diff --git a/.clang-format b/.clang-format index bd446022df..46e7bbce94 100644 --- a/.clang-format +++ b/.clang-format @@ -37,7 +37,7 @@ BinPackParameters: false BreakBeforeBinaryOperators: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: true -ColumnLimit: 80 +ColumnLimit: 120 CommentPragmas: "^ IWYU pragma:" ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000000..1a3337fe8c --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,247 @@ +_help_parse: Options affecting listfile parsing +parse: + _help_additional_commands: + - Specify structure for custom cmake functions + additional_commands: + target_protobuf_sources: + pargs: + - target + - prefix + kwargs: + PROTOS: "*" + LANGUAGE: cpp + IMPORT_DIRS: "*" + GENERATE_EXTENSIONS: "*" + PLUGIN: "*" + _help_override_spec: + - Override configurations per-command where available + override_spec: {} + _help_vartags: + - Specify variable tags. + vartags: [] + _help_proptags: + - Specify property tags. + proptags: [] +_help_format: Options affecting formatting. +format: + _help_disable: + - Disable formatting entirely, making cmake-format a no-op + disable: false + _help_line_width: + - How wide to allow formatted cmake files + line_width: 120 + _help_tab_size: + - How many spaces to tab for indent + tab_size: 4 + _help_use_tabchars: + - If true, lines are indented using tab characters (utf-8 + - 0x09) instead of space characters (utf-8 0x20). + - In cases where the layout would require a fractional tab + - character, the behavior of the fractional indentation is + - governed by + use_tabchars: false + _help_fractional_tab_policy: + - If is True, then the value of this variable + - indicates how fractional indentions are handled during + - whitespace replacement. If set to 'use-space', fractional + - indentation is left as spaces (utf-8 0x20). If set to + - "`round-up` fractional indentation is replaced with a single" + - tab character (utf-8 0x09) effectively shifting the column + - to the next tabstop + fractional_tab_policy: use-space + _help_max_subgroups_hwrap: + - If an argument group contains more than this many sub-groups + - (parg or kwarg groups) then force it to a vertical layout. + max_subgroups_hwrap: 4 + _help_max_pargs_hwrap: + - If a positional argument group contains more than this many + - arguments, then force it to a vertical layout. + max_pargs_hwrap: 5 + _help_max_rows_cmdline: + - If a cmdline positional group consumes more than this many + - lines without nesting, then invalidate the layout (and nest) + max_rows_cmdline: 2 + _help_separate_ctrl_name_with_space: + - If true, separate flow control names from their parentheses + - with a space + separate_ctrl_name_with_space: true + _help_separate_fn_name_with_space: + - If true, separate function names from parentheses with a + - space + separate_fn_name_with_space: false + _help_dangle_parens: + - If a statement is wrapped to more than one line, than dangle + - the closing parenthesis on its own line. + dangle_parens: false + _help_dangle_align: + - If the trailing parenthesis must be 'dangled' on its on + - "line, then align it to this reference: `prefix`: the start" + - "of the statement, `prefix-indent`: the start of the" + - "statement, plus one indentation level, `child`: align to" + - the column of the arguments + dangle_align: prefix + _help_min_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is smaller than this amount, then force reject + - nested layouts. + min_prefix_chars: 18 + _help_max_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is larger than the tab width by more than this + - amount, then force reject un-nested layouts. + max_prefix_chars: 10 + _help_max_lines_hwrap: + - If a candidate layout is wrapped horizontally but it exceeds + - this many lines, then reject the layout. + max_lines_hwrap: 2 + _help_line_ending: + - What style line endings to use in the output. + line_ending: unix + _help_command_case: + - Format command names consistently as 'lower' or 'upper' case + command_case: canonical + _help_keyword_case: + - Format keywords consistently as 'lower' or 'upper' case + keyword_case: unchanged + _help_always_wrap: + - A list of command names which should always be wrapped + always_wrap: [] + _help_enable_sort: + - If true, the argument lists which are known to be sortable + - will be sorted lexicographicall + enable_sort: true + _help_autosort: + - If true, the parsers may infer whether or not an argument + - list is sortable (without annotation). + autosort: true + _help_require_valid_layout: + - By default, if cmake-format cannot successfully fit + - everything into the desired linewidth it will apply the + - last, most aggressive attempt that it made. If this flag is + - True, however, cmake-format will print error, exit with non- + - zero status code, and write-out nothing + require_valid_layout: false + _help_layout_passes: + - A dictionary mapping layout nodes to a list of wrap + - decisions. See the documentation for more information. + layout_passes: {} +_help_markup: Options affecting comment reflow and formatting. +markup: + _help_bullet_char: + - What character to use for bulleted lists + bullet_char: "-" + _help_enum_char: + - What character to use as punctuation after numerals in an + - enumerated list + enum_char: . + _help_first_comment_is_literal: + - If comment markup is enabled, don't reflow the first comment + - block in each listfile. Use this to preserve formatting of + - your copyright/license statements. + first_comment_is_literal: false + _help_literal_comment_pattern: + - If comment markup is enabled, don't reflow any comment block + - which matches this (regex) pattern. Default is `None` + - (disabled). + literal_comment_pattern: null + _help_fence_pattern: + - Regular expression to match preformat fences in comments + - default= ``r'^\s*([`~]{3}[`~]*)(.*)$'`` + fence_pattern: ^\s*([`~]{3}[`~]*)(.*)$ + _help_ruler_pattern: + - Regular expression to match rulers in comments default= + - '``r''^\s*[^\w\s]{3}.*[^\w\s]{3}$''``' + ruler_pattern: ^\s*[^\w\s]{3}.*[^\w\s]{3}$ + _help_explicit_trailing_pattern: + - If a comment line matches starts with this pattern then it + - is explicitly a trailing comment for the preceding + - argument. Default is '#<' + explicit_trailing_pattern: "#<" + _help_hashruler_min_length: + - If a comment line starts with at least this many consecutive + - hash characters, then don't lstrip() them off. This allows + - for lazy hash rulers where the first hash char is not + - separated by space + hashruler_min_length: 10 + _help_canonicalize_hashrulers: + - If true, then insert a space between the first hash char and + - remaining hash chars in a hash ruler, and normalize its + - length to fill the column + canonicalize_hashrulers: true + _help_enable_markup: + - enable comment markup parsing and reflow + enable_markup: false +_help_lint: Options affecting the linter +lint: + _help_disabled_codes: + - a list of lint codes to disable + disabled_codes: [] + _help_function_pattern: + - regular expression pattern describing valid function names + function_pattern: "[0-9a-z_]+" + _help_macro_pattern: + - regular expression pattern describing valid macro names + macro_pattern: "[0-9A-Z_]+" + _help_global_var_pattern: + - regular expression pattern describing valid names for + - variables with global (cache) scope + global_var_pattern: "[A-Z][0-9A-Z_]+" + _help_internal_var_pattern: + - regular expression pattern describing valid names for + - variables with global scope (but internal semantic) + internal_var_pattern: _[A-Z][0-9A-Z_]+ + _help_local_var_pattern: + - regular expression pattern describing valid names for + - variables with local scope + local_var_pattern: "[a-z][a-z0-9_]+" + _help_private_var_pattern: + - regular expression pattern describing valid names for + - privatedirectory variables + private_var_pattern: _[0-9a-z_]+ + _help_public_var_pattern: + - regular expression pattern describing valid names for public + - directory variables + public_var_pattern: "[A-Z][0-9A-Z_]+" + _help_argument_var_pattern: + - regular expression pattern describing valid names for + - function/macro arguments and loop variables. + argument_var_pattern: "[a-z][a-z0-9_]+" + _help_keyword_pattern: + - regular expression pattern describing valid names for + - keywords used in functions or macros + keyword_pattern: "[A-Z][0-9A-Z_]+" + _help_max_conditionals_custom_parser: + - In the heuristic for C0201, how many conditionals to match + - within a loop in before considering the loop a parser. + max_conditionals_custom_parser: 2 + _help_min_statement_spacing: + - Require at least this many newlines between statements + min_statement_spacing: 1 + _help_max_statement_spacing: + - Require no more than this many newlines between statements + max_statement_spacing: 2 + max_returns: 6 + max_branches: 12 + max_arguments: 5 + max_localvars: 15 + max_statements: 50 +_help_encode: Options affecting file encoding +encode: + _help_emit_byteorder_mark: + - If true, emit the unicode byte-order mark (BOM) at the start + - of the file + emit_byteorder_mark: false + _help_input_encoding: + - Specify the encoding of the input file. Defaults to utf-8 + input_encoding: utf-8 + _help_output_encoding: + - Specify the encoding of the output file. Defaults to utf-8. + - Note that cmake only claims to support utf-8 so be careful + - when using anything else + output_encoding: utf-8 +_help_misc: Miscellaneous configurations options. +misc: + _help_per_command: + - A dictionary containing any per-command configuration + - overrides. Currently only `command_case` is supported. + per_command: {} diff --git a/.gitattributes b/.gitattributes index 472cfb380c..7a066d0967 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1,6 @@ # Set default behaviour, in case users don't have core.autocrlf set. #* text=auto - -# These annoying files -rippled.1 binary -LICENSE binary +# cspell: disable # Visual Studio *.sln text eol=crlf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index bc4fe2febd..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# Allow anyone to review any change by default. -* - -# Require the rpc-reviewers team to review changes to the rpc code. -include/xrpl/protocol/ @xrplf/rpc-reviewers -src/libxrpl/protocol/ @xrplf/rpc-reviewers -src/xrpld/rpc/ @xrplf/rpc-reviewers -src/xrpld/app/misc/ @xrplf/rpc-reviewers diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index cc921f5a55..9d1f1f4e6b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug Report -about: Create a report to help us improve rippled -title: "[Title with short description] (Version: [rippled version])" +about: Create a report to help us improve xrpld +title: "[Title with short description] (Version: [xrpld version])" labels: "" assignees: "" --- @@ -27,7 +27,7 @@ assignees: "" ## Environment - + ## Supporting Files diff --git a/.github/actions/build-deps/action.yml b/.github/actions/build-deps/action.yml index f20eb3a595..9d52be1998 100644 --- a/.github/actions/build-deps/action.yml +++ b/.github/actions/build-deps/action.yml @@ -4,9 +4,6 @@ description: "Install Conan dependencies, optionally forcing a rebuild of all de # Note that actions do not support 'type' and all inputs are strings, see # https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#inputs. inputs: - build_dir: - description: "The directory where to build." - required: true build_type: description: 'The build type to use ("Debug", "Release").' required: true @@ -21,6 +18,10 @@ inputs: description: "The logging verbosity." required: false default: "verbose" + sanitizers: + description: "The sanitizers to enable." + required: false + default: "" runs: using: composite @@ -28,17 +29,15 @@ runs: - name: Install Conan dependencies shell: bash env: - BUILD_DIR: ${{ inputs.build_dir }} BUILD_NPROC: ${{ inputs.build_nproc }} BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }} BUILD_TYPE: ${{ inputs.build_type }} LOG_VERBOSITY: ${{ inputs.log_verbosity }} + SANITIZERS: ${{ inputs.sanitizers }} run: | echo 'Installing dependencies.' - mkdir -p "${BUILD_DIR}" - cd "${BUILD_DIR}" conan install \ - --output-folder . \ + --profile ci \ --build="${BUILD_OPTION}" \ --options:host='&:tests=True' \ --options:host='&:xrpld=True' \ @@ -46,4 +45,4 @@ runs: --conf:all tools.build:jobs=${BUILD_NPROC} \ --conf:all tools.build:verbosity="${LOG_VERBOSITY}" \ --conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \ - .. + . diff --git a/.github/actions/generate-version/action.yml b/.github/actions/generate-version/action.yml new file mode 100644 index 0000000000..6b84aac2f3 --- /dev/null +++ b/.github/actions/generate-version/action.yml @@ -0,0 +1,44 @@ +name: Generate build version number +description: "Generate build version number." + +outputs: + version: + description: "The generated build version number." + value: ${{ steps.version.outputs.version }} + +runs: + using: composite + steps: + # When a tag is pushed, the version is used as-is. + - name: Generate version for tag event + if: ${{ github.event_name == 'tag' }} + shell: bash + env: + VERSION: ${{ github.ref_name }} + run: echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" + + # When a tag is not pushed, then the version (e.g. 1.2.3-b0) is extracted + # from the BuildInfo.cpp file and the shortened commit hash appended to it. + # We use a plus sign instead of a hyphen because Conan recipe versions do + # not support two hyphens. + - name: Generate version for non-tag event + if: ${{ github.event_name != 'tag' }} + shell: bash + run: | + echo 'Extracting version from BuildInfo.cpp.' + VERSION="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" + if [[ -z "${VERSION}" ]]; then + echo 'Unable to extract version from BuildInfo.cpp.' + exit 1 + fi + + echo 'Appending shortened commit hash to version.' + SHA='${{ github.sha }}' + VERSION="${VERSION}+${SHA:0:7}" + + echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" + + - name: Output version + id: version + shell: bash + run: echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" diff --git a/.github/actions/print-env/action.yml b/.github/actions/print-env/action.yml index 6019a6de2f..3527ca6f02 100644 --- a/.github/actions/print-env/action.yml +++ b/.github/actions/print-env/action.yml @@ -11,12 +11,6 @@ runs: echo 'Checking environment variables.' set - echo 'Checking CMake version.' - cmake --version - - echo 'Checking Conan version.' - conan --version - - name: Check configuration (Linux and macOS) if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} shell: bash @@ -27,17 +21,23 @@ runs: echo 'Checking environment variables.' env | sort - echo 'Checking CMake version.' - cmake --version - echo 'Checking compiler version.' ${{ runner.os == 'Linux' && '${CC}' || 'clang' }} --version - echo 'Checking Conan version.' - conan --version - echo 'Checking Ninja version.' ninja --version echo 'Checking nproc version.' nproc --version + + - name: Check configuration (all) + shell: bash + run: | + echo 'Checking Ccache version.' + ccache --version + + echo 'Checking CMake version.' + cmake --version + + echo 'Checking Conan version.' + conan --version diff --git a/.github/actions/setup-conan/action.yml b/.github/actions/setup-conan/action.yml index 1184cfd3d9..9d834884d2 100644 --- a/.github/actions/setup-conan/action.yml +++ b/.github/actions/setup-conan/action.yml @@ -2,11 +2,11 @@ name: Setup Conan description: "Set up Conan configuration, profile, and remote." inputs: - conan_remote_name: + remote_name: description: "The name of the Conan remote to use." required: false default: xrplf - conan_remote_url: + remote_url: description: "The URL of the Conan endpoint to use." required: false default: https://conan.ripplex.io @@ -28,19 +28,19 @@ runs: shell: bash run: | echo 'Installing profile.' - conan config install conan/profiles/default -tf $(conan config home)/profiles/ + conan config install conan/profiles/ -tf $(conan config home)/profiles/ echo 'Conan profile:' - conan profile show + conan profile show --profile ci - name: Set up Conan remote shell: bash env: - CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }} - CONAN_REMOTE_URL: ${{ inputs.conan_remote_url }} + REMOTE_NAME: ${{ inputs.remote_name }} + REMOTE_URL: ${{ inputs.remote_url }} run: | - echo "Adding Conan remote '${CONAN_REMOTE_NAME}' at '${CONAN_REMOTE_URL}'." - conan remote add --index 0 --force "${CONAN_REMOTE_NAME}" "${CONAN_REMOTE_URL}" + echo "Adding Conan remote '${REMOTE_NAME}' at '${REMOTE_URL}'." + conan remote add --index 0 --force "${REMOTE_NAME}" "${REMOTE_URL}" echo 'Listing Conan remotes.' conan remote list diff --git a/.github/scripts/levelization/README.md b/.github/scripts/levelization/README.md index f3ba1e2518..c3e6ffa4a8 100644 --- a/.github/scripts/levelization/README.md +++ b/.github/scripts/levelization/README.md @@ -3,21 +3,26 @@ Levelization is the term used to describe efforts to prevent rippled from having or creating cyclic dependencies. -rippled code is organized into directories under `src/rippled` (and +rippled code is organized into directories under `src/xrpld`, `src/libxrpl` (and `src/test`) representing modules. The modules are intended to be organized into "tiers" or "levels" such that a module from one level can only include code from lower levels. Additionally, a module -in one level should never include code in an `impl` folder of any level +in one level should never include code in an `impl` or `detail` folder of any level other than it's own. +The codebase is split into two main areas: + +- **libxrpl** (`src/libxrpl`, `include/xrpl`): Reusable library modules with public interfaces +- **xrpld** (`src/xrpld`): Application-specific implementation code + Unfortunately, over time, enforcement of levelization has been inconsistent, so the current state of the code doesn't necessarily reflect these rules. Whenever possible, developers should refactor any levelization violations they find (by moving files or individual classes). At the very least, don't make things worse. -The table below summarizes the _desired_ division of modules, based on the -state of the rippled code when it was created. The levels are numbered from +The table below summarizes the _desired_ division of modules, based on the current +state of the rippled code. The levels are numbered from the bottom up with the lower level, lower numbered, more independent modules listed first, and the higher level, higher numbered modules with more dependencies listed later. @@ -25,18 +30,33 @@ more dependencies listed later. **tl;dr:** The modules listed first are more independent than the modules listed later. +## libxrpl Modules (Reusable Libraries) + +| Level / Tier | Module(s) | +| ------------ | ----------------------------------- | +| 01 | xrpl/beast | +| 02 | xrpl/basics | +| 03 | xrpl/json xrpl/crypto | +| 04 | xrpl/protocol | +| 05 | xrpl/core xrpl/resource xrpl/server | +| 06 | xrpl/ledger xrpl/nodestore xrpl/net | +| 07 | xrpl/shamap | + +## xrpld Modules (Application Implementation) + +| Level / Tier | Module(s) | +| ------------ | -------------------------------- | +| 05 | xrpld/conditions xrpld/consensus | +| 06 | xrpld/core xrpld/peerfinder | +| 07 | xrpld/shamap xrpld/overlay | +| 08 | xrpld/app | +| 09 | xrpld/rpc | +| 10 | xrpld/perflog | + +## Test Modules + | Level / Tier | Module(s) | | ------------ | -------------------------------------------------------------------------------------------------------- | -| 01 | ripple/beast ripple/unity | -| 02 | ripple/basics | -| 03 | ripple/json ripple/crypto | -| 04 | ripple/protocol | -| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server | -| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net | -| 07 | ripple/shamap ripple/overlay | -| 08 | ripple/app | -| 09 | ripple/rpc | -| 10 | ripple/perflog | | 11 | test/jtx test/beast test/csf | | 12 | test/unit_test | | 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay | @@ -45,8 +65,8 @@ listed later. | 16 | test/rpc test/app | (Note that `test` levelization is _much_ less important and _much_ less -strictly enforced than `ripple` levelization, other than the requirement -that `test` code should _never_ be included in `ripple` code.) +strictly enforced than `xrpl`/`xrpld` levelization, other than the requirement +that `test` code should _never_ be included in `xrpl` or `xrpld` code.) ## Validation @@ -61,10 +81,10 @@ It generates many files of [results](results): - `rawincludes.txt`: The raw dump of the `#includes` - `paths.txt`: A second dump grouping the source module - to the destination module, deduped, and with frequency counts. + to the destination module, de-duped, and with frequency counts. - `includes/`: A directory where each file represents a module and contains a list of modules and counts that the module _includes_. -- `includedby/`: Similar to `includes/`, but the other way around. Each +- `included_by/`: Similar to `includes/`, but the other way around. Each file represents a module and contains a list of modules and counts that _include_ the module. - [`loops.txt`](results/loops.txt): A list of direct loops detected diff --git a/.github/scripts/levelization/generate.sh b/.github/scripts/levelization/generate.sh index 775ddf789f..d700c7a206 100755 --- a/.github/scripts/levelization/generate.sh +++ b/.github/scripts/levelization/generate.sh @@ -29,7 +29,7 @@ pushd results oldifs=${IFS} IFS=: mkdir includes -mkdir includedby +mkdir included_by echo Build levelization paths exec 3< ${includes} # open rawincludes.txt for input while read -r -u 3 file include @@ -59,7 +59,7 @@ do echo $level $includelevel | tee -a paths.txt fi done -echo Sort and dedup paths +echo Sort and deduplicate paths sort -ds paths.txt | uniq -c | tee sortedpaths.txt mv sortedpaths.txt paths.txt exec 3>&- #close fd 3 @@ -71,7 +71,7 @@ exec 4&- #close fd 4 diff --git a/.github/scripts/levelization/results/loops.txt b/.github/scripts/levelization/results/loops.txt index d057391be9..34842d7f48 100644 --- a/.github/scripts/levelization/results/loops.txt +++ b/.github/scripts/levelization/results/loops.txt @@ -4,14 +4,11 @@ Loop: test.jtx test.toplevel Loop: test.jtx test.unit_test test.unit_test == test.jtx -Loop: xrpld.app xrpld.core - xrpld.app > xrpld.core - Loop: xrpld.app xrpld.overlay xrpld.overlay > xrpld.app Loop: xrpld.app xrpld.peerfinder - xrpld.peerfinder ~= xrpld.app + xrpld.peerfinder == xrpld.app Loop: xrpld.app xrpld.rpc xrpld.rpc > xrpld.app @@ -19,12 +16,6 @@ Loop: xrpld.app xrpld.rpc Loop: xrpld.app xrpld.shamap xrpld.shamap ~= xrpld.app -Loop: xrpld.core xrpld.perflog - xrpld.perflog == xrpld.core - Loop: xrpld.overlay xrpld.rpc xrpld.rpc ~= xrpld.overlay -Loop: xrpld.perflog xrpld.rpc - xrpld.rpc ~= xrpld.perflog - diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 251e9c1957..85f2457ea3 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -1,4 +1,6 @@ libxrpl.basics > xrpl.basics +libxrpl.core > xrpl.basics +libxrpl.core > xrpl.core libxrpl.crypto > xrpl.basics libxrpl.json > xrpl.basics libxrpl.json > xrpl.json @@ -15,12 +17,15 @@ libxrpl.nodestore > xrpl.protocol libxrpl.protocol > xrpl.basics libxrpl.protocol > xrpl.json libxrpl.protocol > xrpl.protocol +libxrpl.rdb > xrpl.basics +libxrpl.rdb > xrpl.rdb libxrpl.resource > xrpl.basics libxrpl.resource > xrpl.json libxrpl.resource > xrpl.resource libxrpl.server > xrpl.basics libxrpl.server > xrpl.json libxrpl.server > xrpl.protocol +libxrpl.server > xrpl.rdb libxrpl.server > xrpl.server libxrpl.shamap > xrpl.basics libxrpl.shamap > xrpl.protocol @@ -30,6 +35,7 @@ test.app > test.rpc test.app > test.toplevel test.app > test.unit_test test.app > xrpl.basics +test.app > xrpl.core test.app > xrpld.app test.app > xrpld.core test.app > xrpld.overlay @@ -38,11 +44,13 @@ test.app > xrpl.json test.app > xrpl.ledger test.app > xrpl.nodestore test.app > xrpl.protocol +test.app > xrpl.rdb test.app > xrpl.resource +test.app > xrpl.server test.basics > test.jtx test.basics > test.unit_test test.basics > xrpl.basics -test.basics > xrpld.perflog +test.basics > xrpl.core test.basics > xrpld.rpc test.basics > xrpl.json test.basics > xrpl.protocol @@ -61,9 +69,10 @@ test.core > test.jtx test.core > test.toplevel test.core > test.unit_test test.core > xrpl.basics +test.core > xrpl.core test.core > xrpld.core -test.core > xrpld.perflog test.core > xrpl.json +test.core > xrpl.rdb test.core > xrpl.server test.csf > xrpl.basics test.csf > xrpld.consensus @@ -92,8 +101,8 @@ test.nodestore > test.jtx test.nodestore > test.toplevel test.nodestore > test.unit_test test.nodestore > xrpl.basics -test.nodestore > xrpld.core test.nodestore > xrpl.nodestore +test.nodestore > xrpl.rdb test.overlay > test.jtx test.overlay > test.toplevel test.overlay > test.unit_test @@ -101,6 +110,7 @@ test.overlay > xrpl.basics test.overlay > xrpld.app test.overlay > xrpld.overlay test.overlay > xrpld.peerfinder +test.overlay > xrpl.nodestore test.overlay > xrpl.protocol test.overlay > xrpl.shamap test.peerfinder > test.beast @@ -119,6 +129,7 @@ test.resource > xrpl.resource test.rpc > test.jtx test.rpc > test.toplevel test.rpc > xrpl.basics +test.rpc > xrpl.core test.rpc > xrpld.app test.rpc > xrpld.core test.rpc > xrpld.overlay @@ -146,6 +157,10 @@ test.unit_test > xrpl.basics tests.libxrpl > xrpl.basics tests.libxrpl > xrpl.json tests.libxrpl > xrpl.net +xrpl.core > xrpl.basics +xrpl.core > xrpl.json +xrpl.core > xrpl.ledger +xrpl.core > xrpl.protocol xrpl.json > xrpl.basics xrpl.ledger > xrpl.basics xrpl.ledger > xrpl.protocol @@ -154,26 +169,34 @@ xrpl.nodestore > xrpl.basics xrpl.nodestore > xrpl.protocol xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.json +xrpl.rdb > xrpl.basics +xrpl.rdb > xrpl.core +xrpl.rdb > xrpl.protocol xrpl.resource > xrpl.basics xrpl.resource > xrpl.json xrpl.resource > xrpl.protocol xrpl.server > xrpl.basics +xrpl.server > xrpl.core xrpl.server > xrpl.json xrpl.server > xrpl.protocol +xrpl.server > xrpl.rdb xrpl.shamap > xrpl.basics xrpl.shamap > xrpl.nodestore xrpl.shamap > xrpl.protocol xrpld.app > test.unit_test xrpld.app > xrpl.basics +xrpld.app > xrpl.core xrpld.app > xrpld.conditions xrpld.app > xrpld.consensus -xrpld.app > xrpld.perflog +xrpld.app > xrpld.core xrpld.app > xrpl.json xrpld.app > xrpl.ledger xrpld.app > xrpl.net xrpld.app > xrpl.nodestore xrpld.app > xrpl.protocol +xrpld.app > xrpl.rdb xrpld.app > xrpl.resource +xrpld.app > xrpl.server xrpld.app > xrpl.shamap xrpld.conditions > xrpl.basics xrpld.conditions > xrpl.protocol @@ -181,29 +204,37 @@ xrpld.consensus > xrpl.basics xrpld.consensus > xrpl.json xrpld.consensus > xrpl.protocol xrpld.core > xrpl.basics +xrpld.core > xrpl.core xrpld.core > xrpl.json xrpld.core > xrpl.net xrpld.core > xrpl.protocol +xrpld.core > xrpl.rdb xrpld.overlay > xrpl.basics +xrpld.overlay > xrpl.core xrpld.overlay > xrpld.core xrpld.overlay > xrpld.peerfinder -xrpld.overlay > xrpld.perflog xrpld.overlay > xrpl.json xrpld.overlay > xrpl.protocol +xrpld.overlay > xrpl.rdb xrpld.overlay > xrpl.resource xrpld.overlay > xrpl.server xrpld.peerfinder > xrpl.basics xrpld.peerfinder > xrpld.core xrpld.peerfinder > xrpl.protocol +xrpld.peerfinder > xrpl.rdb xrpld.perflog > xrpl.basics +xrpld.perflog > xrpl.core +xrpld.perflog > xrpld.rpc xrpld.perflog > xrpl.json xrpld.rpc > xrpl.basics +xrpld.rpc > xrpl.core xrpld.rpc > xrpld.core xrpld.rpc > xrpl.json xrpld.rpc > xrpl.ledger xrpld.rpc > xrpl.net xrpld.rpc > xrpl.nodestore xrpld.rpc > xrpl.protocol +xrpld.rpc > xrpl.rdb xrpld.rpc > xrpl.resource xrpld.rpc > xrpl.server xrpld.shamap > xrpl.shamap diff --git a/.github/scripts/rename/README.md b/.github/scripts/rename/README.md new file mode 100644 index 0000000000..cc004a335f --- /dev/null +++ b/.github/scripts/rename/README.md @@ -0,0 +1,47 @@ +## Renaming ripple(d) to xrpl(d) + +In the initial phases of development of the XRPL, the open source codebase was +called "rippled" and it remains with that name even today. Today, over 1000 +nodes run the application, and code contributions have been submitted by +developers located around the world. The XRPL community is larger than ever. +In light of the decentralized and diversified nature of XRPL, we will rename any +references to `ripple` and `rippled` to `xrpl` and `xrpld`, when appropriate. + +See [here](https://xls.xrpl.org/xls/XLS-0095-rename-rippled-to-xrpld.html) for +more information. + +### Scripts + +To facilitate this transition, there will be multiple scripts that developers +can run on their own PRs and forks to minimize conflicts. Each script should be +run from the repository root. + +1. `.github/scripts/rename/definitions.sh`: This script will rename all + definitions, such as include guards, from `RIPPLE_XXX` and `RIPPLED_XXX` to + `XRPL_XXX`. +2. `.github/scripts/rename/copyright.sh`: This script will remove superfluous + copyright notices. +3. `.github/scripts/rename/cmake.sh`: This script will rename all CMake files + from `RippleXXX.cmake` or `RippledXXX.cmake` to `XrplXXX.cmake`, and any + references to `ripple` and `rippled` (with or without capital letters) to + `xrpl` and `xrpld`, respectively. The name of the binary will remain as-is, + and will only be renamed to `xrpld` by a later script. +4. `.github/scripts/rename/binary.sh`: This script will rename the binary from + `rippled` to `xrpld`, and reverses the symlink so that `rippled` points to + the `xrpld` binary. +5. `.github/scripts/rename/namespace.sh`: This script will rename the C++ + namespaces from `ripple` to `xrpl`. +6. `.github/scripts/rename/config.sh`: This script will rename the config from + `rippled.cfg` to `xrpld.cfg`, and updating the code accordingly. The old + filename will still be accepted. + +You can run all these scripts from the repository root as follows: + +```shell +./.github/scripts/rename/definitions.sh . +./.github/scripts/rename/copyright.sh . +./.github/scripts/rename/cmake.sh . +./.github/scripts/rename/binary.sh . +./.github/scripts/rename/namespace.sh . +./.github/scripts/rename/config.sh . +``` diff --git a/.github/scripts/rename/binary.sh b/.github/scripts/rename/binary.sh new file mode 100755 index 0000000000..deb4dd5fb4 --- /dev/null +++ b/.github/scripts/rename/binary.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed is installed and available as `gsed`. +SED_COMMAND=sed +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed +fi + +# This script changes the binary name from `rippled` to `xrpld`, and reverses +# the symlink that currently points from `xrpld` to `rippled` so that it points +# from `rippled` to `xrpld` instead. +# Usage: .github/scripts/rename/binary.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi +pushd ${DIRECTORY} + +# Remove the binary name override added by the cmake.sh script. +${SED_COMMAND} -z -i -E 's@\s+# For the time being.+"rippled"\)@@' cmake/XrplCore.cmake + +# Reverse the symlink. +${SED_COMMAND} -i -E 's@create_symbolic_link\(rippled@create_symbolic_link(xrpld@' cmake/XrplInstall.cmake +${SED_COMMAND} -i -E 's@/xrpld\$\{suffix\}@/rippled${suffix}@' cmake/XrplInstall.cmake + +# Rename references to the binary. +${SED_COMMAND} -i -E 's@rippled@xrpld@g' BUILD.md +${SED_COMMAND} -i -E 's@rippled@xrpld@g' CONTRIBUTING.md +${SED_COMMAND} -i -E 's@rippled@xrpld@g' .github/ISSUE_TEMPLATE/bug_report.md + +# Restore and/or fix certain renames. The pre-commit hook will update the +# formatting upon saving/committing. +${SED_COMMAND} -i -E 's@ripple/xrpld@XRPLF/rippled@g' BUILD.md +${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' BUILD.md +${SED_COMMAND} -i -E 's@xrpld \(`xrpld`\)@xrpld@g' BUILD.md +${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' CONTRIBUTING.md + +popd +echo "Processing complete." diff --git a/.github/scripts/rename/cmake.sh b/.github/scripts/rename/cmake.sh new file mode 100755 index 0000000000..0f88fa5de2 --- /dev/null +++ b/.github/scripts/rename/cmake.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed and head are installed and available as `gsed` +# and `ghead`, respectively. +SED_COMMAND=sed +HEAD_COMMAND=head +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed + if ! command -v ghead &> /dev/null; then + echo "Error: ghead is not installed. Please install it using 'brew install coreutils'." + exit 1 + fi + HEAD_COMMAND=ghead +fi + +# This script renames CMake files from `RippleXXX.cmake` or `RippledXXX.cmake` +# to `XrplXXX.cmake`, and any references to `ripple` and `rippled` (with or +# without capital letters) to `xrpl` and `xrpld`, respectively. The name of the +# binary will remain as-is, and will only be renamed to `xrpld` in a different +# script, but the proto file will be renamed. +# Usage: .github/scripts/rename/cmake.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi +pushd ${DIRECTORY} + +# Rename the files. +find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \; +find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \; +if [ -e cmake/xrpl_add_test.cmake ]; then + mv cmake/xrpl_add_test.cmake cmake/XrplAddTest.cmake +fi +if [ -e include/xrpl/proto/ripple.proto ]; then + mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto +fi + +# Rename inside the files. +find cmake -type f -name '*.cmake' | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i 's/Rippled/Xrpld/g' "${FILE}" + ${SED_COMMAND} -i 's/Ripple/Xrpl/g' "${FILE}" + ${SED_COMMAND} -i 's/rippled/xrpld/g' "${FILE}" + ${SED_COMMAND} -i 's/ripple/xrpl/g' "${FILE}" +done +${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt +${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt +${SED_COMMAND} -i 's/include(xrpl_add_test)/include(XrplAddTest)/' src/tests/libxrpl/CMakeLists.txt +${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h +${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md +${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md + +# Restore the name of the validator keys repository. +${SED_COMMAND} -i 's@xrpl/validator-keys-tool@ripple/validator-keys-tool@' cmake/XrplValidatorKeys.cmake + +# Ensure the name of the binary and config remain 'rippled' for now. +${SED_COMMAND} -i -E 's/xrpld(-example)?\.cfg/rippled\1.cfg/g' cmake/XrplInstall.cmake +if grep -q '"xrpld"' cmake/XrplCore.cmake; then + # The script has been rerun, so just restore the name of the binary. + ${SED_COMMAND} -i 's/"xrpld"/"rippled"/' cmake/XrplCore.cmake +elif ! grep -q '"rippled"' cmake/XrplCore.cmake; then + ${HEAD_COMMAND} -n -1 cmake/XrplCore.cmake > cmake.tmp + echo ' # For the time being, we will keep the name of the binary as it was.' >> cmake.tmp + echo ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >> cmake.tmp + tail -1 cmake/XrplCore.cmake >> cmake.tmp + mv cmake.tmp cmake/XrplCore.cmake +fi + +# Restore the symlink from 'xrpld' to 'rippled'. +${SED_COMMAND} -i -E 's@create_symbolic_link\(xrpld@create_symbolic_link(rippled@' cmake/XrplInstall.cmake + +# Remove the symlink that previously pointed from 'ripple' to 'xrpl' but now is +# no longer needed. +${SED_COMMAND} -z -i -E 's@install\(CODE.+CMAKE_INSTALL_INCLUDEDIR}/xrpl\)\n"\)\n+@@' cmake/XrplInstall.cmake + +popd +echo "Renaming complete." diff --git a/.github/scripts/rename/config.sh b/.github/scripts/rename/config.sh new file mode 100755 index 0000000000..f6e914f502 --- /dev/null +++ b/.github/scripts/rename/config.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed is installed and available as `gsed`. +SED_COMMAND=sed +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed +fi + +# This script renames the config from `rippled.cfg` to `xrpld.cfg`, and updates +# the code accordingly. The old filename will still be accepted. +# Usage: .github/scripts/rename/config.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi +pushd ${DIRECTORY} + +# Add the xrpld.cfg to the .gitignore. +if ! grep -q 'xrpld.cfg' .gitignore; then + ${SED_COMMAND} -i '/rippled.cfg/a\ +/xrpld.cfg' .gitignore +fi + +# Rename the files. +if [ -e rippled.cfg ]; then + mv rippled.cfg xrpld.cfg +fi +if [ -e cfg/rippled-example.cfg ]; then + mv cfg/rippled-example.cfg cfg/xrpld-example.cfg +fi + +# Rename inside the files. +DIRECTORIES=("cfg" "cmake" "include" "src") +for DIRECTORY in "${DIRECTORIES[@]}"; do + echo "Processing directory: ${DIRECTORY}" + + find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" -o -name "*.cmake" -o -name "*.txt" -o -name "*.cfg" -o -name "*.md" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i -E 's/rippled(-example)?[ .]cfg/xrpld\1.cfg/g' "${FILE}" + done +done +${SED_COMMAND} -i 's/rippled/xrpld/g' cfg/xrpld-example.cfg +${SED_COMMAND} -i 's/rippled/xrpld/g' src/test/core/Config_test.cpp +${SED_COMMAND} -i 's/ripplevalidators/xrplvalidators/g' src/test/core/Config_test.cpp # cspell: disable-line +${SED_COMMAND} -i 's/rippleConfig/xrpldConfig/g' src/test/core/Config_test.cpp +${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp +${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp + + +# Restore the old config file name in the code that maintains support for now. +${SED_COMMAND} -i 's/configLegacyName = "xrpld.cfg"/configLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp + +# Restore an URL. +${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg + +popd +echo "Renaming complete." diff --git a/.github/scripts/rename/copyright.sh b/.github/scripts/rename/copyright.sh new file mode 100755 index 0000000000..c5a9fb2cd3 --- /dev/null +++ b/.github/scripts/rename/copyright.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed is installed and available as `gsed`. +SED_COMMAND=sed +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed +fi + +# This script removes superfluous copyright notices in source and header files +# in this project. Specifically, it removes all notices referencing Ripple, +# XRPLF, and certain individual contributors upon mutual agreement, so the one +# in the LICENSE.md file applies throughout. Copyright notices referencing +# external contributions, e.g. from Bitcoin, remain as-is. +# Usage: .github/scripts/rename/copyright.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi +pushd ${DIRECTORY} + +# Prevent sed and echo from removing newlines and tabs in string literals by +# temporarily replacing them with placeholders. This only affects one file. +PLACEHOLDER_NEWLINE="__NEWLINE__" +PLACEHOLDER_TAB="__TAB__" +${SED_COMMAND} -i -E "s@\\\n@${PLACEHOLDER_NEWLINE}@g" src/test/rpc/ValidatorInfo_test.cpp +${SED_COMMAND} -i -E "s@\\\t@${PLACEHOLDER_TAB}@g" src/test/rpc/ValidatorInfo_test.cpp + +# Process the include/ and src/ directories. +DIRECTORIES=("include" "src") +for DIRECTORY in "${DIRECTORIES[@]}"; do + echo "Processing directory: ${DIRECTORY}" + + find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" -o -name "*.macro" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + # Handle the cases where the copyright notice is enclosed in /* ... */ + # and usually surrounded by //---- and //======. + ${SED_COMMAND} -z -i -E 's@^//-------+\n+@@' "${FILE}" + ${SED_COMMAND} -z -i -E 's@^.*Copyright.+(Ripple|Bougalis|Falco|Hinnant|Null|Ritchford|XRPLF).+PERFORMANCE OF THIS SOFTWARE\.\n\*/\n+@@' "${FILE}" # cspell: ignore Bougalis Falco Hinnant Ritchford + ${SED_COMMAND} -z -i -E 's@^//=======+\n+@@' "${FILE}" + + # Handle the cases where the copyright notice is commented out with //. + ${SED_COMMAND} -z -i -E 's@^//\n// Copyright.+Falco \(vinnie dot falco at gmail dot com\)\n//\n+@@' "${FILE}" # cspell: ignore Vinnie Falco + done +done + +# Restore copyright notices that were removed from specific files, without +# restoring the verbiage that is already present in LICENSE.md. Ensure that if +# the script is run multiple times, duplicate notices are not added. +if ! grep -q 'Raw Material Software' include/xrpl/beast/core/CurrentThreadName.h; then + echo -e "// Portions of this file are from JUCE (http://www.juce.com).\n// Copyright (c) 2013 - Raw Material Software Ltd.\n// Please visit http://www.juce.com\n\n$(cat include/xrpl/beast/core/CurrentThreadName.h)" > include/xrpl/beast/core/CurrentThreadName.h +fi +if ! grep -q 'Dev Null' src/test/app/NetworkID_test.cpp; then + echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/NetworkID_test.cpp)" > src/test/app/NetworkID_test.cpp +fi +if ! grep -q 'Dev Null' src/test/app/tx/apply_test.cpp; then + echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/tx/apply_test.cpp)" > src/test/app/tx/apply_test.cpp +fi +if ! grep -q 'Dev Null' src/test/rpc/ManifestRPC_test.cpp; then + echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ManifestRPC_test.cpp)" > src/test/rpc/ManifestRPC_test.cpp +fi +if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then + echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" > src/test/rpc/ValidatorInfo_test.cpp +fi +if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/DoManifest.cpp; then + echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/DoManifest.cpp)" > src/xrpld/rpc/handlers/DoManifest.cpp +fi +if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/ValidatorInfo.cpp; then + echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/ValidatorInfo.cpp +fi +if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then + echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis \n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb +fi +if ! grep -q 'Bougalis' include/xrpl/basics/spinlock.h; then + echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis \n\n$(cat include/xrpl/basics/spinlock.h)" > include/xrpl/basics/spinlock.h # cspell: ignore Nikolaos Bougalis nikb +fi +if ! grep -q 'Bougalis' include/xrpl/basics/tagged_integer.h; then + echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis \n\n$(cat include/xrpl/basics/tagged_integer.h)" > include/xrpl/basics/tagged_integer.h # cspell: ignore Nikolaos Bougalis nikb +fi +if ! grep -q 'Ritchford' include/xrpl/beast/utility/Zero.h; then + echo -e "// Copyright (c) 2014, Tom Ritchford \n\n$(cat include/xrpl/beast/utility/Zero.h)" > include/xrpl/beast/utility/Zero.h # cspell: ignore Ritchford +fi + +# Restore newlines and tabs in string literals in the affected file. +${SED_COMMAND} -i -E "s@${PLACEHOLDER_NEWLINE}@\\\n@g" src/test/rpc/ValidatorInfo_test.cpp +${SED_COMMAND} -i -E "s@${PLACEHOLDER_TAB}@\\\t@g" src/test/rpc/ValidatorInfo_test.cpp + +popd +echo "Removal complete." diff --git a/.github/scripts/rename/definitions.sh b/.github/scripts/rename/definitions.sh new file mode 100755 index 0000000000..403e5eab0d --- /dev/null +++ b/.github/scripts/rename/definitions.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed is installed and available as `gsed`. +SED_COMMAND=sed +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed +fi + +# This script renames definitions, such as include guards, in this project. +# Specifically, it renames "RIPPLED_XXX" and "RIPPLE_XXX" to "XRPL_XXX" by +# scanning all cmake, header, and source files in the specified directory and +# its subdirectories. +# Usage: .github/scripts/rename/definitions.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi + +find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i -E 's@#(define|endif|if|ifdef|ifndef)(.*)(RIPPLED_|RIPPLE_)([A-Z0-9_]+)@#\1\2XRPL_\4@g' "${FILE}" +done +find "${DIRECTORY}" -type f \( -name "*.cmake" -o -name "*.txt" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i -E 's@(RIPPLED_|RIPPLE_)([A-Z0-9_]+)@XRPL_\2@g' "${FILE}" +done +echo "Renaming complete." diff --git a/.github/scripts/rename/include.sh b/.github/scripts/rename/include.sh new file mode 100755 index 0000000000..fbf165b975 --- /dev/null +++ b/.github/scripts/rename/include.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# This script checks whether there are no new include guards introduced by a new +# PR, as header files should use "#pragma once" instead. The script assumes any +# include guards will use "XRPL_" as prefix. +# Usage: .github/scripts/rename/include.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi + +find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + if grep -q "#ifndef XRPL_" "${FILE}"; then + echo "Please replace all include guards by #pragma once." + exit 1 + fi +done +echo "Checking complete." diff --git a/.github/scripts/rename/namespace.sh b/.github/scripts/rename/namespace.sh new file mode 100755 index 0000000000..30fd91bf2c --- /dev/null +++ b/.github/scripts/rename/namespace.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Exit the script as soon as an error occurs. +set -e + +# On MacOS, ensure that GNU sed is installed and available as `gsed`. +SED_COMMAND=sed +if [[ "${OSTYPE}" == 'darwin'* ]]; then + if ! command -v gsed &> /dev/null; then + echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'." + exit 1 + fi + SED_COMMAND=gsed +fi + +# This script renames the `ripple` namespace to `xrpl` in this project. +# Specifically, it renames all occurrences of `namespace ripple` and `ripple::` +# to `namespace xrpl` and `xrpl::`, respectively, by scanning all header and +# source files in the specified directory and its subdirectories, as well as any +# occurrences in the documentation. It also renames them in the test suites. +# Usage: .github/scripts/rename/namespace.sh + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIRECTORY=$1 +echo "Processing directory: ${DIRECTORY}" +if [ ! -d "${DIRECTORY}" ]; then + echo "Error: Directory '${DIRECTORY}' does not exist." + exit 1 +fi +pushd ${DIRECTORY} + +DIRECTORIES=("include" "src" "tests") +for DIRECTORY in "${DIRECTORIES[@]}"; do + echo "Processing directory: ${DIRECTORY}" + + find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" \) | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i 's/namespace ripple/namespace xrpl/g' "${FILE}" + ${SED_COMMAND} -i 's/ripple::/xrpl::/g' "${FILE}" + ${SED_COMMAND} -i -E 's/(BEAST_DEFINE_TESTSUITE.+)ripple(.+)/\1xrpl\2/g' "${FILE}" + done +done + +# Special case for NuDBFactory that has ripple twice in the test suite name. +${SED_COMMAND} -i -E 's/(BEAST_DEFINE_TESTSUITE.+)ripple(.+)/\1xrpl\2/g' src/test/nodestore/NuDBFactory_test.cpp + +DIRECTORY=$1 +find "${DIRECTORY}" -type f -name "*.md" | while read -r FILE; do + echo "Processing file: ${FILE}" + ${SED_COMMAND} -i 's/ripple::/xrpl::/g' "${FILE}" +done + +popd +echo "Renaming complete." diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 025d553b5e..27eb60c005 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -2,11 +2,12 @@ import argparse import itertools import json -from pathlib import Path from dataclasses import dataclass +from pathlib import Path THIS_DIR = Path(__file__).parent.resolve() + @dataclass class Config: architecture: list[dict] @@ -14,12 +15,13 @@ class Config: build_type: list[str] cmake_args: list[str] -''' + +""" Generate a strategy matrix for GitHub Actions CI. On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and -Windows configurations, while upon merge into the develop, release, or master -branches, we will build all configurations, and test most of them. +Windows configurations, while upon merge into the develop or release branches, +we will build all configurations, and test most of them. We will further set additional CMake arguments as follows: - All builds will have the `tests`, `werr`, and `xrpld` options. @@ -27,171 +29,305 @@ We will further set additional CMake arguments as follows: - All release builds will have the `assert` option. - Certain Debian Bookworm configurations will change the reference fee, enable codecov, and enable voidstar in PRs. -''' +""" + + def generate_strategy_matrix(all: bool, config: Config) -> list: configurations = [] - for architecture, os, build_type, cmake_args in itertools.product(config.architecture, config.os, config.build_type, config.cmake_args): + for architecture, os, build_type, cmake_args in itertools.product( + config.architecture, config.os, config.build_type, config.cmake_args + ): # The default CMake target is 'all' for Linux and MacOS and 'install' # for Windows, but it can get overridden for certain configurations. - cmake_target = 'install' if os["distro_name"] == 'windows' else 'all' + cmake_target = "install" if os["distro_name"] == "windows" else "all" # We build and test all configurations by default, except for Windows in # Debug, because it is too slow, as well as when code coverage is # enabled as that mode already runs the tests. build_only = False - if os['distro_name'] == 'windows' and build_type == 'Debug': + if os["distro_name"] == "windows" and build_type == "Debug": build_only = True # Only generate a subset of configurations in PRs. if not all: # Debian: - # - Bookworm using GCC 13: Release and Unity on linux/amd64, set - # the reference fee to 500. - # - Bookworm using GCC 15: Debug and no Unity on linux/amd64, enable - # code coverage (which will be done below). - # - Bookworm using Clang 16: Debug and no Unity on linux/arm64, - # enable voidstar. - # - Bookworm using Clang 17: Release and no Unity on linux/amd64, - # set the reference fee to 1000. - # - Bookworm using Clang 20: Debug and Unity on linux/amd64. - if os['distro_name'] == 'debian': + # - Bookworm using GCC 13: Release on linux/amd64, set the reference + # fee to 500. + # - Bookworm using GCC 15: Debug on linux/amd64, enable code + # coverage (which will be done below). + # - Bookworm using Clang 16: Debug on linux/arm64, enable voidstar. + # - Bookworm using Clang 17: Release on linux/amd64, set the + # reference fee to 1000. + # - Bookworm using Clang 20: Debug on linux/amd64. + if os["distro_name"] == "debian": skip = True - if os['distro_version'] == 'bookworm': - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-13' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': - cmake_args = f'-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}' + if os["distro_version"] == "bookworm": + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13" + and build_type == "Release" + and architecture["platform"] == "linux/amd64" + ): + cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}" skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-16' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/arm64': - cmake_args = f'-Dvoidstar=ON {cmake_args}' + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16" + and build_type == "Debug" + and architecture["platform"] == "linux/arm64" + ): + cmake_args = f"-Dvoidstar=ON {cmake_args}" skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-17' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': - cmake_args = f'-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}' + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17" + and build_type == "Release" + and architecture["platform"] == "linux/amd64" + ): + cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}" skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-20' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): skip = False if skip: continue # RHEL: - # - 9 using GCC 12: Debug and Unity on linux/amd64. - # - 10 using Clang: Release and no Unity on linux/amd64. - if os['distro_name'] == 'rhel': + # - 9 using GCC 12: Debug on linux/amd64. + # - 10 using Clang: Release on linux/amd64. + if os["distro_name"] == "rhel": skip = True - if os['distro_version'] == '9': - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': + if os["distro_version"] == "9": + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): skip = False - elif os['distro_version'] == '10': - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-any' and build_type == 'Release' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': + elif os["distro_version"] == "10": + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any" + and build_type == "Release" + and architecture["platform"] == "linux/amd64" + ): skip = False if skip: continue # Ubuntu: - # - Jammy using GCC 12: Debug and no Unity on linux/arm64. - # - Noble using GCC 14: Release and Unity on linux/amd64. - # - Noble using Clang 18: Debug and no Unity on linux/amd64. - # - Noble using Clang 19: Release and Unity on linux/arm64. - if os['distro_name'] == 'ubuntu': + # - Jammy using GCC 12: Debug on linux/arm64. + # - Noble using GCC 14: Release on linux/amd64. + # - Noble using Clang 18: Debug on linux/amd64. + # - Noble using Clang 19: Release on linux/arm64. + if os["distro_name"] == "ubuntu": skip = True - if os['distro_version'] == 'jammy': - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/arm64': + if os["distro_version"] == "jammy": + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" + and build_type == "Debug" + and architecture["platform"] == "linux/arm64" + ): skip = False - elif os['distro_version'] == 'noble': - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-14' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': + elif os["distro_version"] == "noble": + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14" + and build_type == "Release" + and architecture["platform"] == "linux/amd64" + ): skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-18' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): skip = False - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-19' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/arm64': + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19" + and build_type == "Release" + and architecture["platform"] == "linux/arm64" + ): skip = False if skip: continue # MacOS: - # - Debug and no Unity on macos/arm64. - if os['distro_name'] == 'macos' and not (build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'macos/arm64'): + # - Debug on macos/arm64. + if os["distro_name"] == "macos" and not ( + build_type == "Debug" and architecture["platform"] == "macos/arm64" + ): continue # Windows: - # - Release and Unity on windows/amd64. - if os['distro_name'] == 'windows' and not (build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'windows/amd64'): + # - Release on windows/amd64. + if os["distro_name"] == "windows" and not ( + build_type == "Release" and architecture["platform"] == "windows/amd64" + ): continue - # Additional CMake arguments. - cmake_args = f'{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON' - if not f'{os['compiler_name']}-{os['compiler_version']}' in ['gcc-12', 'clang-16']: - cmake_args = f'{cmake_args} -Dwextra=ON' - if build_type == 'Release': - cmake_args = f'{cmake_args} -Dassert=ON' + cmake_args = f"{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON" + if not f"{os['compiler_name']}-{os['compiler_version']}" in [ + "gcc-12", + "clang-16", + ]: + cmake_args = f"{cmake_args} -Dwextra=ON" + if build_type == "Release": + cmake_args = f"{cmake_args} -Dassert=ON" # We skip all RHEL on arm64 due to a build failure that needs further # investigation. - if os['distro_name'] == 'rhel' and architecture['platform'] == 'linux/arm64': + if os["distro_name"] == "rhel" and architecture["platform"] == "linux/arm64": continue - # We skip all clang-20 on arm64 due to boost 1.86 build error - if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-20' and architecture['platform'] == 'linux/arm64': + # We skip all clang 20+ on arm64 due to Boost build error. + if ( + f"{os['compiler_name']}-{os['compiler_version']}" + in ["clang-20", "clang-21"] + and architecture["platform"] == "linux/arm64" + ): continue - # Enable code coverage for Debian Bookworm using GCC 15 in Debug and no - # Unity on linux/amd64 - if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': - cmake_args = f'-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}' - cmake_target = 'coverage' - build_only = True + # Enable code coverage for Debian Bookworm using GCC 15 in Debug on + # linux/amd64 + if ( + f"{os['distro_name']}-{os['distro_version']}" == "debian-bookworm" + and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): + cmake_args = f"{cmake_args} -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0" + + # Enable unity build for Ubuntu Jammy using GCC 12 in Debug on + # linux/amd64. + if ( + f"{os['distro_name']}-{os['distro_version']}" == "ubuntu-jammy" + and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" + and build_type == "Debug" + and architecture["platform"] == "linux/amd64" + ): + cmake_args = f"{cmake_args} -Dunity=ON" # Generate a unique name for the configuration, e.g. macos-arm64-debug - # or debian-bookworm-gcc-12-amd64-release-unity. - config_name = os['distro_name'] - if (n := os['distro_version']) != '': - config_name += f'-{n}' - if (n := os['compiler_name']) != '': - config_name += f'-{n}' - if (n := os['compiler_version']) != '': - config_name += f'-{n}' - config_name += f'-{architecture['platform'][architecture['platform'].find('/')+1:]}' - config_name += f'-{build_type.lower()}' - if '-Dunity=ON' in cmake_args: - config_name += '-unity' + # or debian-bookworm-gcc-12-amd64-release. + config_name = os["distro_name"] + if (n := os["distro_version"]) != "": + config_name += f"-{n}" + if (n := os["compiler_name"]) != "": + config_name += f"-{n}" + if (n := os["compiler_version"]) != "": + config_name += f"-{n}" + config_name += ( + f"-{architecture['platform'][architecture['platform'].find('/')+1:]}" + ) + config_name += f"-{build_type.lower()}" + if "-Dcoverage=ON" in cmake_args: + config_name += "-coverage" + if "-Dunity=ON" in cmake_args: + config_name += "-unity" # Add the configuration to the list, with the most unique fields first, # so that they are easier to identify in the GitHub Actions UI, as long # names get truncated. - configurations.append({ - 'config_name': config_name, - 'cmake_args': cmake_args, - 'cmake_target': cmake_target, - 'build_only': build_only, - 'build_type': build_type, - 'os': os, - 'architecture': architecture, - }) + # Add Address and Thread (both coupled with UB) sanitizers for specific bookworm distros. + # GCC-Asan rippled-embedded tests are failing because of https://github.com/google/sanitizers/issues/856 + if ( + os["distro_version"] == "bookworm" + and f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20" + ): + # Add ASAN + UBSAN configuration. + configurations.append( + { + "config_name": config_name + "-asan-ubsan", + "cmake_args": cmake_args, + "cmake_target": cmake_target, + "build_only": build_only, + "build_type": build_type, + "os": os, + "architecture": architecture, + "sanitizers": "address,undefinedbehavior", + } + ) + # TSAN is deactivated due to seg faults with latest compilers. + activate_tsan = False + if activate_tsan: + configurations.append( + { + "config_name": config_name + "-tsan-ubsan", + "cmake_args": cmake_args, + "cmake_target": cmake_target, + "build_only": build_only, + "build_type": build_type, + "os": os, + "architecture": architecture, + "sanitizers": "thread,undefinedbehavior", + } + ) + else: + configurations.append( + { + "config_name": config_name, + "cmake_args": cmake_args, + "cmake_target": cmake_target, + "build_only": build_only, + "build_type": build_type, + "os": os, + "architecture": architecture, + "sanitizers": "", + } + ) return configurations def read_config(file: Path) -> Config: config = json.loads(file.read_text()) - if config['architecture'] is None or config['os'] is None or config['build_type'] is None or config['cmake_args'] is None: - raise Exception('Invalid configuration file.') + if ( + config["architecture"] is None + or config["os"] is None + or config["build_type"] is None + or config["cmake_args"] is None + ): + raise Exception("Invalid configuration file.") return Config(**config) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-a', '--all', help='Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).', action="store_true") - parser.add_argument('-c', '--config', help='Path to the JSON file containing the strategy matrix configurations.', required=False, type=Path) + parser.add_argument( + "-a", + "--all", + help="Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).", + action="store_true", + ) + parser.add_argument( + "-c", + "--config", + help="Path to the JSON file containing the strategy matrix configurations.", + required=False, + type=Path, + ) args = parser.parse_args() matrix = [] - if args.config is None or args.config == '': - matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "linux.json")) - matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "macos.json")) - matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "windows.json")) + if args.config is None or args.config == "": + matrix += generate_strategy_matrix( + args.all, read_config(THIS_DIR / "linux.json") + ) + matrix += generate_strategy_matrix( + args.all, read_config(THIS_DIR / "macos.json") + ) + matrix += generate_strategy_matrix( + args.all, read_config(THIS_DIR / "windows.json") + ) else: matrix += generate_strategy_matrix(args.all, read_config(args.config)) # Generate the strategy matrix. - print(f'matrix={json.dumps({"include": matrix})}') + print(f"matrix={json.dumps({'include': matrix})}") diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index 85a78c96dc..4943579be8 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -15,170 +15,198 @@ "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "15", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "16", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "17", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "18", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "19", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "20", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" + }, + { + "distro_name": "debian", + "distro_version": "trixie", + "compiler_name": "gcc", + "compiler_version": "14", + "image_sha": "ab4d1f0" + }, + { + "distro_name": "debian", + "distro_version": "trixie", + "compiler_name": "gcc", + "compiler_version": "15", + "image_sha": "ab4d1f0" + }, + { + "distro_name": "debian", + "distro_version": "trixie", + "compiler_name": "clang", + "compiler_version": "20", + "image_sha": "ab4d1f0" + }, + { + "distro_name": "debian", + "distro_version": "trixie", + "compiler_name": "clang", + "compiler_version": "21", + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "8", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "8", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "jammy", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "16", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "17", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "18", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "19", - "image_sha": "97ba375" + "image_sha": "ab4d1f0" } ], "build_type": ["Debug", "Release"], - "cmake_args": ["-Dunity=OFF", "-Dunity=ON"] + "cmake_args": [""] } diff --git a/.github/scripts/strategy-matrix/macos.json b/.github/scripts/strategy-matrix/macos.json index 14b6089620..6fc44d0f80 100644 --- a/.github/scripts/strategy-matrix/macos.json +++ b/.github/scripts/strategy-matrix/macos.json @@ -15,8 +15,5 @@ } ], "build_type": ["Debug", "Release"], - "cmake_args": [ - "-Dunity=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5", - "-Dunity=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5" - ] + "cmake_args": ["-DCMAKE_POLICY_VERSION_MINIMUM=3.5"] } diff --git a/.github/scripts/strategy-matrix/windows.json b/.github/scripts/strategy-matrix/windows.json index 8637b31012..8c536c70f2 100644 --- a/.github/scripts/strategy-matrix/windows.json +++ b/.github/scripts/strategy-matrix/windows.json @@ -15,5 +15,5 @@ } ], "build_type": ["Debug", "Release"], - "cmake_args": ["-Dunity=OFF", "-Dunity=ON"] + "cmake_args": [""] } diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index 6d74486e96..46f6b7500a 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -1,7 +1,8 @@ # This workflow runs all workflows to check, build and test the project on # various Linux flavors, as well as on MacOS and Windows, on every push to a # user branch. However, it will not run if the pull request is a draft unless it -# has the 'DraftRunCI' label. +# has the 'DraftRunCI' label. For commits to PRs that target a release branch, +# it also uploads the libxrpl recipe to the Conan remote. name: PR on: @@ -50,13 +51,15 @@ jobs: files: | # These paths are unique to `on-pr.yml`. .github/scripts/levelization/** + .github/scripts/rename/** .github/workflows/reusable-check-levelization.yml - .github/workflows/reusable-notify-clio.yml + .github/workflows/reusable-check-rename.yml .github/workflows/on-pr.yml # Keep the paths below in sync with those in `on-trigger.yml`. .github/actions/build-deps/** .github/actions/build-test/** + .github/actions/generate-version/** .github/actions/setup-conan/** .github/scripts/strategy-matrix/** .github/workflows/reusable-build.yml @@ -64,6 +67,7 @@ jobs: .github/workflows/reusable-build-test.yml .github/workflows/reusable-strategy-matrix.yml .github/workflows/reusable-test.yml + .github/workflows/reusable-upload-recipe.yml .codecov.yml cmake/** conan/** @@ -98,6 +102,11 @@ jobs: if: ${{ needs.should-run.outputs.go == 'true' }} uses: ./.github/workflows/reusable-check-levelization.yml + check-rename: + needs: should-run + if: ${{ needs.should-run.outputs.go == 'true' }} + uses: ./.github/workflows/reusable-check-rename.yml + build-test: needs: should-run if: ${{ needs.should-run.outputs.go == 'true' }} @@ -107,26 +116,49 @@ jobs: matrix: os: [linux, macos, windows] with: + # Enable ccache only for events targeting the XRPLF repository, since + # other accounts will not have access to our remote cache storage. + ccache_enabled: ${{ github.repository_owner == 'XRPLF' }} os: ${{ matrix.os }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - notify-clio: + upload-recipe: needs: - should-run - build-test - if: ${{ needs.should-run.outputs.go == 'true' && contains(fromJSON('["release", "master"]'), github.ref_name) }} - uses: ./.github/workflows/reusable-notify-clio.yml + # Only run when committing to a PR that targets a release branch in the + # XRPLF repository. + if: ${{ github.repository_owner == 'XRPLF' && needs.should-run.outputs.go == 'true' && startsWith(github.ref, 'refs/heads/release') }} + uses: ./.github/workflows/reusable-upload-recipe.yml secrets: - clio_notify_token: ${{ secrets.CLIO_NOTIFY_TOKEN }} - conan_remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} - conan_remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} + remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + + notify-clio: + needs: upload-recipe + runs-on: ubuntu-latest + steps: + # Notify the Clio repository about the newly proposed release version, so + # it can be checked for compatibility before the release is actually made. + - name: Notify Clio + env: + GH_TOKEN: ${{ secrets.CLIO_NOTIFY_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ + -F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \ + -F "client_payload[pr_url]=${PR_URL}" passed: if: failure() || cancelled() needs: - - build-test - check-levelization + - check-rename + - build-test + - upload-recipe + - notify-clio runs-on: ubuntu-latest steps: - name: Fail diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml new file mode 100644 index 0000000000..c6361b4016 --- /dev/null +++ b/.github/workflows/on-tag.yml @@ -0,0 +1,25 @@ +# This workflow uploads the libxrpl recipe to the Conan remote when a versioned +# tag is pushed. +name: Tag + +on: + push: + tags: + - "v*" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + upload-recipe: + # Only run when a tag is pushed to the XRPLF repository. + if: ${{ github.repository_owner == 'XRPLF' }} + uses: ./.github/workflows/reusable-upload-recipe.yml + secrets: + remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} + remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} diff --git a/.github/workflows/on-trigger.yml b/.github/workflows/on-trigger.yml index 9df6417c07..210670f5a1 100644 --- a/.github/workflows/on-trigger.yml +++ b/.github/workflows/on-trigger.yml @@ -1,9 +1,7 @@ -# This workflow runs all workflows to build the dependencies required for the -# project on various Linux flavors, as well as on MacOS and Windows, on a -# scheduled basis, on merge into the 'develop', 'release', or 'master' branches, -# or manually. The missing commits check is only run when the code is merged -# into the 'develop' or 'release' branches, and the documentation is built when -# the code is merged into the 'develop' branch. +# This workflow runs all workflows to build and test the code on various Linux +# flavors, as well as on MacOS and Windows, on a scheduled basis, on merge into +# the 'develop' or 'release*' branches, or when requested manually. Upon pushes +# to the develop branch it also uploads the libxrpl recipe to the Conan remote. name: Trigger on: @@ -11,16 +9,14 @@ on: branches: - "develop" - "release*" - - "master" paths: # These paths are unique to `on-trigger.yml`. - - ".github/workflows/reusable-check-missing-commits.yml" - ".github/workflows/on-trigger.yml" - - ".github/workflows/publish-docs.yml" # Keep the paths below in sync with those in `on-pr.yml`. - ".github/actions/build-deps/**" - ".github/actions/build-test/**" + - ".github/actions/generate-version/**" - ".github/actions/setup-conan/**" - ".github/scripts/strategy-matrix/**" - ".github/workflows/reusable-build.yml" @@ -28,6 +24,7 @@ on: - ".github/workflows/reusable-build-test.yml" - ".github/workflows/reusable-strategy-matrix.yml" - ".github/workflows/reusable-test.yml" + - ".github/workflows/reusable-upload-recipe.yml" - ".codecov.yml" - "cmake/**" - "conan/**" @@ -63,10 +60,6 @@ defaults: shell: bash jobs: - check-missing-commits: - if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && contains(fromJSON('["develop", "release"]'), github.ref_name) }} - uses: ./.github/workflows/reusable-check-missing-commits.yml - build-test: uses: ./.github/workflows/reusable-build-test.yml strategy: @@ -74,7 +67,22 @@ jobs: matrix: os: [linux, macos, windows] with: + # Enable ccache only for events targeting the XRPLF repository, since + # other accounts will not have access to our remote cache storage. + # However, we do not enable ccache for events targeting a release branch, + # to protect against the rare case that the output produced by ccache is + # not identical to a regular compilation. + ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }} os: ${{ matrix.os }} strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + upload-recipe: + needs: build-test + # Only run when pushing to the develop branch in the XRPLF repository. + if: ${{ github.repository_owner == 'XRPLF' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + uses: ./.github/workflows/reusable-upload-recipe.yml + secrets: + remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} + remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d0a657dd7e..f43275201c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -3,13 +3,15 @@ name: Run pre-commit hooks on: pull_request: push: - branches: [develop, release, master] + branches: + - "develop" + - "release*" workflow_dispatch: jobs: # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. run-hooks: - uses: XRPLF/actions/.github/workflows/pre-commit.yml@34790936fae4c6c751f62ec8c06696f9c1a5753a + uses: XRPLF/actions/.github/workflows/pre-commit.yml@320be44621ca2a080f05aeb15817c44b84518108 with: runs_on: ubuntu-latest - container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }' + container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-ab4d1f0" }' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 14a2ba2fc0..f61559d6d3 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -22,7 +22,7 @@ defaults: shell: bash env: - BUILD_DIR: .build + BUILD_DIR: build NPROC_SUBTRACT: 2 jobs: @@ -36,7 +36,7 @@ jobs: uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Get number of processors - uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a + uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf id: nproc with: subtract: ${{ env.NPROC_SUBTRACT }} diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index a59dbda71b..85b973ea0c 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -3,32 +3,38 @@ name: Build and test configuration on: workflow_call: inputs: - build_dir: - description: "The directory where to build." - required: true - type: string build_only: description: 'Whether to only build or to build and test the code ("true", "false").' required: true type: boolean + build_type: description: 'The build type to use ("Debug", "Release").' - type: string required: true + type: string + + ccache_enabled: + description: "Whether to enable ccache." + required: false + type: boolean + default: false + cmake_args: description: "Additional arguments to pass to CMake." required: false type: string default: "" + cmake_target: description: "The CMake target to build." - type: string required: true + type: string runs_on: description: Runner to run the job on as a JSON string required: true type: string + image: description: "The image to run in (leave empty to run natively)" required: true @@ -45,33 +51,215 @@ on: type: number default: 2 + sanitizers: + description: "The sanitizers to enable." + required: false + type: string + default: "" + secrets: CODECOV_TOKEN: description: "The Codecov token to use for uploading coverage reports." required: true -jobs: - build: - uses: ./.github/workflows/reusable-build.yml - with: - build_dir: ${{ inputs.build_dir }} - build_type: ${{ inputs.build_type }} - cmake_args: ${{ inputs.cmake_args }} - cmake_target: ${{ inputs.cmake_target }} - runs_on: ${{ inputs.runs_on }} - image: ${{ inputs.image }} - config_name: ${{ inputs.config_name }} - nproc_subtract: ${{ inputs.nproc_subtract }} - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +defaults: + run: + shell: bash - test: - needs: build - uses: ./.github/workflows/reusable-test.yml - with: - run_tests: ${{ !inputs.build_only }} - verify_voidstar: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }} - runs_on: ${{ inputs.runs_on }} - image: ${{ inputs.image }} - config_name: ${{ inputs.config_name }} - nproc_subtract: ${{ inputs.nproc_subtract }} +env: + # Conan installs the generators in the build/generators directory, see the + # layout() method in conanfile.py. We then run CMake from the build directory. + BUILD_DIR: build + +jobs: + build-and-test: + name: ${{ inputs.config_name }} + runs-on: ${{ fromJSON(inputs.runs_on) }} + container: ${{ inputs.image != '' && inputs.image || null }} + timeout-minutes: 60 + env: + # Use a namespace to keep the objects separate for each configuration. + CCACHE_NAMESPACE: ${{ inputs.config_name }} + # Ccache supports both Redis and HTTP endpoints. + # * For Redis, use the following format: redis://ip:port, see + # https://github.com/ccache/ccache/wiki/Redis-storage. Note that TLS is + # not directly supported by ccache, and requires use of a proxy. + # * For HTTP use the following format: http://ip:port/cache when using + # nginx as backend or http://ip:port|layout=bazel when using Bazel + # Remote Cache, see https://github.com/ccache/ccache/wiki/HTTP-storage. + # Note that HTTPS is not directly supported by ccache. + CCACHE_REMOTE_ONLY: true + CCACHE_REMOTE_STORAGE: http://cache.dev.ripplex.io:8080|layout=bazel + # Ignore the creation and modification timestamps on files, since the + # header files are copied into separate directories by CMake, which will + # otherwise result in cache misses. + CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime + # Determine if coverage and voidstar should be enabled. + COVERAGE_ENABLED: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }} + VOIDSTAR_ENABLED: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }} + SANITIZERS_ENABLED: ${{ inputs.sanitizers != '' }} + steps: + - name: Cleanup workspace (macOS and Windows) + if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} + uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf + + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + + - name: Prepare runner + uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + with: + enable_ccache: ${{ inputs.ccache_enabled }} + + - name: Set ccache log file + if: ${{ inputs.ccache_enabled && runner.debug == '1' }} + run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >> "${GITHUB_ENV}" + + - name: Print build environment + uses: ./.github/actions/print-env + + - name: Get number of processors + uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf + id: nproc + with: + subtract: ${{ inputs.nproc_subtract }} + + - name: Setup Conan + env: + SANITIZERS: ${{ inputs.sanitizers }} + uses: ./.github/actions/setup-conan + + - name: Build dependencies + uses: ./.github/actions/build-deps + with: + build_nproc: ${{ steps.nproc.outputs.nproc }} + build_type: ${{ inputs.build_type }} + # Set the verbosity to "quiet" for Windows to avoid an excessive + # amount of logs. For other OSes, the "verbose" logs are more useful. + log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }} + sanitizers: ${{ inputs.sanitizers }} + + - name: Configure CMake + working-directory: ${{ env.BUILD_DIR }} + env: + BUILD_TYPE: ${{ inputs.build_type }} + SANITIZERS: ${{ inputs.sanitizers }} + CMAKE_ARGS: ${{ inputs.cmake_args }} + run: | + cmake \ + -G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \ + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ + ${CMAKE_ARGS} \ + .. + + - name: Build the binary + working-directory: ${{ env.BUILD_DIR }} + env: + BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} + BUILD_TYPE: ${{ inputs.build_type }} + CMAKE_TARGET: ${{ inputs.cmake_target }} + run: | + cmake \ + --build . \ + --config "${BUILD_TYPE}" \ + --parallel "${BUILD_NPROC}" \ + --target "${CMAKE_TARGET}" + + - name: Show ccache statistics + if: ${{ inputs.ccache_enabled }} + run: | + ccache --show-stats -vv + if [ '${{ runner.debug }}' = '1' ]; then + cat "${CCACHE_LOGFILE}" + curl ${CCACHE_REMOTE_STORAGE%|*}/status || true + fi + + - name: Upload the binary (Linux) + if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: xrpld-${{ inputs.config_name }} + path: ${{ env.BUILD_DIR }}/xrpld + retention-days: 3 + if-no-files-found: error + + - name: Check linking (Linux) + if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }} + working-directory: ${{ env.BUILD_DIR }} + run: | + ldd ./xrpld + if [ "$(ldd ./xrpld | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then + echo 'The binary is statically linked.' + else + echo 'The binary is dynamically linked.' + exit 1 + fi + + - name: Verify presence of instrumentation (Linux) + if: ${{ runner.os == 'Linux' && env.VOIDSTAR_ENABLED == 'true' }} + working-directory: ${{ env.BUILD_DIR }} + run: | + ./xrpld --version | grep libvoidstar + + - name: Set sanitizer options + if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }} + run: | + echo "ASAN_OPTIONS=print_stacktrace=1:detect_container_overflow=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV} + echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV} + echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV} + echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV} + + - name: Run the separate tests + if: ${{ !inputs.build_only }} + working-directory: ${{ env.BUILD_DIR }} + # Windows locks some of the build files while running tests, and parallel jobs can collide + env: + BUILD_TYPE: ${{ inputs.build_type }} + PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }} + run: | + ctest \ + --output-on-failure \ + -C "${BUILD_TYPE}" \ + -j "${PARALLELISM}" + + - name: Run the embedded tests + if: ${{ !inputs.build_only }} + working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }} + env: + BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} + run: | + ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" + + - name: Debug failure (Linux) + if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }} + run: | + echo "IPv4 local port range:" + cat /proc/sys/net/ipv4/ip_local_port_range + echo "Netstat:" + netstat -an + + - name: Prepare coverage report + if: ${{ !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} + working-directory: ${{ env.BUILD_DIR }} + env: + BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} + BUILD_TYPE: ${{ inputs.build_type }} + run: | + cmake \ + --build . \ + --config "${BUILD_TYPE}" \ + --parallel "${BUILD_NPROC}" \ + --target coverage + + - name: Upload coverage report + if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 + with: + disable_search: true + disable_telem: true + fail_ci_if_error: true + files: ${{ env.BUILD_DIR }}/coverage.xml + plugins: noop + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true diff --git a/.github/workflows/reusable-build-test.yml b/.github/workflows/reusable-build-test.yml index c6e991df79..0086cbbfb5 100644 --- a/.github/workflows/reusable-build-test.yml +++ b/.github/workflows/reusable-build-test.yml @@ -8,21 +8,24 @@ name: Build and test on: workflow_call: inputs: - build_dir: - description: "The directory where to build." + ccache_enabled: + description: "Whether to enable ccache." required: false - type: string - default: ".build" + type: boolean + default: false + os: description: 'The operating system to use for the build ("linux", "macos", "windows").' required: true type: string + strategy_matrix: # TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations. description: 'The strategy matrix to use for generating the configurations ("minimal", "all").' required: false type: string default: "minimal" + secrets: CODECOV_TOKEN: description: "The Codecov token to use for uploading coverage reports." @@ -46,13 +49,14 @@ jobs: matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} max-parallel: 10 with: - build_dir: ${{ inputs.build_dir }} build_only: ${{ matrix.build_only }} build_type: ${{ matrix.build_type }} + ccache_enabled: ${{ inputs.ccache_enabled }} cmake_args: ${{ matrix.cmake_args }} cmake_target: ${{ matrix.cmake_target }} runs_on: ${{ toJSON(matrix.architecture.runner) }} image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }} config_name: ${{ matrix.config_name }} + sanitizers: ${{ matrix.sanitizers }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml deleted file mode 100644 index a9d5fd7f7c..0000000000 --- a/.github/workflows/reusable-build.yml +++ /dev/null @@ -1,154 +0,0 @@ -name: Build rippled - -on: - workflow_call: - inputs: - build_dir: - description: "The directory where to build." - required: true - type: string - build_type: - description: 'The build type to use ("Debug", "Release").' - required: true - type: string - cmake_args: - description: "Additional arguments to pass to CMake." - required: true - type: string - cmake_target: - description: "The CMake target to build." - required: true - type: string - - runs_on: - description: Runner to run the job on as a JSON string - required: true - type: string - image: - description: "The image to run in (leave empty to run natively)" - required: true - type: string - - config_name: - description: "The name of the configuration." - required: true - type: string - - nproc_subtract: - description: "The number of processors to subtract when calculating parallelism." - required: true - type: number - - secrets: - CODECOV_TOKEN: - description: "The Codecov token to use for uploading coverage reports." - required: true - -defaults: - run: - shell: bash - -jobs: - build: - name: Build ${{ inputs.config_name }} - runs-on: ${{ fromJSON(inputs.runs_on) }} - container: ${{ inputs.image != '' && inputs.image || null }} - timeout-minutes: 60 - steps: - - name: Cleanup workspace - if: ${{ runner.os == 'macOS' }} - uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e - - - name: Checkout repository - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - - - name: Prepare runner - uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a - with: - disable_ccache: false - - - name: Print build environment - uses: ./.github/actions/print-env - - - name: Get number of processors - uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a - id: nproc - with: - subtract: ${{ inputs.nproc_subtract }} - - - name: Setup Conan - uses: ./.github/actions/setup-conan - - - name: Build dependencies - uses: ./.github/actions/build-deps - with: - build_dir: ${{ inputs.build_dir }} - build_nproc: ${{ steps.nproc.outputs.nproc }} - build_type: ${{ inputs.build_type }} - # Set the verbosity to "quiet" for Windows to avoid an excessive - # amount of logs. For other OSes, the "verbose" logs are more useful. - log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }} - - - name: Configure CMake - shell: bash - working-directory: ${{ inputs.build_dir }} - env: - BUILD_TYPE: ${{ inputs.build_type }} - CMAKE_ARGS: ${{ inputs.cmake_args }} - run: | - cmake \ - -G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \ - -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ - -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ - ${CMAKE_ARGS} \ - .. - - - name: Build the binary - shell: bash - working-directory: ${{ inputs.build_dir }} - env: - BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} - BUILD_TYPE: ${{ inputs.build_type }} - CMAKE_TARGET: ${{ inputs.cmake_target }} - run: | - cmake \ - --build . \ - --config "${BUILD_TYPE}" \ - --parallel ${BUILD_NPROC} \ - --target "${CMAKE_TARGET}" - - - name: Put built binaries in one location - shell: bash - working-directory: ${{ inputs.build_dir }} - env: - BUILD_TYPE_DIR: ${{ runner.os == 'Windows' && inputs.build_type || '' }} - CMAKE_TARGET: ${{ inputs.cmake_target }} - run: | - mkdir -p ./binaries/doctest/ - - cp ./${BUILD_TYPE_DIR}/rippled* ./binaries/ - if [ "${CMAKE_TARGET}" != 'coverage' ]; then - cp ./src/tests/libxrpl/${BUILD_TYPE_DIR}/xrpl.test.* ./binaries/doctest/ - fi - - - name: Upload rippled artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - env: - BUILD_DIR: ${{ inputs.build_dir }} - with: - name: rippled-${{ inputs.config_name }} - path: ${{ env.BUILD_DIR }}/binaries/ - retention-days: 3 - if-no-files-found: error - - - name: Upload coverage report - if: ${{ github.repository_owner == 'XRPLF' && inputs.cmake_target == 'coverage' }} - uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 - with: - disable_search: true - disable_telem: true - fail_ci_if_error: true - files: ${{ inputs.build_dir }}/coverage.xml - plugins: noop - token: ${{ secrets.CODECOV_TOKEN }} - verbose: true diff --git a/.github/workflows/reusable-check-levelization.yml b/.github/workflows/reusable-check-levelization.yml index 3430ca28a2..29a1dc1480 100644 --- a/.github/workflows/reusable-check-levelization.yml +++ b/.github/workflows/reusable-check-levelization.yml @@ -25,7 +25,7 @@ jobs: env: MESSAGE: | - The dependency relationships between the modules in rippled have + The dependency relationships between the modules in xrpld have changed, which may be an improvement or a regression. A rule of thumb is that if your changes caused something to be diff --git a/.github/workflows/reusable-check-missing-commits.yml b/.github/workflows/reusable-check-missing-commits.yml deleted file mode 100644 index 07d29174d8..0000000000 --- a/.github/workflows/reusable-check-missing-commits.yml +++ /dev/null @@ -1,62 +0,0 @@ -# This workflow checks that all commits in the "master" branch are also in the -# "release" and "develop" branches, and that all commits in the "release" branch -# are also in the "develop" branch. -name: Check for missing commits - -# This workflow can only be triggered by other workflows. -on: workflow_call - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-missing-commits - cancel-in-progress: true - -defaults: - run: - shell: bash - -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - with: - fetch-depth: 0 - - name: Check for missing commits - env: - MESSAGE: | - - If you are reading this, then the commits indicated above are missing - from the "develop" and/or "release" branch. Do a reverse-merge as soon - as possible. See CONTRIBUTING.md for instructions. - run: | - set -o pipefail - # Branches are ordered by how "canonical" they are. Every commit in one - # branch should be in all the branches behind it. - order=(master release develop) - branches=() - for branch in "${order[@]}"; do - # Check that the branches exist so that this job will work on forked - # repos, which don't necessarily have master and release branches. - echo "Checking if ${branch} exists." - if git ls-remote --exit-code --heads origin \ - refs/heads/${branch} > /dev/null; then - branches+=(origin/${branch}) - fi - done - - prior=() - for branch in "${branches[@]}"; do - if [[ ${#prior[@]} -ne 0 ]]; then - echo "Checking ${prior[@]} for commits missing from ${branch}." - git log --oneline --no-merges "${prior[@]}" \ - ^$branch | tee -a "missing-commits.txt" - echo - fi - prior+=("${branch}") - done - - if [[ $(cat missing-commits.txt | wc -l) -ne 0 ]]; then - echo "${MESSAGE}" - exit 1 - fi diff --git a/.github/workflows/reusable-check-rename.yml b/.github/workflows/reusable-check-rename.yml new file mode 100644 index 0000000000..a73ac49b7d --- /dev/null +++ b/.github/workflows/reusable-check-rename.yml @@ -0,0 +1,54 @@ +# This workflow checks if the codebase is properly renamed, see more info in +# .github/scripts/rename/README.md. +name: Check rename + +# This workflow can only be triggered by other workflows. +on: workflow_call + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-rename + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + rename: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - name: Check definitions + run: .github/scripts/rename/definitions.sh . + - name: Check copyright notices + run: .github/scripts/rename/copyright.sh . + - name: Check CMake configs + run: .github/scripts/rename/cmake.sh . + - name: Check binary name + run: .github/scripts/rename/binary.sh . + - name: Check namespaces + run: .github/scripts/rename/namespace.sh . + - name: Check config name + run: .github/scripts/rename/config.sh . + - name: Check include guards + run: .github/scripts/rename/include.sh . + - name: Check for differences + env: + MESSAGE: | + + One or more files contain changes that do not adhere to new naming + conventions. + + Run the scripts in '.github/scripts/rename/' in your repo, commit + and push the changes. See .github/scripts/rename/README.md for + more info. + run: | + DIFF=$(git status --porcelain) + if [ -n "${DIFF}" ]; then + # Print the differences to give the contributor a hint about what to + # expect when running the renaming scripts on their own machine. + git diff + echo "${MESSAGE}" + exit 1 + fi diff --git a/.github/workflows/reusable-notify-clio.yml b/.github/workflows/reusable-notify-clio.yml deleted file mode 100644 index 0941d5f2e3..0000000000 --- a/.github/workflows/reusable-notify-clio.yml +++ /dev/null @@ -1,91 +0,0 @@ -# This workflow exports the built libxrpl package to the Conan remote on a -# a channel named after the pull request, and notifies the Clio repository about -# the new version so it can check for compatibility. -name: Notify Clio - -# This workflow can only be triggered by other workflows. -on: - workflow_call: - inputs: - conan_remote_name: - description: "The name of the Conan remote to use." - required: false - type: string - default: xrplf - conan_remote_url: - description: "The URL of the Conan endpoint to use." - required: false - type: string - default: https://conan.ripplex.io - secrets: - clio_notify_token: - description: "The GitHub token to notify Clio about new versions." - required: true - conan_remote_username: - description: "The username for logging into the Conan remote." - required: true - conan_remote_password: - description: "The password for logging into the Conan remote." - required: true - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-clio - cancel-in-progress: true - -defaults: - run: - shell: bash - -jobs: - upload: - if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} - runs-on: ubuntu-latest - container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158 - steps: - - name: Checkout repository - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - - name: Generate outputs - id: generate - env: - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - echo 'Generating user and channel.' - echo "user=clio" >> "${GITHUB_OUTPUT}" - echo "channel=pr_${PR_NUMBER}" >> "${GITHUB_OUTPUT}" - echo 'Extracting version.' - echo "version=$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" >> "${GITHUB_OUTPUT}" - - name: Calculate conan reference - id: conan_ref - run: | - echo "conan_ref=${{ steps.generate.outputs.version }}@${{ steps.generate.outputs.user }}/${{ steps.generate.outputs.channel }}" >> "${GITHUB_OUTPUT}" - - name: Set up Conan - uses: ./.github/actions/setup-conan - with: - conan_remote_name: ${{ inputs.conan_remote_name }} - conan_remote_url: ${{ inputs.conan_remote_url }} - - name: Log into Conan remote - env: - CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }} - run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}" - - name: Upload package - env: - CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }} - run: | - conan export --user=${{ steps.generate.outputs.user }} --channel=${{ steps.generate.outputs.channel }} . - conan upload --confirm --check --remote="${CONAN_REMOTE_NAME}" xrpl/${{ steps.conan_ref.outputs.conan_ref }} - outputs: - conan_ref: ${{ steps.conan_ref.outputs.conan_ref }} - - notify: - needs: upload - runs-on: ubuntu-latest - steps: - - name: Notify Clio - env: - GH_TOKEN: ${{ secrets.clio_notify_token }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: | - gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ - -F "client_payload[conan_ref]=${{ needs.upload.outputs.conan_ref }}" \ - -F "client_payload[pr_url]=${PR_URL}" diff --git a/.github/workflows/reusable-strategy-matrix.yml b/.github/workflows/reusable-strategy-matrix.yml index 129f65938b..c975347307 100644 --- a/.github/workflows/reusable-strategy-matrix.yml +++ b/.github/workflows/reusable-strategy-matrix.yml @@ -18,6 +18,10 @@ on: description: "The generated strategy matrix." value: ${{ jobs.generate-matrix.outputs.matrix }} +defaults: + run: + shell: bash + jobs: generate-matrix: runs-on: ubuntu-latest diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml deleted file mode 100644 index 8d4a4a8d33..0000000000 --- a/.github/workflows/reusable-test.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Test rippled - -on: - workflow_call: - inputs: - verify_voidstar: - description: "Whether to verify the presence of voidstar instrumentation." - required: true - type: boolean - run_tests: - description: "Whether to run unit tests" - required: true - type: boolean - - runs_on: - description: Runner to run the job on as a JSON string - required: true - type: string - image: - description: "The image to run in (leave empty to run natively)" - required: true - type: string - - config_name: - description: "The name of the configuration." - required: true - type: string - - nproc_subtract: - description: "The number of processors to subtract when calculating parallelism." - required: true - type: number - -jobs: - test: - name: Test ${{ inputs.config_name }} - runs-on: ${{ fromJSON(inputs.runs_on) }} - container: ${{ inputs.image != '' && inputs.image || null }} - timeout-minutes: 30 - steps: - - name: Cleanup workspace - if: ${{ runner.os == 'macOS' }} - uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e - - - name: Get number of processors - uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a - id: nproc - with: - subtract: ${{ inputs.nproc_subtract }} - - - name: Download rippled artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: rippled-${{ inputs.config_name }} - - - name: Make binary executable (Linux and macOS) - shell: bash - if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} - run: | - chmod +x ./rippled - - - name: Check linking (Linux) - if: ${{ runner.os == 'Linux' }} - shell: bash - run: | - ldd ./rippled - if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then - echo 'The binary is statically linked.' - else - echo 'The binary is dynamically linked.' - exit 1 - fi - - - name: Verifying presence of instrumentation - if: ${{ inputs.verify_voidstar }} - shell: bash - run: | - ./rippled --version | grep libvoidstar - - - name: Run the embedded tests - if: ${{ inputs.run_tests }} - shell: bash - env: - BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} - run: | - ./rippled --unittest --unittest-jobs ${BUILD_NPROC} - - - name: Run the separate tests - if: ${{ inputs.run_tests }} - env: - EXT: ${{ runner.os == 'Windows' && '.exe' || '' }} - shell: bash - run: | - for test_file in ./doctest/*${EXT}; do - echo "Executing $test_file" - chmod +x "$test_file" - if [[ "${{ runner.os }}" == "Windows" && "$test_file" == "./doctest/xrpl.test.net.exe" ]]; then - echo "Skipping $test_file on Windows" - else - "$test_file" - fi - done - - - name: Debug failure (Linux) - if: ${{ failure() && runner.os == 'Linux' && inputs.run_tests }} - shell: bash - run: | - echo "IPv4 local port range:" - cat /proc/sys/net/ipv4/ip_local_port_range - echo "Netstat:" - netstat -an diff --git a/.github/workflows/reusable-upload-recipe.yml b/.github/workflows/reusable-upload-recipe.yml new file mode 100644 index 0000000000..79af516fb3 --- /dev/null +++ b/.github/workflows/reusable-upload-recipe.yml @@ -0,0 +1,97 @@ +# This workflow exports the built libxrpl package to the Conan remote. +name: Upload Conan recipe + +# This workflow can only be triggered by other workflows. +on: + workflow_call: + inputs: + remote_name: + description: "The name of the Conan remote to use." + required: false + type: string + default: xrplf + remote_url: + description: "The URL of the Conan endpoint to use." + required: false + type: string + default: https://conan.ripplex.io + + secrets: + remote_username: + description: "The username for logging into the Conan remote." + required: true + remote_password: + description: "The password for logging into the Conan remote." + required: true + + outputs: + recipe_ref: + description: "The Conan recipe reference ('name/version') that was uploaded." + value: ${{ jobs.upload.outputs.ref }} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-upload-recipe + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + upload: + runs-on: ubuntu-latest + container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158 + steps: + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + + - name: Generate build version number + id: version + uses: ./.github/actions/generate-version + + - name: Set up Conan + uses: ./.github/actions/setup-conan + with: + remote_name: ${{ inputs.remote_name }} + remote_url: ${{ inputs.remote_url }} + + - name: Log into Conan remote + env: + REMOTE_NAME: ${{ inputs.remote_name }} + REMOTE_USERNAME: ${{ secrets.remote_username }} + REMOTE_PASSWORD: ${{ secrets.remote_password }} + run: conan remote login "${REMOTE_NAME}" "${REMOTE_USERNAME}" --password "${REMOTE_PASSWORD}" + + - name: Upload Conan recipe (version) + env: + REMOTE_NAME: ${{ inputs.remote_name }} + run: | + conan export . --version=${{ steps.version.outputs.version }} + conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }} + + - name: Upload Conan recipe (develop) + if: ${{ github.ref == 'refs/heads/develop' }} + env: + REMOTE_NAME: ${{ inputs.remote_name }} + run: | + conan export . --version=develop + conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop + + - name: Upload Conan recipe (rc) + if: ${{ startsWith(github.ref, 'refs/heads/release') }} + env: + REMOTE_NAME: ${{ inputs.remote_name }} + run: | + conan export . --version=rc + conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc + + - name: Upload Conan recipe (release) + if: ${{ github.event_name == 'tag' }} + env: + REMOTE_NAME: ${{ inputs.remote_name }} + run: | + conan export . --version=release + conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release + + outputs: + ref: xrpl/${{ steps.version.outputs.version }} diff --git a/.github/workflows/upload-conan-deps.yml b/.github/workflows/upload-conan-deps.yml index f6262a2f1f..60696a9769 100644 --- a/.github/workflows/upload-conan-deps.yml +++ b/.github/workflows/upload-conan-deps.yml @@ -40,6 +40,10 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +defaults: + run: + shell: bash + jobs: # Generate the strategy matrix to be used by the following job. generate-matrix: @@ -58,43 +62,45 @@ jobs: runs-on: ${{ matrix.architecture.runner }} container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || null }} steps: - - name: Cleanup workspace - if: ${{ runner.os == 'macOS' }} - uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e + - name: Cleanup workspace (macOS and Windows) + if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} + uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf - name: Checkout repository uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Prepare runner - uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a + uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d with: - disable_ccache: false + enable_ccache: false - name: Print build environment uses: ./.github/actions/print-env - name: Get number of processors - uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a + uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf id: nproc with: subtract: ${{ env.NPROC_SUBTRACT }} - name: Setup Conan + env: + SANITIZERS: ${{ matrix.sanitizers }} uses: ./.github/actions/setup-conan with: - conan_remote_name: ${{ env.CONAN_REMOTE_NAME }} - conan_remote_url: ${{ env.CONAN_REMOTE_URL }} + remote_name: ${{ env.CONAN_REMOTE_NAME }} + remote_url: ${{ env.CONAN_REMOTE_URL }} - name: Build dependencies uses: ./.github/actions/build-deps with: - build_dir: .build build_nproc: ${{ steps.nproc.outputs.nproc }} build_type: ${{ matrix.build_type }} force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }} # Set the verbosity to "quiet" for Windows to avoid an excessive # amount of logs. For other OSes, the "verbose" logs are more useful. log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }} + sanitizers: ${{ matrix.sanitizers }} - name: Log into Conan remote if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} diff --git a/.gitignore b/.gitignore index 5476f21a41..2692d707e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,69 +1,48 @@ # .gitignore +# cspell: disable -bin/boostbook_catalog.xml -bin/config.log -bin/project-cache.jam - -# Ignore vim swap files. -*.swp - -# Ignore SCons support files. -.sconsign.dblite - -# Ignore python compiled files. -*.pyc - -# Ignore Macintosh Desktop Services Store files. +# Macintosh Desktop Services Store files. .DS_Store -# Ignore backup/temps +# Build, intermediate, and temporary artifacts. *~ - -# Ignore object files. *.o -.nih_c -tags -TAGS -GTAGS -GRTAGS -GPATH -bin/rippled -Debug/*.* -Release/*.* +*.pdb +*.swp +/.clangd +Debug/ +Release/ +/.build/ +/build/ +/db/ +/out.txt +/Testing/ +/tmp/ +CMakeSettings.json +CMakeUserPresets.json -# Ignore coverage files. +# Coverage files. *.gcno *.gcda *.gcov -# Levelization checking +# Profiling data. +gmon.out + +# Levelization data. .github/scripts/levelization/results/* !.github/scripts/levelization/results/loops.txt !.github/scripts/levelization/results/ordering.txt -# Ignore tmp directory. -tmp +# Customized configs. +/rippled.cfg +/xrpld.cfg +/validators.txt -# Ignore database directory. -db/ -db/*.db -db/*.db-* +# Locally patched Conan recipes +external/conan-center-index/ -# Ignore debug logs -debug_log.txt - -# Ignore customized configs -rippled.cfg -validators.txt - -# Doxygen generated documentation output -HtmlDocumentation -docs/html_doc - -# Xcode user-specific project settings -# Xcode -.DS_Store -/build/ +# XCode IDE. *.pbxuser !default.pbxuser *.mode1v3 @@ -76,38 +55,19 @@ xcuserdata profile *.moved-aside DerivedData -.idea/ *.hmap -# Intel Parallel Studio 2013 XE -My Amplifier XE Results - RippleD +# JetBrains IDE. +/.idea/ -# Compiler intermediate output -/out.txt +# Microsoft Visual Studio IDE. +/.vs/ +/.vscode/ -# Build Log -rippled-build.log +# zed IDE. +/.zed/ -# Profiling data -gmon.out - -Builds/VisualStudio2015/*.db -Builds/VisualStudio2015/*.user -Builds/VisualStudio2015/*.opendb -Builds/VisualStudio2015/*.sdf - -# MSVC -*.pdb -.vs/ -CMakeSettings.json -compile_commands.json -.clangd -packages -pkg_out -pkg -CMakeUserPresets.json -bld.rippled/ -.vscode - -# Suggested in-tree build directory -/.build*/ +# AI tools. +/.augment +/.claude +/CLAUDE.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85568a8b2e..79a3e4e7ec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,14 +26,39 @@ repos: args: [--style=file] "types_or": [c++, c, proto] + - repo: https://github.com/cheshirekow/cmake-format-precommit + rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 # frozen: v0.6.13 + hooks: + - id: cmake-format + additional_dependencies: [PyYAML] + - repo: https://github.com/rbubley/mirrors-prettier rev: 5ba47274f9b181bce26a5150a725577f3c336011 # frozen: v3.6.2 hooks: - id: prettier + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 831207fd435b47aeffdf6af853097e64322b4d44 # frozen: v25.12.0 + hooks: + - id: black + + - repo: https://github.com/streetsidesoftware/cspell-cli + rev: 1cfa010f078c354f3ffb8413616280cc28f5ba21 # frozen: v9.4.0 + hooks: + - id: cspell # Spell check changed files + exclude: .config/cspell.config.yaml + - id: cspell # Spell check the commit message + name: check commit message spelling + args: + - --no-must-find-files + - --no-progress + - --no-summary + - --files + - .git/COMMIT_EDITMSG + stages: [commit-msg] + exclude: | (?x)^( external/.*| - .github/scripts/levelization/results/.*\.txt| - conan\.lock + .github/scripts/levelization/results/.*\.txt )$ diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index dd3fcd018b..c7a31d27fa 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -6,90 +6,85 @@ For info about how [API versioning](https://xrpl.org/request-formatting.html#api The API version controls the API behavior you see. This includes what properties you see in responses, what parameters you're permitted to send in requests, and so on. You specify the API version in each of your requests. When a breaking change is introduced to the `rippled` API, a new version is released. To avoid breaking your code, you should set (or increase) your version when you're ready to upgrade. +The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conventions/request-formatting/#commandline-format) always uses the latest API version. The command line is intended for ad-hoc usage by humans, not programs or automated scripts. The command line is not meant for use in production code. + For a log of breaking changes, see the **API Version [number]** headings. In general, breaking changes are associated with a particular API Version number. For non-breaking changes, scroll to the **XRP Ledger version [x.y.z]** headings. Non-breaking changes are associated with a particular XRP Ledger (`rippled`) release. +## API Version 3 (Beta) + +API version 3 is currently a beta API. It requires enabling `[beta_rpc_api]` in the rippled configuration to use. See [API-VERSION-3.md](API-VERSION-3.md) for the full list of changes in API version 3. + ## API Version 2 -API version 2 is available in `rippled` version 2.0.0 and later. To use this API, clients specify `"api_version" : 2` in each request. - -#### Removed methods - -In API version 2, the following deprecated methods are no longer available: (https://github.com/XRPLF/rippled/pull/4759) - -- `tx_history` - Instead, use other methods such as `account_tx` or `ledger` with the `transactions` field set to `true`. -- `ledger_header` - Instead, use the `ledger` method. - -#### Modifications to JSON transaction element in V2 - -In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. (https://github.com/XRPLF/rippled/pull/4775) -This helps to unify the JSON serialization format of transactions. (https://github.com/XRPLF/clio/issues/722, https://github.com/XRPLF/rippled/issues/4727) - -- JSON transaction element is named `tx_json` -- Binary transaction element is named `tx_blob` -- JSON transaction metadata element is named `meta` -- Binary transaction metadata element is named `meta_blob` - -Additionally, these elements are now consistently available next to `tx_json` (i.e. sibling elements), where possible: - -- `hash` - Transaction ID. This data was stored inside transaction output in API version 1, but in API version 2 is a sibling element. -- `ledger_index` - Ledger index (only set on validated ledgers) -- `ledger_hash` - Ledger hash (only set on closed or validated ledgers) -- `close_time_iso` - Ledger close time expressed in ISO 8601 time format (only set on validated ledgers) -- `validated` - Bool element set to `true` if the transaction is in a validated ledger, otherwise `false` - -This change affects the following methods: - -- `tx` - Transaction data moved into element `tx_json` (was inline inside `result`) or, if binary output was requested, moved from `tx` to `tx_blob`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements -- `account_tx` - Renamed transaction element from `tx` to `tx_json`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements -- `transaction_entry` - Renamed transaction metadata element from `metadata` to `meta`. Changed location of `hash` and added new elements -- `subscribe` - Renamed transaction element from `transaction` to `tx_json`. Changed location of `hash` and added new elements -- `sign`, `sign_for`, `submit` and `submit_multisigned` - Changed location of `hash` element. - -#### Modification to `Payment` transaction JSON schema - -When reading Payments, the `Amount` field should generally **not** be used. Instead, use [delivered_amount](https://xrpl.org/partial-payments.html#the-delivered_amount-field) to see the amount that the Payment delivered. To clarify its meaning, the `Amount` field is being renamed to `DeliverMax`. (https://github.com/XRPLF/rippled/pull/4733) - -- In `Payment` transaction type, JSON RPC field `Amount` is renamed to `DeliverMax`. To enable smooth client transition, `Amount` is still handled, as described below: (https://github.com/XRPLF/rippled/pull/4733) - - On JSON RPC input (e.g. `submit_multisigned` etc. methods), `Amount` is recognized as an alias to `DeliverMax` for both API version 1 and version 2 clients. - - On JSON RPC input, submitting both `Amount` and `DeliverMax` fields is allowed _only_ if they are identical; otherwise such input is rejected with `rpcINVALID_PARAMS` error. - - On JSON RPC output (e.g. `subscribe`, `account_tx` etc. methods), `DeliverMax` is present in both API version 1 and version 2. - - On JSON RPC output, `Amount` is only present in API version 1 and _not_ in version 2. - -#### Modifications to account_info response - -- `signer_lists` is returned in the root of the response. (In API version 1, it was nested under `account_data`.) (https://github.com/XRPLF/rippled/pull/3770) -- When using an invalid `signer_lists` value, the API now returns an "invalidParams" error. (https://github.com/XRPLF/rippled/pull/4585) - - (`signer_lists` must be a boolean. In API version 1, strings were accepted and may return a normal response - i.e. as if `signer_lists` were `true`.) - -#### Modifications to [account_tx](https://xrpl.org/account_tx.html#account_tx) response - -- Using `ledger_index_min`, `ledger_index_max`, and `ledger_index` returns `invalidParams` because if you use `ledger_index_min` or `ledger_index_max`, then it does not make sense to also specify `ledger_index`. In API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4571) - - The same applies for `ledger_index_min`, `ledger_index_max`, and `ledger_hash`. (https://github.com/XRPLF/rippled/issues/4545#issuecomment-1565065579) -- Using a `ledger_index_min` or `ledger_index_max` beyond the range of ledgers that the server has: - - returns `lgrIdxMalformed` in API version 2. Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/issues/4288) -- Attempting to use a non-boolean value (such as a string) for the `binary` or `forward` parameters returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) - -#### Modifications to [noripple_check](https://xrpl.org/noripple_check.html#noripple_check) response - -- Attempting to use a non-boolean value (such as a string) for the `transactions` parameter returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) +API version 2 is available in `rippled` version 2.0.0 and later. See [API-VERSION-2.md](API-VERSION-2.md) for the full list of changes in API version 2. ## API Version 1 This version is supported by all `rippled` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified. -The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conventions/request-formatting/#commandline-format) always uses the latest API version. The command line is intended for ad-hoc usage by humans, not programs or automated scripts. The command line is not meant for use in production code. +## XRP Ledger server version 3.1.0 -### Inconsistency: server_info - network_id +[Version 3.1.0](https://github.com/XRPLF/rippled/releases/tag/3.1.0) was released on Jan 27, 2026. -The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. +### Additions in 3.1.0 + +- `vault_info`: New RPC method to retrieve information about a specific vault (part of XLS-66 Lending Protocol). ([#6156](https://github.com/XRPLF/rippled/pull/6156)) + +## XRP Ledger server version 3.0.0 + +[Version 3.0.0](https://github.com/XRPLF/rippled/releases/tag/3.0.0) was released on Dec 9, 2025. + +### Additions in 3.0.0 + +- `ledger_entry`: Supports all ledger entry types with dedicated parsers. ([#5237](https://github.com/XRPLF/rippled/pull/5237)) +- `ledger_entry`: New error codes `entryNotFound` and `unexpectedLedgerType` for more specific error handling. ([#5237](https://github.com/XRPLF/rippled/pull/5237)) +- `ledger_entry`: Improved error messages with more context (e.g., specifying which field is invalid or missing). ([#5237](https://github.com/XRPLF/rippled/pull/5237)) +- `ledger_entry`: Assorted bug fixes in RPC processing. ([#5237](https://github.com/XRPLF/rippled/pull/5237)) +- `simulate`: Supports additional metadata in the response. ([#5754](https://github.com/XRPLF/rippled/pull/5754)) + +## XRP Ledger server version 2.6.2 + +[Version 2.6.2](https://github.com/XRPLF/rippled/releases/tag/2.6.2) was released on Nov 19, 2025. + +This release contains bug fixes only and no API changes. + +## XRP Ledger server version 2.6.1 + +[Version 2.6.1](https://github.com/XRPLF/rippled/releases/tag/2.6.1) was released on Sep 30, 2025. + +This release contains bug fixes only and no API changes. + +## XRP Ledger server version 2.6.0 + +[Version 2.6.0](https://github.com/XRPLF/rippled/releases/tag/2.6.0) was released on Aug 27, 2025. + +### Additions in 2.6.0 + +- `account_info`: Added `allowTrustLineLocking` flag in response. ([#5525](https://github.com/XRPLF/rippled/pull/5525)) +- `ledger`: Removed the type filter from the RPC command. ([#4934](https://github.com/XRPLF/rippled/pull/4934)) +- `subscribe` (`validations` stream): `network_id` is now included. ([#5579](https://github.com/XRPLF/rippled/pull/5579)) +- `subscribe` (`transactions` stream): `nftoken_id`, `nftoken_ids`, and `offer_id` are now included in transaction metadata. ([#5230](https://github.com/XRPLF/rippled/pull/5230)) + +## XRP Ledger server version 2.5.1 + +[Version 2.5.1](https://github.com/XRPLF/rippled/releases/tag/2.5.1) was released on Sep 17, 2025. + +This release contains bug fixes only and no API changes. ## XRP Ledger server version 2.5.0 -As of 2025-04-04, version 2.5.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu). +[Version 2.5.0](https://github.com/XRPLF/rippled/releases/tag/2.5.0) was released on Jun 24, 2025. ### Additions and bugfixes in 2.5.0 -- `channel_authorize`: If `signing_support` is not enabled in the config, the RPC is disabled. +- `tx`: Added `ctid` field to the response and improved error handling. ([#4738](https://github.com/XRPLF/rippled/pull/4738)) +- `ledger_entry`: Improved error messages in `permissioned_domain`. ([#5344](https://github.com/XRPLF/rippled/pull/5344)) +- `simulate`: Improved multi-sign usage. ([#5479](https://github.com/XRPLF/rippled/pull/5479)) +- `channel_authorize`: If `signing_support` is not enabled in the config, the RPC is disabled. ([#5385](https://github.com/XRPLF/rippled/pull/5385)) +- `subscribe` (admin): Removed webhook queue limit to prevent dropping notifications; reduced HTTP timeout from 10 minutes to 30 seconds. ([#5163](https://github.com/XRPLF/rippled/pull/5163)) +- `ledger_data` (gRPC): Fixed crashing issue with some invalid markers. ([#5137](https://github.com/XRPLF/rippled/pull/5137)) +- `account_lines`: Fixed error with `no_ripple` and `no_ripple_peer` sometimes showing up incorrectly. ([#5345](https://github.com/XRPLF/rippled/pull/5345)) +- `account_tx`: Fixed issue with incorrect CTIDs. ([#5408](https://github.com/XRPLF/rippled/pull/5408)) ## XRP Ledger server version 2.4.0 @@ -97,11 +92,19 @@ As of 2025-04-04, version 2.5.0 is in development. You can use a pre-release ver ### Additions and bugfixes in 2.4.0 -- `ledger_entry`: `state` is added an alias for `ripple_state`. -- `ledger_entry`: Enables case-insensitive filtering by canonical name in addition to case-sensitive filtering by RPC name. -- `validators`: Added new field `validator_list_threshold` in response. -- `simulate`: A new RPC that executes a [dry run of a transaction submission](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069d-simulate#2-rpc-simulate) -- Signing methods autofill fees better and properly handle transactions that don't have a base fee, and will also autofill the `NetworkID` field. +- `simulate`: A new RPC that executes a [dry run of a transaction submission](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069d-simulate#2-rpc-simulate). ([#5069](https://github.com/XRPLF/rippled/pull/5069)) +- Signing methods (`sign`, `sign_for`, `submit`): Autofill fees better, properly handle transactions without a base fee, and autofill the `NetworkID` field. ([#5069](https://github.com/XRPLF/rippled/pull/5069)) +- `ledger_entry`: `state` is added as an alias for `ripple_state`. ([#5199](https://github.com/XRPLF/rippled/pull/5199)) +- `ledger`, `ledger_data`, `account_objects`: Support filtering ledger entry types by their canonical names (case-insensitive). ([#5271](https://github.com/XRPLF/rippled/pull/5271)) +- `validators`: Added new field `validator_list_threshold` in response. ([#5112](https://github.com/XRPLF/rippled/pull/5112)) +- `server_info`: Added git commit hash info on admin connection. ([#5225](https://github.com/XRPLF/rippled/pull/5225)) +- `server_definitions`: Changed larger `UInt` serialized types to `Hash`. ([#5231](https://github.com/XRPLF/rippled/pull/5231)) + +## XRP Ledger server version 2.3.1 + +[Version 2.3.1](https://github.com/XRPLF/rippled/releases/tag/2.3.1) was released on Jan 29, 2025. + +This release contains bug fixes only and no API changes. ## XRP Ledger server version 2.3.0 @@ -109,19 +112,30 @@ As of 2025-04-04, version 2.5.0 is in development. You can use a pre-release ver ### Breaking changes in 2.3.0 -- `book_changes`: If the requested ledger version is not available on this node, a `ledgerNotFound` error is returned and the node does not attempt to acquire the ledger from the p2p network (as with other non-admin RPCs). - -Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. +- `book_changes`: If the requested ledger version is not available on this node, a `ledgerNotFound` error is returned and the node does not attempt to acquire the ledger from the p2p network (as with other non-admin RPCs). Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. ### Additions and bugfixes in 2.3.0 -- `book_changes`: Returns a `validated` field in its response, which was missing in prior versions. +- `book_changes`: Returns a `validated` field in its response. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) +- `book_changes`: Accepts shortcut strings (`current`, `closed`, `validated`) for the `ledger_index` parameter. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) +- `server_definitions`: Include `index` in response. ([#5190](https://github.com/XRPLF/rippled/pull/5190)) +- `account_nfts`: Fix issue where unassociated marker would return incorrect results. ([#5045](https://github.com/XRPLF/rippled/pull/5045)) +- `account_objects`: Fix issue where invalid marker would not return an error. ([#5046](https://github.com/XRPLF/rippled/pull/5046)) +- `account_objects`: Disallow filtering by ledger entry types that an account cannot hold. ([#5056](https://github.com/XRPLF/rippled/pull/5056)) +- `tx`: Allow lowercase CTID. ([#5049](https://github.com/XRPLF/rippled/pull/5049)) +- `feature`: Better error handling for invalid values of `feature`. ([#5063](https://github.com/XRPLF/rippled/pull/5063)) ## XRP Ledger server version 2.2.0 [Version 2.2.0](https://github.com/XRPLF/rippled/releases/tag/2.2.0) was released on Jun 5, 2024. The following additions are non-breaking (because they are purely additive): -- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) +- `feature`: Add a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) + +## XRP Ledger server version 2.0.1 + +[Version 2.0.1](https://github.com/XRPLF/rippled/releases/tag/2.0.1) was released on Jan 29, 2024. The following additions are non-breaking: + +- `path_find`: Fixes unbounded memory growth. ([#4822](https://github.com/XRPLF/rippled/pull/4822)) ## XRP Ledger server version 2.0.0 @@ -129,24 +143,18 @@ Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. - `server_definitions`: A new RPC that generates a `definitions.json`-like output that can be used in XRPL libraries. - In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking. -- API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting). - -## XRP Ledger server version 2.2.0 - -The following is a non-breaking addition to the API. - -- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) +- API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting). The full list of changes is in [API-VERSION-2.md](API-VERSION-2.md). ## XRP Ledger server version 1.12.0 -[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive). +[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive): -- `server_info`: Added `ports`, an array which advertises the RPC and WebSocket ports. This information is also included in the `/crawl` endpoint (which calls `server_info` internally). `grpc` and `peer` ports are also included. (https://github.com/XRPLF/rippled/pull/4427) +- `server_info`: Added `ports`, an array which advertises the RPC and WebSocket ports. This information is also included in the `/crawl` endpoint (which calls `server_info` internally). `grpc` and `peer` ports are also included. ([#4427](https://github.com/XRPLF/rippled/pull/4427)) - `ports` contains objects, each containing a `port` for the listening port (a number string), and a `protocol` array listing the supported protocols on that port. - This allows crawlers to build a more detailed topology without needing to port-scan nodes. - (For peers and other non-admin clients, the info about admin ports is excluded.) -- Clawback: The following additions are gated by the Clawback amendment (`featureClawback`). (https://github.com/XRPLF/rippled/pull/4553) - - Adds an [AccountRoot flag](https://xrpl.org/accountroot.html#accountroot-flags) called `lsfAllowTrustLineClawback` (https://github.com/XRPLF/rippled/pull/4617) +- Clawback: The following additions are gated by the Clawback amendment (`featureClawback`). ([#4553](https://github.com/XRPLF/rippled/pull/4553)) + - Adds an [AccountRoot flag](https://xrpl.org/accountroot.html#accountroot-flags) called `lsfAllowTrustLineClawback`. ([#4617](https://github.com/XRPLF/rippled/pull/4617)) - Adds the corresponding `asfAllowTrustLineClawback` [AccountSet Flag](https://xrpl.org/accountset.html#accountset-flags) as well. - Clawback is disabled by default, so if an issuer desires the ability to claw back funds, they must use an `AccountSet` transaction to set the AllowTrustLineClawback flag. They must do this before creating any trust lines, offers, escrows, payment channels, or checks. - Adds the [Clawback transaction type](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-39d-clawback/README.md#331-clawback-transaction), containing these fields: @@ -181,16 +189,16 @@ The following is a non-breaking addition to the API. ### Breaking changes in 1.11 -- Added the ability to mark amendments as obsolete. For the `feature` admin API, there is a new possible value for the `vetoed` field. (https://github.com/XRPLF/rippled/pull/4291) +- Added the ability to mark amendments as obsolete. For the `feature` admin API, there is a new possible value for the `vetoed` field. ([#4291](https://github.com/XRPLF/rippled/pull/4291)) - The value of `vetoed` can now be `true`, `false`, or `"Obsolete"`. -- Removed the acceptance of seeds or public keys in place of account addresses. (https://github.com/XRPLF/rippled/pull/4404) +- Removed the acceptance of seeds or public keys in place of account addresses. ([#4404](https://github.com/XRPLF/rippled/pull/4404)) - This simplifies the API and encourages better security practices (i.e. seeds should never be sent over the network). -- For the `ledger_data` method, when all entries are filtered out, the `state` field of the response is now an empty list (in other words, an empty array, `[]`). (Previously, it would return `null`.) While this is technically a breaking change, the new behavior is consistent with the documentation, so this is considered only a bug fix. (https://github.com/XRPLF/rippled/pull/4398) +- For the `ledger_data` method, when all entries are filtered out, the `state` field of the response is now an empty list (in other words, an empty array, `[]`). (Previously, it would return `null`.) While this is technically a breaking change, the new behavior is consistent with the documentation, so this is considered only a bug fix. ([#4398](https://github.com/XRPLF/rippled/pull/4398)) - If and when the `fixNFTokenRemint` amendment activates, there will be a new AccountRoot field, `FirstNFTSequence`. This field is set to the current account sequence when the account issues their first NFT. If an account has not issued any NFTs, then the field is not set. ([#4406](https://github.com/XRPLF/rippled/pull/4406)) - There is a new account deletion restriction: an account can only be deleted if `FirstNFTSequence` + `MintedNFTokens` + `256` is less than the current ledger sequence. - This is potentially a breaking change if clients have logic for determining whether an account can be deleted. - NetworkID - - For sidechains and networks with a network ID greater than 1024, there is a new [transaction common field](https://xrpl.org/transaction-common-fields.html), `NetworkID`. (https://github.com/XRPLF/rippled/pull/4370) + - For sidechains and networks with a network ID greater than 1024, there is a new [transaction common field](https://xrpl.org/transaction-common-fields.html), `NetworkID`. ([#4370](https://github.com/XRPLF/rippled/pull/4370)) - This field helps to prevent replay attacks and is now required for chains whose network ID is 1025 or higher. - The field must be omitted for Mainnet, so there is no change for Mainnet users. - There are three new local error codes: @@ -200,10 +208,10 @@ The following is a non-breaking addition to the API. ### Additions and bug fixes in 1.11 -- Added `nftoken_id`, `nftoken_ids` and `offer_id` meta fields into NFT `tx` and `account_tx` responses. (https://github.com/XRPLF/rippled/pull/4447) -- Added an `account_flags` object to the `account_info` method response. (https://github.com/XRPLF/rippled/pull/4459) -- Added `NFTokenPages` to the `account_objects` RPC. (https://github.com/XRPLF/rippled/pull/4352) -- Fixed: `marker` returned from the `account_lines` command would not work on subsequent commands. (https://github.com/XRPLF/rippled/pull/4361) +- Added `nftoken_id`, `nftoken_ids` and `offer_id` meta fields into NFT `tx` and `account_tx` responses. ([#4447](https://github.com/XRPLF/rippled/pull/4447)) +- Added an `account_flags` object to the `account_info` method response. ([#4459](https://github.com/XRPLF/rippled/pull/4459)) +- Added `NFTokenPages` to the `account_objects` RPC. ([#4352](https://github.com/XRPLF/rippled/pull/4352)) +- Fixed: `marker` returned from the `account_lines` command would not work on subsequent commands. ([#4361](https://github.com/XRPLF/rippled/pull/4361)) ## XRP Ledger server version 1.10.0 diff --git a/API-VERSION-2.md b/API-VERSION-2.md new file mode 100644 index 0000000000..2296795271 --- /dev/null +++ b/API-VERSION-2.md @@ -0,0 +1,66 @@ +# API Version 2 + +API version 2 is available in `rippled` version 2.0.0 and later. To use this API, clients specify `"api_version" : 2` in each request. + +For info about how [API versioning](https://xrpl.org/request-formatting.html#api-versioning) works, including examples, please view the [XLS-22d spec](https://github.com/XRPLF/XRPL-Standards/discussions/54). For details about the implementation of API versioning, view the [implementation PR](https://github.com/XRPLF/rippled/pull/3155). API versioning ensures existing integrations and users continue to receive existing behavior, while those that request a higher API version will experience new behavior. + +## Removed methods + +In API version 2, the following deprecated methods are no longer available: ([#4759](https://github.com/XRPLF/rippled/pull/4759)) + +- `tx_history` - Instead, use other methods such as `account_tx` or `ledger` with the `transactions` field set to `true`. +- `ledger_header` - Instead, use the `ledger` method. + +## Modifications to JSON transaction element in API version 2 + +In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. ([#4775](https://github.com/XRPLF/rippled/pull/4775)) +This helps to unify the JSON serialization format of transactions. ([clio#722](https://github.com/XRPLF/clio/issues/722), [#4727](https://github.com/XRPLF/rippled/issues/4727)) + +- JSON transaction element is named `tx_json` +- Binary transaction element is named `tx_blob` +- JSON transaction metadata element is named `meta` +- Binary transaction metadata element is named `meta_blob` + +Additionally, these elements are now consistently available next to `tx_json` (i.e. sibling elements), where possible: + +- `hash` - Transaction ID. This data was stored inside transaction output in API version 1, but in API version 2 is a sibling element. +- `ledger_index` - Ledger index (only set on validated ledgers) +- `ledger_hash` - Ledger hash (only set on closed or validated ledgers) +- `close_time_iso` - Ledger close time expressed in ISO 8601 time format (only set on validated ledgers) +- `validated` - Bool element set to `true` if the transaction is in a validated ledger, otherwise `false` + +This change affects the following methods: + +- `tx` - Transaction data moved into element `tx_json` (was inline inside `result`) or, if binary output was requested, moved from `tx` to `tx_blob`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `account_tx` - Renamed transaction element from `tx` to `tx_json`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `transaction_entry` - Renamed transaction metadata element from `metadata` to `meta`. Changed location of `hash` and added new elements +- `subscribe` - Renamed transaction element from `transaction` to `tx_json`. Changed location of `hash` and added new elements +- `sign`, `sign_for`, `submit` and `submit_multisigned` - Changed location of `hash` element. + +## Modifications to `Payment` transaction JSON schema + +When reading Payments, the `Amount` field should generally **not** be used. Instead, use [delivered_amount](https://xrpl.org/partial-payments.html#the-delivered_amount-field) to see the amount that the Payment delivered. To clarify its meaning, the `Amount` field is being renamed to `DeliverMax`. ([#4733](https://github.com/XRPLF/rippled/pull/4733)) + +- In `Payment` transaction type, JSON RPC field `Amount` is renamed to `DeliverMax`. To enable smooth client transition, `Amount` is still handled, as described below: ([#4733](https://github.com/XRPLF/rippled/pull/4733)) + - On JSON RPC input (e.g. `submit_multisigned` etc. methods), `Amount` is recognized as an alias to `DeliverMax` for both API version 1 and version 2 clients. + - On JSON RPC input, submitting both `Amount` and `DeliverMax` fields is allowed _only_ if they are identical; otherwise such input is rejected with `rpcINVALID_PARAMS` error. + - On JSON RPC output (e.g. `subscribe`, `account_tx` etc. methods), `DeliverMax` is present in both API version 1 and version 2. + - On JSON RPC output, `Amount` is only present in API version 1 and _not_ in version 2. + +## Modifications to account_info response + +- `signer_lists` is returned in the root of the response. (In API version 1, it was nested under `account_data`.) ([#3770](https://github.com/XRPLF/rippled/pull/3770)) +- When using an invalid `signer_lists` value, the API now returns an "invalidParams" error. ([#4585](https://github.com/XRPLF/rippled/pull/4585)) + - (`signer_lists` must be a boolean. In API version 1, strings were accepted and may return a normal response - i.e. as if `signer_lists` were `true`.) + +## Modifications to [account_tx](https://xrpl.org/account_tx.html#account_tx) response + +- Using `ledger_index_min`, `ledger_index_max`, and `ledger_index` returns `invalidParams` because if you use `ledger_index_min` or `ledger_index_max`, then it does not make sense to also specify `ledger_index`. In API version 1, no error was returned. ([#4571](https://github.com/XRPLF/rippled/pull/4571)) + - The same applies for `ledger_index_min`, `ledger_index_max`, and `ledger_hash`. ([#4545](https://github.com/XRPLF/rippled/issues/4545#issuecomment-1565065579)) +- Using a `ledger_index_min` or `ledger_index_max` beyond the range of ledgers that the server has: + - returns `lgrIdxMalformed` in API version 2. Previously, in API version 1, no error was returned. ([#4288](https://github.com/XRPLF/rippled/issues/4288)) +- Attempting to use a non-boolean value (such as a string) for the `binary` or `forward` parameters returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. ([#4620](https://github.com/XRPLF/rippled/pull/4620)) + +## Modifications to [noripple_check](https://xrpl.org/noripple_check.html#noripple_check) response + +- Attempting to use a non-boolean value (such as a string) for the `transactions` parameter returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. ([#4620](https://github.com/XRPLF/rippled/pull/4620)) diff --git a/API-VERSION-3.md b/API-VERSION-3.md new file mode 100644 index 0000000000..46dc3f504d --- /dev/null +++ b/API-VERSION-3.md @@ -0,0 +1,27 @@ +# API Version 3 + +API version 3 is currently a **beta API**. It requires enabling `[beta_rpc_api]` in the rippled configuration to use. To use this API, clients specify `"api_version" : 3` in each request. + +For info about how [API versioning](https://xrpl.org/request-formatting.html#api-versioning) works, including examples, please view the [XLS-22d spec](https://github.com/XRPLF/XRPL-Standards/discussions/54). For details about the implementation of API versioning, view the [implementation PR](https://github.com/XRPLF/rippled/pull/3155). API versioning ensures existing integrations and users continue to receive existing behavior, while those that request a higher API version will experience new behavior. + +## Breaking Changes + +### Modifications to `amm_info` + +The order of error checks has been changed to provide more specific error messages. ([#4924](https://github.com/XRPLF/rippled/pull/4924)) + +- **Before (API v2)**: When sending an invalid account or asset to `amm_info` while other parameters are not set as expected, the method returns a generic `rpcINVALID_PARAMS` error. +- **After (API v3)**: The same scenario returns a more specific error: `rpcISSUE_MALFORMED` for malformed assets or `rpcACT_MALFORMED` for malformed accounts. + +### Modifications to `ledger_entry` + +Added support for string shortcuts to look up fixed-location ledger entries using the `"index"` parameter. ([#5644](https://github.com/XRPLF/rippled/pull/5644)) + +In API version 3, the following string values can be used with the `"index"` parameter: + +- `"index": "amendments"` - Returns the `Amendments` ledger entry +- `"index": "fee"` - Returns the `FeeSettings` ledger entry +- `"index": "nunl"` - Returns the `NegativeUNL` ledger entry +- `"index": "hashes"` - Returns the "short" `LedgerHashes` ledger entry (recent ledger hashes) + +These shortcuts are only available in API version 3 and later. In API versions 1 and 2, these string values would result in an error. diff --git a/BUILD.md b/BUILD.md index ef6b5259df..4d01700a61 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,5 +1,5 @@ -| :warning: **WARNING** :warning: -|---| +| :warning: **WARNING** :warning: | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md). | > These instructions also assume a basic familiarity with Conan and CMake. @@ -10,7 +10,7 @@ ## Branches For a stable release, choose the `master` branch or one of the [tagged -releases](https://github.com/ripple/rippled/releases). +releases](https://github.com/XRPLF/rippled/releases). ```bash git checkout master @@ -33,7 +33,7 @@ git checkout develop See [System Requirements](https://xrpl.org/system-requirements.html). -Building rippled generally requires git, Python, Conan, CMake, and a C++ +Building xrpld generally requires git, Python, Conan, CMake, and a C++ compiler. Some guidance on setting up such a [C++ development environment can be found here](./docs/build/environment.md). @@ -45,7 +45,7 @@ found here](./docs/build/environment.md). It is possible to build with Conan 1.60+, but the instructions are significantly different, which is why we are not recommending it. -`rippled` is written in the C++20 dialect and includes the `` header. +`xrpld` is written in the C++20 dialect and includes the `` header. The [minimum compiler versions][2] required are: | Compiler | Version | @@ -66,7 +66,7 @@ Linux](./docs/build/environment.md#linux). ### Mac -Many rippled engineers use macOS for development. +Many xrpld engineers use macOS for development. Here are [sample instructions for setting up a C++ development environment on macOS](./docs/build/environment.md#macos). @@ -88,6 +88,13 @@ These instructions assume a basic familiarity with Conan and CMake. If you are unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official [Getting Started][3] walkthrough. +#### Conan lockfile + +To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html), +which has to be updated every time dependencies change. + +Please see the [instructions on how to regenerate the lockfile](conan/lockfile/README.md). + #### Default profile We recommend that you import the provided `conan/profiles/default` profile: @@ -119,7 +126,7 @@ default profile. ### Patched recipes The recipes in Conan Center occasionally need to be patched for compatibility -with the latest version of `rippled`. We maintain a fork of the Conan Center +with the latest version of `xrpld`. We maintain a fork of the Conan Center [here](https://github.com/XRPLF/conan-center-index/) containing the patches. To ensure our patched recipes are used, you must add our Conan remote at a @@ -134,17 +141,42 @@ Alternatively, you can pull the patched recipes into the repository and use them locally: ```bash +# Extract the version number from the lockfile. +function extract_version { + version=$(cat conan.lock | sed -nE "s@.+${1}/(.+)#.+@\1@p" | head -n1) + echo ${version} +} + +# Define which recipes to export. +recipes=('ed25519' 'grpc' 'nudb' 'openssl' 'secp256k1' 'snappy' 'soci') +folders=('all' 'all' 'all' '3.x.x' 'all' 'all' 'all') + +# Selectively check out the recipes from our CCI fork. cd external +mkdir -p conan-center-index +cd conan-center-index git init git remote add origin git@github.com:XRPLF/conan-center-index.git git sparse-checkout init -git sparse-checkout set recipes/snappy -git sparse-checkout add recipes/soci +for ((index = 1; index <= ${#recipes[@]}; index++)); do + recipe=${recipes[index]} + folder=${folders[index]} + echo "Checking out recipe '${recipe}' from folder '${folder}'..." + git sparse-checkout add recipes/${recipe}/${folder} +done git fetch origin master git checkout master -conan export --version 1.1.10 recipes/snappy/all -conan export --version 4.0.3 recipes/soci/all -rm -rf .git +cd ../.. + +# Export the recipes into the local cache. +for ((index = 1; index <= ${#recipes[@]}; index++)); do + recipe=${recipes[index]} + folder=${folders[index]} + version=$(extract_version ${recipe}) + echo "Exporting '${recipe}/${version}' from '${recipe}/${folder}'..." + conan export --version $(extract_version ${recipe}) \ + external/conan-center-index/recipes/${recipe}/${folder} +done ``` In the case we switch to a newer version of a dependency that still requires a @@ -155,7 +187,8 @@ the new recipe will be automatically pulled from the official Conan Center. > [!NOTE] > You might need to add `--lockfile=""` to your `conan install` command -> to avoid automatic use of the existing `conan.lock` file when you run `conan export` manually on your machine +> to avoid automatic use of the existing `conan.lock` file when you run +> `conan export` manually on your machine ### Conan profile tweaks @@ -264,7 +297,7 @@ sed -i.bak -e 's|^compiler\.libcxx=.*$|compiler.libcxx=libstdc++11|' $(conan con to do that is to run the shortcut "x64 Native Tools Command Prompt" for the version of Visual Studio that you have installed. -Windows developers must also build `rippled` and its dependencies for the x64 +Windows developers must also build `xrpld` and its dependencies for the x64 architecture: ```bash @@ -335,6 +368,36 @@ The workaround for this error is to add two lines to your profile: tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] ``` +### Set Up Ccache + +To speed up repeated compilations, we recommend that you install +[ccache](https://ccache.dev), a tool that wraps your compiler so that it can +cache build objects locally. + +#### Linux + +You can install it using the package manager, e.g. `sudo apt install ccache` +(Ubuntu) or `sudo dnf install ccache` (RHEL). + +#### macOS + +You can install it using Homebrew, i.e. `brew install ccache`. + +#### Windows + +You can install it using Chocolatey, i.e. `choco install ccache`. If you already +have Ccache installed, then `choco upgrade ccache` will update it to the latest +version. However, if you see an error such as: + +``` +terminate called after throwing an instance of 'std::bad_alloc' + what(): std::bad_alloc +C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(617,5): error MSB6006: "cl.exe" exited with code 3. +``` + +then please install a specific version of Ccache that we know works, via: `choco +install ccache --version 4.11.3 --allow-downgrade`. + ### Build and Test 1. Create a build directory and move into it. @@ -373,19 +436,6 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] `--settings build_type=$BUILD_TYPE` or in the profile itself, under the section `[settings]` with the key `build_type`. - If you are using a Microsoft Visual C++ compiler, - then you will need to ensure consistency between the `build_type` setting - and the `compiler.runtime` setting. - - When `build_type` is `Release`, `compiler.runtime` should be `MT`. - - When `build_type` is `Debug`, `compiler.runtime` should be `MTd`. - - ``` - conan install .. --output-folder . --build missing --settings build_type=Release --settings compiler.runtime=MT - conan install .. --output-folder . --build missing --settings build_type=Debug --settings compiler.runtime=MTd - ``` - 3. Configure CMake and pass the toolchain file generated by Conan, located at `$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`. @@ -407,9 +457,9 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON .. ``` - **Note:** You can pass build options for `rippled` in this step. + **Note:** You can pass build options for `xrpld` in this step. -4. Build `rippled`. +4. Build `xrpld`. For a single-configuration generator, it will build whatever configuration you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, you @@ -428,55 +478,28 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] cmake --build . --config Debug ``` -5. Test rippled. +5. Test xrpld. Single-config generators: ``` - ./rippled --unittest --unittest-jobs N + ./xrpld --unittest --unittest-jobs N ``` Multi-config generators: ``` - ./Release/rippled --unittest --unittest-jobs N - ./Debug/rippled --unittest --unittest-jobs N + ./Release/xrpld --unittest --unittest-jobs N + ./Debug/xrpld --unittest --unittest-jobs N ``` Replace the `--unittest-jobs` parameter N with the desired unit tests concurrency. Recommended setting is half of the number of available CPU cores. - The location of `rippled` binary in your build directory depends on your + The location of `xrpld` binary in your build directory depends on your CMake generator. Pass `--help` to see the rest of the command line options. -#### Conan lockfile - -To achieve reproducible dependencies, we use [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html). - -The `conan.lock` file in the repository contains a "snapshot" of the current dependencies. -It is implicitly used when running `conan` commands, you don't need to specify it. - -You have to update this file every time you add a new dependency or change a revision or version of an existing dependency. - -> [!NOTE] -> Conan uses local cache by default when creating a lockfile. -> -> To ensure, that lockfile creation works the same way on all developer machines, you should clear the local cache before creating a new lockfile. - -To create a new lockfile, run the following commands in the repository root: - -```bash -conan remove '*' --confirm -rm conan.lock -# This ensure that xrplf remote is the first to be consulted -conan remote add --force --index 0 xrplf https://conan.ripplex.io -conan lock create . -o '&:jemalloc=True' -o '&:rocksdb=True' -``` - -> [!NOTE] -> If some dependencies are exclusive for some OS, you may need to run the last command for them adding `--profile:all `. - ## Coverage report The coverage report is intended for developers using compilers GCC @@ -493,20 +516,20 @@ Prerequisites for the coverage report: A coverage report is created when the following steps are completed, in order: -1. `rippled` binary built with instrumentation data, enabled by the `coverage` +1. `xrpld` binary built with instrumentation data, enabled by the `coverage` option mentioned above -2. completed run of unit tests, which populates coverage capture data +2. completed one or more run of the unit tests, which populates coverage capture data 3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) to assemble both instrumentation data and the coverage capture data into a coverage report -The above steps are automated into a single target `coverage`. The instrumented -`rippled` binary can also be used for regular development or testing work, at +The last step of the above is automated into a single target `coverage`. The instrumented +`xrpld` binary can also be used for regular development or testing work, at the cost of extra disk space utilization and a small performance hit -(to store coverage capture). In case of a spurious failure of unit tests, it is -possible to re-run the `coverage` target without rebuilding the `rippled` binary -(since it is simply a dependency of the coverage report target). It is also possible -to select only specific tests for the purpose of the coverage report, by setting -the `coverage_test` variable in `cmake` +(to store coverage capture data). Since `xrpld` binary is simply a dependency of the +coverage report target, it is possible to re-run the `coverage` target without +rebuilding the `xrpld` binary. Note, running of the unit tests before the `coverage` +target is left to the developer. Each such run will append to the coverage data +collected in the build directory. The default coverage report format is `html-details`, but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` @@ -515,11 +538,6 @@ to generate more than one format at a time by setting the `coverage_extra_args` variable in `cmake`. The specific command line used to run the `gcovr` tool will be displayed if the `CODE_COVERAGE_VERBOSE` variable is set. -By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` -set to the number of available CPU cores. This may cause spurious test -errors on Apple. Developers can override the number of unit test jobs with -the `coverage_test_parallelism` variable in `cmake`. - Example use with some cmake variables set: ``` @@ -535,23 +553,37 @@ stored inside the build directory, as either of: - file named `coverage.`_extension_, with a suitable extension for the report format, or - directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats. +## Sanitizers + +To build dependencies and xrpld with sanitizer instrumentation, set the +`SANITIZERS` environment variable (only once before running conan and cmake) and use the `sanitizers` profile in conan: + +```bash +export SANITIZERS=address,undefinedbehavior + +conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug + +cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -Dxrpld=ON -Dtests=ON .. +``` + +See [Sanitizers docs](./docs/build/sanitizers.md) for more details. + ## Options -| Option | Default Value | Description | -| ---------- | ------------- | -------------------------------------------------------------------------- | -| `assert` | OFF | Enable assertions. | -| `coverage` | OFF | Prepare the coverage report. | -| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | -| `tests` | OFF | Build tests. | -| `unity` | OFF | Configure a unity build. | -| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. | -| `werr` | OFF | Treat compilation warnings as errors | -| `wextra` | OFF | Enable additional compilation warnings | +| Option | Default Value | Description | +| ---------- | ------------- | -------------------------------------------------------------- | +| `assert` | OFF | Enable assertions. | +| `coverage` | OFF | Prepare the coverage report. | +| `tests` | OFF | Build tests. | +| `unity` | OFF | Configure a unity build. | +| `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. | +| `werr` | OFF | Treat compilation warnings as errors | +| `wextra` | OFF | Enable additional compilation warnings | -[Unity builds][5] may be faster for the first build -(at the cost of much more memory) since they concatenate sources into fewer -translation units. Non-unity builds may be faster for incremental builds, -and can be helpful for detecting `#include` omissions. +[Unity builds][5] may be faster for the first build (at the cost of much more +memory) since they concatenate sources into fewer translation units. Non-unity +builds may be faster for incremental builds, and can be helpful for detecting +`#include` omissions. ## Troubleshooting @@ -590,7 +622,7 @@ you might have generated CMake files for a different `build_type` than the `CMAKE_BUILD_TYPE` you passed to Conan. ``` -/rippled/.build/pb-xrpl.libpb/xrpl/proto/ripple.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found +/xrpld/.build/pb-xrpl.libpb/xrpl/proto/xrpl.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found 10 | #include | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated. diff --git a/CMakeLists.txt b/CMakeLists.txt index c71fb68599..5ee3aa5d77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,16 @@ cmake_minimum_required(VERSION 3.16) -if(POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) -endif() -if(POLICY CMP0077) - cmake_policy(SET CMP0077 NEW) -endif() +if (POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif () +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif () # Fix "unrecognized escape" issues when passing CMAKE_MODULE_PATH on Windows. -file(TO_CMAKE_PATH "${CMAKE_MODULE_PATH}" CMAKE_MODULE_PATH) +if (DEFINED CMAKE_MODULE_PATH) + file(TO_CMAKE_PATH "${CMAKE_MODULE_PATH}" CMAKE_MODULE_PATH) +endif () list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") project(xrpl) @@ -16,141 +18,132 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") +include(CompilationEnv) + +if (is_gcc) # GCC-specific fixes add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage) # -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3 -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") +elseif (is_clang) # Clang-specific fixes add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options -elseif(MSVC) +elseif (is_msvc) # MSVC-specific fixes add_compile_options(/wd4068) # Ignore unknown pragmas -endif() +endif () + +# Enable ccache to speed up builds. +include(Ccache) # make GIT_COMMIT_HASH define available to all sources find_package(Git) -if(Git_FOUND) +if (Git_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse HEAD - OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch) - if(gch) + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch) + if (gch) set(GIT_COMMIT_HASH "${gch}") message(STATUS gch: ${GIT_COMMIT_HASH}) add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") - endif() + endif () execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse --abbrev-ref HEAD - OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb) - if(gb) + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb) + if (gb) set(GIT_BRANCH "${gb}") message(STATUS gb: ${GIT_BRANCH}) add_definitions(-DGIT_BRANCH="${GIT_BRANCH}") - endif() -endif() #git + endif () +endif () # git -if(thread_safety_analysis) - add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) - add_compile_options("-stdlib=libc++") - add_link_options("-stdlib=libc++") -endif() +if (thread_safety_analysis) + add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + -DXRPL_ENABLE_THREAD_SAFETY_ANNOTATIONS) + add_compile_options("-stdlib=libc++") + add_link_options("-stdlib=libc++") +endif () -include (CheckCXXCompilerFlag) -include (FetchContent) -include (ExternalProject) -include (CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP +include(CheckCXXCompilerFlag) +include(FetchContent) +include(ExternalProject) +include(CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP if (target) - message (FATAL_ERROR "The target option has been removed - use native cmake options to control build") + message(FATAL_ERROR "The target option has been removed - use native cmake options to control build") endif () -include(RippledSanity) -include(RippledVersion) -include(RippledSettings) -# this check has to remain in the top-level cmake -# because of the early return statement +include(XrplSanity) +include(XrplVersion) +include(XrplSettings) +# this check has to remain in the top-level cmake because of the early return statement if (packages_only) - if (NOT TARGET rpm) - message (FATAL_ERROR "packages_only requested, but targets were not created - is docker installed?") - endif() - return () + if (NOT TARGET rpm) + message(FATAL_ERROR "packages_only requested, but targets were not created - is docker installed?") + endif () + return() endif () -include(RippledCompiler) -include(RippledInterface) +include(XrplCompiler) +include(XrplSanitizers) +include(XrplInterface) option(only_docs "Include only the docs target?" FALSE) -include(RippledDocs) -if(only_docs) - return() -endif() - -### +include(XrplDocs) +if (only_docs) + return() +endif () include(deps/Boost) -find_package(OpenSSL 1.1.1 REQUIRED) -set_target_properties(OpenSSL::SSL PROPERTIES - INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2 -) -set(SECP256K1_INSTALL TRUE) -set(SECP256K1_BUILD_BENCHMARK FALSE) -set(SECP256K1_BUILD_TESTS FALSE) -set(SECP256K1_BUILD_EXHAUSTIVE_TESTS FALSE) -set(SECP256K1_BUILD_CTIME_TESTS FALSE) -set(SECP256K1_BUILD_EXAMPLES FALSE) -add_subdirectory(external/secp256k1) -add_library(secp256k1::secp256k1 ALIAS secp256k1) -add_subdirectory(external/ed25519-donna) + add_subdirectory(external/antithesis-sdk) +find_package(date REQUIRED) +find_package(ed25519 REQUIRED) find_package(gRPC REQUIRED) -find_package(lz4 REQUIRED) -# Target names with :: are not allowed in a generator expression. -# We need to pull the include directories and imported location properties -# from separate targets. find_package(LibArchive REQUIRED) +find_package(lz4 REQUIRED) +find_package(mpt-crypto REQUIRED) +find_package(nudb REQUIRED) +find_package(OpenSSL REQUIRED) +find_package(secp256k1 REQUIRED) find_package(SOCI REQUIRED) find_package(SQLite3 REQUIRED) - -option(rocksdb "Enable RocksDB" ON) -if(rocksdb) - find_package(RocksDB REQUIRED) - set_target_properties(RocksDB::rocksdb PROPERTIES - INTERFACE_COMPILE_DEFINITIONS RIPPLE_ROCKSDB_AVAILABLE=1 - ) - target_link_libraries(ripple_libs INTERFACE RocksDB::rocksdb) -endif() - -find_package(nudb REQUIRED) -find_package(date REQUIRED) find_package(xxHash REQUIRED) -target_link_libraries(ripple_libs INTERFACE - ed25519::ed25519 - lz4::lz4 - OpenSSL::Crypto - OpenSSL::SSL - secp256k1::secp256k1 - soci::soci - SQLite::SQLite3 -) +target_link_libraries( + xrpl_libs + INTERFACE ed25519::ed25519 + lz4::lz4 + mpt-crypto::mpt-crypto + OpenSSL::Crypto + OpenSSL::SSL + secp256k1::secp256k1 + soci::soci + SQLite::SQLite3) + +option(rocksdb "Enable RocksDB" ON) +if (rocksdb) + find_package(RocksDB REQUIRED) + set_target_properties(RocksDB::rocksdb PROPERTIES INTERFACE_COMPILE_DEFINITIONS XRPL_ROCKSDB_AVAILABLE=1) + target_link_libraries(xrpl_libs INTERFACE RocksDB::rocksdb) +endif () # Work around changes to Conan recipe for now. -if(TARGET nudb::core) - set(nudb nudb::core) -elseif(TARGET NuDB::nudb) - set(nudb NuDB::nudb) -else() - message(FATAL_ERROR "unknown nudb target") -endif() -target_link_libraries(ripple_libs INTERFACE ${nudb}) +if (TARGET nudb::core) + set(nudb nudb::core) +elseif (TARGET NuDB::nudb) + set(nudb NuDB::nudb) +else () + message(FATAL_ERROR "unknown nudb target") +endif () +target_link_libraries(xrpl_libs INTERFACE ${nudb}) -if(coverage) - include(RippledCov) -endif() +if (coverage) + include(XrplCov) +endif () -set(PROJECT_EXPORT_SET RippleExports) -include(RippledCore) -include(RippledInstall) -include(RippledValidatorKeys) +set(PROJECT_EXPORT_SET XrplExports) +include(XrplCore) +include(XrplInstall) +include(XrplValidatorKeys) -if(tests) - include(CTest) - add_subdirectory(src/tests/libxrpl) -endif() +if (tests) + include(CTest) + add_subdirectory(src/tests/libxrpl) +endif () diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5e0933d00..808d553e17 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ your verifying key. Please set up [signature verification][signing]. In general, external contributions should be developed in your personal [fork][forking]. Contributions from developers with write permissions -should be done in [the main repository][rippled] in a branch with +should be done in [the main repository][xrpld] in a branch with a permitted prefix. Permitted prefixes are: - XLS-[a-zA-Z0-9]+/.+ @@ -47,13 +47,18 @@ choose the next available standard number, and open a discussion with an appropriate title to propose your draft standard. When you submit a pull request, please link the corresponding XLS in the -description. An XLS still in draft status is considered a +description. An XLS still in `Draft` status is considered a work-in-progress and open for discussion. Please allow time for questions, suggestions, and changes to the XLS draft. It is the responsibility of the XLS author to update the draft to match the final implementation when its corresponding pull request is merged, unless the author delegates that responsibility to others. +Any amendment or major RPC change requires either a new XLS or an update +to an existing XLS. Neither change will be released (in an amendment's +case, marked as `Supported::yes`) until the corresponding XLS's status +is `Final`. + ## Before making a pull request (Or marking a draft pull request as ready.) @@ -68,7 +73,7 @@ Ensure that your code compiles according to the build instructions in Please write tests for your code. If your test can be run offline, in under 60 seconds, then it can be an -automatic test run by `rippled --unittest`. +automatic test run by `xrpld --unittest`. Otherwise, it must be a manual test. If you create new source files, they must be organized as follows: @@ -251,13 +256,13 @@ pre-commit install We are using [Antithesis](https://antithesis.com/) for continuous fuzzing, and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/) in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs -by finding external conditions which cause contracts violations inside `rippled`. +by finding external conditions which cause contracts violations inside `xrpld`. The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in `include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside of Antithesis) wrappers for `assert(...)` with added name. The purpose of name is to provide contracts with stable identity which does not rely on line numbers. -When `rippled` is built with the Antithesis instrumentation enabled +When `xrpld` is built with the Antithesis instrumentation enabled (using `voidstar` CMake option) and ran on the Antithesis platform, the contracts become [test properties](https://antithesis.com/docs/using_antithesis/properties.html); @@ -299,7 +304,7 @@ For this reason: - Example **bad** name `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"` (missing namespace, unnecessary full function signature, description too verbose). - Good name: `"ripple::RFC1751::insert : minimum length"`. + Good name: `"xrpl::RFC1751::insert : minimum length"`. - In **few** well-justified cases a non-standard name can be used, in which case a comment should be placed to explain the rationale (example in `contract.cpp`) - Do **not** rename a contract without a good reason (e.g. the name no longer @@ -313,7 +318,7 @@ For this reason: To execute all unit tests: -`rippled --unittest --unittest-jobs=` +`xrpld --unittest --unittest-jobs=` (Note: Using multiple cores on a Mac M1 can cause spurious test failures. The cause is still under investigation. If you observe this problem, try specifying fewer jobs.) @@ -321,7 +326,7 @@ cause is still under investigation. If you observe this problem, try specifying To run a specific set of test suites: ``` -rippled --unittest TestSuiteName +xrpld --unittest TestSuiteName ``` Note: In this example, all tests with prefix `TestSuiteName` will be run, so if @@ -550,16 +555,16 @@ Rippled uses a linear workflow model that can be summarized as: git fetch --multiple upstreams user1 user2 user3 [...] git checkout -B release-next --no-track upstream/develop -# Only do an ff-only merge if prbranch1 is either already +# Only do an ff-only merge if pr-branch1 is either already # squashed, or needs to be merged with separate commits, # and has no merge commits. -# Use -S on the ff-only merge if prbranch1 isn't signed. -git merge [-S] --ff-only user1/prbranch1 +# Use -S on the ff-only merge if pr-branch1 isn't signed. +git merge [-S] --ff-only user1/pr-branch1 -git merge --squash user2/prbranch2 +git merge --squash user2/pr-branch2 git commit -S # Use the commit message provided on the PR -git merge --squash user3/prbranch3 +git merge --squash user3/pr-branch3 git commit -S # Use the commit message provided on the PR [...] @@ -867,11 +872,12 @@ git push --delete upstream-push master-next 11. [Create a new release on Github](https://github.com/XRPLF/rippled/releases). Be sure that "Set as the latest release" is checked. -12. Finally [reverse merge the release into `develop`](#follow-up-reverse-merge). +12. Open a PR to update the [API-CHANGELOG](API-CHANGELOG.md) and `API-VERSION-[n].md` with the changes for this release (if any are missing). +13. Finally, [reverse merge the release into `develop`](#follow-up-reverse-merge). #### Special cases: point releases, hotfixes, etc. -On occassion, a bug or issue is discovered in a version that already +On occasion, a bug or issue is discovered in a version that already had a final release. Most of the time, development will have started on the next version, and will usually have changes in `develop` and often in `release`. @@ -1070,7 +1076,7 @@ git fetch upstreams [contrib]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects [squash]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits [forking]: https://github.com/XRPLF/rippled/fork -[rippled]: https://github.com/XRPLF/rippled +[xrpld]: https://github.com/XRPLF/rippled [signing]: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification [setup-upstreams]: ./bin/git/setup-upstreams.sh [squash-branches]: ./bin/git/squash-branches.sh diff --git a/LICENSE.md b/LICENSE.md index 8aca84866f..c5e3ad0532 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ ISC License Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant. -Copyright (c) 2012-2020, the XRP Ledger developers. +Copyright (c) 2012-2025, the XRP Ledger developers. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/SECURITY.md b/SECURITY.md index 3fd85bad0a..1be412ae2a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -42,7 +42,7 @@ For more information on responsible disclosure, please read this [Wikipedia arti ## Report Handling Process -Please report the bug directly to us and limit further disclosure. If you want to prove that you knew the bug as of a given time, consider using a cryptographic precommitment: hash the content of your report and publish the hash on a medium of your choice (e.g. on Twitter or as a memo in a transaction) as "proof" that you had written the text at a given point in time. +Please report the bug directly to us and limit further disclosure. If you want to prove that you knew the bug as of a given time, consider using a cryptographic pre-commitment: hash the content of your report and publish the hash on a medium of your choice (e.g. on Twitter or as a memo in a transaction) as "proof" that you had written the text at a given point in time. Once we receive a report, we: @@ -78,72 +78,61 @@ To report a qualifying bug, please send a detailed report to: | Email Address | bugs@ripple.com | | :-----------: | :-------------------------------------------------- | -| Short Key ID | `0xC57929BE` | -| Long Key ID | `0xCD49A0AFC57929BE` | -| Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` | +| Short Key ID | `0xA9F514E0` | +| Long Key ID | `0xD900855AA9F514E0` | +| Fingerprint | `B72C 0654 2F2A E250 2763 A268 D900 855A A9F5 14E0` | The full PGP key for this address, which is also available on several key servers (e.g. on [keyserver.ubuntu.com](https://keyserver.ubuntu.com)), is: ``` -----BEGIN PGP PUBLIC KEY BLOCK----- -mQINBFUwGHYBEAC0wpGpBPkd8W1UdQjg9+cEFzeIEJRaoZoeuJD8mofwI5Ejnjdt -kCpUYEDal0ygkKobu8SzOoATcDl18iCrScX39VpTm96vISFZMhmOryYCIp4QLJNN -4HKc2ZdBj6W4igNi6vj5Qo6JMyGpLY2mz4CZskbt0TNuUxWrGood+UrCzpY8x7/N -a93fcvNw+prgCr0rCH3hAPmAFfsOBbtGzNnmq7xf3jg5r4Z4sDiNIF1X1y53DAfV -rWDx49IKsuCEJfPMp1MnBSvDvLaQ2hKXs+cOpx1BCZgHn3skouEUxxgqbtTzBLt1 -xXpmuijsaltWngPnGO7mOAzbpZSdBm82/Emrk9bPMuD0QaLQjWr7HkTSUs6ZsKt4 -7CLPdWqxyY/QVw9UaxeHEtWGQGMIQGgVJGh1fjtUr5O1sC9z9jXcQ0HuIHnRCTls -GP7hklJmfH5V4SyAJQ06/hLuEhUJ7dn+BlqCsT0tLmYTgZYNzNcLHcqBFMEZHvHw -9GENMx/tDXgajKql4bJnzuTK0iGU/YepanANLd1JHECJ4jzTtmKOus9SOGlB2/l1 -0t0ADDYAS3eqOdOcUvo9ElSLCI5vSVHhShSte/n2FMWU+kMUboTUisEG8CgQnrng -g2CvvQvqDkeOtZeqMcC7HdiZS0q3LJUWtwA/ViwxrVlBDCxiTUXCotyBWwARAQAB -tDBSaXBwbGUgTGFicyBCdWcgQm91bnR5IFByb2dyYW0gPGJ1Z3NAcmlwcGxlLmNv -bT6JAjcEEwEKACEFAlUwGHYCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ -zUmgr8V5Kb6R0g//SwY/mVJY59k87iL26/KayauSoOcz7xjcST26l4ZHVVX85gOY -HYZl8k0+m8X3zxeYm9a3QAoAml8sfoaFRFQP8ynnefRrLUPaZ2MjbJ0SACMwZNef -T6o7Mi8LBAaiNZdYVyIfX1oM6YXtqYkuJdav6ZCyvVYqc9OvMJPY2ZzJYuI/ZtvQ -/lTndxCeg9ALNX/iezOLGdfMpf4HuIFVwcPPlwGi+HDlB9/bggDEHC8z434SXVFc -aQatXAPcDkjMUweU7y0CZtYEj00HITd4pSX6MqGiHrxlDZTqinCOPs1Ieqp7qufs -MzlM6irLGucxj1+wa16ieyYvEtGaPIsksUKkywx0O7cf8N2qKg+eIkUk6O0Uc6eO -CszizmiXIXy4O6OiLlVHGKkXHMSW9Nwe9GE95O8G9WR8OZCEuDv+mHPAutO+IjdP -PDAAUvy+3XnkceO+HGWRpVvJZfFP2YH4A33InFL5yqlJmSoR/yVingGLxk55bZDM -+HYGR3VeMb8Xj1rf/02qERsZyccMCFdAvKDbTwmvglyHdVLu5sPmktxbBYiemfyJ -qxMxmYXCc9S0hWrWZW7edktBa9NpE58z1mx+hRIrDNbS2sDHrib9PULYCySyVYcF -P+PWEe1CAS5jqkR2ker5td2/pHNnJIycynBEs7l6zbc9fu+nktFJz0q2B+GJAhwE -EAEKAAYFAlUwGaQACgkQ+tiY1qQ2QkjMFw//f2hNY3BPNe+1qbhzumMDCnbTnGif -kLuAGl9OKt81VHG1f6RnaGiLpR696+6Ja45KzH15cQ5JJl5Bgs1YkR/noTGX8IAD -c70eNwiFu8JXTaaeeJrsmFkF9Tueufb364risYkvPP8tNUD3InBFEZT3WN7JKwix -coD4/BwekUwOZVDd/uCFEyhlhZsROxdKNisNo3VtAq2s+3tIBAmTrriFUl0K+ZC5 -zgavcpnPN57zMtW9aK+VO3wXqAKYLYmtgxkVzSLUZt2M7JuwOaAdyuYWAneKZPCu -1AXkmyo+d84sd5mZaKOr5xArAFiNMWPUcZL4rkS1Fq4dKtGAqzzR7a7hWtA5o27T -6vynuxZ1n0PPh0er2O/zF4znIjm5RhTlfjp/VmhZdQfpulFEQ/dMxxGkQ9z5IYbX -mTlSDbCSb+FMsanRBJ7Drp5EmBIudVGY6SHI5Re1RQiEh7GoDfUMUwZO+TVDII5R -Ra7WyuimYleJgDo/+7HyfuIyGDaUCVj6pwVtYtYIdOI3tTw1R1Mr0V8yaNVnJghL -CHcEJQL+YHSmiMM3ySil3O6tm1By6lFz8bVe/rgG/5uklQrnjMR37jYboi1orCC4 -yeIoQeV0ItlxeTyBwYIV/o1DBNxDevTZvJabC93WiGLw2XFjpZ0q/9+zI2rJUZJh -qxmKP+D4e27lCI65Ag0EVTAYdgEQAMvttYNqeRNBRpSX8fk45WVIV8Fb21fWdwk6 -2SkZnJURbiC0LxQnOi7wrtii7DeFZtwM2kFHihS1VHekBnIKKZQSgGoKuFAQMGyu -a426H4ZsSmA9Ufd7kRbvdtEcp7/RTAanhrSL4lkBhaKJrXlxBJ27o3nd7/rh7r3a -OszbPY6DJ5bWClX3KooPTDl/RF2lHn+fweFk58UvuunHIyo4BWJUdilSXIjLun+P -Qaik4ZAsZVwNhdNz05d+vtai4AwbYoO7adboMLRkYaXSQwGytkm+fM6r7OpXHYuS -cR4zB/OK5hxCVEpWfiwN71N2NMvnEMaWd/9uhqxJzyvYgkVUXV9274TUe16pzXnW -ZLfmitjwc91e7mJBBfKNenDdhaLEIlDRwKTLj7k58f9srpMnyZFacntu5pUMNblB -cjXwWxz5ZaQikLnKYhIvrIEwtWPyjqOzNXNvYfZamve/LJ8HmWGCKao3QHoAIDvB -9XBxrDyTJDpxbog6Qu4SY8AdgVlan6c/PsLDc7EUegeYiNTzsOK+eq3G5/E92eIu -TsUXlciypFcRm1q8vLRr+HYYe2mJDo4GetB1zLkAFBcYJm/x9iJQbu0hn5NxJvZO -R0Y5nOJQdyi+muJzKYwhkuzaOlswzqVXkq/7+QCjg7QsycdcwDjiQh3OrsgXHrwl -M7gyafL9ABEBAAGJAh8EGAEKAAkFAlUwGHYCGwwACgkQzUmgr8V5Kb50BxAAhj9T -TwmNrgRldTHszj+Qc+v8RWqV6j+R+zc0cn5XlUa6XFaXI1OFFg71H4dhCPEiYeN0 -IrnocyMNvCol+eKIlPKbPTmoixjQ4udPTR1DC1Bx1MyW5FqOrsgBl5t0e1VwEViM -NspSStxu5Hsr6oWz2GD48lXZWJOgoL1RLs+uxjcyjySD/em2fOKASwchYmI+ezRv -plfhAFIMKTSCN2pgVTEOaaz13M0U+MoprThqF1LWzkGkkC7n/1V1f5tn83BWiagG -2N2Q4tHLfyouzMUKnX28kQ9sXfxwmYb2sA9FNIgxy+TdKU2ofLxivoWT8zS189z/ -Yj9fErmiMjns2FzEDX+bipAw55X4D/RsaFgC+2x2PDbxeQh6JalRA2Wjq32Ouubx -u+I4QhEDJIcVwt9x6LPDuos1F+M5QW0AiUhKrZJ17UrxOtaquh/nPUL9T3l2qPUn -1ChrZEEEhHO6vA8+jn0+cV9n5xEz30Str9iHnDQ5QyR5LyV4UBPgTdWyQzNVKA69 -KsSr9lbHEtQFRzGuBKwt6UlSFv9vPWWJkJit5XDKAlcKuGXj0J8OlltToocGElkF -+gEBZfoOWi/IBjRLrFW2cT3p36DTR5O1Ud/1DLnWRqgWNBLrbs2/KMKE6EnHttyD -7Tz8SQkuxltX/yBXMV3Ddy0t6nWV2SZEfuxJAQI= -=spg4 +mQINBGkSZAQBEACprU199OhgdsOsygNjiQV4msuN3vDOUooehL+NwfsGfW79Tbqq +Q2u7uQ3NZjW+M2T4nsDwuhkr7pe7xSReR5W8ssaczvtUyxkvbMClilcgZ2OSCAuC +N9tzJsqOqkwBvXoNXkn//T2jnPz0ZU2wSF+NrEibq5FeuyGdoX3yXXBxq9pW9HzK +HkQll63QSl6BzVSGRQq+B6lGgaZGLwf3mzmIND9Z5VGLNK2jKynyz9z091whNG/M +kV+E7/r/bujHk7WIVId07G5/COTXmSr7kFnNEkd2Umw42dkgfiNKvlmJ9M7c1wLK +KbL9Eb4ADuW6rRc5k4s1e6GT8R4/VPliWbCl9SE32hXH8uTkqVIFZP2eyM5WRRHs +aKzitkQG9UK9gcb0kdgUkxOvvgPHAe5IuZlcHFzU4y0dBbU1VEFWVpiLU0q+IuNw +5BRemeHc59YNsngkmAZ+/9zouoShRusZmC8Wzotv75C2qVBcjijPvmjWAUz0Zunm +Lsr+O71vqHE73pERjD07wuD/ISjiYRYYE/bVrXtXLZijC7qAH4RE3nID+2ojcZyO +/2jMQvt7un56RsGH4UBHi3aBHi9bUoDGCXKiQY981cEuNaOxpou7Mh3x/ONzzSvk +sTV6nl1LOZHykN1JyKwaNbTSAiuyoN+7lOBqbV04DNYAHL88PrT21P83aQARAQAB +tB1SaXBwbGUgTGFicyA8YnVnc0ByaXBwbGUuY29tPokCTgQTAQgAOBYhBLcsBlQv +KuJQJ2OiaNkAhVqp9RTgBQJpEmQEAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA +AAoJENkAhVqp9RTgBzgP/i7y+aDWl1maig1XMdyb+o0UGusumFSW4Hmj278wlKVv +usgLPihYgHE0PKrv6WRyKOMC1tQEcYYN93M+OeQ1vFhS2YyURq6RCMmh4zq/awXG +uZbG36OURB5NH8lGBOHiN/7O+nY0CgenBT2JWm+GW3nEOAVOVm4+r5GlpPlv+Dp1 +NPBThcKXFMnH73++NpSQoDzTfRYHPxhDAX3jkLi/moXfSanOLlR6l94XNNN0jBHW +Quao0rzf4WSXq9g6AS224xhAA5JyIcFl8TX7hzj5HaFn3VWo3COoDu4U7H+BM0fl +85yqiMQypp7EhN2gxpMMWaHY5TFM85U/bFXFYfEgihZ4/gt4uoIzsNI9jlX7mYvG +KFdDij+oTlRsuOxdIy60B3dKcwOH9nZZCz0SPsN/zlRWgKzK4gDKdGhFkU9OlvPu +94ZqscanoiWKDoZkF96+sjgfjkuHsDK7Lwc1Xi+T4drHG/3aVpkYabXox+lrKB/S +yxZjeqOIQzWPhnLgCaLyvsKo5hxKzL0w3eURu8F3IS7RgOOlljv4M+Me9sEVcdNV +aN3/tQwbaomSX1X5D5YXqhBwC3rU3wXwamsscRTGEpkV+JCX6KUqGP7nWmxCpAly +FL05XuOd5SVHJjXLeuje0JqLUpN514uL+bThWwDbDTdAdwW3oK/2WbXz7IfJRLBj +uQINBGkSZAQBEADdI3SL2F72qkrgFqXWE6HSRBu9bsAvTE5QrRPWk7ux6at537r4 +S4sIw2dOwLvbyIrDgKNq3LQ5wCK88NO/NeCOFm4AiCJSl3pJHXYnTDoUxTrrxx+o +vSRI4I3fHEql/MqzgiAb0YUezjgFdh3vYheMPp/309PFbOLhiFqEcx80Mx5h06UH +gDzu1qNj3Ec+31NLic5zwkrAkvFvD54d6bqYR3SEgMau6aYEewpGHbWBi2pLqSi2 +lQcAeOFixqGpTwDmAnYR8YtjBYepy0MojEAdTHcQQlOYSDk4q4elG+io2N8vECfU +rD6ORecN48GXdZINYWTAdslrUeanmBdgQrYkSpce8TSghgT9P01SNaXxmyaehVUO +lqI4pcg5G2oojAE8ncNS3TwDtt7daTaTC3bAdr4PXDVAzNAiewjMNZPB7xidkDGQ +Y4W1LxTMXyJVWxehYOH7tsbBRKninlfRnLgYzmtIbNRAAvNcsxU6ihv3AV0WFknN +YbSzotEv1Xq/5wk309x8zCDe+sP0cQicvbXafXmUzPAZzeqFg+VLFn7F9MP1WGlW +B1u7VIvBF1Mp9Nd3EAGBAoLRdRu+0dVWIjPTQuPIuD9cCatJA0wVaKUrjYbBMl88 +a12LixNVGeSFS9N7ADHx0/o7GNT6l88YbaLP6zggUHpUD/bR+cDN7vllIQARAQAB +iQI2BBgBCAAgFiEEtywGVC8q4lAnY6Jo2QCFWqn1FOAFAmkSZAQCGwwACgkQ2QCF +Wqn1FOAfAA/8CYq4p0p4bobY20CKEMsZrkBTFJyPDqzFwMeTjgpzqbD7Y3Qq5QCK +OBbvY02GWdiIsNOzKdBxiuam2xYP9WHZj4y7/uWEvT0qlPVmDFu+HXjoJ43oxwFd +CUp2gMuQ4cSL3X94VRJ3BkVL+tgBm8CNY0vnTLLOO3kum/R69VsGJS1JSGUWjNM+ +4qwS3mz+73xJu1HmERyN2RZF/DGIZI2PyONQQ6aH85G1Dd2ohu2/DBAkQAMBrPbj +FrbDaBLyFhODxU3kTWqnfLlaElSm2EGdIU2yx7n4BggEa//NZRMm5kyeo4vzhtlQ +YIVUMLAOLZvnEqDnsLKp+22FzNR/O+htBQC4lPywl53oYSALdhz1IQlcAC1ru5KR +XPzhIXV6IIzkcx9xNkEclZxmsuy5ERXyKEmLbIHAlzFmnrldlt2ZgXDtzaorLmxj +klKibxd5tF50qOpOivz+oPtFo7n+HmFa1nlVAMxlDCUdM0pEVeYDKI5zfVwalyhZ +NnjpakdZSXMwgc7NP/hH9buF35hKDp7EckT2y3JNYwHsDdy1icXN2q40XZw5tSIn +zkPWdu3OUY8PISohN6Pw4h0RH4ZmoX97E8sEfmdKaT58U4Hf2aAv5r9IWCSrAVqY +u5jvac29CzQR9Kal0A+8phHAXHNFD83SwzIC0syaT9ficAguwGH8X6Q= +=nGuD -----END PGP PUBLIC KEY BLOCK----- ``` diff --git a/cfg/validators-example.txt b/cfg/validators-example.txt index dbcff90f12..6eb49da697 100644 --- a/cfg/validators-example.txt +++ b/cfg/validators-example.txt @@ -1,7 +1,7 @@ # # Default validators.txt # -# This file is located in the same folder as your rippled.cfg file +# This file is located in the same folder as your xrpld.cfg file # and defines which validators your server trusts not to collude. # # This file is UTF-8 with DOS, UNIX, or Mac style line endings. diff --git a/cfg/rippled-example.cfg b/cfg/xrpld-example.cfg similarity index 92% rename from cfg/rippled-example.cfg rename to cfg/xrpld-example.cfg index 5db008431d..995d4e65ff 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/xrpld-example.cfg @@ -29,18 +29,18 @@ # # Purpose # -# This file documents and provides examples of all rippled server process -# configuration options. When the rippled server instance is launched, it +# This file documents and provides examples of all xrpld server process +# configuration options. When the xrpld server instance is launched, it # looks for a file with the following name: # -# rippled.cfg +# xrpld.cfg # -# For more information on where the rippled server instance searches for the +# For more information on where the xrpld server instance searches for the # file, visit: # # https://xrpl.org/commandline-usage.html#generic-options # -# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX, +# This file should be named xrpld.cfg. This file is UTF-8 with DOS, UNIX, # or Mac style end of lines. Blank lines and lines beginning with '#' are # ignored. Undefined sections are reserved. No escapes are currently defined. # @@ -89,8 +89,8 @@ # # # -# rippled offers various server protocols to clients making inbound -# connections. The listening ports rippled uses are "universal" ports +# xrpld offers various server protocols to clients making inbound +# connections. The listening ports xrpld uses are "universal" ports # which may be configured to handshake in one or more of the available # supported protocols. These universal ports simplify administration: # A single open port can be used for multiple protocols. @@ -103,7 +103,7 @@ # # A list of port names and key/value pairs. A port name must start with a # letter and contain only letters and numbers. The name is not case-sensitive. -# For each name in this list, rippled will look for a configuration file +# For each name in this list, xrpld will look for a configuration file # section with the same name and use it to create a listening port. The # name is informational only; the choice of name does not affect the function # of the listening port. @@ -134,7 +134,7 @@ # ip = 127.0.0.1 # protocol = http # -# When rippled is used as a command line client (for example, issuing a +# When xrpld is used as a command line client (for example, issuing a # server stop command), the first port advertising the http or https # protocol will be used to make the connection. # @@ -175,7 +175,7 @@ # same time. It is possible have both Websockets and Secure Websockets # together in one port. # -# NOTE If no ports support the peer protocol, rippled cannot +# NOTE If no ports support the peer protocol, xrpld cannot # receive incoming peer connections or become a superpeer. # # limit = @@ -194,7 +194,7 @@ # required. IP address restrictions, if any, will be checked in addition # to the credentials specified here. # -# When acting in the client role, rippled will supply these credentials +# When acting in the client role, xrpld will supply these credentials # using HTTP's Basic Authentication headers when making outbound HTTP/S # requests. # @@ -218,7 +218,7 @@ # administrative commands. # # NOTE A common configuration value for the admin field is "localhost". -# If you are listening on all IPv4/IPv6 addresses by specifing +# If you are listening on all IPv4/IPv6 addresses by specifying # ip = :: then you can use admin = ::ffff:127.0.0.1,::1 to allow # administrative access from both IPv4 and IPv6 localhost # connections. @@ -237,7 +237,7 @@ # WS, or WSS protocol interfaces. If administrative commands are # disabled for a port, these credentials have no effect. # -# When acting in the client role, rippled will supply these credentials +# When acting in the client role, xrpld will supply these credentials # in the submitted JSON for any administrative command requests when # invoking JSON-RPC commands on remote servers. # @@ -258,7 +258,7 @@ # resource controls will default to those for non-administrative users. # # The secure_gateway IP addresses are intended to represent -# proxies. Since rippled trusts these hosts, they must be +# proxies. Since xrpld trusts these hosts, they must be # responsible for properly authenticating the remote user. # # If some IP addresses are included for both "admin" and @@ -272,7 +272,7 @@ # Use the specified files when configuring SSL on the port. # # NOTE If no files are specified and secure protocols are selected, -# rippled will generate an internal self-signed certificate. +# xrpld will generate an internal self-signed certificate. # # The files have these meanings: # @@ -297,12 +297,12 @@ # Control the ciphers which the server will support over SSL on the port, # specified using the OpenSSL "cipher list format". # -# NOTE If unspecified, rippled will automatically configure a modern +# NOTE If unspecified, xrpld will automatically configure a modern # cipher suite. This default suite should be widely supported. # # You should not modify this string unless you have a specific # reason and cryptographic expertise. Incorrect modification may -# keep rippled from connecting to other instances of rippled or +# keep xrpld from connecting to other instances of xrpld or # prevent RPC and WebSocket clients from connecting. # # send_queue_limit = [1..65535] @@ -382,7 +382,7 @@ #----------------- # # These settings control security and access attributes of the Peer to Peer -# server section of the rippled process. Peer Protocol implements the +# server section of the xrpld process. Peer Protocol implements the # Ripple Payment protocol. It is over peer connections that transactions # and validations are passed from to machine to machine, to determine the # contents of validated ledgers. @@ -396,7 +396,7 @@ # true - enables compression # false - disables compression [default]. # -# The rippled server can save bandwidth by compressing its peer-to-peer communications, +# The xrpld server can save bandwidth by compressing its peer-to-peer communications, # at a cost of greater CPU usage. If you enable link compression, # the server automatically compresses communications with peer servers # that also have link compression enabled. @@ -432,7 +432,7 @@ # # [ips_fixed] # -# List of IP addresses or hostnames to which rippled should always attempt to +# List of IP addresses or hostnames to which xrpld should always attempt to # maintain peer connections with. This is useful for manually forming private # networks, for example to configure a validation server that connects to the # Ripple network through a public-facing server, or for building a set @@ -573,7 +573,7 @@ # # minimum_txn_in_ledger_standalone = # -# Like minimum_txn_in_ledger when rippled is running in standalone +# Like minimum_txn_in_ledger when xrpld is running in standalone # mode. Default: 1000. # # target_txn_in_ledger = @@ -710,7 +710,7 @@ # # [validator_token] # -# This is an alternative to [validation_seed] that allows rippled to perform +# This is an alternative to [validation_seed] that allows xrpld to perform # validation without having to store the validator keys on the network # connected server. The field should contain a single token in the form of a # base64-encoded blob. @@ -745,7 +745,7 @@ # # Specify the file by its name or path. # Unless an absolute path is specified, it will be considered relative to -# the folder in which the rippled.cfg file is located. +# the folder in which the xrpld.cfg file is located. # # Examples: # /home/ripple/validators.txt @@ -840,7 +840,7 @@ # # 0: Disable the ledger replay feature [default] # 1: Enable the ledger replay feature. With this feature enabled, when -# acquiring a ledger from the network, a rippled node only downloads +# acquiring a ledger from the network, a xrpld node only downloads # the ledger header and the transactions instead of the whole ledger. # And the ledger is built by applying the transactions to the parent # ledger. @@ -851,7 +851,7 @@ # #---------------- # -# The rippled server instance uses HTTPS GET requests in a variety of +# The xrpld server instance uses HTTPS GET requests in a variety of # circumstances, including but not limited to contacting trusted domains to # fetch information such as mapping an email address to a Ripple Payment # Network address. @@ -891,7 +891,7 @@ # #------------ # -# rippled creates 4 SQLite database to hold bookkeeping information +# xrpld creates 4 SQLite database to hold bookkeeping information # about transactions, local credentials, and various other things. # It also creates the NodeDB, which holds all the objects that # make up the current and historical ledgers. @@ -902,7 +902,7 @@ # the performance of the server. # # Partial pathnames will be considered relative to the location of -# the rippled.cfg file. +# the xrpld.cfg file. # # [node_db] Settings for the Node Database (required) # @@ -920,11 +920,11 @@ # type = NuDB # # NuDB is a high-performance database written by Ripple Labs and optimized -# for rippled and solid-state drives. +# for xrpld and solid-state drives. # # NuDB maintains its high speed regardless of the amount of history # stored. Online delete may be selected, but is not required. NuDB is -# available on all platforms that rippled runs on. +# available on all platforms that xrpld runs on. # # type = RocksDB # @@ -940,23 +940,7 @@ # # path Location to store the database # -# Optional keys -# -# cache_size Size of cache for database records. Default is 16384. -# Setting this value to 0 will use the default value. -# -# cache_age Length of time in minutes to keep database records -# cached. Default is 5 minutes. Setting this value to -# 0 will use the default value. -# -# Note: if neither cache_size nor cache_age is -# specified, the cache for database records will not -# be created. If only one of cache_size or cache_age -# is specified, the cache will be created using the -# default value for the unspecified parameter. -# -# Note: the cache will not be created if online_delete -# is specified. +# Optional keys for NuDB and RocksDB: # # fast_load Boolean. If set, load the last persisted ledger # from disk upon process start before syncing to @@ -964,8 +948,6 @@ # if sufficient IOPS capacity is available. # Default 0. # -# Optional keys for NuDB or RocksDB: -# # earliest_seq The default is 32570 to match the XRP ledger # network's earliest allowed sequence. Alternate # networks may set this value. Minimum value of 1. @@ -1049,7 +1031,7 @@ # # recovery_wait_seconds # The online delete process checks periodically -# that rippled is still in sync with the network, +# that xrpld is still in sync with the network, # and that the validated ledger is less than # 'age_threshold_seconds' old. If not, then continue # sleeping for this number of seconds and @@ -1069,8 +1051,8 @@ # The server creates and maintains 4 to 5 bookkeeping SQLite databases in # the 'database_path' location. If you omit this configuration setting, # the server creates a directory called "db" located in the same place as -# your rippled.cfg file. -# Partial pathnames are relative to the location of the rippled executable. +# your xrpld.cfg file. +# Partial pathnames are relative to the location of the xrpld executable. # # [sqlite] Tuning settings for the SQLite databases (optional) # @@ -1120,7 +1102,7 @@ # The default is "wal", which uses a write-ahead # log to implement database transactions. # Alternately, "memory" saves disk I/O, but if -# rippled crashes during a transaction, the +# xrpld crashes during a transaction, the # database is likely to be corrupted. # See https://www.sqlite.org/pragma.html#pragma_journal_mode # for more details about the available options. @@ -1130,7 +1112,7 @@ # synchronous Valid values: off, normal, full, extra # The default is "normal", which works well with # the "wal" journal mode. Alternatively, "off" -# allows rippled to continue as soon as data is +# allows xrpld to continue as soon as data is # passed to the OS, which can significantly # increase speed, but risks data corruption if # the host computer crashes before writing that @@ -1144,7 +1126,7 @@ # The default is "file", which will use files # for temporary database tables and indices. # Alternatively, "memory" may save I/O, but -# rippled does not currently use many, if any, +# xrpld does not currently use many, if any, # of these temporary objects. # See https://www.sqlite.org/pragma.html#pragma_temp_store # for more details about the available options. @@ -1173,7 +1155,7 @@ # # These settings are designed to help server administrators diagnose # problems, and obtain detailed information about the activities being -# performed by the rippled process. +# performed by the xrpld process. # # # @@ -1190,7 +1172,7 @@ # # Configuration parameters for the Beast. Insight stats collection module. # -# Insight is a module that collects information from the areas of rippled +# Insight is a module that collects information from the areas of xrpld # that have instrumentation. The configuration parameters control where the # collection metrics are sent. The parameters are expressed as key = value # pairs with no white space. The main parameter is the choice of server: @@ -1199,7 +1181,7 @@ # # Choice of server to send metrics to. Currently the only choice is # "statsd" which sends UDP packets to a StatsD daemon, which must be -# running while rippled is running. More information on StatsD is +# running while xrpld is running. More information on StatsD is # available here: # https://github.com/b/statsd_spec # @@ -1209,7 +1191,7 @@ # in the format, n.n.n.n:port. # # "prefix" A string prepended to each collected metric. This is used -# to distinguish between different running instances of rippled. +# to distinguish between different running instances of xrpld. # # If this section is missing, or the server type is unspecified or unknown, # statistics are not collected or reported. @@ -1236,7 +1218,7 @@ # # Example: # [perf] -# perf_log=/var/log/rippled/perf.log +# perf_log=/var/log/xrpld/perf.log # log_interval=2 # #------------------------------------------------------------------------------- @@ -1246,7 +1228,7 @@ #---------- # # The vote settings configure settings for the entire Ripple network. -# While a single instance of rippled cannot unilaterally enforce network-wide +# While a single instance of xrpld cannot unilaterally enforce network-wide # settings, these choices become part of the instance's vote during the # consensus process for each voting ledger. # @@ -1260,7 +1242,7 @@ # The reference transaction is the simplest form of transaction. # It represents an XRP payment between two parties. # -# If this parameter is unspecified, rippled will use an internal +# If this parameter is unspecified, xrpld will use an internal # default. Don't change this without understanding the consequences. # # Example: @@ -1272,7 +1254,7 @@ # account's XRP balance that is at or below the reserve may only be # spent on transaction fees, and not transferred out of the account. # -# If this parameter is unspecified, rippled will use an internal +# If this parameter is unspecified, xrpld will use an internal # default. Don't change this without understanding the consequences. # # Example: @@ -1284,7 +1266,7 @@ # each ledger item owned by the account. Ledger items an account may # own include trust lines, open orders, and tickets. # -# If this parameter is unspecified, rippled will use an internal +# If this parameter is unspecified, xrpld will use an internal # default. Don't change this without understanding the consequences. # # Example: @@ -1326,7 +1308,7 @@ # tool instead. # # This flag has no effect on the "sign" and "sign_for" command line options -# that rippled makes available. +# that xrpld makes available. # # The default value of this field is "false" # @@ -1405,7 +1387,7 @@ #-------------------- # # Administrators can use these values as a starting point for configuring -# their instance of rippled, but each value should be checked to make sure +# their instance of xrpld, but each value should be checked to make sure # it meets the business requirements for the organization. # # Server @@ -1415,7 +1397,7 @@ # "peer" # # Peer protocol open to everyone. This is required to accept -# incoming rippled connections. This does not affect automatic +# incoming xrpld connections. This does not affect automatic # or manual outgoing Peer protocol connections. # # "rpc" @@ -1432,7 +1414,7 @@ # # ETL commands for Clio. We recommend setting secure_gateway # in this section to a comma-separated list of the addresses -# of your Clio servers, in order to bypass rippled's rate limiting. +# of your Clio servers, in order to bypass xrpld's rate limiting. # # This port is commented out but can be enabled by removing # the '#' from each corresponding line including the entry under [server] @@ -1449,8 +1431,8 @@ # NOTE # # To accept connections on well known ports such as 80 (HTTP) or -# 443 (HTTPS), most operating systems will require rippled to -# run with administrator privileges, or else rippled will not start. +# 443 (HTTPS), most operating systems will require xrpld to +# run with administrator privileges, or else xrpld will not start. [server] port_rpc_admin_local @@ -1496,7 +1478,7 @@ secure_gateway = 127.0.0.1 #------------------------------------------------------------------------------- -# This is primary persistent datastore for rippled. This includes transaction +# This is primary persistent datastore for xrpld. This includes transaction # metadata, account states, and ledger headers. Helpful information can be # found at https://xrpl.org/capacity-planning.html#node-db-type # type=NuDB is recommended for non-validators with fast SSDs. Validators or @@ -1511,19 +1493,19 @@ secure_gateway = 127.0.0.1 # deletion. [node_db] type=NuDB -path=/var/lib/rippled/db/nudb +path=/var/lib/xrpld/db/nudb nudb_block_size=4096 online_delete=512 advisory_delete=0 [database_path] -/var/lib/rippled/db +/var/lib/xrpld/db # This needs to be an absolute directory reference, not a relative one. # Modify this value as required. [debug_logfile] -/var/log/rippled/debug.log +/var/log/xrpld/debug.log # To use the XRP test network # (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), @@ -1533,7 +1515,7 @@ advisory_delete=0 # File containing trusted validator keys or validator list publishers. # Unless an absolute path is specified, it will be considered relative to the -# folder in which the rippled.cfg file is located. +# folder in which the xrpld.cfg file is located. [validators_file] validators.txt diff --git a/cmake/CMakeFuncs.cmake b/cmake/CMakeFuncs.cmake index a4c66a120d..ec2d9db330 100644 --- a/cmake/CMakeFuncs.cmake +++ b/cmake/CMakeFuncs.cmake @@ -1,48 +1,29 @@ -macro(group_sources_in source_dir curdir) - file(GLOB children RELATIVE ${source_dir}/${curdir} - ${source_dir}/${curdir}/*) - foreach (child ${children}) - if (IS_DIRECTORY ${source_dir}/${curdir}/${child}) - group_sources_in(${source_dir} ${curdir}/${child}) - else() - string(REPLACE "/" "\\" groupname ${curdir}) - source_group(${groupname} FILES - ${source_dir}/${curdir}/${child}) - endif() - endforeach() -endmacro() - -macro(group_sources curdir) - group_sources_in(${PROJECT_SOURCE_DIR} ${curdir}) -endmacro() - macro (exclude_from_default target_) - set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_ALL ON) - set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) + set_target_properties(${target_} PROPERTIES EXCLUDE_FROM_ALL ON) + set_target_properties(${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) endmacro () macro (exclude_if_included target_) - get_directory_property(has_parent PARENT_DIRECTORY) - if (has_parent) - exclude_from_default (${target_}) - endif () + get_directory_property(has_parent PARENT_DIRECTORY) + if (has_parent) + exclude_from_default(${target_}) + endif () endmacro () find_package(Git) function (git_branch branch_val) - if (NOT GIT_FOUND) - return () - endif () - set (_branch "") - execute_process (COMMAND ${GIT_EXECUTABLE} "rev-parse" "--abbrev-ref" "HEAD" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - RESULT_VARIABLE _git_exit_code - OUTPUT_VARIABLE _temp_branch - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET) - if (_git_exit_code EQUAL 0) - set (_branch ${_temp_branch}) - endif () - set (${branch_val} "${_branch}" PARENT_SCOPE) + if (NOT GIT_FOUND) + return() + endif () + set(_branch "") + execute_process(COMMAND ${GIT_EXECUTABLE} "rev-parse" "--abbrev-ref" "HEAD" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE _git_exit_code + OUTPUT_VARIABLE _temp_branch + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) + if (_git_exit_code EQUAL 0) + set(_branch ${_temp_branch}) + endif () + set(${branch_val} "${_branch}" PARENT_SCOPE) endfunction () diff --git a/cmake/Ccache.cmake b/cmake/Ccache.cmake new file mode 100644 index 0000000000..000883cf6a --- /dev/null +++ b/cmake/Ccache.cmake @@ -0,0 +1,49 @@ +find_program(CCACHE_PATH "ccache") +if (NOT CCACHE_PATH) + return() +endif () + +# For Linux and macOS we can use the ccache binary directly. +if (NOT MSVC) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PATH}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PATH}") + message(STATUS "Found ccache: ${CCACHE_PATH}") + return() +endif () + +# For Windows more effort is required. The code below is a modified version of +# https://github.com/ccache/ccache/wiki/MS-Visual-Studio#usage-with-cmake. +if ("${CCACHE_PATH}" MATCHES "chocolatey") + message(DEBUG "Ccache path: ${CCACHE_PATH}") + # Chocolatey uses a shim executable that we cannot use directly, in which case we have to find the executable it + # points to. If we cannot find the target executable then we cannot use ccache. + find_program(BASH_PATH "bash") + if (NOT BASH_PATH) + message(WARNING "Could not find bash.") + return() + endif () + + execute_process(COMMAND bash -c + "export LC_ALL='en_US.UTF-8'; ${CCACHE_PATH} --shimgen-noop | grep -oP 'path to executable: \\K.+' | head -c -1" + OUTPUT_VARIABLE CCACHE_PATH) + + if (NOT CCACHE_PATH) + message(WARNING "Could not find ccache target.") + return() + endif () + file(TO_CMAKE_PATH "${CCACHE_PATH}" CCACHE_PATH) +endif () +message(STATUS "Found ccache: ${CCACHE_PATH}") + +# Tell cmake to use ccache for compiling with Visual Studio. +file(COPY_FILE ${CCACHE_PATH} ${CMAKE_BINARY_DIR}/cl.exe ONLY_IF_DIFFERENT) +set(CMAKE_VS_GLOBALS "CLToolExe=cl.exe" "CLToolPath=${CMAKE_BINARY_DIR}" "TrackFileAccess=false" + "UseMultiToolTask=true") + +# By default Visual Studio generators will use /Zi to capture debug information, which is not compatible with ccache, so +# tell it to use /Z7 instead. +if (MSVC) + foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) + string(REPLACE "/Zi" "/Z7" ${var_} "${${var_}}") + endforeach () +endif () diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake index c2b66c9cac..fcc4d44133 100644 --- a/cmake/CodeCoverage.cmake +++ b/cmake/CodeCoverage.cmake @@ -109,6 +109,9 @@ # - add a new function add_code_coverage_to_target # - remove some unused code # +# 2025-11-11, Bronek Kozicki +# - make EXECUTABLE and EXECUTABLE_ARGS optional +# # USAGE: # # 1. Copy this file into your cmake modules path. @@ -169,51 +172,47 @@ include(CMakeParseArguments) option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) # Check prereqs -find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +find_program(GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) -if(DEFINED CODE_COVERAGE_GCOV_TOOL) - set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") -elseif(DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) - set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - if(APPLE) - execute_process( COMMAND xcrun -f llvm-cov - OUTPUT_VARIABLE LLVMCOV_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - else() - find_program( LLVMCOV_PATH llvm-cov ) - endif() - if(LLVMCOV_PATH) - set(GCOV_TOOL "${LLVMCOV_PATH} gcov") - endif() -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - find_program( GCOV_PATH gcov ) - set(GCOV_TOOL "${GCOV_PATH}") -endif() +if (DEFINED CODE_COVERAGE_GCOV_TOOL) + set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") +elseif (DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) + set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if (APPLE) + execute_process(COMMAND xcrun -f llvm-cov OUTPUT_VARIABLE LLVMCOV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + else () + find_program(LLVMCOV_PATH llvm-cov) + endif () + if (LLVMCOV_PATH) + set(GCOV_TOOL "${LLVMCOV_PATH} gcov") + endif () +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + find_program(GCOV_PATH gcov) + set(GCOV_TOOL "${GCOV_PATH}") +endif () # Check supported compiler (Clang, GNU and Flang) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach(LANG ${LANGUAGES}) - if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) - message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") - endif() - elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" - AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang") - message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...") - endif() -endforeach() +foreach (LANG ${LANGUAGES}) + if ("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if ("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif () + elseif (NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES + "(LLVM)?[Ff]lang") + message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...") + endif () +endforeach () -set(COVERAGE_COMPILER_FLAGS "-g --coverage" - CACHE INTERNAL "") +set(COVERAGE_COMPILER_FLAGS "-g --coverage" CACHE INTERNAL "") set(COVERAGE_CXX_COMPILER_FLAGS "") set(COVERAGE_C_COMPILER_FLAGS "") set(COVERAGE_CXX_LINKER_FLAGS "") set(COVERAGE_C_LINKER_FLAGS "") -if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") +if (CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") include(CheckCXXCompilerFlag) include(CheckCCompilerFlag) include(CheckLinkerFlag) @@ -224,51 +223,51 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") set(COVERAGE_C_LINKER_FLAGS ${COVERAGE_COMPILER_FLAGS}) check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path) - if(HAVE_cxx_fprofile_abs_path) + if (HAVE_cxx_fprofile_abs_path) set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_CXX_COMPILER_FLAGS} -fprofile-abs-path") - endif() + endif () check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path) - if(HAVE_c_fprofile_abs_path) + if (HAVE_c_fprofile_abs_path) set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_C_COMPILER_FLAGS} -fprofile-abs-path") - endif() + endif () check_linker_flag(CXX -fprofile-abs-path HAVE_cxx_linker_fprofile_abs_path) - if(HAVE_cxx_linker_fprofile_abs_path) + if (HAVE_cxx_linker_fprofile_abs_path) set(COVERAGE_CXX_LINKER_FLAGS "${COVERAGE_CXX_LINKER_FLAGS} -fprofile-abs-path") - endif() + endif () check_linker_flag(C -fprofile-abs-path HAVE_c_linker_fprofile_abs_path) - if(HAVE_c_linker_fprofile_abs_path) + if (HAVE_c_linker_fprofile_abs_path) set(COVERAGE_C_LINKER_FLAGS "${COVERAGE_C_LINKER_FLAGS} -fprofile-abs-path") - endif() + endif () check_cxx_compiler_flag(-fprofile-update=atomic HAVE_cxx_fprofile_update) - if(HAVE_cxx_fprofile_update) + if (HAVE_cxx_fprofile_update) set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_CXX_COMPILER_FLAGS} -fprofile-update=atomic") - endif() + endif () check_c_compiler_flag(-fprofile-update=atomic HAVE_c_fprofile_update) - if(HAVE_c_fprofile_update) + if (HAVE_c_fprofile_update) set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_C_COMPILER_FLAGS} -fprofile-update=atomic") - endif() + endif () check_linker_flag(CXX -fprofile-update=atomic HAVE_cxx_linker_fprofile_update) - if(HAVE_cxx_linker_fprofile_update) + if (HAVE_cxx_linker_fprofile_update) set(COVERAGE_CXX_LINKER_FLAGS "${COVERAGE_CXX_LINKER_FLAGS} -fprofile-update=atomic") - endif() + endif () check_linker_flag(C -fprofile-update=atomic HAVE_c_linker_fprofile_update) - if(HAVE_c_linker_fprofile_update) + if (HAVE_c_linker_fprofile_update) set(COVERAGE_C_LINKER_FLAGS "${COVERAGE_C_LINKER_FLAGS} -fprofile-update=atomic") - endif() + endif () -endif() +endif () get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) +if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") -endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) +endif () # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) # Defines a target for running and collection code coverage information # Builds dependencies, runs the given executable and outputs reports. @@ -292,186 +291,181 @@ endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) # ) # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the # GCVOR command. -function(setup_target_for_coverage_gcovr) +function (setup_target_for_coverage_gcovr) set(options NONE) set(oneValueArgs BASE_DIRECTORY NAME FORMAT) set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - if(NOT GCOV_TOOL) + if (NOT GCOV_TOOL) message(FATAL_ERROR "Could not find gcov or llvm-cov tool! Aborting...") - endif() + endif () - if(NOT GCOVR_PATH) + if (NOT GCOVR_PATH) message(FATAL_ERROR "Could not find gcovr tool! Aborting...") - endif() + endif () # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) + if (DEFINED Coverage_BASE_DIRECTORY) get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() + else () set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() + endif () - if(NOT DEFINED Coverage_FORMAT) + if (NOT DEFINED Coverage_FORMAT) set(Coverage_FORMAT xml) - endif() + endif () - if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) + if (NOT DEFINED Coverage_EXECUTABLE AND DEFINED Coverage_EXECUTABLE_ARGS) + message(FATAL_ERROR "EXECUTABLE_ARGS must not be set if EXECUTABLE is not set") + endif () + + if ("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...") - else() - if((Coverage_FORMAT STREQUAL "html-details") - OR (Coverage_FORMAT STREQUAL "html-nested")) + else () + if ((Coverage_FORMAT STREQUAL "html-details") OR (Coverage_FORMAT STREQUAL "html-nested")) set(GCOVR_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html) set(GCOVR_CREATE_FOLDER ${PROJECT_BINARY_DIR}/${Coverage_NAME}) - elseif(Coverage_FORMAT STREQUAL "html-single") + elseif (Coverage_FORMAT STREQUAL "html-single") set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.html) - elseif((Coverage_FORMAT STREQUAL "json-summary") - OR (Coverage_FORMAT STREQUAL "json-details") - OR (Coverage_FORMAT STREQUAL "coveralls")) + elseif ((Coverage_FORMAT STREQUAL "json-summary") OR (Coverage_FORMAT STREQUAL "json-details") + OR (Coverage_FORMAT STREQUAL "coveralls")) set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.json) - elseif(Coverage_FORMAT STREQUAL "txt") + elseif (Coverage_FORMAT STREQUAL "txt") set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt) - elseif(Coverage_FORMAT STREQUAL "csv") + elseif (Coverage_FORMAT STREQUAL "csv") set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv) - elseif(Coverage_FORMAT STREQUAL "lcov") + elseif (Coverage_FORMAT STREQUAL "lcov") set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov) - else() + else () set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml) - endif() - endif() + endif () + endif () - if((Coverage_FORMAT STREQUAL "cobertura") - OR (Coverage_FORMAT STREQUAL "xml")) - list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura "${GCOVR_OUTPUT_FILE}" ) - list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty ) + if ((Coverage_FORMAT STREQUAL "cobertura") OR (Coverage_FORMAT STREQUAL "xml")) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura "${GCOVR_OUTPUT_FILE}") + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty) set(Coverage_FORMAT cobertura) # overwrite xml - elseif(Coverage_FORMAT STREQUAL "sonarqube") - list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" ) - elseif(Coverage_FORMAT STREQUAL "jacoco") - list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" ) - list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty ) - elseif(Coverage_FORMAT STREQUAL "clover") - list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" ) - list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty ) - elseif(Coverage_FORMAT STREQUAL "lcov") - list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" ) - elseif(Coverage_FORMAT STREQUAL "json-summary") - list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" ) + elseif (Coverage_FORMAT STREQUAL "sonarqube") + list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}") + elseif (Coverage_FORMAT STREQUAL "jacoco") + list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}") + list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty) + elseif (Coverage_FORMAT STREQUAL "clover") + list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}") + list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty) + elseif (Coverage_FORMAT STREQUAL "lcov") + list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}") + elseif (Coverage_FORMAT STREQUAL "json-summary") + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}") list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty) - elseif(Coverage_FORMAT STREQUAL "json-details") - list(APPEND GCOVR_ADDITIONAL_ARGS --json "${GCOVR_OUTPUT_FILE}" ) + elseif (Coverage_FORMAT STREQUAL "json-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --json "${GCOVR_OUTPUT_FILE}") list(APPEND GCOVR_ADDITIONAL_ARGS --json-pretty) - elseif(Coverage_FORMAT STREQUAL "coveralls") - list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls "${GCOVR_OUTPUT_FILE}" ) + elseif (Coverage_FORMAT STREQUAL "coveralls") + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls "${GCOVR_OUTPUT_FILE}") list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls-pretty) - elseif(Coverage_FORMAT STREQUAL "csv") - list(APPEND GCOVR_ADDITIONAL_ARGS --csv "${GCOVR_OUTPUT_FILE}" ) - elseif(Coverage_FORMAT STREQUAL "txt") - list(APPEND GCOVR_ADDITIONAL_ARGS --txt "${GCOVR_OUTPUT_FILE}" ) - elseif(Coverage_FORMAT STREQUAL "html-single") - list(APPEND GCOVR_ADDITIONAL_ARGS --html "${GCOVR_OUTPUT_FILE}" ) + elseif (Coverage_FORMAT STREQUAL "csv") + list(APPEND GCOVR_ADDITIONAL_ARGS --csv "${GCOVR_OUTPUT_FILE}") + elseif (Coverage_FORMAT STREQUAL "txt") + list(APPEND GCOVR_ADDITIONAL_ARGS --txt "${GCOVR_OUTPUT_FILE}") + elseif (Coverage_FORMAT STREQUAL "html-single") + list(APPEND GCOVR_ADDITIONAL_ARGS --html "${GCOVR_OUTPUT_FILE}") list(APPEND GCOVR_ADDITIONAL_ARGS --html-self-contained) - elseif(Coverage_FORMAT STREQUAL "html-nested") - list(APPEND GCOVR_ADDITIONAL_ARGS --html-nested "${GCOVR_OUTPUT_FILE}" ) - elseif(Coverage_FORMAT STREQUAL "html-details") - list(APPEND GCOVR_ADDITIONAL_ARGS --html-details "${GCOVR_OUTPUT_FILE}" ) - else() + elseif (Coverage_FORMAT STREQUAL "html-nested") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-nested "${GCOVR_OUTPUT_FILE}") + elseif (Coverage_FORMAT STREQUAL "html-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-details "${GCOVR_OUTPUT_FILE}") + else () message(FATAL_ERROR "Unsupported output style ${Coverage_FORMAT}! Aborting...") - endif() + endif () # Collect excludes (CMake 3.4+: Also compute absolute paths) set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) + foreach (EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if (CMAKE_VERSION VERSION_GREATER 3.4) get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() + endif () list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() + endforeach () list(REMOVE_DUPLICATES GCOVR_EXCLUDES) # Combine excludes to several -e arguments set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) + foreach (EXCLUDE ${GCOVR_EXCLUDES}) list(APPEND GCOVR_EXCLUDE_ARGS "-e") list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() + endforeach () # Set up commands which will be run to generate coverage data - # Run tests - set(GCOVR_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) + # If EXECUTABLE is not set, the user is expected to run the tests manually + # before running the coverage target NAME + if (DEFINED Coverage_EXECUTABLE) + set(GCOVR_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) + endif () # Create folder - if(DEFINED GCOVR_CREATE_FOLDER) - set(GCOVR_FOLDER_CMD - ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) - else() - set(GCOVR_FOLDER_CMD echo) # dummy - endif() + if (DEFINED GCOVR_CREATE_FOLDER) + set(GCOVR_FOLDER_CMD ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) + endif () # Running gcovr set(GCOVR_CMD ${GCOVR_PATH} - --gcov-executable ${GCOV_TOOL} + --gcov-executable + ${GCOV_TOOL} --gcov-ignore-parse-errors=negative_hits.warn_once_per_file - -r ${BASEDIR} + -r + ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} ${GCOVR_EXCLUDE_ARGS} - --object-directory=${PROJECT_BINARY_DIR} - ) + --object-directory=${PROJECT_BINARY_DIR}) - if(CODE_COVERAGE_VERBOSE) + if (CODE_COVERAGE_VERBOSE) message(STATUS "Executed command report") - message(STATUS "Command to run tests: ") - string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") - message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}") + if (NOT "${GCOVR_EXEC_TESTS_CMD}" STREQUAL "") + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}") + endif () - if(NOT GCOVR_FOLDER_CMD STREQUAL "echo") + if (NOT "${GCOVR_FOLDER_CMD}" STREQUAL "") message(STATUS "Command to create a folder: ") string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}") message(STATUS "${GCOVR_FOLDER_CMD_SPACED}") - endif() + endif () message(STATUS "Command to generate gcovr coverage data: ") string(REPLACE ";" " " GCOVR_CMD_SPACED "${GCOVR_CMD}") message(STATUS "${GCOVR_CMD_SPACED}") - endif() + endif () add_custom_target(${Coverage_NAME} - COMMAND ${GCOVR_EXEC_TESTS_CMD} - COMMAND ${GCOVR_FOLDER_CMD} - COMMAND ${GCOVR_CMD} - - BYPRODUCTS ${GCOVR_OUTPUT_FILE} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce code coverage report." - ) + COMMAND ${GCOVR_EXEC_TESTS_CMD} + COMMAND ${GCOVR_FOLDER_CMD} + COMMAND ${GCOVR_CMD} + BYPRODUCTS ${GCOVR_OUTPUT_FILE} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce code coverage report.") # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND echo - COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}" - ) -endfunction() # setup_target_for_coverage_gcovr + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD COMMAND echo + COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}") +endfunction () # setup_target_for_coverage_gcovr -function(add_code_coverage_to_target name scope) +function (add_code_coverage_to_target name scope) separate_arguments(COVERAGE_CXX_COMPILER_FLAGS NATIVE_COMMAND "${COVERAGE_CXX_COMPILER_FLAGS}") separate_arguments(COVERAGE_C_COMPILER_FLAGS NATIVE_COMMAND "${COVERAGE_C_COMPILER_FLAGS}") separate_arguments(COVERAGE_CXX_LINKER_FLAGS NATIVE_COMMAND "${COVERAGE_CXX_LINKER_FLAGS}") separate_arguments(COVERAGE_C_LINKER_FLAGS NATIVE_COMMAND "${COVERAGE_C_LINKER_FLAGS}") # Add compiler options to the target - target_compile_options(${name} ${scope} - $<$:${COVERAGE_CXX_COMPILER_FLAGS}> - $<$:${COVERAGE_C_COMPILER_FLAGS}>) + target_compile_options(${name} ${scope} $<$:${COVERAGE_CXX_COMPILER_FLAGS}> + $<$:${COVERAGE_C_COMPILER_FLAGS}>) - target_link_libraries (${name} ${scope} - $<$:${COVERAGE_CXX_LINKER_FLAGS} gcov> - $<$:${COVERAGE_C_LINKER_FLAGS} gcov> - ) -endfunction() # add_code_coverage_to_target + target_link_libraries(${name} ${scope} $<$:${COVERAGE_CXX_LINKER_FLAGS}> + $<$:${COVERAGE_C_LINKER_FLAGS}>) +endfunction () # add_code_coverage_to_target diff --git a/cmake/CompilationEnv.cmake b/cmake/CompilationEnv.cmake new file mode 100644 index 0000000000..59b903c13a --- /dev/null +++ b/cmake/CompilationEnv.cmake @@ -0,0 +1,58 @@ +# Shared detection of compiler, operating system, and architecture. +# +# This module centralizes environment detection so that other CMake modules can use the same variables instead of +# repeating checks on CMAKE_* and built-in platform variables. + +# Only run once per configure step. +include_guard(GLOBAL) + +# -------------------------------------------------------------------- +# Compiler detection (C++) +# -------------------------------------------------------------------- +set(is_clang FALSE) +set(is_gcc FALSE) +set(is_msvc FALSE) +set(is_xcode FALSE) + +if (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") # Clang or AppleClang + set(is_clang TRUE) +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(is_gcc TRUE) +elseif (MSVC) + set(is_msvc TRUE) +else () + message(FATAL_ERROR "Unsupported C++ compiler: ${CMAKE_CXX_COMPILER_ID}") +endif () + +# Xcode generator detection +if (CMAKE_GENERATOR STREQUAL "Xcode") + set(is_xcode TRUE) +endif () + +# -------------------------------------------------------------------- +# Operating system detection +# -------------------------------------------------------------------- +set(is_linux FALSE) +set(is_windows FALSE) +set(is_macos FALSE) + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(is_linux TRUE) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(is_windows TRUE) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(is_macos TRUE) +endif () + +# -------------------------------------------------------------------- +# Architecture +# -------------------------------------------------------------------- +set(is_amd64 FALSE) +set(is_arm64 FALSE) +if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + set(is_amd64 TRUE) +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") + set(is_arm64 TRUE) +else () + message(FATAL_ERROR "Unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}") +endif () diff --git a/cmake/RippleConfig.cmake b/cmake/RippleConfig.cmake deleted file mode 100644 index e0de962d3f..0000000000 --- a/cmake/RippleConfig.cmake +++ /dev/null @@ -1,56 +0,0 @@ -include (CMakeFindDependencyMacro) -# need to represent system dependencies of the lib here -#[=========================================================[ - Boost -#]=========================================================] -if (static OR APPLE OR MSVC) - set (Boost_USE_STATIC_LIBS ON) -endif () -set (Boost_USE_MULTITHREADED ON) -if (static OR MSVC) - set (Boost_USE_STATIC_RUNTIME ON) -else () - set (Boost_USE_STATIC_RUNTIME OFF) -endif () -find_dependency (Boost 1.70 - COMPONENTS - chrono - container - context - coroutine - date_time - filesystem - program_options - regex - system - thread) -#[=========================================================[ - OpenSSL -#]=========================================================] -if (NOT DEFINED OPENSSL_ROOT_DIR) - if (DEFINED ENV{OPENSSL_ROOT}) - set (OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT}) - elseif (APPLE) - find_program (homebrew brew) - if (homebrew) - execute_process (COMMAND ${homebrew} --prefix openssl - OUTPUT_VARIABLE OPENSSL_ROOT_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) - endif () - endif () - file (TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" OPENSSL_ROOT_DIR) -endif () - -if (static OR APPLE OR MSVC) - set (OPENSSL_USE_STATIC_LIBS ON) -endif () -set (OPENSSL_MSVC_STATIC_RT ON) -find_dependency (OpenSSL REQUIRED) -find_dependency (ZLIB) -find_dependency (date) -if (TARGET ZLIB::ZLIB) - set_target_properties(OpenSSL::Crypto PROPERTIES - INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) -endif () - -include ("${CMAKE_CURRENT_LIST_DIR}/RippleTargets.cmake") diff --git a/cmake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake deleted file mode 100644 index 4d16222cbe..0000000000 --- a/cmake/RippledCompiler.cmake +++ /dev/null @@ -1,193 +0,0 @@ -#[===================================================================[ - setup project-wide compiler settings -#]===================================================================] - -#[=========================================================[ - TODO some/most of these common settings belong in a - toolchain file, especially the ABI-impacting ones -#]=========================================================] -add_library (common INTERFACE) -add_library (Ripple::common ALIAS common) -# add a single global dependency on this interface lib -link_libraries (Ripple::common) -set_target_properties (common - PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_CXX_EXTENSIONS OFF) -target_compile_definitions (common - INTERFACE - $<$:DEBUG _DEBUG> - #[===[ - NOTE: CMAKE release builds already have NDEBUG defined, so no need to add it - explicitly except for the special case of (profile ON) and (assert OFF). - Presumably this is because we don't want profile builds asserting unless - asserts were specifically requested. - ]===] - $<$,$>>:NDEBUG> - # TODO: Remove once we have migrated functions from OpenSSL 1.x to 3.x. - OPENSSL_SUPPRESS_DEPRECATED -) - -if (MSVC) - # remove existing exception flag since we set it to -EHa - string (REGEX REPLACE "[-/]EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - - foreach (var_ - CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) - - # also remove dynamic runtime - string (REGEX REPLACE "[-/]MD[d]*" " " ${var_} "${${var_}}") - - # /ZI (Edit & Continue debugging information) is incompatible with Gy- - string (REPLACE "/ZI" "/Zi" ${var_} "${${var_}}") - - # omit debug info completely under CI (not needed) - if (is_ci) - string (REPLACE "/Zi" " " ${var_} "${${var_}}") - endif () - endforeach () - - target_compile_options (common - INTERFACE - -bigobj # Increase object file max size - -fp:precise # Floating point behavior - -Gd # __cdecl calling convention - -Gm- # Minimal rebuild: disabled - -Gy- # Function level linking: disabled - -MP # Multiprocessor compilation - -openmp- # pragma omp: disabled - -errorReport:none # No error reporting to Internet - -nologo # Suppress login banner - -wd4018 # Disable signed/unsigned comparison warnings - -wd4244 # Disable float to int possible loss of data warnings - -wd4267 # Disable size_t to T possible loss of data warnings - -wd4800 # Disable C4800(int to bool performance) - -wd4503 # Decorated name length exceeded, name was truncated - $<$: - -EHa - -GR - > - $<$:-Ox> - $<$,$>: - -GS - -Zc:forScope - > - # static runtime - $<$:-MTd> - $<$>:-MT> - $<$:-WX> - ) - target_compile_definitions (common - INTERFACE - _WIN32_WINNT=0x6000 - _SCL_SECURE_NO_WARNINGS - _CRT_SECURE_NO_WARNINGS - WIN32_CONSOLE - WIN32_LEAN_AND_MEAN - NOMINMAX - # TODO: Resolve these warnings, don't just silence them - _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS - $<$,$>:_CRTDBG_MAP_ALLOC>) - target_link_libraries (common - INTERFACE - -errorreport:none - -machine:X64) -else () - target_compile_options (common - INTERFACE - -Wall - -Wdeprecated - $<$:-Wno-deprecated-declarations> - $<$:-Wextra -Wno-unused-parameter> - $<$:-Werror> - -fstack-protector - -Wno-sign-compare - -Wno-unused-but-set-variable - $<$>:-fno-strict-aliasing> - # tweak gcc optimization for debug - $<$,$>:-O0> - # Add debug symbols to release config - $<$:-g>) - target_link_libraries (common - INTERFACE - -rdynamic - $<$:-Wl,-z,relro,-z,now,--build-id> - # link to static libc/c++ iff: - # * static option set and - # * NOT APPLE (AppleClang does not support static libc/c++) and - # * NOT san (sanitizers typically don't work with static libc/c++) - $<$,$>,$>>: - -static-libstdc++ - -static-libgcc - >) -endif () - -# Antithesis instrumentation will only be built and deployed using machines running Linux. -if (voidstar) - if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...") - elseif (NOT is_linux) - message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...") - elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) - message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...") - endif () -endif () - -if (use_mold) - # use mold linker if available - execute_process ( - COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=mold -Wl,--version - ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) - if ("${LD_VERSION}" MATCHES "mold") - target_link_libraries (common INTERFACE -fuse-ld=mold) - endif () - unset (LD_VERSION) -elseif (use_gold AND is_gcc) - # use gold linker if available - execute_process ( - COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version - ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) - #[=========================================================[ - NOTE: THE gold linker inserts -rpath as DT_RUNPATH by - default intead of DT_RPATH, so you might have slightly - unexpected runtime ld behavior if you were expecting - DT_RPATH. Specify --disable-new-dtags to gold if you do - not want the default DT_RUNPATH behavior. This rpath - treatment as well as static/dynamic selection means that - gold does not currently have ideal default behavior when - we are using jemalloc. Thus for simplicity we don't use - it when jemalloc is requested. An alternative to - disabling would be to figure out all the settings - required to make gold play nicely with jemalloc. - #]=========================================================] - if (("${LD_VERSION}" MATCHES "GNU gold") AND (NOT jemalloc)) - target_link_libraries (common - INTERFACE - -fuse-ld=gold - -Wl,--no-as-needed - #[=========================================================[ - see https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1253638/comments/5 - DT_RUNPATH does not work great for transitive - dependencies (of which boost has a few) - so just - switch to DT_RPATH if doing dynamic linking with gold - #]=========================================================] - $<$>:-Wl,--disable-new-dtags>) - endif () - unset (LD_VERSION) -elseif (use_lld) - # use lld linker if available - execute_process ( - COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version - ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) - if ("${LD_VERSION}" MATCHES "LLD") - target_link_libraries (common INTERFACE -fuse-ld=lld) - endif () - unset (LD_VERSION) -endif() - - -if (assert) - foreach (var_ CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) - STRING (REGEX REPLACE "[-/]DNDEBUG" "" ${var_} "${${var_}}") - endforeach () -endif () diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake deleted file mode 100644 index 05bbde8463..0000000000 --- a/cmake/RippledCore.cmake +++ /dev/null @@ -1,229 +0,0 @@ -#[===================================================================[ - Exported targets. -#]===================================================================] - -include(target_protobuf_sources) - -# Protocol buffers cannot participate in a unity build, -# because all the generated sources -# define a bunch of `static const` variables with the same names, -# so we just build them as a separate library. -add_library(xrpl.libpb) -set_target_properties(xrpl.libpb PROPERTIES UNITY_BUILD OFF) -target_protobuf_sources(xrpl.libpb xrpl/proto - LANGUAGE cpp - IMPORT_DIRS include/xrpl/proto - PROTOS include/xrpl/proto/ripple.proto -) - -file(GLOB_RECURSE protos "include/xrpl/proto/org/*.proto") -target_protobuf_sources(xrpl.libpb xrpl/proto - LANGUAGE cpp - IMPORT_DIRS include/xrpl/proto - PROTOS "${protos}" -) -target_protobuf_sources(xrpl.libpb xrpl/proto - LANGUAGE grpc - IMPORT_DIRS include/xrpl/proto - PROTOS "${protos}" - PLUGIN protoc-gen-grpc=$ - GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc -) - -target_compile_options(xrpl.libpb - PUBLIC - $<$:-wd4996> - $<$: - --system-header-prefix="google/protobuf" - -Wno-deprecated-dynamic-exception-spec - > - PRIVATE - $<$:-wd4065> - $<$>:-Wno-deprecated-declarations> -) - -target_link_libraries(xrpl.libpb - PUBLIC - protobuf::libprotobuf - gRPC::grpc++ -) - -# TODO: Clean up the number of library targets later. -add_library(xrpl.imports.main INTERFACE) - -target_link_libraries(xrpl.imports.main - INTERFACE - absl::random_random - date::date - ed25519::ed25519 - LibArchive::LibArchive - OpenSSL::Crypto - Ripple::boost - Ripple::libs - Ripple::opts - Ripple::syslibs - secp256k1::secp256k1 - xrpl.libpb - xxHash::xxhash - $<$:antithesis-sdk-cpp> -) - -include(add_module) -include(target_link_modules) - -# Level 01 -add_module(xrpl beast) -target_link_libraries(xrpl.libxrpl.beast PUBLIC - xrpl.imports.main - xrpl.libpb -) - -# Level 02 -add_module(xrpl basics) -target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast) - -# Level 03 -add_module(xrpl json) -target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics) - -add_module(xrpl crypto) -target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics) - -# Level 04 -add_module(xrpl protocol) -target_link_libraries(xrpl.libxrpl.protocol PUBLIC - xrpl.libxrpl.crypto - xrpl.libxrpl.json -) - -# Level 05 -add_module(xrpl resource) -target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol) - -# Level 06 -add_module(xrpl net) -target_link_libraries(xrpl.libxrpl.net PUBLIC - xrpl.libxrpl.basics - xrpl.libxrpl.json - xrpl.libxrpl.protocol - xrpl.libxrpl.resource -) - -add_module(xrpl server) -target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol) - -add_module(xrpl nodestore) -target_link_libraries(xrpl.libxrpl.nodestore PUBLIC - xrpl.libxrpl.basics - xrpl.libxrpl.json - xrpl.libxrpl.protocol -) - -add_module(xrpl shamap) -target_link_libraries(xrpl.libxrpl.shamap PUBLIC - xrpl.libxrpl.basics - xrpl.libxrpl.crypto - xrpl.libxrpl.protocol - xrpl.libxrpl.nodestore -) - -add_module(xrpl ledger) -target_link_libraries(xrpl.libxrpl.ledger PUBLIC - xrpl.libxrpl.basics - xrpl.libxrpl.json - xrpl.libxrpl.protocol -) - -add_library(xrpl.libxrpl) -set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl) - -add_library(xrpl::libxrpl ALIAS xrpl.libxrpl) - -file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp" -) -target_sources(xrpl.libxrpl PRIVATE ${sources}) - -target_link_modules(xrpl PUBLIC - basics - beast - crypto - json - protocol - resource - server - nodestore - shamap - net - ledger -) - -# All headers in libxrpl are in modules. -# Uncomment this stanza if you have not yet moved new headers into a module. -# target_include_directories(xrpl.libxrpl -# PRIVATE -# $ -# PUBLIC -# $ -# $) - -if(xrpld) - add_executable(rippled) - if(tests) - target_compile_definitions(rippled PUBLIC ENABLE_TESTS) - target_compile_definitions(rippled PRIVATE - UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE} - ) - endif() - target_include_directories(rippled - PRIVATE - $ - ) - - file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" - ) - target_sources(rippled PRIVATE ${sources}) - - if(tests) - file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" - ) - target_sources(rippled PRIVATE ${sources}) - endif() - - target_link_libraries(rippled - Ripple::boost - Ripple::opts - Ripple::libs - xrpl.libxrpl - ) - exclude_if_included(rippled) - # define a macro for tests that might need to - # be exluded or run differently in CI environment - if(is_ci) - target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) - endif () - - if(voidstar) - target_compile_options(rippled - PRIVATE - -fsanitize-coverage=trace-pc-guard - ) - # rippled requires access to antithesis-sdk-cpp implementation file - # antithesis_instrumentation.h, which is not exported as INTERFACE - target_include_directories(rippled - PRIVATE - ${CMAKE_SOURCE_DIR}/external/antithesis-sdk - ) - endif() - - # any files that don't play well with unity should be added here - if(tests) - set_source_files_properties( - # these two seem to produce conflicts in beast teardown template methods - src/test/rpc/ValidatorRPC_test.cpp - src/test/ledger/Invariants_test.cpp - PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) - endif() -endif() diff --git a/cmake/RippledCov.cmake b/cmake/RippledCov.cmake deleted file mode 100644 index 6cbe2ff921..0000000000 --- a/cmake/RippledCov.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#[===================================================================[ - coverage report target -#]===================================================================] - -if(NOT coverage) - message(FATAL_ERROR "Code coverage not enabled! Aborting ...") -endif() - -if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") - return() -endif() - -include(CodeCoverage) - -# The instructions for these commands come from the `CodeCoverage` module, -# which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, -# then locally changed (see CHANGES: section in `CodeCoverage.cmake`) - -set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) -if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") - separate_arguments(GCOVR_ADDITIONAL_ARGS) -endif() - -list(APPEND GCOVR_ADDITIONAL_ARGS - --exclude-throw-branches - --exclude-noncode-lines - --exclude-unreachable-branches -s - -j ${coverage_test_parallelism}) - -setup_target_for_coverage_gcovr( - NAME coverage - FORMAT ${coverage_format} - EXECUTABLE rippled - EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log - EXCLUDE "src/test" "src/tests" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" - DEPENDENCIES rippled -) - -add_code_coverage_to_target(opts INTERFACE) diff --git a/cmake/RippledDocs.cmake b/cmake/RippledDocs.cmake deleted file mode 100644 index dda277bffa..0000000000 --- a/cmake/RippledDocs.cmake +++ /dev/null @@ -1,85 +0,0 @@ -#[===================================================================[ - docs target (optional) -#]===================================================================] - -option(with_docs "Include the docs target?" FALSE) - -if(NOT (with_docs OR only_docs)) - return() -endif() - -find_package(Doxygen) -if(NOT TARGET Doxygen::doxygen) - message(STATUS "doxygen executable not found -- skipping docs target") - return() -endif() - -set(doxygen_output_directory "${CMAKE_BINARY_DIR}/docs") -set(doxygen_include_path "${CMAKE_CURRENT_SOURCE_DIR}/src") -set(doxygen_index_file "${doxygen_output_directory}/html/index.html") -set(doxyfile "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile") - -file(GLOB_RECURSE doxygen_input - docs/*.md - include/*.h - include/*.cpp - include/*.md - src/*.h - src/*.cpp - src/*.md - Builds/*.md - *.md) -list(APPEND doxygen_input - external/README.md - ) -set(dependencies "${doxygen_input}" "${doxyfile}") - -function(verbose_find_path variable name) - # find_path sets a CACHE variable, so don't try using a "local" variable. - find_path(${variable} "${name}" ${ARGN}) - if(NOT ${variable}) - message(NOTICE "could not find ${name}") - else() - message(STATUS "found ${name}: ${${variable}}/${name}") - endif() -endfunction() - -verbose_find_path(doxygen_plantuml_jar_path plantuml.jar PATH_SUFFIXES share/plantuml) -verbose_find_path(doxygen_dot_path dot) - -# https://en.cppreference.com/w/Cppreference:Archives -# https://stackoverflow.com/questions/60822559/how-to-move-a-file-download-from-configure-step-to-build-step -set(download_script "${CMAKE_BINARY_DIR}/docs/download-cppreference.cmake") -file(WRITE - "${download_script}" - "file(DOWNLOAD \ - https://github.com/PeterFeicht/cppreference-doc/releases/download/v20250209/html-book-20250209.zip \ - ${CMAKE_BINARY_DIR}/docs/cppreference.zip \ - EXPECTED_HASH MD5=bda585f72fbca4b817b29a3d5746567b \ - )\n \ - execute_process( \ - COMMAND \"${CMAKE_COMMAND}\" -E tar -xf cppreference.zip \ - )\n" -) -set(tagfile "${CMAKE_BINARY_DIR}/docs/cppreference-doxygen-web.tag.xml") -add_custom_command( - OUTPUT "${tagfile}" - COMMAND "${CMAKE_COMMAND}" -P "${download_script}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/docs" -) -set(doxygen_tagfiles "${tagfile}=http://en.cppreference.com/w/") - -add_custom_command( - OUTPUT "${doxygen_index_file}" - COMMAND "${CMAKE_COMMAND}" -E env - "DOXYGEN_OUTPUT_DIRECTORY=${doxygen_output_directory}" - "DOXYGEN_INCLUDE_PATH=${doxygen_include_path}" - "DOXYGEN_TAGFILES=${doxygen_tagfiles}" - "DOXYGEN_PLANTUML_JAR_PATH=${doxygen_plantuml_jar_path}" - "DOXYGEN_DOT_PATH=${doxygen_dot_path}" - "${DOXYGEN_EXECUTABLE}" "${doxyfile}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - DEPENDS "${dependencies}" "${tagfile}") -add_custom_target(docs - DEPENDS "${doxygen_index_file}" - SOURCES "${dependencies}") diff --git a/cmake/RippledInstall.cmake b/cmake/RippledInstall.cmake deleted file mode 100644 index 013e3f54b2..0000000000 --- a/cmake/RippledInstall.cmake +++ /dev/null @@ -1,86 +0,0 @@ -#[===================================================================[ - install stuff -#]===================================================================] - -include(create_symbolic_link) - -install ( - TARGETS - common - opts - ripple_boost - ripple_libs - ripple_syslibs - xrpl.imports.main - xrpl.libpb - xrpl.libxrpl - xrpl.libxrpl.basics - xrpl.libxrpl.beast - xrpl.libxrpl.crypto - xrpl.libxrpl.json - xrpl.libxrpl.ledger - xrpl.libxrpl.net - xrpl.libxrpl.nodestore - xrpl.libxrpl.protocol - xrpl.libxrpl.resource - xrpl.libxrpl.server - xrpl.libxrpl.shamap - antithesis-sdk-cpp - EXPORT RippleExports - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include) - -install( - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" -) - -install(CODE " - set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") - include(create_symbolic_link) - create_symbolic_link(xrpl \ - \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple) -") - -install (EXPORT RippleExports - FILE RippleTargets.cmake - NAMESPACE Ripple:: - DESTINATION lib/cmake/ripple) -include (CMakePackageConfigHelpers) -write_basic_package_version_file ( - RippleConfigVersion.cmake - VERSION ${rippled_version} - COMPATIBILITY SameMajorVersion) - -if (is_root_project AND TARGET rippled) - install (TARGETS rippled RUNTIME DESTINATION bin) - set_target_properties(rippled PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) - # sample configs should not overwrite existing files - # install if-not-exists workaround as suggested by - # https://cmake.org/Bug/view.php?id=12646 - install(CODE " - macro (copy_if_not_exists SRC DEST NEWNAME) - if (NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") - file (INSTALL FILE_PERMISSIONS OWNER_READ OWNER_WRITE DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${DEST}\" FILES \"\${SRC}\" RENAME \"\${NEWNAME}\") - else () - message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") - endif () - endmacro() - copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg) - copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) - ") - install(CODE " - set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") - include(create_symbolic_link) - create_symbolic_link(rippled${suffix} \ - \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix}) - ") -endif () - -install ( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RippleConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake - DESTINATION lib/cmake/ripple) diff --git a/cmake/RippledInterface.cmake b/cmake/RippledInterface.cmake deleted file mode 100644 index 375338c788..0000000000 --- a/cmake/RippledInterface.cmake +++ /dev/null @@ -1,97 +0,0 @@ -#[===================================================================[ - rippled compile options/settings via an interface library -#]===================================================================] - -add_library (opts INTERFACE) -add_library (Ripple::opts ALIAS opts) -target_compile_definitions (opts - INTERFACE - BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS - BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT - BOOST_CONTAINER_FWD_BAD_DEQUE - HAS_UNCAUGHT_EXCEPTIONS=1 - $<$: - BOOST_ASIO_NO_DEPRECATED - BOOST_FILESYSTEM_NO_DEPRECATED - > - $<$>: - BOOST_COROUTINES_NO_DEPRECATION_WARNING - BOOST_BEAST_ALLOW_DEPRECATED - BOOST_FILESYSTEM_DEPRECATED - > - $<$:BEAST_NO_UNIT_TEST_INLINE=1> - $<$:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1> - $<$:RIPPLE_SINGLE_IO_SERVICE_THREAD=1> - $<$:ENABLE_VOIDSTAR>) -target_compile_options (opts - INTERFACE - $<$,$>:-Wsuggest-override> - $<$:-Wno-maybe-uninitialized> - $<$:-fno-omit-frame-pointer> - $<$:-pg> - $<$,$>:-p>) - -target_link_libraries (opts - INTERFACE - $<$:-pg> - $<$,$>:-p>) - -if(jemalloc) - find_package(jemalloc REQUIRED) - target_compile_definitions(opts INTERFACE PROFILE_JEMALLOC) - target_link_libraries(opts INTERFACE jemalloc::jemalloc) -endif () - -if (san) - target_compile_options (opts - INTERFACE - # sanitizers recommend minimum of -O1 for reasonable performance - $<$:-O1> - ${SAN_FLAG} - -fno-omit-frame-pointer) - target_compile_definitions (opts - INTERFACE - $<$:SANITIZER=ASAN> - $<$:SANITIZER=TSAN> - $<$:SANITIZER=MSAN> - $<$:SANITIZER=UBSAN>) - target_link_libraries (opts INTERFACE ${SAN_FLAG} ${SAN_LIB}) -endif () - -#[===================================================================[ - rippled transitive library deps via an interface library -#]===================================================================] - -add_library (ripple_syslibs INTERFACE) -add_library (Ripple::syslibs ALIAS ripple_syslibs) -target_link_libraries (ripple_syslibs - INTERFACE - $<$: - legacy_stdio_definitions.lib - Shlwapi - kernel32 - user32 - gdi32 - winspool - comdlg32 - advapi32 - shell32 - ole32 - oleaut32 - uuid - odbc32 - odbccp32 - crypt32 - > - $<$>:dl> - $<$,$>>:rt>) - -if (NOT MSVC) - set (THREADS_PREFER_PTHREAD_FLAG ON) - find_package (Threads) - target_link_libraries (ripple_syslibs INTERFACE Threads::Threads) -endif () - -add_library (ripple_libs INTERFACE) -add_library (Ripple::libs ALIAS ripple_libs) -target_link_libraries (ripple_libs INTERFACE Ripple::syslibs) diff --git a/cmake/RippledSanity.cmake b/cmake/RippledSanity.cmake deleted file mode 100644 index 28ce854135..0000000000 --- a/cmake/RippledSanity.cmake +++ /dev/null @@ -1,70 +0,0 @@ -#[===================================================================[ - convenience variables and sanity checks -#]===================================================================] - -get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - -set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) -if (NOT is_multiconfig) - if (NOT CMAKE_BUILD_TYPE) - message (STATUS "Build type not specified - defaulting to Release") - set (CMAKE_BUILD_TYPE Release CACHE STRING "build type" FORCE) - elseif (NOT (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL Release)) - # for simplicity, these are the only two config types we care about. Limiting - # the build types simplifies dealing with external project builds especially - message (FATAL_ERROR " *** Only Debug or Release build types are currently supported ***") - endif () -endif () - -get_directory_property(has_parent PARENT_DIRECTORY) -if (has_parent) - set (is_root_project OFF) -else () - set (is_root_project ON) -endif () - -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # both Clang and AppleClang - set (is_clang TRUE) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND - CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) - message (FATAL_ERROR "This project requires clang 8 or later") - endif () - # TODO min AppleClang version check ? -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set (is_gcc TRUE) - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) - message (FATAL_ERROR "This project requires GCC 8 or later") - endif () -endif () - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux") - set (is_linux TRUE) -else () - set (is_linux FALSE) -endif () - -if ("$ENV{CI}" STREQUAL "true" OR "$ENV{CONTINUOUS_INTEGRATION}" STREQUAL "true") - set (is_ci TRUE) -else () - set (is_ci FALSE) -endif () - -# check for in-source build and fail -if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") - message (FATAL_ERROR "Builds (in-source) are not allowed in " - "${CMAKE_CURRENT_SOURCE_DIR}. Please remove CMakeCache.txt and the CMakeFiles " - "directory from ${CMAKE_CURRENT_SOURCE_DIR} and try building in a separate directory.") -endif () - -if (MSVC AND CMAKE_GENERATOR_PLATFORM STREQUAL "Win32") - message (FATAL_ERROR "Visual Studio 32-bit build is not supported.") -endif () - -if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8) - message (FATAL_ERROR "Rippled requires a 64 bit target architecture.\n" - "The most likely cause of this warning is trying to build rippled with a 32-bit OS.") -endif () - -if (APPLE AND NOT HOMEBREW) - find_program (HOMEBREW brew) -endif () diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake deleted file mode 100644 index 9f59d9e9eb..0000000000 --- a/cmake/RippledSettings.cmake +++ /dev/null @@ -1,140 +0,0 @@ -#[===================================================================[ - declare user options/settings -#]===================================================================] - -include(ProcessorCount) - -ProcessorCount(PROCESSOR_COUNT) - -option(assert "Enables asserts, even in release builds" OFF) - -option(xrpld "Build xrpld" ON) - -option(tests "Build tests" ON) -if(tests) - # This setting allows making a separate workflow to test fees other than default 10 - if(NOT UNIT_TEST_REFERENCE_FEE) - set(UNIT_TEST_REFERENCE_FEE "10" CACHE STRING "") - endif() -endif() - -option(unity "Creates a build using UNITY support in cmake." OFF) -if(unity) - if(NOT is_ci) - set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") - endif() - set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") -endif() -if(is_clang AND is_linux) - option(voidstar "Enable Antithesis instrumentation." OFF) -endif() -if(is_gcc OR is_clang) - option(coverage "Generates coverage info." OFF) - option(profile "Add profiling flags" OFF) - set(coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING - "Unit tests parallelism for the purpose of coverage report.") - set(coverage_format "html-details" CACHE STRING - "Output format of the coverage report.") - set(coverage_extra_args "" CACHE STRING - "Additional arguments to pass to gcovr.") - set(coverage_test "" CACHE STRING - "On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.") - if(coverage_test AND NOT coverage) - set(coverage ON CACHE BOOL "gcc/clang only" FORCE) - endif() - option(wextra "compile with extra gcc/clang warnings enabled" ON) -else() - set(profile OFF CACHE BOOL "gcc/clang only" FORCE) - set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) - set(wextra OFF CACHE BOOL "gcc/clang only" FORCE) -endif() -if(is_linux) - option(BUILD_SHARED_LIBS "build shared ripple libraries" OFF) - option(static "link protobuf, openssl, libc++, and boost statically" ON) - option(perf "Enables flags that assist with perf recording" OFF) - option(use_gold "enables detection of gold (binutils) linker" ON) - option(use_mold "enables detection of mold (binutils) linker" ON) -else() - # we are not ready to allow shared-libs on windows because it would require - # export declarations. On macos it's more feasible, but static openssl - # produces odd linker errors, thus we disable shared lib builds for now. - set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared ripple libraries - OFF for win/macos" FORCE) - set(static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) - set(perf OFF CACHE BOOL "perf flags, linux only" FORCE) - set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) - set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) -endif() -if(is_clang) - option(use_lld "enables detection of lld linker" ON) -else() - set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) -endif() -option(jemalloc "Enables jemalloc for heap profiling" OFF) -option(werr "treat warnings as errors" OFF) -option(local_protobuf - "Force a local build of protobuf instead of looking for an installed version." OFF) -option(local_grpc - "Force a local build of gRPC instead of looking for an installed version." OFF) - -# this one is a string and therefore can't be an option -set(san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") -set_property(CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") -if(san) - string(TOLOWER ${san} san) - set(SAN_FLAG "-fsanitize=${san}") - set(SAN_LIB "") - if(is_gcc) - if(san STREQUAL "address") - set(SAN_LIB "asan") - elseif(san STREQUAL "thread") - set(SAN_LIB "tsan") - elseif(san STREQUAL "memory") - set(SAN_LIB "msan") - elseif(san STREQUAL "undefined") - set(SAN_LIB "ubsan") - endif() - endif() - set(_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) - set(CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") - check_cxx_compiler_flag(${SAN_FLAG} COMPILER_SUPPORTS_SAN) - set(CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) - if(NOT COMPILER_SUPPORTS_SAN) - message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") - endif() -endif() -set(container_label "" CACHE STRING "tag to use for package building containers") -option(packages_only - "ONLY generate package building targets. This is special use-case and almost \ - certainly not what you want. Use with caution as you won't be able to build \ - any compiled targets locally." OFF) -option(have_package_container - "Sometimes you already have the tagged container you want to use for package \ - building and you don't want docker to rebuild it. This flag will detach the \ - dependency of the package build from the container build. It's an advanced \ - use case and most likely you should not be touching this flag." OFF) - -# the remaining options are obscure and rarely used -option(beast_no_unit_test_inline - "Prevents unit test definitions from being inserted into global table" - OFF) -option(single_io_service_thread - "Restricts the number of threads calling io_context::run to one. \ - This can be useful when debugging." - OFF) -option(boost_show_deprecated - "Allow boost to fail on deprecated usage. Only useful if you're trying\ - to find deprecated calls." - OFF) -option(beast_hashers - "Use local implementations for sha/ripemd hashes (experimental, not recommended)" - OFF) - -if(WIN32) - option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) -else() - set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) -endif() -if(coverage) - message(STATUS "coverage build requested - forcing Debug build") - set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) -endif() diff --git a/cmake/RippledValidatorKeys.cmake b/cmake/RippledValidatorKeys.cmake deleted file mode 100644 index fa520ce9c1..0000000000 --- a/cmake/RippledValidatorKeys.cmake +++ /dev/null @@ -1,20 +0,0 @@ -option (validator_keys "Enables building of validator-keys tool as a separate target (imported via FetchContent)" OFF) - -if (validator_keys) - git_branch (current_branch) - # default to tracking VK master branch unless we are on release - if (NOT (current_branch STREQUAL "release")) - set (current_branch "master") - endif () - message (STATUS "Tracking ValidatorKeys branch: ${current_branch}") - - FetchContent_Declare ( - validator_keys - GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git - GIT_TAG "${current_branch}" - ) - FetchContent_MakeAvailable(validator_keys) - set_target_properties(validator-keys PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") - install(TARGETS validator-keys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - -endif () diff --git a/cmake/RippledVersion.cmake b/cmake/RippledVersion.cmake deleted file mode 100644 index fda3cb6ff7..0000000000 --- a/cmake/RippledVersion.cmake +++ /dev/null @@ -1,15 +0,0 @@ -#[===================================================================[ - read version from source -#]===================================================================] - -file(STRINGS src/libxrpl/protocol/BuildInfo.cpp BUILD_INFO) -foreach(line_ ${BUILD_INFO}) - if(line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") - set(rippled_version ${CMAKE_MATCH_1}) - endif() -endforeach() -if(rippled_version) - message(STATUS "rippled version: ${rippled_version}") -else() - message(FATAL_ERROR "unable to determine rippled version") -endif() diff --git a/cmake/XrplAddTest.cmake b/cmake/XrplAddTest.cmake new file mode 100644 index 0000000000..35189e203f --- /dev/null +++ b/cmake/XrplAddTest.cmake @@ -0,0 +1,13 @@ +include(isolate_headers) + +function (xrpl_add_test name) + set(target ${PROJECT_NAME}.test.${name}) + + file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp") + add_executable(${target} ${ARGN} ${sources}) + + isolate_headers(${target} "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/tests/${name}" PRIVATE) + + add_test(NAME ${target} COMMAND ${target}) +endfunction () diff --git a/cmake/XrplCompiler.cmake b/cmake/XrplCompiler.cmake new file mode 100644 index 0000000000..f7ac8c2b71 --- /dev/null +++ b/cmake/XrplCompiler.cmake @@ -0,0 +1,200 @@ +#[===================================================================[ + setup project-wide compiler settings +#]===================================================================] + +include(CompilationEnv) + +#[=========================================================[ + TODO some/most of these common settings belong in a + toolchain file, especially the ABI-impacting ones +#]=========================================================] +add_library(common INTERFACE) +add_library(Xrpl::common ALIAS common) +include(XrplSanitizers) +# add a single global dependency on this interface lib +link_libraries(Xrpl::common) +# Respect CMAKE_POSITION_INDEPENDENT_CODE setting (may be set by Conan toolchain) +if (NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif () +set_target_properties(common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE}) +set(CMAKE_CXX_EXTENSIONS OFF) +target_compile_definitions( + common + INTERFACE $<$:DEBUG + _DEBUG> + #[===[ + NOTE: CMAKE release builds already have NDEBUG defined, so no need to add it + explicitly except for the special case of (profile ON) and (assert OFF). + Presumably this is because we don't want profile builds asserting unless + asserts were specifically requested. + ]===] + $<$,$>>:NDEBUG> + # TODO: Remove once we have migrated functions from OpenSSL 1.x to 3.x. + OPENSSL_SUPPRESS_DEPRECATED) + +if (MSVC) + # remove existing exception flag since we set it to -EHa + string(REGEX REPLACE "[-/]EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + + foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) + + # also remove dynamic runtime + string(REGEX REPLACE "[-/]MD[d]*" " " ${var_} "${${var_}}") + + # /ZI (Edit & Continue debugging information) is incompatible with Gy- + string(REPLACE "/ZI" "/Zi" ${var_} "${${var_}}") + + # omit debug info completely under CI (not needed) + if (is_ci) + string(REPLACE "/Zi" " " ${var_} "${${var_}}") + string(REPLACE "/Z7" " " ${var_} "${${var_}}") + endif () + endforeach () + + target_compile_options( + common + INTERFACE # Increase object file max size + -bigobj + # Floating point behavior + -fp:precise + # __cdecl calling convention + -Gd + # Minimal rebuild: disabled + -Gm- + # Function level linking: disabled + -Gy- + # Multiprocessor compilation + -MP + # pragma omp: disabled + -openmp- + # No error reporting to Internet + -errorReport:none + # Suppress login banner + -nologo + # Disable signed/unsigned comparison warnings + -wd4018 + # Disable float to int possible loss of data warnings + -wd4244 + # Disable size_t to T possible loss of data warnings + -wd4267 + # Disable C4800(int to bool performance) + -wd4800 + # Decorated name length exceeded, name was truncated + -wd4503 + $<$: + -EHa + -GR + > + $<$:-Ox> + $<$,$>: + -GS + -Zc:forScope + > + # static runtime + $<$:-MTd> + $<$>:-MT> + $<$:-WX>) + target_compile_definitions( + common + INTERFACE _WIN32_WINNT=0x6000 + _SCL_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS + WIN32_CONSOLE + WIN32_LEAN_AND_MEAN + NOMINMAX + # TODO: Resolve these warnings, don't just silence them + _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS + $<$,$>:_CRTDBG_MAP_ALLOC>) + target_link_libraries(common INTERFACE -errorreport:none -machine:X64) +else () + target_compile_options( + common + INTERFACE -Wall + -Wdeprecated + $<$:-Wno-deprecated-declarations> + $<$:-Wextra + -Wno-unused-parameter> + $<$:-Werror> + -fstack-protector + -Wno-sign-compare + -Wno-unused-but-set-variable + $<$>:-fno-strict-aliasing> + # tweak gcc optimization for debug + $<$,$>:-O0> + # Add debug symbols to release config + $<$:-g>) + target_link_libraries( + common + INTERFACE -rdynamic + $<$:-Wl,-z,relro,-z,now,--build-id> + # link to static libc/c++ iff: * static option set and * NOT APPLE (AppleClang does not support static + # libc/c++) and * NOT SANITIZERS (sanitizers typically don't work with static libc/c++) + $<$,$>,$>>: + -static-libstdc++ + -static-libgcc + >) +endif () + +# Antithesis instrumentation will only be built and deployed using machines running Linux. +if (voidstar) + if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...") + elseif (NOT is_linux) + message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...") + elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) + message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...") + endif () +endif () + +if (use_mold) + # use mold linker if available + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=mold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) + if ("${LD_VERSION}" MATCHES "mold") + target_link_libraries(common INTERFACE -fuse-ld=mold) + endif () + unset(LD_VERSION) +elseif (use_gold AND is_gcc) + # use gold linker if available + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) + #[=========================================================[ + NOTE: THE gold linker inserts -rpath as DT_RUNPATH by + default instead of DT_RPATH, so you might have slightly + unexpected runtime ld behavior if you were expecting + DT_RPATH. Specify --disable-new-dtags to gold if you do + not want the default DT_RUNPATH behavior. This rpath + treatment as well as static/dynamic selection means that + gold does not currently have ideal default behavior when + we are using jemalloc. Thus for simplicity we don't use + it when jemalloc is requested. An alternative to + disabling would be to figure out all the settings + required to make gold play nicely with jemalloc. + #]=========================================================] + if (("${LD_VERSION}" MATCHES "GNU gold") AND (NOT jemalloc)) + target_link_libraries( + common + INTERFACE -fuse-ld=gold + -Wl,--no-as-needed + #[=========================================================[ + see https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1253638/comments/5 + DT_RUNPATH does not work great for transitive + dependencies (of which boost has a few) - so just + switch to DT_RPATH if doing dynamic linking with gold + #]=========================================================] + $<$>:-Wl,--disable-new-dtags>) + endif () + unset(LD_VERSION) +elseif (use_lld) + # use lld linker if available + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) + if ("${LD_VERSION}" MATCHES "LLD") + target_link_libraries(common INTERFACE -fuse-ld=lld) + endif () + unset(LD_VERSION) +endif () + +if (assert) + foreach (var_ CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) + string(REGEX REPLACE "[-/]DNDEBUG" "" ${var_} "${${var_}}") + endforeach () +endif () diff --git a/cmake/XrplConfig.cmake b/cmake/XrplConfig.cmake new file mode 100644 index 0000000000..bf6aa475ba --- /dev/null +++ b/cmake/XrplConfig.cmake @@ -0,0 +1,52 @@ +include(CMakeFindDependencyMacro) +# need to represent system dependencies of the lib here +#[=========================================================[ + Boost +#]=========================================================] +if (static OR APPLE OR MSVC) + set(Boost_USE_STATIC_LIBS ON) +endif () +set(Boost_USE_MULTITHREADED ON) +if (static OR MSVC) + set(Boost_USE_STATIC_RUNTIME ON) +else () + set(Boost_USE_STATIC_RUNTIME OFF) +endif () +find_dependency(Boost + COMPONENTS + chrono + container + context + coroutine + date_time + filesystem + program_options + regex + system + thread) +#[=========================================================[ + OpenSSL +#]=========================================================] +if (NOT DEFINED OPENSSL_ROOT_DIR) + if (DEFINED ENV{OPENSSL_ROOT}) + set(OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT}) + elseif (APPLE) + find_program(homebrew brew) + if (homebrew) + execute_process(COMMAND ${homebrew} --prefix openssl OUTPUT_VARIABLE OPENSSL_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif () + endif () + file(TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" OPENSSL_ROOT_DIR) +endif () + +if (static OR APPLE OR MSVC) + set(OPENSSL_USE_STATIC_LIBS ON) +endif () +set(OPENSSL_MSVC_STATIC_RT ON) +find_dependency(OpenSSL REQUIRED) +find_dependency(ZLIB) +find_dependency(date) +if (TARGET ZLIB::ZLIB) + set_target_properties(OpenSSL::Crypto PROPERTIES INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) +endif () diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake new file mode 100644 index 0000000000..cea19db9bc --- /dev/null +++ b/cmake/XrplCore.cmake @@ -0,0 +1,168 @@ +#[===================================================================[ + Exported targets. +#]===================================================================] + +include(target_protobuf_sources) + +# Protocol buffers cannot participate in a unity build, +# because all the generated sources +# define a bunch of `static const` variables with the same names, +# so we just build them as a separate library. +add_library(xrpl.libpb) +set_target_properties(xrpl.libpb PROPERTIES UNITY_BUILD OFF) +target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/xrpl/proto + PROTOS include/xrpl/proto/xrpl.proto) + +file(GLOB_RECURSE protos "include/xrpl/proto/org/*.proto") +target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/xrpl/proto PROTOS "${protos}") +target_protobuf_sources( + xrpl.libpb xrpl/proto + LANGUAGE grpc + IMPORT_DIRS include/xrpl/proto + PROTOS "${protos}" + PLUGIN protoc-gen-grpc=$ + GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc) + +target_compile_options( + xrpl.libpb PUBLIC $<$:-wd4996> $<$: --system-header-prefix="google/protobuf" + -Wno-deprecated-dynamic-exception-spec > + PRIVATE $<$:-wd4065> $<$>:-Wno-deprecated-declarations>) + +target_link_libraries(xrpl.libpb PUBLIC protobuf::libprotobuf gRPC::grpc++) + +# TODO: Clean up the number of library targets later. +add_library(xrpl.imports.main INTERFACE) + +target_link_libraries( + xrpl.imports.main + INTERFACE absl::random_random + date::date + ed25519::ed25519 + LibArchive::LibArchive + OpenSSL::Crypto + Xrpl::boost + Xrpl::libs + Xrpl::opts + Xrpl::syslibs + secp256k1::secp256k1 + xrpl.libpb + xxHash::xxhash + $<$:antithesis-sdk-cpp>) + +include(add_module) +include(target_link_modules) + +# Level 01 +add_module(xrpl beast) +target_link_libraries(xrpl.libxrpl.beast PUBLIC xrpl.imports.main) + +# Level 02 +add_module(xrpl basics) +target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast) + +# Level 03 +add_module(xrpl json) +target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics) + +add_module(xrpl crypto) +target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics) + +# Level 04 +add_module(xrpl protocol) +target_link_libraries(xrpl.libxrpl.protocol PUBLIC xrpl.libxrpl.crypto xrpl.libxrpl.json) + +# Level 05 +add_module(xrpl core) +target_link_libraries(xrpl.libxrpl.core PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol) + +# Level 06 +add_module(xrpl resource) +target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol) + +# Level 07 +add_module(xrpl net) +target_link_libraries(xrpl.libxrpl.net PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol + xrpl.libxrpl.resource) + +add_module(xrpl nodestore) +target_link_libraries(xrpl.libxrpl.nodestore PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol) + +add_module(xrpl shamap) +target_link_libraries(xrpl.libxrpl.shamap PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.crypto xrpl.libxrpl.protocol + xrpl.libxrpl.nodestore) + +add_module(xrpl rdb) +target_link_libraries(xrpl.libxrpl.rdb PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.core) + +add_module(xrpl server) +target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol xrpl.libxrpl.core xrpl.libxrpl.rdb) + +add_module(xrpl ledger) +target_link_libraries(xrpl.libxrpl.ledger PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol + xrpl.libxrpl.rdb) + +add_library(xrpl.libxrpl) +set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl) + +add_library(xrpl::libxrpl ALIAS xrpl.libxrpl) + +file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp") +target_sources(xrpl.libxrpl PRIVATE ${sources}) + +target_link_modules( + xrpl + PUBLIC + basics + beast + core + crypto + json + ledger + net + nodestore + protocol + rdb + resource + server + shamap) + +# All headers in libxrpl are in modules. +# Uncomment this stanza if you have not yet moved new headers into a module. +# target_include_directories(xrpl.libxrpl +# PRIVATE +# $ +# PUBLIC +# $ +# $) + +if (xrpld) + add_executable(xrpld) + if (tests) + target_compile_definitions(xrpld PUBLIC ENABLE_TESTS) + target_compile_definitions(xrpld PRIVATE UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE}) + endif () + target_include_directories(xrpld PRIVATE $) + + file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp") + target_sources(xrpld PRIVATE ${sources}) + + if (tests) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp") + target_sources(xrpld PRIVATE ${sources}) + endif () + + target_link_libraries(xrpld Xrpl::boost Xrpl::opts Xrpl::libs xrpl.libxrpl) + exclude_if_included(xrpld) + # define a macro for tests that might need to + # be excluded or run differently in CI environment + if (is_ci) + target_compile_definitions(xrpld PRIVATE XRPL_RUNNING_IN_CI) + endif () + + if (voidstar) + target_compile_options(xrpld PRIVATE -fsanitize-coverage=trace-pc-guard) + # xrpld requires access to antithesis-sdk-cpp implementation file + # antithesis_instrumentation.h, which is not exported as INTERFACE + target_include_directories(xrpld PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk) + endif () +endif () diff --git a/cmake/XrplCov.cmake b/cmake/XrplCov.cmake new file mode 100644 index 0000000000..62c40407f2 --- /dev/null +++ b/cmake/XrplCov.cmake @@ -0,0 +1,52 @@ +#[===================================================================[ + coverage report target +#]===================================================================] + +if (NOT coverage) + message(FATAL_ERROR "Code coverage not enabled! Aborting ...") +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") + return() +endif () + +include(ProcessorCount) +ProcessorCount(PROCESSOR_COUNT) + +include(CodeCoverage) + +# The instructions for these commands come from the `CodeCoverage` module, which was copied from +# https://github.com/bilke/cmake-modules, commit fb7d2a3, then locally changed (see CHANGES: section in +# `CodeCoverage.cmake`) + +set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) +if (NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") + separate_arguments(GCOVR_ADDITIONAL_ARGS) +endif () + +list(APPEND + GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches + -s + -j + ${PROCESSOR_COUNT}) + +setup_target_for_coverage_gcovr( + NAME + coverage + FORMAT + ${coverage_format} + EXCLUDE + "src/test" + "src/tests" + "include/xrpl/beast/test" + "include/xrpl/beast/unit_test" + "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" + DEPENDENCIES + xrpld + xrpl.tests) + +add_code_coverage_to_target(opts INTERFACE) diff --git a/cmake/XrplDocs.cmake b/cmake/XrplDocs.cmake new file mode 100644 index 0000000000..69581a99c7 --- /dev/null +++ b/cmake/XrplDocs.cmake @@ -0,0 +1,72 @@ +#[===================================================================[ + docs target (optional) +#]===================================================================] + +if (NOT only_docs) + return() +endif () + +find_package(Doxygen) +if (NOT TARGET Doxygen::doxygen) + message(STATUS "doxygen executable not found -- skipping docs target") + return() +endif () + +set(doxygen_output_directory "${CMAKE_BINARY_DIR}/docs") +set(doxygen_include_path "${CMAKE_CURRENT_SOURCE_DIR}/src") +set(doxygen_index_file "${doxygen_output_directory}/html/index.html") +set(doxyfile "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile") + +file(GLOB_RECURSE + doxygen_input + docs/*.md + include/*.h + include/*.cpp + include/*.md + src/*.h + src/*.cpp + src/*.md + Builds/*.md + *.md) +list(APPEND doxygen_input external/README.md) +set(dependencies "${doxygen_input}" "${doxyfile}") + +function (verbose_find_path variable name) + # find_path sets a CACHE variable, so don't try using a "local" variable. + find_path(${variable} "${name}" ${ARGN}) + if (NOT ${variable}) + message(NOTICE "could not find ${name}") + else () + message(STATUS "found ${name}: ${${variable}}/${name}") + endif () +endfunction () + +verbose_find_path(doxygen_plantuml_jar_path plantuml.jar PATH_SUFFIXES share/plantuml) +verbose_find_path(doxygen_dot_path dot) + +# https://en.cppreference.com/w/Cppreference:Archives +# https://stackoverflow.com/questions/60822559/how-to-move-a-file-download-from-configure-step-to-build-step +set(download_script "${CMAKE_BINARY_DIR}/docs/download-cppreference.cmake") +file(WRITE "${download_script}" + "file(DOWNLOAD \ + https://github.com/PeterFeicht/cppreference-doc/releases/download/v20250209/html-book-20250209.zip \ + ${CMAKE_BINARY_DIR}/docs/cppreference.zip \ + EXPECTED_HASH MD5=bda585f72fbca4b817b29a3d5746567b \ + )\n \ + execute_process( \ + COMMAND \"${CMAKE_COMMAND}\" -E tar -xf cppreference.zip \ + )\n") +set(tagfile "${CMAKE_BINARY_DIR}/docs/cppreference-doxygen-web.tag.xml") +add_custom_command(OUTPUT "${tagfile}" COMMAND "${CMAKE_COMMAND}" -P "${download_script}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/docs") +set(doxygen_tagfiles "${tagfile}=http://en.cppreference.com/w/") + +add_custom_command( + OUTPUT "${doxygen_index_file}" + COMMAND "${CMAKE_COMMAND}" -E env "DOXYGEN_OUTPUT_DIRECTORY=${doxygen_output_directory}" + "DOXYGEN_INCLUDE_PATH=${doxygen_include_path}" "DOXYGEN_TAGFILES=${doxygen_tagfiles}" + "DOXYGEN_PLANTUML_JAR_PATH=${doxygen_plantuml_jar_path}" "DOXYGEN_DOT_PATH=${doxygen_dot_path}" + "${DOXYGEN_EXECUTABLE}" "${doxyfile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS "${dependencies}" "${tagfile}") +add_custom_target(docs DEPENDS "${doxygen_index_file}" SOURCES "${dependencies}") diff --git a/cmake/XrplInstall.cmake b/cmake/XrplInstall.cmake new file mode 100644 index 0000000000..340dca553b --- /dev/null +++ b/cmake/XrplInstall.cmake @@ -0,0 +1,74 @@ +#[===================================================================[ + install stuff +#]===================================================================] + +include(create_symbolic_link) + +# If no suffix is defined for executables (e.g. Windows uses .exe but Linux +# and macOS use none), then explicitly set it to the empty string. +if (NOT DEFINED suffix) + set(suffix "") +endif () + +install(TARGETS common + opts + xrpl_boost + xrpl_libs + xrpl_syslibs + xrpl.imports.main + xrpl.libpb + xrpl.libxrpl + xrpl.libxrpl.basics + xrpl.libxrpl.beast + xrpl.libxrpl.core + xrpl.libxrpl.crypto + xrpl.libxrpl.json + xrpl.libxrpl.rdb + xrpl.libxrpl.ledger + xrpl.libxrpl.net + xrpl.libxrpl.nodestore + xrpl.libxrpl.protocol + xrpl.libxrpl.resource + xrpl.libxrpl.server + xrpl.libxrpl.shamap + antithesis-sdk-cpp + EXPORT XrplExports + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES + DESTINATION include) + +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +install(EXPORT XrplExports FILE XrplTargets.cmake NAMESPACE Xrpl:: DESTINATION lib/cmake/xrpl) +include(CMakePackageConfigHelpers) +write_basic_package_version_file(XrplConfigVersion.cmake VERSION ${xrpld_version} COMPATIBILITY SameMajorVersion) + +if (is_root_project AND TARGET xrpld) + install(TARGETS xrpld RUNTIME DESTINATION bin) + set_target_properties(xrpld PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) + # sample configs should not overwrite existing files + # install if-not-exists workaround as suggested by + # https://cmake.org/Bug/view.php?id=12646 + install(CODE " + macro (copy_if_not_exists SRC DEST NEWNAME) + if (NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") + file (INSTALL FILE_PERMISSIONS OWNER_READ OWNER_WRITE DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${DEST}\" FILES \"\${SRC}\" RENAME \"\${NEWNAME}\") + else () + message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") + endif () + endmacro() + copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/xrpld-example.cfg\" etc xrpld.cfg) + copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) + ") + install(CODE " + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + include(create_symbolic_link) + create_symbolic_link(xrpld${suffix} \ + \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/rippled${suffix}) + ") +endif () + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/XrplConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/XrplConfigVersion.cmake + DESTINATION lib/cmake/xrpl) diff --git a/cmake/XrplInterface.cmake b/cmake/XrplInterface.cmake new file mode 100644 index 0000000000..f471b37dd7 --- /dev/null +++ b/cmake/XrplInterface.cmake @@ -0,0 +1,83 @@ +#[===================================================================[ + xrpld compile options/settings via an interface library +#]===================================================================] + +include(CompilationEnv) + +# Set defaults for optional variables to avoid uninitialized variable warnings +if (NOT DEFINED voidstar) + set(voidstar OFF) +endif () + +add_library(opts INTERFACE) +add_library(Xrpl::opts ALIAS opts) +target_compile_definitions( + opts + INTERFACE BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS + BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT + BOOST_CONTAINER_FWD_BAD_DEQUE + HAS_UNCAUGHT_EXCEPTIONS=1 + $<$: + BOOST_ASIO_NO_DEPRECATED + BOOST_FILESYSTEM_NO_DEPRECATED + > + $<$>: + BOOST_COROUTINES_NO_DEPRECATION_WARNING + BOOST_BEAST_ALLOW_DEPRECATED + BOOST_FILESYSTEM_DEPRECATED + > + $<$:BEAST_NO_UNIT_TEST_INLINE=1> + $<$:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1> + $<$:XRPL_SINGLE_IO_SERVICE_THREAD=1> + $<$:ENABLE_VOIDSTAR>) +target_compile_options( + opts + INTERFACE $<$,$>:-Wsuggest-override> + $<$:-Wno-maybe-uninitialized> $<$:-fno-omit-frame-pointer> + $<$:-pg> $<$,$>:-p>) + +target_link_libraries(opts INTERFACE $<$:-pg> $<$,$>:-p>) + +if (jemalloc) + find_package(jemalloc REQUIRED) + target_compile_definitions(opts INTERFACE PROFILE_JEMALLOC) + target_link_libraries(opts INTERFACE jemalloc::jemalloc) +endif () + +#[===================================================================[ + xrpld transitive library deps via an interface library +#]===================================================================] + +add_library(xrpl_syslibs INTERFACE) +add_library(Xrpl::syslibs ALIAS xrpl_syslibs) +target_link_libraries( + xrpl_syslibs + INTERFACE $<$: + legacy_stdio_definitions.lib + Shlwapi + kernel32 + user32 + gdi32 + winspool + comdlg32 + advapi32 + shell32 + ole32 + oleaut32 + uuid + odbc32 + odbccp32 + crypt32 + > + $<$>:dl> + $<$,$>>:rt>) + +if (NOT is_msvc) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads) + target_link_libraries(xrpl_syslibs INTERFACE Threads::Threads) +endif () + +add_library(xrpl_libs INTERFACE) +add_library(Xrpl::libs ALIAS xrpl_libs) +target_link_libraries(xrpl_libs INTERFACE Xrpl::syslibs) diff --git a/cmake/XrplSanitizers.cmake b/cmake/XrplSanitizers.cmake new file mode 100644 index 0000000000..6ddc0b7e7d --- /dev/null +++ b/cmake/XrplSanitizers.cmake @@ -0,0 +1,197 @@ +#[===================================================================[ + Configure sanitizers based on environment variables. + + This module reads the following environment variables: + - SANITIZERS: The sanitizers to enable. Possible values: + - "address" + - "address,undefinedbehavior" + - "thread" + - "thread,undefinedbehavior" + - "undefinedbehavior" + + The compiler type and platform are detected in CompilationEnv.cmake. + The sanitizer compile options are applied to the 'common' interface library + which is linked to all targets in the project. + + Internal flag variables set by this module: + + - SANITIZER_TYPES: List of sanitizer types to enable (e.g., "address", + "thread", "undefined"). And two more flags for undefined behavior sanitizer (e.g., "float-divide-by-zero", "unsigned-integer-overflow"). + This list is joined with commas and passed to -fsanitize=. + + - SANITIZERS_COMPILE_FLAGS: Compiler flags for sanitizer instrumentation. + Includes: + * -fno-omit-frame-pointer: Preserves frame pointers for stack traces + * -O1: Minimum optimization for reasonable performance + * -fsanitize=: Enables sanitizer instrumentation + * -fsanitize-ignorelist=: (Clang only) Compile-time ignorelist + * -mcmodel=large/medium: (GCC only) Code model for large binaries + * -Wno-stringop-overflow: (GCC only) Suppresses false positive warnings + * -Wno-tsan: (For GCC TSAN combination only) Suppresses atomic_thread_fence warnings + + - SANITIZERS_LINK_FLAGS: Linker flags for sanitizer runtime libraries. + Includes: + * -fsanitize=: Links sanitizer runtime libraries + * -mcmodel=large/medium: (GCC only) Matches compile-time code model + + - SANITIZERS_RELOCATION_FLAGS: (GCC only) Code model flags for linking. + Used to handle large instrumented binaries on x86_64: + * -mcmodel=large: For AddressSanitizer (prevents relocation errors) + * -mcmodel=medium: For ThreadSanitizer (large model is incompatible) +#]===================================================================] + +include(CompilationEnv) + +# Read environment variable +set(SANITIZERS "") +if (DEFINED ENV{SANITIZERS}) + set(SANITIZERS "$ENV{SANITIZERS}") +endif () + +# Set SANITIZERS_ENABLED flag for use in other modules +if (SANITIZERS MATCHES "address|thread|undefinedbehavior") + set(SANITIZERS_ENABLED TRUE) +else () + set(SANITIZERS_ENABLED FALSE) + return() +endif () + +# Sanitizers are not supported on Windows/MSVC +if (is_msvc) + message(FATAL_ERROR "Sanitizers are not supported on Windows/MSVC. " + "Please unset the SANITIZERS environment variable.") +endif () + +message(STATUS "Configuring sanitizers: ${SANITIZERS}") + +# Parse SANITIZERS value to determine which sanitizers to enable +set(enable_asan FALSE) +set(enable_tsan FALSE) +set(enable_ubsan FALSE) + +# Normalize SANITIZERS into a list +set(san_list "${SANITIZERS}") +string(REPLACE "," ";" san_list "${san_list}") +separate_arguments(san_list) + +foreach (san IN LISTS san_list) + if (san STREQUAL "address") + set(enable_asan TRUE) + elseif (san STREQUAL "thread") + set(enable_tsan TRUE) + elseif (san STREQUAL "undefinedbehavior") + set(enable_ubsan TRUE) + else () + message(FATAL_ERROR "Unsupported sanitizer type: ${san}" + "Supported: address, thread, undefinedbehavior and their combinations.") + endif () +endforeach () + +# Validate sanitizer compatibility +if (enable_asan AND enable_tsan) + message(FATAL_ERROR "AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously. " + "Use 'address' or 'thread', optionally with 'undefinedbehavior'.") +endif () + +# Frame pointer is required for meaningful stack traces. Sanitizers recommend minimum of -O1 for reasonable performance +set(SANITIZERS_COMPILE_FLAGS "-fno-omit-frame-pointer" "-O1") + +# Build the sanitizer flags list +set(SANITIZER_TYPES) + +if (enable_asan) + list(APPEND SANITIZER_TYPES "address") +elseif (enable_tsan) + list(APPEND SANITIZER_TYPES "thread") +endif () + +if (enable_ubsan) + # UB sanitizer flags + list(APPEND SANITIZER_TYPES "undefined" "float-divide-by-zero") + if (is_clang) + # Clang supports additional UB checks. More info here + # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html + list(APPEND SANITIZER_TYPES "unsigned-integer-overflow") + endif () +endif () + +# Configure code model for GCC on amd64 Use large code model for ASAN to avoid relocation errors Use medium code model +# for TSAN (large is not compatible with TSAN) +set(SANITIZERS_RELOCATION_FLAGS) + +# Compiler-specific configuration +if (is_gcc) + # Disable mold, gold and lld linkers for GCC with sanitizers Use default linker (bfd/ld) which is more lenient with + # mixed code models This is needed since the size of instrumented binary exceeds the limits set by mold, lld and + # gold linkers + set(use_mold OFF CACHE BOOL "Use mold linker" FORCE) + set(use_gold OFF CACHE BOOL "Use gold linker" FORCE) + set(use_lld OFF CACHE BOOL "Use lld linker" FORCE) + message(STATUS " Disabled mold, gold, and lld linkers for GCC with sanitizers") + + # Suppress false positive warnings in GCC with stringop-overflow + list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-stringop-overflow") + + if (is_amd64 AND enable_asan) + message(STATUS " Using large code model (-mcmodel=large)") + list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=large") + list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=large") + elseif (enable_tsan) + # GCC doesn't support atomic_thread_fence with tsan. Suppress warnings. + list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-tsan") + message(STATUS " Using medium code model (-mcmodel=medium)") + list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=medium") + list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=medium") + endif () + + # Join sanitizer flags with commas for -fsanitize option + list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR) + + # Add sanitizer to compile and link flags + list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}") + set(SANITIZERS_LINK_FLAGS "${SANITIZERS_RELOCATION_FLAGS}" "-fsanitize=${SANITIZER_TYPES_STR}") + +elseif (is_clang) + # Add ignorelist for Clang (GCC doesn't support this) Use CMAKE_SOURCE_DIR to get the path to the ignorelist + set(IGNORELIST_PATH "${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt") + if (NOT EXISTS "${IGNORELIST_PATH}") + message(FATAL_ERROR "Sanitizer ignorelist not found: ${IGNORELIST_PATH}") + endif () + + list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize-ignorelist=${IGNORELIST_PATH}") + message(STATUS " Using sanitizer ignorelist: ${IGNORELIST_PATH}") + + # Join sanitizer flags with commas for -fsanitize option + list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR) + + # Add sanitizer to compile and link flags + list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}") + set(SANITIZERS_LINK_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}") +endif () + +message(STATUS " Compile flags: ${SANITIZERS_COMPILE_FLAGS}") +message(STATUS " Link flags: ${SANITIZERS_LINK_FLAGS}") + +# Apply the sanitizer flags to the 'common' interface library This is the same library used by XrplCompiler.cmake +target_compile_options(common INTERFACE $<$:${SANITIZERS_COMPILE_FLAGS}> + $<$:${SANITIZERS_COMPILE_FLAGS}>) + +# Apply linker flags +target_link_options(common INTERFACE ${SANITIZERS_LINK_FLAGS}) + +# Define SANITIZERS macro for BuildInfo.cpp +set(sanitizers_list) +if (enable_asan) + list(APPEND sanitizers_list "ASAN") +endif () +if (enable_tsan) + list(APPEND sanitizers_list "TSAN") +endif () +if (enable_ubsan) + list(APPEND sanitizers_list "UBSAN") +endif () + +if (sanitizers_list) + list(JOIN sanitizers_list "." sanitizers_str) + target_compile_definitions(common INTERFACE SANITIZERS=${sanitizers_str}) +endif () diff --git a/cmake/XrplSanity.cmake b/cmake/XrplSanity.cmake new file mode 100644 index 0000000000..5055414abd --- /dev/null +++ b/cmake/XrplSanity.cmake @@ -0,0 +1,44 @@ +#[===================================================================[ + sanity checks +#]===================================================================] + +include(CompilationEnv) + +get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) +if (NOT is_multiconfig) + if (NOT CMAKE_BUILD_TYPE) + message(STATUS "Build type not specified - defaulting to Release") + set(CMAKE_BUILD_TYPE Release CACHE STRING "build type" FORCE) + elseif (NOT (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL Release)) + # for simplicity, these are the only two config types we care about. Limiting the build types simplifies dealing + # with external project builds especially + message(FATAL_ERROR " *** Only Debug or Release build types are currently supported ***") + endif () +endif () + +if (is_clang) # both Clang and AppleClang + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0) + message(FATAL_ERROR "This project requires clang 16 or later") + endif () +elseif (is_gcc) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0) + message(FATAL_ERROR "This project requires GCC 12 or later") + endif () +endif () + +# check for in-source build and fail +if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "Builds (in-source) are not allowed in " + "${CMAKE_CURRENT_SOURCE_DIR}. Please remove CMakeCache.txt and the CMakeFiles " + "directory from ${CMAKE_CURRENT_SOURCE_DIR} and try building in a separate directory.") +endif () + +if (MSVC AND CMAKE_GENERATOR_PLATFORM STREQUAL "Win32") + message(FATAL_ERROR "Visual Studio 32-bit build is not supported.") +endif () + +if (APPLE AND NOT HOMEBREW) + find_program(HOMEBREW brew) +endif () diff --git a/cmake/XrplSettings.cmake b/cmake/XrplSettings.cmake new file mode 100644 index 0000000000..6d332be19d --- /dev/null +++ b/cmake/XrplSettings.cmake @@ -0,0 +1,114 @@ +#[===================================================================[ + declare options and variables +#]===================================================================] + +include(CompilationEnv) + +set(is_ci FALSE) +if (DEFINED ENV{CI}) + if ("$ENV{CI}" STREQUAL "true") + set(is_ci TRUE) + endif () +endif () + +get_directory_property(has_parent PARENT_DIRECTORY) +if (has_parent) + set(is_root_project OFF) +else () + set(is_root_project ON) +endif () + +option(assert "Enables asserts, even in release builds" OFF) + +option(xrpld "Build xrpld" ON) + +option(tests "Build tests" ON) +if (tests) + # This setting allows making a separate workflow to test fees other than default 10 + if (NOT UNIT_TEST_REFERENCE_FEE) + set(UNIT_TEST_REFERENCE_FEE "10" CACHE STRING "") + endif () +endif () + +option(unity "Creates a build using UNITY support in cmake." OFF) +if (unity) + if (NOT is_ci) + set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") + endif () + set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") +endif () + +if (is_clang AND is_linux) + option(voidstar "Enable Antithesis instrumentation." OFF) +endif () + +if (is_gcc OR is_clang) + include(ProcessorCount) + ProcessorCount(PROCESSOR_COUNT) + + option(coverage "Generates coverage info." OFF) + option(profile "Add profiling flags" OFF) + set(coverage_format "html-details" CACHE STRING "Output format of the coverage report.") + set(coverage_extra_args "" CACHE STRING "Additional arguments to pass to gcovr.") + option(wextra "compile with extra gcc/clang warnings enabled" ON) +else () + set(profile OFF CACHE BOOL "gcc/clang only" FORCE) + set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) + set(wextra OFF CACHE BOOL "gcc/clang only" FORCE) +endif () + +if (is_linux AND NOT SANITIZER) + option(BUILD_SHARED_LIBS "build shared xrpl libraries" OFF) + option(static "link protobuf, openssl, libc++, and boost statically" ON) + option(perf "Enables flags that assist with perf recording" OFF) + option(use_gold "enables detection of gold (binutils) linker" ON) + option(use_mold "enables detection of mold (binutils) linker" ON) + # Set a default value for the log flag based on the build type. This provides a sensible default (on for debug, off + # for release) while still allowing the user to override it for any build. + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(TRUNCATED_LOGS_DEFAULT ON) + else () + set(TRUNCATED_LOGS_DEFAULT OFF) + endif () + option(TRUNCATED_THREAD_NAME_LOGS "Show warnings about truncated thread names on Linux." ${TRUNCATED_LOGS_DEFAULT}) + if (TRUNCATED_THREAD_NAME_LOGS) + add_compile_definitions(TRUNCATED_THREAD_NAME_LOGS) + endif () +else () + # we are not ready to allow shared-libs on windows because it would require export declarations. On macos it's more + # feasible, but static openssl produces odd linker errors, thus we disable shared lib builds for now. + set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared xrpl libraries - OFF for win/macos" FORCE) + set(static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) + set(perf OFF CACHE BOOL "perf flags, linux only" FORCE) + set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) + set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) +endif () + +if (is_clang) + option(use_lld "enables detection of lld linker" ON) +else () + set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) +endif () + +option(jemalloc "Enables jemalloc for heap profiling" OFF) +option(werr "treat warnings as errors" OFF) +option(local_protobuf "Force a local build of protobuf instead of looking for an installed version." OFF) +option(local_grpc "Force a local build of gRPC instead of looking for an installed version." OFF) + +# the remaining options are obscure and rarely used +option(beast_no_unit_test_inline "Prevents unit test definitions from being inserted into global table" OFF) +option(single_io_service_thread "Restricts the number of threads calling io_context::run to one. \ + This can be useful when debugging." OFF) +option(boost_show_deprecated "Allow boost to fail on deprecated usage. Only useful if you're trying\ + to find deprecated calls." OFF) + +if (WIN32) + option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) +else () + set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) +endif () + +if (coverage) + message(STATUS "coverage build requested - forcing Debug build") + set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) +endif () diff --git a/cmake/XrplValidatorKeys.cmake b/cmake/XrplValidatorKeys.cmake new file mode 100644 index 0000000000..5fa7e14886 --- /dev/null +++ b/cmake/XrplValidatorKeys.cmake @@ -0,0 +1,17 @@ +option(validator_keys "Enables building of validator-keys tool as a separate target (imported via FetchContent)" OFF) + +if (validator_keys) + git_branch(current_branch) + # default to tracking VK master branch unless we are on release + if (NOT (current_branch STREQUAL "release")) + set(current_branch "master") + endif () + message(STATUS "Tracking ValidatorKeys branch: ${current_branch}") + + FetchContent_Declare(validator_keys GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git + GIT_TAG "${current_branch}") + FetchContent_MakeAvailable(validator_keys) + set_target_properties(validator-keys PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") + install(TARGETS validator-keys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +endif () diff --git a/cmake/XrplVersion.cmake b/cmake/XrplVersion.cmake new file mode 100644 index 0000000000..6eeda7b1eb --- /dev/null +++ b/cmake/XrplVersion.cmake @@ -0,0 +1,15 @@ +#[===================================================================[ + read version from source +#]===================================================================] + +file(STRINGS src/libxrpl/protocol/BuildInfo.cpp BUILD_INFO) +foreach (line_ ${BUILD_INFO}) + if (line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") + set(xrpld_version ${CMAKE_MATCH_1}) + endif () +endforeach () +if (xrpld_version) + message(STATUS "xrpld version: ${xrpld_version}") +else () + message(FATAL_ERROR "unable to determine xrpld version") +endif () diff --git a/cmake/add_module.cmake b/cmake/add_module.cmake index bcfce1bf60..a3cb247fd2 100644 --- a/cmake/add_module.cmake +++ b/cmake/add_module.cmake @@ -12,26 +12,14 @@ include(isolate_headers) # add_module(parent a) # add_module(parent b) # target_link_libraries(project.libparent.b PUBLIC project.libparent.a) -function(add_module parent name) - set(target ${PROJECT_NAME}.lib${parent}.${name}) - add_library(${target} OBJECT) - file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}/*.cpp" - ) - target_sources(${target} PRIVATE ${sources}) - target_include_directories(${target} PUBLIC - "$" - ) - isolate_headers( - ${target} - "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}" - PUBLIC - ) - isolate_headers( - ${target} - "${CMAKE_CURRENT_SOURCE_DIR}/src" - "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" - PRIVATE - ) -endfunction() +function (add_module parent name) + set(target ${PROJECT_NAME}.lib${parent}.${name}) + add_library(${target} OBJECT) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}/*.cpp") + target_sources(${target} PRIVATE ${sources}) + target_include_directories(${target} PUBLIC "$") + isolate_headers(${target} "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}" PUBLIC) + isolate_headers(${target} "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" + PRIVATE) +endfunction () diff --git a/cmake/create_symbolic_link.cmake b/cmake/create_symbolic_link.cmake index 60fcf2e0b5..82ca915f5c 100644 --- a/cmake/create_symbolic_link.cmake +++ b/cmake/create_symbolic_link.cmake @@ -1,20 +1,19 @@ -# file(CREATE_SYMLINK) only works on Windows with administrator privileges. -# https://stackoverflow.com/a/61244115/618906 -function(create_symbolic_link target link) - if(WIN32) - if(NOT IS_SYMLINK "${link}") - if(NOT IS_ABSOLUTE "${target}") - # Relative links work do not work on Windows. - set(target "${link}/../${target}") - endif() - file(TO_NATIVE_PATH "${target}" target) - file(TO_NATIVE_PATH "${link}" link) - execute_process(COMMAND cmd.exe /c mklink /J "${link}" "${target}") - endif() - else() - file(CREATE_LINK "${target}" "${link}" SYMBOLIC) - endif() - if(NOT IS_SYMLINK "${link}") - message(ERROR "failed to create symlink: <${link}>") - endif() -endfunction() +# file(CREATE_SYMLINK) only works on Windows with administrator privileges. https://stackoverflow.com/a/61244115/618906 +function (create_symbolic_link target link) + if (WIN32) + if (NOT IS_SYMLINK "${link}") + if (NOT IS_ABSOLUTE "${target}") + # Relative links work do not work on Windows. + set(target "${link}/../${target}") + endif () + file(TO_NATIVE_PATH "${target}" target) + file(TO_NATIVE_PATH "${link}" link) + execute_process(COMMAND cmd.exe /c mklink /J "${link}" "${target}") + endif () + else () + file(CREATE_LINK "${target}" "${link}" SYMBOLIC) + endif () + if (NOT IS_SYMLINK "${link}") + message(ERROR "failed to create symlink: <${link}>") + endif () +endfunction () diff --git a/cmake/deps/Boost.cmake b/cmake/deps/Boost.cmake index e431e57b0c..fe62fcb79c 100644 --- a/cmake/deps/Boost.cmake +++ b/cmake/deps/Boost.cmake @@ -1,47 +1,44 @@ -find_package(Boost 1.82 REQUIRED - COMPONENTS - chrono - container - coroutine - date_time - filesystem - json - program_options - regex - system - thread -) +include(CompilationEnv) +include(XrplSanitizers) -add_library(ripple_boost INTERFACE) -add_library(Ripple::boost ALIAS ripple_boost) +find_package(Boost REQUIRED + COMPONENTS chrono + container + coroutine + date_time + filesystem + json + program_options + regex + system + thread) -target_link_libraries(ripple_boost - INTERFACE - Boost::headers - Boost::chrono - Boost::container - Boost::coroutine - Boost::date_time - Boost::filesystem - Boost::json - Boost::process - Boost::program_options - Boost::regex - Boost::system - Boost::thread) -if(Boost_COMPILER) - target_link_libraries(ripple_boost INTERFACE Boost::disable_autolinking) -endif() -if(san AND is_clang) - # TODO: gcc does not support -fsanitize-blacklist...can we do something else - # for gcc ? - if(NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers) - get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES) - endif() - message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*") - target_compile_options(opts - INTERFACE - # ignore boost headers for sanitizing - -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt) -endif() +add_library(xrpl_boost INTERFACE) +add_library(Xrpl::boost ALIAS xrpl_boost) + +target_link_libraries( + xrpl_boost + INTERFACE Boost::headers + Boost::chrono + Boost::container + Boost::coroutine + Boost::date_time + Boost::filesystem + Boost::json + Boost::process + Boost::program_options + Boost::regex + Boost::thread) +if (Boost_COMPILER) + target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking) +endif () +if (SANITIZERS_ENABLED AND is_clang) + # TODO: gcc does not support -fsanitize-blacklist...can we do something else for gcc ? + if (NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers) + get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES) + endif () + message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*") + target_compile_options(opts INTERFACE # ignore boost headers for sanitizing + -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt) +endif () diff --git a/cmake/isolate_headers.cmake b/cmake/isolate_headers.cmake index 0a5a43a6a2..ef53b3f20a 100644 --- a/cmake/isolate_headers.cmake +++ b/cmake/isolate_headers.cmake @@ -37,12 +37,12 @@ include(create_symbolic_link) # `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`. # # isolate_headers(target A B scope) -function(isolate_headers target A B scope) - file(RELATIVE_PATH C "${A}" "${B}") - set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}") - set(Y "${X}/${C}") - cmake_path(GET Y PARENT_PATH parent) - file(MAKE_DIRECTORY "${parent}") - create_symbolic_link("${B}" "${Y}") - target_include_directories(${target} ${scope} "$") -endfunction() +function (isolate_headers target A B scope) + file(RELATIVE_PATH C "${A}" "${B}") + set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}") + set(Y "${X}/${C}") + cmake_path(GET Y PARENT_PATH parent) + file(MAKE_DIRECTORY "${parent}") + create_symbolic_link("${B}" "${Y}") + target_include_directories(${target} ${scope} "$") +endfunction () diff --git a/cmake/target_link_modules.cmake b/cmake/target_link_modules.cmake index acbf67903a..bcd80591b0 100644 --- a/cmake/target_link_modules.cmake +++ b/cmake/target_link_modules.cmake @@ -6,19 +6,19 @@ # target_link_libraries(project.libparent.b PUBLIC project.libparent.a) # add_library(project.libparent) # target_link_modules(parent PUBLIC a b) -function(target_link_modules parent scope) - set(library ${PROJECT_NAME}.lib${parent}) - foreach(name ${ARGN}) - set(module ${library}.${name}) - get_target_property(sources ${library} SOURCES) - list(LENGTH sources before) - get_target_property(dupes ${module} SOURCES) - list(LENGTH dupes expected) - list(REMOVE_ITEM sources ${dupes}) - list(LENGTH sources after) - math(EXPR actual "${before} - ${after}") - message(STATUS "${module} with ${expected} sources took ${actual} sources from ${library}") - set_target_properties(${library} PROPERTIES SOURCES "${sources}") - target_link_libraries(${library} ${scope} ${module}) - endforeach() -endfunction() +function (target_link_modules parent scope) + set(library ${PROJECT_NAME}.lib${parent}) + foreach (name ${ARGN}) + set(module ${library}.${name}) + get_target_property(sources ${library} SOURCES) + list(LENGTH sources before) + get_target_property(dupes ${module} SOURCES) + list(LENGTH dupes expected) + list(REMOVE_ITEM sources ${dupes}) + list(LENGTH sources after) + math(EXPR actual "${before} - ${after}") + message(STATUS "${module} with ${expected} sources took ${actual} sources from ${library}") + set_target_properties(${library} PROPERTIES SOURCES "${sources}") + target_link_libraries(${library} ${scope} ${module}) + endforeach () +endfunction () diff --git a/cmake/target_protobuf_sources.cmake b/cmake/target_protobuf_sources.cmake index da2ef6dc9a..bb5de02b53 100644 --- a/cmake/target_protobuf_sources.cmake +++ b/cmake/target_protobuf_sources.cmake @@ -35,28 +35,20 @@ find_package(Protobuf REQUIRED) # This prefix should appear at the start of all your consumer includes. # ARGN: # A list of .proto files. -function(target_protobuf_sources target prefix) - set(dir "${CMAKE_CURRENT_BINARY_DIR}/pb-${target}") - file(MAKE_DIRECTORY "${dir}/${prefix}") +function (target_protobuf_sources target prefix) + set(dir "${CMAKE_CURRENT_BINARY_DIR}/pb-${target}") + file(MAKE_DIRECTORY "${dir}/${prefix}") - protobuf_generate( - TARGET ${target} - PROTOC_OUT_DIR "${dir}/${prefix}" - "${ARGN}" - ) - target_include_directories(${target} SYSTEM PUBLIC - # Allows #include used by consumer files. - $ - # Allows #include "path/to/file.proto" used by generated files. - $ - # Allows #include used by consumer files. - $ - # Allows #include "path/to/file.proto" used by generated files. - $ - ) - install( - DIRECTORY ${dir}/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING PATTERN "*.h" - ) -endfunction() + protobuf_generate(TARGET ${target} PROTOC_OUT_DIR "${dir}/${prefix}" "${ARGN}") + target_include_directories( + ${target} SYSTEM + PUBLIC # Allows #include used by consumer files. + $ + # Allows #include "path/to/file.proto" used by generated files. + $ + # Allows #include used by consumer files. + $ + # Allows #include "path/to/file.proto" used by generated files. + $) + install(DIRECTORY ${dir}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h") +endfunction () diff --git a/cmake/xrpl_add_test.cmake b/cmake/xrpl_add_test.cmake deleted file mode 100644 index a1dd3847bd..0000000000 --- a/cmake/xrpl_add_test.cmake +++ /dev/null @@ -1,41 +0,0 @@ -include(isolate_headers) - -function(xrpl_add_test name) - set(target ${PROJECT_NAME}.test.${name}) - - file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp" - ) - add_executable(${target} ${ARGN} ${sources}) - - isolate_headers( - ${target} - "${CMAKE_SOURCE_DIR}" - "${CMAKE_SOURCE_DIR}/tests/${name}" - PRIVATE - ) - - # Make sure the test isn't optimized away in unity builds - set_target_properties(${target} PROPERTIES - UNITY_BUILD_MODE GROUP - UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed - - add_test(NAME ${target} COMMAND ${target}) - set_tests_properties( - ${target} PROPERTIES - FIXTURES_REQUIRED ${target}_fixture - ) - - add_test( - NAME ${target}.build - COMMAND - ${CMAKE_COMMAND} - --build ${CMAKE_BINARY_DIR} - --config $ - --target ${target} - ) - set_tests_properties(${target}.build PROPERTIES - FIXTURES_SETUP ${target}_fixture - ) -endfunction() diff --git a/conan.lock b/conan.lock index cb25777423..a1e1c3647c 100644 --- a/conan.lock +++ b/conan.lock @@ -1,56 +1,67 @@ { "version": "0.5", "requires": [ - "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497", - "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683", - "sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869", - "soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318", - "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246", - "rocksdb/10.0.1#85537f46e538974d67da0c3977de48ac%1756234304.347", - "re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976", - "protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614", - "openssl/3.5.4#a1d5835cc6ed5c5b8f3cd5b9b5d24205%1759746684.671", - "nudb/2.0.9#c62cfd501e57055a7e0d8ee3d5e5427d%1756234237.107", - "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999", - "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1756223727.64", - "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1756230911.03", - "libarchive/3.8.1#5cf685686322e906cb42706ab7e099a8%1756234256.696", + "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075", + "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987", + "sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1765850149.926", + "soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1765850149.46", + "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878", + "secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329", + "rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86", + "re2/20230301#ca3b241baec15bd31ea9187150e0b333%1765850148.103", + "protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038", + "openssl/3.5.5#05a4ac5b7323f7a329b2db1391d9941f%1770229825.601", + "nudb/2.0.9#0432758a24204da08fee953ec9ea03cb%1769436073.32", + "mpt-crypto/0.1.0-rc2#575de3d495f539e3e5eba957b324d260%1771955268.105", + "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914", + "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492", + "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03", + "libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1765850144.736", "jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244", - "grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958", - "doctest/2.4.11#a4211dfc329a16ba9f280f9574025659%1756234220.819", - "date/3.0.4#f74bbba5a08fa388256688743136cb6f%1756234217.493", - "c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915", - "bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716", - "boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1756223752.326", - "abseil/20230802.1#f0f91485b111dc9837a68972cb19ca7b%1756234220.907" + "gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152", + "grpc/1.72.0#f244a57bff01e708c55a1100b12e1589%1765850193.734", + "ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772", + "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772", + "c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1765850144.336", + "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837", + "boost/1.90.0#d5e8defe7355494953be18524a7f135b%1769454080.269", + "abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993" ], "build_requires": [ - "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497", - "strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1756234281.733", - "protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614", - "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1756234232.901", - "msys2/cci.latest#5b73b10144f73cc5bfe0572ed9be39e1%1751977009.857", - "m4/1.4.19#b38ced39a01e31fef5435bc634461fd2%1700758725.451", - "cmake/3.31.8#dde3bde00bb843687e55aea5afa0e220%1756234232.89", - "b2/5.3.3#107c15377719889654eb9a162a673975%1756234226.28", + "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075", + "strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1765850165.196", + "protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038", + "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707", + "msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649", + "m4/1.4.19#70dc8bbb33e981d119d2acc0175cf381%1763158052.846", + "cmake/4.2.0#ae0a44f44a1ef9ab68fd4b3e9a1f8671%1765850153.937", + "cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1765850153.479", + "b2/5.3.3#107c15377719889654eb9a162a673975%1765850144.355", "automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56", - "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86" + "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86", + "abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993" ], "python_requires": [], "overrides": { - "protobuf/3.21.12": [ + "boost/1.90.0#d5e8defe7355494953be18524a7f135b": [ null, - "protobuf/3.21.12" + "boost/1.90.0" + ], + "protobuf/5.27.0": [ + "protobuf/6.32.1" ], "lz4/1.9.4": [ "lz4/1.10.0" ], - "boost/1.83.0": [ - "boost/1.88.0" - ], "sqlite3/3.44.2": [ "sqlite3/3.49.1" + ], + "boost/1.83.0": [ + "boost/1.90.0" + ], + "lz4/[>=1.9.4 <2]": [ + "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504" ] }, "config_requires": [] -} \ No newline at end of file +} diff --git a/conan/lockfile/README.md b/conan/lockfile/README.md new file mode 100644 index 0000000000..5e70de102d --- /dev/null +++ b/conan/lockfile/README.md @@ -0,0 +1,12 @@ +# Conan lockfile + +To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html). + +The `conan.lock` file in the repository contains a "snapshot" of the current +dependencies. It is implicitly used when running `conan` commands, so you don't +need to specify it. + +You have to update this file every time you add a new dependency or change a +revision or version of an existing dependency. + +To update a lockfile, run from the repository root: `./conan/lockfile/regenerate.sh` diff --git a/conan/lockfile/linux.profile b/conan/lockfile/linux.profile new file mode 100644 index 0000000000..25ad5988c5 --- /dev/null +++ b/conan/lockfile/linux.profile @@ -0,0 +1,8 @@ +[settings] +arch=x86_64 +build_type=Release +compiler=gcc +compiler.cppstd=20 +compiler.libcxx=libstdc++11 +compiler.version=13 +os=Linux diff --git a/conan/lockfile/macos.profile b/conan/lockfile/macos.profile new file mode 100644 index 0000000000..332a0c143d --- /dev/null +++ b/conan/lockfile/macos.profile @@ -0,0 +1,8 @@ +[settings] +arch=armv8 +build_type=Release +compiler=apple-clang +compiler.cppstd=20 +compiler.libcxx=libc++ +compiler.version=17.0 +os=Macos diff --git a/conan/lockfile/regenerate.sh b/conan/lockfile/regenerate.sh new file mode 100755 index 0000000000..30d38dc2d7 --- /dev/null +++ b/conan/lockfile/regenerate.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -ex + +TEMP_DIR=$(mktemp -d) +trap "rm -rf $TEMP_DIR" EXIT + +echo "Using temporary CONAN_HOME: $TEMP_DIR" + +# We use a temporary Conan home to avoid polluting the user's existing Conan +# configuration and to not use local cache (which leads to non-reproducible lockfiles). +export CONAN_HOME="$TEMP_DIR" + +# Ensure that the xrplf remote is the first to be consulted, so any recipes we +# patched are used. We also add it there to not created huge diff when the +# official Conan Center Index is updated. +conan remote add --force --index 0 xrplf https://conan.ripplex.io + +# Delete any existing lockfile. +rm -f conan.lock + +# Create a new lockfile that is compatible with Linux, macOS, and Windows. The +# first create command will create a new lockfile, while the subsequent create +# commands will merge any additional dependencies into the created lockfile. +conan lock create . \ + --options '&:jemalloc=True' \ + --options '&:rocksdb=True' \ + --profile:all=conan/lockfile/linux.profile +conan lock create . \ + --options '&:jemalloc=True' \ + --options '&:rocksdb=True' \ + --profile:all=conan/lockfile/macos.profile +conan lock create . \ + --options '&:jemalloc=True' \ + --options '&:rocksdb=True' \ + --profile:all=conan/lockfile/windows.profile diff --git a/conan/lockfile/windows.profile b/conan/lockfile/windows.profile new file mode 100644 index 0000000000..4bb266a62e --- /dev/null +++ b/conan/lockfile/windows.profile @@ -0,0 +1,9 @@ +[settings] +arch=x86_64 +build_type=Release +compiler=msvc +compiler.cppstd=20 +compiler.runtime=dynamic +compiler.runtime_type=Release +compiler.version=194 +os=Windows diff --git a/conan/profiles/ci b/conan/profiles/ci new file mode 100644 index 0000000000..c4c0898ad5 --- /dev/null +++ b/conan/profiles/ci @@ -0,0 +1 @@ + include(sanitizers) diff --git a/conan/profiles/default b/conan/profiles/default index def2fffd6b..cde59f7f3b 100644 --- a/conan/profiles/default +++ b/conan/profiles/default @@ -20,12 +20,6 @@ compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}} {% endif %} [conf] -{% if compiler == "clang" and compiler_version >= 19 %} -grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw'] -{% endif %} -{% if compiler == "apple-clang" and compiler_version >= 17 %} -grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw'] -{% endif %} {% if compiler == "gcc" and compiler_version < 13 %} tools.build:cxxflags+=['-Wno-restrict'] {% endif %} diff --git a/conan/profiles/sanitizers b/conan/profiles/sanitizers new file mode 100644 index 0000000000..d7a622359a --- /dev/null +++ b/conan/profiles/sanitizers @@ -0,0 +1,59 @@ +include(default) +{% set compiler, version, compiler_exe = detect_api.detect_default_compiler() %} +{% set sanitizers = os.getenv("SANITIZERS") %} + +[conf] +{% if sanitizers %} + {% if compiler == "gcc" %} + {% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %} + {% set sanitizer_list = [] %} + {% set model_code = "" %} + {% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %} + + {% if "address" in sanitizers %} + {% set _ = sanitizer_list.append("address") %} + {% set model_code = "-mcmodel=large" %} + {% elif "thread" in sanitizers %} + {% set _ = sanitizer_list.append("thread") %} + {% set model_code = "-mcmodel=medium" %} + {% set _ = extra_cxxflags.append("-Wno-tsan") %} + {% endif %} + + {% if "undefinedbehavior" in sanitizers %} + {% set _ = sanitizer_list.append("undefined") %} + {% set _ = sanitizer_list.append("float-divide-by-zero") %} + {% endif %} + + {% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) ~ " " ~ model_code %} + + tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}'] + tools.build:sharedlinkflags+=['{{sanitizer_flags}}'] + tools.build:exelinkflags+=['{{sanitizer_flags}}'] + {% endif %} + {% elif compiler == "apple-clang" or compiler == "clang" %} + {% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %} + {% set sanitizer_list = [] %} + {% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %} + + {% if "address" in sanitizers %} + {% set _ = sanitizer_list.append("address") %} + {% elif "thread" in sanitizers %} + {% set _ = sanitizer_list.append("thread") %} + {% endif %} + + {% if "undefinedbehavior" in sanitizers %} + {% set _ = sanitizer_list.append("undefined") %} + {% set _ = sanitizer_list.append("float-divide-by-zero") %} + {% set _ = sanitizer_list.append("unsigned-integer-overflow") %} + {% endif %} + + {% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) %} + + tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}'] + tools.build:sharedlinkflags+=['{{sanitizer_flags}}'] + tools.build:exelinkflags+=['{{sanitizer_flags}}'] + {% endif %} + {% endif %} +{% endif %} + +tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"] diff --git a/conanfile.py b/conanfile.py index 7f8ab24fbd..fa178f08d9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,149 +1,176 @@ -from conan import ConanFile, __version__ as conan_version -from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout import re -class Xrpl(ConanFile): - name = 'xrpl' +from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout - license = 'ISC' - author = 'John Freeman ' - url = 'https://github.com/xrplf/rippled' - description = 'The XRP Ledger' - settings = 'os', 'compiler', 'build_type', 'arch' +from conan import ConanFile +from conan import __version__ as conan_version + + +class Xrpl(ConanFile): + name = "xrpl" + + license = "ISC" + author = "John Freeman " + url = "https://github.com/xrplf/rippled" + description = "The XRP Ledger" + settings = "os", "compiler", "build_type", "arch" options = { - 'assertions': [True, False], - 'coverage': [True, False], - 'fPIC': [True, False], - 'jemalloc': [True, False], - 'rocksdb': [True, False], - 'shared': [True, False], - 'static': [True, False], - 'tests': [True, False], - 'unity': [True, False], - 'xrpld': [True, False], + "assertions": [True, False], + "coverage": [True, False], + "fPIC": [True, False], + "jemalloc": [True, False], + "rocksdb": [True, False], + "shared": [True, False], + "static": [True, False], + "tests": [True, False], + "unity": [True, False], + "xrpld": [True, False], } requires = [ - 'grpc/1.50.1', - 'libarchive/3.8.1', - 'nudb/2.0.9', - 'openssl/3.5.4', - 'soci/4.0.3', - 'zlib/1.3.1', + "ed25519/2015.03", + "grpc/1.72.0", + "libarchive/3.8.1", + "mpt-crypto/0.1.0-rc2", + "nudb/2.0.9", + "openssl/3.5.5", + "secp256k1/0.7.1", + "soci/4.0.3", + "zlib/1.3.1", ] test_requires = [ - 'doctest/2.4.11', + "gtest/1.17.0", ] tool_requires = [ - 'protobuf/3.21.12', + "protobuf/6.32.1", ] default_options = { - 'assertions': False, - 'coverage': False, - 'fPIC': True, - 'jemalloc': False, - 'rocksdb': True, - 'shared': False, - 'static': True, - 'tests': False, - 'unity': False, - 'xrpld': False, - - 'date/*:header_only': True, - 'grpc/*:shared': False, - 'grpc/*:secure': True, - 'libarchive/*:shared': False, - 'libarchive/*:with_acl': False, - 'libarchive/*:with_bzip2': False, - 'libarchive/*:with_cng': False, - 'libarchive/*:with_expat': False, - 'libarchive/*:with_iconv': False, - 'libarchive/*:with_libxml2': False, - 'libarchive/*:with_lz4': True, - 'libarchive/*:with_lzma': False, - 'libarchive/*:with_lzo': False, - 'libarchive/*:with_nettle': False, - 'libarchive/*:with_openssl': False, - 'libarchive/*:with_pcreposix': False, - 'libarchive/*:with_xattr': False, - 'libarchive/*:with_zlib': False, - 'lz4/*:shared': False, - 'openssl/*:shared': False, - 'protobuf/*:shared': False, - 'protobuf/*:with_zlib': True, - 'rocksdb/*:enable_sse': False, - 'rocksdb/*:lite': False, - 'rocksdb/*:shared': False, - 'rocksdb/*:use_rtti': True, - 'rocksdb/*:with_jemalloc': False, - 'rocksdb/*:with_lz4': True, - 'rocksdb/*:with_snappy': True, - 'snappy/*:shared': False, - 'soci/*:shared': False, - 'soci/*:with_sqlite3': True, - 'soci/*:with_boost': True, - 'xxhash/*:shared': False, + "assertions": False, + "coverage": False, + "fPIC": True, + "jemalloc": False, + "rocksdb": True, + "shared": False, + "static": True, + "tests": False, + "unity": False, + "xrpld": False, + "date/*:header_only": True, + "ed25519/*:shared": False, + "grpc/*:shared": False, + "grpc/*:secure": True, + "grpc/*:codegen": True, + "grpc/*:cpp_plugin": True, + "grpc/*:csharp_ext": False, + "grpc/*:csharp_plugin": False, + "grpc/*:node_plugin": False, + "grpc/*:objective_c_plugin": False, + "grpc/*:php_plugin": False, + "grpc/*:python_plugin": False, + "grpc/*:ruby_plugin": False, + "grpc/*:otel_plugin": False, + "libarchive/*:shared": False, + "libarchive/*:with_acl": False, + "libarchive/*:with_bzip2": False, + "libarchive/*:with_cng": False, + "libarchive/*:with_expat": False, + "libarchive/*:with_iconv": False, + "libarchive/*:with_libxml2": False, + "libarchive/*:with_lz4": True, + "libarchive/*:with_lzma": False, + "libarchive/*:with_lzo": False, + "libarchive/*:with_nettle": False, + "libarchive/*:with_openssl": False, + "libarchive/*:with_pcreposix": False, + "libarchive/*:with_xattr": False, + "libarchive/*:with_zlib": False, + "lz4/*:shared": False, + "openssl/*:no_dtls": True, + "openssl/*:no_ssl": True, + "openssl/*:no_ssl3": True, + "openssl/*:no_tls1": True, + "openssl/*:no_tls1_1": True, + "openssl/*:shared": False, + "openssl/*:tls_security_level": 2, + "protobuf/*:shared": False, + "protobuf/*:with_zlib": True, + "rocksdb/*:enable_sse": False, + "rocksdb/*:lite": False, + "rocksdb/*:shared": False, + "rocksdb/*:use_rtti": True, + "rocksdb/*:with_jemalloc": False, + "rocksdb/*:with_lz4": True, + "rocksdb/*:with_snappy": True, + "secp256k1/*:shared": False, + "snappy/*:shared": False, + "soci/*:shared": False, + "soci/*:with_sqlite3": True, + "soci/*:with_boost": True, + "xxhash/*:shared": False, } def set_version(self): if self.version is None: - path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' - regex = r'versionString\s?=\s?\"(.*)\"' - with open(path, encoding='utf-8') as file: + path = f"{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp" + regex = r"versionString\s?=\s?\"(.*)\"" + with open(path, encoding="utf-8") as file: matches = (re.search(regex, line) for line in file) match = next(m for m in matches if m) self.version = match.group(1) def configure(self): - if self.settings.compiler == 'apple-clang': - self.options['boost'].visibility = 'global' - if self.settings.compiler in ['clang', 'gcc']: - self.options['boost'].without_cobalt = True + if self.settings.compiler == "apple-clang": + self.options["boost"].visibility = "global" + if self.settings.compiler in ["clang", "gcc"]: + self.options["boost"].without_cobalt = True def requirements(self): # Conan 2 requires transitive headers to be specified - transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {} - self.requires('boost/1.88.0', force=True, **transitive_headers_opt) - self.requires('date/3.0.4', **transitive_headers_opt) - self.requires('lz4/1.10.0', force=True) - self.requires('protobuf/3.21.12', force=True) - self.requires('sqlite3/3.49.1', force=True) + transitive_headers_opt = ( + {"transitive_headers": True} if conan_version.split(".")[0] == "2" else {} + ) + self.requires("boost/1.90.0", force=True, **transitive_headers_opt) + self.requires("date/3.0.4", **transitive_headers_opt) + self.requires("lz4/1.10.0", force=True) + self.requires("protobuf/6.32.1", force=True) + self.requires("sqlite3/3.49.1", force=True) if self.options.jemalloc: - self.requires('jemalloc/5.3.0') + self.requires("jemalloc/5.3.0") if self.options.rocksdb: - self.requires('rocksdb/10.0.1') - self.requires('xxhash/0.8.3', **transitive_headers_opt) + self.requires("rocksdb/10.5.1") + self.requires("xxhash/0.8.3", **transitive_headers_opt) exports_sources = ( - 'CMakeLists.txt', - 'cfg/*', - 'cmake/*', - 'external/*', - 'include/*', - 'src/*', + "CMakeLists.txt", + "cfg/*", + "cmake/*", + "external/*", + "include/*", + "src/*", ) def layout(self): cmake_layout(self) # Fix this setting to follow the default introduced in Conan 1.48 # to align with our build instructions. - self.folders.generators = 'build/generators' + self.folders.generators = "build/generators" + + generators = "CMakeDeps" - generators = 'CMakeDeps' def generate(self): tc = CMakeToolchain(self) - tc.variables['tests'] = self.options.tests - tc.variables['assert'] = self.options.assertions - tc.variables['coverage'] = self.options.coverage - tc.variables['jemalloc'] = self.options.jemalloc - tc.variables['rocksdb'] = self.options.rocksdb - tc.variables['BUILD_SHARED_LIBS'] = self.options.shared - tc.variables['static'] = self.options.static - tc.variables['unity'] = self.options.unity - tc.variables['xrpld'] = self.options.xrpld + tc.variables["tests"] = self.options.tests + tc.variables["assert"] = self.options.assertions + tc.variables["coverage"] = self.options.coverage + tc.variables["jemalloc"] = self.options.jemalloc + tc.variables["rocksdb"] = self.options.rocksdb + tc.variables["BUILD_SHARED_LIBS"] = self.options.shared + tc.variables["static"] = self.options.static + tc.variables["unity"] = self.options.unity + tc.variables["xrpld"] = self.options.xrpld tc.generate() def build(self): @@ -158,40 +185,40 @@ class Xrpl(ConanFile): cmake.install() def package_info(self): - libxrpl = self.cpp_info.components['libxrpl'] + libxrpl = self.cpp_info.components["libxrpl"] libxrpl.libs = [ - 'xrpl', - 'xrpl.libpb', - 'ed25519', - 'secp256k1', + "xrpl", + "xrpl.libpb", ] # TODO: Fix the protobufs to include each other relative to - # `include/`, not `include/ripple/proto/`. - libxrpl.includedirs = ['include', 'include/ripple/proto'] + # `include/`, not `include/xrpl/proto/`. + libxrpl.includedirs = ["include", "include/xrpl/proto"] libxrpl.requires = [ - 'boost::headers', - 'boost::chrono', - 'boost::container', - 'boost::coroutine', - 'boost::date_time', - 'boost::filesystem', - 'boost::json', - 'boost::program_options', - 'boost::process', - 'boost::regex', - 'boost::system', - 'boost::thread', - 'date::date', - 'grpc::grpc++', - 'libarchive::libarchive', - 'lz4::lz4', - 'nudb::nudb', - 'openssl::crypto', - 'protobuf::libprotobuf', - 'soci::soci', - 'sqlite3::sqlite', - 'xxhash::xxhash', - 'zlib::zlib', + "boost::headers", + "boost::chrono", + "boost::container", + "boost::coroutine", + "boost::date_time", + "boost::filesystem", + "boost::json", + "boost::program_options", + "boost::process", + "boost::regex", + "boost::thread", + "date::date", + "ed25519::ed25519", + "grpc::grpc++", + "libarchive::libarchive", + "lz4::lz4", + "mpt-crypto::mpt-crypto", + "nudb::nudb", + "openssl::crypto", + "protobuf::libprotobuf", + "soci::soci", + "secp256k1::secp256k1", + "sqlite3::sqlite", + "xxhash::xxhash", + "zlib::zlib", ] if self.options.rocksdb: - libxrpl.requires.append('rocksdb::librocksdb') + libxrpl.requires.append("rocksdb::librocksdb") diff --git a/cspell.config.yaml b/cspell.config.yaml new file mode 100644 index 0000000000..25d97d7c39 --- /dev/null +++ b/cspell.config.yaml @@ -0,0 +1,312 @@ +ignorePaths: + - build/** + - src/libxrpl/crypto + - CMakeUserPresets.json + - Doxyfile + - docs/**/*.puml + - cmake/** + - LICENSE.md +language: en +allowCompoundWords: true # TODO (#6334) +ignoreRandomStrings: true +minWordLength: 5 +dictionaries: + - cpp + - en_US + - en_GB +ignoreRegExpList: + - /\b[rs][1-9A-HJ-NP-Za-km-z]{25,34}/g # addresses and seeds + - /\bC[A-Z0-9]{15}/g # CTIDs + - /\b(XRPL|BEAST)_[A-Z_0-9]+_H_INCLUDED+/g # include guards + - /\b(XRPL|BEAST)_[A-Z_0-9]+_H+/g # include guards + - /::[a-z:_]+/g # things from other namespaces + - /\blib[a-z]+/g # libraries + - /\b[0-9]{4}-[0-9]{2}-[0-9]{2}[,:][A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright dates + - /\b[0-9]{4}[,:]?\s*[A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright years + - /\[[A-Za-z0-9-]+\]\(https:\/\/github.com\/[A-Za-z0-9-]+\)/g # Github usernames + - /-[DWw][a-zA-Z0-9_-]+=/g # compile flags + - /[\['"`]-[DWw][a-zA-Z0-9_-]+['"`\]]/g # compile flags + - ABCDEFGHIJKLMNOPQRSTUVWXYZ + - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +overrides: + - filename: "**/*_test.cpp" # all test files + ignoreRegExpList: + - /"[^"]*"/g # double-quoted strings + - /'[^']*'/g # single-quoted strings + - /`[^`]*`/g # backtick strings +suggestWords: + - xprl->xrpl + - xprld->xrpld # cspell: disable-line not sure what this problem is.... + - unsynched->unsynced # cspell: disable-line not sure what this problem is.... + - synched->synced + - synch->sync +words: + - abempty + - AMMID + - amt + - amts + - asnode + - asynchrony + - attestation + - authorises + - autobridge + - autobridged + - autobridging + - bimap + - bindir + - blindings + - bookdir + - Bougalis + - Britto + - Btrfs + - canonicality + - changespq + - checkme + - choco + - chrono + - citardauq + - clawback + - clawbacks + - coeffs + - coldwallet + - compr + - conanfile + - conanrun + - confs + - connectability + - coro + - coros + - cowid + - cryptocondition + - cryptoconditional + - cryptoconditions + - csprng + - ctest + - ctid + - currenttxhash + - daria + - dcmake + - dearmor + - decryptor + - deleteme + - demultiplexer + - deserializaton + - desync + - desynced + - determ + - distro + - doxyfile + - dxrpl + - elgamal + - endmacro + - exceptioned + - Falco + - finalizers + - firewalled + - fmtdur + - fsanitize + - funclets + - Gamal + - gcov + - gcovr + - ghead + - Gnutella + - gpgcheck + - gpgkey + - hotwallet + - hwrap + - ifndef + - inequation + - insuf + - insuff + - invasively + - iou + - ious + - isrdc + - itype + - jemalloc + - jlog + - jtnofill + - keylet + - keylets + - keyvadb + - kwarg + - kwargs + - ledgerentry + - ledgerhash + - ledgerindex + - leftw + - legleux + - levelization + - levelized + - libpb + - libxrpl + - llection + - LOCALGOOD + - logwstream + - lseq + - lsmf + - ltype + - mcmodel + - MEMORYSTATUSEX + - Merkle + - Metafuncton + - misprediction + - mptbalance + - MPTDEX + - mptflags + - mptid + - mptissuance + - mptissuanceid + - mptoken + - mptokenid + - mptokenissuance + - mptokens + - mpts + - mtgox + - multisig + - multisign + - multisigned + - Nakamoto + - nftid + - nftoffer + - nftoken + - nftokenid + - nftokenpages + - nftokens + - nftpage + - nikb + - nonxrp + - noripple + - nudb + - nullptr + - nunl + - Nyffenegger + - ostr + - pargs + - partitioner + - paychan + - paychans + - Pedersen + - permdex + - perminute + - permissioned + - pointee + - populator + - preauth + - preauthorization + - preauthorize + - preauthorizes + - preclaim + - protobuf + - protos + - ptrs + - pushd + - pyenv + - qalloc + - queuable + - Raphson + - replayer + - rerere + - retriable + - RIPD + - ripdtop + - rippleci + - rippled + - ripplerpc + - rippletest + - RLUSD + - rngfill + - rocksdb + - Rohrs + - roundings + - sahyadri + - Satoshi + - scons + - Schnorr + - secp + - sendq + - seqit + - sf + - SFIELD + - shamap + - shamapitem + - sidechain + - SIGGOOD + - sle + - sles + - soci + - socidb + - sslws + - statsd + - STATSDCOLLECTOR + - stissue + - stnum + - stobj + - stobject + - stpath + - stpathset + - sttx + - stvar + - stvector + - stxchainattestations + - summands + - superpeer + - superpeers + - takergets + - takerpays + - ters + - TMEndpointv2 + - trixie + - tx + - txid + - txids + - txjson + - txn + - txns + - txs + - UBSAN + - ubsan + - umant + - unacquired + - unambiguity + - unauthorizes + - unauthorizing + - unergonomic + - unfetched + - unflatten + - unfund + - unimpair + - unroutable + - unscalable + - unserviced + - unshareable + - unshares + - unsquelch + - unsquelched + - unsquelching + - unvalidated + - unveto + - unvetoed + - upvotes + - USDB + - variadics + - venv + - vfalco + - vinnie + - wextra + - wptr + - writeme + - wsrch + - wthread + - xbridge + - xchain + - ximinez + - EXPECT_STREQ + - XMACRO + - xrpkuwait + - xrpl + - xrpld + - xrplf + - xxhash + - xxhasher diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index b3ee85720f..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -html -temp -out.txt diff --git a/docs/0001-negative-unl/README.md b/docs/0001-negative-unl/README.md index f28ff63c6f..c863cab9da 100644 --- a/docs/0001-negative-unl/README.md +++ b/docs/0001-negative-unl/README.md @@ -134,7 +134,7 @@ validation messages (_PAV_) received from each validator on the node's UNL. Note that the node will only count the validation messages that agree with its own validations. -We define the **PAV** as the **P**ercentage of **A**greed **V**alidation +We define the **PAV** as the Percentage of Agreed Validation messages received for the last N ledgers, where N = 256 by default. When the PAV drops below the **_low-water mark_**, the validator is considered diff --git a/docs/0001-negative-unl/negativeUNLSqDiagram.puml b/docs/0001-negative-unl/negativeUNLSqDiagram.puml index 9f37d43903..d86b98c01f 100644 --- a/docs/0001-negative-unl/negativeUNLSqDiagram.puml +++ b/docs/0001-negative-unl/negativeUNLSqDiagram.puml @@ -43,14 +43,14 @@ alt phase == OPEN alt sqn%256==0 CA -[#green]> RM: getValidations CA -[#green]> CA: create UNLModify Tx - hnote over CA#lightgreen: use validatations of the last 256 ledgers\nto figure out UNLModify Tx candidates.\nIf any, create UNLModify Tx, and add to TxSet. + hnote over CA#lightgreen: use validations of the last 256 ledgers\nto figure out UNLModify Tx candidates.\nIf any, create UNLModify Tx, and add to TxSet. end CA -> GC GC -> CA: propose deactivate CA end else phase == ESTABLISH - hnote over GC: receive peer postions + hnote over GC: receive peer positions GC -> GC : update our position GC -> CA : propose \n(if position changed) GC -> GC : check if have consensus diff --git a/docs/README.md b/docs/README.md index c95a871729..35fcbba2d1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -54,8 +54,8 @@ There is a `docs` target in the CMake configuration. ``` mkdir build cd build -cmake .. -cmake --build . --target docs +cmake -Donly_docs=ON .. +cmake --build . --target docs --parallel ``` The output will be in `build/docs/html`. diff --git a/docs/build/sanitizers.md b/docs/build/sanitizers.md new file mode 100644 index 0000000000..3f9809ae98 --- /dev/null +++ b/docs/build/sanitizers.md @@ -0,0 +1,207 @@ +# Sanitizer Configuration for Rippled + +This document explains how to properly configure and run sanitizers (AddressSanitizer, undefinedbehaviorSanitizer, ThreadSanitizer) with the xrpld project. +Corresponding suppression files are located in the `sanitizers/suppressions` directory. + +- [Sanitizer Configuration for Rippled](#sanitizer-configuration-for-rippled) + - [Building with Sanitizers](#building-with-sanitizers) + - [Summary](#summary) + - [Build steps:](#build-steps) + - [Install dependencies](#install-dependencies) + - [Call CMake](#call-cmake) + - [Build](#build) + - [Running Tests with Sanitizers](#running-tests-with-sanitizers) + - [AddressSanitizer (ASAN)](#addresssanitizer-asan) + - [ThreadSanitizer (TSan)](#threadsanitizer-tsan) + - [LeakSanitizer (LSan)](#leaksanitizer-lsan) + - [UndefinedBehaviorSanitizer (UBSan)](#undefinedbehaviorsanitizer-ubsan) + - [Suppression Files](#suppression-files) + - [`asan.supp`](#asansupp) + - [`lsan.supp`](#lsansupp) + - [`ubsan.supp`](#ubsansupp) + - [`tsan.supp`](#tsansupp) + - [`sanitizer-ignorelist.txt`](#sanitizer-ignorelisttxt) + - [Troubleshooting](#troubleshooting) + - ["ASAN is ignoring requested \_\_asan_handle_no_return" warnings](#asan-is-ignoring-requested-__asan_handle_no_return-warnings) + - [Sanitizer Mismatch Errors](#sanitizer-mismatch-errors) + - [References](#references) + +## Building with Sanitizers + +### Summary + +Follow the same instructions as mentioned in [BUILD.md](../../BUILD.md) but with the following changes: + +1. Make sure you have a clean build directory. +2. Set the `SANITIZERS` environment variable before calling conan install and cmake. Only set it once. Make sure both conan and cmake read the same values. + Example: `export SANITIZERS=address,undefinedbehavior` +3. Optionally use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation. [!NOTE]Building with sanitizer-instrumented dependencies is slower but produces fewer false positives. +4. Set `ASAN_OPTIONS`, `LSAN_OPTIONS`, `UBSAN_OPTIONS` and `TSAN_OPTIONS` environment variables to configure sanitizer behavior when running executables. [More details below](#running-tests-with-sanitizers). + +--- + +### Build steps: + +```bash +cd /path/to/rippled +rm -rf .build +mkdir .build +cd .build +``` + +#### Install dependencies + +The `SANITIZERS` environment variable is used by both Conan and CMake. + +```bash +export SANITIZERS=address,undefinedbehavior +# Standard build (without instrumenting dependencies) +conan install .. --output-folder . --build missing --settings build_type=Debug + +# Or with sanitizer-instrumented dependencies (takes longer but fewer false positives) +conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug +``` + +[!CAUTION] +Do not mix Address and Thread sanitizers - they are incompatible. + +Since you already set the `SANITIZERS` environment variable when running Conan, same values will be read for the next part. + +#### Call CMake + +```bash +cmake .. -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Debug \ + -Dtests=ON -Dxrpld=ON +``` + +#### Build + +```bash +cmake --build . --parallel 4 +``` + +## Running Tests with Sanitizers + +### AddressSanitizer (ASAN) + +**IMPORTANT**: ASAN with Boost produces many false positives. Use these options: + +```bash +export ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=path/to/asan.supp:halt_on_error=0:log_path=asan.log" +export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsan.log" + +# Run tests +./xrpld --unittest --unittest-jobs=5 +``` + +**Why `detect_container_overflow=0`?** + +- Boost intrusive containers (used in `aged_unordered_container`) trigger false positives +- Boost context switching (used in `Workers.cpp`) confuses ASAN's stack tracking +- Since we usually don't build Boost (because we don't want to instrument Boost and detect issues in Boost code) with ASAN but use Boost containers in ASAN instrumented rippled code, it generates false positives. +- Building dependencies with ASAN instrumentation reduces false positives. But we don't want to instrument dependencies like Boost with ASAN because it is slow (to compile as well as run tests) and not necessary. +- See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow +- More such flags are detailed [here](https://github.com/google/sanitizers/wiki/AddressSanitizerFlags) + +### ThreadSanitizer (TSan) + +```bash +export TSAN_OPTIONS="suppressions=path/to/tsan.supp halt_on_error=0 log_path=tsan.log" + +# Run tests +./xrpld --unittest --unittest-jobs=5 +``` + +More details [here](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual). + +### LeakSanitizer (LSan) + +LSan is automatically enabled with ASAN. To disable it: + +```bash +export ASAN_OPTIONS="detect_leaks=0" +``` + +More details [here](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer). + +### UndefinedBehaviorSanitizer (UBSan) + +```bash +export UBSAN_OPTIONS="suppressions=path/to/ubsan.supp:print_stacktrace=1:halt_on_error=0:log_path=ubsan.log" + +# Run tests +./xrpld --unittest --unittest-jobs=5 +``` + +More details [here](https://clang.llvm.org/docs/undefinedbehaviorSanitizer.html). + +## Suppression Files + +[!NOTE] Attached files contain more details. + +### [`asan.supp`](../../sanitizers/suppressions/asan.supp) + +- **Purpose**: Suppress AddressSanitizer (ASAN) errors only +- **Format**: `interceptor_name:` where pattern matches file names. Supported suppression types are: + - interceptor_name + - interceptor_via_fun + - interceptor_via_lib + - odr_violation +- **More info**: [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) +- **Note**: Cannot suppress stack-buffer-overflow, container-overflow, etc. + +### [`lsan.supp`](../../sanitizers/suppressions/lsan.supp) + +- **Purpose**: Suppress LeakSanitizer (LSan) errors only +- **Format**: `leak:` where pattern matches function/file names +- **More info**: [LeakSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer) + +### [`ubsan.supp`](../../sanitizers/suppressions/ubsan.supp) + +- **Purpose**: Suppress undefinedbehaviorSanitizer errors +- **Format**: `:` (e.g., `unsigned-integer-overflow:protobuf`) +- **Covers**: Intentional overflows in sanitizers/suppressions libraries (protobuf, gRPC, stdlib) +- More info [UBSan suppressions](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html). + +### [`tsan.supp`](../../sanitizers/suppressions/tsan.supp) + +- **Purpose**: Suppress ThreadSanitizer data race warnings +- **Format**: `race:` where pattern matches function/file names +- **More info**: [ThreadSanitizer suppressions](https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions) + +### [`sanitizer-ignorelist.txt`](../../sanitizers/suppressions/sanitizer-ignorelist.txt) + +- **Purpose**: Compile-time ignorelist for all sanitizers +- **Usage**: Passed via `-fsanitize-ignorelist=absolute/path/to/sanitizer-ignorelist.txt` +- **Format**: `:` (e.g., `src:Workers.cpp`) + +## Troubleshooting + +### "ASAN is ignoring requested \_\_asan_handle_no_return" warnings + +These warnings appear when using Boost context switching and are harmless. They indicate potential false positives. + +### Sanitizer Mismatch Errors + +If you see undefined symbols like `___tsan_atomic_load` when building with ASAN: + +**Problem**: Dependencies were built with a different sanitizer than the main project. + +**Solution**: Rebuild everything with the same sanitizer: + +```bash +rm -rf .build +# Then follow the build instructions above +``` + +Then review the log files: `asan.log.*`, `ubsan.log.*`, `tsan.log.*` + +## References + +- [AddressSanitizer Wiki](https://github.com/google/sanitizers/wiki/AddressSanitizer) +- [AddressSanitizer Flags](https://github.com/google/sanitizers/wiki/AddressSanitizerFlags) +- [Container Overflow Detection](https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow) +- [UndefinedBehavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) +- [ThreadSanitizer](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual) diff --git a/docs/consensus.md b/docs/consensus.md index 067e15d0c8..23e5e7d5be 100644 --- a/docs/consensus.md +++ b/docs/consensus.md @@ -189,7 +189,7 @@ validations. It checks this on every call to `timerEntry`. - _Wrong Ledger_ indicates the node is not working on the correct prior ledger and does not have it available. It requests that ledger from the network, but continues to work towards consensus this round while waiting. If it had been - _proposing_, it will send a special "bowout" proposal to its peers to indicate + _proposing_, it will send a special "bow-out" proposal to its peers to indicate its change in mode for the rest of this round. For the duration of the round, it defers to peer positions for determining the consensus outcome as if it were just _observing_. @@ -515,7 +515,7 @@ are excerpts of the generic consensus implementation and of helper types that wi interact with the concrete implementing class. ```{.cpp} -// Represents a transction under dispute this round +// Represents a transaction under dispute this round template class DisputedTx; // Represents how the node participates in Consensus this round diff --git a/external/README.md b/external/README.md index 7de1fd25a0..f6e9f77d2d 100644 --- a/external/README.md +++ b/external/README.md @@ -5,5 +5,3 @@ The subdirectories in this directory contain external libraries used by rippled. | Folder | Upstream | Description | | :--------------- | :------------------------------------------------------------- | :------------------------------------------------------------------------------------------- | | `antithesis-sdk` | [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ | -| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures | -| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve | diff --git a/external/ed25519-donna/CMakeLists.txt b/external/ed25519-donna/CMakeLists.txt deleted file mode 100644 index f060d530aa..0000000000 --- a/external/ed25519-donna/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -cmake_minimum_required(VERSION 3.11) - -project(ed25519 - LANGUAGES C -) - -if(PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/output/$/lib") -endif() - -if(NOT TARGET OpenSSL::SSL) - find_package(OpenSSL) -endif() - -add_library(ed25519 STATIC - ed25519.c -) -add_library(ed25519::ed25519 ALIAS ed25519) -target_link_libraries(ed25519 PUBLIC OpenSSL::SSL) -if(NOT MSVC) - target_compile_options(ed25519 PRIVATE -Wno-implicit-fallthrough) -endif() - -include(GNUInstallDirs) - -#[=========================================================[ - NOTE for macos: - https://github.com/floodyberry/ed25519-donna/issues/29 - our source for ed25519-donna-portable.h has been - patched to workaround this. -#]=========================================================] -target_include_directories(ed25519 PUBLIC - $ - $ -) - -install( - TARGETS ed25519 - EXPORT ${PROJECT_NAME}-exports - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" -) -install( - EXPORT ${PROJECT_NAME}-exports - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" - FILE ${PROJECT_NAME}-targets.cmake - NAMESPACE ${PROJECT_NAME}:: -) -install( - FILES ed25519.h - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" -) diff --git a/external/ed25519-donna/README.md b/external/ed25519-donna/README.md deleted file mode 100644 index e09fc27e31..0000000000 --- a/external/ed25519-donna/README.md +++ /dev/null @@ -1,183 +0,0 @@ -[ed25519](http://ed25519.cr.yp.to/) is an -[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA), -developed by [Dan Bernstein](http://cr.yp.to/djb.html), -[Niels Duif](http://www.nielsduif.nl/), -[Tanja Lange](http://hyperelliptic.org/tanja), -[Peter Schwabe](http://www.cryptojedi.org/users/peter/), -and [Bo-Yin Yang](http://www.iis.sinica.edu.tw/pages/byyang/). - -This project provides performant, portable 32-bit & 64-bit implementations. All implementations are -of course constant time in regard to secret data. - -#### Performance - -SSE2 code and benches have not been updated yet. I will do those next. - -Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. - -Batch verification time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles. - -Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! - -Visual Studio performance for `ge25519_scalarmult_base_niels` will lag behind a bit until optimized assembler versions of `ge25519_scalarmult_base_choose_niels` -are made. - -##### E5200 @ 2.5ghz, march=core2 - - - - - - - - - - - -
ImplementationSigngcciccclangVerifygcciccclang
ed25519-donna 64bit 100k110k137k327k (144k) 342k (163k) 422k (194k)
amd64-64-24k 102k 355k (158k)
ed25519-donna-sse2 64bit108k111k116k353k (155k) 345k (154k) 360k (161k)
amd64-51-32k 116k 380k (175k)
ed25519-donna-sse2 32bit147k147k156k380k (178k) 381k (173k) 430k (192k)
ed25519-donna 32bit 597k335k380k1693k (720k)1052k (453k)1141k (493k)
- -##### E3-1270 @ 3.4ghz, march=corei7-avx - - - - - - - - - - - -
ImplementationSigngcciccclangVerifygcciccclang
amd64-64-24k 68k 225k (104k)
ed25519-donna 64bit 71k 75k 90k226k (105k) 226k (112k) 277k (125k)
amd64-51-32k 72k 218k (107k)
ed25519-donna-sse2 64bit 79k 82k 92k252k (122k) 259k (124k) 282k (131k)
ed25519-donna-sse2 32bit 94k 95k103k296k (146k) 294k (137k) 306k (147k)
ed25519-donna 32bit 525k299k316k1502k (645k)959k (418k) 954k (416k)
- -#### Compilation - -No configuration is needed **if you are compiling against OpenSSL**. - -##### Hash Options - -If you are not compiling aginst OpenSSL, you will need a hash function. - -To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`. -This should never be used except to verify the code works when OpenSSL is not available. - -To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your -custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); - -##### Random Options - -If you are not compiling aginst OpenSSL, you will need a random function for batch verification. - -To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your -custom hash implementation in ed25519-randombytes-custom.h. The random function must implement: - - void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); - -Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG -variant of Bob Jenkins [ISAAC](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29) - -##### Minor options - -Use `-DED25519_INLINE_ASM` to disable the use of custom assembler routines and instead rely on portable C. - -Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compiling for 64 bit. - -##### 32-bit - - gcc ed25519.c -m32 -O3 -c - -##### 64-bit - - gcc ed25519.c -m64 -O3 -c - -##### SSE2 - - gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 - gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 - -clang and icc are also supported - - -#### Usage - -To use the code, link against `ed25519.o -mbits` and: - - #include "ed25519.h" - -Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error). - -To generate a private key, simply generate 32 bytes from a secure -cryptographic source: - - ed25519_secret_key sk; - randombytes(sk, sizeof(ed25519_secret_key)); - -To generate a public key: - - ed25519_public_key pk; - ed25519_publickey(sk, pk); - -To sign a message: - - ed25519_signature sig; - ed25519_sign(message, message_len, sk, pk, signature); - -To verify a signature: - - int valid = ed25519_sign_open(message, message_len, pk, signature) == 0; - -To batch verify signatures: - - const unsigned char *mp[num] = {message1, message2..} - size_t ml[num] = {message_len1, message_len2..} - const unsigned char *pkp[num] = {pk1, pk2..} - const unsigned char *sigp[num] = {signature1, signature2..} - int valid[num] - - /* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */ - int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0; - -**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in -`ed25519-randombytes.h`, to generate random scalars for the verification code. -The default implementation now uses OpenSSLs `RAND_bytes`. - -Unlike the [SUPERCOP](http://bench.cr.yp.to/supercop.html) version, signatures are -not appended to messages, and there is no need for padding in front of messages. -Additionally, the secret key does not contain a copy of the public key, so it is -32 bytes instead of 64 bytes, and the public key must be provided to the signing -function. - -##### Curve25519 - -Curve25519 public keys can be generated thanks to -[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html) -leveraging Ed25519's precomputed basepoint scalar multiplication. - - curved25519_key sk, pk; - randombytes(sk, sizeof(curved25519_key)); - curved25519_scalarmult_basepoint(pk, sk); - -Note the name is curved25519, a combination of curve and ed25519, to prevent -name clashes. Performance is slightly faster than short message ed25519 -signing due to both using the same code for the scalar multiply. - -#### Testing - -Fuzzing against reference implemenations is now available. See [fuzz/README](fuzz/README.md). - -Building `ed25519.c` with `-DED25519_TEST` and linking with `test.c` will run basic sanity tests -and benchmark each function. `test-batch.c` has been incorporated in to `test.c`. - -`test-internals.c` is standalone and built the same way as `ed25519.c`. It tests the math primitives -with extreme values to ensure they function correctly. SSE2 is now supported. - -#### Papers - -[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html) \ No newline at end of file diff --git a/external/ed25519-donna/curve25519-donna-32bit.h b/external/ed25519-donna/curve25519-donna-32bit.h deleted file mode 100644 index b0861acf03..0000000000 --- a/external/ed25519-donna/curve25519-donna-32bit.h +++ /dev/null @@ -1,579 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - 32 bit integer curve25519 implementation -*/ - -typedef uint32_t bignum25519[10]; -typedef uint32_t bignum25519align16[12]; - -static const uint32_t reduce_mask_25 = (1 << 25) - 1; -static const uint32_t reduce_mask_26 = (1 << 26) - 1; - - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; - out[5] = in[5]; - out[6] = in[6]; - out[7] = in[7]; - out[8] = in[8]; - out[9] = in[9]; -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; - out[5] = a[5] + b[5]; - out[6] = a[6] + b[6]; - out[7] = a[7] + b[7]; - out[8] = a[8] + b[8]; - out[9] = a[9] + b[9]; -} - -DONNA_INLINE static void -curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* multiples of p */ -static const uint32_t twoP0 = 0x07ffffda; -static const uint32_t twoP13579 = 0x03fffffe; -static const uint32_t twoP2468 = 0x07fffffe; -static const uint32_t fourP0 = 0x0fffffb4; -static const uint32_t fourP13579 = 0x07fffffc; -static const uint32_t fourP2468 = 0x0ffffffc; - -/* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 + a[4] - b[4] + c; - out[5] = twoP13579 + a[5] - b[5] ; - out[6] = twoP2468 + a[6] - b[6] ; - out[7] = twoP13579 + a[7] - b[7] ; - out[8] = twoP2468 + a[8] - b[8] ; - out[9] = twoP13579 + a[9] - b[9] ; -} - -/* out = a - b, where a is the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* out = -a */ -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 a) { - uint32_t c; - out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* out = a * b */ -#define curve25519_mul_noinline curve25519_mul -static void -curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = b[0]; - r1 = b[1]; - r2 = b[2]; - r3 = b[3]; - r4 = b[4]; - r5 = b[5]; - r6 = b[6]; - r7 = b[7]; - r8 = b[8]; - r9 = b[9]; - - s0 = a[0]; - s1 = a[1]; - s2 = a[2]; - s3 = a[3]; - s4 = a[4]; - s5 = a[5]; - s6 = a[6]; - s7 = a[7]; - s8 = a[8]; - s9 = a[9]; - - m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); - m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); - m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); - m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); - m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); - - r1 *= 2; - r3 *= 2; - r5 *= 2; - r7 *= 2; - - m0 = mul32x32_64(r0, s0); - m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); - m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); - m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); - m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); - - r1 *= 19; - r2 *= 19; - r3 = (r3 / 2) * 19; - r4 *= 19; - r5 = (r5 / 2) * 19; - r6 *= 19; - r7 = (r7 / 2) * 19; - r8 *= 19; - r9 *= 19; - - m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); - m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); - m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); - m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); - - r3 *= 2; - r5 *= 2; - r7 *= 2; - r9 *= 2; - - m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); - m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); - m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); - m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); - m8 += (mul32x32_64(r9, s9)); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* out = in*in */ -static void -curve25519_square(bignum25519 out, const bignum25519 in) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - - -/* out = in ^ (2 * count) */ -static void -curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - do { - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - } while (--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - - if (endian_check.s == 1) { - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - } else { - #define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); - #undef F - } - - out[0] = ( x0 ) & 0x3ffffff; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; - out[4] = (( x3) >> 6) & 0x3ffffff; - out[5] = ( x4 ) & 0x1ffffff; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; - out[9] = (( x7) >> 6) & 0x1ffffff; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 f; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ - f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ - f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ - f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ - f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ - f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ - f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ - f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ - f[9] += f[8] >> 26; f[8] &= reduce_mask_26; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= reduce_mask_25; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (reduce_mask_26 + 1) - 19; - f[1] += (reduce_mask_25 + 1) - 1; - f[2] += (reduce_mask_26 + 1) - 1; - f[3] += (reduce_mask_25 + 1) - 1; - f[4] += (reduce_mask_26 + 1) - 1; - f[5] += (reduce_mask_25 + 1) - 1; - f[6] += (reduce_mask_26 + 1) - 1; - f[7] += (reduce_mask_25 + 1) - 1; - f[8] += (reduce_mask_26 + 1) - 1; - f[9] += (reduce_mask_25 + 1) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} - - -/* out = (flag) ? in : out */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { - const uint32_t nb = flag - 1, b = ~nb; - const uint32_t *inl = (const uint32_t *)in; - uint32_t *outl = (uint32_t *)out; - outl[0] = (outl[0] & nb) | (inl[0] & b); - outl[1] = (outl[1] & nb) | (inl[1] & b); - outl[2] = (outl[2] & nb) | (inl[2] & b); - outl[3] = (outl[3] & nb) | (inl[3] & b); - outl[4] = (outl[4] & nb) | (inl[4] & b); - outl[5] = (outl[5] & nb) | (inl[5] & b); - outl[6] = (outl[6] & nb) | (inl[6] & b); - outl[7] = (outl[7] & nb) | (inl[7] & b); - outl[8] = (outl[8] & nb) | (inl[8] & b); - outl[9] = (outl[9] & nb) | (inl[9] & b); - outl[10] = (outl[10] & nb) | (inl[10] & b); - outl[11] = (outl[11] & nb) | (inl[11] & b); - outl[12] = (outl[12] & nb) | (inl[12] & b); - outl[13] = (outl[13] & nb) | (inl[13] & b); - outl[14] = (outl[14] & nb) | (inl[14] & b); - outl[15] = (outl[15] & nb) | (inl[15] & b); - outl[16] = (outl[16] & nb) | (inl[16] & b); - outl[17] = (outl[17] & nb) | (inl[17] & b); - outl[18] = (outl[18] & nb) | (inl[18] & b); - outl[19] = (outl[19] & nb) | (inl[19] & b); - outl[20] = (outl[20] & nb) | (inl[20] & b); - outl[21] = (outl[21] & nb) | (inl[21] & b); - outl[22] = (outl[22] & nb) | (inl[22] & b); - outl[23] = (outl[23] & nb) | (inl[23] & b); - -} - -/* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; - - x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; - x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; - x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; - x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; - x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; - x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; - x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; - x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; - x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; - x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; -} diff --git a/external/ed25519-donna/curve25519-donna-64bit.h b/external/ed25519-donna/curve25519-donna-64bit.h deleted file mode 100644 index 2941d1bcdc..0000000000 --- a/external/ed25519-donna/curve25519-donna-64bit.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - Public domain by Adam Langley & - Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - 64bit integer curve25519 implementation -*/ - -typedef uint64_t bignum25519[5]; - -static const uint64_t reduce_mask_40 = ((uint64_t)1 << 40) - 1; -static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1; -static const uint64_t reduce_mask_56 = ((uint64_t)1 << 56) - 1; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; -} - -/* out = a + b, where a and/or b are the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; -} - -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint64_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = a[1] + b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = a[2] + b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = a[3] + b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = a[4] + b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* multiples of p */ -static const uint64_t twoP0 = 0x0fffffffffffda; -static const uint64_t twoP1234 = 0x0ffffffffffffe; -static const uint64_t fourP0 = 0x1fffffffffffb4; -static const uint64_t fourP1234 = 0x1ffffffffffffc; - -/* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + twoP0 - b[0]; - out[1] = a[1] + twoP1234 - b[1]; - out[2] = a[2] + twoP1234 - b[2]; - out[3] = a[3] + twoP1234 - b[3]; - out[4] = a[4] + twoP1234 - b[4]; -} - -/* out = a - b, where a and/or b are the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + fourP0 - b[0]; - out[1] = a[1] + fourP1234 - b[1]; - out[2] = a[2] + fourP1234 - b[2]; - out[3] = a[3] + fourP1234 - b[3]; - out[4] = a[4] + fourP1234 - b[4]; -} - -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint64_t c; - out[0] = a[0] + fourP0 - b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = a[1] + fourP1234 - b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = a[2] + fourP1234 - b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = a[3] + fourP1234 - b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = a[4] + fourP1234 - b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* out = -a */ -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 a) { - uint64_t c; - out[0] = twoP0 - a[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = twoP1234 - a[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = twoP1234 - a[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = twoP1234 - a[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = twoP1234 - a[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* out = a * b */ -DONNA_INLINE static void -curve25519_mul(bignum25519 out, const bignum25519 in2, const bignum25519 in) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - s0 = in2[0]; - s1 = in2[1]; - s2 = in2[2]; - s3 = in2[3]; - s4 = in2[4]; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * s0; - t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; - t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; - t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; - t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; -#else - mul64x64_128(t[0], r0, s0) - mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) - mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) - mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) - mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) -#endif - - r1 *= 19; - r2 *= 19; - r3 *= 19; - r4 *= 19; - -#if defined(HAVE_NATIVE_UINT128) - t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; - t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; - t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; - t[3] += ((uint128_t) r4) * s4; -#else - mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) - mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) - mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) - mul64x64_128(mul, r4, s4) add128(t[3], mul) -#endif - - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -DONNA_NOINLINE static void -curve25519_mul_noinline(bignum25519 out, const bignum25519 in2, const bignum25519 in) { - curve25519_mul(out, in2, in); -} - -/* out = in^(2 * count) */ -DONNA_NOINLINE static void -curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - do { - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; - r1 = lo128(t[1]) & reduce_mask_51; shl128(c, t[0], 13); r1 += c; - r2 = lo128(t[2]) & reduce_mask_51; shl128(c, t[1], 13); r2 += c; - r3 = lo128(t[3]) & reduce_mask_51; shl128(c, t[2], 13); r3 += c; - r4 = lo128(t[4]) & reduce_mask_51; shl128(c, t[3], 13); r4 += c; - shl128(c, t[4], 13); r0 += c * 19; - c = r0 >> 51; r0 &= reduce_mask_51; - r1 += c ; c = r1 >> 51; r1 &= reduce_mask_51; - r2 += c ; c = r2 >> 51; r2 &= reduce_mask_51; - r3 += c ; c = r3 >> 51; r3 &= reduce_mask_51; - r4 += c ; c = r4 >> 51; r4 &= reduce_mask_51; - r0 += c * 19; - } while(--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -DONNA_INLINE static void -curve25519_square(bignum25519 out, const bignum25519 in) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -DONNA_INLINE static void -curve25519_expand(bignum25519 out, const unsigned char *in) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint64_t x0,x1,x2,x3; - - if (endian_check.s == 1) { - x0 = *(uint64_t *)(in + 0); - x1 = *(uint64_t *)(in + 8); - x2 = *(uint64_t *)(in + 16); - x3 = *(uint64_t *)(in + 24); - } else { - #define F(s) \ - ((((uint64_t)in[s + 0]) ) | \ - (((uint64_t)in[s + 1]) << 8) | \ - (((uint64_t)in[s + 2]) << 16) | \ - (((uint64_t)in[s + 3]) << 24) | \ - (((uint64_t)in[s + 4]) << 32) | \ - (((uint64_t)in[s + 5]) << 40) | \ - (((uint64_t)in[s + 6]) << 48) | \ - (((uint64_t)in[s + 7]) << 56)) - - x0 = F(0); - x1 = F(8); - x2 = F(16); - x3 = F(24); - } - - out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); - out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); - out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); - out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); - out[4] = x3 & reduce_mask_51; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -DONNA_INLINE static void -curve25519_contract(unsigned char *out, const bignum25519 input) { - uint64_t t[5]; - uint64_t f, i; - - t[0] = input[0]; - t[1] = input[1]; - t[2] = input[2]; - t[3] = input[3]; - t[4] = input[4]; - - #define curve25519_contract_carry() \ - t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ - t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ - t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ - t[4] += t[3] >> 51; t[3] &= reduce_mask_51; - - #define curve25519_contract_carry_full() curve25519_contract_carry() \ - t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; - - #define curve25519_contract_carry_final() curve25519_contract_carry() \ - t[4] &= reduce_mask_51; - - curve25519_contract_carry_full() - curve25519_contract_carry_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - t[0] += 19; - curve25519_contract_carry_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - t[0] += (reduce_mask_51 + 1) - 19; - t[1] += (reduce_mask_51 + 1) - 1; - t[2] += (reduce_mask_51 + 1) - 1; - t[3] += (reduce_mask_51 + 1) - 1; - t[4] += (reduce_mask_51 + 1) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - curve25519_contract_carry_final() - - #define write51full(n,shift) \ - f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ - for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f; - #define write51(n) write51full(n,13*n) - write51(0) - write51(1) - write51(2) - write51(3) -} - -#if !defined(ED25519_GCC_64BIT_CHOOSE) - -/* out = (flag) ? in : out */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint64_t flag) { - const uint64_t nb = flag - 1, b = ~nb; - const uint64_t *inq = (const uint64_t *)in; - uint64_t *outq = (uint64_t *)out; - outq[0] = (outq[0] & nb) | (inq[0] & b); - outq[1] = (outq[1] & nb) | (inq[1] & b); - outq[2] = (outq[2] & nb) | (inq[2] & b); - outq[3] = (outq[3] & nb) | (inq[3] & b); - outq[4] = (outq[4] & nb) | (inq[4] & b); - outq[5] = (outq[5] & nb) | (inq[5] & b); - outq[6] = (outq[6] & nb) | (inq[6] & b); - outq[7] = (outq[7] & nb) | (inq[7] & b); - outq[8] = (outq[8] & nb) | (inq[8] & b); - outq[9] = (outq[9] & nb) | (inq[9] & b); - outq[10] = (outq[10] & nb) | (inq[10] & b); - outq[11] = (outq[11] & nb) | (inq[11] & b); -} - -/* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint64_t iswap) { - const uint64_t swap = (uint64_t)(-(int64_t)iswap); - uint64_t x0,x1,x2,x3,x4; - - x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; - x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; - x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; - x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; - x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; -} - -#endif /* ED25519_GCC_64BIT_CHOOSE */ - -#define ED25519_64BIT_TABLES - diff --git a/external/ed25519-donna/curve25519-donna-helpers.h b/external/ed25519-donna/curve25519-donna-helpers.h deleted file mode 100644 index e4058ff5ec..0000000000 --- a/external/ed25519-donna/curve25519-donna-helpers.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - Curve25519 implementation agnostic helpers -*/ - -/* - * In: b = 2^5 - 2^0 - * Out: b = 2^250 - 2^0 - */ -static void -curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { - bignum25519 ALIGN(16) t0,c; - - /* 2^5 - 2^0 */ /* b */ - /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); - /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); - /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); - /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); - /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); - /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); - /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); - /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); -} - -/* - * z^(p - 2) = z(2^255 - 21) - */ -static void -curve25519_recip(bignum25519 out, const bignum25519 z) { - bignum25519 ALIGN(16) a,t0,b; - - /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ - /* 8 */ curve25519_square_times(t0, a, 2); - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ - /* 22 */ curve25519_square_times(t0, a, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); - /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); -} - -/* - * z^((p-5)/8) = z^(2^252 - 3) - */ -static void -curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { - bignum25519 ALIGN(16) b,c,t0; - - /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ - /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ - /* 22 */ curve25519_square_times(t0, c, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); - /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); -} diff --git a/external/ed25519-donna/curve25519-donna-sse2.h b/external/ed25519-donna/curve25519-donna-sse2.h deleted file mode 100644 index 1dbfd44d8b..0000000000 --- a/external/ed25519-donna/curve25519-donna-sse2.h +++ /dev/null @@ -1,1112 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - SSE2 curve25519 implementation -*/ - -#include -typedef __m128i xmmi; - -typedef union packedelem8_t { - unsigned char u[16]; - xmmi v; -} packedelem8; - -typedef union packedelem32_t { - uint32_t u[4]; - xmmi v; -} packedelem32; - -typedef union packedelem64_t { - uint64_t u[2]; - xmmi v; -} packedelem64; - -/* 10 elements + an extra 2 to fit in 3 xmm registers */ -typedef uint32_t bignum25519[12]; -typedef packedelem32 packed32bignum25519[5]; -typedef packedelem64 packed64bignum25519[10]; - -static const packedelem32 bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; -static const packedelem32 top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; -static const packedelem32 top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; -static const packedelem32 bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; - -/* reduction masks */ -static const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; -static const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; -static const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; -static const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; -static const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; - -/* multipliers */ -static const packedelem64 packednineteen = {{19, 19}}; -static const packedelem64 packednineteenone = {{19, 1}}; -static const packedelem64 packedthirtyeight = {{38, 38}}; -static const packedelem64 packed3819 = {{19*2,19}}; -static const packedelem64 packed9638 = {{19*4,19*2}}; - -/* 121666,121665 */ -static const packedelem64 packed121666121665 = {{121666, 121665}}; - -/* 2*(2^255 - 19) = 0 mod p */ -static const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; - -static const packedelem32 packed32packed2p0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; -static const packedelem32 packed32packed2p1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; - -/* 4*(2^255 - 19) = 0 mod p */ -static const packedelem32 packed4p0 = {{0xfffffb4,0x7fffffc,0xffffffc,0x7fffffc}}; -static const packedelem32 packed4p1 = {{0xffffffc,0x7fffffc,0xffffffc,0x7fffffc}}; -static const packedelem32 packed4p2 = {{0xffffffc,0x7fffffc,0x0000000,0x0000000}}; - -static const packedelem32 packed32packed4p0 = {{0xfffffb4,0xfffffb4,0x7fffffc,0x7fffffc}}; -static const packedelem32 packed32packed4p1 = {{0xffffffc,0xffffffc,0x7fffffc,0x7fffffc}}; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - xmmi x0,x1,x2; - x0 = _mm_load_si128((xmmi*)in + 0); - x1 = _mm_load_si128((xmmi*)in + 1); - x2 = _mm_load_si128((xmmi*)in + 2); - _mm_store_si128((xmmi*)out + 0, x0); - _mm_store_si128((xmmi*)out + 1, x1); - _mm_store_si128((xmmi*)out + 2, x2); -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_add_epi32(a0, b0); - a1 = _mm_add_epi32(a1, b1); - a2 = _mm_add_epi32(a2, b2); - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); -} - -#define curve25519_add_after_basic curve25519_add_reduce -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_add_epi32(a0, b0); - a1 = _mm_add_epi32(a1, b1); - a2 = _mm_add_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2; - xmmi r0,r1; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed2p0.v); - a1 = _mm_add_epi32(a1, packed2p1.v); - a2 = _mm_add_epi32(a2, packed2p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(2,2,0,0)), bot32bitmask.v); - r1 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3,3,1,1)), bot32bitmask.v); - - c1 = _mm_srli_epi32(r0, 26); - c2 = _mm_srli_epi32(r1, 25); - r0 = _mm_and_si128(r0, packedmask26.v); - r1 = _mm_and_si128(r1, packedmask25.v); - r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); - r1 = _mm_add_epi32(r1, c1); - - a0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); - a1 = _mm_add_epi32(a1, _mm_srli_si128(c2, 8)); - - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); -} - -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed4p0.v); - a1 = _mm_add_epi32(a1, packed4p1.v); - a2 = _mm_add_epi32(a2, packed4p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed2p0.v); - a1 = _mm_add_epi32(a1, packed2p1.v); - a2 = _mm_add_epi32(a2, packed2p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - - -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = packed2p0.v; - a1 = packed2p1.v; - a2 = packed2p2.v; - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - - -/* Multiply two numbers: out = in2 * in */ -static void -curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { - xmmi m01,m23,m45,m67,m89; - xmmi m0123,m4567; - xmmi s0123,s4567; - xmmi s01,s23,s45,s67,s89; - xmmi s12,s34,s56,s78,s9; - xmmi r0,r2,r4,r6,r8; - xmmi r1,r3,r5,r7,r9; - xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; - xmmi c1,c2,c3; - - s0123 = _mm_load_si128((xmmi*)s + 0); - s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); - s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); - s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); - s4567 = _mm_load_si128((xmmi*)s + 1); - s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); - s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); - s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); - s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); - s89 = _mm_load_si128((xmmi*)s + 2); - s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); - s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); - s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); - - r0 = _mm_load_si128((xmmi*)r + 0); - r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); - r1 = _mm_add_epi64(r1, _mm_and_si128(r1, top64bitmask.v)); - r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); - r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); - r3 = _mm_add_epi64(r3, _mm_and_si128(r3, top64bitmask.v)); - r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_load_si128((xmmi*)r + 1); - r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); - r5 = _mm_add_epi64(r5, _mm_and_si128(r5, top64bitmask.v)); - r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); - r7 = _mm_add_epi64(r7, _mm_and_si128(r7, top64bitmask.v)); - r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_load_si128((xmmi*)r + 2); - r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); - r9 = _mm_add_epi64(r9, _mm_and_si128(r9, top64bitmask.v)); - r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); - - m01 = _mm_mul_epu32(r1,s01); - m23 = _mm_mul_epu32(r1,s23); - m45 = _mm_mul_epu32(r1,s45); - m67 = _mm_mul_epu32(r1,s67); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); - m89 = _mm_mul_epu32(r1,s89); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); - - /* shift up */ - m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); - m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); - m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); - m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); - m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); - - r219 = _mm_mul_epu32(r2, packednineteen.v); - r419 = _mm_mul_epu32(r4, packednineteen.v); - r619 = _mm_mul_epu32(r6, packednineteen.v); - r819 = _mm_mul_epu32(r8, packednineteen.v); - r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); - r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); - r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); - r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); - r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - m0123 = _mm_unpacklo_epi32(r0, r1); - m4567 = _mm_unpackhi_epi32(r0, r1); - m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); - m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); - m89 = _mm_unpackhi_epi32(r4, r5); - - _mm_store_si128((xmmi*)out + 0, m0123); - _mm_store_si128((xmmi*)out + 1, m4567); - _mm_store_si128((xmmi*)out + 2, m89); -} - -DONNA_NOINLINE static void -curve25519_mul_noinline(bignum25519 out, const bignum25519 r, const bignum25519 s) { - curve25519_mul(out, r, s); -} - -#define curve25519_square(r, n) curve25519_square_times(r, n, 1) -static void -curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { - xmmi m01,m23,m45,m67,m89; - xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r0a,r1a,r2a,r3a,r7a,r9a; - xmmi r0123,r4567; - xmmi r01,r23,r45,r67,r6x,r89,r8x; - xmmi r12,r34,r56,r78,r9x; - xmmi r5619; - xmmi c1,c2,c3; - - r0123 = _mm_load_si128((xmmi*)in + 0); - r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); - r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); - r4567 = _mm_load_si128((xmmi*)in + 1); - r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); - r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); - r89 = _mm_load_si128((xmmi*)in + 2); - r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); - - do { - r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); - r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); - r0 = _mm_add_epi64(r0, _mm_and_si128(r0, top64bitmask.v)); - r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); - r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); - r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); - r2 = _mm_add_epi64(r2, _mm_and_si128(r2, top64bitmask.v)); - r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); - r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); - r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); - r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_add_epi64(r4, _mm_and_si128(r4, top64bitmask.v)); - r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); - r5619 = _mm_mul_epu32(r56, packednineteen.v); - r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); - r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); - r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); - r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); - r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_mul_epu32(r7, packed3819.v); - r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); - r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); - r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_mul_epu32(r8, packednineteen.v); - r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); - r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); - r9 = _mm_mul_epu32(r9, packed3819.v); - r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); - - m01 = _mm_mul_epu32(r01, r0); - m23 = _mm_mul_epu32(r23, r0a); - m45 = _mm_mul_epu32(r45, r0a); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); - r23 = _mm_slli_epi32(r23, 1); - m67 = _mm_mul_epu32(r67, r0a); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); - m89 = _mm_mul_epu32(r89, r0a); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); - r67 = _mm_slli_epi32(r67, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); - r45 = _mm_slli_epi32(r45, 1); - - r1 = _mm_slli_epi32(r1, 1); - r3 = _mm_slli_epi32(r3, 1); - r1a = _mm_add_epi64(r1, _mm_and_si128(r1, bot64bitmask.v)); - r3a = _mm_add_epi64(r3, _mm_and_si128(r3, bot64bitmask.v)); - - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); - r34 = _mm_slli_epi32(r34, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); - r78 = _mm_slli_epi32(r78, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); - r56 = _mm_slli_epi32(r56, 1); - - m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - r01 = _mm_unpacklo_epi64(r0, r1); - r45 = _mm_unpackhi_epi64(r0, r1); - r23 = _mm_unpacklo_epi64(r2, r3); - r67 = _mm_unpackhi_epi64(r2, r3); - r89 = _mm_unpackhi_epi64(r4, r5); - } while (--count); - - r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); - r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); - r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); - r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); - r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); - - _mm_store_si128((xmmi*)r + 0, r0123); - _mm_store_si128((xmmi*)r + 1, r4567); - _mm_store_si128((xmmi*)r + 2, r89); -} - -DONNA_INLINE static void -curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { - xmmi x0,x1,x2,z0,z1,z2; - - x0 = _mm_load_si128((xmmi *)(x + 0)); - x1 = _mm_load_si128((xmmi *)(x + 4)); - x2 = _mm_load_si128((xmmi *)(x + 8)); - z0 = _mm_load_si128((xmmi *)(z + 0)); - z1 = _mm_load_si128((xmmi *)(z + 4)); - z2 = _mm_load_si128((xmmi *)(z + 8)); - - out[0].v = _mm_unpacklo_epi32(x0, z0); - out[1].v = _mm_unpackhi_epi32(x0, z0); - out[2].v = _mm_unpacklo_epi32(x1, z1); - out[3].v = _mm_unpackhi_epi32(x1, z1); - out[4].v = _mm_unpacklo_epi32(x2, z2); -} - -DONNA_INLINE static void -curve25519_untangle32(bignum25519 x, bignum25519 z, const packedelem32 *in) { - xmmi t0,t1,t2,t3,t4,zero; - - t0 = _mm_shuffle_epi32(in[0].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(in[1].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(in[2].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(in[3].v, _MM_SHUFFLE(3,1,2,0)); - t4 = _mm_shuffle_epi32(in[4].v, _MM_SHUFFLE(3,1,2,0)); - zero = _mm_setzero_si128(); - _mm_store_si128((xmmi *)x + 0, _mm_unpacklo_epi64(t0, t1)); - _mm_store_si128((xmmi *)x + 1, _mm_unpacklo_epi64(t2, t3)); - _mm_store_si128((xmmi *)x + 2, _mm_unpacklo_epi64(t4, zero)); - _mm_store_si128((xmmi *)z + 0, _mm_unpackhi_epi64(t0, t1)); - _mm_store_si128((xmmi *)z + 1, _mm_unpackhi_epi64(t2, t3)); - _mm_store_si128((xmmi *)z + 2, _mm_unpackhi_epi64(t4, zero)); -} - -DONNA_INLINE static void -curve25519_add_reduce_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3,s4,s5; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, s[0].v); - r1 = _mm_add_epi32(r[1].v, s[1].v); - r2 = _mm_add_epi32(r[2].v, s[2].v); - r3 = _mm_add_epi32(r[3].v, s[3].v); - r4 = _mm_add_epi32(r[4].v, s[4].v); - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ - s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); - c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); - c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ -} - -DONNA_INLINE static void -curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - out[0].v = _mm_add_epi32(r[0].v, s[0].v); - out[1].v = _mm_add_epi32(r[1].v, s[1].v); - out[2].v = _mm_add_epi32(r[2].v, s[2].v); - out[3].v = _mm_add_epi32(r[3].v, s[3].v); - out[4].v = _mm_add_epi32(r[4].v, s[4].v); -} - -DONNA_INLINE static void -curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, packed32packed2p0.v); - r1 = _mm_add_epi32(r[1].v, packed32packed2p1.v); - r2 = _mm_add_epi32(r[2].v, packed32packed2p1.v); - r3 = _mm_add_epi32(r[3].v, packed32packed2p1.v); - r4 = _mm_add_epi32(r[4].v, packed32packed2p1.v); - r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ - r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ - r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ - r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ - r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = r4; -} - -DONNA_INLINE static void -curve25519_sub_after_basic_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3,s4,s5; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, packed32packed4p0.v); - r1 = _mm_add_epi32(r[1].v, packed32packed4p1.v); - r2 = _mm_add_epi32(r[2].v, packed32packed4p1.v); - r3 = _mm_add_epi32(r[3].v, packed32packed4p1.v); - r4 = _mm_add_epi32(r[4].v, packed32packed4p1.v); - r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ - r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ - r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ - r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ - r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ - s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); - c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); - c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ -} - -DONNA_INLINE static void -curve25519_tangle64_from32(packedelem64 *a, packedelem64 *b, const packedelem32 *c, const packedelem32 *d) { - xmmi c0,c1,c2,c3,c4,c5,t; - xmmi d0,d1,d2,d3,d4,d5; - xmmi t0,t1,t2,t3,t4,zero; - - t0 = _mm_shuffle_epi32(c[0].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(c[1].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(d[0].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(d[1].v, _MM_SHUFFLE(3,1,2,0)); - c0 = _mm_unpacklo_epi64(t0, t1); - c3 = _mm_unpackhi_epi64(t0, t1); - d0 = _mm_unpacklo_epi64(t2, t3); - d3 = _mm_unpackhi_epi64(t2, t3); - t = _mm_unpacklo_epi64(c0, d0); a[0].v = t; a[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c0, d0); a[2].v = t; a[3].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c3, d3); b[0].v = t; b[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c3, d3); b[2].v = t; b[3].v = _mm_srli_epi64(t, 32); - - t0 = _mm_shuffle_epi32(c[2].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(c[3].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(d[2].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(d[3].v, _MM_SHUFFLE(3,1,2,0)); - c1 = _mm_unpacklo_epi64(t0, t1); - c4 = _mm_unpackhi_epi64(t0, t1); - d1 = _mm_unpacklo_epi64(t2, t3); - d4 = _mm_unpackhi_epi64(t2, t3); - t = _mm_unpacklo_epi64(c1, d1); a[4].v = t; a[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c1, d1); a[6].v = t; a[7].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c4, d4); b[4].v = t; b[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c4, d4); b[6].v = t; b[7].v = _mm_srli_epi64(t, 32); - - t4 = _mm_shuffle_epi32(c[4].v, _MM_SHUFFLE(3,1,2,0)); - zero = _mm_setzero_si128(); - c2 = _mm_unpacklo_epi64(t4, zero); - c5 = _mm_unpackhi_epi64(t4, zero); - t4 = _mm_shuffle_epi32(d[4].v, _MM_SHUFFLE(3,1,2,0)); - d2 = _mm_unpacklo_epi64(t4, zero); - d5 = _mm_unpackhi_epi64(t4, zero); - t = _mm_unpacklo_epi64(c2, d2); a[8].v = t; a[9].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c5, d5); b[8].v = t; b[9].v = _mm_srli_epi64(t, 32); -} - -DONNA_INLINE static void -curve25519_tangle64(packedelem64 *out, const bignum25519 x, const bignum25519 z) { - xmmi x0,x1,x2,z0,z1,z2,t; - - x0 = _mm_load_si128((xmmi *)x + 0); - x1 = _mm_load_si128((xmmi *)x + 1); - x2 = _mm_load_si128((xmmi *)x + 2); - z0 = _mm_load_si128((xmmi *)z + 0); - z1 = _mm_load_si128((xmmi *)z + 1); - z2 = _mm_load_si128((xmmi *)z + 2); - - t = _mm_unpacklo_epi64(x0, z0); out[0].v = t; out[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(x0, z0); out[2].v = t; out[3].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(x1, z1); out[4].v = t; out[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(x1, z1); out[6].v = t; out[7].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(x2, z2); out[8].v = t; out[9].v = _mm_srli_epi64(t, 32); -} - -DONNA_INLINE static void -curve25519_tangleone64(packedelem64 *out, const bignum25519 x) { - xmmi x0,x1,x2; - - x0 = _mm_load_si128((xmmi *)(x + 0)); - x1 = _mm_load_si128((xmmi *)(x + 4)); - x2 = _mm_load_si128((xmmi *)(x + 8)); - - out[0].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(0,0,0,0)); - out[1].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(1,1,1,1)); - out[2].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(2,2,2,2)); - out[3].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(3,3,3,3)); - out[4].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0,0,0,0)); - out[5].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(1,1,1,1)); - out[6].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2,2,2,2)); - out[7].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(3,3,3,3)); - out[8].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(0,0,0,0)); - out[9].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1,1,1,1)); -} - -DONNA_INLINE static void -curve25519_swap64(packedelem64 *out) { - out[0].v = _mm_shuffle_epi32(out[0].v, _MM_SHUFFLE(1,0,3,2)); - out[1].v = _mm_shuffle_epi32(out[1].v, _MM_SHUFFLE(1,0,3,2)); - out[2].v = _mm_shuffle_epi32(out[2].v, _MM_SHUFFLE(1,0,3,2)); - out[3].v = _mm_shuffle_epi32(out[3].v, _MM_SHUFFLE(1,0,3,2)); - out[4].v = _mm_shuffle_epi32(out[4].v, _MM_SHUFFLE(1,0,3,2)); - out[5].v = _mm_shuffle_epi32(out[5].v, _MM_SHUFFLE(1,0,3,2)); - out[6].v = _mm_shuffle_epi32(out[6].v, _MM_SHUFFLE(1,0,3,2)); - out[7].v = _mm_shuffle_epi32(out[7].v, _MM_SHUFFLE(1,0,3,2)); - out[8].v = _mm_shuffle_epi32(out[8].v, _MM_SHUFFLE(1,0,3,2)); - out[9].v = _mm_shuffle_epi32(out[9].v, _MM_SHUFFLE(1,0,3,2)); -} - -DONNA_INLINE static void -curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { - _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); - _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); -} - -DONNA_INLINE static void -curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { - xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r1_2,r3_2,r5_2,r7_2,r9_2; - xmmi c1,c2; - - out[0].v = _mm_mul_epu32(r[0].v, s[0].v); - out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); - r1_2 = _mm_slli_epi32(r[1].v, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); - out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); - r3_2 = _mm_slli_epi32(r[3].v, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); - out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); - - r1 = _mm_mul_epu32(r[1].v, packednineteen.v); - r2 = _mm_mul_epu32(r[2].v, packednineteen.v); - r1_2 = _mm_slli_epi32(r1, 1); - r3 = _mm_mul_epu32(r[3].v, packednineteen.v); - r4 = _mm_mul_epu32(r[4].v, packednineteen.v); - r3_2 = _mm_slli_epi32(r3, 1); - r5 = _mm_mul_epu32(r[5].v, packednineteen.v); - r6 = _mm_mul_epu32(r[6].v, packednineteen.v); - r5_2 = _mm_slli_epi32(r5, 1); - r7 = _mm_mul_epu32(r[7].v, packednineteen.v); - r8 = _mm_mul_epu32(r[8].v, packednineteen.v); - r7_2 = _mm_slli_epi32(r7, 1); - r9 = _mm_mul_epu32(r[9].v, packednineteen.v); - r9_2 = _mm_slli_epi32(r9, 1); - - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); - out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - -DONNA_INLINE static void -curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { - xmmi r0,r1,r2,r3; - xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; - xmmi d5,d6,d7,d8,d9; - xmmi c1,c2; - - r0 = r[0].v; - r1 = r[1].v; - r2 = r[2].v; - r3 = r[3].v; - - out[0].v = _mm_mul_epu32(r0, r0); - r0 = _mm_slli_epi32(r0, 1); - out[1].v = _mm_mul_epu32(r0, r1); - r1_2 = _mm_slli_epi32(r1, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); - r1 = r1_2; - out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); - r3_2 = _mm_slli_epi32(r3, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); - r2 = _mm_slli_epi32(r2, 1); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); - r3 = r3_2; - out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); - - d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); - d6 = _mm_mul_epu32(r[6].v, packednineteen.v); - d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); - d8 = _mm_mul_epu32(r[8].v, packednineteen.v); - d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); - - r4_2 = _mm_slli_epi32(r[4].v, 1); - r6_2 = _mm_slli_epi32(r[6].v, 1); - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); - out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - - out[0] = ( x0 ) & 0x3ffffff; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; - out[4] = (( x3) >> 6) & 0x3ffffff; - out[5] = ( x4 ) & 0x1ffffff; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; - out[9] = (( x7) >> 6) & 0x1ffffff; - out[10] = 0; - out[11] = 0; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 ALIGN(16) f; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= 0x3ffffff; \ - f[2] += f[1] >> 25; f[1] &= 0x1ffffff; \ - f[3] += f[2] >> 26; f[2] &= 0x3ffffff; \ - f[4] += f[3] >> 25; f[3] &= 0x1ffffff; \ - f[5] += f[4] >> 26; f[4] &= 0x3ffffff; \ - f[6] += f[5] >> 25; f[5] &= 0x1ffffff; \ - f[7] += f[6] >> 26; f[6] &= 0x3ffffff; \ - f[8] += f[7] >> 25; f[7] &= 0x1ffffff; \ - f[9] += f[8] >> 26; f[8] &= 0x3ffffff; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= 0x1ffffff; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= 0x1ffffff; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (1 << 26) - 19; - f[1] += (1 << 25) - 1; - f[2] += (1 << 26) - 1; - f[3] += (1 << 25) - 1; - f[4] += (1 << 26) - 1; - f[5] += (1 << 25) - 1; - f[6] += (1 << 26) - 1; - f[7] += (1 << 25) - 1; - f[8] += (1 << 26) - 1; - f[9] += (1 << 25) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} - -/* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; - xmmi mask = _mm_cvtsi32_si128(swap); - mask = _mm_shuffle_epi32(mask, 0); - a0 = _mm_load_si128((xmmi *)a + 0); - a1 = _mm_load_si128((xmmi *)a + 1); - b0 = _mm_load_si128((xmmi *)b + 0); - b1 = _mm_load_si128((xmmi *)b + 1); - b0 = _mm_xor_si128(a0, b0); - b1 = _mm_xor_si128(a1, b1); - x0 = _mm_and_si128(b0, mask); - x1 = _mm_and_si128(b1, mask); - x0 = _mm_xor_si128(x0, a0); - x1 = _mm_xor_si128(x1, a1); - a0 = _mm_xor_si128(x0, b0); - a1 = _mm_xor_si128(x1, b1); - _mm_store_si128((xmmi *)a + 0, x0); - _mm_store_si128((xmmi *)a + 1, x1); - _mm_store_si128((xmmi *)b + 0, a0); - _mm_store_si128((xmmi *)b + 1, a1); - - a2 = _mm_load_si128((xmmi *)a + 2); - b2 = _mm_load_si128((xmmi *)b + 2); - b2 = _mm_xor_si128(a2, b2); - x2 = _mm_and_si128(b2, mask); - x2 = _mm_xor_si128(x2, a2); - a2 = _mm_xor_si128(x2, b2); - _mm_store_si128((xmmi *)b + 2, a2); - _mm_store_si128((xmmi *)a + 2, x2); -} - -/* out = (flag) ? out : in */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { - xmmi a0,a1,a2,a3,a4,a5,b0,b1,b2,b3,b4,b5; - const uint32_t nb = flag - 1; - xmmi masknb = _mm_shuffle_epi32(_mm_cvtsi32_si128(nb),0); - a0 = _mm_load_si128((xmmi *)in + 0); - a1 = _mm_load_si128((xmmi *)in + 1); - a2 = _mm_load_si128((xmmi *)in + 2); - b0 = _mm_load_si128((xmmi *)out + 0); - b1 = _mm_load_si128((xmmi *)out + 1); - b2 = _mm_load_si128((xmmi *)out + 2); - a0 = _mm_andnot_si128(masknb, a0); - a1 = _mm_andnot_si128(masknb, a1); - a2 = _mm_andnot_si128(masknb, a2); - b0 = _mm_and_si128(masknb, b0); - b1 = _mm_and_si128(masknb, b1); - b2 = _mm_and_si128(masknb, b2); - a0 = _mm_or_si128(a0, b0); - a1 = _mm_or_si128(a1, b1); - a2 = _mm_or_si128(a2, b2); - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); - - a3 = _mm_load_si128((xmmi *)in + 3); - a4 = _mm_load_si128((xmmi *)in + 4); - a5 = _mm_load_si128((xmmi *)in + 5); - b3 = _mm_load_si128((xmmi *)out + 3); - b4 = _mm_load_si128((xmmi *)out + 4); - b5 = _mm_load_si128((xmmi *)out + 5); - a3 = _mm_andnot_si128(masknb, a3); - a4 = _mm_andnot_si128(masknb, a4); - a5 = _mm_andnot_si128(masknb, a5); - b3 = _mm_and_si128(masknb, b3); - b4 = _mm_and_si128(masknb, b4); - b5 = _mm_and_si128(masknb, b5); - a3 = _mm_or_si128(a3, b3); - a4 = _mm_or_si128(a4, b4); - a5 = _mm_or_si128(a5, b5); - _mm_store_si128((xmmi*)out + 3, a3); - _mm_store_si128((xmmi*)out + 4, a4); - _mm_store_si128((xmmi*)out + 5, a5); -} - diff --git a/external/ed25519-donna/ed25519-donna-32bit-sse2.h b/external/ed25519-donna/ed25519-donna-32bit-sse2.h deleted file mode 100644 index db04a13d3f..0000000000 --- a/external/ed25519-donna/ed25519-donna-32bit-sse2.h +++ /dev/null @@ -1,513 +0,0 @@ -#if defined(ED25519_GCC_32BIT_SSE_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int32_t breg = (int32_t)b; - uint32_t sign = (uint32_t)breg >> 31; - uint32_t mask = ~(sign - 1); - uint32_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy */ - "movl %0, %%eax ;\n" - "movd %%eax, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - - /* 0 */ - "movl $0, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movl $1, %%ecx ;\n" - "movd %%ecx, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 1 */ - "movl $1, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 0(%1), %%xmm4 ;\n" - "movdqa 16(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 32(%1), %%xmm4 ;\n" - "movdqa 48(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 2 */ - "movl $2, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 96(%1), %%xmm4 ;\n" - "movdqa 112(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 128(%1), %%xmm4 ;\n" - "movdqa 144(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 3 */ - "movl $3, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 192(%1), %%xmm4 ;\n" - "movdqa 208(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 224(%1), %%xmm4 ;\n" - "movdqa 240(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 4 */ - "movl $4, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 288(%1), %%xmm4 ;\n" - "movdqa 304(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 320(%1), %%xmm4 ;\n" - "movdqa 336(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 5 */ - "movl $5, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 384(%1), %%xmm4 ;\n" - "movdqa 400(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 416(%1), %%xmm4 ;\n" - "movdqa 432(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 6 */ - "movl $6, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 480(%1), %%xmm4 ;\n" - "movdqa 496(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 512(%1), %%xmm4 ;\n" - "movdqa 528(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 7 */ - "movl $7, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 576(%1), %%xmm4 ;\n" - "movdqa 592(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 608(%1), %%xmm4 ;\n" - "movdqa 624(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 8 */ - "movl $8, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 672(%1), %%xmm4 ;\n" - "movdqa 688(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 704(%1), %%xmm4 ;\n" - "movdqa 720(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* conditional swap based on sign */ - "movl %3, %%ecx ;\n" - "movl %2, %%eax ;\n" - "xorl $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa %%xmm2, %%xmm4 ;\n" - "movdqa %%xmm3, %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "pxor %%xmm4, %%xmm0 ;\n" - "pxor %%xmm5, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - - /* store xaddy */ - "addl $48, %%eax ;\n" - "movdqa %%xmm2, %%xmm0 ;\n" - "movdqa %%xmm3, %%xmm1 ;\n" - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - - /* t2d */ - "movl %0, %%eax ;\n" - "movd %%eax, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - - /* 0 */ - "movl $0, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - - /* 1 */ - "movl $1, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 64(%1), %%xmm3 ;\n" - "movdqa 80(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 2 */ - "movl $2, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 160(%1), %%xmm3 ;\n" - "movdqa 176(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 3 */ - "movl $3, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 256(%1), %%xmm3 ;\n" - "movdqa 272(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 4 */ - "movl $4, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 352(%1), %%xmm3 ;\n" - "movdqa 368(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 5 */ - "movl $5, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 448(%1), %%xmm3 ;\n" - "movdqa 464(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 6 */ - "movl $6, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 544(%1), %%xmm3 ;\n" - "movdqa 560(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 7 */ - "movl $7, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 640(%1), %%xmm3 ;\n" - "movdqa 656(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 8 */ - "movl $8, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 736(%1), %%xmm3 ;\n" - "movdqa 752(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* store t2d */ - "movl %2, %%eax ;\n" - "addl $96, %%eax ;\n" - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - "movdqa 0(%%eax), %%xmm0 ;\n" - "movdqa 16(%%eax), %%xmm1 ;\n" - "movdqa 32(%%eax), %%xmm2 ;\n" - - /* conditionally negate t2d */ - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movl $0x7fffffe, %%ecx ;\n" - "movd %%ecx, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store */ - "movdqa %%xmm0, 0(%%eax) ;\n" - "movdqa %%xmm1, 16(%%eax) ;\n" - "movdqa %%xmm2, 32(%%eax) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "m"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : "%eax", "%ecx", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_32BIT_SSE_CHOOSE) */ - diff --git a/external/ed25519-donna/ed25519-donna-32bit-tables.h b/external/ed25519-donna/ed25519-donna-32bit-tables.h deleted file mode 100644 index c977c26ebc..0000000000 --- a/external/ed25519-donna/ed25519-donna-32bit-tables.h +++ /dev/null @@ -1,61 +0,0 @@ -static const ge25519 ALIGN(16) ge25519_basepoint = { - {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, - {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, - {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, - {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} -}; - -/* - d -*/ - -static const bignum25519 ALIGN(16) ge25519_ecd = { - 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 -}; - -static const bignum25519 ALIGN(16) ge25519_ec2d = { - 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 -}; - -/* - sqrt(-1) -*/ - -static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { - 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 -}; - -static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { - {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, - {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, - {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, - {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, - {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, - {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, - {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, - {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, - {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, - {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, - {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, - {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, - {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, - {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, - {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, - {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, - {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, - {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, - {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, - {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, - {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, - {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, - {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, - {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, - {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, - {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, - {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, - {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, - {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, - {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, - {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, - {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} -}; diff --git a/external/ed25519-donna/ed25519-donna-64bit-sse2.h b/external/ed25519-donna/ed25519-donna-64bit-sse2.h deleted file mode 100644 index ca08651d67..0000000000 --- a/external/ed25519-donna/ed25519-donna-64bit-sse2.h +++ /dev/null @@ -1,436 +0,0 @@ -#if defined(ED25519_GCC_64BIT_SSE_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 0(%2) ;\n" - "movl %%r9d, 4(%2) ;\n" - "movl %%r8d, 8(%2) ;\n" - "movl %%r10d, 12(%2) ;\n" - "movl %%edx, 16(%2) ;\n" - "movl %%r11d, 20(%2) ;\n" - "movl %%esi, 24(%2) ;\n" - "movl %%r12d, 28(%2) ;\n" - "movl %%edi, 32(%2) ;\n" - "movl %%r13d, 36(%2) ;\n" - "movq %%rax, 40(%2) ;\n" - - /* store xaddy */ - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 48(%2) ;\n" - "movl %%r9d, 52(%2) ;\n" - "movl %%r8d, 56(%2) ;\n" - "movl %%r10d, 60(%2) ;\n" - "movl %%edx, 64(%2) ;\n" - "movl %%r11d, 68(%2) ;\n" - "movl %%esi, 72(%2) ;\n" - "movl %%r12d, 76(%2) ;\n" - "movl %%edi, 80(%2) ;\n" - "movl %%r13d, 84(%2) ;\n" - "movq %%rax, 88(%2) ;\n" - - /* extract t2d */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movd %%ecx, %%xmm0 ;\n" - "movd %%r9d, %%xmm4 ;\n" - "movd %%r8d, %%xmm8 ;\n" - "movd %%r10d, %%xmm3 ;\n" - "movd %%edx, %%xmm1 ;\n" - "movd %%r11d, %%xmm5 ;\n" - "movd %%esi, %%xmm6 ;\n" - "movd %%r12d, %%xmm7 ;\n" - "movd %%edi, %%xmm2 ;\n" - "movd %%r13d, %%xmm9 ;\n" - "punpckldq %%xmm4, %%xmm0 ;\n" - "punpckldq %%xmm3, %%xmm8 ;\n" - "punpckldq %%xmm5, %%xmm1 ;\n" - "punpckldq %%xmm7, %%xmm6 ;\n" - "punpckldq %%xmm9, %%xmm2 ;\n" - "punpcklqdq %%xmm8, %%xmm0 ;\n" - "punpcklqdq %%xmm6, %%xmm1 ;\n" - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movl $0x7fffffe, %%eax ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movd %%eax, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store t2d */ - "movdqa %%xmm0, 96(%2) ;\n" - "movdqa %%xmm1, 112(%2) ;\n" - "movdqa %%xmm2, 128(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_SSE_CHOOSE) */ - diff --git a/external/ed25519-donna/ed25519-donna-64bit-tables.h b/external/ed25519-donna/ed25519-donna-64bit-tables.h deleted file mode 100644 index 4a6ff9edae..0000000000 --- a/external/ed25519-donna/ed25519-donna-64bit-tables.h +++ /dev/null @@ -1,53 +0,0 @@ -static const ge25519 ge25519_basepoint = { - {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, - {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, - {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, - {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} -}; - -static const bignum25519 ge25519_ecd = { - 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff -}; - -static const bignum25519 ge25519_ec2d = { - 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff -}; - -static const bignum25519 ge25519_sqrtneg1 = { - 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d -}; - -static const ge25519_niels ge25519_niels_sliding_multiples[32] = { - {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, - {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, - {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, - {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}}, - {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}}, - {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}}, - {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}}, - {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}}, - {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}}, - {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}}, - {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}}, - {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}}, - {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}}, - {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}}, - {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}}, - {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}}, - {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}}, - {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}}, - {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}}, - {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}}, - {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}}, - {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}}, - {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}}, - {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}}, - {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}}, - {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}}, - {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}}, - {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}}, - {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}}, - {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}}, - {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}}, - {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}} -}; diff --git a/external/ed25519-donna/ed25519-donna-64bit-x86-32bit.h b/external/ed25519-donna/ed25519-donna-64bit-x86-32bit.h deleted file mode 100644 index 1ce109c5b7..0000000000 --- a/external/ed25519-donna/ed25519-donna-64bit-x86-32bit.h +++ /dev/null @@ -1,435 +0,0 @@ -#if defined(ED25519_GCC_64BIT_32BIT_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 0(%2) ;\n" - "movl %%r9d, 4(%2) ;\n" - "movl %%r8d, 8(%2) ;\n" - "movl %%r10d, 12(%2) ;\n" - "movl %%edx, 16(%2) ;\n" - "movl %%r11d, 20(%2) ;\n" - "movl %%esi, 24(%2) ;\n" - "movl %%r12d, 28(%2) ;\n" - "movl %%edi, 32(%2) ;\n" - "movl %%r13d, 36(%2) ;\n" - - /* store xaddy */ - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 40(%2) ;\n" - "movl %%r9d, 44(%2) ;\n" - "movl %%r8d, 48(%2) ;\n" - "movl %%r10d, 52(%2) ;\n" - "movl %%edx, 56(%2) ;\n" - "movl %%r11d, 60(%2) ;\n" - "movl %%esi, 64(%2) ;\n" - "movl %%r12d, 68(%2) ;\n" - "movl %%edi, 72(%2) ;\n" - "movl %%r13d, 76(%2) ;\n" - - /* extract t2d */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movd %%ecx, %%xmm0 ;\n" - "movd %%r9d, %%xmm4 ;\n" - "movd %%r8d, %%xmm8 ;\n" - "movd %%r10d, %%xmm3 ;\n" - "movd %%edx, %%xmm1 ;\n" - "movd %%r11d, %%xmm5 ;\n" - "movd %%esi, %%xmm6 ;\n" - "movd %%r12d, %%xmm7 ;\n" - "movd %%edi, %%xmm2 ;\n" - "movd %%r13d, %%xmm9 ;\n" - "punpckldq %%xmm4, %%xmm0 ;\n" - "punpckldq %%xmm3, %%xmm8 ;\n" - "punpckldq %%xmm5, %%xmm1 ;\n" - "punpckldq %%xmm7, %%xmm6 ;\n" - "punpckldq %%xmm9, %%xmm2 ;\n" - "punpcklqdq %%xmm8, %%xmm0 ;\n" - "punpcklqdq %%xmm6, %%xmm1 ;\n" - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movl $0x7fffffe, %%eax ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movd %%eax, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store t2d */ - "movdqa %%xmm0, 80(%2) ;\n" - "movdqa %%xmm1, 96(%2) ;\n" - "movd %%xmm2, %%rax ;\n" - "movq %%rax, 112(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_32BIT_CHOOSE) */ - diff --git a/external/ed25519-donna/ed25519-donna-64bit-x86.h b/external/ed25519-donna/ed25519-donna-64bit-x86.h deleted file mode 100644 index 7c844ecda4..0000000000 --- a/external/ed25519-donna/ed25519-donna-64bit-x86.h +++ /dev/null @@ -1,357 +0,0 @@ -#if defined(ED25519_GCC_64BIT_X86_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -#if defined(__clang__) || defined (__GNUC__) -# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) -#else -# define ATTRIBUTE_NO_SANITIZE_ADDRESS -#endif - -ATTRIBUTE_NO_SANITIZE_ADDRESS DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - "movq %%rcx, 0(%2) ;\n" - "movq %%r8, 8(%2) ;\n" - "movq %%rdx, 16(%2) ;\n" - "movq %%rsi, 24(%2) ;\n" - "movq %%rdi, 32(%2) ;\n" - - /* store xaddy */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - "movq %%rcx, 40(%2) ;\n" - "movq %%r8, 48(%2) ;\n" - "movq %%rdx, 56(%2) ;\n" - "movq %%rsi, 64(%2) ;\n" - "movq %%rdi, 72(%2) ;\n" - - /* extract t2d */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - - /* conditionally negate t2d */ - "movq %3, %%rax ;\n" - "movq $0xfffffffffffda, %%r9 ;\n" - "movq $0xffffffffffffe, %%r10 ;\n" - "movq %%r10, %%r11 ;\n" - "movq %%r10, %%r12 ;\n" - "movq %%r10, %%r13 ;\n" - "subq %%rcx, %%r9 ;\n" - "subq %%r8, %%r10 ;\n" - "subq %%rdx, %%r11 ;\n" - "subq %%rsi, %%r12 ;\n" - "subq %%rdi, %%r13 ;\n" - "cmpq $1, %%rax ;\n" - "cmove %%r9, %%rcx ;\n" - "cmove %%r10, %%r8 ;\n" - "cmove %%r11, %%rdx ;\n" - "cmove %%r12, %%rsi ;\n" - "cmove %%r13, %%rdi ;\n" - - /* store t2d */ - "movq %%rcx, 80(%2) ;\n" - "movq %%r8, 88(%2) ;\n" - "movq %%rdx, 96(%2) ;\n" - "movq %%rsi, 104(%2) ;\n" - "movq %%rdi, 112(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_X86_CHOOSE) */ - diff --git a/external/ed25519-donna/ed25519-donna-basepoint-table.h b/external/ed25519-donna/ed25519-donna-basepoint-table.h deleted file mode 100644 index 41dcd526a2..0000000000 --- a/external/ed25519-donna/ed25519-donna-basepoint-table.h +++ /dev/null @@ -1,259 +0,0 @@ -/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ -static const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { - {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, - {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, - {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, - {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, - {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, - {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, - {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, - {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, - {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, - {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, - {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, - {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, - {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, - {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, - {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, - {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, - {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, - {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, - {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, - {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, - {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, - {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, - {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, - {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, - {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, - {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, - {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, - {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, - {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, - {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, - {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, - {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, - {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, - {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, - {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, - {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, - {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, - {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, - {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, - {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, - {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, - {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, - {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, - {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, - {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, - {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, - {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, - {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, - {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, - {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, - {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, - {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, - {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, - {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, - {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, - {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, - {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, - {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, - {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, - {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, - {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, - {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, - {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, - {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, - {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, - {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, - {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, - {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, - {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, - {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, - {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, - {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, - {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, - {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, - {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, - {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, - {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, - {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, - {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, - {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, - {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, - {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, - {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, - {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, - {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, - {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, - {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, - {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, - {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, - {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, - {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, - {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, - {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, - {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, - {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, - {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, - {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, - {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, - {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, - {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, - {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, - {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, - {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, - {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, - {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, - {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, - {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, - {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, - {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, - {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, - {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, - {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, - {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, - {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, - {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, - {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, - {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, - {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, - {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, - {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, - {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, - {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, - {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, - {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, - {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, - {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, - {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, - {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, - {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, - {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, - {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, - {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, - {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, - {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, - {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, - {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, - {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, - {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, - {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, - {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, - {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, - {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, - {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, - {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, - {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, - {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, - {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, - {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, - {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, - {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, - {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, - {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, - {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, - {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, - {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, - {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, - {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, - {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, - {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, - {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, - {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, - {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, - {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, - {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, - {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, - {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, - {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, - {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, - {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, - {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, - {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, - {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, - {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, - {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, - {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, - {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, - {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, - {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, - {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, - {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, - {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, - {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, - {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, - {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, - {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, - {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, - {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, - {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, - {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, - {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, - {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, - {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, - {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, - {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, - {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, - {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, - {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, - {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, - {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, - {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, - {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, - {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, - {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, - {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, - {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, - {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, - {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, - {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, - {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, - {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, - {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, - {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, - {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, - {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, - {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, - {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, - {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, - {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, - {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, - {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, - {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, - {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, - {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, - {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, - {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, - {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, - {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, - {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, - {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, - {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, - {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, - {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, - {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, - {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, - {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, - {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, - {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, - {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, - {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, - {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, - {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, - {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, - {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, - {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, - {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, - {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, - {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, - {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, - {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, - {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, - {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, - {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, - {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, - {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, - {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, - {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} -}; diff --git a/external/ed25519-donna/ed25519-donna-batchverify.h b/external/ed25519-donna/ed25519-donna-batchverify.h deleted file mode 100644 index 43c4923b3e..0000000000 --- a/external/ed25519-donna/ed25519-donna-batchverify.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - Ed25519 batch verification -*/ - -#define max_batch_size 64 -#define heap_batch_size ((max_batch_size * 2) + 1) - -/* which limb is the 128th bit in? */ -static const size_t limb128bits = (128 + bignum256modm_bits_per_limb - 1) / bignum256modm_bits_per_limb; - -typedef size_t heap_index_t; - -typedef struct batch_heap_t { - unsigned char r[heap_batch_size][16]; /* 128 bit random values */ - ge25519 points[heap_batch_size]; - bignum256modm scalars[heap_batch_size]; - heap_index_t heap[heap_batch_size]; - size_t size; -} batch_heap; - -/* swap two values in the heap */ -static void -heap_swap(heap_index_t *heap, size_t a, size_t b) { - heap_index_t temp; - temp = heap[a]; - heap[a] = heap[b]; - heap[b] = temp; -} - -/* add the scalar at the end of the list to the heap */ -static void -heap_insert_next(batch_heap *heap) { - size_t node = heap->size, parent; - heap_index_t *pheap = heap->heap; - bignum256modm *scalars = heap->scalars; - - /* insert at the bottom */ - pheap[node] = (heap_index_t)node; - - /* sift node up to its sorted spot */ - parent = (node - 1) / 2; - while (node && lt256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], bignum256modm_limb_size - 1)) { - heap_swap(pheap, parent, node); - node = parent; - parent = (node - 1) / 2; - } - heap->size++; -} - -/* update the heap when the root element is updated */ -static void -heap_updated_root(batch_heap *heap, size_t limbsize) { - size_t node, parent, childr, childl; - heap_index_t *pheap = heap->heap; - bignum256modm *scalars = heap->scalars; - - /* sift root to the bottom */ - parent = 0; - node = 1; - childl = 1; - childr = 2; - while ((childr < heap->size)) { - node = lt256_modm_batch(scalars[pheap[childl]], scalars[pheap[childr]], limbsize) ? childr : childl; - heap_swap(pheap, parent, node); - parent = node; - childl = (parent * 2) + 1; - childr = childl + 1; - } - - /* sift root back up to its sorted spot */ - parent = (node - 1) / 2; - while (node && lte256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], limbsize)) { - heap_swap(pheap, parent, node); - node = parent; - parent = (node - 1) / 2; - } -} - -/* build the heap with count elements, count must be >= 3 */ -static void -heap_build(batch_heap *heap, size_t count) { - heap->heap[0] = 0; - heap->size = 0; - while (heap->size < count) - heap_insert_next(heap); -} - -/* extend the heap to contain new_count elements */ -static void -heap_extend(batch_heap *heap, size_t new_count) { - while (heap->size < new_count) - heap_insert_next(heap); -} - -/* get the top 2 elements of the heap */ -static void -heap_get_top2(batch_heap *heap, heap_index_t *max1, heap_index_t *max2, size_t limbsize) { - heap_index_t h0 = heap->heap[0], h1 = heap->heap[1], h2 = heap->heap[2]; - if (lt256_modm_batch(heap->scalars[h1], heap->scalars[h2], limbsize)) - h1 = h2; - *max1 = h0; - *max2 = h1; -} - -/* */ -static void -ge25519_multi_scalarmult_vartime_final(ge25519 *r, ge25519 *point, bignum256modm scalar) { - const bignum256modm_element_t topbit = ((bignum256modm_element_t)1 << (bignum256modm_bits_per_limb - 1)); - size_t limb = limb128bits; - bignum256modm_element_t flag; - - if (isone256_modm_batch(scalar)) { - /* this will happen most of the time after bos-carter */ - *r = *point; - return; - } else if (iszero256_modm_batch(scalar)) { - /* this will only happen if all scalars == 0 */ - memset(r, 0, sizeof(*r)); - r->y[0] = 1; - r->z[0] = 1; - return; - } - - *r = *point; - - /* find the limb where first bit is set */ - while (!scalar[limb]) - limb--; - - /* find the first bit */ - flag = topbit; - while ((scalar[limb] & flag) == 0) - flag >>= 1; - - /* exponentiate */ - for (;;) { - ge25519_double(r, r); - if (scalar[limb] & flag) - ge25519_add(r, r, point); - - flag >>= 1; - if (!flag) { - if (!limb--) - break; - flag = topbit; - } - } -} - -/* count must be >= 5 */ -static void -ge25519_multi_scalarmult_vartime(ge25519 *r, batch_heap *heap, size_t count) { - heap_index_t max1, max2; - - /* start with the full limb size */ - size_t limbsize = bignum256modm_limb_size - 1; - - /* whether the heap has been extended to include the 128 bit scalars */ - int extended = 0; - - /* grab an odd number of scalars to build the heap, unknown limb sizes */ - heap_build(heap, ((count + 1) / 2) | 1); - - for (;;) { - heap_get_top2(heap, &max1, &max2, limbsize); - - /* only one scalar remaining, we're done */ - if (iszero256_modm_batch(heap->scalars[max2])) - break; - - /* exhausted another limb? */ - if (!heap->scalars[max1][limbsize]) - limbsize -= 1; - - /* can we extend to the 128 bit scalars? */ - if (!extended && isatmost128bits256_modm_batch(heap->scalars[max1])) { - heap_extend(heap, count); - heap_get_top2(heap, &max1, &max2, limbsize); - extended = 1; - } - - sub256_modm_batch(heap->scalars[max1], heap->scalars[max1], heap->scalars[max2], limbsize); - ge25519_add(&heap->points[max2], &heap->points[max2], &heap->points[max1]); - heap_updated_root(heap, limbsize); - } - - ge25519_multi_scalarmult_vartime_final(r, &heap->points[max1], heap->scalars[max1]); -} - -/* not actually used for anything other than testing */ -unsigned char batch_point_buffer[3][32]; - -static int -ge25519_is_neutral_vartime(const ge25519 *p) { - static const unsigned char zero[32] = {0}; - unsigned char point_buffer[3][32]; - curve25519_contract(point_buffer[0], p->x); - curve25519_contract(point_buffer[1], p->y); - curve25519_contract(point_buffer[2], p->z); - memcpy(batch_point_buffer[1], point_buffer[1], 32); - return (memcmp(point_buffer[0], zero, 32) == 0) && (memcmp(point_buffer[1], point_buffer[2], 32) == 0); -} - -int -ED25519_FN(ed25519_sign_open_batch) (const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid) { - batch_heap ALIGN(16) batch; - ge25519 ALIGN(16) p; - bignum256modm *r_scalars; - size_t i, batchsize; - unsigned char hram[64]; - int ret = 0; - - for (i = 0; i < num; i++) - valid[i] = 1; - - while (num > 3) { - batchsize = (num > max_batch_size) ? max_batch_size : num; - - /* generate r (scalars[batchsize+1]..scalars[2*batchsize] */ - ED25519_FN(ed25519_randombytes_unsafe) (batch.r, batchsize * 16); - r_scalars = &batch.scalars[batchsize + 1]; - for (i = 0; i < batchsize; i++) - expand256_modm(r_scalars[i], batch.r[i], 16); - - /* compute scalars[0] = ((r1s1 + r2s2 + ...)) */ - for (i = 0; i < batchsize; i++) { - expand256_modm(batch.scalars[i], RS[i] + 32, 32); - mul256_modm(batch.scalars[i], batch.scalars[i], r_scalars[i]); - } - for (i = 1; i < batchsize; i++) - add256_modm(batch.scalars[0], batch.scalars[0], batch.scalars[i]); - - /* compute scalars[1]..scalars[batchsize] as r[i]*H(R[i],A[i],m[i]) */ - for (i = 0; i < batchsize; i++) { - ed25519_hram(hram, RS[i], pk[i], m[i], mlen[i]); - expand256_modm(batch.scalars[i+1], hram, 64); - mul256_modm(batch.scalars[i+1], batch.scalars[i+1], r_scalars[i]); - } - - /* compute points */ - batch.points[0] = ge25519_basepoint; - for (i = 0; i < batchsize; i++) - if (!ge25519_unpack_negative_vartime(&batch.points[i+1], pk[i])) - goto fallback; - for (i = 0; i < batchsize; i++) - if (!ge25519_unpack_negative_vartime(&batch.points[batchsize+i+1], RS[i])) - goto fallback; - - ge25519_multi_scalarmult_vartime(&p, &batch, (batchsize * 2) + 1); - if (!ge25519_is_neutral_vartime(&p)) { - ret |= 2; - - fallback: - for (i = 0; i < batchsize; i++) { - valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; - ret |= (valid[i] ^ 1); - } - } - - m += batchsize; - mlen += batchsize; - pk += batchsize; - RS += batchsize; - num -= batchsize; - valid += batchsize; - } - - for (i = 0; i < num; i++) { - valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; - ret |= (valid[i] ^ 1); - } - - return ret; -} - diff --git a/external/ed25519-donna/ed25519-donna-impl-base.h b/external/ed25519-donna/ed25519-donna-impl-base.h deleted file mode 100644 index 48913edcb4..0000000000 --- a/external/ed25519-donna/ed25519-donna-impl-base.h +++ /dev/null @@ -1,364 +0,0 @@ -/* - conversions -*/ - -DONNA_INLINE static void -ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); -} - -DONNA_INLINE static void -ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); - curve25519_mul(r->t, p->x, p->y); -} - -static void -ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { - curve25519_sub(p->ysubx, r->y, r->x); - curve25519_add(p->xaddy, r->y, r->x); - curve25519_copy(p->z, r->z); - curve25519_mul(p->t2d, r->t, ge25519_ec2d); -} - -/* - adding & doubling -*/ - -static void -ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { - bignum25519 a,b,c,d,t,u; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_sub(t, q->y, q->x); - curve25519_add(u, q->y, q->x); - curve25519_mul(a, a, t); - curve25519_mul(b, b, u); - curve25519_mul(c, p->t, q->t); - curve25519_mul(c, c, ge25519_ec2d); - curve25519_mul(d, p->z, q->z); - curve25519_add(d, d, d); - curve25519_sub(r->x, b, a); - curve25519_add(r->y, b, a); - curve25519_add_after_basic(r->z, d, c); - curve25519_sub_after_basic(r->t, d, c); -} - - -static void -ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { - bignum25519 a,b,c; - - curve25519_square(a, p->x); - curve25519_square(b, p->y); - curve25519_square(c, p->z); - curve25519_add_reduce(c, c, c); - curve25519_add(r->x, p->x, p->y); - curve25519_square(r->x, r->x); - curve25519_add(r->y, b, a); - curve25519_sub(r->z, b, a); - curve25519_sub_after_basic(r->x, r->x, r->y); - curve25519_sub_after_basic(r->t, c, r->z); -} - -static void -ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 a,b,c; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ - curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_add_reduce(r->t, p->z, p->z); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ - curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ -} - -static void -ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 a,b,c; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ - curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(r->t, p->z, q->z); - curve25519_add_reduce(r->t, r->t, r->t); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ - curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ -} - -static void -ge25519_double_partial(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_partial(r, &t); -} - -static void -ge25519_double(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_full(r, &t); -} - -static void -ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { - ge25519_p1p1 t; - ge25519_add_p1p1(&t, p, q); - ge25519_p1p1_to_full(r, &t); -} - -static void -ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { - bignum25519 a,b,c,e,f,g,h; - - curve25519_sub(a, r->y, r->x); - curve25519_add(b, r->y, r->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(e, b, q->xaddy); - curve25519_add(h, e, a); - curve25519_sub(e, e, a); - curve25519_mul(c, r->t, q->t2d); - curve25519_add(f, r->z, r->z); - curve25519_add_after_basic(g, f, c); - curve25519_sub_after_basic(f, f, c); - curve25519_mul(r->x, e, f); - curve25519_mul(r->y, h, g); - curve25519_mul(r->z, g, f); - curve25519_mul(r->t, e, h); -} - -static void -ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { - bignum25519 a,b,c,x,y,z,t; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(x, b, q->xaddy); - curve25519_add(y, x, a); - curve25519_sub(x, x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(t, p->z, q->z); - curve25519_add(t, t, t); - curve25519_add_after_basic(z, t, c); - curve25519_sub_after_basic(t, t, c); - curve25519_mul(r->xaddy, x, t); - curve25519_mul(r->ysubx, y, z); - curve25519_mul(r->z, z, t); - curve25519_mul(r->t2d, x, y); - curve25519_copy(y, r->ysubx); - curve25519_sub(r->ysubx, r->ysubx, r->xaddy); - curve25519_add(r->xaddy, r->xaddy, y); - curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); -} - - -/* - pack & unpack -*/ - -static void -ge25519_pack(unsigned char r[32], const ge25519 *p) { - bignum25519 tx, ty, zi; - unsigned char parity[32]; - curve25519_recip(zi, p->z); - curve25519_mul(tx, p->x, zi); - curve25519_mul(ty, p->y, zi); - curve25519_contract(r, ty); - curve25519_contract(parity, tx); - r[31] ^= ((parity[0] & 1) << 7); -} - -static int -ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { - static const unsigned char zero[32] = {0}; - static const bignum25519 one = {1}; - unsigned char parity = p[31] >> 7; - unsigned char check[32]; - bignum25519 t, root, num, den, d3; - - curve25519_expand(r->y, p); - curve25519_copy(r->z, one); - curve25519_square(num, r->y); /* x = y^2 */ - curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ - curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ - curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - curve25519_square(t, den); - curve25519_mul(d3, t, den); - curve25519_square(r->x, d3); - curve25519_mul(r->x, r->x, den); - curve25519_mul(r->x, r->x, num); - curve25519_pow_two252m3(r->x, r->x); - - /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ - curve25519_mul(r->x, r->x, d3); - curve25519_mul(r->x, r->x, num); - - /* 3. Check if either of the roots works: */ - curve25519_square(t, r->x); - curve25519_mul(t, t, den); - curve25519_sub_reduce(root, t, num); - curve25519_contract(check, root); - if (!ed25519_verify(check, zero, 32)) { - curve25519_add_reduce(t, t, num); - curve25519_contract(check, t); - if (!ed25519_verify(check, zero, 32)) - return 0; - curve25519_mul(r->x, r->x, ge25519_sqrtneg1); - } - - curve25519_contract(check, r->x); - if ((check[0] & 1) == parity) { - curve25519_copy(t, r->x); - curve25519_neg(r->x, t); - } - curve25519_mul(r->t, r->x, r->y); - return 1; -} - - -/* - scalarmults -*/ - -#define S1_SWINDOWSIZE 5 -#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) -#define S2_SWINDOWSIZE 7 -#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) - -/* computes [s1]p1 + [s2]basepoint */ -static void -ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { - signed char slide1[256], slide2[256]; - ge25519_pniels pre1[S1_TABLE_SIZE]; - ge25519 d1; - ge25519_p1p1 t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - - ge25519_double(&d1, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - - /* set neutral */ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } -} - - - -#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) - -static uint32_t -ge25519_windowb_equal(uint32_t b, uint32_t c) { - return ((b ^ c) - 1) >> 31; -} - -static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - bignum25519 neg; - uint32_t sign = (uint32_t)((unsigned char)b >> 7); - uint32_t mask = ~(sign - 1); - uint32_t u = (b + mask) ^ mask; - uint32_t i; - - /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ - uint8_t packed[96] = {0}; - packed[0] = 1; - packed[32] = 1; - - for (i = 0; i < 8; i++) - curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); - - /* expand in to t */ - curve25519_expand(t->ysubx, packed + 0); - curve25519_expand(t->xaddy, packed + 32); - curve25519_expand(t->t2d , packed + 64); - - /* adjust for sign */ - curve25519_swap_conditional(t->ysubx, t->xaddy, sign); - curve25519_neg(neg, t->t2d); - curve25519_swap_conditional(t->t2d, neg, sign); -} - -#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ - - -/* computes [s]basepoint */ -static void -ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { - signed char b[64]; - uint32_t i; - ge25519_niels t; - - contract256_window4_modm(b, s); - - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); - curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); - curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memset(r->z, 0, sizeof(bignum25519)); - curve25519_copy(r->t, t.t2d); - r->z[0] = 2; - for (i = 3; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double(r, r); - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); - curve25519_mul(t.t2d, t.t2d, ge25519_ecd); - ge25519_nielsadd2(r, &t); - for(i = 2; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } -} - diff --git a/external/ed25519-donna/ed25519-donna-impl-sse2.h b/external/ed25519-donna/ed25519-donna-impl-sse2.h deleted file mode 100644 index 5fe3416381..0000000000 --- a/external/ed25519-donna/ed25519-donna-impl-sse2.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - conversions -*/ - -static void -ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { - packed64bignum25519 ALIGN(16) xz, tt, xzout; - curve25519_mul(r->y, p->y, p->z); - curve25519_tangle64(xz, p->x, p->z); - curve25519_tangleone64(tt, p->t); - curve25519_mul_packed64(xzout, xz, tt); - curve25519_untangle64(r->x, r->z, xzout); -} - -static void -ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { - packed64bignum25519 ALIGN(16) zy, xt, xx, zz, ty; - curve25519_tangle64(ty, p->t, p->y); - curve25519_tangleone64(xx, p->x); - curve25519_mul_packed64(xt, xx, ty); - curve25519_untangle64(r->x, r->t, xt); - curve25519_tangleone64(zz, p->z); - curve25519_mul_packed64(zy, zz, ty); - curve25519_untangle64(r->z, r->y, zy); -} - -static void -ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { - curve25519_sub(p->ysubx, r->y, r->x); - curve25519_add(p->xaddy, r->x, r->y); - curve25519_copy(p->z, r->z); - curve25519_mul(p->t2d, r->t, ge25519_ec2d); -} - -/* - adding & doubling -*/ - -static void -ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { - bignum25519 ALIGN(16) a,b,c,d; - packed32bignum25519 ALIGN(16) xx, yy, yypxx, yymxx, bd, ac, bdmac, bdpac; - packed64bignum25519 ALIGN(16) at, bu, atbu, ptz, qtz, cd; - - curve25519_tangle32(yy, p->y, q->y); - curve25519_tangle32(xx, p->x, q->x); - curve25519_add_packed32(yypxx, yy, xx); - curve25519_sub_packed32(yymxx, yy, xx); - curve25519_tangle64_from32(at, bu, yymxx, yypxx); - curve25519_mul_packed64(atbu, at, bu); - curve25519_untangle64(a, b, atbu); - curve25519_tangle64(ptz, p->t, p->z); - curve25519_tangle64(qtz, q->t, q->z); - curve25519_mul_packed64(cd, ptz, qtz); - curve25519_untangle64(c, d, cd); - curve25519_mul(c, c, ge25519_ec2d); - curve25519_add_reduce(d, d, d); - /* reduce, so no after_basic is needed later */ - curve25519_tangle32(bd, b, d); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdmac, bd, ac); - curve25519_add_packed32(bdpac, bd, ac); - curve25519_untangle32(r->x, r->t, bdmac); - curve25519_untangle32(r->y, r->z, bdpac); -} - - -static void -ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { - bignum25519 ALIGN(16) a,b,c,x; - packed64bignum25519 ALIGN(16) xy, zx, ab, cx; - packed32bignum25519 ALIGN(16) xc, yz, xt, yc, ac, bc; - - curve25519_add(x, p->x, p->y); - curve25519_tangle64(xy, p->x, p->y); - curve25519_square_packed64(ab, xy); - curve25519_untangle64(a, b, ab); - curve25519_tangle64(zx, p->z, x); - curve25519_square_packed64(cx, zx); - curve25519_untangle64(c, x, cx); - curve25519_tangle32(bc, b, c); - curve25519_tangle32(ac, a, c); - curve25519_add_reduce_packed32(yc, bc, ac); - curve25519_untangle32(r->y, c, yc); - curve25519_sub(r->z, b, a); - curve25519_tangle32(yz, r->y, r->z); - curve25519_tangle32(xc, x, c); - curve25519_sub_after_basic_packed32(xt, xc, yz); - curve25519_untangle32(r->x, r->t, xt); -} - -static void -ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 ALIGN(16) a,b,c; - packed64bignum25519 ALIGN(16) ab, yx, aybx; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(r->y, b, a); - curve25519_add_reduce(r->t, p->z, p->z); - curve25519_mul(c, p->t, q->t2d); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); - curve25519_tangle32(bd, b, rb[2+(signbit^1)]); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); - curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); -} - -static void -ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 ALIGN(16) a,b,c; - packed64bignum25519 ALIGN(16) ab, yx, aybx, zt, zt2d, tc; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(r->y, b, a); - curve25519_tangle64(zt, p->z, p->t); - curve25519_tangle64(zt2d, q->z, q->t2d); - curve25519_mul_packed64(tc, zt, zt2d); - curve25519_untangle64(r->t, c, tc); - curve25519_add_reduce(r->t, r->t, r->t); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); - curve25519_tangle32(bd, b, rb[2+(signbit^1)]); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); - curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); -} - -static void -ge25519_double(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 ALIGN(16) t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_full(r, &t); -} - -static void -ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { - ge25519_p1p1 ALIGN(16) t; - ge25519_add_p1p1(&t, p, q); - ge25519_p1p1_to_full(r, &t); -} - -static void -ge25519_double_partial(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 ALIGN(16) t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_partial(r, &t); -} - -static void -ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { - packed64bignum25519 ALIGN(16) ab, yx, aybx, eg, ff, hh, xz, ty; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - bignum25519 ALIGN(16) a,b,c,d,e,f,g,h; - - curve25519_sub(a, r->y, r->x); - curve25519_add(b, r->y, r->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, q->ysubx, q->xaddy); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(h, b, a); - curve25519_add_reduce(d, r->z, r->z); - curve25519_mul(c, r->t, q->t2d); - curve25519_add(g, d, c); /* d is reduced, so no need for after_basic */ - curve25519_tangle32(bd, b, d); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); /* d is reduced, so no need for after_basic */ - curve25519_untangle32(e, f, bdac); - curve25519_tangle64(eg, e, g); - curve25519_tangleone64(ff, f); - curve25519_mul_packed64(xz, eg, ff); - curve25519_untangle64(r->x, r->z, xz); - curve25519_tangleone64(hh, h); - curve25519_mul_packed64(ty, eg, hh); - curve25519_untangle64(r->t, r->y, ty); -} - -static void -ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { - ge25519_p1p1 ALIGN(16) t; - ge25519 ALIGN(16) f; - ge25519_pnielsadd_p1p1(&t, p, q, 0); - ge25519_p1p1_to_full(&f, &t); - ge25519_full_to_pniels(r, &f); -} - -/* - pack & unpack -*/ - -static void -ge25519_pack(unsigned char r[32], const ge25519 *p) { - bignum25519 ALIGN(16) tx, ty, zi; - unsigned char parity[32]; - curve25519_recip(zi, p->z); - curve25519_mul(tx, p->x, zi); - curve25519_mul(ty, p->y, zi); - curve25519_contract(r, ty); - curve25519_contract(parity, tx); - r[31] ^= ((parity[0] & 1) << 7); -} - - -static int -ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { - static const bignum25519 ALIGN(16) one = {1}; - static const unsigned char zero[32] = {0}; - unsigned char parity = p[31] >> 7; - unsigned char check[32]; - bignum25519 ALIGN(16) t, root, num, den, d3; - - curve25519_expand(r->y, p); - curve25519_copy(r->z, one); - curve25519_square_times(num, r->y, 1); /* x = y^2 */ - curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ - curve25519_sub_reduce(num, num, r->z); /* x = y^2 - 1 */ - curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - curve25519_square_times(t, den, 1); - curve25519_mul(d3, t, den); - curve25519_square_times(r->x, d3, 1); - curve25519_mul(r->x, r->x, den); - curve25519_mul(r->x, r->x, num); - curve25519_pow_two252m3(r->x, r->x); - - /* 2. computation of r->x = t * num * den^3 */ - curve25519_mul(r->x, r->x, d3); - curve25519_mul(r->x, r->x, num); - - /* 3. Check if either of the roots works: */ - curve25519_square_times(t, r->x, 1); - curve25519_mul(t, t, den); - curve25519_copy(root, t); - curve25519_sub_reduce(root, root, num); - curve25519_contract(check, root); - if (!ed25519_verify(check, zero, 32)) { - curve25519_add_reduce(t, t, num); - curve25519_contract(check, t); - if (!ed25519_verify(check, zero, 32)) - return 0; - curve25519_mul(r->x, r->x, ge25519_sqrtneg1); - } - - curve25519_contract(check, r->x); - if ((check[0] & 1) == parity) { - curve25519_copy(t, r->x); - curve25519_neg(r->x, t); - } - curve25519_mul(r->t, r->x, r->y); - return 1; -} - - - -/* - scalarmults -*/ - -#define S1_SWINDOWSIZE 5 -#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) -#define S2_SWINDOWSIZE 7 -#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) - -static void -ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { - signed char slide1[256], slide2[256]; - ge25519_pniels ALIGN(16) pre1[S1_TABLE_SIZE]; - ge25519 ALIGN(16) d1; - ge25519_p1p1 ALIGN(16) t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - - ge25519_double(&d1, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - - /* set neutral */ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } -} - -#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) - -static uint32_t -ge25519_windowb_equal(uint32_t b, uint32_t c) { - return ((b ^ c) - 1) >> 31; -} - -static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - bignum25519 ALIGN(16) neg; - uint32_t sign = (uint32_t)((unsigned char)b >> 7); - uint32_t mask = ~(sign - 1); - uint32_t u = (b + mask) ^ mask; - uint32_t i; - - /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ - uint8_t ALIGN(16) packed[96] = {0}; - packed[0] = 1; - packed[32] = 1; - - for (i = 0; i < 8; i++) - curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); - - /* expand in to t */ - curve25519_expand(t->ysubx, packed + 0); - curve25519_expand(t->xaddy, packed + 32); - curve25519_expand(t->t2d , packed + 64); - - /* adjust for sign */ - curve25519_swap_conditional(t->ysubx, t->xaddy, sign); - curve25519_neg(neg, t->t2d); - curve25519_swap_conditional(t->t2d, neg, sign); -} - -#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ - -static void -ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t table[256][96], const bignum256modm s) { - signed char b[64]; - uint32_t i; - ge25519_niels ALIGN(16) t; - - contract256_window4_modm(b, s); - - ge25519_scalarmult_base_choose_niels(&t, table, 0, b[1]); - curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); - curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memset(r->z, 0, sizeof(bignum25519)); - r->z[0] = 2; - curve25519_copy(r->t, t.t2d); - for (i = 3; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double(r, r); - ge25519_scalarmult_base_choose_niels(&t, table, 0, b[0]); - curve25519_mul(t.t2d, t.t2d, ge25519_ecd); - ge25519_nielsadd2(r, &t); - for(i = 2; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } -} diff --git a/external/ed25519-donna/ed25519-donna-portable-identify.h b/external/ed25519-donna/ed25519-donna-portable-identify.h deleted file mode 100644 index 26a264cf9e..0000000000 --- a/external/ed25519-donna/ed25519-donna-portable-identify.h +++ /dev/null @@ -1,103 +0,0 @@ -/* os */ -#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__) - #define OS_WINDOWS -#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__) - #define OS_SOLARIS -#else - #include /* need this to define BSD */ - #define OS_NIX - #if defined(__linux__) - #define OS_LINUX - #elif defined(BSD) - #define OS_BSD - #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__)) - #define OS_OSX - #elif defined(macintosh) || defined(Macintosh) - #define OS_MAC - #elif defined(__OpenBSD__) - #define OS_OPENBSD - #endif - #endif -#endif - - -/* compiler */ -#if defined(_MSC_VER) - #define COMPILER_MSVC -#endif -#if defined(__ICC) - #define COMPILER_INTEL -#endif -#if defined(__GNUC__) - #if (__GNUC__ >= 3) - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) - #else - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) ) - #endif -#endif -#if defined(__PATHCC__) - #define COMPILER_PATHCC -#endif -#if defined(__clang__) - #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__)) -#endif - - - -/* cpu */ -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64) - #define CPU_X86_64 -#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) - #define CPU_X86 500 -#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) - #define CPU_X86 400 -#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) - #define CPU_X86 300 -#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64) - #define CPU_IA64 -#endif - -#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9) - #define CPU_SPARC - #if defined(__sparcv9) - #define CPU_SPARC64 - #endif -#endif - -#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC) - #define CPU_PPC - #if defined(_ARCH_PWR7) - #define CPU_POWER7 - #elif defined(__64BIT__) - #define CPU_PPC64 - #else - #define CPU_PPC32 - #endif -#endif - -#if defined(__hppa__) || defined(__hppa) - #define CPU_HPPA -#endif - -#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) - #define CPU_ALPHA -#endif - -/* 64 bit cpu */ -#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)) - #define CPU_64BITS -#endif - -#if defined(COMPILER_MSVC) - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef signed short int16_t; - typedef unsigned short uint16_t; - typedef signed int int32_t; - typedef unsigned int uint32_t; - typedef signed __int64 int64_t; - typedef unsigned __int64 uint64_t; -#else - #include -#endif - diff --git a/external/ed25519-donna/ed25519-donna-portable.h b/external/ed25519-donna/ed25519-donna-portable.h deleted file mode 100644 index aad1441a99..0000000000 --- a/external/ed25519-donna/ed25519-donna-portable.h +++ /dev/null @@ -1,136 +0,0 @@ -#include "ed25519-donna-portable-identify.h" - -#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) - -/* platform */ -#if defined(COMPILER_MSVC) - #include - #if !defined(_DEBUG) - #undef mul32x32_64 - #define mul32x32_64(a,b) __emulu(a,b) - #endif - #undef inline - #define inline __forceinline - #define DONNA_INLINE __forceinline - #define DONNA_NOINLINE __declspec(noinline) - #define ALIGN(x) __declspec(align(x)) - #define ROTL32(a,b) _rotl(a,b) - #define ROTR32(a,b) _rotr(a,b) -#else - #include - #define DONNA_INLINE inline __attribute__((always_inline)) - #define DONNA_NOINLINE __attribute__((noinline)) - #undef ALIGN - #define ALIGN(x) __attribute__((aligned(x))) - #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) - #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) -#endif - -/* uint128_t */ -#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT) - #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif defined(COMPILER_MSVC) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); - #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); - #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); - #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) - #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } - #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); } - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128) - #if defined(__SIZEOF_INT128__) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif (COMPILER_GCC >= 40400) - #define HAVE_NATIVE_UINT128 - typedef unsigned uint128_t __attribute__((mode(TI))); - #elif defined(CPU_X86_64) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); - #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; - #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; - #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) - #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); - #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #endif - #endif - - #if defined(HAVE_NATIVE_UINT128) - #define HAVE_UINT128 - #define mul64x64_128(out,a,b) out = (uint128_t)a * b; - #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift)); - #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64); - #define shr128(out,in,shift) out = (uint64_t)(in >> (shift)); - #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64); - #define add128(a,b) a += b; - #define add128_64(a,b) a += (uint64_t)b; - #define lo128(a) ((uint64_t)a) - #define hi128(a) ((uint64_t)(a >> 64)) - #endif - - #if !defined(HAVE_UINT128) - #error Need a uint128_t implementation! - #endif -#endif - -/* endian */ -#if !defined(ED25519_OPENSSLRNG) -static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { - p[0] = (unsigned char)(v ); - p[1] = (unsigned char)(v >> 8); - p[2] = (unsigned char)(v >> 16); - p[3] = (unsigned char)(v >> 24); -} -#endif - -#if !defined(HAVE_UINT128) -static inline uint32_t U8TO32_LE(const unsigned char *p) { - return - (((uint32_t)(p[0]) ) | - ((uint32_t)(p[1]) << 8) | - ((uint32_t)(p[2]) << 16) | - ((uint32_t)(p[3]) << 24)); -} -#else -static inline uint64_t U8TO64_LE(const unsigned char *p) { - return - (((uint64_t)(p[0]) ) | - ((uint64_t)(p[1]) << 8) | - ((uint64_t)(p[2]) << 16) | - ((uint64_t)(p[3]) << 24) | - ((uint64_t)(p[4]) << 32) | - ((uint64_t)(p[5]) << 40) | - ((uint64_t)(p[6]) << 48) | - ((uint64_t)(p[7]) << 56)); -} - -static inline void U64TO8_LE(unsigned char *p, const uint64_t v) { - p[0] = (unsigned char)(v ); - p[1] = (unsigned char)(v >> 8); - p[2] = (unsigned char)(v >> 16); - p[3] = (unsigned char)(v >> 24); - p[4] = (unsigned char)(v >> 32); - p[5] = (unsigned char)(v >> 40); - p[6] = (unsigned char)(v >> 48); - p[7] = (unsigned char)(v >> 56); -} -#endif - -#include -#include - - diff --git a/external/ed25519-donna/ed25519-donna.h b/external/ed25519-donna/ed25519-donna.h deleted file mode 100644 index de1120f46f..0000000000 --- a/external/ed25519-donna/ed25519-donna.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - Public domain by Andrew M. - Modified from the amd64-51-30k implementation by - Daniel J. Bernstein - Niels Duif - Tanja Lange - Peter Schwabe - Bo-Yin Yang -*/ - - -#include "ed25519-donna-portable.h" - -#if defined(ED25519_SSE2) -#else - #if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) - #define ED25519_64BIT - #else - #define ED25519_32BIT - #endif -#endif - -#if !defined(ED25519_NO_INLINE_ASM) - /* detect extra features first so un-needed functions can be disabled throughout */ - #if defined(ED25519_SSE2) - #if defined(COMPILER_GCC) && defined(CPU_X86) - #define ED25519_GCC_32BIT_SSE_CHOOSE - #elif defined(COMPILER_GCC) && defined(CPU_X86_64) - #define ED25519_GCC_64BIT_SSE_CHOOSE - #endif - #else - #if defined(CPU_X86_64) - #if defined(COMPILER_GCC) - #if defined(ED25519_64BIT) - #define ED25519_GCC_64BIT_X86_CHOOSE - #else - #define ED25519_GCC_64BIT_32BIT_CHOOSE - #endif - #endif - #endif - #endif -#endif - -#if defined(ED25519_SSE2) - #include "curve25519-donna-sse2.h" -#elif defined(ED25519_64BIT) - #include "curve25519-donna-64bit.h" -#else - #include "curve25519-donna-32bit.h" -#endif - -#include "curve25519-donna-helpers.h" - -/* separate uint128 check for 64 bit sse2 */ -#if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) - #include "modm-donna-64bit.h" -#else - #include "modm-donna-32bit.h" -#endif - -typedef unsigned char hash_512bits[64]; - -/* - Timing safe memory compare -*/ -static int -ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { - size_t differentbits = 0; - while (len--) - differentbits |= (*x++ ^ *y++); - return (int) (1 & ((differentbits - 1) >> 8)); -} - - -/* - * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 - * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 - * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); - */ - -typedef struct ge25519_t { - bignum25519 x, y, z, t; -} ge25519; - -typedef struct ge25519_p1p1_t { - bignum25519 x, y, z, t; -} ge25519_p1p1; - -typedef struct ge25519_niels_t { - bignum25519 ysubx, xaddy, t2d; -} ge25519_niels; - -typedef struct ge25519_pniels_t { - bignum25519 ysubx, xaddy, z, t2d; -} ge25519_pniels; - -#include "ed25519-donna-basepoint-table.h" - -#if defined(ED25519_64BIT) - #include "ed25519-donna-64bit-tables.h" - #include "ed25519-donna-64bit-x86.h" -#else - #include "ed25519-donna-32bit-tables.h" - #include "ed25519-donna-64bit-x86-32bit.h" -#endif - - -#if defined(ED25519_SSE2) - #include "ed25519-donna-32bit-sse2.h" - #include "ed25519-donna-64bit-sse2.h" - #include "ed25519-donna-impl-sse2.h" -#else - #include "ed25519-donna-impl-base.h" -#endif - diff --git a/external/ed25519-donna/ed25519-hash-custom.h b/external/ed25519-donna/ed25519-hash-custom.h deleted file mode 100644 index 7dc249129d..0000000000 --- a/external/ed25519-donna/ed25519-hash-custom.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - a custom hash must have a 512bit digest and implement: - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); -*/ - diff --git a/external/ed25519-donna/ed25519-hash.h b/external/ed25519-donna/ed25519-hash.h deleted file mode 100644 index 6ba8f52383..0000000000 --- a/external/ed25519-donna/ed25519-hash.h +++ /dev/null @@ -1,219 +0,0 @@ -#if defined(ED25519_REFHASH) - -/* reference/slow SHA-512. really, do not use this */ - -#define HASH_BLOCK_SIZE 128 -#define HASH_DIGEST_SIZE 64 - -typedef struct sha512_state_t { - uint64_t H[8]; - uint64_t T[2]; - uint32_t leftover; - uint8_t buffer[HASH_BLOCK_SIZE]; -} sha512_state; - -typedef sha512_state ed25519_hash_context; - -static const uint64_t sha512_constants[80] = { - 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, - 0x3956c25bf348b538ull, 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, - 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, - 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 0xc19bf174cf692694ull, - 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, - 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, - 0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, - 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 0x06ca6351e003826full, 0x142929670a0e6e70ull, - 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull, - 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, - 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, - 0xd192e819d6ef5218ull, 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, - 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, - 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, - 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, - 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, - 0xca273eceea26619cull, 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, - 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull, - 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull, - 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull -}; - -static uint64_t -sha512_ROTR64(uint64_t x, int k) { - return (x >> k) | (x << (64 - k)); -} - -static uint64_t -sha512_LOAD64_BE(const uint8_t *p) { - return - ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - ((uint64_t)p[7] ); -} - -static void -sha512_STORE64_BE(uint8_t *p, uint64_t v) { - p[0] = (uint8_t)(v >> 56); - p[1] = (uint8_t)(v >> 48); - p[2] = (uint8_t)(v >> 40); - p[3] = (uint8_t)(v >> 32); - p[4] = (uint8_t)(v >> 24); - p[5] = (uint8_t)(v >> 16); - p[6] = (uint8_t)(v >> 8); - p[7] = (uint8_t)(v ); -} - -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S0(x) (sha512_ROTR64(x, 28) ^ sha512_ROTR64(x, 34) ^ sha512_ROTR64(x, 39)) -#define S1(x) (sha512_ROTR64(x, 14) ^ sha512_ROTR64(x, 18) ^ sha512_ROTR64(x, 41)) -#define G0(x) (sha512_ROTR64(x, 1) ^ sha512_ROTR64(x, 8) ^ (x >> 7)) -#define G1(x) (sha512_ROTR64(x, 19) ^ sha512_ROTR64(x, 61) ^ (x >> 6)) -#define W0(in,i) (sha512_LOAD64_BE(&in[i * 8])) -#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) -#define STEP(i) \ - t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ - t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha512_constants[i] + w[i]; \ - r[7] = r[6]; \ - r[6] = r[5]; \ - r[5] = r[4]; \ - r[4] = r[3] + t0; \ - r[3] = r[2]; \ - r[2] = r[1]; \ - r[1] = r[0]; \ - r[0] = t0 + t1; - -static void -sha512_blocks(sha512_state *S, const uint8_t *in, size_t blocks) { - uint64_t r[8], w[80], t0, t1; - size_t i; - - for (i = 0; i < 8; i++) r[i] = S->H[i]; - - while (blocks--) { - for (i = 0; i < 16; i++) { w[i] = W0(in, i); } - for (i = 16; i < 80; i++) { w[i] = W1(i); } - for (i = 0; i < 80; i++) { STEP(i); } - for (i = 0; i < 8; i++) { r[i] += S->H[i]; S->H[i] = r[i]; } - S->T[0] += HASH_BLOCK_SIZE * 8; - S->T[1] += (!S->T[0]) ? 1 : 0; - in += HASH_BLOCK_SIZE; - } -} - -static void -ed25519_hash_init(sha512_state *S) { - S->H[0] = 0x6a09e667f3bcc908ull; - S->H[1] = 0xbb67ae8584caa73bull; - S->H[2] = 0x3c6ef372fe94f82bull; - S->H[3] = 0xa54ff53a5f1d36f1ull; - S->H[4] = 0x510e527fade682d1ull; - S->H[5] = 0x9b05688c2b3e6c1full; - S->H[6] = 0x1f83d9abfb41bd6bull; - S->H[7] = 0x5be0cd19137e2179ull; - S->T[0] = 0; - S->T[1] = 0; - S->leftover = 0; -} - -static void -ed25519_hash_update(sha512_state *S, const uint8_t *in, size_t inlen) { - size_t blocks, want; - - /* handle the previous data */ - if (S->leftover) { - want = (HASH_BLOCK_SIZE - S->leftover); - want = (want < inlen) ? want : inlen; - memcpy(S->buffer + S->leftover, in, want); - S->leftover += (uint32_t)want; - if (S->leftover < HASH_BLOCK_SIZE) - return; - in += want; - inlen -= want; - sha512_blocks(S, S->buffer, 1); - } - - /* handle the current data */ - blocks = (inlen & ~(HASH_BLOCK_SIZE - 1)); - S->leftover = (uint32_t)(inlen - blocks); - if (blocks) { - sha512_blocks(S, in, blocks / HASH_BLOCK_SIZE); - in += blocks; - } - - /* handle leftover data */ - if (S->leftover) - memcpy(S->buffer, in, S->leftover); -} - -static void -ed25519_hash_final(sha512_state *S, uint8_t *hash) { - uint64_t t0 = S->T[0] + (S->leftover * 8), t1 = S->T[1]; - - S->buffer[S->leftover] = 0x80; - if (S->leftover <= 111) { - memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); - } else { - memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); - sha512_blocks(S, S->buffer, 1); - memset(S->buffer, 0, 112); - } - - sha512_STORE64_BE(S->buffer + 112, t1); - sha512_STORE64_BE(S->buffer + 120, t0); - sha512_blocks(S, S->buffer, 1); - - sha512_STORE64_BE(&hash[ 0], S->H[0]); - sha512_STORE64_BE(&hash[ 8], S->H[1]); - sha512_STORE64_BE(&hash[16], S->H[2]); - sha512_STORE64_BE(&hash[24], S->H[3]); - sha512_STORE64_BE(&hash[32], S->H[4]); - sha512_STORE64_BE(&hash[40], S->H[5]); - sha512_STORE64_BE(&hash[48], S->H[6]); - sha512_STORE64_BE(&hash[56], S->H[7]); -} - -static void -ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { - ed25519_hash_context ctx; - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, in, inlen); - ed25519_hash_final(&ctx, hash); -} - -#elif defined(ED25519_CUSTOMHASH) - -#include "ed25519-hash-custom.h" - -#else - -#include - -typedef SHA512_CTX ed25519_hash_context; - -static void -ed25519_hash_init(ed25519_hash_context *ctx) { - SHA512_Init(ctx); -} - -static void -ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen) { - SHA512_Update(ctx, in, inlen); -} - -static void -ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash) { - SHA512_Final(hash, ctx); -} - -static void -ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { - SHA512(in, inlen, hash); -} - -#endif - diff --git a/external/ed25519-donna/ed25519-randombytes-custom.h b/external/ed25519-donna/ed25519-randombytes-custom.h deleted file mode 100644 index 9f5106340c..0000000000 --- a/external/ed25519-donna/ed25519-randombytes-custom.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - a custom randombytes must implement: - - void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); - - ed25519_randombytes_unsafe is used by the batch verification function - to create random scalars -*/ diff --git a/external/ed25519-donna/ed25519-randombytes.h b/external/ed25519-donna/ed25519-randombytes.h deleted file mode 100644 index 53d1c3fe1e..0000000000 --- a/external/ed25519-donna/ed25519-randombytes.h +++ /dev/null @@ -1,91 +0,0 @@ -#if defined(ED25519_TEST) -/* - ISAAC+ "variant", the paper is not clear on operator precedence and other - things. This is the "first in, first out" option! - - Not threadsafe or securely initialized, only for deterministic testing -*/ -typedef struct isaacp_state_t { - uint32_t state[256]; - unsigned char buffer[1024]; - uint32_t a, b, c; - size_t left; -} isaacp_state; - -#define isaacp_step(offset, mix) \ - x = mm[i + offset]; \ - a = (a ^ (mix)) + (mm[(i + offset + 128) & 0xff]); \ - y = (a ^ b) + mm[(x >> 2) & 0xff]; \ - mm[i + offset] = y; \ - b = (x + a) ^ mm[(y >> 10) & 0xff]; \ - U32TO8_LE(out + (i + offset) * 4, b); - -static void -isaacp_mix(isaacp_state *st) { - uint32_t i, x, y; - uint32_t a = st->a, b = st->b, c = st->c; - uint32_t *mm = st->state; - unsigned char *out = st->buffer; - - c = c + 1; - b = b + c; - - for (i = 0; i < 256; i += 4) { - isaacp_step(0, ROTL32(a,13)) - isaacp_step(1, ROTR32(a, 6)) - isaacp_step(2, ROTL32(a, 2)) - isaacp_step(3, ROTR32(a,16)) - } - - st->a = a; - st->b = b; - st->c = c; - st->left = 1024; -} - -static void -isaacp_random(isaacp_state *st, void *p, size_t len) { - size_t use; - unsigned char *c = (unsigned char *)p; - while (len) { - use = (len > st->left) ? st->left : len; - memcpy(c, st->buffer + (sizeof(st->buffer) - st->left), use); - - st->left -= use; - c += use; - len -= use; - - if (!st->left) - isaacp_mix(st); - } -} - -void -ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { - static int initialized = 0; - static isaacp_state rng; - - if (!initialized) { - memset(&rng, 0, sizeof(rng)); - isaacp_mix(&rng); - isaacp_mix(&rng); - initialized = 1; - } - - isaacp_random(&rng, p, len); -} -#elif defined(ED25519_CUSTOMRNG) - -#include "ed25519-randombytes-custom.h" - -#else - -#include - -void -ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { - - RAND_bytes(p, (int) len); - -} -#endif diff --git a/external/ed25519-donna/ed25519.c b/external/ed25519-donna/ed25519.c deleted file mode 100644 index 58a755b8d3..0000000000 --- a/external/ed25519-donna/ed25519.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - Public domain by Andrew M. - - Ed25519 reference implementation using Ed25519-donna -*/ - - -/* define ED25519_SUFFIX to have it appended to the end of each public function */ -#if !defined(ED25519_SUFFIX) -#define ED25519_SUFFIX -#endif - -#define ED25519_FN3(fn,suffix) fn##suffix -#define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) -#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) - -#include "ed25519-donna.h" -#include "ed25519.h" -#include "ed25519-randombytes.h" -#include "ed25519-hash.h" - -/* - Generates a (extsk[0..31]) and aExt (extsk[32..63]) -*/ - -DONNA_INLINE static void -ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { - ed25519_hash(extsk, sk, 32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; -} - -static void -ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { - ed25519_hash_context ctx; - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, RS, 32); - ed25519_hash_update(&ctx, pk, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hram); -} - -void -ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { - bignum256modm a; - ge25519 ALIGN(16) A; - hash_512bits extsk; - - /* A = aB */ - ed25519_extsk(extsk, sk); - expand256_modm(a, extsk, 32); - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - ge25519_pack(pk, &A); -} - - -void -ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { - ed25519_hash_context ctx; - bignum256modm r, S, a; - ge25519 ALIGN(16) R; - hash_512bits extsk, hashr, hram; - - ed25519_extsk(extsk, sk); - - /* r = H(aExt[32..64], m) */ - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, extsk + 32, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hashr); - expand256_modm(r, hashr, 64); - - /* R = rB */ - ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); - ge25519_pack(RS, &R); - - /* S = H(R,A,m).. */ - ed25519_hram(hram, RS, pk, m, mlen); - expand256_modm(S, hram, 64); - - /* S = H(R,A,m)a */ - expand256_modm(a, extsk, 32); - mul256_modm(S, S, a); - - /* S = (r + H(R,A,m)a) */ - add256_modm(S, S, r); - - /* S = (r + H(R,A,m)a) mod L */ - contract256_modm(RS + 32, S); -} - -int -ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { - ge25519 ALIGN(16) R, A; - hash_512bits hash; - bignum256modm hram, S; - unsigned char checkR[32]; - - if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) - return -1; - - /* hram = H(R,A,m) */ - ed25519_hram(hash, RS, pk, m, mlen); - expand256_modm(hram, hash, 64); - - /* S */ - expand256_modm(S, RS + 32, 32); - - /* SB - H(R,A,m)A */ - ge25519_double_scalarmult_vartime(&R, &A, hram, S); - ge25519_pack(checkR, &R); - - /* check that R = SB - H(R,A,m)A */ - return ed25519_verify(RS, checkR, 32) ? 0 : -1; -} - -#include "ed25519-donna-batchverify.h" - -/* - Fast Curve25519 basepoint scalar multiplication -*/ - -void -ED25519_FN(curved25519_scalarmult_basepoint) (curved25519_key pk, const curved25519_key e) { - curved25519_key ec; - bignum256modm s; - bignum25519 ALIGN(16) yplusz, zminusy; - ge25519 ALIGN(16) p; - size_t i; - - /* clamp */ - for (i = 0; i < 32; i++) ec[i] = e[i]; - ec[0] &= 248; - ec[31] &= 127; - ec[31] |= 64; - - expand_raw256_modm(s, ec); - - /* scalar * basepoint */ - ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); - - /* u = (y + z) / (z - y) */ - curve25519_add(yplusz, p.y, p.z); - curve25519_sub(zminusy, p.z, p.y); - curve25519_recip(zminusy, zminusy); - curve25519_mul(yplusz, yplusz, zminusy); - curve25519_contract(pk, yplusz); -} - diff --git a/external/ed25519-donna/ed25519.h b/external/ed25519-donna/ed25519.h deleted file mode 100644 index dc86675cd1..0000000000 --- a/external/ed25519-donna/ed25519.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef ED25519_H -#define ED25519_H - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -typedef unsigned char ed25519_signature[64]; -typedef unsigned char ed25519_public_key[32]; -typedef unsigned char ed25519_secret_key[32]; - -typedef unsigned char curved25519_key[32]; - -void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); - -int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); - -void ed25519_randombytes_unsafe(void *out, size_t count); - -void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); - -#if defined(__cplusplus) -} -#endif - -#endif // ED25519_H diff --git a/external/ed25519-donna/fuzz/README.md b/external/ed25519-donna/fuzz/README.md deleted file mode 100644 index 306ddfe08c..0000000000 --- a/external/ed25519-donna/fuzz/README.md +++ /dev/null @@ -1,173 +0,0 @@ -This code fuzzes ed25519-donna (and optionally ed25519-donna-sse2) against the ref10 implementations of -[curve25519](https://github.com/floodyberry/supercop/tree/master/crypto_scalarmult/curve25519/ref10) and -[ed25519](https://github.com/floodyberry/supercop/tree/master/crypto_sign/ed25519/ref10). - -Curve25519 tests that generating a public key from a secret key - -# Building - -## *nix + PHP - -`php build-nix.php (required parameters) (optional parameters)` - -Required parameters: - -* `--function=[curve25519,ed25519]` -* `--bits=[32,64]` - -Optional parameters: - -* `--with-sse2` - - Also fuzz against ed25519-donna-sse2 -* `--with-openssl` - - Build with OpenSSL's SHA-512. - - Default: Reference SHA-512 implementation (slow!) - -* `--compiler=[gcc,clang,icc]` - - Default: gcc - -* `--no-asm` - - Do not use platform specific assembler - - -example: - - php build-nix.php --bits=64 --function=ed25519 --with-sse2 --compiler=icc - -## Windows - -Create a project with access to the ed25519 files. - -If you are not using OpenSSL, add the `ED25519_REFHASH` define to the projects -"Properties/Preprocessor/Preprocessor Definitions" option - -Add the following files to the project: - -* `fuzz/curve25519-ref10.c` -* `fuzz/ed25519-ref10.c` -* `fuzz/ed25519-donna.c` -* `fuzz/ed25519-donna-sse2.c` (optional) -* `fuzz-[curve25519/ed25519].c` (depending on which you want to fuzz) - -If you are also fuzzing against ed25519-donna-sse2, add the `ED25519_SSE2` define for `fuzz-[curve25519/ed25519].c` under -its "Properties/Preprocessor/Preprocessor Definitions" option. - -# Running - -If everything agrees, the program will only output occasional status dots (every 0x1000 passes) -and a 64bit progress count (every 0x20000 passes): - - fuzzing: ref10 curved25519 curved25519-sse2 - - ................................ [0000000000020000] - ................................ [0000000000040000] - ................................ [0000000000060000] - ................................ [0000000000080000] - ................................ [00000000000a0000] - ................................ [00000000000c0000] - -If any of the implementations do not agree with the ref10 implementation, the program will dump -the random data that was used, the data generated by the ref10 implementation, and diffs of the -ed25519-donna data against the ref10 data. - -## Example errors - -These are example error dumps (with intentionally introduced errors). - -### Ed25519 - -Random data: - -* sk, or Secret Key -* m, or Message - -Generated data: - -* pk, or Public Key -* sig, or Signature -* valid, or if the signature of the message is valid with the public key - -Dump: - - sk: - 0x3b,0xb7,0x17,0x7a,0x66,0xdc,0xb7,0x9a,0x90,0x25,0x07,0x99,0x96,0xf3,0x92,0xef, - 0x78,0xf8,0xad,0x6c,0x35,0x87,0x81,0x67,0x03,0xe6,0x95,0xba,0x06,0x18,0x7c,0x9c, - - m: - 0x7c,0x8d,0x3d,0xe1,0x92,0xee,0x7a,0xb8,0x4d,0xc9,0xfb,0x02,0x34,0x1e,0x5a,0x91, - 0xee,0x01,0xa6,0xb8,0xab,0x37,0x3f,0x3d,0x6d,0xa2,0x47,0xe3,0x27,0x93,0x7c,0xb7, - 0x77,0x07,0xb6,0x88,0x41,0x22,0xf3,0x3f,0xce,0xcb,0x6b,0x3e,0x2b,0x23,0x68,0x7f, - 0x5b,0xb9,0xda,0x04,0xbb,0xae,0x42,0x50,0xf5,0xe9,0xc5,0x11,0xbd,0x52,0x76,0x98, - 0xf1,0x87,0x09,0xb9,0x89,0x0a,0x52,0x69,0x01,0xce,0xe0,0x4a,0xa6,0x46,0x5a,0xe1, - 0x63,0x14,0xe0,0x81,0x52,0xec,0xcd,0xcf,0x70,0x54,0x7d,0xa3,0x49,0x8b,0xf0,0x89, - 0x70,0x07,0x12,0x2a,0xd9,0xaa,0x16,0x01,0xb2,0x16,0x3a,0xbb,0xfc,0xfa,0x13,0x5b, - 0x69,0x83,0x92,0x70,0x95,0x76,0xa0,0x8e,0x16,0x79,0xcc,0xaa,0xb5,0x7c,0xf8,0x7a, - - ref10: - pk: - 0x71,0xb0,0x5e,0x62,0x1b,0xe3,0xe7,0x36,0x91,0x8b,0xc0,0x13,0x36,0x0c,0xc9,0x04, - 0x16,0xf5,0xff,0x48,0x0c,0x83,0x6b,0x88,0x53,0xa2,0xc6,0x0f,0xf7,0xac,0x42,0x04, - - sig: - 0x3e,0x05,0xc5,0x37,0x16,0x0b,0x29,0x30,0x89,0xa3,0xe7,0x83,0x08,0x16,0xdd,0x96, - 0x02,0xfa,0x0d,0x44,0x2c,0x43,0xaa,0x80,0x93,0x04,0x58,0x22,0x09,0xbf,0x11,0xa5, - 0xcc,0xa5,0x3c,0x9f,0xa0,0xa4,0x64,0x5a,0x4a,0xdb,0x20,0xfb,0xc7,0x9b,0xfd,0x3f, - 0x08,0xae,0xc4,0x3c,0x1e,0xd8,0xb6,0xb4,0xd2,0x6d,0x80,0x92,0xcb,0x71,0xf3,0x02, - - valid: yes - - ed25519-donna: - pk diff: - ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - - sig diff: - 0x2c,0xb9,0x25,0x14,0xd0,0x94,0xeb,0xfe,0x46,0x02,0xc2,0xe8,0xa3,0xeb,0xbf,0xb5, - 0x72,0x84,0xbf,0xc1,0x8a,0x32,0x30,0x99,0xf7,0x58,0xfe,0x06,0xa8,0xdc,0xdc,0xab, - 0xb5,0x57,0x03,0x33,0x87,0xce,0x54,0x55,0x6a,0x69,0x8a,0xc4,0xb7,0x2a,0xed,0x97, - 0xb4,0x68,0xe7,0x52,0x7a,0x07,0x55,0x3b,0xa2,0x94,0xd6,0x5e,0xa1,0x61,0x80,0x08, - - valid: no - -In this case, the generated public key matches, but the generated signature is completely -different and does not validate. - -### Curve25519 - -Random data: - -* sk, or Secret Key - -Generated data: - -* pk, or Public Key - -Dump: - - sk: - 0x44,0xec,0x0b,0x0e,0xa2,0x0e,0x9c,0x5b,0x8c,0xce,0x7b,0x1d,0x68,0xae,0x0f,0x9e, - 0x81,0xe2,0x04,0x76,0xda,0x87,0xa4,0x9e,0xc9,0x4f,0x3b,0xf9,0xc3,0x89,0x63,0x70, - - - ref10: - 0x24,0x55,0x55,0xc0,0xf9,0x80,0xaf,0x02,0x43,0xee,0x8c,0x7f,0xc1,0xad,0x90,0x95, - 0x57,0x91,0x14,0x2e,0xf2,0x14,0x22,0x80,0xdd,0x4e,0x3c,0x85,0x71,0x84,0x8c,0x62, - - - curved25519 diff: - 0x12,0xd1,0x61,0x2b,0x16,0xb3,0xd8,0x29,0xf8,0xa3,0xba,0x70,0x4e,0x49,0x4f,0x43, - 0xa1,0x3c,0x6b,0x42,0x11,0x61,0xcc,0x30,0x87,0x73,0x46,0xfb,0x85,0xc7,0x9a,0x35, - - - curved25519-sse2 diff: - ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - ____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____, - - -In this case, curved25519 is totally wrong, while curved25519-sse2 matches the reference -implementation. \ No newline at end of file diff --git a/external/ed25519-donna/fuzz/build-nix.php b/external/ed25519-donna/fuzz/build-nix.php deleted file mode 100644 index c69144ebc9..0000000000 --- a/external/ed25519-donna/fuzz/build-nix.php +++ /dev/null @@ -1,134 +0,0 @@ -set = false; - - $map = array(); - foreach($legal_values as $value) - $map[$value] = true; - - for ($i = 1; $i < $argc; $i++) { - if (!preg_match("!--".$flag."=(.*)!", $argv[$i], $m)) - continue; - if (isset($map[$m[1]])) { - $this->value = $m[1]; - $this->set = true; - return; - } else { - usage("{$m[1]} is not a valid parameter to --{$flag}!"); - exit(1); - } - } - } - } - - class flag extends argument { - function flag($flag) { - global $argc, $argv; - - $this->set = false; - - $flag = "--{$flag}"; - for ($i = 1; $i < $argc; $i++) { - if ($argv[$i] !== $flag) - continue; - $this->value = true; - $this->set = true; - return; - } - } - } - - $bits = new multiargument("bits", array("32", "64")); - $function = new multiargument("function", array("curve25519", "ed25519")); - $compiler = new multiargument("compiler", array("gcc", "clang", "icc")); - $with_sse2 = new flag("with-sse2"); - $with_openssl = new flag("with-openssl"); - $no_asm = new flag("no-asm"); - - $err = ""; - if (!$bits->set) - $err .= "--bits not set\n"; - if (!$function->set) - $err .= "--function not set\n"; - - if ($err !== "") { - usage($err); - exit; - } - - $compile = ($compiler->set) ? $compiler->value : "gcc"; - $link = ""; - $flags = "-O3 -m{$bits->value}"; - $ret = 0; - - if ($with_openssl->set) $link .= " -lssl -lcrypto"; - if (!$with_openssl->set) $flags .= " -DED25519_REFHASH -DED25519_TEST"; - if ($no_asm->set) $flags .= " -DED25519_NO_INLINE_ASM"; - - if ($function->value === "curve25519") { - runcmd("building ref10..", "{$compile} {$flags} curve25519-ref10.c -c -o curve25519-ref10.o"); - runcmd("building ed25519..", "{$compile} {$flags} ed25519-donna.c -c -o ed25519.o"); - if ($with_sse2->set) { - runcmd("building ed25519-sse2..", "{$compile} {$flags} ed25519-donna-sse2.c -c -o ed25519-sse2.o -msse2"); - $flags .= " -DED25519_SSE2"; - $link .= " ed25519-sse2.o"; - } - runcmd("linking..", "{$compile} {$flags} {$link} fuzz-curve25519.c ed25519.o curve25519-ref10.o -o fuzz-curve25519"); - echoln("fuzz-curve25519 built."); - } else if ($function->value === "ed25519") { - runcmd("building ref10..", "{$compile} {$flags} ed25519-ref10.c -c -o ed25519-ref10.o"); - runcmd("building ed25519..", "{$compile} {$flags} ed25519-donna.c -c -o ed25519.o"); - if ($with_sse2->set) { - runcmd("building ed25519-sse2..", "{$compile} {$flags} ed25519-donna-sse2.c -c -o ed25519-sse2.o -msse2"); - $flags .= " -DED25519_SSE2"; - $link .= " ed25519-sse2.o"; - } - runcmd("linking..", "{$compile} {$flags} {$link} fuzz-ed25519.c ed25519.o ed25519-ref10.o -o fuzz-ed25519"); - echoln("fuzz-ed25519 built."); - } - - - cleanup(); -?> diff --git a/external/ed25519-donna/fuzz/curve25519-ref10.c b/external/ed25519-donna/fuzz/curve25519-ref10.c deleted file mode 100644 index efefce6fde..0000000000 --- a/external/ed25519-donna/fuzz/curve25519-ref10.c +++ /dev/null @@ -1,1272 +0,0 @@ -#include - -typedef int32_t crypto_int32; -typedef int64_t crypto_int64; -typedef uint64_t crypto_uint64; - -typedef crypto_int32 fe[10]; - -/* -h = 0 -*/ - -void fe_0(fe h) -{ - h[0] = 0; - h[1] = 0; - h[2] = 0; - h[3] = 0; - h[4] = 0; - h[5] = 0; - h[6] = 0; - h[7] = 0; - h[8] = 0; - h[9] = 0; -} - -/* -h = 1 -*/ - -void fe_1(fe h) -{ - h[0] = 1; - h[1] = 0; - h[2] = 0; - h[3] = 0; - h[4] = 0; - h[5] = 0; - h[6] = 0; - h[7] = 0; - h[8] = 0; - h[9] = 0; -} - -/* -h = f + g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Postconditions: - |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -void fe_add(fe h,fe f,fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 h0 = f0 + g0; - crypto_int32 h1 = f1 + g1; - crypto_int32 h2 = f2 + g2; - crypto_int32 h3 = f3 + g3; - crypto_int32 h4 = f4 + g4; - crypto_int32 h5 = f5 + g5; - crypto_int32 h6 = f6 + g6; - crypto_int32 h7 = f7 + g7; - crypto_int32 h8 = f8 + g8; - crypto_int32 h9 = f9 + g9; - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = f -*/ - -void fe_copy(fe h,fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - h[0] = f0; - h[1] = f1; - h[2] = f2; - h[3] = f3; - h[4] = f4; - h[5] = f5; - h[6] = f6; - h[7] = f7; - h[8] = f8; - h[9] = f9; -} - - -/* -Replace (f,g) with (g,f) if b == 1; -replace (f,g) with (f,g) if b == 0. - -Preconditions: b in {0,1}. -*/ - -void fe_cswap(fe f,fe g,unsigned int b) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 x0 = f0 ^ g0; - crypto_int32 x1 = f1 ^ g1; - crypto_int32 x2 = f2 ^ g2; - crypto_int32 x3 = f3 ^ g3; - crypto_int32 x4 = f4 ^ g4; - crypto_int32 x5 = f5 ^ g5; - crypto_int32 x6 = f6 ^ g6; - crypto_int32 x7 = f7 ^ g7; - crypto_int32 x8 = f8 ^ g8; - crypto_int32 x9 = f9 ^ g9; - b = -b; - x0 &= b; - x1 &= b; - x2 &= b; - x3 &= b; - x4 &= b; - x5 &= b; - x6 &= b; - x7 &= b; - x8 &= b; - x9 &= b; - f[0] = f0 ^ x0; - f[1] = f1 ^ x1; - f[2] = f2 ^ x2; - f[3] = f3 ^ x3; - f[4] = f4 ^ x4; - f[5] = f5 ^ x5; - f[6] = f6 ^ x6; - f[7] = f7 ^ x7; - f[8] = f8 ^ x8; - f[9] = f9 ^ x9; - g[0] = g0 ^ x0; - g[1] = g1 ^ x1; - g[2] = g2 ^ x2; - g[3] = g3 ^ x3; - g[4] = g4 ^ x4; - g[5] = g5 ^ x5; - g[6] = g6 ^ x6; - g[7] = g7 ^ x7; - g[8] = g8 ^ x8; - g[9] = g9 ^ x9; -} - -static crypto_uint64 load_3(const unsigned char *in) -{ - crypto_uint64 result; - result = (crypto_uint64) in[0]; - result |= ((crypto_uint64) in[1]) << 8; - result |= ((crypto_uint64) in[2]) << 16; - return result; -} - -static crypto_uint64 load_4(const unsigned char *in) -{ - crypto_uint64 result; - result = (crypto_uint64) in[0]; - result |= ((crypto_uint64) in[1]) << 8; - result |= ((crypto_uint64) in[2]) << 16; - result |= ((crypto_uint64) in[3]) << 24; - return result; -} - -void fe_frombytes(fe h,const unsigned char *s) -{ - crypto_int64 h0 = load_4(s); - crypto_int64 h1 = load_3(s + 4) << 6; - crypto_int64 h2 = load_3(s + 7) << 5; - crypto_int64 h3 = load_3(s + 10) << 3; - crypto_int64 h4 = load_3(s + 13) << 2; - crypto_int64 h5 = load_4(s + 16); - crypto_int64 h6 = load_3(s + 20) << 7; - crypto_int64 h7 = load_3(s + 23) << 5; - crypto_int64 h8 = load_3(s + 26) << 4; - crypto_int64 h9 = load_3(s + 29) << 2; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - - -/* -h = f * g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. - |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. - -Postconditions: - |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. -*/ - -/* -Notes on implementation strategy: - -Using schoolbook multiplication. -Karatsuba would save a little in some cost models. - -Most multiplications by 2 and 19 are 32-bit precomputations; -cheaper than 64-bit postcomputations. - -There is one remaining multiplication by 19 in the carry chain; -one *19 precomputation can be merged into this, -but the resulting data flow is considerably less clean. - -There are 12 carries below. -10 of them are 2-way parallelizable and vectorizable. -Can get away with 11 carries, but then data flow is much deeper. - -With tighter constraints on inputs can squeeze carries into int32. -*/ - -void fe_mul(fe h,fe f,fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 g1_19 = 19 * g1; /* 1.4*2^29 */ - crypto_int32 g2_19 = 19 * g2; /* 1.4*2^30; still ok */ - crypto_int32 g3_19 = 19 * g3; - crypto_int32 g4_19 = 19 * g4; - crypto_int32 g5_19 = 19 * g5; - crypto_int32 g6_19 = 19 * g6; - crypto_int32 g7_19 = 19 * g7; - crypto_int32 g8_19 = 19 * g8; - crypto_int32 g9_19 = 19 * g9; - crypto_int32 f1_2 = 2 * f1; - crypto_int32 f3_2 = 2 * f3; - crypto_int32 f5_2 = 2 * f5; - crypto_int32 f7_2 = 2 * f7; - crypto_int32 f9_2 = 2 * f9; - crypto_int64 f0g0 = f0 * (crypto_int64) g0; - crypto_int64 f0g1 = f0 * (crypto_int64) g1; - crypto_int64 f0g2 = f0 * (crypto_int64) g2; - crypto_int64 f0g3 = f0 * (crypto_int64) g3; - crypto_int64 f0g4 = f0 * (crypto_int64) g4; - crypto_int64 f0g5 = f0 * (crypto_int64) g5; - crypto_int64 f0g6 = f0 * (crypto_int64) g6; - crypto_int64 f0g7 = f0 * (crypto_int64) g7; - crypto_int64 f0g8 = f0 * (crypto_int64) g8; - crypto_int64 f0g9 = f0 * (crypto_int64) g9; - crypto_int64 f1g0 = f1 * (crypto_int64) g0; - crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1; - crypto_int64 f1g2 = f1 * (crypto_int64) g2; - crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3; - crypto_int64 f1g4 = f1 * (crypto_int64) g4; - crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5; - crypto_int64 f1g6 = f1 * (crypto_int64) g6; - crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7; - crypto_int64 f1g8 = f1 * (crypto_int64) g8; - crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19; - crypto_int64 f2g0 = f2 * (crypto_int64) g0; - crypto_int64 f2g1 = f2 * (crypto_int64) g1; - crypto_int64 f2g2 = f2 * (crypto_int64) g2; - crypto_int64 f2g3 = f2 * (crypto_int64) g3; - crypto_int64 f2g4 = f2 * (crypto_int64) g4; - crypto_int64 f2g5 = f2 * (crypto_int64) g5; - crypto_int64 f2g6 = f2 * (crypto_int64) g6; - crypto_int64 f2g7 = f2 * (crypto_int64) g7; - crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19; - crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19; - crypto_int64 f3g0 = f3 * (crypto_int64) g0; - crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1; - crypto_int64 f3g2 = f3 * (crypto_int64) g2; - crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3; - crypto_int64 f3g4 = f3 * (crypto_int64) g4; - crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5; - crypto_int64 f3g6 = f3 * (crypto_int64) g6; - crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19; - crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19; - crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19; - crypto_int64 f4g0 = f4 * (crypto_int64) g0; - crypto_int64 f4g1 = f4 * (crypto_int64) g1; - crypto_int64 f4g2 = f4 * (crypto_int64) g2; - crypto_int64 f4g3 = f4 * (crypto_int64) g3; - crypto_int64 f4g4 = f4 * (crypto_int64) g4; - crypto_int64 f4g5 = f4 * (crypto_int64) g5; - crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19; - crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19; - crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19; - crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19; - crypto_int64 f5g0 = f5 * (crypto_int64) g0; - crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1; - crypto_int64 f5g2 = f5 * (crypto_int64) g2; - crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3; - crypto_int64 f5g4 = f5 * (crypto_int64) g4; - crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19; - crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19; - crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19; - crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19; - crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19; - crypto_int64 f6g0 = f6 * (crypto_int64) g0; - crypto_int64 f6g1 = f6 * (crypto_int64) g1; - crypto_int64 f6g2 = f6 * (crypto_int64) g2; - crypto_int64 f6g3 = f6 * (crypto_int64) g3; - crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19; - crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19; - crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19; - crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19; - crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19; - crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19; - crypto_int64 f7g0 = f7 * (crypto_int64) g0; - crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1; - crypto_int64 f7g2 = f7 * (crypto_int64) g2; - crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19; - crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19; - crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19; - crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19; - crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19; - crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19; - crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19; - crypto_int64 f8g0 = f8 * (crypto_int64) g0; - crypto_int64 f8g1 = f8 * (crypto_int64) g1; - crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19; - crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19; - crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19; - crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19; - crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19; - crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19; - crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19; - crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19; - crypto_int64 f9g0 = f9 * (crypto_int64) g0; - crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19; - crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19; - crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19; - crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19; - crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19; - crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19; - crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19; - crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19; - crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19; - crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; - crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; - crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; - crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; - crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; - crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; - crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; - crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; - crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; - crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - /* - |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) - i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 - |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) - i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 - */ - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - /* |h0| <= 2^25 */ - /* |h4| <= 2^25 */ - /* |h1| <= 1.51*2^58 */ - /* |h5| <= 1.51*2^58 */ - - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - /* |h1| <= 2^24; from now on fits into int32 */ - /* |h5| <= 2^24; from now on fits into int32 */ - /* |h2| <= 1.21*2^59 */ - /* |h6| <= 1.21*2^59 */ - - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - /* |h2| <= 2^25; from now on fits into int32 unchanged */ - /* |h6| <= 2^25; from now on fits into int32 unchanged */ - /* |h3| <= 1.51*2^58 */ - /* |h7| <= 1.51*2^58 */ - - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - /* |h3| <= 2^24; from now on fits into int32 unchanged */ - /* |h7| <= 2^24; from now on fits into int32 unchanged */ - /* |h4| <= 1.52*2^33 */ - /* |h8| <= 1.52*2^33 */ - - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - /* |h4| <= 2^25; from now on fits into int32 unchanged */ - /* |h8| <= 2^25; from now on fits into int32 unchanged */ - /* |h5| <= 1.01*2^24 */ - /* |h9| <= 1.51*2^58 */ - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - /* |h9| <= 2^24; from now on fits into int32 unchanged */ - /* |h0| <= 1.8*2^37 */ - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - /* |h0| <= 2^25; from now on fits into int32 unchanged */ - /* |h1| <= 1.01*2^24 */ - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = f * 121666 -Can overlap h with f. - -Preconditions: - |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. - -Postconditions: - |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. -*/ - -void fe_mul121666(fe h,fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int64 h0 = f0 * (crypto_int64) 121666; - crypto_int64 h1 = f1 * (crypto_int64) 121666; - crypto_int64 h2 = f2 * (crypto_int64) 121666; - crypto_int64 h3 = f3 * (crypto_int64) 121666; - crypto_int64 h4 = f4 * (crypto_int64) 121666; - crypto_int64 h5 = f5 * (crypto_int64) 121666; - crypto_int64 h6 = f6 * (crypto_int64) 121666; - crypto_int64 h7 = f7 * (crypto_int64) 121666; - crypto_int64 h8 = f8 * (crypto_int64) 121666; - crypto_int64 h9 = f9 * (crypto_int64) 121666; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = f * f -Can overlap h with f. - -Preconditions: - |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. - -Postconditions: - |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. -*/ - -/* -See fe_mul.c for discussion of implementation strategy. -*/ - -void fe_sq(fe h,fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 f0_2 = 2 * f0; - crypto_int32 f1_2 = 2 * f1; - crypto_int32 f2_2 = 2 * f2; - crypto_int32 f3_2 = 2 * f3; - crypto_int32 f4_2 = 2 * f4; - crypto_int32 f5_2 = 2 * f5; - crypto_int32 f6_2 = 2 * f6; - crypto_int32 f7_2 = 2 * f7; - crypto_int32 f5_38 = 38 * f5; /* 1.31*2^30 */ - crypto_int32 f6_19 = 19 * f6; /* 1.31*2^30 */ - crypto_int32 f7_38 = 38 * f7; /* 1.31*2^30 */ - crypto_int32 f8_19 = 19 * f8; /* 1.31*2^30 */ - crypto_int32 f9_38 = 38 * f9; /* 1.31*2^30 */ - crypto_int64 f0f0 = f0 * (crypto_int64) f0; - crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; - crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; - crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; - crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; - crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; - crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; - crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; - crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; - crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; - crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; - crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; - crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; - crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; - crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; - crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; - crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; - crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; - crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; - crypto_int64 f2f2 = f2 * (crypto_int64) f2; - crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; - crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; - crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; - crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; - crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; - crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; - crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; - crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; - crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; - crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; - crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; - crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; - crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; - crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; - crypto_int64 f4f4 = f4 * (crypto_int64) f4; - crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; - crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; - crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; - crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; - crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; - crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; - crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; - crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; - crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; - crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; - crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; - crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; - crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; - crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; - crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; - crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; - crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; - crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; - crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; - crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; - crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; - crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; - crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; - crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; - crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; - crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; - crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; - crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; - crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; - crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = f - g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Postconditions: - |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -void fe_sub(fe h,fe f,fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 h0 = f0 - g0; - crypto_int32 h1 = f1 - g1; - crypto_int32 h2 = f2 - g2; - crypto_int32 h3 = f3 - g3; - crypto_int32 h4 = f4 - g4; - crypto_int32 h5 = f5 - g5; - crypto_int32 h6 = f6 - g6; - crypto_int32 h7 = f7 - g7; - crypto_int32 h8 = f8 - g8; - crypto_int32 h9 = f9 - g9; - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -Preconditions: - |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Write p=2^255-19; q=floor(h/p). -Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). - -Proof: - Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. - Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. - - Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). - Then 0> 25; - q = (h0 + q) >> 26; - q = (h1 + q) >> 25; - q = (h2 + q) >> 26; - q = (h3 + q) >> 25; - q = (h4 + q) >> 26; - q = (h5 + q) >> 25; - q = (h6 + q) >> 26; - q = (h7 + q) >> 25; - q = (h8 + q) >> 26; - q = (h9 + q) >> 25; - - /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ - h0 += 19 * q; - /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ - - carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; - carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; - carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; - carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; - carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; - carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; - carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; - carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; - carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; - carry9 = h9 >> 25; h9 -= carry9 << 25; - /* h10 = carry9 */ - - /* - Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. - Have h0+...+2^230 h9 between 0 and 2^255-1; - evidently 2^255 h10-2^255 q = 0. - Goal: Output h0+...+2^230 h9. - */ - - s[0] = h0 >> 0; - s[1] = h0 >> 8; - s[2] = h0 >> 16; - s[3] = (h0 >> 24) | (h1 << 2); - s[4] = h1 >> 6; - s[5] = h1 >> 14; - s[6] = (h1 >> 22) | (h2 << 3); - s[7] = h2 >> 5; - s[8] = h2 >> 13; - s[9] = (h2 >> 21) | (h3 << 5); - s[10] = h3 >> 3; - s[11] = h3 >> 11; - s[12] = (h3 >> 19) | (h4 << 6); - s[13] = h4 >> 2; - s[14] = h4 >> 10; - s[15] = h4 >> 18; - s[16] = h5 >> 0; - s[17] = h5 >> 8; - s[18] = h5 >> 16; - s[19] = (h5 >> 24) | (h6 << 1); - s[20] = h6 >> 7; - s[21] = h6 >> 15; - s[22] = (h6 >> 23) | (h7 << 3); - s[23] = h7 >> 5; - s[24] = h7 >> 13; - s[25] = (h7 >> 21) | (h8 << 4); - s[26] = h8 >> 4; - s[27] = h8 >> 12; - s[28] = (h8 >> 20) | (h9 << 6); - s[29] = h9 >> 2; - s[30] = h9 >> 10; - s[31] = h9 >> 18; -} - -void fe_invert(fe out,fe z) -{ - fe t0; - fe t1; - fe t2; - fe t3; - int i; - - -/* qhasm: fe z1 */ - -/* qhasm: fe z2 */ - -/* qhasm: fe z8 */ - -/* qhasm: fe z9 */ - -/* qhasm: fe z11 */ - -/* qhasm: fe z22 */ - -/* qhasm: fe z_5_0 */ - -/* qhasm: fe z_10_5 */ - -/* qhasm: fe z_10_0 */ - -/* qhasm: fe z_20_10 */ - -/* qhasm: fe z_20_0 */ - -/* qhasm: fe z_40_20 */ - -/* qhasm: fe z_40_0 */ - -/* qhasm: fe z_50_10 */ - -/* qhasm: fe z_50_0 */ - -/* qhasm: fe z_100_50 */ - -/* qhasm: fe z_100_0 */ - -/* qhasm: fe z_200_100 */ - -/* qhasm: fe z_200_0 */ - -/* qhasm: fe z_250_50 */ - -/* qhasm: fe z_250_0 */ - -/* qhasm: fe z_255_5 */ - -/* qhasm: fe z_255_21 */ - -/* qhasm: enter pow225521 */ - -/* qhasm: z2 = z1^2^1 */ -/* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ -/* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ -fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); - -/* qhasm: z8 = z2^2^2 */ -/* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ -/* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ -fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); - -/* qhasm: z9 = z1*z8 */ -/* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ -/* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ -fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2); - -/* qhasm: z_5_0 = z9*z22 */ -/* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ -/* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ -fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2); - -/* qhasm: z_10_0 = z_10_5*z_5_0 */ -/* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ -/* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ -fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2); - -/* qhasm: z_20_0 = z_20_10*z_10_0 */ -/* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ -/* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ -fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3); - -/* qhasm: z_40_0 = z_40_20*z_20_0 */ -/* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ -/* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ -fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2); - -/* qhasm: z_50_0 = z_50_10*z_10_0 */ -/* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ -/* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ -fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2); - -/* qhasm: z_100_0 = z_100_50*z_50_0 */ -/* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ -/* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ -fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3); - -/* qhasm: z_200_0 = z_200_100*z_100_0 */ -/* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ -/* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ -fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2); - -/* qhasm: z_250_0 = z_250_50*z_50_0 */ -/* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ -/* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ -fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1); - -/* qhasm: z_255_21 = z_255_5*z11 */ -/* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,= 0;--pos) { - b = e[pos / 8] >> (pos & 7); - b &= 1; - swap ^= b; - fe_cswap(x2,x3,swap); - fe_cswap(z2,z3,swap); - swap = b; -/* qhasm: fe X2 */ - -/* qhasm: fe Z2 */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe X4 */ - -/* qhasm: fe Z4 */ - -/* qhasm: fe X5 */ - -/* qhasm: fe Z5 */ - -/* qhasm: fe A */ - -/* qhasm: fe B */ - -/* qhasm: fe C */ - -/* qhasm: fe D */ - -/* qhasm: fe E */ - -/* qhasm: fe AA */ - -/* qhasm: fe BB */ - -/* qhasm: fe DA */ - -/* qhasm: fe CB */ - -/* qhasm: fe t0 */ - -/* qhasm: fe t1 */ - -/* qhasm: fe t2 */ - -/* qhasm: fe t3 */ - -/* qhasm: fe t4 */ - -/* qhasm: enter ladder */ - -/* qhasm: D = X3-Z3 */ -/* asm 1: fe_sub(>D=fe#5,D=tmp0,B=fe#6,B=tmp1,A=fe#1,A=x2,C=fe#2,C=z2,DA=fe#4,DA=z3,CB=fe#2,CB=z2,BB=fe#5,BB=tmp0,AA=fe#6,AA=tmp1,t0=fe#3,t0=x3,t1=fe#2,t1=z2,X4=fe#1,X4=x2,E=fe#6,E=tmp1,t2=fe#2,t2=z2,t3=fe#4,t3=z3,X5=fe#3,X5=x3,t4=fe#5,t4=tmp0,Z5=fe#4,x1,Z5=z3,x1,Z4=fe#2,Z4=z2, - -typedef unsigned char ed25519_signature[64]; -typedef unsigned char ed25519_public_key[32]; -typedef unsigned char ed25519_secret_key[32]; - -typedef unsigned char curved25519_key[32]; - -void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); - -int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); - -void ed25519_randombytes_unsafe(void *out, size_t count); - -void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); - -#if defined(ED25519_SSE2) -void ed25519_publickey_sse2(const ed25519_secret_key sk, ed25519_public_key pk); -int ed25519_sign_open_sse2(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_sse2(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); - -int ed25519_sign_open_batch_sse2(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); - -void ed25519_randombytes_unsafe_sse2(void *out, size_t count); - -void curved25519_scalarmult_basepoint_sse2(curved25519_key pk, const curved25519_key e); -#endif - -#endif // ED25519_H diff --git a/external/ed25519-donna/fuzz/ed25519-ref10.c b/external/ed25519-donna/fuzz/ed25519-ref10.c deleted file mode 100644 index a8e802df29..0000000000 --- a/external/ed25519-donna/fuzz/ed25519-ref10.c +++ /dev/null @@ -1,4647 +0,0 @@ -#include -#include -#include - -static int crypto_verify_32(const unsigned char *x,const unsigned char *y) -{ - unsigned int differentbits = 0; -#define F(i) differentbits |= x[i] ^ y[i]; - F(0) - F(1) - F(2) - F(3) - F(4) - F(5) - F(6) - F(7) - F(8) - F(9) - F(10) - F(11) - F(12) - F(13) - F(14) - F(15) - F(16) - F(17) - F(18) - F(19) - F(20) - F(21) - F(22) - F(23) - F(24) - F(25) - F(26) - F(27) - F(28) - F(29) - F(30) - F(31) - return (1 & ((differentbits - 1) >> 8)) - 1; -} - -#if defined(ED25519_REFHASH) - -/* reference/slow SHA-512. really, do not use this */ - -#define HASH_BLOCK_SIZE 128 -#define HASH_DIGEST_SIZE 64 - -typedef struct sha512_state_t { - uint64_t H[8]; - uint64_t T[2]; - uint32_t leftover; - uint8_t buffer[HASH_BLOCK_SIZE]; -} sha512_state; - -typedef sha512_state ed25519_hash_context; - -static const uint64_t sha512_constants[80] = { - 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, - 0x3956c25bf348b538ull, 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, - 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, - 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 0xc19bf174cf692694ull, - 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, - 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, - 0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, - 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 0x06ca6351e003826full, 0x142929670a0e6e70ull, - 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull, - 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, - 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, - 0xd192e819d6ef5218ull, 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, - 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, - 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, - 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, - 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, - 0xca273eceea26619cull, 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, - 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull, - 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull, - 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull -}; - -static uint64_t -sha512_ROTR64(uint64_t x, int k) { - return (x >> k) | (x << (64 - k)); -} - -static uint64_t -sha512_LOAD64_BE(const uint8_t *p) { - return - ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - ((uint64_t)p[7] ); -} - -static void -sha512_STORE64_BE(uint8_t *p, uint64_t v) { - p[0] = (uint8_t)(v >> 56); - p[1] = (uint8_t)(v >> 48); - p[2] = (uint8_t)(v >> 40); - p[3] = (uint8_t)(v >> 32); - p[4] = (uint8_t)(v >> 24); - p[5] = (uint8_t)(v >> 16); - p[6] = (uint8_t)(v >> 8); - p[7] = (uint8_t)(v ); -} - -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S0(x) (sha512_ROTR64(x, 28) ^ sha512_ROTR64(x, 34) ^ sha512_ROTR64(x, 39)) -#define S1(x) (sha512_ROTR64(x, 14) ^ sha512_ROTR64(x, 18) ^ sha512_ROTR64(x, 41)) -#define G0(x) (sha512_ROTR64(x, 1) ^ sha512_ROTR64(x, 8) ^ (x >> 7)) -#define G1(x) (sha512_ROTR64(x, 19) ^ sha512_ROTR64(x, 61) ^ (x >> 6)) -#define W0(in,i) (sha512_LOAD64_BE(&in[i * 8])) -#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) -#define STEP(i) \ - t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ - t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha512_constants[i] + w[i]; \ - r[7] = r[6]; \ - r[6] = r[5]; \ - r[5] = r[4]; \ - r[4] = r[3] + t0; \ - r[3] = r[2]; \ - r[2] = r[1]; \ - r[1] = r[0]; \ - r[0] = t0 + t1; - -static void -sha512_blocks(sha512_state *S, const uint8_t *in, size_t blocks) { - uint64_t r[8], w[80], t0, t1; - size_t i; - - for (i = 0; i < 8; i++) r[i] = S->H[i]; - - while (blocks--) { - for (i = 0; i < 16; i++) { w[i] = W0(in, i); } - for (i = 16; i < 80; i++) { w[i] = W1(i); } - for (i = 0; i < 80; i++) { STEP(i); } - for (i = 0; i < 8; i++) { r[i] += S->H[i]; S->H[i] = r[i]; } - S->T[0] += HASH_BLOCK_SIZE * 8; - S->T[1] += (!S->T[0]) ? 1 : 0; - in += HASH_BLOCK_SIZE; - } -} - -static void -ed25519_hash_init(sha512_state *S) { - S->H[0] = 0x6a09e667f3bcc908ull; - S->H[1] = 0xbb67ae8584caa73bull; - S->H[2] = 0x3c6ef372fe94f82bull; - S->H[3] = 0xa54ff53a5f1d36f1ull; - S->H[4] = 0x510e527fade682d1ull; - S->H[5] = 0x9b05688c2b3e6c1full; - S->H[6] = 0x1f83d9abfb41bd6bull; - S->H[7] = 0x5be0cd19137e2179ull; - S->T[0] = 0; - S->T[1] = 0; - S->leftover = 0; -} - -static void -ed25519_hash_update(sha512_state *S, const uint8_t *in, size_t inlen) { - size_t blocks, want; - - /* handle the previous data */ - if (S->leftover) { - want = (HASH_BLOCK_SIZE - S->leftover); - want = (want < inlen) ? want : inlen; - memcpy(S->buffer + S->leftover, in, want); - S->leftover += (uint32_t)want; - if (S->leftover < HASH_BLOCK_SIZE) - return; - in += want; - inlen -= want; - sha512_blocks(S, S->buffer, 1); - } - - /* handle the current data */ - blocks = (inlen & ~(HASH_BLOCK_SIZE - 1)); - S->leftover = (uint32_t)(inlen - blocks); - if (blocks) { - sha512_blocks(S, in, blocks / HASH_BLOCK_SIZE); - in += blocks; - } - - /* handle leftover data */ - if (S->leftover) - memcpy(S->buffer, in, S->leftover); -} - -static void -ed25519_hash_final(sha512_state *S, uint8_t *hash) { - uint64_t t0 = S->T[0] + (S->leftover * 8), t1 = S->T[1]; - - S->buffer[S->leftover] = 0x80; - if (S->leftover <= 111) { - memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); - } else { - memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); - sha512_blocks(S, S->buffer, 1); - memset(S->buffer, 0, 112); - } - - sha512_STORE64_BE(S->buffer + 112, t1); - sha512_STORE64_BE(S->buffer + 120, t0); - sha512_blocks(S, S->buffer, 1); - - sha512_STORE64_BE(&hash[ 0], S->H[0]); - sha512_STORE64_BE(&hash[ 8], S->H[1]); - sha512_STORE64_BE(&hash[16], S->H[2]); - sha512_STORE64_BE(&hash[24], S->H[3]); - sha512_STORE64_BE(&hash[32], S->H[4]); - sha512_STORE64_BE(&hash[40], S->H[5]); - sha512_STORE64_BE(&hash[48], S->H[6]); - sha512_STORE64_BE(&hash[56], S->H[7]); -} - -static void -crypto_hash_sha512(unsigned char *hash, const unsigned char *in, size_t inlen) { - ed25519_hash_context ctx; - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, in, inlen); - ed25519_hash_final(&ctx, hash); -} - -#else - -#include - -static void -crypto_hash_sha512(unsigned char *hash, const unsigned char *in, size_t inlen) { - SHA512(in, inlen, hash); -} - -#endif - - - - -typedef int32_t crypto_int32; -typedef uint32_t crypto_uint32; -typedef int64_t crypto_int64; -typedef uint64_t crypto_uint64; - -typedef crypto_int32 fe[10]; - -/* -h = 0 -*/ - -static void fe_0(fe h) -{ - h[0] = 0; - h[1] = 0; - h[2] = 0; - h[3] = 0; - h[4] = 0; - h[5] = 0; - h[6] = 0; - h[7] = 0; - h[8] = 0; - h[9] = 0; -} - -/* -h = 1 -*/ - -static void fe_1(fe h) -{ - h[0] = 1; - h[1] = 0; - h[2] = 0; - h[3] = 0; - h[4] = 0; - h[5] = 0; - h[6] = 0; - h[7] = 0; - h[8] = 0; - h[9] = 0; -} - -/* -h = f + g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Postconditions: - |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -static void fe_add(fe h,const fe f,const fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 h0 = f0 + g0; - crypto_int32 h1 = f1 + g1; - crypto_int32 h2 = f2 + g2; - crypto_int32 h3 = f3 + g3; - crypto_int32 h4 = f4 + g4; - crypto_int32 h5 = f5 + g5; - crypto_int32 h6 = f6 + g6; - crypto_int32 h7 = f7 + g7; - crypto_int32 h8 = f8 + g8; - crypto_int32 h9 = f9 + g9; - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - - -/* -Replace (f,g) with (g,g) if b == 1; -replace (f,g) with (f,g) if b == 0. - -Preconditions: b in {0,1}. -*/ - -static void fe_cmov(fe f,const fe g,unsigned int b) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 x0 = f0 ^ g0; - crypto_int32 x1 = f1 ^ g1; - crypto_int32 x2 = f2 ^ g2; - crypto_int32 x3 = f3 ^ g3; - crypto_int32 x4 = f4 ^ g4; - crypto_int32 x5 = f5 ^ g5; - crypto_int32 x6 = f6 ^ g6; - crypto_int32 x7 = f7 ^ g7; - crypto_int32 x8 = f8 ^ g8; - crypto_int32 x9 = f9 ^ g9; - b = -b; - x0 &= b; - x1 &= b; - x2 &= b; - x3 &= b; - x4 &= b; - x5 &= b; - x6 &= b; - x7 &= b; - x8 &= b; - x9 &= b; - f[0] = f0 ^ x0; - f[1] = f1 ^ x1; - f[2] = f2 ^ x2; - f[3] = f3 ^ x3; - f[4] = f4 ^ x4; - f[5] = f5 ^ x5; - f[6] = f6 ^ x6; - f[7] = f7 ^ x7; - f[8] = f8 ^ x8; - f[9] = f9 ^ x9; -} - - -/* -h = f -*/ - -static void fe_copy(fe h,const fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - h[0] = f0; - h[1] = f1; - h[2] = f2; - h[3] = f3; - h[4] = f4; - h[5] = f5; - h[6] = f6; - h[7] = f7; - h[8] = f8; - h[9] = f9; -} - - -static crypto_uint64 load_3(const unsigned char *in) -{ - crypto_uint64 result; - result = (crypto_uint64) in[0]; - result |= ((crypto_uint64) in[1]) << 8; - result |= ((crypto_uint64) in[2]) << 16; - return result; -} - -static crypto_uint64 load_4(const unsigned char *in) -{ - crypto_uint64 result; - result = (crypto_uint64) in[0]; - result |= ((crypto_uint64) in[1]) << 8; - result |= ((crypto_uint64) in[2]) << 16; - result |= ((crypto_uint64) in[3]) << 24; - return result; -} - -/* -Ignores top bit of h. -*/ - -static void fe_frombytes(fe h,const unsigned char *s) -{ - crypto_int64 h0 = load_4(s); - crypto_int64 h1 = load_3(s + 4) << 6; - crypto_int64 h2 = load_3(s + 7) << 5; - crypto_int64 h3 = load_3(s + 10) << 3; - crypto_int64 h4 = load_3(s + 13) << 2; - crypto_int64 h5 = load_4(s + 16); - crypto_int64 h6 = load_3(s + 20) << 7; - crypto_int64 h7 = load_3(s + 23) << 5; - crypto_int64 h8 = load_3(s + 26) << 4; - crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -Preconditions: - |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. - -Write p=2^255-19; q=floor(h/p). -Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). - -Proof: - Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. - Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. - - Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). - Then 0> 25; - q = (h0 + q) >> 26; - q = (h1 + q) >> 25; - q = (h2 + q) >> 26; - q = (h3 + q) >> 25; - q = (h4 + q) >> 26; - q = (h5 + q) >> 25; - q = (h6 + q) >> 26; - q = (h7 + q) >> 25; - q = (h8 + q) >> 26; - q = (h9 + q) >> 25; - - /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ - h0 += 19 * q; - /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ - - carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; - carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; - carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; - carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; - carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; - carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; - carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; - carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; - carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; - carry9 = h9 >> 25; h9 -= carry9 << 25; - /* h10 = carry9 */ - - /* - Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. - Have h0+...+2^230 h9 between 0 and 2^255-1; - evidently 2^255 h10-2^255 q = 0. - Goal: Output h0+...+2^230 h9. - */ - - s[0] = h0 >> 0; - s[1] = h0 >> 8; - s[2] = h0 >> 16; - s[3] = (h0 >> 24) | (h1 << 2); - s[4] = h1 >> 6; - s[5] = h1 >> 14; - s[6] = (h1 >> 22) | (h2 << 3); - s[7] = h2 >> 5; - s[8] = h2 >> 13; - s[9] = (h2 >> 21) | (h3 << 5); - s[10] = h3 >> 3; - s[11] = h3 >> 11; - s[12] = (h3 >> 19) | (h4 << 6); - s[13] = h4 >> 2; - s[14] = h4 >> 10; - s[15] = h4 >> 18; - s[16] = h5 >> 0; - s[17] = h5 >> 8; - s[18] = h5 >> 16; - s[19] = (h5 >> 24) | (h6 << 1); - s[20] = h6 >> 7; - s[21] = h6 >> 15; - s[22] = (h6 >> 23) | (h7 << 3); - s[23] = h7 >> 5; - s[24] = h7 >> 13; - s[25] = (h7 >> 21) | (h8 << 4); - s[26] = h8 >> 4; - s[27] = h8 >> 12; - s[28] = (h8 >> 20) | (h9 << 6); - s[29] = h9 >> 2; - s[30] = h9 >> 10; - s[31] = h9 >> 18; -} - - -/* -h = f - g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Postconditions: - |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -static void fe_sub(fe h,const fe f,const fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 h0 = f0 - g0; - crypto_int32 h1 = f1 - g1; - crypto_int32 h2 = f2 - g2; - crypto_int32 h3 = f3 - g3; - crypto_int32 h4 = f4 - g4; - crypto_int32 h5 = f5 - g5; - crypto_int32 h6 = f6 - g6; - crypto_int32 h7 = f7 - g7; - crypto_int32 h8 = f8 - g8; - crypto_int32 h9 = f9 - g9; - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - - -/* -h = f * f -Can overlap h with f. - -Preconditions: - |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. - -Postconditions: - |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. -*/ - -/* -See fe_mul.c for discussion of implementation strategy. -*/ - -static void fe_sq(fe h,const fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 f0_2 = 2 * f0; - crypto_int32 f1_2 = 2 * f1; - crypto_int32 f2_2 = 2 * f2; - crypto_int32 f3_2 = 2 * f3; - crypto_int32 f4_2 = 2 * f4; - crypto_int32 f5_2 = 2 * f5; - crypto_int32 f6_2 = 2 * f6; - crypto_int32 f7_2 = 2 * f7; - crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ - crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ - crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ - crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ - crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ - crypto_int64 f0f0 = f0 * (crypto_int64) f0; - crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; - crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; - crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; - crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; - crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; - crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; - crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; - crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; - crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; - crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; - crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; - crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; - crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; - crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; - crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; - crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; - crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; - crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; - crypto_int64 f2f2 = f2 * (crypto_int64) f2; - crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; - crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; - crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; - crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; - crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; - crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; - crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; - crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; - crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; - crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; - crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; - crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; - crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; - crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; - crypto_int64 f4f4 = f4 * (crypto_int64) f4; - crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; - crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; - crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; - crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; - crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; - crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; - crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; - crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; - crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; - crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; - crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; - crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; - crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; - crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; - crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; - crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; - crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; - crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; - crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; - crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; - crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; - crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; - crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; - crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; - crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; - crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; - crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; - crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; - crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; - crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = 2 * f * f -Can overlap h with f. - -Preconditions: - |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. - -Postconditions: - |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. -*/ - -/* -See fe_mul.c for discussion of implementation strategy. -*/ - -static void fe_sq2(fe h,const fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 f0_2 = 2 * f0; - crypto_int32 f1_2 = 2 * f1; - crypto_int32 f2_2 = 2 * f2; - crypto_int32 f3_2 = 2 * f3; - crypto_int32 f4_2 = 2 * f4; - crypto_int32 f5_2 = 2 * f5; - crypto_int32 f6_2 = 2 * f6; - crypto_int32 f7_2 = 2 * f7; - crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ - crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ - crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ - crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ - crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ - crypto_int64 f0f0 = f0 * (crypto_int64) f0; - crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; - crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; - crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; - crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; - crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; - crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; - crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; - crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; - crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; - crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; - crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; - crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; - crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; - crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; - crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; - crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; - crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; - crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; - crypto_int64 f2f2 = f2 * (crypto_int64) f2; - crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; - crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; - crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; - crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; - crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; - crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; - crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; - crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; - crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; - crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; - crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; - crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; - crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; - crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; - crypto_int64 f4f4 = f4 * (crypto_int64) f4; - crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; - crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; - crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; - crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; - crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; - crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; - crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; - crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; - crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; - crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; - crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; - crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; - crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; - crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; - crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; - crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; - crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; - crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; - crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; - crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; - crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; - crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; - crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; - crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; - crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; - crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; - crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; - crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; - crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; - crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - h0 += h0; - h1 += h1; - h2 += h2; - h3 += h3; - h4 += h4; - h5 += h5; - h6 += h6; - h7 += h7; - h8 += h8; - h9 += h9; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -/* -h = f * g -Can overlap h with f or g. - -Preconditions: - |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. - |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. - -Postconditions: - |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. -*/ - -/* -Notes on implementation strategy: - -Using schoolbook multiplication. -Karatsuba would save a little in some cost models. - -Most multiplications by 2 and 19 are 32-bit precomputations; -cheaper than 64-bit postcomputations. - -There is one remaining multiplication by 19 in the carry chain; -one *19 precomputation can be merged into this, -but the resulting data flow is considerably less clean. - -There are 12 carries below. -10 of them are 2-way parallelizable and vectorizable. -Can get away with 11 carries, but then data flow is much deeper. - -With tighter constraints on inputs can squeeze carries into int32. -*/ - -static void fe_mul(fe h,const fe f,const fe g) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 g0 = g[0]; - crypto_int32 g1 = g[1]; - crypto_int32 g2 = g[2]; - crypto_int32 g3 = g[3]; - crypto_int32 g4 = g[4]; - crypto_int32 g5 = g[5]; - crypto_int32 g6 = g[6]; - crypto_int32 g7 = g[7]; - crypto_int32 g8 = g[8]; - crypto_int32 g9 = g[9]; - crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */ - crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ - crypto_int32 g3_19 = 19 * g3; - crypto_int32 g4_19 = 19 * g4; - crypto_int32 g5_19 = 19 * g5; - crypto_int32 g6_19 = 19 * g6; - crypto_int32 g7_19 = 19 * g7; - crypto_int32 g8_19 = 19 * g8; - crypto_int32 g9_19 = 19 * g9; - crypto_int32 f1_2 = 2 * f1; - crypto_int32 f3_2 = 2 * f3; - crypto_int32 f5_2 = 2 * f5; - crypto_int32 f7_2 = 2 * f7; - crypto_int32 f9_2 = 2 * f9; - crypto_int64 f0g0 = f0 * (crypto_int64) g0; - crypto_int64 f0g1 = f0 * (crypto_int64) g1; - crypto_int64 f0g2 = f0 * (crypto_int64) g2; - crypto_int64 f0g3 = f0 * (crypto_int64) g3; - crypto_int64 f0g4 = f0 * (crypto_int64) g4; - crypto_int64 f0g5 = f0 * (crypto_int64) g5; - crypto_int64 f0g6 = f0 * (crypto_int64) g6; - crypto_int64 f0g7 = f0 * (crypto_int64) g7; - crypto_int64 f0g8 = f0 * (crypto_int64) g8; - crypto_int64 f0g9 = f0 * (crypto_int64) g9; - crypto_int64 f1g0 = f1 * (crypto_int64) g0; - crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1; - crypto_int64 f1g2 = f1 * (crypto_int64) g2; - crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3; - crypto_int64 f1g4 = f1 * (crypto_int64) g4; - crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5; - crypto_int64 f1g6 = f1 * (crypto_int64) g6; - crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7; - crypto_int64 f1g8 = f1 * (crypto_int64) g8; - crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19; - crypto_int64 f2g0 = f2 * (crypto_int64) g0; - crypto_int64 f2g1 = f2 * (crypto_int64) g1; - crypto_int64 f2g2 = f2 * (crypto_int64) g2; - crypto_int64 f2g3 = f2 * (crypto_int64) g3; - crypto_int64 f2g4 = f2 * (crypto_int64) g4; - crypto_int64 f2g5 = f2 * (crypto_int64) g5; - crypto_int64 f2g6 = f2 * (crypto_int64) g6; - crypto_int64 f2g7 = f2 * (crypto_int64) g7; - crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19; - crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19; - crypto_int64 f3g0 = f3 * (crypto_int64) g0; - crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1; - crypto_int64 f3g2 = f3 * (crypto_int64) g2; - crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3; - crypto_int64 f3g4 = f3 * (crypto_int64) g4; - crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5; - crypto_int64 f3g6 = f3 * (crypto_int64) g6; - crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19; - crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19; - crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19; - crypto_int64 f4g0 = f4 * (crypto_int64) g0; - crypto_int64 f4g1 = f4 * (crypto_int64) g1; - crypto_int64 f4g2 = f4 * (crypto_int64) g2; - crypto_int64 f4g3 = f4 * (crypto_int64) g3; - crypto_int64 f4g4 = f4 * (crypto_int64) g4; - crypto_int64 f4g5 = f4 * (crypto_int64) g5; - crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19; - crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19; - crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19; - crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19; - crypto_int64 f5g0 = f5 * (crypto_int64) g0; - crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1; - crypto_int64 f5g2 = f5 * (crypto_int64) g2; - crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3; - crypto_int64 f5g4 = f5 * (crypto_int64) g4; - crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19; - crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19; - crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19; - crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19; - crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19; - crypto_int64 f6g0 = f6 * (crypto_int64) g0; - crypto_int64 f6g1 = f6 * (crypto_int64) g1; - crypto_int64 f6g2 = f6 * (crypto_int64) g2; - crypto_int64 f6g3 = f6 * (crypto_int64) g3; - crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19; - crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19; - crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19; - crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19; - crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19; - crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19; - crypto_int64 f7g0 = f7 * (crypto_int64) g0; - crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1; - crypto_int64 f7g2 = f7 * (crypto_int64) g2; - crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19; - crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19; - crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19; - crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19; - crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19; - crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19; - crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19; - crypto_int64 f8g0 = f8 * (crypto_int64) g0; - crypto_int64 f8g1 = f8 * (crypto_int64) g1; - crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19; - crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19; - crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19; - crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19; - crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19; - crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19; - crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19; - crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19; - crypto_int64 f9g0 = f9 * (crypto_int64) g0; - crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19; - crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19; - crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19; - crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19; - crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19; - crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19; - crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19; - crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19; - crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19; - crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; - crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; - crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; - crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; - crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; - crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; - crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; - crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; - crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; - crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - - /* - |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) - i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 - |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) - i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 - */ - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - /* |h0| <= 2^25 */ - /* |h4| <= 2^25 */ - /* |h1| <= 1.71*2^59 */ - /* |h5| <= 1.71*2^59 */ - - carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - /* |h1| <= 2^24; from now on fits into int32 */ - /* |h5| <= 2^24; from now on fits into int32 */ - /* |h2| <= 1.41*2^60 */ - /* |h6| <= 1.41*2^60 */ - - carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - /* |h2| <= 2^25; from now on fits into int32 unchanged */ - /* |h6| <= 2^25; from now on fits into int32 unchanged */ - /* |h3| <= 1.71*2^59 */ - /* |h7| <= 1.71*2^59 */ - - carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; - /* |h3| <= 2^24; from now on fits into int32 unchanged */ - /* |h7| <= 2^24; from now on fits into int32 unchanged */ - /* |h4| <= 1.72*2^34 */ - /* |h8| <= 1.41*2^60 */ - - carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; - /* |h4| <= 2^25; from now on fits into int32 unchanged */ - /* |h8| <= 2^25; from now on fits into int32 unchanged */ - /* |h5| <= 1.01*2^24 */ - /* |h9| <= 1.71*2^59 */ - - carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - /* |h9| <= 2^24; from now on fits into int32 unchanged */ - /* |h0| <= 1.1*2^39 */ - - carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - /* |h0| <= 2^25; from now on fits into int32 unchanged */ - /* |h1| <= 1.01*2^24 */ - - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - - -/* -return 1 if f is in {1,3,5,...,q-2} -return 0 if f is in {0,2,4,...,q-1} - -Preconditions: - |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -static int fe_isnegative(const fe f) -{ - unsigned char s[32]; - fe_tobytes(s,f); - return s[0] & 1; -} - - -/* -return 1 if f == 0 -return 0 if f != 0 - -Preconditions: - |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. -*/ - -static const unsigned char zero[32] = {0}; - -static int fe_isnonzero(const fe f) -{ - unsigned char s[32]; - fe_tobytes(s,f); - return crypto_verify_32(s,zero); -} - -/* -h = -f - -Preconditions: - |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. - -Postconditions: - |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. -*/ - -static void fe_neg(fe h,const fe f) -{ - crypto_int32 f0 = f[0]; - crypto_int32 f1 = f[1]; - crypto_int32 f2 = f[2]; - crypto_int32 f3 = f[3]; - crypto_int32 f4 = f[4]; - crypto_int32 f5 = f[5]; - crypto_int32 f6 = f[6]; - crypto_int32 f7 = f[7]; - crypto_int32 f8 = f[8]; - crypto_int32 f9 = f[9]; - crypto_int32 h0 = -f0; - crypto_int32 h1 = -f1; - crypto_int32 h2 = -f2; - crypto_int32 h3 = -f3; - crypto_int32 h4 = -f4; - crypto_int32 h5 = -f5; - crypto_int32 h6 = -f6; - crypto_int32 h7 = -f7; - crypto_int32 h8 = -f8; - crypto_int32 h9 = -f9; - h[0] = h0; - h[1] = h1; - h[2] = h2; - h[3] = h3; - h[4] = h4; - h[5] = h5; - h[6] = h6; - h[7] = h7; - h[8] = h8; - h[9] = h9; -} - -static void fe_invert(fe out,const fe z) -{ - fe t0; - fe t1; - fe t2; - fe t3; - int i; - - -/* qhasm: fe z1 */ - -/* qhasm: fe z2 */ - -/* qhasm: fe z8 */ - -/* qhasm: fe z9 */ - -/* qhasm: fe z11 */ - -/* qhasm: fe z22 */ - -/* qhasm: fe z_5_0 */ - -/* qhasm: fe z_10_5 */ - -/* qhasm: fe z_10_0 */ - -/* qhasm: fe z_20_10 */ - -/* qhasm: fe z_20_0 */ - -/* qhasm: fe z_40_20 */ - -/* qhasm: fe z_40_0 */ - -/* qhasm: fe z_50_10 */ - -/* qhasm: fe z_50_0 */ - -/* qhasm: fe z_100_50 */ - -/* qhasm: fe z_100_0 */ - -/* qhasm: fe z_200_100 */ - -/* qhasm: fe z_200_0 */ - -/* qhasm: fe z_250_50 */ - -/* qhasm: fe z_250_0 */ - -/* qhasm: fe z_255_5 */ - -/* qhasm: fe z_255_21 */ - -/* qhasm: enter pow225521 */ - -/* qhasm: z2 = z1^2^1 */ -/* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ -/* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ -fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); - -/* qhasm: z8 = z2^2^2 */ -/* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ -/* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ -fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); - -/* qhasm: z9 = z1*z8 */ -/* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ -/* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ -fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2); - -/* qhasm: z_5_0 = z9*z22 */ -/* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ -/* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ -fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2); - -/* qhasm: z_10_0 = z_10_5*z_5_0 */ -/* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ -/* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ -fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2); - -/* qhasm: z_20_0 = z_20_10*z_10_0 */ -/* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ -/* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ -fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3); - -/* qhasm: z_40_0 = z_40_20*z_20_0 */ -/* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ -/* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ -fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2); - -/* qhasm: z_50_0 = z_50_10*z_10_0 */ -/* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ -/* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ -fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2); - -/* qhasm: z_100_0 = z_100_50*z_50_0 */ -/* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ -/* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ -fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3); - -/* qhasm: z_200_0 = z_200_100*z_100_0 */ -/* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ -/* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ -fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2); - -/* qhasm: z_250_0 = z_250_50*z_50_0 */ -/* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ -/* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ -fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1); - -/* qhasm: z_255_21 = z_255_5*z11 */ -/* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,z2=fe#1,z2=fe#1,>z2=fe#1); */ -/* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ -fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); - -/* qhasm: z8 = z2^2^2 */ -/* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ -/* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ -fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); - -/* qhasm: z9 = z1*z8 */ -/* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */ -/* asm 2: fe_sq(>z22=t0,z22=t0,>z22=t0); */ -fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0); - -/* qhasm: z_5_0 = z9*z22 */ -/* asm 1: fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */ -/* asm 2: fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */ -fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1); - -/* qhasm: z_10_0 = z_10_5*z_5_0 */ -/* asm 1: fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */ -/* asm 2: fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */ -fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1); - -/* qhasm: z_20_0 = z_20_10*z_10_0 */ -/* asm 1: fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */ -/* asm 2: fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */ -fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2); - -/* qhasm: z_40_0 = z_40_20*z_20_0 */ -/* asm 1: fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */ -/* asm 2: fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */ -fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1); - -/* qhasm: z_50_0 = z_50_10*z_10_0 */ -/* asm 1: fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */ -/* asm 2: fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */ -fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1); - -/* qhasm: z_100_0 = z_100_50*z_50_0 */ -/* asm 1: fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */ -/* asm 2: fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */ -fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2); - -/* qhasm: z_200_0 = z_200_100*z_100_0 */ -/* asm 1: fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */ -/* asm 2: fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */ -fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1); - -/* qhasm: z_250_0 = z_250_50*z_50_0 */ -/* asm 1: fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */ -/* asm 2: fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */ -fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0); - -/* qhasm: z_252_3 = z_252_2*z1 */ -/* asm 1: fe_mul(>z_252_3=fe#12,z_252_3=out,X); - fe_1(h->Y); - fe_1(h->Z); -} - -static void ge_p3_0(ge_p3 *h) -{ - fe_0(h->X); - fe_1(h->Y); - fe_1(h->Z); - fe_0(h->T); -} - -static void ge_precomp_0(ge_precomp *h) -{ - fe_1(h->yplusx); - fe_1(h->yminusx); - fe_0(h->xy2d); -} - -/* -r = p -*/ - -static void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p) -{ - fe_mul(r->X,p->X,p->T); - fe_mul(r->Y,p->Y,p->Z); - fe_mul(r->Z,p->Z,p->T); -} - -/* -r = p -*/ - -static void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p) -{ - fe_mul(r->X,p->X,p->T); - fe_mul(r->Y,p->Y,p->Z); - fe_mul(r->Z,p->Z,p->T); - fe_mul(r->T,p->X,p->Y); -} - -/* -r = p -*/ - -static void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p) -{ - fe_copy(r->X,p->X); - fe_copy(r->Y,p->Y); - fe_copy(r->Z,p->Z); -} - - -/* -r = 2 * p -*/ - -static void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p) -{ - fe t0; -/* qhasm: enter ge_p2_dbl */ - -/* qhasm: fe X1 */ - -/* qhasm: fe Y1 */ - -/* qhasm: fe Z1 */ - -/* qhasm: fe A */ - -/* qhasm: fe AA */ - -/* qhasm: fe XX */ - -/* qhasm: fe YY */ - -/* qhasm: fe B */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Y3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe T3 */ - -/* qhasm: XX=X1^2 */ -/* asm 1: fe_sq(>XX=fe#1,XX=r->X,X); */ -fe_sq(r->X,p->X); - -/* qhasm: YY=Y1^2 */ -/* asm 1: fe_sq(>YY=fe#3,YY=r->Z,Y); */ -fe_sq(r->Z,p->Y); - -/* qhasm: B=2*Z1^2 */ -/* asm 1: fe_sq2(>B=fe#4,B=r->T,Z); */ -fe_sq2(r->T,p->Z); - -/* qhasm: A=X1+Y1 */ -/* asm 1: fe_add(>A=fe#2,A=r->Y,X,Y); */ -fe_add(r->Y,p->X,p->Y); - -/* qhasm: AA=A^2 */ -/* asm 1: fe_sq(>AA=fe#5,AA=t0,Y); */ -fe_sq(t0,r->Y); - -/* qhasm: Y3=YY+XX */ -/* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,X); */ -fe_add(r->Y,r->Z,r->X); - -/* qhasm: Z3=YY-XX */ -/* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,Z,X); */ -fe_sub(r->Z,r->Z,r->X); - -/* qhasm: X3=AA-Y3 */ -/* asm 1: fe_sub(>X3=fe#1,X3=r->X,Y); */ -fe_sub(r->X,t0,r->Y); - -/* qhasm: T3=B-Z3 */ -/* asm 1: fe_sub(>T3=fe#4,T3=r->T,T,Z); */ -fe_sub(r->T,r->T,r->Z); - -/* qhasm: return */ -} - - -/* -r = 2 * p -*/ - -static void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p) -{ - ge_p2 q; - ge_p3_to_p2(&q,p); - ge_p2_dbl(r,&q); -} - - -/* -r = p -*/ - -static void ge_p3_to_cached(ge_cached *r,const ge_p3 *p) -{ - fe_add(r->YplusX,p->Y,p->X); - fe_sub(r->YminusX,p->Y,p->X); - fe_copy(r->Z,p->Z); - fe_mul(r->T2d,p->T,d2); -} - -/* -r = p + q -*/ - -static void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) -{ - fe t0; -/* qhasm: enter ge_add */ - -/* qhasm: fe X1 */ - -/* qhasm: fe Y1 */ - -/* qhasm: fe Z1 */ - -/* qhasm: fe Z2 */ - -/* qhasm: fe T1 */ - -/* qhasm: fe ZZ */ - -/* qhasm: fe YpX2 */ - -/* qhasm: fe YmX2 */ - -/* qhasm: fe T2d2 */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Y3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe T3 */ - -/* qhasm: fe YpX1 */ - -/* qhasm: fe YmX1 */ - -/* qhasm: fe A */ - -/* qhasm: fe B */ - -/* qhasm: fe C */ - -/* qhasm: fe D */ - -/* qhasm: YpX1 = Y1+X1 */ -/* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ -fe_add(r->X,p->Y,p->X); - -/* qhasm: YmX1 = Y1-X1 */ -/* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ -fe_sub(r->Y,p->Y,p->X); - -/* qhasm: A = YpX1*YpX2 */ -/* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YplusX); */ -fe_mul(r->Z,r->X,q->YplusX); - -/* qhasm: B = YmX1*YmX2 */ -/* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YminusX); */ -fe_mul(r->Y,r->Y,q->YminusX); - -/* qhasm: C = T2d2*T1 */ -/* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ -fe_mul(r->T,q->T2d,p->T); - -/* qhasm: ZZ = Z1*Z2 */ -/* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ -fe_mul(r->X,p->Z,q->Z); - -/* qhasm: D = 2*ZZ */ -/* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ -fe_add(t0,r->X,r->X); - -/* qhasm: X3 = A-B */ -/* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ -fe_sub(r->X,r->Z,r->Y); - -/* qhasm: Y3 = A+B */ -/* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ -fe_add(r->Y,r->Z,r->Y); - -/* qhasm: Z3 = D+C */ -/* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ -fe_add(r->Z,t0,r->T); - -/* qhasm: T3 = D-C */ -/* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ -fe_sub(r->T,t0,r->T); - -/* qhasm: return */ -} - - -/* -r = p - q -*/ - -static void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) -{ - fe t0; -/* qhasm: enter ge_sub */ - -/* qhasm: fe X1 */ - -/* qhasm: fe Y1 */ - -/* qhasm: fe Z1 */ - -/* qhasm: fe Z2 */ - -/* qhasm: fe T1 */ - -/* qhasm: fe ZZ */ - -/* qhasm: fe YpX2 */ - -/* qhasm: fe YmX2 */ - -/* qhasm: fe T2d2 */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Y3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe T3 */ - -/* qhasm: fe YpX1 */ - -/* qhasm: fe YmX1 */ - -/* qhasm: fe A */ - -/* qhasm: fe B */ - -/* qhasm: fe C */ - -/* qhasm: fe D */ - -/* qhasm: YpX1 = Y1+X1 */ -/* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ -fe_add(r->X,p->Y,p->X); - -/* qhasm: YmX1 = Y1-X1 */ -/* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ -fe_sub(r->Y,p->Y,p->X); - -/* qhasm: A = YpX1*YmX2 */ -/* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YminusX); */ -fe_mul(r->Z,r->X,q->YminusX); - -/* qhasm: B = YmX1*YpX2 */ -/* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YplusX); */ -fe_mul(r->Y,r->Y,q->YplusX); - -/* qhasm: C = T2d2*T1 */ -/* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ -fe_mul(r->T,q->T2d,p->T); - -/* qhasm: ZZ = Z1*Z2 */ -/* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ -fe_mul(r->X,p->Z,q->Z); - -/* qhasm: D = 2*ZZ */ -/* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ -fe_add(t0,r->X,r->X); - -/* qhasm: X3 = A-B */ -/* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ -fe_sub(r->X,r->Z,r->Y); - -/* qhasm: Y3 = A+B */ -/* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ -fe_add(r->Y,r->Z,r->Y); - -/* qhasm: Z3 = D-C */ -/* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ -fe_sub(r->Z,t0,r->T); - -/* qhasm: T3 = D+C */ -/* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ -fe_add(r->T,t0,r->T); - -/* qhasm: return */ -} - - -/* -r = p + q -*/ - -static void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) -{ - fe t0; -/* qhasm: enter ge_madd */ - -/* qhasm: fe X1 */ - -/* qhasm: fe Y1 */ - -/* qhasm: fe Z1 */ - -/* qhasm: fe T1 */ - -/* qhasm: fe ypx2 */ - -/* qhasm: fe ymx2 */ - -/* qhasm: fe xy2d2 */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Y3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe T3 */ - -/* qhasm: fe YpX1 */ - -/* qhasm: fe YmX1 */ - -/* qhasm: fe A */ - -/* qhasm: fe B */ - -/* qhasm: fe C */ - -/* qhasm: fe D */ - -/* qhasm: YpX1 = Y1+X1 */ -/* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ -fe_add(r->X,p->Y,p->X); - -/* qhasm: YmX1 = Y1-X1 */ -/* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ -fe_sub(r->Y,p->Y,p->X); - -/* qhasm: A = YpX1*ypx2 */ -/* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yplusx); */ -fe_mul(r->Z,r->X,q->yplusx); - -/* qhasm: B = YmX1*ymx2 */ -/* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yminusx); */ -fe_mul(r->Y,r->Y,q->yminusx); - -/* qhasm: C = xy2d2*T1 */ -/* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ -fe_mul(r->T,q->xy2d,p->T); - -/* qhasm: D = 2*Z1 */ -/* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ -fe_add(t0,p->Z,p->Z); - -/* qhasm: X3 = A-B */ -/* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ -fe_sub(r->X,r->Z,r->Y); - -/* qhasm: Y3 = A+B */ -/* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ -fe_add(r->Y,r->Z,r->Y); - -/* qhasm: Z3 = D+C */ -/* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ -fe_add(r->Z,t0,r->T); - -/* qhasm: T3 = D-C */ -/* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ -fe_sub(r->T,t0,r->T); - -/* qhasm: return */ -} - - -/* -r = p - q -*/ - -static void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) -{ - fe t0; -/* qhasm: enter ge_msub */ - -/* qhasm: fe X1 */ - -/* qhasm: fe Y1 */ - -/* qhasm: fe Z1 */ - -/* qhasm: fe T1 */ - -/* qhasm: fe ypx2 */ - -/* qhasm: fe ymx2 */ - -/* qhasm: fe xy2d2 */ - -/* qhasm: fe X3 */ - -/* qhasm: fe Y3 */ - -/* qhasm: fe Z3 */ - -/* qhasm: fe T3 */ - -/* qhasm: fe YpX1 */ - -/* qhasm: fe YmX1 */ - -/* qhasm: fe A */ - -/* qhasm: fe B */ - -/* qhasm: fe C */ - -/* qhasm: fe D */ - -/* qhasm: YpX1 = Y1+X1 */ -/* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ -fe_add(r->X,p->Y,p->X); - -/* qhasm: YmX1 = Y1-X1 */ -/* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ -fe_sub(r->Y,p->Y,p->X); - -/* qhasm: A = YpX1*ymx2 */ -/* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yminusx); */ -fe_mul(r->Z,r->X,q->yminusx); - -/* qhasm: B = YmX1*ypx2 */ -/* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yplusx); */ -fe_mul(r->Y,r->Y,q->yplusx); - -/* qhasm: C = xy2d2*T1 */ -/* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ -fe_mul(r->T,q->xy2d,p->T); - -/* qhasm: D = 2*Z1 */ -/* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ -fe_add(t0,p->Z,p->Z); - -/* qhasm: X3 = A-B */ -/* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ -fe_sub(r->X,r->Z,r->Y); - -/* qhasm: Y3 = A+B */ -/* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ -fe_add(r->Y,r->Z,r->Y); - -/* qhasm: Z3 = D-C */ -/* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ -fe_sub(r->Z,t0,r->T); - -/* qhasm: T3 = D+C */ -/* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ -fe_add(r->T,t0,r->T); - -/* qhasm: return */ -} - - -static void ge_p3_tobytes(unsigned char *s,const ge_p3 *h) -{ - fe recip; - fe x; - fe y; - - fe_invert(recip,h->Z); - fe_mul(x,h->X,recip); - fe_mul(y,h->Y,recip); - fe_tobytes(s,y); - s[31] ^= fe_isnegative(x) << 7; -} - -static void ge_tobytes(unsigned char *s,const ge_p2 *h) -{ - fe recip; - fe x; - fe y; - - fe_invert(recip,h->Z); - fe_mul(x,h->X,recip); - fe_mul(y,h->Y,recip); - fe_tobytes(s,y); - s[31] ^= fe_isnegative(x) << 7; -} - -static int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s) -{ - fe u; - fe v; - fe v3; - fe vxx; - fe check; - - fe_frombytes(h->Y,s); - fe_1(h->Z); - fe_sq(u,h->Y); - fe_mul(v,u,d); - fe_sub(u,u,h->Z); /* u = y^2-1 */ - fe_add(v,v,h->Z); /* v = dy^2+1 */ - - fe_sq(v3,v); - fe_mul(v3,v3,v); /* v3 = v^3 */ - fe_sq(h->X,v3); - fe_mul(h->X,h->X,v); - fe_mul(h->X,h->X,u); /* x = uv^7 */ - - fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ - fe_mul(h->X,h->X,v3); - fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ - - fe_sq(vxx,h->X); - fe_mul(vxx,vxx,v); - fe_sub(check,vxx,u); /* vx^2-u */ - if (fe_isnonzero(check)) { - fe_add(check,vxx,u); /* vx^2+u */ - if (fe_isnonzero(check)) return -1; - fe_mul(h->X,h->X,sqrtm1); - } - - if (fe_isnegative(h->X) == (s[31] >> 7)) - fe_neg(h->X,h->X); - - fe_mul(h->T,h->X,h->Y); - return 0; -} - - -static void slide(signed char *r,const unsigned char *a) -{ - int i; - int b; - int k; - - for (i = 0;i < 256;++i) - r[i] = 1 & (a[i >> 3] >> (i & 7)); - - for (i = 0;i < 256;++i) - if (r[i]) { - for (b = 1;b <= 6 && i + b < 256;++b) { - if (r[i + b]) { - if (r[i] + (r[i + b] << b) <= 15) { - r[i] += r[i + b] << b; r[i + b] = 0; - } else if (r[i] - (r[i + b] << b) >= -15) { - r[i] -= r[i + b] << b; - for (k = i + b;k < 256;++k) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else - break; - } - } - } - -} - - -/* -r = a * A + b * B -where a = a[0]+256*a[1]+...+256^31 a[31]. -and b = b[0]+256*b[1]+...+256^31 b[31]. -B is the Ed25519 base point (x,4/5) with x positive. -*/ - -static void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b) -{ - signed char aslide[256]; - signed char bslide[256]; - ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ - ge_p1p1 t; - ge_p3 u; - ge_p3 A2; - int i; - - slide(aslide,a); - slide(bslide,b); - - ge_p3_to_cached(&Ai[0],A); - ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); - ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); - ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); - ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); - ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); - ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); - ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); - ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); - - ge_p2_0(r); - - for (i = 255;i >= 0;--i) { - if (aslide[i] || bslide[i]) break; - } - - for (;i >= 0;--i) { - ge_p2_dbl(&t,r); - - if (aslide[i] > 0) { - ge_p1p1_to_p3(&u,&t); - ge_add(&t,&u,&Ai[aslide[i]/2]); - } else if (aslide[i] < 0) { - ge_p1p1_to_p3(&u,&t); - ge_sub(&t,&u,&Ai[(-aslide[i])/2]); - } - - if (bslide[i] > 0) { - ge_p1p1_to_p3(&u,&t); - ge_madd(&t,&u,&Bi[bslide[i]/2]); - } else if (bslide[i] < 0) { - ge_p1p1_to_p3(&u,&t); - ge_msub(&t,&u,&Bi[(-bslide[i])/2]); - } - - ge_p1p1_to_p2(r,&t); - } -} - -static unsigned char equal(signed char b,signed char c) -{ - unsigned char ub = b; - unsigned char uc = c; - unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ - crypto_uint32 y = x; /* 0: yes; 1..255: no */ - y -= 1; /* 4294967295: yes; 0..254: no */ - y >>= 31; /* 1: yes; 0: no */ - return y; -} - -static unsigned char negative(signed char b) -{ - unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ - x >>= 63; /* 1: yes; 0: no */ - return x; -} - -static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b) -{ - fe_cmov(t->yplusx,u->yplusx,b); - fe_cmov(t->yminusx,u->yminusx,b); - fe_cmov(t->xy2d,u->xy2d,b); -} - - - -static void select(ge_precomp *t,int pos,signed char b) -{ - ge_precomp minust; - unsigned char bnegative = negative(b); - unsigned char babs = b - (((-bnegative) & b) << 1); - - ge_precomp_0(t); - cmov(t,&base[pos][0],equal(babs,1)); - cmov(t,&base[pos][1],equal(babs,2)); - cmov(t,&base[pos][2],equal(babs,3)); - cmov(t,&base[pos][3],equal(babs,4)); - cmov(t,&base[pos][4],equal(babs,5)); - cmov(t,&base[pos][5],equal(babs,6)); - cmov(t,&base[pos][6],equal(babs,7)); - cmov(t,&base[pos][7],equal(babs,8)); - fe_copy(minust.yplusx,t->yminusx); - fe_copy(minust.yminusx,t->yplusx); - fe_neg(minust.xy2d,t->xy2d); - cmov(t,&minust,bnegative); -} - -/* -h = a * B -where a = a[0]+256*a[1]+...+256^31 a[31] -B is the Ed25519 base point (x,4/5) with x positive. - -Preconditions: - a[31] <= 127 -*/ - -static void ge_scalarmult_base(ge_p3 *h,const unsigned char *a) -{ - signed char e[64]; - signed char carry; - ge_p1p1 r; - ge_p2 s; - ge_precomp t; - int i; - - for (i = 0;i < 32;++i) { - e[2 * i + 0] = (a[i] >> 0) & 15; - e[2 * i + 1] = (a[i] >> 4) & 15; - } - /* each e[i] is between 0 and 15 */ - /* e[63] is between 0 and 7 */ - - carry = 0; - for (i = 0;i < 63;++i) { - e[i] += carry; - carry = e[i] + 8; - carry >>= 4; - e[i] -= carry << 4; - } - e[63] += carry; - /* each e[i] is between -8 and 8 */ - - ge_p3_0(h); - for (i = 1;i < 64;i += 2) { - select(&t,i / 2,e[i]); - ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); - } - - ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r); - ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); - ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); - ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r); - - for (i = 0;i < 64;i += 2) { - select(&t,i / 2,e[i]); - ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); - } -} - -/* -Input: - s[0]+256*s[1]+...+256^63*s[63] = s - -Output: - s[0]+256*s[1]+...+256^31*s[31] = s mod l - where l = 2^252 + 27742317777372353535851937790883648493. - Overwrites s in place. -*/ - -static void sc_reduce(unsigned char *s) -{ - crypto_int64 s0 = 2097151 & load_3(s); - crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5); - crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2); - crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7); - crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4); - crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1); - crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6); - crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3); - crypto_int64 s8 = 2097151 & load_3(s + 21); - crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5); - crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2); - crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7); - crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4); - crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1); - crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6); - crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3); - crypto_int64 s16 = 2097151 & load_3(s + 42); - crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5); - crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2); - crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7); - crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4); - crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1); - crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6); - crypto_int64 s23 = (load_4(s + 60) >> 3); - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - crypto_int64 carry10; - crypto_int64 carry11; - crypto_int64 carry12; - crypto_int64 carry13; - crypto_int64 carry14; - crypto_int64 carry15; - crypto_int64 carry16; - - s11 += s23 * 666643; - s12 += s23 * 470296; - s13 += s23 * 654183; - s14 -= s23 * 997805; - s15 += s23 * 136657; - s16 -= s23 * 683901; - s23 = 0; - - s10 += s22 * 666643; - s11 += s22 * 470296; - s12 += s22 * 654183; - s13 -= s22 * 997805; - s14 += s22 * 136657; - s15 -= s22 * 683901; - s22 = 0; - - s9 += s21 * 666643; - s10 += s21 * 470296; - s11 += s21 * 654183; - s12 -= s21 * 997805; - s13 += s21 * 136657; - s14 -= s21 * 683901; - s21 = 0; - - s8 += s20 * 666643; - s9 += s20 * 470296; - s10 += s20 * 654183; - s11 -= s20 * 997805; - s12 += s20 * 136657; - s13 -= s20 * 683901; - s20 = 0; - - s7 += s19 * 666643; - s8 += s19 * 470296; - s9 += s19 * 654183; - s10 -= s19 * 997805; - s11 += s19 * 136657; - s12 -= s19 * 683901; - s19 = 0; - - s6 += s18 * 666643; - s7 += s18 * 470296; - s8 += s18 * 654183; - s9 -= s18 * 997805; - s10 += s18 * 136657; - s11 -= s18 * 683901; - s18 = 0; - - carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; - carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; - carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; - carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; - carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; - carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; - - carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; - carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; - carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; - carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; - carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; - - s5 += s17 * 666643; - s6 += s17 * 470296; - s7 += s17 * 654183; - s8 -= s17 * 997805; - s9 += s17 * 136657; - s10 -= s17 * 683901; - s17 = 0; - - s4 += s16 * 666643; - s5 += s16 * 470296; - s6 += s16 * 654183; - s7 -= s16 * 997805; - s8 += s16 * 136657; - s9 -= s16 * 683901; - s16 = 0; - - s3 += s15 * 666643; - s4 += s15 * 470296; - s5 += s15 * 654183; - s6 -= s15 * 997805; - s7 += s15 * 136657; - s8 -= s15 * 683901; - s15 = 0; - - s2 += s14 * 666643; - s3 += s14 * 470296; - s4 += s14 * 654183; - s5 -= s14 * 997805; - s6 += s14 * 136657; - s7 -= s14 * 683901; - s14 = 0; - - s1 += s13 * 666643; - s2 += s13 * 470296; - s3 += s13 * 654183; - s4 -= s13 * 997805; - s5 += s13 * 136657; - s6 -= s13 * 683901; - s13 = 0; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; - carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; - carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; - carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; - carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; - carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; - - carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; - carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; - carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; - carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; - carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; - carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; - carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; - carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; - carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; - carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; - carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; - carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; - carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; - carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; - carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; - carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; - carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; - carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; - carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; - carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; - carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; - carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; - carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; - carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; - carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; - carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; - carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; - - s[0] = s0 >> 0; - s[1] = s0 >> 8; - s[2] = (s0 >> 16) | (s1 << 5); - s[3] = s1 >> 3; - s[4] = s1 >> 11; - s[5] = (s1 >> 19) | (s2 << 2); - s[6] = s2 >> 6; - s[7] = (s2 >> 14) | (s3 << 7); - s[8] = s3 >> 1; - s[9] = s3 >> 9; - s[10] = (s3 >> 17) | (s4 << 4); - s[11] = s4 >> 4; - s[12] = s4 >> 12; - s[13] = (s4 >> 20) | (s5 << 1); - s[14] = s5 >> 7; - s[15] = (s5 >> 15) | (s6 << 6); - s[16] = s6 >> 2; - s[17] = s6 >> 10; - s[18] = (s6 >> 18) | (s7 << 3); - s[19] = s7 >> 5; - s[20] = s7 >> 13; - s[21] = s8 >> 0; - s[22] = s8 >> 8; - s[23] = (s8 >> 16) | (s9 << 5); - s[24] = s9 >> 3; - s[25] = s9 >> 11; - s[26] = (s9 >> 19) | (s10 << 2); - s[27] = s10 >> 6; - s[28] = (s10 >> 14) | (s11 << 7); - s[29] = s11 >> 1; - s[30] = s11 >> 9; - s[31] = s11 >> 17; -} - -/* -Input: - a[0]+256*a[1]+...+256^31*a[31] = a - b[0]+256*b[1]+...+256^31*b[31] = b - c[0]+256*c[1]+...+256^31*c[31] = c - -Output: - s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l - where l = 2^252 + 27742317777372353535851937790883648493. -*/ - -static void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c) -{ - crypto_int64 a0 = 2097151 & load_3(a); - crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5); - crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2); - crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7); - crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4); - crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1); - crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6); - crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3); - crypto_int64 a8 = 2097151 & load_3(a + 21); - crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5); - crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2); - crypto_int64 a11 = (load_4(a + 28) >> 7); - crypto_int64 b0 = 2097151 & load_3(b); - crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5); - crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2); - crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7); - crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4); - crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1); - crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6); - crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3); - crypto_int64 b8 = 2097151 & load_3(b + 21); - crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5); - crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2); - crypto_int64 b11 = (load_4(b + 28) >> 7); - crypto_int64 c0 = 2097151 & load_3(c); - crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5); - crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2); - crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7); - crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4); - crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1); - crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6); - crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3); - crypto_int64 c8 = 2097151 & load_3(c + 21); - crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5); - crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2); - crypto_int64 c11 = (load_4(c + 28) >> 7); - crypto_int64 s0; - crypto_int64 s1; - crypto_int64 s2; - crypto_int64 s3; - crypto_int64 s4; - crypto_int64 s5; - crypto_int64 s6; - crypto_int64 s7; - crypto_int64 s8; - crypto_int64 s9; - crypto_int64 s10; - crypto_int64 s11; - crypto_int64 s12; - crypto_int64 s13; - crypto_int64 s14; - crypto_int64 s15; - crypto_int64 s16; - crypto_int64 s17; - crypto_int64 s18; - crypto_int64 s19; - crypto_int64 s20; - crypto_int64 s21; - crypto_int64 s22; - crypto_int64 s23; - crypto_int64 carry0; - crypto_int64 carry1; - crypto_int64 carry2; - crypto_int64 carry3; - crypto_int64 carry4; - crypto_int64 carry5; - crypto_int64 carry6; - crypto_int64 carry7; - crypto_int64 carry8; - crypto_int64 carry9; - crypto_int64 carry10; - crypto_int64 carry11; - crypto_int64 carry12; - crypto_int64 carry13; - crypto_int64 carry14; - crypto_int64 carry15; - crypto_int64 carry16; - crypto_int64 carry17; - crypto_int64 carry18; - crypto_int64 carry19; - crypto_int64 carry20; - crypto_int64 carry21; - crypto_int64 carry22; - - s0 = c0 + a0*b0; - s1 = c1 + a0*b1 + a1*b0; - s2 = c2 + a0*b2 + a1*b1 + a2*b0; - s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0; - s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0; - s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0; - s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0; - s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0; - s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0; - s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0; - s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0; - s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0; - s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1; - s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2; - s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3; - s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4; - s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5; - s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6; - s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7; - s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8; - s20 = a9*b11 + a10*b10 + a11*b9; - s21 = a10*b11 + a11*b10; - s22 = a11*b11; - s23 = 0; - - carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; - carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; - carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; - carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; - carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; - carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; - carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; - carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; - carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; - carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21; - carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21; - carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21; - - carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; - carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; - carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; - carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; - carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; - carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; - carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; - carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; - carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21; - carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21; - carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21; - - s11 += s23 * 666643; - s12 += s23 * 470296; - s13 += s23 * 654183; - s14 -= s23 * 997805; - s15 += s23 * 136657; - s16 -= s23 * 683901; - s23 = 0; - - s10 += s22 * 666643; - s11 += s22 * 470296; - s12 += s22 * 654183; - s13 -= s22 * 997805; - s14 += s22 * 136657; - s15 -= s22 * 683901; - s22 = 0; - - s9 += s21 * 666643; - s10 += s21 * 470296; - s11 += s21 * 654183; - s12 -= s21 * 997805; - s13 += s21 * 136657; - s14 -= s21 * 683901; - s21 = 0; - - s8 += s20 * 666643; - s9 += s20 * 470296; - s10 += s20 * 654183; - s11 -= s20 * 997805; - s12 += s20 * 136657; - s13 -= s20 * 683901; - s20 = 0; - - s7 += s19 * 666643; - s8 += s19 * 470296; - s9 += s19 * 654183; - s10 -= s19 * 997805; - s11 += s19 * 136657; - s12 -= s19 * 683901; - s19 = 0; - - s6 += s18 * 666643; - s7 += s18 * 470296; - s8 += s18 * 654183; - s9 -= s18 * 997805; - s10 += s18 * 136657; - s11 -= s18 * 683901; - s18 = 0; - - carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; - carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; - carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; - carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; - carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; - carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; - - carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; - carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; - carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; - carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; - carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; - - s5 += s17 * 666643; - s6 += s17 * 470296; - s7 += s17 * 654183; - s8 -= s17 * 997805; - s9 += s17 * 136657; - s10 -= s17 * 683901; - s17 = 0; - - s4 += s16 * 666643; - s5 += s16 * 470296; - s6 += s16 * 654183; - s7 -= s16 * 997805; - s8 += s16 * 136657; - s9 -= s16 * 683901; - s16 = 0; - - s3 += s15 * 666643; - s4 += s15 * 470296; - s5 += s15 * 654183; - s6 -= s15 * 997805; - s7 += s15 * 136657; - s8 -= s15 * 683901; - s15 = 0; - - s2 += s14 * 666643; - s3 += s14 * 470296; - s4 += s14 * 654183; - s5 -= s14 * 997805; - s6 += s14 * 136657; - s7 -= s14 * 683901; - s14 = 0; - - s1 += s13 * 666643; - s2 += s13 * 470296; - s3 += s13 * 654183; - s4 -= s13 * 997805; - s5 += s13 * 136657; - s6 -= s13 * 683901; - s13 = 0; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; - carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; - carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; - carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; - carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; - carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; - - carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; - carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; - carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; - carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; - carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; - carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; - carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; - carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; - carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; - carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; - carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; - carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; - carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; - carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; - carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; - carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; - carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; - - s0 += s12 * 666643; - s1 += s12 * 470296; - s2 += s12 * 654183; - s3 -= s12 * 997805; - s4 += s12 * 136657; - s5 -= s12 * 683901; - s12 = 0; - - carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; - carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; - carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; - carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; - carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; - carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; - carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; - carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; - carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; - carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; - carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; - - s[0] = s0 >> 0; - s[1] = s0 >> 8; - s[2] = (s0 >> 16) | (s1 << 5); - s[3] = s1 >> 3; - s[4] = s1 >> 11; - s[5] = (s1 >> 19) | (s2 << 2); - s[6] = s2 >> 6; - s[7] = (s2 >> 14) | (s3 << 7); - s[8] = s3 >> 1; - s[9] = s3 >> 9; - s[10] = (s3 >> 17) | (s4 << 4); - s[11] = s4 >> 4; - s[12] = s4 >> 12; - s[13] = (s4 >> 20) | (s5 << 1); - s[14] = s5 >> 7; - s[15] = (s5 >> 15) | (s6 << 6); - s[16] = s6 >> 2; - s[17] = s6 >> 10; - s[18] = (s6 >> 18) | (s7 << 3); - s[19] = s7 >> 5; - s[20] = s7 >> 13; - s[21] = s8 >> 0; - s[22] = s8 >> 8; - s[23] = (s8 >> 16) | (s9 << 5); - s[24] = s9 >> 3; - s[25] = s9 >> 11; - s[26] = (s9 >> 19) | (s10 << 2); - s[27] = s10 >> 6; - s[28] = (s10 >> 14) | (s11 << 7); - s[29] = s11 >> 1; - s[30] = s11 >> 9; - s[31] = s11 >> 17; -} - -/* -int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) -{ - unsigned char h[64]; - ge_p3 A; - int i; - - randombytes(sk,32); - crypto_hash_sha512(h,sk,32); - h[0] &= 248; - h[31] &= 63; - h[31] |= 64; - - ge_scalarmult_base(&A,h); - ge_p3_tobytes(pk,&A); - - for (i = 0;i < 32;++i) sk[32 + i] = pk[i]; - return 0; -} -*/ - -int crypto_sign_pk_ref10(unsigned char *pk,unsigned char *sk) -{ - unsigned char h[64]; - ge_p3 A; - int i; - - crypto_hash_sha512(h,sk,32); - h[0] &= 248; - h[31] &= 63; - h[31] |= 64; - - ge_scalarmult_base(&A,h); - ge_p3_tobytes(pk,&A); - - for (i = 0;i < 32;++i) sk[32 + i] = pk[i]; - return 0; -} - -int crypto_sign_ref10( - unsigned char *sm,unsigned long long *smlen, - const unsigned char *m,unsigned long long mlen, - const unsigned char *sk -) -{ - unsigned char az[64]; - unsigned char r[64]; - unsigned char hram[64]; - ge_p3 R; - unsigned long long i; - - crypto_hash_sha512(az,sk,32); - az[0] &= 248; - az[31] &= 63; - az[31] |= 64; - - *smlen = mlen + 64; - for (i = 0;i < mlen;++i) sm[64 + i] = m[i]; - for (i = 0;i < 32;++i) sm[32 + i] = az[32 + i]; - crypto_hash_sha512(r,sm + 32,mlen + 32); - for (i = 0;i < 32;++i) sm[32 + i] = sk[32 + i]; - - sc_reduce(r); - ge_scalarmult_base(&R,r); - ge_p3_tobytes(sm,&R); - - crypto_hash_sha512(hram,sm,mlen + 64); - sc_reduce(hram); - sc_muladd(sm + 32,hram,az,r); - - return 0; -} - -int crypto_sign_open_ref10( - unsigned char *m,unsigned long long *mlen, - const unsigned char *sm,unsigned long long smlen, - const unsigned char *pk -) -{ - unsigned char h[64]; - unsigned char checkr[32]; - ge_p3 A; - ge_p2 R; - unsigned long long i; - - *mlen = -1; - if (smlen < 64) return -1; - if (sm[63] & 224) return -1; - if (ge_frombytes_negate_vartime(&A,pk) != 0) return -1; - - for (i = 0;i < smlen;++i) m[i] = sm[i]; - for (i = 0;i < 32;++i) m[32 + i] = pk[i]; - crypto_hash_sha512(h,m,smlen); - sc_reduce(h); - - ge_double_scalarmult_vartime(&R,h,&A,sm + 32); - ge_tobytes(checkr,&R); - if (crypto_verify_32(checkr,sm) != 0) { - for (i = 0;i < smlen;++i) m[i] = 0; - return -1; - } - - for (i = 0;i < smlen - 64;++i) m[i] = sm[64 + i]; - for (i = smlen - 64;i < smlen;++i) m[i] = 0; - *mlen = smlen - 64; - return 0; -} - diff --git a/external/ed25519-donna/fuzz/ed25519-ref10.h b/external/ed25519-donna/fuzz/ed25519-ref10.h deleted file mode 100644 index c8a0f69b65..0000000000 --- a/external/ed25519-donna/fuzz/ed25519-ref10.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ED25519_REF10_H -#define ED25519_REF10_H - -int crypto_sign_pk_ref10(unsigned char *pk,unsigned char *sk); -int crypto_sign_ref10(unsigned char *sm,unsigned long long *smlen,const unsigned char *m,unsigned long long mlen,const unsigned char *sk); -int crypto_sign_open_ref10(unsigned char *m,unsigned long long *mlen,const unsigned char *sm,unsigned long long smlen,const unsigned char *pk); - -#endif /* ED25519_REF10_H */ - diff --git a/external/ed25519-donna/fuzz/fuzz-curve25519.c b/external/ed25519-donna/fuzz/fuzz-curve25519.c deleted file mode 100644 index 43017014c2..0000000000 --- a/external/ed25519-donna/fuzz/fuzz-curve25519.c +++ /dev/null @@ -1,172 +0,0 @@ -#if defined(_WIN32) - #include - #include - typedef unsigned int uint32_t; - typedef unsigned __int64 uint64_t; -#else - #include -#endif - -#include -#include - -#include "ed25519-donna.h" -#include "curve25519-ref10.h" - -static void -print_diff(const char *desc, const unsigned char *a, const unsigned char *b, size_t len) { - size_t p = 0; - unsigned char diff; - printf("%s diff:\n", desc); - while (len--) { - diff = *a++ ^ *b++; - if (!diff) - printf("____,"); - else - printf("0x%02x,", diff); - if ((++p & 15) == 0) - printf("\n"); - } - printf("\n\n"); -} - -static void -print_bytes(const char *desc, const unsigned char *bytes, size_t len) { - size_t p = 0; - printf("%s:\n", desc); - while (len--) { - printf("0x%02x,", *bytes++); - if ((++p & 15) == 0) - printf("\n"); - } - printf("\n\n"); -} - - -/* chacha20/12 prng */ -void -prng(unsigned char *out, size_t bytes) { - static uint32_t state[16]; - static int init = 0; - uint32_t x[16], t; - size_t i; - - if (!init) { - #if defined(_WIN32) - HCRYPTPROV csp; - if (!CryptAcquireContext(&csp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - printf("CryptAcquireContext failed\n"); - exit(1); - } - if (!CryptGenRandom(csp, (DWORD)sizeof(state), (BYTE*)state)) { - printf("CryptGenRandom failed\n"); - exit(1); - } - CryptReleaseContext(csp, 0); - #else - FILE *f = NULL; - f = fopen("/dev/urandom", "rb"); - if (!f) { - printf("failed to open /dev/urandom\n"); - exit(1); - } - if (fread(state, sizeof(state), 1, f) != 1) { - printf("read error on /dev/urandom\n"); - exit(1); - } - #endif - init = 1; - } - - while (bytes) { - for (i = 0; i < 16; i++) x[i] = state[i]; - - #define rotl32(x,k) ((x << k) | (x >> (32 - k))) - #define quarter(a,b,c,d) \ - x[a] += x[b]; t = x[d]^x[a]; x[d] = rotl32(t,16); \ - x[c] += x[d]; t = x[b]^x[c]; x[b] = rotl32(t,12); \ - x[a] += x[b]; t = x[d]^x[a]; x[d] = rotl32(t, 8); \ - x[c] += x[d]; t = x[b]^x[c]; x[b] = rotl32(t, 7); - - for (i = 0; i < 12; i += 2) { - quarter( 0, 4, 8,12) - quarter( 1, 5, 9,13) - quarter( 2, 6,10,14) - quarter( 3, 7,11,15) - quarter( 0, 5,10,15) - quarter( 1, 6,11,12) - quarter( 2, 7, 8,13) - quarter( 3, 4, 9,14) - }; - - if (bytes <= 64) { - memcpy(out, x, bytes); - bytes = 0; - } else { - memcpy(out, x, 64); - bytes -= 64; - out += 64; - } - - /* don't need a nonce, so last 4 words are the counter. 2^136 bytes can be generated */ - if (!++state[12]) if (!++state[13]) if (!++state[14]) ++state[15]; - } -} - - - -int main() { - const size_t skmax = 1024; - static unsigned char sk[1024][32]; - unsigned char pk[3][32]; - unsigned char *skp; - size_t ski, pki, i; - uint64_t ctr; - - printf("fuzzing: "); - printf(" ref10"); - printf(" curved25519"); -#if defined(ED25519_SSE2) - printf(" curved25519-sse2"); -#endif - printf("\n\n"); - - for (ctr = 0, ski = skmax;;ctr++) { - if (ski == skmax) { - prng((unsigned char *)sk, sizeof(sk)); - ski = 0; - } - skp = sk[ski++]; - - pki = 0; - crypto_scalarmult_base_ref10(pk[pki++], skp); - curved25519_scalarmult_basepoint(pk[pki++], skp); - #if defined(ED25519_SSE2) - curved25519_scalarmult_basepoint_sse2(pk[pki++], skp); - #endif - - for (i = 1; i < pki; i++) { - if (memcmp(pk[0], pk[i], 32) != 0) { - printf("\n\n"); - print_bytes("sk", skp, 32); - print_bytes("ref10", pk[0], 32); - print_diff("curved25519", pk[0], pk[1], 32); - #if defined(ED25519_SSE2) - print_diff("curved25519-sse2", pk[0], pk[2], 32); - #endif - exit(1); - } - } - - if (ctr && (ctr % 0x1000 == 0)) { - printf("."); - if ((ctr % 0x20000) == 0) { - printf(" ["); - for (i = 0; i < 8; i++) - printf("%02x", (unsigned char)(ctr >> ((7 - i) * 8))); - printf("]\n"); - } - } - } -} - diff --git a/external/ed25519-donna/fuzz/fuzz-ed25519.c b/external/ed25519-donna/fuzz/fuzz-ed25519.c deleted file mode 100644 index b242e8e5da..0000000000 --- a/external/ed25519-donna/fuzz/fuzz-ed25519.c +++ /dev/null @@ -1,219 +0,0 @@ -#if defined(_WIN32) - #include - #include - typedef unsigned int uint32_t; -#else - #include -#endif - -#include -#include - -#include "ed25519-donna.h" -#include "ed25519-ref10.h" - -static void -print_diff(const char *desc, const unsigned char *a, const unsigned char *b, size_t len) { - size_t p = 0; - unsigned char diff; - printf("%s diff:\n", desc); - while (len--) { - diff = *a++ ^ *b++; - if (!diff) - printf("____,"); - else - printf("0x%02x,", diff); - if ((++p & 15) == 0) - printf("\n"); - } - printf("\n"); -} - -static void -print_bytes(const char *desc, const unsigned char *bytes, size_t len) { - size_t p = 0; - printf("%s:\n", desc); - while (len--) { - printf("0x%02x,", *bytes++); - if ((++p & 15) == 0) - printf("\n"); - } - printf("\n"); -} - - -/* chacha20/12 prng */ -void -prng(unsigned char *out, size_t bytes) { - static uint32_t state[16]; - static int init = 0; - uint32_t x[16], t; - size_t i; - - if (!init) { - #if defined(_WIN32) - HCRYPTPROV csp = NULL; - if (!CryptAcquireContext(&csp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - printf("CryptAcquireContext failed\n"); - exit(1); - } - if (!CryptGenRandom(csp, (DWORD)sizeof(state), (BYTE*)state)) { - printf("CryptGenRandom failed\n"); - exit(1); - } - CryptReleaseContext(csp, 0); - #else - FILE *f = NULL; - f = fopen("/dev/urandom", "rb"); - if (!f) { - printf("failed to open /dev/urandom\n"); - exit(1); - } - if (fread(state, sizeof(state), 1, f) != 1) { - printf("read error on /dev/urandom\n"); - exit(1); - } - #endif - init = 1; - } - - while (bytes) { - for (i = 0; i < 16; i++) x[i] = state[i]; - - #define rotl32(x,k) ((x << k) | (x >> (32 - k))) - #define quarter(a,b,c,d) \ - x[a] += x[b]; t = x[d]^x[a]; x[d] = rotl32(t,16); \ - x[c] += x[d]; t = x[b]^x[c]; x[b] = rotl32(t,12); \ - x[a] += x[b]; t = x[d]^x[a]; x[d] = rotl32(t, 8); \ - x[c] += x[d]; t = x[b]^x[c]; x[b] = rotl32(t, 7); - - for (i = 0; i < 12; i += 2) { - quarter( 0, 4, 8,12) - quarter( 1, 5, 9,13) - quarter( 2, 6,10,14) - quarter( 3, 7,11,15) - quarter( 0, 5,10,15) - quarter( 1, 6,11,12) - quarter( 2, 7, 8,13) - quarter( 3, 4, 9,14) - }; - - if (bytes <= 64) { - memcpy(out, x, bytes); - bytes = 0; - } else { - memcpy(out, x, 64); - bytes -= 64; - out += 64; - } - - /* don't need a nonce, so last 4 words are the counter. 2^136 bytes can be generated */ - if (!++state[12]) if (!++state[13]) if (!++state[14]) ++state[15]; - } -} - -typedef struct random_data_t { - unsigned char sk[32]; - unsigned char m[128]; -} random_data; - -typedef struct generated_data_t { - unsigned char pk[32]; - unsigned char sig[64]; - int valid; -} generated_data; - -static void -print_generated(const char *desc, generated_data *g) { - printf("%s:\n", desc); - print_bytes("pk", g->pk, 32); - print_bytes("sig", g->sig, 64); - printf("valid: %s\n\n", g->valid ? "no" : "yes"); -} - -static void -print_generated_diff(const char *desc, const generated_data *base, generated_data *g) { - printf("%s:\n", desc); - print_diff("pk", base->pk, g->pk, 32); - print_diff("sig", base->sig, g->sig, 64); - printf("valid: %s\n\n", (base->valid == g->valid) ? "___" : (g->valid ? "no" : "yes")); -} - -int main() { - const size_t rndmax = 128; - static random_data rnd[128]; - static generated_data gen[3]; - random_data *r; - generated_data *g; - unsigned long long dummylen; - unsigned char dummysk[64]; - unsigned char dummymsg[2][128+64]; - size_t rndi, geni, i, j; - uint64_t ctr; - - printf("fuzzing: "); - printf(" ref10"); - printf(" ed25519-donna"); -#if defined(ED25519_SSE2) - printf(" ed25519-donna-sse2"); -#endif - printf("\n\n"); - - for (ctr = 0, rndi = rndmax;;ctr++) { - if (rndi == rndmax) { - prng((unsigned char *)rnd, sizeof(rnd)); - rndi = 0; - } - r = &rnd[rndi++]; - - /* ref10, lots of horrible gymnastics to work around the wonky api */ - geni = 0; - g = &gen[geni++]; - memcpy(dummysk, r->sk, 32); /* pk is appended to the sk, need to copy the sk to a larger buffer */ - crypto_sign_pk_ref10(dummysk + 32, dummysk); - memcpy(g->pk, dummysk + 32, 32); - crypto_sign_ref10(dummymsg[0], &dummylen, r->m, 128, dummysk); - memcpy(g->sig, dummymsg[0], 64); /* sig is placed in front of the signed message */ - g->valid = crypto_sign_open_ref10(dummymsg[1], &dummylen, dummymsg[0], 128 + 64, g->pk); - - /* ed25519-donna */ - g = &gen[geni++]; - ed25519_publickey(r->sk, g->pk); - ed25519_sign(r->m, 128, r->sk, g->pk, g->sig); - g->valid = ed25519_sign_open(r->m, 128, g->pk, g->sig); - - #if defined(ED25519_SSE2) - /* ed25519-donna-sse2 */ - g = &gen[geni++]; - ed25519_publickey_sse2(r->sk, g->pk); - ed25519_sign_sse2(r->m, 128, r->sk, g->pk, g->sig); - g->valid = ed25519_sign_open_sse2(r->m, 128, g->pk, g->sig); - #endif - - /* compare implementations 1..geni against the reference */ - for (i = 1; i < geni; i++) { - if (memcmp(&gen[0], &gen[i], sizeof(generated_data)) != 0) { - printf("\n\n"); - print_bytes("sk", r->sk, 32); - print_bytes("m", r->m, 128); - print_generated("ref10", &gen[0]); - print_generated_diff("ed25519-donna", &gen[0], &gen[1]); - #if defined(ED25519_SSE2) - print_generated_diff("ed25519-donna-sse2", &gen[0], &gen[2]); - #endif - exit(1); - } - } - - /* print out status */ - if (ctr && (ctr % 0x1000 == 0)) { - printf("."); - if ((ctr % 0x20000) == 0) { - printf(" ["); - for (i = 0; i < 8; i++) - printf("%02x", (unsigned char)(ctr >> ((7 - i) * 8))); - printf("]\n"); - } - } - } -} \ No newline at end of file diff --git a/external/ed25519-donna/modm-donna-32bit.h b/external/ed25519-donna/modm-donna-32bit.h deleted file mode 100644 index dfd76be668..0000000000 --- a/external/ed25519-donna/modm-donna-32bit.h +++ /dev/null @@ -1,469 +0,0 @@ -/* - Public domain by Andrew M. -*/ - - -/* - Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - - k = 32 - b = 1 << 8 = 256 - m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b -*/ - -#define bignum256modm_bits_per_limb 30 -#define bignum256modm_limb_size 9 - -typedef uint32_t bignum256modm_element_t; -typedef bignum256modm_element_t bignum256modm[9]; - -static const bignum256modm modm_m = { - 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, - 0x00000014, 0x00000000, 0x00000000, 0x00000000, - 0x00001000 -}; - -static const bignum256modm modm_mu = { - 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, - 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, - 0x000fffff -}; - -static bignum256modm_element_t -lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { - return (a - b) >> 31; -} - -/* see HAC, Alg. 14.42 Step 4 */ -static void -reduce256_modm(bignum256modm r) { - bignum256modm t; - bignum256modm_element_t b = 0, pb, mask; - - /* t = r - m */ - pb = 0; - pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; - pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; - pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; - pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; - pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; - pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; - pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; - pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; - pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); - - /* keep r if r was smaller than m */ - mask = b - 1; - r[0] ^= mask & (r[0] ^ t[0]); - r[1] ^= mask & (r[1] ^ t[1]); - r[2] ^= mask & (r[2] ^ t[2]); - r[3] ^= mask & (r[3] ^ t[3]); - r[4] ^= mask & (r[4] ^ t[4]); - r[5] ^= mask & (r[5] ^ t[5]); - r[6] ^= mask & (r[6] ^ t[6]); - r[7] ^= mask & (r[7] ^ t[7]); - r[8] ^= mask & (r[8] ^ t[8]); -} - -/* - Barrett reduction, see HAC, Alg. 14.42 - - Instead of passing in x, pre-process in to q1 and r1 for efficiency -*/ -static void -barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { - bignum256modm q3, r2; - uint64_t c; - bignum256modm_element_t f, b, pb; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements - q2 = mu * q1 - q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); - c >>= 30; - c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); - f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); - f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); - f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); - f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); - f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); - f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); - f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); - f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[8], q1[8]); - f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) - r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ - c = mul32x32_64(modm_m[0], q3[0]); - r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); - r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); - r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); - r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); - r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); - r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); - r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); - r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); - r2[8] = (bignum256modm_element_t)(c & 0xffffff); - - /* r = r1 - r2 - if (r < 0) r += (1 << 264) */ - pb = 0; - pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; - pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; - pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; - pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; - pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; - pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; - pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; - pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; - pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); - - reduce256_modm(r); - reduce256_modm(r); -} - -/* addition modulo m */ -static void -add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c; - - c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; - c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; - c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; - c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; - c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; - c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; - c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; - c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; - c += x[8] + y[8]; r[8] = c; - - reduce256_modm(r); -} - -/* multiplication modulo m */ -static void -mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm r1, q1; - uint64_t c; - bignum256modm_element_t f; - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) - q1 = x >> 248 = 264 bits = 9 30 bit elements */ - c = mul32x32_64(x[0], y[0]); - f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); - f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); - f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); - f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); - f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); - f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); - f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); - f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); - f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); - f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); - f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); - f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); - f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); - f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); - f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); - f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[8], y[8]); - f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; - - barrett_reduce256_modm(r, q1, r1); -} - -static void -expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { - unsigned char work[64] = {0}; - bignum256modm_element_t x[16]; - bignum256modm q1; - - memcpy(work, in, len); - x[0] = U8TO32_LE(work + 0); - x[1] = U8TO32_LE(work + 4); - x[2] = U8TO32_LE(work + 8); - x[3] = U8TO32_LE(work + 12); - x[4] = U8TO32_LE(work + 16); - x[5] = U8TO32_LE(work + 20); - x[6] = U8TO32_LE(work + 24); - x[7] = U8TO32_LE(work + 28); - x[8] = U8TO32_LE(work + 32); - x[9] = U8TO32_LE(work + 36); - x[10] = U8TO32_LE(work + 40); - x[11] = U8TO32_LE(work + 44); - x[12] = U8TO32_LE(work + 48); - x[13] = U8TO32_LE(work + 52); - x[14] = U8TO32_LE(work + 56); - x[15] = U8TO32_LE(work + 60); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; - - /* 8*31 = 248 bits, no need to reduce */ - if (len < 32) - return; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ - q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; - q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; - q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; - q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; - q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; - q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; - q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; - q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; - q1[8] = ((x[15] >> 8) ); - - barrett_reduce256_modm(out, q1, out); -} - -static void -expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { - bignum256modm_element_t x[8]; - - x[0] = U8TO32_LE(in + 0); - x[1] = U8TO32_LE(in + 4); - x[2] = U8TO32_LE(in + 8); - x[3] = U8TO32_LE(in + 12); - x[4] = U8TO32_LE(in + 16); - x[5] = U8TO32_LE(in + 20); - x[6] = U8TO32_LE(in + 24); - x[7] = U8TO32_LE(in + 28); - - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; -} - -static void -contract256_modm(unsigned char out[32], const bignum256modm in) { - U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); - U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); - U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); - U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); - U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); - U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); - U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); - U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); -} - - - -static void -contract256_window4_modm(signed char r[64], const bignum256modm in) { - char carry; - signed char *quads = r; - bignum256modm_element_t i, j, v; - - for (i = 0; i < 8; i += 2) { - v = in[i]; - for (j = 0; j < 7; j++) { - *quads++ = (v & 15); - v >>= 4; - } - v |= (in[i+1] << 2); - for (j = 0; j < 8; j++) { - *quads++ = (v & 15); - v >>= 4; - } - } - v = in[8]; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - - /* making it signed */ - carry = 0; - for(i = 0; i < 63; i++) { - r[i] += carry; - r[i+1] += (r[i] >> 4); - r[i] &= 15; - carry = (r[i] >> 3); - r[i] -= (carry << 4); - } - r[63] += carry; -} - -static void -contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { - int i,j,k,b; - int m = (1 << (windowsize - 1)) - 1, soplen = 256; - signed char *bits = r; - bignum256modm_element_t v; - - /* first put the binary expansion into r */ - for (i = 0; i < 8; i++) { - v = s[i]; - for (j = 0; j < 30; j++, v >>= 1) - *bits++ = (v & 1); - } - v = s[8]; - for (j = 0; j < 16; j++, v >>= 1) - *bits++ = (v & 1); - - /* Making it sliding window */ - for (j = 0; j < soplen; j++) { - if (!r[j]) - continue; - - for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { - if ((r[j] + (r[j + b] << b)) <= m) { - r[j] += r[j + b] << b; - r[j + b] = 0; - } else if ((r[j] - (r[j + b] << b)) >= -m) { - r[j] -= r[j + b] << b; - for (k = j + b; k < soplen; k++) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else if (r[j + b]) { - break; - } - } - } -} - - -/* - helpers for batch verifcation, are allowed to be vartime -*/ - -/* out = a - b, a must be larger than b */ -static void -sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t carry = 0; - switch (limbsize) { - case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 0: - default: out[i] = (a[i] - b[i]) - carry; - } -} - - -/* is a < b */ -static int -lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - switch (limbsize) { - case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; - case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; - case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; - case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; - case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; - case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; - case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; - case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; - case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; - } - return 0; -} - -/* is a <= b */ -static int -lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - switch (limbsize) { - case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; - case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; - case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; - case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; - case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; - case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; - case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; - case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; - case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; - } - return 1; -} - - -/* is a == 0 */ -static int -iszero256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 9; i++) - if (a[i]) - return 0; - return 1; -} - -/* is a == 1 */ -static int -isone256_modm_batch(const bignum256modm a) { - size_t i; - if (a[0] != 1) - return 0; - for (i = 1; i < 9; i++) - if (a[i]) - return 0; - return 1; -} - -/* can a fit in to (at most) 128 bits */ -static int -isatmost128bits256_modm_batch(const bignum256modm a) { - uint32_t mask = - ((a[8] ) | /* 16 */ - (a[7] ) | /* 46 */ - (a[6] ) | /* 76 */ - (a[5] ) | /* 106 */ - (a[4] & 0x3fffff00)); /* 128 */ - - return (mask == 0); -} diff --git a/external/ed25519-donna/modm-donna-64bit.h b/external/ed25519-donna/modm-donna-64bit.h deleted file mode 100644 index a47a38a42d..0000000000 --- a/external/ed25519-donna/modm-donna-64bit.h +++ /dev/null @@ -1,361 +0,0 @@ -/* - Public domain by Andrew M. -*/ - - -/* - Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - - k = 32 - b = 1 << 8 = 256 - m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b -*/ - -#define bignum256modm_bits_per_limb 56 -#define bignum256modm_limb_size 5 - -typedef uint64_t bignum256modm_element_t; -typedef bignum256modm_element_t bignum256modm[5]; - -static const bignum256modm modm_m = { - 0x12631a5cf5d3ed, - 0xf9dea2f79cd658, - 0x000000000014de, - 0x00000000000000, - 0x00000010000000 -}; - -static const bignum256modm modm_mu = { - 0x9ce5a30a2c131b, - 0x215d086329a7ed, - 0xffffffffeb2106, - 0xffffffffffffff, - 0x00000fffffffff -}; - -static bignum256modm_element_t -lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { - return (a - b) >> 63; -} - -static void -reduce256_modm(bignum256modm r) { - bignum256modm t; - bignum256modm_element_t b = 0, pb, mask; - - /* t = r - m */ - pb = 0; - pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b; - pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b; - pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b; - pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b; - pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32)); - - /* keep r if r was smaller than m */ - mask = b - 1; - - r[0] ^= mask & (r[0] ^ t[0]); - r[1] ^= mask & (r[1] ^ t[1]); - r[2] ^= mask & (r[2] ^ t[2]); - r[3] ^= mask & (r[3] ^ t[3]); - r[4] ^= mask & (r[4] ^ t[4]); -} - -static void -barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { - bignum256modm q3, r2; - uint128_t c, mul; - bignum256modm_element_t f, b, pb; - - /* q1 = x >> 248 = 264 bits = 5 56 bit elements - q2 = mu * q1 - q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56); - mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul) - f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul) - f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul) - f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul) - f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f) - f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56); - q3[4] |= (f << 16); - - mul64x64_128(c, modm_m[0], q3[0]) - r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul) - r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul) - r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul) - r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul) - r2[4] = lo128(c) & 0x0000ffffffffff; - - pb = 0; - pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b; - pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b; - pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b; - pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b; - pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40)); - - reduce256_modm(r); - reduce256_modm(r); -} - - -static void -add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c; - - c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56; - c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56; - c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56; - c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56; - c += x[4] + y[4]; r[4] = c; - - reduce256_modm(r); -} - -static void -mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm q1, r1; - uint128_t c, mul; - bignum256modm_element_t f; - - mul64x64_128(c, x[0], y[0]) - f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul) - f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul) - f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul) - f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul) - f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul) - f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul) - f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul) - f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[4]) add128_64(c, f) - f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - q1[4] |= (f << 32); - - barrett_reduce256_modm(r, q1, r1); -} - -static void -expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { - unsigned char work[64] = {0}; - bignum256modm_element_t x[16]; - bignum256modm q1; - - memcpy(work, in, len); - x[0] = U8TO64_LE(work + 0); - x[1] = U8TO64_LE(work + 8); - x[2] = U8TO64_LE(work + 16); - x[3] = U8TO64_LE(work + 24); - x[4] = U8TO64_LE(work + 32); - x[5] = U8TO64_LE(work + 40); - x[6] = U8TO64_LE(work + 48); - x[7] = U8TO64_LE(work + 56); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ - out[0] = ( x[0]) & 0xffffffffffffff; - out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; - out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; - out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; - out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff; - - /* under 252 bits, no need to reduce */ - if (len < 32) - return; - - /* q1 = x >> 248 = 264 bits */ - q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff; - q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff; - q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff; - q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff; - q1[4] = ((x[ 7] >> 24) ); - - barrett_reduce256_modm(out, q1, out); -} - -static void -expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { - bignum256modm_element_t x[4]; - - x[0] = U8TO64_LE(in + 0); - x[1] = U8TO64_LE(in + 8); - x[2] = U8TO64_LE(in + 16); - x[3] = U8TO64_LE(in + 24); - - out[0] = ( x[0]) & 0xffffffffffffff; - out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; - out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; - out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; - out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff; -} - -static void -contract256_modm(unsigned char out[32], const bignum256modm in) { - U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56)); - U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48)); - U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40)); - U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32)); -} - -static void -contract256_window4_modm(signed char r[64], const bignum256modm in) { - char carry; - signed char *quads = r; - bignum256modm_element_t i, j, v, m; - - for (i = 0; i < 5; i++) { - v = in[i]; - m = (i == 4) ? 8 : 14; - for (j = 0; j < m; j++) { - *quads++ = (v & 15); - v >>= 4; - } - } - - /* making it signed */ - carry = 0; - for(i = 0; i < 63; i++) { - r[i] += carry; - r[i+1] += (r[i] >> 4); - r[i] &= 15; - carry = (r[i] >> 3); - r[i] -= (carry << 4); - } - r[63] += carry; -} - -static void -contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { - int i,j,k,b; - int m = (1 << (windowsize - 1)) - 1, soplen = 256; - signed char *bits = r; - bignum256modm_element_t v; - - /* first put the binary expansion into r */ - for (i = 0; i < 4; i++) { - v = s[i]; - for (j = 0; j < 56; j++, v >>= 1) - *bits++ = (v & 1); - } - v = s[4]; - for (j = 0; j < 32; j++, v >>= 1) - *bits++ = (v & 1); - - /* Making it sliding window */ - for (j = 0; j < soplen; j++) { - if (!r[j]) - continue; - - for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { - if ((r[j] + (r[j + b] << b)) <= m) { - r[j] += r[j + b] << b; - r[j + b] = 0; - } else if ((r[j] - (r[j + b] << b)) >= -m) { - r[j] -= r[j + b] << b; - for (k = j + b; k < soplen; k++) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else if (r[j + b]) { - break; - } - } - } -} - -/* - helpers for batch verifcation, are allowed to be vartime -*/ - -/* out = a - b, a must be larger than b */ -static void -sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t carry = 0; - switch (limbsize) { - case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 0: - default: out[i] = (a[i] - b[i]) - carry; - } -} - - -/* is a < b */ -static int -lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t t, carry = 0; - switch (limbsize) { - case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++; - case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63); - } - return (int)carry; -} - -/* is a <= b */ -static int -lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t t, carry = 0; - switch (limbsize) { - case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++; - case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63); - } - return (int)!carry; -} - -/* is a == 0 */ -static int -iszero256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 5; i++) - if (a[i]) - return 0; - return 1; -} - -/* is a == 1 */ -static int -isone256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 5; i++) - if (a[i] != ((i) ? 0 : 1)) - return 0; - return 1; -} - -/* can a fit in to (at most) 128 bits */ -static int -isatmost128bits256_modm_batch(const bignum256modm a) { - uint64_t mask = - ((a[4] ) | /* 32 */ - (a[3] ) | /* 88 */ - (a[2] & 0xffffffffff0000)); - - return (mask == 0); -} diff --git a/external/ed25519-donna/regression.h b/external/ed25519-donna/regression.h deleted file mode 100644 index b4c2e62c0a..0000000000 --- a/external/ed25519-donna/regression.h +++ /dev/null @@ -1,1024 +0,0 @@ -{{0x9d,0x61,0xb1,0x9d,0xef,0xfd,0x5a,0x60,0xba,0x84,0x4a,0xf4,0x92,0xec,0x2c,0xc4,0x44,0x49,0xc5,0x69,0x7b,0x32,0x69,0x19,0x70,0x3b,0xac,0x03,0x1c,0xae,0x7f,0x60,},{0xd7,0x5a,0x98,0x01,0x82,0xb1,0x0a,0xb7,0xd5,0x4b,0xfe,0xd3,0xc9,0x64,0x07,0x3a,0x0e,0xe1,0x72,0xf3,0xda,0xa6,0x23,0x25,0xaf,0x02,0x1a,0x68,0xf7,0x07,0x51,0x1a,},{0xe5,0x56,0x43,0x00,0xc3,0x60,0xac,0x72,0x90,0x86,0xe2,0xcc,0x80,0x6e,0x82,0x8a,0x84,0x87,0x7f,0x1e,0xb8,0xe5,0xd9,0x74,0xd8,0x73,0xe0,0x65,0x22,0x49,0x01,0x55,0x5f,0xb8,0x82,0x15,0x90,0xa3,0x3b,0xac,0xc6,0x1e,0x39,0x70,0x1c,0xf9,0xb4,0x6b,0xd2,0x5b,0xf5,0xf0,0x59,0x5b,0xbe,0x24,0x65,0x51,0x41,0x43,0x8e,0x7a,0x10,0x0b,},""}, -{{0x4c,0xcd,0x08,0x9b,0x28,0xff,0x96,0xda,0x9d,0xb6,0xc3,0x46,0xec,0x11,0x4e,0x0f,0x5b,0x8a,0x31,0x9f,0x35,0xab,0xa6,0x24,0xda,0x8c,0xf6,0xed,0x4f,0xb8,0xa6,0xfb,},{0x3d,0x40,0x17,0xc3,0xe8,0x43,0x89,0x5a,0x92,0xb7,0x0a,0xa7,0x4d,0x1b,0x7e,0xbc,0x9c,0x98,0x2c,0xcf,0x2e,0xc4,0x96,0x8c,0xc0,0xcd,0x55,0xf1,0x2a,0xf4,0x66,0x0c,},{0x92,0xa0,0x09,0xa9,0xf0,0xd4,0xca,0xb8,0x72,0x0e,0x82,0x0b,0x5f,0x64,0x25,0x40,0xa2,0xb2,0x7b,0x54,0x16,0x50,0x3f,0x8f,0xb3,0x76,0x22,0x23,0xeb,0xdb,0x69,0xda,0x08,0x5a,0xc1,0xe4,0x3e,0x15,0x99,0x6e,0x45,0x8f,0x36,0x13,0xd0,0xf1,0x1d,0x8c,0x38,0x7b,0x2e,0xae,0xb4,0x30,0x2a,0xee,0xb0,0x0d,0x29,0x16,0x12,0xbb,0x0c,0x00,},"\x72"}, -{{0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b,0xed,0xb7,0x44,0x2f,0x31,0xdc,0xb7,0xb1,0x66,0xd3,0x85,0x35,0x07,0x6f,0x09,0x4b,0x85,0xce,0x3a,0x2e,0x0b,0x44,0x58,0xf7,},{0xfc,0x51,0xcd,0x8e,0x62,0x18,0xa1,0xa3,0x8d,0xa4,0x7e,0xd0,0x02,0x30,0xf0,0x58,0x08,0x16,0xed,0x13,0xba,0x33,0x03,0xac,0x5d,0xeb,0x91,0x15,0x48,0x90,0x80,0x25,},{0x62,0x91,0xd6,0x57,0xde,0xec,0x24,0x02,0x48,0x27,0xe6,0x9c,0x3a,0xbe,0x01,0xa3,0x0c,0xe5,0x48,0xa2,0x84,0x74,0x3a,0x44,0x5e,0x36,0x80,0xd7,0xdb,0x5a,0xc3,0xac,0x18,0xff,0x9b,0x53,0x8d,0x16,0xf2,0x90,0xae,0x67,0xf7,0x60,0x98,0x4d,0xc6,0x59,0x4a,0x7c,0x15,0xe9,0x71,0x6e,0xd2,0x8d,0xc0,0x27,0xbe,0xce,0xea,0x1e,0xc4,0x0a,},"\xaf\x82"}, -{{0x0d,0x4a,0x05,0xb0,0x73,0x52,0xa5,0x43,0x6e,0x18,0x03,0x56,0xda,0x0a,0xe6,0xef,0xa0,0x34,0x5f,0xf7,0xfb,0x15,0x72,0x57,0x57,0x72,0xe8,0x00,0x5e,0xd9,0x78,0xe9,},{0xe6,0x1a,0x18,0x5b,0xce,0xf2,0x61,0x3a,0x6c,0x7c,0xb7,0x97,0x63,0xce,0x94,0x5d,0x3b,0x24,0x5d,0x76,0x11,0x4d,0xd4,0x40,0xbc,0xf5,0xf2,0xdc,0x1a,0xa5,0x70,0x57,},{0xd9,0x86,0x8d,0x52,0xc2,0xbe,0xbc,0xe5,0xf3,0xfa,0x5a,0x79,0x89,0x19,0x70,0xf3,0x09,0xcb,0x65,0x91,0xe3,0xe1,0x70,0x2a,0x70,0x27,0x6f,0xa9,0x7c,0x24,0xb3,0xa8,0xe5,0x86,0x06,0xc3,0x8c,0x97,0x58,0x52,0x9d,0xa5,0x0e,0xe3,0x1b,0x82,0x19,0xcb,0xa4,0x52,0x71,0xc6,0x89,0xaf,0xa6,0x0b,0x0e,0xa2,0x6c,0x99,0xdb,0x19,0xb0,0x0c,},"\xcb\xc7\x7b"}, -{{0x6d,0xf9,0x34,0x0c,0x13,0x8c,0xc1,0x88,0xb5,0xfe,0x44,0x64,0xeb,0xaa,0x3f,0x7f,0xc2,0x06,0xa2,0xd5,0x5c,0x34,0x34,0x70,0x7e,0x74,0xc9,0xfc,0x04,0xe2,0x0e,0xbb,},{0xc0,0xda,0xc1,0x02,0xc4,0x53,0x31,0x86,0xe2,0x5d,0xc4,0x31,0x28,0x47,0x23,0x53,0xea,0xab,0xdb,0x87,0x8b,0x15,0x2a,0xeb,0x8e,0x00,0x1f,0x92,0xd9,0x02,0x33,0xa7,},{0x12,0x4f,0x6f,0xc6,0xb0,0xd1,0x00,0x84,0x27,0x69,0xe7,0x1b,0xd5,0x30,0x66,0x4d,0x88,0x8d,0xf8,0x50,0x7d,0xf6,0xc5,0x6d,0xed,0xfd,0xb5,0x09,0xae,0xb9,0x34,0x16,0xe2,0x6b,0x91,0x8d,0x38,0xaa,0x06,0x30,0x5d,0xf3,0x09,0x56,0x97,0xc1,0x8b,0x2a,0xa8,0x32,0xea,0xa5,0x2e,0xdc,0x0a,0xe4,0x9f,0xba,0xe5,0xa8,0x5e,0x15,0x0c,0x07,},"\x5f\x4c\x89\x89"}, -{{0xb7,0x80,0x38,0x1a,0x65,0xed,0xf8,0xb7,0x8f,0x69,0x45,0xe8,0xdb,0xec,0x79,0x41,0xac,0x04,0x9f,0xd4,0xc6,0x10,0x40,0xcf,0x0c,0x32,0x43,0x57,0x97,0x5a,0x29,0x3c,},{0xe2,0x53,0xaf,0x07,0x66,0x80,0x4b,0x86,0x9b,0xb1,0x59,0x5b,0xe9,0x76,0x5b,0x53,0x48,0x86,0xbb,0xaa,0xb8,0x30,0x5b,0xf5,0x0d,0xbc,0x7f,0x89,0x9b,0xfb,0x5f,0x01,},{0xb2,0xfc,0x46,0xad,0x47,0xaf,0x46,0x44,0x78,0xc1,0x99,0xe1,0xf8,0xbe,0x16,0x9f,0x1b,0xe6,0x32,0x7c,0x7f,0x9a,0x0a,0x66,0x89,0x37,0x1c,0xa9,0x4c,0xaf,0x04,0x06,0x4a,0x01,0xb2,0x2a,0xff,0x15,0x20,0xab,0xd5,0x89,0x51,0x34,0x16,0x03,0xfa,0xed,0x76,0x8c,0xf7,0x8c,0xe9,0x7a,0xe7,0xb0,0x38,0xab,0xfe,0x45,0x6a,0xa1,0x7c,0x09,},"\x18\xb6\xbe\xc0\x97"}, -{{0x78,0xae,0x9e,0xff,0xe6,0xf2,0x45,0xe9,0x24,0xa7,0xbe,0x63,0x04,0x11,0x46,0xeb,0xc6,0x70,0xdb,0xd3,0x06,0x0c,0xba,0x67,0xfb,0xc6,0x21,0x6f,0xeb,0xc4,0x45,0x46,},{0xfb,0xcf,0xbf,0xa4,0x05,0x05,0xd7,0xf2,0xbe,0x44,0x4a,0x33,0xd1,0x85,0xcc,0x54,0xe1,0x6d,0x61,0x52,0x60,0xe1,0x64,0x0b,0x2b,0x50,0x87,0xb8,0x3e,0xe3,0x64,0x3d,},{0x6e,0xd6,0x29,0xfc,0x1d,0x9c,0xe9,0xe1,0x46,0x87,0x55,0xff,0x63,0x6d,0x5a,0x3f,0x40,0xa5,0xd9,0xc9,0x1a,0xfd,0x93,0xb7,0x9d,0x24,0x18,0x30,0xf7,0xe5,0xfa,0x29,0x85,0x4b,0x8f,0x20,0xcc,0x6e,0xec,0xbb,0x24,0x8d,0xbd,0x8d,0x16,0xd1,0x4e,0x99,0x75,0x21,0x94,0xe4,0x90,0x4d,0x09,0xc7,0x4d,0x63,0x95,0x18,0x83,0x9d,0x23,0x00,},"\x89\x01\x0d\x85\x59\x72"}, -{{0x69,0x18,0x65,0xbf,0xc8,0x2a,0x1e,0x4b,0x57,0x4e,0xec,0xde,0x4c,0x75,0x19,0x09,0x3f,0xaf,0x0c,0xf8,0x67,0x38,0x02,0x34,0xe3,0x66,0x46,0x45,0xc6,0x1c,0x5f,0x79,},{0x98,0xa5,0xe3,0xa3,0x6e,0x67,0xaa,0xba,0x89,0x88,0x8b,0xf0,0x93,0xde,0x1a,0xd9,0x63,0xe7,0x74,0x01,0x3b,0x39,0x02,0xbf,0xab,0x35,0x6d,0x8b,0x90,0x17,0x8a,0x63,},{0x6e,0x0a,0xf2,0xfe,0x55,0xae,0x37,0x7a,0x6b,0x7a,0x72,0x78,0xed,0xfb,0x41,0x9b,0xd3,0x21,0xe0,0x6d,0x0d,0xf5,0xe2,0x70,0x37,0xdb,0x88,0x12,0xe7,0xe3,0x52,0x98,0x10,0xfa,0x55,0x52,0xf6,0xc0,0x02,0x09,0x85,0xca,0x17,0xa0,0xe0,0x2e,0x03,0x6d,0x7b,0x22,0x2a,0x24,0xf9,0x9b,0x77,0xb7,0x5f,0xdd,0x16,0xcb,0x05,0x56,0x81,0x07,},"\xb4\xa8\xf3\x81\xe7\x0e\x7a"}, -{{0x3b,0x26,0x51,0x6f,0xb3,0xdc,0x88,0xeb,0x18,0x1b,0x9e,0xd7,0x3f,0x0b,0xcd,0x52,0xbc,0xd6,0xb4,0xc7,0x88,0xe4,0xbc,0xaf,0x46,0x05,0x7f,0xd0,0x78,0xbe,0xe0,0x73,},{0xf8,0x1f,0xb5,0x4a,0x82,0x5f,0xce,0xd9,0x5e,0xb0,0x33,0xaf,0xcd,0x64,0x31,0x40,0x75,0xab,0xfb,0x0a,0xbd,0x20,0xa9,0x70,0x89,0x25,0x03,0x43,0x6f,0x34,0xb8,0x63,},{0xd6,0xad,0xde,0xc5,0xaf,0xb0,0x52,0x8a,0xc1,0x7b,0xb1,0x78,0xd3,0xe7,0xf2,0x88,0x7f,0x9a,0xdb,0xb1,0xad,0x16,0xe1,0x10,0x54,0x5e,0xf3,0xbc,0x57,0xf9,0xde,0x23,0x14,0xa5,0xc8,0x38,0x8f,0x72,0x3b,0x89,0x07,0xbe,0x0f,0x3a,0xc9,0x0c,0x62,0x59,0xbb,0xe8,0x85,0xec,0xc1,0x76,0x45,0xdf,0x3d,0xb7,0xd4,0x88,0xf8,0x05,0xfa,0x08,},"\x42\x84\xab\xc5\x1b\xb6\x72\x35"}, -{{0xed,0xc6,0xf5,0xfb,0xdd,0x1c,0xee,0x4d,0x10,0x1c,0x06,0x35,0x30,0xa3,0x04,0x90,0xb2,0x21,0xbe,0x68,0xc0,0x36,0xf5,0xb0,0x7d,0x0f,0x95,0x3b,0x74,0x5d,0xf1,0x92,},{0xc1,0xa4,0x9c,0x66,0xe6,0x17,0xf9,0xef,0x5e,0xc6,0x6b,0xc4,0xc6,0x56,0x4c,0xa3,0x3d,0xe2,0xa5,0xfb,0x5e,0x14,0x64,0x06,0x2e,0x6d,0x6c,0x62,0x19,0x15,0x5e,0xfd,},{0x2c,0x76,0xa0,0x4a,0xf2,0x39,0x1c,0x14,0x70,0x82,0xe3,0x3f,0xaa,0xcd,0xbe,0x56,0x64,0x2a,0x1e,0x13,0x4b,0xd3,0x88,0x62,0x0b,0x85,0x2b,0x90,0x1a,0x6b,0xc1,0x6f,0xf6,0xc9,0xcc,0x94,0x04,0xc4,0x1d,0xea,0x12,0xed,0x28,0x1d,0xa0,0x67,0xa1,0x51,0x38,0x66,0xf9,0xd9,0x64,0xf8,0xbd,0xd2,0x49,0x53,0x85,0x6c,0x50,0x04,0x29,0x01,},"\x67\x2b\xf8\x96\x5d\x04\xbc\x51\x46"}, -{{0x4e,0x7d,0x21,0xfb,0x3b,0x18,0x97,0x57,0x1a,0x44,0x58,0x33,0xbe,0x0f,0x9f,0xd4,0x1c,0xd6,0x2b,0xe3,0xaa,0x04,0x04,0x0f,0x89,0x34,0xe1,0xfc,0xbd,0xca,0xcd,0x45,},{0x31,0xb2,0x52,0x4b,0x83,0x48,0xf7,0xab,0x1d,0xfa,0xfa,0x67,0x5c,0xc5,0x38,0xe9,0xa8,0x4e,0x3f,0xe5,0x81,0x9e,0x27,0xc1,0x2a,0xd8,0xbb,0xc1,0xa3,0x6e,0x4d,0xff,},{0x28,0xe4,0x59,0x8c,0x41,0x5a,0xe9,0xde,0x01,0xf0,0x3f,0x9f,0x3f,0xab,0x4e,0x91,0x9e,0x8b,0xf5,0x37,0xdd,0x2b,0x0c,0xdf,0x6e,0x79,0xb9,0xe6,0x55,0x9c,0x94,0x09,0xd9,0x15,0x1a,0x4c,0x40,0xf0,0x83,0x19,0x39,0x37,0x62,0x7c,0x36,0x94,0x88,0x25,0x9e,0x99,0xda,0x5a,0x9f,0x0a,0x87,0x49,0x7f,0xa6,0x69,0x6a,0x5d,0xd6,0xce,0x08,},"\x33\xd7\xa7\x86\xad\xed\x8c\x1b\xf6\x91"}, -{{0xa9,0x80,0xf8,0x92,0xdb,0x13,0xc9,0x9a,0x3e,0x89,0x71,0xe9,0x65,0xb2,0xff,0x3d,0x41,0xea,0xfd,0x54,0x09,0x3b,0xc9,0xf3,0x4d,0x1f,0xd2,0x2d,0x84,0x11,0x5b,0xb6,},{0x44,0xb5,0x7e,0xe3,0x0c,0xdb,0x55,0x82,0x9d,0x0a,0x5d,0x4f,0x04,0x6b,0xae,0xf0,0x78,0xf1,0xe9,0x7a,0x7f,0x21,0xb6,0x2d,0x75,0xf8,0xe9,0x6e,0xa1,0x39,0xc3,0x5f,},{0x77,0xd3,0x89,0xe5,0x99,0x63,0x0d,0x93,0x40,0x76,0x32,0x95,0x83,0xcd,0x41,0x05,0xa6,0x49,0xa9,0x29,0x2a,0xbc,0x44,0xcd,0x28,0xc4,0x00,0x00,0xc8,0xe2,0xf5,0xac,0x76,0x60,0xa8,0x1c,0x85,0xb7,0x2a,0xf8,0x45,0x2d,0x7d,0x25,0xc0,0x70,0x86,0x1d,0xae,0x91,0x60,0x1c,0x78,0x03,0xd6,0x56,0x53,0x16,0x50,0xdd,0x4e,0x5c,0x41,0x00,},"\x34\x86\xf6\x88\x48\xa6\x5a\x0e\xb5\x50\x7d"}, -{{0x5b,0x5a,0x61,0x9f,0x8c,0xe1,0xc6,0x6d,0x7c,0xe2,0x6e,0x5a,0x2a,0xe7,0xb0,0xc0,0x4f,0xeb,0xcd,0x34,0x6d,0x28,0x6c,0x92,0x9e,0x19,0xd0,0xd5,0x97,0x3b,0xfe,0xf9,},{0x6f,0xe8,0x36,0x93,0xd0,0x11,0xd1,0x11,0x13,0x1c,0x4f,0x3f,0xba,0xaa,0x40,0xa9,0xd3,0xd7,0x6b,0x30,0x01,0x2f,0xf7,0x3b,0xb0,0xe3,0x9e,0xc2,0x7a,0xb1,0x82,0x57,},{0x0f,0x9a,0xd9,0x79,0x30,0x33,0xa2,0xfa,0x06,0x61,0x4b,0x27,0x7d,0x37,0x38,0x1e,0x6d,0x94,0xf6,0x5a,0xc2,0xa5,0xa9,0x45,0x58,0xd0,0x9e,0xd6,0xce,0x92,0x22,0x58,0xc1,0xa5,0x67,0x95,0x2e,0x86,0x3a,0xc9,0x42,0x97,0xae,0xc3,0xc0,0xd0,0xc8,0xdd,0xf7,0x10,0x84,0xe5,0x04,0x86,0x0b,0xb6,0xba,0x27,0x44,0x9b,0x55,0xad,0xc4,0x0e,},"\x5a\x8d\x9d\x0a\x22\x35\x7e\x66\x55\xf9\xc7\x85"}, -{{0x94,0x0c,0x89,0xfe,0x40,0xa8,0x1d,0xaf,0xbd,0xb2,0x41,0x6d,0x14,0xae,0x46,0x91,0x19,0x86,0x97,0x44,0x41,0x0c,0x33,0x03,0xbf,0xaa,0x02,0x41,0xda,0xc5,0x78,0x00,},{0xa2,0xeb,0x8c,0x05,0x01,0xe3,0x0b,0xae,0x0c,0xf8,0x42,0xd2,0xbd,0xe8,0xde,0xc7,0x38,0x6f,0x6b,0x7f,0xc3,0x98,0x1b,0x8c,0x57,0xc9,0x79,0x2b,0xb9,0x4c,0xf2,0xdd,},{0xd8,0xbb,0x64,0xaa,0xd8,0xc9,0x95,0x5a,0x11,0x5a,0x79,0x3a,0xdd,0xd2,0x4f,0x7f,0x2b,0x07,0x76,0x48,0x71,0x4f,0x49,0xc4,0x69,0x4e,0xc9,0x95,0xb3,0x30,0xd0,0x9d,0x64,0x0d,0xf3,0x10,0xf4,0x47,0xfd,0x7b,0x6c,0xb5,0xc1,0x4f,0x9f,0xe9,0xf4,0x90,0xbc,0xf8,0xcf,0xad,0xbf,0xd2,0x16,0x9c,0x8a,0xc2,0x0d,0x3b,0x8a,0xf4,0x9a,0x0c,},"\xb8\x7d\x38\x13\xe0\x3f\x58\xcf\x19\xfd\x0b\x63\x95"}, -{{0x9a,0xca,0xd9,0x59,0xd2,0x16,0x21,0x2d,0x78,0x9a,0x11,0x92,0x52,0xeb,0xfe,0x0c,0x96,0x51,0x2a,0x23,0xc7,0x3b,0xd9,0xf3,0xb2,0x02,0x29,0x2d,0x69,0x16,0xa7,0x38,},{0xcf,0x3a,0xf8,0x98,0x46,0x7a,0x5b,0x7a,0x52,0xd3,0x3d,0x53,0xbc,0x03,0x7e,0x26,0x42,0xa8,0xda,0x99,0x69,0x03,0xfc,0x25,0x22,0x17,0xe9,0xc0,0x33,0xe2,0xf2,0x91,},{0x6e,0xe3,0xfe,0x81,0xe2,0x3c,0x60,0xeb,0x23,0x12,0xb2,0x00,0x6b,0x3b,0x25,0xe6,0x83,0x8e,0x02,0x10,0x66,0x23,0xf8,0x44,0xc4,0x4e,0xdb,0x8d,0xaf,0xd6,0x6a,0xb0,0x67,0x10,0x87,0xfd,0x19,0x5d,0xf5,0xb8,0xf5,0x8a,0x1d,0x6e,0x52,0xaf,0x42,0x90,0x80,0x53,0xd5,0x5c,0x73,0x21,0x01,0x00,0x92,0x74,0x87,0x95,0xef,0x94,0xcf,0x06,},"\x55\xc7\xfa\x43\x4f\x5e\xd8\xcd\xec\x2b\x7a\xea\xc1\x73"}, -{{0xd5,0xae,0xee,0x41,0xee,0xb0,0xe9,0xd1,0xbf,0x83,0x37,0xf9,0x39,0x58,0x7e,0xbe,0x29,0x61,0x61,0xe6,0xbf,0x52,0x09,0xf5,0x91,0xec,0x93,0x9e,0x14,0x40,0xc3,0x00,},{0xfd,0x2a,0x56,0x57,0x23,0x16,0x3e,0x29,0xf5,0x3c,0x9d,0xe3,0xd5,0xe8,0xfb,0xe3,0x6a,0x7a,0xb6,0x6e,0x14,0x39,0xec,0x4e,0xae,0x9c,0x0a,0x60,0x4a,0xf2,0x91,0xa5,},{0xf6,0x8d,0x04,0x84,0x7e,0x5b,0x24,0x97,0x37,0x89,0x9c,0x01,0x4d,0x31,0xc8,0x05,0xc5,0x00,0x7a,0x62,0xc0,0xa1,0x0d,0x50,0xbb,0x15,0x38,0xc5,0xf3,0x55,0x03,0x95,0x1f,0xbc,0x1e,0x08,0x68,0x2f,0x2c,0xc0,0xc9,0x2e,0xfe,0x8f,0x49,0x85,0xde,0xc6,0x1d,0xcb,0xd5,0x4d,0x4b,0x94,0xa2,0x25,0x47,0xd2,0x44,0x51,0x27,0x1c,0x8b,0x00,},"\x0a\x68\x8e\x79\xbe\x24\xf8\x66\x28\x6d\x46\x46\xb5\xd8\x1c"}, -{{0x0a,0x47,0xd1,0x04,0x52,0xae,0x2f,0xeb,0xec,0x51,0x8a,0x1c,0x7c,0x36,0x28,0x90,0xc3,0xfc,0x1a,0x49,0xd3,0x4b,0x03,0xb6,0x46,0x7d,0x35,0xc9,0x04,0xa8,0x36,0x2d,},{0x34,0xe5,0xa8,0x50,0x8c,0x47,0x43,0x74,0x69,0x62,0xc0,0x66,0xe4,0xba,0xde,0xa2,0x20,0x1b,0x8a,0xb4,0x84,0xde,0x5c,0x4f,0x94,0x47,0x6c,0xcd,0x21,0x43,0x95,0x5b,},{0x2a,0x3d,0x27,0xdc,0x40,0xd0,0xa8,0x12,0x79,0x49,0xa3,0xb7,0xf9,0x08,0xb3,0x68,0x8f,0x63,0xb7,0xf1,0x4f,0x65,0x1a,0xac,0xd7,0x15,0x94,0x0b,0xdb,0xe2,0x7a,0x08,0x09,0xaa,0xc1,0x42,0xf4,0x7a,0xb0,0xe1,0xe4,0x4f,0xa4,0x90,0xba,0x87,0xce,0x53,0x92,0xf3,0x3a,0x89,0x15,0x39,0xca,0xf1,0xef,0x4c,0x36,0x7c,0xae,0x54,0x50,0x0c,},"\xc9\x42\xfa\x7a\xc6\xb2\x3a\xb7\xff\x61\x2f\xdc\x8e\x68\xef\x39"}, -{{0xf8,0x14,0x8f,0x75,0x06,0xb7,0x75,0xef,0x46,0xfd,0xc8,0xe8,0xc7,0x56,0x51,0x68,0x12,0xd4,0x7d,0x6c,0xfb,0xfa,0x31,0x8c,0x27,0xc9,0xa2,0x26,0x41,0xe5,0x6f,0x17,},{0x04,0x45,0xe4,0x56,0xda,0xcc,0x7d,0x5b,0x0b,0xbe,0xd2,0x3c,0x82,0x00,0xcd,0xb7,0x4b,0xdc,0xb0,0x3e,0x4c,0x7b,0x73,0xf0,0xa2,0xb9,0xb4,0x6e,0xac,0x5d,0x43,0x72,},{0x36,0x53,0xcc,0xb2,0x12,0x19,0x20,0x2b,0x84,0x36,0xfb,0x41,0xa3,0x2b,0xa2,0x61,0x8c,0x4a,0x13,0x34,0x31,0xe6,0xe6,0x34,0x63,0xce,0xb3,0xb6,0x10,0x6c,0x4d,0x56,0xe1,0xd2,0xba,0x16,0x5b,0xa7,0x6e,0xaa,0xd3,0xdc,0x39,0xbf,0xfb,0x13,0x0f,0x1d,0xe3,0xd8,0xe6,0x42,0x7d,0xb5,0xb7,0x19,0x38,0xdb,0x4e,0x27,0x2b,0xc3,0xe2,0x0b,},"\x73\x68\x72\x4a\x5b\x0e\xfb\x57\xd2\x8d\x97\x62\x2d\xbd\xe7\x25\xaf"}, -{{0x77,0xf8,0x86,0x91,0xc4,0xef,0xf2,0x3e,0xbb,0x73,0x64,0x94,0x70,0x92,0x95,0x1a,0x5f,0xf3,0xf1,0x07,0x85,0xb4,0x17,0xe9,0x18,0x82,0x3a,0x55,0x2d,0xab,0x7c,0x75,},{0x74,0xd2,0x91,0x27,0xf1,0x99,0xd8,0x6a,0x86,0x76,0xae,0xc3,0x3b,0x4c,0xe3,0xf2,0x25,0xcc,0xb1,0x91,0xf5,0x2c,0x19,0x1c,0xcd,0x1e,0x8c,0xca,0x65,0x21,0x3a,0x6b,},{0xfb,0xe9,0x29,0xd7,0x43,0xa0,0x3c,0x17,0x91,0x05,0x75,0x49,0x2f,0x30,0x92,0xee,0x2a,0x2b,0xf1,0x4a,0x60,0xa3,0xfc,0xac,0xec,0x74,0xa5,0x8c,0x73,0x34,0x51,0x0f,0xc2,0x62,0xdb,0x58,0x27,0x91,0x32,0x2d,0x6c,0x8c,0x41,0xf1,0x70,0x0a,0xdb,0x80,0x02,0x7e,0xca,0xbc,0x14,0x27,0x0b,0x70,0x34,0x44,0xae,0x3e,0xe7,0x62,0x3e,0x0a,},"\xbd\x8e\x05\x03\x3f\x3a\x8b\xcd\xcb\xf4\xbe\xce\xb7\x09\x01\xc8\x2e\x31"}, -{{0xab,0x6f,0x7a,0xee,0x6a,0x08,0x37,0xb3,0x34,0xba,0x5e,0xb1,0xb2,0xad,0x7f,0xce,0xcf,0xab,0x7e,0x32,0x3c,0xab,0x18,0x7f,0xe2,0xe0,0xa9,0x5d,0x80,0xef,0xf1,0x32,},{0x5b,0x96,0xdc,0xa4,0x97,0x87,0x5b,0xf9,0x66,0x4c,0x5e,0x75,0xfa,0xcf,0x3f,0x9b,0xc5,0x4b,0xae,0x91,0x3d,0x66,0xca,0x15,0xee,0x85,0xf1,0x49,0x1c,0xa2,0x4d,0x2c,},{0x73,0xbc,0xa6,0x4e,0x9d,0xd0,0xdb,0x88,0x13,0x8e,0xed,0xfa,0xfc,0xea,0x8f,0x54,0x36,0xcf,0xb7,0x4b,0xfb,0x0e,0x77,0x33,0xcf,0x34,0x9b,0xaa,0x0c,0x49,0x77,0x5c,0x56,0xd5,0x93,0x4e,0x1d,0x38,0xe3,0x6f,0x39,0xb7,0xc5,0xbe,0xb0,0xa8,0x36,0x51,0x0c,0x45,0x12,0x6f,0x8e,0xc4,0xb6,0x81,0x05,0x19,0x90,0x5b,0x0c,0xa0,0x7c,0x09,},"\x81\x71\x45\x6f\x8b\x90\x71\x89\xb1\xd7\x79\xe2\x6b\xc5\xaf\xbb\x08\xc6\x7a"}, -{{0x8d,0x13,0x5d,0xe7,0xc8,0x41,0x1b,0xbd,0xbd,0x1b,0x31,0xe5,0xdc,0x67,0x8f,0x2a,0xc7,0x10,0x9e,0x79,0x2b,0x60,0xf3,0x8c,0xd2,0x49,0x36,0xe8,0xa8,0x98,0xc3,0x2d,},{0x1c,0xa2,0x81,0x93,0x85,0x29,0x89,0x65,0x35,0xa7,0x71,0x4e,0x35,0x84,0x08,0x5b,0x86,0xef,0x9f,0xec,0x72,0x3f,0x42,0x81,0x9f,0xc8,0xdd,0x5d,0x8c,0x00,0x81,0x7f,},{0xa1,0xad,0xc2,0xbc,0x6a,0x2d,0x98,0x06,0x62,0x67,0x7e,0x7f,0xdf,0xf6,0x42,0x4d,0xe7,0xdb,0xa5,0x0f,0x57,0x95,0xca,0x90,0xfd,0xf3,0xe9,0x6e,0x25,0x6f,0x32,0x85,0xca,0xc7,0x1d,0x33,0x60,0x48,0x2e,0x99,0x3d,0x02,0x94,0xba,0x4e,0xc7,0x44,0x0c,0x61,0xaf,0xfd,0xf3,0x5f,0xe8,0x3e,0x6e,0x04,0x26,0x39,0x37,0xdb,0x93,0xf1,0x05,},"\x8b\xa6\xa4\xc9\xa1\x5a\x24\x4a\x9c\x26\xbb\x2a\x59\xb1\x02\x6f\x21\x34\x8b\x49"}, -{{0x0e,0x76,0x5d,0x72,0x0e,0x70,0x5f,0x93,0x66,0xc1,0xab,0x8c,0x3f,0xa8,0x4c,0x9a,0x44,0x37,0x0c,0x06,0x96,0x9f,0x80,0x32,0x96,0x88,0x4b,0x28,0x46,0xa6,0x52,0xa4,},{0x7f,0xae,0x45,0xdd,0x0a,0x05,0x97,0x10,0x26,0xd4,0x10,0xbc,0x49,0x7a,0xf5,0xbe,0x7d,0x08,0x27,0xa8,0x2a,0x14,0x5c,0x20,0x3f,0x62,0x5d,0xfc,0xb8,0xb0,0x3b,0xa8,},{0xbb,0x61,0xcf,0x84,0xde,0x61,0x86,0x22,0x07,0xc6,0xa4,0x55,0x25,0x8b,0xc4,0xdb,0x4e,0x15,0xee,0xa0,0x31,0x7f,0xf8,0x87,0x18,0xb8,0x82,0xa0,0x6b,0x5c,0xf6,0xec,0x6f,0xd2,0x0c,0x5a,0x26,0x9e,0x5d,0x5c,0x80,0x5b,0xaf,0xbc,0xc5,0x79,0xe2,0x59,0x0a,0xf4,0x14,0xc7,0xc2,0x27,0x27,0x3c,0x10,0x2a,0x10,0x07,0x0c,0xdf,0xe8,0x0f,},"\x1d\x56\x6a\x62\x32\xbb\xaa\xb3\xe6\xd8\x80\x4b\xb5\x18\xa4\x98\xed\x0f\x90\x49\x86"}, -{{0xdb,0x36,0xe3,0x26,0xd6,0x76,0xc2,0xd1,0x9c,0xc8,0xfe,0x0c,0x14,0xb7,0x09,0x20,0x2e,0xcf,0xc7,0x61,0xd2,0x70,0x89,0xeb,0x6e,0xa4,0xb1,0xbb,0x02,0x1e,0xcf,0xa7,},{0x48,0x35,0x9b,0x85,0x0d,0x23,0xf0,0x71,0x5d,0x94,0xbb,0x8b,0xb7,0x5e,0x7e,0x14,0x32,0x2e,0xaf,0x14,0xf0,0x6f,0x28,0xa8,0x05,0x40,0x3f,0xbd,0xa0,0x02,0xfc,0x85,},{0xb6,0xdc,0xd0,0x99,0x89,0xdf,0xba,0xc5,0x43,0x22,0xa3,0xce,0x87,0x87,0x6e,0x1d,0x62,0x13,0x4d,0xa9,0x98,0xc7,0x9d,0x24,0xb5,0x0b,0xd7,0xa6,0xa7,0x97,0xd8,0x6a,0x0e,0x14,0xdc,0x9d,0x74,0x91,0xd6,0xc1,0x4a,0x67,0x3c,0x65,0x2c,0xfb,0xec,0x9f,0x96,0x2a,0x38,0xc9,0x45,0xda,0x3b,0x2f,0x08,0x79,0xd0,0xb6,0x8a,0x92,0x13,0x00,},"\x1b\x0a\xfb\x0a\xc4\xba\x9a\xb7\xb7\x17\x2c\xdd\xc9\xeb\x42\xbb\xa1\xa6\x4b\xce\x47\xd4"}, -{{0xc8,0x99,0x55,0xe0,0xf7,0x74,0x1d,0x90,0x5d,0xf0,0x73,0x0b,0x3d,0xc2,0xb0,0xce,0x1a,0x13,0x13,0x4e,0x44,0xfe,0xf3,0xd4,0x0d,0x60,0xc0,0x20,0xef,0x19,0xdf,0x77,},{0xfd,0xb3,0x06,0x73,0x40,0x2f,0xaf,0x1c,0x80,0x33,0x71,0x4f,0x35,0x17,0xe4,0x7c,0xc0,0xf9,0x1f,0xe7,0x0c,0xf3,0x83,0x6d,0x6c,0x23,0x63,0x6e,0x3f,0xd2,0x28,0x7c,},{0x7e,0xf6,0x6e,0x5e,0x86,0xf2,0x36,0x08,0x48,0xe0,0x01,0x4e,0x94,0x88,0x0a,0xe2,0x92,0x0a,0xd8,0xa3,0x18,0x5a,0x46,0xb3,0x5d,0x1e,0x07,0xde,0xa8,0xfa,0x8a,0xe4,0xf6,0xb8,0x43,0xba,0x17,0x4d,0x99,0xfa,0x79,0x86,0x65,0x4a,0x08,0x91,0xc1,0x2a,0x79,0x44,0x55,0x66,0x93,0x75,0xbf,0x92,0xaf,0x4c,0xc2,0x77,0x0b,0x57,0x9e,0x0c,},"\x50\x7c\x94\xc8\x82\x0d\x2a\x57\x93\xcb\xf3\x44\x2b\x3d\x71\x93\x6f\x35\xfe\x3a\xfe\xf3\x16"}, -{{0x4e,0x62,0x62,0x7f,0xc2,0x21,0x14,0x24,0x78,0xae,0xe7,0xf0,0x07,0x81,0xf8,0x17,0xf6,0x62,0xe3,0xb7,0x5d,0xb2,0x9b,0xb1,0x4a,0xb4,0x7c,0xf8,0xe8,0x41,0x04,0xd6,},{0xb1,0xd3,0x98,0x01,0x89,0x20,0x27,0xd5,0x8a,0x8c,0x64,0x33,0x51,0x63,0x19,0x58,0x93,0xbf,0xc1,0xb6,0x1d,0xbe,0xca,0x32,0x60,0x49,0x7e,0x1f,0x30,0x37,0x11,0x07,},{0x83,0x6a,0xfa,0x76,0x4d,0x9c,0x48,0xaa,0x47,0x70,0xa4,0x38,0x8b,0x65,0x4e,0x97,0xb3,0xc1,0x6f,0x08,0x29,0x67,0xfe,0xbc,0xa2,0x7f,0x2f,0xc4,0x7d,0xdf,0xd9,0x24,0x4b,0x03,0xcf,0xc7,0x29,0x69,0x8a,0xcf,0x51,0x09,0x70,0x43,0x46,0xb6,0x0b,0x23,0x0f,0x25,0x54,0x30,0x08,0x9d,0xdc,0x56,0x91,0x23,0x99,0xd1,0x12,0x2d,0xe7,0x0a,},"\xd3\xd6\x15\xa8\x47\x2d\x99\x62\xbb\x70\xc5\xb5\x46\x6a\x3d\x98\x3a\x48\x11\x04\x6e\x2a\x0e\xf5"}, -{{0x6b,0x83,0xd7,0xda,0x89,0x08,0xc3,0xe7,0x20,0x5b,0x39,0x86,0x4b,0x56,0xe5,0xf3,0xe1,0x71,0x96,0xa3,0xfc,0x9c,0x2f,0x58,0x05,0xaa,0xd0,0xf5,0x55,0x4c,0x14,0x2d,},{0xd0,0xc8,0x46,0xf9,0x7f,0xe2,0x85,0x85,0xc0,0xee,0x15,0x90,0x15,0xd6,0x4c,0x56,0x31,0x1c,0x88,0x6e,0xdd,0xcc,0x18,0x5d,0x29,0x6d,0xbb,0x16,0x5d,0x26,0x25,0xd6,},{0x16,0xe4,0x62,0xa2,0x9a,0x6d,0xd4,0x98,0x68,0x5a,0x37,0x18,0xb3,0xee,0xd0,0x0c,0xc1,0x59,0x86,0x01,0xee,0x47,0x82,0x04,0x86,0x03,0x2d,0x6b,0x9a,0xcc,0x9b,0xf8,0x9f,0x57,0x68,0x4e,0x08,0xd8,0xc0,0xf0,0x55,0x89,0xcd,0xa2,0x88,0x2a,0x05,0xdc,0x4c,0x63,0xf9,0xd0,0x43,0x1d,0x65,0x52,0x71,0x08,0x12,0x43,0x30,0x03,0xbc,0x08,},"\x6a\xda\x80\xb6\xfa\x84\xf7\x03\x49\x20\x78\x9e\x85\x36\xb8\x2d\x5e\x46\x78\x05\x9a\xed\x27\xf7\x1c"}, -{{0x19,0xa9,0x1f,0xe2,0x3a,0x4e,0x9e,0x33,0xec,0xc4,0x74,0x87,0x8f,0x57,0xc6,0x4c,0xf1,0x54,0xb3,0x94,0x20,0x34,0x87,0xa7,0x03,0x5e,0x1a,0xd9,0xcd,0x69,0x7b,0x0d,},{0x2b,0xf3,0x2b,0xa1,0x42,0xba,0x46,0x22,0xd8,0xf3,0xe2,0x9e,0xcd,0x85,0xee,0xa0,0x7b,0x9c,0x47,0xbe,0x9d,0x64,0x41,0x2c,0x9b,0x51,0x0b,0x27,0xdd,0x21,0x8b,0x23,},{0x88,0x1f,0x5b,0x8c,0x5a,0x03,0x0d,0xf0,0xf7,0x5b,0x66,0x34,0xb0,0x70,0xdd,0x27,0xbd,0x1e,0xe3,0xc0,0x87,0x38,0xae,0x34,0x93,0x38,0xb3,0xee,0x64,0x69,0xbb,0xf9,0x76,0x0b,0x13,0x57,0x8a,0x23,0x7d,0x51,0x82,0x53,0x5e,0xde,0x12,0x12,0x83,0x02,0x7a,0x90,0xb5,0xf8,0x65,0xd6,0x3a,0x65,0x37,0xdc,0xa0,0x7b,0x44,0x04,0x9a,0x0f,},"\x82\xcb\x53\xc4\xd5\xa0\x13\xba\xe5\x07\x07\x59\xec\x06\xc3\xc6\x95\x5a\xb7\xa4\x05\x09\x58\xec\x32\x8c"}, -{{0x1d,0x5b,0x8c,0xb6,0x21,0x5c,0x18,0x14,0x16,0x66,0xba,0xee,0xfc,0xf5,0xd6,0x9d,0xad,0x5b,0xea,0x9a,0x34,0x93,0xdd,0xda,0xa3,0x57,0xa4,0x39,0x7a,0x13,0xd4,0xde,},{0x94,0xd2,0x3d,0x97,0x7c,0x33,0xe4,0x9e,0x5e,0x49,0x92,0xc6,0x8f,0x25,0xec,0x99,0xa2,0x7c,0x41,0xce,0x6b,0x91,0xf2,0xbf,0xa0,0xcd,0x82,0x92,0xfe,0x96,0x28,0x35,},{0x3a,0xcd,0x39,0xbe,0xc8,0xc3,0xcd,0x2b,0x44,0x29,0x97,0x22,0xb5,0x85,0x0a,0x04,0x00,0xc1,0x44,0x35,0x90,0xfd,0x48,0x61,0xd5,0x9a,0xae,0x74,0x96,0xac,0xb3,0xdf,0x73,0xfc,0x3f,0xdf,0x79,0x69,0xae,0x5f,0x50,0xba,0x47,0xdd,0xdc,0x43,0x52,0x46,0xe5,0xfd,0x37,0x6f,0x6b,0x89,0x1c,0xd4,0xc2,0xca,0xf5,0xd6,0x14,0xb6,0x17,0x0c,},"\xa9\xa8\xcb\xb0\xad\x58\x51\x24\xe5\x22\xab\xbf\xb4\x05\x33\xbd\xd6\xf4\x93\x47\xb5\x5b\x18\xe8\x55\x8c\xb0"}, -{{0x6a,0x91,0xb3,0x22,0x7c,0x47,0x22,0x99,0x08,0x9b,0xdc,0xe9,0x35,0x6e,0x72,0x6a,0x40,0xef,0xd8,0x40,0xf1,0x10,0x02,0x70,0x8b,0x7e,0xe5,0x5b,0x64,0x10,0x5a,0xc2,},{0x9d,0x08,0x4a,0xa8,0xb9,0x7a,0x6b,0x9b,0xaf,0xa4,0x96,0xdb,0xc6,0xf7,0x6f,0x33,0x06,0xa1,0x16,0xc9,0xd9,0x17,0xe6,0x81,0x52,0x0a,0x0f,0x91,0x43,0x69,0x42,0x7e,},{0xf5,0x87,0x54,0x23,0x78,0x1b,0x66,0x21,0x6c,0xb5,0xe8,0x99,0x8d,0xe5,0xd9,0xff,0xc2,0x9d,0x1d,0x67,0x10,0x70,0x54,0xac,0xe3,0x37,0x45,0x03,0xa9,0xc3,0xef,0x81,0x15,0x77,0xf2,0x69,0xde,0x81,0x29,0x67,0x44,0xbd,0x70,0x6f,0x1a,0xc4,0x78,0xca,0xf0,0x9b,0x54,0xcd,0xf8,0x71,0xb3,0xf8,0x02,0xbd,0x57,0xf9,0xa6,0xcb,0x91,0x01,},"\x5c\xb6\xf9\xaa\x59\xb8\x0e\xca\x14\xf6\xa6\x8f\xb4\x0c\xf0\x7b\x79\x4e\x75\x17\x1f\xba\x96\x26\x2c\x1c\x6a\xdc"}, -{{0x93,0xea,0xa8,0x54,0xd7,0x91,0xf0,0x53,0x72,0xce,0x72,0xb9,0x4f,0xc6,0x50,0x3b,0x2f,0xf8,0xae,0x68,0x19,0xe6,0xa2,0x1a,0xfe,0x82,0x5e,0x27,0xad,0xa9,0xe4,0xfb,},{0x16,0xce,0xe8,0xa3,0xf2,0x63,0x18,0x34,0xc8,0x8b,0x67,0x08,0x97,0xff,0x0b,0x08,0xce,0x90,0xcc,0x14,0x7b,0x45,0x93,0xb3,0xf1,0xf4,0x03,0x72,0x7f,0x7e,0x7a,0xd5,},{0xd8,0x34,0x19,0x7c,0x1a,0x30,0x80,0x61,0x4e,0x0a,0x5f,0xa0,0xaa,0xaa,0x80,0x88,0x24,0xf2,0x1c,0x38,0xd6,0x92,0xe6,0xff,0xbd,0x20,0x0f,0x7d,0xfb,0x3c,0x8f,0x44,0x40,0x2a,0x73,0x82,0x18,0x0b,0x98,0xad,0x0a,0xfc,0x8e,0xec,0x1a,0x02,0xac,0xec,0xf3,0xcb,0x7f,0xde,0x62,0x7b,0x9f,0x18,0x11,0x1f,0x26,0x0a,0xb1,0xdb,0x9a,0x07,},"\x32\xfe\x27\x99\x41\x24\x20\x21\x53\xb5\xc7\x0d\x38\x13\xfd\xee\x9c\x2a\xa6\xe7\xdc\x74\x3d\x4d\x53\x5f\x18\x40\xa5"}, -{{0x94,0x1c,0xac,0x69,0xfb,0x7b,0x18,0x15,0xc5,0x7b,0xb9,0x87,0xc4,0xd6,0xc2,0xad,0x2c,0x35,0xd5,0xf9,0xa3,0x18,0x2a,0x79,0xd4,0xba,0x13,0xea,0xb2,0x53,0xa8,0xad,},{0x23,0xbe,0x32,0x3c,0x56,0x2d,0xfd,0x71,0xce,0x65,0xf5,0xbb,0xa5,0x6a,0x74,0xa3,0xa6,0xdf,0xc3,0x6b,0x57,0x3d,0x2f,0x94,0xf6,0x35,0xc7,0xf9,0xb4,0xfd,0x5a,0x5b,},{0x0f,0x8f,0xad,0x1e,0x6b,0xde,0x77,0x1b,0x4f,0x54,0x20,0xea,0xc7,0x5c,0x37,0x8b,0xae,0x6d,0xb5,0xac,0x66,0x50,0xcd,0x2b,0xc2,0x10,0xc1,0x82,0x3b,0x43,0x2b,0x48,0xe0,0x16,0xb1,0x05,0x95,0x45,0x8f,0xfa,0xb9,0x2f,0x7a,0x89,0x89,0xb2,0x93,0xce,0xb8,0xdf,0xed,0x6c,0x24,0x3a,0x20,0x38,0xfc,0x06,0x65,0x2a,0xaa,0xf1,0x6f,0x02,},"\xbb\x31\x72\x79\x57\x10\xfe\x00\x05\x4d\x3b\x5d\xfe\xf8\xa1\x16\x23\x58\x2d\xa6\x8b\xf8\xe4\x6d\x72\xd2\x7c\xec\xe2\xaa"}, -{{0x1a,0xcd,0xbb,0x79,0x3b,0x03,0x84,0x93,0x46,0x27,0x47,0x0d,0x79,0x5c,0x3d,0x1d,0xd4,0xd7,0x9c,0xea,0x59,0xef,0x98,0x3f,0x29,0x5b,0x9b,0x59,0x17,0x9c,0xbb,0x28,},{0x3f,0x60,0xc7,0x54,0x1a,0xfa,0x76,0xc0,0x19,0xcf,0x5a,0xa8,0x2d,0xcd,0xb0,0x88,0xed,0x9e,0x4e,0xd9,0x78,0x05,0x14,0xae,0xfb,0x37,0x9d,0xab,0xc8,0x44,0xf3,0x1a,},{0xbe,0x71,0xef,0x48,0x06,0xcb,0x04,0x1d,0x88,0x5e,0xff,0xd9,0xe6,0xb0,0xfb,0xb7,0x3d,0x65,0xd7,0xcd,0xec,0x47,0xa8,0x9c,0x8a,0x99,0x48,0x92,0xf4,0xe5,0x5a,0x56,0x8c,0x4c,0xc7,0x8d,0x61,0xf9,0x01,0xe8,0x0d,0xbb,0x62,0x8b,0x86,0xa2,0x3c,0xcd,0x59,0x4e,0x71,0x2b,0x57,0xfa,0x94,0xc2,0xd6,0x7e,0xc2,0x66,0x34,0x87,0x85,0x07,},"\x7c\xf3\x4f\x75\xc3\xda\xc9\xa8\x04\xd0\xfc\xd0\x9e\xba\x9b\x29\xc9\x48\x4e\x8a\x01\x8f\xa9\xe0\x73\x04\x2d\xf8\x8e\x3c\x56"}, -{{0x8e,0xd7,0xa7,0x97,0xb9,0xce,0xa8,0xa8,0x37,0x0d,0x41,0x91,0x36,0xbc,0xdf,0x68,0x3b,0x75,0x9d,0x2e,0x3c,0x69,0x47,0xf1,0x7e,0x13,0xe2,0x48,0x5a,0xa9,0xd4,0x20,},{0xb4,0x9f,0x3a,0x78,0xb1,0xc6,0xa7,0xfc,0xa8,0xf3,0x46,0x6f,0x33,0xbc,0x0e,0x92,0x9f,0x01,0xfb,0xa0,0x43,0x06,0xc2,0xa7,0x46,0x5f,0x46,0xc3,0x75,0x93,0x16,0xd9,},{0x04,0x26,0x6c,0x03,0x3b,0x91,0xc1,0x32,0x2c,0xeb,0x34,0x46,0xc9,0x01,0xff,0xcf,0x3c,0xc4,0x0c,0x40,0x34,0xe8,0x87,0xc9,0x59,0x7c,0xa1,0x89,0x3b,0xa7,0x33,0x0b,0xec,0xbb,0xd8,0xb4,0x81,0x42,0xef,0x35,0xc0,0x12,0xc6,0xba,0x51,0xa6,0x6d,0xf9,0x30,0x8c,0xb6,0x26,0x8a,0xd6,0xb1,0xe4,0xb0,0x3e,0x70,0x10,0x24,0x95,0x79,0x0b,},"\xa7\x50\xc2\x32\x93\x3d\xc1\x4b\x11\x84\xd8\x6d\x8b\x4c\xe7\x2e\x16\xd6\x97\x44\xba\x69\x81\x8b\x6a\xc3\x3b\x1d\x82\x3b\xb2\xc3"}, -{{0xf2,0xab,0x39,0x6f,0xe8,0x90,0x6e,0x3e,0x56,0x33,0xe9,0x9c,0xab,0xcd,0x5b,0x09,0xdf,0x08,0x59,0xb5,0x16,0x23,0x0b,0x1e,0x04,0x50,0xb5,0x80,0xb6,0x5f,0x61,0x6c,},{0x8e,0xa0,0x74,0x24,0x51,0x59,0xa1,0x16,0xaa,0x71,0x22,0xa2,0x5e,0xc1,0x6b,0x89,0x1d,0x62,0x5a,0x68,0xf3,0x36,0x60,0x42,0x39,0x08,0xf6,0xbd,0xc4,0x4f,0x8c,0x1b,},{0xa0,0x6a,0x23,0xd9,0x82,0xd8,0x1a,0xb8,0x83,0xaa,0xe2,0x30,0xad,0xbc,0x36,0x8a,0x6a,0x99,0x77,0xf0,0x03,0xce,0xbb,0x00,0xd4,0xc2,0xe4,0x01,0x84,0x90,0x19,0x1a,0x84,0xd3,0xa2,0x82,0xfd,0xbf,0xb2,0xfc,0x88,0x04,0x6e,0x62,0xde,0x43,0xe1,0x5f,0xb5,0x75,0x33,0x6b,0x3c,0x8b,0x77,0xd1,0x9c,0xe6,0xa0,0x09,0xce,0x51,0xf5,0x0c,},"\x5a\x44\xe3\x4b\x74\x6c\x5f\xd1\x89\x8d\x55\x2a\xb3\x54\xd2\x8f\xb4\x71\x38\x56\xd7\x69\x7d\xd6\x3e\xb9\xbd\x6b\x99\xc2\x80\xe1\x87"}, -{{0x55,0x0a,0x41,0xc0,0x13,0xf7,0x9b,0xab,0x8f,0x06,0xe4,0x3a,0xd1,0x83,0x6d,0x51,0x31,0x27,0x36,0xa9,0x71,0x38,0x06,0xfa,0xfe,0x66,0x45,0x21,0x9e,0xaa,0x1f,0x9d,},{0xaf,0x6b,0x71,0x45,0x47,0x4d,0xc9,0x95,0x4b,0x9a,0xf9,0x3a,0x9c,0xdb,0x34,0x44,0x9d,0x5b,0x7c,0x65,0x1c,0x82,0x4d,0x24,0xe2,0x30,0xb9,0x00,0x33,0xce,0x59,0xc0,},{0x16,0xdc,0x1e,0x2b,0x9f,0xa9,0x09,0xee,0xfd,0xc2,0x77,0xba,0x16,0xeb,0xe2,0x07,0xb8,0xda,0x5e,0x91,0x14,0x3c,0xde,0x78,0xc5,0x04,0x7a,0x89,0xf6,0x81,0xc3,0x3c,0x4e,0x4e,0x34,0x28,0xd5,0xc9,0x28,0x09,0x59,0x03,0xa8,0x11,0xec,0x00,0x2d,0x52,0xa3,0x9e,0xd7,0xf8,0xb3,0xfe,0x19,0x27,0x20,0x0c,0x6d,0xd0,0xb9,0xab,0x3e,0x04,},"\x8b\xc4\x18\x5e\x50\xe5\x7d\x5f\x87\xf4\x75\x15\xfe\x2b\x18\x37\xd5\x85\xf0\xaa\xe9\xe1\xca\x38\x3b\x3e\xc9\x08\x88\x4b\xb9\x00\xff\x27"}, -{{0x19,0xac,0x3e,0x27,0x24,0x38,0xc7,0x2d,0xdf,0x7b,0x88,0x19,0x64,0x86,0x7c,0xb3,0xb3,0x1f,0xf4,0xc7,0x93,0xbb,0x7e,0xa1,0x54,0x61,0x3c,0x1d,0xb0,0x68,0xcb,0x7e,},{0xf8,0x5b,0x80,0xe0,0x50,0xa1,0xb9,0x62,0x0d,0xb1,0x38,0xbf,0xc9,0xe1,0x00,0x32,0x7e,0x25,0xc2,0x57,0xc5,0x92,0x17,0xb6,0x01,0xf1,0xf6,0xac,0x9a,0x41,0x3d,0x3f,},{0xea,0x85,0x5d,0x78,0x1c,0xbe,0xa4,0x68,0x2e,0x35,0x01,0x73,0xcb,0x89,0xe8,0x61,0x9c,0xcf,0xdd,0xb9,0x7c,0xdc,0xe1,0x6f,0x9a,0x2f,0x6f,0x68,0x92,0xf4,0x6d,0xbe,0x68,0xe0,0x4b,0x12,0xb8,0xd8,0x86,0x89,0xa7,0xa3,0x16,0x70,0xcd,0xff,0x40,0x9a,0xf9,0x8a,0x93,0xb4,0x9a,0x34,0x53,0x7b,0x6a,0xa0,0x09,0xd2,0xeb,0x8b,0x47,0x01,},"\x95\x87\x2d\x5f\x78\x9f\x95\x48\x4e\x30\xcb\xb0\xe1\x14\x02\x89\x53\xb1\x6f\x5c\x6a\x8d\x9f\x65\xc0\x03\xa8\x35\x43\xbe\xaa\x46\xb3\x86\x45"}, -{{0xca,0x26,0x7d,0xe9,0x6c,0x93,0xc2,0x38,0xfa,0xfb,0x12,0x79,0x81,0x20,0x59,0xab,0x93,0xac,0x03,0x05,0x96,0x57,0xfd,0x99,0x4f,0x8f,0xa5,0xa0,0x92,0x39,0xc8,0x21,},{0x01,0x73,0x70,0xc8,0x79,0x09,0x0a,0x81,0xc7,0xf2,0x72,0xc2,0xfc,0x80,0xe3,0xaa,0xc2,0xbc,0x60,0x3f,0xcb,0x37,0x9a,0xfc,0x98,0x69,0x11,0x60,0xab,0x74,0x5b,0x26,},{0xac,0x95,0x7f,0x82,0x33,0x5a,0xa7,0x14,0x1e,0x96,0xb5,0x9d,0x63,0xe3,0xcc,0xee,0x95,0xc3,0xa2,0xc4,0x7d,0x02,0x65,0x40,0xc2,0xaf,0x42,0xdc,0x95,0x33,0xd5,0xfd,0x81,0x82,0x7d,0x16,0x79,0xad,0x18,0x7a,0xea,0xf3,0x78,0x34,0x91,0x5e,0x75,0xb1,0x47,0xa9,0x28,0x68,0x06,0xc8,0x01,0x75,0x16,0xba,0x43,0xdd,0x05,0x1a,0x5e,0x0c,},"\xe0\x5f\x71\xe4\xe4\x9a\x72\xec\x55\x0c\x44\xa3\xb8\x5a\xca\x8f\x20\xff\x26\xc3\xee\x94\xa8\x0f\x1b\x43\x1c\x7d\x15\x4e\xc9\x60\x3e\xe0\x25\x31"}, -{{0x3d,0xff,0x5e,0x89,0x94,0x75,0xe7,0xe9,0x1d,0xd2,0x61,0x32,0x2f,0xab,0x09,0x98,0x0c,0x52,0x97,0x0d,0xe1,0xda,0x6e,0x2e,0x20,0x16,0x60,0xcc,0x4f,0xce,0x70,0x32,},{0xf3,0x01,0x62,0xba,0xc9,0x84,0x47,0xc4,0x04,0x2f,0xac,0x05,0xda,0x44,0x80,0x34,0x62,0x9b,0xe2,0xc6,0xa5,0x8d,0x30,0xdf,0xd5,0x78,0xba,0x9f,0xb5,0xe3,0x93,0x0b,},{0x5e,0xfe,0x7a,0x92,0xff,0x96,0x23,0x08,0x9b,0x3e,0x3b,0x78,0xf3,0x52,0x11,0x53,0x66,0xe2,0x6b,0xa3,0xfb,0x1a,0x41,0x62,0x09,0xbc,0x02,0x9e,0x9c,0xad,0xcc,0xd9,0xf4,0xaf,0xfa,0x33,0x35,0x55,0xa8,0xf3,0xa3,0x5a,0x9d,0x0f,0x7c,0x34,0xb2,0x92,0xca,0xe7,0x7e,0xc9,0x6f,0xa3,0xad,0xfc,0xaa,0xde,0xe2,0xd9,0xce,0xd8,0xf8,0x05,},"\x93\x8f\x0e\x77\x62\x1b\xf3\xea\x52\xc7\xc4\x91\x1c\x51\x57\xc2\xd8\xa2\xa8\x58\x09\x3e\xf1\x6a\xa9\xb1\x07\xe6\x9d\x98\x03\x7b\xa1\x39\xa3\xc3\x82"}, -{{0x9a,0x6b,0x84,0x78,0x64,0xe7,0x0c,0xfe,0x8b,0xa6,0xab,0x22,0xfa,0x0c,0xa3,0x08,0xc0,0xcc,0x8b,0xec,0x71,0x41,0xfb,0xca,0xa3,0xb8,0x1f,0x5d,0x1e,0x1c,0xfc,0xfc,},{0x34,0xad,0x0f,0xbd,0xb2,0x56,0x65,0x07,0xa8,0x1c,0x2b,0x1f,0x8a,0xa8,0xf5,0x3d,0xcc,0xaa,0x64,0xcc,0x87,0xad,0xa9,0x1b,0x90,0x3e,0x90,0x0d,0x07,0xee,0xe9,0x30,},{0x2a,0xb2,0x55,0x16,0x9c,0x48,0x9c,0x54,0xc7,0x32,0x23,0x2e,0x37,0xc8,0x73,0x49,0xd4,0x86,0xb1,0xeb,0xa2,0x05,0x09,0xdb,0xab,0xe7,0xfe,0xd3,0x29,0xef,0x08,0xfd,0x75,0xba,0x1c,0xd1,0x45,0xe6,0x7b,0x2e,0xa2,0x6c,0xb5,0xcc,0x51,0xca,0xb3,0x43,0xee,0xb0,0x85,0xfe,0x1f,0xd7,0xb0,0xec,0x4c,0x6a,0xfc,0xd9,0xb9,0x79,0xf9,0x05,},"\x83\x83\x67\x47\x11\x83\xc7\x1f\x7e\x71\x77\x24\xf8\x9d\x40\x1c\x3a\xd9\x86\x3f\xd9\xcc\x7a\xa3\xcf\x33\xd3\xc5\x29\x86\x0c\xb5\x81\xf3\x09\x3d\x87\xda"}, -{{0x57,0x5b,0xe0,0x7a,0xfc,0xa5,0xd0,0x63,0xc2,0x38,0xcd,0x9b,0x80,0x28,0x77,0x2c,0xc4,0x9c,0xda,0x34,0x47,0x14,0x32,0xa2,0xe1,0x66,0xe0,0x96,0xe2,0x21,0x9e,0xfc,},{0x94,0xe5,0xeb,0x4d,0x50,0x24,0xf4,0x9d,0x7e,0xbf,0x79,0x81,0x7c,0x8d,0xe1,0x14,0x97,0xdc,0x2b,0x55,0x62,0x2a,0x51,0xae,0x12,0x3f,0xfc,0x74,0x9d,0xbb,0x16,0xe0,},{0x58,0x27,0x1d,0x44,0x23,0x6f,0x3b,0x98,0xc5,0x8f,0xd7,0xae,0x0d,0x2f,0x49,0xef,0x2b,0x6e,0x3a,0xff,0xdb,0x22,0x5a,0xa3,0xba,0x55,0x5f,0x0e,0x11,0xcc,0x53,0xc2,0x3a,0xd1,0x9b,0xaf,0x24,0x34,0x65,0x90,0xd0,0x5d,0x7d,0x53,0x90,0x58,0x20,0x82,0xcf,0x94,0xd3,0x9c,0xad,0x65,0x30,0xab,0x93,0xd1,0x3e,0xfb,0x39,0x27,0x95,0x06,},"\x33\xe5\x91\x8b\x66\xd3\x3d\x55\xfe\x71\x7c\xa3\x43\x83\xea\xe7\x8f\x0a\xf8\x28\x89\xca\xf6\x69\x6e\x1a\xc9\xd9\x5d\x1f\xfb\x32\xcb\xa7\x55\xf9\xe3\x50\x3e"}, -{{0x15,0xff,0xb4,0x55,0x14,0xd4,0x34,0x44,0xd6,0x1f,0xcb,0x10,0x5e,0x30,0xe1,0x35,0xfd,0x26,0x85,0x23,0xdd,0xa2,0x0b,0x82,0x75,0x8b,0x17,0x94,0x23,0x11,0x04,0x41,},{0x17,0x72,0xc5,0xab,0xc2,0xd2,0x3f,0xd2,0xf9,0xd1,0xc3,0x25,0x7b,0xe7,0xbc,0x3c,0x1c,0xd7,0x9c,0xee,0x40,0x84,0x4b,0x74,0x9b,0x3a,0x77,0x43,0xd2,0xf9,0x64,0xb8,},{0x68,0x28,0xcd,0x76,0x24,0xe7,0x93,0xb8,0xa4,0xce,0xb9,0x6d,0x3c,0x2a,0x97,0x5b,0xf7,0x73,0xe5,0xff,0x66,0x45,0xf3,0x53,0x61,0x40,0x58,0x62,0x1e,0x58,0x83,0x52,0x89,0xe7,0xf3,0x1f,0x42,0xdf,0xe6,0xaf,0x6d,0x73,0x6f,0x26,0x44,0x51,0x1e,0x32,0x0c,0x0f,0xa6,0x98,0x58,0x2a,0x79,0x77,0x8d,0x18,0x73,0x0e,0xd3,0xe8,0xcb,0x08,},"\xda\x9c\x55\x59\xd0\xea\x51\xd2\x55\xb6\xbd\x9d\x76\x38\xb8\x76\x47\x2f\x94\x2b\x33\x0f\xc0\xe2\xb3\x0a\xea\x68\xd7\x73\x68\xfc\xe4\x94\x82\x72\x99\x1d\x25\x7e"}, -{{0xfe,0x05,0x68,0x64,0x29,0x43,0xb2,0xe1,0xaf,0xbf,0xd1,0xf1,0x0f,0xe8,0xdf,0x87,0xa4,0x23,0x6b,0xea,0x40,0xdc,0xe7,0x42,0x07,0x2c,0xb2,0x18,0x86,0xee,0xc1,0xfa,},{0x29,0x9e,0xbd,0x1f,0x13,0x17,0x7d,0xbd,0xb6,0x6a,0x91,0x2b,0xbf,0x71,0x20,0x38,0xfd,0xf7,0x3b,0x06,0xc3,0xac,0x02,0x0c,0x7b,0x19,0x12,0x67,0x55,0xd4,0x7f,0x61,},{0xd5,0x9e,0x6d,0xfc,0xc6,0xd7,0xe3,0xe2,0xc5,0x8d,0xec,0x81,0xe9,0x85,0xd2,0x45,0xe6,0x81,0xac,0xf6,0x59,0x4a,0x23,0xc5,0x92,0x14,0xf7,0xbe,0xd8,0x01,0x5d,0x81,0x3c,0x76,0x82,0xb6,0x0b,0x35,0x83,0x44,0x03,0x11,0xe7,0x2a,0x86,0x65,0xba,0x2c,0x96,0xde,0xc2,0x3c,0xe8,0x26,0xe1,0x60,0x12,0x7e,0x18,0x13,0x2b,0x03,0x04,0x04,},"\xc5\x9d\x08\x62\xec\x1c\x97\x46\xab\xcc\x3c\xf8\x3c\x9e\xeb\xa2\xc7\x08\x2a\x03\x6a\x8c\xb5\x7c\xe4\x87\xe7\x63\x49\x27\x96\xd4\x7e\x6e\x06\x3a\x0c\x1f\xec\xcc\x2d"}, -{{0x5e,0xcb,0x16,0xc2,0xdf,0x27,0xc8,0xcf,0x58,0xe4,0x36,0xa9,0xd3,0xaf,0xfb,0xd5,0x8e,0x95,0x38,0xa9,0x26,0x59,0xa0,0xf9,0x7c,0x4c,0x4f,0x99,0x46,0x35,0xa8,0xca,},{0xda,0x76,0x8b,0x20,0xc4,0x37,0xdd,0x3a,0xa5,0xf8,0x4b,0xb6,0xa0,0x77,0xff,0xa3,0x4a,0xb6,0x85,0x01,0xc5,0x35,0x2b,0x5c,0xc3,0xfd,0xce,0x7f,0xe6,0xc2,0x39,0x8d,},{0x1c,0x72,0x3a,0x20,0xc6,0x77,0x24,0x26,0xa6,0x70,0xe4,0xd5,0xc4,0xa9,0x7c,0x6e,0xbe,0x91,0x47,0xf7,0x1b,0xb0,0xa4,0x15,0x63,0x1e,0x44,0x40,0x6e,0x29,0x03,0x22,0xe4,0xca,0x97,0x7d,0x34,0x8f,0xe7,0x85,0x6a,0x8e,0xdc,0x23,0x5d,0x0f,0xe9,0x5f,0x7e,0xd9,0x1a,0xef,0xdd,0xf2,0x8a,0x77,0xe2,0xc7,0xdb,0xfd,0x8f,0x55,0x2f,0x0a,},"\x56\xf1\x32\x9d\x9a\x6b\xe2\x5a\x61\x59\xc7\x2f\x12\x68\x8d\xc8\x31\x4e\x85\xdd\x9e\x7e\x4d\xc0\x5b\xbe\xcb\x77\x29\xe0\x23\xc8\x6f\x8e\x09\x37\x35\x3f\x27\xc7\xed\xe9"}, -{{0xd5,0x99,0xd6,0x37,0xb3,0xc3,0x0a,0x82,0xa9,0x98,0x4e,0x2f,0x75,0x84,0x97,0xd1,0x44,0xde,0x6f,0x06,0xb9,0xfb,0xa0,0x4d,0xd4,0x0f,0xd9,0x49,0x03,0x9d,0x7c,0x84,},{0x67,0x91,0xd8,0xce,0x50,0xa4,0x46,0x89,0xfc,0x17,0x87,0x27,0xc5,0xc3,0xa1,0xc9,0x59,0xfb,0xee,0xd7,0x4e,0xf7,0xd8,0xe7,0xbd,0x3c,0x1a,0xb4,0xda,0x31,0xc5,0x1f,},{0xeb,0xf1,0x0d,0x9a,0xc7,0xc9,0x61,0x08,0x14,0x0e,0x7d,0xef,0x6f,0xe9,0x53,0x3d,0x72,0x76,0x46,0xff,0x5b,0x3a,0xf2,0x73,0xc1,0xdf,0x95,0x76,0x2a,0x66,0xf3,0x2b,0x65,0xa0,0x96,0x34,0xd0,0x13,0xf5,0x4b,0x5d,0xd6,0x01,0x1f,0x91,0xbc,0x33,0x6c,0xa8,0xb3,0x55,0xce,0x33,0xf8,0xcf,0xbe,0xc2,0x53,0x5a,0x4c,0x42,0x7f,0x82,0x05,},"\xa7\xc0\x4e\x8b\xa7\x5d\x0a\x03\xd8\xb1\x66\xad\x7a\x1d\x77\xe1\xb9\x1c\x7a\xaf\x7b\xef\xdd\x99\x31\x1f\xc3\xc5\x4a\x68\x4d\xdd\x97\x1d\x5b\x32\x11\xc3\xee\xaf\xf1\xe5\x4e"}, -{{0x30,0xab,0x82,0x32,0xfa,0x70,0x18,0xf0,0xce,0x6c,0x39,0xbd,0x8f,0x78,0x2f,0xe2,0xe1,0x59,0x75,0x8b,0xb0,0xf2,0xf4,0x38,0x6c,0x7f,0x28,0xcf,0xd2,0xc8,0x58,0x98,},{0xec,0xfb,0x6a,0x2b,0xd4,0x2f,0x31,0xb6,0x12,0x50,0xba,0x5d,0xe7,0xe4,0x6b,0x47,0x19,0xaf,0xdf,0xbc,0x66,0x0d,0xb7,0x1a,0x7b,0xd1,0xdf,0x7b,0x0a,0x3a,0xbe,0x37,},{0x9a,0xf8,0x85,0x34,0x4c,0xc7,0x23,0x94,0x98,0xf7,0x12,0xdf,0x80,0xbc,0x01,0xb8,0x06,0x38,0x29,0x1e,0xd4,0xa1,0xd2,0x8b,0xaa,0x55,0x45,0x01,0x7a,0x72,0xe2,0xf6,0x56,0x49,0xcc,0xf9,0x60,0x3d,0xa6,0xeb,0x5b,0xfa,0xb9,0xf5,0x54,0x3a,0x6c,0xa4,0xa7,0xaf,0x38,0x66,0x15,0x3c,0x76,0xbf,0x66,0xbf,0x95,0xde,0xf6,0x15,0xb0,0x0c,},"\x63\xb8\x0b\x79\x56\xac\xbe\xcf\x0c\x35\xe9\xab\x06\xb9\x14\xb0\xc7\x01\x4f\xe1\xa4\xbb\xc0\x21\x72\x40\xc1\xa3\x30\x95\xd7\x07\x95\x3e\xd7\x7b\x15\xd2\x11\xad\xaf\x9b\x97\xdc"}, -{{0x0d,0xdc,0xdc,0x87,0x2c,0x7b,0x74,0x8d,0x40,0xef,0xe9,0x6c,0x28,0x81,0xae,0x18,0x9d,0x87,0xf5,0x61,0x48,0xed,0x8a,0xf3,0xeb,0xbb,0xc8,0x03,0x24,0xe3,0x8b,0xdd,},{0x58,0x8d,0xda,0xdc,0xbc,0xed,0xf4,0x0d,0xf0,0xe9,0x69,0x7d,0x8b,0xb2,0x77,0xc7,0xbb,0x14,0x98,0xfa,0x1d,0x26,0xce,0x0a,0x83,0x5a,0x76,0x0b,0x92,0xca,0x7c,0x85,},{0xc1,0x79,0xc0,0x94,0x56,0xe2,0x35,0xfe,0x24,0x10,0x5a,0xfa,0x6e,0x8e,0xc0,0x46,0x37,0xf8,0xf9,0x43,0x81,0x7c,0xd0,0x98,0xba,0x95,0x38,0x7f,0x96,0x53,0xb2,0xad,0xd1,0x81,0xa3,0x14,0x47,0xd9,0x2d,0x1a,0x1d,0xdf,0x1c,0xeb,0x0d,0xb6,0x21,0x18,0xde,0x9d,0xff,0xb7,0xdc,0xd2,0x42,0x40,0x57,0xcb,0xdf,0xf5,0xd4,0x1d,0x04,0x03,},"\x65\x64\x1c\xd4\x02\xad\xd8\xbf\x3d\x1d\x67\xdb\xeb\x6d\x41\xde\xbf\xbe\xf6\x7e\x43\x17\xc3\x5b\x0a\x6d\x5b\xbb\xae\x0e\x03\x4d\xe7\xd6\x70\xba\x14\x13\xd0\x56\xf2\xd6\xf1\xde\x12"}, -{{0x89,0xf0,0xd6,0x82,0x99,0xba,0x0a,0x5a,0x83,0xf2,0x48,0xae,0x0c,0x16,0x9f,0x8e,0x38,0x49,0xa9,0xb4,0x7b,0xd4,0x54,0x98,0x84,0x30,0x5c,0x99,0x12,0xb4,0x66,0x03,},{0xab,0xa3,0xe7,0x95,0xaa,0xb2,0x01,0x2a,0xcc,0xea,0xdd,0x7b,0x3b,0xd9,0xda,0xee,0xed,0x6f,0xf5,0x25,0x8b,0xdc,0xd7,0xc9,0x36,0x99,0xc2,0xa3,0x83,0x6e,0x38,0x32,},{0x2c,0x69,0x1f,0xa8,0xd4,0x87,0xce,0x20,0xd5,0xd2,0xfa,0x41,0x55,0x91,0x16,0xe0,0xbb,0xf4,0x39,0x7c,0xf5,0x24,0x0e,0x15,0x25,0x56,0x18,0x35,0x41,0xd6,0x6c,0xf7,0x53,0x58,0x24,0x01,0xa4,0x38,0x8d,0x39,0x03,0x39,0xdb,0xef,0x4d,0x38,0x47,0x43,0xca,0xa3,0x46,0xf5,0x5f,0x8d,0xab,0xa6,0x8b,0xa7,0xb9,0x13,0x1a,0x8a,0x6e,0x0b,},"\x4f\x18\x46\xdd\x7a\xd5\x0e\x54\x5d\x4c\xfb\xff\xbb\x1d\xc2\xff\x14\x5d\xc1\x23\x75\x4d\x08\xaf\x4e\x44\xec\xc0\xbc\x8c\x91\x41\x13\x88\xbc\x76\x53\xe2\xd8\x93\xd1\xea\xc2\x10\x7d\x05"}, -{{0x0a,0x3c,0x18,0x44,0xe2,0xdb,0x07,0x0f,0xb2,0x4e,0x3c,0x95,0xcb,0x1c,0xc6,0x71,0x4e,0xf8,0x4e,0x2c,0xcd,0x2b,0x9d,0xd2,0xf1,0x46,0x0e,0xbf,0x7e,0xcf,0x13,0xb1,},{0x72,0xe4,0x09,0x93,0x7e,0x06,0x10,0xeb,0x5c,0x20,0xb3,0x26,0xdc,0x6e,0xa1,0xbb,0xbc,0x04,0x06,0x70,0x1c,0x5c,0xd6,0x7d,0x1f,0xbd,0xe0,0x91,0x92,0xb0,0x7c,0x01,},{0x87,0xf7,0xfd,0xf4,0x60,0x95,0x20,0x1e,0x87,0x7a,0x58,0x8f,0xe3,0xe5,0xaa,0xf4,0x76,0xbd,0x63,0x13,0x8d,0x8a,0x87,0x8b,0x89,0xd6,0xac,0x60,0x63,0x1b,0x34,0x58,0xb9,0xd4,0x1a,0x3c,0x61,0xa5,0x88,0xe1,0xdb,0x8d,0x29,0xa5,0x96,0x89,0x81,0xb0,0x18,0x77,0x6c,0x58,0x87,0x80,0x92,0x2f,0x5a,0xa7,0x32,0xba,0x63,0x79,0xdd,0x05,},"\x4c\x82\x74\xd0\xed\x1f\x74\xe2\xc8\x6c\x08\xd9\x55\xbd\xe5\x5b\x2d\x54\x32\x7e\x82\x06\x2a\x1f\x71\xf7\x0d\x53\x6f\xdc\x87\x22\xcd\xea\xd7\xd2\x2a\xae\xad\x2b\xfa\xa1\xad\x00\xb8\x29\x57"}, -{{0xc8,0xd7,0xa8,0x81,0x8b,0x98,0xdf,0xdb,0x20,0x83,0x9c,0x87,0x1c,0xb5,0xc4,0x8e,0x9e,0x94,0x70,0xca,0x3a,0xd3,0x5b,0xa2,0x61,0x3a,0x5d,0x31,0x99,0xc8,0xab,0x23,},{0x90,0xd2,0xef,0xbb,0xa4,0xd4,0x3e,0x6b,0x2b,0x99,0x2c,0xa1,0x60,0x83,0xdb,0xcf,0xa2,0xb3,0x22,0x38,0x39,0x07,0xb0,0xee,0x75,0xf3,0xe9,0x58,0x45,0xd3,0xc4,0x7f,},{0xfa,0x2e,0x99,0x44,0x21,0xae,0xf1,0xd5,0x85,0x66,0x74,0x81,0x3d,0x05,0xcb,0xd2,0xcf,0x84,0xef,0x5e,0xb4,0x24,0xaf,0x6e,0xcd,0x0d,0xc6,0xfd,0xbd,0xc2,0xfe,0x60,0x5f,0xe9,0x85,0x88,0x33,0x12,0xec,0xf3,0x4f,0x59,0xbf,0xb2,0xf1,0xc9,0x14,0x9e,0x5b,0x9c,0xc9,0xec,0xda,0x05,0xb2,0x73,0x11,0x30,0xf3,0xed,0x28,0xdd,0xae,0x0b,},"\x78\x3e\x33\xc3\xac\xbd\xbb\x36\xe8\x19\xf5\x44\xa7\x78\x1d\x83\xfc\x28\x3d\x33\x09\xf5\xd3\xd1\x2c\x8d\xcd\x6b\x0b\x3d\x0e\x89\xe3\x8c\xfd\x3b\x4d\x08\x85\x66\x1c\xa5\x47\xfb\x97\x64\xab\xff"}, -{{0xb4,0x82,0x70,0x36,0x12,0xd0,0xc5,0x86,0xf7,0x6c,0xfc,0xb2,0x1c,0xfd,0x21,0x03,0xc9,0x57,0x25,0x15,0x04,0xa8,0xc0,0xac,0x4c,0x86,0xc9,0xc6,0xf3,0xe4,0x29,0xff,},{0xfd,0x71,0x1d,0xc7,0xdd,0x3b,0x1d,0xfb,0x9d,0xf9,0x70,0x4b,0xe3,0xe6,0xb2,0x6f,0x58,0x7f,0xe7,0xdd,0x7b,0xa4,0x56,0xa9,0x1b,0xa4,0x3f,0xe5,0x1a,0xec,0x09,0xad,},{0x58,0x83,0x2b,0xde,0xb2,0x6f,0xea,0xfc,0x31,0xb4,0x62,0x77,0xcf,0x3f,0xb5,0xd7,0xa1,0x7d,0xfb,0x7c,0xcd,0x9b,0x1f,0x58,0xec,0xbe,0x6f,0xeb,0x97,0x96,0x66,0x82,0x8f,0x23,0x9b,0xa4,0xd7,0x52,0x19,0x26,0x0e,0xca,0xc0,0xac,0xf4,0x0f,0x0e,0x5e,0x25,0x90,0xf4,0xca,0xa1,0x6b,0xbb,0xcd,0x8a,0x15,0x5d,0x34,0x79,0x67,0xa6,0x07,},"\x29\xd7\x7a\xcf\xd9\x9c\x7a\x00\x70\xa8\x8f\xeb\x62\x47\xa2\xbc\xe9\x98\x4f\xe3\xe6\xfb\xf1\x9d\x40\x45\x04\x2a\x21\xab\x26\xcb\xd7\x71\xe1\x84\xa9\xa7\x5f\x31\x6b\x64\x8c\x69\x20\xdb\x92\xb8\x7b"}, -{{0x84,0xe5,0x0d,0xd9,0xa0,0xf1,0x97,0xe3,0x89,0x3c,0x38,0xdb,0xd9,0x1f,0xaf,0xc3,0x44,0xc1,0x77,0x6d,0x3a,0x40,0x0e,0x2f,0x0f,0x0e,0xe7,0xaa,0x82,0x9e,0xb8,0xa2,},{0x2c,0x50,0xf8,0x70,0xee,0x48,0xb3,0x6b,0x0a,0xc2,0xf8,0xa5,0xf3,0x36,0xfb,0x09,0x0b,0x11,0x30,0x50,0xdb,0xcc,0x25,0xe0,0x78,0x20,0x0a,0x6e,0x16,0x15,0x3e,0xea,},{0x69,0xe6,0xa4,0x49,0x1a,0x63,0x83,0x73,0x16,0xe8,0x6a,0x5f,0x4b,0xa7,0xcd,0x0d,0x73,0x1e,0xcc,0x58,0xf1,0xd0,0xa2,0x64,0xc6,0x7c,0x89,0xbe,0xfd,0xd8,0xd3,0x82,0x9d,0x8d,0xe1,0x3b,0x33,0xcc,0x0b,0xf5,0x13,0x93,0x17,0x15,0xc7,0x80,0x96,0x57,0xe2,0xbf,0xb9,0x60,0xe5,0xc7,0x64,0xc9,0x71,0xd7,0x33,0x74,0x60,0x93,0xe5,0x00,},"\xf3\x99\x2c\xde\x64\x93\xe6\x71\xf1\xe1\x29\xdd\xca\x80\x38\xb0\xab\xdb\x77\xbb\x90\x35\xf9\xf8\xbe\x54\xbd\x5d\x68\xc1\xae\xff\x72\x4f\xf4\x7d\x29\x34\x43\x91\xdc\x53\x61\x66\xb8\x67\x1c\xbb\xf1\x23"}, -{{0xb3,0x22,0xd4,0x65,0x77,0xa2,0xa9,0x91,0xa4,0xd1,0x69,0x82,0x87,0x83,0x2a,0x39,0xc4,0x87,0xef,0x77,0x6b,0x4b,0xff,0x03,0x7a,0x05,0xc7,0xf1,0x81,0x2b,0xde,0xec,},{0xeb,0x2b,0xca,0xdf,0xd3,0xee,0xc2,0x98,0x6b,0xaf,0xf3,0x2b,0x98,0xe7,0xc4,0xdb,0xf0,0x3f,0xf9,0x5d,0x8a,0xd5,0xff,0x9a,0xa9,0x50,0x6e,0x54,0x72,0xff,0x84,0x5f,},{0xc7,0xb5,0x51,0x37,0x31,0x7c,0xa2,0x1e,0x33,0x48,0x9f,0xf6,0xa9,0xbf,0xab,0x97,0xc8,0x55,0xdc,0x6f,0x85,0x68,0x4a,0x70,0xa9,0x12,0x5a,0x26,0x1b,0x56,0xd5,0xe6,0xf1,0x49,0xc5,0x77,0x4d,0x73,0x4f,0x2d,0x8d,0xeb,0xfc,0x77,0xb7,0x21,0x89,0x6a,0x82,0x67,0xc2,0x37,0x68,0xe9,0xba,0xdb,0x91,0x0e,0xef,0x83,0xec,0x25,0x88,0x02,},"\x19\xf1\xbf\x5d\xcf\x17\x50\xc6\x11\xf1\xc4\xa2\x86\x52\x00\x50\x4d\x82\x29\x8e\xdd\x72\x67\x1f\x62\xa7\xb1\x47\x1a\xc3\xd4\xa3\x0f\x7d\xe9\xe5\xda\x41\x08\xc5\x2a\x4c\xe7\x0a\x3e\x11\x4a\x52\xa3\xb3\xc5"}, -{{0x96,0x0c,0xab,0x50,0x34,0xb9,0x83,0x8d,0x09,0x8d,0x2d,0xcb,0xf4,0x36,0x4b,0xec,0x16,0xd3,0x88,0xf6,0x37,0x6d,0x73,0xa6,0x27,0x3b,0x70,0xf8,0x2b,0xbc,0x98,0xc0,},{0x5e,0x3c,0x19,0xf2,0x41,0x5a,0xcf,0x72,0x9f,0x82,0x9a,0x4e,0xbd,0x5c,0x40,0xe1,0xa6,0xbc,0x9f,0xbc,0xa9,0x57,0x03,0xa9,0x37,0x60,0x87,0xed,0x09,0x37,0xe5,0x1a,},{0x27,0xd4,0xc3,0xa1,0x81,0x1e,0xf9,0xd4,0x36,0x0b,0x3b,0xdd,0x13,0x3c,0x2c,0xcc,0x30,0xd0,0x2c,0x2f,0x24,0x82,0x15,0x77,0x6c,0xb0,0x7e,0xe4,0x17,0x7f,0x9b,0x13,0xfc,0x42,0xdd,0x70,0xa6,0xc2,0xfe,0xd8,0xf2,0x25,0xc7,0x66,0x3c,0x7f,0x18,0x2e,0x7e,0xe8,0xec,0xcf,0xf2,0x0d,0xc7,0xb0,0xe1,0xd5,0x83,0x4e,0xc5,0xb1,0xea,0x01,},"\xf8\xb2\x19\x62\x44\x7b\x0a\x8f\x2e\x42\x79\xde\x41\x1b\xea\x12\x8e\x0b\xe4\x4b\x69\x15\xe6\xcd\xa8\x83\x41\xa6\x8a\x0d\x81\x83\x57\xdb\x93\x8e\xac\x73\xe0\xaf\x6d\x31\x20\x6b\x39\x48\xf8\xc4\x8a\x44\x73\x08"}, -{{0xeb,0x77,0xb2,0x63,0x8f,0x23,0xee,0xbc,0x82,0xef,0xe4,0x5e,0xe9,0xe5,0xa0,0x32,0x66,0x37,0x40,0x1e,0x66,0x3e,0xd0,0x29,0x69,0x9b,0x21,0xe6,0x44,0x3f,0xb4,0x8e,},{0x9e,0xf2,0x76,0x08,0x96,0x1a,0xc7,0x11,0xde,0x71,0xa6,0xe2,0xd4,0xd4,0x66,0x3e,0xa3,0xec,0xd4,0x2f,0xb7,0xe4,0xe8,0x62,0x7c,0x39,0x62,0x2d,0xf4,0xaf,0x0b,0xbc,},{0x18,0xdc,0x56,0xd7,0xbd,0x9a,0xcd,0x4f,0x4d,0xaa,0x78,0x54,0x0b,0x4a,0xc8,0xff,0x7a,0xa9,0x81,0x5f,0x45,0xa0,0xbb,0xa3,0x70,0x73,0x1a,0x14,0xea,0xab,0xe9,0x6d,0xf8,0xb5,0xf3,0x7d,0xbf,0x8e,0xae,0x4c,0xb1,0x5a,0x64,0xb2,0x44,0x65,0x1e,0x59,0xd6,0xa3,0xd6,0x76,0x1d,0x9e,0x3c,0x50,0xf2,0xd0,0xcb,0xb0,0x9c,0x05,0xec,0x06,},"\x99\xe3\xd0\x09\x34\x00\x3e\xba\xfc\x3e\x9f\xdb\x68\x7b\x0f\x5f\xf9\xd5\x78\x2a\x4b\x1f\x56\xb9\x70\x00\x46\xc0\x77\x91\x56\x02\xc3\x13\x4e\x22\xfc\x90\xed\x7e\x69\x0f\xdd\xd4\x43\x3e\x20\x34\xdc\xb2\xdc\x99\xab"}, -{{0xb6,0x25,0xaa,0x89,0xd3,0xf7,0x30,0x87,0x15,0x42,0x7b,0x6c,0x39,0xbb,0xac,0x58,0xef,0xfd,0x3a,0x0f,0xb7,0x31,0x6f,0x7a,0x22,0xb9,0x9e,0xe5,0x92,0x2f,0x2d,0xc9,},{0x65,0xa9,0x9c,0x3e,0x16,0xfe,0xa8,0x94,0xec,0x33,0xc6,0xb2,0x0d,0x91,0x05,0xe2,0xa0,0x4e,0x27,0x64,0xa4,0x76,0x9d,0x9b,0xbd,0x4d,0x8b,0xac,0xfe,0xab,0x4a,0x2e,},{0x01,0xbb,0x90,0x1d,0x83,0xb8,0xb6,0x82,0xd3,0x61,0x4a,0xf4,0x6a,0x80,0x7b,0xa2,0x69,0x13,0x58,0xfe,0xb7,0x75,0x32,0x5d,0x34,0x23,0xf5,0x49,0xff,0x0a,0xa5,0x75,0x7e,0x4e,0x1a,0x74,0xe9,0xc7,0x0f,0x97,0x21,0xd8,0xf3,0x54,0xb3,0x19,0xd4,0xf4,0xa1,0xd9,0x14,0x45,0xc8,0x70,0xfd,0x0f,0xfb,0x94,0xfe,0xd6,0x46,0x64,0x73,0x0d,},"\xe0\x72\x41\xdb\xd3\xad\xbe\x61\x0b\xbe\x4d\x00\x5d\xd4\x67\x32\xa4\xc2\x50\x86\xec\xb8\xec\x29\xcd\x7b\xca\x11\x6e\x1b\xf9\xf5\x3b\xfb\xf3\xe1\x1f\xa4\x90\x18\xd3\x9f\xf1\x15\x4a\x06\x66\x8e\xf7\xdf\x5c\x67\x8e\x6a"}, -{{0xb1,0xc9,0xf8,0xbd,0x03,0xfe,0x82,0xe7,0x8f,0x5c,0x0f,0xb0,0x64,0x50,0xf2,0x7d,0xac,0xdf,0x71,0x64,0x34,0xdb,0x26,0x82,0x75,0xdf,0x3e,0x1d,0xc1,0x77,0xaf,0x42,},{0x7f,0xc8,0x8b,0x1f,0x7b,0x3f,0x11,0xc6,0x29,0xbe,0x67,0x1c,0x21,0x62,0x1f,0x5c,0x10,0x67,0x2f,0xaf,0xc8,0x49,0x2d,0xa8,0x85,0x74,0x20,0x59,0xee,0x67,0x74,0xcf,},{0x4b,0x22,0x99,0x51,0xef,0x26,0x2f,0x16,0x97,0x8f,0x79,0x14,0xbc,0x67,0x2e,0x72,0x26,0xc5,0xf8,0x37,0x9d,0x27,0x78,0xc5,0xa2,0xdc,0x0a,0x26,0x50,0x86,0x9f,0x7a,0xcf,0xbd,0x0b,0xcd,0x30,0xfd,0xb0,0x61,0x9b,0xb4,0x4f,0xc1,0xae,0x59,0x39,0xb8,0x7c,0xc3,0x18,0x13,0x30,0x09,0xc2,0x03,0x95,0xb6,0xc7,0xeb,0x98,0x10,0x77,0x01,},"\x33\x1d\xa7\xa9\xc1\xf8\x7b\x2a\xc9\x1e\xe3\xb8\x6d\x06\xc2\x91\x63\xc0\x5e\xd6\xf8\xd8\xa9\x72\x5b\x47\x1b\x7d\xb0\xd6\xac\xec\x7f\x0f\x70\x24\x87\x16\x3f\x5e\xda\x02\x0c\xa5\xb4\x93\xf3\x99\xe1\xc8\xd3\x08\xc3\xc0\xc2"}, -{{0x6d,0x8c,0xdb,0x2e,0x07,0x5f,0x3a,0x2f,0x86,0x13,0x72,0x14,0xcb,0x23,0x6c,0xeb,0x89,0xa6,0x72,0x8b,0xb4,0xa2,0x00,0x80,0x6b,0xf3,0x55,0x7f,0xb7,0x8f,0xac,0x69,},{0x57,0xa0,0x4c,0x7a,0x51,0x13,0xcd,0xdf,0xe4,0x9a,0x4c,0x12,0x46,0x91,0xd4,0x6c,0x1f,0x9c,0xdc,0x8f,0x34,0x3f,0x9d,0xcb,0x72,0xa1,0x33,0x0a,0xec,0xa7,0x1f,0xda,},{0xa6,0xcb,0xc9,0x47,0xf9,0xc8,0x7d,0x14,0x55,0xcf,0x1a,0x70,0x85,0x28,0xc0,0x90,0xf1,0x1e,0xce,0xe4,0x85,0x5d,0x1d,0xba,0xad,0xf4,0x74,0x54,0xa4,0xde,0x55,0xfa,0x4c,0xe8,0x4b,0x36,0xd7,0x3a,0x5b,0x5f,0x8f,0x59,0x29,0x8c,0xcf,0x21,0x99,0x2d,0xf4,0x92,0xef,0x34,0x16,0x3d,0x87,0x75,0x3b,0x7e,0x9d,0x32,0xf2,0xc3,0x66,0x0b,},"\x7f\x31\x8d\xbd\x12\x1c\x08\xbf\xdd\xfe\xff\x4f\x6a\xff\x4e\x45\x79\x32\x51\xf8\xab\xf6\x58\x40\x33\x58\x23\x89\x84\x36\x00\x54\xf2\xa8\x62\xc5\xbb\x83\xed\x89\x02\x5d\x20\x14\xa7\xa0\xce\xe5\x0d\xa3\xcb\x0e\x76\xbb\xb6\xbf"}, -{{0x47,0xad,0xc6,0xd6,0xbf,0x57,0x1e,0xe9,0x57,0x0c,0xa0,0xf7,0x5b,0x60,0x4a,0xc4,0x3e,0x30,0x3e,0x4a,0xb3,0x39,0xca,0x9b,0x53,0xca,0xcc,0x5b,0xe4,0x5b,0x2c,0xcb,},{0xa3,0xf5,0x27,0xa1,0xc1,0xf1,0x7d,0xfe,0xed,0x92,0x27,0x73,0x47,0xc9,0xf9,0x8a,0xb4,0x75,0xde,0x17,0x55,0xb0,0xab,0x54,0x6b,0x8a,0x15,0xd0,0x1b,0x9b,0xd0,0xbe,},{0x4e,0x8c,0x31,0x83,0x43,0xc3,0x06,0xad,0xbb,0xa6,0x0c,0x92,0xb7,0x5c,0xb0,0x56,0x9b,0x92,0x19,0xd8,0xa8,0x6e,0x5d,0x57,0x75,0x2e,0xd2,0x35,0xfc,0x10,0x9a,0x43,0xc2,0xcf,0x4e,0x94,0x2c,0xac,0xf2,0x97,0x27,0x9f,0xbb,0x28,0x67,0x53,0x47,0xe0,0x80,0x27,0x72,0x2a,0x4e,0xb7,0x39,0x5e,0x00,0xa1,0x74,0x95,0xd3,0x2e,0xdf,0x0b,},"\xce\x49\x7c\x5f\xf5\xa7\x79\x90\xb7\xd8\xf8\x69\x9e\xb1\xf5\xd8\xc0\x58\x2f\x70\xcb\x7a\xc5\xc5\x4d\x9d\x92\x49\x13\x27\x8b\xc6\x54\xd3\x7e\xa2\x27\x59\x0e\x15\x20\x22\x17\xfc\x98\xda\xc4\xc0\xf3\xbe\x21\x83\xd1\x33\x31\x57\x39"}, -{{0x3c,0x19,0xb5,0x0b,0x0f,0xe4,0x79,0x61,0x71,0x9c,0x38,0x1d,0x0d,0x8d,0xa9,0xb9,0x86,0x9d,0x31,0x2f,0x13,0xe3,0x29,0x8b,0x97,0xfb,0x22,0xf0,0xaf,0x29,0xcb,0xbe,},{0x0f,0x7e,0xda,0x09,0x14,0x99,0x62,0x5e,0x2b,0xae,0x85,0x36,0xea,0x35,0xcd,0xa5,0x48,0x3b,0xd1,0x6a,0x9c,0x7e,0x41,0x6b,0x34,0x1d,0x6f,0x2c,0x83,0x34,0x36,0x12,},{0xef,0xbd,0x41,0xf2,0x6a,0x5d,0x62,0x68,0x55,0x16,0xf8,0x82,0xb6,0xec,0x74,0xe0,0xd5,0xa7,0x18,0x30,0xd2,0x03,0xc2,0x31,0x24,0x8f,0x26,0xe9,0x9a,0x9c,0x65,0x78,0xec,0x90,0x0d,0x68,0xcd,0xb8,0xfa,0x72,0x16,0xad,0x0d,0x24,0xf9,0xec,0xbc,0x9f,0xfa,0x65,0x53,0x51,0x66,0x65,0x82,0xf6,0x26,0x64,0x53,0x95,0xa3,0x1f,0xa7,0x04,},"\x8d\xdc\xd6\x30\x43\xf5\x5e\xc3\xbf\xc8\x3d\xce\xae\x69\xd8\xf8\xb3\x2f\x4c\xdb\x6e\x2a\xeb\xd9\x4b\x43\x14\xf8\xfe\x72\x87\xdc\xb6\x27\x32\xc9\x05\x2e\x75\x57\xfe\x63\x53\x43\x38\xef\xb5\xb6\x25\x4c\x5d\x41\xd2\x69\x0c\xf5\x14\x4f"}, -{{0x34,0xe1,0xe9,0xd5,0x39,0x10,0x7e,0xb8,0x6b,0x39,0x3a,0x5c,0xce,0xa1,0x49,0x6d,0x35,0xbc,0x7d,0x5e,0x9a,0x8c,0x51,0x59,0xd9,0x57,0xe4,0xe5,0x85,0x2b,0x3e,0xb0,},{0x0e,0xcb,0x26,0x01,0xd5,0xf7,0x04,0x74,0x28,0xe9,0xf9,0x09,0x88,0x3a,0x12,0x42,0x00,0x85,0xf0,0x4e,0xe2,0xa8,0x8b,0x6d,0x95,0xd3,0xd7,0xf2,0xc9,0x32,0xbd,0x76,},{0x32,0xd2,0x29,0x04,0xd3,0xe7,0x01,0x2d,0x6f,0x5a,0x44,0x1b,0x0b,0x42,0x28,0x06,0x4a,0x5c,0xf9,0x5b,0x72,0x3a,0x66,0xb0,0x48,0xa0,0x87,0xec,0xd5,0x59,0x20,0xc3,0x1c,0x20,0x4c,0x3f,0x20,0x06,0x89,0x1a,0x85,0xdd,0x19,0x32,0xe3,0xf1,0xd6,0x14,0xcf,0xd6,0x33,0xb5,0xe6,0x32,0x91,0xc6,0xd8,0x16,0x6f,0x30,0x11,0x43,0x1e,0x09,},"\xa6\xd4\xd0\x54\x2c\xfe\x0d\x24\x0a\x90\x50\x7d\xeb\xac\xab\xce\x7c\xbb\xd4\x87\x32\x35\x3f\x4f\xad\x82\xc7\xbb\x7d\xbd\x9d\xf8\xe7\xd9\xa1\x69\x80\xa4\x51\x86\xd8\x78\x6c\x5e\xf6\x54\x45\xbc\xc5\xb2\xad\x5f\x66\x0f\xfc\x7c\x8e\xaa\xc0"}, -{{0x49,0xdd,0x47,0x3e,0xde,0x6a,0xa3,0xc8,0x66,0x82,0x4a,0x40,0xad,0xa4,0x99,0x6c,0x23,0x9a,0x20,0xd8,0x4c,0x93,0x65,0xe4,0xf0,0xa4,0x55,0x4f,0x80,0x31,0xb9,0xcf,},{0x78,0x8d,0xe5,0x40,0x54,0x4d,0x3f,0xeb,0x0c,0x91,0x92,0x40,0xb3,0x90,0x72,0x9b,0xe4,0x87,0xe9,0x4b,0x64,0xad,0x97,0x3e,0xb6,0x5b,0x46,0x69,0xec,0xf2,0x35,0x01,},{0xd2,0xfd,0xe0,0x27,0x91,0xe7,0x20,0x85,0x25,0x07,0xfa,0xa7,0xc3,0x78,0x90,0x40,0xd9,0xef,0x86,0x64,0x63,0x21,0xf3,0x13,0xac,0x55,0x7f,0x40,0x02,0x49,0x15,0x42,0xdd,0x67,0xd0,0x5c,0x69,0x90,0xcd,0xb0,0xd4,0x95,0x50,0x1f,0xbc,0x5d,0x51,0x88,0xbf,0xbb,0x84,0xdc,0x1b,0xf6,0x09,0x8b,0xee,0x06,0x03,0xa4,0x7f,0xc2,0x69,0x0f,},"\x3a\x53\x59\x4f\x3f\xba\x03\x02\x93\x18\xf5\x12\xb0\x84\xa0\x71\xeb\xd6\x0b\xae\xc7\xf5\x5b\x02\x8d\xc7\x3b\xfc\x9c\x74\xe0\xca\x49\x6b\xf8\x19\xdd\x92\xab\x61\xcd\x8b\x74\xbe\x3c\x0d\x6d\xcd\x12\x8e\xfc\x5e\xd3\x34\x2c\xba\x12\x4f\x72\x6c"}, -{{0x33,0x1c,0x64,0xda,0x48,0x2b,0x6b,0x55,0x13,0x73,0xc3,0x64,0x81,0xa0,0x2d,0x81,0x36,0xec,0xad,0xbb,0x01,0xab,0x11,0x4b,0x44,0x70,0xbf,0x41,0x60,0x7a,0xc5,0x71,},{0x52,0xa0,0x0d,0x96,0xa3,0x14,0x8b,0x47,0x26,0x69,0x2d,0x9e,0xff,0x89,0x16,0x0e,0xa9,0xf9,0x9a,0x5c,0xc4,0x38,0x9f,0x36,0x1f,0xed,0x0b,0xb1,0x6a,0x42,0xd5,0x21,},{0x22,0xc9,0x9a,0xa9,0x46,0xea,0xd3,0x9a,0xc7,0x99,0x75,0x62,0x81,0x0c,0x01,0xc2,0x0b,0x46,0xbd,0x61,0x06,0x45,0xbd,0x2d,0x56,0xdc,0xdc,0xba,0xac,0xc5,0x45,0x2c,0x74,0xfb,0xf4,0xb8,0xb1,0x81,0x3b,0x0e,0x94,0xc3,0x0d,0x80,0x8c,0xe5,0x49,0x8e,0x61,0xd4,0xf7,0xcc,0xbb,0x4c,0xc5,0xf0,0x4d,0xfc,0x61,0x40,0x82,0x5a,0x96,0x00,},"\x20\xe1\xd0\x5a\x0d\x5b\x32\xcc\x81\x50\xb8\x11\x6c\xef\x39\x65\x9d\xd5\xfb\x44\x3a\xb1\x56\x00\xf7\x8e\x5b\x49\xc4\x53\x26\xd9\x32\x3f\x28\x50\xa6\x3c\x38\x08\x85\x94\x95\xae\x27\x3f\x58\xa5\x1e\x9d\xe9\xa1\x45\xd7\x74\xb4\x0b\xa9\xd7\x53\xd3"}, -{{0x5c,0x0b,0x96,0xf2,0xaf,0x87,0x12,0x12,0x2c,0xf7,0x43,0xc8,0xf8,0xdc,0x77,0xb6,0xcd,0x55,0x70,0xa7,0xde,0x13,0x29,0x7b,0xb3,0xdd,0xe1,0x88,0x62,0x13,0xcc,0xe2,},{0x05,0x10,0xea,0xf5,0x7d,0x73,0x01,0xb0,0xe1,0xd5,0x27,0x03,0x9b,0xf4,0xc6,0xe2,0x92,0x30,0x0a,0x3a,0x61,0xb4,0x76,0x54,0x34,0xf3,0x20,0x3c,0x10,0x03,0x51,0xb1,},{0x06,0xe5,0xd8,0x43,0x6a,0xc7,0x70,0x5b,0x3a,0x90,0xf1,0x63,0x1c,0xdd,0x38,0xec,0x1a,0x3f,0xa4,0x97,0x78,0xa9,0xb9,0xf2,0xfa,0x5e,0xbe,0xa4,0xe7,0xd5,0x60,0xad,0xa7,0xdd,0x26,0xff,0x42,0xfa,0xfa,0x8b,0xa4,0x20,0x32,0x37,0x42,0x76,0x1a,0xca,0x69,0x04,0x94,0x0d,0xc2,0x1b,0xbe,0xf6,0x3f,0xf7,0x2d,0xaa,0xb4,0x5d,0x43,0x0b,},"\x54\xe0\xca\xa8\xe6\x39\x19\xca\x61\x4b\x2b\xfd\x30\x8c\xcf\xe5\x0c\x9e\xa8\x88\xe1\xee\x44\x46\xd6\x82\xcb\x50\x34\x62\x7f\x97\xb0\x53\x92\xc0\x4e\x83\x55\x56\xc3\x1c\x52\x81\x6a\x48\xe4\xfb\x19\x66\x93\x20\x6b\x8a\xfb\x44\x08\x66\x2b\x3c\xb5\x75"}, -{{0xde,0x84,0xf2,0x43,0x5f,0x78,0xde,0xdb,0x87,0xda,0x18,0x19,0x4f,0xf6,0xa3,0x36,0xf0,0x81,0x11,0x15,0x0d,0xef,0x90,0x1c,0x1a,0xc4,0x18,0x14,0x6e,0xb7,0xb5,0x4a,},{0xd3,0xa9,0x2b,0xba,0xa4,0xd6,0x3a,0xf7,0x9c,0x22,0x26,0xa7,0x23,0x6e,0x64,0x27,0x42,0x8d,0xf8,0xb3,0x62,0x42,0x7f,0x87,0x30,0x23,0xb2,0x2d,0x2f,0x5e,0x03,0xf2,},{0x47,0x1e,0xbc,0x97,0x3c,0xfd,0xac,0xee,0xc0,0x72,0x79,0x30,0x73,0x68,0xb7,0x3b,0xe3,0x5b,0xc6,0xf8,0xd8,0x31,0x2b,0x70,0x15,0x05,0x67,0x36,0x90,0x96,0x70,0x6d,0xc4,0x71,0x12,0x6c,0x35,0x76,0xf9,0xf0,0xeb,0x55,0x0d,0xf5,0xac,0x6a,0x52,0x51,0x81,0x11,0x00,0x29,0xdd,0x1f,0xc1,0x11,0x74,0xd1,0xaa,0xce,0xd4,0x8d,0x63,0x0f,},"\x20\x51\x35\xec\x7f\x41\x7c\x85\x80\x72\xd5\x23\x3f\xb3\x64\x82\xd4\x90\x6a\xbd\x60\xa7\x4a\x49\x8c\x34\x7f\xf2\x48\xdf\xa2\x72\x2c\xa7\x4e\x87\x9d\xe3\x31\x69\xfa\xdc\x7c\xd4\x4d\x6c\x94\xa1\x7d\x16\xe1\xe6\x30\x82\x4b\xa3\xe0\xdf\x22\xed\x68\xea\xab"}, -{{0xba,0x4d,0x6e,0x67,0xb2,0xce,0x67,0xa1,0xe4,0x43,0x26,0x49,0x40,0x44,0xf3,0x7a,0x44,0x2f,0x3b,0x81,0x72,0x5b,0xc1,0xf9,0x34,0x14,0x62,0x71,0x8b,0x55,0xee,0x20,},{0xf7,0x3f,0xa0,0x76,0xf8,0x4b,0x6d,0xb6,0x75,0xa5,0xfd,0xa5,0xad,0x67,0xe3,0x51,0xa4,0x1e,0x8e,0x7f,0x29,0xad,0xd1,0x68,0x09,0xca,0x01,0x03,0x87,0xe9,0xc6,0xcc,},{0x57,0xb9,0xd2,0xa7,0x11,0x20,0x7f,0x83,0x74,0x21,0xba,0xe7,0xdd,0x48,0xea,0xa1,0x8e,0xab,0x1a,0x9a,0x70,0xa0,0xf1,0x30,0x58,0x06,0xfe,0xe1,0x7b,0x45,0x8f,0x3a,0x09,0x64,0xb3,0x02,0xd1,0x83,0x4d,0x3e,0x0a,0xc9,0xe8,0x49,0x6f,0x00,0x0b,0x77,0xf0,0x08,0x3b,0x41,0xf8,0xa9,0x57,0xe6,0x32,0xfb,0xc7,0x84,0x0e,0xee,0x6a,0x06,},"\x4b\xaf\xda\xc9\x09\x9d\x40\x57\xed\x6d\xd0\x8b\xca\xee\x87\x56\xe9\xa4\x0f\x2c\xb9\x59\x80\x20\xeb\x95\x01\x95\x28\x40\x9b\xbe\xa3\x8b\x38\x4a\x59\xf1\x19\xf5\x72\x97\xbf\xb2\xfa\x14\x2f\xc7\xbb\x1d\x90\xdb\xdd\xde\x77\x2b\xcd\xe4\x8c\x56\x70\xd5\xfa\x13"}, -{{0x0d,0x13,0x1c,0x45,0xae,0xa6,0xf3,0xa4,0xe1,0xb9,0xa2,0xcf,0x60,0xc5,0x51,0x04,0x58,0x7e,0xfa,0xa8,0x46,0xb2,0x22,0xbf,0x0a,0x7b,0x74,0xce,0x7a,0x3f,0x63,0xb6,},{0x3c,0x67,0x29,0xdb,0xe9,0x3b,0x49,0x9c,0x4e,0x61,0x4a,0x2f,0x21,0xbe,0xb7,0x29,0x43,0x8d,0x49,0x8e,0x1a,0xc8,0xd1,0x4c,0xba,0xd9,0x71,0x7a,0x5d,0xbd,0x97,0xcd,},{0xa9,0xc5,0xee,0x86,0xfb,0x06,0xd9,0xe4,0x6b,0x37,0x9c,0x32,0xdd,0xa7,0xc9,0x2c,0x9c,0x13,0xdb,0x27,0x4d,0xc2,0x41,0x16,0xfb,0xdd,0x87,0x86,0x96,0x04,0x54,0x88,0xcc,0x75,0xa5,0x2f,0xff,0x67,0xd1,0xa5,0x11,0x3d,0x06,0xe3,0x33,0xac,0x67,0xff,0x66,0x4b,0x3f,0x2a,0x40,0x5f,0xa1,0xd1,0x4d,0xd5,0xbb,0xb9,0x74,0x09,0xb6,0x06,},"\xb4\x29\x1d\x08\xb8\x8f\xb2\xf7\xb8\xf9\x9d\x0d\xce\x40\x07\x9f\xcb\xab\x71\x8b\xbd\x8f\x4e\x8e\xab\xc3\xc1\x42\x8b\x6a\x07\x1f\xb2\xa3\xc8\xeb\xa1\xca\xcc\xcf\xa8\x71\xb3\x65\xc7\x08\xbe\xf2\x68\x5b\xc1\x3e\x6b\x80\xbc\x14\xa5\xf2\x49\x17\x0f\xfc\x56\xd0\x14"}, -{{0xa7,0x5e,0x3b,0x6b,0x41,0x70,0xe4,0x44,0x78,0x1b,0xe4,0xee,0xac,0x3e,0x0f,0xda,0xa4,0xb4,0x35,0x6f,0x70,0x54,0x86,0xbc,0xb0,0x71,0xa3,0x25,0xae,0x07,0x1f,0xba,},{0x99,0x3d,0x38,0xa7,0xd7,0x2f,0x0a,0xee,0x15,0xff,0x6f,0x4f,0xdc,0x37,0xca,0x77,0x24,0xfd,0x13,0x73,0xa3,0x76,0x6b,0x27,0x5d,0xbc,0x77,0xe6,0x47,0x98,0x0e,0x0a,},{0xa5,0xdb,0x4d,0x3d,0x33,0x29,0xab,0xe3,0x69,0x79,0x59,0xe6,0xb5,0x94,0x7e,0xa8,0x60,0x1b,0x03,0xef,0x8e,0x1d,0x6f,0xe2,0x02,0x14,0x49,0x31,0x27,0x2c,0xa0,0xa0,0x9b,0x5e,0xb0,0xf3,0x90,0x57,0x2e,0xa7,0xef,0x03,0xc6,0x13,0x1e,0x9d,0xe5,0xf1,0x6b,0xf0,0xb0,0x34,0x24,0x4f,0x7e,0x10,0x4f,0xf5,0x31,0x1b,0xbf,0x66,0x3a,0x0d,},"\x40\x37\x86\x6f\x65\x48\xb0\x1c\xc6\xbc\xf3\xa9\x40\xe3\x94\x5a\xa2\xd1\x88\xb4\xb7\xf1\x82\xaa\x77\xec\x4d\x6b\x04\x28\xab\x5b\x84\xd8\x5d\xf1\x92\xa5\xa3\x8a\xda\x08\x9d\x76\xfa\x26\xbf\x67\x73\x6a\x70\x41\xa5\xeb\x8f\x0c\x57\x19\xeb\x39\x66\x93\xc4\x51\x60\xf8"}, -{{0xbc,0xbc,0xf5,0x61,0xec,0xc0,0x5a,0x41,0xc7,0xd7,0xe5,0x5e,0x69,0x6d,0x32,0xce,0x39,0xb4,0xd0,0x3c,0x1f,0x5f,0x3f,0x3a,0x89,0x27,0xfe,0x5e,0x62,0xe8,0x44,0xb2,},{0x4d,0xdf,0x53,0xfa,0xd6,0xa7,0xa9,0xed,0x30,0xf3,0xaf,0xec,0xca,0x13,0x6f,0xd7,0x84,0x3b,0x72,0xc2,0x43,0x09,0x08,0x91,0xae,0x40,0x21,0xa3,0x2c,0xad,0xff,0x1a,},{0x9f,0xf1,0x51,0x15,0xf6,0x66,0x1f,0x32,0x11,0xd7,0xa4,0x07,0x64,0x96,0x76,0x29,0xba,0x6a,0x52,0x63,0x95,0x1b,0xdc,0x3c,0x6a,0x4c,0x90,0xd0,0x70,0xf7,0xbe,0x00,0x02,0x4b,0x80,0xd8,0x3b,0x6b,0xc2,0x75,0x87,0xfc,0xff,0x5f,0x5c,0xcc,0x0e,0xb3,0xcd,0xe1,0x49,0x7c,0xf5,0x68,0x95,0x14,0x7a,0x06,0x3f,0x61,0xf0,0x8a,0xdf,0x0b,},"\x6f\x67\x16\xb6\x78\x47\x40\x98\x0a\xeb\xc3\x24\x88\x07\xe3\x1c\x12\x86\xac\x7b\x68\x1c\x00\xb6\x6c\x88\xff\x7a\x33\x6d\x44\x1f\xa5\xc3\xeb\x25\x6d\x20\xcf\x6d\x1a\xc9\x2c\xcf\xe4\xbe\x6d\xcc\x41\xb1\xaf\xf8\x46\xd3\x60\xc2\x43\x00\x1c\xab\xdf\xbf\x1a\x9b\x24\x04\x55"}, -{{0x21,0x05,0x32,0x80,0x5f,0xa9,0xcc,0x9b,0xe9,0x16,0xd2,0x13,0xca,0xc3,0x74,0xe3,0xcd,0x6f,0xc2,0x60,0x2a,0x54,0x4d,0x0c,0x1c,0xe2,0x9d,0x30,0x10,0x5d,0x69,0xab,},{0x10,0x69,0x9e,0x49,0x9b,0xe9,0x9e,0x2b,0x11,0xb9,0x8f,0x6f,0x86,0xb6,0x7c,0xdc,0x4c,0xcf,0x69,0xf3,0xc5,0x3c,0xe0,0x94,0x87,0x56,0x47,0xd2,0xd0,0xd0,0xec,0xc5,},{0x4c,0x2d,0x31,0xd5,0xbb,0xc4,0x2e,0x02,0x6d,0xc1,0xe0,0x79,0xec,0xc4,0xdd,0x07,0x2c,0x5d,0x2c,0xce,0x65,0xe3,0xdb,0x8d,0x8a,0x1d,0xd9,0x05,0x7f,0xaa,0x03,0x71,0x72,0x7f,0x72,0x72,0x31,0xa0,0xf0,0x60,0xfa,0x27,0x09,0x75,0x33,0xb6,0xdb,0x3b,0x8f,0x62,0x52,0xf2,0x79,0x3d,0x75,0x66,0x2c,0xaa,0xdf,0x5f,0x0f,0xcc,0x71,0x0e,},"\x9f\xc4\xd2\x8c\xfd\x25\xe6\xc0\xc5\xe7\x24\xe1\x9c\xa3\x9d\x71\xe5\x3b\xf4\xaa\x27\x96\xc5\x4c\x33\x51\xf1\x08\xfc\x70\xf2\x61\x1a\x62\xe0\xab\x90\xaf\x6a\xde\x52\x16\x78\x8e\x9e\xb2\xa8\x73\x05\x9b\x1e\x79\xd7\xd5\x9d\xeb\xd6\x8f\x2d\x4d\x80\xff\xe3\x1b\xf7\x4b\x92\x8c"}, -{{0x18,0x5d,0x64,0xb6,0x94,0x79,0xe0,0xba,0x0a,0x58,0x44,0xa1,0x0a,0xd8,0x41,0x25,0xba,0x11,0xc4,0xb4,0x0d,0x63,0xed,0xa2,0xc5,0x7a,0xfc,0x7e,0x01,0x9c,0x8e,0x0c,},{0xa5,0x76,0x4f,0x63,0x98,0xa5,0xae,0x22,0x66,0xa3,0x8f,0x97,0x14,0x53,0x3c,0x4b,0xbd,0x8d,0x07,0x82,0x6f,0x63,0xe2,0x04,0xcb,0xac,0x37,0x4b,0x0a,0xce,0xf1,0xbd,},{0x43,0xe0,0x38,0x7d,0xa5,0xba,0x09,0xa1,0x90,0xf6,0xe7,0xb2,0x68,0x05,0x78,0xd8,0x89,0x76,0x9b,0xcc,0x44,0x5e,0x5e,0xf5,0x71,0xb4,0x92,0x87,0x1c,0x15,0x5c,0x5b,0x9f,0x62,0x0b,0xfa,0xcf,0xbf,0x2d,0xf1,0xfd,0x87,0x44,0x46,0x04,0xb7,0x1b,0x2e,0x23,0x7b,0xaa,0xa7,0xee,0x20,0x93,0xed,0xe4,0xa6,0x01,0xed,0xf8,0x83,0xe3,0x07,},"\x4a\x08\x24\xfe\x70\xd4\x31\x54\x13\xd0\xa0\xca\xfb\xf4\xf5\xfe\x11\x7d\x5e\x07\xe1\xc3\xa4\xef\xfb\x9d\x0a\xe9\x14\x90\x23\x48\x78\xcc\xf6\x79\x2a\x91\xf6\x8c\x6a\x52\x0d\xe1\x60\x71\xf0\x8a\xbe\x35\xdc\x5e\xa4\x28\xf1\x95\x7b\x66\x33\x71\xce\x24\xc6\x09\xdd\x55\xb8\xf4\x93"}, -{{0xcf,0xa9,0xd9,0x16,0x4b,0x3c,0x4f,0x6f,0x72,0x26,0x35,0xd2,0x06,0x6c,0xd7,0xea,0x5e,0x55,0x33,0xd2,0xc7,0x4f,0x8a,0xdd,0x66,0x9c,0x37,0x1f,0xaa,0x47,0x64,0x26,},{0x41,0x16,0x9a,0x66,0xf9,0xa6,0x3f,0x28,0x57,0x82,0xa6,0xc2,0xdb,0x81,0xcc,0x3f,0x70,0xb3,0xad,0xa2,0x1a,0x68,0xc8,0x47,0x45,0xc8,0x8a,0x74,0xc3,0xb0,0xa2,0xde,},{0x01,0xd7,0xc9,0xb5,0x70,0x1a,0xf7,0x1e,0x2f,0x48,0x77,0xff,0xc9,0xb7,0xb5,0x30,0x5f,0x52,0x81,0x6d,0x44,0x58,0xe3,0x7e,0x41,0xc7,0x71,0x9f,0xac,0x1d,0x76,0xa0,0x1f,0xff,0x3f,0x50,0xfe,0x1a,0x58,0x75,0xcc,0xc3,0xfb,0x70,0x00,0x1c,0x94,0x7a,0x33,0xfc,0x8b,0x20,0x7d,0xe1,0x35,0x72,0xcc,0xdb,0x8b,0xa9,0x89,0x33,0xab,0x01,},"\x75\x76\x21\xb1\x67\x5d\xb7\xca\xce\xf7\xf2\x78\x25\x87\xff\x3a\xf5\x1a\x3e\xf2\xf4\xbc\xf9\x27\x9c\x4c\xe9\x40\x02\xe1\xf0\x04\x24\xbf\x0e\xb6\x21\x98\x2c\xc8\x5c\xb4\xd1\x71\xe5\x64\xa0\xc2\xf6\xe3\x56\x7a\x1a\xae\x2c\xdd\xb7\xe9\xb2\x5f\x47\xdc\x20\xa5\x10\x50\x54\x29\x69\xca"}, -{{0x1a,0xcb,0x4a,0x25,0x6c,0x2f,0x89,0x93,0xca,0x24,0xde,0x1e,0x00,0x14,0x60,0x6d,0x66,0x8b,0x5e,0x75,0x60,0x32,0xd2,0x69,0xf1,0xd2,0x4d,0x35,0x1c,0x8e,0xea,0x4a,},{0xcb,0xbd,0xcd,0x8c,0xbc,0x88,0x5a,0xb4,0x3a,0x05,0x7e,0x5f,0x95,0x79,0xf1,0x16,0x19,0x54,0x15,0x9e,0x7b,0x56,0x2e,0xa2,0x6c,0xd9,0xa4,0x3c,0x88,0xd3,0xf9,0x6d,},{0x05,0xaa,0x76,0xf7,0xfe,0x51,0x89,0x23,0x03,0xd7,0x89,0x14,0x71,0x59,0x95,0xe7,0xd7,0x68,0xff,0x77,0x14,0xce,0x27,0x0f,0x17,0x5e,0x56,0xaf,0x17,0xae,0x01,0x8d,0x3f,0xa9,0x39,0xf5,0xf6,0x20,0xde,0x82,0xbc,0xd1,0x54,0x96,0x87,0xb2,0x05,0xc7,0x87,0x12,0x03,0xe6,0x24,0x23,0x8c,0x4e,0x30,0x9f,0xab,0x7f,0x92,0xfb,0xaa,0x05,},"\xc4\x6a\x6d\x61\xaa\x0a\xed\x1c\x1d\x85\x47\xa7\x0b\x89\xb7\x19\x64\x75\xd5\xa4\x87\x08\x81\xb1\xec\xd0\xf0\xcb\x9c\x74\x5f\x8a\x2a\xdc\x80\x24\xe2\xdc\x55\xb5\x3a\xa5\xd3\x83\xa8\x1a\xab\xc1\xa4\x7e\x8d\x07\xd0\x0b\x7f\x0b\x56\xce\xdd\xbf\xb1\xf4\x24\xbb\x5c\x02\x18\x46\x78\xa6\x66"}, -{{0xac,0xe3,0xc4,0x64,0x24,0x82,0x36,0x22,0x97,0x9f,0xc3,0xa8,0x4a,0x7d,0xa6,0x9c,0x1d,0x52,0x7d,0x83,0x12,0xe8,0xfb,0x01,0x83,0x75,0xbd,0x3a,0x96,0xc2,0x9c,0x18,},{0x93,0x7c,0xf3,0x41,0x36,0xd9,0xe1,0xcc,0xe0,0xde,0x11,0xb1,0x2c,0x70,0xcb,0xfb,0x74,0x55,0x44,0x84,0x21,0xe9,0x2c,0x82,0xe7,0xc4,0x09,0x34,0xbf,0xf8,0xc6,0x76,},{0xfe,0xb8,0x89,0x6d,0xd3,0xfe,0x60,0x01,0xff,0xea,0x17,0x1b,0x37,0xb7,0x88,0xa6,0x9f,0x7f,0x85,0x01,0x93,0xa6,0x34,0x06,0xf5,0x63,0x76,0xdd,0x26,0x3d,0x09,0x9a,0xef,0x80,0xec,0xe6,0x7e,0x2c,0x43,0xf4,0x0e,0xca,0x46,0x2c,0x6b,0x71,0xe7,0x94,0x06,0xb1,0x8d,0xb7,0x4a,0xe5,0xd4,0x98,0x44,0xe3,0xb1,0x32,0xbc,0x2a,0x13,0x07,},"\xa9\xf1\x37\xbc\x90\x21\xbf\x10\x5a\xee\x25\xbe\x21\xcd\x9e\xe5\xb3\x54\x7c\xf1\x0c\xc5\xf9\x84\x76\xfb\x58\x8b\xd7\x0e\x2d\x6d\x6b\x08\x34\xe8\x42\xe4\xee\x94\x30\x3c\xf9\x6b\x09\xc1\x71\x53\x81\xb3\x6e\x14\xa4\x91\xb8\x0f\x89\x5e\xa4\x21\xb8\xec\x2b\x1d\x3c\x18\x7e\x02\x93\x5c\x55\x26"}, -{{0x88,0xf6,0x81,0x93,0x4e,0x33,0xc3,0x5c,0x07,0xdc,0x6e,0x5a,0x83,0x29,0x42,0xae,0x3d,0x59,0x90,0x3c,0xcd,0xe2,0xf7,0x6c,0xcb,0x75,0x87,0xce,0xa7,0xec,0x41,0xb6,},{0x6a,0x4e,0x8a,0xa5,0xad,0xb6,0x3d,0x22,0xfd,0x7b,0x14,0xa2,0x6f,0xdb,0x03,0xb7,0xc8,0xaa,0x6c,0xcd,0x5a,0x19,0x6f,0x2c,0x54,0xb0,0x46,0x5a,0xdb,0x50,0x92,0xe1,},{0x45,0xb2,0x7b,0xf1,0xb9,0xea,0xc0,0x6b,0x62,0xb6,0x86,0xf6,0xd5,0x46,0x56,0x3b,0x2d,0xfe,0x5b,0x17,0x5d,0xbe,0xf3,0x2b,0xf7,0x8c,0x35,0xa1,0x6c,0x95,0x8a,0x9d,0x4f,0x26,0xd2,0x91,0xde,0x9b,0xb2,0x06,0x6c,0x0a,0x28,0x61,0x13,0xcc,0x09,0x17,0x2d,0x40,0xa3,0x6d,0x4c,0xbd,0x95,0x17,0x08,0x86,0x02,0x26,0xeb,0x30,0xcd,0x05,},"\x6e\x8b\xac\x1f\x85\x3b\x81\xfe\xf9\x47\x07\xe1\x8c\xc6\x1c\x6f\x0a\x9c\xbc\x2a\x41\xd0\x78\xdc\xc8\x3f\xc0\x22\x9c\x7f\x8d\xbe\x6d\xbd\xd9\x08\x54\xb1\xf1\xae\x2b\x9f\x2b\x12\x0b\x86\xa8\x78\x6b\x4e\x78\xce\x23\xab\x86\xba\xaf\x88\x75\x4a\xf0\xf3\xd8\x88\x81\xda\xe0\xbc\x52\x61\xbf\xd0\x38"}, -{{0x48,0x05,0x0a,0x6e,0x01,0x58,0xf6,0xad,0x25,0x34,0x12,0xe4,0x49,0x7c,0xff,0x62,0xd5,0xee,0x55,0x5e,0xdf,0xfe,0x59,0xe4,0xdc,0x40,0x15,0x22,0x81,0x32,0x95,0xce,},{0x97,0x5e,0x01,0x0a,0xbb,0x9a,0x3e,0x56,0x65,0x91,0x37,0xb0,0x50,0x60,0x57,0xf2,0x83,0x98,0x2f,0x88,0x6c,0xa1,0x72,0xc7,0xbc,0x2c,0x50,0x0e,0xd9,0xbd,0x26,0xc1,},{0x72,0x16,0xab,0x60,0xc3,0x51,0x68,0x18,0x7d,0x0f,0xce,0x47,0x53,0xc8,0x6e,0x80,0x05,0x8d,0x54,0x0b,0x76,0xbf,0x95,0x84,0x3a,0x58,0x98,0x84,0x10,0x60,0xa9,0x9a,0x44,0xde,0x6f,0x43,0x96,0x25,0xa3,0xf6,0x36,0x5f,0x59,0xc3,0x77,0xbf,0x45,0x90,0x9b,0xbf,0xef,0x5c,0x50,0xb2,0x5f,0x31,0x94,0xe5,0xfb,0xd3,0x4e,0xa5,0xe7,0x06,},"\xed\x6e\xec\x29\xfb\x70\x49\xdf\xf7\x07\xf0\xa4\x42\x6e\xbc\x8f\x5b\x35\x0e\x95\x87\x0b\x9d\x61\x98\xc8\x13\x9e\x9c\x3e\x1e\x40\x99\x37\xd1\xa8\x58\xa0\xde\xa4\x82\xa5\xcb\x1a\x85\x4e\xd3\xb5\xa9\x39\x7a\xcb\x63\xbf\xf6\xb6\x40\x39\xef\x2e\xb1\x15\x9e\x99\x85\x83\x10\xbb\xbd\x86\x12\x5c\x3e\x0e"}, -{{0x18,0xd1,0x3d,0x0c,0x00,0xe8,0xe3,0x38,0x6a,0x5c,0xfb,0x30,0xa9,0xe7,0x9f,0xe8,0x8b,0x18,0x61,0xed,0x2d,0x12,0x01,0xeb,0x17,0x00,0x38,0xe1,0x94,0x77,0x04,0x03,},{0xa4,0xaf,0xc8,0x33,0x40,0x18,0x76,0x09,0x0d,0x9b,0x88,0x0c,0x41,0x26,0x7d,0x68,0xcb,0xbe,0xea,0xa3,0x8a,0xfb,0x20,0x88,0x4e,0x27,0x32,0x8f,0x3b,0x7f,0x53,0x5e,},{0x03,0x39,0x88,0x15,0x4c,0x5d,0x79,0xd2,0x51,0x0b,0xe8,0x3e,0x77,0x80,0x15,0xdf,0xe2,0xfb,0x85,0xb8,0x11,0x1f,0x7e,0xc1,0x39,0x91,0x8b,0x54,0x00,0xe3,0xd6,0x56,0xee,0x80,0xa9,0xf5,0xc9,0x07,0x2b,0x5b,0x46,0x7a,0x5c,0xc5,0xa5,0x7c,0xc8,0xad,0x10,0x62,0xb5,0xbf,0xf1,0x08,0x62,0xd9,0xd3,0x69,0xdd,0xe2,0xcc,0x96,0x67,0x01,},"\x91\x0f\x6c\x27\x2d\xd9\x79\x31\xac\x47\x31\x0d\x24\x4c\xad\xb4\x32\x51\x36\x5e\x02\xba\x9f\x6a\x5b\x3c\x32\x26\xbe\x9d\x7d\x3a\x74\xa2\xba\x49\x06\xe8\xe7\x1a\x4b\xf3\xd3\x55\x6e\xbd\xfc\x66\x6c\xd6\xb1\x2f\x20\xc4\xa0\x08\x34\xb8\x8f\xbb\x24\x45\x75\x19\x92\x86\xb0\xb9\x34\x4c\xf3\x34\xaf\xf0\x07"}, -{{0x4a,0xdc,0x8c,0x28,0x64,0x6a,0x93,0xa8,0x17,0x29,0x3a,0x14,0xd2,0x9b,0x48,0xe2,0xc6,0xd7,0x12,0xa6,0x89,0x93,0x54,0x7a,0x5c,0x5e,0x4d,0x14,0x52,0xac,0xbc,0x3a,},{0x7f,0x40,0x47,0x36,0x28,0xf2,0x3f,0xc0,0xdf,0xf0,0x02,0x1a,0xfd,0x48,0x77,0x40,0xd4,0x91,0x6a,0x91,0x22,0xe6,0xc9,0x7d,0x36,0x43,0x3e,0x5e,0xbf,0x04,0xf8,0x8c,},{0x6d,0x3b,0x4e,0x90,0xec,0x40,0x83,0x11,0xf9,0xb1,0x5b,0x92,0x53,0xd3,0xd9,0x5c,0x5d,0x15,0x26,0x20,0xc2,0x60,0xd5,0x63,0x02,0x55,0x5a,0x88,0x04,0xa5,0x10,0x4b,0xa5,0xe8,0xd2,0x9e,0xe1,0x08,0xe7,0x64,0xa6,0x42,0x19,0x29,0x72,0x98,0xab,0x76,0x74,0xbb,0xca,0x78,0x4d,0xee,0x28,0x77,0x3b,0x34,0xe1,0x85,0xa3,0x86,0xc2,0x08,},"\x09\xfb\x55\x01\xf1\x68\x8f\x80\xa0\xab\x9e\x22\xd7\x78\xae\x13\x0a\xca\xf7\x4d\x7f\x51\x85\xb4\xda\x19\x8c\x6b\x9e\xda\xc4\x30\x2e\x2b\x75\x3e\x57\x87\x66\xe1\x7d\x40\x56\xdc\x40\xd9\x5c\xf4\xca\x8b\xcc\x65\x65\x79\x5e\x97\xd6\x8b\xcd\xa7\x9f\xa7\x7c\x49\x33\x97\x71\x63\x56\x16\x4c\xaa\xb5\xd1\x9c\xfd"}, -{{0xf2,0x6e,0x1c,0x84,0x69,0x7a,0x49,0x08,0x15,0x1b,0x44,0x7d,0xcf,0x6c,0x7c,0x7a,0x38,0xb0,0x40,0x81,0xdb,0x9e,0x7c,0x77,0x38,0xe6,0xfe,0xc9,0x00,0xbe,0xd0,0xc1,},{0xa8,0x6e,0x14,0x22,0xc1,0x23,0x5f,0xf8,0xe1,0xaa,0x08,0x34,0x70,0xd5,0xe4,0x22,0x88,0xcb,0x00,0x7a,0xb5,0x0e,0x79,0x5d,0xd0,0xb4,0xff,0x87,0x39,0x49,0x66,0xc4,},{0x44,0xf3,0x34,0x4b,0x95,0x66,0xc9,0xdf,0xd2,0x2d,0x61,0x98,0xe1,0xcb,0xf9,0x5d,0x9e,0x28,0xf2,0x98,0x2f,0xc7,0xf1,0x66,0xab,0x25,0xdd,0xa3,0x0c,0x46,0xf7,0x68,0xc5,0x58,0xe0,0x39,0x4f,0xb9,0xab,0x3e,0x1d,0x4d,0xb4,0xcf,0x48,0x7c,0x17,0x64,0x1a,0x13,0xf3,0xf4,0x89,0x39,0xe0,0xc6,0x48,0x27,0xa7,0x51,0x03,0xc5,0x74,0x06,},"\x54\xed\x47\x60\x6a\x14\x87\xc2\xf9\x00\xce\xfb\x6e\x89\x9d\xba\xf6\xc3\x1c\xc8\x8e\xbe\x35\x58\xb8\x3b\x93\xf6\xd4\x22\xc3\x1e\x88\x8e\x48\xe5\x20\xee\xae\xdd\x7e\x55\x4a\x9c\xd4\x0c\x2c\x51\x9d\x53\x3b\x61\x44\xce\xe4\x84\xc3\x89\xe9\x76\xb1\xe4\x02\x2b\x50\xe7\xdb\xb8\x7e\xad\x7e\x54\x1a\x20\x04\xda\xf7"}, -{{0xcc,0x0c,0x33,0xf3,0xa8,0x6f,0x5a,0x17,0xd3,0x0c,0x18,0x6c,0xe0,0xf3,0xb7,0x40,0xba,0xfa,0x5f,0xe3,0xc7,0x09,0x0f,0x14,0x35,0x41,0xe2,0xb2,0xc1,0xe5,0x34,0xbc,},{0x96,0x7a,0x71,0xc7,0xcf,0x9b,0x82,0xcc,0x78,0xcb,0xe1,0x09,0x10,0x4d,0x8b,0x43,0x8a,0x8d,0x1f,0xd7,0x1d,0x26,0x0d,0x02,0x90,0x46,0xa9,0xa4,0x52,0x68,0x66,0xff,},{0xe2,0x77,0xb3,0xdd,0x65,0x5c,0x33,0xff,0x75,0xfa,0x92,0x0a,0xf1,0xfc,0xc8,0x59,0x40,0x1e,0x6c,0x7a,0x6e,0xf4,0xc6,0xbf,0xbf,0xac,0x50,0x69,0x63,0x8f,0x19,0xca,0x11,0x5b,0xaf,0x13,0xc0,0x9c,0x82,0xaf,0x79,0x3f,0xac,0xb6,0xab,0xd0,0xcd,0x58,0xe8,0x48,0x1b,0x08,0xc1,0xb6,0x8a,0xd7,0xa2,0x66,0x5c,0x4a,0x61,0x4a,0x28,0x06,},"\x19\x44\xe5\xe1\x55\xd7\x5e\x0d\x0b\xe9\x2e\x1b\xe1\x4c\xec\x37\x0a\xd1\x37\x91\xf2\xbf\xd4\x0f\x27\x12\x14\xe9\x4f\xcf\x21\x3c\x71\xbc\x20\xd7\xce\x0c\x75\x84\x42\x1a\xc4\xef\xc4\x51\x88\x3c\xc3\xf4\x95\x6f\x21\xf7\x3a\x42\x16\x72\x04\x38\xbc\x38\xff\x2c\xfd\xf3\x70\x99\x05\xa5\x0a\x9d\x94\xb1\xd9\xe7\x93\x2b"}, -{{0xf0,0xbc,0x97,0x93,0x75,0xa7,0x07,0x30,0x68,0xdb,0xa7,0xf6,0xc0,0x94,0xdb,0x65,0x98,0xb4,0xe4,0x5d,0xf7,0xd5,0x49,0x58,0x3c,0x22,0xfd,0xed,0x80,0x48,0xfa,0x2e,},{0xb4,0x2b,0x6c,0x57,0xa7,0x8f,0x1d,0x90,0x09,0x0a,0x71,0x81,0xab,0x2a,0xe0,0x9f,0x42,0x6c,0xbc,0x2b,0xe9,0x6e,0xb2,0xcf,0x27,0xab,0xc7,0x0d,0x7d,0x32,0xa4,0xb3,},{0x19,0xdb,0xc3,0x02,0x7f,0x9f,0xae,0x70,0x7d,0xeb,0x76,0xf5,0x88,0xf9,0xfd,0x07,0xaa,0x8e,0xae,0x29,0xbd,0x4e,0x1d,0x04,0xc2,0xc9,0x84,0x38,0x82,0x86,0xb3,0xb1,0x22,0x24,0x8a,0x6c,0x03,0xed,0x67,0xec,0xa3,0x5d,0xf4,0xdb,0x3d,0xc1,0xe4,0x23,0x7f,0x26,0x78,0x92,0x51,0x84,0x97,0xd9,0x55,0x2a,0x21,0xde,0x19,0xb5,0x14,0x0f,},"\x27\xab\x30\x49\xb5\xc6\x35\x1f\x6c\xfe\x38\xb1\x3a\x05\x9f\x50\x37\x25\x7e\xe3\xd6\x5d\x60\x79\x65\x68\x56\xed\xc8\x76\xea\x08\x1f\xd8\xa9\x48\x04\x66\xf8\x83\x94\x78\x08\x84\x66\xf5\x1e\xcb\xfa\xf2\xd6\x5d\xef\x25\xf0\xc4\xdd\x8d\x08\x58\x82\x02\x81\x22\x32\xf5\x79\x45\xdf\x8a\x6f\xa1\x61\xed\x8c\x03\x43\xb5\x83"}, -{{0x30,0x22,0x97,0x5f,0x29,0x8c,0x0a,0xd5,0xdd,0xbe,0x90,0x95,0x4f,0x20,0xe6,0x3a,0xe0,0xc0,0xd2,0x70,0x4c,0xf1,0x3c,0x22,0x1f,0x5b,0x37,0x20,0xaf,0x4d,0xba,0x32,},{0xb8,0x45,0xbc,0xe3,0x8e,0x26,0xab,0x02,0x7b,0x82,0x47,0x46,0x3d,0x43,0x7a,0x71,0xbb,0xdd,0xca,0x2a,0x23,0x81,0xd8,0x1f,0xad,0x4c,0x29,0x7d,0xf9,0x14,0x0b,0xd5,},{0xae,0x14,0xa8,0x60,0xfa,0xd0,0x05,0x1b,0x3e,0xb7,0x2b,0x37,0x21,0xa8,0x2f,0x7b,0x95,0x46,0xb2,0x86,0x72,0x61,0xe2,0xb7,0xb6,0x38,0x97,0x9e,0x25,0x61,0xbd,0xeb,0x89,0xb6,0x00,0x76,0x8f,0x82,0x45,0x0a,0x66,0xc8,0xb0,0x48,0x12,0x83,0xfa,0x21,0xcb,0x6c,0x53,0xbd,0xe3,0x50,0xef,0xfb,0x68,0xa7,0xd1,0x11,0x4b,0xfd,0xb2,0x03,},"\x9a\xa1\x9a\x59\x5d\x98\x93\x78\xcd\xc0\x68\x91\x88\x7e\xf5\xf9\xc2\x46\xe5\xf8\x3c\x0b\x65\x87\x10\x67\x3e\x4e\x7d\xb7\x60\xc7\x63\x54\xc4\xf5\xd1\xe9\x0d\xb0\x4a\x23\xb4\xfb\x43\x4c\x69\x38\x45\x93\xd0\x10\xe3\x12\xb1\x1d\x29\x9c\x9f\x97\x48\x2d\xe8\x87\xce\xcf\xe8\x2e\xa7\x23\xbc\xa7\x9a\x1b\xd6\x4d\x03\xef\x19\xee"}, -{{0x0f,0x71,0x0b,0x6c,0x48,0x1f,0x71,0x44,0x95,0x89,0x75,0x33,0x12,0xef,0x64,0x93,0x2b,0x46,0x52,0xeb,0xe0,0xe0,0x75,0x97,0xf7,0xda,0x1c,0x4f,0x3d,0xcf,0xfb,0x80,},{0x69,0x73,0xff,0x29,0x32,0xcc,0xdd,0xfc,0x1d,0x16,0xc4,0xc0,0xda,0x50,0xc8,0xb2,0x9f,0xe6,0x45,0x2d,0x1e,0xe8,0x4d,0x52,0x06,0x4e,0xbf,0x3d,0x62,0x8d,0x40,0x3e,},{0x02,0xa8,0xd2,0x6a,0xee,0x11,0x42,0x0f,0xb4,0xf0,0x9d,0x11,0x63,0xe1,0x4b,0x86,0x7d,0xf7,0xc6,0xf6,0xc8,0xf8,0xdc,0x7a,0x78,0x03,0x46,0x59,0xf0,0x40,0x1c,0xad,0x0a,0xa9,0x03,0x97,0xef,0xdd,0x07,0x04,0xb7,0x98,0xdb,0x19,0x36,0x50,0x30,0x26,0xe2,0xa1,0xad,0xc2,0x97,0xe2,0x79,0x74,0xd4,0xbe,0x31,0x2a,0x37,0x53,0xf8,0x04,},"\x85\xd8\x57\x44\xad\x55\xe9\xef\x9a\x65\xca\x91\xe8\x5c\x8a\x4f\x80\xe4\xc5\x8f\x8e\x4e\x93\x54\xe8\x33\x98\x60\x98\xb7\xd9\xfe\x9f\xdc\x0d\xed\xb0\xd7\x5d\x25\x39\xfb\xa0\x00\x34\xfc\x0c\x2e\x84\x34\x4d\x1e\xda\xa0\x9d\x4f\x63\xd5\x54\x6d\x67\x80\x3d\xd6\xb5\x4d\xdc\xc0\xb1\xd3\xf2\x58\x2d\xd7\x52\x89\xe3\x1d\xe4\x2e\x69"}, -{{0x7a,0x05,0xf1,0x21,0xf6,0x01,0x12,0xdd,0x16,0xfe,0xe8,0xc9,0x1b,0xc2,0xa1,0x14,0x79,0xf4,0xb6,0x7e,0xe3,0x34,0x56,0x04,0x2c,0x8d,0xe1,0x67,0xfc,0x58,0x80,0x17,},{0xb3,0xb0,0x5b,0xe9,0x89,0xce,0xa7,0x19,0x75,0x05,0xd4,0xb5,0x43,0x35,0xe5,0xe1,0xd7,0x7a,0x4b,0x52,0xba,0x72,0x82,0x60,0x4b,0xbc,0x1c,0xf6,0xc4,0xe8,0x7a,0x6c,},{0xd3,0x0c,0xe8,0xa3,0x22,0xb4,0x50,0xa2,0xfb,0x1a,0xfd,0x32,0x9c,0xec,0x85,0x59,0xcc,0xf1,0x12,0xbd,0x83,0x96,0x5f,0x9e,0xc4,0x73,0x62,0x70,0xa0,0x91,0x4e,0x06,0x11,0x96,0xbf,0x52,0x09,0x77,0x8c,0x9f,0x8c,0xcf,0x39,0xc4,0x66,0x8b,0xbf,0x0e,0x13,0x63,0xf8,0x1a,0xfe,0x45,0xdd,0x74,0xe8,0x0d,0x58,0x75,0xdd,0xbf,0x6f,0x01,},"\xd9\xc5\x9e\x8c\xc4\xed\xe5\x37\xbe\x21\x22\xab\x49\x2a\x5b\x91\x5a\x9b\x0a\x11\x4b\x2a\xde\x35\x6f\xc0\x45\x7e\xf9\x87\x22\xd5\xf5\x67\xb8\x62\x11\xe2\x83\x69\xd1\x41\x68\xec\x4a\x3c\x80\x40\x76\xe1\x54\xad\xc7\x0a\x66\x8c\xf6\x4a\x20\xd1\x3c\xf1\x90\xd1\x15\xcd\x68\x8d\x03\x6e\x46\x93\x82\x51\xdf\x49\x64\xdc\x35\x17\xb1\x0c"}, -{{0xbf,0x38,0x1f,0x8d,0xfb,0x5d,0x0c,0x6d,0x64,0xe4,0x16,0xac,0x23,0xe0,0xd0,0xfc,0xb8,0x6e,0xbb,0x89,0x9b,0x1d,0x14,0x6a,0xbd,0x91,0x1b,0x92,0xa7,0x80,0x8e,0xb6,},{0x86,0x3f,0xad,0x8d,0x1f,0x1b,0xc6,0x30,0xa1,0x5f,0x6f,0xe8,0xec,0xef,0xe6,0xb4,0x49,0x7b,0x60,0xb2,0x1a,0xe8,0x83,0x0d,0xa4,0x67,0x42,0x04,0x5f,0xef,0x15,0x6f,},{0x99,0xb7,0x53,0x78,0x73,0x8f,0xca,0xc8,0x06,0x76,0x69,0xe8,0x50,0x9b,0x5d,0x26,0x07,0xe1,0xef,0x76,0xaf,0x90,0x04,0xe1,0x3f,0xe5,0xd3,0x93,0x2d,0xf6,0x0b,0x16,0x82,0x16,0xf5,0x85,0x65,0x34,0x0f,0xa4,0xd6,0x38,0x05,0x5a,0x89,0x04,0x4e,0xe7,0xd4,0x5e,0x2b,0xd0,0x82,0xa5,0x33,0x82,0x28,0x9a,0x34,0x70,0x06,0x48,0x98,0x0e,},"\x86\x54\xf2\xf5\xc6\xdc\xd2\xcf\xcb\xb6\xed\x8d\x2b\xc5\xfb\x5f\xec\x53\xe3\xef\xfb\x0d\xe6\x5a\xac\x50\x7f\xa5\x6c\x89\x77\x32\x39\x5a\xa0\x99\x46\xd3\xb6\x58\x6a\x92\xed\xd6\xdc\x99\x31\x5e\x1b\xa7\x4c\x6a\x02\x47\xc4\xba\x77\x60\xb9\x48\xeb\x3c\x09\x32\xd9\xfe\x1f\x0e\x9f\xea\x6e\xb6\x1a\x54\x8a\x9a\xb4\x8f\xfd\xf1\x54\x73\x29"}, -{{0x36,0x98,0x32,0x41,0xa0,0xa8,0xe6,0x0c,0xe0,0x2a,0x61,0xb3,0xfa,0xfa,0xb1,0x5a,0x73,0x13,0xa5,0xa2,0x70,0xd0,0x15,0xb9,0xc9,0xec,0x07,0x0d,0xc4,0x2d,0xee,0xda,},{0x66,0x47,0x98,0x4d,0x42,0xb9,0xa5,0xb3,0xb1,0xaf,0xa3,0xb7,0xf8,0xf4,0x9d,0x4c,0x2b,0x05,0xe3,0x89,0x84,0xe9,0x9c,0xea,0x8f,0xd6,0x82,0x35,0xd2,0xae,0x46,0x27,},{0xee,0x37,0xdf,0x8a,0xf4,0x22,0xf9,0x1f,0x85,0xdf,0xe4,0x3e,0xfe,0x79,0xf6,0x23,0x78,0x06,0x8c,0xcd,0xba,0xf3,0x91,0x6e,0xec,0xbc,0x3a,0xdf,0xed,0x05,0x08,0xbd,0xeb,0xaf,0x5c,0xe0,0x6b,0x3b,0xc2,0x79,0xf7,0x80,0x87,0xf0,0xdb,0x8d,0xb3,0xc6,0x82,0x3e,0xdf,0xb3,0x2c,0x12,0x21,0x78,0x30,0xbe,0x72,0x3d,0x88,0x72,0xb3,0x0c,},"\xce\xbb\x9e\x40\x44\x51\x81\x82\x53\xc0\x39\x2a\x45\x54\xee\x73\x23\xc5\xd5\xb8\xb2\x26\x77\x57\x00\xb8\x06\xed\x5b\x91\x33\x79\x16\xea\x7e\xcb\xc3\xd4\x10\x3f\xc6\x5e\x53\x72\xae\x7e\x5f\x9b\xa2\xd8\xf5\xae\xe2\x4c\xcf\x6e\x63\x1a\xe2\x0c\x4a\xf9\xb5\xf7\x28\xcd\xf8\x9e\x81\x89\xde\xf1\xa5\xb3\xd3\x53\x47\xaa\x20\x35\x25\xea\x1d\x2e"}, -{{0xd0,0x68,0x99,0xf9,0x3a,0x40,0x8d,0xac,0xb4,0x1c,0x96,0x97,0x18,0x34,0x6f,0x1e,0x28,0x9b,0xb5,0xea,0x65,0xe2,0x83,0xff,0x79,0xc7,0x05,0xa0,0x74,0x51,0x7c,0x35,},{0x46,0xbf,0x2a,0x08,0xa0,0x76,0xc4,0x7d,0x7f,0x11,0xb7,0x33,0xf8,0x14,0x1c,0x35,0x53,0x63,0xed,0x85,0xd7,0xde,0xf2,0x6b,0xa6,0xa0,0xce,0x15,0xac,0x5f,0x2b,0xe8,},{0x6f,0x89,0xde,0x92,0xa6,0x6b,0xc5,0xf4,0x14,0x43,0x39,0x12,0x49,0x50,0xbd,0xf5,0x88,0x14,0x4c,0xb3,0x72,0xf6,0x73,0x62,0x45,0x35,0x1c,0x94,0x76,0xbe,0xcc,0x59,0xa2,0x58,0xf9,0xa9,0x33,0xff,0xff,0x2b,0xef,0x4b,0x46,0xcd,0x10,0x57,0x39,0x52,0x25,0x79,0x9f,0xd0,0x9d,0xed,0xe6,0x82,0x3d,0xb0,0xe3,0x25,0xdb,0xc8,0x14,0x0d,},"\x08\x64\xc3\x9a\xc4\xfd\xa8\xeb\x90\x48\x59\x7b\xd4\x0b\xe0\x40\x10\x21\xfd\x2d\xd3\xa3\x39\x0a\x8f\xac\xce\x98\x4b\x26\x0a\x13\xfa\x2c\x7c\xfc\x00\xd1\x92\xfa\xdf\x13\x4a\x0a\xd5\xa1\x81\xee\x89\xef\xf0\xc7\x95\xea\xa0\xfb\xfe\x2f\x3b\x26\x11\x5d\x07\x16\x8d\xb4\x2e\xd2\x1a\x51\x30\x3b\x19\x58\xe4\xa4\x2d\xc0\x65\xb2\x2c\xe4\x8f\x17\xa6"}, -{{0xee,0xbc,0xa7,0x96,0x69,0x70,0xee,0x9f,0x2c,0xc4,0xd7,0x4c,0x6f,0x1d,0x8e,0x0e,0xbf,0xf7,0xc4,0x5a,0xeb,0xad,0x34,0x9f,0xb9,0xf8,0x6d,0xf6,0x28,0xdf,0xff,0x0e,},{0x89,0x10,0x1e,0x03,0x09,0xf7,0x67,0xe6,0x4a,0xe9,0xc9,0x8c,0x4a,0x5d,0x8d,0x23,0x28,0xfb,0x3e,0xf2,0x62,0xd0,0x82,0xf4,0x9b,0x64,0xca,0x20,0x9e,0x19,0x90,0xf6,},{0x7d,0x44,0x7e,0xe5,0x32,0x8c,0x9f,0xe7,0xf1,0x19,0x36,0xcc,0x42,0x99,0x87,0x54,0xa5,0x6c,0xd1,0xd2,0xa6,0x95,0x1a,0xf4,0xfe,0xe7,0xc4,0xa8,0xeb,0x31,0x9d,0x49,0x23,0x70,0x7c,0x79,0x3c,0x55,0xd7,0x90,0x67,0xf8,0x22,0xd5,0xb1,0x6b,0xb5,0x77,0x6e,0x38,0xdf,0xfa,0xbc,0x67,0x23,0x7a,0x91,0x6a,0x81,0xa6,0x33,0x39,0xb0,0x03,},"\x0f\xac\x79\x0a\xdb\x9f\x59\xe5\xcb\x0d\xdc\xb2\xb6\x67\x17\x2f\x2a\x21\x03\x4d\x93\xbc\xad\xdf\x18\x86\x06\xfa\x9e\x77\x6d\xb3\x3a\x8f\xcc\x6b\xd7\xf5\x56\x78\x83\xfc\x0d\xe3\x51\xaa\x9a\xfa\xa3\x6d\x20\x75\xb1\xba\x85\x3b\xad\xa8\x49\xb8\x66\x1d\x5c\x81\x54\xe7\xb0\xaf\xea\x65\x6d\xd1\x5e\x01\xa9\xc5\xba\x21\x58\x9b\x02\xf8\xfc\x54\x81\xc2"}, -{{0x38,0x20,0xb6,0xb1,0x59,0x39,0xd0,0xaf,0xe1,0x8c,0x9c,0xb3,0xd9,0xa2,0xa0,0x8f,0x16,0x7d,0xd4,0x58,0xeb,0x6c,0x7e,0x3f,0x15,0x58,0xb0,0xc6,0xdb,0x4c,0x68,0x90,},{0x80,0xb8,0x5c,0x65,0x59,0xfe,0xa8,0xb4,0x00,0xe1,0x99,0x9c,0xc5,0xbf,0xed,0x50,0x7a,0xd7,0xfc,0x29,0x4c,0xd9,0xba,0x0c,0xe2,0xdd,0x25,0x84,0xa9,0x10,0x89,0xb0,},{0x82,0x3e,0xe2,0xc0,0xc8,0xd8,0x7f,0xaa,0x0e,0xc0,0x14,0x1e,0x9c,0xe0,0x8b,0x51,0xe5,0x7c,0x83,0x97,0x92,0xd1,0xfb,0xd9,0x7a,0x96,0x72,0x07,0xfd,0x41,0x58,0x49,0xeb,0xfb,0x5d,0xad,0xb5,0xa1,0xdc,0x2c,0x0a,0x8b,0x7f,0xc6,0x3f,0xc3,0x54,0x85,0x7b,0x8c,0x90,0xc4,0x47,0x20,0xe1,0x3f,0x45,0xcd,0x01,0xe7,0xaa,0x23,0x14,0x0c,},"\x3e\x5a\xd9\x2d\x44\xb4\x0e\x86\x14\xd8\x08\x7c\x9c\x74\x3d\xe0\xc0\x86\x1a\x07\xf1\xf5\x14\x6d\x71\xca\xc2\xf3\x74\x00\x24\xe8\x41\xcc\x2d\x46\x02\x7c\xf5\xd2\x61\xd3\xee\x7c\x18\x75\xb3\x95\x51\x01\x7b\x5f\xb1\x46\x81\x14\xfc\x3e\x09\x8a\x89\x9c\xdb\xd5\x58\xb3\x9f\x09\x8e\x15\x6b\x6e\x98\x01\xeb\xcd\xd6\x5f\xed\x56\xdb\xfc\xaf\x2c\x8c\x78\x7b"}, -{{0x0d,0x20,0xfa,0x4a,0x37,0xff,0x30,0xc4,0xdc,0xc3,0xe4,0x4e,0xa7,0xac,0x50,0x11,0x37,0xe5,0x80,0x7e,0x97,0x81,0x33,0x0a,0xc3,0x10,0x98,0x2c,0xc3,0xd3,0x9d,0xbd,},{0x67,0xbb,0x0a,0x01,0xbc,0x86,0x17,0xb4,0x91,0xef,0xf1,0xa3,0x26,0xc1,0xc7,0x0f,0x7d,0x0c,0x5b,0x95,0xa5,0xad,0x48,0x24,0x1a,0xed,0xce,0x1c,0x6f,0x08,0x83,0xcf,},{0xde,0xab,0x12,0xed,0x82,0xba,0x94,0xb4,0x69,0xca,0x98,0xb6,0x6f,0xa2,0x04,0x44,0xb4,0xb7,0x88,0x1c,0x4f,0x0f,0x85,0x34,0x09,0xc9,0xa1,0x50,0x4a,0x5b,0x2b,0x6d,0x78,0x60,0xf2,0x6a,0xda,0x6b,0xf7,0x34,0x59,0xb9,0xcd,0xb5,0x73,0xc8,0x01,0x71,0x21,0x33,0x8e,0xfa,0x60,0xf4,0x14,0x80,0x86,0xd7,0xa3,0xa8,0xed,0x59,0xbb,0x07,},"\x35\xe0\xf4\xb4\xa5\x17\xf9\xc7\xaa\x45\x14\xf0\x3e\x6d\x65\xf1\x9b\x27\xc6\x2c\xc0\x69\xf6\xbf\x07\xdd\x63\x78\xbd\x6a\xfe\x2b\x76\x65\x60\x00\x6c\xbd\x57\x30\xa0\x09\x19\xed\x11\x19\x1f\xb0\xc8\xda\xc5\x6e\x15\x3f\xc1\xce\xa4\xbd\xce\x50\x46\xcc\xcb\x71\x77\x59\xa4\x08\x3e\x1c\x16\xf7\x40\x76\x32\x64\xcc\x80\x4d\xe0\xd0\xe1\xa4\xb5\xa2\x30\x67\xaf"}, -{{0xbe,0xe1,0x61,0x88,0x1d,0x81,0x9b,0x37,0x0d,0x24,0x0d,0x50,0x9b,0xa4,0x6b,0x06,0xfb,0x82,0x8e,0x20,0x31,0x0d,0x9f,0x6b,0x30,0x97,0x80,0x70,0x3e,0x98,0x92,0x7b,},{0x10,0x85,0x43,0x80,0xde,0x89,0x16,0x2b,0xfb,0x9f,0x78,0x35,0xa2,0x71,0x6a,0x3a,0x6e,0x02,0x65,0x67,0x1b,0x25,0x0b,0x38,0x9d,0x01,0xc3,0xbc,0xc0,0x37,0x36,0xb8,},{0xb0,0x7d,0x07,0x2e,0xb3,0x83,0x1f,0xae,0x8a,0x06,0xef,0xfa,0x92,0x01,0x79,0x74,0x96,0xdc,0xe1,0x26,0xb8,0xe1,0x1f,0xef,0x2f,0xa0,0x7f,0x66,0x4d,0xc5,0xcf,0x3d,0x4b,0xf9,0xc3,0x8a,0x8b,0x3c,0x09,0xfb,0x5f,0x14,0xfa,0x2d,0xeb,0x21,0x9e,0x7d,0x85,0x2f,0xdd,0x27,0xc7,0xba,0x32,0xd3,0x09,0x94,0x2f,0x27,0x46,0xdf,0xe4,0x04,},"\x5a\x6f\xe5\x99\xb6\xb0\x9b\x05\xc0\xba\x6a\x62\x2d\xf3\xa9\x2b\x3d\x37\x6d\x24\xd0\x4e\xa8\x5e\xbe\x76\x7b\xc2\xec\x4d\x14\xe8\x3e\x69\x37\xdc\x0b\x91\x4b\x48\x09\xfd\xb6\x07\x90\x68\x41\xa6\xfd\x1d\xcd\xf6\x1a\xae\xa8\xf9\xbb\x81\xb2\xcc\xaa\x32\xdf\x41\x29\x89\xae\x53\x64\x66\x80\xa7\x1a\x21\x1c\x84\x40\xea\xb0\xf1\xae\xc5\xe4\xfc\x00\xe6\xa2\xc9\x6d"}, -{{0x70,0x15,0x0e,0x95,0x16,0x16,0x4a,0x3d,0x7b,0x7e,0x8b,0x6f,0x25,0x5b,0x65,0xca,0xc9,0xf0,0x74,0x59,0xb3,0x2d,0x11,0xbb,0x94,0xb3,0xd2,0x77,0x20,0x8a,0xbc,0x99,},{0x23,0x28,0xbe,0xc8,0xe4,0x03,0x51,0x04,0x78,0x82,0xe8,0xb4,0x3b,0xc1,0xab,0x08,0x53,0x86,0xfa,0x47,0x98,0x7e,0x46,0xea,0x87,0x60,0x88,0x14,0xc5,0xda,0x71,0x3c,},{0xed,0xa3,0xf5,0x03,0x3e,0xa7,0x95,0x3a,0x0d,0x58,0x3c,0x64,0x57,0x52,0x2e,0x84,0xad,0x78,0x44,0x53,0x04,0xd4,0x8e,0x57,0x7d,0x4d,0x69,0xe8,0x64,0x1f,0xeb,0xe1,0x52,0x48,0xd8,0xd9,0x0c,0xe0,0x94,0x4a,0x8f,0x80,0x1d,0x39,0x09,0x9b,0xc7,0x74,0x94,0xba,0xc4,0xce,0x2a,0x20,0xb3,0x83,0x69,0xc6,0xad,0xfb,0x71,0xe0,0x3d,0x0f,},"\x77\xbe\x8e\xce\xaa\xb4\x31\xa1\x3c\x2a\x28\xd0\xd1\x55\x64\x89\xd8\xc3\x92\xfd\x7a\xe4\x11\x57\xf7\xca\xf0\x82\xcb\x54\xe4\x5f\x08\x62\x6b\xe0\x07\x6b\xe8\x44\xd3\x8f\xde\x90\x1a\x5e\xab\x0e\x88\x32\xd6\x9d\xac\x22\xfb\x85\x07\xfb\x8e\xc4\xfa\xf7\xc8\x8f\xd2\x6d\xa3\x08\x46\x1a\xfe\x38\x59\x87\x97\x2b\x5e\x76\x0a\x34\xa5\xe1\x8b\x9a\x82\xb4\xaa\xa5\x29\xb7"}, -{{0x3f,0x87,0xfc,0xfd,0xb4,0x21,0x42,0x2a,0x9c,0x5f,0xb9,0x82,0x68,0x31,0x3c,0x15,0x12,0x8c,0x78,0x84,0x4e,0xf9,0xeb,0x3b,0x37,0x13,0xfa,0x77,0xb6,0x71,0x89,0x03,},{0x53,0x3e,0xc5,0x92,0x28,0x37,0x4b,0xd0,0x3a,0x46,0x99,0xe3,0xa8,0x89,0x6b,0x86,0x18,0x2f,0xcf,0x8f,0xc3,0x08,0x5f,0xdb,0x8f,0x5c,0x46,0x71,0x52,0x4d,0x6f,0xe0,},{0xf6,0x51,0x9d,0x7e,0xdb,0x61,0x34,0x11,0x19,0x74,0x03,0x3f,0x03,0xb8,0xd8,0x9e,0x9c,0x76,0xca,0xec,0x89,0x65,0xa8,0xe1,0x7c,0xd4,0x5f,0xff,0x19,0xde,0x26,0x15,0xd7,0x3e,0xcc,0xdb,0x4a,0x66,0x64,0xa8,0xf0,0xe2,0x3a,0xdf,0x98,0x98,0x8e,0x96,0x25,0x1b,0xf2,0x6e,0xb7,0xa4,0xcc,0xaa,0xc1,0x07,0x9f,0x0a,0x77,0x2f,0x9b,0x05,},"\xc0\x0f\xed\x2d\x68\x94\x68\xbc\xba\xcc\xcd\x44\x6e\x8d\x8f\x29\x9e\x2a\x86\x92\x5e\x62\xe5\x97\x09\xaf\xaf\x48\x57\x46\x9f\xf1\xe0\x06\xd0\x0f\xa3\xe1\x8a\x36\x15\xf8\xf0\x6b\x6e\xbd\xff\x78\x5d\xde\x58\x85\x1d\x2c\x23\x90\x38\xa0\xc3\x44\xdc\xe9\x85\xbd\x1f\xc8\xde\xb4\x77\x9a\xe5\xf8\x93\x2e\x2f\x9e\xd5\x99\x0b\x64\x72\xdb\xe4\xe6\xfe\xf6\x91\x76\x57\xe0\xb5"}, -{{0x44,0xce,0xef,0x04,0x4f,0xf9,0x98,0xd4,0xab,0xea,0xaf,0x37,0x4e,0xb4,0x1d,0x08,0x67,0x18,0xb6,0x30,0x97,0xb1,0xe3,0x5f,0x89,0x63,0x4c,0x14,0x89,0x71,0x32,0xea,},{0xe8,0x3c,0x86,0x67,0x7d,0x03,0xed,0x3a,0x5e,0x8c,0x95,0xf4,0x1f,0x0b,0x32,0x5f,0xf4,0x33,0x37,0x02,0xf2,0xff,0x69,0x36,0xf5,0x7f,0xf3,0x0a,0xa3,0x14,0x85,0xc7,},{0x55,0x45,0x52,0xd6,0xb7,0x90,0xd4,0x21,0xd0,0x6b,0x0a,0x67,0xf8,0xe0,0x02,0xad,0x7a,0x1e,0xd0,0x1c,0x06,0xcf,0x00,0xcb,0xea,0xec,0x2a,0x26,0x8b,0xda,0x29,0xf1,0x18,0x3f,0x0c,0xea,0xfc,0x62,0x5f,0xa5,0xfd,0xb8,0x47,0xdc,0x86,0xfa,0xe1,0xa2,0x04,0x06,0xe4,0x59,0xd4,0xa0,0x17,0x7c,0xb5,0x15,0x22,0x0a,0x56,0x8e,0x08,0x00,},"\x8d\x3e\x2d\xec\x46\x44\xc7\xb5\x16\x33\xb1\x3e\x63\x75\xca\x42\xff\x91\x38\x46\x5f\x43\xd7\x80\x0c\x73\x13\x19\x9f\x67\xc9\xcf\x1b\x52\x0b\x18\x20\xbd\x63\x0e\xcf\x1c\x99\x2e\x27\x67\xb3\x8e\xb5\xbb\xc4\x41\xa4\xab\x8d\x31\x7d\xb4\x41\xdb\x35\xa0\xfe\x3a\xbe\x7a\x9e\x45\x41\x88\x1c\x2d\x7b\x1a\x26\x12\x30\x69\x59\x81\x5d\x1d\xa4\x12\x67\xd9\x64\x9d\xd4\x49\x4a\xce"}, -{{0x98,0xef,0x2a,0x44,0xd4,0xc8,0x47,0x6d,0xff,0x05,0xaa,0x78,0xdc,0xf9,0xc6,0xdc,0x08,0x6c,0xb2,0xf6,0x22,0xa0,0x67,0x45,0xd6,0x0c,0xbf,0x22,0x3f,0xaa,0xba,0x66,},{0x42,0xfd,0xb1,0xda,0xa3,0x9f,0x01,0x59,0x11,0x9b,0xee,0xc1,0xbe,0xdf,0x6f,0x03,0x94,0xb2,0x6a,0x2a,0x29,0xbd,0x1f,0xde,0x08,0x1e,0xcc,0xda,0xde,0xcc,0x22,0x6a,},{0xab,0x5e,0x87,0x24,0xa3,0xe6,0xff,0x76,0x05,0x8c,0xfb,0x21,0x4d,0x57,0x4e,0x04,0xd0,0x55,0x74,0xec,0xdd,0x4f,0xfe,0x8c,0x07,0xc7,0xaf,0x39,0x6e,0x88,0x26,0x87,0xc5,0xd7,0x9e,0xf1,0xe6,0x2f,0xbb,0x4c,0x5f,0x1b,0xd0,0x6b,0x9b,0xd8,0x97,0x82,0x6e,0xdd,0xe0,0xd1,0x11,0xd9,0x18,0xe8,0xef,0x96,0x1f,0xf2,0xa0,0x0d,0x77,0x00,},"\xc8\xb5\xfc\xfc\x3c\x18\xc7\xd9\x59\x57\xb6\x68\xe9\x1c\x73\x1d\x50\xc7\xfc\xea\x4f\x95\x75\xbb\xf7\x84\x62\x58\x70\xe2\x38\xdf\x54\x6e\x2c\xb1\xa1\x9d\x28\x08\xdd\x5b\x23\x0d\x38\x71\xfd\xec\x16\x10\x0e\xe1\xfb\xf9\xb7\x22\xfa\x37\x44\xa7\x50\xa3\xb3\x96\xb0\x5f\x9c\x21\xb8\xc0\xf6\x1e\xad\x57\xa7\x8c\x5e\xcf\x72\xb5\x79\xcf\xe8\x8a\x3f\x40\x4c\x8a\xcf\x52\x4f\x9a\xb9"}, -{{0x93,0xa8,0xc7,0x92,0xa2,0x39,0xc9,0x31,0x91,0x7c,0x11,0x48,0x24,0xa0,0x17,0x4f,0x8b,0xc4,0xeb,0xbf,0x98,0xaf,0x8c,0x7e,0x32,0x1e,0x0f,0x5b,0xea,0x40,0x15,0xec,},{0x9b,0x2e,0xaa,0x8a,0x9c,0x2c,0x25,0xff,0x4f,0x6e,0x13,0xbb,0x12,0xba,0xe5,0xd0,0x6f,0xda,0x0e,0xb1,0x10,0x5f,0xaf,0xae,0x58,0x80,0xff,0x16,0x87,0x40,0xbb,0x74,},{0xcf,0xe3,0x2c,0x44,0x35,0xd9,0x11,0xd7,0x72,0xdc,0x07,0x27,0xe7,0x8d,0x68,0x9d,0x01,0x64,0xc5,0x06,0x95,0x97,0xcb,0x44,0x1b,0x22,0xc1,0xd2,0x62,0x36,0x47,0x9f,0x1a,0xfd,0x70,0x89,0x12,0x1b,0x9a,0xb4,0xf6,0x1b,0xbb,0x1f,0xae,0x1a,0xb4,0x2f,0x76,0x35,0xa9,0x2a,0x53,0x78,0x4d,0x71,0x70,0x91,0x6b,0x70,0x3a,0xa5,0xcc,0x09,},"\x90\x1b\xf4\xe0\x41\xca\xf1\x6e\x04\xf2\xff\xde\x8d\x6f\xe9\x7e\x93\xd0\x90\x0f\x6b\xc0\xfc\x09\xa9\xa0\x17\x9d\x13\x7b\x4b\x77\x88\xe5\x7e\xb9\x27\x66\xa9\xc6\x34\xf3\x5a\xdb\x5c\x29\x88\xaf\x1e\x86\x20\x8f\x46\x19\x98\xf5\x9c\xfe\xc9\x92\x04\xb4\x84\xfb\xca\xd3\x95\x1e\x7e\xe4\x40\x55\x23\x70\x5d\x97\x39\xb4\x43\x07\xdb\x03\xf7\x13\xfd\xa7\x8d\xb4\x21\xef\x31\x21\xb3\xba"}, -{{0x70,0x01,0xfa,0x0c,0x44,0x04,0xc2,0x8a,0xa5,0xb5,0xfc,0xff,0x30,0xa9,0x61,0xf2,0x1a,0x22,0xf5,0xb8,0x5a,0x9e,0x38,0x2e,0x07,0xae,0xa8,0xa8,0x92,0x4d,0x0e,0xc1,},{0xda,0xeb,0xb6,0x3c,0x4d,0x8f,0x40,0xce,0xba,0x8e,0xc3,0x5e,0x3d,0xd9,0x46,0xa6,0xb7,0x5b,0xc7,0x4f,0xcb,0x29,0xad,0xe7,0xb5,0x5e,0xee,0x3c,0xc3,0xae,0xa5,0xca,},{0x64,0xea,0xc9,0xce,0x87,0x46,0x06,0x18,0x63,0x6b,0x41,0xfd,0x2d,0xec,0xc1,0x67,0x3b,0xfc,0x48,0xc5,0xf4,0x79,0xdf,0xac,0xb5,0x1e,0x86,0x68,0x64,0x07,0x37,0x4b,0x1d,0x10,0xbf,0x65,0xd6,0xd7,0x47,0x42,0x14,0xd7,0x77,0x0c,0x9e,0x5c,0x7f,0x80,0x6c,0x80,0xd5,0x3d,0x48,0xb7,0x20,0x87,0x0e,0x5e,0x78,0xf3,0x2e,0x3a,0x7e,0x05,},"\x44\xf4\x8c\xfb\x02\xf0\x87\x77\xa5\x78\x73\x85\x5f\x96\xbe\x4c\x02\x91\x32\x3f\x27\x39\xb2\x75\xd9\x07\x57\xa1\x54\x72\xe5\x75\x04\x36\xe0\x10\x74\x08\xfe\x30\x26\xc0\x06\x25\x68\x99\x83\xf9\x90\xeb\xa9\xbe\xcb\xfc\xe4\x03\xcc\xd5\x63\x56\xad\x27\x41\xfd\x21\x44\x5d\xfb\x23\xd7\x61\x12\xe5\x78\xb3\x39\x5c\xf9\xd9\x60\x95\x5f\x1d\xa8\xf3\x99\xca\x28\x6f\x21\x39\x0e\x25\xa5\x9a"}, -{{0x3a,0xdc,0xe3,0xa3,0xd3,0xfb,0xc9,0x77,0xdd,0x4b,0x30,0x0a,0x74,0x74,0x9f,0x13,0xa3,0xb0,0x4a,0x5d,0x73,0xa2,0xcd,0x75,0xa9,0x94,0xe3,0x19,0x5e,0xfe,0xbd,0xac,},{0x6f,0xf1,0x9b,0x1f,0x18,0xd6,0x48,0x51,0xd5,0xc7,0x48,0x45,0xc6,0x40,0x7f,0x0b,0xf5,0x96,0xa5,0x2e,0x38,0x5e,0x02,0x01,0x27,0xe8,0x3e,0x54,0xcf,0xf5,0xac,0x19,},{0x7d,0xda,0x89,0xf8,0x5b,0x40,0x53,0x9f,0x5a,0xd8,0xc6,0xde,0x49,0x53,0xf7,0x09,0x4a,0x71,0x5b,0x63,0xdd,0xa3,0x0e,0xc7,0xcf,0x65,0xa7,0x85,0xce,0xae,0x5f,0xc6,0x88,0x70,0x7e,0xe0,0x0b,0xe6,0x82,0xce,0xcb,0xe7,0xee,0x37,0xd8,0xfc,0x39,0xee,0x6d,0x83,0xc6,0x44,0x09,0x68,0x17,0x08,0xa0,0x89,0x8a,0x18,0x3b,0x28,0x8a,0x06,},"\xfe\x6c\x1a\x31\x06\x8e\x33\x2d\x12\xaa\xb3\x7d\x99\x40\x65\x68\xde\xaa\x36\xbd\xb2\x77\xce\xe5\x53\x04\x63\x3b\xd0\xa2\x67\xa8\x50\xe2\x03\xbb\x3f\xab\xe5\x11\x0b\xcc\x1c\xa4\x31\x66\x98\xab\x1c\xf0\x0f\x0b\x0f\x1d\x97\xef\x21\x80\x88\x7f\x0e\xc0\x99\x1e\x8c\x11\x11\xf0\xc0\xe1\xd2\xb7\x12\x43\x3a\xd2\xb3\x07\x1b\xd6\x6e\x1d\x81\xf7\xfa\x47\xbb\x4b\xb3\x1a\xc0\xf0\x59\xbb\x3c\xb8"}, -{{0x14,0x80,0x3c,0x1f,0x23,0xa4,0x7f,0xcd,0xd3,0x5e,0x5d,0x14,0x6e,0x20,0xca,0x63,0x0c,0xd7,0x12,0xc0,0x47,0xd5,0x33,0x0b,0x65,0x2e,0x31,0x85,0x7a,0xcb,0xc9,0xe8,},{0x36,0xf2,0xd5,0xbd,0x6d,0x83,0x24,0xfa,0x6e,0x9d,0xb7,0xf7,0xd8,0x54,0xeb,0xe4,0x8c,0x0e,0x62,0x99,0x99,0x81,0x22,0xe9,0xd4,0x4b,0x8a,0xdb,0xef,0x54,0xf0,0x93,},{0x07,0xa7,0xde,0x6c,0xe9,0x76,0x64,0xb3,0xea,0x09,0x28,0xe1,0x38,0x5c,0x33,0x09,0xbe,0x08,0xa4,0x7c,0xbf,0x4d,0xaa,0x91,0x86,0xa1,0xb9,0x48,0xc8,0x6f,0xbb,0xa3,0x9c,0x4e,0xfc,0xfc,0xb7,0xa0,0xa3,0x86,0x6b,0xc9,0x4c,0x67,0x88,0xff,0xe6,0xbe,0x0d,0x49,0x72,0xe5,0x6d,0x0c,0x32,0x92,0xd1,0xcc,0x6e,0x25,0x44,0x7b,0x99,0x04,},"\x55\x59\x83\x67\x9d\x02\x6e\x53\x54\xb4\xcc\x05\x5a\xe1\xbc\x14\x65\x3c\x72\x81\xec\x72\x23\x72\xf3\xfe\xb7\x78\xe8\x41\xda\x82\x1b\x3d\x0b\x8e\xe7\xa9\xa9\x12\x9e\xa0\x68\x24\xbe\x83\x79\xfb\xbd\xcb\x07\x48\xf4\x23\x72\x1c\xcb\x17\x2a\x1b\xaf\xa1\xd5\xae\x9f\xc1\xc5\x1e\x93\xd4\x1d\xd5\x51\xc3\x08\x60\x79\xb6\x20\x28\x6c\x1c\x40\xc1\x22\x3b\xbc\xbb\x76\x72\x2e\x92\xca\x21\xd8\x41\x0a"}, -{{0x1a,0x61,0x15,0x4d,0x34,0x72,0xcd,0x96,0xb3,0x28,0xee,0x67,0x4b,0xeb,0x4f,0xc8,0x67,0x63,0xa9,0x69,0xfb,0x41,0x04,0x94,0xe0,0x67,0x84,0x14,0xe3,0x1a,0x46,0xa6,},{0x75,0x76,0xd9,0x3a,0xc8,0x5d,0x0f,0xc6,0x1f,0x25,0x8c,0x55,0xcf,0x90,0xbd,0x87,0xa6,0x35,0x09,0x9c,0x0e,0x81,0x0e,0xd0,0xb9,0x37,0x25,0x8d,0x13,0xb4,0x25,0x59,},{0xad,0xa1,0x66,0x6c,0x9c,0x3b,0x82,0x84,0xb8,0xa2,0x1c,0x4f,0x26,0x18,0xef,0x08,0x08,0xa6,0x46,0xf3,0xf1,0x09,0x41,0xe4,0x70,0xf7,0x38,0xe1,0x78,0x5e,0x2d,0xe9,0xfd,0xd9,0xc8,0xcb,0x52,0x6f,0x94,0x5c,0x7a,0x8c,0x69,0x94,0xf1,0x51,0xb7,0xd0,0x66,0x58,0x1b,0x1d,0x75,0x53,0x07,0x94,0x7c,0x62,0xbe,0xfc,0x8a,0xb7,0x07,0x0f,},"\x64\xc5\x65\xef\xbc\xb8\xb9\x52\x8e\xd4\x72\x53\xf3\xc6\xa4\x03\x5d\xb7\x81\xd6\xf0\x97\x6b\x5e\x5b\xa8\x44\x7d\x4e\xd5\x4b\x04\x10\x52\x93\xef\x4c\x00\x0d\x8b\x2e\x1b\x5b\x75\xe7\x27\xe5\xd2\xa0\x77\x74\x3b\x50\xd1\x83\xb4\x91\x76\x48\x01\xa2\x50\x4d\x16\xee\x6d\x7d\x8a\xc4\xfe\x40\xe6\xbf\xc2\xa8\x12\x9c\x72\x85\xa5\xac\x69\x1c\x35\xe6\x42\xed\x16\x2c\xf7\xfb\xc6\x45\x16\x73\x3a\x23\xb3"}, -{{0xf2,0x15,0xd3,0x4f,0xe2,0xd7,0x57,0xcf,0xf9,0xcf,0x5c,0x05,0x43,0x09,0x94,0xde,0x58,0x79,0x87,0xce,0x45,0xcb,0x04,0x59,0xf6,0x1e,0xc6,0xc8,0x25,0xc6,0x22,0x59,},{0x1e,0xd5,0x06,0x48,0x5b,0x09,0xa6,0x45,0x0b,0xe7,0xc9,0x33,0x7d,0x9f,0xe8,0x7e,0xf9,0x9c,0x96,0xf8,0xbd,0x11,0xcd,0x63,0x1c,0xa1,0x60,0xd0,0xfd,0x73,0x06,0x7e,},{0xcb,0xef,0x65,0xb6,0xf3,0xfd,0x58,0x09,0x69,0xfc,0x33,0x40,0xcf,0xae,0x4f,0x7c,0x99,0xdf,0x13,0x40,0xcc,0xe5,0x46,0x26,0x18,0x31,0x44,0xef,0x46,0x88,0x71,0x63,0x4b,0x0a,0x5c,0x00,0x33,0x53,0x41,0x08,0xe1,0xc6,0x7c,0x0d,0xc9,0x9d,0x30,0x14,0xf0,0x10,0x84,0xe9,0x8c,0x95,0xe1,0x01,0x4b,0x30,0x9b,0x1d,0xbb,0x2e,0x67,0x04,},"\xfb\xed\x2a\x7d\xf4\x18\xec\x0e\x80\x36\x31\x2e\xc2\x39\xfc\xee\x6e\xf9\x7d\xc8\xc2\xdf\x1f\x2e\x14\xad\xee\x28\x78\x08\xb7\x88\xa6\x07\x21\x43\xb8\x51\xd9\x75\xc8\xe8\xa0\x29\x9d\xf8\x46\xb1\x91\x13\xe3\x8c\xee\x83\xda\x71\xea\x8e\x9b\xd6\xf5\x7b\xdc\xd3\x55\x75\x23\xf4\xfe\xb6\x16\xca\xa5\x95\xae\xa0\x1e\xb0\xb3\xd4\x90\xb9\x9b\x52\x5e\xa4\xfb\xb9\x25\x8b\xc7\xfb\xb0\xde\xea\x8f\x56\x8c\xb2"}, -{{0x8c,0x9f,0x95,0x08,0x30,0x75,0xa4,0x3f,0xe4,0x26,0xd1,0x9f,0x1e,0x87,0x71,0x9b,0x40,0x04,0x3d,0xe8,0x8e,0xb0,0xee,0x97,0x1f,0x70,0xe1,0x0c,0x76,0x94,0xce,0x4e,},{0xe9,0x1d,0x16,0x7a,0xa3,0xeb,0xc2,0x3e,0x70,0xaa,0xb4,0x5d,0xab,0xe9,0x05,0xe4,0x16,0x26,0x2f,0x91,0x0e,0x2a,0x95,0x5d,0xd8,0x61,0x9e,0xfc,0x74,0xc2,0x4e,0x85,},{0xca,0xc5,0x55,0x22,0x2d,0xaf,0xec,0x76,0xa0,0xb4,0x7b,0x9d,0x2c,0x58,0x6b,0x3b,0x3b,0x9b,0x3b,0x9c,0x83,0x64,0xbe,0xb3,0xca,0xe1,0xe8,0xdd,0x7f,0x1a,0xe9,0xdd,0x74,0xf2,0x2b,0x8d,0xd4,0xad,0x2b,0x29,0x0f,0x81,0x35,0x1a,0x41,0x5a,0x99,0xf0,0x30,0xf1,0x07,0x78,0xbe,0x4c,0xda,0x85,0xd1,0xd3,0x53,0x33,0x1e,0x70,0xf1,0x09,},"\xb6\x9d\x70\xe8\x60\xf5\x5c\x42\x7e\xf2\xa7\x1d\xf3\x6e\x05\xbb\xc4\x3b\xb2\xe0\x64\x63\xaa\x5d\xe3\x44\x19\xc6\xa6\x14\xee\xa6\x69\x53\x35\xa8\x75\x26\xc1\x22\x64\x88\xd8\x42\x89\x1d\x05\x74\xdf\x34\x3c\x9c\x1e\x17\xae\xd6\x95\x8e\xce\xe8\x74\x74\x22\x1e\xb7\x7a\x59\x9e\xcb\x05\x93\x44\xc0\xd0\x52\xc0\x00\x2a\x66\xe5\xa6\x01\x31\x85\xaf\x69\xa0\x1b\xa5\xdb\xc6\x60\xd3\x6c\xae\x23\x5f\x67\xfe\x0e"}, -{{0xd7,0xeb,0x1f,0xba,0x42,0x4f,0xee,0xd1,0x00,0x77,0x7e,0xed,0xb4,0x87,0x4b,0xf2,0x08,0x10,0xad,0x68,0x6b,0x67,0xe3,0x1d,0x27,0xec,0xf6,0x10,0x60,0x9a,0x33,0xf5,},{0xa2,0x5a,0xcb,0x11,0xa6,0xc8,0x25,0x71,0x3a,0x08,0x5f,0xa7,0x54,0x69,0x28,0x86,0xa8,0x7d,0x07,0xfb,0x9b,0xe1,0xa5,0x3e,0xb9,0x61,0x72,0x8b,0xb6,0x6c,0x90,0x60,},{0x2b,0xf7,0x19,0x68,0x2b,0x07,0xcc,0x5e,0xcc,0x04,0x80,0xf3,0x7e,0x9d,0x12,0x3f,0xf6,0xf4,0x4c,0x26,0xe6,0x95,0x8e,0x59,0xf0,0x80,0x46,0x6f,0x9c,0xd3,0x73,0xa1,0x65,0x00,0xda,0xf1,0x23,0xdc,0x3f,0x13,0x34,0x77,0x4b,0xfc,0x9f,0xa8,0x45,0x03,0xb1,0x6d,0xbf,0x21,0xa8,0x15,0xc1,0xad,0xa6,0xeb,0xef,0x49,0x20,0x46,0x17,0x02,},"\xa1\xd0\xf8\x1e\x3d\x59\x08\x9c\xc2\xb1\x9e\x07\xd2\xfc\xe4\x3d\xb4\xcf\x17\x1f\xaa\x64\x2f\x3b\x0b\xbd\xe7\x7a\xe3\xd5\x3a\xf5\xc0\x2b\xf8\xfc\x12\xff\xb4\xe5\x7f\x7c\x8a\x01\x5d\x6c\x2d\x17\x89\x44\xfa\xe9\xf7\xc8\xfc\x96\x9d\x4b\x77\xbe\xa5\x18\x76\xae\x99\xd5\x9e\x94\xad\x24\x56\xe0\xed\x72\xc5\x2c\xf4\xe5\x34\x0d\xa1\x7c\x44\xdb\xff\x86\x45\x7a\x51\x9b\x6f\xff\xe2\x69\x06\x62\x90\xd6\x29\xfe\x69"}, -{{0x4f,0x6a,0xeb,0x35,0xfc,0xe1,0x4f,0xbc,0xbb,0x9a,0xa8,0xa4,0xf6,0x45,0x1b,0xf9,0x5b,0x98,0xdf,0x04,0x7f,0xa8,0xc4,0x3f,0x1e,0xad,0x3b,0x40,0x4d,0x3f,0x92,0x8f,},{0xbf,0x66,0xa9,0xed,0xd0,0x94,0x81,0xdb,0x84,0x44,0xa1,0x76,0xc8,0xce,0x05,0x78,0xd2,0x93,0x4f,0x0c,0xdc,0x97,0x34,0xe8,0x6f,0xca,0xac,0x05,0xbf,0x33,0x30,0xf1,},{0x6a,0xdb,0x07,0xe3,0x64,0xf2,0xa4,0x55,0xcb,0x05,0x86,0x7a,0xbc,0x51,0x1a,0xcd,0x9d,0x65,0x89,0x77,0xf0,0xca,0xca,0xfc,0x92,0x82,0x8e,0x7b,0x72,0x4f,0x6b,0xbf,0x98,0xbf,0x0b,0xfb,0x29,0xf4,0xe5,0xe6,0xc7,0x47,0x38,0xd4,0xfd,0xd8,0x16,0xd9,0x25,0x24,0x07,0xae,0x4f,0x3a,0xfc,0x57,0x4c,0x4f,0x00,0x61,0x48,0x24,0xe2,0x03,},"\x2d\xfb\xb3\xf5\x9e\x19\xea\x17\xd4\x4a\x5b\xde\x4a\xd2\x27\xa1\xa3\x51\xdd\xa1\x7a\xf8\x40\xee\x0a\x75\xda\x21\xa5\xcc\xa8\x9b\x6d\x1c\x56\x7c\x33\x3e\x9c\xc9\x10\xe2\x15\x7e\x05\xe8\x6a\xd5\xd9\x31\x14\x50\x64\x59\x4c\x47\xba\xee\xa8\x66\x3a\x34\x64\x9c\x43\xe9\x0e\xb9\x5c\xa1\x0f\x7d\x51\x59\x7b\x37\x8a\x72\x2f\x1f\x70\x4a\xdf\x9f\x22\xe9\xf8\x85\xb8\x9d\x1f\x93\x80\x06\xa2\xef\xcd\xb4\x2a\xaf\xf5\xe3"}, -{{0xef,0x4a,0x67,0x62,0xb4,0x00,0x97,0x52,0x04,0xcc,0xc1,0x3a,0xbb,0x47,0x34,0x40,0x15,0x45,0x49,0x06,0x85,0x0f,0xf1,0x49,0x40,0xcb,0xb8,0x3a,0xa2,0x24,0x14,0xae,},{0xea,0xca,0x45,0x09,0x96,0xf5,0x0c,0xfa,0xf2,0xbd,0x7f,0x9d,0x7f,0xa7,0x08,0x7f,0x09,0xad,0x49,0x66,0x42,0x06,0xa8,0x0b,0xc2,0xe5,0xbb,0xbb,0x85,0xbb,0x66,0x8e,},{0x02,0x69,0x7d,0x44,0xca,0xd8,0x62,0xf1,0xda,0xf5,0x70,0x82,0x05,0xf4,0x50,0xd4,0x08,0x52,0x5b,0x10,0xc0,0x1f,0xfd,0x06,0xcf,0xee,0x80,0x37,0x4f,0x3d,0xb1,0x6f,0xa9,0xa4,0x9c,0x19,0xa9,0x84,0x4b,0x34,0x5f,0x2f,0x95,0x59,0xea,0x74,0xaa,0xb1,0x73,0xba,0xa0,0x78,0xc5,0x43,0x70,0xa5,0x16,0x67,0x00,0xc6,0xda,0xfb,0x78,0x0a,},"\xa4\xb6\x3e\xae\xd5\xa6\x4a\x94\xf2\xca\xd2\x12\xce\x2a\xe7\x10\x92\xfd\x3e\xa7\x44\xf5\xbd\x89\x56\x2b\x2f\xc2\xa6\xc9\xe4\xd7\xaa\x27\xad\xd5\x62\x64\xa5\xa5\x50\x16\x61\x0b\xe6\xc1\x9f\xf7\xd4\x98\x9e\x95\x04\x74\x08\x53\x01\x27\x15\xa7\x9e\xce\x9e\x12\xc3\x01\xb3\x31\x7c\x7d\x9b\x67\x30\xdb\x86\x2a\x4a\x1d\x28\x05\x8e\x0f\x8b\x5d\xdd\x97\x38\xc7\xc6\x2e\xa5\x72\xcf\xe5\x9e\xae\x08\xe2\xb8\xb6\x59\x3b\x58"}, -{{0x55,0x01,0x7e,0x5f,0x61,0xf0,0xc5,0xba,0xfb,0xcd,0xe6,0xf8,0x49,0xf4,0x2a,0x31,0xe5,0xe7,0xa8,0x78,0xc1,0xd3,0xf9,0x12,0x6f,0xc5,0x69,0xfd,0x41,0x7e,0xa9,0xf2,},{0x66,0x91,0x4f,0x74,0xed,0x93,0x2f,0xc8,0x81,0xff,0x01,0x66,0x68,0x3f,0x67,0x5a,0x7c,0x28,0xa9,0x26,0xfd,0xdd,0x64,0x69,0xcd,0xb3,0xf2,0x8e,0x6d,0xec,0x42,0xcc,},{0xb1,0xa5,0xe7,0xc4,0x9b,0x8f,0xc6,0xb4,0x33,0x1e,0x04,0x16,0xce,0x7e,0x4e,0xd5,0x9e,0xdd,0x56,0x30,0x0b,0x80,0x2e,0x0d,0x72,0xab,0xca,0x4a,0x6f,0xcb,0x87,0x6c,0x03,0xbf,0x33,0x15,0x79,0x12,0x4a,0xe0,0xd3,0xfe,0x43,0xf7,0x89,0x8b,0xc8,0x7e,0x93,0xfc,0x2d,0xa3,0x97,0x0f,0xc8,0x63,0x89,0x57,0xd1,0x8c,0x66,0x13,0xc8,0x08,},"\x2f\xc8\x4a\x09\x98\xfa\x6e\x16\x8a\x86\x64\x10\xbb\x68\x10\x5d\xf2\x49\xa2\x8c\xfc\x76\x60\x4b\xe9\x4f\xd7\xdf\xff\xf2\xfc\x1d\xed\xd2\x20\x19\x94\x65\x57\x5e\x8d\xf8\x60\x19\x0f\x16\xac\xa4\x08\x41\x69\xbe\x16\xc6\xba\x32\xeb\x67\x04\x2f\xfd\x4f\x23\x03\x16\xa2\x6b\x26\x24\xa4\x2f\x8f\x90\xad\x57\xf6\x91\x64\x86\xfa\x91\xfd\x94\xed\x68\xad\xed\x4e\x63\x24\x30\xef\x71\x94\x46\x97\x9b\xfa\xf3\x45\x40\x9c\x38\x7f"}, -{{0x05,0x53,0xfb,0xa8,0x66,0x94,0x23,0x41,0x21,0x7c,0xf2,0x78,0xac,0x57,0xcb,0x21,0xac,0xd0,0x9d,0x99,0x16,0xcc,0x6a,0xf0,0xac,0x46,0x94,0x1e,0xa1,0x39,0xd5,0x45,},{0x84,0x0c,0x66,0xe5,0x7c,0x2d,0x4f,0x52,0xa4,0xa2,0x79,0x6d,0x2a,0x53,0xc5,0x70,0x9b,0x96,0xa6,0x28,0xc2,0xe0,0x63,0xfe,0x6e,0xfd,0x47,0xf2,0x83,0xef,0x5e,0x82,},{0xbc,0x33,0x64,0xc1,0x52,0xee,0x5c,0x80,0x8a,0xc3,0x40,0xf4,0x9e,0xa2,0xcc,0x40,0x4e,0x93,0x51,0x71,0x21,0x22,0x0c,0xce,0x6f,0x7c,0x30,0xa2,0x25,0x00,0xe4,0x1b,0xcd,0xb6,0xe8,0x20,0x48,0x0f,0x8f,0xcc,0xdd,0x22,0xff,0x9a,0xd9,0x6d,0xa5,0x32,0x80,0x2f,0x43,0x1e,0x94,0x24,0x0f,0xb8,0x3d,0x4b,0xce,0xaa,0x09,0xb9,0x2b,0x0d,},"\xc1\xfa\xe6\x26\x2a\x0e\x98\xa6\xb1\x23\x5f\xcb\x62\x28\x3b\x7f\x0a\x09\x7f\x9d\x00\x24\x16\xd3\x18\xfe\xfc\x60\xc5\xa1\x58\x4f\x90\x0a\xd0\xab\x26\xcc\xfa\xe0\xd6\xd8\x4a\xa9\xaa\x2d\xf1\x6d\x4c\x11\x7e\xa2\x72\x46\x76\xcb\x86\x6d\x48\x70\xa8\x72\xfc\x82\x9a\x7c\x2a\x5d\x21\xba\x83\x34\x0a\xdb\x33\x9a\x34\xc5\x18\x4c\x7f\x5e\xad\x0f\x07\x72\x89\xb3\x36\x77\xed\x6a\x1b\xa3\x4b\xe1\x99\x4e\x25\x76\x3b\xd1\xd9\xfa\xec"}, -{{0x7a,0x5a,0xc6,0x02,0xde,0x19,0xf3,0xc2,0x10,0x40,0xbc,0xdd,0xbf,0xf4,0x2f,0x6a,0xee,0x6f,0x95,0xc1,0xb0,0x93,0x86,0x8f,0x48,0xe5,0x04,0x82,0xdb,0xf4,0xf9,0xc7,},{0xfb,0xb6,0xc7,0x53,0x1c,0xda,0x21,0xe7,0xd1,0x7e,0xa9,0x03,0xc4,0xd1,0x4b,0xe6,0xc6,0x8b,0x4c,0xa8,0x03,0xa1,0x6b,0xd8,0x71,0x20,0xf5,0xaa,0xf7,0xdc,0xe1,0xd4,},{0x84,0x10,0x1d,0xd4,0xb5,0xe8,0xca,0x3e,0xd9,0x8c,0x1e,0x8a,0x06,0xe1,0x1d,0x7e,0x42,0x4b,0x0d,0x12,0xca,0x71,0x4e,0xe7,0x37,0x4b,0x64,0xc2,0x9d,0x51,0xa2,0x02,0x1c,0xc7,0x7a,0xc7,0x53,0x89,0xd9,0xb0,0xa6,0x46,0xa4,0x47,0x62,0x3d,0x7d,0x04,0xd1,0x24,0x18,0x66,0xb0,0xca,0x6e,0xdd,0x1b,0x7a,0xc0,0x15,0x66,0x6b,0x70,0x0d,},"\xbd\x16\x85\x41\x92\x79\xeb\x81\xe4\xcf\x3c\x90\x90\x31\xf0\xf0\x9c\x5f\xfa\xe7\xe2\xce\x6b\xa9\xd9\x6c\x2b\xce\x87\xb8\xba\x0d\xd7\x63\x23\x10\x01\xe5\x32\xc7\xdd\xd6\x21\x03\xab\xf7\x01\x28\x8e\x19\xdd\x8f\x53\x02\xe8\xf5\xd3\x1b\x64\xcc\x33\x9b\xd8\xb7\xa9\x55\x50\xc8\xa1\x16\xfd\x48\x69\x48\x77\x2b\xd5\xaf\x8d\xfd\x46\x00\x1c\x59\x76\x7b\x0d\x6b\xdc\xe3\x83\xa7\x07\x89\x92\xd1\x02\x2f\xbc\xaf\x90\x71\x06\x87\xb9\xaa"}, -{{0x50,0x41,0x4c,0xf5,0x49,0xbc,0xc5,0x5b,0x5b,0x6b,0x75,0xea,0x37,0x82,0xb2,0xea,0x7c,0x08,0x7b,0x6a,0x01,0x06,0x17,0x5e,0x46,0x9c,0xa2,0xcc,0x76,0x4a,0xeb,0x01,},{0xd0,0xf3,0x0c,0x12,0xe9,0x97,0xf9,0x6e,0x7a,0xee,0xcd,0x1b,0xff,0x6a,0x01,0x2e,0xc3,0x88,0xeb,0xf8,0xf3,0xf4,0xaf,0x66,0x48,0x04,0xd1,0x63,0x8e,0x4c,0x34,0x6a,},{0xb3,0x09,0x80,0x01,0x60,0xde,0x43,0xa6,0x3a,0x89,0xa0,0xac,0xb8,0xa6,0x05,0x00,0x59,0x58,0x9b,0x3e,0xae,0xca,0xc2,0x0b,0x25,0x6f,0xec,0xe4,0x38,0x04,0x2f,0x69,0x41,0x5d,0x8a,0x56,0x88,0x3e,0xe3,0x83,0x6d,0x31,0x34,0xa7,0xfc,0x1d,0xe6,0x4f,0xa8,0xc8,0xce,0xcc,0x3c,0xe2,0x75,0x89,0xf6,0x06,0x05,0x88,0x20,0x85,0x7a,0x0c,},"\x75\xad\x77\xe8\xc5\x4b\x0b\x05\xfb\x2d\x16\x2e\x7c\xad\xb8\xa7\x52\x80\x81\xb8\x63\xf7\x6a\x44\x1b\x37\x44\x69\x41\x3e\x57\x14\xed\xf5\x4f\x80\x04\x96\xaf\x01\x57\xc1\x7e\x42\x55\x83\x41\x4d\x43\x61\xf2\x13\x41\x71\xc0\xb8\x7c\x22\xce\x68\x20\xa4\x85\x0a\xb4\x9d\x99\xa9\xba\xdc\xe9\xe3\x61\x10\xe7\xf3\x06\x01\x18\xb3\x59\x0f\x82\xb4\x37\x71\xe9\xfb\xb0\x81\xaf\xe6\x22\x27\xe0\x24\xd9\x8d\xe6\xcd\xec\x02\x8d\x7c\x49\x49\x0d"}, -{{0x93,0xcb,0x00,0xd8,0xfe,0x9c,0x97,0x77,0xa6,0x83,0x63,0x1f,0x39,0xba,0x0f,0x48,0x76,0x14,0x82,0xcf,0x1c,0x36,0x6b,0xd8,0x63,0xcf,0x71,0x51,0x01,0x53,0x25,0x55,},{0x87,0xe9,0x4a,0x1e,0xa5,0x25,0x8d,0x61,0x18,0x0c,0xb8,0x28,0x59,0x0f,0xf1,0x41,0x8a,0x87,0xd0,0x1e,0x70,0x26,0x86,0xba,0x8a,0xbc,0x26,0x92,0xc8,0xdc,0x3c,0x91,},{0x09,0x82,0x4f,0xa2,0xdf,0xbc,0x4d,0x6e,0xf7,0x6a,0x9e,0x41,0x45,0x96,0x11,0x16,0x76,0x91,0x30,0x55,0x3b,0x3e,0xdf,0xfa,0x50,0xd0,0x4f,0x39,0xb8,0xb7,0x9f,0xac,0xbd,0x23,0x7a,0xcf,0x71,0x35,0x4a,0x53,0xa6,0xe5,0xfe,0xe7,0x54,0xe8,0x23,0xb0,0xb2,0x90,0xf9,0x61,0x93,0x20,0xa1,0x3d,0x56,0x12,0x69,0xa2,0x21,0x63,0x9f,0x03,},"\x88\xd8\x53\x8d\x31\x86\x78\x13\xd8\x8f\xef\x72\x28\xd4\x9a\x7e\x95\x0d\x73\x83\x96\xf1\x16\xdd\xa1\x02\x5f\x79\x13\x54\x7c\x5d\x1d\xc5\x67\x7a\x6d\xe4\xb4\xa5\x88\x05\x07\xb3\x61\x78\x0b\x61\xb4\x3f\x77\x95\x26\x3d\xb2\x2f\xf3\x41\x64\x5f\x2f\x59\x14\xfd\x60\x88\xc2\x81\x12\x11\xed\x47\x56\xac\x01\x9a\x60\x35\xd6\x6e\x31\x70\xc1\xd8\x2b\xfa\xa3\x05\x96\xb3\x96\xb3\x26\x0c\xc1\xd1\x0d\x41\x3d\xd4\x7e\xbe\x6d\xaa\x0c\x30\xdc\x42"}, -{{0x2b,0x4c,0xae,0x38,0x0e,0x95,0xce,0x69,0x4c,0x26,0xac,0x79,0x57,0x44,0x73,0x47,0xf9,0x8e,0x31,0xb4,0xbf,0x02,0xd7,0x44,0xe1,0x31,0x52,0x90,0x71,0xe2,0x30,0x1d,},{0xe6,0xfc,0x70,0x5a,0x79,0xc9,0x8e,0x11,0x5b,0x4e,0x28,0xd3,0xaa,0x15,0x06,0xb7,0x4e,0xe7,0x42,0x76,0xc5,0xfc,0x11,0x09,0xa7,0xf4,0xd8,0x9c,0x6f,0xaf,0xb8,0x89,},{0x55,0x5e,0x45,0x65,0x6b,0xa9,0xcf,0xbf,0x51,0x55,0xd0,0xe5,0x25,0x76,0xe5,0x19,0x7a,0xbb,0xbc,0x9d,0xd2,0x33,0x99,0x3e,0xec,0x2a,0x1e,0xe7,0xf6,0xa8,0x64,0x09,0xc0,0xb7,0x1b,0x0a,0x66,0x19,0x78,0xff,0x5e,0x0a,0xcd,0xc9,0x46,0x3d,0xc4,0x49,0x90,0x6f,0x47,0x4f,0x8e,0x79,0xbb,0x86,0x16,0x8b,0xf7,0x07,0x41,0xe3,0x4b,0x02,},"\xe0\xb8\x25\x0e\x27\xb7\xc0\x29\x1d\xbc\x47\xa6\xda\x6f\x12\x68\x98\x7a\xfd\xf0\xa1\xe9\x0b\xe6\x9b\xcb\xc4\x37\x08\x65\x21\x78\x30\xd5\x20\x86\x93\xbe\x7b\x70\x45\x09\x9a\x22\xea\x27\xf9\x52\xeb\x3f\x79\xa9\xa0\xf1\xb5\xa8\x7b\x19\x36\x77\x90\x78\x8d\x34\xc2\x19\xc2\xe2\xa6\xb8\x34\x02\x0f\xb4\xfd\x14\x9d\xc5\x6b\x54\x4f\xdd\xbb\x42\x07\x1a\x16\x2f\xc7\xcb\x33\xc1\x46\xca\xc0\x5a\x31\xb1\x83\xe9\xda\xad\xc6\x16\xf3\xaf\x44\x9b\x17"}, -{{0xb5,0x64,0x91,0xe5,0x49,0x99,0xbb,0x5a,0x17,0x15,0xeb,0xfa,0x2f,0xeb,0x14,0xa5,0x45,0xa3,0xa4,0x3c,0x2f,0xdf,0xd4,0xbe,0x0c,0x95,0xfc,0x11,0x81,0x9a,0xd6,0x95,},{0xcd,0x42,0xbf,0x41,0x4f,0x9b,0xfc,0x72,0xec,0x06,0x98,0x82,0xa8,0x00,0x55,0x7c,0xdf,0x31,0xbc,0x34,0x64,0xfb,0x10,0x2c,0x31,0x0e,0x6d,0xbd,0x3a,0xe2,0x08,0x63,},{0xe3,0xbe,0x3e,0x71,0xa8,0x98,0x52,0xdf,0x3c,0xff,0xd7,0x2d,0x68,0x20,0x78,0x69,0xdd,0x3e,0xce,0xb4,0x9b,0x1f,0x02,0x94,0x93,0xec,0xcb,0xb9,0x32,0x44,0x4e,0xbe,0x8c,0x8c,0x6d,0xb5,0xf0,0xa5,0xa6,0x7e,0x21,0x94,0x40,0x8d,0xf9,0x84,0x19,0x13,0xa5,0xac,0x1a,0x60,0x68,0x96,0x41,0x9a,0x66,0x8f,0x4f,0x47,0xc5,0x6c,0x2b,0x08,},"\xeb\x44\x18\xba\x30\x68\x3e\xc7\x95\x9b\xdb\x1e\xc7\xb2\x63\xf8\x3e\x81\xf0\x54\xdd\xcd\xbe\x0a\x67\x38\xca\x77\x63\xe2\x46\x93\x5b\xac\x41\x90\x26\xc2\x2b\xfb\xdd\x12\x36\x33\x6c\xc1\x61\x07\xc5\x35\x13\xe3\xdd\xf3\x4e\x12\x08\x46\x96\x2c\x3b\xdd\x54\xf5\xad\x57\x49\x59\x72\x08\xf1\x5a\x8b\xb5\x66\x67\xba\xa8\x95\xf0\x83\x40\xdb\x89\xb8\x5c\x43\x5e\x77\x09\x31\x92\x8d\x8a\xbc\x99\x26\x2f\x83\x9a\xed\xd9\xbe\x2a\xa1\x38\xc9\x25\x9a\xdf"}, -{{0x65,0x79,0xc2,0x47,0xdd,0x2c,0xd0,0x2b,0xa2,0xf7,0xd7,0xa9,0x50,0xa3,0x30,0x75,0x26,0x81,0xe9,0x2c,0x0d,0xc6,0x29,0x84,0xbb,0xea,0x27,0x9e,0xa5,0x21,0xc3,0x81,},{0x0b,0x08,0x7b,0xea,0x1a,0x1b,0x3d,0x15,0x80,0x5c,0xb6,0x04,0xf4,0xbb,0x8d,0x68,0xed,0xde,0x27,0x4f,0xaf,0x52,0x1f,0xe6,0xdf,0x50,0xc5,0x5f,0x8a,0xd4,0xa7,0x0d,},{0xec,0xca,0xf8,0x01,0xae,0x0a,0x91,0x2e,0x21,0xc6,0xb8,0x3a,0x5f,0x0e,0x4e,0x88,0xd4,0xb2,0x71,0x34,0x59,0xff,0x93,0x44,0x9f,0xc0,0xb2,0x1a,0x9f,0x41,0x60,0x50,0x11,0x3c,0xba,0xe4,0xe8,0x14,0xd2,0x0c,0x0a,0x79,0x8f,0x76,0xd2,0xf9,0xd3,0x26,0xed,0x83,0x95,0x9e,0xa0,0x2a,0xbd,0xc1,0xab,0x35,0x0a,0x46,0x71,0x23,0xf7,0x09,},"\xdf\x7c\x55\x2f\xfc\x89\x37\x4b\x95\x71\xa6\x02\x4a\x8d\x04\x71\xd7\xeb\x6b\xe8\xdf\xca\x6f\x41\x66\xb5\x81\xb6\x54\x79\x01\x5a\x05\x68\x12\x90\x74\xcc\x04\xd6\x34\x2c\x75\x8c\xa1\x8f\x79\x87\xde\xc5\x36\xb7\x03\x3d\x5f\x96\x81\x50\x43\x40\xe2\x09\x86\xf0\x27\xb8\xcf\x1f\x26\x3b\xe7\x6d\xb3\x52\x5d\x17\x34\x22\x95\x0e\xa8\xdc\xed\xdc\x58\x56\x40\x91\x8a\xa9\xd2\x5c\xa8\x9c\xba\x70\x1c\x20\x20\x15\x38\x73\xf4\x61\x08\xc7\x72\xcb\x38\x8d\x55"}, -{{0x18,0xfb,0xa6,0x0c,0x50,0x26,0xf3,0xc9,0xdd,0x7a,0xed,0xc0,0x42,0x09,0xd5,0x26,0x03,0x61,0xde,0x40,0x0e,0x19,0x0a,0xeb,0x60,0x16,0x9e,0x05,0xa3,0x36,0x7c,0x9f,},{0xdf,0xff,0x34,0x7f,0x3d,0xd2,0x55,0x53,0x0b,0xf7,0xfb,0x34,0xd0,0x2b,0xa4,0x86,0xd1,0x12,0xbb,0x46,0xe9,0x50,0xe2,0xef,0x80,0xe5,0x17,0x01,0x4c,0xc9,0x57,0x34,},{0x4b,0xc0,0x11,0xe4,0x0f,0x0f,0x59,0xc6,0x18,0xf6,0xbb,0xe2,0x30,0xb6,0xf7,0xbc,0x2f,0x50,0xe3,0x61,0x7c,0x7f,0xaa,0xb7,0xf4,0xc2,0x1c,0xb8,0x4f,0x77,0xeb,0xa9,0x94,0xcb,0x7c,0x2a,0x1b,0xf1,0x0b,0x01,0xbb,0x20,0x08,0x44,0x97,0xfd,0xf0,0xa6,0xab,0x5d,0x9b,0xcd,0x22,0xc4,0xa2,0xc5,0xa7,0x8f,0x79,0x92,0x68,0x25,0x94,0x0f,},"\x34\xf0\x8a\x80\x4d\x78\x29\xcc\x39\x14\xf0\x00\xce\x1a\x32\x88\xac\xce\x21\x49\xc8\xa0\x20\x86\xb9\xf6\x7a\xfc\xcd\x83\xa1\x78\xb0\xbc\xfd\x49\x70\xc0\x56\x99\x7d\xa7\xdc\x3d\x47\x56\x2f\x16\x66\x3c\xed\xc5\x2f\x82\xd7\x10\x85\x0c\xf4\x05\x03\x79\xef\xda\xc2\x3b\xee\x17\xc3\x30\xa3\x83\xad\x13\x7f\x78\x84\x73\xb2\xb0\x72\x36\x03\xb6\xde\xb1\xfd\xbf\x6c\x52\x3f\xc9\x48\xa0\xcc\xc4\xff\x10\x0f\xb9\x46\xd8\x74\xc1\xf9\x90\x43\x6a\xe8\xc4\xf3\xb2"}, -{{0x07,0x3c,0xc1,0x5b,0x05,0x36,0x28,0x59,0x33,0xb2,0xbe,0x39,0x25,0x3c,0xf4,0xfd,0x69,0x6b,0x81,0x61,0x0f,0x5d,0xd3,0xad,0xac,0x2e,0x9c,0xbf,0x33,0x8e,0xf2,0xf6,},{0x00,0xb5,0x51,0xd3,0x71,0x54,0x43,0x75,0xda,0xc5,0xc4,0xe9,0x6c,0xd1,0xf0,0x21,0x52,0x07,0xe8,0xe1,0x66,0xa1,0xfe,0x49,0xd5,0xb0,0xa5,0x1a,0xc1,0x84,0x43,0xec,},{0x3a,0xa5,0x2a,0x83,0x06,0x2a,0x8f,0x28,0xa5,0xd6,0xb7,0x60,0x7f,0x48,0x4b,0x66,0xcc,0x37,0x48,0x96,0xb7,0x66,0x12,0x31,0x26,0x33,0x3c,0x57,0x95,0x81,0x31,0x6c,0x74,0x28,0x06,0xf6,0x27,0xb5,0xbc,0x55,0xca,0xd7,0x05,0xcc,0x1d,0x47,0x82,0xb0,0x44,0x08,0x0c,0x8a,0xc8,0x40,0xf3,0x8c,0x0c,0x50,0xd3,0x5e,0x34,0x5c,0x78,0x03,},"\xc2\x85\x36\x2b\xc8\xef\x62\x8f\x7a\xed\xf6\x54\x23\x1e\xe5\x1a\xcd\xf2\xcf\x69\xa8\x86\xb9\x42\xbb\x9b\xfe\xd8\x15\x51\x05\xd9\x20\x9d\xed\x2a\xf2\x4f\x16\x9a\xd5\xfc\xd4\x51\x37\x0f\x58\x27\xa8\x51\x11\xc7\xa5\x2e\x03\x2c\x50\x38\x61\x7c\x0c\x01\x70\xe2\xa6\xc2\x31\xdc\x40\x1d\x12\x06\x2e\xdb\x18\x60\x36\x11\x4e\x38\x79\x3b\x79\x08\x90\x77\x58\x1b\x97\x83\xf4\x00\x07\x10\x3e\xf1\x74\x72\x49\x1c\x00\xe7\x13\x8a\xec\xc5\x08\x4d\x3c\x85\x01\x04\x70"}, -{{0xfd,0x89,0x4a,0x1e,0x82,0x32,0x20,0x3b,0x28,0x95,0x05,0xd5,0xc6,0x8c,0x68,0x79,0x1f,0xfc,0x0e,0x54,0xf2,0xa8,0x75,0x30,0xfb,0xba,0x5b,0x3a,0x3f,0x2c,0xaf,0x00,},{0xe9,0x5a,0xb5,0x65,0x94,0x5c,0x7a,0xe5,0xd5,0x33,0xdf,0x5d,0x0c,0xcc,0xc7,0xe9,0xab,0xbc,0x83,0x8e,0x20,0xa0,0xb6,0x1c,0x93,0x0f,0x5d,0x41,0xd8,0x1a,0x6f,0xe7,},{0xf5,0x11,0x02,0x21,0x9e,0x88,0x04,0xbe,0x71,0x3e,0x55,0x6d,0xf4,0xe4,0xaf,0xa2,0xf8,0x86,0x6f,0xe8,0x65,0x41,0xa1,0xc2,0xa0,0x93,0x4d,0x24,0xc3,0xc9,0xbe,0xb2,0x80,0xa7,0x0d,0xd8,0xd5,0x27,0xfe,0x8b,0x7e,0x0b,0x94,0x82,0x14,0xd5,0xf2,0xf9,0x63,0x86,0x19,0x91,0x4b,0x72,0xd5,0x5d,0xc1,0x98,0xb0,0x22,0x9a,0x84,0x87,0x08,},"\x26\x69\x62\x4a\x94\xf2\xc4\x4a\x05\xb7\xdc\x3e\xbf\x93\xe5\x8a\x4b\xf3\xa0\x1c\x27\x36\x57\xe7\xe7\x87\x89\x76\xf6\xb6\xea\x73\x7f\xa3\xf2\x2c\xc8\x36\x5b\x8b\x22\x0c\x00\x7d\x5b\x64\x27\x26\xa4\x08\xfe\x2f\xab\x69\xeb\xb3\xbd\x07\x2b\x34\x9f\x4d\xc3\x37\x7e\xe7\xcc\x75\x29\x34\x25\x42\x15\xd2\x39\x89\xbd\x3c\xd0\x2c\xe9\x99\xad\xec\x97\x84\x99\x3f\x4c\x19\x94\x08\x15\xf3\x9c\x9e\x22\x92\x47\xf5\x20\x5c\x36\xcb\xa4\x4e\x71\x42\x66\x36\x92\x89\xb4\xa7"}, -{{0x18,0xef,0x46,0x4e,0x28,0xf8,0x7f,0xfc,0xfa,0x4d,0x3a,0x9c,0x09,0xa2,0x29,0x10,0x95,0x1b,0x8c,0x71,0x9f,0xda,0xcd,0xb5,0x6d,0xe6,0x2c,0x4b,0x40,0x6d,0xf0,0x0c,},{0xc5,0x06,0x4c,0x9d,0x43,0xee,0x2d,0xa7,0x5b,0x06,0xbb,0x09,0xc7,0x72,0x67,0xdb,0xd0,0xd3,0x91,0x28,0xf1,0xcd,0xc6,0xbf,0xa4,0x51,0xa0,0x3e,0x93,0xaf,0x4a,0x70,},{0xd1,0xe7,0xf1,0x6e,0x8e,0x59,0x7d,0x42,0x8a,0xde,0xa6,0x55,0x91,0xd5,0x51,0xb5,0x4b,0x66,0x7a,0xff,0x20,0x20,0xc4,0x64,0xf7,0xf4,0xe5,0x3c,0x47,0x73,0xf7,0x04,0x33,0x24,0x9a,0x3c,0x71,0xb4,0xd1,0x1c,0x89,0xc3,0xfa,0xa8,0x92,0x80,0x92,0x27,0xb9,0xf2,0x9e,0xf4,0xf7,0xf5,0xd0,0x20,0xd4,0x67,0x4d,0x40,0x21,0x35,0x94,0x05,},"\x9c\x82\x57\x07\xd9\x35\x83\x65\xab\x9d\x38\xf7\xe7\x28\xd6\x28\xaa\x72\x2a\x4f\x1a\x20\xa3\x8e\x47\xc9\x99\xff\xf8\xfc\x32\x41\x7f\xbe\x07\x2f\x96\xeb\x6a\x0e\x11\xe4\xda\x9b\x6d\xe9\x61\x54\x45\x28\x0e\x93\xc7\x7a\x36\x34\xd3\xd2\xc6\x87\x98\x56\xc2\x48\xf9\x80\x0f\x60\xa0\xd3\x8d\xc1\xce\xa8\xb7\xf3\x1f\x28\x6c\xb0\x37\x48\x27\xb4\xc6\xba\x14\x4a\x66\x94\xf2\xb9\x08\xea\xd6\x8d\x18\x34\x01\x24\xcb\x59\xcf\x17\x01\x86\x3b\xd4\xf3\xef\xc7\x09\xf3\x62\x7a"}, -{{0xc9,0x11,0xbd,0xf2,0xf9,0xe7,0xcc,0x5f,0xff,0x35,0xc9,0x6e,0x15,0xcc,0x12,0xea,0xfd,0x05,0xab,0x0d,0xb3,0x1f,0x64,0x9f,0x74,0x08,0xac,0xd0,0xca,0xda,0x76,0xe0,},{0xde,0x44,0x69,0x6c,0xd6,0xbd,0x2c,0xbe,0x9b,0x11,0xa0,0xef,0x18,0xb8,0x81,0x64,0x80,0x1a,0x96,0x9d,0x5e,0x06,0xed,0x45,0x3e,0xb4,0x00,0x8c,0xce,0x9a,0x57,0x25,},{0xd5,0x84,0xb5,0xda,0x37,0x1a,0xe4,0xf5,0xc9,0x85,0x9b,0x25,0xf7,0x0d,0xc5,0x6c,0x1b,0x7b,0x4e,0x02,0xd1,0xae,0x66,0x36,0x28,0x3b,0x1b,0x7b,0x11,0x21,0x7a,0xfd,0xcd,0xf6,0x5d,0x1b,0x49,0xca,0x2c,0x8e,0xf1,0x79,0x66,0xe9,0xbc,0x65,0xf1,0x0c,0x31,0x0b,0x77,0xbb,0x5d,0xf7,0xaf,0xf5,0xec,0x1b,0x37,0x9a,0x2c,0xe5,0x5d,0x0d,},"\x76\xc4\x71\x24\x1d\x17\x19\x29\x84\xb0\x03\x62\x69\x6e\x4d\x9d\x4d\x2b\x7f\x83\x9c\x20\x64\x11\x7e\x50\xa1\x59\x8f\x3a\x11\x72\xb1\x6c\x55\xe5\x39\x68\x66\x08\x47\x52\x02\x4f\x3a\x7e\xb6\x8b\xb3\xff\xdb\x80\x97\x9a\x0a\xf6\xd0\xf6\xaf\x26\xb6\xf0\xbc\x0c\x03\x84\x43\x3b\xcf\xd4\x4c\x75\xeb\x65\x4a\x8a\x82\x25\xcb\x9c\x4a\x7f\xb3\xc8\x24\xc3\xaf\x61\x25\xfd\x46\xdb\x28\x7e\x70\x49\x2d\x15\x46\x32\xcb\x8f\x62\x43\x26\x59\xd9\x58\xd6\x28\x1d\x04\xa5\x4f\x5f\x5f"}, -{{0xd3,0x70,0x32,0x99,0xc4,0x1d,0xb3,0x6d,0x77,0xdd,0x3a,0x49,0x54,0x1f,0x3f,0xb2,0x1d,0x0b,0x2b,0xad,0x1f,0x6e,0x07,0x4a,0xff,0xd9,0x6f,0x1c,0x40,0xd0,0xf9,0x27,},{0x86,0x2c,0x5e,0xf6,0x16,0xa5,0xf0,0x66,0xfd,0x87,0x75,0x8a,0x56,0xab,0x45,0x05,0x6f,0xea,0x4b,0xd3,0x3f,0x00,0x8b,0xe2,0x4f,0x7b,0x54,0x0e,0x09,0x5e,0x14,0x8e,},{0xdf,0x28,0x27,0x71,0x21,0xea,0xc4,0x46,0x30,0x08,0x4c,0xce,0x75,0x91,0x7a,0xe9,0xf6,0xbe,0xc6,0x5a,0xf5,0x57,0x2d,0xc3,0x07,0x19,0xbd,0xe6,0x61,0xcf,0x69,0x6b,0x85,0xb8,0x67,0x2d,0xd4,0x98,0x3c,0xab,0x30,0xbd,0x05,0xcc,0x3a,0x11,0x9d,0x7d,0xb9,0xba,0xbd,0x52,0x2d,0x7b,0x3a,0x6b,0xcf,0x38,0x86,0xec,0xd2,0x5e,0x08,0x0f,},"\xac\x92\xed\xbe\x22\x25\x7b\xb0\x6d\x94\xaa\x95\x0e\x62\xd1\x8c\xa2\xac\x0a\x8f\xc1\x06\x00\x0d\x22\x31\xf8\xa1\x3b\x8d\x7a\x20\x9c\xcd\x8c\xc4\x9a\x6c\xd6\x8a\x7f\x36\xc0\x2f\xb8\xf7\x28\xd1\x55\x95\x16\x7f\x0b\xa8\xcf\xe9\x5c\x8a\x1e\x43\x5f\x32\x75\x13\x01\x4a\xc4\x28\xb7\x5d\x4f\x72\xe7\xc8\x34\xdd\x70\xe1\xa4\x48\xf1\x84\x7d\x34\x98\x47\x5f\x74\xe3\xd9\x33\x4d\xc7\xdc\xc4\xfe\xd7\x2b\xf6\xc7\xfe\x3b\x1d\x4f\x53\xd4\x29\x61\x6f\x1d\xf4\x4f\x19\x73\x31\x58\xb6"}, -{{0xd4,0x11,0xcd,0x33,0x57,0x6d,0x0e,0xfe,0x9e,0xc4,0x13,0xcc,0xda,0xab,0xd4,0xfc,0xba,0xfe,0xc0,0x1a,0x3a,0xf4,0xb3,0xcb,0xe3,0x4f,0x8b,0x05,0xef,0x8b,0x59,0xba,},{0xe8,0x70,0x34,0x4d,0xf9,0x8d,0xd3,0xa8,0x70,0x2c,0x45,0x19,0xbf,0x9e,0x8b,0x35,0xa9,0xd1,0x89,0xe7,0x46,0xf7,0x20,0x3d,0xbb,0xf9,0xbb,0xfa,0xb2,0x2d,0x6f,0x63,},{0x83,0x46,0x0d,0x15,0x46,0x1d,0x67,0x17,0x71,0x0b,0xaf,0xd6,0xa4,0x7a,0x1e,0xaa,0x90,0x0a,0x80,0xf2,0xbf,0x8b,0x8a,0xae,0x24,0x68,0x77,0x36,0x14,0xee,0x84,0xbd,0x62,0x8c,0x97,0x17,0x47,0x63,0x68,0xef,0x36,0x40,0xcf,0x76,0x0a,0xca,0xc8,0x3a,0xd6,0x02,0x32,0xa7,0x69,0x63,0xb7,0xd5,0x25,0x88,0xb1,0x1d,0xc0,0x04,0xd7,0x0d,},"\x11\xd2\xc2\xa7\xf0\x19\x09\x88\x12\x66\x96\x43\x1b\x4b\xbc\xd9\x0a\xb7\xb5\x6a\x32\xda\x64\x04\xae\x44\x6a\xa7\x62\xa4\xdd\xc6\x60\x94\x97\x15\x38\xee\xb8\x5b\xde\x04\x70\xa5\x10\xbe\x0d\x6d\x85\x78\x0e\xe7\x30\xa9\x85\x41\x38\x72\x8a\xe6\x81\x61\x62\x26\x8d\xa8\x52\x85\x8e\xae\xd4\xec\x74\xc7\xac\x62\xe6\xe7\x09\x6d\xc0\x02\xdf\x0b\xdf\x5f\xa4\x0d\xa5\x65\xb4\x1d\x18\x1a\x3f\x0a\xd0\xc5\xe0\xb9\x76\x74\x3e\x31\x5d\x9d\xb8\xed\x41\x60\xab\xe6\x9c\x13\xa2\xb3\xf0\x9a"}, -{{0xe1,0x0a,0x2f,0x13,0x80,0xc3,0xe4,0x72,0x0e,0x8a,0x87,0x07,0xa9,0xbc,0xb2,0x5a,0x0f,0x58,0x27,0x0d,0x70,0x59,0xcd,0x76,0x26,0xc7,0x15,0x34,0x47,0xed,0xfb,0x87,},{0xa3,0xc7,0x17,0xac,0xab,0x36,0x6a,0x40,0xb5,0x11,0x87,0xbb,0xf3,0x5b,0x2d,0x15,0xe9,0x7c,0xfe,0xac,0xd7,0x34,0x9c,0x06,0xef,0x1c,0x91,0xac,0x93,0xe9,0x06,0x56,},{0x09,0x4b,0xf6,0xf9,0x53,0xca,0x0e,0xb7,0x7d,0xf4,0x51,0x29,0xb7,0xbf,0x10,0xd1,0x92,0xcf,0x6d,0xde,0xae,0x94,0xad,0x62,0x02,0xb8,0xea,0xcf,0xbe,0xc1,0x19,0xe5,0x29,0x15,0x78,0xfe,0x64,0xa0,0x84,0xae,0x60,0x0f,0xe0,0x7e,0xfd,0xb8,0xa7,0x82,0x61,0x0d,0xbd,0xb0,0xb4,0x9e,0xb5,0xf2,0xa4,0x6c,0x43,0x23,0x55,0x55,0x2f,0x01,},"\x13\x52\x12\xa9\xcf\x00\xd0\xa0\x52\x20\xbe\x73\x23\xbf\xa4\xa5\xba\x7f\xc5\x46\x55\x14\x00\x77\x02\x12\x1a\x9c\x92\xe4\x6b\xd4\x73\x06\x2f\x00\x84\x1a\xf8\x3c\xb7\xbc\x4b\x2c\xd5\x8d\xc4\xd5\xb1\x51\x24\x4c\xc8\x29\x3e\x79\x57\x96\x83\x5e\xd3\x68\x22\xc6\xe0\x98\x93\xec\x99\x1b\x38\xad\xa4\xb2\x1a\x06\xe6\x91\xaf\xa8\x87\xdb\x4e\x9d\x7b\x1d\x2a\xfc\x65\xba\x8d\x2f\x5e\x69\x26\xff\x53\xd2\xd4\x4d\x55\xfa\x09\x5f\x3f\xad\x62\x54\x5c\x71\x4f\x0f\x3f\x59\xe4\xbf\xe9\x1a\xf8"}, -{{0xb2,0xe6,0x97,0xb3,0xd3,0xef,0xec,0x97,0x6e,0xf3,0x36,0x95,0x30,0xc7,0x92,0x71,0x7b,0xdb,0xb4,0x28,0xd9,0xed,0x0c,0x11,0xec,0x0e,0xa9,0xb2,0xe5,0xf3,0x9f,0x82,},{0xc4,0xd2,0xe4,0xb3,0xc2,0x36,0xd6,0xc9,0xb8,0xc7,0x4f,0xa3,0x84,0x61,0x2c,0x47,0x10,0xd8,0x3a,0xa1,0x6a,0xd7,0xef,0x01,0xfb,0xb7,0x42,0x1d,0x4f,0xb3,0xf0,0xf6,},{0x50,0x47,0xfa,0x38,0x19,0x7b,0x83,0x28,0xe7,0x8d,0xd8,0xa1,0x0e,0x96,0x6a,0xfb,0x7b,0xd3,0xd4,0x36,0x08,0x28,0x0f,0x1c,0x25,0x7d,0x25,0xca,0x43,0xbc,0x1c,0x06,0xe9,0x4a,0x57,0x47,0xab,0x62,0x15,0xec,0xe5,0x4c,0xde,0xff,0x8c,0x56,0x56,0x7d,0x70,0xd2,0xf9,0x1f,0x9e,0xc8,0xc2,0x60,0xaa,0x10,0x80,0xa6,0xab,0x5a,0x7a,0x02,},"\x7b\x43\x62\x32\xac\x21\x11\xa8\x40\x59\x51\x0c\x48\x36\x25\x88\xfc\xb7\x38\x34\x26\xbe\x5e\x6f\x62\xf3\x72\xe4\xf7\xcc\xa8\x3c\x81\xc2\x35\x7f\x9b\x54\xf4\xa1\x52\x91\x06\x5b\x6d\x41\xaa\xd1\xea\x93\xcf\xfa\x77\x6b\x9a\xca\xa5\x8a\xfe\x2b\x51\x64\x4b\x97\xaf\x9a\x3e\x53\xf8\x4e\x40\xaa\x6d\x86\x05\x1e\x69\x14\xcd\x03\x9d\x41\x70\xa9\xa5\x26\xdd\x69\x95\x5f\xf5\x07\xc3\x3f\x74\xe2\x17\x65\x91\xfb\x0b\x3c\xd7\xf0\x0e\xe4\x18\xf2\xc2\x58\xa9\x98\x1c\xcc\xee\x72\xf0\x1c\x84\x30"}, -{{0x19,0xa6,0x79,0xa7,0xa9,0x05,0xa1,0xe2,0xb3,0x03,0x8e,0x6e,0x41,0x8b,0x3d,0xa9,0x7c,0x30,0x89,0xc7,0xcd,0x35,0x1e,0xa0,0x7b,0xc8,0xd1,0xaf,0x64,0xea,0xcc,0x46,},{0x19,0xf0,0x83,0x61,0xf4,0x69,0xb4,0xae,0x1e,0x0c,0xeb,0x94,0xf4,0x7a,0x7d,0xe7,0x31,0x74,0x10,0xa9,0x2d,0xd0,0x13,0xb1,0x6a,0xe0,0xd0,0x53,0x2f,0xa4,0xb3,0xef,},{0x43,0x47,0xb7,0xb4,0xf7,0xc3,0xc4,0xdd,0x31,0x5b,0x83,0x84,0xa0,0xb0,0xca,0xee,0xd8,0x4b,0xda,0xbe,0x24,0xb2,0x91,0x5f,0x12,0x51,0x2d,0xfd,0x04,0x77,0x0f,0xc9,0x96,0xa1,0xbf,0xb7,0x29,0xaf,0xef,0x9e,0xdd,0x61,0x14,0x47,0x08,0x1a,0x53,0x30,0x61,0x7e,0xae,0xa1,0xc1,0xda,0xb1,0xbf,0x13,0xce,0xa8,0x99,0x72,0x04,0x91,0x0c,},"\x98\x0c\x7b\x4d\x29\x39\x06\x1a\xc7\xb9\xba\x44\x11\x17\xa1\x94\x85\x66\x17\x81\xa4\x08\x30\x67\xc5\x5a\xcf\x93\x02\x6c\x08\x2a\x93\xcc\x12\x4f\x09\x5e\x1b\x4f\x2c\x3f\x6c\x13\x54\x12\xa5\x09\x62\x28\xe8\xa0\x71\xe8\xb4\xb6\x68\xba\x9d\x96\x44\xea\x9f\x4d\xab\xfc\x54\xa9\x85\x6c\x3e\x96\x5e\x63\x63\x39\x5a\xb7\x09\x03\x7d\xda\x22\x9b\xaf\x92\x7c\xd0\x1f\x9a\xf5\xe0\x39\xaf\xc4\x2f\x3c\xec\x63\x4f\x5d\x83\x2d\x2a\xb7\xc7\xca\xd3\xad\x7b\x8c\xf2\x7e\xbd\xac\x69\x84\x31\xad\x82\x36"}, -{{0xf0,0x3b,0x83,0x63,0xee,0x5b,0x0e,0xef,0x70,0x18,0xa4,0x9b,0xc0,0x2a,0xdf,0x73,0x1d,0xa5,0x4e,0xe5,0x0a,0x7f,0x03,0xb8,0x8a,0x29,0xa2,0x08,0x2b,0x18,0x9c,0x43,},{0x31,0x28,0x7e,0xf5,0xa2,0xe6,0x41,0x04,0xab,0x77,0x90,0xb3,0x12,0xf3,0x5c,0x7a,0xd4,0xaf,0x6b,0xeb,0x0d,0x7c,0xeb,0x8a,0x58,0xf3,0x6a,0x54,0xce,0x27,0x2c,0x3e,},{0xe8,0xfa,0x96,0x7e,0x6a,0xfa,0xdf,0x6a,0x87,0x7d,0x87,0xe5,0xf5,0xc5,0x2b,0xb6,0x34,0xb7,0x5a,0x78,0x04,0x19,0x9a,0x2b,0xc9,0xd0,0x27,0xb6,0x3a,0x35,0x65,0x4d,0x9d,0xdd,0x06,0x83,0x04,0x55,0x64,0x1d,0xbf,0xb4,0x9e,0xdc,0xe4,0x2e,0x20,0xe7,0xd4,0x10,0x4a,0x07,0x1c,0x2c,0xbb,0xec,0x23,0x01,0x8c,0x29,0x7c,0xed,0x99,0x08,},"\x24\x19\x1b\x54\x64\xb3\x5a\xc7\xbc\xf4\xa3\x75\xf0\x33\xef\xba\x89\x43\xb0\x9b\x9f\xf0\xfc\x40\x3c\xa7\xaa\xe7\x02\xa3\xcb\xf3\x96\xc5\x13\x1b\xc0\x08\x13\x2c\xf5\xf1\x29\x10\xd5\x86\xdc\x1d\xb9\xc0\x84\x57\x4a\x96\xba\xbe\xe9\x56\x42\xf9\x22\x37\x1c\x03\x82\xec\x04\x02\xa2\x6f\xeb\x14\x2e\x41\x46\xbb\xd3\x36\x0c\x2b\x36\x83\x4f\xe4\x5a\xf5\xe2\x86\x8d\x4d\x56\xfd\xd5\x04\xce\xbf\x0c\x2d\x7f\x57\x91\xb4\x42\x94\x17\xc8\xb6\x5a\x98\xe0\xb1\x5c\x46\x6c\x13\x7f\x41\x05\x24\xfc\xe7\x37"}, -{{0x11,0x08,0x6b,0x0d,0x11,0xe4,0x15,0xab,0x1c,0xe0,0x2a,0xaf,0x8f,0x06,0x21,0xb5,0x44,0x30,0xf6,0xfb,0x13,0x5c,0x74,0xf4,0x0d,0x38,0xe8,0xc6,0x47,0x37,0x06,0x4b,},{0x71,0x66,0xdf,0xbc,0x69,0x1e,0xb8,0xc2,0x01,0x11,0x4b,0xa0,0xd1,0xa2,0xc7,0xb8,0x7f,0x7a,0x1f,0xd8,0xd0,0xb3,0x60,0x58,0xb0,0xd7,0xdc,0xab,0xe1,0xae,0x30,0xda,},{0xe9,0x07,0x45,0x9d,0x5a,0xdc,0xd0,0xd0,0xc3,0x64,0x18,0x58,0x1f,0x19,0xd0,0xee,0xbd,0xa7,0x13,0x8e,0xbd,0x9f,0xaa,0x0b,0x26,0x22,0x01,0xf4,0x58,0xc8,0x56,0x31,0x0b,0xb7,0x7f,0x4c,0x7d,0xe9,0x22,0x49,0x5d,0xcf,0xe8,0xb2,0x48,0xed,0xa2,0xad,0x0d,0xf6,0xa7,0x3f,0x47,0xbb,0xfb,0x89,0x4b,0xaa,0x7d,0x88,0x69,0x87,0x58,0x02,},"\x4b\x5b\x29\x36\xc5\xe3\x60\xa3\x84\x55\x50\x37\x21\x07\x8f\x8a\xdb\x40\x4a\x7e\xe7\xec\xc1\x48\x01\xdc\x87\xa6\x7a\x15\x2b\x76\x95\x69\xfb\xea\xc0\xaf\xa2\x5a\x20\x70\xa1\x68\x6b\x90\x0a\xc1\x63\x3d\x49\x98\x08\xcd\xb2\xe8\x1c\xe3\x91\x6d\x5a\x3c\x04\xd1\x9c\x5b\xb2\x69\x9a\x66\x2b\x8a\xba\x4a\xf9\x4d\x39\x0b\xac\x7c\xcc\x8e\xc9\x10\xed\x2a\xcd\xf8\x6e\xbb\x71\xad\xb6\x01\x87\x78\x85\xee\xf3\xc9\x16\x62\xfc\x30\x73\x8e\x35\x2c\xc7\x43\x53\xcc\xf8\xd8\xed\xee\xfa\xcc\x04\x2c\x10\xa0\xe5"}, -{{0xef,0xce,0x76,0x67,0xa8,0xef,0x91,0x22,0x8c,0xae,0xd1,0x4e,0xb4,0x77,0xa3,0x45,0xe5,0xe8,0x23,0x92,0x34,0x08,0x08,0x48,0x76,0x0e,0xd0,0x97,0x07,0x13,0xfa,0x86,},{0x91,0x93,0x05,0x5a,0x84,0xdf,0x1e,0xac,0xca,0x28,0xce,0x2a,0x08,0xc2,0xa0,0x7a,0x50,0xf0,0x4c,0x02,0x4e,0xcf,0x1f,0xe4,0xa4,0x7d,0x2e,0xfb,0xaf,0x63,0xed,0x58,},{0xe5,0xa6,0x31,0x24,0xdb,0x16,0x96,0xb6,0x41,0x40,0xb6,0xe9,0x61,0x2f,0xa9,0x58,0x7b,0x3e,0xef,0x71,0x01,0x09,0x39,0x8d,0x44,0xba,0x0c,0xa6,0x3c,0x0e,0xba,0xd0,0x6f,0x0a,0x6c,0x89,0x94,0xea,0x34,0xb3,0xa2,0xaf,0x91,0xa8,0x9b,0xf4,0x1a,0xe6,0x14,0xd7,0x72,0x7d,0x71,0x6f,0xd4,0x2f,0x8b,0x92,0xe1,0xac,0x64,0xfd,0xbf,0x03,},"\xaa\x1b\xc8\x0d\x7b\xcc\x1d\x94\xa2\x3a\x57\xce\xdf\x50\x27\x48\x24\x77\xdc\x46\xb8\x68\x90\xbc\x0e\x5a\xc2\x9a\xe6\xc9\x1b\xbc\x43\x13\x03\x48\x79\x73\x05\xf7\x55\x43\x58\x0a\x8a\x06\x9b\x34\x8a\x7b\xd8\xfc\x3e\x01\x52\x30\xb7\xc1\x94\x0c\x7f\x80\xa8\x2b\x12\x90\x09\x10\xdb\xcf\x06\x30\xda\x03\xf0\x81\xd4\x4c\x7f\x95\x5d\x4a\x11\x72\xf5\x6e\xcc\x7c\x5a\xc6\x46\x69\x6b\xff\xdf\x4e\xb6\xd8\x8b\xdd\x9c\xc3\x84\x35\x28\xb7\x25\x83\xab\xb3\xba\xd0\x2e\x56\xef\x76\x46\xee\xd5\x13\x95\x51\xcd\xeb"}, -{{0x88,0xfc,0xca,0xa9,0x6a,0xd8,0x84,0xd1,0x16,0x5b,0xe7,0x1d,0xd0,0xc4,0xf5,0xf8,0xf4,0x42,0x1c,0x60,0xfb,0xfa,0x49,0x8b,0xfe,0xe9,0xb9,0x67,0x46,0x24,0x43,0xbd,},{0xc7,0x5c,0xb0,0xe0,0x23,0x7b,0x45,0xb8,0x65,0x6e,0xea,0x9f,0x3d,0x1a,0x9d,0x4a,0xcd,0x01,0xa1,0x03,0xaa,0x26,0x9b,0xb2,0x4f,0xd5,0x41,0x22,0xfd,0x81,0xf2,0xac,},{0x27,0xd3,0xa1,0x97,0xcc,0x99,0x94,0x21,0x20,0x63,0xbc,0xe8,0xd7,0x99,0xe7,0x7b,0x68,0x53,0xb7,0x35,0x5e,0xbe,0x36,0x9b,0xcf,0x18,0x89,0xa4,0x18,0xa8,0x2c,0xaa,0x3a,0x79,0x87,0xa6,0x63,0xf6,0x21,0xde,0xfe,0x86,0xb3,0xac,0x4a,0xd4,0x4f,0xae,0xed,0x16,0xc9,0x11,0x6a,0xce,0x28,0xfc,0xcf,0x91,0x55,0x57,0xfa,0x77,0x99,0x03,},"\x9d\x0e\xac\x98\x55\x6b\xfa\x86\x72\xc3\x57\x05\xd1\xd6\x1a\xc4\xd0\xfc\xa1\x9d\xc0\xd9\x93\x01\x58\x77\x85\x7d\x27\xfd\x80\xf7\x4a\xca\xce\x66\x6c\x56\x34\x85\xd8\x1e\x53\x60\x3a\x6a\xef\x40\x87\x5f\xa5\x51\xcc\x10\x5f\x2c\xc1\x0b\x39\x69\x46\x79\xcd\xf4\xa6\xb0\x73\xbc\x88\x64\x5f\xc5\x1a\x36\xda\x17\x9d\x3d\x1e\x3c\x77\x22\x45\x4c\x5e\x73\x57\x7c\x61\xaa\x7d\x14\x8c\x4b\xa5\x0e\xa4\x6c\x56\xa1\xc3\xb3\xb3\xc4\x70\xf9\x31\x00\x49\x4e\x08\xbc\x55\x14\xac\x76\x3a\x85\x48\x3c\x42\xc7\xcd\xc2\x7c"}, -{{0x67,0x0b,0x30,0x62,0x6f,0xe3,0x67,0xd8,0xb4,0x5f,0x43,0x73,0x3d,0x6f,0x25,0xb3,0x7e,0xcc,0xbc,0xb5,0x51,0x96,0x3f,0x0a,0xc8,0xb6,0x66,0xb4,0x80,0x41,0xc7,0x2d,},{0x65,0xaa,0x4c,0x6d,0x4b,0xa0,0xab,0x34,0xbc,0x75,0xb3,0x9f,0x09,0x52,0x7c,0xa6,0xf2,0x42,0x5f,0x52,0x41,0x5c,0xdf,0xfd,0xf2,0xdf,0xf2,0x73,0xf8,0xea,0x61,0x2c,},{0x1b,0x6b,0x43,0x77,0xd2,0xb9,0x8e,0x0f,0x9d,0x24,0xae,0x8d,0xfe,0x30,0xe2,0x39,0x6e,0x20,0x04,0x38,0x0d,0x34,0x31,0x48,0x8e,0x58,0x43,0xcf,0x8d,0x2d,0x7a,0x00,0x70,0xab,0x21,0xf8,0xa3,0xb5,0x1c,0xe8,0x4d,0x2f,0x4b,0xa2,0x09,0xf7,0x39,0xf9,0x22,0xbe,0xbf,0x79,0x80,0x96,0x69,0x3f,0x56,0x22,0x87,0x3d,0x79,0xae,0x6f,0x04,},"\xd0\x0b\xcc\xa7\xe1\x84\xd1\x0e\x1f\x1f\xe4\x20\xb5\x06\x39\xe1\xd5\xde\xba\x52\xa7\x51\x23\x6e\x68\xc5\x9b\xb4\xbf\xf9\x80\x2f\x5f\xc1\x65\xed\x42\xfd\x6d\x53\x46\x70\xa7\xc6\xfb\x60\xe4\x30\x7d\x94\x79\x15\xa2\x48\xbf\x2f\x93\x46\x5c\x2c\xb4\x4d\x8f\x45\x3d\x2c\x01\x5a\xfb\xc8\xed\x58\x81\x8e\xa5\x17\x26\xa2\x51\x77\x93\x0e\x9e\xa1\x92\xef\x45\x14\xf4\xbb\x0e\xb4\xe0\xf5\xd4\xae\x3c\x46\xe3\x57\xc8\x11\x87\xf7\xed\x17\x47\x33\xff\xf9\x59\xc3\xf9\xfa\xe6\x48\x6c\xfa\x13\x56\xa9\x56\x99\x21\x1d\xe5"}, -{{0x81,0x3c,0x4d,0xae,0xd6,0x7a,0x19,0x0d,0x68,0xbb,0x63,0x5d,0x73,0xaf,0x6d,0xa7,0x4f,0x32,0xfd,0xf7,0xc4,0x8c,0xca,0x6e,0x59,0x26,0x29,0x46,0xb8,0xe8,0xc7,0x1f,},{0xa2,0x09,0x54,0x57,0xd7,0x69,0x70,0x20,0xe2,0xb8,0x84,0xd9,0x5a,0x96,0x57,0x8c,0x2a,0x90,0x0a,0x76,0x66,0xac,0x0d,0xc7,0xbd,0x38,0xf1,0x93,0x1d,0x79,0x45,0xd8,},{0xb4,0x46,0x57,0x4f,0xf6,0xa4,0xbd,0x2b,0x57,0x2e,0x48,0x7c,0x4a,0xb4,0x43,0xca,0x64,0x10,0x75,0x16,0x8a,0xa4,0xe1,0x09,0x2f,0x71,0xf3,0x0b,0xdb,0x06,0x8c,0xe4,0x6a,0x39,0x5e,0xfe,0xe1,0xee,0x66,0x0b,0x9f,0xac,0x26,0xd5,0x41,0x09,0x72,0x2c,0x15,0xcd,0xb7,0x91,0xbf,0xb8,0x7f,0xff,0x63,0xc6,0x59,0x6a,0xd4,0xf2,0x27,0x0c,},"\xce\x54\xcb\x04\x50\xe6\x89\xa0\xdb\xef\x78\x53\x08\xb3\x17\x74\x72\xfc\xd6\xd3\x82\x03\xe5\x8a\x05\x90\xb3\x1f\xa2\x53\xf9\xea\x59\x0b\xe5\x36\x8a\x92\x2d\xe8\x8b\x63\x45\x01\x02\x68\x44\x43\xfb\x81\x89\xe6\x01\x28\x20\x03\x32\x3b\x89\xc8\x1e\x92\xea\xef\x2b\x5d\xdc\x4a\x55\xc5\x3f\xa3\xcf\xad\x41\x60\x24\x8b\x3c\x28\x6f\xf8\x0d\x31\xd1\x61\xb7\xb8\xde\xe7\x13\x55\x2b\x56\xf1\x50\x7f\xb7\x2e\xad\xfa\x89\x05\x4e\x9d\x16\x00\xac\x87\x4c\x4b\x0a\x96\x10\x04\xeb\x6d\x0d\x4b\xfd\x2e\xcb\x9c\x73\x4f\x00\xba"}, -{{0x84,0x00,0x96,0x2b,0xb7,0x69,0xf6,0x38,0x68,0xca,0xe5,0xa3,0xfe,0xc8,0xdb,0x6a,0x9c,0x8d,0x3f,0x1c,0x84,0x6c,0x8d,0xce,0xeb,0x64,0x2b,0x69,0x46,0xef,0xa8,0xe3,},{0x98,0xbe,0x21,0x00,0x19,0x93,0xa7,0xeb,0x1a,0x12,0x77,0xff,0x74,0xc1,0x55,0x04,0x18,0x3d,0x25,0xfd,0xfc,0xc0,0x5f,0x0d,0x4d,0xea,0x89,0x2f,0x6e,0x30,0x18,0x90,},{0x0a,0xd7,0x1b,0x00,0x25,0xf3,0xd9,0xa5,0x0d,0xb3,0x38,0x41,0x4d,0x6d,0x67,0x0e,0x77,0x99,0xb7,0x27,0x0a,0x84,0x44,0xf6,0xae,0x7f,0x12,0xae,0x7e,0xb7,0x1b,0xd0,0x3f,0xfd,0x3c,0x4f,0x36,0x63,0x1f,0x69,0xfd,0xcc,0x40,0x61,0x46,0x8f,0xf5,0x82,0xed,0xe4,0x95,0x24,0x3e,0xf1,0x36,0x1a,0x3b,0x32,0x95,0xfa,0x81,0x3b,0xa2,0x05,},"\xf7\xe6\x7d\x98\x2a\x2f\xf9\x3e\xcd\xa4\x08\x71\x52\xb4\x86\x4c\x94\x3b\x1b\xa7\x02\x1f\x54\x07\x04\x3c\xcb\x42\x53\xd3\x48\xc2\x7b\x92\x83\xac\xb2\x6c\x19\x4f\xd1\xcb\xb7\x9e\x6a\xfc\x32\xff\x68\x6b\x55\xb0\xb3\x61\x72\x18\xdc\xf3\x93\x16\xb4\xb6\x6b\x3c\x8c\x0d\x67\x26\x7a\x86\xdb\x8a\xdf\x37\x50\x80\x1b\xcf\x93\x27\xd4\xc2\x54\x41\xb9\x61\x97\x83\x2b\x4c\xde\x0e\xac\x3f\xf2\x28\x92\xa2\xf0\xbc\x17\xc2\xc2\x13\xc0\x23\x77\xa3\x33\xe3\x08\xed\x27\x16\x58\x04\x93\x83\xb7\xe2\xe5\x7b\x6b\x8b\x12\x55\x12\xe0"}, -{{0x62,0x88,0x72,0x20,0x35,0xd1,0xea,0x69,0x9b,0xc7,0xcf,0xdf,0x18,0xd8,0x96,0x25,0x42,0x31,0x80,0xb6,0x83,0xfa,0x74,0x63,0x9f,0x4f,0x30,0xf1,0x53,0x59,0xcc,0x85,},{0xe1,0x7f,0xaa,0x01,0x95,0x72,0x86,0x1a,0x06,0x4e,0x1b,0xc5,0x71,0x25,0x6d,0xea,0x14,0x68,0xf3,0xa4,0x85,0x90,0xa8,0x91,0x38,0xaa,0xa8,0x59,0x25,0x08,0x0c,0xd7,},{0x9d,0xec,0x92,0xb6,0xe8,0x9a,0xdb,0xe8,0xf4,0xe1,0xb5,0xe9,0x3a,0xc4,0xfc,0xf9,0x57,0xde,0x7d,0x19,0x70,0xa2,0x26,0x77,0x0e,0xc4,0xed,0xa6,0x47,0xc8,0xe3,0xb3,0xdf,0xfb,0x27,0x31,0xa3,0x9e,0x16,0xe4,0xa0,0x11,0x9d,0x36,0x62,0xa9,0x37,0xe5,0x60,0x52,0x24,0x91,0xec,0x7a,0x16,0x96,0xbe,0x04,0xc0,0x76,0xb1,0x2e,0x35,0x01,},"\x8b\x6c\xaa\xca\xc5\x1d\x89\x49\xfb\x86\xac\xbc\xb1\xb9\x9d\x85\x9f\xf6\x7c\x64\x14\x7b\xc1\x21\x69\x09\xdc\xab\x07\xee\x6e\xf0\x9f\x40\x38\x63\x32\x73\x94\x68\x9d\xc3\x4a\xbc\x77\x8f\xcb\x5c\x1f\x50\x91\xac\xf5\xa0\x8f\x9d\x84\x22\x11\xd1\xae\x2e\xb4\x0b\xe9\xbb\x8d\x66\x79\x07\x74\x71\x54\x7a\x6c\x71\xff\x77\xb5\x19\xd4\xb7\x10\x8e\x32\xbc\x46\x25\x1c\x60\xde\xe8\xe3\x32\xb6\x22\x93\x16\xe6\xd5\x7c\x22\xab\x82\x6f\xf1\xbc\x33\xf2\xb0\x21\x38\x07\xc1\x92\x80\xaf\x11\x0f\xd2\x6e\xe2\x74\x68\x20\x1c\xff\x49\xcb"}, -{{0x13,0x03,0x8a,0x3a,0x65,0xef,0x32,0x75,0x9a,0x9c,0xd9,0x03,0xac,0xb5,0x54,0xb2,0x52,0xde,0x00,0xe7,0xcd,0xb7,0x7b,0xbe,0xd1,0x97,0x0b,0x20,0x68,0x0e,0xe1,0x7b,},{0xb6,0xa3,0x08,0xe6,0x7f,0x9b,0x46,0xc6,0x64,0x99,0x45,0x6a,0xb5,0xcd,0x13,0x5c,0xb2,0xfe,0x84,0xa3,0x2e,0xb0,0x45,0x35,0x86,0x26,0x60,0x4d,0xa4,0x12,0x2c,0x8f,},{0x52,0x61,0x55,0x8e,0xcc,0x3c,0x98,0xff,0x36,0x35,0x1f,0x42,0xf5,0x04,0xca,0xd4,0xa3,0x2f,0xfd,0xa5,0xa7,0x44,0x56,0x09,0x60,0xb4,0xc1,0x06,0xe4,0x49,0x2f,0x02,0xe2,0x04,0x78,0x88,0x7a,0xfe,0xe4,0xf7,0x70,0xf0,0x55,0x97,0xa7,0xe3,0x88,0xca,0xce,0xae,0x80,0x5a,0xe3,0x51,0xe0,0xe4,0x5e,0x8e,0x57,0x8e,0x6a,0x6f,0xf2,0x0c,},"\xdd\xf0\x0b\x40\x33\xa2\xa0\x88\x02\x2d\xab\xe9\x33\x56\x43\x2f\x50\xdd\xc6\xc6\xe1\xa6\x59\xdc\x1a\x93\x12\x4a\x4c\x2f\xff\xfd\x18\x27\x65\xa2\xf5\x6c\x43\xea\x0b\xfd\x8d\xe8\x01\x50\x60\x88\x9a\xe6\x94\x1c\x3f\x3e\x25\x5d\x44\x21\xa1\xc3\x62\x01\xbe\x84\x6a\x27\x38\xa7\x1f\x12\x0c\xad\x59\x8c\xa8\x52\x7d\x70\xff\x8d\x5a\x09\x93\xb5\x5c\xb5\x15\x35\x17\x11\x0a\x41\x96\x2d\xaf\xf4\x22\x50\x15\x8f\x20\x96\xd1\xdd\xaf\x71\x86\xe5\x02\x98\xcb\xe5\x1f\xcb\x42\x9c\xbe\xa4\x11\x29\x3f\x8a\x7b\xd9\xcf\x06\x9f\xa2\x37\xe4"}, -{{0xb9,0xde,0x5b,0x06,0x3d,0x3c,0xa3,0xa7,0x73,0xf1,0x14,0x94,0x1b,0x2e,0x42,0x27,0xc0,0x75,0x11,0xc0,0xf5,0xc0,0x60,0x17,0xb9,0xc8,0x84,0x50,0x18,0xf2,0x34,0x32,},{0x52,0x95,0x24,0x3c,0x86,0x46,0xe0,0x96,0x67,0x4d,0xda,0x15,0x97,0x9b,0x32,0x2b,0x9d,0xd0,0xfa,0xf2,0x7d,0x02,0x4a,0x0e,0xd5,0x77,0x13,0x34,0xe1,0x17,0x9e,0xd2,},{0x92,0xba,0x76,0x0d,0x14,0xd1,0x41,0x5c,0xfa,0xf2,0x18,0xca,0x84,0x70,0x14,0x08,0x8a,0xe5,0x1a,0xd8,0x21,0x11,0x3a,0x6f,0x86,0x30,0x35,0x6f,0x7b,0xa8,0x5c,0x00,0x5e,0x23,0x30,0xf1,0x06,0x6d,0x0d,0xf4,0x64,0x80,0x60,0x52,0xa4,0x17,0x46,0x10,0x05,0x04,0x62,0xf3,0xe0,0x13,0xd7,0x02,0xe7,0xc7,0x71,0x85,0xa0,0x32,0x58,0x0b,},"\x94\x93\xcc\x23\x89\x6b\x84\x09\x60\x46\xae\x10\x53\xaf\xe3\x94\x99\xe9\x42\x42\x54\xb3\x66\xfe\x14\x3f\x4d\xa3\x21\xe2\xdc\x9e\x47\x84\x20\x8e\x12\xa5\x42\xd8\x99\x82\x8d\xde\x7e\xff\x62\x5a\x7f\x12\x41\x69\x90\xc2\x84\x1f\xfb\x09\x5b\xf9\x4c\x0c\x61\x0e\x5a\x66\x39\x18\xb6\x89\x03\x1c\xcd\x6b\x51\x93\x49\xd0\x4d\xe1\xc2\x12\xca\x2a\x9d\x7a\xbf\x52\xe1\xb4\xfd\x46\x7b\xb6\x65\xb6\x91\x9e\xf8\xf9\x16\x17\xe2\x05\x56\x5b\xf5\x66\x47\xe5\xf8\xd5\x08\xea\x20\x0a\x84\x46\x7f\x8f\xa1\x22\xe7\x4b\xc3\xb9\x97\x9f\x11\x74\xe5"}, -{{0x8f,0xf0,0x29,0x7c,0xc0,0x88,0x42,0xb5,0xe6,0x75,0x52,0xec,0x28,0x43,0xe0,0x43,0x53,0xa3,0x4d,0x74,0xef,0x89,0xb8,0x56,0x5d,0x97,0x20,0x5b,0x74,0xca,0x13,0x3a,},{0x0f,0x7e,0xf9,0x8c,0x5b,0xa4,0xaf,0x98,0x4d,0xfb,0x77,0xbc,0x4e,0x53,0x7b,0x2b,0x39,0xe6,0x27,0x3b,0xb3,0xe7,0xb9,0x5f,0xe1,0xb7,0xe6,0x78,0x19,0x52,0xbd,0x4a,},{0x07,0x83,0x73,0x7f,0x70,0x6e,0x6f,0xf3,0x66,0x14,0xf8,0x50,0x07,0x4f,0xca,0x1f,0x48,0x5f,0x24,0xfc,0xde,0x2a,0x28,0xaf,0x54,0x4f,0x37,0xab,0xd6,0x9b,0x7a,0x58,0x1d,0xef,0xd8,0xc7,0x71,0xb0,0x31,0xe1,0x08,0xd1,0x9d,0x78,0x8c,0x74,0xc5,0xf2,0x0b,0xb3,0xf1,0xc2,0x1c,0xd9,0x2b,0xe3,0x17,0xba,0xcd,0x8f,0x65,0x0b,0x49,0x05,},"\x2b\xdc\x3a\x48\x6c\x5e\x4e\xa6\x2d\xcf\xec\x8a\x9d\x4f\xcf\x9e\xa9\x49\x0d\xbc\xc7\x15\x61\x5d\x58\x49\x0a\x72\xce\x83\x3f\xa2\x23\x87\xca\x50\xa0\x05\x25\x08\xcf\x0a\xff\x1c\xa7\x27\xf0\xfe\xd4\x6f\xfa\x7d\x3c\x8e\x23\xc5\xbb\x01\xd4\x7e\x90\xff\x06\xd3\x85\x8a\x55\x7d\x99\x26\x48\x15\x79\xda\xf4\x38\x4a\xea\x50\xe9\x6e\xc6\x15\xd2\xa3\xbf\x3c\x11\x22\xf1\xf2\x4d\xd6\xed\x98\xa5\xde\x42\x18\x83\x58\x9c\x21\x39\x98\xca\x54\x32\x37\x3e\x68\xbb\xbe\x89\x42\x8c\xa9\x88\x5d\x05\x93\xd5\xe6\x21\x51\x16\xb8\x26\x63\x86\x45\x2b"}, -{{0x05,0x0d,0x55,0x3d,0x28,0x2d,0xca,0x32,0x69,0xc8,0x3c,0x18,0x17,0x68,0xec,0x06,0x7b,0x81,0xc9,0xfe,0x0c,0x94,0xf2,0xa0,0xeb,0xbb,0x0c,0x94,0x2d,0x0f,0xcd,0x7c,},{0x63,0xe2,0x30,0xb0,0x03,0xc5,0x3a,0x56,0x72,0xe8,0x32,0xff,0x7f,0x24,0x43,0x0b,0xe2,0x23,0xe4,0x97,0xde,0x84,0x02,0x33,0xf5,0x95,0xa3,0xe2,0x00,0xc7,0x12,0x7e,},{0x3f,0x0e,0x83,0x76,0x5b,0x31,0xbb,0xe8,0xe1,0xfb,0x92,0xe9,0x67,0x8d,0x6c,0xde,0x57,0x1a,0x03,0xba,0x7f,0x1d,0xcc,0x11,0x28,0x46,0x1f,0x70,0x85,0x25,0x45,0x7f,0x4e,0x0e,0x23,0x53,0xaa,0x2b,0x59,0x8c,0x06,0x3f,0xf1,0xbf,0xfd,0xac,0x91,0x6b,0x5a,0x22,0x00,0x65,0x51,0x56,0x90,0x4b,0x05,0x85,0x57,0x7a,0x16,0x28,0x56,0x0d,},"\x15\xe1\x3b\x8c\x01\x00\x4f\x6a\xa5\xb2\x36\xdb\xb2\x81\x67\x7f\x74\x6d\x81\xe5\x48\xe0\xaa\x80\xf0\xe4\x14\x52\x15\x21\xd8\x56\xcd\x69\x4e\x7c\x91\x52\xbb\x5e\x43\x77\x6b\x60\xf6\xb5\x60\xed\x1a\xd3\xe4\xb3\x90\xdb\xf3\xe4\x6e\xf9\x25\x74\x43\xf3\x9c\x14\x9e\x02\x40\xa0\x2d\x02\x1e\x1e\x3d\x7d\x04\x6b\x26\xfd\x00\x4e\xee\x7c\xa1\x6a\x80\x59\xe1\x26\xc7\x4c\xb3\xf2\x19\x4d\xb4\x7b\xf6\x04\x65\xec\xef\x5c\x70\x4d\x2e\x2c\x75\xe2\xe5\x00\x60\xea\x2a\x31\xcb\x72\xb7\xb3\xc6\xb1\xb5\xec\x72\xab\x38\x00\x40\x85\x28\x1a\x22\xfe\x86"}, -{{0x69,0x49,0x7c,0xd7,0xb4,0xe8,0x68,0xcf,0xa0,0x32,0x8d,0x92,0xbd,0x60,0x52,0xd7,0x72,0xb2,0x76,0x73,0x95,0xc1,0x45,0x95,0xb2,0x79,0x85,0x1a,0x9c,0xdd,0x31,0xaa,},{0x5d,0x27,0x6d,0x62,0x6e,0x23,0x0d,0x18,0xe7,0xbc,0xd6,0x11,0x41,0xcb,0x93,0xc9,0x0e,0xf0,0xf7,0x9e,0x01,0x32,0x12,0x12,0xd8,0x38,0xec,0x71,0x45,0x7b,0x1a,0xac,},{0xbe,0xaf,0xa5,0x83,0x40,0x96,0x09,0x08,0xe8,0xd8,0x6e,0x40,0x32,0x9e,0x3a,0x45,0x23,0xfc,0x7b,0xe7,0x70,0xad,0xdb,0x86,0xe3,0x4c,0x37,0x72,0xf8,0x4c,0xd9,0xfb,0x33,0x8d,0x1f,0x3b,0x65,0xbf,0xcd,0xb0,0x9f,0x35,0xc6,0xda,0x36,0xd1,0xa3,0xad,0xf8,0xf9,0x1f,0x1f,0xfd,0x57,0x82,0xcc,0x83,0x02,0x06,0x43,0x3a,0x08,0x41,0x0d,},"\x53\xcd\x08\x0a\x0c\x61\xf1\xa0\x93\xd3\xb3\xa7\x45\x71\xc2\x96\x30\x3f\x36\x3b\x41\x07\xed\xbe\x88\x0b\x7a\xa9\xdf\xe4\x4a\xb5\xd5\xdc\x5f\x74\xbe\x9c\x8d\x87\x6f\x04\xd7\x54\x65\x34\x91\xab\x51\xb1\x35\xfc\x95\x3f\x71\x28\x7b\x62\xff\x41\xb6\x7c\x74\x2b\xd3\x44\x56\x71\xa9\xd4\xf2\xdc\x17\x4c\xa1\xb0\x33\x5f\x78\x62\x7a\x0d\xd4\xb3\x06\x50\x50\x41\x78\x03\x9e\x73\x93\x63\x85\x10\xff\xe8\x40\x91\xb5\x72\x98\xd3\xac\x90\x01\xc3\x67\xc1\x45\x2f\xbc\xb3\x3d\xc5\x4a\x5d\xc3\x16\xfb\x2a\x52\x70\x76\x4a\x2a\xc8\x20\xa0\xb6\x3f\xbd\xc6"}, -{{0x21,0x65,0xa4,0x86,0xb6,0x12,0xbb,0xff,0x52,0x9c,0xd0,0x03,0x46,0x96,0x4a,0x3c,0xb8,0xcd,0xcf,0xfa,0x51,0xdc,0x3d,0x52,0x4d,0xd5,0xad,0xc5,0xac,0x93,0x6d,0x68,},{0x7e,0xbc,0x83,0x9a,0x46,0x5e,0x14,0xf5,0x89,0x24,0x76,0xe4,0xa1,0x3b,0x39,0x88,0xf8,0x3b,0x3c,0xd2,0x7e,0xf7,0x9e,0x19,0x3f,0x86,0xfa,0x16,0xf3,0x4a,0x1c,0xe1,},{0x7e,0xc6,0xfb,0xa5,0x6b,0xa5,0x24,0x60,0xa1,0xb4,0xf2,0x73,0x86,0x89,0xc1,0x88,0x3d,0xda,0x9a,0xaf,0xfc,0x8b,0xde,0x17,0xcb,0x60,0x29,0xbd,0xce,0x3a,0x0e,0xbe,0x2f,0xff,0xda,0x55,0x93,0x9b,0x70,0xbb,0xd0,0x7f,0xdb,0xf6,0xfc,0x5c,0xda,0x87,0xfe,0xd8,0xba,0x58,0x57,0x5f,0x89,0x4a,0x36,0x6e,0x45,0xe5,0x70,0x5e,0xea,0x09,},"\xb7\x28\xda\x7a\x36\x16\x7c\x60\x85\xbd\x2d\x96\x2c\xf6\x39\x59\xfa\xcd\x95\xc9\xad\x45\x42\x02\x8a\xfb\xa9\x0e\xc9\xc6\xc0\x76\x0b\xda\xe9\x35\x42\x9c\x3f\xeb\x39\x33\xe2\xf0\x00\x42\xc6\x72\xad\x2c\xd7\x34\x8d\x92\xbc\x33\xf8\x17\x51\xe2\x94\xae\x91\x71\xb9\x45\xb1\x93\x14\x4e\xf8\xac\xb9\xa1\xbd\x9a\xbf\x04\x75\xce\x0d\x0a\xc7\x89\xb2\x00\xc3\x2e\x9c\x9a\x27\x36\xb1\x68\x36\x9c\xe5\xf9\x7b\x1e\x8d\x2e\x79\x00\xe1\xa7\x59\x17\x84\x41\xf1\xfc\x43\x05\x64\xae\x12\x9b\xae\x78\x57\x74\x05\x11\xa6\x68\xf3\x2c\x0a\x3b\x07\x7a\x9d\x8b\x19"}, -{{0x1c,0x64,0xad,0x63,0xdd,0x14,0x70,0x34,0x59,0x8e,0x12,0x8f,0x74,0x06,0xec,0x05,0x30,0x74,0x6e,0xa1,0xc5,0xb7,0x2e,0xcf,0x79,0xe8,0x88,0x06,0x54,0x86,0xfa,0x1b,},{0xba,0xa6,0xbc,0xc1,0xc3,0xd8,0xd3,0xb1,0x1f,0xfc,0x15,0x87,0xad,0xdd,0xc5,0x8b,0xfd,0x96,0xc2,0xb9,0x92,0xb6,0xc6,0xf5,0x9f,0xcc,0x50,0xcc,0xbc,0xdd,0x0e,0xb9,},{0x74,0x77,0xe5,0x41,0x58,0xf1,0x3b,0x71,0x28,0xc0,0xa1,0x10,0xca,0x6b,0x65,0xf4,0x25,0x14,0xfb,0x70,0xcd,0x5c,0xf2,0x8a,0x8b,0x1c,0xc6,0x11,0x0e,0xa0,0x6f,0xcf,0x94,0x29,0x0d,0xa1,0x3f,0x85,0xa1,0x1c,0x23,0x51,0xd3,0xbb,0xcc,0xbb,0x4c,0x64,0xe0,0x21,0x5d,0x6d,0x0f,0x00,0x99,0xe7,0xf2,0x7b,0xc9,0x4e,0x94,0x9b,0x15,0x0b,},"\x9e\xbd\x8e\x33\x78\x93\xbb\x05\x3e\xf2\xb9\xe3\x26\x9d\xf5\x48\x48\x49\x4f\x03\xcd\x63\x57\x6b\x33\xe6\x4b\x10\x80\xbe\x4b\xe0\x15\x26\x4a\x40\x3f\xb9\x60\x2b\xbf\x90\xca\x19\xb2\x41\xa9\xb6\x68\x63\x90\x9b\x90\x08\xce\x1b\x2f\xfc\xf2\x36\xef\xa4\xc2\x66\x8f\x0f\x47\xdb\x9f\xf5\xfa\x15\x7d\x9c\xb6\x05\x41\x2b\xe7\xdd\x8b\x07\xea\x87\x8c\xcc\xae\x6b\xf5\x0f\x93\x5b\x86\xd1\x9e\x1b\x64\x8b\x69\xe5\x28\x55\x3a\x56\xd8\xaf\xb7\x82\x21\xad\x53\x30\x7b\x7a\x4e\xc8\xd2\xfd\x48\x61\xb5\x5d\xc5\xda\xe8\xe9\x3e\xf3\x87\xfb\xbe\x0b\x4c\xe7\xf7\x88"}, -{{0x55,0xab,0xbc,0x5d,0xac,0x41,0x28,0x13,0x4d,0xc8,0xc6,0x01,0x8a,0x21,0x3e,0xd4,0xb6,0x0f,0xcc,0x8e,0x90,0xcb,0xd4,0x1d,0xb2,0xd2,0x1e,0xda,0x53,0x73,0xe9,0x36,},{0x25,0x1a,0xfa,0xa2,0x64,0x69,0x26,0xb2,0xa3,0x71,0xf2,0xa0,0x9d,0x58,0x65,0xb9,0x8c,0x9a,0x5e,0xb6,0xca,0x04,0x7c,0xd0,0xd8,0xee,0x36,0xe5,0xe0,0x41,0x69,0x74,},{0xf6,0xa6,0x1c,0x2e,0x66,0x1a,0x9e,0xb7,0xbd,0xe1,0x82,0xe3,0x8e,0xc9,0x9a,0xf9,0x85,0xf6,0x16,0x98,0xa5,0xd7,0xfa,0x43,0x0d,0x16,0xe3,0xf1,0xa9,0x37,0x09,0xb7,0x55,0x22,0x32,0x0d,0xe4,0x8a,0xfc,0xc5,0x95,0xab,0x20,0x91,0x22,0xae,0x0c,0xe1,0x32,0xcd,0xf4,0xb0,0x39,0x17,0x46,0xe7,0xff,0x34,0x11,0x77,0x57,0x0c,0x81,0x08,},"\x47\x01\x0e\x13\x98\xad\x55\xfa\xbe\x37\x1d\xd8\x64\x8f\x76\x8d\x90\xdf\x4b\x96\x5a\x3b\x39\x61\x00\xb3\x03\xb4\x0a\x17\x51\x8b\xed\x6d\x86\xb0\x9f\x73\x4a\xb7\xc1\x0b\x5f\x3a\x01\xb5\x3d\xee\xc5\xf8\x53\x4b\x70\xc7\x9f\x3f\x29\xb2\x84\xfd\xec\x48\x6f\x22\xf4\x4c\x22\xcc\xd5\xc6\x46\x35\x94\x41\x52\x67\xba\xa6\x11\xf7\x0b\x1b\x31\x6c\xaa\x1b\x68\xb5\xe0\xe9\x9b\x31\xc5\xbb\x0c\xe1\x36\x79\xa2\x3c\x31\xa6\x39\x99\x69\x81\x64\xcb\xf3\x7d\x10\x3b\xa9\x24\x90\x18\x8b\xe5\x99\x37\xf1\x23\x04\x3e\xc7\x86\xef\xe3\xd4\x11\xf9\xb0\x62\x3a\x6a\xd9\x72"}, -{{0xf2,0xdc,0xf4,0xa1,0xa0,0xd4,0x6d,0xdb,0x2d,0x72,0xf8,0xfd,0xd8,0x0b,0xbe,0xc5,0xb7,0xde,0xa5,0x91,0x3d,0xa4,0x96,0x6c,0x2f,0x4d,0x12,0xc2,0x61,0xf0,0xbf,0x98,},{0xd3,0x95,0x70,0xa2,0x5c,0xa5,0x9f,0x22,0x57,0xf9,0x3f,0x96,0x60,0x0d,0xf4,0xf6,0x3e,0x68,0x4b,0xf6,0x3a,0xe8,0xdf,0xfd,0x91,0x4e,0x46,0x29,0xc3,0xd5,0x09,0x5f,},{0x42,0x88,0x2a,0x81,0x1d,0xad,0x2d,0x85,0x18,0x85,0xe4,0xcb,0xe9,0x04,0x47,0x08,0xd9,0x1a,0x86,0xf1,0x5d,0xfa,0x1d,0x66,0xc3,0xeb,0x30,0x43,0x14,0x53,0x1f,0x30,0x15,0x20,0x8c,0x71,0x1b,0x9b,0xdb,0xc5,0xfb,0x23,0x39,0x51,0xe5,0x69,0xb5,0x9d,0x34,0xe4,0x15,0xee,0xc4,0xb3,0x7f,0xfd,0x37,0x4d,0x41,0x2c,0x9a,0x36,0x0d,0x0c,},"\x3b\x00\xe8\x08\xfc\xa4\xc1\x16\x51\xd8\x53\xd6\xb9\x0f\x95\x2c\xcf\x56\x47\xe1\x02\xd4\xee\x0a\xd7\xa5\xd1\x81\xd5\xb4\x25\x8c\x52\x3c\xd3\x9e\x3d\x98\x25\x29\x8d\x84\xc8\xcb\xa0\x9f\x43\xdb\xba\x11\x99\x88\x22\x2c\x76\x05\x9c\xaf\x17\xb4\xbf\x99\x31\xc4\x5e\x61\x74\x48\xae\xad\xe1\x51\x18\x14\x97\xb2\x45\x52\x36\x7e\x52\xbc\x45\xac\x79\x08\x88\x06\xd3\x36\x82\x07\xaa\xfe\xfd\x30\x57\x84\x5d\xce\x81\x9d\x5a\xaa\xa7\x7b\x21\x8e\x2a\xed\x3d\xa7\x6d\x40\xc1\xf0\x76\x99\xf8\x17\x2e\x4a\x5c\x80\x3f\x7a\x2a\xce\xb9\xa4\x7a\x89\x52\xe1\xb2\xf0\x53\xf2"}, -{{0x22,0x46,0xbf,0xb0,0x61,0x55,0x85,0x9e,0x10,0xa7,0x48,0xff,0x8f,0x59,0x19,0xad,0x5d,0x1d,0xaa,0xb7,0x56,0xf0,0x10,0x57,0xb7,0x90,0xd0,0x74,0x74,0x77,0x5f,0x4f,},{0xfa,0x63,0x49,0xb6,0x2d,0xc8,0xc6,0xa2,0xfe,0xee,0xf6,0xff,0xc3,0x3a,0xe0,0x85,0xc6,0x49,0x79,0x5c,0x1c,0x9d,0x98,0x98,0xe7,0x5c,0x13,0xae,0x16,0x25,0xdb,0x34,},{0x2b,0xe4,0x91,0x5a,0x35,0x2f,0x77,0x85,0x48,0x30,0x46,0xd8,0xae,0x96,0x25,0xb8,0xb6,0x32,0x57,0xaf,0x57,0xc0,0x73,0x69,0x12,0x56,0xee,0x07,0x6d,0x6e,0x1b,0x97,0x2a,0x10,0x1f,0x55,0x1c,0x70,0x5d,0x3f,0x96,0x15,0x7c,0x33,0xb5,0x6e,0xa0,0x49,0xbe,0x4a,0xf4,0xdc,0x56,0x1c,0xbe,0x3c,0x1e,0xc5,0x07,0x2d,0x7f,0x13,0x4e,0x07,},"\x63\xee\x1c\x7b\xbb\x15\xce\xbe\x1c\x22\x53\x2d\x48\x16\x82\x75\x4b\xda\xf5\x8b\x8b\xc9\x97\xae\x30\xa3\x4c\x9d\x23\xc3\x3f\x16\x90\xc3\x46\xab\x0a\x73\x65\xff\x62\x45\x74\x24\xb6\x10\x5f\x84\x21\xec\xa0\xce\x3c\x63\x0a\xcf\xeb\x9a\x1c\xc4\x16\x39\x0e\xdf\x49\x20\xe2\x2b\x23\x67\xe9\xfb\x5d\x2a\xb2\x5b\xee\x56\xda\x03\xea\x55\xe3\xf5\x78\x82\xd4\x8b\x89\x22\x93\x14\xd7\x34\xcb\x83\xc7\x9f\x4e\x17\xee\x64\xba\xe6\xf7\xad\xdb\xe9\xb5\x25\xfc\xd0\x3a\x91\x40\x9a\x2d\xde\x90\x77\x51\xdb\x8c\xc9\x7e\x08\xd0\xea\x89\xc4\xd1\x87\x18\xd2\x6d\x0b\x89\x7b\x64"}, -{{0xc0,0x88,0xa3,0xdd,0x2c,0xb8,0xbd,0x5d,0x68,0x4d,0xb8,0x53,0x8d,0xc2,0x24,0x73,0xb6,0xf0,0x14,0xf6,0x4f,0xe8,0x6a,0xf1,0x68,0xb4,0xbb,0x01,0xb9,0x0a,0x1d,0xd0,},{0xaa,0xd6,0x15,0xa9,0xc2,0x87,0x59,0xf0,0x3d,0x37,0x3a,0xbe,0x66,0x66,0x91,0xde,0xad,0x8b,0x84,0xf9,0xb8,0xb5,0x0a,0x67,0xf8,0xf0,0xaa,0x4a,0x70,0x15,0x80,0xd1,},{0x3b,0xb4,0x59,0xd1,0xac,0x57,0x5a,0x18,0x0c,0x17,0x28,0xd8,0xb8,0x92,0x49,0x70,0x49,0x2a,0x0c,0x8d,0x2a,0x37,0x8c,0x29,0xd1,0xd4,0x17,0x85,0xc8,0x37,0x9a,0x58,0xe2,0xba,0x36,0x06,0x78,0x5e,0x1c,0x5d,0xa2,0x9e,0x55,0x27,0x55,0x2b,0xc6,0xdc,0x89,0xa2,0xb6,0x9c,0x27,0xfe,0x51,0xed,0x25,0x3a,0x9f,0x3b,0x56,0x5b,0x27,0x00,},"\x74\x90\x6a\xe0\x5a\x5a\xf8\xe9\x96\x8b\x6f\xeb\x49\x85\x69\xd6\x34\x5a\x24\xf9\x71\x1b\xef\xb1\x36\xe6\xc3\xb5\xed\x49\x33\x9e\x59\xa7\x93\x8b\x4b\xa1\xa1\x18\xf1\x69\xb9\xac\xe0\xf7\x84\x2a\x26\xa6\x45\xf1\x4c\x0a\xd2\x2e\xbb\xcd\xa9\x3e\x67\xe4\xc3\x48\xef\xc3\xd9\xec\xbb\x14\x19\xe6\x26\x2d\x04\x36\xa5\x8e\xa8\x2c\x22\x02\x38\x90\x65\xcc\xf6\x7c\x4f\x55\x0e\x45\xb5\xf6\xa1\x2a\x6c\x01\x1b\x2e\x0a\x30\x10\x1d\x5c\x62\x32\x8b\xbf\x99\xc8\xc9\x55\x63\xa6\xe3\x3b\xdd\x9c\xce\x72\xb1\xf7\x20\x13\x9c\x2f\xd3\xe0\x49\x13\x14\x6a\xe5\xba\xc5\x28\x8e\x0e\x3e"}, -{{0x45,0x66,0x7d,0x1e,0x7b,0x59,0x10,0x97,0x9c,0x4a,0x32,0x83,0x17,0x96,0x83,0x71,0xc8,0x64,0xd5,0x64,0xa6,0x61,0xc5,0xcc,0xe5,0x57,0xc9,0xec,0xc6,0x1b,0xab,0x9e,},{0xed,0xcd,0xf5,0xe1,0xa1,0x70,0xe0,0x0c,0x8c,0x68,0x7e,0x7e,0x9c,0x18,0xf9,0x89,0x3b,0x5f,0xe4,0x95,0xcd,0x29,0x77,0xce,0xb7,0xf4,0x46,0xc0,0x14,0x9a,0xa9,0xd3,},{0x6d,0xe6,0x68,0xf1,0xca,0x6f,0x29,0x28,0x14,0x62,0x52,0x89,0xa0,0x80,0x80,0x20,0xc8,0x7c,0x89,0xac,0x94,0xf5,0xb0,0x50,0x8e,0x55,0x7b,0xdf,0x80,0x00,0xa5,0xca,0x80,0x8f,0x02,0x1c,0x96,0x79,0xb5,0x0e,0xe2,0xf3,0x20,0x06,0x4c,0x95,0xa4,0x64,0xa8,0x43,0x93,0x79,0x82,0x8c,0x3b,0x76,0xcf,0xa7,0x66,0x45,0x5e,0x12,0x8c,0x0b,},"\xcd\x66\xce\xc4\x76\xc8\x7c\x8d\xbf\x47\xec\x91\xda\xc4\x8f\xb5\xb4\x2d\xb1\x28\x2a\x57\x3e\x0a\x5c\xf0\xb9\x17\x68\x98\x66\x08\xe1\xd7\xeb\xd0\x5f\x52\x51\xbc\xf8\xb4\x7a\x17\x09\x32\x29\xac\xef\xbd\x44\xbe\xb2\x1c\x0c\x0c\x92\x8d\xd3\xcd\x3f\x89\x66\xec\xce\x69\x10\x33\x1c\x50\x8e\xa7\x6b\xaf\x90\x4d\x8c\x21\xf6\xc1\x7c\x2c\x58\xd0\x0a\xfd\x32\x59\xb8\xbf\x79\x4c\x14\x6b\x12\xb9\x95\xcd\xdd\x1c\x42\x89\xc5\xbe\x31\x68\xeb\xd6\x16\xb3\x84\xc2\x81\xce\x1b\x38\xa1\x0e\x18\x07\x80\x88\x53\xc6\x81\xa6\x40\xa0\x09\xb4\xd2\xac\xd7\x93\x4f\x8c\x6d\x07\x57\x81\x61"}, -{{0x24,0x89,0x74,0x28,0xae,0x65,0x46,0xd8,0x5b,0x31,0x90,0xeb,0xe3,0xf1,0xf7,0xbf,0x7c,0x71,0x25,0x28,0xac,0x85,0x1a,0x58,0x8b,0x07,0xd5,0xc8,0xf9,0x4e,0xec,0xd1,},{0x5f,0x34,0x8f,0xe3,0xea,0x5b,0x2c,0x02,0x3d,0x0a,0xf7,0xed,0xe6,0x0e,0x55,0xf9,0x1a,0xa5,0x51,0x99,0x69,0x9d,0xa1,0x5a,0x11,0xc3,0x79,0x1d,0x68,0xd7,0x10,0xbd,},{0x1b,0x5e,0x75,0xde,0xf4,0x9f,0x51,0xd6,0xb2,0xde,0x00,0x8c,0x71,0xfc,0x1a,0x90,0x9b,0xd4,0x2c,0xa8,0x13,0x29,0x8d,0xce,0x4e,0xee,0xf7,0x17,0x81,0x5d,0x7a,0x6c,0x07,0x8c,0x2f,0x3d,0x9a,0x3f,0xce,0x1a,0xb5,0xb3,0xad,0x8e,0xf8,0xd4,0x5c,0xdf,0x2e,0xb4,0x90,0x1c,0x32,0xee,0xa2,0xd5,0xe0,0x18,0xdc,0xf2,0x83,0x3c,0xad,0x0c,},"\x52\x01\xd9\x72\x5f\x1d\xff\xa1\x86\x3f\xa4\xd8\x4c\x30\x18\x61\x14\x1a\xcd\xfb\x64\xbe\x1f\xbf\xdd\x5b\x93\x86\xdb\x20\xef\x39\x40\x99\xee\xbc\xfd\xfe\xcc\x62\xc6\x26\x86\x07\xa8\x4d\x55\xc5\x5c\xd0\xef\xdc\x37\x2e\xcf\x30\x67\x34\x3e\x7b\x07\x31\xc2\x68\x54\x61\xe2\x4b\x95\x3f\x99\x94\x9e\x59\xba\x3e\x67\xed\x0f\x08\x48\x31\x37\x93\x96\x2a\x29\x2c\x45\x98\x14\xc5\xe2\x86\x90\xec\x1f\x45\x17\x1f\x1a\xba\xb8\x6f\xdd\x14\x56\x8b\x00\xca\xf4\x85\x81\x11\x5e\xe5\xea\x83\xb0\x00\x28\x2f\xbb\xf0\xc0\xb2\xa1\x11\x60\x39\xa3\x5c\xfa\x3f\x20\x14\x22\x20\x7a\x3d\x49\x48"}, -{{0x7b,0x04,0xac,0xa7,0xcf,0x92,0x62,0x16,0xcb,0x96,0x0a,0x38,0x90,0x78,0x63,0x39,0xd0,0xa6,0x15,0x96,0x76,0x80,0x19,0x01,0x23,0xfd,0xa3,0xb6,0x0c,0x6a,0xeb,0x11,},{0xcd,0xbc,0x3e,0x70,0xe4,0xe8,0xfd,0x13,0xd0,0xcc,0xe2,0x85,0x2a,0x3b,0x93,0x72,0xc3,0xa6,0x16,0x0c,0xd6,0xde,0xab,0xa9,0x0f,0x9b,0x30,0x22,0xf7,0x0c,0x91,0xf9,},{0x25,0xd2,0xd3,0x61,0x75,0x1d,0x52,0xb4,0xfe,0x66,0xea,0x18,0xe4,0xb9,0x86,0x6b,0xde,0x3d,0x12,0x1a,0x73,0x12,0xfd,0x9e,0x28,0xa1,0xe2,0x95,0xe0,0x87,0xe3,0x17,0x6c,0x94,0xc8,0x74,0xa2,0xe8,0x16,0x00,0xf2,0x4c,0x46,0x54,0xf4,0x3d,0x1b,0x67,0xd4,0x7b,0x64,0x82,0x26,0x48,0x59,0x0c,0xe5,0xce,0x44,0xf3,0xb5,0xdd,0xc5,0x02,},"\x1c\xb0\x96\x24\xb1\xf1\x4a\x02\x60\xc7\xf5\x6d\x8c\x60\xb5\xfe\x45\x83\x71\x14\x23\x25\x51\xef\x59\x66\x38\x6e\x0c\x2b\x44\x1b\x75\xcf\xdb\x8d\xf2\x18\x57\x85\xd2\x2c\xf5\x26\xfa\x9d\xf7\xfd\x45\xd9\xd8\x38\x81\xb6\x6c\x1f\xee\xe0\x91\x3e\x23\x81\x21\xee\xdb\xb7\xab\x50\x4d\xa0\xbe\xe8\x99\x80\x16\x68\x45\x35\x03\x19\x91\xf1\x1b\xfc\xd9\xb9\x56\x90\xaa\xd2\xd1\x9b\xd6\xa9\xde\x18\x44\xed\x13\x62\x30\x2d\xf4\x21\x72\x30\xb2\x5c\x05\x52\xce\x27\x75\x34\xc6\x50\xca\xe5\x26\x57\x7f\x25\xd8\xb1\xfe\x9f\x9f\xeb\xca\x2c\x81\x46\x70\xd4\x80\x5b\x21\xad\xef\x85\x2d\xaf\x94"}, -{{0xea,0x73,0xbf,0x64,0xa1,0xa9,0x78,0x77,0xc3,0xc3,0xe7,0xca,0x46,0x44,0xb7,0x1a,0xaa,0x66,0x31,0x4c,0x8f,0x1b,0x66,0xba,0xfa,0xeb,0xd5,0xed,0xfb,0x88,0x8b,0xcd,},{0xca,0xac,0x93,0x90,0x2e,0x57,0x64,0xad,0xe4,0x72,0x94,0xed,0xd5,0x1f,0xaa,0x14,0x62,0x09,0x40,0xc6,0x68,0xb5,0xc1,0xc3,0x92,0xa6,0x92,0x83,0x25,0xd4,0xc3,0xfd,},{0xbd,0x86,0xcb,0x9c,0x70,0xa0,0x55,0x27,0x9a,0x86,0xa9,0xe6,0x48,0x70,0x98,0x8b,0x8a,0x73,0x45,0xc3,0xcd,0x29,0x48,0xa0,0xfa,0xbc,0xfb,0x38,0xab,0xce,0x3c,0x42,0x0b,0x4d,0x55,0x21,0x61,0x8e,0x11,0xd2,0xde,0x82,0x7d,0x9d,0xe5,0x69,0xf6,0xbc,0x3b,0xe6,0x6a,0xad,0x40,0x63,0x6c,0xda,0xa6,0x47,0x60,0xde,0xd3,0xb7,0xc2,0x09,},"\x36\x2e\xec\x68\xb9\x12\x85\x27\x86\xbb\x4f\x9a\xff\xf9\xec\xf7\xcb\x28\xc9\xde\x6b\x18\x42\x2a\x8c\xa9\x40\xb0\xd7\xe6\xdc\xb8\x3a\xa4\x4b\xe0\xaf\xb5\xf1\x80\x6d\x43\xf0\xe3\x1d\x71\xf9\x22\xf8\x53\x61\x5a\x26\xe2\x87\xa2\x7f\x08\xa0\x4f\xbc\xe3\xd4\x5a\x0c\x6c\x31\x1d\x4b\x7c\xb1\x7e\x42\x5b\xbe\xb0\xa6\xb4\x10\xb5\xd6\xdb\xb7\xac\x11\xdf\x98\x50\xa1\x31\xa6\x91\xe3\xb6\x0b\x0b\x21\x4e\xbe\x04\x41\x06\xe9\x82\x43\x32\x87\x59\x52\x67\xb0\x31\xb5\xd4\xa0\x92\x62\xde\xd8\x93\x4f\xdf\xdf\x96\x4d\x86\x8e\xf9\xa2\xc8\x42\xf8\x04\xea\xfd\xde\xfc\xb7\x1d\x9f\x16\xa5\x9b\xf8"}, -{{0xb8,0x12,0x3c,0x11,0x6b,0x33,0xba,0xd0,0xdc,0xbc,0x2c,0x4d,0xc0,0x6a,0x3d,0x66,0x85,0x0d,0xab,0x36,0x0c,0xdb,0x5a,0x03,0x3c,0x14,0x89,0x5c,0x4e,0xe3,0x1b,0xfb,},{0xbd,0xca,0x15,0x1b,0xa3,0x2c,0x6b,0xb3,0x15,0x31,0xb0,0x5f,0xdf,0x86,0xc6,0xd7,0x8c,0x8c,0xd1,0x93,0x56,0x11,0xd5,0xff,0x11,0x1a,0x0f,0x00,0x63,0x5b,0x18,0x85,},{0x9c,0xf1,0x3e,0xba,0x3d,0xcc,0x37,0xb8,0xfc,0x70,0xcc,0xb2,0x32,0x74,0x36,0xb9,0xf0,0x88,0x55,0xe7,0x26,0xaa,0x7e,0xd8,0x2b,0xd5,0xcb,0x7d,0xf4,0x5f,0xdf,0x9e,0xc1,0xf9,0x6a,0xfa,0xd1,0x93,0xf4,0x75,0x72,0xd7,0x70,0x44,0x4b,0x65,0xb7,0x4a,0x37,0xcc,0x03,0x4f,0xc5,0x14,0xcb,0x3f,0x91,0xb2,0xd8,0xad,0xa5,0xb0,0x20,0x06,},"\x79\x70\xf6\x66\x66\x34\x54\x8c\x84\x8b\xb5\x23\x38\x81\x7b\x26\xa4\xd0\xca\x68\xdf\x3d\x28\xaf\xff\x20\x7c\x2d\x02\x80\x67\xa1\x8e\x4c\x95\x43\x02\x5f\x5b\x02\x28\xaa\x69\x1e\x50\x88\x51\x31\x51\xa9\x44\x94\xe1\x5d\x1f\x54\x21\x03\x28\xe0\xdf\x15\x9b\x35\x2c\x30\xaa\xa7\xa8\x44\xf1\x8a\x9f\x4c\x39\x5d\xcb\xb3\xfb\x9f\xcf\xbe\xd1\x10\x3e\x07\x06\xfb\xf9\xc3\x5f\xe2\x66\x68\x48\xfa\x35\xdc\x2c\xf5\x22\x7e\xbe\xe8\x9e\x7d\x3b\xcf\xae\x27\x21\xb2\x5f\xde\xc3\xd3\x17\x4e\xa7\xce\x26\x7a\x55\xdd\x61\xd5\x82\x01\xe9\x6b\xda\x30\x3c\xf4\x18\xed\xf6\xe3\x2f\xb9\x2f\x5d\xc1\xa0\xb1"}, -{{0xb1,0x8e,0x1d,0x00,0x45,0x99,0x5e,0xc3,0xd0,0x10,0xc3,0x87,0xcc,0xfe,0xb9,0x84,0xd7,0x83,0xaf,0x8f,0xbb,0x0f,0x40,0xfa,0x7d,0xb1,0x26,0xd8,0x89,0xf6,0xda,0xdd,},{0x77,0xf4,0x8b,0x59,0xca,0xed,0xa7,0x77,0x51,0xed,0x13,0x8b,0x0e,0xc6,0x67,0xff,0x50,0xf8,0x76,0x8c,0x25,0xd4,0x83,0x09,0xa8,0xf3,0x86,0xa2,0xba,0xd1,0x87,0xfb,},{0x6b,0xd7,0x10,0xa3,0x68,0xc1,0x24,0x99,0x23,0xfc,0x7a,0x16,0x10,0x74,0x74,0x03,0x04,0x0f,0x0c,0xc3,0x08,0x15,0xa0,0x0f,0x9f,0xf5,0x48,0xa8,0x96,0xbb,0xda,0x0b,0x4e,0xb2,0xca,0x19,0xeb,0xcf,0x91,0x7f,0x0f,0x34,0x20,0x0a,0x9e,0xdb,0xad,0x39,0x01,0xb6,0x4a,0xb0,0x9c,0xc5,0xef,0x7b,0x9b,0xcc,0x3c,0x40,0xc0,0xff,0x75,0x09,},"\x91\x6c\x7d\x1d\x26\x8f\xc0\xe7\x7c\x1b\xef\x23\x84\x32\x57\x3c\x39\xbe\x57\x7b\xbe\xa0\x99\x89\x36\xad\xd2\xb5\x0a\x65\x31\x71\xce\x18\xa5\x42\xb0\xb7\xf9\x6c\x16\x91\xa3\xbe\x60\x31\x52\x28\x94\xa8\x63\x41\x83\xed\xa3\x87\x98\xa0\xc5\xd5\xd7\x9f\xbd\x01\xdd\x04\xa8\x64\x6d\x71\x87\x3b\x77\xb2\x21\x99\x8a\x81\x92\x2d\x81\x05\xf8\x92\x31\x63\x69\xd5\x22\x4c\x99\x83\x37\x2d\x23\x13\xc6\xb1\xf4\x55\x6e\xa2\x6b\xa4\x9d\x46\xe8\xb5\x61\xe0\xfc\x76\x63\x3a\xc9\x76\x6e\x68\xe2\x1f\xba\x7e\xdc\xa9\x3c\x4c\x74\x60\x37\x6d\x7f\x3a\xc2\x2f\xf3\x72\xc1\x8f\x61\x3f\x2a\xe2\xe8\x56\xaf\x40"}, -{{0x93,0x64,0x9c,0x63,0x91,0x0b,0x35,0x71,0x8e,0x48,0xc5,0x90,0xd2,0x61,0xc4,0x8e,0x4e,0xf8,0x33,0x66,0x13,0xf6,0xaa,0x07,0x7b,0x46,0x26,0x76,0xb3,0xba,0x88,0x29,},{0x06,0xa6,0x85,0x89,0x8b,0x85,0x52,0x12,0xeb,0xc2,0x89,0x91,0x5d,0x10,0x5a,0x43,0x20,0xd6,0x20,0xd8,0x57,0x71,0xb8,0xc6,0xb1,0x5b,0xf1,0x0a,0x1b,0xe6,0xe9,0xb8,},{0x62,0x74,0xf2,0xd4,0xf4,0x31,0xd5,0xaf,0xfe,0xfa,0x35,0xe7,0xcf,0x58,0x4a,0x59,0x90,0x17,0x19,0x3d,0xa9,0x90,0x94,0xca,0x90,0x8b,0x75,0xac,0xb6,0x08,0xd1,0xbf,0x98,0x18,0x57,0xbe,0x93,0xa7,0xda,0xfb,0x0f,0xad,0xb3,0xff,0x09,0x06,0xf4,0x8a,0x5e,0xe9,0x50,0x45,0x6f,0x78,0x2c,0x2d,0x60,0x5b,0x14,0x09,0x5b,0xa0,0xff,0x0f,},"\x2c\xd1\xa9\x51\x05\x6c\x9e\xba\xe1\x39\x9b\x6b\xd2\xd8\x2c\x0a\xe2\x77\x85\x62\x90\xd0\x69\x20\xac\x56\xca\xc8\xfb\x42\x43\x51\x01\xc7\x2a\xa9\xc0\x8d\xd2\xd1\x24\x26\x32\x55\x62\xc2\xf0\xa4\x9c\xd8\x21\xb1\x1b\x93\x9a\xaf\xa5\x93\xb4\x09\x5c\x02\x1b\xcb\x48\x27\xb1\x07\xb9\x66\x4d\x68\x28\x28\x88\xbc\x4a\x44\xaf\x3e\x3b\xdc\x86\x1b\xe6\xaf\x30\x90\x44\xc3\xda\xab\x57\xb7\x70\x23\xdc\x90\x2d\x47\xeb\xc3\x26\xf9\xbd\xd0\x2d\xbc\x02\xcd\x54\x0f\xf8\x1b\x2d\xdf\x7c\xf6\x79\xa4\x11\x93\xdf\xe5\xf8\xc8\xca\x1a\xae\xfc\x41\xef\x74\x02\x80\xd9\x82\x3e\x30\xa3\x54\x71\x7c\x84\x31\xf5\xd8"}, -{{0x1c,0x15,0xcb,0xeb,0x89,0x36,0x2d,0x69,0x47,0x6a,0x2a,0xa4,0xa5,0xf3,0xef,0x20,0x89,0xcf,0x87,0x28,0x63,0x49,0xe0,0xdf,0xe0,0xe7,0x2d,0x9e,0x3e,0x5a,0x66,0xc7,},{0x13,0xa8,0x82,0xa1,0x06,0x41,0x82,0x58,0x2c,0x21,0x18,0x47,0xe1,0x9b,0x4d,0xac,0x59,0x72,0x2c,0x9f,0xfd,0x34,0x82,0x6d,0x96,0xf3,0x31,0x13,0x40,0x0f,0xac,0x7a,},{0x59,0x98,0xb2,0x80,0x8a,0xdf,0xde,0xea,0xeb,0xe2,0xc3,0xea,0xc0,0x26,0xd3,0xf8,0x25,0xf9,0xc7,0xf2,0xaf,0x97,0xca,0x32,0x4f,0xbd,0x57,0xaa,0xc1,0xbe,0xdf,0xf7,0x8a,0x8e,0xe6,0x21,0xd0,0x37,0xee,0x3a,0xd2,0xa7,0x12,0xe9,0xa0,0x09,0xc5,0x8e,0xa3,0xe6,0xf2,0xa8,0x28,0xf7,0x4b,0x86,0xda,0x27,0x5a,0x44,0xa4,0xb1,0xe5,0x0b,},"\x09\x1c\x9b\x9b\x11\x6a\xe8\x3d\x23\xd0\x1a\x62\x95\x21\x17\x85\xd4\x46\xb6\x22\x8d\xd6\x87\xdd\xf7\x9b\xd0\xd5\xa4\xda\xa8\xc7\x9d\x2c\xbf\xc3\x73\x65\xf1\xf2\x85\xe3\x61\x73\x81\x23\xe3\x4e\x2b\xcb\xfc\x66\x4c\xe1\x25\x3a\x11\xd9\xe4\xa7\x98\x2e\x58\xcf\x94\x68\xe1\x01\x7e\xa1\x4d\x2c\xc6\xd0\x86\x5d\x40\xfd\xe8\xcb\x56\x02\x41\xe9\x6a\xc1\x61\x7c\x79\x1f\x0c\xa7\xc6\x41\x0c\xad\xf3\x28\x61\x1b\x18\xae\xf3\x33\xd8\x35\x0a\xc4\x97\xf0\xa4\xae\x2d\x03\xfd\xf0\xe2\x3e\x42\x6d\x34\xf4\x51\x47\x80\xd1\x47\x4e\x11\x35\x83\x54\x1f\x3c\x04\x36\x72\x05\x71\x72\x61\x8c\xb2\x05\x9e\xaa\xed\x56"}, -{{0x11,0x24,0x1f,0xfd,0xf3,0x4a,0xe8,0xab,0x87,0x54,0x75,0xe9,0x4c,0x6c,0xc3,0x29,0x1f,0x0b,0x88,0x20,0xdc,0x85,0xe2,0x0f,0x32,0xfc,0x53,0xb2,0x4a,0xe6,0x89,0x78,},{0x09,0xc0,0x45,0xe4,0xbd,0x51,0x37,0x31,0x4c,0x0e,0xc1,0xd0,0x31,0xfa,0xf9,0x14,0x91,0x0c,0x45,0xa4,0x67,0x6f,0x5a,0x3c,0xd8,0xf5,0x81,0xbc,0xcc,0xb0,0x3c,0x97,},{0x72,0xce,0x9f,0x91,0xbe,0x2e,0x66,0xcf,0xc9,0x0f,0x95,0x25,0x95,0x94,0x6f,0xfc,0x90,0xbf,0xce,0x53,0x08,0x7d,0x49,0xe5,0xdd,0x7c,0x08,0x7f,0x3f,0xaa,0x8f,0x18,0xf2,0x35,0x6d,0xe9,0x71,0xe4,0x42,0x9d,0x98,0x5a,0x99,0x19,0x4b,0x4f,0x92,0xce,0xd3,0xef,0x47,0xcd,0x71,0x14,0x37,0x9e,0x0b,0x32,0x67,0xa9,0xf8,0xb1,0xe7,0x06,},"\x3b\x89\xde\xcc\xb7\x02\x3e\x4b\x2b\x7a\xff\x2c\x39\x51\x87\x0a\xf4\x13\xa9\xb0\x4d\xd8\x6a\xc7\x8b\x7c\x8f\xd8\x87\x49\x2d\x8d\xde\x49\xd8\xfd\xa1\x49\xed\xd5\x47\x81\xae\x2b\x50\x80\x30\xd1\x44\x16\xa9\xa3\x8b\xed\x2b\x9a\xeb\xbb\xb2\x02\x50\xb3\xc9\x31\xac\xd4\xe3\x2f\xbe\xee\xc5\xa2\x65\x01\xbe\xab\x72\x68\xd1\x44\xfc\xe8\x95\x1a\x10\x1c\x4b\x51\x78\x16\x6f\xbb\x59\x27\xb1\xdf\xb1\xe1\xce\x90\xd1\xd1\x23\x06\x8e\x3f\x47\x2c\x88\x8f\xdb\x01\xfd\xf7\x0e\x7f\x8d\xe9\xb0\xad\xb2\x84\xb7\x11\x9f\x55\x35\x43\x16\xf8\x4e\xd0\x90\x03\x0f\x9c\x26\x62\x06\x1c\xa4\x84\x47\xcc\x0a\xef\x96\x41\x26"}, -{{0x3b,0xdb,0x16,0x24,0x65,0xea,0xce,0xff,0x98,0xd6,0x9c,0x86,0xf7,0x00,0x39,0xc5,0x17,0xd1,0x68,0xae,0xfe,0x6b,0xb1,0x01,0xb4,0xf7,0x69,0xa8,0x6b,0x17,0xc9,0x72,},{0xd7,0x6c,0xb7,0xbe,0x74,0x32,0x82,0x89,0xfd,0x1c,0x64,0xbe,0x74,0x7c,0xca,0x5b,0xb3,0x02,0x95,0xdf,0xac,0xcd,0x0f,0x2e,0x43,0xf5,0x17,0x03,0xfd,0x5d,0x36,0x83,},{0x6f,0x13,0x62,0xa4,0x02,0x06,0x37,0x91,0xf9,0x50,0x98,0x4f,0x54,0x49,0x28,0xe6,0x16,0xa4,0xef,0x79,0xbb,0xeb,0x68,0x54,0xe9,0x61,0x5a,0xab,0x9c,0xdb,0xae,0xc4,0x83,0xfb,0x9a,0x04,0xbf,0x22,0xde,0x5d,0x97,0xa1,0x5b,0xda,0x2d,0x39,0x04,0x83,0xc7,0xf6,0x1d,0xbe,0xe0,0x7b,0xb5,0x14,0x1f,0xc1,0x73,0xb1,0xaa,0x47,0x65,0x0d,},"\xfb\xf3\x68\xfe\xae\xba\x87\x91\x8b\x1b\x8c\x7b\x8a\x26\x83\x2b\xe6\xe7\xfc\x1c\xbd\xb8\x90\x25\x19\x28\x1a\x06\x54\xec\x73\xde\x0b\xb0\x71\x01\xa9\xd6\x03\xf7\x45\xd4\xec\x23\x57\xae\xe9\x87\x0c\xb1\x9a\x56\xcb\x44\xfb\xd9\xc9\x1f\xc3\x47\x52\x61\x2f\xbd\x83\xd6\xfc\x1a\x16\xbf\x8a\x85\xa2\x15\xd0\x14\x8e\x4a\xf3\x7d\x29\x84\x67\xe5\xcc\x48\x6b\x13\x13\x52\xce\x09\x21\x82\xce\x82\x84\x15\x9a\x38\x12\xb3\x0b\xac\xbf\xf5\x95\x86\x38\x11\xbf\x9a\x30\xa9\xda\x49\x45\x65\xc3\xac\x18\x14\x43\x00\x18\xea\x0e\xee\xd3\x9c\xdb\xca\x27\xf9\x31\x40\xe4\x69\x49\xdb\x57\x0b\xfa\x2e\xd4\xf4\x07\x3f\x88\x33"}, -{{0xd5,0xef,0xe5,0x1d,0x5c,0xd8,0xe1,0x08,0xbd,0x92,0x2f,0xc0,0xea,0x12,0x61,0x90,0xa9,0x46,0x28,0xff,0xa5,0x3c,0x43,0x3a,0x51,0x80,0x22,0x79,0x2d,0xdc,0x78,0xef,},{0x42,0x6b,0x01,0xcc,0x61,0xff,0x5e,0x0e,0x72,0x4d,0xa1,0xd3,0xb2,0x97,0xf5,0x32,0x5c,0x18,0xc6,0x2f,0x64,0xd5,0xeb,0x48,0xd4,0xa5,0x21,0x6a,0x8e,0x9a,0x40,0x73,},{0x23,0x06,0xf5,0x8f,0xcd,0x4c,0xff,0x22,0x22,0xd8,0x1b,0x05,0xa4,0x75,0x53,0x2b,0x8b,0x19,0xdc,0x67,0xe6,0xd7,0x8d,0xdb,0x42,0x05,0xa3,0xb7,0x62,0x1c,0xc5,0xae,0xf0,0xb3,0x93,0xd5,0xd2,0x4d,0xd9,0x6c,0x88,0xcc,0xbc,0x53,0xa3,0x20,0x8d,0xa3,0x23,0xbe,0x45,0x87,0xd5,0xec,0x06,0x7c,0x82,0x0f,0x07,0x23,0xaa,0x44,0xe9,0x0e,},"\x9d\x17\xbc\xfe\x2d\xfc\x74\x2f\x41\x1c\xb5\x3a\x94\xf3\x59\xc0\x01\xab\xf0\x96\xc7\x41\xf3\x4a\xf4\x86\x79\xf2\x81\xe7\xce\x6b\xbd\x9e\x87\x70\x9f\xc0\x72\x8a\x56\x3d\xb2\xb9\xcf\x8e\xa4\xfb\xdc\xc3\x44\xc1\x84\x8e\x65\x3c\xe9\x70\xc6\xce\x29\xde\x2c\xcd\x52\x03\x00\x64\x9a\xdc\xdd\xfc\x75\x39\x71\xf8\x46\xaa\xc1\xba\x42\xae\x45\x28\x95\x2d\x94\x98\x0a\xa7\xc6\xcf\xa2\x14\x29\x07\x64\x7f\x89\x4a\xe9\x74\xa7\x4d\x59\x03\x5a\x73\xef\x56\xa1\x0b\x66\x12\x62\x48\x09\x52\x01\x90\xac\xe6\x61\xc3\xa4\x70\x95\xe0\x32\x2e\xfd\x78\x1d\x50\xd1\x16\x35\x98\xf2\xda\x32\xf3\x1b\xc9\xc4\xf9\x13\xd1\xb1\x48\x61"}, -{{0x18,0xaf,0x89,0x02,0x5e,0xbf,0xa7,0x6b,0xd5,0x57,0xcf,0xb2,0xdf,0xf1,0x48,0x24,0x52,0x14,0x64,0x1f,0xd5,0xbd,0xa1,0x59,0xf7,0x3d,0xa0,0x4b,0x08,0xe8,0x7c,0x88,},{0x0c,0x58,0x44,0x59,0xb9,0xeb,0xcc,0xca,0xd5,0x87,0xb2,0x72,0x16,0x0b,0xc6,0x0b,0x27,0xf4,0xf7,0x72,0xb4,0x32,0x1d,0xe7,0x72,0x3a,0xfe,0xf5,0x77,0xed,0xc7,0xb4,},{0x26,0xbb,0x08,0x82,0x29,0x7c,0x2c,0x08,0xa7,0x52,0xd3,0x98,0x11,0x45,0xdc,0xde,0x55,0x89,0x3a,0x11,0xdf,0x77,0xf8,0xaa,0x4c,0x19,0xd0,0xb9,0xed,0x6e,0x52,0x20,0xed,0x12,0xe9,0xfa,0xc3,0xaf,0x13,0xd0,0xf0,0xc7,0x15,0x68,0xf4,0xa5,0x47,0xd3,0x01,0x14,0xa6,0x59,0x9a,0x23,0x68,0x06,0xc4,0xbe,0xee,0x67,0x65,0x28,0x44,0x08,},"\xe8\x2f\x46\x65\x2a\xb9\x14\xaf\x53\x5d\x8f\xb7\x20\xb5\x57\xac\x95\x01\x8d\x9f\x2a\x3f\xcc\xe8\x57\x71\xbb\x40\xab\x14\xcb\x9a\x98\x6e\x09\x6f\x3a\xfe\x5b\xee\x82\x9d\xfd\x8b\x97\x33\x5c\x53\x6a\xc9\x71\xa2\x16\x55\xaf\x16\xa2\xf8\xfd\xba\x18\x3a\x4e\x18\x56\x4c\x21\x49\x29\x56\x53\x7a\x41\x9a\xbb\xbb\xb0\x2a\x4b\xbd\xc0\x14\x81\xf5\xc6\xe6\x58\xec\xf3\xc3\x4f\x01\x1a\xd8\x46\xf5\xed\xcd\x49\x39\x19\x5d\xf8\x5e\x41\x30\x3f\xb9\xa8\x8f\xdf\xbd\x70\x43\x96\xf7\x55\x9a\x32\x73\x18\xb9\x52\xb3\xe6\x0c\xe8\xdd\xde\x56\x37\x85\x79\x23\x2f\xaf\x95\x0c\x78\xe7\xf0\xb1\x7c\x3b\x8d\xec\xe3\x6b\x78\x8a\x84\x73"}, -{{0x0c,0x93,0xd9,0x98,0x15,0xff,0xf8,0xfe,0x22,0xb9,0xe4,0x5a,0xa0,0x2b,0x3e,0x64,0x45,0xce,0x1d,0x6b,0xf5,0xa6,0x5d,0xce,0x3d,0xa1,0x07,0xaa,0x10,0x55,0x94,0x0e,},{0x4d,0x27,0xa4,0x7b,0x0f,0xc8,0x08,0x00,0xd8,0x4d,0x24,0x4e,0xeb,0xb1,0xde,0xb4,0x43,0x6d,0x97,0x63,0x3a,0x83,0xe6,0x71,0x25,0xad,0x52,0xea,0x01,0x68,0x50,0x57,},{0x7d,0xc4,0x46,0x7a,0xbc,0xf6,0x43,0x1a,0xdb,0x7c,0xcf,0xe8,0x68,0xea,0xc8,0xcd,0x8a,0x61,0x5a,0x0f,0xf6,0x5f,0x6a,0x9e,0x33,0x83,0x75,0xb1,0xaa,0xe3,0xc4,0x9a,0x12,0x6c,0x9e,0xba,0x79,0x42,0x6d,0x16,0x41,0xc6,0xb9,0x7c,0x3e,0x92,0xc1,0x94,0xe5,0xee,0x44,0x31,0xef,0xa2,0x43,0x9f,0xd4,0x50,0xf2,0xcd,0x01,0x8c,0x87,0x00,},"\x11\xe8\x77\xde\x58\xc1\x34\xea\xf4\xc9\xf1\xb5\x3c\x3d\xc4\x51\xd3\xc0\x55\xf1\x6b\x09\x62\x27\x25\xb2\x79\x76\x85\x12\xfe\x10\xa7\xad\xb0\x76\x5b\x68\x9e\xc2\x1d\x5b\x6e\xfa\xa1\x9f\x1b\x9d\x36\x25\x4d\xf0\xa9\x36\x7f\x44\x1b\x26\xbd\xb9\x0b\x28\xcb\xc4\x03\xe5\x07\x40\x82\xfa\x1f\xed\x58\xe1\x40\xda\xc9\x7a\xea\xf4\x83\xe2\xc1\x3f\x3c\xc5\x60\xab\xff\xab\xa0\x5b\x76\x3f\xee\xdb\x51\xe6\x06\x98\x15\x1c\xf5\x6e\xfd\xf1\xd3\x7d\x6c\xe0\x56\x44\x86\x21\x0f\x05\x2e\x93\x7f\x2e\xa2\x6f\x63\xef\xa5\xd2\x47\xff\x18\x83\x29\xbb\x1a\xa8\x3c\xe3\xf4\xf3\x5a\x3d\x7d\xec\x14\x59\x9e\x5f\xeb\x7b\x6d\x5f\xe4\x29\x6a"}, -{{0x98,0x9e,0x99,0x94,0x56,0x35,0x19,0x2c,0x02,0x3c,0xc5,0x18,0x6f,0xc2,0x5b,0xba,0xef,0x47,0x24,0x07,0x75,0xd1,0x5a,0x56,0x19,0x5d,0x88,0xcd,0x07,0xc3,0x74,0x8e,},{0xca,0x0b,0xea,0xfd,0xf7,0x31,0xd8,0x93,0x01,0xf7,0x72,0x3c,0x5b,0xb7,0xe5,0xa1,0xc3,0xff,0x3e,0xab,0x27,0xc9,0x7d,0x71,0x1b,0xcd,0x76,0xe4,0x20,0x54,0xbe,0xe4,},{0xae,0xf7,0x56,0xbf,0xb8,0xa7,0x26,0x6e,0x17,0xd1,0x5f,0x3f,0x11,0xee,0x50,0xed,0x25,0xbe,0x42,0x0e,0x95,0xa0,0x74,0x22,0x71,0xeb,0xd1,0x22,0x94,0xe2,0xcb,0x96,0xea,0xd0,0x83,0xb8,0xff,0x0b,0x82,0x9d,0x2e,0xde,0xb1,0x4d,0xa8,0x6e,0x40,0x2e,0xf2,0x5e,0x6d,0x4a,0x5a,0x79,0x58,0xc1,0x84,0xed,0x10,0xc1,0x76,0xcb,0x57,0x0b,},"\xc4\x84\x14\xf5\xc7\x57\xd0\x3c\x52\x3e\xf3\xf3\xb8\x51\x07\x71\xb0\xff\x3b\x4b\x97\xde\x27\x96\x25\xd3\x49\xec\x18\x5a\x29\x92\x7a\x66\xb9\x59\x3b\xa1\x93\x38\xc2\xf5\xe4\x13\x1f\x1a\xc0\x7e\xa4\x6d\x2c\x1b\x6e\x4a\xb5\x22\x92\x80\xb2\xe2\xbb\x9d\x14\x0d\x1e\xf7\xaf\x7b\x16\x92\xbf\x2d\x09\x7b\x80\xf8\x11\xad\xcf\xa9\x5d\x5c\xbf\x9e\xee\x92\xa1\x64\x1c\x55\x2b\x4b\xe4\xa0\xd7\x34\xf0\xaf\xd4\x70\xb9\xd7\xf4\xe4\x57\x78\x95\x1e\x21\xfc\x53\x4f\x20\x0a\x12\x8b\x96\xad\xb8\x37\x3f\x10\xce\xce\xc2\xda\xc2\x99\x6a\x06\x2f\xb3\xc2\x94\x31\x59\x65\xa9\xd5\xd7\xb0\x77\xc4\xb0\x13\xc6\x4a\x38\x42\x97\x69\xd2\x3e\xab"}, -{{0x6b,0xdb,0xbe,0x06,0xd9,0xf4,0x21,0x9e,0xea,0x64,0x03,0xa3,0x57,0xb2,0x5e,0x56,0x19,0x92,0xfa,0xe0,0xf0,0xf6,0x14,0x56,0x1d,0xd8,0x6d,0x23,0xde,0x41,0x5a,0x43,},{0xed,0x52,0xdd,0x1c,0xce,0x32,0xd9,0xb4,0x85,0xe0,0x94,0x07,0x46,0x42,0x1d,0x36,0xb9,0xfd,0xe6,0xcd,0xf0,0x21,0x15,0x45,0xb6,0x34,0x04,0x4d,0x4b,0x3c,0xb8,0xf1,},{0x95,0x02,0x06,0x60,0x5b,0x0f,0x41,0x7c,0x90,0x84,0x3e,0x2c,0x8d,0x8e,0x66,0xc8,0x28,0xbb,0x10,0xb9,0x9b,0x36,0xee,0xee,0xe8,0xca,0xf2,0xe0,0xe5,0x48,0x4d,0x93,0xfe,0x02,0xbf,0x53,0x34,0x05,0xf4,0xbb,0x74,0xa5,0x0e,0x55,0x85,0xfa,0x0d,0xae,0xf4,0x82,0x1f,0x03,0x01,0xd0,0x1b,0x46,0x32,0x1b,0xaa,0x31,0xe1,0xf0,0x8d,0x03,},"\x58\x2a\xda\x13\xd6\x92\x93\xe4\x9b\xbd\x46\x10\x32\xdf\xea\x1c\xa2\x02\x5b\x52\xe0\x13\xa3\x3a\x03\x87\xfc\xfc\x5f\x7c\x0b\x8e\xc9\x55\x98\x26\x07\xfc\x90\x1e\x1b\x7f\x63\x6a\x9d\x37\x1e\x1f\x91\xfe\x47\x6b\xdd\x44\x85\x6e\x27\x5d\x67\xef\xa1\x42\x38\x16\x43\x54\xc2\x31\x12\x4c\x84\xde\x8f\x5b\x89\xd5\xa5\x8e\xa6\x74\x4b\x4d\x3b\x3d\x79\x06\x90\x52\x33\xcc\xe6\x94\xa6\x4d\x69\x6f\x5a\x70\x24\xfc\x90\x33\xb1\xce\x39\x08\x99\xa3\xb4\x41\xa4\x8e\x53\xc7\xc9\xb3\x0b\xa1\x2e\x7d\x61\xf3\x5f\x15\xe6\x58\xc7\xcc\x44\x07\xe2\xf6\x89\xea\x8a\x55\xd0\x1b\xf5\xdb\xac\xb1\x19\x54\x75\x4f\x92\x0f\x09\xdb\xd4\x84\x09\xbb\xb5"}, -{{0xd7,0x61,0xc8,0xc5,0xa9,0x60,0x1b,0x91,0x45,0xb7,0xd0,0x51,0x24,0x9b,0x00,0x41,0x07,0xe4,0x52,0xe5,0x63,0x10,0x0c,0x6c,0x78,0x80,0x38,0xc9,0xee,0x8a,0xda,0xd7,},{0xe6,0x48,0x87,0x75,0xd6,0x40,0x7e,0xfc,0x7b,0x2b,0xca,0x89,0x0a,0x7f,0xc6,0x22,0x66,0xfc,0x54,0xcd,0xac,0x89,0x33,0x43,0xb4,0xf5,0x9a,0x19,0x6d,0x94,0x88,0x98,},{0x7a,0xb7,0x8b,0x64,0xe6,0xdb,0x35,0x9a,0x2d,0xc8,0x30,0x2e,0x10,0x92,0xed,0x66,0xfa,0x73,0x6b,0x53,0x62,0x53,0xa1,0xcd,0x90,0xfd,0xb8,0xc1,0x0e,0xfd,0x78,0x30,0x02,0x25,0xe1,0x91,0x96,0x35,0x99,0xba,0x54,0x9c,0xc8,0x59,0x20,0x9d,0xf0,0xff,0x61,0xcd,0x06,0x9b,0x03,0xd2,0x54,0xe6,0xe7,0xd7,0x6c,0x79,0x84,0x40,0xf9,0x07,},"\x84\xea\xd5\xea\xbd\x2f\xd4\xb7\xc7\x9a\x9a\x92\x8a\xb8\xee\x0a\x16\xa5\xfd\x66\x7a\x05\x7f\x8a\x25\x46\x63\xd5\x6d\xaa\xe1\x56\xd1\xa4\x9a\xff\xb2\x99\x61\x37\xb9\xd8\xb3\x40\xe6\x35\x73\x2f\x9d\x2b\x4c\x60\x21\x84\x42\x54\x1e\x72\xd2\xb0\x0e\x1e\xe7\xa7\x3c\x3f\x67\xca\xa4\x99\xfa\x9d\x07\x0b\x57\xd0\x76\xdc\xde\x96\xb0\x76\x47\x23\xc3\xc6\x59\xc7\xa0\x0c\x1b\x78\xb1\x5c\xcc\x22\x23\x89\x0b\x51\x06\x7f\xc8\x1e\x23\xe9\x45\x8a\xb0\x68\x3b\xa6\x26\xa5\x3d\x0c\x37\x93\xa5\x8a\x98\x57\xbb\x44\xb3\xbd\x85\xbb\x6c\xe5\x3a\x85\x69\x4e\x7f\x53\xcc\x1b\xd4\x6d\x50\xed\xa3\x7d\x81\xf5\x38\x1b\x51\x3d\x1f\x38\x33\x9d\x29\x1b"}, -{{0xc5,0xe0,0xc7,0xa7,0xbb,0x8b,0x7c,0xa0,0x7b,0xf0,0xa0,0x5e,0xa6,0x7e,0xff,0x6d,0xee,0xbf,0xe3,0x71,0x4e,0xe3,0xe1,0xa2,0x27,0xf4,0xdc,0x8e,0x24,0x2a,0x2f,0xa0,},{0x51,0x35,0xef,0xcd,0x90,0x52,0xbe,0xc5,0x7a,0x44,0x31,0xca,0xab,0xe8,0x26,0x80,0xee,0xc0,0xa3,0x3a,0xfd,0x59,0xb3,0x02,0x03,0xb2,0x80,0xba,0x12,0xbe,0x48,0x5c,},{0x2e,0x7f,0xde,0xb3,0x48,0x4d,0x0a,0x5e,0x8d,0xce,0x94,0x44,0x89,0x79,0x49,0x6b,0x06,0x42,0xca,0xbc,0x37,0x33,0xa5,0x1f,0x8c,0x3c,0x5c,0x51,0xc1,0x9a,0xe3,0x19,0x01,0x8d,0xa9,0x10,0x91,0xc2,0x38,0x5f,0x2f,0x4e,0x9a,0x59,0xed,0xbc,0xa2,0xab,0xd0,0xd0,0x85,0xee,0x40,0xd3,0xf0,0xd4,0x20,0x61,0xa5,0xa9,0x83,0x2a,0x37,0x0c,},"\x37\x70\xa6\x78\x66\x52\xc4\xb7\x8a\x04\x3e\xdc\xe0\x7f\x3e\x20\x4d\x81\x99\x7c\x42\xaf\xc2\x23\x31\xf7\x5a\x54\x94\xa8\x26\xd7\xcb\x69\xab\x43\x14\xa4\x73\x72\x10\x58\xa1\x83\x99\x81\xd5\xb7\x02\x2d\x0c\xd8\x67\x03\x77\xda\xf3\x32\x04\x76\xd2\x5b\x9f\x55\x95\x61\xd6\x6e\xe0\xa7\x09\xfe\x17\x36\x1e\x2a\x52\x89\x8f\x57\x53\xc4\xfb\x43\xbd\x0c\x98\xb3\x68\xf5\x12\xad\xc0\x9c\xd9\x27\xc6\x62\x26\x76\x92\x6d\x8c\x2d\x91\xa1\x4a\xca\x32\xf2\x26\xf7\x00\x36\xc1\xc8\x58\xbc\xff\xc2\xb5\x9f\x54\xc1\xc3\x7b\xf8\x1e\xb5\x2e\xcb\x3f\x00\xda\x60\x2c\x94\x36\x1b\x52\xa5\xaf\xdd\xbf\xd7\xe0\x50\x36\xe3\x77\x50\x30\x50\x33\x3b\xe5\x12"}, -{{0x11,0xbb,0x47,0x48,0xd2,0x54,0x7e,0x61,0x96,0xbe,0x82,0x3c,0x9b,0xe7,0xaa,0x18,0x15,0x0c,0x20,0x4b,0x12,0xca,0x8d,0x73,0xc1,0xbd,0x46,0xb1,0x1a,0x54,0xb4,0x75,},{0xef,0xeb,0x42,0xda,0x28,0xd7,0x64,0x96,0x64,0x03,0xdd,0x30,0x0d,0x9f,0x94,0x51,0xb2,0x58,0xab,0x1c,0x80,0xdf,0x06,0xfe,0x59,0x43,0x15,0x3f,0x53,0x01,0xcc,0xcb,},{0x44,0xc5,0x8d,0xa4,0x9d,0x23,0x65,0xd2,0x70,0x29,0xd1,0xee,0xbb,0x3b,0xeb,0xf7,0xc0,0x32,0xd8,0x58,0xaa,0x07,0xe0,0x75,0x6b,0x1c,0x26,0xa5,0x41,0x2d,0x22,0x69,0x11,0x76,0x03,0x13,0x41,0xad,0x37,0xd7,0xbb,0x78,0x43,0x28,0x9e,0xb3,0x9d,0xb4,0x91,0x58,0x4c,0x1b,0x2a,0x1d,0xa2,0xe4,0xa2,0x64,0x9c,0x22,0x93,0x82,0x66,0x06,},"\xf4\xb7\x65\xb2\x58\xba\x35\xb4\x27\x52\x5c\x7f\x10\xa4\x6f\x0b\xcc\xd3\x57\xec\x1a\xd5\x2a\x5b\x13\x94\x17\xa9\xd3\x89\x4c\x51\x2d\x89\xeb\x88\xe6\x81\xb1\xf3\x0a\xac\x4c\x11\x5c\xcf\x36\x54\x5e\x83\xf3\x78\x34\xc8\x2e\x83\x00\xcc\x1e\xb2\x89\xaf\x43\x75\x96\x8c\x29\xc0\xff\xef\xb4\x0e\x15\x6c\x20\xc0\x43\x26\x69\xac\x8d\xc0\xa8\x3c\x13\xb1\xe8\x55\xa8\x4a\xd0\x13\x3c\x40\xc8\x2c\x87\xee\x1e\x7d\xd4\x08\x4d\x74\x1c\x80\xde\x8a\x7a\x9f\x77\x59\xe8\x43\xa5\x62\x09\x9c\x4d\x7d\xf8\x75\x35\x20\x39\xff\x4d\x38\x24\x65\x13\x86\xc9\x77\x59\xff\x7d\xba\x52\x06\x4e\x6d\x31\x12\xe0\x80\x81\x9a\xee\x8c\xe7\x23\xa1\xa2\xaa\x46\x4d\x8a"}, -{{0x74,0x52,0xa0,0x01,0x56,0xd7,0x94,0xed,0xeb,0xff,0x4a,0xdb,0x1f,0x7a,0x7e,0xec,0x26,0x21,0x7f,0xef,0x67,0xc3,0xd2,0x68,0x35,0x2b,0x2b,0x54,0x60,0xa7,0xdc,0x25,},{0x5f,0x4d,0xc3,0x38,0xcf,0xbd,0x38,0x4b,0x5f,0x1c,0x14,0xc2,0x26,0x70,0x14,0x46,0xb5,0x2b,0x1e,0x3e,0x2a,0x3c,0xba,0x1a,0x40,0xee,0x28,0x25,0x08,0x0d,0x1d,0xe6,},{0xa8,0xf9,0xfa,0x24,0xa3,0xde,0xa1,0x02,0x2e,0x73,0xf0,0xd8,0x8b,0x1c,0x37,0xd0,0x6d,0x0f,0x0b,0x20,0xbb,0xff,0x0e,0xcd,0xb4,0xa4,0x0c,0x86,0xd7,0xe4,0x75,0x61,0x7c,0x03,0x57,0x0a,0x74,0x19,0xd7,0x4b,0xa0,0xf1,0x32,0x70,0x96,0xbf,0x19,0xf0,0xd0,0xcf,0x9f,0x51,0xd4,0x83,0x11,0x2f,0x26,0x92,0x23,0x78,0x68,0x2f,0x48,0x07,},"\x8c\x4e\xe2\x86\x76\x56\xe3\x3f\x52\x69\x41\x4d\x77\xb4\x2d\x8e\x47\x50\xdb\xa9\x3c\x41\x8b\xac\xca\x10\x93\x8c\xc3\xb5\x70\xc6\x60\x3d\x52\xc2\x34\x44\x88\x60\x7b\x2f\x93\x4f\x6d\x26\x9f\xcb\x2a\xd9\x66\x21\x9b\x1a\xb1\x14\x72\xf4\x2c\x67\x2c\xe2\x05\x92\x49\x0e\xc5\xba\xf6\xa2\xd2\xfc\x8a\x3e\xe3\x53\x74\xb1\x90\x2f\xde\xfc\x78\x70\xb1\xb6\x26\xfa\x46\xb1\x2b\x6c\xee\x24\x1f\x60\x1a\x9b\x3f\xe4\xc5\x08\x12\xe5\x73\xe6\x75\x2c\xe2\xc7\x64\x4e\x33\x67\xa6\xa6\xb7\x77\x58\xd8\xe4\x93\x4b\x58\xaf\x23\xab\xae\x8f\xec\xac\x25\xed\xd7\x34\x03\x0e\xe7\xcf\x39\x90\x7e\x3e\xed\x81\x86\xa1\x9a\x80\x71\x03\xa9\xfc\x49\xd3\x8f\x4c\x84\x60"}, -{{0x88,0x0e,0xf1,0x06,0x73,0x3f,0x04,0xe7,0x61,0x95,0xeb,0xa2,0x80,0xb3,0xfa,0xdd,0xa0,0xf2,0x5d,0xcf,0x96,0xa6,0xa9,0x9c,0x8c,0xcf,0x84,0x2c,0x68,0xaf,0xda,0xe5,},{0x70,0xce,0xe3,0x3d,0x41,0xc7,0x28,0xce,0x7b,0x14,0x19,0x31,0xe6,0xe8,0x52,0x45,0x67,0xd7,0x60,0x1e,0xb7,0x9f,0x67,0xfd,0xcd,0x07,0xb9,0xd6,0x82,0xc6,0x50,0xf0,},{0xff,0x6c,0xae,0xdd,0x8a,0x46,0x8a,0xa0,0x7d,0x4c,0x6e,0x71,0x31,0xbb,0xda,0x76,0x18,0x2b,0xa9,0x58,0x64,0x93,0x76,0xe7,0x11,0xf4,0x4c,0x7b,0xba,0xcb,0xa6,0x07,0x7b,0xea,0x87,0x8b,0xa5,0x94,0x9c,0xde,0xee,0xf0,0x5c,0xfd,0x49,0x83,0xb0,0x05,0x7d,0x27,0x5e,0xa3,0xe1,0x8c,0x32,0x65,0x94,0x68,0xc3,0x0c,0x47,0xac,0x8f,0x0b,},"\xf4\xf3\x8d\x07\x7f\x2b\x03\xda\x82\x1b\xd3\x6f\xde\x67\x3d\x66\x6e\x52\xf4\x83\x2e\x1c\x0d\xcf\xee\xf0\x49\x32\x8a\xcb\x7b\xd7\x1a\xd2\xbf\xc4\x9c\x12\x35\x16\xe1\x96\xc4\x70\xdf\x08\x47\xb3\x84\x8a\x45\xa2\xc6\x9b\xea\x03\xe2\xaf\xa7\xe5\x82\x05\xb6\x3b\x52\x38\x14\xfc\x8e\x24\x2f\x05\x9c\x69\xff\x7e\x40\xf9\x7b\xe8\x12\x5b\x70\xa5\x4f\xda\xf3\x5a\xea\xfa\xc7\x91\x14\xa7\xb4\x19\xe6\xbb\x9e\x70\xbf\x07\xad\xb5\x59\x81\x96\x00\xdc\x25\xe5\x1b\x4b\x70\x0d\x27\xca\x54\x72\xa0\xe7\xcb\xbf\xd1\x4e\x09\x9f\xaa\x3a\x72\x00\x2d\xa5\x38\xcb\xe4\x5d\x62\x1e\xf0\xd5\x25\x2b\xa2\x9d\x83\xf8\xb3\xec\x83\x89\xc9\xce\xb6\xc6\xb2\xe8\xd8\xa2\x0f"}, -{{0xa2,0xd8,0x8f,0x37,0xec,0xc2,0xb2,0xc0,0x5d,0xd6,0xcb,0x31,0x59,0x96,0x2c,0x5f,0x64,0x6a,0x98,0x15,0xb2,0xfb,0x37,0x79,0x1f,0xc7,0xb6,0x06,0xe2,0x91,0x3e,0xd5,},{0x58,0xdd,0x67,0xd7,0xa1,0x5d,0x4c,0xa0,0x34,0x1a,0x4c,0x86,0x95,0x66,0xca,0xd8,0xc4,0xee,0x16,0xe5,0x83,0xa1,0x0b,0x48,0x24,0x17,0x3b,0x08,0x29,0x0d,0x92,0xd1,},{0xcc,0xf2,0x40,0x0c,0xd6,0x73,0xe1,0xef,0xfd,0x20,0x16,0x1d,0x7b,0x68,0xa5,0xfb,0x87,0xc1,0xe9,0x9d,0x36,0x35,0xd7,0x8c,0x2d,0xa1,0xb5,0x09,0xfa,0xc3,0x33,0x46,0xc0,0x69,0x16,0x3a,0x6c,0x46,0xc7,0x82,0x6a,0x48,0xbb,0xbd,0x03,0xb0,0x5e,0x6e,0x23,0x51,0xfa,0x62,0xbf,0x89,0xbf,0x7c,0xcf,0x9a,0x90,0x24,0xbd,0x15,0x7d,0x07,},"\xd1\xb8\x7e\x9e\x88\x6d\xfb\xbd\xc8\xca\x8a\xb9\x01\x0e\xcf\x9b\xba\xf2\x3f\x72\xab\x3c\xbe\x76\x9d\xb1\xd4\x3c\x2a\x47\x4a\x81\x65\x1c\x46\x4e\x9f\xb9\x27\x34\x63\x46\x41\xc9\x48\x5a\x02\x39\xb3\x11\x07\x71\xe7\xf7\x5e\x05\x25\x2e\x4d\x8f\x4c\x0a\xa1\xba\x08\x62\x6d\x7e\x96\x31\x7c\x20\xac\xde\x2a\xd9\x9b\x23\xbd\xad\xfd\x6f\x17\x46\x8e\xb4\x02\xec\x5e\xef\xa5\x7b\x47\xca\xf9\x72\xb3\xdd\x21\xd8\x9f\x0e\x29\x89\xff\x87\xd5\x1e\xd2\xe2\xd6\x39\xc1\x64\x4e\x69\x8c\xbe\x02\x21\xb8\xe1\x79\xf3\xcf\xb0\x4a\x20\xcb\x24\x70\x21\x6a\x68\x82\xfb\x4f\xf7\x99\xe1\x15\x36\xcf\x64\x21\x9f\x0c\x07\x51\x76\xbc\x7c\xf0\xf6\xc5\xb7\x92\x5f\xcd\x61\x55"}, -{{0x42,0xaa,0xfd,0x0a,0xe2,0x6d,0xf1,0xe7,0xaa,0x02,0x76,0x86,0x0d,0x75,0x27,0x83,0xaf,0x97,0x28,0x04,0x39,0xbb,0x23,0xea,0xe4,0x6e,0x3f,0x84,0xca,0xac,0x78,0xde,},{0xda,0xa2,0x35,0x0a,0xdb,0x55,0xdb,0xa9,0xdf,0x7d,0x7a,0xf5,0x10,0x19,0x98,0xfe,0x51,0x5d,0x31,0x1c,0x3c,0xba,0x3e,0xea,0xb9,0x13,0x82,0x33,0x19,0x0c,0x3b,0x4e,},{0x11,0x61,0x43,0x65,0x0b,0x6c,0x13,0x3d,0x61,0x78,0x59,0xdb,0x24,0x29,0xc2,0x91,0x35,0x79,0x79,0x0b,0x21,0x97,0xd7,0xb7,0xb1,0xb4,0x96,0x2b,0x32,0x87,0x21,0x03,0x2c,0xee,0xca,0x58,0xb2,0xd5,0x64,0x39,0xe2,0x33,0xbb,0x84,0xdc,0x52,0x5e,0x28,0x4f,0xf8,0xdf,0x2b,0xde,0x1d,0xb4,0x98,0x6f,0xaf,0xd2,0x1b,0x3d,0x7d,0x6a,0x0a,},"\x72\x13\x1b\x80\xad\x59\x9b\x6f\x5f\xf6\x98\x54\x7d\x16\xe7\x49\x9d\x71\x27\x5e\x4e\x9b\x30\x52\x6a\x5a\xac\x0b\x0c\x8b\x14\xfa\x4a\x54\x0c\xfb\x11\x45\xfc\x00\x44\x18\xbc\xd3\x18\xc1\xa7\x0e\x62\x69\xa3\xfb\x69\xba\xed\x86\xf3\x63\xf5\xb8\xf9\x7f\x56\x9c\x20\xd4\xf4\x99\x0e\x7b\xb4\xd0\xc3\x99\x21\x26\x8d\x63\x6e\xd0\x55\x4b\xd6\x2a\xcf\xca\xcd\x3b\x8e\x03\x02\x17\xaa\xfa\xc3\x04\x4c\x03\x7e\x0f\x94\xda\x18\xc6\xb9\xa0\x93\x2c\x3c\x58\x75\xd3\xa9\x3f\xbd\xad\xcf\x67\x96\x4e\xec\x9e\xc2\xbe\x69\xb4\x8f\x02\x0f\x6c\x98\x74\xde\x5f\x8a\x51\x67\xb5\xee\x02\x4a\x2c\x2e\xfd\x0c\xdc\xd2\xac\xd8\xc1\xf7\x87\x81\x41\x41\xe3\x0b\x38\xb1\x63\x17\x5b"}, -{{0xb6,0x9c,0x33,0xb1,0x1b,0xa6,0x78,0x41,0xc3,0xd4,0xe6,0xf9,0x23,0x4e,0x35,0x37,0x0a,0x28,0xb4,0x76,0x62,0xac,0x56,0x0b,0x27,0xc0,0x78,0xb6,0x6a,0xb1,0xb0,0x21,},{0x9d,0xf6,0x8e,0x9a,0xcf,0x67,0x37,0x92,0x61,0x74,0x4d,0xb5,0xd1,0xe3,0x77,0x89,0x2f,0x2b,0x69,0x2e,0xd5,0xa3,0x8b,0x37,0x07,0x3c,0x04,0xde,0x5d,0x22,0x67,0x37,},{0x24,0x36,0x8f,0xee,0x5b,0xd8,0x48,0xb4,0xc6,0x61,0xa3,0xbe,0x4f,0x31,0x0c,0xfc,0x43,0x6e,0x79,0xec,0x4a,0x78,0x50,0x1b,0x81,0x09,0x5f,0xe5,0x16,0x14,0x23,0x1b,0x6c,0xa1,0xab,0x12,0x69,0x99,0x6a,0xd2,0xe9,0x8e,0x29,0x97,0x81,0xaf,0x8e,0x29,0x80,0x4b,0x24,0xfe,0x56,0x79,0xca,0x3b,0xa6,0x50,0xc5,0xc4,0xcc,0x58,0xce,0x01,},"\xf9\xea\x12\x6d\x3a\xb2\x19\x61\xaa\x24\x33\x90\x0a\x39\x82\xb8\x3e\x0e\xf8\x6d\x52\xd1\x34\x40\xaf\xa4\x81\x7f\x9b\x82\x2f\xb5\x82\xcc\x39\x32\xbf\x45\x0d\x46\x77\xc9\x18\x81\x81\xfe\x75\x26\xad\x6f\xe5\xab\xc6\x1d\x0a\xe7\x59\xf2\x15\x01\x3c\x0b\x2b\x41\x06\x4c\xb6\x27\x8b\xa7\xe3\x9e\x2f\x4c\x10\xd6\xcc\x96\x05\xb3\x86\x9e\x16\x9d\x7d\xa4\x2e\x88\xeb\x85\x78\x70\xfe\x61\x18\xbb\x02\xbc\x08\xc8\x05\x5f\x0c\x18\x9b\x62\xf7\x9f\xb1\x46\xb4\xc5\x43\xaa\x30\xcc\x0c\xd5\x7f\x03\x7e\x9e\xf7\xa6\x37\x11\xf6\x6e\x6f\x28\x78\x93\x17\x02\x20\x27\x02\x61\x42\x77\xd5\x13\xf0\x85\x0b\x75\x85\x49\x33\x6b\x30\xcf\x40\xab\x8b\xd4\x60\xe6\x0e\x12\xde\xed\x04"}, -{{0x7b,0x63,0x61,0x3f,0x6d,0xae,0x01,0xcd,0xcd,0x5e,0x6b,0x37,0x68,0x69,0x71,0xcd,0x8d,0x8a,0x99,0x54,0x2f,0x63,0x29,0xa1,0x28,0x54,0xa9,0xd8,0xff,0x81,0x05,0xac,},{0x72,0xec,0x43,0xfa,0xf3,0x4d,0x87,0x30,0x17,0x7d,0x1f,0x07,0x43,0xc7,0x4c,0x20,0xbf,0x72,0xc2,0x39,0x4b,0x8a,0x7d,0x47,0x1f,0xfe,0x2a,0x04,0xab,0x00,0x81,0x1c,},{0x76,0xf5,0x0b,0x2b,0x9c,0x2a,0xd9,0x7b,0xfb,0x94,0x99,0xee,0x41,0x92,0x8a,0xc0,0x72,0xda,0x5e,0x8b,0xc7,0x1d,0x02,0x12,0x55,0x09,0x42,0x33,0x2b,0x62,0xe7,0x0c,0x8b,0xfe,0x1c,0x72,0x25,0x42,0x39,0x46,0x88,0xde,0xcd,0x91,0x7a,0xec,0x8f,0x95,0x35,0x3e,0x1d,0x72,0x62,0x4b,0x70,0xeb,0xed,0x5d,0x17,0xf6,0xc5,0x49,0x77,0x02,},"\x18\x16\x48\x8f\x1f\xc8\x3e\x1e\xd5\x91\x16\x37\xdd\x42\xba\x20\x77\x65\x7d\xfe\x1a\xe4\x22\xad\x0a\xee\x59\xdf\x9d\xd5\x6a\x27\x63\xc2\xdd\x0e\xf6\x1a\x12\xbb\x82\x5b\x0d\xac\x1e\xda\x5f\xbb\x69\x1c\x5e\xd5\x8f\x3f\xb3\x25\x05\x0b\x45\x63\xa4\x04\x20\x99\x98\x2f\xff\xa5\xd6\xed\x74\x2d\x95\x82\x3d\xa8\xe1\x78\x7c\xf7\x46\xef\x63\xb3\xfb\xb0\xe8\x8a\x6c\x0b\xea\xe4\xf7\x31\x83\x66\x93\x6b\x49\x17\xf5\x07\x33\x60\x68\xb1\x94\x68\x09\x00\xa7\xbf\x4a\x6f\xb6\x9a\x5c\x38\x7b\x97\xe3\x1b\xc7\xf9\xbe\x53\xc2\xa8\x9e\x36\x51\xce\x1d\xe4\x1b\x10\xe9\x21\xb2\x06\xeb\xf3\x2e\x56\x21\xef\x80\x81\x61\x6d\xcd\x7a\x20\x59\x43\x7e\xfa\xd0\x14\xbb\x8e\x2c\x82\x21"}, -{{0x35,0x58,0xd3,0xa7,0x43,0x95,0xbd,0xcb,0xa5,0x60,0xe2,0xc4,0x5a,0x91,0x96,0x0c,0xec,0x6c,0xb3,0xed,0xbc,0xd3,0x0e,0x72,0x2f,0x7f,0x05,0x52,0x10,0xf3,0x7b,0x51,},{0x53,0x4f,0x43,0xeb,0xa4,0x03,0xa8,0x4f,0x25,0x96,0x7c,0x15,0x2d,0x93,0xa0,0x17,0x5e,0xc8,0x29,0x3e,0x6f,0x43,0x75,0x31,0x9e,0xad,0xf9,0x57,0x40,0x1f,0xbb,0xd2,},{0xb3,0x65,0xb5,0x56,0x1a,0x13,0xa5,0x45,0x17,0xcf,0x90,0xd8,0x8b,0x35,0xeb,0x09,0x67,0xd6,0xd5,0x84,0x14,0xb8,0xc1,0x54,0x7e,0x69,0x31,0x59,0xe0,0x13,0x78,0x56,0x36,0x54,0xc5,0x0f,0xb4,0x23,0x23,0xf0,0x9d,0xd7,0x8f,0xfe,0x28,0x05,0x6d,0xdf,0xa5,0x4f,0xeb,0xf4,0x48,0x91,0xe8,0xa7,0x41,0xb6,0xa1,0x68,0x7d,0x72,0x86,0x05,},"\xbe\x75\x44\x4f\x9c\xe6\xbe\x1d\x83\xaf\x62\x2a\x8c\x47\x8d\x51\x01\x27\xdb\x56\xf1\xde\x6e\xb8\xa5\x12\x65\x22\xb0\x9f\xdc\x6c\xa0\x86\x2c\xec\x0b\x8b\x2a\xaf\xa3\x1c\x17\xa2\xcc\x47\x7d\xa5\x33\xd2\x76\xa1\xae\x4f\x8e\x07\x59\xd6\xaf\xa0\xb1\x74\x11\xb5\x17\x0b\x52\xf2\x05\x47\xc7\x2f\x3e\x88\xd4\x8c\xb4\x56\xfe\x62\x5b\x62\xfe\xb0\xf8\x13\x17\xed\xf1\xec\x09\xec\xe5\x34\xb9\xf5\x00\xd4\xe1\xb1\xbd\xa2\xdb\x21\x98\x2a\xa9\x50\x94\x22\x6e\xe9\xf5\xb0\xa6\x5d\xa8\x3f\x91\x12\x1c\x96\xb3\xb4\x01\x0a\xe7\x82\x6c\x9e\x80\x63\x6c\xba\x00\xf7\x0c\x3c\x8a\x27\x9b\x01\xb9\x52\x94\xcb\x85\x0f\x91\x70\x9f\x43\x76\x66\x2a\x58\x0b\x15\xac\x29\x81\xaf\xe9\xf8\x54"}, -{{0xa3,0x5b,0x92,0xf2,0x44,0x06,0x3a,0x19,0xbb,0x5e,0x3e,0xd4,0xd6,0x99,0xed,0x20,0x69,0x60,0x71,0x16,0xd2,0xbd,0x08,0x11,0x3f,0x0d,0x83,0x73,0x61,0x3f,0x35,0xb7,},{0x7e,0xc9,0x36,0x01,0x86,0x4e,0xe4,0x99,0x5a,0x4f,0x7a,0xbc,0xd3,0xdf,0xc1,0x01,0xe9,0xe7,0xf3,0x69,0xe6,0x3d,0xe1,0xae,0x68,0xa0,0x7a,0xa7,0xf0,0x75,0xb3,0x29,},{0xa2,0x3d,0xbe,0x37,0x57,0xe4,0x78,0xdb,0xc8,0x4d,0x3d,0xb3,0xa9,0x33,0xb0,0x42,0x8c,0xed,0xb6,0xb0,0x1b,0x86,0xd8,0xd7,0x3f,0x39,0x59,0x87,0x8d,0xae,0x6f,0x05,0x88,0xf5,0x05,0xcd,0x4d,0x39,0xf2,0xab,0x46,0x77,0xb6,0x48,0x05,0xd6,0x29,0x65,0x2a,0x22,0x52,0x98,0x25,0xc3,0xa9,0x1d,0x04,0x37,0x49,0xfc,0x71,0xf0,0x37,0x06,},"\x65\xcd\x36\xda\xe0\x16\x8d\x69\x97\x4f\x95\xf0\x9d\xd9\xa5\x9d\xb7\x99\xf9\x11\xe1\xa1\x5b\x85\xa0\x08\x93\xb8\xc9\xa3\xd4\x8a\x2f\x58\xac\x12\x6b\xfa\xa0\xa6\x06\xc0\x5d\x94\x70\x1d\x27\x3a\xbf\x7d\x68\x81\x7f\x2c\x71\xb1\xc5\x41\x79\x5c\x4f\x60\x95\xe2\x6c\x9d\xff\x80\x3f\x03\x2f\x75\x66\x3f\xd1\x69\x8e\xdd\x97\xff\x3a\x0e\x72\xe1\xb7\xc9\x94\x8b\x08\xba\xcb\x5f\x7d\xe5\x02\xb2\xfe\xa6\x7c\xa2\xfe\xf1\x90\xd6\x0e\xae\x92\xd1\x51\x58\xda\x44\x4a\x49\xd2\xe9\xd5\xa5\x73\xe8\xe1\x77\xe8\xbb\xf7\xe6\xc4\x9f\x90\x71\x36\xe7\x1d\x2a\x66\xcb\x07\x63\x6d\x48\x76\x8f\xf4\x17\xc8\xbe\xcc\xf4\x32\x31\x81\xfe\xfb\x31\x24\xe4\x34\x04\x9e\xa4\x5d\xd5\x01\x9e\x40\xb4"}, -{{0x72,0xd4,0xa5,0x64,0xca,0x15,0x49,0x9b,0x5e,0x4e,0x75,0xd8,0xac,0x0f,0x28,0x21,0x7d,0x32,0x11,0x4a,0x0c,0x64,0x9a,0x7c,0x8e,0xaa,0xdd,0x0c,0xc7,0x8c,0x52,0x0b,},{0xc7,0x66,0xbd,0x73,0x83,0x7c,0x4f,0xaa,0x52,0x15,0x50,0x2f,0x1e,0xfc,0x90,0xc0,0x03,0xf7,0x11,0xbb,0xef,0x55,0x17,0x00,0x91,0x02,0x8a,0x34,0x49,0x34,0x08,0xa9,},{0x8f,0xc4,0xf1,0x79,0x33,0x0b,0x64,0x2d,0xd8,0x6c,0xa9,0x36,0x26,0x51,0xb8,0x3b,0x00,0x6d,0x83,0x75,0xcc,0xef,0x81,0x1d,0x3c,0x67,0x06,0xf9,0x15,0x94,0x65,0x1d,0xf2,0x76,0x99,0x53,0x72,0x30,0x46,0xcc,0xb9,0xbf,0xe6,0x6a,0x66,0x7e,0x0d,0x11,0xfc,0x3e,0xa2,0xd8,0x22,0x62,0x34,0xfd,0xd5,0x16,0x47,0x65,0x26,0x0f,0x7b,0x05,},"\x6c\x7e\x7b\x62\xeb\x24\x4a\x45\xd7\x84\x36\xe2\x97\x0d\xcd\x6c\x0f\x7d\xb8\x22\x97\xa8\x61\x40\xea\x58\xdd\x22\xc2\x19\x5a\xdb\xc9\x56\xd4\xc4\xec\x05\x35\x4b\x21\xef\xe2\x4c\xfc\xfe\x10\xe1\x76\x22\x36\x88\x48\x18\x0d\x2c\x46\x80\xcc\x21\x5e\x8c\xee\xa6\xcc\xe2\x22\x16\x1f\x1e\x09\x22\x39\x25\x3b\x97\x46\xf7\x88\x7d\xf2\x42\x5a\xb5\xa8\x80\xbd\xba\x98\x15\x3b\xe7\x86\xdc\x83\x8c\xbe\xca\x01\x6b\x1d\x06\x52\x4b\xd6\xbf\xba\x80\x9a\x8b\xb3\x7a\xda\xb1\x5d\x42\x41\x5f\x86\xec\x03\x58\x36\x5e\xa8\x7b\x81\x50\xb0\x54\x41\xd9\xd4\x98\x46\x87\x14\x85\xca\xae\x6d\xe3\x59\x73\x6c\x27\x18\x97\x36\xd8\xf1\x76\x5f\x3e\x5c\x5f\x6b\x92\x16\x83\x96\x39\x0b\xee\x94\xcf\xbd"}, -{{0x2e,0x5a,0xaa,0xb2,0x98,0xe6,0x6c,0x2d,0xc1,0xd7,0x7e,0xa7,0x42,0x1f,0xf8,0x95,0x25,0x5f,0x9d,0x90,0x0d,0xb0,0x45,0x0d,0x63,0xf9,0xf7,0x9c,0x1a,0x70,0x13,0xcf,},{0x03,0x81,0xf3,0xf1,0x90,0x45,0x71,0x9b,0x9e,0x8c,0xeb,0x56,0x2f,0x0e,0x96,0x5d,0xc0,0x7b,0x09,0xf3,0x71,0xa9,0x63,0xa2,0x81,0xc7,0x49,0xc2,0x53,0x2f,0x65,0x4a,},{0x7c,0x74,0x30,0x30,0x5b,0x36,0x1a,0x9e,0x35,0xb2,0x78,0x0c,0x4d,0x44,0x08,0x07,0x1b,0x21,0x30,0x93,0x1d,0x39,0x83,0x0e,0xc8,0xd3,0x13,0xaa,0xfb,0xc8,0x3a,0x65,0xda,0xe1,0x9c,0xb7,0x47,0xd9,0xd1,0xc4,0xce,0x3f,0x35,0x9c,0xc8,0x24,0xea,0x8c,0x92,0xf6,0x6a,0x42,0xb8,0x61,0x4e,0x78,0x48,0xb8,0x84,0xac,0x8a,0xa4,0xae,0x02,},"\x3d\xf0\xe5\x4c\x71\x1e\x31\x32\xd7\xae\x95\x3d\xeb\x7b\x66\x86\x9e\xe5\x31\xee\x40\xb6\x3c\xe6\x93\x20\x6c\xdb\x2f\x4b\xda\x0a\x25\x69\xe9\x13\xac\x3e\x65\x32\xc5\xd9\x64\x8e\xfd\x46\x27\x78\x0f\xb8\xa3\x1d\x10\x7e\x03\x3f\x05\x4d\x19\xed\x8b\x7c\x49\xdc\x40\x7d\x2e\x94\x9d\xe2\x5f\x99\x30\x72\x21\xd3\x58\x43\xf6\xd5\xeb\x7d\xe5\xcd\xf4\x1b\x91\xdb\xbf\x34\xcb\x6c\x9c\x53\x00\x21\x01\x4b\x56\xab\xc4\x4a\xc2\x30\x03\x13\x61\x56\x08\xa7\xb4\xa2\x35\xe9\x9c\x14\xce\xf8\x05\x08\x87\x03\x22\x09\x48\x8b\x9e\xae\xaa\x82\xc0\x94\x05\xfc\x75\xbe\xc9\x4d\xd4\x2d\x6f\xf1\xb5\x99\xa6\x3e\xe5\x74\x2f\x33\x64\x09\x3a\xc9\x2c\xab\xab\x30\x35\x82\x2a\xa8\x67\xae\x56\xdc\xc9\x9d"}, -{{0xb6,0x36,0xa0,0x24,0x48,0x00,0x35,0x43,0xdb,0x86,0x4b,0x40,0xb5,0xd8,0xd6,0xdd,0x9a,0xd6,0x11,0x62,0x4c,0x9b,0x0f,0xc6,0x89,0x0c,0x51,0xea,0x55,0x92,0xc7,0x90,},{0x1e,0xf3,0x60,0x49,0x59,0x68,0xe5,0x6e,0x6d,0x3f,0xe7,0x40,0xb1,0xc8,0x4c,0x4e,0x44,0x90,0xed,0x68,0x2d,0xeb,0x43,0x05,0xaf,0xd5,0x96,0xef,0xb2,0x80,0x22,0x3b,},{0xd4,0xba,0x80,0x30,0x0d,0x5c,0xb5,0x13,0x53,0xc0,0x3f,0x28,0xc4,0x4f,0xd0,0xa4,0x24,0xff,0xe1,0xe4,0x0d,0x78,0xed,0x7b,0xb1,0x13,0x3e,0x8f,0xe4,0xe1,0x87,0x50,0x52,0x93,0xb2,0x0a,0x39,0x1d,0xa9,0x62,0xc6,0xa8,0xac,0x0a,0xce,0xc9,0xc6,0x72,0x26,0xaf,0x3b,0x61,0x95,0xda,0xbe,0x39,0xb3,0x66,0x22,0x94,0xda,0x3e,0x0e,0x09,},"\x4a\xa8\x5a\xac\x25\x03\x4f\x61\x4e\xd4\x4f\x7a\xdc\xdb\xee\xec\x25\xfc\xc2\xa9\xee\xa3\x2a\xb6\xa8\x69\x95\x06\xf7\xa1\xca\xd3\xbc\x89\x2e\x9d\xce\x93\x4e\x75\xb0\xa8\xcd\x14\x64\x2b\x77\x85\x99\x28\x6c\xfd\x8f\x50\xa9\xe4\xf2\xed\xf9\xf9\xd6\x29\x1a\x2e\x29\x79\xcf\x18\x06\xb9\x3e\xd8\xc9\xa7\x8f\xae\x19\x9b\x28\x54\xa0\x3e\xc4\x06\xab\x3f\x72\x08\x35\xee\x26\x3f\xbb\xc9\x1c\xb4\xef\x07\x58\xd7\x75\xfc\x78\x4c\x7d\x5b\x25\x1a\xc8\x93\x79\x19\xa9\xe6\x7b\xe8\x8c\x9e\x44\xcf\x2e\xc7\xf5\x60\x26\x9a\xa0\xf1\x11\x3d\x91\xb8\x44\x01\xdb\x15\xa3\xc4\x8c\x7d\xac\xff\x49\x39\xee\x01\xba\xbb\x98\x2f\xb9\x56\x25\xc6\xc3\xad\x78\x74\x90\x60\x55\x1b\xfd\xe8\xcc\xe4\xfb\x8a\x29"}, -{{0x5c,0xa0,0x54,0x3c,0x71,0xf5,0x68,0xa0,0x0e,0xed,0xf5,0x0a,0x95,0x20,0xf4,0xc1,0x5b,0x52,0x6e,0x3f,0xb0,0xda,0x81,0x6c,0x29,0xea,0x3d,0x50,0xb2,0xf6,0x2a,0x12,},{0xd4,0xa2,0x93,0x3c,0xe1,0x94,0x54,0xe3,0x31,0xb5,0x28,0x01,0x00,0x20,0x9a,0x6c,0xe8,0xe5,0x69,0xf9,0x93,0xc2,0xac,0xab,0x51,0xdb,0xe8,0x64,0xc5,0xcb,0x25,0x63,},{0x43,0x68,0x23,0xee,0xff,0x3e,0xdc,0xe5,0xd8,0x58,0x7d,0x68,0xe5,0x47,0x3e,0xf3,0xd8,0xdc,0x94,0x65,0xb5,0x58,0xb6,0xe8,0xe7,0xcd,0x31,0x37,0xec,0xcc,0x80,0xb4,0xc4,0xe8,0x06,0xed,0xf1,0x36,0x19,0xd8,0xe7,0x17,0xe6,0x9f,0x48,0xd7,0x06,0x1b,0x68,0xde,0x02,0xc8,0x20,0x9b,0xe1,0xf7,0xac,0x26,0xba,0x8e,0xdf,0x60,0x6d,0x02,},"\x4e\xf8\x49\x69\x78\xd2\x8c\x10\xab\xd5\x4a\x26\x35\x6e\xe5\x59\x21\xce\xb3\x50\xdd\x4b\x74\x2c\x41\x61\xfb\xeb\xa8\xa1\x60\x1f\x8a\xd0\x48\x4b\x21\xa8\xcf\x5a\x29\x4f\xac\x00\xec\x8a\x6f\x59\xe3\x36\x2e\x47\xbf\xae\x1e\x28\xa2\xe6\xd0\x17\xc5\xca\xa7\x5f\xb0\xf4\x84\x82\x80\x80\x37\xca\x21\x47\x69\x54\xd7\x78\xff\x1a\x05\x86\xda\x3e\xf6\x9d\x6c\xef\x6d\x2d\x8d\xf4\xae\x7a\x85\x44\x2a\x1e\x46\xc9\x98\xcf\x40\x7a\x6a\xd4\xc5\x46\x3a\x43\xc2\x48\xf3\xb6\x93\x7f\xdb\xc8\x45\xb6\x0c\x6d\x85\xe0\x56\x3c\xc1\x6b\xa9\x67\x5d\x36\x4f\x52\x5f\x66\x9a\xaa\xc9\x5f\x42\x8b\xb5\x82\x05\x09\x9f\x9e\x4a\x6d\xbb\xd0\x15\x1f\xb6\x5b\xab\xe1\x23\xe5\x39\x3a\xd6\x40\x26\x93\x5c\xb4\x88\xaa"}, -{{0x5f,0x87,0x11,0x7d,0xa9,0xbb,0xb6,0x09,0x1c,0x94,0xda,0x6b,0x23,0x0b,0x7d,0x8f,0x6d,0xe0,0xed,0x2a,0x07,0x64,0x13,0xb9,0x2e,0xac,0xdc,0x43,0xab,0xbc,0x68,0x97,},{0xaa,0x78,0x6a,0x14,0x62,0x26,0x83,0x2a,0xa7,0x3c,0x43,0x4b,0x0e,0xdc,0x2d,0x41,0xd2,0x55,0x8f,0x82,0x0a,0xb8,0xf8,0x7e,0x09,0xe6,0xcd,0xa9,0x10,0x72,0xb9,0xb6,},{0x0f,0x19,0xe6,0xea,0x0c,0x05,0xf3,0x81,0x85,0xc0,0x1c,0x2d,0x64,0x77,0x99,0x5d,0xaf,0x50,0x65,0xba,0x9d,0x80,0x17,0x3f,0xa6,0xbb,0x23,0xa7,0x74,0xdc,0x88,0xb3,0xaa,0xe8,0x79,0xd8,0xa6,0x24,0x71,0xd2,0xd3,0x04,0xcc,0x3d,0xc6,0x62,0x78,0xa7,0xab,0xcb,0x0b,0xb0,0x77,0x1c,0xd2,0x78,0xe1,0x1e,0x7b,0x93,0x2e,0x9f,0x9b,0x0f,},"\x22\x97\xc4\x0a\x2e\x83\x65\xba\xe4\xc5\xf0\x63\x0c\x50\xb1\x3b\xdd\x9a\xd9\x77\x0a\x5d\x9a\x94\x51\xd0\x08\x74\xb0\x23\xd2\x5e\xcd\x46\x8b\x96\x57\x1b\x2f\x16\xdc\xb1\xb0\xd3\xd7\x56\xc1\xf0\x44\xfc\xdd\xd1\xc5\x1f\x27\x72\x7a\x03\x69\xc9\xcf\x25\xbd\x6a\xa5\x95\x51\xb5\xb0\x7c\xf8\xf8\x07\xd9\x2b\x15\x91\x98\x63\x97\x04\x74\x0f\xe6\xed\xa0\xf2\x6d\xba\x7e\x75\xd4\x53\x0b\x28\x00\xf0\x3f\xb6\xaa\x67\x7d\x84\xdf\x75\xd6\x8d\x4f\xbb\x64\xad\x21\x00\x1e\x3f\xc8\x7b\x60\x9b\x9c\x25\x1e\x8c\xcb\x12\xbb\xca\x92\x74\x47\xe2\x05\x4e\x07\x68\x8e\xb8\xa2\x05\x21\xa5\x22\x49\xe7\xb9\x43\xbe\xd6\x0e\x6a\x93\xc0\x1e\x3e\xb6\x21\xf0\x46\x0c\x18\xa6\x90\xb6\xf6\xb6\x6e\xdc\x6e\x87\x43\xa6"}, -{{0xb5,0x3a,0x64,0x4c,0x92,0xba,0x2d,0xc7,0x10,0x8b,0x16,0x83,0x3f,0x09,0xad,0x59,0x17,0x84,0x64,0x37,0x22,0x5a,0x77,0x3d,0x32,0xd7,0x9c,0x97,0x73,0x3c,0x0a,0x58,},{0x51,0x58,0x18,0xc6,0x9c,0x0e,0x0a,0x17,0x06,0xb0,0x41,0x43,0x84,0x2f,0x3e,0x9e,0x27,0x14,0x48,0xfb,0xaf,0x3a,0x89,0x91,0x19,0xc3,0x2f,0x42,0x56,0x6f,0xfd,0x33,},{0x13,0xd2,0xcb,0xac,0x79,0x76,0xad,0x27,0xf0,0xbf,0x66,0x9a,0xd5,0x88,0xef,0xb2,0xc9,0x1b,0xab,0x85,0x07,0xd5,0x7f,0xb1,0x6b,0xfe,0xa9,0xca,0xff,0x2b,0x09,0x64,0xe7,0x56,0x25,0xc4,0xd8,0x08,0xd7,0xbb,0xb7,0x8c,0x5b,0x46,0x4e,0xdf,0xfe,0x49,0x49,0xec,0xfb,0xc8,0xb9,0x5f,0xf6,0xfd,0xb1,0xbd,0xca,0x27,0x42,0x06,0x81,0x00,},"\x13\x03\x6d\xaa\xee\x45\xfc\xfd\xe0\xc5\x3e\x06\xd0\x5a\xa9\xc0\x1e\xa9\x4a\x67\xe8\x6c\x6c\x53\x8c\xcb\x28\x3b\x36\x8d\xaf\x70\x78\xd3\xfb\xab\x58\x0c\x76\xec\xf8\x2b\x4e\x96\x60\xf0\x68\xdc\xbb\x50\x0b\x80\x59\x50\x17\xc5\xbe\x3c\x44\x8f\xbd\x8a\x17\xd9\x7c\x56\x43\x19\x78\x90\xe1\x67\xb3\x53\x45\xbf\x65\xe7\x5b\x82\xc8\xd6\x52\x29\xf2\xf6\x0a\xae\x27\x72\x58\x1b\xc9\x9c\x49\xd4\x16\xbc\x3d\x78\x74\x6e\xf8\x30\xf1\xaf\x94\x4f\x4a\x67\x15\xab\x4f\xfb\x01\x59\x1b\xac\x28\x57\xf1\xa9\xc9\xd1\x70\x08\x88\x78\x00\x06\xa3\x16\x07\x33\x8f\x7a\xf7\xbe\xdf\x6e\xfe\x0b\x57\x29\x9a\xc9\x15\x52\x6f\xe5\xe1\xe1\x01\x29\x87\x08\xc6\xe6\x1b\x84\x22\x0a\xfe\x95\xb5\x3f\x89\x59\x87\x45\x61\x52"}, -{{0xd2,0x7c,0x9e,0xaf,0xcf,0x88,0x15,0x19,0x90,0xbb,0x5b,0x2f,0xa8,0x44,0x3e,0x70,0x9b,0x5f,0xd8,0xd7,0x8d,0x23,0x38,0x03,0x32,0x2d,0xc8,0x6d,0x93,0xd9,0x32,0x95,},{0x08,0xe0,0xef,0xf5,0x29,0x77,0x67,0x14,0x68,0x61,0x96,0xd8,0x17,0xfd,0xf7,0x1e,0xb5,0xb6,0xe8,0x32,0x65,0x16,0xef,0x48,0x9b,0xfe,0x18,0x6a,0xc5,0xc5,0xbf,0x6d,},{0xc2,0x54,0xe3,0x71,0x44,0x56,0x33,0x13,0x74,0x42,0xee,0xfe,0x40,0xad,0x4a,0x82,0xe6,0x9b,0x1e,0xbf,0x48,0xa6,0x85,0xa2,0xbc,0x6f,0xfb,0xac,0x12,0x6d,0x22,0x84,0x87,0xb2,0xe3,0x53,0x7c,0x97,0xef,0x74,0x10,0x34,0x20,0x91,0x96,0x2e,0x50,0xc0,0xcb,0x85,0xde,0x7b,0x39,0xce,0xb4,0x1a,0xc4,0x07,0x8d,0x40,0xf3,0x40,0x71,0x06,},"\x77\xc3\x5b\xda\x32\xa5\x96\x7d\x8b\x30\x2f\xa7\xa4\x75\x83\xce\xab\x89\xc9\xa6\x09\xa6\x67\xb7\x53\x15\x5f\xa6\x99\x6f\x86\x31\xd0\xeb\xed\xfe\x0a\xc3\x64\xc7\x7e\x85\xba\x37\x31\x1f\x0d\xe5\x7a\x0d\xc2\xc1\xe9\xe4\x00\xd5\x8b\x42\x4a\x32\x2e\x1d\x57\x71\xe0\xa9\xfd\x95\x02\xad\x02\x32\xce\x54\x4f\x07\xd8\xc6\x6e\x7c\x31\x47\xf8\x60\x7a\xc6\x18\x9b\xb6\x90\x66\xf2\xfa\xd6\x31\x18\x5f\x45\x7f\x46\x7e\xba\x33\x22\x8e\xcc\x40\xe8\x94\xa7\x7b\x57\x16\x98\xa9\xbf\xac\x84\x1a\x54\xea\xc5\x21\x9d\xa9\x9c\x6a\x91\x25\xc4\x69\xa2\x2f\xe8\x1f\x3b\x95\x14\x33\x89\x6f\x19\xce\x39\xb3\x73\xfd\x7e\x5c\x7b\x65\x0a\x5e\xf2\x36\x5a\xe7\x51\x0b\x0d\xa5\xe4\x9d\x7c\x07\x07\x3c\xf1\x66\xa9\x83\x87\xe8"}, -{{0x70,0x21,0x3d,0x3a,0x79,0xc6,0x5d,0x6d,0xbb,0xa5,0x42,0xa3,0x67,0x96,0x35,0x00,0x3a,0x68,0x2a,0xf5,0xfa,0x58,0xde,0x6b,0x0d,0x65,0xbf,0xa2,0x41,0x84,0x90,0x1c,},{0x44,0x02,0xfb,0x92,0xcc,0x12,0x49,0xdd,0x1a,0xe1,0x69,0x0f,0x03,0xb3,0xec,0x4f,0x1e,0x9b,0xda,0xb0,0xde,0x5b,0xfd,0x28,0x9f,0x10,0x29,0x68,0x30,0xfd,0x40,0x3e,},{0x5b,0x6c,0xe2,0x77,0x4d,0x40,0x0e,0xce,0xa8,0xa8,0x08,0xf5,0xfd,0x0a,0x79,0x7f,0xfc,0x61,0x16,0x75,0x23,0x76,0xcd,0x7b,0xfa,0x3b,0x2c,0xca,0x3a,0x84,0xd5,0x59,0x3f,0x5c,0x03,0xad,0x3e,0xec,0x1d,0x89,0x53,0x22,0x75,0xc4,0x7b,0x7c,0xe2,0xa0,0xe9,0xc5,0x9c,0xc4,0x02,0x8a,0x8a,0x65,0xe5,0xbb,0x90,0x97,0xea,0x71,0xc2,0x08,},"\xcd\x6e\x1c\xd9\xc9\x0f\x56\x6d\xe0\x43\xd7\x5d\x72\x44\xec\xfd\xb3\x8e\x8b\xde\x2f\x9a\x6c\xd5\xa4\xfd\xac\x72\xb5\xed\xe6\xaf\x62\xd9\x81\x91\x8c\x5e\x61\x0a\x38\x78\x92\x74\xfa\x10\xe5\x27\xf8\x5f\xad\x20\x9b\x76\xca\x1c\x28\x1a\xd5\x89\x0f\x9c\x96\xd3\x5d\xe5\x22\xf1\xdd\xcc\xb5\x39\xb8\x79\x8a\x00\x67\xac\xdd\x45\xb6\xe3\x44\xa5\xd9\xa9\x77\x31\xf5\x45\xff\xa4\xb1\x7b\x87\x5c\x67\xb4\x8e\x9d\x4c\x4b\xa7\x2c\x98\xa4\x50\x55\x83\xfd\xbf\x1e\x12\xf2\x2b\x5a\x7a\x49\x47\x46\xcc\x9b\x6c\x1b\x57\x19\x06\xc6\x7f\xcc\x88\x3a\x9c\x15\xa3\x80\x68\x75\xb6\x59\xe5\x81\x6b\x42\x76\xc3\x19\x0e\x25\xcc\x1a\xc3\xde\x47\xbf\x99\xc4\x99\x65\x38\x8f\x54\xf3\xef\x8e\xb5\x69\x90\x6c\x60\x08\xe5\xfb\xbd"}, -{{0x5d,0x54,0x0b,0x3b,0x14,0xf0,0xc0,0x17,0x5c,0x04,0x7e,0xaf,0x02,0x6c,0x90,0x70,0x65,0x9e,0xf1,0x3e,0x9d,0x28,0xe0,0xc5,0xc5,0x16,0xa4,0x28,0x26,0x9b,0x14,0xeb,},{0x1d,0x2d,0x4d,0x55,0x1a,0x57,0xc6,0xfb,0x2b,0x04,0x18,0x10,0x49,0xd4,0x03,0x9d,0x57,0x5c,0xf8,0x0c,0x0b,0xc6,0xec,0x70,0x33,0x06,0x7f,0x27,0x30,0x93,0x44,0xde,},{0x32,0x52,0x7d,0xa7,0x55,0x31,0x28,0x89,0x93,0x5d,0xd5,0xee,0x91,0xb1,0xbb,0x11,0x7a,0x5d,0x37,0x7d,0xd2,0x3e,0xf5,0xb7,0xe1,0x5b,0xaf,0xfa,0xe9,0xa5,0x43,0x91,0xa3,0xfd,0x23,0x4b,0xdc,0xe0,0x73,0xe0,0x98,0xc5,0x8d,0x05,0xbf,0x19,0x5b,0x4c,0x3c,0xc6,0x39,0x72,0x38,0x3b,0xa4,0xb5,0x10,0x72,0x97,0x1a,0xeb,0xcb,0x62,0x0d,},"\xe4\xc9\xe8\x70\x68\x98\xca\xd4\xac\x68\xd7\x3c\x13\x0e\xfa\x04\xa5\x4f\x8c\xa2\x59\x19\xea\x6b\xfa\xa5\x4c\x8c\x72\x0c\xed\x85\x4c\x5e\x95\x09\x10\x2c\x7b\x88\x5a\xed\xdf\xfb\xd1\xb7\xf2\xc5\x92\x25\x83\x67\x7a\xc9\xee\xa9\xa1\x08\xc7\xe8\x3e\x88\x71\xae\xd5\xa0\x84\xf5\x44\x0b\x0f\x39\x1a\xd7\xff\xc6\xba\xb4\x57\x4a\xf1\xb9\x67\x70\xf4\x37\x0e\x8e\x98\x8e\x85\xec\xb1\xa8\xd6\x03\x4f\xc3\xd7\xf4\x9f\x74\x22\x02\x3b\x9d\xab\x5d\x0c\x16\xbe\xab\x5f\x5d\x37\xb0\xa4\xd7\xde\x19\x7a\xd8\x7c\xd4\xff\x8c\xe7\x8e\xb1\x2e\x1d\xaf\x73\x9d\x8b\x47\xab\x38\x0a\xbe\x90\x93\x35\x6d\xb5\xb5\x97\x17\x75\x1a\x49\xe1\x94\x84\x72\xfd\xac\xc2\x59\xff\xff\xc8\xc1\xdb\xae\x59\x26\x07\xd4\xec\x71\xcc\x6a\x8f\x6b"}, -{{0xca,0x41,0x76,0x9c,0xaf,0x17,0x17,0xb4,0xe4,0x5c,0x93,0xc1,0x21,0xdc,0x82,0xa5,0x34,0xfb,0xc6,0xec,0x09,0x86,0x66,0x2c,0x32,0x22,0xd7,0x14,0x92,0xbd,0x11,0x76,},{0xaf,0x3f,0x89,0xf6,0x18,0x7d,0xbc,0xf9,0x21,0x77,0x50,0xc6,0x7e,0xf8,0x9e,0xd4,0x7b,0x03,0x9f,0x9e,0xb0,0x62,0xff,0xec,0x9d,0xf6,0x4a,0xb5,0x2b,0x0b,0x45,0xcb,},{0x5c,0xda,0x87,0x2f,0x7e,0xd6,0xd7,0xc9,0x02,0x18,0xac,0x10,0xbe,0xe8,0xe2,0x14,0xf3,0xb3,0x4d,0x15,0xd2,0x5c,0x39,0x25,0x5e,0xc9,0xe6,0xb0,0x17,0x7a,0xa3,0xcb,0x73,0x68,0xd1,0x1c,0xb8,0xed,0x6f,0xf5,0xcf,0x0c,0x04,0x28,0x1d,0x06,0xbc,0x42,0x72,0xb8,0xbc,0x09,0xc2,0x3f,0x6f,0x4c,0xd5,0xa8,0x10,0xdd,0xc7,0xb9,0xc1,0x03,},"\x9d\xe8\x47\x6c\x58\x13\x84\x8a\xb1\x45\x15\x37\x84\x1c\xc1\x78\x00\x21\x81\xa2\x18\x2a\xf3\x05\xb1\x2e\x5f\x7c\x3b\x1d\x56\xb2\x2c\xf4\x6a\xe6\x27\x6d\x18\x26\xec\x0a\x8c\x9a\x7d\x9f\x68\x08\x3b\x72\x25\xbb\xfa\xef\xce\x82\xb3\xb6\x45\x94\x05\x2a\x77\x00\xf3\x09\x23\x3a\x79\xff\xfd\xfc\xcc\x5c\x21\x40\x0c\x91\xcc\x0e\x41\x8d\x51\x41\xd4\x86\xb5\x21\x99\x01\xd6\xdd\x24\x47\xc1\xf7\xb7\xcf\x5a\x08\x79\xe7\x0e\x1d\xd6\x58\xd0\xf2\xec\xf3\x1e\xbe\xee\x11\xa5\xc7\x44\x40\xc6\x3b\x9d\x8b\x45\x31\x8c\x34\x65\xd7\xff\x03\x36\x5e\xdd\x03\x85\xed\xf8\x0d\x4f\xde\xd5\x1f\x0f\x75\x33\xee\x40\x99\xf1\x9e\x93\xbc\x9d\x08\xda\xdc\xd1\x34\x85\xdb\x23\x95\x22\xff\xc8\x1e\x2c\x05\x1f\x87\x96\xd6\x2e\x97\x9f\xcf"}, -{{0xfe,0xdd,0x63,0xff,0xd4,0xcf,0xbf,0x61,0x88,0x94,0x96,0x2e,0x12,0x1a,0x90,0x25,0xee,0xa3,0x18,0xa8,0x0a,0x1a,0xdf,0x16,0x9d,0x64,0x90,0x44,0x5d,0x2e,0x02,0xa0,},{0x54,0x2f,0x22,0x44,0xbd,0xb7,0xd8,0x4b,0x87,0xe6,0x28,0xa8,0xe6,0xa1,0x2f,0x17,0xbf,0x74,0xa9,0xa6,0xd0,0xea,0x46,0xc5,0x95,0xdb,0xfd,0xc6,0x80,0xc0,0x4b,0x26,},{0xed,0x59,0xd9,0xe2,0x3d,0xec,0x34,0x94,0xb0,0xfb,0xc5,0xd1,0x0c,0xd0,0x2b,0xab,0x86,0xb3,0xeb,0x35,0xab,0xbf,0x9e,0x4d,0x4a,0x92,0x64,0x79,0xf1,0x34,0x58,0x3a,0x44,0xce,0x72,0xdc,0x41,0x22,0xac,0xa3,0x77,0xa4,0x07,0x2b,0x71,0x56,0x46,0x2b,0x74,0xe8,0xdf,0x46,0xb6,0x86,0x69,0x86,0x36,0x83,0x6e,0xf2,0x03,0x17,0x9c,0x07,},"\x2e\x2a\xe5\x84\x64\x1b\xe0\x3d\xd4\x8f\x9c\x61\x80\x77\xae\xaa\x18\x21\x2a\x42\x41\xf0\xc0\x19\x4e\xd2\x3e\x37\x0d\x74\x1a\x3a\xe1\x1a\x5f\xec\x3b\x04\x0c\x16\xea\xfa\x4a\xc8\xd1\x8a\xba\xa7\xce\x8f\x28\x69\x67\x33\x71\x89\xf0\x49\x5f\xfd\xd6\x19\x95\xcd\xe3\x1d\xd8\xdf\xc3\xdf\x57\x00\xb5\x7a\x7a\x29\x98\x0e\x9c\x82\x3f\xee\x85\xd6\x14\x51\x17\x67\x29\xe7\x27\x87\xc6\x10\x9b\x47\x35\x9b\x93\xdf\xd6\x2e\x1e\x5a\x2d\x64\x2c\x05\x72\x42\xda\xe5\x00\xa9\x4c\xa1\xa9\x3b\xc5\x7b\xe1\xad\xe7\x6f\xe4\x50\x1c\x0f\x63\x77\xed\x0e\x92\x46\x17\x9a\xec\xdd\x99\x46\xb6\x71\xe8\x19\x0e\x1e\xd2\x3f\x96\x6e\x96\x40\x9b\x94\x82\x22\xd8\xea\x58\x39\xde\x90\x4f\xc5\x13\x48\x07\x3b\x8f\x40\xed\xbd\x9b\x4a\x4b\x22\x75"}, -{{0x38,0xf2,0x18,0x4e,0xaa,0x55,0x36,0x56,0xee,0x29,0x02,0x70,0x6b,0xce,0xc4,0xac,0xb5,0xaf,0x25,0x15,0x7c,0xa0,0xf6,0xa2,0xd4,0x8d,0xe8,0x52,0x85,0xfa,0x3b,0xc0,},{0x7f,0xf0,0x3f,0xb4,0xc8,0x2e,0x9c,0x15,0xd6,0x59,0xdf,0x42,0x4b,0x3e,0x73,0xed,0x1d,0x78,0x00,0x6f,0x3e,0x0b,0x79,0xeb,0x64,0xd9,0x8c,0x13,0xae,0xc6,0xba,0x37,},{0x4a,0x64,0x13,0xc2,0xc8,0x7f,0x2b,0x38,0x56,0xa8,0xde,0xcb,0xce,0x49,0x3a,0xde,0xae,0x0c,0x69,0xc9,0x41,0x34,0x70,0x7f,0xb0,0xf1,0x8f,0x30,0x49,0xfd,0x3e,0x3d,0x05,0x1a,0xbd,0xb9,0xd4,0xbe,0xe2,0x53,0xc6,0x10,0x7c,0x02,0xd5,0x7a,0xd7,0xcc,0x9f,0x31,0x01,0xdb,0x66,0x0a,0xfa,0xc2,0xb7,0x98,0x19,0x38,0xe9,0x56,0x4f,0x01,},"\xc2\xdf\x77\xc9\xe4\x79\xf6\x19\x83\xb6\xc7\x48\x3e\xf9\x3f\xb8\x5a\x10\x3b\x21\x39\x23\x92\x65\x23\x06\x5e\xbf\xf2\x25\x7e\x85\x42\x7e\x05\xcd\xc2\x75\x82\xef\x6c\x16\xbe\x35\x3a\x3b\x25\x03\x72\xd6\x37\x0e\xec\xb6\xc8\x96\x29\x17\xeb\x65\x6f\x26\x41\x69\x01\x89\xd1\x72\xa1\x11\x05\x15\x57\xab\xc2\x49\x4e\x32\xca\xb6\x5e\xd0\x63\x3a\xff\xe9\x24\x08\xb5\x5c\x4e\xd8\xaf\x65\xe2\xc5\xe7\xaa\xb8\x87\xa3\xcc\x8d\x28\xc5\x2e\x9e\x13\x36\xd0\xb7\xbb\x3f\xe2\xcd\x84\x3e\x7f\xa1\x68\x03\x42\xf8\xa4\xaa\xfa\x02\xc4\xab\x25\x2f\x08\xc3\xd4\x6d\x5f\x00\xfd\x01\x48\x42\x63\xee\x63\x52\x84\xf6\xdb\x26\xd6\x29\x8d\xe5\xb0\xdd\x23\x8d\xa4\x0a\x8d\x2a\x93\x37\x6d\xa0\x30\x27\x83\xa0\xe3\xbe\x23\xd9\xe7\xf9\x90\xd2\x5b"}, -{{0x8b,0xfc,0xa4,0x84,0x62,0xd2,0x53,0x6f,0x74,0xb8,0x4f,0x6a,0xf5,0x9f,0x5d,0x85,0x82,0xff,0x8f,0x7e,0xc2,0x87,0x45,0xd6,0x72,0xe7,0x2e,0xb7,0x2e,0x79,0xd3,0xe9,},{0x9d,0x10,0xd2,0x75,0xc3,0xd3,0xfe,0x45,0x9f,0x7f,0xe2,0x90,0x1b,0xce,0x38,0x91,0x91,0xcc,0x84,0x83,0xc0,0xf5,0x11,0x40,0xd9,0xc6,0x2b,0x08,0xfa,0xde,0x81,0xbb,},{0x44,0xd7,0x7e,0x43,0x9e,0xf6,0xca,0x5e,0xb9,0x40,0xc6,0x0f,0xf8,0x73,0x2d,0xdc,0x16,0x26,0x9e,0xa0,0x23,0xbb,0x26,0x13,0xbd,0x44,0x7e,0xba,0x7f,0xd6,0x98,0x51,0x22,0x6c,0x48,0x19,0xce,0x8d,0x44,0x98,0x5a,0x49,0xf3,0xf4,0x1a,0xc7,0xaf,0x33,0xc4,0x7f,0xfe,0x5f,0x89,0x30,0x4a,0x32,0x56,0xe4,0x45,0xf8,0xd6,0x86,0xe3,0x07,},"\x81\xee\x4c\xb9\xc4\x5d\xa6\x91\xda\xcd\x7d\xd0\x9a\xff\x59\x73\x72\x67\xbb\x55\xc3\xad\xe1\xba\x32\xc1\x7b\x7d\x0d\x2d\x0c\x60\x79\xc3\x9d\x5f\xd5\xb2\x9b\xa5\xf9\xc1\x76\x20\x97\x70\x98\x43\xee\xe5\x61\x2b\xd2\x0b\xc8\x18\x5b\xf6\x4d\x5c\x93\x41\x84\xe1\x36\x24\xe6\xf8\x77\xa2\xa5\xdd\xa1\x5c\x0d\xf6\x2a\xfb\xb9\x70\x57\xcc\x91\xca\xc9\xa1\x84\x06\xa0\xe0\x10\x9c\xc3\x9b\x2e\x3f\x81\x2e\x22\x7a\x40\x62\xd5\xef\x81\xc9\x2c\x22\xa7\xdc\x79\x7c\x84\x5d\x71\xeb\x6e\xa9\xe4\x2e\xc8\x41\x7f\xba\x90\xa9\x6d\x2b\xb1\x43\x94\x18\x33\x0b\x4b\xb2\xf9\x9c\x6d\x63\xd3\x04\xa0\xe5\x06\xdc\xa9\x65\x3e\x5d\xe0\xdd\x56\xe3\x09\xdb\x1a\x76\xa0\xfa\xab\xab\x16\x37\x74\xf0\x00\x08\x8c\xef\x3d\x1b\x7a\x6c\xf6\x61\xd2\xe1\xd9"}, -{{0xd7,0x48,0x0d,0x42,0x72,0xbc,0xb1,0x55,0x7b,0x1b,0xbe,0xe0,0x49,0x15,0xc1,0x26,0xa5,0x2c,0xa6,0xd6,0xa8,0xbb,0x53,0x14,0xa0,0xe1,0xa5,0x2b,0x59,0xbf,0xc9,0x9c,},{0x99,0xc8,0x39,0xd3,0x6d,0x8f,0x5b,0x86,0x52,0x61,0x8e,0xd7,0xb0,0xfe,0x9e,0xc3,0xd9,0x4e,0xff,0xf4,0xc4,0x53,0xc5,0x40,0x63,0x14,0x76,0xa5,0x97,0x9b,0xbb,0xe0,},{0xe0,0x4d,0xc8,0x44,0x2d,0x35,0x21,0x73,0xe9,0x31,0x81,0x8e,0x29,0x08,0x58,0xde,0x85,0x68,0x8a,0x46,0x49,0xea,0x3e,0x3c,0x3a,0xe7,0x4e,0xda,0xa5,0x4a,0xd0,0x1b,0x64,0x62,0x2a,0xd8,0xa0,0x90,0xb6,0xad,0x60,0xad,0xfd,0x01,0x88,0x18,0x82,0x82,0x8d,0x39,0x07,0x8b,0xb5,0xb2,0x71,0x4f,0xd3,0xea,0x83,0x97,0xa3,0x42,0xfd,0x04,},"\x61\x5c\xc1\x9f\x94\x20\x17\x36\x5b\xa8\xbf\xa2\x56\xce\xcc\xc8\x5e\xe2\x89\xa1\xc3\x4b\xb1\x44\x2a\xcc\x07\x16\xc7\xfc\x2c\xae\xb7\x6a\x9d\xe1\x9a\xde\xc1\x06\x37\x1e\x47\xa3\x0d\x2e\x12\x39\xce\x1f\x7d\xca\x25\x52\x6d\x60\x4b\xdd\x64\x76\x59\xd9\x42\xbc\xba\xc3\x68\x91\x13\x49\xc3\xb9\x46\xa9\x7d\xa1\x0a\x42\xdb\xcf\x3c\x73\x41\x6d\x2e\x6b\xa2\x2b\xd2\x9d\x9f\x70\x56\x72\xe9\xe3\x38\x94\x4c\xef\x01\xad\x21\xf0\x09\x74\x2e\x07\xbc\xd8\x88\xca\x31\xe1\xee\x95\x3e\x8c\x1b\x1f\xd9\x54\xb7\xdc\xf1\xa0\xb1\xd5\xa0\x69\x06\x5a\x66\xcb\x72\x1a\xdc\x02\x0f\x4e\xfe\x1a\xbd\xd1\x67\x42\x74\x69\x39\x28\x57\x80\xd7\x53\x13\x7a\xe0\x14\x0b\xb4\x10\xfb\x6c\xe3\x36\x76\xc2\x7a\xee\xc5\x93\xa8\x8c\xbc\x73\xaf\xd9\xf4\x05\x11"}, -{{0x3c,0x2d,0x36,0x50,0x73,0x5b,0x41,0xef,0x90,0x06,0xbb,0x45,0xe4,0xbe,0x2e,0x0a,0xa5,0xcd,0xe8,0x51,0xae,0xac,0x42,0x1e,0xe9,0xc1,0xb4,0x92,0xd8,0x7a,0xa1,0x8a,},{0x3e,0x46,0xdd,0xce,0x29,0x88,0x44,0xfc,0xaf,0xa0,0x0a,0x1b,0x47,0xea,0xf3,0xde,0x70,0x59,0x6d,0xf1,0xbb,0xee,0x3c,0x80,0x9d,0x1b,0xe7,0xdd,0x94,0x08,0x0e,0x34,},{0x3f,0x2a,0xf0,0x1a,0xd5,0x37,0x7a,0xc3,0x90,0x40,0xd4,0x1a,0x41,0xe3,0x6e,0x7b,0x93,0xfa,0x72,0x35,0xb8,0x41,0x79,0x1f,0x43,0x2e,0xcd,0x7f,0x91,0xa3,0xb2,0x1a,0xb7,0x19,0x6c,0x88,0x3a,0xd5,0xa7,0xdb,0x44,0x6f,0x6c,0x06,0x67,0x24,0x60,0xf3,0xf6,0x3e,0xf8,0x63,0xd9,0x43,0x2b,0xe9,0xca,0xea,0xbb,0x79,0xe8,0x7e,0x22,0x08,},"\x14\x25\xd8\xd2\x18\xda\x1a\x10\xa8\x0b\x6a\x9c\x3c\x27\x50\xef\xe4\x16\x57\x98\x4a\xbd\x51\x00\xf4\x51\xba\x94\x9d\xb0\x10\x46\xb7\x12\x6b\xe8\x40\x23\x34\xed\x57\x52\x8b\xac\x05\x62\x25\x53\xa8\x6b\x72\x67\x22\x69\x5a\x8f\xb3\x31\xd8\x56\x54\x17\xc4\xff\x0f\x25\x1a\x32\x0a\xd0\x6d\xed\xbb\x75\x0d\xef\x35\xd5\x21\xc3\xc4\xcd\x57\x1a\x45\xad\xa8\x45\x06\x53\xd5\xe8\x1f\xe0\xbe\xb5\x3a\xaa\xe7\x87\xb3\xeb\x65\x3c\x23\x81\xed\x55\xaa\xf2\x59\x0e\xe5\xed\x8b\x66\x26\xf1\xc4\xb0\x43\x0a\x54\xf3\x96\x58\x62\x4e\x66\x35\xfe\xfc\x98\xfe\xe8\xfc\x3e\x1c\xc7\xff\x3d\xd4\x20\xde\x9d\xa1\x1a\x62\xfc\xae\x0e\x0c\xb4\x54\xfc\x6f\x7d\xf0\x39\x54\x29\x1d\x26\x20\x2f\x1b\x18\x8b\x65\x7b\x3b\xae\x07\x38\x94\x49\xb7\x5e\x67\x42\x2f"}, -{{0x74,0x96,0x59,0x96,0x26,0x8c,0xdc,0x4c,0x09,0x22,0x0b,0xd3,0x1c,0xe0,0x7b,0x21,0x7a,0x03,0x82,0x6e,0xe9,0x81,0xfa,0x89,0xf3,0xa2,0x35,0x9c,0xed,0x09,0x5e,0xf1,},{0x40,0x96,0xd0,0x27,0xc1,0xc5,0xee,0x4c,0xbf,0xc0,0x4b,0x9d,0x53,0x41,0x74,0x02,0x9f,0xdb,0x50,0xcf,0x56,0x10,0xd3,0x02,0x1e,0xf9,0x33,0xb4,0xca,0xf3,0x39,0x85,},{0x8c,0x66,0x28,0x34,0x43,0x17,0xa6,0x3a,0xca,0x6f,0x78,0xcf,0xae,0xa9,0x65,0xb3,0xaa,0x55,0x22,0xce,0x91,0x41,0x95,0x14,0x1c,0x08,0x87,0x0a,0x1b,0x8d,0xac,0xf3,0x4b,0x79,0xc7,0xab,0xc6,0x93,0xcd,0x9e,0x5e,0xbe,0x1a,0x2e,0x86,0xf0,0x33,0x2d,0x20,0x48,0xdb,0x3c,0xbd,0xef,0x01,0x68,0x79,0x62,0xd6,0xdf,0x24,0x9e,0x38,0x00,},"\x45\xb2\xf0\x64\x61\x5b\xf7\x74\xfc\xe9\x7f\x51\xc4\x64\x68\x5d\x7b\x3e\x4f\xef\xff\x92\x31\x24\x0a\x71\x9b\x3b\x06\x21\xcd\x4a\xd8\x33\x05\x67\x5c\xd6\xea\xae\xbf\xf7\x91\x00\x0b\x0b\x1f\xa3\x1d\x82\xd8\x18\x1b\x7f\xe5\x7c\x5e\x00\xce\xc5\x6f\xf9\x02\x2e\x9c\xe8\xdb\x66\x35\x6e\x40\x8e\x3e\xe2\x62\xfe\x62\x77\x89\xe6\x55\x35\xef\x1a\x63\xe8\xfe\xc9\x33\xbe\x3d\xee\x34\xd2\xfa\xcd\xb8\x92\x8c\xc4\x56\xab\xf2\xf3\xe8\xca\xb4\x7e\xff\x1c\xa4\x2e\x8b\x0e\x48\xd2\xc7\x3e\x7b\xcc\x5d\xe3\xf1\x05\x6f\xc5\x23\xdf\xef\x6b\x00\x23\xf3\x28\x89\xed\x39\x4e\xed\xa0\x32\xab\xf6\xbc\xaa\xda\xa7\xf3\xee\x74\x11\x87\x60\xab\x6d\x91\xdf\x52\x8b\xdc\x58\x07\x97\x2c\x85\xfa\x7c\xb5\x6e\x38\x7d\x73\x32\xe7\x79\xe5\x2d\x0d\xd7\xdb\x0c\xfb"}, -{{0x0a,0xbf,0x06,0x9c,0x08,0xb2,0x69,0x1c,0x3a,0x26,0xf7,0x9d,0xc8,0xed,0x05,0xcb,0x71,0xd2,0x20,0xff,0x78,0xf3,0xa5,0xc5,0x78,0x0a,0xe9,0xda,0x18,0xe4,0x56,0x43,},{0x9e,0xf3,0xb5,0xcc,0x01,0x6c,0xc8,0x2d,0xbd,0xda,0x70,0x57,0x66,0xaa,0x44,0x8b,0xd6,0x1f,0xa1,0xaa,0xf1,0x17,0x0e,0xfe,0x91,0x49,0xda,0xa9,0xfe,0x64,0xa1,0xae,},{0xc7,0x56,0x6f,0xb3,0xb4,0xd8,0xde,0xf6,0x67,0xe0,0x40,0xf2,0x76,0xd3,0xed,0x98,0xd3,0x6d,0xff,0x46,0x01,0x26,0xa7,0x5b,0x4c,0xc2,0x10,0x03,0x86,0xbb,0x01,0xc6,0x42,0xf6,0xd8,0xde,0x7e,0x64,0x9b,0xe6,0xe0,0x81,0x8b,0x08,0xd7,0x7c,0xe6,0x0f,0x4e,0xe5,0xe7,0x71,0x7a,0x50,0x88,0x4b,0xde,0xe0,0x20,0x34,0xec,0xf1,0xcd,0x0c,},"\x0d\x05\x52\x91\xb2\xe8\x61\xea\xe1\x9e\xa0\xfb\x20\x69\xd8\xc9\xee\xf4\xf1\x34\x7f\x35\x76\xd7\x84\x11\xae\x7c\x0b\x1c\x1c\xaf\x31\xfd\xe7\x36\xdc\x8a\xcc\xac\xb6\x62\xdf\x76\xb6\x20\xb6\x2c\xe9\x0b\x9f\x92\xc8\x33\x09\x12\x86\x21\xd0\x57\xcf\x84\x58\x05\x94\x90\x88\xe9\x38\xdd\xbc\x3d\x41\xc5\xe5\x54\x1f\xec\x82\x98\x68\x7a\xd2\xf7\x9a\xcd\xa0\x1a\xa2\x15\xd2\x58\x21\x43\x6e\xac\x9d\x26\x87\x16\xd4\xcd\x60\x50\x26\x0c\xb4\xef\x6a\xad\xa4\x83\x5e\x07\x3a\x84\x58\x21\xff\x21\x1a\xe2\xba\xad\xce\xb6\xe5\x7f\x06\xf8\x83\x45\xed\xbf\x93\xbf\xdf\x54\xfb\x74\x12\x3b\x57\xc0\xfb\x4a\x79\x60\x8d\x8d\xb6\x74\x08\x89\xe1\x57\x33\x50\x77\x99\xf7\xa1\xfd\x30\x17\xbc\xd7\x7b\x28\xa2\xbb\x6c\x91\xec\xd1\x54\xe9\xc5\xa5\xff\xa0\xeb\x62"}, -{{0xf3,0xfd,0x5e,0xc5,0xe2,0x30,0xb6,0xda,0xd1,0xac,0x3d,0x3a,0xeb,0xad,0xc7,0x86,0x3f,0xf8,0x9d,0xe2,0xa1,0x31,0x7f,0x42,0x4d,0x15,0x98,0x9a,0x3e,0xfb,0x0a,0xfd,},{0xf9,0x9e,0x5d,0x5e,0xee,0xae,0xd1,0x20,0x5c,0xfb,0x5c,0x2c,0xc4,0xe5,0xe9,0xf6,0xb4,0xe7,0xf6,0x41,0x29,0xf8,0x60,0x10,0x4c,0xa6,0x24,0x4e,0xb9,0xfe,0xb5,0x64,},{0x44,0xb0,0x12,0x46,0x63,0xad,0xb0,0xc7,0x3a,0xed,0x49,0xf7,0x34,0x03,0x46,0x1f,0xcb,0x19,0x11,0x1b,0x0b,0xa1,0x7a,0xa9,0x96,0x56,0x6f,0x47,0x7e,0x37,0xd5,0x24,0xb0,0xe1,0xf1,0x07,0x61,0x2f,0xc5,0x2a,0x7c,0x76,0x7b,0x18,0x1f,0xbf,0x4d,0x62,0x9b,0xdd,0xc0,0x8f,0x30,0x58,0x4d,0xec,0x61,0x24,0xc5,0xd3,0x9d,0x42,0x31,0x02,},"\x71\xf2\x89\x73\xed\x3d\xf0\x59\x45\xfa\x0b\xdb\x23\xe9\xbe\xca\x65\x1d\x3e\xe6\xbf\x9f\xa4\x5f\xfd\xc6\x06\x1e\x42\xfa\x2e\x8d\x76\x23\x5f\x0e\x9e\x2d\xaa\x65\xe5\x26\x31\xfc\x3b\xea\xd3\x3d\xa0\x55\xbb\x49\x2e\x47\x58\xe5\x98\xa0\x30\xa3\x3b\x3c\x40\xb3\x43\x71\x45\x9b\x23\x3c\xcc\x04\x3c\xcc\xc3\xa3\xcb\xce\x54\x9e\x20\xe0\xb2\xb4\x33\x05\xb6\x4a\xec\x66\x1a\xad\xba\x65\x56\xb1\x7d\x76\xe3\xbb\xed\x62\xc4\xa4\xea\xc4\xf8\x86\x03\x99\x67\x52\xd2\x36\x3c\x8d\x4a\x27\x89\xd1\x28\xf6\xe9\x59\x94\x5c\x68\xc3\x01\x46\xd1\x94\xcc\xb6\x83\x9e\xc6\x53\x44\x60\x16\x52\xc1\x8b\x00\x74\xe2\xbc\x76\x68\x31\x16\x97\xd9\x60\xc7\x06\x65\x97\x92\x4d\x70\x4d\x02\xa0\x19\x3f\xaf\xbf\xdf\x57\x1e\xe0\xdf\xe4\x14\xdc\x2f\x52\x89\x69\x12\xbc\x32"}, -{{0x73,0x8f,0x13,0x10,0xa4,0xe0,0x8f,0x91,0x7a,0x0a,0x5c,0x1f,0xba,0xf4,0xef,0x72,0xf9,0x5e,0xe6,0x2f,0xcd,0xed,0x50,0x86,0x8a,0x3d,0xaf,0x98,0x85,0x6a,0x44,0x8d,},{0x42,0x27,0x2c,0x2c,0x8b,0x08,0x47,0x0e,0xe5,0xdd,0x8a,0xf8,0x84,0x9c,0x01,0xb7,0x50,0x8d,0x3a,0x3c,0x65,0xb0,0x33,0x0e,0x69,0x5c,0x84,0x1d,0x5d,0xcc,0xb2,0xf5,},{0xce,0x1e,0x35,0x77,0xb6,0xa2,0x10,0x16,0xb9,0xdd,0x0b,0x51,0x7b,0xaa,0x0c,0xcb,0x10,0x7b,0xc1,0x99,0xb8,0xbb,0xae,0xf6,0x8f,0x95,0x0c,0x8e,0xd5,0x80,0x13,0xc8,0x53,0xb4,0xd3,0x38,0xee,0xdc,0x67,0x50,0x79,0xab,0x13,0x90,0x46,0x2f,0xfe,0xfa,0x6a,0x95,0x9b,0x04,0x3f,0x8b,0x56,0x51,0xc6,0xca,0x37,0x5c,0xe0,0xb4,0xa4,0x03,},"\xf0\xe7\xef\x67\x82\xd0\x4c\x69\x43\xb1\x9e\xb6\x6f\xf6\x22\x6b\x73\x6e\x3b\x09\x40\xc0\x9b\xb1\x26\xbf\xc4\xc4\xca\x7a\x5e\x70\x16\xc2\x86\xb7\xbf\xd7\x3a\xa6\xa7\x9a\x96\x03\x1b\xc8\x1c\xb5\xda\x68\xce\xc7\x1a\x6a\x0d\x39\x78\x0c\xbe\x6a\x0c\xd4\x77\x4d\x3a\xa0\x6a\x88\x16\x10\x44\x4a\x8c\x9d\x19\x10\x22\x94\xe5\xf6\x35\x18\x7a\xa6\xf4\x8d\x11\x91\x2c\x70\x94\xb3\x88\x33\x02\x8d\x57\x0c\xb1\x10\xdb\x60\x62\x5b\xb1\xbd\xc3\x7a\xff\xa2\x5e\xa3\xc8\xf8\xdb\xfc\x25\x14\xf4\x36\x5c\x62\xb2\x98\x9a\x66\xd2\x7c\x80\x38\x4e\x74\xae\x5f\xba\x8c\x1c\x2a\xf9\xc7\x2c\x49\x71\xe6\x4f\xa6\xa1\xdc\x25\x17\xb3\x1e\xa5\x7c\xcb\x08\x15\xa7\xfe\x2d\xa0\xf1\x46\xca\xa0\x84\x31\xd2\x5d\x15\x16\x62\xd9\xd2\x6e\x95\x22\x9d\x0c\x62\x82\x36\x64\x12\x3c"}, -{{0x88,0x41,0xd2,0x2a,0xde,0xd6,0x9c,0x13,0x1e,0xf5,0xee,0x0a,0x10,0xab,0x0a,0x9b,0x77,0xcb,0x75,0x4e,0xde,0x8d,0x25,0x7a,0x53,0x72,0x72,0x6e,0x2b,0x49,0x9c,0x6e,},{0x71,0x5e,0xcc,0xa6,0x36,0x81,0xbc,0x6e,0x9e,0x31,0xd1,0x88,0x48,0x90,0x2f,0x4d,0x96,0xfe,0xaf,0x43,0xb9,0x5d,0x00,0x86,0x42,0x90,0x3b,0x17,0x63,0xbc,0x9f,0xb8,},{0xbb,0x2b,0xab,0x70,0x03,0xf1,0x31,0x1b,0xe9,0xb8,0xc8,0x83,0xfc,0x4f,0xd5,0x28,0xad,0xfd,0x51,0xa9,0xc9,0x9d,0xb3,0xdc,0xa8,0xda,0x0f,0xca,0x95,0x8d,0xa1,0x9a,0x10,0xeb,0x22,0x33,0x26,0x67,0xb1,0xa0,0x06,0x5d,0x3d,0xbc,0x0d,0x06,0x26,0x9a,0x12,0x59,0xb6,0xa8,0x90,0x48,0x4a,0xa2,0x14,0x3a,0x52,0x69,0x5f,0x14,0x5b,0x0a,},"\x08\x7c\xa6\xbe\x2a\x95\x0c\x02\x4b\x3e\x74\x67\xfe\x00\xa7\xd3\x64\x55\x5d\x5d\xc6\x77\x0f\x5e\xbd\x26\x06\x42\x52\x5b\xd3\xc0\xf9\x65\xdb\x36\xd7\xb2\x29\xa5\x74\x21\xee\xc6\x4e\x4d\x99\x1c\xdd\xe5\x91\x23\x03\x44\x70\x55\x3f\x4e\xb0\xbe\x81\xad\x29\x36\xc8\xca\x26\xbc\xab\x4e\x5d\x79\x04\x0e\x29\x79\x87\x28\x60\x16\x84\xa4\x68\x32\x3c\xf3\xba\xae\x4d\x94\x8d\x0a\x1f\xd9\x05\xef\xfe\x16\xdc\x44\x64\x20\x88\xdf\x53\xf6\x38\x8b\xc4\x80\xed\xf4\xaa\x20\x7d\x0e\xd1\x61\xed\xa3\x45\x71\x2b\x4c\x00\xcb\x05\xfc\xf6\x35\xec\x25\x88\x78\x5b\xfb\x8a\x27\xcd\xc2\x89\x96\xa1\xdb\x3e\x67\x87\x02\x33\x93\xc0\x75\xd8\x3c\x90\x38\xfe\xd7\x89\x9c\x55\xfe\xc3\x07\xde\x32\x49\xc1\x4b\xda\x49\xe8\xb8\x95\x86\x09\x42\xc3\x6d\x64\x0b\xb8\x93\x77\x91\x42"}, -{{0xc0,0x21,0x35,0xe7,0xb6,0x5a,0xac,0x72,0xf6,0x3c,0x32,0xbf,0x5b,0xef,0x5b,0x68,0xc7,0xf3,0xb8,0xed,0x56,0x20,0x8e,0x59,0xe4,0x75,0x20,0x70,0xe9,0xd0,0x70,0x95,},{0xdc,0xf6,0x00,0xf2,0x44,0x03,0x7a,0x75,0x20,0x3a,0xe1,0x1a,0xc3,0x16,0xe8,0xdb,0xe9,0x98,0x6f,0x0d,0xce,0x23,0x47,0x39,0x39,0x33,0x4b,0xf5,0xce,0xa4,0x8b,0x0d,},{0xdd,0x5c,0xba,0xe4,0x79,0xeb,0x5e,0x22,0x95,0x74,0xc2,0x1e,0xc3,0xbe,0xd9,0x11,0x11,0x3a,0x57,0xa1,0x91,0x6d,0x33,0x13,0x45,0x75,0x15,0xd5,0x5c,0xc5,0xb6,0xe6,0xeb,0xc5,0x2c,0x93,0xf8,0x21,0xd1,0x39,0x88,0xdb,0xba,0x8d,0xf5,0x09,0x6d,0x55,0xff,0x9c,0x39,0xe7,0xf9,0xd5,0x61,0xcb,0x58,0x93,0x0c,0x96,0xa7,0xa5,0xd6,0x0b,},"\x86\xd9\x49\x13\x50\xd2\x56\x6e\x70\x8e\xd3\x56\x18\x5d\x61\x0c\x73\x46\x5b\x2a\x5c\x70\x12\x91\x99\x58\xaf\x2c\xf7\x6a\xf9\x95\x23\x0d\x36\x0d\xe4\x00\xb7\x13\x71\x70\xdd\x08\x35\xf1\x0f\xcb\xec\x22\x4e\xe4\xe4\x2c\x7d\x1c\xeb\xb7\xf5\x80\xfe\xa8\xed\x62\x23\x16\x3b\xac\xdd\x19\x23\xa5\x72\xcb\xb6\xdc\x26\xca\x8b\x17\xad\xe6\x8c\x6d\x28\x08\xc4\xca\x1e\xca\x28\xea\xe9\xa1\x45\xf6\x8d\x40\x79\xd8\xd5\x9d\x14\x0e\x95\x82\x28\xe7\xe9\x95\x20\xe3\x42\xdb\xd7\x45\x7a\x91\x59\x74\x0f\x48\xbd\xc2\x7b\x93\xbd\xab\xeb\xa4\x65\xcb\xf0\xc8\xdf\x5e\xf2\xc0\xf9\x38\x6e\xeb\xe6\x56\xf5\xd7\x49\xd5\xf9\x14\x7f\x52\x52\x66\x91\x0d\x7b\x80\x39\x6a\x90\xbe\x5c\xc1\x88\xa9\xa9\x45\xf9\x3e\x75\x3f\xc9\x9b\xaf\xa1\x8e\xe0\xa6\xdf\xf7\x9b\xf8\x48\x48\x98\xef"}, -{{0x15,0x4a,0x47,0xeb,0xa1,0xb8,0xc3,0x83,0x62,0xea,0x61,0xfa,0xeb,0x0c,0x0a,0xd7,0xe6,0x1e,0x41,0x2a,0x3c,0xba,0x46,0x88,0xaf,0x0d,0xb2,0xa4,0x87,0x20,0x8b,0x1c,},{0x16,0xde,0x2c,0x89,0x4a,0x50,0xcb,0xd4,0xca,0x90,0x41,0x9a,0x4c,0xa6,0x49,0x42,0xcb,0x14,0xbd,0x33,0x5c,0x5d,0x3f,0x4a,0x53,0xe2,0x39,0xc2,0x80,0xbd,0xa7,0x25,},{0xf4,0xb6,0xeb,0x1a,0x8d,0x95,0x0e,0x88,0x7f,0xd2,0xf3,0x0f,0x70,0xa2,0x3b,0x41,0x87,0x14,0x95,0xbf,0xa5,0xb8,0xa4,0xad,0x39,0x96,0xcd,0x9b,0xf5,0x1e,0xb7,0x42,0xe0,0x7f,0x4c,0x4d,0x2d,0xa4,0xb0,0x1a,0xb0,0x87,0x36,0x7a,0x50,0xe2,0xb6,0x5b,0x3c,0xef,0x51,0x4e,0x40,0xd8,0x37,0x54,0x0b,0x8c,0x89,0x96,0x64,0x85,0x91,0x0f,},"\xbf\x60\x7e\x8b\x6e\x14\xd9\xc8\xac\xd9\x68\x15\xaf\x0c\x03\x5a\xc7\x3c\x41\x04\xc9\x37\x86\xcc\xc1\xc9\xf8\x59\x39\x5d\xd7\x81\x90\x03\x20\xeb\xf3\x56\xaa\x99\x1c\xdc\x9f\x50\x3f\xce\xe9\xf8\x36\x75\x88\x8a\x7d\x59\x20\x02\xd2\xa5\x4a\x57\x3a\x96\x99\x4b\x3f\xa8\x65\x53\x8c\x61\x7e\xd8\xad\x1f\xf6\x20\x18\x28\x8a\x67\x4f\x44\x9b\xe0\xaa\xb5\x22\x2f\x74\xc4\xfd\x47\x5e\xd6\xa8\xdf\xb2\x7f\x45\x28\x7b\x22\xb2\xb6\xc3\xbd\x15\x17\x9f\x26\x7d\x15\x7d\x7d\x8a\x41\x59\x67\x9b\xe8\x5b\x25\xc2\xbb\x2b\xa8\x50\xaa\xed\x9a\xe3\xae\x57\x1b\xe4\xf7\x58\x36\x32\x9c\xf3\x6f\x41\x2c\x1c\x80\xf1\x41\x3b\x76\x61\xea\xb4\xa8\xe1\x1b\x60\x24\x24\x4f\xc6\x23\x23\xff\x02\xe3\x8a\xce\xb1\x73\x7b\xd4\x74\xbf\x1e\x98\x01\x5d\xbc\x78\x8b\x02\x7b\xbe\x21\x7c\xf4\xe7"}, -{{0xd3,0x02,0x84,0x31,0xce,0x2e,0xef,0x73,0xbd,0x94,0x0a,0xb8,0x4c,0xa2,0x9f,0x13,0xfb,0x26,0x43,0x6a,0xa2,0x5e,0x1b,0x7b,0xf2,0x6c,0xb3,0x3f,0x17,0xfd,0xf8,0x17,},{0x63,0xdf,0x20,0x3e,0x28,0x60,0xba,0xc4,0xd3,0x52,0xe7,0x22,0xc1,0xc9,0x1f,0xe3,0x77,0x6e,0x1c,0xbc,0xae,0x85,0x53,0xa4,0xf1,0x98,0x90,0x26,0x0b,0xf0,0xe4,0x57,},{0xce,0x97,0x29,0xa9,0x6c,0x3e,0xd2,0x89,0x43,0xb2,0x78,0x39,0xc7,0x33,0x82,0xec,0xd5,0x72,0x96,0x0c,0x1f,0x9e,0x90,0xc5,0xef,0xf9,0xdd,0x49,0x9f,0xf4,0x8f,0x17,0xd2,0x5e,0xdd,0x12,0x68,0xef,0xfe,0x41,0xee,0x6a,0x81,0xce,0x48,0xd8,0x4d,0xe5,0x13,0xdf,0x9c,0x41,0x44,0x26,0x21,0xb2,0xf5,0x49,0x1e,0x34,0x6b,0xe1,0x8c,0x04,},"\x08\x63\x35\xd6\x12\x75\xd1\x68\xea\xac\x05\x40\x47\x7f\x50\xd4\xb1\x5f\x9e\x50\xb9\xbe\x69\x39\x21\xed\x54\xa9\x94\x1b\xc4\x06\x43\xcd\xa6\x2e\x1d\x80\x5d\x02\x50\xa8\x11\x46\xbd\x5f\xe2\xd3\x9e\x81\x44\x4d\x21\xe2\xb2\x1b\x03\x1c\x11\x13\x06\xca\xcb\xf5\x27\x17\xf6\xfb\x4c\xd3\x41\x6f\x12\x15\xf8\xdd\xdc\xed\xd2\xf0\x09\x6b\x0f\xcf\xa0\xa6\xcc\x2c\xde\x7a\x2b\xab\x7f\x1e\x32\x79\x0b\x53\x61\xdf\x36\x71\x42\x4c\xc7\x22\xf2\x31\xbf\x71\x89\x5b\xcd\xcb\x7b\x22\xee\x07\x4e\x8f\xb4\xa9\x67\x85\x04\xe7\x35\x36\x6c\x17\x2f\x07\x63\x7b\x7a\x93\x14\x9b\xb2\x1f\x38\x88\x33\x78\xa1\xdb\x27\x3f\xc2\x32\x39\xe3\x53\x37\xf9\xce\x56\x6d\x8d\xdf\x3b\x31\x33\xca\xd7\xf2\xce\x81\xed\xb5\x03\xce\x1d\x27\xc5\xa6\x57\x16\x0b\x78\xdc\xa9\xae\xae\xa3\x79\xbe\x9c\x85"}, -{{0xee,0x89,0x85,0xdc,0x27,0x50,0x44,0x40,0xa8,0x75,0x8d,0x4c,0x53,0xe4,0x22,0x52,0x15,0x79,0x7a,0x00,0xcd,0x86,0x31,0xd5,0x9b,0xd9,0x3b,0xc6,0x6f,0x37,0x3d,0x5e,},{0xcd,0x64,0x7b,0xb0,0x65,0x69,0x3d,0x48,0x65,0x89,0x15,0x6a,0x9f,0xa2,0x61,0x43,0x75,0x34,0xdc,0x86,0xf4,0x6f,0x72,0xd0,0xa8,0x00,0x39,0x9a,0x7a,0xf0,0x10,0xf7,},{0x5b,0xd6,0x0a,0xd5,0xe9,0xba,0xd9,0x93,0x2c,0xa9,0xc7,0x5f,0x23,0x1a,0x76,0x88,0x9a,0xe7,0xa8,0xb8,0x64,0xb9,0x1d,0x1f,0xcb,0xa5,0xc5,0xd4,0xbf,0xa1,0xd9,0x28,0x38,0xad,0xb9,0x74,0x84,0x2a,0x07,0x10,0x77,0x9b,0x3e,0x30,0x94,0x04,0x49,0x09,0xe9,0x2c,0x7c,0xf0,0x46,0xce,0x51,0x9f,0x4c,0x68,0xe8,0xf1,0x9e,0xc0,0x3c,0x02,},"\xf2\x22\x04\x85\xad\xdf\xeb\xce\x02\xa8\x33\xac\xa3\x33\x81\xd1\xdf\x91\x7e\xd6\x09\x95\x0e\xd2\x4f\x85\xe3\xb0\x2b\x2b\x99\x4b\x4d\x93\x97\x84\xe3\x32\xf4\x10\x64\xc8\xb4\xa2\x63\x0a\xb3\x69\x61\x74\x2a\xa1\xcf\xfd\xcb\x08\xc1\x44\xee\xae\xde\xaf\xd4\x8b\x5d\xbe\x96\xbf\x24\x35\x0e\x14\xfd\x68\x28\x6b\xc0\x8e\xea\xef\x8b\xc6\xad\x9e\x19\x5d\x14\x84\xaf\xcd\x30\xaf\xa8\xce\xd4\x84\x81\x26\xd5\x6c\x81\xb4\x3c\x27\xa5\xdb\xbd\xec\x1a\x50\xc1\x10\x62\xce\x21\xc6\x1d\x86\x0c\x25\xa8\x62\xfb\xb7\x5c\x3b\xd5\x1c\x8d\xc0\x76\x36\x66\x86\x69\xbb\xf7\x51\xea\xca\xcc\xb3\xb5\x1d\x2c\x0d\x41\x40\x31\x6c\xfc\xe2\xeb\x18\xd2\x90\x8c\xec\xd5\xa1\x88\x67\x9b\xc5\xf5\xde\x29\x0f\x54\x8e\x7e\xbc\x57\xd4\x1b\x58\x9a\x24\xce\x88\xee\x48\xd9\x7e\x8d\x0c\x7c\x76\x99\x60"}, -{{0x80,0xdf,0xe2,0xbf,0x73,0x87,0xba,0xd4,0x65,0x4e,0xb0,0x76,0xf8,0xda,0xe9,0x59,0x51,0x63,0xe4,0x01,0x27,0xf5,0xdf,0x49,0x2d,0xad,0x7d,0xf0,0x4c,0x72,0x21,0xc4,},{0xd1,0x78,0x3c,0xee,0xb9,0xcf,0x8e,0x4d,0x07,0x76,0x4c,0x47,0x3f,0xa4,0x06,0x1b,0x82,0x74,0x39,0x71,0x03,0xf2,0x07,0x6d,0x70,0x32,0x49,0xd7,0x58,0xb8,0xfb,0xd5,},{0x27,0x27,0x9e,0x3c,0xdc,0xb0,0x3e,0xf5,0x57,0xa5,0xde,0xfc,0x2f,0x6c,0x58,0x12,0x8a,0x6d,0xc3,0xf8,0xb0,0x38,0x59,0x58,0x01,0x4e,0x70,0x9c,0x1f,0x61,0xb0,0xae,0x6b,0x40,0x35,0x76,0xf0,0xe4,0x54,0xd5,0xe4,0xc6,0x4c,0x17,0x31,0x38,0xee,0x4b,0xbd,0x5f,0xe7,0xb6,0x0d,0x06,0xc5,0xab,0xe2,0x3f,0xe9,0x9e,0xe3,0xb4,0x6a,0x00,},"\xaa\x09\xd7\x84\xbb\x09\xdc\x99\x99\x31\xeb\xb4\xc0\x0e\x42\x4c\xef\xec\xa1\x04\x81\x8d\x8e\xaf\x06\x61\xf0\x97\x28\xad\x02\x5e\xf4\x73\x93\x21\x05\x71\xf1\x74\x04\xe9\xaa\x6d\x8c\xbd\x5f\xd8\x8c\xd7\xdf\xb8\xe2\xe8\xa1\x08\xc0\x5d\xe2\x06\xf3\x40\x82\x34\xa3\xb4\x63\xdb\xe7\x1a\x07\xd0\x55\x87\x32\x45\x24\xb7\x32\x6e\xe7\x9d\x33\x48\xdd\xbe\xd7\x87\x1b\x86\xfc\xb4\x88\x03\x1d\xc9\xea\x93\xf6\xb8\xd7\xfd\xa6\x23\x93\x48\xa5\x62\x44\x4f\xaf\x1e\x72\xd3\x1a\xf3\x54\x43\xe9\xdf\x53\xe7\x62\xf3\xe5\x6b\x48\x66\x8f\x97\x84\xb3\x36\x8a\xb2\x78\xa4\x8e\xf4\x54\x6a\x26\xcf\xad\x0d\x0a\x51\x61\x69\x8f\x26\xee\x8d\x34\xfc\x2b\x3d\x6d\xfb\x93\xb0\x09\xac\x29\x6f\x6a\xfe\x48\x7e\xe3\x35\xea\xc9\xf0\x2c\xfc\xae\x5f\xcb\xd1\xa1\x6b\xa4\xe7\x1b\xe1\xb1\x12\x56\x2f\xc2"}, -{{0xda,0x1f,0x86,0x85,0x42,0xcd,0x7c,0xce,0x7a,0x5c,0xa3,0xfa,0x3c,0x24,0x08,0x1b,0x4d,0x23,0x44,0xb2,0x1a,0x15,0x7f,0x02,0x64,0xa3,0x47,0x13,0x2d,0x19,0x65,0x9d,},{0xcb,0x3a,0x25,0xa5,0x3f,0x27,0x2e,0xa8,0x13,0x80,0x44,0x68,0xd6,0x50,0x0e,0x96,0xa1,0xea,0xf8,0x22,0x70,0x5b,0x77,0x90,0xa8,0xac,0x3e,0x98,0xcc,0x4e,0x52,0x4b,},{0x75,0xc5,0x17,0xad,0xe4,0xf0,0x8d,0x77,0x46,0x30,0x57,0x43,0xd1,0xa7,0x76,0xc3,0xc5,0x5e,0xb5,0xee,0xdf,0xdf,0xcb,0x5e,0xb1,0xd5,0x63,0x4a,0x1b,0xda,0xf7,0xa4,0xb8,0xd2,0x41,0x87,0xd6,0xc8,0x85,0x0e,0x3c,0xed,0x65,0x67,0xa0,0x3c,0x4c,0x59,0x38,0x9a,0x4c,0xf4,0x71,0x14,0xce,0x54,0x73,0x16,0x0f,0x23,0x05,0x46,0xe6,0x0d,},"\xc6\x98\x7e\xf3\x80\xd5\xd0\xe7\x41\x96\x44\x3a\xaa\x3a\x32\x35\x6c\xbc\x02\x63\x6c\x5a\x4b\x6d\x62\xa8\x11\x4b\x21\x11\xbc\x1a\xbd\xdd\x9e\x44\xb3\x67\x2c\x18\xb5\x8d\x4e\xf5\x91\xaf\x45\x62\xe0\x20\x04\x9f\x8e\x12\x74\x68\x8e\x1f\x8e\x52\x96\xd2\xf9\x25\x2e\x7f\xc8\x4c\xd1\xd0\xc5\x8e\x98\xf0\xf1\x60\x53\x0a\xa2\x2c\x87\x1e\xef\x65\x2e\x71\x97\x4c\xe9\x1b\x4a\x65\xfc\x25\xfd\x09\xfa\x1b\x6c\x32\x08\x6e\x98\xec\x70\x8d\x9a\xbc\xb1\xd9\xcc\x8e\x1a\x08\x9e\xd8\xdb\x22\x06\xee\x95\x70\x23\x6a\xd6\x9b\x3d\xe6\x82\x18\x62\xfd\x2c\x70\xcd\x83\xa3\x2a\x68\xb0\x48\x62\x29\x55\x3d\x92\x8d\xe4\x8d\x03\xa1\x04\xe8\x73\x81\x96\x4a\xbe\xa7\x66\x83\x97\x6d\x52\x7c\x84\x16\x3a\x12\xee\xe0\xa5\x59\x86\xcf\x14\x31\xe9\xc8\x6c\xba\x81\x82\xca\x94\x68\x9b\xac\xd1\x65\xfb\xce"}, -{{0xf1,0x3d,0xae,0xc0,0xef,0x33,0xdd,0xd1,0x33,0xc7,0xd2,0x44,0xd1,0x0f,0xd2,0x7d,0xdb,0x23,0x70,0x52,0x80,0xff,0x5f,0x18,0x15,0xf0,0xf6,0x56,0xd8,0x36,0xfe,0x84,},{0x2d,0xc7,0xf1,0x36,0x7d,0xe6,0x72,0xc5,0x1e,0x00,0x5c,0x74,0xf8,0x76,0xf9,0x82,0x59,0x39,0x96,0x87,0x3a,0xcb,0xa0,0x79,0x29,0x27,0x34,0xc2,0x09,0xc2,0xb1,0x11,},{0xdb,0x77,0x18,0x33,0xf7,0xfd,0xba,0xcd,0xab,0x2b,0x5c,0xc8,0x0e,0xed,0x50,0xaf,0xdf,0x13,0x78,0x3b,0x7f,0xe5,0xe9,0x03,0xd5,0xdb,0xb4,0xc2,0xe5,0x35,0x31,0x6a,0x6e,0xef,0x4c,0x34,0xf0,0x04,0xd2,0xb9,0xa4,0xe2,0x70,0x0b,0xd6,0xe2,0xac,0xdd,0x56,0x4c,0x3c,0x80,0xcc,0x68,0xa3,0x03,0xf5,0xfb,0x09,0x1c,0xb4,0x34,0x0f,0x0a,},"\xec\x02\xff\x18\x04\xb2\xb3\x09\xaf\x31\x58\xb6\x62\x72\xa1\x4a\x3a\xad\x83\xc4\x1a\x71\x98\x46\xf7\x08\x8c\xa9\x79\x2a\xf5\x75\xc7\x89\x13\xc4\x32\x75\x9f\x0b\x9a\x74\x8b\xdc\x55\x68\x49\x6e\x41\x65\x8c\xc1\xcd\xb8\xda\x6c\x91\xd0\x7c\x3e\xc2\xf4\xaf\x50\x42\x49\xb9\x96\xaa\x00\xc0\x07\x1c\xdf\xa7\x93\xf8\x2d\x0e\xc5\xd2\x67\x26\x2f\x51\x8f\xc0\x29\xb8\x8e\x20\xb6\x20\x1f\xb9\xe0\x5a\xbd\x3f\x95\x24\xc5\xda\x2f\xa8\x97\x8f\xf2\xef\xd4\x81\x20\xcf\x00\x82\x2d\x1b\xee\x90\xdf\x81\x61\x25\xd8\xed\xc0\xcf\xb5\xde\x66\xd1\x6b\xe6\x38\x96\xa4\x12\xa6\x2b\x03\x1b\x71\x18\xac\x13\xfe\x2c\x9f\xaa\x6b\x1a\x33\x42\xf9\xcc\xf7\x88\x41\x66\xcf\x48\x9a\x84\xde\x26\xb5\xce\x5b\x21\x85\x6a\x3a\xf2\x89\xbc\x66\x22\xc0\xaa\xb9\xf2\x14\x2d\x39\x3f\x5d\x4b\x23\x67\x79\xdb\xb0\x66"}, -{{0x42,0xdc,0x16,0xc5,0x7f,0xb6,0xf1,0x28,0x94,0x5f,0xa1,0x01,0xe0,0x5b,0xbf,0x54,0x8e,0xf7,0xd9,0x77,0x26,0xb6,0x92,0xfe,0x40,0x40,0x69,0xcc,0x57,0xcc,0xef,0xa0,},{0x0a,0x1b,0xa5,0xdf,0x52,0x39,0x96,0xf9,0x54,0xb3,0x4d,0xdc,0xfa,0xba,0xd3,0xf3,0xde,0xe2,0x1a,0x5f,0xa7,0xa4,0xce,0x32,0x2d,0x21,0x6b,0xd8,0xcc,0xaf,0x43,0x8c,},{0xc7,0x59,0x77,0xe8,0x3b,0xcf,0xe9,0xdf,0x72,0x92,0xa8,0x60,0xed,0x97,0x25,0x55,0xb5,0xc2,0x44,0x16,0xfd,0x4b,0x7e,0xe3,0x28,0x53,0x88,0xfa,0x5b,0x14,0x47,0x60,0x8e,0x4a,0x34,0x78,0x13,0xcf,0xe0,0x93,0x51,0x2a,0x76,0x51,0xe4,0x22,0xe9,0x86,0x7d,0xb7,0xb9,0x7c,0x0b,0x08,0x67,0xf0,0xb8,0xc7,0xb7,0xf4,0xf0,0x2c,0x31,0x0d,},"\xf2\x71\x4c\x23\xa3\xa6\xfc\x11\xad\x15\xc9\x80\xb7\x35\x0f\xc8\x42\x17\x87\x76\x61\x18\x80\x55\xff\x75\x0d\x82\xc4\x9c\x5f\xef\x7b\xc8\xe6\xaa\xc5\x74\xa1\xb7\x9a\x3f\x26\xd1\x69\x69\xc0\xf4\x06\xee\xab\x3e\x9e\x12\x85\x0a\x55\x70\x97\x45\xe3\x0d\xff\xa6\x2a\x69\xdf\xb2\xb6\x4b\x3c\x1b\xd2\xbc\x35\x86\xe2\x6d\x4e\xea\x71\x4d\x2a\x7b\x71\xcf\x79\xfb\x8f\xfb\xf2\xaa\xad\x00\xca\x3e\x4f\x2b\x6f\x50\x3c\xc1\xfe\xf2\xea\xb3\x65\x6f\xb4\x4f\x8d\x62\xa8\xdb\x8a\xb5\x8f\x39\x46\x93\x94\x9e\xea\x57\xfa\xfe\xcf\x00\x5f\x6e\xbf\x12\x87\xdb\xa4\xd2\xd6\x23\xc0\x2e\xa1\x71\xf5\x67\xe5\x26\xad\xd2\x07\x09\xeb\xca\xb9\x62\xf8\x3d\x98\xef\x66\x8e\xbd\x01\xef\x20\x48\x8b\x36\x65\xe3\xa4\x46\xfb\xfb\x13\xd3\x40\x50\x94\x2c\x74\x9b\xb2\xdf\xfc\x76\x63\x67\xfd\x45\x2e\x68\xe5\xb0\xc6"}, -{{0x90,0xb4,0x55,0xc6,0xbb,0x9c,0xec,0x83,0xe1,0x37,0x35,0x70,0x65,0x33,0x9d,0x03,0x05,0x25,0xd0,0xea,0x7f,0x5b,0x92,0x3a,0x2d,0x59,0x72,0xc3,0xc1,0x2a,0xa3,0x7b,},{0x5c,0xef,0x03,0x8c,0x16,0xbf,0xa4,0xb4,0xc9,0x23,0xa0,0xfe,0x70,0xcd,0x7f,0x25,0xc8,0xbc,0x83,0x7f,0xdf,0x5a,0x7e,0xfb,0x9d,0x95,0xf2,0x1b,0x96,0xbe,0x92,0x5a,},{0xc9,0x34,0x5e,0xec,0x2c,0x4a,0x0a,0xec,0x73,0x23,0x86,0x49,0x4a,0x69,0xa3,0xfc,0xe8,0xb8,0xa1,0xbe,0x36,0x6b,0xbe,0xd1,0x65,0x9f,0x13,0x1f,0xe9,0x7c,0xc0,0x37,0xfb,0x1b,0x7c,0x1b,0x68,0xb0,0xf3,0x02,0x39,0x45,0xd2,0x00,0x90,0xa0,0xcd,0x2c,0x15,0x53,0xa4,0x7f,0xae,0xc4,0xd6,0x6f,0xd8,0x16,0xce,0x12,0x11,0x68,0xf3,0x09,},"\xc6\x2c\xfd\xb9\xd2\x1e\xee\x6b\xe4\x7f\x30\x72\x7a\xae\xe5\x1f\x07\x03\x78\x9a\x43\x1d\x32\x22\x85\x33\x35\x02\x17\xa9\x3a\x18\x90\x06\x69\xc9\x59\x56\xf3\xf2\xae\x90\xdc\x74\x5a\x71\xe1\x83\x40\xd0\x58\xd1\x6b\x4c\x6f\xe3\x3b\x64\xaf\x8d\xad\x97\x3f\xe5\xdc\x02\xe8\x52\x07\x05\xc7\xa8\xbb\x3c\xcb\xe1\x83\x8c\x6c\x24\x93\x37\xf9\xb6\xa4\xc0\xe1\xf8\xa4\xe5\xd1\x03\x19\x6f\xa7\x99\x98\x92\x3d\x04\x22\xe9\xd0\x79\xa7\x2c\xc2\xa8\xf8\x6d\x65\x90\x31\xa6\x07\xd4\xcc\xa0\xb9\x47\xb3\xab\xee\xee\xf6\x4c\x28\xda\x42\x0d\x05\xde\x66\x5a\x55\x10\xfe\x55\xf7\x75\x98\xec\xad\x7f\xaa\x0a\xc2\x84\x80\x0b\x53\x82\x93\x94\xc4\xae\x90\xbe\x66\x67\x8f\xf0\x4a\xb4\x6d\xa2\x65\xae\x06\x40\x2d\x8c\x83\xca\xd8\x4d\x61\xa0\x51\xde\x02\x60\x55\x98\x88\xe7\x79\xf7\x4b\x72\xa5\xd7\x1c\x13\x2f"}, -{{0xdc,0x18,0x5c,0x2b,0xa0,0xb3,0x78,0xdf,0xe5,0xdd,0xa5,0x10,0xc3,0x2f,0xef,0xf5,0x35,0xca,0x2e,0x8a,0x02,0x43,0x4b,0x32,0x6e,0x01,0x58,0xbc,0x87,0x8e,0x88,0x48,},{0x33,0xd6,0xcc,0x05,0xa4,0x34,0xe4,0x19,0x28,0x0d,0x58,0x64,0xa1,0xaf,0x20,0x9a,0x2c,0x67,0x68,0x14,0xb7,0x0f,0x72,0xf8,0x14,0x1a,0xc7,0xe0,0x57,0x3e,0xe6,0x3e,},{0xf1,0xe4,0x45,0x14,0xd2,0xec,0xbc,0xc8,0xd1,0xa7,0xe8,0x4b,0xf5,0x84,0xce,0x73,0x18,0x35,0xe9,0x89,0x4f,0x88,0x97,0x4f,0x09,0x8d,0x45,0x6b,0x60,0x71,0x8f,0x57,0x5e,0xf4,0xd8,0x06,0x2f,0x21,0x82,0x50,0x42,0x50,0xcf,0x83,0xbb,0x2a,0xf2,0xa7,0x9b,0x1f,0x58,0xa6,0xa9,0x7b,0xd9,0x8d,0xa4,0x67,0x13,0x2d,0x7b,0xec,0x2f,0x05,},"\xe2\x76\xb1\x19\x12\xcc\xa5\xa8\x4b\xba\x65\x0c\x17\x2a\xef\x3a\x4d\x5f\x91\xac\x72\x29\x13\xbb\x89\x1a\x3a\xb0\x42\x4a\xb0\x7e\xa7\x09\xcb\x8b\xba\x3a\x3d\x11\xf8\x2f\x51\xc2\xaf\x01\x62\xa8\x2f\x72\x19\xce\x27\xb3\x5a\x30\x50\x7d\x53\x6a\x93\x08\x17\xe4\x0f\x85\xa2\x2a\x5a\x43\x2b\x94\xd1\x92\xc3\xc8\x91\x17\x77\xcf\xdb\x7f\xe9\x37\xa6\x75\x02\x77\x0d\x6d\x75\x75\x3d\x3a\xe8\x82\x29\xe0\x8f\x1e\xd2\x3b\x43\x28\xd8\x62\xac\x61\x86\x3c\x06\x3e\xa9\x84\x8f\x8a\xb9\x6a\x02\x13\xd7\xb9\x36\xc4\x8f\xe7\x54\x83\x6c\x98\x48\x78\x59\xd1\x99\xb3\xd9\x40\x39\x27\x16\xa1\xd5\x69\xe6\xc0\xcb\x1b\xa9\x18\x93\x2c\xf8\x85\x25\xe2\x56\xc8\xab\xb1\x1a\xaf\x0b\x45\x46\x55\xd5\xdb\x55\x71\x3c\xeb\xba\x28\x7a\xe2\x02\x65\x1a\xc8\x72\xbf\xc8\x0f\xea\xa7\xe0\x0d\x47\xc0\xbe\x38\xe6\x58\xf7\xc5"}, -{{0x90,0x72,0x1c,0x43,0xbc,0x36,0x6f,0x24,0xbf,0x4e,0x8c,0x99,0x3e,0x13,0x80,0x24,0x68,0x2f,0x10,0x29,0xdb,0xa3,0x5a,0xbe,0xb0,0xd6,0x0c,0x7f,0xa7,0x10,0x02,0x1c,},{0x7c,0x63,0xa2,0xf1,0x3b,0x7b,0x22,0x0a,0x0b,0xb7,0x52,0xe3,0x80,0x07,0x53,0xb8,0xb6,0xb3,0x26,0x69,0x37,0x8c,0xe1,0x31,0xbb,0x77,0xa9,0xa8,0xd2,0x30,0xe9,0xae,},{0xd2,0x06,0x4a,0x6d,0x6c,0x99,0xc6,0xc3,0xf1,0x52,0xd2,0xd4,0x35,0xf2,0x4e,0x34,0xb5,0x45,0x9b,0x08,0x2e,0xf1,0x1e,0x94,0x4a,0x77,0xff,0x54,0xdd,0xf9,0x86,0x27,0x37,0xec,0xb2,0xac,0x8d,0x54,0x20,0x7d,0x36,0xc5,0x1a,0xd4,0x1f,0x36,0x49,0x0a,0x11,0x1b,0xa8,0x0e,0x12,0x6b,0xfe,0xcb,0x09,0xde,0xf6,0xac,0xcb,0xdf,0x88,0x0e,},"\x65\x1c\x96\x17\xca\xc9\x58\xc7\xed\xd4\xa5\xf3\xfe\xdf\xb8\x3d\xc9\x71\xab\xfb\xb6\x9a\x31\xe8\x98\xcc\xa8\x47\x2e\xf0\x68\x03\x4a\x6d\x23\x76\xee\x0e\x72\xd0\xa9\xbf\xee\x27\x57\x96\xc3\x79\x5a\xda\xc8\xeb\xe1\xd1\x2b\x66\xec\x26\x8f\x6b\x75\xfa\x39\x41\x15\x4f\x99\xe2\x23\xfa\xf2\xcb\xab\x5b\x92\xe2\xb3\xba\x7b\x79\xbe\x77\x00\xef\x9d\xba\x69\x25\x3c\xce\x53\x56\xb0\xc4\xe7\x47\x03\xcf\xca\xfd\xb5\x54\x68\x50\xb4\x62\x32\x67\x5c\x90\xc0\x2d\x5e\x42\x6d\x33\xd6\x0c\xeb\xf0\xc7\x93\x01\x82\x37\x9d\xbb\x00\x7f\x53\x61\x63\xc8\xdd\xbb\xd3\x15\x7b\xb2\xda\x62\x34\x01\x33\xf0\x0a\xe2\x68\x2e\xc6\xba\xa6\x41\x6b\x5a\x01\x52\x1c\xc1\x0e\x04\x69\x52\x95\xf2\xe5\xb9\x4c\x05\xf0\x03\x83\xff\xe9\x54\x83\x07\x97\xf6\xdf\x82\x31\x72\x53\x2f\x98\x16\x5f\xe3\x14\xab\x32\x59\x29\xaf\x83\x85"}, -{{0x9c,0xec,0x24,0x67,0x58,0xe4,0x12,0xe7,0x37,0x8b,0x45,0x79,0xea,0xfe,0x9f,0xac,0x5a,0x25,0xd5,0x40,0x5f,0x92,0x70,0xb5,0xd7,0xe5,0x43,0x41,0x4e,0xc3,0xd5,0xda,},{0x97,0x5a,0x9e,0x6a,0x15,0x2c,0xae,0xbb,0x2f,0x9d,0xd0,0xde,0xb7,0x6d,0xd9,0x22,0xb6,0xdc,0x77,0x05,0x5d,0xda,0x03,0xfb,0xae,0x9e,0x7c,0x68,0x5d,0x07,0x3a,0xa1,},{0x9b,0xad,0x1e,0x3b,0x12,0x79,0xef,0x65,0x8f,0x4d,0x07,0x16,0x44,0xc6,0x3a,0xe2,0xb7,0xa7,0x80,0x35,0x7e,0x9d,0xc4,0x26,0xf1,0x65,0x0e,0xc0,0x63,0x4d,0xfc,0x52,0x0f,0x8e,0xda,0x9d,0xc8,0xf1,0x0a,0xa7,0x32,0x4c,0x59,0x42,0xd2,0x34,0x7f,0xf8,0x80,0x2b,0xd9,0x0e,0x95,0xfc,0xec,0x31,0x33,0x52,0xcd,0xae,0x64,0xf3,0x2a,0x04,},"\x17\xec\x9b\xd4\x7a\xdd\x6c\xcf\xbd\x78\x7a\xf0\xd9\x01\x3e\x9c\xc9\x79\xaa\xf8\x50\xe0\x94\x26\xd3\xb2\x8e\xdf\xd7\x12\x96\xeb\x31\xff\x8b\x21\xc5\xfe\x7b\xe0\x50\xf5\x36\x32\x4c\x3e\xc4\x88\x50\xe0\xb5\x08\xa3\x6b\xb4\xcb\x7e\x75\x4b\x32\x71\x83\xa1\xb3\x94\xd8\x8a\x79\x41\xd1\xce\x8d\xac\x62\xa5\xd8\x29\x18\x74\xd7\x84\x85\xe5\x1f\x29\xed\x05\x86\x5a\x20\x6e\x52\xec\xb1\x2c\x5d\x10\x7d\x4f\xf9\x6f\x25\xd3\xc5\xd1\x81\xd2\xc4\xba\x64\x63\x60\x0d\xb1\xcc\xa3\x28\x57\xfc\xf5\x97\xcb\xdf\xb2\xfd\xa2\x70\x8a\x8a\xba\x28\x1b\x43\xc3\xd2\x8c\x4a\x4e\x79\x83\x36\x15\x09\xf6\x1a\x10\x74\xe6\xf0\xad\x61\x01\xc7\xb5\x67\xee\x40\x78\xe9\x83\x9c\x47\xf4\x65\x31\xb7\x29\xff\x0e\xfe\xef\x7c\x9d\x1a\x8d\x83\x3d\x9c\x0f\x42\x81\x2a\x34\x18\x7c\x3a\x77\x8c\x16\x5c\x09\xd6\x45\x9c\x9c\x7c\xea\xa2"}, -{{0xd1,0x40,0x3f,0x63,0x20,0x2e,0x08,0x05,0x25,0x84,0x3b,0xde,0x25,0x5e,0xeb,0x6b,0x67,0x83,0xc1,0xca,0xae,0x9d,0x6e,0xd0,0x0b,0xa6,0x08,0x05,0xbe,0xd1,0x94,0x1f,},{0x23,0x8a,0xea,0x3a,0xd6,0xd6,0xf2,0x77,0x83,0xe7,0x05,0x16,0xbb,0xfc,0xca,0x47,0x70,0x36,0x6b,0x50,0xed,0x0f,0xe6,0xa4,0xe9,0x66,0xb5,0x3a,0xf1,0x21,0xa7,0x21,},{0x8e,0x60,0xe7,0x3c,0x06,0x38,0x16,0x79,0x5e,0x29,0xf5,0xd6,0x4e,0xce,0x11,0x59,0xf1,0xb5,0xd5,0x02,0x1a,0x6f,0x8f,0x65,0x5e,0x26,0x1a,0x4d,0x00,0x26,0xf5,0xb9,0x4f,0xf2,0x92,0x32,0x50,0x49,0x9d,0x99,0x52,0x98,0x48,0x05,0x12,0xe4,0x12,0x62,0x76,0xaa,0x4a,0x22,0x6d,0x01,0x5a,0x95,0x82,0x7b,0x3c,0xe6,0x92,0xe2,0x33,0x02,},"\xc4\xf1\x7d\x44\x2f\xba\x4c\xa0\xdf\x8d\xc1\xd0\x62\x8d\x7d\x7f\x36\xb6\x0b\x57\x58\xd7\xc1\x3b\x80\xb8\xf9\x7a\x62\x12\x4d\x96\xa2\x3b\x27\x95\x65\x49\x5a\x8a\xcc\xab\x59\x97\x11\x5b\x13\xa4\xba\x22\x0a\x73\x95\x7e\xb7\x93\x05\x20\xac\xbb\xfb\x6f\x54\xcf\x68\x72\x6b\x64\x50\xc6\xff\xa9\x47\x0b\x05\x5e\xa2\x62\x91\x4e\x2b\xc6\x12\x63\x3f\x1a\xc3\xd0\x61\x8a\x23\xdf\xf1\x88\xa7\x33\xd7\x6b\xcb\xcc\x46\x0f\x52\xab\x61\xe1\x99\x38\xf9\xc8\xca\xaa\x79\x2c\x20\x8d\x1f\x6c\x75\x47\x28\x90\x5f\xda\x51\xd8\x81\xa3\x47\xa5\x3d\xa7\x44\xd3\xba\xad\xc0\xa7\x6c\x47\x4c\x55\x86\x80\x26\x90\x95\xf9\x08\x4a\x74\x47\x1d\x5c\x09\xff\xc2\x91\x41\xb5\xbf\xaf\x49\x54\xdf\xac\xbc\xa6\x63\xd0\x37\xb1\x7e\xbf\x95\x59\x88\x22\x33\xe5\xca\x5a\x8b\xf7\x5c\xca\x4f\xc9\xc5\xa4\x10\x9f\x32\xe1\x45\xf3\x85\x3b\x17"}, -{{0xbd,0xf6,0xbd,0xc3,0x1a,0xb0,0xb5,0x31,0x37,0x84,0x48,0x3a,0xbe,0xca,0x6e,0xa5,0xe9,0xcd,0xc6,0x8f,0x81,0xb2,0x1f,0x35,0x0d,0x09,0xc3,0x90,0x7b,0xb9,0xb6,0xa1,},{0x03,0x62,0x77,0x12,0xb7,0x55,0xe5,0x06,0x9f,0xb9,0xab,0x8f,0x9e,0x89,0x97,0x24,0x02,0x9a,0x7f,0x26,0x8a,0xf9,0x39,0x88,0x21,0xee,0xec,0x93,0x60,0xc9,0x28,0x5b,},{0x38,0xfa,0xc6,0x03,0xed,0x24,0x6f,0x83,0x3f,0x1c,0x0f,0xd4,0x58,0x56,0x98,0xb0,0xa7,0x13,0x05,0xef,0xf0,0xd1,0x4a,0x00,0x49,0xb3,0xce,0xf0,0x73,0xbd,0x03,0x6d,0xd4,0x51,0xb3,0xda,0xba,0xda,0xae,0xae,0xa2,0xae,0xaf,0x83,0xd3,0x95,0x74,0x6f,0x4e,0x86,0x86,0x6a,0xda,0x97,0x1c,0xbe,0x48,0x2e,0xdb,0x04,0x19,0x33,0x2f,0x0e,},"\x90\xa6\x6a\xaf\xa5\x64\x2a\x98\xe7\x9f\x0d\x88\x14\x70\x80\x16\x7b\x11\xe4\x46\x65\x18\xf1\x95\xcd\xdd\x89\x40\xd1\x2e\xe4\x91\x8d\x31\xa6\xd4\xcb\x77\xd0\xbf\x5a\xf2\x99\x83\xbb\xe5\x08\x56\x10\xa7\x9d\xaf\x0c\x75\xa7\x8c\xcb\xcf\xfb\xbd\xab\x21\x89\xc3\x94\xae\x24\xe2\x65\xbd\x8c\x55\xfd\x3f\x40\x98\xe1\xb1\x75\x57\x75\x49\x51\x8e\x7a\x4d\xcf\x74\x52\x08\x6d\xd1\x27\x8d\xd5\x8e\xa4\xc0\xaa\x69\x0e\x91\x79\x51\xef\x39\xfc\xff\x60\xcb\xfa\x1e\x90\x91\x0b\xab\x53\x74\x92\x8d\x47\x22\xf7\x02\xbf\x5a\xd6\x02\x8f\xfd\xa6\x54\x1f\xa5\xba\x1a\x37\x79\xec\x78\xb0\xa9\x5f\xe3\x85\x0c\x74\x8b\x6c\x8f\x42\xf3\x30\xec\x79\x54\x1a\x52\xa1\xcf\x57\xdb\x72\xdf\x4f\x92\xce\x7f\x74\x8a\xee\xf1\xaf\x33\xbc\x5a\xe0\xa8\x2c\x89\xdf\xf2\x16\xf2\x3a\xec\x16\x8a\x7d\xbb\x51\x0a\xa6\x32\xda\xab\xcc\x97\x1b\x3f"}, -{{0x57,0xb3,0xb1,0x4a,0xce,0x1c,0xd0,0xcd,0x60,0x3e,0x63,0x28,0xbd,0x21,0x9e,0xe7,0xd9,0xd0,0x94,0x48,0x7f,0xa6,0x68,0xf2,0x8a,0xee,0xc0,0x2b,0x43,0xc9,0x09,0xa7,},{0x24,0xe6,0xb6,0x39,0x5f,0x97,0xea,0x0e,0x23,0x71,0x86,0xd4,0x69,0xb7,0x19,0x23,0xd2,0x11,0x3a,0xdf,0x40,0x3b,0xee,0xeb,0x4a,0x2d,0x27,0x90,0x9a,0xaf,0x3e,0xda,},{0xfc,0x79,0xfd,0xc6,0xd0,0x90,0x88,0x7a,0x61,0xe4,0x3c,0x6b,0x91,0x87,0xb6,0x57,0xd2,0xe4,0xd9,0xcb,0xaf,0xd6,0xe7,0xca,0xeb,0x7e,0xbd,0xea,0x84,0x28,0x25,0xb7,0x8f,0xb9,0x49,0xd2,0xc4,0x9a,0x0c,0xf3,0x8b,0x6c,0x73,0x29,0x6d,0x82,0xc8,0xdd,0xeb,0x1f,0xe2,0xd4,0x0a,0xad,0xdd,0x79,0x64,0xda,0x68,0xac,0xf8,0xc6,0x6f,0x0e,},"\xb2\xe0\xde\xdd\x80\x2e\xed\x99\x6d\xbd\x58\x36\xbf\x86\x88\xb0\xd1\x20\x1b\xf5\x44\x2f\xf9\xbb\xd3\x51\xae\xef\xe1\xa0\xc2\x1f\xea\x2b\x5c\x9f\xe5\xed\xee\x47\xe9\x21\x09\x9b\x05\xae\xda\xa8\x03\x67\xc1\xce\x08\x82\x1d\x78\x3a\x5b\x64\xcf\x05\x9c\x0f\x43\x35\x08\x39\x86\xa5\xa6\xec\xff\x8c\x84\xfd\x40\xe0\xba\x5d\xd5\xe5\xd2\xf0\x11\x12\xa8\x4c\xe5\xcf\x8e\x0d\xb7\x8b\xeb\x18\x2d\x91\x39\xc0\xb0\xf3\xe0\x06\x0a\x3f\xa7\x38\x69\xe9\x64\x23\xf1\x70\xdf\x9a\xf1\xcb\x9c\x35\x56\x6d\x87\xdf\xf5\x42\x22\x3f\x6d\x43\x9b\xdb\x54\x72\x9d\x36\x6a\xff\x63\x7b\x0f\x36\xa5\xd1\x4b\x15\xd6\x12\xbd\x03\x07\x6c\xc4\xd0\x4c\x1f\x25\xb3\xba\x84\xe0\xd1\xfe\x47\x4e\x57\x18\xd1\xa1\x7d\x5a\x48\x84\x65\x66\x2e\xe4\xc3\xf6\x64\xb4\xc9\x27\x4b\x64\x9d\x78\xce\xa4\xe8\x52\x43\xf3\x71\x32\x39\x04\x8a\x90\x8c\xe3\xe1"}, -{{0x01,0x8a,0x2c,0x3d,0xee,0xa5,0x0a,0xb5,0x06,0x75,0x1f,0x9c,0x2a,0xda,0xad,0xfd,0x9e,0x21,0x92,0x12,0x16,0x09,0x93,0x16,0x84,0xeb,0x26,0x5e,0x19,0x3e,0x7f,0x89,},{0xaf,0x41,0x0b,0xdd,0xde,0xfc,0x64,0x4e,0xf1,0x2c,0x98,0x99,0xff,0x71,0xb9,0xe1,0xd0,0xdf,0xa3,0xd6,0x9d,0x8c,0x2c,0xd6,0x76,0xc1,0x91,0x6b,0x34,0x59,0x1c,0xfd,},{0x7a,0x44,0xe6,0xa3,0x19,0x32,0xde,0xe6,0xdc,0x2d,0x83,0x94,0xe2,0x9a,0x65,0x51,0xd1,0x3e,0x6c,0x6f,0xfd,0xfa,0x21,0x8f,0xa5,0xb9,0x98,0x66,0x8d,0x84,0x39,0xdb,0x5e,0x05,0x37,0x9f,0xbf,0xa0,0xda,0x5b,0x56,0x3e,0xd9,0x66,0x43,0x5a,0xe2,0xc5,0x4e,0x3a,0xd1,0x6e,0x1a,0x9f,0xca,0x1f,0x5a,0x15,0x7a,0x08,0x07,0x04,0xab,0x03,},"\xcf\x78\x13\xef\xac\x12\xad\x1c\x7c\x73\x22\xcc\xbe\x54\xaa\x0e\x9a\x8b\xa4\xfd\x43\x45\xb0\x6e\x4c\xe7\xa3\x5c\x8b\x1c\xd5\xe3\xf7\xf0\x68\x85\x33\x84\x9b\xa2\xcf\x4c\x75\xb6\xf2\x09\x26\xa1\x19\x4a\x72\xdf\x0e\x1b\x1b\x34\x45\x6a\x21\x33\x11\x2d\x00\x67\x22\xfe\x81\x1d\x5e\x40\xc4\x12\x11\x59\xde\xd8\x89\x90\xc0\xac\x2b\xfd\x34\xf3\x5a\xf4\xf0\x7c\xc4\x02\xe9\xa3\x81\xa6\x75\xd0\x3f\xec\x7e\xc4\x38\xc4\xad\x9d\x92\x9a\xec\x8f\x24\x2d\xef\x02\x3c\x99\x3c\x9e\x8b\xa1\x8c\x74\x28\xe8\x8f\xde\x68\xa4\x71\x1e\x50\x6d\x79\x69\xf6\x3c\x8e\x0b\xc8\x3f\xf0\xde\x4e\x13\x36\x10\x6c\x05\xe0\x9d\x59\x22\x40\x0e\x8a\x81\xbf\x54\x88\x56\x67\x89\x97\x85\x88\x2b\x70\xf2\x0d\xd8\xfb\x1e\x75\xf5\x85\x5b\x76\x5a\x25\x6d\xa4\x34\x1b\xf2\x3e\xa0\xff\xa1\x8a\xad\xda\x38\x18\x16\x94\x60\x01\x04\x56\x69\xc8\xd0\x4d\xf0"}, -{{0xbe,0xa4,0x45,0xe9,0xb6,0xd3,0xf2,0x12,0x35,0x91,0x2c,0xd6,0xc4,0x2e,0xc0,0x57,0x72,0x97,0xca,0x20,0xa1,0x03,0x57,0x88,0x0c,0x2b,0x84,0x6d,0xd8,0xe2,0xcc,0x77,},{0x02,0x41,0x74,0x96,0x62,0x21,0x69,0x9e,0xa4,0xb0,0xa3,0x7e,0x51,0x7f,0xf9,0xb1,0x65,0x98,0xae,0x4d,0x4e,0x83,0xbf,0xa3,0xca,0x50,0xbc,0x61,0x68,0x41,0xf5,0x95,},{0x69,0x64,0xb9,0xc5,0x90,0x3e,0x74,0xe9,0x93,0x28,0xac,0xef,0x03,0x65,0x58,0xee,0xcd,0x33,0x69,0x15,0x0a,0x52,0xe2,0xcb,0xad,0x4b,0xbb,0x97,0xd4,0x61,0xb3,0xdf,0xc6,0xb3,0xe8,0x45,0x58,0x13,0xa4,0xf4,0xbd,0xca,0x46,0x30,0x2e,0x02,0xe6,0x83,0xec,0xea,0x18,0x20,0x17,0x1c,0x53,0x8e,0x54,0xc3,0xde,0x6c,0x95,0x4a,0xa4,0x07,},"\x47\x43\xc7\xc0\x99\xab\x81\x59\x27\xb3\x67\x4d\x00\x54\xb6\xde\x59\xaf\x28\x11\xab\xc2\xcf\x7f\xde\x08\xf6\x29\x29\x18\x5a\xdc\x23\x8f\xad\xd5\xe7\x5a\xe3\xba\x00\x36\xff\x56\x5a\x79\x40\x5b\x42\x4f\x65\x52\x33\x1e\x27\x89\xd9\x70\x9a\xc1\xec\xbd\x83\x9a\xa1\xe9\x1c\x85\x48\x17\x59\x79\x58\xcc\x4b\xd9\x1d\x07\x37\x75\x07\xc2\xc8\xd3\xc0\x06\xcf\xeb\x6c\x0a\x6c\x5a\x50\xee\xe1\x15\xe2\x11\x53\xdd\x19\x8e\xa0\xa3\xaf\xf6\x2b\x70\x75\xd5\xa4\x61\x78\x87\x83\xf0\x50\xe6\x59\xc5\x72\x96\x3d\x7a\x59\xe5\xaf\xaa\x2b\x9c\x50\x1f\x43\xc6\xac\x08\xab\x47\x97\xc4\x56\x6d\x22\xb9\x3c\xdf\x65\xa9\x9a\x2a\x1d\x63\x8e\x79\xf7\x2b\x5f\x46\x31\xfe\x5e\x9e\x5f\x96\x8f\x6d\xb7\xa1\x88\x0d\xf5\x1d\x8f\xeb\xc1\x49\x42\x67\x2f\x8e\xa6\xfc\x3a\x72\x81\x4a\x44\xd6\x6d\x14\x84\x20\xa6\x90\x00\xf6\x8c\x33\x0d\xe5\xb8\x0f\xc6"}, -{{0x64,0x47,0x54,0x0e,0xd7,0xbe,0x0a,0x11,0xc2,0xa8,0xde,0x79,0x3d,0x83,0xc6,0xe2,0x44,0x98,0x3d,0xb1,0x8d,0x78,0xec,0x9d,0x75,0xf1,0x72,0x9c,0x92,0xe0,0xfd,0xf1,},{0x39,0x12,0x12,0xc8,0xed,0xc4,0xd3,0x34,0xa5,0xbe,0xc8,0x60,0xef,0x0f,0x5e,0xbb,0x5e,0xc4,0x4e,0x8b,0xb5,0x1c,0x0f,0x67,0x41,0x99,0x89,0x59,0xb2,0xb3,0x79,0xfc,},{0x3a,0xb5,0xf8,0x8e,0x2f,0x72,0x76,0xb5,0xb6,0x58,0x3d,0xff,0xba,0x56,0x39,0x99,0x3a,0x90,0x5d,0xbf,0x9b,0x88,0xce,0xea,0xaa,0xae,0x33,0x35,0x80,0x0e,0x4a,0x5f,0x10,0xf8,0x3d,0xa6,0xd6,0x22,0x5a,0x8d,0xbe,0x99,0xae,0x80,0x07,0x50,0x09,0xdd,0x50,0x87,0x86,0xb3,0x97,0x51,0x13,0xdb,0x47,0x8e,0x14,0xba,0x10,0x1b,0xee,0x0f,},"\xa4\x38\x1c\x76\x38\xc4\x87\x99\xe9\xb5\xc4\x3f\x67\xfc\x3a\xa3\xcb\xb5\xec\x42\x34\xf3\x7e\x70\xcc\xcc\xce\xd1\x62\x7a\x57\x68\x3d\x1e\x53\xf4\xe0\x88\x3d\x8b\x46\x2b\xf8\x3f\x13\x08\x63\x03\x68\xc8\x9b\x49\x15\x33\xdd\xb8\xc9\xa5\xb9\xe8\x15\x50\x02\xfd\xd5\x81\xa9\xa5\xbe\x0e\x43\x0b\x90\x86\xa6\xbe\xac\x47\x20\x21\x0f\x87\xb1\x4e\x86\x2d\x97\xe5\xcc\x69\x28\x67\x86\xa7\x58\x67\x23\xf2\x31\xef\x0e\x3e\x1b\x93\x2d\xbb\xa3\xa1\x8a\x0c\xb2\x21\xcb\x07\xf8\x0e\x6a\x8e\x13\x00\x05\x6c\x13\xe7\x02\xb2\x3b\xfb\x32\x50\xec\x7c\xc8\x64\xd5\xc7\xec\x57\x86\x24\x07\x09\xc5\x60\x24\xea\x6b\xe5\xf7\xb1\x5a\x4f\xa5\x55\x5e\x39\xa7\x44\xa1\xdc\x55\x7d\xf5\xb9\x48\xdb\x22\x0b\x3d\x57\x45\x74\x66\x91\xda\xcb\x44\x21\x64\x1c\xdc\xc1\x2e\x7e\xc0\x45\x02\x93\xf1\x9e\xc5\x7b\x09\xcf\xf1\x35\x84\x7a\xab\xe4\x46\xa6\x13\x32"}, -{{0x0c,0x58,0x7a,0x81,0x1a,0xdd,0x88,0xb9,0x94,0x45,0x8c,0x3c,0x80,0x8a,0xc4,0xe3,0xa8,0x3a,0xfa,0xb2,0x6d,0x4c,0xff,0x5c,0x96,0x1b,0x9d,0xf0,0xb5,0xc8,0x33,0x44,},{0x06,0x78,0x3b,0x0c,0xdc,0xc5,0x02,0x8c,0x56,0x38,0xbd,0x74,0x8f,0x0b,0xc7,0x6f,0x7e,0x94,0xd1,0xaa,0x20,0x15,0xca,0x94,0x87,0x38,0xa3,0x50,0x04,0x60,0xac,0xa0,},{0x33,0xb4,0xf4,0x27,0x4f,0x20,0x00,0x8a,0x72,0x1d,0x1e,0x8d,0x05,0x4a,0x2b,0x4e,0x95,0x32,0x7e,0x38,0xbb,0x07,0xb3,0x3c,0x4b,0xee,0x7e,0x1c,0xe0,0x20,0xa4,0x42,0xfb,0x26,0x27,0xed,0xa3,0xb7,0xac,0x93,0xcd,0x3a,0xb0,0xb1,0x2b,0x99,0x93,0x5a,0x1a,0x92,0x33,0x11,0x16,0x04,0xda,0x4a,0xcf,0xfb,0x53,0x15,0xb9,0x07,0x12,0x0b,},"\xf5\x6d\xc6\xb7\x60\x76\x32\x5b\x21\x26\xed\x11\xd1\xf0\x9d\xec\xef\x9d\x15\xc3\x1d\x0e\x90\xcd\xb1\xa2\x7e\x08\x9c\xc5\x63\x29\xf6\xec\x3f\x66\x5e\xb6\x73\x9e\xc5\x67\x8b\x3f\x37\xee\x1f\xb3\x7d\xeb\x9e\x24\x00\x92\xb7\xa8\x8f\xd2\x55\x25\xac\xd5\x5e\x29\x4e\xb1\x04\x6f\x9b\x1b\x69\xa8\x47\xeb\x9c\xeb\x7b\x15\x93\xb9\xf6\x97\x8e\xf6\x18\xc1\x5d\xe4\xe0\x59\xec\xc3\xbf\xda\x32\x97\xa1\x9c\x2d\xf2\x02\xad\xf7\x21\x55\xcf\x21\xea\xbd\x03\x94\x8d\xf1\x51\x98\xe8\xa6\x8b\x08\x84\xf9\x3a\xd5\xe3\x6e\xb0\x98\x3c\xca\x30\xe4\x5a\x8b\x4b\x5f\xb8\x13\x6f\xde\xa8\xa3\x34\x1d\xd7\x87\x75\x40\xa5\x57\xde\xbf\x75\x30\xcc\x33\xae\xee\xf6\x27\x1c\x3f\x0a\xf6\xd0\x97\x87\xe8\x15\xf2\xf1\xdd\x25\xce\x4d\x2f\xd0\x9f\xfa\x9f\x53\x08\x1b\x46\x9c\x50\x0d\xa4\xd4\x41\x80\xc0\x4e\xb1\x86\x93\x29\xcb\xf2\xd8\x23\x18\x7e\x83\x1c\x24"}, -{{0x66,0xcf,0x40,0x1a,0x21,0x42,0xfc,0xf4,0xa8,0x01,0x80,0x46,0xcf,0x41,0x40,0xbc,0xa1,0x8d,0x76,0xef,0x62,0x66,0xe7,0xa0,0x24,0x75,0x7d,0xf1,0x72,0xa5,0xd6,0x53,},{0x67,0xd4,0x8d,0xfd,0x23,0x74,0x3c,0xc2,0xca,0x40,0xe4,0xdf,0xd6,0xb8,0xcc,0x5d,0x84,0xbe,0x82,0xdd,0x2b,0x11,0x20,0xcc,0x47,0x6e,0x6a,0xf6,0xf2,0x5e,0xcc,0x98,},{0xd6,0xb0,0xe8,0x0e,0x60,0xbc,0x1b,0x29,0xab,0x8f,0x74,0x80,0x8f,0xc4,0x60,0x84,0x77,0x95,0xcc,0xb8,0x87,0xba,0xc0,0xec,0xaa,0x8e,0x13,0x52,0x97,0xa8,0x50,0x97,0x71,0x2b,0x24,0xb0,0xa1,0xfb,0xaf,0x7a,0x67,0xc5,0xd5,0x30,0xa4,0x7d,0x06,0x43,0xfc,0x87,0x02,0xc0,0x59,0xd2,0x15,0xfb,0x11,0x2d,0xbe,0x47,0x5e,0x5b,0xca,0x0d,},"\xda\xa8\xef\xb3\xfd\x41\xf1\x2f\xbc\x55\xbd\x60\x46\x41\x57\xa2\x6d\x71\x86\x32\xd8\x82\xae\xdb\x6b\xf9\x8e\x47\xdd\x23\x37\x87\x9e\x0b\x46\x45\x2e\x06\x2e\x6d\xfb\xff\x3e\x7b\xca\x72\x89\xe4\xef\x6b\x3f\x41\xd4\xb0\x3b\xdc\x2c\x84\x2a\xfe\x97\xf3\x02\x98\x83\xed\x45\xf6\x05\x4d\xde\x96\x90\x64\x9a\xbb\x2b\x8d\xc2\x8f\x5f\xe8\xce\xcf\x80\xfc\x1e\xa4\x11\xbf\xc4\x0b\xbf\x4f\xd2\x0b\x21\x8c\xf4\x7e\xa8\xee\x11\x8d\x4d\x5a\xef\xa5\xc1\xbf\xa0\x8a\x8f\xb1\xb3\x0d\x6d\xe0\x97\x7c\xd1\x5e\x50\x29\x2c\x50\x1f\x2e\x71\xce\x27\x40\xff\x82\x8b\x84\x32\xda\x5a\x59\x4b\xab\x52\x23\x76\x0b\x64\x79\x2e\xd3\xa6\x9d\xd7\x5e\x28\x29\x23\x49\x43\x65\x65\x13\xdf\x1a\x17\xa2\xa0\x67\xa9\xa8\xea\xa6\x4e\x19\x56\x9f\x46\x93\x9d\x34\xb9\x92\x71\xae\x50\xa4\x7d\x7d\xbc\xa3\x62\x0c\x81\x25\x5b\x0e\x1f\xd1\xf3\xce\xc8\x51\xf1\xb1\x1b\x35"}, -{{0x5d,0xbf,0x88,0x5a,0xa5,0x98,0xe8,0x95,0x57,0x1f,0x5f,0x65,0x09,0x0b,0x72,0x32,0x3e,0x9d,0x70,0xb0,0xf5,0x81,0x10,0x68,0x7a,0xfb,0xbc,0x38,0x3a,0xfe,0xdc,0xac,},{0xfa,0x17,0xeb,0xa7,0x6e,0x3b,0xc3,0xea,0x6d,0xab,0x3a,0x5b,0x12,0x0d,0xc5,0xec,0xb9,0xae,0x6f,0x00,0x13,0x8f,0x7d,0x36,0xdd,0xa9,0x26,0x8b,0xc4,0x72,0x21,0x74,},{0xe1,0x42,0x9d,0xab,0x2e,0x42,0xcd,0x03,0x5b,0x7f,0xc6,0x02,0xef,0xd6,0xba,0xf9,0x47,0x06,0xf1,0x6e,0xaf,0x2f,0x8b,0x5f,0xed,0x32,0x92,0x39,0xe8,0x75,0x60,0x5f,0xb1,0x72,0xf5,0xdd,0x9a,0xe2,0xbc,0x2e,0xb4,0x2e,0xb4,0x74,0x56,0x7e,0x29,0x2f,0x52,0x06,0xe8,0x2e,0x69,0x4b,0xca,0x0d,0x6d,0x43,0x3b,0x86,0x76,0x34,0xcb,0x0d,},"\x1e\x0b\x6c\xf1\x5c\xe0\x33\x37\x17\x9c\x02\xd6\x54\x08\xdf\x5b\xe9\x20\x0c\x37\x82\xb6\x00\x4a\xf9\x4e\xa4\xde\xcb\x25\x79\x99\xd6\xfd\xff\x30\x1d\x11\xd0\x0c\x98\xc3\x72\xfa\xc0\xd0\x26\xcb\x56\xdf\xef\xe3\xde\xf7\xeb\x99\xac\x68\xd6\x96\x8e\x17\x12\x4d\x84\x46\xf5\x3e\x8d\x2d\x3d\xd8\x90\xd3\x7a\x23\xc7\xe0\xb8\x3a\x48\x4b\x3c\x93\xbd\xdf\x6c\x11\x8e\x02\x81\x95\x9d\x27\xbd\x87\xd3\x7e\x84\x3d\x57\x85\xf4\xa4\x07\x71\x39\x84\x94\xe6\xc4\x32\x2f\xbb\x67\x5c\x1d\x47\x93\x21\x03\x21\x48\xf7\xfe\x52\x56\x4d\xdf\x7a\xe7\xac\x26\x9d\x0c\xd2\xe5\x52\xfe\xc5\x89\xae\xae\x0f\xb9\x3f\xe3\xee\xae\xf0\x85\x60\x96\xcf\x4f\x6b\x34\x97\xe7\x23\x5c\xc8\x49\x4d\x81\x0a\x0b\x46\xc5\xea\xc8\x7f\x18\x7e\x50\x5b\xb7\x76\x4f\x80\x45\xc9\x54\x19\x83\xf7\xb0\x25\x69\x80\x09\xa2\x3d\x9d\xf0\xbd\x1a\x47\x3c\xbe\xe4\xcf\x5e\x94\x88\xec\xbc"}, -{{0x84,0xb3,0xae,0xdd,0x47,0x97,0xa5,0x65,0xc3,0x51,0xde,0x7d,0xfa,0x07,0x00,0xb9,0xff,0x7c,0x4d,0x72,0x91,0xc8,0x80,0x8d,0x8a,0x8a,0xe5,0x05,0xcd,0xd2,0x25,0x90,},{0xd7,0xad,0x72,0xca,0xa7,0xc2,0x22,0x09,0xec,0x46,0x78,0xd1,0x1d,0x55,0x90,0xa6,0xcb,0x28,0xa0,0x71,0x17,0xfe,0x5a,0xef,0x57,0xb5,0x07,0x51,0x58,0x32,0x01,0xa5,},{0x92,0x20,0xf0,0xed,0xaa,0xae,0xe1,0xb8,0x76,0x35,0x0d,0xbe,0x92,0x66,0x06,0x17,0x67,0xb8,0x62,0x96,0xc3,0x51,0xd4,0xca,0xc9,0x9d,0x07,0xcd,0x61,0x2c,0x6e,0xfb,0x24,0xf8,0xf9,0xb0,0xb9,0x75,0xf9,0x5c,0x42,0xc5,0xb6,0xaf,0xed,0xc8,0x92,0xf8,0x7e,0xfe,0xdd,0x39,0xd5,0x16,0x02,0x94,0xc2,0x76,0x58,0xbd,0xcf,0x42,0x85,0x0b,},"\x53\x25\x67\xff\xa5\x3b\x5c\x0f\xcd\x29\xc3\x94\x99\xd2\xe7\x8e\xcd\x20\xe6\x31\x23\x49\x92\x40\xe7\x75\x08\x8b\x39\x4d\xc6\x5c\x8b\xaa\xa0\xfe\x8f\x6a\xa7\xe7\x01\x81\xf9\xe1\x0a\xdd\x8b\x4a\x8b\xeb\x0b\x2e\xc3\x8a\x43\x30\x9f\x10\x0c\xd4\xbe\x91\xc6\xf4\x8e\x79\xdc\x0a\xee\x93\xa1\x5c\x94\x03\x77\x3b\x35\x4a\x8d\x42\xed\x48\xd8\xf2\x76\x23\x0f\xa6\xde\x5a\xda\x50\x1e\xe0\xa6\x53\xb4\x45\x8f\x0e\xcf\x6d\x5b\x3c\x33\xe2\x14\x1c\x66\x2f\x6e\xa0\x55\xf7\x41\xe5\x45\x86\x91\x7d\x2e\x0c\x4e\xb2\xb5\x66\x21\xf9\x66\x5f\xef\x32\x46\xf0\xbd\x80\x0b\x53\x3e\x3b\xc6\x15\xc4\x02\x1f\x8d\x0e\x2a\xd2\x33\xa1\x1e\x77\x36\xc4\x93\xac\xc3\x1f\xae\xe7\x6a\x09\x7d\xc4\x0d\xb9\xef\xc2\x24\x46\xea\xcf\x1c\xc1\x8f\x51\xfd\x10\x23\x6a\x2f\x94\x2d\x0a\x53\xc3\xce\x20\x91\x08\xb5\x93\x8c\x0a\x9e\x53\x6b\x89\xef\x0a\xd6\xb4\x05\xa1\x0f\x22\xc3"}, -{{0x69,0x50,0xbf,0xcf,0x48,0x0b,0x98,0xea,0x18,0xa2,0xd5,0xae,0x5b,0xa6,0xe7,0x66,0x8f,0x4c,0x28,0x3f,0xf2,0x71,0x13,0x57,0x74,0x0f,0xfe,0x32,0xcf,0x25,0x81,0x9a,},{0x8e,0x4c,0x6f,0x23,0x3f,0x7b,0x86,0x32,0x1c,0x9d,0x67,0x99,0xba,0xc2,0x8a,0xaf,0xcd,0x25,0x03,0xd7,0xaa,0x0a,0x7b,0xde,0xd8,0x72,0x27,0x27,0xfb,0xbc,0xae,0xb8,},{0x94,0xde,0x5d,0xf7,0xa2,0x5e,0xcd,0x70,0x20,0x5d,0x40,0xbc,0x94,0x99,0xfc,0x7c,0xd7,0x13,0x65,0x68,0x06,0x0a,0x41,0x9a,0x93,0xbe,0x6e,0x31,0x86,0x64,0xbb,0x6d,0xfc,0xe6,0x0e,0x2d,0x4e,0x63,0x3f,0x7e,0xc1,0x48,0xfe,0x4f,0x83,0x4e,0xd2,0x77,0xc1,0xfe,0xc4,0xc4,0xe2,0xa8,0x6f,0x44,0xc4,0x58,0x9c,0x81,0x78,0x88,0xdb,0x00,},"\xa4\x01\xb9\x22\xab\xa5\x7e\xe0\xc6\xac\x1c\x8f\x1b\x48\x29\x6a\x85\x62\xee\xf1\x37\x52\x68\x93\x88\x6a\x08\x30\x6e\x22\x03\x66\x77\x88\x61\x8b\x93\x98\x64\x46\x7a\x31\xf1\x6e\xdc\xe1\x52\xa4\x2c\x25\x54\x6b\x64\x0e\xa8\xbe\xd1\x89\xa4\xf8\x98\x86\xa3\x7f\x10\x69\x11\xea\xe1\xf5\x00\x81\xbf\x79\x5e\x70\xc6\x50\x44\x37\xd2\xa8\x0c\xb8\x39\x47\x9e\xcb\xb8\x7c\x12\x9b\xcc\x5f\xe3\x1d\x71\x6e\xf9\x78\xc2\x06\xd7\xf0\x8a\x79\x34\x66\x59\x4f\x4d\x75\xe2\x15\xbb\x63\x74\x59\x6f\x8e\x7d\x00\xee\xa7\x24\x78\x09\x43\xe8\x9b\xd3\x86\x3c\x95\x1b\xbd\x24\xef\xee\x23\xc9\x7c\x2c\x79\x7c\x7f\xaf\xbf\x8f\x2c\x8b\x43\xf3\x7a\x5f\x88\x11\x29\xa0\x95\x73\xfa\x7a\x03\x4a\x28\x5e\x80\xdc\x4b\xa4\xbc\x95\x64\xa4\xdc\xed\xeb\x33\x16\x7e\x0b\x30\xc5\xa0\x0b\x9a\x10\x9a\x22\x31\xcf\xa0\x01\x2b\x29\xb2\xb3\x45\x0b\x89\x2e\xcc\xef\x08\x08\xe5\x03\xf8"}, -{{0x61,0xb2,0x60,0xf5,0xb8,0x48,0xb2,0x71,0xef,0x48,0xe5,0xa5,0x6d,0x29,0x74,0x32,0xd8,0x9f,0x2a,0xb8,0x5b,0xd5,0x38,0xfa,0x66,0x88,0x70,0xd0,0x56,0x02,0x20,0xe5,},{0x60,0x86,0xfe,0x87,0x35,0xf3,0x99,0xf1,0xaf,0x2e,0x39,0x5e,0x0f,0xdf,0xb5,0x62,0x9e,0xbc,0xb0,0x4b,0x6e,0xd4,0xa5,0x4a,0x9e,0x47,0x05,0x2c,0x6e,0x81,0x91,0xd4,},{0x98,0x28,0xfe,0xc8,0xff,0x5c,0xf8,0x5a,0x98,0xf4,0x50,0x77,0x0b,0x5b,0xdb,0x4b,0x80,0xda,0xca,0x44,0x37,0x9d,0x8f,0x53,0xc9,0x1c,0x34,0x8e,0x22,0xdf,0x64,0xac,0x48,0xf2,0xb6,0xe2,0xa7,0xb3,0xb6,0x42,0xbc,0x81,0x93,0xa1,0x94,0x31,0x62,0x29,0xe6,0x94,0x47,0xed,0x24,0x1c,0xd4,0x23,0xd8,0x3b,0x6f,0xe7,0xb2,0xd4,0x4b,0x00,},"\x28\x26\x29\x5d\x79\x94\x5f\x67\x54\x76\xbc\x4d\x45\xef\x80\x0d\x80\xb1\xf0\x39\x8e\x4b\xe6\x0e\x3d\xe4\x57\x1e\xd1\x08\xdf\x98\x9f\x03\x2d\xe6\xc2\x34\x5d\x99\x48\xd6\x77\x92\x7e\xa0\xb8\xcf\x1a\x5c\xa3\x6f\xd5\xf2\x3c\x25\xdc\x0d\x2a\xb5\xbd\x56\x5a\x54\xaf\x46\xfd\x97\xd3\x38\xd7\x70\xe3\xa7\xb4\x7e\xfb\x54\xc0\x7a\x16\x64\x70\x77\x71\xeb\x4e\x37\xd9\xd7\x0b\xa7\x79\x25\x1d\xcd\xcd\x3b\xf6\xd1\x24\x8a\xde\xc5\x3f\x78\x72\x59\xc4\xd5\x94\xd5\xfd\x4c\xed\x8e\x3d\xb7\x62\x1d\x49\x65\xd4\x82\x98\x17\x81\x24\x93\x1a\x3d\x0c\xd2\x69\xb2\xd5\x3b\x7c\xd2\x61\xb9\x6d\x37\x0c\x5d\x96\x93\xc8\xad\x13\x3e\xd5\x89\x45\xee\x35\x40\xe1\x06\x25\xd9\x24\xae\xba\x9b\xda\xfc\x65\x61\x00\xaa\xb2\x76\xfa\x99\x6b\x1d\xb4\x77\xbf\x85\xea\x55\x90\x81\xd5\xb4\xc7\x30\x7d\xc1\x59\x56\x54\xac\xa8\x2f\x7b\x6d\x2d\xda\xf7\x35\x7c\x15\xa4\xd7\xd8\xb9\x08"}, -{{0x93,0x6d,0xc1,0xce,0xf6,0xa3,0x10,0x74,0x7f,0x35,0x00,0x88,0x05,0x5a,0x39,0xaa,0x76,0x2d,0x9a,0x4b,0x52,0xc8,0xc8,0xe4,0xc6,0x82,0x79,0x43,0x80,0xc2,0x72,0x5c,},{0x03,0xb3,0x18,0x00,0x41,0x2d,0xf4,0xd5,0x6f,0x15,0x32,0xc0,0x58,0x28,0xc0,0xb7,0x25,0x28,0xa6,0x7a,0x78,0x1b,0xef,0x4c,0x06,0xc1,0xfb,0x6f,0xf2,0xce,0x32,0x4b,},{0x3f,0x99,0x4b,0x8e,0xf5,0x28,0xf6,0x42,0x1c,0x6a,0x6a,0x22,0xe9,0x77,0xad,0xe5,0xce,0xe8,0x87,0x26,0x3d,0xe3,0x8b,0x71,0x9a,0xcd,0x12,0xd4,0x69,0xbf,0xd8,0xc3,0xf6,0x8e,0x7a,0xc0,0x7d,0x2f,0xae,0x80,0xa2,0x09,0x27,0x78,0xdf,0x0b,0x46,0x35,0x37,0xad,0x3a,0x05,0x51,0x99,0x7a,0x3d,0x5b,0x51,0xf8,0x32,0xd9,0xc8,0x23,0x0b,},"\xeb\x58\xfe\x86\xc4\xef\x34\x9c\x29\xae\x6f\xb0\x4f\x10\x85\x0e\x38\xc6\x82\x3d\xbe\x64\xa0\x9a\x5b\xf1\xe0\xce\x60\x0d\x39\x4e\xfa\x6f\xb9\x6e\xd6\xa8\xf2\xc9\xd4\xbe\xc0\x5e\x6a\x5e\xbd\x5a\x1b\xf4\xd0\xc5\x1d\xb9\x34\xe5\x7b\x79\xe5\xc6\xa8\x79\xd9\x75\x19\x7d\xbb\x10\x47\x5f\x65\xc7\xf8\xa8\xc6\xa7\x7a\x42\x03\x84\xb5\x06\x2a\x27\x40\xf1\x40\x17\x40\xee\x0f\x5e\x04\x3a\xad\x7a\x2a\x2b\x42\x60\xc5\xd9\x07\xf7\x05\xed\xaf\x65\xb0\xe3\x75\xdf\xc7\xb0\x0b\xd6\x60\xdb\x61\x47\xf2\xeb\xe8\x70\xa0\xee\x18\xdc\x2b\xa3\xc9\x2b\x0b\x76\xfa\xe2\xb9\x09\x32\xcd\xb6\xc1\x49\xe4\x6f\x3f\xee\xcf\x4c\x26\xf0\x44\x1f\x3a\x9e\x00\x66\x78\xae\xcf\xf8\xcc\xae\xca\xed\xa7\x3a\x18\xa6\x8a\xc9\x88\xb6\x2e\x83\xa9\xbb\x51\x88\xae\xde\x38\xdf\x77\xa9\xa1\x64\xab\xbd\xd9\xd5\x8e\x52\xa6\xca\xf7\x22\x23\x89\xf1\x98\xe8\x5f\xbf\x96\x62\x36\xdc\xdb\xd4\xc1"}, -{{0xf8,0x9e,0xed,0x09,0xde,0xc5,0x51,0x36,0x1f,0xa4,0x6f,0x37,0x59,0x73,0xd4,0xfb,0xfa,0x5c,0x5c,0x12,0xf1,0xb5,0xe5,0xab,0xf4,0x5c,0xfa,0x05,0xff,0x31,0xa3,0x40,},{0x3e,0x0e,0xfd,0xca,0x39,0x19,0xfa,0x10,0xd4,0xa8,0x49,0xce,0xf1,0xde,0x42,0x88,0x51,0xbd,0x08,0xef,0xd2,0x48,0x59,0x4f,0xd8,0x9c,0xde,0xb9,0xde,0xee,0x43,0xb0,},{0x89,0x7e,0x6f,0x27,0x97,0xc3,0xf3,0x26,0xd2,0xcd,0xb1,0xd2,0x67,0x3d,0x36,0x06,0x31,0xf0,0x63,0x30,0x45,0x80,0xff,0x5b,0x4e,0xb4,0x3d,0x39,0xad,0x68,0x51,0x83,0x4c,0x9c,0xf8,0x91,0xd9,0xf0,0x90,0x5b,0xf8,0xde,0x07,0x5f,0x76,0x35,0xdf,0xca,0x60,0x1a,0xdc,0x0f,0x14,0xe7,0xb2,0xc7,0x6f,0x75,0x71,0xbf,0xa4,0x68,0xed,0x0c,},"\x4c\xf9\x77\x3d\xa0\x5f\xd3\x22\xfc\x14\x7b\xe9\x00\xef\x5c\xf2\x56\xc8\x8a\xfd\xad\x4b\x08\xc2\x30\xdf\xc8\x98\x1f\xb6\x9f\x47\x6f\x7d\x45\xef\x7c\x90\x06\xbc\x10\x03\x2b\xa5\x34\x36\xac\x22\x84\x3e\x0d\x76\x28\x9c\xf6\x8f\x98\x18\xfa\x64\x03\x1d\x4b\x40\x95\x50\x59\xaa\x69\x11\x09\x15\x88\x9f\x5e\x22\x73\x2a\x13\x43\x91\x25\x81\xab\x3b\x11\xa3\xba\xe7\xa4\x71\x35\x95\x08\x59\x65\x75\xf8\x88\x16\x0b\xee\xf9\x66\xe5\x70\x8f\x0e\x31\x47\xea\xcf\xce\xc1\xca\xa3\xef\x24\x0c\x5e\x0a\x14\xc1\x86\x54\x6c\x8e\xeb\x64\x65\x83\x50\xb1\xaf\xfc\x0c\xfd\x2a\xc2\x13\xaf\x67\x0a\xfc\xa7\xbb\xc9\xdd\xdd\x28\xa4\x65\xb5\x86\xe6\x9c\x38\x8c\xd7\x34\x78\xd6\x8e\xfb\x32\x2b\xdf\x86\xd9\x21\x30\x11\xe7\x11\xb2\xb9\x5f\xef\xa7\xbb\x9b\x59\x39\x76\x17\x06\xaa\x71\x21\x02\x49\x06\x42\x0b\xdd\xf1\xd8\x80\x0a\x43\x38\xd9\x38\xfa\x13\x7c\xf2\x7e\x9f\xfc\x51\xc6"}, -{{0x40,0x07,0x96,0xef,0x60,0xc5,0xcf,0x40,0x84,0xde,0xe1,0x80,0x1c,0x4a,0x19,0x75,0xe4,0x82,0xe7,0x0a,0xef,0x96,0x1c,0xd4,0x2e,0x2f,0xd5,0xa3,0xfa,0x1a,0x0f,0xbe,},{0xf4,0x7d,0xa3,0x81,0x28,0xf2,0xd0,0x12,0xcc,0x57,0x97,0x57,0x1d,0x47,0x9c,0x83,0xe7,0xd8,0xa3,0x40,0x98,0x02,0xf9,0xa7,0xd9,0x76,0xc2,0x70,0x67,0xcb,0xbe,0x43,},{0x84,0xd3,0xaa,0x3f,0x36,0x18,0x44,0x39,0x67,0x54,0xd8,0x0d,0x9f,0xa0,0x5b,0x8b,0x2f,0xa4,0xab,0xf3,0xa0,0xf3,0x6b,0x63,0x9b,0xee,0x9c,0xfb,0x5c,0x85,0x30,0xa3,0xa9,0xcc,0x34,0x67,0x7f,0x92,0xa9,0x13,0xc4,0x1e,0x80,0x0f,0x2e,0x80,0x41,0xf7,0x66,0x6d,0x07,0xed,0x85,0xf1,0x6a,0x57,0xd8,0x17,0xb1,0x24,0x1f,0xc5,0xee,0x04,},"\xc4\x73\x32\x5e\x78\x5b\x27\xdf\x44\x71\xee\xfb\x9e\xbe\xbd\x64\x61\xd5\x70\x80\x01\x81\x10\x0f\xf3\x6c\xaf\x3c\x38\xf6\x7c\x19\x21\xb1\x57\xec\x8e\x61\x26\xf9\x55\xae\xbd\x90\xea\x3f\xe5\x38\x5f\x80\x42\xcd\x70\x4b\x27\xcc\x1d\x69\x78\xc0\xe2\xa2\x96\x69\x5f\x5e\xf9\x7b\x7c\x2e\x16\xae\x4f\xf4\xd0\x63\xc6\x88\xd7\xf4\x6e\x96\x4e\x1f\x0a\x00\x50\x3f\x35\x73\x45\x97\x76\x83\xd6\xe4\xc3\x42\x3d\x56\xbd\xb6\xce\x86\x4b\x69\x87\xe0\x85\xe8\x3e\x70\xc7\xc1\xa1\x4e\x0e\x41\x3f\x59\x2a\x72\xa7\x1e\x01\x7d\x50\x5b\x64\xc2\x4f\x1a\x1a\x6b\x81\x3e\x06\x4e\x6e\x0c\xf8\xbd\x45\x71\xd0\xff\x2f\x26\x7a\x6a\x13\xe0\xcd\x43\x04\x63\xb6\xca\x3b\x88\xf0\xcd\x40\xb0\xfb\x83\xd5\xbe\xdf\x6f\x7d\x47\xe1\x70\xe8\x7d\x0a\x75\x00\x93\x69\x3e\xda\x23\x2a\x6d\xaf\x98\x12\x57\x27\xb9\x58\x8e\xcb\x89\x4a\xe3\x73\xba\xe3\xa4\x45\xa1\x06\x30\x64\x69\xa4\xc2\xcd\x77\xff"}, -{{0x67,0x03,0xa6,0x23,0x2c,0x5e,0x2e,0x65,0xe0,0xab,0x3b,0x92,0xe2,0xaa,0xf9,0xf5,0xfb,0xd3,0x3f,0xb4,0x69,0x88,0x04,0x7d,0x6f,0x4d,0x0f,0xf5,0x38,0x7f,0xa0,0x29,},{0x04,0x7c,0xff,0xca,0x8b,0x7b,0x11,0xac,0x6e,0xac,0xc0,0xea,0xa0,0xc5,0xb7,0x3c,0x75,0xb9,0xc6,0x37,0x95,0x69,0x73,0xaf,0x9d,0x97,0xb2,0xdd,0x5b,0x60,0x5d,0x6f,},{0xca,0xe9,0x68,0x79,0xe5,0xb6,0x03,0xbe,0x86,0x66,0x09,0xd4,0xa0,0x53,0xbf,0xa1,0x2a,0x51,0x37,0x8e,0x99,0xb2,0xa2,0x81,0x2e,0x47,0x89,0x26,0x7d,0x8f,0x32,0xf4,0x73,0x24,0x3f,0x8a,0xf7,0x4b,0x9b,0xe7,0x3f,0x47,0xde,0xa5,0x0f,0x0d,0x16,0x5e,0xbf,0x49,0x45,0x8b,0x73,0xe5,0x3d,0x88,0x58,0x0c,0x19,0x1a,0x18,0x2d,0x19,0x04,},"\xa2\x6b\x30\xa7\x69\x19\x79\x32\xa3\xa6\x28\x54\x96\x8d\x76\x01\x51\x61\x23\x66\x77\x8d\xc9\x94\x57\x6a\x2e\x0e\x03\x55\x49\x6b\x46\x20\x0e\x50\x69\x48\xa0\xd1\x02\xb6\x65\x1b\x2e\x73\x34\xca\x6c\x6e\xae\xf8\xbc\xa4\x4b\x42\x59\x70\xa0\xb3\x7d\x6b\xde\x0d\xa9\xd3\xc1\xb9\xf5\x1c\xbb\x25\xbc\x33\x5c\xd6\xfa\x92\x8a\x74\xf2\xc0\xdc\x2c\x6e\x99\xd3\x7a\x12\x86\x3a\x47\x4d\x4d\xf4\x3a\xad\x35\x41\x5f\xfc\xaa\x24\xd8\xc2\x9f\x91\x45\x72\xab\x2a\xbe\xc3\x89\x2d\xb4\x9e\x67\x9c\x5e\xa2\x20\xc2\xf5\x19\xa7\xd0\x33\xac\x1a\x2c\x5a\x46\x78\x69\xe3\x0e\xda\x3d\x26\x35\xca\x86\x34\x31\x47\x3f\x95\x8d\x55\x2b\xdc\x55\x82\x35\x2c\x29\x0d\x0c\xe4\xfa\x9c\xfd\x0a\xd4\x27\x99\xc2\x27\xec\x90\xb7\xc9\xe5\xdb\x9f\x5a\x7b\x6d\x56\x92\x12\xee\xd9\x4d\x32\x33\x26\x80\x5f\x2b\x3a\x00\x10\xd6\xc1\x1e\xb4\x10\x7c\x82\x83\x03\x76\x52\xf5\x0d\xc0\x67\xb6\xdc\x81\xf4\xdb"}, -{{0xe0,0xe7,0x2f,0x8f,0x17,0x86,0x33,0x62,0x67,0x33,0xbc,0xbd,0xa2,0xad,0x2a,0x50,0xe6,0x53,0x89,0x0f,0x15,0x35,0x9b,0x6c,0x22,0xfc,0x73,0x45,0xad,0x33,0x31,0x09,},{0xd1,0x3c,0xee,0x54,0x0d,0x84,0xb5,0x66,0x7d,0x51,0x6f,0xe7,0xec,0x72,0x39,0xbf,0x8d,0xa9,0x15,0x46,0xee,0x79,0x1f,0x84,0xed,0xd8,0xff,0xcf,0x3a,0x08,0x3e,0x76,},{0x14,0x55,0x21,0x71,0xb9,0x52,0x45,0xac,0x0f,0x0e,0x5a,0x6e,0x7a,0x2f,0x54,0x17,0x21,0x06,0x8d,0xb6,0x50,0xc6,0xda,0xda,0x04,0xc2,0x8c,0xab,0x7c,0x49,0x19,0x5f,0x64,0x36,0x71,0x21,0x44,0xcb,0x31,0x91,0x3c,0x56,0x2e,0x30,0xc3,0x9d,0x8a,0x85,0x49,0xfb,0x64,0xff,0xea,0x81,0xc7,0x44,0x51,0x43,0xb5,0xf2,0x32,0x86,0xda,0x05,},"\x79\x1f\xd6\x13\xc1\x09\x52\x92\xc8\xa4\xa2\xc8\x6b\x47\xae\x02\x61\x55\xb8\x46\x5b\x60\x7d\xbb\x41\x64\x77\xef\x79\xa2\x97\xc9\xd7\x75\x8c\xe3\x4a\xf9\xdc\xbf\x1c\x68\x47\x4f\x30\x90\x9f\xbe\x74\xb7\xba\x42\x96\x32\xf2\x40\x3a\xad\x83\x2b\x48\x6b\x72\xc2\x30\x54\xad\x42\xf7\x65\x3a\x9d\xdb\x45\x6c\xc7\x91\xf3\x48\x88\x6a\x7a\xe5\xdc\xec\x7c\x0b\xa8\x15\xf7\xa9\x3a\x10\xfe\x33\x1e\x90\x3b\x97\x0f\x7b\x50\x28\xbe\x49\xd1\x4b\xc5\x62\x0d\x63\x79\x26\x72\xb9\x8b\x94\x88\xc6\x7a\xe1\x66\x46\x69\x3e\x11\x20\x47\xf0\xac\x89\x21\xff\x56\x1c\x92\xdd\x05\x96\xd3\x2d\xf0\xa6\xe5\x07\xac\x1b\x07\xde\x51\x6c\x98\x42\x8d\x57\x0a\x37\xdb\x9b\xcd\x7c\x7e\x61\xc6\x94\x8a\xb3\xfe\x91\x25\x0d\xd1\xd5\xbd\x67\x12\x75\xdf\x9a\x97\x2f\x22\xc2\xba\x36\x80\x47\x47\xae\xc1\xea\x24\x16\xc1\xf4\x1a\xb8\x7b\xef\xde\x31\x62\x9b\x2d\x43\x31\x7c\xe4\x1c\xda\x03\x62\x62\x86\xc0"}, -{{0x54,0x4d,0xaf,0xd9,0x96,0x0d,0x82,0x97,0x56,0xc6,0xd4,0xb3,0xea,0xdd,0x44,0x37,0x5f,0xe7,0x80,0x51,0x87,0x6b,0xf9,0x78,0xa3,0x81,0xb0,0xde,0xca,0xaa,0x80,0x96,},{0xae,0x4f,0x64,0x25,0xc1,0xb6,0x7c,0xcb,0x77,0xf9,0xaa,0xcf,0xea,0x28,0xea,0xef,0x76,0x9c,0x8c,0xac,0xee,0x03,0x52,0x05,0xcd,0xcd,0x78,0x7e,0x8d,0x07,0x62,0x9d,},{0xa2,0xae,0x11,0x7c,0x8d,0xe4,0xca,0x6d,0x6f,0xe7,0x5e,0x46,0x60,0x23,0xbd,0x55,0x0c,0x26,0xfe,0xdd,0x3e,0x74,0xca,0x13,0xad,0xb6,0x25,0xf2,0x72,0xe1,0x75,0xf1,0x4d,0x5d,0xf5,0x50,0xac,0xe7,0xd8,0x22,0x88,0xef,0xef,0xab,0xf9,0x63,0x11,0xa1,0x23,0xbe,0xe2,0x38,0x89,0xad,0x37,0x11,0xbf,0xf2,0xb8,0x08,0x79,0x46,0xbf,0x0e,},"\x44\x7f\xe7\x34\x4c\xad\x1f\xae\x09\xd6\xa7\xd0\x5f\x09\xd5\x03\xc1\xb3\xd3\xd5\xdf\xa5\x84\x81\x0c\x35\xbc\x41\xe4\x95\x56\x93\x70\x61\x54\xe2\xd7\x51\xb2\xf1\xb5\x25\xe1\xa1\x45\x47\xba\x7f\x8b\x23\x20\x88\xa6\xfc\x92\x27\x02\xd9\x3a\x11\xcd\x82\x94\x9c\x27\xbe\xd6\x45\xdc\x35\x1f\xb4\xc1\x24\x2c\xf4\x1d\x01\x57\x54\x12\xe7\x92\xae\xd2\x14\x53\x1d\x94\xfd\x66\xe0\x3d\xd3\x2e\x97\x2f\xd7\x7f\x69\x47\xa3\x53\xe1\xae\x5e\x00\xf5\xa6\xca\x77\x99\x24\x72\xf0\x96\xb6\xe7\x47\x5f\xe5\x34\xe9\x13\xa7\x7b\xcb\x0d\x68\x1f\xdf\xb3\xa7\xa0\xdc\xb5\x6d\x27\x4d\xf4\xaa\x10\x9d\x4a\x8a\x37\x79\x4a\x92\x76\xf5\x00\x06\x69\x6f\xf1\x2c\xa4\xd0\x25\x40\x39\xdf\x0f\xb3\xf7\x2a\x96\x0d\xa0\x5c\x98\x72\xf2\xe3\x3e\xe8\x1d\x1c\xf7\xa6\xf4\x8b\xbc\xe0\xaa\x18\xc7\xc0\xf0\x6b\xa5\x5e\x67\x68\x9e\x0a\xf5\x87\xb5\x00\xea\xb7\x9c\xc7\xf9\x64\x0b\xca\x10\x4b\x7f\xbf\x31\xf0\x8e"}, -{{0xbf,0xbc,0xd8,0x67,0x02,0x7a,0x19,0x99,0x78,0xd5,0x3e,0x35,0x9d,0x70,0x31,0x8f,0xc7,0x8c,0x7c,0xc7,0xbb,0x5c,0x79,0x96,0xba,0x79,0x7c,0x85,0x54,0xf3,0xf0,0xf0,},{0x7c,0x5a,0xe3,0xba,0xb9,0x20,0x11,0x99,0xdf,0xbe,0x74,0xb7,0xd1,0xec,0x15,0x71,0x25,0xbd,0xba,0xa4,0x52,0x0f,0x50,0x1d,0xa3,0xf2,0x48,0x57,0x9d,0xc6,0xc2,0x2d,},{0xe4,0x86,0x15,0xb6,0x56,0x33,0xe6,0x19,0x93,0xb0,0xaa,0xa1,0xfa,0xfb,0x74,0xb9,0x62,0x9c,0x38,0x4f,0xd5,0x92,0xbd,0x73,0x5f,0xa1,0xf6,0x2c,0x5c,0xad,0x11,0x29,0x1f,0xcd,0x8c,0x2e,0x91,0xa5,0x0b,0xfe,0x0b,0x03,0xb4,0x35,0x02,0xff,0xf3,0xa5,0xc3,0x82,0xb9,0xc2,0x82,0x19,0x07,0xef,0xc3,0x4d,0xa5,0xba,0x05,0x4a,0xf0,0x0e,},"\x11\x7f\xae\x13\xe7\x87\x77\xb6\x21\x9f\x02\x02\x14\xc1\xb8\x7c\x57\x04\x6d\x1c\x09\xce\x82\xee\x2b\x56\x29\x89\x8d\x9b\x0d\xe7\x4a\x15\xcf\xe9\x9f\x80\x54\x8b\xa9\x13\xd7\x03\x6c\x56\x28\x5a\x4c\xba\x49\x3b\x52\xd2\xcb\x70\xd6\x36\x5a\xce\x3d\xa1\x2b\x1f\x34\xa2\x77\x8a\xf3\x6e\xf5\x2a\xb8\x2e\xde\x04\xca\xca\xf2\x79\x3f\x5f\x89\x83\x1e\x3b\x20\x5a\x9e\xe4\xc1\xd6\xfb\xda\xb4\xba\x4d\x9f\xae\x65\xdd\x79\xa5\xfe\x76\xb4\xb3\x9a\x30\x92\xcc\x71\x48\xd2\x11\xe8\x5e\xe8\x2a\xb4\x63\xd3\x4d\xce\xe9\x06\x1d\x9c\x21\xde\xd2\x05\x1b\xbd\x50\xb4\x13\xf0\xe2\x1a\x0e\x48\xd1\xff\xa8\xdc\xae\x24\x0b\x34\x95\xbe\x25\xd9\x31\x51\xb5\x7a\xa2\x71\xab\x99\xaa\x70\x8c\xa2\x80\x80\xca\xb4\x80\x4f\xce\xfa\x92\x9f\x5f\x1e\xf3\xf4\xc6\xc0\xfb\xfb\x40\xbe\xf7\xea\x1b\x50\x9b\x36\xba\x12\x60\x32\x35\x12\x37\x9d\x7b\xc3\xfd\xbb\x5d\x3f\xaa\xc9\xb0\x0e\x21\xf1\x2e\xa1\xca\x2e\x29"}, -{{0xdf,0x2d,0xf8,0xa9,0xd6,0x6d,0x56,0x38,0xcd,0xee,0x09,0x32,0x4e,0x7b,0x10,0xf8,0xed,0x29,0xab,0x91,0x38,0x7e,0x31,0x47,0xb7,0xdc,0x03,0xf7,0xcd,0x80,0x05,0x08,},{0x5c,0x04,0x2e,0x15,0x7f,0xb7,0xfb,0x12,0xd4,0xd4,0xfe,0xf2,0x84,0x71,0x41,0xec,0xfb,0x57,0xc1,0x25,0x3e,0x14,0xea,0xf3,0x00,0x4d,0x65,0x13,0xf5,0x2f,0xe6,0x25,},{0x9a,0x10,0x74,0x53,0x1e,0xd4,0x3d,0x07,0xbf,0xfc,0x7f,0x2b,0x6c,0x13,0xb8,0x83,0x8f,0xc7,0x5c,0xba,0x02,0xc7,0xd1,0xec,0x7b,0xa3,0x8b,0xca,0x3c,0xef,0x20,0xdc,0x9b,0xad,0xf3,0xa3,0x06,0x4a,0x2c,0x93,0xb1,0x84,0x24,0x41,0x42,0x0b,0x6a,0x8d,0x42,0x1a,0x96,0x0d,0x70,0xdf,0xb7,0xc7,0x0e,0xec,0x29,0x5f,0x21,0xf8,0x3f,0x0a,},"\x21\x57\x66\x15\xc9\x34\x6a\x63\xdc\xcf\x0c\x50\xec\xbd\x7c\x6d\x72\xad\x45\x2c\xfe\xd4\x3e\xa7\x32\x02\xcc\x7a\x98\x57\x60\x56\xb9\x66\x4b\x54\x62\x29\x05\xa1\xe7\x22\x17\x20\x73\x0a\xc6\x85\xd3\xbd\x39\x77\xec\x39\x59\xd4\x46\xbf\xa9\x41\xe7\x25\xb6\xfe\x16\xaf\xe5\x43\x2c\x4b\x4b\xde\xe7\xaa\x0f\xd8\x03\x09\x48\xed\x6f\xcb\xa7\xc0\xbd\xb4\x0c\x2e\x51\x7d\xa9\x74\x56\xe7\x4e\x1f\x93\xd5\xed\x67\x6d\xe0\xf4\xa8\xb0\xae\xa4\x49\x40\x4b\xd1\x5b\x6d\xa7\x9d\xc1\xb8\x13\x96\x5f\xe5\x57\x24\x10\xd7\x6f\x5b\x5e\xac\x66\x30\x50\x57\x03\x11\xdc\x98\x42\xb6\xfb\xf8\x80\x6a\xec\x03\x15\x17\x15\xca\xcf\x7f\x21\x80\x2e\x8b\xf5\xe9\x8a\x89\xc0\xd7\xd0\xd0\x98\xb7\x3c\x6e\xfc\x09\x96\x2e\x36\xb4\xe0\x30\xc1\xa6\x4b\x5d\x34\x9f\x5f\x20\x42\xc7\x44\x28\x67\x1e\x4a\x2c\x7f\xea\x0c\xae\xe2\x42\x2d\x85\xc4\xfc\xdd\xfe\xd3\x22\x13\x85\x9a\x69\x95\x5d\x4e\x3e\xbb\x7e\x1b\x20\x22"}, -{{0xe8,0xee,0x06,0x5f,0x99,0x07,0xf1,0xef,0xa2,0xda,0xec,0xb2,0x3a,0x04,0x25,0xf3,0x53,0x09,0x4d,0xa0,0x2b,0xc2,0xc9,0x31,0xf0,0xa5,0x87,0xef,0xc0,0xd1,0x3d,0xe1,},{0xc7,0x26,0x51,0xb7,0xfb,0x7a,0xc0,0x33,0x7a,0x17,0x29,0x77,0x49,0x6f,0xd7,0xf2,0xa7,0x2a,0xea,0x88,0x93,0x85,0x83,0x5e,0x56,0x3c,0x6b,0x60,0x53,0xa3,0x2d,0xc1,},{0xa5,0x10,0xdf,0xf4,0x2d,0x45,0x59,0xa1,0x9a,0x7b,0xf0,0xfe,0x0b,0xea,0x53,0xd3,0xe1,0xf2,0x2d,0xfa,0x6b,0xe5,0x50,0x39,0x89,0x5e,0x12,0xa5,0xd0,0x7d,0xa5,0xf2,0xe3,0x77,0x13,0xcc,0xb2,0xeb,0x21,0x60,0x11,0x62,0x8f,0x69,0x83,0xf8,0x71,0xfe,0xe2,0x86,0xe6,0x6f,0xff,0x4b,0xe7,0x58,0x2c,0x96,0x1a,0x1e,0xd7,0x56,0x84,0x04,},"\xa2\xf0\xc1\x37\x34\x73\xa3\x05\xd8\xf1\xd9\x91\x38\xb0\x6b\x9a\x96\x94\xff\xaa\x8a\x88\x22\x2d\xe9\xf7\x29\xbe\xe1\x30\x51\x75\xdf\xb1\x70\x01\xcc\x77\xf6\x7b\x6d\x40\xc9\x0c\x1a\x28\xfb\x22\x6c\x11\x28\x6d\xb4\xa1\x3e\x45\xe6\x92\x11\x24\x2b\xcd\xd0\x1c\xb6\xe2\xc4\x54\xe7\x6c\x0c\xab\x88\x1b\x4d\x2d\x9d\x3a\xb1\x00\xa5\xd6\x1d\x17\x25\xd8\x66\xe4\xfd\xb6\x6d\x93\xd7\x7f\x5b\x30\x86\x93\xb9\xb5\xa3\x33\xe5\x7f\xa2\x5d\x1e\x5d\x2e\x38\xdf\x6e\x4e\x9e\xc8\x41\x59\xbb\xee\x1f\xfe\xa9\x26\x83\x6a\x01\x01\xc9\x14\x83\xbd\x5b\xc8\x8a\x6f\x1c\xc4\xd4\xe7\xf0\x08\xad\x08\x45\x3a\x01\x23\x42\x9d\xd3\x35\x78\x1c\x7c\xbf\x8d\x68\x5a\x89\x99\xed\x11\x77\x60\x70\x04\xa1\x3c\x4c\xb5\xea\x49\x08\xc5\x42\x60\x7d\x3f\x2c\xd6\x69\x0c\xf1\xf2\xa7\x45\x5b\xbd\x38\xf5\x38\xf0\x7a\x10\x39\x64\x31\x7e\xfb\xce\xe3\x7e\xb4\x69\x31\xc0\x27\xcf\x15\x3e\xf8\x6e\x43\xd7\x82\x81\xeb\xd7\x10"}, -{{0xc7,0x2e,0x67,0xd8,0xc3,0xfe,0xc0,0x04,0xff,0x61,0x87,0x18,0xa9,0x09,0x9e,0xb8,0xad,0x7b,0x06,0xff,0x3b,0x8c,0x54,0x2a,0x7e,0x8b,0x98,0x47,0x31,0x34,0x75,0xe1,},{0x4e,0xb0,0x02,0xd3,0xcc,0xeb,0x18,0x8c,0x66,0x58,0xfe,0xc5,0x1c,0xb4,0x79,0xa6,0x52,0x64,0xac,0x55,0x5c,0x75,0xcd,0xc2,0x24,0x9c,0xf1,0xce,0x3d,0xef,0xc1,0x6d,},{0x2d,0x7b,0xab,0x8e,0xbd,0xa7,0xfc,0xa5,0xbb,0x3c,0x25,0xf5,0x1d,0xc5,0x1b,0x73,0xe6,0xff,0x6a,0x3b,0xb1,0xb5,0x2a,0xcc,0x78,0x11,0xa7,0xd2,0x59,0x5c,0xd6,0xfd,0xaf,0x73,0x04,0x94,0x41,0x8e,0x2f,0x57,0xef,0xdc,0x56,0x17,0xb0,0x66,0xfd,0x7b,0x62,0x07,0x68,0x0d,0x94,0xfb,0x8c,0x43,0xd3,0xd4,0x74,0x0b,0x41,0xcb,0x69,0x01,},"\xa8\xf3\x41\x35\xc0\x13\x2e\xc9\x5b\x64\xb0\xcb\xf5\x1d\x66\x90\x01\x43\x37\x04\x06\x79\x1f\xbb\x55\xf2\xb8\xca\x95\x3c\xc7\x4a\x46\xe0\x8b\x00\x2f\xa2\xda\x21\xb9\x51\xb8\x87\x1f\x7a\x29\xbc\x6d\x38\x79\x0a\xfc\x66\xa3\x29\xc3\x97\xd9\xf9\x25\x0b\xae\x0e\x30\xae\x34\x26\xe0\x8d\x8e\xad\x01\x79\xa3\xb3\x13\xc9\x08\x83\x91\x92\xf2\x89\xa3\xf3\xb6\xe9\x60\xb4\xc5\xce\xbe\xf0\xa0\x9d\xaa\x9c\x7a\x15\xc1\x9d\x4e\xbc\x6f\xc2\xac\x3c\xd0\x22\x32\xe8\x32\xb2\x34\xed\xd7\x96\x5d\x68\x7b\xfe\xb7\x58\xf7\x0f\xa7\x96\x38\x41\xb7\x85\x9b\xb9\x7c\x97\x1b\xd5\x57\xbc\x87\x69\x52\x4a\xc4\xc6\xee\xb3\x57\x97\x93\x33\x4b\x52\x2d\x17\x6b\xc6\x2f\x86\xb4\xd5\xc0\xd4\x01\x70\x36\xd2\xb6\xbd\x4e\x43\x84\x41\x6e\xf8\x26\x31\x39\x69\x1a\x86\x06\x17\x0d\x73\xc9\x3d\x64\x17\xdc\xc1\xa0\x8a\x53\x7c\x9e\xd4\x40\x04\x71\xa4\x6f\x52\x90\x7b\x46\xb1\x0a\x8b\x68\x89\xdb\xb4\x64\x7a\x8b\xbc\x71\x49"}, -{{0x69,0x64,0x50,0xb5,0x57,0xec,0x3c,0x94,0xcf,0x1a,0xf1,0x32,0x64,0x75,0x63,0x4a,0xa8,0x1d,0xef,0x38,0x14,0xff,0x30,0xa0,0x2b,0xa7,0xf2,0x04,0x4b,0x59,0xc0,0xfe,},{0x85,0x84,0x77,0x3c,0x56,0x6b,0x0e,0xed,0x3f,0x43,0x28,0x17,0x05,0xb5,0x75,0xa4,0x34,0xe4,0x7d,0x6c,0xf6,0xb2,0x51,0xb8,0x98,0x03,0xfe,0xf5,0x35,0x34,0xcb,0x29,},{0xce,0x8b,0x0a,0x57,0x79,0xf4,0xf5,0xf4,0x01,0xe8,0x4d,0x65,0x92,0x7a,0x0c,0x28,0xdf,0x82,0x9e,0x95,0xd0,0x9b,0xfa,0x97,0x11,0x1b,0x87,0x00,0x07,0x8f,0xf8,0x94,0xcf,0x72,0x77,0xe3,0x4a,0x71,0x61,0x44,0xd5,0x53,0x06,0xfc,0x9e,0x2f,0x64,0xcd,0x28,0x75,0x83,0xcc,0x80,0x03,0xbe,0x0e,0x8f,0xaf,0x26,0xaf,0x76,0x40,0x14,0x0e,},"\xcc\x25\x78\x29\xf3\x0a\x5f\x90\xdf\xdb\xc2\x47\xd4\x2e\x38\x87\x38\xb7\x6c\x41\xef\x8a\x82\xa5\xe0\x22\x5d\xdf\x1e\x38\x6d\x77\x08\x0b\x3b\x9d\xf8\x6c\x54\xb8\x5c\xdf\x2c\x32\xf3\x67\xab\xa0\xc3\xb6\xbf\x88\x8a\x5a\x69\x03\x52\x9b\x6a\xeb\x4d\x54\x07\xa1\x01\x80\x14\x91\x14\x13\x02\x28\xfc\x43\x56\xcc\xf3\x66\xb7\x7b\xe8\x97\x96\xa9\xe7\x1a\x0c\x69\x3f\x31\xe5\x84\xa4\xf1\x43\x09\x7b\xa3\x70\x36\x3b\x67\xb2\xf2\xe2\xfd\x8d\x6f\xe8\xb4\xe8\xdb\xf0\xd7\xdc\xc1\xa8\x36\x00\x41\x15\x8a\xa2\xaf\xf7\xe2\xa3\x25\xb8\xe5\x18\xf1\x93\xa2\x8b\xae\x05\xe3\xd5\x2b\x26\x62\x1a\xf4\x02\x02\x6d\x7f\x25\x0e\x86\xdc\xee\x30\x1a\x58\xb6\x31\xea\xdf\x45\x27\xe9\x58\xf0\x2a\x61\x58\x7f\x0b\xb5\x16\xce\xfa\xc0\x09\xfe\x51\x05\x2f\xff\x53\x33\x6d\xbd\x94\xe7\x26\x6d\x3b\x43\xca\xba\x8a\x1b\x38\xe5\xd8\x71\xc2\xa2\x4a\x4c\x41\x2f\xff\x3f\x7a\x9a\x52\xa8\xab\x23\xba\xc9\x79\x1b\x2b\x5a\x66\x9a"}, -{{0xa8,0xdd,0x35,0xf0,0x54,0xfb,0x6f,0xf6,0xf0,0xab,0x09,0x4a,0x0d,0x3d,0x1c,0x26,0x28,0x32,0x18,0x1d,0xf3,0x5c,0xcd,0x51,0x92,0x54,0x5e,0xbd,0x6a,0x9c,0xf5,0x29,},{0xca,0x41,0x23,0x38,0xd3,0x81,0x4b,0x88,0x6d,0x96,0x4b,0x71,0x92,0x5e,0x1a,0xab,0xb3,0xff,0xd0,0x78,0x34,0xdb,0xe7,0xdc,0x51,0x25,0x68,0x88,0x2b,0x53,0xe4,0xa3,},{0xfa,0x70,0x9f,0xbc,0x83,0x82,0xaf,0x83,0xd1,0x18,0x12,0x61,0x8d,0xfa,0xca,0x45,0x2e,0xab,0x83,0xe4,0xc5,0x3f,0xe9,0xe5,0x85,0x84,0x67,0xd0,0x7b,0x67,0x67,0xe1,0x79,0x75,0xc1,0xe0,0x63,0x93,0xd6,0xdd,0xe1,0x5a,0x34,0xd9,0x47,0x3d,0x1c,0xf4,0xd6,0xd8,0xc2,0xd5,0x73,0x94,0x52,0x00,0x80,0xfa,0xc4,0xe4,0x34,0x48,0xbe,0x07,},"\x55\xa7\xad\x91\x32\xd6\x3a\xc1\x61\xe7\xad\xb1\x32\xb9\x18\x9f\xdd\x84\xc3\x61\xc1\xe4\xf5\x41\x9a\x6d\xf7\x3d\xf4\xd7\xae\xb2\x9a\x8d\xc4\xbf\x01\x49\x0d\x4f\x48\x4e\x2d\x12\x07\x75\x17\xf5\xfc\x7a\xd0\xbd\xed\xa2\x0a\x6c\xb0\x22\x79\x42\x29\x0b\x08\xc3\xfe\x33\xab\x9b\x21\x35\xbc\x38\xa6\x57\x9a\x54\xbd\x98\x2f\x7d\x14\x17\xce\x86\x71\x17\xae\xa9\x18\xdb\xd3\xdd\x47\x6e\x7e\xb5\xb5\xd3\xc3\xe4\x8a\x86\x4a\x2f\x94\x2a\x31\x50\x1a\xa2\xb2\x9b\x53\xb8\x05\x13\xc9\x5d\x6a\x41\x18\x44\xf0\xde\xdf\x16\xa2\x9a\xc2\x67\xd3\x31\xe5\x3b\xdc\x25\x39\xbf\xcf\x32\xdc\x9b\x5d\x64\x0f\x12\x31\xe2\xca\xfb\x0a\xe9\x4b\xb5\x18\x94\x26\x86\x33\x64\x26\x2e\xfb\x47\xb5\xb5\xcc\xdb\xbc\x93\x32\x42\x16\xa7\x99\xb6\xf5\x0d\x37\x04\xf1\x5e\xd5\x9a\xf6\xcc\x7d\x91\x0c\xf0\x62\xd1\xbe\x63\x2d\xca\x5d\xf2\x13\xd4\x87\xd8\x56\x4f\x2b\x2b\xd7\xd8\x18\xbb\xa2\x7c\x36\x40\x13\xd9\x2d\x7f\x72\x62\x54\x62"}, -{{0xae,0x1d,0x2c,0x6b,0x17,0x1b,0xe2,0x4c,0x2e,0x41,0x3d,0x36,0x4d,0xcd,0xa9,0x7f,0xa4,0x76,0xaa,0xf9,0x12,0x3d,0x33,0x66,0xb0,0xbe,0x03,0xa1,0x42,0xfe,0x6e,0x7d,},{0xd4,0x37,0xf5,0x75,0x42,0xc6,0x81,0xdd,0x54,0x34,0x87,0x40,0x8e,0xc7,0xa4,0x4b,0xd4,0x2a,0x5f,0xd5,0x45,0xce,0x2f,0x4c,0x82,0x97,0xd6,0x7b,0xb0,0xb3,0xaa,0x7b,},{0x90,0x90,0x08,0xf3,0xfc,0xff,0xf4,0x39,0x88,0xae,0xe1,0x31,0x4b,0x15,0xb1,0x82,0x2c,0xaa,0xa8,0xda,0xb1,0x20,0xbd,0x45,0x2a,0xf4,0x94,0xe0,0x83,0x35,0xb4,0x4a,0x94,0xc3,0x13,0xc4,0xb1,0x45,0xea,0xdd,0x51,0x66,0xea,0xac,0x03,0x4e,0x29,0xb7,0xe6,0xac,0x79,0x41,0xd5,0x96,0x1f,0xc4,0x9d,0x26,0x0e,0x1c,0x48,0x20,0xb0,0x0e,},"\x9e\x6c\x2f\xc7\x6e\x30\xf1\x7c\xd8\xb4\x98\x84\x5d\xa4\x4f\x22\xd5\x5b\xec\x15\x0c\x61\x30\xb4\x11\xc6\x33\x9d\x14\xb3\x99\x69\xab\x10\x33\xbe\x68\x75\x69\xa9\x91\xa0\x6f\x70\xb2\xa8\xa6\x93\x1a\x77\x7b\x0e\x4b\xe6\x72\x3c\xd7\x5e\x5a\xa7\x53\x28\x13\xef\x50\xb3\xd3\x72\x71\x64\x0f\xa2\xfb\x28\x7c\x03\x55\x25\x76\x41\xea\x93\x5c\x85\x1c\x0b\x6a\xc6\x8b\xe7\x2c\x88\xdf\xc5\x85\x6f\xb5\x35\x43\xfb\x37\x7b\x0d\xbf\x64\x80\x8a\xfc\xc4\x27\x4a\xa4\x56\x85\x5a\xd2\x8f\x61\x26\x7a\x41\x9b\xc7\x21\x66\xb9\xca\x73\xcd\x3b\xb7\x9b\xf7\xdd\x25\x9b\xaa\x75\x91\x14\x40\x97\x4b\x68\xe8\xba\x95\xa7\x8c\xbb\xe1\xcb\x6a\xd8\x07\xa3\x3a\x1c\xce\x2f\x40\x6f\xf7\xbc\xbd\x05\x8b\x44\xa3\x11\xb3\x8a\xb4\xd4\xe6\x14\x16\xc4\xa7\x4d\x88\x3d\x6a\x6a\x79\x4a\xbd\x9c\xf1\xc0\x39\x02\x8b\xf1\xb2\x0e\x3d\x49\x90\xaa\xe8\x6f\x32\xbf\x06\xcd\x83\x49\xa7\xa8\x84\xcc\xe0\x16\x5e\x36\xa0\x64\x0e\x98\x7b\x9d\x51"}, -{{0x02,0x65,0xa7,0x94,0x4b,0xac,0xcf,0xeb,0xf4,0x17,0xb8,0x7a,0xe1,0xe6,0xdf,0x2f,0xf2,0xa5,0x44,0xff,0xb5,0x82,0x25,0xa0,0x8e,0x09,0x2b,0xe0,0x3f,0x02,0x60,0x97,},{0x63,0xd3,0x27,0x61,0x5e,0xa0,0x13,0x9b,0xe0,0x74,0x0b,0x61,0x8a,0xff,0x1a,0xcf,0xa8,0x18,0xd4,0xb0,0xc2,0xcf,0xea,0xf0,0xda,0x93,0xcd,0xd5,0x24,0x5f,0xb5,0xa9,},{0xb6,0xc4,0x45,0xb7,0xed,0xdc,0xa5,0x93,0x5c,0x61,0x70,0x8d,0x44,0xea,0x59,0x06,0xbd,0x19,0xcc,0x54,0x22,0x4e,0xae,0x3c,0x8e,0x46,0xce,0x99,0xf5,0xcb,0xbd,0x34,0x1f,0x26,0x62,0x39,0x38,0xf5,0xfe,0x04,0x07,0x0b,0x1b,0x02,0xe7,0x1f,0xbb,0x7c,0x78,0xa9,0x0c,0x0d,0xda,0x66,0xcb,0x14,0x3f,0xab,0x02,0xe6,0xa0,0xba,0xe3,0x06,},"\x87\x4e\xd7\x12\xa2\xc4\x1c\x26\xa2\xd9\x52\x7c\x55\x23\x3f\xde\x0a\x4f\xfb\x86\xaf\x8e\x8a\x1d\xd0\xa8\x20\x50\x2c\x5a\x26\x93\x2b\xf8\x7e\xe0\xde\x72\xa8\x87\x4e\xf2\xee\xbf\x83\x38\x4d\x44\x3f\x7a\x5f\x46\xa1\x23\x3b\x4f\xb5\x14\xa2\x46\x99\x81\x82\x48\x94\xf3\x25\xbf\x86\xaa\x0f\xe1\x21\x71\x53\xd4\x0f\x35\x56\xc4\x3a\x8e\xa9\x26\x94\x44\xe1\x49\xfb\x70\xe9\x41\x5a\xe0\x76\x6c\x56\x5d\x93\xd1\xd6\x36\x8f\x9a\x23\xa0\xad\x76\xf9\xa0\x9d\xbf\x79\x63\x4a\xa9\x71\x78\x67\x77\x34\xd0\x4e\xf1\xa5\xb3\xf8\x7c\xe1\xee\x9f\xc5\xa9\xac\x4e\x7a\x72\xc9\xd7\xd3\x1e\xc8\x9e\x28\xa8\x45\xd2\xe1\x10\x3c\x15\xd6\x41\x0c\xe3\xc7\x23\xb0\xcc\x22\x09\xf6\x98\xaa\x9f\xa2\x88\xbb\xbe\xcf\xd9\xe5\xf8\x9c\xdc\xb0\x9d\x3c\x21\x5f\xeb\x47\xa5\x8b\x71\xea\x70\xe2\xab\xea\xd6\x7f\x1b\x08\xea\x6f\x56\x1f\xb9\x3e\xf0\x52\x32\xee\xda\xbf\xc1\xc7\x70\x2a\xb0\x39\xbc\x46\x5c\xf5\x7e\x20\x7f\x10\x93\xfc\x82\x08"}, -{{0x6b,0xce,0x4d,0xfd,0x53,0xbf,0xa5,0x50,0x6f,0x2f,0x55,0x4d,0x2d,0x99,0x4a,0x0d,0xc4,0x0c,0xaf,0xcd,0xec,0x7e,0x1b,0xe0,0x50,0x00,0x6e,0x5c,0x5a,0x4b,0x38,0xa1,},{0xc8,0x90,0x02,0x37,0x28,0xd8,0x39,0x70,0x70,0x29,0x17,0x71,0xe6,0x5e,0x03,0x4d,0x34,0xd4,0xaa,0xe5,0xe2,0x47,0x65,0x3e,0x4f,0xf4,0xc0,0x74,0x59,0x1d,0xa7,0x02,},{0x99,0xae,0x67,0x82,0xff,0x27,0x64,0x6c,0x27,0xf6,0x1e,0x23,0x63,0x6a,0xe1,0x88,0x15,0x21,0xcf,0xa5,0xed,0x25,0x6f,0x70,0xbc,0xe7,0xce,0x00,0xb6,0x82,0x80,0xce,0x8e,0x0c,0x82,0xaa,0x76,0x5a,0xfb,0x8b,0x5a,0x1f,0xf2,0xfe,0x42,0xc5,0x74,0x41,0xe4,0x58,0xe4,0x43,0xdc,0x8b,0x12,0x34,0x77,0xae,0x33,0xd8,0x84,0x88,0x8c,0x0b,},"\x32\x39\x19\x07\x47\xee\x33\xd4\x0b\xf8\x70\xac\x9a\xd4\x9d\x88\xee\x32\x0f\x63\xc0\x52\x57\xe8\xab\x2c\x60\x30\x65\x97\xce\x76\xd1\xf1\xe7\x92\xab\x6a\x65\xca\xa5\x44\xfb\xec\x20\x89\x2f\xd4\x96\x05\x94\xf3\x1b\x37\x63\xef\x07\xd4\x98\x2e\xae\x4a\x2d\xbf\x33\x77\xdc\xc1\xe3\xf9\x5e\x46\xed\x39\xb7\xf0\x22\x2f\x04\xbb\x5c\x3b\x43\x4c\x8f\x9f\x31\x0d\xe9\xf1\x22\xa2\x9f\x82\x41\xe8\x1e\x20\x65\x49\xae\x62\x8d\x2b\x8a\xd7\x68\x97\x2c\x98\x84\x7c\x11\x88\xad\x04\xc8\x35\x35\x63\x78\xbe\xf7\x9c\xd1\x26\x86\x94\x05\xb1\x29\xfd\xbd\xc3\xbc\x48\x9c\xbd\x13\x99\x50\x5d\xad\xef\x76\x17\xb5\xbe\x5d\xa1\x73\xd3\xe8\x0e\x58\x38\xc9\x9e\x34\x92\x76\x24\x27\x29\xe0\x21\x9b\xd7\x47\x6a\xe5\xc4\xf8\x1a\x12\x87\x8f\xb4\x83\xa6\xc0\xe9\xb0\xdf\x29\x62\xeb\x0b\xf0\x01\x57\x78\x2c\xf7\x68\xa1\xb7\x1c\x01\x01\x69\xee\x85\x22\xde\xf0\x02\x4a\xd7\xe4\x57\x75\xa2\x90\x63\x9c\x53\xaa\xf4\x81\x98\xc4\x2d\xe7\x5c"}, -{{0x17,0x86,0x1a,0x8d,0x41,0x54,0xac,0xd4,0xfa,0x9c,0x8f,0xc9,0x47,0xc1,0x88,0x6c,0x11,0x29,0x0b,0xe2,0x22,0x87,0x2f,0xf4,0xf8,0xcd,0x25,0x93,0x9e,0x4d,0x13,0x61,},{0x43,0x77,0x3f,0x44,0x49,0x06,0x5e,0xae,0xba,0xf8,0x93,0x7b,0xaf,0x75,0x85,0x60,0xb0,0xc4,0xd2,0xde,0x46,0x97,0x78,0x39,0xb3,0xb8,0x73,0xd5,0xd7,0xd5,0xfd,0x8f,},{0xa5,0xee,0x02,0x4c,0xcd,0xbd,0xd4,0xc2,0x1a,0x24,0x70,0x9e,0xc5,0x3d,0xcc,0xb7,0xee,0x17,0x62,0x6d,0xd0,0x0a,0x09,0x3d,0x08,0x84,0xf5,0xb4,0x5c,0x4c,0x9d,0x16,0x91,0x84,0x01,0x51,0xc3,0x3c,0x8a,0xa0,0x7b,0x69,0xb3,0x4e,0x16,0xf6,0x16,0x47,0xeb,0xe7,0x93,0xae,0x4d,0xaa,0x70,0xcf,0xf4,0x8e,0x6a,0xb4,0x2f,0xfd,0xbc,0x00,},"\x18\x4d\xf5\xea\x32\x15\xeb\xe1\x80\x39\x0b\x0f\xf0\x42\xba\x23\x81\x15\x5a\x03\x8d\xc7\x32\xf7\x6a\x01\xc7\xe7\x0f\x82\xd1\xcc\xc9\xde\x9a\x05\x96\xb3\xfe\xe4\x47\x20\x9c\x99\x26\x84\xf6\x43\xdf\x21\xf4\xcf\x9d\x17\x92\x62\x79\x0e\x86\x23\xe4\x24\x72\xdc\x35\x19\x97\xe6\xda\x18\x9c\x07\xe1\xe8\x88\x2c\x07\xf8\x6c\x63\x37\xec\x01\x13\x91\x2c\xf9\x22\x15\xc8\xde\x19\x82\xb8\xfc\x57\xbf\xab\xc5\x5a\x3e\x87\x36\xf7\x36\x10\x42\x9d\x97\xfe\xb5\x1d\x79\x4f\x50\x5d\x0c\x5a\x0b\x3a\xbd\x48\xef\x7f\x55\xa6\x28\xf9\x0b\x85\x67\xa1\xc1\x5e\xa9\xd1\x90\xd7\xbf\x4e\xc2\xbc\x93\x34\xad\xa6\xcb\x92\x80\x8d\xfc\x20\x64\x83\x6f\xcf\xa4\x6b\x96\xfd\x7a\x5d\x6f\x4b\x05\x4d\xab\x09\xb7\x35\x95\xfe\xb8\x9e\xd0\x05\xb9\xec\x9d\x31\x88\x12\x1d\xe6\x96\x96\xd6\x4e\x7c\x7b\xbd\xfc\x1c\x46\x9f\xaf\x14\x8c\x38\xa7\x78\x59\x70\xaf\xe1\xac\xd0\x6a\x92\xc9\x94\x78\xfe\x44\x97\x4e\x3b\xb2\x09\x5e\x44\x67\xe9\xb2\xe9\x96"}, -{{0x0a,0x84,0xba,0xa5,0x4f,0x11,0xcf,0x17,0x09,0x0f,0xec,0x61,0xf3,0xf9,0x40,0x15,0x08,0xa3,0xa0,0x38,0x87,0xac,0xa1,0xa7,0x93,0x93,0x94,0xb1,0xee,0x40,0xa9,0x25,},{0x30,0x9a,0x73,0xc6,0x2d,0x23,0xd7,0x40,0xf2,0xe9,0x3c,0x18,0x58,0x7a,0xc1,0x5e,0x7e,0xc4,0x80,0xd2,0x5a,0xc0,0x79,0x4e,0x10,0xf8,0xcd,0x46,0x1c,0xc2,0xb1,0x30,},{0x4d,0x87,0x0b,0xd5,0x3a,0xf8,0xf1,0x3f,0x21,0x4d,0x99,0x34,0xec,0x90,0x3a,0xc4,0x82,0x84,0x09,0x2c,0xd9,0xb1,0x62,0xa4,0x4c,0xce,0xc8,0x51,0xfa,0x94,0x2d,0xe7,0x15,0xcc,0xda,0x07,0xb7,0x99,0x1d,0x71,0x27,0x23,0xe7,0xa4,0xd5,0xb4,0xf0,0x37,0x4a,0xb8,0x5a,0xc3,0x86,0x7e,0x0b,0x53,0xeb,0xc4,0x6b,0x53,0x0f,0x9f,0xed,0x05,},"\xfe\x70\x01\x7b\x14\x67\x8b\x0d\x3a\xd0\x3e\x18\x3d\x6f\x53\x31\x43\x78\x37\x9a\xb3\xda\x65\xb3\x51\x12\x57\xb3\xd5\x40\x86\xe8\x6f\x20\x31\x13\x90\x21\x39\x1a\xf9\xd7\x20\x85\xff\x7c\x3d\xc8\xc1\xe2\xd9\x1e\x53\x33\x38\x55\x42\x3d\x0f\x78\x5e\x2c\xc5\xf8\xb7\x79\x9f\xcf\x1b\x70\xe6\xbe\xcb\x78\x8e\x53\xe9\x02\x0f\x29\x95\xdd\xb0\xc3\x83\xa1\xf8\x10\x38\xfc\x3d\x54\x3c\xe0\xa3\x8c\x9c\x28\x8a\x9b\xc4\x07\x7f\x42\x77\xdc\xc6\xc5\x64\x22\x63\xfc\xfe\x19\x68\x80\x05\xa6\x03\xf5\x76\x75\xd2\x43\x4f\x3e\xd1\xf4\x6d\x32\xf1\x4e\xae\xb0\x73\xe8\x3e\xe7\x08\x6d\xa2\xfb\x67\x65\x9d\x3f\xb6\x8c\x62\x32\x0b\x77\x27\xb3\xb8\xea\x00\x65\x76\xbc\x2c\x7e\x6b\x5f\x1e\xce\xfa\x8b\x92\xe7\x0c\x92\xc8\x89\x51\xd0\xc1\x2d\x91\xde\x80\x1c\x38\xb7\xca\x5a\x0a\x04\xb4\xc3\x42\x9a\xba\x86\x38\x6e\x96\xe0\x6a\xfd\x20\xd4\xc5\xc2\xfe\x2b\x9b\x42\x73\xeb\x05\x20\x1a\x79\x27\x3a\xbd\xbe\xb3\x7e\xd1\x83\x0d\x22\x6b\x6b\xdb"}, -{{0x38,0x37,0x94,0x23,0xda,0xfd,0xbf,0x25,0xe1,0x9d,0x72,0x31,0xbd,0xdd,0x80,0xb4,0xce,0xfc,0xfe,0x2a,0xed,0x93,0x25,0x84,0xdf,0xa0,0xcc,0x3c,0x9f,0x92,0x32,0xde,},{0x59,0x7e,0x81,0xdc,0xee,0x94,0x48,0xb7,0x7d,0xe6,0x82,0x9e,0x79,0x21,0xc8,0xa3,0x90,0x53,0x5d,0x89,0xa0,0x84,0x94,0x30,0xae,0xd6,0x63,0x64,0xee,0x14,0x0d,0x8b,},{0xd8,0xb5,0x0a,0x88,0xae,0xd6,0xf2,0xa9,0x6d,0x08,0x22,0x13,0xad,0xf8,0xb2,0x51,0x9f,0x6a,0x0b,0xbd,0x30,0xdd,0x3c,0xb0,0xf3,0xfd,0x3c,0xe1,0xc6,0x43,0xfc,0x02,0x99,0x46,0xcd,0x43,0x46,0x2e,0xd2,0x25,0x13,0xf1,0xd6,0x5f,0xca,0x24,0xbd,0xe3,0x81,0x81,0x66,0xba,0xa8,0x6d,0xaa,0x79,0x87,0x92,0xaf,0xaf,0xe0,0xc1,0xa1,0x0a,},"\x36\x12\x5c\xa6\x66\x68\x80\x29\x06\x23\x7e\x63\xa2\xfe\x5a\xe6\x10\xf1\x1a\x7c\xf9\x25\x20\xd1\x9e\x66\x90\xa3\xad\xfa\xfd\x5d\x07\xa7\x84\xbc\x1a\x0e\x18\x52\x73\xd1\x1d\x34\x0d\x5e\xff\x90\x15\x97\xde\xdf\x45\x0c\x46\x99\xd4\x3f\x3f\xb1\x68\xd5\x57\xf6\xc9\xc0\x30\x77\xc3\xcd\xc3\x70\xd3\x48\x32\xcc\xdf\x2a\x8e\x3d\x75\x79\x64\x90\xed\x02\x42\x89\x9d\x25\xdd\xf4\x4b\xfc\x66\xf3\x29\xcf\x4c\x45\x16\x87\x03\xc3\x1b\xc9\x20\x2d\x89\x0f\x39\x69\xff\xd3\xac\x35\xa1\x28\x18\xdc\xa7\x51\xce\xb8\x80\x8f\xe8\x1e\xfa\x26\xa5\xe0\xd2\x00\xc5\xec\x1d\x94\xa5\x09\x7e\xa7\x4b\x64\x98\xfe\x28\x8f\x30\xc4\x8d\x72\x7e\x9d\x3d\x35\xc8\xe1\x2d\x85\x42\x07\x02\x55\x6f\x28\x61\x48\x4f\xfd\x09\xb4\xf1\x22\x65\xcc\x9a\xba\xfe\xb8\x2c\xf5\x90\x02\x88\x95\xa7\xd0\x50\xff\x57\xcc\xf5\xf2\x80\x22\xd0\x16\xab\x40\x94\xb0\x62\xe4\x8b\x66\xfd\x36\xd1\xe1\x96\x26\xe5\x21\x5e\xfa\x40\xfb\x7e\x3b\x70\x62\xf8\x1e\x95\x48\x30\xc9"}, -{{0xf9,0x25,0xd2,0x74,0xaa,0xf1,0xfe,0x1a,0x21,0x65,0x62,0x37,0x38,0x5e,0x97,0xf7,0x78,0x3e,0x78,0x09,0x0c,0x5d,0x42,0x17,0xfe,0xce,0x70,0x57,0xc8,0x0f,0x42,0x6d,},{0x3b,0x0f,0xc3,0x70,0xbe,0x3a,0x4b,0x19,0xa8,0x8a,0xb9,0x98,0xc5,0x95,0x04,0xff,0xb5,0x9a,0x87,0x60,0x63,0x38,0xe6,0x73,0xdf,0x5b,0x3f,0xab,0x4d,0x9b,0xfb,0x8d,},{0x79,0x54,0x9a,0x31,0x7d,0x10,0xa0,0xbe,0x32,0x2a,0x94,0xa1,0x51,0xad,0x11,0xe7,0x7e,0xfc,0x48,0x36,0xcc,0x80,0x06,0xa8,0x50,0x81,0x27,0x3d,0x76,0x02,0xa6,0x38,0x96,0x3a,0x9c,0xaf,0x19,0xc3,0xed,0xf1,0xe2,0x5f,0xad,0x1e,0x9d,0x68,0x70,0x1a,0x71,0xde,0xa7,0x27,0xda,0x6a,0x5c,0x5b,0xca,0xc9,0x33,0x95,0x89,0x22,0x4b,0x05,},"\x14\x3c\xaa\xfa\x5f\x62\xb1\x3e\x43\xdf\xfa\x49\xd4\x20\xfa\x99\xf7\x71\xb1\x92\x6d\x40\xd6\xcb\x2b\xbb\x42\x7f\x27\xb6\xc2\x66\xeb\x3d\xeb\x2d\x8b\xbb\xd4\x7b\x82\x14\xad\x40\x25\x1c\xb1\x90\x7a\xd6\x5e\xb9\x41\x93\xe5\x4a\xd8\x5c\x67\x00\xb4\x18\x9e\x80\xf1\xcc\x01\x54\xc6\x3e\xd1\x51\xa8\xbb\xbd\x30\xe0\x16\x37\xca\x58\xe7\x0a\xa3\xee\x52\xef\x75\xd0\x87\x30\x78\xa4\x05\x01\x4f\x78\x6e\xb2\xd7\x7b\x7f\x44\x22\xf9\x27\x82\x3e\x47\x5e\x05\xb2\x42\x45\xf9\x06\x8a\x67\xf1\x4f\x4f\x3c\xfb\x1e\xb3\x0b\xfe\xde\x7b\x32\x62\x23\x0c\xed\x9e\x31\x36\x1d\xb1\x96\x36\xb2\xc1\x2f\xdf\x1b\x9c\x14\x51\x0a\xcd\x5b\xc1\x8c\x0d\xdf\x76\x35\xe0\x03\x50\x3e\x6f\x71\xe1\xc3\x65\xcd\xfb\x4c\x65\xee\x75\xb4\xde\x06\x94\xaf\x87\x07\x63\x74\xd6\x31\xe6\xc4\xb8\xe2\x40\xfa\x51\xda\xb5\xe1\xf8\x0c\xa2\xa0\x6c\x49\xf4\x2e\xa0\x9e\x04\x75\xde\xfb\x18\x4d\x9c\xde\x9f\x58\xf9\x59\xe6\x40\x92\xaa\xc8\xf2\x02\x7e\x46\x81\x26\xf2\xfb"}, -{{0x97,0x1f,0x80,0x6b,0xe6,0xf0,0x7d,0x41,0xbe,0x88,0x30,0xff,0x8d,0xae,0x70,0x4b,0x08,0x63,0x8a,0xd6,0xcf,0xf7,0x22,0xd8,0x43,0x25,0x38,0x12,0x7b,0x76,0x96,0x25,},{0xaf,0x6a,0xc9,0x8d,0xce,0x20,0x78,0xa6,0xc7,0x3f,0x60,0x97,0xba,0xb6,0x3f,0x20,0x5c,0xaf,0x69,0x53,0xaf,0xa2,0x84,0xd0,0x42,0xbd,0x50,0xa4,0xfc,0xe9,0x6c,0xb4,},{0x20,0x37,0xa0,0xa7,0x67,0x4b,0x84,0xff,0x27,0xd0,0xb2,0x2f,0x62,0xb4,0xba,0xc6,0x5e,0x2d,0xc0,0xf5,0xfd,0xc8,0x99,0xfe,0xb7,0x80,0x0f,0x25,0xc2,0x99,0x81,0xde,0xe6,0x41,0xc5,0xa5,0x0f,0x8b,0x94,0x10,0x97,0x0b,0x49,0xd2,0xd5,0x36,0x58,0xc8,0x9e,0xe1,0x69,0x61,0xdc,0xcf,0x53,0x91,0xa6,0x91,0x8f,0x2a,0x84,0xea,0xda,0x0b,},"\x01\x34\x55\xd0\x49\xaa\x54\xed\x99\x5f\xbd\x94\xe6\x36\x99\x55\x49\x53\x95\xe4\x43\x88\x22\x25\x9b\x10\x60\xe9\xa3\x47\x79\x04\x2a\x1a\x69\x21\x1f\x6e\xa2\x07\x73\x99\xdd\x23\x48\x06\xba\x0b\x35\x3c\xd7\x9a\x57\xe1\xc4\x9b\x25\x0a\xb2\x71\x06\xdc\xde\x57\x6e\xcf\xa1\x15\xea\xe4\x61\xfe\xbb\x12\xd2\xda\x25\xff\xcf\x17\xb7\x15\xf8\xd9\x5c\x2f\x0c\x42\x5d\x5a\x81\xf7\x00\x11\x5b\x70\xd4\x9e\x1c\xfe\x49\xfc\xaa\x14\xfa\x20\x5e\x28\xec\x85\x24\x7f\x1a\x6e\x71\x28\xbf\x3b\xb3\x06\x0d\xc0\x84\x64\xbd\xa6\x53\x85\x40\xd0\xac\x47\x20\x93\xe5\xa0\x72\x0f\xde\x2f\x3d\xc4\x78\x8e\x0e\x9b\x0d\xbf\xe2\xa2\xb5\xf1\xa0\xf3\xf8\x0d\xe9\x84\x02\x5b\x15\xc6\x5a\xf7\x7f\x67\x1e\x1c\x5e\x28\x40\x44\x4d\xe5\xc7\xed\xa0\x25\xe6\xdc\x1a\x3f\xf1\x6e\x26\xcc\x54\xcd\xee\xd5\x6b\xe7\x3f\x9b\x01\xab\x2b\x1b\xc1\x6c\x8e\xf5\x8a\x5b\x76\xdd\x47\x28\x78\x07\xe5\xc5\x0f\x0d\x7c\x0a\x5b\x81\x20\xdf\xde\x64\x5a\x01\x2c\x5c\xf1\x14\x91\xbc"}, -{{0x2b,0xb0,0x65,0x2f,0x8f,0xff,0x69,0x01,0x99,0x11,0x48,0xc6,0x8a,0x32,0x67,0x87,0x72,0x71,0x00,0x6a,0xe9,0x58,0x91,0x49,0xbb,0x20,0x68,0x50,0xcd,0xf5,0x2f,0xb0,},{0xc0,0x3b,0x77,0xbe,0x98,0x3e,0x74,0xa2,0x34,0xc1,0x98,0x64,0x96,0xb2,0x92,0xe1,0x39,0x99,0x2e,0xb7,0x52,0x9e,0x70,0xb3,0xaf,0xad,0x7a,0xe4,0xfd,0xcf,0x8a,0x66,},{0x4e,0x15,0x8d,0xea,0xae,0xc3,0xd8,0x89,0x41,0x29,0x6a,0xf2,0xd2,0x73,0x41,0x01,0x2b,0x02,0x41,0xd4,0xe0,0xf4,0x6e,0x43,0x5e,0x37,0x5c,0x98,0x75,0xe8,0x9f,0x5e,0x32,0xc0,0x57,0xb5,0x27,0xbc,0x34,0x11,0xaf,0x09,0x6a,0x77,0xbf,0xce,0xb4,0x5b,0x98,0x3e,0xfe,0x45,0x5e,0x3f,0x03,0x15,0x5d,0x6b,0xc7,0xb0,0xac,0xc8,0xe6,0x0c,},"\xb9\x23\xca\x67\xe3\x96\xd8\x65\x6f\xa3\xdb\xce\x82\x89\xa3\x8b\xd3\xc1\x28\xce\xfb\x30\xef\xc1\x86\x2b\xb9\x44\xb4\x50\x78\x05\x41\x98\x24\xce\x2b\x83\xd6\x90\xef\x4c\xf1\x07\x49\x28\x17\x14\x3b\xf6\x4c\x02\x49\x89\xaf\x1a\x7d\x2e\x1f\x5a\xc9\x78\x74\xf8\x6b\xb0\xd3\x77\x3f\xf8\x40\xf5\x14\xd9\xa1\x39\x4a\x39\x59\xb0\x11\xd3\xa6\xb8\x16\xa3\xfa\xe5\xde\x17\xb2\xa9\xff\x34\x98\x63\xd2\x7f\xbb\xb5\x0c\xca\x73\x41\x08\x75\x10\x00\xd6\x35\x8c\xa0\x64\x7a\x93\xeb\x49\xe2\xe7\xaf\x06\x28\x7d\x48\xf2\xc0\x9d\x5c\x1c\x73\xe4\xd8\xf7\x7e\xa2\xbc\xaa\x73\x56\x79\x5b\x26\x72\x87\x19\xbe\xd5\xff\xdb\x82\x15\x78\xbd\x5d\x66\xbf\x92\xed\xaf\x8b\x23\x8b\x2b\xbd\x7d\x1e\x2c\x30\xa7\x87\xf9\x01\xa3\x3d\x0a\x76\x66\x9a\x9c\x3c\x7f\x2b\x55\x2c\xcb\x83\x49\xc7\xde\xd5\xe1\xa4\x61\x70\xcf\x28\xe3\x59\xe2\xfd\xd5\x4b\x05\xa5\x62\xf5\x28\xc6\x8a\x56\x97\x4d\xf8\x2d\x46\x66\x37\xc8\xe5\x32\x46\xa7\x21\x7e\x43\x86\x80\x1e\x0e\x32\x66"}, -{{0xdb,0x9b,0x81,0x2c,0xb3,0xc7,0xc0,0x3b,0x97,0x7f,0x48,0x7d,0x3d,0x65,0xcc,0xd9,0xcd,0x2f,0x3d,0xee,0x11,0x60,0x20,0x67,0xdb,0xfb,0x72,0xb5,0x89,0xff,0x3f,0x79,},{0xff,0xa0,0x38,0xad,0x8c,0x3b,0x37,0x8c,0xe7,0x5d,0x65,0x84,0x4d,0x08,0xe3,0xd6,0xa9,0x2d,0x19,0x4a,0x1b,0x78,0x62,0xe9,0xd9,0x72,0x0d,0x20,0x67,0x9b,0x29,0x44,},{0xa6,0x28,0xa7,0x74,0x21,0xb2,0xab,0xab,0x57,0x6e,0xed,0x35,0xd2,0xee,0x3d,0x14,0x56,0x1b,0x21,0xfa,0x14,0xa6,0xe2,0xfa,0xc2,0x63,0xc3,0xea,0xdd,0x79,0xf2,0xfc,0x06,0x69,0xf9,0x42,0x9b,0x91,0x0b,0x84,0x22,0xb4,0xb2,0x9a,0xc0,0x26,0xa4,0x2e,0x98,0xd1,0x81,0xbe,0x35,0x07,0xc5,0xed,0x7c,0x74,0x8a,0x1f,0xdc,0xf1,0xd8,0x07,},"\xa7\x00\x92\xc7\x69\x7c\xd4\xa2\x09\x56\x7c\x38\xba\x7f\xb7\x1a\xa8\xf1\x5e\x58\x27\xa2\x08\x76\x92\x39\x43\xfd\x6a\xdc\x65\x9c\x98\x67\xac\x6f\x58\xa6\x1d\xc7\xce\xc3\xd3\x62\x41\x16\x82\x00\x0c\x1a\x9a\xd1\x29\x5e\xb8\xb7\x0f\x24\x2d\x86\xb5\x86\x5e\xb7\x6b\x87\xe3\xf2\xc6\x94\x1d\x26\x12\xee\x3b\xcd\xe8\xf1\x97\x65\x56\x67\x33\x15\x2e\xf5\x4e\x95\x69\x09\x43\x28\x5f\x78\xb3\x75\xf4\x03\x65\x85\xd4\x73\x9d\xee\xde\xef\x6d\x94\x6d\xb6\x1c\xa4\x58\xef\x4f\x65\x0d\xa9\x63\xc3\x85\xe2\x9d\xfd\xee\x41\x5f\xe4\x95\x84\x5f\x55\x19\x7a\x87\x0f\x8c\xde\xb5\xa0\x10\xba\x6b\xbb\x32\xbf\x1a\x58\x8c\xc7\x74\xd4\x89\x01\x84\xc4\xb2\x92\x4a\x5b\x80\x73\x31\x3b\xce\x22\x65\x85\xf1\xad\xfc\x22\x9c\x90\xbc\x6c\xc9\xd2\x12\xe6\x2f\x05\xd3\x3b\xed\xac\x96\x1d\x77\xcf\x8c\x26\x20\xe4\x51\xde\x81\x7f\x8c\x1b\xb1\x6a\x2c\x59\xff\x80\x4b\x63\x5a\x73\xa8\xcf\x8c\x18\x1b\x3f\x94\x01\xc3\xb6\x43\xd1\x8a\x2f\x70\x6e\xa9\xca\xe4\x70\x71\xa6"}, -{{0xce,0x37,0x9b,0xbe,0x2f,0xa8,0xab,0xcb,0xa5,0x1c,0x7a,0x75,0x43,0xde,0x5b,0x71,0x80,0x77,0x1b,0x3c,0x44,0xbc,0x6b,0x41,0x89,0x2e,0x7b,0x88,0x97,0x9b,0xab,0x90,},{0x7f,0x3c,0xff,0x89,0xf4,0x1b,0xab,0xf4,0xfa,0x64,0xcb,0xa3,0x3a,0x5b,0xb1,0x7f,0x41,0x3b,0xbf,0x2a,0x1e,0x11,0x2b,0x50,0xa8,0xe9,0xb1,0xf8,0x21,0xd8,0x49,0xbf,},{0xda,0x98,0xdf,0xb1,0x89,0x38,0x5b,0x2c,0x85,0x3b,0x6c,0xf3,0x75,0x73,0x80,0x46,0xa8,0xf2,0x7e,0xf2,0x79,0x74,0xab,0xce,0xce,0xa1,0xdb,0x02,0x98,0x9b,0x95,0x1f,0xe4,0x33,0xa6,0xce,0x1e,0x22,0x5b,0x3f,0xa8,0x20,0x32,0xfe,0x06,0x0a,0x7d,0x3f,0x6c,0x18,0x3f,0xd1,0x15,0x7f,0x79,0x1a,0x06,0x4b,0x40,0x76,0x50,0x57,0x16,0x00,},"\x00\x1a\x74\xf0\x95\xc8\x14\xd3\xbe\xed\x67\xa8\xd1\x5f\xc1\x8e\xfe\x23\x5d\xc3\xf6\x45\x78\x12\xa4\x03\x9b\x7a\x46\xfe\x9a\x0e\x9d\xe8\x1a\x7a\x4e\x5f\xba\xb5\xeb\xe9\xe1\xe4\x80\x1b\xd1\x1b\x45\xc9\xf7\xad\x06\x36\xa0\x9b\xff\x42\x16\x4b\xe5\x74\x9a\x04\xc0\x2f\x0a\xb6\x1f\x0e\xcf\xdf\xef\x79\x9b\x82\x7d\xa6\xa2\x74\xc8\xd3\xb3\x9f\x2e\x38\x05\xa6\x79\x12\x87\xee\xdb\x23\x14\xd3\xf8\x42\xb5\x58\xb9\xb4\x89\xaf\xe1\xed\x37\xbb\xbc\xfc\x5e\x60\xa4\x31\xd5\xac\x60\xb3\x9e\x94\x6d\x90\x3d\x6b\xf6\xb1\x40\xe1\x2c\x7e\x07\xf9\xed\x7a\xc4\x6a\x39\x99\xc6\x24\x5c\x8a\xb1\xbd\xb2\x18\x79\xa3\x17\xa3\xdc\xd2\x57\xa5\xc4\xf3\x49\xb7\xf5\x9e\x4e\x43\xd6\x2d\x9f\x1c\xd1\x6f\x51\x8f\x1c\xa6\xca\xd3\x7e\x2c\xb2\x0f\x25\x98\xc4\x13\x42\x91\xc6\xb8\xa9\x8a\xae\x52\x47\xe2\x6e\xef\xb7\x6a\xa3\x8c\x9c\x82\x31\xc1\x7e\x9d\xbf\x27\x1c\xec\x80\xfb\xa5\xb4\xa8\x34\xbd\x9b\xe8\x1e\xa8\x41\x63\x7a\xa9\xcd\xd4\xc4\xbf\x26\xd7\xad\x24\xca\x3c"}, -{{0x2b,0x2e,0xe8,0x09,0xd6,0x47,0x02,0x3e,0x7b,0x77,0xfc,0x54,0x1f,0x44,0x87,0x5a,0x35,0xfa,0x94,0x1d,0x37,0xf7,0xc5,0xb2,0x1f,0xd3,0x49,0x34,0xd2,0x39,0x19,0x35,},{0x2c,0x29,0xd5,0x3e,0x1b,0xf2,0xc7,0x87,0x9d,0x73,0xd2,0x0b,0xa8,0x8c,0xa0,0x7a,0x0b,0x21,0x6d,0x7f,0x6d,0x05,0xd9,0x36,0x63,0xa6,0x5c,0x3d,0x9e,0x10,0x63,0x3a,},{0x12,0xd9,0x06,0x85,0x77,0x55,0x72,0xc9,0xea,0xbc,0x9b,0xe2,0x57,0x4c,0xa9,0xae,0x66,0xf0,0xe6,0x52,0xe5,0x78,0xb2,0x17,0x36,0xcd,0x6e,0x65,0x4f,0x7c,0x6b,0x15,0x45,0x88,0x3d,0x56,0xbf,0x76,0x0c,0xcf,0xc3,0xcf,0x87,0x54,0x4e,0x00,0x04,0xc7,0x98,0x06,0x12,0x57,0xe1,0x30,0x03,0x0c,0xb9,0x97,0xa7,0x88,0x36,0x9a,0x9a,0x05,},"\xc4\x14\x7d\x64\xeb\xfd\xa4\x1a\x1b\xe5\x97\x72\x62\x95\x81\x04\xe9\x40\xc3\x87\x6b\xcd\x5b\x69\x56\xac\xfd\xec\x32\xc6\x60\x91\x4d\x62\x62\x3c\x21\x06\x63\xcb\x2c\xbe\x62\x49\xd7\xf5\x27\x49\x91\xc6\x0e\x95\x0e\x8e\x28\x09\x04\x99\x53\xc6\x95\x81\xd2\x46\x9f\x4f\xe9\x82\xc7\x43\x4f\xed\xd9\xd4\xe0\x0a\xe0\x88\x96\xd6\x2c\xc1\xfb\x98\x4d\xd2\x33\x15\x0c\xc2\x48\x3e\x15\x9c\xff\x40\x97\xdf\x8c\x03\x6b\xb6\x33\x00\x3a\xbb\xfb\xe1\x8c\x8f\xa7\x9b\x5a\x22\x27\x08\x38\x12\x3f\xc9\xbe\x39\xb8\x89\x2c\x80\x38\x4a\x38\x50\x28\xc1\xa8\x1e\xc5\x8c\x8f\x21\x06\x0e\x78\xaf\xd2\xc0\x4b\xfd\x2d\x30\xca\x39\x77\xc6\xed\xad\x51\x8c\xc1\xe2\x00\x4c\xdc\x14\xbf\x3d\x15\xf5\xf5\x28\xe5\xaf\x27\x7f\xa1\x82\x27\x58\x70\xe5\xc0\x12\xf5\xf8\x2f\xb1\xaf\xd0\x4e\xdd\xe4\x57\x8d\xdd\x21\x60\xa1\xa3\xdb\xc0\x50\xe8\x0b\xdd\x81\x1b\xc8\x8e\xad\x79\xbf\x93\xf0\x10\xcd\x0f\xd4\x43\x3d\x0b\xc3\x48\xda\xcf\xd0\x94\x7c\xce\xda\x62\xbf\xa4\x97\x11\xd0\x13"}, -{{0x4e,0xa1,0x8d,0x6b,0x4a,0xf8,0x05,0x3b,0x88,0x5e,0xc1,0x88,0xbe,0x48,0xde,0xb8,0x6f,0xfb,0x2a,0x69,0xa4,0xce,0xc8,0x66,0x37,0xbb,0xd7,0xb4,0x1b,0x80,0x7c,0x46,},{0xe5,0x98,0x60,0x59,0x97,0x62,0x33,0xed,0x77,0x38,0x2c,0x3d,0x99,0x59,0xf3,0x4e,0x31,0x79,0x62,0x69,0x65,0x53,0xe8,0x6e,0xd1,0xe5,0x90,0x2c,0x4b,0xed,0xd1,0x67,},{0x27,0x57,0x0c,0x00,0x2a,0x48,0x7d,0x00,0x0c,0xa3,0x92,0x8b,0x83,0xcb,0x43,0x19,0x72,0x2c,0x46,0xdf,0xb4,0xcc,0xa2,0x60,0xde,0x79,0x0e,0xc0,0xe3,0xc1,0x93,0x26,0x88,0xf8,0x73,0x62,0x95,0x28,0x18,0xb5,0x4f,0x51,0xbc,0x7a,0xee,0xb2,0x63,0xf9,0x60,0xbc,0x0d,0xa8,0x96,0x4b,0xf3,0x12,0xef,0x93,0xe8,0x1f,0x06,0xc8,0x0b,0x04,},"\xe9\xc8\x9a\x1a\x11\x19\x37\x32\x06\xce\x40\xed\xe3\xb8\x9a\x82\xf8\x94\x62\xa1\xde\xe9\xe7\x89\xe9\x84\x5e\xec\x21\xf5\x71\xc0\xfa\xef\xd4\x30\xad\x33\x8e\x4a\x72\xc0\x47\xa3\x9a\x42\x59\x58\x03\x87\xfb\x9a\xac\xad\xdc\x36\xa2\xb5\x1e\x7b\x60\xa8\x7c\xa1\x32\x1f\xf8\x06\x79\x4c\xd6\xdd\x45\x49\xa4\xdf\x45\xc2\xda\xe3\xe5\x39\xc4\xd7\xd0\x6b\x6e\x6e\x9f\x46\x6f\xfc\xa2\xfa\x49\x78\xce\x3d\xc7\x92\xe4\x4a\x62\x83\x88\x0c\xd1\x38\xa7\x5a\x22\x6f\x98\x5d\xa4\x1f\xfd\xc0\xe3\x2a\x5a\x85\xc8\x5f\xe9\xa4\x3a\xe7\x8f\xcf\xe5\x7f\x4d\xd7\x54\x0a\x6d\xd3\x92\x4a\x49\xab\x39\xeb\x69\x95\x0d\x42\x11\x51\xd9\x6b\x1e\x4f\xd3\x93\x58\x90\xf6\x34\xcd\x52\xa7\x3a\x75\x5f\x5c\x2f\xb7\x2f\x9c\xd5\xa2\xe6\x7e\xa9\x30\x91\x5e\x13\x3b\x47\xcf\x6b\x7c\x10\xa9\xd8\x89\xc6\xaf\x6b\x5f\x1f\x4f\x51\x09\x4d\x27\xfb\xba\x22\x8a\xc2\x26\x8b\x34\x40\x27\xfd\x49\xe4\x26\x34\x3c\xc0\x13\x43\x99\xb4\xb5\x10\xaa\xea\x50\x23\x4d\xf4\x2c\x37\xfa\x1c\x4f\x4d\x0e"}, -{{0xfc,0x1b,0x75,0xd1,0x7d,0x38,0x07,0x21,0x73,0x51,0xd2,0xaa,0x40,0xd9,0xb0,0x4f,0x52,0x5b,0x89,0xed,0x3f,0x5f,0xcd,0xb3,0x11,0xbe,0xc2,0xae,0xc5,0xcb,0x7e,0xce,},{0x55,0xe4,0x84,0xe7,0x74,0xa4,0x39,0x2a,0x9d,0x6e,0xef,0xf8,0x35,0xa8,0xfb,0xb2,0x32,0xcf,0x62,0x76,0xa8,0x9c,0x74,0xfc,0x0d,0x1b,0xb2,0x04,0x5a,0x8b,0x21,0xbe,},{0x9a,0x68,0xd1,0x51,0xfe,0xa3,0x90,0x98,0x93,0x35,0x9e,0x60,0xb9,0x6b,0x68,0xb2,0xa3,0xe2,0x94,0x6f,0x2b,0x47,0xb8,0x75,0x39,0x8a,0x1e,0x39,0xeb,0x01,0x46,0x3d,0x35,0xea,0xe7,0xd9,0x76,0xf8,0x33,0xa7,0x62,0xb5,0x1f,0x27,0x26,0xee,0x0d,0xcc,0xad,0x5c,0xe3,0x60,0x05,0x64,0xfd,0x9d,0xd5,0x8c,0x23,0x80,0x7f,0xdf,0xfd,0x05,},"\xd0\x31\xbd\x11\xda\x30\x80\x97\xe3\xbe\xb6\xff\xdb\x26\x00\xee\x6a\x19\x3c\xa6\xd8\x32\x45\x01\xc9\x72\xb1\xa2\x51\x66\xfa\x7a\x36\x9f\x5b\xc8\x82\xea\x45\x61\x2c\xf0\x25\x80\x25\x4d\x21\xb4\x0b\x03\x63\x23\x7e\x83\x5d\xae\x26\x56\xc1\xb7\xf4\x73\x6e\x88\xbe\x53\xd6\xb1\x19\xc0\x7f\x57\x29\xbb\xd8\x2f\x67\xde\x03\x58\x83\x22\x87\x92\x43\xc5\x99\x0a\x7e\x61\xf5\x69\x07\xb2\x41\x71\xa5\x7c\xbb\x0b\xbe\xfb\xa2\x31\x62\x77\xaf\x93\x26\xf9\xcb\xf3\x53\x8b\xcb\xf6\x78\x0b\xe4\x18\x25\xa2\xca\x77\x4b\x41\xbd\xb1\xcd\x5c\x60\x88\x51\xec\x23\x39\xeb\x2f\x4f\xee\xdd\xaa\x89\x1a\x63\x26\xb2\x9d\x97\xd7\xfb\xf3\x11\xe3\xbb\x74\x9c\x5d\x4c\x05\x8d\xcc\x14\xf4\x52\xf9\x33\x49\x91\xe2\x71\xc1\x6d\x65\x08\xc8\x18\x63\x39\x27\xf4\x29\x80\x4c\xa7\xa3\x81\x70\xf1\xb9\xf6\xbd\x73\xed\x67\x5e\x11\xe8\xc0\xd3\x21\xfa\xc9\x12\x73\x0b\x4b\xa2\xf7\xc4\x28\x53\x4a\xdc\xaa\x4d\xad\x31\x4c\x55\x80\x7e\x6c\x64\x2d\x49\x4c\x6b\x2f\x0e\x8c\xd1\x29\x77\x5c\xc0"}, -{{0x0d,0x0b,0xf4,0xd4,0x2e,0xf8,0x10,0xb1,0x79,0xeb,0x84,0x17,0x71,0xde,0x6d,0xbd,0xe7,0x63,0x61,0xca,0xf8,0x94,0xe4,0x2a,0x14,0xb1,0xe0,0x97,0x87,0xea,0x3e,0x06,},{0x71,0x71,0x51,0x0b,0x43,0xfc,0x17,0xef,0xa8,0x0b,0x15,0xe3,0x20,0xb1,0xb0,0xa4,0x08,0x33,0x25,0x42,0xe0,0xd3,0x6e,0x4a,0xb9,0xa6,0x49,0xcd,0x94,0x1b,0x5a,0xed,},{0x24,0x44,0x6b,0xdf,0x03,0x41,0x6a,0x4d,0x08,0x61,0x44,0x66,0xfb,0x85,0x1d,0xb5,0x0e,0x91,0xa6,0x23,0xca,0xcd,0x1b,0x0b,0x35,0x66,0x0f,0x3c,0xf9,0x33,0x20,0x0e,0x15,0x30,0x87,0x08,0xda,0x34,0x99,0xa5,0xad,0x25,0xf0,0xf0,0x30,0x6b,0x79,0x42,0x76,0x2e,0x20,0xa7,0x65,0xb7,0xca,0x9b,0x90,0x1c,0x75,0x0b,0x3a,0x95,0x32,0x0a,},"\x8e\x21\x79\x97\x5d\x0a\x8e\x5a\x69\xfe\x87\x5a\x3c\xb1\xe7\x9a\xec\x49\xc3\x85\x3e\x30\xdd\x03\x20\xfe\x3e\xbf\xb6\x38\xb8\x2f\x89\xad\x16\x43\x03\x6b\x37\xe5\x6e\x0b\x55\xe0\xa9\xe2\x2a\x4e\x28\x3d\x7a\x27\x48\x5c\xe9\x10\x2d\xb6\x78\x7d\x66\x28\xb7\x79\x13\xe1\x08\x96\x77\x4e\x49\x5c\x26\xe8\xba\xb2\x6e\x7f\x9a\x94\xd2\x9a\xaa\x36\xae\xc9\xc2\x6a\xd3\xf5\x0e\x5d\x8c\x0b\x76\x98\xbb\x5f\x01\xb8\x76\xd0\xd6\x5f\xcf\x5e\x9e\x32\xcd\x7b\x89\x82\x9e\xd0\x5b\x0b\x8f\x63\xa9\x38\x58\x98\x5b\xc9\x56\x9f\xce\x42\x9f\xd3\x7a\x21\x1a\xbe\xd6\x50\xf5\x85\xc3\xb5\x59\x00\x44\x3b\x6c\x5d\x6e\x8a\x48\xba\x67\xde\xee\xd0\x7b\x76\xe9\x69\xfc\x88\x43\x0f\xce\x27\x09\xc0\xbb\x5c\xe9\x26\xab\x7f\x44\xe0\xcd\x79\xf4\xec\x35\x9e\xf7\x67\x48\x88\x3f\xcc\x3d\x02\x6e\xdd\x06\xc8\xb9\xcb\xa5\x4b\x99\x0d\x30\xaa\x41\xf1\x44\x8a\x10\x89\x3f\xb0\x53\x92\x80\xc5\x99\xd4\x23\x61\x43\x3a\x34\xcd\xaf\xd8\xeb\xdd\x92\xef\xb9\xc3\x8a\x36\xda\xf4\xc7\x40\x60\xc6\x96"}, -{{0x57,0xb5,0x19,0x4d,0x26,0xab,0xe4,0xab,0x21,0x16,0xc0,0xf0,0x3d,0x23,0xdb,0xe1,0x16,0xd4,0x88,0x25,0xa2,0x5e,0x77,0xd6,0x46,0x48,0xb4,0x36,0x92,0xae,0x25,0xbf,},{0x49,0x9c,0x02,0xdb,0xad,0x2a,0x4e,0xab,0x3b,0x6f,0xf1,0xab,0xa3,0x94,0x4b,0x91,0xc3,0xf2,0x73,0xa3,0x82,0xc5,0x48,0xa6,0xf3,0xa1,0x9c,0x83,0xf0,0xa8,0x67,0x24,},{0x4c,0x73,0x45,0x96,0x0c,0x8f,0xd4,0x8a,0x7d,0xea,0xd7,0x1d,0xbd,0x61,0x90,0x84,0x68,0xef,0xa8,0x65,0xa1,0x35,0x56,0x8c,0x8f,0x9c,0xa0,0x05,0x54,0x83,0x46,0x86,0x17,0xa7,0xe3,0x35,0x84,0x0f,0x57,0xc6,0xcd,0x8f,0x2c,0x98,0x05,0xcd,0x47,0xa9,0xd7,0xcd,0xfd,0xe5,0x3d,0xa8,0xef,0x4f,0x1a,0xdb,0xb6,0xf6,0x98,0xaa,0xf1,0x00,},"\xb4\x81\x3c\x9d\x13\x21\x5f\xe9\xf6\x3a\x78\xff\x7a\xc9\x51\x73\xeb\x81\x0b\x46\x13\xf0\xf4\x8d\x68\x76\xb2\xbd\x3b\x2c\x72\xbc\x7d\x98\xcb\x1a\xc3\x2b\xc4\x1c\xa4\x7f\x09\x89\x6f\x79\x20\x4e\xcf\xb8\x26\x4c\xe8\xf3\xc3\xe7\x6d\xc1\x24\xda\x8d\xdc\x6e\x0d\xfc\x1e\x13\xb5\xa5\x29\xf2\x0c\x82\x61\x3f\xb9\xa8\x2e\x5f\x5d\x77\x32\x6a\x86\x1f\xae\xda\xbc\x73\x25\xc5\x9a\xf3\x3d\xae\x67\x44\x02\x5e\x64\x97\x74\xfc\x4f\x79\x13\x4b\xf9\xf6\xe3\xd5\x87\x5d\xd9\x1b\xc8\xa1\x4c\xc3\x6a\x66\x28\x3d\x01\xd8\xd1\x08\xc1\x33\x27\xec\xa5\x30\x57\xba\x50\xbf\x21\x0c\x19\xf1\x39\xde\x64\x94\x98\x26\x46\x19\x8a\x12\x46\xc2\x71\xb0\xa3\x68\xc1\x0a\xab\x95\xcd\x89\x61\x23\x5d\x74\x2d\xf4\x54\x5b\xe6\x8b\xd0\x10\xdc\x0d\xb2\x3b\x67\x3e\x62\x36\x09\xe4\x20\xee\x76\xb1\x05\x6c\x52\x0f\x9c\xe8\xfb\xe8\xee\x18\x63\xdf\x97\xd1\x7b\x71\x74\x63\x6c\x3a\x2b\x61\x22\x95\x09\x19\x48\x81\x0d\x1d\x4b\x8a\x58\x43\x76\x0a\x28\x87\xdc\x55\xef\x51\x2a\xf0\x41\xec\x54\xfa\xd3"}, -{{0x06,0x8d,0x27,0xb2,0x1e,0x2a,0xcf,0xcc,0x19,0xc3,0xe9,0x67,0x3d,0xd4,0x41,0x42,0xd9,0x8a,0xac,0xae,0x89,0x49,0x30,0xe2,0x0c,0xa0,0x67,0x43,0x9e,0x74,0x9a,0x79,},{0xe2,0x2d,0xdd,0x39,0x6f,0x95,0x5b,0xb9,0x0e,0x28,0x47,0x76,0xaa,0x76,0xe9,0x21,0xe5,0x06,0x99,0xd0,0xca,0x89,0x14,0xa9,0xb7,0xb8,0x41,0xeb,0x5f,0xf4,0x7d,0x6d,},{0x0c,0x17,0x3c,0x48,0x8a,0xd0,0x01,0xcb,0xb9,0xc4,0x3d,0x7b,0x30,0xa7,0xc0,0x71,0xa2,0xfd,0xb0,0x8c,0xf7,0xf3,0x7d,0xaf,0x71,0xd7,0xae,0x71,0x28,0xdc,0x0d,0x43,0xf0,0xf0,0x95,0xb2,0x92,0x9c,0x54,0xb7,0x73,0xed,0x4a,0x1f,0x0b,0xf0,0xdc,0x4f,0x36,0x4f,0x06,0x01,0xe8,0xd5,0xae,0x06,0x2f,0x5b,0x78,0xc0,0x5b,0xfb,0xc7,0x02,},"\x1c\x68\x15\x42\x3d\x1a\x2c\x5e\xbe\x88\x28\xd1\x64\x65\x27\xc1\x7b\x20\x06\xe5\x47\xf0\x16\xb5\x35\x0f\x01\x0d\x79\xb1\x3d\xf4\xfb\x8c\x6e\xd5\x7b\xa9\xc2\x6c\x3c\xb0\xe0\xa6\x41\x78\xb6\x50\xa3\xea\x54\x44\xa4\xfa\xd5\xb2\x0a\x3e\xb8\xca\xa7\x02\x63\x40\x11\xcf\x78\x92\xa0\x72\x7b\x6e\x81\x50\xb0\x77\x04\x29\xa3\x7a\x8a\x0b\xb3\xa7\xed\xb8\x91\xa7\xc9\x02\x40\xbc\x03\x60\xb1\x4e\x6d\xd7\x70\xa9\x90\xb3\x1b\x31\xf3\x3d\xdb\xf6\x53\x98\x8f\x82\x74\x2e\x5e\xec\x31\xb2\x73\x68\xeb\x0e\x4f\x1e\xcf\x4d\x67\x6f\x49\x21\x4a\x52\x0d\x1e\x5b\x2b\xbb\x59\xac\x2e\x13\x26\x7e\x07\xa0\xcb\xac\xbe\xd9\xf9\x4d\x74\x73\xed\x69\x78\x28\xb0\x92\x8f\xcc\x61\x6e\xe0\x2e\x51\xfc\xd8\xdb\x4d\x8f\x75\x33\xb7\xb1\x39\xa0\x5e\x06\xf9\xe0\xea\xe3\x29\x93\xe3\x02\x5a\xef\x05\x90\xb3\xfb\xb4\x29\x2a\x3a\xc4\x07\x65\xe8\x58\x4e\xad\x00\x26\x6a\xcd\xcb\xdd\xe1\x45\x7a\x03\xb7\xd5\x7b\xd5\xc9\xe6\x4f\xb0\x6b\x64\xa5\x0f\x35\xf0\xa1\xec\x34\xb6\xdd\xbd\xe7\x67\xb9\x6f\xfd"}, -{{0xa3,0x4d,0x52,0x56,0x31,0x59,0xe0,0x72,0x3e,0x9f,0x3f,0xd1,0x33,0xbd,0x96,0xe2,0x0a,0xda,0xe6,0x23,0xf8,0xc7,0x98,0x01,0x3b,0xc3,0x6b,0x44,0x14,0x89,0xbd,0xc2,},{0x1f,0xb6,0x58,0xe6,0x45,0xde,0x6d,0x3e,0xfd,0xb0,0x83,0xa7,0x3f,0xbd,0x59,0x2f,0xcd,0x4b,0x80,0x0e,0x03,0xc7,0xbd,0x68,0x1a,0xea,0xe6,0x57,0x6b,0xfb,0xbe,0x2f,},{0x5f,0xab,0x5a,0x71,0x40,0xd4,0x78,0x73,0x68,0x43,0x05,0xaa,0x63,0x53,0xd3,0x86,0x2f,0x5f,0xc1,0x3e,0x54,0xa4,0x0c,0x95,0x63,0xcc,0xea,0xc8,0xf7,0x40,0x08,0xc6,0xc4,0x45,0x63,0x1f,0xa8,0x64,0xe0,0xf1,0xc3,0x45,0xb5,0x95,0x4f,0x80,0x05,0x6a,0xeb,0xa2,0x56,0x62,0xb7,0x88,0x27,0xb5,0xe8,0xe3,0xa9,0x43,0x78,0x13,0x72,0x0f,},"\x1d\x21\x5f\x85\xc0\x89\xf3\x5f\x30\x7a\x74\x6c\x66\xc7\xc1\xe4\x1d\x6b\xa3\x77\x30\xd7\x59\xe6\xe5\x62\x2d\x6c\x6a\x19\x8e\x40\xf6\x3d\x37\x87\x3b\x71\x5d\xf7\x51\x8b\x3c\x6b\xb5\xe9\x5a\x46\x77\x26\xb9\x7c\x9a\x0f\x8f\x5d\xfc\xdb\xfd\x1e\x0d\xe3\x57\x66\x1d\xde\xab\x55\x50\x42\xb9\x45\xfd\x89\x9f\xad\x6d\x38\x2d\x79\x17\xda\x9e\x12\xdf\xbd\xa0\xd6\x99\x00\xb3\x97\x51\x65\xa7\x3d\x0a\xc9\xde\x01\xfd\x30\x48\xb8\xfe\x5f\x0b\x90\xbe\x67\xe0\x3d\xc2\x2f\x65\x3a\x0a\x13\xeb\x4b\x0b\x75\x3f\x3f\x3b\xbf\x78\x73\x69\xeb\xd8\xbf\x5e\x00\xeb\x78\xbf\x0b\x35\x15\xa9\x1e\x68\xb1\xd5\xfc\x69\x20\xbf\x4f\x42\x59\xf8\xa7\x30\xef\xc7\xf1\x01\x6d\x50\x1e\xf6\xfb\x7c\xb8\x36\x6f\xc8\xe7\x16\xcf\xa5\x0e\xa8\xb2\x03\xcc\xa1\xa3\x16\x70\x7e\x0b\x0f\xc5\x7e\xaf\xce\x82\xd6\x2f\x7f\xf3\xae\x04\xac\x8f\xd0\x41\xb5\x5b\x19\xa3\x52\xa6\x9e\x6d\x4b\x79\xd0\xe6\x50\x17\x51\x68\xe3\x4f\xa3\x35\x8e\xac\x81\x6c\xec\xf2\xc8\xdd\x1b\xf2\xa5\x89\x11\x3e\x91\xbb\x81\x8f\x91\xf8"}, -{{0x58,0xdf,0xe7,0x68,0xbf,0x52,0x11,0x84,0x94,0xb2,0x99,0x75,0x15,0x4c,0xf4,0x52,0xbd,0x97,0x46,0xdc,0x7d,0xe1,0xd6,0xbc,0xd1,0x8e,0xe6,0xa0,0x5a,0xcf,0xd8,0x58,},{0x0f,0x14,0x76,0xc6,0xcc,0x2a,0x1b,0x47,0x64,0xaf,0x75,0x80,0x5e,0x77,0x34,0x1f,0x14,0xa0,0xd8,0xb0,0x9c,0x6a,0x5b,0x2e,0xa2,0x87,0xfd,0x51,0x7c,0x3f,0xa6,0xb9,},{0x97,0x71,0x37,0xa3,0x8a,0xf4,0x4f,0x4b,0x26,0x2a,0xbf,0xf7,0xe0,0x72,0x82,0x43,0x3c,0x58,0x92,0x6d,0x56,0x2f,0xbc,0x61,0x80,0xbd,0xe6,0xcd,0x94,0x97,0x86,0x1f,0xb6,0xd9,0x55,0xcf,0x38,0x3d,0x99,0x9f,0xa1,0x03,0x7b,0x8b,0x17,0x54,0xce,0x88,0x8c,0x9f,0xfc,0x15,0x60,0xa4,0x51,0xd0,0xe9,0xdb,0x8d,0x74,0xd2,0x94,0x06,0x04,},"\x60\x97\x94\x20\x1c\x4f\x6f\xaf\x48\x87\x90\xd6\x1d\xbf\xf3\xf4\x1b\x32\x8c\x5b\x06\x95\xcb\xe9\xaa\x8a\x13\x6d\x72\xb4\x97\x7b\x21\xb5\x00\xf2\x16\xe9\xf3\x21\x68\xad\xa8\xc1\x3b\xff\x25\x32\x76\x47\xe3\x0d\x8a\x24\x4d\x74\xd8\x83\x03\xab\xc9\x0b\x7f\x71\xaa\x07\xca\x04\xd1\x7b\xc8\xa0\x16\x7d\x6e\x63\xfb\x88\xba\xa1\xda\xb8\x1d\x50\xf1\xe9\x1f\x46\xf5\xaf\x77\xf2\xe8\x40\x8b\x82\x63\x36\xa3\x50\x52\xef\xff\xdf\x4a\xf7\x95\x96\xaf\x1b\xb2\x25\x9f\x83\xc1\xbc\x10\x9c\xfd\xc3\xdd\x50\xfd\x96\xd3\x10\xf2\x7e\xa4\xc6\xc7\x69\x0f\x21\x81\x5e\xa9\x2b\xd7\x93\x89\x68\x0c\xfe\x3e\xd4\x0c\x80\x18\x11\x90\x68\x8d\x24\x22\x2d\x9a\x1e\xd5\x2c\xe6\xa1\x6b\x41\xdb\xd9\x10\x7e\xb6\xd2\xe3\x59\x4e\x44\x94\xd7\x5d\xd7\xc0\x89\xe3\xb2\x6f\xfd\x00\xd1\x00\x3c\x92\xc4\xc3\x9a\xe5\x38\x2e\xf9\x29\x14\x91\xa8\x80\xca\x4e\xc3\xac\x2b\x86\xe6\x67\x19\xb9\x2b\x6f\x7c\xea\x2c\xb0\xbb\xb1\xcf\x62\x4d\x0d\x1a\xbe\xae\x55\x6e\x5f\x73\x90\x9d\xd5\x46\x27\x70\x37\xec\x97\x2f\xd4"}, -{{0x5a,0x63,0xef,0x9b,0xd7,0xdb,0xf0,0xe8,0x9f,0xef,0x15,0x59,0x83,0x65,0x9e,0x8a,0x0a,0x6c,0xa0,0x02,0xbc,0x42,0xfa,0xd5,0xa4,0x5a,0xf8,0xe0,0x28,0x19,0x23,0xf4,},{0xe6,0x32,0xf4,0xdc,0x99,0x42,0x31,0xcc,0x17,0x90,0xc2,0x1a,0xfa,0xda,0xa9,0x77,0xa5,0x89,0xb0,0xeb,0x0d,0xa1,0x9f,0xcb,0x27,0x92,0x91,0x1b,0x15,0xec,0xf8,0xaf,},{0x75,0x46,0x1f,0x99,0x65,0x0c,0x03,0x68,0x05,0x81,0x13,0xa1,0x5b,0xa1,0x6b,0xd2,0x33,0x7b,0x2e,0x63,0x3d,0xa3,0x81,0x12,0x87,0x8c,0x48,0x34,0xfa,0xc9,0xba,0x2e,0x30,0x7c,0x86,0x6c,0x02,0xaf,0x79,0xbe,0xa3,0x36,0x59,0x61,0x4c,0xbb,0x44,0x65,0xc5,0x7e,0xc3,0xef,0xfd,0x4c,0x47,0x8a,0xe3,0x8a,0x34,0xa0,0x5c,0xf1,0xed,0x07,},"\x79\x6b\xc8\x36\x1c\x6e\x8e\xec\x39\x83\x8b\x24\xf5\x39\x71\xe8\x20\xf8\x23\x61\xe0\x51\x0e\xb4\xde\xf1\xdb\x25\x12\x38\x7d\x6b\xf3\x5b\xbd\xfa\x31\x88\x79\x20\x94\x35\xd6\x88\x7b\x14\x10\xb3\xeb\xc1\x45\x5f\x91\xf9\x85\xe0\xfa\xb1\xce\x1c\x50\x5c\x45\x55\x76\xbc\xa0\x35\x39\xd0\x48\xad\x3a\x0e\xd1\xf1\x1c\x73\xba\xc6\x80\x9e\x2e\xa1\x47\x97\x5b\xee\x27\xc6\x52\x61\xac\xa1\x17\xdf\x0f\xae\x70\x08\xe2\xc3\xc1\x30\xbe\xc5\x53\x3a\xb8\x93\x51\xc2\x14\x0c\x9d\x1a\x62\xbd\xf6\x88\x62\x97\x87\xf9\x54\xe1\xc6\x10\xcb\xb7\x5e\xdb\x86\x20\x9d\x7c\x35\x7c\xd0\x6e\xf4\x19\x31\xdd\x5d\xfd\x1c\x7d\x40\x7f\xa4\xee\x1e\xf2\x93\x93\xbe\xab\x57\x13\x17\x38\x02\xcc\xe2\xd5\x62\x29\xcf\xa7\x6b\x60\x16\x62\xc4\xd9\xa8\x4a\x49\x36\xc5\x2a\xbb\x19\x81\x37\x8b\x71\x7e\xb5\x5c\xb6\x04\xa6\x8d\x34\xf0\x3b\x21\x9f\x32\x22\x6c\xa0\xe6\x69\x34\x8a\x2d\x8d\x24\x53\x93\x0e\xb6\xe9\xc2\xbf\x66\xfa\x4e\x92\xc7\x51\x36\xe1\x48\xcd\xb0\x34\x13\x0d\x3f\x64\x63\x82\xe1\xc7\x15\x79\xac\x70"}, -{{0x8b,0x2f,0x06,0x14,0x1e,0x40,0x11,0x63,0xf9,0x0f,0x67,0x4b,0x04,0xdc,0x90,0xdc,0xb6,0xdd,0x33,0x86,0x41,0x93,0x39,0x66,0x2e,0xcb,0x0d,0xff,0xad,0xf2,0x50,0x0b,},{0x54,0xda,0x93,0x4a,0x65,0x91,0x19,0x19,0x85,0x53,0xfd,0x45,0x66,0xb6,0x60,0xd8,0xd6,0x10,0xad,0xc3,0x29,0x0c,0xb8,0x48,0x29,0xc8,0x94,0x14,0x8c,0xf3,0xf6,0x7e,},{0xd6,0x8e,0x37,0x50,0xdc,0x56,0x43,0x23,0x97,0x40,0x1c,0x98,0xff,0x15,0x29,0xdb,0x9e,0xd4,0x8f,0xea,0x24,0x6d,0xd4,0xed,0x38,0x3e,0xc7,0x4c,0x1a,0x46,0x3a,0xeb,0x78,0x4c,0x87,0xb1,0xfd,0xa8,0xbb,0xce,0x97,0x0f,0xc9,0x7a,0xa9,0x80,0x7d,0xdb,0xe9,0x5d,0x41,0xfb,0x02,0x2e,0xa6,0x8c,0x1e,0x31,0x16,0x54,0xfa,0x1d,0xa2,0x07,},"\x1d\xeb\x25\xd4\x34\x58\x69\x03\x23\xa7\xd2\x6a\x26\x69\x50\x90\x99\x34\x74\xf4\x67\xc6\xfd\xe5\xdd\xb3\x4d\xa9\x45\xbe\x3c\xea\x2f\x6b\x75\x65\x2a\xe2\x1c\xbc\x4f\xd2\x27\x63\xa1\xb4\x55\x83\xe1\xc3\xe8\x8b\xbb\x5f\xea\x20\x49\xb7\x33\x6c\x91\x15\x99\x88\xc0\x15\x26\x82\x4c\xa3\xbe\xf1\x6b\x36\x2b\x92\x02\xb8\xb9\x75\x41\x85\xbd\x61\xbe\xa8\xf5\x39\xaa\xdf\x4a\x1a\xb1\x35\xfb\xc3\x1d\x2a\x8e\x33\x17\x80\x73\x10\x6c\xbb\xc0\x2d\x4c\xd0\xd3\xc8\xfe\xaa\x8e\xb7\x33\x08\x43\x56\x25\x17\x95\xaf\xbd\x78\xac\x3c\x4f\x8a\x3b\xa1\x9a\xed\x75\x5c\x64\x6f\x35\x56\x9c\x7a\x6c\x67\x5b\x6d\x69\x18\xe8\x34\x96\x9a\xca\x03\xf7\x1a\x2e\x72\xcc\xb1\x70\x03\xbb\x75\xb6\x2e\x85\x2a\xaf\x58\xb3\xba\xea\x89\xbc\xd6\x4a\x32\xeb\x14\xa6\xb9\xe1\x0d\xe4\x89\x71\xe5\x3d\x0e\x9a\xc9\x9a\x78\xf4\x2d\xe0\x38\x2e\xf0\xe8\x0e\xd3\xcf\xa3\x43\xf3\x5e\x4a\x99\x83\xb9\xae\xed\x98\x6d\x3a\x57\xf4\x7e\x5e\x46\xd4\x0e\x9d\x67\x73\x02\x80\x9a\x2d\x37\xe4\xec\x01\x1f\x05\x1b\x4d\x03\x1e\xd6\x00"}, -{{0xdc,0x64,0x9f,0xbb,0x1b,0xee,0x0a,0x44,0x81,0x4d,0x6d,0x9e,0x90,0x80,0xd5,0xd9,0x0c,0x1f,0xc1,0x73,0xab,0x5f,0xef,0xed,0x82,0x6a,0x74,0x72,0x3a,0x77,0x4e,0x0a,},{0x02,0x14,0xc8,0x9f,0x38,0x67,0xad,0x2e,0x88,0x70,0xe5,0x0f,0x8c,0x2a,0x62,0x54,0x98,0x6d,0x9c,0x22,0x0e,0x33,0x38,0x41,0x13,0x00,0xcd,0x9c,0x64,0x04,0xd4,0xb1,},{0x0e,0x0c,0x5e,0x4e,0x18,0x43,0x75,0xda,0x4e,0xf7,0xe2,0xa2,0xe4,0x88,0x80,0x50,0xcd,0x84,0xe2,0xfe,0x21,0xd0,0x8e,0x84,0xa8,0x52,0xdb,0x2b,0xe3,0xfb,0xc3,0x72,0xc4,0x72,0xde,0x09,0x54,0xdc,0xd1,0xdc,0x11,0xae,0xc4,0x93,0xc5,0x69,0xf4,0x0f,0xc6,0xf7,0x7f,0x03,0xee,0x52,0x4f,0xb0,0x6e,0xc4,0x0f,0xaa,0x1d,0x6c,0xc1,0x0f,},"\x32\x87\x00\xa8\xae\x58\x1c\x1e\xdc\x4e\x2c\x00\xc7\x8b\xf4\x60\x60\x97\xf9\xbd\x75\xaa\xde\x20\x5a\x24\x3c\x5f\xd7\x43\x4d\x62\x22\xda\x93\x7e\x28\x81\xa2\xe3\xc5\x74\x35\x6d\x4d\x56\x79\x30\x1d\xa9\x9e\x11\xcf\x74\x9c\x27\x92\x1c\x8c\xaa\x2a\xb2\xa5\x64\xd8\x7c\x5d\xf8\xec\xf1\xa7\x2b\x68\x01\x84\x82\x4f\x69\x86\x02\x2e\x3f\xc9\x8b\xd2\xa2\x1c\x34\x55\xab\xf1\x15\x49\x54\xfb\x30\xc8\x98\x82\x94\x7b\x02\xf3\x5a\xf7\xb1\xbf\xad\x05\x23\x7d\x24\x2e\x2b\x74\x83\x2f\xc5\x36\x19\x6f\x2e\x59\xd1\xac\xd0\xc1\xdb\x6f\x19\x43\xd0\xf6\x04\x3b\xbd\x6a\x76\x90\x83\xed\x66\xba\x0e\x05\xa5\x0f\xeb\x0a\xcf\x72\xb6\xc1\x6b\xa9\xaf\x03\x9a\xfb\x7f\xe2\xa4\xaa\xeb\x4d\x06\x18\x1c\x5a\x18\x78\x68\x9e\x67\xa3\xf5\xd0\xad\x39\xe7\x94\xd6\x23\x9a\x7e\x0a\x12\xce\x82\x0c\x5b\xe6\x0f\xd5\xf1\xdd\x79\x70\x2f\x49\xd0\x2b\x79\x75\x5f\xe8\x73\xf5\x78\x5c\x72\xf7\x46\x25\xcd\x7e\x24\x28\x26\x25\x97\xd3\x14\x82\xc2\xc0\x50\x88\x01\xfd\x96\x31\x9d\x61\xb9\x1b\xa2\x53\xa5\xe7\x22\xf4\x14\xcf"}, -{{0x39,0xb8,0x06,0x2d,0xa4,0x3e,0x64,0xe1,0x67,0x67,0x65,0xd6,0x2c,0x7f,0xb8,0xe0,0xa9,0x9c,0x4f,0xd4,0x17,0xd6,0xf7,0xe3,0x31,0x9b,0xb1,0x30,0x44,0x20,0x5f,0x3b,},{0x62,0x27,0xce,0xfe,0x88,0xea,0x4f,0xb2,0x7b,0x37,0xb5,0xf7,0x97,0x77,0x8b,0xd7,0x2f,0xda,0xfe,0xad,0xcc,0xd9,0xae,0xb6,0x7a,0xd4,0x37,0xce,0x08,0xfb,0xa6,0xa8,},{0xc5,0xf6,0x26,0x49,0x0c,0x0e,0xf4,0xe1,0xef,0xc3,0xed,0xeb,0x0c,0xbc,0x3f,0x7d,0xe2,0x67,0x05,0x7f,0xb7,0xb6,0xeb,0x8f,0x0c,0x81,0x35,0x84,0x96,0x5b,0xc5,0xc4,0x21,0xfe,0xed,0xf5,0x42,0x41,0xca,0xe0,0x01,0xec,0x6d,0x5e,0x25,0xc9,0xb1,0xfb,0xa0,0x38,0x5e,0x5d,0xbd,0x95,0xa0,0x6e,0xc1,0xd8,0xae,0x51,0x91,0x44,0x96,0x0d,},"\x74\x0a\xf6\x79\xe3\x06\x9f\xad\x05\x9f\xa4\x82\x5f\xa4\x1c\x59\xfb\xd4\x84\xaa\x64\x93\x03\xc2\x7c\x4f\x7a\x94\x71\x1c\x5b\x71\x3b\x2a\x6b\x89\x87\x85\x9e\x22\x71\xa6\xa7\x1e\xb0\xb4\xa1\x5a\xbd\xe4\xf5\x16\x8f\x6c\xb9\xdb\xdc\x6a\x27\xa2\xa1\x3d\x52\xc9\x72\x08\x96\xa1\xf4\xce\x3a\x53\x45\xee\x79\x3b\x6c\xc3\xad\x80\xd7\xd5\x81\x63\xd5\x45\x5b\x9c\xbd\x07\x3e\x2b\x7a\xdb\xff\x95\x59\x0c\x71\x72\x27\x1b\xd9\x1f\xef\xdb\xd0\x16\x57\xee\x17\x50\x65\x10\x36\xcd\xc3\x56\x0b\x44\x4c\xa2\x18\x4b\xf4\xf3\xea\x89\xfc\x97\x3a\xab\x6f\xb4\xa8\xee\x57\x04\xbb\xe5\xa7\x1c\x99\xfa\x3b\x5e\xf0\xd0\x39\x62\x49\x75\x82\x97\x69\x9a\xe2\x02\xb8\x19\x69\x0d\xc7\xac\x46\x92\x77\x03\x46\x90\x78\x45\xe2\x21\x0d\x53\x63\xad\xee\xc0\x3f\x0f\xc7\x76\x1b\x7e\x0e\xc0\xfe\xa1\xbc\xf6\xb0\x4f\xc5\x4b\x3e\x4c\x40\xd1\x9b\x8f\xa6\x49\xac\x84\x79\xe8\xf8\x07\x30\xc0\xc9\x4e\x9f\x4a\x1a\xd5\x06\xf2\xbc\xab\x0c\x49\x54\x0f\x6d\xec\xaa\x77\xb3\xd6\x57\xdc\x38\xa0\x2b\x28\xa9\x77\xec\xe4\x82\x54\x5a"}, -{{0x52,0xf4,0x67,0x5d,0x8c,0xcd,0x0e,0xb9,0x09,0xdf,0x0a,0x51,0x66,0x48,0xdb,0x26,0xfa,0x03,0x3b,0xa4,0x1d,0x43,0xfc,0x38,0x45,0x89,0x6d,0x45,0x6e,0x14,0x26,0x5f,},{0xf3,0x9e,0x7d,0xaf,0xc9,0x7b,0x0a,0x84,0xdc,0xbf,0x7f,0xa1,0x4a,0x94,0x03,0xee,0x1f,0xa9,0x2b,0x85,0xe5,0xa7,0xe5,0xd0,0x5f,0x03,0x1b,0x44,0xdd,0xf1,0xf7,0x94,},{0x4b,0xf6,0x68,0x82,0x7a,0x72,0x0a,0xf6,0x88,0x98,0xa0,0x6e,0xa7,0xb4,0x45,0x45,0xa3,0x4c,0xa8,0x96,0xec,0xf3,0x11,0xfe,0xea,0x47,0xe0,0x68,0x6d,0x91,0x1f,0xad,0xaa,0x03,0x11,0x89,0x97,0x15,0x3c,0x65,0x36,0x1f,0xea,0x15,0xde,0x9b,0xb8,0x91,0xb8,0x90,0x98,0x72,0x04,0x55,0x08,0xff,0xad,0x0c,0xd9,0xea,0xb2,0x1a,0x97,0x02,},"\x74\x42\x71\x10\x85\x7c\xb4\xaf\x0a\x33\x42\xc2\xb5\x29\x97\xbc\xe1\xa0\xdb\x64\x05\xc7\x4e\x96\x51\xc5\xb8\x59\x79\xac\xb0\x71\xe5\x67\xfe\x70\x41\x2c\x4e\x0d\x8c\x9f\xa4\x21\x91\x4f\x6a\x62\xf2\xae\x42\x0b\x7b\x2f\x4c\xf8\x0c\x90\x57\x42\x21\x22\x22\x88\xb6\x58\x67\xea\xa6\x6e\x7e\x0a\x05\x57\xa2\x6c\x54\x9f\x9a\x7a\x4e\x70\x83\x8b\xa4\x07\x4b\x4c\xd7\xa9\xd7\x58\xb3\x78\xb8\x8d\xd4\x94\x41\xdf\x80\x2a\x44\x4d\xcb\xc3\x06\x24\x93\x3b\x59\x92\x2f\x33\xc2\x0f\x01\x9f\xe7\x8e\xe2\x4b\x8f\xba\x79\xa6\x82\xf3\x88\x50\x5a\xc9\xc9\x7f\x4e\xb8\x7c\x61\x18\x80\x02\x6b\x4c\x23\x30\x6b\x86\x51\x73\xf5\xd7\x16\xab\xc6\xcd\x9a\x99\x06\xdb\x34\x30\x13\x6f\x75\x41\x29\xc4\x43\xb2\x0c\x42\xbe\x2f\xbc\xbc\xd4\x40\x34\xd7\x14\xf5\x8a\x4b\xa8\xe7\x56\x60\x7a\x02\xb6\x08\xef\x49\x64\x8f\x2a\xd0\xce\xa9\x9e\x7a\xb3\x0a\x8d\xd7\x81\x40\x04\xf7\x25\xf4\x93\x01\xd7\xb3\x04\xdc\xda\x62\x5c\x29\x6d\x92\x8c\xb5\x81\x73\x6a\xb7\x39\xc8\x6b\x46\x92\x41\xa8\x25\x93\x51\xfd\x37\xb4\x78\x0a\x99\x93"}, -{{0xba,0xd7,0x3c,0x9f,0xda,0x4c,0xeb,0x9d,0xa6,0xc7,0x01,0xc2,0xa6,0xe2,0xef,0xc0,0x46,0x7a,0xfa,0x0a,0x74,0xf8,0x75,0x0c,0x52,0xcf,0x1f,0xd4,0xc8,0xe7,0x48,0x9a,},{0xbb,0x0f,0x02,0x7a,0x90,0x35,0x37,0x6e,0x1a,0xa3,0x20,0x6c,0x3d,0x77,0x44,0x75,0xe3,0x51,0xf5,0x76,0x7e,0xf8,0x6e,0xf4,0x8a,0x72,0xc0,0x37,0xc2,0x4c,0xce,0x62,},{0x19,0x7d,0x6b,0x6c,0xc8,0x8a,0x98,0xc0,0x6d,0xfc,0xa0,0xc0,0x12,0x25,0xed,0xfe,0x38,0xa0,0xb2,0x28,0x9f,0x29,0xf8,0xa4,0x4e,0xc0,0x81,0x6a,0x95,0x2d,0x58,0x5e,0x2d,0x59,0xb5,0xb0,0x8d,0xe1,0x00,0xc0,0x60,0x62,0x96,0xcc,0xf5,0xe9,0x2a,0x99,0xe0,0x93,0x62,0x31,0x44,0xb8,0xb2,0x2d,0xb8,0x7d,0x92,0x92,0x25,0x54,0x60,0x05,},"\x74\xb9\x66\xcb\x78\x07\x71\xae\xe6\x3d\x73\x4d\xf3\x75\x67\x02\xd1\xd5\xfd\xed\xdf\x32\x13\x6c\x63\x58\xb8\x36\x31\x8a\x4f\x98\x4f\xe7\x1e\x77\x16\xad\xdd\xbd\x64\x9e\xba\x44\xcd\x42\x82\xe0\x05\x5d\x8c\x1e\xd2\xd3\x51\x23\xd6\x6e\x5a\x98\xf1\xc0\x83\x8d\xed\x56\x3b\x9a\x20\xeb\x80\x07\x53\x8f\xc7\xb0\x71\x3e\x7e\x48\x5e\x3c\x28\xf6\xeb\xc4\x21\xa2\x9d\xce\x25\x24\xdb\x7f\x29\x20\x57\x61\x03\x6a\xda\x62\xe5\xb0\xb7\xd5\xb7\xf2\x94\xff\x17\xf3\x38\x23\x2f\xa5\xfd\x42\xb6\xf7\x25\x33\x04\x09\x2d\x84\x8f\x50\x73\x52\x48\x59\x5d\xa0\xf7\xef\x28\xe5\x68\xe9\x91\x6b\xfc\x56\xd7\xed\x0d\x81\x1b\x59\xd5\xd8\x91\xae\x43\xe1\xb1\x98\x07\x13\x06\xbf\x52\x5c\x67\x8c\x63\x43\x99\x80\x05\xfb\xb7\x86\x9d\x1c\x40\xf8\xca\xc8\x07\xfe\x2e\xf0\x3f\x3d\x5b\x93\x3f\x58\x97\x8e\xf2\x90\x6f\xcc\xf7\x44\x4a\x29\x36\xe6\x3d\x92\x8c\x69\x09\x26\xc9\xc9\x94\xed\x3d\x66\x62\x63\xe9\x56\xfd\xfe\xa2\x77\x64\xbc\x5f\x74\x12\x5b\xc4\x6b\xc1\x02\xdd\x3e\x5f\xf9\x3b\x5e\x12\x3e\x4b\x38\xbd\xef\x69\x7e\x15"}, -{{0x70,0x73,0x27,0xa4,0x31,0xdb,0xa7,0x76,0x39,0xb3,0x96,0x6b,0x2b,0xc0,0x95,0xf8,0xee,0xdf,0x57,0xf7,0xa2,0x00,0xe3,0xb0,0x07,0x7c,0xe4,0x20,0x38,0x9c,0x92,0xfe,},{0xee,0x24,0x96,0x91,0x08,0x64,0x18,0x9f,0xda,0xa3,0xc7,0x75,0x7e,0xb3,0xcd,0xa9,0xab,0x1e,0x70,0xfc,0x9e,0x7f,0x71,0xa3,0x8a,0x0b,0xfc,0x84,0x59,0x31,0xc9,0x5a,},{0xfb,0x99,0x02,0x9f,0xec,0xa3,0x87,0xa5,0xd7,0x65,0x96,0x1e,0x36,0x1d,0x71,0x72,0xb9,0x8b,0x7e,0x0f,0x11,0x29,0x0b,0xb1,0xe5,0xb5,0x7b,0x51,0xbc,0x21,0x23,0xd0,0xbc,0xe2,0x90,0x20,0x39,0x2a,0x4f,0xec,0x9a,0xe6,0xa7,0x2c,0x4c,0x38,0x6c,0xea,0x18,0x57,0xcb,0x8f,0x9c,0x50,0xaa,0x9a,0x76,0xd7,0xf1,0x68,0x7f,0xcf,0x29,0x00,},"\x32\xef\x31\xb6\x4e\xee\x70\x0f\xca\x2a\xb2\x1a\x26\x7f\x8d\x9d\x3b\xdc\x68\x9c\x75\x38\xfe\x95\x9b\xf7\x13\xfa\x99\x5d\xb2\xc0\xad\x36\xdd\xe4\x30\xa8\x41\x7d\x43\x7b\x72\xc7\x4e\x26\xdb\xe3\x1d\x93\x70\x1d\x46\x17\xfe\x51\x82\x5c\xff\x7a\x54\x4f\xc9\xf4\x4e\x43\x45\xe1\x4b\x4b\x11\xe1\x5f\x26\xff\xc2\xaf\x80\x35\xf3\xf9\x70\xe4\xdd\xa4\x4c\x0e\xbc\x03\x63\xc2\xb5\x6f\xde\x21\x86\x63\xbf\x78\x83\x90\x92\x53\x8f\xc2\xf3\x91\x53\xd4\xeb\x29\xda\x0c\x1a\x08\xaa\x96\x66\x01\xcc\x68\xca\x96\xe9\x93\xb0\x1b\x17\x3a\x26\x1b\x2e\xf3\x27\x65\x03\x82\xf5\x68\xfe\x94\x48\x55\xb0\xf4\xfd\x9d\x15\xe7\x52\xac\x74\xdc\xfd\x37\xb3\x78\x6f\xff\xce\xf2\x33\x39\xc2\x1e\x92\x70\xdc\xe8\x89\x1d\xd5\xee\xeb\xa9\x60\x8f\xdc\x7b\x6f\xbc\xc9\x9f\xa1\xb5\x90\x3d\xaa\x09\x68\xe1\xb6\x91\xd1\x9d\x06\xf2\x15\xde\xd0\x47\xef\x9d\x76\x61\x0f\x5d\xe2\x20\xf5\x04\x1b\x31\x3f\xaf\x9e\x96\xc9\xfd\x7d\xb5\x4b\x52\x25\x72\x6a\xf4\x35\xf9\xcb\xd9\xfd\x87\xab\x40\xce\x8f\x2c\x69\x40\xb5\x5f\x0f\xaa\xe8\x78\x50\xca"}, -{{0x6a,0xa5,0xc9,0xf0,0x08,0xf9,0x90,0x47,0x3b,0xa4,0xa6,0x28,0x6a,0x41,0x66,0x14,0x02,0x66,0x61,0xf1,0x1e,0x1a,0x24,0xef,0xa8,0x1a,0xc3,0x58,0x52,0xd1,0xd0,0x70,},{0x60,0x5a,0xc9,0xb4,0xdb,0xdd,0x50,0x33,0xd6,0xc8,0x28,0xbf,0xaf,0xa9,0x3c,0x00,0x39,0x44,0x0a,0xa1,0x1c,0xa7,0x24,0xae,0x83,0x40,0x43,0xe0,0x7b,0xd0,0x32,0xd5,},{0x97,0x56,0x30,0x3b,0x90,0x65,0x5e,0x93,0x52,0x51,0x03,0x2a,0xb1,0x9c,0xfc,0x95,0xca,0x1c,0x2a,0x2c,0x3e,0xa2,0x8b,0x03,0x3b,0xd4,0x70,0x66,0xcb,0xd4,0xc7,0xd8,0x98,0x2a,0x8b,0x98,0x86,0xf1,0xb9,0xcd,0x02,0xe8,0x8a,0x65,0x56,0x4d,0xa8,0xdc,0xc3,0x4f,0x30,0x8b,0xa9,0xf1,0x01,0x44,0xba,0x46,0x9c,0x2e,0xfa,0x49,0xe0,0x04,},"\xb5\x16\x5d\x39\x63\xf6\xe6\xf9\xea\x56\x57\xe9\xf0\x7f\xf3\xa3\x21\xeb\x33\x8f\x9a\x8c\x3d\x3c\x42\x30\x6b\x2b\x27\x89\x78\xb3\x1c\x62\x3a\x63\x1b\xe3\xb0\x4c\x41\xed\xfd\xed\xdf\x53\x8e\x1b\x76\x5b\xc8\x78\x54\x01\xc1\xaf\x29\xd0\x46\x7a\x64\x41\x1c\x49\x73\x95\xd7\x55\xdc\xa0\x3a\xe3\x27\x2f\x4b\xc1\xfb\x19\x18\xdc\xc1\xed\x6f\x04\xd6\x49\x84\x04\xa8\xce\x14\x09\xd4\x47\xf5\x70\xa4\x35\x95\x22\xcc\x54\x62\x92\x02\xeb\xe5\x07\xab\x69\x38\x43\x14\x1b\xd5\xea\x05\x73\xb2\x0f\x32\x1a\x48\x3f\xf3\x83\xa4\x68\x97\xf5\x92\x6f\xe0\xb8\xaf\xc2\x55\x72\x70\x7b\x63\xee\xed\x28\x35\x32\x92\x8a\x41\x44\x19\x64\x97\x94\x2c\x57\x2a\xc5\x47\x60\x51\x39\x25\x6b\x0a\xa0\xea\xf0\x4d\xb1\xa2\x56\x01\x2e\xd4\x53\xb1\x73\xee\x19\xad\x6e\x9b\x1a\xf3\xf4\x5f\xf3\x04\x4a\x64\x1f\x8c\x8e\xb0\xac\x7b\xb4\x5a\xbb\xde\xd4\x72\x86\xb2\xa0\x69\xd3\x90\x86\x94\xee\x06\xf2\xfb\xd0\xef\x60\x5a\x79\x11\x02\x6e\xa9\xea\x3c\x49\x13\xf3\x8c\x04\xd8\xb6\x95\x65\xa7\x02\x78\x67\xab\x30\x92\xd0\x5f\x4c\xfb\x18\xfc\x7c"}, -{{0x8e,0xfb,0x8b,0x79,0x74,0x2b,0xe2,0x1e,0x6d,0x31,0xde,0x67,0x8b,0xc8,0x14,0x50,0xba,0x86,0x21,0x08,0x2c,0xd6,0xf0,0x00,0x3e,0x22,0x86,0x1e,0x22,0x91,0xc4,0x81,},{0x33,0x38,0x1e,0x35,0x6c,0x4f,0xd3,0x86,0xa3,0xf7,0xb9,0x69,0xaf,0xd9,0xf5,0xc0,0x0d,0x20,0x67,0xb6,0x98,0xb3,0xf1,0xf0,0x0f,0x37,0x84,0x20,0x2d,0x30,0x84,0xcf,},{0x92,0x30,0x05,0xcb,0x48,0x48,0x40,0x2a,0xa8,0xf9,0xd5,0xda,0x74,0x03,0x0b,0x00,0x94,0x44,0x92,0x4c,0x21,0x4a,0xd6,0x00,0xdd,0xba,0xb4,0xc1,0x53,0xa6,0xff,0x02,0x2b,0x53,0xcf,0x63,0x64,0xcd,0x7e,0xe9,0x9b,0xef,0x34,0xfe,0x14,0x4d,0xa9,0x64,0xed,0xfc,0x38,0xa0,0xba,0x63,0x33,0x12,0x65,0x0e,0xbf,0x0e,0x55,0xa0,0x60,0x09,},"\x6b\x75\x03\x25\xd3\xa0\xf0\x8a\x14\x77\x00\xb5\x1a\x9b\x37\x25\x57\x10\x94\x81\x8e\xd6\x9d\x1f\x76\x10\x13\xeb\x86\xf3\x23\xf7\x3c\x49\xf5\xe4\x39\x87\x7c\x27\x83\xb3\x36\xd1\xf1\xa6\x74\xef\x3e\x43\x1f\xc1\xae\x01\x80\x08\x2d\xf5\xfc\xa6\x9f\x84\x81\x39\xfe\x6a\xb6\x73\x9a\x05\x92\xeb\xd6\xd4\x70\x5c\x7f\x01\x36\xb2\x21\x89\xa1\x1d\x60\xd4\xd3\xc9\xbc\x80\xfe\x7d\x7c\x00\x95\x2d\x57\x42\xf9\xc0\xc2\x12\x1f\xe7\x92\xdf\x13\x3f\x22\x1d\xb9\x91\xfc\x96\x0e\xe6\x4b\x9d\x32\xe0\x17\x8e\x54\x2b\xce\x8e\xfa\x8d\x03\xac\x80\x26\xcd\x77\xba\x8b\xf0\xb2\x42\x15\xb9\xfa\xed\x2e\xae\xc9\x20\xe9\x25\xd5\xec\x46\xff\xf6\xbd\xe7\x25\xe9\x1c\x82\x80\xe4\xad\xa2\x32\xa5\x43\x3a\xe9\x68\x0e\xbb\x53\xeb\x55\x55\x31\x47\xc9\x33\x70\x57\x48\x54\x89\x61\x54\x51\x42\x99\xc0\x93\x21\x9a\x11\x1d\xca\x4e\x63\x7a\xd5\x00\x13\x38\xc6\xd4\xd5\xee\x90\x98\xc6\x58\x32\xf7\xaf\x83\x5b\xcb\x62\x21\x28\x42\x30\x36\xc7\x9a\x57\x37\x73\x8a\x75\x39\xf8\xd4\xa6\xb8\xb2\x21\xb5\x6d\x14\x01\xae\xb7\x4d\x45\x71\xbc\x00\x9d"}, -{{0xed,0x04,0x6d,0x68,0x8b,0x2b,0x0a,0x1b,0xc3,0xda,0xf2,0x11,0x9d,0xd3,0x21,0xa6,0x07,0xb1,0x6d,0x2a,0x2d,0x1d,0x96,0x3a,0xdd,0x12,0x09,0xc6,0x65,0xb5,0xcc,0xba,},{0x87,0x34,0xf1,0xff,0xcb,0xd7,0x1c,0xfd,0xe2,0x90,0x01,0x7e,0xa6,0x25,0x3e,0x58,0x0d,0x59,0xe6,0x5b,0x54,0x1b,0x46,0x52,0x1f,0x5e,0x5e,0xc1,0x45,0x1e,0xae,0xc6,},{0x72,0x1b,0xfd,0x47,0x76,0xcf,0xba,0x13,0x33,0x0f,0xd3,0x72,0x69,0xe9,0x79,0xc1,0xd7,0xb6,0xce,0x54,0xa5,0x1b,0x82,0xf4,0x56,0xe1,0x37,0x37,0x8e,0x58,0x2f,0x19,0x2a,0x12,0x08,0x9d,0xa5,0xab,0xa7,0x6a,0x7b,0x16,0x18,0x13,0xdc,0xe5,0x6b,0x72,0x89,0x2a,0x35,0x33,0x0c,0x94,0xf7,0xff,0x21,0xd0,0x9c,0xf0,0x9e,0x55,0x35,0x04,},"\xb9\xcc\x90\xfd\x8d\xe2\xa1\x41\xf9\x51\x16\xdb\x3b\x04\xbe\x83\xe9\x85\x22\x59\x7e\xc2\x17\x49\x64\x24\x51\x80\xb9\xa4\x73\x76\x7d\x6d\x47\x0a\x21\x7d\xb5\xff\x5a\x1a\xb7\x77\xe1\xe2\x8a\x0b\x16\x97\x5e\x2b\xac\xb8\x73\x02\x04\x44\xb4\x7e\xd8\x32\x64\x21\xb9\x0e\xbb\x50\x36\x88\xf0\x90\xc1\x1b\x3b\x13\x61\x7c\x5c\x50\x52\xc2\x97\xa4\x1e\x28\x93\x77\x5e\x34\xd5\x9a\xda\x49\xd9\x94\xc0\xe4\xa9\xf5\x22\x0e\x9f\x03\x15\xa6\x77\x05\xa3\xec\x08\xaf\x0d\xc7\x24\xb5\xcf\x67\xff\x34\xfa\xda\x8b\xa7\x10\x9e\xd2\xb5\xa8\x90\x7b\xb4\x03\xfb\x1a\x83\x8b\x4b\x05\x9f\x18\xc7\x92\xd7\xbf\xec\x05\xde\xe0\xc9\xcb\xbf\x17\x53\x40\x9d\x7d\xb3\xac\xea\xf4\x7b\x4c\x61\x39\x84\x97\xb0\xec\xa6\xc1\xf8\xac\x08\xa7\xea\x1e\xb9\xc4\x0b\xc4\xe9\x2e\x88\x82\x12\xf7\xd9\xee\x14\xfd\xb7\x31\x58\x16\x09\x44\xff\x9b\xcd\xfe\xf1\xa7\x46\x9c\xc7\x0f\x94\x74\xe5\xf2\x4d\xff\xfe\xa5\x85\xf0\x9e\xaa\xab\x4b\xe2\xaf\xeb\xbe\x8e\x6c\xf8\x6d\x35\x68\x0d\xc5\xd1\xb9\x29\x13\xe8\x48\x25\x6e\xc7\x36\x31\x6f\xd0\xa2\x14\x20\x63\xb0"}, -{{0x76,0xac,0x8e,0x57,0x0a,0x39,0xb3,0xa0,0x23,0x2c,0x45,0x49,0x75,0x37,0xfb,0x21,0x55,0xac,0xec,0x36,0x17,0x86,0x5e,0xd1,0xdf,0x21,0x0f,0x00,0xb4,0x9d,0x1b,0x8d,},{0x31,0x2a,0x3a,0xd8,0x99,0xae,0x6a,0x25,0x50,0x7a,0xe6,0xe4,0x52,0x4e,0x10,0xb6,0x3a,0x6e,0x7a,0xe5,0x3d,0x9c,0xff,0xd3,0x9c,0xf2,0x85,0x21,0xd9,0x35,0x33,0xd6,},{0xcf,0x03,0xf5,0x25,0x91,0x3c,0x44,0x30,0x3b,0x2f,0x80,0x07,0x93,0x93,0xc2,0x1c,0x11,0x58,0x14,0x6e,0xcf,0x99,0x63,0x6f,0x5d,0x97,0xad,0xfd,0xd9,0xf3,0x58,0x39,0x80,0x4c,0x23,0x80,0x4c,0xbf,0x1e,0x55,0x3c,0xfd,0x4b,0x73,0xf6,0x89,0xa9,0x14,0x3a,0xec,0x29,0x8f,0x82,0x76,0xe1,0xe4,0xee,0x08,0x91,0xf1,0xba,0x75,0xde,0x04,},"\x53\xce\xd9\xdb\x2b\x47\x9e\x59\xd3\xed\x64\x3f\x7c\xc3\x78\x4c\x24\xb8\xbd\x4c\x63\x20\x6c\x72\xe2\x3f\xa8\x50\x02\x88\x99\xa4\x1c\xe1\xa8\xbd\xc0\x03\xf1\x2b\x7c\x29\x97\x2c\x9a\x08\xbc\xd2\x31\xfe\x0e\x1a\x0f\xef\x0b\xaf\xbf\xa4\xe0\xe0\x27\xd7\x20\x04\x07\x5b\xa3\x7d\x49\x0e\xb9\x96\x4e\x78\x3b\xb9\x8f\x9e\x50\x3e\x9c\x1f\xd3\xd2\x3f\xb0\x01\x7c\xc7\xc7\xa9\xf8\x6d\x17\x1f\x04\x1e\x23\x55\xd8\xc5\xe6\x22\x9d\x34\xc7\xee\xac\xb6\x35\x8c\xf3\x06\x0d\x5d\x26\x5b\xae\x20\x04\xa5\x58\x87\x86\x59\xa3\x0d\xfe\xd5\xf2\xec\x78\x8b\x4e\x14\x39\x7b\x5d\x00\xc2\x9d\xb5\xd4\xeb\xf1\x66\x39\xa8\xdf\x29\x2a\x3d\x24\xf6\x98\x3c\xbc\xa7\x60\xd9\x03\xe9\x76\xf5\xb6\x98\x64\x2b\xa1\xfe\xd4\x9e\x79\xc3\x8f\x4b\xb3\x94\x6e\xfc\xcc\x9d\x6a\xef\xad\x33\x6d\x55\x8f\x78\xe4\xf2\x05\x42\x2e\x10\x38\x4a\x4e\x53\x1e\x75\x80\x7e\xfb\x38\x9d\x2a\xf4\xca\xb4\x38\x25\xfb\x87\xf1\x96\xa9\x08\x07\x69\xfe\x75\x85\x78\x29\x70\xa6\x91\x8a\xff\xe1\x0d\x20\xd6\x29\xb7\x05\x84\x55\x97\x41\x8d\x69\x9d\xe3\xf1\xde\x85\x4f\x94\xbd"}, -{{0xf6,0x4a,0x66,0xba,0x0f,0x08,0x19,0xf3,0x00,0x14,0x16,0xc2,0x20,0xbf,0x52,0xd8,0x60,0x13,0x0a,0x19,0x76,0x4a,0xa8,0xab,0x38,0xd1,0x5b,0x2a,0xa7,0x5a,0xc0,0x22,},{0x81,0x25,0x25,0x3c,0xd3,0x37,0xe0,0x0d,0x45,0xb4,0x50,0x79,0xb5,0x85,0x34,0x95,0x61,0xe5,0xf5,0x42,0xa8,0x1f,0x6d,0x2f,0xcf,0xd9,0x85,0xc1,0x0f,0xea,0xb2,0xaf,},{0x4d,0xe6,0xf5,0x25,0x08,0x22,0xd7,0xc9,0xd5,0xbb,0x98,0x58,0x25,0x00,0xb5,0xc0,0x85,0xf5,0x41,0xeb,0xdc,0x45,0x0e,0xd1,0xac,0xaf,0x83,0x68,0x48,0x27,0xed,0x1d,0xc7,0x71,0x47,0xaa,0xe4,0xb1,0x9e,0x14,0xa7,0xdc,0x5b,0xbe,0x1f,0x1e,0x4f,0x57,0x71,0xd8,0xa6,0xe4,0xf2,0x35,0x17,0x39,0xaf,0xb0,0x8c,0x80,0x6d,0x55,0x87,0x01,},"\x80\x72\x86\x2e\xd0\xab\x35\x92\x1d\xb5\xec\x2c\xba\x8e\x6a\xed\xb0\x44\x1f\xdf\x47\x49\x10\x06\xc0\x1e\x64\x56\xad\x70\xfa\xe3\xc4\x15\x2d\xcf\xbf\xdb\xb8\xf0\xfd\xde\xc5\xe9\x6b\x12\xbf\x67\x98\x9b\xa9\x67\x93\xf4\x86\x1a\x11\xb6\x39\x09\xce\x8d\x19\xb8\xca\x64\xa5\x44\xb3\x1c\xe0\x51\xfb\xc8\x8e\x06\x28\x06\xd9\x96\x5c\xbd\x29\x67\xb0\x16\x14\xe8\x6b\x53\x2f\xbf\x59\x84\x32\x18\xdc\x9c\x19\xc8\x03\x15\xf0\x44\x73\x17\x19\x37\x10\x92\xa3\xda\x38\x87\x8b\xc4\xcf\x77\xde\x97\x2e\x86\x04\x66\xb8\xfc\x45\xe4\x65\xdc\x3d\x0e\xbf\x94\xbd\xea\x60\xef\x0b\x98\x91\xce\xd4\x1b\x99\x7b\x11\xb3\x1e\xe4\x16\x7d\xb6\x0c\x9c\xfc\x8b\x85\xbe\xac\xfe\x22\x3c\xc1\x82\x92\x13\x77\x40\x85\xd7\xc0\x6d\x2b\x2e\x63\x2c\xc2\x1c\xd9\x66\x0d\xf4\x7c\x4f\xa9\x18\xbd\xd5\x96\xdd\xf6\x22\xdc\xb6\x52\x64\x2b\x67\x52\x7b\xa8\xed\x15\xa8\x19\xa8\xe2\x1f\x48\xd7\xee\x70\x24\x7f\x52\x00\xe3\x7c\x25\x9d\xff\xd1\x7e\xec\x8c\x23\x2f\x97\x0c\xb0\x31\x82\xfe\x39\x64\x13\x29\x93\xf6\xec\xb7\xc4\xdb\x18\xcc\xef\x39\x0c\x9e\xb3\x63\x9e"}, -{{0x84,0x39,0xb1,0xd6,0x0a,0xa4,0x84,0x60,0x13,0x5e,0xb1,0x00,0x2c,0xc1,0x12,0x79,0x29,0x95,0x07,0x9a,0x77,0xe6,0xe8,0xab,0x02,0x0b,0x9a,0xba,0xca,0x89,0x20,0xb4,},{0xea,0xdc,0x3e,0x0c,0x5b,0xdd,0xbc,0x30,0x52,0xc3,0xb2,0xf8,0xb0,0xa9,0x45,0x66,0xc2,0xb2,0xc8,0x79,0xed,0x17,0x03,0x4a,0xc0,0xe6,0xa4,0x5f,0x2b,0x3e,0x32,0xd2,},{0x62,0xda,0x81,0xe1,0x64,0x40,0x82,0x1b,0x59,0x3b,0x6e,0xe6,0x54,0x0e,0x15,0xd1,0xae,0xa7,0x5d,0x23,0xe0,0xa1,0xbb,0xfe,0xdc,0x80,0x8c,0x95,0x48,0xf8,0x7e,0x8b,0xbf,0x36,0x91,0x5a,0x39,0xa7,0x47,0x16,0xf6,0x45,0xcc,0xa5,0x71,0x4d,0x17,0x0a,0xf9,0x07,0x57,0x6d,0x4f,0x37,0x05,0xe5,0x43,0xd2,0xad,0xdd,0xc5,0xff,0x23,0x03,},"\x54\x19\xf6\xd2\x4e\xb4\x66\x35\xd4\xa7\xf8\xea\xb8\x03\xcf\xd0\xd0\x4d\xe0\x92\xaf\xbd\x86\xf2\xa6\x96\x1a\x8d\x1e\xb8\xc0\xd1\x97\xba\x55\xee\x08\xc9\x91\x82\x2a\x5a\xa7\x02\xba\xe0\x33\x7a\xbd\x5c\xa7\xfa\xa1\x5e\x1f\x1a\xe3\x69\x94\x6e\x9b\x81\x21\x6c\x0f\x5f\xc2\x2b\xbd\x44\x33\xc3\xde\x93\xc5\xca\xa2\x74\x16\x83\xbb\xd0\xe1\xa7\x8d\xf2\x8d\xda\x19\x17\x41\x01\x87\x63\x34\xd4\x03\x39\x65\x9f\x02\x1a\xe7\x66\x16\x2c\x6c\xc5\x42\x1b\x79\xcf\x9d\x5c\x09\x0e\xd4\xaf\x07\xec\x84\x49\x30\x35\xbd\x0b\x24\x21\xb5\x33\x68\x42\x95\xbb\xe7\x6a\x70\xfe\xc5\x96\xef\x8c\x89\xc5\xc9\xdd\xa3\xc3\x3b\x77\x35\xd2\xd2\xf2\x0b\x28\xf1\xa5\x40\x2e\x72\xd0\x4b\xa2\x91\xdd\x59\xf1\x4a\xf0\x8a\xdf\x56\xee\xb0\x86\xd7\x69\xc6\xbe\xc3\x45\x18\x91\x37\x23\x45\xfd\x6b\xd0\x2d\xcf\x95\xe8\x03\xaf\x03\x53\x15\x0e\x18\x2e\x32\x3a\xaf\x68\x3e\x03\x6d\x9a\x13\x5d\x2e\x6f\x98\xcb\x4d\x32\x7e\x2c\xe7\xd5\x42\x47\xf3\x59\x2e\xd0\x67\xb4\xce\x76\x27\x17\x4f\x99\x6f\x28\x16\x5c\x9c\x11\xf0\x7e\x5e\xe9\xce\xe6\x38\x51\xc6\xb6\x8e\xa2"}, -{{0x3a,0x04,0x63,0x97,0xf0,0xaf,0xc0,0x72,0xbc,0x7f,0x90,0x7c,0x74,0xd3,0x8f,0xd1,0xb9,0xaf,0xdf,0x27,0xe1,0x4a,0x35,0x34,0x76,0x8b,0x0d,0xd2,0xdf,0x3a,0x1c,0x22,},{0x99,0xcd,0x70,0xef,0x3b,0xe3,0x42,0x49,0x33,0x93,0x87,0x2f,0x54,0xc4,0x7d,0xea,0xa0,0x81,0x02,0x18,0x92,0xd1,0x1a,0x32,0x68,0xf3,0x14,0x5e,0xd4,0xf3,0xab,0xe5,},{0x50,0x24,0xce,0x60,0x25,0x79,0x65,0x68,0x70,0x80,0xc5,0xb1,0xfc,0x7d,0x13,0x01,0xc3,0x2a,0xa6,0xfc,0xc8,0x35,0x49,0x7d,0x9c,0xb2,0x3a,0x74,0xa6,0xca,0x27,0x24,0xf5,0x53,0x53,0xc1,0xb7,0x57,0x82,0x7c,0xa5,0x44,0x0c,0x9e,0xf8,0xf8,0xc1,0x05,0x09,0x13,0xe2,0x0a,0xab,0xec,0x35,0xc4,0x97,0xb5,0x60,0x41,0xb5,0xde,0xb2,0x09,},"\xf0\x8d\xde\xf4\x6c\xc6\xc3\x41\x79\x82\x0c\x98\x61\x37\x51\x72\xfd\xdf\x77\x4f\x8d\xc3\xf7\xd6\x4a\xa4\x32\xda\x8e\x5f\xae\x64\x4c\x0a\x8a\x9e\x69\x08\x51\x7d\x50\x5d\xeb\xd6\x12\x86\x8a\xc6\xda\xf9\x5c\xd7\xe1\x69\x97\x50\x02\x2c\xcd\x4b\x88\xdb\xae\x2b\xbf\x73\x54\x6e\xe4\xb8\x35\xd3\x19\xa8\x42\xda\xe8\xb9\xed\x68\x33\x23\xf3\x1e\x5c\xc5\x79\x19\xbc\x9d\xbe\x3b\xcf\xff\xb2\xad\xa4\x80\x72\x69\x7f\xf4\xa7\xd3\x10\xc9\x1a\xdb\xca\x81\xfa\xf2\x6a\x0e\xb7\xbb\x0c\x40\x4a\xc9\xd8\xdf\xec\x63\xe9\xc6\x4e\x2f\x42\x0c\x07\xd3\x23\xb7\xc0\xdc\x3b\x73\x50\x72\x83\xae\xb1\xce\xe5\x1d\xb4\xe1\xa8\x3a\x69\x2c\x7c\x1e\xa3\x98\xf6\xf3\x09\x40\xfa\xb8\x5e\x21\x38\xd4\xb8\x5a\xa4\xe2\x31\xe5\x42\x4f\x5b\x06\x4e\xd0\x26\xf0\xcc\xb9\x9d\x1c\x85\xa9\xeb\x15\xf5\x93\x4a\x11\x35\x9d\x41\x1c\xf9\x4a\xe8\xff\xa3\x36\x1a\x22\x4f\x46\xba\xb8\x52\xd1\x84\xa2\x48\xb4\xc3\x1f\xe3\xa7\xe7\xf5\x13\x4c\x05\x10\x31\xa9\xf3\x28\xa7\xbe\x4a\x7c\xbb\xb1\xd8\xd8\x63\xa4\x00\xfd\x2d\x58\xda\xa4\x4f\x1b\x9d\x8e\x9d\xdf\x96\x1c\xe6\x32\x2f"}, -{{0x12,0x4f,0x74,0x16,0xa8,0x04,0x53,0xe4,0xcf,0x1c,0xd7,0xb5,0xe0,0x50,0xa9,0x76,0x14,0x18,0x25,0x8b,0xf7,0xd2,0x7b,0xeb,0x7f,0x23,0x23,0x8c,0x45,0x40,0xbe,0x2d,},{0x0d,0xa3,0x4a,0xb1,0x73,0x99,0x01,0x50,0xdf,0x73,0x99,0xb6,0xbc,0xdd,0xba,0x93,0xc6,0xdb,0xcb,0xf4,0xd1,0x76,0x94,0x1c,0xb5,0x07,0x1e,0x87,0x34,0xc5,0xdc,0x92,},{0xb0,0x57,0x21,0x04,0xaa,0x69,0xe5,0x29,0xe3,0x46,0x5a,0x6f,0xd2,0x8f,0x40,0x4a,0x4e,0xc2,0x02,0x76,0xa9,0x93,0xb1,0x72,0x5e,0xb8,0xc5,0xf6,0x50,0xb4,0xa2,0x16,0xf1,0x87,0x1b,0x24,0xe3,0x68,0xcc,0x46,0xcd,0x1e,0xe0,0x17,0x4c,0xda,0x1b,0x5e,0x4a,0xe2,0x20,0x0a,0xa9,0xfc,0x44,0x52,0x2d,0x97,0x5a,0x9c,0x51,0x81,0x49,0x08,},"\x9d\xcb\x98\x73\xff\x05\x4d\xb1\x1d\x0a\x9b\x19\xde\x68\x85\xff\xba\x7f\x0e\x68\x1c\xf7\xfb\x8f\x6c\xd9\x50\xc4\x83\x28\xd1\xf9\x19\xca\x46\x05\x4e\xee\xe6\xc9\xe5\x78\x43\xeb\xdd\xa7\xb2\x4b\xc3\x50\x3c\x4d\x61\x2a\xbb\x1a\x31\x4f\x39\xf5\x82\x21\xd2\xb5\x4d\xc7\x55\xac\xca\x79\x69\x74\x0e\x7f\xa8\xb1\xa9\x52\x3b\x8c\x73\x79\xfd\x39\x52\x53\xf4\xe6\xcd\x05\x4e\xe2\x4b\x75\x61\x3c\x35\x81\xd4\x9e\x19\x24\x6a\x7b\x3b\xe1\xce\xcb\x33\x4b\xe4\x4f\x3d\x62\x6f\xe3\xb7\xb2\x69\xe6\x28\xd4\x45\x80\xc2\x06\x36\xeb\xa2\x64\x2f\x27\x44\xb9\x59\xe6\x57\x57\xd0\xee\x60\x18\x43\xf1\x88\xe9\x5d\x17\x25\x3f\xef\x56\x70\x68\xa5\x40\x5a\x3a\x9e\x67\x7f\xea\x3d\x7d\x55\xf7\xea\xd1\x9a\x3f\x30\xc5\xf9\x85\x67\x1b\x55\xfa\x12\x0c\xb9\xd0\x5f\x47\x1b\x6e\x1e\x8d\x77\x9a\x2c\x80\x3a\x19\xe6\xd0\xd7\xcd\x50\x78\x87\xed\x64\x7c\x2a\x95\x48\x3f\x93\x39\x91\xed\x45\xae\x30\x1a\x2b\x0e\x95\x4a\x57\x03\xd2\x48\xc7\x88\x10\xaa\x0b\x19\x9c\xc2\xbe\xbb\x2f\x1d\x71\xcc\x40\x48\x7d\xbd\x42\xee\xe0\xf7\x45\xf7\xd2\x85\x68\x5b\x1f\xb3\x1b\x15"}, -{{0x25,0xd1,0x3b,0x38,0x37,0x60,0x1b,0x07,0xa9,0x75,0x69,0x3e,0x5a,0x33,0xd5,0x33,0x7c,0x34,0xc1,0x12,0x7f,0xe4,0xc2,0x74,0x90,0x61,0x2a,0xaf,0x7f,0x64,0x2e,0x9a,},{0x3a,0x07,0xcd,0x68,0xee,0x26,0x92,0xd5,0x1c,0xfa,0xd1,0xa8,0x0e,0x77,0x63,0xb1,0x8a,0x04,0x3c,0x74,0xf4,0xe1,0xb0,0x1e,0xdc,0x55,0xba,0x9a,0x9e,0x07,0x79,0x5a,},{0x20,0xcb,0xf0,0x83,0x92,0xfe,0xa6,0xa9,0x9c,0xf4,0x46,0xa9,0x5c,0x19,0x9c,0xaa,0x0c,0x0f,0x98,0x13,0xcc,0x21,0x7b,0x8d,0x22,0x8e,0x2e,0xd9,0x0b,0xab,0x95,0xea,0x92,0xcd,0x73,0xac,0x95,0x83,0x47,0x64,0xd3,0x3e,0x42,0x24,0x3c,0x80,0xa7,0x60,0x34,0x91,0xc8,0xd3,0xe4,0x9a,0xc7,0x15,0xfd,0x8a,0x5b,0x9e,0x47,0x89,0xbb,0x03,},"\x11\x5b\x32\x20\xb4\x5c\xa8\xf3\x6c\x7f\xf5\xb5\x38\x87\xd4\x7e\x66\x9b\x78\xda\xc1\x3b\x98\xcc\x7a\xac\xa5\xc2\xe1\x9f\xce\x81\xec\x86\x17\xca\x41\x0e\x11\xc9\xa9\x11\x8a\x66\x84\x53\xb3\x29\xff\xb7\x18\xea\xec\x73\x91\x72\xf0\xa8\x49\xa0\x84\x81\x92\xa5\xbd\xea\x18\xab\x4f\x60\xd8\xd1\xa0\xd3\x38\x95\x2d\x77\xb2\xcc\x13\xef\xe8\x3c\x76\xe8\xdd\x58\x80\x3b\x1d\x8b\x3c\x97\x29\xef\x10\x2b\x20\x83\x5b\x7d\xe8\x72\xbe\xf3\x01\x0f\x15\xa4\xca\xdd\xf0\x7c\xf7\xbd\xd2\x22\xd8\x4b\x17\x4b\xc2\x15\x27\xcf\xfb\x1b\x7f\xfd\xe8\x1e\x28\x1d\x30\xcb\x7b\xce\x25\xea\x3d\xff\xb6\xea\x1f\xbb\x06\xcb\x70\x56\x9a\x95\xed\x1a\x07\xe9\x7c\xa4\x2d\xe7\x0a\xa2\x18\x15\x9e\xfd\x60\x8f\xa9\xb0\x89\x6e\x0b\x58\x51\x8a\x32\x2f\x25\x1d\x13\x3e\x58\xc8\xfc\x14\x28\xab\x0a\x17\x0e\xd8\x45\xc7\x5f\xb4\x03\xf1\xff\xb9\x7d\x2d\x2a\x6d\x4f\x27\x79\x11\xd3\x26\xc1\xca\xbb\xb8\x51\x6c\xbc\x17\x90\x8a\xb8\x1f\xf8\xd7\x9a\xf4\x46\x11\xea\x1d\x05\x87\x9c\x1e\xc8\x1d\x06\x93\x6e\x0f\x4a\x0a\xef\x6d\x57\x48\xe1\x81\xd3\x0e\xc2\x52\x36\x59\x7a\x97\x3d"}, -{{0x7b,0x3a,0x76,0xde,0xca,0xea,0x60,0xc4,0x1e,0x95,0xb0,0x58,0x77,0xa7,0xda,0x82,0x06,0x4c,0x27,0x27,0x8c,0x8d,0x7d,0xf5,0xf0,0xbb,0x95,0xf0,0xad,0x2d,0x04,0x35,},{0xf8,0x0d,0xb5,0xc2,0x87,0x21,0xb1,0xc6,0x11,0xbd,0x87,0xeb,0x14,0x5a,0x98,0xbb,0xf3,0x83,0xb0,0x68,0x04,0x5d,0xf2,0x45,0x8d,0x1a,0x6f,0xda,0x09,0x9f,0x7f,0xc2,},{0x2c,0xd2,0x6f,0xb3,0xc4,0xf7,0x44,0x0a,0x72,0xaf,0xfe,0x93,0x56,0x4f,0x6f,0x65,0x59,0xad,0xb1,0x5c,0xc7,0xa2,0xba,0x10,0x87,0x9f,0xb7,0xd6,0x7e,0x47,0xd4,0xeb,0xd0,0x2f,0xe4,0x82,0x36,0x98,0xa5,0xfb,0xd4,0xa9,0x07,0xfd,0x69,0x18,0x4c,0x25,0x5a,0x17,0x0e,0x5f,0x17,0x47,0xfc,0xe9,0x68,0x10,0x2d,0xc2,0x19,0xb5,0x0d,0x02,},"\x37\x5f\xad\xae\xdd\x9c\xac\x49\xb6\x4e\x15\x74\x02\x80\x46\x06\x9f\x4c\x83\x65\x4c\x8a\x70\x11\xab\xdb\x64\xdb\x16\xb4\x7f\xa3\x11\x79\x81\x72\xf9\x07\x22\x17\xb0\xa6\xa4\x3e\x5d\xf6\xff\xcc\x11\x54\xbc\xec\x1c\x68\xe1\xd3\x5e\xc0\x58\x80\xd0\x12\xce\x76\xe4\xce\xbf\x30\x1b\xb2\xec\x98\x3d\x00\xb4\xa0\x54\x0c\x93\x7f\xf1\xc6\xdf\x94\x41\xc6\x1b\xdb\x3b\xe8\xe0\xc7\xc1\x1a\x35\xd4\x9b\x6f\x55\xc3\x81\x26\x9a\x0e\x76\x8e\xfb\xd4\x53\x44\x7f\xe4\x8b\x75\xac\x39\x64\x6c\xa8\x2e\xca\x7d\x14\x93\x04\x42\x34\x91\x87\x1c\x10\xdb\xcf\xc5\x97\x3a\x57\xfa\xb8\x37\x1c\x30\xcb\xc4\xe9\x0b\xec\xc0\xb6\x71\x52\x22\x6e\xe1\x77\xb4\xff\x36\x8e\xc8\x79\xb3\x91\xeb\x95\xe3\x6d\xcb\xb0\x7b\x2c\x16\xba\x39\x55\x45\xd4\x52\x9f\x72\x7b\x1a\x11\xef\x65\xd1\x20\x97\x6b\x7c\xcc\x86\xaf\x4b\xd2\x04\xcb\x94\x89\xc9\x21\xe4\x3b\xa5\xe8\x50\xcf\xe5\x98\x99\xf1\xc1\xec\x4a\xa5\xc9\x2b\x6d\xac\x69\x14\xb1\x95\x2b\x53\xdc\xb5\x40\xb4\x09\x23\x13\x81\x56\x89\x87\xbb\x22\x36\xbc\x40\x89\x5d\xf3\xf1\x7e\xab\x7c\x02\x74\xf2\x24\x4f\x95\x86\x12\xe8\x8e"}, -{{0x5f,0xf8,0xd4,0x05,0x26,0x08,0xeb,0x03,0x3a,0x5e,0x94,0xb6,0x03,0xce,0x38,0x4d,0x84,0x52,0xf6,0x0a,0x26,0x49,0x8b,0x91,0x12,0x56,0x7f,0x34,0x10,0xc1,0x86,0x66,},{0xc4,0x90,0x0d,0xe2,0x4d,0x9a,0xf2,0x48,0x27,0x63,0x10,0x99,0x26,0xaf,0x7c,0x48,0x13,0x80,0xfa,0xbc,0xda,0x94,0x40,0xc1,0xa5,0x3e,0xa1,0xcd,0xc2,0x7e,0x65,0x68,},{0xb7,0x37,0xd4,0xe5,0xbe,0x27,0xde,0xb6,0xd8,0x77,0x29,0xc6,0x36,0xdf,0xf7,0xa4,0x06,0xc0,0x13,0xf3,0x13,0xc3,0x8c,0xf6,0x83,0xfe,0x14,0xf7,0x5a,0x3b,0x30,0x05,0xd9,0x53,0x5d,0x7e,0x58,0x15,0xc8,0xf8,0xb3,0x7c,0x51,0xd6,0x92,0x71,0x11,0xc9,0x79,0xf7,0xd9,0xd8,0x1a,0x34,0x7a,0xa9,0xcc,0x09,0xed,0x4e,0x6c,0x18,0xe9,0x0f,},"\x13\x8c\x60\x55\x7c\x2e\x90\x08\xaf\xc0\x3d\x45\xbe\xc7\x1f\x96\x11\x49\xa0\x83\x59\x26\x75\x1c\x8f\xf3\x93\x5c\x7d\x65\x2d\x83\xe1\xb0\xb1\xda\x7d\x5b\xbe\x0b\x8e\x17\x1a\x4e\x49\xaa\xe0\x6f\xd8\xa9\xde\xff\x78\xdc\xde\x4d\x25\xb1\xaa\x89\x99\x98\xa0\xf9\x9e\x1d\xf6\xf9\x33\x7a\x3e\xa2\xf2\x4b\x76\xc3\x17\xa7\x01\x4d\xb4\xe5\x28\x31\x91\x79\x5a\x70\xd8\x82\x1d\x21\x78\x46\x49\x0f\x95\x87\x01\xd3\x9d\xc2\xc8\xce\x47\xd9\x28\x93\x88\x74\xd8\x7b\x35\x58\x98\x9b\xc7\x7a\xf8\x20\x97\x9a\x35\x1e\xef\x95\x94\xaa\x5b\x94\xf3\x34\x1e\xde\xd4\xea\x20\xb0\x8c\x3e\x7c\x56\x10\xd4\x32\x67\x81\x8d\xfa\xc0\xa8\x7d\xdf\x52\x7f\xbc\xe8\x51\x2b\xbf\x85\xb6\x6c\x9b\xb5\xd6\x2f\x0f\xe8\x40\x48\xf2\x3b\x19\x60\x4a\x5c\x8d\x82\xb1\xf2\x5a\x8d\xa0\x27\x31\xfe\xb2\xec\xae\x48\x9b\x84\x75\xf7\xbd\x32\x6d\xdf\x1a\x08\x18\x9e\x46\xc0\x8c\xf5\x05\x38\xc2\xa3\x63\xe2\xf4\xeb\x2c\x01\xa2\x04\xc7\xff\xbc\x0b\x98\x1a\xdc\x0f\xd9\x97\xaa\xfd\xf2\xa2\x22\xee\x84\xc3\x09\xf6\xe9\x5e\xc7\xde\x4f\xa8\x5d\x47\x68\xd5\xc0\x03\x16\x50\x28\x22\x5e\x22\xe0\x9e"}, -{{0xee,0xde,0xfc,0x17,0x57,0xe3,0xa7,0xe5,0xed,0x39,0x46,0xdb,0xed,0xc3,0x96,0xa3,0x62,0xf6,0x83,0xd2,0xc5,0x1b,0x0b,0x9f,0x60,0x76,0x5d,0x4b,0xfc,0x51,0x34,0xde,},{0xa9,0x87,0x2b,0xc2,0x19,0x2f,0xc0,0x2b,0x18,0x9c,0xee,0xd4,0x03,0xab,0x9f,0x27,0x0a,0x03,0x2a,0x83,0x5f,0xde,0xbf,0xaf,0x1c,0x9d,0x69,0x34,0xed,0x83,0x04,0xbc,},{0xd5,0xbe,0xa8,0xea,0x9a,0x5f,0xe9,0xed,0x6d,0x2b,0xf8,0x39,0x93,0x0c,0x0c,0x6c,0xd5,0x03,0x9e,0x98,0x8f,0x55,0x1f,0xde,0xdb,0x54,0x37,0xe1,0xc1,0xaf,0x0e,0xd7,0xb3,0x89,0x7c,0x03,0x57,0x11,0xc3,0xc5,0x19,0x26,0xbe,0x8d,0x1b,0x32,0x02,0x4d,0x5c,0xd5,0x82,0xf5,0xf8,0x36,0x9a,0xd8,0x4d,0x18,0xb1,0x25,0x02,0x65,0x2f,0x07,},"\xb1\x94\xdb\x73\xf9\x94\xcb\xdc\x3c\xbe\x63\x0b\xa7\x2c\x47\xc2\x24\x9b\xc0\x59\x2a\xb5\x47\x94\x2b\x1d\x1b\x88\x2b\x44\xf5\xb3\x85\x5e\x56\x8b\xdd\xdf\x92\xef\x05\x02\x2d\x88\xfc\xfc\x29\x4e\x76\xb6\x4a\x00\xe9\xc7\x43\x55\x37\x37\x63\xe4\x9a\x4e\xbc\x47\x24\x3d\x48\xa9\xad\x58\x89\x94\xa5\x18\xf8\x0f\x86\x15\xc2\xb3\x1d\xa5\x87\xa5\x3e\x52\x9d\x43\x5a\x86\x97\x35\x0d\xfc\xde\x02\xd2\x0c\xce\x7d\x5e\xee\xfe\x3f\x5a\xb2\xaa\xc6\x01\x25\x9c\xda\x38\x53\x8a\x1b\x83\x01\xf9\x83\x2e\x75\xab\x90\xf8\xa9\x32\xf2\x67\xea\xc1\x81\x00\x39\x65\xd5\x26\x6f\x20\x61\x80\xc6\xc3\x80\xec\xe8\x03\x57\x7c\xcb\x46\x17\x6b\xf6\x07\x15\x94\x86\xf2\x42\x59\x74\x7e\x2c\xa6\xfb\x19\x12\xdb\x7b\x78\xa9\x73\xb2\x84\x63\x87\xc1\x20\x80\x30\xee\x1f\x40\x0d\x0c\x5b\x5e\x8b\xde\x96\x35\xae\x55\x63\x8b\xa1\x7c\x73\x4d\xe8\x63\x8b\xb8\x5d\xfc\xd7\x66\x29\xa7\xf9\xf4\x0d\x6a\xb9\x54\xd5\x5b\xf8\x57\x5f\xc9\xc9\xa5\x95\x09\x7e\x08\x93\xdb\x5a\x7b\x8a\x6c\x45\x5e\xcb\xd3\xd2\x2d\x72\x5e\x19\xde\x29\x41\xf4\x67\xf9\xeb\x93\xd6\x6a\x0e\x2b\xbd\xbf\x92\xed\x1c"}, -{{0x09,0xd2,0x2b,0xba,0xa5,0x95,0x6c,0xfa,0xcb,0xbf,0x9f,0xd5,0x51,0x09,0x75,0x12,0x86,0x86,0xc4,0x0c,0x6e,0xa9,0x6b,0x89,0xef,0x4c,0x0f,0x0c,0x64,0x9b,0xcd,0x7f,},{0xe5,0x59,0xea,0x8a,0xcb,0xdc,0x61,0xb6,0x70,0x9a,0x7d,0x83,0xae,0x15,0x84,0x9a,0x6c,0x78,0xb2,0x03,0x92,0x3d,0xd0,0xa2,0x99,0x23,0x9e,0xe4,0x88,0x69,0x30,0xba,},{0xe6,0x52,0x75,0xc4,0x32,0x8a,0x70,0xad,0x62,0x40,0x8e,0xd7,0xfb,0x17,0x28,0xbe,0x87,0xa7,0x3a,0x81,0x4f,0xee,0x8e,0xbd,0x94,0xf2,0x66,0x5c,0x71,0xbc,0x66,0xab,0x0c,0x1b,0x07,0xa6,0x00,0xb3,0x0b,0xc0,0x81,0xa7,0x4c,0x53,0x68,0x57,0xc2,0x06,0x10,0x38,0x4b,0xe2,0x68,0xd9,0xaf,0x3e,0x3e,0xcd,0xdd,0x3e,0xb0,0xc1,0x4c,0x0c,},"\x1c\x26\xa0\xf3\xa1\xa5\xb2\xd7\xd5\xb2\x97\xaf\x8a\x6a\x68\x9d\x7c\x62\xa2\x52\x67\xe1\x97\xd2\x3b\xec\xd2\xf2\xb8\x16\xc4\xde\x92\xfb\xda\xff\xb9\x41\xc3\xfc\x8d\xb7\xa8\x43\x35\xa8\x4c\xfb\xc9\x2c\xb3\xac\x80\x6e\xd5\x8d\xf1\x6b\x6b\x8e\x11\x9a\x48\xdf\x4f\x27\xc7\x1e\x93\x1a\x59\x38\xe7\xd0\x02\x73\x48\x85\xe1\x3a\x25\x8a\x15\xb6\xe1\x13\x6e\xfb\xa7\x2f\x1d\x09\x6b\x68\x9f\x76\x18\xf4\x9c\x96\x80\x63\xe8\xf9\x91\xfa\x0b\x55\x60\x1e\x43\x0e\xee\x13\x49\x2a\x1b\x09\x41\x3e\xb2\x38\x13\x59\x1a\x7a\x9f\x07\x0c\xc3\x96\xca\x9d\x1f\xac\xdd\x4f\x4c\xe3\x7c\x40\xf7\x24\x5f\x55\x03\x5e\x10\xfa\xd6\xb8\x5b\x5f\x01\xa1\xda\xac\xc0\xdf\x94\x06\x9f\x7d\xe8\xf6\x46\x7f\x96\xd1\xfb\x98\x64\x8e\x8a\x05\x20\xa8\xcd\x72\x3c\x98\xe9\xdc\x2d\xd4\xb2\x93\x4d\x82\x28\xf0\xae\x1a\x41\x5b\xd3\xa7\xcd\xa3\x8d\x7a\x99\x83\xce\x1a\xf6\xf8\xc9\x70\xa2\xa5\x91\x63\x5f\xe1\x2b\x91\x75\x36\xef\x81\x5e\xaf\x1a\x31\x38\xd7\x0c\xe7\x0a\x79\x42\x64\xd7\xc9\x86\xd9\xee\x32\x90\x44\x5f\x15\xa9\x24\x8f\x27\x65\x27\x1e\x5a\x99\x21\x96\xae\x33\x1a\xbd\x41\x64\xbf"}, -{{0x77,0x82,0x6e,0xd3,0x51,0xa3,0xf0,0x92,0x54,0xae,0x56,0x92,0x88,0x5d,0x77,0x4c,0xb3,0xf2,0x44,0x10,0xa4,0x80,0x9f,0xd9,0x0f,0x8a,0x00,0xda,0x9a,0xee,0x99,0x03,},{0x3e,0xac,0x8f,0x41,0xee,0x73,0xe6,0xef,0x13,0x68,0x21,0xf7,0x95,0x7a,0x1c,0x27,0xe1,0x56,0x38,0xd0,0xe3,0x91,0x6e,0x6c,0xaa,0xc6,0xfb,0x7b,0xeb,0x7b,0xcf,0xb0,},{0x97,0x7a,0xdc,0xcd,0xb8,0x29,0xb4,0x0b,0xbd,0x8e,0x53,0x85,0x6a,0x78,0x3d,0xb3,0x46,0xa3,0x9d,0xff,0x62,0x04,0x1a,0x29,0x72,0xd2,0x90,0x09,0xf1,0xc9,0xff,0x81,0xb8,0xad,0x54,0xcb,0x90,0x1e,0x49,0x7c,0x1d,0x30,0x21,0xb5,0x0b,0x6c,0x69,0xee,0x73,0x55,0x8f,0xd7,0xbe,0x05,0xd6,0x25,0xf5,0x72,0x7f,0x9a,0xf2,0xce,0x87,0x02,},"\x1f\xf0\x6c\x0b\x39\x99\xce\xcb\x19\x00\xa4\x7d\x26\x7b\xea\xfb\xb3\x5d\x93\xd1\x4c\xb2\xc8\x92\x5e\x3e\x3f\xe5\xd9\x67\x58\x69\x25\xee\x4b\xaa\x41\x99\x8e\xdd\x01\x03\x20\x58\x10\xaa\xd5\xc0\xbb\xdc\x77\x87\x44\x76\x81\x02\x46\xd1\x30\x89\xa6\x4d\xb5\x76\x42\x4f\xae\x0b\xed\x96\x64\xa4\x2a\x49\x11\x47\xd1\xee\x3b\x9c\x3b\x1b\xa4\x87\x5b\xe1\x54\x62\x39\x25\x40\xf9\x97\x8d\x9a\x46\x30\xba\x4c\x52\x54\x99\x75\x1a\x45\xef\xc2\x99\xec\x7d\x73\xb1\x7f\x9a\xd2\x75\xee\x71\xa6\x87\xe7\x26\x90\xd7\x32\x02\x42\xd2\xdc\x2b\xd4\xd5\xc5\xcf\x0f\x17\xa4\x65\x18\x5d\xcf\x60\xf8\xef\xff\x53\x90\x3f\x20\xb0\xc2\xab\x21\x92\xd4\x43\x68\xf2\xf2\xfb\x36\x04\x8a\xf0\x71\xf7\xaa\x85\x7b\x14\xad\x1d\x11\x46\x12\x05\xbe\xbe\x17\xe0\x2b\xe2\xe3\xcc\xb6\x09\x28\x21\x88\x5c\x4e\x0d\x48\x11\xbe\x3f\x45\xb1\xfe\xa0\x88\x45\x3e\x02\x24\x32\xf5\x62\x56\x2b\x43\xa3\x55\xcb\x56\x27\x0c\xed\xb6\xc2\xc4\x2d\xbf\x9b\xe8\x50\xe7\x71\x92\xfd\xc6\x5c\xfd\x36\x83\x4b\xe9\x88\xdb\xe9\xa9\x3e\x25\x18\xc1\x38\xb0\x90\xfb\x9d\xa8\x27\xcb\x1c\x91\xc8\xfe\x52\xfe\x7c\x57\xf7"}, -{{0x99,0xa9,0x95,0x31,0xc3,0xcd,0x6e,0x3e,0x9c,0x90,0x0a,0x9e,0xeb,0x26,0x26,0x7e,0x72,0xf0,0x9d,0x11,0xb6,0x51,0xa8,0x97,0xeb,0xb7,0x9b,0xe0,0x16,0xf6,0x4c,0x6e,},{0x9b,0xf9,0xf8,0xb4,0x8a,0x27,0x28,0xe0,0x26,0x08,0xfc,0x19,0x89,0x9d,0x21,0x96,0x56,0x83,0x9d,0x1c,0xc1,0xe9,0xa8,0x98,0x4d,0xf6,0x74,0xec,0x26,0x66,0x2f,0x41,},{0x0e,0x89,0xda,0x5d,0x94,0x9c,0xf2,0xbf,0x40,0xc7,0xe1,0x7c,0x2d,0x0f,0x9c,0xea,0xbc,0x88,0xa0,0x92,0xeb,0x4d,0x49,0xcf,0xbf,0xea,0xb7,0xc8,0xbf,0xf4,0x32,0x45,0xc6,0x7b,0x9e,0x2e,0x92,0xf9,0xbc,0xb9,0xb3,0x4b,0x3f,0xcf,0x8b,0x01,0xfa,0x2e,0xa7,0xa9,0x64,0x9f,0x81,0x4c,0x3a,0xa9,0x8b,0x3d,0xd0,0x45,0x40,0xc3,0x1d,0x09,},"\x7a\x89\xc0\xc1\x95\x2f\xdc\x42\x98\xdc\xae\xa8\x54\xef\xc1\x34\x65\x6b\xe1\x47\xe9\xe8\xe8\x2f\xc9\xa4\x49\x05\x9d\x80\x57\x0f\x75\x67\x6b\x81\xc4\xa9\x4f\x76\xa9\x68\x20\x0c\xde\xb0\x98\x8c\x73\xf5\x9a\xfc\x72\xad\x4c\x31\x03\xe1\x9f\xe6\x3b\x7e\x95\xe1\x40\xb5\xcb\x2e\xfc\x7b\x97\xa6\xff\xbb\x6c\x29\x8d\xda\xce\x3b\xe6\xd2\xed\x3d\x59\x8b\x8b\xdf\x0c\x2f\xe6\xc9\x76\x02\x14\x2a\x76\xe9\x78\x51\x4c\x19\x6c\x1b\x9a\x88\xef\xdc\x19\x25\xfc\x50\x61\x55\xcf\xf9\xa2\xf2\x1a\xb6\x34\xe2\xb9\x3e\x96\x92\x8a\x5d\x8f\x7c\xe4\xcb\x73\x26\xd9\x68\x94\x69\x24\x2b\xa9\xc6\xa0\x1b\x77\x49\x6b\xad\xef\x87\x57\x8f\x5a\x17\x28\x4e\x90\x0a\x72\xdf\x14\x1c\x61\x99\xb0\xe7\x1a\xb5\xda\x43\x75\x03\x76\x17\xec\x61\x96\xd4\xf4\xe2\x3a\xe2\x91\x6a\x72\xd0\xfc\xe7\x96\x02\x23\x05\xac\x9f\xbb\xbb\xe4\x70\x5b\x34\x0e\x42\xb7\x8e\x1c\x02\xbb\x10\x01\x86\x0c\xdc\xaf\x71\xed\x89\x25\x5d\xd5\x6c\xc0\xb3\x1c\x59\xd4\x59\x6d\xce\xf8\x4e\x22\x23\x4b\xe5\x62\xbd\x80\x1e\x94\x11\x1d\x83\xa7\x80\x64\xc9\x0f\x9d\x82\xfc\xe9\x1f\x68\xab\xb0\x3c\x73\xb6\xbd\x8d\x7e\x02\xd4"}, -{{0xaa,0x58,0x40,0x3e,0x76,0x3b,0xac,0x40,0x5d,0xb0,0x65,0xeb,0x11,0xeb,0x6b,0xe3,0xe3,0xb6,0xcf,0x00,0xec,0x4a,0x22,0x2b,0x52,0xbf,0xf4,0xb6,0xe3,0xd1,0x56,0xac,},{0x16,0x7f,0x9b,0x9a,0x46,0x65,0xf9,0x3f,0x5d,0x7d,0x30,0x16,0xac,0xe6,0xfb,0xd1,0x34,0x20,0xb2,0xe5,0x1e,0x72,0xbd,0xe5,0x9e,0xed,0xf2,0x69,0x93,0xb6,0x6c,0xae,},{0x64,0xb5,0x98,0xca,0x5b,0x8f,0x9a,0xe7,0x42,0xe4,0x6e,0xe0,0xd8,0xc1,0xaa,0xf3,0x14,0x58,0xb5,0x0c,0x25,0xd2,0x67,0xa6,0x77,0xe4,0x4b,0xe5,0xb7,0x55,0xf1,0x4d,0x51,0x80,0x1a,0x30,0x39,0x9b,0xfc,0xc3,0x8d,0x14,0x07,0x1a,0xa0,0xae,0x93,0xda,0x82,0x5a,0x58,0x1a,0xb6,0xc2,0x07,0x25,0xa0,0xa9,0x10,0xb4,0x73,0x5d,0xfa,0x0b,},"\x3b\xaa\x09\x98\xff\x02\xb3\x2b\x90\xb5\x1f\x9a\x84\x0c\x7b\x5c\x58\x70\xcf\xb1\x81\x0a\x9b\x0f\x77\xb5\x59\x09\xd4\x7a\xd3\x35\x14\x7a\x99\x1c\x29\xfb\xeb\xfc\x59\x2e\x93\x07\x17\x5c\x19\x64\x12\x9a\x2d\x5e\xfc\x62\x15\x80\x74\x53\xbc\xd7\x26\x96\x97\x81\x22\x2b\xca\xd1\xc9\x9a\x49\x74\x8b\x9e\xe6\x67\xc4\xd0\xc8\x28\x89\xe2\xf5\x00\x64\xc1\x15\xdb\xd8\xfb\x48\x3d\x72\xab\x0c\xca\xdf\x76\xbd\xdb\x2d\xc7\x27\xdb\xc3\xfa\x5c\x46\x24\xc2\x83\xd8\x92\x1c\x8a\xa4\x42\x51\x10\xdc\xdd\x69\xc0\x5e\x5e\xd5\x9b\x35\x96\x25\xee\xaa\xec\x1e\x27\xea\xfe\x9d\x9a\x5c\xe7\x36\xc3\xf9\xc5\x27\xea\x54\x78\x18\xb9\xbc\xa6\x81\x1b\xe4\xcc\x15\x05\x8a\x6f\x5b\x68\x33\x03\xb8\x0c\x90\xc9\x4a\x83\xb8\xb1\x58\x69\x71\x3a\x66\xb1\xe0\xf6\x56\x33\x1b\x28\x6d\x1e\xf7\x69\x88\x34\xab\x3e\x13\x84\x17\xaa\xd6\xbb\x3a\xb3\xbd\x9f\xc7\x87\x61\xa4\x82\xdf\xc6\x54\xf3\xf8\x62\x8c\x8d\x9f\xc1\x60\x18\x89\x8f\x16\x41\xe8\x62\x2b\xd2\x72\xe3\x8d\x41\x70\x6c\xb9\xce\xbe\x6e\xe5\xe1\x73\x57\x6b\xf6\x1b\xb1\x18\x8c\xf2\xf3\x9c\x62\x22\x0b\xba\x88\xfc\xb4\xde\x48\x98\xb2\x5b\x04"}, -{{0x10,0x44,0xee,0x37,0x08,0xc0,0xb0,0xe9,0x09,0xa8,0xcb,0x2b,0xa2,0xcd,0x0a,0xf8,0xd2,0x8a,0x5d,0xe0,0x1d,0x96,0x2e,0x82,0x60,0x87,0xfb,0x23,0x2d,0xf7,0xb2,0xd2,},{0x46,0xd2,0x41,0xea,0x0c,0x70,0x2c,0x18,0x89,0xd4,0x46,0x55,0x82,0x46,0x29,0xb6,0x72,0x84,0xd4,0xe6,0x44,0xa4,0x8f,0xa4,0x54,0x55,0xd2,0x7a,0xc5,0xf6,0x25,0x29,},{0x7d,0x6b,0xed,0x7f,0x87,0xd0,0x90,0xab,0xe0,0x13,0xc3,0x1e,0x12,0x03,0x90,0x3b,0xac,0x9c,0x93,0x44,0x5d,0x06,0xc7,0xb5,0x3d,0x31,0xd1,0x5f,0x97,0x0d,0x88,0x64,0x7a,0x7e,0xd2,0xc3,0xa6,0x30,0x50,0xba,0x19,0xd6,0x80,0x43,0xaa,0xdd,0x18,0xbd,0x86,0x1d,0xe1,0xac,0x47,0x15,0xb8,0xe8,0x28,0xb2,0xb1,0x6f,0x8a,0x92,0xb0,0x01,},"\xb8\xa4\x45\x45\x5f\xb6\x6e\x17\xe3\x14\x3d\x35\x20\x4c\x9e\xa9\x34\x74\xee\xbe\xef\x93\x96\x3e\xe5\xc1\xd3\x77\xca\x21\x7a\xcd\x4c\xa6\x3e\x57\x55\xda\x08\xfb\xff\xdb\xd4\x35\x2b\xf1\x65\x19\x38\x96\xc8\xd6\xf7\x6b\xb4\xcd\x3b\xc2\xd3\xa4\x76\xa4\xe3\x20\x82\x4a\x12\x10\xce\x74\xd0\x01\x4d\x74\x7f\x11\x1e\xec\x31\x0c\x5c\x89\xed\x4d\x08\x50\xe8\x11\xf8\x0a\x8b\xb2\x8d\xca\xf6\xf4\x11\xdf\x83\xe2\xc1\xdf\xd9\x0c\x4a\xd2\x35\x61\x45\x4e\xb5\xd7\x56\xb6\x3b\x4e\xa7\xf3\x7d\xc5\xd4\x66\xc1\x6e\xf7\x0d\x11\x19\x0c\x4f\x53\x16\xfe\x2a\xa8\x59\x74\x40\xe8\x8b\xbe\xba\xeb\x35\xea\x5f\x04\xf0\x7b\x03\x39\x26\x41\x58\xef\x90\x9a\xd5\x16\x3b\xfc\x24\x8c\xd7\x24\x13\x3e\x27\x4f\x81\x26\x95\xf2\x90\xe5\x71\x76\xa9\x6b\x93\x93\xd0\x7b\xb3\x10\x29\x9f\x5d\x2a\x6b\x6d\xd1\xda\xbc\xb5\x1b\xf2\x9c\x5a\xfa\x7e\xbb\x07\x01\xc6\xc8\x47\x67\xac\x13\x77\x93\x09\x1f\xe0\xed\x6e\x47\xd7\x80\x62\x8a\x32\xc8\x4f\x83\xe0\x0e\x9c\x16\x74\x2a\x52\x3e\xcb\x63\xc2\x4f\x4a\x33\x8e\xd2\x99\xa0\x61\x94\x92\x4f\x44\xc5\xa5\xd3\xc9\x37\xff\x9b\x09\x45\x98\x2a\xd2\x4a\x2d\x1c\x79"}, -{{0x95,0xdd,0x1a,0x5e,0x65,0x8f,0xa6,0xc8,0xd4,0x25,0x07,0xb3,0xe5,0xb8,0xed,0xb5,0xba,0xec,0xa6,0x2d,0xeb,0x00,0xfc,0x5d,0x4d,0xca,0x8e,0x1a,0xb5,0x83,0x5e,0x59,},{0x3a,0x53,0x23,0xdd,0x1e,0x07,0xf3,0x23,0xbb,0x6d,0x83,0xe9,0xc2,0xdb,0x92,0xa2,0x9f,0x62,0xe2,0xe0,0x03,0xee,0x0d,0xea,0xcd,0x7e,0x2e,0x4e,0x03,0x0d,0x8d,0x27,},{0xd0,0x2a,0x75,0x23,0xdc,0xbd,0x29,0x57,0x6b,0xa8,0x09,0xb5,0x31,0x03,0x77,0x74,0xdf,0x41,0x73,0x4a,0x41,0x17,0x58,0x13,0x11,0x9c,0x6a,0x6a,0x78,0x8c,0xd9,0xb8,0xad,0x78,0x08,0x65,0x67,0x86,0x67,0x69,0x9a,0xe6,0x6d,0x01,0x09,0x19,0xa9,0x66,0xa0,0x51,0xc0,0x81,0x63,0xdf,0x67,0xa9,0x77,0xee,0x6e,0x22,0x0d,0x0d,0xc3,0x0f,},"\x9b\x7a\xfd\x48\xc4\x74\x60\x4c\x26\x36\x75\x31\x55\x68\x40\xc3\x88\x66\x8b\x0f\x38\x40\x06\x3d\xfc\x98\x69\xad\x5b\x90\x12\x74\xb9\x31\x29\x3d\x04\xf3\xc8\xe8\xf7\xf8\xea\xb8\x15\xa6\x41\xd7\xc3\x51\x28\x4e\x8b\xb0\x43\x7a\xc5\x51\xbb\x29\x43\x89\x64\xe6\xa7\xc7\xba\x77\x23\x44\xb3\x33\xf9\xed\xa5\xa7\x75\x68\xc8\x93\x1d\xdc\xaf\x21\xe3\x2e\x07\xb1\x0b\xf4\x82\x0f\xb8\x59\xbc\xf8\x7b\x81\xc4\xbf\xf4\x26\xf2\x4a\x4d\x46\x8f\x2e\x9a\xed\xa8\xf1\x7d\x93\x97\x09\x97\x0d\xb1\x1d\xf7\x62\x47\xe9\x8a\x39\xeb\x8b\x38\xf5\x94\x9f\x34\x9f\x2a\xe0\x5a\xb4\x8c\x01\x85\x17\xc4\x8f\xa0\x20\x5d\xc7\xf1\x56\x64\x53\xe1\x05\xe4\x8c\x52\xeb\x45\x5c\x0c\x40\x80\x2f\x79\x7b\x3e\xef\xb1\xe2\xf3\xb1\xf8\x43\x15\xae\xd5\xb0\x71\x1c\x64\x99\xa6\x91\xb7\x4b\x91\xf1\x2e\xf7\x0f\x76\xc4\xc0\x5c\x1a\xa1\xa9\x93\xe2\xf3\xe5\x28\xab\x34\x3d\xd2\x36\x81\x62\xf4\x03\x6a\x61\xa1\x3a\x88\x04\x5d\xcd\xef\xa8\x5d\x68\x53\x22\x75\xbc\xf5\xb8\xf5\xf0\x0e\xfd\xea\x99\x9a\x95\x78\x31\x75\xd9\xee\x95\xa9\x25\xd4\x8a\x54\x49\x34\xd8\xc6\xb2\x62\x22\x5b\x6e\xbe\xa3\x54\x15\xdd\x44\xdf\x1f"}, -{{0x1a,0xbc,0x0b,0x9a,0xa0,0x1d,0xc5,0x7c,0xa5,0x3e,0xfe,0x73,0x80,0x96,0x2b,0x1a,0x88,0xd5,0x0a,0x96,0x4f,0x5c,0xd9,0x86,0x40,0x98,0x2c,0x74,0x39,0x3f,0x29,0x26,},{0x8d,0x4f,0xd1,0x43,0x94,0xd7,0xc1,0x40,0x57,0x00,0x30,0x69,0x83,0xfb,0xf7,0x6e,0xa9,0xf1,0x71,0xb1,0x5a,0x6b,0x56,0x61,0x2a,0x1f,0xeb,0x1c,0xbd,0xae,0x5d,0xd5,},{0xf7,0x38,0xaf,0x2d,0x3e,0x29,0x0b,0x3d,0x23,0xd9,0xaf,0xf7,0x41,0x4b,0xfc,0x5f,0xfa,0x47,0x23,0x5d,0xc0,0x53,0x68,0x7a,0x8b,0xa5,0xc8,0x54,0x1b,0x85,0x11,0xf7,0x81,0x56,0x6c,0xda,0xa1,0x30,0xe0,0x67,0x7d,0xb5,0x5f,0xa8,0xbe,0x9d,0x81,0xa0,0x92,0xcb,0x58,0x92,0x3a,0x86,0x28,0x49,0x4d,0x2f,0x62,0xd9,0x5c,0x16,0x71,0x00,},"\xda\x2d\xd9\x40\xd5\xe1\xdb\x6e\x80\xbf\x7e\x2b\x78\x2e\x7e\x74\x5c\xd4\xfd\x25\x2e\x98\x15\x17\x97\x58\x87\xdd\x05\xac\x77\xed\x83\x7d\x08\x29\x61\x57\x5e\xfe\xdf\x30\x1f\xdf\x24\xb7\x07\x18\xb9\x91\xb8\xd9\x2b\xdd\x2e\x6b\xee\x17\xc8\xaa\x4b\xc6\x94\xa7\x27\xbc\xfc\x78\xfd\x85\x19\x5c\x42\xca\xf8\x83\xa2\xc3\x8d\x16\x1c\xad\xd7\x9c\xfd\xa9\xa3\x91\x10\xe1\x26\x4d\x30\xbd\x4c\x5c\x4a\x58\x76\x77\x7f\x23\x3b\x07\x1b\x1b\x0b\x40\x89\x35\xf0\x46\x89\x54\xcc\x74\x4a\xf8\x06\x3b\x00\x4e\xde\x56\xcd\x98\x1c\x4d\xd5\x60\x8a\xbf\xfe\xae\xc9\xe5\x8f\x3f\xaf\xaa\x67\x14\x67\x80\x4b\x7f\xa2\x55\x8f\x4f\x95\x17\x42\x01\xf1\x83\xd8\x0a\x59\x14\x06\x5f\xed\x53\x11\x5b\x41\xeb\xc3\x38\xf7\x8d\xf0\x50\x05\x3b\x8a\x4e\x75\xea\x7c\x6f\xdc\x35\x4d\xad\x27\xbf\xd8\xa2\xe6\x6f\xcd\x7a\xe2\xf5\x87\xd2\x4b\xe0\xd4\xa3\x3d\xa3\x0a\x22\x0e\x51\xbc\x05\xfa\x4e\x41\x2b\x95\x9f\xd9\x5d\x89\xea\x6e\xc0\x16\x25\x16\xc0\x96\xa9\x43\x3a\x9e\x7c\xf5\x99\xc9\x28\xbd\x53\x05\xc2\x17\x3b\xf7\x49\x3e\xd0\xc1\xc6\x03\xcd\x03\xf0\x82\xcc\xe4\x42\x37\xa7\x9f\xfd\x8b\xe9\xa6\x72\xc2\xeb\xaa"}, -{{0xcb,0xff,0xce,0x2c,0x9b,0xd3,0xe2,0x3e,0x40,0x6e,0x5f,0x66,0xe6,0x32,0xdc,0xfa,0x72,0x66,0x54,0xd2,0x9a,0x95,0x5c,0xec,0x98,0x31,0x73,0x23,0x5f,0xa3,0x59,0xd0,},{0x49,0x65,0x3e,0xdd,0x64,0xa5,0x5f,0x7c,0xd4,0x0e,0xaf,0x3f,0x8e,0x72,0xeb,0x96,0xdb,0xcd,0xee,0x39,0x8f,0x34,0x81,0x7f,0x2c,0x95,0x86,0x79,0x49,0x71,0x0b,0x14,},{0xe7,0xce,0xd4,0xfa,0x2a,0x7d,0xff,0x73,0xf1,0x06,0x8b,0xba,0xd0,0xec,0x9a,0x11,0x09,0x04,0x3c,0x97,0xa6,0x2e,0xff,0xa1,0x48,0x87,0x6f,0x09,0x69,0xed,0x4d,0xc6,0x08,0xe2,0x8b,0xce,0x79,0x7a,0xf3,0xb8,0x25,0x32,0xc9,0x4d,0xec,0x4d,0x68,0x11,0xb7,0xf5,0x63,0x67,0x91,0x29,0xfa,0xcf,0x17,0xbb,0x73,0xd6,0x93,0x75,0xeb,0x05,},"\x1f\xfd\xe6\x82\x6e\x4f\x0c\x24\xa7\x96\x1f\x19\x1e\x74\xcc\x0b\xbc\x92\x8e\x3f\x1a\xec\x3e\xfa\xb3\x27\x65\xc2\x50\x1c\xbc\x16\x20\xe7\xee\x6f\x61\xfc\xcf\xb0\x0c\xfc\xa9\xfb\x98\x14\x3b\x52\x9b\xcc\x8c\x3d\x0f\xdf\x89\xee\x7c\x34\x2f\x10\x18\x15\xfa\xbf\x7d\xea\xf9\xf3\x02\xa2\x88\xfe\x17\x58\x26\xd5\x90\xd9\x9e\xe6\xfd\x92\xda\x74\xf9\x59\x6b\x78\x3c\x0e\x7d\x47\xd7\x11\xa3\x2f\x39\xea\x41\x65\xe5\x21\x24\x31\x44\x1b\x49\x8c\x6b\x70\xdb\x3b\x09\xd1\xf4\xe4\xa1\x4a\x6b\xae\x39\xda\x50\x88\xbb\x85\xb3\x28\x5c\xe9\xdf\x2f\x90\x68\x1a\xf2\xc7\x4d\xec\xe4\x39\xae\xb9\x1e\x1c\x1b\x07\x12\xed\xdb\xee\x8d\x72\x56\x98\x28\xf3\x7c\xb7\x20\xc5\x09\xd0\x2a\xec\x47\x60\x70\x48\x4e\x9b\x16\xec\x71\x79\x94\x7a\xc9\x6c\xaf\x0e\x1b\xe8\xb6\xb7\x4f\x37\x2d\x72\x35\xfe\x6e\x39\x99\xdf\x73\x3b\xcc\xd4\x82\xdf\xe2\xe6\x31\xf5\x6b\x58\x26\x67\xdc\xe5\xe3\x12\x17\x63\xad\xfa\xcf\x3b\x18\xcf\x20\x95\xf7\x39\x4d\xee\x49\x27\xfc\x2b\xea\x6b\x58\x24\xd9\x0c\xd5\x9e\x85\x4e\xc5\x87\x2b\x45\x51\xb0\x2e\xfa\xba\x5a\xd5\x4a\x9b\x7a\x8f\x6d\xe5\xd7\xcd\xa5\x82\x5b\x32\x5b\x07\x6d\xed"}, -{{0x9f,0x91,0x23,0x14,0x97,0x48,0x4c,0xab,0x39,0xb9,0xe2,0x0f,0x86,0x11,0x81,0xd3,0x97,0x90,0x85,0x77,0xbb,0xb2,0x96,0x82,0x42,0xd0,0x71,0xbc,0xa4,0x81,0x3f,0xfb,},{0x88,0x24,0xbc,0x6c,0xd6,0xa6,0xf1,0x5a,0x5f,0x41,0x66,0x8f,0x2b,0x3b,0xae,0x8f,0xc4,0x96,0x73,0x83,0x07,0x8d,0x08,0xb5,0x1d,0x6d,0x1b,0x2b,0x93,0xa1,0x07,0x1f,},{0x0a,0x1c,0x70,0x6d,0xd8,0xa1,0x30,0x77,0xab,0x18,0x38,0x6c,0x65,0xfa,0x97,0xcf,0x9d,0xfc,0x43,0x54,0x2d,0x18,0x46,0xec,0xbd,0xde,0xb7,0xb3,0xc9,0x3f,0x3c,0x66,0xf3,0xcc,0xd0,0x44,0x7a,0xac,0xdd,0x4d,0xad,0x8f,0xbf,0x73,0x6c,0x4f,0xf9,0xdb,0xdb,0x62,0xbf,0xc1,0x4d,0x88,0x83,0xe3,0x85,0xbc,0xe9,0xba,0xc5,0x6a,0x35,0x0c,},"\x21\xd4\xfb\xc9\x81\x63\xc3\xfb\x6e\x09\xf7\x75\xc2\xab\x7b\x18\xb1\x87\x92\x34\x0b\xaf\xed\xac\xb4\x96\x05\x62\x2e\x3c\x08\xaa\x3b\x2b\x8d\x0e\x09\x02\xf3\x61\xaa\x1c\x0f\x65\x2e\x27\x32\xb1\x0a\x0c\x5c\x6a\x05\x09\x89\x96\xb5\x88\x26\x7c\xc8\x95\x1a\x78\xb5\xd4\x31\xe7\x22\x2b\xbb\x50\x8e\xee\xf1\xb5\xe8\xb8\xd0\x1d\x39\x91\xe1\x8d\xdd\xc6\xca\x8d\x22\x2e\xf1\x77\xce\x62\x93\x8d\x18\x10\xee\xcf\x06\xf4\x73\x8b\x28\xf4\x40\x94\x6c\xca\xd2\xa1\x2e\x39\xd3\x86\x11\xbe\xd3\xa3\x9f\x93\x41\x9a\x17\x9e\xc2\xb1\xb5\x2d\x5f\xe5\xc8\x0c\x23\xb8\x4d\x88\x03\x75\x5f\x51\x46\x09\x2c\xc1\x99\xb4\xbd\xce\xa5\xbc\xf2\x03\x7b\xd5\x3f\xf6\x34\x66\x94\x15\x5f\x02\x7d\x8c\xe2\xba\xff\xe3\x0a\x56\x66\x59\x6c\x00\x78\x3a\xae\xad\xe9\xc7\x7f\xc8\x63\x79\x42\xec\xe0\x17\xd6\x48\x4c\x28\x99\xb1\x91\x8d\x3a\x48\x0b\xd5\x15\x76\x78\xd4\x77\x2d\x27\x1f\x9b\x99\x76\x8e\xe1\xbc\xc4\x6b\x24\x89\xae\x87\xcd\x03\x0f\x47\xd1\x33\x3c\x76\x72\xcb\x90\x2c\xb4\xf5\xfe\x74\x6e\x85\x3d\xe5\x79\x40\xba\x22\x64\xd3\xe6\x29\x64\x4d\x65\x3a\x5b\x7a\xf7\x8c\xe6\x4a\x99\x3f\x36\x25\x0f\x8c\xb7\xcb\x45"}, -{{0x1e,0x2b,0xd5,0x48,0x7c,0x5f,0x5c,0xed,0x46,0x1f,0x60,0x4d,0xcc,0xb4,0xe7,0x8e,0xb9,0x16,0x08,0xf0,0xb8,0x21,0xf5,0xaf,0xc4,0xe3,0xe5,0x34,0xf7,0x96,0x03,0x92,},{0xef,0x82,0x54,0x75,0xcf,0x20,0x51,0xa2,0x01,0x7a,0xe5,0x32,0xf0,0x77,0xd9,0x67,0x74,0x34,0x7d,0x27,0x67,0xea,0x7b,0x45,0xf9,0xc1,0xb8,0x60,0xab,0x99,0x35,0x06,},{0x4d,0x33,0xc9,0x6a,0x2e,0x3a,0x5d,0xb7,0x39,0x1a,0xdf,0x65,0xc1,0xcc,0x35,0x65,0xfe,0x76,0xee,0xaf,0xd0,0xb5,0xc7,0xab,0xb0,0xb4,0x92,0xa0,0xb5,0x1e,0x1f,0xa3,0x36,0x39,0x94,0x6a,0x24,0x3b,0x2d,0xde,0xf3,0x57,0x55,0x22,0x98,0xce,0x0a,0xa9,0x5e,0xac,0x6f,0xbf,0xe6,0x60,0x98,0x82,0x71,0x87,0x7e,0xb2,0xa7,0xda,0x18,0x06,},"\x1d\xbb\xbb\x13\xcd\xad\x88\x85\x4b\x80\x9c\xed\xed\x27\x33\x43\xd3\x06\xa8\xde\xab\xf3\xff\x02\xc9\xce\xc6\xf0\x02\xb8\xe9\xe1\x0e\xf5\xd1\xb0\xf5\x71\x1f\x33\x26\x7a\xa9\x1c\x17\x1b\x61\xe9\x60\xf7\x40\x45\x7b\x81\xd7\x51\xa4\x73\xf4\x4f\x75\x0a\x08\x0c\xab\x80\xaf\x7c\xcc\xa7\xdf\xfc\xfa\xc9\xee\x4c\x39\xdc\x85\xcb\xdf\x51\x25\x9c\xcd\x34\x70\xd9\xba\xd3\xad\x30\xf4\xee\x5d\xbd\x4f\xac\x6b\xd5\xc6\xc4\xdf\x73\x11\xa4\x70\x04\x46\x95\xa7\xe1\xa7\xe1\x85\x72\x20\x75\x88\xaf\xa5\x7e\xeb\xcd\x4d\x57\x5b\x6d\x42\x44\x57\xee\x92\x46\x5c\xe1\x86\x3e\x3c\x67\x7c\xf8\x75\xfd\xb9\x8d\x40\x78\xeb\xe7\x14\x42\x60\x80\x70\x52\x57\x71\x44\xcb\x8e\x03\x59\xaa\x42\xad\x15\x5d\x79\xda\xe3\xde\xb9\x9c\x46\x32\xc1\x91\xc7\x99\xcb\xfe\x58\x7d\x95\x47\x87\x06\x8d\x66\x3b\xdf\xc0\xfa\xb1\x33\x4f\x18\x76\xbf\x49\x8c\x4d\xb5\xc5\x3d\xb7\xb0\x20\x4e\xd5\xa5\x21\xc6\x2f\x09\xea\xca\x8d\x01\x89\xf3\xb3\x94\x14\x3f\x29\xc4\x21\xcb\x5c\x8d\x07\xbd\x75\x1b\xaf\x4c\xbe\x3b\xf4\xbe\x17\x01\xdf\x4b\x22\x07\xdf\xb2\x90\x4d\x84\xf4\xdb\xda\x51\xcb\xa5\x76\xd5\xa5\xbb\x16\xef\xe6\x98\xed\xd6\x08"}, -{{0xf7,0x8d,0xb1,0x4d,0x6d,0x1a,0x64,0x3d,0xd7,0x73,0x5b,0xaf,0x26,0x35,0x32,0x12,0x44,0xe7,0xec,0x8c,0xa7,0x2c,0x5c,0x38,0xc9,0x8c,0x80,0x9d,0xb9,0xcb,0x5a,0x55,},{0x54,0x14,0xf7,0x5f,0x52,0xf3,0x86,0x4a,0xfb,0x0c,0x79,0xc2,0xc5,0xc1,0xd0,0x6b,0x4b,0xce,0x40,0x0f,0xbd,0xdf,0x17,0xfe,0x9c,0xfb,0x2a,0x8b,0xac,0x47,0xa0,0xdd,},{0xd7,0xcb,0xd4,0x18,0x1f,0x67,0x71,0x20,0x07,0xb7,0xf0,0xe1,0x84,0x52,0xe0,0xa0,0x24,0x46,0x4d,0x9d,0xc9,0xb5,0xff,0x9c,0xf6,0x69,0xd1,0xb9,0x11,0x69,0xd7,0x57,0x32,0x62,0xf8,0x33,0x36,0xb9,0x7c,0x86,0x1b,0xfa,0xb3,0xfc,0xf6,0x69,0x22,0x3c,0xe8,0xca,0xf3,0x19,0xf2,0x1d,0x23,0xf1,0xfa,0x33,0x1a,0x2d,0x89,0xb6,0xca,0x0b,},"\x05\xca\xf1\xb8\xed\xc3\xb1\x73\xfb\xc1\xed\x29\xb9\x5e\x2b\xf0\x6d\x81\x4b\xa2\x40\x7d\x4b\x31\xc7\x28\xd0\x4e\xc2\x73\xd2\x53\x94\x42\x3a\xc7\xd4\xff\xf2\xca\x36\xee\x90\x27\x30\x93\xc7\x56\xe2\xbd\x13\xc9\x6d\x4a\x3d\xc7\xf5\xbe\x17\x59\xfc\xd3\x28\xeb\x66\xc5\x88\x2b\x58\xfa\x45\x88\xe5\xb2\xa3\x71\x3a\x41\x54\xa2\x34\x0d\x0b\x06\xad\x01\x96\x01\xb0\xe0\x28\xe4\x97\xf8\x98\x25\x6b\x02\x8a\xf9\x5c\xd8\x16\x8d\xf5\xe5\x8a\x57\xcd\x1e\xbf\xc0\xa0\xc9\x1c\xed\x61\xdb\xb4\x80\xac\xa7\xdf\x8d\xca\x91\xeb\x16\xe9\x80\x07\xcd\x2c\xd1\xa2\x04\x5b\x0e\x44\x77\xd1\x2d\x5a\x40\x72\xf3\x65\x42\x65\x67\xc9\xd6\x15\x77\xf3\x48\x5c\x8f\x46\x60\x5e\x7f\x47\x5e\xf0\x4a\x39\x48\xf6\x0d\xba\x8c\x55\x08\xd1\x4b\xfd\xdb\x9b\x11\xdd\x04\x4e\xf2\xd8\x4c\x16\xb9\xa9\x03\x8d\x8e\x78\xed\xa4\x3b\x91\x29\x7d\xf3\x5f\x43\x61\xa3\x83\xb4\x1d\x49\x67\x7a\x68\x7d\x5b\x34\x4a\xd1\xab\x0f\xc7\x30\x17\xb3\xbe\xbf\x32\x30\x6f\xb3\xfd\x7b\x3d\x50\x71\xf3\xab\x5f\x6e\x49\xaa\x15\x54\x0c\xad\x65\x03\xbe\xa7\x78\x4c\xf9\x42\x18\x01\xce\x13\x85\x83\x98\x93\x36\x2a\x97\xfa\xe1\x21\x30\x0d\x67\x83\xaf\x0f"}, -{{0x7d,0xfa,0x32,0x8e,0x90,0xa1,0xb8,0x49,0xc2,0x19,0xe3,0xda,0x83,0x2d,0xf9,0xed,0x77,0x44,0x82,0x34,0xf0,0xd8,0x9e,0xa5,0xd1,0x7a,0x3d,0x64,0xe7,0x88,0x3d,0xaf,},{0xe3,0x0c,0xe6,0xfd,0x5f,0x58,0x00,0x38,0x9a,0x70,0xcd,0x11,0x73,0x64,0xf5,0x99,0x45,0xaf,0xb1,0x80,0xf2,0x29,0x92,0x73,0x60,0xb0,0x6b,0x48,0x35,0xf8,0xdc,0x91,},{0x1c,0x61,0xd5,0x3b,0x87,0x2f,0x8c,0xde,0x59,0x86,0x09,0x68,0x2c,0x79,0xf6,0xc5,0xdf,0x00,0x7c,0x51,0x3a,0x71,0xcf,0xb3,0xa0,0x6d,0xcb,0x82,0xd8,0x5c,0x4b,0x00,0xcc,0xc4,0x0b,0x00,0xe5,0x9f,0x59,0x53,0x93,0x08,0x8b,0x4c,0xd0,0x43,0x28,0x55,0xc6,0x7a,0x20,0x7d,0xa7,0x1f,0x87,0xe7,0x2c,0x40,0x9b,0x3e,0x50,0x27,0x95,0x07,},"\xe5\xe4\x95\xd6\x63\xf4\x72\x36\x71\x45\x32\x68\x7a\x24\x30\x8f\x94\x2c\xa9\xc3\x3e\x08\x8f\x7f\x10\x6a\x5a\x72\x35\x18\xca\xcb\xbe\xf4\xa6\x8c\x93\x9a\x69\x50\xb2\xdc\x25\x89\xf8\x2d\x35\x4e\x57\x52\x72\xd4\x2b\x13\x83\xd3\x15\xab\x8a\x20\xaa\x0c\xdc\x9d\x4d\xf6\x78\xab\x3b\x26\x61\x2b\x5d\xca\x66\xe7\x1f\x9f\x3f\xa7\xd9\xe7\x31\xdc\x48\x1e\x2b\xc7\x12\x7c\xea\x3b\x62\x03\xca\x6c\xd8\x16\x2e\x90\x88\x6a\x73\xdc\x46\xc8\x3d\xde\xfc\x4b\x9e\x2d\x53\xd2\x9d\xd3\x87\xc6\x24\xe0\x8b\xd8\xd5\x3b\xe9\x28\xa4\x0a\x9a\xa8\xae\x8b\x1c\x8d\x0f\xb6\xa7\xbd\x6d\xce\x5f\x62\x31\x5b\x7a\x21\x81\xf6\x27\xf2\x56\xbb\xe7\xe2\xa9\x5b\xf4\x64\xe6\x13\x22\x04\xc1\x74\x20\x96\x29\x84\x02\x35\xb2\xc3\x99\x13\x30\x1a\x4b\x40\x32\x5d\x11\x8d\x38\x4b\xc7\xac\x02\x8c\xd4\xf1\x27\x02\xe1\x61\x19\x1b\x14\x9e\x42\x09\x05\x8a\x55\x12\x2b\xbb\x8b\x22\xb2\x46\x83\xba\x4f\x8e\x2e\x6c\xcf\xc0\x8d\xc8\xc8\xb1\xbc\xfb\x6d\x60\xbd\x8f\x06\x21\x96\x93\x3d\xf3\x19\xab\x16\x90\x6d\x08\x57\x30\xeb\xa1\x72\x0d\x4b\x02\xc6\x7d\xaf\x38\xcc\xe6\xab\xa3\x8e\x25\xd6\x8e\xf9\x5b\x2f\x52\x19\x13\xa1\xd7\x7d\x5e\xb6\x50"}, -{{0x6c,0xe1,0x3d,0x3c,0x2e,0xc7,0x1f,0xed,0x83,0x13,0x1a,0x69,0xd5,0xd0,0x30,0x31,0x4a,0xb4,0x9e,0x65,0x65,0xef,0x68,0x16,0x3f,0xff,0x09,0xac,0x5d,0x9b,0x47,0xe7,},{0x9c,0x7b,0x11,0x18,0xfa,0xb9,0x1e,0x0e,0x7b,0x19,0x2a,0x23,0xd9,0x5f,0xb8,0x77,0xcb,0x79,0x36,0xcc,0x6c,0x8a,0x33,0x05,0x92,0xf4,0x8e,0x67,0x84,0xed,0xc2,0x92,},{0x60,0x8b,0x2b,0xf6,0xf6,0xda,0x05,0xc2,0xac,0x5b,0xbf,0xd7,0x95,0xa2,0xac,0x32,0xc7,0x9c,0x74,0x15,0x3f,0x94,0x31,0xde,0xa5,0x97,0x68,0xff,0x4c,0x22,0x5e,0x3b,0x69,0x3b,0x64,0x5a,0x50,0x67,0x66,0xb8,0x60,0x85,0x0e,0xe9,0x7e,0xa4,0x30,0x32,0xb0,0x5b,0x69,0xe5,0x67,0x67,0xe8,0xeb,0x9d,0x19,0x18,0xdf,0x9a,0xfb,0xa8,0x05,},"\x10\xbb\xc3\x11\xeb\x2a\x76\x5e\x01\x67\xff\x37\x61\x8f\xf7\x0e\x13\xf0\x2d\x7b\x06\x17\xae\x4a\xc0\x6b\xef\xbb\xe1\x49\xc9\x72\xa9\x94\xf6\x80\xca\x4d\xc9\xa9\x2e\xc7\xef\xa5\x39\x97\xfa\xd3\x56\xb9\xff\x4e\xbd\xee\x62\x95\x41\xd1\xf4\xde\xa6\x2e\xd0\xd2\x49\x4f\x9c\xcf\xdf\x07\xa9\x31\x04\x91\xf6\x1c\x4b\x3e\x27\x00\xb4\xa3\xc6\x68\xd6\x78\x32\x9a\x38\xc2\xef\xf9\xd8\xcb\xa4\x31\xfb\x95\x9e\x7f\x76\x55\xbd\x0f\xbd\x77\xd5\x3b\xbb\xc2\xeb\x8d\xc5\x1d\xd7\x18\xed\x98\x72\x8a\x18\x16\x86\xbe\x12\x2b\x84\x4d\x3d\xa3\x31\xe3\x29\xd3\x95\x9b\x59\x23\xf7\x73\x43\x25\xa0\x21\x02\x6e\x27\x54\xe1\x7a\x15\x10\x8b\xe8\x01\x46\x5a\xd9\x58\xdb\xcf\x21\xdf\x89\x0c\xfe\x5d\x5b\x88\x3c\xa4\x3c\x61\xce\xdc\xcb\xdb\x58\xb8\x49\xea\x75\x37\x4f\x1e\x91\x8e\x80\x3e\x57\x7a\x5d\xc7\xa1\xc1\x79\x36\xec\xcf\xcd\x34\x81\xbd\x2b\x1e\xb0\x75\xb8\x32\x37\xca\x6f\x3c\x07\xc1\x9e\x9a\xf9\x73\x12\x67\xbe\x82\xd4\x89\x8e\xee\x96\xeb\xc9\x00\xd4\x8b\x05\x9d\x51\xb0\xdd\x41\x5b\x1c\x89\x06\x60\xa8\x8d\x25\xf5\xc5\xf3\x5d\x8e\x45\xe5\x23\xe0\xce\x33\x36\x92\x3a\xb4\x36\x70\xe3\x5c\x50\x57\xd5\x6c\x75\x88\x76"}, -{{0xd4,0x5e,0xe6,0x9a,0x5f,0x1a,0x7c,0xfd,0xd0,0x34,0x3f,0x87,0x70,0xd1,0xc6,0xbc,0x02,0x6f,0x06,0x7a,0x70,0xdb,0xe8,0x39,0xa8,0x6f,0x2a,0xa0,0x68,0xc3,0x3f,0x81,},{0xfc,0x8d,0x9f,0xb0,0xe4,0xf3,0x47,0x93,0x09,0x07,0x55,0xe0,0x32,0x80,0x96,0xe0,0x1e,0x28,0x1e,0xa3,0x51,0xb8,0xd9,0x5c,0xd9,0x11,0x6e,0x13,0x1a,0x5c,0xa5,0x4e,},{0x15,0x6c,0x51,0xc5,0xf9,0x15,0xd8,0x9b,0x8d,0x14,0x00,0x35,0x0f,0x8f,0x21,0x7a,0x5c,0x02,0xe2,0x62,0x9e,0xde,0x9f,0x4a,0x30,0xb6,0xe7,0x1d,0x1e,0xa7,0xa9,0x53,0xcc,0x6d,0xb3,0x1b,0xa5,0xc7,0x78,0xc2,0x69,0x92,0x0b,0x64,0x9f,0xb4,0x22,0x1c,0x6d,0x38,0xcf,0x2c,0xea,0x2a,0x7d,0xe3,0xad,0x42,0x3e,0x04,0xfa,0xaa,0x06,0x07,},"\xeb\x5e\xd8\xab\x79\xcb\xfe\x61\xc2\x59\x81\xb9\xd1\xd6\xb7\x0f\x10\xb6\x01\x94\xb4\x16\x1f\xe1\x7d\x11\xaf\xf1\x76\x79\x94\xaa\x08\x13\xe9\xec\xe2\xf4\xc5\xd5\x31\xb9\x9e\x8a\xdf\x18\x88\xc3\x0a\x63\x89\x3e\xb4\x51\xaa\xf5\x5a\xcd\x5a\x52\xad\x8c\x40\x1f\xaa\x88\xd6\xea\xcf\x3e\x49\x47\x05\x66\x11\x4f\xd0\xc6\xa2\x74\xe9\x54\x48\x46\xb0\xae\x9b\xfa\x12\x4d\x79\x51\xeb\x26\x71\x5e\x19\x25\x3f\xf7\xed\xc8\xa7\x09\x65\x77\x6f\x23\xce\x46\x03\x1e\x03\x4a\x20\x07\x23\xba\x3d\x11\xe1\x1d\x35\x3d\x7e\x7c\xd8\x4a\xed\xe2\x67\xff\x64\xbe\xd4\x18\xcb\x9f\x28\xc6\x1c\xd0\xf6\x3b\x6c\xe2\xec\xae\x14\xb2\x0b\xc6\xbd\xae\xd8\xc4\x28\xba\xd1\x8b\xe4\xb7\xd6\x63\x38\x36\x4a\xcd\x80\x42\xa8\x25\x6f\x25\x8a\x69\x96\x9b\x8d\x3c\xa2\xea\xb3\xae\xa3\x70\x6e\x5f\x21\xc3\xb1\xef\xcc\x25\x4a\x82\x4b\xb4\xe7\xea\x7a\xba\x88\x27\xc8\xeb\x82\x78\x6c\x66\x5a\xa9\x73\x82\x19\x31\xff\x99\x0a\x63\xfd\x34\xa7\x4a\x6d\x8c\x22\xa8\x82\xb0\xb9\x35\x15\x2c\xcb\x36\xfc\xc7\x6f\x4e\xca\x65\xd6\x7c\x86\x80\x94\x2f\x75\xdf\xad\x07\x34\x39\xc0\x91\x60\x65\xe8\x38\x77\xf7\xba\x20\x93\x03\xf3\x35\x48\xd9\xe4\x0d\x4a\x6b"}, -{{0x8a,0x76,0xea,0xab,0x3a,0x21,0xec,0x5a,0x97,0x5c,0x8b,0x9e,0x19,0x7a,0x98,0x9e,0x8e,0x03,0x08,0x99,0xeb,0x45,0xd7,0x89,0x68,0xd0,0xfb,0x69,0x7b,0x92,0xe4,0x6d,},{0x2d,0x9c,0x81,0x3d,0x2d,0x81,0xe2,0x73,0x0b,0x0d,0x17,0xd8,0x51,0x2b,0xb8,0xb5,0xd3,0x3f,0x43,0x6c,0xab,0xaa,0x13,0xe1,0x41,0xca,0x1c,0xb7,0x85,0x01,0x43,0x44,},{0xfc,0xee,0xcc,0xa4,0xb0,0x14,0xfe,0xcd,0x90,0xb9,0x21,0xb0,0xfa,0x3b,0x15,0xae,0xaa,0x4e,0x62,0xca,0xa1,0xfb,0x22,0x72,0x9c,0x70,0x26,0x92,0x32,0xc3,0x3c,0xef,0x0d,0x0a,0xee,0xa6,0x64,0x32,0xc1,0x28,0xaf,0xb9,0xa3,0x64,0x6b,0xc7,0xf0,0x3a,0x12,0x77,0x4d,0xa8,0x75,0x83,0x98,0xc2,0xa0,0xdc,0xce,0x0b,0xbb,0xf6,0x74,0x0a,},"\xc6\xc7\x8f\x2e\x20\x80\x46\x1a\xed\x9f\x12\xb4\xf7\x7c\x98\x9b\x19\x71\x67\x80\xfa\xb6\x0e\x6e\xcb\x97\x93\xb4\xbc\x7e\xd6\x9e\x5f\x70\xfa\x6b\xdb\xa1\x6e\x9b\xd3\x19\x49\x69\xee\xa6\x66\x5a\xbf\xd6\x30\xde\xee\xfa\x3d\x71\x7b\x6d\x25\x4d\xd2\x4b\xc9\x7d\xde\x21\xf0\xf2\x9f\x9e\xd3\x4b\x8b\xd7\xa0\x13\x38\x0f\x4f\x82\xc9\x84\xfd\xbd\x95\xaf\x98\x05\xb7\x44\xbc\xd9\x52\xc5\xa7\x1f\xbb\x57\xd1\x1f\x41\x1c\x18\xcc\x30\xbc\x35\x94\xf7\xad\x82\x28\xcb\x60\x99\x39\x4a\x1b\x6b\x0a\x81\x85\x81\xbd\xf9\x3c\xce\x58\xf3\xa4\xa2\x3e\x55\xdb\x3e\x69\xca\x9d\x60\xcf\xb3\xa9\x07\xfb\x68\x32\x9e\x2f\xfb\x6c\x65\xf1\xe8\x28\xd2\x81\x27\x10\x9c\x9e\x9f\xb7\x01\x60\xf2\xef\x82\xa2\xee\x9f\x9b\xd1\x70\xc5\x1e\x13\xfd\x3f\xc1\x86\x6b\x22\xc7\x9f\xe6\xd5\x10\x12\x17\x97\x9d\xbe\x27\x24\xdc\xad\x8a\x9b\xc6\x9a\xcc\x42\xc1\x12\xdc\x69\x7b\xd2\x71\xee\xa5\x50\xe9\xe5\x04\x06\xbf\xd2\x82\x45\xb8\x3b\x8f\x01\x2d\x34\xdb\x6d\xbd\xd5\x5a\xe6\xe5\x75\x74\x5c\x15\x3d\x6e\x75\x34\x90\x10\x27\xea\xdc\x2f\xcc\x33\xa5\x28\x7d\xdb\xca\x6d\x3a\xea\xb8\x97\x22\x94\xdc\x6c\x71\x2b\x99\x42\x54\x72\x77\x34\x0e\x7a\xd1\x9e"}, -{{0x18,0xa8,0xf9,0x36,0x48,0xcd,0xcf,0x47,0x13,0x36,0x30,0xaf,0x1e,0x11,0xc0,0xce,0xea,0x3d,0xe0,0x73,0x27,0x31,0x4c,0x96,0x58,0x0d,0xf7,0x75,0x59,0x7d,0x7a,0x9c,},{0x29,0x12,0xf4,0x1a,0xb4,0xc8,0x7e,0x39,0x37,0xa0,0x33,0x31,0x80,0x2c,0xba,0x87,0x71,0x6b,0x4e,0xea,0x14,0xb9,0xfb,0xa6,0xf5,0x46,0xd0,0xac,0x2c,0x09,0x73,0xdf,},{0x3b,0x77,0x39,0x4c,0xd6,0x9f,0x8b,0x45,0xd0,0x0c,0xfe,0x3a,0x79,0xa7,0x90,0x06,0x28,0xa5,0x65,0x18,0xb3,0x79,0xed,0x8a,0x11,0x58,0x1f,0xc3,0xa3,0x76,0xe5,0xd6,0x68,0x07,0xdf,0x11,0xe7,0x09,0x04,0xf6,0x96,0xc7,0x41,0xd2,0x1d,0x13,0x93,0x10,0xfa,0x1b,0x89,0xa9,0x3b,0xdc,0x4d,0x2c,0x39,0x97,0x99,0x1f,0x52,0x20,0xee,0x00,},"\x59\x20\x93\xac\x7c\xd6\x71\xd6\x07\x0b\x00\x27\xed\xac\x1f\xb0\x15\xcc\x20\x5d\x78\xbb\x60\x3f\x37\x8e\xb9\xf8\xaa\x38\x8c\xa8\x30\xdb\x3c\xb2\x34\x20\xc7\xe8\x52\xdb\x0b\x55\x24\x1e\xb8\x8a\x02\xcc\x62\x7a\xa9\x41\x43\xbe\x43\x9a\xab\x4b\xf2\x63\x47\x57\x47\x04\x06\xe8\x42\xf2\x0e\xb1\x0f\x07\x00\xe3\xc2\xda\x36\x4f\x58\x8a\x80\x00\xf2\x38\x50\xc1\x2c\xe9\x76\xf3\x26\xd2\xdf\x1b\xac\x13\xe9\x50\x20\xb4\x12\xb1\x75\xbf\x74\xbd\x7e\xbb\xac\xf3\xae\x55\xc0\xda\xeb\xb5\xc0\x10\xbf\x80\x4f\xee\xe1\xd7\xd4\x9f\xae\x05\x0b\xea\x55\x99\x6f\x53\xcf\xe1\xf1\x5a\x0c\xf2\x07\x27\xdb\x4e\xe3\x11\xc2\x60\xba\xd9\x68\x2d\x7b\x96\x5e\x27\xa9\x49\x1f\x47\x1d\x4a\x47\x3a\xff\x64\x6c\x7d\x42\x4d\x5a\x0b\xdc\xbb\x8a\x02\x33\xf4\xb3\x06\x0d\xd0\x4c\x98\xec\x98\xdf\xd0\x5e\xc7\x24\x78\x84\xe2\xd8\xe1\x52\xd4\xae\x52\xb3\xd5\x86\x5d\x9e\xfd\x67\x06\xa6\x0e\x08\x8e\x1e\x7c\x9f\x62\x45\x10\xab\xc7\xa2\x04\x5a\x2c\x7a\x75\x88\xe2\x53\x5e\x73\x19\x1d\xd5\xcf\x05\x42\x15\x63\xf5\x56\xa1\x3e\x82\x36\x67\x03\x43\xcd\x5b\xa4\xd4\x66\xe2\x45\xc4\xee\x3b\x5a\x41\xe7\x0c\x9a\x0f\x5e\x6e\xa2\xc5\x59\xeb\xe6\x1b\xa8\x1e"}, -{{0x20,0x6c,0xd2,0xb8,0x11,0x4a,0xae,0x18,0x8d,0x81,0x86,0x2c,0xce,0xc4,0xcb,0x92,0xc4,0xef,0x5f,0xc7,0x8c,0x24,0x43,0x5a,0x19,0xf9,0xed,0x9b,0x8a,0x22,0xf4,0x7e,},{0x97,0xa6,0x7a,0xc2,0x81,0x1f,0x52,0x94,0x56,0xdf,0x53,0x27,0x37,0xd7,0x6b,0xed,0x7e,0x38,0x7d,0xa8,0x3b,0xd5,0x54,0x59,0x37,0x2f,0xdf,0xb2,0x7f,0xfa,0xcf,0xf3,},{0x73,0xa4,0x0d,0x9d,0xa0,0x8f,0xb9,0x8e,0xa2,0x5b,0x67,0xe7,0x21,0x55,0x7a,0x1a,0x51,0x22,0x52,0x94,0xd3,0x16,0xb5,0x31,0x49,0xaf,0x89,0x5f,0xa4,0xd6,0x3c,0xb4,0xa3,0xf5,0x6f,0x68,0x85,0x66,0xef,0x6d,0xa4,0x2f,0xd2,0x94,0x1d,0xff,0xa0,0x6d,0x49,0x7a,0xa9,0x02,0x16,0x5d,0x50,0x21,0x3a,0x62,0x14,0x11,0x62,0x99,0xa9,0x0c,},"\x48\x0c\x48\x00\xf6\x8c\x79\xf5\xdf\xc0\xc3\x66\x6c\x0a\xc4\x29\xb3\x0f\xe0\xc5\xfe\x84\x87\x50\xdb\x21\x71\x38\x0b\x80\xc8\xe9\xfe\xc0\xa0\x54\xb1\x6d\x08\x67\x4c\xef\xe2\xf6\x4e\xc2\x8b\xb6\xb0\x59\x6b\x35\x23\x55\x75\xf1\x89\xbe\xe2\x59\xac\xa7\x66\xc2\x22\xac\x0a\x46\xcf\x2a\xf7\x57\x74\xda\x4e\x34\xa0\xb5\x4f\xc2\xac\x49\xec\x8b\xed\xf4\x88\x7c\xd9\xb7\xbe\x4f\xdb\x7f\x68\x69\x02\xdd\xfa\xb0\x46\x27\xe2\x6e\xa2\xdc\x3d\x97\xd6\x2a\x4b\x15\x46\x18\x02\x18\xed\x8f\xa1\x13\x33\x48\x19\xb5\x27\x5c\xc5\x4a\xfd\xee\x44\x30\x90\x08\x59\x65\x07\x97\x16\x75\xe6\xd8\xb8\xa8\xed\xec\x47\x18\xf2\xd4\xbd\x73\x52\x13\xcb\xbd\x18\x79\x1f\xaa\x80\x54\x17\x49\x07\xa7\xac\x17\xd7\x14\x3a\x47\x57\xe4\x93\xbe\xee\xc4\x84\x9d\x0b\x83\x6f\x18\xbb\x2b\x3c\x90\x16\xf2\x5a\xf4\x7f\xb9\x61\x99\x25\x17\x20\x54\x9f\x15\xd1\x49\x50\x3d\x41\x09\x5e\x25\xf2\x62\x09\xda\xac\x39\x15\x44\x85\xc3\xde\xd7\xcb\x1a\x8c\x3e\x83\xa5\x2f\x5a\x06\xec\x09\xcf\x83\xdf\x00\x72\x6b\x79\x68\xf6\x4c\x0c\xba\xe2\x99\x51\x2f\xb4\x38\x56\x0f\x04\xb3\xb6\x44\x34\x6f\x93\x8a\xc8\xe9\x04\x86\x61\x4c\xd8\x44\xb5\x4e\xae\x07\x8b\xf6\x78\xb3"}, -{{0x59,0xb1,0x44,0xa7,0x08,0xab,0xec,0x97,0x27,0x29,0xa0,0x4a,0x6c,0x13,0xf0,0xea,0x02,0x0b,0x4e,0xd4,0xa4,0x82,0x98,0x02,0x3a,0x56,0x89,0x58,0xc2,0x12,0x15,0xec,},{0xc4,0xf4,0x72,0x00,0x92,0xed,0x61,0x79,0xa0,0x82,0xae,0x4d,0x61,0x45,0xdf,0x37,0x71,0x78,0x6e,0xfc,0xa9,0xbd,0x9b,0xb7,0x9c,0x9f,0x66,0x67,0xd2,0xcb,0x56,0xb3,},{0x1a,0x80,0x85,0x0f,0xcb,0xd6,0xe6,0x43,0xc6,0xba,0x8e,0xb6,0x84,0xdb,0xef,0x7d,0xf0,0x15,0x15,0x92,0x28,0xda,0xed,0xcf,0x06,0x04,0x70,0x91,0x86,0x05,0x4d,0xb1,0x85,0xaa,0x7b,0xaa,0xcb,0x09,0xd6,0xca,0xad,0x01,0x63,0x8e,0xff,0x8e,0x46,0x87,0x35,0xa6,0x01,0x24,0xde,0x0c,0x53,0x76,0xe9,0x43,0x40,0xe5,0x41,0xa9,0x80,0x07,},"\x38\x57\xbd\x26\x0b\x8a\xad\x9d\x07\x3f\x06\x76\x5d\x37\xfe\x89\x3a\x3f\x53\xe2\x3d\xe8\x66\xdd\xac\x33\x49\x5a\x39\xad\x33\xee\x9e\x9d\x5c\x22\x50\x2b\xc1\xc4\xb5\x47\x0d\x0e\x3f\x3a\x58\x52\x23\xfe\x4c\xb9\x3c\xc4\xad\x2b\x5b\xa6\xd7\x88\x26\xa5\x3f\xc0\x25\x3d\xc5\x80\xa2\x01\x8c\xc9\xff\x1c\xfe\xdb\xd3\xac\x0b\x53\x29\x2d\xee\xfb\xc1\x4e\x58\x9a\xcf\x49\x6c\xb5\xf7\x67\x01\x30\xfd\xbb\x6c\xf3\x8d\x20\x89\x53\xc0\x15\xa0\x47\x46\x75\xb7\x24\xbd\x10\x9f\x7c\xb8\x9c\x33\x01\x67\x51\xfe\x7a\xa7\x85\xd0\x99\xd0\x9a\xb2\x0d\xd5\x25\x8c\xd7\x64\xac\x8d\xaf\x34\x3c\xe4\x79\x0e\xad\x08\x63\xaf\x43\x12\x1a\xa5\x27\xa3\x7a\x11\x62\x8f\x47\x86\x96\x68\xf8\xea\xc0\x0d\x80\xb6\xbf\x99\x06\x66\x3d\x7a\x28\x99\xc1\xcb\x67\x8c\xd7\xb3\xeb\x3b\xc8\x02\x26\xb8\xb1\x3b\x6e\x46\x87\x7f\x38\xf0\x7c\x3d\x9c\x86\xd3\x36\x8b\xaa\xc4\xa6\xf6\xb9\x3c\xce\xbc\xec\x98\x11\x47\x4b\x6a\x6a\x4d\xa5\xc3\xa5\x96\x65\x71\xee\xd0\x5e\xdc\xc0\xe3\xfe\x7c\xd1\x59\x15\xc9\x1f\x44\xee\xe8\xc1\x49\xae\x45\x1f\x37\x55\x18\xa7\x9f\xb6\x00\xa9\x71\xa3\x9b\x94\x33\xdf\xa1\x9f\x91\x93\x1b\x19\x32\x27\x57\x47\xc2\x62\xee\xdc\xbd\x27\xf1"}, -{{0x8d,0x16,0x21,0xee,0xab,0x83,0x27,0x0d,0xe8,0x57,0x33,0x5c,0x66,0x5b,0xbf,0x57,0x26,0xe3,0x72,0x22,0x25,0xfd,0x01,0x6e,0x23,0xbf,0x90,0xab,0x47,0xae,0xec,0x3d,},{0xbe,0xcd,0xbc,0x02,0x4d,0xae,0x6a,0x94,0xed,0x4e,0x29,0xc8,0x0f,0x2a,0xff,0x79,0x6a,0xed,0x8f,0xeb,0x2c,0x1b,0x37,0x90,0xa8,0xc7,0x2d,0x7b,0x04,0x8a,0x2c,0x61,},{0xe0,0x8d,0x6c,0xaa,0x5f,0x39,0x32,0x7d,0x6e,0x66,0x52,0xed,0x74,0xdd,0x1a,0x37,0x84,0x4b,0x97,0x9f,0x5c,0xce,0x74,0x7a,0x60,0x6f,0x56,0x79,0xf4,0x89,0x8b,0xbb,0x76,0x43,0xdf,0x7e,0x93,0x1b,0x54,0xa2,0xb4,0x0e,0xbd,0xef,0xe8,0x30,0x03,0xf6,0x1c,0xa0,0xf1,0x11,0x12,0xf0,0x23,0xc6,0xa3,0xe8,0xcc,0x18,0xca,0xfe,0x5f,0x0d,},"\x97\xfa\xcd\xdc\x82\xcc\xcc\xcf\x78\x8c\x31\xb3\x30\x5e\x93\xeb\xa9\x56\xf8\x96\x13\xe6\xe5\x35\x42\xb0\x43\x26\x7f\xee\x54\x4c\x2b\x0a\x8a\xe8\x88\x6a\x31\xb9\xd3\x21\xa6\x3c\x27\x62\x3b\xae\xfe\xa8\x40\xb2\xa8\xaf\x5b\x23\x30\x19\x3f\xfb\x5b\xaf\x87\x3c\x33\x55\x28\xaf\xea\xe2\x16\x01\x63\xc8\x51\xc5\xa2\xe5\x81\x54\xa1\xb0\x56\x9c\x2d\x13\x66\xc0\x71\x04\x37\x62\x3b\x0e\x08\xc6\x86\xe5\x4f\xc2\x79\xed\x4c\x45\xf3\xe8\x56\x86\x83\x75\xf7\x82\x24\xc7\x77\xb1\x3d\x75\xde\x10\xd7\x91\x73\x55\x24\x25\xd1\x5a\x56\x19\x04\x15\x5f\x21\x17\xb2\xf1\x47\x13\xeb\x0b\x04\x64\x8a\x3b\xde\xb3\x30\x21\x67\xd1\x97\x3e\x78\x8a\x06\xcb\x00\xd4\x8c\xcb\x26\x9f\xa7\x1a\xf8\xba\x68\xea\xe5\x5d\xbb\xfd\x95\x94\xd5\xc2\xb4\xdc\x13\xae\x03\x21\x71\x85\x61\xac\xdf\x67\xdc\x8c\xfc\xc2\x5b\xc4\x6b\xb6\x6e\x09\x6a\x19\x41\xd9\x33\x52\x07\xd3\xf7\xd1\x1e\x89\x04\x90\x4f\xab\xe3\xa5\x0a\x38\x83\xe7\x07\x80\x47\xdf\x25\x2f\x38\xb6\x7c\xd2\x8a\x6a\xc4\x5c\x7d\x7a\x1d\x2a\x1d\xe8\xd4\x57\x47\xcf\x09\x30\x1e\x01\xcd\xaf\xd0\xcd\x99\xa6\xe9\x1b\x70\x4d\x50\x9f\xce\x69\x2f\xbd\xef\x2f\x71\xa5\xce\x0b\x35\xbc\x15\xc6\x5f\x87\x68\x24"}, -{{0xf2,0x73,0x5d,0x50,0xee,0x3a,0x9a,0x65,0xb5,0x8c,0x8a,0xcf,0x55,0x16,0x63,0xe9,0x88,0x09,0xec,0x40,0x6f,0x73,0xe3,0xe7,0xf4,0xe7,0x3b,0xc4,0xea,0x92,0x38,0x74,},{0xdf,0x48,0xa5,0xb9,0x4a,0x07,0xaf,0x3c,0x2c,0x99,0xb8,0x38,0x87,0x62,0x24,0x32,0x33,0xc8,0x50,0xdc,0x17,0x53,0x17,0xd6,0x02,0x63,0x8e,0x5b,0x86,0xab,0x49,0xed,},{0x69,0x42,0xa7,0x69,0x64,0x17,0xef,0xaa,0x59,0x1b,0x95,0xe1,0x1f,0x02,0xd7,0x63,0xbe,0xf5,0x27,0x9b,0x93,0x2a,0x8e,0x2a,0x7c,0xbb,0x9f,0x58,0x36,0x95,0xc1,0x4c,0xe5,0xcc,0x55,0x6b,0xec,0x66,0x79,0x9b,0x33,0xcb,0x59,0x2d,0xa4,0xdf,0x27,0x35,0xf9,0xee,0xf2,0xc3,0xce,0xca,0x43,0x62,0x16,0x4b,0x6c,0xc9,0x3d,0xa4,0xe1,0x05,},"\xae\x31\xe9\x4e\x71\x97\xe4\xe4\xd0\x23\x93\x48\x02\x5e\xd6\x68\x1e\x51\x3c\xe1\xa6\xe0\xaa\x0e\x5b\x97\x93\x73\x91\x21\x50\xef\x11\x3e\x50\xef\x05\x69\xc4\x83\xf7\x56\x8c\x4b\xbc\x47\x03\xc5\xda\xca\xa8\x0a\x0d\xe4\xe7\x38\x38\x3f\xa1\xf1\x0d\x6d\x40\x71\xa3\x1b\x99\xe6\x48\x51\x43\x97\x23\x16\xc8\x65\x22\xe3\x7c\x68\x87\xa1\xc3\x07\xb2\x9b\x0d\xd6\xf9\xf1\xb4\x38\x31\x0a\xf9\xd8\xd7\x34\x6f\xb4\x1f\x9b\x2d\xd2\xe8\x0b\x14\xc4\x5e\xb8\x7d\x4e\xd4\x8e\x37\xa5\x26\x0b\x52\x25\x7b\x3e\x99\x78\x7a\x13\xc5\x53\x92\xba\x93\x0c\x08\xe0\x24\x0e\x96\x0d\xef\x0c\x29\xb8\x55\x07\x45\xcf\x14\x9d\xee\x53\xa5\xd1\x74\xec\x06\x5d\x2d\x66\x77\xde\xe1\xfc\x42\x05\x70\x62\xc3\x4e\x27\xea\x5d\xbc\xdb\x86\x1b\x9f\x67\x0c\x60\x32\xc7\x84\x6c\xec\x8e\x87\xa7\xc9\x52\x0e\x27\x96\x7b\x01\x86\xee\x71\xb7\x7e\xd6\xd0\x29\xbb\xdd\x70\x94\x9c\xec\x4a\x70\x93\x29\xfa\x37\xfe\xe0\x02\x49\x0c\xc1\xbc\x4c\x2d\xf6\xf7\x63\xf9\x85\x8f\x33\xd7\x50\xc5\xb5\x05\xa6\x7e\x23\x70\x63\xc0\x48\x6f\x94\x56\xd3\xc6\x20\xd9\xac\x7c\x98\xf1\x38\x1d\xe0\xef\xfe\x41\xc1\x82\x59\x50\x4a\x15\x0d\x68\xa6\xa2\x8b\x0a\x3e\xea\x80\x3b\x85\x53\x15\xc9\xe0"}, -{{0xca,0xd9,0xd2,0x1a,0x01,0xc7,0xe1,0xd1,0x5d,0xf2,0xfb,0xd7,0x9c,0x51,0x6e,0xb8,0xc3,0x40,0x1e,0x9f,0xe2,0x84,0x67,0xcc,0x7b,0x21,0x67,0x9d,0x4e,0x33,0x1a,0x3d,},{0xa7,0xb5,0x5c,0x15,0xd6,0x79,0x0b,0x40,0x53,0x6f,0xca,0xe5,0xad,0x28,0x92,0xcd,0x66,0xb1,0x86,0x89,0xf4,0x99,0xc1,0xfd,0xee,0xa6,0x6d,0x4a,0x7d,0xf3,0x94,0x24,},{0x31,0x92,0x7d,0x01,0xdb,0x9f,0x24,0x72,0xf4,0xdf,0x6f,0x63,0xc1,0x8e,0xbd,0x83,0xc2,0xb1,0xaa,0xf8,0x8d,0x58,0x0e,0x84,0x88,0x54,0xdf,0x8c,0xba,0x63,0x95,0xd3,0xda,0x7b,0xd6,0xbb,0x9e,0xdc,0x1f,0xce,0x1c,0x7d,0x7e,0x13,0x60,0x55,0x8f,0xcd,0xdf,0xa9,0x39,0x15,0xbe,0x07,0x6e,0xfb,0x8e,0xa2,0xdc,0x5e,0xa7,0xb2,0x0d,0x0a,},"\x70\x70\x2b\xf1\x9c\x91\x9f\x98\x36\xde\xfd\x7b\x84\x6f\xd9\x99\x2d\x8b\x7e\xb2\xe1\x06\xae\xb7\x1e\x60\xa3\x1b\x4e\xa2\x5a\x41\xb2\x12\xdc\x7d\xe7\xc9\x1c\xbd\x61\x3d\x58\xd0\x59\x5d\xb8\x33\xcf\xe7\xe5\x05\x84\xf2\x55\x69\x60\x2c\x77\x44\xfa\x67\x5d\x15\x6d\x0f\x63\xcd\x2b\x7c\x08\x9c\x8a\x00\x68\x6a\x43\x71\x69\x82\x6a\x12\xdc\x48\x5b\x38\xc0\x68\xa8\x00\x71\x42\xe5\x16\x37\x47\x01\x1a\x07\xa4\x15\x68\x36\x22\xab\x1e\x23\xce\x57\x7c\x73\x2b\xa1\x4f\x40\x1f\xbc\x30\x43\xe0\x69\x3a\x92\x05\xc1\x9a\x92\x29\x8a\x3d\x9b\x08\xfb\x7a\xfa\xfa\xe0\xa9\xf0\x16\xbc\x75\x0e\xe6\x31\xa5\xf5\xda\x5d\xb6\xf9\xba\x26\x92\xc7\x4c\xaa\xae\xb4\xd0\x97\xe9\x0e\x3c\x02\xd2\xe3\xa7\xfb\x3a\xa0\x00\x04\x0b\x7c\x17\xb7\x45\x64\xe6\x46\xbe\xa1\x6b\xad\x61\x1e\xbc\x08\x59\xa3\x82\x88\x04\xab\x4f\x5c\xfb\xa4\x17\xd2\x54\x51\x5c\xa3\x62\x0a\x3a\xd6\x83\xc4\x6c\xa6\x26\x7b\xb4\x95\x39\xbb\x30\xe3\x69\x08\x7e\x67\x43\x8e\x94\x89\x56\x27\x50\xdc\xcb\xa3\xaa\x0b\x1b\x0a\x6c\x26\x70\x32\xd2\x0c\x2a\xdb\x75\xe6\x8d\xf1\x12\x3b\x52\x59\xbf\xe4\xea\xc6\xca\xdc\xa6\x77\x81\x38\xa3\x73\x18\xad\xb3\x0e\x8d\x66\x9f\x3b\xc9\x69\x2c\xc7\x4b\x68"}, -{{0xd9,0xbe,0x84,0x22,0x55,0xe9,0xa1,0x6b,0x0a,0x51,0xa8,0x67,0x42,0x18,0xce,0xe7,0xcd,0x9a,0x8b,0xdf,0x34,0x35,0x08,0x39,0x7f,0x4d,0xdb,0x05,0xf3,0xfa,0x00,0x82,},{0x79,0x31,0xbc,0x6d,0xfa,0x33,0x24,0x94,0x3a,0xab,0x18,0x3d,0x12,0x85,0x51,0x59,0x19,0x39,0x9f,0xfe,0x0b,0x71,0x06,0x77,0xf0,0x91,0x5d,0x3a,0x5b,0xe5,0x1e,0x92,},{0xc9,0x38,0x45,0x65,0x8c,0x95,0x60,0xd2,0xc0,0xe2,0x8f,0x28,0x2a,0xdb,0xd4,0x65,0x2b,0xaf,0xd3,0xbb,0x2e,0xde,0xc1,0x7c,0x94,0x87,0x8f,0x7b,0x94,0xd3,0xc7,0x7a,0xfe,0xc9,0x06,0xed,0x29,0x2a,0x8d,0xfb,0xf5,0xf8,0xe7,0xc1,0x18,0xe8,0xf2,0xca,0x33,0xdd,0xa7,0x90,0x9d,0x9b,0x69,0x5b,0x8f,0xf5,0xa1,0xc0,0xe9,0x7a,0xc8,0x07,},"\xac\x6c\x55\xb1\x34\x66\x3e\x41\xf0\x2a\x6d\xcb\x85\x49\xea\xa1\xc0\x13\xf5\x96\x58\xd8\x1d\x81\x2f\x95\xb7\x40\x09\x51\x37\x23\x67\x19\x45\xe1\x32\x4f\x90\xf8\xa3\xf9\x71\x36\x91\x81\xb5\x87\xba\xb4\x56\x65\xf7\x88\xd6\x63\xab\x78\x14\x0c\x5a\x22\xc1\xc1\x8d\x4a\xfe\xdc\x74\x48\xa7\x48\xaf\xe5\xbf\x23\x87\x00\x3c\x1d\x65\xab\x18\x48\x2e\xf9\x89\x22\xb4\x70\xda\x80\xad\x14\xc9\x44\x95\x1c\xe4\xae\xd3\x73\x90\xcc\xe7\x9a\x8e\x01\xb2\x4c\x7d\xfc\x11\x41\xc0\xec\xa2\xc7\xf7\x73\xed\x4b\x11\x80\x6a\x34\x61\x55\x13\x48\x6e\x4e\xe1\x1a\xf0\x80\x78\xa1\xb4\x05\x4c\xf9\x88\x02\x98\x60\x8d\xd9\xb3\xfa\xa1\xa2\x42\xa4\x52\xfe\x51\x16\x04\xb3\x10\x2c\x31\x3d\x14\xcc\x27\xc6\xf0\xf8\x47\x1d\x94\x55\x53\x17\xea\xa2\x64\xcd\xf5\x2c\x69\xe1\x8f\x46\x1e\x47\x90\x3d\x21\x29\x87\x16\xb1\x72\xee\x9c\xb1\x78\xf0\x8f\xf2\xd3\xc9\xc1\x62\x12\x1c\x2e\xd2\x1d\x87\x34\xb2\xf0\x63\x0d\x39\x91\x46\xcb\xf7\x6e\x02\x8a\x14\x3f\x2b\xf7\xbb\x50\xaf\x0f\x57\xb9\xba\x80\x21\xd2\x64\xb0\x0c\x66\x62\xf8\x4c\x86\xcb\x6d\x59\x52\xb3\xd2\x41\xf7\xdc\x3e\x70\x0c\x96\x61\x6c\xbc\xfb\x0d\x0e\x75\x3f\xfd\x5d\x21\xee\x32\x0e\x65\xe9\x7e\x25\xcb\x86\x09"}, -{{0xcf,0xc4,0x8c,0xc6,0xf6,0x58,0x11,0xfe,0x7d,0x7b,0xba,0x85,0xd1,0xcd,0x84,0x85,0x8f,0xd6,0xf7,0xed,0xd6,0x38,0xf4,0xf5,0x52,0x36,0x3e,0xe7,0x68,0x5f,0x69,0xca,},{0xd2,0x9c,0x10,0x69,0x4c,0x5e,0x8e,0x3f,0x34,0x47,0xed,0x78,0xd3,0x4d,0xbd,0x74,0xa2,0xb3,0x01,0x37,0x3b,0xa8,0x71,0xb5,0x85,0x0c,0x33,0x3d,0xff,0x7b,0xf8,0xd0,},{0x80,0xc5,0xd5,0x1e,0x96,0xd1,0xca,0xc8,0xef,0xd3,0x45,0x98,0x25,0xe7,0x9c,0x1e,0x9f,0x65,0xaf,0x70,0x1d,0x1d,0x29,0xe1,0xf9,0x5b,0x03,0x67,0x07,0x11,0x3b,0x77,0x98,0x4b,0x7b,0x33,0x50,0xf0,0x40,0x77,0x33,0x3c,0x95,0x7f,0x8f,0xbc,0x7d,0x9b,0x04,0x0c,0x36,0x26,0x51,0x41,0x7b,0x98,0x99,0x02,0x7c,0xd3,0x3e,0xdb,0x11,0x03,},"\x8e\x7d\xef\xb9\xd1\x6d\x03\x6b\xd6\x42\xcf\x22\x6e\x32\x77\x3e\x60\x53\x61\xc5\xec\x4b\x95\x12\x55\x78\x8d\xb0\xa0\x42\xc6\x3e\x5a\x43\x67\xd6\x15\x24\xf1\x0e\x62\x58\x99\x13\x25\xa3\x9a\xb6\xb0\x36\x12\x26\x0c\x3f\xe3\xdf\x20\xb3\x42\x02\xd3\x43\x95\xbd\x4e\xd4\x0b\xd6\x13\x73\xdf\x78\x1a\x4c\x8b\xcf\xbd\x15\x30\x10\x60\xf0\x74\x37\x73\x23\x33\xd8\xe4\x97\x36\x32\x2d\xee\x6b\x22\x43\x8e\x78\x7d\x88\x56\xb7\x0c\x26\xec\x57\xd6\xda\xde\x9c\x3c\x28\xe2\x72\x20\xc5\x67\x0e\x39\x35\x44\xed\x09\x59\x37\x29\x8d\xc3\xad\xc7\x38\x65\xf7\x77\xe9\x00\x37\xbd\xef\x83\x47\x16\x47\x6d\x78\xf4\xe6\xcb\x49\x61\xa4\xc6\x8a\x8a\x83\x63\x38\xa9\xf5\xda\x17\x9c\x4d\x5e\x93\xc3\xf7\x0d\xd3\x5e\xec\x70\x96\x53\xdd\x8d\xe3\x79\x96\xb1\x20\x56\xd4\xee\xfc\xb4\xb6\xb3\xc1\x3b\xa9\x84\xd8\x32\x27\x5c\x43\x86\xeb\xf4\xa8\xff\x7f\x07\x8b\xe3\xd4\x28\xc1\xe0\xd9\xb1\x62\x38\x1f\x06\xa5\xb7\xbb\x12\x70\x40\x03\xd9\x1f\x25\xd1\xd8\xfd\x43\x62\x6c\xe7\x0f\xff\x59\xd2\x92\x77\x68\xa7\x6b\xf7\xf9\xef\x76\xff\x95\x48\x9f\x38\xed\xcd\x1c\x9e\x9b\x8a\x8b\x0e\xf6\x6c\x32\x80\x57\x76\xd5\xae\x9f\xbd\x84\xa7\xaf\x4f\xa6\x56\x3e\xc7\x0a\xc5\x73\x3a\x44"}, -{{0x15,0xc9,0xf7,0xc4,0xd8,0x4a,0x5a,0x47,0x90,0x41,0x95,0x2e,0x6a,0x8c,0xac,0x24,0xe7,0x6f,0xd2,0xd2,0x75,0xc1,0x97,0xe6,0xb5,0x21,0x92,0x9b,0x43,0xba,0x6c,0x5d,},{0x86,0x33,0xc1,0x82,0x9d,0x29,0x09,0x1d,0xf7,0x1f,0xd5,0xc0,0xef,0x64,0x05,0x72,0xe4,0xb6,0x49,0x74,0xcd,0x09,0x7d,0xbe,0xbb,0xcd,0xde,0xba,0x04,0x16,0x47,0xc0,},{0x1e,0x36,0xbe,0xa5,0xa5,0x83,0x76,0x7e,0xbd,0x80,0x30,0x6c,0xab,0x23,0x31,0x55,0xb7,0xb4,0x28,0x14,0xb4,0x34,0x73,0xcf,0x45,0xcd,0xc5,0x03,0x9c,0x93,0x97,0x44,0xa9,0x69,0x4b,0x87,0x22,0x0d,0xaf,0x4c,0xcd,0x29,0xf2,0x5c,0xea,0x40,0x5e,0x7c,0x08,0xdb,0x2e,0xf1,0x7f,0x3f,0x03,0x4d,0xbb,0x49,0xcf,0xf6,0x02,0x83,0xe3,0x06,},"\x11\x73\x0d\xd4\x5d\xda\x80\xd8\x4d\x08\x0d\x92\xe9\xbd\xda\xee\xa6\x87\x8e\x4a\x0b\x3b\x51\x2d\x9e\xa7\x33\x80\x8e\x1c\xef\x51\xd4\x90\x48\xd6\xc7\x81\x16\xa4\xbd\xe3\xc6\x4a\xce\xaa\x52\xbe\xca\x86\xb3\x31\xab\x59\xe9\x18\x5c\x70\x28\x6a\x02\xbb\x5d\xd0\x4f\x5c\x7f\x4e\x9c\x7e\x44\x5e\x77\x45\x85\x65\xf1\x59\xc7\x83\xdf\xd4\xd9\x76\xa9\x10\xe9\x37\x78\x9d\x21\x41\xd4\x16\xed\x3a\x7f\x60\x8d\x26\x73\x7a\x86\xb2\x0b\x62\x4e\x3c\x36\xaf\x18\xd2\x5c\x7d\x59\xb8\xd7\x42\x7e\xc6\xc4\xd3\xd4\x38\xd7\xae\x09\x49\xdd\x7d\x74\x8c\x1f\xfd\x6f\x28\xe8\x28\x5d\x44\x04\x22\xd2\x2a\x37\x61\x20\x2e\x95\x84\xf5\xcd\xb3\x50\x45\x47\xaa\x4b\x68\x57\x30\xc9\x82\xcb\xa2\x13\xde\x08\x02\x0a\x5e\x4e\x46\xa9\x5f\xac\x4b\x48\x1b\xea\x0b\x63\x0a\xbd\x03\x0d\xdd\x33\x5a\x20\xfe\x2c\xf7\x09\x4a\xef\x48\x13\x95\x69\x91\x91\x3c\x68\x21\xf4\xb5\x41\x0d\xf4\xf1\x33\xfe\x63\xe2\x2c\x08\x09\x2a\x0a\x65\x97\x27\x22\xa2\x7a\xe4\x20\x11\xa8\x07\xc3\x27\xb4\x17\x23\x7c\x54\x01\x14\xee\xcb\x9f\x0e\x96\xcd\xa5\xdc\xf0\x24\x6f\x1d\x27\x17\xf4\x9b\x9c\xea\x9d\xc6\xa3\xda\x9b\x39\x6f\x02\x70\x52\x92\x26\xf5\xdc\xba\x64\x99\x91\x8a\x6c\x28\x9f\xe0\x55\xfe\xc8"}, -{{0x6d,0x2d,0x0d,0x82,0x3f,0x29,0x47,0x46,0xb9,0xa5,0x51,0x2e,0x14,0xe7,0x3c,0x1d,0x85,0x5b,0x5e,0x4b,0xca,0x65,0xfe,0x81,0x77,0x29,0x81,0x0c,0xc5,0xef,0x84,0x0d,},{0x1b,0x64,0x80,0xa6,0xa9,0x0d,0xfb,0x47,0x29,0x84,0x85,0x5c,0xef,0x6f,0x1a,0xb3,0x1e,0xb7,0xb3,0xf1,0x3c,0x8a,0xc0,0x0f,0xa5,0x56,0xd2,0x0b,0x53,0xe5,0xae,0x17,},{0xb5,0x15,0xf4,0x9e,0xb3,0x2a,0xd4,0x78,0x69,0x2d,0xf8,0x8f,0x07,0xb7,0x80,0x2c,0x6e,0x0e,0x53,0x27,0xaa,0x08,0xa6,0x36,0x6e,0x4c,0xb1,0xd1,0xe2,0x6f,0x9e,0x65,0xfc,0x81,0xab,0xeb,0xe2,0x21,0x5d,0x64,0x91,0x00,0xf2,0x75,0x98,0x27,0x3a,0x41,0x2b,0x62,0x4e,0x84,0x2d,0x81,0x30,0x40,0x37,0x97,0xe5,0x7d,0xec,0x97,0x5a,0x0a,},"\x87\x72\x72\x1f\x72\xea\xf7\xf7\x30\x40\xc0\x68\xa7\xc3\x75\x3b\xff\xca\x7d\xc2\xd0\x93\x0c\x65\x25\xf4\x25\xe6\x00\x5c\x25\xcd\x4c\x0f\xf5\x09\x5c\x9c\x61\xa5\xd8\xa1\x96\x7b\x8c\x86\x01\x0c\x88\x4e\x50\x9e\x6b\x16\x70\xf7\x90\x46\xe2\x29\x79\xeb\xd3\x54\x73\x40\x90\xd3\xad\xa2\x14\x35\xc1\xf8\x25\x4f\x7b\x52\x22\xcd\x55\x64\xf0\x64\xe9\x77\x64\x03\x66\x44\x9f\x4e\x50\x08\xf8\x70\xf9\xc4\x84\x05\x65\xbf\x4f\xb5\xf5\x74\xc9\x77\x4b\xa2\x56\x8e\x71\xa9\xcc\xd8\x2f\xfc\x59\xb6\x94\xf2\x6e\x7d\xe4\xce\x2e\x3f\xd8\x80\xa0\xee\xf3\x87\x93\x13\x33\xed\xe0\x0d\xcb\x06\x5e\x6d\x0f\x79\x59\x1a\x2a\xa9\x56\xdf\x19\x48\xa2\x65\xcb\x95\x75\x0d\x8a\x23\x3b\x15\xc2\x88\xa0\x54\x87\xc5\x15\x66\x3f\x93\xe7\x40\xfb\x15\x70\xfb\xe4\xbd\x80\xc6\x8e\x8d\x92\x97\x34\x5a\x8a\x01\xcd\xbd\x88\xf4\xa3\x9b\xed\x9c\x5e\xf0\x9f\x14\x4b\xce\x5d\xe5\x68\xbf\x37\x33\xbc\x53\xb2\x03\x9a\x29\xcb\x3e\x19\x45\x01\xad\xc1\xc1\x0e\x86\x38\x3a\xac\x8b\x0f\x85\xc6\x7a\x66\x89\xbb\xe1\x47\x0a\x39\x24\x76\x31\x34\x39\xca\x88\xd9\x8c\x02\x1c\x0e\xae\xc2\x5f\xb2\xf9\xa1\x60\xce\x5c\x78\x61\x70\xbe\x02\x38\xfb\x87\x85\xdd\x33\xbf\xa9\x05\x9a\x6c\x37\x02\xd0\xde\x05"}, -{{0xc0,0xcf,0x79,0x9a,0xf7,0x39,0x5b,0xf2,0x7b,0xaf,0xa3,0x6c,0xab,0x43,0x70,0x45,0xe3,0x9c,0x90,0x3b,0xf8,0x07,0x54,0x83,0x19,0xce,0x44,0xf2,0x87,0x49,0x4f,0xbb,},{0xaf,0xbf,0x55,0x0c,0xa2,0x90,0xc9,0x05,0xbd,0xd9,0x2f,0xc8,0x83,0x1e,0xbe,0x3d,0xfe,0xb6,0xda,0xae,0x4f,0x56,0x00,0x52,0x53,0xcc,0x50,0x95,0x1e,0x50,0xed,0xc2,},{0x5b,0xba,0x01,0xa4,0xc7,0xb2,0x55,0x42,0xd0,0x69,0x12,0xde,0x70,0xaa,0x1e,0x22,0x04,0x23,0xfd,0xf8,0x33,0x8a,0x9e,0x69,0x33,0x95,0xcb,0x6f,0x0d,0xc1,0xfb,0xfd,0x01,0x8e,0x3c,0x77,0xe5,0x0a,0xef,0x90,0xa9,0x08,0x0f,0x30,0xf1,0xf5,0x79,0x2b,0x24,0x31,0x07,0x8f,0xe6,0xe3,0xe0,0x04,0x64,0x24,0x5e,0x17,0xcd,0x8d,0xc1,0x07,},"\xdb\xe6\x57\x80\xe9\x68\xde\x9e\x40\xff\xb5\x7c\xf5\x9a\x60\xfd\x93\xb3\xf9\xa5\xe7\xd8\xed\x51\x80\xad\xbc\x57\x8c\xa1\xbc\x48\xbd\x9f\xb6\x0a\x13\x24\xc9\xc2\xc1\x14\x14\x79\xa0\xdc\xf0\xf1\xd0\x7e\x84\x93\x65\x26\xdf\x42\x33\x3c\x0d\x77\x3e\x3f\xed\x9e\x40\x38\xde\x5b\x95\xad\x90\x5c\x92\xcb\xe0\x40\x48\x7b\xf5\x5e\x10\xe1\xed\xb4\x29\xa0\xec\xc4\xe0\xe8\xd0\x0a\x98\x8a\x9c\xd5\x3e\x2e\xb3\x72\xf4\xfc\x4c\xd9\x53\x7b\x26\x9b\xa3\xa2\x3c\xef\xbc\x8d\xf6\x47\x6e\x75\x43\x4b\x81\xd9\x3e\x88\x91\xbf\x41\x7c\x82\xe3\x63\xf3\xe4\xab\xf8\x0a\x4f\x73\xac\xa8\x4a\xc7\xdf\x63\x37\xf5\x36\xd6\x3d\x93\x9d\x92\xcb\xa6\x4b\xe7\x42\x22\x11\x16\x06\x9e\xf2\x51\xab\xba\x0b\x00\xaf\x01\x71\x8b\xb5\x80\xdd\xbe\xb7\x99\x73\xef\x10\xa6\x8b\x4d\x0f\xa0\x23\xd6\xeb\xd3\x07\x9d\x6b\x32\xa1\xaa\x20\xa2\x1e\x92\x02\xf2\x75\x90\xc3\xf0\xc0\xcc\x25\x30\x73\xc3\xf8\x22\xaa\xc4\x59\xd3\x9f\x50\x75\x8b\x70\xc0\x07\x10\xa3\xc9\x84\x38\x41\x65\x08\x52\x2e\x51\x2a\xda\xa0\xaf\xd5\x03\xa7\xce\xb0\x4f\xb9\x4a\x4a\x93\x2c\xe8\x0c\xd5\xa7\xf1\x1b\xb8\x61\x26\x3f\x58\xe5\x74\x9d\x54\x2a\x11\x0d\xe7\xc7\x68\x9d\xfc\xb0\xc5\x1a\xfa\x9d\x54\xa5\x8f\xf8\x9f\x3f\x67"}, -{{0xcd,0xaa,0x50,0xe8,0x52,0x7d,0xc7,0xa5,0x0f,0xb3,0x7e,0x28,0xfa,0x8b,0x95,0x68,0xc3,0x7e,0x85,0x67,0xe0,0xb4,0x99,0x99,0x7b,0x9a,0xed,0x67,0x61,0x80,0xc3,0xb0,},{0x7c,0x56,0xe1,0x64,0x51,0x02,0x68,0xc1,0x82,0xb4,0x23,0x74,0x79,0x04,0xf1,0xd3,0xa5,0x80,0x93,0x30,0xf6,0xe1,0xb2,0x92,0x66,0xec,0x46,0xe7,0x3b,0xe1,0x55,0x0f,},{0x13,0x7b,0xd1,0x0a,0x50,0xef,0x60,0x93,0x84,0xfe,0x66,0x87,0x68,0xfb,0x87,0x1d,0xe7,0x41,0xca,0x0f,0x53,0xff,0x84,0x77,0xd7,0xeb,0xfa,0x90,0xaa,0xfd,0x5e,0x26,0x81,0xfd,0xf1,0xb8,0x92,0x50,0x46,0x3c,0x15,0xdb,0x8e,0x17,0xa5,0x88,0x25,0xfe,0x94,0x27,0xde,0x08,0x9c,0x34,0xde,0x13,0xcd,0x07,0xbb,0xa1,0x8d,0x4a,0xa4,0x0d,},"\x94\xfc\xfb\xaa\xa3\x03\xde\xce\x7b\x90\x8f\x87\x4c\xc5\xf0\x95\x06\x1f\x17\x54\xbb\x35\x78\x0d\xb6\x66\xb6\x3a\xb8\x29\x08\x11\xbf\x1c\x52\x1a\x7f\x8f\x78\x5e\xa2\x70\xdf\xb3\x9d\x0d\x6e\xd9\x5a\xb7\x19\x55\xa1\x1f\xfa\xea\xa2\x68\xe0\x81\xff\x3e\x4f\x24\x25\xb4\x18\x80\xa9\x87\x15\x1e\x67\x8e\x89\x11\x13\x50\x94\x2d\x82\x0c\x3e\xec\x36\x21\x24\x26\x66\x3b\xe1\x75\xe5\x28\x6b\x4a\xd1\xcc\x80\x4e\x3e\x3a\x03\xb9\xfa\x3e\x82\x83\x8e\xbb\xc2\x61\x5a\x64\x5f\x2c\xa1\x46\x8a\xc4\xa1\xcd\xbe\x52\x37\x61\xe8\x3f\x43\x81\xb0\xc8\x55\x0a\xe5\xe8\xc8\xcd\x1f\xda\x57\x19\x14\x36\xe2\x7c\xb8\x83\xbc\x64\xbe\x86\xa9\xdc\x61\x10\xef\x34\x01\xd8\x8a\x7d\xeb\xd1\xb7\x01\xd9\xc2\x57\xa6\x82\x6c\xf0\x1e\x9e\x29\x22\xe3\xae\x57\x7f\x28\x34\x27\x5f\xb0\xec\xda\x80\xed\x8c\xf1\x80\x1e\x0b\xc5\xe0\x1e\x26\xa7\x7c\x48\xbd\xf4\x6a\x5c\x48\x94\xd2\x2a\xb5\x3e\x74\x18\x27\xe2\x4b\xed\x5f\x07\x50\xff\xad\x05\xe5\x3f\x1d\x5e\x61\xdf\xd3\x16\xb1\x91\xd9\x79\x7e\xf7\x13\x13\x1a\x8b\x43\x0a\xbe\x3f\xac\x5f\x3c\x4a\x2c\xa0\x21\x87\x8b\x15\xad\xc8\xc5\xf5\x42\x11\x42\x60\xe6\x87\xa9\xd1\x99\xd2\x30\xc4\xe0\xd3\xfc\x69\x69\x93\xb5\x9c\xcf\xa3\xff\xa9\xd8\xd2\xfb"}, -{{0x0f,0xde,0xa9,0xbe,0xe6,0x28,0x8f,0x94,0x7e,0x0a,0xdb,0xdd,0xa4,0xdf,0xb2,0xba,0xa0,0x38,0x91,0xaf,0x25,0x02,0x4a,0x5e,0x13,0x8a,0xc7,0x79,0x84,0xd0,0x05,0x07,},{0x70,0xab,0xd8,0x64,0x30,0xd7,0xe8,0xd6,0x32,0x09,0xc8,0xb3,0x73,0xec,0x4e,0x4b,0x79,0xe9,0x89,0xe6,0x72,0x5f,0xac,0xef,0xba,0xde,0x3c,0x75,0x74,0xd2,0x3c,0xd0,},{0x80,0xc4,0x2d,0xd5,0xdf,0x03,0xb2,0x85,0xa8,0x6a,0xc9,0x5c,0xe6,0x66,0x9f,0x78,0x6a,0x97,0x8a,0x81,0x3a,0x9d,0x7b,0x8c,0x6a,0x23,0xde,0x76,0xfb,0xd0,0x9b,0xdb,0x66,0xc5,0xdd,0x1c,0xc9,0xf1,0xa1,0x76,0xcb,0xa3,0x88,0xd5,0x05,0x17,0x64,0xa3,0x2f,0xa2,0x7f,0x00,0x28,0xba,0x48,0x98,0x06,0x8b,0xd0,0x1a,0x3e,0xe1,0x72,0x08,},"\xcf\x72\xc1\xa1\x80\xa2\xbc\x37\xd8\x47\x8d\x9a\x7a\x39\xac\xf0\x3b\xf2\xa5\x07\x90\xf7\x90\x2f\x81\x12\x12\x22\xd3\x1d\x3e\xc9\x16\xf4\xf2\x4c\xef\x9d\x7c\x41\xdc\x02\x1b\x0e\x84\x87\xbb\x89\x2e\x47\x30\x5e\x54\x52\x03\x03\xe8\x9b\x30\xb2\x63\xda\xc4\xa9\xba\x37\x5d\x46\xc4\x0f\xcf\x40\x05\x35\xc9\x59\xd2\xb7\x46\xa7\xfc\x97\x0c\xf6\x5b\x47\x2e\x84\xb5\xf1\xd0\xeb\xad\xcf\xa1\xae\xd6\xfc\x47\xfa\xcc\xe1\x6a\x36\x6a\x3b\x1d\x6e\x51\x68\x13\xc1\x96\x09\x75\xf8\xf2\xb4\x30\x42\xfb\x4e\xea\xab\xe6\x3c\x6f\x65\xdb\x45\xdd\xb7\xdb\x88\x8a\x19\xa9\xd7\xba\x6c\xa4\x79\xfc\xd7\x0c\x5d\x1e\x97\x0f\x12\xc1\x4f\x4d\x24\xfb\x7e\x2f\x35\x7b\xd3\xa9\x4a\xa1\xb8\x68\xcc\xc0\x84\x7f\x2e\xef\x21\x85\x3e\x25\x3b\xaf\xbf\x07\xc4\xe6\x17\x6a\x1e\xf0\x77\x16\x78\x41\xeb\xbe\x56\x29\x33\x71\x57\xf3\x9f\x75\xc7\x1d\x21\xe7\xe9\x6c\x51\xa1\xb1\x6f\xa8\xdc\x60\xf0\xb1\x27\x9f\xcd\xa2\x64\x1f\xc8\x59\x1e\x3c\x49\x2f\x15\xbf\x83\xca\xf1\xd9\x5b\x2c\xd9\x13\x32\xf1\xb4\x20\x2f\xe7\x28\x62\xca\x2e\xa2\xef\x92\xc1\x1d\xb8\x31\xd8\x2f\x8f\xc3\xd4\x1f\xe2\x9a\x76\xc2\x11\xa7\x58\xe2\xf7\x1b\xd8\x9d\x2c\x66\x10\xf2\x01\x42\x9f\x34\x8d\x56\xe1\x0e\x3b\x7a\xf5\x3e\x27"}, -{{0x03,0xd5,0xe4,0x66,0xf8,0x29,0x8a,0xb5,0x43,0x8a,0x30,0x97,0x6d,0x13,0x22,0xa7,0x21,0x5a,0x64,0x2d,0xd5,0xfb,0x4c,0x3f,0x85,0x19,0x40,0x9a,0x75,0x22,0xf0,0x92,},{0x4b,0x3e,0xd4,0xdb,0x08,0x0e,0x2a,0x45,0x2e,0x16,0x91,0x2c,0x14,0x50,0x44,0x24,0x92,0x0a,0x60,0x97,0x56,0x04,0xe4,0xf3,0x79,0x25,0x8d,0x1c,0x8b,0x19,0x3d,0x6f,},{0x6d,0x7e,0x46,0x58,0xf2,0x6f,0x33,0x7c,0x98,0xe0,0x3f,0x13,0x54,0x2e,0x2f,0x39,0x44,0x0f,0xf7,0xbf,0x8d,0x88,0xf3,0xf6,0xdf,0xa4,0xd6,0x49,0x48,0xcd,0x96,0xb7,0x90,0x51,0x49,0x2f,0xc2,0x8f,0x65,0xf2,0xcc,0x0d,0x23,0xa0,0xc4,0xd5,0xe2,0x30,0x7b,0xb1,0xc4,0x7e,0x11,0xe5,0x3b,0x37,0x1f,0x09,0x1b,0x69,0xf8,0x0d,0xbd,0x05,},"\x1b\x47\xb7\x00\x13\xcb\x53\xe1\xf8\xf4\x97\x1e\x0f\x39\x56\x3c\xe8\x7e\xdb\xc2\xce\xdd\x99\xe5\xa3\x55\x85\xdf\x8b\x00\xa8\x52\xf7\xb9\xc9\x7c\x7e\x4a\x54\x65\xfc\x56\x05\xae\x8c\x5c\x36\x57\x0a\x99\x20\x1a\x7a\xd6\x03\x12\x87\xef\x0c\x7b\x2b\xa6\xe5\x7b\x05\x6d\x0f\xc8\xd6\xca\x43\xbf\x6c\xbd\xab\x09\x89\x34\xb4\x03\x19\x7b\x52\x5d\x22\xd4\x5e\x6b\x29\xc7\x8f\x8d\x61\x83\xe4\x1f\xfe\x19\x7d\xae\x25\xba\x22\xb0\x66\x69\xae\x05\xba\xdd\x7e\x1d\xa6\x93\x2a\x7d\x05\x4c\xba\xb3\xf5\x4e\x51\x46\x22\x3a\xd8\x67\x12\x31\xbc\x16\xfe\x62\x67\x9b\xd2\x81\x7a\x6b\x80\xe6\x53\x99\x8c\x49\x49\xf8\x1f\xf5\x3b\x61\x73\x16\x3e\x11\xda\x3e\x6d\x3c\x76\xd8\x4c\x71\x32\x25\xb4\x17\x3d\x6b\xf0\x6a\x85\xb6\x98\x8a\x48\xbe\x43\x59\xcb\x51\x55\x03\xca\x56\x3f\x43\x53\xf8\xe7\xd4\x5e\x4d\x94\x46\x2c\x89\xa0\x4a\x00\xf1\xb3\xb0\xca\x64\x22\xd5\xdb\x02\x9c\x50\x7d\x46\x48\x34\xa2\x0c\x78\xa7\x13\x66\x1d\x84\xed\xff\xc4\x96\xd6\x92\x82\x61\x98\x94\x43\x7b\x44\x87\x95\x4c\xbe\xa2\xaa\x72\x61\xe6\xa6\x2b\x68\x51\x15\x4a\x5d\x25\xfb\x6b\x4f\x09\xc5\x94\x73\xd3\x85\xce\x03\xe9\x1b\xa8\x65\xea\xb6\x6c\x58\xc0\xab\xb0\xb7\xa7\x8e\x4b\xe9\x27\xe5\x54\x60\xcc\xd7\x0d\x82"}, -{{0x76,0xcc,0x18,0xa1,0xda,0xff,0xfa,0x10,0x05,0x86,0xc0,0x6a,0x7b,0x40,0xf7,0x9c,0x35,0xfe,0x55,0x8c,0x33,0x9c,0x29,0x99,0xa5,0xf4,0x38,0x75,0xcf,0xad,0xe0,0x3e,},{0x4b,0x9d,0xa8,0xd2,0xf1,0x37,0xdc,0x6c,0x85,0x7a,0x99,0xa5,0x99,0x8d,0xd8,0x9d,0xd5,0xf0,0x59,0x71,0xa2,0x1e,0x8c,0x77,0x66,0x70,0xeb,0x47,0xbc,0x12,0x70,0xa5,},{0xdb,0x74,0x75,0x1c,0x66,0xe6,0xb1,0x86,0x60,0x44,0xdd,0x9a,0xe9,0x9f,0x19,0xe6,0x33,0x4f,0x17,0x9e,0x79,0xd8,0xb8,0xe0,0xc8,0xcd,0x71,0xd2,0x2c,0xef,0xb9,0xea,0xb7,0xe3,0xe7,0xa9,0xc2,0xda,0x22,0x5f,0x2a,0x9d,0x93,0xa3,0x13,0xd1,0xcb,0xf1,0xb7,0xfe,0x25,0x97,0xb8,0xd7,0x02,0xbf,0x30,0x17,0xa6,0xa6,0xbc,0x7b,0x7b,0x06,},"\x45\x22\xb1\xd8\x23\x73\xf7\xa3\x18\x22\x1e\x7e\x57\x61\x75\x03\xdd\xf4\x4f\xd5\x39\x97\x52\x2a\x1d\x96\x3c\x85\xb7\x08\xd0\xb2\x45\xde\x37\x2a\xd5\x2e\xc7\xf5\x4f\x62\x13\xd2\x71\xf7\xc9\x1d\x5a\x1d\x36\xd1\x34\xdb\x38\x9d\xf0\xb0\x81\xa0\x6b\xc0\xc7\xa4\x87\x5f\x72\x40\x92\x79\x31\x72\xc9\x11\x56\x41\xc6\xd0\x54\xf1\xd9\x92\xe0\xfa\xe4\xdf\x58\x69\x5f\x0e\xa3\x44\x9d\x7a\x4b\x3a\x88\x57\xe1\x98\x03\xfe\x49\xb6\xd5\x2c\x9f\xf3\x74\x6a\x57\x4a\x27\x56\x95\x65\x79\xf9\xfb\x80\x9a\x0e\xde\xc9\x2c\x55\xe9\x5f\xfe\xfa\x3d\x05\xf1\x65\x82\x2f\x46\x4a\x21\x99\x9f\x29\x69\x1f\x67\x44\xac\x5a\x3e\xe4\x90\x17\x88\x06\x45\xe8\x37\xed\xeb\xfd\x2e\x0f\x24\x99\x7f\x04\x11\x45\xa7\x2e\x23\x76\xad\xa2\x83\x18\x6c\xa2\xb8\x36\x36\x29\x77\x19\x5b\xae\xe3\x0a\x3a\xcc\x81\xb2\x43\xf3\xee\x37\x6a\x2c\x47\x64\xc7\x83\x66\x7a\x4b\x11\x77\xe7\x95\x1d\x3e\x3c\x7b\xe4\xf1\xbd\x7a\xe8\xc6\x0f\xd5\xfb\x0f\xd9\x1f\x0c\x1c\x14\xd0\xd2\x32\x7e\x8f\x20\xd9\x2c\x0d\xfc\xc5\x38\x70\xe9\xd9\x9f\xdb\xf9\xdd\x9a\x17\xe8\x82\x50\x9a\xe7\xba\xa8\x65\x3e\x39\xed\xc8\xee\x56\x90\x00\xd6\x24\xcb\x93\xa0\x75\x4a\x79\x8d\x1f\x81\x1f\x6a\x0e\xf5\x50\x1a\x17\xbc\xf2\x5f\xd0\xf9\x16\x26"}, -{{0x71,0xad,0x98,0x0d,0x58,0xad,0x8e,0x7d,0x33,0x30,0x66,0x89,0x35,0x89,0x36,0xa3,0x72,0xd5,0x19,0x0b,0x24,0xec,0x7f,0x9b,0xde,0x74,0x9c,0xb8,0x11,0x50,0xef,0xda,},{0xfd,0x35,0xa7,0x5f,0xe5,0xab,0xc2,0x01,0x04,0x69,0x1a,0x24,0xa4,0x65,0x94,0x40,0xb5,0x5a,0xea,0xea,0x90,0x2a,0xc3,0xbe,0x27,0x4a,0xf2,0x7a,0xa8,0x31,0x28,0x69,},{0x81,0x67,0x0b,0x10,0x29,0xe4,0x81,0xe9,0xff,0x3c,0x17,0x1f,0x05,0xc1,0x68,0x61,0xc8,0x46,0xee,0x79,0xcd,0xf2,0xe2,0x1e,0x3b,0xf9,0x52,0xbc,0xfa,0xc9,0x75,0x65,0xf2,0xb1,0xdc,0xed,0xf6,0x9d,0x2e,0x7e,0xb3,0x5c,0xaf,0x56,0x62,0xe8,0xbc,0x67,0x1f,0xbb,0x96,0x75,0x6a,0x63,0xa5,0x96,0x26,0x4d,0x1b,0x7f,0x4a,0xf9,0x7e,0x06,},"\xe8\x7a\xe0\x73\xff\x5d\xcc\x54\x85\xa1\x99\x40\xe4\xe3\xff\x26\x3a\x06\x18\xa9\x02\x5a\xd4\x03\x2d\xfb\x36\xd1\x71\xce\x88\x1f\x71\xc1\x8a\x49\x21\x0e\xb4\x58\x19\x80\x61\x42\xe2\xf0\x0d\xb3\x04\x18\x35\xbf\x2c\x3b\xcc\xf1\xdb\xa0\x2b\x8b\x5a\x5b\xda\xf8\xfe\xa3\x16\xc0\x62\x3d\xd4\x8a\x56\x4e\xc1\x66\xf0\x37\xd5\x87\xc8\xc0\x16\x84\xe5\xe5\xc0\xba\x9d\xba\x4d\x23\xb4\x9a\x03\x09\x24\x4e\x28\x2a\x51\x40\x86\x22\xed\xb0\x57\x04\x74\x7e\x0c\xde\xec\x97\x68\x93\x77\x70\x71\x09\x89\x72\xc1\x13\xa8\xab\x63\x9c\x31\xf1\x61\x32\x33\xee\x46\x0e\xea\x8a\x8c\x10\xe1\xe6\xe1\x52\x21\x45\x29\x87\x8c\xf1\xad\xae\xaf\x78\xcf\x19\xba\xc7\x13\x61\x81\x5b\xf5\x79\x55\x49\x8f\xab\x4f\x0f\x2b\x75\x86\xc8\x6f\x9f\x4c\x2d\xdf\x89\x72\xf9\xb9\xe0\xeb\x63\x6d\x84\xbc\xc1\x43\x85\xb2\xd0\x38\xbe\x55\xa9\x63\x70\x2e\xfe\x22\x5a\x50\xbd\xd0\xc4\xda\x92\xa2\xa6\xa0\x91\x00\xea\x04\xa2\x11\xd3\x96\x45\x8d\xce\xb4\x48\x71\x16\x83\x7d\x13\x9e\xb0\xf1\x22\x53\x8e\xd3\x98\x6a\xd0\xaf\x4d\xa2\xdf\xfc\x89\xf3\x26\x9c\xa8\x85\x38\x08\x6e\x69\x1e\x5b\xea\xe9\x58\x1e\x7c\x63\xd8\xe6\x12\xda\x2c\x47\xf7\x4d\xde\x1d\x94\x95\x1e\xad\xb0\xdf\x60\xc3\x89\x7d\x2a\x30\x95\xc5\x06\x09\x3b"}, -{{0x61,0x59,0x4e,0x24,0xe7,0x5f,0x99,0x6b,0x4f,0xb6,0xb3,0xe5,0x63,0xf6,0xa4,0xf9,0x91,0x5c,0xfa,0x65,0xdd,0xb1,0x99,0xb0,0x1f,0xed,0x7f,0x8e,0xd7,0x82,0x4e,0xcb,},{0x86,0x27,0xd2,0x14,0x15,0x79,0xcd,0x25,0x21,0xaa,0x07,0x68,0x00,0xac,0x35,0x4b,0x9e,0x3a,0x47,0xd7,0x1c,0xed,0xc8,0x54,0x74,0x34,0x26,0x82,0x25,0xe3,0x30,0x05,},{0x63,0x02,0xb3,0xff,0x27,0x10,0xbe,0x30,0x6c,0x92,0xb9,0xaa,0xe3,0x0d,0x23,0xc3,0xd4,0xbe,0xff,0x39,0x4e,0x63,0x20,0x1e,0x6a,0xd1,0x17,0x13,0x34,0x5c,0x4f,0xcb,0x5c,0xc8,0xd3,0xdd,0x10,0xad,0xfb,0x82,0xbb,0x11,0xa1,0x89,0xce,0x7e,0xc3,0xe4,0x22,0x27,0x27,0x62,0x4f,0xc1,0x78,0x81,0xc1,0x47,0x88,0xd2,0x71,0x0e,0x16,0x08,},"\xbc\x01\xb0\x8c\x7c\xaa\x23\x61\x00\xa0\x12\xa7\x26\x47\x7d\x0e\xc3\x89\xdb\xfa\xda\xc7\x3d\x51\x06\x42\x4c\x5d\x1f\x3d\x1c\xef\x16\x95\xcf\xd9\x3a\x70\x62\xec\x8b\xf1\x06\x70\x47\x85\x49\x20\x16\x2f\x65\x13\x57\xbe\xdf\x1c\xd5\xa9\x2e\xc2\x9b\xdb\x5d\xff\x71\x6e\x8f\x60\x25\x51\x5a\x95\x49\xba\x36\xcd\xc3\x5c\xed\x7c\x5c\x0c\x36\x8e\x6c\xd9\x2f\x2f\x10\xae\x14\x6a\x20\x72\x8c\x37\x4b\xba\x50\x96\x41\xce\x88\xcb\x42\xff\xf0\xce\xdf\xd9\xfd\x67\xf3\x10\xf9\xd0\x1a\x3f\x36\x90\xeb\x21\xdb\x17\xbc\xe6\x7a\xe3\x5c\x4c\xd2\x4c\x20\x9f\x09\xf0\x44\x75\x9d\x8d\x5a\x7d\x24\x8e\x2b\xd9\x66\x52\x4b\xa8\xc0\xc2\x89\x74\x72\x6b\x43\xbd\x05\xde\x84\x34\x33\xcc\x40\x05\x98\x92\x29\x74\x62\x3d\x9a\xcb\xfd\xc7\x61\xc4\xc0\x43\x75\xa9\x52\xce\x54\xca\xff\xaa\x96\xac\xff\x6d\x9d\xc2\x78\x74\x2a\xf4\x76\xe1\x86\x5c\xb8\xc2\x0d\x13\xd1\xc1\x90\x08\x63\xbc\xa2\x31\xe4\x4c\x6b\x0d\x47\xcb\x41\xd5\x10\xf7\x95\x8f\x48\xf3\x04\xd0\x3d\xa0\x33\x48\x4a\x3e\x1f\x27\x3f\xaf\x69\x83\x37\x5b\x7d\x3b\xe0\x3d\x8a\x0a\x00\x2d\xef\x63\x65\xbe\xb2\xfa\x8c\xcf\x1a\x94\x98\x7a\xdc\xd3\x3d\x0d\xa1\x17\x7f\xc5\x15\x9b\x6e\x56\xd0\x04\x30\x1e\x92\x1d\xbc\x12\xec\x0a\x73\xf4\x13\xcf\x2c\x48"}, -{{0x54,0xe6,0xbb,0xfb,0xf8,0xc0,0x6f,0xf2,0xc0,0x66,0x31,0x8c,0x2e,0xbf,0x03,0xd5,0x06,0x54,0x7b,0xf4,0x3c,0x2d,0x7a,0x5d,0x4d,0xf3,0x05,0xa3,0x03,0x2b,0x71,0x38,},{0x3b,0x71,0xaa,0x1d,0xef,0x66,0x6d,0x91,0x88,0xf4,0x03,0xf8,0x2e,0xd3,0x04,0x54,0xab,0xa5,0xbc,0x9f,0x47,0x0f,0x6e,0xb9,0x88,0xda,0x18,0x7c,0x92,0x52,0x32,0x84,},{0x3d,0xf4,0xd0,0x90,0x79,0xf8,0x30,0xe3,0xf9,0x82,0x28,0x36,0x81,0xba,0x37,0xb5,0x0f,0x3c,0x73,0xde,0x2c,0x5d,0x22,0xa2,0x91,0x35,0x8e,0xbb,0x1f,0xb8,0x54,0xe5,0x10,0xf6,0x3f,0x9a,0x48,0xe9,0xff,0xf7,0xfd,0x83,0x11,0x30,0x2e,0xa3,0xe9,0x69,0x39,0x4e,0x6d,0x49,0xc9,0xe3,0x18,0x20,0x54,0x94,0x2f,0x6a,0x74,0x4c,0xee,0x03,},"\x03\x18\xd7\xcb\x48\x05\xaf\x98\x21\xdd\x3f\x91\x4b\x0e\x07\x6f\xea\x04\xa7\xd2\xdb\x3a\x59\xa0\x0a\xff\xea\xd3\x32\x5a\x2b\xe4\x0c\x1f\x87\xf5\x32\x76\xa8\x55\x26\x04\xf2\x28\xb9\x76\xe2\x88\xb9\xbe\x90\x6a\x7b\xd2\x5b\x2f\xfa\xb8\xa8\xaf\x5d\x0f\x6e\x08\x78\x6f\xd0\x34\xe2\xfe\x1e\xb7\xee\x03\x39\x79\x86\x0d\xd1\xe5\x32\x72\x87\xe9\xe6\x15\xf5\xdc\x5a\x96\x0f\x17\x02\x6b\x56\x84\x2f\xc8\xd4\x4c\xad\x00\x2e\xdc\x85\x01\xcf\xb9\x56\x00\x15\x02\xe4\xdd\xc8\x1a\x77\x00\xd9\xc0\xbe\x88\xeb\x4a\xaa\x64\xa6\xcb\xc3\x9d\xe8\x2f\x13\xc1\x10\x86\xde\x1a\x42\x70\xd3\xaf\x97\x28\x4b\xac\x1c\xae\xf1\xd3\xed\xaa\x10\x71\x66\x6b\xd8\x3b\x2e\xde\x39\x62\xd9\x8b\x9d\x93\x49\x7d\xdf\xd8\xe9\x7d\xab\x30\x89\x95\x0c\xf3\x0e\xd1\x1d\xb7\x7a\xd1\x43\x7a\x0a\xf5\x88\x9d\x8e\xfc\x44\xe6\x12\x42\x0e\x39\x07\x26\x7d\xf3\xac\xff\x4b\xd3\xfb\x6e\x8c\xa5\xba\xdf\x8e\x72\xf9\xde\x39\x52\x86\x53\x05\x85\x24\x45\x6a\x81\xda\x5f\x84\x98\x2a\xfa\xc3\x4b\xef\x5f\x71\xe9\x1f\x8f\x90\x93\x8a\x6f\x5f\x1f\x28\x77\x16\xde\x56\xa0\x94\x6d\x26\x1e\x87\xbc\x77\x5c\xe1\x89\xe4\x1a\x77\xba\xed\xe7\x32\x0a\x3c\x60\x8f\xc9\x71\xe5\x5d\x0a\x77\x3c\x4d\x84\x8d\x42\x86\x37\xf1\x1b\x4e\x44\x60\x39\x0c"}, -{{0x68,0x62,0x06,0x1b,0xe0,0xde,0x9d,0xfd,0x99,0x81,0x18,0x20,0x4b,0x2b,0x98,0xdb,0x3c,0xe7,0xd7,0xe8,0x19,0xdb,0xc1,0x07,0x94,0xaf,0x0a,0xb2,0xb0,0x6e,0x84,0x34,},{0x9c,0x5f,0x7c,0x22,0x65,0xdd,0xe1,0xb2,0x5e,0x4f,0x27,0xec,0x71,0x58,0x0d,0x52,0xdc,0x89,0xf2,0xc3,0xa7,0x12,0xbc,0x1a,0xd5,0xd6,0xd6,0x9e,0x71,0x1e,0x08,0xd4,},{0x96,0x5e,0xdb,0x34,0xe8,0xab,0x8b,0xc3,0x20,0x4a,0x32,0x01,0xd2,0x21,0x86,0x37,0x2d,0xe4,0x24,0x26,0x00,0x29,0x7c,0xfd,0xb5,0x7a,0xa1,0xdf,0x07,0x4e,0xc5,0x0d,0xdf,0x10,0x10,0x5e,0x9d,0x4c,0x89,0xa2,0x66,0xc3,0x4d,0xb7,0x77,0x2a,0xa9,0x4c,0xba,0x94,0x64,0x29,0xe6,0x8b,0xa6,0x2b,0xf9,0xa0,0xac,0x90,0xf5,0xf0,0x5b,0x02,},"\x17\x40\xdd\xe8\x43\x4a\x0d\x68\x99\x25\x67\x9b\x0c\x18\x03\x00\xcd\xbd\x0c\xf6\xa8\x9a\xd8\xfd\xe3\x46\x53\x31\x6c\xee\x4c\x57\x1a\x41\x05\xc9\xe9\xe0\x28\x42\x38\xfe\xf2\xc3\x8a\x09\x15\x7c\x5d\xb9\x43\x40\x57\x1b\x39\x0a\xdf\xb6\x9f\xf4\xc0\xdc\x50\x53\x25\x3a\x67\x9d\x42\xcc\x1f\x1b\xf1\xff\x42\x92\x29\xea\x0a\x50\x44\xc6\xf7\x95\x64\xe0\xdd\x28\x7f\x53\xf0\x15\xb8\x31\x87\xd9\xad\x27\xd9\x10\x39\xaf\x06\x2c\x43\x7b\x15\x75\xa0\xea\xb6\xae\xb8\xaa\x0d\x27\xb2\x76\x65\xd6\xde\xa9\x04\x1f\xf9\x96\x3a\x31\x18\xb3\x29\x8a\x85\x44\xe3\xfd\x69\xac\x68\x77\xe3\xe4\x05\x2f\xe4\x42\x2b\xf0\x35\x60\xb2\xc5\x7e\xc5\x31\xee\x8b\x5f\xf5\x3c\x28\xdb\xde\x35\xbb\x45\xc3\x50\x77\x63\x6e\x6f\x84\x1b\x59\xd7\xeb\x77\xbc\x77\x91\xb6\x09\x38\x58\xa3\xa8\x0a\x3a\xa6\xd7\x78\xdb\xf5\x3d\xb9\xd0\x61\x19\xc5\x0b\x71\xc7\x91\xc0\x49\x5c\x57\x6d\x1b\x59\xd3\x96\x87\x3e\xd8\x71\x48\x53\x52\xc8\x29\x9a\x35\x9d\xa5\xee\x9d\x7f\x36\xed\x14\x55\xf8\x98\x51\xa3\x08\x51\xbe\xa7\x19\x68\x5a\xec\xd0\x8f\x25\x56\x26\x09\xdd\x10\x66\x30\x73\x52\x77\xe1\xd6\x51\x9b\xb1\x68\x7d\xe8\xb8\xc6\x8b\x96\x71\x45\x2e\xdb\xb3\x49\x1d\xa2\x64\xcd\xfa\x00\x17\xc5\x12\xd2\x76\x97\x59\xcb\x92\x5f\xb6\x64"}, -{{0xb2,0x25,0x0b,0xbc,0xb2,0x68,0xd2,0x47,0x7c,0x83,0x12,0xb1,0x90,0x0f,0xd9,0x99,0x82,0xba,0xa2,0x9a,0x68,0x97,0x4f,0xbf,0x87,0x78,0xa1,0x22,0x8d,0xc9,0x75,0x50,},{0x44,0xaa,0x8d,0xf1,0x18,0x16,0x74,0xb0,0x5a,0xde,0x98,0x0f,0x7e,0xdd,0xba,0xf3,0xbd,0x74,0x22,0xa9,0x20,0x28,0x7c,0xb2,0xd2,0xdb,0x59,0xa0,0x63,0xee,0xbf,0x74,},{0xf2,0xb8,0xd9,0x2e,0xd5,0x1e,0xbd,0x10,0x00,0xbf,0x9d,0xd3,0x41,0x1a,0x9f,0xa9,0xe7,0xae,0xe5,0x4c,0x4c,0x86,0xe2,0x4a,0xd0,0xf9,0xad,0x5c,0x55,0x64,0x3a,0x12,0xd6,0x80,0x01,0x9c,0xa0,0x3f,0x21,0x6b,0xd4,0xbd,0x32,0xc9,0xce,0x1c,0xd8,0xa5,0x28,0xc3,0xff,0xaa,0x5d,0x5b,0x1d,0xc9,0x1a,0x4b,0xe5,0x6f,0x0e,0x2c,0x5e,0x06,},"\x7e\xf0\xae\x13\x36\xa6\xfa\xb3\x7f\x99\xda\x5f\xa7\xd0\xde\xc7\x40\x9c\x07\x26\x23\xea\xd8\x4f\x24\x1d\x53\xd0\x59\x6b\x46\x17\x05\xfb\x1b\x3c\x53\x7d\x36\xb8\x9e\x89\x60\xfe\xbb\x4c\xdc\x0d\x42\x7c\xe2\xfc\x1b\xe5\x8d\xbb\xce\x15\x1e\x35\xac\xd8\xb6\xac\xe4\x0a\x19\x82\x29\x14\xa4\xbd\x8c\x4a\xf6\x32\xf1\x36\x41\x8a\xc4\x9b\x18\x4d\x55\x19\x3e\xbc\xc3\x2d\x0d\x79\x87\x09\xb1\xa8\xfe\x29\x4f\xba\x8a\x1f\xe7\x2d\x97\x6b\x44\x00\xd4\xa3\x93\x24\x23\x11\xb0\xf8\xcc\x99\x4e\x89\x47\x5b\x00\x38\xae\x5d\x89\x14\x93\x8e\x8f\x6e\x87\xc6\xf5\x0b\x9d\x65\x6c\x45\xd7\xb1\x42\x31\xef\xed\x97\xf3\xc9\x06\x68\x91\x36\x70\xbf\x5b\xe2\xef\xd5\xc2\x70\xc7\xcb\xaf\x01\xe8\x57\x2e\x98\x00\x97\x8d\xfe\x2e\x10\xa2\xfc\x04\x40\xb8\x55\x62\x9b\xf9\xcd\x40\x9e\xa9\x41\xcb\x69\x22\x6c\xac\x77\x1b\x15\xea\x77\xc0\x32\x68\x48\x80\x6f\xf8\xd2\xe2\x01\xe6\xe2\x6c\xd5\xf4\x54\x30\xda\xdc\xff\x8f\x59\xc3\x21\xc1\xc9\xc6\xa2\x9b\x94\x88\x29\x35\x44\x7d\x3e\x6c\x2e\x88\x04\xb1\x16\x15\x76\xbd\xf0\x32\x0f\xe5\x3c\x30\x7d\x9c\xde\x42\x60\x77\xa7\x67\x7c\xde\x3c\x1b\xc8\x3e\x18\xe6\x0a\x0c\x4e\xe6\xdc\xcd\x87\x7c\x21\x3a\x8e\x4c\xca\x64\x0e\xe0\x49\x29\x80\x45\x70\xae\x1f\x96\x15\x7c\x04\x35\x7a"}, -{{0xb8,0x09,0x36,0x1f,0x55,0xcf,0xe8,0x13,0x7f,0xbd,0xa8,0x80,0xfc,0x62,0xcb,0xe4,0x4c,0x21,0x6e,0x14,0x18,0x93,0x34,0x63,0x02,0xb3,0x36,0x04,0x5d,0xe2,0x18,0x78,},{0xfd,0x23,0xe4,0x2f,0xf0,0x66,0x44,0xea,0xd3,0x47,0xab,0xcc,0x1b,0x3e,0x03,0xb0,0xe8,0x85,0x93,0xb6,0x12,0x54,0x98,0x1d,0xd8,0xae,0x59,0x45,0x4e,0x61,0xb3,0xe0,},{0xb5,0xb5,0x95,0x0d,0x37,0x72,0xd2,0xee,0xf8,0x8e,0x1b,0x0f,0x5d,0xf5,0xff,0xae,0x2f,0x21,0x03,0x88,0x5e,0x71,0x44,0x6d,0x34,0x6f,0xbb,0x5d,0xae,0xf9,0x49,0x67,0xa6,0xb7,0xb6,0xe4,0xbe,0x88,0x51,0x10,0x06,0x58,0x76,0xc6,0x65,0xb7,0x81,0x2d,0xe4,0x6a,0xd3,0x1e,0xc3,0xbf,0xcb,0xea,0xee,0x13,0xed,0x0c,0x1e,0x0b,0x30,0x0e,},"\x17\xac\xe1\x97\xd0\x83\xaa\xf1\x72\x6f\x53\xe5\xef\x81\xb5\xa8\xc0\x92\x22\xf2\x60\xee\x5f\x1f\x54\x04\xab\x78\xd9\x00\xd4\x89\x68\x84\x49\xb8\x43\xba\xd3\xc4\x98\xaa\xc6\xd8\x0b\x46\x39\xb7\x6e\x6e\x81\xc5\x52\x76\xa6\xf9\xc7\xce\xcd\x70\xb7\x1a\xaa\xf2\x01\x8e\xf7\x6c\x0e\x30\x15\x4a\xae\x86\xa5\xc8\x6d\x4e\x8d\x0e\x4e\xc6\x8c\xc4\x27\x06\x0b\xd5\x65\x14\xf7\x23\x80\x86\xbb\xef\x5b\xfc\xa1\xf5\x67\x1b\x18\x04\x18\x38\xfd\x01\x35\x72\x44\x3d\xba\x48\xfb\xdd\x95\xca\x74\x0b\x0d\xaa\x43\x27\x16\x4a\x1e\x34\x67\x72\x49\x70\x8f\x77\xbd\x79\x3e\x7c\xaa\x66\x38\xb5\xdc\x9f\xbe\x6f\x0d\xfd\x41\x20\x20\x90\x97\x20\x9c\x93\xce\xdf\xaf\x21\xb6\xbf\x59\xca\x6e\x99\xe6\x20\x96\x39\x44\x4f\x0e\x82\x7b\xbc\xc0\xa6\x1c\x3a\x23\x7c\xa2\x2a\x28\x32\x13\x22\x3a\xb6\x58\xe7\x12\xc7\x55\x62\x38\xd3\xa5\xfe\x31\x72\x2d\x65\xf5\x70\x6e\xf6\xd6\x4d\x73\x23\x2d\x30\x43\x22\x0f\x14\xe5\xcf\xd3\xc2\xc8\x3a\x83\xd6\x8e\x20\x27\x4b\x6f\x96\xb2\x9d\xe0\x40\xce\xc8\x47\x50\x30\xb6\xa8\xa8\x7d\x29\x80\x8d\xd3\x81\x79\x5c\x3d\x22\xac\xf5\xdc\x19\x3b\x72\x0d\x95\xa7\x52\xd9\xf1\x23\xc2\x09\xff\xba\x00\x4e\x48\xdd\x06\xdd\x8c\x9e\x17\x2b\xc9\xe0\x87\xd8\x0b\xc5\x21\x6c\x0b\x0b\x6e\x77\x03\x12\x41"}, -{{0xee,0xef,0x80,0x74,0xc2,0xeb,0x9a,0x1c,0xee,0x2f,0x2d,0x3b,0xb0,0x53,0x25,0x54,0x6a,0x9f,0xb7,0xcb,0xe4,0x4b,0x59,0x94,0x61,0xfc,0x58,0x85,0xf5,0xfd,0x9c,0xac,},{0x9b,0x89,0x29,0x41,0xa0,0x57,0x3b,0x7a,0x16,0x73,0xef,0x48,0x0f,0x08,0x11,0x68,0xd9,0xb7,0x49,0x6a,0x81,0xf9,0x17,0x7d,0xc4,0x27,0xca,0x1f,0x84,0xcb,0xbf,0x7d,},{0x6f,0x71,0x01,0x98,0x4f,0xd6,0x89,0x2e,0x21,0x44,0xb7,0xd4,0x56,0x19,0x83,0x0c,0xae,0xb6,0x71,0x3b,0xfa,0xb4,0xee,0xbb,0xe2,0x17,0xc5,0xbe,0xcd,0x24,0x9b,0xd9,0xd7,0x52,0xeb,0x76,0xe9,0xfa,0x99,0x5e,0x7c,0x71,0xff,0x7d,0xf8,0x6b,0xb2,0x60,0xcd,0xda,0x17,0x3f,0xf5,0xde,0xec,0x6a,0xf2,0x04,0xb7,0xdd,0xe0,0x11,0xde,0x09,},"\x9a\xe3\x9f\xea\xde\x90\x5a\xff\xcb\xed\xd2\xe7\x2a\x6f\x24\x29\xb3\xd1\x10\x8e\x5b\xc1\xa9\xdb\xaf\x49\x0a\x62\x99\xbc\xcd\x94\xac\xc4\x13\xad\xac\xc9\x18\xb1\x4a\xfa\x85\xc7\x8b\xc1\x68\xcc\x00\x74\x0c\x3d\xa0\xe0\x81\x83\x91\x5f\x79\xb7\xfe\x38\x68\xce\x2a\x7e\x88\x6b\x32\xad\x45\x00\x98\x05\xbf\xb8\x1b\x8c\x07\xb3\xb1\x02\x24\x20\xc0\xf0\x09\xb8\x89\xd7\xfc\x22\xfd\x19\x97\xae\x34\x19\x84\x38\xca\x94\x77\x85\x75\x12\x2f\xca\xaf\x96\xe6\x50\x2c\x33\xa7\x5a\x12\x9a\x2d\x0d\xbb\x07\x3d\x93\x82\x0d\x9c\x96\x68\x3d\xb3\x18\x99\x0b\xe3\xfe\xf4\xca\xfc\x89\x0a\xfb\xd9\xb1\x50\x4c\x74\x39\xa0\x8a\x06\x5e\x78\x14\xee\x4f\x9b\x6f\x57\xee\x16\xba\xed\x3f\x0e\x3a\xa3\x5d\xd2\x3d\x35\x28\xa4\x58\x91\x9a\xd7\x70\x48\xb4\xe2\xe6\x17\x23\x46\xbe\x24\x9a\x50\xaf\x02\xbc\x6c\x85\x33\x04\xc2\x08\xae\x0b\xa0\x27\x71\x26\x2a\x0d\x8a\x46\x5f\x71\xfa\x06\x35\xe5\x3e\xb2\xef\x0a\x84\x7d\x56\xa0\xbc\xd7\xdd\x3f\xe0\x77\xc9\x2b\xcd\xca\x30\x69\xa4\xa6\x82\xa2\x85\x99\x28\x31\x5c\xe3\xeb\x44\x5c\x60\x72\xa7\x14\x92\xee\x82\xe1\x72\xa2\x0b\xe0\xb6\x48\xb7\x56\xe6\xc7\x75\x37\x6f\x0c\x7c\x3d\xf8\xe6\x42\x88\x08\x9c\x2f\x81\xce\x95\x93\xc6\xe0\x8b\xb1\xcc\x1b\x27\xfc\xbd\x39\x2f\xc7\x95\x2c\x55"}, -{{0x61,0xfa,0xeb,0x15,0xf8,0x57,0xf6,0x55,0x78,0x62,0xc8,0xb8,0xc7,0xef,0x41,0xf8,0x05,0x45,0x52,0x09,0x96,0xfc,0xc1,0x12,0x7b,0x8c,0x24,0x91,0x82,0x22,0x01,0xae,},{0x60,0xa2,0x90,0xc0,0xfc,0x42,0x5a,0x08,0x74,0x67,0x3d,0x94,0xf9,0xbb,0x14,0x00,0xf9,0xda,0xcd,0xe9,0x95,0x4f,0x9f,0x5b,0x05,0xdd,0x48,0xab,0x74,0x7a,0x39,0x50,},{0x31,0xf9,0x0f,0x50,0xb2,0xdc,0x70,0x5f,0x1d,0x92,0xf1,0x2c,0xa9,0x97,0x5d,0x76,0xf1,0xb2,0x82,0x6a,0xda,0x3c,0xc1,0x85,0xb0,0xed,0x6c,0x83,0x86,0x07,0x77,0xbd,0x8c,0x48,0x9b,0x59,0x85,0x5a,0x91,0xf6,0x48,0x39,0xd4,0x9b,0xa4,0x67,0x98,0x5a,0xbb,0x37,0x6c,0x47,0xa4,0x90,0x8b,0x27,0x1b,0x8f,0x77,0xc5,0x8d,0x01,0xfd,0x04,},"\x25\x3b\x56\x6e\xcc\xb5\x63\xbd\x6e\x48\x0c\x69\x73\x9b\x8e\x37\x25\x19\xa3\x43\x72\x54\xe0\xe5\x02\x9c\xac\x86\xc7\x16\x38\xf2\xdf\x2a\x6c\xf9\xe5\x6d\xb2\x56\x99\x34\xde\xba\x90\xdb\x75\x54\x7e\x36\x71\x74\x7d\xf6\x4d\x6f\x2a\xaf\x3c\x11\x0f\xa6\x7a\x70\x94\xcc\xbe\x4c\xc5\x35\x5f\x0d\x43\x23\x51\x36\xee\x26\xdb\xe3\x7f\x42\x25\xd3\xbb\xfe\x24\x55\x95\x28\x05\x85\xfb\x54\x8f\x89\x4e\x86\xc5\x16\x10\x25\x80\x29\x1f\xa7\xa0\x28\x59\x55\x7f\xb9\x8e\xb5\x88\x87\x08\x28\xb0\x99\x0a\xe9\xd7\x4f\x38\x31\xda\x58\x94\x6b\xc7\xa5\xce\x1b\xa4\x98\xb4\xe8\xbe\x89\x89\xa3\xb5\x0d\x7e\x87\x89\xf5\x6b\x8b\x4f\xec\xbc\x2a\x33\xbf\xa3\xef\x59\x1a\x0f\xbc\xd9\x32\xfa\x93\xe1\x9f\x3a\x81\x2a\xe5\xe4\xe3\xb4\xb2\x42\xbe\x77\x05\xa5\x87\x4a\xf7\x3b\xe3\x10\xb0\x05\x82\x66\xa3\x78\xf2\x3c\x13\x48\x52\x47\x15\xb0\xcc\xc1\x8d\x66\x34\xb2\x36\x36\xc3\x16\xba\x6a\x1d\xd2\xfd\x50\x92\xc0\x67\x16\xa7\x17\xb5\x4d\x0e\xb9\xfc\x7f\x63\x6f\x85\xbb\xf2\x25\xa2\xcf\x03\x5b\x4b\x7c\xfd\xdd\x75\x35\x16\x82\xc0\x57\x6c\x6b\x3b\xa5\xa1\xc0\xb2\x5e\xc5\x94\xe7\x70\x9d\xd0\x9a\x00\x79\x77\x2f\xf3\xac\xc6\x7f\xb6\xc1\xb3\x7b\xb3\x74\x2b\x72\x6e\x77\xe8\x05\x61\xd9\xab\x73\x16\x0b\x73\x36\x25\x81\xda\x5b\x9c\x7f"}, -{{0xe6,0xb9,0xcd,0x4d,0xa0,0x7c,0xb3,0x4f,0x30,0x39,0x1c,0xf6,0x8f,0x0d,0x87,0xc7,0xcf,0xcf,0x68,0xf8,0x10,0xff,0xa4,0x0f,0x97,0x39,0xc9,0x5d,0xeb,0x03,0x7f,0x71,},{0x56,0x9e,0xde,0x0f,0x04,0x63,0x0b,0x43,0xa0,0x4c,0x5a,0x66,0xb6,0xa5,0x63,0x6b,0x76,0x6c,0x75,0x96,0x59,0x84,0xa7,0x47,0x7e,0x15,0x49,0x19,0x60,0xfd,0xd8,0x64,},{0x1e,0x37,0x5c,0x94,0xbd,0x80,0x9c,0xa0,0xcd,0xd0,0x2f,0x89,0xec,0xec,0x4e,0x43,0x77,0x32,0xdd,0x20,0xa0,0xa8,0x4b,0x25,0x4e,0xae,0x88,0x9d,0x80,0x70,0xe6,0x82,0xd1,0x13,0xb0,0xbe,0x22,0xe4,0x1e,0x6c,0xdc,0x3b,0xe8,0x77,0x68,0x0e,0x7e,0xeb,0x7f,0x09,0x95,0xe6,0x62,0x2d,0xc0,0xb4,0x34,0xfb,0x09,0x49,0xdd,0x99,0x4b,0x0c,},"\x69\xde\xf0\x52\x3a\xfd\xa6\x96\xf8\x44\x8f\x9c\x11\x43\xab\xc2\x65\x33\xe6\x86\x95\xa0\x90\xdf\x0d\x9e\x43\xd0\xc0\xef\xf4\x35\x83\xe6\xf7\x09\xd2\x04\x3c\x81\x5f\xbb\x3f\x96\xba\x2b\x0d\xc3\xbe\x6f\xec\xad\x5d\xd3\x81\x48\x78\x8e\x4a\x03\x85\xa9\xfe\x7a\x92\x1f\xcb\x8c\xce\xe0\xe4\xd3\xae\xd4\xbc\x3d\x21\x6d\x84\xb4\x14\xf9\x58\x0b\x02\x82\x0c\x03\xd9\x2e\x67\x5e\x68\x5c\x4b\x58\x51\xf3\x63\xbb\x4d\xf9\x7b\x41\x7c\x3f\xd9\x00\x22\xee\xaf\xa2\x0d\xfb\xe8\x29\x64\xf2\xff\x07\x3d\x25\x57\x58\xfb\xe5\x67\xc7\x6b\x2c\x35\xe2\xb0\x9f\x8a\x8d\x7a\xfa\x32\xc6\xf5\xad\x01\xbc\x3e\xbf\x6e\x21\x06\x06\xdb\x03\x8e\xcb\x68\x20\xce\x1e\xa4\xdd\x52\x9f\xc1\xad\xfb\xc2\xa1\x38\x56\x5a\xc6\xd0\xf4\xa4\x10\x9b\xdd\x47\xb8\xaa\x6e\xf4\xb8\xbe\xde\x45\x46\x80\xd1\xdb\xdb\x75\xfe\x1e\xb2\xe5\x48\xd5\xde\x7c\xb6\xd7\x92\xfe\xf3\xaa\x0d\x84\x80\xa6\x03\x0b\x30\xf1\x04\xd7\xe7\x6b\x58\xe9\xf4\x76\xeb\xf2\xcc\x83\x29\x23\xb5\x0c\x50\xc1\x11\xc3\x51\x5f\xc5\x18\x85\x23\x23\x42\x6c\xa7\x78\xa5\x96\xd3\x19\x5d\xa8\x58\x5d\x8c\x3a\xa9\x20\x83\x31\x3a\x6e\x65\x85\xb7\x0c\x98\xb1\x85\xb4\x72\x79\x8a\x61\xcd\xe7\x7e\x62\xec\x27\x2f\x14\xb0\xd9\xeb\x4f\x22\xf9\xc7\xc0\x58\x17\xda\x6f\xde\xfe\x78\x79\xa5\x84"}, -{{0x4d,0x90,0x44,0xf1,0x7b,0x5a,0x09,0x77,0xdc,0x5a,0xa9,0x91,0x6a,0x92,0x43,0x00,0xa2,0x44,0xa1,0xef,0x7f,0x06,0x02,0x77,0xad,0x49,0x78,0x35,0x1e,0xa6,0x42,0x91,},{0xab,0x9c,0x06,0x92,0xa6,0x06,0xb2,0x56,0x7c,0x19,0xc3,0x0f,0x9f,0xaa,0x3b,0x4c,0xfe,0x72,0xfb,0x23,0x70,0x77,0x76,0x7b,0x76,0xd3,0xb2,0xae,0x14,0x90,0xa6,0xd4,},{0x6f,0xa4,0x8a,0xea,0x4d,0x5b,0x9a,0xf6,0x5a,0xf9,0x64,0xcd,0xb7,0x09,0x44,0x3a,0x11,0xfa,0x84,0xf7,0xd4,0x4a,0xcd,0xda,0xb1,0x6e,0x04,0xa6,0xfc,0xef,0xb2,0x7a,0xe3,0x3c,0x05,0xb3,0x6d,0xa1,0x3c,0x23,0xde,0x51,0x7d,0x6e,0x6a,0xc5,0x74,0xa0,0x3e,0xa6,0x30,0xba,0x4f,0xbb,0x95,0x81,0x31,0x12,0x9a,0xa7,0xf1,0x35,0x4c,0x01,},"\x7c\x8c\x71\x89\xaf\x67\x32\x7a\xf1\xc6\xdd\x2c\x30\xe9\x75\xf1\x90\xe3\xb3\x8d\x00\x8b\x45\x85\x16\x7e\x0d\x45\x07\x40\xd4\x67\x34\x58\x7f\x6d\x20\x87\x84\x24\x5c\xc5\xcb\x06\x2a\x2a\x27\x7f\x17\xeb\xb2\x74\x6f\x9b\xdf\x4a\x82\x37\xca\x47\x9a\xb0\xa4\x30\x17\x7e\x19\xed\x7d\xd3\x62\x25\x76\xb1\x4c\xdc\x08\x28\x22\x14\xfe\x5e\xe4\xd7\x6b\x43\xc1\x6a\xc9\x08\x64\xc5\x1b\xe8\xae\xd4\x5d\x7b\x98\x0d\xf7\x91\x7f\x29\x0f\xdf\x79\x58\x46\x46\x5f\x27\xfc\xb7\xe5\x73\x06\x37\x94\x4f\x05\x77\xc9\x2f\x32\x37\x5e\x99\x5b\xc0\xcd\xa9\xd7\x19\x6f\x2c\x0c\x1a\xc8\xb8\x0d\x12\xa0\x43\x99\x63\xeb\xd2\x25\x4c\x34\x77\x03\x57\x58\x16\xe7\x96\x4c\x13\xd4\x4d\x62\x92\x80\xc3\x12\xea\x26\x53\x44\xde\x38\xf3\xb1\x8d\x91\x50\xf8\xf9\x24\xaf\xb4\x4b\x6b\xfb\x9e\xda\x51\x3d\x59\xe6\x5e\x2e\xf1\x86\x66\xe6\xc2\xa2\x1c\x40\x18\x66\x5b\xef\xe9\x2c\xae\x58\x1d\x3c\xb1\x4e\x23\xe9\x7d\x83\x00\x02\xcb\x90\x93\x1a\xe0\x21\x00\x68\xaf\x39\x4e\xbe\x35\x1b\xe5\xb8\x17\xf3\x67\x4b\xfb\xf4\x00\x49\x03\x0e\x4f\xe5\x05\xd3\x4a\x1d\x50\x2a\x2c\x50\xd8\xe6\x38\xe9\x26\xc2\x30\x67\x6b\x7e\xde\xfb\x6b\xec\x77\xb1\xc0\xce\x60\x93\x25\x28\x7b\xa5\xfd\xd7\xa9\x97\x69\x87\xbd\x07\xfc\x6a\x43\x44\x95\x6e\xbf\x81\x8f\x08\x58\x6c"}, -{{0x75,0xad,0x76,0xbb,0x4c,0x0c,0x22,0x9a,0x5a,0xdc,0x79,0xe4,0x44,0xb1,0x3f,0x88,0xa9,0x64,0x59,0x86,0x2c,0x8c,0xf0,0xba,0x49,0x8d,0x0c,0x99,0x6a,0xf9,0x4a,0x7a,},{0xf0,0x74,0xdd,0x2b,0x9c,0x1c,0x30,0x91,0x05,0xec,0x95,0x1b,0xb5,0x81,0x2a,0x91,0xdd,0xb5,0x40,0x23,0xb3,0x80,0x9a,0xb3,0x79,0xc5,0x6a,0xf0,0x46,0x1a,0xf6,0x17,},{0x0c,0x46,0x43,0xa8,0xbe,0x6d,0xc2,0x2f,0x4b,0xeb,0x6b,0xcc,0x70,0xc6,0x17,0x2e,0xc7,0x60,0x83,0x78,0x65,0x3c,0xb4,0xe9,0x9f,0x3a,0xe7,0x95,0xea,0xdf,0x4e,0x98,0x2a,0x29,0x76,0x09,0xca,0x79,0x38,0xf5,0xdf,0x63,0x2b,0x09,0x56,0x28,0xcb,0x75,0x06,0x2d,0x3d,0x51,0xfc,0x0f,0x33,0x23,0xbf,0xa7,0xb2,0x2e,0xc4,0xd4,0x72,0x05,},"\x0c\xa8\xc1\xc7\x41\x28\xd7\x4e\x9d\x0a\x7b\xf8\x96\x42\x91\xd0\x74\x91\x7f\x2f\x99\x20\xef\xb9\x11\x52\x05\x67\x64\x2a\x50\xa6\x15\xab\xcb\xd0\x0a\xed\x4a\xbb\xfe\xf1\xa9\x83\xcc\xe3\x33\xe1\xd0\xdf\x3e\x64\x04\xfb\x90\x43\xc6\x80\x39\x14\xcd\x5f\xff\xbc\x66\xa0\x79\x0c\x78\x78\xa2\x40\x89\xa5\x71\xf8\x95\x66\x2a\x1d\x18\xbe\x3f\x01\xff\x97\xfb\x33\x23\x33\x4b\x6f\x5b\xaf\x96\x55\x14\x48\xe4\x09\x0d\x03\x3c\x46\x42\x94\xd0\x91\x33\xb1\x51\xd5\xb5\xc6\x32\x1b\x50\xe2\x24\x1d\xe0\xef\x6f\x88\x28\x89\xcc\xf4\xad\x35\x40\xd5\xa1\xe3\xf7\x54\x8f\xb1\x3b\xe7\x1c\x16\x51\x66\x06\xe7\x9d\x04\x49\xc2\xa0\x8e\x5d\xc2\x31\x48\x84\x3c\x84\xe9\x7e\xd2\x40\x69\x16\x1c\x8e\x75\x20\x8f\x33\xe9\x5b\x3e\x10\xd1\xd4\x9a\x2f\xae\xf9\xd9\x86\xab\x62\x80\x9f\x62\xad\x39\xc7\xcc\x87\x1f\x37\x5a\x4f\x5a\x6f\xaf\x10\x4d\x7e\x11\xb8\x90\xcf\xb0\x58\x99\x02\x68\x52\x16\xec\x07\xcb\x8e\x8e\x9e\x7a\x7c\x43\x63\x5e\x23\x21\x2b\x69\xca\x3b\x7e\xd5\x4f\x0b\x97\x94\x9e\x3d\x9a\x66\x62\xf8\xe4\xb3\xab\x09\xcd\x49\x52\x94\xc3\x31\xc0\x47\xd8\x6e\xe7\x85\xff\x65\x8b\xcd\x7f\xcf\x9c\x48\x06\x05\xce\x05\xe8\x10\x06\x8d\x60\xfc\x9b\x26\xb5\xf0\x63\xeb\x90\x00\xd2\x65\x7a\x50\x94\x28\x4a\xc8\x0f\x13\x75\xd0\xb6\x6d\x6f\x5f"}, -{{0xad,0xc6,0xe9,0xb2,0xe1,0x03,0xb6,0x2c,0x24,0xad,0x43,0x46,0x41,0x0e,0x83,0xa1,0xa0,0xbd,0x25,0x3e,0x4a,0xbf,0x77,0x91,0x18,0x50,0xc6,0xd9,0x66,0x6e,0x09,0xf9,},{0xfc,0xe3,0x16,0xe3,0x3c,0x91,0x08,0x21,0xbe,0xed,0xdd,0x63,0x4b,0xed,0xc5,0x8e,0xe5,0x79,0x99,0xa7,0x6e,0xce,0x38,0x46,0x05,0x28,0x3b,0x99,0xb5,0x43,0xb7,0x8b,},{0xcb,0x01,0x7d,0x6d,0x26,0x82,0xc9,0x85,0x43,0x66,0x25,0x9a,0xa3,0x5f,0x30,0xd4,0x91,0xcf,0xaa,0x93,0x09,0x98,0xc2,0x97,0xdb,0xdd,0xc6,0xad,0xed,0x5b,0x3d,0x40,0x1c,0xf7,0x6d,0x80,0xd8,0xa2,0x76,0x4d,0xe1,0x31,0x71,0x8b,0x6e,0x0c,0x48,0x1d,0x71,0x96,0xbc,0x72,0x57,0x97,0x16,0xb0,0xc0,0xf6,0xff,0x05,0x3e,0x68,0xc5,0x0c,},"\x8c\xcc\xd9\x8e\xbb\xf2\x43\x9f\xfd\xfa\xc4\x16\x87\x63\x8f\xaa\x44\x4e\x1c\xa4\xb6\x3d\x13\xe8\x98\xea\xa8\x35\x54\x92\xf2\x88\x13\xab\x81\x3f\xd0\x15\x10\xe1\x12\xbe\x10\x6b\x20\x45\xd3\x0f\x63\x33\x5d\x24\x89\x04\xd5\x21\xde\x18\x1a\xba\xc0\x3e\x3d\x2c\xb2\xd1\x6c\x44\xb3\xb0\x12\xa0\xc5\x1f\x99\x01\xae\xf9\x05\x6c\x72\x4d\x7a\x2c\x6b\x2a\xcb\x0a\x07\x55\x59\x40\xe4\xc6\xe2\x11\x54\x89\x06\x11\xad\xeb\x64\x89\xf4\x61\xd3\xe5\xec\xd1\xaf\x5a\x4d\x2b\x0a\xda\xf4\x17\x47\x43\x6e\xb4\x14\x75\x7a\x8f\xe4\x77\x56\x74\xe3\xc6\xe5\xde\x45\x69\xd6\xfc\x6c\x78\x8e\x10\x90\x5e\xba\x32\xc2\x70\xa3\x93\xe6\xf7\x21\xa7\x65\x29\x4e\x2a\xc9\x9a\x9b\x6e\x53\x4d\x3d\xf0\x8d\x1d\xb9\x7d\x60\x2a\xc3\x19\x5c\xb0\xb7\x7f\x5b\xd4\xac\xaf\x73\x7f\xad\xd6\x99\x1f\x06\x88\xab\xc7\x49\x18\x04\x75\x74\xea\xc2\x82\x89\x73\x9a\x66\x4e\x0e\x0e\x20\x57\x4a\x2c\x25\xfd\xe4\x9d\x14\x53\x9d\xb1\xce\xdd\x4a\x92\x04\xa7\x0a\xcf\xf0\xa6\x2c\x8f\x25\xcd\x76\x8f\xfa\xb1\x5c\x4d\xb3\x16\x84\x0a\x4d\x1b\xc9\x2e\x21\x26\x70\xbe\x07\xc5\xbd\xcf\x53\x75\x90\x60\x7d\xfb\xbb\xb4\xd9\xf9\x8b\x89\xda\x0b\x4d\xf7\xd8\x8f\x3e\xca\x48\x14\xd1\x6b\xfa\x20\xc8\xd2\xfa\x94\xf9\xf2\x59\xf2\xee\x2d\x3a\x83\xc9\xe4\x17\x1b\x1a\x26\x2c\x4b\x99"}, -{{0x37,0xfc,0x1b,0xed,0xa4,0x06,0x0b,0x6c,0x57,0x88,0x3d,0xdb,0xa0,0x77,0x6c,0x2b,0xcf,0x5a,0xc2,0x8a,0x65,0x13,0x26,0x02,0x1c,0xca,0x97,0x72,0x37,0x30,0xfb,0xb0,},{0x7b,0xd7,0xbf,0x1c,0x99,0xdc,0x82,0xe0,0x6f,0x08,0xbb,0x45,0x4d,0x8f,0xb2,0x88,0xa5,0x79,0x27,0xe0,0x7f,0xf1,0xb1,0x2a,0xf1,0x5e,0xe2,0xc1,0x2f,0xbb,0x6b,0x3d,},{0xa0,0x1d,0xd6,0x5f,0xad,0xa2,0x70,0x39,0xf1,0x68,0xb1,0x23,0x41,0x9d,0x8a,0xbf,0xbd,0xa4,0x8c,0x57,0x2e,0xce,0x24,0xfd,0xa0,0x6e,0x1a,0x5e,0xc3,0x1e,0x08,0x4f,0x4e,0xe1,0xcb,0xf9,0x96,0x1e,0x88,0xed,0x51,0xe1,0x89,0xfc,0xb7,0xf5,0xf2,0x35,0xde,0x1e,0x5b,0x28,0xd0,0x8f,0x2b,0xfc,0xa1,0x90,0xb0,0xf0,0x19,0xec,0xc2,0x07,},"\x3d\xfc\xac\x02\x65\xa0\x24\xa8\x3c\xb9\x32\x67\x44\x89\xa1\x63\xaa\xc3\x14\xbf\x3d\x96\x9f\x27\x59\x6e\x45\x17\x33\xb9\x9d\xeb\xa5\xee\xb7\x79\x21\x0b\xaf\x95\xbf\x54\x5a\x1a\xe6\xb8\xa9\x15\x86\x06\x93\xee\x89\x0f\x93\x93\x20\xe0\x6a\x84\x44\x83\xd1\x8c\x6a\x1b\xcd\x03\xc6\x38\xbb\x7d\x1f\xe2\xa8\x2e\xb4\x48\xa3\x11\xb1\x30\x2e\xa6\x42\x8f\x54\xa3\x9f\x45\xa4\xd5\x60\xbe\x15\x57\xa2\xb2\x54\xc4\x5c\x13\x7f\x45\xcc\x68\x35\x68\x36\xe2\x1b\xed\x0b\x7f\x73\xa5\x18\xce\x09\xdb\x0b\xe3\x93\x92\x7c\x33\x9b\xf2\xa4\xb5\x98\x75\x39\x40\x4c\xe6\x50\x28\x4d\xe1\x2e\x3b\x55\x3b\x26\x2e\xfe\x23\x84\x83\x32\xcc\xfd\xc3\x5e\x79\x1a\x0a\xb4\x3f\x13\x9c\x71\xed\x0f\xcb\x2d\x17\x3b\xb3\x77\xee\x46\xb1\xa9\xdc\xa9\x27\x7e\x77\xdf\x85\x5f\x28\x30\x25\x1e\x31\xe2\x6a\xcd\x86\x76\x3c\x8d\x7e\xac\x22\xc8\x82\xfc\x17\x4f\x2b\x5e\x75\xca\x6a\xd1\xad\xe0\x3f\x94\x2b\xb2\xa1\x3b\xf5\x41\x90\x61\x59\x15\x8c\x68\x36\x3c\x74\x80\xc5\xb2\x7a\x99\x32\x0f\x82\x83\xa2\x69\x9d\x43\x69\xc0\x71\xc5\x0d\xbd\x90\xb7\x79\x2e\x47\x72\xef\xbc\x0b\x19\x5b\xce\x84\xcc\x4d\xcf\xff\x70\x72\xa4\x89\x68\xdb\x69\xf9\xfe\xdd\xd0\xf9\xce\xd6\x59\xeb\x5d\xb7\x16\x7f\x35\xf9\x88\xce\xc1\x14\x88\x7d\xcb\xfd\xf2\x7d\x02\xd3\x00\xb3\xe1\xab\xec"}, -{{0x8d,0x42,0xf4,0xdd,0xd2,0xbb,0xd2,0xb8,0x27,0xb0,0xa0,0xd3,0x1d,0x8f,0x75,0x8e,0xbd,0x13,0xa1,0xb9,0xb3,0x71,0x22,0x28,0x94,0x8c,0xa6,0x10,0xbb,0x88,0x58,0xe5,},{0xb7,0x35,0x48,0x98,0x79,0x4f,0x9d,0xb0,0xa8,0xaf,0x6e,0xea,0xfc,0xdb,0xdf,0x01,0x1d,0x3f,0xbe,0xf0,0x21,0x2a,0xd9,0x38,0xa4,0xa4,0xad,0x27,0xab,0x16,0xeb,0xbf,},{0x70,0x76,0x4b,0xe3,0x9c,0x6d,0xca,0x0f,0x06,0x7a,0xbe,0x1e,0xca,0x49,0x0f,0xda,0x95,0x1f,0xd4,0xe9,0x49,0x96,0x95,0x26,0x6e,0x27,0x0b,0x9b,0x05,0xea,0xe7,0x06,0xca,0x8d,0x1c,0xa6,0xa9,0x2d,0x7c,0x48,0x8e,0xc6,0xad,0x8b,0xa1,0x14,0x57,0xa4,0x2a,0x5e,0x31,0x70,0x2a,0x9c,0x2b,0xce,0x89,0x2d,0xc4,0x05,0x35,0xc0,0x9f,0x01,},"\xe3\xa2\xbe\xbc\x04\x96\xd8\x97\x4a\x8f\x40\x61\x88\x03\x69\x31\x4e\xd9\xe4\x40\xc1\xb7\x7e\x26\xfe\x50\x71\xce\x69\x4f\xfd\x21\x36\xdb\x0c\x4d\x5e\x88\x0e\x60\x00\x08\x3a\x75\xc9\x0d\x3c\xf7\x2b\x9c\xf5\xa2\xb1\xa9\x00\x2c\x27\x01\xa2\xff\x59\xb0\x69\x9a\x8f\x42\xd7\x9d\xd8\xa5\xfb\x71\xa8\x12\x54\x53\xd9\x1f\xb8\x00\x80\xa3\xf0\xa1\x65\x84\x28\x2f\x17\xec\x7d\xfd\xc2\xe5\xc6\x9c\x4d\x9b\xdf\x48\x4d\x55\x94\x4d\xae\x27\x3f\x21\x1c\xfb\x76\xad\x37\xda\x45\x87\x13\x65\x43\x9a\xf3\x5e\xea\x1f\xbe\xcd\x4c\xa6\x79\xb5\x9b\x5e\x01\xba\xcf\x49\xc7\xf4\xe5\xef\xaa\x40\x6b\xa1\xda\xeb\x08\x54\x82\xaf\x5d\xed\x89\xdc\x68\x85\xff\xbe\x3d\x14\xd2\x93\x1b\x83\x89\x7e\x28\xad\x06\xe5\x56\x4e\x27\x89\xba\xea\x81\xbd\x93\x2a\xa2\x79\xfe\x8e\x32\x4b\x9a\x8e\xf1\x11\xc2\xab\xe2\xf1\x37\xd4\xbb\x50\xd8\xab\x76\xce\xbc\x0b\xd9\x82\xa2\x39\x19\x75\x1a\xd4\xd4\x9e\x88\xeb\x14\x17\x3d\x33\x10\x28\x9a\x87\x23\x17\xe4\xa4\x51\xe8\x8d\x54\x32\x08\x91\x87\x0f\x15\xb2\xd5\x33\x24\x43\x08\x77\xa9\xfb\x5b\x49\xbb\x92\x9f\x21\x1c\x5b\x89\x76\x4d\xd9\xc3\xa5\x95\xa1\x45\x1e\x9f\x85\xa2\x38\x54\x00\x02\x56\x6e\x53\xa9\x9e\xd1\xe6\xdd\xc9\xb4\x85\x3f\x45\x5e\xdb\x4c\xf1\x98\x0d\x56\xbb\xdc\x13\x13\xa3\x6e\x76\xea\x9c\xbb\x04\x8a"}, -{{0xb6,0x2d,0xe5,0xa1,0xac,0xfe,0x4c,0xa2,0xd1,0xf0,0xc1,0x32,0xaf,0xcb,0xda,0xe6,0x6f,0xb2,0x9a,0x02,0xf2,0x97,0xfb,0xc2,0x40,0x7f,0xad,0xbb,0xf2,0x45,0x42,0x00,},{0xb6,0x3b,0x2d,0x0b,0xf3,0x55,0xf7,0xb6,0xd0,0xba,0xc0,0x74,0x03,0x41,0x1c,0x40,0xaf,0xbb,0xb2,0xf7,0x07,0x50,0x3b,0x3f,0xc2,0xce,0xe8,0xa1,0xc7,0xd0,0xa8,0x38,},{0x5c,0xdb,0x00,0xe9,0x8d,0xe7,0x3e,0xab,0x48,0x0b,0xe4,0x2f,0x8a,0x8a,0x61,0x63,0x80,0x9a,0x0d,0x37,0x10,0x1b,0x6a,0x5a,0x4e,0xed,0x6a,0x0c,0x92,0x03,0x0d,0x09,0xa5,0x56,0x2c,0x72,0x90,0x80,0xce,0x6f,0x65,0x94,0xc8,0xfa,0xfb,0x1f,0x59,0x47,0x72,0xdb,0x7a,0x90,0xa9,0xe7,0xda,0x15,0x89,0x6e,0x82,0xf7,0x05,0x69,0x39,0x0d,},"\xe6\x59\xe5\x1d\x7b\x19\x3c\x4b\x8e\x2b\x3e\xd7\x3a\x9d\x75\x57\xed\x2b\xab\x61\x53\x88\x3a\xb7\x23\x59\x2f\x73\x0a\x91\x45\x67\x14\x2b\x3f\xa4\x35\xdb\x32\x19\xf8\x3a\x54\x2d\xc7\xa4\xbd\x80\x5a\xf6\x66\xea\x86\x5b\x85\x31\x46\xf8\xe3\xa9\xfe\x87\x07\x11\xf9\x0d\x12\xb0\x69\x34\x92\xaf\x2a\x1e\xdf\x99\xa1\x64\x58\xf7\x81\xf1\x26\x6e\xc4\x37\xa5\x29\x6a\x82\x2c\xa9\xd6\x9c\xe8\x44\xb5\xc5\x90\x97\xa2\xa5\x6f\x3e\xb8\xfd\x27\x3a\x63\x61\x16\xdb\x77\x43\x00\x92\x2d\x45\xb7\x44\x65\x7a\x69\x2f\x5e\x8b\xfb\xcb\x06\xd2\x42\x28\x18\xae\xb5\x1e\x7c\xda\x68\xac\xfb\xed\xa1\x6e\x7c\x79\x58\x0d\xcc\xcd\xe2\x4e\x8e\x3d\x60\x1b\x16\xe0\x63\xb4\x3a\x6d\x0d\x14\x07\x55\x2f\x75\x04\xf5\xbe\x19\x88\x2e\x4f\xfe\x32\x34\x4f\x5f\x47\x3e\x73\xa8\xf6\xed\x37\xb0\xd8\xd9\xe5\xe0\xa0\xdc\x98\x28\x39\x5b\xcb\xd8\xf3\xa4\xe3\x12\x48\x69\x24\x9d\x05\x8b\xe0\xe0\x45\xde\x0b\x1e\x12\xb1\xc8\x3b\xa0\xaa\x22\x7c\x95\xb8\x2b\xf7\x42\xc3\xea\xc0\x15\x2b\x33\xe6\xd1\x9b\xe8\xb3\x3a\x35\xbf\x70\x5d\xaa\xb1\x06\x22\xa9\x0a\xed\x02\x2e\xa6\xe4\x39\xed\x50\xa9\x30\x84\x37\x92\x99\x24\xba\x3a\xb1\x11\xad\x0c\xaa\x6f\xeb\x0a\x6e\xb1\x65\x82\x4e\xbd\xb0\x86\x65\x71\xef\xc0\x7e\x52\x22\xed\x86\x86\xb1\x4d\x92\x70\xbf\x76\xb9\x45\xd5\x20\x14"}, -{{0x97,0x32,0x05,0x9d,0x7b,0xf0,0x20,0x0f,0x5f,0x30,0x41,0x24,0x30,0x33,0x6b,0xe4,0xef,0x1e,0x3c,0xae,0x62,0x93,0x8a,0xd0,0x87,0x29,0xce,0x3b,0xa7,0x14,0xcf,0xd4,},{0x0d,0xe8,0x42,0x5f,0x5e,0x30,0xb2,0xb8,0xae,0xbb,0x80,0x72,0x00,0x9a,0x30,0xcf,0x04,0x11,0xc3,0xc8,0x23,0x8f,0x4e,0x42,0x08,0x76,0x0c,0x56,0xc3,0x3e,0x43,0x4f,},{0xfb,0xa1,0x74,0x9b,0x64,0x1d,0xd4,0xdf,0x34,0x66,0x4b,0xc4,0x3c,0x00,0x46,0x8c,0x7d,0x75,0xe8,0x4a,0xfa,0xd7,0x2d,0xe4,0x73,0xfd,0x1e,0x9c,0x87,0xda,0x15,0xea,0x60,0x4f,0xc2,0x54,0x9a,0x1a,0x86,0x7f,0xa8,0x08,0x50,0xe9,0xc2,0xa5,0x9c,0xd9,0x90,0x53,0x88,0x67,0x60,0xa8,0xd9,0x76,0x4b,0x84,0xdd,0x67,0x26,0x76,0x72,0x0d,},"\x1a\x13\xe7\xab\x60\x3b\x48\xeb\x89\x6f\xe1\x71\x73\xfb\x31\x95\x0b\x0d\xcd\x5a\x35\xff\xdb\xe1\x37\x1c\x7a\x5b\xfb\xa5\x93\x31\x75\x89\xd9\x65\x2d\x88\x79\x77\x29\x18\x0b\x8d\x0e\x51\x5a\xbf\xe6\x54\x8f\x16\x04\x21\xe5\x37\xd5\xc9\x4a\xef\x2b\x34\xc7\xeb\xb0\x97\x42\x00\x03\xbc\x0f\x36\x1b\x42\x3e\x7e\x14\x63\x0a\x80\x3c\x11\x82\x02\x54\x00\x49\xf6\x8c\x9c\xf4\x6f\xae\x03\x68\xd1\x62\xe4\x00\xd7\x7b\xb4\x52\x3c\xf6\xc7\x53\xb9\x75\xc2\x45\xbc\x99\xed\x2f\x41\x3a\x9d\x06\xc2\xda\x6c\xe0\xcc\x09\x87\xb6\x40\x6b\x80\x9e\x8e\xb3\x19\x03\x3d\x2d\xe9\x13\x1d\xee\x3b\x1b\x7b\x5c\x95\xd6\x53\xce\xd8\xfc\xcf\x99\x8d\xa1\x76\x85\x11\xec\xa4\xd3\xc5\xf7\x35\xad\xab\x96\x50\x3b\x35\x51\x80\x3e\x49\x22\x63\x50\x95\xef\x81\x1b\xe4\xc0\x8a\x6c\xba\xc9\x17\xcb\xe6\xcd\x91\xa4\xae\x5a\x33\x0c\xce\xc0\xe8\xe8\x15\x37\x12\x17\xa3\xde\x62\xf2\xd2\xd6\x14\x66\x21\x98\x33\xf3\x34\x47\x13\x2f\x4d\x43\x35\x0c\x58\xcb\xaf\x42\x24\x75\xed\xb1\x28\xc5\x6d\x80\xa4\x95\x72\x6b\x1f\xdb\xc5\x65\x51\xeb\x72\xd0\xf4\xfe\xc2\x6b\xa8\xbf\xf5\xee\xd6\x77\x4b\x85\x03\x9a\x52\x92\x83\x4b\x5d\x1c\xc1\xb0\x9b\xa0\xa3\x95\x4d\x29\x32\x36\x73\xf5\xe7\x12\x76\xa1\x2a\xc4\xc5\x79\x35\x5b\xf1\xec\xca\x48\xe6\xa7\x16\xb9\xfc\xec\xdc\x56\x5c\x51\xb9"}, -{{0x9c,0x7f,0x6f,0x37,0x9e,0x38,0x57,0x00,0x7e,0x2a,0xc6,0x32,0x4c,0xbb,0xce,0xd5,0x7a,0xc9,0xee,0xe4,0x47,0x78,0x13,0xf8,0x3a,0x81,0xfc,0x8c,0xef,0xa9,0x64,0xd5,},{0xa5,0x4b,0xa3,0x96,0xd6,0x87,0x63,0x4d,0x3e,0xcc,0xf4,0x1c,0x57,0x82,0x49,0x4f,0x5f,0x10,0xa5,0x21,0xa1,0xe5,0xd3,0x88,0x52,0x3d,0x80,0xee,0xba,0x5b,0x0b,0x2b,},{0x65,0x68,0x5f,0x9c,0xa5,0x98,0x2e,0x15,0xa2,0x2b,0xa3,0xc8,0x3a,0x03,0x48,0x34,0x84,0x82,0xdf,0xae,0x57,0xce,0xa1,0x78,0xf0,0x78,0x0c,0x05,0x7b,0xae,0xbe,0x4a,0xf6,0x32,0xf9,0x84,0x54,0x0a,0x26,0x01,0x9a,0x7f,0xb3,0x42,0x53,0xc9,0xec,0xe7,0xff,0x30,0x8a,0xda,0x23,0x3c,0xe0,0x68,0x63,0x47,0xab,0x5b,0x21,0xce,0x57,0x0b,},"\x3f\x2d\x30\x72\xfe\x73\x83\xe5\x41\x55\x1e\xa9\xab\xdb\xae\xae\x6a\x46\x4a\xe6\xb9\xf0\xba\x78\x6a\x44\x1b\x2d\x08\xda\x5b\xca\xda\x3c\x54\x24\xdc\x69\x31\xd6\xb3\x95\x23\xe2\xde\x0a\x0c\x2e\x4e\x6b\x5b\x8c\xda\x92\x5e\x5e\xac\x93\x84\x16\xa2\xc5\x1b\xf1\x3d\x49\x53\x1d\x7e\xc7\x11\x4b\x1c\x82\xfe\xaf\x90\xf3\xf8\x75\x91\xe3\x97\xd0\x27\x02\xf8\xec\x1b\x30\xd9\x9f\x5b\xe7\xd2\x20\x3e\x4f\xe4\xdb\x2e\xa4\x7e\x7b\x45\x89\xd8\xac\x50\x62\x48\xd7\x34\x74\x66\xed\xbc\x96\xea\x32\xbf\x3a\x6e\xa7\x50\x2d\xd6\x0c\x9e\x84\x90\x27\x15\xab\x2c\x6c\xa6\x8f\x5b\x00\xe1\xd9\x09\xd8\x3a\xa6\xab\x66\x2d\x8a\xea\x87\x0e\xcd\x86\x1f\xec\x69\xf2\xee\xc0\xae\x67\x7d\x29\x95\xb0\xed\x68\x8f\xaa\x8e\xf7\x82\x44\xe0\xd1\x19\x56\x97\xb0\x71\x22\xce\xaa\x11\xf5\xa6\xea\x58\xfb\xdf\xa2\xe2\xec\x2d\xf9\xd1\x86\x93\xae\x96\xd4\x71\x27\x55\x6e\x91\xf0\x86\x49\x82\xc1\x34\x19\xb0\x4a\x63\xf2\x08\xe7\x30\xd2\x69\x51\x88\x2a\xef\xe0\x01\xbc\xa3\x40\x8b\xd9\x86\x27\x48\xc6\xcc\x87\x6c\x28\xca\xc3\xbb\x2e\xb3\x39\x58\x18\xc2\x09\x1e\x0f\xbd\x7a\x0b\x44\x68\xc6\xb0\xd0\x0c\xd0\x08\xc1\x1c\x3c\x3a\xd0\x10\x80\xa1\xf5\xa4\x0a\xe2\xe4\xb0\xc3\xa0\x71\xef\xc8\xe1\xd1\xba\x6a\xce\x6d\x4d\xf0\xff\x19\x82\x9b\x0c\x68\x0b\x3a\xeb\x75\x91\x77\xed\x34"}, -{{0xa4,0x78,0xf3,0x5a,0xbb,0x73,0x72,0x7b,0x6b,0xe6,0xee,0x5e,0x56,0xee,0xc3,0x23,0xc9,0x51,0x78,0x82,0xfd,0x69,0x19,0x36,0x0e,0xbb,0xbf,0x5d,0x5c,0xb8,0xb8,0x3a,},{0x7a,0x6e,0x26,0x6a,0x54,0xd1,0x35,0xdd,0xa0,0x00,0x9c,0xcd,0xa8,0xa9,0x4a,0x47,0x12,0xae,0x5c,0xb1,0x47,0x61,0xe8,0x43,0x6e,0x97,0xc4,0xb7,0x81,0x4d,0x8e,0x8c,},{0x9d,0x16,0xfd,0x40,0xb9,0xf8,0xdd,0x9b,0x4a,0x1a,0x8c,0x6d,0x70,0x3b,0x9f,0xcc,0xbb,0x94,0x0b,0x1e,0x0a,0xe7,0x7a,0x59,0x70,0x37,0x4a,0xf0,0xcf,0x72,0x6f,0x44,0x79,0xfd,0x30,0xd7,0xdf,0xf5,0xcf,0x53,0x49,0x4d,0x9a,0x29,0x6a,0xb6,0xb9,0xe4,0x6e,0xa6,0xc1,0x36,0xb4,0xdb,0x2c,0x71,0xc2,0x1b,0x97,0xc1,0xc8,0x25,0x4d,0x0a,},"\x01\x73\xa3\x40\x50\xb4\x37\x48\x06\x1f\xf8\xf5\xa3\xd7\xc4\x3b\x63\x60\x84\x77\x86\xe8\xbb\x75\xe5\x36\xfb\x47\xb6\x45\xb2\x14\xf2\x21\xba\x24\xd8\x3d\x28\xbc\x02\x50\x24\x66\x3e\x53\x4f\x90\xf6\xe8\x3a\x93\xd8\xbd\xde\xda\x2c\xd8\x80\x81\x55\x65\x2a\x90\x8c\x43\x7c\x2d\xb6\xf3\xed\x49\x12\xf5\x7c\xa5\xb9\x79\x28\xa7\x3b\xe9\x64\xaf\x59\xdf\x44\x39\x85\x4b\xb0\x06\xfc\x29\x5a\x87\xb7\xb7\x22\x39\xc7\xfa\xdf\xec\x40\x71\x55\x09\xd9\x85\x79\xda\xad\xfb\x8d\x52\x4b\x4c\xec\x66\x20\x70\x5e\xfd\x41\x04\xc2\x97\x14\x4a\xea\x72\x29\x74\xe1\x2c\x5e\xce\xe5\x39\x1e\xf2\xd9\x3a\xc2\xb1\x24\xe4\xac\x49\x61\x47\xc8\xb7\x03\x63\x58\x5d\x70\x78\xcc\xc5\x3e\x2a\xe5\x93\x35\x0b\xc2\x55\x48\xa0\x54\x25\x26\xab\x00\xaf\xe4\x77\xa0\xf4\xb2\x73\x97\xc7\x2b\xc7\x4a\x8a\x8a\xb1\x56\xe6\x2b\x8b\xb4\x7c\x3f\xbb\x4b\x34\x91\x3e\x45\x96\x87\x47\x6b\xf3\x31\x42\xc6\x14\x70\x21\x07\xff\xe2\xcc\x01\xe2\x5f\xa3\x02\x75\xe1\xe2\xe6\x3c\xea\x91\x68\xe4\xa4\x7c\x02\xde\x09\x7d\x4d\x85\x3b\x27\x67\x5c\x5b\xb3\x30\xb9\x4a\x97\x4e\xad\x85\xe2\xbd\xee\x8e\xe1\x7c\xbb\x56\x53\x34\x66\x58\xdf\x2f\x91\xf6\xbd\x73\x94\x91\xdd\x71\x98\x8b\x3a\x97\x6a\x3e\x2e\x7a\x9d\x13\x74\x10\xf4\xac\xba\x9f\xeb\x5f\x11\x79\x8c\x9a\x43\xb6\xad\xce\x14\x36\x5a\x7c\x6d"}, -{{0xff,0xe8,0x25,0x14,0x8c,0x09,0x59,0xb3,0xa6,0x8d,0xe8,0x6a,0xd8,0xe8,0xaf,0x7f,0xa5,0xe0,0x78,0xf3,0x63,0xdc,0x12,0x42,0x13,0xc9,0x00,0x20,0xda,0x0c,0x90,0x89,},{0x13,0x91,0x52,0xa0,0xbd,0x22,0x96,0x2d,0xd9,0x19,0xae,0x3e,0x0b,0x16,0x20,0xe0,0x3c,0x03,0x3c,0x2a,0xd0,0xa3,0x97,0x9e,0xc6,0xbc,0xd1,0x70,0x5e,0x23,0xd5,0x98,},{0xfe,0x4e,0x89,0xee,0x31,0x78,0x6c,0x0a,0x3d,0x3d,0xe3,0x64,0x9b,0xb9,0x3f,0x0b,0x8a,0xef,0x1c,0xaf,0x5a,0x83,0x2e,0xc5,0xe4,0x06,0x78,0x10,0x70,0x5a,0xdd,0xdf,0x53,0x9b,0x8f,0x4e,0x05,0xad,0x08,0xcf,0x34,0x79,0xe4,0x5b,0x42,0xc9,0x65,0x28,0xf6,0xd5,0x9a,0x46,0x25,0x70,0x3d,0xdb,0xf1,0x5b,0x63,0x09,0x39,0x65,0xd8,0x0d,},"\xf1\x25\x78\x0d\x0c\xd0\x88\x53\x0f\x0c\x87\xb7\x0b\xd4\x2e\xba\xb5\x6a\xdb\x5a\xd4\x34\x5f\x92\x9a\xe5\xde\xae\x07\xfb\x55\x32\x21\x53\xa8\xf0\x23\xd3\x88\x43\xbf\x5d\x6a\x93\xfe\x99\x3e\xee\x71\xbc\x2e\xe5\x63\xb2\x5a\x50\x91\x8f\x03\xef\xdb\x5d\xbf\x72\x69\xad\xd6\x9d\xed\x3e\x66\x95\x38\x95\x62\x0d\x9b\x6c\xf4\x6b\xa2\x34\x8f\x8d\x66\xd7\xf0\x92\x23\x5e\x37\x8c\x1e\x3e\xdf\xeb\xeb\x78\x08\x4b\xc8\xde\xa0\x13\xf9\x93\x3a\xae\x14\xa0\x41\x94\x82\x76\xd0\x1f\x1c\xb5\x83\x4b\x0e\x59\x0e\x13\xd9\x31\xd1\x92\x92\xbb\x1d\x80\x41\xff\x2f\xe2\xe1\x17\x1a\x2e\x0b\x9a\x05\x98\x21\xd0\x92\x4d\xde\x7f\x3b\x1b\xb5\x98\x13\xf5\xe3\xc6\x35\x20\xaa\xfb\x88\x01\xba\x62\xc7\x09\x7d\x4d\x8c\xf4\x37\xa5\x68\xa7\xf0\x08\x7c\x6e\xa0\xfc\xe6\xe5\x68\xc4\x88\x3f\x1c\xd1\x2c\x74\x9d\x06\xa6\xfe\xb2\x78\xf1\x08\x6a\x8b\x04\x76\x99\x21\xf7\x8a\x99\x59\x06\x2a\xb0\x6f\x98\xee\x80\xc2\xc7\x85\x4f\xfa\x76\x0f\x86\xa8\x9e\xe1\xa5\x12\x66\x05\x3d\x19\x5e\x61\xbb\x1d\xbd\x18\xdd\x89\xff\x39\x4e\x40\x8a\xce\x0f\x64\x1a\x39\x5d\x56\x11\x8e\xa7\x2b\x7d\x8a\xdf\x78\xb1\x65\x5e\xce\xce\x7e\x82\x50\xe8\xa3\xa9\x1c\xb8\xfc\xa0\xd9\xce\x0b\xaf\x89\x80\xa3\x87\xc5\xed\x43\x18\x66\x32\x80\xe5\xb4\x53\x1f\x31\x87\xc4\x7e\xae\xa7\xc3\x29\x72\x8d\xdd\x0e\x40"}, -{{0x49,0xaf,0xf4,0x21,0xa7,0xcd,0x12,0x72,0x2a,0xa8,0x4c,0x48,0xc1,0xfb,0x1c,0x5f,0x8d,0x9e,0x27,0x7d,0x0a,0x99,0xec,0xbc,0x93,0x48,0xc3,0xaa,0xa7,0x4b,0xe4,0x22,},{0x88,0xd2,0xc2,0x62,0x66,0xf4,0x93,0xbc,0x67,0x57,0x8c,0xa0,0xb1,0xf5,0x11,0x60,0xcf,0x0f,0xdb,0x6a,0x09,0xa9,0x06,0xdb,0x9f,0xaa,0x68,0x6f,0x11,0xf8,0x20,0x8d,},{0x74,0x91,0x81,0x28,0x4d,0xf0,0x5d,0xbe,0x59,0x74,0xb9,0x17,0x82,0xa1,0xa7,0x6e,0xa0,0x86,0x42,0xcb,0x0f,0x0c,0x98,0xdb,0x58,0x6c,0x57,0x5c,0x21,0x0c,0xdc,0x8b,0x65,0x1b,0xd3,0x4b,0x75,0x7a,0xe3,0x8e,0x4b,0x6b,0xe9,0x46,0x52,0x35,0xbd,0x0e,0xca,0x43,0x0e,0x26,0xc3,0xee,0xde,0x56,0x1c,0x6e,0x82,0x4d,0xfa,0x20,0x0e,0x0a,},"\x70\xa1\xac\x14\x4b\x75\xfd\xa7\x55\x86\xa7\x9c\x36\xfd\x39\xcc\xe5\xf5\xca\xe2\xe6\x37\x58\x52\xd3\xb6\x2a\x96\x30\x33\x6a\x29\x3e\xa6\xd2\xac\x6e\x5b\x57\xda\x21\xef\x36\x4a\x59\x5b\xb0\x75\x0f\x5b\xf4\xd2\xb3\x20\x67\x64\x23\x87\x0e\x4b\x8e\x08\x69\x60\x1f\x16\x68\x06\x19\x04\x8c\x4e\xde\x27\x6d\xa6\x9f\x20\x5a\x70\x17\x6e\x25\xea\x04\xbd\x08\x97\x63\xe7\x09\xba\x34\x3f\xc8\x83\x1e\x52\x04\x4e\xab\xf9\x44\x1e\x69\x97\xf8\xba\x1a\xeb\x9e\xf0\xf4\x91\x17\x06\x67\xa7\xf5\xfc\x96\x27\xcb\xd0\x55\x1b\x76\xbe\x27\x28\x3a\x4b\x0c\x5f\x66\x78\x46\x68\x82\x26\xa1\x15\xee\x80\x20\xdf\x08\x04\x2b\x19\xb5\x9f\xe5\x51\x31\x6a\x6c\xb6\x91\x68\x60\xb9\xec\xd7\x41\x54\xb4\x05\x10\x38\xa1\x73\x52\x37\x2e\xc1\x4d\x3c\x95\x7d\x2e\xf5\x0f\xf7\x86\x18\x9a\x8a\xeb\x9c\x08\xf4\x5e\xeb\x5e\xb8\xb0\x40\x33\x99\x74\xaa\x97\x98\xc4\x25\xd7\xbe\xcb\x22\x8c\x44\x7a\x6d\x0b\x3c\xef\x27\x18\x93\xe0\xf7\x07\x6e\x22\x3a\x7e\x87\xc6\xa3\xd2\x70\xa0\x33\xbc\x97\xa4\x56\x5e\xdc\xe0\xaa\x91\xff\xc3\xf7\x80\x17\x75\xa6\xf2\x9b\x23\x02\x45\xbd\x71\xfa\x03\x43\x53\xde\x37\x23\x95\xd1\xbf\xcb\xde\xbb\xa0\x81\x33\x0f\x7c\x07\x6b\xe9\x9c\x2c\xf4\x86\x7f\x15\xb7\x8d\x52\xf4\x6f\xc7\x39\x1c\x9c\xb9\x5e\x5d\x64\x64\x3b\xaf\xfe\x72\xa8\xe3\xa6\x50\x66\x7f\xbb\x3e"}, -{{0x70,0x3a,0x6e,0x2b,0x62,0xd0,0x09,0x0c,0x61,0xd8,0x65,0x9b,0x6a,0x96,0x3e,0x03,0xc9,0xd6,0x2c,0x1b,0x38,0xf7,0xd7,0x0e,0x5f,0x9f,0xf0,0x55,0x90,0xcd,0x03,0x60,},{0x37,0x0c,0x21,0xde,0x6e,0xf2,0xfa,0xb5,0x34,0xad,0xa9,0x99,0x86,0x9c,0x90,0xbc,0x9b,0x92,0xcc,0xbf,0x24,0x9b,0x79,0xd3,0x9d,0x95,0x44,0x1d,0x1e,0xde,0x21,0x0a,},{0xe5,0xfd,0x64,0xda,0x02,0x88,0x00,0xc6,0xce,0xed,0x06,0x8a,0x5e,0x59,0x6f,0x16,0x21,0xc7,0x0a,0x8c,0xb1,0x38,0xb3,0x1b,0x32,0x64,0x7e,0xb4,0xb0,0x7b,0xd2,0xec,0xc5,0x94,0x2c,0x18,0x84,0x4f,0x36,0x70,0x33,0xf6,0x73,0x98,0xe3,0x14,0xba,0x2c,0x7c,0xcf,0x29,0x9c,0x06,0x97,0x87,0x77,0x70,0x25,0xd8,0x45,0xf2,0xaa,0xd6,0x0e,},"\xd4\x2a\x17\x56\xe8\x4d\xf4\xb4\xe9\x77\x3f\x86\xf7\x67\x4a\x2c\xd7\x8e\x71\xe4\x0a\xa8\xf6\x44\xe6\x70\x2d\xfb\xc2\xc2\xc5\xca\x90\xfc\x24\x2e\x9c\xb0\x09\x9c\xc8\xf2\xc2\xd3\x13\x6b\xaa\xfc\x0f\xf6\x95\x48\x2f\xda\xcd\xef\x9f\x56\x56\x10\xb6\xe1\x90\x07\x22\xf4\x35\xc6\x38\x5b\x35\xe9\xf6\xc4\x36\xca\x03\x7e\x03\xf6\x4e\x22\x33\xdf\xfa\x58\xdb\x3b\x91\xcc\x1d\xaa\x0b\xb0\xc5\x4c\x8a\x43\xe4\x69\xd2\xcf\xf7\xfa\x2b\xf8\xf5\xd1\xd8\x77\x93\x10\x89\xc8\x2e\xd8\x9a\xba\x42\xf2\xee\x2b\x86\xe4\x45\xcf\xd0\x9f\x4c\xd7\x8b\x35\x19\x1b\xf4\x67\xe7\x84\xee\xf7\x5d\xc9\x87\xe0\x46\xd3\x7d\x4d\x4e\x8e\x9b\xbe\x14\xaf\x80\xd0\x3a\x1f\x40\x89\x83\x84\xb9\xd3\x27\x9f\xac\x9c\x57\xfd\x9c\x7e\xec\xbe\x19\xa5\xac\xc1\x50\x33\xb8\x4e\x07\xfd\x0e\x40\x9b\xdb\xd5\xa5\x7f\x65\x64\x11\x83\xa6\xc0\xa8\xec\x42\x6d\x1f\x1d\x22\x31\x66\xff\x0a\x19\x00\xb2\xe9\x2b\x7d\x85\x83\x5d\x01\x9d\x17\x77\x5e\x50\x93\xcc\xd1\x26\xf9\x0f\x63\xcb\x7d\x15\xcb\xeb\x53\x13\x24\x21\x9c\xd6\x4d\xed\x67\x14\xb2\x1a\x65\x37\x1a\xf0\x72\x10\xdf\xdf\x0e\x4e\x58\xdd\xc7\xd5\x9f\x4c\xfa\x65\xc4\x21\xd8\x14\xee\x2c\x9b\xf6\xdb\xf6\x48\x73\xd5\x79\xb0\x9e\xe5\xdc\xed\xd7\x33\x06\x3e\x03\x9a\xc9\xa5\xf9\xca\x4c\x25\x25\xa4\xcc\x8e\x98\x4d\xa7\x18\x5e\x2d\x64\xfa\xd8\x1c\x8a"}, -{{0x76,0x84,0x9c,0x18,0x8e,0x3e,0xdd,0x0f,0xf5,0xf8,0xfb,0x87,0x4d,0xc0,0x45,0x66,0x45,0x51,0x84,0x45,0xe4,0x1a,0x7d,0x68,0x33,0xe6,0x16,0xc3,0xc4,0x8c,0x98,0x68,},{0xd6,0x70,0xe2,0xea,0x07,0xdb,0x60,0xc2,0x2a,0xb7,0x9a,0x93,0xeb,0xf4,0x9d,0x22,0xa6,0x24,0x5e,0xe3,0xaf,0x07,0xb3,0xbe,0x58,0x4e,0xda,0x69,0x4c,0x37,0x72,0x9e,},{0x71,0x41,0x39,0x9d,0x51,0xda,0xa6,0xeb,0x45,0x19,0xbf,0x3f,0x01,0xb2,0x33,0x92,0x0f,0xa9,0x08,0xfe,0xfa,0x61,0x2f,0x0c,0xd7,0xd5,0xaf,0x8a,0x9a,0x3c,0x44,0x19,0x0e,0x3f,0x63,0x84,0xa8,0xd1,0x4d,0x37,0xc9,0x70,0x30,0xef,0x50,0x18,0xcf,0x8a,0xee,0x8a,0xeb,0x15,0x69,0xa7,0x3d,0x84,0x86,0x2a,0x59,0xb7,0xdf,0x72,0xfe,0x09,},"\x1e\xcc\xb0\xbc\x8e\xca\x3a\xb5\xbe\xe6\x8c\x5f\x8c\xaa\x34\x53\x67\x66\xc7\x05\xf5\x08\x27\xdb\x7a\xc3\x75\xd4\xfe\x30\xb5\x8f\xfb\x7e\x2f\xe4\x90\xcc\x71\xa8\xff\x86\xc0\x06\xd6\x17\x4d\x05\x79\x3a\xb8\xa5\x5d\xd5\x1b\x06\xde\x41\x7b\xc0\xac\x45\x2c\xdc\x7c\xfb\x0b\xb0\x03\x62\xb6\x76\x5d\x20\xdb\x23\xeb\x18\x48\x02\x70\x64\xa1\xd9\x09\x1d\x3b\x10\xed\x77\x6f\x28\xb7\x67\x68\xbd\xfc\x08\xf0\xbc\x51\x1f\x76\xfa\xeb\xa7\x6c\xfc\x4c\xb5\xc8\x3d\xc9\xeb\xe8\xa8\xd7\x9e\xdc\xa9\x23\xec\xcd\x52\x40\x09\xca\xfe\xdc\x90\xe3\xad\x87\xd1\x39\x2e\x1f\xcc\xf4\xe6\x0c\xca\xb9\x5d\xc0\xab\x54\xbf\x44\x24\x5a\x00\x7a\x96\xd4\x66\x34\xb1\xb2\x96\x5b\x82\x9c\x3d\x7d\xaa\x76\x59\x72\xb5\x4a\x7b\x36\x5b\x6f\x34\xd7\x7d\x71\x76\xac\xd8\xd8\x94\xf6\xb4\x17\x09\x1b\x6c\x00\xed\xb7\xa4\xe8\x13\x79\x98\x8b\xfc\xec\xb6\x92\xe9\xc3\xc4\x31\x0a\x7e\x24\x0e\x5c\x10\x63\xcd\xe1\x13\xf2\x2a\x68\x4a\x50\xa1\x12\xff\x47\xd3\x89\x88\x12\xef\xb9\x26\x37\x07\x2b\x86\x16\x3a\xd8\x93\x16\xd2\x21\x19\x5a\xcb\xfa\xd0\xa0\x3a\x1f\xbc\x2d\x96\x7f\xe8\x3f\x84\xc8\x45\x9f\xcc\xd4\x90\xb9\xc5\xb3\xe5\x5d\x27\xe9\x48\x4e\x94\x3c\x41\x7f\x21\x28\xd7\x37\x01\xda\x28\xf4\x9f\xd3\x68\x3f\x33\xa3\x9c\xde\xe2\x34\xbd\x30\x5b\x94\x91\xe2\xf3\xeb\x62\x1b\xe3\xdd\x1d\xbb\xb3\x1b"}, -{{0x83,0xae,0x48,0xad,0x70,0xda,0x0b,0xb3,0xcd,0xf8,0x74,0x81,0xee,0x2c,0x0c,0x85,0x71,0xc2,0xca,0x98,0x67,0x12,0xf8,0xbc,0x23,0x29,0xe9,0xa3,0xe3,0x33,0x83,0xc5,},{0xb7,0x85,0x30,0x90,0x00,0xdf,0x95,0xf5,0xa0,0x4f,0x7d,0x89,0xc4,0x11,0x33,0x01,0x05,0x7a,0xda,0xee,0xb2,0x9b,0xcd,0x28,0xd9,0x93,0x71,0xb5,0x37,0xbb,0xa2,0xf6,},{0x43,0x33,0x23,0x51,0xd3,0xfb,0x7b,0x45,0xfc,0xf3,0x7c,0x60,0x7d,0x44,0x2e,0xa8,0x0d,0xbd,0xa2,0xcb,0x69,0xc2,0x88,0x4f,0x42,0x4e,0x65,0xea,0x3a,0x33,0x1e,0xd8,0x47,0x2d,0x43,0x68,0x40,0x5c,0xb7,0x36,0xb2,0xd6,0x68,0x5a,0xd7,0x82,0xe2,0x39,0xfe,0x83,0x3e,0xd7,0x89,0xa2,0x92,0x31,0x85,0x16,0x6f,0x60,0x83,0x42,0xee,0x05,},"\xb7\x52\x1d\x3f\x71\xc6\x79\xfa\x70\x37\xfe\x74\x88\xa6\x41\xf6\xb9\x7c\x49\x45\x4a\xcc\x8e\x36\xb9\x03\xd8\xf9\xeb\xb5\x4d\x89\xcb\x56\xef\xd1\x9e\x04\xba\x6a\x7c\x8f\x48\xa7\xd3\xec\x9d\xec\xd3\xf1\xcd\x0f\xaf\x6e\x97\x81\x18\xe6\xad\xce\x9c\x6c\x6b\xe6\x3c\x6a\x6a\x1a\xe2\x16\x51\x82\x84\x79\xa4\x6b\xc9\xa0\xf7\x94\x30\x40\xf9\x40\xa0\xd4\x70\xc8\xe5\x77\xc5\xd5\x75\xcb\x53\xc1\xbf\x3a\xb1\xfe\xb0\x50\xdc\xb6\xfe\xf0\xba\x44\x47\xf2\x99\xfd\xb9\xf2\x7e\xcb\x07\x14\xec\xfe\xfd\x74\xba\xd7\xb1\x22\xa4\x62\xc2\x4a\x20\x98\x48\xa0\x33\x89\x07\x45\x78\xc5\xbd\xc3\x63\x96\xd8\x09\xb0\xf1\x40\x18\xda\x64\x91\x7e\x6b\xf8\x7e\xf4\x05\xc8\xf3\xe3\x33\xff\x9c\x3b\xaf\x63\x39\x66\x76\x20\x79\x4b\xb4\x74\x3f\x05\x14\xb5\xde\x7d\x7f\xdd\x94\x7a\x7e\x35\x01\xee\x88\xef\xad\x15\x9e\x33\xa1\x07\x2f\xbb\x99\xc7\xc7\x1e\x9d\x13\xa5\x02\xd5\xa0\x7c\x4f\x81\x7e\xeb\x7f\x0c\x53\x19\xaa\x41\xa9\x6d\x5f\xf4\xf1\x5a\x73\xc2\x9b\x57\x1f\xe2\x11\x09\x0e\x17\x2c\x8d\xb5\x18\x62\x46\x12\xa5\xc3\x71\xa9\xd7\xce\xf6\xde\x35\xeb\xef\x96\xe8\x8e\x1a\x78\xaf\x3b\xd5\xdd\x35\x25\x1a\xb5\x4d\x73\x71\x8f\x3e\x70\xd2\xd5\x90\x21\x53\x1d\xc7\x31\x84\xf0\xfc\x69\xc2\xe9\x29\x65\x84\x4e\xc2\x7c\x1c\x02\xaf\x5e\x9a\x34\x69\xde\x35\x5d\xb2\x25\x6e\x0e\xc2\xa4\xeb\xa3\x0a"}, -{{0x39,0xe5,0x6a,0x65,0x62,0x3a,0x0a,0xeb,0xad,0xe0,0xda,0x12,0xce,0x1d,0xf3,0x78,0xbc,0x92,0x40,0x73,0xf7,0x3a,0x54,0x9e,0xff,0xae,0xbc,0x46,0x5d,0x1a,0x78,0xe2,},{0x83,0xda,0x8a,0xd5,0x0b,0xad,0x09,0xeb,0x3e,0x94,0xc7,0x25,0xdf,0x3c,0xc3,0xa1,0x19,0x73,0x6a,0xdc,0x85,0x9c,0xa1,0xa1,0x05,0x03,0xf4,0x8f,0xf2,0xfe,0xc5,0x96,},{0x39,0x8e,0x82,0x60,0x01,0x1f,0x57,0xd8,0xac,0x8c,0x58,0xd5,0x45,0x7b,0xc6,0x52,0xc7,0x41,0x4a,0xaf,0x6f,0xb2,0xf4,0x26,0xb7,0x89,0x90,0x56,0x60,0x5c,0x0a,0xfc,0x28,0x39,0x24,0x23,0xb2,0xb5,0x71,0xf5,0xe6,0xc3,0xc7,0xf6,0xd6,0x02,0x45,0xe5,0x3e,0xbd,0x03,0xbd,0xc5,0xad,0x3c,0x1a,0xd8,0x73,0x8c,0xb3,0x22,0x14,0xd0,0x0f,},"\xa9\x6d\xc2\xea\x3f\xa1\x35\x14\x92\xa4\x61\x9d\x91\x94\x68\x1f\x8e\xc4\x00\xa9\x71\x58\x24\x44\x82\x65\x38\x38\xcc\xb7\xe1\x56\xa8\x2d\x56\x43\x68\xf8\x3a\x6e\xe1\xbe\x46\xbc\x34\xb8\x17\x20\x0e\x84\x64\xc3\xd1\x2b\x5e\xf2\xc5\x0b\x19\x56\x5b\x88\x1c\x4c\x3d\x45\x63\xfb\x94\x7e\xb4\x7c\x3e\xe9\xc1\xee\x78\x53\x26\x98\x74\x45\x5b\xfa\xcb\xa3\x05\xf3\x07\xd1\xac\x53\x09\xee\xae\x5c\x07\xfa\x5c\x4d\x42\x8e\xdb\xc8\xb9\x52\x8c\x44\x15\x24\x3a\x9e\xf5\x80\xaf\xf8\xfc\xfb\x12\x00\x0a\x71\xfc\xee\xe8\x9d\xe9\x7f\x90\x27\x95\x29\xbc\xc8\x22\xed\x3c\xb3\x4c\x82\xba\x5f\xec\x15\xf4\x94\x56\x63\x63\x6d\x67\xb5\xfe\xce\xac\xc3\x1d\x25\xf9\x8a\xea\x07\xf7\x80\x0d\x5a\x10\x34\x25\x1c\xb9\x1d\xd0\x96\x3e\xc2\xc1\xa5\x47\x73\xa4\xd9\x6c\x18\x35\x7f\x8d\x10\x1d\xe5\x8e\x93\x2f\x8c\x6c\xdd\xe8\xe3\xcf\xce\xf5\xa7\x44\x3f\xdb\xa7\xb7\x83\x20\x40\x3c\x01\x96\x84\x47\x24\xa6\x12\x18\x3e\x34\xbd\xd8\x08\xce\x7b\x95\x88\x61\xca\x37\x11\x57\x30\xea\xed\xe1\xfd\x0b\xaa\xbe\x97\x6e\xfe\xfd\x03\x65\xfd\xf9\x26\x77\x6c\x53\x6f\x47\xff\x80\xde\x5c\x18\x29\x1b\xb7\xe9\xf1\xb9\x13\xff\xd1\xd9\x44\x68\xb7\x89\x75\x2f\xae\x6c\xa8\x97\xc0\xcc\xa5\x3e\xf1\xe7\x31\xd0\x0c\x8b\xdb\xe8\x92\x9e\xa6\xb1\xdc\xe1\xf3\x1a\x20\x68\x8d\x37\xb0\xf3\xa2\xb4\x15\x3b\x30\x6b\xdb\xa1"}, -{{0x4b,0x99,0x21,0x85,0x2f,0x40,0x9a,0x32,0x3a,0xe3,0x81,0x75,0xe8,0xd7,0x6a,0x21,0x1f,0xc4,0xd9,0xc6,0x54,0x17,0x8e,0xea,0x3b,0xaa,0x7a,0x76,0x7a,0x6f,0xda,0x06,},{0x4c,0x72,0x3e,0x43,0x6b,0x6b,0xd9,0x7f,0x44,0xaf,0x52,0x50,0x3b,0x21,0xcc,0x50,0xd5,0xf6,0xad,0x6c,0xfc,0x82,0x88,0x34,0x5d,0xde,0x80,0x54,0xe9,0x95,0x58,0x2e,},{0xcb,0xf1,0xf1,0x64,0x2d,0xf9,0x50,0xeb,0x71,0xfd,0x09,0x59,0x0d,0x34,0xc2,0x65,0x92,0x2c,0x58,0xbd,0x80,0x26,0xbb,0xa3,0xfc,0x0e,0x59,0x4a,0x6b,0xb1,0xf2,0xb9,0x0d,0xa3,0xdc,0x1d,0x5f,0x6b,0x6d,0x5b,0x40,0x5a,0x89,0x6d,0x1d,0xbb,0x71,0xb8,0x68,0x5c,0x4d,0xfc,0x44,0x4a,0xca,0xff,0xe6,0x5a,0xb8,0x33,0x17,0x89,0xf5,0x07,},"\x3f\x33\xd8\xfb\x83\xe6\x87\x41\x09\x0a\x37\xbe\xdd\x74\x5c\xf1\x41\xaa\xae\xd8\xc9\x2f\xfa\x74\x2a\x52\x56\x17\x77\x88\x58\x05\xac\xe1\x42\x46\xab\x98\xa8\xcb\x59\x8c\x9c\xe3\xde\x9b\x29\xba\xe5\xfa\x04\xb1\xcf\x82\x8d\xe1\x1a\xff\x80\xa7\xef\x8a\x3a\x38\xae\xde\x4f\x3c\x35\x63\xa2\x5d\x04\x9b\xad\xca\xd5\xed\x7e\x47\xfd\xbb\xa6\xe1\x11\x30\x7e\xeb\xe9\xef\x49\x06\xbc\x98\x97\x28\xb7\x6e\x84\xaf\xe8\x08\xe6\x65\x3b\x27\x1e\x21\x10\x4a\xa6\x65\xf1\x89\x8d\xd2\xaa\xb2\x30\x90\xe2\x2b\x4e\x34\x4a\x26\x16\xfb\xd8\xee\x4a\xd8\xed\x81\x08\x39\x5e\xba\x81\x7f\xbd\x14\xfe\xc5\xc1\x7d\xcf\x56\xb8\x22\x08\x56\xb2\xb8\x33\xe0\x91\x40\x7d\x50\x89\xb3\x5d\xdf\x34\xb8\x6f\xf7\xdc\x9f\xde\x52\xb2\x1e\xf1\x21\x76\xef\x33\x70\xb7\xf3\xa0\xa8\xcb\x1b\x05\x8a\x51\xae\xff\xf3\xd2\x79\xd8\x0f\x51\xa6\x8b\xfb\x59\x25\x87\xb4\x5c\x5c\x63\xa7\xe4\xd6\x25\xb8\x87\xde\x48\x6a\x11\x83\x16\xc3\xb6\xa2\x38\x57\x5f\x92\xac\x5b\x1c\x94\xc3\xf5\xdb\xbd\x96\x68\x60\x00\xd6\xd3\x9c\xcc\xd5\x58\xd4\x20\xe4\xd4\x47\xa8\xcb\xc4\xbc\x7b\x8c\x6a\x03\xaf\x0f\x00\x34\xfb\x35\x18\xd9\x38\x00\xf0\xf7\x13\xe4\xb1\x37\x32\xe1\x6a\xda\x51\x80\x1d\x7e\x55\x9c\xf8\x39\xd1\x05\x8f\x64\x95\x56\x98\x31\x13\x99\x34\x54\x16\x85\x0d\xdd\xcc\x56\x01\xa6\x84\xfd\x09\xe6\xaf\xd3\x94\x4f\x5e\x19"}, -{{0x1b,0xff,0x65,0x2a,0x2c,0x83,0x09,0xa3,0x93,0xac,0x11,0xda,0x3a,0xa9,0x7f,0xb0,0x78,0xbb,0x28,0x4e,0xd5,0xe1,0xb8,0xcc,0xc9,0x83,0x65,0x2e,0xf8,0x55,0x6c,0xd0,},{0xaa,0xab,0xdc,0x09,0x1f,0xc3,0x68,0x23,0x54,0x20,0x17,0x44,0xe9,0xb7,0x3f,0xd2,0xa6,0xcf,0xb2,0x81,0x91,0x4b,0xf2,0xc7,0x0e,0xc3,0xdc,0x1d,0xec,0x72,0x16,0xb0,},{0x93,0xc9,0xc3,0x34,0x93,0xfc,0x64,0x17,0x2d,0x51,0xe1,0x6a,0x0a,0x1c,0xd7,0x29,0xa0,0xd9,0x9e,0x3c,0xb8,0x64,0xe8,0x9a,0x42,0x98,0x7f,0x39,0xdd,0x8c,0xd2,0x65,0x45,0xfd,0xfe,0x37,0x58,0x19,0x11,0xe8,0x03,0x67,0x7d,0xa4,0xc5,0x5b,0x0a,0x68,0x3d,0xdf,0x62,0xb7,0x28,0xf8,0xf3,0x06,0x85,0xae,0x58,0xf6,0x28,0xeb,0xe6,0x09,},"\x48\xd0\x26\x98\xa9\x7b\xdc\xb3\xef\x07\x8d\xcf\xcf\x57\x50\x00\x5f\x17\x02\xd3\x00\xe7\xe8\x9b\xc4\x36\xe3\x81\x11\x34\x01\xf8\x52\xb8\xb4\xac\xff\x60\xff\xbd\x4a\xb4\x6d\x20\x21\x68\xd9\x8b\x87\x35\xe7\x9c\xb3\x50\xe3\x5b\x07\x0f\xf6\xbd\xca\xfd\x95\x4b\x55\x19\x69\xb6\xb1\xa7\x0c\x91\x31\xeb\xd4\x0d\x96\x14\x02\x91\xd8\xd2\xb0\x91\x54\x0a\x8b\x18\xd8\xe5\x46\x59\x15\xc2\x5d\xbc\x6b\x5c\x9a\x68\x79\x42\x53\x3c\x37\x2c\x8b\x4e\x95\xa9\x53\x67\x71\x69\xb9\x50\xed\xd3\x46\x43\x75\xcd\x43\x13\x2f\xf9\xbd\x54\x1e\xe2\x2b\xd4\x18\xce\x23\x19\x5f\x65\xd8\xb2\x89\xf6\x33\xec\x8d\x71\xe1\xa8\x01\xb0\x6c\x3c\x82\x7f\x62\x7e\x72\x3d\x21\x99\x10\x0c\xe7\x3e\x8e\x4a\x44\x40\xe7\x78\x31\x7a\x47\x49\x10\x79\x3b\x47\xb1\x0f\xfb\x55\xdb\x7f\x28\x1c\x7d\x7a\x03\x3b\xd8\x00\x48\xb8\x26\x73\xb8\x7c\xf9\x5e\x99\x42\x2b\xa6\x28\x68\x8f\x3c\x97\x18\x90\xca\x15\xd1\x2f\x57\x2f\xa1\x97\x7a\x17\x30\x70\x69\xda\x30\x4e\xad\x30\x26\xeb\x01\x04\x26\x68\x89\x0d\x17\x00\x8c\xd1\xe9\x2c\x46\xcb\xe9\xc8\x57\xe7\x19\x3d\xe3\xab\xa3\x91\x1e\x4f\x86\xfe\x0a\x16\x98\xab\x7c\xdb\x92\x51\xa8\x42\x4b\x28\x48\xb9\x6a\xd8\x1e\xa2\x39\xd3\x65\xfd\xea\x92\xea\x5c\x04\x73\xd0\xa6\xbb\x1e\x37\x13\x56\xbd\xfa\xd2\xd0\x35\x03\x36\xd3\xe1\x94\x7c\x93\x6f\xd0\xc2\x51\x95\x44\x50\x11\x73\x1b"}, -{{0x00,0x2f,0xdd,0x1f,0x76,0x41,0x79,0x3a,0xb0,0x64,0xbb,0x7a,0xa8,0x48,0xf7,0x62,0xe7,0xec,0x6e,0x33,0x2f,0xfc,0x26,0xee,0xac,0xda,0x14,0x1a,0xe3,0x3b,0x17,0x83,},{0x77,0xd1,0xd8,0xeb,0xac,0xd1,0x3f,0x4e,0x2f,0x8a,0x40,0xe2,0x8c,0x4a,0x63,0xbc,0x9c,0xe3,0xbf,0xb6,0x97,0x16,0x33,0x4b,0xcb,0x28,0xa3,0x3e,0xb1,0x34,0x08,0x6c,},{0x0d,0xf3,0xaa,0x0d,0x09,0x99,0xad,0x3d,0xc5,0x80,0x37,0x8f,0x52,0xd1,0x52,0x70,0x0d,0x5b,0x3b,0x05,0x7f,0x56,0xa6,0x6f,0x92,0x11,0x2e,0x44,0x1e,0x1c,0xb9,0x12,0x3c,0x66,0xf1,0x87,0x12,0xc8,0x7e,0xfe,0x22,0xd2,0x57,0x37,0x77,0x29,0x62,0x41,0x21,0x69,0x04,0xd7,0xcd,0xd7,0xd5,0xea,0x43,0x39,0x28,0xbd,0x28,0x72,0xfa,0x0c,},"\x5a\xc1\xdf\xc3\x24\xf4\x3e\x6c\xb7\x9a\x87\xab\x04\x70\xfa\x85\x7b\x51\xfb\x94\x49\x82\xe1\x90\x74\xca\x44\xb1\xe4\x00\x82\xc1\xd0\x7b\x92\xef\xa7\xea\x55\xad\x42\xb7\xc0\x27\xe0\xb9\xe3\x37\x56\xd9\x5a\x2c\x17\x96\xa7\xc2\x06\x68\x11\xdc\x41\x85\x83\x77\xd4\xb8\x35\xc1\x68\x8d\x63\x88\x84\xcd\x2a\xd8\x97\x0b\x74\xc1\xa5\x4a\xad\xd2\x70\x64\x16\x39\x28\xa7\x79\x88\xb2\x44\x03\xaa\x85\xaf\x82\xce\xab\x6b\x72\x8e\x55\x47\x61\xaf\x71\x75\xae\xb9\x92\x15\xb7\x42\x1e\x44\x74\xc0\x4d\x21\x3e\x01\xff\x03\xe3\x52\x9b\x11\x07\x7c\xdf\x28\x96\x4b\x8c\x49\xc5\x64\x9e\x3a\x46\xfa\x0a\x09\xdc\xd5\x9d\xca\xd5\x8b\x9b\x92\x2a\x83\x21\x0a\xcd\x5e\x65\x06\x55\x31\x40\x02\x34\xf5\xe4\x0c\xdd\xcf\x98\x04\x96\x8e\x3e\x9a\xc6\xf5\xc4\x4a\xf6\x50\x01\xe1\x58\x06\x7f\xc3\xa6\x60\x50\x2d\x13\xfa\x88\x74\xfa\x93\x33\x21\x38\xd9\x60\x6b\xc4\x1b\x4c\xee\x7e\xdc\x39\xd7\x53\xda\xe1\x2a\x87\x39\x41\xbb\x35\x7f\x7e\x92\xa4\x49\x88\x47\xd6\x60\x54\x56\xcb\x8c\x0b\x42\x5a\x47\xd7\xd3\xca\x37\xe5\x4e\x90\x3a\x41\xe6\x45\x0a\x35\xeb\xe5\x23\x7c\x6f\x0c\x1b\xbb\xc1\xfd\x71\xfb\x7c\xd8\x93\xd1\x89\x85\x02\x95\xc1\x99\xb7\xd8\x8a\xf2\x6b\xc8\x54\x89\x75\xfd\xa1\x09\x9f\xfe\xfe\xe4\x2a\x52\xf3\x42\x8d\xdf\xf3\x5e\x01\x73\xd3\x33\x95\x62\x50\x7a\xc5\xd2\xc4\x5b\xbd\x2c\x19\xcf\xe8\x9b"}, -{{0x25,0xb0,0xf0,0xbb,0x3d,0xcb,0x42,0x2a,0x6f,0x3c,0x6c,0x22,0x0e,0xaa,0xdb,0x11,0xdb,0xfe,0x48,0x9c,0x2d,0x45,0x5b,0x27,0x6c,0xef,0xe8,0xcb,0xa0,0x57,0xf9,0xf3,},{0xfe,0x03,0xc9,0xc4,0x39,0x4a,0xdc,0x74,0xb1,0x3f,0x47,0x65,0x4b,0xea,0xd8,0xbc,0x85,0x59,0x58,0xb4,0x19,0x4f,0xda,0xb2,0x09,0x7a,0xc1,0xb1,0x57,0x93,0x3c,0x05,},{0xda,0x50,0xd5,0x24,0x2b,0xf5,0x1c,0x39,0x51,0x78,0x0c,0xaf,0xd9,0x26,0xd6,0x7b,0xdf,0x56,0x40,0xd5,0xd3,0xbb,0x08,0x43,0x38,0x31,0xd5,0x6e,0x48,0xe2,0x59,0x2a,0x1c,0x37,0x59,0x68,0xbb,0x4d,0x2f,0xbe,0xa5,0x61,0x45,0xab,0xf2,0xd8,0x29,0x91,0x36,0x3b,0x15,0x65,0xfa,0x1e,0xff,0xe2,0x14,0x01,0x1a,0x68,0x6e,0x39,0x95,0x0e,},"\x54\xd9\x9f\x96\x9e\xfa\x88\x70\xfc\x20\xfa\x9a\x96\x2b\xb3\x72\x61\x9c\x32\x44\x39\x72\x8a\xf3\x13\x9c\x2a\x07\xe8\xc1\xb2\x9c\x1e\x4e\xed\xc2\xd4\x0b\xa7\x22\xf6\x3c\xe3\x76\x70\x36\x2a\xf6\xf5\x20\x2a\xdd\x66\x8c\x4f\xb4\xd6\x2f\xa8\xba\xcb\xc7\xd0\x7f\xf3\xbd\x38\xc1\x5a\x01\x06\x42\x59\xcc\x34\x13\x48\x61\x63\x29\x67\x46\x05\x41\xa9\x9b\x8d\x51\x82\xbf\x59\x34\x7b\x5a\x59\x87\x9a\xa3\xb0\x91\xa1\xf3\xe0\x41\x35\xbd\x63\x01\xbe\x52\x26\xd4\x89\x5e\x5e\x9c\x2b\x15\xe4\x8e\x5e\xcd\xf4\x41\x29\xe6\x12\x28\x53\xa6\x06\xfc\x11\x84\x66\xfa\x72\x0b\x5a\xb1\x65\x63\x5c\x3b\xde\x04\xd7\x42\x89\x27\x4f\xa0\x35\x47\xac\xcb\xde\x78\x0e\x1f\xa0\xbf\x2c\x56\xf8\x43\x6a\x53\xe7\x38\x78\xa4\x24\xa2\x9a\xa9\xde\x38\x5d\xba\x41\x9a\xe6\xa5\xd1\x2e\x00\x42\x76\x15\x2b\x58\xd3\x25\xb3\x02\x40\x0a\x55\x33\x3c\x38\xcd\xe4\x90\x8a\xe1\xd0\x12\x1c\xbe\xca\x95\x08\x09\xc5\x43\x31\x42\x77\xc1\x48\x5e\x68\xd9\xf9\xc0\xa9\x62\xd1\xb1\xe0\xdd\xa1\xd4\xa5\x2b\x56\xf8\x30\x8a\x80\xb9\x2a\xcc\x9f\x4e\xbc\x3e\xd4\x5d\x91\xa1\x29\xda\x86\x75\x62\x1a\xf6\x76\x70\x3d\xef\x3b\x84\x11\x31\x83\xb2\xe3\xa8\xc5\x61\x57\xf2\x43\xf1\x39\x80\xf3\xd1\x75\x6f\xea\x76\x68\xc9\x15\x03\xd3\x5c\x83\x9a\x21\x20\xc7\x9e\xc9\x54\xfb\x54\x6d\x7b\x54\x2f\x98\x72\x89\x53\x4f\xfd\xef\x62\xd4\x7f\xd5\xec"}, -{{0xbf,0x5b,0xa5,0xd6,0xa4,0x9d,0xd5,0xef,0x7b,0x4d,0x5d,0x7d,0x3e,0x4e,0xcc,0x50,0x5c,0x01,0xf6,0xcc,0xee,0x4c,0x54,0xb5,0xef,0x7b,0x40,0xaf,0x6a,0x45,0x41,0x40,},{0x1b,0xe0,0x34,0xf8,0x13,0x01,0x7b,0x90,0x0d,0x89,0x90,0xaf,0x45,0xfa,0xd5,0xb5,0x21,0x4b,0x57,0x3b,0xd3,0x03,0xef,0x7a,0x75,0xef,0x4b,0x8c,0x5c,0x5b,0x98,0x42,},{0x27,0x9c,0xac,0xe6,0xfd,0xaf,0x39,0x45,0xe3,0x83,0x7d,0xf4,0x74,0xb2,0x86,0x46,0x14,0x37,0x47,0x63,0x2b,0xed,0xe9,0x3e,0x7a,0x66,0xf5,0xca,0x29,0x1d,0x2c,0x24,0x97,0x85,0x12,0xca,0x0c,0xb8,0x82,0x7c,0x8c,0x32,0x26,0x85,0xbd,0x60,0x55,0x03,0xa5,0xec,0x94,0xdb,0xae,0x61,0xbb,0xdc,0xae,0x1e,0x49,0x65,0x06,0x02,0xbc,0x07,},"\x16\x15\x2c\x2e\x03\x7b\x1c\x0d\x32\x19\xce\xd8\xe0\x67\x4a\xee\x6b\x57\x83\x4b\x55\x10\x6c\x53\x44\x62\x53\x22\xda\x63\x8e\xce\xa2\xfc\x9a\x42\x4a\x05\xee\x95\x12\xd4\x8f\xcf\x75\xdd\x8b\xd4\x69\x1b\x3c\x10\xc2\x8e\xc9\x8e\xe1\xaf\xa5\xb8\x63\xd1\xc3\x67\x95\xed\x18\x10\x5d\xb3\xa9\xaa\xbd\x9d\x2b\x4c\x17\x47\xad\xba\xf1\xa5\x6f\xfc\xc0\xc5\x33\xc1\xc0\xfa\xef\x33\x1c\xdb\x79\xd9\x61\xfa\x39\xf8\x80\xa1\xb8\xb1\x16\x47\x41\x82\x2e\xfb\x15\xa7\x25\x9a\x46\x5b\xef\x21\x28\x55\x75\x1f\xab\x66\xa8\x97\xbf\xa2\x11\xab\xe0\xea\x2f\x2e\x1c\xd8\xa1\x1d\x80\xe1\x42\xcd\xe1\x26\x3e\xec\x26\x7a\x31\x38\xae\x1f\xcf\x40\x99\xdb\x0a\xb5\x3d\x64\xf3\x36\xf4\xbc\xd7\xa3\x63\xf6\xdb\x11\x2c\x0a\x24\x53\x05\x1a\x00\x06\xf8\x13\xaa\xf4\xae\x94\x8a\x20\x90\x61\x93\x74\xfa\x58\x05\x24\x09\xc2\x8e\xf7\x62\x25\x68\x7d\xf3\xcb\x2d\x1b\x0b\xfb\x43\xb0\x9f\x47\xf1\x23\x2f\x79\x0e\x6d\x8d\xea\x75\x9e\x57\x94\x20\x99\xf4\xc4\xbd\x33\x90\xf2\x8a\xfc\x20\x98\x24\x49\x61\x46\x5c\x64\x3f\xc8\xb2\x97\x66\xaf\x2b\xcb\xc5\x44\x0b\x86\xe8\x36\x08\xcf\xc9\x37\xbe\x98\xbb\x48\x27\xfd\x5e\x6b\x68\x9a\xdc\x2e\x26\x51\x3d\xb5\x31\x07\x6a\x65\x64\x39\x62\x55\xa0\x99\x75\xb7\x03\x4d\xac\x06\x46\x1b\x25\x56\x42\xe3\xa7\xed\x75\xfa\x9f\xc2\x65\x01\x1f\x5f\x62\x50\x38\x2a\x84\xac\x26\x8d\x63\xba\x64"}, -{{0x65,0xde,0x29,0x7b,0x70,0xcb,0xe8,0x09,0x80,0x50,0x0a,0xf0,0x56,0x1a,0x24,0xdb,0x50,0x00,0x10,0x00,0x12,0x5f,0x44,0x90,0x36,0x6d,0x83,0x00,0xd3,0x12,0x85,0x92,},{0xba,0x8e,0x2a,0xd9,0x29,0xbd,0xce,0xa5,0x38,0x74,0x10,0x42,0xb5,0x7f,0x20,0x67,0xd3,0x15,0x37,0x07,0xa4,0x53,0x77,0x0d,0xb9,0xf3,0xc4,0xca,0x75,0x50,0x4d,0x24,},{0x7a,0x9b,0x73,0x6b,0x01,0xcc,0x92,0xa3,0x34,0x9f,0x1a,0x3c,0x32,0xdb,0xd9,0x19,0x59,0x82,0x53,0x94,0xff,0x44,0x3c,0x56,0x74,0x05,0xe8,0x99,0xc8,0x18,0x5c,0xe8,0xfa,0xd9,0x50,0x0e,0x1f,0xce,0x89,0xd9,0x5a,0x62,0x53,0xc0,0x04,0x77,0x43,0x5a,0xcf,0x04,0xbf,0xf9,0x93,0xde,0x1b,0x00,0x49,0x5d,0xef,0x08,0x34,0xee,0x1f,0x07,},"\x13\x1d\x8f\x4c\x2c\x94\xb1\x53\x56\x5b\x86\x59\x2e\x77\x0c\x98\x7a\x44\x34\x61\xb3\x9a\xa2\x40\x8b\x29\xe2\x13\xab\x05\x7a\xff\xc5\x98\xb5\x83\x73\x9d\x66\x03\xa8\x3f\xef\x0a\xfc\x51\x47\x21\xdb\x0e\x76\xf9\xbd\x1b\x72\xb9\x8c\x56\x5c\xc8\x88\x1a\xf5\x74\x7c\x0b\xa6\xf5\x8c\x53\xdd\x23\x77\xda\x6c\x0d\x3a\xa8\x05\x62\x0c\xc4\xe7\x5d\x52\xaa\xbc\xba\x1f\x9b\x28\x49\xe0\x8b\xd1\xb6\xb9\x2e\x6f\x06\x61\x5b\x81\x45\x19\x60\x6a\x02\xdc\x65\xa8\x60\x9f\x5b\x29\xe9\xc2\xaf\x5a\x89\x4f\x71\x16\xef\x28\xcf\xd1\xe7\xb7\x6b\x64\x06\x17\x32\xf7\xa5\xa3\xf8\xaa\x4c\x2e\x56\x9e\x62\x7a\x3f\x97\x49\xaa\x59\x7b\xe4\x9d\x6b\x94\x43\x6c\x35\x2d\xd5\xfa\x7b\x83\xc9\x2d\x26\x10\xfa\xa3\x20\x95\xca\x30\x21\x52\xd9\x1a\x3c\x97\x76\x75\x0e\x75\x8e\xe8\xe9\xe4\x02\xc6\xf5\x38\x5e\xaa\x5d\xf2\x38\x50\xe5\x4b\xeb\x1b\xe4\x37\xa4\x16\xc7\x11\x5e\xd6\xaa\x6d\xe1\x3b\x55\x48\x25\x32\x78\x7e\x0b\xee\x34\xb8\x3f\x30\x84\x40\x67\x65\x63\x54\x97\xc9\x31\xb6\x2a\x05\x18\xf1\xfb\xc2\xb8\x91\xdc\x72\x62\xc7\xc6\xb6\x7e\xda\x59\x4f\xa5\x30\xd7\x4c\x93\x29\xba\xd5\xbe\x94\xc2\x87\xfb\xcd\xe5\x3a\xa8\x02\x72\xb8\x33\x22\x61\x3d\x93\x68\xe5\x90\x40\x76\xfd\xbc\xc8\x8b\x2c\x0e\x59\xc1\x0b\x02\xc4\x48\xe0\x0d\x1b\x3e\x7a\x9c\x96\x40\xfe\xff\xb9\x52\x3a\x8a\x60\xe1\xd8\x3f\x04\xa4\xb8\xdf\x69\x15\x3b"}, -{{0x08,0x26,0xe7,0x33,0x33,0x24,0xe7,0xec,0x8c,0x76,0x42,0x92,0xf6,0x01,0x5d,0x46,0x70,0xe9,0xb8,0xd7,0xc4,0xa8,0x9e,0x8d,0x90,0x9e,0x8e,0xf4,0x35,0xd1,0x8d,0x15,},{0xff,0xb2,0x34,0x8c,0xa8,0xa0,0x18,0x05,0x8b,0xe7,0x1d,0x15,0x12,0xf3,0x76,0xf9,0x1e,0x8b,0x0d,0x55,0x25,0x81,0x25,0x4e,0x10,0x76,0x02,0x21,0x73,0x95,0xe6,0x62,},{0x4b,0xac,0x7f,0xab,0xec,0x87,0x24,0xd8,0x1a,0xb0,0x9a,0xe1,0x30,0x87,0x4d,0x70,0xb5,0x21,0x34,0x92,0x10,0x43,0x72,0xf6,0x01,0xae,0x5a,0xbb,0x10,0x53,0x27,0x99,0x37,0x3c,0x4d,0xad,0x21,0x58,0x76,0x44,0x1f,0x47,0x4e,0x2c,0x00,0x6b,0xe3,0x7c,0x3c,0x8f,0x5f,0x6f,0x01,0x7d,0x08,0x70,0x41,0x4f,0xd2,0x76,0xa8,0xf4,0x28,0x08,},"\x7f\x9e\x3e\x2f\x03\xc9\xdf\x3d\x21\xb9\x90\xf5\xa4\xaf\x82\x95\x73\x4a\xfe\x78\x3a\xcc\xc3\x4f\xb1\xe9\xb8\xe9\x5a\x0f\xd8\x37\xaf\x7e\x05\xc1\x3c\xda\x0d\xe8\xfa\xda\xc9\x20\x52\x65\xa0\x79\x2b\x52\x56\x3b\xdc\x2f\xee\x76\x63\x48\xbe\xfc\xc5\x6b\x88\xbb\xb9\x5f\x15\x44\x14\xfb\x18\x6e\xc4\x36\xaa\x62\xea\x6f\xca\xbb\x11\xc0\x17\xa9\xd2\xd1\x5f\x67\xe5\x95\x98\x0e\x04\xc9\x31\x3b\xc9\x4f\xbc\x8c\x11\x34\xc2\xf4\x03\x32\xbc\x7e\x31\x1a\xc1\xce\x11\xb5\x05\xf8\x57\x2a\xda\x7f\xbe\x19\x6f\xba\x82\x2d\x9a\x91\x44\x92\xfa\x71\x85\xe9\xf3\xbe\xa4\x68\x72\x00\xa5\x24\xc6\x73\xa1\xcd\xf8\x7e\xb3\xa1\x40\xdc\xdb\x6a\x88\x75\x61\x34\x88\xa2\xb0\x0a\xdf\x71\x75\x34\x1c\x1c\x25\x76\x35\xfa\x1a\x53\xa3\xe2\x1d\x60\xc2\x28\x39\x9e\xea\x09\x91\xf1\x12\xc6\x0f\x65\x3d\x71\x48\xe2\xc5\xce\xb9\x8f\x94\x08\x31\xf0\x70\xdb\x10\x84\xd7\x91\x56\xcc\x82\xc4\x6b\xc9\xb8\xe8\x84\xf3\xfa\x81\xbe\x2d\xa4\xcd\xda\x46\xbc\xaa\x24\xcc\x46\x1f\x76\xee\x64\x7b\xb0\xf0\xf8\xc1\x5a\xc5\xda\xa7\x95\xb9\x45\xe6\xf8\x5b\xb3\x10\x36\x2e\x48\xd8\x09\x5c\x78\x2c\x61\xc5\x2b\x48\x1b\x4b\x00\x2a\xd0\x6e\xa7\x4b\x8d\x30\x6e\xff\x71\xab\xf2\x1d\xb7\x10\xa8\x91\x3c\xbe\x48\x33\x2b\xe0\xa0\xb3\xf3\x1e\x0c\x7a\x6e\xba\x85\xce\x33\xf3\x57\xc7\xae\xcc\xd3\x0b\xfb\x1a\x65\x74\x40\x8b\x66\xfe\x40\x4d\x31\xc3\xc5"}, -{{0x00,0xad,0x62,0x27,0x97,0x7b,0x5f,0x38,0xcc,0xda,0x99,0x4d,0x92,0x8b,0xba,0x90,0x86,0xd2,0xda,0xeb,0x01,0x3f,0x86,0x90,0xdb,0x98,0x66,0x48,0xb9,0x0c,0x1d,0x45,},{0x91,0xa4,0xea,0x00,0x57,0x52,0xb9,0x2c,0xbe,0xbf,0x99,0xa8,0xa5,0xcb,0xec,0xd2,0x40,0xae,0x3f,0x01,0x6c,0x44,0xad,0x14,0x1b,0x2e,0x57,0xdd,0xc7,0x73,0xdc,0x8e,},{0xdc,0x50,0x1d,0xb7,0x9f,0xd7,0x82,0xbc,0x88,0xca,0xe7,0x92,0x55,0x7d,0x5d,0x27,0x3f,0x9b,0xa5,0x60,0xc7,0xd9,0x00,0x37,0xfe,0x84,0xac,0x87,0x9d,0x68,0x4f,0x61,0x2a,0x77,0x45,0x2c,0x44,0x43,0xe9,0x5c,0x07,0xb8,0xbe,0x19,0x2c,0x35,0x76,0x9b,0x17,0xbb,0xdf,0xca,0x42,0x28,0x0d,0xe7,0x96,0xd9,0x21,0x19,0xd8,0x33,0x67,0x0d,},"\xcb\x5b\xc5\xb9\x8b\x2e\xfc\xe4\x35\x43\xe9\x1d\xf0\x41\xe0\xdb\xb5\x3e\xd8\xf6\x7b\xf0\xf1\x97\xc5\x2b\x22\x11\xe7\xa4\x5e\x2e\x1e\xc8\x18\xc1\xa8\x0e\x10\xab\xf6\xa4\x35\x35\xf5\xb7\x9d\x97\x4d\x8a\xe2\x8a\x22\x95\xc0\xa6\x52\x17\x63\xb6\x07\xd5\x10\x3c\x6a\xef\x3b\x27\x86\xbd\x5a\xfd\x75\x63\x69\x56\x60\x68\x43\x37\xbc\x30\x90\x73\x9f\xb1\xcd\x53\xa9\xd6\x44\x13\x9b\x6d\x4c\xae\xc7\x5b\xda\x7f\x25\x21\xfb\xfe\x67\x6a\xb4\x5b\x98\xcb\x31\x7a\xa7\xca\x79\xfc\x54\xa3\xd7\xc5\x78\x46\x6a\x6a\xa6\x4e\x43\x4e\x92\x34\x65\xa7\xf2\x11\xaa\x0c\x61\x68\x1b\xb8\x48\x6e\x90\x20\x6a\x25\x25\x0d\x3f\xda\xe6\xfb\x03\x29\x97\x21\xe9\x9e\x2a\x91\x49\x10\xd9\x17\x60\x08\x9b\x5d\x28\x1e\x13\x1e\x6c\x83\x6b\xc2\xde\x08\xf7\xe0\x2c\x48\xd3\x23\xc6\x47\xe9\x53\x6c\x00\xec\x10\x39\x20\x1c\x03\x62\x61\x8c\x7d\x47\xaa\x8e\x7b\x97\x15\xff\xc4\x39\x98\x7a\xe1\xd3\x11\x54\xa6\x19\x8c\x5a\xa1\x1c\x12\x8f\x40\x82\xf5\x56\xc9\x9b\xaf\x10\x3e\xca\xdc\x3b\x2f\x3b\x2e\xc5\xb4\x69\x62\x3b\xc0\x3a\x53\xca\xf3\x81\x4b\x16\x30\x0a\xed\xbd\xa5\x38\xd6\x76\xd1\xf6\x07\x10\x26\x39\xdb\x2a\x62\xc4\x46\x70\x7c\xe6\x46\x9b\xd8\x73\xa0\x46\x82\x25\xbe\x88\xb0\xae\xf5\xd4\x02\x04\x59\xb9\x4b\x32\xfe\x2b\x01\x33\xe9\x2e\x7b\xa5\x4d\xd2\xa5\x39\x7e\xd8\x5f\x96\x6a\xb3\x9e\xd0\x73\x0c\xca\x8e\x7d\xac\xb8\xa3\x36"}, -{{0x15,0x21,0xc6,0xdb,0xd6,0xf7,0x24,0xde,0x73,0xea,0xf7,0xb5,0x62,0x64,0xf0,0x10,0x35,0xc0,0x4e,0x01,0xc1,0xf3,0xeb,0x3c,0xbe,0x83,0xef,0xd2,0x6c,0x43,0x9a,0xda,},{0x2f,0x61,0xa2,0x6f,0xfb,0x68,0xba,0x4f,0x6e,0x14,0x15,0x29,0xdc,0x26,0x17,0xe8,0x53,0x1c,0x71,0x51,0x40,0x48,0x08,0x09,0x3b,0x4f,0xa7,0xfe,0xda,0xea,0x25,0x5d,},{0xa8,0x17,0xed,0x23,0xec,0x39,0x8a,0x12,0x86,0x01,0xc1,0x83,0x2d,0xc6,0xaf,0x76,0x43,0xbf,0x3a,0x5f,0x51,0x7b,0xcc,0x57,0x94,0x50,0xfd,0xb4,0x75,0x90,0x28,0xf4,0x96,0x61,0x64,0x12,0x5f,0x6e,0xbd,0x0d,0x6b,0xf8,0x6f,0xf2,0x98,0xa3,0x9c,0x76,0x6d,0x0c,0x21,0xfd,0xb0,0xcb,0xfd,0xf8,0x1c,0xd0,0xeb,0x1f,0x03,0xcd,0x8a,0x08,},"\x3e\x3c\x7c\x49\x07\x88\xe4\xb1\xd4\x2f\x5c\xbc\xae\x3a\x99\x30\xbf\x61\x7e\xbd\xff\x44\x7f\x7b\xe2\xac\x2b\xa7\xcd\x5b\xcf\xc0\x15\x76\x09\x63\xe6\xfe\x5b\x95\x6f\xb7\xcd\xb3\x5b\xd5\xa1\x7f\x54\x29\xca\x66\x4f\x43\x7f\x08\x75\x3a\x74\x1c\x2b\xc8\x69\x2b\x71\xa9\x11\x5c\x58\x2a\x25\xb2\xf7\x4d\x32\x98\x54\xd6\x0b\x78\x17\xc0\x79\xb3\x52\x3a\xaf\xf8\x79\x3c\x2f\x72\xff\xf8\xcd\x10\x59\x2c\x54\xe7\x38\xdf\x1d\x64\x52\xfb\x72\xda\x13\x1c\x67\x31\xea\x5c\x95\x3c\x62\xea\x17\x7a\xc1\xf4\x73\x5e\x51\x54\x47\x73\x87\x10\x9a\xfa\xe1\x5f\x3e\xd6\xee\xb0\x86\x06\xe2\x8c\x81\xd4\x38\x6f\x03\xb9\x37\x69\x24\xb6\xef\x8d\x22\x1e\xe2\x95\x47\xf8\x2a\x7e\xde\x48\xe1\xdc\x17\x72\x3e\x3d\x42\x17\x1e\xea\xf9\x6a\xc8\x4b\xed\xc2\xa0\x1d\xd8\x6f\x4d\x08\x57\x34\xfd\x69\xf9\x1b\x52\x63\xe4\x39\x08\x3f\xf0\x31\x85\x36\xad\xff\x41\x47\x30\x8e\x3a\xaf\xd1\xb5\x8b\xb7\x4f\x6f\xb0\x21\x4a\x46\xfd\xcd\x35\x24\xf1\x8d\xf5\xa7\x19\xce\x57\x31\x9e\x79\x1b\x4e\xa6\x06\xb4\x99\xbf\xa5\x7a\x60\xe7\x07\xf9\x4e\x18\xf1\xfe\xd2\x2f\x91\xbc\x79\xe6\x36\x4a\x84\x3f\x9c\xbf\x93\x82\x5c\x46\x5e\x9c\xae\x90\x72\xbc\x9d\x3e\xc4\x47\x1f\x21\xab\x2f\x7e\x99\xa6\x33\xf5\x87\xaa\xc3\xdb\x78\xae\x96\x66\xa8\x9a\x18\x00\x8d\xd6\x1d\x60\x21\x85\x54\x41\x1a\x65\x74\x0f\xfd\x1a\xe3\xad\xc0\x65\x95\xe3\xb7\x87\x64\x07\xb6"}, -{{0x17,0xe5,0xf0,0xa8,0xf3,0x47,0x51,0xba,0xbc,0x5c,0x72,0x3e,0xcf,0x33,0x93,0x06,0x99,0x2f,0x39,0xea,0x06,0x5a,0xc1,0x40,0xfc,0xbc,0x39,0x7d,0x2d,0xd3,0x2c,0x4b,},{0x4f,0x1e,0x23,0xcc,0x0f,0x2f,0x69,0xc8,0x8e,0xf9,0x16,0x2a,0xb5,0xf8,0xc5,0x9f,0xb3,0xb8,0xab,0x20,0x96,0xb7,0x7e,0x78,0x2c,0x63,0xc0,0x7c,0x8c,0x4f,0x2b,0x60,},{0xef,0xe2,0xcb,0x63,0xfe,0x7b,0x4f,0xc9,0x89,0x46,0xdc,0x82,0xfb,0x69,0x98,0xe7,0x41,0xed,0x9c,0xe6,0xb9,0xc1,0xa9,0x3b,0xb4,0x5b,0xc0,0xa7,0xd8,0x39,0x6d,0x74,0x05,0x28,0x2b,0x43,0xfe,0x36,0x3b,0xa5,0xb2,0x35,0x89,0xf8,0xe1,0xfa,0xe1,0x30,0xe1,0x57,0xce,0x88,0x8c,0xd7,0x2d,0x05,0x3d,0x0c,0xc1,0x9d,0x25,0x7a,0x43,0x00,},"\xc0\xfa\xd7\x90\x02\x40\x19\xbd\x6f\xc0\x8a\x7a\x92\xf5\xf2\xac\x35\xcf\x64\x32\xe2\xea\xa5\x3d\x48\x2f\x6e\x12\x04\x93\x53\x36\xcb\x3a\xe6\x5a\x63\xc2\x4d\x0e\xc6\x53\x9a\x10\xee\x18\x76\x0f\x2f\x52\x05\x37\x77\x4c\xde\xc6\xe9\x6b\x55\x53\x60\x11\xda\xa8\xf8\xbc\xb9\xcd\xaf\x6d\xf5\xb3\x46\x48\x44\x8a\xc7\xd7\xcb\x7c\x6b\xd8\x0d\x67\xfb\xf3\x30\xf8\x76\x52\x97\x76\x60\x46\xa9\x25\xab\x52\x41\x1d\x16\x04\xc3\xed\x6a\x85\x17\x30\x40\x12\x56\x58\xa3\x2c\xf4\xc8\x54\xef\x28\x13\xdf\x2b\xe6\xf3\x83\x0e\x5e\xee\x5a\x61\x63\xa8\x3c\xa8\x84\x9f\x61\x29\x91\xa3\x1e\x9f\x88\x02\x8e\x50\xbf\x85\x35\xe1\x17\x55\xfa\xd0\x29\xd9\x4c\xf2\x59\x59\xf6\x69\x5d\x09\xc1\xba\x43\x15\xd4\x0f\x7c\xf5\x1b\x3f\x81\x66\xd0\x2f\xab\xa7\x51\x1e\xcd\x8b\x1d\xde\xd5\xf1\x0c\xd6\x84\x34\x55\xcf\xf7\x07\xed\x22\x53\x96\xc6\x1d\x08\x20\xd2\x0a\xda\x70\xd0\xc3\x61\x9f\xf6\x79\x42\x20\x61\xc9\xf7\xc7\x6e\x97\xd5\xa3\x7a\xf6\x1f\xd6\x22\x12\xd2\xda\xfc\x64\x7e\xbb\xb9\x79\xe6\x1d\x90\x70\xec\x03\x60\x9a\x07\xf5\xfc\x57\xd1\x19\xae\x64\xb7\xa6\xef\x92\xa5\xaf\xae\x66\x0a\x30\xed\x48\xd7\x02\xcc\x31\x28\xc6\x33\xb4\xf1\x90\x60\xa0\x57\x81\x01\x72\x9e\xe9\x79\xf7\x90\xf4\x5b\xdb\xb5\xfe\x1a\x8a\x62\xf0\x1a\x61\xa3\x1d\x61\xaf\x07\x03\x04\x50\xfa\x04\x17\x32\x3e\x94\x07\xbc\x76\xe7\x31\x30\xe7\xc6\x9d\x62\xe6\xa7"}, -{{0x0c,0xd7,0xaa,0x7d,0x60,0x5e,0x44,0xd5,0xff,0xb9,0x79,0x66,0xb2,0xcb,0x93,0xc1,0x89,0xe4,0xc5,0xa8,0x5d,0xb8,0x7f,0xad,0x7a,0xb8,0xd6,0x24,0x63,0xc5,0x9b,0x59,},{0x48,0x89,0x85,0x5f,0xe4,0x11,0x6b,0x49,0x13,0x92,0x7f,0x47,0xf2,0x27,0x3b,0xf5,0x59,0xc3,0xb3,0x94,0xa9,0x83,0x63,0x1a,0x25,0xae,0x59,0x70,0x33,0x18,0x5e,0x46,},{0xbf,0x91,0x15,0xfd,0x3d,0x02,0x70,0x6e,0x39,0x8d,0x4b,0xf3,0xb0,0x2a,0x82,0x67,0x4f,0xf3,0x04,0x15,0x08,0xfd,0x39,0xd2,0x9f,0x86,0x7e,0x50,0x16,0x34,0xb9,0x26,0x1f,0x51,0x6a,0x79,0x4f,0x98,0x73,0x8d,0x7c,0x70,0x13,0xa3,0xf2,0xf8,0x58,0xff,0xdd,0x08,0x04,0x7f,0xb6,0xbf,0x3d,0xdd,0xfb,0x4b,0x4f,0x4c,0xbe,0xef,0x30,0x03,},"\x28\xa5\x5d\xda\x6c\xd0\x84\x4b\x65\x77\xc9\xd6\xda\x07\x3a\x4d\xc3\x5c\xbc\x98\xac\x15\x8a\xb5\x4c\xf8\x8f\xd2\x0c\xc8\x7e\x83\xc4\xbb\xa2\xd7\x4d\x82\xce\x0f\x48\x54\xec\x4d\xb5\x13\xde\x40\x04\x65\xaa\xa5\xee\xe7\x90\xbc\x84\xf1\x63\x37\x07\x2d\x3a\x91\xcd\xe4\x0d\x6e\x0d\xf1\xba\x0c\xc0\x64\x5f\x5d\x5c\xbb\xb6\x42\x38\x1d\x7b\x9e\x21\x1d\x25\x26\x7a\x8a\xcf\x77\xd1\xed\xb6\x9c\x3a\x63\x0f\x5b\x13\x3d\x24\xf0\x46\xa8\x1b\xf2\x2f\xf0\x3b\x31\xd8\x44\x7e\x12\xc3\xf7\xb7\x71\x14\xa7\x0c\xbd\x20\xbb\xd0\x8b\x0b\x38\x27\xa6\xbb\xcf\x90\x40\x9e\x34\x44\x47\xa7\xfb\xc5\x9b\xdd\x97\xd7\x29\x07\x1f\x8d\x71\xdc\xc3\x3e\x6e\xf2\xcb\xab\x1d\x41\x1e\xdf\x13\x73\x4d\xb1\xdd\x97\x03\x27\x6f\x5e\xb2\xd6\xaa\x2c\xb8\x95\x2d\xd6\x71\x2b\xfa\xe8\x09\xce\x08\xc3\xaa\x50\x2b\x81\x35\x71\x3f\xac\x0a\x9c\x25\xb1\xd4\x5b\x6a\x58\x31\xe0\x24\x21\xbb\xa6\x5b\x81\xa5\x96\xef\xa2\x4b\x05\x76\xbd\x1d\xc7\xfd\xfb\x49\xbe\x76\x28\x75\xe8\x1b\xd5\x40\x72\x2b\xc0\x61\x40\xb9\xaa\x2e\xf7\xb8\x4a\x80\x1e\x41\xde\xd6\x8d\x45\x46\xac\x48\x73\xd9\xe7\xce\xd6\x49\xb6\x4f\xad\xaf\x0b\x5c\x4b\x6e\xb8\xd0\x36\x31\x52\x33\xf4\x32\x6c\xa0\x1e\x03\x39\x30\x50\xcd\x02\x7c\x24\xf6\x73\x03\xfb\x84\x6b\xd2\xc6\xb3\xdb\xa0\x6b\xed\x0d\x59\xa3\x62\x89\xd2\x4b\xd6\x48\xf7\xdb\x0b\x3a\x81\x34\x66\x12\x59\x3e\x3d\xdd\x18\xc5\x57"}, -{{0x33,0x37,0x1d,0x9e,0x89,0x2f,0x98,0x75,0x05,0x2a,0xc8,0xe3,0x25,0xba,0x50,0x5e,0x74,0x77,0xc1,0xac,0xe2,0x4b,0xa7,0x82,0x26,0x43,0xd4,0x3d,0x0a,0xce,0xf3,0xde,},{0x35,0x92,0x9b,0xde,0xd2,0x7c,0x24,0x9c,0x87,0xd8,0xb8,0xd8,0x2f,0x59,0x26,0x0a,0x57,0x53,0x27,0xb5,0x46,0xc3,0xa1,0x67,0xc6,0x9f,0x59,0x92,0xd5,0xb8,0xe0,0x06,},{0x98,0x5c,0xa4,0x46,0xdd,0xc0,0x07,0x82,0x7c,0xc8,0xf2,0x85,0x2c,0xbd,0x81,0x15,0xef,0x8c,0x59,0x75,0xe9,0xd7,0xce,0x96,0xd7,0x4d,0xfe,0xd8,0x59,0xaa,0x14,0xa4,0xc1,0x52,0x54,0x00,0x6b,0xea,0x5e,0x08,0x35,0x9e,0xfe,0x26,0x25,0xd7,0x15,0xe0,0x89,0x7e,0xe5,0xa1,0x6f,0x15,0x12,0x03,0xbe,0x50,0x10,0x41,0x86,0x37,0xde,0x05,},"\x27\xa3\x2e\xfb\xa2\x82\x04\xbe\x59\xb7\xff\x5f\xe4\x88\xca\x15\x8a\x91\xd5\x98\x60\x91\xec\xc4\x45\x8b\x49\xe0\x90\xdd\x37\xcb\xfe\xde\x7c\x0f\x46\x18\x6f\xab\xcb\xdf\xf7\x8d\x28\x44\x15\x58\x08\xef\xff\xd8\x73\xed\x9c\x92\x61\x52\x6e\x04\xe4\xf7\x05\x0b\x8d\x7b\xd2\x67\xa0\xfe\x3d\x5a\x44\x93\x78\xd5\x4a\x4f\xeb\xbd\x2f\x26\x82\x43\x38\xe2\xaa\xaf\x35\xa3\x2f\xf0\xf6\x25\x04\xbd\xa5\xc2\xe4\x4a\xbc\x63\x15\x9f\x33\x6c\xf2\x5e\x6b\xb4\x0d\xdb\x7d\x88\x25\xdf\xf1\x8f\xd5\x1f\xc0\x19\x51\xea\xed\xcd\x33\x70\x70\x07\xe1\x20\x3c\xa5\x8b\x4f\x7d\x24\x2f\x81\x66\xa9\x07\xe0\x99\x93\x2c\x00\x1b\xfb\x1e\xc9\xa6\x1e\x0e\xf2\xda\x4e\x84\x46\xaf\x20\x82\x01\x31\x5d\x69\x68\x17\x10\xd4\x25\xd2\x40\x0c\x38\x7d\x7b\x9d\xf3\x21\xa4\xae\xc6\x02\xb9\xc6\x56\xc3\xe2\x31\x0b\xff\x87\x56\xd1\x8b\x80\x21\x34\xb1\x56\x04\xf4\xed\xc1\x11\x14\x9a\x98\x79\xe3\x12\x41\xdd\x34\xf7\x02\xf4\xc3\x49\x61\x7b\x13\x52\x97\x69\xa7\x72\xf5\xe5\x2a\x89\xc0\x98\xe0\xdc\xa5\x92\x06\x67\x89\x3a\x25\x00\x61\xb1\x79\x91\x62\x6e\xb9\x31\x92\x98\x68\x5b\xe4\x6b\x6a\x8b\x68\x42\x24\x44\xfa\x5a\x36\xbc\xf3\xa6\x87\xe2\xec\xcb\x93\x22\xc8\x7d\xc8\x01\x65\xda\x89\x89\x30\x85\x0b\x98\xfc\x86\x3c\xad\xa1\xaa\x99\xc6\xd6\x1c\x45\x1b\x9c\xcf\x48\x74\xc7\xf0\xe7\x5b\x0a\x0c\x60\x2f\x04\x48\x12\xc7\x17\x65\xad\xaf\x02\x02\x53\x95\xb0"}, -{{0xbe,0xed,0xb8,0x07,0x3d,0xf5,0x8f,0x8c,0x1b,0xff,0xbd,0xbd,0x77,0xec,0x7d,0xec,0xb2,0xc8,0x2a,0x9b,0xab,0xec,0xef,0xc0,0x33,0x15,0x07,0xbd,0xc2,0xc2,0xa7,0xe7,},{0xb2,0x7e,0x90,0x8b,0x80,0x5e,0x29,0x6f,0xc3,0x0d,0x2e,0x47,0x4b,0x06,0x0c,0xd5,0x0c,0x0f,0x6f,0x52,0x0b,0x36,0x71,0x71,0x21,0x83,0xbd,0x89,0xd4,0xe7,0x33,0xe9,},{0x8c,0x89,0x0c,0xcc,0xad,0xc7,0x76,0x0e,0x1e,0x82,0xe4,0x3c,0x44,0xb3,0xdc,0x0b,0x68,0x5a,0x48,0xb4,0x79,0xae,0x13,0xcc,0x0a,0x6b,0x05,0x57,0xd0,0xfb,0x1c,0xba,0xbb,0xa6,0x3d,0x2a,0x96,0x84,0x34,0x12,0xea,0x8d,0x36,0xc5,0x0a,0xcb,0xf5,0x2b,0x92,0xcf,0xb2,0xdc,0xe4,0x9d,0xc4,0x8a,0xf6,0xdd,0xcf,0x8e,0xe4,0x7a,0x86,0x08,},"\x35\xca\x57\xf0\xf9\x15\xe5\x20\x9d\x54\xea\x4b\x87\x1f\xfb\x58\x53\x54\xdf\x1b\x4a\x4a\x17\x96\xfb\xe4\xd6\x22\x7d\x3e\x1a\xba\x51\x71\xed\x03\x91\xa7\x9e\x83\xe2\x4d\x82\xfd\xaf\xd1\x5c\x17\xb2\x8b\xf6\xc9\x4d\x61\x8c\x74\xd6\x52\x64\xe5\x8f\xaa\xac\xd2\x90\x28\x72\xfd\xd0\xef\xa2\x2e\x8d\x2d\x7c\xe8\xe3\xb8\x19\x7f\x0c\x36\x15\xb0\xa3\x85\x23\x5f\xa9\xfd\x8e\x45\x64\xee\x6e\x6b\x16\x50\xb4\xcf\xb9\x4d\x87\x2c\x80\x5c\x32\xd4\xf3\xa1\x8f\x96\x64\x61\xd3\xad\xbb\x60\x5f\xa5\x25\x88\x4f\x8e\xb1\x97\x62\x73\x96\xba\x4d\x99\x5d\x78\xac\x02\x94\x8a\x0e\xaa\xbb\x58\x51\x9b\x9a\x8e\x2e\x79\x85\xcd\x1d\xe2\xc7\x1d\x89\x18\xd9\x6a\x01\x68\x66\x0c\xe1\x7c\xdd\xf3\x64\xe3\xec\x0d\x4b\xd9\x0f\x21\x04\x75\x1a\x19\x27\xee\x1d\x23\xf3\xe7\xa6\x98\x40\xed\x04\x0b\x00\xe5\xf6\xe4\x86\x6e\xc5\x88\x13\x14\x9c\xc3\x82\xae\xbf\x61\x62\x60\x8c\x79\x57\x4d\x55\x3f\x47\x23\x0e\x92\x4a\x0e\xf1\xeb\xf5\x5d\x8e\x1a\x52\xab\xb6\x2a\x2d\x7a\xc8\x60\x27\xc7\xc0\x3c\xc8\x3f\xa1\x94\x9d\xa2\x9e\x2f\x30\x37\xab\x98\x6f\xd2\xff\xfe\x65\x0e\x31\x49\xba\xba\xe5\xa5\x0b\x1e\xe9\x69\x6f\x3b\xab\xec\x72\xe2\x96\x97\xc8\x24\x22\x81\x4d\x27\x20\x85\x50\x0f\xd8\x37\xfe\x3c\x7a\x97\x3e\xf4\xc1\x69\xaf\x12\xdd\x7f\x02\x70\x06\x20\xbb\x04\x5b\xdb\xf8\x46\x23\xf3\x26\x35\x05\x70\xb3\xca\xdb\xc9\xae\xa4\x20\x0b\x28\x28\x7e\x17\xab"}, -{{0x91,0x84,0xef,0x61,0x88,0x16,0x83,0x25,0x92,0xbc,0x8e,0xb3,0x5f,0x4f,0xfd,0x4f,0xf9,0x8d,0xfb,0xf7,0x77,0x6c,0x90,0xf2,0xaa,0xd2,0x12,0xce,0x7e,0x03,0x35,0x1e,},{0x68,0x7b,0x77,0x26,0x01,0x0d,0x9b,0xde,0x2c,0x90,0xe5,0x73,0xcd,0x2a,0x2a,0x70,0x2f,0xf2,0x8c,0x4a,0x2a,0xf7,0x0a,0xfc,0x73,0x15,0xc9,0x4d,0x57,0x56,0x01,0xe5,},{0xb3,0xc2,0x4e,0x75,0x13,0x2c,0x56,0x34,0x75,0x42,0x2d,0x5e,0xa4,0x12,0xb5,0xc1,0xe8,0xe6,0xe5,0xea,0x1c,0x08,0xea,0xd1,0x39,0x3c,0x41,0x2d,0xa1,0x34,0xc9,0xa1,0x63,0x82,0x84,0xea,0x7e,0x2c,0xa0,0x32,0xfe,0x3d,0x3e,0x32,0xa9,0x06,0x6a,0x8c,0x88,0x39,0x90,0x3f,0x6e,0xf4,0x6e,0x96,0x6b,0xb5,0xe4,0x92,0xd8,0xc2,0xaa,0x00,},"\x72\x9e\xb7\xe5\x4a\x9d\x00\xc5\x86\x17\xaf\x18\xc3\x45\xb8\xdc\x6e\x5b\x4e\x0f\x57\xde\x2f\x3c\x02\xe5\x4a\x2e\xc8\xf1\x42\x5e\xc2\xe2\x40\x77\x5b\x5a\xb0\xc1\x0f\x84\xac\x8b\xaf\xda\x45\x84\xf7\xe2\x1c\x65\x5f\xae\xcd\x80\x30\xa9\x89\x06\xbd\x68\x39\x8f\x26\xb5\xd5\x8d\x92\xb6\xcf\x04\x5e\x9b\xd9\x74\x3c\x74\xc9\xa3\x42\xec\x61\xce\x57\xf3\x7b\x98\x1e\xac\x4d\x8b\xf0\x34\x60\x88\x66\xe9\x85\xbb\x68\x68\x6a\x68\xb4\xa2\xaf\x88\xb9\x92\xa2\xa6\xd2\xdc\x8c\xe8\x8b\xfb\x0a\x36\xcf\x28\xbb\xab\x70\x24\xab\xfa\x2b\xea\x53\x31\x3b\x66\xc9\x06\xf4\xf7\xcf\x66\x97\x0f\x54\x00\x95\xbd\x01\x04\xaa\x49\x24\xdd\x82\xe1\x54\x13\xc2\x26\x79\xf8\x47\xe4\x8c\xd0\xc7\xec\x1f\x67\x7e\x00\x5f\xec\x01\x77\xfb\xd5\xc5\x59\xfc\x39\xad\xd6\x13\x99\x1f\xba\xea\xe4\xd2\x4d\x39\xd3\x09\xef\x74\x64\x7f\x81\x92\xcc\x4c\x62\xd0\x64\x20\x28\xc7\x6a\x1b\x95\x1f\x6b\xc9\x63\x9d\xeb\x91\xec\xc0\x8b\xe6\x04\x3f\x21\x09\x70\x5a\x42\xc7\xea\xe7\x12\x64\x9d\x91\xd9\x6c\xcb\xbf\xb6\x3d\x8d\x0d\xd6\xdd\x11\x21\x60\xf6\x13\x61\xec\xdc\x67\x93\x92\x9c\xa9\xae\xf9\xab\x56\x94\x4a\x6f\xa4\xa7\xdf\x1e\x27\x9e\xaf\x58\xce\x83\x23\xa9\xcf\x62\xc9\x42\x79\xff\xf7\x44\x0f\xbc\x93\x6b\xaa\x61\x48\x9c\x99\x93\x30\xba\xdc\xb9\xfc\x0e\x18\x4b\xc5\x09\x3f\x33\x0c\xbb\x24\x2f\x71\xfb\x37\x87\x38\xfe\xa1\x05\x11\xdd\x43\x83\x64\xd7\xf7\x6b\xcc"}, -{{0x35,0x4e,0x13,0x15,0x2e,0xe1,0xfe,0x74,0x8a,0x12,0x52,0x20,0x4c,0x65,0x27,0xbd,0xc1,0xb1,0xeb,0x2e,0xb5,0x36,0x78,0x15,0x0e,0x63,0x59,0x92,0x47,0x08,0xd8,0x12,},{0xd4,0x5f,0xf6,0xc5,0xfb,0x83,0xe7,0xbb,0x96,0x69,0xaa,0x89,0x60,0xde,0xb7,0xdb,0xc6,0x65,0xc9,0x88,0x43,0x9b,0x6c,0x9e,0xf6,0x72,0xc6,0x81,0x1d,0xc8,0xbc,0xf6,},{0xde,0x2b,0x46,0xe6,0x5f,0x3d,0xec,0xef,0x34,0x33,0x2e,0x50,0x0f,0x2e,0x11,0x30,0x6f,0xbd,0xcf,0x1b,0xe8,0x5a,0x1c,0x1e,0xe6,0x8b,0xa3,0x04,0x5d,0xce,0xc2,0xc7,0xbe,0x60,0x8d,0x22,0x92,0x7d,0xa1,0xf4,0x4c,0x0e,0x20,0x83,0xae,0x62,0x2c,0xf3,0xc2,0x9d,0x89,0x38,0x87,0x99,0x4e,0xfc,0xfa,0x2c,0xa5,0x94,0xf5,0x05,0x1f,0x03,},"\x8e\x5f\xcc\xf6\x6b\x1b\xa6\x16\x9c\xb6\x85\x73\x3d\x9d\x0e\x01\x90\x36\x1c\x90\xbc\xab\x95\xc1\x63\x28\x5a\x97\xfe\x35\x6d\x2b\xdc\xde\x3c\x93\x80\x26\x88\x05\xa3\x84\xd0\x63\xda\x09\xcc\xd9\x96\x9c\xc3\xff\x74\x31\xe6\x0a\x8e\x9f\x86\x9c\xd6\x2f\xaa\x0e\x35\x61\x51\xb2\x80\xbc\x52\x6e\x57\x7c\x2c\x53\x8c\x9a\x72\x4d\xc4\x8b\xf8\x8b\x70\x32\x1d\x7e\x1e\xee\xdb\x3c\x4a\xf7\x06\x74\x8c\x94\x2e\x67\xbd\xab\xdb\x41\xbe\xc2\x97\x7b\x15\x23\x06\x9e\x31\xe2\x9b\x76\x30\x02\x88\xf8\x8a\x51\xb3\x84\xb8\x0c\xc2\x52\x6f\x16\x79\x34\x0d\xde\xc3\x88\x1f\x5c\xd2\x8b\x03\x78\xd9\xcd\x0a\x81\x2b\x68\xdd\x3f\x68\xf7\xa2\x3e\x1b\x54\xbe\xe7\x46\x6a\xc7\x65\xcf\x38\xdf\x04\xd6\x74\x41\xdf\xa4\x98\xc4\xbf\xfc\x52\x04\x5f\xa6\xd2\xdb\xcd\xbf\xa3\x3d\xfa\xa7\x76\x44\xff\xcc\xef\x0d\xec\xdb\x67\x90\xc7\x0a\x0d\x73\x4e\xc2\x87\xcc\x33\x8c\xb5\xa9\x09\xc0\x05\x51\x89\x30\x11\x69\xc4\xf7\x70\x2c\x05\xc0\x91\x1a\x27\xb1\x6e\xf9\xed\x93\x4f\xa6\xa0\xca\x7b\x13\xe4\x13\x52\x34\x22\x53\x56\x47\x96\x80\x30\xed\xc4\x0c\xd7\x3e\x7d\x6b\x34\x5b\x75\x81\xf4\x38\x31\x6d\x68\xe3\xcd\x29\x2b\x84\x6d\x3f\x4f\x7c\x48\x62\xbc\x7e\x6b\x3f\xb8\x9a\x27\xf6\xf6\x0c\xd7\xdb\x2e\x34\xec\x9a\xae\x10\x13\xfe\x37\xac\xff\x8a\xd8\x88\xcb\x9a\x59\x3e\xf5\xe6\x21\xea\xe5\x18\x6c\x58\xb3\x1d\xcf\xde\x22\x87\x0e\x33\x6d\x33\xf4\x40\xf6\xb8\xd4\x9a"}, -{{0x7f,0xf6,0x2d,0x4b,0x3c,0x4d,0x99,0xd3,0x42,0xd4,0xbb,0x40,0x1d,0x72,0x6b,0x21,0xe9,0x9f,0x4e,0xf5,0x92,0x14,0x9f,0xc3,0x11,0xb6,0x87,0x61,0xf5,0x56,0x7f,0xf6,},{0x7f,0xdf,0xdb,0x9e,0xca,0x29,0xd3,0xf0,0x1d,0x94,0x86,0xd7,0xe1,0x12,0xce,0x03,0xaa,0x37,0xb9,0x13,0x26,0xa4,0x28,0x3b,0x9c,0x03,0x99,0x9c,0x5e,0xda,0x09,0x9a,},{0x05,0x8f,0x79,0x92,0x7f,0xbf,0x61,0x78,0x72,0x48,0x15,0xc7,0xb1,0x1c,0x63,0xba,0xaa,0x90,0xbc,0xc1,0x5d,0x72,0x72,0xbe,0x08,0x2f,0x8a,0x91,0x41,0x86,0x1c,0x81,0x64,0x33,0x05,0x5f,0x6c,0xf6,0x49,0x14,0x24,0x85,0x3f,0x9e,0xc7,0x8b,0xb9,0x1a,0xce,0x91,0x3a,0x93,0x41,0x1b,0x4e,0x5e,0xd5,0x8b,0xc4,0xba,0x57,0x15,0xc6,0x0a,},"\x99\xc4\x4c\x79\x65\x72\xa4\x82\x3f\xc6\xc3\x80\x77\x30\x83\x91\x73\x77\x4c\x05\xdb\xfc\x14\x92\xed\x0d\x00\x50\x9a\x95\xa1\xde\x37\x27\x4b\x31\x35\xed\x04\x56\xa1\x71\x8e\x57\x65\x97\xdc\x13\xf2\xa2\xab\x37\xa4\x5c\x06\xcb\xb4\xa2\xd2\x2a\xfa\xd4\xd5\xf3\xd9\x0a\xb3\xd8\xda\x4d\xcd\xaa\x06\xd4\x4f\x22\x19\x08\x84\x01\xc5\xdc\xee\xe2\x60\x55\xc4\x78\x2f\x78\xd7\xd6\x3a\x38\x06\x08\xe1\xbe\xf8\x9e\xee\xf3\x38\xc2\xf0\x89\x7d\xa1\x06\xfa\xfc\xe2\xfb\x2e\xbc\x5d\xb6\x69\xc7\xc1\x72\xc9\xcf\xe7\x7d\x31\x09\xd2\x39\xfe\x5d\x00\x5c\x8e\xe7\x51\x51\x1b\x5a\x88\x31\x7c\x72\x9b\x0d\x8b\x70\xb5\x2f\x6b\xd3\xcd\xa2\xfe\x86\x5c\x77\xf3\x6e\x4f\x1b\x63\x5f\x33\x6e\x03\x6b\xd7\x18\xbe\xc9\x0e\xe7\x8a\x80\x28\x11\x51\x0c\x40\x58\xc1\xba\x36\x40\x17\x25\x3a\xa8\x42\x92\x2e\x1d\xd7\xd7\xa0\xf0\xfc\x9c\x69\xe4\x3f\xc4\xea\xef\xfa\xaf\x1a\xe5\xfa\x5d\x2d\x73\xb4\x30\x79\x61\x7b\xab\xa0\x30\x92\x3f\xe5\xb1\x3d\x2c\x1c\x4f\xe6\xfa\xc3\xf2\xdb\x74\xe2\x02\x0a\x73\x4b\x61\x21\xa0\x30\x2f\xce\x82\x0b\xa0\x58\x0c\xe6\x13\x53\x48\xfd\xf0\x63\x2e\x00\x08\xdf\x03\xee\x11\x21\x68\xf5\xcf\xa0\x03\x7a\x26\xa1\xf6\x9b\x1f\x13\x17\xed\xf2\xa3\xab\x36\x74\x55\xa7\x7e\x00\x69\x12\x15\xd7\xaa\x31\x33\xc2\x15\x9d\x3d\xa2\xb1\x34\xcf\x04\xf0\xde\xfb\xf0\x7a\x60\x64\x01\x1e\x64\xdd\x14\xd4\xf8\xf0\x64\x35\x66\x55\x42\x88\x04\xc2\x77\x1a"}, -{{0x6c,0xab,0xad,0xd0,0x3f,0x8a,0x2e,0x6e,0xba,0xb9,0x6a,0x74,0xf8,0x0e,0x18,0x16,0x4e,0x4d,0x1b,0x6b,0xaa,0x67,0x8f,0x5a,0x82,0xe2,0x56,0x04,0xaf,0x98,0x9a,0xaf,},{0x2a,0x4a,0x31,0x79,0x56,0x41,0x94,0xe0,0x01,0x00,0xc1,0x8b,0xc3,0x53,0x51,0xd8,0xb1,0x35,0xbb,0xae,0x5b,0x32,0xb2,0x8f,0xce,0x1d,0x7b,0x67,0x66,0xca,0x4b,0x32,},{0x4e,0x65,0xc6,0xc1,0xd4,0x93,0x04,0x5e,0x8a,0x92,0x50,0xe3,0x97,0xc1,0xd1,0xd3,0x0f,0xfe,0xd2,0x4d,0xb6,0x6a,0x89,0x61,0xaa,0x45,0x8f,0x8f,0x0f,0xcb,0x76,0x0c,0x39,0xfe,0x86,0x57,0xd7,0xab,0x8f,0x84,0x00,0x0b,0x96,0xd5,0x19,0x71,0x7c,0xff,0x71,0xf9,0x26,0x52,0x2c,0x1e,0xfe,0xc7,0xf8,0xb2,0x62,0x4e,0xae,0x55,0xf6,0x0c,},"\x27\x9f\x78\xcf\x3b\x9c\xcf\xc6\xe1\xb0\x1e\x1a\x82\xf5\x0e\xd1\x72\xe9\xa8\xe1\xe7\x02\xbb\x15\x66\x1d\xd7\xdc\x3a\x45\x6f\xf7\xa7\xa7\xfd\xfb\x08\x1d\xb3\x86\x70\x79\x63\x0c\x7f\x70\xfd\x75\x32\x92\xec\x60\xec\xbf\x50\x63\x2e\x9a\xa4\x5b\x99\x65\x05\xc6\x6e\x6d\xc3\xc6\xae\x89\x2e\x21\xb6\xa8\x70\x5e\x4b\xba\xe8\xf1\x6a\x33\x78\x55\x4b\x31\xfd\xb0\x13\x9d\xcd\x15\xc9\x6a\x8a\x7e\x4b\x88\x75\x6a\x86\xd1\x8d\xb5\xdc\x74\xfd\x76\x91\x19\x7d\xd8\x8e\x2c\x7d\x5d\xf5\x2b\x04\x93\x44\xcd\xc4\x77\xc9\xcd\x7e\x89\xed\xa9\x9c\xcf\xb1\xd0\x08\x14\xd0\x15\x2b\x96\x54\xdf\x32\x79\x37\x2c\xa5\xf1\x8b\x1c\x94\x6f\x28\x94\xa7\x6b\x07\x9d\xdb\x1c\x3c\xd6\x1f\xbb\x96\x9a\xee\xc9\x19\x3a\x6b\x88\xfb\x7d\x13\x6c\x07\xf9\x82\x1e\x5c\x10\x74\xb4\xe9\x3b\xca\xf6\xfa\x14\xd0\xd1\xd7\xe1\x70\x75\x89\xd7\x7e\xc1\x33\x72\x06\xe5\x3a\x1f\x06\xcc\x26\x67\x2f\xf9\x5c\x13\xd5\xff\x44\x47\x66\x93\x1b\xa3\x0a\x0a\xfd\xcd\xad\xd2\x09\x8e\x9c\x41\xfd\x87\xa3\xf2\x3c\xd1\x6d\xbb\x0e\xfb\xf8\x09\x2c\xe3\x3e\x32\x7f\x42\x61\x09\x90\xe1\xce\xe6\xcb\x8e\x54\x95\x1a\xa0\x81\xe6\x97\x65\xae\x40\x09\xae\xed\x75\x8e\x76\x8d\xe5\x0c\x23\xd9\xa2\x2b\x4a\x06\xdc\x4d\x19\xfc\x8c\xbd\x0c\xde\xf4\xc9\x83\x46\x17\x55\xd0\xa3\xb5\xd6\xa9\xc1\x22\x53\xe0\x95\x68\x33\x9f\xf7\xe5\xf7\x8c\x5f\xdf\x7e\xc8\x9f\x91\x86\xa6\x21\xa8\xc0\xee\xd1\x1b\x67\x02\x2e"}, -{{0x0f,0xa0,0xc3,0x2c,0x3a,0xe3,0x4b,0xe5,0x1b,0x92,0xf9,0x19,0x45,0x40,0x59,0x81,0xa8,0xe2,0x02,0x48,0x85,0x58,0xa8,0xe2,0x20,0xc2,0x88,0xc7,0xd6,0xa5,0x53,0x2d,},{0xd6,0xae,0xe6,0x2b,0xd9,0x1f,0xc9,0x45,0x36,0x35,0xff,0xcc,0x02,0xb2,0xf3,0x8d,0xca,0xb1,0x32,0x85,0x14,0x03,0x80,0x58,0x0c,0xcd,0xff,0x08,0x65,0xdf,0x04,0x92,},{0x7e,0x9a,0xb8,0x5e,0xe9,0x4f,0xe4,0xb3,0x5d,0xcb,0x54,0x53,0x29,0xa0,0xef,0x25,0x92,0x3d,0xe5,0xc9,0xdc,0x23,0xe7,0xdf,0x1a,0x7e,0x77,0xab,0x0d,0xcf,0xb8,0x9e,0x03,0xf4,0xe7,0x85,0xca,0x64,0x29,0xcb,0x2b,0x0d,0xf5,0x0d,0xa6,0x23,0x0f,0x73,0x3f,0x00,0xf3,0x3a,0x45,0xc4,0xe5,0x76,0xcd,0x40,0xbd,0xb8,0x4f,0x1a,0xe0,0x01,},"\x53\xf4\x4b\xe0\xe5\x99\x7f\xf0\x72\x64\xcb\x64\xba\x13\x59\xe2\x80\x1d\xef\x87\x55\xe6\x4a\x23\x62\xbd\xda\xf5\x97\xe6\x72\xd0\x21\xd3\x4f\xfa\xce\x6d\x97\xe0\xf2\xb1\xf6\xae\x62\x5f\xd3\x3d\x3c\x4f\x6e\x9f\xf7\xd0\xc7\x3f\x1d\xa8\xde\xfb\x23\xf3\x24\x97\x5e\x92\x1b\xb2\x47\x32\x58\x17\x7a\x16\x61\x25\x67\xed\xf7\xd5\x76\x0f\x3f\x3e\x3a\x6d\x26\xaa\xab\xc5\xfd\xe4\xe2\x04\x3f\x73\xfa\x70\xf1\x28\x02\x09\x33\xb1\xba\x3b\x6b\xd6\x94\x98\xe9\x50\x3e\xa6\x70\xf1\xed\x88\x0d\x36\x51\xf2\xe4\xc5\x9e\x79\xca\xbc\x86\xe9\xb7\x03\x39\x42\x94\x11\x2d\x5d\x8e\x21\x3c\x31\x74\x23\xb5\x25\xa6\xdf\x70\x10\x6a\x9d\x65\x8a\x26\x20\x28\xb5\xf4\x51\x00\xcb\x77\xd1\x15\x0d\x8f\xe4\x61\xee\xd4\x34\xf2\x41\x01\x5f\x32\x76\xad\x7b\x09\xa2\x91\xb4\xa7\xf3\x5e\x3c\x30\x05\x1c\xbf\x13\xb1\xd4\xa7\xfa\x0c\x81\xa5\x0f\x93\x9e\x7c\x49\x67\x3a\xfd\xc8\x78\x83\xc9\xe3\xe6\x1f\x5a\x1d\xf0\x37\x55\x47\x0f\xda\x74\xbf\x23\xea\x88\x67\x6b\x25\x8a\x97\xa2\x80\xd5\xf9\x0b\x52\xb7\x14\xb5\x96\x03\x5b\xae\x08\xc8\xd0\xfe\x6d\x94\xf8\x94\x95\x59\xb1\xf2\x7d\x71\x16\xcf\x59\xdd\x3c\xfb\xf1\x82\x02\xa0\x9c\x13\xf5\xc4\xfb\xc8\xd9\x72\x25\x49\x28\x87\xd3\x28\x70\xc2\x29\x7e\x34\xde\xbd\x98\x76\xd6\xd0\x1a\xc2\x7a\x16\xb0\x88\xb0\x79\x07\x9f\x2b\x20\xfe\xb0\x25\x37\xcd\xa3\x14\xc4\x3c\xb2\xdc\xa3\x71\xb9\xdf\x37\xed\x11\xec\x97\xe1\xa7\xa6\x99\x3a"}, -{{0x7b,0x06,0xf8,0x80,0x26,0xfa,0x86,0xf3,0x9f,0xce,0x24,0x26,0xf6,0x7c,0xc5,0x99,0x6b,0xed,0xd0,0xcf,0xc4,0xb5,0xeb,0xb1,0xb5,0xe3,0xed,0xbb,0x47,0xe0,0x80,0xaa,},{0x3f,0x14,0x69,0xee,0x6a,0x2e,0x78,0x67,0xe2,0xe9,0x01,0x2d,0x40,0x2c,0xf5,0xa4,0x86,0x14,0x97,0xc0,0x1d,0xf8,0x79,0xa1,0xde,0xb1,0xc5,0x39,0x83,0x0b,0x58,0xde,},{0x42,0xf1,0x33,0xe3,0x4e,0x3e,0xb7,0x03,0x2a,0x13,0x3e,0xd7,0x81,0x53,0x7e,0xc6,0x2e,0x44,0xa5,0xce,0x83,0x81,0xe5,0xe0,0xbf,0x9e,0x13,0xa9,0x14,0xa4,0xb2,0xc7,0x57,0x81,0x1d,0x6d,0x3b,0x1e,0x86,0x67,0x24,0x24,0xea,0x42,0x30,0xd1,0x0f,0x7c,0x61,0x0a,0xbb,0x70,0x69,0xe6,0x1e,0x31,0x9b,0x40,0x66,0xa2,0xbd,0x7b,0xc9,0x00,},"\x71\x17\x5d\x4e\x21\x72\x12\x97\xd9\x17\x6d\x81\x7f\x4e\x78\x5d\x96\x00\xd9\x23\xf9\x87\xfe\x0b\x26\xfd\x79\xd3\x3a\x5e\xa5\xd1\xe8\x18\xb7\x1f\x0f\x92\xb8\xc7\x3a\xfd\xda\xbd\xcc\x27\xf6\xd1\x6e\x26\xaa\xfa\x87\x4c\xfd\x77\xa0\x0e\x06\xc3\x6b\x04\x14\x87\x58\x2b\xb9\x33\x76\x0f\x88\xb4\x19\x12\x73\x45\x77\x6e\xa4\x18\xf8\x35\x22\x25\x4f\xed\x33\x81\x9b\xc5\xc9\x5f\x8f\x84\x04\xcc\x14\x4e\xbf\x14\x86\xc8\x85\x15\x40\x9d\x34\x33\xaa\xf5\x19\xd9\x92\x0f\x52\x56\xe6\x29\x41\x9e\x9a\x95\x58\x0a\x35\xb0\x69\xb8\xd2\x55\x33\xdf\xcb\xc9\x8a\xd3\x64\x04\xa9\x51\x80\x8e\x01\x37\x8c\x03\x26\x63\x26\xd1\x20\x04\x69\x75\xfd\xe0\x7d\xae\xf3\x26\x6c\xaa\xcd\x82\x1c\x14\x03\x49\x9d\x7f\xdf\x17\xc0\x33\xc8\xd8\xc3\xf2\x8f\x16\x2b\x5f\x09\xdf\xda\xca\x06\x28\x5f\x00\xc6\xcb\x98\x6d\xfd\xf5\x15\x1a\xa6\x63\x96\x08\xb5\xb1\x3e\x78\xd6\x5a\x43\x68\x58\x5b\x16\x13\x87\x54\xfb\xd1\x13\x83\x5a\x68\x6c\xd0\x66\xc2\xb8\x9b\xb0\x95\x3c\x24\xd5\x0e\x77\xbf\x0f\xc4\x57\xc1\xe0\xfc\xf5\xd4\x4d\xa8\xdb\x9a\x88\xf0\x62\xbe\x3b\x68\x8d\x5c\xdc\xff\x1d\x1c\x00\xe8\x1e\xc9\xd4\x13\x88\x22\x95\xb3\x41\xfe\xe8\xfa\x42\x7d\xc1\x09\xad\xeb\x5f\x28\x4e\xec\x20\x2f\x1b\xef\x11\x5b\xf9\x6b\x17\x82\xd3\xcc\xde\xb6\x82\xb6\x9b\xf9\x2d\x17\x0c\x00\x7d\x5d\xf8\x0e\x1e\xd9\x62\xf6\x77\xdc\x24\xa1\x45\xa1\xe4\xe8\x29\xe8\xde\xc0\x10\x4e\x5f\x78\x36\x59\x44"}, -{{0xc3,0xf5,0xe1,0x49,0x96,0x8a,0x24,0xf4,0xde,0x91,0x19,0x53,0x19,0x75,0xf4,0x43,0x01,0x5c,0xcc,0xa3,0x05,0xd7,0x11,0x9e,0xd4,0x74,0x9e,0x8b,0xf6,0xd9,0x4f,0xc7,},{0x39,0xaa,0xcc,0xdb,0x94,0x8a,0x40,0x38,0x53,0x8a,0x45,0x88,0x32,0x2f,0x80,0x6b,0xb1,0x29,0xb5,0x87,0x6c,0x4b,0xec,0x51,0x27,0x1a,0xfe,0x4f,0x49,0x69,0x00,0x45,},{0x5f,0xa2,0xb5,0x31,0x67,0x7b,0x00,0xb8,0x5b,0x0a,0x31,0x3c,0xbd,0x47,0x9f,0x55,0xf4,0xab,0x3e,0xc5,0xcf,0xce,0x5e,0x45,0x4d,0x2b,0x74,0x17,0x6c,0xcc,0x33,0x99,0xc8,0x99,0xf9,0xd6,0xb5,0x1e,0xd4,0xc1,0xe7,0x61,0x85,0xac,0x9f,0xe7,0x30,0xc4,0xb4,0x01,0x40,0x44,0xf7,0x04,0x11,0x85,0xbc,0x3c,0x85,0x72,0x2e,0xb2,0xea,0x02,},"\xc4\x63\x70\xe3\x7f\x2e\x0c\xad\xcf\x93\x40\x2f\x1f\x0c\xb0\x48\xf5\x28\x81\xba\x75\x0b\x7a\x43\xf5\x6a\xb1\x1c\xe3\x48\x73\x2f\xb5\x7e\x7f\x9a\xaf\x8d\xfc\xbe\x45\x5e\x14\xe9\x83\xc2\x48\xd0\x26\xa2\x7e\x7f\x14\x8d\x5d\xb5\xa5\x3f\x94\x63\x57\x02\xb8\x95\x12\x77\x71\x04\x7a\x87\x6d\x14\x10\x73\x86\xc5\xe0\xff\x89\x33\x34\x5b\xbd\x7a\x93\x6d\x99\x0d\x33\xef\xa2\x8c\x2e\xc4\xe4\x86\x4f\xfd\x2f\xf5\x76\xf7\xc8\x8f\x95\x4c\xfc\x1c\x45\x9e\x88\x3b\xb7\x12\xda\xe3\xcd\xf6\x63\x20\x66\xf1\xf4\xd1\x3a\x50\x96\x15\xb3\x36\x0c\xad\xc5\xa3\x07\xf2\x3e\x52\xa5\x1b\x40\xa6\xfe\xeb\xe0\xb1\x8d\x0e\x9e\xe4\xe3\x48\xf3\x3c\xd8\x1a\x8d\xef\x22\x2f\x6a\x59\xb1\x28\x61\xd3\x35\xbd\x9a\xf8\x5c\xc0\x04\xbe\x46\xf1\xd3\xa4\x24\xf4\x87\x0a\xe9\xdc\x58\x7e\x5a\x4a\xde\x13\x6b\x93\x70\x64\x93\x48\xc3\x3a\xc3\xbf\x1f\xeb\xee\xbf\xfe\xa3\x70\x85\xed\x59\xca\xc9\xd9\xe6\x96\x47\x0b\x23\x46\x09\xe9\xa1\x0a\x9d\x43\x1f\xf9\x1e\x69\xcb\x51\x35\xfd\x11\x7f\xf5\x8a\x36\x53\x97\x44\xeb\xe7\x0c\xea\x69\x73\xc0\x0c\x7a\x4d\x57\xb6\x2f\x4a\x71\x36\xd7\x31\xb8\xe4\x6f\xf1\x8e\xc0\xed\x69\x07\x00\x31\x90\x50\x75\xd8\x54\x1d\x56\x8c\xfc\xe6\xee\xb7\x62\x42\xb7\x81\x9a\x7b\x6a\x93\x55\x21\x11\xbb\x88\xf1\x65\x52\x7c\xfa\x69\x66\xd3\x9f\xcb\xe0\xa7\xde\xa0\x08\xe3\x9c\x7a\x3e\x57\x7a\xb3\x07\xcd\x1d\x0e\xa3\x26\x83\x3d\x52\x65\x4e\x17\x29\x55\xf3\xfc\xd4"}, -{{0x42,0x30,0x5c,0x93,0x02,0xf4,0x5e,0xa6,0xf8,0x7e,0x26,0xe2,0x20,0x8f,0xd9,0x4b,0x3c,0x4a,0xd0,0x37,0xb1,0xb6,0xc8,0x3c,0xf6,0x67,0x7a,0xa1,0x09,0x6a,0x01,0x3c,},{0x3b,0x97,0xb1,0xf1,0x1c,0xe4,0x5b,0xa4,0x6f,0xfb,0xb2,0x5b,0x76,0xbf,0xc5,0xad,0x7b,0x77,0xf9,0x0c,0xc6,0x9e,0xd7,0x61,0x15,0xde,0xa4,0x02,0x94,0x69,0xd5,0x87,},{0x18,0xd0,0x5e,0x5d,0x01,0x66,0x8e,0x83,0xf4,0x0f,0xa3,0xbb,0xee,0x28,0xb3,0x88,0xac,0xf3,0x18,0xd1,0xb0,0xb5,0xad,0x66,0x8c,0x67,0x2f,0x34,0x5c,0x8e,0xda,0x14,0xc2,0xf8,0x84,0xcd,0x2a,0x90,0x39,0x45,0x9c,0xe0,0x81,0x0b,0xc5,0xb5,0x80,0xfe,0x70,0xd3,0x96,0x4a,0x43,0xed,0xb4,0x9e,0x73,0xa6,0xff,0x91,0x4b,0xbf,0x04,0x0c,},"\xd1\x10\x82\x8d\x44\x91\x98\xd6\x75\xe7\x4e\x8e\x39\x43\x9f\xd1\x5e\x75\xbf\x2c\xc1\xf4\x30\xab\xfb\x24\x58\x36\x88\x5b\xaf\xc4\x20\xf7\x54\xb8\x9d\x2f\xbb\xf6\xdd\x34\x90\x79\x2e\x7a\x4f\x76\x60\x73\xcf\xe3\xb3\x02\xd0\x89\x83\x1a\xce\x86\x9e\x27\x30\xfd\xe4\x5c\x21\x21\xec\x3e\xf2\x17\xaa\x9c\x43\xfa\x7c\xc7\xe9\xed\x0a\x01\xad\x9f\x1d\x2f\xc3\x61\x36\x38\xca\x9f\xc1\x93\xc9\x8b\x37\x45\x5b\xf5\xdb\xf8\xf3\x8b\x64\x70\x8d\xfd\xca\x6c\x21\xf0\x97\x5f\x10\x17\xc5\xda\x5f\x64\x34\xbd\xa9\xf0\x33\xce\xc2\xa6\x31\xab\x50\x31\x8e\x01\x7b\x17\x0b\x24\x0b\xf0\x1e\xb8\xb3\x6c\x7e\x1c\xb5\x9e\x77\x36\xac\x34\x44\x42\x08\x13\x2a\x8f\x59\xe4\xf3\x13\xd6\x5d\x84\x9c\x6a\x4f\xdf\x13\xe2\x0e\xca\xee\x38\x23\xe5\x89\xa1\x71\xb3\x9b\x24\x89\x49\x7b\x06\xe6\xff\x58\xc2\xc9\xf1\xdc\x5d\x3a\xa3\xbd\x10\xe6\x44\x3e\x22\xd4\x2d\x07\xb7\x83\xf7\x9f\xd4\x3a\x46\xe1\xcd\xe3\x14\xb6\x63\xa9\x5f\x72\x46\xde\xa1\x31\xfc\xd4\x6d\x1d\xc3\x33\xc5\x45\x4f\x86\xb2\xc4\xe2\xe4\x24\xde\xa4\x05\xcc\x22\x30\xd4\xdc\xd3\x9a\x2e\xab\x2f\x92\x84\x5c\xf6\xa7\x99\x41\x92\x06\x3f\x12\x02\x74\x9e\xf5\x2d\xcb\x96\xf2\xb7\x9e\xd6\xa9\x81\x18\xca\x0b\x99\xba\x22\x85\x49\x08\x60\xeb\x4c\x61\xab\x78\xb9\xdd\xc6\xac\xc7\xad\x88\x3f\xa5\xe9\x6f\x9d\x02\x91\x71\x22\x3a\xbf\x75\x73\xe3\x62\x30\xe0\xa8\x1f\x6c\x13\x11\x15\x14\x73\xee\x26\x4f\x4b\x84\x2e\x92\x3d\xcb\x3b"}, -{{0xc5,0x7a,0x43,0xdc,0xd7,0xba,0xb8,0x51,0x60,0x09,0x54,0x69,0x18,0xd7,0x1a,0xd4,0x59,0xb7,0x34,0x5e,0xfd,0xca,0x8d,0x4f,0x19,0x92,0x98,0x75,0xc8,0x39,0xd7,0x22,},{0x20,0x83,0xb4,0x44,0x23,0x6b,0x9a,0xb3,0x1d,0x4e,0x00,0xc8,0x9d,0x55,0xc6,0x26,0x0f,0xee,0x71,0xac,0x1a,0x47,0xc4,0xb5,0xba,0x22,0x74,0x04,0xd3,0x82,0xb8,0x2d,},{0x1e,0xde,0xf9,0xbc,0x03,0x69,0x71,0xf1,0xfa,0x88,0xed,0xf4,0x53,0x93,0xc8,0x02,0xe6,0xc1,0xa1,0x63,0x1c,0x8a,0x06,0x87,0x1a,0x09,0xa3,0x20,0x82,0x1d,0xce,0x40,0xbe,0xca,0x97,0xe5,0x3a,0x03,0x61,0xa9,0x55,0xa4,0xc6,0xd6,0x0b,0x8c,0xa8,0xe4,0x00,0xc8,0x13,0x40,0x91,0x1c,0xcb,0x4f,0x56,0x28,0x40,0x41,0xcd,0xbb,0x18,0x04,},"\xa4\xf6\xd9\xc2\x81\xcf\x81\xa2\x8a\x0b\x9e\x77\x49\x9a\xa2\x4b\xde\x96\xcc\x12\x64\x37\x44\x91\xc0\x08\x29\x4e\xe0\xaf\x6f\x6e\x4b\xbb\x68\x63\x96\xf5\x90\x68\xd3\x58\xe3\x0f\xe9\x99\x2d\xb0\xc6\xf1\x66\x80\xa1\xc7\x1e\x27\xa4\xa9\x07\xac\x60\x7d\x39\xbd\xc3\x25\x8c\x79\x56\x48\x2f\xb3\x79\x96\xf4\xbe\xb3\xe5\x05\x1b\x81\x48\x01\x9a\x1c\x25\x6e\x2e\xe9\x99\xeb\xc8\xce\x64\xc5\x4e\x07\xfe\xdb\x4f\xbd\x89\x53\xeb\xd9\x3b\x7d\x69\xce\x5a\x00\x82\xed\xd6\x20\x9d\x12\xd3\x61\x9b\x4f\xd2\xea\xe9\x16\x46\x1f\x72\xa4\xce\x72\x71\x57\x25\x1a\x19\x20\x9b\xbf\xf9\xfb\xdb\xd2\x89\x43\x6f\x3f\xca\xcc\x6b\x4e\x13\x18\x52\x1a\x47\x83\x9c\xba\x4b\x14\xf7\xd7\xa2\x1e\x7b\x5d\x6b\x6a\x75\x3d\x58\x04\xaf\xcd\x2b\x1e\xb7\x77\x9b\x92\xab\xab\x8a\xfa\x8a\xa4\xfa\x51\xca\xec\x0b\x85\xdc\xd0\xfc\x2a\x06\x76\x03\x6d\x3f\x56\x63\x0a\x83\x1f\xfe\xb5\x02\x86\x1d\xd8\x91\x61\xc7\x08\xa9\xc0\x06\xc7\x3c\x93\x0c\xe5\xb9\x47\x56\x42\x6f\xf1\x8a\xa1\x12\xfb\x4e\xb9\xa6\x85\x00\xb4\x8d\x4e\xed\xbd\x41\x67\xb6\xff\xd0\xa1\x1d\x49\x44\x3a\x17\x3c\xe9\xd9\x49\x43\x67\x48\xfc\x06\x34\xf0\x6b\xb0\x8b\x8f\x34\x23\xf4\x46\x3d\xba\x7b\x4d\x19\x9b\x64\xdf\x57\x81\x17\xf0\xa2\x64\x5f\x0b\x2a\x1e\x2a\xda\x27\xd2\x86\xf7\x67\x33\xf2\x5b\x82\xed\x1d\x48\xa5\xc3\x89\x8d\x4a\xd6\x21\xe5\x0e\xd9\x06\x0d\xaa\xd4\x0a\x39\x53\x2e\x4d\x1b\xf1\x62\xce\x36\x80\x4d\x5d\x4e\x2d"}, -{{0x2d,0xdd,0xb6,0xb8,0xfd,0x04,0xfa,0x90,0xec,0xe1,0xa7,0x09,0xf8,0x41,0x8f,0x2e,0x5d,0x0c,0x9c,0x43,0xaf,0xe7,0xcf,0xce,0x19,0xe6,0xad,0x15,0xa7,0x34,0x76,0xf7,},{0x80,0x59,0xde,0x6a,0x7c,0x47,0x76,0x48,0x9e,0xcc,0x2e,0x7d,0x70,0x7f,0xfc,0xe3,0x02,0x85,0xbf,0x30,0xa2,0x3f,0x78,0xd7,0x2d,0xb4,0x9c,0xfd,0x6e,0xd0,0xd4,0x92,},{0xc6,0x34,0xea,0x7b,0xf7,0x2e,0x89,0x5a,0x2e,0x79,0x6e,0x28,0x34,0x20,0x14,0x15,0xb8,0xb4,0x5e,0x05,0xe0,0x45,0x55,0x92,0x84,0xeb,0x90,0x52,0xc0,0xe8,0x4f,0x62,0xa5,0xa9,0xf0,0xc9,0x76,0x4f,0x75,0x76,0x78,0x8c,0x72,0x28,0xb1,0x9e,0xf5,0x17,0xc1,0x95,0x49,0x73,0x25,0xa4,0x8a,0x93,0x44,0xb1,0x47,0xc1,0x2f,0xd7,0x55,0x09,},"\x47\x4b\xaa\x59\x0a\x4c\xd7\x2d\x54\x24\xe5\x1d\x82\x57\xb3\xd4\x43\x25\xbc\x4c\x50\x63\xa0\x03\x3c\x86\xeb\xbe\x99\xed\x72\x12\x18\x4c\x19\x94\x4d\x08\x2a\x11\x53\x79\xdd\x4c\xec\xe9\x73\xfa\xa0\xbc\xa6\x48\x5b\xd2\x5f\x37\x44\xa7\x19\xe7\x0a\xa0\x29\x1e\x1b\x5a\x96\xe6\x37\xc1\x40\x61\x6a\x98\x26\x33\x57\xc7\x6b\x6e\xb0\x08\x3f\xe5\x14\x14\xe3\x86\x87\x0d\x0f\xdc\x7d\xd9\xab\xe4\xff\x6f\xb5\xbb\xf1\xe7\xb1\x5d\xac\x3e\x08\xe2\x61\x5f\x65\x5c\x31\x04\xce\xb3\x2a\x4c\xc2\xc9\xe9\xc4\x3c\xf2\x82\xd3\x46\xac\x25\x3c\xcc\x46\xb6\x35\xae\x04\x09\x73\xb4\x97\x35\x72\x0f\xfb\x89\x04\x69\xa5\x67\xc5\x82\x4e\x0c\x00\xd7\xcc\xd5\x50\x9a\x71\x80\x92\xa9\x06\x46\x1c\x4d\x61\x63\xea\xf4\x22\x41\x8f\x5f\xc6\xe0\x09\xfc\x3f\x52\x9a\xc6\x1a\x2f\x89\xbb\x8e\x0e\xd4\x5d\x94\x0c\x4c\x23\x31\xff\x8d\x8e\x1d\x6d\x58\xd4\x17\xd8\xfc\x26\x56\xa0\x2e\x87\x01\xae\xe7\x5a\xed\x91\x87\x24\xee\xbe\x4a\x2c\xf4\x74\x4c\x5c\x40\x1e\x21\x70\x23\xdf\x68\xa6\xf6\xa0\x22\x8b\xd0\x5a\x67\x9a\x69\x7d\x8d\xe7\x03\x6b\x9e\xd2\x69\x09\x0d\x3c\x65\x48\x6a\xfb\x91\xe2\x79\x54\xeb\x15\xb9\x64\x66\x5e\xde\x7a\xd0\x08\xf1\x2f\xb3\xa9\xd0\xe6\x9c\x13\xb4\x25\x4f\x43\x81\x9e\x08\x18\xa4\x19\x5f\x68\xb8\xa3\x8a\xe8\x1f\x3f\xcb\x18\x79\xc9\x5a\xb4\xcd\x0f\xfc\x38\xe3\x81\x08\x92\x60\xcc\xa9\x67\xac\xe5\xa0\x85\xb4\x57\xab\x5e\xb3\x63\x85\x21\x01\x37\x75\x70\xf9\xac\x9e\x38"}, -{{0x55,0x47,0xf1,0x00,0x4b,0xae,0xdf,0xce,0x5c,0xfc,0x08,0x50,0xb0,0x53,0x02,0x37,0x4a,0xad,0x24,0xf6,0x16,0x39,0x94,0xec,0xd7,0x51,0xdf,0x3a,0xf3,0xc1,0x06,0x20,},{0x7c,0xe6,0x20,0x78,0x73,0x85,0xee,0x19,0x51,0xac,0x49,0xa7,0x73,0x52,0xee,0x0d,0x6f,0x8c,0x5c,0xd4,0x7d,0xf7,0x4e,0x9e,0x32,0x16,0xa6,0x32,0x4f,0xc7,0xcf,0x7f,},{0x29,0xdf,0x3a,0xd5,0x89,0x00,0x9c,0x66,0x7b,0xaa,0x5e,0x72,0xda,0xbb,0x4e,0x53,0xcb,0x78,0x76,0xde,0x4e,0x7e,0xfe,0x5c,0xc2,0x1e,0xad,0x7f,0xa8,0x78,0xdb,0x57,0xf9,0x7c,0x11,0x03,0xdd,0xb3,0x9a,0x86,0x1e,0xb8,0x86,0x53,0xc1,0xd4,0xec,0x3b,0x43,0x06,0xe4,0x58,0x4b,0x47,0xb8,0xbc,0x90,0x42,0x31,0x19,0xe7,0xe4,0xaf,0x00,},"\xa6\xc1\x7e\xeb\x5b\x80\x66\xc2\xcd\x9a\x89\x66\x73\x17\xa9\x45\xa0\xc7\xc9\x69\x96\xe7\x7a\xe8\x54\xc5\x09\xc6\xcd\x06\x31\xe9\x22\xad\x04\x50\x3a\xf8\x7a\x3c\x46\x28\xad\xaf\xed\x76\x00\xd0\x71\xc0\x78\xa2\x2e\x7f\x64\xbd\xa0\x8a\x36\x2b\x38\xb2\x6c\xa1\x50\x06\xd3\x8a\xcf\x53\x2d\x0d\xed\xea\x41\x77\xa2\xd3\x3f\x06\x95\x6d\x80\xe9\x63\x84\x8e\xc7\x91\xb2\x76\x2f\xa9\x94\x49\xb4\xf1\xa1\xed\x9b\x3f\x25\x80\xbe\x3a\xc7\xd7\xf5\x2f\xb1\x44\x21\xd6\x22\x2b\xa7\x6f\x80\x77\x50\xc6\xcb\xb0\xb1\x6f\x08\x95\xfc\x73\xd9\xdf\xc5\x87\xe1\xa9\xe5\xd1\xe5\x83\x75\xfb\xab\x70\x5b\x8f\x0c\x1f\xd7\xdf\x8b\x3a\xd4\x46\xf2\xf0\x84\x59\xe7\xed\x1a\xf5\x95\x56\xfb\xc9\x66\xdc\x24\x9c\x1c\xf6\x04\xf3\xe6\x77\xc8\xa0\x9d\x43\x63\x60\x87\x74\xbf\x38\x11\xbe\xf0\x64\x27\x48\xc5\x5c\x51\x6c\x7a\x58\x0f\xa3\x49\x90\x50\xac\xb3\x0e\xed\x87\x0d\x0d\x91\x17\x4c\xb6\x23\xe9\x8c\x3a\xd1\x21\xcf\x81\xf0\x4e\x57\xd4\x9b\x00\x84\x24\xa9\x8a\x31\xee\xaa\xf5\xf3\x8e\x00\x0f\x90\x3d\x48\xd2\x15\xed\x52\xf8\x62\xd6\x36\xa5\xa7\x36\x07\xde\x85\x76\x01\x67\x26\x7e\xfe\x30\xf8\xa2\x6e\xbc\x5a\xa0\xc0\x9f\x5b\x25\x8d\x33\x61\xca\x69\xd1\xd7\xee\x07\xb5\x96\x48\x17\x9a\xb2\x17\x0e\xc5\x0c\x07\xf6\x61\x6f\x21\x68\x72\x52\x94\x21\xa6\x33\x4a\x4a\x1e\xd3\xd2\x67\x1e\xf4\x7b\xc9\xa9\x2a\xfb\x58\x31\x4e\x83\x2d\xb8\xa9\x00\x34\x08\xa0\x48\x75\x03\xfe\x4f\x67\x77\x0d\xd4\xb6"}, -{{0x3d,0xd7,0x20,0x3c,0x23,0x7a,0xef,0xe9,0xe3,0x8a,0x20,0x1f,0xf3,0x41,0x49,0x01,0x79,0x90,0x5f,0x9f,0x10,0x08,0x28,0xda,0x18,0xfc,0xbe,0x58,0x76,0x8b,0x57,0x60,},{0xf0,0x67,0xd7,0xb2,0xff,0x3a,0x95,0x7e,0x83,0x73,0xa7,0xd4,0x2e,0xf0,0x83,0x2b,0xcd,0xa8,0x4e,0xbf,0x28,0x72,0x49,0xa1,0x84,0xa2,0x12,0xa9,0x4c,0x99,0xea,0x5b,},{0x4c,0x03,0x69,0x35,0xa9,0x6a,0xbc,0x0d,0x05,0x0d,0x90,0x7b,0xed,0xbe,0x99,0x46,0xfb,0x97,0x43,0x9f,0x03,0x9c,0x74,0x2e,0x05,0x1c,0xcf,0x09,0xad,0xd7,0xdf,0x44,0xd1,0x7d,0xa9,0x8c,0x2c,0xa0,0x1b,0xdc,0x24,0x24,0xda,0x1e,0x4d,0xeb,0xf3,0x47,0xf8,0xff,0xf4,0x8a,0xc8,0x03,0x0d,0x2c,0xc0,0x7f,0x95,0x75,0xc0,0x44,0xbe,0x04,},"\xdb\x28\xed\x31\xac\x04\xb0\xc2\xde\xce\xe7\xa6\xb2\x4f\xc9\xa0\x82\xcc\x26\x2c\xa7\xcc\xf2\xa2\x47\xd6\x37\x2e\xc3\xe9\x12\x0e\xce\xdb\x45\x42\xea\x59\x3f\xea\x30\x33\x5c\x5a\xb9\xdd\x31\x8a\x3b\x4f\xd5\x83\x42\x99\xcf\x3f\x53\xd9\xef\x46\x13\x7b\x27\x3c\x39\x0e\xc3\xc2\x6a\x0b\x44\x70\xd0\xd9\x4b\x77\xd8\x2c\xae\x4b\x24\x58\x78\x37\xb1\x67\xbb\x7f\x81\x66\x71\x0b\xae\xb3\xee\x70\xaf\x79\x73\x16\xcb\x7d\x05\xfa\x57\xe4\x68\xae\x3f\x0b\xd4\x49\x40\x4d\x85\x28\x80\x8b\x41\xfc\xca\x62\xf5\xe0\xa2\xaa\x5d\x8f\x3a\xca\xb0\x08\xcc\x5f\x6e\x5a\xb0\x27\x77\xbd\xcd\xe8\x7f\x0a\x10\xef\x06\xa4\xbb\x37\xfe\x02\xc9\x48\x15\xcf\x76\xbf\xb8\xf5\xcd\xd8\x65\xcc\x26\xdc\xb5\xcf\x49\x2e\xdf\xd5\x47\xb5\x35\xe2\xe6\xa6\xd8\x54\x09\x56\xdc\xba\x62\xcf\xea\x19\xa9\x47\x44\x06\xe9\x34\x33\x7e\x45\x42\x70\xe0\x10\x36\xac\x45\x79\x3b\x6b\x8a\xce\xda\x18\x7a\x08\xd5\x6a\x2c\xe4\xe9\x8f\x42\xea\x37\x5b\x10\x1a\x6b\x9f\xcb\x42\x31\xd1\x71\xaa\x46\x3e\xeb\x43\x58\x6a\x4b\x82\xa3\x87\xbc\xdd\xaf\x71\xa8\x0f\xd5\xc1\xf7\x29\x2e\xfc\x2b\xd8\xe7\x0c\x11\xea\xa8\x17\x10\x60\x61\xb6\xc4\x61\xc4\x88\x3d\x61\x3c\xc0\x6c\x7e\x2a\x03\xf7\x3d\x90\xfc\x55\xcd\xc0\x72\x65\xee\xfd\x36\xbe\x72\x27\x03\x83\xd6\xc6\x76\xca\xe3\x7c\x93\x69\x1f\x1a\xe3\xd9\x27\xb3\xa1\xcd\x96\x3e\x42\x29\x75\x7a\xe5\x23\x1e\xea\x73\xa9\xf7\x15\x15\x62\x83\x05\x41\x0a\xc2\x59\x3b\x32\x5c\xc6\x31"}, -{{0x28,0x27,0x75,0xdf,0x9e,0xbb,0xd7,0xc5,0xa6,0x5f,0x3a,0x2b,0x09,0x6e,0x36,0xee,0x64,0xa8,0xf8,0xea,0x71,0x9d,0xa7,0x77,0x58,0x73,0x9e,0x4e,0x74,0x76,0x11,0x1d,},{0xa2,0xb4,0x96,0x46,0x03,0x3a,0x13,0x93,0x7c,0xad,0x6b,0x0e,0x91,0x4e,0x3c,0xec,0x54,0x98,0x9c,0x25,0x2c,0xa5,0x64,0x3d,0x07,0x65,0x55,0xd8,0xc5,0x5e,0x56,0xe0,},{0x15,0x76,0x39,0x73,0x85,0x94,0x02,0x90,0x7d,0x8d,0xcb,0x86,0xad,0xc2,0x4a,0x2a,0x16,0x8b,0xa3,0xab,0xf2,0x24,0x61,0x73,0xd6,0x34,0x8a,0xfe,0xd5,0x1e,0xf6,0x0b,0x0c,0x0e,0xde,0xff,0x4e,0x10,0xbc,0xef,0x4c,0x6e,0x57,0x78,0xc8,0xbc,0x1f,0x5e,0x9e,0xe0,0x23,0x73,0x73,0x44,0x5b,0x45,0x51,0x55,0xd2,0x3d,0xe1,0x27,0xa2,0x02,},"\x14\xcc\x50\xc2\x97\x3e\xa9\xd0\x18\x7a\x73\xf7\x1c\xb9\xf1\xce\x07\xe7\x39\xe0\x49\xec\x2b\x27\xe6\x61\x3c\x10\xc2\x6b\x73\xa2\xa9\x66\xe0\x1a\xc3\xbe\x8b\x50\x5a\xea\xad\x14\x85\xc1\xc2\xa3\xc6\xc2\xb0\x0f\x81\xb9\xe5\xf9\x27\xb7\x3b\xfd\x49\x86\x01\xa7\x62\x2e\x85\x44\x83\x7a\xad\x02\xe7\x2b\xf7\x21\x96\xdc\x24\x69\x02\xe5\x8a\xf2\x53\xad\x7e\x02\x5e\x36\x66\xd3\xbf\xc4\x6b\x5b\x02\xf0\xeb\x4a\x37\xc9\x55\x49\x92\xab\xc8\x65\x1d\xe1\x2f\xd8\x13\x17\x73\x79\xbb\x0c\xe1\x72\xcd\x8a\xaf\x93\x7f\x97\x96\x42\xbc\x2e\xd7\xc7\xa4\x30\xcb\x14\xc3\xcd\x31\x01\xb9\xf6\xb9\x1e\xe3\xf5\x42\xac\xdf\x01\x7f\x8c\x21\x16\x29\x7f\x45\x64\x76\x8f\x4d\xb9\x5d\xad\x8a\x9b\xcd\xc8\xda\x4d\x8f\xb1\x3e\xf6\xe2\xda\x0b\x13\x16\xd3\xc8\xc2\xf3\xed\x83\x6b\x35\xfe\x2f\xd3\x3e\xff\xb4\x09\xe3\xbc\x1b\x0f\x85\x22\x5d\x2a\x1d\xe3\xbf\xc2\xd2\x05\x63\x94\x64\x75\xc4\xd7\xca\x9f\xdd\xba\xf5\x9a\xd8\xf8\x96\x1d\x28\x7a\xe7\xdd\x80\x3e\x7a\xf1\xfa\x61\x23\x29\xb1\xbd\xc0\x4e\x22\x56\x00\xae\x73\x1b\xc0\x1a\xe0\x92\x5a\xed\x62\xac\x50\xd4\x60\x86\xf3\x64\x6c\xf4\x7b\x07\x2f\x0d\x3b\x04\x4b\x36\xf8\x5c\xec\x72\x9a\x8b\xb2\xb9\x28\x83\xca\x4d\xfb\x34\xa8\xee\x8a\x02\x73\xb3\x1a\xf5\x09\x82\xbb\x61\x31\xbf\xa1\x1d\x55\x50\x4b\x1f\x6f\x1a\x0a\x00\x43\x8c\xa2\x6d\x8a\xb4\xf4\x8b\xcd\xdc\x9d\x5a\x38\x85\x1a\xbe\xde\x41\x51\xd5\xb7\x0d\x72\x07\x32\xa0\x0a\xbe\xa2\xc8\xb9\x79"}, -{{0x47,0x30,0xa5,0xcf,0x97,0x72,0xd7,0xd6,0x66,0x5b,0xa7,0x87,0xbe,0xa4,0xc9,0x52,0x52,0xe6,0xec,0xd6,0x3e,0xc6,0x23,0x90,0x54,0x7b,0xf1,0x00,0xc0,0xa4,0x63,0x75,},{0xf9,0xf0,0x94,0xf7,0xcc,0x1d,0x40,0xf1,0x92,0x6b,0x5b,0x22,0xdc,0xe4,0x65,0x78,0x44,0x68,0xb2,0x0a,0xb3,0x49,0xbc,0x6d,0x4f,0xdf,0x78,0xd0,0x04,0x2b,0xbc,0x5b,},{0x55,0x2c,0x73,0x47,0xbd,0xfe,0x13,0x16,0x46,0xce,0x09,0x32,0xd8,0x2a,0x36,0xd2,0xc1,0xb7,0x6d,0x7c,0x30,0xee,0x89,0x0e,0x05,0x92,0xe1,0x9f,0x9d,0x18,0xb9,0xa5,0x6f,0x48,0xd7,0xa9,0xb6,0x8c,0x01,0x7d,0xa6,0xb5,0x50,0xc9,0x43,0xaf,0x4a,0x90,0x7b,0xaf,0x31,0x7e,0x41,0x9f,0xbb,0xc9,0x6f,0x6c,0xf4,0xbf,0xad,0x42,0xde,0x00,},"\xe7\x47\x6d\x2e\x66\x84\x20\xe1\xb0\xfa\xdf\xba\xa5\x42\x86\xfa\x7f\xa8\x90\xa8\x7b\x82\x80\xe2\x60\x78\x15\x22\x95\xe1\xe6\xe5\x5d\x12\x41\x43\x5c\xc4\x30\xa8\x69\x3b\xb1\x0c\xde\x46\x43\xf5\x9c\xbf\xcc\x25\x6f\x45\xf5\x09\x0c\x90\x9a\x14\xc7\xfc\x49\xd3\x7b\xfc\x25\xaf\x11\xe8\xf4\xc8\x3f\x4c\x32\xd4\xaa\xbf\x43\xb2\x0f\xa3\x82\xbb\x66\x22\xa1\x84\x8f\x8f\xfc\x4d\xff\x34\x08\xbb\x4e\xc7\xc6\x7a\x35\xb4\xcd\xae\xe5\xe2\x79\xc0\xfc\x0a\x66\x09\x3a\x9f\x36\xa6\x0f\xdd\x65\xe6\x33\x4a\x80\x4e\x84\x5c\x85\x30\xb6\xfd\xa3\x63\xb5\x64\x03\x37\xd0\x27\x24\x3c\xcf\xb3\xc1\x77\xf4\x3e\x71\x78\x96\xe4\x6e\xad\x7f\x72\xca\x06\xaa\x0f\xf1\xe7\x72\x47\x12\x1b\xaf\x48\xbe\x9a\x44\x5f\x72\x9c\xa1\x39\x0f\xc4\x61\x51\xcb\xd3\x3f\xcb\xd7\x37\x3f\x27\xa6\xba\x55\xc9\x2c\xbf\x69\x45\xb0\x9b\x44\xb9\xa4\xe5\x80\x0d\x40\x30\x70\xae\x66\x04\x89\x97\xb2\x19\x7f\x02\x18\x1a\x09\x7e\x56\x3f\x9b\x9a\xcc\x84\x11\x39\x25\x8a\x25\x8b\xc6\x10\xd3\xbd\x89\x16\x37\x35\x6b\x2e\xdc\x8c\x18\x4c\x35\xc6\x5a\xf9\x1a\xaf\x7b\x1c\x16\xd7\x4a\x5f\x5f\x86\x25\x48\x13\x92\x54\xec\xf5\x50\x63\x1d\x5f\x88\x49\xaf\xdb\x5b\x64\xcf\x36\x6f\xf2\x63\x3a\x93\xf3\xa1\x8c\x39\xb5\x15\x02\x45\xfb\x5f\x33\xc9\xe4\xe2\xd9\x4a\xf6\x96\x3a\x70\xb8\x8f\x9e\x7e\x51\x9f\x8f\xa2\xa0\xf2\xe3\x74\x9d\xe8\x83\xd0\xe6\xf0\x52\xa9\x49\xd0\xfc\x71\x53\xa8\x69\x3f\x6d\x80\x1d\x73\x52\xeb\x2f\x7a\x46\x5c\x0e"}, -{{0x27,0x70,0xaa,0xdd,0x1d,0x12,0x3e,0x95,0x47,0x83,0x2d,0xfb,0x2a,0x83,0x7e,0xba,0x08,0x91,0x79,0xef,0x4f,0x23,0xab,0xc4,0xa5,0x3f,0x2a,0x71,0x4e,0x42,0x3e,0xe2,},{0x3c,0x5f,0xbb,0x07,0x53,0x0d,0xd3,0xa2,0x0f,0xf3,0x5a,0x50,0x0e,0x37,0x08,0x92,0x63,0x10,0xfe,0xd8,0xa8,0x99,0x69,0x02,0x32,0xb4,0x2c,0x15,0xbd,0x86,0xe5,0xdc,},{0xf2,0x67,0x71,0x5e,0x9a,0x84,0xc7,0x31,0x4f,0x2d,0x58,0x69,0xef,0x4a,0xb8,0xd2,0x14,0x9a,0x13,0xf7,0xe8,0xe1,0xc7,0x28,0xc4,0x23,0x90,0x62,0x93,0xb4,0x9c,0xe6,0x28,0x34,0x54,0xdd,0x1c,0x7b,0x04,0x74,0x1d,0xf2,0xea,0xbe,0xdc,0x4d,0x6a,0xb1,0x39,0x7d,0xc9,0x5a,0x67,0x9d,0xf0,0x4d,0x2c,0x17,0xd6,0x6c,0x79,0xbb,0x76,0x01,},"\xa5\xcc\x20\x55\xeb\xa3\xcf\x6f\x0c\x63\x32\xc1\xf2\xab\x58\x54\x87\x09\x13\xb0\x3f\xf7\x09\x3b\xc9\x4f\x33\x5a\xdd\x44\x33\x22\x31\xd9\x86\x9f\x02\x7d\x82\xef\xd5\xf1\x22\x71\x44\xab\x56\xe3\x22\x2d\xc3\xdd\xcc\xf0\x62\xd9\xc1\xb0\xc1\x02\x4d\x9b\x41\x6d\xfa\x3e\xe8\xa7\x02\x79\x23\x00\x34\x65\xe0\xff\xae\xfb\x75\xb9\xf2\x9d\xc6\xbc\xf2\x13\xad\xc5\xe3\x18\xfd\x8b\xa9\x3a\x7a\xa5\xbf\xb4\x95\xde\x9d\x7c\x5e\x1a\x19\x6c\xd3\xa2\xd7\x72\x1f\x8b\xa7\x85\xaa\x90\x52\xa1\x81\x1c\x7f\xcc\x8f\x93\x93\x27\x65\x05\x9c\xab\x9c\x9b\x71\x89\x45\x89\x5e\xf2\x6f\x3a\xc0\x48\xd4\xca\xbf\x91\xa9\xe6\xaa\x83\xac\x14\xd4\x31\x56\x82\x78\x37\x91\x4e\xb7\x63\xa2\x3c\xba\x53\xf6\x0f\x15\x0f\x4b\x70\x20\x3e\xc1\x83\x3f\xf1\x05\x84\x94\x57\xa8\xda\x73\x27\x66\x1f\xb2\x3a\x55\x41\x64\xe0\x5f\xcf\x01\x46\xb1\x06\x74\x96\x4b\xe6\xf6\xaa\x0a\xcc\x94\xc4\x1a\xd5\x71\x80\xe5\x18\x0d\x19\x9b\xd9\x10\x2f\x55\xd7\x40\xe8\x17\x89\xb1\x56\x71\xbb\xd0\x67\x0e\x6d\xe5\xd9\x7e\x1a\xe6\x26\xd8\xa0\xeb\xc3\x2c\x8f\xd9\xd2\x47\x37\x27\x4e\x47\xd2\xdd\x59\x41\xa2\x72\xe7\x2a\x59\x89\x28\xad\x10\x9c\xde\x93\x7b\xf2\x48\xd5\x7f\x5d\x29\x42\x98\x3c\x51\xe2\xa8\x9f\x8f\x05\x4d\x5c\x48\xdf\xad\x8f\xcf\x1f\xfa\x97\xf7\xde\x6a\x3a\x43\xca\x15\xfc\x67\x20\xef\xae\xc6\x9f\x08\x36\xd8\x42\x23\xf9\x77\x6d\x11\x1e\xc2\xbb\xc6\x9b\x2d\xfd\x58\xbe\x8c\xa1\x2c\x07\x21\x64\xb7\x18\xcd\x7c\x24\x6d\x64"}, -{{0x4f,0xda,0xb7,0xc1,0x60,0x0e,0x70,0x11,0x4b,0x11,0xf5,0x33,0x24,0x23,0x76,0xaf,0x76,0x14,0xb4,0xd5,0xda,0x04,0x6a,0xc4,0xbe,0xde,0xa2,0x1d,0x8a,0x36,0x15,0x98,},{0xa2,0x5c,0x9a,0x94,0xd6,0xe4,0xec,0xd9,0x5a,0x4b,0xd6,0x80,0x5f,0x76,0x2e,0xb1,0xc4,0x57,0xa8,0xd4,0x5d,0x24,0x32,0x38,0xb1,0x83,0x9c,0xbb,0xa8,0xf4,0x41,0xcc,},{0x50,0x75,0xc0,0x90,0xcf,0xbe,0xb6,0xb0,0x18,0x02,0xaf,0x7f,0x4d,0xa5,0xaa,0x4f,0x43,0x4d,0x5e,0xe2,0xf3,0x53,0x0e,0xeb,0xb7,0x5c,0x85,0xe0,0x86,0x21,0xf8,0x3e,0xdc,0x08,0xaa,0x96,0x69,0x38,0x94,0xa4,0x27,0x76,0x33,0xba,0x81,0xe1,0x9e,0x9e,0x55,0xaf,0x5c,0x49,0x5d,0xaa,0x5e,0x1a,0x6f,0x8c,0xbb,0x79,0xc0,0x1c,0x72,0x07,},"\xda\x40\x58\x90\xd1\x1a\x87\x2c\x11\x9d\xab\x5e\xfc\xbf\xf6\x1e\x93\x1f\x38\xec\xcc\xa4\x57\xed\xc6\x26\xd3\xea\x29\xed\x4f\xe3\x15\x4f\xaf\xec\x14\x44\xda\x74\x34\x3c\x06\xad\x90\xac\x9d\x17\xb5\x11\xbc\xb7\x3b\xb4\x9d\x90\xba\xfb\x7c\x7e\xa8\x00\xbd\x58\x41\x1d\xf1\x27\x5c\x3c\xae\x71\xb7\x00\xa5\xda\xb4\x91\xa4\x26\x16\x78\x58\x79\x56\xaa\x4a\x21\x9e\x1a\xc6\xdd\x3f\xb2\xcb\x8c\x46\x19\x72\x18\xe7\x26\xdc\x7e\xd2\x34\x52\x6a\x6b\x01\xc0\xd7\x2c\xb9\x3a\xb3\xf4\xf3\x8a\x08\xe5\x94\x0b\x3f\x61\xa7\x2a\xd2\x78\x9a\x05\x32\x00\x0f\xac\x1d\x2d\x2e\x3a\xd6\x32\xac\x8b\x62\xbb\x3f\xf5\xb9\x9d\x53\x59\x7b\xf4\xd4\x4b\x19\x67\x49\x24\xdf\x9b\x3d\xb3\xd0\x25\x3f\x74\x62\x7c\xca\xb3\x00\x31\xc8\x5e\x29\x1c\x58\xb5\xfa\x91\x67\x52\x2a\x46\x74\x6f\xc3\x07\x03\x67\x45\xd4\xf9\x81\x77\x86\xe5\xd3\x00\xe6\xc5\xd5\x03\x12\x5f\xea\x01\xde\xc3\xe3\xfe\xdb\xf3\x86\x1c\xa2\x62\x7a\x05\x18\xfb\x2b\x24\xe5\xa7\xa0\x14\x17\x87\x19\xe9\xb3\x45\xf7\xb2\x49\xce\x3a\x41\x32\x80\xc8\xde\xb6\x74\xf5\x9a\x25\xbe\x92\xa8\xab\x64\x00\xc7\xc5\x2b\x07\x28\xae\x34\xe2\x2b\x2e\xc2\x00\xc1\xcb\xab\xa2\xcc\xd8\xaf\x29\x24\x9d\x17\xaf\x60\xc3\x60\x07\xa7\x22\xfc\x80\x25\x8a\x7b\xeb\xab\x1c\xda\xad\x74\x62\xa8\xb7\x58\x8c\x2f\x7e\x27\xc6\xd0\x7a\xfc\xf6\x01\x17\xfe\xd1\x1b\xd6\x85\x9e\x75\xe3\xb4\xfc\xee\x39\x81\x88\x1e\x95\xdd\x11\x68\x27\xdd\x4b\x36\x9a\xf0\x69\xd3\xc8\xf2\x67\x6f\x8a"}, -{{0x26,0x45,0x04,0x60,0x4e,0x70,0xd7,0x2d,0xc4,0x47,0x4d,0xbb,0x34,0x91,0x3e,0x9c,0x0f,0x80,0x6d,0xfe,0x18,0xc7,0x87,0x9a,0x41,0x76,0x2a,0x9e,0x43,0x90,0xec,0x61,},{0xeb,0x2b,0x51,0x8c,0xe7,0xdc,0x71,0xc9,0x1f,0x36,0x65,0x58,0x16,0x51,0xfd,0x03,0xaf,0x84,0xc4,0x6b,0xf1,0xfe,0xd2,0x43,0x32,0x22,0x35,0x3b,0xc7,0xec,0x51,0x1d,},{0xee,0xa4,0x39,0xa0,0x0f,0x7e,0x45,0x9b,0x40,0x2b,0x83,0x51,0x50,0xa7,0x79,0xee,0xd1,0x71,0xab,0x97,0x1b,0xd1,0xb5,0x8d,0xcc,0x7f,0x93,0x86,0xda,0xdd,0x58,0x3d,0xe8,0xdc,0x69,0xe2,0x67,0x12,0x1d,0xde,0x41,0xf0,0xf9,0x49,0x3d,0x45,0x0b,0x16,0x21,0x9c,0xdf,0x3c,0x22,0xf0,0x94,0x82,0xce,0x40,0x2f,0xe1,0x7c,0xa4,0x9e,0x08,},"\x90\x1d\x70\xe6\x7e\xd2\x42\xf2\xec\x1d\xda\x81\x3d\x4c\x05\x2c\xfb\x31\xfd\x00\xcf\xe5\x44\x6b\xf3\xb9\x3f\xdb\x95\x0f\x95\x2d\x94\xef\x9c\x99\xd1\xc2\x64\xa6\xb1\x3c\x35\x54\xa2\x64\xbe\xb9\x7e\xd2\x0e\x6b\x5d\x66\xad\x84\xdb\x5d\x8f\x1d\xe3\x5c\x49\x6f\x94\x7a\x23\x27\x09\x54\x05\x1f\x8e\x4d\xbe\x0d\x3e\xf9\xab\x30\x03\xdd\x47\xb8\x59\x35\x6c\xec\xb8\x1c\x50\xaf\xfa\x68\xc1\x5d\xad\xb5\xf8\x64\xd5\xe1\xbb\x4d\x3b\xad\xa6\xf3\xab\xa1\xc8\x3c\x43\x8d\x79\xa9\x4b\xfb\x50\xb4\x38\x79\xe9\xce\xf0\x8a\x2b\xfb\x22\xfa\xd9\x43\xdb\xf7\x68\x37\x79\x74\x6e\x31\xc4\x86\xf0\x1f\xd6\x44\x90\x50\x48\xb1\x12\xee\x25\x80\x42\x15\x3f\x46\xd1\xc7\x77\x2a\x06\x24\xbc\xd6\x94\x1e\x90\x62\xcf\xda\x75\xdc\x87\x12\x53\x3f\x40\x57\x33\x5c\x29\x80\x38\xcb\xca\x29\xeb\xdb\x56\x0a\x29\x5a\x88\x33\x96\x92\x80\x8e\xb3\x48\x1f\xd9\x73\x5e\xa4\x14\xf6\x20\xc1\x43\xb2\x13\x3f\x57\xbb\x64\xe4\x47\x78\xa8\xca\x70\x91\x82\x02\xd1\x57\x42\x61\x02\xe1\xdf\xc0\xa8\xf7\xb1\xae\x48\x7b\x74\xf0\x27\x92\x63\x31\x54\xdf\xe7\x4c\xaa\x1b\x70\x88\xfd\xa2\x2f\xa8\xb9\xbc\x35\x4c\x58\x5f\x15\x67\x70\x6e\x29\x55\x49\x38\x70\xf5\x41\x69\xe0\xd7\x69\x11\x59\xdf\x43\x89\x79\x61\xd2\x4a\x85\x2e\xa9\x70\xc5\x14\x94\x8f\x3b\x48\xf7\x1e\xe5\x86\xe7\x2e\xc7\x8d\xb8\x20\xf2\x53\xe0\x8d\xb8\x4f\x6f\x31\x2c\x43\x33\xbd\x0b\x73\x2f\xe7\x58\x83\x50\x77\x83\xe9\xa1\xfd\x4f\xba\xb8\xe5\x87\x0f\x9b\xf7\xad\x58\xaa"}, -{{0x2c,0xa7,0x44,0x7a,0x36,0x68,0xb7,0x48,0xb1,0xfd,0x3d,0x52,0xd2,0x08,0x0d,0x30,0xe3,0x4d,0x39,0x7b,0xb2,0x84,0x6c,0xaf,0x8f,0x65,0x9a,0xc1,0x68,0x78,0x8c,0xa5,},{0xab,0x33,0x1c,0xd4,0x0a,0x31,0xd0,0x17,0x3c,0x0c,0x8c,0x1c,0x17,0x00,0x25,0x32,0x80,0x7b,0xf8,0x9e,0x3e,0xdb,0x6d,0x34,0xc2,0xdd,0x82,0x94,0x63,0x2b,0x9f,0xbc,},{0xf9,0x3a,0xda,0x15,0xae,0x9c,0xd2,0xb5,0x4f,0x26,0xf8,0x6f,0x0c,0x28,0x39,0x2a,0xed,0x5e,0xb6,0xb6,0xb4,0x4d,0x01,0xa4,0xe3,0x3a,0x54,0xe7,0xda,0x37,0xc3,0x8e,0x8d,0x53,0x36,0x6f,0x73,0xfd,0x85,0xbe,0x64,0x2e,0x4e,0xc8,0x12,0x36,0xd1,0x63,0xf0,0xd0,0x25,0xe7,0x6c,0x8b,0xbd,0xd6,0x5d,0x43,0xdf,0x49,0xf0,0x9c,0x1f,0x01,},"\xa8\x2b\xcd\x94\x24\xbf\xfd\xa0\xf2\xf5\xe9\xea\xe1\x78\x35\xdb\xe4\x68\xf6\x1b\x78\x5a\xab\x82\x93\x47\x37\xa9\x1c\x5f\x60\x2c\xb7\xc6\x17\xcd\xff\xe8\x7c\xad\x72\x6a\x49\x72\xe1\x5a\x7b\x8e\xe1\x47\xf0\x62\xd2\xa5\xa4\xd8\x97\x06\xb5\x71\xfa\x8a\xa2\xb9\x59\x81\xc7\x8a\xbe\xaa\xae\x86\x20\x3f\xa2\xc0\xe0\x72\x97\x40\x6e\xa8\xc2\x71\x11\xa8\x6d\xbe\x1d\x5a\x7c\x3b\x7a\xe9\x30\x90\x4d\x98\x90\xf6\xd4\xab\xeb\xd1\x41\x2a\x73\xad\x5f\xee\xa6\x4a\xcf\x06\x5d\x3e\x63\xb5\xcb\xe2\x0c\xf2\x0b\xbd\x2d\x8b\x94\xf9\x05\x3e\xd5\xf6\x66\x33\x48\x25\x30\x12\x44\x46\x60\x59\x18\xde\x66\x45\x5e\x8c\xf4\xb1\x01\xa1\x27\x23\x3c\x4e\x27\xd5\xd5\x5b\xf9\x5b\xd3\x19\x5d\x03\x40\xd4\x35\x31\xfc\x75\xfa\xf8\xdd\xed\x52\x75\xbf\x89\x75\x0d\xe8\x38\xfd\x10\xc3\x17\x45\xbe\x4c\xa4\x1f\xa8\x71\xcb\x0f\x9b\x01\x67\x06\xa1\xa7\xe3\xc4\x4b\xb9\x0a\xc7\xa8\xad\x51\xe2\x72\x38\x92\x92\xfd\x6c\x98\xad\x7a\x06\x9e\x76\xe3\xf5\xf3\xe0\xcc\x77\x0b\x9e\x9b\x35\xa7\x65\xd0\xd9\x37\x12\xd7\xcd\xab\xd1\x7e\x5d\x01\xdd\x81\x83\xaf\x4a\xd9\x36\x5d\xb0\xa0\xfa\x41\x38\x1f\xce\x60\xa0\x81\xdf\x1c\x5a\xb0\xf8\xc1\x8f\x95\xa7\xa8\xb5\x82\xdf\xff\x7f\x14\x9e\xa5\x79\xdf\x06\x23\xb3\x3b\x75\x08\xf0\xc6\x63\xf0\x1e\x3a\x2d\xcd\x9d\xfb\xee\x51\xcc\x61\x52\x20\xfd\xaf\xfd\xab\x51\xbd\xae\x42\xcb\x9f\x7f\xa9\xe3\xb7\xc6\x9c\xc8\xad\xa5\xcc\xd6\x42\x52\x9b\xa5\x14\xfd\xc5\x4f\xcf\x27\x20\xb8\xf5\xd0\x8b\x95"}, -{{0x49,0x4e,0xa9,0xbc,0xce,0x26,0x88,0x5b,0x7d,0x17,0xd1,0xfc,0x11,0x44,0x48,0xf2,0x39,0xf0,0xce,0x46,0xe5,0xf2,0x47,0xb4,0xc9,0x99,0xfa,0x86,0x29,0x69,0x24,0x72,},{0x69,0x01,0xe5,0xef,0xae,0x57,0x53,0x6b,0xa5,0xfd,0xd9,0x6b,0x59,0x65,0x73,0x59,0x06,0x5f,0x25,0xd3,0x91,0xa1,0xaa,0x8c,0xdc,0x0d,0x38,0xbb,0x5d,0x53,0xc1,0x39,},{0x54,0x8a,0x09,0x3a,0x68,0x03,0x61,0xb7,0xdc,0x56,0xf1,0x45,0x03,0xb5,0x5e,0xee,0xc3,0xb3,0xf4,0xfd,0x4c,0xa9,0x9d,0x6a,0xed,0xce,0x08,0x30,0xf7,0xf4,0xae,0x2f,0x73,0x28,0x53,0x9b,0x34,0xc4,0x8f,0xc9,0x76,0x09,0x22,0x33,0x3d,0xae,0x9c,0x7c,0x01,0x7e,0x7d,0xb7,0x3b,0x8f,0xaa,0x6c,0x06,0xbe,0x05,0xe3,0x47,0x99,0x2b,0x06,},"\x3b\xad\xbf\xa5\xf5\xa8\xaa\x2c\xce\x0a\x60\xe6\x86\xcd\xce\x65\x4d\x24\x45\x2f\x98\xfd\x54\x87\x2e\x73\x95\xb3\x94\x64\x38\x0a\x0e\x18\x55\x57\xea\x13\x4d\x09\x57\x30\x86\x4f\x42\x54\xd3\xdd\x94\x69\x70\xc1\x0c\x80\x4f\xcc\x08\x99\xdf\xa0\x24\x20\x5b\xe0\xf8\x0b\x1c\x75\x44\x95\x23\x32\x4f\xe6\xa0\x75\x1e\x47\xb4\xff\x48\x22\xb8\xc3\x3e\x9e\xaf\x1d\x1d\x96\xe0\xde\x3d\x4a\xcd\x89\x69\x6b\x7f\xcc\x03\xd4\x9f\x92\xf8\x2b\x97\x25\x70\x0b\x35\x0d\xb1\xa8\x76\x15\x36\x95\x45\x56\x1b\x85\x99\xf5\xea\x92\x0a\x31\x0a\x8b\xaf\xc0\xe8\xd7\x46\x8c\xbf\x6f\x38\x20\xe9\x43\x59\x4a\xfd\xd5\x16\x6e\x4e\x33\x09\xdd\xdd\x76\x94\xef\x67\xe6\x94\xf3\x4f\xc6\x27\x24\xff\x96\xac\x33\x64\x17\x6f\x34\xe8\xa0\x2b\x4c\xf5\x69\xdb\x5b\x8f\x77\xd5\x85\x12\xae\xda\xbf\x0b\xcd\x1c\x2d\xf1\x2d\xb3\xa9\x47\x3f\x94\x8c\x5c\x32\x43\x30\x9a\xae\x46\xc4\x9e\xfd\x08\x8b\x60\xf3\x1a\x8a\x72\xad\x7e\x5a\x35\xac\xc5\xd8\x9f\xa6\x68\x07\xeb\x5d\x3b\xa9\xcd\xf0\x8d\x47\x53\xcb\x85\x08\x9e\xe3\x6f\x5c\x96\xb4\x32\xb6\x92\x83\x52\xaf\xad\x58\x01\x22\x25\xd6\x15\x7f\x9e\x36\x11\x42\x6d\xf9\x21\xb6\xd1\xd8\x37\x46\x28\xa6\x30\x31\xe9\xff\xb9\x0e\x42\xff\xbb\xa0\x21\xf1\x74\xf6\x85\x03\x15\x54\x30\x15\x2c\x91\x55\xdc\x98\xff\xa2\x6c\x4f\xab\x06\x5e\x1f\x8e\x46\x22\xc2\xf2\x8a\x8c\xb0\x43\x11\x0b\x61\x74\x41\x14\x0f\x8e\x20\xad\xc1\x6f\x79\x9d\x1d\x50\x96\xb1\xf5\x05\x32\xbe\x50\x42\xd2\x1b\x81\xea\x46\xc7"}, -{{0x00,0xd7,0x35,0xeb,0xae,0xe7,0x5d,0xd5,0x79,0xa4,0x0d,0xfd,0x82,0x50,0x82,0x74,0xd0,0x1a,0x15,0x72,0xdf,0x99,0xb8,0x11,0xd5,0xb0,0x11,0x90,0xd8,0x21,0x92,0xe4,},{0xba,0x02,0x51,0x7c,0x0f,0xdd,0x3e,0x26,0x14,0xb3,0xf7,0xbf,0x99,0xed,0x9b,0x49,0x2b,0x80,0xed,0xf0,0x49,0x5d,0x23,0x0f,0x88,0x17,0x30,0xea,0x45,0xbc,0x17,0xc4,},{0xdc,0xdc,0x54,0x61,0x19,0x37,0xd2,0xbd,0x06,0xca,0xcd,0x98,0x18,0xb3,0xbe,0x15,0xce,0x74,0x25,0x42,0x7a,0x75,0xf5,0x0d,0x19,0x7a,0x33,0x7a,0x3b,0x8b,0xa6,0x71,0x4e,0xf4,0x88,0x66,0xf2,0x43,0xbd,0x5a,0xc7,0x41,0x5e,0x91,0x45,0x17,0xa2,0xc1,0xc5,0xa9,0x53,0xf4,0x32,0xb9,0x9d,0xb0,0xe6,0x20,0xd6,0x4f,0x74,0xeb,0x85,0x05,},"\x59\xc0\xb6\x9a\xf9\x5d\x07\x4c\x88\xfd\xc8\xf0\x63\xbf\xdc\x31\xb5\xf4\xa9\xbc\x9c\xec\xdf\xfa\x81\x28\xe0\x1e\x7c\x19\x37\xdd\xe5\xeb\x05\x70\xb5\x1b\x7b\x5d\x0a\x67\xa3\x55\x5b\x4c\xdc\xe2\xbc\xa7\xa3\x1a\x4f\xe8\xe1\xd0\x3a\xb3\x2b\x40\x35\xe6\xda\xdb\xf1\x53\x20\x59\xee\x01\xd3\xd9\xa7\x63\x3a\x0e\x70\x6a\x11\x54\xca\xb2\x2a\x07\xcd\x74\xc0\x6a\x3c\xb6\x01\x24\x4c\xf3\xcf\x35\xa3\x5c\x31\x00\xba\x47\xf3\x13\x72\xa2\xda\x65\xdc\xff\x0d\x7a\x80\xa1\x05\x5d\x8a\xa9\x92\x12\xe8\x99\xaa\xd7\xf0\x2e\x94\x9e\x6f\xee\x4d\x3c\x9c\xef\xa8\x50\x69\xea\xff\x1f\x6a\xd0\x6f\xc3\x00\xc8\x71\xab\x82\xb2\xbe\xdb\x93\x4d\x20\x87\x5c\x2a\x26\x32\x42\xcd\xb7\xf9\xbe\x19\x2a\x87\x10\xb2\x4c\x7e\xa9\x8d\x43\xda\xec\x8b\xaa\x55\x53\xc6\x78\xa3\x8f\x0e\x0a\xdf\x7d\x3f\xf2\xdc\xc7\x99\xa1\xdb\xad\x6e\xab\x1c\x3d\x94\x58\xa9\xdb\x92\x2f\x02\xe7\x5c\xfa\xb9\xd6\x5c\x73\x36\xda\xe7\x18\x95\xd5\xbb\x15\xca\xc2\x03\xf2\xb3\x8b\x99\x96\xc4\x10\xf8\x65\x5a\xd2\x2d\x3c\x09\x1c\x20\xb7\xf9\x26\xd4\x5e\x78\x01\x28\xf1\x97\x47\x46\x2a\xbc\x5c\x58\x93\x2f\xbb\x9e\x0b\xc6\x2d\x53\x86\x88\x02\xf1\xb0\x83\xf1\x83\xb8\xa1\xf9\x43\x49\x86\xd5\xcf\x97\xc0\x4e\x2f\x3e\x14\x57\x30\xcb\xa9\x87\x79\xc7\xfe\xd0\xca\xb1\xc0\x5d\x5e\x46\x53\xc6\xc3\xf6\x73\x62\x60\xbc\x78\xee\x43\x72\x86\x2f\xfe\x9e\x90\x37\x1d\x76\x2c\x74\x32\x78\x1f\x35\xce\xd8\x84\xa4\xba\xca\x05\x65\x3e\xf2\x5f\x25\xa6\xf3\xd5\x62\x83\x08"}, -{{0x8c,0x34,0xb9,0x05,0x44,0x0b,0x61,0x91,0x1d,0x1d,0x81,0x37,0xc5,0x3d,0x46,0xa1,0xa7,0x6d,0x46,0x09,0xaf,0x97,0x3e,0x18,0xeb,0x4c,0x57,0x09,0x29,0x56,0x27,0xbb,},{0xb6,0x9a,0x8b,0x2f,0xdf,0x5c,0x20,0xe7,0x34,0xc2,0xff,0xb2,0x94,0xbc,0x8a,0xe1,0x01,0x1d,0x66,0x4f,0x11,0xaf,0xe7,0xfb,0xc4,0x71,0x92,0x5c,0xf7,0x2f,0xa9,0x9d,},{0x3e,0x0b,0x72,0x07,0x3d,0xc9,0x37,0x5e,0xed,0xcc,0xa6,0xc4,0xfc,0x1c,0xd3,0x15,0x93,0x8a,0x05,0x0c,0x92,0x71,0x6b,0xd2,0x28,0x4f,0x46,0x29,0xa9,0x62,0xbe,0xec,0x0b,0x7d,0x7c,0xf1,0x6a,0xb9,0x23,0xd5,0x8f,0x5b,0x90,0xd3,0x90,0x1a,0x8e,0x5c,0x75,0xc8,0xf1,0x7d,0xab,0x99,0x98,0xe0,0x07,0xd8,0xc4,0x95,0x11,0x97,0x3d,0x0e,},"\x30\xb5\x7a\x38\x9b\x48\xa0\xbe\xb1\xa4\x84\x32\xbf\xf6\xb3\x14\xbd\xed\x79\xc4\xa1\x76\x3a\x5a\xcb\x57\xce\xa1\xbf\xb4\xc6\xd0\x16\xcf\x09\x0f\x5b\xd0\x5b\xbd\x11\x4e\x33\xae\x7c\x17\x78\x2d\xfa\x26\x4f\x46\xc4\x5f\x8c\x59\x9c\x60\x30\x16\xfe\x9f\xf0\x5b\x6b\x5a\x99\xe9\x2f\xe7\x13\xa4\xcd\x5c\x41\xb2\x92\xed\x2b\xb2\xe9\xcf\x33\xa4\x40\x54\x2e\x82\x1e\xc8\x2c\xbf\x66\x5c\x3f\x02\xe3\xdc\x33\x7d\x7f\xdb\x58\xe3\x1b\x27\xcb\x29\x54\x54\x14\x68\x81\x46\x98\x51\x0d\xf1\x8c\x85\xc8\x1f\xad\x12\xdb\x11\xec\x6b\x96\x6f\x49\x30\xda\x56\x46\xb9\x91\xdb\x97\x44\x50\x97\xda\x30\xda\xb6\x1c\xda\x53\xa4\x10\x83\xcb\x96\xad\xd1\x9d\xe6\xc5\xee\xc3\x23\xbc\xa9\xd3\x53\x0e\x38\xc0\x0b\x35\xaf\x73\x60\x07\x76\x01\xbe\x6a\xc9\x7f\x30\x30\xf9\x30\xa2\x7b\x90\xfe\x8b\x69\x11\xba\xe3\x89\x06\x5a\xdc\x15\xe1\x88\x23\x00\xe2\xa0\x03\x27\x4d\x23\x18\x2d\x5e\xfd\x5b\xa4\xb9\x13\x0c\x07\xbd\x5c\x65\xfe\xcb\x8b\x5c\xb7\xeb\x38\x83\x6b\x31\x8b\xef\xdf\xd7\x7d\xe4\xd6\xca\x01\x81\xf7\x7a\xe5\x74\x08\x91\x68\x32\x25\xf5\x49\xdd\x84\x26\x14\x5c\x97\xc5\x81\x8c\x31\x9f\x7a\xb2\xd8\x68\xe1\xa4\x1c\xea\xb6\x4c\x08\x51\x16\x06\x98\x97\xbf\x2c\xa3\x66\x76\x52\x40\x61\x55\xed\x06\x46\x43\x1b\x6d\xe1\xcc\xc0\x3b\x42\x79\xae\x4d\x32\x66\x79\x26\x5d\xce\x82\x04\x8e\x72\x98\xe1\xf8\x7f\xce\xc0\x76\x8a\xc0\xf5\xd8\xff\x84\xf7\x21\x0b\xe5\x4d\x41\x1a\xf8\xed\xea\x72\x17\xf4\xe5\x94\x13\x12\x1e\x14\x8c\x60\xda"}, -{{0x77,0xa8,0x3e,0x18,0xc9,0xf0,0x00,0xee,0xff,0x7d,0xee,0xac,0x95,0x9e,0xcb,0xa2,0x20,0x6c,0x0a,0xa3,0x9d,0x2f,0x0e,0x2a,0xed,0x57,0x29,0x48,0x2a,0x7a,0x02,0x29,},{0x62,0xb1,0xb3,0x16,0x13,0x55,0x96,0xbf,0xbc,0xa6,0x03,0x7e,0xd8,0x47,0xc6,0x1f,0xb7,0xf0,0x9f,0xa3,0x6c,0xe9,0x0a,0xbb,0x77,0x89,0xb8,0x6f,0x76,0x8b,0x59,0xdd,},{0x1e,0xaa,0xd8,0x42,0x0a,0xc1,0x2c,0x99,0xac,0x1f,0xf4,0x47,0x66,0x78,0xe3,0xcb,0xbe,0x94,0xda,0x6a,0x79,0x7f,0x17,0x46,0x64,0xd5,0xee,0x0f,0x64,0x14,0x33,0xfb,0x1e,0x7c,0xb2,0xf5,0x61,0x3e,0x10,0x80,0x5d,0xf8,0x65,0x4c,0xd8,0xe0,0xd4,0x5d,0x96,0x23,0x09,0x32,0xbc,0x7f,0x20,0xb0,0x4e,0xae,0x83,0x64,0x35,0x13,0x43,0x09,},"\xf3\xd5\xfa\x2a\xca\xef\xd8\x58\xf1\xdf\x26\xe0\x30\x59\xcd\xcb\xc2\x46\x8a\xd7\x4a\xfc\x99\x3d\x0d\xb9\xc4\xcd\xe4\x11\x3f\x8d\x55\xc7\xda\x71\xd3\x8b\xa0\x65\x20\x53\x1c\x61\xfd\xdb\x5f\x33\xd5\xf0\x35\x3b\xe2\x37\x6e\x58\x07\x11\xbe\x45\xc0\xa3\x0b\x1f\xa0\x1b\x55\xe2\x28\xc6\xfa\x35\xe3\xf9\x5b\x67\x90\x9f\xc7\xdf\x3f\xd4\x64\xd9\x3d\x66\x1a\x92\x6f\x9d\x11\xf7\x55\x0c\x17\xfb\xcc\x34\x96\x52\x6e\x8f\x10\xe0\xc8\x91\x66\x77\xb2\xbe\x5b\x31\x9b\x68\x8f\x21\xe8\x1a\xaa\x94\x82\xe5\xc9\x3e\x64\xce\x8c\x43\x7b\x9c\x1e\x14\xfe\xfe\xd7\x0a\x3f\xee\x56\x88\x11\xdc\x31\xca\xda\xb3\xd5\xb2\x20\x25\x44\x65\x33\x6d\xc4\xd9\x7a\x3b\xd0\x96\xb5\xe0\x65\xe0\xcf\xbe\x82\x84\x9e\x2c\x19\x05\xac\xa4\x86\x53\x3f\x0d\xa7\xa6\x1f\x1e\x9a\x55\xb8\xe2\xa8\x32\x62\xde\xeb\x59\xf2\xb1\x3d\x3a\x8a\xef\x57\x00\x84\x5b\x83\xb2\x5a\xe2\x18\x3c\x0d\xda\xc0\xce\x42\xf8\xd2\x56\x74\xcb\x0d\x0d\x22\x0a\x6d\xe7\xc1\x85\x8b\xb0\x7d\x59\xa3\x37\x23\x44\xd9\x44\x60\x2a\xa4\x51\xd2\xb9\x37\xdb\x0f\xe6\xfe\xca\x0b\xeb\xa8\x17\x21\xfc\x36\x1e\xa7\x50\x9e\x2b\x6d\x39\x7e\x1c\x19\x1b\x56\xf5\x4a\xb4\x36\xd0\xd2\x7a\xb4\xc0\x61\xbd\x66\x1a\xd1\xa4\x45\x23\x87\xe8\x73\x57\x54\xd0\x7f\xa7\xef\x4d\x45\x48\xb1\x72\x58\x24\x25\xb2\x99\x04\x6e\x63\x01\xb5\xba\x6b\x91\x44\x18\xf1\x49\xcf\x72\x2e\x10\xbd\xe2\xe0\xd4\x17\x00\xf1\x2c\x84\x29\xfc\x89\x7b\x78\x19\xda\x92\x29\x22\x40\xcd\x45\x56\x54\x58\xc9\xa7\xb2\x9c\x12"}, -{{0x73,0xb0,0x33,0x73,0xef,0x1f,0xd8,0x49,0x00,0x5e,0xcd,0x62,0x70,0xdd,0x99,0x06,0xf1,0x9f,0x44,0x39,0xe4,0x03,0x76,0xcd,0xbc,0x52,0x09,0x02,0xbc,0x97,0x68,0x12,},{0x66,0x37,0x19,0xe0,0x8b,0xa3,0xba,0x16,0x66,0xf6,0x06,0x9a,0x3f,0x54,0x99,0x18,0x66,0xb1,0x8c,0xc6,0xbe,0x41,0x99,0x1b,0x02,0xeb,0x30,0x26,0xff,0x9e,0x15,0x5f,},{0xa4,0x0a,0xbe,0x98,0xfc,0x69,0xda,0x8a,0x1f,0xf9,0xff,0x5c,0x2c,0xca,0x93,0x63,0x2e,0x97,0x59,0x80,0xee,0x8b,0x82,0xc3,0xc3,0x76,0x02,0x2d,0x65,0x24,0xab,0x73,0x6d,0x01,0xb0,0x72,0xf2,0xb6,0x81,0xb5,0xf1,0xcd,0x3e,0xa0,0x67,0x01,0x2e,0xd6,0xd0,0x74,0xe9,0x49,0xc4,0x23,0x27,0xa3,0x66,0xca,0xa9,0xe4,0x75,0x0a,0x3c,0x08,},"\xd5\xc2\xde\xab\xa7\x95\xc3\x0a\xba\x32\x1b\xc7\xde\x69\x96\xf0\xd9\x0e\x4d\x05\xc7\x47\xfb\x4d\xae\x8f\x34\x51\x89\x5d\xef\x6e\x16\xe7\x2f\x38\xea\xce\x75\x6f\x36\x63\x5f\x8f\xb0\xb7\x2a\x3a\x0c\x1f\x54\x66\x38\x17\xa9\x4d\x4f\xd3\x46\xf8\x35\xab\x0e\x65\x7f\x00\x1a\x6f\x2c\xec\xb8\x6d\x08\x25\xbd\x02\x63\x92\x54\xf7\xf7\xf3\x8c\xa9\x9d\xbb\x86\xc6\x4a\x63\x3f\x73\xba\xf9\x33\xaa\xe3\x56\x32\x81\xf4\x00\x5e\x2d\x0e\x7c\xec\x9f\xbd\xe8\xe5\x88\xa9\x57\xe2\x11\x06\x8b\xe6\x5b\x3d\x3d\x35\xbf\x4e\x8d\x5b\xb3\x47\x83\x33\xdf\x9c\xed\x9b\x2a\xba\xf4\x86\x97\x99\x4a\x14\x5e\x93\x21\x49\x9f\xc5\xee\x56\x0f\x4f\xbb\x68\x49\xe1\xae\x8e\xb3\xd1\xde\x00\x83\xa2\x1a\x03\xf6\xa6\xb2\x81\x76\xf0\x13\x0d\x38\x95\xe5\x0e\x75\xe3\xd7\xd0\x94\x7a\x7b\xc2\xc5\xb9\xff\x69\x89\x5d\x27\x79\x14\x42\xba\x8d\x0f\x21\x80\x71\x2b\x56\x7f\x71\x2e\xa9\x12\xf3\xb0\xd9\x2c\x19\x34\x2e\x01\x06\xff\x1d\x87\xb4\x6a\xd3\x3a\xf3\x00\xb9\x08\x55\xba\x97\x69\xd3\x66\xe7\x94\x25\xd9\x8e\x4d\xe1\x99\x05\xa0\x45\x77\x70\x7c\xbe\x62\x5b\x84\x69\x17\x81\xcd\x26\xbf\x62\x26\x0b\x4a\x8b\xd6\x05\xf7\x7a\xf6\xf9\x70\xe1\xb3\xa1\x12\xe8\x91\x83\x44\xbd\x0d\x8d\x2e\x41\xdf\xd2\xce\x98\x95\xb0\x24\x6e\x50\x88\x7a\xa3\xa5\x77\xff\x73\xbe\x4b\x6a\xe6\x0f\xeb\x0c\xa3\x6f\x6a\x5f\x81\x71\xed\x20\x9e\x5c\x56\x65\x29\xc0\x94\x0d\x9b\x4b\xd7\x44\xcc\xee\x56\xe5\x4a\x9a\x0c\x6e\x4d\xa5\x20\xdd\x31\x5c\x28\x72\xb0\x2d\xb5\x63\x70\x3e"}, -{{0xea,0xb1,0x79,0xe4,0x1e,0xd5,0xc8,0x89,0xff,0xe6,0xaa,0xbd,0xc0,0x54,0xfa,0xf1,0x30,0x7c,0x39,0x5e,0x46,0xe3,0x13,0xe1,0x7a,0x14,0xfe,0x01,0x02,0x3f,0xfa,0x30,},{0x86,0xf3,0x47,0x46,0xd3,0xf7,0xa0,0x1d,0xdb,0xe3,0x22,0xf1,0xac,0xa5,0x6d,0x22,0x85,0x6d,0x38,0x73,0x3a,0x3a,0x69,0x00,0xbb,0x08,0xe7,0x76,0x45,0x0e,0xc8,0x03,},{0x14,0x3c,0xb2,0x80,0x27,0xc2,0xf8,0x2e,0x37,0x5e,0x5f,0x34,0x0e,0x7f,0xe6,0xe6,0x0c,0xe7,0xbd,0x51,0x00,0x0b,0x49,0xc7,0x41,0x68,0xaf,0x85,0xe2,0x6e,0xd2,0xed,0x63,0x0e,0xd2,0x67,0x20,0x90,0x16,0x4c,0xc5,0x4b,0x05,0x2d,0xa6,0x94,0xeb,0xdd,0x21,0xa2,0x1b,0x30,0x53,0xf4,0xdc,0xfd,0x78,0x95,0xea,0x5f,0x6c,0x8a,0xa8,0x0d,},"\x97\x10\x95\xce\xbe\x50\x31\x53\x02\x24\x38\x7c\x5c\x31\x96\x6e\x38\x9b\x85\x66\x39\x00\x54\xcf\x45\x26\x4b\x44\xe1\x89\x64\xb7\xbe\x52\xc3\x3c\x4f\xfb\x25\x9a\xf1\x62\x83\x43\x8f\xa1\x5d\xd6\x6b\xc7\x79\x1b\x75\x33\xef\x10\xcb\x0b\xea\xb5\x24\xa6\x43\x76\x26\xf4\xcc\x74\x51\x28\x51\xad\xcc\x2f\xb1\x29\x05\x5a\x48\x2c\x61\x10\x73\x83\xfb\x7c\x52\x41\x83\x1d\x55\x51\x63\x4e\xef\x0d\xc0\xb8\xf9\x05\x3a\x00\x97\x1a\xa8\xfa\x1a\xe0\x89\x8e\x4b\x48\x1b\x67\x07\xe9\x7c\x0f\x94\x20\x40\xb3\x39\xd9\x2f\xc1\x7b\xba\xde\x74\x67\x5a\xf2\x43\xd8\xb2\xda\xfb\x15\xb1\xdb\x55\xd1\x24\x15\xb8\x5f\x30\x37\x29\x19\x30\xab\x61\x60\x0b\xa3\x43\x1f\x8e\xb4\x25\xbe\x44\x91\x61\x47\x28\xaf\x10\x1e\x81\xc0\x91\xf3\x48\xbc\x5f\xfd\x1b\xde\x6a\xe6\xca\xd5\xc1\x5b\x3a\xa7\x35\x80\x78\xcc\x4e\xff\xb5\x4a\x86\xe7\xf0\xe0\xc5\x5e\x4c\xfe\x0a\x54\x60\x5e\xd4\x43\xfd\xf2\xaa\xba\x01\x65\x85\xda\x61\x7e\x77\x34\x1d\x52\x88\x9d\x75\xdd\x54\x0d\x39\xfe\x8b\x79\x93\xed\x70\x5c\xfd\xde\xa0\xcb\x0d\x5a\x73\x1d\x6b\xfc\xdb\x81\x6a\xfa\xff\x47\xe9\x63\xee\xde\xbd\xf2\x41\xaf\x55\x93\x35\x3d\x6d\x40\x1a\x34\xf0\x29\xa8\xcd\xeb\x19\x04\xcc\x2c\xaa\x4f\x96\x35\xcc\x2b\xa6\xb7\xb1\xa2\x9d\xa6\x25\xff\xc3\x83\xbe\x2f\x5a\x8f\x1f\xa4\xf3\x9b\x2d\x4b\x4f\x4c\x2d\x88\x38\xce\x25\x8a\x04\xd4\xa1\x20\x49\x3f\xdf\x07\xf6\x8c\x0f\xfd\x1c\x16\xb7\x68\xa3\x5c\x55\xfe\xa2\xca\xc6\x96\xb5\xc2\x0e\xfc\x10\x86\x5c\xde\x8a\x64\x62\x7d\xcd"}, -{{0xfb,0xf1,0x46,0xeb,0xd5,0x10,0x75,0x57,0x0e,0xc5,0x1a,0xc4,0x10,0xae,0x9f,0x39,0x1d,0xb7,0x5b,0x61,0x0a,0xda,0x63,0x62,0xb4,0xdb,0xd9,0x49,0x65,0x6c,0xfb,0x66,},{0xbe,0x7c,0x2f,0x5b,0x21,0xd7,0x46,0xc8,0xea,0x32,0x45,0xce,0x6f,0x26,0x8e,0x9d,0xa7,0x4e,0x00,0xfa,0x85,0xc9,0xc4,0x75,0x26,0x0c,0x68,0xfa,0x1a,0xf6,0x36,0x1f,},{0x67,0x68,0x00,0x6f,0xe0,0xf2,0x01,0xb2,0x17,0xdd,0x10,0xeb,0x05,0xd4,0xb8,0x2a,0xdc,0xfe,0xb2,0xec,0xfc,0x83,0x73,0xc3,0x30,0x8f,0x41,0x50,0x39,0x48,0x11,0xeb,0x60,0x49,0x18,0x81,0xa2,0xe5,0x3d,0x12,0x89,0xd9,0x64,0x78,0xe1,0x8a,0x64,0xc3,0x4b,0x2a,0x19,0x83,0x2c,0xdc,0xcf,0xd9,0x6a,0x2e,0x4a,0x0c,0x46,0x9f,0xdc,0x0b,},"\xcd\x7a\xd4\xf1\x7f\xcf\xf7\x3a\xcc\x40\x2d\xc1\x02\xd0\x90\x79\xb2\x9a\xaf\x2a\x0f\x4b\x27\xcf\x6b\xee\xb1\xe2\xb2\x3d\x19\xab\x47\xde\xb3\xae\x1b\xec\xd6\x88\x61\xea\x27\x9c\x46\x69\x17\x38\xf4\xff\xf4\x7c\x43\x04\x7c\x4f\x8b\x56\xb6\xbb\xcc\x3f\xde\x07\x23\xd4\x41\x20\xdc\xd3\x07\xa6\x31\x0d\xc4\xf3\x66\xb8\xf3\xcd\x52\xdb\x19\xb8\x26\x6a\x48\x7f\x78\x72\x39\x1c\x45\xfe\x0d\x32\x48\xa7\xab\xf2\xc2\x00\x22\xd3\x76\x95\x47\xf6\x83\x06\x7d\xcc\x36\x3c\xd2\x2f\xd7\xcd\xa3\xca\xdc\x15\x80\x40\x56\xf0\xe2\xaa\x2b\x79\x50\x08\xc5\x98\xbe\x7a\x96\x18\x05\xe6\xdf\x29\x1b\xa3\x04\x1c\x47\xff\x56\x40\x27\x5f\x46\xe6\xae\x82\x09\x2d\x21\xab\xcb\xcf\xba\x11\xe7\x30\x21\x60\x08\x82\x2d\xe3\xce\x46\x24\x00\x59\x6d\xa7\x9f\x7a\xe5\xd1\xdf\x83\x89\x11\x2a\xd9\x88\x68\xfa\x94\xfb\x05\x46\xbf\xe6\xa6\x7a\xa8\xd2\x8c\x4d\x32\x07\x2d\x2e\xad\xd6\x25\x62\x55\xf1\x8c\x23\x82\xe6\x62\xdf\xa9\x22\xa6\x80\xe0\x6a\x43\x62\x2c\x48\x71\xd2\x7d\x18\x07\xf7\xb2\x70\x30\x70\xc8\x3d\xb8\xdd\x92\x9c\x06\x03\x8b\x21\x83\xcb\x8e\x2b\x9e\xc4\xc7\x78\xd7\xec\xf9\xe9\xff\xac\x77\xfa\x77\x37\xb0\x55\xfe\xac\x2e\x79\x82\xae\xee\xc0\xb7\x2f\x1b\xbc\xa2\x42\x4e\x1a\x84\x4b\xba\xc7\x9c\xb2\xe7\x40\x0f\x81\xdc\x44\x9d\x05\x60\xb5\x21\xa7\xc1\x6b\xb4\x16\x7e\x66\x96\x58\x60\x58\xa9\xb8\xed\x2e\x51\x16\x69\x0b\x77\xf2\xa1\x7e\x5c\x0b\x16\xa8\x3d\xcb\xd2\xe2\x45\x52\x29\x3e\x25\x8b\x32\xba\x7f\x84\x49\x44\x37\x93\x42\x69\x86\x27"}, -{{0xdf,0xf0,0xeb,0x6b,0x42,0x6d,0xea,0x2f,0xd3,0x3c,0x1d,0x3f,0xc2,0x4d,0xf9,0xb3,0x1b,0x48,0x6f,0xac,0xb7,0xed,0xb8,0x50,0x29,0x54,0xa3,0xe8,0xda,0x99,0xd9,0xfd,},{0xc2,0x45,0x08,0x5e,0xce,0x69,0xfb,0x9a,0xa5,0x60,0xd0,0xc2,0x7f,0xdb,0x63,0x4f,0x7a,0x84,0x0d,0x41,0xd8,0x46,0x36,0x60,0xfb,0xe8,0x24,0x83,0xb0,0xf3,0xcc,0x3a,},{0x6b,0x48,0xb1,0x0f,0x54,0x5d,0xdb,0x7a,0x89,0xcd,0x58,0x29,0xf4,0xe5,0xb2,0x01,0x46,0xcf,0x6b,0xc9,0x6e,0x55,0x0d,0x06,0xf6,0x5d,0xe8,0xbd,0xae,0x7c,0xcd,0xde,0xd2,0x6c,0xd6,0x30,0xf8,0x6c,0x92,0x66,0xbc,0xcf,0x88,0xe9,0x24,0x03,0x3e,0x04,0xf8,0x3a,0x54,0xf8,0x29,0x0d,0x7f,0x73,0x4c,0xf8,0x67,0x3c,0xca,0x8f,0x97,0x03,},"\xe7\xc9\xe3\x13\xd8\x61\x60\xf4\xc7\x4a\xa0\xae\x07\x36\x9e\xe2\x2b\x27\xf8\x1b\x3f\x69\x09\x7a\xff\xae\x28\xda\xe4\x84\x83\xfb\x52\xa5\xc0\x62\x30\x6b\x59\x61\x0f\x5c\xdb\xff\x63\x32\xb1\x96\x0c\xd6\xf2\xb8\xf7\xb4\x15\x78\xc2\x0f\x0b\xc9\x63\x7a\x0f\xdf\xc7\x39\xd6\x1f\x69\x9a\x57\x3f\x1c\x1a\x0b\x49\x29\x45\x06\xcf\x44\x87\x96\x5e\x5b\xb0\x7b\xbf\x81\x80\x3c\xb3\xd5\xcb\x38\x29\xc6\x6c\x4b\xee\x7f\xc8\x00\xed\xe2\x16\x15\x09\x34\xd2\x77\xde\xa5\x0e\xdb\x09\x7b\x99\x2f\x11\xbb\x66\x9f\xdf\x14\x0b\xf6\xae\x9f\xec\x46\xc3\xea\x32\xf8\x88\xfd\xe9\xd1\x54\xea\x84\xf0\x1c\x51\x26\x5a\x7d\x3f\xef\x6e\xef\xc1\xcc\xdb\xff\xd1\xe2\xc8\x97\xf0\x55\x46\xa3\xb1\xca\x11\xd9\x51\x7c\xd6\x67\xc6\x60\xec\x39\x60\xf7\xa8\xe5\xe8\x02\x02\xa7\x8d\x3a\x38\x8b\x92\xf5\xc1\xde\xe1\x4a\xe6\xac\xf8\xe1\x7c\x84\x1c\x95\x57\xc3\x5a\x2e\xec\xed\x6e\x6a\xf6\x37\x21\x48\xe4\x83\xcc\xd0\x6c\x8f\xe3\x44\x92\x4e\x10\x19\xfb\x91\xcb\xf7\x94\x1b\x9a\x17\x6a\x07\x34\x15\x86\x72\x10\x67\x04\x10\xc5\xdb\xd0\xac\x4a\x50\xe6\xc0\xa5\x09\xdd\xfd\xc5\x55\xf6\x0d\x69\x6d\x41\xc7\x7d\xb8\xe6\xc8\x4d\x51\x81\xf8\x72\x75\x5e\x64\xa7\x21\xb0\x61\xfc\xd6\x8c\x46\x3d\xb4\xd3\x2c\x9e\x01\xea\x50\x12\x67\xde\x22\x87\x9d\x7f\xc1\x2c\x8c\xa0\x37\x9e\xdb\x45\xab\xaa\x6e\x64\xdd\xa2\xaf\x6d\x40\xcc\xf2\x4f\xbe\xba\xd7\xb5\xa8\xd3\xe5\x20\x07\x94\x5e\xcd\x3d\xdc\x1e\x3e\xfe\xb5\x22\x58\x1a\xc8\x0e\x98\xc8\x63\xba\x0c\x59\x0a\x3e\xd9\x5c\xd1"}, -{{0x9f,0x32,0x95,0x8c,0x76,0x79,0xb9,0x0f,0xd5,0x03,0x60,0x56,0xa7,0x5e,0xc2,0xeb,0x2f,0x56,0xec,0x1e,0xff,0xc7,0xc0,0x12,0x46,0x1d,0xc8,0x9a,0x3a,0x16,0x74,0x20,},{0x1d,0x72,0x69,0xdc,0xb6,0xd1,0xf5,0x84,0xe6,0x62,0xd4,0xce,0x25,0x1d,0xe0,0xab,0xa2,0x90,0xef,0x78,0xb9,0x7d,0x44,0x8a,0xfb,0x1e,0x53,0x33,0xf1,0x97,0x6d,0x26,},{0x98,0x81,0xa5,0x76,0x3b,0xdb,0x25,0x9a,0x3f,0xef,0xbb,0xa3,0xd9,0x57,0x16,0x2d,0x6c,0x70,0xb8,0x04,0xfa,0x94,0xab,0x61,0x34,0x06,0xa6,0xec,0x42,0x50,0x5b,0x87,0x89,0x46,0x5c,0xa1,0xa9,0xa3,0x3e,0x18,0x95,0x98,0x88,0x42,0x27,0x0c,0x55,0xe5,0xbd,0xd5,0x48,0x3f,0x6b,0x17,0xb3,0x17,0x81,0xb5,0x93,0x50,0x7a,0x6c,0x18,0x08,},"\xa5\x6b\xa8\x6c\x71\x36\x05\x04\x08\x7e\x74\x5c\x41\x62\x70\x92\xad\x6b\x49\xa7\x1e\x9d\xaa\x56\x40\xe1\x04\x4b\xf0\x4d\x4f\x07\x1a\xd7\x28\x77\x9e\x95\xd1\xe2\x46\x05\x84\xe6\xf0\x77\x35\x45\xda\x82\xd4\x81\x4c\x91\x89\xa1\x20\xf1\x2f\x3e\x38\x19\x81\x3e\x5b\x24\x0d\x0f\x26\x43\x6f\x70\xee\x35\x3b\x4d\x20\xce\xa5\x4a\x14\x60\xb5\xb8\xf1\x00\x8d\x6f\x95\xf3\xaa\x2d\x8f\x1e\x90\x8f\xce\xd5\x0d\x62\x4e\x3a\x09\x69\x38\xb9\x35\x38\x54\xb9\x6d\xa4\x63\xa2\x79\x8a\x5a\x31\x2e\xc7\x90\x84\x2c\x10\xc4\x46\xe3\x35\x0c\x76\x4b\xf5\xc9\x72\x59\x3b\x99\x87\xbf\x23\x25\x6d\xaa\x88\x94\xd4\x7f\x22\xe8\x5b\x97\x60\x7e\x66\xfc\x08\xa1\x2c\x78\x9c\x47\x46\x08\x03\x68\xd3\x21\xbb\x90\x15\xa1\x15\x5b\x65\x52\x3a\xd8\xe9\x9b\xb9\x89\xb4\x4e\xac\x75\x6b\x07\x34\xac\xd7\xc6\x35\x7c\x70\xb5\x97\x43\x24\x6d\x16\x52\xd9\x1b\x0f\x98\x96\x96\x51\x41\x34\x5b\x99\x45\xcf\x34\x98\x04\x52\xf3\x50\x29\x74\xed\xb7\x6b\x9c\x78\x5f\xb0\xf4\x39\x52\x66\xb0\x55\xf3\xb5\xdb\x8a\xab\x68\xe9\xd7\x10\x2a\x1c\xd9\xee\x3d\x14\x25\x04\xf0\xe8\x8b\x28\x2e\x60\x3a\x73\x8e\x05\x1d\x98\xde\x05\xd1\xfc\xc6\x5b\x5f\x7e\x99\xc4\x11\x1c\xc0\xae\xc4\x89\xab\xd0\xec\xad\x31\x1b\xfc\x13\xe7\xd1\x65\x3b\x9c\x31\xe8\x1c\x99\x80\x37\xf9\x59\xd5\xcd\x98\x08\x35\xaa\x0e\x0b\x09\xbc\xbe\xd6\x34\x39\x11\x51\xda\x02\xbc\x01\xa3\x6c\x9a\x58\x00\xaf\xb9\x84\x16\x3a\x7b\xb8\x15\xed\xbc\x02\x26\xed\xa0\x59\x5c\x72\x4c\xa9\xb3\xf8\xa7\x11\x78\xf0\xd2\x0a\x5a"}, -{{0xf8,0x6d,0x6f,0x76,0x6f,0x88,0xb0,0x07,0x17,0xb7,0xd6,0x32,0x7e,0xb2,0x6c,0xf3,0xce,0xeb,0xa5,0x38,0x51,0x84,0x42,0x6f,0x9c,0xfd,0x82,0x95,0xe2,0x42,0x1f,0xf2,},{0xcb,0x1d,0x25,0x05,0x04,0x75,0x41,0x83,0x70,0x4d,0xbe,0x21,0xc3,0x23,0xd6,0x6f,0x9f,0x90,0x11,0x75,0x8f,0x6d,0x8d,0xab,0x6f,0x59,0x7b,0x19,0x96,0x62,0x14,0x5b,},{0xec,0x61,0xc0,0xb2,0x92,0x20,0x3a,0x8f,0x1d,0x87,0x23,0x5e,0xde,0x92,0xb7,0x47,0x23,0xc8,0xd2,0x34,0x08,0x42,0x37,0x73,0xae,0x50,0xb1,0xe9,0xbc,0x44,0x64,0xe0,0x3e,0x44,0x6d,0xa9,0xdc,0xe4,0xc3,0x9f,0x6d,0xd1,0x59,0xbe,0xa2,0x6c,0x00,0x9e,0xd0,0x01,0x20,0xbc,0x36,0xd4,0xa2,0x47,0xdc,0x0d,0x24,0xbc,0xef,0xcc,0x11,0x0c,},"\xda\x84\x23\xa6\xb7\xa1\x8f\x20\xaa\x1f\x90\xed\x23\x31\xb1\x7b\x24\x06\x7c\x40\x17\x5b\xc2\x5d\x81\x09\xe2\x1d\x87\xac\x00\x52\x8e\xb3\xb2\xf6\x6a\x2b\x52\xdc\x7e\xf2\xf8\xce\xcb\x75\xc7\x60\x99\xcf\xa2\x3d\xb8\xda\x89\x70\x43\xba\x1c\xce\x31\xe2\xdf\xea\x46\x07\x5f\x5e\x07\x32\x03\xea\xeb\x3d\x62\xc8\x4c\x10\x7b\x6d\xab\x33\xa1\x4e\xaf\x14\x9a\xa6\x18\x50\xc1\x5f\x5a\x58\xd8\x8a\x15\xab\xa9\x19\x6f\x9e\x49\x5e\x8d\xbe\xcb\xcf\x7e\x84\x44\xf5\xdd\x72\xa0\x8a\x09\x9d\x7f\x62\x09\x99\x0b\x56\x29\x74\xea\x82\x9e\xf1\x1d\x29\xa9\x20\xe3\xa7\x99\xd0\xd9\x2c\xb5\x0d\x50\xf8\x17\x63\x1a\xb0\x9d\xe9\x7c\x31\xe9\xa0\x5f\x4d\x78\xd6\x49\xfc\xd9\x3a\x83\x75\x20\x78\xab\x3b\xb0\xe1\x6c\x56\x4d\x4f\xb0\x7c\xa9\x23\xc0\x37\x4b\xa5\xbf\x1e\xea\x7e\x73\x66\x8e\x13\x50\x31\xfe\xaf\xcb\xb4\x7c\xbc\x2a\xe3\x0e\xc1\x6a\x39\xb9\xc3\x37\xe0\xa6\x2e\xec\xdd\x80\xc0\xb7\xa0\x49\x24\xac\x39\x72\xda\x4f\xa9\x29\x9c\x14\xb5\xa5\x3d\x37\xb0\x8b\xf0\x22\x68\xb3\xba\xc9\xea\x93\x55\x09\x0e\xeb\x04\xad\x87\xbe\xe0\x59\x3b\xa4\xe4\x44\x3d\xda\x38\xa9\x7a\xfb\xf2\xdb\x99\x52\xdf\x63\xf1\x78\xf3\xb4\xc5\x2b\xcc\x13\x2b\xe8\xd9\xe2\x68\x81\x21\x3a\xbd\xeb\x7e\x1c\x44\xc4\x06\x15\x48\x90\x9f\x05\x20\xf0\xdd\x75\x20\xfc\x40\x8e\xa2\x8c\x2c\xeb\xc0\xf5\x30\x63\xa2\xd3\x05\x70\xe0\x53\x50\xe5\x2b\x39\x0d\xd9\xb6\x76\x62\x98\x48\x47\xbe\x9a\xd9\xb4\xcd\x50\xb0\x69\xff\xd2\x9d\xd9\xc6\x2e\xf1\x47\x01\xf8\xd0\x12\xa4\xa7\x0c\x84\x31\xcc"}, -{{0xa5,0xb3,0x4c,0xef,0xab,0x94,0x79,0xdf,0x83,0x89,0xd7,0xe6,0xf6,0xc1,0x46,0xaa,0x8a,0xff,0xb0,0xbe,0xc8,0x37,0xf7,0x8a,0xf6,0x46,0x24,0xa1,0x45,0xcc,0x34,0x4e,},{0x7b,0x0f,0x4f,0x24,0xd9,0x97,0x2b,0xc6,0xfe,0x83,0x82,0x6c,0x52,0x71,0x6a,0xd1,0xe0,0xd7,0xd1,0x9f,0x12,0x38,0x58,0xcb,0x3e,0x99,0xfa,0x63,0x6a,0xc9,0x63,0x1a,},{0x2f,0xbd,0x89,0x9d,0x72,0xb6,0xd3,0x9e,0x4f,0x45,0xb8,0xb6,0x2c,0xbb,0xd5,0xf3,0xc0,0xac,0xb1,0xad,0x85,0x40,0x91,0x3f,0xa5,0x85,0x87,0x7e,0x91,0xcc,0xfe,0xf7,0xbe,0xe5,0x0a,0x4b,0x0f,0x9f,0xed,0xf5,0xcc,0x1e,0x0d,0x19,0x53,0xad,0x39,0x9c,0x83,0x89,0xa9,0x33,0x91,0xe1,0xb7,0xc9,0x29,0xaf,0x6d,0x6f,0x3b,0x79,0x6c,0x08,},"\xe2\x1e\x98\xaf\x6c\x2b\xac\x70\x55\x7e\xb0\xe8\x64\xda\x2c\x2b\x4d\x6c\x0a\x39\xa0\x59\xd3\x47\x72\x51\xf6\x17\x8a\x39\x67\x6f\x47\x49\xe7\xfb\xea\x62\x3f\x14\x8a\x43\xa8\xb0\xfe\x06\x10\x50\x6f\xa6\x58\xab\xd2\xf5\xfa\x39\x19\x8f\x26\x36\xb7\x24\xdb\x22\xd1\xae\xbc\x2a\xb0\x7b\x2b\x6d\xbf\xfd\xee\x8c\xec\xe8\x1e\x1a\xf1\x49\x3e\xc1\x96\x4e\x16\xbf\x86\xab\x25\x8c\xa0\xfe\xb7\x7e\x3c\x87\x17\xe4\x40\x38\xab\xe1\x52\xc1\x4b\xe1\x56\x60\xbf\x93\xb2\xd4\x8d\x92\xc4\xed\x70\x74\xd2\x49\x42\x10\x62\x1b\xcf\x20\x4f\xba\x88\xc6\x54\xd5\xff\xe0\x1e\x1a\x53\xd0\x8f\x70\xbb\x23\x70\x89\xdc\x80\x72\x16\xff\x6a\x85\xdb\xec\x31\x02\x23\x7d\x42\x59\x07\x78\xac\xf6\xc1\xdc\x56\x6d\x5a\x2b\xb9\xa6\x3b\xc2\x1c\x32\x9c\x27\x2e\x59\x65\xba\xee\xb0\xfe\x89\x1d\xe3\xcc\x8c\xbf\xa8\xe5\x41\xa8\x88\x1d\xf6\x89\x42\xe7\xff\x8d\xc6\x56\xbd\x08\x57\x5f\x6a\xaf\x92\x4a\x17\x6d\x66\x3b\x1a\x1f\x43\x57\x4d\x11\x76\x8c\x70\x1b\x26\x95\x61\xe5\x54\x38\xdb\xeb\xfd\x44\x3d\x21\x15\xcb\x93\x3d\x1c\xde\x4a\x91\x5b\x54\xc3\x25\xc2\x7f\x49\x9e\xf0\x2b\xd0\x12\xff\x1f\x9a\x36\x39\x09\x22\x88\x76\x00\xfe\x71\x2b\xcd\xc2\x3e\xb5\x97\x4a\x30\x53\x72\xad\x52\x95\x1f\x83\xf0\xe5\x8c\xc4\x9e\x28\x98\x41\x62\x19\x17\xf1\xfc\xb0\x23\x51\x47\x24\x0d\xae\x4c\xf3\xb9\x9b\x6a\xc6\xd8\xde\x94\xef\xe7\xc4\x43\x67\x14\x50\x8b\xcd\x01\x14\xc5\x60\x68\xff\x1b\x7c\x16\xd5\x1b\xd9\x06\x43\x78\x74\xd6\x54\x9a\xb5\xd8\x08\x78\x96\x87\x2e\xc8\xa0\x9d\x74\x12"}, -{{0xad,0x75,0xc9,0xce,0x29,0x9c,0x4d,0x59,0x39,0x33,0x67,0xd7,0x7a,0x4c,0x9f,0x8d,0xf8,0xdc,0xec,0x76,0x5c,0x6d,0xbd,0x25,0xb5,0x27,0xfb,0x76,0x69,0x91,0x36,0x04,},{0xb9,0x91,0x05,0x48,0xfe,0x63,0x12,0xa1,0x19,0xc9,0x99,0x3e,0xeb,0xcf,0xb9,0xdc,0x90,0x03,0x0f,0xfb,0x0e,0x4d,0xe2,0xb7,0xcc,0xd2,0x3c,0xbe,0xb4,0xfe,0xf7,0x1b,},{0x6b,0x7e,0xf2,0x7b,0xcf,0xbf,0x2b,0x71,0x49,0x85,0x03,0x37,0x64,0xfc,0xcf,0xf5,0x55,0xe3,0xf5,0xbc,0x44,0x61,0x0d,0x6c,0x8c,0x62,0x11,0x7c,0xb3,0x83,0x1a,0x07,0xf4,0xa8,0xbd,0xdb,0x0e,0xae,0xd1,0xd4,0x6b,0x02,0x89,0xb1,0x5d,0xe1,0xaa,0x4d,0xcc,0x17,0xd7,0x1b,0xe9,0x6a,0x09,0xe6,0x6b,0xa4,0xdc,0x46,0x27,0xc7,0x87,0x05,},"\x62\xfc\x5a\xb6\x7d\xeb\x1f\xee\x9a\xb6\xcc\xa3\xb8\x8a\x1d\xf1\xe5\x89\xf0\xfd\x4a\x88\xf4\xaa\x77\x38\x94\x87\x61\xfe\x84\x37\x2c\x5b\x18\xe4\x65\x52\x20\xc1\xd8\x4d\x52\xac\xad\x32\xe2\x29\xa5\xc7\x56\xc2\x0f\xc6\x2f\xe4\xb4\xb4\xe5\xfd\x70\x77\xae\x4e\xd5\x39\x7a\xa7\x96\xf2\x30\x7c\xee\xdb\x65\x05\xb3\x92\x97\x85\x6f\x4a\xeb\x5e\x70\x93\x8e\x36\xee\x24\xa0\xac\x7d\x98\x68\x30\x6f\x6b\x53\x91\x06\x23\xb7\xdc\x89\xa6\x67\x2a\xd7\x38\x57\x6e\xd5\xd8\x88\x31\xdd\x33\x83\x21\xc8\x90\x2b\xc2\x06\x1f\x65\xe9\x4d\x45\x2f\xdf\xa0\xdc\x66\x5c\xef\xb9\x23\x08\xe5\x23\x01\xbd\x46\x27\x00\x6b\x36\x3d\x06\xb7\x75\xa3\x95\x91\x4d\x8c\x86\x3e\x95\xa0\x0d\x68\x93\xf3\x37\x61\x34\xc4\x29\xf5\x64\x78\x14\x5e\x44\x56\xf7\xa1\x2d\x65\xbb\x2b\x89\x65\xd7\x28\xcb\x2d\xdb\xb7\x08\xf7\x12\x5c\x23\x70\x95\xa9\x21\x95\xd9\x2f\xa7\x27\xa3\x72\xf3\x54\x5a\xe7\x01\xf3\x80\x8f\xee\x80\x2c\x89\x67\xa7\x6e\x8a\x94\x0e\x55\xfb\x2d\x81\x0b\xfb\x47\xad\xa1\x56\xf0\xed\xa1\x82\x9b\x15\x9c\xf0\x5c\x7f\x36\xcf\x38\x47\xd7\xb2\x1d\xe8\x4c\x3d\xc0\xfe\x65\x83\x47\xf7\x93\x96\xa0\x11\x39\xa5\x08\xb6\x00\x22\xdb\x1c\x0e\x5a\xee\xf4\x7e\x44\x5e\x66\xf7\x83\xe6\x2c\x96\x59\x7b\xdb\x16\xf2\x09\xc0\x8a\x91\x32\xc7\x57\x31\x36\x17\x0e\xe3\xeb\xf2\x42\x61\x26\x5a\x89\xfb\x4f\x10\x33\x33\x75\xe2\x0b\x33\xab\x74\x03\x46\x4f\x52\x49\x46\x1c\x68\x53\xc5\xfd\xdb\x9f\x58\xaf\x81\x68\x92\x91\x03\x93\xa7\x07\x7b\x79\x9f\xdc\x34\x89\x72\x09\x98\xfe\xea\x86"}, -{{0x1c,0xed,0x57,0x45,0x29,0xb9,0xb4,0x16,0x97,0x7e,0x92,0xeb,0x39,0x44,0x8a,0x87,0x17,0xca,0xc2,0x93,0x4a,0x24,0x3a,0x5c,0x44,0xfb,0x44,0xb7,0x3c,0xcc,0x16,0xda,},{0x85,0xe1,0x67,0xd5,0xf0,0x62,0xfe,0xe8,0x20,0x14,0xf3,0xc8,0xb1,0xbe,0xae,0xd8,0xee,0xfb,0x2c,0x22,0xd8,0x64,0x9c,0x42,0x4b,0x86,0xb2,0x1b,0x11,0xeb,0x8b,0xda,},{0xe0,0x30,0x3a,0xef,0xe0,0x8a,0x77,0x73,0x8d,0xcc,0x65,0x7a,0xfb,0xb9,0xb8,0x35,0xed,0x27,0x96,0x13,0xa5,0x3c,0x73,0xfd,0xc5,0xdd,0xbf,0xb3,0x50,0xe5,0xcf,0xf4,0xd6,0xc9,0xbb,0x43,0xdc,0x07,0xc9,0x5b,0xf4,0xe2,0x3b,0x64,0xc4,0x0f,0x88,0x04,0xc7,0x16,0x99,0x52,0xe3,0xc8,0xd5,0x9a,0x71,0x97,0x24,0x1b,0xfe,0xd0,0x74,0x0f,},"\x1b\x3b\x95\x3c\xce\x6d\x15\x30\x3c\x61\xca\x70\x76\x09\xf7\x0e\x72\x50\xf6\xc0\xde\xba\x56\xa8\xce\x52\x2b\x59\x86\x68\x96\x51\xcd\xb8\x48\xb8\x42\xb2\x22\x96\x61\xb8\xee\xab\xfb\x85\x70\x74\x9e\xd6\xc2\xb1\x0a\x8f\xbf\x51\x50\x53\xb5\xea\x7d\x7a\x92\x28\x34\x9e\x46\x46\xf9\x50\x5e\x19\x80\x29\xfe\xc9\xce\x0f\x38\xe4\xe0\xca\x73\x62\x58\x42\xd6\x4c\xaf\x8c\xed\x07\x0a\x6e\x29\xc7\x43\x58\x6a\xa3\xdb\x6d\x82\x99\x3a\xc7\x1f\xd3\x8b\x78\x31\x62\xd8\xfe\x04\xff\xd0\xfa\x5c\xbc\x38\x1d\x0e\x21\x9c\x91\x93\x7d\xf6\xc9\x73\x91\x2f\xc0\x2f\xda\x53\x77\x31\x24\x68\x27\x4c\x4b\xee\x6d\xca\x7f\x79\xc8\xb5\x44\x86\x1e\xd5\xba\xbc\xf5\xc5\x0e\x14\x73\x49\x1b\xe0\x17\x08\xac\x7c\x9f\xf5\x8f\x1e\x40\xf8\x55\x49\x7c\xe9\xd7\xcc\x47\xb9\x41\x0f\x2e\xdd\x00\xf6\x49\x67\x40\x24\x3b\x8d\x03\xb2\xf5\xfa\x74\x2b\x9c\x63\x08\x67\xf7\x7a\xc4\x2f\x2b\x62\xc1\x4e\x5e\xbd\xdc\x7b\x64\x7a\x05\xff\xf4\x36\x70\x74\x5f\x28\x51\xef\xf4\x90\x9f\x5d\x27\xd5\x7a\xe8\x7f\x61\xe9\x65\xee\x60\xfd\xf9\x77\x24\xc5\x92\x67\xf2\x61\x0b\x7a\xd5\xde\x91\x98\x56\xd6\x4d\x7c\x21\x26\x59\xce\x86\x56\x14\x9b\x6a\x6d\x29\xd8\xf9\x2b\x31\x2b\xe5\x0b\x6e\x2a\x43\x1d\x36\xae\x02\x2b\x00\xa6\xfe\x36\x0e\x3a\xf6\x54\x32\x89\x9c\x43\xbe\x04\x27\xe3\x6d\x21\xcf\xec\x81\xf2\x1a\xa5\x3b\x33\xdb\x5e\xd2\xc3\x7d\xa8\xf9\x6a\xc3\xe7\xdc\x67\xa1\xde\x37\x54\x6c\xf7\xde\x10\x08\xc7\xe1\xad\xbe\x0f\x34\xfa\x7e\xb2\x43\x4d\x94\xe6\xa1\x3f\x4c\xf8\x6a\x98\xd4\x97\x62\x2f"}, -{{0xf0,0x79,0x0d,0x93,0xe2,0xd3,0xb8,0x4f,0x61,0xef,0x4c,0x80,0x71,0x47,0xab,0xa4,0x10,0xe4,0x15,0xe7,0x2b,0x71,0xb0,0xd6,0x1d,0x01,0x02,0x6f,0xed,0x99,0xda,0x3d,},{0xef,0xdf,0x64,0x9f,0xb0,0x33,0xcf,0x32,0x8e,0x0b,0x28,0x77,0x96,0xf8,0xa2,0x5e,0x9c,0x6e,0x2e,0x87,0x1b,0x33,0xc2,0xc2,0x1a,0x40,0x28,0xa8,0xa2,0x5a,0x4b,0x28,},{0x08,0x77,0x3a,0x6a,0x78,0x76,0x2c,0xbb,0x1e,0x25,0xfc,0xbb,0x29,0x13,0x99,0x41,0xbd,0xf1,0x6f,0x4e,0x09,0xa1,0xfa,0x08,0xfc,0x70,0x1f,0x32,0xf9,0x33,0xed,0xd7,0x4c,0x0a,0xe9,0x83,0xc1,0x2a,0x0a,0x5b,0x02,0x0b,0x6b,0xcf,0x44,0xbb,0x71,0x9d,0xde,0x8e,0xd0,0x78,0x1a,0x82,0x98,0x26,0x56,0x40,0xe1,0x60,0x8c,0x98,0xb3,0x01,},"\x79\x73\xe9\xf3\x2d\x74\x80\x59\x92\xeb\x65\xda\x0d\x63\x73\x35\xe5\x0e\xff\x0c\xe6\x8e\xa2\xd1\xf3\xa0\x2d\xe7\x04\x49\x2b\x9c\xfb\xe7\xe7\xba\x96\xfd\xb4\x2b\xb8\x21\xa5\x13\xd7\x3f\xc6\x04\x02\xe9\x2c\x85\x5d\xea\xed\x73\xff\xea\xf7\x09\x52\x02\x90\x62\xc8\x33\xe1\x4e\xc1\xb1\x4f\x14\x4e\x22\x07\xf6\xa0\xe7\x27\xe5\xa7\xe3\xcb\xab\x27\xd5\x97\x29\x70\xf6\x95\x18\xa1\x5b\x09\x3e\x74\x0c\xc0\xce\x11\xbf\x52\x48\xf0\x82\x6b\x8a\x98\xbd\xe8\xbf\x2c\x70\x82\xc9\x7a\xff\x15\x8d\x08\x37\x11\x18\xc8\x90\x21\xcc\x39\x74\xae\x8f\x76\xd8\x66\x73\xc3\xf8\x24\xb6\x2c\x79\xc4\xb4\x1f\x40\xea\xa8\x94\x37\x38\xf0\x33\x00\xf6\x8c\xbe\x17\x54\x68\xeb\x23\x5a\x9f\xf0\xe6\x53\x7f\x87\x14\xe9\x7e\x8f\x08\xca\x44\x4e\x41\x19\x10\x63\xb5\xfa\xbd\x15\x6e\x85\xdc\xf6\x66\x06\xb8\x1d\xad\x4a\x95\x06\x55\x84\xb3\xe0\x65\x8c\x20\xa7\x06\xea\xf4\xa0\x77\x7d\xa4\xd2\xe0\xcd\x2a\x0f\xca\x60\x10\x9c\x2b\x44\x03\xdb\x3f\x03\xcd\x47\x81\xc1\xfb\xb0\x27\x22\x02\xbc\xb1\x16\x87\x80\x8c\x50\xcb\x98\xf6\x4b\x7f\x3f\xd3\xd4\x33\x33\xbb\x5a\x06\x1b\x9e\x37\x70\x90\xab\xb1\xe0\xa8\x85\xcb\x26\xb7\x3c\x16\x3e\x63\xff\x64\x51\xff\x2f\x4e\xc8\x24\x9c\x7e\x15\x2b\xd0\x39\x73\xa1\xe9\x64\xe2\xb5\xb2\x35\x28\x1a\x93\x83\x99\xa1\x12\xa2\x45\x29\xe3\x83\xa5\x60\xdc\x50\xbb\x1b\x62\x2a\xd7\x4e\xf3\x56\x58\xdc\xb1\x0f\xfe\x02\x25\x68\xac\x3f\xfa\xe5\xb4\x65\xa8\xed\x76\x43\xe8\x56\x1b\x35\x2e\xe9\x94\x4a\x35\xd8\x82\xc7\x12\xb1\x87\x78\x8a\x0a\xba\xe5\xa2\x2f"}, -{{0x4c,0xb9,0xdf,0x7c,0xe6,0xfa,0xe9,0xd6,0x2b,0xa0,0x9e,0x8e,0xb7,0x0e,0x4c,0x96,0x9b,0xde,0xaf,0xcb,0x5e,0xc7,0xd7,0x02,0x43,0x26,0xe6,0x60,0x3b,0x06,0x21,0xbf,},{0x01,0x80,0x69,0xdd,0x0e,0xb4,0x40,0x55,0xa3,0x5c,0xd8,0xc7,0x7c,0x37,0xca,0x9f,0xb1,0xad,0x24,0x17,0x27,0x13,0x85,0xe1,0x34,0xb2,0xf4,0xe8,0x1f,0x52,0x03,0x3c,},{0xe3,0x3c,0x07,0x83,0x6c,0x53,0x7d,0x6b,0xfb,0xd0,0xf4,0x59,0x2d,0x6e,0x35,0xb1,0x63,0x49,0x9b,0xa7,0x8d,0xc7,0xff,0xce,0xc5,0x65,0xd0,0x4f,0x9a,0x7d,0xb7,0x81,0x94,0x3e,0x29,0xe6,0xce,0x76,0x76,0x3e,0x9b,0xad,0xdf,0x57,0x43,0x7f,0xd9,0xc6,0xb0,0x32,0x39,0xa6,0xe6,0x85,0x0e,0x45,0x02,0xa3,0x56,0xc2,0xe1,0x2c,0x37,0x05,},"\x14\x62\x7d\x6e\xa0\xe7\x89\x54\x60\x75\x94\x76\xdc\x74\xc4\x28\x00\xce\xef\x99\x43\x27\x51\x81\x51\x49\x0d\x9d\xf2\x30\x67\x91\x4e\x44\x78\x8a\x12\x76\x8c\xcb\x25\x47\x1b\x9c\x3b\xa9\xd1\x4f\xb4\x36\xdc\xba\x38\x42\x9b\x3a\x04\x56\x87\x77\x63\xc4\x91\x75\xd0\xe0\x82\x68\x3e\x07\xa9\x05\x8f\x36\x85\xc6\x27\x93\x07\xb2\x30\x3d\x12\x21\xb9\xc2\x97\x93\xd8\xa4\x87\x7f\x6d\xf5\x15\x87\x38\x4d\xad\xf7\x51\xc5\xf7\xbf\xbd\x20\x7d\x51\x96\x22\xc3\x7b\x51\xce\xee\xe2\xc2\x0d\x82\x69\xf8\xcb\x88\xd3\xfe\x43\xd6\xd4\x34\xd5\xbb\xd0\xe2\x03\xc1\x53\x2d\x97\xba\x55\x21\x47\x22\x74\x96\xc8\x7f\x67\xb5\x0b\xb7\x61\x93\xad\xd0\x14\x4d\xf1\xc1\x76\x65\x75\x85\x40\x83\x62\xca\x2e\xd0\x4a\xd6\x2a\xcf\x1c\x25\xe3\x41\xdf\xd1\x49\x8d\x85\xb4\xb1\x34\x9a\x8b\x0b\x9b\x02\xc4\x35\x23\xc5\x58\x53\x41\x9b\xfe\xd3\x7d\x5a\x2c\xdf\x17\xdf\xbf\x1a\x3b\xd7\x75\x9d\x6a\xe1\x80\xf9\xd2\x7d\xcd\x9a\x89\x33\xe2\x9a\x7c\x0a\x30\x77\x1e\xea\x7c\x2e\x0f\xa2\x42\x92\x5d\x23\x36\xdc\xe5\x85\x62\x90\x57\xd8\x44\x32\x39\x64\xf6\xd3\xd1\x1f\xf0\xb3\xf8\x29\xa3\xbe\x8c\x9f\x04\x68\xa6\x82\x3d\x8e\x70\xab\x5a\x2d\xa2\x1e\x15\xfa\x8b\x04\x1a\x29\x81\x22\x22\xe9\xc3\x0b\x2b\xd9\xa1\x2d\x1f\xde\xe6\xf8\x78\x76\xe8\xce\x81\x00\x96\x37\xa8\xbb\x22\x36\x12\x9a\x47\xca\x74\x28\x9e\xe4\xaa\xd4\x29\xff\xe2\x9f\x47\x43\x02\x41\xca\x8c\xc3\x84\x8b\x72\x00\xfd\x6e\x14\x70\x65\x1a\x9a\x0a\x6f\x72\xc9\x03\x3e\x83\x1d\xf0\x51\x40\x8a\x62\x60\xf6\x5c\xba\xf6\xe0\x12\xb1\x8e"}, -{{0xa1,0x36,0xe0,0x09,0xd5,0x3e,0x5e,0xf5,0x9d,0x09,0x46,0xbc,0x17,0x56,0x63,0xa8,0x6b,0xc0,0xfc,0xd2,0x9e,0xad,0xd9,0x5c,0xfc,0x9d,0x26,0x60,0x37,0xb1,0xe4,0xfb,},{0x9c,0x18,0x06,0xec,0x04,0x54,0xf5,0x83,0x14,0xeb,0x83,0x97,0xd6,0x42,0x87,0xde,0xe3,0x86,0x64,0x0d,0x84,0x91,0xab,0xa3,0x64,0x60,0x76,0x88,0x84,0x17,0x15,0xa0,},{0xbc,0x09,0x4b,0xa9,0x1c,0x11,0x5d,0xee,0x15,0xd7,0x53,0x36,0x1a,0x75,0xf3,0xf0,0x3d,0x6a,0xf4,0x5c,0x92,0x15,0x7e,0x95,0xdb,0xe8,0xd3,0x21,0x94,0xb6,0xc5,0xce,0x72,0xb9,0xdc,0x66,0xf7,0x3d,0xf1,0x2d,0xca,0x0b,0x63,0x9f,0x3e,0x79,0x1d,0x47,0x86,0x16,0xa1,0xf8,0xd7,0x35,0x9a,0x42,0xc8,0xea,0xe0,0xdd,0xa1,0x6b,0x16,0x06,},"\xa4\x9d\x1c\x3d\x49\xe1\x3c\x2e\xda\x56\x86\x8a\x88\x24\xaa\x9f\x8d\x2b\xf7\x2f\x21\x95\x5e\xba\xfd\x07\xb3\xbd\xc8\xe9\x24\xde\x20\x93\x6c\xee\x51\x3d\x8a\x64\xa4\x71\x73\xa3\xbd\x65\x9e\xff\x1a\xcc\xff\x82\x44\xb2\x6a\xae\x1a\x0c\x27\xfa\x89\x1b\xf4\xd8\x5e\x8f\xb1\xb7\x6a\x6c\xab\x1e\x7f\x74\xc8\x9e\xe0\x7b\xb4\x0d\x71\x43\x26\xf0\x9b\x3f\xd4\x06\x32\xfa\xd2\x08\xea\x81\x6f\x90\x72\x02\x8c\x14\xb5\xb5\x4e\xcc\x1c\x5b\x7f\xc8\x09\xe7\xe0\x78\x6e\x2f\x11\x49\x5e\x76\x01\x7e\xb6\x2a\xa4\x56\x3f\x3d\x00\xee\x84\x34\x8d\x98\x38\xcd\x17\x64\x9f\x69\x29\xa6\xd2\x06\xf6\x0e\x6f\xc8\x2e\x0c\x34\x64\xb2\x7e\x0e\x6a\xbd\x22\xf4\x46\x9b\xdf\xd4\xcb\x54\xf7\x7e\x32\x9b\x80\xf7\x1b\xf4\x21\x29\xec\x13\xc9\xdf\xe1\x92\xad\xfa\xa4\x2e\xe3\xdd\xee\xda\x38\x58\x16\xfb\xad\x5f\x41\x19\x38\xc6\x3b\x56\x0f\x4e\xcd\x94\x53\x4b\xe7\xd9\x87\x25\xcd\x94\xc9\x9c\xe4\x92\xf0\xf0\x69\xba\x0e\xc0\x8f\x87\x7a\x78\x12\xef\x27\xae\x19\xd7\xa7\x7b\xe6\x3f\x66\xbc\xf8\xd6\xcf\x3a\x1a\x61\xfc\x9c\xfe\xf1\x04\xc7\x46\x2a\x21\xca\x7f\x03\xaf\xb5\xbb\x1a\xc8\xc7\x51\x24\xb5\x54\xe8\xd0\x44\xb8\x10\xd9\x5f\xf8\xc9\xdd\x09\xa3\x44\x84\xd8\xc4\xb6\xc9\x5f\x95\xc3\xc2\x28\x23\xf5\x2c\xe8\x44\x29\x37\x24\xd5\x25\x91\x91\xf1\xba\x09\x29\xe2\xac\xdb\xb8\xb9\xa7\xa8\xad\xf0\xc5\x2e\x78\xac\xdf\xdf\x05\x7b\x09\x85\x88\x1a\xfb\xed\x4d\xbe\xbd\xeb\xbd\xae\x0a\x2b\x63\xbd\x4e\x90\xf9\x6a\xfd\xcb\xbd\x78\xf5\x06\x30\x9f\x9b\xdb\x65\x00\x13\xcb\x73\xfa\xed\x73\x90\x4e"}, -{{0xff,0x0f,0x1c,0x57,0xdd,0x88,0x4f,0xbe,0xea,0x6e,0x29,0x17,0x28,0x2b,0x79,0xba,0x67,0xf8,0xa6,0x85,0x12,0x67,0xb9,0xf4,0x63,0x6d,0xaf,0xda,0x33,0xbd,0x2b,0x5b,},{0xfe,0xf6,0x37,0x8a,0xd1,0x2a,0x7c,0x25,0x2f,0xa6,0xeb,0x74,0x2b,0x05,0x06,0x4b,0x41,0x53,0x0f,0xf0,0x19,0xdc,0x68,0x0a,0xb5,0x44,0xc0,0x27,0xea,0x28,0x36,0xe7,},{0xd5,0x00,0x84,0x86,0x72,0x6c,0xce,0x33,0x0a,0x29,0xdd,0x7e,0x4d,0x74,0x74,0xd7,0x35,0x79,0x82,0x01,0xaf,0xd1,0x20,0x6f,0xeb,0x86,0x9a,0x11,0x2e,0x5b,0x43,0x52,0x3c,0x06,0x97,0x67,0x61,0xbe,0x3c,0xf9,0xb2,0x71,0x63,0x78,0x27,0x3c,0x94,0xf9,0x35,0x72,0xa7,0xd2,0xb8,0x98,0x26,0x34,0xe0,0x75,0x5c,0x63,0x2b,0x44,0x90,0x08,},"\x52\x2a\x5e\x5e\xff\x5b\x5e\x98\xfa\xd6\x87\x8a\x9d\x72\xdf\x6e\xb3\x18\x62\x26\x10\xa1\xe1\xa4\x81\x83\xf5\x59\x0e\xce\xf5\xa6\xdf\x67\x1b\x28\xbe\x91\xc8\x8c\xdf\x7a\xe2\x88\x11\x47\xfe\x6c\x37\xc2\x8b\x43\xf6\x4c\xf9\x81\xc4\x55\xc5\x9e\x76\x5c\xe9\x4e\x1b\x64\x91\x63\x1d\xea\xee\xf6\xd1\xda\x9e\xbc\xa8\x86\x43\xc7\x7f\x83\xea\xe2\xcf\xdd\x2d\x97\xf6\x04\xfe\x45\x08\x1d\x1b\xe5\xc4\xae\x2d\x87\x59\x96\xb8\xb6\xfe\xcd\x70\x7d\x3f\xa2\x19\xa9\x3b\xa0\x48\x8e\x55\x24\x7b\x40\x5e\x33\x0c\xfb\x97\xd3\x1a\x13\x61\xc9\xb2\x08\x4b\xdb\x13\xfb\x0c\x05\x89\x25\xdb\x8c\x3c\x64\x9c\x9a\x3e\x93\x7b\x53\x3c\xc6\x31\x0f\xa3\xb1\x61\x26\xfb\x3c\xc9\xbb\x2b\x35\xc5\xc8\x30\x00\x15\x48\x8a\x30\xfa\xdc\xa3\xc8\x87\x1f\xa7\x0d\xfd\xc7\x05\x5b\xf8\xe6\x31\xf2\x0c\x9b\x25\x28\x31\x1e\x32\x4a\x7c\x4e\xdd\x54\x62\x07\x9f\x34\x41\xc9\xec\xf5\x5f\xa9\x99\xe7\x31\x37\x23\x44\xfd\xc0\xd4\x13\xe4\x17\xaa\xa0\x01\xa1\xb2\xd3\xd9\xbc\x00\x0f\xec\x1b\x02\xbd\x7a\x88\xa8\x12\xd9\xd8\xa6\x6f\x94\x64\x76\x4c\x07\x0c\x93\x04\x1e\xef\xb1\x7c\xe7\x4e\xff\x6d\x4a\xff\x75\xf0\xcb\xf6\xa7\x89\xa9\xec\xde\x74\xab\xe3\x31\x30\xfc\xa0\xda\x85\x3a\xa7\xc3\x31\x3a\xda\x3f\x0a\xe2\xf5\x95\xc6\x79\x6a\x93\x68\x5e\x72\x9d\xd1\x8a\x66\x9d\x63\x81\x82\x5a\xb3\xf3\x6a\x39\x1e\x75\x25\xb2\xa8\x07\xa5\x2f\xa5\xec\x2a\x03\x0a\x8c\xf3\xb7\x73\x37\xac\x41\xfc\xeb\x58\x0e\x84\x5e\xed\x65\x5a\x48\xb5\x47\x23\x8c\x2e\x81\x37\xc9\x2f\x8c\x27\xe5\x85\xca\xad\x31\x06\xee\xe3\x81\x4a"}, -{{0x0b,0xc6,0xaf,0x64,0xde,0x57,0x09,0xd3,0xdb,0xc2,0x8f,0x7e,0xf6,0xd3,0xfe,0x28,0xb6,0xde,0x52,0x9f,0x08,0xf5,0x85,0x7c,0xcb,0x91,0x06,0x95,0xde,0x45,0x4f,0x56,},{0xfb,0x49,0x1f,0xc9,0x00,0x23,0x7b,0xdc,0x7e,0x9a,0x11,0x9f,0x27,0x15,0x0c,0xd9,0x11,0x93,0x5c,0xd3,0x62,0x87,0x49,0xff,0x40,0xef,0x41,0xf3,0x95,0x5b,0xc8,0xac,},{0xdb,0xc7,0x13,0x4d,0x1c,0xd6,0xb0,0x81,0x3b,0x53,0x35,0x27,0x14,0xb6,0xdf,0x93,0x94,0x98,0xe9,0x1c,0xf3,0x7c,0x32,0x43,0x37,0xd9,0xc0,0x88,0xa1,0xb9,0x98,0x34,0x7d,0x26,0x18,0x5b,0x43,0x09,0x00,0x41,0x29,0x29,0xe4,0xf6,0x3e,0x91,0x03,0x79,0xfc,0x42,0xe3,0x55,0xa4,0xe9,0x8f,0x6f,0xee,0x27,0xda,0xfa,0xd1,0x95,0x72,0x06,},"\xac\x78\x86\xe4\xf4\x17\x2a\x22\xc9\x5e\x8e\xea\x37\x43\x7b\x37\x5d\x72\xac\xce\xdc\xee\x6c\xc6\xe8\x16\x76\x33\x01\xa2\xd8\xef\x4d\x6f\x31\xa2\xc1\xd6\x35\x81\x8b\x70\x26\xa3\x95\xce\x0d\xaf\xd7\x1c\x51\x80\x89\x3a\xf7\x6b\x7e\xa0\x56\xc9\x72\xd6\x80\xec\xa0\x1d\xcb\xdb\xae\x6b\x26\xf1\xc5\xf3\x3f\xc9\x88\xb8\x24\xfb\xbe\x00\xca\xcc\x31\x64\x69\xa3\xba\xe0\x7a\xa7\xc8\x88\x5a\xf7\xf6\x5f\x42\xe7\x5c\xef\x94\xdb\xb9\xaa\xb4\x82\x51\x43\xc8\x50\x70\xe7\x71\x6b\x76\x12\xf6\x4e\xf0\xb0\x16\x60\x11\xd2\x3e\xb5\x65\x4a\xa0\x98\xb0\x2d\x8d\x71\xe5\x7c\x8f\xa1\x7b\xff\x2f\xe9\x7d\xc8\x19\x31\x77\xea\xdc\x09\xfb\x19\x2d\x80\xaa\x92\xaf\xa9\x87\x20\xd4\x61\x48\x17\xff\x3c\x39\xd3\xac\xce\x18\x90\x6f\xa3\xde\x09\x61\x89\x31\xd0\xd7\xa6\x0c\x44\x29\xcb\xfa\x20\xcf\x16\x5c\x94\x79\x29\xac\x29\x3a\xe6\xc0\x6e\x7e\x8f\x25\xf1\x26\x42\x91\xe3\xe1\xc9\x8f\x5d\x93\xe6\xec\xc2\x38\x9b\xc6\x0d\xbb\xf4\xa6\x21\xb1\x32\xc5\x52\xa9\x9c\x95\xd2\x6d\x8d\x1a\xf6\x11\x38\xb5\x70\xa0\xde\x4b\x49\x7e\xbe\x80\x51\xc7\x27\x3a\x98\xe6\xe7\x87\x6d\x0b\x32\x75\x03\xaf\x3c\xb2\xcc\x40\x91\xce\x19\x25\xcb\x2f\x29\x57\xf4\xec\x56\xee\x90\xf8\xa0\x9d\xd5\x7d\x6e\x83\x06\x7a\x35\x6a\x4c\xfe\x65\xb1\xb7\xa4\x46\x5d\xa2\xab\x13\x3b\x0e\xfb\x5e\x7d\x4d\xbb\x81\x1b\xcb\xbd\xe7\x12\xaf\xbf\x0f\x7d\xd3\xf3\x26\x22\x22\x84\xb8\xc7\x4e\xac\x7a\xd6\x25\x7f\xa8\xc6\x32\xb7\xda\x25\x59\xa6\x26\x6e\x91\xe0\xef\x90\xdb\xb0\xaa\x96\x8f\x75\x37\x6b\x69\x3f\xca\xa5\xda\x34\x22\x21"}, -{{0x2f,0x5e,0x83,0xbd,0x5b,0x41,0x2e,0x71,0xae,0x3e,0x90,0x84,0xcd,0x36,0x9e,0xfc,0xc7,0x9b,0xf6,0x03,0x7c,0x4b,0x17,0x4d,0xfd,0x6a,0x11,0xfb,0x0f,0x5d,0xa2,0x18,},{0xa2,0x2a,0x6d,0xa2,0x9a,0x5e,0xf6,0x24,0x0c,0x49,0xd8,0x89,0x6e,0x3a,0x0f,0x1a,0x42,0x81,0xa2,0x66,0xc7,0x7d,0x38,0x3e,0xe6,0xf9,0xd2,0x5f,0xfa,0xcb,0xb8,0x72,},{0x9f,0x80,0x92,0x2b,0xc8,0xdb,0x32,0xd0,0xcc,0x43,0xf9,0x93,0x6a,0xff,0xeb,0xe7,0xb2,0xbc,0x35,0xa5,0xd8,0x22,0x77,0xcd,0x18,0x7b,0x5d,0x50,0xdc,0x7f,0xc4,0xc4,0x83,0x2f,0xff,0xa3,0x4e,0x95,0x43,0x80,0x6b,0x48,0x5c,0x04,0x54,0x8e,0x7c,0x75,0x42,0x94,0x25,0xe1,0x4d,0x55,0xd9,0x1f,0xc1,0x05,0x2e,0xfd,0x86,0x67,0x43,0x0b,},"\xb7\x66\x27\x3f\x06\x0e\xf3\xb2\xae\x33\x40\x45\x4a\x39\x1b\x42\x6b\xc2\xe9\x72\x64\xf8\x67\x45\x53\xeb\x00\xdd\x6e\xcf\xdd\x59\xb6\x11\xd8\xd6\x62\x92\x9f\xec\x71\x0d\x0e\x46\x20\x20\xe1\x2c\xdb\xf9\xc1\xec\x88\x58\xe8\x56\x71\xac\xf8\xb7\xb1\x44\x24\xce\x92\x07\x9d\x7d\x80\x1e\x2a\xd9\xac\xac\x03\x6b\xc8\xd2\xdf\xaa\x72\xaa\x83\x9b\xff\x30\xc0\xaa\x7e\x41\x4a\x88\x2c\x00\xb6\x45\xff\x9d\x31\xbc\xf5\xa5\x43\x82\xde\xf4\xd0\x14\x2e\xfa\x4f\x06\xe8\x23\x25\x7f\xf1\x32\xee\x96\x8c\xdc\x67\x38\xc5\x3f\x53\xb8\x4c\x8d\xf7\x6e\x9f\x78\xdd\x50\x56\xcf\x3d\x4d\x5a\x80\xa8\xf8\x4e\x3e\xde\xc4\x85\x20\xf2\xcb\x45\x83\xe7\x08\x53\x93\x55\xef\x7a\xa8\x6f\xb5\xa0\xe8\x7a\x94\xdc\xf1\x4f\x30\xa2\xcc\xa5\x68\xf1\x39\xd9\xce\x59\xea\xf4\x59\xa5\xc5\x91\x6c\xc8\xf2\x0b\x26\xaa\xf6\xc7\xc0\x29\x37\x9a\xed\xb0\x5a\x07\xfe\x58\x5c\xca\xc6\x03\x07\xc1\xf5\x8c\xa9\xf8\x59\x15\x7d\x06\xd0\x6b\xaa\x39\x4a\xac\xe7\x9d\x51\xb8\xcb\x38\xcf\xa2\x59\x81\x41\xe2\x45\x62\x4e\x5a\xb9\xb9\xd6\x87\x31\x17\x33\x48\x90\x53\x15\xbf\x1a\x5a\xd6\x1d\x1e\x8a\xda\xeb\x81\x0e\x4e\x8a\x86\xd7\xc1\x35\x37\xb0\xbe\x86\x0a\xb2\xed\x35\xb7\x33\x99\xb8\x80\x8a\xa9\x1d\x75\x0f\x77\x94\x3f\x8a\x8b\x7e\x89\xfd\xb5\x07\x28\xaa\x3d\xbb\xd8\xa4\x1a\x6e\x00\x75\x6f\x43\x8c\x9b\x9e\x9d\x55\x87\x2d\xf5\xa9\x06\x8a\xdd\x8a\x97\x2b\x7e\x43\xed\xad\x9c\xed\x22\x37\xca\x13\x67\xbe\x4b\x7c\xdb\x66\xa5\x4e\xa1\x2e\xef\x12\x94\x71\x15\x86\x10\xea\xf2\x8f\x99\xf7\xf6\x86\x55\x7d\xcd\xf6\x44\xea"}, -{{0x72,0x2a,0x2d,0xa5,0x0e,0x42,0xc1,0x1a,0x61,0xc9,0xaf,0xac,0x7b,0xe1,0xa2,0xfe,0xd2,0x26,0x7d,0x65,0x0f,0x8f,0x7d,0x8e,0x5b,0xc7,0x06,0xb8,0x07,0xc1,0xb9,0x1d,},{0xfd,0x0b,0x96,0x45,0x62,0xf8,0x23,0x72,0x1e,0x64,0x9c,0x3f,0xed,0xb4,0x32,0xa7,0x6f,0x91,0xe0,0xae,0xad,0x7c,0x61,0xd3,0x5f,0x95,0xed,0x77,0x26,0xd7,0x85,0x89,},{0xc2,0x69,0x5a,0x57,0x17,0x2a,0xaa,0x31,0xbd,0x08,0x90,0xf2,0x31,0xca,0x8e,0xee,0xc0,0x28,0x7a,0x87,0x17,0x26,0x69,0xa8,0x99,0xad,0x08,0x91,0xce,0xa4,0xc4,0x75,0x79,0xb5,0x04,0x20,0xe7,0x91,0xcd,0xec,0x8c,0x18,0x2c,0x8a,0x0e,0x8d,0xde,0x21,0xb2,0x48,0x0b,0x0c,0xfd,0x81,0x11,0xe2,0x8e,0x56,0x03,0x34,0x7a,0x35,0x2d,0x04,},"\x17\x3e\x8b\xb8\x85\xe1\xf9\x08\x14\x04\xac\xac\x99\x90\x41\xd2\xec\xfc\xb7\x3f\x94\x5e\x0d\xb3\x6e\x63\x1d\x7c\xd1\xab\x99\x9e\xb7\x17\xf3\x4b\xf0\x78\x74\xbf\x3d\x34\xe2\x53\x0e\xb6\x08\x5f\x4a\x9f\x88\xae\x1b\x0f\x7d\x80\xf2\x21\x45\x6a\x8e\x9a\x88\x90\xb9\x1a\x50\x19\x2d\xea\xaa\xcc\x0a\x1a\x61\x5a\x87\x84\x1e\x2c\x5a\x9e\x05\x79\x57\xaf\x6e\x48\xe7\x8c\xc8\x61\x98\xe3\x2e\x7a\xa2\x4d\xcf\x6c\xff\xa3\x29\xbc\x72\x60\x6d\x65\xb1\x16\x82\xc8\xba\x73\x6c\xce\x22\xa0\x57\x85\xdf\x11\x46\x33\x1e\x41\x60\x9c\xf9\xca\x71\x1c\xf4\x64\x95\x82\x97\x13\x8b\x58\xa9\x07\x3f\x3b\xbf\x06\xad\x8a\x85\xd1\x35\xde\x66\x65\x21\x04\xd8\x8b\x49\xd2\x7a\xd4\x1e\x59\xbc\xc4\x4c\x7f\xab\x68\xf5\x3f\x05\x02\xe2\x93\xff\xca\xba\xaf\x75\x59\x27\xdf\xdf\xfb\xfd\xe3\xb3\x5c\x08\x0b\x5d\xe4\xc8\xb7\x85\xf4\xda\x64\xef\x35\x7b\xc0\xd1\x46\x6a\x6a\x96\x56\x0c\x3c\x4f\x3e\x3c\x0b\x56\x3a\x00\x3f\x5f\x95\xf2\x37\x17\x1b\xce\x1a\x00\x17\x71\xa0\x4e\xde\x7c\xdd\x9b\x8c\xa7\x70\xfd\x36\xef\x90\xe9\xfe\x00\x00\xa8\xd7\x68\x5f\xd1\x53\xcc\x72\x82\xde\x95\x92\x0a\x8f\x8f\x08\x98\xd0\x0b\xf0\xc6\xc9\x33\xfe\x5b\xb9\x65\x3f\xf1\x46\xc4\xe2\xac\xd1\xa2\xe0\xc2\x3c\x12\x44\x84\x4d\xac\xf8\x65\x27\x16\x30\x2c\x20\x32\xf9\xc1\x14\x67\x9e\xd2\x6b\x3e\xe3\xab\x4a\x7b\x18\xbc\x4e\x30\x71\xf0\x97\x7d\xb5\x7c\xd0\xac\x68\xc0\x72\x7a\x09\xb4\xf1\x25\xfb\x64\xaf\x28\x50\xb2\x6c\x8a\x48\x42\x63\x33\x4e\x2d\xa9\x02\xd7\x44\x73\x70\x44\xe7\x9a\xb1\xcf\x5b\x2f\x93\xa0\x22\xb6\x3d\x40\xcd"}, -{{0x5f,0xe9,0xc3,0x96,0x0e,0xd5,0xbd,0x37,0x4c,0xc9,0x4d,0x42,0x35,0x7e,0x6a,0x24,0xdc,0x7e,0x30,0x60,0x78,0x8f,0x72,0x63,0x65,0xde,0xfa,0xcf,0x13,0xcd,0x12,0xda,},{0x0c,0xe7,0xb1,0x55,0xc8,0xb2,0x0e,0xbd,0xaa,0xcd,0xc2,0xaa,0x23,0x62,0x7e,0x34,0xb1,0xf9,0xac,0xe9,0x80,0x65,0x0a,0x25,0x30,0xc7,0x60,0x7d,0x04,0x81,0x4e,0xb4,},{0x37,0x9f,0x9c,0x54,0xc4,0x13,0xaf,0x0d,0x19,0x2e,0x9b,0xc7,0x36,0xb2,0x9d,0xa9,0xd5,0x21,0xe7,0xba,0x78,0x41,0xd3,0x09,0xf9,0xbc,0xc1,0xe7,0x42,0xec,0x43,0x08,0xfe,0x9f,0x7b,0xa5,0x1e,0x0b,0x22,0xae,0xd4,0x87,0xcb,0x4a,0xa3,0x91,0x3b,0x9b,0xeb,0xfb,0x3a,0xac,0xd3,0x8f,0x40,0x39,0xf9,0xbb,0xbe,0xbe,0x1a,0xd8,0x00,0x02,},"\xc9\x49\x0d\x83\xd9\xc3\xa9\x37\x0f\x06\xc9\x1a\xf0\x01\x68\x5a\x02\xfe\x49\xb5\xca\x66\x77\x33\xff\xf1\x89\xee\xe8\x53\xec\x16\x67\xa6\xc1\xb6\xc7\x87\xe9\x24\x48\x12\xd2\xd5\x32\x86\x6a\xb7\x4d\xfc\x87\x0d\x6f\x14\x03\x3b\x6b\xcd\x39\x85\x2a\x39\x00\xf8\xf0\x8c\xd9\x5a\x74\xcb\x8c\xbe\x02\xb8\xb8\xb5\x1e\x99\x3a\x06\xad\xfe\xbd\x7f\xc9\x85\x4a\xe5\xd2\x9f\x4d\xf9\x64\x28\x71\xd0\xc5\xe4\x70\xd9\x03\xcf\xbc\xbd\x5a\xdb\x32\x75\x62\x8f\x28\xa8\x0b\xf8\xc0\xf0\x37\x66\x87\xda\xe6\x73\xbf\x7a\x85\x47\xe8\x0d\x4a\x98\x55\xae\x25\x72\xfc\x2b\x20\x5d\xc8\xa1\x98\x01\x6d\xdc\x9b\x50\x99\x5f\x5b\x39\xf3\x68\xf5\x40\x50\x4a\x55\x18\x03\xd6\xdd\x5f\x87\x48\x28\xe5\x54\x1d\xed\x05\x28\x94\xd9\xe2\xdc\x5e\x6a\xa3\x51\x08\x7e\x79\x0c\x0d\xd5\xd9\xc4\xde\xcb\x21\x7e\x4d\xb8\x1c\x98\xa1\x84\xb2\x64\xe6\xda\xea\xc0\xf1\x1e\x07\x4c\xae\x2b\xfc\x89\x9f\x54\xb4\x19\xc6\x5d\xcc\x22\x66\x4a\x91\x5f\xbf\xff\xac\x35\xce\xe0\xf2\x86\xeb\x7b\x14\x49\x33\xdb\x93\x3e\x16\xc4\xbc\xb6\x50\xd5\x37\x72\x24\x89\xde\x23\x63\x73\xfd\x8d\x65\xfc\x86\x11\x8b\x6d\xef\x37\xca\x46\x08\xbc\x6c\xe9\x27\xb6\x54\x36\xff\xda\x7f\x02\xbf\xbf\x88\xb0\x45\xae\x7d\x2c\x2b\x45\xa0\xb3\x0c\x8f\x2a\x04\xdf\x95\x32\x21\x08\x8c\x55\x5f\xe9\xa5\xdf\x26\x09\x82\xa3\xd6\x4d\xf1\x94\xee\x95\x2f\xa9\xa9\x8c\x31\xb9\x64\x93\xdb\x61\x80\xd1\x3d\x67\xc3\x67\x16\xf9\x5f\x8c\x0b\xd7\xa0\x39\xad\x99\x06\x67\xca\x34\xa8\x3a\xc1\xa1\x8c\x37\xdd\x7c\x77\x36\xaa\x6b\x9b\x6f\xc2\xb1\xac\x0c\xe1\x19\xef\x77"}, -{{0xec,0x2f,0xa5,0x41,0xac,0x14,0xb4,0x14,0x14,0x9c,0x38,0x25,0xea,0xa7,0x00,0x1b,0x79,0x5a,0xa1,0x95,0x7d,0x40,0x40,0xdd,0xa9,0x25,0x73,0x90,0x4a,0xfa,0x7e,0xe4,},{0x71,0xb3,0x63,0xb2,0x40,0x84,0x04,0xd7,0xbe,0xec,0xde,0xf1,0xe1,0xf5,0x11,0xbb,0x60,0x84,0x65,0x8b,0x53,0x2f,0x7e,0xa6,0x3d,0x4e,0x3f,0x5f,0x01,0xc6,0x1d,0x31,},{0x84,0xd1,0x8d,0x56,0xf9,0x64,0xe3,0x77,0x67,0x59,0xbb,0xa9,0x2c,0x51,0x0c,0x2b,0x6d,0x57,0x45,0x55,0xc3,0xcd,0xda,0xde,0x21,0x2d,0xa9,0x03,0x74,0x55,0x49,0x91,0xe7,0xd7,0x7e,0x27,0x8d,0x63,0xe3,0x46,0x93,0xe1,0x95,0x80,0x78,0xcc,0x36,0x85,0xf8,0xc4,0x1c,0x1f,0x53,0x42,0xe3,0x51,0x89,0x96,0x38,0xef,0x61,0x21,0x14,0x01,},"\x27\x49\xfc\x7c\x4a\x72\x9e\x0e\x0a\xd7\x1b\x5b\x74\xeb\x9f\x9c\x53\x4e\xbd\x02\xff\xc9\xdf\x43\x74\xd8\x13\xbd\xd1\xae\x4e\xb8\x7f\x13\x50\xd5\xfd\xc5\x63\x93\x45\x15\x77\x17\x63\xe6\xc3\x3b\x50\xe6\x4e\x0c\xd1\x14\x57\x30\x31\xd2\x18\x6b\x6e\xca\x4f\xc8\x02\xcd\xdc\x7c\xc5\x1d\x92\xa6\x13\x45\xa1\x7f\x6a\xc3\x8c\xc7\x4d\x84\x70\x7a\x51\x56\xbe\x92\x02\xde\xe3\x44\x46\x52\xe7\x9b\xae\x7f\x0d\x31\xbd\x17\x56\x79\x61\xf6\x5d\xd0\x1a\x8e\x4b\xee\x38\x33\x19\x38\xce\x4b\x2b\x55\x06\x91\xb9\x9a\x4b\xc3\xc0\x72\xd1\x86\xdf\x4b\x33\x44\xa5\xc8\xfb\xfb\xb9\xfd\x2f\x35\x5f\x61\x07\xe4\x10\xc3\xd0\xc7\x98\xb6\x8d\x3f\xb9\xc6\xf7\xab\x5f\xe2\x7e\x70\x87\x1e\x86\x76\x76\x98\xfe\x35\xb7\x7e\xad\x4e\x43\x5a\x94\x02\xcc\x9e\xd6\xa2\x65\x7b\x05\x9b\xe0\xa2\x10\x03\xc0\x48\xbb\xf5\xe0\xeb\xd9\x3c\xbb\x2e\x71\xe9\x23\xcf\x5c\x72\x8d\x17\x58\xcd\x81\x7a\xd7\x4b\x45\x4a\x88\x71\x26\xd6\x53\xb9\x5a\x7f\x25\xe5\x29\x3b\x76\x8c\x9f\xc5\xa9\xc3\x5a\x23\x72\xe3\x74\x1b\xc9\x0f\xd6\x63\x01\x42\x7b\x10\x82\x4b\xb4\xb1\xe9\x11\x0b\xfb\xa8\x4c\x21\xa4\x0e\xb8\xfe\xd4\x49\x7e\x91\xdc\x3f\xfd\x04\x38\xc5\x14\xc0\xa8\xcb\x4c\xac\x6a\xd0\x25\x6b\xf1\x1d\x5a\xa7\xa9\xc7\xc0\x0b\x66\x9b\x01\x5b\x0b\xf8\x14\x25\xa2\x14\x13\xe2\xff\xb6\xed\xc0\xbd\x78\xe3\x85\xc4\x4f\xd7\x45\x58\xe5\x11\xc2\xc2\x5f\xee\x1f\xec\x18\xd3\x99\x0b\x86\x90\x30\x0f\xa7\x11\xe9\x3d\x98\x54\x66\x8f\x01\x87\x06\x5e\x76\xe7\x11\x3a\xe7\x63\xc3\x0d\xdd\x86\x72\x0b\x55\x46\xa6\xc3\xc6\xf1\xc4\x3b\xc6\x7b\x14"}, -{{0x61,0x32,0x69,0x2a,0x5e,0xf2,0x7b,0xf4,0x76,0xb1,0xe9,0x91,0xe6,0xc4,0x31,0xa8,0xc7,0x64,0xf1,0xae,0xbd,0x47,0x02,0x82,0xdb,0x33,0x21,0xbb,0x7c,0xb0,0x9c,0x20,},{0x7a,0x2d,0x16,0x61,0x84,0xf9,0xe5,0xf7,0x3b,0xea,0x45,0x44,0x86,0xb0,0x41,0xce,0xb5,0xfc,0x23,0x14,0xa7,0xbd,0x59,0xcb,0x71,0x8e,0x79,0xf0,0xec,0x98,0x9d,0x84,},{0xeb,0x67,0x7f,0x33,0x47,0xe1,0xa1,0xea,0x92,0x9e,0xfd,0xf6,0x2b,0xf9,0x10,0x5a,0x6c,0x8f,0x49,0x93,0x03,0x3b,0x4f,0x6d,0x03,0xcb,0x0d,0xbf,0x9c,0x74,0x2b,0x27,0x07,0x04,0xe3,0x83,0xab,0x7c,0x06,0x76,0xbd,0xb1,0xad,0x0c,0xe9,0xb1,0x66,0x73,0x08,0x3c,0x96,0x02,0xec,0x10,0xae,0x1d,0xd9,0x8e,0x87,0x48,0xb3,0x36,0x44,0x0b,},"\xa9\xc0\x86\x16\x65\xd8\xc2\xde\x06\xf9\x30\x1d\xa7\x0a\xfb\x27\xb3\x02\x4b\x74\x4c\x6b\x38\xb2\x42\x59\x29\x4c\x97\xb1\xd1\xcb\x4f\x0d\xcf\x75\x75\xa8\xed\x45\x4e\x2f\x09\x80\xf5\x03\x13\xa7\x73\x63\x41\x51\x83\xfe\x96\x77\xa9\xeb\x1e\x06\xcb\x6d\x34\xa4\x67\xcb\x7b\x07\x58\xd6\xf5\x5c\x56\x4b\x5b\xa1\x56\x03\xe2\x02\xb1\x88\x56\xd8\x9e\x72\xa2\x3a\xb0\x7d\x88\x53\xff\x77\xda\x7a\xff\x1c\xae\xbd\x79\x59\xf2\xc7\x10\xef\x31\xf5\x07\x8a\x9f\x2c\xda\xe9\x26\x41\xa1\xcc\x5f\x74\xd0\xc1\x43\xec\x42\xaf\xba\xa5\xf3\x78\xa9\xe1\x0d\x5b\xf7\x45\x87\xfa\x5f\x49\xc1\x56\x23\x32\x47\xda\xfd\x39\x29\xac\xde\x88\x8d\xc6\x84\x33\x7e\x40\xcd\xc5\x93\x2e\x7e\xb7\x3f\xfc\xc9\x0b\x85\xc0\xad\x46\x04\x16\x69\x1a\xef\xbd\x7e\xfd\x07\xb6\x57\xc3\x50\x94\x6a\x0e\x36\x6b\x37\xa6\xc8\x08\x9a\xba\x5c\x5f\xe3\xbb\xca\x06\x4a\xfb\xe9\xd4\x7f\xbc\x83\x91\x4a\xf1\xcb\x43\xc2\xb2\xef\xa9\x8e\x0a\x43\xbe\x32\xba\x82\x32\x02\x00\x1d\xef\x36\x81\x72\x51\xb6\x5f\x9b\x05\x06\xce\xf6\x68\x36\x42\xa4\x6e\xd6\x12\xf8\xca\x81\xee\x97\xbb\x04\xd3\x17\xb5\x17\x34\x3a\xde\x2b\x77\x12\x6d\x1f\x02\xa8\x7b\x76\x04\xc8\x65\x3b\x67\x48\xcf\x54\x88\xfa\x6d\x43\xdf\x80\x9f\xaa\x19\xe6\x92\x92\xd3\x8c\x5d\x39\x7d\xd8\xe2\x0c\x7a\xf7\xc5\x33\x4e\xc9\x77\xf5\x01\x0a\x0f\x7c\xb5\xb8\x94\x79\xca\x06\xdb\x4d\x12\x62\x7f\x06\x7d\x6c\x42\x18\x6a\x6b\x1f\x87\x42\xf3\x6a\xe7\x09\xba\x72\x0e\x3c\xd8\x98\x11\x66\x66\xd8\x1b\x19\x0b\x9b\x9d\x2a\x72\x20\x2c\xb6\x90\xa0\x3f\x33\x10\x42\x9a\x71\xdc\x04\x8c\xde"}, -{{0xf2,0x19,0xb2,0x10,0x11,0x64,0xaa,0x97,0x23,0xbd,0xe3,0xa7,0x34,0x6f,0x68,0xa3,0x50,0x61,0xc0,0x1f,0x97,0x82,0x07,0x25,0x80,0xba,0x32,0xdf,0x90,0x3b,0xa8,0x91,},{0xf6,0x6b,0x92,0x0d,0x5a,0xa1,0xa6,0x08,0x54,0x95,0xa1,0x48,0x05,0x39,0xbe,0xba,0x01,0xff,0xe6,0x0e,0x6a,0x63,0x88,0xd1,0xb2,0xe8,0xed,0xa2,0x33,0x55,0x81,0x0e,},{0x17,0xf0,0x12,0x7c,0xa3,0xba,0xfa,0x5f,0x4e,0xe9,0x59,0xcd,0x60,0xf7,0x72,0xbe,0x87,0xa0,0x03,0x49,0x61,0x51,0x7e,0x39,0xa0,0xa1,0xd0,0xf4,0xb9,0xe2,0x6d,0xb1,0x33,0x6e,0x60,0xc8,0x2b,0x35,0x2c,0x4c,0xba,0xcd,0xbb,0xd1,0x17,0x71,0xc3,0x77,0x4f,0x8c,0xc5,0xa1,0xa7,0x95,0xd6,0xe4,0xf4,0xeb,0xd5,0x1d,0xef,0x36,0x77,0x0b,},"\x01\x55\x77\xd3\xe4\xa0\xec\x1a\xb2\x59\x30\x10\x63\x43\xff\x35\xab\x4f\x1e\x0a\x8a\x2d\x84\x4a\xad\xbb\x70\xe5\xfc\x53\x48\xcc\xb6\x79\xc2\x29\x5c\x51\xd7\x02\xaa\xae\x7f\x62\x73\xce\x70\x29\x7b\x26\xcb\x7a\x25\x3a\x3d\xb9\x43\x32\xe8\x6a\x15\xb4\xa6\x44\x91\x23\x27\x91\xf7\xa8\xb0\x82\xee\x28\x34\xaf\x30\x40\x0e\x80\x46\x47\xa5\x32\xe9\xc4\x54\xd2\xa0\xa7\x32\x01\x30\xab\x6d\x4d\x86\x00\x73\xa3\x46\x67\xac\x25\xb7\xe5\xe2\x74\x7b\xa9\xf5\xc9\x45\x94\xfb\x68\x37\x7a\xe2\x60\x36\x9c\x40\x71\x3b\x4e\x32\xf2\x31\x95\xbf\x91\xd3\xd7\xf1\xa2\x71\x9b\xf4\x08\xaa\xd8\xd8\xa3\x47\xb1\x12\xe8\x4b\x11\x88\x17\xcb\x06\x51\x33\x44\x02\x17\x63\x03\x52\x72\xa7\xdb\x72\x8a\x0c\xcd\xaa\x94\x9c\x61\x71\x5d\x07\x64\x14\x0b\x3e\x8c\x01\xd2\x0f\xf1\x59\x3c\x7f\x2d\x55\xc4\xe8\x2a\x1c\x0c\xb1\xea\x58\x44\x2b\xf8\x0a\x74\x1b\xca\x91\xf5\x8a\xb0\x58\x1b\x49\x8e\xe9\xfe\x3c\x92\xca\x65\x41\x48\xef\x75\x31\x35\x43\xd1\xaf\xf3\x82\xbe\xfe\x1a\x93\xb0\x21\x90\xce\x01\x02\x17\x51\x58\xe2\x07\x1d\x02\xba\xca\xd8\xdb\xe9\xfb\x94\x0f\xcb\x61\x0c\x10\x5a\xd5\x2c\x80\xfe\xb1\xec\x4e\x52\x4f\x4c\x0e\xc7\x98\x3e\x9c\xe6\x96\xfa\x4f\xcf\x4b\xf0\x51\x4b\x8f\x04\x32\xb1\x7d\x54\x48\xfc\x42\x6f\xea\x2b\x01\xac\x7b\x26\xc2\xae\xd7\x69\x92\x75\x34\xda\x22\x57\x6f\xc1\xbb\xa7\x26\xe9\xd6\x5b\xe0\x1b\x59\xf6\x0a\x64\x8a\xce\x2f\xc3\xe5\xe2\x75\x78\x9f\xa6\x37\xcb\xbd\x84\xbe\x3d\x6a\xc2\x44\x57\xa6\x29\x2c\xd6\x56\xc7\xb5\x69\xa5\x2f\xfe\xa7\x91\x6b\x8d\x04\xb4\xf4\xa7\x5b\xe7\xac\x95\x14\x2f"}, -{{0xfc,0x18,0x00,0x35,0xae,0xc0,0xf5,0xed,0xe7,0xbd,0xa9,0x3b,0xf7,0x7a,0xde,0x7a,0x81,0xed,0x06,0xde,0x07,0xee,0x2e,0x3a,0xa8,0x57,0x6b,0xe8,0x16,0x08,0x61,0x0a,},{0x4f,0x21,0x5e,0x94,0x8c,0xae,0x24,0x3e,0xe3,0x14,0x3b,0x80,0x28,0x2a,0xd7,0x92,0xc7,0x80,0xd2,0xa6,0xb7,0x50,0x60,0xca,0x1d,0x29,0x0c,0xa1,0xa8,0xe3,0x15,0x1f,},{0xa4,0x3a,0x71,0xc3,0xa1,0x9c,0x35,0x66,0x0d,0xae,0x6f,0x31,0xa2,0x54,0xb8,0xc0,0xea,0x35,0x93,0xfc,0x8f,0xca,0x74,0xd1,0x36,0x40,0x01,0x2b,0x9e,0x94,0x73,0xd4,0xaf,0xe0,0x70,0xdb,0x01,0xe7,0xfb,0x39,0x9b,0xf4,0xca,0x60,0x70,0xe0,0x62,0x18,0x00,0x11,0x28,0x5a,0x67,0xdd,0x68,0x58,0xb7,0x61,0xe4,0x6c,0x6b,0xd3,0x20,0x04,},"\xb5\xe8\xb0\x16\x25\x66\x4b\x22\x23\x39\xe0\xf0\x5f\x93\xa9\x90\xba\x48\xb5\x6a\xe6\x54\x39\xa1\x75\x20\x93\x2d\xf0\x11\x72\x1e\x28\x4d\xbe\x36\xf9\x86\x31\xc0\x66\x51\x00\x98\xa6\x8d\x7b\x69\x2a\x38\x63\xe9\x9d\x58\xdb\x76\xca\x56\x67\xc8\x04\x3c\xb1\x0b\xd7\xab\xba\xf5\x06\x52\x9f\xbb\x23\xa5\x16\x6b\xe0\x38\xaf\xfd\xb9\xa2\x34\xc4\xf4\xfc\xf4\x3b\xdd\xd6\xb8\xd2\xce\x77\x2d\xd6\x53\xed\x11\x5c\x09\x5e\x23\x2b\x26\x9d\xd4\x88\x8d\x23\x68\xcb\x1c\x66\xbe\x29\xdd\x38\x3f\xca\x67\xf6\x67\x65\xb2\x96\x56\x4e\x37\x55\x5f\x0c\x0e\x48\x45\x04\xc5\x91\xf0\x06\xea\x85\x33\xa1\x25\x83\xad\x2e\x48\x31\x8f\xf6\xf3\x24\xec\xaf\x80\x4b\x1b\xae\x04\xaa\x89\x67\x43\xe6\x7e\xf6\x1c\xa3\x83\xd5\x8e\x42\xac\xfc\x64\x10\xde\x30\x77\x6e\x3b\xa2\x62\x37\x3b\x9e\x14\x41\x94\x39\x55\x10\x1a\x4e\x76\x82\x31\xad\x9c\x65\x29\xef\xf6\x11\x8d\xde\x5d\xf0\x2f\x94\xb8\xd6\xdf\x2d\x99\xf2\x78\x63\xb5\x17\x24\x3a\x57\x9e\x7a\xaf\xf3\x11\xea\x3a\x02\x82\xe4\x7c\xa8\x76\xfa\xbc\x22\x80\xfc\xe7\xad\xc9\x84\xdd\x0b\x30\x88\x5b\x16\x50\xf1\x47\x1d\xfc\xb0\x52\x2d\x49\xfe\xc7\xd0\x42\xf3\x2a\x93\xbc\x36\x8f\x07\x60\x06\xea\x01\xec\x1c\x74\x12\xbf\x66\xf6\x2d\xc8\x8d\xe2\xc0\xb7\x47\x01\xa5\x61\x4e\x85\x5e\x9f\xa7\x28\xfb\x1f\x11\x71\x38\x5f\x96\xaf\xbd\xe7\x0d\xea\x02\xe9\xaa\x94\xdc\x21\x84\x8c\x26\x30\x2b\x50\xae\x91\xf9\x69\x3a\x18\x64\xe4\xe0\x95\xae\x03\xcd\xc2\x2a\xd2\x8a\x0e\xb7\xdb\x59\x67\x79\x24\x67\x12\xfa\xb5\xf5\xda\x32\x7e\xfe\xc3\xe7\x96\x12\xde\x0a\x6c\xca\xa5\x36\x75\x9b\x8e"}, -{{0xa2,0x83,0x6a,0x65,0x42,0x79,0x12,0x12,0x2d,0x25,0xdc,0xdf,0xc9,0x9d,0x70,0x46,0xfe,0x9b,0x53,0xd5,0xc1,0xbb,0x23,0x61,0x7f,0x11,0x89,0x0e,0x94,0xca,0x93,0xed,},{0x8c,0x12,0xbd,0xa2,0x14,0xc8,0xab,0xb2,0x28,0x6a,0xcf,0xfb,0xf8,0x11,0x24,0x25,0x04,0x0a,0xab,0x9f,0x4d,0x8b,0xb7,0x87,0x0b,0x98,0xda,0x01,0x59,0xe8,0x82,0xf1,},{0xe6,0xa9,0xa6,0xb4,0x36,0x55,0x9a,0x43,0x20,0xc4,0x5c,0x0c,0x2c,0x4a,0x2a,0xed,0xec,0xb9,0x0d,0x41,0x6d,0x52,0xc8,0x26,0x80,0xac,0x73,0x30,0xd0,0x62,0xae,0xbe,0xf3,0xe9,0xac,0x9f,0x2c,0x5f,0xfa,0x45,0x5c,0x9b,0xe1,0x13,0x01,0x3a,0x2b,0x28,0x2e,0x56,0x00,0xfd,0x30,0x64,0x35,0xad,0xa8,0x3b,0x1e,0x48,0xba,0x2a,0x36,0x05,},"\x81\x3d\x60\x61\xc5\x6e\xae\x0f\xf5\x30\x41\xc0\x24\x4a\xa5\xe2\x9e\x13\xec\x0f\x3f\xb4\x28\xd4\xbe\xb8\xa9\x9e\x04\xbc\xa8\xc4\x1b\xdd\xb0\xdb\x94\x5f\x48\x7e\xfe\x38\xf2\xfc\x14\xa6\x28\xfa\xfa\x24\x62\xf8\x60\xe4\xe3\x42\x50\xeb\x4e\x93\xf1\x39\xab\x1b\x74\xa2\x61\x45\x19\xe4\x1e\xe2\x40\x3b\xe4\x27\x93\x0a\xb8\xbc\x82\xec\x89\xce\xaf\xb6\x09\x05\xbd\x4d\xdb\xbd\x13\xbd\xb1\x96\x54\x31\x4f\xc9\x23\x73\x14\x0b\x96\x2e\x22\x58\xe0\x38\xd7\x1b\x9e\xc6\x6b\x84\xef\x83\x19\xe0\x35\x51\xcb\x70\x7e\x74\x7f\x6c\x40\xad\x47\x6f\xbe\xfd\xce\x71\xf3\xa7\xb6\x7a\x1a\xf1\x86\x9b\xc6\x44\x06\x86\xe7\xe0\x85\x5e\x4f\x36\x9d\x1d\x88\xb8\x09\x9f\xba\x54\x71\x46\x78\x62\x7b\xba\x1a\xff\x41\xe7\x70\x7b\xc9\x7e\xdd\xf8\x90\xb0\xc0\x8d\xce\x3e\x98\x00\xd2\x4c\x6f\x61\x09\x2c\xe2\x8d\x48\x1b\x5d\xea\x5c\x09\x6c\x55\xd7\x2f\x89\x46\x00\x91\x31\xfb\x96\x8e\x2b\xc8\xa0\x54\xd8\x25\xad\xab\x76\x74\x0d\xcf\x0d\x75\x8c\x8b\xf5\x4f\xf3\x86\x59\xe7\x1b\x32\xbf\xe2\xe6\x15\xaa\xab\xb0\xf5\x29\x30\x85\x64\x9c\xf6\x0b\x98\x47\xbc\x62\x01\x1c\xe3\x87\x8a\xf6\x28\x98\x4a\x58\x40\xa4\xad\x5d\xae\x37\x02\xdb\x36\x7d\xa0\xf8\xa1\x65\xfe\xd0\x51\x7e\xb5\xc4\x42\xb0\x14\x53\x30\x24\x1b\x97\xee\xca\x73\x3b\xa6\x68\x8b\x9c\x12\x9a\x61\xcd\x12\x36\xaf\xf0\xe2\x7b\xcf\x98\xc2\x8b\x0f\xbe\xea\x55\xa3\xd7\xc7\x19\x3d\x64\x4b\x27\x49\xf9\x86\xbd\x46\xaf\x89\x38\xe8\xfa\xae\xaf\xbd\x9c\xec\x36\x12\xab\x00\x5b\xd7\xc3\xee\xaf\xe9\xa3\x12\x79\xca\x61\x02\x56\x06\x66\xba\x16\x13\x6f\xf1\x45\x2f\x85\x0a\xdb"}, -{{0xf0,0x51,0xaf,0x42,0x6d,0x0c,0x32,0x82,0xfa,0xfc,0x8b,0xf9,0x12,0xad,0xe1,0xc2,0x42,0x11,0xa9,0x5a,0xd2,0x00,0xe1,0xee,0xf5,0x49,0x32,0x0e,0x1c,0xb1,0xa2,0x52,},{0xfa,0x87,0x95,0x5e,0x0e,0xa1,0x3d,0xde,0x49,0xd8,0x3d,0xc2,0x2e,0x63,0xa2,0xbd,0xf1,0x07,0x67,0x25,0xc2,0xcc,0x7f,0x93,0xc7,0x65,0x11,0xf2,0x8e,0x79,0x44,0xf2,},{0xb8,0xf7,0x13,0x57,0x8a,0x64,0x46,0x67,0x19,0xac,0xeb,0x43,0x2f,0xce,0x30,0x2a,0x87,0xcf,0x06,0x6b,0xf3,0xe1,0x02,0xa3,0x50,0x61,0x69,0x21,0xa8,0x40,0x96,0x4b,0xfc,0x7e,0x68,0x5d,0x8f,0xd1,0x74,0x55,0xac,0x3e,0xb4,0x86,0x1e,0xdc,0xb8,0x97,0x9d,0x35,0xe3,0xa4,0xbd,0x82,0xa0,0x78,0xcd,0x70,0x77,0x21,0xd7,0x33,0x40,0x0e,},"\xb4\x8d\x9f\x84\x76\x2b\x3b\xcc\x66\xe9\x6d\x76\xa6\x16\xfa\x8f\xe8\xe0\x16\x95\x25\x1f\x47\xcf\xc1\xb7\xb1\x7d\x60\xdc\x9f\x90\xd5\x76\xef\x64\xee\x7d\x38\x85\x04\xe2\xc9\x07\x96\x38\x16\x5a\x88\x96\x96\x47\x1c\x98\x9a\x87\x6f\x8f\x13\xb6\x3b\x58\xd5\x31\xfe\xa4\xdd\x12\x29\xfc\x63\x16\x68\xa0\x47\xbf\xae\x2d\xa2\x81\xfe\xae\x1b\x6d\xe3\xeb\xe2\x80\xab\xe0\xa8\x2e\xe0\x0f\xbf\xdc\x22\xce\x2d\x10\xe0\x6a\x04\x92\xff\x14\x04\xdf\xc0\x94\xc4\x0b\x20\x3b\xf5\x57\x21\xdd\x78\x7e\xd4\xe9\x1d\x55\x17\xaa\xf5\x8d\x3b\xdd\x35\xd4\x4a\x65\xae\x6b\xa7\x56\x19\xb3\x39\xb6\x50\x51\x8c\xef\xcc\x17\x49\x3d\xe2\x7a\x3b\x5d\x41\x78\x8f\x87\xed\xbd\xe7\x26\x10\xf1\x81\xbf\x06\xe2\x08\xe0\xeb\x7c\xdf\xe8\x81\xd9\x1a\x2d\x6c\xc7\x7a\xa1\x9c\x0f\xcf\x33\x0f\xed\xb4\x46\x75\xd8\x00\xeb\x8c\xff\x95\x05\xd8\x88\x75\x44\xa5\x03\xcb\xe3\x73\xc4\x84\x7b\x19\xe8\xf3\x99\x57\x26\xef\xd6\x64\x98\x58\x59\x5c\x57\xcc\xaf\x0c\xbc\x9e\xb2\x5d\xe8\x3b\xa0\x46\xbc\x9f\x18\x38\xac\x7b\x89\x53\xdd\x81\xb8\x1a\xc0\xf6\x8d\x0e\x93\x38\xcb\x55\x40\x25\x52\xaf\xb6\xbc\x16\x94\x93\x51\xb9\x26\xd1\x51\xa8\x2e\xfc\x69\x5e\x8d\x7d\xa0\xdd\x55\x09\x93\x66\x78\x97\x18\xcc\xbf\x36\x03\x0b\xd2\xc3\xc1\x09\x39\x9b\xe2\x6c\xdb\x8b\x9e\x2a\x15\x5f\x3b\x2c\xb1\xbf\xa7\x1a\xb6\x9a\x23\x62\x5a\x4a\xc1\x18\xfe\x91\xcb\x2c\x19\x78\x8c\xf5\x2a\x71\xd7\x30\xd5\x76\xb4\x21\xd9\x69\x82\xa5\x1a\x29\x91\xda\xec\x44\x0c\xda\x7e\x6c\xc3\x28\x2b\x83\x12\x71\x42\x78\xb8\x19\xbf\xe2\x38\x7e\xb9\x6a\xa9\x1d\x40\x17\x30\x34\xf4\x28"}, -{{0xa1,0x03,0xe9,0x26,0x72,0xc6,0x5f,0x81,0xea,0x5d,0xa1,0xff,0xf1,0xa4,0x03,0x87,0x88,0x47,0x9e,0x94,0x1d,0x50,0x3a,0x75,0x6f,0x4a,0x75,0x52,0x01,0xa5,0x7c,0x1d,},{0xee,0x63,0xa5,0xb6,0x96,0x41,0x21,0x7a,0xcb,0xaf,0x33,0x39,0xda,0x82,0x9e,0xc0,0x71,0xb9,0x93,0x1e,0x59,0x87,0x15,0x35,0x14,0xd3,0x01,0x40,0x83,0x7a,0x7a,0xf4,},{0x2a,0xa2,0x03,0x5c,0x2c,0xe5,0xb5,0xe6,0xae,0x16,0x1e,0x16,0x8f,0x3a,0xd0,0xd6,0x59,0x2b,0xcf,0x2c,0x4a,0x04,0x9d,0x3e,0xd3,0x42,0xfc,0xeb,0x56,0xbe,0x9c,0x7c,0xb3,0x72,0x02,0x75,0x73,0xae,0x01,0x78,0xe8,0x87,0x8e,0xbe,0xfc,0xa7,0xb0,0x30,0x32,0x7b,0x8a,0xad,0x41,0x85,0x7d,0xe5,0x8c,0xb7,0x8e,0x1a,0x00,0xcb,0xac,0x05,},"\xb1\x98\x4e\x9e\xec\x08\x5d\x52\x4c\x1e\xb3\xb9\x5c\x89\xc8\x4a\xe0\x85\xbe\x5d\xc6\x5c\x32\x6e\x19\x02\x5e\x12\x10\xa1\xd5\x0e\xdb\xbb\xa5\xd1\x37\x0c\xf1\x5d\x68\xd6\x87\xeb\x11\x32\x33\xe0\xfb\xa5\x0f\x94\x33\xc7\xd3\x58\x77\x39\x50\xc6\x79\x31\xdb\x82\x96\xbb\xcb\xec\xec\x88\x8e\x87\xe7\x1a\x2f\x75\x79\xfa\xd2\xfa\x16\x2b\x85\xfb\x97\x47\x3c\x45\x6b\x9a\x5c\xe2\x95\x66\x76\x96\x9c\x7b\xf4\xc4\x56\x79\x08\x5b\x62\xf2\xc2\x24\xfc\x7f\x45\x87\x94\x27\x3f\x6d\x12\xc5\xf3\xe0\xd0\x69\x51\x82\x4d\x1c\xca\x3e\x2f\x90\x45\x59\xed\x28\xe2\x86\x8b\x36\x6d\x79\xd9\x4d\xc9\x86\x67\xb9\xb5\x92\x42\x68\xf3\xe3\x9b\x12\x91\xe5\xab\xe4\xa7\x58\xf7\x70\x19\xda\xcb\xb2\x2b\xd8\x19\x6e\x0a\x83\xa5\x67\x76\x58\x83\x6e\x96\xca\x56\x35\x05\x5a\x1e\x63\xd6\x5d\x03\x6a\x68\xd8\x7a\xc2\xfd\x28\x3f\xdd\xa3\x90\x31\x99\x09\xc5\xcc\x76\x80\x36\x88\x48\x87\x3d\x59\x7f\x29\x8e\x0c\x61\x72\x30\x80\x30\xff\xd4\x52\xbb\x13\x63\x61\x7b\x31\x6e\xd7\xcd\x94\x9a\x16\x5d\xc8\xab\xb5\x3f\x99\x1a\xef\x3f\x3e\x95\x02\xc5\xdf\xe4\x75\x6b\x7c\x6b\xfd\xfe\x89\xf5\xe0\x0f\xeb\xdd\x6a\xfb\x04\x02\x81\x8f\x11\xcf\x8d\x1d\x58\x64\xfe\x9d\xa1\xb8\x6e\x39\xaa\x93\x58\x31\x50\x6c\xf2\x40\x0e\xa7\xed\x75\xbd\x95\x33\xb2\x3e\x20\x2f\xe8\x75\xd7\xd9\x63\x8c\x89\xd1\x1c\xb2\xd6\xe6\x02\x1a\xe6\xbd\x27\xc7\x75\x48\x10\xd3\x5c\xd3\xa6\x14\x94\xf2\x7b\x16\xfc\x79\x4e\x2c\xd2\xf0\xd3\x45\x3a\xda\x93\x38\x65\xdb\x78\xc5\x79\x57\x1f\x8f\xc5\xc5\xc6\xbe\x8e\xaf\xfc\xe6\xa8\x52\xe5\xb3\xb1\xc5\x24\xc4\x93\x13\xd4\x27\xab\xcb"}, -{{0xd4,0x7c,0x1b,0x4b,0x9e,0x50,0xcb,0xb7,0x1f,0xd0,0x7d,0x09,0x6d,0x91,0xd8,0x72,0x13,0xd4,0x4b,0x02,0x43,0x73,0x04,0x47,0x61,0xc4,0x82,0x2f,0x9d,0x9d,0xf8,0x80,},{0xf4,0xe1,0xcb,0x86,0xc8,0xca,0x2c,0xfe,0xe4,0x3e,0x58,0x59,0x4a,0x87,0x78,0x43,0x6d,0x3e,0xa5,0x19,0x70,0x4e,0x00,0xc1,0xbb,0xe4,0x8b,0xbb,0x1c,0x94,0x54,0xf8,},{0x62,0x7e,0x7c,0xa7,0xe3,0x4e,0xd6,0x33,0x1d,0x62,0xb9,0x54,0x1c,0x1e,0xa9,0xa9,0x29,0x2b,0xe7,0xb0,0xa6,0x5d,0x80,0x5e,0x26,0x6b,0x51,0x22,0x27,0x2a,0x82,0xdb,0x7d,0x76,0x5a,0xcc,0x7e,0x2a,0x29,0x0d,0x68,0x58,0x04,0x92,0x2f,0x91,0xed,0x04,0xa3,0xc3,0x82,0xc0,0x3f,0xf2,0x1a,0x17,0x68,0xf5,0x84,0x41,0x3c,0x4e,0x5f,0x00,},"\x88\xd7\x00\x9d\x51\xde\x3d\x33\x7e\xef\x0f\x21\x5e\xa6\x6a\xb8\x30\xec\x5a\x9e\x68\x23\x76\x1c\x3b\x92\xad\x93\xea\x34\x1d\xb9\x2e\xce\x67\xf4\xef\x4c\xeb\x84\x19\x4a\xe6\x92\x6c\x3d\x01\x4b\x2d\x59\x78\x1f\x02\xe0\xb3\x2f\x9a\x61\x12\x22\xcb\x9a\x58\x50\xc6\x95\x7c\xb8\x07\x9a\xe6\x4e\x08\x32\xa1\xf0\x5e\x5d\x1a\x3c\x57\x2f\x9d\x08\xf1\x43\x7f\x76\xbb\x3b\x83\xb5\x29\x67\xc3\xd4\x8c\x35\x76\x84\x88\x91\xc9\x65\x8d\x49\x59\xeb\x80\x65\x6d\x26\xcd\xba\x08\x10\x03\x7c\x8a\x18\x31\x8f\xf1\x22\xf8\xaa\x89\x85\xc7\x73\xcb\x31\x7e\xfa\x2f\x55\x7f\x1c\x38\x96\xbc\xb1\x62\xdf\x5d\x87\x68\x1b\xb7\x87\xe7\x81\x3a\xa2\xde\xa3\xb0\xc5\x64\xd6\x46\xa9\x28\x61\xf4\x44\xca\x14\x07\xef\xba\xc3\xd1\x24\x32\xcb\xb7\x0a\x1d\x0e\xaf\xfb\x11\x74\x1d\x37\x18\xfe\xde\xe2\xb8\x30\x36\x18\x9a\x6f\xc4\x5a\x52\xf7\x4f\xa4\x87\xc1\x8f\xd2\x64\xa7\x94\x5f\x6c\x9e\x44\xb0\x11\xf5\xd8\x66\x13\xf1\x93\x9b\x19\xf4\xf4\xfd\xf5\x32\x34\x05\x7b\xe3\xf0\x05\xad\x64\xee\xbf\x3c\x8f\xfb\x58\xcb\x40\x95\x6c\x43\x36\xdf\x01\xd4\x42\x4b\x70\x6a\x0e\x56\x1d\x60\x17\x08\xd1\x24\x85\xe2\x1b\xcb\x6d\x79\x9d\x8d\x1d\x04\x4b\x40\x00\x64\xec\x09\x44\x50\x14\x06\xe7\x02\x53\x94\x70\x06\xca\xbb\xdb\x2d\xd6\xbd\x8c\xee\x44\x97\x65\x3d\x91\x13\xa4\x4d\x4d\xe9\xb6\x8d\x4c\x52\x6f\xca\x0b\x9b\x0c\x18\xfe\x50\xfb\x91\x7f\xdd\x9a\x91\x4f\xb8\x16\x10\x8a\x73\xa6\xb3\xff\xf9\xe6\x54\xe6\x9c\x9c\xfe\x02\xb0\x5c\x6c\x1b\x9d\x15\xc4\xe6\x5c\xf3\x10\x18\xb8\x10\x0d\x78\x46\x33\xee\x18\x88\xee\xe3\x57\x2a\xaf\xa6\xf1\x89\xea\x22\xd0"}, -{{0xfc,0x0c,0x32,0xc5,0xeb,0x6c,0x71,0xea,0x08,0xdc,0x2b,0x30,0x0c,0xbc,0xef,0x18,0xfd,0xde,0x3e,0xa2,0x0f,0x68,0xf2,0x17,0x33,0x23,0x7b,0x4d,0xda,0xab,0x90,0x0e,},{0x47,0xc3,0x7d,0x8a,0x08,0x08,0x57,0xeb,0x87,0x77,0xa6,0xc0,0xa9,0xa5,0xc9,0x27,0x30,0x3f,0xaf,0x5c,0x32,0x09,0x53,0xb5,0xde,0x48,0xe4,0x62,0xe1,0x2d,0x00,0x62,},{0x68,0x87,0xc6,0xe2,0xb9,0x8a,0x82,0xaf,0x5e,0xe3,0xdf,0xa7,0xca,0x2c,0xb2,0x5d,0x9c,0x10,0x74,0x56,0x20,0xa8,0x29,0x56,0xac,0xba,0x85,0xcb,0x57,0xc8,0xec,0x24,0x27,0x9f,0xa4,0x2f,0x09,0x23,0x59,0xa1,0xb6,0xbb,0xea,0xfb,0xa0,0x50,0xf1,0x4b,0x62,0x88,0x20,0x9e,0x6e,0xf7,0xbc,0x1e,0x0a,0x2b,0x87,0x2c,0x11,0x38,0xf3,0x05,},"\xa7\xb1\xe2\xdb\x6b\xdd\x96\xb3\xd5\x14\x75\x60\x35\x37\xa7\x6b\x42\xb0\x4d\x7e\xbd\x24\xfe\x51\x5a\x88\x76\x58\xe4\xa3\x52\xe2\x21\x09\x33\x56\x39\xa5\x9e\x25\x34\x81\x1f\x47\x53\xb7\x02\x09\xd0\xe4\x69\x8e\x9d\x92\x60\x88\x82\x6c\x14\x68\x96\x81\xea\x00\xfa\x3a\x2f\xca\xa0\x04\x7c\xed\x3e\xf2\x87\xe6\x17\x25\x02\xb2\x15\xe5\x64\x97\x61\x4d\x86\xb4\xcb\x26\xbc\xd7\x7a\x2e\x17\x25\x09\x36\x0e\xe5\x88\x93\xd0\x1c\x0d\x0f\xb4\xd4\xab\xfe\x4d\xbd\x8d\x2a\x2f\x54\x19\x0f\xa2\xf7\x31\xc1\xce\xac\x68\x29\xc3\xdd\xc9\xbf\xb2\xff\xd7\x0c\x57\xba\x0c\x2b\x22\xd2\x32\x6f\xbf\xe7\x39\x0d\xb8\x80\x9f\x73\x54\x7f\xf4\x7b\x86\xc3\x6f\x2b\xf7\x45\x4e\x67\x8c\x4f\x1c\x0f\xa8\x70\xbd\x0e\x30\xbb\xf3\x27\x8e\xc8\xd0\xc5\xe9\xb6\x4a\xff\x0a\xf6\x4b\xab\xc1\x9b\x70\xf4\xcf\x9a\x41\xcb\x8f\x95\xd3\xcd\xe2\x4f\x45\x6b\xa3\x57\x1c\x8f\x02\x1d\x38\xe5\x91\xde\xc0\x5c\xb5\xd1\xca\x7b\x48\xf9\xda\x4b\xd7\x34\xb0\x69\xa9\xfd\x10\x65\x00\xc1\xf4\x08\xab\x7f\xe8\xe4\xa6\xe6\xf3\xed\x64\xda\x0e\xd2\x4b\x01\xe3\x3d\xf8\x47\x5f\x95\xfa\x9e\xd7\x1d\x04\xdd\x30\xb3\xcd\x82\x37\x55\xa3\x40\x1b\xf5\xaf\xae\x10\xee\x7e\x18\xec\x6f\xe6\x37\xc3\x79\x3f\xd4\x34\xb4\x8d\x71\x45\x13\x04\x47\xe0\x02\x99\x10\x10\x52\x55\x8b\x50\x65\x54\xec\x9c\x39\x9f\x62\x94\x1c\x3f\x41\x4c\xbc\x35\x2c\xaa\x34\x5b\x93\x0a\xde\xcf\xad\xda\xc9\x1e\xe5\x3d\x14\x51\xa6\x5e\x06\x20\x10\x26\x32\x5d\xe0\x7c\x93\x1f\x69\xbb\xa8\x68\xa7\xc8\x7e\xe2\x3c\x60\x4e\xc6\x79\x43\x32\x91\x7d\xfe\x2c\x5b\x69\x66\x9b\x65\x97\x06\x91\x7f\x71\xed\xdf\x96"}, -{{0xa8,0xd7,0x3d,0x63,0x9a,0x23,0xcc,0x6a,0x96,0x7e,0xf3,0x1b,0xca,0xbb,0x5d,0x06,0x3e,0x53,0xe1,0xea,0xb8,0xfc,0xc7,0xca,0xb9,0xbc,0x3a,0x17,0xfd,0xe9,0xc2,0xf8,},{0x8d,0xaa,0x9f,0x4c,0x8b,0x1a,0x44,0x69,0x1b,0xf4,0x45,0x21,0xf2,0xf7,0xca,0x45,0xdc,0x7f,0xc6,0x1f,0x6a,0x4c,0xe6,0xf9,0x8f,0xaa,0x41,0xc2,0xa7,0x49,0x77,0xd1,},{0xc4,0xdc,0xef,0x1a,0x24,0x53,0x93,0x9b,0x36,0x4b,0x34,0x02,0x50,0xc3,0x12,0x94,0x31,0x43,0x1d,0x5b,0xa3,0xf4,0x76,0x70,0xab,0x07,0xce,0x68,0x0c,0x69,0xbf,0x28,0xb6,0x78,0x62,0x7c,0x76,0xa6,0x36,0x0f,0xc4,0x0d,0xc1,0x09,0xaa,0x7d,0xea,0x37,0x1b,0x82,0x5e,0x46,0x13,0x4f,0x62,0x45,0x72,0x18,0x2a,0xcf,0x39,0x57,0xe7,0x0f,},"\xfd\x1f\xac\x3d\x53\x31\x3b\x11\xac\xd2\x9f\x5a\x83\xac\x11\x89\x6d\xab\x25\x30\xfa\x47\x86\x5b\x22\x95\xc0\xd9\x9d\xd6\x7c\x36\xed\x8e\x5f\xa5\x49\x15\x0c\x79\x4c\x55\x49\xef\xb5\xc1\xd6\x91\x14\xd5\xd6\x07\xb2\x32\x85\xb7\x21\x2a\xfa\xab\x57\x84\x6a\x54\xae\x67\xb9\xe8\x80\xe0\x7b\x65\x86\x60\x7c\xec\xf6\xd4\xee\xd5\x16\xa3\xa7\x55\x11\xfe\x36\x7d\x88\xeb\x87\x1e\x6d\x71\xb7\xd6\xaa\x13\x67\xa0\x14\x21\xb1\x08\x8f\xc2\xd7\x5e\x44\x95\x4b\x73\x62\x5c\x52\xda\x8a\x3a\x18\x3c\x60\xbe\x9d\xa6\x05\x0f\x59\xa4\x53\xca\xa5\x35\x20\x59\x36\x71\x72\x8d\x43\x18\x77\xbf\xaa\xc9\x13\xa7\x65\xfb\x6a\x56\xb7\x52\x90\xb2\xa8\xaa\xac\x34\xaf\xb9\x21\x7b\xa1\xb0\xd5\x85\x0b\xa0\xfd\xab\xf8\x09\x69\xde\xf0\xfe\xee\x79\x4c\xeb\x60\x61\x4e\x33\x68\xe6\x3e\xf2\x0e\x4c\x32\xd3\x41\xec\x9b\x03\x28\xea\x9f\xe1\x39\x20\x7e\xd7\xa6\x26\xff\x08\x94\x3b\x41\x52\x33\xdb\x7c\xfc\xc8\x45\xc9\xb6\x31\x21\xd4\xed\x52\xec\x37\x48\xab\x6a\x1f\x36\xb2\x10\x3c\x7d\xc7\xe9\x30\x3a\xce\xa4\xba\x8a\xf7\xa3\xe0\x71\x84\xfb\x49\x1e\x89\x1e\xde\x84\xf0\xdc\x41\xca\xdc\x39\x73\x02\x8e\x87\x9a\xcd\x20\x31\xaf\xc2\x9a\x16\x09\x28\x68\xe2\xc7\xf5\x39\xfc\x1b\x79\x2e\xda\xb1\x95\xa2\x5a\xb9\x83\x06\x61\x34\x6b\x39\xef\x53\x91\x5d\xe4\xaf\x52\xc4\x21\xea\xf1\x72\xe9\xda\x76\xa0\x8c\x28\x3a\x52\xdf\x90\x7f\x70\x5d\x7e\x85\x99\xc5\xba\xae\x0c\x2a\xf3\x80\xc1\xbb\x46\xf9\x34\x84\xa0\x3f\x28\x37\x43\x24\xb2\x78\x99\x2b\x50\xb7\xaf\xa0\x25\x52\xca\xfa\x50\x3f\x03\x4f\x8d\x86\x6e\x9b\x72\x02\x71\xdd\x68\xcc\xb6\x85\xa8\x5f\xff\xd1"}, -{{0x79,0xc7,0xdc,0xb7,0xd5,0x9a,0x8d,0xf6,0xb2,0xb2,0xba,0x04,0x13,0x05,0x9d,0x89,0x68,0x09,0x95,0xc2,0x0e,0x91,0x6d,0xa0,0x1b,0x8f,0x06,0x7d,0xc6,0x0c,0xde,0xb4,},{0x29,0x87,0x43,0xc7,0x39,0x18,0xbd,0x55,0x6b,0x28,0xf8,0xd4,0x82,0x4a,0x09,0xb8,0x14,0x75,0x2a,0x7a,0xea,0xe7,0xee,0x04,0x87,0x5c,0x53,0xf4,0xd6,0xb1,0x08,0xd9,},{0x7b,0x7c,0xbe,0x44,0xc7,0x71,0xe4,0x37,0x1b,0xae,0x13,0xb0,0x72,0x2b,0xab,0xcc,0x10,0x64,0x15,0x57,0x32,0x96,0x2f,0x40,0x7c,0xba,0x2a,0xcd,0x35,0x38,0x1d,0x42,0x21,0x0b,0xec,0xe8,0x22,0xf4,0x68,0x11,0x21,0xfd,0x4d,0xab,0x74,0x5a,0x1f,0x30,0x77,0x92,0x2f,0xba,0x1a,0x78,0x04,0x5b,0x71,0x29,0x02,0xba,0xcc,0xac,0x66,0x0e,},"\x5f\xe2\x02\xf5\xb3\x3b\x77\x88\x81\x0d\x25\x08\xa1\x3b\x31\x14\xd6\x9b\x85\x96\xe6\xea\xcd\xa0\x5a\x04\xa2\xeb\x59\x7f\xa3\x27\x9c\x20\x8b\x5a\x5b\x65\xda\xac\xb6\x99\xf1\x44\xe1\xd6\x60\xe7\x8e\x13\x9b\x57\x83\x31\xab\xec\x5c\x3c\x35\x33\x44\x54\xf0\x3e\x83\x2c\x8d\x6e\x29\x84\xdf\x5d\x45\x0e\xcb\x5d\x33\x58\x2a\x78\x80\x8a\x9c\x78\xf2\x6e\xbc\xd1\x24\x4e\xf5\x2e\x3f\xa6\xdc\xa1\x15\xc1\xf0\xcb\x56\xe3\x8e\xae\x0e\x5b\x39\xf5\xfd\x86\x3d\xff\xd0\xb2\xfb\x5b\x95\x8f\x2d\x73\x9d\xb3\x12\xfc\x66\x7a\x17\xb0\x31\xc4\xc9\xf8\xc5\xa2\xad\x57\x79\x84\xcc\x41\x46\xc4\x37\x58\x0e\xfd\x21\x52\x17\x3f\xe0\xd5\x78\x2c\xc2\xae\x98\x31\xa8\xd9\xa0\x41\x77\x25\x60\x18\xff\x76\x31\xe0\xb0\xd8\xa9\x9c\xb2\x8f\x00\x8b\x32\x04\x21\xe2\x7a\x74\xc3\x13\x59\x18\x86\x63\x45\x6d\x85\xe0\x98\xc1\xeb\xd2\x81\x70\x10\x97\xb6\xae\x5a\x87\x1e\x5c\xcc\x02\x05\x8a\x50\x14\x16\xcb\x91\xc1\x2c\xef\x5b\xe6\xf1\x91\x43\x70\xe5\x63\xf1\xa1\xb2\xaa\x41\xf4\xb8\xee\x84\xcd\x32\xa1\xd5\x09\xe5\x29\x78\x7d\x14\xa4\x45\x43\x8d\x80\x7e\xcd\x62\x0e\x2f\xa2\x6d\xe0\xda\x64\x26\x86\x47\x84\xd4\xa2\x8f\x54\x10\x3e\x60\x92\x83\xb9\x9e\xe9\xb2\xb6\x99\xc9\x80\xbb\xb7\x88\x2c\x3e\xa6\x8d\xdc\x90\x80\x2a\xc2\x32\xf2\xc8\xe8\x42\x91\x98\x7b\xf3\xc5\x24\x09\x21\xb5\x9c\xfa\x21\x49\x69\x31\x76\x73\xd0\xbe\x7f\x34\xb1\xca\x0e\x15\xea\x73\xc7\x17\x54\x01\xce\x55\x0b\xe1\x06\xb4\x9e\x62\xf8\xdb\x68\x69\x5e\x74\x0e\x0f\x3a\x35\x56\xa1\x9f\x3c\x8e\x6b\x91\xac\x1c\xc2\x3e\x86\x3f\xcd\x0f\x0d\x9e\xb7\x04\x7a\xa6\x31\xe0\xd2\xeb\x9b\xcc\x6b"}, -{{0xb9,0xce,0xd0,0x41,0x25,0x93,0xfe,0xfe,0xd9,0x5e,0x94,0xac,0x96,0x5e,0x5b,0x23,0xff,0x9d,0x4b,0x0e,0x79,0x7d,0xb0,0x2b,0xf4,0x97,0x99,0x4d,0x3b,0x79,0x3e,0x60,},{0xc1,0x62,0x9a,0x72,0x31,0x89,0x95,0x93,0x37,0xf5,0x53,0x52,0x01,0xe5,0xd3,0x95,0xba,0x0a,0x03,0xea,0x8c,0x17,0x66,0x0d,0x0f,0x8b,0x6f,0x6e,0x64,0x04,0xbb,0x12,},{0xf1,0xb7,0x97,0xde,0xd8,0xa6,0x94,0x2b,0x12,0x62,0x68,0x48,0x34,0x0f,0xb7,0x19,0xfc,0xdd,0xaf,0xd9,0x8f,0x33,0xe2,0x99,0x2d,0x35,0x7b,0xfd,0xd3,0x59,0x33,0xc7,0xac,0x56,0x1e,0x5b,0x2f,0x93,0x94,0x64,0x33,0x8c,0x56,0x66,0x85,0x4c,0xa8,0x85,0xc4,0xd0,0x46,0xeb,0x2c,0x54,0xe4,0x8a,0x1b,0x5e,0xd2,0x66,0xad,0x34,0xde,0x05,},"\x55\x5b\xb3\x9c\x18\x99\xd5\x7c\xab\xe4\x28\x06\x4c\x2d\x92\x5f\x5f\xc4\xcf\x70\x59\xb9\x5f\xb8\x9a\x8e\x9e\x3a\x7e\x42\x6c\x6c\x92\x2d\x9e\x4d\x76\x98\x4e\xa2\x38\x3c\xab\xb4\xf2\xbe\xfd\x89\xc1\xf2\x0e\xaa\x8a\x00\xdb\xe7\x87\xcf\xa7\x0a\xe2\xae\x6a\xa9\x03\x31\xcb\xbe\x58\x0f\xa5\xa0\x21\x84\xed\x05\xe6\xc8\xe8\x9d\x57\x6a\xf2\x8a\xee\xaf\x7c\x4e\x25\x00\xf3\x58\xa0\x09\x71\xa0\xa7\x59\x20\xe8\x54\x84\x9b\xf3\x32\x14\x29\x75\x40\x4f\x59\x8c\x32\xe9\x69\x82\x04\x3d\x99\x2b\xcd\x1a\x4f\xe8\x19\xbb\x56\x34\xad\x03\x46\x7a\xfc\x4c\xe0\x50\x73\xf8\x8b\xa1\xba\x4a\xe8\x65\x3a\x04\x66\x5c\xf3\xf7\x16\x90\xfe\x13\x34\x38\x85\xbc\x5e\xbc\x0e\x5e\x62\xd8\x82\xf4\x3b\x7c\x68\x90\x0a\xc9\x43\x8b\xf4\xa8\x1c\xe9\x01\x69\xec\x12\x9e\xe6\x3e\x2c\x67\x5a\x1a\x5a\x67\xe2\x7c\xc7\x98\xc4\x8c\xc2\x3f\x51\x07\x8f\x46\x3b\x3b\x7c\xc1\x4e\x3b\xcf\xd2\xe9\xb8\x2c\x75\x24\x09\x34\xcb\xdc\x50\xc4\x30\x8f\x28\x2f\x19\x31\x22\x99\x56\x06\xf4\x01\x35\x10\x0a\x29\x1c\x55\xaf\xdf\x89\x34\xeb\x8b\x61\xd8\x14\x21\x67\x41\x24\xde\xc3\xb8\x8f\x9a\x73\x11\x0a\x9e\x61\x6f\x5b\x82\x6b\x9d\x34\x3f\x3a\xc0\xe9\xd7\xbd\xf4\xfd\x8b\x64\x8b\x40\xf0\x09\x8b\x38\x97\xa3\xa1\xcd\x65\xa6\x45\x70\x05\x9b\x8b\xc5\xc6\x74\x38\x83\x07\x4c\x88\x62\x3c\x1f\x5a\x88\xc5\x89\x69\xe2\x1c\x69\x2a\xca\x23\x68\x33\xd3\x47\x0b\x3e\xb0\x98\x15\xe1\x13\x8e\x9d\x06\x50\xc3\x90\xee\xe9\x77\x42\x21\x93\xb0\x09\x18\xbe\x8a\x97\xcc\x61\x99\xb4\x51\xb0\x5b\x57\x30\xd1\xd1\x33\x58\xcf\x74\x61\x06\x78\xf7\xac\x7f\x78\x95\xcc\x2e\xfc\x45\x6e\x03\x87\x3b"}, -{{0x81,0xda,0x16,0x8f,0x02,0xd4,0x6b,0xb8,0x7c,0xda,0x84,0x5d,0xa4,0x3f,0x8a,0x6c,0xba,0x2c,0x01,0x68,0x78,0xd6,0xf4,0x9c,0x6f,0x06,0x1a,0x60,0xf1,0x55,0xa0,0x4a,},{0xaf,0xf8,0x6e,0x98,0x09,0x3c,0xa4,0xc7,0x1b,0x1b,0x80,0x4c,0x5f,0xe4,0x51,0xcf,0xdf,0x86,0x82,0x50,0xde,0xa3,0x03,0x45,0xfa,0x4b,0x89,0xbb,0x09,0xb6,0xa5,0x3b,},{0x4a,0xac,0xa9,0x47,0xe3,0xf2,0x2c,0xc8,0xb8,0x58,0x8e,0xe0,0x30,0xac,0xe8,0xf6,0xb5,0xf5,0x71,0x1c,0x29,0x74,0xf2,0x0c,0xc1,0x8c,0x3b,0x65,0x5b,0x07,0xa5,0xbc,0x13,0x66,0xb5,0x9a,0x17,0x08,0x03,0x2d,0x12,0xca,0xe0,0x1a,0xb7,0x94,0xf8,0xcb,0xcc,0x1a,0x33,0x08,0x74,0xa7,0x50,0x35,0xdb,0x1d,0x69,0x42,0x2d,0x2f,0xc0,0x0c,},"\x6b\xc6\x72\x6a\x34\xa6\x4a\xae\x76\xab\x08\xc9\x2b\x17\x9e\x54\xff\x5d\x2e\x65\xeb\x2c\x6c\x65\x9a\xe8\x70\x3c\xc2\x45\xcb\xc2\xcf\x45\xa1\x2b\x22\xc4\x68\xae\x61\xfd\x9a\x66\x27\xad\x06\x26\xc9\xb1\xe5\xaf\x41\x2c\xb4\x83\xea\xee\x1d\xb1\x1b\x29\xf0\xa5\x10\xc1\x3e\x38\x02\x0e\x09\xae\x0e\xee\x76\x25\x37\xa3\xe9\xd1\xa0\xc7\xb0\x33\xd0\x97\xfd\xc1\xf4\xf8\x26\x29\xa9\xde\x9e\xf3\x8d\xa1\xcf\x96\xa9\x40\x35\x7d\x5f\x2e\x0e\x7e\x8d\xbc\x29\xdb\x72\x8a\x1e\x6a\xad\x87\x6e\x5e\x05\x31\x13\xd0\x64\x20\x27\x2b\x87\xcf\x0c\x40\xdf\xe0\x3a\x54\x4d\xe9\x6c\x7a\xea\x13\xba\x00\x29\xb5\x7b\x48\xd9\x9d\xcc\x6a\x65\x04\x92\xd7\x8c\x4c\xdd\x1b\x28\xe1\xa1\x15\xa7\xe3\xe7\xa7\xcb\x21\x33\x3d\x4f\xf8\x08\x58\xdf\xb6\x77\x82\xc1\x63\x54\xb8\x71\x65\x96\x56\x0d\x7d\x8e\x38\x9e\xb1\x5a\x05\x2a\x0b\xf5\xd1\x6e\xb5\x4f\xb3\xe4\x97\x3a\xd4\x98\x4e\x72\xa1\x87\xf5\x34\x7d\x5b\x26\x2c\x32\xb1\x64\x7e\x42\xb6\xa5\x38\x37\x09\x6c\xc7\x8c\x2a\x05\xce\x1c\x6e\x12\x49\x3a\x03\xf1\xa6\x67\x58\x4c\xb9\x7f\x4f\xcd\x57\xee\x94\x4c\x65\xb7\xee\xd2\x5f\x7a\xe0\xf3\xf6\xce\xde\x17\x3f\xdf\xac\xf5\xaf\x1d\xb1\x43\x73\x0d\x18\x09\x66\x64\x91\x4b\xa4\xcf\xc6\x96\x6f\x39\x20\x22\x78\x1c\x66\xa9\x41\x7c\xa2\x68\x0b\x51\xf6\x3e\x4f\xba\x42\x4e\xcf\xdb\xc6\xa2\xf0\x17\x87\xd0\xe7\x48\x4f\x8a\x8a\xb3\x90\xae\xaa\x6d\x1f\x7e\xd3\x25\xd8\x2f\xea\xa1\x69\x2a\x49\x84\xfa\xe4\x3d\xa8\x73\x29\xb0\x45\xda\x8f\x0a\x4f\x56\xb6\x95\xaa\x93\x5d\xe1\x52\xce\x03\x85\x15\x37\x20\x97\x9a\x2b\x70\x06\xd4\x05\xfc\xb0\xfb\xa0\x9e\x23\xb8\x5f\xd1\x9b"}, -{{0xaf,0x2e,0x60,0xda,0x0f,0x29,0xbb,0x16,0x14,0xfc,0x3f,0x19,0x3c,0xc3,0x53,0x33,0x19,0x86,0xb7,0x3f,0x3f,0x9a,0x0a,0xec,0x94,0x21,0xb9,0x47,0x3d,0x6a,0x4b,0x6a,},{0xc8,0xbf,0xe2,0x83,0x58,0x22,0x19,0x9c,0x61,0x27,0xb8,0x06,0xfa,0xbe,0xef,0x0c,0xb9,0xff,0x59,0xf3,0xc8,0x1f,0xf0,0xcb,0x89,0xc5,0x56,0xf5,0x51,0x06,0xaf,0x6a,},{0x50,0xf9,0xf9,0x41,0xa8,0xda,0x9f,0x62,0x40,0xf7,0x6d,0x2f,0xa3,0xb0,0x6d,0xd6,0xb2,0x29,0x2e,0xd3,0x2d,0x1c,0x05,0x21,0x80,0x97,0xd3,0x4d,0x8a,0x19,0xdf,0xe5,0x53,0xf7,0x6a,0xe3,0xc6,0xb4,0xa2,0xed,0x20,0x85,0x21,0x28,0x46,0x15,0x40,0xde,0xcf,0x41,0x8f,0x52,0xd3,0x8e,0x64,0x03,0x7e,0xec,0x77,0x71,0xbd,0x1a,0xfe,0x00,},"\x7d\xbb\x77\xb8\x8b\xda\x94\xf3\x44\x41\x6a\x06\xb0\x96\x56\x6c\x6e\x8b\x39\x39\x31\xa8\x24\x3a\x6c\xab\x75\xc3\x61\xfd\xe7\xdc\x53\x6a\xec\x40\xcd\xed\x83\x29\x6a\x89\xe8\xc3\xbe\xf7\xd7\x87\xcf\xc4\x94\x01\xa7\xb9\x18\x3f\x13\x8d\x50\x00\x61\x9f\xf0\x73\xc0\x5e\x2f\x84\x1d\x60\x08\x35\x8f\x10\xa2\xda\x7d\xcf\xac\x3d\x4d\x70\xc2\x0d\x2e\xc3\x4c\x7b\x6d\x5c\xd1\xa7\x34\xd6\xbb\xb1\x1c\x5f\xd8\xd2\xbc\xe3\x2a\xc8\x10\xef\x82\xb4\x18\x8a\xa8\xea\x3c\xfc\x30\x32\x23\x3d\xc0\xe2\x60\x0e\x9d\xb6\xe1\x8b\xc2\x2b\x10\x04\x4a\x31\xc1\x5b\xac\xea\xf5\x55\x4d\xe8\x9d\x2a\x34\x66\x80\x7f\x24\x44\x14\xd0\x80\xff\x29\x63\x95\x6c\x6e\x83\xc8\xe1\x44\xed\x00\x66\x08\x8b\x47\x6d\xdc\xb5\x64\x40\x34\x47\xd9\x15\x9f\x90\x89\xab\xa2\xb4\xd5\x57\x5c\x4d\x8a\xe6\x6f\xc8\x69\x0e\x73\x49\xed\x40\x83\x2e\x63\x69\xc0\x24\x56\x3e\xc4\x93\xbf\xcc\x0f\xc9\xac\x78\x7a\xc8\x41\x39\x7f\xe1\x33\x16\x72\x83\xd8\x0c\x42\xf0\x06\xa9\x9d\x39\xe8\x29\x79\xda\x3f\xa9\x33\x4b\xd9\xed\xe0\xd1\x4b\x41\xb7\x46\x6b\xce\xbb\xe8\x17\x1b\xc8\x04\xa6\x45\xd3\x72\x32\x74\xa1\xb9\x2b\xf8\x2f\xd9\x93\x35\x87\x44\xde\x92\x44\x19\x03\xd4\x36\xfd\x47\xf2\x3d\x40\x05\x2a\x38\x29\x36\x7f\x20\x2f\x05\x53\xb5\xe4\x9b\x76\xc5\xe0\x3f\xa6\xce\x7c\x3c\xf5\xee\xb2\x1d\xe9\x67\xbe\xc4\xdd\x35\x59\x25\x38\x4e\xbf\x96\x69\x7e\x82\x37\x62\xba\xc4\xd4\x3a\x76\x7c\x24\x1a\x4c\xef\x72\x4a\x97\x0d\x00\xff\x3a\x8a\xb3\xb8\x3e\xed\x84\x00\x75\xc7\x4e\x90\xf3\x06\xe3\x30\x01\x32\x60\x96\x21\x61\xe9\xd0\x91\x0d\xe1\x83\x62\x2c\xe9\xa6\xb8\xd5\x14\x42\x80\x55\x0f\xc7"}, -{{0x60,0x5f,0x90,0xb5,0x3d,0x8e,0x4a,0x3b,0x48,0xb9,0x7d,0x74,0x54,0x39,0xf2,0xa0,0x80,0x7d,0x83,0xb8,0x50,0x2e,0x8e,0x29,0x79,0xf0,0x3e,0x8d,0x37,0x6a,0xc9,0xfe,},{0xaa,0x3f,0xae,0x4c,0xfa,0x6f,0x6b,0xfd,0x14,0xba,0x0a,0xfa,0x36,0xdc,0xb1,0xa2,0x65,0x6f,0x36,0x54,0x1a,0xd6,0xb3,0xe6,0x7f,0x17,0x94,0xb0,0x63,0x60,0xa6,0x2f,},{0xdd,0x02,0x12,0xe6,0x32,0x88,0xcb,0xe1,0x4a,0x45,0x69,0xb4,0xd8,0x91,0xda,0x3c,0x7f,0x92,0x72,0x7c,0x5e,0x7f,0x9a,0x80,0x1c,0xf9,0xd6,0x82,0x70,0x85,0xe7,0x09,0x5b,0x66,0x9d,0x7d,0x45,0xf8,0x82,0xca,0x5f,0x07,0x45,0xdc,0xcd,0x24,0xd8,0x7a,0x57,0x18,0x13,0x20,0x19,0x1e,0x5b,0x7a,0x47,0xc3,0xf7,0xf2,0xdc,0xcb,0xd7,0x07,},"\x3b\xcd\xca\xc2\x92\xac\x95\x19\x02\x4a\xae\xce\xe2\xb3\xe9\x99\xff\x5d\x34\x45\xe9\xf1\xeb\x60\x94\x0f\x06\xb9\x12\x75\xb6\xc5\xdb\x27\x22\xed\x4d\x82\xfe\x89\x60\x52\x26\x53\x0f\x3e\x6b\x07\x37\xb3\x08\xcd\xe8\x95\x61\x84\x94\x4f\x38\x8a\x80\x04\x2f\x6c\xba\x27\x4c\x0f\x7d\x11\x92\xa0\xa9\x6b\x0d\xa6\xe2\xd6\xa6\x1b\x76\x51\x8f\xbe\xe5\x55\x77\x3a\x41\x45\x90\xa9\x28\xb4\xcd\x54\x5f\xcc\xf5\x81\x72\xf3\x58\x57\x12\x0e\xb9\x6e\x75\xc5\xc8\xac\x9a\xe3\xad\xd3\x67\xd5\x1d\x34\xac\x40\x34\x46\x36\x0e\xc1\x0f\x55\x3e\xa9\xf1\x4f\xb2\xb8\xb7\x8c\xba\x18\xc3\xe5\x06\xb2\xf0\x40\x97\x06\x3a\x43\xb2\xd3\x64\x31\xcc\xe0\x2c\xaf\x11\xc5\xa4\xdb\x8c\x82\x17\x52\xe5\x29\x85\xd5\xaf\x1b\xfb\xf4\xc6\x15\x72\xe3\xfa\xda\xe3\xad\x42\x4a\xcd\x81\x66\x2e\xa5\x83\x7a\x11\x43\xb9\x66\x93\x91\xd7\xb9\xcf\xe2\x30\xcf\xfb\x3a\x7b\xb0\x3f\x65\x91\xc2\x5a\x4f\x01\xc0\xd2\xd4\xac\xa3\xe7\x4d\xb1\x99\x7d\x37\x39\xc8\x51\xf0\x32\x7d\xb9\x19\xff\x6e\x77\xf6\xc8\xa2\x0f\xdd\x3e\x15\x94\xe9\x2d\x01\x90\x1a\xb9\xae\xf1\x94\xfc\x89\x3e\x70\xd7\x8c\x8a\xe0\xf4\x80\x00\x1a\x51\x5d\x4f\x99\x23\xae\x62\x78\xe8\x92\x72\x37\xd0\x5d\xb2\x3e\x98\x4c\x92\xa6\x83\x88\x2f\x57\xb1\xf1\x88\x2a\x74\xa1\x93\xab\x69\x12\xff\x24\x1b\x9f\xfa\x66\x2a\x0d\x47\xf2\x92\x05\xf0\x84\xdb\xde\x84\x5b\xaa\xeb\x5d\xd3\x6a\xe6\x43\x9a\x43\x76\x42\xfa\x76\x3b\x57\xe8\xdb\xe8\x4e\x55\x81\x3f\x01\x51\xe9\x7e\x5b\x9d\xe7\x68\xb2\x34\xb8\xdb\x15\xc4\x96\xd4\xbf\xcf\xa1\x38\x87\x88\x97\x2b\xb5\x0c\xe0\x30\xbc\x6e\x0c\xcf\x4f\xa7\xd0\x0d\x34\x37\x82\xf6\xba\x8d\xe0"}, -{{0x9e,0x2c,0x3d,0x18,0x98,0x38,0xf4,0xdd,0x52,0xef,0x08,0x32,0x88,0x68,0x74,0xc5,0xca,0x49,0x39,0x83,0xdd,0xad,0xc0,0x7c,0xbc,0x57,0x0a,0xf2,0xee,0x9d,0x62,0x09,},{0xf6,0x8d,0x3b,0x81,0xe7,0x35,0x57,0xee,0x1f,0x08,0xbd,0x2d,0x3f,0x46,0xa4,0x71,0x82,0x56,0xa0,0xf3,0xcd,0x8d,0x2e,0x03,0xeb,0x8f,0xe8,0x82,0xaa,0xb6,0x5c,0x69,},{0x38,0xa3,0x1b,0x6b,0x46,0x50,0x84,0x73,0x82,0x62,0xa2,0x6c,0x06,0x5f,0xe5,0xd9,0xe2,0x88,0x6b,0xf9,0xdd,0x35,0xcd,0xe0,0x5d,0xf9,0xba,0xd0,0xcc,0x7d,0xb4,0x01,0xc7,0x50,0xaa,0x19,0xe6,0x60,0x90,0xbc,0xe2,0x5a,0x3c,0x72,0x12,0x01,0xe6,0x05,0x02,0xc8,0xc1,0x04,0x54,0x34,0x66,0x48,0xaf,0x06,0x5e,0xab,0x0e,0xe7,0xd8,0x0f,},"\x19\x48\x5f\x52\x38\xba\x82\xea\xdf\x5e\xff\x14\xca\x75\xcd\x42\xe5\xd5\x6f\xea\x69\xd5\x71\x8c\xfb\x5b\x1d\x40\xd7\x60\x89\x9b\x45\x0e\x66\x88\x45\x58\xf3\xf2\x5b\x7c\x3d\xe9\xaf\xc4\x73\x8d\x7a\xc0\x9d\xa5\xdd\x46\x89\xbb\xfa\xc0\x78\x36\xf5\xe0\xbe\x43\x2b\x1d\xdc\xf1\xb1\xa0\x75\xbc\x98\x15\xd0\xde\xbc\x86\x5d\x90\xbd\x5a\x0c\x5f\x56\x04\xd9\xb4\x6a\xce\x81\x6c\x57\x69\x4e\xcc\x3d\x40\xd8\xf8\x4d\xf0\xed\xe2\xbc\x4d\x57\x77\x75\xa0\x27\xf7\x25\xde\x08\x16\xf5\x63\xfa\x88\xf8\x8e\x07\x77\x20\xeb\xb6\xac\x02\x57\x46\x04\x81\x98\x24\xdb\x74\x74\xd4\xd0\xb2\x2c\xd1\xbc\x05\x76\x8e\x0f\xb8\x67\xca\x1c\x1a\x7b\x90\xb3\x4a\xb7\xa4\x1a\xfc\x66\x95\x72\x66\xac\x0c\x91\x59\x34\xaa\xf3\x1c\x0c\xf6\x92\x7a\x4f\x03\xf2\x32\x85\xe6\xf2\x4a\xfd\x58\x13\x84\x9b\xb0\x8c\x20\x3a\xc2\xd0\x33\x6d\xcb\xf8\x0d\x77\xf6\xcf\x71\x20\xed\xfb\xcd\xf1\x81\xdb\x10\x7e\xc8\xe0\x0f\x32\x44\x9c\x1d\x3f\x5c\x04\x9a\x92\x69\x4b\x4e\xa2\xc6\xeb\xe5\xe2\xb0\xf6\x4b\x5a\xe5\x0a\xd3\x37\x4d\x24\x6b\x32\x70\x05\x7e\x72\x4a\x27\xcf\x26\x3b\x63\x3a\xb6\x5e\xcb\x7f\x5c\x26\x6b\x80\x07\x61\x8b\x10\xac\x9a\xc8\x3d\xb0\xfe\xbc\x04\xfd\x86\x3d\x96\x61\xab\x6e\x58\x49\x47\x66\xf7\x1b\x9a\x86\x7c\x5a\x7a\x45\x55\xf6\x67\xc1\xaf\x2e\x54\x58\x8f\x16\x2a\x41\xce\x75\x64\x07\xcc\x41\x61\xd6\x07\xb6\xe0\x68\x29\x80\x93\x4c\xaa\x1b\xef\x03\x6f\x73\x30\xd9\xee\xf0\x1e\xcc\x55\x35\x83\xfe\xe5\x99\x4e\x53\x3a\x46\xca\x91\x6f\x60\xf8\xb9\x61\xae\x01\xd2\x0f\x7a\xbf\x0d\xf6\x14\x1b\x60\x4d\xe7\x33\xc6\x36\xb4\x20\x18\xcd\x5f\x1d\x1e\xf4\xf8\x4c\xee\x40\xfc"}, -{{0x31,0x01,0x0d,0x1d,0x67,0xeb,0x61,0x63,0x48,0xe8,0x47,0x92,0xb9,0x2d,0x5d,0xc1,0x28,0x55,0x3c,0xb5,0x2f,0x63,0x68,0x15,0x9f,0xe7,0xb8,0x16,0xcd,0x0e,0x7c,0x37,},{0x26,0x65,0x43,0xd9,0x67,0x87,0xca,0x90,0x1f,0xcf,0xf0,0x6e,0x6e,0x43,0x44,0x91,0xae,0x09,0x70,0x88,0x0a,0x5a,0x18,0x7d,0x53,0x5e,0xdb,0x19,0xdb,0x5c,0xab,0xeb,},{0x7b,0x1e,0xb6,0x77,0xc3,0xe5,0xe6,0xa8,0xb4,0xba,0x69,0xfc,0xb7,0xf6,0xb1,0x87,0x0e,0x42,0xa8,0xd5,0x89,0x58,0xa3,0x5c,0x67,0x4e,0x2d,0xb8,0x21,0x07,0x48,0x1c,0x4c,0x7b,0x37,0xf0,0xf6,0x89,0xd3,0x9d,0x9f,0x51,0xe1,0x81,0xb1,0x7b,0x11,0x08,0xc1,0x5a,0x3e,0x27,0xb2,0x9d,0xf3,0xa4,0x31,0x5d,0xcc,0x4f,0xaf,0x12,0x22,0x05,},"\x39\xf8\x9a\x5e\x7a\xa5\x30\xb5\x46\x3d\x49\x8f\x80\x35\xb9\x90\x9d\x55\xda\x52\x7c\xdb\xd4\xde\x6d\x22\x83\x79\xf0\x89\xe6\x08\xa9\x20\x7a\x2c\x5b\x9c\x42\x05\x1a\x60\xc8\xca\x3f\xb9\x7a\x1c\x06\xcd\x74\x7d\x9d\x07\x39\x97\x0c\xeb\x88\xce\x52\x6f\x97\x11\x40\xea\x2e\xc2\x1f\x09\x0b\xa0\x75\xbf\x89\x75\xfa\xa5\x08\xb1\xcc\x10\xef\xa4\x94\xdc\x17\x2e\x6d\x3d\x3f\x3f\x75\xdc\x8e\x0e\x96\xf0\x5c\x0c\xcc\xb2\xf9\x6e\x91\x1c\xfa\x7a\x2c\x82\xc9\x84\x50\x18\xbb\x1f\x9d\x75\xf8\x2e\x3d\xfe\x11\x39\x34\x7b\x2a\xc0\x58\xb0\x14\xac\x93\x76\x0c\x90\xf5\x56\x7a\xb5\xc4\xeb\xa0\x4b\x49\xfb\x09\xdd\xad\xd3\x05\xbe\x51\x1d\xfe\x05\xc9\x6e\xbc\x86\xfd\x67\xb5\xd0\xab\x57\xd8\x5f\x4f\xe5\xe2\xf0\xfa\x9d\x88\xa6\x8f\x0f\x6b\x6b\xc8\xbb\x94\x4e\xb3\xc0\xb1\x75\x57\xe5\x5d\x5e\xa1\x87\xd9\x22\xa4\x28\x13\xe6\x90\x57\xc9\xb6\xa7\xf7\x5e\x49\x92\x1b\x70\x79\xe5\x8f\x8a\x63\x71\x9e\xe3\xe1\xad\x10\xcf\x0e\x8a\x70\xc4\xf1\x54\x02\x18\xb7\x04\x94\xbd\x02\x9e\xe0\x2f\xf9\x72\x7a\x7d\x85\xd3\x77\x91\x9e\xc4\x05\x14\x79\xb7\x0f\x7c\xd6\x76\x77\x23\xfe\x42\xc1\xc7\x89\x9c\x2b\x7c\x1f\x70\x2d\xd6\xb4\xd1\x3b\x67\x2d\x48\x8f\x34\xa0\xe9\x69\xdb\x79\xcc\x2c\xb2\x52\x4a\x94\x8a\x8d\xe4\xc5\xb6\x23\xec\xd9\x0d\x6e\x82\xd9\x70\x33\xc1\x25\x63\x7d\x1c\xd8\xc8\x48\x03\xd8\xfb\xc0\x12\x84\x6f\xfe\x48\x4f\x6c\x02\x14\x92\x58\xf9\x46\x2f\xa1\xe9\x9c\x30\x7d\xd0\x06\x2f\xe0\xb6\xf1\x1e\xee\x40\xc2\x62\x9e\xf7\xc0\xf6\xa5\x10\x72\x59\xea\x5b\x9f\xfb\x6f\x29\xf1\x2c\x32\xf7\xb5\x22\x8c\xab\xc9\x86\xab\x66\x45\x0a\xf9\xdc\xc3\xda\x09\xd0\xe0\xb9\xa4"}, -{{0x8f,0xf2,0x39,0x8c,0xd5,0x1f,0x51,0xd4,0xc2,0xc5,0x78,0x69,0xa2,0x21,0x8b,0x84,0x86,0x82,0x20,0x31,0xf4,0x00,0x72,0x9f,0x4a,0xc4,0xd5,0x90,0x9c,0x48,0xba,0xfe,},{0xa5,0xa8,0x87,0x04,0xb6,0x86,0x77,0xbe,0x3d,0x16,0xc3,0xdc,0x00,0x52,0xcf,0xee,0x6e,0x2b,0x30,0xe0,0x86,0x09,0x05,0x9d,0x4c,0xba,0x52,0xc6,0xd9,0x60,0x61,0xfb,},{0x41,0x7a,0x64,0x78,0x29,0xc9,0x28,0x98,0xe5,0x20,0xff,0x53,0x11,0xda,0xa0,0xa1,0x39,0xcd,0x8f,0xff,0xcb,0x25,0xa1,0x8e,0x6d,0x9b,0x50,0xcb,0x52,0xcb,0xc3,0x54,0x24,0xc3,0x9e,0xbb,0xb5,0xd5,0xac,0x6a,0x6d,0x63,0xf1,0xf5,0x3c,0x4d,0xf2,0x12,0xf7,0x02,0x5a,0x8a,0xae,0xf8,0xe3,0x64,0x93,0xc8,0x74,0xc3,0xce,0x34,0x1a,0x0e,},"\x99\x39\x53\xe4\x7a\x34\x11\x88\xbc\x59\x29\x42\xe1\x55\x7a\xf2\x95\x46\xe4\xe9\x36\x8e\x2f\x1a\x5e\xe9\x80\x6e\x2b\xaf\x66\xb6\x19\x01\x91\xfc\x5d\x2b\x7e\x47\xde\x37\xff\x05\x4f\xb2\xbb\xb1\xf0\x31\x68\x4a\xda\x5d\x60\x7a\xdd\xa3\xd6\x54\x33\x12\x2f\xa9\x04\xe0\x45\x6f\xaa\x84\x10\x9b\xbc\x51\x7f\x8a\xd3\x96\x60\x87\x63\x82\xad\xcf\xed\x0f\x76\x20\xcf\x11\x64\x62\x2e\xac\xd9\x1e\xb3\x7a\x85\x96\x46\x2e\xbe\x9e\xbe\x26\xbd\xc1\xe3\x2c\xc3\x4a\xd4\x6f\xb1\xce\xa4\x20\xe7\x3c\x31\x21\x54\x08\xe6\xd3\x54\x25\xf4\x4a\x82\x9b\x13\x2f\x63\x1a\x3f\x6d\xd4\xb8\x73\xa0\x00\x66\x7e\x19\xeb\x22\xff\xfd\x59\x03\xaa\xa7\xd4\xc8\xfd\xf2\x19\x53\xc3\xc6\x17\x8f\x5f\x8c\xb2\xaa\x6b\xff\x92\x89\x4e\xad\x83\x58\x88\xdf\x06\x0a\x3c\x90\x43\x02\x6e\x0e\x2c\xef\x27\x54\x97\xe7\xd1\x05\xdf\x3b\x64\x4a\x98\xf2\x6b\xf0\x01\x05\xc9\x94\x13\xee\x0a\xf8\x85\x19\x54\xd6\x5c\xeb\x8d\x79\xad\x30\x71\xb8\xbb\x87\xf0\xb1\x97\x43\xd2\x55\x6f\xfd\x98\x19\x83\x0b\x6e\xeb\xf7\xec\xc7\xe0\x45\x66\x1f\x43\x57\x0c\xe9\xfd\xbb\xe2\xd2\x52\x40\x6f\xa9\x0d\x04\x23\x6f\x22\x2c\x42\x9e\xc1\x6b\x12\x87\x22\x4a\xda\x1a\x53\x21\x61\xae\x8b\x48\x1b\xca\xb8\xd4\x7a\xfb\x3e\xd0\x44\x5b\x30\x60\xfd\x67\x59\x17\x98\x56\xf4\x08\x5c\x1e\x58\x5f\xd7\xc1\x40\x97\x99\xaf\x69\x3c\xf4\x27\xbd\x1d\x3d\xc1\x0b\x5a\xe3\x44\x7a\x8d\x2a\x18\xdc\x3a\x12\xa6\x86\x0b\x22\x17\x5d\xd5\xeb\x53\xa0\x95\x04\x32\xe2\xd7\xae\xfe\xce\x8a\xf0\xad\xe3\xd8\x56\x77\x43\xde\x43\x69\x0f\x2d\x25\x37\x23\xc5\xd7\xe4\x8b\xd3\x0d\x29\x37\x59\x37\x01\xce\xcd\xe9\x15\x4b\x76\x65\xcb\x61\x1d\x7d"}, -{{0xef,0x81,0x6c,0x8f,0x5e,0xc3,0x4e,0xf4,0x1f,0x68,0x83,0x1d,0x90,0xcd,0x29,0xe5,0x2d,0xe8,0x97,0x37,0x82,0xd0,0x03,0xee,0x4e,0xda,0xda,0x2a,0xda,0x26,0x91,0xd6,},{0x47,0xf9,0xb3,0x63,0xa8,0x8a,0x45,0x05,0x3a,0x05,0xbb,0x72,0x16,0x08,0x52,0xbf,0xe8,0xf7,0xdf,0xef,0xc2,0xf3,0x72,0x83,0xde,0x34,0x67,0x52,0xca,0xf0,0x92,0xcc,},{0x65,0xc5,0xd1,0x0e,0xa7,0xbf,0xdb,0xb3,0x8d,0x55,0x36,0x4a,0x99,0x68,0xf8,0x2b,0x54,0x82,0x24,0xdf,0xf3,0x36,0x3b,0x2d,0xdc,0xf5,0x85,0x16,0x3d,0xea,0x27,0xdc,0x63,0xb0,0x56,0x3e,0xb1,0xa8,0xdf,0xbe,0xe9,0x51,0xd3,0xc9,0xb3,0x3f,0xcd,0x6b,0xbf,0x09,0x21,0xc3,0xab,0xb2,0x17,0x86,0xb2,0x29,0x06,0x9b,0xd9,0xca,0x00,0x0a,},"\x95\x93\xc3\x5c\xde\xc5\x35\xbe\xbb\x69\x65\xda\x68\xea\xb0\xb6\x46\xbf\xfc\xfb\xd0\x48\x83\xbc\x4c\xef\x90\xd5\xd0\x1f\x01\x8c\x63\xc9\xb0\xdd\xfb\x3c\xef\x5e\x78\x62\x84\xd5\x21\x8c\xaa\xaf\x06\x0e\x92\x88\x95\x2f\x16\x30\x1e\xd8\xa4\xc1\xbc\xee\x25\x63\x56\xa0\xc8\xbd\xa3\x59\xfb\xaa\x27\x82\xb1\x0c\x86\xd1\x8e\x20\xf7\xa0\xec\x99\xb2\x7a\x0b\x4d\xbe\xfc\x0a\x26\x2a\x3b\xf6\x8f\xe8\x14\x44\xdc\xae\x5f\x69\x3e\xb0\xf1\x6e\x6e\xe0\x3f\x8f\xcb\xf3\xa3\x39\x81\x46\xd2\x0e\xc4\xd2\x65\x77\x61\xfd\x03\x20\xfe\xe7\xea\x70\x3c\x49\xa6\xa5\x43\xbc\x9b\xba\x91\x1e\x79\x25\x03\x87\x10\xe8\xc3\x65\x52\xd4\x76\xd6\x02\x7f\x58\xb2\xc5\x2b\xa5\x1a\xd6\x5e\xa4\xf0\x39\xc7\x8f\x96\xb8\x89\x10\x2b\xb4\xbd\xd6\x9b\x68\xe9\xc3\xd4\x5b\x51\x76\xa2\xd8\x2b\x0b\x95\xdc\x32\x10\x16\x37\x0d\xae\x30\xc3\x93\x65\x15\xdb\x04\x64\xc4\x17\x74\x30\x1c\x74\xe4\x2d\x89\xb8\xbf\x4b\x9c\x19\xed\x55\x4b\x12\xfe\xba\xc0\xf6\x0d\xdb\x32\x19\xcc\xc5\x60\x35\x31\xdb\xf2\xeb\x5f\x29\x34\x25\xd7\x2c\xce\xfa\x0c\x7f\x14\x4a\xba\x89\x34\x7b\x29\x6b\xe8\x7f\xf1\x89\x94\xb4\xa0\xc7\x0c\x93\x0f\x05\x93\x03\xb5\xdd\x4c\x8f\xe1\xe6\xbb\xc3\xcd\x68\xc6\xc0\xd8\x42\x46\xdc\x6e\x61\x40\xa2\xab\xd1\x78\x0b\x13\xf1\x59\x4a\x60\x19\xd1\x77\x8b\x7c\xbb\x3a\x3e\x3a\x34\xbf\xae\x72\x97\xf0\xb3\xed\xc3\x76\x94\x1c\x32\x35\x2a\x4b\xe3\x14\xb8\x4a\x9d\x8d\x6d\x7f\x1f\x38\xa0\xad\x37\x98\x02\x0a\xa2\xa3\x31\xa4\x02\xbe\x9c\x70\x44\x84\x74\x4a\x73\x0c\xbd\xed\xcb\x90\x4b\x6f\xde\x70\x8f\xbd\x14\xbf\xdc\x29\xef\xd4\x61\xd1\xd0\xb5\x82\x5d\xe0\xbc\x79\x42\x2b\x69\xa2\x72\x2f"}, -{{0x45,0xeb,0x0c,0x4d,0xfa,0xfa,0x2a,0x76,0x90,0xef,0x57,0x9c,0x09,0x54,0x56,0xce,0xed,0xcd,0x32,0xf0,0xb6,0x14,0x4d,0x0c,0x38,0x0f,0x87,0xfb,0x74,0x4a,0x0b,0x1f,},{0xfc,0x85,0x63,0x2c,0x98,0x38,0x4b,0x5f,0x96,0x82,0xae,0xd9,0xcd,0x66,0x4c,0xf1,0xf4,0x8e,0x58,0x8b,0xe2,0xd5,0x68,0xe5,0xc7,0x34,0x49,0x4d,0xf4,0xc7,0x12,0xb8,},{0x55,0x85,0x1d,0xe8,0xe1,0x09,0x2f,0x78,0x94,0x4f,0x6c,0x6d,0xd9,0x5b,0xf0,0x7e,0x2d,0xbc,0x8d,0xf7,0xf5,0x7a,0xd5,0x76,0x82,0x9b,0x97,0x8e,0x3a,0xf5,0x8a,0x7a,0x8e,0x94,0xed,0x4d,0xcc,0xbc,0x01,0x82,0x46,0x7e,0xdf,0x0b,0xad,0x4b,0xae,0x7c,0xa8,0x4a,0xa9,0xa0,0xc1,0x7c,0x61,0xa9,0xe0,0xdd,0xff,0x1d,0x75,0x25,0xd7,0x04,},"\x6f\x66\xd8\x47\x40\x5a\x03\xd7\xbd\x6f\x8d\x28\x97\xdb\xdf\x04\xe7\x6d\x7d\xf2\xd9\x47\x0a\x49\x96\xb7\xdd\x6d\xb8\x85\x00\xf8\xf4\xf8\x3e\x96\x0e\x21\x9a\x24\x86\xe2\x45\x45\xad\xd1\x36\x14\x55\x04\x14\xd8\x27\xc4\x1a\x9b\x08\x31\x8d\xaf\x01\xb1\x52\x14\xc6\x4a\x42\x66\xcb\xf8\xa5\x71\x7a\xda\x3e\x62\xc2\x67\x29\x07\x3e\x16\xdd\xbd\x66\xf2\xd5\x20\xe1\xe0\x99\x35\xde\x05\xe4\xdb\x11\xc3\x96\xd4\x77\x01\x0a\xec\x66\xaa\xfb\x76\x2e\x69\x23\x8d\x0b\x9e\x76\xb4\x52\x45\x4b\xf9\xe4\x51\xe7\x6a\xc7\x9e\x69\x90\xd4\x1b\x93\x2b\xc3\x29\x17\x09\x37\x83\xc9\x1b\xc9\xcf\x0b\xbe\x3b\x51\x40\x70\xa1\xe6\x92\xff\x34\xfd\x06\xb6\x6e\xa1\x1f\x39\xe1\x0a\xf9\x33\xee\x96\xd8\xe9\xb6\x77\xcb\x03\x73\x7e\x79\x64\xee\xaa\x72\x5f\x12\x12\x07\xf9\xc1\xb2\x6a\x96\xc6\x16\xdf\x7c\xb7\xca\xef\x47\xbd\xa9\x01\x36\x8f\xf2\xea\x58\x6e\x42\x2e\x65\xbf\x21\xa6\x91\xbd\xd2\xc1\x3e\x67\xff\xf5\x8c\xfb\xfe\xd8\x17\x82\x04\x9d\xaf\xa0\xf7\x27\xdf\x88\x62\x3f\x2f\x7e\x8f\x26\x2d\xaf\x93\x95\x42\xa1\x87\xb8\x72\x0a\x9b\x6b\x2b\x09\x89\x0e\x54\x87\x6b\x28\xa4\x38\x74\xab\xbe\x3b\xfa\x98\x1f\x81\x38\xb7\x72\xc5\xd5\x17\x36\x88\x5f\x86\xac\xac\x22\x15\xa0\xb0\x10\xdf\xc2\xc6\xb1\x50\x84\x5d\x4f\x82\x96\x25\x25\x86\xa3\xe1\x15\xf3\x03\xc3\xd8\xa5\x82\xe2\x0f\xd2\xd4\x3f\x6c\x44\x6e\x5d\x00\x28\x0e\xc1\x79\x82\x3b\x7f\xb4\xc1\xb0\xfe\xb9\x4e\xb4\xef\x17\x07\xf5\x18\x4e\x3b\x52\x46\x1a\x75\x62\xd1\xf3\x07\xcb\x75\x1c\xdb\xbf\x6e\xae\x49\xff\xae\x91\x86\x23\x58\xe7\x4e\x95\x48\x82\x2b\x8a\x04\x9f\xec\x6b\xf4\xc7\xa9\x9c\xab\xbe\x09\x20\x65\x77\xb6\x57\xe3\x1f"}, -{{0x70,0x9d,0x2e,0x19,0x90,0x06,0xf5,0x36,0x9a,0x7a,0x0b,0xdd,0x34,0xe7,0x4d,0xc7,0x84,0xbe,0x33,0x88,0x0e,0xa3,0xc5,0xdd,0x10,0xed,0x5c,0x94,0x45,0x1e,0x79,0x72,},{0x06,0xf9,0x89,0x20,0x2b,0xa2,0xcb,0xc9,0xc1,0x50,0xbe,0x61,0x12,0x62,0xac,0xa0,0x0c,0x45,0xf0,0x12,0xf8,0x9f,0xba,0xf8,0x9f,0x8c,0xec,0xcb,0xa0,0xb1,0x93,0x4a,},{0x62,0x9b,0xf9,0x7b,0x0c,0x78,0xee,0x6a,0x9c,0x87,0x59,0xfb,0xea,0x28,0x22,0x4e,0x27,0xab,0xbb,0x6c,0xbe,0x4d,0xea,0x5b,0xb7,0x97,0xe6,0xe0,0xfe,0x80,0xc9,0x13,0xf9,0x53,0xe3,0xa9,0xb6,0x23,0x35,0x2d,0x13,0xac,0xf4,0xce,0x62,0x50,0xfb,0x02,0x9a,0x1e,0x19,0x8d,0x72,0xbd,0x5e,0x74,0x02,0xe6,0x0e,0x9e,0x48,0xca,0x35,0x01,},"\x62\xf0\x03\x14\x0f\xa0\x9e\x03\x87\xd1\x87\xa0\xff\x96\xc4\x56\x3d\xf9\xf4\xe2\x8c\x22\x82\xc0\x18\x3a\xc3\xee\xde\x13\x12\x35\x49\x21\xf7\x80\xfc\xa5\x36\x1d\x30\x68\xd2\x99\x49\x63\x0b\x75\x30\xcd\x59\x14\xac\xe0\x46\x8d\x01\x4b\x6f\x53\xd8\x39\xb8\x2e\x38\x81\x7d\xbf\x2d\x83\x92\xc3\xce\x34\x24\xea\xb8\x6a\x24\xd8\x04\xc7\xac\xb1\xce\x7a\xcf\xe0\xa1\xcd\xa4\x39\x39\x24\x28\x31\x05\xda\x4a\x77\x41\x19\x6e\x02\x75\x50\x04\x7f\x85\xb7\xa0\xa0\x1d\x45\x41\x24\xef\xc0\xe2\x99\xf0\xef\x9a\xd1\x43\x50\x54\x30\x53\x48\x22\x61\x52\x8b\xaa\x56\xe6\x59\x99\xac\x80\x2c\x00\xa3\x36\x26\x7c\x63\x51\x06\xb2\x64\x03\xc1\x9f\x39\x1d\x53\xbd\x82\x86\x1d\x6d\x48\xa4\x38\x0b\x30\x43\xaa\x91\xd6\x49\x53\x68\x81\x20\x4e\xcc\xb0\xde\x20\xd4\x3e\x5a\x37\x55\xb7\xf6\x00\x91\x6e\xcc\xae\x42\xa0\xc9\x05\x3b\x46\x2d\x94\x17\xa1\x3d\x67\xd7\x78\x26\x4a\x89\x6e\x8e\xaf\x90\xba\xf6\x6d\x29\xe5\x43\x8a\x71\x67\x81\x12\x3a\x89\xfa\x9b\x8b\xee\xf9\x1d\x96\x5a\xf2\xf4\xa1\xa5\xbd\x5d\x2e\x2a\xaf\x46\xd5\xc9\x4b\x77\x09\xcd\xd3\x8d\x05\xfe\xee\x4b\xfb\x76\xa3\x59\x07\x7c\x16\xbc\x4b\xe9\x11\x6e\x69\x00\x12\x71\xcd\xa5\x65\xbc\x19\xbf\x47\xd4\xf9\x86\xbd\x9c\x0d\x18\x4c\xd8\xa3\x52\x0c\xa1\xbd\xb4\xb5\x05\xaa\xf7\xcb\x4e\xc9\xf9\x47\x89\x77\x9d\x30\x71\x4e\x79\x11\x6d\xd5\x01\x9d\x59\xb2\x8b\x17\xda\xd9\x6f\x4e\x21\x55\xad\x9c\x61\x27\x4a\xdd\xc6\xb6\x38\x10\x95\x04\xe9\xed\x19\xf4\xed\xa5\x37\x77\x62\x64\x8c\x40\x98\x22\x4e\x33\x91\x04\x3e\x4c\x2a\xd5\x91\x65\x4c\x9e\x7f\x97\x4e\xfd\xf0\xb0\x50\x4b\x6f\xa5\xf6\x46\xce\xcf\x44\xcd\x37\x24\x12\x37\x25\x05"}, -{{0x51,0x51,0x61,0x74,0x21,0xaa,0xdc,0x9c,0x95,0xa4,0x42,0xb4,0x5e,0x7f,0xf6,0xde,0x06,0xa2,0xc7,0x33,0xb8,0x5b,0xd7,0x89,0xfb,0xad,0x41,0x4e,0xe3,0xc9,0x1a,0xdd,},{0x14,0x94,0x1d,0x55,0x97,0x61,0xb3,0x0a,0xb0,0xa8,0x6d,0x47,0xe0,0xf7,0xd1,0x89,0x6b,0x33,0x78,0x45,0x27,0xc8,0x0a,0xf4,0x1c,0xb8,0x48,0x10,0xcb,0xff,0x9d,0xbf,},{0xfa,0xe4,0x77,0x3b,0x33,0x44,0x60,0xc7,0x7b,0xf0,0x1e,0xc6,0x36,0x6c,0x4f,0xe6,0x1c,0x0c,0xab,0x57,0xd8,0xa4,0xb0,0x39,0x09,0xc6,0x19,0xe1,0x1e,0xe3,0x46,0x1c,0x13,0xfa,0x21,0x57,0x6f,0x63,0x87,0x0e,0x42,0x3d,0xd0,0x41,0x81,0xe4,0xa7,0x01,0x3a,0x75,0x24,0xf2,0x46,0xfe,0x33,0x85,0x3c,0x67,0x41,0x62,0xa7,0x81,0x51,0x04,},"\x21\x6e\x9d\x40\xbc\xdc\x3b\x26\x50\x18\x8d\x12\x1c\x9f\x8e\xf2\x9e\x91\x4f\xac\xd0\x22\xfe\x01\xb9\x0e\xd1\x12\x25\xf2\xeb\x93\x53\x8e\x5f\xce\xe5\xab\x80\x45\xe9\x19\x9a\xa7\x6a\x16\xbd\xd0\x61\x68\x05\x66\x0e\x24\x7f\xec\xd7\xe2\x28\x21\xb6\x9b\x1f\x8e\x8a\x58\xac\x3f\xb8\x56\x91\xd7\x5d\x59\x57\xa1\xda\xf5\x3f\xf9\xee\x64\x76\xd7\xc4\xbc\x54\x1e\x6a\xd3\x8e\x3a\x34\xea\x90\xfc\x52\xa4\x8b\x93\x99\xf9\x2d\x17\xc9\xbb\x0d\x7f\xc3\x10\x4c\x55\xd0\xef\xb4\xea\x5b\x83\x1f\xf9\x49\x0b\x3f\x79\xf4\xd9\xd6\x99\x59\x4b\x74\x15\x66\xf2\xb5\x0a\x8f\xc7\x8c\xc4\x03\xfa\x40\xf5\xab\xb6\x63\x8a\x32\xf4\x49\xa8\xb3\xef\x02\x9c\x40\x2f\x46\x93\x1a\xd2\xbd\x3e\x8e\x68\x31\x08\x71\x4c\x98\x9a\xe2\x16\x89\xe9\xc4\x44\xb9\xf5\x5b\x81\x11\x9b\xb5\x03\x5b\xcf\x73\xe9\x7c\xe4\x3a\x22\x18\xc7\xbc\x3e\x43\x0d\x1e\x81\x4f\x34\xde\xe0\x57\x26\x5d\x31\x94\xb9\xf4\x38\x75\xd8\x38\x1f\x52\x5f\x78\x57\x6e\x64\xce\x69\x25\x84\xfa\xa3\x0f\xb7\x43\xa1\x2d\x1b\x77\x61\x4d\x2e\x10\xa6\xb8\x56\xb5\x2b\xe2\x7c\xdb\x63\x0b\xa1\xf0\xd3\xa6\xf8\xea\x98\x44\x54\x2e\x58\x4e\xa0\xa2\x77\x75\x27\xd0\xc5\x2a\xca\x94\x9a\xac\xda\x45\xad\x83\xd1\x6d\x5c\x83\xd6\x63\xad\xb7\x9c\xad\x6f\x3e\x39\xe9\x90\xfe\x28\x2a\x14\xc3\x53\xaa\x23\x79\xd7\xf0\x6a\xda\xb7\x4c\xea\x02\x1b\x89\x83\xa5\x7f\x1d\x0c\xf7\x03\x29\x2e\xb0\x5e\xce\x89\xc5\x3f\x3a\x12\x65\x61\x0e\x0c\x1e\xa8\xdd\xd4\x44\xd1\xff\xd6\xbc\x3d\x03\xf0\xa6\xe4\xd0\xdf\x5c\x5b\x8d\xc1\xf9\x5d\x9f\x55\x58\xb1\x18\xaf\xe6\xbe\xa0\xf6\xc2\x93\x13\x63\xf0\x3a\xb3\x4e\x75\x7d\x49\x36\x41\x74\xf6\x58\xef\xbb\xf3\x8d\xc1\x77"}, -{{0x38,0xbe,0xd4,0x45,0x55,0x6d,0xe7,0x44,0x82,0xbf,0x5f,0xec,0x05,0x06,0xf9,0xaf,0x33,0x0b,0x15,0x1e,0x50,0xd4,0x77,0x4d,0xfe,0x85,0x91,0xd7,0xb7,0xe0,0x27,0x6b,},{0x4c,0x0f,0x9c,0x49,0xa4,0x2f,0x40,0x47,0xbf,0xe6,0x88,0x55,0x51,0xc5,0xe4,0xb8,0x56,0xcf,0x77,0x1a,0x67,0xaf,0x3f,0x89,0xdb,0xf6,0x02,0xf9,0xdb,0x92,0x20,0xf3,},{0xf7,0x02,0xd0,0xd4,0x63,0x28,0x2f,0xc7,0xfd,0x5f,0x8f,0x90,0x29,0xb8,0x9c,0x62,0x6c,0xaf,0xd8,0x34,0x50,0xc3,0xbb,0x9d,0xd8,0xf6,0x58,0x9f,0x0c,0x4b,0x4b,0x71,0xf6,0x49,0xea,0x21,0x2e,0x5e,0x33,0x48,0x7c,0x59,0xc1,0x68,0xea,0x3a,0xd8,0x31,0x50,0xf1,0xfc,0xdf,0xe8,0xc5,0x3e,0xba,0x65,0xad,0xc2,0x02,0x3c,0x25,0x83,0x0f,},"\x0f\xf0\x03\x1d\xf0\xbe\xef\xf3\x71\x0c\x6b\x76\x3f\x9b\x8e\xc8\x17\x19\xbf\xa1\x52\x8c\xe4\x65\x19\xad\xf3\xd3\x41\x2d\x93\xfb\x18\x8f\xd4\x97\xd5\xd1\x70\x91\xc0\xf0\x34\x59\x60\xdd\x0e\xb0\xc0\x9f\xc4\x00\x51\x73\x66\x5d\x4d\x97\xf9\x5c\x13\x82\x8b\xc7\x6b\x34\x92\xb8\x7a\x4b\x64\x25\x3c\x8b\x5f\xa4\x7a\xa7\x5f\xa3\xb8\x6d\x5a\xbe\xea\x8d\xe5\x95\x9a\x60\x22\x89\x13\x6f\x60\xa6\x9b\x30\x9e\x77\x3b\x22\x55\xcd\xe1\x9e\xd2\xa2\xe1\x99\xc3\x3d\xb1\x1c\x16\xad\xe0\x8a\x31\x97\x50\xb8\x51\xd9\x2c\x69\x29\x24\xfc\x98\x59\xbe\x52\x34\x31\xcb\xe7\x8e\xc0\x92\xdb\x11\x29\x21\x0e\xbb\xea\xa7\xc2\xa2\xc0\x00\xee\xb1\x05\xca\x03\x01\xa4\x8f\x3e\x45\xfd\xfb\x15\xb2\x75\xcb\xab\x83\xca\x5c\x99\xd7\x37\xa5\x85\x32\x0e\x9e\x3b\x31\x71\x79\xbd\x86\x46\x7f\xa9\x69\x4f\xcd\xb2\xac\x6a\xd3\x6e\xd7\x14\x48\x43\xdb\xc3\x4e\x42\x3d\x35\xaf\xd7\xd8\x97\x2a\x1c\x43\xc1\x99\xa1\x91\xab\xd6\xce\xba\x49\x36\xd3\x95\xc9\x95\xa3\xeb\x13\xcb\x05\x7f\x88\xa9\xdc\x94\x90\xfe\x98\x84\x5e\xe5\xd2\x6a\x89\xfb\x64\x2a\x2a\x51\x6d\xc3\x05\x6c\x54\xd3\x63\x72\x13\x36\x3a\x86\x28\xa4\x2a\x39\x5d\x94\x2b\x95\x4a\x89\xe8\xef\x7a\x74\x4d\x8a\xe5\xad\xac\x88\xc6\x16\xef\xaa\x90\xe2\x07\x72\x05\xa6\x0b\xaf\xfe\xde\x5c\x87\xbb\x14\xde\xad\x30\x62\x29\x49\x5f\x69\x8f\x3e\x49\x06\x16\x96\x6b\x16\x36\x38\x7d\x0d\x86\x18\x3f\x94\x5b\x24\xa9\xdc\xfc\xcf\x4d\x36\x72\x2c\xd1\x2e\xbb\x6b\xd8\xe7\x83\x25\x75\x2a\xfa\x2b\x1a\xbd\x13\xc4\xbd\xbc\xad\xd1\x70\x86\x91\x36\x82\x62\x42\xac\xfb\x72\x1d\xe5\xff\x27\xba\x8a\xa0\xc0\x18\xb2\x25\xed\x34\x04\x80\x3c\xe9\xfa\x2d\x50\x8d\x89\x44"}, -{{0x05,0x54,0x60,0xb3,0x2d,0xd0,0x4d,0x7f,0x4b,0x23,0x11,0xa8,0x98,0x07,0xe0,0x73,0xfd,0x55,0x65,0x65,0xa4,0x77,0x18,0x57,0xd8,0x82,0x79,0x41,0x30,0xa2,0xfe,0x5d,},{0x26,0x0f,0x8f,0xed,0x4b,0xba,0x30,0xb9,0xe1,0x2a,0xd8,0x52,0x3f,0xbb,0x6f,0x57,0xf0,0xa7,0xa8,0x82,0x55,0x00,0x61,0xf1,0xda,0x46,0xfb,0xd8,0xea,0x44,0x22,0x21,},{0x23,0xf4,0xf1,0x62,0x7f,0xba,0xbd,0x78,0x91,0xd7,0xd8,0x48,0x96,0x31,0xc7,0x23,0x1d,0x22,0xde,0x71,0x86,0x4e,0x26,0x2a,0xb4,0xda,0x84,0xea,0x8a,0x13,0xa6,0x0f,0xea,0xc4,0xdc,0xfb,0x18,0x12,0xf1,0x20,0x04,0x44,0xb7,0x75,0xf1,0x21,0xd7,0x26,0x6d,0x75,0x5c,0xe9,0xb6,0xa9,0xad,0x79,0x65,0x59,0xc0,0xa2,0x6b,0x51,0x6d,0x02,},"\x74\x07\xf9\x6e\xe3\xe7\x9c\x69\xd3\x6c\xe1\xf6\x4e\x4f\x18\x86\x55\xea\x68\xb9\x47\xe7\xe2\xbe\x97\xb0\x5e\xbc\x6d\x44\x39\xe9\x50\x27\x6e\xf3\xf0\xe6\xa0\x3d\xd4\x8b\x24\xf6\x69\x29\xb4\x9c\x15\x80\xeb\x46\x88\x07\xe1\xe7\xa2\x5e\xb9\xb9\x4d\xa3\x40\xc5\x3f\x98\x4f\x8b\x81\x60\x3e\xfb\x61\x04\x7b\xf3\xf1\x4b\x68\x6d\x97\x98\x00\x3d\x2f\x68\x58\x9a\x79\xeb\xfa\xd5\x44\x09\xc7\x1c\x90\xff\x67\xc1\x1f\xbd\x76\xcc\x72\xc2\xd1\x45\xf4\x58\xe4\x2f\x88\xb7\x5d\x25\x0e\xad\xca\xfe\x66\xbf\x37\xff\xc8\x37\xb6\x2f\xf0\x06\x68\x5b\x7f\x85\xa9\xd8\x75\xfc\x07\x8c\x82\xe6\x1f\xe3\x5d\x19\x22\x52\x7a\x55\x1d\xab\x62\xf9\xe4\x77\x49\x91\x46\xba\xd9\x12\x20\x3e\x66\x4c\x41\x7c\x36\x79\xc0\x2d\x87\x2a\xba\xc0\x03\x2f\x8c\xc7\x7f\x77\xbf\xe5\x4d\x33\x26\xfd\xee\x92\x76\xa4\x8e\xa4\xeb\x25\x13\x50\x40\x68\x82\xd0\x8c\x83\x0e\x76\x49\xfe\x68\x54\x55\x8a\x75\x13\xab\x2d\x8d\x2a\xc3\xe5\xce\xd8\xa8\x08\xd2\xae\xe4\x54\x77\x9e\xda\xbd\x1a\xa6\x3b\xb1\x9f\x71\x8f\x47\x0b\xdc\x84\x51\xcd\x9b\x29\x49\x41\xe3\x49\x70\x63\xb1\xe3\x9b\x6c\xa1\x84\x56\x2f\xe8\x38\xcb\xfe\xee\x92\x2d\xe2\x4d\xdf\xcf\x98\x82\xc5\xe6\x15\xb1\x1b\xf9\x04\x81\x7f\xbd\x64\x71\x39\xdb\x80\xb4\xe8\xfe\xb3\x7f\x11\xe1\x85\x2d\x7e\x87\x6d\xb9\xcb\x63\xc9\x4d\x7e\xe3\x41\x92\xf7\x20\x0b\x5b\xc7\x7a\x03\x11\xae\x43\xb8\x06\xeb\xd4\xc2\x89\x6c\x53\xf5\x8f\x7e\xbc\x16\x25\xcb\x20\xd7\x10\x7e\xf9\xdb\x0d\xa2\x87\x88\x52\x3d\xe9\x91\xef\x6c\x58\x66\xb1\x8d\x8d\xe8\x3a\x95\x4d\x32\x81\xe0\x6d\xbf\x27\xc4\xf2\x38\x2e\x08\xcd\x0e\x0f\x6e\xba\xe3\xf9\x61\xb7\x7f\xce\x5a\x95\xa9\xb0\x62\x1b\x75\x6f"}, -{{0xe9,0xf6,0xd3,0x1b,0x93,0x69,0x42,0xc5,0x26,0xe0,0xf9,0xec,0x4f,0x5a,0x7a,0xc2,0x5f,0xa7,0x89,0xe0,0xc4,0x34,0xbc,0xd9,0x19,0x9d,0x72,0x0c,0x74,0x3c,0x84,0xc4,},{0x32,0x12,0x6d,0x26,0xe2,0x82,0x31,0xc5,0xb5,0x85,0xb1,0x3f,0x43,0xa0,0x1c,0x6f,0xe5,0x42,0x94,0x6b,0x07,0xd3,0xa9,0x1e,0x57,0xd2,0x81,0x52,0x3f,0x5c,0xb4,0x5c,},{0x7e,0x3b,0x1c,0x4c,0x71,0x6c,0x80,0x8e,0x90,0xb9,0x74,0x45,0x89,0x15,0xf3,0xb2,0x23,0x9c,0x42,0x07,0x71,0x19,0xfe,0x27,0x07,0x88,0xfa,0xe5,0x20,0x57,0x8b,0xd7,0xda,0x64,0x88,0x04,0x41,0x32,0xe1,0xbe,0xf2,0x3e,0x3b,0x23,0xc3,0x4d,0x9c,0x18,0x62,0x74,0x4f,0x28,0xfc,0xae,0xcd,0xa6,0xca,0xc0,0xfd,0x72,0xb9,0x3b,0x6a,0x0f,},"\xe8\x81\x33\xf3\xd1\x76\x42\xd5\xc2\x27\x79\xa8\x53\x16\xba\x0d\xf3\x4c\x79\x2b\x4e\xfe\xe4\x9e\xd7\xdd\x93\xca\x33\x22\xef\x47\xc7\x2e\x5b\x2e\x45\x95\xc7\x78\x00\x43\x4b\x60\x71\x9a\xdf\x54\xe4\xc1\xa3\x4c\x89\xfa\x1e\x27\xee\x8d\x35\xa0\x92\x1f\x97\x55\xac\x4a\x77\xa6\xc1\x68\x4e\xa0\xf5\xc8\xee\x5f\x75\x9c\xe5\x9b\xfe\x83\x15\x80\x0a\x67\xaa\x6c\x64\xdd\xfa\xac\x92\xea\xbe\x6c\x2c\x61\x37\x79\x78\x4b\x3a\xff\xaf\xcc\x62\x0f\x2a\x6d\xc5\xcb\x8d\x8d\xc7\xd7\x4a\xa4\xd7\x94\x94\x67\x84\x94\xe5\xe6\x39\x4c\x43\x3c\x14\x80\x9f\xf4\x0c\x9a\x59\x2d\x0d\x69\x4a\x81\x10\x3b\x44\x53\x1e\x1f\x48\xbc\x13\x96\x5d\x15\xaf\x8b\xf3\x34\x04\x88\xf8\xcd\x58\xf0\x9a\xe1\xa6\x61\x6b\xf8\x5a\xc9\xde\x7e\x0c\x66\x96\xaa\x2f\x1b\xec\x15\xe1\x7a\x44\xda\x4a\x84\xed\xb4\xec\x6d\x77\x24\x77\x88\xba\x0d\xe3\xae\x12\xa1\x55\xcb\xed\xc0\xda\x2f\x56\x8e\xef\x0b\x75\xa8\x77\xea\x5b\x0c\x2c\x0d\x4b\xf2\xc6\x1d\x46\x8a\x46\xfa\xad\xfa\xec\xe3\x5f\xc2\x63\xa9\xbe\x99\x87\xf4\xf7\xf7\x8f\x05\xc7\x07\x78\x43\x78\xc7\xb8\xf7\xda\xf9\xac\x3a\x12\x2a\xad\x39\xa1\x67\x79\x66\xda\x9e\xf2\x86\xc9\xe0\x62\xc4\xf4\x39\xad\x0b\xdd\xea\x26\xe5\x4b\x2f\x73\x88\xe2\x38\xb2\xa6\x49\x28\x45\x0d\x34\x56\x4c\x5a\x44\x7e\x7a\xfb\xbe\xdd\x10\x85\xf1\xf2\x4c\x11\xae\x08\x43\x22\xd1\xa3\x2c\xf8\xaa\x47\x39\x41\xf0\x0d\x56\xb1\x61\x82\x13\xca\xb3\x90\x0a\xa6\x06\x46\x3d\x9f\x80\x0e\x92\x6f\x9f\x42\xd4\xb0\x82\xd8\xc5\xec\x3a\x4a\x02\x5b\x45\xf9\xaa\xdc\x8b\xcb\xd1\x70\x91\xb3\xda\x49\xe9\x45\x3d\xc5\x5e\x89\xb5\xb5\xfe\x6b\x31\xf5\xed\xda\xd1\x0b\x66\x01\x57\x25\x68\xd8\xe2\x05\xd3\x25\x1a"}, -{{0x6b,0xf4,0xca,0xaa,0xbb,0x96,0x85,0x4a,0x38,0xa5,0x72,0xf4,0xce,0x6c,0x78,0x38,0xf7,0xe7,0x50,0x11,0x8c,0x73,0xf2,0x72,0x35,0x82,0x61,0x8e,0x23,0x07,0xf8,0x38,},{0x08,0x12,0x63,0x73,0xd0,0x56,0xf0,0x0e,0x54,0xb8,0xd4,0x3d,0x77,0xc3,0x5f,0x5f,0x91,0x98,0x33,0xe9,0x0d,0x8a,0xaf,0xd6,0xc8,0x24,0x6d,0x27,0x91,0x7a,0xd0,0x91,},{0xd2,0x11,0x3f,0x80,0xd6,0xcf,0x92,0x84,0x86,0xa2,0x50,0xa6,0x79,0xd6,0xe7,0x4b,0x35,0xea,0x9d,0x26,0x06,0x1f,0xa9,0x4d,0x76,0x9e,0x1a,0x8f,0xbf,0xa0,0xa7,0x34,0x22,0x7f,0x55,0x53,0x7e,0x4e,0xbf,0xf5,0x93,0x36,0xdb,0x14,0x1c,0xf5,0xd6,0xd4,0x82,0xa0,0x71,0x1f,0x1e,0x9f,0xc7,0x2f,0xf7,0x09,0x56,0xa1,0x1b,0x4f,0xb9,0x09,},"\x47\x76\xe9\xd6\x00\x85\x48\x1f\xa5\x37\xbf\x29\x5b\xda\xbd\x8b\x1c\xf6\x32\xa8\xcd\x40\xbc\xe6\xbd\x32\x5c\x12\x9f\x97\x70\x00\xe8\x84\x68\xeb\xf2\xdc\x15\x8a\xc0\xf2\x07\x21\x2d\xb0\x0f\xb6\x0b\x8e\xc8\xba\xe2\x29\x37\x2e\x9a\x6b\x01\x53\x0a\x7e\xd1\xbc\x9d\x38\x9e\xc8\x91\x3f\x59\x03\x0d\x5b\x54\xaf\x56\xae\x1c\xcc\x28\xf3\x7c\xc9\x6a\x8e\x53\x20\x4e\x92\xa6\x77\x76\x6a\xdf\xaa\xda\x99\xb0\x28\x1f\x86\x7f\x61\xac\x9f\xf7\xd9\x72\xee\x3e\xd4\x27\xd7\x2f\xaa\xe7\x5d\x4a\xec\x01\xb5\xff\xc3\x70\x61\xb6\xf0\xf7\xe5\x71\x4c\x4c\xf3\x0d\x5b\x73\x1b\x07\x46\x06\x5f\x19\xe4\xc8\x92\x2d\xde\x64\x2f\x80\xfe\x24\xa3\xc8\xdc\xb2\xe5\xf1\xc2\x66\xe2\xaf\x6c\x37\xde\xcf\x55\xa2\xba\xa5\x4f\x0d\x5c\xf0\x83\x93\x70\xc3\xe0\xb4\xe7\x7a\x4f\x36\xbb\xb3\x16\x20\x14\x93\x3a\x4a\x4e\xbc\xae\x8c\x60\x96\x1a\xc6\xdc\xf1\x34\xf3\x08\x28\xd3\x14\x02\xae\x74\xe7\xe8\x51\x3c\x9d\x2a\xd8\xee\x46\xb7\xa9\xd5\x3a\x1f\x87\xeb\xfc\xe0\x4f\x46\x1b\xde\xd1\x74\x9b\x6f\xc4\xc4\xf2\x57\x93\x52\x56\x92\xd7\xa0\xe4\x26\xc8\x4e\x06\x08\x2c\xc3\xe6\xab\xb5\x13\x68\x37\x0c\xbb\x10\x6c\x7a\x08\x97\xf6\x6d\x92\xc9\x73\x9c\xff\x9f\x27\x06\xd6\xa2\x98\x0e\xce\xa3\xac\x49\x45\xf0\xf4\x7e\x65\x6b\xd9\x63\x77\x77\xe8\x53\xd2\xa8\x39\x10\x43\x27\xdc\x04\x9e\xbc\x34\xf0\x49\xd6\xc2\xf8\x0e\xca\x99\xdb\x7b\x41\x84\x24\xac\xef\x75\x22\x60\xd2\xd4\x27\x94\x93\x23\x99\x7c\xd9\x61\x7e\xdf\x50\xd4\x41\xd0\x08\x8b\x1d\x47\x91\x2e\x35\xcf\x54\x23\x15\x26\x58\x29\xf3\x83\xf4\x58\x60\xd3\xb4\x5e\x73\x5b\xb2\xf8\x58\x6d\xcf\x58\xdb\x4f\x2a\xcf\xb4\xa6\x88\x53\xa9\x6e\xed\x7b\x89\x76\x9d\x36\x56\x13"}, -{{0x5d,0x95,0x85,0x73,0x6a,0xb2,0x09,0xb0,0xab,0xe8,0xbf,0x74,0xac,0xa4,0xee,0xa4,0xf6,0xd1,0x65,0x0b,0x53,0x25,0x50,0xa2,0x23,0xe0,0x44,0x58,0x0f,0x8e,0x20,0xde,},{0xe7,0x77,0x29,0xed,0xfd,0x21,0x44,0xb2,0xb1,0x20,0x78,0x76,0x54,0x17,0xfa,0x21,0xf1,0x59,0x4f,0x09,0xb2,0x69,0xe9,0xb6,0x70,0x68,0x02,0xb4,0xf3,0xbd,0xfe,0x85,},{0xe7,0xb0,0x8e,0x1d,0x58,0x09,0xfd,0xd8,0x52,0x94,0x43,0xd6,0x5a,0xda,0x5d,0xd6,0x55,0xea,0x55,0xb5,0x41,0x5a,0x01,0x13,0x93,0xbe,0x70,0x71,0x67,0x64,0x86,0xd3,0x58,0xe8,0xd2,0xa4,0x60,0xeb,0xe0,0x75,0xb0,0xe7,0x01,0xb2,0x4c,0x9e,0x3a,0xb5,0xf2,0xb0,0x33,0x59,0x2d,0x4d,0xe3,0xb7,0xf3,0x7f,0xd5,0x41,0xf6,0x92,0x09,0x09,},"\x08\x69\x35\x91\xe6\xc5\x8a\x5e\xad\x9c\x85\xfe\x8e\xc5\x85\x08\xf8\x1a\x34\x67\x63\x6c\x2d\x34\xfc\xc1\xf4\x66\xe5\xc6\xda\xfd\xc3\x7c\x35\xcb\xee\x35\x58\x9c\x69\x97\xe2\xb1\x54\x48\x13\x27\x44\xe5\xa1\xe1\x31\xbb\x49\xbf\x5c\x25\x63\xf8\x7e\xad\x3e\xfe\x01\xe8\x8c\xbf\x24\xcc\x17\x69\xc7\x8c\xdf\xc1\x67\xe3\x78\x21\x5b\x15\x85\x9c\x7a\x28\xec\xe7\x0e\x18\x8f\xa3\x30\x26\x7d\x3f\xc5\x7b\x4a\xce\x6c\x15\x20\xec\x67\x87\x50\x67\xfd\x33\xbe\x86\xf4\xa1\x96\x7a\xfb\x3e\xb1\x64\xc7\x97\xcf\x28\xd8\x07\x2a\xa6\x9d\x82\xaf\xa3\x83\x74\xf8\xe5\x79\x7c\x4c\x28\x47\x1b\x7d\x69\xf5\xb9\xc7\xb4\xac\xdb\xc1\x9f\x3c\x5c\x5d\x40\x08\x08\xa9\x82\xa4\x78\x37\xae\xd1\xb3\x84\x1d\x69\x89\x0e\xeb\x31\x49\x4e\x10\xe3\xe5\x13\xd1\x2d\x0c\xa6\x86\xc7\xce\x65\x17\x78\x09\x27\x03\xfe\xf0\xdc\xc0\x21\x40\x77\xdf\xb3\x61\x25\x1b\xde\xa4\x36\x4d\xd4\x1b\x97\xbc\xeb\x0f\xb1\x47\x5a\x50\xe4\x70\x8f\x47\xf7\x87\x8c\x74\x40\x1e\x97\x71\xcc\x3f\xce\xac\xe8\x91\x69\x98\x1a\xa7\x72\x50\x85\x00\x90\xd1\x81\xd8\x35\x8e\xbb\xa6\x5e\x29\x0a\xcb\x03\x52\xbe\xce\x8c\x57\x98\x32\xa6\x01\x55\x18\x16\xd1\xc0\x56\x21\xcc\xbb\xee\x0f\xbe\x39\xea\x2f\x19\x53\x93\x19\x9e\x69\xc2\x34\xc2\xfb\x1c\x37\xe4\x74\x84\x08\x60\xce\x60\x91\x61\xfc\xfc\xe2\x86\x95\x74\xbe\x0d\x38\xf9\x5e\x20\xf4\xf8\x72\x52\x47\xb9\x62\x7b\x46\xe8\x34\x90\x51\x01\xac\x12\xb9\x34\xcb\xf8\x7c\xb2\xd1\x90\xd2\xf5\x14\x90\xa8\x2c\x4e\x81\x0e\xdd\xb8\x1f\x95\x6a\x9f\x36\xbd\xa4\x97\xbc\xa5\x06\xa4\x9e\xe9\xcd\x47\xfd\xa5\xb7\xf2\xb8\x84\xa3\x64\x8c\xad\xd1\x2a\xb6\x18\x98\xad\xa4\x6e\xcc\x97\x0f\x81\xdc\x9f\x87\x68\x45\xdb"}, -{{0x60,0xb1,0x42,0xf1,0x65,0x11,0x41,0x43,0xca,0x30,0xa6,0x04,0xfe,0xf5,0x1c,0x68,0x64,0x36,0xaa,0x1b,0x9a,0xfd,0xb2,0x66,0xb3,0xe3,0x98,0xcc,0xb3,0xc4,0xd8,0x55,},{0xea,0xf6,0xc5,0xa7,0x6c,0xa9,0x9b,0xf7,0x30,0x64,0x98,0x88,0x8c,0x3b,0x7a,0x1f,0xea,0xe9,0x8b,0xf8,0x98,0x8d,0x7f,0x2e,0x15,0x47,0xf8,0xf5,0x3a,0x45,0x28,0xaa,},{0xa6,0x21,0xf0,0x84,0xea,0x1a,0x36,0xef,0x81,0x2a,0x97,0x55,0xc9,0xaf,0xbb,0x53,0xda,0xda,0xae,0x6b,0x3a,0x53,0xfa,0x83,0x44,0xca,0x40,0xd3,0x61,0x2a,0x26,0x8a,0x35,0xfe,0xd0,0xfd,0x39,0x8a,0xb7,0x5b,0xcd,0x63,0x9c,0x54,0x79,0x37,0xc9,0x41,0x55,0xab,0x1a,0x7a,0x34,0x67,0xdd,0x4b,0xfd,0xdf,0xac,0xab,0x16,0x55,0xe9,0x08,},"\x18\x15\xde\xe1\x17\x3b\x78\x26\x47\x20\xd3\x5b\x7c\xc2\x45\x4a\x00\x0a\x65\xff\xf2\x14\xe2\x47\x3e\x20\xbc\x83\xf3\xec\xde\x9c\x04\xc1\xe0\x69\x6c\xe6\xe5\x55\x19\xdd\x2a\x75\xce\x04\x64\xbf\x60\x1a\xdc\x38\x1e\x79\x3e\xcb\x9f\x8c\xe7\xab\x87\xb6\xca\x2a\x3e\x41\x0f\x63\x90\x69\x45\x19\x78\xd1\x48\x73\xd3\x39\x0f\xab\x86\x23\x96\x97\x13\xc3\xdf\xcd\x58\xd8\x6d\x12\x40\x73\x76\x1e\xe0\x9a\x65\x2a\x48\x76\x7f\x96\x46\xcb\x72\x6a\xc4\x54\xac\x9a\x1b\xc5\xfa\xed\x30\x26\xb7\x03\x98\x2b\xc2\xb1\xe0\x75\x82\x10\xe1\xd6\x25\x19\x23\x0e\xb2\xb2\xf4\xa4\x86\xbc\x55\x16\x85\x60\xc4\x36\x3d\xf5\xff\x5a\xdf\xda\x11\xac\x7e\xf5\x1b\x18\x19\x6c\x94\x33\x7c\x07\xae\xf1\x17\x99\x0f\x77\x0c\x0f\x1e\x8c\x0f\x88\xeb\x6f\xfc\x40\xe8\xed\x7c\x3a\x80\xa6\x32\xdb\x1e\x7f\x63\xb6\x30\x96\xe2\xac\x49\xe5\x77\x92\xb3\x11\x43\xe2\xf4\xfa\xab\xce\xae\x66\xb2\x74\x71\x68\x1c\x36\xfc\x11\x39\x00\x7f\x9b\x54\x8c\xdc\x6e\x3b\x8f\xbb\xda\xba\x7a\x8a\xdb\x84\x34\x31\x23\x8b\xb4\x61\xba\x24\xf6\xe0\x9f\x62\xc7\x2d\x63\x77\xb4\x04\x8c\xb0\x13\x4c\x25\xa5\x41\x1a\x20\xbf\xcf\xc1\x3e\x48\xd8\x0e\x36\xbf\xb0\xda\x7e\x01\x85\xd3\x3f\x19\x28\x63\x6e\x15\xde\xe0\xe5\xdf\x89\x92\xa1\x65\x72\xb1\x3e\xa8\xf7\xcf\x85\xca\xe3\x2d\x52\x9f\x66\xe8\xf6\xd2\xfb\x2a\xd0\xbb\xfe\x71\x99\x16\x9b\x25\x67\xba\x00\xc7\x81\xb2\x0a\x48\xe1\xd7\x0d\xf9\xfa\x31\x19\xcd\x7e\x5b\xbe\x58\x88\x4b\x0b\x51\x21\x89\x40\xfa\x81\x5f\x85\x62\x5f\xa2\x03\x47\x1c\xee\x80\x84\x78\x0e\xb0\xb9\x35\x6f\x9f\x3d\x4f\x6d\xf7\x40\x30\x1d\x70\x7e\xf1\xff\xb3\x51\x9e\x3f\x90\xb8\x06\x4b\x98\xe7\x0f\x37\x5d\x07\x14\x26\x88\x17\x18"}, -{{0x73,0x4b,0xa4,0x70,0x33,0xc6,0x14,0x02,0x32,0xdd,0x4a,0x7a,0x14,0xf1,0xa7,0x74,0x3e,0xef,0xe9,0x07,0x0b,0xad,0x96,0x62,0x49,0x16,0x30,0xcc,0x9d,0x28,0xc1,0xf3,},{0x2f,0xa5,0xdf,0x30,0x26,0xd6,0x07,0x42,0xe2,0xaf,0xf6,0xb5,0x78,0x42,0xc7,0x12,0x68,0x46,0xc8,0xa7,0xbb,0xe9,0x26,0x6e,0xfa,0x7b,0x3f,0x23,0x98,0xc3,0x57,0xea,},{0x9b,0xd0,0x74,0xd1,0xd0,0xbd,0x28,0x00,0x1b,0xaf,0x7d,0x2d,0x4e,0x82,0x43,0x5d,0xf0,0x8c,0x42,0x64,0xd8,0xcb,0xb1,0xc3,0x81,0x18,0x3c,0x2f,0x01,0x22,0x3f,0x79,0xf9,0x49,0x23,0xca,0x17,0x8c,0xac,0x75,0x56,0x4e,0x16,0xc7,0xf5,0x60,0x79,0x08,0x8f,0x7e,0xd8,0x85,0xde,0x4d,0x50,0x9f,0xbc,0x78,0xf4,0x38,0xfb,0xa3,0xf6,0x07,},"\x5d\x3c\x65\x98\x10\xc3\xfe\xa5\x2a\x6d\xf3\x86\x1e\x5c\xdc\x5b\x70\x3c\xc1\xce\xf4\x85\x58\xc6\x1d\x8c\x51\xd0\xed\xea\x5a\x14\x79\xcf\xe5\x06\x3d\x82\xde\xd9\xca\x68\x1e\x57\x48\x88\x7c\x40\xec\xfb\x9e\x1a\x9a\x8b\x7f\x85\x09\xd1\x07\x76\x46\x1c\x39\x23\x39\x96\x93\xa7\x81\x89\x08\x91\x78\xd5\xaa\xbd\x15\xf8\xc8\x46\x64\x2b\xe4\x7d\x6d\x4c\xaf\x13\x82\x4e\xdc\xef\xb8\x09\x86\x8f\xa7\x2d\xdf\x03\x5c\x4d\xe8\xef\x0a\x9c\x83\x22\x64\xf6\x6f\x01\x27\x61\xce\x69\x55\xbc\x3c\x41\x6e\x93\xe2\x91\x88\x02\x5e\xbb\xb1\x3a\x55\x32\x58\xc1\xd7\xc4\x99\xc9\xa4\xae\xb1\x0b\xb3\x6f\x61\xd1\xbb\x4c\xec\x5a\xe5\x5d\x17\x57\x22\xb9\xa9\x69\x6d\xf8\x81\x95\x1e\x35\x20\x0b\x96\x53\xcf\x6e\xd4\xb3\xd1\x5d\xe0\x87\xa9\xd1\xc3\x19\xfc\xe8\x58\x21\x56\xbe\xbf\x3f\xc9\x1e\x0e\x61\x0f\xf7\xa1\x53\x08\xfd\x1d\x2c\x60\x69\xfb\xbb\x29\x47\xd3\x11\x07\x31\xd2\x45\xae\x29\x63\x01\x4b\xd7\x6d\xea\x42\xdb\x12\x5c\xec\xc4\x93\xc8\xe9\x09\x1a\x76\x64\x65\x77\x72\x9a\xed\x49\x66\xfc\xe9\x69\x9f\xe1\x2e\x36\x7d\x66\x5d\xf9\xe9\x5a\x91\x93\xe1\x13\x3e\x14\x3a\xf9\x2f\x82\xb6\x6a\xc7\x76\x4e\x50\x33\x17\x86\x90\x52\x18\x09\xa7\x10\x7d\x8a\xe9\xb8\x8e\x0e\xd1\xf3\x5b\x17\x19\x90\x1b\x93\x0a\xd0\xe1\xcb\xce\x7f\xb3\x02\x67\xb1\x15\x52\x04\xf6\x05\xf5\x25\xe4\x9d\xe2\x98\x8e\xa7\xf7\x4b\xe8\x81\x51\x77\xfd\x97\x6a\x1b\xcc\x12\x6d\x9c\x9c\x13\x5c\x5b\x42\x76\xd3\x80\x19\xc3\x4a\xef\xb7\xa0\x22\x0f\x7f\x5a\xef\xf3\x80\xae\xd6\x27\xb0\x70\xc2\xc9\xe2\x15\x33\xbb\x35\xc0\x8e\x39\x4c\x85\xae\x25\xe6\x86\x29\x42\x59\x9c\x65\xdb\xae\x59\x77\xa5\x84\xa8\x81\x80\xe0\xc8\xc7\x1e\x5a\x84\x09\xe0\x4e\xf7"}, -{{0x45,0xe3,0x4d,0x0e,0xf4,0xc1,0x96,0xfa,0x6d,0x57,0x2b,0x6b,0x17,0x74,0xb5,0x21,0x8f,0x7c,0x32,0x91,0x30,0x4c,0x13,0x50,0x0d,0xf7,0x07,0x0d,0x90,0xe8,0x03,0x9e,},{0x13,0xa7,0x30,0x4d,0xff,0x42,0x33,0x59,0x17,0x7a,0xba,0xfa,0x5e,0x65,0x08,0xd2,0x67,0x69,0xca,0x99,0xcf,0x8a,0xf4,0x5c,0x38,0x3f,0x3f,0xf6,0x34,0x40,0x60,0x03,},{0xb4,0x2c,0x1f,0x92,0x5f,0x4b,0xac,0xcd,0x12,0x9e,0xfb,0x10,0x9d,0xb3,0x54,0xac,0xa3,0x1c,0x68,0x98,0xf4,0xf4,0x51,0x29,0x47,0x49,0xa2,0x6a,0x6d,0xa1,0x67,0x7b,0xd3,0xa5,0xc0,0x41,0x19,0xe3,0x5f,0x47,0x31,0x9f,0x20,0xcf,0xdf,0xc0,0x8b,0xb4,0x52,0x8b,0x21,0x00,0x9e,0x00,0xbd,0x41,0xeb,0xc0,0xf4,0x68,0x63,0xbe,0xd1,0x0b,},"\x3d\x9e\xd5\xc6\x4b\x75\xe1\x35\xdf\x2f\x5e\x85\x30\x0d\x90\xf2\x1b\x36\x39\x35\xe2\x81\x75\x56\xfc\x93\x11\x75\x1b\xa7\x53\x54\x77\xde\xc8\x35\x6e\xc3\x85\xef\xb8\x2b\x41\x40\x62\xf3\x5b\xb6\xd3\xed\xea\xfd\xe3\x05\xf9\x90\x0a\x25\xe9\x81\x3c\x9e\xe0\x23\x7d\x46\x40\x96\x50\xcd\xcd\xb5\xdf\xa2\x30\x1a\x8e\x26\x47\xf8\xd3\x81\x9d\x86\xf7\xb7\xe3\x07\x0d\x33\x44\x0f\x82\xc4\x05\x4b\x1a\xb5\xed\xeb\xeb\x27\xf9\x5b\x3c\x4c\x6f\xdd\x46\x8f\x21\x60\x0f\x03\xb3\x49\x4d\xa2\x00\xba\xb9\x29\x3c\x38\xd0\x2f\xc4\x40\x48\xe5\x2f\xf5\xfd\x0f\x72\x17\xa0\x4d\x4c\xe9\x12\xa1\x80\xd1\x62\x8f\x36\x82\x80\xb6\x89\x26\x72\xe8\xff\x98\xd4\x62\x9a\xc2\x8b\x60\xc0\x2a\x30\x1e\x6c\x60\x26\xc1\xb9\xe9\xef\x21\xcf\x03\x92\xdf\x22\x50\x08\xd5\xa0\xe0\x28\x4b\x28\x26\x31\xad\x17\x10\xf8\x11\x61\x56\x97\x06\x6c\x98\x29\x65\x19\x94\x8a\x7c\xfe\xd5\xae\xeb\x45\x4e\xe7\xa6\x1c\xc2\x71\xbd\x3d\x49\x9b\xe1\x7d\xf0\x9d\x3a\x0e\x79\x0e\xe6\xb9\xbd\x99\xe1\xb9\x19\xbe\xd4\xa0\x63\xb8\xd1\xa3\x4f\x1a\xfd\x2e\x95\x2b\x9d\xfe\xfd\x77\x09\x69\xc8\xb2\xfc\x37\x97\x7a\xbb\x0f\xee\x63\x17\x25\x3a\x23\xec\xc9\x75\x78\x16\x89\x73\x33\x4c\x8f\x91\x76\x3a\xb9\x7f\x29\xc4\x9b\xae\xee\x7b\x35\xf3\xae\x7f\x5c\xd3\xa4\xa6\xe6\x97\xef\x25\x5a\x3c\x2e\xc0\xc7\x52\xa3\x39\x6f\x69\xf6\x63\xca\x1f\xc2\xb3\x32\xdf\xe6\xc0\xfa\xf7\x8a\xfe\x9c\x68\xd9\x95\x71\xe8\xe8\x96\xc5\x09\x30\x85\xe9\x86\x3a\x27\x64\x8a\x9e\x58\xf3\xa9\xa8\x4c\xbb\xfe\x2b\x41\xca\x36\x33\xdd\x5c\xf6\xe8\x2c\xb7\x7c\xec\xac\xad\x8d\x78\xb3\x53\xf4\x8d\xb4\x2d\x99\xc3\x6b\xca\xd1\x70\xea\x9e\x98\xab\xb2\x78\x8c\x33\xa3\xc7\x06\x26\x8f\x36\x31"}, -{{0x88,0x8c,0xe2,0xec,0xce,0xda,0x9c,0xa2,0xb9,0x48,0xac,0x14,0x43,0xc2,0xae,0xdd,0x75,0x95,0xaa,0xcf,0x36,0xed,0xaf,0x27,0x25,0x5b,0xde,0x7a,0x69,0x91,0xdc,0xc0,},{0x01,0x6e,0x57,0x2b,0x4f,0x98,0x41,0x7c,0x6e,0xe2,0x97,0xab,0xd7,0x84,0xea,0x48,0x22,0x6f,0xf4,0xfb,0xf0,0x05,0x0a,0x5a,0xde,0x88,0x06,0xe7,0x04,0x6d,0x3b,0xa3,},{0x99,0xd8,0x3f,0x14,0x8a,0x23,0x6e,0xbb,0xef,0x1c,0xad,0x88,0xcb,0x3c,0x76,0x94,0xf4,0x98,0x6c,0x92,0x50,0xe2,0x1c,0x36,0x03,0xa0,0xd9,0x41,0xbf,0xf1,0x99,0xcf,0x77,0xd6,0xce,0x99,0xef,0xdb,0x20,0x53,0x31,0x88,0xd6,0x8a,0xd1,0x33,0xde,0x03,0x3a,0x1f,0xb3,0x46,0x8a,0xbb,0x70,0x6d,0x2b,0x8b,0x4f,0xba,0xc0,0x8d,0xfe,0x03,},"\x5c\x80\x1a\x8e\x66\x4e\x76\x60\x76\x0a\x25\xa5\xe1\x43\x1a\x62\x15\x9f\xc3\xf3\xaa\x71\x37\x80\xae\x7c\xbc\xe2\x3b\x85\x64\x78\x27\x99\xbf\x2b\xe4\x81\x7e\xe2\x92\x19\x65\xba\xb7\xe1\xd4\x48\x33\x82\x4c\x16\x28\xd4\x2d\xce\xe3\xe4\x6a\xe4\x2b\x28\x16\xd0\xa4\x32\xa1\xab\x0b\xd2\x1f\xcf\x30\xad\xb6\x3d\x8d\xd7\x65\x69\x54\x43\x43\xd0\x03\x5c\x76\x05\x22\xca\x68\xbe\xa7\x2c\x40\x4e\xdd\xa1\xe9\x09\x5e\xc9\x0f\x33\x25\x68\x1c\x6d\xe0\xf4\xc1\x2d\x1a\xfb\xcb\xa2\xc7\x87\x1a\x1b\x1e\x1f\x19\xc3\x5b\x0b\xed\x9e\xc2\xa8\x7c\x04\x3d\x36\xd8\x19\x39\x6b\xd5\xd0\x99\xe1\xaa\x09\x03\x91\x29\x7c\x73\x3f\x65\xa8\xc5\xd2\x12\x0c\x67\x63\x53\x16\xfa\xb2\x5b\x4d\x48\x47\xa4\x5f\xc3\xf7\x6f\x2e\x24\x26\xdb\xee\x46\x29\x97\x50\x62\xfc\xe1\x4e\x21\x89\xdb\xa2\x7f\xb1\xde\xd2\x45\x3f\x00\x1d\xeb\xfa\xa8\x99\xc1\x16\x60\x61\x2d\x2c\xe2\xad\x2f\x76\x2e\xa5\xde\xe7\xe7\x1e\x58\xad\xcd\xce\xfa\x79\xe8\xe8\xb2\x7f\xc4\xcc\xf8\x9a\xab\xf1\x76\xb5\xd3\x4f\x82\xdd\x15\xd8\x89\xf9\xf0\x87\xdc\x9a\xe8\xa4\x2a\x72\xf3\xb8\x35\x83\x61\x6e\x17\x06\x37\xcd\x1a\xdf\x38\xaa\x65\x51\xcb\xac\xca\x36\x02\xbd\xc7\xae\x21\x0c\x4a\x44\x6b\x3a\xf8\xdb\x27\x20\xe5\x49\xbb\xed\xb8\xbe\xd2\x15\xae\x00\xf1\x9d\xa2\x9d\x8f\xb0\xb6\x42\xd2\x7b\x2d\x88\x57\x5f\x0e\xe8\x4f\x3d\x12\x9e\xb7\x74\xd2\x0f\x53\x7a\x1c\x0f\xdc\xf7\x17\xbd\xeb\xcf\xe4\x7f\x83\x31\xa3\x41\x86\x43\x46\xfa\x6a\x1c\x6b\xbf\xd1\x78\x81\x9e\x38\x7a\x0d\x54\x99\xa6\x8e\x81\xcc\x9f\x82\xad\x39\xe3\x1e\x4d\xfe\x71\x95\x2d\x5e\xa5\xcc\x80\x52\xa3\xce\xed\x17\x51\xf5\x9d\xc7\xec\xc9\x74\x2f\xad\x14\x4e\x18\xdd\xa8\xd0\x58\x2e\x74\xe3\x9c\xa8\xc4"}, -{{0x61,0x73,0x90,0x85,0x7d,0xc1,0x0c,0xdf,0x82,0xb5,0xc9,0x42,0x61,0xf5,0x8c,0xe2,0xd4,0x4a,0xa2,0xf5,0x7d,0x29,0x8f,0x08,0xa2,0xd6,0xc7,0x4d,0x28,0x14,0x7d,0xaf,},{0x89,0xe0,0xc3,0xe0,0xa0,0xf1,0x30,0xd1,0x91,0x6e,0x0e,0x38,0x49,0xb7,0x28,0x6f,0xa2,0xe3,0xac,0x4c,0x17,0xbd,0x1f,0x71,0x6e,0xe5,0xa7,0x2f,0x02,0x57,0xfb,0x8d,},{0x63,0xe9,0x0a,0x6a,0xfb,0xbb,0xb0,0xee,0x69,0x6b,0xfb,0x56,0xef,0xd6,0x79,0xd6,0x8a,0x98,0x51,0xa8,0x94,0x76,0x40,0xa9,0x7f,0x41,0xf6,0x8e,0xdf,0xea,0xdd,0x21,0x6e,0xd8,0x69,0x8e,0x2e,0x43,0xc8,0x20,0xc9,0x04,0x4c,0xaa,0x7a,0xda,0xab,0x5b,0x76,0x76,0x2b,0x68,0x18,0x31,0xa9,0xf7,0x60,0x47,0x6a,0x84,0x43,0xc4,0x3c,0x06,},"\x1f\xd9\xe7\x45\x3e\xaf\xfd\x7c\x9b\x54\x05\x56\x22\xdd\xe1\x70\xdd\x58\xb7\x1c\xb9\x45\xde\x75\x35\x1d\x5f\xce\xb1\xf5\x36\xbd\xe2\x51\x58\xf0\x37\x86\x15\x5f\x95\x3d\xc2\x07\xa1\x70\x8f\x90\xd9\x5b\x15\xac\xa0\xae\xe3\x09\x7f\xdc\xaa\xe8\x5e\x4a\xb1\xc2\xcd\xb7\x05\xc5\x3e\x6c\x2e\xd2\x1a\x99\x4b\x30\x4a\x75\xca\xf2\xce\x4f\xc7\xd6\x1f\x56\x1e\x74\xe2\x97\x39\x7e\x2c\xde\x5c\xc6\x90\x56\x94\x03\x43\xaa\x81\x37\x5d\x0a\xf1\x8d\x17\xd2\xf3\x4c\x0a\x71\xdc\xf1\xde\x3c\x4f\xc4\x88\xa1\x4c\x5f\xa6\xb3\x33\x7a\x31\x74\xb1\xda\x79\x58\xfb\x00\xbd\x59\x55\x14\x82\x21\x42\x7c\x60\xdb\xa0\x41\x17\xc8\x0d\x24\x88\x65\x6d\xbd\x53\x43\xde\x89\x12\x87\xb5\x0e\xf4\xdf\x98\x25\xed\xa7\x6b\x49\x77\xf3\xac\xd4\xab\x6d\x31\x02\xfa\x56\x87\x83\x06\xcd\x76\x56\x14\x91\xbc\xfd\xaa\x1d\xa5\x67\xe6\x77\xf7\xf0\x3b\xae\x5d\xbf\x44\x26\xc3\xc4\xa6\xc3\xd0\x82\xf9\x17\x8b\x2e\xfd\xd2\xbd\x49\xee\xe9\x7e\xf4\xdc\xf3\xf0\xf5\x1b\xbd\xef\xfe\x5a\xe6\x60\x1e\x28\x01\x95\x18\xf8\x27\xf0\x2e\x51\xf6\x67\x9b\x87\x15\x97\x8b\xec\x3e\x69\xd5\x77\x15\x6d\xd7\x19\x95\x93\x71\xba\xf0\x34\x21\x9f\xbb\xd1\x7a\x23\x69\xa8\x54\x14\x90\xf6\xa0\x20\x13\xe3\x3e\x74\xf4\x76\x9b\xe3\x7a\xef\xa4\xde\xfb\x6b\xfb\x3f\x35\x1c\x2a\x26\x14\x82\xc2\xfb\xec\x49\xf8\x5f\x84\x45\x45\x6e\x8f\x5a\x47\x40\x30\xcd\x72\xd0\x95\xef\x6a\x62\x20\x30\xe1\xe4\x3a\x0c\x5d\xeb\xb0\x34\x73\x1d\x2f\x5e\x8e\x4b\xa3\x99\x0f\x07\x7d\x0c\x16\x26\x49\xd1\xfa\x3e\xa4\xfe\x1e\x81\xd7\x4a\xa8\x49\xe2\x1b\x05\x9d\x96\x6c\xba\xd4\xc4\x93\xca\x10\xba\xfe\x7a\x69\x24\x3e\x3c\x0a\x6e\xbf\xd1\x3d\x69\x79\x06\x30\x33\x92\xba\x65\xd4\xfe\x06\xb6\xa5"}, -{{0x87,0x7d,0x01,0x74,0x36,0x36,0x9e,0xc2,0x45,0x3f,0xed,0x46,0xe9,0x77,0xd6,0xac,0xc3,0xa7,0xbe,0x60,0xd3,0x13,0x95,0xad,0x6e,0x7e,0xa9,0xe0,0x74,0x80,0xe4,0xc9,},{0x4e,0x65,0x42,0x2f,0xed,0x33,0x4a,0x55,0xe8,0xb6,0x73,0x89,0x3e,0xba,0x7c,0x18,0x1d,0xd7,0x24,0xdd,0xa0,0x02,0x81,0x7b,0x0b,0xae,0x28,0xac,0xdc,0x3f,0x7f,0xc0,},{0x76,0x88,0xf3,0xf2,0x40,0x1e,0xac,0xaf,0x2d,0xd8,0x8e,0x17,0x0f,0xf1,0xc4,0xd7,0xe9,0x48,0x22,0xa7,0x7f,0x6b,0x55,0x0b,0x56,0x9e,0x82,0x15,0x2b,0xbb,0xb4,0x34,0x05,0x7e,0x01,0x23,0x0b,0x05,0xce,0x58,0xee,0x1d,0xee,0x52,0x26,0xb5,0xc7,0xcd,0xbe,0x5a,0x8a,0xde,0x3b,0x94,0x65,0xf5,0x9a,0xed,0x74,0x14,0x5d,0x14,0x33,0x0c,},"\x4e\xd3\xf5\xbd\xbd\x41\xd0\xe3\xb0\xa8\xa7\xfc\x37\x52\xee\xa4\x96\xd6\x14\x16\x78\xcb\xfe\x06\x75\x7f\x61\xe1\xa1\x68\xd7\x61\xb6\xda\x83\x05\x2f\x79\x94\x95\x0d\x24\x62\x6f\x00\x4f\xbe\x9b\x8c\x95\x62\xe0\xc9\x55\xfb\x3b\x5c\x08\xfd\x2d\x3d\x25\x83\x93\xa3\x49\x03\x0c\x8e\x15\x62\x05\xb4\x04\x83\x03\x8b\xe1\x95\x9f\x1c\xba\x49\x0a\x87\xfe\x13\x89\x9e\x4f\x37\x52\x06\x3b\x68\xfe\x3e\x1c\x50\x71\xf7\xdb\x00\x02\xf0\x14\x94\xb4\xa3\xee\x2e\x07\x99\x2b\xdd\x20\x0d\xb4\x31\x66\x29\xee\x8a\x95\xca\x34\x7f\x0b\x28\xd6\x40\x2a\x6d\xa8\xb5\x3e\x6b\x32\x58\x1c\x36\x91\xe1\x1a\xe9\xb6\xe0\xf0\x49\x48\x94\xe6\x49\xa9\x2d\x03\xeb\x49\xc4\xd6\x83\x3f\xa1\xf5\x4f\x8d\xcd\x91\xd0\x69\x36\xa6\xe6\x2d\x49\x1e\x2c\xea\x46\xdd\x07\xd9\xf0\x2d\x32\x54\xb8\x50\xbc\x97\x49\xf2\x58\xa6\x1a\xd3\xb9\xcc\x24\xb0\x32\x87\x33\x1b\x85\xa2\x41\x43\xaa\xf8\xfc\xcc\xac\x5f\x18\xbf\xc7\x2d\xec\x75\xc0\x23\x35\x16\xaa\x6e\x45\x89\xc7\x8c\x66\x5a\x18\x6e\xd9\x02\x09\x1d\xf9\x7b\x0d\x04\xe8\x3a\x2d\x74\xd7\x89\x89\x1a\xea\x2c\xac\xf8\x13\xff\xfb\x5e\xfa\xf7\x8d\xbc\xd7\xaf\x54\xef\x55\xc7\x7b\x1c\x4c\x8a\xce\x9e\x92\x78\xad\xc2\x3d\x76\xc7\x79\xd6\x4b\x3b\xbb\xd1\xfb\x33\xb0\x98\x36\xea\x64\xa7\x1e\x47\x11\xe8\x9e\x8d\xa0\xf7\x09\x21\x33\x42\x17\x6a\xe2\x2c\x6e\x78\x52\xc3\x97\x3b\x60\xd9\xf9\x88\x89\xb4\x42\xaa\x48\xd7\xbf\xdf\xde\xf6\x4c\x36\xc5\x86\xc4\xfb\x2a\xd2\xe2\x7e\xbe\x47\x9f\x6d\x72\x2f\x06\x9f\xd6\x10\x6b\x0d\x08\x97\x5d\x5f\x72\x15\x47\xc3\xb9\xc5\x2f\x9f\xc5\xf4\x5b\xb4\x5b\x5b\x63\x21\x88\xe8\x06\x26\x51\x8a\x79\x05\x6b\xdc\x4e\xe1\xd2\xbe\x6c\x65\x42\xa2\x1f\xad\xea\x92\xc6\xdf\xb7\x76"}, -{{0x4f,0x0b,0x36,0x07,0xd7,0x0b,0x0f,0x26,0x98,0x32,0x7e,0xf4,0xf1,0x98,0x2c,0x5b,0x4b,0x94,0xbe,0x78,0xf5,0x0c,0x76,0xf4,0x3b,0xd6,0x42,0xf1,0xf0,0xed,0xe3,0x9b,},{0x94,0x2b,0x43,0x08,0x9f,0xd0,0x31,0xce,0xc0,0xf9,0x9e,0x5e,0x55,0x0d,0x65,0x30,0x7f,0xb6,0xc3,0xe7,0x93,0x44,0x9f,0xb3,0x90,0xff,0x73,0x0f,0xff,0xd7,0xc7,0x4b,},{0xf3,0x96,0xa1,0x1f,0x2f,0x03,0xc6,0x14,0x39,0x68,0x4f,0x79,0x00,0x1b,0xd4,0xf3,0x46,0xa3,0x48,0xdc,0xf1,0xd3,0xbe,0xb2,0xd3,0xbf,0xe3,0x3e,0xa7,0x3a,0x5a,0xd4,0xeb,0x97,0x50,0x6a,0xcf,0xbf,0xfb,0x78,0x4e,0x77,0x54,0x81,0x89,0xcd,0x59,0x9f,0x8c,0xcf,0x17,0x35,0x5d,0xde,0x80,0xe7,0x50,0x24,0xef,0x2a,0x78,0xd5,0xfa,0x03,},"\x9f\x70\x0a\x1d\x25\x60\xf6\x9d\x9b\xc1\x05\xbc\x83\xbf\xf5\x39\xe4\x25\x8c\x02\x48\x60\x20\x13\xa9\x59\xb9\x78\xa1\x9c\xc2\x73\x28\x0d\x90\xc0\x17\x80\x89\x57\x8b\x50\x51\x8e\x06\xad\x1e\xab\x79\x0f\xfe\x71\x0c\x63\xd7\x88\x87\xa9\x55\x69\x14\x4f\x3e\x58\xa8\x83\x7f\x93\xdd\x51\x6f\xcd\xdd\x22\xbc\x97\xa7\xf1\x44\x11\xd4\x24\xb2\xe8\xe9\xaa\x7c\x28\x01\x19\xad\x94\xce\x92\x53\x3f\xc7\xfe\xa6\xc6\x62\x48\x64\x4a\xc3\xe1\xbe\xef\x25\x53\xa6\xf6\x1e\x91\xb9\x37\x9b\x0f\xe0\xc6\x8b\x40\x68\x14\x55\xb3\x11\xf4\x0d\xf0\xc9\x7f\x53\xfc\x95\x42\x42\xc3\x75\xe7\x70\x8d\x61\xba\xd9\xf5\x12\x96\x24\x72\x74\xfa\x01\xa7\x32\x8f\xa5\x00\x9d\x99\x95\xf5\x01\xae\x86\x83\x55\x2b\x11\xa4\x9d\x26\x38\x11\x67\x23\xb1\x31\x94\x50\xa9\x01\x38\xd2\x78\xcd\x95\x12\xb8\x0c\xa5\x79\x2e\xd1\x6c\x68\x3b\xef\x92\xec\x87\x88\x4c\x9f\x07\xf1\x37\xdc\x47\xa1\x31\x46\xe5\x11\x06\x5c\x2e\x1b\x4b\x80\xef\xde\x88\xae\x12\xe2\x94\x31\xbe\xb7\xae\xe3\x65\xc1\x6d\x80\x50\x6b\x99\xaf\xa6\xa1\x40\x6e\xdb\x06\x17\x66\x87\x58\x32\xdb\xa4\x73\xe5\x19\xdd\x70\x18\xf4\x02\xeb\x1b\xb3\x01\x4b\x7c\xee\x4f\x02\xe9\x80\xb1\xb1\x71\x27\xe7\xd2\x5d\xfe\x0c\x16\x8c\x53\x44\xf1\xc9\x00\x44\xf8\x27\x70\x7d\xca\x03\x07\x0e\x4c\x43\xcc\x46\x00\x47\xff\x62\x87\x0f\x07\x5f\x34\x59\x18\x16\xe4\xd0\x7e\xe3\x02\xe7\xb2\xc2\xca\x92\x55\xa3\x5e\x8a\xde\xc0\x35\x30\xe8\x6a\x13\xb1\xbd\xfa\x14\x98\x81\x30\x98\xf9\xba\x59\xf8\x18\x7a\xbc\xaf\xe2\x1b\xa0\x9d\x7c\x4a\xaa\x1a\xd1\x0a\x2f\x28\x33\x4a\xb5\x39\x96\x14\x7c\x24\x59\xc0\x1b\x6a\x10\x83\x9e\x03\x01\x12\x3d\x91\xa3\x5c\xed\x7a\xf8\x9a\xfb\xac\x7d\x9c\xf8\xac\x9a\x38\xce\xeb\xef\x83"}, -{{0xb8,0xa0,0x01,0x0c,0x78,0x4d,0x8d,0x00,0x2a,0x31,0xda,0x11,0xd0,0x22,0xd3,0x01,0x88,0xa4,0x19,0x7a,0x1d,0x5f,0x14,0xea,0x4c,0x0d,0xab,0x29,0xa2,0xe4,0x06,0x68,},{0x8b,0xdc,0x63,0xe5,0x0b,0xed,0xe1,0x3c,0x91,0xa4,0x1e,0x4b,0x4b,0x78,0x57,0xb9,0xe5,0x53,0xf4,0x84,0xe3,0xc1,0xec,0x16,0x7d,0xc0,0x4c,0x28,0x1e,0xa8,0x66,0x22,},{0xb3,0xf6,0xcf,0x4c,0x0e,0x0f,0x90,0x74,0xff,0x2c,0x2c,0x47,0xe1,0x63,0x20,0x2f,0x1e,0x9d,0x6e,0xe1,0x17,0xcf,0x75,0x76,0x33,0xe4,0xab,0xe7,0x44,0x23,0xaa,0x70,0x00,0x8a,0xda,0x15,0x09,0xec,0x1d,0xc1,0x17,0xc1,0xc2,0x30,0xe9,0xb2,0x37,0x86,0xf3,0xd0,0xf2,0x9b,0x73,0xaa,0x28,0x45,0x36,0xe9,0x58,0x01,0x06,0xa8,0xa7,0x0c,},"\x5c\x6c\xcb\x29\x8b\xe2\x16\x80\x8b\x81\x1e\x56\xd9\x72\xf4\x56\xb6\x9a\xd3\x95\x94\xee\xe3\x54\x70\x1c\xa6\xb3\xe3\x8d\x1f\x41\xa3\x59\xe5\x51\x2a\xf9\x8a\x3a\x08\x73\x26\x5f\xe5\x19\x1f\x4f\x2e\xca\xf6\x6b\xee\x75\xa3\xac\x0b\x71\xa4\xdd\xf2\xa7\x59\xeb\xdd\xdb\xd8\x8a\x6a\x1c\x6f\xd0\xfc\xf7\xd7\xcb\x92\xa8\x4e\x33\x07\xb4\xa4\xf9\x8c\x71\x0a\xbf\x4f\x55\x3d\xee\x74\xf6\x52\xd2\xac\x64\xbc\x30\xf7\x2b\xf4\x35\x4e\xf7\xe8\x06\xa1\x90\x71\xa0\x51\xbc\xfc\xfb\x27\xe3\x7f\xdd\xd4\x1e\xce\xae\xc1\x75\x8e\x94\x69\x5c\x67\x0e\xf4\xc5\xa5\x90\x21\x78\x32\x9d\xb9\x58\x5c\x65\xef\x0f\xa3\xcd\x62\x44\x9b\xb2\x0b\x1f\x13\xae\xcf\xdd\x1c\x6c\xf7\x8c\x51\xf5\x68\xce\x9f\xb8\x52\x59\xaa\xd0\x5b\x38\xc6\xb4\x85\xf6\xb8\x60\x76\x92\x8d\xdb\x4e\x20\x36\xf4\x5e\x7b\x9c\x6a\x7f\xf2\x4a\xe1\x77\x60\x30\xe2\x57\x68\x25\x01\x9a\xb4\x63\xeb\xf7\x10\x3a\x33\x07\x20\x33\xea\xcb\xb5\xb5\x03\xf5\x32\x66\xaf\xb8\x2f\x9b\x24\x54\xb8\xdc\x05\x7d\x84\xf3\x0d\x9d\x2c\xb7\xc3\xa3\x1a\x7d\xbd\xfb\xa5\xb8\xe4\x92\x31\xc2\x31\x39\x6c\x47\xca\x04\x2c\x8e\x48\xa1\xa5\xe3\xec\x9a\xfe\x40\x20\x59\x53\x90\xf9\x99\x0d\xfb\x87\x4e\x08\x25\xae\x9a\xe5\xe7\x52\xaf\x63\xaf\x6f\xd3\xe7\x87\xe7\x5e\x8d\x8d\xc4\xc6\x63\x02\x27\x7a\xc0\x1b\x30\xa1\x8a\x56\xcb\x82\xc8\xa7\xeb\xdc\x91\x5b\x71\x53\x25\x5a\x1f\xed\xc4\x92\xe4\x96\x60\x26\x2b\xb2\x49\x78\x0d\x17\x3e\x1f\xd2\x0d\x18\xc4\xf6\xb0\xb6\x9a\xa2\xec\xa0\x24\xbf\x3c\x80\xd7\xd5\x96\x2c\xc4\xa1\x29\xa7\x94\x3b\x27\xf3\x3c\xc7\x99\xa3\x60\x45\x54\x12\x75\xa2\xcd\xb9\x2a\x40\xe4\x85\xba\x8b\x73\x7a\x04\xb4\x3d\x29\xc3\xe2\x5f\x76\xcb\x3d\x93\xa6\xb9\x44\x61\xf8\x8f\x56\x96"}, -{{0xef,0xc8,0x6c,0xbe,0x40,0x36,0x3a,0xbf,0xbb,0x2a,0x4b,0x1f,0xcc,0xe5,0xfd,0x60,0x84,0xda,0x96,0xe7,0xe8,0x14,0xde,0x71,0xaa,0xdf,0x9a,0x61,0x8f,0x30,0x36,0x25,},{0x22,0xf2,0x95,0xce,0xe7,0x27,0xd2,0x8d,0x2b,0x93,0x17,0x15,0x3e,0x7d,0x94,0x12,0xda,0x10,0x65,0xc1,0xb1,0x6a,0xe2,0xa2,0x51,0xdd,0x1f,0xb4,0x31,0xc6,0x2b,0x01,},{0xf8,0x81,0x83,0x10,0x22,0x8c,0xa7,0x61,0x11,0x52,0x4c,0xe9,0x4b,0xfc,0xb0,0x24,0x6e,0xa6,0x35,0x08,0xce,0xe9,0x30,0x65,0x92,0xb2,0xf7,0x75,0x48,0xed,0xef,0xcf,0x76,0xbd,0x14,0x54,0x50,0x8e,0xa7,0x15,0x04,0x2c,0xec,0x16,0x9c,0xea,0x51,0x15,0xab,0x54,0x23,0x5c,0xb1,0x09,0x7b,0x10,0x70,0x2a,0xa3,0x83,0x78,0x02,0x8e,0x0c,},"\x9e\x4f\xa4\x5d\xc0\x26\x71\x0f\x6b\xef\x4e\xd0\xf0\x7c\x54\x4b\x0b\xb0\xd8\x8f\xa7\x9e\x71\x77\xd8\x44\x8b\xc2\x09\xd7\x1c\xfe\x97\x43\xc1\x0a\xf0\xc9\x93\x7d\x72\xe1\x81\x9e\x5b\x53\x1d\x66\x1c\x58\xc6\x31\x41\xce\x86\x62\xc8\x83\x9e\x66\x4d\xb7\x9e\x16\xc5\x4d\x11\x3a\xbb\x02\xa7\x5b\xdf\x11\xb3\x45\x3d\x07\x18\x25\xbc\x41\x57\x41\xe9\x94\x83\x54\x6b\x8e\x1e\x68\x19\xde\x53\x01\x70\x92\xe4\xef\x87\x1f\x1c\xa0\xd3\x50\x8f\x93\x78\x28\xa4\x66\x7d\xb1\x1f\xff\xf9\x41\x6e\xeb\xb9\x4b\xf9\xb8\x4d\x65\x46\x03\x09\x48\x34\xa9\x9c\xa7\x0b\x90\xf5\x62\xa8\x68\x23\x62\x4d\xfe\x9c\xb2\xf9\xe8\x8c\x17\x3f\x13\x46\x4d\x4c\xe2\x55\xf2\x22\xdb\x50\xdd\x63\xab\x42\x46\x57\x34\xe7\x52\x95\xc0\x64\xb6\x4c\xc3\xf1\x5e\x62\x37\xe3\x7f\x33\xd6\x15\xf7\xc2\x43\xe4\xba\x30\x89\x60\xcf\xd4\x39\x34\x02\x52\x55\x00\xbb\x79\x02\x97\x0b\x39\x31\xd4\x8b\x35\x66\x6a\x2d\x4d\x2a\xb0\x8f\xa1\x2a\xf3\x66\xa0\x04\x34\x6c\x9d\xd9\x3d\x39\xfb\x1b\x73\x40\xf1\x04\xe5\x1f\xed\xbb\x53\x36\x05\xb5\xff\x39\xcf\x6d\x59\x51\x3f\x12\x85\x6d\xcf\xa1\x98\xd7\x93\xb0\xfc\x87\x5c\xde\xa0\x74\x1f\x14\x55\x74\x6d\x8a\x19\xc3\xe9\xd9\x28\xf0\x02\x1b\x01\xc2\x51\x31\x81\x1e\x48\xc3\xc7\x5c\x6f\x41\x42\x2a\x88\x10\xc6\xc8\x1f\x35\xb4\x54\xee\xae\x8c\xd1\x7c\xf3\xf2\xe6\xf0\xbc\xd9\xf2\x90\x98\x4f\x49\x65\x78\x62\x3a\xb8\xe2\x73\x8d\x2d\x10\x84\x0e\xb9\x1d\x10\x1c\xb4\xa2\x37\x22\xb7\x2e\x3d\xd1\x85\x44\x0c\x3b\x9f\x44\xd4\x6a\x39\x3a\x34\xc1\x87\xa2\x0d\x61\x0b\xb6\x98\xc5\x05\x31\x74\x1e\xfe\x96\x32\x35\x12\x32\x98\x00\x77\x2a\x40\x80\x65\xa7\xef\x8e\x4e\x41\x05\xeb\x1f\x5b\xf6\xd3\xfd\x6b\x21\x7f\xd8\x36\xd8\x9f\x53\xb9\x6f\x45"}, -{{0x33,0x55,0x6c,0x60,0xde,0x2f,0x2c,0x9a,0x93,0x03,0xb9,0x9a,0xdd,0x37,0x85,0x92,0x06,0x05,0x05,0xf8,0xe4,0x98,0x61,0x08,0x5a,0x4b,0x15,0xf0,0x72,0xa7,0xef,0x28,},{0x23,0x1e,0xc8,0xcd,0x84,0x58,0x59,0xf6,0x99,0x61,0x27,0x51,0x19,0xdb,0xe4,0xf7,0x15,0xe5,0xec,0x5a,0xa9,0x8b,0xb8,0x74,0x16,0x75,0xb3,0xc2,0xd0,0xc8,0x9f,0xee,},{0xe0,0x6a,0x7a,0x41,0x44,0x57,0xbb,0xbe,0xf2,0xba,0xc3,0x77,0x5c,0xca,0xd0,0x87,0xda,0xcb,0x1f,0xa4,0xbf,0x93,0x88,0x94,0xe8,0xc9,0x29,0x11,0x8e,0x09,0xe6,0x78,0xdd,0x19,0x93,0x8b,0xc8,0x8f,0x43,0xed,0x0f,0x7d,0x31,0xcc,0x6a,0x0e,0x60,0x2c,0x4e,0x4d,0x1f,0xee,0x33,0xd4,0x1e,0x74,0xa1,0x19,0xfa,0x2d,0x1e,0x4e,0x34,0x0f,},"\x96\xaf\x54\x0e\xa2\xb1\x92\x3f\x5f\xd0\xaa\xd3\x21\xac\x03\x20\x70\xc2\xd6\x5b\xa1\x3d\x16\x4e\x75\xc3\x46\x97\x58\xfc\xf3\x1b\xb3\x16\x55\xcb\x3a\x72\x1f\x9c\xb3\x4b\xe2\xc9\x0c\x77\xeb\x65\xbe\x37\xf6\x06\xd3\x2a\x91\x7a\x4c\xb9\xa7\x09\xac\x07\x05\x22\x99\x30\xef\x6e\xb6\xfd\xb0\xfa\x3c\x0f\xd3\xa9\x0c\xe1\x71\x67\x4e\xe3\xed\x06\x35\x4b\xaf\xc3\xc7\x07\x54\x67\xa5\x74\x45\xb8\x03\x85\x64\x04\x47\x90\x2b\xe3\x92\x62\x89\x4b\x1f\x64\xfe\xa5\x82\x87\xdc\x32\x2d\x19\x87\x59\x72\xa7\xc8\xbe\x91\xd3\x1f\x02\x1c\x70\xeb\x68\x2f\xdf\x11\xa1\x0f\x8f\x58\x2a\x12\x6e\x06\x47\x94\x83\x8c\x69\xfd\xf6\x4f\x5b\x6e\x8b\xa5\x9d\x48\xb4\x38\x4f\x8e\x9f\xb5\xc0\x87\xcc\x77\x38\x29\x5c\xd3\x23\x44\xba\x3b\x69\x7e\xe6\xb6\xa8\xb7\x8e\xe7\xa9\x57\x5c\x97\x97\x2a\x4d\x1b\xb1\x84\x86\xf9\x03\x7a\x0f\x3c\x6f\x47\x1a\x90\xf8\x64\x98\xdb\xc0\xdf\x52\x32\xc0\x7e\x8c\x01\xb6\x90\xbe\xe7\x53\x02\x99\x2a\x7a\x36\xfb\x44\x37\xc2\x5a\x8b\xf5\xe3\x4c\xf7\xd5\xb5\x55\x72\xc7\x00\xa0\x79\x84\x8d\x38\x13\x64\xf9\x94\x6a\x91\xeb\x16\x03\xff\x3d\xe5\xeb\xdd\x52\x3b\xd9\x25\x64\x81\x8e\x23\x7a\x53\xe8\xf5\x22\xde\xaa\x2c\x29\xb8\x97\xe9\x61\x58\x6e\x10\x0e\xd0\xfc\x0a\xd7\x0d\x16\x09\x34\xe6\x94\x02\x7e\x5c\x95\x79\x20\xbc\x05\x46\xe9\x01\xbe\x39\xa8\x45\x35\x59\x7e\x1f\x28\x0c\x22\x22\x67\xab\xe9\x7f\x41\x20\x5d\x81\x71\x82\x0d\xd2\xfa\xaf\xc0\x69\x94\x19\x32\x1a\x91\x60\xf6\x9b\x99\xfd\x41\x18\x09\x45\xb6\x2d\x2d\xd1\x05\xcc\x7b\xbe\x82\x1d\x28\x60\x5e\x09\x8e\xdf\xa8\xb2\x30\x9a\xeb\x05\x34\xe7\x56\x37\x7f\x59\x93\x7c\x67\x46\x3f\xd8\x7c\x8b\x92\xab\x58\x11\x9c\xf4\xce\x6c\x66\x5a\xf5\x72\xfb\xae\x1d\xe4\xa2\xcc\x71"}, -{{0x7a,0x5c,0x74,0x31,0x4e,0x11,0x83,0x33,0x4a,0x4b,0x62,0x26,0xb9,0xa8,0x2d,0x70,0xfc,0x2a,0x12,0x4e,0x3f,0x87,0xdb,0x6a,0x22,0x83,0xee,0x05,0xb6,0x8e,0x34,0xe0,},{0xbe,0xae,0x7d,0x3d,0xd9,0x7c,0x67,0xf6,0x27,0x3b,0xfa,0xa0,0x66,0x13,0x1f,0xed,0x8a,0xce,0x7f,0x53,0x5f,0xe6,0x46,0x4e,0x65,0x79,0x1c,0x7e,0x53,0x98,0x57,0x6c,},{0xc2,0xab,0x1f,0x6f,0x51,0x14,0xa8,0x4f,0x21,0x85,0x02,0x58,0x2c,0x56,0x7b,0x37,0xa8,0xbd,0xbc,0xdf,0x63,0x40,0xfa,0x46,0x22,0x87,0x3b,0xe8,0x91,0x06,0xf0,0xa9,0x0b,0x48,0x29,0x50,0x5f,0x72,0x12,0x9d,0xf0,0xab,0x3d,0x85,0x13,0x26,0x87,0x74,0xa3,0x4d,0xf3,0xad,0x21,0xce,0x25,0x4b,0x46,0x44,0x88,0xad,0xdd,0x6c,0x9b,0x04,},"\x98\xba\xc6\x72\x47\x55\x91\x29\x92\xad\xc2\xa4\x8b\x54\x42\x37\x6f\x2d\x92\x79\x97\xa0\x40\xfb\x98\xef\xe5\x44\xeb\x0c\x8e\x18\x66\xb9\x61\x6e\x29\x8d\x33\x60\x31\x6e\xd9\x76\xbd\x94\x6a\x41\x1f\xdd\x3a\x6b\x62\x5c\x0c\x1a\x37\xaf\x0f\x41\xcf\x65\x69\xa7\x88\x4a\xb8\x46\x74\x91\xa9\x87\xdf\x3e\xa7\xa0\xb7\xeb\xc4\x69\x25\x69\xa3\x4c\xe3\xa2\xea\x35\x03\x49\x5b\x2c\x02\xd4\x9d\x7d\x7d\xb5\x79\xd1\x3a\x82\xcf\x0c\xf7\xa9\x54\x7a\x6e\xae\xbe\x68\xe7\x26\x7d\x45\xa6\x0b\x8d\x47\x72\x45\x52\x28\xcc\xa4\x03\x6e\x28\x2e\x1a\x12\x16\xf3\x4c\xef\x7e\xa6\x8f\x93\x82\x70\xbd\xb0\x42\x93\xc8\x85\xd0\x05\xf9\xf7\xe6\x38\xa8\xb4\xea\xd2\x62\x6c\x09\x45\x17\x4f\xf2\xa3\xe2\xd6\xe1\x5a\x4c\x03\x38\xc0\x9e\x12\x60\xf0\x92\x8c\xa9\xd3\x49\x98\x24\xf3\xfe\xdc\x47\x85\xda\x49\xc5\xc3\x4a\x56\x85\x5e\x24\x1f\xac\xc6\x34\x7a\x39\x9d\xdc\xac\x43\x99\xa8\xb1\x58\x19\x8c\x15\x14\x61\xa3\xb1\x89\xe5\x8e\xc1\xf7\xef\xcf\x2a\xb2\x03\x1f\xb1\x7b\x6f\x03\x5b\xa1\xf0\x92\xe9\xee\xe2\xe9\x2c\x2d\x6c\xc2\x03\x22\x87\xf8\x54\xb4\x1e\x70\xfc\x61\xc8\xd1\x1a\x2e\x4f\x07\x08\xf0\x2e\xeb\xd0\x2e\x8c\x7e\x8c\x7b\x38\xa5\x7b\xfa\x1a\x74\x5f\x3a\x86\xc2\x39\x09\xf6\xf8\x9a\xb1\x6c\xe7\xe1\x81\x3c\x1d\x20\x14\x7f\x31\xb4\xcf\x2a\xd0\xb6\x06\xfb\x17\xe5\xac\x1a\xb5\x1e\xf4\xa7\xd8\x09\x3c\xee\x9a\x65\x5f\x47\x1d\xc5\xb1\x46\xbd\x1b\x93\xe5\x40\xa3\xd3\xd3\xe2\xde\x81\x05\x91\x1c\x10\xd6\xab\x5f\xf7\x9c\x2d\x06\x02\x7f\x7a\x54\x56\x1f\x20\x71\x41\x4b\xd3\x30\xa8\x78\x54\x42\x25\x1c\x81\x0e\x23\x2f\x83\xc3\x67\xf0\xbe\x77\x99\xa9\x3f\x52\x38\xf7\xf1\x7b\x5b\xe8\x29\xfd\x89\x12\x3c\x04\x83\x3a\xf8\xb7\x7e\x5a\x43\x63\x04\x7c\xec\xa7"}, -{{0xda,0x80,0x06,0xad,0xc4,0x92,0xca,0x5d,0xc8,0x6c,0x29,0x59,0x43,0x7a,0x75,0xde,0xb6,0x12,0x0f,0xf7,0x87,0xd2,0xec,0xb9,0xc2,0x0c,0x30,0xb5,0x2c,0x26,0xbc,0x41,},{0xff,0x11,0x3b,0xf0,0xaa,0x58,0xd5,0x46,0xf2,0x38,0x5d,0x44,0x4e,0xcb,0x78,0x88,0xf8,0xca,0xba,0x43,0xa1,0x74,0xa8,0x9f,0xd6,0x06,0x5f,0x2b,0x7d,0xc1,0x7b,0xf0,},{0x1f,0x53,0x75,0xdc,0xb3,0xad,0x2b,0xaa,0xff,0x95,0x6d,0x85,0x54,0xec,0xb4,0x24,0x17,0x6b,0xe9,0xa6,0xeb,0x9e,0xa5,0x4e,0x81,0x4e,0x0a,0x73,0xdf,0x2a,0x5d,0x84,0x8a,0xda,0x26,0xba,0x8e,0x18,0x05,0xcd,0x51,0xc5,0xe1,0x69,0x50,0xc1,0xff,0x7d,0x4d,0x27,0x64,0xda,0xa6,0xf4,0xc7,0x50,0x2f,0xb8,0x65,0xcb,0xe5,0x5a,0xaf,0x0b,},"\x3e\xb4\x32\x4d\xbc\x01\x49\xd2\xe7\xd6\xdf\x63\x2b\xb0\xcb\xe9\xa9\xf6\xdf\xa8\x3e\x22\x7f\xc0\x7b\xde\x1b\x57\x7b\x36\x11\xfb\x92\x1c\x9f\x83\x13\xf0\x68\xe6\x29\x5d\x49\x13\xa8\x19\x6b\xe5\x30\xf6\xa0\x1f\x57\xc0\x9c\x02\x84\x91\x44\x4b\x78\x47\x20\xe9\x09\xea\x1f\xb6\x9c\x1c\x1d\xd6\x30\x44\x00\x32\x7b\x77\x31\xb3\x3c\xc4\x6d\xeb\x04\x6c\xda\xb6\xad\x1b\x53\xf1\x74\x9a\x0c\x65\xcb\x9a\x7e\x37\x6f\xfa\x02\x23\x0f\x53\x65\x84\xae\xa2\x43\xc6\x39\x10\x3a\xdb\xba\x76\x43\x21\x64\x9d\x7e\x01\x26\xf8\x2e\x0b\x4f\xd9\xdc\xb8\x6c\x73\x1c\xbc\xc5\x17\xf2\x01\x68\x41\xe9\x16\xbc\xd5\xfd\xe8\x71\xdc\x09\x8c\xd9\x13\xdc\x54\x62\x84\xd1\xb2\x16\x5c\x63\xe8\x8f\x32\xa2\x78\x9a\x50\x08\x56\x37\x1b\x50\xd2\x2f\xb8\xc8\x7d\x1a\x3c\xae\xdc\xdf\xd0\x1e\xe5\xf8\x70\xa5\x3c\x28\x41\x81\xd6\x32\xec\x66\xd4\x8b\x6b\xdd\x56\x46\xac\x39\xc9\xe7\x53\x38\xa5\x20\x21\x20\x62\xbc\x34\x66\xef\x5c\x58\x76\x55\x70\xb9\x05\xf6\x3a\x93\xd0\x7f\x8f\x1b\xaa\xc3\x52\x6b\x01\x6d\xa7\x99\xf3\xe9\xe0\x3a\x4f\x7f\x81\x35\x5e\x0f\x7a\x76\xf3\x0a\x42\xb8\x07\x32\x20\x51\xb7\x1c\x62\x6a\x7a\x29\x6d\x75\xb9\xd9\xd1\xa2\x3b\xcb\x13\xc9\xef\x48\xa9\x12\xdc\x05\x73\x25\xd3\xbc\xfb\x3f\x9f\xad\xaf\x0c\x24\x9b\x10\x2a\xeb\x85\x4a\xa3\x63\x1e\x34\xf6\x9a\xd9\x0c\x2a\xb2\xed\x33\xba\xcc\x40\xb9\xed\x10\x37\xfa\xe6\x7c\xdf\x79\x9d\x5a\x9b\x43\x78\x59\x61\x12\x7d\x62\xf8\xe0\xbc\x15\x89\xfd\x1a\x06\xfc\xa2\xae\xa7\xcf\xc0\x12\xcb\xf7\xb5\xb2\x07\xdd\xc4\xe6\x77\xd8\xae\x4a\xec\x10\x00\x45\xce\x36\xc0\x0b\x74\xd1\xd2\x82\x50\x79\x12\x36\xdc\x5d\xcc\x1e\xd3\x13\xc8\xc2\x46\x17\x26\x66\xf7\x52\x17\x43\x7c\x60\x34\xac\xd6\x41\x98\xcd\x96\xdf\x2a"}, -{{0xa2,0x84,0xe2,0x6b,0x97,0xe5,0x38,0x83,0x9c,0x80,0x8d,0x45,0xbd,0xe6,0xf0,0x12,0xa3,0x54,0x45,0x4a,0xef,0x81,0xca,0xa8,0xc5,0x59,0x14,0x62,0x4f,0x2b,0x7d,0x66,},{0x5a,0xe4,0x6e,0x34,0x69,0x5e,0xfa,0xf4,0x63,0xa4,0x20,0x8f,0xc4,0xe3,0x5b,0x81,0xf2,0xc6,0x35,0x93,0x23,0x8a,0x56,0xf2,0x44,0x4b,0x85,0x0f,0x05,0x8c,0x3c,0x5c,},{0xbf,0x11,0x0e,0x2e,0x9c,0xec,0xbc,0x31,0xfa,0x3e,0x0c,0x24,0x38,0xcd,0x1f,0x43,0x21,0xf9,0x2c,0xd2,0x87,0x00,0x5a,0x48,0x52,0x8a,0xdd,0xf7,0x6c,0xad,0x8d,0x88,0xbb,0x22,0x71,0x9e,0xf9,0x1b,0x13,0x95,0x62,0xa1,0x51,0x18,0x38,0x68,0x26,0x74,0xfa,0xa9,0xff,0x7e,0x7a,0xde,0x6c,0x9d,0x57,0x3f,0x84,0x50,0x36,0xd1,0x89,0x05,},"\x9e\xbf\xe9\x10\xb5\x0a\x5c\xb7\x19\xd9\x5b\x96\x1e\x59\x05\xf0\x0e\xc7\x94\x3b\x55\x46\x8a\xb5\x95\x66\x92\x01\x76\x45\xb3\x66\x07\x1f\x8f\xbb\x77\xeb\x49\xec\x73\xea\x7d\x64\x51\x14\x05\xb9\x0d\xe2\x2d\xb9\x8c\x3e\xae\x39\xc4\x03\x9c\x7a\x13\x34\x30\xe8\x01\x0b\xdd\x39\xa0\x0f\xd1\xa5\x28\xb1\x13\xda\xe1\x49\xcf\xad\x3a\xe3\x40\xda\x27\xdc\xc5\x07\x78\x2e\xcd\x89\x29\x23\x75\x17\xaf\xe7\x46\x3e\xca\x24\x73\xc7\xac\xf6\xf7\xaa\x04\xef\xc9\xf2\x66\xae\x7b\x6d\x63\xbb\x8c\xc2\xa4\x38\xb3\x44\x82\x7f\x07\x13\xd1\xf1\x73\x6f\x0c\xbb\x65\xb9\x93\x53\xf2\x03\x55\xfa\x02\x30\xd4\xfa\x70\x73\x28\xa8\x66\x26\x54\xe8\x3a\xd0\x53\x0a\x10\xf9\xa6\x9e\x17\xc0\x99\xe1\xe2\xb5\xdb\x18\xe5\xf6\xf1\xdc\xed\xa5\x88\x3e\x8c\xab\x79\x70\x1a\x5e\x90\x89\x56\x2e\xd1\x53\xad\x08\xc6\x74\xf0\x97\xc2\x8e\x4d\x16\x63\x3e\x09\x29\x69\xa8\xf0\xbd\xac\x54\x52\x7c\x0e\xe0\x3b\xc2\x00\xe5\xbe\x61\x2e\x3d\x1e\xab\xd8\x70\x91\x10\x1b\x49\x62\xaf\xa0\x7b\x31\x08\x06\x99\x2f\x37\x30\x76\xd7\x6a\x58\x18\x51\x18\x13\x7c\x9d\x26\xee\x2c\xd4\xc6\x18\xc1\x82\x83\xdd\x19\xf0\xe7\xa0\x89\xee\x37\x30\x5b\x6b\x95\x18\xa7\x8d\x80\x98\x43\x6e\xf6\x2b\xe7\xd6\x99\x80\x8a\xce\xcf\x67\x93\x9d\x61\xb3\xe0\x29\x37\xcd\x8c\x5f\x1e\x74\x6d\x42\x74\x33\x4b\xc9\xc3\x7f\xdc\xba\x23\x4c\x16\x6f\xd7\x12\x89\x3f\x3a\x04\x08\x32\xec\x54\x25\xe5\x7d\x80\xf1\x1e\xf9\xca\x5f\xbc\xd6\xc1\x47\xfb\xbf\x5e\x2f\xae\x74\x6e\x0d\xdb\x60\x58\x67\xe3\xbd\x05\x04\x83\xc3\xcd\x13\x29\xab\xe5\x7a\x60\xbf\x88\x89\x8d\xc7\xe8\x0e\xde\x0f\x45\x17\xde\x8f\xc8\x07\xe8\x88\xb6\x21\xa0\x0f\x66\x30\x84\xff\x94\xb9\x99\x96\x62\x8f\x3b\x11\x69\x0a\x60\xf0\x91\x8c\xb5\xc9\xa7\xef"}, -{{0xcc,0x97,0xa9,0x63,0x01,0xce,0xed,0x0f,0x92,0x27,0x31,0xb6,0x85,0xba,0xd8,0xad,0x4f,0x06,0x20,0x7b,0xe3,0x40,0xf5,0xa4,0x4f,0xd1,0x87,0xf2,0x99,0x03,0xec,0x20,},{0xeb,0x56,0x3a,0x7b,0xce,0x12,0xdb,0x97,0xf1,0x89,0x1d,0x0f,0x61,0x0b,0xeb,0xd5,0x51,0x01,0xa3,0x12,0x5c,0xa8,0xdb,0xb5,0x0b,0x25,0xa6,0xb5,0x05,0x0d,0x37,0x84,},{0xff,0xbd,0xd3,0x24,0x41,0x81,0xcd,0xf6,0x03,0x4f,0x4a,0x45,0x0f,0xdd,0x95,0xde,0xe4,0x97,0x1a,0x93,0x3f,0x8b,0xe0,0x22,0xbb,0x0a,0x41,0x06,0xae,0xf3,0x9a,0xf3,0x05,0x5b,0x72,0x18,0x81,0xc9,0xb5,0x4d,0x1e,0x99,0xb9,0x40,0x90,0x96,0xfb,0xe6,0xdc,0x2c,0x99,0x66,0xe3,0x67,0x99,0x64,0xbd,0x7e,0xf4,0xc8,0x08,0xca,0xbf,0x01,},"\xb9\xea\x3b\x3d\xf7\x18\x7e\xa4\x15\xa3\xc3\x35\xe0\x83\x4e\x10\xf4\x40\x91\x5b\x2a\xd4\x1c\x71\xf2\x55\xd6\x95\x0a\x4e\x91\x20\xe4\xd4\x94\xfd\x9e\x67\x2c\xe5\x32\x06\xfd\xc4\x17\xd8\x65\x89\x7b\x47\xac\x10\x54\xe1\xca\x10\x68\x19\x52\x32\xd4\x29\x74\x35\xe4\x4e\x12\x24\xe6\x6a\x91\x2d\x9d\x7d\x18\x29\x46\xff\x5a\x9f\x08\x5b\xb8\xba\x19\xc5\x4d\x16\xb5\x86\xa9\xb3\x04\x61\xb6\x77\x3b\x93\x95\x03\x11\xe1\x61\x98\x86\xf5\xa5\xb3\xf1\x11\xaa\xad\x09\x4b\xae\x31\xc4\x8f\x19\x41\x08\x09\x68\xbd\x02\x77\xbb\x6f\xa9\x2e\xeb\xf3\x24\xb1\x92\xdf\x5c\xc9\x69\x51\x6c\x78\xc7\xb2\xd1\x21\x59\xb4\xd1\xc8\xeb\x03\x16\x0c\x4c\xd1\x90\x7f\x62\xed\x4b\x85\x4c\x56\x9e\xcc\x48\x1c\x08\xe6\x36\xf4\x4e\xd7\xc3\x90\xe5\x8b\x59\x37\xd2\x90\x6b\x28\x17\xbc\x37\x69\xda\xd9\xda\x1b\x0f\x79\x39\x1b\x55\x94\x20\x63\x05\x5d\xa0\xd6\xf2\x49\xa3\xe4\x52\xba\xdd\xaa\x03\x29\x98\xd7\xf7\x33\x98\xcc\xd0\x15\x1b\xfc\x92\xc5\xe2\xfd\xfa\x9b\x14\x85\x5e\x6b\x0d\x37\x46\xdc\xe2\x48\xe2\x19\x67\x29\x87\x25\x2e\xc7\x47\xdf\x27\x47\xfd\x3f\xbd\x8b\x71\x4c\x88\x2d\x70\x7e\xe3\x02\xa9\x04\x95\x0c\x34\x75\x4f\x85\x35\x0e\x1a\xa3\xf8\xea\x62\x93\xcf\x01\xf7\x17\xce\xfb\x6b\x83\xa2\x21\x26\xdf\x5c\x4f\x56\x98\xaa\xfd\x06\xa2\x24\x4a\xd7\xd0\x1f\x34\x01\x7c\xa0\xec\xe6\xf2\x10\x40\x04\x8a\xba\x6c\xa4\xae\xb0\x43\x25\xb9\x40\x2b\xcd\x43\xab\x13\x0a\x10\x57\x88\xac\x3d\x7b\x7d\xa0\x1e\xa9\x42\x6d\xd0\xea\x19\x33\xa8\x18\x99\x33\xa6\xc0\xc6\xcd\x64\x8e\xa3\x16\xa7\x46\x9a\x5f\xdc\x6e\x7c\x93\x4d\x91\x86\x58\x60\x97\xb5\x5d\xd5\x1a\xc4\x87\xbb\x80\xed\x11\xd4\xdf\x8d\x33\x62\x6b\xbc\xe9\x5e\x4f\x13\xbd\x49\x92\x2f\x00\xc9\x20\x22\x3f\x4c\xbf\x93\xcb"}, -{{0x67,0x9e,0x3e,0x34,0x77,0x3a,0xbe,0x4a,0xe2,0x5c,0xae,0x7d,0x07,0xcc,0xd0,0xeb,0x3b,0x0e,0xc0,0xa3,0x5d,0x57,0x02,0x57,0xd6,0x25,0x70,0xde,0x58,0xea,0x25,0x16,},{0x18,0xac,0xff,0xce,0x25,0x3b,0x27,0x25,0x95,0x79,0xed,0x99,0x24,0xf4,0x79,0xca,0xe3,0x12,0x16,0x7b,0xcd,0x87,0x6e,0xdb,0xa8,0x8b,0x5d,0x1d,0x73,0xc4,0x3d,0xbe,},{0x1a,0x51,0x02,0x26,0x28,0xcc,0xbb,0x88,0xea,0xe9,0xb2,0x17,0x73,0xc3,0xf8,0x30,0xb7,0xb6,0xe5,0xbc,0x36,0xc9,0x90,0x3c,0xe7,0x0f,0xbc,0xf4,0x59,0xd6,0xa1,0xed,0x8a,0x1d,0xce,0xff,0x5b,0x19,0x26,0x9e,0xbf,0x5a,0x6f,0xd3,0xd8,0x95,0x88,0x60,0xf5,0x54,0x46,0x1f,0x0e,0x9f,0xc0,0xe2,0x9a,0xf9,0xb1,0xfb,0x17,0x44,0xa8,0x0b,},"\xfb\x2b\x64\x8e\xbb\x16\x68\x82\x44\xf7\x8b\x2e\xe9\xa2\x73\x59\x9d\x56\xb6\x19\x89\x00\xd4\x38\xa9\xe9\x9c\x19\x14\x25\xc7\x2b\xec\x4f\x23\x58\x47\xe1\x8e\x47\xf5\x7c\x3c\xb3\x96\x65\x5f\x77\x89\x21\xf9\x08\x58\x0e\x8e\x83\xc9\x6c\x10\x8b\x20\xdd\x41\x66\x78\x02\x1b\xca\x25\x9b\x98\x51\x8f\xab\xb2\xd3\x53\x2e\x48\x51\xd9\xd5\x2a\xdd\x25\x42\xc0\xcb\x3e\xfa\x38\x57\xa1\x7e\x51\x24\x38\xbc\x0e\xc4\x76\x2e\x2f\x9b\xab\xa4\x29\xc0\x3e\x99\xbe\xc4\x03\x8e\x6b\x0c\xa4\x2b\xff\x5b\x23\x3b\x24\xc3\x33\xb4\xca\xea\xd2\xde\x37\x4a\x87\xb2\xab\x5d\x80\xd6\xe4\x9e\x44\x56\x32\x9d\x51\xae\x97\x3b\xc8\x3d\x78\x62\xf3\xd3\x15\xe5\x14\x48\x1b\x12\x85\x4a\x9d\xfc\x09\xe7\xd1\x4f\x0d\x02\x2c\x0b\xa3\x02\x25\x78\xeb\xa8\xf8\x74\xde\xba\x4a\xa8\xc8\x33\xf2\xb1\x32\x86\x1d\x4d\x51\xe5\x0f\xe9\xaa\x4b\x78\x7b\xd2\xf0\x51\xaa\xc5\x0c\x37\x53\x90\xcb\xbc\xfb\xa2\x00\x2b\x80\xad\x00\xcd\xc1\x29\x80\xf8\xba\x8b\xcb\x70\x64\xaf\xc0\x4d\x5c\x46\x82\xc1\x02\x9b\x10\xa6\xd4\x5f\xe6\xec\xd7\x04\x24\x5f\xaf\x59\x8c\x46\x59\x59\x7c\x5d\x68\xa1\x92\xcc\x1c\xd4\xfa\x45\xe8\x4b\x54\x9e\x8e\x5e\x67\xda\xa8\x79\xae\x5a\x52\x0a\x6b\x55\x50\x51\x98\x76\xa5\x62\xac\x49\xc6\xdb\x0a\xa7\x6e\xc6\x9b\xb6\x4d\xd6\xb5\xe1\xa3\xaf\x2e\x13\x1e\x72\x2e\x7c\xdd\x05\xbe\x34\xb5\xfc\xc6\x25\x9a\xa1\x24\xcc\xf8\x14\xcf\x5b\x50\x0d\x17\x6b\xe2\x8e\xbc\x40\xbb\x21\xf0\x3e\x24\xcc\xc1\x31\xe0\xf4\x1d\xaa\x1c\xa0\x2e\x6b\x00\xc9\xc5\x3f\xad\x12\x48\x61\x4e\x94\x0d\x4b\x23\x77\x60\xab\x75\x69\xa7\x67\xb7\x51\x5d\xd2\xd6\x23\xe5\x7a\x28\x41\xb7\xd2\x44\x1c\xf4\x30\x49\xe4\x69\x8d\x2f\x9c\x9e\xae\x7b\x29\x10\xf6\xad\x65\xed\xf9\xcb\x2b\xdb\xd9\xb2\x9f\x60\x6e\x0d"}, -{{0x9b,0xfa,0x60,0x92,0x3a,0x43,0xed,0x0c,0x24,0xe2,0xf1,0x2f,0x5b,0x86,0xa0,0x71,0x63,0x29,0xf9,0x3d,0x4d,0x8d,0x3e,0x06,0x23,0x80,0x02,0x89,0x32,0x78,0xc1,0x9a,},{0xfb,0x1c,0x00,0x68,0x77,0x81,0xb5,0x5b,0x89,0x3d,0x6b,0x2f,0x4f,0x49,0xcf,0x5f,0x73,0xd2,0x90,0x3c,0x31,0x6d,0x1e,0xee,0x75,0x99,0x1d,0x98,0x3a,0x18,0x68,0xc0,},{0x55,0xf2,0x02,0xef,0xb2,0xa5,0x7b,0xe8,0xb4,0xe4,0xfd,0x89,0x4d,0xcc,0x11,0xa4,0xfc,0x5f,0x82,0x76,0x61,0x8e,0xf5,0xcd,0x34,0xa4,0x49,0x5a,0xdb,0x01,0x6a,0x29,0x8e,0x64,0x80,0xa3,0x5c,0xfc,0x53,0xed,0xb2,0x5f,0xf1,0x49,0x9f,0xc5,0x32,0xa3,0x30,0x61,0xcc,0x01,0xa2,0x50,0x45,0x8a,0xa5,0xe4,0xf7,0xf1,0x6f,0x51,0x44,0x0d,},"\xa9\x90\x28\xb0\xf4\xa3\xaa\x5e\x79\xab\xef\x6c\x0d\xf4\xa7\x83\xef\x47\x0f\x1a\x29\xba\x51\xeb\xa0\x0f\x62\x14\xe8\x40\xfe\x19\xe5\xb6\xdc\x60\x21\xab\x59\x9b\xb2\xee\x36\x99\x57\x60\x15\xd7\x9a\x79\x39\xaf\x82\x35\x35\xb6\x30\xe3\x93\x8c\x72\x3f\x6e\x0b\x92\x29\xd4\x6b\xb3\x37\x9a\xcd\xba\x58\x7c\x23\x85\x67\xe3\xd8\x9b\xc3\xbd\x35\x19\xb7\x27\xfc\x69\x4f\xff\x11\x18\xbf\x22\xc8\xbc\x8b\xc8\x2c\x4d\xf7\xf5\xad\x38\xde\x05\xfe\x9f\x76\x29\x99\xec\xaa\x79\x5f\x3a\xe6\x30\xa9\xa3\x16\xd2\x6d\xce\x9f\x15\x68\xff\xa3\xf2\x2b\x02\x95\x21\x40\x20\xb3\xd3\xf5\x33\x7c\x14\x95\x68\x19\x22\x18\x13\x2a\x90\x70\x92\x79\xc0\x1d\x23\xba\xef\xa6\x69\xe1\xc4\xe4\x20\x38\x17\x3f\x13\x19\xc2\x12\xda\x14\x4f\x1c\x4e\xa4\xc5\x2c\x00\x5c\xbc\x0b\x5b\xc2\x83\xe7\x44\x83\xa0\xdc\xa6\x92\x79\xde\xb1\x7a\xe5\xb2\x9c\xfa\xfa\x7d\x00\x63\xf4\xe1\xbc\x93\x53\x7e\xfd\x93\x7e\x58\xa8\xac\xa7\x37\x22\x8f\x93\x7f\xf2\xa7\x41\x89\x0e\x96\xc5\x72\x5d\xa1\x1b\x45\xc4\x13\xa9\xbb\xb4\x18\x0a\x41\x99\x87\xbb\xf0\x46\xbf\xd3\x46\x29\x5d\x62\xf0\x81\xc7\x6d\xaf\x2b\x0e\x1e\xb4\xf6\x71\x2f\xee\xbe\x6f\x0a\x92\xe3\x58\xe7\xdd\xb8\x58\x96\x50\x7c\x34\x0a\x01\xf6\x8d\x1b\x0f\x08\x57\x78\xb7\xc4\x4b\x01\x4a\xa6\x67\x3e\x50\x17\x96\x95\x9a\x17\xa6\x88\xdb\x09\x59\x05\x84\x88\xa7\x11\x25\x72\xf2\x3c\xf9\xcd\xb5\x3b\x5e\xb4\xb4\x5f\x59\x53\xba\x0c\x0c\x69\x0f\x86\xbd\x75\xe8\x9a\x04\x7b\xeb\xaf\x84\x7c\x1d\xfc\x34\x5a\x4f\x3c\x7d\x3b\xee\xc9\x8b\x84\xb0\x21\x90\x03\xe8\x19\xf5\xc2\xad\xb4\x5f\x87\x17\x90\x3d\x1f\x5b\xd5\xd7\x19\x14\xc5\x6f\xca\xbc\x7a\x29\x0f\x9c\x41\x69\x9c\x95\x58\x4d\x6a\x3a\x16\x34\x0c\xb1\x7b\xaa\x1f\xc5\xe5\x46\x7a\xf7\xac\x32\x21"}, -{{0x6e,0x3a,0xf4,0x5e,0x66,0xe2,0x28,0x90,0xc3,0xf3,0xc9,0x34,0xf5,0x23,0xa4,0xd6,0x94,0x27,0x97,0x6e,0x6e,0x52,0x62,0x5f,0x8b,0xad,0x55,0x89,0x93,0x96,0x32,0x19,},{0xe0,0x97,0x36,0x4e,0x76,0xff,0x9f,0x2e,0x1d,0x16,0x7f,0x6b,0x20,0xc1,0xbc,0x58,0x30,0x08,0x5e,0x7e,0xc9,0x93,0xc1,0x38,0xf8,0xb1,0xb2,0x17,0x56,0x37,0xe7,0x41,},{0x26,0xba,0x56,0x2e,0x8a,0x40,0x65,0x70,0x82,0x07,0xc2,0x5e,0x23,0x9b,0x78,0x0a,0xee,0x38,0x79,0x4c,0xf9,0x83,0xa3,0x7a,0xcb,0xb9,0xd5,0x57,0xa6,0x5c,0xee,0xd3,0xc0,0xda,0x47,0xd1,0x7f,0x3e,0x8b,0x8f,0x4e,0xeb,0x1b,0x65,0xa2,0xc1,0x82,0xea,0x6f,0x29,0x62,0x3b,0x63,0xbb,0x0f,0x1c,0x72,0x59,0x26,0x83,0xb1,0x26,0xb9,0x01,},"\x5c\xfc\x2f\x4b\x55\x9f\x82\x05\xb3\x91\x02\x08\x76\x17\xf4\xd8\x6c\x7c\xe6\xcb\x25\x1e\x5f\x89\x60\x1d\xfc\x88\xed\x28\xe8\xd7\xa6\x70\xec\x00\x87\xd2\xea\x5d\x89\x30\x21\xc7\x04\x4d\xa2\x89\x9a\x22\xd7\x76\xfe\x90\x17\x0e\x51\xc2\x03\x25\x06\x90\xd3\x7a\x29\x45\x55\xe7\x4a\xf9\x23\x4c\xbf\x1a\xd8\xf2\x2c\xee\x89\x74\x82\x8a\x0d\x09\xe9\x55\x4b\x71\xee\x3b\xcf\x88\x0a\xb9\x83\x25\xf7\x06\x27\x21\x94\xeb\x2e\x80\xc7\x01\xd4\x41\xb5\xf8\x66\x85\x61\xb8\x88\x49\xf8\x27\xaf\x70\x3a\xb0\x95\x41\x05\xfd\x3c\x54\xb3\xf6\xec\x54\x93\x59\x6d\x0e\x3b\xc6\x78\x18\x04\x83\x10\xc4\xa3\xe0\xc5\x56\xbc\x80\x67\x5f\x20\x1f\x9b\xb9\xc6\x53\x8a\x41\xd9\x9a\xa4\x0c\x88\x6f\xc4\x31\x46\x72\x18\xd8\x19\xc2\x3e\x78\x49\x8a\xed\x06\x13\xfa\x6f\x97\x3e\x22\x11\xdf\x9f\xb8\x7f\x44\x11\x6f\x3f\xe4\xc2\x6d\x6c\xb2\xfa\x33\x4c\x87\xf7\x8c\x08\xca\x8c\x9b\x90\x41\xd8\x3a\x12\x30\x67\x7e\x0a\xf7\x88\x59\x8a\x42\xe4\x4c\xfd\xf6\x96\x4a\x4e\xe8\x0e\x38\x40\x2b\xa6\x7c\x73\xa5\x81\xe5\x52\xba\xa2\x28\x24\x25\xcb\x2c\xa1\x7c\xa9\x2e\xdf\xbf\x98\x29\x91\x02\xfb\xa7\x61\xb9\xb7\x1a\x54\x52\x14\x1b\xb9\xc1\x8d\xd9\x5f\xeb\xc2\xa7\x82\xde\x9c\xee\xc0\x8b\xd2\xee\x3f\x7f\x0c\x1b\xd8\x94\x6d\xba\x99\xcf\x9e\xa0\x86\xab\xaf\xd3\x7c\x9c\xa6\x02\x13\xf0\xde\x17\xc6\x1f\xf9\xc3\x91\xc9\x81\x8e\xd5\xcd\x85\x71\x77\x8b\x7d\xcc\x13\x22\x49\x62\x38\x6f\xb8\xca\x14\xf8\x61\xe9\x9f\x3b\x18\xed\xac\x8a\x5f\x13\x0f\x7b\xfc\xd4\x5d\x04\x5d\x0f\xf3\x4c\x81\x57\x2a\x51\x23\x63\xd6\x53\x0f\x93\x81\x3e\x5f\xb1\x0e\x9c\xb8\x33\x8a\x7f\x93\x80\x04\x91\x00\x6f\x44\x63\xe8\x9f\x0e\xd4\x53\x0e\x5f\x12\xdf\x67\x4f\x59\x89\x04\x78\x0a\xd0\x81\x2b\x1e\x35\x21\xfc\xd0\xf8\x3e"}, -{{0x5f,0x1f,0x27,0x18,0x44,0xd9,0xed,0x5a,0x6a,0x6f,0x20,0x9a,0x21,0x40,0x8d,0xae,0xa4,0x70,0xf6,0xfd,0x53,0xba,0x64,0x79,0xd7,0x40,0x71,0x05,0xb7,0xde,0x4d,0x65,},{0x60,0x85,0xd7,0xfb,0x5a,0x9b,0x2e,0xd8,0x06,0xc1,0xfd,0x30,0xa2,0xaf,0xde,0x76,0x09,0x61,0xf7,0xa3,0x6b,0x48,0xf4,0x87,0x52,0x46,0xe6,0x15,0xa2,0xbd,0x99,0x28,},{0x31,0x9b,0xb4,0xde,0xb2,0x17,0x81,0x12,0x24,0x1b,0x3f,0xb8,0xf4,0x6e,0x10,0x5c,0x3b,0x8e,0x4e,0xf7,0x21,0xeb,0x20,0x0d,0x76,0x2e,0xf3,0x63,0xe2,0x71,0x6f,0x2a,0x89,0xf8,0x0b,0x5b,0x9e,0x89,0x97,0x08,0x90,0xa0,0x98,0x92,0xad,0x6a,0x58,0x80,0x8b,0x47,0x7e,0x94,0x3b,0x3c,0xfa,0x77,0x77,0x4a,0x36,0x45,0xbc,0x74,0x5f,0x03,},"\xee\xd6\xb4\x47\x5d\xc2\x63\xbd\x22\x07\xfe\x9d\x41\xd4\x82\x82\xb7\x13\xf6\x80\xf2\xe0\x37\x38\x4f\x18\xb4\xbf\x22\x43\x47\xf5\xe4\xc4\xb0\x60\xb8\x08\xd4\x12\xea\xab\xcf\x73\x3d\xc3\x9a\x40\xc6\xbd\xa0\x50\x5c\xe7\x1f\xa8\x23\xbd\x1b\x17\x94\x84\x76\x78\xdc\x03\x4e\x79\x99\xc1\x63\x69\x34\x0b\xc6\x0c\x64\xd0\x9b\xb9\x18\x7b\x2e\x32\x60\x55\xa0\x53\xf8\xe5\x05\xea\x41\x96\x86\x14\x71\x62\x2d\xb0\xe4\x6f\x0f\x89\x54\xd8\xa1\xf0\x73\x32\xda\x4d\x8a\xc5\x57\x12\x62\x60\x09\x91\x2f\x8a\x15\xa9\xcd\x63\xa7\x4a\x03\xc9\x2f\x24\x6c\xb6\x3c\xc7\x3f\x92\xe5\x1d\xad\x1b\xc9\x71\x5b\x1e\xd3\xfe\x5f\x2e\x1b\x29\x59\xb9\xb7\x1e\x0e\x37\x36\x0e\xb2\x95\x36\xcf\x79\x71\x47\xfa\xb1\x08\x64\xd6\x14\x6c\x36\xb8\x23\x35\xa0\xce\x93\x14\x08\x47\x9c\x7e\xde\x48\x4f\xf7\x3e\x2d\xbf\xff\xc6\xc9\x22\x7e\x16\xd7\xa2\x3f\x4d\x90\xf1\x55\x84\x51\x4c\x39\x59\x4e\x17\xbf\xbb\x29\x5d\xe9\xd6\x2a\xda\xdb\x58\x9d\xbb\xe0\xb0\x6d\xc8\xda\xc5\xb3\xbf\x51\x7b\x24\xc1\x83\x7b\x39\x47\x2a\x6d\xd3\x89\x31\xff\xbb\xff\x5b\x76\x36\x38\x80\x5b\x4e\x22\x32\x1f\x7a\xfe\x92\xcd\xf5\x02\xfb\x63\xd1\x09\xdd\xcd\x9e\x40\x51\xad\x6f\x45\x59\x85\x32\xbe\x17\x95\x23\x71\x08\x51\xd3\x93\x1e\x88\x7d\x02\xc3\x45\xc7\x9c\x48\x9f\xc1\x06\xa4\xae\x16\x2f\x7d\xf7\x1a\xb9\x0b\x75\x1d\xa7\x03\x8a\x6d\xf7\x61\x6c\xfc\x11\x88\x7e\x21\x06\x8f\xb9\xe3\x3b\xe5\x66\x40\x2b\xe5\x04\xf3\xfc\x27\x42\xb8\x81\x50\x9b\xd4\xfe\x6a\x0f\xc7\x22\x64\x98\x83\xf8\xcb\x65\x55\x98\xa1\x5a\x1d\x4c\x22\x9d\xd8\x6b\x5c\xae\xb7\x11\xa0\x28\xde\xfd\x43\x11\x54\xbb\xa4\x6b\x48\x17\x2a\x4d\x8c\xbd\x45\xbc\x90\xaa\xf8\x74\xb6\x08\x5f\xa2\x84\xf5\xfe\xd6\x55\xad\x6f\xa1\x7d\x67\xb3\xb9\xa7\x96\xfa\x3e"}, -{{0x04,0x8a,0xc9,0xec,0x3e,0xcb,0x30,0xa3,0xb1,0xbf,0xda,0x9b,0x3b,0x79,0xa4,0x8c,0x07,0x93,0xb4,0x90,0x87,0x9e,0x3c,0x8a,0x5e,0x23,0xee,0x2b,0xab,0xcd,0x9b,0x7c,},{0x94,0x6c,0x18,0x6f,0xea,0xfc,0x35,0x80,0xa5,0x8d,0xdd,0x52,0x6f,0xf2,0x29,0xc0,0x47,0x20,0x25,0x0f,0x4c,0xf6,0xbd,0xe0,0x27,0x1e,0xef,0x9b,0x12,0xb1,0xc3,0xf3,},{0x2e,0xcf,0x5b,0x8a,0x59,0xa8,0xe2,0x7d,0x25,0x89,0x0a,0x2a,0xa3,0x2f,0x4a,0x06,0x73,0x27,0x5d,0x53,0x9b,0x17,0x4a,0xfa,0x7b,0x2c,0xeb,0xf2,0xe7,0x62,0x80,0xdf,0xfc,0x33,0x8e,0xde,0x85,0xac,0x8f,0x61,0x40,0x39,0x56,0x0e,0x28,0x06,0xd9,0xe1,0xe3,0xcf,0x9c,0xce,0x2c,0xeb,0x78,0x74,0xff,0xe1,0xa7,0xe8,0x0c,0xde,0xf4,0x0b,},"\xd6\x8b\xe8\xef\x7b\x4c\x7a\x42\x89\xf2\xb1\x8b\x16\xad\xe9\x7f\x4e\x4f\xa1\x64\x52\x97\x6a\xfb\x58\x16\x93\x38\x0c\xc5\x4d\xe3\x8a\x07\x58\x7f\x32\xe2\xd4\x54\x9f\x26\x59\x5f\xee\x23\x93\xbd\x06\x2e\x9b\x00\xba\xe7\x24\x98\xe4\x14\x8c\x8b\x88\x2a\x88\x40\xe1\x5b\x58\x5c\x82\xb5\xc0\xde\xfb\x23\x35\x18\x40\x99\x16\x61\x5d\xeb\x3a\x55\xa5\xf8\x4e\x6b\x3a\xab\x93\x84\x4d\xe3\xb1\xe4\xd8\x6e\x09\xf8\x89\xac\x71\xc3\x24\xeb\x12\xd0\xfb\xd8\x61\xcc\x31\x22\x95\x40\xe8\x43\xa3\x4f\x8d\x5b\xe4\x7c\x0e\xc0\xd2\x3d\xf4\x3e\x06\x81\x3f\xca\x30\x94\x39\x90\x4c\x16\x7d\x10\x43\xc0\xdc\xd4\x44\xb0\x04\xbe\x1f\xf2\x7b\x78\x62\xb0\x0e\xba\x94\x33\xb9\x4b\x0f\xcd\xc6\x75\x21\xda\x0c\x1d\x53\x58\x63\x6c\x78\xf5\x30\x43\x11\x64\xdd\xe2\x0a\x1c\xf1\x64\xf5\x1e\x29\xb8\xe6\x3e\xac\xde\xcc\x86\x9b\x41\x39\x2c\x66\x76\x64\xd9\x16\x80\xd9\xac\x51\x6a\xf5\x48\xf0\x9e\x60\x56\x4e\x81\x4e\x36\xe0\xb5\x63\xdb\xae\x55\xc6\x27\xff\xc1\x41\x58\xa5\x6d\x8e\xb3\x60\x9e\x17\x43\x81\xb2\x1d\xe4\xba\x82\x34\x44\x66\xdd\x57\x7f\x4d\x11\x03\xc4\x3c\x27\xfb\x83\xcb\x83\x3d\x87\xaf\xdf\x74\x12\xb4\x09\x09\x09\xb1\xdd\xe2\x64\xda\xdd\xce\x96\x7f\x49\x6b\xf6\xf1\x71\x12\xbf\x35\x1e\x41\x7d\xb5\x95\x3b\x13\xb8\xf0\xfc\xcc\xbf\x30\xf5\xbc\xf3\x76\x86\x1c\x12\xef\x20\xee\xc8\x9e\xd2\x3c\xf3\x84\xee\x78\xdc\x6e\xb4\x0f\xd5\x81\x1a\x7b\x23\x92\x7c\x13\xe7\xdc\x5d\xa3\xa9\x21\xb8\x83\xa9\xb2\xb1\x15\x59\x70\xfb\x0d\xa7\xd2\x99\x3d\xcd\xfd\x43\x43\x64\x2a\x9d\x5a\x63\x47\xe4\x3c\x19\x3b\x57\x93\xe4\x45\x3a\xc1\x53\x7a\xa3\xd0\x4d\xc9\xf7\x74\xe8\x40\x93\x48\x81\xd7\x8a\x39\xba\x25\x04\x38\xc5\x07\x25\x0e\xed\x2f\x6e\x07\xcc\x95\x3f\x78\x3d\x6b\x72\xb1\xcc\x61\x99\x81"}, -{{0x2f,0x05,0x7d,0x20,0xb1,0x67,0x85,0x31,0x61,0x1f,0x48,0xf0,0x03,0xb7,0xd2,0x2e,0xba,0x5d,0xbb,0xd7,0xe2,0xdd,0x41,0xb7,0xc7,0x9d,0x09,0x07,0x1f,0x85,0xe9,0x93,},{0x62,0x0f,0xc4,0xea,0xa3,0x4d,0x78,0x7d,0xf6,0x75,0xcc,0xbf,0x7e,0x89,0x32,0x04,0x82,0x8d,0xb9,0x2e,0xad,0x17,0xa1,0x16,0x5a,0xc7,0xfa,0x1a,0xb4,0x27,0x19,0xd8,},{0x30,0xdf,0x7b,0x0b,0x1c,0x04,0xfb,0x1e,0xfa,0x35,0x17,0xe9,0x28,0xd6,0xd5,0x7c,0x2c,0xa0,0xd0,0x7f,0x4e,0x04,0xff,0xb1,0xf0,0x8b,0x47,0x92,0xc5,0x93,0x7d,0xd2,0x71,0xcc,0xab,0xdc,0x00,0xdc,0xe8,0x50,0xaf,0xe5,0x0a,0xf5,0x99,0x0f,0x22,0x4e,0x84,0x20,0xa6,0x81,0xd9,0x5f,0x9f,0x7f,0x51,0x5a,0xfe,0xc1,0x02,0xef,0xd1,0x0e,},"\x6e\x35\xf6\xea\xa2\xbf\xee\x06\xea\x6f\x2b\x2f\x7a\xb1\x5f\xa9\x7c\x51\x80\x95\x8a\xf2\xe9\x0a\xf9\x18\xad\xfb\x3d\xb8\x32\x3f\x44\x7c\x7b\xf2\x6d\xc5\x34\x99\x7c\x38\xb7\xfc\x97\x7f\x64\x2d\xe2\x88\xcd\xf2\x53\x07\x1c\xac\xf3\x56\x4e\x3b\x8e\xd6\xdc\xe5\x7d\xdf\xba\x9f\xf7\x83\xba\xd2\xe7\x6d\xf1\x24\x82\x8f\xc1\x03\x1a\xcf\xad\xf0\x1a\x44\xd4\x1b\x42\x16\x1a\xd9\x06\x03\x01\xc1\xaf\x19\x28\xb9\xe5\xb7\x3b\x9b\xd2\x1c\xac\x60\xa8\x42\xb5\x04\xdc\x3c\xc3\x11\xc5\x22\xe3\xbb\x04\x8b\xf2\x21\x44\x4f\x53\xce\xb0\x8e\x77\xe9\x48\x59\x0e\x94\xed\x98\xf1\xb6\x04\xcb\x9e\xad\xc9\x3b\xbe\x74\x31\xc1\x14\x9b\x23\x19\x3f\xf9\x3e\x85\x69\xf1\x13\xe1\x68\x4d\x89\x76\xec\xae\x6f\x09\xe0\x10\x36\x14\xbe\x41\x8a\x47\x2e\xf5\x5b\xb8\x89\x0d\x72\xb3\x41\xcd\xd7\x50\x5b\x50\xa4\x55\x22\xab\x63\xed\x79\x1c\xe8\xf8\x2f\xed\xdd\x7a\x62\x0a\x4f\x6f\xb1\xd2\xfb\x0e\xd0\xc4\x56\x0d\x78\x44\x6d\x83\xb3\xd1\xb1\xbb\x56\xb3\x66\xd1\x96\x02\x0d\x06\x24\xb1\xfb\xdb\x75\xce\x73\x5d\xd4\x3e\x8e\x8d\xf1\x63\xc4\x4e\x23\x69\x93\xdc\xa3\x41\xf5\x13\x2d\x82\x5d\x0a\x4e\x39\x3a\x19\xd3\x8f\x61\xe1\x1e\x0c\xf3\x92\xcb\x9b\x64\x6e\xa2\x3c\x58\x09\x98\x24\xdd\x8d\x9f\xbe\x26\xa4\x9e\x33\xb2\x3d\xf8\x06\x07\xab\xf1\x97\x15\x79\x9c\x19\xac\xc7\x22\xed\x9b\xcf\x94\xa0\xc2\x9a\xd2\x4b\x78\xb0\xb0\x35\xb3\x24\x1c\x64\xcd\x86\xed\xea\xc8\x10\xe6\x67\x45\x69\x4b\x5e\xb1\x62\x50\x60\xed\xf2\xd9\x49\xde\x0d\x34\xf5\x22\xdf\x2d\xc6\x0a\xe6\x94\xa1\x93\xf3\xb8\x2c\x1d\x6f\x83\xa0\xcb\xb8\x40\xf4\x6c\x49\xa3\xd7\xd1\xcf\x06\xde\xaf\x96\xc6\x4f\x8f\x9e\x17\xbd\x9a\xd5\x12\xae\x63\x09\xc4\x86\xd9\xe2\xa7\x8d\xce\xec\xa4\x73\xa0\x42\x1d\xd1\xb6\x43\xc7\x87\x54\x27\x1b\x53\xce"}, -{{0x3a,0x3d,0x27,0x97,0x0f,0xe2,0xac,0xb6,0x95,0x1e,0xdd,0x5c,0xa9,0x0d,0xda,0x0f,0xc6,0xdd,0x22,0x9c,0x0a,0x56,0xdf,0x6e,0xb1,0x1a,0x9c,0x54,0xd2,0x42,0xdb,0xbf,},{0x56,0x4f,0x0d,0xc3,0xdc,0x47,0x20,0xe6,0x8e,0x44,0xdd,0x16,0x71,0x1e,0x04,0x9e,0x61,0x12,0x00,0x00,0x98,0xfa,0x62,0xa1,0xb9,0x8c,0x28,0x80,0x42,0xf7,0xc3,0xbd,},{0x22,0xeb,0x8e,0xa0,0x50,0x73,0x49,0xb6,0xa0,0xac,0xe2,0x5c,0xf9,0x18,0x0c,0xb0,0x8e,0x03,0x57,0xb0,0x45,0x02,0x90,0x5f,0xbe,0x69,0xb4,0xe2,0x1b,0x2b,0xd9,0x4e,0x22,0xcf,0xbd,0xb8,0x51,0xae,0x71,0x6a,0x5c,0x25,0x3c,0x70,0xd5,0xe2,0xb2,0x4e,0xa7,0x8f,0x35,0xbc,0x21,0x32,0x92,0x54,0x3d,0x94,0xe1,0x41,0x10,0xb2,0x41,0x06,},"\x43\x74\xf6\x1c\x2c\xd8\x8a\x3b\x89\x72\x24\x9b\xfa\x79\xb3\x6a\xb6\x9e\x3e\xd4\x84\xcc\x60\xe5\xd9\x54\x1f\xa7\x68\x6c\xf4\xee\xd1\x21\x0c\x5d\x0d\xcf\x42\xdd\x25\x97\x25\x01\x90\x91\x93\xca\x76\xae\x6e\xb7\xf4\x71\xd8\xbd\x0d\x5f\xb5\xa6\xb4\x31\xbc\x3d\xe0\xe0\x31\x8d\x50\x51\x45\x24\xde\x87\xc4\xb8\x30\x05\xdf\xb4\x12\x45\xfb\x1a\xf7\x9b\x84\xa9\x7b\x83\xd3\xca\xc7\xad\x7a\x53\x36\x4e\x2e\x9b\x21\xc9\x7b\x76\x9b\xdc\x57\xf0\x70\x31\x16\x16\x83\x80\xf3\xcc\x88\x36\x89\xeb\x4a\x7f\xa3\xb2\x6d\xbe\x12\xbc\x28\xf8\xc4\x03\x81\xaf\x64\xdf\x4b\x53\x61\xd1\x74\xcf\x75\xac\xbd\x46\x42\x87\x40\xb0\xd1\x32\x2d\x32\xbb\xe9\x48\x45\x21\x59\x66\xae\x58\x87\x77\xa8\xc0\x53\x36\xe3\x52\x30\x6d\x49\x27\x8d\x32\x8e\x49\x6d\xb6\x5e\x9e\xcf\x6c\xe6\x40\x5e\xd1\xc8\x93\x49\x0b\xc4\x8c\x13\xa1\x34\xe1\xfb\x6e\x80\xde\xbe\x6d\x32\xfc\xe6\xef\x74\x78\x3c\x8d\x77\x98\x0a\x44\x1a\x26\xae\xb4\xfd\x83\xcc\x85\x53\x52\xce\xdc\x18\x8f\x52\x79\xce\x21\x1f\x74\x4a\x40\xb2\x3c\xe7\xff\x24\x43\x7a\x1d\xd3\x37\x3e\xc5\xb2\x90\xda\x1f\x94\xf4\x3a\x07\xa3\xff\xea\x5b\x5f\x67\xb5\x2c\x19\x61\x85\xbc\xe9\xe9\xa8\x58\x25\x7f\xcd\x7a\x8e\xba\xf9\x04\x0e\xd0\x91\xfa\xce\x5a\x15\x5a\xa4\x47\xfa\x15\xe1\x21\x22\xd2\x5e\x8f\xc3\x6e\xae\xe2\x13\x7c\x7b\x3a\xa3\x0b\x7e\x3f\xf6\xcc\x86\xb6\xdc\xb9\xea\xf4\x9c\x95\x76\xf0\xf4\x62\x00\x84\x39\xcb\x1a\x3a\xba\x01\x3e\x89\x7a\x0f\xaf\x99\x4c\xb7\xd5\x9e\xde\x57\x74\xbb\x14\x47\x74\xf7\x3c\xa3\x0e\x64\x14\xa7\xcc\x7c\x74\xb2\x0c\x51\xa1\x40\x4d\xdc\x41\x9e\xf7\x62\x45\x93\xe9\xbc\xfb\x37\xc0\xa7\x62\xea\xb6\x8f\xac\xa5\x86\x34\x43\xe1\x6e\xdb\x75\x9d\xbc\x87\x88\x73\x2b\x9e\x4f\x59\xc1\x11\x92\xc3\xfc\xc8\x72\xaf\x55\xf3\x2d"}, -{{0x06,0xd4,0x98,0x31,0x8d,0xa4,0x56,0x24,0x2b,0x9c,0x3b,0x9a,0xb6,0xd5,0x32,0xa1,0x28,0xfc,0xe0,0x44,0xf5,0x38,0x82,0x68,0x2e,0x92,0x62,0x14,0x9c,0x16,0x52,0x88,},{0x41,0x35,0x17,0xaa,0x63,0x20,0x0a,0x17,0x17,0x32,0x09,0xa4,0xb3,0xe7,0x8a,0xb9,0x38,0x3c,0xb4,0xe3,0x9e,0xfd,0x67,0x94,0xc4,0x6a,0x2d,0x13,0xfa,0xfa,0x99,0xc0,},{0x82,0x50,0xf7,0x6d,0xc5,0x99,0xc5,0x12,0x87,0x87,0xe4,0xf6,0xd3,0xda,0x23,0x17,0x33,0x30,0xce,0x33,0x20,0xdb,0xa9,0x59,0xbd,0x71,0x4c,0xc8,0xcc,0x07,0xc6,0x79,0x45,0xd6,0x3e,0x75,0x66,0x2c,0x07,0x5e,0x26,0x74,0x60,0xab,0x7b,0xf5,0x61,0xf2,0x4f,0xaa,0xe3,0xb4,0x1d,0xbf,0x67,0x68,0x99,0x19,0x1e,0x3b,0x02,0xb5,0xaf,0x0a,},"\x3f\xe3\x0e\xcd\x55\x07\x7a\x6e\x50\xdf\x54\xbb\x1b\xf1\x24\x8b\xea\x40\x63\xe3\xfa\x75\x5f\x65\xfc\xd1\x15\x9e\xe0\x46\xef\xd0\xeb\x5f\x2f\xbb\x38\xb5\xc0\x09\x47\xc9\x7d\xc8\x79\xb3\x6b\x9e\x53\x61\x92\x28\x60\x86\xd0\xdc\x12\x05\x36\x10\x38\x61\x74\xa7\xc5\x6f\x22\xa8\x5b\x73\xff\x20\x8c\x59\x44\xf3\x93\x23\x6c\x32\x41\x58\x09\xda\x03\x6e\x73\xca\xd8\xfc\x3c\x30\x37\x80\x64\xa7\x6a\xfa\x93\x0a\x3b\xaa\xe9\xaa\x35\x70\x61\xa8\xc5\xe8\xe7\x56\xa9\xce\xcf\x94\xb7\x2d\xf4\x3f\xac\xd8\x8f\xa4\x9c\xb4\x94\x8c\x63\x68\x31\x8a\x6b\x1e\x5c\xff\x52\xe5\x87\xec\xdf\xae\xfd\xb6\x90\x81\xf2\x8c\x2d\x13\xbf\x8e\xab\x81\xdb\xaa\x5e\x37\x28\xc4\x31\x7f\xb7\x93\xdd\x19\x6b\xca\x0f\xe5\x4a\x6c\x24\x2c\xf2\x6e\x2d\x12\x9b\xa0\xd8\x2a\x2c\x3a\x45\xbc\x8d\x1d\xfd\x6f\x54\xf8\xda\x4f\x51\x89\xc9\x1a\xc2\x14\xfd\xab\xf4\xc5\x97\x38\x1b\x2e\x5c\x40\xcc\x71\xfa\x70\x51\xcf\x2e\xa9\x39\x06\xa3\x7d\x57\xdf\x12\xd5\xc7\xe5\xcd\x77\xc9\x07\xe4\x42\x56\x63\x15\xba\xe5\x1a\x22\x22\xd6\x2e\x3f\x42\xd1\x76\x78\x82\x63\x7d\x66\xa1\xd5\x30\x5a\xb4\x01\x0a\x0e\x49\xc5\x7d\xef\x69\xdc\xea\x83\x9e\x1b\x76\xa4\x11\x35\xba\x95\x2c\xc4\x24\x95\x0e\x8d\x3a\xac\x19\xe1\xd9\x3d\xe7\x75\x7c\x15\xff\x99\x97\xb3\xd2\xa8\x61\x3c\xd9\xa1\x64\x78\x1d\x1b\xe3\x31\x79\x9f\xa6\x10\x9c\xef\x61\x43\x05\xa1\x95\x8f\x62\x90\x3c\x8c\x9e\xa0\xb2\x3b\xa7\x06\xd4\x9c\x54\xba\xcc\xc1\xe6\x3c\xb4\xbf\x14\x78\x5f\xc7\xb0\x62\xa9\x80\x03\x49\xbd\xb0\xbb\x92\x72\x60\xb6\x77\xb6\x0f\x10\xe6\x2c\x87\x80\xf3\xeb\xb5\xeb\x6f\xf0\x36\x02\x63\xd4\x57\xab\x52\xfd\x11\x25\xc9\xce\x04\x6a\x95\xd8\x9d\x28\x73\x50\xc8\x04\xcf\xd4\xff\x2b\x2d\xdd\x18\xa9\xe1\x35\x19\xf2\x0b\x4d\x1e\x05\x1a\xf6\x24\x64\x0f"}, -{{0x8e,0x8e,0x1d,0xb5,0xb1,0x10,0x2e,0x22,0xa9,0x5c,0x47,0xaf,0x36,0x61,0x46,0x9f,0x00,0x0a,0x33,0xf1,0x3b,0x8b,0x87,0xb1,0x15,0xd2,0x45,0x2a,0x41,0x1f,0x6f,0x39,},{0x56,0xd7,0xb3,0x16,0x9a,0x95,0xc2,0x29,0x98,0xec,0x93,0x79,0x25,0xbd,0x7c,0xad,0x13,0xcc,0x65,0x80,0x8c,0xd5,0xd3,0x4a,0x6c,0x4d,0xa8,0x70,0xea,0xf3,0x23,0x64,},{0xf6,0xee,0x5e,0x13,0xcf,0xaa,0x36,0x2c,0x89,0x71,0xd5,0xa4,0xa8,0x79,0xa7,0xe3,0x69,0x66,0x52,0x5c,0xcd,0x86,0xc5,0xa4,0x8c,0xba,0x08,0xd9,0x13,0xec,0xe1,0xa7,0x9c,0x4c,0xd1,0x46,0xb8,0xe9,0xc6,0x51,0x25,0xfb,0xad,0xf1,0x7b,0xac,0x1c,0xab,0xcd,0xe8,0xfd,0x17,0xcf,0xd6,0x8f,0xa1,0xf9,0xc4,0x4e,0xa6,0x1c,0x08,0xa4,0x05,},"\xb2\x46\x34\xfb\xdd\x1b\x76\x61\x31\x5d\x9d\xc1\x53\xba\x90\xd6\x6a\x88\x62\x2a\x41\x58\xf8\xbc\xff\x25\xba\x9c\x29\xe6\x5f\x29\x7f\x8e\x60\x31\x18\x00\xb7\x33\x1b\x69\xfc\x20\xc9\xf8\x5b\xb7\xc1\x84\xbd\x40\x86\xb3\xa9\xf9\xa2\x71\x02\xb6\x23\x62\xbd\xb4\xfa\x5b\x20\x15\x94\x25\x0f\xc6\x28\xfd\x2e\x0e\x0d\x1b\xe0\x3d\xcf\x81\x8c\x60\x94\xc4\xc2\x91\x21\xcb\x2b\xf6\xd9\x08\xed\x8a\xab\x42\x7c\x37\x71\xc0\xc9\x5f\x0a\xc1\x46\x9a\x08\x10\xb6\x03\xa4\x70\x28\x2e\x59\x80\xa6\x07\x29\x19\x7f\xe6\xc2\x0e\xf6\x81\xcd\x1b\x96\x93\x2d\x20\x58\xf8\x96\xea\x74\x16\x42\x2a\x7e\x54\x1f\x22\x4a\x5f\x04\x25\x30\x80\x74\x1c\x5d\x4e\x3e\xb0\x39\xdb\x6b\xa0\x51\xb4\xca\x54\x17\xce\x8a\xfd\xc7\x02\x14\xba\x4d\xcc\x85\xb6\x23\xd1\x1e\x68\x1c\x60\x09\xae\xe4\xe6\x13\x0a\x83\xed\xd0\xd2\xc9\x9f\xb0\x64\x7e\x11\xed\xe7\x30\x1a\xe5\x6b\x59\x90\x4e\xf7\x02\x57\x32\xcd\xe0\x38\x80\x1e\xc7\xe8\xd9\x0a\x9a\x1b\xba\x04\x7f\xe6\x28\x35\x1b\x3b\x89\xd0\xbc\x5a\xe6\x65\xa7\x00\x89\x1f\x09\xeb\xee\xc0\x55\x91\x84\x2a\xdf\xcc\x25\xad\xc3\xc7\x1c\x1e\xbc\x4a\x31\x2e\x54\x71\xbe\x67\x25\x3b\x0e\x94\x28\xb0\xca\xe3\x76\x45\xa0\xf7\xec\xb8\x9d\xd7\x9f\xbd\x9b\xe2\x87\x54\x33\x66\x7a\xe0\x7d\x74\xa7\x98\x3c\x4c\xea\x60\x1e\x72\xe9\x75\xc2\x1d\xf9\x93\xe7\xfa\x22\xa9\xfa\xbd\x45\x45\x5d\x45\xe3\x70\x31\x55\x8e\x13\xa7\xa4\xf5\xf4\x97\xea\x78\xfb\x73\x99\xf8\x83\x8c\x0f\xd5\xde\x4e\xbb\x66\xdb\x29\x0f\x43\xa4\x86\x7d\x50\x53\x09\xf1\xc1\xbc\x27\xe9\xfa\xbc\xbb\xa7\x13\x02\xfc\x12\x04\x71\x5c\xe3\xfc\xb0\x90\x5b\xfa\x41\x1c\x9d\x1c\x9a\xb4\xa3\x99\x54\xe5\x0b\x8e\x0c\xf7\x36\xc1\x02\x89\x56\x3b\xdf\xa9\x67\x55\x3c\x36\xcd\x9e\x55\x5b\xc8\xcc\x56\xbe\x59\x48\x47\xde\x9f\x26\xf9"}, -{{0x38,0x84,0xb8,0xb7,0x9a,0xbf,0xd3,0xbe,0x6c,0x13,0x98,0x5e,0xb8,0x59,0xab,0x74,0x3f,0x15,0x7c,0xd9,0xde,0xb8,0x1b,0x2f,0xe9,0x7e,0xa4,0xd6,0x17,0x3e,0x46,0xf5,},{0xbd,0x7f,0xd9,0xa8,0xde,0xf1,0x3a,0x54,0x2e,0xd2,0xf2,0xfb,0x04,0x88,0x86,0x88,0x5b,0xa9,0xb5,0xce,0x59,0xcb,0x70,0x19,0xfb,0x54,0x66,0x79,0x86,0xee,0xbc,0x26,},{0xf4,0x20,0x6f,0xcd,0x34,0x50,0x24,0x41,0xd5,0x4a,0x73,0x32,0x3f,0x33,0xa5,0xdb,0xb4,0xc9,0x85,0x57,0x31,0x9f,0x21,0x24,0x6f,0x26,0x0f,0xfb,0xbe,0x58,0x44,0x88,0x6d,0xb5,0x67,0xf4,0xb6,0x3c,0x47,0x94,0x3d,0xbb,0x78,0xfc,0x35,0x65,0x7d,0x7c,0x04,0xd4,0xfe,0xb0,0x42,0xff,0x85,0x36,0xf6,0x72,0x92,0x5c,0x31,0x9e,0xfb,0x09,},"\x12\xad\xaf\xe3\x0e\xaf\x2b\x9c\x72\x03\xca\x5d\x44\xb9\x7f\xfe\xd4\xbf\x65\x17\xa4\x99\x88\xe4\xe6\x76\xc8\xe3\x14\xad\xbd\xbe\x23\xd8\xf2\xd3\xe2\xb0\x81\xa7\x02\x4f\xa5\x25\xab\x5a\xae\x26\xe6\x00\x57\xc1\x01\xe8\xf3\x68\xd3\xad\xdb\x93\x76\xc4\x68\x2c\x1f\x42\x24\xd7\xf1\x49\xa8\x47\x4b\xb9\xa8\xf6\x63\xef\x21\x0e\x95\x72\xce\x82\x9d\xa3\x88\xd8\xaa\xe7\x2a\x46\x71\x41\xad\xc1\x53\x47\x3b\xe3\x65\x3b\xaa\xa6\x4b\x5b\x1e\x2e\x30\x68\x3f\x6f\x06\xda\xc2\x78\x4d\x5b\xbf\x0d\x08\x2a\xab\x47\x30\x5e\xd8\xa8\xef\xd0\x88\x6c\xe6\x3a\x17\x93\x15\x22\x5d\x1e\x4d\x4f\xfc\xf1\xf2\x4a\xc2\xf4\x64\xcf\x5e\xd3\xa8\xb6\xd3\x99\x84\x54\xf1\xc0\x2c\xdb\xf0\xa4\x44\xee\x2b\x59\xdd\xbe\x0a\x17\x4a\x0d\x93\x7f\xa6\x28\x65\x08\x8a\xc6\x47\x49\x99\x57\xd2\x81\xc6\x94\x98\x03\xa5\xfb\xdf\xdd\x0d\xd9\xe9\x1b\x69\x76\x86\x1f\x3c\x5f\x21\x26\xf3\x9a\xac\x93\x5b\xe0\x9f\x4b\x97\x15\xbd\x4f\x0d\x5c\x55\xdf\x73\xa6\xb9\xf2\xc0\xad\x26\xce\x49\xd8\x22\xbf\x85\xbf\xa2\x34\x6f\x31\x65\xb0\x38\x59\xa7\x1c\x3d\x2a\x7b\x86\xdb\x6e\x9f\x2e\x5d\x7b\x16\x9a\x91\x0e\xeb\x7e\xf3\x8f\xbd\xfb\xbe\xc4\x3a\x9a\x25\xf0\x4b\xc3\xac\xfd\x3b\x06\x91\x54\x2a\xb6\xde\x9d\xb6\xf0\x30\x58\xf9\x58\x40\x24\xf9\x91\x8e\xde\xcd\x90\xfb\xb8\x57\x35\xd6\xdc\xec\x5b\xd5\x93\xae\x63\xe2\xcc\x96\x55\x35\x99\xa3\x10\xf8\xf2\x00\x9b\xa9\x53\x71\x19\x6b\x4d\x5b\x80\xe7\x55\x96\x37\xf2\x29\x26\x77\x8b\xe5\xe1\xcc\xef\x51\x26\xe2\x44\x3f\xa9\x39\xc2\xa5\x3d\xdd\xb0\x49\x61\xee\xfd\x34\xe5\x38\xcd\x8d\x7f\x0b\xec\x2b\xff\x1e\xf0\xd3\xa4\xbd\xd3\x58\x31\x76\x37\xf4\x2d\x59\x55\x38\xc1\x12\x22\x51\xa9\x4e\x96\x3d\x1f\x81\xe7\xb9\xae\xb1\x64\xf9\x5d\xa9\xa4\xed\x75\x29\xb8\x45\xeb\xc9\x61\xb2\x7b\x5c\x19"}, -{{0xec,0xd5,0x19,0xf2,0x87,0xad,0x39,0x50,0x52,0xb0,0xb3,0x0d,0xea,0xc3,0x41,0xd2,0xa9,0xdf,0x13,0xd6,0x56,0x7c,0x89,0x1c,0x81,0x3a,0x0c,0x9c,0xa5,0x2e,0x87,0x1e,},{0x8e,0xe9,0x4c,0x58,0x8e,0x0b,0x34,0x35,0x85,0xfc,0x67,0x48,0xfd,0x1b,0x54,0xb5,0x77,0x0c,0x64,0xe9,0x93,0x7a,0x56,0x35,0x7a,0x48,0xd4,0x4a,0xe2,0xf5,0x18,0x24,},{0xe8,0xf5,0x1b,0xe7,0x3f,0xc4,0xe0,0x23,0x5a,0xa1,0x53,0xa2,0xe1,0xb3,0x54,0xe9,0xc5,0xd2,0xd3,0x3a,0x11,0xae,0x0e,0x33,0x34,0x78,0xde,0x1d,0x8e,0x6c,0x44,0x56,0xd2,0xe2,0x50,0x82,0x4c,0x32,0x46,0xca,0x0e,0x8d,0x6a,0xe3,0xe1,0x66,0x77,0xa9,0x73,0x44,0x14,0x41,0x08,0xc1,0x3b,0x95,0x9e,0x1d,0xaf,0x51,0xcf,0x0f,0xe5,0x01,},"\xaa\x71\xbe\x5f\x55\x7e\x10\xc9\xfb\x5f\x09\x1a\x3a\x27\x44\x53\x94\x7c\x07\xa0\xe2\x5b\x26\xf9\x50\x92\x24\x54\x1d\xff\x76\xf4\xd9\x6e\xff\xd0\xd5\xa4\x1d\x31\x9b\xc9\x32\x1a\x86\x66\x7d\x55\xcf\x49\x43\x2f\xb5\xc3\xe7\x15\x38\x8f\x3f\x10\x6c\x91\x74\xb1\x61\x0c\x8f\x30\x75\xd5\x93\x1c\x29\x00\x99\x38\x5c\xe9\x24\x9e\x23\x51\x28\xe9\x07\xc5\x33\x90\x03\x6f\xbf\x5d\xa9\x68\xf8\xd0\x12\x33\x69\x58\xde\x90\xc5\xe8\xe6\xb1\x01\x6a\xd4\x3f\xb5\x7c\x8e\x28\x8d\xaf\xe1\x4e\x90\xe6\x4b\x63\x79\x1e\x5c\xbe\x55\x7e\x02\xdf\x8a\xc9\x37\x06\x42\xa7\x1f\xaf\x85\x10\x75\xe5\x56\x5f\x6f\x9a\x26\x7f\x4f\x6b\x45\x4c\xe4\xc5\x47\x48\x10\xb8\x04\x84\x4d\xda\x38\x39\x29\x39\x71\x97\x93\x24\x6a\xa4\x74\x54\xb9\xb0\xe8\x2e\x98\x03\xc0\x99\x35\xd0\x02\x7f\x39\x95\xcc\xa9\x71\x30\x69\xbb\x31\x02\x7f\x7b\x2a\xf1\x2f\xe5\xfe\xec\x7e\xeb\x06\x84\x3d\x82\x96\xec\x56\x82\x26\x2a\x07\xda\xe7\x47\xed\x7b\xc8\x21\xec\x17\x01\x8d\x89\x9f\xd1\x67\xb3\x6a\x7e\x37\x73\xb4\x27\x49\x9d\x99\xdc\x58\x3b\xbe\x4b\x42\x9a\xfa\x6a\x26\x59\x39\x53\xf9\x43\xe4\x67\x3b\xdd\x0d\x2a\x84\x42\x56\x13\x16\x03\xcd\x09\x03\x25\x6f\x33\x4d\x4f\x8e\xc8\x2d\xe1\x15\xb6\xca\x53\x38\xc7\x5c\x8b\xaa\x44\xb4\xba\x96\x3c\x7c\x78\x51\x0d\x8d\xe9\xb2\xa5\x85\x2f\x42\xf3\x46\x3c\x68\x5f\xb3\xa6\xda\x61\xa8\xe0\x89\x26\x62\xd6\xa2\x50\xfc\xaa\x6f\xef\x74\xd4\x50\xfc\x45\x7b\x98\x71\xd0\x8b\xb5\xbe\x30\x11\x29\x4a\xc8\x88\xfc\xe2\x15\xd5\x35\xc3\xb1\xa4\x3b\xb4\x7e\xfe\x3a\xd2\x5d\xa1\x59\x19\x1a\xed\x55\x19\x54\x69\xc5\x90\x93\xff\xb2\x4f\x65\xd6\x0c\x40\x20\xbf\xbe\x64\x7f\xf5\xdb\x7a\xb8\xa0\x1d\x5e\x48\x7b\x0b\x1b\x64\xef\x25\xda\x15\x6d\xb1\x42\xe6\xad\x87\x2a\x4d\xc1\xee\x9b\xa6\x68\x46\x52\x65\x37\x9e"}, -{{0x19,0x3f,0x3c,0x63,0x0f,0x0c,0x85,0x5b,0x52,0x9f,0x34,0xa4,0x4e,0x94,0x49,0x70,0xf4,0xa6,0x97,0x2e,0x6c,0x38,0x59,0x35,0x9c,0x2e,0x0c,0x87,0x62,0xba,0x9e,0xaf,},{0x32,0x56,0xf2,0xc8,0x2e,0x7c,0x80,0x12,0x01,0x21,0x01,0x40,0x56,0x9f,0xaf,0x18,0x50,0x7e,0x60,0x33,0x8c,0x2c,0xc4,0x11,0x8b,0xb1,0xce,0x60,0x5b,0x0e,0xbe,0x61,},{0xb1,0x25,0x10,0xac,0x5f,0x2f,0x6d,0x33,0x36,0x0c,0xdd,0xc6,0x72,0x91,0xd6,0xc2,0x70,0xfd,0x9e,0xe6,0x2d,0xc0,0x86,0xb3,0x8d,0x93,0x2d,0x26,0x47,0x3f,0xe9,0xa2,0x4e,0xfb,0xd4,0x24,0x88,0x67,0xea,0x7e,0x91,0x5a,0x30,0xc5,0xbf,0xb3,0xb8,0xb1,0x9a,0xa0,0x1a,0xa2,0xfe,0xbf,0x0d,0xac,0x6c,0xfd,0x66,0x38,0xa2,0xba,0x7e,0x0c,},"\x98\x62\x3f\x65\x16\x98\x08\x5b\xde\x02\x76\x2e\x8c\x33\x21\xf1\x4d\xa1\x61\x9b\x5c\x3f\x7c\x1a\x56\x8e\x8c\x26\xff\x0c\x62\xfd\xcc\x41\x24\x75\x91\x2e\xb8\xe8\xc4\xb0\xd3\x09\x18\xb8\xff\xee\xf3\x50\x93\x15\xe5\x8d\xa3\x59\xcd\xc2\xf2\x6b\xeb\xfb\x57\x03\x95\x3b\xe1\x6b\x8f\x3b\xeb\x1e\x54\xa1\xab\xee\x0a\xeb\xe2\x4e\x64\xdb\xe8\x73\x40\x2e\x15\x6f\x37\xdf\xc1\x68\xea\xf8\xa1\x14\xce\x08\xa6\x79\x5d\x3f\x64\xf5\x15\x1e\x9a\x8b\x82\x75\xcc\x7b\x49\xa6\xb8\xd8\xa6\x6b\x6d\x4b\x76\x32\xef\x80\x74\x0d\xc1\xc1\xb0\xa3\x8d\x1a\x28\xf7\xc1\xb2\x9f\xa4\x45\x41\xc1\xaa\xd3\x54\xd4\x59\x0c\x23\x1d\xae\x68\x7a\x2a\x8f\xed\x09\xe8\xc1\xeb\xbf\xcc\x38\xf3\x47\xbf\x06\xd9\x45\x77\xe4\x9a\xd1\x39\xf7\x10\xed\x8b\xb1\xfd\x07\x66\x3c\x03\x20\x84\x6f\xbb\x45\x5a\xb8\x37\xef\x96\x4a\xe7\xd4\xec\xee\xa4\x5f\xd7\xbd\x8d\x50\x9f\x82\x1e\x6e\xb0\x27\x49\x4e\xfd\x8d\xd8\xe9\x92\xb8\x86\x98\xee\xc2\xeb\xc5\xe0\x30\x25\xbe\x78\x9c\x18\x01\x3f\x20\x1f\x77\xaa\x2d\x34\xf5\x68\x64\x60\xe4\x3f\xb4\x89\xe0\x87\x76\xf9\x8b\xcd\xe2\xce\xeb\x9d\x4f\xaf\xdf\xfe\x03\x75\x60\x43\x71\xec\x32\xf4\x6b\x81\xfe\xc4\x74\x38\x29\x08\xe9\xd2\x50\xa0\xba\x27\x80\xa7\xd6\xdf\x40\x7b\xd2\xb1\xeb\x12\x67\x48\xd7\x25\x11\xb9\xb0\x69\xeb\x1c\xd4\x42\x70\xf2\x9f\xe8\x4b\x9a\x71\x77\x51\x83\x1d\x04\xc2\x81\x8e\x40\x8f\x22\x78\x93\x76\xc6\x1c\x2c\xa4\x5e\x32\xe7\x88\xea\xd3\xa7\x53\x6b\xf0\x9d\xa8\xaf\x47\x03\x90\x2f\x55\x16\xa0\x20\xd8\x92\x63\xe9\x37\x01\xa2\x56\x5e\xef\x12\x70\x41\x89\x25\xf3\x5a\x28\x8e\x32\x7b\xab\x62\x8a\xc2\xf0\x24\x8c\xfb\xca\x34\x82\xe2\x65\xd1\x62\x1c\xc3\x43\xc3\x1f\x65\x49\x3f\x06\x4b\xad\x0d\x76\x02\x46\x07\x15\xfa\x48\x6f\x29\x42\x63\x46\xaf\x53\xe3\x33\xb7\x5f\x59\x05"}, -{{0xa8,0x8a,0xd0,0x04,0x8d,0x38,0xc4,0x4c,0xeb,0xe7,0x35,0xea,0x38,0x02,0xca,0x57,0x6e,0x37,0x12,0x1c,0x7d,0x4d,0x76,0x0d,0xfd,0x88,0xde,0x16,0x63,0x06,0x4a,0xbb,},{0x14,0xdd,0x8b,0xb3,0x06,0x80,0x3e,0x5a,0x75,0x8e,0xd6,0x8a,0xd2,0x1d,0x07,0xd8,0x81,0x61,0xd5,0x0f,0x1c,0x74,0x71,0x37,0x77,0xda,0x12,0x09,0xaf,0xba,0xea,0x0b,},{0x13,0x41,0xa1,0x48,0xda,0x45,0x93,0xc8,0x8e,0xbc,0x5a,0x58,0x82,0x1e,0xef,0x77,0xf9,0x21,0x86,0x39,0x0f,0xf6,0x33,0xe7,0x62,0x07,0x08,0x4e,0x78,0x74,0xcc,0xf0,0xeb,0x1f,0x9e,0xc7,0x0a,0x3a,0x3f,0x96,0xb5,0x89,0x34,0xbc,0xb0,0x61,0xff,0x92,0x01,0x24,0xf7,0xe5,0x80,0xfa,0x2b,0x0b,0x27,0x95,0x83,0xad,0xf9,0x23,0x2d,0x0c,},"\x2c\xe8\xbc\xa2\x61\x78\x91\x3b\x16\x76\xe9\x0f\xfe\xfd\x94\x5b\xc5\x61\x98\x26\x60\xe2\xa7\x5d\x48\x2f\xf3\x0a\xab\xa1\xba\x43\xf8\x2d\x2e\x6b\x90\x9e\xc1\x0f\xc0\x97\x89\xff\x5c\xf3\x2a\x51\x80\xb6\x01\xea\x80\xfa\xde\xce\x6d\x7e\x7b\xae\xef\x48\x1d\xc6\x97\x9e\x2f\x65\x8a\xe0\xf6\xd8\xe4\x16\xb9\x32\x98\xf7\xd3\x40\x31\xbb\x76\xf7\x16\xed\x99\x1a\x16\xd0\x9a\x58\x2e\x58\xba\x40\x03\xac\x17\xbe\x8b\x44\x69\xe1\xa8\x89\xb2\xfb\xb2\x28\x9e\x98\xaf\x1c\x6d\x5b\xbe\xe7\x77\x56\x71\x3c\x07\x78\xb0\xdc\x44\x6a\x1f\x6c\x48\xc4\xd4\x08\x18\xec\x79\x99\x05\xf0\x69\xbc\x95\x34\x16\x57\xca\x5d\x02\xb7\xa5\x39\xa1\x3a\x02\xcd\x03\x76\xa5\x0e\x83\x43\xc0\xdc\x20\x34\x6d\xe5\x27\x5b\x1d\xcd\x4a\xd7\xaf\x72\x51\x31\xac\x75\xe9\x54\x82\x5d\x30\xea\xa5\x7a\x68\xbb\x98\xdf\xc4\x1c\xaf\xe5\x71\x05\x56\x64\x7b\x38\x7d\x9b\x7f\xd4\xe4\x76\x51\xe5\x13\x80\x50\x79\x8f\x6d\x40\xf4\xee\x71\x20\xb5\x8f\x74\xda\x94\xd7\x3c\xac\xbf\xd3\x93\xd1\x34\x73\x88\xee\x00\xb7\x9b\x8d\xbf\xeb\x57\x81\x41\x21\xbd\xda\x60\xc6\x27\xdc\xe1\x47\xd4\xd5\x68\xd7\x90\x52\xe9\x7b\x9a\x5f\x3e\xb5\x40\x7c\xc4\x64\x61\xa5\x5e\x18\xa9\x60\xd8\x09\x4a\x5f\xea\x48\xb6\x93\x75\x29\xcc\x4e\xc9\x19\xcd\xbe\xdf\x91\x85\x45\x6d\xc0\x0e\x8d\x98\xad\x15\x37\xee\x10\xa0\x57\xf4\xee\xc4\xb8\x1d\xc6\x03\x92\xfc\x91\x88\xd3\xe5\x61\x78\x59\x65\x09\x2e\x44\x31\x7f\x2a\x48\xe3\x66\x05\xfc\x58\x3f\xc1\x73\xb0\x5d\xb9\xdc\xbc\x75\x57\xd0\x64\x87\x39\x0f\xbb\xba\x77\xaf\x3a\x01\x4e\x1a\xc3\x51\x39\xca\xa1\xc5\x3a\x8d\x17\x34\x7f\x17\x8e\x1c\x54\xd0\xf5\x2b\x40\xe9\x10\x42\xc9\x3e\x7e\x48\x1d\x79\x2e\x28\x8f\xc2\x7e\x4c\x2f\xcf\x11\x1f\xe9\x7d\x9e\x23\x37\xd2\xfc\x1c\x30\x98\xf0\x66\x84\xa3\x1d\x55\xeb\xf3\x62\xc0\x27"}, -{{0x3f,0x59,0xd6,0xa0,0x18,0xf5,0x0a,0x82,0x21,0x17,0xe5,0xb4,0x73,0x60,0x9e,0x30,0xcd,0x64,0x92,0x0c,0xa1,0xc2,0x75,0x0d,0xcb,0x09,0xea,0xab,0x80,0x7a,0x3e,0xac,},{0x45,0x7d,0x0e,0x59,0xc1,0x1f,0x34,0x8f,0x3b,0xfb,0xdd,0x3f,0x32,0x7d,0xe7,0x8c,0x0a,0x75,0x77,0xc0,0xae,0xef,0x42,0xd4,0xc1,0xe5,0x67,0x00,0xd1,0x08,0x80,0x8b,},{0xd7,0x42,0x5e,0xa1,0x94,0xa6,0x71,0x5c,0x45,0x2e,0xc4,0xf6,0xd6,0xc7,0x6e,0x6d,0xd3,0x74,0xd3,0xca,0x7a,0xe7,0xa1,0x19,0x95,0xd0,0x2b,0x94,0x2d,0x4a,0x31,0x87,0x0d,0xd7,0x34,0xc1,0x2f,0xca,0x89,0xa8,0xeb,0x02,0x13,0xeb,0x13,0x9c,0x14,0xa8,0x7a,0x6a,0x33,0xe8,0x18,0x60,0x3b,0x2e,0x31,0x30,0x23,0xfa,0x58,0x73,0x7d,0x0e,},"\x7d\x10\x3a\x6c\x6b\xa2\xd0\x90\x87\xee\xf2\x25\x4c\x1c\x90\x3f\x06\x76\x95\xa5\x4c\x45\x15\xe4\xd1\x3b\xc1\xfb\xfb\x54\xd6\xe7\xa1\x67\x34\x9c\x14\x80\x99\x76\xda\x04\xa7\xe5\x8d\x96\xb4\x0a\xac\x3b\x2b\xdd\x14\xb9\xb5\x03\x22\xbb\x11\x64\x5f\x05\xe5\xe9\x78\xbc\x7f\xbd\x02\x49\x2e\xf8\x8f\x87\xd6\x68\x28\x0f\xd7\x08\x37\x32\x07\xff\x67\x0f\xcd\xa9\x7d\xf8\x48\x5d\x5e\x46\xdc\x3b\xd0\x43\x47\xf4\xd7\x52\x7e\xab\x27\x18\xf7\xd9\x3d\x13\x2b\xa7\x75\x82\x18\x89\x4e\x75\xa7\xde\xab\xe6\x93\x33\x5b\xa0\xdc\x73\xbf\x26\xc2\x88\xbf\xe9\xbe\x8a\x73\x6d\x75\xe5\xe0\xea\xa7\xbb\xe8\xd0\xb7\x7a\xbd\xd5\x14\x6e\x0f\xc9\xb3\x0d\xb9\xf0\x7c\xf4\xbf\x36\x26\x0a\x1f\x41\x41\x03\x31\xf8\xb4\x7c\x6b\x38\x33\x8c\x6d\xc9\xe8\x01\xff\xe1\xd5\x85\xf9\xb7\xfc\x31\xe9\x77\x8b\xca\x30\x27\xc2\x32\xc0\x74\xcb\x18\xe5\xb7\x29\x97\x00\x5f\xfe\xee\x4b\xf3\x7c\x8f\x87\x4b\x1b\x24\x6a\x63\x45\x41\x5d\xac\xac\xa7\x07\x5a\x60\x44\x3a\xc3\x31\x92\x36\xe2\x3c\xf6\xb7\x54\x47\x40\x80\x70\x52\x11\x49\x84\xb8\xd8\xf7\xe8\x57\xdc\xc6\xfa\xec\x88\x69\xcf\x96\xb9\x97\xdf\xa9\xaf\x91\x84\xad\x62\x3f\x1d\x90\xb8\xca\x75\x9b\x44\x8e\xab\xfc\xe1\x8c\x17\xcf\xdf\x9a\x3e\x33\x12\xe6\x3e\x5f\x08\x4c\xea\x90\x4c\x1c\x90\x99\x13\xcc\x4b\x19\xd0\x44\xa3\x72\x00\x34\x97\x3c\x73\x84\x94\x9b\xd6\xf9\xba\x92\x56\xf9\x8c\xd3\x94\xc5\x66\xda\x83\xc3\x11\x80\x10\x9f\x16\xd1\x03\x47\xb7\xe3\xe9\xdd\x6b\xe3\xbd\x3c\x77\xff\x1a\x79\x96\xa0\x78\xdc\xf8\x9d\xcd\xce\x2d\x1b\x61\x56\x95\xf4\xcc\x9f\x8f\x4f\x2a\x08\x80\x46\x41\xbc\xa8\x26\x62\xce\x88\xfa\xa5\x31\x45\xb6\xa4\x59\x55\xae\xc8\xcc\x2a\xf8\x1c\xcc\xb5\xd7\xc6\x4f\x9e\xce\x1c\x99\x83\x32\x64\x84\xa1\xe5\xec\xe4\xce\x36\x54\x4d\x63\x73\x5f\x77\x76\xf2\x1a\x20"}, -{{0xa1,0x21,0x2b,0x34,0xdb,0xca,0x63,0xb7,0x09,0x36,0x12,0xd0,0x5d,0xab,0x7b,0x4c,0xc8,0xf7,0xb6,0x76,0xa9,0x34,0xad,0x01,0xf6,0x59,0x85,0x1b,0x3b,0xb4,0x4e,0x4e,},{0xba,0x2f,0xcc,0xea,0x9a,0x08,0x05,0x91,0xbe,0x71,0x26,0x8d,0x7e,0x95,0x1f,0x25,0x0d,0xed,0xc0,0x04,0x16,0xe5,0xf3,0xf9,0x08,0xdb,0x6c,0xc5,0x71,0x25,0x49,0x25,},{0xfa,0x93,0xed,0x65,0x95,0xbc,0x95,0x8d,0xc0,0x42,0xce,0x16,0x45,0x16,0x7b,0x79,0xe8,0xf6,0x73,0x4c,0x46,0xf8,0x0f,0x63,0x1f,0xd5,0x48,0x49,0x08,0xf5,0xe5,0x1a,0x22,0x42,0x7e,0xe6,0x86,0xf5,0x64,0xff,0x98,0x2f,0x6e,0xf4,0xd2,0xca,0x1f,0x0c,0xa5,0x62,0x49,0x10,0xcd,0xd6,0x3c,0x11,0xa3,0xc2,0xb1,0x6d,0x40,0x97,0x3c,0x07,},"\x07\xc3\x7c\x46\xbe\x3c\x68\xd0\x56\x89\x57\x7a\xa6\x4a\x93\x2b\x90\x64\x46\xb2\x9b\xaf\x12\xf6\x17\x4a\x6b\x42\xbb\xae\xfd\x1f\x1f\x37\x3e\x0b\xcc\xc4\x73\xdd\xfc\xee\x1a\x7f\x21\xb9\x6a\x62\x60\xef\x0a\xa1\xf2\xd8\xb2\x95\x9e\x71\xd1\x2c\x95\x33\x58\xa2\x77\x4c\xc5\xe6\xf3\x79\xa3\x13\xe4\x35\xed\x69\xdf\xd6\xd4\xa5\x9a\xde\xe3\xcc\x7e\xc4\xba\xcb\xdb\xb3\xfe\xe5\x43\x0b\x73\xf6\x05\x1a\x60\x96\xc6\x0e\x9b\xc9\x2c\xc8\xfa\x05\x9f\xac\x2a\x93\xef\x70\x07\xd6\x4f\xbe\x50\x06\x49\x64\xd5\xa0\xad\x60\x11\x75\xcd\x9c\xab\xa4\x53\xf9\x10\x3b\x25\x48\x55\x45\xd3\x01\xf0\x3c\x5f\x9f\x94\x78\xbd\xf9\xd4\x14\xbf\x1d\xca\x3b\x1c\x1d\x9d\xaa\x99\x71\xf9\xe6\x17\xfb\xfa\xf5\xb0\x2a\x7f\xbd\x5d\x4f\xb8\x94\xc0\x97\x5c\x54\x59\x2b\x49\xa0\xfc\x85\xdd\x08\x53\xf3\x0c\x51\x50\x2d\x98\xfc\x1a\xb8\x5a\x17\xcc\x58\x96\x1a\xae\x97\x64\x57\x0b\xa5\xcb\xdb\xc9\x6d\xfc\xeb\x8d\x11\xda\x53\x36\x4b\x40\x25\xfe\x0b\x8b\xa8\xa3\x53\xad\x23\x68\x67\x20\x16\x9f\xe9\x73\x43\x2f\xfe\x29\x1a\x4b\x11\xde\xdd\xa0\xaa\xc7\x9a\x5e\x42\x62\x0a\x64\x58\x7d\x20\x59\xe7\x87\x01\x3b\x40\xce\xec\x59\x92\x08\xf6\x6e\xd0\xca\x6e\x1b\xe9\x09\x2e\xc2\x7d\xb2\x16\xee\x6d\xad\xfe\xbc\x21\x70\x5b\xc4\xa8\x5a\xee\x57\x7e\x57\xd2\x39\xaf\x58\x6e\xfe\xec\x22\xcf\x38\xd1\xcf\xb3\xcd\x74\xdd\x0d\x9a\x33\x81\xaa\x81\xe6\xa2\x97\xe3\x9b\x81\x91\x37\xad\x27\xd4\x75\xe2\xbf\x54\xaa\x42\x6d\xc2\x9c\x4c\xa8\x17\x6d\xf3\x43\x13\x7a\x2d\x79\xd1\x2e\xf9\xaa\x7b\xe1\xcf\x67\x75\xe5\xd8\xa4\x43\x0a\x85\xc3\x3d\xb6\x1c\xd2\xf3\x51\x87\xb4\xf6\xea\x9e\xbd\xd7\x53\xd1\xc4\xef\x72\x47\x11\x59\xff\x07\xb7\x78\x70\x90\x64\x96\x24\x9d\x42\x78\xe3\xf3\xca\x6b\xcb\xf3\x7a\x26\x5b\x89\x65\x39\x19\x0f\x9a\x31\xf1\xe7\xb4\xb6\x5c\xd1"}, -{{0xd9,0x68,0x20,0x86,0xfe,0x7d,0xda,0x30,0xb8,0x71,0x11,0x06,0x01,0x93,0xd8,0x47,0x56,0x6a,0xb9,0x4c,0xfd,0x9c,0x97,0xab,0x6b,0x43,0xe7,0xa8,0xd3,0xf7,0x93,0x82,},{0x8b,0x0b,0x13,0x72,0xd8,0x87,0x33,0xef,0x72,0x33,0xf6,0x37,0x97,0x90,0xd1,0xe4,0x6e,0x1e,0x07,0xe9,0xd3,0xfb,0x8b,0x0b,0xe2,0x52,0xed,0x04,0xc5,0xfa,0x16,0x3d,},{0x17,0x93,0xe4,0x97,0xeb,0x52,0x1c,0xa7,0x4e,0x35,0xd1,0x4a,0x63,0x86,0x8c,0xbe,0x94,0x99,0xda,0x2f,0x21,0xb4,0xeb,0x52,0x60,0x34,0x0f,0xca,0x3c,0x1f,0xec,0xa7,0x8d,0xbe,0x5b,0x14,0xac,0x10,0xf3,0xfa,0x76,0xfa,0x2e,0x71,0xe4,0xc9,0x14,0x61,0xaa,0x75,0x97,0x7e,0x5e,0x70,0x79,0x26,0x70,0xef,0x7f,0xf0,0xe6,0xa2,0x87,0x08,},"\xe8\x81\x4b\xe1\x24\xbe\x3c\x63\xcc\x9a\xdb\x03\xaf\x49\x3d\x44\x2f\xf2\x0d\x8b\x20\x0b\x20\xcd\x24\x93\x67\xf4\x17\xf9\xa9\xd8\x93\xfb\xbb\xe8\x5a\x64\x2b\xe2\x70\x1d\x1d\x1b\x3c\xd4\x8a\x85\xcf\x58\xf1\x59\xa1\x97\x27\x31\x43\xa5\x78\xf4\x2e\x8b\xcc\x8b\x62\x40\xf9\x32\x71\x90\x05\x38\xff\xc1\x87\xc0\xaf\xc8\xdb\xcc\x49\x2b\xcd\x67\x9b\xaa\xef\x3a\xf5\x08\x84\x34\xa9\x45\x86\xf9\x4b\x49\x97\x0b\xba\x18\xf5\xea\x0e\xbf\x0d\x27\xee\x48\x2a\xa8\x3a\xd0\xdd\x0e\xe6\x09\xdf\x59\xd3\x7f\x81\x8b\x2c\x8d\x7c\x15\xf0\xf6\xf5\x44\xdd\x4c\x7e\x7c\xb3\xa1\x67\x24\x32\x4f\x77\xd5\x89\x48\xf8\x47\x5a\x60\xd5\x3e\x5b\xd5\x10\xc1\x71\x37\xc9\x9e\x1c\xfa\x51\x5a\xf9\xbc\x85\x56\x9d\x21\x2a\x21\x19\x07\x29\xf2\x81\x7d\xe8\xc4\x69\x15\xe0\x21\xdf\x70\xff\x6d\x60\x21\x5f\x61\x4f\xc2\x11\x39\x90\x4d\xf3\xb2\x92\xb7\x49\xdc\x4d\xea\x02\x51\x8b\x62\xd1\x58\x62\xc9\x2d\x2a\x4c\x99\x67\x01\xcd\xec\xae\xd8\x4a\xb6\x28\xee\x98\x4f\xc1\x11\xee\xcb\x59\xe4\x84\x44\xef\xc0\xd4\x56\xe2\xc8\x52\x51\x84\x41\xc3\xdb\x76\x30\xdd\xd5\x15\x62\x49\xa2\x87\x30\x98\x38\x38\xae\x59\xac\x4c\xc7\x11\x0f\xd6\xde\x68\x10\x1e\xa5\xb2\xff\x69\xfd\x36\x4e\x3c\x94\x48\xde\xfe\xfe\x17\x5b\xcb\xe1\x17\xcc\x11\xb4\xff\x75\x49\xc3\x3e\x10\x25\xb6\xb5\x92\x04\x8a\x8e\x31\x96\x9e\x81\x8d\xcc\x18\x8b\xb1\x9d\x7a\x24\x40\xa3\xba\xba\x4e\xb1\xb8\x1c\x45\x67\x9d\xb4\x6b\x31\xbc\xde\x77\x76\x75\x7d\x99\x31\xec\x20\x63\xfc\x6f\x1f\xcd\x76\x1e\xcc\x57\xa7\xd0\x30\xa8\x5e\xa2\x73\xef\x18\x25\xb0\x50\x92\xab\x96\x45\x35\x9a\x44\x4f\xf7\xd1\x66\xb5\x75\xfa\xc2\x98\x30\x8d\x9f\xaa\x68\x46\x3d\x1d\x0f\x7b\x7d\xf8\xa5\x1c\x68\x15\xd3\x71\x59\xad\xc0\xb5\x93\x22\x4a\x81\x83\x21\xd7\x21\x9f\x09\x68\x6c\xfc\x95\x22\x59\x71\x8d\xfc"}, -{{0xb5,0x2b,0x24,0x9a,0x7a,0xea,0xe0,0xfb,0xd9,0x4f,0xfc,0xf9,0xa9,0xfd,0xe1,0x0d,0xe6,0x1c,0x3f,0x4c,0xbd,0xa1,0x4b,0x28,0x9f,0xe0,0x1f,0x82,0x70,0x73,0x34,0xca,},{0x73,0x51,0x63,0xbf,0xcf,0xd5,0x4f,0x9d,0x35,0x2e,0x1c,0x2f,0x3c,0x01,0x70,0xc9,0x5c,0x18,0x42,0xcc,0xc7,0x42,0x16,0x23,0xae,0x04,0x96,0x98,0x0c,0xee,0x79,0x1c,},{0x6f,0x48,0xa9,0xf7,0xf0,0xfa,0x19,0x2b,0x66,0xd1,0x21,0x75,0xa3,0x33,0x61,0x23,0x03,0xe1,0x80,0xb9,0xfa,0xb1,0x8e,0xda,0xbe,0xbc,0xdf,0x66,0x74,0xfd,0xfc,0xc5,0x36,0x07,0x08,0x9b,0xf9,0x80,0xce,0x35,0x89,0x4c,0x2f,0x9b,0xab,0xdc,0x44,0x38,0x66,0x7a,0xb3,0x29,0x7a,0x62,0x48,0xec,0x02,0x69,0xfa,0xa9,0x9c,0x72,0x48,0x07,},"\x1d\x44\x5e\x8e\xe3\x6f\x6e\x10\x64\xee\x12\x81\xe6\xb4\xa4\xce\xc5\x0a\x91\xc2\xb6\x67\xc8\x30\x5d\x1e\x9a\x5f\x7b\x73\xa3\x44\x58\x82\x58\x1f\xb0\xc1\x1e\x64\xf6\xee\x92\xe8\x11\xf9\xf2\xd6\xc5\x9c\x63\x44\xbe\x76\x91\xd1\x16\xdd\xa4\x93\xca\xde\x51\xc0\xce\x77\x37\x2b\x61\xa7\xc4\xfb\xb6\x33\x40\x13\x33\xcb\xf7\x13\x72\xad\x2f\x04\x4e\x99\x2a\xc0\x35\xf5\x87\x9c\x05\x30\x04\xf8\x22\x3f\x23\x7a\x24\xa4\x09\xb7\x89\x4f\x6a\xd5\x18\xe0\x46\xb8\xa8\x4c\x3f\x4c\x62\x60\xe6\x16\x9f\xd9\x44\xd5\x7f\xbc\xf9\xba\x27\x75\xf2\xd6\x0e\xd7\x72\xc4\x6c\xcd\x63\xc8\x50\xb8\x0d\x58\x7c\x52\x08\xdf\xb1\xa2\x58\x78\xc0\x2d\xec\xe3\xe6\x02\xe9\x63\x2f\xc3\xc2\xc7\x9b\x25\xab\x41\x03\x4c\x6e\x26\xb8\x69\x25\x53\x57\xa6\x86\x78\x1d\xfe\x6e\x64\x4b\xeb\xa9\xb6\x27\xda\x1f\xcb\x5e\xc0\xbe\x49\x7c\xf1\x88\xe1\xef\x1a\xf0\x60\x1b\xf1\x6b\x29\x11\xfd\x9f\xf3\x4f\x0e\x97\xac\x95\xa7\xfe\x2c\xf9\x0e\xa6\xce\xd3\x3c\xcb\x0e\xd1\xef\x2d\x41\x60\xef\xb0\x7c\x59\x1a\x5c\xb1\x6c\x70\xca\x16\x94\xfb\x36\xf2\xca\x19\xeb\xa5\x2b\xe3\xd4\xad\x89\x5a\xbc\xad\xa4\xb3\x6f\x02\x61\xd6\x5f\x59\xe0\xcf\xd2\xa6\x14\x8a\x88\x92\xdd\xbb\x45\x81\x0d\xb3\xbf\x4a\x9e\x26\xe9\x2c\x15\xea\x26\x18\xcf\xee\xb4\x62\xd8\x62\x8f\x25\x4f\x54\xd2\xaf\x27\x11\x3b\xab\x4f\x9a\x7d\x06\x79\x18\x11\x94\x2b\xdc\x32\xf8\x45\x92\x2d\x7b\x2d\xdb\xa9\x59\x14\x09\x28\xf8\xc2\x8d\x98\xb4\x4e\x1d\x19\xb9\x7f\xd3\x9c\xc0\xf9\xa5\x23\x6d\x34\x9f\xc8\x35\xac\x49\x21\x92\x46\x2e\x40\xac\x62\x9b\xeb\xff\xd2\xeb\xa7\x2d\x27\x88\xb2\x44\xbb\x77\x7a\xd0\xf7\xb7\xf9\x6f\x23\x41\x23\x99\xfc\x1d\x87\xa1\xd0\x87\xba\x08\x90\x27\xea\xbb\xc0\x5e\xda\xfe\xe4\x33\x79\xe8\x93\x29\x13\x31\xb4\x60\xbf\xa7\x33\x2e\x08\x42\xec\x25\x73\x39\x3d\xe9\x53\x06"}, -{{0x78,0x2a,0x93,0xef,0xe0,0xef,0x06,0xcb,0x25,0x34,0x33,0x0e,0xfd,0x0e,0x96,0x84,0xe9,0x96,0x9b,0x52,0x58,0x12,0x3e,0x49,0x02,0x39,0xbf,0x24,0xbf,0x9f,0x65,0x23,},{0x94,0x2f,0xa1,0x40,0x6e,0xe2,0x68,0x3e,0x29,0x37,0x7e,0x49,0xf7,0xba,0x75,0x7c,0xf5,0x0e,0xf0,0x72,0x37,0x07,0xd4,0x40,0x3d,0x28,0x62,0x25,0x70,0x45,0xde,0x87,},{0x93,0xe7,0x40,0x5a,0x40,0x44,0x51,0x01,0x66,0xc8,0xac,0x26,0x4c,0xe3,0xb5,0xba,0x66,0x65,0xd6,0x8b,0xad,0x45,0x87,0x12,0xdc,0x93,0xc2,0xc3,0x90,0x56,0x8d,0x74,0x02,0xef,0x7d,0x57,0xf5,0x49,0xb8,0xa1,0x04,0x2f,0x7f,0x69,0xa6,0x79,0xaa,0x85,0x5f,0x34,0xf8,0x01,0xd5,0x7d,0x79,0x89,0x5d,0xeb,0x8d,0xea,0xdb,0x35,0x23,0x08,},"\x46\xa4\xe3\x19\xa6\x70\xac\x99\x39\x94\xa5\x33\x00\xc3\xf7\x91\x44\xc2\xf7\xfe\xc1\x11\x6e\xee\xb3\x62\x1c\x76\xac\x35\xda\x79\xdb\xff\x6e\x18\x9c\xa9\xdb\xfc\x9a\xbb\xda\x05\x48\x47\xb2\x97\x1b\x02\xfa\xce\xbb\xe9\x26\xd4\x69\xeb\x0a\x86\x03\x89\xac\x74\x41\x62\xbf\x6f\xb1\x3b\x42\xcb\x9b\xb8\xc9\xd7\x26\x07\x13\x8e\x78\x00\x12\x1e\xe0\xcd\x63\x3e\xd5\x35\xc7\xae\x5f\x40\x60\xbb\xdd\x27\x1c\x9d\x11\x0a\xbf\xf5\xe0\x60\xea\x6e\xe8\x38\x90\xb1\xe9\x2a\x92\x56\xd7\xb2\xba\x98\x2a\x31\x14\xbb\x6d\xef\xfe\xe2\x69\x6f\x0a\x2f\x9c\x21\xaa\xa5\xb2\xde\xfa\x11\xaa\xb7\x07\x6d\xe6\xe5\x7e\x86\xf2\x84\xbb\x67\xf5\xa4\x9e\xe6\x85\x92\x10\x32\xc9\x5b\x74\xe7\xe3\xea\xc7\x23\xf1\x75\xaf\x08\x2c\x85\x8e\x0d\xfa\x01\x72\x8c\x38\xfb\xbb\x4c\x83\x58\x1f\x81\xac\xe6\xc6\x3c\x6b\xda\xac\x56\x20\xeb\x9a\x56\x8e\x7e\xbb\x7b\x72\xb3\xd1\xa1\x64\xef\x52\x4e\x7b\x9f\x00\x79\x9a\xb0\x86\x71\x59\x76\xc1\x4d\x0d\xf6\x5f\x7b\x96\xbf\x9e\xbc\xda\x7f\xee\xef\x11\x34\x22\x00\x1a\x03\xa7\x63\x3d\xf5\xe4\x99\x39\xa1\x21\xdb\x89\x9d\x9b\x8a\xc2\xdb\x4f\xad\x0c\x30\xcf\x0b\x8b\xdb\xc9\xe9\x80\x2a\x79\x7c\x82\x38\xe4\x65\x11\xff\x24\x06\x8c\xad\xcf\xf2\x44\x8c\xc0\xbf\xf9\x27\x69\x22\x33\x48\xd4\x5d\x6b\x6f\x2c\x8f\x15\x93\x38\x8c\x0b\xbb\xf4\x4b\x6d\xdb\x50\xb9\x8c\xd7\xf0\x9c\x73\x0f\x7d\xe4\xd0\x08\x15\x6c\xb3\xcd\xe0\xca\xb3\xad\x0a\x58\xa8\x39\x54\xe2\x34\xa0\xa8\xa0\x4b\x57\x3c\x9a\x8e\x9b\x92\x9e\xd3\x8b\x8b\x22\x8b\xf5\x5a\x3c\x6e\x2c\x6b\x51\xf6\x82\x65\x2f\xbb\x70\x8e\x74\x64\x0e\x33\x13\xe1\x7b\x46\x94\xd7\xfd\xf0\x11\x1f\x90\x60\x8c\x1b\x5a\xf4\x22\xdc\xde\xca\xd9\xdd\xb7\xf5\x0d\x1b\xf5\xbc\x63\x78\xcc\xaf\xfc\x32\x01\xe6\xc7\x87\xb4\x8c\x44\x3b\xa2\x40\xd9\xd5\x0f\xf6\xc0\xe9\xdf\x7f\x1a\x5b"}, -{{0x6f,0xe7,0xbc,0xf7,0xa6,0x84,0x42,0x3d,0xe1,0x07,0x6f,0xd7,0x6d,0xa7,0x83,0x42,0x33,0x73,0xb3,0x81,0x32,0x9e,0xfd,0x61,0x57,0x42,0x4e,0xc4,0xb2,0x65,0x5a,0x94,},{0x77,0x40,0xe9,0x1a,0xfe,0x45,0x32,0x4f,0x8b,0xb9,0x90,0xca,0x2a,0x34,0x12,0x79,0xdd,0xaf,0x23,0x2c,0x3b,0xb4,0x15,0xf1,0x78,0xb6,0x09,0x2f,0xba,0x19,0x5f,0xec,},{0x99,0x14,0xcc,0x50,0xfe,0xf0,0x93,0x5e,0xfb,0x89,0xb3,0xd6,0x4e,0x3c,0x1c,0x34,0x12,0xae,0xd6,0x59,0xb9,0x01,0x66,0x22,0x2c,0x0d,0x13,0xec,0x1c,0xe3,0xa6,0x8a,0xe6,0x28,0x1b,0x7e,0xfd,0x9d,0x4e,0xc6,0x4b,0x82,0xe7,0x3e,0x14,0x47,0x9f,0x03,0xfb,0xac,0x8f,0xa3,0xab,0xdb,0x41,0xea,0x42,0x15,0xc4,0xa4,0xd4,0x94,0x9d,0x09,},"\x0b\xaf\x0a\xd4\x40\x61\x2b\x4c\x5a\x13\x6c\x3a\x42\xbe\x1c\xa2\xb7\xc3\x19\x86\x2a\x44\xa9\xfd\x50\xc4\xee\x73\x54\x1c\x5e\x64\x57\xef\xa8\x18\x25\xb6\xdd\x4a\x72\x19\x4a\x29\x68\x68\x8b\xd4\x9e\x5a\x8f\x4c\x04\xdb\xaf\xc2\xe7\x88\x4c\x0c\x70\xc2\x08\xd4\xe9\x54\xcd\x16\x75\xda\x8e\x74\xc6\x5c\x49\x7c\xf9\xdc\x69\x42\x49\x65\xbd\xcb\xa5\xde\x52\x93\x6f\x92\x5f\x62\xe2\x01\xf9\x95\x05\xd3\x77\x7b\xeb\x3c\x2e\x08\xb2\xec\x9a\x87\x3e\x5a\x9c\x21\xfb\x4a\x2f\x3e\x86\x1f\x3c\xf4\xd6\xb5\xdc\xd1\xc8\x8b\xcd\x91\x63\x53\x9a\xc6\x2c\xd0\x65\x9f\x4e\xf2\x32\xc2\xce\x57\xfc\x77\xf9\x02\x85\xeb\x35\x01\x69\xed\xc6\xa8\x06\xff\x50\xf6\x1c\x7e\x0b\xee\xeb\xec\xec\x63\xbf\xc9\xd3\x98\x3f\x5b\xb4\xb2\x61\xc7\x46\x47\x1f\xcb\xf2\x89\x2c\x61\x08\x97\x0b\x68\xdb\x5e\x43\xc4\x50\x4d\xda\xe2\xd0\xff\xff\xa2\x8b\x67\x59\xae\x11\x28\xe1\x6f\x66\xd4\x92\xad\x61\xe3\x72\x2c\x96\x0f\x88\x69\x2b\xe8\x1a\x9f\x41\x28\x90\xff\xa3\x46\xe7\x02\xc8\x67\xdf\xa2\x59\x70\x3b\x73\xf5\x25\x07\x4f\x32\x27\xc4\x9c\xec\x1b\x64\x5a\x10\x3b\xd4\x47\x1f\x33\xf9\xf1\xba\xc3\x27\xd7\x91\x78\x61\xd0\xad\x91\xab\xee\x60\x22\x2e\xa2\xa3\xc8\xca\xc0\x52\xae\x9a\x2c\xbd\x90\x85\x5d\x73\x3d\x53\x19\x13\x3f\x95\x41\xbd\x0b\x61\xf0\x99\x52\x68\x35\x1e\x28\x63\xc1\xca\x2c\xa5\x1e\x3c\x97\x63\x83\xf5\xc4\xc1\x1f\xf4\x10\x03\x6f\xd5\x1d\x5a\xc5\x6b\x02\x3c\xe9\x02\x9c\x62\x0f\x22\x55\x70\x19\xad\x9b\x42\x64\xed\x4d\x71\xb4\x34\xf4\xa4\xd1\x7a\x7d\x57\x69\xfa\x1e\x14\xa6\x9f\x7a\xe4\x19\xcc\xf5\x94\x7f\x8c\x76\x82\x69\x71\x16\xc2\x40\x5f\x5a\x19\x59\xc5\x4b\x48\xf0\x87\x2f\x59\x6e\xd4\x59\x64\x48\x8d\xde\xc1\x2b\xdb\x63\x6d\x0b\x34\x9e\x74\x9e\xb6\x60\x92\xff\x45\x11\xfb\xa5\x9b\x59\x62\xcb\x93\xcc\x85\x51\x5c\xc8\x6a\xb0\xc6\xb2"}, -{{0xdd,0xa4,0x8a,0x0d,0x15,0xa2,0x9e,0xba,0x9a,0x76,0x30,0x5d,0x36,0x0e,0x46,0x6e,0x72,0xd8,0x04,0x0e,0xfe,0x2e,0x89,0xc0,0x4b,0x64,0x61,0x31,0x5a,0x9b,0x8b,0xf4,},{0x4f,0x5c,0xc3,0x6a,0x80,0x94,0x16,0xb5,0x8e,0x15,0xd2,0x4c,0xc5,0x79,0x68,0xcb,0x57,0x3b,0x76,0xad,0x90,0x88,0x7a,0x8e,0xf3,0x6c,0xde,0x7e,0xca,0x40,0x0f,0xcc,},{0xce,0x71,0xbc,0x82,0xd5,0x31,0xd0,0xf9,0x3b,0x57,0xbf,0xdc,0x2f,0x73,0x16,0xcf,0x40,0x4e,0xe0,0x9a,0xf8,0x8f,0x33,0xbf,0x80,0x6c,0x7c,0xad,0x6b,0x8f,0xfa,0x36,0x62,0x36,0xba,0x74,0xe7,0x5c,0x15,0x09,0x6d,0xda,0xa6,0xe3,0xa6,0x2a,0x8f,0x5e,0xb1,0xc8,0xc3,0xf6,0xb6,0xc9,0x4a,0x6a,0x34,0x9f,0xc7,0xc0,0xcb,0xfb,0x19,0x0d,},"\xf5\xac\x19\xb8\x1f\x21\x11\xa0\xdb\x0a\xe3\x0d\x15\x13\xed\x34\x3e\x7f\x57\xf7\xf7\x7d\x65\xb8\xac\x7c\xe3\xa6\x01\x17\x4b\xae\xd9\xbf\xa1\x36\x03\x59\x76\xf5\x16\xd5\xa8\x70\xf4\x5d\xb1\x91\x9f\x1e\xb1\xcb\xec\xbe\x88\xec\x32\xd1\x91\xe9\x24\x88\x21\xa7\xe7\x68\x1f\xe3\xab\xec\x11\x58\x4b\xdb\x33\xde\x1b\x4c\xa9\x48\x91\xeb\x66\xdc\xb8\x53\x9a\xc4\x11\x63\x73\x6c\xcf\xd6\x9a\xbb\x83\x81\x4d\xd3\x8c\xd6\x03\x81\x31\x87\x28\x05\x2a\x25\xcb\x66\x54\x71\x05\x86\x50\xcc\xc7\x57\x56\xdb\xee\x68\x8a\xb8\x26\xec\xad\x4a\xd5\xa7\xdb\x57\xe8\xf6\x5f\x1b\x64\xab\xff\x82\xdd\x53\x33\x4b\x79\x7a\xc4\x02\x28\xdd\x81\x7f\x23\x9d\x3e\xe8\x04\xa1\x9a\xea\xc8\xcf\xe3\x3e\xb6\x57\xec\x9c\xe9\x23\xd6\xb3\x88\x91\x4c\xfb\xa2\xe7\x2b\xfc\x2b\xc3\xd6\xf9\x85\xc0\xd9\x75\x34\xdb\x95\x8e\xed\xe5\x7b\x16\x49\x1f\xfb\x75\x5c\x1a\x58\xd7\x8a\xb3\x77\xfa\xec\x0d\x31\x18\x18\xe8\x99\x26\x0e\x3e\xbd\x1c\xcd\x29\x24\x6f\xa8\x2d\x0b\x76\x62\x2b\x2c\x4b\xc5\x2f\x54\x9f\xee\x72\xa3\x0f\x55\x4f\x33\x1f\x36\xd2\xa7\x4d\x99\x9e\xc1\x0a\x08\x29\x4f\x00\x2b\x43\x61\xe5\x90\x27\x9c\x2f\xb1\xbd\xa4\x31\x2c\xcb\x24\xd7\x52\x82\xce\x7c\x06\x1a\x0c\xa5\x52\x0c\x74\xf6\xf6\x33\x3b\x18\xc4\xb5\x41\xcb\x6c\x51\xe0\x15\x75\xba\x80\x51\x2f\xfa\x7c\xe0\xac\xcd\x22\xd1\x40\x27\xc5\x3a\xba\x1f\x74\x37\x83\x5f\x11\x14\xd6\x8e\x3a\xcf\x3f\xf8\xde\x94\xc8\xe4\xef\x6d\x3a\xb3\x12\xc9\x1d\x02\x97\x01\x57\x50\x8f\x54\xa5\x81\x6f\x46\x7a\x21\x4e\x9b\x12\x84\x30\x02\x89\xe6\x5f\x36\x5a\x61\x0a\x8e\xa2\x84\x66\x6c\xfe\x55\x18\xe4\x35\xbc\xcd\x21\x62\x75\x01\xc7\x25\xf0\xb8\xeb\x57\x25\xe0\xe0\x6e\x0c\xef\x5d\xb2\x01\xb4\x8e\xc9\x1e\xbf\x87\x8d\xd5\x7c\xe8\xda\xc7\x33\x48\x48\xa1\xbc\x82\xc1\x8b\x06\x59\x55\xe4\xf5\x9b\xe3\x39\x85\x94\xdc"}, -{{0xec,0x57,0xb9,0x41,0xad,0xf3,0xca,0x13,0xe7,0x7a,0x78,0x05,0x77,0xcf,0xd0,0xdf,0x5b,0x49,0xed,0xc8,0x53,0x51,0x05,0x2d,0xa3,0x4e,0x99,0xf8,0xa9,0xbf,0x32,0x08,},{0x28,0x59,0xc0,0x71,0x97,0x8a,0x04,0xb7,0xf5,0x40,0x7b,0x6d,0x22,0x40,0x1a,0x78,0xef,0xd0,0x39,0x4b,0xb9,0x66,0xb9,0xa0,0x4d,0xa6,0xb5,0xef,0x81,0x9d,0xe3,0xfa,},{0x11,0x8e,0x14,0x62,0x12,0x6b,0x45,0xb8,0xc6,0x80,0x35,0x23,0x75,0x5c,0x56,0xdf,0xc4,0xe1,0x23,0xe4,0xac,0xbb,0x66,0xba,0x0b,0xa6,0xfe,0x3e,0x05,0x3d,0xa4,0x11,0x9f,0x57,0x19,0x29,0x5e,0x0c,0x82,0xac,0x64,0xd7,0xc5,0xcb,0x1a,0xc8,0x98,0xdf,0x26,0x3d,0xdf,0xd3,0x60,0xf3,0x00,0x8d,0x91,0x01,0x8b,0x26,0xf6,0xa1,0x73,0x0a,},"\xd2\xbc\xbd\x1b\xc3\x61\xab\x32\xc6\x6d\x72\xfd\x48\xa8\xe2\x27\xdc\x6b\x8d\x6b\x15\x08\x48\xba\x71\x5f\xf4\x7d\xd3\x5c\x8e\x49\x38\x1b\xb4\xe2\x93\x3f\x42\xcd\x26\xb7\x5b\x14\xd9\xc0\x03\x92\x82\xb6\x2b\x85\x56\xaa\xa1\x1c\xd6\x91\xe8\x28\x38\x2b\xe3\x06\x88\x9f\xc9\x20\x51\x37\xb1\x69\xd3\xbf\x17\xb7\xf3\x76\x93\xfc\xe2\x86\x03\x9f\x03\x80\x9d\x7d\x9d\x98\xc8\xfd\xe4\x6f\x11\x01\x94\x2a\x27\x9c\x51\x67\x06\xf5\x01\x91\xa9\x11\x2f\x6a\x24\x63\x0e\x1a\x26\xc3\x21\xe4\x6c\x9c\xcc\x85\xb6\xef\x94\x2f\x35\x3a\x64\x2b\x9e\x7e\xf9\x98\xc0\xfc\xe2\xd3\xa7\x5b\x99\x9e\xeb\x77\xf3\x1f\x9b\x08\x13\xa9\x7e\x30\x14\xc3\xa8\x6e\x25\x58\x73\x46\x21\xa3\x06\x6d\xae\x35\x84\x50\x31\xe3\x56\x65\xf1\x92\x29\x07\xdb\xb7\x39\x78\x6a\x8b\x76\x58\xab\x60\x27\x6f\x2d\x92\x1d\x1a\x51\x23\x0f\xc7\x4d\x19\xe8\x01\x84\xa4\xf1\x0e\x9e\x83\x4a\xbc\x9a\x36\xc4\x29\x72\x6b\xc0\x55\xdc\x8c\x06\x3f\x0e\xca\x9c\x61\xa8\xa9\x70\xbd\x4b\xb5\xf4\x24\xee\x4d\x04\xbf\xc2\x95\xe3\xbb\x1f\x34\xbe\xcb\xd9\x92\x0f\xe2\xe7\x7f\xcf\x36\x76\x3f\x32\xfc\x9c\xfd\x5e\x46\x59\x79\xc1\x67\xca\xbf\x5a\x12\x44\xb4\x91\xfc\x06\xb8\x94\x64\x19\x04\x6b\xa5\x16\xc5\xb2\x33\xc4\x14\xdd\xef\xb6\xda\x04\xf2\xe1\x3d\xaf\xf7\xa9\xa0\xc0\x2a\x51\x8e\xde\x57\xad\x95\x21\xde\x64\xed\xdf\x6f\x49\xa9\x67\x0f\x63\x2d\x3f\x7d\x42\x42\x52\x07\xd0\x53\x60\x4f\xe3\x9d\x13\xb9\xf5\x2c\x8b\xc2\x92\xb0\x07\x6e\xa4\x2a\x56\x00\x56\xdf\x25\xde\x51\xad\x35\x88\x1d\x08\x54\x32\x24\xd7\xfa\x5d\x70\xb8\x60\x3e\xf2\x3c\xe0\x63\x39\xd6\xcd\x09\xe2\x2a\x95\x74\x9e\x50\xdf\xbd\x3b\x8a\xd6\x9f\xd3\x04\x96\xb9\x84\xd1\xc0\xa1\x99\xc8\x59\x48\x05\xf3\x8b\xa4\x46\x31\xa2\xc5\x9e\xad\xc6\x55\x4d\x19\xf9\xbc\x98\x36\x6d\xfd\xec\x2a\x12\x1d\x0e\x48\x14\xd2\xcd\x3f\x58\x71"}, -{{0xcb,0xfd,0x91,0xd7,0x69,0x5c,0x1f,0x27,0x0f,0x69,0x24,0x6a,0xb3,0xdf,0x90,0xed,0xb2,0x14,0x01,0x10,0x1c,0xa7,0xf8,0xf2,0x6c,0x6d,0x00,0xf4,0xdc,0xb7,0x23,0x3e,},{0x51,0x38,0x79,0xcf,0x79,0xd2,0xf4,0x6d,0xf4,0xb8,0x5a,0x5c,0x09,0x49,0xeb,0x21,0x16,0xab,0xf9,0x81,0x73,0x5a,0x30,0x31,0x64,0xcb,0xd8,0x5a,0xdf,0x20,0xb7,0x52,},{0xf3,0x36,0x13,0x7d,0xfe,0x6f,0x42,0xa6,0x66,0x9b,0x55,0xf7,0x4b,0x80,0xb3,0x03,0x5a,0x04,0x03,0x67,0xf9,0x06,0x56,0xfc,0xef,0x0a,0x64,0x4c,0x52,0x27,0x2d,0xdc,0x39,0x27,0x3c,0xd7,0x72,0x60,0x10,0xeb,0xcd,0x8a,0x30,0xa0,0x52,0x01,0xab,0x70,0xb8,0xff,0x97,0xd0,0x28,0x8a,0x2c,0xb9,0x4c,0xbc,0x49,0x02,0x06,0x47,0x39,0x0b,},"\x26\x4a\x93\x3f\x7d\x0a\xec\xba\xc1\x3e\xef\x64\x4b\x0b\x53\xdd\x53\xa1\x28\x09\x04\x10\x0d\xbc\x1a\xb8\x7b\x51\x14\x89\x98\xf9\xda\x0b\x3a\x0a\x63\x37\xf5\xe3\x48\x6c\x2b\x7e\x54\x8d\x21\x12\x59\x39\x7a\xaa\x19\x4e\xe4\x69\x5b\xf9\x8c\x2d\x5f\x44\x87\x69\x9f\x73\x97\xe5\xd3\xa7\xe6\xd5\xf6\x28\xfb\xd0\x54\x97\xc5\x56\xa5\x0a\x4d\x05\xe2\xb7\x12\xcd\xbc\x35\x10\x68\xe4\x2a\xf1\x95\x38\x90\x1b\x88\x25\x31\x0e\x34\x3e\x1a\x17\xa1\x86\x7d\xde\x0e\xb4\x7d\xda\xb4\x56\xd3\x16\xf3\x52\x15\x54\x93\x7b\xf8\x08\xae\x4e\x4b\xc1\xc3\xc5\xb4\x75\x6e\x4a\x16\x5a\xd9\xe8\x82\x7f\x53\x16\xf7\x48\xca\xc6\x99\x8e\xd2\xd2\x10\x4f\x26\x84\x07\xc1\x35\xe6\x2f\x26\xa9\x22\x46\x0e\xab\x6d\x85\x16\x39\xa0\x0e\x5f\x08\xb3\x47\x65\xea\x02\x44\xf4\x75\xbb\xfe\xac\x18\x3e\x3b\x5b\xd1\xaa\xb7\x98\x52\x27\x98\xa0\x8e\xc6\xbf\x22\x57\xd4\x69\x2f\x5b\x03\xcd\xd0\xa2\x13\x3d\xe9\x70\x60\x3e\x32\x51\x47\x5a\xad\x8d\x93\x4a\xf6\xb2\xbf\xc7\xa6\x50\xb9\x1b\xde\xc1\x43\xf8\xad\x25\x4c\xfa\x50\x6b\xbf\xf2\x8a\x03\xbe\xb6\x59\xef\x5e\x5d\xdf\xfe\x76\xe2\x32\x30\xc4\xcc\xd4\x63\x10\xb3\x7d\xd9\x1f\xa6\xaa\x68\x16\x7f\x62\xa5\x5c\x8a\x69\xf9\xed\x1e\xc6\xcd\xb1\x44\xdd\x81\xab\x0b\xcb\xd6\x26\x43\x42\x0b\xca\xe6\x78\x69\xf6\x4c\x0b\x16\x9f\x3c\xdf\x3c\x90\x58\x95\xb7\xd3\x5b\x6f\xaf\xda\x25\xcc\xf2\x3c\x3d\x10\xde\x32\xe7\xf2\x71\xe3\x00\xd3\x95\x97\xda\x8f\x84\x37\x22\xef\x08\x36\x4a\x5f\x7a\x10\x5b\x96\x55\x17\x2d\xf7\xc8\x2d\x73\x74\xf9\x82\x64\xc9\xcd\xcc\xb4\x96\xf2\xe1\x0f\xd8\x26\x2f\xb1\xa9\xa9\x96\x5b\x0b\x84\x1a\xc0\xd0\xe9\xc1\xa3\xd9\x49\x3e\xa7\xaa\x60\x02\x05\xb8\xf9\x00\xbe\x0d\x7a\xbb\x4d\x98\xa0\x65\x83\xd2\x29\x5c\x27\x63\x18\xbe\x28\xd4\x21\x98\x2d\xed\xd5\xbf\xc3\x3b\x88\x65\xd9\x4e\xf7\x47\xd6\x26\xaf\x99"}, -{{0x51,0xa4,0x19,0x7a,0xb7,0x68,0x6f,0x82,0xf6,0x00,0x3a,0x0c,0x32,0xf3,0x9d,0x0f,0x2e,0x47,0x55,0x5f,0x4e,0x9f,0x8d,0xee,0xe7,0x5b,0xcb,0x1b,0xd1,0xef,0x69,0xe5,},{0x06,0x38,0x6d,0xf8,0x6b,0x61,0xf1,0xf8,0xf4,0xdc,0x45,0xb7,0x3e,0xda,0xa8,0x41,0x92,0x09,0x68,0xbb,0xd1,0x31,0xcc,0x5c,0xa1,0xc5,0x29,0x4e,0xee,0xd5,0xc8,0xba,},{0x2c,0x07,0x29,0x69,0xff,0x47,0x19,0x21,0x2a,0x12,0x19,0x38,0xb5,0x06,0xc6,0x02,0x99,0x5b,0x4d,0x02,0xa2,0x2e,0x61,0x98,0xd6,0xe8,0x7d,0xd6,0xae,0x07,0x62,0x25,0xac,0x70,0xbb,0x25,0xef,0x8c,0x0e,0xe8,0x1e,0xb6,0xfe,0x95,0x3d,0xf6,0xb1,0x81,0x59,0x49,0xe8,0xed,0x05,0x06,0xcb,0x01,0x2e,0x87,0x3c,0xd3,0x6c,0xd0,0x9b,0x0a,},"\x2a\xed\xb7\xe8\x2f\x1f\xe4\xce\x46\x9a\xda\x48\x34\x5d\x00\x6d\x1b\x3b\xff\x40\xeb\x21\x86\x7f\x51\xfc\xe9\x65\x64\x0c\x40\x9e\xc1\x3a\xd4\xd5\x2f\x89\x1b\xd7\x90\x66\xd6\xb4\xd9\x44\xca\x86\x8d\x89\x86\xd2\x42\xb5\x7e\xcc\xc4\xc4\xa4\x88\x29\x1b\x15\x9c\x8d\xe4\x39\x2b\xe4\xb8\x6f\xeb\xaa\x75\xea\xc5\xd2\x2d\x3c\x4f\x8d\x6b\xef\x79\xad\xb9\xb9\x2b\x49\x14\xd5\xea\x07\xc7\xf0\x21\xe2\xc2\x9f\x58\xd0\x7b\xe8\xa0\x84\x10\x0b\xc1\x52\xd5\x1c\xa8\x97\xd7\xc1\x31\x64\x4d\x08\x95\x32\x2e\x94\x40\xa8\x33\x9e\x1a\xa3\x90\xa7\xf4\xfc\xb5\x1d\xdf\xb6\xdf\x48\xaa\xf5\x67\x63\x37\xd8\x7d\xdd\x85\xb1\xd9\x25\xe1\xa9\xc2\x9f\xe0\x81\x8f\x51\x4e\xf7\x2f\x74\x7a\x67\x49\x46\x47\x69\x07\xa7\xca\x99\xe9\xdb\x8d\x20\x96\x41\x05\x7a\x7f\x44\xa3\x17\xb9\x09\x74\xbc\x86\xf9\x61\x7a\x96\x8a\x76\xa6\xb8\x38\x7c\xf5\x85\x3e\x60\x81\x90\xc1\xa7\x9f\x1e\x1d\x68\x6e\x0d\xe2\x2d\xb6\xcd\x9a\xeb\x85\x32\xc5\xc8\x5c\xc9\x0b\x5a\x01\x85\x79\xf2\x8e\x50\x2a\x77\x0a\x4e\xc6\x75\x26\x3d\x0d\xd7\x81\xb4\xfa\x53\xc9\xdb\xf8\x09\x8d\x57\xb3\x3a\xe2\xaf\xba\xeb\x3e\x68\x26\x6a\xd9\xaa\xb7\x17\x4b\xa6\x8c\x64\x79\x88\x39\x92\x67\x0c\xcf\x3e\x5a\xc6\xa1\x7e\x65\xe3\x1e\x1f\xdc\x85\xe2\x69\xc8\x09\x35\xef\x57\x4f\x20\xd2\x39\x56\x84\x86\xe7\xd9\x4a\x4f\x72\x4a\xb7\x00\x60\x98\xb2\x4f\x3f\x61\x58\x76\x91\x43\x5c\x7f\x29\xce\x4e\x5c\xa7\x1b\x2b\x18\x74\x55\x64\x33\xa3\x58\xc8\xc5\xef\x3c\x88\x08\x43\x03\x0c\x2d\x13\xd5\x1b\x78\xc9\xbf\x1a\x88\x24\xe6\x2e\x11\x18\x44\x39\x6f\x5a\xf2\xe2\x5c\x31\x26\xef\x36\x26\xe2\x6e\xfa\xfa\xcf\x99\x83\x0a\xa4\x12\x12\x33\x2f\x37\x8a\x16\x72\x33\xa0\xb4\x22\x13\xaf\xe3\x6d\x83\xdc\x45\x82\xa7\x96\x93\xb9\xd5\x71\xa5\x77\x12\xa0\x8b\x85\x66\xd3\x61\xac\x90\x26\x47\xaf\xc8\x86\x60\x3e\x24\x28\x3e\xfb"}, -{{0xb1,0x11,0x9c,0x36,0x11,0x8b,0x7a,0x06,0x5a,0x19,0x5b,0xfb,0x8b,0x79,0xa5,0xc2,0x87,0xe0,0x9b,0xd2,0x87,0xc2,0xda,0xac,0x5e,0x6b,0x01,0x16,0x4c,0x5d,0x73,0x7f,},{0x88,0xf2,0x18,0xec,0xba,0x99,0xe7,0x70,0xed,0x21,0x4a,0x8d,0x01,0xa9,0x2a,0x10,0x40,0x0a,0xca,0xf1,0xf6,0xee,0xd4,0x20,0x06,0x7e,0x13,0x6e,0xe2,0xc0,0xc6,0x70,},{0x24,0xec,0x1e,0x54,0xfc,0x7e,0x72,0x2d,0x37,0x55,0x1d,0x02,0xcf,0x13,0x5d,0x33,0xf5,0xd3,0xff,0x53,0x57,0x73,0xe0,0x29,0x91,0xee,0x85,0xff,0xd3,0xaa,0x29,0x99,0x7f,0x9c,0x46,0x44,0x70,0x19,0x7f,0xee,0x81,0xdc,0xe1,0x10,0x60,0x9f,0x87,0x0b,0x27,0xc1,0x8d,0xfb,0xcf,0xd9,0x32,0x05,0x48,0x52,0x5e,0x93,0x14,0x8e,0x22,0x05,},"\x88\x16\xb1\xeb\x20\x6d\x5f\x6d\xcc\x2e\x4c\xc3\x91\xd2\x32\x09\x00\x6d\xe9\x35\xe3\x18\x15\x2e\x93\xfc\x8c\x2c\xf0\x8e\x26\x43\x2b\xad\x9a\xdb\x32\x03\xd8\x98\xdf\x0a\x2e\x7f\x1f\x83\xdc\x2f\x3e\xd3\x20\x5b\xec\x8e\xfc\xfd\x31\xad\xc1\xac\xa5\x75\x5d\xb9\xbd\x4e\xfe\x54\xcc\x17\x07\x30\x77\xde\x4a\x3f\xdd\x11\x99\x6e\x84\xb6\xa0\x52\xf0\x34\xb4\x10\x99\x22\x6c\x9c\x27\x2e\xae\x12\x52\x8f\x16\x58\x1b\x91\xb8\x12\x85\x0c\x20\x71\x44\xdb\xff\x3e\x85\x0c\xca\x84\x8e\xc2\xb1\xdd\x16\x47\x44\xd7\xb5\x93\x37\xd7\xe3\xef\xef\x00\x81\x62\xe6\x80\xbd\x4a\x08\x99\xce\xd6\x0b\x17\x1f\x8c\xbe\xb4\x8c\x51\x58\xdf\x6c\xbf\xdb\x26\x24\x08\x81\xbd\x58\xeb\xb8\xb6\xa0\x79\x58\x72\x79\x67\x9c\xb5\xad\x82\xf3\x71\xb5\x3c\x80\x13\x80\x4c\x35\x59\x6c\x88\x7e\x43\x6d\x23\x92\x6f\x99\x4e\x09\xd9\x8f\xbb\x8c\xe2\x70\x41\x74\xef\x38\xb6\x82\x62\xa7\xf1\xa7\x12\xda\x0e\xf0\xde\xc6\x39\x60\x68\x14\xb3\xbd\xca\xf2\x53\xff\x31\xc4\x8e\x8a\x75\x2c\x11\x1b\xd7\x10\x10\x31\xcc\x3d\x38\xef\xb0\xc9\xc7\xf1\x9c\x59\x08\x15\x84\xa0\xe0\x15\xee\x7c\x75\xb1\x0a\x4c\x51\xff\x54\x3a\x30\xe5\x2d\x5f\x94\xd8\x18\x8c\x6b\x08\xe9\xdf\x1e\x84\xa4\xe2\xc8\x07\x17\x0a\xc1\x24\xa7\x71\xb9\x94\x65\xa0\xd3\x8b\x1f\x1c\x63\x30\x40\x3c\x82\x54\x35\x82\xc5\xbb\x61\xb2\x20\xde\x1b\x9e\x0e\xf6\x9b\xda\xe2\x60\x23\x18\x1b\xa4\xcc\x07\x7a\x5f\x0d\x42\x57\x32\xac\xe1\x32\xae\x0c\x6f\xf0\xbb\x18\xba\xea\x83\xe8\x87\x7a\xfb\xe6\x50\xfe\x0b\xd0\x20\x93\xf0\x0a\x7b\x53\x65\x72\x8d\xcb\x66\xfb\xb8\x81\xf5\x92\x94\x50\x58\xa5\xb3\x50\x66\x5a\xf9\x1c\x55\x7a\x54\x72\x50\xad\x29\x5e\x68\xb4\xfb\x72\x45\x7c\xfb\x9d\x5e\xa1\xa7\xb2\xa3\x9c\x9a\xb7\xd7\xac\xe0\xaf\x5d\x51\x66\x9c\xb6\xc2\xc4\xc0\x7b\x22\x56\xd1\x0e\x5f\xfc\x6b\x97\xc6\x60\x00\x63\x13\xc4\xeb\x8d"}, -{{0xcb,0xb5,0x87,0x51,0x4e,0x0a,0x34,0xff,0xc3,0x4c,0xbc,0x04,0xf2,0x8c,0x9b,0x4f,0x64,0x65,0xf1,0xeb,0x22,0x5c,0xca,0x19,0xb8,0x64,0x87,0x6d,0xae,0xf3,0x7d,0x7f,},{0x6b,0x70,0x5d,0x46,0x77,0xd2,0xd8,0x49,0xb6,0x74,0x4b,0x1e,0xbe,0xd1,0x67,0xdb,0xcb,0xf6,0x45,0x92,0x4b,0x1f,0xf2,0xe6,0x36,0x07,0x94,0xbd,0xd0,0xe0,0x97,0x88,},{0x12,0x74,0xd6,0xf3,0x56,0xeb,0x64,0x14,0x72,0xb6,0xb9,0xe5,0xb3,0xce,0x65,0xd2,0x65,0x4e,0x6c,0xb8,0x7d,0x3a,0x83,0xfb,0x49,0xd0,0xf7,0xda,0x9c,0x44,0xbe,0x2b,0x53,0x26,0x04,0x46,0x5f,0x60,0x89,0xd6,0x80,0xd2,0xd9,0x4b,0x0e,0xdd,0x2b,0x6b,0x2b,0x80,0x5c,0x5e,0x84,0xc3,0x79,0xef,0xc0,0x59,0x67,0x3d,0x31,0x00,0x7a,0x09,},"\xbd\xf7\xd1\x7c\x70\x67\x96\xef\xd3\x48\x95\x59\xb5\x27\xb1\xc0\x58\x4b\x90\x22\xc9\xcb\xda\x3a\xac\x51\x46\xda\x34\x0d\x9c\xea\x69\xf9\x16\x03\x7c\xd2\x1b\x3e\xb1\x10\x43\x48\x88\x0f\xd5\xc5\xb7\xc6\x5f\xf8\x20\xf7\x49\x93\x46\x01\x69\x51\xcb\x71\x5d\x8d\xf2\xb4\x1c\x88\xcd\x3c\x66\x10\x54\x58\xb7\xb5\x90\xc2\x1c\x1a\xe2\xf6\xea\x9d\xde\xa7\x47\x0f\x25\xe0\x20\x27\xd1\x71\xe0\xe5\x74\xa2\xbb\x21\x64\x2f\x8f\x9d\xa5\x08\xe2\x1d\x8e\x73\x35\xb5\xac\xe5\x93\x52\x99\x40\x7b\xd1\xb0\x1b\xdd\x14\x23\x13\x3e\xf0\x45\x23\x4e\x70\x1f\x55\x54\x94\x34\xad\xe9\x4a\x60\xbe\x1e\x14\x06\xca\x5c\x75\x8c\x36\x79\x9c\xe1\x70\x30\x84\x47\x6e\x48\x4f\xb1\x74\x05\x30\xae\xe8\x42\x66\xd0\x7a\xdf\xb4\xcc\x68\x9f\x32\x65\x13\x3a\x59\xcd\xf9\x92\xfb\xb9\xa4\xb1\x2d\xef\xbe\x24\x1d\xdb\xf6\x5d\x12\xb2\xfb\xdd\xfc\x05\xaf\x0f\xb8\xde\x42\x08\x07\x75\xba\xd2\x9c\x6b\x04\x59\x84\x1c\xbb\x64\x8a\x9a\x95\xe4\x8d\x6e\x36\xac\x51\x44\x80\xa3\xde\xb4\xb3\x65\x54\xd8\xda\x62\x08\x08\xae\x9d\x47\x32\x97\x10\xd2\x0a\xaa\x6e\x5d\x7f\x54\x7d\x81\xad\x30\xf8\x4c\x0e\x3d\x23\x9c\xde\x5b\x16\x9d\x9d\xdf\x29\x48\x32\xd6\x7a\x80\x60\xba\x32\x9c\x4e\xf3\x9b\xe9\x4a\xc4\x64\x34\xdd\x21\x85\x93\x1d\x12\x31\xf9\xb6\xdf\x87\x8a\x5a\xf0\x83\x1e\x0e\x9d\x8a\x08\xd0\x80\x69\xde\xd6\xa9\x61\xef\x7f\x39\xfa\xd5\x01\xff\xd1\x7d\x6d\x9b\x7c\x65\x46\x53\xc1\xf5\x8f\xce\xe1\xa6\xcd\x80\x3d\x2a\xef\x16\x6c\x78\xef\x55\x14\xa3\x27\x6d\x69\x98\xdc\x7c\x09\xa3\xfa\x98\x2e\x42\x7c\x78\x5a\xa6\xa9\xe2\x56\xf7\xba\x72\xd5\xa6\xba\x33\xeb\x46\xf1\xf9\xfe\x9b\xe2\xbf\xc1\x41\x09\xf6\x47\x73\xc0\x0c\x06\x3b\x4d\x5c\xb4\xf4\xf8\xa0\xbe\xca\x92\xa9\xa0\x16\xc4\xf5\x40\xfe\xea\x9c\x3a\x31\xe3\x13\xbb\xcb\xc2\xff\x5e\xca\x99\x67\x85\x7f\x5f\x8a\x90\x9a\x29\xd7\xf2\x0d"}, -{{0x8b,0xde,0x3f,0xf6,0x1a,0x16,0x99,0x5a,0xb9,0xd5,0x39,0xf6,0x05,0x32,0x19,0x08,0x1b,0xca,0xea,0x1d,0x45,0x8e,0xc3,0x36,0x84,0xfc,0x1c,0x01,0xfb,0x56,0x5b,0xfa,},{0xcd,0x9d,0x78,0x2a,0x35,0x6e,0x84,0x7b,0x7a,0x04,0xc8,0x85,0xa9,0xb0,0x90,0x7c,0xc3,0x3b,0xa9,0x7a,0xd5,0x39,0x0d,0x4e,0xa5,0xfe,0xe5,0xeb,0x19,0x8d,0x08,0xb3,},{0x74,0x64,0xdf,0x0b,0x67,0xeb,0x90,0xb4,0xb7,0x3f,0xf0,0x82,0xad,0x0d,0x60,0xeb,0xfe,0x06,0x60,0xda,0xe9,0x70,0x69,0xb5,0x2c,0x37,0x27,0x22,0x3b,0xf7,0x0e,0x29,0xe4,0x87,0x11,0xa2,0xbb,0xb4,0x38,0xf5,0xf8,0xd8,0xa3,0x3b,0xb9,0xc4,0x8f,0xe7,0xb6,0x28,0xfa,0x8a,0x54,0x2f,0xf0,0xb5,0xae,0x36,0x26,0x9d,0x40,0x07,0xa5,0x05,},"\xa1\xf4\x0e\xc5\x80\x7e\x7a\x27\x06\x9a\x43\xb1\xae\xbf\xf5\x83\xef\x03\x70\x28\xc0\x2c\x85\x95\x25\xeb\x8f\xa4\xc3\xba\x95\xa9\x01\xff\x3a\xed\x78\xc4\xf8\x77\x52\xfb\x79\x55\x22\xf5\xbf\x71\x5b\xe7\xe3\xde\xfa\xc1\x0f\xcf\x17\xe3\xfa\x5c\x54\xb2\x00\x89\xa4\x72\x33\x33\x27\x25\x2e\xc9\x45\x71\x8f\xb4\x55\xe3\xf2\x7c\xcf\xde\xf8\x23\xd1\x2d\x40\x6e\x62\xa4\xae\xba\x3c\xb9\xd1\xc6\x1b\x2b\x17\xe4\x9e\x20\x0a\x84\x18\xf9\x35\xf2\x6e\xeb\x57\x60\x2c\x7a\xa3\xb3\xa2\x4f\x7e\x62\x38\xd3\xe0\x8d\x2d\x60\x9f\x2e\xad\xa0\x33\x2b\xc8\xcb\x12\x91\x6c\xb0\x3b\x0d\x4f\x9c\xd6\x02\x00\x25\x86\xd3\xe4\xcc\x7e\x0e\x03\x81\xc0\x45\xad\x2e\x1e\xe2\x82\x98\xae\x7f\xcf\x0c\x10\xf2\x12\x80\x85\x65\x29\x6f\x15\x8d\x2c\x32\xe8\xcb\x28\x15\x65\x81\xaf\x52\xbf\xc3\x47\x0c\x3c\x95\x82\x13\x8d\x22\x55\xe8\x42\x6d\x64\x8c\xa2\x37\xd7\xaa\xd2\x85\x6f\x17\x16\x38\x55\x82\x41\xd8\xae\x3f\x62\xba\x92\xdb\x59\x65\x68\xed\xee\x3e\xc0\xef\x37\x0f\x83\x62\x6a\xa0\x44\x5a\xf0\x8f\x96\x78\x63\x66\x0e\x8f\xba\x5a\x41\xc8\xe8\xed\xe1\xc9\x60\x51\x4a\x14\x68\x7a\x4a\x81\xe7\x76\xae\x0e\x8e\x77\x7f\xb0\xf2\x50\xd5\x1a\x83\xb5\x5f\x8c\x1f\xfd\xd7\x8d\xf3\xbd\xc9\x7f\xf1\x77\xaf\xec\xa0\x46\xc7\x2d\x72\xaf\x92\x4a\xd0\xd0\xab\x2b\xfc\x11\xb7\xf4\xab\xde\xd5\x1c\x39\x87\xa8\xbb\x94\xd6\x40\xc8\x71\x0e\x5f\xc9\xa4\x19\x0e\x8a\x00\x83\x63\xd7\x41\x9c\xea\x17\xc4\x0d\xea\x20\xea\x51\x56\x02\x9f\x3d\xeb\xf0\x52\x41\x91\x8f\x54\xaf\x50\x39\xe2\xc4\xcf\x2c\xa2\xe1\x39\xf6\x0e\x45\xcc\x65\x59\x5c\xdf\x54\xa6\x7d\x92\xb6\xac\x66\xfc\x0c\x5a\x29\x04\x95\xca\x57\xb0\x7e\xf5\x75\x0d\x05\xf5\x7d\x87\xd0\xc2\x28\xf7\xe4\xe1\x5a\xd0\xba\x01\x78\x73\x0f\x95\x1c\x69\x75\x83\x48\x1c\x66\xcb\xfc\xd4\x80\x32\x54\x4a\xa8\xd5\x09\x08\x30\x4b\xd8\x19\x40\x30\x87\x06"}, -{{0xda,0x59,0xbb,0xc5,0x23,0x40,0x4f,0x07,0x64,0x6a,0xdd,0x79,0x08,0x29,0x49,0x77,0xe4,0x66,0x45,0xbc,0x8a,0x38,0xba,0xd2,0x80,0x96,0x41,0xa2,0x3d,0xe3,0xb1,0x5a,},{0xb2,0x2c,0x0f,0x21,0xaa,0x1c,0x2d,0x45,0xf4,0xb2,0xe5,0x6c,0xc9,0xb5,0xe0,0x2f,0x9e,0x31,0xa2,0xea,0xa3,0x67,0xec,0xb4,0x82,0xf8,0x74,0xcb,0xd8,0xe9,0xfe,0x34,},{0x14,0x72,0x45,0x9c,0xbb,0xae,0x2c,0xf2,0x1c,0xe4,0x4a,0x15,0xba,0xe9,0xfc,0x85,0xdc,0xa4,0x0b,0x81,0x82,0xda,0x7d,0x52,0xcb,0xf5,0x6e,0xd5,0x38,0xd1,0x8e,0x03,0x47,0x7c,0x14,0x0a,0x3d,0xdd,0x0e,0xfb,0xa4,0x3c,0x96,0xaa,0x92,0xf5,0xf9,0xbc,0xdf,0x34,0x81,0x28,0x6c,0xe7,0x62,0xa7,0xe2,0xbd,0x1e,0x77,0x9b,0xa9,0x9b,0x0d,},"\x09\x71\x06\xc3\x62\x4d\x77\x4d\xde\x25\x51\xe0\xc2\x7e\x19\x50\x4e\x65\x18\xcc\x86\x36\x9a\xb2\x6f\xf8\x10\x96\x9e\x7d\xe2\x4a\xbc\x68\xb4\xb5\x3f\x11\xd9\x45\xd4\x9e\xf0\x78\xeb\x4f\x6b\xa6\xbf\x25\x7f\xf7\xb6\x08\xaf\xdc\xb3\x0a\x5c\x59\xa7\x56\xfd\x77\xa6\xc1\x24\x7f\x6f\x2a\x41\x10\x0d\x99\xfc\x52\x06\xaf\x3b\xcc\x6d\xe1\xd3\xe4\x96\x8e\x28\xfb\xa0\x12\x3f\x60\x45\xa1\xb5\x4d\x69\x3a\x42\xbd\xfa\x07\x1b\x2b\x91\x4b\x3c\x3c\x0c\x29\xb2\x59\x3d\x07\xe8\xbd\xc8\x6c\xa4\x2a\xc5\x55\xb7\xdc\xd9\x43\x9d\xf9\xfb\xd4\xbb\xec\x73\x0d\x63\x27\xbf\xae\x4f\xc4\x1e\xd4\x98\xb4\xf0\x4a\x0e\xb1\x4c\xee\x60\x82\x83\xaa\xa6\xe6\xaa\x46\x67\x6b\xc8\x8a\xed\x5d\x99\x39\x03\x7a\xad\x49\x15\x66\x1a\xf9\x4b\xb5\xf6\xe6\x53\xa2\xca\xc1\x23\x28\x70\x73\x27\x0e\x0b\x13\xfd\xa1\xdd\x48\x71\xaf\x6a\x92\xf9\x92\xf5\x39\xdf\x88\x17\x12\xfe\xfb\x03\x85\x40\xd4\x11\x91\x12\x3b\x6b\x3b\x4b\x6f\xf8\x7f\xfc\x92\x9a\x6b\xe5\x3c\x6c\xef\x02\xf4\x8f\x2f\x0c\xf2\xfe\x64\xa4\x5f\xd6\x60\x25\xcc\x2d\x7e\xe5\x5e\xbe\x23\x16\xc0\x00\x85\x56\x61\x16\x5e\x2a\x5b\xa4\x1a\xfc\x20\x97\x95\x7b\x6f\xe4\xc5\x52\x21\x20\x4b\x6f\xc1\xf3\x17\xdd\x3b\xa1\x3c\xac\x39\x92\x40\x26\xbd\xb6\x6b\xe4\x54\x22\x68\x87\x56\x31\xd2\x77\xf2\x10\x10\x7a\x33\x76\x7f\x6d\x95\x96\xe2\x57\x42\xd7\xa9\x0e\xa7\x91\xea\x4b\xc9\xee\x84\xa6\x7f\xd3\x28\xb8\x0f\x79\x1e\xde\x96\xd8\x96\x63\xe9\x37\xf0\xb7\x55\xba\xa9\xd5\x2b\xda\x21\x0c\xee\x1d\xb3\x39\xff\x1d\x3c\x4b\x00\x0b\x65\x3b\x9b\xde\x33\x80\x49\xaf\x84\x36\x4e\x21\x77\xf8\x0d\xd5\x1e\x2a\x16\x72\xee\x55\x5d\x63\x17\x58\x9f\x6f\x1d\x5a\xbe\x6c\x28\x77\x35\x8b\xf9\x4b\x0b\x80\x8f\xf8\x57\x36\x3f\xbf\xbe\x32\xe9\x73\x37\xe4\xb8\xa8\xc2\x21\xa9\xe7\x59\x62\xa8\xdc\x9b\x5a\x3d\x7c\xa5\xf9\xc9\xb6\x1c\x73\xc1\x46\x9a\x72\xbd"}, -{{0x40,0xea,0x82,0xda,0x41,0xfd,0x15,0xb0,0x6f,0xfe,0xb9,0x9c,0xd6,0x16,0xdc,0x6b,0xc8,0xc1,0xb2,0x14,0x77,0xea,0x23,0x94,0x66,0x08,0x8e,0x28,0x49,0xbf,0x10,0x16,},{0x59,0x10,0xe5,0x80,0xbf,0x41,0x2c,0x31,0xa8,0x74,0x51,0xd9,0xdd,0xf3,0x2b,0x3a,0xb7,0x13,0xf9,0xe4,0xa2,0x2c,0x59,0x0c,0x64,0x1c,0x14,0xa5,0xdf,0xbb,0xe0,0xd7,},{0xd2,0x98,0xfc,0xc9,0xa8,0xec,0xb7,0x6a,0x98,0xd4,0xa7,0x1d,0xfb,0x01,0xd2,0x76,0xab,0x2d,0x96,0x70,0xa9,0x5b,0xab,0x34,0xcf,0x1d,0x83,0x64,0x51,0x6d,0x1e,0xbd,0xb2,0x39,0x03,0x46,0x02,0x15,0x30,0x71,0x25,0xaf,0xd0,0x9c,0x75,0x8e,0x98,0x1a,0x45,0x2d,0xa9,0x5c,0x0a,0xc2,0xc0,0xb9,0x58,0xc6,0x91,0x7e,0x68,0x74,0x19,0x0d,},"\xa0\x6c\x4e\x02\xb8\x3a\xb7\xe1\x91\xad\x81\x8c\xb8\x18\x7b\x52\xa8\xda\x00\x4f\xe8\x38\xdb\x33\x3c\x4e\x02\x54\x8d\xb6\xbd\xf7\x91\x44\x46\x42\xe5\x7f\xdb\xc8\x59\x4e\x59\xd7\x02\x32\x80\xbb\xae\x82\x98\x6f\x39\x98\x05\x43\x4b\xb0\x72\xc8\xa2\x7a\x2d\xcd\x5a\xa6\x2f\x06\x5b\xc5\x8b\x06\x21\xfc\xd3\x65\xf6\xcd\xbf\x4d\x57\xd5\x77\xd9\x11\x50\x30\x1f\xa4\x8f\x18\x2f\x87\xe8\xdc\xa7\xce\x45\xa7\xd6\x48\x45\xff\x43\x4d\x1b\xab\x05\x34\xcc\xc8\x3a\xa0\x97\x4e\x88\xb3\x8f\xc2\x50\x8c\xef\xcb\xbc\x82\x13\x5b\x73\xb3\x84\xc8\x0e\xcc\xb8\xa0\x9e\x28\x73\xcc\x07\x12\x90\x21\xd8\x1c\xe1\x29\xa9\xdf\x65\xe6\x13\x41\x0a\xf9\x50\x19\x7d\xbf\x9a\xfc\x28\xed\xc4\xe6\x5c\x3e\x84\xda\x40\xd2\xef\x84\x1b\x88\x6b\xc4\x47\x19\xa5\xd5\x9d\xb2\xc6\xdc\x77\x64\x01\xc8\x95\xe2\xb3\xc8\x37\x83\xd7\x81\x7b\xba\x68\xba\xff\x59\x47\x0d\x60\x15\xbb\xa8\xd9\x75\xf0\xeb\x71\x2f\x3b\x89\x02\x91\x28\x05\x52\x3a\xa7\x1c\x90\x49\x9d\xe6\x89\xd3\x1a\xe4\x4e\x21\x0b\x84\x46\xf2\x48\x47\x27\xcc\x49\x1b\x92\xa8\xe8\xb1\x99\xd6\x28\xe1\xdf\x79\xa2\x8c\x56\x1e\x5a\x7d\x88\x2e\x30\x78\x7d\x08\xfb\x2d\x51\x96\xba\x61\x19\x63\x09\xb3\xbf\x0c\x58\x24\xa3\x54\x8c\x70\x00\x03\xfe\x99\x13\xbe\xfe\x12\x22\x31\x50\x01\x26\x85\xe9\x07\x20\xe9\xec\x6b\xc4\xdb\x60\x74\x25\xae\xc5\x31\xc4\xfa\x36\x08\x6d\x3b\x9b\xe3\x91\xa3\xf0\x46\x35\xa8\x07\x7a\x44\x7a\x16\xa6\xfd\x89\xaf\xbb\x9a\x72\xd0\xd3\x55\xcb\x0b\x22\xd5\x62\xf4\x3f\x59\xd4\xe3\x71\x28\xb3\xe2\xd9\x06\xc8\xae\x23\xd0\xaa\x59\x9c\x70\xd3\x77\x8a\x07\x6c\x1a\x39\x72\x8f\x1d\x69\x37\xbd\x48\xb9\x78\x74\x08\x50\x56\x61\x38\xd3\x48\x52\xb6\x30\x75\xe8\x9a\x8e\x22\x80\xed\xba\x6f\x4e\xe8\xf6\x15\x11\xe9\xb7\x68\xe9\x5c\x78\xd1\x97\xb6\x93\xb1\x09\xe8\x88\x18\xb4\x86\xa9\xdf\xdb\x74\xb4\xc5\x55\x0a\xcd\xfb\xd5"}, -{{0x28,0xbb,0x81,0xa1,0x7d,0x45,0x84,0x75,0x4d,0x52,0x81,0x8c,0xd0,0xf1,0xf2,0x1b,0xaa,0x77,0x7e,0x69,0x58,0x44,0xa1,0x51,0x22,0xac,0x05,0x34,0x4d,0xdd,0xc0,0x27,},{0xd5,0xf6,0x1d,0x51,0x99,0x44,0xd1,0x3b,0x84,0xbf,0xa7,0xcd,0x67,0xcb,0x0b,0xea,0x4e,0xf2,0x28,0x1e,0xfa,0x46,0x1f,0x22,0xad,0xe4,0xba,0x88,0x2d,0x11,0xb2,0x52,},{0x9c,0xe4,0x5a,0x07,0xdb,0xd2,0x8d,0x3f,0x6f,0x1b,0x35,0x63,0x0a,0x3f,0xd5,0x6f,0x1d,0x54,0x8f,0x84,0xff,0xb1,0xc6,0xae,0x64,0xb2,0x14,0x98,0xae,0x38,0xe5,0x96,0x91,0x6e,0x77,0xf7,0x99,0x05,0xe6,0x09,0xfb,0x1a,0xe0,0xda,0x36,0x13,0x8a,0x80,0xf2,0x42,0x12,0x21,0x67,0x06,0x80,0x92,0xcc,0x60,0x57,0x96,0xc5,0x66,0x9e,0x06,},"\x92\xe8\x4c\x7a\x55\xb0\xbe\xa0\x3e\x17\xcf\xb6\x5f\x70\x85\xce\x3f\x44\x5b\x15\x42\xba\xe9\x97\xde\x5f\x09\x2a\x24\xff\x24\x33\x80\x28\x6d\x13\x70\x91\xa5\x98\xf3\x5e\x6d\xae\x1a\x1c\x64\x8f\x5a\x49\x4c\x81\x9d\xfb\x24\x06\x52\xff\x90\x83\x81\xf3\x2d\x70\xbc\x51\x31\x00\xac\xa1\x6f\xe7\x22\x02\x95\xb1\xc7\x18\x35\xf1\x6d\x93\x10\xa9\xd2\x7a\x04\xa9\x80\xac\xe2\x97\xd5\xaf\x3f\x7c\xb7\xc7\x8b\x24\x99\x7c\xcb\x41\xf5\x4e\xcb\xab\x50\x7e\xb7\x3e\xa6\xa3\xed\x47\x0e\x49\x59\x05\x09\xf5\xd1\xe6\x03\x2a\x26\x05\xdb\x87\xf4\xa9\xb9\xec\x91\x60\x25\x83\xf1\x4e\x2f\xe1\xbd\xb9\x00\xec\xb8\x97\x11\x96\xb5\x5c\x0d\x43\x34\x89\xf2\x6b\xe9\xca\x15\x7c\xbd\x56\x57\x28\x87\xba\x85\x9f\x39\x67\x4a\x8e\x0c\xa0\x8f\x2d\xbb\x0f\x27\x07\x35\x51\xd0\xb1\x99\x06\x85\x17\x8b\x1a\xe9\xe7\x88\x54\x99\x14\x3d\x9d\x72\xc8\x57\x1d\x11\xe0\xd8\x5b\xf5\x8d\xf9\x4e\x2a\x74\xd9\xb6\x84\x65\x57\xf9\x12\x5c\xa0\x94\x4c\xe5\x71\x8d\x2c\xba\xe1\x67\x2b\xa0\x2b\x84\x7c\x17\xa6\xf6\xb4\x45\x63\x4d\x2f\x01\x75\xa7\x5c\xf6\x88\x3c\x62\xe5\xb5\x21\xc5\x71\x41\xf2\x18\xb2\xfb\x09\x94\xb3\x72\xa7\x16\xc4\xa2\x17\x43\x4b\xea\xb7\x57\x40\xb8\xe9\x1c\x62\x21\x87\xd0\x3c\x85\xda\x00\x1e\x00\x24\x73\x12\xa4\x65\x22\x5f\x5d\x6a\xf2\x32\x06\x4a\x42\x7d\x30\x18\x70\x0d\xed\x77\x4b\x90\x26\x77\x7a\x52\x75\xfc\x04\x75\x46\x06\xc8\x66\x00\x29\x7b\xf7\xb7\x1a\xaf\xf8\xb9\xa7\x46\x67\x7a\x36\x62\xf3\x75\x0e\x81\xb5\x01\x66\xf6\x23\x70\x00\x05\x1f\xfa\x15\x86\x8d\xef\xdf\x09\x00\x57\x72\x2a\xe2\x29\x96\x4a\x4e\xa0\x85\xe0\xdb\xc0\x4c\xe1\x99\x77\x22\xc5\xbb\x65\xd2\xb4\x7e\xcb\x74\x6f\xd8\x3a\x9f\x6a\x69\xc8\x15\x45\xa9\xb5\x02\xf5\xe7\x6d\x31\x30\xc5\xaf\xcb\x1c\x9a\xf9\x9d\x91\x87\x40\x83\x7c\xe8\x9d\x7c\xd2\x13\xfe\xf2\xfd\x06\x2c\xe8\x85\x0f\x69\x65\x9e\x4a\xd3\x27"}, -{{0x24,0xbf,0xd4,0xfc,0x45,0xd5,0x09,0x35,0x85,0x67,0x81,0x01,0xcf,0x56,0x3a,0xb8,0x01,0x1f,0xd6,0x43,0x0d,0xe1,0x55,0xf2,0xa4,0x25,0xf0,0x63,0x3e,0xe3,0xb7,0xcd,},{0x9c,0xf5,0xc5,0xfc,0x0c,0xcf,0xae,0xb2,0x8a,0x08,0xba,0x67,0x70,0x7b,0x18,0xdc,0x84,0xea,0x06,0x98,0xff,0xbd,0xbc,0x16,0x9a,0x09,0xc2,0x81,0x23,0xe6,0xc2,0xac,},{0xdc,0x93,0x5b,0x60,0xfd,0xe4,0x43,0x59,0xaf,0x8f,0x50,0xed,0x7f,0x91,0x9f,0x48,0x3c,0xe3,0xf2,0x4e,0x23,0x20,0xc5,0x5b,0xa9,0x2f,0x3e,0x76,0x17,0xc1,0x9b,0xfb,0x54,0x70,0x19,0x03,0xff,0x18,0x3b,0x42,0xcb,0xed,0xfe,0xf0,0x87,0x5f,0x42,0xb1,0x28,0x75,0xd3,0x6a,0x0a,0xee,0xc7,0x3f,0xfd,0x09,0x50,0x9d,0x92,0xb2,0x8b,0x0d,},"\xba\x54\x12\x8f\x45\xbe\x20\x01\xdb\xb0\x60\xd5\xdc\xc4\x71\x44\x99\x74\x15\xd4\x29\x4f\x6e\xba\x8d\xce\xba\x4f\x6c\xf2\x23\x46\x83\xc4\x26\x5f\x88\x03\x22\x05\x29\x6e\x9b\x27\xd6\x85\x06\x23\x2d\x57\xb6\x88\x40\x76\x48\xf8\x7c\xeb\x34\x20\x52\xbd\xe9\xd0\x06\x55\x42\xff\x17\x15\xc9\x42\x02\x7e\x67\x48\x2a\xf4\xbc\x27\x8f\xf7\x19\x66\xfb\x3f\x62\xa2\xa5\x32\x3c\xb1\xb4\xba\xe1\xe7\xb8\xfe\xdc\xbc\x73\xea\x05\xb4\x07\x64\x21\xb0\xb4\xfa\xe8\xbc\x33\x37\x41\x6a\x17\xfe\x12\x4e\x7e\xe4\x65\xeb\xb3\x8d\x87\x92\x30\x64\x29\xd8\x27\x9a\x1b\xd5\x4c\x37\xbe\xe8\xf9\xc8\x5e\xeb\xe3\xaf\xd1\xf6\x44\x89\xd4\xe5\x3a\xc5\xf5\x06\x57\xbb\x6f\xfb\x97\x12\x07\x44\xb7\x5d\x47\xc6\x22\x6d\x5a\x9c\x9c\x26\x4e\xe3\xe6\xa6\xde\xd0\x50\x62\xca\x10\x06\x66\x91\x18\x45\x45\x50\x01\x09\x19\xc2\x63\x3c\xf0\x86\x95\x03\x45\xe5\x14\xaf\x38\x43\x14\x8e\x5c\x64\x35\x2e\x69\x03\x7d\xfe\x60\xd4\xa8\xea\xb3\xeb\x8c\xb5\x4b\xd3\x9a\xf2\xf3\x53\xd5\xde\xd2\xe2\xbc\x8b\x11\xc0\x9f\x61\x2e\x12\x8c\x6e\xfa\x41\xf6\xeb\x2c\x95\x80\x87\xbe\x34\xc6\x33\x5a\x43\x00\x5d\x11\xa9\xd3\xb5\xa5\x29\xc2\xd1\xb0\x64\x2f\x77\xaf\xdd\x8c\x6b\x1d\x6f\xb2\xa9\xdc\xb6\x5f\x42\xf4\xec\xa8\xea\x9a\x05\x40\x58\xbe\x86\x13\x66\x76\x10\xe3\xee\xd8\xd1\xdf\x07\x39\xec\xa1\x71\x95\x41\x17\x98\x9d\x1b\x12\x18\x9a\xb5\x79\x04\xaa\x96\x0b\x0c\xa8\x55\x41\x74\x63\x85\xef\xa9\x85\xbe\x9d\x97\xb5\xa9\x02\x99\x89\xa9\xc7\x14\x98\xdf\xab\xdb\x81\x36\x81\xf5\x7e\x27\x6b\x64\xdb\x49\x1b\x8f\x08\x2a\x88\x51\x45\x46\x9a\x53\x1b\x7f\x9f\x04\xca\x0a\x2c\x2f\x8d\xff\x20\xcc\xb9\x9c\x28\x61\xf5\x4e\x5e\xaf\xa9\x62\xcc\x53\xea\xf1\x8d\x3d\x5e\x50\xd3\x37\xaf\x48\x5f\x19\x97\x5f\x05\x93\x07\x00\xa8\xa7\x25\x3f\x11\xf1\x84\x13\x0d\x0a\xee\x70\x96\x9d\x96\xfe\x08\xf2\x16\x95\x1d\x9d\xce\xd5\x23\x88"}, -{{0x2f,0xc2,0xf9,0xb2,0x05,0x0a,0xd7,0xd1,0x39,0x27,0x3e,0x93,0xe2,0xa0,0x45,0x1c,0x7b,0x5c,0xce,0x57,0x59,0x9a,0xa6,0xb0,0x8d,0x3e,0xdc,0x5b,0xb0,0x75,0x90,0xc8,},{0xff,0xe5,0xa1,0x78,0x80,0xd7,0x18,0xcc,0x79,0x88,0xc2,0xfd,0x98,0x25,0xb0,0x3b,0x93,0x45,0x0a,0xc1,0xde,0xb8,0xfb,0xd1,0xf1,0xbf,0x3b,0x8f,0x87,0x80,0x59,0x54,},{0x7a,0xff,0x16,0x2a,0x3c,0x0d,0x28,0xdf,0xf4,0x17,0x15,0xa9,0x74,0xaf,0x07,0xec,0xac,0x21,0x32,0xfc,0x18,0xbc,0x43,0xa1,0x98,0xfe,0x66,0x46,0x59,0x05,0x0d,0xa1,0x9a,0xe2,0x27,0x58,0xd5,0x2c,0x9c,0xbb,0x94,0xf1,0x35,0x8b,0xb0,0x26,0x10,0xa8,0xa3,0x51,0xc2,0x11,0x62,0x79,0xe7,0x24,0x5a,0xdf,0x69,0x67,0x5d,0xfd,0x36,0x0a,},"\xdc\x12\x97\x99\x0c\xc0\x27\xd5\x6d\x1f\xee\x26\x5c\x09\xbc\xf2\x07\xa9\x58\x3e\x6b\xab\x8d\x32\x47\x82\x28\xe0\xbc\x30\x5b\x98\x18\x15\x4c\x33\x8c\xee\xc3\x4b\x04\xc4\xad\xe7\xac\x61\xdc\xb0\x9b\xfa\xc8\xad\xe0\x0d\x1f\x29\xde\x31\x70\x60\xb8\xa4\xda\xf1\x98\x7d\xe4\x09\xca\x2c\x3f\xe4\x38\x00\x88\x07\x3c\xcf\x48\x5e\x9a\x69\x51\x6b\x5b\xbb\x41\x30\xf2\x0b\xe6\x9b\x2d\xd6\xa9\xb4\x65\x15\x9c\xca\x1a\xc8\x8b\x32\x8b\x80\xc5\x1b\x66\xaf\x7f\x4c\x50\xf6\x22\x87\x72\xf2\x87\x34\x69\x3c\xe4\x80\x5a\x41\x63\xdf\xf1\x4b\x4d\x03\x98\x11\xee\x3f\xce\x65\x93\x54\x44\xa6\xea\x9a\x72\xd7\x8b\x91\x5c\x9c\x3b\x76\x6c\x60\xb7\xe0\x32\x9e\x43\xc9\xc5\x7e\xde\x94\xb9\x15\x25\xce\x5a\x07\x5a\x72\x97\x21\x97\x72\xef\x3c\x02\x96\x49\xb5\x86\xa9\x5a\x73\xbb\xdf\x16\xd8\xfc\x20\x36\x8d\xe4\xba\x44\xde\x10\x64\xbe\x58\x26\xb3\x76\xbe\x31\xa8\x6c\xa4\x78\xa5\x2e\xfb\x98\xf1\xfa\x33\x31\x57\x71\x9b\xd6\xe0\xda\x80\xed\x68\xd0\xef\xea\xfe\xe5\xa1\x3b\xcc\x3b\x45\x75\x25\x25\x8f\x1f\x7e\x03\x1f\x7b\x40\x3a\x46\x15\x06\x92\x7b\x1e\x6c\x7d\x4a\x0c\x8d\x84\xb5\xf3\xdd\x0e\xb8\xbd\xb1\x3e\xdc\x2b\x51\x4a\x81\xd0\x88\xeb\x07\x7a\x52\xc8\xa8\x31\x86\x1f\xee\xe8\x11\x0e\x41\xa3\x25\xdc\xe2\x06\xb2\xd6\x7d\x25\xf9\x0e\xf5\x7e\x0f\xde\x70\x9f\x3e\x5a\x39\xc0\x4e\xed\x31\xe5\x7c\x19\x3b\x28\x3e\x2d\xa7\x27\x9e\xe3\xf1\xee\xd4\x82\xb3\xbb\xcd\x37\x39\x02\xc1\xdf\x81\x1a\xc3\x3e\x1d\xe0\x64\x29\xe8\xf8\x44\x3f\x60\x20\x19\x65\x0b\xdc\x2e\xe8\xd7\xf6\x50\x03\x6a\x7a\x22\xb8\xfd\x88\x51\x75\x11\x22\x9c\x72\x9a\x32\x69\xb3\xa3\xe8\xfc\x72\xb0\x1b\x5a\x4b\x3e\x33\xf5\x27\x2f\x3a\xd2\x16\x29\xd0\x8b\x1f\x71\x79\x35\xe9\xe1\x04\xad\xd2\xf0\xf2\x03\x34\x32\xbe\xc8\x2e\x21\x21\xd9\x8c\x9c\x1a\x58\xe0\xda\xba\x25\x53\x6a\x1b\xe8\xe5\x08\x83\x47\xf4\xa1\x4e\x48\xd8\xe3"}, -{{0x8a,0xfe,0x33,0xa0,0xc0,0x8a,0xa3,0x48,0x7a,0x97,0xdf,0x9f,0x01,0xf0,0x5b,0x23,0x27,0x7d,0xf0,0xbb,0x7e,0x4c,0xe3,0x95,0x22,0xae,0xc3,0xd1,0x78,0x16,0xe4,0x67,},{0xd0,0x04,0x37,0x0e,0x6e,0xdc,0x34,0xb3,0xe8,0x81,0x86,0x67,0x21,0x6f,0x5b,0x22,0x6b,0x0f,0xf7,0x5a,0x58,0x48,0x4c,0x86,0x16,0xe1,0xa8,0x66,0x44,0x4c,0xab,0x57,},{0x63,0xa8,0xae,0xac,0x02,0x5f,0x2d,0xde,0x9a,0x73,0x28,0x6e,0x56,0xc2,0xd6,0x2d,0xcb,0x79,0xa2,0x41,0xba,0x0b,0x2e,0x2d,0xba,0xca,0x87,0x52,0xed,0x2f,0xc8,0xcc,0x7a,0xb8,0xe6,0x60,0x0b,0x67,0x64,0x5f,0xb5,0xe8,0x18,0xa4,0xe8,0x2c,0x29,0x18,0x0a,0x6b,0x2c,0x3f,0x58,0xd0,0x99,0xcb,0x63,0x5c,0xe5,0x2b,0xdc,0x15,0x70,0x04,},"\x86\xfb\x74\x1f\x1b\x97\x08\x92\x91\x95\x03\x1a\xa1\x64\x5f\xb7\x09\xa8\xae\x32\x3f\xff\x85\xe5\x47\x01\x94\x45\x2e\x11\xb7\xb1\x27\x91\x94\xb5\xe2\x42\x7c\xe2\x3e\x1d\x74\x9c\x3d\xdf\x91\x0b\x01\x7e\x4f\x2d\xff\x86\xdb\xe4\x82\xc9\x1b\xd9\x94\xe8\x49\x3f\x2e\x68\x24\xbb\xa3\xbc\x7d\x7a\x84\x5f\x21\x7a\xe9\x76\x0b\x3c\xd0\x02\x26\xd9\xff\x26\x16\xd4\x52\x75\x1a\x90\xc3\xd0\xd3\xc3\x6d\x4a\xb4\xb2\x52\x0f\x67\x28\x81\x71\xbd\x3a\x34\xb2\xea\xca\xe8\xd4\x4c\x1e\x15\x3d\xda\x1f\x90\xbc\xd3\x59\x5d\xad\x37\x71\x3b\x8d\x34\x01\x56\xea\x90\xa4\xe1\x35\x95\x1b\xa7\x16\x9a\xc1\x75\x57\x8b\x81\xe9\x7a\x54\x1a\xb9\xbf\xb7\x63\x28\x79\x8d\x7d\x63\x1c\x14\xdf\x2a\xd6\x13\xe9\xc6\xe1\x14\x7a\x0e\x84\x06\x2d\xdb\xa0\x35\x85\x9d\x46\xba\xde\x5f\xad\xd9\xb3\x2b\x43\xda\xd4\x83\xc6\xb8\x02\x3b\x32\x39\x1e\x51\xef\x15\x20\xc6\x8c\x61\x91\x32\x6c\x49\x44\x23\x08\x0c\x62\x3d\xc4\xad\x0a\xa0\x74\x74\x8d\x82\x6c\x29\x64\x4c\x38\x98\x6a\x77\x00\x2f\x0c\xab\x90\x68\xe6\xc9\xec\x73\xcc\x2e\x0c\x58\x4b\x80\xe0\xbc\x37\x57\x21\xf7\xa8\xfc\x35\x31\x7a\x5e\x24\x0e\x8c\x66\x09\x2f\xb6\x30\x5b\x01\x2c\x70\xe1\x7a\xea\xff\x13\x38\x6d\x5e\x28\xd0\x64\x30\xca\x58\x5b\x0c\x85\xb2\x74\xe7\xfc\xbb\x63\xe3\x42\x3a\x98\x25\x79\xe5\xa6\x4a\x02\x62\xc4\x19\x08\xe5\x5d\xbe\x43\xda\xc1\xe5\xcc\x1b\xb7\x29\x8b\xe4\x28\x72\x0a\x12\xe3\xb0\x72\x55\x9e\xc2\x67\x5d\x45\x7a\xaf\x8f\x13\x25\x2e\x28\xaa\xd6\x3c\x15\x13\xf5\xf2\x39\x56\x4d\x36\x3c\x85\x05\xff\xa4\xe5\x0f\x66\x48\xc1\xcb\x82\xbb\xa8\x52\xbf\xf0\xac\xb0\x30\xcb\xe7\x3f\x05\x9d\xd8\x7b\xbd\x73\x18\xc5\x58\x6e\x70\x86\x18\xa4\xf4\xc9\xf3\xbe\xc3\xf4\xf0\x7c\x60\x9e\xeb\xb2\x4b\xa8\x78\xc6\xbf\x1e\x4f\x2d\x0f\xd1\x45\x0a\xb9\x4e\x31\x75\x52\x17\x78\x6f\xb1\x51\x82\x76\x0f\xfb\xe5\xa2\x67\xcb\xe9\x98\xa4\xff\x90\xa2"}, -{{0x6d,0xc7,0xcc,0xf3,0x29,0x37,0x8e,0x81,0x31,0xb6,0xde,0xfc,0xd8,0x93,0x70,0x30,0x10,0x68,0x94,0x63,0x36,0xb0,0xb7,0x62,0xac,0x5e,0xa5,0x14,0x87,0xdb,0xd3,0x9e,},{0x04,0xe9,0x0d,0x27,0x5e,0x79,0xdf,0x5f,0x2b,0x6e,0xf4,0xa3,0x15,0x05,0xaa,0xc0,0x5a,0x69,0x45,0x9b,0xaf,0x2c,0x58,0x1b,0x3c,0xe3,0xdb,0x29,0xf0,0xf1,0xfc,0x14,},{0x04,0x50,0x9d,0xb0,0x03,0xa1,0xa6,0xed,0x3f,0xbc,0xec,0x21,0xac,0x44,0xec,0x10,0xcc,0x06,0xd7,0x9f,0x27,0x14,0x96,0x08,0x82,0x17,0x03,0x16,0x27,0x5d,0xf8,0x04,0x23,0xa1,0xc1,0xa1,0x12,0xd8,0x81,0xfc,0x24,0xd2,0x81,0x25,0x26,0x07,0x90,0x58,0xaa,0x8b,0x60,0x8b,0xfc,0x6b,0x5e,0x57,0x63,0x22,0x40,0xc6,0x36,0xd6,0xeb,0x00,},"\x20\xce\xbb\xe9\x84\x01\xac\x89\x34\xc3\xe6\x5a\x57\x38\xcb\x0e\xc0\xcd\xc7\x5f\xdb\x09\xdc\x96\x31\x28\x94\xb1\x87\xc0\xa4\x6d\x2c\x38\xf4\x85\x5b\xe3\xee\xcc\xdc\xdc\xc5\x6d\x92\x6a\x8c\x08\xce\x6e\x74\x8e\x2a\x85\x8f\x53\x53\x2e\x7e\x5f\xc5\xf7\x01\x4c\x8c\x6f\x86\x31\x0c\xc2\x6e\xfe\xf3\x0a\xe5\x25\xa5\x15\x79\x40\xab\x53\x5e\xd8\xe4\x03\x11\x2b\x08\xe3\x5e\x2b\xb3\xdd\x91\xa9\xae\x8f\x77\x2d\x2a\xff\x37\xd8\xc4\x0d\x2b\x5c\xc8\x87\xa6\xf1\x50\x50\xa0\xf5\xbc\xf0\x36\x0c\x3a\x9d\x12\xd5\x91\x86\x55\xed\xc3\xc1\x3c\x86\xba\x6f\x4a\x2f\xa3\xbf\xcd\x40\x5e\xd3\x8f\x87\x1c\xf7\xdf\xf0\xf7\x5d\xaf\x2c\x32\x10\x84\xee\x9f\xa8\x12\x11\xad\xb1\x05\xb2\x5c\x22\x88\xf0\xf2\xf7\xf9\x3e\xf6\x56\xb2\xde\x19\x01\x22\xe7\xa4\xbf\xd4\xa1\xbd\x98\x93\xa8\x48\x5b\x50\x9f\xf0\xbc\x46\xcc\x96\x10\x51\xc1\xdb\x5a\x12\x49\x0c\x7e\x74\x19\x22\xcc\xc0\xa6\x65\x49\x64\x70\x27\x6f\x69\xc7\xb7\x70\x98\xc1\xe6\x70\xaf\x6b\x9f\x85\x12\x52\x99\x68\x75\xeb\x80\x35\xa8\x17\xfa\x9b\xe0\x7f\x2b\xe0\xbb\xb1\x20\x25\xe0\x56\x54\x14\xc8\x17\xe9\x42\x1a\xc7\x00\x37\x38\x93\x86\x2f\x24\xcb\x16\x5f\x9a\x27\x1a\x64\xfd\x23\x05\xc6\x67\x2c\x46\x76\x7f\x8f\x07\x5b\xe5\xd2\xd4\x07\x9b\xfa\xdc\x39\x56\x28\x8b\x02\x15\x60\x53\x11\xb5\xbf\x32\xf0\x03\x7b\x7c\x5a\xd5\x02\x01\x3e\x82\xae\x34\x19\xd9\xd8\xf3\x9c\x54\x5b\x58\x88\xf4\x71\x06\xc9\x4d\x5f\xd6\x08\x4d\x26\x03\x4a\x99\xf5\xdc\xbf\x26\xa8\x4e\xb4\xee\x14\x9c\x62\xa0\x41\x0d\x8c\x70\x7b\x1a\x9b\x07\x1f\x74\xed\x23\x93\x25\x85\x07\x2c\xe6\xcb\xd3\x3d\x4d\x54\xee\x91\x79\x16\xf5\xdf\xc6\x4d\x26\xa4\x98\x01\x84\x38\xb4\x55\x73\x93\x45\xdd\x60\xae\x0f\x47\x50\x62\x59\x15\xcc\x82\x9a\xb6\x82\x2d\x6f\x05\xf6\xd2\xbd\xa0\xa7\xbf\x56\x01\xe9\xa2\xed\x6d\xe9\x60\x37\x1d\x17\xe6\xf4\x37\x09\xc9\x67\x8c\xa7\x43\xad\xfb\xdb\x45"}, -{{0xcc,0xae,0x07,0xd2,0xa0,0x21,0xfe,0x3e,0x6e,0xe2,0x38,0x36,0xa7,0x11,0xb9,0x7b,0x04,0xe0,0xa4,0x41,0xf1,0x69,0x60,0x75,0x72,0x73,0x1c,0xb0,0x8c,0x26,0x94,0x88,},{0xa3,0x22,0x65,0xe5,0x32,0x8a,0x4f,0x49,0xcf,0x06,0xb4,0x67,0xa9,0x8b,0x9f,0x9d,0x5b,0x99,0x7b,0x85,0xdf,0xb7,0x52,0x3c,0xa6,0xa0,0xa1,0xd6,0x27,0xd3,0x28,0x91,},{0x0e,0xec,0x75,0x41,0x05,0x44,0x7f,0x97,0xd4,0xa9,0xcd,0x24,0x6c,0x7e,0xed,0xe3,0xfd,0x06,0x90,0x18,0xf0,0xd0,0x1a,0x41,0xdf,0xab,0xca,0x3e,0x90,0xa7,0x41,0x83,0x5e,0xa4,0xa9,0xd6,0x82,0x34,0x22,0x67,0xb2,0x50,0xfc,0x1c,0x8c,0x54,0x7c,0x89,0x63,0x2d,0x9f,0x68,0x9a,0xf5,0x36,0xc7,0x92,0x90,0x04,0xde,0xd0,0xd9,0x6f,0x09,},"\xa4\xbf\x82\x97\xd0\xdc\x5e\x4c\x92\xbd\x00\xad\x5b\x9c\x09\xb1\x23\x8b\x50\x3d\x61\x91\x16\xef\x74\x26\x03\x78\x34\x9a\x92\x82\xb4\x1f\x3f\x46\x76\xa6\x21\x5e\x3c\xe6\xd0\x22\x38\x48\x0a\x96\x04\x3b\x29\x42\xb3\xfe\xed\x12\x62\x0b\x1f\xa9\x7f\x77\x03\xb3\xeb\x68\x3c\x16\x01\xbd\x2f\x51\x82\x5c\x45\x0d\xf4\xfd\x1f\x33\xb0\xbf\x9c\x23\xc0\x32\x23\x78\x9e\x06\xe2\x4c\xf1\x36\xd3\xb5\x57\x40\x3a\x66\x98\x1f\x4b\x77\x7d\xcf\xe8\x90\xd2\xba\x96\xda\x4a\x47\x42\xae\xed\xdd\x6a\x61\x1d\x05\xfc\x21\x56\x94\xa5\xd8\x9a\x5d\xe6\x76\x0b\x1d\x94\x15\x15\x50\x44\xc0\x49\xcb\x02\x29\x1a\x15\x14\xfa\xa2\xe7\x7d\x2a\xe3\x3d\x44\x58\x5b\xda\xc6\x36\x5b\xf4\x81\xd9\xc9\x78\x33\x93\x7e\xab\x63\x6e\xd6\x57\x42\xa0\xd5\x97\x3b\x24\xd5\x40\x89\xb2\xda\xf0\x84\xd5\x41\x47\x65\x10\x5e\x4e\xca\x14\xaa\xad\xd1\x05\x33\x38\xa8\x47\x05\x05\x23\x2e\x4a\xc6\x33\x34\x5c\x5c\xde\xe1\xe4\x65\x3d\x1d\x93\x58\x3a\xf1\x18\x54\xb1\xd9\xb6\x5f\xc2\x02\x81\x83\x8c\x56\xdf\x11\x48\xf3\x5c\xcf\x9b\xfe\x2f\x3f\x80\xab\x73\xf5\xb7\x91\xcb\xed\x2d\x92\x06\x44\xcf\x03\x16\xf0\xcb\x5d\x36\x62\xb9\x12\x06\x47\xda\x56\xaf\xbe\xb4\x7a\x95\x29\x53\xbc\x1a\x37\xde\x85\x7e\x4b\x39\xfd\x92\xb6\x32\xb8\x51\x59\xf4\x6c\xd0\x5b\x6a\xbc\x23\x38\xd4\x63\x2d\x48\xe9\xa1\x78\x86\x0d\xe8\xf6\x5d\x9b\xc2\x3f\x24\x50\x7b\x7c\x56\x29\xe0\xbd\xaa\xc0\x67\xc4\x76\xc9\xc3\x94\x1d\x86\xf7\x88\x94\x4d\x74\x48\x52\xa6\x1d\xa7\x16\xf9\x5f\x3b\x04\xf0\x78\x3a\x56\x29\x41\xbc\xdd\xa4\x39\x59\x0f\xd1\x86\xb2\xa8\xeb\xf1\x9a\x5a\x7e\x4f\x4a\x3a\xaa\xb7\xa8\x7a\x43\x45\x24\xfb\xc9\x79\x9c\x99\x31\xeb\x8c\xe4\xe3\x4e\x99\xb6\x08\xca\xc9\x4a\xb7\xe7\x44\x95\x66\x8d\xf1\x36\x18\x5f\x48\x7d\x9f\xbc\xb6\x60\x5a\xd7\x25\x34\x54\x03\xec\x57\xf3\xf6\xdb\x36\x4a\x87\xf3\x8f\xea\x4b\x4c\x27\x15\x52\xe9\xf2\xe4\xa1\xbe"}, -{{0xdb,0x5d,0x5f,0x41,0xfd,0xdd,0x67,0x68,0x70,0x97,0x47,0xab,0x82,0x39,0xbb,0x4f,0x42,0xa3,0x1d,0x34,0xb4,0xfa,0x88,0x82,0x4d,0x94,0xbf,0x78,0xd3,0x14,0x92,0x64,},{0x03,0x85,0x8c,0xe6,0xb2,0xd2,0x40,0x79,0xee,0xad,0x66,0xca,0x0d,0xfe,0x77,0x2e,0xcd,0xa9,0xaf,0x4d,0x46,0xbc,0x9b,0x5e,0xdf,0xdc,0x28,0x6b,0x95,0xfe,0x97,0x16,},{0x5b,0x3d,0x0d,0xa7,0x10,0x23,0x55,0x48,0x6b,0xe4,0xd6,0x9c,0xfd,0x65,0x88,0x6c,0x9d,0x9c,0x87,0x38,0xb2,0x93,0xca,0xfb,0x23,0xb2,0x10,0x4b,0xfd,0xac,0x8d,0x7d,0x01,0x29,0x8e,0xeb,0x18,0xfd,0xe3,0xde,0xd6,0x49,0x1d,0x41,0xb4,0x19,0xcc,0x66,0x37,0x52,0xc4,0xe6,0x7d,0xbe,0x89,0x86,0x83,0x3d,0x20,0xe4,0xef,0x34,0x18,0x0b,},"\x67\xee\x03\xde\x45\xc3\xe7\x03\x0d\xb5\x24\x6e\xe5\xb5\x1b\xf2\x98\xbb\xa3\xe4\xd0\x93\x49\x37\xfc\x12\xd9\xa6\x29\x60\x4c\x53\xc0\x70\xe3\x0d\x61\x19\x99\xa9\xcd\xda\xf2\xd9\xac\xda\x6a\x9f\x67\x20\x2b\x35\x23\x69\xd4\x82\x60\xee\xbc\xe0\xe7\x8e\x4d\x5a\xe5\x4f\x67\x75\x21\xf8\x4a\x7b\xe0\x01\x7f\xab\x27\x8b\x2b\x57\x27\x5e\xfc\x5f\xa5\x7c\x61\x71\x86\xfc\x1b\xa4\x9e\xdf\xbd\x33\x08\x63\x48\x78\xd8\x64\xf2\xda\x15\x83\xca\x8d\x56\xce\x9f\xae\x77\xc4\x62\x03\x9a\xbc\x32\xd0\x53\x9c\x0a\x60\xb7\xbb\xba\x50\x29\xe9\x32\x9d\x27\x56\x83\xd9\xc4\xce\x77\xd0\xb9\x08\xad\xe9\x8b\x0e\x32\xb4\x42\x0d\x9a\xee\x2c\xc1\x0e\x4b\xe9\x22\xf9\x57\x25\x82\xdd\x89\x67\x14\x1c\x1d\x40\x2e\x21\x5f\x20\xae\xe0\xa8\x90\xe2\x36\x8e\x40\x6d\xea\x11\xbd\x11\x17\x7f\x2e\x03\x8a\xa2\xf1\xa0\xdf\xf5\x1a\x12\x8d\x95\x5d\x5e\x5f\x8d\x5d\x00\x09\xaa\xa8\x24\x40\xa9\x68\x64\xd6\xc6\x97\xf9\x10\xd1\xdf\x23\x0f\x46\x7f\x0e\x02\xa2\xe0\x2b\xf9\xe4\x5d\xa9\x5f\x25\x54\x10\xcc\x5a\xab\x8d\x85\xf4\x49\xa5\xde\x99\xaa\xbd\x44\xfd\x76\x3e\xc1\x46\x29\xf3\xdb\xab\x1a\x24\x7b\xff\xb7\x17\x46\x48\xe4\x3b\x9f\xb1\xeb\x0d\xf5\xe4\x10\x9b\x7a\x88\xe0\x55\x12\xb2\x08\x65\xba\xd3\x9f\x9e\xa7\x9d\x52\xf5\x18\x8e\x7c\xa5\x19\x44\x05\xbf\xb1\xa0\x97\x27\x61\x7f\x3f\x6c\x88\x19\x20\x08\xed\xbc\x0c\x65\x85\xdb\xf2\x61\xf1\x49\xdf\xfb\x59\x3d\x42\x71\x6e\x5a\x57\x77\xf5\x46\x2b\xee\xb1\xe9\xa5\x6a\x2c\x76\xe6\xcb\x73\x51\x17\xcc\x11\x83\xa3\x8d\x1e\x00\xb3\x03\xd1\x74\xaa\x9c\xf5\xc7\x31\xb2\xc7\x0e\xdd\x79\xcc\x5d\xc9\x6f\x40\x18\xf1\xd7\x1d\x71\x98\xbb\xb7\xd1\x34\xcd\x2f\xf8\xc1\x5f\x9a\x04\x28\x0d\xb2\x6a\x8f\xa9\x99\x7e\xb8\x6b\x13\x3c\x02\x2e\xda\x15\xd8\xad\x5e\x77\xcc\x9f\x62\x61\x59\x60\xba\xc2\xf9\xbb\xc3\xeb\xbd\x19\x8f\x72\xc5\x72\xb9\x71\x56\xfa\x7f\xa2\x29\xa9\x80\x14\xe1\x70"}, -{{0x7f,0x04,0x8d,0xfc,0xc2,0x65,0x0c,0xda,0x59,0x49,0x1d,0x4c,0xe2,0xb2,0x53,0x3a,0xec,0xc8,0x9c,0xc4,0xb3,0x36,0x88,0x51,0x94,0xb7,0xad,0x91,0x7d,0xb5,0xcd,0x14,},{0x08,0x00,0x1b,0x5d,0x40,0x95,0x8b,0xcb,0x27,0x0b,0xee,0xa9,0xba,0xba,0x33,0x87,0xe3,0xa4,0xb9,0x00,0xfc,0x42,0x27,0x56,0x57,0xc6,0xc6,0x91,0xa2,0xe2,0x64,0xf2,},{0x58,0x33,0x70,0x97,0x1d,0x24,0x65,0x2a,0xd2,0x13,0xc4,0x26,0x15,0x91,0x19,0x38,0xfa,0x9a,0xa3,0xd9,0xb7,0x19,0x69,0x40,0xe6,0xeb,0x08,0x15,0x12,0x00,0xc7,0xb6,0x72,0x9d,0x1e,0xff,0x8f,0x4f,0x09,0x04,0x07,0x4d,0xab,0x3d,0xdd,0xa6,0xaf,0x1e,0x4e,0x56,0x2b,0x7d,0x62,0x20,0xc1,0xa5,0x62,0x68,0x3b,0xea,0xb2,0x68,0xf8,0x0e,},"\x91\x75\x19\xcd\xb3\x35\x19\x68\x0b\xca\xe0\x4f\xaa\x79\x07\x71\xce\x7d\x13\x97\xc3\x45\xf1\xb0\x3d\xd7\x62\x57\x76\xf3\xf1\x95\x80\x99\x32\x61\x8b\x1c\x64\xac\xd9\x3a\xd0\x00\xea\xd0\x96\x54\xa3\x3d\x14\xf7\x48\xb4\x6b\x67\xaa\xe0\xff\x12\xdf\x3c\xc1\x63\x28\x0f\x47\xce\xdc\x16\xa8\x57\x90\x34\xe4\x98\x84\x29\x67\x72\xec\xbd\xbb\x71\xca\x29\xc1\x66\x23\x35\x33\xc8\xde\x54\x01\x2b\x41\x2c\xa1\x3c\xc2\x58\xf7\xc5\x46\x5d\x83\x42\x2f\x52\x4e\x4c\x05\xf8\x06\x31\x34\x78\x31\x9f\xd1\x43\xcf\x50\x88\xe6\x98\x37\x69\x7d\x36\x15\xd8\x0a\x7f\xa7\xe7\x44\x3f\xca\x65\xe7\x53\xac\x1b\x11\xd8\xef\xf3\x47\x66\x36\xae\x02\xd7\xa2\x0f\x4b\x23\x88\xda\xd6\x84\x00\x2f\x5c\xe9\x57\xca\xdd\xd2\x05\x3d\x0e\xd5\x33\x13\x2a\x81\xca\x19\xbb\x08\x0b\xd4\x3b\xe9\x32\x02\x8c\xb5\xf6\xb9\x64\xf0\x08\xb5\xb1\xc1\xc5\x99\x3b\xc9\xb5\x48\x5b\x22\xbb\xef\x70\x1f\x0a\x26\xa3\xe6\x75\xea\x31\x12\x2b\xba\xe9\x1d\x86\x4b\x54\xd8\x95\xaf\xdc\x79\xca\x58\xd4\xfe\x44\x92\x13\x35\x3b\x14\x9f\x31\x43\xb5\x14\x4d\x74\x7c\x5b\x46\x97\x47\x9a\xe6\x85\x28\x48\x53\x84\x04\x4a\xa2\xc9\x9b\xa4\xb1\x7b\x18\x4e\x94\x98\x22\x69\xbd\xe2\xde\x0b\x17\x70\x5d\x0b\xfc\x46\xd6\x90\x6a\x90\xed\xef\xe8\x91\x95\xde\x6b\xb8\xf3\xfb\x6a\x37\x41\x86\xc7\xcd\x08\x6d\x13\xd1\xb3\x52\x5a\x39\x94\xdc\x80\x20\xe1\xa0\x05\x54\xac\x8a\x82\xd6\x04\x7c\x5b\xff\x5e\x7f\x12\x45\x0f\x48\x65\xda\x16\x1e\x1a\x02\x1f\xd9\xbe\x8b\xd3\x3a\x32\xbb\x54\xa4\xdd\xf8\x74\x51\x2e\x74\xb5\xcf\xd3\xfc\x3c\xd9\xac\x11\xed\xd8\x78\x43\x36\x68\xe3\xfc\xc7\x82\xb9\x7b\x6d\x90\x5a\xdb\x0e\xbe\xc4\x2c\x92\x54\xac\x90\xf3\x58\x22\xc0\x0f\x97\xff\x3f\x0c\x7c\x39\xed\x3c\x7c\xb3\x92\x0f\x56\x08\xbb\x45\x83\x8b\xb2\x42\xa5\x2a\x86\x37\xd7\xce\xcd\xcf\x48\x9f\xa1\x83\xb4\x54\x51\xc6\xc9\xfc\xbb\xbf\x91\x4f\x5f\x7e\x6b\x22\x3b\xcb\x46\x75"}, -{{0x9f,0xeb,0x3d,0xf8,0x8c,0x49,0x4a,0x99,0x84,0x9c,0x6f,0xca,0x19,0x42,0x01,0x47,0x7a,0x2f,0xa7,0x56,0x4e,0x29,0xfb,0x06,0xcb,0x44,0xc1,0x15,0x4e,0x8c,0xea,0x3a,},{0xc3,0x56,0x28,0xca,0x6e,0xe2,0x8e,0xc1,0xc2,0x39,0xdd,0xc5,0xbb,0xa2,0xa9,0xe0,0x9e,0x48,0x46,0x81,0x6b,0x14,0x3c,0x74,0xdf,0xa2,0xae,0xc1,0xf6,0x25,0x51,0xb6,},{0xa1,0xc2,0x60,0x78,0x35,0xbe,0xc1,0xa1,0xd8,0x78,0x72,0xfd,0x8e,0xe4,0x88,0xd0,0xae,0x9e,0xd2,0x3d,0x49,0xfd,0x67,0x86,0xfc,0x49,0x96,0x72,0x5e,0x49,0xb3,0x26,0x21,0x18,0xba,0xbb,0x48,0x34,0x87,0x7c,0x7f,0x78,0xfb,0xea,0xc0,0x2d,0xf4,0x0a,0xb0,0x91,0xb8,0xb4,0x20,0xdc,0x99,0x51,0x38,0x1e,0x3b,0xcd,0xa0,0x67,0x05,0x02,},"\x95\xfb\x75\x81\xbd\x25\xff\xd4\x42\xc3\xae\x38\xa1\x9b\xea\x73\x49\xc7\xb7\x68\x3b\xa6\x76\x7e\x14\x8f\x0a\xfc\x15\x37\x3f\x67\xc1\x6d\x47\x17\x81\x20\x2e\x6d\xa8\x05\x4e\xd7\xfb\x9e\xe2\x04\xcc\x0f\x63\xc2\x10\xa6\x70\xa5\xf9\xce\xd4\x29\x45\x88\x19\x63\x30\xd3\x1b\x8e\x83\x92\xbe\xf6\xb4\x8f\xe3\xc9\x20\x78\xfa\xe1\x12\x84\xb4\xc3\xba\x20\xd9\x37\xe2\x71\x9d\xe7\xbf\x67\xc0\x06\x69\xad\x23\xe6\x13\x84\xeb\xdf\x8c\x6e\x60\x73\x54\x28\xc0\x84\xfe\x21\x7f\xdb\x47\x09\xcc\xb6\x08\x3f\xc0\xae\x4a\x05\x27\x3e\xef\x73\x90\x23\xd3\x4b\xb7\x3f\x66\x2d\xac\xdf\x11\x0b\x6d\xbd\x3e\x74\xfc\x14\x91\xe8\xc9\x65\x96\x07\x5f\xae\x5c\x36\xaa\xbe\x2a\x0a\x53\x05\x2b\xf7\x7c\x44\x62\x43\x80\x63\xaa\x7b\xc0\xc5\x0a\xb9\x20\xc9\xeb\x28\x86\x71\x56\x0c\xa5\xba\x7a\xf4\x4a\x53\xdb\x2e\x2f\xf4\x3c\xa5\x60\x69\xea\x55\x17\xcb\x21\x4e\x76\xfa\xa5\x3d\xbd\xa1\x00\x00\x3c\x4f\x61\x75\x41\x40\x41\xbe\x74\xde\x22\xce\x15\x5d\x22\x81\xb6\xf4\x03\x5b\xe3\x98\x41\xaf\xdb\x96\xdd\x89\xaa\x80\x8e\x68\x65\xba\xe6\x2d\x6b\xed\xd9\x19\xd3\xe8\x65\x10\xb9\xfa\x5f\xed\xd1\x97\x7c\x41\x31\xb2\xb8\x6e\x0f\x48\xd7\x21\x5e\xb1\x3d\x54\x98\xca\x5d\x23\x68\xf8\x18\x95\xed\x85\x5a\x52\x71\x24\x65\x7e\xc9\x53\x9e\xfe\x3b\x24\x99\xa3\xb0\xb3\x38\x26\x2f\x26\x34\x0e\x22\x55\x4c\x79\xf4\xfa\xd2\xb4\xe4\x19\xc7\x0b\xc1\xa2\x10\x7d\x20\x64\x56\xb6\x36\x87\x81\xbe\x4b\x5e\x2c\x54\xda\x42\xd3\x36\x04\x0f\xb7\xba\x49\xc3\x2d\x75\x23\x21\xad\xcd\x92\x98\x6e\x78\xbe\xdb\x22\x6c\xea\xc5\x02\x92\x08\x9b\xb5\x79\x02\x7f\x70\x22\x17\x74\x5a\xfe\x06\xa5\xbe\x13\x6b\x39\x98\xa3\x60\x4c\x9f\xf2\xac\xd6\xfa\x3f\x3f\x71\x63\x3d\x31\x02\xfb\xf0\x30\x47\xc5\x48\x6f\x84\xc4\xdc\x24\x47\xd8\x63\x79\x63\x83\xd5\x5f\x08\xc9\x81\xfd\x4d\xd7\xdc\x1c\xb7\x2b\x8b\xa4\x43\x5a\xf6\xab\xdd\x74\xe6\xf6\xe6\x79\x8f\x1a\xe2"}, -{{0xbf,0xf6,0x89,0x55,0xdd,0x6a,0xe0,0xe8,0xba,0x85,0xab,0x0d,0x0c,0xda,0xf0,0x4a,0x9f,0x5b,0xef,0xd5,0xef,0x60,0x14,0xf4,0x99,0x94,0xa7,0x83,0x63,0xdc,0x17,0xf7,},{0x0a,0xd9,0x49,0x3a,0xf8,0x0b,0x15,0xf0,0x7a,0x52,0x1c,0xcd,0x67,0x4f,0xe9,0xe5,0x21,0x2a,0x4a,0x28,0xc1,0x7c,0x74,0xf6,0x60,0x5f,0xfe,0xf7,0x8a,0x4a,0xed,0x72,},{0x93,0x19,0xee,0xf7,0x40,0x63,0x3a,0xda,0x1a,0xf0,0xe1,0x37,0x64,0x4c,0x61,0xfb,0x3e,0x11,0xba,0x4b,0x01,0xd3,0xc6,0xf2,0x53,0x92,0xdc,0x93,0x67,0x87,0x2a,0x23,0xbe,0x56,0x31,0x0d,0x31,0x2e,0xfc,0xb9,0x1b,0xdb,0xab,0x78,0xa7,0x5e,0x57,0x6e,0xbe,0x90,0x81,0x97,0x24,0x15,0xf5,0x62,0xdb,0x41,0xba,0xf5,0xe2,0x33,0x8b,0x07,},"\xd8\xf5\x65\x0a\xa3\x58\x1c\x4d\x39\xbd\x1b\x8a\xfc\x96\xc1\xad\x7c\x4b\xf7\x23\x42\x6f\x9d\x7f\xab\xd1\xa5\xc8\xac\x1d\x2f\xe5\x4a\x97\x1f\xac\x76\x5e\x05\xaf\x6e\x40\x7d\x72\x69\xba\xb6\x61\xb3\x43\x22\x92\xa4\x84\xf9\x52\xc1\x10\x95\xbb\xd2\x0a\x15\xd7\x7c\x41\xf8\xf3\x73\x1a\x50\x4d\x51\x8e\xe1\x0c\xd0\x06\xc9\x6e\xe5\x73\x72\xde\x5b\xea\x34\x8e\xc8\xba\x15\x91\x62\x17\x0c\x63\xe9\x70\xf1\xc7\xa3\x46\x5a\x3d\x59\x2e\x1d\x56\xc6\x54\x0f\xbd\xb6\x02\x28\xe3\x40\x90\x96\x46\x32\x0c\x95\xf2\x56\x98\xcd\x48\x96\xbd\xff\x58\xe2\x56\x1e\x3b\x3d\x9a\x73\xb8\x97\x47\x91\x2a\x1c\xf4\x67\xd6\x3e\x41\x45\x5f\xda\x77\x47\x7f\x46\xfe\x69\x37\xbb\x0e\x79\xd9\x2c\xcd\x52\xe8\x2d\xba\x90\x8a\x05\xa5\x7c\x7e\xcf\x49\x55\x4a\xb4\x4c\x0b\x71\x8e\x3b\xdd\x5f\xc0\xbf\x70\x70\xd9\xc5\x8f\x86\x05\x91\xc1\x8b\xca\x8b\x3a\x9a\x14\x8a\x06\x54\x8e\x0f\x01\x60\x2b\x1e\x6f\x68\x60\x37\xc9\x4f\xf7\x32\xe1\x55\xd5\x2d\x5b\x0b\x44\x70\x3b\x3d\x11\x16\x3e\x3f\x56\xe3\xb9\xc1\xb8\x64\x76\xe4\xdc\xbf\xc5\x3f\xa0\x59\x84\xe8\xc7\x5d\xd2\x18\x43\xcf\x96\xf9\xe4\x94\xab\xba\xe7\x18\x4a\xa4\x27\x36\x63\x3e\x38\x11\xae\xff\x40\x2b\x2f\xcb\x7d\x7f\x70\x2e\x44\x72\x41\xe2\x2a\x58\x84\x2f\xd6\xd0\xc0\x3d\x33\xff\x5b\x8c\x79\x22\x00\xe1\x73\xda\xa7\xb2\x17\xe4\xb2\xf4\x43\x3e\x6c\x02\x0a\xcc\xe5\x01\xb9\x32\x3a\xa0\x24\x11\x44\x43\x4b\x08\xe9\xd2\x46\x91\x39\xff\x67\x34\x22\x08\x90\x05\x46\x20\x0f\xd9\x71\xa6\x5d\xbd\x6d\xb6\xc2\x1e\x3e\xf9\x17\x2a\xbb\xa1\xea\x9e\xa2\xa2\x49\xad\xdf\x1a\x1e\xaa\x3c\xe1\x19\x38\xb1\x3e\x30\x91\x3c\xd0\xda\xd4\x91\xfc\xbb\x32\x85\xea\x37\x8b\x8e\xf9\x22\x7f\x3f\xa8\x0b\x58\x6e\xcf\xea\xe1\x37\x06\x6f\x84\x48\xac\xdf\xb7\x8d\x6d\x3e\x9e\xf4\xa6\xb3\x62\xdf\x42\x41\xad\x9a\xe2\x53\xb8\xe1\x59\x7d\x65\x6e\x00\x0c\xea\x44\x7a\x02\xfa\x49\x33\x32\x86\x09\xbb\xa0"}, -{{0x1b,0xa9,0x19,0xc0,0x66,0xbb,0x56,0xe6,0x40,0xc3,0x33,0x59,0x68,0xe1,0xd1,0xb5,0xbc,0xc0,0x93,0x38,0x3e,0x2d,0x7c,0xf8,0xb5,0xff,0xf5,0xc6,0x1e,0xc4,0x7a,0x77,},{0x80,0x4c,0x90,0xbd,0xc2,0xb3,0x61,0x8b,0x01,0xf0,0x75,0xe0,0x41,0xfa,0x97,0x1b,0x83,0xc5,0xb6,0xcf,0xa3,0xb6,0xb3,0x97,0x4f,0x3f,0xa4,0x35,0x99,0xbe,0xac,0xab,},{0x50,0x3e,0xb7,0xed,0x6d,0xe1,0xb7,0x76,0xc9,0x52,0xf2,0x55,0xbb,0xd4,0xbc,0xfb,0x0e,0x48,0xbc,0x70,0xc2,0xcc,0x2f,0x1f,0x72,0xbf,0x68,0x81,0x47,0x90,0x40,0xc4,0x75,0x24,0xec,0x54,0x2a,0xe1,0x3f,0x60,0x05,0xca,0x50,0x16,0xb5,0x8b,0x73,0x6a,0x50,0x89,0x8d,0xd0,0x56,0x9d,0x4d,0x38,0xad,0x29,0x86,0x30,0xd6,0x8a,0xdb,0x0b,},"\x87\xc5\xc7\x5d\x8a\xd0\x7d\x52\xac\xd7\x81\xd1\xbb\x95\xf7\x8c\x70\xe2\x1c\x2d\xd6\x6f\x7a\xa4\x42\x34\x15\x2f\x98\x23\x4d\x12\x83\x58\xa8\xae\xe9\x8e\xa9\x03\xa7\x7b\x44\x1d\xb1\x44\x7a\xe6\xff\x34\x32\xdd\xd4\x57\x0f\x7f\x58\x03\x61\x22\xc1\xfd\xcc\x93\xcb\x21\x57\x37\x39\xc1\x9c\xca\xa4\x11\x50\x8e\x08\xde\x26\x06\xf3\xd8\xf2\xdb\x89\xdf\x6a\x44\xa4\x61\x33\xd5\x70\x18\x46\x26\x27\xe2\x2f\x57\xef\x36\xd1\xde\x02\x4d\xe3\xd4\xae\x41\xb7\x52\xdf\x48\x21\x15\x59\x34\xb4\x47\xb2\xef\xfe\x51\x24\x87\x52\x1b\xe0\x35\x68\x32\xa7\x4c\xe0\xe2\xd8\x30\x1b\x79\xf9\x31\x75\xe8\xb6\xb9\x61\xb1\xdf\x63\x7d\x8a\xca\xdc\x88\x45\x43\xc6\x86\x4f\x80\x25\xec\xec\xec\x7c\x6e\x4f\xe0\xfe\xcf\xc4\x0d\xcd\x95\xe8\xd6\xab\x93\xce\x25\x59\x53\x84\x43\x6b\x59\x8b\x73\xc7\x4b\x03\xd4\x9e\xd5\x00\x2c\x0f\x85\x8c\xfd\x9d\x0d\xf6\x1e\xde\x93\x7c\xc4\x16\x59\xd6\x70\x8b\x96\xfc\x5a\xaa\xde\xe1\x09\xe2\xa6\x88\x46\xba\xf2\xc2\x46\xdf\xcf\x3d\x27\xc2\x8b\xd1\x37\x1e\x35\xfc\x94\x12\x63\x14\x42\xee\x75\xf3\x8c\x6e\x49\x58\x07\x0a\x74\xf6\xe6\xa2\x20\xf7\x5c\x72\x80\xea\xb4\x73\x7d\x97\xe3\x78\x82\xf3\x62\x48\x11\x67\x5f\x16\xca\xf6\x0c\xb9\x44\xbc\xe9\x2e\x75\x88\x4c\x56\x48\x3c\x61\xf2\x6b\x63\x71\xb1\xb5\x12\x37\x62\x1a\x06\x54\x3e\xb4\xab\xea\x7b\xec\xc4\xfc\x31\xdb\xb5\x47\x5b\x3d\xeb\x9b\xb3\xc8\x99\x23\x87\x10\x48\x30\xc6\x07\x2a\xfe\x1a\xf2\x44\xbf\x68\x1a\x40\x32\x9c\x9b\x37\x77\x2b\x09\xc5\xe8\x8e\x78\xf7\xdf\xfb\xc0\x45\x49\xff\xa1\x3b\x41\x44\xdd\xfa\x53\x8f\xc4\xb3\x30\x05\x40\xad\x83\x02\x15\xe2\x5f\x11\x44\x6d\x28\x9f\x33\x12\x2c\x2c\x88\x0d\xe3\xda\x71\xc4\x53\xd7\xe8\x8f\x7c\xa4\xea\x3d\x12\x55\xe8\x2f\x4b\xc9\xe5\x53\x3d\xc4\x01\xc3\x30\x40\xe1\x69\x40\xb2\xcf\x9c\xf2\x1f\xea\xca\x1c\x2c\x6c\x33\x33\x7c\xf7\x5e\x18\x84\xb4\x83\xbf\x80\x15\x36\xd3\x04\x08\x91\x15\xa0"}, -{{0x9b,0x36,0x24,0x7c,0x17,0x71,0x0e,0x95,0x26,0x1a,0x7d,0x70,0x2f,0x57,0xfe,0x81,0xf2,0x97,0x11,0x17,0xa5,0x0c,0x87,0x92,0x01,0x93,0xb3,0x86,0xd4,0x94,0xca,0x97,},{0x29,0xae,0x39,0xf2,0x73,0xe3,0x5f,0xb3,0xf6,0x11,0xda,0x09,0x16,0x00,0x65,0x0e,0xfb,0xc4,0xfc,0x4d,0x1e,0x7b,0x4c,0x76,0xac,0xed,0x5a,0x83,0xf8,0x26,0x34,0xf3,},{0x03,0x59,0x70,0xa6,0x72,0xe9,0x3f,0x87,0xeb,0x42,0xcc,0x39,0x6f,0x6e,0xa7,0xe1,0xb3,0xdd,0x5c,0x59,0x51,0x57,0x28,0x26,0xd1,0x07,0x5a,0x15,0xc2,0xd7,0xe4,0x54,0xdf,0x19,0x5b,0x51,0xaa,0xe8,0xdc,0x61,0xef,0x7a,0xb8,0x95,0x48,0x5f,0x64,0xe5,0x98,0x95,0x73,0xd9,0x8a,0x06,0x2e,0x67,0xae,0x73,0x56,0xfe,0x5c,0x9e,0x3b,0x0f,},"\xe8\xd9\xd5\x3b\xa2\x7e\x98\xed\xd5\x5d\xf3\xc6\xb2\x45\xea\xcd\xdc\x8a\x40\xe3\xef\xb0\x07\xbc\x91\x8e\xc5\xa8\x69\x17\x8a\x17\x0b\xb4\xa6\x35\xb7\xf8\xf7\x42\xe3\x7a\xd4\x5d\x14\xa7\x43\x44\xa6\xb5\x22\x83\x0a\x52\x21\x06\xeb\x96\x0d\xaf\x19\x2d\xc1\xe0\xfd\x70\xf1\x61\x60\xe1\x22\x51\x68\x92\xd0\xe2\xab\xd0\xd4\xae\x0f\x0d\x2e\x5a\xdc\xc9\x9a\xd5\x53\x02\xe2\x51\xb3\xe7\xa4\xd0\xcb\x33\x77\x4a\x49\x70\x49\x90\x5c\x33\xde\x1f\xbb\xc1\xad\x2b\x6c\x64\x52\x95\xfe\x41\x6b\x4d\x12\xb2\x32\xef\xe0\xa3\x3c\xd2\xad\x87\x32\xeb\xa1\xc3\xcb\x0e\xae\xb0\xb2\xa5\x7f\xa0\x3e\xc5\x67\xca\x29\x21\x0b\xf6\xff\x95\x42\xa7\x66\xf4\x96\xfe\x68\x05\x8a\xa9\x83\x80\x6c\xbe\x7a\xb1\x0a\x47\x92\x0b\xac\x82\x48\x81\x8e\x54\xa4\x15\x51\xc9\xa0\x95\x9e\x89\x94\xca\xc6\x0f\xc8\x68\xad\x48\xb5\xa2\x4d\x5f\x24\xa7\xa5\xa3\xfd\x90\xb8\x47\xe8\x17\xad\x3d\xd5\xd0\xd6\xf8\xde\x2d\x20\x4f\x64\x24\x83\xbd\x53\x58\x5a\x92\xef\x92\x54\x15\xa9\xb3\x8f\xbb\xf0\x7f\xc0\xf3\x5e\x70\x75\x69\xcf\x48\x8b\x20\x54\x53\xce\x54\x33\xeb\xa6\xfd\xe8\x78\x1a\xf7\x2b\x52\xbf\xbc\xab\x85\xea\xd3\x85\xd9\xd3\x17\x5e\x21\xad\x33\x73\xad\x53\x5c\xf0\xe3\x57\xed\x6b\x53\x83\xef\x38\x29\xa9\xd5\x09\x5b\x87\xdc\x9a\xad\xbe\x0c\xa7\xab\xad\xf3\x3e\xc3\xb6\xff\xd6\xeb\x94\xaf\xdc\xc1\x2e\x8d\x66\xa6\xfc\x05\xac\xf9\x73\x68\xdb\x0f\x69\x56\x5d\xcd\x8f\xef\x4d\x1e\x49\xd7\xdd\x4a\xc0\x53\xc2\x18\xf5\x24\x0c\x81\x2d\x4e\xbb\xa4\x40\xdc\x54\xca\xcd\xdb\x1c\x39\x32\x9e\x5b\xd0\xc3\xc8\x0d\xc3\x25\x9a\x80\xf0\x59\xf9\x46\x79\xaa\x07\x94\xca\x01\x15\xcc\x62\xaf\x25\xe1\x24\xcb\x8a\x9d\x41\x60\xea\xce\x6d\x22\xc7\xb1\xc4\x45\x44\xf8\x11\x42\xa1\x9e\xbb\x02\xa9\xbd\xa6\x42\x9c\x50\xe7\x83\xdb\x4a\x07\xf0\x21\x9e\x85\x7c\x8d\x3c\x56\x55\xa5\x82\x83\x1c\x8e\xab\xc3\xf1\x9b\x59\xad\x8d\x2c\x71\x4a\xde\xaf\x40\x39\xd5\xcf\x70"}, -{{0x6f,0xed,0xe7,0x39,0x6c,0x46,0x20,0x33,0x18,0x9a,0xcd,0x23,0xd2,0xf9,0xd0,0x2b,0x68,0x89,0x8d,0x35,0xf3,0xa0,0x1a,0x79,0x8f,0xc2,0x4d,0x48,0x8d,0xe9,0x3a,0x78,},{0xb3,0x40,0x62,0x06,0x0b,0x2c,0x20,0x07,0x6a,0x98,0xfe,0xa9,0x39,0xb3,0xb3,0xa5,0x04,0x51,0xa5,0xf4,0x9f,0x83,0x51,0xc0,0xad,0x75,0x91,0xdb,0xbe,0xbb,0x13,0x0f,},{0x88,0xa8,0x3e,0x20,0x12,0xd2,0x09,0xca,0x03,0xb8,0xeb,0xf6,0xde,0x5b,0xb7,0xef,0x4c,0xcb,0x5e,0x3d,0xf5,0xca,0xc7,0x89,0x54,0xaa,0x69,0x49,0x30,0xe4,0xde,0x82,0x54,0x4e,0xf5,0x08,0x3c,0x48,0x92,0xdb,0x9f,0x05,0xd7,0x7b,0xf6,0x3f,0x4f,0xdf,0xce,0x15,0xa4,0xd1,0xc3,0xf8,0x5b,0xae,0x80,0x77,0x06,0x2b,0xec,0x0e,0x7b,0x07,},"\x5a\xbc\xc1\x4b\x9d\x85\x78\xde\x08\x32\x1d\xe0\xd4\x15\xe3\xd4\x0e\x9d\xe3\x1e\x18\x88\x13\x74\x75\xce\x62\xbc\x6f\xbe\xe8\xfd\xd0\x3b\x9d\x47\xc7\xb8\x8b\xbc\xeb\x80\x44\x44\x49\x0b\xf6\xa3\xcc\xb7\xa2\x73\x26\x1e\x24\x00\x4e\xa6\x7c\xef\xa3\xd5\xd1\x73\x57\x6d\x01\xe3\x8f\x76\xc1\xe0\xe5\x15\x08\x3c\x97\xe7\x99\x14\xac\xf2\xbe\x41\x60\xef\x93\x60\xbb\xe9\x86\xb3\x6e\x9f\xf9\x33\x46\xb0\xe7\x06\x91\xd9\x34\xe4\x7f\x8a\x50\x3f\xa9\x33\xab\x2a\x50\x42\x69\x47\xcd\xa8\xe8\x10\xc9\xeb\xe3\xb3\x69\x82\xf0\x9a\xee\x60\x92\x73\x9f\xa2\x35\x8b\x61\x3c\x7f\x12\x9d\xb0\xdc\xbe\x36\x8b\xee\x52\xf2\xf7\xf1\xdf\xe3\xd2\x43\x46\x05\xb5\xaf\xcf\x25\x60\x71\x71\x7d\x92\x4f\xd0\x80\x3b\xbd\x0d\xd1\xf9\x55\x5c\xe8\x34\xda\xc7\x81\xdf\x4c\xc7\xaa\x19\xe7\xf1\x1d\xa9\xfb\x99\xcb\x9e\x6b\x9e\x1e\x6f\xb4\xf7\xe8\xdc\xb2\x23\x6c\x28\xae\xb6\xcb\xc5\x5a\x13\x0e\x03\xc1\xb1\x7a\x99\x1c\xca\x1b\x79\x4e\x6c\x13\x73\x2d\x5b\x0a\x66\xf6\xeb\xa8\x60\xec\xb9\x85\x55\xaa\x4c\x21\x8d\x11\x2b\x11\x6b\xce\x23\x82\x95\xde\x14\x27\x41\xf6\x87\xbe\x0b\x24\x87\xf5\x8f\xfc\x5c\x12\xa0\xa5\x19\xf1\xe2\x37\x93\x24\x2e\xf8\x57\xed\x39\x8a\x20\x69\x9d\x43\x51\x45\x3f\xc2\xf0\x92\x76\x2a\xbd\xe3\x4f\x4d\xa2\xdb\xe0\xce\x2a\xab\xaf\x6b\xc4\xc0\x15\x9f\x3f\xe1\xae\xa1\x6a\x03\x6f\x7e\xae\xcd\x62\x95\x38\xf3\xe0\xee\xd8\x3c\x9a\x4d\xc1\xab\xc2\x38\xf9\x0d\xaa\xf4\x89\xfd\x61\xb3\x4d\x93\x7b\x6f\x46\x07\xa7\x88\xba\xa8\x20\x61\x94\x3d\xba\xb2\x6c\x1d\x38\x4d\x8d\x49\xf9\x93\x48\x80\x0b\xf3\x61\xf8\x71\xf5\xd6\xcd\xa1\x8f\x68\x99\x18\xce\xc3\x1a\xd1\x58\xf1\x86\x3d\x13\xff\xac\x54\x05\xc1\x62\xc3\x2d\xe0\x6e\x32\x99\x4c\xc4\x10\x6f\x95\xbb\x4f\xff\xdb\xef\xe7\xd6\x29\xec\x77\x97\x39\x46\x09\xfd\xbf\xea\xdb\x46\x92\x73\x70\xa1\x1f\xb3\x84\x71\x54\x0f\x95\x1b\x93\xc6\xeb\x23\x86\x68\xdc\x00\x6c\x21\x66\x0b\xa2"}, -{{0xd5,0x59,0x58,0x01,0x34,0xab,0x05,0x0a,0xca,0x44,0x6e,0xa7,0x75,0x0e,0xf6,0xb3,0x71,0xd9,0x2d,0x76,0x45,0xec,0x76,0x35,0xfe,0x78,0x51,0x10,0x0b,0xc4,0xe5,0x1e,},{0xde,0x50,0x20,0xcd,0x21,0xa8,0xb3,0x23,0x39,0xde,0xcb,0xed,0xff,0x24,0x66,0x4d,0x95,0x80,0x32,0x63,0x27,0xae,0xdf,0x09,0xc5,0xec,0x6b,0x3f,0xe5,0x40,0x52,0x26,},{0x6f,0xcb,0x1a,0xc9,0x29,0x0a,0xb7,0x67,0xd5,0x9b,0x59,0x8c,0x9a,0x24,0xec,0xdb,0x6c,0x05,0xbb,0x02,0x3e,0xc3,0x60,0x14,0xa4,0x0d,0x90,0x8e,0xf0,0xdc,0x37,0x8a,0x45,0x28,0xb3,0x76,0x0d,0x88,0x9a,0x79,0x17,0x4e,0x21,0xca,0xe3,0x5d,0xf4,0x5d,0x42,0x7b,0xa6,0xea,0x81,0x2b,0xdd,0xca,0x16,0xe3,0x5a,0x69,0xb5,0xe7,0x9f,0x0a,},"\x68\x42\xe3\x19\x0a\x11\x0e\xee\x96\xc5\x07\xd4\xbc\xb4\xc5\x48\xc3\xa0\xed\x7b\x1a\x8e\xd7\x7d\xd9\x3b\x38\x61\x3b\x23\xc7\x3e\x83\x0b\x20\x5e\x62\x65\x19\x21\xad\x82\x96\xb0\x8d\x1e\x10\x08\xad\x78\xf2\x99\x6e\x3c\x7f\x38\x03\x2e\x46\x7c\xff\xec\xd7\x7b\x85\x25\xe2\x43\xce\xc0\x21\xf8\x52\x96\xaf\xd5\x45\xd7\xbe\x1a\x62\x56\x8b\xb0\xcf\xcd\xb9\x0d\x61\x4e\xd7\x98\xbf\xb7\xef\xc6\x55\x32\x68\x16\xa6\x10\x82\x25\x1d\xf0\x16\x13\xaa\xc8\x8e\xfc\xea\x1e\x0e\xa2\x96\x1b\x8f\x92\x1e\xbe\x15\x58\xde\xe8\x33\x74\xa0\x11\x3a\x78\xc5\x58\x57\xce\x20\x55\xbb\x2c\x48\xba\xdb\xd3\xd8\xf4\xcb\x19\x73\x4d\x00\xd0\x60\x4b\x61\x90\x73\x02\x0d\x72\xa9\x9a\x19\x23\xe6\x16\x0a\x09\x94\x65\x67\xfd\x4b\xda\x66\x44\x2e\xf5\xa7\x36\x07\x86\xd1\x78\xda\xe4\x49\x22\xf3\x50\xce\x2e\xdc\x6a\xf7\x3d\x1b\xd8\x0d\xc0\x3e\xc3\xca\x70\x05\xf4\x10\x9d\x10\xc6\xd4\xf7\xd8\xfa\x61\x73\x51\x10\xf8\xdb\xae\xdf\x91\xa0\xba\xd7\xd7\xfb\x5c\x04\xd7\x06\x37\x3c\x15\xc6\x45\x06\x3f\xf4\xb4\xfb\xd2\xd5\x59\xb0\xaf\xad\x43\x2d\x4c\x49\x6c\xd8\xab\xfe\xa2\x86\xfa\x67\x5d\xc0\x76\x72\x6e\xc5\x22\xb3\xa3\xc2\xf4\x7a\xec\xc5\x39\xf4\x8a\x79\x21\x69\xc4\xcc\x8c\xd4\x1c\xd2\xcb\x6b\x63\xdd\xbc\x19\x37\x3a\xc9\x69\x1c\x2b\xc2\xf7\x8f\x22\x60\x3d\x55\x13\x71\x5a\x16\xd4\x57\x4e\x7a\xcc\x4b\xea\x6d\xcd\x8c\xa7\xf1\x98\x65\xa4\x9d\x36\x64\xa2\x10\xdf\xad\x29\x07\x74\xb1\x0b\x71\x88\xf2\x55\xb3\xbe\x4d\xc8\xfa\x86\xf8\xda\x3f\x73\xa4\xe7\xc9\x29\x95\x1d\xf3\x0f\xe6\x6a\x17\xc8\xce\xe2\x3e\x4f\x2e\xd2\x06\x3f\x0b\x02\xab\x40\x37\x2c\xbe\x54\xb9\xa7\x08\xdf\x7c\x48\xa0\x65\x66\xd3\x9b\x19\x43\x4c\x6c\x76\x69\x87\xb3\xeb\xb0\x06\x75\xf4\x4c\x4b\x3c\x1e\x9f\x45\x04\xe7\xa9\x27\x05\x89\xc0\xd0\xf4\xcb\x73\x42\x35\xa5\x8e\xf0\x74\xcf\x9d\xec\xf3\x60\x1a\xee\xca\x9f\x1d\x8e\x35\x6c\xb2\xdb\x5f\xce\x79\xcb\xc3\x61\x43\xf3\x4b"}, -{{0x9d,0x4c,0xe9,0x75,0x54,0x78,0x76,0x63,0x6f,0xea,0x25,0x43,0x7c,0x28,0x80,0xc9,0xaa,0x8e,0xe6,0xb2,0x70,0xd1,0xb2,0xda,0x19,0x7c,0x8d,0x7f,0x95,0xe7,0xdc,0xcc,},{0xbd,0xe4,0x99,0x3c,0x03,0x04,0x77,0xc3,0x58,0x90,0xaa,0xe8,0x2b,0xb5,0x08,0x7e,0x91,0x4e,0x64,0xb9,0x4f,0xfc,0x64,0xe2,0xd7,0xa5,0xa7,0xc9,0x19,0xe2,0xd9,0x02,},{0xbe,0x17,0x44,0x4c,0xd4,0x65,0xa8,0x7a,0x97,0x1d,0xf8,0x4e,0xb1,0x02,0xf9,0xc7,0xa6,0x26,0xa7,0xc4,0xff,0x7a,0xea,0x51,0xd3,0x2c,0x81,0x35,0x3d,0x5d,0xbc,0x07,0x39,0x3c,0xa0,0x3d,0xb8,0x97,0xd1,0xff,0x09,0x94,0x5c,0x4d,0x91,0xd9,0x8c,0x9d,0x91,0xac,0xbd,0xc7,0xcc,0x7f,0x34,0x14,0x4d,0x4d,0x69,0xeb,0x04,0xd8,0x1f,0x0c,},"\xea\x0f\xa3\x2a\x4a\x28\x88\x11\x30\x1b\x9e\xe5\x33\xfa\x35\x1f\xdf\xbf\x6b\xc1\xd0\x55\x5a\x74\x02\x76\x7a\x3a\x91\x98\x55\x8f\x74\xbb\xa7\x03\x18\x57\x99\x5b\x9f\x32\x62\x26\xf1\xdd\x5d\xf1\x07\xb0\x63\x42\x20\x3e\xb8\xd4\x0c\x5f\x1d\xc9\x5b\x4f\x3f\x88\x97\x5a\xa2\x4a\xf8\x76\x9e\x26\x70\xc4\x66\x71\xbe\xbb\x7a\x0f\x1b\x75\x68\x72\x9a\xee\x47\x7e\x89\x88\xaf\x9c\x74\x9f\x32\x02\x70\x81\x71\xfd\x94\xb3\x37\xae\x67\xed\x21\xa6\xc4\x41\x74\x01\x4b\x0b\x0e\xb5\xba\x71\xc2\x77\x97\x8d\x48\x8c\x24\xc4\xa7\x84\x13\x09\x84\x6b\x4e\x30\xa4\xfb\xbc\xfc\x45\x07\x8d\x7e\x14\x01\x41\x14\xb1\xac\x64\xf7\xc3\x3c\x9a\xc2\x5e\xa5\x62\x6c\x2c\x81\x9f\xba\xa2\xa4\xde\x8a\x2b\xf5\xf1\x36\x5d\x6b\x70\x40\x7e\x80\x94\xf9\x91\x97\xce\x1f\x0c\x35\xe1\x1a\x98\xfb\xe3\x72\x41\x4e\xa2\x06\x4a\x3a\x12\xd1\xcd\x5c\x8d\xf8\xfc\x0e\x79\xf5\xb7\x70\xb5\x8f\x47\x7f\x91\x97\x6c\xa0\x13\x98\x95\x12\x0e\x24\x6b\xaa\xb5\xa0\x26\xf2\xd3\x9c\x68\x7d\xc0\x78\x83\x34\xb5\xc6\x26\xd5\x2c\xde\xbe\x05\xea\xf3\x08\x64\xb4\x13\xee\xbd\xc5\x58\x1e\xf0\x0d\x43\x92\x76\xe5\x2f\x47\x9c\x9c\x05\xb1\x16\x39\x58\x26\xb6\x04\x90\xb3\xce\x70\x0c\xc0\x02\x7f\x61\xe4\x6c\xa2\xf6\xfb\xc2\xc9\xde\x2e\x80\x08\x06\x55\x0a\xfb\x06\xd4\xa0\x8e\xac\x7a\x75\x8e\x24\x58\x2a\x4d\x6d\x42\x8b\x43\x3d\x36\x5f\xc3\x1d\x44\x44\x60\x7a\xfb\x64\xf1\x5e\x37\x07\x94\x00\x5a\x3a\x22\x44\xe6\x66\xd5\xd4\xc3\x8a\xd2\x00\x9c\x76\x9a\x51\xcd\xbf\x73\x8d\x23\x59\x42\xf4\x12\xd0\x7f\xee\xb7\x3b\x36\x57\xd0\xb0\xc9\x1c\xb5\x94\x0b\xad\x6a\x70\x6e\x14\xed\xcd\xc3\x42\x25\xb1\xc1\xf3\x8b\x1a\xbe\xcb\x2a\xdc\xaf\x81\x91\x55\xa9\x4f\xe1\x90\xfd\x55\x68\x22\xd5\x59\xd9\xc4\x70\x85\x4d\x3a\x43\xbf\xb8\x68\xda\xdd\x6e\x44\x3d\x98\xee\x87\xe4\xd8\x28\x4f\x5c\xf3\xa6\xda\xfa\xf2\x95\xb9\x02\x83\x6c\x64\x05\x11\xe6\x10\xae\x7d\x0c\xb1\xb1\xd3\xd6\x07\x9f\xe6"}, -{{0x02,0x73,0x86,0x82,0x32,0xf5,0xbe,0x48,0x59,0x2c,0xfa,0x05,0x13,0x4e,0x8d,0x55,0x54,0xed,0x1f,0x9a,0x57,0xbc,0x7e,0x39,0x82,0xa3,0x30,0xc5,0x7e,0x5a,0x7f,0x3a,},{0xf1,0x72,0x20,0x87,0x82,0xdb,0x66,0xd4,0x66,0xcb,0xe4,0xf4,0x41,0x7f,0x6f,0xc4,0x77,0xb7,0x34,0x9f,0x2a,0x98,0xdb,0x56,0xc0,0x3a,0x47,0x22,0x75,0x46,0xbc,0x5a,},{0x15,0xe8,0xd8,0xdc,0x7d,0x5d,0x25,0x35,0x9d,0x6a,0x10,0xd0,0x4e,0xe4,0x19,0x18,0xa9,0xc9,0xdf,0x4c,0x87,0xbe,0x26,0x9f,0xa8,0x32,0x43,0x4d,0x53,0x01,0xdb,0x02,0x24,0x81,0xbf,0xa3,0x95,0xa3,0xe3,0x46,0x6f,0x95,0x54,0xce,0xee,0x05,0x32,0xa8,0x18,0x3a,0x0d,0x05,0x50,0xe7,0xd1,0xab,0xe9,0x9f,0xc6,0x94,0xc6,0xff,0x93,0x01,},"\xf7\xa1\xd4\x61\x4c\xc6\x4a\x3b\xc4\x8f\x00\xc6\x27\x63\x04\xf3\x4d\x4d\xfd\x15\xe0\x61\x7b\x93\xcc\xef\x12\x6c\x5c\x63\x8c\x9d\x99\x53\xaa\xbb\x7d\xf4\x2d\xf4\xe0\xaa\xa7\xea\xc9\x6a\x4b\x38\xc7\xba\x75\x8d\x86\x0c\x90\xd0\x5e\x3d\x14\xe4\x79\xe5\x45\xf3\x19\xb0\xe5\xa8\x5a\xd8\xf0\x99\x1b\x43\xd6\xe4\x9c\x24\xfa\x06\x0e\x3e\x5d\xf9\x5c\x98\xd9\x45\x1a\xb8\x33\xe1\x2a\xa9\x7f\x40\x46\x11\xbb\xa3\x59\x49\x62\x65\xa6\xdb\x11\x91\x7d\x0d\xa5\xc6\xa7\x02\xd0\xb1\x02\xde\x36\xdd\x0c\x98\xdf\x5b\x54\x80\x6c\xe6\x26\xbb\x96\x37\x44\x75\xf6\x8a\x60\x60\xeb\x35\x0a\x7d\x2a\xae\x32\x04\xb3\xdf\xdf\x9f\x1e\x31\xbe\x81\xf7\x17\x0f\x8a\x1b\x93\x85\x41\x3f\xf8\xf6\x88\x1e\x10\xc1\xe8\xda\x4c\x88\xaf\xb5\x06\x39\xab\x44\x88\x7a\xca\x2a\xbe\xec\xed\xf1\x10\xd2\x95\x8c\x13\xfd\x33\x90\xd1\xb9\x6a\x76\x2d\x16\xce\x19\x69\x20\xce\x85\xf6\xc4\x15\xbe\xd5\x45\xb1\x44\x53\x02\xa6\xf0\x01\xeb\x8d\x00\xe9\x7c\x75\x18\x87\x86\x8d\x48\x1a\x0b\x1e\x4d\xfa\x04\xb6\xf7\x61\x08\x6e\xe8\xe6\x97\xb0\x19\xe0\x17\x10\x4b\xaf\xb9\x8f\xca\x24\x2e\x33\x4c\x6f\x18\xf1\xdb\x5b\x6f\x29\x5f\x05\xc5\x59\x36\x1c\x68\x31\xda\xbc\x42\xc2\x11\x07\x03\xf9\xd1\xf6\x4e\x12\xdd\xf2\x6a\x86\x79\x85\x4e\x9f\x8e\xf8\x47\x9e\x1f\x12\xc3\x54\x47\xaa\xc0\x2e\xa7\xf2\x42\xe5\x86\x32\xcf\x2f\xd0\x63\xfe\x66\x50\x70\x44\x5b\x80\xf3\xdc\x6a\x33\x03\xbb\xa9\x6e\x05\xfa\x88\xee\xc2\x01\xc5\xc2\xd0\x0c\xa8\x1b\x8d\xa6\x96\x9d\x0a\x4d\xd0\x48\x3b\x34\x77\xd3\x25\xa7\x1f\xac\xd6\xfa\x22\x09\xb4\x8c\xb4\xf6\x52\x5d\xa7\x3c\x9c\x05\xb2\xd9\x78\x9b\x01\x44\x8e\x15\x27\xe5\x6a\x09\xa9\xbc\x61\x36\xd9\x83\x72\x43\xc2\x07\x7b\x92\x5b\xbb\x93\x3f\x8f\xb1\xda\xac\x96\x33\x98\xc5\x80\x2a\xed\xa3\xbb\xca\x8a\xe3\xb8\xf4\xa9\xa8\x71\xf7\xea\x8e\x2c\x0c\xe8\x98\xc5\x66\x21\x7b\x5c\x06\xff\x55\xff\x9f\x4f\xe7\x83\x98\xae\x79\x73\x64\x1e\xaf\xb5\x21"}, -{{0x33,0x6a,0x83,0xb5,0x5a,0xbf,0x4c,0x02,0xe2,0x5e,0x54,0x03,0x29,0xb5,0x27,0x58,0x43,0xc2,0xec,0xb8,0xdf,0x69,0x39,0x5b,0x5a,0x5e,0x24,0x1b,0xd0,0xd8,0xc1,0x0d,},{0xdd,0x60,0x56,0x98,0x44,0x57,0x0c,0x9f,0x0a,0x82,0x64,0x3f,0x44,0x64,0x78,0xb5,0xac,0x6f,0xc5,0x42,0x21,0x42,0x31,0xa7,0xca,0x65,0x6a,0x92,0xb5,0xfd,0xaa,0x54,},{0xd2,0x63,0xf5,0x6d,0x59,0xcb,0x9b,0x28,0x96,0xa9,0x47,0x26,0x7c,0x2e,0xd7,0x8a,0x94,0x5b,0xac,0x5a,0xbd,0xbf,0x3c,0x14,0xdc,0x3a,0xd0,0x92,0xb2,0x30,0x8c,0xb9,0x31,0x5c,0x46,0x49,0x42,0xa0,0xa2,0x0b,0x20,0x24,0x51,0x1d,0x76,0x6e,0x85,0xc9,0x36,0x49,0x9a,0x14,0x9c,0xd0,0xbb,0xb2,0x09,0x15,0x0a,0x16,0x43,0x26,0x52,0x00,},"\x9a\xfe\xe8\xab\x48\x20\x10\xe2\x92\x64\xb4\x06\xd9\xb4\x94\x53\xd1\xce\x6d\x55\x09\x39\x07\x21\x82\x86\x3e\x46\x65\x28\x4a\xb0\x5d\x86\x25\x8e\x06\x23\xb1\x87\x54\xc4\x78\x52\x38\xf6\x97\xf0\x75\xad\xfb\x9e\x1d\x31\xa4\x2e\x85\x93\x4e\xc0\x71\xdd\xdd\xec\xc2\xe6\xc2\xf6\x13\x34\xa7\x95\x26\x78\x8b\x49\x52\x19\x07\x16\x90\x6d\xde\x17\xfb\xa5\x56\xee\xa4\xc8\xb5\x97\x27\x51\x4f\x6f\x56\x15\xa1\x9c\xa3\x6d\xa3\x58\xfa\xe6\xa6\xc5\x4f\x7f\x4b\x7a\x92\x9e\x31\xba\x7c\xc7\x1b\xde\x78\x82\xfa\x9f\xfd\x87\x30\x01\x36\x40\x9c\xaf\x3c\xa6\x4e\xef\xea\x61\x6a\xed\x58\xda\x5d\xfb\xf2\x8b\x66\x8e\xc1\xcc\xcf\xfc\xef\x6e\x2e\x14\xf8\x10\x9e\x9c\xbf\x76\xcf\xa4\x14\xf9\x1a\xc0\x0f\x48\xe9\x3e\xad\xa3\x85\xdd\x3d\x5c\x16\xe1\xa3\x9e\xa3\xdd\x55\xc7\x61\xfc\xa3\x61\xb4\x28\xf5\x16\xc0\x5e\x69\x4f\xe5\xc3\xc3\x45\xcd\x94\x45\x71\x87\xa8\xe6\x04\xb2\x00\xa1\xa0\xf9\x37\xae\x89\xf4\xd6\xb5\x42\x1d\xff\xcf\x7c\xa1\x5f\x2e\x2c\x25\x37\x8a\x41\x13\x23\x3f\x76\x13\xf4\x57\x0a\xa4\xb9\x09\xa9\x13\x5e\xae\x4c\x7b\x9e\xad\x45\x80\x07\xae\x17\x12\x6a\x11\xd1\x45\x25\x8a\xf9\x56\x3d\xb2\xf7\xe8\x92\x54\x31\x87\x8b\x0e\xec\xa8\xaf\xfc\x01\xac\x59\x13\xbf\x5b\xac\x4f\xa3\xa8\x57\xc5\x4c\xc8\x90\x6d\x6a\xf7\x7d\xe6\xb9\x32\x6b\x65\x06\x15\x10\x99\xe8\x7e\x99\xb1\xe8\x19\xc6\xfb\xe0\x82\x68\x8f\x34\xb8\x03\xd5\x88\xe4\x16\xd8\x53\x16\x97\x65\xd6\x2f\x7e\x0b\xdf\x72\xc5\xcd\x66\x66\x9a\x03\x35\x56\x23\x36\x73\x5e\x7e\xfb\x73\x4a\x2f\xad\xa3\x27\xf8\x58\xbe\xc6\x02\xd0\xda\x08\xeb\xa4\x47\x9e\x7f\x6d\xc4\xde\xf6\xe4\xeb\xdb\xb7\x30\xee\x91\xa3\x34\x45\xca\xdc\x9d\xf5\x2c\x82\x5a\xd3\x61\x49\xce\xfb\xc5\x1a\xb1\x02\x03\x35\x30\x81\x4b\xaf\xa7\xe8\x79\x61\xb0\x63\x67\xff\x89\x6f\x08\xae\x33\x4a\x9b\x1a\xad\x70\x3d\xa6\x86\x70\x6c\x11\xa0\x49\x43\xea\x75\xe1\x29\x92\xdc\xf6\x10\x6e\x37\x20\x77\xcd\x03\x11\x02\x9f"}, -{{0x88,0x40,0x91,0x72,0x61,0x8b,0x49,0x03,0x93,0xdb,0x27,0xd9,0x60,0x17,0x1c,0xbc,0x18,0x7e,0xaf,0x4d,0xd8,0xb3,0x20,0xb3,0xd2,0xf8,0x24,0x98,0x00,0x43,0x71,0x8f,},{0xce,0x2e,0x7c,0x58,0x39,0xef,0x56,0x32,0xa1,0x23,0xdc,0x37,0x3d,0xc1,0x4b,0x1f,0x05,0x05,0x76,0x6e,0x96,0x75,0x40,0x76,0x04,0xca,0x7c,0xf5,0x4e,0x8d,0x44,0xb2,},{0x93,0xb6,0xe2,0x9d,0x63,0x94,0x5d,0x5c,0x42,0x73,0x87,0xd0,0x06,0xc7,0xf0,0xb0,0x19,0x56,0xa9,0x5f,0xc0,0x43,0x6e,0xd4,0x2b,0x46,0xd0,0xf1,0x7b,0x5b,0xb1,0x93,0xea,0x8c,0x0e,0xbb,0xf3,0xd6,0xd1,0x3b,0xb5,0x39,0xe3,0x5c,0x91,0xf3,0xf0,0xf9,0xfa,0x34,0x14,0xa0,0x22,0x3c,0x90,0x60,0xba,0xc8,0x36,0x53,0xc6,0xfc,0xd9,0x06,},"\xfb\x3e\x82\xf1\x1b\xc2\x86\x26\x7e\x12\x38\x17\xad\x88\x64\xe0\x77\xd9\xf7\xa8\xe7\xa1\x63\xac\x7e\xea\xf9\x3d\x55\xdd\x11\x1d\xe8\x08\x3b\x66\xb5\x3c\xe7\xbc\x77\x1f\xc5\x07\x1a\x2d\x7a\xc2\xf8\x5d\x6f\xc6\xad\xcf\xce\xc4\x46\xe1\x6a\xa1\x04\x6d\xf3\x72\x09\xad\x7a\x29\xcf\x96\x65\xb4\x39\xa5\x4d\x6f\x8d\x94\x2f\x89\xbd\xaa\x56\xf2\xf1\x12\x60\xcc\x95\x99\x30\x38\xb0\xe8\xfb\xdb\x32\x14\xf1\x42\xe6\xc9\x0b\x61\xa1\xd2\xb1\x42\x07\x62\x06\xaf\x30\xac\x35\x78\x4a\x6d\xc1\x5a\x1e\x79\x25\x1a\x8c\x77\x31\xa1\xc5\x39\x78\x03\x8f\x8d\x76\xd7\x0c\x6c\x1c\xdf\x52\x9f\xbd\xb8\x4d\x15\x07\xdc\xff\xdd\x42\x87\x3d\xfa\x6a\x8f\xe6\xbd\x6f\x7f\xd2\x9c\x80\xe4\xb2\xf9\x33\xd2\xb6\xc9\xe6\x2c\x94\x57\xe6\x65\x47\x26\x55\x05\x9b\x63\xb6\x18\xe2\xa9\xa8\xe5\xb9\xe4\x1c\x36\x46\x17\x3a\x89\x2b\x8e\x6d\x4b\xca\xd6\xa6\x2a\x6f\xcc\xd3\x45\x58\x90\xb5\x8e\xc2\x68\x1a\x95\xcc\x97\x76\xa9\xfc\xe8\x3c\x54\xa9\xef\x31\x2a\x33\x19\x59\xc7\xef\x3f\x79\xee\x57\x6e\xb7\xb7\x94\x69\xc9\x23\x4b\x1e\xae\xf6\x09\x88\x47\x08\xfe\x4b\xb0\xef\xac\x66\x2d\xa8\x71\xba\x61\xdd\xab\xb3\xfc\xbd\xeb\x8f\x63\x56\x57\xdd\x9a\x5d\x73\x11\xe6\x39\xa8\x24\x85\x8b\x9a\x98\x68\xd3\xf9\x38\x4d\xa6\x12\xc7\xf2\xe7\x71\xa4\x6b\xd2\x62\x4c\x99\xea\x2b\x6c\xcb\xca\x99\x6c\x1d\x9c\x37\x55\x54\xf2\xa5\x51\x61\x9c\xe6\xd5\xe6\xe4\xd6\xb8\x44\xa4\xdb\xea\x83\xba\x73\x23\x31\xfc\xf4\x65\x72\xc1\xfb\x0e\x25\x7c\xe1\x04\x1b\x26\x5d\xf0\x2e\x69\x0a\x92\x81\x4b\xbf\x3b\x5e\xca\xc6\x9e\xe9\x98\x76\x6a\x02\xb0\xd2\xf9\x08\xb3\xc1\x5f\x95\x26\x99\x61\x6f\x2c\x07\xd5\x89\x19\x89\x89\xe6\x05\x6c\x16\x31\x9a\xab\x6c\xf8\x77\x19\x02\xc0\x78\x04\x6a\x88\xb2\x57\x0c\x13\xbc\x5e\xde\xba\x2e\xd1\xe3\xba\x13\x1d\xaf\x94\xe6\x89\x18\x62\xbb\x3d\xe7\xd1\x06\x3f\xe4\x05\x30\x7a\x5c\xd9\x75\x69\x3e\x9d\x58\xe1\x7c\x69\x0e\xee\xf4\xa2\x60\x3c\xaf\xc6\x8c\x2b"}, -{{0xe5,0x71,0x18,0x9b,0x5c,0xd9,0xe7,0x88,0x30,0x2d,0xe3,0x91,0x9d,0x85,0x0c,0x22,0x7d,0xcb,0xb6,0x15,0x02,0x2e,0x56,0x8b,0xda,0xeb,0x37,0xac,0x5b,0x29,0x39,0xc5,},{0xed,0xda,0x89,0x0f,0x42,0xdd,0x5f,0xbc,0x73,0x16,0xa5,0xfa,0xdf,0xbe,0xc3,0x85,0x56,0xf2,0x3f,0x51,0xb8,0xef,0xd2,0x62,0x54,0x37,0xf6,0xb5,0x06,0x9f,0x1e,0xe5,},{0x7f,0x79,0x7a,0x31,0x71,0x5d,0x7c,0x35,0x6f,0x8f,0x1f,0x78,0x37,0x00,0xaa,0x99,0x74,0xbb,0x93,0x6d,0x66,0x16,0x61,0xad,0x96,0x8c,0x7c,0xde,0x1a,0xc9,0xe7,0x67,0xbe,0x56,0xa2,0xdd,0x49,0xb9,0x23,0x0e,0x90,0x11,0x0c,0x67,0xc0,0xed,0x18,0x7c,0xb7,0xe7,0x5c,0x30,0x53,0xec,0xe8,0x44,0x98,0x4d,0x29,0x6f,0x0d,0x85,0xcb,0x07,},"\xb6\x2c\x86\x7a\xd6\x22\x74\x35\xbf\xa6\xda\xb8\x30\x68\x4e\x38\xd1\x96\xe1\xf8\x61\xaa\xde\x0f\xd6\xa7\x69\x9b\x6d\x60\x90\x1f\xef\xb2\xd7\x99\xc3\x5c\x6f\x3d\x8b\xb9\x4d\xee\xe8\x34\x40\x39\x81\x86\x6b\xab\x84\x94\x6a\xe9\x47\x6c\x75\xe9\xf1\xd3\x60\x2b\x42\xcb\x2d\xb4\x37\xbf\xf3\x3a\x77\x58\x22\xf0\xd6\xa2\x57\xd4\xb7\x54\x00\xeb\xa5\xb8\xab\xb3\x14\xb7\x1f\xc6\xb4\x6f\x8a\x34\xe8\x61\xa9\xa6\x2a\xbf\x33\xde\x84\x82\xf6\x3f\x9d\x71\x69\xe7\x73\xa2\xdc\xeb\xee\x03\x70\x5d\xac\x11\x7f\xd1\x49\x9b\x68\xe7\x41\x4f\x51\xff\x94\x37\xf2\x53\xa1\xd9\x90\x1e\xc3\xb0\xbb\xa8\x69\x65\xa1\x93\x83\x65\x54\x87\xb5\x80\x10\xf8\x04\x90\x9d\xe1\xff\xb2\x21\x2c\x02\x52\xdd\xd9\xbf\x2a\x56\xac\x46\xbd\x59\xc0\xc3\x4d\xd5\x9e\x46\x59\x8b\x6b\xab\xd4\xe5\xf3\xff\xfd\xe5\x5e\x48\xda\xb0\x39\x8c\x22\xaf\x9e\x26\xba\xdd\xf7\x72\x75\xe5\xf0\x17\xb3\x5a\x9b\x8f\x84\x35\xf9\x63\x19\x36\xb3\x91\xcb\x95\xd7\xad\xf3\x5d\x1d\x85\x45\xa0\xfd\x06\x64\x12\xd5\x08\x96\x7b\xbe\x9a\x20\x24\x5a\x26\x9e\x3b\xe2\x77\x71\x17\xe7\x5f\xba\xc1\x70\xdb\xa3\x52\xbe\x69\xb2\x54\xd3\x53\xb3\xb2\xcb\x3b\x7e\x21\xb7\x21\xaa\x9f\xe0\x44\xf8\x91\x6b\x4b\x2a\x6f\x8c\x28\xf8\xab\xe6\x6a\xc9\x2b\x91\x32\x3a\xc7\x3a\xfd\x93\xdf\xbe\xea\xee\xf2\x6d\x19\xbd\x9f\x67\xe9\x9d\x48\xcd\x2a\xd2\xd3\xe5\x5e\x45\xd2\x4d\x54\xb5\x0f\x44\xa3\x9b\x90\xe2\x42\xeb\xe9\xb4\x2b\xeb\xdb\x23\x0c\x47\x0b\xdf\xde\x1b\xc7\x72\x1c\x31\x20\x00\x84\x77\x39\x3d\xcc\x2e\x15\xfd\x22\xb2\x51\xfe\xb0\xe1\x8b\x02\x88\x3c\x07\x8a\xee\x4f\xb7\x60\x65\x5a\x67\x1d\xc7\xb8\xaa\xdb\x9a\x56\x24\x20\xa3\xc2\xef\xa2\xd3\x42\xe1\xe0\x09\x9d\x95\x1b\x42\x24\x29\x84\xf5\x94\xe6\x91\x4f\xe2\x82\xb1\xee\x12\x87\x35\x98\x4e\xf9\x3a\x66\x9e\x6e\xcb\xa2\x6c\x9f\xcb\x9f\x09\xf0\x92\x56\x64\x56\x17\xf1\x39\x2d\x35\x90\x89\x17\xcb\x8d\x29\xe0\x89\x7c\x75\x03\xcd\xdd\x5d\xe1\x95\x96\x86"}, -{{0x37,0x17,0x44,0xab,0x63,0xc1,0x15,0x61,0x39,0x29,0xa3,0x43,0x70,0x9b,0xb0,0x19,0xb7,0x35,0x7d,0xff,0x72,0xd2,0xa1,0x49,0xf1,0xd0,0xf7,0x1d,0x3a,0x20,0x1e,0xfe,},{0xe5,0x8a,0xbf,0xad,0x4a,0x13,0x85,0x9f,0x0a,0xcb,0x05,0xd0,0xe4,0x7d,0x59,0x63,0x8f,0x7b,0x1b,0x49,0x36,0x10,0x0b,0x98,0x8d,0x61,0xe6,0xe7,0x0e,0x22,0x66,0x7d,},{0x5e,0xae,0x4a,0xc7,0x2a,0xf0,0x17,0x4a,0xb2,0x56,0x52,0x7b,0x7c,0xd3,0x37,0xa0,0xe5,0x48,0x2e,0x61,0x5a,0xf0,0x68,0xdb,0x21,0xda,0xe3,0x5a,0x64,0x64,0x07,0x42,0x60,0x4d,0xf7,0x3f,0xd4,0xca,0x02,0xed,0x95,0x15,0xa5,0x60,0x8d,0x73,0x19,0x52,0x30,0xfa,0xdc,0xa7,0xb4,0x26,0xf0,0x2a,0x2f,0xbf,0xd0,0x20,0x61,0xaf,0x36,0x00,},"\xc2\x19\xde\x1e\x8d\x7a\xd8\xdf\x08\xc4\x93\x77\x39\x6f\xe7\xc1\xf2\xd5\x7b\xd2\x17\x06\x33\xa0\x0d\x70\x8f\xaa\xde\xe1\x80\xce\xba\x92\x84\x9a\x77\x78\x50\x6c\xbb\x36\x68\x75\xbf\x91\x24\x70\x18\x94\xce\xcd\xb3\x38\x51\x47\xd0\x67\x18\x43\x92\x2a\x64\x9a\xff\x7c\x43\x5e\xb5\xa9\xc7\x49\x27\x50\x30\x72\xd0\x06\x79\x78\x71\x6d\xc8\x0b\xe1\x54\x5a\x2d\xbf\x5a\x1c\x38\x53\x6e\x12\xbd\x77\x20\xc1\x96\x5d\x38\x03\xa4\xe8\xaa\x55\x76\x51\x92\xa1\x3b\x70\x5c\xa1\x05\x9d\xed\x0e\x80\x63\x62\xfc\x5b\xbe\x6c\x76\xa1\xc9\x67\x4b\xb8\x53\x79\x0f\x7e\x90\xaf\x00\x75\x3e\x00\x43\x6d\xa4\x8c\xd0\x82\xea\xd6\x4f\xdd\xb6\x89\x89\x01\x62\x08\x2f\x84\x82\x92\x4f\x33\xac\xd6\x04\x64\x0f\x69\x92\x73\x52\xb4\x3f\x64\x40\x2d\x27\xa8\x83\xfa\x6b\x72\xaa\x70\xd2\x41\xdf\xfa\xa1\x70\x1a\x25\xcf\x10\x79\x35\x82\x60\x79\x38\x75\xf7\x6a\x29\x78\xe9\xf9\xf9\xd6\x86\x34\xeb\x3f\x5f\x01\xbd\xe1\xce\x49\xe5\x92\x12\x52\xf9\x49\xf0\x82\x79\x5e\x4e\xaf\xed\x7b\xe5\xb4\x9a\x9f\x95\xed\xbb\x4a\x13\x53\x2e\x3f\x3b\x3b\xe6\x2e\x26\x52\x23\x12\x53\xa2\x0c\x1d\x54\x77\xe8\xf4\xbc\x57\xed\x76\xfa\x19\xea\xf0\x3a\x11\xbb\xa4\x29\xb6\x49\x6c\xe7\x62\x46\x17\x0e\x04\x3b\xc1\x4f\x2d\x2f\x70\x3d\x96\x8f\x1d\xeb\x09\x38\x87\x15\xc3\x7c\xb4\x75\x2d\xa8\xd4\x64\xe3\x48\xe0\x31\x3c\x89\x93\xe2\x41\x33\xa7\xc5\x45\x28\x4e\x3c\x9c\x90\x7d\x01\xb2\x60\xc4\x88\x3f\x9c\xb3\xe3\xdc\x5b\x6f\x7f\xb6\xd7\x55\x36\x36\x5f\x21\x32\xea\xed\xda\xb5\x70\xe7\x27\x3a\xfa\xc0\xbf\xf5\xc9\xfc\x0b\x82\x0f\x20\x78\xe0\x33\x60\x52\xe1\xfe\x7b\xde\xc8\x66\x74\xd0\x99\x8e\xc7\x8d\xa1\xc3\xf3\x47\x51\xf8\x86\x72\x76\x95\xf3\x5e\xca\x13\x04\xb1\x47\x34\x76\x6a\xb0\x5c\x11\x86\x30\x6d\xed\x9d\xb3\xee\xf6\x5d\x3c\x04\x56\xcd\xae\x81\x81\xaf\xee\x04\xb2\x96\xc6\x72\x2a\x88\xc7\xef\x30\x88\xd2\x6f\x7f\xe7\x4b\xc8\x9c\xf5\x28\x5c\x68\x8f\x02\x7b\x7e\x68\x60\x04\x86\xaf"}, -{{0x49,0x8b,0x6e,0xe6,0x49,0x2d,0x53,0x23,0x1b,0x35,0x32,0xd1,0x93,0x57,0x8b,0xa7,0x5d,0x6a,0x89,0x4e,0x2e,0x53,0x00,0x34,0xe2,0x1a,0xb8,0xad,0x8d,0x2c,0x0d,0x1f,},{0xd1,0x24,0x66,0x5b,0x28,0xfa,0xcd,0x2d,0x17,0x94,0x6a,0x04,0xdf,0xe3,0xd1,0x29,0xa4,0x56,0x1a,0x2b,0x24,0xeb,0x32,0x6d,0x84,0xb6,0x2b,0x42,0x2e,0x44,0xdb,0xcf,},{0x11,0x2f,0x5c,0x6d,0x3b,0xcb,0x3d,0xd9,0x93,0x46,0xd3,0x2a,0xd6,0x9c,0xbf,0xac,0x3e,0x65,0x3b,0xef,0x29,0xc6,0x8a,0x33,0xf4,0x32,0x31,0xf6,0x6c,0xea,0x1d,0x0a,0x19,0x54,0x27,0xd6,0xe1,0x0c,0x0e,0x77,0xc5,0xd5,0x5f,0xe2,0x79,0x42,0x87,0xee,0x32,0xe5,0xe2,0x2b,0xaf,0xbb,0xd8,0x05,0x2a,0xd3,0x60,0x6b,0x90,0xf9,0x45,0x05,},"\x04\x98\xa5\x9b\x87\xcd\xae\x28\x69\x55\x47\xe1\x08\x63\xbc\xe8\x04\xd9\x7d\xe0\xac\x80\x08\xf3\xd5\xfb\x65\x2c\x17\x57\x41\x9f\xdc\x9e\x0f\x97\x36\xf4\xc5\x9a\x34\xf2\x1c\xfc\x74\x59\x9f\xa7\x88\xfc\xc1\x0c\x67\x30\xc7\xdf\x8c\x3d\x2c\x1b\x6a\x78\x6d\x12\x30\xb6\x55\x85\x71\x9d\x1c\xb5\xc4\x90\x35\x9b\x94\x43\x5d\x6d\xd6\x71\xf5\x4d\x6e\x9a\x19\xb9\xb5\xaa\xad\x7e\x0f\x23\x3f\x87\x97\xdf\x99\x78\x28\xd8\x8c\xd9\x2e\xf0\x89\xef\x7d\xbf\x1e\x95\x27\x78\x94\xa2\xf7\xc2\xfd\x0c\x8e\x4d\xfd\xfa\x6d\x3d\x14\x58\x9f\xf0\x19\x16\xdb\xf9\xdd\xd8\x11\xc2\xf5\xe0\x1e\x94\x29\x89\x90\xa1\x45\xa6\xcf\xc2\x68\x95\x61\x4c\x7c\x96\x3f\xef\x30\x8a\x4e\x38\x56\xc3\x2d\xd3\xe3\x59\xbc\x56\xd2\xcc\xa4\x96\xad\x19\x9f\xf1\xa5\x68\xd6\x43\x0a\xc5\xcd\x20\x8e\x0e\x2d\x07\x80\x3c\xa5\x23\xe0\xd8\x13\xad\x37\x33\xab\x50\xbd\xca\xdc\xb9\x88\xae\xe7\x58\xea\x50\x43\x9b\xf3\x8e\xe6\x49\x99\x76\x04\xf1\x51\xc6\x02\xc8\x29\x00\xa8\x20\x5d\x8f\x6f\x67\x0c\x86\x84\xbf\x5a\xbb\x5f\x75\xff\x29\xa3\x7e\xb9\xbf\x81\x05\x19\x9f\xbb\xfb\x47\x07\xe1\x62\xe6\x4c\x71\x52\x70\xf8\x53\xe6\x48\xb0\xaa\x26\xfe\xa0\xf6\xdb\x56\x28\x96\xbf\x42\x4a\x9f\xfc\xb2\x92\xfa\xe8\x5b\x76\xce\xfb\x8b\xd5\xa4\xb3\xce\x1f\xb3\x9b\xd2\xa5\x0d\x0c\x9e\x6d\x93\x3e\x16\x7f\xf6\x29\xb8\xa4\x94\xf2\xa9\xb7\x74\xeb\x30\x3c\x78\x1e\xa0\x2a\xff\x1a\x8a\xfa\xdc\x24\x65\xcc\x61\x69\x68\x01\x5e\xd6\xa5\xa3\x3c\x31\x20\xb9\x45\xed\x53\x51\x98\x1e\x32\xfb\x9f\xb9\x6b\x22\x12\xdc\xf8\xfe\x9a\xc5\x6e\x3c\xf4\x1d\xc5\x24\xf8\x00\x63\x10\x20\xb0\x25\x91\x91\x78\xce\x07\x4e\xef\x07\x8d\x68\x42\x01\x2a\x27\x6e\xfa\x62\x8d\xb5\x40\x58\xd1\xeb\x5b\x5b\x70\x5f\x1e\x18\x18\xd2\xdf\x51\x64\xba\xab\xb0\xc6\x19\x56\xec\xdb\x8c\x70\x6e\x56\x2f\xc4\xfd\x64\x05\x28\x70\x53\x0a\xe4\x25\xb2\x21\xf8\x9d\xd6\xf9\x0d\xab\x88\x2e\x76\x3e\x7a\x7f\xfa\x14\x1b\xba\xa8\xbf\x7a\x3f\x21\xb0"}, -{{0xce,0xfc,0xfc,0xd1,0xcf,0xf4,0xd8,0x91,0x07,0x49,0x27,0x91,0x31,0x83,0x0b,0x1d,0xa1,0x9d,0xfc,0x52,0x45,0xf7,0x8c,0xa6,0x8b,0x8c,0x3c,0x1b,0x62,0x2b,0x45,0x51,},{0x1d,0x39,0x4a,0xbd,0x1b,0x4e,0xd1,0xae,0xdf,0x96,0x6a,0x60,0xef,0xd3,0xff,0x88,0x21,0x40,0xa7,0xe5,0x6b,0x42,0x83,0x74,0xec,0xb4,0x43,0x28,0x9a,0x9c,0x7f,0x00,},{0x7d,0x83,0xff,0x66,0xec,0x79,0x30,0x7b,0x1c,0x0c,0x09,0x3f,0xda,0x39,0x68,0xa9,0x6c,0xf6,0x04,0x4f,0x5c,0x80,0x28,0x88,0x58,0x40,0x18,0x84,0x5e,0x7c,0xaf,0x2a,0x13,0x5a,0xc6,0xf1,0x67,0x7e,0x84,0xd2,0x2e,0x45,0x8e,0x22,0x7e,0x4f,0x93,0x02,0x09,0x91,0x9b,0xc1,0x1b,0x12,0xf7,0xaa,0xf2,0xb8,0xc9,0x43,0x02,0xd6,0x42,0x00,},"\x5e\xc9\x4e\xd0\x6f\xc1\x25\x7a\xe9\xc1\x83\xce\x56\x27\x12\x07\xac\xa3\x7a\x23\xfd\xb4\xb0\xe7\x4a\xc9\x30\x7a\x1b\xb1\x12\xe0\x5e\xd5\xa5\xd0\x47\xc9\x31\x09\xe2\xe5\x94\x77\xb0\x33\x78\x34\x64\x22\xde\x36\x71\x4c\x29\x61\xbb\x97\x36\xa5\x13\xca\x36\x71\xc6\x03\xa6\x8c\x2b\xe7\x31\x7b\x1b\x52\xa0\x76\xda\xe2\xaf\xf7\xbc\x88\xcd\x5e\xea\x0a\xa2\x68\xfa\xaa\xda\xe5\x39\xc9\x38\xbb\x4f\xd4\xb6\x06\x9b\x19\x45\xeb\x6a\xf0\xc9\xe6\xc8\xaa\x5e\xe4\xa4\xaf\x37\xe9\x0c\x67\xe2\x48\xe8\xd2\x7b\xd7\xf9\x58\x9c\x4d\x30\xe9\x05\x65\x1b\xaf\x45\x36\x4f\xa0\x49\x95\x7e\xa5\xd9\xb7\x14\x6c\xa6\x82\x04\xe5\xe9\x73\xd0\xf1\xc9\x1a\x1c\x4b\xde\xd6\x61\x15\x02\x8a\x71\x11\x4f\x0f\x4f\x85\x1b\xd1\x15\xfa\xeb\x95\x4e\x3f\x71\xa0\x14\x70\xb2\x48\x1a\x00\x98\xd9\x9f\x9d\x74\x89\x8c\x8b\xa0\x28\x7c\xc7\x83\x41\x55\x21\x41\x73\xd1\xfc\xba\xfc\xfe\x9b\x08\x25\x03\x84\x43\x94\x76\x05\x58\x83\x83\x38\x16\xc9\x52\x4c\xfd\x57\x44\xaa\xa2\x59\xdb\x7e\xbd\x3a\x6a\xa2\x0b\x5a\x65\x46\xda\xde\xfd\x14\x06\x68\xeb\x0e\xcc\xb5\xf6\x68\xdb\x9f\xc6\x29\x83\xdf\x98\x08\x50\xc9\xd1\x98\x82\xa1\x75\x50\xd5\xdc\xa3\x54\x2c\xd3\x60\x03\xa0\xd0\x3c\xff\xb0\x45\x75\xa3\xe8\xe1\xd0\x70\x15\xc7\xb3\x0e\xca\x91\x15\xcd\x2b\x72\xe4\x6d\xfd\xdf\x6a\x4d\xda\x1f\xaa\x2d\xbd\xc8\x90\x00\xd4\x33\xf6\xec\x9a\xdc\x46\x14\x6d\x93\x9f\x32\x12\x1b\x99\xb2\x89\x83\xd9\x8b\x9d\xde\x8c\x3f\x6e\x57\x79\xf2\xb0\x70\x0c\xb0\x23\xdb\x13\xde\x65\x6e\x0a\xed\x1d\xa2\xd5\xc6\xba\x26\x52\x34\x36\x48\xad\x42\x0f\x6a\xb9\xe5\x5a\x97\x48\x2a\x1a\x22\xb3\xbc\x2e\xe5\x98\x62\x9a\xba\xd9\x54\x7e\xdb\x5f\xf7\x90\x99\x05\x64\xbd\x87\x1f\x81\xb2\x4b\x12\xf2\xbf\x8d\xbd\xfe\x7a\x88\x37\x5f\xad\x9c\xcb\xd9\xfc\x0b\xa1\xd3\xbb\xa5\xe3\xc4\x81\x3c\x18\xa0\x34\x8a\xad\x83\xfb\x1b\x82\x68\x90\x54\xd9\x9b\x46\x00\xdd\x17\x60\xd0\xdc\xce\x44\x75\x74\x67\xbe\xc1\x94\x64\x06\xd5\x30"}, -{{0xd1,0x07,0xcf,0x26,0xf5,0x27,0xdb,0x71,0xa2,0x06,0xe4,0x1d,0x17,0x95,0x53,0x21,0x01,0x32,0x25,0xbb,0x20,0xf9,0x3e,0x12,0xdf,0x3d,0xc7,0x39,0x9e,0x72,0x0c,0xa3,},{0x18,0x6b,0xf4,0x53,0xc9,0x5d,0xc0,0xa2,0xfd,0x58,0x9a,0x78,0xe2,0xc8,0x00,0x40,0xb3,0xf6,0xdd,0xf9,0xa6,0xf8,0x68,0x1d,0x14,0x60,0x36,0xcf,0x21,0x46,0xe8,0xfc,},{0x80,0x71,0xd9,0x7f,0x32,0x4f,0x10,0x35,0x8f,0x13,0xac,0x8c,0x61,0xd4,0x24,0xb4,0xf3,0x00,0xdd,0x04,0x19,0x57,0x1c,0x39,0xe4,0x0d,0x99,0xae,0xa5,0xf0,0x31,0x40,0xe6,0x2a,0xb4,0xc9,0x71,0x27,0xab,0x33,0xe9,0x82,0x69,0x96,0x6a,0xe1,0xd4,0x55,0x7e,0x45,0x9b,0xf7,0xf5,0x97,0xb3,0x13,0xf3,0x51,0xa2,0x01,0x22,0xf0,0x66,0x0e,},"\x78\xeb\x9e\x13\x78\x99\x28\xa7\x4f\x36\x01\x41\x72\x8e\xde\x98\x38\x96\x85\xc8\x36\xb9\x1f\xaf\xbf\x1a\x7e\x8c\x19\xcf\xbe\x21\xbd\x3c\x3d\x6c\x6e\xd8\x3c\x40\x9e\xf6\x93\xf1\xd7\x35\xda\x3f\xa4\x66\x49\x7e\x19\xf3\x8e\x30\xfb\xa2\xa1\x02\x37\x85\x45\x90\x70\xe6\xe9\x2c\x1c\xb7\xc9\xbd\x0c\x9b\xa6\x12\x20\x15\x78\x66\xc3\xbe\xd2\xb0\x1e\x6e\x6b\x9b\x8d\xd3\xf0\xc4\x7c\x02\xf1\x81\x34\x6a\x0a\x9b\x9b\x5d\x3d\x7e\x18\xa9\x4d\x69\x56\x85\x5e\x16\xe8\xea\xaa\xab\x71\xb1\x03\x02\xf3\x5b\xd8\xfb\x1f\x9b\x58\x47\x30\x41\x60\x32\x49\x26\x64\x5b\x05\x82\xc2\xf2\xf1\x53\x3a\x24\x28\x14\x61\x51\x42\x41\xdb\x28\x50\xef\x31\xc5\x76\x3b\x2e\x3d\x4f\xb1\x8f\xc6\xd8\xc1\xd7\xe5\x2f\x7c\x13\x39\x2c\x17\xe2\x70\x19\xff\x60\x00\x8e\x43\x1f\x17\x14\x37\x0b\xc0\xef\xd9\x45\x2a\x61\xf5\xc5\x64\x88\xd9\x1a\x18\x50\x37\xf1\xf6\x47\xf7\x2f\xa7\x85\x01\x0d\x5d\x78\xf0\xa1\x15\x87\xcc\xf6\x6b\x80\x88\xe0\xe6\x35\xff\xf3\x77\x41\x93\xb2\xed\xef\xfd\x92\xd6\xe8\xa0\x32\x11\x28\xae\x64\xcd\xb8\x62\xe6\x31\xe2\xee\x5b\xa0\xda\x44\xbb\xd5\x89\xdc\x39\x2b\x5a\x11\x3b\x86\xa7\x27\xa8\xdd\xb6\x98\xa3\x34\xcc\x66\x8b\x39\xb1\xcd\xe1\x99\xb8\x88\x37\xca\x5f\x00\xf5\x53\xf8\x9c\x62\x28\x34\x27\x36\x41\xd3\x9b\xc1\x0c\x6a\x24\xe1\xeb\x42\x58\x75\x42\xf0\x3f\xc1\x62\x75\x24\xed\x6b\x74\x93\x91\xf1\x10\x28\x70\x6c\x42\x36\x44\x25\xb2\xca\xf2\x01\x80\xe1\xb8\x02\xc7\x44\xb4\x9b\x7b\xcd\x9b\xf7\xb1\x5c\x23\xa0\xbf\x1c\x69\x65\x96\x0d\x34\x15\x54\xe1\x96\x6b\x6e\xf8\x2f\xcf\xbb\xe4\x1d\x1e\x09\xd7\x41\xe3\x09\x25\x44\x46\x77\x7f\x13\xc2\x9a\x67\xb8\xbd\xeb\xc5\xf7\xf0\x4d\x16\x0d\x60\xe3\x32\xe3\xd0\x44\x1a\x0f\x2f\x7b\x19\x2c\x3e\x2b\xdf\x6d\xad\xec\x2a\x42\x4f\x88\x66\x98\x06\x23\x6e\xe0\x4d\xea\x69\x2b\xd8\xbb\x6f\x91\xca\x06\x82\xec\xe3\x49\x14\x25\x75\x35\x8b\x9b\x7b\xe7\x06\x00\xb3\xcb\x81\xe1\x45\x6b\xa0\x79\x9f\xdc\x01\xff\xd6\x86\x23"}, -{{0xaf,0x7e,0xa8,0xe4,0x1c,0x89,0x37,0xa4,0xec,0x47,0x5a,0xd8,0x13,0x71,0xa1,0x71,0xd3,0xd0,0xf9,0xfd,0x75,0x19,0xa0,0x4c,0x75,0x1e,0xd4,0xad,0x8f,0xf8,0xfe,0xf9,},{0x15,0xdf,0xc7,0x15,0x85,0xba,0xc7,0x1e,0xf2,0x0f,0x37,0x49,0x87,0xc5,0x55,0xa3,0xf2,0xf0,0x7d,0x6b,0x9c,0x78,0x70,0x66,0xc1,0x0d,0x63,0xcf,0x06,0xe0,0x2a,0xb0,},{0xc0,0xf1,0x73,0x91,0x67,0x27,0x4b,0xf9,0x18,0x31,0xc7,0x4b,0xeb,0x64,0x5a,0xf7,0x90,0x45,0x9b,0x28,0xbb,0x3f,0x21,0x32,0x53,0x65,0x13,0x0f,0x40,0x9a,0xcb,0x66,0xdf,0x1d,0x22,0x37,0x59,0xa9,0x75,0x8e,0x08,0xfd,0x72,0x53,0x73,0x74,0x84,0xe2,0x85,0xa6,0xfb,0x47,0x40,0x4a,0xbe,0x2e,0xba,0x5e,0xf2,0x49,0xfd,0x02,0x5c,0x0a,},"\x05\xf2\x26\x3f\x02\x45\xec\xb9\xfa\xeb\x14\xe5\x7a\xca\x43\x66\x68\x30\x8c\x81\x25\xdf\x31\x16\xc4\xee\x20\x50\x1d\x0c\xde\x70\x1b\x36\x6e\x2b\x50\xa1\xc5\xed\xf4\x84\x14\x4c\xe1\x6b\xfb\x1f\x7d\x26\xdc\x42\x75\xea\x97\x32\xe2\x64\xba\x4d\x4a\x36\x2b\x40\x27\x5b\xa4\x73\x77\xdb\xc3\x32\xcb\x65\xe2\xf4\xc8\x85\x38\x94\xaa\x87\x8a\x4c\x17\x5d\xc5\xb3\xb2\xa7\x57\xff\x3c\x8d\x7d\xe6\x60\x97\x3b\x89\xda\xdf\x07\x6e\x2e\x4f\xc7\x62\x39\xb7\xbc\x75\x2a\x22\x9d\x44\xe0\x00\xce\xb6\x67\x10\x4c\xb0\x74\x6b\xfc\xf5\x9d\x69\x60\x3a\xe7\xfc\x1b\xcf\x11\xd2\xe3\x3f\x61\xdc\x49\x7e\xc1\xb0\xbd\x5e\x4f\x1d\xbe\xf4\x35\xf2\xf2\x91\xf3\x0b\x00\xa8\x5e\x83\x39\x46\xc8\xb1\x04\x84\xe4\xab\xd7\xd6\x0b\xdb\xb1\xfe\x6d\xff\x58\x07\xa5\x3b\xb8\x93\x82\x15\x30\x13\xb7\x0c\xa0\x8e\xfc\x91\xb7\xe9\xfc\x5b\x5d\xbb\xb6\xaf\x12\x3b\x57\xbe\x2e\x14\x0f\xc4\x71\xa4\x5d\x89\xfa\x82\x84\xcc\x27\xe0\xa1\xfe\x77\x1f\x55\x59\x8b\xbd\xcf\x06\x8d\x50\x6d\xad\x0a\x59\x21\x79\xce\xca\x39\xee\x95\x26\xf9\xe4\xfe\x47\xbf\x2b\xb1\x4f\xb1\x48\x6a\x67\x7d\x4d\x7b\x99\xa5\x20\x54\x56\x76\xa0\xf1\xfa\x80\x90\x49\xaa\x24\x14\xae\x7b\x81\x7d\x9a\x03\x6e\x5c\x15\x78\x86\xe8\x34\x1d\x4e\x81\x9c\x09\x2a\x3b\x48\xb3\x60\x6b\x03\xac\xb7\x27\xc6\xc2\x21\x7d\x0a\xf3\x01\x21\x54\x6a\x94\xaf\x6b\x49\xca\xa2\xa8\xc9\xb1\x78\x6f\xa0\xc2\xa5\x24\xec\x7a\x02\x3e\x92\x4b\x5f\x8a\x89\xa5\x37\x80\xc7\xf8\x78\x1c\x5b\x8e\x86\x94\x30\xca\xa0\xe6\xd0\x43\x79\x67\xe3\xae\xd4\x4f\x45\xc9\x01\xcb\xcf\x10\x26\xfb\xbd\x4e\x3d\xd9\xa0\x91\xec\xf8\xb3\x4f\x7d\xd5\x03\x8e\x54\x3d\xc7\xeb\x6a\xd5\x49\x4e\xfb\x14\x5c\xf6\x3e\xc0\xd3\x55\xbb\x8e\x17\x2f\x45\x5d\x8a\x6b\x13\xda\xca\xad\xdb\xc5\x6e\x47\xde\x3c\xf7\x62\xa1\xa7\x38\xef\x09\x2f\x14\x36\x68\x04\x67\xb5\xcd\x82\xe9\xe3\x6e\x2d\x2b\x68\x42\xb3\xbd\x5d\xce\x77\x18\x0d\xda\xf0\xb6\x43\x37\x8e\x69\x85\x99\xdd\x47\xf5\xcd\xbb"}, -{{0x0c,0x57,0xcb,0xfc,0xeb,0xde,0x10,0xed,0xe0,0x2d,0x1c,0xb0,0x1d,0xf3,0x60,0xd4,0x1f,0x2e,0x66,0xa5,0x04,0x43,0xd5,0x8b,0x5d,0x4f,0x08,0x28,0xc9,0xa1,0x8b,0xb7,},{0xc4,0xd7,0x61,0xba,0x18,0x99,0x71,0xb9,0x46,0x2c,0x61,0xbf,0x46,0xa7,0x65,0xf8,0x8e,0x2e,0xca,0xa5,0xbf,0x22,0x11,0x22,0x0a,0xfb,0x00,0xac,0x65,0x7f,0x7c,0xe5,},{0x8a,0xf7,0xbb,0xe0,0x1b,0x8a,0xb9,0x39,0x51,0xd1,0x6f,0xca,0x05,0xa9,0xc9,0x67,0xd1,0xc5,0x2c,0x97,0x4b,0xea,0x15,0x1e,0xa7,0x2e,0x4c,0xeb,0xaa,0x20,0xcc,0x78,0x3b,0xb6,0x1d,0x8d,0x69,0x38,0x5c,0xac,0x5b,0xc6,0xd7,0x2d,0xbd,0x16,0x2b,0xee,0xf1,0xfc,0xb5,0xdd,0x0e,0x0a,0x08,0xb4,0x8c,0xa0,0xb9,0xf6,0xd9,0xa9,0x88,0x0c,},"\x33\x77\x03\x24\x3a\xb5\xb4\xe4\xd3\x48\x1e\xe8\xdd\x1f\x44\x94\x50\x71\x74\x41\x26\x58\xa9\x39\x88\xb5\xc3\x04\x03\xa7\xb7\xed\x85\x22\xce\xb4\x6f\xa1\xee\x02\x75\x3a\x87\x4e\xf0\x67\x5d\x39\x7c\x57\x5d\xa0\xb0\x8c\xaa\x8c\xee\x33\x93\x78\x4d\x0f\x0d\xb8\x45\x98\x37\xaf\x90\xb9\x05\x6d\xf4\xe3\x8e\x41\x7f\x3a\xd2\xeb\x1a\x10\x0e\xf2\x07\xce\x2c\xa6\xc6\x10\x01\x80\x21\x66\x1e\x30\x70\x99\xf2\xb7\xc4\xae\x87\x59\x91\x14\x0b\xdd\x3f\x0f\x99\xad\x2c\x5d\x55\xaa\xcb\x84\xcc\x1c\xdc\xd5\x79\xe0\x80\x72\xb6\x95\x1f\xd4\x5e\xd2\x89\xac\x9f\xf7\xf0\x98\x6a\xc8\x8a\x4f\xbb\x9d\xc9\x20\x3d\x9b\xaf\x18\x0c\x90\xed\xf9\x37\x25\x8c\x9d\x0a\x6d\x48\xe2\x20\xf7\x2d\x25\x0c\x7f\x2c\x77\x7e\xaa\x7f\xb9\xfa\x11\xd5\x0a\x57\x98\x77\x2f\x9f\xd9\x76\xb0\x05\x99\xf1\xf0\x27\x6f\x3a\x2e\x4d\x98\x8a\xe9\x21\x25\x46\x7a\x8d\xed\xb7\xa1\x6f\x9e\x3a\x56\xe8\xd0\x06\x62\xb3\xeb\x67\xa3\x5b\x9b\x60\xe7\x3b\xd9\x35\x07\x7e\xe2\x38\xdf\x8f\x6e\x83\x3b\x9a\x55\x23\x38\x68\x26\xc1\xf2\x91\x7b\x1c\x3e\xc9\x8e\x0a\x5f\xde\x89\xc4\x8b\x1d\x44\x6d\xa5\xd0\xc8\x85\xfe\xf0\xe3\x74\xbf\xf3\x0a\x99\x7c\x7b\xaf\xd5\xe7\x43\xc8\x5d\x0c\x6a\xaa\x6e\xf1\x0a\x06\x12\x11\xa2\x32\x7c\x6d\x84\xeb\x74\x7a\x56\xe9\xbf\x60\xfc\xd5\xb5\x53\xb7\x98\x83\x4d\x0c\x5c\xca\xdb\x9d\x4b\x54\xe7\x23\x7d\x12\xc6\x79\xc1\x93\xa2\x87\xbb\x2f\x51\x1c\xd4\xee\x2a\x2d\x85\x49\xb4\x4b\x21\xc1\x1f\xbe\x57\x23\x38\x1c\x6c\x5f\x78\x46\x87\xfd\x90\xce\xbc\x5b\x49\x5a\xf9\xe4\x14\xf2\x96\x1b\x06\xa1\xc8\x43\x3b\x9a\xa3\x29\x2b\xcf\xf4\x24\x1c\x22\x71\x67\xf8\xd1\xde\x05\x4b\xa3\x3a\xd8\x1d\xa3\xeb\x3e\xc6\xe4\x0a\x6e\x26\x85\x4a\xf3\x49\x54\x01\x71\xb7\x5d\x75\xfb\x9a\x8d\x12\x93\x78\x27\xfd\x59\x4d\x31\x7b\x7a\x8d\x9f\x1c\x2f\xca\xbd\xa5\x63\x75\x56\x8c\x3e\x9e\x51\x4c\x2e\xff\xfc\x38\x78\x36\x3d\xcf\xad\x9f\xd9\x54\x36\xb0\x22\xe8\x77\x2a\x88\xcb\x71\xe8\x03\xbf\x90\x38\x19\x62"}, -{{0xfe,0x71,0x72,0x27,0x83,0x64,0x19,0x4b,0xcf,0xef,0xb4,0x78,0x31,0x42,0xb7,0x9f,0x59,0xd5,0xfd,0x97,0x8b,0x1e,0x47,0xc3,0x14,0xd7,0x8d,0x4c,0xb3,0xf6,0x1c,0x8a,},{0x2e,0x82,0xcc,0xe4,0x79,0x10,0xc7,0xe2,0xa7,0x9b,0xc1,0xf4,0x19,0xdc,0x3c,0x3d,0xf5,0x4f,0x23,0x29,0x1f,0xc8,0x19,0x3e,0x82,0x58,0xcc,0xd2,0xfd,0x38,0xd5,0x48,},{0xf6,0xc2,0xa4,0x29,0x6b,0x9a,0x34,0x07,0xc6,0xd7,0xa5,0x67,0x9d,0xae,0x86,0x66,0xb5,0x03,0xd1,0xa1,0x7e,0xac,0xf7,0x1d,0xf4,0x93,0x79,0x1b,0x8f,0xf0,0xc0,0xaa,0x8e,0xed,0x36,0xb3,0x27,0xa2,0x9a,0xb7,0x82,0x8f,0x46,0xf2,0x2d,0xe8,0x68,0xb6,0x28,0xb1,0xcf,0xd5,0x01,0xe8,0x59,0x9f,0xa3,0x16,0x93,0xb1,0x5f,0x61,0x08,0x0f,},"\x23\x50\x94\x51\xa0\x59\x96\x9f\x2b\x4b\xdf\xce\xe5\x38\x89\x57\xe9\x45\x6d\x1f\xc0\xcd\x85\x7e\x4f\x4d\x3c\x25\xa4\x15\x5d\x5e\xe9\x1c\x20\x53\xd5\x58\x06\x2e\xea\x68\x27\x95\x0d\xe8\x63\xbc\x9c\x3d\xf9\x67\x2c\xde\x8b\xa7\x41\x74\x4e\xbb\xdd\xb4\x5e\xc1\xf4\x28\x45\x70\xfd\x0a\xac\xd0\x7e\xa5\x8c\x58\x1b\xe2\xaf\xc9\x5a\xe4\x44\xe6\x78\xed\xc2\xa0\x24\x39\xf3\x87\xce\xc9\x82\xea\x3a\x44\x81\x4a\x8a\x30\x2b\xb3\xbf\xe8\x22\x8d\x58\xde\x03\x9d\xeb\xdf\x7c\x2a\x7e\xdd\xb4\xe7\x1c\xa4\x74\xf9\x4f\x7e\x2b\xd8\x9d\xc6\x5b\x16\x10\x73\x3c\x91\xff\xf8\x9b\xd4\x99\xf4\x01\x54\xa6\x19\x8f\xdf\x5e\xc7\xad\x37\x22\xd9\x25\xb2\x92\x19\x6c\x42\x94\x99\x07\x5b\xe0\xc5\xb6\xda\x9c\x09\x0c\x07\x91\xa7\x01\x9e\xb5\xe7\x36\x6b\xe6\xce\x58\xab\x2f\x04\xfe\xcd\x91\x27\xc4\x27\x18\x04\x7b\xf4\x70\x30\x69\x15\x21\x31\x2c\x08\x77\xaa\x3f\x36\xcc\x5f\xbc\x9c\xaa\xe0\xfd\xe3\x94\x5d\x2a\x86\x8e\xe2\x50\x2a\x38\x33\x20\x8e\xb8\x50\xa1\x63\xcf\xcb\xf6\xda\x9e\xe6\xad\x9f\xe0\x67\xfe\x24\x19\x86\xfe\x44\x36\xd6\xae\x4e\xdc\x61\x56\x19\x38\xe2\xa3\x3f\x4a\x33\xdb\x63\xf6\x9d\x3f\x1a\x88\x50\xed\x40\x02\x88\x69\x16\x41\x03\x48\x8f\xb7\x95\xcd\x82\xca\x06\x7f\xe1\xb4\x89\x7c\xaa\x49\xa7\xca\x9a\x80\xf3\xa8\x15\x1f\xd1\x3b\xbb\x7f\xf3\x50\xe8\x57\x9f\x56\x5d\xc1\xc4\xa9\xca\x93\x8d\x27\xb1\x5b\x3f\x85\x8e\xf4\x5d\x3d\xd7\x8b\x2c\x35\x86\x35\x35\x63\x15\xf5\x5a\x97\x52\x8e\xcf\xec\x5d\x11\xa5\xb7\x21\x50\x31\x07\xfa\xa4\x06\xc1\x70\x34\xe6\x01\x47\x4b\x3b\x60\xcf\x48\x69\x2e\x26\x92\x61\x15\x8f\xc3\x53\xd4\xdf\x42\x74\x38\x13\x57\x79\x0b\x77\x56\x08\x7b\x00\xcc\x79\xe3\xb9\xd2\x8a\x3f\x24\x39\xfe\xbf\x19\x9e\x64\xa8\xb3\x7c\x91\xb5\xa4\x33\x4e\x33\x54\xe8\xfa\xf3\xa3\x61\xe8\x56\xc5\x4b\xda\xa4\x3b\xfd\xcd\x6e\xe6\xc9\xf9\x67\x95\x88\xf6\x06\x99\x50\x83\x23\x48\xaa\xcb\xa2\xbf\xee\xba\xca\xa2\x07\x1d\xdc\x7d\x77\x89\x8e\xf0\xf6\x87\x93\xcd\x25"}, -{{0xa9,0x51,0xe4,0xe6,0xba,0x9f,0x1f,0x0b,0x35,0x48,0x31,0xc9,0x86,0x94,0x24,0x48,0xfa,0xed,0xe3,0x7e,0x11,0xb0,0xf2,0x47,0xda,0x27,0x06,0xdc,0xee,0xf7,0x3a,0xc7,},{0x30,0x36,0x20,0x14,0x97,0x4b,0xf7,0x5c,0x84,0x95,0xc2,0xe2,0x71,0xe7,0x13,0xd5,0x73,0x84,0x38,0x4d,0x0a,0x5d,0xa8,0x8e,0xde,0xea,0x79,0x27,0x9c,0x0c,0x58,0xec,},{0x02,0x78,0xc8,0x6a,0x15,0x20,0x8d,0x9b,0xe5,0xb1,0xe1,0x57,0x47,0x61,0x86,0x1b,0x8a,0xf7,0x2a,0xe0,0x8d,0x40,0xcd,0xcb,0xec,0x35,0x4e,0x65,0xa9,0xc3,0xd0,0xa0,0x6b,0x5f,0xcb,0xb2,0x97,0xd0,0x9b,0xef,0x39,0x74,0x62,0x39,0x59,0x86,0xc3,0x09,0x3e,0xeb,0x22,0x64,0x4c,0x00,0x3c,0x30,0x78,0x17,0x8c,0xdf,0x67,0x4e,0x99,0x0a,},"\x20\x57\x7d\xca\xc8\x91\x74\x88\x5e\xed\xb0\x62\x48\x9c\xd5\x12\xfa\x72\x86\x3e\xc5\x43\x8e\x31\xe9\x58\x78\xb7\x5c\xe2\x77\x2a\xee\x62\x90\xa0\xba\x3c\x8f\x64\x2c\x1d\x0e\xf5\x5d\xa8\xd5\xbc\x14\x84\xf8\x3b\xb9\x87\x6c\x7a\x8c\x0b\x6b\x60\x9b\x94\xd1\x12\xa0\x6f\xc8\x3c\xe8\xd2\xc1\xe0\x8e\xd6\xc7\x35\xe5\x7b\x24\x4a\xad\x6e\xcf\x70\x75\x36\x3d\x56\x5b\xa4\x78\x65\x69\x5c\x84\x23\x51\x09\x09\xe0\xa3\xdb\x4b\x61\xed\x7a\xa6\x7a\x74\x71\x33\x1e\x83\xa0\xc5\x8b\x82\x20\xa6\x24\x5f\x65\x66\x15\x49\xc1\xa1\x2d\x4c\x0d\x50\xc3\x26\xfb\x94\x91\x7c\xbd\x07\xbe\x51\xe8\x3f\xe8\xbb\x3e\x46\xca\x01\xb0\xa2\x60\xda\xaf\x1d\x6a\xbe\x37\x03\xd6\xa9\x25\x11\x3b\xb4\xd5\x7e\xa1\xa4\x8b\x4c\x7d\xbd\xaa\x03\xee\xa8\x14\xa4\xb5\xf0\x2e\x1d\xfb\x54\x5c\xc6\x23\xfe\x17\xa3\xbb\x18\xe4\x37\x3f\x5f\x7e\xc2\xfb\x52\x17\xd2\x3e\x4f\xed\x54\xa7\x72\xe1\x13\x23\xe7\x30\xaa\xd7\xef\xca\x8c\x46\x44\x00\xe7\x67\x90\x55\xfc\xc1\x25\xa8\x76\xef\x7b\x8b\x9d\xe1\x86\xe2\x29\xa7\xab\xf1\x91\xd0\xc5\x6d\x91\x81\x5f\x67\x87\x2e\x95\x7b\xfb\xc7\x63\x4a\xac\x40\x35\x76\xa5\x8f\x42\x7b\xdb\xb3\x0e\x8c\x4b\x6f\xc6\xc4\x47\x74\x10\x24\xeb\xb5\x03\xa5\xa9\x02\x51\x24\xa4\x88\x7f\x82\x5a\x43\xee\x94\x0f\x21\x0a\x1b\xd5\xae\x4f\x67\x32\xd6\x0f\x95\xf2\xb8\x32\x01\xc4\xc6\xdf\xe2\x79\x41\x2d\x75\x02\xa5\x21\x1f\x8f\x48\xf8\x00\xdb\x30\xfc\x37\x76\xc4\xed\x3a\x38\xbb\x46\x34\x82\x2c\x98\xa6\xd6\xdd\x32\x33\xbe\x60\xe4\x2c\xca\x45\xa3\x16\x3c\xc8\x4e\x9e\x8d\xa6\x47\xc0\x71\x1b\xc4\xc6\xcc\xd6\x5a\xa1\xe9\x72\xc0\x74\x04\xd1\x03\xe7\x4b\xcc\x31\xa7\xe2\xc3\xee\xa5\xac\x92\x57\xab\x42\x89\x47\xab\x3d\xd3\xfb\x15\x3d\x90\x69\x4a\x40\x73\x37\x3c\x4d\xd9\xce\xb1\x31\x15\x4f\xe8\x77\x47\x3f\xd9\x96\xf4\x24\xf3\x3e\x31\x6e\x4e\xb0\x2b\x8c\x75\x13\xbe\x69\x98\xe5\x16\xcb\xba\x54\xd9\x4c\xd0\xa4\x35\xe0\xff\xcc\x2c\x0a\x8e\xf7\x2b\x63\x0e\xc2\x47\x81\x06\x6a\xa5\xef\xb9"}, -{{0x38,0xa9,0xb2,0xd4,0x9b,0xa8,0xb8,0x2f,0x30,0x1a,0x57,0x72,0xce,0xa0,0xef,0xc2,0x21,0x84,0x55,0xc8,0xb2,0x18,0xb2,0x2c,0xba,0xa2,0xaa,0xd2,0xd7,0xad,0x3b,0x35,},{0x9d,0xf5,0xea,0x1f,0x78,0xf8,0x10,0xa5,0x21,0x77,0x46,0x02,0xbb,0xba,0x49,0x42,0xf0,0x45,0x92,0x38,0x96,0x6c,0x8b,0xcd,0x21,0x90,0x0a,0xfb,0xf3,0xd8,0x42,0x93,},{0xe1,0x9e,0x62,0xac,0x53,0x9a,0x9c,0xa2,0x51,0xd1,0x2d,0x4c,0x71,0x05,0x5b,0x0a,0x3f,0x58,0x1d,0x19,0xf2,0x68,0x2e,0x67,0x24,0x04,0xc7,0x8a,0xc1,0xf1,0x2b,0xbe,0xfc,0x91,0x51,0x92,0x76,0xa5,0xcb,0xe1,0x6f,0x52,0x0c,0xf7,0xa7,0xf6,0x87,0xa2,0x40,0xf0,0x32,0x91,0x57,0xc5,0x9f,0x50,0x02,0x6a,0x58,0xdc,0xdc,0x50,0xfc,0x08,},"\x17\x78\x16\x7c\x49\xb3\xa4\x4d\x4a\x5b\xa8\x38\xb7\x38\x85\x53\xb1\xe1\x3d\x36\xea\x4f\x86\xd3\x02\x42\xe1\xa8\x22\xa3\xbb\xaf\xf5\xce\xa6\x3e\x2a\xe2\xa4\x63\x5b\xe2\x36\xfe\xf2\xb8\x13\x5d\x14\xfb\x62\x1c\x0b\xb7\x73\xc9\xc1\x77\x53\xf8\x09\x26\xeb\x55\xd0\xf1\x15\xbd\x09\xa8\x85\xd8\x44\xb8\x18\xc9\xf0\x44\x89\xa3\x31\xbb\x5e\x03\x2b\x8e\x58\xcd\xa3\x69\x49\xc5\xa8\xd0\x8b\x55\xbb\x8d\xe9\x65\xe1\xf9\x0d\x3b\x9c\xfe\xec\xfc\x6a\xd9\xa4\xee\x5c\xb4\x04\x7e\x94\x50\xac\xdc\x64\x64\x01\x66\xa8\xc0\x69\xea\x84\x9a\xeb\xdd\xac\x1a\xe4\xaf\xec\x91\xdd\xd1\x7f\xa5\x55\x3f\xa8\x7c\x56\xf7\xe5\x1e\xc1\xcd\x6b\x5c\xc2\x33\x51\xd0\x57\xa4\xce\x4a\x89\x23\xc8\xae\x6a\xc7\xa8\xaf\xdc\xc0\x88\x1c\x0e\x74\xeb\xb0\x24\xef\x72\x96\x16\x2c\xb9\x3c\x68\xe5\x0b\xbb\x07\x4e\x65\x1a\xc8\x7d\xac\x9e\xa5\x9d\x4c\x3f\xbf\x0f\xe3\x79\xf3\xe9\x7a\x24\x56\x6e\xca\xe5\x43\x03\xbc\xfb\x6f\x0c\xc9\xf1\x5f\x66\x39\x43\x0e\x66\xb1\x9a\x42\x78\x49\xfd\xff\xf8\x33\xdf\x02\x68\x9e\x9d\xe4\x40\x06\xc9\x03\xc5\x59\x18\x34\x59\xb9\xf4\xa9\x7f\x54\xa0\xf2\xa2\x8d\xf7\xb0\xe9\xde\xed\xa8\x23\x9d\x7b\x51\x69\x77\xf5\xe7\xd6\x97\x1b\x45\x02\xe9\x88\x5f\x75\x0a\xf8\xd1\xa6\x66\x9e\x25\xe7\x7d\x5f\x32\x7c\x77\xc8\x7a\x86\xe0\xa1\x87\x2b\xc9\x6a\x76\x06\x0f\x5f\x8a\x0c\x40\xcc\x97\x3b\xfc\x7f\xe6\xed\x9b\xca\x78\xf8\x84\xe6\xa2\x82\x8b\x94\xd4\x89\xd3\x2a\x0f\xd3\x37\xe6\x9d\xb8\x3f\xb8\x78\x9a\xfd\x4e\x8e\xf5\x4c\x22\xa7\x8c\x25\x87\x46\x8b\x9a\xe0\x71\xba\xe3\xb2\x02\xd3\x18\x3a\xd5\xf0\xf8\xe8\x42\xe5\xa8\xde\x85\xbf\xff\x49\xe0\x3c\x83\x81\xbc\xa7\xfd\x42\x78\xdd\xcc\xaf\x01\x34\xfb\x55\x93\xa3\x95\xa7\x7a\x5c\xbd\x43\x45\x93\xbc\x4a\xd0\xff\x4b\x84\x00\xec\x67\x4c\x4e\xca\xf1\xd5\x77\x54\xbe\x0c\xb2\xfa\x9a\x64\x41\xa9\xab\xad\x7b\x42\x19\x7a\xd8\x2e\x50\x82\x7e\x4a\x42\x45\x57\x3a\x8f\x0e\xf8\x7f\x58\x22\x8a\x28\x67\xf4\xb3\xb8\x34\xb6\x63\x50\x37\x94\x0a"}, -{{0x9a,0x17,0x17,0x87,0x36,0x89,0xa0,0x3c,0x11,0x2d,0xd6,0xb4,0xd7,0x6a,0xe7,0x3b,0x89,0xb4,0x16,0xa5,0x98,0xce,0xec,0x20,0x9e,0x27,0x96,0x1e,0x7b,0xb1,0xee,0x8a,},{0xee,0xca,0xd1,0xe0,0xe4,0xb8,0x63,0x29,0x18,0x81,0xa8,0xc2,0x41,0xdb,0x9c,0xcf,0xff,0xe4,0xe5,0x5d,0x8b,0x5a,0x42,0xf3,0x07,0xb4,0x43,0x6a,0xcd,0x06,0x49,0xa6,},{0x1a,0xf8,0xbe,0x09,0x55,0x38,0x96,0x58,0x00,0xd8,0xef,0xf6,0xd7,0x23,0xd0,0x28,0xd6,0x5d,0x0e,0x9c,0x6e,0xb5,0xe9,0xd1,0x25,0xbb,0x3b,0x17,0x83,0xf1,0x1e,0xf7,0x07,0x9a,0x49,0xa8,0x07,0xe2,0x7e,0xf1,0x26,0x0b,0xe2,0x6a,0x3b,0x23,0x1d,0x03,0xb2,0xae,0x15,0x1e,0x49,0xf6,0xf1,0x89,0xf1,0x5b,0x1c,0x83,0xea,0xb0,0x1c,0x02,},"\xe2\x65\x80\x47\x09\x01\xa0\x7a\xb0\x93\x1a\xa2\x38\x29\x80\x2c\xe0\x4d\xa5\x9f\xdc\x2f\x77\x3b\xc5\x67\xf1\xe6\x5b\x4f\x2e\x2d\x4a\x1a\x6a\xec\x1f\x54\x15\x8a\xdf\xce\x9b\x09\x97\x90\xb5\x03\xa1\x3d\x22\x09\x7a\xe2\x3e\xbc\xcf\x92\x3f\x3b\xb1\x98\x6d\x6e\x49\x11\x1a\x8c\xf0\xd4\xeb\x82\x36\xbf\xe0\xd7\xc9\xe9\x3a\x5e\xfc\x7f\xeb\x8e\x6a\x9c\xd1\xb8\xd9\x21\xef\xa2\x1e\x44\x9f\xf4\x9e\x06\xc1\xcc\xfe\xa3\x1f\x93\xe0\x33\xc3\xc2\xa5\x4d\xdb\x0f\x65\x3a\x09\xfb\xd1\x8a\x70\xb5\x63\x15\xf1\x93\xe7\xbe\x56\xe5\x16\x8f\x59\x56\x38\x21\xd4\xbc\x3b\xbb\x0e\xaa\x20\x48\x28\x6b\xbe\xee\x5a\xa3\xf3\xe7\x53\x6c\xf2\xb7\x50\xfd\x32\x26\x02\xbb\x38\x47\xce\xca\x39\xb7\x54\x74\x32\x2d\x76\xb1\xde\x80\xfa\x2e\xad\xba\x15\x2d\x6f\x8f\x02\x0d\x4d\x93\x1c\x53\xf0\xa2\x80\x12\x24\xd3\x5d\xeb\x6e\xc1\x3b\x01\x48\x73\xe6\x89\x90\x36\x07\xde\x96\xd9\xb7\xa7\x43\xa8\x87\xd2\xf4\x8d\xaf\x2e\xd2\xee\xfb\x20\x2a\xbf\x60\x82\x79\x69\x81\x12\x3b\x96\x6e\x93\x6d\xcf\x34\x83\xe2\xd2\x4d\x69\x4e\xcb\x86\x5f\xbe\xb6\x96\x9f\x34\x70\x27\xfb\x8b\x17\x5d\x24\xa4\xc0\x45\xc0\xbb\x4a\xb5\xe0\x2d\xdc\xbe\x77\xd4\x75\x6c\x46\xd1\x37\xb0\x94\x47\x3a\x02\x30\x7a\x10\x83\x40\xac\xad\x9d\x03\xba\xe8\x40\x3a\xf1\x99\xcb\x75\xca\xe3\x16\x2f\x38\x15\x81\x3c\xc6\x8b\xf2\xa5\xe4\x99\xe5\x94\x92\x11\x49\xf3\xbb\xd2\x14\xda\x51\x37\xe7\x56\x52\x15\x59\xdc\x80\xd9\xa4\xb7\x4a\x0f\x49\x43\x02\x2c\x7c\xd5\xfc\xa4\x23\x15\xe0\xbc\xee\xae\x90\x69\x61\x5c\xe6\x7a\x04\x38\x24\x12\x31\x3a\x31\xd6\x7b\x34\x6c\x32\x9a\xd8\x2e\x74\x2c\x0a\x6c\xe0\xa6\xa0\x24\x54\xc1\x13\xe5\x20\x22\xf3\xcc\x03\xfd\xa6\x91\xeb\xdf\xe1\x4c\x53\xc8\xce\x5c\xa9\xb9\x32\xca\x1a\x38\x6e\x3e\xb4\xe9\x0a\x4d\xc6\xe8\xad\x85\x33\xb5\xaf\x1a\xae\xf5\x00\x31\x28\x65\x5c\xa6\x4f\x67\xfc\xd9\x7c\x6a\xc8\x03\x00\x24\x04\x90\x0b\xc0\xfa\xe9\x84\x63\xbc\xc3\x14\x09\xf9\x98\x17\x48\x78\x9a\xde\x2d\x07\x78\x3b\xc3\x2b"}, -{{0x43,0xbd,0x92,0x4d,0xb8,0x15,0x60,0x08,0xc6,0xb3,0x99,0x4a,0x81,0x30,0xd4,0x27,0xd5,0x14,0xdb,0x8a,0x61,0x3b,0x84,0xdf,0xb0,0xb8,0xe0,0xde,0x6a,0xc3,0x06,0x76,},{0x1b,0x34,0x61,0xc2,0x69,0xd5,0xb0,0x06,0x2d,0x5d,0xf6,0xfa,0x65,0x4a,0x25,0x86,0xf6,0x47,0xa0,0x68,0x42,0x18,0xa0,0x6e,0x5e,0x2f,0x7b,0xad,0xfb,0x39,0x41,0x31,},{0xd2,0xa0,0x5d,0x88,0xd9,0xd5,0x43,0xd9,0x4d,0x57,0xec,0x88,0xae,0x55,0x68,0x17,0x50,0xf2,0x0b,0x9b,0xe9,0xc1,0xe9,0x18,0xcd,0xaf,0x45,0x77,0x67,0xf2,0x94,0x8d,0xd6,0x29,0xe9,0x4f,0x06,0x8e,0xdc,0xf3,0xd9,0x92,0x7e,0x33,0x02,0x34,0xba,0xdc,0x3a,0x02,0xfa,0x5a,0xd3,0xd9,0xd8,0x5e,0x94,0x8c,0xb0,0xb0,0xcb,0x3c,0xd7,0x0a,},"\x61\x84\xe6\x48\x0c\x42\xe9\x6c\xc8\x77\x26\x9b\x16\x37\x15\x45\xff\x95\x23\xc4\x5e\xa8\x8e\x76\xa1\x34\x8c\x68\xae\x7f\x31\x8b\x08\x8f\xe4\x61\x09\x28\x23\x91\x85\xb6\xb5\x5b\xfa\x0f\x43\x64\x4c\x4a\x4c\x97\xc5\x6e\xd7\x7d\x08\xb1\xf4\xaa\xd2\xf4\xaa\x06\x99\x94\xab\xec\xa9\x6b\x7b\xf8\x1b\x80\x64\xea\x43\x50\xd8\xa8\xb0\x22\x97\xa5\x13\x08\xb6\x1c\x57\xc8\xf1\x87\x3c\x6f\x97\x00\x7a\xca\x31\x80\x42\x9e\x73\x0a\x66\x43\xf2\x87\x33\x54\x7b\xcf\x7b\x9a\xdf\xe3\x27\xe8\x57\x36\xbd\x04\xaf\x7f\x1d\x9f\x4f\xb8\x4a\x7f\x3a\xff\xdf\x4e\x22\xb5\x74\xec\xb4\xbc\x88\x36\xb1\x0b\x84\x53\xae\xaa\x5c\x1b\xf1\x32\x24\x8b\x82\x6c\xc5\x23\x0f\x75\xe0\x75\xfa\xc9\xf0\x37\x56\x11\x36\xe0\x06\x43\xd0\x82\x53\xe7\xad\x65\x2f\x70\x2c\x0d\x15\xb6\xd7\xd4\x8a\xa6\xf8\xe9\xb5\xf5\xcc\x14\x6e\x3f\x15\x6f\xb2\x52\x27\x51\xc3\x71\x00\x41\xbd\x92\x2f\x37\xa5\x03\x77\xe0\x28\xb0\xc4\xe4\xbc\x34\x65\xd7\xc8\x4a\xf6\xa5\xfb\x42\x7a\xcb\x3b\x41\x37\x8b\x10\x2b\xda\x46\xd8\xf6\xf2\x03\xa5\xff\xcf\x39\x5d\x43\x5e\x93\x45\x8a\x0b\x0a\x4c\x2e\x77\x82\xfa\xfe\x11\x9f\x76\x9f\x67\x05\x8c\x66\x77\xf6\xd1\x0d\x9c\xf5\xcb\x87\x48\xe1\x80\x57\x98\xed\x23\x3f\x6f\x93\x0e\xee\x0e\x50\x75\xbc\x58\xb9\x7a\xf9\x17\x7f\xda\x75\xd5\x37\x08\xbe\xb0\x4d\xc4\xf1\x9a\x43\xe7\x68\x07\x46\x09\xf1\x40\x65\xf4\x8f\xda\xd5\x07\x7c\xe1\x09\xba\xcc\x35\x71\x74\xa6\xb7\x95\x6f\x6e\x7f\x32\xe3\x84\x15\xbe\x52\x63\x70\xfa\x58\xc3\xc0\xb3\x1f\x51\xe6\xcd\x4b\x2c\xf2\x7f\x8b\xcb\xc2\x12\x59\xd9\xe5\xc3\xb5\xc2\x94\x6a\x9f\xc1\xb0\x0d\x9d\x15\xc3\xb7\xd8\x0b\xfd\x9d\x05\xdb\x91\xd2\x49\xd3\xe4\x2d\x89\x56\x68\x20\x44\x54\x8d\x83\xbd\xa8\xd5\xcc\x92\x12\x44\x2f\x30\xb4\x5c\xf4\xae\xad\x80\xcc\xe9\xb3\x51\x2c\x39\xc5\xc7\x37\xd3\xf8\xd7\x47\xaf\xba\xb2\x65\xaf\x5e\xee\xf8\xca\x93\x62\xec\x76\xe9\x43\xb0\xa0\xd7\xa3\x9f\x3d\xb1\x1e\xca\x14\x45\x8a\x7b\x59\x2e\x5e\x4f\xf2\x27\x5d\xd4\x8b\x28\x53"}, -{{0x8f,0xb0,0x86,0x20,0x6d,0xd9,0x5a,0x26,0x21,0xf5,0x98,0x56,0x0c,0xcb,0x28,0x1f,0x82,0x73,0xc8,0xfc,0x72,0xe2,0x36,0x11,0x08,0x9b,0xaa,0xc8,0x9d,0x3c,0x3c,0x78,},{0x20,0x27,0x6e,0xf4,0x79,0xf4,0xd4,0x52,0x3a,0xb7,0x74,0x20,0xd4,0x24,0xe8,0x81,0x9c,0x33,0xc8,0x37,0x79,0xed,0x80,0xc7,0xf6,0x66,0xe8,0xf4,0x40,0x3f,0x94,0xd7,},{0xa9,0x30,0x5e,0x00,0x16,0x00,0xd5,0x97,0xd0,0x5e,0xf6,0x71,0x69,0x9b,0xf0,0x9f,0x0d,0xcc,0x0c,0x44,0x47,0x5d,0x3c,0xa3,0x1e,0x7f,0xf1,0xbf,0xfe,0xdc,0x0c,0x67,0xda,0xa1,0xf3,0xb7,0x6a,0x03,0x59,0x48,0xc5,0x9c,0xd8,0x7f,0x82,0x45,0x3a,0x40,0x95,0x0a,0x1c,0x97,0x03,0xc2,0xe7,0xd9,0x28,0x0e,0x73,0x03,0x96,0x6d,0xa3,0x01,},"\xf0\x29\x03\xed\x42\x66\xe8\x49\xa4\x48\x52\x05\x95\x4f\xff\xa8\xa1\x08\xc3\x23\xb7\xe3\xf8\x43\x31\x04\x35\x14\xe4\x85\x56\xab\x01\x94\x97\x23\x3a\x5a\x12\x7b\xff\x3c\xd7\xc9\x70\x86\xbe\xce\xf5\x38\xb3\xf3\x39\xd7\xd0\x6e\x53\x2d\xc7\x32\x5e\x59\x7a\xe3\x57\xf8\x16\xde\xa4\x2a\x6a\x22\xc7\x9d\x22\x07\x4a\x2e\x1a\xd8\x02\x3c\x42\x4b\x7e\x09\x6e\x5a\xd8\x89\x7b\x05\xef\x7d\x00\xd3\x0a\x04\xaa\xf2\x98\x1e\xdd\xff\x2b\x34\x7f\x1e\x27\xe2\x0a\xab\xbe\x7e\x7a\x95\x44\x97\x8e\x09\x2b\x00\xcc\xe4\x20\xab\xa0\x61\x87\x37\x4f\xfb\xb3\x7b\x4c\x22\xd7\x5f\x04\xe5\x75\x90\xf6\x10\xa2\x73\x47\x28\x6c\x29\x83\x12\xa6\xc9\xb1\xbd\xf2\x4f\xbd\xa8\x51\x3c\x4f\x83\x56\xcc\xf7\x57\x06\x8f\xfc\x11\xbc\x65\x11\x37\x83\xa5\xdd\xe7\x72\x2f\xaf\x4c\xeb\x19\xfb\xb6\x2f\x40\x70\x2e\x2c\x6e\x6a\x8b\xb4\x9e\xf4\x04\x46\x45\x0c\x4c\x59\xa2\x99\x09\x44\xda\x47\x44\xf6\xee\x77\x0b\x93\x0c\x24\x66\x69\x81\x3c\xe5\xa9\xf5\xa4\x7d\xd8\x03\x88\x98\x1b\xfc\xc3\xa5\x6b\x5b\xe2\xc4\xc7\xe6\x59\xa2\xe9\x18\x2d\xec\x0a\xaa\xfe\x90\x31\xaa\x39\x54\xd4\xfe\x7c\x43\x11\x96\xa5\x61\xa5\xb7\x8e\xab\xa6\x4f\x3d\xb1\xb5\x86\xc5\x3b\x16\xf6\x79\xa8\x49\x21\xa6\x42\xc2\x60\xe4\x65\x3a\x61\xde\x10\x8e\xbd\xe6\xf7\x05\x3a\xfa\x2c\xb3\xf3\x66\x8e\xde\x12\x10\x20\xdd\x1b\xac\xe8\x41\x8a\xeb\xac\x3a\x5b\xd5\x14\x2f\x10\x5a\xc2\x6f\xe4\x9e\x5f\xb1\x40\xc1\x9b\x22\xd5\x4a\x62\x91\xdf\xc9\x54\x67\x02\x47\x88\x16\x46\x87\x4d\xef\xad\x81\x49\x95\x51\x9f\x62\x60\xe9\x77\x4a\x8d\x18\x5c\x37\x88\x1b\x4f\x25\x43\xc4\xb6\x3f\xbf\x19\x85\x01\x6a\xb4\x1c\x4d\x72\x8c\xbc\x90\xb3\xab\x87\x62\x67\xbe\xd4\x1d\x0c\x09\x02\xf6\xb5\x0e\x8f\xa9\x06\xfc\x47\x88\xf7\xb8\x20\x46\x73\x06\xe0\xfe\x9e\x03\x6a\x0a\x00\xf8\x04\xf9\x1c\x3c\xa7\x18\xb9\x5f\xf6\xd9\xe2\x20\x4b\xc3\x16\x1b\xf7\x0f\xcc\x17\xb2\x96\x4b\x56\xbc\x61\x2e\x29\x40\x2d\x96\xf5\x09\x86\x51\x4b\xc7\xd8\x31\xd5\x8e\x42\x79\x37\x86\xd5\x80\x6f"}, -{{0xaf,0xa1,0xb8,0x46,0xc2,0x10,0xb5,0x23,0x00,0xe9,0x76,0x96,0xf8,0x1b,0x8e,0xa7,0x74,0xd1,0xdf,0x12,0xe6,0x12,0x52,0x7c,0x55,0x74,0x7f,0x29,0xc1,0x93,0x73,0x96,},{0xb6,0x09,0x56,0x6b,0xbd,0x19,0x47,0xbd,0x7a,0xfa,0xce,0xb1,0x43,0x89,0xe8,0x36,0x22,0x71,0x69,0x21,0x5f,0xab,0x66,0x85,0x1a,0xa5,0xd7,0x0d,0x6e,0x2e,0x3b,0x89,},{0x98,0xb0,0xc6,0x31,0x3c,0xec,0xaf,0x7c,0x82,0xcb,0xde,0xb3,0xd0,0x28,0x06,0x41,0xc6,0x1a,0x06,0x0f,0x65,0xe5,0x63,0xaa,0x93,0xce,0x18,0x30,0x0a,0x9b,0x58,0x27,0x2d,0xc8,0x68,0x0b,0x48,0x5e,0x8c,0xd1,0x1c,0xf8,0x0f,0xdc,0xa8,0x68,0xfa,0xb3,0x65,0x37,0x83,0x84,0xa1,0x42,0x72,0x7f,0x2f,0x84,0x4f,0x87,0xcf,0xdf,0x19,0x05,},"\x4c\xac\x1b\x1f\x4b\xd4\x82\x84\xdc\xc9\xaf\xc8\xb5\x95\x5b\x64\xb4\x36\xdb\x70\x4b\x03\x35\xd9\x75\x5c\xc1\xf9\x74\x77\xf8\xd3\x23\xcb\x64\x10\xef\x14\x6a\xb8\xa9\xef\xb9\x52\x6d\x8b\x62\xe3\xbb\xad\x1f\x72\x95\xf4\x7b\xa9\xf0\xde\x95\x8f\x8e\xc9\xb7\x7a\xb4\x22\x32\x43\x7e\xd9\x74\x85\x64\x44\xcd\x22\xe2\x0b\xe3\x5e\x91\x81\x3b\xff\x4b\x01\x6f\x81\x0d\x0f\x61\xd8\x9f\x6b\x61\x4d\xb3\x3f\x34\xbd\x09\x98\x5b\x59\x3f\xe3\xe0\x6e\x06\x5b\x7b\xc6\xcd\x39\xd5\x5c\x2c\xfb\xec\x7b\x6d\x59\xc0\xb3\x7d\xd1\xd0\xd3\x51\x35\xab\x1d\x1b\x04\xf2\xf3\x0c\x2f\x04\xf4\xba\x2b\x36\x58\x27\x38\x08\x1c\xf5\x91\x90\xf5\x28\x36\x3d\xb9\x44\xed\x61\x29\x31\xd1\xd5\x14\xc6\x21\x4f\x9a\xb9\x2a\xbb\x18\x33\x92\x61\x83\xac\x52\xfb\xa2\xa4\x55\x1e\x20\xe4\xc0\xac\x95\x9a\x49\xdd\xb1\x67\xa3\x81\xe0\x24\x1d\x40\xc0\x86\xe9\x0e\x52\xac\xa0\x17\x25\x89\x75\xdb\xab\x2b\xa4\x51\xee\x53\x9a\x71\x8f\x07\x6a\x58\x70\x9c\x66\x97\x41\x8d\x9c\x6f\x13\xe4\xd3\x91\x36\x8b\xf0\xe8\xbd\x8f\x29\x32\xdd\x95\xce\xaf\x7a\xac\xa1\x24\x11\x47\xd3\x41\xa3\xac\xd0\x8d\xc3\x29\x05\x48\x35\x72\xb8\x9a\x80\xcc\x47\x23\x14\x68\xab\x8d\xe3\x59\xdd\x52\x5a\x62\x57\xcf\x19\x6c\x2e\xcb\x82\xfa\x8a\x78\xaa\x3a\x85\x1c\x7c\x96\xca\x25\xbf\x7c\xa3\xdc\xf3\xca\x21\x45\x3d\x0d\xfd\x33\x23\xd5\xa4\x22\xde\xc8\x43\x16\x10\x2f\x68\x4c\x35\x9f\x22\x6b\xb5\x37\x79\xc0\xb9\x95\x09\x39\x28\x1e\xf7\x9a\x58\xc0\x11\x99\x3e\xac\xe0\x85\x49\x7a\xfa\x4d\xaf\x64\xc9\x68\x7b\x0a\x11\xaa\x11\x6c\xfa\x7b\x03\x93\x62\x41\xa5\x56\x7b\x64\x6e\x7e\x42\xe9\xfb\x59\x24\x05\xb8\xfa\x3c\x0a\x82\x1f\xc3\x12\x1b\x45\xb1\x75\x3c\xec\x9a\x83\x94\x7d\x21\x1a\x45\x49\x9b\xd6\x37\x90\xb8\x7f\x01\x47\x2f\xe5\x66\xd8\x76\x96\xef\xed\xbb\x74\xed\x00\x04\x8c\x38\x4b\xa7\xf0\x27\xb3\xaa\x42\x98\xdc\x41\x10\x34\x9f\xed\xf5\x2a\x96\xcd\x05\xd0\x8b\xd6\x35\x77\x1e\xd4\x51\x07\x38\xd8\xf0\x7a\x60\x21\x24\x4d\x19\x03\x57\x9a\x3e\xa7\x39"}, -{{0xc8,0x59,0x13,0xa6,0x87,0x78,0x77,0x13,0x10,0x01,0x62,0x3c,0xcd,0xa9,0xcd,0xc1,0x2b,0x9d,0x40,0x43,0xb8,0xa8,0x37,0x93,0xc4,0x46,0x96,0x63,0x2c,0xd6,0x42,0x1c,},{0x9c,0xc6,0x7c,0x69,0x48,0xf7,0xbf,0x6e,0x55,0x6d,0x08,0x49,0xd3,0xb8,0xd2,0x03,0x45,0x7a,0x7b,0x61,0x54,0x9b,0x36,0x68,0x1d,0x75,0x4f,0x1d,0xc0,0x84,0x1e,0x96,},{0x01,0xfc,0xcf,0xdb,0x1f,0xb6,0x88,0x8b,0x03,0x10,0xa9,0x13,0x17,0x0f,0x7e,0x36,0x68,0x16,0xda,0xeb,0xe7,0x65,0x0d,0x72,0x51,0x3d,0x95,0x06,0xe6,0x6f,0x7d,0x62,0x20,0x8a,0x49,0xec,0xe0,0xaf,0x18,0x71,0x49,0x7f,0x45,0x41,0xef,0x60,0x5b,0xde,0x71,0x1c,0x9e,0x0a,0x12,0x05,0xef,0x48,0xf2,0x6c,0x03,0xdc,0x1a,0xd4,0xaf,0x03,},"\x91\xb5\x00\x9e\x83\xd0\xf6\x10\x33\x99\xc2\xd3\xfe\xec\x00\x84\x97\x3a\x30\x5b\xf4\x17\x6e\xc7\x82\x53\x75\x60\x47\x2d\xb1\x87\xa1\x1b\x4d\xcb\x4b\x2f\xfb\x7f\x06\x44\xfe\xb3\x94\xb2\x8e\x5b\xfe\x97\x24\x7c\x4a\x4a\x23\x1c\xf6\xe9\x16\xbf\x99\x34\x4c\xcd\xa8\x8a\x7f\x5d\x83\x1d\x6d\xe3\xd5\x63\xdd\x10\x2e\xae\xb1\x08\xc5\xbd\xce\x44\xe0\x63\x2d\x17\xe6\xfa\x55\xb1\x80\x67\xdf\x2f\xa8\xd2\x00\xa9\x86\x9f\x6a\xff\x92\x0c\x51\xd4\x6a\x1c\xed\x2d\x90\x3b\x1d\x9b\x6b\x07\x5f\xac\xbf\x91\xcd\x05\xeb\x41\xad\x81\x1a\x8e\xf4\x0d\x91\x18\x26\x10\x12\xc7\x2b\x89\x79\xf1\x51\x53\xdb\xb8\x56\x12\x93\xda\x9f\x8b\x77\xc8\xff\x14\xf7\x53\x87\x53\x6f\x00\x36\xd1\x71\x3a\x72\xce\x8c\x35\xb1\x06\x2f\x2c\x67\x32\xae\xbf\x32\x93\x67\x99\xb5\x1c\x2c\xbc\xd6\x57\x24\x13\xe7\xdf\xaa\xb8\x64\x1a\x02\xc1\x50\x23\x73\x81\xcf\x7a\x14\xe2\x2c\x74\xc6\xc2\x00\x09\xde\x7d\x3b\x7e\x69\xcd\x1b\x45\x84\xac\x2c\x01\xba\xba\xf9\x73\xc5\x6b\x38\x14\xbb\x00\x89\x72\x0e\x41\x96\x81\x06\xcf\x26\x50\x9d\x4a\xa5\x46\xfc\xad\x55\x34\xaf\x30\x3f\xfc\xa4\x2b\x16\xae\x6c\x93\xee\x06\xbc\x3c\xac\xe1\x2e\x4e\xc7\x18\x84\x4b\xd3\x0d\x22\x24\xcc\x48\x6d\x10\x6d\x1c\x45\x6b\xfa\x16\x5e\xa0\x12\x0f\xab\x3d\xf2\xc5\xab\x3a\x52\x3b\xbf\xa7\x89\xde\xed\x44\x03\x2a\xb0\xbe\x86\xeb\x7c\xc0\x9c\xdb\x7c\x07\xaa\x94\x8d\xd5\x27\x7c\x3d\xf1\xd9\xd1\x84\x35\x67\xde\xc8\x4f\x92\x88\xe0\x85\xb0\x5a\xe4\xb8\xaf\x2c\xea\x5d\x9a\x18\x4d\x50\xbe\xf8\x55\x50\xc8\x36\x61\x3d\x5d\x3a\xf5\xf9\xc2\x92\x8e\x6a\x89\x66\x0f\xa6\x27\x19\xeb\xff\x77\x3e\x46\xb7\x7e\x34\xbc\x04\x70\xda\x4d\x2c\xdb\xc7\x07\x1d\xa7\x58\xc4\xd3\x9f\xe6\x52\x01\xc8\x8a\xaa\x8e\x66\x03\xd0\xbb\xe7\xc3\xe9\xb2\xd9\xe4\x1b\x63\x46\x82\x09\x2f\x14\x73\x41\xad\x6d\x66\x7f\x20\xc6\x4e\x81\xa6\x8d\x62\x94\x67\xa5\x4d\xd8\x6e\x1c\xe1\x2c\x56\x0a\x6f\x9b\x64\x51\x2d\x6f\x38\x86\xcb\xb9\xf3\x7c\x37\xeb\x39\x85\xc8\xac\x38\xdd\x66\x82\xf4\x8f\xe1"}, -{{0xfa,0x1e,0x11,0xdc,0x83,0x64,0x20,0x8d,0x8e,0x1c,0xb6,0x6a,0x36,0x1b,0xe7,0xe8,0x4c,0x5e,0x36,0x81,0x66,0x58,0x7d,0x4f,0xdb,0x06,0xac,0xed,0x7f,0x62,0xe1,0x7c,},{0x4d,0x8e,0x6f,0x4b,0x34,0x15,0xdf,0x6c,0xed,0xab,0xfb,0x29,0x5c,0x19,0x84,0xfd,0x41,0x99,0x23,0xc6,0xac,0x41,0x76,0x4e,0x32,0xd2,0x2d,0xaf,0x37,0x2c,0x50,0xfc,},{0xe8,0x57,0xdb,0x08,0x7e,0x28,0xd6,0x75,0x0b,0xf5,0x4e,0x53,0x79,0x72,0x51,0xd8,0x43,0x99,0x89,0x57,0x6c,0x12,0xda,0x2d,0x9c,0x81,0x1a,0x14,0x87,0x7c,0x3b,0xd4,0x6c,0x4e,0xfa,0xb8,0x61,0xa1,0x0e,0xeb,0xe7,0xda,0x04,0xc0,0xb0,0xb4,0x45,0xc7,0xa3,0x90,0xa5,0x0c,0x13,0xde,0x36,0xf3,0xa3,0xc7,0xae,0x01,0x57,0x02,0x2c,0x0e,},"\x29\x4e\x63\xba\xcc\xcb\x80\x1b\xbf\x04\xc1\xf1\x9d\x0a\xee\x16\xf5\x65\x0a\x6e\x8e\xea\x6f\xe4\x11\x10\x66\x3e\xc0\x15\x32\xbd\x49\x60\xa5\x27\xf1\x5e\xca\x4a\xf2\xf4\xe6\xb7\xb0\xfc\x34\x0c\xf9\x7a\xa2\x34\xe9\x2c\xf7\xd6\x9d\x50\xe4\x00\x9c\x24\x96\xe3\xed\x4d\x9a\xff\x00\x0f\x9e\x18\x52\x75\xb8\x17\xd2\x6a\x0b\xab\x69\xb7\xf7\xee\x1e\xa3\x0d\xae\xc8\xbc\xee\x38\x7a\xe4\x6b\x4b\x29\x9c\x27\xbd\xc0\x6e\xea\x63\xf2\x4d\xbe\xe9\x55\xa6\xc0\x96\x90\x37\xee\xf9\x1c\x34\x32\x1e\x3c\x5c\x97\x2f\xde\x99\x31\x83\xb7\xd2\x3f\x6e\x01\x9c\x3e\x0c\xac\x75\x89\xae\x4a\x15\x21\xaf\x87\xea\x42\xdf\x8c\x22\xc2\x27\x0e\xc2\x3d\x6d\x14\x0f\x9c\xf6\xd4\xd5\x2f\xac\x1b\x9d\x6c\x89\x39\xef\x81\x31\xcb\x62\xa0\x35\xc5\x26\x15\x38\xbc\xdf\xd6\xdb\x41\x9a\x55\xef\x9f\xe5\xd7\xa5\xac\x44\x57\x9d\xe7\x00\x85\x8d\x74\xa3\x43\x48\x44\xf2\x83\x42\xc5\x65\x89\x27\x22\xe2\x7f\x40\x7d\x7f\x17\xb7\x4a\x59\x34\xbe\x91\x5b\x20\xc2\x40\x06\x43\x23\x5f\x8a\xb5\x79\x5f\x32\x4e\x33\xc5\x06\x44\xa0\x40\x33\x54\x2c\xb3\x81\x6d\x77\x0f\xa8\x99\xe7\x31\x1c\x14\x30\x1c\x1b\xd0\xf5\xaa\x60\xa2\xeb\x31\x65\x68\x0c\x72\x0e\x1e\xfa\x80\x96\xfc\x25\xd2\x77\x92\x75\xf1\x84\x2b\x2d\xb5\x3b\x4d\xa0\xad\x3e\x59\xc0\x75\x40\xc2\x84\x60\xce\xc1\xfd\xd3\xcd\xb7\xa3\x47\x8b\x91\xa9\xca\xf9\xac\x89\x1c\xdf\x3a\xea\xee\xca\x9a\x96\x56\xac\x13\x07\x25\x99\x22\xfc\xa7\x4c\x5c\xc6\x9f\x7e\x25\xc6\xbf\x58\x79\x73\xa4\xb7\xd3\xe3\xac\x06\x35\xb0\xdb\x22\xa0\x09\x3a\x79\x07\x68\x81\xc7\x17\x36\xee\x1d\x4d\x45\xf8\xed\x2d\x29\xa0\x67\x1a\x64\xe6\xca\x2f\x7a\x5e\xf4\x04\xb1\xed\xeb\x84\x20\x34\xf5\x71\xb6\x99\xbc\x59\xe5\xa3\x7d\xf0\x20\x54\xe8\x48\x2b\xf1\xe7\xb7\x7d\x8e\x83\x97\xda\x15\xd8\x9d\x73\x55\xa5\xdc\xe8\x6b\x16\x83\xa9\xac\x4e\x40\x6c\x08\xa9\x4a\x6e\xb0\x0e\x5a\xe1\x6d\x96\x72\x29\x72\xe5\xc5\x0c\x7b\xee\x4a\x84\xd0\x69\x7b\xbe\x67\xce\xb7\xef\x29\x5f\x06\xaa\xea\x5a\xbb\xa4\x44\x66\xbe\x0f\x67"}, -{{0x24,0xa9,0x14,0xce,0xb4,0x99,0xe3,0x75,0xe5,0xc6,0x67,0x77,0xc1,0xed,0x20,0x43,0xbe,0x56,0x54,0x9d,0x5e,0x50,0x2a,0x84,0x47,0x10,0x36,0x40,0x42,0xba,0x9a,0xcb,},{0x20,0xd2,0x1e,0xe7,0x64,0xb1,0xf3,0x5f,0x94,0x56,0x82,0x00,0xd6,0x3b,0xd5,0x82,0x8a,0xca,0x8c,0x5d,0x3e,0x90,0x47,0xd2,0x3f,0x47,0x8b,0x92,0x52,0x95,0xfa,0x2e,},{0x3a,0xe0,0xcc,0x7b,0xca,0x8d,0x73,0xbe,0x83,0xa9,0xb8,0x09,0xb1,0x33,0x38,0xc1,0x27,0x06,0xaa,0xef,0x75,0xc4,0xd1,0xa4,0x78,0x17,0x8f,0x9d,0xc5,0x65,0x51,0x4c,0x75,0x29,0xe2,0x98,0x04,0x3e,0xa7,0x8d,0x21,0xa5,0xa0,0x9d,0xd0,0x4f,0x10,0xae,0x87,0x44,0x1e,0x56,0x86,0xa9,0x33,0xc9,0x2c,0x75,0x54,0x84,0x27,0xad,0x3a,0x03,},"\x3f\xf9\xf6\x6f\xa2\x64\x6e\xc6\x6a\x1b\xf9\x33\xc2\xb4\xcc\x0f\xbf\x91\x2b\x4d\x6d\xb5\x05\x34\x25\x7f\x97\xd0\x1e\x69\x8d\x05\x48\x57\x47\xde\x25\x44\xe9\xf5\xa4\xa4\xa0\x75\x38\x8c\xf4\x40\x0a\xb8\x9b\x03\x53\xce\x86\x19\x82\x02\xdb\x3a\x90\x37\x67\xb8\x79\xa2\xaf\x9d\xaa\x15\x58\x43\x11\x1a\xf1\x5a\x2b\xc3\x5e\xfe\x41\xbc\xc9\x2c\x82\x07\xe0\x01\x13\xb0\x4f\x13\x03\x00\x79\x49\xff\xb6\xce\x8d\xf4\xb0\xb3\x42\x48\xfe\xdf\x5d\x9c\xb2\xce\xe9\x4b\x81\x2e\xd5\x8e\xce\x2a\x0c\xe0\x45\x4c\xf1\x4c\x20\xe4\x9e\x09\xfe\x66\x4d\x6e\x25\x76\x2e\x87\x89\x59\x32\xcd\x5c\xd3\x2e\xb6\xa3\xab\xb3\x8e\xe1\x63\x07\x8c\x13\x3e\x93\x58\x87\x91\xdb\xf6\xaf\x49\x9a\x31\xea\x44\x53\xbb\xcc\x7a\x85\xe4\x06\xc9\x84\x8a\x66\x40\x52\xf1\x11\x13\xfb\xb4\xff\xa7\x60\xde\xe4\xc2\x61\xe3\x96\x94\x24\x91\x11\x9d\xa2\x9a\x33\x58\x2f\x82\x1d\x41\x25\xe0\xb4\x16\x2f\x28\xbe\xb0\x66\x03\x1a\x65\x2d\x05\x74\x9a\xa7\x24\x4d\xd4\xf3\xd3\xbb\x15\xd2\x68\x32\x8d\x6a\x02\xfc\xe2\x50\x18\x15\x25\x7f\x8a\xd5\xaf\x4e\xcb\xe7\xcb\x8a\xe9\x66\x1e\x34\x4f\x90\x72\x31\x87\x91\xf3\xe8\x59\x09\x11\x21\xe0\x8a\xef\xca\x89\x82\xea\xaf\x66\x25\x9d\x9d\xe4\xf4\x6a\x31\xe7\x16\xdc\x03\x3d\x0f\x95\xd1\xfa\x93\x6b\x6c\x60\x79\xb1\x37\xdd\x11\x58\xd1\xde\xf1\x13\x01\x8c\x73\xf8\xeb\xb9\x80\x7e\x0f\x74\x15\x40\x4e\xa9\xc7\x85\x44\xac\xe7\xce\x46\x3c\xd1\xd1\xc5\x7e\x31\xf4\x09\x1b\xc0\x91\x80\x4c\xbc\xdd\xad\x0e\x15\xa4\x0c\xa9\x1a\xcb\xe1\xc6\x22\x4e\xd1\x3c\xaf\xb4\xdf\x2c\x84\xac\x9f\x0c\x3c\x9b\x54\x60\x07\xd9\xdd\x6e\x52\x4c\x46\x70\x72\x56\x3d\x4a\xc0\xd7\x00\xcc\x1b\xf3\x0f\xeb\xb3\x34\x31\x3d\xae\x57\x61\x74\x5e\xc0\xa5\xe9\xe8\x81\x50\x25\x95\x8f\x00\xfa\x2e\x58\x06\x0d\x7e\x9a\x5f\x2b\x72\x7f\x48\x69\x9f\x92\x9c\x84\x59\x93\x08\x92\x57\x3f\x78\x4f\xef\x56\x92\x51\x8b\x5c\xa2\x68\xe2\xa7\x3e\xbe\xad\x6e\xbd\xeb\x7e\xc2\x4e\xac\x92\xaa\x7d\xcb\x41\xb5\x98\xbd\x6e\xff\x36\x32\xd0\x69\x72\x62\x91"}, -{{0x55,0x32,0xe0,0x9b,0x93,0x7f,0xfd,0x3d,0x5f,0x4c,0x1d,0x9f,0x1f,0xfc,0xde,0xd2,0x6e,0xe7,0x4d,0x4d,0xa0,0x75,0x26,0x48,0x44,0x69,0x0b,0xd9,0xc8,0x61,0x39,0x94,},{0x50,0x93,0x96,0x9f,0x37,0x7b,0xec,0x3e,0x35,0xf5,0x9e,0xfd,0xa0,0x1a,0xb4,0x18,0x6c,0x5d,0x2a,0x36,0x74,0x0c,0xf0,0x22,0x67,0x5e,0x01,0x09,0x6b,0x1a,0x3f,0x0a,},{0xd5,0x27,0xff,0x0d,0x4a,0x21,0x9d,0x61,0xf4,0x18,0x12,0x12,0x06,0xa5,0x4a,0xe4,0x98,0x58,0x54,0xa3,0x10,0x48,0x27,0x44,0x48,0x6e,0x4d,0x13,0x0a,0x7d,0xe9,0x7c,0x31,0x9d,0xf8,0x37,0x2c,0x82,0x82,0x8c,0x93,0x6e,0x6a,0x8a,0xfd,0x9c,0x5d,0xe1,0x82,0x85,0x73,0xd8,0x26,0x1a,0xe9,0x36,0x5b,0x8f,0x23,0x76,0x76,0x18,0x24,0x02,},"\xad\xd4\xd7\xa9\xce\x3f\x63\xd1\xf9\x46\xe8\x67\x90\x65\x54\x5d\x8c\x7b\xf0\xa2\xcc\x3a\x4c\x00\xb8\xf1\x42\xf0\x94\x5a\xe3\x62\xc4\xc9\x46\x2a\x75\x76\xa4\x05\x9d\x57\x86\x16\x62\x88\x4b\xd8\x0b\x96\xd9\x0d\x27\x9a\x95\x2e\xda\x95\x2d\x37\xd4\xf9\x5c\xf0\xd7\x0d\xa9\x8f\x4f\xba\xca\x39\xe1\x69\xf9\xd9\x45\xd4\x1f\x87\x23\x97\xbb\xdd\x57\x01\x45\x43\x03\xd7\x7d\x31\xe8\x63\x48\x27\x1d\xa4\x0a\x1b\x8f\x1e\x57\xc3\x6f\xcd\x80\x3e\x14\xfa\x17\x71\x6c\x56\x31\xef\xa0\x1d\x3a\x79\x5d\xc2\x0b\x2b\xde\x36\xab\x73\xff\x6a\x2d\x53\x3b\xc1\x5c\xce\x22\x32\x87\x13\xc3\xc9\xcc\xd0\x72\xc3\xe4\x50\xd7\xf2\x2c\x0c\x9f\x94\x91\x97\x52\xcb\xfe\x45\xee\x65\x5d\x1b\x53\x67\x65\x93\xcd\xb4\x48\x70\x41\x02\x63\x1c\xaa\xa9\x76\x95\x2e\xaa\x1f\x6c\x2e\x87\x65\x64\xe4\x20\xf0\xc6\x46\xa0\xf8\x83\x65\xf7\x64\x15\xb4\x08\x5f\x60\xa3\x38\xb2\x9c\x51\x63\x3e\x54\x0f\x0b\xf3\x2d\x40\x87\xe7\xd0\xfb\x68\x5b\xe8\x8c\x75\x95\xdc\x53\x1c\x99\xb4\x89\x58\x45\x60\xad\x82\x34\xb1\x8e\x39\xa1\x07\xcf\x5d\x84\x2d\xab\xd4\x21\xe7\x7d\x26\xea\x5e\x0f\x14\x05\xce\x35\xfe\x79\x27\x14\xeb\x4e\xe1\xa8\x01\x76\x48\xac\x1a\xe7\x39\xa3\x3d\x7b\x1e\x08\x91\x05\xd1\xe5\xad\xd2\x7a\x62\xce\x64\x15\x45\x70\x34\x0a\xf9\xeb\x14\xe7\xfd\xfc\x2f\x9a\x2c\x2f\xcf\xcd\xac\x3c\xc4\x22\x77\x63\xf4\xd6\x29\x49\x74\x79\xf8\x49\x21\x6e\x5d\x90\xec\x16\xdf\xa3\x6b\x72\x51\x7f\x7b\x54\x86\xba\xee\x7f\xda\x44\x50\xc3\x52\xcf\xfb\xba\xe7\x39\x26\xc8\x43\x22\x4f\x8c\xe4\x4b\x38\xda\xe5\x3f\x3e\xad\x21\x89\x0b\x52\xa7\x80\x10\x75\x29\x16\x84\xfd\x59\x10\xed\x86\xad\x33\xe8\xa0\x07\xf6\xc3\xf8\x5c\x16\xb2\x09\x29\x37\x40\x18\x4f\x58\x90\x87\x4d\x43\x1c\xd4\xe0\xea\x40\x87\xc4\x9c\x34\x71\xd7\x89\xc8\x13\xc6\xdc\x9a\x78\x69\x93\x63\xa1\xd8\x71\x97\xd3\xb9\x2c\x02\x86\x68\x93\x11\x82\x3f\x4d\xf2\x2c\xe8\x03\x5e\x75\x73\x2c\xde\xa7\xf5\x62\x1f\x67\xdb\x0e\x2a\x4c\xa6\x61\x61\x93\x22\x1c\x0a\xa3\xd6\xde\x50\xd8\x52\x82\xee"}, -{{0xeb,0x36,0x51,0x10,0x09,0xd3,0x7a,0x9c,0x46,0xc4,0xd1,0x37,0x4d,0x0b,0xbd,0x0d,0x99,0x81,0xe7,0x8c,0xee,0x7d,0x18,0x8c,0x5a,0xab,0x98,0x3e,0xc2,0x39,0xe1,0x0c,},{0xb1,0xcc,0x21,0x2b,0x45,0x21,0xbb,0xe7,0xb1,0x9a,0x76,0x93,0x87,0x8a,0x55,0x84,0x40,0xee,0xc3,0x62,0x05,0xd8,0x43,0x9d,0x04,0x0a,0x46,0xa9,0x90,0x2f,0xbf,0x55,},{0x9f,0x58,0x37,0x24,0xde,0x55,0x2e,0xae,0x82,0xf2,0x54,0xac,0x6e,0x2e,0xd4,0x83,0xec,0x1a,0x07,0x34,0x62,0x66,0x73,0x5c,0x49,0x09,0x20,0x69,0x0c,0x1e,0x3f,0xb2,0xa9,0xe9,0xa3,0x41,0x94,0xed,0x64,0x73,0x73,0x3b,0x30,0x0d,0x4f,0x23,0xc9,0xae,0xc0,0xda,0x5a,0x20,0x22,0x05,0x4c,0xa4,0x38,0x85,0xa1,0x5a,0x29,0x84,0x32,0x0e,},"\xba\x24\x66\xe5\x6c\x1d\xf7\x7f\x22\xb6\xf0\x24\x1f\xc7\x95\x2a\xe9\xbc\x24\x75\x64\x19\xa9\x44\x6d\xd2\xb4\x9e\x2c\xb9\xdf\x59\x4e\x5b\x6c\x77\xa9\x5a\xa5\xfb\xd9\xdc\x57\xfe\xc8\x39\x62\xc7\x75\x1e\xeb\xb4\xba\x21\x82\x53\xf9\x16\xa9\x22\xa5\x13\x96\x63\xe3\x20\x3e\x3b\xe4\x82\xbe\x37\x9c\xa1\x51\xc4\x63\xd9\xad\xa2\x14\x46\x13\x5f\x35\x69\x94\xfa\x54\x49\xf0\x84\x47\x8f\x5b\xb4\xf5\xba\x61\x45\xc5\x15\x8e\xb7\xb1\xc4\x3c\x32\xeb\xea\x25\xe0\x9c\x90\x0f\x01\xef\x91\xe9\x2f\x88\xc0\x3c\x76\x50\x4a\xce\x96\x46\x01\x6f\xfc\x27\x89\x55\x9d\x0f\x3c\xc9\xd0\x0f\xb6\x1b\xdc\x6a\xf7\xd3\x94\x0f\x30\x2e\x58\x8e\x04\xf7\x9f\x7b\x3d\x4b\x91\xa5\xd1\x93\xa4\xf8\x22\x2b\xfe\xb6\x9b\xf0\x34\x7d\x98\xad\x81\xef\x99\xd1\x30\xeb\xc7\xb3\x6b\x07\x83\x39\x4e\xea\x92\xa3\x8d\xdd\x5e\x74\x80\xd2\xad\xd4\xe4\xde\xf5\x3e\xb9\x9c\x44\x9b\xff\x94\xe4\x71\x8b\x09\xf2\xea\x9b\x1f\x2b\x88\x65\x94\xa9\x5c\x33\xa6\x9e\x03\x33\x15\x4e\x44\x0a\xb3\x4b\x7b\x6c\x11\x34\xd8\x17\x9b\x6f\x0c\x56\x25\x1a\x9a\xd8\xe1\xb6\xb0\xf9\xb8\xa5\xc9\x70\x81\xa7\xf8\xfd\x05\xd0\xb0\xaf\xfc\x82\xdb\xdd\xc8\xb0\xc0\xab\x7e\x83\x3f\x30\x06\x26\xd4\xb9\x73\xb3\xf6\x0f\xea\xc5\x55\x71\xe8\x9c\xda\x0f\x2b\x44\x1e\xd2\xfa\xa6\x69\xa7\x0d\x55\x6c\xb4\x8f\x9b\x1d\x1c\xbc\xe3\x2e\xde\x5d\x16\x6b\x11\x43\xe2\x64\xb1\x1e\xa3\x27\x68\x1c\xb5\x59\xed\xd1\x3c\x36\x4b\xd2\xba\xf1\xfd\x54\xbb\x78\x18\x07\xbd\x59\xc8\x68\xb0\xe4\x79\x5a\x77\x9e\x67\xf0\xbd\x0d\x14\xb5\xa6\xb9\xe4\x40\xb5\x7a\x58\x23\x32\x8b\x59\xaf\xfb\xd0\x27\xed\xa7\xdd\x78\x50\x79\xc5\xf0\x2b\x5e\x32\x89\x0b\x03\x87\x30\x98\x6a\x39\xa5\xa9\x83\x4a\x3f\xed\x86\x8b\x6f\x45\xcb\xdd\x28\xac\xb2\x70\x9a\xff\x55\x62\x63\x86\x4f\x9a\xe1\xe7\x57\xb3\x27\x8c\x28\x8d\xbe\x29\x32\x82\x57\x12\x77\x3e\x43\x1f\x7c\x29\x32\x98\x57\xfd\xae\xa7\x98\xed\x93\x92\x08\x93\x63\x14\x02\xe6\xb1\x3b\xab\x62\xb4\x85\x54\x61\xed\xb9\x46\x20\xf2\xd1\x75\x18\x65\xf4\x45\xc4\x66"}, -{{0x7d,0xbc,0x81,0x90,0x2e,0x4e,0xaa,0xb3,0x07,0x75,0x40,0xf5,0x59,0x99,0x5c,0x38,0x74,0x03,0xca,0xc3,0x06,0xd4,0x86,0xe9,0x59,0xc5,0xeb,0x59,0xe4,0x31,0xc0,0xa8,},{0xe0,0x30,0x66,0x13,0x90,0x82,0xf6,0x13,0x44,0x8b,0xdb,0xc2,0x7f,0xe5,0x3a,0xa3,0xf8,0x89,0x94,0xc3,0x1d,0xdc,0xe0,0x02,0xe3,0x6b,0xbb,0x29,0x63,0xdf,0x3e,0xc8,},{0x5b,0x7f,0x65,0x2f,0x08,0xf2,0x29,0xfd,0xa1,0xb0,0xbd,0x75,0x93,0x77,0xb3,0xfb,0x72,0x6c,0x1b,0x9c,0x9a,0x10,0xef,0x63,0x42,0x6d,0x35,0x2d,0xd0,0x86,0x9b,0xd5,0x4d,0x87,0x6c,0x30,0x92,0xf1,0xcd,0x41,0x1c,0x37,0x57,0xd3,0xc6,0xb6,0xea,0x94,0x2a,0xa7,0x0c,0x3a,0xae,0xb4,0x21,0x7a,0x4c,0x73,0x64,0xd1,0x8e,0x76,0xe5,0x0f,},"\xdf\xf7\x98\xb1\x55\x7b\x17\x08\x5a\x06\x34\x37\x1d\xed\x5d\xdf\x7a\x5a\xcb\x99\x6e\xf9\x03\x54\x75\xe6\x82\x63\x36\xf6\x4a\xd8\xb8\x4b\x88\x2e\x30\xba\xde\xc2\xb4\xa7\x11\x99\x87\x52\xf4\xa1\x57\x4b\xc1\xf8\x9d\x43\x25\xcf\x2b\x39\x86\x10\x44\xdd\x03\x69\x1e\x71\xd0\x77\x68\xb5\x93\x3a\x30\x52\xcc\x7c\x81\xd5\x71\xa9\xde\x06\x1d\xc1\x90\x26\xc2\xf1\xe7\x01\xf2\xdc\xf2\x6a\x88\xd3\x40\x1b\xc9\x9f\xb8\x15\x59\xdc\xa7\x6d\x8a\x31\xa9\x20\x44\xa2\x73\x58\x7d\x62\x2a\x08\xd1\xcc\xe6\x1c\x8f\x94\x8a\x34\xde\xd1\xac\xb3\x18\x88\x1c\x9b\x49\xf6\xf3\x7c\x30\xa6\x5d\x49\x5b\x02\xd5\x42\x9e\x7a\xb4\x04\x0d\x8b\xeb\xeb\x78\x79\x4f\xf7\x36\xd1\x51\x10\x31\xa6\xd6\x7a\x22\xcd\xf3\x41\xb9\x80\x81\x1c\x9d\x77\x5f\xb1\x9c\x64\x78\xf0\x5e\xd9\x84\x30\x10\x3e\xa2\x4c\x0f\x41\x4d\x4c\xc0\x7d\x86\x0b\x72\xdc\x54\x2f\xf2\x2d\x83\x84\x5a\x42\xf8\xba\x45\xca\x7f\xf3\xaa\xb0\xb1\xe7\xde\x2b\x10\x94\xde\xac\x08\xd1\x6e\xee\x01\x96\x9f\x91\xbc\x16\xfe\xc2\x9c\xcc\x06\x1c\x54\xdb\x53\x45\xba\x64\x84\x2d\xac\xc9\x9e\xe7\x72\x94\x68\xd8\x0a\x3f\x09\x55\x83\xd8\xe8\x01\x24\x08\x51\x9d\x58\x2c\xc3\xff\x9a\x2e\xb7\xae\xba\xa2\x2d\xb8\x1f\xfc\x78\xee\x90\xef\x4e\xc5\x89\xdc\xce\x87\x11\x8d\xab\x31\xa6\x32\x8e\x40\x9a\xd5\x05\x9a\x51\x32\xc8\x2d\xf3\xce\xfe\x2e\x40\x14\xe4\x76\xf0\x4c\x3a\x70\x18\xe4\x52\x67\xec\x50\x18\xec\xd7\xbf\xf1\xdd\xa9\x26\x7e\x90\x66\x6b\x6b\x14\x17\xe8\x9d\xda\xcb\x50\x85\x94\x3b\xef\xc7\xad\x2f\x4d\xf5\xf1\xee\x0a\xf9\x43\x1a\xee\xb6\xb2\x4a\x55\x15\xb9\x3d\xbc\xf6\x86\x40\xf7\xda\xf8\xc9\x61\xe5\x67\xd7\x53\x49\x00\x20\x5c\x3d\xf2\x18\x4b\x6a\xc2\xda\x96\x1c\x4c\x1d\x2b\xc4\x9b\x4e\xa9\x6b\x81\x54\xff\xd4\xef\xff\xdc\x5e\x55\xa7\x11\x9c\xb8\xaf\x42\x9e\x85\x10\x5d\xff\xd4\x1f\xe4\xa2\xeb\xba\x48\x16\x8a\xa0\x5f\xa7\xdf\x27\xc4\x29\x87\x35\xff\x86\x8f\x14\x96\xbe\xb4\xb2\xed\x0b\x89\x80\xc7\x5f\xfd\x93\x9d\xdd\x1a\x17\xe4\x4a\x44\xfe\x3b\x02\x79\x53\x39\xb0\x8c\x8d"}, -{{0x91,0xb0,0x95,0xc8,0xa9,0x99,0xe0,0x3f,0x3e,0xd7,0x49,0xcd,0x9f,0x2f,0xaa,0xcc,0x00,0x76,0xc3,0xb4,0x77,0xa8,0x7a,0xb5,0xcc,0xd6,0x63,0x17,0x38,0x76,0x74,0x46,},{0xda,0xd1,0x74,0xd3,0x59,0xda,0xec,0xca,0x9c,0x6b,0x38,0x9b,0xa0,0x96,0x45,0x2a,0xb5,0xca,0x91,0xe6,0x38,0x3c,0x6d,0x04,0x2a,0x28,0x4e,0xce,0x16,0xba,0x97,0xb6,},{0x64,0xee,0x9e,0xfd,0xb0,0xc2,0x60,0x1a,0x83,0x5f,0x41,0x85,0x20,0x64,0x1e,0x43,0x6c,0x7d,0xd4,0x7c,0x33,0x3d,0x9f,0xc3,0x0c,0xfb,0xb9,0xe3,0x90,0xfe,0x76,0x45,0x30,0x65,0x47,0x08,0xb4,0x0b,0x03,0x58,0x18,0x99,0xa9,0xac,0x87,0x0e,0xfd,0x76,0x6f,0xfb,0xb4,0x63,0x71,0x52,0xf8,0xff,0x27,0x79,0x64,0xfe,0x35,0x42,0x52,0x09,},"\x9b\x0d\x8b\x00\x29\x98\x52\xd6\x8b\xbf\x49\x7f\xe6\x03\x96\x1a\x48\x54\x66\xa9\x9a\x54\x84\x00\x5d\xb7\x3d\x4e\x4b\xad\x81\x4e\x85\x74\xef\xd5\x4d\x64\x8b\xd5\xc9\x1a\xe8\x48\x3c\x54\xb2\xf9\x98\xb0\x2e\x1a\xbd\x6f\x40\x1a\x25\x52\x68\x43\xa5\xf2\xa2\x3a\x97\xbd\x58\x9d\x1f\x7e\x1a\xb1\x49\x15\xb1\xe3\x59\xa3\x96\xd3\x52\xc3\x60\xae\x65\x84\x32\x5a\xe4\xbb\x7d\x62\x4f\x61\x25\x5c\x5c\x7b\xf0\xa6\x7a\xca\xb4\x6c\x3b\x57\xb3\x45\x34\xc0\xee\x84\x31\xd2\x60\x57\x66\x06\xcb\xd8\x4d\x8d\x18\x39\xe7\x3d\xa6\xfe\x4b\x0b\x8b\x78\xf0\xf9\x58\x82\x7c\x2f\x1d\x93\xba\x7a\x34\x6d\xcc\x75\xcb\x56\x3d\xff\xde\x26\xf9\x97\x59\x8e\x8b\x5c\x2f\x16\x17\xc6\xfe\xfc\x9b\xe4\xb2\x8b\x54\x01\xb0\x00\x64\x13\xa2\x51\x69\x0d\x12\x03\xaa\xae\x4f\x6d\x8a\x3f\xb2\x1f\x24\x00\x9a\xb3\xbf\xf1\x37\x37\xa8\xa7\xe6\x64\x6c\x02\x73\x2d\x9e\xc5\xa4\xa5\x10\x46\x9e\x2d\x29\x9e\x4c\xc1\xad\x64\x80\xa4\x82\xaa\x95\x6f\x89\xdd\xcc\xcc\x64\xa1\x36\xfb\x15\xb8\x76\xb6\xec\xd8\x8c\x7c\x86\xa4\xdf\xc6\x0e\x66\x62\x07\xc6\x04\x16\x7d\x16\x34\x40\xca\x9a\xb9\xcf\x87\xa5\xe0\xf7\xbb\xc5\x51\x7d\xe4\xde\xe8\x76\xc0\x37\xf8\xcc\x9d\x95\x9c\x8f\xf5\xdb\xe9\x44\xff\x54\xcd\x91\xa7\x71\xe2\x92\x31\xf8\xb5\xf1\x7d\x61\xde\x90\x4c\x95\x5f\xe2\x02\x5d\xc5\x2e\xd4\x80\xfb\x3c\xc9\x0f\x23\x24\x59\xc6\x07\xef\x7e\x2a\xdb\x52\xc7\x48\x2b\xec\xd6\x7a\xd2\x14\x9a\x41\x28\xf9\x84\x03\x8b\x58\xaa\x90\x17\x67\x82\x39\x36\x04\xaa\xc7\x4c\x18\x20\x9a\x3d\x6a\x78\x63\x0c\x01\x95\x5a\x7c\xec\xe5\xda\x83\x84\xda\x3b\xaf\x63\xaa\x2d\xdf\x59\x63\xfa\xe0\x5b\xa3\xb8\x1c\x6a\x03\xd8\x6a\x00\xef\x78\xed\xb4\x18\x4f\xdc\x89\xb1\xd6\xbf\xeb\x31\x0f\xd1\xb5\xfc\xce\x1e\x21\x95\x24\xa3\xcf\xb2\xe9\x72\x57\x7f\x06\xb1\xdd\xde\xba\x00\x86\x5d\xae\x49\x79\x00\x0c\x00\x8a\xd9\x9f\x3b\x63\x8c\xce\xb8\xe8\xc7\xa0\xf9\x98\xd3\x4d\x92\x14\x3d\x81\xc0\xe1\xc0\x96\xa9\x25\xce\xba\x65\xc4\x30\x03\xee\x18\xd4\x94\xd0\x03\xe9\xc6\x1f\x77\xd6\x57\x59"}, -{{0x8c,0x56,0x8b,0x31,0x0a,0xce,0x7d,0x1f,0x0e,0xde,0xce,0xfd,0x60,0x3a,0x88,0x40,0x00,0x54,0x4c,0x79,0x25,0x65,0xd4,0x81,0xc3,0xd3,0xe0,0x6e,0x2d,0x82,0xca,0x96,},{0x5f,0xa6,0xe2,0x67,0xc7,0x66,0x73,0x68,0x41,0x41,0x10,0x72,0xd1,0x98,0x3d,0x19,0x00,0xac,0xf0,0x1d,0x48,0xc3,0xce,0x11,0x77,0x0b,0x26,0xf7,0x8d,0xa9,0x79,0xf7,},{0xde,0xbd,0xd8,0xe5,0xd3,0x11,0x2f,0xd7,0x7b,0x39,0x4a,0xa0,0xe3,0x6e,0x94,0x26,0xba,0xc9,0x1d,0xf1,0x26,0xfa,0x9c,0x31,0x7c,0xea,0x7c,0x9d,0x45,0x95,0x7c,0xdd,0x96,0xa4,0x5a,0xe3,0xad,0x76,0x04,0x13,0xee,0x12,0x05,0xaf,0xd7,0x1a,0x29,0xf9,0xc3,0xcb,0x58,0x6c,0xd2,0xd7,0xcd,0x1e,0x93,0xbc,0x16,0x52,0xfc,0x34,0xdc,0x04,},"\xb5\x9f\x5f\xe9\xbb\x4e\xcf\xf9\x28\x95\x94\x72\x1f\x26\x47\x04\x7b\x0d\xa5\xe0\xe4\x94\x1b\xbe\x57\xc5\xb7\x22\xb4\x76\x72\x3f\x0a\xc5\x97\x0b\x41\x11\xf8\x93\xbc\xaa\x41\x1f\x28\xfc\xeb\x4f\x58\x5a\x2a\x71\x87\x01\x8a\x90\x4b\x70\xef\x8f\xe1\xf6\x56\x9a\x54\xd0\x0a\xda\x37\xb6\x9c\xb5\xe9\xc9\xd2\x6c\x16\xa9\x03\x51\x81\x48\xe0\x4a\x1b\x93\x6a\x32\x32\x9c\x94\xee\x1a\x8f\xb6\xb5\x91\x89\x2c\x3a\xff\x00\xbf\x6e\x44\xdd\x0a\x76\x2b\xab\xe8\x9d\x70\x60\xc1\x7b\x90\x39\x0d\x23\xbf\x9d\x36\x0a\x29\x3b\x83\x08\x38\x30\x86\x91\x6e\x11\x82\xb1\xba\x43\x36\xf0\x01\xb8\xd2\x0d\xea\xe9\xa0\x29\xf7\xe8\x53\x97\xa9\xae\x5c\xf3\xca\x10\xc7\xf3\x87\x55\x88\xb8\xff\xab\xb0\x63\xc0\x0c\xa2\x6f\x58\x0f\x69\xed\xc5\x27\xa1\xac\xcf\x4f\x41\x39\x7b\x33\x76\x6b\xcf\x6d\x55\xeb\x8d\xe0\x81\xa4\x8c\x98\x1d\x05\xc0\x66\x61\x7b\x80\xd8\xf6\xf5\xe6\x0e\x59\xdd\x9b\x93\x0b\xc4\xd0\x45\x86\x40\x3b\xb8\x68\xdf\x75\x93\x3b\xdd\x86\x23\x0e\x44\x70\x36\xc1\x75\xa1\x0d\xe9\xbb\x39\x95\x3d\xcb\x19\x66\xa1\xf1\x19\x12\x07\x8e\x35\x8f\x48\xc5\xb2\x09\xa6\x36\xc7\xf7\x83\xf4\xd3\x6a\x93\xad\x2c\xc2\xe3\x24\x45\x19\x07\x8e\x99\xde\x1d\x51\x58\xb3\x96\x1e\x0f\xc5\xa4\xf2\x60\xc2\x5f\x45\xf5\xe8\x58\x5e\x60\x1d\xb0\x8b\xa0\x58\xd2\x90\x9a\x1b\xf4\x99\x5f\x48\x13\x46\x0d\x36\x95\x03\xc6\x87\x36\x85\xeb\xcd\x33\x30\xa1\x30\xb7\x5f\x23\x65\xfb\x2a\x5a\x34\xea\x63\xd9\x58\xa2\xa8\x67\xe9\x05\x52\xd2\xce\xc8\xc3\x90\x08\x4b\xe0\xc1\x08\xb0\xfd\x2d\x83\xcb\x92\x84\xdb\x5b\x84\x2c\xbb\x5d\x0c\x3f\x6f\x1e\x26\x03\xc9\xc3\x0c\x0f\x6a\x9b\x11\x8e\x1a\x14\x3a\x15\xe3\x19\xfd\x1b\x60\x71\x52\xb7\xcc\x05\x47\x49\x79\x54\xc1\xf7\x29\x19\x9d\x0b\x23\xe5\x38\x65\x40\x3b\x0a\xd6\x80\xe9\xb4\x53\x69\xa6\xaa\x38\xd6\x68\x5a\xbd\x39\x7f\x07\xfb\xca\x40\x62\x7e\xca\xf8\xd8\xd3\x01\x33\xa6\xd9\xd5\xaf\x00\x91\x92\x75\x1c\x9c\x45\xf7\x7c\x0b\xc0\x11\x26\x88\x00\xbf\x55\x25\x12\x73\x0e\x69\x97\x3c\x5b\xf3\x62\xab\x16\x48\x94\xbf"}, -{{0x3d,0x09,0xaf,0xce,0xe3,0xc4,0x32,0xfd,0xfb,0x6b,0xdc,0xea,0xd5,0x4e,0x3d,0xa5,0xb1,0xb4,0x16,0x5c,0x50,0xd6,0xd3,0x10,0xb7,0xfa,0xd7,0x87,0xb4,0x44,0xd6,0x80,},{0xb0,0xd9,0x02,0x8c,0x4d,0x14,0x87,0xd2,0x93,0xed,0x58,0x5a,0x76,0xbc,0x94,0xff,0xfb,0xaf,0xe2,0xc6,0x5d,0x98,0x0c,0x49,0x4e,0x14,0x1e,0x48,0x10,0xa3,0x5c,0xb9,},{0x89,0x73,0x9f,0xe4,0x41,0xca,0x0c,0xed,0x08,0xa6,0xeb,0x57,0x96,0xe9,0xbd,0xda,0x0e,0x74,0xfb,0x47,0x35,0x28,0xfd,0x49,0x07,0xed,0xb6,0x59,0xaa,0xb4,0x4d,0x33,0x43,0x22,0x90,0x46,0x71,0x63,0x68,0xfa,0xf8,0x8e,0x85,0xc1,0x64,0x4a,0xf6,0x6f,0xf2,0xdc,0xaf,0x0b,0x17,0xac,0x93,0xca,0x13,0x81,0x9f,0x3f,0x24,0x1d,0xd3,0x00,},"\x76\x71\x65\xca\xae\x0e\x57\x8f\x16\x53\x7e\x17\x50\xbe\x7d\xe8\x7a\x78\x9a\x51\xff\x2d\xe1\x18\x38\xf5\x64\xe2\x58\x0b\x23\x91\x36\x2d\x28\x68\xa5\xa4\x70\x8a\xf1\x5d\x2e\x2d\xb7\xb9\xbe\x39\xc1\x6a\xdc\xc1\x20\x0b\x34\xe6\xb4\xd4\x02\x7d\xdf\xfc\x1a\x2a\x35\x95\xe2\x9e\x85\x5e\xc5\x26\x1b\x20\xbd\x55\xc4\x28\xb0\x13\x09\xba\xdb\x59\xe2\xca\x3e\xdb\x96\x7f\xc2\xf4\xba\xc0\x72\x9d\xdf\x54\xfb\x6c\x20\x05\x7b\xdd\xa9\xe7\xaf\x7c\xbf\xc0\x92\xfb\xa8\x65\xfd\x32\x75\xb9\xd3\xbc\xb0\xc3\x46\xb9\x51\xd1\x70\xac\x9a\xa6\x50\xa8\x6d\xf4\x98\x55\xd4\x8a\x1b\x37\xce\x56\xc9\xf2\x73\x89\xf5\xc8\xb1\x5f\x5c\x2c\x90\x0c\x4f\x10\x7c\x06\x4f\x60\x3e\x4f\x86\x7e\xf2\xe9\xc1\x0a\x1b\x74\x21\x0e\x6b\x89\xbb\x01\x17\x93\xaa\x85\xde\xd4\x3b\x51\xb7\x49\xba\x7f\x70\x28\x7b\x6b\xc1\xb8\x94\x34\xdb\x8b\x8c\x8b\x5d\x73\xb2\x14\xb4\x1e\x36\xb5\x28\x00\x5b\xfb\xfe\x00\x2e\x21\xb1\x00\x6f\xb9\xd2\x4b\xab\xd7\x21\x06\xd0\x93\xe3\xc7\x09\x3b\x31\x38\xae\xa7\x19\xd6\x94\x79\x08\x46\x47\x49\x8c\xd6\xc9\xbb\xb7\x44\x50\x9c\xd7\xda\x8d\xd6\x1a\x62\x71\x00\xf0\x3c\x21\xe7\x50\xac\xb3\xfc\xf4\x63\x1d\x7c\x0f\x61\x81\x54\xd2\xe5\xfa\x66\x56\xfb\x76\xf7\x4c\x24\x79\x50\x47\xbb\xce\x45\x79\xeb\x11\x06\x43\xfa\x98\xe1\xf7\x76\xca\x76\xd7\xa2\xb7\xb7\xb8\x67\x81\x73\xc7\x73\xf4\xbe\x7e\x18\x2f\xd2\x4d\xd7\x62\x91\xac\x67\xd9\xf2\x6a\x28\xc5\xe3\xcb\x02\x5c\x68\x13\xa3\x78\xb3\x83\x22\x46\x42\xb4\xae\xfa\xd0\xc7\x6a\x65\x79\x51\x7b\x8f\x36\x07\x97\xdd\x22\x61\x3e\xe6\x82\xb1\x79\x38\x19\x50\xfb\x71\x60\x9a\x5f\xb5\x49\x4d\x2d\x57\xdc\xb0\x0f\x26\xd1\xe7\x29\x56\xf4\xd6\x67\x28\x30\xe0\x5c\x01\xb3\x77\x96\x77\xc0\x7e\xa0\x09\x53\xc6\xb8\xf0\xdc\x20\x4c\x8d\xbd\xcc\xb3\x81\xbc\x01\xb8\x9c\x5c\x26\x1d\xb1\x89\xab\x1f\x54\xe4\x6b\xc3\xed\xc4\xde\x5a\xd4\xf0\xeb\x29\xc0\xa1\x20\xe4\x37\xcd\x8f\x37\xac\x67\xd4\x8c\x7f\x0e\x73\x02\x78\x70\x8f\x02\xb5\x4a\xee\x62\xb7\x29\x52\xbc\x1c\x0e\xb4\x37\xca\x8b\xd5\x65\x54\x37"}, -{{0x41,0xc1,0xa2,0xdf,0x93,0x69,0xcd,0xc9,0x27,0x16,0x4a,0xa5,0xad,0xf7,0x75,0x71,0x36,0xab,0xe5,0x13,0x95,0x60,0x42,0x66,0x33,0x4c,0xc5,0x46,0x0a,0xd5,0x68,0x3e,},{0x40,0x55,0x78,0x34,0xcc,0xe8,0xe0,0x43,0x58,0x0a,0x42,0x72,0xa8,0x80,0x4d,0x4f,0x92,0x6e,0x88,0xcb,0x10,0xd1,0xdf,0x0c,0x5e,0x28,0xb9,0xb6,0x7e,0x1b,0x63,0xda,},{0xb8,0xb2,0x75,0x2a,0x09,0x71,0x96,0xc2,0x89,0x84,0x9d,0x78,0xf8,0x11,0xd9,0xa6,0x2f,0xc7,0x67,0x27,0x8f,0x0c,0x46,0x62,0x8b,0x52,0x1f,0x62,0xed,0x27,0x59,0xd7,0x44,0x62,0xa1,0x75,0xda,0x22,0x40,0x3f,0x15,0x02,0x04,0x45,0xca,0xe0,0x6d,0xa3,0xed,0x61,0xcc,0xa6,0x20,0x3b,0x70,0x06,0x36,0x2a,0x0e,0x19,0x89,0x63,0xd2,0x0e,},"\xb6\x4b\x14\xba\x77\xd2\x39\xe6\xf8\x1a\xbe\x06\x0a\xcc\xef\x85\xf0\x44\x2b\x65\x0c\x44\x01\x5e\xfc\x43\xa0\xaa\x2b\xa1\x0b\xf4\x8d\x30\x18\xb1\x95\x3d\xdf\xff\xbc\xda\x5b\xf3\xbb\xe0\xb6\xb3\xe4\xb0\xd9\xa3\x2c\x6b\x72\x5b\xbb\x23\x1e\x0a\x27\x04\x47\x1e\xe8\xbc\x1d\x59\x4f\x5c\x54\x22\x6f\x5d\xd9\xdf\xa1\x63\xcf\xc1\x45\x2c\x61\xf9\x3e\x4f\x81\x39\xab\x4c\xe4\x47\x6f\x07\xec\x93\x36\x61\xea\xe9\x1b\x6d\x50\x0b\xf5\x08\xac\x63\xe4\xba\xaf\x1f\xfc\x8f\x00\x07\xd8\x02\xe0\x05\xf1\xb4\xfc\x1c\x88\xbe\xe4\xd5\xe9\xe7\x63\x84\xf5\xa7\x04\x3b\xd6\x60\xcc\xe7\x1f\x3b\x67\xf0\x1f\x6a\xb8\x44\x29\x85\x31\xaa\xc7\x3a\x39\xd0\x45\x37\x00\x88\x85\x50\x05\xa0\x9c\x6d\x04\x23\x8e\xa4\x78\xdf\xac\xad\x1e\x6b\x22\xb2\xbe\x4c\x46\xb0\xd5\x9b\x1e\xba\x1f\x06\x0b\xf7\xda\x5d\x15\x66\xcf\x1f\xdb\x5c\x54\x3a\x33\x92\x6a\xf6\x3f\x01\xa0\xdb\x86\xe1\xa6\x71\x1c\x47\x3d\xc7\x95\xab\x28\x3c\x8d\x93\xfa\xcf\xb5\x70\x1f\xa2\xf2\xf6\xbb\x99\xf9\xb7\xe3\x74\x9b\x07\x1d\x58\x60\x7b\xe4\x4a\x70\x89\xbc\xb5\x03\xec\x14\x95\xb5\xfe\xed\xb3\x99\x96\x1f\xd3\x67\x7d\x74\x93\xea\xa3\xb3\xe9\xcc\x5e\x36\x42\xf4\x0d\x47\xde\x9b\xfe\xe7\xc2\x0b\x0e\x51\x9c\x4e\xb4\xa4\x0f\x4d\xa4\x46\xed\x6a\xc7\xaa\xca\x05\x3e\x75\x9c\x97\xda\xbe\x0a\x8e\xc2\xf5\x8e\x7f\x2f\x9b\x20\x72\x76\x2f\x9f\x79\x4a\x6a\x4e\x36\x06\x0b\x88\x72\xbd\x2c\x18\xd0\x6a\x85\xc2\xc1\x41\xa7\x82\x93\x77\x3e\xe8\xcf\xbf\x15\x4b\x99\x30\xcd\x39\xda\x31\xb4\x97\xe7\x37\xa7\x75\x0c\x90\xa1\x3f\x5a\xaa\x14\x7c\xd0\xdc\x43\x11\xf2\xe3\x49\x41\x25\x2e\xf1\x98\xb0\xc1\xf5\x08\x27\xe5\x6c\x9f\x16\xf5\x95\xac\xed\x6d\x2a\x69\x34\x65\x31\x49\x5a\x64\x99\x77\x4d\x36\x07\x66\xca\x9b\xe5\xed\x88\x81\xc0\xdb\x26\xed\x7c\x5e\x6f\xf3\xa4\xf9\xb7\x3c\xd8\xb6\x54\x64\x0d\xc9\x6b\xf4\x3b\xd4\x26\xa0\xf2\x8c\x9b\x25\xfa\x70\x4d\x62\xff\x02\x88\xfc\xce\xff\xaa\xeb\xd3\xea\x30\x97\xbc\xbb\xd7\x78\x42\x0e\xbc\x52\x0a\x41\x77\x30\xa1\xb5\xb3\xb8\xc9\x6c\xda\x9f\x4e\x17\x7d"}, -{{0xa0,0x06,0x11,0x48,0x94,0x67,0x12,0x2c,0x4c,0x16,0x4b,0xfb,0x6a,0x61,0x6e,0x6a,0x61,0x9b,0x9f,0x83,0xc4,0x36,0x72,0x06,0xb8,0x5d,0x3f,0xbe,0xc3,0x8c,0xd6,0x2c,},{0x57,0xab,0x58,0xba,0xbb,0x41,0xdc,0x0d,0xa0,0xbc,0xd5,0x06,0x05,0x9a,0xac,0x9f,0x46,0xec,0xa9,0x1c,0xd3,0x5a,0x61,0xf1,0xba,0x04,0x9a,0x9a,0xc2,0x27,0xf3,0xd9,},{0xc7,0x71,0xba,0x0a,0x3d,0x3c,0x4a,0x7b,0x06,0x4b,0xd5,0x1a,0xd0,0x5c,0x9f,0xf2,0x7f,0xd3,0x26,0x61,0x0f,0xbf,0xa0,0x91,0x83,0x03,0x9e,0x5e,0xdf,0x35,0x47,0x2d,0xde,0xd8,0xfc,0x22,0x75,0xbb,0xcc,0x5d,0xf1,0xbf,0x12,0x98,0x60,0xc0,0x1a,0x2c,0x13,0x11,0xda,0x60,0x2f,0xba,0xff,0xc8,0xb7,0x9c,0x24,0x9c,0x9c,0xc9,0x55,0x02,},"\x34\xdb\x02\xed\x75\x12\xbf\x8c\x67\xd3\x59\xe7\x20\x3a\x2e\xa4\x41\xe2\x0e\x72\x97\x66\xc1\x5a\xa0\x0f\xa2\x49\xa3\x51\x8f\xc2\x9e\xf8\x90\x5a\xa5\xb4\x67\x09\x58\xc6\xa4\x60\xd7\x7b\x3a\x80\xef\xcb\x47\x38\x59\xbb\xaf\xf8\x62\x22\x3e\xee\x52\xfe\x58\xac\xfd\x33\x15\xf1\x50\xf3\xc6\xc2\x7f\xf4\x8f\xca\x76\x55\x2f\x98\xf6\x58\x5b\x5e\x79\x33\x08\xbf\x59\x76\xba\xd6\xee\x32\x7b\x4a\x7a\x31\x32\x14\xb9\xae\x04\xb9\x65\x1b\x63\xcd\x8d\x9f\x5b\x3b\xec\x68\x9e\x0f\xd0\x00\xdd\x50\x17\x70\xdd\x0e\x99\xb8\xf9\x9e\xaf\xa0\x9c\x39\x6a\x24\x5a\x4a\x96\xe5\x68\x96\xa2\x9b\x24\x19\x0b\x1e\xf1\x10\x63\xf3\x9b\x63\xee\x3a\x58\x6b\x07\x62\x7d\xd3\x50\x0c\x4e\x17\x0b\x83\x5d\xc0\xec\x23\x6f\xa5\xa3\x5c\x44\x18\x47\x07\x56\x5c\x4a\x50\x66\x2d\x8d\xbc\xcf\xff\x7f\x9a\x7a\x68\xd0\x21\xb4\xaf\x64\xd5\x32\xb7\xc3\xd2\x74\x74\x18\xc2\xd7\x17\xbb\x6a\xca\x6b\x58\x74\x7a\xe4\xdd\x56\x41\xd8\x26\xf7\x9a\x8a\x31\x5c\x38\x21\x1a\x53\x8a\x92\x9e\x5b\x45\x1f\x62\x3f\x4f\xcb\xbc\xac\xdb\x86\xc8\x75\x2e\xa1\x3a\x61\x7a\xb4\x14\xab\x65\x3e\xb2\xe6\x8d\x54\x20\xdf\x7c\x6d\xf9\x24\x38\x16\x8d\xcf\x9c\x06\x65\x81\xdf\xe7\xb2\xc4\x68\x19\x4a\x23\x70\x7d\xe4\x65\x9b\xd6\x7e\xb6\x34\xff\x02\x47\x41\xc5\xfc\x86\x98\xfd\x4d\xc4\x1f\xe5\xdf\xc6\x29\x9b\x7a\x08\xe6\xff\xca\x37\x10\x9c\x02\x10\xc8\xf9\x4e\xa2\xd3\xdd\xc9\x77\xff\xc0\xb3\x79\x4f\xe6\xba\x43\x37\xc7\xaa\xb4\x34\xa6\x8a\xc6\x65\x48\x4e\xa8\x24\x3a\x84\xb7\x9a\xa1\x81\xee\x6a\xb5\xaa\x37\xa3\x2d\x87\x97\x25\xed\xc0\x18\xf8\x55\x21\x81\x81\x6d\x7d\x27\x2c\xa8\x81\x8a\x7b\x92\xe6\xee\x44\x54\xd1\xf7\x82\x8d\xd8\xaf\xba\x1a\x79\x03\x64\xb4\xff\x28\xd8\x4e\x02\x85\x97\x35\x3e\xbb\xef\x24\x83\x7b\xc3\x19\xe1\xae\x8f\x2b\x0b\x6a\x85\x1b\x48\x9c\x3e\x17\x0e\xef\x53\xe0\x65\xf7\x03\x26\x53\xcd\x6b\x46\xd8\xe5\x7e\x4e\x11\x1b\x78\x9b\xa9\x50\xc4\x23\x0a\xba\x35\xe5\x69\xe0\x66\x15\x40\x34\x07\xbc\xe0\x36\x9a\xaa\xb4\xea\xfa\xef\x0c\xae\x10\x9a\xc4\xcb\x83\x8f\xb6\xc1"}, -{{0xde,0x16,0x34,0xf3,0x46,0x0e,0x02,0x89,0x8d,0xb5,0x32,0x98,0xd6,0xd3,0x82,0x1c,0x60,0x85,0x3a,0xde,0xe2,0xd7,0xf3,0xe8,0xed,0xd8,0xb0,0x23,0x9a,0x48,0xcf,0xaf,},{0x9d,0xc1,0x46,0x5b,0x33,0x83,0xf3,0x7d,0xe0,0x0e,0xa2,0xd3,0xc7,0x0f,0x2c,0x8f,0xac,0x81,0x5f,0x01,0x72,0x02,0x9c,0x3f,0x57,0x95,0x79,0xc9,0x84,0xa5,0x89,0x5e,},{0xd2,0x05,0x06,0xeb,0x84,0x69,0x23,0xa0,0xb1,0x6f,0xf8,0x2f,0xb2,0xc3,0x92,0x3b,0x00,0xc1,0xb3,0xbc,0xc6,0xe2,0xf6,0x48,0x2f,0xba,0x24,0x80,0x75,0x21,0xe8,0xe0,0x22,0x3f,0x69,0x2e,0x62,0xea,0xc9,0x93,0xf4,0x98,0xf6,0x71,0x02,0xa0,0x4f,0xd1,0xac,0xf9,0xc7,0xe3,0x88,0x8d,0x85,0x7c,0x9a,0x08,0x0b,0x8a,0xf6,0x36,0x10,0x06,},"\xd1\x0c\x3e\x4d\xe7\xfa\x29\x89\xdb\xa8\x75\x37\xe0\x05\x93\xd0\xee\xd4\xd7\x5e\xe6\x58\x46\xda\xb1\x49\x8b\x47\x49\xd6\x4f\x40\xe3\x4b\x59\x11\xc5\xce\x3b\x53\xa7\xe3\x7d\x2d\x02\xbb\x0d\xae\x38\xed\x96\x2a\x4e\xdc\x86\xc0\x02\x07\xbe\xe9\xa8\xe4\x56\xec\xca\xe8\xbd\xf4\xd8\x7a\x76\x74\x60\x14\x20\x1a\xf6\xca\xff\xe1\x05\x66\xf0\x8d\x10\xda\xaf\x07\x71\x60\xf0\x11\xfe\xac\xa2\x5b\x9c\x1f\x6e\xca\x9f\xc5\x33\x14\xa8\x05\x47\x95\x17\x54\x35\x55\x25\x25\x7d\x09\xa7\xfd\xad\x5b\xc3\x21\xb7\x2a\xa2\x8d\x1e\x02\xd8\x69\x6d\x4f\x9e\xb0\xad\x3b\x21\x96\xf8\xbc\xfa\xeb\x1d\x61\x48\x28\x7a\x3f\xae\xfe\xf9\x1a\x7a\x3e\x06\x09\xc2\x8c\xe5\x9d\x0c\xa1\x4d\x0b\x30\x50\xdd\x4f\x09\x6b\x7b\xc2\x51\x39\x88\xba\x21\x21\x28\xd5\x02\x6d\xaa\xa7\x18\x88\x46\xdb\x21\xc5\xc1\xd1\x79\xab\x94\x87\xc1\xa5\xbd\x34\x65\x88\x12\x7c\x20\x39\x8d\x36\x2d\x4c\x75\x9c\xfa\xb2\xa6\x77\x75\x0b\x9e\x45\x67\x6a\x1e\x7e\x09\x2e\xf0\x2e\xdb\xf2\x78\xfb\x19\xa5\x8e\x9b\xf6\xc9\xe9\x96\xe2\x4e\xda\xd7\x3f\x3c\xe3\x1f\xa0\x4b\x6d\x85\x33\x43\x6b\xf8\x0b\x4b\x2f\x80\x5e\xd9\x1e\x7f\xcd\xa3\xbc\x2b\xab\x3b\x2b\xb1\x57\x15\x8a\xf0\xea\x8e\x3f\x07\x31\xdf\xad\x45\x9d\x2e\x79\xb6\xd3\x71\x5f\xe7\xbf\x1e\xaf\xc5\x39\x75\x93\x20\x88\x57\xe5\x7b\x7f\xeb\x2f\x73\x87\x94\x3a\x8e\x09\x13\x47\x0c\x16\x1a\xef\x4f\xe2\x05\xd3\x63\x7f\x23\x17\x7f\xf2\x63\x04\xa4\xf6\x4e\xba\x3f\xe6\xf7\xf2\x72\xd2\x34\xa6\x72\x06\xa3\x88\xdd\xd0\x36\x6e\x89\x4e\xaa\x4b\xb0\x5d\x73\xa4\x75\xf1\xb3\x4c\xa2\x22\xbb\xce\x16\x85\xb1\xb5\x6e\x03\x4e\x43\xb3\xc4\x0e\x81\xff\xf7\x96\x82\xc1\x9f\x32\xaa\x3f\x2a\x89\x5c\x07\x09\xf9\xf7\x4a\x4d\x59\xd3\xa4\x90\x29\xec\xfc\xb2\x83\x08\x2b\x06\x7f\x1a\x0d\x95\x05\x75\x0f\xd8\x67\x32\x19\x99\x48\x42\x49\xef\xa7\x25\xf5\x2c\x94\xc7\x59\x62\x06\xa9\x11\xf3\xf5\x05\xd6\x3f\x03\x13\x25\x4b\xd4\x45\xf0\x5b\xe3\x99\x6b\x58\xfe\x18\x19\xaf\x87\x35\x2e\x7f\x0a\x2c\xa3\x20\xd9\xcc\x00\xa5\xfe\x77\xad\x41\x64\x0d\x50\xbe\x84\x36"}, -{{0xc7,0x38,0xef,0x5f,0x09,0x35,0x28,0x1b,0xa6,0x25,0xfa,0x40,0x14,0xd4,0xa4,0xd0,0xbe,0x7e,0x28,0xfe,0xd7,0x79,0xa9,0xcf,0x65,0x8e,0x21,0xdb,0xa4,0x3c,0xeb,0xc1,},{0x95,0x79,0x9f,0xaf,0x70,0x6d,0x19,0x5e,0x54,0x4c,0x76,0xca,0xfd,0xdf,0x09,0xd0,0x2d,0x1b,0xea,0xfc,0x42,0xc9,0xd6,0xc9,0xea,0xd4,0xc1,0x84,0x55,0x87,0xd3,0x9e,},{0xf4,0x43,0x71,0xe6,0xc3,0x39,0x16,0x39,0xd4,0x57,0xed,0x14,0x64,0x81,0x84,0x80,0x94,0x11,0xe8,0x0a,0x32,0x01,0xf8,0x81,0x16,0x70,0xe5,0x00,0xfc,0xad,0x92,0xf3,0x00,0xaa,0xbf,0x7f,0xc6,0x8e,0x44,0x01,0x91,0xe8,0x81,0xd6,0xc3,0x47,0x4e,0xfd,0x6d,0x28,0xf0,0x9d,0xc4,0x43,0x12,0xfc,0xfc,0xb8,0x27,0x01,0xba,0x3c,0x29,0x0a,},"\x16\x8d\x0b\xc5\x59\x8b\xe0\x2f\x54\x43\xbf\xe7\xdf\xb8\x82\x99\x85\xca\x5d\x28\x2a\xf9\xcf\x1b\x14\x82\x60\x2f\x24\x3d\x48\x6b\xd8\x2b\xa0\x39\xa0\x75\x09\x09\xe9\xb3\xc7\xd4\xd5\xf8\xb8\xba\xf4\x57\x18\xaf\x03\x11\x85\x4f\x4d\x1c\x78\x37\xf3\x1d\x8e\xe6\x8d\x35\x58\xe7\xe5\x1e\x0c\x64\x6a\x4a\x63\x75\x96\xee\x90\x05\x7b\x01\xed\x0a\x17\xda\xa3\x95\x0b\x81\xab\x47\xae\x8b\x94\xc1\x7d\x40\x74\x69\x13\xc4\x6b\xa1\x47\x8b\xfc\xa5\x1b\x16\x76\x28\xfc\x3e\xe1\xe2\x2f\x2f\x19\xd6\xd8\xda\xf9\x3d\xf6\x54\x0c\xed\xb7\xa8\x59\xd1\xa2\xba\x59\x11\xba\x71\x76\x6e\x8b\x7f\xce\x0c\x0e\x86\x63\x61\x6d\x01\x80\x69\x7d\x78\xce\x30\x40\xd4\x38\x13\x19\x82\xf3\xf8\x11\x2a\xcc\xa2\x9a\xe5\x3e\x53\x9f\xf8\xc9\xec\x41\x06\xd1\x32\xf4\x02\x01\x85\x18\x30\x84\x85\xf2\xaa\x6c\x9e\x8d\x1e\x62\xfe\xd6\x0c\xb2\x49\x45\x7d\xb3\x3c\x6f\xd1\xfe\x07\x44\x53\x61\xf0\x81\x94\xa2\xb5\xa0\x57\xcb\x03\xcc\x75\x4e\x5c\x7d\x4a\x7e\xea\x53\xa7\xf7\xd2\x07\xca\xcc\xa5\xe6\x8c\xaf\xa9\x69\xa3\x52\x1d\xbb\x81\x03\x99\xa1\x7f\x32\x8e\xe7\x67\xcf\x55\x92\x6b\x2b\xd5\xf0\x29\x54\x9d\x3b\x46\x45\x79\xc4\x26\x55\x26\x53\x98\x47\x2e\x1c\x77\xcc\x8d\xd9\xaf\xf1\x87\xf7\xac\x34\xdd\x45\x6a\xce\x99\x9a\x73\x6e\xcc\xa6\xd4\x05\xd4\x92\x2c\x77\x9c\x60\x0c\x47\xb8\x4c\x9c\x1d\xf5\xe5\xf8\xed\x3b\x28\x11\xd3\x51\x33\x91\x13\xf8\x45\x3c\xca\x4c\x44\x11\x68\x8c\xb0\x38\x82\x58\xeb\xbd\x18\x72\xb8\x36\x10\x04\x22\x49\x49\x4e\xd5\x60\xd4\xcd\xa6\xa6\x84\x55\xd9\x57\xe8\x06\xdd\x0b\xdd\x83\x00\x4c\x4c\xa8\x07\x74\xb8\xa0\xa1\x66\x58\x66\xf1\x70\x85\x01\x4e\xad\xb3\xea\xe7\x38\x2f\xa8\x70\xde\xb2\x9d\xd8\xc9\x31\xb5\x30\x19\x62\x57\x40\xe2\x83\x92\xf3\x85\x75\xc0\xe2\xa9\xe5\x04\xfc\x35\xbd\x95\xdf\x56\x43\x9a\x89\x82\x30\xa2\x39\x8c\xd2\x22\x5c\x76\x6e\xf3\x6f\x12\xae\x7e\x49\xb3\x0a\x9c\x0a\xad\x46\x9d\x58\x95\xbb\xf7\x21\xcc\x0f\xf5\x1d\x84\x0c\x80\x2d\x4a\x7e\xef\xba\x84\xfe\x52\x05\xa2\xc2\xf1\x40\x11\x92\x2d\xde\x56\x14\x56\xf7\x9e\x61\x61"}, -{{0x5f,0xea,0x38,0x73,0x9c,0x61,0xca,0x83,0xbf,0x7b,0x4a,0xd1,0x75,0xa2,0x11,0x76,0x27,0xb9,0x71,0xa6,0x34,0xa3,0x05,0xa8,0x4f,0xa5,0x7f,0xec,0xb8,0x03,0x56,0x24,},{0xdd,0xd1,0x4b,0x0f,0xc0,0x67,0x68,0xd5,0x10,0x4c,0x50,0x76,0x4b,0xfd,0x3b,0x95,0x23,0x52,0xa3,0x40,0x07,0xc5,0x0d,0x5d,0xdd,0x22,0x4f,0xf5,0x1a,0xfc,0xdf,0x9c,},{0xf4,0xe2,0x74,0x82,0x3f,0x2c,0x39,0x6f,0x3a,0x32,0x94,0x86,0xaa,0x64,0x10,0xc5,0xff,0x19,0x26,0x6f,0x07,0x70,0xfd,0x04,0xfb,0x14,0xa7,0x60,0x2d,0x2b,0x69,0xa4,0xa2,0xb0,0x09,0x28,0xe9,0xe1,0xd9,0x23,0x89,0xf8,0x03,0x33,0x59,0xed,0x6f,0xb2,0x14,0x64,0x67,0xaa,0x15,0x4c,0xba,0x59,0x7d,0xec,0x6a,0x84,0x17,0x3f,0x8d,0x07,},"\x10\x13\xc6\x0a\x73\x95\x35\x49\xe5\xed\x10\x5b\xde\xa1\x50\xb9\x1e\x60\xec\x39\x20\x0d\x43\x72\x13\x04\xbf\xc8\xec\x43\x9d\x39\x60\x96\x13\xc2\xd8\x78\x04\x4a\x9d\xa0\x1b\x26\xd8\x6d\x6d\x65\xdb\x93\xd9\x1a\x13\x7e\x9c\x48\x08\xa9\x7d\x4e\xf2\x86\xa9\x03\xf3\xf1\x38\x2c\xc6\xd1\x29\x42\x16\xb9\xfa\xfc\x01\x3c\x86\xb9\xff\x68\xb5\x5a\x50\xea\x37\x66\xe6\x1d\xc1\xce\x38\x34\x8e\x91\xd6\x2c\xe7\x32\xc1\x52\xd7\x66\xb9\x33\x5c\x68\xd6\xca\xd7\x7b\xe2\xb4\xa0\xcd\x50\xb9\xa1\xec\x63\x2b\xa5\x56\x48\xa6\xe7\xe1\x1a\x14\xc0\x68\x53\xc0\x2a\xec\x48\x09\xbd\x14\x7a\x5d\xdd\x9f\xbc\x3b\xe9\xf0\xc8\x15\x8d\x84\xab\x67\x95\xd7\x71\xb4\x2b\x18\x14\xa1\x7a\x3c\x7a\x6c\xa0\xf4\xa8\xf7\xb3\xa0\xdb\x1c\x73\xba\x13\xb1\x64\x00\xdf\xec\xbd\x03\xd2\x16\x65\x0e\x4d\x69\x70\x4a\x70\x72\x46\x44\x4d\x57\x91\xfa\x27\x37\x52\xf5\x9c\xb5\xae\x9f\xd4\x16\xa5\x18\x66\x13\xd6\x6a\xfd\xbd\x1c\xe6\x91\xa8\x7b\xd7\xd8\xb6\x71\x90\xe9\xac\x68\x70\x62\xa0\x80\xd2\xec\x39\xfe\x76\xed\x83\x35\x05\x82\x51\x87\x28\x39\xe8\x5e\xb6\x2f\x18\xec\xe1\x87\xca\xba\x55\xb5\xf7\xd5\xed\xca\xde\x01\xcd\xc5\x43\xcc\x67\x7e\x50\x23\x8b\x89\xc5\x63\x5a\xd5\xc8\xfc\x22\x0f\x5e\x0b\xe1\xbc\x66\x7d\x20\x98\x97\x53\xa6\xd6\x16\xfa\x69\xf8\xb1\x29\x40\xb8\xca\x9e\x2c\x48\x57\x71\x32\xd8\x69\x1b\x05\x37\x79\xa1\x52\xcb\xac\xff\x3b\x8b\x1b\xd7\xaf\x69\x2e\x56\xc7\x3b\xba\xe4\x63\x47\x76\xcf\xc2\x13\xc9\x9b\x9a\xe4\x58\xdf\x1b\xef\xc8\xc8\x77\x74\x26\x64\xb0\xa0\xbb\x1f\x69\x15\xc8\xda\xe3\xb3\xf5\x5d\xd7\x5a\xba\x6a\x3b\xcc\x41\x76\xb4\xe3\xba\x03\xd0\xc1\xc0\x4c\x3c\x64\x08\x77\x8b\x2b\x8e\x5a\x8a\x3e\xb5\x2e\xd3\x2a\x74\x28\xc0\x0a\x98\xa5\x89\xd8\xca\x93\x90\xa2\x10\xf4\xa7\xac\x00\x4f\xa1\xfe\x4c\x6d\xa6\x94\xf1\x22\x76\xe3\x20\xb4\x1b\x0b\x59\xf7\x5d\x26\x4a\x39\x6d\x45\x0b\x63\x1a\xb3\x53\xf1\x61\x27\x09\xe7\xa2\xe6\xa5\x0d\x01\xcb\x11\x0e\x53\x04\x05\x46\xdd\x3b\x1e\x11\xd2\x57\x32\x81\x3a\xa7\x6b\xe5\xe8\x1f\xcf\x7a\x57\x73\xf6\x81\x5b\xbd"}, -{{0x60,0xf9,0xa1,0x4c,0xce,0x5d,0x43,0xfd,0x9a,0xab,0x4e,0xe8,0xcc,0x83,0x79,0xd5,0x75,0x94,0x91,0x52,0x69,0x3b,0xf2,0x9a,0x67,0x90,0xb0,0x35,0xe4,0x2a,0x44,0xde,},{0xbd,0x4a,0x70,0x74,0x0d,0x5a,0xca,0xbe,0x49,0xf9,0xa2,0x15,0x20,0x82,0xfa,0x20,0x25,0x33,0x0e,0x64,0x40,0x43,0x7f,0x1d,0x04,0x7f,0x31,0x3d,0xe4,0x90,0xdc,0xa5,},{0x72,0xf5,0x4b,0xb8,0xbd,0xd1,0x7e,0x9e,0x42,0x2c,0xd3,0x39,0x63,0x1d,0xd3,0x9f,0x57,0x35,0x50,0x15,0xd4,0xcb,0xd1,0x5a,0xca,0xb7,0x54,0x2e,0xfd,0x78,0x4a,0x32,0x1c,0x1f,0x61,0x25,0x76,0x4c,0x0d,0x15,0x40,0x45,0xb3,0x2e,0x70,0xdc,0x2e,0x03,0xfb,0xfe,0x11,0x17,0x46,0x8a,0xc3,0xe7,0x31,0x27,0xb5,0xfa,0xc8,0xd4,0x21,0x02,},"\xdd\x7f\x44\xf9\xeb\x72\x8a\xb4\x8d\xe5\x4e\xcd\xe6\xb6\x18\x4b\xd5\xdd\xd8\x70\x75\x45\xa0\x12\x9f\x2e\x90\x59\x05\xb5\x5d\x3e\x7f\xd5\x7e\x28\x48\x5d\x25\x81\x48\xf6\x60\x5e\x23\x77\xd5\xb2\x67\xd2\xea\xf4\xcd\x4b\x46\xe4\x54\x96\x22\x19\x86\x82\x32\xb6\xf4\x1f\x88\xa7\x97\xf9\xcd\xd5\xc3\x9a\xda\x51\xa6\x41\x21\x4f\xb9\xdb\x2c\x2a\x9b\x5a\x5b\x16\xe3\x03\x57\x53\x18\xb6\x25\xcc\xa9\x70\xb7\x43\x48\x72\x79\x02\xa1\xcf\x26\x8b\xd1\x6e\x10\x71\x13\x16\x1c\x8c\xbc\x99\x30\x3c\x2b\x9f\x23\x55\x41\xa7\xb3\x1e\x43\x31\x20\xfe\xba\x14\xfe\xbe\x4b\xcb\x0f\x5b\x93\x6c\x7e\xdd\xdd\x0e\xcf\xc7\x2c\x8d\x38\xf6\x4c\xdb\x6c\xfc\x29\x10\xbc\x29\xa5\x21\xc5\x0a\x51\xab\xcb\xc2\xaa\xbf\x78\x9d\xe8\x22\xcb\x04\xf5\x72\x8f\xee\x15\x3d\xd5\x50\x1b\x2d\xb5\x9c\x59\xf5\x0c\xab\x17\xc2\x92\x16\xd6\x69\x51\x01\x9e\x14\x5b\x36\xfd\x7e\x84\x1b\xfb\xb0\xa3\x28\x55\x4b\x44\xdd\x7e\xf5\x14\x68\xc3\xd5\xb7\xd3\xa1\xf7\xb9\xde\xf5\x8d\x8c\xf9\xd9\xbc\xaf\xe9\x2c\x86\xcf\x6d\x61\x19\xe9\x8d\xba\x6f\x38\xea\x57\xe3\x22\xdd\xc9\xc2\x19\x8d\x4b\xbc\x3b\x94\xea\x13\x29\xdb\x0d\x45\x8e\x01\xc7\x08\x1b\x33\x92\x5a\x3e\x28\x7f\x59\x9a\x85\x8c\x50\xc3\xa8\xf1\x8c\xc2\xaa\x63\x4d\xf6\x3e\x7f\x10\xe4\x03\xad\xea\xb2\xf4\x1d\xb5\x57\x87\x90\xc3\xb4\xf0\x41\xa8\xb7\xa4\xf6\x9c\xd6\xe0\x62\x15\xdf\x82\x01\xae\x5b\x3e\x1d\x1d\x25\xa0\xa3\x9b\xfc\x3d\x04\x1a\x2f\x98\x21\x3e\xf4\x14\x12\x45\x79\x2a\x76\xf0\x6d\x4d\xe2\x5f\x64\x67\xa0\xe5\x6f\x2f\x5c\xf6\x94\x00\xd2\x21\x17\xde\x7b\x46\x14\x95\x54\xb7\x0c\x75\xb9\xf9\x94\x84\xa4\xf6\xf0\x35\xad\x3f\x10\xe3\x75\x3c\xb1\x4f\x4f\x39\x8d\xcf\x6a\x64\xd1\x0c\xf6\xc4\xfa\xc0\x7c\x91\x19\x3c\xc0\xf5\x4f\x0d\xe5\x8c\x63\x43\xe9\xca\xaa\x6b\x4f\x47\x5e\xf9\x1a\x59\xe0\x83\xf9\xf2\x11\xf5\xbc\x8e\x7e\x45\x16\xb4\x5c\xf0\x6b\xf5\x0b\xeb\x8f\xc4\xab\x57\x9d\x86\xd4\xa4\x19\x0e\xea\xc7\x48\xd0\x6e\x08\x52\xc4\xb9\xba\x8c\xfc\x50\xdd\x0a\x03\x7a\x7b\xad\x7f\xad\x55\xaf\x30\x9a\x5f\x13\xd4\xc9\x1e\xd3\xe0"}, -{{0xa3,0x90,0x53,0xc5,0xc5,0x8b,0xf3,0x1d,0x46,0x2b,0x27,0xa6,0x20,0xb0,0xb3,0x7b,0x80,0x52,0xc6,0xb1,0xc4,0x10,0x2b,0x61,0x45,0x66,0x3a,0xa1,0x5e,0x97,0x87,0x18,},{0x36,0x42,0xac,0x2a,0x32,0x80,0xdc,0xe5,0x2a,0xd8,0xdf,0xcf,0xd3,0x70,0x94,0x36,0xed,0xc4,0xe7,0xe4,0xae,0x1b,0x45,0x2d,0x9b,0x22,0x07,0x80,0xb0,0x86,0x79,0xfa,},{0xf7,0x38,0x3e,0x96,0x6c,0xb2,0x30,0x9d,0xee,0xdf,0x86,0x01,0x00,0x18,0x3a,0xae,0xfa,0xc6,0x72,0xca,0x16,0xd5,0x41,0x9c,0xd6,0x42,0x2c,0xa7,0x0e,0x16,0xb3,0x97,0x6f,0x5f,0x16,0x5a,0xfc,0x27,0x86,0x11,0x7c,0x86,0x82,0x34,0xba,0x11,0x09,0xed,0xe0,0x31,0xf8,0x97,0x9b,0x50,0xe5,0x67,0x35,0x8b,0xd4,0xf8,0xbd,0x95,0x82,0x02,},"\xf6\x55\x40\xd3\xab\xeb\x1e\xe5\xea\x98\x70\x62\xc1\xb5\x79\x51\x6d\x3c\x29\xc3\x9c\xbc\x6b\x09\xd6\x0e\x18\xfe\x27\x4c\x2b\xef\xe0\xf5\xfe\x7d\xbd\x57\xc2\xd5\x83\x52\x29\xbb\x75\x4e\xc4\x34\x13\x94\x76\x57\x76\xd6\xa9\x17\x8c\x4e\x6a\x31\x2c\xd7\x4b\xdb\xac\xa0\xe8\x82\x70\x62\x8c\xd8\x41\x00\xf4\x72\xb0\x75\xf9\x36\x92\x83\x01\x22\xf0\x0f\x9b\xd9\x1a\xc5\x82\x83\x6c\x8b\xfa\x71\x4a\xa4\x8e\x97\x70\x03\x55\x6e\x1b\x69\x6d\xf3\x28\xef\x58\x4f\x41\x3f\x8a\xb6\x14\x76\x06\x99\xc4\xd1\x47\xc3\xee\xa1\xda\x04\x35\x83\x5c\x9b\xf7\xad\x54\x60\x6f\x02\x13\xeb\x74\xa1\xb4\x76\x14\x15\x06\xae\x2c\xd1\x24\xcd\x51\xd6\x6e\x7e\x7e\x57\x95\x60\x57\x63\x05\xc5\xfb\xe8\x43\x0b\xe3\xeb\xeb\xaa\xcb\xa3\xf9\x98\x9d\xd7\xd1\x99\xf5\xa4\x55\xa5\x0c\xdb\x37\x55\x03\x7e\x1a\x70\x67\x4a\x4f\xef\x40\xb4\xa3\xaa\xf7\xbd\x3c\x95\xb1\xab\x41\xbb\x20\x62\x11\xc3\xa1\x27\x6d\x3e\x37\xd8\xa3\xa5\xc3\xd5\xd0\xf3\x6e\xf5\xb4\xf3\xde\x26\xb7\xf2\x0f\x6b\x29\x00\x71\x6d\xcc\x22\xab\x73\x4e\xba\xf1\xe8\xd0\x00\x20\xe5\xf0\x19\x55\x16\x53\xb9\xc2\xf7\x0a\x40\x38\xdf\xb2\xf1\x2d\x25\xd6\xd8\x4e\x79\x07\x3a\x65\x48\xfe\x15\xe4\x82\x8f\xe5\xde\x83\xac\x3d\x8d\x98\xb7\xda\xf9\x27\x10\x48\x2c\x37\xf7\xbd\x24\x31\xa8\x11\x4c\x61\x37\x65\x7b\xb1\x77\x88\x2d\x8a\x3c\x76\xba\xbf\x1c\x67\x1a\x70\x55\x36\x5f\xe9\x08\x66\x16\x7a\x2d\x1d\xbc\x87\x0b\xe8\x3b\x36\x01\xf0\x9d\x4a\x31\x7a\xe2\x54\xca\xc9\xf9\x8d\xcc\x7a\xea\xd9\x22\x4c\xd9\xc9\xd8\xa2\x00\xab\xc8\x0a\x2d\xd1\x08\xaf\x28\xfd\x46\xad\x70\x80\xae\x74\x1b\x50\x05\x4b\x9b\x9a\x92\x01\xef\xb7\x83\x8b\xc4\xc5\xc2\xcc\x3d\x76\xba\x0f\xcc\x49\xc4\x6e\x79\x2c\x26\x29\x2b\x7d\x03\x12\xaf\xf9\x55\xa9\xf8\xed\xf0\xc6\x96\xa7\x0a\x61\x4f\x35\x53\xad\x38\x69\xbf\xde\x48\xd2\x6a\x4d\x36\x7b\x6c\xec\x05\x7e\x62\xa4\xe5\x48\x55\x4b\x48\xb5\x3e\xcd\xa7\x90\xba\x7a\x0a\xb2\xe3\xde\x58\x7b\xdc\x22\xb0\x2f\x59\x47\x63\x4d\x73\x09\x9f\x54\x7d\xb2\x2e\xc1\xbb\xf8\x23\x43\xf9\xa2\xca\x38\xbc\xe4\xeb\x59\xbe"}, -{{0xe0,0xc2,0x9d,0xf4,0xde,0x45,0xc4,0x75,0x39,0xe0,0x89,0x6b,0x3a,0x59,0xbc,0x3d,0xe6,0xb8,0x02,0xfd,0x14,0xdb,0xdc,0x9f,0x25,0xe7,0x17,0xac,0x82,0xc3,0x28,0xf3,},{0xa6,0x90,0x02,0xb0,0xf5,0xef,0x35,0x4c,0xe3,0xb2,0xd6,0xb8,0xd8,0xba,0x70,0xab,0x77,0x84,0x32,0xb2,0x2f,0x14,0x4d,0xc9,0xc2,0xeb,0x92,0xd9,0x9d,0x99,0xdd,0x2a,},{0xbb,0x3b,0x8c,0x5c,0x27,0x59,0x1f,0xd8,0xb9,0xc5,0xba,0x48,0x9d,0x6b,0x6e,0xe5,0xb0,0xfb,0x4a,0x7b,0x0d,0xe5,0x1f,0x16,0x39,0xaf,0xc6,0x73,0xd0,0xe5,0xf7,0x5e,0x31,0x3a,0xa7,0xe1,0xd0,0x00,0x90,0x81,0xdb,0xca,0x74,0x35,0xb6,0x87,0xcc,0xd1,0x2f,0x64,0xf7,0x4a,0x38,0x6e,0x77,0x2b,0x9e,0x24,0x78,0x1b,0x92,0x5c,0x8c,0x0c,},"\x6a\x37\xcb\x4c\x74\x9c\x58\x35\x90\xc8\xd8\x49\xbc\xe3\xfa\x65\x7f\x10\x00\x91\x90\xca\xd9\xbe\x41\xed\xe1\x9b\xf2\xfd\xb3\xc5\x62\xa6\x10\x1f\x27\xbd\x37\xf2\x23\xca\xb1\x3c\xed\x24\x5a\x1c\xed\xf8\x52\xf5\x51\xf8\x57\xaa\xd9\x72\x7f\x62\xc9\x67\xc0\xa9\x21\xdf\x11\x6f\x48\xa8\x0a\x60\x40\xb3\xc7\x23\xab\x5c\xb5\x94\xc4\x50\x7a\x3d\x20\xcd\x60\x51\x4e\x22\x16\x4a\x82\xb7\x4f\x19\xdc\xfd\xd8\x3c\x57\xbc\x36\x52\x37\x55\x17\x41\x4a\xf5\xd1\x8e\x0a\x64\xcc\xab\x36\x69\x97\x68\xd0\x7c\xf4\x0b\x70\x63\xa8\x3e\x43\xd5\xf6\x07\x96\x4b\x1b\xf0\x84\x0a\x45\xad\x50\xab\xf8\x3d\xbc\x84\x9f\x40\xe5\xb4\xcf\xb6\xa3\x34\x7b\x29\xfe\xc5\x07\x74\x04\x6a\x4b\x50\x04\x10\x32\xaa\x4d\x56\x7e\x85\x64\xb3\xee\xd1\x64\x20\x40\x68\x2d\xd8\xae\x7d\x71\x79\x28\x6c\xf6\xe1\x85\x3d\xc8\x7d\x27\xc3\xe9\xe6\x0f\xa4\x7c\xf8\xcb\x2d\xa0\x18\x1d\x53\xee\xc4\x06\x14\xb0\x73\x31\xa4\xfb\x70\x28\x08\x6d\x0b\x1c\xe2\xe1\x11\x5b\x73\xa1\x62\xc5\x27\xbd\xd7\xca\xb5\x33\x5b\x86\x3d\x10\x8b\xe0\x47\xbd\xbc\xa1\x12\xcc\x6e\x77\x6b\xb4\x53\xc3\x17\x31\x43\x88\xbb\x96\x53\xef\xb4\x44\x4b\xf5\xcf\x1e\xc8\xda\x23\xb7\x11\xba\x71\x79\x6c\x0a\xe0\x2b\xa1\xdc\xc8\x38\x45\x50\x78\xc3\x89\x7f\x07\xe9\xe1\x3b\x76\xe4\x92\x74\xc2\xe2\x07\x50\x6b\x00\xa0\xb5\x58\x88\x3a\xa1\x22\xb6\x67\xdb\x9d\x67\x05\x08\x60\x6a\x3f\x54\x32\x06\x36\xcd\x19\xf9\x73\x91\x7f\xb1\x87\x5f\x43\x63\xe2\x20\xf1\xe1\x23\x98\xcc\x6a\xfd\x79\x09\x47\x43\x33\x84\x56\x81\x3a\x58\x26\xad\x3f\x1a\xba\x7c\xd7\xbe\xab\x1f\xe1\x83\x85\x9c\x0c\xc9\xef\x40\xa5\xea\xb9\x12\xca\xf5\x15\xa8\xd4\xc3\xb9\x3d\x64\x1b\x7a\xb3\xe7\x6b\x16\xc1\x29\x71\xac\xe8\x8f\xf3\x3e\x5a\x1e\xd9\xb4\x4e\x45\xdb\x8f\x30\x85\xdb\xf0\x70\xb2\x56\xb0\xd7\x51\x2e\xe1\x06\x94\x32\x60\x3d\x73\x09\x5d\xb8\x74\x9c\xa5\x47\x96\x3b\xd7\x1a\x8a\x68\x4a\xb8\x51\x6b\x14\x6c\x41\x87\x17\x63\x86\xaf\xdf\x6c\xb1\x36\x8a\x3d\xd8\xfc\xb2\xcf\xff\x77\x05\x6a\xaf\x78\x23\xf8\x00\xb2\x66\xac\xce\x72\xbf\x64\x3c\x6d\x0c\x28\xf0\xab"}, -{{0x19,0x8b,0x5f,0xd1,0xc0,0x38,0x27,0xe0,0x99,0x4a,0xd5,0xbf,0xee,0x9b,0x5b,0x7b,0xe9,0x96,0x6c,0x9c,0x3a,0x26,0x7e,0x4d,0x74,0x30,0x34,0x37,0x67,0x40,0x3c,0x67,},{0x66,0x82,0xc6,0xf1,0xa8,0x66,0xb4,0x9b,0x2f,0x8e,0xe9,0x7f,0x2e,0x53,0x2f,0xa9,0x16,0x66,0xbf,0x38,0xda,0x1b,0x4d,0xd6,0x55,0x43,0xa1,0x77,0x77,0x94,0xcb,0xee,},{0xf4,0x54,0xf3,0x5b,0x18,0x53,0x8f,0x87,0x7e,0x5d,0x61,0x4a,0x76,0xb5,0x27,0x6a,0x27,0xfc,0x0b,0x43,0x3f,0x21,0x5d,0xc4,0xe9,0x63,0xb3,0xf0,0x47,0x69,0x4c,0x78,0x0c,0x51,0x5c,0x6e,0xf6,0xfe,0x2d,0xb4,0xb0,0x09,0x00,0x9b,0xc2,0x73,0x3a,0xec,0x4f,0xd4,0x6e,0x61,0x53,0x57,0xcc,0x0b,0xcc,0x9f,0x1f,0x7f,0xc2,0x1e,0x3c,0x02,},"\x3f\xda\xa1\x5c\x46\xf2\x51\x43\xdb\x97\x20\x79\xd7\x01\x3c\x7f\x69\xa1\x36\xf4\x5f\x3f\x6b\xa2\xce\xd8\xb8\x28\x46\x8e\xb3\xda\xa6\xb5\x0b\x4f\x8d\x33\x80\xfe\xc6\x4a\x03\x43\xbe\x11\x6f\x6f\x83\xb6\xee\x64\xcc\x4c\x1b\x1d\x08\xd5\x4f\xd4\x20\x29\xe4\x28\x5c\xfc\x6c\x6d\xd5\xcd\x18\x1a\xb5\x33\xff\xcd\x41\x1f\x23\xa1\x00\x3d\xa9\x4e\xc9\x34\x0e\x2e\xc7\x11\x99\xd6\x78\x54\x0d\x51\x82\xe1\x39\xff\xcb\xc5\x05\xa1\x70\xb8\xf0\x7f\x4a\x7e\x69\x4c\xa9\x2f\x58\x32\x0c\x0a\x07\x85\x64\xce\x9d\xe9\x9b\x0f\xa8\xe6\x6b\x0d\x82\x2e\x46\x7a\x5a\xeb\x83\x56\x79\x96\xa4\x8b\x89\xdb\x25\xca\xde\x64\x57\x79\x4e\x54\x14\xd6\x7e\x9d\x4a\xb7\xcd\x6c\xc2\x05\x8b\xb7\xa5\x13\xab\xd7\x09\xf4\xca\xf2\x4b\xb6\x7c\xe1\xc0\x3a\xb6\x2d\xbd\xfe\x30\x9e\xc7\xdb\x0f\xa3\xea\x7a\xae\x82\x36\xf2\x59\xb9\x22\xd4\x53\x61\x15\xa6\x3b\xc8\x9a\xcb\x20\x51\xd0\x9e\x73\x1c\xbb\x0d\xf1\x57\xd9\xd3\x45\xbd\x91\x09\x97\x3c\x2b\x59\x4f\x14\x8e\xfc\x6f\x33\x77\xde\x51\x63\xb7\xf6\x98\x69\xff\xef\x85\x3e\xae\xfe\xb4\x02\xe2\x35\x29\x59\x4f\xbd\x65\xca\x05\xfe\x40\x62\xc5\x29\xd8\xe3\x21\xab\xc0\x52\x00\xca\xc1\xe8\x39\xe8\x7b\x1f\xd3\xfd\xf0\x21\xd6\x8c\xbb\x3a\x41\x42\xb6\x9c\xc3\xaf\x6f\x63\x2e\xdd\x65\xb8\x3f\x5a\xa4\xcb\x17\xda\x5b\x6b\xa3\xfc\x03\xed\xb1\x7c\x2a\x3c\xb5\xb0\x48\x36\xe7\x66\x0e\x63\xc8\xa0\x48\x3e\x24\x39\x83\x37\x1d\xfa\x98\x39\xf9\x16\x4a\xd4\xda\x0d\x59\x53\x65\x5e\x3a\x95\x18\xe1\x36\xda\x74\x57\x37\xc7\x92\x43\xc3\x55\xfc\x12\x5c\xbd\xcc\x76\xae\xc9\x22\x16\x84\x6c\x45\x74\xf4\xf7\xf2\x98\xbc\xde\x54\xfd\x24\x44\xad\x30\x25\x95\x5c\x10\x03\x15\xde\x5a\x4e\x27\xc3\x33\xa0\x02\x84\xb2\xf7\x02\xfd\xd3\xde\x22\xac\x6c\x24\x0d\xbc\x14\xbf\x71\xe6\x2d\x13\x1b\x62\xf2\xdb\x99\x24\x73\xf2\xf9\x13\xf6\x0c\x91\x6e\xcf\x57\xdf\x5f\x3f\x02\x1f\xb3\x30\x83\x43\x95\xb7\x94\x72\xca\xff\x19\xfc\xfa\x0a\x27\x17\x95\xc7\x6d\x69\xb4\xdb\x3f\x85\xb8\xd2\xe5\xc3\x44\x19\x65\x48\x4d\xcc\x39\xab\xa5\x9b\x70\x12\x74\xf7\xfc\x42\x52\x46\x85\x60\x69"}, -{{0x43,0x92,0xf7,0xd4,0xfb,0xd6,0x8f,0xe1,0x54,0xe4,0xba,0x38,0xad,0x52,0x07,0x61,0x2a,0x06,0x48,0x55,0x60,0x56,0xc3,0x9a,0xc1,0x16,0xad,0x46,0x8f,0x89,0xbd,0x2d,},{0xcb,0xea,0xef,0x41,0xac,0xac,0x02,0xbf,0x1f,0x78,0x0c,0xe9,0x34,0xaa,0xbd,0x63,0x13,0x64,0xb3,0x69,0x56,0x7b,0xe1,0xbe,0x28,0xe3,0x90,0x6f,0x9d,0xb1,0x20,0xfa,},{0x86,0xe7,0xcc,0xf0,0x6e,0x79,0x36,0x2d,0x40,0xcd,0xb7,0xfb,0x75,0xa9,0x89,0x78,0xbb,0xd3,0x34,0xa1,0xdb,0x75,0x90,0x36,0x7d,0x60,0x84,0x9b,0xd5,0x3e,0x2f,0xb1,0xa4,0xbd,0xae,0x59,0x0d,0x1f,0x47,0xb5,0x49,0x0d,0x87,0x02,0xe7,0xc1,0xa8,0x72,0x68,0xb8,0xee,0x9d,0xb6,0x12,0xde,0x7b,0xdc,0x2e,0x38,0xfa,0x6d,0xeb,0x7e,0x05,},"\xcf\x17\x09\xdc\x9a\x08\x67\xee\x90\x87\x21\xb1\x36\xcb\x93\xa8\x42\x29\xe8\x3b\x46\x20\x47\x77\xca\x81\x94\xd0\x8b\x7a\x3c\xa9\xc9\x12\xeb\x24\x3e\x5b\xda\xbf\xee\xd3\x52\x34\x9d\x20\xbe\x80\x1b\x72\x2a\xf0\x89\x22\x38\xe7\x2e\xdf\x19\x0e\x63\x61\xf5\x75\x72\x78\x1a\xd3\xc2\x59\x0b\x19\x73\x57\x64\x1c\x80\x53\x83\xba\xa1\xd4\x97\x2f\x76\xc6\x54\x48\x53\x2c\x11\x08\x34\xa0\xba\xa8\xf4\x88\x63\xe1\x66\xb7\x06\x65\x37\x08\xcd\x40\x57\xd3\xa4\xf9\xfc\xb2\xce\xb4\x12\x00\x01\x27\x7d\x38\xc4\x38\x47\xd8\x22\x82\x2b\x77\x7c\x2b\xb4\xda\x40\x15\xa1\xc2\x4d\x41\x6d\x50\x62\xa8\x71\x84\x91\xd8\x55\xaa\xa5\xdb\xf5\x57\x9c\x16\x4d\x8e\x52\x4a\x9f\x2f\xa3\xf2\x2e\xb0\x98\x61\xff\xe6\xad\x65\x9f\xe3\x6e\xb4\x04\x31\x22\x2c\x22\xd7\x13\x7a\x6c\xab\xca\x8d\xb7\x86\xe3\x9d\x81\xf6\x61\xaf\xde\x4e\x39\x58\x9b\x4d\xb4\xd3\xc5\x1c\xa5\x35\x90\xa1\x4e\x11\x5d\x0a\xfc\x3a\x87\x7b\x83\x9a\x96\x38\xbe\xce\x80\xc3\x2c\x19\xe5\x1b\x75\x32\x02\x48\x45\xf7\x6c\xfe\x9b\xfb\x2a\xc0\x51\x30\xf6\x75\x8b\xf7\xfe\x99\x3a\xa9\x3a\xa2\x72\xe4\xe6\xbd\x0c\x75\xc1\x40\x99\xd4\x3e\x65\x2a\x22\x3e\x5b\xcd\x64\xc3\x62\xd4\xb8\xf4\xb9\x5e\x01\x6f\x93\x50\xc7\xfa\x74\xe6\x53\x52\x5d\x08\x01\x15\x58\xb2\xc6\xe9\xbf\x4f\xdf\x9d\xbd\x5e\xf9\xb0\x9b\xbc\x84\x6a\xfc\x2b\xcb\xc8\x6c\x4c\xcc\x31\x5f\x6d\x1c\xcd\x48\x9b\x0c\xf8\xed\x0d\x93\xf2\xf5\x32\xa4\x26\x26\x5c\x59\x0b\xa3\xa5\x90\x23\x34\x7d\x81\x9d\x9b\x28\x1e\xf8\x53\x10\xb0\x53\x16\xd4\x6c\x8a\x8c\x03\x65\xd0\x68\xa8\x70\x86\x64\xea\x4d\x77\xac\x0c\xd1\x50\xa6\x5a\x56\x58\x6b\xab\xd3\x4b\x74\x36\x5b\xb8\xfe\x3e\x61\x87\x26\x22\x84\xd6\x44\x32\xe4\xc8\x1e\xa4\xc0\xe5\x7c\x1d\x71\xae\x98\x0c\x7f\x4d\x1d\x87\x10\x32\xe1\x88\xbb\xf9\xd1\x75\x8c\xdc\x1d\xff\x98\x9f\x2d\x12\x88\xfe\xf4\xe2\x05\xe9\x9e\x7c\xbf\x2c\xc3\x24\xb8\xc9\x30\x46\xf4\x76\xc5\x9d\x3d\x0a\x59\xdb\x6f\xe3\x73\x82\xdc\x79\xc5\xec\x16\x05\x6a\xb3\x93\x4a\x52\xf7\xd2\x88\x0d\x04\x71\xa3\x77\xb6\xa8\xae\x84\xd5\x6a\xc2\x2d\x1d\x54\x55\x1c"}, -{{0x0b,0xea,0x98,0xab,0xe7,0xd6,0x3f,0x15,0x83,0x90,0xee,0x66,0x8a,0xa0,0x50,0xe8,0x4a,0x25,0xd2,0x89,0x3e,0x49,0xfc,0x83,0xf0,0x79,0xf9,0xbb,0xa6,0xa5,0x5a,0x75,},{0x22,0x19,0x2e,0xc0,0xd3,0x2e,0xf9,0x83,0x56,0x65,0xa6,0x1b,0xc8,0x8b,0xcf,0x4e,0x16,0x04,0x63,0x79,0x21,0x15,0x2c,0x11,0x6a,0xf5,0x03,0x36,0x5b,0xf6,0xbe,0x42,},{0x7e,0xb3,0x13,0x9b,0x88,0x0f,0xdf,0x66,0x37,0x6a,0x20,0x90,0x81,0x88,0x40,0x04,0x97,0x67,0xc8,0x37,0xf3,0xad,0x00,0x36,0xb1,0x41,0x66,0x70,0x52,0xb3,0x36,0x09,0x81,0x7c,0xa5,0xe2,0x40,0xed,0x8c,0xdf,0x3c,0xcf,0x3a,0xee,0x29,0x27,0x45,0x34,0x59,0x4d,0xb0,0xb4,0xcc,0xc5,0xc6,0xe5,0xbb,0xa3,0x28,0x0b,0x87,0x3f,0x29,0x01,},"\xc1\x78\xe3\x8d\x4e\x83\xed\x2b\xe5\x7c\xe1\xc3\xab\x64\x25\x3a\x81\x71\xe6\x10\x00\x81\x81\xfb\xfc\x6d\x75\x22\x69\xf7\xf1\xc5\xa9\xec\x62\xcb\x27\xf1\x9a\xd9\x9c\xe1\xf5\x11\x6a\x36\x3d\x96\xfd\xc5\xa4\x2f\x35\x8b\x6d\xbe\x7c\xab\xdf\xc9\xf6\x07\x18\xe4\x01\x2c\x1b\xb1\xf8\x42\xc5\x56\x08\x11\xba\x83\x74\xa0\x63\x77\x47\xff\x92\xea\xc2\x1c\xa6\x5d\xde\xaf\x43\xe9\x98\x9b\x7d\xe2\xd4\x32\x52\x0a\xfe\xe3\x64\xec\xfb\xa4\xda\x66\x9a\xd4\x89\x3d\x0b\xf6\x9f\x9f\x81\xe7\xdf\x69\x65\x7b\xe2\x2b\x92\x06\x97\x45\xf2\x16\xc2\x42\xcc\xd4\x6d\x02\xd3\x56\x16\xe1\x6c\x75\x5e\x0e\x37\xf9\x61\xa6\xf3\x63\x77\x52\x53\x4f\x6d\xfa\xb8\x80\x5a\xb7\x59\xa0\x32\xa4\xe7\xe4\xc8\x19\x53\x32\x5a\x2f\x68\x6b\xb6\x9a\x02\x9c\xe4\xe0\x3b\xec\xb3\x60\x56\x37\xc5\xa6\x5b\x52\xe3\x31\xc2\x6c\x92\x6e\xd4\x71\x1a\x50\x4d\x37\x33\xbb\x53\xc9\x7b\x80\xea\xfe\x4e\x75\xdd\xd9\xf4\x15\x36\x28\x88\xc3\xd4\xd3\x7b\xae\x0e\x63\xfa\x11\xbf\x75\x56\x66\x43\x7d\x72\xf5\x8c\x91\xd7\xa2\xf8\xcb\x61\x9b\x76\x20\xa0\x70\xb2\x6b\x18\xb4\xd5\x01\x84\xc5\x81\x87\x12\x11\x0e\x36\xd3\xe2\x83\x0f\x6a\x85\x76\xba\x57\xf9\xcc\xcb\x8f\xff\x40\x28\xbf\x8e\xf9\xcb\x81\x48\x25\xbb\xca\x82\x7d\x64\x95\x47\xbf\x6f\x2b\xef\x93\x17\x04\xca\x7f\x6d\xf1\x5f\x78\x01\x55\xed\x46\xea\xa7\xca\x7d\x72\xe2\x24\x34\xca\x04\x83\xbf\xb2\xf7\x90\x2d\xc7\x87\xf6\x17\xeb\x9b\xd4\x1e\xd4\x52\x0a\xdf\xd4\x30\x94\x8c\x71\x08\x05\xa7\x3c\x1b\xa5\x49\x2e\x96\x48\x4c\x4b\xaa\x7d\xa2\x4c\x74\x35\xc4\x6a\x05\x2b\xf3\x51\x5d\x33\xe4\x2d\xce\xf5\x17\xca\xa4\x5f\x36\xc8\x79\x12\x10\x78\xc6\x88\xdd\x10\xd7\x66\x56\xa1\x19\x76\x2b\x6a\x83\x41\x36\xfa\x1f\x8a\x64\x32\x24\xb9\x22\x4c\x54\x3c\xf0\x47\x0b\x3f\x8e\xe0\x17\xd6\x20\xdb\xdc\xc8\x4d\x98\x51\x54\xe9\xd1\xae\x80\xe5\xf1\x43\x87\xb8\x8a\x0f\x6a\x5c\x35\x90\x5a\xa5\x7f\xb3\xab\xeb\x0e\xa6\xec\xcd\xdb\x00\x44\x74\x63\x3c\xc4\x83\xb5\x6b\x8a\x8e\x20\xe8\xf2\xe0\x9e\x97\x9a\xa0\x98\x93\x08\x78\x75\xc6\xb1\x17\xb5\xf1\x38\x47\xad\x8f\xc0\x56\x04\xc4"}, -{{0xc2,0x58,0x78,0xb0,0xd1,0xe0,0x92,0x5c,0x8f,0x5f,0x04,0xa1,0xe5,0x79,0x90,0x80,0x96,0x3c,0x41,0x3a,0x13,0x99,0xc1,0x18,0xaf,0xb1,0x68,0x7c,0x79,0x7f,0x48,0x39,},{0x13,0xac,0x2c,0xad,0x41,0x90,0x8c,0x25,0x5f,0x67,0x1f,0x93,0x93,0x4a,0xe5,0xd7,0xbe,0x32,0x53,0x46,0x72,0x5c,0x8b,0x40,0xdc,0x39,0xea,0x80,0xd7,0x0d,0xdf,0x34,},{0x06,0xf5,0x51,0x98,0xb4,0x19,0x19,0x14,0xb7,0x43,0x06,0xf3,0x8e,0x38,0x13,0x16,0xea,0xc4,0x0b,0x5b,0x5a,0xdb,0x8a,0x31,0x24,0x64,0xf6,0x71,0x75,0xec,0xf6,0x12,0xe0,0x14,0x7b,0x1c,0xef,0x46,0xc2,0x51,0x87,0x50,0xa5,0x60,0x6b,0xb0,0x3b,0xc6,0x46,0x7b,0xb9,0x32,0x15,0x14,0xf6,0x9d,0xcb,0xeb,0xce,0x8f,0x69,0x05,0x80,0x02,},"\x68\x56\xcc\x71\x44\xb6\xbd\xdc\xc4\xb5\x89\x54\xd1\xa2\xe7\x10\x1d\x65\x84\xb5\xd5\xe7\x19\xa0\xae\xa0\xfb\xbd\xf2\x21\xc2\xa2\xaa\xcb\xac\xdc\x40\x20\xc5\xc8\xce\x68\x1f\xf7\x38\x1a\xcd\x60\x7b\x0f\x52\x39\x69\x23\x35\x70\x06\x55\xbe\x2d\x94\xc5\x3d\x7b\x51\x48\xe9\x2a\x2b\xc1\x63\x38\xc2\xf4\xc1\xa7\xd1\xc5\x95\xaf\x62\x2c\x24\x0c\xe5\x79\xa5\xe0\xf5\xb6\x51\xbf\x56\x25\x18\xce\xc8\xaa\x2c\xe4\xb4\xaa\xdb\x1f\x2f\xda\x6c\xf6\x29\x5b\xc3\x78\x03\xb5\x37\x7d\xab\x65\xc9\xb9\xa2\x94\x9f\xdd\x49\xbf\x9d\xdc\x8f\x96\xd2\x60\xff\x95\x1b\xf8\xe8\xcc\xf9\x82\x7e\x68\x69\xc4\x4b\xfd\x97\x33\x58\xce\xfd\xb0\x10\xdb\x5e\x1f\xe5\xdb\xd9\xf5\xd2\xb2\xca\x39\x3c\x17\xd4\x46\xf6\x37\x05\x9e\x69\x2d\x7a\x91\xaa\xdc\xc7\x68\x9f\x5f\x9e\x1b\x30\x52\x17\x5d\x9b\x6b\x20\x8f\x90\x26\x78\x7f\xdb\x66\x78\x3f\x45\x37\x2a\x24\x94\x6b\x1b\xd1\x68\x7b\xf0\xcf\xcc\x81\x74\xeb\xe4\xd3\x2e\x43\x28\x4f\xc7\x8d\x78\x44\xde\x0f\xa2\x2e\x20\x65\xe0\x75\x28\xba\xab\xaf\x01\x5c\xb3\x4d\x62\x9c\x35\x96\xad\x04\x0d\xe3\x1c\x56\x20\xeb\x26\x6d\xef\xa7\x53\x3a\xc0\x40\x19\x98\xe5\x67\x3a\x75\x43\x65\x04\x7d\xeb\xfc\xf7\xe1\x37\xa2\x0d\x16\xcd\xd6\xa5\x52\x19\x82\xf4\x44\xcf\xc3\x42\x93\x97\xc6\x41\xbd\x7e\x74\xa7\x70\xbb\x11\xfc\xb2\x94\x83\xe3\x37\xba\xe5\x16\x9e\xe8\x2d\xa9\xa9\x1a\xdf\x3a\xf6\x7c\xd8\x14\xc2\x82\x5d\x29\x01\x8e\xf0\x35\xea\x86\xf8\xde\x4c\x75\x63\xaa\xf6\x6e\x0c\x75\xd1\x7c\xa6\x8f\x49\xf0\x75\x8e\xc2\xd9\xc5\x17\x9d\x01\xaa\xed\x7d\x45\x15\xe9\x1a\x22\x2b\x0b\x06\xfb\xde\x4f\x07\xa7\xd9\xdf\x2d\xe3\xbc\xae\x37\xca\x2c\x84\x60\xc2\xa6\xb3\x74\x9e\x9b\xda\x36\xd0\x8e\x66\xbc\xc3\x56\xb3\x90\x43\x4b\x4a\x18\xcf\xa4\x5a\xf5\x57\xdc\xa3\xd8\x57\xff\x3a\xd3\x47\xcf\xb0\x7e\x23\x58\xc2\xac\xfd\x5c\xd5\x3b\x3b\x0e\xa2\xa4\x1e\xe5\xc0\x80\x2f\xd4\x73\xdb\x5f\x30\x52\x63\x34\xda\x41\xeb\x4b\xc7\x51\x83\x83\x89\x8a\x0b\x75\x07\xad\x4c\xa2\x89\xd6\x6c\x5e\x2e\xb7\x5c\xf2\x55\xdf\xf3\x12\xcb\x1e\x04\xee\xbe\xb4\x7f\x29\x30\xb9\x0d\x5e\x00\x2e\xb0"}, -{{0x0b,0x2e,0xc6,0x27,0x63,0xf6,0x87,0x59,0x31,0x35,0xda,0x19,0x61,0xef,0x29,0xa2,0x88,0x08,0x96,0x96,0xd9,0x44,0xb2,0x65,0xa5,0xf9,0x68,0x93,0xcd,0x2d,0x82,0x25,},{0xc1,0xe2,0x34,0xfa,0x8b,0xc9,0x6d,0x26,0x8e,0x7a,0xad,0x02,0x8b,0x03,0xf0,0xa9,0x11,0xb6,0x97,0x71,0x5d,0xb3,0xa2,0x1c,0x2f,0xc7,0xdf,0x48,0xec,0xda,0x88,0x75,},{0xff,0x70,0x1f,0x34,0xb3,0x59,0x4d,0xe3,0xb8,0x00,0x45,0xf4,0x29,0xe5,0xe3,0x2d,0xd8,0x8d,0x60,0x51,0xd4,0x19,0x5f,0x16,0x85,0xbe,0x78,0x37,0x66,0xe8,0x01,0x19,0x36,0x8f,0x56,0xb3,0x74,0x97,0x25,0xb9,0x13,0xf1,0x22,0x3f,0x87,0xfb,0x0f,0xb2,0x4d,0x9d,0xfa,0x08,0x41,0xd6,0xa0,0xe2,0xeb,0x1f,0xdd,0xf7,0x75,0xc2,0xd2,0x05,},"\xa8\x34\x34\xc6\x86\x93\xd5\xfc\xed\x91\xbd\xa1\x02\x13\xfc\xd5\x0c\x48\x92\x0b\x90\xce\xe9\xb7\x3a\x9c\x61\x08\x1a\x09\x74\x93\x3f\x4f\xdb\x0a\x67\xe6\x71\xf8\x35\x1b\x0e\xd5\xec\x0f\xe7\xb5\xfb\x0c\x87\x58\x6f\xe5\x82\xff\xb1\xbf\xa2\xdb\x5f\xce\xdd\x33\x02\x42\x82\x34\xb2\xbb\x0e\x72\x6d\xed\xf4\x5b\x13\xa7\x0c\xd3\x5a\xb3\xe2\x99\xd1\x3f\x34\x50\x35\x08\x27\x8c\x44\x58\xee\xa5\xb7\x35\x1b\x05\x83\x6b\xda\xd5\xb0\x5f\x60\xe4\x45\xfc\x65\x73\x7a\xe2\x7d\x2e\x52\xdf\x9c\x39\xe5\xda\x02\x86\x39\x2d\x08\xff\xf7\xec\xb7\x06\x68\x20\xfc\x90\xfc\x8a\x44\xd5\x61\x65\x61\xc5\x0b\x52\x71\x47\x02\x30\x2b\xca\x58\x74\xde\x85\xdb\xa0\x45\x04\x5f\x9f\x0e\x60\x4e\xb8\x6d\x6d\x7f\xbd\x77\x5f\x72\xea\x49\x3b\x2c\x4e\xf7\xc3\xbe\x16\xdb\x2c\xa7\xe4\xd8\xbd\x79\xeb\x20\xcf\xb5\xf0\xf6\xf0\x53\x36\xb7\x5c\xc8\x6d\x21\x9f\x3b\x8f\x2e\x91\xba\x7d\x52\xb6\x4f\xdd\x6a\x66\x64\xf0\x4f\x2f\xba\xb7\x58\xcd\xf9\x84\x16\x86\x91\xc3\x2f\x53\xe8\x61\x6b\x49\xf7\x6a\xb7\xb1\x92\xb9\x00\x90\x30\x82\xcc\x89\x65\x6a\x97\x05\x80\x4c\xc9\xb9\x28\x8a\x3e\x42\x17\x09\x84\xf8\xdc\x45\x4e\x08\x64\xb9\x34\x16\x72\x68\x6a\x17\x8c\x06\x00\x50\x17\x8a\x36\xc6\xd9\x06\xb2\xce\x07\x0d\x8f\xaa\xac\xd9\xa5\x8c\x79\x4a\x5e\xa4\x10\x8b\x4a\x48\x5c\x65\x81\x1c\x2d\xca\x2e\xe7\xbb\x10\xbf\xff\xf7\x5d\x45\x86\xb9\x90\xf4\x37\x63\xa1\x6f\xbc\x0b\x48\xae\x1f\xaf\xb0\x8a\x9a\x36\xfa\x43\x26\x84\x5d\xba\x5b\xa2\xfb\xd3\x2b\xbf\x66\x50\x5c\x5e\x86\x57\xed\x01\x07\xe3\xe1\x61\x44\xef\x31\xfa\x6a\xae\x72\xe7\x74\x09\x74\x83\xf5\x48\x0a\xa4\x55\x40\x56\x8f\xd0\x8c\xba\x0d\x57\x77\x68\x00\x4f\x58\xae\x9b\x95\xbe\x37\x4e\xd7\xf0\x29\x9f\xe7\x21\x27\x5e\x47\x6e\x0b\x9a\xb7\x2d\xc0\x6e\xa3\x28\x38\x4e\x39\xbf\x3a\xc3\x31\xc6\x25\x48\x43\x12\xcd\x9b\x06\xb1\x5a\x29\x54\xd3\x3e\x7a\xab\xa6\xbe\x22\x61\x88\x6c\xa8\x11\xdb\x96\xb1\x14\x3d\x06\xdd\x6e\x0f\x3c\xba\x7a\x1a\xe9\xb9\x4e\xaf\x67\x77\x1b\xb2\xd2\x4e\x2f\x94\xde\x9c\x47\x0f\xcd\xe7\xbf\xdb\x32\xf4\x10\x19\x8b\x5a\xa9\x69\x8e\x32"}, -{{0x89,0x60,0xd7,0xbe,0xe8,0xc6,0xb3,0x9c,0xa5,0x93,0x4d,0x7c,0xdd,0xd1,0x6f,0x16,0xb3,0x66,0x3e,0x6e,0x03,0xe8,0x33,0xc0,0x57,0xe2,0x18,0x1e,0x45,0x97,0xcb,0x68,},{0x43,0x40,0x90,0x95,0xd4,0xf5,0x0f,0x5e,0xdd,0xbd,0x5c,0xd4,0xd2,0x01,0x22,0x98,0xcb,0x41,0xa4,0x0e,0x99,0x49,0x2d,0x5a,0x2d,0xb0,0x8b,0xe5,0x37,0x7e,0xa1,0x83,},{0x72,0x13,0xdd,0x4a,0x79,0xfd,0x54,0xde,0xc0,0xc5,0x48,0xef,0x42,0xe6,0xca,0xe0,0x15,0xbe,0x77,0x80,0x2b,0xf5,0x15,0xcd,0x25,0x82,0x76,0x8f,0x72,0xf5,0x63,0xeb,0xb2,0xda,0x36,0xaf,0x4a,0xae,0xac,0x56,0xbb,0xff,0xc9,0x93,0x2c,0x2e,0x24,0xec,0x95,0xda,0xff,0x00,0xa5,0xf7,0xa0,0xac,0xab,0x9c,0x8b,0xd3,0xc2,0x3b,0xb4,0x0c,},"\x30\x8d\x84\xc7\xa5\xf7\x86\xe5\x63\xe5\xc1\xea\x57\xaa\xb5\xe5\x55\xc0\x09\x97\x74\x9d\x15\xae\xe3\x54\x39\xef\xa6\x45\xda\x2c\x39\x67\x70\x31\x15\xc6\xc6\x3e\xd7\xf9\x47\x85\xc5\x47\x8f\x38\x46\x7b\x86\xe7\x62\x6e\x8f\xff\xa4\xd5\x1a\x2d\xc4\x5e\x6d\xf2\xa3\x5c\xec\x99\x55\x5e\xab\xc9\xf7\xa9\x3e\x2e\x2b\x68\x94\x59\xb4\xe0\xc9\x2b\x35\x15\x62\xc4\x17\xb1\x99\x71\x13\x75\x4e\xa5\x9e\x4a\x91\x51\x07\x28\xff\x30\x71\xa2\xbb\xd1\xf4\x65\xa6\x87\xf6\x7d\xae\x95\x56\x15\x03\x1a\x8a\xd5\x51\xfe\x73\x8a\x26\x0b\xbc\x44\x6b\x48\xdc\xa1\xd9\x79\x05\x1a\xb5\x84\x08\x32\xe1\x9d\x47\x3b\x66\x62\x17\xa9\x18\x39\x80\xd6\xb2\x7e\x3d\x3c\x76\xd9\x36\x65\xba\x23\x93\xe6\xab\x1a\x42\xc3\x90\x4d\x40\x25\x93\x2d\x60\x1a\x20\x2a\x59\xa4\xc4\x9f\xdb\x77\xf0\xe0\x28\x68\x24\x7d\xe5\xaf\xdf\xaa\x1b\x89\x42\x08\xac\x00\xd7\x7c\x6b\xb5\x4c\x6b\x2a\x73\xa4\x76\x57\xe4\x4c\x85\x13\x79\x63\xb5\x75\x21\xaf\x20\x97\x62\x48\xeb\x26\x14\x82\x14\x7c\xdf\x7a\x14\x5c\x36\x43\xe2\x9e\x05\x88\xbf\xda\xe6\xa0\x82\x90\x48\x53\xce\x5a\x10\xd2\x49\x70\xeb\xdf\xb7\xf5\x9d\x5e\xfd\xd6\xa5\xe7\xe0\xd2\x87\x97\x1c\x84\x6a\xcd\x54\xd8\x4d\xd4\x54\x68\xa4\x11\x0b\xab\x6e\xf8\xd9\xa5\xb4\xb2\x42\x67\x88\x90\x0b\x7e\x1a\xdf\xe0\x62\x43\x44\xf9\x8f\xe5\x9e\xf8\xa1\xe6\xc4\x05\xb3\x44\xeb\x97\xbb\x20\x47\x73\x74\x4b\x6a\x2d\x8c\x6e\x65\xd1\x7c\xea\x07\xde\x03\xb7\xf0\xfe\x49\xf1\xa5\x5c\x33\xd5\xf1\x5c\xe5\x5d\xf7\xc9\x56\x1b\x25\x1c\x6a\xc8\x07\xa9\x25\x53\xe1\xce\x91\x70\x12\xdc\xcf\xd6\x9e\x7d\xbd\x03\x8c\x7e\xee\xca\xe9\x86\x23\xf1\x8f\xbb\x65\x0e\x22\x18\xa0\xbc\x0f\xff\x43\xa7\x5a\x11\x64\x48\xbb\x73\x62\xf5\x27\xee\x6b\xc8\xe1\x07\x61\xcc\xcf\x9b\xcf\xc0\xd0\x00\xf2\x12\x7b\x4c\xc1\x92\x11\xd0\x95\xa0\xbd\xaa\x4e\x4b\xe4\x51\x9e\x6c\x84\x45\xea\xb9\xb3\x14\x4a\x45\xca\xb9\x99\x61\x35\xbf\x7f\x75\xa7\x8d\x22\x27\x59\x00\xf4\xce\x1f\x0a\x9e\xac\x13\x63\x64\x10\x30\x62\x89\x3d\xad\x43\x90\x42\x2b\x77\xe5\xf5\xd1\xd9\x4d\x70\x29\xc6\x09\x7b\x35\xca\x64\xa7\xa4\x76\xfc\xc7"}, -{{0xef,0x6b,0x9b,0x51,0xfd,0x4f,0x85,0x86,0xca,0x62,0x65,0x8e,0x04,0x2f,0xc0,0x9a,0x83,0xb9,0x43,0x03,0x35,0x26,0xff,0xc3,0x26,0xc6,0x5e,0xb3,0xa5,0xfb,0x59,0x4b,},{0x1d,0x6e,0xec,0xe8,0x05,0xe0,0x88,0x78,0x21,0x87,0x6b,0x7e,0xd6,0xed,0x5b,0x07,0x14,0xd6,0x46,0xfb,0xec,0xda,0x38,0x76,0x4f,0x94,0xc8,0x15,0x5e,0x61,0xd0,0x04,},{0x71,0xd1,0x71,0x07,0x1c,0xd0,0xfe,0xa1,0xc6,0xa9,0xcf,0xad,0x1f,0x7f,0xd8,0x35,0xe8,0x5f,0xf9,0x06,0x77,0x8b,0xc6,0x34,0x5a,0x4d,0xec,0x43,0x13,0xec,0xc2,0xbf,0xf7,0x55,0xa7,0x17,0xeb,0xd9,0x12,0xa5,0xe0,0x28,0x40,0xac,0x07,0x38,0x42,0xf9,0xbf,0xca,0xa5,0x89,0x13,0xe2,0x60,0xe3,0xc7,0x33,0x93,0xd3,0x66,0x85,0xc7,0x0e,},"\xa8\xf3\xf1\x96\x65\xde\x23\x90\xd5\xcc\x52\xb0\x64\xb4\x85\x12\x73\x67\x74\x86\xd8\xf5\x56\x3b\xb7\xc9\x5f\xa9\x4d\xb3\x35\x61\x61\xee\x62\x22\x21\xf1\x0c\xbb\x1f\xa1\x95\xaa\xc7\x23\x1e\xa7\x16\xd7\x4b\x46\xb3\x7b\xc8\x5a\x70\xdb\xa3\xdf\xaa\x16\x75\x21\x7b\x35\x11\x99\xe7\x4a\x97\x10\x28\xf7\x29\xb7\xae\x2b\x74\xae\x8c\x6b\x3a\x06\x79\xc3\xe3\x29\x68\x02\x84\x4a\xd5\xbb\xa3\x43\xf6\xf9\xf7\xc4\x66\x1b\x4a\x29\xb4\x4f\x17\xe8\x9e\x11\x4f\xb2\x20\xe9\x84\xcd\x98\x0e\x94\xc3\xd2\xbf\x98\x73\xe0\x60\x5c\x92\x30\x17\x44\xa3\x03\x5e\xf0\x46\xba\xd2\x66\x6b\x5c\x63\xeb\xec\xf9\x3c\xc1\x40\x29\x19\x46\xc0\xfa\x17\x03\x40\xce\x39\x50\x92\xde\xed\x79\x84\x13\x52\xfb\xfe\xe0\x3a\x92\x7e\xb4\x58\xf2\xa6\x33\xed\x32\x71\x65\x2f\x5b\x0f\x99\x60\xcd\xf9\x01\x5d\x56\xfd\xab\xd8\x9e\xe7\x1e\x25\x9a\xf6\xeb\x51\x4b\x4c\x1b\xd4\xa6\x66\xf5\xb5\xa3\x5c\x90\xf3\x5b\x14\x94\x57\xaf\x29\x44\xdd\x0a\xa8\xd9\xb5\x42\x28\x3a\x7e\x54\x12\xb7\x75\xe4\x21\xd2\x12\x6f\x89\xbe\xbc\x3c\xa3\x7f\x73\x07\x16\x21\xf1\x32\x1e\xee\x52\xe9\x69\x04\x86\xa3\x3c\xd7\xff\x9c\x99\x67\xfb\x65\xee\x4e\x90\x7b\x6b\x85\x22\x11\x47\x3d\x21\xe9\xd9\x1a\x93\x36\x2a\xc7\x61\x76\x0e\x8c\x7b\xbe\xa4\x86\xc3\xd6\x05\xf9\xe1\x1b\x86\x13\x68\x19\xa7\xab\x3f\x32\xf1\x3f\xfc\xa1\x68\x17\xfe\xd1\x97\xff\x88\x0b\x4d\x6d\x9a\x80\x8f\x7f\x87\x87\x63\xa0\x45\x72\x8d\xf7\x2f\xaa\xa9\x63\xe4\xcb\x1c\x09\xcc\x2b\x2d\xa9\x20\x28\x0c\x83\x66\xb7\xd1\x8b\xf8\x97\x2d\xf1\x6c\xc2\x34\x48\xfb\xe6\xb2\xe6\xe1\x6c\xbb\xf0\x74\x51\x29\x85\x40\x53\x18\x96\x37\xce\x11\x5d\x23\x98\x43\x3c\x15\xd6\xf1\x16\xa2\x05\x33\x48\x24\xaf\x28\x2f\xa7\x58\x49\x4c\x47\x86\x8e\xa8\xf4\xdf\xad\xc7\x05\xe8\x61\xaa\xd2\xeb\x8e\xf3\xdb\xbe\xd2\xa4\x56\x9e\x15\x83\x4a\x76\x0c\xce\x0c\xbb\xc8\x4b\x28\x9e\x77\x9b\x98\x83\x46\xb9\x06\x9c\x74\x4c\x97\xab\x2b\xf4\x2b\x08\x6d\x2f\xb0\xa4\x11\xf5\xce\x99\xf0\x81\x9a\x30\x86\xb4\xfe\x9d\x96\xc7\xc9\x90\x8d\xce\x28\xdf\x1d\xdd\x30\xf3\x50\x1d\xda\xf7\x81\x10\x73\x4f\x9d\xcd\xfe\xc3"}, -{{0xba,0xd4,0x7c,0xd4,0xbd,0x89,0x84,0x90,0x67,0xcc,0xe1,0xe6,0x3c,0x3d,0x91,0xe9,0xb7,0x87,0xae,0xa8,0x58,0x4e,0xdb,0x07,0xf3,0x45,0x1e,0xf6,0x7e,0x7b,0xd7,0x9b,},{0xab,0x0c,0xe9,0xba,0x1d,0x29,0xbd,0xfb,0x85,0xa0,0xe6,0x6b,0x76,0xb5,0xe2,0xe0,0x5f,0xf7,0x32,0x56,0x9e,0x43,0x75,0xcc,0xd7,0x50,0x98,0xe9,0xe7,0x1d,0x17,0xbf,},{0xe5,0x72,0x4a,0x1d,0xd4,0x63,0xa9,0x7d,0x12,0x22,0xc5,0x18,0xc4,0x92,0x5d,0x32,0x22,0x02,0xd1,0x0f,0x04,0xcd,0x07,0x8e,0x77,0x1e,0x0f,0xb3,0x95,0x1d,0xbc,0x14,0x93,0xa2,0x34,0x46,0x07,0x54,0xc3,0xaa,0xe3,0xdf,0x93,0x00,0x8d,0xbb,0xfb,0x31,0x0c,0x99,0x59,0x2b,0xed,0xe7,0x35,0xa4,0xae,0xab,0x03,0x23,0xa1,0x21,0x0d,0x0e,},"\xb5\xa6\x1e\x19\xe4\x86\x3e\x0b\xb5\xf3\xfa\xb6\xc4\x97\x0d\x87\x85\x96\x89\x55\x21\xfa\x1e\x7f\x67\x8c\xaf\xa2\xde\x53\x32\x2f\xd4\x58\xa9\x8a\xa6\xe3\x58\x05\x42\x9f\x65\x12\x91\xb9\x5b\xd9\x95\x0e\x15\x5f\x3a\xda\x0b\x60\x91\x59\xa4\xab\xda\x59\x90\xc0\x4b\xc2\xe7\x64\x42\x2f\xb4\x9e\xf4\x2f\x12\x52\x9f\xf6\xf6\xa8\x20\x29\xff\x01\x85\x66\x2e\x65\x8f\x83\xc5\x46\xee\xd0\x9f\x06\xb5\xa6\x8e\x85\x7c\xda\xd0\xeb\x9e\xc4\xee\xcb\xfd\x88\xf3\x4b\xc8\x09\x90\xf8\x64\x4a\x9b\xfd\xde\x1d\x9f\x3a\x90\xd5\x57\xa8\xb8\x28\xd5\xce\x06\xa6\x4e\x3b\x23\x85\x82\xbb\x4c\xbe\xba\x30\xed\xc4\x9e\x81\x22\xc5\x5e\x95\xba\xdc\xf5\x02\xcc\x56\x78\x69\xc0\x9e\x9f\x46\xc6\xff\x3f\x68\x78\x98\x6b\x1d\xe0\x0b\x72\xa1\x85\x80\x46\xfc\xd3\xa6\xe9\xcd\xaf\x5b\x07\x3c\x56\xf2\x02\x50\x63\xa2\xd1\x78\xbd\x4c\x1e\x8c\xbc\x1e\x6e\x67\x1a\xa9\x7f\xb2\xcb\x4c\xc8\xa6\x2c\x20\xbe\x41\xc7\x76\x37\x2c\x8e\x7b\xe6\x3b\x48\x2e\x6c\x63\xfa\x85\xd7\xcf\xfb\xc1\xb2\x82\x0b\xae\x1f\xc1\x28\x34\x3a\x1e\x20\xfc\xf1\xbc\x35\x02\xee\xe8\x13\x58\xcc\x9a\x74\xc7\x2a\xf6\x35\x30\xf9\x6a\x25\xa6\x04\x64\x8f\xf5\x70\xdf\x1e\xb8\x9d\x1f\xdd\xba\xb2\x86\x79\xba\x2e\x9b\x41\x97\x7e\x9a\x9c\x1c\xae\xcd\xbf\xc3\x61\xa1\xdd\x05\x5e\xc5\x16\x20\xa9\xbb\xdb\xba\xf7\x18\xc9\xcc\x13\x6d\x20\x07\x71\x03\x99\x53\x6d\x13\x33\x24\x85\xec\x38\x87\x97\x85\xe0\xc9\xce\x99\x15\xa8\x02\x51\x37\x39\x90\xa5\x9b\xce\x44\x03\x26\x03\x1a\xb1\xb4\x58\xbf\xa5\xb8\xa4\x79\x3d\xa4\xee\x11\xab\x7a\xf2\x0d\xe2\xa1\x18\xc9\xae\x52\x1a\x41\x7b\x68\x20\x7f\xc8\x85\xe1\x09\xd8\x46\x3e\x9f\x02\x27\x87\xcc\x73\x0d\xb0\xb1\xfa\xae\xd2\x57\xbe\xd9\x01\x71\x08\x85\xb7\x4e\x99\x4f\x54\xf6\xf2\xae\xb6\x4f\x0f\x60\xb5\x9e\xfb\xf2\xe3\xbb\x65\x15\x42\x46\x03\xa1\x13\xc0\xb8\xa3\x1b\xa3\xc1\xe9\xa9\xb8\x11\x8c\x87\xec\x69\x49\xb7\x5f\x49\x62\x7e\xa7\xb1\x32\x88\x89\x39\x11\x04\xd4\xf4\xa3\x89\x2c\xf0\x0f\x26\xa7\x3c\xda\x2a\x40\xf9\xb7\x15\x7a\xfc\x40\x66\x7f\x4a\x04\xf6\x47\xdb\xf9\x39\x06\xb8\x4c\x9a\x35\x16\x4e\x1b\xc9\x02"}, -{{0xca,0xba,0x8e,0x05,0x33,0x11,0x3a,0x4b,0xe1,0x73,0x40,0x8b,0xa8,0x3c,0x0d,0xb7,0x42,0x60,0x80,0x2f,0x91,0x86,0xc3,0x91,0x40,0x26,0x55,0xac,0xde,0x60,0x15,0xcb,},{0x2d,0x7b,0xef,0x61,0x64,0xc2,0x79,0xfa,0x10,0x28,0xa9,0x78,0x8e,0x3e,0x8e,0xe8,0xac,0x15,0xed,0xcf,0x92,0xa5,0x85,0x50,0x62,0x95,0x23,0x10,0xb4,0x68,0x45,0x47,},{0xec,0x35,0xec,0x32,0xc8,0xa4,0x00,0x88,0x27,0xe1,0x78,0x49,0x2b,0x3b,0x8b,0xee,0x22,0xa4,0x95,0x4f,0xc6,0xb2,0x5f,0x4f,0x22,0x5d,0xd7,0xed,0x23,0x69,0x89,0x00,0xde,0x81,0x56,0x75,0x6a,0x8e,0xdc,0x35,0xc5,0x1d,0x10,0xf8,0x2b,0x83,0x0a,0x2a,0x65,0x96,0x76,0xea,0xc9,0x11,0xf9,0x60,0x24,0x47,0x66,0xe0,0xc3,0xc6,0x07,0x05,},"\x24\x13\xa3\x2b\xca\x5c\xe6\xe2\x30\xe5\x65\xeb\x85\x84\x93\xd5\xd0\x4e\x6d\x2e\x2a\x7a\xb1\xf8\x9a\x3b\x42\x33\x11\x67\x6b\xfa\x93\xc6\x7d\xaa\xfd\x1c\xfc\x71\x09\xe0\x40\xba\xc5\x2c\xbf\xe0\x7c\x28\x28\x0b\xb6\xac\xf6\xe3\xa3\x10\x73\xda\xb2\x96\x53\x78\xdd\x77\xf6\x1f\xe9\x24\x71\x35\xc1\xa6\x31\xb7\x9a\xd6\x68\xc9\xea\x1c\xd4\x11\x2d\x8d\x3a\x06\x4c\xc2\x1d\xf3\x2a\xea\xc7\xdd\x71\x8b\x09\x1f\xb6\x91\x5b\x8b\xc0\x63\xbb\x58\x15\xc3\x76\xe0\x14\x76\x31\x2a\x2e\x54\x33\x41\x7a\x7a\x93\x15\xd6\x59\x99\xb0\x2f\xf4\x64\xa4\x74\xa5\x97\xe5\x39\x88\x77\x36\x70\xec\xa4\x6a\x6e\x26\xcf\x96\xe9\x48\x8e\x9e\x63\x44\xbc\x78\x3d\xdf\xb5\x35\xe7\x6b\xb3\xb9\xa6\x03\xff\x4c\x59\xc7\xdb\xe2\xd8\xb6\x19\x8d\x5b\x24\x49\x0b\x4e\xa9\x6c\x95\x95\x9f\xfb\xf3\xd8\x21\x8e\x76\x0d\xaf\x20\xe0\x1e\x2f\x36\xc8\x4b\xb0\x97\x11\x5a\xbd\xde\xe9\x2b\xed\x82\xd1\x6b\x15\xa9\xe1\x92\xe9\x89\x3a\xc6\x38\x46\x1d\xf5\x07\x20\x7b\x0c\xf5\x95\x88\x4d\x8a\x99\xfb\x9c\x70\x45\xf9\xbf\xf7\xb7\x3f\x00\xca\x3f\xd5\x95\xa5\xce\xc2\x92\xad\xb4\x58\xbd\x94\x63\xbe\x12\x04\xd0\x16\x78\xd2\xf4\x38\x9b\x87\x20\x11\x5f\xa5\x97\xc4\x02\xb4\xff\x69\x4b\x71\xce\x4f\x3d\x33\x0d\x5e\x2f\x3c\x3a\xd6\xd9\x6a\x9b\x34\x39\x23\x0f\xc5\x3a\x44\x79\x4c\xda\x59\x55\x57\xc4\x06\xca\x15\x89\xbc\x7b\xe8\x1e\x2d\x79\x63\x60\x33\x25\x3f\xa7\xbd\xd6\x00\xc6\x7f\xc5\x59\x36\xbd\x96\xce\x04\x28\xc3\xeb\x97\xba\xd1\xde\x0a\x5f\xbb\x9b\x67\x51\x57\xde\x5f\x18\xbc\x62\xa7\xc2\x2c\x94\x83\xe2\x80\x2e\x67\x9b\x5b\x8f\x89\xdb\x0f\xc3\x7f\x7c\x71\x50\xad\x5a\xc8\x72\x2c\xeb\x99\x9b\x24\x35\xe6\x99\x72\x17\x09\x23\x36\xef\x1c\x8a\x22\x92\xda\xb9\xa4\x6f\xf8\xa9\xe1\x0d\x33\x55\x76\x5c\xac\x9d\x65\x98\x77\x0f\x4f\x01\xea\x63\x91\x25\xfd\x03\x16\x09\xdd\x1a\x50\x7d\x96\x28\x0c\x7d\x01\xa3\xee\x98\x7e\x9b\x21\x0e\xc8\x74\x4c\xd4\x8c\x74\xf8\xaf\xee\x96\x1e\x8e\xf2\x21\xf8\x26\xa1\xfe\x6e\x7d\xf0\xcb\x15\xad\x7c\x7e\xf4\xa9\x1f\x9d\x0f\x4c\x2e\x1b\xde\xa6\x35\xd2\x75\xfa\xc8\xc4\xbc\x06\x01\xf4\x90\xdb\xdb\xc7\x34"}, -{{0x9b,0xf3,0xfb,0xc7,0x30,0x8b,0x46,0xf6,0x03,0x6b,0xad,0xe0,0xc3,0xca,0x19,0x9f,0xac,0x66,0x2b,0x07,0xf1,0x03,0xbf,0x75,0x18,0x1d,0x52,0xba,0x6a,0x58,0xbe,0x05,},{0x2f,0x6a,0xc6,0xfc,0x33,0xbc,0x06,0x0c,0x1d,0xc3,0xcb,0x9d,0x1a,0x2b,0x91,0x15,0x84,0x5a,0xdd,0xb1,0x6c,0x4b,0x84,0xbe,0x37,0xed,0x33,0xad,0xb3,0xb3,0xd3,0xa8,},{0x0c,0x31,0x36,0xe0,0x1f,0x9b,0xcd,0x99,0xe1,0x0d,0x3d,0x12,0x4b,0x0c,0xdb,0x07,0x72,0xbe,0xc1,0x8a,0x86,0x4b,0xe8,0x1b,0xd1,0xda,0xa4,0x4d,0x81,0x8c,0x3d,0x47,0x0d,0xfa,0xa8,0xab,0x6e,0x9a,0x76,0x1c,0xf0,0x3f,0x93,0xef,0x9c,0xc7,0x82,0x91,0x09,0x6e,0xd6,0xd1,0x0c,0x08,0xfa,0x2f,0xba,0x3b,0xac,0x04,0xdd,0xe2,0x0f,0x0c,},"\xd6\x5e\x36\xa6\xa3\x81\x95\xec\xb9\x1d\xe3\xc8\x48\xb5\x1f\x63\x92\x45\xfa\x2b\xab\xa8\xa6\xf8\x59\x47\x15\x9d\xec\x0e\xd3\xfa\xe8\x0c\x5a\x0f\x8c\x66\xff\x24\x79\x3c\x89\xc0\xc6\x87\x54\x3b\xc6\x33\x54\x7a\x1f\x37\xf7\x30\xd9\x70\x12\xeb\xbd\xc7\xac\x33\x9c\x48\x90\xc0\x85\x6b\xbf\xe2\xba\x29\xb2\x5a\x7a\xa6\xb0\x89\xc0\x33\xfe\xcb\x76\xdb\x62\xdd\x3c\x00\xf6\x42\x1b\x9e\x76\xdd\x0e\xa3\x66\xeb\x2d\x4a\x05\x2e\xe6\xcc\x73\x6e\x38\x19\x19\x1d\x5a\xd7\xa6\x6d\x2b\xe0\x42\xcc\x65\x39\xe5\xf3\x56\x52\xb1\x55\xa7\x27\xf3\x88\x8d\x93\xf9\x3a\x91\x02\x59\x8f\x75\x38\xa9\xab\x7c\x77\x7e\xec\x79\x42\x6a\x60\x75\xd6\xf3\x8d\x64\xc4\x85\x52\x0f\x64\x13\xff\x4d\x35\x8a\x8a\x9c\xbd\xab\x01\xad\xf4\xdb\x02\xad\xae\xa2\x64\x94\xd1\xf5\xd6\x17\x63\x7f\x27\x7f\x8b\x0e\x6e\x7e\x61\xe2\xee\xcc\xdd\x33\x7d\xe2\xba\xf0\xca\x26\x4c\x14\xc8\xcb\x83\x68\x00\x0b\x9c\x71\x43\x85\xf4\x13\x73\x7d\x68\x16\xe2\x12\xca\xe2\xae\xcf\xff\xc3\x2f\xd1\x6d\x46\xc3\xec\xee\x6a\xb0\x74\xc0\xd7\x68\xbd\xfe\x99\xb8\x6c\xbb\xc8\xdf\x9c\x47\xcd\x58\x6d\x46\x58\x71\x26\x8d\x4a\x9d\x1c\x87\x72\x36\xab\x78\xf8\x85\x9c\x11\x4e\x25\x1c\xab\xc4\xbe\x0f\x8b\xc2\x5d\x14\x8c\x5f\x54\x3e\x29\x07\x45\xd1\x18\x03\xe4\x9f\x5b\x53\x19\x3f\xe3\x99\x69\xc0\x39\xb3\xf2\x49\xb3\x2f\x2b\x85\x98\xb6\xac\xf4\xed\x64\xd5\x75\x2b\xb7\x72\xff\x4e\xe0\x0c\xe0\xf8\x5e\xcb\xb4\xcf\xc4\xce\x07\xda\xf2\x80\x98\x68\xc2\x90\x3b\x78\x1e\x12\xa2\x74\x10\x5f\x06\x18\x10\x29\xe4\x7f\x2b\xfb\x21\xf4\x94\x80\xaa\x1e\x44\x47\x15\xc0\xb9\xff\x07\xea\xd8\x89\x75\xd9\x35\x85\xd2\xff\x42\x48\x32\xa9\x78\x3d\x94\x90\x6a\x60\xf8\x77\xae\x1c\x85\xff\x15\x31\x7b\xad\xca\x1e\x61\x31\x74\x33\xc7\xce\x96\x27\x9b\x67\x8e\xc9\xd1\x74\xdd\x08\x70\x08\x0b\x23\x41\x54\xf6\x26\xa5\x34\x62\xcf\xd5\x47\x84\x2e\xab\x87\x05\x60\x5b\x8e\xe8\x85\x72\x9e\xe7\x8d\x18\x33\xaa\x43\xf5\x5a\xc2\x27\x31\x98\x9f\xde\xda\x7d\xc5\xfa\x9c\x01\x98\x5f\x26\x61\xe6\xc7\x32\x6d\x34\x6e\x6d\xb2\x7e\x6f\x92\x1f\xae\x7c\x93\xa2\x17\x0e\x10\xdd\x0c\x46\x0b\xdc"}, -{{0x64,0xe8,0x93,0x04,0xa3,0x35,0xe9,0x03,0xcb,0x36,0xc0,0xbd,0xf1,0xa6,0x41,0x2e,0xf3,0x68,0x46,0x80,0x06,0xb7,0x3d,0x3d,0x2d,0x61,0xcb,0x03,0x0c,0xc5,0xf8,0xd1,},{0xa1,0x80,0xef,0x3a,0x66,0x1c,0x3c,0x47,0x9d,0x5f,0x69,0x80,0x7c,0x90,0x27,0x48,0xe3,0x5e,0x7f,0x72,0x51,0x21,0xe3,0x7a,0x5d,0x91,0xb8,0xbe,0xc8,0x8d,0x83,0xa6,},{0x92,0xeb,0x44,0x54,0x81,0x40,0x01,0xec,0xfc,0x18,0x02,0x5d,0x64,0x21,0xf6,0x46,0x45,0xa5,0xbc,0xbb,0x5c,0xb8,0xfd,0x85,0xc1,0x4d,0x77,0x26,0x17,0xc5,0x03,0xe8,0xbe,0x7d,0x3b,0xcf,0x11,0x7f,0x5e,0x68,0x01,0xd1,0xc3,0xb9,0x6f,0x90,0x90,0xa6,0x6d,0xdc,0x67,0xf8,0xcf,0x8f,0xf0,0xf1,0xc1,0x25,0xb1,0x6b,0x15,0xe2,0xce,0x07,},"\x2f\x51\x07\x4d\x98\x1b\xda\xfa\xfb\x02\xa4\x0f\xe8\x26\xc4\x5f\x31\x71\xc1\xb3\x18\x4d\x8c\x26\x0b\x82\xb8\x41\x1f\xc6\x25\xcb\x02\xcc\xfe\x75\x5d\xc2\x9d\xc7\x89\x5b\xf7\x59\xe6\x1b\x24\x50\xda\x1a\x65\x6a\x38\xd4\xf7\x0d\x2e\xe7\x48\xc5\x18\xc6\x42\x03\x06\xe5\xf0\x1e\xc7\xa0\xff\xe0\xe9\xdc\xeb\x93\xf6\xc0\x77\xb1\x26\x62\x88\x15\x84\xf9\x8c\xe6\xab\x94\x5f\x87\xfc\x6d\x12\x3c\x45\xd6\xcd\xfd\x82\x37\xa1\xce\x36\x35\xb6\x23\xa7\x9d\x02\x0d\xf4\x4c\x74\xb8\x9a\xc1\x4a\x32\x1f\xbf\x33\xa8\xc0\xa2\x55\x9f\xea\x1c\x2b\x15\x60\x76\xb8\x13\x90\x8f\x84\x2e\xbe\x4c\x2b\x94\x90\x89\xe5\x2b\x1a\xe4\x0d\xc6\xe4\xb2\xab\xbc\x43\x9a\x0b\xf7\x23\x69\x67\x9a\xab\x6f\x4c\x00\x01\x8b\xe1\x47\xf7\xc0\xa6\x7b\x96\x79\xee\x88\xa5\x38\x19\xc4\x9f\x7b\x67\x5e\x30\xa8\xb5\xaf\x39\x66\x1e\xe8\xdb\x21\x01\x04\x11\x29\x49\x68\xf8\x8e\x5d\x60\x4d\x0d\x88\xd7\x6a\x7e\x48\x64\xfa\xd3\xa5\x6f\x5f\x62\x4b\xa1\xb3\x4e\xa9\xcb\x72\x08\x50\xaa\xd3\xbd\x4f\x0a\x88\x2a\x7d\x25\xfb\xec\x2b\xb7\xca\x86\xda\x61\x6d\xa9\x6c\x15\x62\xc6\xd6\xa1\xab\xcc\x64\x1e\x1b\x58\xb2\xc1\x78\xe1\xc3\xbc\x8a\x3b\x36\xec\x9e\x14\x4d\xd2\xe7\x5b\x0b\xc8\xc0\x8c\xcb\x0d\x6e\x34\x27\xb0\x32\x2b\x3d\x6a\xb9\x3f\x3f\x60\xb9\xcc\x5b\x61\xda\xd0\x23\x85\xa1\x49\x49\xf9\xb8\x7a\x8e\x3a\xf1\xe0\xe0\xfa\xb7\xa9\xa9\x28\xc7\x53\xfc\x61\x10\x44\x4a\xf7\xcc\xaf\x80\x27\xed\x64\x1b\x9e\xd8\x7f\xa5\xd8\xe1\xf7\x6c\xae\x46\x5d\x57\xa7\x0d\xad\x9e\xbf\xdd\x3c\xe7\x57\x6a\xc4\xde\x89\xd9\x8f\x42\xe2\x82\xad\x87\xad\x6a\x50\x42\x57\x7c\xbb\xbc\x4d\x95\x1e\x2a\x86\x76\xfe\xdc\x8c\xb1\xb1\xbd\xf7\x6c\x3a\x38\x84\x63\x85\xa8\x5a\xa2\x47\x06\xc2\x0a\x8b\x38\x46\x5f\xe2\xae\x0e\x41\xf7\x8e\x61\x4b\x8e\x96\x42\xfe\x24\x71\xa9\x01\x57\x47\xdb\x97\x6e\x0c\x78\x48\xc2\x3f\xf3\xf4\x17\xcb\x05\xa8\xd5\xef\x40\x13\x0a\xdf\x85\x5c\x99\x8a\x62\x10\x4d\x7e\x2f\xb7\xc0\xf9\xaa\x2a\x49\x60\x75\x62\x3c\xed\x2c\x0f\x7e\xec\x10\x14\x7f\xf9\x60\x8a\x8a\x04\x2e\xf9\x81\x17\x45\x9b\x93\x83\x7f\xd1\xb8\xd5\xef\x03\x97\x8e\xad\xa7\x4c\xac"}, -{{0x6f,0x63,0x43,0x87,0xca,0x2c,0x0c,0xb1,0x67,0xa7,0x40,0xd6,0xaf,0xd8,0x9e,0x2a,0x28,0xf5,0x30,0x71,0x84,0xe8,0x1c,0xba,0x3c,0x03,0x70,0x46,0xa5,0xed,0xe2,0x3c,},{0x01,0x1f,0x2a,0x9a,0x11,0x1c,0x38,0xf3,0x49,0x0c,0xad,0x16,0x85,0xbe,0x78,0xec,0xee,0xdc,0x6f,0xac,0x4a,0x32,0x21,0x30,0x1c,0x69,0xc8,0x4b,0x1e,0xc7,0xb3,0xa7,},{0xfd,0x17,0xc6,0x18,0xcd,0xbb,0x5d,0x45,0x9e,0xa2,0xac,0xa8,0x86,0xf0,0x51,0x2c,0x62,0x32,0x51,0x28,0x4a,0xae,0x3a,0x83,0xeb,0x5d,0x7f,0x60,0xda,0x1d,0x9b,0x2b,0xa0,0x83,0xc4,0x55,0xa5,0xe2,0x58,0x3a,0x3c,0xba,0x73,0x6e,0x7b,0x96,0x1b,0xa1,0x9c,0x1c,0xc8,0xdd,0x90,0x74,0x5d,0xa8,0x2a,0x15,0xdf,0xc6,0x62,0xe8,0xe1,0x0d,},"\x86\x5c\x20\xa9\x4a\xc3\xf2\xe3\xbd\x5c\xb8\x5b\xec\x9d\x33\x72\x66\x71\xfe\x01\xf9\xc5\x37\x01\x7d\x59\xc8\xd5\x10\x6e\x43\x36\x0b\xf7\x6f\xc0\x61\x86\x70\x59\x80\xc8\xa8\x7b\xa3\x63\x3a\x4a\x17\x04\x26\xec\xc0\xde\xfb\x6d\xb2\x67\x0f\x5f\x59\x25\x33\x77\x4c\xda\x50\x05\x2a\xe5\x97\xd4\x8d\xea\xcc\x26\x37\x06\x3b\xfd\x51\x9f\x2e\x79\xba\xc8\x17\x75\xbe\xcc\xb1\xab\x2f\x5b\x39\x71\x2e\x2e\x82\x94\x69\xb7\x5a\x2d\x2d\xbd\x08\xaa\x6d\x24\x72\x34\x04\xb2\x5e\xb9\x48\xa4\x83\x4c\x55\x24\x6c\x80\x79\xa8\x2e\xc6\x43\x54\xe8\xc2\x38\x8f\x8c\x5a\x61\x6b\x3c\xdc\x37\x1e\x62\x63\xfa\xbc\x9f\x60\x99\x21\x9e\x86\x15\x85\xfe\x82\xa6\x7d\x61\x0d\xd1\xeb\x5c\x81\xc9\x6b\x5c\xb3\x54\xa6\x89\xfd\x8a\xac\x8d\xb7\x6c\x43\x3f\x0c\xb0\xb3\x1c\xf1\xd8\x55\xb6\xa3\x0a\x3d\x2a\x21\x2e\x9b\x4f\x7d\x7a\xfe\x61\x99\x51\xf9\x8d\x2f\x1b\xa2\xc1\x01\x08\x5b\xa8\x1f\x49\xb3\x60\x37\xcd\x64\x57\xa7\xea\xa8\xf4\xf3\xbe\xdf\x68\xd0\x9f\xc9\xfa\x25\xa9\xd7\x54\xdb\x65\x36\x02\x85\x41\x2d\x1a\x6d\xa5\x37\x88\x90\x5f\xcf\x4e\xfa\x8a\x80\xcd\x86\xca\x48\xb8\x45\x63\x3d\x8c\x31\xc2\xae\x06\xf1\x6c\x4c\x6b\xbb\xe9\xcd\x1a\xfb\x59\xe1\x01\xbe\x50\xe0\x35\x35\xdd\x8a\x65\xe4\x5b\xba\x46\xd4\x5c\xb1\x4b\xad\xfc\x8e\x93\xab\x52\x67\xf4\xe4\x92\xab\x1f\x9a\x95\xe6\x1f\xca\xb8\x1c\xbf\x2b\xd8\x67\xa3\xec\x7b\x4b\xaa\x18\x9a\x0f\x08\x56\x70\x75\x59\x61\x29\xdc\xf9\xff\x1c\x50\x2d\x32\x79\xe8\xaa\x6c\xe5\x6e\xaf\x13\x45\x82\xa9\xe4\x30\xa5\xaa\x8c\xa1\x0c\x3d\xa8\xbc\x79\x3d\x02\x56\xad\x19\xae\xa7\x14\x9f\x0e\xa7\xea\x95\xfa\xcf\xac\x1c\x5c\xfd\x29\xd7\xa3\xfe\x1a\x41\x79\x75\x73\x9e\x14\xda\x8e\xdc\x81\x99\x00\x47\x2c\xa8\xc6\x97\x16\x32\x8e\x8a\x29\x9f\x97\x4e\xdf\xf7\x41\xaa\xbc\x1c\x07\x4a\x76\x1b\x3e\xc8\x76\x1d\xda\x2e\x7e\xed\x7a\xf3\x3e\xf0\x04\x09\x84\x9d\x41\x54\x97\xc5\xed\x5d\xfa\xa2\x25\x9a\x31\xd0\x76\x39\x81\x70\xb2\xd9\xd2\x10\x20\x8b\x4a\x4c\x7d\xb8\xc6\x26\xd1\xc5\x33\x56\x2a\x1f\x95\x48\x9f\x98\x19\xe4\x98\x5f\xc4\xe1\xd1\xa7\x07\xbe\x5e\x82\xb0\x05\x48\x1d\x86\x37\x7f\x42\x4e"}, -{{0x4b,0x2e,0x1a,0xe6,0x0f,0xa5,0xd3,0x83,0xba,0xba,0x54,0xed,0xc1,0x68,0xb9,0xb0,0x5e,0x0d,0x05,0xee,0x9c,0x18,0x13,0x21,0xdb,0xfd,0xdd,0x19,0x83,0x95,0x91,0x54,},{0x36,0xc0,0x20,0xb1,0x85,0x52,0x34,0x56,0x19,0xef,0x88,0x37,0xeb,0x8d,0x54,0x94,0x84,0x0e,0x85,0xf4,0x68,0x09,0x34,0x3b,0x4d,0x6f,0x40,0x61,0x25,0xda,0x55,0x7d,},{0x22,0x20,0x11,0x9e,0x83,0xd6,0x9a,0x6a,0x3e,0xed,0x95,0xfa,0x16,0x6d,0x1d,0x11,0x28,0xa3,0xf2,0x32,0xca,0x1b,0x78,0xbc,0x94,0xb4,0xd4,0x76,0xc4,0x77,0x94,0x43,0x61,0x4b,0x87,0x72,0xaa,0x22,0x32,0xcb,0x07,0x20,0xa0,0x55,0xeb,0x71,0xd8,0x40,0x7f,0x3a,0xb1,0x9b,0xaa,0x1d,0x96,0x2c,0x05,0x2c,0x84,0xc0,0xbd,0x58,0x96,0x08,},"\xfa\xb9\x8b\x2b\xbf\x86\xae\xb0\x50\x86\x81\x2a\x4b\x00\x49\xa1\x04\x2a\xbb\x76\xdf\x9c\xd2\x90\x87\x55\x70\x63\x03\xef\xed\xb1\xad\x21\xe8\xbc\x8d\x75\x62\x34\x9e\x1e\x98\xce\x0d\x75\x2f\x4b\x3d\x99\xe6\x77\x36\x8b\xd0\x8c\x78\xfe\x74\x25\xec\x3b\x56\x0e\x38\x3b\xd4\x2a\xf6\x49\x98\x86\xc3\x5a\xdd\x80\xa5\x82\x8b\x61\xd6\x64\x4d\x7d\xc4\x43\xba\x2c\x06\xf9\xba\xd2\xec\xcb\x98\x3d\x24\x45\x8f\x6a\xda\x1b\x10\xbb\x5b\x77\x17\x2c\x5c\xdd\x56\xd2\x73\xd1\xe4\x10\x10\xb2\x5c\xf4\x8a\x7d\x58\xd7\x25\x57\x02\xac\x12\xf2\xa6\xfe\x29\x18\x46\x63\x95\xf4\x60\xd1\x52\x36\xd0\x35\xae\x94\x10\xca\x86\xc4\x60\x51\x28\x29\x9f\xaa\xf0\x90\x15\xf1\xad\xee\x77\x68\xee\x1a\x8f\x8c\xa0\x6d\x10\xdd\x7f\x95\xc4\x6f\xa1\x02\x53\x06\x5f\x9d\x6f\x90\x29\x59\x08\x80\x9f\xd7\x79\x57\x1b\xe2\x9e\x0a\xe6\x6e\x0b\xcb\xde\xb7\x91\x3d\x2b\xbb\x76\xac\x30\x2f\x34\x52\xc5\x5e\xf1\x99\xa4\x8e\xce\xb0\xe3\x59\x6c\x7b\x4c\x03\x86\xda\xe7\x10\x1e\xa2\x44\xa3\x3c\x4c\xdc\x83\x06\x72\xdf\x83\x65\x5b\x35\x33\x80\x52\x30\x7b\x94\xd2\x23\xca\xb1\xaf\x69\xe0\x7f\x78\xe5\x8c\xbb\x0c\xb3\xc5\x35\x1e\x3a\x6b\x0c\x4a\x92\x7f\x75\x62\xc5\x98\xd2\xd3\xdf\x90\x56\x9f\x61\xdb\x1a\x3c\xb0\x14\x0b\x56\xea\x02\xcf\x77\x45\xfb\xee\xc2\x02\x86\x73\xd6\x7f\x1e\xc5\xf7\xda\xf9\x71\x5f\x75\x4a\x9d\x8e\xd4\x6a\x7a\x63\xef\x72\x2e\xe0\xd5\x89\x93\x31\xb6\x3c\x97\x4f\xa8\x80\x42\x94\x35\x76\x7f\x96\x25\x4e\xf4\x6c\x99\x68\xf3\xfe\xda\xaf\xea\xf3\xe8\xf4\x56\x34\xb5\x4f\x5e\x0a\x5f\xc2\xd2\x37\x3a\xb9\xe9\x8d\x9a\xcf\xe3\x69\x7e\x64\x2a\x18\xe0\xdf\xd9\xfb\xc2\xf0\x94\x86\x6d\x40\x1f\x0a\x4c\xa2\xa4\x56\xed\xf6\xa1\xa7\x7b\x9c\x29\x6c\x39\x22\x06\x7e\xb3\xd5\xa5\xca\x0a\x77\xf4\x30\xe4\xc8\x61\x1d\x8f\x05\xa1\xba\xac\x16\x35\xef\x7b\xa8\x3d\xfc\x69\xd3\x01\x94\x98\x56\xbe\x4d\x2c\x8a\xb6\x1d\xe2\x9c\xf3\x92\x50\xc5\x79\x4c\xbf\x57\x50\xcd\xa9\x5d\x04\x68\xaf\xa2\xb7\xf2\x3d\xba\x4e\xf5\xf5\x29\x5a\x3b\xf4\x14\x00\x18\xb7\xed\x06\x18\x84\x44\x4f\x5b\xb1\xb7\xd2\x39\x31\x2d\xd7\x39\x99\x95\x36\xc6\x84\x45\x6e\xa0\x6b"}, -{{0xb2,0x16,0xce,0xbf,0x87,0x80,0x24,0xc2,0x0d,0xfc,0x86,0xce,0x4b,0x37,0xbd,0xc4,0x7a,0xa2,0x8f,0x29,0x20,0x3b,0x5b,0x44,0x92,0x50,0x65,0xd9,0x93,0xa2,0x59,0xfe,},{0xc3,0x6e,0xdb,0xb6,0x25,0x4a,0x91,0x3f,0x08,0xfe,0x25,0x9e,0x23,0x87,0x80,0x63,0x8f,0x72,0xec,0x0b,0x30,0x07,0x26,0x4b,0xcc,0x60,0xa9,0xe8,0x1e,0xe9,0x29,0x8f,},{0xb7,0x38,0x9e,0xe7,0x8d,0xd9,0x76,0x3f,0x9d,0x28,0x92,0x91,0x2e,0xdc,0xbe,0x3e,0x8a,0x23,0x6b,0x8b,0xdc,0x25,0xf4,0x4b,0x9c,0xfd,0xc8,0xc4,0x7c,0xd5,0x81,0x68,0xab,0x56,0xeb,0x04,0x02,0xa5,0xbd,0x75,0x2a,0xc8,0xf4,0x97,0x8d,0x2e,0xa2,0xb6,0x5d,0x2f,0xa8,0x52,0x65,0x96,0x6b,0x9f,0x57,0x22,0x7e,0xf4,0xa5,0x9a,0xe0,0x09,},"\x9c\x87\x17\xcc\x86\xfe\x02\x48\x0b\xfd\x9e\x92\x2b\xd7\x6b\xff\xee\x21\x70\xc4\xcb\x1b\x13\xdf\x83\x4a\xc0\x1d\x45\x00\x60\x86\x29\x7f\x1b\x8a\x26\xf2\xba\x67\x4d\x33\xe1\xd1\x62\xf1\x93\x67\xfe\xba\x97\x35\x2b\x7d\xf2\xe7\x5b\x30\x9d\x4b\x6f\x8b\x07\xcc\x0e\xb6\x77\x7e\x81\xe2\x68\xe0\x2d\x07\xf2\xa0\x8f\x8f\x39\xd5\xa8\x32\x0b\xfc\x01\xfc\x8c\x92\x27\xd2\xcf\x05\xe1\x28\x91\xff\x4d\xe8\x85\xa1\xc9\x33\x71\xa0\x91\x0b\xa5\x33\x92\xaf\xf9\xba\x2e\xed\x9a\x20\x55\x97\x7e\xc4\x15\x7b\xd6\x5b\x34\xdf\x79\x37\x2f\x4d\x50\xed\xbc\x48\x92\x43\x53\xcf\xa1\x69\x23\x19\xd8\x8a\x7a\x5b\xb7\x26\x25\x4c\x20\x92\x91\xe9\xb1\xd2\xc1\xa6\xc8\x23\x63\x98\x10\x9c\x59\xed\x42\xa0\xac\x9e\x76\x33\xc5\x20\x73\x4e\xcc\xfe\xa4\xfe\xa9\x5a\x47\xa8\xf0\xa0\x68\xb4\x27\x50\x00\x43\x9c\xc9\x7c\x57\x87\x1e\x10\x5c\xc0\x79\x0e\x9d\xcc\x9c\x25\xd5\xaf\x70\x63\xff\xd0\x5c\x4f\x37\x80\xe7\xbc\xa4\xc4\x56\xd0\x17\x0d\xa7\x09\xfc\x6c\xb3\xfa\xa7\x2b\xdc\xf5\x62\x90\x8a\xe9\x34\x0a\xef\x4d\x0c\x8b\x91\xf0\xfb\xcc\xbc\xf1\xcd\x89\x8b\x1c\x71\x6f\x4f\x14\x74\xc3\xaa\x31\x62\x42\xab\xdf\x63\x68\xe5\x7a\x24\x7f\xf2\xfd\x5c\xe2\x3d\x18\x7f\x69\x4f\x11\xe3\x8d\xfb\xfb\xc3\xd9\xdb\x20\x90\x3b\x4e\xbb\x44\x9b\x90\x49\xee\x02\x0f\x6e\x2f\x50\x8e\x8b\x2b\x16\x5b\xad\x74\x64\xdb\xdd\x17\x8c\xbd\x42\x32\x33\x76\x5d\x37\x1e\x7a\xe1\xc3\xe8\x78\xcd\xb5\xb8\x24\xb2\x0c\xb3\x09\x86\x7c\x0e\x47\x3c\x06\x7e\x67\x44\x00\x85\x27\xb6\xbc\x07\x6d\x07\x7f\x48\x67\x62\x2a\xee\xd1\xc2\x53\xdb\xde\x7c\x6a\x76\xc7\x01\x59\x62\xfb\x73\x39\x16\x98\x60\x0b\xb3\x18\xff\xa7\xb0\x13\x6e\xe4\xcc\xb0\x7d\xaa\xf0\x1f\x40\xff\x9c\x19\x4f\x98\x68\x1f\x9f\xae\xf8\xb6\xf9\xe9\x9f\x95\xdf\x00\x80\xda\x89\x66\xa8\xba\x7a\x94\x74\xc5\x37\xb9\x2d\xf9\x79\x9e\x2f\xd1\x6f\x78\x8d\xad\x7a\x7b\xcc\x74\x52\x26\xe1\xe6\x37\x1f\x52\xeb\xcd\xbd\x14\x40\x44\xdd\xfe\x63\x2d\xfc\x0a\x43\xd3\xa4\x50\x92\x31\x70\xeb\xc7\xae\x21\x9e\x50\xe0\x78\xa5\x11\xbc\x12\xef\x14\xcd\x14\xb5\x30\x9f\x38\xab\xd6\x5d\xb2\xb2\xa7\xaf\x22\x43\xb2\x29\xc9\xfd\x2e"}, -{{0xaf,0xce,0xce,0xa9,0x24,0x39,0xe4,0x4a,0x43,0xed,0x61,0xb6,0x73,0x04,0x3d,0xcb,0xc4,0xe3,0x60,0xf2,0xf3,0x0c,0xd0,0x78,0x96,0xcd,0xa2,0x0c,0xb9,0x88,0xd4,0xe3,},{0xd2,0x31,0xf6,0x92,0x35,0xa2,0xe3,0xa1,0xdd,0x5f,0x6c,0x2a,0x9a,0xaf,0x20,0xc0,0x34,0x54,0xb9,0xa2,0x9f,0x4e,0x3a,0x29,0xab,0x94,0x68,0x9d,0x0d,0x72,0x3e,0x50,},{0xa6,0x55,0x45,0xcf,0x3d,0xf4,0x56,0xb2,0x8d,0x83,0xa6,0xd9,0x4c,0x03,0x6a,0x19,0xd0,0xd2,0x9f,0xb0,0x65,0xed,0xc2,0x7e,0x5e,0x93,0xa1,0xf4,0x02,0x79,0x89,0x7e,0x1c,0x6f,0x25,0x95,0x9a,0x72,0x5a,0xba,0xbc,0x87,0xcf,0x2a,0xe7,0x27,0xf3,0x46,0x7b,0x79,0x57,0x0e,0x90,0x27,0x11,0x91,0x71,0x91,0xd9,0xcb,0x0d,0x2d,0x66,0x0c,},"\x0b\x05\xf8\x9e\xbb\x33\x97\x94\x76\x87\xaf\xbe\xf0\xed\xe8\x7c\xf3\x81\x06\x76\x27\x70\x37\x52\x1d\x95\x2a\x3b\xbb\xbd\xc8\x56\x59\x88\xa0\x95\xd8\xd4\xf6\xf5\x9b\xe5\x72\xd3\xd8\x21\xdd\x78\x99\x77\xef\x77\xa2\xfd\x71\x10\xce\xee\xd9\xf3\x75\x6e\xd8\xe1\x88\x26\x7b\x97\xa3\x0e\xf8\x95\x7c\x78\xae\xa3\xa2\x96\x3d\xec\xa6\x18\x60\x54\x5e\x0c\x40\x82\x48\x81\xeb\xb1\xdb\x10\xf6\x07\xe1\x0d\xdb\xdd\xce\x40\x0e\xa2\x36\xba\x47\x45\xaa\x99\xa0\x56\x41\x97\x67\x66\x78\x9e\xd0\xda\x7d\xb5\x5f\xda\xb4\x59\xeb\xd4\xb4\x41\xa6\x28\x2f\x7c\xfd\x5a\x20\xea\x06\xef\xfa\x33\x59\x55\xe5\xfd\x29\x18\x16\x71\xbc\x92\xc0\x00\x52\xf7\xf7\x5c\x39\x27\x7c\x9a\x43\xb7\x87\xac\x9f\xb1\x51\x6e\x99\x62\x32\xa5\x09\x77\x4d\x1d\xc2\x1d\x8c\x05\x13\xf7\x84\x4b\x0a\x5b\x5f\x18\x95\x75\x81\xf9\x90\x44\xa1\x42\x23\xcc\xda\x8a\x28\x4d\xe1\x2f\xd4\x24\x26\x5f\xe5\x7b\x27\x02\x15\xf8\xfa\x9f\xf2\xbe\xa5\x17\x93\x4e\x48\x00\xa4\x7d\x34\x6f\xb6\xc3\x61\xcf\xba\xbe\xff\xab\xd9\xc4\x16\x4f\x45\x15\x6e\x24\x5c\x97\x7e\xdb\x47\x36\x42\xc3\x94\x0b\xe5\xad\x6f\xd1\xa7\x11\x9a\x7b\x18\xe9\x8d\x6d\xc8\x43\xe0\xd2\x54\xc9\x3d\x01\x46\xd1\x8e\x5c\x62\xed\xe1\x49\x0f\x89\xa6\x05\xeb\x45\x4f\x97\x47\x78\xcf\xae\x20\x93\x2e\x95\x47\x7b\xd0\x3b\xcd\xb9\x7d\x5b\xcb\x76\x33\x59\x42\xe9\x2e\xe6\x68\xf2\x31\xe6\x9c\x57\x0a\xc5\x44\x6d\x0f\x77\x40\x66\x73\x7f\xdf\x49\xf1\x0c\xeb\x1b\x52\xd6\xd8\xa4\x63\x98\x46\xa3\x37\x3a\x7c\x6f\x3b\x4b\x31\x59\xfe\x2e\x7a\xf7\xee\xe2\xf0\xdf\x17\x2d\x94\xd2\x55\xd0\x17\x65\x1d\xa3\x00\x90\x05\xe5\xea\xc3\x17\x6c\x09\x38\x9e\xe4\x0d\x70\x38\x3b\xd3\x71\x17\xec\xa0\x83\x59\x8a\x18\x01\xf5\x92\xd0\x57\x18\x6e\x56\x8e\x24\x7c\x25\x2b\xe4\xb1\x4f\x72\x3a\xb7\xdd\xb9\x7a\xe9\x76\x8c\x26\x82\xfd\x63\xac\xc3\x00\x77\x9f\xe0\x4e\x2b\x88\x87\x47\x51\x34\x6c\x9e\x0f\x97\xa2\xa2\x16\x77\x2f\xf9\x62\x5c\x33\xbd\x7e\x29\xfe\xd8\x00\x3a\x08\xdb\xd3\x3b\x5d\x17\x89\x9c\x94\x3c\x25\xe9\x5a\xd7\x54\xfb\x63\x2e\x04\x7c\x11\x2a\xf7\xf7\xce\xba\x72\x36\x2e\x1a\x3d\xdd\x29\x35\xaa\xf7\xf8\x18\xa2\x7c"}, -{{0xb8,0x34,0xc6,0xe0,0xfa,0xcb,0xff,0x58,0x0d,0xd3,0xb2,0x37,0x53,0x95,0x9a,0x4c,0x21,0x54,0xc2,0x19,0x52,0x1b,0x3d,0x27,0x03,0x5d,0x07,0x1f,0x65,0x99,0xbd,0x02,},{0xd1,0xc3,0x84,0x71,0x5e,0x3b,0x3d,0x02,0xc1,0x3e,0x09,0x06,0x05,0x53,0x4c,0x7d,0xb7,0x40,0xda,0x2a,0xa5,0x60,0xf5,0x32,0x00,0xa3,0xce,0xd8,0xbe,0xae,0x8c,0xf8,},{0x0f,0x19,0xb7,0x06,0x6d,0x57,0x92,0x32,0x8a,0x98,0x00,0xd9,0xd4,0xf8,0xf6,0x7d,0x5b,0x08,0x9b,0x54,0x12,0x26,0xa1,0x67,0xda,0xcd,0x43,0x9f,0xa4,0x85,0xb0,0x02,0x5a,0x5d,0xc7,0xf2,0xc7,0xe2,0x3f,0xc4,0xa5,0xc6,0x86,0x9e,0x76,0x19,0xd3,0x56,0x39,0x97,0x00,0xc9,0x36,0x50,0xe8,0x9c,0xd2,0x5b,0x90,0xfb,0x99,0x25,0xe3,0x04,},"\x6c\xf1\x47\xb1\x60\x55\x28\xa3\x6b\xe7\x57\x16\xa1\x4b\x42\x0b\xcf\x06\x7c\x03\xf1\xcf\xe9\xc4\x40\x2f\x14\x98\x7f\xbf\xc9\xd3\xec\xc3\xcc\xf4\xf8\xd2\xd0\x3a\x55\x90\x0b\x8d\xc7\x9a\xf3\xb6\xe7\x74\x36\xf6\x9b\x14\x17\xad\x4b\x68\xfd\x44\xe5\xe3\x33\xed\x90\xea\x79\x43\xfb\xd1\x12\x26\x09\xec\x8f\xf6\xbb\x25\xe4\x2e\x99\x14\xf5\x92\x0f\xc7\x2c\x4d\x01\x3b\x6a\x96\x85\xc9\x96\xfb\xd8\x35\x2a\xaf\xb1\x84\xc2\x2d\x9e\x47\x87\x1a\x52\x80\xe4\xab\x7d\xd6\xa5\xcf\xd1\x0a\x59\x94\xa2\x00\xf6\x70\xe0\xb6\x22\xa9\x39\x4d\x47\x93\xd0\xa4\x20\xe7\xd8\x80\x6c\xb1\x27\xc7\xac\x69\x0d\x45\xa2\xe9\x41\x66\xce\xa6\x72\xbc\xd9\x82\xb0\xe9\xba\xad\x56\x31\x2d\x25\x70\xdd\xde\x7e\x0b\x9e\x7f\x47\x13\x6f\x04\x81\xd0\x0f\x66\xa2\xaa\xca\x4d\x1b\x09\xd7\xce\x6c\x5a\x98\xa7\x6b\x68\xcd\x97\xd5\x79\x39\x68\xd6\x67\x07\x3f\x82\x17\xf9\x05\x47\x35\x34\x0f\x9b\x14\x9c\x0d\xce\x84\x5b\x09\x9e\x88\xd0\x70\x96\x80\xf0\xf7\x76\x03\xff\x0a\x23\x31\xc5\x58\xfc\x36\xd5\xf2\x4d\xa9\xa6\x2d\x69\xaf\x51\x90\xd2\x1b\x5c\x85\x7a\x1e\x08\xf0\x14\xc6\xd4\x56\x46\x86\x65\xa7\xf8\x45\xc6\x6f\x91\x11\xf9\xc0\x98\xc6\x89\x40\xef\xcd\x87\xb6\x57\x07\x0c\xb9\x16\x4b\xc9\x74\x3a\xce\xb7\x43\x9a\x0d\x01\xc0\x06\x2a\x11\xaf\x2e\x11\x34\x93\x97\xf5\xd1\x52\x87\x2b\x13\xc5\xab\x32\xf5\x1c\xc5\x8f\x14\x75\xec\x82\xac\x67\x15\x61\xdc\xbd\x34\x3c\xfb\x3c\x5f\x78\xd0\xfc\x73\x05\x3c\x60\x04\xb0\xa4\xca\x3f\x20\x43\xff\x4b\x0c\x54\x27\x5c\x4f\xcb\x9c\xad\xc6\xba\xab\xe5\x7b\x1d\x5a\xcd\x53\x1e\x97\x2e\xf9\x33\x51\x36\xcd\x1d\x65\x51\x2b\xa1\xf5\xb6\xcc\xc4\xb6\x6b\x42\x50\xaa\xfa\x29\x67\xdd\x42\x11\xa2\x74\x2e\x0f\x17\x7d\x8f\x40\x63\x89\x9f\x61\x81\x5c\xbe\x6d\x8f\xbf\xcd\xf7\x48\x12\xbd\x40\xcc\x10\x08\x4e\x46\xa9\x9a\xc1\x28\x05\x8e\xaf\x16\xa4\x9a\x24\xb6\xae\x22\x8e\xcf\x01\x09\xc5\x2d\xfc\x06\xe3\x7d\x6a\x33\x3b\xcb\x24\xab\xa3\x12\x16\x4c\x6c\x02\x90\x48\x5d\x25\x12\x80\x53\x8c\xe9\x54\x1c\x09\x16\x64\x0e\x36\xd6\x92\x9d\xcd\x95\x88\xeb\x99\x57\x7f\x5f\x6d\x82\xbc\xbb\x19\x88\x26\x26\x7e\x49\xf5\xda\xff\x2c\x0d"}, -{{0x22,0x69,0xa5,0xd8,0xf7,0xac,0x2c,0xd9,0x04,0x8f,0x5f,0x49,0xe3,0x49,0xe5,0xc4,0x35,0xa1,0x59,0xb3,0x19,0xfe,0x3b,0x30,0xbf,0xac,0x8d,0x0d,0x50,0x59,0x43,0xf4,},{0x1c,0x81,0x79,0x43,0xdc,0x39,0xc2,0x4b,0x01,0xda,0x38,0xa4,0x87,0xb1,0x75,0x48,0x24,0x60,0xc6,0x09,0xe4,0x72,0x63,0x49,0xa9,0xaa,0x7a,0xea,0x9b,0xc0,0xfb,0x34,},{0xbe,0x0f,0xb3,0x30,0x8a,0x07,0x6a,0x61,0xa4,0xa9,0x2a,0x97,0xf6,0xac,0x55,0x32,0x71,0x90,0xe1,0x34,0x1d,0x6d,0xd4,0x10,0xd8,0x6b,0x41,0xbd,0xaf,0x2d,0x33,0x74,0x09,0x3e,0xf7,0x20,0xbd,0xb7,0x7f,0xeb,0x70,0x14,0xe0,0xf7,0x7d,0x3b,0x80,0x96,0x23,0xc7,0xca,0x53,0xe2,0xae,0x4b,0x09,0x71,0x13,0xe9,0x6d,0xb7,0x7a,0x2d,0x08,},"\x71\x53\xd4\xd9\xe6\x41\xaa\x61\x92\x0d\xb0\xff\x4b\xd5\x37\xa6\xd6\x13\x0a\x39\x65\x54\xcc\x94\x53\x76\x98\xf9\xca\xd1\x6b\x99\xee\xbe\xfa\x5f\x27\x76\xf2\xfe\xaf\xf6\xbd\x9a\x69\x04\x12\x0c\x67\xe0\x88\x3f\x6b\x96\xbb\xbb\x19\x5e\x95\xae\xc7\x53\xb6\x99\xba\xb3\xd0\x39\x44\xc1\x3c\x72\xfc\x84\xe3\xf2\xcb\xf6\x29\x6f\x64\x55\x49\x11\x1c\x93\xfa\xe1\xa7\x59\xbf\xcd\x16\xfc\x09\xe6\x0b\xb9\x78\x55\x35\xad\x27\xda\x24\x4e\xf2\xf8\x57\xf2\xde\x99\xa6\xe9\x21\x88\x89\x0e\x45\x2c\x7f\x5b\x9e\x3a\x4b\x96\x8e\x11\x74\x3b\x6f\xc7\xfa\xf1\x27\x5e\x53\x60\xa5\x46\x89\x41\x79\x78\x94\xd7\x70\xfa\x7d\xa3\x64\xa3\x37\x30\x22\x39\xfe\x83\xae\x0b\x0d\x08\x4a\xa1\x2a\xcd\xc6\x34\x62\x52\x4e\x0e\xb1\x0f\xef\xe8\x1b\xa9\x6f\x71\xf2\x75\xf3\x44\x9a\x3f\x8d\xb2\x1d\x58\x74\x9a\x38\x85\x3d\x39\xb0\xad\x8e\x69\x89\x1b\xd2\x04\xdf\xca\x8f\x6c\x23\x9d\xc9\xa0\xac\x27\xf5\x4d\xb4\x23\x8d\x47\x06\xdf\x11\xd6\x07\x36\x9d\xc7\xf7\x04\xda\x1d\x39\xf2\xe8\x2a\xf8\xc2\x83\xd2\x20\xc1\x24\x31\xf5\x6d\x80\x30\x69\xb4\xac\xb7\x70\x81\xc0\x31\xae\x33\x19\xfc\x77\xfc\xa7\x84\x50\x97\xfd\x72\x7a\xd0\xd0\x80\x89\x5b\xba\x23\xe8\x73\xd2\xde\xf8\xcd\xc2\x16\xc3\xee\xd6\x1b\x08\x76\x1b\xb9\xeb\xce\x02\x82\xcf\x50\x2a\xaf\x6c\xe7\xe8\xc0\x58\x63\x79\x58\xc3\xea\x1b\x72\xfe\x6e\x8d\xf8\xd3\x7a\xc0\x55\xdb\x69\x92\x58\x7f\xab\xbd\xc4\x67\xf5\x24\x75\x64\x4f\x91\x88\x63\xaf\x62\x04\x92\xf3\x46\x80\xf2\x05\x6c\xbc\xab\x75\xe2\x32\x36\x26\xc0\x94\x75\x9c\x0e\x0e\x99\xef\x19\x75\x95\x27\x25\x06\x46\xad\x76\x01\x20\xba\x38\x66\x99\xd5\x39\x34\xf9\x56\xb8\xbb\xc7\x39\x5b\xb4\x96\xce\xb2\xdd\x22\x3c\x7b\x50\x1b\x92\xd3\x6a\x95\xf8\xf0\xa0\x2e\xb5\xba\x4d\xdd\xf1\x66\xb9\xb9\x5b\x4a\x59\xe7\x2a\x30\xc6\x3c\xf2\x1e\x60\x85\x75\x19\x23\xd5\x4b\x30\x28\x1e\x52\xa0\x96\x18\xe6\xf0\x23\xba\x0a\x21\x67\x5e\x7f\x98\x9b\x89\x91\x58\x8c\x96\xc2\xb5\x6a\x78\xf5\xd2\x94\x5a\x7b\xae\xb6\xa0\xc1\xbb\xd5\xd9\x5a\xf3\xee\x83\x0f\x58\x09\xc7\x94\xa1\x5a\xb4\xb5\xf8\x9d\xd2\xbe\x2d\xfd\xcd\x8f\xe0\x52\x0f\xda\x2b\x3f\x02\xa1\xac\x01\x55"}, -{{0xe9,0x65,0xb3,0xf2,0x57,0x35,0x66,0x85,0xc9,0x8b,0x42,0xb9,0x64,0xa2,0x53,0xfc,0x49,0x53,0x99,0xcc,0x94,0xb0,0x99,0xc2,0x44,0x5f,0xc8,0x1c,0x75,0x9c,0x68,0xe5,},{0x68,0x9f,0x54,0x10,0xc8,0xe0,0xf4,0xd3,0x7b,0xc0,0x7c,0x85,0xd7,0xcc,0xe6,0xc9,0xb6,0x36,0x01,0xf9,0xbd,0xaf,0xec,0xaa,0x44,0x8a,0x5e,0xed,0x64,0xaf,0xc8,0xc6,},{0x8d,0x2b,0xc4,0xe1,0xcd,0x25,0x6a,0xad,0x8a,0x15,0x1d,0xec,0x01,0x0d,0xc9,0x3a,0x5e,0x5c,0xca,0x58,0x29,0x8d,0xec,0x49,0xcb,0xc9,0xc4,0x71,0x7b,0x5c,0xfb,0x54,0x60,0xd4,0x30,0xbe,0x72,0x6b,0x0f,0x30,0x2c,0xbd,0x92,0x6b,0xee,0xa1,0x9a,0xa3,0xc9,0x3a,0xeb,0x45,0x2a,0x44,0xf6,0x00,0x7a,0xf4,0x9a,0xdf,0x2f,0x05,0xbb,0x04,},"\x6f\x20\xa9\xad\x27\xe3\x0d\xac\x76\xb3\x0d\x4c\x19\xa5\xbd\x6d\xfd\x6d\x04\x92\x13\xf4\xbe\xcd\xd9\x63\xd7\x2b\x8b\x2d\xad\x68\x7b\x00\x38\x08\x20\x1d\x50\xf7\xdd\x6e\x59\x9e\xf5\x8c\xeb\x60\x68\xc5\x45\xed\x99\xb9\xe7\x63\xf9\xb0\xec\x1d\xb5\xfc\xbd\x7d\x49\x0a\x12\x1e\xce\xc6\xbb\xa1\xeb\x5e\xdb\xd6\xde\x85\x36\x47\x07\xc5\x5e\x30\x0c\x8b\x16\xbb\x25\x30\xf7\x08\x98\x13\x66\x89\xc9\x88\x59\x1d\x53\x91\xd9\xcc\x34\x7d\x79\x31\x06\x1a\x9b\x76\x96\xe2\xc9\xf3\x5b\xc0\xd3\x04\xa8\x1c\x2c\xf9\x54\xd9\xc3\xa8\x8a\x22\xe1\xd6\x7b\xbe\x0a\x85\x30\x84\x77\xf6\x29\x18\xc2\x5d\xb5\x04\xe4\x76\x2f\x0e\x3b\x42\x46\x00\x79\x08\xac\x70\x17\x79\x00\x6b\x77\xd7\x25\x10\xed\xc6\x9e\x17\xd0\xf6\x39\x4c\x77\xe5\x55\x18\x75\xa4\x46\xf8\x12\x33\x41\x5d\x0a\x91\xa0\x46\x0b\x51\xc4\x13\xd6\x44\xe8\x50\xf8\x55\x72\x81\xc4\x66\x99\xe5\x3b\x22\xa7\xc7\x3b\x06\x8e\xa3\x86\x52\xcf\xf3\xb0\xa7\xb8\xba\x30\x97\x1e\xab\x18\xfd\xbb\xd8\x73\x9e\xe1\xee\x0c\xd5\xcb\xfb\x7d\x5d\x41\x75\x7b\x63\x31\x27\x1f\xb7\x80\x97\x51\xe2\x03\x51\x3c\x99\x70\xf6\x6d\x91\xbc\x0c\xe0\x62\xf4\xfc\xb2\x8b\xe0\xa6\x99\x86\x7b\x79\x59\x4c\x64\x58\xa0\xd3\x07\xac\xac\x91\xf4\x13\xc4\x61\x58\x77\xdc\x53\xe1\xb0\x18\xda\x5c\xfc\xe1\xb6\x3f\x40\xbe\x1e\x55\x27\x4c\x43\x74\xcd\xfc\x21\x52\x44\x99\xa6\x83\xa2\x31\xad\xef\x77\x9d\x19\x21\x44\x0e\x5d\x3f\xdb\xd5\x03\x3d\xc9\x83\xcf\xc9\x31\xab\xe6\x38\xc3\x5d\x5a\x95\x86\x9e\x9f\xe3\xd9\x3e\xb9\x0b\xd1\x86\x1f\x85\x5c\xe1\xf6\x08\xb7\xbc\xad\x6b\x5e\x1b\xd9\x7e\xdc\x95\xed\x5d\xdc\xbc\xb7\x15\xd9\x19\xf5\xff\x77\xdf\x2d\xa4\x38\xf7\xa3\xa9\x82\x86\xdb\xd5\xb6\xe0\x43\xfc\x73\x72\xf6\x97\x04\xf0\x9d\x86\x55\x30\xf4\xf0\xed\xd3\x30\x0f\x18\x5b\x6d\x73\xd8\x71\x6d\x32\xd3\x2b\x1c\x9a\xc2\xdd\xf4\xf9\x02\xd3\xf2\x16\xd3\x5a\x33\xf3\x68\x09\x5d\xed\x10\xbe\x94\xbb\x53\xd6\xf2\x56\x56\x0f\xac\x2f\x4a\xf0\xed\xf5\xc5\xc7\x02\x14\x37\x77\x12\x6e\x7d\xe3\x2d\x07\x49\x39\x32\x66\x21\x29\xba\x0e\x7f\xc7\xcf\xb3\x6f\xd2\xca\x53\x16\x46\xe8\xcd\x22\x11\x85\x4f\xc5\x10\xaf\x3b\x1e\x8c\xaf\xde\x7a"}, -{{0xbc,0x3b,0x1e,0x0b,0xf8,0xd6,0x9e,0xa5,0xb4,0xcb,0xbf,0x10,0xbb,0x33,0xfc,0x95,0x5a,0xdc,0xbe,0x13,0xfc,0x20,0xaf,0x8a,0x10,0x87,0x2c,0xe9,0xdf,0x39,0xd6,0xbd,},{0xac,0xcd,0x26,0x28,0x15,0x59,0x19,0xbb,0xc7,0xf9,0xd8,0x6f,0x91,0xda,0xfe,0xc3,0x5c,0x71,0x1a,0x78,0xc7,0x9a,0xd3,0x60,0xed,0xdb,0x88,0xfa,0x8a,0x18,0x0b,0x2d,},{0x6e,0xf7,0xf0,0xe9,0x1f,0x2c,0xc6,0x71,0x5f,0x8e,0x5a,0x98,0x57,0x4b,0x44,0x00,0xc2,0x61,0xa6,0x43,0xe0,0x54,0x5f,0xf2,0x67,0x47,0xf8,0xe1,0x73,0x98,0x99,0xd7,0x66,0x40,0xb6,0x45,0x1c,0x43,0xc1,0xd0,0x3a,0x47,0x75,0xb5,0x4f,0xcf,0x9b,0xce,0x18,0xed,0x3f,0xcc,0xad,0x33,0x8b,0x77,0x64,0x02,0x4f,0xdf,0xa2,0xde,0x82,0x01,},"\x4c\x73\xe0\x4a\xbe\x08\x19\xde\x1f\x84\xd7\x05\x41\xeb\x1b\xb6\x1c\x4f\x42\x92\x0e\x1f\x2d\x1d\x9e\x62\x81\xa8\xa2\xe8\xb3\xeb\x45\x53\x7d\x83\x96\x90\x27\xf9\x9e\xf0\xea\x27\xca\x08\x5b\x13\xf9\xdb\x48\x0f\x00\xc0\x2f\x3f\xd7\x42\x9d\xd5\x67\x70\x89\x53\xbb\xf3\xb9\xe8\xe2\xc6\xac\x4d\x32\x1f\xf8\xf9\xe4\xa3\x15\x47\x23\x08\x5a\x54\xe9\xc9\x57\x3c\xc7\x35\x0c\x09\xf8\x97\x3f\x94\x8b\x08\x73\x03\x73\x59\x7a\x5f\xd0\x34\x98\x21\xae\x0a\x3c\xd6\xc8\x49\x92\xb1\x89\x12\x8f\x34\x90\x98\x7e\x1e\x9a\xd4\xf6\x57\x4c\xa5\x38\xfd\xfd\x83\x28\x4c\x1e\xb0\x95\x3f\x24\xc0\x8f\x74\x93\x2d\x43\x64\xdb\xbe\xf9\x22\x54\x24\x40\xda\xe8\x04\x24\xa9\x2e\xae\xf2\x7c\x18\x89\xbd\x08\xc4\x4f\x9d\xf0\x3a\x3a\xf3\x0d\xff\xb4\x8f\xae\x44\x5e\x62\x5f\x4d\x92\x65\xcf\x38\x7a\x1d\xa3\x5f\xe4\xc2\x31\x50\x45\x35\xdb\x72\xea\x81\xa1\x86\x80\x5f\x85\x6e\xbe\x6a\x6a\x65\x24\x14\x32\x53\x0f\xe6\xc9\x60\xc5\xf9\xbe\x6c\x22\x95\x70\x60\x30\x4e\x9d\xd8\xef\xbc\x1e\x48\x2e\x7d\xdb\xd8\xaf\x03\xbf\x23\x82\x89\x9c\x98\x6d\x91\x66\x11\xe4\xf2\x7a\xe5\x2f\x81\x7e\xf0\x1b\x6a\x14\x1f\xe4\xf6\x85\xd9\x4d\xc8\xcd\x52\x83\x00\x43\x93\x45\x87\x70\x4c\x1e\x64\x2e\x8f\xe5\x6b\xe6\xd6\xb8\x5b\xf4\xa6\xfe\xb2\xb6\x85\x8f\x1f\x00\x7f\x99\xd3\x9e\xa0\x4c\x9f\xe5\xfa\x7e\xf1\xb9\x1f\x49\x5e\xd0\xe7\xfa\x42\x13\xdd\x68\xce\xa4\x2b\x67\x29\xf9\x50\x31\x90\x7e\x27\xc4\x40\x98\x09\x43\x86\xfa\xbf\xb0\x4a\xb9\xb4\xde\x3d\x68\x61\xde\x46\x23\x12\xc5\x9b\x27\xc7\x6f\x7b\x6a\x4f\xc7\x1e\xa0\xd5\xda\xf6\xb7\x32\x05\x21\xa6\x7e\x5c\xb3\x75\x04\x97\x6a\xd7\x3d\xae\x2d\x64\x9f\xeb\x75\xe2\xea\xdd\x34\x01\xa7\xf2\xf3\x6e\x16\xdf\xbf\xbd\xb2\xaf\x57\x16\xcb\xa1\xbc\xe2\x0c\xd4\x7c\xe1\xc1\xd7\xbe\x00\x69\x70\x01\xfb\xbe\xb4\x91\x5a\xa6\xe5\x39\x3b\x5a\xb2\x0e\x0f\x31\xf5\x11\x91\x49\xa2\xcb\x4c\x4d\x45\x2c\x81\x56\x11\x3a\xc7\x82\x4f\x84\xf0\x9a\xeb\x81\x20\x2e\x8d\xd3\xda\xc0\xaa\x89\x39\x9b\x5a\x38\xb1\xe2\x18\x30\x19\x60\xa3\x7d\x52\x63\x2e\xea\xef\xe3\x68\x74\x55\x46\x42\x88\xeb\x17\xd9\xe1\x9a\x3a\x72\xed\x9d\xe3\x2c\x17\xbe\x79\xa3\xb9"}, -{{0x10,0x71,0x8f,0xa6,0xe2,0xd7,0xf6,0xed,0x38,0xfd,0x66,0xcb,0x6d,0xbf,0xa0,0x87,0xe8,0xf1,0xe8,0xa8,0xa2,0x4f,0xab,0x58,0xd7,0x9d,0x79,0x54,0xb8,0x72,0x0c,0x3e,},{0x87,0x0d,0x4f,0x66,0x6d,0x06,0xfd,0xa9,0xf9,0x51,0x1b,0x58,0x60,0x2e,0xec,0x05,0x0d,0x75,0x4e,0xa6,0xd8,0xe7,0x9c,0xdd,0x19,0xf6,0x01,0xc4,0x77,0xdf,0x1a,0xa0,},{0xe1,0x65,0x91,0x86,0xf1,0xf7,0x6f,0xe4,0x3a,0xc8,0xa1,0x17,0x03,0x36,0x0f,0xbe,0xff,0x53,0xb5,0xe5,0x7b,0x59,0x74,0xaa,0xa0,0x8e,0x25,0x75,0x57,0x9c,0x27,0x08,0x4c,0xf6,0x80,0x2e,0x7c,0x20,0x63,0x47,0x31,0x44,0x75,0xb6,0x03,0x19,0x74,0x94,0xe7,0xd6,0x1f,0xe4,0xb1,0xee,0x7b,0x78,0xe1,0x8d,0x94,0x46,0x93,0x52,0xdf,0x0c,},"\x41\x25\x9b\x6e\xef\x13\xd6\xff\xe3\x3c\xdd\xe7\x99\xb9\x95\xc4\x0b\xe7\x82\xcf\x97\x84\x40\xb6\x6b\xe5\x1c\x44\x05\x82\xab\xd4\x2f\x52\x66\x96\xbb\x3c\xb9\x22\x65\xb1\xed\x0e\x4b\xba\x76\x4c\xae\x28\x39\x83\x0a\x25\x26\x35\xdc\x80\xce\x5f\x73\xd5\x21\xb3\xd6\xff\x03\xac\x30\xe1\x98\xad\x20\x56\x7e\x75\xa3\x4f\xa8\x25\xeb\xf9\x84\x15\x08\xda\x84\xcd\x67\x42\x36\xca\x7b\x43\xde\x35\x64\xc9\x4a\xb0\x79\x40\x8f\xd9\x41\x37\xce\x3f\x90\xa5\xdd\x5d\x3a\xc3\x9a\x05\xec\x86\x71\x5a\x8f\x02\x5e\x45\x39\xa7\x64\x0a\xb8\x88\x36\xf4\xef\xba\xbd\x5e\x16\x52\xc4\x9e\xa2\x16\x13\xac\xfe\x34\x3a\x88\x0e\xe5\xa4\x2f\x2f\x91\x34\xef\x4e\x37\x16\xb1\x6d\x13\x4a\x9c\x4c\x71\xc3\x9b\x3c\x1a\x85\x7d\x3c\x89\x43\x97\x83\xee\xf1\xed\xd7\x1b\xf4\x49\x2d\x05\xfd\x18\x67\x3a\x52\x42\xff\x41\x87\xb9\xde\x47\xad\x49\x68\xda\x49\xdb\xa5\xa6\x09\x2e\x95\xea\x27\xdd\xfc\x74\x48\xdc\xf5\x97\x2d\x9d\x22\x8d\x63\xe5\x29\x1b\xa6\xe6\xfb\xd0\x7e\x32\x41\xf9\x36\x6c\xa4\x97\x6b\xb0\x4b\x22\xd0\x1f\x0d\xba\xe7\x94\xfa\x9c\x1d\x90\x29\xf8\x8a\x83\x60\x2b\x0e\x0e\xc5\x5e\x22\xc3\x7b\x20\x11\x25\xca\xdb\x53\x41\xef\x73\xf6\xda\x1a\xbb\xe2\xb1\xc4\x75\xf0\x75\x03\x45\xb1\xbe\x42\x59\xd8\xc2\x85\x31\xff\xe7\x78\x86\x67\xc4\x10\xda\xc3\x39\x91\x8c\x86\x9b\x00\xab\x80\xf2\x0b\xf7\x99\x0d\x36\x6f\x9b\x3d\x5e\x8e\xb2\xf4\x8d\x7e\xd0\xe6\x4b\x85\xdc\x9f\xe3\xbb\x99\x8b\x1e\xec\xd1\x23\x1e\x90\x2d\x2d\x15\x2e\x09\xda\x2d\x25\x92\xbd\xb3\x2c\x8c\xd2\xe2\xc4\x89\x49\x6b\x29\x80\xc0\x3d\xbb\x09\xec\x7f\x8a\x4e\xa2\xc7\x02\x0f\x2a\x0f\xaa\x65\x7c\xd6\xce\xd4\x8d\x6d\xa2\x78\x64\xcf\x5e\x97\xee\xa9\xb3\xc2\xf0\xf3\x4a\xbf\x8d\x87\xbd\x2a\xde\xb6\x0c\x72\x72\xfc\x43\x06\xd9\x55\xbd\xc8\x02\x3d\x7d\x3d\xc2\xf3\xda\xfe\x9e\xbe\x8a\x8d\x13\x89\x65\xa7\xf6\xce\x93\x51\x7c\xd2\x09\x96\x63\xf6\x7c\x34\x55\x21\x76\xdd\xb5\x95\xac\x6e\xa5\x60\x9f\xeb\xcf\x24\xc7\xd6\x9d\x41\x27\x09\xe5\x78\x67\x0a\x21\xac\x8a\xfc\xcb\x8b\xf2\xb1\x8f\xf3\xaf\x7d\xe2\x1d\xc7\x1d\x50\xd6\x0d\x37\xb6\xed\x72\x9d\xb0\x4b\xef\xf7\xd3\x4b\x29\x20\xd8\x75\x51\xce\x15"}, -{{0xc1,0xd4,0x72,0x4c,0x6c,0xb1,0xbc,0x67,0x23,0xb2,0xb4,0x30,0x34,0x27,0x8b,0x3c,0x5b,0x48,0xfe,0xd7,0xf8,0xa3,0xcc,0x23,0x18,0x03,0x3e,0x75,0x52,0x04,0x73,0x51,},{0xc2,0x7e,0x39,0x2e,0x7c,0x36,0x64,0xb9,0x06,0x1e,0xa7,0x6d,0x25,0x75,0xdd,0x7c,0x41,0xea,0xf1,0xda,0x3a,0x65,0xf3,0xa9,0x86,0xe0,0xa5,0x7f,0x6c,0x40,0xc1,0x7e,},{0xd3,0x7a,0x6e,0xc8,0x2e,0xd4,0x5c,0xa9,0xb4,0x85,0x5d,0xe9,0xcb,0x94,0x25,0x64,0xe8,0x83,0xff,0x70,0xa7,0x9b,0x8e,0x71,0x2d,0x5f,0x60,0x4e,0xc8,0x97,0x4d,0xe5,0x36,0x3a,0xc8,0x49,0xcb,0xab,0x28,0xe7,0xae,0xef,0xf2,0x8e,0xd3,0xf2,0xd1,0x4b,0x60,0x8b,0x31,0x46,0xc2,0xef,0xe0,0x73,0x5a,0xd8,0x15,0xc7,0xd7,0x5a,0x1a,0x01,},"\xde\xee\x99\xd7\xa7\x7d\x43\x00\xc1\x7a\xec\x1a\xb3\x23\xc5\x71\xc6\xe9\xe7\x3a\x43\x49\x1a\x3c\x78\x88\xb7\x6f\xc0\x3e\xc4\x3d\x07\xaf\x42\xa0\x5a\x2a\xa3\x22\xd0\x0c\x85\x60\xac\xef\x31\x41\x06\xb1\x0b\x9b\xd1\x26\x54\x35\x7f\xfa\x26\xf2\x39\x00\x50\xda\x63\xd6\x68\xc9\xe2\xdf\x54\x8f\x87\x63\x9e\x09\x6a\x35\x85\x3f\x82\xe7\x61\xfd\x71\x1d\x2a\x26\x54\x38\xf5\xd4\xdb\x5e\x32\x77\x57\x08\x15\x0d\xa6\xcb\x68\x6a\x2b\x4c\xa2\x11\xd7\xf0\x0d\xc0\xab\xcb\x2c\xa1\x50\xe7\x91\x11\x6a\x10\xa5\xef\xcf\xf3\x51\x4d\xab\x8e\xd8\x0a\x70\x92\xc3\xa0\x15\x15\x2c\xb2\x5d\x9f\x86\xec\x0d\x1c\xa6\x7d\xda\xb4\x4d\x64\xee\xb1\xf9\x31\xbf\xab\x2a\xb1\x88\x95\x6c\x74\x3d\xb4\x81\x48\x08\xc5\xcd\xe1\xb0\x74\x5b\x3e\xdd\x34\x0e\xb0\x3f\xfc\xc8\x0a\x78\xf3\xdb\x31\x0f\x4f\x5c\x20\x00\x9f\xc0\x27\x9c\x2c\x1b\xcb\x3c\xed\xf9\x90\xbd\x0e\x20\xc6\xf9\xfb\x75\x15\xad\x6e\x93\x3b\x07\xe9\x9d\xa6\xac\x32\xb9\x71\x41\x18\x7e\xf6\x3b\xdb\x10\x62\xe3\x72\x20\xa4\xdc\xd4\x19\xd6\x24\x4c\xdc\xc3\x4e\xa4\x1d\x0b\xcb\xc3\x13\x8b\x1d\x54\xae\xfc\x01\x90\xe3\x0b\x18\x7d\xb0\x73\xaa\x7d\x6c\xfe\x04\xbd\x3f\xd2\xac\x00\x31\x3e\x3d\xdd\x64\xa1\x81\x93\x5c\xa4\xb8\xb2\xa8\x5d\x36\xbc\x27\xd9\x7b\x76\x26\x76\x7b\x93\xee\x38\xde\xf8\xb6\xb2\xc8\xda\x9b\x00\x26\x36\x14\x34\x2f\xaa\x9d\x3e\x73\x8d\x27\x13\xc4\x5f\xfb\xee\xf8\xc8\x4b\xcd\xbc\x8d\xa4\x30\x9c\x84\x45\x53\x0f\x5c\x61\x7d\xc8\x66\x25\x1f\x54\x89\x50\xa1\x4f\x07\x5a\xa3\x11\x7f\x96\xe4\x1f\x89\x9d\xbe\x73\x40\xb1\xd9\x0a\x13\x52\xd3\xb8\xfb\x41\xb7\x9f\x16\xa8\x2b\xc2\xe4\xa1\x93\xb8\xa7\x23\x24\x00\x99\x6b\x73\xb1\xfc\x00\xb2\xec\x1c\x66\x75\x77\xf8\x28\x24\xd3\x9f\xb7\xf6\xe7\x69\x2d\xcd\x97\xb1\xd8\xce\x94\x08\x3c\xa1\x97\xe9\xa5\xd4\x0f\xad\xff\x0b\x9a\xc5\x7e\x9d\xe7\x61\xc1\x56\xe6\xd3\x1d\x52\xc3\x32\xd5\x13\xe9\xf5\x86\x97\xdc\xbd\xd8\x0a\x5e\x42\xc5\x51\x70\x2c\x3d\xe7\xbe\xcc\xc3\xdb\x84\x5b\x1a\x04\xc8\xcb\xd4\x16\x95\xea\x74\x28\xab\xba\x89\xe0\xdc\xe3\xe3\xd9\xe7\x02\x30\xae\x91\x47\xc2\xb8\x85\x59\xdc\x69\x5d\x68\x09\xa5\x1c\xcb\xc1\xdd\x9e\x08\x9c\x58\x5f"}, -{{0x37,0xc0,0x70,0xd4,0xa5,0x3b,0x13,0xbe,0x76,0x06,0x35,0x11,0x0d,0x1b,0xd4,0xf0,0x19,0x20,0x22,0x5a,0xfa,0xbe,0xc5,0x76,0xfa,0xae,0xc9,0x10,0xf2,0x92,0x6d,0x1a,},{0x0a,0xa8,0x5f,0x2a,0xb1,0xdf,0xf8,0x95,0xd1,0xfa,0xd0,0xc1,0x19,0xf2,0xbf,0x57,0x12,0x6a,0xab,0x60,0x1c,0x52,0x8d,0x37,0x69,0x8e,0x97,0x70,0x2d,0x35,0xf5,0x25,},{0x9d,0xa6,0x0c,0xc4,0xa6,0x4d,0x07,0xde,0xe1,0x34,0x6b,0xd3,0xd3,0x01,0x09,0x95,0xce,0x27,0x38,0x20,0x8a,0xb3,0x5b,0x34,0xc2,0xa8,0xfd,0x17,0x87,0xae,0x3a,0x1e,0x20,0x7f,0xe7,0x84,0x52,0x51,0x54,0xfa,0xe4,0xf5,0x79,0x4c,0xd8,0x50,0x30,0x45,0xfe,0xa8,0x5c,0xf7,0x7f,0xd9,0x2f,0x6a,0x70,0xcd,0x0c,0x5a,0x52,0xc0,0x81,0x0e,},"\x10\xc6\x46\x44\x7f\x81\xad\x94\xd0\x15\xd8\x6d\x0d\x98\xb2\x45\x2d\xca\x60\xa4\x7a\xb3\x52\x64\x03\x5e\x33\xa0\x94\x2b\x95\x4e\x3e\x23\xb9\x1d\x81\x23\xb8\x59\x3c\x6a\xf7\xc8\xd3\xec\xd2\x90\xe0\xe5\xee\x36\xfd\x4e\x53\xb7\xbe\x63\x3a\x6c\xf0\x27\xa5\xac\x3f\x0f\x67\x9e\xb1\xbd\xd2\x10\xa3\x8e\xa6\xe4\x8b\x05\x58\xe3\x03\x01\x0a\xf4\x74\xe7\xf6\xdf\x2a\x4e\x45\x76\x99\xfc\x38\xe3\x69\x38\xb0\x5f\xfc\xaa\x1b\x69\x4e\x32\xf3\xd1\xb2\xcc\x5d\x00\xcf\x25\x6f\x12\x18\x4c\x87\x3e\x51\x90\x89\xec\x1d\xf1\x5b\x0d\xc7\x6e\x7b\xfe\x90\x78\x0d\xf5\x81\x36\xfe\x59\x7f\xce\x89\x4c\xa5\x63\xe0\x8e\xfa\x0f\x2d\x4d\x20\x8b\xed\xe9\xa8\x74\x88\x28\x73\xd2\x51\xba\xf0\x19\xfe\x46\xd1\xd6\x50\x4b\x3b\xcd\x24\x3b\x79\x53\x51\xf3\x4d\x2e\x76\x06\xaa\x97\x55\x28\xee\x50\xd5\x9e\xfb\x6e\xe6\x99\x2a\x89\xb2\x42\x69\x56\xc2\xca\x42\x47\xe0\xdf\x01\x29\x85\x29\x83\xe9\x76\x7a\x8e\xed\x1b\xc7\x33\x5f\xfc\xa8\xd0\x28\x9f\x04\x80\x7f\x67\xca\x7d\xa9\x71\xf5\x8d\xb8\xb9\xbc\x9f\xdb\xe4\xf8\x3c\xfe\x9a\x00\xf1\xca\x58\x47\x98\xbc\x71\xd8\x51\xff\x7c\xd6\xc5\x1b\x89\x90\xaa\xba\x4d\x38\xb4\x16\xb9\x22\x40\xdf\xb7\x0e\xe3\xc1\x2b\x5e\x73\x10\x57\x76\x2e\xf9\x08\x23\xfb\xf6\x83\xca\x06\xd0\x5c\x20\xd3\xae\x2b\x97\xa8\x3e\xbe\x70\xae\x17\xaf\xff\x9d\x16\x60\x9d\x54\x6d\x8d\x3c\x74\xbc\x28\x18\x84\x89\x4f\x3d\x49\xe0\x83\xf1\x0a\xe7\xc1\x1c\x1d\xca\x0e\xff\xef\xcf\xa6\xe0\xf1\x53\x50\x81\xfa\xc3\xa2\x81\x9f\xd2\xe3\x26\x55\x27\x18\x2a\xe9\xd3\x91\xb2\x32\xbb\x75\x42\xe6\x84\x55\xcd\x26\x77\x60\xdb\x65\x2d\x19\xe2\x2f\xb2\xed\x11\xcd\x13\x05\xba\x8d\x98\xc1\xeb\xf2\xd1\x96\x9b\x24\xd6\x4f\x3e\x31\x9a\xf7\x4e\x09\x20\x06\xd2\xa3\xff\x74\x48\x72\xa2\x0e\xbf\x18\xd1\x77\x48\xab\x71\x10\x80\x50\x96\xea\x13\x6b\xce\x2f\x96\x8b\x20\x5e\x65\x0b\x80\x3c\x53\x1d\x06\x77\x5a\xe5\xce\xea\x28\xbb\x92\xe9\xa0\xed\xec\x89\x51\xce\x20\x09\xa8\x8e\xe1\xb6\x4d\x9b\x9e\x89\xf6\x90\x51\x20\x33\x84\x21\x0a\x10\x2a\x44\xd2\xd6\x70\x31\x73\xb6\x85\x07\xdc\xea\xdd\x3b\xf6\x51\x0d\xf2\xa5\xce\xfd\x9c\x80\xe4\xf3\x85\xb2\xf9\xe6\x21\x58\x13\xed\x32"}, -{{0x11,0x26,0x49,0x6a,0x58,0x2c,0xe5,0x8d,0x3d,0x61,0x8d,0xd8,0xa3,0x93,0x35,0x47,0xaa,0x7a,0x8a,0x30,0xfb,0x54,0x06,0x3b,0x8d,0xfd,0xd3,0x16,0x71,0xc6,0xc7,0x3d,},{0xe1,0x02,0x29,0xc6,0x23,0xfa,0x8a,0xd8,0x98,0x2c,0x3e,0x4c,0x36,0xff,0x52,0xdf,0x0f,0x21,0x9b,0x57,0x91,0x5b,0x6e,0x98,0x0e,0x5f,0xe7,0x2e,0xa0,0x96,0x2e,0x22,},{0xb3,0x0e,0xb5,0x6c,0xa9,0xb1,0x20,0xbf,0x84,0x9a,0x3a,0x9d,0x56,0xaf,0x03,0x3d,0xe8,0xa5,0x90,0xc9,0xe1,0x24,0x0c,0x1e,0x36,0xdb,0xc6,0xcf,0x0a,0x71,0xb7,0x8a,0x11,0xec,0x14,0x3f,0xb9,0x95,0x9a,0x8f,0x25,0xb5,0x77,0x11,0xd6,0xa9,0x0a,0x67,0xe0,0x1b,0xe3,0xa4,0xda,0x2b,0x69,0x39,0x48,0x69,0xbb,0x8d,0x64,0xb8,0x7e,0x0f,},"\x6a\x4b\x52\xd7\x30\xdd\xab\x82\x9b\x2a\x17\x95\x90\xcb\xd4\xc3\x72\x49\x8e\x9f\x43\x99\x77\xc0\xa1\x0d\xc1\x3c\x0a\xe1\x73\x6e\xaa\xff\x06\x33\x71\x43\x4f\xd0\xda\x80\x36\x0e\xc5\x89\x06\x07\xd2\xfa\xe1\xc9\xa2\xe1\xab\x0b\x7f\x3d\x66\x7f\x5b\x1b\x9c\x41\x8f\x18\xb1\x0c\x9e\x6f\xd6\x69\xd3\xeb\xec\x16\x8e\xfe\xf4\x41\x63\xe5\x77\xa2\xeb\xd0\xf2\xcb\x76\x8f\x80\xc2\x31\x88\xe8\x60\x69\xe4\xd1\x0f\x41\x03\x06\xce\xdd\x7a\x34\x1a\x61\xe0\xf4\xf3\xbc\x25\x04\x1b\xc2\xf9\x22\xed\x07\x3e\x1e\x2f\x1b\x70\x9c\x57\x9d\x10\x63\x0f\x33\x07\x17\x54\xd7\x07\x89\x4a\x1c\x62\x19\x0d\xe1\x88\x82\xc5\x64\xdc\x4c\x01\xdc\x54\x5d\xd8\x96\x64\x04\xed\x78\xfa\x32\x67\xa9\x46\x9f\x63\xb6\x12\x0a\xbb\x65\xf9\xb3\xba\x3e\xee\x28\xd7\x9c\x2e\xb4\xe7\x02\x0c\xc6\x98\x7d\xfc\x5c\x29\x67\x2f\x8c\x0f\xa3\xe6\x90\xd5\x84\xfe\x00\x0c\x64\xf3\x52\x61\x01\x79\x62\x1b\xfd\x5f\xf3\xeb\x30\xd1\x8f\x1a\x02\x50\x41\x6d\xb9\x3b\x1c\x1e\x93\xcf\x8a\x36\x46\x51\x75\x60\xd1\xcc\x8f\xff\x82\x2b\x51\xef\x27\xb2\x00\xe9\x87\xb5\x92\x39\x07\x53\x45\x3e\xf1\x38\xbd\x3d\x29\xdb\x7c\xb1\xb5\xf4\x5e\x47\x95\xb8\x9c\x53\xf4\x97\x04\x19\x27\x52\x23\x7c\x6a\xb2\x74\x84\x9f\x95\x94\xee\x97\x77\xf6\xef\xe7\x04\x83\x12\x9d\x06\x7f\x97\x19\x9d\x9a\xe3\x60\x90\x70\x38\x64\xf7\xca\x47\x50\xa6\xf3\xb6\xff\x83\x82\x4c\x91\x04\x84\x39\x4d\x1e\x2e\xce\xba\x18\x44\x6f\xe4\xe9\x94\xce\x07\x43\x3a\x74\x0d\xdd\x05\xf0\xe3\x96\xd4\x82\x89\x4e\x6f\x14\xac\xf7\xb9\x7b\xae\x6c\x7e\xb8\x87\x03\x03\x9f\xa7\x85\xd6\x0a\x3a\xf7\x8b\x13\x24\x3a\x4f\x88\xdd\xe1\xd9\x98\x61\x7f\x2e\x3f\xa7\xea\xfc\x2f\x43\x5d\xd4\xac\x1e\xa9\xc2\x38\x40\x7a\xa0\x9b\x4e\xea\x8e\xd4\x34\x92\x7b\x40\x66\x74\xac\x27\x04\x58\xcf\xb3\xbf\x29\xc3\x47\xf9\x45\x59\x61\x31\x79\xb9\x50\x21\x92\x32\x1b\x88\xe9\xaf\x0a\x90\xe9\xa4\xab\x9e\xdd\xaa\xe3\x82\xe3\x73\x4d\x14\x15\xeb\xe3\x24\x99\xc3\x4e\x6f\xde\xaf\x15\xb0\xd9\x78\x79\x85\xe0\x8d\xfe\x49\x54\x60\xc5\x4f\x67\x43\xd8\x1f\xf1\x68\x81\xe5\xe3\x0c\x51\xf4\xb0\x92\x37\x37\x83\xf1\x24\x23\xc3\xe1\xae\x85\x91\x13\x0a\x26\x99\x80\xca\xa1\xcb\x5c"}, -{{0x9c,0x16,0x7a,0xff,0x3b,0x1b,0x78,0x8f,0x13,0x3d,0x42,0x2d,0xe8,0xca,0x9a,0x64,0x31,0x64,0x09,0xf9,0xe3,0x5b,0xfe,0x22,0x03,0x2e,0xc4,0x17,0xae,0x9a,0xbc,0x6d,},{0xef,0xb5,0x34,0xf0,0xd4,0x7c,0x06,0x8e,0x77,0xb2,0x8a,0x90,0x6d,0x95,0xad,0x8d,0x21,0x3a,0x4d,0x4f,0xc1,0xc7,0x05,0x42,0xf0,0x1e,0x59,0x6d,0x57,0xb5,0xf0,0x19,},{0xc9,0xae,0x67,0xfd,0x64,0x15,0xdc,0xba,0xb2,0x92,0xfa,0xb3,0x94,0xca,0x6c,0x3b,0x7d,0x90,0xca,0x24,0x4d,0xc6,0xa7,0x76,0x4e,0x74,0xfd,0x20,0x2b,0xf4,0xb2,0x90,0x5b,0xd2,0x03,0x0e,0x6b,0xeb,0x91,0x4c,0x3c,0x23,0x8d,0xb3,0x71,0xb1,0xcb,0xa6,0xd9,0x26,0x1a,0xa3,0x92,0xec,0x87,0x1a,0x4b,0x8b,0x12,0xfe,0x9c,0x1c,0x97,0x0e,},"\x68\xac\x0f\xc2\xb6\x07\xba\x38\xe3\x77\xfa\xe8\x45\xc8\x08\xc8\xf9\xfa\x61\x4e\xb1\xf3\x11\x58\xa9\x62\x0a\x93\x7d\x3e\x30\x1e\x85\xac\xaa\x69\x14\x4b\xc3\x49\xa3\x9d\xfb\x58\x20\x41\xc4\xa1\x97\xae\x99\xb4\xd4\xd5\x9b\x7a\x2c\xa3\xd1\x62\x28\xb5\x59\x1c\xbf\x57\xc1\x8a\x78\x1e\xfd\x19\x19\x3c\x47\xb1\x6c\x60\x23\xa3\xa8\xba\x3d\x66\x8f\x05\xa3\x7f\x1e\x83\xb0\xd7\xfe\xbd\xd1\x0f\x63\xe4\x8e\xf7\xa2\x0e\x01\x5b\x1c\x67\x25\xd4\xc3\x00\xa9\x86\xc6\x0e\x3a\x11\x54\x69\xc8\xe5\x2b\xa0\x5b\x51\xc0\x5d\x0a\xf4\x0d\x89\xfd\x9e\xd7\x6f\x36\x95\x0a\xee\x3c\x78\x19\x89\x8a\x90\x3c\xfe\x03\x61\xa9\x1c\x69\x10\x0b\x49\x51\x41\xe8\x6e\xe7\x9d\x63\xd1\x74\x03\xfb\x1a\x16\x29\xef\x63\xcb\x7e\x9d\x27\x20\xcb\xff\xf0\x00\x2b\x19\x0b\xcd\xc2\x67\x94\x12\x4d\xd3\x8d\x42\xbc\xaa\x71\x75\x40\x5e\xb0\xbb\xcf\x8e\x37\xd6\x5d\x05\xa3\x71\x95\xb4\x79\x37\x1f\xa2\xbb\xbb\x16\x7d\x91\xce\xe8\x82\x35\xdd\x72\xea\x88\xfc\x73\xce\x3c\xe4\x3d\x33\xb7\x15\xf2\x5f\x19\x2e\xc2\x15\xda\xc1\x24\x89\x9c\x5e\x75\x86\xe8\x63\x40\xd8\xcb\xe5\x37\x35\xde\xfb\xe0\x2e\x4c\xc9\xfd\xe6\x9f\xb9\x79\x4d\x1d\xb7\x2b\x98\xc0\xf1\x97\x66\xee\x51\x38\xbb\xfa\x78\x90\x9a\xa2\x99\xb4\x91\x3c\x49\x9d\xea\xf5\x4b\x48\x41\xd5\x04\x48\x29\x98\x49\x36\x70\x0d\xcf\x92\xf3\x65\x42\xb2\xfc\x7e\x86\x44\x1b\x99\x25\xf5\xd0\xb7\x8c\x17\xa8\x5c\xfc\xfc\xb2\x0b\x0f\xd7\x51\x34\x9c\x27\x46\x3a\xbd\xe4\xd2\x7d\xf7\x42\x65\x28\x87\x13\xf9\x6d\xea\x01\x3b\x94\x55\x21\x80\x8b\x49\x96\xb1\xb2\xdc\x03\x38\xb6\xd2\x36\xef\xd6\xd2\xb2\x7d\xaf\xda\x46\xec\x5f\xa3\x2b\x96\x5e\x8b\xb5\xe8\xbb\x61\xbd\x96\x6e\xde\xb7\x74\x68\x1e\x0e\xa8\xc1\x7b\x8c\x99\xfa\x7d\x66\x0f\x0f\x66\xc9\xbc\x6d\x95\xcb\xd7\xdc\x09\x47\x24\x09\x8e\xb0\x51\x91\xb5\x3a\x3d\xf6\x56\x6b\x9c\x90\xe0\xd7\xdf\xf2\x94\x38\x48\xb6\x1a\x20\xd4\x8c\x22\xb6\xd3\xc9\x58\xe2\x93\xd7\x09\xc8\xf4\x81\x10\x23\x0f\xf5\x19\x18\x56\x28\x77\xda\xf6\xd9\x20\xc8\x5a\x82\xe0\x7c\x45\x1f\xe7\xae\x97\x59\xc0\xa7\x7e\x97\xbb\x29\x8b\x5d\x05\x92\xa4\x1d\x08\xf6\x7a\x4e\xd5\xa1\xbb\x41\xe9\x37\xb6\xa6\x8a\xeb\x38\xfd\x5b\xe9"}, -{{0xe9,0x94,0x88,0x05,0xeb,0x34,0x1b,0x28,0x67,0x47,0x9c,0x66,0x8f,0xd3,0x53,0x2c,0x30,0x99,0x41,0xc0,0xad,0x4c,0xb2,0xe5,0x42,0x31,0x75,0x6e,0x6a,0x1b,0xde,0xcb,},{0x54,0x47,0xa8,0xe3,0x4d,0x6a,0x64,0x00,0x02,0xd8,0xd6,0x0b,0xcf,0x1d,0xdc,0x71,0x1e,0x4c,0x46,0x5c,0x94,0xc3,0x4b,0x50,0xbd,0xef,0x35,0x89,0x60,0xff,0x81,0xf1,},{0xd3,0xdc,0x62,0xd6,0xce,0x9c,0x76,0x6f,0x2a,0xba,0xf9,0xa7,0xfb,0xe0,0x9d,0x6b,0xdb,0x07,0xa4,0x74,0x7b,0x56,0x08,0x0d,0xb0,0x9b,0xeb,0x4a,0x4e,0x80,0x4a,0x70,0xd7,0xdd,0xf4,0x11,0x94,0x75,0xc7,0xbe,0x83,0x4f,0x31,0x95,0x6f,0x4a,0x71,0xda,0xd0,0x29,0xcd,0xf2,0x36,0x3d,0xd0,0x36,0x5c,0xe2,0x2d,0xc2,0x7f,0x07,0x80,0x03,},"\x91\xcf\xfd\x7e\xb1\xcf\x6b\xd4\x75\x6b\xce\x6a\x30\xaf\x9d\xfb\xa2\x6d\xdd\x1c\xce\x03\x94\xc1\x94\xa3\xe3\x9c\xc3\xd1\xcb\xc2\x21\xb7\xeb\x70\xbe\xa1\x8d\x29\xc2\x67\x45\x71\x76\xa3\xc9\xe5\x3c\x18\xe4\x7d\x10\xa6\x7c\x46\x45\x05\x19\x77\x02\xe6\xb2\x47\x0d\x38\x86\x9d\xb5\x17\x4b\x15\x8f\x99\x92\xe4\x43\x5d\x02\x24\x6f\x54\x02\x58\xde\xdd\x3c\xe3\x3d\xf5\x82\x55\x5a\x68\x1f\xb7\x6e\xca\xcc\xb1\xc2\x98\x9b\x17\x7e\x3b\x7e\x45\x4a\xaa\x52\x9d\xe5\x9b\xf5\xa0\x31\x23\xd5\x71\xdf\x2e\x7f\x7c\xb8\x30\x80\x5c\x58\xb7\x4a\x65\x3b\xac\x0e\x5a\x88\x8e\x08\xdc\x22\x36\xd6\xcd\x49\x6a\xa0\x6d\x0d\x67\xcf\x3b\x33\x5e\x21\x8c\x49\xde\xda\xd8\x2f\xc1\xbe\x9e\xf2\x0c\xac\x61\x90\x5c\x30\xeb\x13\x2d\x73\x9b\x16\xca\x8a\x8c\x90\x66\x19\xc0\xe0\xd8\xb3\x39\x85\x32\x7e\x36\xf3\xd4\xb8\xfd\xa3\x87\xc1\x86\xcc\x50\x44\x31\x04\xdb\x76\x1f\x7f\xf9\x30\x12\x70\x20\x4a\x71\x3e\x58\x90\x21\x01\xfa\xd0\x00\xce\x93\x16\x47\xc5\x77\xfd\xec\x14\x8d\xca\x95\xcd\xc0\x89\x18\xeb\xed\x03\x7c\x60\x33\x2f\xad\xf0\x88\xf0\x36\x08\x3e\xbc\x92\xe1\x73\xb7\xdd\xcc\x30\xc4\x93\xf2\x7e\x69\xcd\x17\xa2\x0d\x30\xb7\x8f\x83\xa7\x2e\x4f\x5a\x74\x7d\x86\xd9\x6c\x5e\x1b\xb7\xa4\x38\x16\x62\x04\x01\x3e\x21\x64\xd6\xaa\xbc\x0d\x56\x2f\x54\x01\x5c\x36\x5c\x80\x44\x56\x07\x14\x5e\x56\x92\xee\x34\xf6\x35\x30\x77\xfa\xb7\x45\x2d\x88\xce\x3e\xb0\x1d\x2b\x37\x97\xdc\x91\xb3\x41\xa3\xa7\x26\x30\x15\x16\xba\xae\x18\xe8\x51\xf7\x4d\xfb\xdf\x08\x66\xbb\x23\x76\x86\x7d\xe5\x52\x31\xe3\x62\xc4\x72\xc5\x21\x16\x54\x4c\xd4\xf8\x1e\x93\x57\x1c\x4e\xc8\x20\xe7\xe6\x53\xf4\xe2\x1b\xe0\xa9\x42\x57\x6c\x9d\xe9\x1e\x7d\x12\x51\x68\x3d\x85\x9d\xe4\x48\xf8\x22\xdc\xf3\xd2\xcf\x55\xed\xe2\xf9\xc7\x1b\x60\x63\xd1\x37\x30\x61\xf8\xf5\x93\x6b\x69\x8d\x13\x84\xe6\x54\x59\xea\x2b\xc2\x6e\xc9\x67\x75\xef\x42\x52\x07\x43\x2d\xda\x0a\xc1\xfe\x28\x52\x6c\x5e\x45\x59\x34\x9c\x3d\x8d\xf9\x91\x82\x30\xf4\x04\x46\x83\xcc\x2c\x1b\x85\x8d\x14\x1a\xb8\xd0\x80\x5b\xb9\x33\x60\x67\x52\x2a\xa8\x9c\x81\x0f\x3e\xaa\x7a\xc2\xd8\xdd\x28\xc3\x75\x12\x25\xa1\x9e\xce\xc8\xbc\xca\x52\x43\x99\x46"}, -{{0xb0,0x17,0x53,0xef,0xa7,0x3b,0xb3,0xde,0x7a,0xa7,0x78,0xbe,0x7a,0xfc,0xbf,0xf6,0x6a,0x5d,0x3e,0x2c,0x2f,0x8b,0x5a,0xa2,0xb0,0x48,0x84,0x40,0x50,0x99,0x69,0x65,},{0xd0,0xcc,0x6c,0xf1,0x09,0xc9,0x99,0xfb,0xf6,0xd1,0x6f,0x47,0x1f,0xaf,0xd0,0x23,0x2b,0x0a,0x68,0xd4,0xc4,0x64,0x06,0xec,0x75,0x45,0xdb,0xab,0xa8,0x19,0x41,0x58,},{0x16,0xb7,0x42,0x12,0x27,0xae,0x09,0x13,0x06,0x85,0xcb,0xb1,0xa0,0xc6,0x0a,0xa5,0x7a,0x5e,0x1a,0xfe,0x1b,0xbe,0x6b,0xac,0xea,0x0c,0x28,0x1b,0xcc,0x89,0x98,0xe6,0x82,0x4a,0x77,0x2c,0x32,0x08,0xa6,0xb6,0xb4,0xd2,0x36,0x69,0x55,0x05,0xc9,0xbe,0x82,0x70,0x0c,0xf9,0x3a,0x78,0x39,0x85,0xa3,0x9e,0x16,0xe3,0x77,0xa7,0x41,0x0e,},"\x68\x4e\x61\x2f\x27\xee\xad\x0d\x34\x84\x4c\xc8\x1b\xa9\x11\xc2\x8a\xaf\x6d\x66\xe7\x12\x29\xe8\xcc\x34\x62\xf7\xc7\xa0\x50\xda\xa3\x0c\xb7\x44\x71\x15\x0f\x07\xda\xd4\x59\xb5\xa9\x13\x58\x47\x6c\x05\x98\x25\x5d\x8a\x64\x2d\xd7\xc0\x80\x28\x11\xbd\x88\xe4\xca\xc5\x97\xef\xe4\x1e\xbd\x96\xcd\x0f\x3b\x5c\xe7\x2d\xb4\xbe\x1a\x3d\xbd\x6b\x84\xf5\x44\x6e\x3d\xa6\x00\xd3\xb1\xd2\xb4\x60\xa0\x09\xbd\x31\xca\xcd\x98\xa9\x15\x18\xce\x33\xe9\xa7\x03\xd4\x04\x28\x87\x36\xcc\xc4\x31\x03\xfc\x69\xe6\x79\x74\xf3\x16\x52\xfa\x3d\xad\xef\x33\x37\xf6\xc8\x97\xa3\xd2\x01\x30\x3c\x8f\x03\x59\x7b\x4a\x87\xc9\x8f\x29\x1c\xcd\x58\xa3\xf1\xe8\x98\x33\x2a\xa5\x99\x3b\x47\xfc\xb5\xdd\xaa\x1c\x08\x68\xb6\x43\x74\x2d\x0e\x4a\x4b\x9c\xd4\x27\x03\x8b\x3b\x74\x99\x9b\xc8\x9a\xc3\x48\x4c\x0c\xa1\x3f\x25\xaa\xe8\xe7\x8a\xe1\xcc\xee\x62\x18\xac\xca\xb8\x1a\x4f\x69\x4f\x53\x24\xa3\x47\x62\x9d\x49\xb5\x5e\x40\x37\x50\x4a\x9a\xcc\x8d\xf5\x8c\x68\x41\xdd\xdc\xd4\xfc\x43\x47\xf7\xb6\xf1\xfd\x9d\xe0\x56\x45\x77\xe6\xf3\x29\xed\x95\x1a\x0a\x6b\x91\x24\xff\x63\xe2\x2e\xb3\x6d\x3a\x88\x63\xbc\x1b\xf6\x9c\xea\x24\xc6\x05\x96\x7e\x7d\x89\x48\x95\x3f\x27\xd5\xc4\xc7\x5f\x08\x49\xf8\x72\xa3\xe3\xd1\x6d\x42\x2f\xa5\xa1\x1e\x1b\x9a\x74\xdf\x6f\x38\xb9\x0f\x27\x7d\x81\xfc\xe8\x43\x7a\x14\xd9\x9d\x2b\xef\x18\x9d\x7c\xac\x83\xdd\xc6\x13\x77\xed\x34\x8b\x3c\x4f\xc0\x9e\xc2\xb9\x00\x59\x25\xd0\x4a\x71\xe2\x6d\x64\x16\x67\xbd\xf5\x49\x29\x43\x31\xc6\xea\x01\xcd\x5c\x0b\xd1\xb6\xa7\xec\xfd\xa2\x0b\x0f\x19\x29\x58\x2b\x74\x69\x7c\xb2\x62\xc3\x92\x7d\x6b\x22\x3f\x4b\x5f\x30\x43\xaa\x6e\xb4\x57\x1a\x78\xe9\xda\x11\xc2\xb3\x6f\x64\x55\x25\x80\xca\xa7\xb5\xfa\x6b\x90\xf9\x29\xe0\x16\x2e\x60\x8d\x12\x40\xd7\x24\x2c\xd2\xf4\x70\x25\xc0\x3d\xeb\xe0\x59\xb1\xdc\x94\x77\x02\x32\xbc\x67\x65\x14\x84\x80\xbb\x1d\x9f\x50\xda\x1e\xe6\x44\x8c\xf9\xc8\x8b\x19\xdd\x45\x99\x32\xc0\x6e\xd8\x11\xc4\xa6\x4a\x12\xd5\x93\x8b\xd1\xc7\x57\xbc\xfa\xea\xee\x89\x33\xfe\x5f\xff\x21\x76\x3d\xe7\x40\x48\x2b\xcf\x1b\xa5\x9a\xfd\xc8\xfc\xf8\x73\xc3\xd5\x07\xbb\x39\x4e\x32\xe4\x5f\x73\x65\x19"}, -{{0x4f,0x4b,0x20,0xd8,0x99,0x36,0x6f,0x2f,0x23,0xee,0x62,0x8f,0x22,0x9b,0x23,0x6c,0xf8,0x0f,0x43,0xba,0x18,0x31,0x77,0xc9,0x7e,0xe3,0x48,0x29,0x54,0x6f,0x17,0x42,},{0xc9,0x45,0x76,0x64,0x1f,0x4a,0x89,0x3c,0xdf,0xce,0xe7,0xb3,0x9f,0xc2,0x19,0x29,0xb8,0x6b,0x34,0x99,0x76,0xd7,0xb0,0xa4,0x6d,0x39,0xa5,0x88,0xbc,0xfe,0x43,0x57,},{0x0f,0x80,0xff,0x5d,0x17,0x48,0x8f,0xe2,0x6f,0x93,0xc5,0x43,0xb0,0x4e,0xd9,0x59,0xb5,0xf0,0x64,0x3f,0xc6,0x1c,0x7f,0x2c,0x3b,0xc6,0x01,0x32,0xba,0x9c,0x62,0x10,0xc8,0xb2,0x50,0xea,0x5e,0x84,0xd0,0x7b,0x01,0xde,0x68,0xbc,0x17,0x44,0x14,0xee,0xeb,0x31,0xfd,0xc2,0xba,0x68,0x23,0xe2,0x31,0xe3,0x12,0xa9,0x1e,0xde,0xdd,0x02,},"\xdb\x8e\xf0\x2e\x30\x33\xe6\xb9\x6a\x56\xca\xb0\x50\x82\xfb\x46\x95\xf4\xa1\xc9\x16\x25\x0d\xd7\x51\x73\xf4\x30\xa1\x0c\x94\x68\x81\x77\x09\xd3\x76\x23\x34\x6a\xe8\x24\x5b\x42\xbd\xa0\xda\x6b\x60\x46\x2c\xcf\xdf\xc7\x5a\x9a\xb9\x94\xe6\x6c\x9a\xb9\xfe\xcd\xd8\x59\x96\x10\x91\x0a\xff\xe4\xf1\x02\x15\xcb\x28\x0b\xf8\xf9\xf2\x70\x0a\x44\x47\x96\xda\xe9\x3e\x06\xc6\xbe\xa7\xd8\xb4\xfe\x13\x01\xba\xa7\x9c\xce\xc7\x69\x36\x8f\xeb\x24\x42\xc7\xde\x84\xf0\x95\xe6\xb3\xbf\xf6\x3d\x38\x8c\xba\xfb\x2b\x98\x09\xdc\x38\xe9\xb1\x2e\xbd\x03\x9c\x0a\x57\xf4\xd5\x22\xe9\x1e\xc8\xd1\xf2\xb8\xd2\x3a\x4a\x0a\xe0\x59\xaf\x85\x39\x3b\xb0\xa1\x5f\x74\x91\x10\xf6\x77\x4a\x1f\xd7\x31\xa6\xec\x21\x3e\x4f\xf4\x35\xda\xab\x54\x6d\x31\xed\x9e\xc3\xb6\xd8\xcc\x2e\xda\xce\xbf\x4f\xac\xc5\x56\x65\x56\xee\xa9\x2e\x5b\x3f\x25\x42\x23\x9b\x25\xe2\x80\x12\xdd\x4e\xf4\x00\x72\xee\xbf\x83\xed\x2a\x25\x51\x81\xf3\xa4\x42\x18\x9d\x68\xc6\xc6\x09\xf4\xdf\xdf\x3d\xb7\xd6\x7d\x08\x7a\x2f\xcd\x6d\x2d\xc5\x0b\xbf\xed\x8b\xfb\xbf\xcb\x74\xd3\xc4\x1f\x02\xa8\x78\x65\xb1\x3b\x8e\xfc\xf5\xc3\x58\x12\x57\xbe\x0a\xa9\x13\xf6\x0c\x37\x05\x27\xbd\xe1\x1a\x47\x5c\x13\x6a\x17\xc5\xee\xfe\xb0\x3f\x5b\xff\x28\x69\x3e\xd8\x41\xe8\xed\x1f\x7c\x29\x10\x2f\x55\x99\xdd\x44\x40\x09\xbc\xea\x6a\x92\xd5\x57\x41\x52\x45\x8e\x0c\xaf\x8a\x36\xaa\x72\xb5\xdc\x49\x08\xa6\x46\x1c\x9b\x74\x14\x53\x00\x5c\x8f\xbc\xc6\x81\x13\xae\x18\x42\x08\xee\x14\xb8\x35\x48\x0c\x6e\xfa\xfe\xd1\x8a\x76\x00\x0b\x38\xe5\x85\x82\x90\xf4\xd5\x1f\x52\xf0\x96\xcb\xe4\x90\xe1\xeb\x5c\xac\xb2\x26\xec\x49\x5a\x55\xa7\xfa\x45\x78\x43\xd5\x7f\xab\x67\xf8\xbe\x7e\x20\x93\x34\x78\x5b\xdd\x66\x5d\x7b\x63\xe4\xda\xf5\x7b\x6e\x78\x92\x8b\x60\x3c\x8c\x0f\x9b\xc8\x54\x64\x73\x3b\x61\x27\x3e\xf9\xe2\xb8\xa0\xcd\x7c\x3b\xf8\xee\x0a\x68\x72\xe3\x4d\x5a\x27\xa6\x25\xe3\x5e\xaf\x7f\xf5\x44\x0b\x8b\x14\x1a\xf7\x04\xdf\x70\xc9\xc1\x86\x23\xbd\x11\x20\x95\x13\x19\x25\x05\x10\x5c\xd7\xbc\xfa\x5f\x0d\x91\x9d\xa7\x06\x94\x8f\xbe\x1f\x76\x1f\x31\x58\x46\xaa\x3b\x48\x13\xdd\x9b\xa3\xd8\x1b\x92\x04\xe5\x40\x9c\x03\x82\xb6\xeb"}, -{{0xd2,0xe0,0x1d,0x25,0x78,0xb6,0x25,0xa7,0x06,0x0a,0xab,0xc2,0x57,0x65,0xf1,0x68,0xc6,0x80,0xce,0xf7,0x67,0xaa,0x97,0xca,0x0e,0x5e,0xb3,0xd6,0x67,0x47,0x4b,0x2a,},{0x19,0x1a,0xc2,0x23,0x57,0x54,0x24,0xaa,0x35,0x4b,0x25,0x5b,0x81,0x2d,0xd3,0x02,0x5d,0x70,0xed,0x82,0x9e,0x08,0x26,0xc0,0x16,0x29,0xf9,0xdf,0x35,0x45,0x08,0x2b,},{0x87,0xa0,0x10,0x39,0x4a,0x9f,0x2c,0x90,0x4e,0xff,0xef,0xca,0x9f,0xb4,0xd5,0xce,0x13,0x79,0x33,0x01,0xa4,0x92,0x5b,0xa5,0x1d,0xb1,0x19,0x12,0x3a,0x4d,0x73,0x0a,0xbf,0x76,0x4c,0xe0,0x65,0xe4,0x8d,0x90,0xa7,0x9d,0x90,0x7d,0x72,0x54,0xc4,0x0c,0xc3,0x58,0x98,0x7a,0x46,0x94,0x9e,0x92,0x8b,0xbb,0x3c,0xd0,0x85,0xdf,0xab,0x06,},"\x20\xd5\xdd\x69\x9b\x28\x53\x30\x2a\x68\x17\x09\x4d\x5e\xa5\x12\xbd\xf8\x53\x45\x04\xcb\x28\x9c\x60\x24\x67\x41\x07\x40\xec\x7e\xb8\xea\x64\x42\xc8\x0f\x14\x59\x35\x06\x8f\x91\x22\xfd\xf4\xa3\x9f\x20\x10\xf3\x3d\xb5\x5b\x81\x4d\x97\xbf\x2e\x58\x72\x32\x9f\x11\x26\xd4\xeb\x95\xb8\x06\xca\x19\x73\x11\x31\x65\xb1\x16\xbe\x87\x16\x37\x1f\x81\x33\x17\x79\xdc\x79\xa5\xcb\x39\x42\x08\x1a\xb5\xf2\x07\xf6\xb5\x3d\xb0\xe0\x03\x81\x07\xd6\x3c\xa9\x77\x08\x18\x19\x82\xdc\xb5\xf3\xb9\x30\x10\xec\x6e\xdf\xb2\xcf\xd3\x1c\xab\x00\x09\x0b\x3c\x38\x51\x5f\x97\x81\x76\x96\x86\xcb\x17\xab\x81\xd5\x4a\x8b\x77\x57\x54\xd4\x2f\xba\xd0\x86\xb8\x0b\x28\xd6\x36\xf7\x8b\x7e\xb7\x7e\xd9\xca\x35\xb6\x84\x3a\x51\x0f\x0a\xd0\xac\x1b\x20\x26\x7a\x00\x03\x01\xb3\xc7\x07\xa2\x0f\x02\x14\xd5\x9b\x5b\x81\x99\xc2\xf9\xee\x25\xd3\x20\x60\xac\xe3\xe0\xf2\x59\x46\x50\x41\x6a\x00\x71\x6c\xd3\xf9\x86\x04\xa5\xe1\x04\xb3\x33\x10\xfd\xae\x94\xc3\x14\x01\x3c\xdc\xa5\xba\x24\x14\x40\x9e\xb7\xf1\x90\x13\x94\xf0\x07\xd6\xfa\x0a\x29\xdb\xe8\xec\x3d\xf9\x8c\x39\x3c\x8d\x72\x69\x58\x77\xcc\x9b\xaf\x49\x1e\xf3\x0e\xf7\xdb\x33\x71\x60\x8c\xa9\x7c\xc6\x21\x56\x25\x20\xee\x58\x1d\x5d\x1c\xdb\xc7\x82\x32\xd6\xc7\xe4\x39\x37\xb2\xcc\x85\x49\xe6\xf1\xe0\x8d\xf5\xf2\xea\xc8\x44\xfe\x0f\x82\x2b\x24\x83\xad\x0a\x5d\xe3\x3b\xe6\x40\x89\x49\x0e\x77\xd6\x98\x00\xfa\xe2\x58\x9e\xe5\x87\x12\xac\x15\xa3\xf1\x9e\x6f\xfd\xbc\xa4\x2f\xe1\x89\x4e\x88\x9b\x94\xc0\x4b\x04\x24\x0d\xaf\xb0\xb2\x73\x0c\x23\x6b\x8c\xce\xb2\xcb\x97\xaf\xd1\xd5\x15\xdc\x19\xd1\x06\x7f\xd4\xab\xa8\xce\x29\x7f\xd6\xd1\x10\xb3\x5a\x21\xbd\x3c\x07\x5c\x57\x7d\x93\xfe\x1d\xf7\x7d\x64\x8f\x71\x19\x49\x20\x99\xb0\x17\xaf\x44\xeb\xa0\x9c\x80\x7f\x11\xa4\xc3\xf4\xa1\x1a\x2f\xff\x30\x6a\x72\x8b\xa7\x89\x83\x32\x3c\x92\xa2\xfd\x5f\xcc\x80\xc1\x8d\x42\x34\x26\xf8\x23\xa7\x3f\xe0\x40\x94\x95\x52\x84\x29\x3f\x5f\x6b\x3c\xa4\xff\x10\x80\xdb\xb1\xe4\xc6\xf7\x4c\x1d\x93\x5e\xd2\x1e\x30\x09\x4c\x7d\xe3\x36\xb8\x2d\xd8\x20\x0b\x0d\x65\x95\x83\xc5\xbf\xd5\x47\x0f\x9d\xb3\x42\xe7\x0e\xc4\x00\x07\x42\xc5\x64\x0a\x21\x4e\x3c\x2e"}, -{{0x7c,0xd7,0xec,0x99,0xdd,0x03,0xae,0xde,0x1f,0xf1,0x07,0x3e,0xc2,0xca,0x70,0x10,0x27,0x6e,0x94,0x7e,0x2a,0xa9,0xb0,0xe6,0x5f,0x87,0x7e,0x4c,0xcf,0x1b,0x3a,0x14,},{0xe4,0xc3,0x9d,0xbe,0x94,0x93,0x17,0x6b,0x82,0x13,0xf1,0x42,0x2a,0x9d,0xe7,0xc7,0x4f,0xb6,0xa5,0x91,0x90,0xfc,0xdb,0xf6,0x37,0xc7,0xad,0x5e,0xe1,0x65,0xc0,0x4f,},{0x6f,0x99,0x20,0x27,0x70,0x96,0x45,0x35,0xe4,0x83,0xa0,0xee,0x01,0xa5,0x29,0x44,0x2e,0xb3,0x21,0x30,0x3f,0xa8,0x05,0xd4,0x75,0x60,0x4d,0x7f,0xc7,0x28,0xa9,0x10,0x3f,0xb7,0xb5,0x58,0xb9,0x55,0xf4,0xd0,0x37,0x19,0xee,0xfa,0xa3,0xb7,0xed,0x5b,0x0d,0xa7,0x57,0x10,0xbb,0x98,0x78,0x7f,0x5c,0x22,0x82,0xed,0x66,0xe9,0xf6,0x0c,},"\xa6\x03\x4a\xa3\xc2\x48\x49\x23\xe8\x0e\x90\xe5\xa8\xe1\x74\x83\x50\xb4\xf2\xc3\xc8\x31\x9f\xaf\x1a\x2e\x32\x95\x15\x0a\x68\xe1\xee\xca\x1b\xc8\x49\x54\xcc\x89\xd4\x73\x1a\x7f\x65\x12\xaf\x01\x46\x4f\xdb\xce\x5d\xf6\x8e\xe8\x06\x6a\xd9\xa2\xfd\x21\xc0\x83\x5a\x76\x55\x9c\xa1\xc7\x44\x9a\x93\x3b\xcb\x15\xaf\x90\x22\x3d\x92\x5f\xf6\x1c\xd8\x3e\xb9\x35\x69\x83\x47\xa5\x70\x72\x70\x9a\x86\xb4\xe5\xa7\xa6\x26\xe0\x7a\x3f\x2e\x7e\x34\x1c\x77\x83\xa5\x40\xf8\x4a\xa7\x3e\x91\x7e\x86\x7b\xb8\x0b\xac\xe6\x25\x47\x05\xa9\xd1\xa1\x18\x5d\xe5\x6e\x1a\x4e\x78\xaa\xf5\x39\xe7\x49\xb8\xf7\x65\xbd\x05\x2c\x4c\xd1\x5b\x63\x8b\xf8\xec\xf8\x7d\x98\x14\x60\x6f\xed\x5a\x69\xf4\xda\xe9\xda\x47\xf3\x80\x6d\xd9\x0b\xe6\x4f\xcc\xd3\x36\x5c\xbe\x9e\x01\xc5\x88\xfe\x65\xd6\xb6\x03\x28\x07\x40\x96\x2a\xa8\xdd\xb9\x5a\x3f\x4f\x67\x4c\x03\xbc\x40\x43\x09\x2c\x54\x45\x95\x56\x82\x70\xa2\xc2\xa8\xaa\x06\xe3\xf6\x7c\x31\x99\x8c\x50\xb9\xa5\x8a\xca\xd0\x06\x90\xd3\x84\x81\x14\xcb\x19\x32\x93\xc8\xac\x21\x01\x6f\xd9\x96\xf5\xc6\x42\x14\x06\x4f\x82\x16\x7b\x2c\x92\x0c\xd8\xa8\x39\x75\x58\x52\xac\x77\xc3\xd9\x05\x26\xdd\x3a\xdb\x96\x83\x7c\xf4\xe7\x26\xf3\x4b\xd0\x29\x55\xcb\xac\x5b\x82\xc9\x2c\xf4\xaa\x8b\x54\xbb\x6e\x43\x6d\xae\x9b\xf8\x93\xef\x05\x0c\x6f\x13\x5a\x7e\x62\xfc\xd8\x34\xda\xc1\xd2\xbe\x8b\x8e\x59\xd6\x96\x13\x18\x11\x70\x1c\x43\x18\xbb\x6e\x9b\x5a\x20\xbe\xc6\x56\xfd\x2b\xa1\x92\xe2\x73\x2f\x42\x29\x63\xbe\xd4\xa4\xfd\x1e\xc9\x32\x63\x98\xdc\xe2\x90\xe0\x84\x8c\x70\xea\x23\x6c\x04\xc7\xdb\xb3\xb6\x79\x21\x44\x0c\x98\xd7\x27\x53\xf6\xa3\x32\xea\xad\x59\xfd\x0f\x57\x74\x29\x23\xfb\x62\x5f\xef\x07\x0f\x34\x22\x5e\xa0\x6c\x23\x63\xd1\x23\x66\x6b\x99\xac\x7d\x5e\x55\x0d\xa1\xe4\x04\xe5\x26\xb5\xb2\x29\xcb\x13\x0b\x84\xb1\x90\x3e\x43\x1c\xdb\x15\xb3\x37\x70\xf5\x81\x1d\x49\xfb\xd5\x0d\x60\xa3\x47\x4c\x0c\x35\xfc\x02\x1d\x86\x81\x81\x9e\xc7\x94\xcc\x32\xa6\x34\xbc\x46\xa9\x55\xaa\x02\x46\xb4\xff\x11\x24\x62\x3c\xba\xfb\x3c\xb9\xd3\xb9\x2a\x90\xfd\xe6\x48\xe4\x14\x63\x61\x92\x95\x2a\x92\x29\x1e\x5f\x86\xef\xdd\xb8\x9c\xa0\x78\xae\xa7\x71\x7f\xc7"}, -{{0xe3,0xca,0x37,0x13,0xa2,0xfd,0x41,0x2a,0xd5,0x33,0x6b,0xc3,0x56,0xb7,0x7b,0xe0,0x27,0xd5,0xb7,0x08,0x15,0xb3,0xac,0x2a,0xec,0xd8,0x34,0x0e,0xf5,0xf8,0x89,0xb1,},{0x1d,0x51,0x6c,0xb8,0xbe,0xf1,0x16,0xa0,0xc1,0xb6,0x92,0x90,0x09,0x93,0x3f,0x6e,0xb6,0x2c,0x23,0x05,0x07,0x45,0xfe,0x7e,0x8d,0x3c,0x63,0x16,0x23,0x77,0x81,0x11,},{0xb3,0x85,0x7e,0xa6,0x1b,0xaa,0x9e,0x62,0x83,0x8c,0x4e,0x3a,0x99,0x65,0x02,0xd3,0x36,0x4f,0xe1,0xec,0x59,0x42,0x58,0x35,0x50,0x73,0xdd,0x10,0xe4,0x97,0xc6,0x00,0xbe,0xfb,0x1f,0x8f,0x23,0x3f,0xd6,0xe3,0xb2,0xc8,0x7f,0x10,0xdc,0xb7,0x26,0x1a,0xaf,0x34,0x81,0xbf,0xd0,0x90,0x26,0x05,0xac,0xcc,0x90,0x0f,0xef,0x84,0xd4,0x07,},"\xdd\x99\xba\xf2\x95\xe0\x13\xee\xd1\x07\xba\x8a\xf8\x11\x21\xaa\xf1\x83\x5a\x3c\xca\x24\xf8\xe4\x64\xb4\xcf\xca\xa3\xc7\xbf\xfe\x6f\x95\x36\x01\x6d\x1c\x8c\xf3\x75\x03\x8c\x93\x27\xe8\xe2\x1b\x00\x40\x66\xf5\xea\xc0\xf7\x6a\x3e\x8e\xdf\xb0\x7b\xe8\xbd\x2f\x6b\xc7\x9c\x3b\x45\x6d\xe8\x25\x95\xe2\xc2\x10\x5b\xb1\xb0\xaa\xba\x5e\xee\xe1\xad\xef\x75\x21\x67\xd6\x33\xb3\x22\xeb\xf8\xf7\xcd\x5f\xbf\x59\x50\x8f\xdb\xdb\xec\xf2\x5e\x65\x7a\x9c\x70\x50\xaf\x26\xa8\x0a\x08\x5b\x08\x17\xc6\x21\x7e\x39\xac\xd5\x4c\xb9\xfa\x09\x54\x0f\xc7\xbd\xc5\x22\x6d\x6a\x27\x6d\x49\x2c\xc8\xa3\xdf\xfc\x2a\xbc\x6d\x0b\x9f\xb0\x8c\xbc\xcd\xd9\x43\x2e\x44\x98\x21\xa5\xdc\x98\xcf\xb3\xa4\x18\xe5\x39\xc8\x90\xfe\x5a\x04\x46\xb9\xf8\x1d\x30\x67\x00\x92\x7a\xde\x61\xcf\xdc\xc0\x62\x4f\x13\xb5\x84\x07\x48\x77\x46\x04\x80\x57\x31\xd9\x2e\x77\xd5\xde\xf6\x6b\xe4\x4c\xc8\x17\x94\x6f\x1c\xd7\x58\x19\x6c\xf4\x80\xf9\x9e\x71\x17\x83\x5c\x4c\x87\xcb\xd6\x40\x77\xa5\x62\xa8\x0c\xf1\x1d\x8c\xa6\x5b\xe7\xa9\x4d\x92\xb9\xdd\xae\xa9\x97\xe9\x3f\x14\x48\x57\x7e\xd6\xd8\x43\x6b\x2f\x31\x44\x69\x2c\x1f\xd7\xd2\x8a\x03\xe9\x27\x4b\xc9\xe8\x66\x9d\x85\x75\xf5\xde\x20\xcf\xbd\xbc\xb0\x4e\x9f\x39\xf3\x45\x1d\x70\x48\x37\x5e\x26\x98\xe7\x22\x84\x6c\xb4\xf2\xd1\x9a\x81\x0c\x53\xd4\xc1\xa6\xc3\xb7\x70\xfb\x40\x2d\xf0\x53\x0e\x7b\x29\x07\x22\x3f\xd0\x89\x9e\x00\xcb\x18\x8c\xa8\x0c\x15\x31\xb4\xe3\x7f\xba\x17\x6c\x17\xa2\xb8\xf5\xa3\xdd\xc7\xa9\x18\x8d\x48\xff\xc2\xb2\x72\xc3\xda\x9c\x9b\x89\xdf\xe5\x3f\x2f\xe7\xe3\x67\x2f\x91\xd1\x18\x18\x49\x1a\xce\x14\x0a\xdc\xae\x98\x50\x2e\x11\x4f\x4b\x35\x2b\x90\xe2\xe7\xfb\xd3\x33\xb2\x45\x9e\x7f\x15\xdd\x07\x64\xc9\xc3\x4e\x4c\xb7\xcc\x09\x55\x00\xcd\xa0\x35\xe8\xe2\xe4\xe3\xc8\xfd\x5d\xf5\xf3\xaa\x57\x9a\x73\x5d\xd8\xa9\xf1\x9e\xf3\x36\xfa\x97\x11\x14\xe4\x66\x18\x73\x4a\x4c\x13\xd3\x0c\x81\x12\x8c\xa2\x1d\xef\x47\x33\x01\x03\xd2\x3d\x80\xff\xe6\x74\x21\xa6\xcc\xf9\xf3\x6a\x93\xf0\x56\x03\xc5\x99\xee\x10\xb0\x34\x51\xf3\x6b\x21\x33\xc1\x87\xa7\x9a\xd9\xe6\xfd\xfb\xb1\x25\x95\xab\x73\xbb\x3e\x2e\x2e\x43\x03\x0f\xd3\x7e\x59\x1c\xf5\x5d"}, -{{0x29,0xa6,0x3d,0xcd,0x48,0xa3,0x51,0x77,0x14,0x11,0xfd,0xdc,0xab,0x46,0xbb,0x07,0x1e,0x91,0x49,0x85,0x76,0xe8,0xd0,0x2f,0x8b,0x60,0x44,0xf5,0xbd,0xd3,0xed,0x90,},{0x39,0x23,0xfd,0xcc,0x2a,0x9f,0xe5,0xca,0xbf,0x6e,0x99,0x32,0xe4,0x6d,0xbd,0x2b,0x7f,0x36,0x32,0x50,0x0f,0x9d,0x95,0x55,0x2d,0xb2,0xb0,0x45,0xbc,0x41,0x16,0x6f,},{0x12,0xbf,0x62,0x95,0x93,0xe2,0xca,0xad,0xc9,0x10,0xec,0x40,0xbf,0xe2,0xb7,0xa6,0x25,0x14,0x12,0x6b,0x16,0xba,0x3a,0x43,0x8d,0x88,0xe2,0xd2,0x1f,0x59,0x5a,0xae,0xe8,0xab,0xfa,0x4a,0xf2,0xec,0x87,0x03,0x61,0xd0,0xea,0x04,0xdf,0xc8,0xc6,0xa3,0x30,0xfb,0x28,0x41,0xc2,0xd8,0x21,0x1a,0x64,0xfa,0x1e,0x7e,0x7d,0x27,0x38,0x00,},"\xff\x18\xca\x0c\x20\x4c\x83\x86\xa4\xaa\x74\xec\x45\x73\xc7\xb6\x92\x16\xb3\x14\x70\xda\xed\xd9\x6a\x4f\x23\x02\x11\x6c\x79\x55\xd7\x2d\xac\xc8\x8e\x37\x14\x55\x0c\x09\xe6\xf7\xb9\xa8\x58\x62\x60\xdc\x7e\x63\xda\x4c\x63\x3b\xae\x01\x62\xe1\x16\xe5\xc1\x79\x7b\x78\xd8\x7d\x47\xff\xee\xa3\xd7\x81\x9d\xf9\xc8\x52\xf0\xff\x30\x93\x6a\x10\x5d\x3a\xf5\x53\x1a\x8f\x89\x54\x97\x11\xc1\x4c\x2d\x3e\xe1\x15\x64\xe7\xc8\x52\x5b\xd5\x88\x64\x00\x97\x62\xa0\x55\x41\xd8\xe0\x7a\xd8\x41\xa5\x5a\x6a\x9a\x00\x7e\xf2\x09\xcc\xec\x4b\x56\x40\xba\xbe\x35\x65\x1b\x61\xdf\x42\xde\x4d\x91\x0e\xe7\x3a\x93\x3c\x0b\x74\xe9\x95\x75\x7e\x84\xa9\x9e\xb0\x34\xf4\x18\x07\x18\x3c\x90\xca\x4e\xa8\xd8\x4c\xdb\xa4\x78\x61\x3c\x8e\x58\x7c\xb5\xf8\xfb\x6a\x05\x50\x81\xda\x6e\x90\x22\x0d\x5d\x86\xe3\x4e\x5f\x91\xe4\x88\xbd\x12\xc7\xa1\xa6\xb3\xc9\xfc\xe5\x30\x5e\x85\x34\x66\x58\xef\xfa\x81\x0d\x0e\x8a\x2a\x03\x9d\xb4\xa4\xc9\x49\x65\xbe\x40\x11\xf9\xd5\xe5\xda\x26\x62\x33\xe6\xc4\xe1\x8e\xd4\xf8\xa2\x5a\x57\xe4\x0a\x59\x1c\x7e\xd5\x90\xc0\xf8\xb1\xa1\x19\xc7\xc9\x74\x7f\x69\x1b\x02\x19\x6c\xd1\x8e\x69\x45\x21\x3f\x1d\x4c\x8c\x95\x79\xc6\xe0\xa2\xac\x45\x92\x41\x28\xd6\xd9\x2c\x8e\x4c\x66\x06\x53\x20\x35\x3d\x48\xd1\xd5\xe1\x31\x94\xd9\x05\xf8\x37\x07\x8f\x8d\xac\x0b\x68\xcf\x96\xae\x9e\x70\x55\x4c\x14\xb2\xfa\x29\xb1\x96\x30\xe4\xb0\xf5\xd2\xa7\x67\xe1\x90\xef\xbc\x59\x92\xc7\x09\xdc\xc9\x9a\xa0\xb5\xaa\xf4\xc4\x9d\x55\x13\xe1\x74\xfd\x60\x42\x36\xb0\x5b\x48\xfc\xfb\x55\xc9\xaf\x10\x59\x69\x27\xbc\xfa\xd3\x0b\xac\xc9\x9b\x2e\x02\x61\xf9\x7c\xf2\x97\xc1\x77\xf1\x92\x9d\xa1\xf6\x8d\xb9\xf9\x9a\xc6\x2f\xf2\xde\x3b\xb4\x0b\x18\x6a\xa7\xe8\xc5\xd6\x12\x39\x80\xd7\x59\x92\x7a\x3a\x07\xaa\x20\x8b\xee\xb7\x36\x79\x5a\xe5\xb8\x49\xd5\xda\xe5\xe3\x57\x37\x10\xaa\xa2\x4e\x96\xd5\x79\x1e\x27\x30\xd0\x27\x0f\x5b\x0a\x27\x05\xba\x51\x5d\x14\xaa\x7e\x6f\xa6\x62\x23\x75\x37\x7f\x9a\xba\x64\xd0\x25\x69\xa2\x09\xd3\x3d\xe6\x86\xe0\x89\xec\x60\x11\x8e\x48\x14\xff\xc6\xc0\x77\x8c\x64\x27\xbc\xe2\xb6\xb8\x44\xcf\xcd\x5a\x7c\xed\x0e\x35\x30\x3f\x50\xa0\xdf\xe5\xdf\x5d\xde\x1a\x2f\x23"}, -{{0xc7,0x18,0x8f,0xdd,0x80,0xf4,0xcd,0x31,0x83,0x9e,0xc9,0x58,0x67,0x1e,0x6d,0xd0,0x8b,0x21,0xf9,0xd7,0x52,0x8c,0x91,0x59,0x14,0x37,0x34,0xf9,0x4b,0x16,0x98,0x83,},{0x01,0x97,0x52,0xff,0x82,0x9b,0x68,0x59,0xb9,0x05,0x8d,0x00,0xc2,0x79,0x5e,0x83,0x56,0x55,0x44,0x06,0x75,0x75,0x3f,0x37,0xe8,0x5e,0xb7,0xbc,0x58,0x39,0xc4,0xca,},{0x35,0xc1,0x70,0xdd,0x0c,0x6d,0xc2,0x92,0x0a,0x59,0x57,0x75,0xd8,0xe2,0xdd,0x65,0x24,0x3e,0x9c,0x1b,0xf9,0x6e,0xf4,0x27,0x79,0x00,0x1e,0xd4,0x5f,0x01,0xb7,0xdf,0xeb,0xd6,0xf6,0xa7,0xdc,0x2d,0x38,0x6e,0xf4,0xd2,0xa5,0x67,0x79,0xeb,0xe7,0x7f,0x54,0xe5,0xae,0xcf,0xda,0x2d,0x54,0xa0,0x68,0x47,0x6b,0x24,0xdb,0xd7,0x8b,0x0c,},"\x4a\xf5\xdf\xe3\xfe\xaa\xbe\x7f\x8f\xcd\x38\x30\x8e\x0b\xd3\x85\xca\xd3\x81\x1c\xbd\xc7\x9c\x94\x4e\xbf\xe3\xcd\x67\x5c\xf3\xaf\xbe\xf4\x54\x2f\x54\x29\x75\xc2\xe2\xa6\xe6\x6e\x26\xb3\x2a\xc3\xd7\xe1\x9e\xf7\x4c\x39\xfa\x2a\x61\xc5\x68\x41\xc2\xd8\x21\x2e\x2b\xd7\xfb\x49\xcf\xb2\x5c\xc3\x60\x9a\x69\x3a\x6f\x2b\x9d\x4e\x22\xe2\x09\x9f\x80\xb7\x77\xd3\xd0\x5f\x33\xba\x7d\xb3\xc5\xab\x55\x76\x6c\xeb\x1a\x13\x22\xaf\x72\x6c\x56\x55\x16\xce\x56\x63\x29\xb9\x8f\xc5\xdc\x4c\xbd\x93\xce\xfb\x62\x76\x88\xc9\x77\xaf\x93\x67\xb5\xc6\x96\x59\xe4\x3c\xb7\xee\x75\x47\x11\xd6\x65\xc0\x03\x2a\xe2\x29\x34\xf4\x4c\x71\xd3\x11\x78\xef\x3d\x98\x10\x91\x28\x74\xb6\x2f\xa5\xe4\x02\x0e\x6d\x5d\x64\x58\x18\x37\x32\xc1\x9e\x2e\x89\x68\x5e\x04\x64\xe9\x1a\x9b\x1c\x8d\x52\x51\xe2\x4e\x5f\x91\x81\x3f\x50\x19\xa7\x40\xa0\x4b\x5d\x91\xcb\xb8\x30\x9e\x51\x61\xbb\xa7\x9d\xca\xb3\x82\x39\xa0\x91\xf5\x0e\x09\x9f\xf8\x19\xe3\xa7\xb5\x20\x5f\xe9\x07\xcd\xfe\x9c\x0d\xc3\xee\x85\xe3\x2d\x7b\xcd\x3c\xe0\x26\x35\xe2\x05\x83\x88\x03\x1e\x31\x7f\xbf\x22\xab\x9f\x39\xf7\xf7\xe3\xcd\x1a\x11\xa9\xc1\xf4\x5f\x4e\x1e\x42\xd2\x53\x6c\x12\x2c\x59\x18\x37\x91\x18\x47\x10\x8c\xea\xfd\x99\x08\x13\xc2\xb6\x34\x4c\xff\xc3\x4b\xe3\x71\x61\xdd\x81\x56\x26\x90\x0e\x8f\xcb\x85\xc2\x1a\xfb\x4f\x6b\xe8\xad\x01\x51\x6a\x31\xc2\xa6\x58\x03\x15\x85\x7c\x6a\x21\x67\x35\xca\x99\x10\x09\xdb\xc2\xea\x50\x34\x16\x07\x47\xa8\x69\xd5\xca\xdb\x0b\x47\xff\xbd\x5d\x3a\xc9\x7f\xdd\x05\x26\xca\xe6\xea\xa3\x5c\xff\x7a\x16\xea\xf4\xfb\x95\x0c\xa3\x15\x11\x34\x6f\xea\x61\x41\x99\x9a\x3f\x75\x4e\x62\x81\xcf\xba\x15\xe8\xa8\x26\x93\x2c\x58\x9c\x5d\x24\x7c\x90\x9d\x94\xb4\xea\xb7\xeb\xcb\x09\x07\x76\x48\xaf\x06\x5c\x2d\x86\x61\x1e\xb5\x88\x45\x3e\xd7\xc2\x47\x80\xd7\x3c\x68\x9c\x87\x44\xaf\xd5\x33\xa8\x6d\x9e\xe9\xe3\x36\x57\x32\xcb\xd0\xc3\x51\xe4\x36\xf8\x98\xb7\x04\x32\x92\x09\x7e\x03\xe6\x08\x1a\x23\xac\x86\x5e\x19\xdc\x88\x58\x96\x9b\x99\x9d\x01\xfa\x65\xef\x20\x0c\x3f\x26\x9c\x81\x8e\x30\xb9\x36\x5e\xcc\x68\x3b\xcf\xe6\x9c\x20\x3b\x4e\x0a\xb6\xfe\x0b\xb8\x71\xe8\xec\xaa\xae\x82\xd3\xac\xd3\x5d\x5b\x50"}, -{{0x38,0xba,0x06,0x21,0x70,0x4d,0x21,0x55,0xfc,0x2f,0x78,0x55,0x51,0x96,0x57,0x5d,0xe0,0x6d,0x80,0x25,0x5c,0x35,0xe9,0xdc,0x96,0x5b,0x6f,0xe9,0x6a,0x4d,0x53,0x89,},{0x43,0x88,0xf7,0xf6,0x8a,0x9e,0xff,0xbc,0x36,0x6e,0x42,0xd9,0x07,0x01,0x56,0x04,0xda,0xce,0xd1,0x72,0x7c,0xd1,0xd8,0x9d,0x74,0xad,0xcc,0x78,0x9f,0xd7,0xe6,0xe1,},{0x42,0xbe,0xd6,0xa9,0x87,0x86,0xf6,0x64,0x71,0x5f,0x39,0xbb,0x64,0x3c,0x40,0x5a,0xe1,0x75,0x00,0x56,0x46,0x0e,0x70,0x04,0x69,0xc8,0x10,0x38,0x95,0x04,0xc5,0x1c,0xff,0xd9,0xe1,0xa9,0x4c,0x38,0xf6,0x92,0xfb,0x31,0x62,0x65,0x31,0x6d,0x8f,0x4d,0xc3,0xad,0x1c,0xdd,0x8a,0x6d,0x59,0x91,0xef,0x01,0x0c,0xd1,0x48,0x9d,0x7c,0x09,},"\xed\x4c\x26\x83\xd6\x44\xb0\x5b\x39\xb0\x48\xef\x1f\x8b\x70\x25\xf2\x80\xca\x7e\x8f\xf7\x2c\xb7\xed\xa9\x93\x29\xfb\x79\x54\xb7\x00\x40\x07\x05\x27\x5f\x20\xb8\x58\xcf\x7e\x34\x9a\x35\x10\x66\x5b\x63\x06\x09\xc5\xe2\xe6\x20\x69\x26\x3a\xb9\xc5\x5e\x41\x23\xa5\x64\xdc\xa6\x34\x8c\x8a\x01\x33\x20\x75\xe7\xa5\xbe\xc9\xc2\x0a\x03\x80\x79\x57\xfe\xfa\x91\x0e\x60\xc3\x5a\xe5\x79\x77\x8c\xe2\xce\x42\xe6\xa6\x9a\x1b\x64\x76\x81\xe4\x3e\xc4\xb6\x3b\xd5\xfb\xef\xab\xb3\x17\x12\xcb\x3d\x64\x19\xea\xd7\x8d\xd4\x1c\x8a\x92\xaa\xce\xb6\x3c\xbf\xa8\x9d\x2a\xf3\x96\x06\xde\x01\x0a\x39\x7e\x30\x20\x53\xa6\x15\xc1\x6e\x5e\x95\xad\x99\x35\xc0\x79\xa0\xb8\x10\x31\x25\x78\x94\x71\xa1\xe3\x57\x4f\x42\x9b\x29\xe4\xd2\x25\xc7\x72\x3f\xbb\x3c\xf8\x8c\xbd\x73\x82\x3d\x9f\x0b\x6c\x7d\x05\xd0\x0b\xde\xb0\xfb\x0a\xd3\xd7\x13\x20\x33\x18\x3e\x21\xf6\xc1\xe8\xd8\xe4\xc0\xa3\xe4\xf5\x2f\x50\x01\xda\x68\x71\x71\x34\x5c\x6d\xc8\xb4\x2c\x42\xa6\x0d\x1f\x1f\xfa\x8f\xe3\xe7\xbc\xec\xe5\x9a\x03\x58\x78\xf9\xd4\xd8\x11\x27\xe2\x24\x96\xa4\x9b\xfc\xf6\xbf\x8b\x46\xa8\x0b\xd5\x62\xe6\x52\x55\x07\x1f\x9d\x11\xa9\xeb\x04\x81\xf4\x62\x6d\x4d\x71\xff\xc3\x8a\xfe\x6e\x35\x8a\x4b\x28\x91\x79\xcb\xce\x97\x64\xd8\x6b\x57\xac\x0a\x0c\x82\x7e\x8f\xf0\x78\x81\x33\x06\xa1\xd5\xfa\xdd\x32\xb4\x6a\x1f\xbc\xd7\x89\xff\x87\x54\x06\x3e\xec\xfe\x45\x31\x3b\xeb\x66\x01\xc3\xa3\x01\x0e\x8e\xb9\x7c\x8e\xff\xbd\x14\x0f\x1e\x68\x83\x11\x09\x2d\x27\x3c\x4d\xef\xca\x47\xda\x6f\x1f\x08\x25\x74\x46\x76\xf9\xa2\x80\xb6\xc2\xa8\x14\xfa\x47\xfa\xbc\x19\x80\xd0\xb3\x7f\x08\x7a\x53\xca\x87\x78\xf3\x9f\xfb\x47\x4f\xf5\xf1\x17\x1b\x44\x2c\x76\xdd\x00\x8d\x92\x18\x2f\x64\x4a\x71\x4a\x0f\x01\x1e\x21\x5a\x78\xb9\x7a\xf3\x7b\x33\x52\x0e\xbf\x43\x37\x2a\x5a\xb0\xcf\x70\xdc\xc1\xdc\x2f\x99\xd9\xe4\x43\x66\x58\xf8\xe0\x7c\xdf\x0b\x9e\xa4\xdd\x62\x24\xc2\x09\xe7\x52\x1b\x98\x1e\xe3\x51\xc3\xc2\xdf\x3a\x50\x04\x05\x27\xfc\xd7\x28\x04\x17\x60\x46\x40\x5d\xb7\xf6\x73\x4e\x85\xc5\xd3\x90\xf5\x20\xb0\xc0\x8d\xcb\xfa\x98\xb8\x74\x24\x80\xd5\xe4\x6f\x9b\xe8\x93\xf6\xd6\x61\x43\x40\xf8\x16\x16\x11\xd5\x05\x3d\xf4\x1c\xe4"}, -{{0xae,0x33,0x1f,0xc2,0xa1,0x47,0x59,0xb7,0x3f,0x1c,0xd9,0x65,0xe4,0x85,0x14,0xe1,0x2b,0x29,0xf6,0x3b,0x06,0xcc,0xfc,0x0a,0xd4,0x9f,0x36,0x82,0x0e,0x57,0xec,0x72,},{0x08,0x80,0x3d,0x48,0x23,0x8e,0xda,0x3f,0x9c,0xeb,0xb6,0x28,0x53,0x01,0x21,0xde,0x00,0xf0,0xf0,0x46,0x8c,0x20,0x2d,0x88,0x52,0x8b,0x8b,0xce,0xc6,0x87,0xa9,0x03,},{0x75,0xf7,0x39,0x08,0x88,0x77,0xe0,0x6d,0xc5,0x6d,0xae,0xc8,0xf1,0xe4,0xd2,0x11,0xb7,0x54,0xe3,0xc3,0xed,0xbf,0xa7,0xed,0xa4,0x44,0xf1,0x8c,0x49,0xb6,0x9c,0x5a,0x14,0x2d,0xb4,0x5a,0x0a,0x76,0x50,0xe4,0x7d,0x10,0x55,0x0b,0xa6,0x81,0xff,0x45,0xdd,0x44,0x63,0xc4,0xac,0x48,0xbf,0x44,0xb7,0x30,0x34,0xbd,0x56,0x59,0x22,0x0e,},"\x57\x16\x00\x33\x90\xe4\xf5\x21\x65\x98\xa0\x3d\x7c\x43\x0d\xbf\x49\x5e\xe3\xa7\x55\x7b\x58\x06\x32\xba\x59\xf1\x51\x98\xb6\x18\x0a\x42\x46\x9c\x23\x7d\xb5\xbc\x81\xf2\x9c\xfa\xab\x0a\xff\x3c\x99\x66\x30\x9a\xb0\x69\x58\xc9\xd7\x12\x6a\xdd\x78\xe3\xb3\x24\x59\xff\x8a\x0e\x0b\xde\xf8\x74\xb5\x8e\x60\x83\x66\x8f\x38\xad\x7d\x63\xaa\xe1\xf1\x2e\x26\xa6\x13\x34\x8f\x9f\x03\xea\x5d\x20\x5f\x04\x5d\x78\xcc\x89\x02\xd4\x7f\x81\xe8\xb5\x22\x93\xe7\x0e\x86\xc9\x80\x3d\x4d\xac\xea\x86\xc3\xb6\x74\x58\xae\x35\x79\xbc\x11\x11\x3b\x54\x90\xbc\xf3\xe1\xcd\x4e\x79\x79\xc2\x64\xd8\x35\x16\x1f\xd5\x5e\xfe\x95\x3b\x4c\x26\x39\x5d\xd9\x2c\xa4\x93\x09\x20\xe9\x04\xfa\xdc\x08\x89\xbb\x78\x22\xb1\xdf\xc4\x45\x26\x04\x84\x0d\xf0\x24\xdb\x08\x21\xd2\xd5\xe9\x67\x85\xa5\xc3\x7d\xbf\xd2\xc3\x75\x98\x32\x83\xe9\xb5\xb4\x3a\x32\x07\xa6\xa9\xb8\x33\x94\x83\x29\xd5\xde\x41\xe4\x50\x08\xbc\xba\xd4\x93\xde\x57\x54\xdd\x83\xde\xcc\x44\x0e\x51\x66\xed\xaa\xe0\x20\x8f\x00\x0c\x5f\x6d\x9c\x37\x21\x53\x20\x9e\x5b\x75\x78\x11\x6f\x89\xcf\x2f\x8b\x10\x04\xd1\x30\x7e\xa7\x9e\xd3\x74\x80\xf3\x19\x4a\x7e\x17\x98\x3a\x23\x04\x65\xcc\xc3\x0f\xcc\x1a\x62\xd2\x80\xfb\xba\xcc\xf0\x06\xdc\x4d\xee\x0e\xa7\x96\xb8\x1a\xcc\xc6\x1a\x06\x3e\x2c\x08\x3d\xae\xc0\x39\xbd\x9a\x64\xa7\x70\x24\xaf\x82\xec\x1b\x08\x98\xa3\x15\x43\x29\xfd\xf6\x16\x73\xc3\x6e\x4c\xc8\x1f\x7a\x41\x26\xe5\x62\x90\xe4\xb4\x56\x81\x9b\xde\xbf\x48\xcb\x5a\x40\x95\x5b\xab\x29\x7c\x2b\xbc\xb0\x18\xad\xbf\x24\x82\x86\x60\xa5\xd1\x2a\x06\x13\xbf\x3c\xcb\x5e\xeb\x9a\x17\xfb\x0a\x05\x47\xdb\x8d\xa2\x4d\x2e\xfb\x87\xba\x1b\x84\x31\x42\xa7\x5e\x4c\xa0\xb0\xa3\x33\xe4\xa1\x4f\xab\x35\xa6\x26\x69\x32\x9c\xa8\x75\x3f\x01\x6a\xc7\x0c\xd9\x97\xe8\xbc\x19\xee\x44\x8a\xea\xf0\xf4\xbf\x3c\xe5\x23\x05\x50\x57\x8a\xb6\x4c\x19\x01\x94\x46\xce\x2d\x9c\x01\xa0\x3d\x88\x9a\x99\x09\x86\x0a\xef\x76\xf0\x67\xc5\x0b\x61\xc3\xd0\xf1\x2c\xc8\x68\x6f\x5c\x31\xbf\x03\x2a\x84\x10\x15\xcf\xef\xf1\xcf\xda\xe9\x4f\x6b\x21\xda\xe9\x41\xb3\x35\xdc\x82\x1f\x32\x84\xce\x31\x50\x8f\x5d\xb5\xc4\x48\xff\xaa\x37\x73\xe9\xbe\x1a\x4c\x85\xa1\xc5\x8b\x00\x9f\xa3"}, -{{0x82,0x43,0x5f,0x39,0x79,0x01,0x06,0xb3,0xaf,0x72,0xf9,0x1f,0x14,0xc9,0x28,0xd2,0x46,0x5f,0x98,0xcd,0xd1,0x00,0x84,0xc4,0xa4,0x4d,0x19,0xaf,0x71,0xa1,0x92,0x7c,},{0xc5,0x2a,0x92,0x64,0x6f,0x5a,0xdb,0x21,0xc6,0xdd,0xe0,0xde,0x58,0x78,0x68,0x37,0xf8,0xa3,0x41,0x4c,0x09,0xae,0xdf,0xc2,0x7c,0x81,0x22,0x18,0xa7,0xe7,0x23,0x9e,},{0x1d,0xaa,0x44,0xef,0x06,0xd4,0xc1,0x0d,0xdb,0x48,0x67,0x84,0x23,0xc5,0xf1,0x03,0xa1,0xb5,0x68,0xd4,0x2b,0x20,0xcc,0x64,0xaf,0x11,0x0f,0xce,0x9d,0x76,0x79,0xa2,0xde,0xe4,0x12,0xb4,0x98,0x05,0x85,0xc2,0x6c,0x32,0x0d,0xba,0xa6,0x01,0xc4,0x72,0xde,0xfc,0x3c,0x85,0x41,0x5d,0xae,0xcd,0xd6,0xd2,0xd9,0xea,0xca,0xc8,0x5e,0x07,},"\xf3\xd6\xc4\x6a\xc5\x24\x8d\x53\x86\xb6\xb6\x84\x62\x59\x7d\x64\x70\x39\xf5\x44\xbb\x01\xac\x2d\x10\x67\xda\xaa\xa3\x97\xd2\xdb\xaf\x12\x5a\x1c\xf8\xfd\xf2\x80\xa6\xaf\xec\x32\x4d\x53\x11\xf5\x43\x68\x8a\x15\x6c\x84\x98\x19\xbb\x04\x6b\x91\x1c\x42\xea\x3c\xa0\x1b\x99\x80\x8c\x4d\x1f\x3b\x8b\x15\xda\x3e\xfe\x2f\x32\x52\x3e\xc3\xb0\x9c\x84\xb4\x8c\xff\xd1\x3c\x17\xc9\xe2\x6c\x91\x2d\x9c\x3e\x93\x46\xdf\xae\x3f\xd0\xc5\x6c\x88\x58\x78\x07\x82\xf6\x1a\x4c\x4d\xbf\xff\x1e\x9c\xb4\xb3\x62\xcd\x80\x01\xf9\xcd\xfe\xb1\xa7\x20\x82\xdc\xe9\xc9\xad\xe5\x2e\xff\xc9\x74\x46\x88\xac\x0b\x86\xc8\x82\x66\xb5\x3d\x89\x5c\x17\xea\xd9\xe8\x9e\xd8\xd2\x4d\x40\x64\x2f\x3a\xd3\xb9\xbf\x9b\xbc\x4d\xda\x79\x66\xef\x83\x28\x28\x9f\xb3\x1e\x17\xc8\x1f\xd0\x28\xef\x1b\xd9\xa1\xd4\xc7\x92\xe8\x6e\xc2\xdb\xdc\xe3\xf9\x37\xee\xcc\x3e\xeb\x51\x88\xd3\x25\x94\x19\x19\xbb\xf7\x5b\x43\x88\xe2\x39\x95\x07\xa3\xd7\xfb\x38\x75\x02\xa9\x5f\x42\x1c\x85\x82\x6c\x1c\x91\x76\xc9\x23\xe3\x16\x31\x0a\x4b\xa4\x5c\x8a\x5e\xf7\x55\x7c\xf8\x7b\x77\x02\x0b\x24\xf5\xba\x2b\xfd\x12\x28\x10\x95\x66\x30\x7f\xea\x65\xec\x01\x50\x19\x69\x12\x17\xbc\xe6\x9a\xee\x16\xf7\x62\x49\xc5\x8b\xb3\xe5\x21\x71\xcf\xef\xd5\x25\x4e\x5e\x0f\x39\x71\x69\x18\x6d\xc7\xcd\x9c\x1a\x85\xc8\x10\x34\xe0\x37\x18\x3d\x6e\xa2\x2a\xee\x8b\xb7\x47\x20\xd3\x4a\xc7\xa5\xaf\x1e\x92\xfb\x81\x85\xac\xe0\x1d\x9b\xf0\xf0\xf9\x00\x61\x01\xfc\xfa\xc8\xbb\xad\x17\x1b\x43\x70\x36\xef\x16\xcd\xae\x18\x81\xfc\x32\x55\xca\x35\x9b\xba\x1e\x94\xf7\x9f\x64\x55\x55\x95\x0c\x47\x83\xba\xb0\xa9\x44\xf7\xde\x8d\xf6\x92\x58\xb6\xaf\xe2\xb5\x93\x22\x17\x19\x5d\xa2\x45\xfe\xe1\x2a\xc3\x43\x82\x4a\x0b\x64\x03\xdf\xe4\x62\xd4\x3d\x28\x8d\xb3\x1f\x99\x09\x7e\xc3\xed\xc6\xe7\x65\x47\xa3\x74\x2f\x03\xc7\x77\xef\xb1\x58\xf5\x8d\x40\x53\xfa\x6c\xc8\xd6\x8b\x19\x6a\xf4\xf9\xde\x51\x6f\xd9\xfb\x7a\x6d\x5d\x9e\xe4\xa8\x9f\x9b\x9b\xce\x1e\x4d\xee\x35\x7a\x1e\x52\xc0\x54\x4c\xfb\x35\xb7\x09\x2d\x1a\xa5\xa6\xf7\xf4\xc7\x60\x26\x10\xe9\xc0\x0e\xf5\xb8\x76\x1b\xc7\x22\x79\xba\x22\x8a\x18\xb8\x40\x0b\xd7\x6d\x5b\x2b\xfd\x7c\x3c\x04\xaa\xc4\x43\x6d\xae\x2e\x98"}, -{{0x1b,0xea,0x77,0x26,0xd9,0x12,0xc5,0x5e,0xc7,0x8b,0x0c,0x16,0x1a,0x1a,0xd3,0xc9,0xdd,0x7b,0xc3,0x29,0xf8,0x5d,0x26,0xf6,0x2b,0x92,0xe3,0x1d,0x16,0xd8,0x3b,0x48,},{0xc9,0xdd,0xb4,0x21,0x06,0xcc,0xef,0x4e,0x0e,0xf4,0x79,0x45,0x51,0xd2,0x1d,0xf9,0x4a,0x63,0x06,0x87,0x2f,0x23,0x16,0x63,0xe4,0x7e,0x24,0x1f,0x77,0xcc,0x3e,0x82,},{0xf9,0xb0,0x45,0x17,0xbd,0x4f,0xd8,0xef,0x90,0xf2,0x14,0x0f,0xc9,0x5d,0xc1,0x66,0x20,0xd1,0x60,0x2a,0xb3,0x6c,0x9b,0x16,0x5f,0xff,0x3a,0xba,0x97,0x8d,0x59,0x76,0x71,0x10,0xbb,0x4e,0x07,0xa4,0x8f,0x45,0x12,0x14,0x47,0xac,0x0c,0x1a,0xba,0xc5,0x85,0xd3,0x91,0xd4,0x04,0x20,0x41,0x89,0x86,0x28,0xa2,0xd2,0xdc,0xc2,0x51,0x0d,},"\xb1\x12\x83\xb1\xf0\xce\x54\x9e\x58\x04\x73\x0a\xc3\x20\x7a\xc0\x03\x32\xd2\xaa\xcf\x9c\x31\x0d\x38\x32\xd8\x79\xf9\x63\x4b\xd8\xa5\x8a\xdf\x19\x9e\x4b\x86\x3b\xb1\x74\x81\xd2\x8a\xcb\x2d\xa0\xe1\x55\x7b\x83\x36\xa4\x00\xf6\x29\x56\x25\x03\x1d\x09\xe4\xdf\x4d\x31\x9b\xbc\x1e\x8f\x6e\x92\x32\xd2\x30\x53\xbb\x3f\xfa\xc4\xfe\x2c\x70\xce\x30\x77\xfc\x00\x60\xa5\xcb\x46\x92\xa1\xcf\x0b\x3e\x62\xfe\x45\x48\x02\xae\x10\xb8\x3d\xed\x61\xb6\xbf\x45\x4c\xa7\x5e\x4c\xda\xd5\x53\x2f\x20\xb7\x06\x54\xf1\x2b\xa9\x06\xf0\x03\xa8\xb9\xe9\x86\xf1\x5a\x39\x41\x9d\xeb\x2e\xa1\xea\xd7\x59\x82\x90\xee\xeb\xf9\x25\x2b\x0c\x27\x60\x5a\x7a\x73\xa6\xab\xeb\xb4\x22\x71\xd7\x1a\x3c\x19\x7a\x46\xbc\xc8\xdb\x11\xd9\x24\x28\x42\xf3\x78\x36\x4a\x37\xee\xca\xa3\x4e\x98\x21\x35\xbe\x34\x18\x2c\x69\xca\x8e\x6e\x3c\x8c\x90\xe1\xb4\xb2\xb4\x75\x81\x5a\x17\x83\x77\xae\x01\x65\xa7\x64\xc8\xba\x28\x89\xb5\xab\x29\x09\x49\xd8\x48\x7a\x88\xe0\xd3\xd2\xbc\x7e\x25\x20\x17\x6a\xa6\xff\x9f\xf0\xc4\x09\xff\x80\x51\x5f\x4f\x0b\x83\xc5\xe8\x2c\x23\xfd\x33\x26\xcd\xd6\xb7\x62\x52\xe7\xfd\xdc\xd6\xe4\x77\x09\x78\xcd\x50\x3e\xd2\xd6\xb4\x80\x10\x11\x67\xd3\xf1\x91\xfe\xd8\xd6\xd7\x4d\x74\xa2\x00\x7d\xb1\x09\x2e\x46\xa2\x3d\xde\xcd\xdc\xdb\x98\x46\x64\x04\x7b\x8d\xd7\xcc\x8a\x57\x6e\x1a\x80\x6f\x52\xcb\x02\x7a\x94\x80\xa9\x5c\xc4\x4b\x1e\x6f\x2e\x28\x6e\x9b\x7a\x6b\xf7\xb3\x96\xfa\x54\x96\xb7\xa5\xb1\xc0\x3d\x9c\x5c\x27\xda\x1a\x42\x99\x0d\x10\xb1\x2f\xb8\x64\x0e\x15\x96\xf2\x6b\x36\x6d\x27\x0b\xa6\x4f\x99\xaf\xff\xe3\xfe\xce\x05\xa9\xb0\x25\x4b\x20\x8c\x79\x97\xcd\xb5\x12\xfc\x77\x52\x79\x54\xa1\xcb\x50\xfd\xab\x1c\xc9\xa4\x51\x62\x74\x1f\xd6\xf9\xd3\xfd\x5f\x2e\x38\x28\x53\xd7\x33\x5d\xba\x1e\x6b\x29\x59\xdd\x86\xe1\x25\xe6\x7b\x53\xdc\x8e\x45\x3c\x81\x0b\xc0\x1b\xf2\x0b\xce\x7b\x61\x8d\xd5\xd1\xed\x78\x41\x06\xee\x06\xa3\xec\xaf\x6b\x3b\xee\x0b\x56\x83\x3b\x0b\x81\x31\x39\xc5\xa6\x96\x00\x0a\x44\x9c\x97\x90\x6a\x2f\xbd\xdc\x2d\x9d\xe9\x40\x6e\xa2\x82\xac\x4e\xe5\xef\x8b\xf3\x85\x4c\x74\xa6\xb7\x17\x3d\xd2\xf7\x9c\x7a\x12\x6f\x3c\x7b\x04\x33\xfd\x4e\xa2\x6e\x87\x7a\x14\x83\x1d\xd4\x15\xa1\x9d"}, -{{0xd0,0x1a,0x0e,0xad,0x9d,0x69,0x48,0x33,0x28,0x3b,0x9c,0xd7,0x29,0x9a,0x7b,0xd7,0x5f,0xa9,0x0b,0x1d,0x2d,0x78,0x84,0xe4,0x55,0x7b,0x33,0xc9,0x98,0x77,0x2a,0x68,},{0xa0,0xf7,0x57,0x47,0x9b,0xa6,0x27,0xef,0xef,0x95,0xd6,0xec,0x7a,0x93,0x1d,0xfa,0xc4,0x37,0x3d,0xf3,0x3d,0xaa,0xf4,0xdd,0xc4,0xec,0x68,0x94,0xc8,0x26,0x1e,0xd7,},{0x9a,0x0f,0xf7,0xf3,0x51,0x74,0xec,0x3f,0x66,0xd2,0x2a,0x6f,0x06,0xdf,0x60,0xe0,0x9c,0x8f,0x62,0x3a,0x5a,0xca,0x81,0x0e,0x23,0xa8,0x8d,0x0e,0x6a,0x31,0xcb,0x6f,0x1c,0xe1,0xc1,0xf9,0xdc,0xcc,0x9e,0x14,0x84,0xb6,0x8d,0xd0,0x04,0xac,0x53,0x59,0x7e,0x29,0xad,0x6a,0xb7,0x2e,0x8c,0xe2,0xb7,0x5a,0xd5,0xb8,0x0e,0xb8,0x48,0x03,},"\x76\x27\x53\x4e\x9a\x83\xd1\xe4\x06\xab\x94\x8d\x30\xd1\xda\x9c\x6a\x5d\xb0\x8e\x0f\xeb\x7f\xc5\xba\x5c\xbf\x76\x84\x9e\xe8\xad\xd4\x84\x7e\xf5\xca\x5a\x0d\xae\x41\x1a\xca\x09\x74\x51\xcb\x4c\x2b\x49\x8c\x94\x70\x97\x40\x70\x07\x64\x0d\xc1\x9e\xd9\x38\xe3\xb9\x1b\xf5\x1c\x95\x81\x16\x8d\xf8\x60\xbd\x94\x75\x16\x68\xda\xbd\x72\x1d\xc7\x39\x98\x40\x0b\xe2\x0c\x9a\x56\x3d\x50\x51\xef\x70\xe3\x54\x6f\xee\x67\x33\x12\xb5\x2a\x27\x40\x41\x05\x7e\x70\x84\x8e\xb7\xc5\xa2\x16\x44\xc9\x7e\x44\x8a\xbd\x76\x40\x20\x7d\x7c\xda\xfc\xf4\x5d\xa6\xdf\x34\x94\xd3\x58\x5b\x0e\x18\xac\x5a\xc9\x08\x1c\xb7\xa4\x07\xa3\x9a\x87\x77\x05\xcb\xaf\x79\xa0\x1b\x91\x5f\x73\x6e\xb0\x25\xc5\x8b\x4b\x5d\x80\x7f\xb7\xb7\x56\x6c\x59\x69\x78\x7c\x1d\x6c\xa4\xeb\xa9\x7d\x50\x9e\xf7\xfb\x35\x50\xd2\x1d\x37\x7e\xce\xff\xcf\x0e\xb6\x68\x18\x95\xad\xbd\x24\x6e\xe7\xbf\x3c\x93\x5a\x00\x64\x78\xb8\x32\xec\xe4\x6d\xe6\x11\x8b\x17\xe4\x66\xa2\x7f\xc2\xa4\x4a\x89\x6b\xaa\xe2\x72\xf9\xec\xf0\x18\xc6\x5c\xb5\x0c\xfb\xfc\x8d\x26\x09\x94\xa1\x8a\x83\x2d\x97\x19\x28\xc4\x49\x67\x57\x24\x58\x51\x31\xc8\x71\x53\x3c\x98\x97\xd8\xf8\x0f\x9c\x04\x16\xb7\x18\x78\x6b\x10\xfe\xa8\xeb\x5b\xd8\x13\xa2\x69\xa1\xb6\x77\xb7\xa2\x50\x7a\x44\xb7\x13\xd7\x05\x08\x65\x30\x99\x5e\x59\x33\x5d\xdc\x28\x55\xe8\x47\xe4\xf4\xdb\x06\xc9\x1f\x1d\x54\x02\x3d\x8a\x10\xf6\x9f\x9e\x61\xbd\xce\x4b\x68\x6f\xb6\x17\xbd\x50\x30\xe7\x55\xca\xdb\x1f\x64\x4e\x1d\xdd\x91\x61\x9b\x96\xec\xd6\x05\xb0\x01\x98\xb9\xa6\xed\xdb\x5a\x84\xeb\xd3\x69\x2b\x66\x59\x79\x76\x66\x37\xc6\x77\x37\x8c\x1c\x77\x04\x1f\xd4\xa6\xb3\x55\x5c\x1d\xc8\xa8\x3f\xe9\x01\x3b\xb6\x10\x6c\xc1\x8a\x2b\x03\x7c\x93\x77\xb7\xa1\xa5\xa5\xd0\xdc\xc5\x49\x18\xea\xad\x7e\x32\xc8\x80\x76\x7b\x26\xfd\x2e\xa2\xd6\x8b\x04\x05\xf5\xe0\x74\xf5\x5a\x19\xd8\xa3\x9f\xfb\xb7\xdc\x32\xfa\xee\x6a\x7f\x95\x32\xae\xc8\xa0\x77\x6c\x3f\xf8\x3a\xe3\xa4\x62\x77\x38\x49\x6a\x37\x1e\xb9\xe0\x90\xb7\x4e\x0e\xdd\xec\xfc\xd4\x1b\xed\x0c\x0c\xe5\x81\x27\x52\x43\x47\x2d\x26\xda\x8c\x99\x8e\x4b\x6d\x6b\x44\xfc\x88\xba\x2a\xb5\x46\x42\x22\x54\x17\x12\x02\x94\x41\x78\x05\x74\x2b\xdb\x33\xb7\xb1\x22"}, -{{0xdf,0x64,0x89,0x40,0xb5,0x78,0xbc,0x31,0xd2,0xa6,0x52,0x96,0x5f,0x30,0x39,0x1c,0xaf,0x06,0xd5,0xf2,0x51,0x59,0x9a,0x73,0x7c,0xe1,0x0b,0xe5,0x5f,0x4a,0x9d,0x0d,},{0x27,0xde,0x92,0x04,0x19,0xc1,0x86,0xb0,0x1b,0xe5,0x42,0x79,0xfb,0x8f,0x9b,0xe4,0xbb,0x4b,0x2c,0xad,0x75,0xca,0x7e,0x8f,0x79,0x2b,0xfa,0x7b,0xb9,0x7c,0x7f,0x41,},{0x62,0xbc,0x99,0x1c,0x45,0xba,0x9b,0x26,0xbf,0x44,0x01,0x16,0x26,0x41,0x62,0xc3,0x4c,0x88,0x59,0x78,0x85,0xe9,0x60,0x50,0x83,0xc6,0x04,0xb5,0xf5,0xd8,0xfa,0x6f,0x66,0x2b,0xa2,0x14,0xf7,0x6e,0x6c,0xf8,0x4e,0x5e,0xc0,0x4d,0xf1,0xbe,0xef,0xc5,0xf2,0x5d,0x3a,0x3b,0x72,0xf9,0x8b,0x50,0x69,0x83,0x19,0x16,0xa6,0x32,0x96,0x01,},"\x1a\xe5\x20\xbe\xeb\x4a\xd0\x72\x2b\x43\x06\x7f\xa7\xcd\x28\x74\xab\xcf\x34\xdd\x92\x37\xb4\x47\x8e\xae\x97\x72\xae\xa2\x97\xa6\x7f\xb7\x9b\x33\x07\x02\x04\xba\xee\x44\x0b\x9c\x87\xe2\xfb\xcb\xeb\x76\x80\x1d\xdd\xea\x5e\x45\x30\xd8\x9e\x11\x58\x31\x79\x93\x9a\x00\xa3\x2f\x81\x13\x32\xc5\x22\x91\xcc\x7a\xc9\x1e\x5a\x97\x0c\xd5\xaa\x70\x8b\x1d\xa2\x6b\xe9\xfe\x43\x2a\x9b\xbd\xa1\x31\x9e\x31\xe4\xbc\xc9\xf1\x66\x6a\x05\xb5\xc0\x5b\x87\x6b\xfd\x1f\x76\x66\x87\xcc\xea\x4e\x44\x82\xe9\x24\x32\x9a\xfa\xce\x5e\xe5\x2e\x98\x79\xfd\x69\xb7\x6e\x0f\x7e\x45\x2e\xc4\x71\x3b\xff\x21\x6d\x00\xc8\x25\x99\xd2\x7c\xa4\x81\xf7\x3a\xae\x13\x6f\x08\x75\xc8\x8a\x66\xb1\xb6\xf3\x4c\x50\x52\x3a\xb6\x02\xe9\xd4\xeb\xb7\xee\xb9\xe0\x43\xa6\x5e\x41\x89\x9d\x79\x75\x2a\x27\x9d\x2e\xd4\x69\x93\x92\x6f\x36\x21\xe7\xc3\x2c\x9a\x9b\x3b\x59\xd8\xdd\x57\xbe\xca\x39\x28\x54\x34\xde\x99\x1c\xbd\x2d\xfc\xbc\x5c\xa6\x2a\x77\x79\xf4\x75\xd0\xce\xf2\xf3\xe5\x62\xf2\x9a\xcd\x47\x4f\x3c\x99\xec\x5b\xd8\xde\x01\x10\x1b\xed\x2e\x0c\x9b\x60\xe2\xd7\x0f\xd4\x32\xc8\x92\xfc\x66\xf8\xd4\x61\x9a\x91\x1b\x56\x25\x16\x3e\x9a\x42\xbf\x9e\xa3\x85\x86\xd8\xe7\x64\x00\x15\x64\xd3\x35\x41\x12\x25\xfc\xb0\xa0\x6d\xc2\xa8\x2d\xa0\x77\x9a\x3c\x44\x4e\xb7\x86\x42\x01\xb4\x3e\xbb\x72\xb9\x21\xf3\x4d\x3c\x13\x08\x9d\xf2\xf4\xfa\xc3\x66\xff\x1e\x3c\x0b\x96\xf9\x3d\x2b\x4d\x72\x6a\x5c\xe4\xd6\x91\x6d\x82\xc7\x8b\xe3\x54\xa1\x23\x0c\x2c\xf0\x41\x8c\x78\xa1\x91\x3e\x45\x4f\x64\x8c\xc9\x2c\x8d\xd0\xe1\x84\x64\x5f\xe3\x78\x1d\x26\x3c\xff\x69\xf5\xc6\x0b\x1e\xbb\x52\x00\x5a\x8b\x78\xa5\x15\xc7\xe8\x88\x6f\xfe\x05\x4d\xab\x42\x8e\x2e\x22\x1d\x9d\x76\xaf\xf4\x26\x54\x16\x8d\x83\x3b\x88\x17\x82\x93\xe1\xfe\xdd\x15\xd4\x6c\xd6\x09\x48\x31\x29\xc4\xd2\xd8\x44\x32\xa9\x9d\x31\xff\xe9\xbd\xb5\x66\xf8\xc7\x5c\xe6\x5e\x18\x28\x8e\x4d\xf8\xc1\x67\x31\xa0\xf3\xfd\xde\x1c\xca\x6d\x8e\xde\x04\x35\xff\x74\x36\xca\x17\xd0\xae\xb8\x8e\x98\xe8\x06\x5c\xbc\xbf\xd0\xff\x83\x04\x3a\x35\x7c\xd1\xb0\x82\xd1\x70\x3d\x46\x18\x81\x87\x2c\xdf\x74\x1e\x4f\x99\xbd\x14\x67\x45\xba\x70\x39\x74\xbe\x40\xf5\x79\xbf\x5c\x4d\xba\x5b\xdb\x8c\x94\x1b\xce"}, -{{0xc8,0xac,0x23,0x45,0x58,0xaa,0x69,0x81,0x6b,0x36,0x8b,0x77,0xb7,0xcc,0xcb,0x5c,0x8d,0x2a,0x33,0xec,0x53,0xae,0xef,0x2c,0xe2,0x28,0x71,0x43,0xbd,0x98,0xc1,0x75,},{0x53,0x64,0xba,0xf1,0xfd,0xb2,0xc6,0x38,0x40,0xb3,0x0d,0x40,0x31,0xcf,0x83,0xa2,0xe1,0x8e,0x62,0x07,0x93,0xba,0xe5,0x9d,0x10,0x35,0xc0,0xed,0xe5,0x5e,0x52,0x8b,},{0x32,0x25,0x03,0x61,0xdf,0x6e,0xd2,0x83,0x48,0x5f,0x95,0xf3,0xd3,0x57,0xa4,0xf1,0xc3,0x3a,0x8c,0xf9,0x16,0x58,0x32,0x7c,0xd4,0x53,0xd4,0x9c,0x95,0x36,0x65,0x51,0x08,0x70,0xaa,0x45,0x4c,0xfa,0x3b,0x83,0x24,0x52,0x20,0xa8,0x27,0xd0,0xec,0x74,0x77,0xf9,0xec,0xeb,0x79,0xc4,0xa2,0x9f,0x30,0x1f,0x95,0x3c,0xc8,0xca,0xac,0x07,},"\xce\x48\x8d\x26\x97\x5c\x1c\x93\x28\xb4\x7f\xa9\x2e\x19\x56\x13\x30\x04\x1b\x23\xa0\xe5\x7a\x4b\x8b\xca\x89\xeb\x5f\x61\x5e\x73\xdd\x7f\xae\x69\xc2\x38\x0e\x32\x12\xf9\xb7\x33\x41\xc3\x56\xdb\x75\xa6\x25\x6d\x7a\x20\xa9\x7f\x75\x9d\x4c\xba\x71\x97\x17\x8e\xa7\x24\xdd\x93\x29\x49\x36\x0e\x96\xc5\x0a\x4b\x3b\xa5\x5a\x95\x33\x72\xc3\x97\xb0\x96\x9c\x2b\x14\xd3\x60\x9e\x0a\x85\x2d\x48\x4d\xf7\x0e\xaa\xb1\x12\x49\xeb\xeb\x32\x37\x92\x1f\x0a\x39\xa5\x5d\x7d\xcc\xfe\xf2\x05\xd9\x4e\xc8\x0d\x9e\x1f\xd6\xa2\xc1\xef\xd2\x98\x44\x10\x1d\xfe\x2c\x5f\x66\x8a\xdb\x79\x75\x91\x5d\xed\xd0\x86\x50\x0c\xee\x2c\x1e\x23\x3e\x8e\x48\x85\x5c\xc1\xa6\xf2\x87\xd6\x3d\xce\x10\xad\xdd\x13\xca\xc7\xb7\xa1\x87\xef\xe4\x7e\x12\xd1\xc3\x5b\xb3\x97\x40\x52\xb2\x3a\x73\x66\x8d\x3e\x4c\x87\xdb\x48\x41\xaf\x84\x6e\x80\x86\x72\xc4\x3d\x0a\x15\x22\xe2\x96\x5f\x08\x39\x51\xb2\xb2\xb0\xc4\x09\x54\x8e\xe6\x18\x2f\x0c\x98\x50\x51\x4c\x9e\x6c\x10\x2f\x54\xba\x41\x24\xc9\x2a\x90\x27\x4f\x40\x58\x91\xe6\x62\xf5\xeb\xb3\x77\x1b\x85\x78\x31\x56\xe9\xe5\x83\x67\x34\xd0\x9d\x1b\xaf\x5b\x21\x34\xc9\x31\x62\xee\xc4\xbe\x03\xbd\x12\xf6\x03\xcd\x27\xbe\x8b\x76\xac\xcc\x6e\x8b\x8b\xac\x02\x0c\xba\x34\x79\x65\x1c\x9f\xfa\x53\xce\x4e\xb7\x7a\x77\x31\x3b\xc1\x26\x5d\xda\xb8\x03\xef\x7a\x65\x63\xba\x6f\x79\x9d\x1e\xf3\x0e\xf5\xa0\xb4\x12\x96\x5f\xda\xc0\xb9\xda\xb8\x42\xc7\x8e\xe2\xcc\x62\x8e\x3d\x7d\x40\x61\xe3\x4e\xde\x37\x97\xe1\x54\xb0\x6e\x8c\x66\xce\xbd\xf2\xde\xd0\xf8\x1b\x60\xf9\xf5\xcd\xda\x67\x5a\x43\x52\x77\xba\x15\x24\x55\x7e\x67\xf5\xce\xfa\xfc\xe9\x29\x29\x1d\xce\x89\xec\xb0\x8a\x17\xb6\x7a\x60\xc5\x82\xb4\x87\xbf\x2f\x61\x69\x62\x66\x15\xf3\xc2\xfe\x3b\x67\x38\x8b\x71\x3d\x35\xb9\x06\x66\x69\x96\x0d\xe4\xdb\x41\x3c\xd8\x52\x8e\xe5\x6e\xd1\x73\xe9\x76\xa3\xc9\x74\xac\x63\x3a\x71\x34\xcc\xe3\x83\x19\x73\x5f\x85\x7b\x7d\x71\xba\x07\xf4\x77\xef\x85\x84\x8a\xa8\xf3\x9e\x11\x81\x18\x77\x9e\xd8\x7b\x4f\x42\xaa\x35\x8a\x89\xf7\xec\x84\x4a\x45\x1e\x7e\x8f\xc0\xaf\x41\x8b\x85\xbc\x9b\xf2\xf2\x6d\x1e\xa1\x37\xd3\x35\xec\x7e\xe7\x57\xb7\x0a\xe2\xfd\xd9\xcc\x13\x49\x32\xf0\xe5\x42\x5b\xf3\x7f\xb9\x15\xe7\x9e"}, -{{0x2c,0x47,0xf2,0xb8,0xb9,0xd2,0xce,0xe9,0xe6,0xf6,0x54,0xbc,0x24,0x65,0x8f,0x9e,0xaf,0x43,0x9c,0x23,0xbe,0xaa,0x0a,0x79,0xbf,0x35,0xcc,0x8c,0xd2,0xde,0xba,0xf4,},{0x44,0x4a,0xf2,0xf3,0x4f,0xd3,0x2e,0x5a,0x19,0xf6,0x1f,0x87,0xd0,0x3e,0x10,0x76,0x27,0xa3,0xee,0xb8,0xbd,0x94,0xd2,0xfa,0xea,0xa3,0x48,0xb0,0x5d,0xea,0x19,0x80,},{0x85,0x54,0xb0,0x1d,0x09,0xed,0x86,0xe6,0x13,0x95,0xb9,0x1a,0x2b,0x1e,0xe1,0x87,0x15,0xc4,0x2f,0x9c,0x7e,0x7f,0x07,0x00,0xd7,0x9f,0xf9,0xfb,0x57,0x81,0x29,0x3d,0x61,0xc5,0x58,0xdd,0x5b,0x43,0x1c,0x93,0x71,0x8d,0xcc,0x0f,0x98,0xfb,0x65,0x2b,0x59,0x6f,0x18,0xc3,0x0f,0x82,0x21,0x5e,0x8e,0x63,0xe4,0xf6,0x56,0x8c,0x88,0x00,},"\x04\x4c\x8f\xaa\x8c\x8a\xaf\x9f\x2b\x81\x86\xa6\xb9\xb3\x38\x47\xec\x7b\x45\x24\x23\xb2\x2a\x91\x74\x3d\x2e\x59\x7e\xcc\x1e\x1e\x22\xae\x60\x05\x3e\x9e\xe6\x23\x3b\x04\x4e\x77\x59\x20\xe4\xe3\xd6\x67\x19\x90\x13\x25\xcf\xdd\x39\xbb\x53\x2f\x8a\xa4\x69\xaa\xb4\x2e\x96\x08\xc2\x12\x60\xc0\x4c\x27\x41\x3a\x7a\x94\xe4\x66\xf6\x3c\x49\x52\xe9\x0e\xf9\x0c\x12\x81\x4b\x34\x51\xb1\xca\xd7\xda\x91\x47\xf8\x40\x92\x20\xf6\x49\x8c\xc0\xa6\x7f\xef\x4b\xc0\x4f\xc0\x6e\x1d\x89\x8a\x55\x15\x59\x1e\x8b\xe0\xc4\x3d\x75\xa6\xfe\x42\x5b\x7c\xbe\xfb\x1b\x91\xb1\xbd\x78\xb5\xbe\xc7\x82\x90\x56\x98\x2e\xfd\xc5\xbe\x24\xaf\x66\x78\x00\x6a\xdc\x6f\x04\x46\x20\x2e\x7e\xc3\xa2\xd6\x97\x9c\xb0\xdf\x7e\x25\xd7\x42\x33\x91\x4d\x9c\x58\xb8\x1c\xf5\x5b\xe0\x69\x67\xd3\xa5\x95\xc1\xb9\x67\x28\x69\x99\x4c\xfb\xa6\x71\x62\x83\x3a\x21\x43\xaa\x91\xcc\x93\xac\xda\xfa\x5b\x45\x20\x8d\xf3\xe8\x8c\xcc\x01\xa2\xa4\xd2\x20\xe3\x60\x09\x8d\x91\x54\xd2\x25\xa7\xca\x5f\x2f\x1e\x52\xb1\x00\x3d\x10\x66\x50\xa7\x7b\x28\x3b\x95\xe4\xba\xf1\xe7\x33\x6f\xa9\xa7\x47\xa2\xb3\x82\x3d\x36\x09\x10\x41\x2e\x76\xdb\x72\x5c\xe1\xab\x1e\x1d\x18\x9d\x0d\x3a\xbe\xf8\x2d\x76\x66\xbc\xf1\xb7\x66\x69\xe0\x64\x3b\x44\xf7\x4e\x90\xce\xaf\xa0\xc8\x37\x1b\x57\xc5\x8f\x3b\x37\x0a\x54\x7c\x60\x95\x8f\x0f\xcf\x46\x1b\x31\x50\xf8\x48\xc4\x70\xfa\x07\xe2\x9b\xf5\xf0\xd4\xb5\x9e\xfa\x5a\xb0\xd0\x34\x1e\x04\x51\xd0\xab\xb2\x9d\x74\x14\xcd\xdc\x46\xcc\x6d\x74\xcf\x3d\xc2\x33\xd0\xd1\x70\x73\x87\xbd\x8c\x77\x80\xff\x78\xe5\x46\xfb\x77\x29\x4d\x58\xa5\xdd\xa5\xf0\x5c\x12\x97\xe3\xd1\x77\x11\x56\xd2\x85\x63\x5b\xf7\xec\xed\xb3\x8a\x9e\x5e\x77\x44\x98\x04\xf3\x89\x9e\xa4\x6a\x50\x26\x6b\x25\x5a\xeb\x52\xd1\x8e\x0f\xa1\x36\xe5\x35\xcc\x90\x26\xf6\x78\x55\x2f\xa3\xee\x21\x46\x08\x1d\x99\x96\x85\xe2\x4b\xf7\x80\x7c\xc4\x7c\x13\x04\x36\xc5\x44\xd3\x5b\x4b\x87\x5b\xd8\xaf\xa3\x12\xce\x3a\xe1\x7c\xf1\xc7\xf5\xea\x1e\xce\xcb\x50\xf9\x53\x44\x72\x0c\xec\xf0\x88\x43\x4f\xf8\xe0\xba\x04\x4e\xc1\x9c\x98\xad\xa7\x78\x21\x16\x30\x4c\xbe\xac\x1c\x3e\x35\xf5\xa4\xf4\x43\x13\x35\x4d\xc9\xa4\x0e\xce\x5a\x0f\x9a\xd3\xa2\x02\x5a\xce\xf2\x62\xc5\x67\x9d\x64"}, -{{0x88,0x7f,0xdb,0x48,0x70,0x68,0x1d,0x4f,0xb0,0x6a,0x93,0x62,0x59,0xf7,0x5c,0xae,0x05,0x17,0xf5,0x01,0xaf,0x64,0x6b,0xc0,0x7a,0x4d,0x72,0xbe,0xe7,0xfb,0x1c,0x73,},{0xc7,0x62,0xeb,0xd4,0x8b,0x2c,0xe0,0x2d,0x06,0x38,0x4e,0x38,0x55,0x4b,0x82,0x5a,0xd3,0x22,0xeb,0xea,0x74,0xd2,0x59,0xdf,0x15,0x47,0xa4,0xd5,0x47,0xce,0x00,0x24,},{0x41,0x0a,0x5a,0xf3,0xc5,0x9b,0x7c,0x6b,0xdb,0x21,0x4b,0x16,0x6c,0xb7,0x9d,0x96,0xf8,0x30,0xcf,0x98,0xbf,0x52,0xda,0xd7,0xb6,0xff,0x29,0x79,0xc9,0x7f,0xea,0x4f,0xed,0x5e,0xf7,0xd3,0xd4,0x9f,0x03,0x09,0x72,0x79,0xb9,0xa0,0x99,0x22,0x6e,0x2a,0x08,0xdd,0x30,0xc6,0x07,0x86,0x25,0x4e,0x2d,0xa8,0xde,0xe2,0x40,0xbf,0xc3,0x08,},"\xc5\xdc\x77\x9f\x3f\x3f\xac\x06\xdd\x28\xe5\xa6\x7e\x0e\x52\x4a\xf5\xb5\xdc\x3b\x34\x40\x96\x57\xb6\x3d\xfa\xce\x94\x71\xe9\xa4\x1e\x11\x32\x17\x5a\x0b\x56\x9c\x8f\xea\x9d\x2e\xef\x2c\xf5\xd5\x96\x2c\x7e\x0b\x61\x45\xa9\xe7\xa0\xc1\xaa\x33\x77\x20\x44\xf9\xc3\x99\x8c\x5a\x8c\x48\x86\x45\x8b\x4e\x58\x6f\x93\x07\x60\x83\x61\xf5\x11\xe7\xab\x50\x92\xac\x41\xec\x76\xe0\x58\x6e\xf5\xb9\xc2\x36\xfc\xf5\xca\x2f\xc8\xdd\x6a\xae\xb7\x89\x36\x7f\x2e\x7c\x99\x09\x32\x55\x5d\xc5\x22\x61\xe4\x4e\x49\x42\x34\x98\xb5\x24\x41\x91\x83\xb6\xc1\xf1\xd4\x2c\x45\x46\x4e\xcc\xb0\xc2\xf7\xe2\x51\x77\xfe\x5c\xd4\x63\x50\x2b\x40\x3e\x06\xd5\x11\xfc\xf9\xdc\xb6\x40\x12\xe0\xf2\x0b\x34\xc2\xea\x7c\x00\x4d\x9e\x48\x4a\x7e\xd8\x1f\x32\x60\xc4\x1c\x8b\x19\x53\x52\x9f\x47\xf7\x1e\x86\x78\x43\xcc\x3c\x33\x2a\xd0\x36\x6a\x63\x81\x7e\xd1\x2d\xd4\x73\x0d\x3d\xfd\xbd\x75\x72\xb9\xff\x79\x80\x45\x94\x0d\xd1\x9f\xad\x0c\x8a\xea\x0b\x4a\xb6\x1c\x40\x16\xde\x32\x79\x9c\x73\xaa\x2b\x92\xd2\xc2\x5e\xe9\xb7\x2d\x46\xfe\x8f\x06\x93\xc5\x87\x75\xef\xb0\x5e\x9e\x17\xa5\xc3\x46\xa8\x12\x65\xd3\x5b\xe6\x9a\x22\xd0\x95\xde\x18\x60\x66\xa5\xc6\xd8\xc0\x7a\x3d\x38\xd0\x02\xa1\x0e\x5e\xfd\xb8\x66\xda\x4a\x9b\xdd\x54\xf5\x09\x26\x61\xb6\xc2\xd7\x43\xf5\xae\xaa\x4c\x6c\x31\x8f\xb5\x93\x23\x90\x30\x57\xe4\x9c\x23\x7b\x45\xf6\x75\x42\xa4\xf2\x7c\xaf\x65\xb5\x7c\xfc\xf8\x8b\x71\x20\x3d\x43\xd7\xf9\x53\x22\x16\x0f\x95\xc2\x32\xdd\x10\xab\xb1\x13\xb7\x21\xdd\xba\x22\x26\xb0\x63\x22\x9b\xb4\x41\x02\x33\x6b\x10\xbf\x16\x56\x55\x11\x61\x24\x97\x86\xd4\x54\xf4\xe0\x90\x9d\x50\x00\x17\xf6\xc7\x56\x4f\x73\x3c\x83\x1a\xf4\xe5\xec\x94\xdf\xd3\xbf\x8f\xf5\xf3\x02\x1b\x70\xa5\xca\x5d\x28\xc6\xdf\xb8\xa2\xc1\x8a\x1a\x66\x2a\x33\x35\x9f\x26\x4d\x16\x96\x98\xc1\xab\x55\x78\x3f\xac\xa7\x3b\xd6\x8c\x0f\x79\xd1\xd0\x4a\xe0\xec\xdb\x52\xae\x76\x18\x92\xc0\x24\x93\xff\x35\xf3\xd8\x4f\x66\xe2\x36\xfc\x58\x13\x4a\xd6\xa7\x7d\x92\x25\x49\x05\xd7\x73\x90\x0d\x9d\xdf\x26\x54\xc7\x0b\x46\xf3\x41\xda\xcb\x47\x93\xca\x51\xee\xde\x45\x53\x3e\xae\xeb\x6e\x33\x23\xbc\x3e\x6c\x85\xa7\x94\x06\x51\xc4\xf6\xf9\x81\x91\xc6\x18\xc8\x91\xea\x4e\x22\x0e\xa4"}, -{{0x88,0xb3,0xb4,0x63,0xdf,0xc3,0x0d,0x01,0x5e,0xef,0xbb,0xbd,0xd5,0x0e,0x24,0xa1,0xf7,0x27,0x77,0x75,0xbc,0xef,0x14,0xa6,0xbe,0x6b,0x73,0xc8,0xc5,0xc7,0x30,0x3e,},{0xf2,0xb6,0x28,0x4c,0x93,0x0d,0x4a,0xd3,0x2d,0x0a,0xc7,0x19,0x04,0x0e,0xe7,0x88,0x6b,0x34,0x72,0x2e,0xdf,0x53,0xda,0x80,0x1a,0xcb,0x5f,0x93,0x19,0x69,0xe1,0x19,},{0x82,0x5a,0xff,0x71,0xf7,0x93,0x03,0xbf,0x45,0x92,0xbd,0x8d,0xa4,0xd7,0xd9,0x43,0x7f,0xf2,0x67,0x97,0x6f,0x74,0x64,0x37,0x65,0x59,0x88,0xdd,0xcf,0x29,0x37,0x94,0x65,0xa3,0xb4,0x8c,0x9f,0xb0,0xf3,0x1c,0xef,0x03,0xe6,0x36,0x88,0x61,0xc3,0x69,0xb4,0x36,0x4f,0xb8,0xe4,0xb0,0xc7,0x2e,0x26,0xa9,0xa9,0xdd,0xed,0x1c,0x25,0x04,},"\x17\xc3\x17\xfa\x6b\xc9\x0c\x55\x32\x32\x8f\x02\xcc\xfb\x6c\x09\x9e\x6f\xe1\x00\x01\x74\xf2\xaf\x3a\x3a\x93\x09\x42\x85\x06\x71\x7c\x5c\x43\x35\xbd\xd7\xc3\x67\xff\x4e\x44\x8a\x9c\x04\x75\x03\xaf\xba\x68\xfd\x8f\x79\x87\x23\x7b\xe7\xf7\xfb\xdc\x6d\x73\xf2\x4c\x64\x21\xca\xb4\x22\xb3\xfb\x25\xf6\x7b\x2d\x71\x04\x2e\x71\x57\x0d\xf2\xaf\x37\xbf\xe5\xc1\x14\x21\x1f\xd5\x52\x4b\x6c\x1c\x6c\xc5\x2f\xab\xc3\xcd\x7f\xb4\x64\xcd\x58\x0b\xb7\x40\x71\xcb\x30\x0f\x8c\x9f\x8a\x46\x20\x8e\x5a\xa5\xdd\xfe\xa5\xfe\x90\x69\x7a\xa2\xf1\x4c\x60\x79\x50\xc9\x8f\x23\x12\xa9\xe1\x6e\xf6\x34\x6a\x8f\xd1\x29\x23\x27\x33\x82\x7e\x15\x01\xa6\x60\xc7\x7c\x29\xc5\x6d\x2f\xdd\x1c\x55\x97\xf8\xbc\x89\xaa\xef\xe3\x71\x37\x34\xfe\x82\x85\x82\x01\x89\x1a\x11\x47\xef\xaf\x1d\x78\xa4\x71\xf9\x20\xde\xfc\x88\x03\x44\x55\x3e\xb7\x16\xcc\xe3\x26\x0e\x86\xa1\xbc\x0b\xe2\x83\x73\xa6\xa0\x66\x11\x6e\x8e\xcb\x10\xa0\xc4\xa7\x0c\xa2\xb5\x36\x4e\x11\x9f\x84\xae\xc6\x0d\xec\xed\x3a\x4e\xff\x1f\xe6\x88\xc5\xe3\xe2\x51\x47\x0a\xb5\x16\xfa\x96\x4a\x4b\x6f\x28\x36\x8d\xd1\xe2\x83\x59\x79\x34\x06\x4d\xc0\xc5\xb5\x69\x10\x62\xcb\x2e\x26\x7b\xd1\x5f\xd4\x22\xbc\xfe\xfb\x83\xcc\xef\x7a\xa9\xa2\x27\x5e\xf5\x7e\x47\x31\x49\x98\x8c\x15\x78\xfd\x18\x70\x8d\x2f\xf6\x9f\x8e\x59\x80\xaa\x82\x6a\x82\xca\xb7\xd8\xb9\x2b\xb5\x3b\xdd\x46\xdb\x04\x6e\xcd\xfc\x8c\xd7\xae\x5c\xe4\x4f\x3c\x5b\x8c\x05\x65\xb5\xd3\xc0\x72\xc7\x6b\x95\xce\x90\x0a\xc3\xee\x55\x10\xdb\x0e\x75\xd3\xa4\x15\x0a\x98\xf3\xcc\xcc\xc6\x9e\x93\x0c\x6b\xa7\x41\xdb\xb0\xeb\x9f\xb3\x19\x68\x71\xba\x20\x6a\x58\xe0\xda\xe3\x9c\x8d\x6b\xb7\x2a\x82\x39\x9c\x4b\x7b\x9d\xa3\x85\x77\xac\x17\xff\x15\x24\xd6\x53\xc0\xbf\x33\x67\x93\x23\xca\x7e\xef\x4e\x92\x28\x72\x90\x31\x56\x0e\xd8\xf2\xe5\x19\x3c\x64\x0b\x2f\x5e\x60\x80\x75\xa2\xed\x61\x42\x8d\xfc\xcd\xc0\x00\x50\xba\x4b\x99\xed\x6d\x15\x36\xd5\xac\x1e\x93\x96\x74\xb4\x1d\x16\x31\x2a\xe5\xb0\x7d\xef\x1b\xf5\x35\x89\xbe\xd4\x40\x06\x02\xee\x11\xb8\x50\x33\x0f\x38\xaa\xd3\x3e\xf0\x41\x70\xa3\x90\x5c\x28\xb5\x0e\xcc\x57\xdc\xcf\x4f\x29\xd0\xc0\x0f\x71\x3d\x32\xff\xc8\x57\x95\x65\x88\xa6\x32\x6b\x95\x49\xed\xb0\xe4\xfe\x61\x85"}, -{{0x42,0x7d,0x6e,0x42,0x39,0x17,0x89,0x68,0x31,0x60,0x1b,0x8f,0x4e,0x21,0x56,0x1d,0xb6,0x10,0x85,0x71,0xbe,0x00,0x9e,0x29,0xdc,0xa4,0x9a,0x59,0x60,0xff,0x31,0x4b,},{0x8d,0x9e,0x63,0x60,0xfd,0xef,0x24,0x99,0x75,0xdf,0x27,0xb3,0x10,0x6a,0x71,0x12,0x05,0x87,0x72,0x2d,0xf3,0x27,0x0a,0x85,0xa1,0x3a,0x8c,0x3b,0xb8,0xc9,0x80,0x9e,},{0xd1,0xc9,0xa0,0x1c,0x56,0xe3,0x39,0x60,0xf4,0x9d,0xf3,0x7e,0xab,0x96,0x3b,0xc5,0xa9,0x9f,0x25,0xc6,0x00,0x44,0x6c,0xe2,0xca,0x48,0xd9,0x13,0x9d,0xa5,0x73,0x3b,0x71,0x8f,0xbf,0x1a,0x98,0x73,0x93,0xf6,0xe5,0x82,0x3c,0x2d,0x13,0x0c,0x7c,0xe6,0x0e,0xa3,0xdb,0x35,0x43,0xc8,0x85,0x4e,0xf1,0x2b,0x98,0xd3,0x3a,0xdd,0xe7,0x05,},"\x9c\x2c\xc7\xf2\x46\x2e\x09\xc4\xc5\x8c\x27\x09\xab\x42\x59\x88\x5a\x4e\x88\x7d\x9f\xa5\x31\x88\x15\x05\xaa\xf2\x03\xc1\x63\xfb\x3a\x0d\xc0\x28\xf4\xad\xa6\x06\x70\x63\x8d\x4a\x97\x27\xa3\x90\x83\xbe\xdb\xac\xed\x58\xed\xb7\x79\xe1\xce\x6c\xcd\xfb\x42\x8c\x36\x2b\xb1\xdb\x0c\x10\x53\x00\x6b\xd8\xf4\xbe\xf8\x9a\x1a\x9d\xe0\x1c\x77\x4e\x35\x7f\x91\x0e\x5c\x39\xb2\x24\x77\x55\x5e\x5f\x7c\x04\x98\xb5\xb2\x8f\x36\x9e\x5d\x3f\xa4\x2a\xb3\x60\xe4\xf4\x51\xc6\x9f\x81\xba\x0f\x3c\xce\xd4\x3a\x55\x9d\xb6\x00\x10\x42\x78\xf8\x68\x79\x6b\x2c\x91\x1b\x3b\x03\x2b\x72\x9f\x4b\x22\xac\x14\x9d\xc4\x67\xa0\xca\xe4\x8d\x19\xe9\xd9\x85\xb4\x2b\x62\x54\x9d\xe1\x71\xff\x56\x6e\x1d\x1e\x9b\xb8\xe5\x6c\xfd\x1a\xe8\xf7\xbd\xdc\xfd\x8a\x23\x41\x82\x7d\xbe\x89\xc8\x82\xab\x3e\x49\x83\x39\xff\x68\x1c\x7d\xc1\x10\x4d\xe7\x38\xb4\x80\x31\x69\x43\x10\x9f\x70\x3d\x47\x1a\xb8\x6e\x4c\xa4\x28\x7e\x4c\xd7\x4c\x31\x2f\xf7\xd0\x37\x39\x56\x06\xfb\x25\xf8\x71\xe7\x27\x70\x78\xa7\x87\xd0\x2f\x31\xcc\x9e\x81\x5b\xe8\x60\x0a\x7c\x47\xc6\xfd\xd8\x23\x31\xae\x9c\x49\x6a\x54\x7b\xdb\x23\x5b\x8a\x56\xd5\x32\x59\xe6\x29\x61\x24\xa3\x2c\x3b\x62\x5d\x20\x24\x19\xd0\x64\xb9\xa4\xe8\x3e\xfa\x87\xf1\x35\x37\xb4\xf5\x13\xb9\x16\xa8\x4f\xc8\x66\xd8\xa8\x99\x80\x4c\x78\x33\xea\xa0\x19\xe0\xd7\xe0\xe8\x07\x5b\xd6\xb5\xcb\x6f\xfc\x76\x64\x79\xf3\xf6\xe2\x0e\x48\x1e\x6a\xb2\x7b\xd8\x08\xad\x90\x6c\xdc\xc7\x82\x74\x30\xe3\x12\xf7\x40\xf2\x75\xdd\xf5\x1d\xd8\x32\x48\xfa\x05\x7c\x43\xc9\xcb\x77\x55\x7b\x2f\xd9\xc2\xd5\x28\x24\xff\x9e\x14\x6d\xea\xc1\xe6\x69\x1d\x45\x02\x13\xbc\x59\x0a\x49\xbe\xc7\x2d\x52\xe3\x8f\x6b\x4d\xc6\xcc\xa9\x51\xee\xf2\x18\x4d\x24\x25\x03\x1a\xd5\x9b\x24\x2e\xff\xa6\x8b\x6c\x72\xc5\x4c\x9d\xfd\xb4\x19\xc0\x2e\xb4\x3e\xf3\xf3\x4d\x33\x8d\x2a\x9d\xd0\x3a\x78\xcf\xdd\x01\x40\x98\xe2\x49\x25\x9e\x77\x28\x2e\x0c\x3f\xc1\x01\x0b\x02\xa6\x7f\xf8\x51\xe9\xcf\xd9\x74\x9c\x1c\xd8\xf0\x6c\xf4\x62\xe6\xad\xe9\x95\xac\x46\x6f\xab\x5c\x79\x5e\x9e\xff\x13\xe5\x5b\x43\x50\xb9\x4c\x73\x16\xaa\x49\x8d\xf9\xfd\xee\x99\x58\x04\x77\x93\xe3\xbb\xb8\x9f\xb8\x1d\xa8\x5f\x4b\x9d\x43\xe4\xb0\xd4\x3b\x38\x1b\x94\xcd\xc9\xa9\x9d\x06"}, -{{0xbe,0x93,0x52,0x09,0xf6,0x2d,0xea,0x60,0x12,0xec,0xda,0x6a,0x61,0x56,0xcd,0x16,0x6a,0x4d,0x76,0x11,0x50,0xde,0xed,0x45,0x68,0x16,0xea,0xf0,0xce,0x78,0xa7,0xf6,},{0xd3,0x9a,0x89,0xaf,0x72,0x29,0x39,0x48,0xb1,0x34,0x21,0xfb,0x88,0x3b,0xbe,0x37,0x2a,0xf9,0x08,0x9c,0x22,0x4d,0x42,0xb9,0x01,0x97,0x9f,0x7e,0x28,0x04,0xe1,0xc0,},{0x08,0xe0,0x98,0xa7,0x49,0xfc,0xe6,0xd1,0x23,0x54,0x39,0x58,0x78,0xa8,0xbe,0x35,0xfe,0x9e,0xdf,0x72,0x68,0x4d,0xd8,0x28,0x12,0x24,0x89,0x9b,0x1c,0xae,0xa4,0xed,0x68,0x77,0x85,0xdf,0xf5,0x5a,0x19,0x98,0x9e,0x03,0x63,0x6e,0x16,0x66,0x38,0x6f,0x22,0xc3,0xf4,0x43,0xec,0xf6,0xfd,0x34,0xd5,0x99,0xff,0x3e,0xc2,0xfa,0xf1,0x01,},"\x11\x7f\x42\x7c\xb6\x81\x50\xca\xfc\xfa\x46\x2c\x42\x20\x61\x41\x42\x7c\x4d\xce\xa1\xc8\xea\xcc\x2d\x30\xbe\xd1\xe9\x02\x07\xd5\xae\x30\x5e\x1f\xc1\x6c\x54\xe4\xc5\x4c\xc6\x87\x8c\xdb\xed\xc9\xf5\x1f\xe1\x84\x61\xec\x37\xc5\x57\xb1\x15\xd1\x3c\x86\x82\xc4\xe1\x5f\x50\x52\x96\xa1\x76\x0e\x1e\x75\xf5\xab\x27\xa5\xc1\x5a\x13\x57\xd2\xc8\xc4\x0d\xd5\x35\x5f\x7c\x82\xfe\xa5\xd2\x7e\x28\x87\x63\x58\xc1\x2e\x91\x13\xee\x29\x83\xea\x6f\x09\xc6\x4e\x06\xe2\x97\xdd\x96\xb3\x4d\x9b\x5e\xd4\x9f\xc4\x7a\x88\x39\x54\x9c\x66\xb0\x02\xfe\x94\x5e\x8f\x94\xe7\xd2\x31\x5c\x50\xca\x4d\xc0\x98\xbe\x4b\x32\x89\x81\x2f\xbe\xa9\x6b\x47\xce\x60\x45\x40\xbd\xe0\xe5\xab\x0b\x1b\xc0\x36\xbe\x9b\x6a\x95\xe0\x9c\x81\xe8\x98\x64\x0c\x8f\x05\xd6\x0a\xd9\x42\x18\xd0\xe6\x6c\xeb\x85\xa2\x6b\x78\x29\x22\x20\xbf\xd0\x61\xdd\x07\x35\x12\x92\x3b\x90\xc7\x9d\xcf\x5a\x19\x35\xfa\xfe\x8e\x01\xef\x8b\xf8\x1b\x4d\x37\xc5\xa5\x71\xb5\x0c\x42\x1f\x9b\xd2\x19\x4b\xef\x35\x86\xfc\xb8\x58\x48\x77\xbb\x7e\x04\x81\x65\x5b\x05\xc7\xb6\x43\xb1\xe4\x5b\x04\x03\x62\x72\x84\x18\x52\xe3\x19\x40\xef\x8f\x3b\x6d\x4f\xeb\x5d\xf0\x79\xd1\x76\xf9\x79\xc1\x8a\x11\xa6\x6d\x12\x14\xe5\x2f\x68\x7e\x90\x63\xc1\xc2\xb7\x27\x7b\x68\x5d\x5c\x72\xad\x56\x9f\x78\x73\x83\x8f\x91\x02\x57\xa0\x53\x13\x1c\x83\xeb\xce\x86\xe6\x9d\x73\x63\x62\xbe\xbc\x96\xbb\xfa\x35\xfc\xba\x1c\xb5\x27\xe7\x48\xe5\xf5\x79\x92\x9f\xd4\x0c\x56\xb1\xa5\x1a\x22\x2e\x86\x33\x02\x70\x5c\x86\xf7\xb5\x4e\xbf\xbb\x94\x82\xf7\xe2\x80\xf7\xbe\xc8\xca\xf3\xa6\xb5\x67\x1a\xc3\x0c\xd1\xbe\x52\x92\x88\x79\x7c\x01\x3c\xe5\x6b\xd1\x86\xde\x7d\xfc\x18\x28\x69\x14\x25\xc1\x47\xc5\x17\x4a\x29\x0d\x80\xcb\xd5\x9c\x19\xda\x7a\xdf\x77\x91\x88\x82\xa7\xb2\xa9\xa6\x4e\x6d\x76\xb4\x8b\x92\xf2\xa2\x66\xee\xe6\xe2\x51\xd2\xe8\x17\x65\x2b\x88\xb5\x02\xde\x73\x99\x78\x2d\x75\x29\xa8\x1d\x0a\x36\x39\x96\xb9\xdf\x68\xb1\x5a\x76\x30\x90\x4c\x8c\x24\x60\x81\xfa\x4f\x09\x29\x9f\x15\x75\x79\x58\xe0\x89\xa9\x01\xc3\x56\x46\x15\xc0\xf7\xcf\x27\x52\xb8\xb9\xe5\x21\x33\x8d\x83\x6e\x3d\xae\x4c\xe2\x37\x46\x42\x25\x3c\x4c\x98\x31\x97\x4e\x5d\x8c\x28\x42\xf4\x90\x07\xb7\x17\x75\x09\x3d\xfe\x57\xf4\x44\x92\xf0"}, -{{0x68,0x18,0xc6,0x0b,0xb6,0x43,0x9a,0xc2,0xee,0xe2,0xd4,0xe1,0x28,0xe9,0xd8,0x69,0x1d,0x4a,0xd5,0xd3,0x63,0xfe,0xd7,0xd6,0x57,0x7a,0x62,0xb6,0x56,0x99,0x94,0xa4,},{0x73,0x45,0xec,0x11,0xbc,0xcc,0x05,0x6f,0xc4,0xef,0xfa,0x3e,0x4e,0xf6,0x70,0x99,0x6a,0xa2,0x6a,0x1b,0xb1,0xb8,0x33,0x91,0xba,0xbc,0x39,0xa1,0xa5,0x96,0x01,0xf9,},{0x15,0x05,0x96,0x7a,0x27,0xb9,0xf8,0x6e,0x92,0x42,0x44,0x40,0x02,0xa1,0xe3,0x19,0x7d,0x74,0xdd,0xcd,0x89,0x65,0x9e,0xc5,0x14,0x02,0x02,0xaa,0xc7,0x94,0xb8,0xad,0xc1,0x93,0xe7,0xd3,0x0f,0x33,0x82,0x64,0x29,0x90,0xf6,0xfe,0xd7,0xa9,0x99,0xca,0xc8,0xc6,0x1e,0xaa,0x39,0xb7,0xd9,0x08,0x16,0xf1,0xd7,0x38,0x74,0x4b,0xe1,0x01,},"\xb2\xae\x65\x8b\x3c\x13\xc3\xcd\xeb\x1d\xc9\x93\xb0\xf4\x5d\x63\xa2\xea\x9a\xbd\x0b\x7a\x04\xf1\xf5\xce\x59\x32\x80\x6c\x2c\xa9\xb7\xa2\x04\xfb\xf8\xd0\x66\xb7\xf0\xfe\x6a\xe0\xd1\xda\x68\xc8\x85\xee\x11\xf6\xf6\xdb\x7e\x83\x20\xa2\xea\x65\x0b\x53\x38\x51\xcd\xd9\x9d\x90\x3a\xa0\xb3\xfa\xa3\xc9\x50\xf7\x02\xf0\x4e\x86\xb4\xee\xb3\xa1\xc7\xbc\x85\x4b\x25\x14\xfa\x5b\x47\x66\xd3\x75\xb4\xf1\xad\x61\x07\x53\x78\xdd\x92\xfd\x62\x6c\x2b\x47\xe0\x13\x83\xea\x72\x98\x79\x59\x26\x2c\x56\x28\x62\xb4\x5b\x75\x57\x67\x14\x13\xb6\x66\x14\xbc\xc9\xf7\xbd\xb9\xee\x46\xcb\xed\x89\x65\xbf\xa5\x05\x31\x50\x90\xc7\x20\x4b\xea\x89\x17\x5b\xe5\xf2\x08\x02\xe3\xde\xdd\xcb\xd8\xdd\x64\xcf\xef\x7e\xe6\xa6\xe3\x86\x0c\xe1\xe5\x79\x9d\xf5\xd8\x10\xd5\xec\xf3\x2e\x61\x5d\x16\xdf\xf8\x7a\xbd\x4a\x63\x6e\xa1\x7a\xa4\xec\xe5\xb6\xb2\xc0\x46\xb6\x5b\x5a\xf7\x49\x86\x2b\x45\x79\x0c\x39\x17\x68\x20\xb3\x69\x01\xbe\x64\x9c\xf4\x16\x9d\xf7\xe9\x23\x95\x6d\x96\x06\x49\x50\xc5\x55\xf4\x5a\xcb\x94\x50\x7c\xfd\x0c\x3b\x33\xb0\x80\x78\x5e\x35\xc0\xd2\xb0\xad\xdc\x4c\x0a\xd3\xfb\x21\x6a\xc2\xe6\x01\xc9\xc7\xe6\x17\xda\xbd\xa3\x33\xda\xe6\x03\xcc\x9d\xb1\xfc\x62\xae\x4e\x0e\x45\xe3\xcc\xdd\x16\x6a\x67\x81\xe2\x43\xb7\xda\xa1\x38\x80\x66\x32\xf5\x38\x84\x4e\xe3\xd1\x40\xb7\xa8\xbb\x2b\x54\x01\x00\x77\x8c\x45\x8e\x06\x61\x70\x70\x5e\x5f\xb2\xc8\x80\x29\x09\x8b\x99\x2c\x39\xbc\x9f\xf6\x33\x0b\xfc\xfe\x77\x52\x32\x0e\x6e\xa0\x94\x9d\x2c\x87\x1a\xed\xc1\x87\xbe\x27\xfe\xf7\xdb\x5f\x72\xa6\xa7\x73\xed\xde\x0d\xc5\x2a\xe2\xed\x93\x1c\xb2\x68\x17\xb8\x5b\x15\x45\x89\x4d\x92\x29\x8a\xaf\x87\xcc\xbc\x78\x3e\x8d\xd6\xd1\x64\x93\xf5\x6e\xad\x2b\xa8\x52\xee\x9c\x7d\x10\x07\x44\x06\x44\x0d\x2a\x27\x9a\xbc\x87\x4f\x15\x46\x8d\xd6\x6a\x71\x7b\xac\xe3\x7b\xe7\xb7\x05\x5d\xd9\x68\x1f\x8b\xe8\x13\x29\xee\x7a\xf9\x7e\x3a\xbc\x43\x4a\xc1\xc9\x3a\xec\x58\x2f\x23\xfd\x1e\xc0\xfa\x5a\xaf\xcf\x7b\xfb\xda\x00\xff\xa9\x7a\xe3\x17\xae\x91\x8d\x34\x9d\x21\xa7\xf4\x61\x91\x42\xba\x23\xda\xce\xf7\xb3\x90\xae\x26\xa1\x7e\x2e\x29\x62\xae\x27\x00\x53\x76\xb7\x2d\x4d\xa9\xe2\x97\x96\x53\xa6\x63\x25\xa1\x46\x17\x63\x8d\xbe\x1a\x55\x40\xb6\x83\xac\x00\x17"}, -{{0x6d,0x1d,0xa5,0xb4,0x83,0xe6,0x4b,0x03,0x65,0x99,0x0f,0xf0,0x93,0x81,0xfb,0x17,0x02,0xfd,0x8e,0xc3,0xa1,0xa3,0x69,0xcd,0x52,0xe4,0xc5,0x67,0x13,0xa3,0x14,0xa5,},{0x08,0x05,0x5c,0x26,0x1f,0x26,0xe0,0x2a,0x65,0x8f,0x66,0xd9,0xba,0x01,0xfc,0xde,0x53,0xe9,0xad,0xe3,0xed,0xc6,0xbf,0x81,0x5e,0x4a,0x68,0x02,0xe1,0x67,0x7a,0xb3,},{0xa5,0xb8,0xb4,0x4a,0x91,0x44,0x4c,0x64,0x37,0x4b,0x52,0x3c,0xb4,0xdc,0xb0,0xce,0xf4,0xce,0x52,0x40,0x8b,0x98,0x12,0x6d,0x7e,0x1a,0xe8,0xbd,0xc2,0x8c,0xf5,0x14,0x70,0xce,0x4e,0x25,0x3e,0x0b,0xe6,0x2b,0xd6,0x8e,0xbf,0x5f,0xa6,0xbc,0xe1,0x58,0x5e,0xcc,0xfa,0x92,0x56,0xc0,0x73,0xee,0x03,0xe5,0x4c,0x52,0x5b,0xbe,0x2d,0x0a,},"\x79\xa2\xc3\x70\x55\xf1\x89\xf3\x24\x7f\x1f\x8c\xea\x19\xb2\xea\x40\xd8\x58\xdb\x1f\x5d\x13\x92\xee\x6d\x41\x1c\x78\x02\xee\x23\xde\x52\xad\x02\x81\x17\x25\xa9\x4d\x76\x67\x5d\xa8\x9a\x96\xb5\xd0\x7a\xbc\xee\x23\x3a\x1a\x2e\x1f\xa3\x24\xff\xf9\xe7\x8a\x4c\x19\x61\x47\xf8\x57\x0b\x0b\x13\x71\x3d\x96\xaa\x5d\x75\x0a\x15\xd7\xcd\x16\x2e\x7b\xa2\xe7\x53\x33\x60\x7d\xd6\x98\xeb\x47\x73\xc7\xe9\x1f\x76\x68\xff\x8b\x62\xf0\x46\x40\xeb\x12\xec\xf1\x22\xfc\xe6\xb8\x32\xe0\xd0\xdf\x92\x8e\xef\xd2\xc2\x00\x23\x64\xaf\x6b\xb5\x52\x91\xd3\xf5\x49\x29\x08\x5b\xe3\x38\x34\x2f\x09\xda\x73\xe2\x79\xc8\x7c\x83\x24\x55\x58\x19\xed\x57\xe7\x8d\x7a\xc4\x09\x51\xd3\x3f\x65\xb9\x4a\xa1\xe5\x55\xe9\x2a\x06\x3d\x11\xf1\xff\x7b\x12\x69\x43\x41\xe3\xfe\x44\x49\x33\xd0\x1a\xa3\x67\x53\xed\x3c\xdd\xa8\x90\xbd\xf9\x5a\x82\x05\xb5\xd8\x93\x22\x19\x91\xc7\x95\xad\x0a\x4a\x94\x6f\x58\xd4\x0a\x45\x34\x51\xaf\x21\x4f\xd4\x65\xe2\x8d\x3e\x2f\x0a\x56\xaa\x56\xde\xf8\xdc\x04\xaa\xd3\x57\x13\xab\xfc\x8b\xd7\x85\x6d\x5a\x9d\xc3\xf6\x0a\x3f\x2b\xd3\xe6\x36\x6f\x1f\x24\x4e\x94\x1d\x6a\xea\x89\x2f\x6a\x88\x93\x1f\xe1\xc3\x13\xe0\x90\x78\xe9\x0b\xc6\x39\x2d\x49\x05\x33\xc9\xea\x3f\xf6\xde\xaf\x3a\xad\xfa\x8d\xfd\xc4\xe9\x0f\x64\xaf\x47\x58\x9e\xa6\x5a\x87\xac\xd2\x19\x96\x02\x35\x1d\x3a\xfc\x21\x03\x19\x6e\x03\x94\xed\x52\x3a\xa7\x99\xd3\x1e\x11\xd3\x4f\xff\x54\x6d\x44\xf4\x36\xb3\x48\x59\xf9\xcf\xbc\x9c\xe4\x03\xde\x5a\x98\x30\xec\x3d\x45\x3f\x0d\x45\x97\x0f\x57\x2c\x14\x4f\x19\x1b\x2f\xbb\x2d\x0e\xa6\xcc\x9c\x8e\x24\xd9\xc0\xb2\x18\x3b\x27\x80\x72\xeb\xb0\xbe\x2d\x70\xd0\x37\xfd\x2e\x8e\xc1\x8d\xc4\xc9\xb2\x1a\xbd\xc6\xa4\xce\x8d\x46\x68\xa2\x20\xee\xbd\x69\x34\xf0\x4b\xaf\x0e\x88\xa4\x88\xd2\xdf\xc7\x35\xa7\xc5\xa7\x0d\xbb\x01\x66\xa2\x1a\xe0\x11\xfc\x6e\x7d\xa1\x0f\xc3\x20\x33\x62\x71\xd9\xee\xad\x51\x0a\x6f\x70\x32\xf2\x29\x66\x92\xbe\x50\x80\x21\xbc\x98\xc1\x70\xbe\x42\x35\xf7\xce\x31\xf2\xbc\xd6\x34\x11\x63\x68\x33\x76\xae\x2c\x56\x62\xcb\x47\x70\xc9\x6e\x01\x8e\xf1\xbf\x47\x91\x33\x19\xc9\xa0\x9b\x9e\x96\x5a\xb5\xc3\xe9\x7b\xbc\x75\x6a\x56\x66\xb4\x56\x7f\x2c\xff\x2d\x0c\x3a\x6a\x40\x26\x15\x8c\xb9\xf9\x0f\x95\x00\x56"}, -{{0x51,0x46,0xf5,0xb7,0xf1,0xba,0xa1,0x9f,0xc8,0xcd,0x78,0x5c,0x89,0x6e,0x0f,0x90,0xf9,0xf6,0x59,0xb7,0x7b,0x1b,0x9b,0xb4,0xad,0xca,0xb5,0xa6,0x26,0x72,0x05,0xe4,},{0x68,0x8a,0x8d,0xe6,0x4e,0xff,0x33,0xba,0x6b,0xbe,0x36,0xcd,0xd6,0xa3,0x84,0xbb,0x67,0xb3,0xf4,0x26,0x36,0xdb,0x23,0x4f,0xf5,0xef,0xe0,0xb3,0x17,0x43,0xc7,0xe6,},{0x4b,0xdb,0xd7,0xc6,0x4f,0x13,0xe2,0x78,0xc2,0x39,0x69,0xe7,0xeb,0x38,0x6b,0xbe,0x49,0x9d,0xbd,0xef,0xc3,0xff,0x4e,0x30,0xcf,0xac,0x5c,0xf8,0x6f,0x21,0x6c,0x24,0xc9,0xe6,0xcd,0xe2,0x0e,0x52,0x9d,0x14,0x7f,0xb7,0xea,0x08,0xf2,0x59,0x3a,0xd5,0x09,0x03,0xb5,0xed,0xbf,0x86,0xb4,0xd2,0x8f,0x2e,0xb3,0x2e,0xf1,0x37,0xf0,0x0c,},"\x97\xbd\x99\xf5\x18\xee\x07\x88\xd5\x76\xd9\x9c\x04\x3b\x44\x9d\xfc\x24\x2a\xc5\xee\xae\xc3\x44\xa1\x94\x32\xb3\x45\x96\x2e\xc4\x12\xce\x55\x36\x2b\x3b\x85\x1d\x98\x11\x9f\xce\xb9\x32\x83\x47\xf6\xfc\xc6\x8d\xbf\x56\xa2\x81\x4d\xb0\x9e\x93\x85\x84\x3a\x93\x11\x89\xea\x3e\x72\xda\x9d\x79\xa4\x56\x93\x05\x3c\x03\x57\x01\xdc\x55\x51\x24\x0f\x95\xb3\x03\xfb\xa1\x6f\x89\xaa\x53\xa4\x38\x82\xb0\xf1\x38\x12\x02\xc7\x8f\x9c\x74\x19\x89\x9f\x23\x51\xec\xa9\x5e\x20\xbf\xee\x76\x35\x1c\x48\xd0\x04\x99\xf5\x91\xda\x56\xa9\x95\x24\xbb\x74\xfe\x1c\x83\x4e\xe9\x10\x77\x13\x9f\x1e\xdf\x67\x31\x5c\x07\xa3\xfd\x97\xf8\x0b\x7c\x27\x6b\x6c\xf6\xb5\xcc\x36\xbe\x36\x3b\x73\x12\x17\xf6\x31\x9f\x51\x29\xba\x7b\x14\xd0\x54\xc8\xd8\x1d\x8e\x3a\x3f\x3b\xe6\x2a\xc3\x1f\xf6\x2d\xf6\xa3\xb2\xee\x25\x96\x96\x9b\x99\x17\x04\xb3\x1c\x68\x99\x97\xab\x46\x28\xbc\x26\x60\xc6\x78\x72\x13\x2e\x85\xda\x0c\x4f\xcf\x56\x79\x65\xf1\x25\x4a\x8f\x43\x26\x92\xa1\x7b\xb8\x6c\xb3\xc1\xdc\xba\xac\x93\x95\x52\xf0\x9e\x50\xec\x5b\x0d\xe2\xef\x85\xe0\xac\x25\x3a\x41\x65\x65\x5d\xb5\xb5\xc4\x98\x03\x82\x1d\x85\x9c\x60\x96\x1e\x06\x1d\x58\x27\x8b\x82\x7d\xd4\xd3\xbc\x47\xf1\xc2\x2d\xe0\x94\x90\x6b\xdb\xbf\x3b\xad\xbd\xde\x22\xba\x24\x25\x58\x55\xeb\x86\xd1\xd7\xf3\x70\x82\x05\x93\x11\xdc\x07\x28\xeb\xea\xf2\x6c\x44\x73\xba\xd1\xfa\x9e\x61\x4b\x53\x3b\x81\x1b\x6b\xcb\x06\x50\xc0\x6d\x87\x9a\x52\x45\x78\x8f\x34\x01\xb4\x61\x97\x30\x07\x74\xa9\xaa\x73\xcd\x97\x8c\x05\x30\xc8\x1a\x53\xbd\xb3\xfc\x93\x24\x14\xb3\xe3\x04\x40\xdc\x12\x74\x41\xef\xf1\x60\x5e\x7f\xd9\xac\x8c\x63\x2e\x82\xbf\x1b\x45\x3d\x4f\x33\xa5\x7e\x4b\x67\xb0\xb6\xfc\xf6\xed\x55\x55\xb5\xf5\xa3\x00\xa1\x4a\x00\xd0\x38\x5a\x33\x75\x05\x25\xb0\x0e\xdb\x31\x2c\x6b\xfd\xd6\x4e\xdd\x3b\x53\x16\xd1\x9f\x95\x8c\x51\x76\x34\xf0\x13\xb0\x08\x93\x6d\x34\xe9\xb5\xe1\xe9\x28\x3a\x5f\x0f\xd7\x78\x33\x77\xc0\xe5\x09\x06\x41\xbb\x9d\x33\x8c\xf3\x13\x3a\xcd\x0b\x97\x1e\x53\x79\x04\xf1\x7a\xf9\x29\x11\xaf\xad\x72\xee\x97\xf9\xa8\x28\x3a\x16\xa7\xe2\x6a\xb4\x28\x41\x6c\x10\x17\xda\xe9\xb1\xa9\x9c\x4c\x33\x20\xad\x16\x3b\xdc\xfc\x32\x8b\xfa\xf9\xb8\xd5\xd7\xd2\x6d\x41\xd1\xef\x21\xa5\x20\x8f\x01"}, -{{0x5e,0x6f,0xda,0xc9,0x35,0x1a,0x63,0x7b,0x99,0xf3,0x3a,0x26,0x4e,0x12,0x87,0x69,0x7e,0x2a,0xba,0xb0,0xcc,0xa1,0x66,0x21,0x79,0x24,0x84,0xf5,0x60,0x6f,0x44,0xc1,},{0x57,0xe5,0xf8,0x8a,0xcd,0xdc,0x8c,0xde,0x7d,0xd0,0x7a,0x31,0x46,0xfb,0x1d,0x4f,0x7a,0x9b,0x63,0x83,0xa8,0xf6,0xb2,0xb8,0xd9,0xb0,0x7e,0xbc,0x3f,0xc4,0xdd,0x20,},{0x98,0x7e,0x32,0xe0,0x0a,0x8a,0x16,0x32,0xf4,0x7b,0x50,0x31,0x94,0x35,0x5c,0x98,0x0c,0xb2,0x2a,0xde,0xb3,0x26,0xb4,0xe3,0x11,0x5e,0xca,0xb0,0x4b,0x70,0x4d,0x18,0x6c,0xd9,0x2e,0x3c,0x3a,0xc7,0xb4,0xe2,0x93,0x6c,0xbd,0x07,0xcb,0x79,0x4e,0xc0,0xcf,0xe9,0x1a,0x97,0x87,0x2f,0xf2,0xb4,0x13,0x76,0xf5,0xf1,0x8f,0x55,0xb8,0x05,},"\x4d\x6c\xd3\xbc\x2f\x86\x26\x6b\x8b\xb1\xb6\x1d\x0e\x1c\xaa\x9b\xd2\xd4\xa1\x80\x36\x1a\xef\x3a\x18\xd3\x90\xb1\x0f\x7e\x86\x0f\x69\x7e\x24\x7e\xb6\xc3\xe5\x1d\x3b\x97\x6b\xf0\xca\x18\x3d\x01\xa6\x98\x80\xf1\x5c\x94\xb8\x75\x66\x8c\xa3\x0d\xad\xa0\x89\x5b\xed\xd4\xd7\x05\xa0\xe0\x33\x04\xd0\x63\xde\xa8\x7c\x7f\xde\xc9\x8b\x89\xc0\x6f\x13\x0d\xd5\xbd\x58\x6b\x54\xd9\xba\x73\x78\x26\xbb\x40\x5c\xd8\xac\x8b\xbc\x95\x00\xac\xda\x3c\x07\x46\x1d\x00\x94\x40\xaf\x0b\x25\x31\xe7\x2f\x3f\xf5\x01\x6a\xe2\xd8\x6d\x69\xb8\x7f\xb2\x73\xd1\xe8\xdd\x5f\x6a\x26\x4b\xee\xbb\x2f\x88\x59\x96\x74\x1f\xfd\xa2\x77\xa0\xfb\xf8\xef\x08\xf8\x1f\x22\xee\x59\x61\xd9\xd3\xfc\x93\x83\x62\xe1\xca\x12\x00\x4a\x91\xd9\xb5\xf7\xa6\x83\x3a\x6c\x22\x95\x5a\xc0\xcd\xa3\x39\x06\x71\x91\x0c\xbd\x51\xe6\x85\xfe\x09\x59\x73\xe4\x15\xfc\x2d\xb8\xad\xf1\x0b\x14\x7e\xc7\x08\x0c\x3b\x8e\xbd\x07\xd2\x1b\xb9\x55\x6d\xa8\x54\x30\xa2\x68\xee\xd8\x48\x6b\x1e\x31\xc9\x43\x13\xb0\x16\x49\xfe\x91\xb2\x22\xf8\x5a\xde\xe1\x5e\xb7\x77\x07\xd7\x8f\xfc\xb6\x60\x92\x65\x44\xd3\x3b\xe9\x99\x4a\x29\x76\x20\xdc\x7a\xed\x97\xf3\x92\x63\x90\x53\xf3\x88\xb0\xb3\xaa\x3b\xd0\xac\x5b\x03\x3c\xb4\x14\xbe\x52\x0b\x43\xdf\x68\x26\xb9\x76\x89\x0d\x0c\x53\xb9\x7b\x6c\x92\xe7\xd1\xa1\x57\x3d\x0c\x74\x94\xd7\x47\xe0\xca\xd9\xbd\x8e\xa5\x38\xd6\x2a\xd5\x98\x01\xad\x07\x16\xf1\x70\x19\x3e\x30\x09\xd9\x95\x9c\x55\xd2\xff\x64\x79\x9b\xd9\x59\x35\x9a\xbb\x94\xca\x97\x23\xb5\xff\xc2\x4c\x95\x07\xf8\xc5\xfd\x6e\x88\xea\xae\x7a\x70\xad\xd8\x4d\x74\x4c\xcf\x8b\x98\x36\x37\x88\xf0\xbf\xb1\xa0\x25\x22\x02\x57\x51\xe5\x34\x71\x0d\x40\xa2\xd3\x8a\x79\x11\x94\xeb\xa2\x93\xfd\x20\x46\xcc\x14\xdd\x38\x76\xd1\x68\xfc\x6e\x23\x6c\xbe\x14\x6d\x63\x69\xd2\x25\xbf\xa6\x7e\x53\x97\x98\x65\xf7\x88\x73\xa9\xfc\xf0\x3c\x18\x6f\xa8\x52\x1f\x0a\x55\x45\xac\xce\xe8\x0d\x1e\x55\x10\x72\x21\xe2\x1f\x0f\x22\x91\xc1\x43\xde\x02\x3e\x88\xd7\x33\x0c\xc8\x7d\x4c\x51\xff\x29\xa3\x09\x06\x05\xe9\x73\x94\x90\xc1\xdc\xee\x71\x34\x95\xf2\x31\xc2\xa3\x6b\x11\xab\x23\x55\x47\xfb\x63\x28\xf7\x47\x33\x6d\x9b\x1e\xf2\x5a\x8a\xb9\x9c\xed\xa9\x57\xb2\xdc\xce\xe4\x07\x5b\x0d\x03\x38\x1b\x94\xae\x18\xd0\x41\xea"}, -{{0xfc,0xff,0xf0,0x93,0x2d,0xc8,0x6e,0xa5,0x90,0x2a,0x8d,0x33,0x07,0x33,0x29,0x96,0x0c,0xd8,0x18,0x8a,0x07,0x5d,0xd0,0xbc,0xdf,0xa8,0x38,0x2c,0x20,0xb0,0xe7,0x8f,},{0x0c,0x92,0x05,0xa9,0x0b,0xbe,0x7f,0x2d,0x50,0x5e,0x17,0xfa,0x3d,0x08,0x0b,0x52,0x2a,0x1d,0x7a,0x15,0x2c,0xad,0x2d,0x85,0xd3,0x1b,0x34,0xa0,0x47,0x1c,0x0d,0x4c,},{0x37,0xdd,0xd8,0x3f,0x98,0xb0,0x57,0xb7,0xcb,0x32,0x08,0xa8,0x32,0xc5,0x8a,0xa9,0x06,0x94,0x56,0x3c,0x23,0x54,0x8d,0x43,0x22,0x91,0x38,0x0b,0x73,0x59,0x13,0x01,0xf2,0x74,0xb0,0x4c,0xee,0x2e,0xf7,0x8c,0x06,0xd9,0x6c,0x3d,0x9b,0x7c,0x17,0x52,0x1a,0xae,0x1a,0x8c,0xa5,0x0d,0x34,0x7c,0x09,0xc3,0xcf,0x70,0x3b,0xc8,0x83,0x0b,},"\x3d\x4b\x76\x12\x23\x73\xe2\x12\xa3\x46\xd1\x9a\x66\xbb\xfc\x4b\x62\x32\x92\x64\x9b\xd0\xce\x5c\xf6\xbb\x13\x56\x48\xbd\x01\xdb\x74\x03\xb3\xd0\xbd\xd1\x69\x7f\xf4\xe6\xe9\x08\x90\x41\x16\x75\x4d\x37\x0c\x40\xd7\x00\xcd\xb6\x64\xc4\x6a\x91\xdd\x84\xa3\x58\xb9\xd2\x38\x14\x43\xe6\x0f\x2c\x3f\x56\x40\x26\x1b\x6b\x85\x8b\xa8\xf8\x28\xb0\x97\x1f\x41\x22\xb2\x02\x88\xa2\x6b\xa2\x09\x0b\xa1\x4f\xd2\x76\x36\x0c\xc6\x86\x79\xcd\x84\x19\xae\x19\xc6\xd4\xdc\x7b\x66\x14\xc0\x6d\xf5\xe5\xc0\x51\x0e\x2c\xb6\x86\xde\x0e\xbd\x75\xe5\x21\x0a\x21\x55\x62\x58\x9b\x28\xc9\xcc\xc7\xd2\x72\xb9\x8b\xd4\xbf\x93\x49\x5e\xfe\x4f\xc5\xb7\x8d\xef\xec\xfb\xca\xa9\xfe\x12\x6b\xad\x30\xe8\x9b\x3a\x38\x9b\x42\x56\xf6\xa4\x8a\x76\xc3\x45\xde\x5a\x36\xa1\x44\x9f\x08\x34\x5b\x9a\x5e\x6a\x00\x1d\xa1\xff\x9c\xd4\x33\x70\x93\x48\xe9\xae\xfb\xc7\x8b\xa5\x2d\x3a\xb3\xb4\x69\x86\x93\x5e\xba\x8e\xcf\x81\xed\xc4\x3c\x5b\x2e\x3b\x5e\xb3\x8d\x9a\x16\x5e\x9e\x7f\x72\xf6\x17\x60\x54\x63\xbe\xdb\xa9\x73\xeb\xfd\xcd\xf2\xb0\x88\x9c\x71\x41\x2f\x8f\x85\x0c\x7a\x3b\x55\x18\xec\xd8\x9d\x2e\x25\xc0\xc1\xc3\x0f\x08\x5a\x0f\xfe\x54\x0e\xf9\xc0\xe8\x8f\xc7\xec\x4a\xf1\x94\x8a\x4e\x6f\x7a\x6e\x25\x6b\x30\x7a\x11\x27\xb7\x1b\xa6\x86\xef\xea\xdc\xa0\xe4\x86\x09\x47\xcf\x67\x4f\xce\xd6\xca\xf7\x31\x0c\xcb\xaa\x8d\x90\x47\xda\xed\x30\xfd\x55\x85\xd4\x1d\xde\xae\x4d\xf2\xfe\xd4\xb6\x22\x80\x32\xc3\xe4\xae\x23\x80\xe8\x7e\xc6\xcd\x72\xe4\xd7\x4b\x8b\x4c\x38\x13\xfb\x04\x33\x89\x39\x1e\x9c\x13\xf7\xd3\x3c\x3a\xab\x5a\x78\xfc\x4c\x6a\x63\x4c\x61\xa7\x0f\x02\xa9\x40\x54\x8d\xa1\x77\xc6\x5d\xf6\xab\x17\xcd\x96\x83\xf3\x7e\xa8\x21\xc7\x40\x88\x9d\x82\xe8\x8c\x83\x4e\x7d\x5d\xc1\x16\x62\xea\x78\xb1\x3c\x6a\x4b\x62\x18\xd3\x17\x84\x21\x9a\x47\x67\x59\x5b\x1a\x56\x21\x65\x25\xcd\x68\x93\x8b\x22\xbd\xb1\xf8\xc5\xa7\xf1\x70\x1a\xfe\xb9\x61\x88\x8e\x2e\x0e\xc0\xc8\x38\xcd\x62\x0c\xb7\xdd\x8a\x14\x93\xa0\x2c\xd5\x6b\x54\x51\x25\xe4\x70\x0c\x08\x89\xfa\x26\x44\xe6\x44\xa3\xaf\x53\x1d\x1c\xd6\xbc\x95\xe5\xdf\x91\x75\xf1\x37\xf2\x84\x08\xcb\x69\x9c\x7a\xe6\x6f\x65\xd1\xd2\x93\x0f\xac\x57\xca\x8a\x60\xe6\x31\x1a\x40\x78\x48\x8c\x9e\xa4\x04\x94\x8a\x9d\xeb\xeb\x9d\x5e\x10"}, -{{0xa1,0xe4,0xfc,0xfd,0xe0,0x44,0xf1,0xbb,0x0e,0x7b,0xbc,0x63,0x1a,0x83,0x1a,0x8d,0x07,0xe9,0x0a,0xe0,0x8a,0x96,0x6a,0xd6,0x27,0xb6,0x20,0xb1,0xe2,0x8c,0x42,0xcf,},{0x25,0x56,0x0f,0x31,0x16,0x8b,0xd4,0xb7,0x25,0x52,0xed,0xed,0xd0,0x8b,0xb6,0xbf,0x79,0xa9,0x40,0x63,0xc1,0xf1,0xe1,0xd3,0x04,0x86,0x9d,0xd1,0xce,0x04,0x9b,0x95,},{0xc8,0x00,0x15,0x27,0xbd,0x90,0x2c,0x15,0xc3,0xdd,0x5a,0xe1,0x81,0x80,0x52,0x5b,0x5e,0x82,0x02,0xbe,0x66,0x71,0x1f,0x82,0x88,0x5c,0x82,0x22,0xa1,0x5f,0x06,0x00,0x92,0xa2,0xa6,0xe2,0xf7,0xd7,0xe9,0x80,0x31,0x12,0x09,0x19,0x1b,0x32,0xb8,0xad,0xe4,0x8d,0x3e,0xa9,0x8c,0xf2,0x45,0xf0,0xfa,0xd6,0x2c,0x00,0x9c,0x5a,0x71,0x08,},"\x8c\x14\x54\xd4\xe0\x8a\x14\x01\x64\x6b\xf7\xa8\x85\x9e\x8a\x14\x5e\x85\xee\xeb\x40\xdb\x38\xff\x01\x69\x70\x96\x41\x21\x2c\x81\xb6\x73\x90\x74\x9c\x01\xa7\x98\x07\xf3\xcc\xad\xbb\xd2\x25\x6f\x36\xff\xc1\x80\xcf\x9b\xa4\x4b\xf4\xa7\x61\x2d\x44\x1c\x23\xb2\xe2\x5d\x33\xc4\x8a\x73\xe1\x6c\xe3\x57\x56\x27\x58\xad\xb0\x05\x53\xc3\x14\x2f\xb8\x17\x6b\x6a\xe8\xfb\x61\x0a\x60\xf9\x23\xb0\x91\x18\x14\xb1\x0f\x56\x79\x93\x6c\x36\x77\xb7\x0e\x84\x6e\x21\x8f\x58\x75\x67\xf2\x01\x9c\x7d\x28\x2a\x10\x7f\x3c\xc8\x47\x63\xad\xae\xc8\x89\x93\xc0\xcc\x50\x03\xe7\x7a\xf6\x0d\x67\xdb\x53\xf8\xcb\x72\x7a\xa6\x67\x2d\xe0\x04\x49\x8c\x3b\x3e\x22\x2a\xa7\x08\x2d\x91\xf9\x8a\x1a\x06\x83\x74\xc5\x10\xff\x53\xa5\xe5\x59\xcb\xe2\xd6\xc7\xc3\x44\x2d\x72\x38\x90\x7c\x81\x1d\x58\xaa\x7f\x5a\x46\xb8\x31\x12\x44\xf0\xdb\xe1\xb9\xc0\xe9\x44\xdd\xa1\xd8\x01\x08\x64\x94\x9c\x59\x39\x6c\x6b\x34\x6a\x11\xf3\xaa\x86\x6d\x6b\xce\xad\xfc\x90\x90\x38\xd2\x2e\xfb\xc8\xf1\xda\xc8\x10\xa9\xf2\xfa\xfc\xce\x7c\x03\x89\xeb\x0a\x56\xc0\xf6\x8c\xae\x24\xae\x3d\xdb\xdf\xf7\x11\x6d\x2f\xad\xeb\x9b\x0e\x75\x09\x53\x6f\xdc\x3b\x83\xe7\x13\x54\xda\x6a\x1a\xed\x16\x88\x74\x90\xdc\x2f\x4d\xf5\x7b\xba\xa7\x24\x45\x28\xfa\x30\x94\xb9\x9e\x86\x75\x81\xac\xef\x90\x62\x70\xb2\xcf\x4d\xed\xa6\xb8\xfd\x9d\xbb\x79\xad\xd7\xbe\xa8\xf8\x6f\xcb\x1f\x64\xdf\xd5\x0e\x38\x5b\x42\x09\xec\x0b\x1a\x9f\x6d\x2e\x51\x90\x68\x29\x7a\x2b\x5c\x40\x5c\x21\x6b\x4a\x2e\xd9\x83\xff\x69\xc5\x9b\x53\x0e\xff\xa6\x0c\x03\x67\x05\x12\x67\xdd\x2b\xbd\x1e\x86\xa9\xab\x5a\x11\x4d\xd4\xf6\x9b\x54\x0b\xfa\xbf\xe9\x7c\x04\x03\xb8\xfc\xbb\x27\x62\x57\x61\xed\xa3\xe2\xad\x8e\x62\x5c\xfe\x4b\x61\x5b\x70\x25\x53\x1a\x49\x89\x18\xc2\x4e\x02\xa0\x0e\x79\x7b\xba\xfd\x14\xf9\xd3\xf6\x82\x7e\x39\x00\x63\xc4\x36\x08\x06\x88\xd0\x37\xa6\xe2\x99\x3c\x56\xd3\xa8\xe9\x5f\x37\x5c\x10\x04\x0b\xf0\x4f\x03\x0c\x97\x26\x23\xd9\xe3\x80\x1c\x13\xb4\xec\x8d\x01\xcf\x18\x38\x55\xf5\x93\x5f\x10\xdd\xb2\xc5\x4c\x51\xc8\x0c\xbe\xd0\xc2\x4d\xb5\x6e\x1e\xd1\x48\x93\x1d\x89\x16\x1c\x5e\xa3\x7c\x2f\x97\x87\xf8\x8e\xf7\x33\x0e\x5d\xcd\x0e\x43\xd8\x1b\xfc\x8b\xf2\x3d\xdf\x79\x83\xcc\x1d\x73\x38\x43\xa3\x3c\xcb\x39\x5d\xfc"}, -{{0xbe,0xd1,0xbb,0xca,0xe1,0x86,0x43,0xd6,0xf6,0xaa,0xc3,0x4f,0x3d,0x9b,0x6a,0x14,0x78,0x39,0x4d,0x02,0xb9,0x31,0xcf,0xf0,0x06,0xd8,0x5f,0x21,0xb7,0xdb,0xc7,0x47,},{0x4f,0x52,0x8b,0x38,0x18,0x5a,0x42,0x4c,0x6f,0xde,0xce,0x46,0x51,0x1a,0x0c,0x29,0xb7,0xc0,0x4b,0x32,0xeb,0x04,0x83,0xab,0xb5,0x2d,0x5f,0x8e,0xb6,0xb3,0x52,0xeb,},{0x0f,0xc9,0x9d,0xd3,0xb9,0xa0,0xe8,0xb1,0xfc,0x6e,0x63,0x5a,0xf5,0xc6,0x40,0x06,0xb6,0x72,0x00,0xfe,0x95,0x8f,0x53,0xcc,0xe1,0xb9,0xb0,0x91,0xa4,0xe7,0x06,0x69,0xb5,0x93,0xf1,0x55,0x94,0xbc,0x08,0x42,0xe5,0x57,0x62,0x59,0xf9,0xa6,0x85,0x9a,0x0d,0xb2,0x2d,0x74,0x0f,0x9f,0x80,0x24,0xb5,0xba,0xf1,0xef,0x6f,0x95,0x8c,0x05,},"\xff\x7c\x64\x13\xe6\x18\xa0\x56\xde\x40\x1e\xe1\x0c\x40\xad\xe3\xd7\xc0\xe6\x86\x14\x95\xd9\x7c\x26\x89\xec\x6a\xbb\x69\xdd\x2a\xe7\x01\xfd\xca\xc8\xf0\x83\x31\xea\x5c\x5f\x5d\x80\x5b\x57\x89\xee\x5e\x24\x1f\xf4\xac\x8b\x96\x0f\x4f\x2b\x9f\xef\x6a\x72\x7f\xad\x86\xdc\xd4\x32\xde\x9f\xad\x6b\xa4\x5e\x00\xaa\x36\x87\xb0\xce\xeb\x2c\x0d\x43\x0b\x7d\x5f\xde\x63\xb4\xf6\xb9\x82\xc4\xf9\xe0\x3c\x43\x0a\xba\xd9\x04\x4d\x06\xdc\x49\xe8\x9d\xf4\x81\x40\x5d\x8f\xeb\xbb\x06\x53\xe9\x68\x69\x48\xaa\xd2\xd9\x07\x25\x44\xdf\x94\x24\xfd\x48\x7f\x4e\x24\xba\x7f\x24\x55\xdd\xec\x41\x05\x82\x8c\x39\x81\xbd\xdb\xb1\xb7\xfb\xdb\xac\x15\x59\x03\xe9\x60\xfc\xd9\x4c\x07\x16\xe7\x36\xf5\x19\x86\x7f\xbc\x52\xc5\x12\x60\xf5\x71\xd7\xed\xcb\x08\x1a\x23\x55\x0a\xd8\xc7\x0b\xb2\x68\x86\x4a\xb2\x76\xaa\x2c\xc2\xdb\xf6\x23\x83\xbb\x66\x03\x0e\xbe\x94\x35\x41\x74\xcc\xec\x2d\x2a\x90\x75\x78\x55\x64\x44\x50\x7c\xbf\x84\x88\xbb\x23\xc6\x24\x23\xa3\xa9\x8d\xa7\xcc\x96\x8f\x59\x9d\x3d\xc8\x4d\xca\x3a\xfa\xd7\xf1\x4e\xc3\x06\xe1\xdb\x53\x41\x43\x21\x6a\xa2\x2a\xd1\x80\x74\xc7\x19\x57\x08\x05\xea\x46\xbc\x86\xb7\x1a\x8f\xf5\x8e\x41\xe7\x3c\xb2\x9a\xd5\x75\x0f\xcf\xc9\xa1\xc5\x42\x92\xb6\x4b\x47\xec\x95\x38\xf5\x38\x16\xe3\x6e\xd0\xd0\xc1\xae\x5e\xad\x06\xd4\x77\xaa\x97\x5e\xce\xba\xf6\x2d\x90\x23\xb7\x7e\x50\xe7\xb6\xd4\xab\xda\xa4\x85\xea\x34\xec\x76\x6b\xeb\x1d\x9b\xa0\x3c\x9c\x06\x71\x86\xe2\xe3\x82\x66\xc6\xe2\x53\x1e\x97\x48\x02\x14\x63\x8a\x2b\xb3\x14\x31\xac\x20\x86\x79\x71\x55\xfc\x77\x5b\x3a\xad\x8d\x5a\x0b\x90\x4c\x38\x1e\xdd\x0c\x6b\xc2\x3c\x66\xa1\x90\x49\x55\xed\x45\x0a\x9c\xbd\x16\x45\x9c\x32\xf5\xca\x35\x4b\xbc\x2d\xa7\xb1\xa4\xd8\x14\xf1\xb8\x71\x0a\xad\xb2\xcc\xc4\xf3\x97\x75\x8b\x7e\x9d\x91\xf3\xa9\x1e\x58\x25\xab\x86\x82\xff\x5e\x41\x70\x2e\x07\x84\x1a\xc7\x69\x8c\x3d\xa9\xf5\x58\xed\xd0\x1f\x86\xce\x2c\x50\x6b\xf4\xc2\x14\x9a\xc9\xc1\x95\xa5\x9c\x7d\xd7\xd4\xec\xf9\x3c\x90\xb4\x42\x3b\x43\x50\x58\x8d\x41\x67\x2c\xed\xc8\x51\x0a\x7a\xd5\x3b\x4b\x7e\xdc\xaf\x23\xe4\x3e\x05\x66\x9d\x27\xa1\xfe\x97\xb7\x87\x30\xd3\xfc\x06\x0b\xd4\xed\xd9\x87\x2c\xff\xb9\x62\x85\x35\x1b\xef\x14\x8e\xf7\x83\xab\x39\x21\x16\xbd\x7b\x90\x7b\xad"}, -{{0xc7,0x18,0x82,0x3f,0x43,0xdb,0x22,0x17,0xc6,0x6a,0xb2,0x89,0x97,0x04,0x16,0x5d,0x20,0x85,0x73,0xde,0x60,0xf3,0x3b,0xc0,0xb9,0x33,0x8d,0x88,0x0f,0x19,0x3f,0xb5,},{0x29,0x40,0xb8,0x79,0xb6,0x3f,0x2c,0xb1,0xf6,0xe3,0xef,0x9c,0x9d,0x33,0x3b,0xa9,0x17,0x70,0xfe,0x18,0xcc,0x5a,0x34,0x7f,0xdf,0x12,0xb0,0xef,0xc5,0xca,0x2e,0xc9,},{0x4c,0x9c,0xdb,0x1a,0xd4,0x65,0x09,0x56,0x0d,0x87,0x1d,0x30,0x89,0xaf,0xb8,0x73,0x46,0x48,0x20,0x1b,0x10,0xac,0xc9,0x53,0xe8,0xb6,0x1f,0x2c,0xce,0x2d,0xba,0xe0,0xfb,0x9b,0x86,0x8a,0xc9,0x57,0x43,0x2b,0x72,0x22,0xdb,0xf7,0xe4,0xcf,0x0b,0xc7,0x53,0x09,0xbe,0xa3,0x60,0xb2,0x63,0xab,0xbd,0xe1,0x88,0x53,0x2d,0xda,0x25,0x04,},"\x05\x0e\x68\x77\xf6\x5e\xc7\x26\xee\xc7\x01\x86\x3f\xab\x14\x0b\x99\x4a\xa1\xe9\x2a\x48\x7d\xb1\xa1\x87\x01\x31\x20\x57\xdb\x44\xbf\xde\x70\x91\x1e\xc2\x6e\xaa\x28\x63\x2d\x03\x79\x4d\x54\x5d\xfc\xb2\xae\xd4\x34\x0c\xab\x7d\x09\x25\x95\xcd\x59\xed\x23\x99\x40\x43\xf5\x0b\xa6\x96\xe9\x80\x2b\xd6\x49\x90\x12\x13\x97\x28\x64\x57\xae\x69\xd7\x6c\xb8\xe3\x4d\x7c\x1a\xb2\x45\xcb\x07\xb1\xb4\x08\xf2\xbb\xbf\xdf\x33\xa1\xbd\xd5\x59\x63\x67\x02\xc9\x18\xf9\x82\xc2\xac\x02\x21\xf7\xf9\x4d\xb9\x1e\xde\xfc\xe2\x81\x18\x25\x9f\x89\xd9\x94\xda\xd5\xbb\x01\x3c\x67\x8c\x1c\x33\x8b\x65\x39\x6b\x15\xe8\x89\x9c\x16\x99\x21\xf2\x78\x85\x9c\xe0\xc8\x56\xd8\x89\xb8\xc6\x34\x18\xeb\xc5\x73\xd2\xd6\x25\xd5\xb5\x93\x88\x39\xf2\xb1\x69\xb6\x91\x6d\x8e\x40\xdd\xe7\x0d\x3b\x72\x88\x7a\xd2\x47\x8e\xf6\xfb\x12\x84\xfa\x0e\x4f\xc5\x24\xe3\xc6\xfa\x1d\xd2\x2b\xa6\xb8\x1d\xef\x82\x79\xf3\x82\xbc\xb4\x50\x48\x85\x1b\x17\xcd\x65\x9d\x59\x40\x9f\x57\x1f\xa8\xa9\x20\xa2\x09\x34\xd9\xdb\xe1\x02\x2d\x63\x58\x40\x96\x54\x00\x24\x0f\x87\x0a\xce\xff\xd5\xdb\x7c\x7d\xf0\x8a\xf8\x9e\x47\xe1\xb9\xe2\x0b\xb9\x9f\x96\xab\x07\x3e\xdf\x53\x69\x4c\x74\x82\x89\x0e\x36\x31\x34\x02\x17\xe6\x87\xab\x27\xc9\x84\xb6\x08\x25\x16\x94\x57\xd4\x35\xa5\x40\x9a\xd8\xe4\x2d\xa0\xaa\x63\xe2\x0c\x2b\xc6\x7b\xd8\xb9\xa2\x67\xf3\x96\x73\xa7\x7f\x7f\x31\x36\xdc\x5c\xb2\xd2\x49\x48\xdb\xe7\xbc\xd7\x12\x93\x18\xc6\x8c\x6f\xe9\x5d\xd4\xdd\x4f\xe9\x42\x28\x68\x31\xea\x53\x35\x2f\xbb\x25\x2a\x12\x88\xbc\xd8\x38\x92\x13\x56\x78\x5d\x07\x21\x34\xcb\x82\x0f\x62\x79\xcc\x71\x46\x1f\x43\x1b\xe9\xd3\x01\x47\x24\x32\x1c\x92\xfd\xc5\x76\x32\x01\x37\x70\x5c\xff\xb2\xc2\x36\x64\xb7\x05\xe9\xbe\x60\xae\x1a\x19\x0f\x3e\x34\x84\xf7\x00\x58\xe7\x02\x40\x7b\x05\x6d\x7f\xe5\xd3\x1c\xee\x9c\x2a\x6a\xc6\xea\xda\x35\x16\xab\xc5\x51\x72\x56\xdf\x12\x43\x78\x0a\x03\xbb\x00\xba\x00\xce\x24\x80\x76\xee\xca\x6f\xee\x91\xd5\xef\x9e\xb9\x07\xb8\x01\xaf\x09\x7f\x3e\x9e\xb2\x56\xbd\xcd\xe8\x1e\xfe\x4b\xaf\x81\x89\xb0\x39\x9e\x36\xf1\xea\xa3\xab\x62\x66\x17\xcf\x3b\x47\xdd\x89\xca\xf6\x9c\x64\xc5\xb8\xf6\x8b\xd9\x17\xfe\x03\xe4\x66\x85\x38\x46\x0a\x1b\xe8\x8d\x9a\x84\x6c\xef\x39\x93\x46\x27\xd4\x74\x73\x4f"}, -{{0x25,0x43,0xd1,0x66,0xc9,0xf5,0xf7,0x42,0x7f,0xf3,0x03,0x4f,0xfa,0x81,0x03,0xcb,0x11,0x7b,0xf4,0x72,0x33,0x1a,0x73,0xd9,0xa2,0xf1,0xbc,0x0a,0x02,0xa6,0xff,0x1b,},{0x42,0x67,0x8c,0xf3,0x85,0x70,0x21,0xaa,0x55,0x67,0x70,0x6d,0xb0,0x31,0xe7,0x92,0x71,0x5c,0xca,0xf8,0xab,0xb0,0x2a,0x04,0x2b,0xad,0x17,0xdb,0x3d,0x5f,0xa1,0x03,},{0x20,0xea,0x93,0x68,0xa2,0xcc,0xd0,0x8b,0xf9,0xcb,0xf4,0x8d,0x4a,0x2f,0x7d,0x03,0xf0,0xdb,0x08,0xa5,0x4b,0x87,0x67,0x9c,0xda,0x03,0xe2,0x96,0xaf,0x9e,0xf3,0x78,0xbe,0x9b,0x8f,0x04,0xb4,0x06,0x5b,0x00,0x9d,0xa6,0xdb,0x01,0x6f,0x3d,0xf9,0xdb,0x64,0x82,0x58,0x73,0xe2,0xfb,0x4d,0xe3,0x04,0x49,0x91,0x5c,0xd7,0x3c,0x46,0x09,},"\x74\x6d\x7a\xbf\x0b\xfb\x26\x62\xc2\x5a\xb5\xc5\xe4\x61\x2c\x30\x6f\x16\xd1\x3e\x44\xd0\xdb\x39\x4a\x00\x15\x67\x6c\xe6\x09\x78\x4f\x03\x23\xda\x1d\xfa\x94\xd2\xb2\xf1\xf6\xe0\x24\x44\xa9\x36\xd0\x19\xb1\x43\x02\x1f\x73\xc7\x9d\xf9\x30\x9e\x7b\xdf\xf3\x9d\xae\xec\x4c\xac\xa0\x0c\xba\x4e\xf3\x1c\x83\x10\xc1\xa0\x8e\xf4\xb3\x6f\x81\xc3\x77\x84\x6b\x5b\x90\xac\xd4\x11\xaa\x67\x1e\xd7\xaf\x27\x8a\x24\x22\x9b\x78\x93\xc1\xb4\x15\xd7\x98\x88\xd7\x63\x7f\x5c\xb5\xc9\xc6\xc6\x31\xae\x5f\xfa\x29\xf1\x34\x0e\x44\x40\x96\xab\x53\x36\x17\xfd\xcb\x80\xff\x81\xda\x0a\x7c\x6c\x14\x2e\xe0\xfe\x5e\xa8\x2f\x68\xcc\x3e\xa3\x8b\x56\xf2\x72\xb0\xd8\x0f\xd5\xf4\xf5\x5c\xa9\x34\x8c\x16\x18\x81\x43\x58\x13\xc3\xfa\x9f\xff\x66\xa2\xee\x6d\x5b\xd3\xed\xba\x0d\x2f\x9a\xa7\x4b\x1c\x44\xbf\xd0\xe6\x46\x78\xd3\x71\x51\x24\x96\x3a\xc5\x75\xff\xb0\x9e\xe1\x64\x37\xda\x48\x4b\x3b\xa5\x8e\x5a\xeb\x8e\xd8\xc5\xc0\xf4\x7b\x59\x90\x8f\xe5\x80\xf3\x7e\xc1\xde\x26\x6b\x29\x5d\x6b\xe8\x5e\x62\x35\x8e\x9b\xbd\xc7\x89\x64\xfb\x83\x7e\xea\x29\xfd\xb7\xde\x86\xcc\x56\xf4\x8b\xd9\xa3\xe6\xe2\xbe\x51\xd8\xa1\xdc\xff\x3c\xa4\xd5\x6e\xa9\x34\xc6\x82\x77\x2b\xca\xfb\x51\x49\x7b\xe5\xd0\xf2\xa2\x3d\xd4\x97\x0c\x02\xc4\x4c\x09\xad\x89\x7b\x42\x41\xac\xd7\xd6\xab\x12\xd8\xf0\x0c\x9a\xad\xc3\x34\xb4\x31\xfe\xc5\xbb\x69\xa2\x85\xb7\x55\x0a\x63\x9e\xce\x96\x95\x26\x82\xb7\x33\x4b\x68\xc6\x51\x52\xe8\x93\xb1\xc8\x10\x0c\x69\x4d\x8c\x5c\xfe\x26\xac\x03\xc1\xf3\x91\x4e\x65\xc8\x4f\x0e\x77\x72\x90\xc7\x6f\x6a\xcc\xe3\x40\xbf\xf6\x6d\xa7\x22\x0f\x73\x17\x5e\x94\xaf\x52\xf9\xf1\x9e\x61\xf8\x0d\xc1\xf3\x57\x16\xb3\xf4\x8d\xfa\x50\x25\xc9\xeb\xef\x73\x82\xe0\x55\x83\x0f\x5b\xbf\x15\xc6\xf6\xa9\x50\x32\x90\x9c\x89\x2c\x0f\x89\xc8\xc1\x5f\xc3\xea\x40\xa2\x0e\xe1\xa4\x52\x9b\x52\x19\x51\xdf\x44\xd9\xd7\x9d\x74\xe0\xc4\xc2\xe0\xfe\xd8\x49\xb8\x78\x52\x06\xdb\xe6\x2b\xfa\x2c\xa2\x10\x87\xa9\x12\xe9\xb1\x84\x55\x16\x59\xcd\x8a\x58\x7e\x95\xb0\x43\x17\x19\x25\x96\xbb\x0b\x7f\xc9\xf7\xbb\xb6\xee\x04\x9c\x8b\x02\xfd\xd7\x58\xb4\xe7\x98\x82\x07\x3b\x71\xea\xab\x18\xaa\x29\x37\x01\xc1\x7d\x55\xf9\xec\x46\xc5\x2d\xe1\xe8\x86\xb6\x75\x0f\xb0\xfb\xcd\x64\xf4\x56\x8a\x21\x0a\xe4\x51\xe9"}, -{{0x85,0xe0,0xa8,0x0f,0x3b,0x30,0xc2,0x01,0x99,0xd9,0xc1,0xec,0x66,0x2e,0x39,0x2f,0xdf,0x15,0x46,0x37,0x73,0x43,0xf1,0x24,0x71,0xdb,0x2a,0x03,0x10,0xa7,0x05,0xbd,},{0x54,0x0a,0x3a,0x1d,0x83,0x67,0x2e,0x49,0x50,0x34,0xcf,0xf4,0x08,0xe1,0xfb,0xe8,0x2e,0x53,0x8f,0x09,0x17,0xe8,0xa1,0xc7,0xd1,0x7a,0xab,0x58,0xe0,0x43,0xd3,0xc6,},{0x18,0x5e,0xf2,0x24,0x6a,0xba,0x2b,0x1a,0x56,0x80,0x32,0xc7,0xdf,0x93,0xc6,0x67,0x79,0x9b,0x8a,0x52,0x1a,0x6f,0x97,0x32,0x1e,0xad,0x58,0x66,0xb4,0xcb,0x9c,0x65,0xb6,0x4a,0x1c,0x40,0xb9,0xb6,0xa9,0x10,0xe7,0x42,0xdc,0x32,0xa7,0xe6,0x6d,0x11,0xea,0x45,0xdb,0xea,0xac,0xae,0x9f,0x09,0x51,0x1b,0x81,0x01,0xf8,0xaf,0x0c,0x0c,},"\xd2\x80\x2f\x15\x96\xf8\x38\x3b\x64\xed\xbd\xc5\x94\x06\x0b\xff\x0e\x70\x13\xd5\xb7\xc8\x5d\x83\x0f\xae\x11\xae\xb3\x4d\xd5\x94\x95\x9d\xa6\x24\xe0\x44\x47\x4c\x54\x09\xc0\x05\x96\x73\xbd\xc6\x1a\x67\x1e\xf5\xb0\xb8\xa2\x6f\x30\x10\x0b\x3b\x73\x96\x8d\x8e\x4d\x83\xa7\x2f\x25\xb5\x13\x44\x8d\x2f\x6b\x6a\x44\x75\xfd\xf8\x9e\x31\xca\x92\x68\xa3\x07\x05\xaf\x3f\x64\x9e\x3f\xe0\x1d\xde\x0c\xf4\xb2\x9e\xc2\xda\x54\x36\x44\x4a\xf0\x91\xd6\x27\x30\xac\xd4\xca\xb6\x08\xf0\xdf\x26\xf0\x88\xc6\xb9\xb9\x67\x37\x94\xf0\x74\x7d\xab\x2c\xe1\x90\xf9\x05\x92\x00\x9f\xdc\xe5\x46\x4b\x36\x61\xb7\xe8\x62\x0b\xad\x65\x50\x9a\x6c\x75\x2b\x72\x7a\x8d\xc8\xd3\xef\xa5\x84\xfd\xe0\x27\x2c\x45\x1d\x65\xa9\x3b\xec\xe4\xf5\x9d\x87\xdc\x6f\xbe\xb4\x51\x40\x1e\x3e\x2e\x00\x3c\x6a\xca\x7b\x3d\x3f\x92\x71\x91\x50\xc6\x77\x8f\x01\x5a\xff\x2a\x59\xbf\xbf\x2e\x91\xb2\x1b\x0a\xd6\x87\x75\x36\xeb\x54\x56\x70\x59\xf5\x87\xf5\x4d\x4e\x2a\x6f\xe1\xfd\xcd\xd6\xa7\xfd\xcb\x85\x15\x57\x5b\xcc\x37\x05\xd7\x78\x59\x35\x2f\xa0\xb0\x44\x16\x6e\x3c\x31\x88\x46\xa5\xdf\x33\x56\x30\x03\xcb\x20\xbc\x94\x2d\x30\x39\x10\x93\xe8\xd5\x83\xe8\xe6\x4d\xec\x57\x0e\xe1\xc4\x13\x87\x62\xf6\x48\x38\x98\xd3\x2e\x20\x32\xbd\xe9\xbb\xe0\x7e\xc2\xc3\xeb\x47\xd9\x68\x76\xf0\xfc\x0f\x02\x4d\x75\x3c\xeb\x34\xff\x84\x80\xb4\xcf\x57\x62\x30\xbb\x82\x63\xdd\x80\xee\xac\x66\x2e\xba\x31\xd8\xa6\x1f\x30\x9e\x17\x5f\x4c\x01\x43\xe2\x8a\x85\x2b\x1c\x30\x61\xce\x78\xef\xbd\x16\xa2\x87\x3d\xd2\x81\x98\xa4\x6e\xc0\xa8\x00\xb3\x0d\xc8\xa9\x3b\x8d\xbb\x81\xa7\x30\xde\x45\x0b\x86\x4d\xea\x76\x80\xe5\x09\xd8\x00\xe8\x23\x29\xc2\x61\xb0\x7e\x72\xaa\x80\xee\x16\xec\x37\x5d\xdb\xbb\x6f\xe3\xd8\xd4\x7b\x0e\x3c\x5a\x9f\x23\xc4\xd2\x0b\x72\x4c\x1d\xf5\x98\x35\xd8\x30\xdd\x22\xd1\x04\x03\xd8\xf1\x5c\x10\x2c\x4b\x37\x69\xc4\x16\x66\xc3\xab\x8c\x7e\x80\xb9\x40\xd0\xbb\xb5\x86\x52\xd1\x0a\x3f\xfe\x8d\x44\xdf\x10\x12\xa3\xdd\xc4\xe1\xc5\x18\xd4\x90\x19\xf7\xc5\xd3\xd9\xf9\x5e\xd9\x3a\x31\x97\x46\xd1\xe5\x43\xff\xa6\x9e\xdb\x49\xbb\x34\x39\xf8\xa3\x25\xac\x6a\x0c\xb4\xed\xd6\x5b\xa6\x00\x80\xa0\x44\x7c\x67\x4f\xaa\x72\xd8\xae\xbd\xb5\xd2\x54\x4f\x2f\x2d\x84\x7c\x72\xc2\xdf\xa6\x05\x7a\x69\x0a\xdc\x5c\x44\x1a"}, -{{0x82,0xa2,0xc6,0x49,0x3f,0x11,0xba,0x80,0xe4,0xb8,0xb3,0xb4,0x38,0x41,0xbe,0x97,0x0e,0x2a,0x10,0xa9,0x4d,0x22,0x49,0xd8,0xac,0x6f,0x54,0x14,0xcf,0x5a,0x3c,0xb5,},{0x4c,0x2e,0xe0,0x1c,0xde,0xa0,0x7d,0xb3,0x63,0x5f,0x5d,0x4c,0x10,0x82,0xb9,0x2f,0x29,0x8d,0xeb,0x17,0xd0,0xf9,0x05,0xdf,0x71,0xb6,0x6f,0xb2,0x27,0x4e,0xae,0x99,},{0x68,0xa9,0x1d,0x4f,0x8d,0x24,0x1c,0x1d,0xef,0xbd,0x5c,0xa9,0xe9,0xe1,0xed,0x82,0x74,0x41,0x95,0x06,0x75,0x1c,0x96,0x79,0x47,0xb1,0x0d,0x50,0x11,0x8b,0xbf,0xab,0xc7,0x65,0xff,0xd7,0xb3,0x1a,0x01,0x67,0xc4,0xfd,0x8b,0x11,0x75,0x33,0x24,0x12,0xdf,0x19,0xd8,0xaa,0x1a,0x90,0x95,0x90,0x86,0x13,0x20,0x92,0x3d,0xbc,0xb2,0x04,},"\x09\x85\x4d\x13\x68\x49\x50\x41\x9e\x0b\xb1\x64\x64\xe0\x99\x88\x90\x5c\x02\x17\x18\x3a\xa1\xe4\x8a\xdb\x14\x7b\xfc\xc2\xeb\x57\xc2\x30\x0b\x0d\xfc\x39\xd4\x89\x66\x55\xa5\x7a\xe2\x04\x15\x40\x8b\xb5\xf2\xc2\x38\x01\x39\x55\xf0\xa4\xfc\x78\x2e\x0c\x99\x3f\xe4\x2c\xb0\x8c\xd8\xcf\x41\x5c\xcb\xd6\xcf\x1c\xee\x2e\x80\x97\xf0\x4e\x8f\x09\xae\x5d\xa5\xf4\x15\xb1\x6c\x2c\xb3\x0c\xb2\xab\x66\x52\xba\x50\xeb\xbc\xae\x4a\x59\xe3\x1f\xe1\x1e\x7e\xf3\x69\x9c\xa9\x0a\xaf\xa5\x86\xbb\x24\x2c\x89\xcd\x2e\x33\x2b\x2b\xfa\x2f\x81\x42\xac\xca\xf4\x36\xf8\x9b\x64\x53\xbb\x48\x05\xa1\xe7\xf3\xab\x62\x70\xf0\xda\xf8\x93\x89\xe7\x17\xd1\xb7\x01\x75\xec\x57\x07\xc8\xf5\x12\xc4\x0a\xb9\x24\xc4\x57\xe9\xf0\x91\x47\x91\x75\x0d\xc2\x92\xbb\x27\xd6\xf6\x3b\xa8\xcc\xf5\x4b\x90\xd3\xeb\xa7\xf1\x9e\xb3\x00\xd9\xeb\x8f\x3b\x72\x03\x2b\xa9\x30\x37\xf5\x52\xb4\x09\xb5\x80\xa5\xf6\x51\x16\xfa\xff\xe0\xfd\xfd\xc6\xdb\x38\x81\x38\x6c\x3c\xbc\x16\xb6\x7e\xb2\x57\x63\xd7\xae\x3a\xac\x0b\x85\xaa\x1e\x9a\xa2\x2e\x49\x59\x60\x9d\x43\x81\xe4\xb6\xd7\x15\x9f\xf3\xe3\xb2\xd3\x7b\x64\x0f\x88\xcf\xbe\x4f\x8a\x77\xf8\x01\x64\x57\x22\x8b\xa6\xd3\xaf\x5c\x4e\x33\x12\x5d\x48\xbc\xfc\xf3\x67\x8c\x16\x3b\x69\x8e\x52\xe8\x56\x17\xab\x1a\x75\xff\x20\xc6\x90\xab\x07\x15\x5e\xe7\x57\x59\x85\x78\x07\x2d\x4a\x09\xdf\xc6\xc6\xc0\x94\xec\x04\x85\x67\xd5\x13\xce\x2b\x18\x34\xe1\x63\xdf\x15\x45\x31\x9d\x80\x61\xe0\xe5\x7f\x58\xef\x04\x1b\x7b\xff\xc4\x96\x6a\xc1\x66\x03\x31\xb9\x7a\xbb\xc9\x7b\xe2\x1a\xe2\xbc\x58\xc6\xc3\x27\x4a\x8a\xda\xd5\xfd\x2c\x3b\xc1\x6b\x92\xe1\xf8\xde\x87\x7b\x6a\x26\xf0\xc6\xab\x71\x62\xe8\xaa\xb9\x3a\xf8\xd8\x59\x18\xc1\x3d\x3e\x23\x5a\x27\x37\x48\xc6\x2f\x0d\x22\xcb\x1c\x93\xe1\x34\xa4\x95\xb1\xb5\xef\x8f\x1a\x11\x34\x51\x2d\x53\xb7\xa2\x11\x26\x31\x77\xf7\xa6\x0b\xdf\x47\x46\x91\xf2\x24\xa3\xb5\xba\xc4\x00\x6d\xb3\x45\xca\x67\x25\xf5\xee\x70\x3e\xca\x0d\xea\x10\xd7\x12\x67\x6f\x63\xef\x3e\x53\x7e\x63\xab\xd2\x60\x8c\xb4\xfb\xe2\x00\xe1\x5f\x18\x20\x91\x53\x49\x60\x72\x90\x80\x44\xc9\x5a\x4e\x9c\x53\x56\xaa\xe8\xed\x5f\x09\x59\xea\xc0\x91\xe2\x27\xa0\xb8\x1f\x58\x03\x27\x6b\x3b\x3b\xf4\xb6\x86\x5a\x55\xfc\x67\x82\xf6\x2e\xa6\xd6\x39\x90\xf9\xbe\xfe\x01"}, -{{0xe5,0x5b,0x34,0x3a,0x0f,0xa1,0xfb,0x74,0x71,0x89,0xcb,0x00,0xdb,0xc3,0xa6,0xaa,0x2d,0xcf,0x5b,0x86,0xe5,0x7d,0x76,0x93,0xf3,0x07,0x42,0x03,0x89,0x76,0x11,0x53,},{0x23,0xa1,0x44,0x60,0xea,0x98,0x3c,0xf9,0x97,0xc7,0x82,0xeb,0x45,0x82,0xab,0x3c,0x8a,0xa6,0xdd,0xe5,0x33,0x25,0xb9,0x77,0xb7,0x8e,0x33,0xd2,0xdc,0x5f,0x27,0xaa,},{0x07,0x26,0x6c,0x18,0x65,0x0e,0xcf,0x06,0x32,0xe2,0x25,0x62,0x4e,0xc4,0xc9,0x7f,0xc3,0x87,0xdc,0x37,0x46,0x87,0xa6,0x19,0x56,0xdc,0xcc,0xe7,0x28,0x94,0xee,0x13,0x8a,0xab,0xc8,0x0c,0xfc,0x90,0xc9,0xee,0xa6,0xdd,0x4c,0x59,0xaf,0x45,0x02,0xee,0x29,0x63,0x5a,0x92,0x88,0x07,0x86,0x67,0x8b,0x14,0xa3,0x93,0x1a,0x69,0xf9,0x07,},"\x36\x28\x9b\x5e\xaf\xf2\xa8\x5a\x7c\x6d\x57\x5b\xd1\x5e\xa5\x94\xb2\xfd\x85\x10\x87\x4a\x46\x9b\x52\x10\x91\x63\x69\x6d\x85\xb6\x8c\x5b\x21\x1d\x29\x64\xef\xdc\x66\xe6\x25\xab\xe8\xaa\xfe\x4c\xd9\x22\x0c\xdb\x34\x11\x07\xff\xa8\x27\x6e\xd4\xb3\x70\xfe\x37\x6c\x14\x82\x68\x71\x67\xdb\xc8\xf7\xb2\x05\xa3\xf3\x30\x1a\x16\x64\xd9\x07\x28\x77\xd9\xf9\x8b\x8f\x69\x83\x13\x01\xdf\x99\x94\x71\x7f\xc8\x89\x69\x24\x23\x91\xd9\xb0\x51\x7d\x6e\xfb\x27\x17\x01\xea\xb3\xf4\xa9\xb1\x20\x42\x13\xe8\xcd\x13\xf9\xd0\x99\x04\x8b\x82\x07\x56\x2f\x2e\x4e\xbc\x65\x3c\xc6\x5e\x9d\x55\x12\xd6\x5b\x41\x02\x2c\x79\xb4\xeb\x37\x29\x87\x69\xae\xaa\x6e\xfe\xd6\x9e\x9a\x8c\xb4\x45\xc7\x01\x22\x74\xde\x62\xf5\x09\xf4\xe4\x81\x4a\xdc\xbf\x44\x53\xb4\xfa\xb8\x5d\x7c\x8f\xd8\x45\xe0\x08\x30\xef\x5b\x7b\x1e\x63\xc6\x76\x13\x98\x4c\xae\xfe\x91\x5a\x54\x8e\x18\xe5\x05\x62\x2c\xb2\xb3\x92\x99\xf4\x27\xf4\xd8\x39\x83\xba\x2a\xa0\x0d\x53\xbe\xe1\xf5\x9a\xec\x83\x18\xc5\xea\x34\x5d\x29\x42\x52\x36\x97\x92\x76\x2a\xdd\x3e\x56\xfc\xfa\x6e\x77\x97\xf0\x28\xc7\x99\x47\x90\x45\xed\xb2\xe2\x05\xeb\x6d\xd6\xca\x04\xee\xe5\x6f\x94\x96\xd2\xbf\x26\x09\x93\x57\xc9\x73\x83\x5b\x99\x36\x02\x49\x11\xe4\x65\x5d\x3e\x22\xc8\x11\xc8\xd4\xdb\xd1\xb0\x4f\x78\x97\x3f\x07\x75\x23\xa3\x89\xb6\xf2\x8f\x6f\x54\x21\x61\x42\xcb\x93\xe3\x3d\x72\xb4\xa5\x05\x2d\x27\xe4\x91\x1e\x41\xe6\xce\xc7\xbe\xbe\x1b\x0a\x51\x13\xe6\xb7\x0b\x47\x9d\x2a\xbe\xed\xf6\x9b\x75\x64\xe5\xa5\x73\xb3\x52\xd1\x6c\xec\x89\x07\x01\xbb\x38\x3d\x3f\x66\x56\xed\xa0\x89\x2f\x8c\xcc\x70\x94\x0f\x62\xdb\xe5\x28\xa6\x5e\x31\xac\x53\x88\x26\xc1\x38\xac\x66\x52\x4e\x33\x16\x37\xba\x2d\x37\x73\x03\x58\xe6\xc7\x32\xcf\xf8\xfe\xe9\x40\xaf\xd2\x2c\x39\xae\x38\x1e\x5d\x88\x26\x73\x9b\x23\xfd\xc1\xb8\x0a\xea\x5a\x62\xa2\xcf\x0f\xf1\x52\x5e\x44\x6c\xf3\x10\x46\x19\x50\x51\xd5\x85\x03\xee\xd1\xbe\xfd\x79\x3e\xea\xe1\xd5\xd1\xb6\x2a\x5c\x98\x45\x15\x7a\x09\x5c\xdc\x08\xa1\xd7\x7b\xa4\x7e\x84\xa5\xa7\x39\x98\x0f\x0f\x5b\xe7\xaa\xec\x9a\x21\x5b\x20\x4b\x4b\xb7\xcb\x1b\x38\x6d\xed\x58\xd7\xaa\xf7\x28\x53\x41\x90\x7c\x63\x33\x6e\xe3\xe6\xef\x07\x7a\xd1\x11\xb9\x74\xe7\x50\x4b\xd9\x89\xf5\x66\xfd\xa1\xb1\xb5\x9a\xba\xa9\x1c\x78\xbb\x40"}, -{{0x39,0x73,0x03,0x8f,0xa2,0xef,0x6a,0x27,0x8d,0x3c,0x1c,0xff,0x9a,0x22,0x56,0x69,0xe4,0x65,0xa6,0x9d,0x07,0x50,0x50,0x3d,0xe7,0x48,0xc0,0x02,0xdb,0xf9,0x27,0x8a,},{0xc7,0x5e,0x77,0xc7,0x81,0x49,0xd9,0xd2,0xdb,0xc2,0x63,0xdd,0xf8,0xac,0x4d,0x65,0x4d,0x1f,0xf4,0x55,0xcb,0x18,0x97,0xe1,0xc3,0xce,0x31,0xb9,0x4c,0xfe,0x32,0x10,},{0xfc,0x0c,0x54,0x53,0x83,0x9e,0xa9,0x92,0x96,0xff,0xfa,0x50,0x1d,0x58,0x36,0x66,0x28,0xdf,0x89,0xf6,0x16,0x76,0x69,0x42,0xd5,0x04,0x0a,0x05,0x60,0x56,0xda,0xb1,0x8b,0x44,0x05,0xc0,0x4a,0xbf,0x90,0x59,0xc3,0x08,0x68,0xd7,0x9c,0x93,0x6c,0xcc,0xc8,0x4c,0x4f,0xbd,0x6f,0xd3,0x0b,0x60,0xf8,0xbc,0xbd,0x7a,0x66,0x40,0x42,0x02,},"\x33\x92\xe0\x2f\x3c\x84\x66\x1e\xaf\x81\xa5\xff\x04\x35\x7f\x21\x2e\x92\x36\x1c\x5c\x22\x07\x39\xd9\x6b\x4d\x3d\x9c\x22\xd1\x8d\xf4\x8b\xe6\xb5\x51\x26\xf5\x81\x60\x1f\xfe\x0d\xa6\x3f\x38\xe1\x9c\xbb\x12\x72\x6c\xa0\xa6\xaa\x32\x55\x67\xa0\x03\xa7\x84\x9d\x06\x78\x39\x92\xeb\x9e\xb9\x28\x53\x29\x7d\x72\x28\xdb\xa9\x80\xb2\x50\xbb\x11\x0f\x63\xd0\xb8\x46\x70\xe5\xec\xb3\x19\xcb\xfd\x61\x27\x8f\x1f\x4c\xab\xf1\xfc\xb3\xf7\x01\xf1\x2f\x6e\xf8\xd3\xcc\x42\x82\xfc\xbe\x58\x9e\xb5\x65\x95\x03\xa2\xdd\xd8\xbb\xa3\x8e\x5e\xff\x09\x2d\xfa\xf5\x39\xfd\x80\x4f\x21\xf7\x3a\x90\xad\xf5\x69\xa0\x0b\xf9\xd2\x5a\x9a\xd3\xa6\x33\x09\xcc\x60\x93\x14\x24\x71\xa4\x78\xf0\xb8\x99\x22\x86\xde\x02\x3c\x68\xef\xd4\x99\x87\xec\x27\x0b\xd9\x46\xf6\xdb\x48\xf6\x84\xf1\xc2\xad\xee\xe2\x6d\x68\xdc\xe9\x5a\x55\xe4\xcb\x27\xbc\x60\x52\x30\x80\xdf\x6b\xa2\xb1\x99\x99\x6b\x1f\x1d\xa6\x92\x0d\x15\x59\xf7\x9b\xfd\xe9\xfa\x1a\x02\xde\xae\x14\x80\xc7\x6f\x94\x7f\x9d\x21\x3f\xc4\x3b\xb2\x88\x0a\x1b\x4d\x03\xbb\x14\xf5\xb0\x44\xa0\xfd\x83\xce\x04\x92\xf4\x9c\xa3\xaf\x25\x21\x1b\x86\xfa\xa5\x73\x5a\xd7\xfe\xaf\x31\xa1\xa7\x49\x1e\x70\x8b\x41\x82\x9d\x68\xe3\x24\x14\xf6\x83\x52\xb7\x1d\x1c\xd2\x3c\x8e\x12\xfb\x02\xda\x71\x14\x84\xf6\xef\x97\x52\x8a\x00\xd2\x4f\xcf\x91\xd4\xe0\x6e\x9b\xad\xae\x9a\x44\xdb\xdb\x3f\x77\x80\x41\x76\x8d\x86\x37\x04\xd7\x36\x81\x04\x00\xe7\xf2\x93\x1e\xfb\x85\xc8\x72\x4a\x59\x34\x26\xaa\x2a\xf1\xec\x5b\x66\x4f\x85\xc2\x25\x48\x96\xfd\xcf\x31\x6d\xb0\x92\x4e\x11\xaa\xe8\xd6\x83\xe9\xa0\x21\x92\x9d\x0a\x9d\x6f\xec\xb4\x59\x4b\x1b\x3f\xbc\x16\xb1\x76\xd2\x9d\x1e\xfb\x18\x19\xa4\xa4\x23\xfb\xe0\xca\x05\x59\xc5\x7e\x9e\x54\x49\xf1\x4b\xce\x91\x36\x0d\xaf\xda\x6a\x42\x7c\xe4\xa0\x99\x3d\xd0\x30\x82\xdd\xee\x06\x65\x33\xf6\xd3\xbd\xa5\x66\x0f\x42\xfd\x77\x57\x69\x0d\x67\x05\x98\xec\x70\x96\xf4\x75\xa0\x1a\x51\x99\x50\x34\x1a\x83\x1f\xc9\xa2\x81\xc0\x94\x7a\x86\x3f\x1f\x6e\x03\xbb\xa7\x74\xde\x77\xad\xc2\x3f\xbe\x52\x5c\xae\x6c\xcc\xe4\x7a\x0e\xc4\x97\x9e\x8b\xec\x86\xf3\x32\xfc\x6a\x57\x36\xe3\xb9\x8f\xb3\x32\xe9\xe8\x24\x4e\x68\xa1\x00\x45\x5e\x64\x99\xba\x8d\xba\xe9\x8b\x92\xba\x3d\x9c\x6b\x4f\xf9\x80\x34\x3e\x4c\x8e\xf4\xd5\xa4\xaa\xcf\x8b\x1a"}, -{{0xc7,0x1c,0xc1,0x0a,0xd2,0xd4,0x43,0xe0,0x25,0xad,0x06,0x25,0x68,0x6b,0x12,0x35,0x03,0xe5,0x90,0x19,0x3a,0x2b,0xc8,0xcc,0x57,0xa7,0xb9,0xb4,0x15,0x8d,0xe6,0xcb,},{0xfc,0x06,0xac,0xaa,0xb5,0x3a,0xd0,0x8e,0x97,0x62,0xdd,0x11,0xcd,0x21,0x22,0xb3,0x15,0x99,0xbd,0x25,0x98,0xce,0x6f,0x24,0x87,0x95,0xe7,0x32,0x21,0x9c,0x2f,0xc7,},{0x2e,0xb3,0x3b,0xc2,0xd5,0xde,0xb7,0xf3,0xa2,0xdc,0xc3,0x77,0xb0,0xc6,0xa8,0x62,0x13,0x4b,0xf3,0x19,0x1e,0xc4,0x0f,0xc1,0x28,0xac,0x28,0xab,0xf2,0x31,0x6e,0xf1,0x40,0x16,0x49,0xb8,0xf4,0xcf,0xa1,0xa9,0x36,0xde,0x79,0xb5,0x32,0xdc,0x04,0x3b,0x6d,0x36,0x02,0x4b,0x4c,0x37,0xbb,0xa2,0x92,0x90,0xac,0x9f,0x44,0x9b,0xa6,0x0d,},"\x2e\x08\x46\x53\x6d\xc6\xcc\xe1\x9c\xcf\x82\xdc\x2d\x0c\xd2\x1b\xd4\xe1\xca\x7b\xc3\x17\x06\x7a\xf8\xd9\x0e\xe4\x81\x8c\x85\x18\xbc\x3e\xf9\x60\xce\x11\x2a\x41\xd2\xb9\x97\x9a\x28\x2a\xe1\x3d\x70\x6a\x00\x5e\x00\x34\xf0\x6b\x39\xff\x4b\x0a\x5a\xfa\xed\x70\xb5\x61\xbc\xce\xb1\xbb\xd2\xec\x19\xf9\x74\x48\xea\xed\x4b\xe6\x20\xe3\x6a\x96\x2d\x87\x8c\x6f\x80\x17\x2b\x9f\xad\x43\xee\xd0\x7f\xf9\x3d\xb9\xb9\xca\x22\x62\xd5\xa3\xc2\x29\xc5\x4e\x30\xa4\x5e\x73\x66\x08\x92\xf0\x48\xe3\x63\xf3\x71\x44\xed\x19\x21\xf7\x29\x92\xb4\xd0\x15\x29\x87\x0c\xfe\x37\x3b\x7e\x7c\xbe\xda\xf9\x69\x26\x9f\xb7\x0a\xa7\x83\xd1\xe7\x44\x17\xc7\xba\xe0\xfe\x03\xd9\x51\xfd\xb8\xc7\x1c\x62\xe9\xbe\x7f\xdd\x5d\x23\x3e\x39\xf4\x6f\xed\x05\x7e\x49\xb6\xf3\x40\x68\x45\x91\x48\xda\x3d\x42\x41\x61\xad\x2c\x86\x95\x08\x60\x2e\x9c\x0b\xb3\x0b\xfb\x88\xac\xd5\xf4\xdf\xdf\xfd\x47\x35\x03\xcd\xfe\xda\xbc\x44\x42\xb7\x43\xbe\x07\x5e\x7c\x6f\x61\x0e\x64\xff\xc2\xe5\x31\x87\x74\x5c\xd7\x19\x65\x8f\xc6\xe6\x2a\x5b\xe5\x18\x43\x7c\x5b\xd6\xa4\xfe\xba\x94\xae\x3f\x44\xf2\xf2\x93\x08\xe8\x31\xfe\xef\xed\x67\x69\x09\xce\x5e\x80\xc8\x4c\xbd\xca\xc4\x7e\x47\xd2\x7c\x97\x12\xa0\x1f\x6b\xc5\xda\xed\xc0\x2e\x64\x14\x40\x7e\x91\x1c\x0a\x5a\x53\xe5\x32\x8a\x5a\x5f\xd9\xf0\x40\xaa\x7f\xb7\x0b\x79\xb3\x1c\xd1\xb6\xfd\x9b\xd5\x02\x90\x40\xbd\x22\xae\x22\x2f\xd2\xf6\x87\x0d\x07\xf4\x35\x32\x26\x39\xcf\x31\x93\xca\x57\x09\xb8\x82\xb0\x7a\x58\xf9\x52\xa9\x96\x3e\x56\x8f\x8c\x5a\x58\x4a\x6b\x9e\x27\x5c\x5c\x07\x95\x7a\x4d\x2c\xda\xa9\xf1\xeb\x44\x4e\xd1\x22\x4b\xac\x65\x63\xb2\xf9\x27\x3e\x80\x30\x1d\x44\xd5\x0a\xe3\x83\xb5\x97\x21\x3b\x00\xda\x5b\xf2\x7e\x5d\x1f\xe2\x40\xcc\x3b\xb6\x5a\xa5\x03\x0d\x65\x1b\x6b\x5b\x31\x76\x1d\x53\xce\x0c\x6d\x74\xa1\x5d\xad\x54\x79\xf3\x1c\x91\x5c\xcf\x44\x66\x59\x85\x3b\x89\xa5\x1a\x28\xee\x89\x76\x85\x35\x53\xfd\x2e\x02\xfe\x72\x43\x53\x8d\x00\xb4\xed\x07\xd8\xb8\xa8\x0b\x5c\x16\x5c\xd4\x63\x41\xff\xd8\x16\x3c\x55\x57\x02\x66\x3a\x4e\x6a\xb2\x95\x2b\x7e\x74\x43\xd0\xf6\xb1\x23\xb6\x94\x67\x21\xaa\x63\xe8\x7b\x11\x55\xec\xa8\xa6\xa1\xbc\x9f\xd2\x5c\x67\x62\xe5\x27\x42\xc8\x6b\xca\x1b\xa9\xd8\x37\x04\x15\x24\x4f\x0e\xdf\xdb\xe0\x93\x2b\x5c\xa0\x61\x15\x09\xc9"}, -{{0x0a,0x4f,0x5e,0x16,0x70,0xf1,0xe2,0x4b,0xfa,0x37,0xb7,0x3c,0x99,0x43,0x30,0xb3,0x6e,0x7d,0xaa,0xf9,0x30,0x16,0x1b,0x78,0xa4,0xa8,0x48,0x66,0xff,0x25,0xe3,0xd5,},{0x9d,0xcb,0xba,0x90,0x39,0x81,0x59,0x4c,0x7b,0x67,0x7e,0xa8,0x00,0x20,0x01,0xd6,0x64,0xcf,0xf7,0xce,0x8e,0x5c,0xfa,0xe5,0x88,0x40,0xcf,0x74,0xaf,0xf0,0xd3,0xa9,},{0xdc,0xf3,0x53,0xb2,0xb9,0x9a,0x4e,0xf4,0x5f,0x3f,0xdf,0x65,0x28,0x63,0x2e,0x8a,0xbd,0xc4,0x33,0x34,0x24,0x76,0xa8,0xc2,0xb3,0x79,0x00,0x40,0x4a,0x4e,0x33,0x3d,0x38,0x78,0x14,0x23,0x57,0x57,0xef,0x7a,0xd0,0x38,0x58,0xa0,0xf3,0x5d,0x46,0x15,0xe8,0xab,0xa4,0x84,0xfd,0x64,0xf1,0x11,0x2e,0xc1,0xb1,0xae,0xd2,0xcb,0x64,0x0e,},"\xf4\xb0\x5b\x3e\xfd\xcb\x1d\x5c\x07\xda\x95\x0c\x46\x56\x55\x28\x44\x0b\xb4\x88\x35\xee\x4c\x13\xf4\x3d\x7a\x16\x18\xde\x11\x9e\xbb\xb2\x59\xea\x74\x80\xa5\x04\x81\x74\xfa\xec\xc1\x05\x5b\x32\xdc\x01\xac\x71\x56\x34\x43\x21\xe8\xeb\xa6\x98\xf3\x02\xee\x16\x43\xb5\xf0\x4b\x8e\x7e\xcc\xa6\x3b\x91\x56\x1c\xe3\x51\x4a\xbe\x78\x51\xb6\xfb\x17\xfc\x94\x3b\xdc\x94\xda\x30\x8c\x8e\x47\x69\xfe\xc2\x0f\xad\xf4\xfa\x8e\x7f\x62\xb6\xff\xb5\xf1\x70\xd6\x44\xed\x29\x35\x5e\xbd\x22\xcb\x3a\xa1\x48\x6b\x1e\x36\x7c\x72\x9d\xd3\xf7\x9b\xcd\x40\xff\xd0\x8a\xf2\x8c\xeb\xc8\xd7\x76\xe1\xa4\x83\xe9\x11\xd7\x9b\xc6\x13\xe0\x9c\xc6\x21\xca\xde\xb0\x34\xdd\x6f\x72\x37\x47\x71\x98\x51\x27\xf7\xa3\xa1\xaa\x78\x6a\x52\x3a\xe6\xe3\x4e\xe4\x33\xdc\x30\xc3\x75\x98\x7c\xff\x50\xbd\xcb\xc9\x97\xfc\xd5\x1c\x94\x56\x7a\x67\xae\xfb\x6e\xf5\xed\xf9\xbd\xd6\x59\x64\xd4\x64\xbe\x9e\xbd\xfb\x88\xc0\xe2\x31\xb0\x7f\xf6\x40\x5c\x00\xf8\x25\x31\xe9\x61\xbf\xc5\xea\xd2\x66\xbc\xc0\x87\x18\x87\x8c\xaf\xb1\xd3\x75\x36\xf1\x83\xe4\x8b\xf3\x8d\x3f\x6b\xe9\x00\x25\x2d\x1f\xb4\x19\xe6\xa2\xac\x58\x96\x03\x9f\x63\xc3\x14\x01\xff\xf9\x32\xce\x98\x14\xb0\x85\xab\x20\x41\x69\x72\xa2\xb3\x51\xc8\x15\xa6\x2d\xe5\x09\x67\x46\x28\xb0\xd3\x56\x6f\xc9\xc2\xe0\xa9\x23\x7b\x93\xf9\xbb\xb2\xde\xed\xf0\x2b\xff\x83\xbf\x6d\x86\x8b\x63\x99\x32\x6d\x48\x09\xd0\x41\x9f\x31\xb2\xf3\xa4\x81\x28\x5b\x94\x07\x8b\x47\x06\x1c\xe9\x1d\xad\x58\x3d\xd5\xb1\x3b\xd0\x10\xfb\x30\xf2\x49\x5b\xb7\x04\x20\x18\x3a\x93\x01\x59\xe4\xdb\x19\x3d\xf6\xac\xd1\x24\x42\x3e\x03\x9a\x67\xf1\x56\x88\xae\xc5\x0c\x59\x27\xfb\x27\x18\x22\xaa\xa6\x6f\x29\x4b\xc8\x05\xd3\xbc\x7c\x83\x41\x87\x8a\x54\x10\x09\xf3\x0d\xa9\x9f\xcc\x00\x85\x07\x9c\xe7\xfc\x55\xe0\x01\x16\x85\x56\x2a\xbd\xb3\xa9\x47\x1f\xfd\xe6\x17\x63\x00\xef\x5b\x31\xe0\xdf\x60\x9a\x54\xa1\xee\x66\x24\x07\x0d\xa9\x9c\x87\x76\x89\x1f\xdf\x6a\xa7\x8b\x4d\x55\xb1\xf5\xda\xdf\xc0\x61\xad\xd5\xaf\x00\xfd\x3a\xde\xdb\x44\x8c\x55\x9b\xff\xf2\x04\x06\x80\x43\xa5\xd1\xd6\x21\x47\x48\x62\x8c\x3e\xbc\x5f\x02\x24\x32\x6c\xa1\x8e\xf0\x48\x42\x5d\xa9\x30\x01\x33\xfb\x69\x5d\x4f\x26\x31\x65\xac\x22\xf3\x61\x9d\x40\x5a\xf2\x71\xa7\x1a\x9a\xfb\x19\x8b\xf6\x31\x24\x1d\x34\x59\xb9\x53\x98"}, -{{0xb8,0x55,0xc8,0x18,0x05,0xc7,0x08,0x74,0x10,0xe6,0x9f,0x96,0xb0,0x24,0x02,0x71,0xdc,0x76,0xc1,0xe4,0xad,0xe3,0x8c,0x6a,0x92,0x78,0xe3,0xc9,0x4f,0xbe,0xa2,0x56,},{0x6a,0xdb,0x02,0x5a,0x40,0x26,0x0f,0x56,0x98,0x84,0xb8,0xca,0xb3,0x75,0x2b,0x4f,0x25,0x5c,0x37,0x3e,0x2b,0x42,0x4b,0x62,0x87,0xeb,0xb5,0x10,0xfa,0x06,0xff,0xf0,},{0x3c,0xaa,0x81,0x32,0x73,0xe7,0x53,0x54,0x2f,0xfb,0xfe,0xb2,0x1b,0xc3,0xe2,0xcf,0x8c,0xa7,0xd9,0x20,0xfa,0xac,0x7c,0x49,0xdc,0x2a,0xa9,0x91,0x17,0x68,0xc7,0xad,0x43,0xb3,0x8b,0x02,0x36,0xdb,0x27,0xf3,0xee,0xae,0x0b,0x12,0x06,0x00,0x1e,0x66,0x5a,0x60,0x70,0x78,0xc5,0x22,0xed,0x7a,0x9d,0xc4,0x68,0x85,0x34,0x63,0x59,0x00,},"\x85\xa9\xbd\xb7\x0a\x6c\x75\x28\x97\xe4\x3a\x91\x10\x6e\xe9\xa9\x9c\x2c\xa9\x4f\xf7\xb4\x46\x1a\x44\xa3\x91\x74\xc1\x7e\xcd\x99\xdf\x46\xee\xcd\x81\xc3\xf5\x25\x13\xdc\x9d\x54\x7d\xad\x37\x21\xc6\xd5\xee\x1f\x8f\xac\x0b\xa5\xaf\xb3\x68\x70\x44\x73\x9e\xd5\x35\xb8\x44\x00\x87\x04\xc0\x9f\xe1\xe5\xd7\x85\xd4\xc9\xc3\xd0\xb0\x58\x89\xb9\xc2\x0f\xc3\xfd\x68\xdf\x12\xdb\xeb\x2c\x34\xf6\xf7\xec\x1c\x6f\xb7\xfa\x81\x1f\xf8\x46\xb5\xa6\x1f\xa5\xfe\x55\x37\x9e\xe6\x3a\xbc\xd3\x73\xfe\xd0\x02\x54\xeb\xd0\x6b\xc8\xb2\x2f\x7f\xbf\x2f\x72\x7a\x5f\xad\x88\x51\x41\x59\xe2\x6d\x78\xdf\xdb\x09\x57\xf6\xef\xaf\x51\xa8\xe8\x0b\x58\x5e\x83\x8b\x96\x21\xd0\x51\x07\x4a\x4f\x58\x67\xb4\xae\x2f\x2f\xf6\xd6\x2b\x85\xbc\xce\xc0\xb4\xaa\xa4\x79\x16\x37\x38\x8c\x09\x01\xfd\x49\xdc\xcc\xce\x72\x04\x85\x9f\x81\xee\xfc\x63\x9f\xed\x92\x28\x04\x56\xe6\x9a\x15\x09\xb4\xb1\xbd\x76\x24\x44\x7d\x86\x2c\x45\xa0\xc8\xb0\xc5\xbb\x2c\x4c\xa5\x12\xcb\xc0\x37\xf5\x1b\x78\x09\x82\xb1\x83\xa5\xca\xfa\x15\x29\x75\x85\xc9\x47\xa2\x5b\xe8\xc2\x24\x0e\xbf\xb6\x86\x8e\xce\x5e\xa2\xaa\xb2\xc2\x39\xc8\x37\x54\xc7\xd5\x94\xb3\x72\x5a\xce\xef\x34\x4b\xa7\xe6\xae\xf4\x9f\x7f\x31\x3b\x0a\xe8\x2c\xca\xca\xd3\x87\xa6\xe9\x33\x7f\x05\xf8\xc7\x99\xef\xe7\x82\x9b\x27\xb4\xd5\xb2\x01\xfd\x5a\xe5\x83\x43\x51\x69\x07\x59\xf3\xea\x17\x5f\xd4\x74\x1b\xe2\x28\xd8\x07\xfb\x54\xdf\x4a\x74\x10\x38\xfa\xee\x47\xed\xf1\xf5\x61\x65\x25\x98\x60\x1f\x27\x15\x5f\xc5\x0d\x9d\x50\x11\x43\x37\x11\xc1\x06\xd4\xb6\x07\x85\xa5\xcc\x93\xb3\xfd\xd1\xda\xd7\x0c\x0c\x8e\xaa\x33\xf1\x51\x2e\x35\xa5\x41\x74\x5e\x37\x6c\x15\x16\x7f\xa8\xf6\xb3\xb2\xc4\xc3\xa3\x66\xfc\x41\x49\x7d\x29\x73\x57\x81\x6a\xe7\x95\xa8\x04\xc9\x80\xe7\xcb\xfb\x0c\x74\xd8\x83\x5d\x92\x9a\xe3\xbb\x52\xba\xb1\x29\x64\x56\x6d\x74\x6b\xd2\xc1\xd1\x32\xb6\x23\x3f\xa3\x4f\x75\xe2\x68\xed\xee\x77\x5e\xb3\xce\x13\x2e\x6b\xeb\x2e\x8d\x71\xf0\xc8\x76\x29\x91\xcd\xe4\xe2\x6f\x71\x43\x9d\xfa\x83\x97\x8f\x99\x56\x03\x86\x1b\xc0\xb1\xd9\x06\x0b\xbc\xca\xcc\xf8\x6f\x87\x45\xad\x96\x99\x4d\x5d\x00\x7d\x52\xe8\x3a\xa5\xe6\x94\x12\x96\x4b\xdb\xfb\xe4\x78\x0a\xaa\x8d\xe4\x1b\xe1\x29\x8a\xbb\xe9\x89\x4c\x0d\x57\xe9\x7f\xca\xcc\x2f\x9b\xbd\x63\x15\xd3\xfc\xd0\xea\xf8\x2a"}, -{{0x95,0xb9,0xc8,0xa6,0xef,0x80,0xeb,0xd5,0xcb,0xd4,0x7a,0x04,0xca,0x54,0x38,0x73,0x73,0xdf,0x4d,0x67,0xa2,0xb4,0x75,0x59,0x77,0x65,0xac,0x89,0xfc,0xf9,0x3e,0x93,},{0xf2,0xc9,0x47,0xb1,0x8a,0xdc,0x3e,0xa6,0xa2,0x3f,0x7a,0xbc,0xa3,0x64,0xb9,0x85,0x3a,0xe8,0x5a,0x2b,0x0c,0x8c,0x26,0xf0,0xd3,0x17,0x3c,0x27,0x32,0xc3,0xc7,0xff,},{0x2c,0x8b,0xf5,0x43,0xe2,0xa3,0xe0,0x04,0x15,0xee,0x4f,0x10,0x7b,0x2f,0x5a,0x66,0x87,0x17,0x6f,0x5d,0x52,0x11,0x17,0x75,0x9c,0xeb,0x56,0x17,0x51,0xbc,0xc7,0x7d,0x9b,0x08,0xa6,0xa6,0x31,0xf6,0x44,0x7c,0xd9,0x01,0xde,0x96,0x69,0x9a,0xeb,0xb1,0x68,0xbf,0x97,0x50,0x0d,0xc5,0x4a,0x05,0x43,0xef,0x14,0xe4,0xb5,0xa0,0x81,0x06,},"\x78\x55\xbc\x39\x26\x30\xcc\xf5\x31\xd3\x06\x16\x06\xdd\xfc\x81\xa0\xfd\x92\x94\xc5\x47\x91\xb5\xf9\x55\x9b\x68\x27\x25\x4a\xa1\xf2\x5c\x54\x0b\x7d\x7d\xf3\xec\x9c\xdf\x14\x25\x66\x29\xdb\xcf\x9b\x72\x5f\xeb\x34\x12\xeb\xf3\x5f\x0e\xf9\x37\x9e\x41\x31\xcc\x77\xe0\xf0\xfb\x6f\x74\x59\xa7\x38\x36\x1a\x99\xae\x4c\xcb\x2b\x60\xa9\x9f\xe9\x2b\xd6\xc3\xa5\x3d\x6f\x45\x4e\xe9\x00\x5b\xce\xc5\xae\xdc\xfa\x82\x34\x73\x92\xef\xcf\x11\x75\xe5\x78\x39\x6a\x8d\x80\x0d\xab\xa0\xf4\xc2\xcf\x4d\x49\x13\xb0\x52\x86\x20\xe3\xba\xa0\xf6\xd8\x6e\x06\x28\xe4\x7c\x0c\xa2\x6d\xf3\xb0\xc7\x88\xc4\xe1\x65\x57\xf7\xfc\x28\xdf\x82\x0c\x12\xfb\xb6\xff\xbf\xec\xb9\x82\x9d\xdb\x65\xef\x8d\x63\xe9\x0d\x68\xfc\x71\x94\xb5\xb8\x85\x91\x3f\x08\xed\xee\x84\x56\x76\x47\xff\xa3\xf0\xd0\xd3\x25\xd0\x82\x60\x0c\xe7\x1a\x23\x45\xc7\x7d\x65\xbd\x96\x25\x20\x03\xe5\xc1\x25\xa7\x18\xa0\x73\x70\xc3\x1b\x57\x08\x07\x5c\xf1\x83\x7c\x69\x25\x63\x5c\xc6\x8d\xd1\xb7\x51\xe4\x0a\xb6\x08\xb0\xd9\xd8\x85\x2c\x18\xd3\x06\x92\x19\xef\x80\x7b\x76\xd2\x88\xf9\x2c\x29\xa9\x3e\x3d\x75\xb5\xb2\xe5\x36\x81\x67\x1d\x3a\xe0\x14\x5a\xc0\x3c\xca\xd3\x16\x2e\x44\x70\x3b\x04\x01\xd3\xeb\x16\x7c\xd8\xdd\xc1\xe1\xa5\xa3\x26\xb7\x28\xb1\xe0\xc0\x0a\x94\xd8\x6d\xe6\x13\x52\xa6\x61\xe4\x08\x97\x17\x5d\x28\xd3\x41\xe4\xd1\xd9\x96\x2e\x35\xf4\xde\x18\xa5\x40\x17\x61\x1a\xd0\x53\x59\xce\x08\xb9\x7b\xfe\xdb\xfb\xe3\x99\x2e\xd5\x8e\xd4\x0f\x51\x7a\xab\x01\xc0\xfe\xfe\x8b\x63\x64\x3d\xa1\xa4\x54\x15\x27\x30\xbf\x99\xaf\x87\x40\xad\xf9\x8a\x77\xb8\xd7\x3a\xdb\x08\xe6\x09\xe0\x0c\xe9\xb1\xcc\xdf\xef\x3e\x9a\x9b\x05\xaa\x56\xe0\xbc\x79\xb6\xbb\xba\x80\xdd\x8e\x46\x1a\xf7\xcb\x20\x28\x92\xd8\x9b\x2d\x05\xa4\x45\x8a\xb3\xfa\x54\xb4\x74\xb8\xf8\xf5\x81\x79\x5d\x6c\x27\x39\xe5\x9d\x0f\xe0\x62\x40\x0b\xae\x2d\x2d\x53\x4b\x34\x0b\xb8\xe2\x61\x57\x77\xa9\xa5\x61\x5b\xb2\xcf\x43\x7b\xa5\x25\xe0\x0e\x70\x38\xf2\x2a\x57\x88\x2a\xc5\x20\xb3\x33\xe7\x5c\x3c\x92\xa8\xb9\xf0\xe3\x7f\x67\x1c\x94\xb1\x5d\xd8\x18\x2a\x08\xd7\xc1\x43\xe9\x4e\x92\x62\xb3\xcc\x55\x44\xc2\x94\xf5\xf3\x35\xc2\xb2\x8a\xc1\x19\xfe\xa0\x0f\x96\x34\xdb\x06\x39\x93\x98\x8b\x5f\x15\x05\x79\xc7\xcc\x25\xb6\xa1\xfb\x0d\xde\x94\x80\x4f\xa6\xef\x66\xff\x79\xfb\x91\x07"}, -{{0xb7,0x86,0xcc,0xfb,0x58,0x6d,0x43,0xb8,0xc4,0x6b,0xb9,0x7b,0x96,0xc9,0x18,0x73,0x1b,0xc2,0xcc,0x11,0x92,0x77,0xf1,0x23,0x67,0x1e,0x30,0x14,0x81,0x58,0xd2,0xed,},{0x90,0xc7,0x00,0x46,0x00,0xf3,0xdc,0xe4,0x09,0xfd,0xea,0xdc,0x8e,0xd0,0x18,0xf9,0xea,0x26,0x3f,0x75,0x16,0x0a,0x74,0xab,0x54,0xf4,0xc2,0x39,0x9a,0x90,0xca,0x78,},{0x52,0xba,0x96,0x58,0xa1,0xa0,0xb3,0xe9,0x8e,0xd5,0x20,0x9e,0x39,0x3e,0x42,0x00,0x66,0xa3,0x7d,0x37,0x14,0xda,0xa7,0x3d,0x5c,0x67,0x1d,0x33,0x07,0x5a,0x5f,0x57,0x27,0xfe,0x4e,0x08,0x1e,0xe0,0xfa,0x3c,0x21,0x33,0xdc,0x95,0x3a,0x2d,0xa6,0x20,0x29,0x13,0x71,0xf0,0x0c,0xcb,0x57,0xd8,0x79,0x2e,0xb5,0x96,0xa2,0xff,0x81,0x01,},"\xba\xbf\x48\xbd\x55\xea\x91\xbd\x0c\x93\xb9\x70\x24\x1b\x52\x9d\x9d\xb4\x3d\x49\x27\xfe\xa5\xf1\xa1\xf7\x08\x2d\xd6\xcb\x50\xa5\x2b\x09\x4b\x31\x29\xfc\xd9\x03\xa4\x4f\xec\x8b\xfd\xb5\xc8\x6c\x00\x2a\x2a\x45\x28\x87\xca\x25\xa6\x0e\xce\xb5\xe1\xf9\xf5\xc9\x3d\xc5\x94\x23\xc7\xaf\xe7\x47\xc6\xbf\x40\x7c\xac\xad\xec\xcf\x5d\x78\x79\x70\xcb\x06\x17\xbb\x3c\xfe\x7f\xd1\x75\x63\xd3\xa0\xdc\x91\x63\x1f\x71\xb8\x4b\xe2\x4a\xe8\x00\x11\x37\x50\xf0\x31\xd0\x1f\xd0\x53\x64\xb4\xf2\x7f\x86\xf8\xdc\x3a\xd7\x40\x7e\x1a\xe9\xe7\x68\x15\x4e\x3d\xde\x58\xe8\x67\x12\x9e\x24\x74\x54\x7b\x40\x82\x17\x96\x48\x44\x85\x8d\x05\x6b\x31\xc3\x74\x99\x1b\x7f\x16\x1f\x52\xf0\x88\xb8\x06\xe0\xf3\x13\xd6\x8a\x15\xc5\x40\x1e\xd5\x5b\x2b\x77\xde\xea\x58\x6c\xb0\x54\xdc\xd7\x1a\xf2\xab\x6a\xb1\x1e\x84\xb3\x0c\x53\x93\x45\xde\x3e\xb4\x3f\xb7\xb3\xa3\xb4\x89\x87\xc3\xbf\xa7\x06\x55\xd5\x99\xf2\xe3\x1d\x12\xad\x23\xcc\x96\xe8\x6d\x38\x0b\xfd\xa8\x12\xfe\xff\x3d\xd3\x02\x42\x92\x91\x69\x07\x02\x28\x91\xe1\x19\xbf\xc3\xed\x9c\x25\x54\x6c\xd1\x9f\xc9\x92\xd8\xa6\x1e\x60\x59\xca\x3c\xe7\x80\x2a\xf1\x11\x87\x56\x62\x0b\x87\xa7\x24\x2b\xd8\x38\x97\xc9\x4d\xd5\xa3\x6e\xd4\x0f\xc0\xf3\x4c\x2c\x93\x11\x0b\x37\xd1\x7d\xd9\x6a\x22\x06\x25\x90\xbc\xdb\x54\x67\x42\xef\x72\x18\xad\xcc\xc5\xad\x28\xf4\xfc\xe6\xec\xf7\x05\x83\x5f\x41\x13\xd8\x2e\xa5\x33\x90\x3a\xec\x8c\x38\x20\xfe\x4b\x47\x15\xf3\x7e\x20\xce\xbc\x1e\x71\x51\x9a\xa0\xb2\x40\xb4\x84\x0a\xa4\xfd\xcf\xb5\x24\x67\xfe\xdd\x8f\x4d\x1f\x9b\xc3\x3e\xe1\x14\xf3\xef\x85\xf5\xfd\xb0\x9c\xa8\x84\xaf\x38\x8a\xd3\xad\xf8\x4c\x79\x3f\x38\x6e\xfe\x6f\xf8\xa4\x6e\xd8\x1e\x5d\x45\xa3\x7c\x25\xcd\x80\xf2\xd7\x36\x3f\x43\xae\x45\xe3\x77\x2c\x0d\xf8\x9f\x11\x44\x79\x39\x80\x6c\x09\x6e\xf9\x33\xa1\x39\x44\xf0\x89\x0d\x88\x7c\x2e\x5b\xbb\x6b\x12\xea\x95\x0b\x09\xb8\xfe\x42\x52\x89\x37\x73\x52\xf3\x5f\x84\xcc\x4d\xcd\x4d\x7a\x44\x94\x89\xfa\x92\x51\xc0\x31\x13\x48\x92\x25\x80\x9c\xdf\x3c\xb6\x34\x75\xf1\x0d\x34\x17\x09\x37\x1c\x6f\xd4\xbb\x7a\x94\x94\x83\xd1\xbc\x2b\x31\xdd\xf4\xd9\x63\xa0\x7d\xe7\xea\x5c\x3f\xee\x9a\x0e\x33\xf0\x76\x9f\x2f\xaa\x40\x61\x2a\x54\x69\x74\xbd\xe0\xb7\x33\x91\x79\xe4\x12\x4a\x44\x7b\xd4\x28\x79\xcc\xda\x5c\x8a\xd1\x81\x9c\x53"}, -{{0xdd,0x1a,0x97,0x74,0xf7,0x58,0x4d,0x85,0x89,0xb1,0x9f,0x92,0xab,0x69,0x39,0xac,0x48,0x56,0x02,0xfe,0x16,0x44,0xce,0xe2,0xf6,0xf3,0xcd,0x60,0xfb,0xd5,0x84,0x00,},{0x4b,0xea,0x7d,0x0b,0x0f,0x4b,0xd5,0x90,0xf9,0xe3,0x57,0x9f,0x0c,0x5f,0xa4,0xce,0xf4,0xd6,0x0a,0x49,0xd2,0xc4,0x37,0xa0,0xaa,0xea,0xd9,0xd4,0x3a,0x73,0xd4,0xa3,},{0x19,0x59,0xbd,0xe0,0xa6,0x97,0xa6,0x39,0x93,0xec,0x47,0xd1,0x58,0x22,0x37,0x39,0xfe,0x65,0x87,0x1f,0xa0,0x58,0x70,0xd7,0xde,0x0d,0x38,0x08,0x65,0x91,0x20,0x2a,0x51,0xb1,0x74,0xd1,0xc6,0x18,0x28,0x08,0xc6,0xce,0x62,0x63,0x1d,0x81,0xdb,0xa3,0x4e,0xbe,0xd4,0xaf,0x2f,0x29,0xb0,0x6c,0x00,0xa5,0x7a,0x3c,0xb6,0x66,0x36,0x06,},"\xe5\xdc\x3e\xd2\x6c\x1f\x69\x3c\xf8\x52\x46\x5a\x05\xe3\x04\x8b\x50\x5d\xb5\x11\x6d\x9e\x31\x59\x22\x05\xa9\xc3\xd4\x72\x0b\xc1\x0b\x6c\x20\x63\x9a\x0e\xe2\xf0\xe1\x47\x22\x5b\x5b\x19\xea\x51\x1c\xfb\xa0\xc2\x1a\xac\x10\x71\x5a\x2f\x23\x2f\x10\xc2\xc8\xaa\xd4\x11\x12\xb6\xb0\x12\xe7\x5a\x41\x55\xf8\xc6\x92\x62\x53\xca\x2b\x4d\xdb\x7b\xfe\x7f\x86\xe9\x0a\x53\xdb\xc0\xcb\xa8\x9e\x48\x5c\xec\xa8\xfd\x26\xe5\x0c\x7f\x28\x2a\x25\x35\x73\xcb\x0a\x8f\xa8\x8c\xc4\x46\x23\xe8\x2e\x8f\xa2\xed\xb6\xcb\xc7\x53\x8a\xc9\x2c\x11\xe4\xc5\xb1\xea\x5f\x68\x96\x6d\x15\xd9\x3c\x34\xf3\x96\xd2\x75\x72\xf8\x64\x38\x2a\xb7\x6a\x7b\xe6\x5a\x55\x7b\x13\x97\x66\x36\x8a\x20\x7d\x98\xbc\x0c\x20\x92\x63\x70\xde\xa2\x70\x48\x16\x03\x63\xed\x85\xf4\x09\x9e\x7c\xd6\x6d\x12\xd0\x98\x8c\xfc\x9e\x2f\x16\xaa\x56\x5f\x8f\x33\xb3\x9e\x97\x8c\x05\x87\x37\x1f\x92\xdb\x50\x56\x31\x75\x64\x41\x1b\xd8\xa3\xb6\xfe\xa0\x9d\x34\x87\xaa\xf7\x34\x03\x49\x18\xff\xed\x1c\x9f\xba\x7b\xde\xc6\xfe\x68\x87\x6f\xc7\x36\x0c\xc5\x62\x9b\x92\x10\x40\x27\xfe\x57\x59\xc5\xab\x36\x53\x54\x75\x1e\x79\x69\x11\x6c\x3b\x9a\x21\xb1\x52\x33\x0a\x96\xa9\x38\x1a\xf7\x30\xd1\x78\x22\xd7\x8a\xd6\xea\x86\x00\x06\x91\x5b\x5c\xab\x44\x7a\x75\x93\x72\xe0\x5d\x49\x5e\xbb\x32\x8e\x75\xd2\x48\xda\xa0\x2f\x5d\x2e\xb9\x78\xd2\x71\x0c\xf1\xc5\xfb\x82\x48\x76\x77\x0e\x32\xca\x6d\xe2\xc7\x30\x56\x48\x92\x41\x5b\xcb\x53\xe5\x98\x1d\x70\x7a\xdd\x96\x1c\x5f\x37\xfd\xaf\xa1\x39\x9a\xf8\xae\xa9\x60\x45\x8d\x2c\xa3\x10\x55\x3f\x7c\x98\x66\xcc\xbe\x8e\x9d\x88\xe0\x8a\x44\x68\x72\xea\x66\xfc\x30\x8c\x82\x45\x14\xb7\xda\xce\x03\x34\xdb\x73\x5e\x6f\x14\xc8\x5b\x5e\x61\x9a\x5d\x60\x56\x48\xa8\x81\xe8\x76\xc7\x8d\xbe\x06\x57\x23\x3d\x4f\x7f\x3b\xfd\xdf\x63\xb4\x45\x31\x1d\x6a\xbc\x47\x63\x47\xec\x4f\xb4\x3c\x89\x46\xf9\xd1\x7c\x36\x93\x81\xd1\xc5\x64\xff\xcf\xe2\xdc\x7b\x47\x26\xfd\x57\x38\x7f\x0b\x44\xdb\x8e\xf9\x5a\x0b\x4e\x32\xa7\xbe\xdf\x31\x9e\x53\xa9\xe7\x12\x6c\x28\x11\xf9\x82\x9d\x1f\x4a\xe9\xab\xd9\xd5\xf4\x2e\xfe\xf2\x07\x5f\x47\x05\x1c\x63\xa4\xf8\x20\x20\x40\xec\x47\x23\x68\x63\x82\xc6\x03\x31\x27\xc1\xfb\xff\xf4\xbc\x82\x37\x35\x08\x75\x2d\x43\x1d\xc4\x73\xf5\x2d\xde\xab\x03\x42\xdc\x4f\x54\x47\xf8\xf2\x57\x38\xef\x65\xd7\x85\x56"}, -{{0x66,0xf5,0xea,0x8c,0xdb,0x95,0xee,0x1a,0x75,0xe3,0x24,0x67,0xd7,0xc8,0x3c,0x59,0x44,0x77,0x42,0xc8,0x5d,0xdd,0x49,0x9c,0x43,0xc0,0x86,0x73,0xe1,0x49,0x05,0x3a,},{0xa8,0xad,0x04,0xb9,0xc1,0x44,0xb9,0x7f,0xe8,0x67,0x37,0x4d,0x4f,0xe5,0x7d,0x7e,0xc0,0xc2,0x49,0x18,0x3e,0x43,0xbd,0xfb,0x5d,0x52,0x64,0x4e,0x7f,0xbe,0x1d,0xf3,},{0xec,0x5c,0x7e,0x83,0x92,0xfa,0x8b,0x61,0xbc,0x82,0x96,0x81,0x86,0x6e,0x45,0xac,0x8b,0xe4,0xb5,0xb7,0xb6,0xa8,0x22,0xc1,0xbc,0xd0,0xf2,0xcc,0x2c,0x8c,0x44,0xc3,0x3c,0xf8,0x3f,0xa4,0x2d,0x43,0xa2,0xf1,0x88,0x41,0x41,0xb4,0xa5,0x9a,0xaf,0xf4,0x7f,0x9b,0xe0,0x7e,0x63,0x2e,0x20,0x18,0x75,0x93,0x24,0xea,0xc9,0xd1,0x49,0x00,},"\xc0\xd0\x1d\xce\xb0\xa2\xd1\x71\x91\x10\x18\x79\xab\xb0\x93\xfb\x07\x75\x71\xb5\x21\xbe\x7b\x93\xa1\x17\xc6\x96\xc0\x87\x2f\x70\xea\x11\x39\xab\x62\x83\x29\xee\x56\x55\xfc\x0a\xa7\x7e\x81\x11\xd2\xfc\x88\x47\x48\xc1\xf2\x67\xb9\xeb\x09\xdc\x26\xf5\x7f\xc4\x02\xd6\x1b\xa3\x6f\x63\xf4\xd5\x89\xaa\xe6\x3c\x76\xee\xee\x15\xbf\x0f\x9e\x2d\xcd\xe4\xe4\xe3\xe7\x8f\xc6\xc2\x9e\x3a\x93\xf3\xff\x0e\x9a\x6e\x0b\x35\x66\x45\x95\x38\x90\xde\xbf\x62\xdb\xea\xf4\x90\x51\x78\xd4\xf0\xa5\xa5\x92\xc1\x92\x94\xee\xba\x7c\x21\xcf\x8f\x1b\xb3\xf4\x51\x21\x87\x37\x6d\xe7\x2f\x11\x36\xa4\x8a\xc2\xdf\xaf\x32\xd0\xf3\x7d\xe0\x64\x59\x25\x92\xb6\xe1\xbc\x0c\x51\x2c\xf4\xd2\xd8\x5d\x16\x79\x78\x53\xa8\x09\x33\xb0\x9c\x2f\x7b\xfb\x9e\x54\xa6\x9e\x51\xa8\xe4\x23\xa9\x1c\x3e\x5f\xde\xb4\x79\x05\x33\xe8\x7a\x4b\x1c\x0e\x0e\x23\xa9\xdb\x95\x73\xac\x17\xab\x6e\xc7\x01\x4d\x8b\x7c\x44\x86\xe1\x57\x25\xf8\xd2\x64\xee\xa3\x05\x0e\x83\x5a\xe0\xac\x44\x9d\xb3\x34\x50\x2a\x6d\x97\x35\x8f\xa8\x59\x10\x6a\xd0\xf6\xf4\x29\x5f\x23\x44\x92\x0a\xdf\x93\x55\xa6\x94\x9d\x8d\x14\x5c\x25\x62\x8a\x46\xa1\x04\xca\x09\x9b\xd9\xdd\xe9\x41\x11\x9c\x83\x82\x0c\xdc\x2c\xb2\xd0\x97\x22\x69\x49\x01\x04\x3c\x37\xcf\x0a\xe8\x79\xbe\x20\x30\xd0\x37\x31\x58\xb9\xc4\xb0\x71\x82\x98\xbe\x45\xf6\x30\xf6\xfc\xdc\x19\x0f\x7b\x29\x26\xd8\x76\x55\xa1\x8b\xb7\x97\xac\x50\x75\x7f\xcd\x36\x55\xc9\xe4\x1d\x51\x63\x29\x3d\x9a\x13\xd9\x84\xf5\x91\xf7\x5b\x7e\x4e\x5c\xad\xb6\x4c\x4c\x9f\xdf\xef\x76\xca\xb6\x93\x81\xd0\xf6\x0b\x48\x3f\x80\x4b\xb3\xb3\x33\x64\xdf\x8c\xff\xac\xb3\xc9\xb1\x3f\xf4\xc8\xd8\xd4\xea\x40\x76\x6a\x7d\x42\xd8\x25\x6c\x6b\x1c\x11\xc1\x91\xda\xba\x1b\x8e\xf2\x15\x93\xe4\x7b\x18\x85\x8e\xc1\x9d\x81\x73\x58\x67\x8d\x85\x48\xff\x15\x35\xd5\xfc\xf4\x41\x4b\x6a\x11\xd3\x4a\x37\x42\xf8\xd7\x14\x9f\xa6\x81\x38\x3a\x94\x08\x88\x7f\x1c\x0a\x98\xed\x52\x1e\x72\x79\x32\x77\x82\x4d\x6f\x74\x6d\x49\xb6\x3d\x44\x4e\x31\x2e\x6d\x9b\x98\x66\x11\x25\x81\x96\xa5\xb0\x12\xb8\x8f\xaa\x29\xf9\xa6\xc6\x7e\xd2\x5d\xf8\x7b\x2d\xbf\x0d\xbd\x2d\xc3\x08\x0c\x5b\x8d\x15\xa3\x7d\x34\x72\x90\x98\xed\x0d\xe9\x2d\x75\x80\x74\x29\xb2\xca\xe5\xd7\x28\x3c\x4e\x5c\x9b\xd1\x96\xd1\xad\x43\x6c\x7c\x34\xf3\xc9\x46\x6e\x5c\xb3\x19\x6b\x44\x3f\x4b"}, -{{0xed,0x25,0x58,0xe5,0xc5,0x67,0x84,0xbc,0xfb,0x4f,0x4d,0xde,0xa3,0xc0,0xdf,0xbe,0xf8,0xd9,0x6f,0xf1,0xca,0xbf,0x15,0x8e,0xc4,0xab,0xe6,0x0a,0xff,0x66,0x99,0x9e,},{0x1e,0xdc,0x99,0x10,0x12,0xac,0x6f,0x88,0x8f,0xa7,0xe6,0x04,0x57,0x77,0xe9,0xba,0x1d,0x4c,0x03,0xc4,0x02,0x92,0xd2,0xda,0x6b,0x72,0x2b,0x4a,0xd0,0xa3,0xed,0x74,},{0xab,0x9e,0x01,0x16,0x65,0x24,0xfd,0x28,0x8e,0x5c,0x68,0x9e,0x56,0xd7,0x30,0xd4,0x98,0x30,0x00,0x55,0x10,0x30,0x49,0x33,0x34,0xa3,0x98,0x4e,0x22,0x23,0xdc,0x9f,0x7a,0x5b,0x91,0x0c,0x61,0x76,0x0c,0x61,0x57,0x99,0x0a,0x4c,0x33,0x5e,0x34,0x8e,0x3a,0x7b,0xc8,0x22,0x3e,0x09,0xc1,0x0c,0x5e,0x52,0x0c,0x8d,0x61,0xaf,0xf5,0x00,},"\x2c\x64\x33\xe9\xbf\xbf\x4c\xfd\x4e\x07\x1f\x15\xce\x6b\x12\x9d\x78\x0a\x4b\x3d\xe0\x14\xfa\xc0\x34\xe0\xd4\x4e\xf7\x72\xe2\xc8\xb0\xd6\xa3\x48\x1d\x7b\x3d\xde\xb2\x37\x63\x26\x73\x55\x33\x13\xde\xac\x1e\xfa\xfe\x37\x02\xa7\xa4\x41\x1e\x12\xbd\x34\x1e\x8d\x8e\x96\xc5\x9c\x5e\x30\xc3\x68\x07\xa8\x38\x5a\x53\x8e\x9b\x66\x90\x7d\x6a\x52\x84\x00\xbd\x9f\x95\xee\xdc\x52\x16\xb2\x8f\xd7\x43\x7d\x8f\x4a\x02\x9f\xdb\xdc\x7c\x93\x8e\x4e\xb9\x81\x2f\xec\x05\xea\x69\x32\x29\x62\x9a\xce\x6a\xcc\x7a\xf6\xba\x4c\x23\x8e\x77\x22\xf3\x12\xf7\x89\x6b\x00\x49\x22\xf7\x06\x7e\xde\x10\x6f\x8e\x70\x15\x4d\x78\x3f\xb4\x12\x91\xf3\xc7\xe2\xe4\x82\x60\x45\xb5\x74\x1b\xcb\x4a\x88\x38\xf8\x7a\x32\xe0\x04\x97\x04\xe9\xb5\x32\x34\xc2\x24\xff\x89\x8a\x75\x6e\x52\x91\x34\xc1\xa9\xbf\x50\xfd\x02\x98\x19\xb2\x23\x8b\x60\xb2\xae\xc1\x12\x8f\x34\xd2\x1f\x9d\x66\x98\x3b\xed\x39\x86\x59\xd8\x08\xb6\x7a\x2e\x50\x1b\x5a\x1f\x25\xf7\x1f\x0f\x0c\x1e\xb2\xfe\xa0\xab\x42\xd8\x2f\xf3\xbc\x93\x58\xbb\x20\xc2\x75\x20\xc1\x44\xcf\x21\x16\xf4\xa4\x9c\xbc\x61\x99\x4d\x2d\x71\x05\x46\x69\x4c\x4f\x60\x2d\xc4\x06\xe0\xb0\xc2\x7e\x5f\x5e\x64\x66\x7e\x95\xc2\xec\x9d\xf2\xd6\x52\x9c\xf5\x36\x22\xea\x10\xb9\x56\xb3\x45\xec\x55\xb6\xc3\x9a\x1e\x6e\xd8\x8a\xe6\x6e\x5b\x45\x71\x79\x42\x5d\x1a\x84\x90\x37\xb0\x7c\x46\xcf\x5f\x36\x33\x01\x09\x58\x37\xce\x81\x1b\xff\x49\x60\xbf\x9c\xbd\x15\x20\x1c\x1b\x67\x40\xbd\x70\x10\x21\x40\x74\x4c\x33\x27\xac\xa9\xd6\xd6\xd1\x54\x93\x67\x98\xac\x38\x1f\xa6\x39\xdb\x43\x6e\xe8\x16\x56\x67\xd5\x38\xa6\xc7\x4a\x23\x3c\x12\x4b\xf6\x04\xfd\xad\x51\x98\x4c\x41\x70\xb8\x20\x0d\x2d\xf7\x3c\x29\xbb\x1e\x37\x6a\xff\xc3\x14\xdd\xe3\xe8\x6a\xf9\xd2\xc2\xe6\xc3\xa6\x52\x4d\x32\x1b\xce\x93\xe2\x1f\xc9\x65\x56\x4f\xaf\x77\xd0\xcd\x1a\xcc\xb4\xd7\x62\x94\x85\xf5\x64\xc7\x9f\x4d\x8a\x2f\xde\xfb\x46\x54\x54\x02\x8c\x6d\xd1\x42\x80\x42\x80\x53\x70\x74\x33\x63\xbb\x18\x47\x6a\x3f\x23\x20\xdb\x25\x89\xc7\x21\x33\xcf\x5e\x29\xda\xfb\x7d\x07\xaa\x69\xa9\xb5\x81\xba\xb5\xa8\x3f\x40\x3e\xef\x91\x7a\xfa\x14\xb7\x64\xc3\x9a\x13\xc0\xc5\xea\x70\x19\xd2\xfd\xfb\xd7\xf3\xf7\xd4\x0e\xb6\x3b\x2a\x08\x4d\xa9\x21\x89\x5f\xe4\x8f\x4f\xd5\x94\x01\x7f\x82\x56\x9b\x46\x7a\xb9\x01\x16\x9e\xb5\xda\x9c\x40\x17\x1d\x5f"}, -{{0xb7,0x27,0x98,0xb8,0x11,0xe2,0x33,0x84,0x31,0x25,0x6d,0x24,0x80,0xfe,0x7a,0x36,0x63,0xac,0xec,0xbb,0xe6,0xe6,0xc1,0xb9,0x19,0x1e,0x9d,0x9a,0x22,0x44,0x79,0x40,},{0xce,0x49,0x1d,0xaa,0xd2,0x96,0xb5,0x57,0x27,0xb0,0x95,0x13,0xdf,0x02,0xba,0x59,0x28,0xa3,0x71,0x73,0x7c,0xd3,0x58,0x41,0xe5,0xf7,0x35,0xac,0xab,0x7c,0x5d,0xf8,},{0xdc,0xfc,0x6f,0xd4,0x77,0x99,0xfe,0xc7,0x72,0xc2,0x09,0x9b,0x3c,0x64,0x37,0x24,0x6c,0x3a,0xd0,0x72,0x29,0xfc,0x74,0x0e,0x05,0x31,0x1a,0x20,0x6b,0x18,0xb0,0x2e,0xcd,0xb0,0x26,0xc9,0x26,0xf4,0x9c,0x65,0x52,0xe3,0x47,0xfd,0x35,0xdf,0xde,0x06,0xcb,0x63,0x9a,0x79,0x7c,0x50,0x61,0x2f,0x98,0xe2,0x47,0x8a,0x92,0xaa,0xf6,0x09,},"\xa5\xd4\x62\x98\xb0\x79\x06\x10\xae\xdc\x09\x70\xfe\xa2\xa7\x07\x50\x81\x84\x72\x66\xf2\x2f\x12\x47\x8b\x93\xd7\xe6\x74\xc6\xc5\x17\xf3\xc1\x4e\xd0\x61\x26\x9d\x17\x0a\xc3\x1e\x2a\x64\xf9\x75\x4a\x56\x5b\xac\x1d\xd9\x75\x73\x22\xc1\x11\x32\xe7\xbb\xee\x5f\x32\x81\x8e\x0e\x30\x63\xab\x64\xe5\x52\xd0\x9b\x0f\xd1\x75\x76\x39\xb9\xb9\xd1\xc7\x70\x01\x6b\x67\x74\x65\x87\x2b\x66\x9d\xd4\x8b\xe0\x38\x66\x57\x51\x67\x4d\xd2\xf4\x0a\x96\x6a\x26\x74\x8f\xd3\xe5\xdb\xfd\x92\x26\x5e\xb9\x36\xf5\x5b\x09\x42\x86\xc0\x10\x62\x99\x04\x34\x7c\xb4\xc5\x26\xe3\x77\x47\x0a\xa9\x6e\x81\x69\xa6\xf2\x11\x63\x38\x07\xa5\x00\x30\xe7\xff\x68\xe3\x89\x11\xb3\x55\x5e\x72\x8e\xd8\x59\x0b\x2d\xc4\x5f\xea\x69\x94\x5c\xc0\xc9\xa3\xd3\xe6\xc9\x54\xb3\xe8\x01\x06\xa5\xc9\x1d\x3d\x22\xe8\x9e\x8c\x0e\x1d\xe9\x02\x05\x8e\x9c\xd0\xf8\xce\x80\x6e\xac\x4f\x89\x3e\xe0\x42\x99\x00\xfb\x54\x87\xb8\xfd\x36\xdb\xdc\xb3\x4f\x2d\x54\xfc\x6c\xc7\x4a\x92\x39\x51\xb8\x63\xda\x70\xf1\xb6\x92\xbf\x04\x38\x48\x43\x66\xcd\x85\xee\xb8\x80\xb2\x79\xf8\xfc\xa9\xd3\x24\x2c\x55\x83\x30\xf1\xca\x57\xc6\xa5\x86\x08\xcd\xbc\x07\x73\xe1\x60\x82\xbc\xa9\x64\xdd\xc4\x03\x47\xda\x8a\x36\xb2\xa9\x32\x8c\x2f\x46\x60\x9e\x09\x2f\xd6\x4b\x41\x34\xee\xe1\xd0\x99\x81\x3e\x12\x46\x48\x9e\x8e\xe5\xb1\x9b\x3d\x3b\x89\x1c\x28\xf3\x0b\x38\xb6\xa2\x8e\xc1\xd3\xe9\xb0\x05\xde\xc9\xc6\x3f\x8b\x98\x13\xbc\x1d\xe4\xaa\xf9\x95\xf1\x77\x9d\xde\xd1\x5c\x7a\x43\x0d\x70\xca\x46\xe7\xca\xfd\x4e\x9a\x54\x38\x04\x44\x6a\xb0\x80\x7d\x64\xf2\x55\xe2\x01\xef\x42\x8a\x47\x4d\xae\x8a\x0a\x75\x02\x1b\x62\xad\x39\x88\xff\xb8\x1c\xd8\x22\x1b\x24\x30\x85\xa0\xad\x04\x6f\xdc\x16\xc6\x7f\x17\xb9\xf8\x18\x20\x09\x59\x53\xa5\xb9\x8a\xcb\xdf\x93\xeb\xcf\x80\xbc\x9c\x99\xaf\x5f\xbf\xfa\xcb\x61\xa9\x25\x1c\x5a\xaf\xdb\x22\xb1\x12\x9b\xfc\x60\xc9\x8e\x0f\x17\x52\x63\xbd\xf9\x3d\xc9\xa0\x8b\x8e\xfc\x2e\x8c\xda\xf0\xf8\x3d\x6c\x49\xec\x90\x16\x45\xea\xc5\xa4\xff\x63\x38\x5a\x6f\x1a\xf2\x07\x18\x97\x66\x2a\x37\x22\x19\xc9\x30\x1f\x54\x5a\x2e\xbb\x8f\x59\x17\xdb\x7f\x29\xca\x13\xfc\x86\x1a\xf3\x8d\x90\xc3\x5c\x03\xac\x91\x84\xc1\x22\xe5\x7b\x05\x7c\xde\x42\x6f\xd7\x6d\xca\x79\xe2\x5e\x64\xdb\xb4\x1c\x84\x14\xa0\x45\x0d\xa4\x90\x5b\x90\x2a\xe9\x8d\x2d\xa4\xba\x79\x28\x01"}, -{{0x1f,0xe7,0x32,0x7e,0xa9,0x07,0xd3,0xff,0x17,0x9b,0x11,0x78,0x11,0xd3,0x01,0x93,0xfc,0xba,0x4c,0x34,0x7b,0x90,0x65,0x7f,0xee,0xd9,0x8d,0xee,0xec,0xda,0x9a,0xc9,},{0xee,0xf3,0x01,0xb1,0x6f,0xd7,0xbf,0x3c,0x7b,0x64,0x0b,0xf5,0xee,0x87,0x00,0xac,0x5a,0x87,0x16,0x9e,0xab,0x5f,0x56,0x01,0x5b,0x3f,0x49,0x9d,0x95,0x5e,0x07,0xeb,},{0x9c,0x7f,0xdb,0x53,0xfd,0x60,0x6b,0xc7,0xc9,0xc2,0x23,0xfe,0x94,0x31,0xe1,0xad,0x00,0x95,0x46,0xd0,0x00,0x98,0x81,0x2a,0x49,0x51,0x97,0xf2,0x54,0x1e,0x87,0xf8,0xd6,0xf5,0xda,0x22,0xec,0xef,0xcb,0xb7,0xda,0x56,0x66,0x2a,0x73,0x09,0xd1,0x0a,0x6c,0x4a,0x4f,0x7f,0x29,0x92,0x78,0xd5,0x1b,0xbd,0x11,0xe0,0xcc,0x1b,0x87,0x09,},"\x19\xa8\x32\xf2\x6f\xbb\x02\x39\xf0\xd9\xd2\x6a\x2e\xbd\xed\x24\x03\xc2\xa4\x06\xdd\x1f\x68\x31\x8d\x67\x7a\xfa\x64\xf3\x50\x43\x31\x6a\x5e\xfd\x72\x97\x83\xc7\xf9\xd1\x8c\x09\x82\x46\x14\x65\x20\x91\x88\x6c\xc9\x54\xbe\x9f\x93\x12\xd4\x58\x6b\xf3\x6f\x30\x35\xac\x70\x34\x38\xb0\xcf\xe3\xde\xc5\x07\x78\x13\xc7\x10\xd1\x44\x75\x61\xab\x61\x57\xbc\x7a\xd5\xea\xb5\xb0\xc0\xaf\xdc\xc9\xdb\x77\xe6\x6f\xa8\x07\x13\x66\x82\x9c\x50\x10\x96\xc3\xd3\xa9\x38\x21\x8a\x6e\x42\x07\x10\x9d\x1e\xb8\x1f\x7d\x88\xbd\x6f\xbb\x2a\xef\xb1\xad\xef\x35\x94\xaa\xe5\x7c\x46\xb7\xb9\x84\xdb\x94\x68\xcd\x96\x2c\x61\x84\xfb\x97\x6f\x0e\x2a\xa8\x41\x52\xde\xb1\xc7\x6a\xea\x75\xae\x48\x84\x42\x94\x3a\x80\xba\x7d\x98\xa2\x8c\xb8\x64\xb5\xe8\x7c\xdb\x28\x4a\xd6\xe8\xd7\xaa\xdc\x6b\x75\xd6\x9d\x3b\xd3\x45\x78\x3b\x3e\xbb\x67\x6f\xf9\x5d\x7b\x41\x91\xe5\x99\x85\x1c\x96\x28\x83\x5c\x7c\x01\x19\x7e\x7c\x8f\x86\xf9\xc8\xfb\x49\xfe\x3e\x28\x45\x8b\xa9\xb0\x23\x62\x19\xbd\x46\xc2\x8d\xf6\x53\x24\x96\x99\x4a\xc9\xba\x73\x3c\x01\x05\xa0\x2a\x26\x9a\x2b\xe8\xb7\xcb\x40\x07\x4b\x88\x16\x02\xef\x92\x47\x05\x2d\xe9\xd6\x37\x08\x91\x88\xbd\x4c\x18\x5c\xca\xe2\x58\xa2\xae\x98\x56\xa2\xcb\xf8\x45\x11\x17\x68\x3c\xe3\x41\xf8\x09\x6e\x1d\x91\xe8\x74\xc5\xcb\x8a\x4e\x09\x39\xeb\x77\x37\x3a\x9a\x0e\xb7\x91\x64\x5b\x8f\x54\x60\x47\x2d\x66\x9d\x80\x14\x68\x1a\x5e\x77\x87\x06\xcb\x55\x66\xbb\xd4\x72\x7d\x17\x16\xb2\x3c\x62\x0d\x22\x8b\x5d\x4d\xc2\xb3\x52\xb4\x23\x93\x1f\x8a\x7e\x8f\xb5\x9e\xda\xd8\xae\x42\x45\x87\x29\x86\x1a\x98\xe0\xc8\x50\xa7\x7e\xd6\x55\xe7\xfc\xfe\x4f\xe3\x6f\x97\x72\xdf\x1a\xc3\xc6\x43\xad\x31\xdb\x56\x30\xd5\x71\xdf\x9f\xcc\x9c\x50\xde\x76\x22\x10\x84\x11\x96\x2b\xbf\x72\xde\xfb\xf4\x9e\x99\x70\x59\xc7\x31\x1b\xd9\xdd\xd5\xb3\x38\xa9\x85\x19\x38\xd3\x7e\x7a\x26\x21\x08\xa2\x91\xe2\x01\x68\x03\xbb\xef\xf4\xf9\xc7\x76\x12\x5c\xeb\x7e\x72\x72\xb5\x1c\x7c\x33\x46\x1d\x80\x89\xf8\x40\x8d\x8d\xda\x92\x50\x6d\x50\x02\x08\x4d\x4f\x41\x4d\x8a\x4d\x28\xd3\x69\x4c\x88\x63\x0e\x31\x80\x19\x90\xd9\x52\x71\xce\xf4\x7a\xa5\xc2\x63\xf9\x7b\x7d\xac\xa1\x78\x87\x01\x43\x63\x29\xb5\xbf\xaf\x72\x65\x3c\x16\x6d\xb0\x87\x70\x81\x30\xc5\xc0\xd7\x8c\xc4\xe9\x06\x4f\x86\x06\x80\x27\x1a\xfe\x4c\x40\x98\x53\xc2\xfa\xd6\x75"}, -{{0x5f,0x9d,0xcd,0x93,0xfb,0x14,0x06,0x10,0xb0,0xe2,0x11,0xb3,0x9a,0xdd,0xb1,0xeb,0x87,0xba,0x97,0x80,0x48,0x77,0xaf,0xbc,0xc3,0x81,0x38,0x8c,0xad,0x65,0x08,0x45,},{0x18,0x2a,0x23,0x7d,0x87,0x8c,0x58,0x19,0x33,0x33,0x2b,0x41,0x78,0xb6,0x7e,0xc4,0x08,0xb3,0x19,0x4d,0x44,0xe4,0xe6,0x93,0x92,0xef,0x80,0x0b,0x26,0x7c,0x29,0x49,},{0xc1,0x91,0x5e,0x05,0x2b,0x66,0x47,0x97,0xe0,0xd5,0xfa,0xad,0xc7,0x8f,0x2a,0x00,0x9d,0x6f,0xbc,0xfd,0xe0,0x3f,0x3a,0xaa,0xd5,0x9b,0x9f,0x45,0x88,0xe7,0xfc,0x3b,0x21,0x99,0x0c,0x52,0x08,0xd3,0xd7,0x6b,0x4a,0xa9,0x5b,0xd9,0x34,0xe8,0x8d,0x3c,0x98,0xc5,0x91,0x93,0x0a,0x59,0xde,0x2a,0x05,0x67,0x01,0xd9,0xf7,0x57,0x74,0x00,},"\xc3\x8b\x87\x4d\x3f\xf0\x10\xff\xf1\xa6\x61\x3b\xfa\x13\x42\x57\xb2\x48\x33\xcb\x53\x6d\xe3\xe7\x49\x92\xc3\xcb\x01\xfe\x3b\xbd\xee\xd9\x7d\xc3\xc4\x59\x6f\xa4\x40\x61\x44\x2b\xd3\x1a\x9d\x4a\xa8\xc8\x1e\x34\xad\x98\x88\x71\x82\x06\x63\x55\x09\xb1\x33\xb1\xba\x69\xcb\x1a\xa0\xe7\x5c\x7a\x18\x93\xc0\x80\x16\x1d\x26\x15\x2a\xce\xf4\x0f\x6e\xf4\x21\x0e\x95\x2a\x49\x82\x8b\x5c\xdd\xe8\x04\xbc\xb5\x36\xcd\xc3\x49\xa8\xe8\x31\xb4\xb6\x9d\x37\x85\xa7\x6b\xd9\xfb\x27\x08\x05\x65\x97\x2d\x0b\x8f\xbd\x16\xf3\xf9\x60\xa6\xbf\x3b\xa0\xc5\xb9\xc4\x04\x96\x7e\xc1\xaf\xfe\x59\xb8\xc4\xec\xc6\x50\xfd\xde\x1c\xb0\x6b\x70\x59\x5a\xd4\xd3\x25\xda\x0f\xab\x4c\x55\x40\xa7\xa8\xd5\xeb\xea\xcc\x4e\x99\xbd\x0d\xc9\x6b\xde\x82\xf2\xbd\x7d\x95\x86\x30\x84\x65\xe5\x5b\x1c\xc3\x88\xd7\x50\x48\x6b\xdd\x5c\x72\x64\xd5\x4f\x56\x14\xd4\x87\x26\xd9\x9e\x44\xd7\x77\x8d\x9e\xd0\x32\x39\x58\xab\x98\x58\xe2\xb2\x5d\xf2\xbf\x99\x4b\xa3\xe6\x25\xe2\x80\x3b\x6c\x69\x31\xe7\xa9\x92\x6f\x1e\x61\xed\x86\x24\x03\xce\x39\x2a\xb8\x3b\x7d\x1b\x66\x08\x5d\xcc\x06\xd8\x2d\xbf\x17\x6d\x01\x6d\x9f\x44\xcd\xcb\x50\x72\xd0\x04\x59\x1e\x92\xd0\x45\x9e\xf0\x5a\x51\xb8\xf5\x4b\xa1\x72\x51\xe1\x66\x21\xeb\xb7\x53\xe5\xb1\x59\x0c\x02\xd2\x1e\x40\xf4\xb7\x5e\xee\x46\x02\x86\x0b\x97\x41\xfb\xbc\x0d\x2e\x38\x5b\x8d\xac\xa8\x3c\xce\x68\xc3\x4a\x99\xbd\xe6\xa6\x0d\x13\xba\x64\x34\x7d\x0a\x38\xd6\x4b\x2a\xde\x25\x0f\x38\x85\x2c\x4e\xda\x2e\x2e\x4f\x30\x3c\x3d\xe1\xa8\xa9\xd4\xab\x33\x00\xc9\xe6\x36\x22\x87\x9f\xc8\x53\x7f\xfc\x63\xb1\x85\x61\xfa\x1f\xff\x65\x53\x12\x41\x51\x5a\x62\xbb\x9b\x08\xb8\x0a\xf3\x76\x67\xa6\x01\xae\x04\x17\x17\x93\xcc\x83\xb1\x1a\xdf\x9c\x30\xca\x9f\x4d\xab\xc7\xb4\x01\xe1\x6a\x18\x14\xcf\xc7\x50\x24\x8c\xc2\xf7\x7e\x03\xf9\xc4\x33\x44\x65\xff\x6a\x2c\x83\xcb\xb5\x6d\xb4\xb7\x34\x75\x10\x43\x83\x2c\x40\x00\x97\x2e\xe3\x23\x2f\x92\x9f\x23\x33\x7e\xba\x5e\x65\x1e\x34\xcb\xdd\xfe\x68\xba\x21\x9b\x63\x2e\x7a\xcd\xbd\x46\x30\xa0\x31\xbf\x16\x89\xfb\xbc\x7f\xbb\xb2\x10\xdb\xf2\x5e\xe8\x7e\x2e\xf2\xb3\xcb\xaf\x8d\x9e\xbd\x8f\xc9\x2c\x3a\x58\xd3\xc0\x5b\x13\x85\xa7\x6c\x87\x79\x1d\x7c\xd3\x74\x1b\x71\xb6\xc3\x29\xde\x9a\x9d\x75\x08\xa0\xc1\x56\xa9\x52\x1a\x90\x20\x56\x30\x99\xa8\x2b\x87\x70\xae\x9a\x94\x4a\x7e\x94"}, -{{0x92,0x5e,0xbe,0x04,0xc6,0xea,0xc4,0x9b,0x26,0x73,0x8d,0x6c,0x13,0x00,0xf3,0x1f,0xd4,0x82,0x84,0x78,0xcb,0xe9,0x7d,0xab,0x18,0xbb,0x88,0x96,0x42,0xe1,0xe1,0x10,},{0xcd,0x72,0x31,0xb6,0xeb,0x74,0xe1,0xfe,0x9f,0x92,0x6f,0x00,0xd8,0xde,0x2c,0x51,0x3d,0x49,0x64,0x05,0x25,0xb0,0x79,0x5c,0xab,0x89,0x3d,0x0c,0x89,0x29,0xe3,0xe0,},{0x2c,0x4d,0x69,0xbe,0xd5,0xad,0x8b,0x95,0x84,0xd8,0x49,0xcf,0x3d,0xf2,0xba,0xc7,0x22,0x82,0xb5,0xf3,0x0d,0xe2,0x66,0xb1,0x4f,0x53,0x3c,0xa9,0x6e,0x95,0x50,0xc4,0xb8,0x54,0xc1,0x54,0xbd,0xc1,0x7a,0xa8,0x80,0xcf,0x00,0x1a,0x64,0x54,0xff,0xaf,0xaa,0x2e,0x50,0x17,0x8d,0xe2,0x12,0x16,0xed,0x12,0x6b,0x63,0xf7,0x7f,0x2d,0x02,},"\xe6\xc0\xba\xd2\x3a\x92\xae\x8b\x1d\x85\x77\x82\x88\x15\x7a\xc6\xc6\x17\xc6\x33\x63\x34\x1d\x77\x78\x70\x34\x1b\xb1\x0a\x8d\x3d\xfc\x89\xbe\x4f\x55\xad\x4f\x64\xe8\x3b\xf2\x49\x9b\x69\xfd\xf7\x21\x74\xd2\x84\x4e\x6b\xd2\x89\xda\xaa\x03\x5f\xec\x5b\xf7\xcf\x45\x52\x21\x19\xdc\x7a\x8c\x81\x1d\x79\x57\x8c\x5b\xb0\xf6\xd3\x4d\xb5\x07\xad\x1f\xb6\xdb\xff\xf9\x97\xb7\x9d\xac\xfb\x3d\xa5\x0a\x41\x5e\x35\x0c\x99\x8c\x0a\x02\x80\x0a\xa5\x0f\xfd\xfe\x5f\x42\x76\xd8\xe6\xbb\x82\xeb\xf0\x47\xfe\x48\x71\x1d\xaf\x7a\x89\x3b\xdc\x75\x37\xbd\xae\xdf\x3d\xcb\x4d\xec\x5d\x24\x58\x68\x11\xf5\x9b\x25\xb1\x9e\x83\xca\x61\xe5\x59\x2f\xed\xc0\x8c\xa5\x44\x73\xce\xa2\xec\x12\x1b\xaa\x0e\x77\xfb\x2d\x9d\x76\x56\x57\xde\x67\x98\x0e\xd5\x7f\x2f\x17\x78\x58\xb6\xde\xcf\x84\xff\x90\x21\x2d\x96\x47\xf4\x1e\xed\x9b\x9d\x0e\xa3\xd8\xd6\x21\xe4\xbb\x40\x41\xac\xc5\x14\x6e\x96\xdf\xcf\x14\xea\x96\x2d\x30\xc8\xcc\xb3\x9e\xa2\xbe\x95\x8c\x9b\x87\x74\x45\x1b\xfe\xb7\xdd\xce\x71\x6e\x94\x92\x3c\xc8\x5f\xbd\x3a\x31\x30\x78\x0e\x2b\x3b\x2b\xb7\x6d\xa5\x34\x19\x12\xa4\xe9\x94\xca\xfa\x19\xbb\xa1\x97\x32\xf2\xea\x40\x2d\x71\xd3\xd8\xa9\x69\x67\x9b\x9d\x10\x42\x43\xd9\x83\x9c\x69\xee\x9e\x95\x5e\x1c\x60\x44\x97\x88\xd1\xf4\xf6\x65\x1f\x4b\xc9\xb9\x4d\x73\x52\x2e\xc0\xcf\x72\xca\xcf\xcf\x19\xf1\xf0\x3a\xd6\x23\x21\x04\xb5\x5c\xbb\x8b\x5b\xb1\xe2\x13\x44\x71\x3d\x48\x27\x42\xd6\xab\xc5\xa9\x57\x17\x4f\x62\x3b\x84\x95\x27\x2c\xc1\xe2\xb8\x31\x5e\x5c\x80\xf9\x47\xf5\x00\xc8\x3d\x85\x44\xf7\xcd\x4f\x65\x34\x89\x49\xef\x44\x20\xd7\xfc\x83\x1f\xa4\xae\x2e\xe1\x8d\xbb\xa6\x14\x92\x5c\xe1\xd7\x67\xc1\x77\xa6\x26\xc4\x52\x7a\x81\x54\xb5\x72\x92\x18\x6b\x04\x4c\xbf\x92\x89\x42\x53\xb0\x0f\xd9\x34\x3f\x9e\x69\x7b\x14\x12\xeb\xa4\x35\x97\xeb\x72\xa6\x69\xaa\xa2\xd7\x7e\xac\xb9\x68\xc2\x0f\xe1\x95\x05\xa3\x80\x74\x15\x86\x21\xb6\x06\xf7\x7d\x97\xbc\x6e\xbe\x50\xe7\x58\x92\x93\xdb\x27\xfc\x7d\xfe\x63\x1a\x4b\xee\x83\xb2\x26\x82\xa7\x73\x28\xc3\x6d\x9d\x7d\x1d\x89\x1d\x65\x21\x7c\xc4\x78\x64\xf6\x80\xdc\x8b\x5f\xd1\xa0\x1a\x0f\x7c\x34\x43\x0f\x77\x06\x0b\x69\x1a\x1a\xd2\x13\xd2\x28\x68\xe6\x1b\xbd\x38\xf4\x3f\x0c\x8b\x4d\xa6\x8a\x58\x31\x86\x66\xc0\x99\x76\x61\x70\xc2\xdb\x76\x6a\xaf\x41\x7f\x55\x6c\xc9\xa0\xa3\x93\x4e\x9f\xce\xf1"}, -{{0x4d,0xd3,0xb4,0x78,0xeb,0xdc,0x59,0x47,0x2b,0xab,0x14,0xa8,0xcd,0xd0,0xc2,0xfd,0xac,0x57,0x23,0xee,0x04,0xdd,0x89,0x17,0xc7,0xcf,0xe7,0xa5,0x36,0x48,0x5c,0x77,},{0x5b,0xcc,0xb3,0x7e,0x68,0xc2,0x34,0xbe,0xad,0x49,0x33,0x7d,0xe2,0x08,0xaf,0xba,0xf6,0x11,0x81,0x1d,0x96,0x58,0x59,0xa0,0x6d,0x31,0x30,0x12,0x47,0xd6,0x6a,0xcf,},{0x57,0x88,0xe7,0x9e,0x84,0x3b,0xde,0x9e,0xf1,0x1a,0x9d,0xfa,0xc9,0x70,0x19,0x6a,0x56,0x7c,0x63,0x08,0xc3,0x48,0xe5,0x17,0x4b,0x38,0x77,0x95,0x04,0x6d,0x59,0x0a,0x47,0x49,0x1f,0xd7,0x1d,0x97,0xae,0xaa,0x78,0xc1,0x61,0x59,0x71,0xb8,0x34,0x90,0xe8,0x59,0x28,0x20,0xf9,0x59,0x2a,0xc7,0x62,0x69,0xb9,0xd2,0xba,0x70,0x29,0x01,},"\x1c\xdb\xd2\x85\x56\xec\x44\xe8\x70\x5a\xfd\xa9\x2b\xd5\xa5\x3f\x95\xd8\xfe\x8b\x0f\xfe\x46\x33\x73\x63\x33\x16\xc5\x22\x74\xc1\x1e\xdc\xd6\x15\x51\xe3\x19\x9e\x49\x4d\xff\x6d\x90\x6a\x73\x9e\x7b\x32\x43\x03\xfc\x47\x82\x7e\x56\xde\xf0\xbd\xcc\x46\xb8\x16\x01\x7c\x71\x23\x05\x37\x02\x63\xba\xbd\x2c\x71\xbe\x47\x8f\x41\xce\x30\xb1\xdf\x63\xbe\xdd\x3b\x2e\x6a\x51\x9c\x53\xdf\x51\x58\x52\xc4\x13\x7b\xc1\xac\xa4\x9b\xf4\xc4\x63\x1f\xd6\x56\x46\x57\xd1\x1c\xd8\x3e\xa7\x3c\xc3\xd0\xcf\x9e\x3b\x3c\x3e\x7c\xa9\x9b\x4f\x12\xa9\xc9\xb6\x7c\x87\x98\x14\x8e\x0a\x0d\xc1\xef\x8b\xf5\x86\x42\xa1\x4f\x97\xa5\x72\x13\x55\x14\xc1\x0b\x19\xaa\xbe\xc2\x5a\x9c\x6b\x35\xaa\x40\x34\xa5\x7a\xae\x1b\x6d\x05\xbd\xe2\xb6\x33\x0f\x25\x1d\x78\xdb\x09\x93\xf0\xca\x4c\x26\x38\x6e\x34\x89\xa2\x09\x28\x33\xb8\xac\xbb\xc4\xf4\x91\x7f\xd3\x09\x3d\xf5\x82\xff\xf7\x1e\xce\x21\x9d\x36\x72\x45\x55\x82\x60\x9c\x0d\xb8\xd9\x6a\x70\xfc\x8a\xed\x67\x98\xde\x54\xbf\xb2\xb3\xee\x6c\x5d\x32\x8d\xb1\x63\x59\x3f\x58\x01\x9f\x38\xf3\x39\xfd\x37\x53\xf8\x96\xa4\xa2\xcc\xa8\xc1\x40\x0a\x77\xea\x39\x19\x35\xf3\x4e\x26\x39\xc5\x60\x86\x08\x10\xbb\xbe\x4b\xe1\xd1\x6e\x01\x2c\x11\x49\x0a\xa8\x4f\x29\x64\xc8\x77\xc2\x93\xb3\x00\xf4\x3d\x37\x9f\x3e\xba\x9a\xf3\x91\xde\xe5\x10\x85\x6a\x4d\xdc\xf7\x6e\x0a\x0a\xe0\x6a\x6a\x7c\x0f\x9c\x5e\x3f\xa1\xb8\x35\x4f\xe8\x97\x7b\x4e\xa3\xb2\x06\x61\x49\x1f\xa4\x61\x3b\xa6\x2f\x55\x6d\x5d\x5d\xa8\x21\x3d\x01\x21\xde\x2c\x87\x25\xdf\x0a\xae\x04\x8a\xc8\x91\xab\xbc\x06\xbd\xce\xf3\xc3\xef\xfd\xf5\xa3\x17\x49\x47\x6f\x81\x4d\xb9\x45\x79\x45\xf0\xd9\x1e\x14\x08\x00\x56\xbe\x92\x1a\x16\xaa\x96\x4a\x92\x98\x22\x1b\x15\x75\x94\x97\x3e\x32\x96\x99\x93\x31\x0c\x87\x07\xe1\x9f\x31\x43\xab\xc4\xfd\xa7\xc8\xad\x01\x60\xac\xf0\x31\xab\xa6\x52\x80\x1a\xa8\x1a\x01\x6b\x31\x37\x03\x9e\x27\xd6\x73\x8d\x02\x80\x0a\x93\xa8\x6f\x9f\x55\x85\xc5\x18\xdf\xa9\xe7\xd8\xac\x72\x7f\x37\x43\x7e\x56\xd2\x78\x83\x86\xe1\x16\x53\xa0\x4e\x16\x51\x69\xf9\x03\x97\x2a\x01\x48\x47\x51\xe7\xcb\x38\x63\x25\x90\xec\x80\xd5\xfc\xe4\x54\x16\x01\xa0\xe0\x95\x78\x5a\x9e\xe8\xd3\x59\xed\xf2\x6b\x99\x46\xe7\x98\xda\x59\x98\xcb\xb7\x36\xf9\x4e\xb7\x13\x46\x3f\x79\xf5\x61\x75\x9b\xbc\xb4\xc4\xac\x69\x3c\xab\xf2\xe1\xe0\x36\xb2\xd0\xb0\x87\x9a"}, -{{0x07,0x4d,0x92,0x18,0xc1,0x21,0x7e,0x75,0x82,0x3c,0x90,0xe0,0x10,0x48,0x4c,0x2a,0xdb,0x88,0xec,0xcc,0xd2,0xbd,0xf0,0x12,0x0a,0xa3,0xed,0xff,0xcf,0xcb,0xd4,0xbf,},{0x37,0x35,0xad,0x19,0x19,0x03,0x3d,0x16,0x17,0xb8,0x5b,0xda,0x04,0xb1,0x61,0x21,0xda,0x1d,0x86,0x1b,0x40,0x41,0x54,0xfa,0x96,0x1d,0x49,0x46,0xe5,0x5e,0xcd,0x83,},{0xb1,0xf7,0x1c,0x3b,0xd1,0xb6,0xbe,0xc4,0x33,0x37,0xe2,0x6d,0xee,0x65,0x5a,0x8d,0x5f,0x4a,0x8d,0xad,0x84,0xa5,0x11,0x84,0xb7,0x75,0xb6,0x86,0xfa,0xd3,0x1d,0x80,0x29,0xe3,0x87,0x69,0x27,0xf9,0x57,0x6e,0x90,0xc3,0x62,0x48,0x75,0xfc,0x00,0x29,0xa5,0xc1,0x0a,0x8a,0x0a,0xf7,0x5d,0x7a,0x88,0x0c,0x68,0x44,0xa4,0xa8,0x3a,0x00,},"\x6b\x5a\xa4\x0e\x91\x67\xbf\xdb\x84\x7d\xaa\x7d\x27\x86\xe2\x8e\x75\x33\xe1\xd6\xac\x53\xbe\xb6\xf6\x9b\x59\x53\x79\x5a\x2b\xf5\x9b\xbf\x7d\x14\x19\x26\x96\x8f\x50\x96\x9b\xad\x74\x2a\x4f\xb5\x79\xd3\x25\x0f\xb1\xbe\x4c\x57\xeb\xf4\xf9\x11\x2c\x70\xcd\x9f\x72\xa0\x0d\xb1\xc8\x89\x6f\xe2\xb5\xbd\xa7\xc7\x03\x0f\x49\x7c\x0b\x00\x1e\xa2\x5b\xa0\xd4\x47\xf0\x8c\x36\xdb\x8b\x90\x7c\x2f\x2a\xbb\xbb\x62\x0d\x3e\x8a\x2c\x66\xe4\x17\x12\x85\xad\xca\xad\xd1\xc1\x4f\xe2\x39\xbc\x59\x5f\x09\x83\x96\xaa\x87\x80\xff\xb8\x0f\xe1\x44\x6a\x07\x00\x1e\xc2\x34\xd8\x2a\xbd\xcd\x81\x00\x79\x39\x15\xb0\xb3\xf8\x0d\x84\xe2\x0e\x51\xea\xbc\x79\x78\x06\xf3\xbe\x81\x08\xa4\xf4\x37\x55\x0b\x06\x69\x40\x50\xa8\x29\x31\xac\x40\xc0\xa4\x89\x77\xed\xf6\xce\xd2\x42\x8d\x7c\xfe\xa8\x20\x55\x06\xde\x86\x40\x80\x65\xd1\xa1\x98\x70\xfa\x33\xa7\x08\x10\x37\xb3\xee\x44\x91\xb6\xe7\xf3\xd1\x0b\x14\xa3\x0c\x20\x91\x59\xa1\xc8\x12\x31\xa3\x5f\x03\x65\xb4\x7d\x3e\x0d\xa0\x4a\x32\xc9\x5d\x98\x33\x3c\x44\xf5\x72\xcd\xaa\xa9\x05\xd0\x69\x19\x7f\x6e\x86\x1b\x5d\xfc\xdf\xb9\xdb\x6c\x7b\x0d\x0c\xb0\x0f\x37\xc9\x16\xa1\xc4\xc0\xb8\x98\x5b\x09\xf3\x34\x09\x5e\x12\x83\xed\xfd\xd4\xe6\x2a\x29\x41\x09\x9a\x2b\x69\x36\x96\x60\x4d\x99\x43\x11\xe3\xd5\xf6\x10\x66\x83\xe1\xd7\xa1\xc7\xe5\x3d\xf7\xb7\x90\x94\x7a\x9a\x80\x1a\x0c\xcd\x48\x43\x95\xf6\xcb\xfd\x9c\xa4\xd9\x80\x4f\x18\xd5\x2b\xb0\xf9\x46\xd1\xa8\x9f\x97\xa6\xfb\x06\x80\xa8\xc4\xc0\x57\xb6\x06\x2b\x2b\x9d\xe7\xc0\x37\x48\x79\xb8\xa6\xa6\xd2\xc1\x0a\xef\x78\x05\x08\xeb\x28\xbb\x56\x9a\x08\x35\x09\x44\xc8\x2f\x6e\xf2\x8d\xb2\x30\x4d\xb6\x97\xc3\xae\x1a\xf4\x3a\x50\x0b\x0b\x97\x48\x03\xe9\xf4\x6e\xa2\xa0\x2e\x85\xed\x27\xdd\xa6\x16\xd2\x4d\x6d\xb3\xcc\x4f\x5a\xed\x82\x40\xb1\xae\xa3\xdc\xf6\x9d\xee\x5f\x14\xf9\x5e\x6e\x72\x98\x7b\xbe\x61\x89\xbc\x20\x45\xf0\xd7\x83\xa7\xb4\x7b\xfc\x19\x83\x0b\xc7\xf4\xe7\x98\xab\xe9\x02\x45\xfb\xd4\x3f\x37\xc3\xf0\x36\xd1\xcb\xf1\xe7\x3d\xcb\x1d\x9d\xaa\x87\x37\x9b\x11\x06\x97\x34\x81\xa2\x15\xc1\xf4\xf4\x6c\x16\x03\xa5\xd5\xcd\x97\xb7\x07\x6f\x1f\x5d\xc7\x89\xaa\x6a\x71\xe7\x2e\xf5\x4e\xd3\x28\xa4\xab\x64\x34\x05\x39\xff\xd1\x64\xd0\xec\x64\x5f\x32\x2d\x1b\xc3\x71\x12\xdc\x08\xd8\xc8\x07\x9d\x19\xd3\x7a\xbb\x23\x53\xf4\x8b\x5c\x49\x2f\x80\x6e\xd2"}, -{{0xd2,0xea,0x2d,0xff,0x7a,0xf0,0xba,0x2a,0x6b,0xed,0x7f,0x6c,0xc6,0x8c,0x0d,0xf6,0x64,0xa6,0xb1,0x0c,0xe8,0x01,0xc4,0x2e,0xd5,0xbb,0xe6,0x17,0xbc,0xc8,0xb8,0x4a,},{0xab,0x44,0x70,0x63,0x44,0x02,0x6e,0xd3,0x5e,0x21,0x98,0x29,0x64,0xf7,0xb4,0xdb,0xbb,0xe2,0x07,0xfd,0x27,0xc4,0x67,0x99,0x70,0x1c,0x19,0xa4,0xd8,0x8d,0x1d,0x72,},{0x9a,0xbd,0xb9,0xdd,0x2a,0xb7,0x7b,0x6f,0x5e,0x1b,0x91,0xba,0x0b,0x61,0x3f,0x5f,0x36,0x0e,0xfb,0x50,0x0d,0x3f,0xe9,0x92,0x90,0xef,0x7c,0xa1,0x4b,0xd2,0xb3,0x30,0xf4,0x05,0xa4,0xf7,0xdc,0xda,0xef,0x49,0x23,0xd3,0x11,0x1d,0x40,0xbf,0x03,0x20,0x35,0x33,0x86,0xf6,0x34,0xb4,0x0d,0xe6,0xf0,0x4d,0xe9,0x19,0x0a,0xd5,0x1c,0x08,},"\x03\xab\x5d\xae\xbc\x6e\x70\xd3\x52\x97\x79\x32\xa0\x31\x07\x87\x9b\xd5\x5d\xaf\xd0\xc6\xba\x7a\xd9\x69\x7a\x17\xb1\x27\xb3\xa7\x4a\x3e\xae\xba\xbd\x0f\x8e\xee\xbf\xc0\x48\x3d\x63\xfe\xdd\xe5\x2d\xeb\x46\xa3\x75\x24\x49\xc9\xc4\x49\x5c\x51\xa1\xc9\x1f\x57\xe3\xad\x2e\x6d\x01\xa1\x3d\x0c\x47\x0c\x52\x91\xb8\xe9\x12\x28\x83\x40\x97\x0f\xbb\x85\x78\x7b\x8b\x37\x6d\x72\x17\x52\x50\xe8\xcd\x90\xc0\x78\x88\xbf\xef\x5e\xbf\x50\x86\xc8\xff\x2a\xbc\xdd\x12\xd2\x14\xb9\xc4\x5d\x12\x08\x73\xb4\x60\x2e\x57\xa6\xaa\xb0\xb8\x28\xd1\x08\x4d\xff\xaa\x36\x51\xee\x35\x66\x26\x95\xb7\xf3\x43\x3f\x4a\xb5\x30\xc2\x9a\xc6\xcc\x5b\xb4\x3e\xcc\xd1\xb6\x89\x8b\x9e\xf7\xae\xc6\xd5\xae\xc6\x8d\x5c\x11\x14\xbb\x5d\xf7\x82\x09\x66\x59\x4c\x99\x4d\x64\x08\x91\xb8\xf2\xdc\x5d\x25\x63\x8d\xe4\x35\x49\xd8\x6d\x34\x30\x6f\xf3\xf5\x74\x57\x51\x16\x40\x5b\x9e\x8e\x28\x6e\xe0\xcd\x97\x8a\x76\x00\x2c\x44\x35\xfe\xaa\xc6\xe8\x4e\xae\x16\x54\xf3\x39\xa5\x67\xd8\xd0\x4f\xcf\xa3\xeb\x6a\x04\xb9\xad\xc6\x66\x02\x13\x00\xe9\xee\x59\x72\xb3\xdf\x5d\x4d\x0d\xd4\xbf\x79\x21\xdc\x98\xde\x82\xce\xf2\xd1\xb1\xd6\x1b\x79\x7f\xc9\x96\x8e\x11\x84\x84\xc4\x13\x42\x41\x6d\xdc\x6a\xdc\x4e\xe5\xd6\x87\xd9\x4a\x40\xce\x57\x2f\x42\xa2\x04\x86\x68\xc1\x75\xcf\x7b\x1f\x24\xc4\xef\xd0\x20\x55\x4f\xc6\xf6\x42\xe1\x4a\x57\xba\xec\x23\xe9\x5c\x25\x14\x30\x6d\x0a\x6d\x33\x64\x88\x41\x49\x7e\xac\x48\xea\xbd\x96\xd0\x47\x31\xba\xb0\x8b\xf5\xea\x9d\x43\xe0\xcf\x9a\x37\xfa\xaf\xa7\x32\x86\x9d\x68\xe7\xd5\xfe\x69\x54\xf8\xa3\x19\xef\x55\xda\x1e\x17\x8e\x43\xe8\x4a\x3b\x9a\xa3\xad\x00\xc2\x9b\x1d\x16\x11\x63\xdf\x4b\x79\xf2\x88\xe9\x39\x1d\x70\xa2\xf8\x81\x3d\x66\x62\x2e\x8a\xc3\x33\xfa\x6a\xa5\x31\x1e\xab\xec\x38\x3b\xa4\xcc\x12\x28\x15\xde\x00\x88\x77\xef\xbe\x6e\x12\xc3\x22\xc9\x75\x43\x4a\xfa\xd1\x73\xeb\xe2\x42\x03\xd9\x16\xd5\x75\x78\xbd\x2b\xca\xcc\x78\xf6\xe2\x56\x45\x13\xf8\xd1\x13\xa8\x33\xc2\xc2\x26\xeb\x97\xba\x2e\x23\x36\x1a\x5d\x02\x66\x4a\xb3\x77\xf9\x64\xc4\x30\x0b\xe2\xd7\x7b\x62\xd9\x24\x08\x23\xa0\x98\x84\xdf\x30\x7e\xff\x3b\xe5\x66\x4d\x72\xd1\x1a\xd5\x13\xe1\xbc\x56\x10\xdb\xfd\x10\x09\xdb\x39\xf0\xcb\xfe\x47\x05\x55\xec\x1b\x56\xb8\x71\x67\x07\x93\xd3\xb7\x04\xfb\x06\xee\x95\x0b\x1a\xd2\xa4\xd7\x29\x7c\xa5\x8b\xba\xd8\x10\xc3\xfa\xd4"}, -{{0x7a,0x60,0xcd,0xf1,0x87,0x04,0x60,0xde,0x8a,0xe7,0x78,0x11,0x76,0xd5,0x12,0x7e,0x71,0x20,0x7f,0xaf,0x2f,0x21,0x0b,0xd4,0xdc,0x54,0x73,0x85,0xb6,0x67,0xf2,0xf2,},{0xea,0xd6,0x7a,0x9c,0xf3,0x4d,0x0f,0xf1,0x4e,0x79,0xaf,0xa4,0x6f,0x2d,0xc9,0x96,0xe9,0xac,0x0e,0x3e,0x07,0x63,0x22,0xfb,0xb4,0x00,0x97,0x67,0xb1,0x33,0xf0,0x1b,},{0xb2,0xe0,0x81,0x42,0xbd,0xd6,0x2b,0x78,0x65,0x92,0xc0,0x91,0xf5,0xfe,0x6a,0x9b,0x7f,0x30,0xce,0x13,0x4c,0x3b,0x23,0x6f,0xbc,0x6d,0xfe,0x67,0x34,0xf8,0x82,0x70,0xac,0x58,0xf6,0xd7,0x4b,0x4f,0xd9,0x9c,0x22,0x45,0x1c,0xa4,0x65,0xa4,0x2c,0x00,0x6d,0xb2,0x5a,0xf2,0x15,0xed,0x24,0x1a,0xf1,0x18,0x96,0x27,0xc6,0x05,0x0f,0x00,},"\x9d\xc0\x23\xa5\x25\xd0\x1b\xa3\x51\x37\x98\xb7\x38\xc7\x91\x62\x92\x6e\xbc\xcc\x0a\xdf\x1e\x57\xac\x47\xc2\x0d\xea\x6c\xe1\x37\x5c\x3d\x2a\xaa\x17\x33\xb7\xf0\xc3\xbd\x94\x5c\x33\x5f\xf3\x57\x61\x12\xbb\xdc\x10\xb6\x78\x3b\xa6\x54\xe8\xc6\x10\x47\xf2\x77\x3a\xa2\x29\xbf\x84\x69\x22\xa8\x9c\x6a\x73\xd5\xf1\x05\x1e\x8d\x96\xed\x36\xd7\xd6\x74\x7e\x06\x3a\x7a\xc6\x02\xf1\x9f\xc5\x2e\x02\x1a\x4b\xbc\x28\xb0\x35\x14\xfb\xd5\x1c\x7b\x3f\xd6\x59\xf1\x2d\x54\x7d\x05\x92\xdd\x09\xf8\x73\xc9\xec\xc6\x43\x9c\x7e\x93\x1a\xd0\xe4\x85\x6b\xe3\x1c\x60\x5d\xef\x2e\xd9\xb5\xd1\x3c\x59\x42\xb2\xf3\x25\x39\x7d\xac\x6c\x97\x60\xe9\xb1\xbb\x0c\x06\xf7\x13\xcb\x92\x0c\x23\x4b\xcc\xfe\xe9\xf0\xb8\x5d\xd0\x20\xf7\x98\x8f\x3b\xe1\xcc\x66\xe9\xe5\x1b\xab\xe2\xfe\xe2\x37\xeb\x84\xec\x7e\xff\x94\x09\xaa\x91\xc1\x94\xe3\x0d\xb1\xe0\x65\x01\x59\x55\xde\x97\x46\xbb\xa0\x3f\x7e\xdf\x9a\x58\x75\x12\x40\x9a\x41\x61\xfa\x77\xea\x62\xcc\xf4\x31\x60\x2d\xcd\xcf\x36\x5e\xd6\xbf\x0a\xed\xdd\x32\xf7\xc8\x44\xe3\xa3\x4d\x26\x6e\x28\x38\x2f\x40\x62\xfd\x4d\x6f\x82\x14\x25\x21\x04\xd6\x43\xa9\xbf\xd8\x07\x17\x16\x37\x1c\xcb\xb5\x4c\x8c\xc8\xdb\x79\xad\xd6\x5b\xcb\xce\xa0\xd0\x80\xd8\x40\x28\x03\xfe\x23\x2d\xf7\x0f\x76\x57\x72\x47\xa6\x3d\x55\x83\xbb\xd5\x64\x27\x67\xbc\x63\xf3\xc5\xa7\xbb\x3a\x47\xeb\x12\x98\x4e\x45\x41\xf4\x1f\xdb\x55\x86\x9a\x08\xfa\xde\x66\xc2\x0f\x69\xa5\xa9\xde\x25\xf6\xb3\x6b\xa1\x8a\xce\x5b\x4a\xc3\x36\xbb\x2a\x8e\xbf\x63\x0a\xd0\x3e\x8b\xb8\x73\x1d\x01\xe8\x4b\x91\xd0\x24\xd1\x17\x45\x9a\x74\x89\x2e\x93\xd5\x3b\x61\xe6\xb8\x06\x8e\x4f\x04\xb4\x18\x1f\x03\x87\xb4\x56\x7c\xcd\x45\xe1\xb8\x71\x8a\x2d\x7d\x78\x78\x72\xf3\xdc\xf8\x7a\x15\x93\x5a\xd7\xda\xaa\x74\x4e\xd6\x8a\x28\x66\x6a\x51\xa1\x0d\x39\xfc\x13\x9c\xdf\xe9\xa6\x87\x30\x76\xf7\xc4\x25\x00\x9c\x38\xfa\xee\x13\x5e\x51\x32\x07\xb0\x6e\x7b\xa3\x56\x85\xf5\x07\x2d\xa3\x4b\x60\x45\xb5\x7c\xd5\xd1\xb1\xa1\xfd\xf0\x17\xb8\xaa\x8e\xbd\x27\x52\x2b\xc9\x5e\x47\x90\x87\x34\xe4\x17\x22\xa7\x67\x90\x5c\x5e\xcc\x30\xc7\x24\x81\xb6\xc1\x2b\xf4\xac\xe9\x4d\x5b\xb3\xa3\x15\x56\x91\xb7\x07\x5b\x40\xeb\xf5\x96\x8f\xdd\x90\x3d\x8f\xd3\xcc\x50\xb8\xd6\x46\x48\x59\xb1\x0f\x75\x51\x32\xc6\xd9\xb6\xda\xd1\xd6\xf1\x4c\x41\x85\xb2\x64\xd3\x49\x7a\x4e\x54\x98\x77\xfe\x94\x6e"}, -{{0x33,0x79,0xd2,0x5c,0x11,0x17,0xcf,0x80,0x2e,0xc7,0x9c,0x06,0x57,0x5d,0x18,0xe6,0xbe,0xce,0x4c,0x70,0x93,0xdd,0x43,0xfd,0xee,0x03,0x68,0x5c,0x70,0xb2,0xfa,0x9f,},{0x85,0x25,0x15,0x6f,0xe2,0x9f,0xc2,0xfb,0xf6,0x61,0xba,0x50,0x18,0x2b,0xe2,0x0c,0x89,0x98,0xd9,0x41,0x49,0x3d,0x59,0x33,0xdc,0xa4,0xd8,0xb4,0x1f,0xb4,0x42,0xd5,},{0x4c,0x36,0xbf,0xc8,0x1e,0xef,0x00,0xb9,0xcb,0x3a,0xb5,0x14,0xc6,0xd4,0x51,0xb9,0x93,0x36,0x1e,0x09,0xa4,0xbe,0x4b,0x50,0x40,0x92,0x6f,0xeb,0x0e,0x0d,0x9b,0x52,0xf0,0x3d,0xe4,0x68,0xe7,0xba,0xd8,0x3f,0x37,0x91,0x54,0xbf,0x2c,0x43,0x7a,0x71,0xf7,0x54,0xf3,0xf4,0x07,0x98,0xee,0xeb,0xd6,0x2e,0x55,0xf2,0xbe,0x77,0x14,0x03,},"\x7a\xcd\xb3\x9f\x12\x26\xbd\x3a\xbf\xfa\x50\x35\x0a\x14\x97\xd7\x61\xf8\xf0\xaa\xef\xbf\xbb\xbb\x92\x5f\xf5\x63\xe3\x89\x76\xaa\x17\x2d\x40\x7b\x61\xff\xdf\xb1\xcd\x53\x8a\x4c\xd0\x00\xb5\x78\x18\xa0\xbc\x92\xc0\xe0\xcd\x0a\x5a\xbf\xcf\x57\x83\x00\xf5\xf4\xe6\xce\xfa\x26\x72\x75\xd1\x78\x45\xda\x70\x66\xfd\x4e\x18\x01\x00\x27\x96\x0c\xd3\x95\xe6\x82\xad\x71\xaf\x34\x9b\xbd\xad\x5e\xba\xa0\xf1\x1a\x77\x61\xe1\x9e\xa1\xbe\xf6\x61\x07\x43\x16\x4b\x17\x14\x14\x53\xb4\x72\xae\x2c\x8f\x36\xce\x6b\x08\x0f\x1c\x07\x45\x35\x24\x54\xce\x5a\xea\xe1\x1c\x9d\x75\xde\x3c\x08\x00\x42\x65\xfc\x4c\xa8\x0d\x33\xb2\x6e\xae\x14\x00\xdf\xd8\x97\x7b\xf7\x23\xa6\x16\xda\xeb\x6d\x42\x19\x90\x10\xb7\x3e\x19\x3a\xb7\x2a\x58\xbd\xd2\x48\xa7\xf4\x11\x1c\xa5\x0c\x1d\xe6\x46\xbf\xea\x7b\x4d\x5b\xaf\x0f\x93\xdd\x97\x3e\xe9\x36\x49\xe2\x1e\xc0\xc6\xc4\xfc\xca\x8c\xd6\xff\x69\xdf\x76\x16\x12\x02\x1d\x85\xff\x1f\xb2\xa9\x53\x37\xda\x48\x05\xa7\x6d\x34\x7e\xe7\x1e\xf1\x9c\x0d\xff\xb5\x9f\x15\xf6\x50\x29\x3a\xbb\x97\x21\x05\x3f\x74\x06\x90\x5a\xe6\x83\xf9\x6c\x83\xa3\xa7\x44\x7b\x1a\xfb\x14\xe1\x20\x8c\x63\x9f\x37\xa9\x75\x0b\xa2\x1d\xa5\x55\x2c\xc2\x04\xea\xc4\x53\xca\x03\x62\x82\xf7\xe0\x96\x10\x93\xc3\x9e\xc1\x18\x13\x8d\xcf\x71\xcf\x2d\x28\xfb\x96\xa2\x49\x62\xb5\x2d\x33\x93\xf8\x80\x65\x3b\xcb\xa2\xc9\xb9\xd5\x7b\x77\xc5\x22\xf4\x21\xfc\xf5\xad\x75\xfb\xa9\xcf\x33\x89\xb1\x23\xaa\x97\x52\x17\x13\xff\xf8\x84\x67\xde\xb8\xc8\x99\x1d\x4b\x57\xc1\x43\x81\x70\x53\x7c\xb5\x0c\xdc\xc6\x57\xe5\x0e\x5c\x48\x0e\x12\xc0\xd4\x49\x39\xb6\x39\x99\x44\xe7\xc7\x1e\x18\x6c\x2a\xbb\x81\xfc\x57\x34\x88\x36\xd5\xe5\x7b\x72\xb2\x24\xa6\xb7\x1b\x6c\xaf\x72\x1a\xca\x73\x47\x8c\xb6\xcf\x5f\xb8\x90\x71\xae\x3a\x39\x82\x02\xdb\xb3\x8c\x30\x81\x25\x63\xbb\x9a\x23\x40\x66\x57\xa9\x56\xd3\x05\xa3\x44\x9a\x60\xcc\x86\x41\xb6\x21\x75\xa7\x17\x0c\x23\xbd\x5a\x25\xf0\xf1\x2e\x15\xa7\xed\x91\xfa\xda\x6a\x4a\x2f\x0e\x7b\x15\x5a\x3d\x64\x85\xec\x03\xce\x6e\x34\xdf\x7e\x21\x62\x40\xbb\x28\xa2\xdd\x73\x2f\xf7\x90\xd2\x28\x6e\x20\x0b\x33\xc2\x9a\x31\xa5\xe1\x9a\xd2\xcd\x02\x97\x4b\xad\xc4\xbc\x22\xde\xb7\x50\x4c\x15\x24\x1f\xc1\x06\x0c\x8a\xce\xf4\xfb\xb2\x5e\xc7\x60\x2f\xce\x36\xa2\x7b\xb8\x7b\x6e\x64\x23\xe6\xb4\xf6\xe3\x6f\xc7\x6d\x12\x5d\xe6\xbe\x7a\xef\x5a"}, -{{0xef,0x38,0xc3,0xfc,0x74,0xf0,0x54,0xae,0x43,0xe8,0xd2,0x9d,0x6b,0xa6,0xdc,0x80,0xb5,0xaf,0x84,0x82,0x70,0xd4,0xaf,0x58,0x84,0x4d,0x24,0xbc,0xf9,0x87,0x41,0x4e,},{0x0a,0xe1,0x47,0x8b,0x05,0xfb,0x32,0x99,0x65,0xea,0x0f,0xa9,0x28,0xdc,0xbe,0x81,0xa0,0xbd,0xbb,0x6f,0xf6,0x6c,0x81,0x16,0x71,0x63,0x5e,0x43,0x88,0x88,0x80,0x51,},{0x1d,0x3a,0xc6,0xb6,0xbf,0x18,0xab,0x53,0x09,0x14,0x87,0x99,0x48,0x5b,0x27,0x6d,0x20,0x40,0x1c,0x6a,0xf5,0xf9,0xb2,0xf6,0x03,0x23,0x95,0xa3,0xc2,0xf4,0xb6,0x73,0xb7,0x14,0x0c,0x07,0xcc,0x26,0xf4,0xfc,0x56,0xa5,0xee,0x00,0xb0,0x74,0x6b,0x2a,0x80,0xda,0x6f,0xda,0xd1,0x7e,0xdd,0x11,0x49,0x20,0x10,0x1d,0x2c,0x89,0xc3,0x0e,},"\xbf\x29\x0d\xb3\xdd\xa8\x76\x39\x37\xae\x4c\x83\x74\x67\x05\x32\x72\x95\xc2\xc2\x48\x06\x8f\x5a\xb8\x5c\x8b\x5d\x75\x6f\x4e\x3e\x34\x06\x2b\x55\x49\x38\x72\x61\x47\x6b\xcb\xd1\xe7\x33\x19\x90\xf1\x19\x10\xd1\x1f\x94\x60\x7c\x2b\x71\xf6\x5b\x77\x1a\xac\xab\xdc\x10\xf4\x2a\xe9\x18\xdd\x25\x94\xac\x71\x05\x1c\x85\xb3\x30\x77\x9c\x47\xaf\x00\xa5\xb9\x81\x91\xb5\x6c\xbc\xf7\xef\xe4\x1a\x27\xe8\x7c\x67\x71\x68\xc8\xab\xe9\x49\x6e\xb2\xe7\xab\xbd\x0b\x16\x04\x28\x6e\xd1\xa1\xb1\x8d\x26\x4d\x73\x3d\xe8\x7d\x0d\x3f\x80\x55\x52\x8c\x4d\x42\x6d\x7f\x8e\x6e\xd0\x24\xa7\x41\x40\xab\xd3\x54\x00\x79\x62\xa2\xa9\x7a\x5c\x2f\xf9\x76\x54\x6a\x8d\x1a\xc4\x92\x4c\x09\x22\x3d\x34\x8d\xdc\xd8\x71\x0a\x37\x99\xf9\x1b\xb8\x70\xb3\xf4\x6d\x51\xf1\xe7\xf6\x89\x2d\x6b\x08\xb9\x91\x74\x8a\x03\x7a\x86\x7e\xcc\x39\xee\x8d\x64\x62\xa7\x61\x44\x88\xed\xd3\xc2\xba\x61\x5c\xa2\xe3\x78\x54\x88\x94\x41\xb1\x3d\xc8\x35\xc3\x6b\x38\x65\x3f\x65\x98\x61\x6f\x35\x78\x3e\x2e\x15\x83\x84\xbb\x93\x1c\x90\x1b\x70\x3a\xcb\x39\x91\xfb\x7a\xa5\xba\x69\xd9\xa5\xbd\x05\x70\x24\x29\x61\xa7\x1a\x52\x47\x03\x15\xe9\x82\xe3\x41\xa6\x1c\x64\xa6\x19\xbd\x16\xfe\x81\x19\xaa\xe0\xd7\x50\x3c\xe7\xd7\xe9\x26\x14\x6b\x91\xc2\x89\x2f\x13\x16\x69\xd1\xe3\x9e\x5b\x75\xe9\xc7\x24\x52\x61\x80\x99\xa5\x7d\xc2\xee\x37\x7b\xe6\x58\x75\xee\x01\xbb\x88\xed\x52\x6f\xc3\x94\xe2\xf5\xc8\x12\x7a\x5f\x69\x12\x5e\x67\x38\x5e\xf9\x4b\x1f\x33\xad\x52\x62\x9d\x72\x0e\x31\xc0\x2a\xe0\xb5\x82\x33\x9f\xf0\xf0\xbb\x07\xff\x2b\x03\x0f\x48\xfa\x7b\x69\x27\x16\x50\x1a\xd7\x77\x3a\xd3\x15\x12\x04\xa2\xa5\x40\xfa\x94\x36\xbd\xd4\x20\x2a\x15\x73\x09\xec\x36\xce\xcb\xe5\x8b\x33\xef\xf5\x57\xfd\x33\xe0\x3f\xd3\xeb\x19\x00\x9b\xd7\xa2\xde\xa9\xef\xee\xf8\x78\x55\x67\xaa\xb2\xa4\xc9\x8b\xd1\xf2\xa8\x10\x11\xb3\x43\xa9\xf2\x0c\x44\xc5\x77\xa4\x52\xfd\x54\xba\x21\x02\x9d\x47\x06\x81\x3b\x29\x87\xc7\x6b\xb2\x42\xab\x26\x20\x84\x3c\x22\x60\xb6\x69\xad\x35\x8e\xfe\xe7\xf9\x83\x0d\xc9\xc7\xd4\x78\xa2\xde\x4a\x2c\xf8\xc4\x3d\xa7\x70\xe2\x88\xe2\xed\xbb\x6d\x73\xbc\xf2\xec\xb0\x23\xde\x6b\x2d\xcc\x6b\x16\x6e\x87\xa3\x85\xeb\x0a\xdc\x30\x56\x65\xc5\xbf\xa5\x7f\x25\x0f\xe2\x23\xad\x7f\xf4\x51\x8d\xe3\x9c\x79\xe8\x7d\xc1\x01\xa9\xfa\xa6\x82\x1a\x74\x44\x2b\xfc\xfd\xf0\xa9\xe6\x3a\x50\x9e\x2a\x2e\x76"}, -{{0x7e,0x7b,0x39,0xaf,0x69,0x38,0x0c,0xf4,0x46,0x60,0xe2,0xc1,0xff,0x30,0x83,0x34,0xe8,0x25,0x0f,0xee,0xb8,0x8b,0xe0,0xd4,0x3a,0xab,0xe5,0xe6,0x8b,0x8e,0xf1,0x71,},{0xcc,0xef,0x9d,0xae,0xd9,0x25,0x23,0x53,0x3d,0x4a,0x2d,0xab,0x6d,0x24,0x19,0xf6,0xd0,0x86,0x04,0xdb,0x64,0xce,0x37,0xe3,0x29,0x04,0xac,0x77,0xb9,0xb4,0xa0,0x1c,},{0x10,0x62,0xa2,0xdc,0x9c,0xd5,0x37,0x96,0x75,0xc0,0x4f,0x5e,0x21,0x33,0x8d,0xcf,0xb7,0x7d,0xfb,0xab,0xce,0xdd,0x62,0xb2,0x60,0x71,0x00,0xd7,0x64,0x9a,0x05,0xe8,0x08,0x71,0xe9,0x61,0x23,0x21,0x4f,0x80,0xf4,0xf7,0x3b,0x0d,0x9b,0x06,0xe2,0xd3,0x1f,0x56,0x11,0x9c,0xea,0x69,0xda,0x23,0x47,0xda,0x84,0xa2,0x75,0xb7,0xb2,0x07,},"\xd4\xa3\x97\x6d\xbf\x83\x20\x18\x56\x67\xb5\xa8\x23\x66\x40\xf2\xeb\xc9\xe4\x5e\x6d\x5f\x2a\x8d\x92\x99\x79\x27\xdd\x9b\xc5\xdb\x95\xf4\x46\x34\xbd\x65\x4e\xef\xec\xe1\x0d\x99\xd9\x2b\x46\x71\x57\x91\x64\x50\x04\xac\xcc\x6d\x14\x0f\x32\xa1\xc8\x72\xe5\x4a\xa9\xa7\x49\x3a\xf9\x45\x88\xb7\xbb\x40\x0d\x94\xd4\x58\xd4\x32\x92\x30\x7c\x5a\x1a\x38\x82\xa1\xc8\xa6\xa7\x8d\x9a\x94\x5f\x79\xd6\x4b\x32\x94\xa2\x8c\x3d\x59\xd8\x20\x22\xb0\x09\xcc\x4d\x2d\xa9\x3a\x16\xb0\x71\xc9\xab\x8e\xe9\xa3\x66\x3d\x72\xed\x34\x4f\x15\x1d\x68\xc6\x66\xa4\xb4\x96\x52\xd9\x7a\x46\xd1\x42\xa4\x74\x11\x27\xf3\xc5\x7f\x15\x51\xc4\x09\x76\xcd\x13\x81\xa8\x2a\xea\xe7\xbc\x5a\xdb\x39\x87\x20\xeb\x43\x3f\x08\x99\x48\x7e\xd2\x37\x84\x46\xb1\xa8\xdc\x6a\x33\xfc\xd4\x53\x7a\x05\xfb\x60\x3e\xc0\xa9\x0a\x27\x53\x23\x00\x24\x2b\x20\x00\x10\x86\x21\xb6\x5a\xb0\x00\xbc\x06\x38\x15\x30\xf6\x90\xd7\xe5\x6f\x81\x60\x4d\xac\xff\x19\x10\x71\x50\x40\x41\x0a\xa1\xf9\x44\xc9\x2d\xd9\xbb\xaa\x5b\xd0\x8e\xa0\x0c\x84\x42\xdf\x94\xf0\x85\xeb\x3d\xe9\x73\x35\xb6\x00\x5e\x6f\x84\xf8\x23\xd4\x34\x70\xab\x1c\x67\xda\x12\xad\x44\x99\x36\xc6\xb5\x5f\x9f\xfd\x20\x3d\xfd\x6e\x3f\x33\x30\x9e\x8a\x99\x45\xa5\x93\x20\xe6\x67\x34\xc7\x9c\x48\x14\xdb\xa5\xa1\xc1\x40\x95\xc6\x29\x25\xa1\xe1\x73\x3e\xfd\x94\x81\x7a\x25\xef\x9e\x47\x9d\xd9\xcc\xde\x6c\xa8\xad\xb7\xa8\x05\x3c\x1b\x55\x13\x46\x97\x50\x4a\xf8\x05\x3d\x59\x5b\x84\x46\x40\xb6\x1e\x93\x16\x80\x75\x46\x84\x50\xeb\x5d\xe0\x35\x86\x97\xc1\x04\xaf\xa6\xa3\x79\x6a\x50\x9c\x26\xb4\xc2\x77\xc2\x3f\xff\x42\xdf\x14\x6d\xe5\x5e\x95\xd0\xd4\xb8\x0a\x7a\xa1\x77\xd9\x92\x27\xec\xb2\xa0\x59\x4d\xee\xde\xbb\x9c\xaf\xb1\xa4\x58\xac\xa8\x07\x2c\xc7\xd7\x7c\x71\x75\xf6\x10\xca\x30\x0e\xfd\x7a\xf9\x38\x83\x46\x49\x8c\x22\x99\x15\x64\x50\x0e\x0b\x0a\xa4\xd2\x94\x6f\x18\xe6\xf5\x37\x5a\x84\x82\x86\xf3\x69\x54\xc1\xca\x22\x68\x4c\x69\x28\xc2\xa2\x5c\x7f\xe2\x1a\xba\x4a\x71\x11\xd7\xe0\x5b\xc8\xd7\x0b\x3d\xcb\x4f\x6a\xae\xc0\x64\x84\x5e\xef\x55\x25\xf8\x50\x24\xc2\x57\x0f\x3b\x78\x69\x8c\x4b\xce\xc0\xd7\x1a\xad\x53\x78\xd8\x81\x9e\x1f\xac\x44\xee\x41\x63\x70\x21\x2d\xba\xaa\xe5\x4d\x2a\xf2\x93\x9b\x82\xcb\xaa\xe7\xf4\x2f\xf4\x85\xd4\x5b\x3a\xcc\x21\x09\x0f\x5b\xa4\x1e\xc0\xda\x30\x9e\x52\xef\x28\x38\xd1\xde\x47\x1e\x0b\x7c\xf9\x85"}, -{{0xa9,0x04,0x8a,0xf0,0xc2,0x0a,0x12,0x5f,0x5d,0x39,0xc5,0x0f,0x22,0xb8,0x05,0xae,0x74,0x2c,0xf6,0x4f,0x1f,0xe8,0xdf,0xbe,0x8d,0xfd,0xaa,0x51,0x1a,0xaa,0x57,0x6f,},{0x15,0x86,0x55,0xdb,0x94,0xb1,0x5c,0xa7,0x29,0x83,0x87,0x7b,0x6d,0xb2,0x31,0xa5,0x84,0x3d,0xf5,0xdb,0xca,0x28,0x10,0xa7,0xe4,0x96,0xfb,0x59,0xab,0x71,0x04,0xca,},{0x18,0xa3,0x12,0xb2,0x0d,0x86,0xac,0x33,0x9a,0x58,0xef,0x2b,0x85,0x2d,0x46,0x7c,0x23,0xbb,0x2c,0xb1,0x22,0x7c,0xb1,0x53,0x38,0xaf,0x07,0xfd,0x04,0xb9,0xa7,0x11,0xe8,0x56,0xee,0x5b,0x2c,0x82,0xe3,0x66,0xc1,0x7f,0x86,0x17,0x13,0xd1,0x08,0x8c,0x1b,0x21,0x44,0xd1,0xc3,0x7d,0x05,0xbd,0xc0,0x0d,0x73,0x96,0x73,0x85,0x20,0x00,},"\x8e\xef\x2d\x9f\x5d\x59\x70\x99\x59\xc9\x24\xf8\x7c\x22\x78\x97\x67\x39\x3a\x15\x5d\x5c\x87\xde\x48\x8c\xef\x50\xb7\xbf\x7d\xa8\x70\xe3\xad\xc3\x00\xae\xe6\x60\x3b\x2e\xf0\x87\x64\xd9\x9d\x9e\x77\x51\xe5\xdc\xe9\x2a\xaa\x71\xaa\x18\xa6\x9c\xc8\x23\x13\x4e\x85\x52\xd9\x59\xa0\xdb\xb4\x11\x17\xe0\xa5\x93\xc3\x18\x33\xb6\xec\x21\x72\xdd\xaf\xaf\x78\x48\xdd\xd1\x8d\x28\xd0\xd4\xed\x33\x23\x7e\xc8\x04\xf6\x59\x38\xae\xd8\xe8\xa3\x28\x0d\x42\xe3\x53\xd0\x1b\xe0\x18\x7b\x13\x01\xf8\x3d\x89\x84\x90\x67\xb0\x4a\x90\x31\xf7\xe0\xf3\x3e\x34\x16\x24\x0c\x53\xd9\x26\x5e\xd0\x66\x39\x59\x97\x1f\x41\x7c\xb5\xf2\x10\xcd\xc5\xae\xbc\xb5\xe1\xdb\x7d\xfb\x82\xdf\x43\x58\x76\xa6\xe9\x8f\x41\x5b\x0d\xf8\x69\xf0\xd8\x85\x15\x35\x37\x56\x45\xee\xf7\x0f\xae\xc7\x44\xee\x0d\xc3\xac\xbc\xb0\x40\xf6\x8d\x50\x2c\x2c\x62\xc8\xdb\x45\xeb\xe5\x48\x54\xa4\xb3\x6f\x43\xfe\xb4\x9a\x6d\x1c\x2c\x2e\xa7\x99\x14\xa7\xc2\x3c\x60\xba\xaa\x67\xcb\x47\xb2\x17\x8e\x12\xdc\xe7\x6b\x00\x4c\x87\xb7\xb8\x34\x6e\xfa\xdf\x38\x0b\x9e\x1e\x41\xf6\x31\x48\xda\x51\x78\x1d\x75\xce\xc0\x40\xe4\x26\x88\x20\x21\x1f\x3c\x46\x25\x01\xd8\x08\x99\x89\x4e\x79\xd6\x18\xde\x42\x46\x1d\x78\x5a\xea\xce\x53\xae\x14\xb7\x9d\x33\x50\x1e\xd5\x62\x9b\xbd\xd0\x71\x28\x15\x6d\xb0\x72\x5f\x5b\x4b\xed\x59\x3a\x95\x29\x47\x83\x03\x84\xf6\x1d\xf0\x0e\xe0\xaa\x09\x90\x99\xc3\xcd\x97\x65\xa9\xc1\xc7\xe8\xa6\xa8\x34\x30\xb8\xd9\x86\x7c\x8e\x17\x92\x0a\xd0\xff\x64\xd8\xcd\x2f\xf5\xf1\x14\x38\x8c\xe6\xd4\x3e\xec\x17\x15\xd0\x35\xf0\x22\xfa\x97\x96\x9e\x1a\x5d\xd9\xf5\x8d\x89\x6b\x17\xc1\x22\x1c\x9e\x6c\x85\x55\x59\x72\x35\xee\xda\x6e\xc4\x1b\x0c\x11\x76\x12\xb0\x0c\x5f\x0e\xd1\x81\x6b\x05\x73\x63\x58\x27\x07\xa8\xaa\x0d\x98\xd4\xd4\xbe\x5e\x8f\xa3\x2d\x6c\x9d\x27\x82\x21\xef\x30\x67\xb8\xba\x15\x16\xd9\xe0\x51\xd2\xf6\x8b\x7d\x1b\x15\x1f\x74\xa3\x53\x4e\x78\x12\xc0\x51\xe5\xf2\xb6\x3b\x30\x35\xf8\xe5\x70\x3b\x5f\x68\xfd\x2d\x65\xbb\x75\x65\xe8\xaa\x67\xbf\xd2\xa1\x2c\xaf\x0b\xc5\x48\x11\x97\xa9\xff\x89\xd7\x7d\xf7\xa0\xe9\x65\x5e\xf0\x29\xb4\x3d\xd9\x06\xd0\xb8\x88\xe3\x13\xae\x9d\x1c\x7e\x93\x68\xa0\x13\x52\xd0\x0c\x66\x80\xdd\x0f\x1f\x57\x4a\x58\x77\x34\x8a\x7e\xa2\xc0\xb9\xe8\xe2\x72\x75\x10\xbf\x0c\x9e\xf7\x44\xf3\x69\xeb\x3c\x6c\x4f\xc1\x6a\xde\xb6\xe1\x94\x5b\xe8\x28\x7d\x0f\x30"}, -{{0xf8,0xc9,0x18,0x3f,0x23,0x10,0x5f,0xad,0x0c,0x6e,0x51,0x03,0x35,0x8b,0x58,0x32,0x88,0xf9,0xff,0x6c,0x7d,0xfc,0x91,0x10,0x6d,0x07,0x98,0x7f,0xf6,0x9c,0xe1,0xeb,},{0x4c,0x79,0x62,0x8c,0x95,0x8c,0xde,0x0c,0xc3,0xcf,0x68,0x60,0x95,0xb8,0xa2,0xf4,0x4b,0x71,0x93,0xc6,0x16,0xf5,0x1b,0x21,0xb6,0x70,0xb0,0x38,0xce,0x6f,0x67,0xff,},{0xc6,0xa8,0xbc,0x7a,0x0d,0x5c,0x61,0x85,0xb6,0xec,0xd6,0x03,0x3e,0x42,0x32,0x1d,0x5c,0x87,0x1b,0xf8,0x89,0xbe,0x72,0xbd,0x54,0xcc,0x00,0x83,0xed,0x60,0xa4,0x70,0xb2,0xcc,0x0f,0xb4,0x68,0x2c,0x89,0x4c,0x75,0xb0,0xdf,0x95,0xf1,0xec,0xfb,0xba,0x2d,0x5a,0xce,0xf3,0xe1,0xaa,0xfe,0x54,0xb9,0xf7,0xe8,0x03,0xa1,0xd0,0x15,0x0a,},"\xb1\xd6\x05\x95\x32\x3f\xf3\xc8\x44\x87\x41\x90\xe1\x83\x6e\x41\x01\x40\x9c\xbc\xea\xe2\x8d\x5d\xa8\x1f\xad\x29\x8f\xe4\x7f\x6b\xdf\x44\x74\x5b\x7c\xd0\xd3\x71\x31\xc3\xec\x36\x5b\x92\xf5\xa1\xa6\x9c\x09\xfe\x2d\x9e\x81\xda\x10\xcf\x19\xd8\x5f\xf5\xff\x26\xf9\xe7\xdb\x9f\x07\x93\xb2\x5a\xb2\x6e\x6a\x74\xf4\x4e\xb8\xc4\xf0\x78\xeb\x7a\xd1\x8e\x65\xa1\x62\x10\xd5\xc8\x44\xd3\xce\xf7\x5f\x1d\xaf\x44\xee\xe5\x58\xf9\x0e\x52\x4a\x03\x2b\x6c\xae\x6c\x8d\x23\x36\x7c\x28\xce\x1c\x75\xfc\x25\xac\x87\x43\x39\x77\xd5\x97\x53\x3c\x92\xae\x65\xf2\x91\x3a\x18\x90\x7a\xc7\xd9\x54\x3d\xf2\x41\x27\x74\x39\x43\xfe\xfd\x9c\xf8\x3e\xd8\x33\xf6\x3e\xc8\x36\x72\x33\xd8\x97\xbf\xa1\x2d\x46\x6d\x2c\x4a\x9a\xd7\x0d\x5a\x67\x2f\xc1\x07\x75\xea\x2d\x20\x4e\x63\x6d\xe7\x01\x07\x88\xda\x27\x1d\xf0\x38\x81\xa2\x5c\x8d\xfa\x5a\xf7\x3e\xe5\x59\xf8\x1b\x52\x9b\x35\xaa\x12\x7f\xdc\x0e\xe8\xfd\x36\x9c\x7a\x04\x36\x62\x39\x86\xaa\x64\x07\xfa\x67\xa1\x42\x0c\x46\xf3\x21\x1a\xb8\x4f\x84\x46\x6d\xd5\x8b\xb7\x95\x08\xa1\xfe\xb0\xa5\xa5\xdc\x3b\xb0\xc1\xb2\x48\x09\x82\x62\xa0\x64\xf3\x7b\xb2\xf0\x19\xe2\x90\xc6\x0a\xfa\xa1\x20\x66\x51\xa2\x69\x7c\xaa\xcc\x3e\xcc\x02\xec\xfc\x07\x7f\x27\x2e\x8f\x75\xce\xa7\x1c\x3b\xc3\x35\x6d\x2b\x58\x07\x27\x6f\x19\x55\x00\x1c\xfe\x10\xa6\x17\x16\xb4\x08\x2b\xd6\xf8\x4c\xae\x4b\xb0\xd9\xa4\xb7\x5a\x4b\x57\x62\xf8\x10\x79\xf1\x9d\x7d\x19\xea\xff\x86\x31\xc9\x24\x88\x5b\xd3\xa6\x4e\x12\x9f\x4c\xf6\xb7\x9c\x7a\x98\x29\x66\x55\x11\xe9\xd8\x5c\x74\x5e\xb2\x2c\x1b\x7c\xb2\xa1\x7a\x49\xb6\x28\x5c\xce\x37\xb3\xde\x41\x59\x40\x32\x83\x23\xef\xe2\x4a\x1a\x07\xee\x87\x46\x8f\x65\x10\xe4\x2d\xd2\x06\xfe\x7f\x09\xe3\xd4\x33\xfb\x52\x15\x6a\xe3\x48\x38\x31\x15\x64\x88\x63\xe4\x5b\xf6\xa3\x71\xb1\x7e\x70\xe1\x9f\x96\x27\xd7\xf0\xa5\x8b\x95\xc6\xa4\x78\x8d\x5f\xd7\x86\x2f\x16\x12\xc0\x34\x73\x25\xb7\x97\x65\x1b\xe3\x0c\x3e\x1e\x60\xea\x4a\xe6\x0b\x57\x45\xa3\x8b\x6a\x9d\x4e\xb4\x93\x5d\x6f\x3c\xb8\xd7\x1a\xd3\xf3\x9a\xdd\xa5\xe4\x2e\x22\x19\xde\x0d\x38\x19\x09\xc9\xcd\x31\x7d\xd4\x37\x94\x21\xa2\xa8\x42\x68\xa7\xea\x71\x80\xa6\x4c\x12\x9b\xe1\xe5\xe8\xfc\xbb\xf5\xed\x65\x9e\x9f\x7e\x76\x3c\xe8\x4f\x63\x0d\x54\x07\x95\x4f\x9f\x75\x57\x50\xa6\xdb\xf9\xf7\x66\x07\x17\xde\x8e\x2a\xdc\x1e\x9a\xc9\xee\x31\x65\x4d\x18\x37\xce\xe3\x97\x95"}, -{{0x16,0x08,0x9a,0x1b,0x93,0x2f,0x8d,0x14,0x99,0x56,0x88,0xb4,0x8d,0xd8,0x41,0xed,0xae,0x3d,0xa5,0xcf,0xd2,0xcb,0x16,0x55,0x53,0x06,0xf3,0xfe,0x8b,0xd3,0xed,0xb9,},{0x9e,0xcd,0x9f,0xdd,0x7e,0x0b,0x92,0x3d,0xef,0xf5,0xd8,0x87,0xb2,0x42,0x58,0x5d,0x9d,0x41,0xcd,0x2c,0x7c,0x10,0xf9,0xc3,0x45,0xb3,0x9f,0x63,0x3f,0x4a,0xb9,0x03,},{0x78,0x78,0xab,0x74,0x1e,0xba,0xe2,0x74,0x7c,0x78,0x97,0xcb,0xb1,0xd1,0x05,0x48,0x2f,0x37,0xbe,0x2f,0x5f,0x91,0x79,0x52,0x32,0xcd,0xfb,0xcc,0xc5,0x26,0x60,0x89,0x18,0xe2,0x75,0x6d,0xdb,0x75,0x36,0xb3,0x68,0x0c,0x16,0x2c,0xf8,0xa1,0xef,0x38,0xa3,0x41,0xb9,0x36,0x2b,0xfe,0x5d,0x46,0x8b,0x4b,0xce,0x21,0xdf,0x23,0x4f,0x0f,},"\x58\x50\x02\x32\x38\x8d\x9a\xa4\xb5\xfa\xf8\x5b\x02\x33\x24\x7e\x71\x7f\xd1\x68\x40\xde\x9b\xfd\x0e\xf8\x6e\x01\xe6\x13\x02\x77\x55\x13\xe2\x24\x12\x5e\x0d\x20\x42\x0e\xa9\x49\xf6\xc2\x64\x25\xf7\x00\x77\x91\x1f\x97\x11\x31\x0c\xd6\xfd\x8b\xff\x27\xcd\xea\x11\x48\x0c\x73\xe8\xf8\xb3\xc3\x76\x41\xe7\xe8\xdd\x86\x07\xc1\x64\x02\x18\xfe\xc8\x0a\x02\x09\x28\xb9\x3d\x4d\x55\x7e\xbe\x82\xec\x0b\xb1\x75\x38\x86\x7d\x2c\xb1\x4d\x44\xd3\xea\x72\x7f\xdd\x52\x82\x0b\x0d\xa9\x44\xde\x21\xcd\x5d\xa3\x03\xd7\x76\xfe\x99\xcb\xc2\x64\x83\x65\xe6\xa0\xa9\x8d\x4d\xb1\x50\x84\x26\x61\x76\x8b\xe8\x4c\x68\x50\x7a\x5c\x45\xd2\x07\x84\x0b\x03\x35\x37\x78\x6c\xb2\x1d\xad\xad\x5f\xba\xb9\xc5\xcf\xc1\xe3\x54\x7d\xe5\x50\xd3\x13\x63\x1d\xd4\xfb\xb7\xca\x8f\x71\x93\x86\x27\x60\x8d\x2e\xbf\x65\x5d\xb4\x32\x5a\xbf\x3e\xd5\x04\xdc\x18\x30\x58\xf9\xde\x1e\x44\x93\x12\xd9\x04\xc8\x46\xa1\x84\xa0\x28\xf3\x64\xc0\x28\xb2\x7e\xb4\x94\x64\x27\xe3\x1c\x21\xe1\x05\x1d\xf3\x64\xd4\x99\xf4\x77\xbf\x51\xe7\xa8\x89\x31\x83\xe5\xec\xf7\x7d\x51\x3a\x1a\x76\xb1\xa6\xfd\xfb\x16\xbe\x90\xd7\x4b\xe4\xc4\x34\x5a\x4f\x9f\x87\xee\x44\x1a\x10\x22\xd6\x7e\xe8\x44\x78\x9f\x21\xb0\xc3\x1a\xdc\xc0\xd9\x56\x63\xcd\xfb\x40\xa8\x95\xb9\x22\xdc\xe8\x06\x9b\x93\x2c\x80\x2f\xd3\xab\x1e\xf0\xce\x6b\xff\xdc\xc5\x65\x3b\x1c\xd5\x25\x7e\x19\xa0\x95\x16\x87\xe5\x45\xfa\xf4\xaa\x66\x06\x5a\x55\xc4\xb4\x19\x1e\x34\xe8\x04\x7d\x6a\x4a\xb5\x2d\x1b\x06\xc3\x69\xa4\x26\xca\x2d\x16\xb5\x1a\x02\x71\xf2\x7f\x8d\x74\x4c\x71\x1f\xce\x3a\xad\x9d\x4a\xc0\x38\xee\x70\x0e\x4e\x97\x1b\x21\xca\x48\x9f\xf2\xb8\xc7\x78\xa3\x72\x1a\xdf\x47\xc1\xae\x5a\x41\xb9\xa2\x7f\xa7\x42\xfd\x0f\x18\x16\x4e\xf3\xc2\x6b\x8a\xe7\xd1\xfa\x29\xb7\xc0\xcc\x46\x83\xbe\x65\x02\x5c\x96\x53\x7a\x12\xd5\xfc\xeb\xbd\x05\xe9\x30\xc3\x69\x3e\xbb\xba\x0a\x78\xad\xf5\x9d\x8a\x3b\x59\x8a\x34\x8e\xaa\x9f\x47\xca\xf5\x31\xfe\x44\x96\x52\xdb\x5b\x20\xd6\x89\x94\xe3\x5a\xfe\xc2\xc2\x57\x09\x05\x5a\x1d\xe2\x60\x82\xe3\x91\x2d\x49\x7c\x64\x77\x20\xa3\xf8\x73\x62\x14\x56\xe6\xa5\xb9\xeb\x61\x3a\xcb\x43\xb6\x6d\x47\xd0\xb9\x54\xc6\x9e\x8f\xbf\x2c\x5e\x63\x4c\x48\x6e\x57\x24\x93\x0e\x0b\x56\xa5\x16\x94\x0c\x8c\xb0\xe7\x75\x27\x4d\xef\xf9\x7c\xbb\x77\x59\xce\x90\xa2\xb9\x3e\x9e\xfa\xa6\x24\xe6\xb3\x8a\x39\x84\x9d\xca\x1d\xf6\x12\x73\x6f"}, -{{0x94,0xd5,0x09,0x15,0x14,0x4c,0x7e,0x7d,0xd0,0xf8,0x5f,0xef,0x87,0xed,0xdc,0x22,0x06,0xc1,0x56,0x9e,0xd1,0x43,0x1c,0x8c,0x5a,0x15,0x3e,0x32,0xe1,0xcb,0x2f,0xb7,},{0x3b,0xb0,0x98,0xcf,0x16,0x0f,0x3a,0xec,0x31,0x70,0xb5,0x7d,0x6a,0xdd,0x4f,0x56,0x73,0x92,0x70,0xe4,0xb3,0xa8,0xef,0x79,0x66,0xec,0x30,0x61,0x9b,0x29,0x91,0x02,},{0x59,0xa1,0xce,0x55,0xf5,0xa6,0xba,0xdc,0x1b,0x93,0x91,0x26,0x36,0x20,0x54,0x2c,0xfc,0xae,0x87,0xa0,0xf2,0xb9,0x50,0x22,0x50,0xcf,0xe4,0xbd,0xcb,0xf7,0x6c,0x46,0x19,0x77,0xc3,0x34,0xa4,0x8d,0x91,0x6e,0xde,0xbd,0x56,0xc2,0x1c,0xe2,0x17,0xc3,0x5a,0x64,0x44,0xcf,0xbf,0xd3,0xb1,0x1a,0x3d,0x48,0xfa,0x2e,0xdb,0x6e,0xb4,0x0f,},"\x4d\x91\x5f\x27\x33\x2d\xd7\x50\x51\x71\x9a\x24\xae\x8d\x0e\x9c\x30\xda\x79\x09\x99\xe2\x2d\x9b\x58\x7e\xf2\x03\x21\xbe\xe4\xc0\x7d\x0a\x12\x49\x4f\xfe\x59\x9f\x47\xf9\x69\x25\xf5\xd9\x25\x17\xfc\x3e\x5f\x04\x1d\x0c\x70\x9f\x2a\x97\x83\x12\x5e\xec\xa6\x65\x29\x97\x20\x1c\x42\x9a\xa6\xf1\xce\x2f\x07\xa0\xd4\xa0\xa1\x8c\xf2\x0b\x3e\x9a\x4f\x76\x63\xea\x52\x62\xca\xd8\xf9\x49\x41\x1b\x05\xff\x5c\x5e\xdd\x7b\x30\xb2\x17\xd7\x5d\x8c\x86\xc9\x4e\x5f\x92\xc1\x67\x34\x37\x4e\x8c\xea\xd6\x1b\x0b\x27\xbb\x4b\xf5\xf4\x3a\x31\x3c\x1d\xd5\xb8\x3e\x0e\xa9\x33\xb6\xca\xdf\xed\xd7\xa6\x4a\xa5\xdd\x5b\x5d\x02\xc6\x95\xea\x20\xe0\x91\xfd\xaa\x72\xef\x4e\x7c\xa4\x0f\x38\x39\x5b\xe8\xbf\x7a\x25\x5c\x6d\x06\xa6\x32\xd7\xd7\x85\xd9\xe0\x47\xf2\x32\xaa\x50\xfa\x14\x52\x9f\x98\x6f\x9e\xf9\xd7\xb5\x80\xa0\x39\x65\xb0\x15\x47\x88\x82\x2a\x22\x5b\xb5\xab\x34\x38\xb8\x9a\x5c\x28\x74\x4a\xb0\xbc\x0b\x20\x14\xe5\x79\x6a\xcb\x49\x35\xa8\x1b\x02\xa0\x46\x32\xac\xb8\x8c\xaa\x7e\x39\xe0\x69\xc7\xc8\xe1\x75\x82\x91\x09\x4a\x53\xe3\x62\xfc\xed\xaa\xa5\x83\xec\xa7\x66\xef\xeb\xf6\x9b\x38\xe8\xcd\xe9\xce\x58\xe0\x12\xc6\x0e\xc8\x8e\x8c\x42\xbe\xad\xfa\x83\x8c\xfe\x44\x0f\xa0\xc0\x1d\x65\x9c\x96\x34\x57\x6d\x7d\x7a\x2d\x3a\x04\x4f\x99\xc6\xe4\x26\x3d\x4c\x0b\x37\x4a\x38\x8a\x2a\xcf\x38\xef\xf2\x9c\x77\x7e\x9d\xaa\x60\xd5\x98\x03\x5a\x7d\x9e\xdf\x67\xa5\x02\xc3\xf5\x73\x20\x7b\x11\x9c\xac\xac\x3f\xa7\x1e\x2a\x02\x07\xc6\x01\xcc\x0d\xd6\x37\xef\x56\x2b\xac\xc3\x5c\x57\x04\x27\x38\xf1\xf5\x58\x15\xa5\x26\x80\x82\xcd\x6a\x50\x82\x92\xfa\x29\xe3\x4e\x96\x45\xd8\x7a\x1a\x2b\x6e\x58\xad\xb7\xf4\xa5\x7f\xbb\x53\xe9\x21\x3e\xf3\xdc\x87\x3f\x29\x39\x62\x58\xa1\xea\x54\x6f\xb5\x95\x2c\xe3\x43\xce\xe9\xbb\xb9\x0c\x1c\xda\x72\xc6\x5a\x7c\x8e\x40\x31\x2b\x32\x8e\x23\x19\x20\xc2\x33\x07\x7d\xca\x34\xd0\x4f\x9d\x89\xda\xa9\xa2\xf4\x34\x59\x16\x5f\xd1\x02\xff\x56\x43\xc7\x17\x52\x30\xb3\x9e\xc7\xc3\xc4\x75\x65\x0e\xf1\x31\x60\x9d\x32\x20\xf5\xa2\x94\xa4\x03\xb1\xe1\xc4\x2c\xfa\x16\x2c\xd4\x26\xf0\xae\x43\xfd\x6b\x7a\xb5\x47\xa6\x2b\x7d\x5f\x84\x74\x03\xc4\xe5\x98\x79\x53\x87\x71\x58\xcf\xde\xe2\x3c\x04\xf7\x51\xc7\xc8\x6d\x07\x8e\x82\x4c\xa6\x3b\x5e\x65\x54\x3e\x97\x8b\x6b\x0c\xc6\x89\xef\x66\x44\x12\xb0\x1b\x8f\xf1\x65\xe7\xdb\xde\x3c\x09\x9b\xf4\xf3\x4e\xbd\xdc\xb4\xc4"}, -{{0x0d,0x81,0x92,0x6f,0x51,0x3d,0xb4,0xb2,0x5d,0xfa,0x1e,0x52,0xb5,0xdc,0xa6,0x78,0xf8,0x28,0xa6,0x1c,0x7c,0x91,0x3c,0x82,0x82,0x47,0xc2,0xeb,0x04,0x22,0xb7,0xd1,},{0x0f,0x32,0x41,0x1e,0xf9,0x1d,0x4e,0x4b,0x69,0x41,0xdf,0xca,0xab,0x14,0x2e,0xf3,0xbe,0xc1,0x60,0x98,0x39,0x93,0xa5,0x26,0x2c,0xcf,0x27,0xfa,0xdd,0x2a,0xf8,0x90,},{0xe0,0xcb,0x6c,0x71,0xeb,0xf8,0xd7,0x05,0xe5,0x0c,0xad,0x9f,0x0b,0x8c,0xba,0x3e,0xcf,0x4b,0x9e,0x37,0x93,0x40,0x00,0x92,0xaa,0x5b,0x12,0x1e,0x7d,0xbb,0xc8,0xbe,0xa7,0x1d,0xf2,0x95,0x28,0xca,0x9b,0x47,0xab,0xf8,0x7c,0x19,0x8a,0x8d,0xc4,0xe1,0x4d,0x51,0x80,0xce,0x93,0x2d,0xd2,0x11,0x4a,0x3c,0xda,0xa5,0x55,0x2c,0xc2,0x05,},"\xa9\x38\x37\x52\x2f\x7e\xc2\xe9\x3a\x2e\x4b\x4c\x8b\x46\xde\x92\x6a\x81\xad\xa2\xd2\x48\xbc\xd3\x3b\x39\xb6\xc9\x5f\xb6\x2a\x61\xdb\xbe\xda\x1a\xa8\x5a\x21\xd9\xb9\x6a\x08\x51\x0d\x8d\x3a\x65\x8c\xf3\x20\xa1\x09\x28\x69\x59\x99\xd2\xc0\xd6\x05\xc7\xf9\x5a\x12\xf5\x6a\x87\x18\x50\x7d\xb0\xf4\x97\xe3\xea\xd6\x13\x13\x2a\xb0\x92\xcb\xf1\x9d\x22\x60\x35\x86\x30\x35\x8d\x9b\x26\xe6\x8d\x50\xdd\xae\x37\xc8\xaf\x0b\xb7\xd2\x74\x1f\xd2\x92\x9c\x21\x27\x9a\x78\xd1\x0e\x2c\x5f\x3c\x5b\xf4\xa4\x2a\x36\x17\x03\x6d\x54\x74\x36\x47\x76\x5a\xfd\x8c\xd9\x10\xf8\x1b\x38\xce\xd7\x23\x90\x63\x0e\xe6\x89\x44\xa3\x7d\x29\xc2\xfe\xca\xda\x1c\xc5\x9e\xc5\x44\x07\x5b\xdb\xc1\x4c\x63\xc6\x23\x4b\x88\x40\x49\x00\x0c\x27\xc7\x34\x06\x03\x56\x04\xfc\xa8\x76\x0b\x49\xa5\xe2\x10\x9e\xf9\x12\x85\xad\xc4\xec\x48\xc8\x19\xd6\x2d\x94\x8f\xac\xa9\x0f\x62\xcf\xae\xf0\xb0\x7d\x6f\xe5\x76\xd7\x62\xbf\xd0\xee\xf9\x4c\xf6\xb5\x33\x2c\x4d\x42\x25\x11\x60\x7f\x2f\xac\xc7\xac\x04\x6a\x59\xb9\x61\x7e\x83\x83\xd1\x02\x9c\xc9\x1a\xc5\x92\xb5\x20\x84\x41\x30\x32\xbe\x84\x1b\xaa\x9b\xf9\x62\x51\xa6\xbd\xa6\x71\xd4\xcd\x4b\x12\x5d\xa6\x58\xa4\xe5\xa5\x0f\x44\x28\xee\xbf\x26\x14\xfb\x0c\xe5\xfe\xbe\x80\xf7\x21\xa5\xf4\xc0\x32\x55\x06\xd2\x7a\x8d\x31\xe3\x3d\x86\x25\x38\x70\xdd\x63\xc0\x8e\xdc\x73\x02\xb2\x80\xe9\xb9\xbd\xc2\x8b\xee\xf0\x5c\x7d\xcb\x30\xd4\xc1\x62\xe9\xbe\x83\x2e\x1c\x78\x5e\x37\x55\x12\x18\x42\x1e\xec\x85\x2c\x42\x98\x21\x3b\x2f\x27\xf8\xf8\xc7\x06\xd3\x91\xb9\xc6\x9a\x56\xdb\x7c\xe5\xd8\x15\x48\xfc\xa5\xfe\xd4\x56\xf2\xd8\xaf\xd0\xb7\x5f\x79\xf8\x58\x68\x31\x6f\x4a\x09\x21\xf0\xc6\x63\x99\x26\x51\x6b\x3c\x3e\x52\xa9\xcb\x22\x55\x45\x46\xef\x70\xe1\x4c\x77\xec\xbd\xcd\x5c\x0d\x59\xa8\x17\x69\xb3\x0d\x5d\x13\x1f\x2f\xb4\x49\xc9\x96\xb8\xde\x8a\xc7\xf8\x08\x4f\x84\x99\xe1\xa5\x6f\x7c\xd2\x9d\xb6\xaa\xef\xcc\xae\x8a\x60\xe7\x56\x16\xa1\xf7\x02\xc3\xbc\x8d\xea\xa1\x00\x4a\x8d\xae\x03\x92\xa5\x9c\xee\x54\x81\x0c\x6e\x94\x0e\xee\x25\xfb\x2e\x5d\x57\x32\x67\x04\x4b\x89\x3f\xfd\xe3\x78\xfe\x75\xac\x26\x13\x37\x3d\x84\xa0\xca\x81\x87\xaf\x4a\x33\x58\xe5\x0a\x99\x4e\xd0\x33\x67\xde\x64\x5e\x10\x39\x0f\xea\x4c\x33\xbb\x1a\x6c\x0c\x39\x85\x8b\x8d\xb4\xa6\x9f\xe8\x94\xa4\x22\x3d\x45\xaf\x69\xb3\x6c\x61\x17\xc4\xdc\x25\xde\x49\xa6\x30\x17\x00\x2b\xa9\xae\x55\x1e\xf9"}, -{{0x6c,0x8c,0x53,0xb5,0x6b,0xbc,0xb4,0xc0,0xa2,0x5d,0xc4,0x0c,0x18,0x24,0x0b,0x6a,0x5c,0x75,0x76,0xb8,0x9d,0xde,0x45,0xef,0x13,0xfb,0x15,0x8e,0xa1,0x7f,0x8e,0xd9,},{0x23,0x8e,0x51,0xd6,0xa4,0x4f,0xa7,0xac,0x64,0x26,0x88,0x01,0x26,0x1e,0xa3,0x5b,0x62,0x63,0x8a,0x00,0x6c,0xc4,0x52,0xbd,0xdb,0x9f,0x16,0xfc,0x58,0x03,0x06,0x0c,},{0x4b,0xf1,0xe7,0xd4,0x9c,0xd4,0xd5,0xc3,0xc1,0xfd,0x4a,0x4b,0xc4,0x8f,0xf6,0xb6,0xe5,0x2f,0xd9,0x51,0x0a,0x41,0x18,0x12,0x29,0x69,0x96,0xe4,0xfe,0xc5,0x6b,0xe4,0x45,0x14,0xc5,0x67,0xd1,0xd3,0x34,0x77,0xbd,0x5d,0xc0,0x83,0xc3,0x95,0x8b,0xd9,0x5b,0xfe,0x59,0x9c,0x15,0x3f,0x21,0xae,0x26,0x25,0x29,0x67,0xb7,0x32,0x60,0x03,},"\xb6\x0d\xf2\x94\x4b\xa0\x15\x75\x98\x02\xd3\xc5\x87\xbc\xfe\xbe\x52\x1a\x7e\x77\xb9\x98\x5b\x76\x1c\x96\x76\x45\x4d\x24\xa6\x64\xaf\x0b\x0d\x44\x22\x5a\x55\x75\x12\xe1\xc1\xcd\x7d\xd8\x33\x5c\x8f\x6a\xdf\x92\x8e\x18\xf8\x9f\xd5\xee\xdf\x6f\x41\x1d\xcd\xaf\x99\x69\x12\xe8\xc3\xe2\x3d\x1c\xb9\x5e\xca\x4b\x9e\x24\xe7\x53\x9c\x3b\x98\xbf\x3d\x07\xec\x25\x13\x92\x09\x6c\x19\xac\x53\x74\xdc\xba\x52\x61\x32\xb6\xd9\xbb\x8f\x6c\x85\x9c\xe9\x85\xd5\x84\xc7\xbb\xa5\xb0\x2a\x81\x03\x4b\x6d\x8b\x52\x1b\xd2\x80\xe5\x0d\x77\xda\xa2\xb2\x41\x3e\xd6\x79\x83\x4f\x81\x61\xd5\xd0\x57\x3b\xdd\x47\x6a\xc3\xcd\x0a\x3a\x7d\x8d\xb4\x53\x34\xe8\x9c\x00\xab\x66\xbc\x36\x8a\x07\xb4\x23\xe2\x46\x43\x46\x36\x27\x2a\xa4\xe4\x63\x7a\x53\x06\xb2\xc3\x39\x79\x92\x78\x1f\x30\x23\x8d\xe7\x9e\xc1\x04\xac\xc7\x20\x0d\xef\xad\x96\x08\x83\xd3\x91\x44\x3e\x70\xef\xbd\x22\xf1\xcf\xce\xec\x51\x12\xfe\x9e\x8e\x13\xbb\x94\x1c\x08\x34\x68\xdd\x71\xff\xca\x97\x6c\xd5\x1c\xe1\x61\x79\x31\x10\xef\x00\xaf\xf5\xee\x2c\xcb\x77\x06\xa5\x12\xb8\x5b\xeb\x94\xac\x49\xd1\x9a\xfb\x63\x33\x65\x5c\xf3\xae\xa5\x35\xa6\xf9\xc7\x5e\x03\x48\x41\xe7\x63\xc5\xa2\x49\xb4\x70\x4e\x1b\xe7\x8b\x0e\xca\xc6\x80\x2c\x34\x3c\x1b\x7e\x7b\x57\x70\xde\x4c\x93\xa3\xa7\x9c\x46\xe6\x83\x5d\xa8\xae\x5d\xb3\x83\x8e\x17\x96\xb5\x64\xa4\x80\xa4\xf2\x90\xb6\x0a\x1c\x63\xa7\x25\xff\x3f\xef\x43\x4d\x2a\x0b\x3d\x89\x31\x97\x87\x42\xb5\x25\xc8\x3b\xae\x67\x94\xae\x64\x19\x37\x94\xb3\x70\xc2\x89\xba\x35\xed\x79\xd3\x70\x72\xa8\xdc\xfc\xad\xb4\x6d\x5f\xfa\xee\xba\x1b\xfd\x4f\x87\xd7\x66\xb5\x04\xe6\x2b\x4a\xcd\xd7\x74\x46\xe7\x9b\xa9\x94\xd6\xdb\xf4\x76\x5e\xbd\x74\xb0\x36\x51\x00\xda\x56\x16\x2c\x36\xfe\x5a\x95\x07\x7f\x6b\x42\x65\xe8\x17\x96\xb4\xa5\x74\x43\x78\x29\x70\xb9\x6c\xb4\x56\x9b\xa9\x85\xc5\x5f\xe3\xa7\x18\x38\x0b\xca\x39\xf1\x66\x24\xf8\xe4\x7c\xc6\x3c\x1b\x6f\xa1\xbd\xe1\xae\xba\x9c\x51\xf9\x4b\x70\x2b\x13\x10\x8c\xc1\x48\x1d\x42\xe6\xfa\x98\x1e\x3e\xbf\xe0\x64\xd2\xdc\xa7\x42\x0c\x74\x59\x57\x92\x31\x2a\xe3\xfb\x91\x01\xd4\xb6\x6d\x99\x16\xdf\xd6\xc1\x3a\xe8\x83\xe6\x61\xc6\x28\x22\x8b\xe9\x79\x4c\xf6\x03\x45\x07\x6d\xb2\x61\x84\xb6\x17\xe2\x72\x29\x8c\xd4\x18\x3f\x27\xbd\x52\xd4\x05\x10\xbb\x01\x5d\x20\x97\xd4\xcc\x76\xe7\x6c\x0a\x62\xbb\xfd\xaf\x53\xc7\x26\x87\x75\xbb\xfb\xdb\x88\x70\xeb\x9b\xab"}, -{{0x69,0xb3,0x20,0xfb,0xd4,0x77,0x40,0x30,0xa2,0x97,0x67,0xa0,0xcc,0x15,0x50,0xd1,0x0b,0x74,0x9b,0x44,0xd6,0x19,0xd4,0x1d,0xce,0x11,0x46,0xf7,0xac,0x80,0xa7,0x55,},{0xdc,0x50,0x8a,0x79,0xc6,0xb8,0xab,0x86,0x6c,0xd1,0x17,0xa5,0xa8,0x4d,0xd9,0xd9,0x31,0xfd,0xa4,0x50,0xbe,0xc2,0x93,0x35,0x34,0x4d,0x0d,0x21,0x92,0x16,0xd6,0x5e,},{0x69,0x7d,0x4d,0x89,0x7e,0x0e,0x2c,0xc0,0x2b,0xc1,0xc2,0xdd,0xa5,0x7f,0x0d,0xda,0x62,0x0b,0x37,0xe8,0x61,0x82,0x2b,0xb7,0xf1,0xa7,0x01,0x93,0x5e,0x95,0x9e,0xa0,0xd8,0x45,0x3f,0x74,0x6f,0xb9,0x2c,0x08,0x7e,0xd6,0x5d,0x98,0x0e,0xea,0x1d,0x6f,0xdb,0xf2,0x3e,0x99,0xb2,0x89,0xaa,0xe0,0xdc,0xbb,0x12,0x8e,0xf8,0x36,0x64,0x0a,},"\x21\x7e\x33\xf8\x86\x22\xc9\x6f\x8d\x09\x2c\x9e\x26\x66\x4f\xe9\xef\xc0\xd8\xd2\xeb\x59\xa0\x36\xfa\x46\x4c\xee\x65\xce\x44\x89\xca\xf9\x03\xdc\xe1\x7a\xfa\xfb\xc4\xf1\x8d\xc9\xbb\xfd\x6c\x1a\x4b\xe7\xb8\x34\x85\xa6\xca\x94\x7d\xef\xb1\xd3\x51\x25\xd0\x77\x39\x62\xa3\x44\xa3\x8b\x6d\xca\x9a\x40\xc3\x1c\x1c\x4e\xb2\xd7\xf6\x81\x8f\x97\x8e\x57\x3d\x66\xb9\x90\x92\x1b\x92\xb7\x77\x47\x1a\x4f\x6f\x05\x47\x7e\xbc\x35\x3a\xce\x1d\x86\xb0\x0c\xc2\x51\x77\x7a\xaf\x6a\xf3\xaa\x11\x79\xbf\xf7\x8d\xf5\x04\x8e\x5e\xf2\x99\x68\x67\x0e\x53\x54\x83\x56\x8d\x6b\xb1\x6d\xa8\x29\x56\x8f\x81\xc7\x99\xb9\xaf\xd4\xaa\xd6\xef\x08\x52\x52\xc0\xce\x3a\xc0\x1a\xc2\x1a\x9e\xa6\x9b\xd5\x8e\xad\xc6\x69\x68\xf5\x5d\xee\x38\x6b\x65\x3f\x33\x34\xef\xc3\x98\xef\x3c\x37\xa3\x8c\xe9\x3b\x21\xf1\x07\xcc\x54\xde\xc2\x6f\x53\xfe\xe5\x60\x4e\xb0\x9a\x36\xaf\xe6\xb6\x65\xb6\x32\x4a\x84\xc7\xda\x7b\x7d\xd0\x1d\x92\x78\xe4\x72\xf1\x5a\x5c\xe9\xff\x0f\xd9\x3d\x0a\xa0\x60\x4d\xd2\xdf\x8d\x5b\xf6\xa9\x12\x73\x4e\xc5\x1d\xe7\x7f\x0c\xe0\x99\xba\x11\x67\x02\x10\xa6\xa2\x06\x10\x6b\x0e\xde\x2d\xed\x85\x8a\x6b\xc4\x11\xe7\x61\x3e\x6f\x80\xe1\xaa\x52\xc3\x23\xe3\x0f\xa8\x49\x95\x1c\xc9\xb7\x76\xe4\xcc\x58\xc9\x0c\xfc\x8f\x44\x2d\xf6\x41\x51\xa7\xfd\x4a\x3d\xd6\x1a\x43\x36\xda\x21\xd0\x39\x44\x63\x5d\x3f\xd6\x67\xbe\x74\x1e\xf4\x5b\x1f\x7c\xb2\x76\xd9\xf4\xde\x81\x07\xde\x64\x58\x2f\x79\x17\xc6\xea\xb3\x8e\x0a\x88\x90\xa4\xbe\xe4\x8b\xc9\x26\x17\xa3\x61\xcc\x7b\x1d\x25\xe0\x89\x45\x3c\xe0\xa5\x25\x44\xf8\x68\xdc\xb3\x24\x9d\xe7\x61\xe7\x9d\xf6\x3e\xfa\x07\x94\xe3\xc4\x61\x8c\x55\x47\x53\xee\x28\x1c\x52\xac\x8a\xd7\x8d\x53\x38\xf0\xda\xc3\x60\xa7\x69\x38\x1b\xb4\xa3\x9f\x19\x0b\x88\x7b\x47\x23\x80\x6a\xc4\xa4\xf2\xff\x30\x4b\xc6\xf9\x33\x7a\xb5\x4c\x86\x6e\x6b\xa5\x1d\xf5\x0c\x43\xea\xb5\x2e\x2b\x39\x79\x4c\x99\x17\xe0\xc3\x14\x33\xf0\x36\x81\xd2\xf1\xd9\x3a\x04\x36\x01\x8c\xaa\xae\x20\x20\x6a\x34\x58\xad\x6c\x03\x7a\xcb\x51\x1e\xf1\x28\xf6\xdc\xd0\x53\x05\xf0\x70\x49\xa1\x3b\x6c\x6c\x3c\x5b\x81\x70\xf1\x58\xc8\xf1\x2d\x46\xe1\x60\x93\x1b\xa1\x8b\xd5\x9a\xe1\x29\xec\x07\xa0\x65\x5f\xa4\x82\xeb\xbd\x3b\x85\x0d\x36\xb8\x32\xbb\xb7\x75\xf5\x38\xe3\xc1\xb3\xa4\x3e\xcf\x94\xca\x63\x0c\xa1\x5d\x50\x28\x13\xee\xd3\xe3\x5e\x8f\xd2\x3d\x2a\xb6\x38\x60\x04\x27\xd1\x59\x7c\xb2\x9d\xa2\xa5"}, -{{0x66,0xda,0x8b,0x25,0x4a,0x37,0x06,0x73,0x78,0xf6,0x81,0x38,0xaf,0xed,0xd6,0x64,0x96,0x59,0x6a,0x05,0x85,0x52,0x4c,0x71,0x6b,0xde,0x2b,0x31,0x24,0xc3,0xe7,0xd1,},{0x85,0xbd,0xe2,0x8a,0x92,0x2a,0xb5,0xee,0xaa,0x4a,0x62,0x94,0x52,0x1a,0x2c,0xca,0xc0,0xef,0x23,0x03,0xdc,0xdf,0x8c,0x7f,0xee,0x22,0x8f,0xb4,0x55,0x20,0x12,0xe7,},{0x40,0x82,0xa5,0xbc,0x73,0x0f,0xb5,0x4b,0x6b,0xd0,0xbc,0xd2,0xa0,0x44,0xed,0x5d,0x3d,0x32,0x7d,0xc1,0x9c,0xea,0xc8,0x82,0x5e,0x62,0x9b,0x9e,0x64,0x23,0xcb,0x1c,0x61,0x42,0x36,0xf0,0x97,0xa6,0xb7,0x3d,0x47,0x39,0x47,0xcb,0x81,0xc4,0xe2,0x70,0x85,0x2e,0xe5,0xf1,0x3a,0x5b,0x03,0xdc,0x18,0xe1,0xc9,0xc2,0x7a,0x9a,0x68,0x02,},"\x3f\xae\x36\x63\x88\x37\xd0\xed\xc8\xdc\xee\x51\x7e\x43\xc4\x88\xed\x57\xfa\x6c\x98\x53\xa7\x45\xaa\xed\xfb\x10\x9e\xc1\x40\x9f\xb8\xa2\xfe\x51\xd2\x3e\x0d\xd9\xfb\xfd\x94\xf9\x1c\x18\xe6\x11\x4d\x80\x89\x01\xbf\x61\x7d\x26\x67\xce\xeb\xd2\x05\xc5\xc6\x6f\x5d\x75\x34\xfd\x2e\xc3\x3d\xbf\xe5\x80\xad\x91\x9f\x50\x42\x04\xea\xf2\x42\xaf\x87\x00\xb1\x38\xcf\xbe\x0f\x37\x29\x19\xc0\x6b\x86\x1a\x27\xd7\x20\xd0\x9d\xf2\x0f\x4f\xb7\xb7\x48\xe7\x18\xb0\xfc\x48\x6d\xbd\xfc\xb6\x94\xcb\x3f\x14\x20\x03\x5a\xc1\xbe\x55\xd3\x1f\x30\xf9\x97\xa0\x43\xd0\x47\x08\xa5\xc5\x42\xee\x37\xc0\xf7\xfe\x0b\x32\x11\xd1\x8a\x87\x03\x3d\xcb\x15\xc7\x9e\x66\x81\xc4\x97\x05\x93\xd3\x2a\x13\xc4\x8f\x0a\x3a\xf8\xbf\xc1\x36\xe0\xf9\xb5\x6a\x12\x3b\x86\xc4\xc6\x40\xb6\x50\xcb\x7d\xee\x9a\x89\xe8\x2a\xee\xee\x77\x3b\x5c\xb0\x32\xfc\xa4\x1c\x20\xc4\x07\x32\x8b\xfe\xd2\x92\x44\xe4\x60\x55\xa8\x31\x14\x61\x4d\x3d\xb5\x65\x81\x60\x4b\x11\x5f\xba\x14\xf6\x18\xe1\x02\xa1\xe1\x6c\xb0\x36\xea\x69\xdf\x92\x75\xb9\x77\xa0\x85\x81\x18\xc9\x1a\x34\xb9\xa8\x51\x9b\xd0\xda\xc3\xb6\x14\x34\xea\x08\x8f\x38\x1b\xa0\x8b\xc1\x58\x31\x89\xa4\xa7\xc8\xb6\xad\x18\xf7\x32\xd7\x4e\xff\x3a\xce\xf4\xb6\x90\x4d\xf5\x8c\x64\x69\x43\x21\x51\x37\x2d\xf9\x32\x7a\xe7\x1a\x0f\x35\x6c\x94\x46\x8d\xcf\xc2\xe4\xa5\xc0\xe4\xec\x0b\x16\x6d\x90\xcd\x46\x5f\x92\x60\xeb\xd6\xa7\xa6\x2c\xe6\xc7\x15\xbc\xc7\x15\xbe\x0c\x7e\x1f\x28\xc4\x45\x60\x12\xd3\x31\x77\xa7\xd4\x11\x3c\x9a\x5a\x22\xac\xfa\xf2\xd6\xb6\x33\x09\x07\x8f\xc1\xb1\xba\xa8\xf3\x6c\x7e\x86\x6c\x1f\x97\x2a\x65\x00\xa5\xee\xa7\x92\x01\x65\x1a\x73\x05\x20\x8b\x6c\x93\xc4\x92\xbc\x77\xca\xcb\xc9\x9c\x9c\xde\xd1\x79\xe6\x64\xa2\xf4\xe1\x69\x38\xcc\x26\xfc\xa8\xb4\x33\xeb\x80\x12\xf7\xb3\xad\x19\xba\x1f\xb8\x58\xfe\x4a\x00\xfb\x3d\x1f\x8f\xd0\xed\xdf\x0c\x37\xdc\xdb\x2e\x5d\x35\xc2\x54\x6f\x22\xe8\xc0\xf8\xce\x90\xe2\xdf\x8a\xbf\x24\x82\x7a\x01\x9b\x2c\x33\xfc\x59\x0b\xbe\x71\x2f\x01\x92\x87\x00\x2b\xc2\x21\x7c\x0d\xc0\x93\x1d\xc8\xed\x8f\x50\xbb\x44\x2f\x8b\x2d\xe2\x78\x57\x36\x2c\xe5\xa9\xfd\x97\xf0\xfd\x1b\x2b\x92\x51\xca\xd2\xa4\xac\xa1\xa9\x4d\xe2\xe9\x53\x90\x2d\x72\x28\x14\x24\x07\x44\x3b\x1d\x51\x71\x07\x64\x8a\x7b\xab\x83\x07\x49\x87\xd0\x97\x8b\xc6\x1d\x41\x9b\xc8\x45\x91\xc9\x69\xc3\xd6\xf4\xe8\x6f\xc4\x73\x87\x37\xbc\x05\x58\x75\x5c\x11\x0a"}, -{{0x27,0x65,0x48,0x29,0x0f,0x3e,0x0f,0x90,0x05,0x15,0xdc,0x63,0x36,0x6c,0x03,0xfe,0x0f,0xc6,0xee,0x13,0x0c,0x21,0xfb,0x60,0xa4,0xdf,0x9c,0xf4,0x64,0x79,0x7c,0xda,},{0x7e,0x2a,0x35,0x78,0x00,0x0a,0x08,0x7e,0xdc,0xc9,0xe9,0x4f,0xde,0x50,0x9f,0xc4,0xbe,0x05,0xca,0x0d,0xd0,0x90,0xdf,0x01,0xae,0x11,0x21,0x12,0x35,0x36,0xf7,0x2a,},{0x88,0xa1,0x46,0x26,0x1a,0xd1,0x11,0xc8,0x0f,0xa4,0x29,0x95,0x77,0xe7,0x10,0xf6,0x85,0x9c,0xf0,0xd1,0xca,0x80,0xe5,0x12,0xa5,0x52,0xc7,0x25,0xb8,0x38,0x40,0x37,0xee,0xcf,0x64,0x65,0xce,0x97,0x58,0x5c,0x9d,0x66,0x0a,0x41,0xab,0x91,0x04,0xe5,0xf7,0xc9,0xb2,0xf8,0xec,0x6f,0xb2,0x1f,0x1d,0xdd,0x50,0xd6,0x5b,0x9b,0x66,0x0e,},"\xf0\xdb\x44\x2d\xe2\x9a\x7a\x1d\xed\x55\x0d\x12\x00\x02\xcc\x12\xab\xff\xf9\x8b\x1f\x57\x6d\x65\xbd\xe1\x6d\xea\xba\x68\x7e\x4e\x0b\x0d\x5a\x87\x48\xd7\x50\x3d\xa2\x96\x9c\x64\xd6\xa7\xc2\x8d\x27\xb6\xc9\x3a\xd2\x57\xce\x32\xec\xda\xee\x37\x5f\x43\xff\xf9\x7c\x43\x2d\x45\x3f\x71\x96\xc7\x09\xc3\xbd\xfb\x73\x88\xd4\xd8\xea\xf1\x39\xf1\x82\x94\x0c\xe1\x7b\x45\x52\xe2\xd2\x0a\xed\x55\x57\xba\x4d\x2a\xcb\xf8\x45\x73\x0c\x0a\x66\xb4\x5b\x40\x95\x0b\xaf\x6a\x94\x64\x37\xaf\x6c\x9e\x3b\x33\xa7\x9e\x04\xdc\xea\xe5\x7c\x2a\x54\x95\x42\xea\xbd\x21\x6b\xf1\x39\x48\xd4\x1f\xfb\x94\x83\xfe\x29\x80\x1f\xc8\xc1\x78\x28\x40\xde\xeb\x3f\xb4\xda\x31\x92\x78\x5b\xca\x13\xed\x0a\x9e\xff\x57\xd6\x13\x6b\xaf\xbf\x9d\xec\x69\x7b\x83\x24\x47\xb2\xb6\xe7\x30\xfa\x7f\x99\x95\xba\xc6\xb7\x83\x2e\xaa\x09\x90\x5e\xe4\x9d\x46\x5a\x5e\xe4\x50\xf5\x2d\x1a\x6d\x36\x4c\x61\x81\x44\xe8\x86\xe8\xef\x63\x3d\xc7\x9d\x0a\xf8\x93\xd1\x6b\x3e\xed\xa0\xfe\xfe\xfd\x87\x59\xf2\xa0\xda\x19\x30\x17\x0d\xd1\x9e\xb7\x8f\x0d\x7a\x7b\x74\x51\x54\x03\x37\x5a\x95\xbd\xbc\xce\x01\x8b\xc1\xed\xb0\x8d\x89\x7b\xb7\x98\xa9\x5e\x7e\x86\xa5\x2a\xf3\xd9\xb8\xa4\xa1\x4b\x03\x71\xd6\x34\x98\xdc\xb2\x01\x62\x48\xeb\xd0\xbe\x80\x0e\x9f\x21\xd5\x49\xe5\xe0\xe7\xb4\x89\x5c\xa5\xcb\x72\x5a\x0c\xab\x27\xda\x8a\x8b\x12\x99\xbe\x38\xa4\x26\x09\x00\xae\x10\xdf\x5b\xab\xa1\x1a\xe2\xba\xb7\x17\x9d\xd8\x45\x39\x69\x42\x9c\xcc\x4d\x41\x60\x55\xf2\xbc\xb9\x3c\x1c\xac\x6d\x7e\x80\x4c\xf8\x12\xdf\x14\x62\xf2\x2e\xe9\xe8\x33\xa9\x76\x9e\x8e\x67\x75\x50\x40\x2c\x40\x94\xdf\x21\x2f\xd2\xc5\xfc\xc0\x9a\x72\xc7\xce\x00\x77\x51\x00\x73\x09\x0d\x0e\x63\xdb\x63\x7d\x43\xd4\xc2\x1f\x86\x19\xd3\x4d\xa5\xdb\x08\x03\x3f\x68\x6c\xe8\xb8\xa0\x82\x12\x22\xf9\x54\x34\xac\x4e\x6f\x70\x30\x94\xed\xde\xd6\xfb\x1b\x84\x6e\x97\x96\x50\x97\x9d\x3c\x77\x45\x3f\x40\xf7\xfe\xe7\xc3\xe8\x8a\x96\xfd\x1d\x70\x2e\x81\xc2\xa4\xf3\xf3\x75\x3c\x79\x64\x84\x2d\xfd\x9d\x39\x58\xa7\x43\xda\x06\x3d\x1d\x64\x8e\x51\xb2\x10\xa2\x8e\xd2\x48\x7f\x14\xd5\xf1\xbc\x6f\x33\x9b\x2d\xd1\x7a\x66\x1c\x39\x73\x6d\xa9\x9e\x4a\x4f\x07\x36\x03\x42\xd2\x37\xe3\x81\x3e\xa3\x99\x8d\x66\xeb\x31\xa2\xd7\x08\xaf\x06\x5c\x32\xb9\x27\xf7\x57\xc3\x7a\x80\x06\x60\x67\x4e\x97\x17\xba\x58\xf2\x80\xeb\x2a\xa4\x64\xfa\x74\x40\x21\x08\xa5\xd5\x66\x2e\x8d\x0f\xea\xf3\x29\x68\x7a"}, -{{0x97,0x2c,0x06,0x16,0x55,0x6e,0xf2,0x2c,0x21,0x48,0x68,0xfd,0xd8,0x22,0xc5,0x57,0x39,0xe1,0xf9,0x6a,0x93,0xae,0x83,0x51,0x2a,0xfd,0xa9,0xca,0x7a,0xa7,0x4c,0xd2,},{0x9e,0x1c,0x6d,0x41,0x07,0xf8,0xab,0x81,0x61,0xc5,0xdb,0x5b,0x88,0xa3,0x7c,0xa1,0xde,0x9f,0x4e,0x29,0x13,0x67,0xab,0xb1,0xef,0xc8,0x4f,0x83,0xf7,0x07,0x69,0x53,},{0x54,0xdd,0x06,0xfb,0xb3,0xd7,0xc6,0x3f,0x8c,0xda,0xf7,0x83,0xc2,0xd7,0xba,0xc1,0x6b,0x4c,0x82,0x6e,0x2d,0x1b,0x18,0x07,0xc8,0x4e,0x04,0x9f,0x64,0xe2,0x71,0xb2,0x1c,0xfa,0x3e,0x37,0xc3,0x44,0x26,0x02,0x87,0x80,0x5d,0x71,0x88,0x06,0xb6,0x2c,0x56,0xb4,0x7f,0x6d,0x5c,0x50,0x81,0x25,0xc9,0xfb,0x5d,0x5e,0xa3,0x5f,0xd5,0x01,},"\x86\x89\xe2\xf9\x5c\x8f\xd5\x0d\xc4\x46\x64\xa1\x8f\xb1\xa9\xf2\xc8\xf3\xee\x73\xc0\xf9\x58\x7e\xe2\x8b\xfa\x35\xc9\x23\x1c\x75\xbf\xd3\xd9\x53\x41\x74\xe5\xad\x3f\xa9\xf0\x92\xf2\x59\x94\x2a\x0f\xf0\xba\x2c\xa2\xcb\x59\x04\x3d\x19\x2c\xa8\xe3\xc8\x86\x9b\xed\xd2\x35\x4c\xbc\x5a\xc7\x82\xd7\x27\xc0\xb6\x94\x07\xf6\x8d\x13\x26\xdf\x65\xa6\x0c\x4d\x32\xf8\x7f\x19\xa1\x0f\x3d\x76\x5f\xf9\x23\x43\x4f\x55\x11\xd1\x34\xd3\x97\xc4\xfe\xf6\xbb\x19\x53\xab\xfc\xe6\x08\x27\xc3\x59\xaa\x4b\x54\xf9\x12\xaa\x8b\x17\xb8\x3d\xcc\x7e\x3b\xcb\xc5\x05\xba\x04\x6f\xe5\x7c\x16\xda\xcf\x4e\xe2\xfa\xd5\x38\xbc\x06\x81\x7c\x9b\x9d\x8d\xbc\x5f\x9d\x9b\xbf\x9f\x4a\x93\x4f\x14\xa4\x2c\x29\xe0\xe2\xf3\xa4\x9f\x46\xb2\x0e\xe7\x6c\xfe\x20\xde\xa1\xe9\x74\x50\xeb\x6a\x8f\xda\x04\x81\x68\xdd\x82\x78\x10\x20\x7f\x00\x5a\x3c\xaa\x93\xca\x11\xf4\xee\x60\x8a\x7a\x93\x55\x49\x43\x13\xae\xc8\xd7\x07\x5a\xfc\x94\xc7\xcc\xcc\x75\xc2\x31\x9b\xb4\x58\xc0\xce\x37\x3e\x9d\x00\x7f\x75\x3b\x33\xb5\x27\x93\xd5\x84\x96\xb2\xd2\x5c\xd1\xdc\xd7\x83\x2a\xac\x5d\xdb\x38\xf4\xdb\x19\xc4\x27\x21\x9e\x1a\x04\x20\xea\xd4\x7b\xa9\x5a\xb6\xd8\x9c\x65\x93\x90\x41\xcc\x73\x4c\x08\xeb\x6b\x47\x6c\xaf\x7f\xc7\x6c\x59\x8d\x94\x7f\xf4\x44\xb1\x07\x70\xf6\x29\x45\xae\x65\x04\x4f\x78\x09\x82\x99\xe2\x62\x6b\x63\x8a\x73\x28\xd1\xb7\xda\xa5\x88\x9e\x8d\xb9\x4b\xbf\xf2\xde\xd6\x2e\x14\x46\x37\x60\x22\x7c\x3f\x32\x6e\xd4\x93\x56\x5d\xdf\x0a\x17\x61\xb8\xe4\xbb\x7d\x24\x10\xfa\x0f\xdb\xf3\x56\x84\x39\x7e\xef\xea\x95\x89\x58\x89\xa0\xa9\xdf\xfc\x5e\x02\xc0\x92\x38\x3b\x7c\xe7\x4d\x2d\x90\x93\x99\x16\xf2\x6b\x71\xaf\xd2\x65\xf8\xbe\xc7\x4f\x0d\xe2\x47\xc9\x64\x39\x05\x58\x3d\xf3\xce\xe2\x35\x37\xd6\xb5\x68\xc8\x33\x8c\xe5\xfe\xe4\x2f\x7d\xd1\x5d\xad\x52\x47\xf0\x09\xac\xbf\xd5\xd7\x69\xb6\x36\x69\x59\xcd\x0a\xe1\x50\xf5\x8f\x7c\x80\xfa\x10\xd9\x89\xed\x90\x11\x93\x72\xe5\xfe\xa5\xda\x48\xa4\xe8\xea\x9c\x72\x78\x75\xdc\x4a\x20\x05\xb0\xdc\x2e\x3f\x69\x7c\x0c\xe0\xa4\xbd\xb2\xf7\x50\xc0\x4f\xbc\x0c\x27\xd0\x2d\xd8\x28\x6e\x54\xc9\xc3\x95\x9b\x6f\xfb\xdb\x1d\xe2\xaf\xfe\x9e\x78\x26\x51\xe5\x16\x8a\x50\x0a\xfe\xd0\x37\xb3\xe1\x79\x0d\xdd\x59\x38\x51\xa6\xa6\xcc\xca\x9f\xff\xb4\xa9\x9e\x27\xdf\x43\x81\x88\x71\x53\x6a\xb0\x4f\x14\xa0\x6a\x1c\x7c\xb4\x7b\xed\x62\x41\xce\x74\x30\xad\x3e\x64\x0a\x72\x67\x52\xfa\x06\xa9"}, -{{0xe0,0x40,0x5d,0x37,0x89,0x3e,0x89,0xf5,0x38,0x11,0xd6,0xd4,0x46,0xe1,0xf1,0x93,0xf5,0x1a,0xfa,0x1b,0xbb,0xa7,0x25,0xf9,0x5e,0xb4,0x80,0x33,0x42,0x4a,0x25,0x09,},{0x45,0x10,0x4d,0x59,0x5e,0x44,0x3e,0x8c,0xe6,0x54,0xde,0x9d,0x65,0x50,0x54,0xbf,0x0a,0x99,0xd3,0x56,0x13,0xd7,0x7d,0x57,0x45,0x4c,0xa2,0xd1,0xc8,0x99,0xb5,0x17,},{0x77,0xdd,0xd4,0x91,0xca,0x66,0x2e,0xbf,0xfb,0x12,0xf7,0xf4,0x92,0xd7,0xfb,0xc1,0xa1,0xb4,0x47,0xf6,0xc8,0x59,0x98,0xf2,0xf7,0xcc,0x9a,0xdc,0xe6,0x7d,0xe6,0x3b,0x6e,0xeb,0xd0,0x81,0x17,0x84,0x5a,0x03,0x02,0xf7,0x34,0x97,0x14,0xba,0x9d,0xb2,0xaf,0x58,0x04,0x8b,0x85,0x83,0x7d,0x76,0x60,0xec,0x3d,0xeb,0xee,0xe2,0xd0,0x0f,},"\xdf\x58\xc4\xfd\x07\x02\xa2\x0f\xaf\xa3\xd1\xd4\xfe\x7d\x85\x93\x8b\x12\x0f\xc1\x1e\x8d\x41\xb6\x01\xf0\xe6\x0e\x42\x23\x6a\x49\xf1\x26\x81\x3b\xd5\x12\xee\x71\x35\x90\x61\xe1\x3e\xb3\x14\xd4\x17\xf5\x6d\x6d\x56\x02\x85\xfa\x89\x91\x21\x32\x84\xc4\x2b\xc2\xce\xf2\xdc\x93\x7b\xdc\x0b\x5e\x9d\xc2\x26\x9a\xfa\xb3\x2d\xb3\x0e\x68\x49\x85\x59\x51\xcf\xbc\x53\xec\xfa\x01\x64\x38\x63\xe0\x32\x89\x95\xfe\x85\x0c\x0d\xb5\x54\x21\xbf\xa5\x64\x60\x1b\x8c\x9d\xb7\x55\x2c\x7e\x6a\xa7\xad\xfa\x15\xa5\x80\x21\xa8\x42\x66\xe9\x59\x5c\x65\xfc\xa4\xa1\x5f\xa7\x0f\x55\xf5\xd2\x12\xc9\xe2\x77\xff\xb8\x30\xf4\xca\xd1\x86\x1f\x3f\x49\x5a\x9d\x67\x2f\x56\x91\x31\x06\x39\xc1\x2d\xcd\x07\xe3\xef\x17\xa2\x37\x50\xbc\xb4\x6b\x7a\xd7\xea\xc4\x62\xeb\x51\x22\x25\xf3\xbe\x7e\x32\xf8\xf4\x98\x7a\x11\xdf\x34\x11\x66\x06\x2b\x43\xc6\x3a\xb8\x58\xa6\x00\x49\x76\x67\xfb\xb8\x8e\x93\xc7\xe2\xe0\xaa\xb4\x1c\x09\xc0\x23\xeb\x90\x2e\xc3\xba\xf6\x79\xe2\x5b\x96\xe1\x06\x92\x1a\x91\x4f\xd5\xde\x20\x0a\x47\x88\x9d\xe2\x3e\x7b\x65\xd0\xcc\xdf\x0c\x29\x03\x64\x67\xa1\x21\x0c\x00\x30\x30\x9a\x2d\x04\xec\x25\x6d\x5a\x4d\x8b\x97\xd4\x6a\x3e\x15\xf3\x45\xb6\x67\x17\x08\x03\xcd\xac\xf6\xcb\x48\xad\xd0\xa1\x34\x62\xdd\x30\xfa\x06\x2b\xd4\x56\x66\x41\xda\x07\xd7\xf6\x1e\x06\x36\x86\xed\xd9\x6b\xfe\x8f\x97\xb9\x86\xb7\xc0\xe4\x42\x49\xcd\x2d\x73\x17\x47\x29\x99\xb8\xee\x4e\xa8\x0c\x90\x2f\x3b\x18\x89\x36\x71\x2e\x89\xd8\xbf\x02\xce\x8a\xe7\x7b\x6b\x31\xab\xb0\x63\x20\x65\x45\x5d\xdd\x9f\x9d\x1c\xd9\x53\xa4\xa4\x9a\xac\x1a\x15\x16\x9e\x68\x7d\x4f\xd3\xf7\xc2\xed\xfb\x3a\xab\xc3\xb6\x61\x55\xf7\xd3\x15\xf8\xa2\x94\xfa\xdd\xff\xdb\x49\x51\x36\x7a\x0c\xb8\x70\x75\x9e\x85\xa8\x38\xaf\x66\xba\x3f\xc1\x03\xda\x2b\xab\xc3\xf3\x81\x69\x6e\xf8\x88\x2d\x85\xa8\x27\x8d\x5f\xac\x3a\x72\xf1\x6e\xb1\x19\xee\x99\x00\xb1\xfd\x98\x6c\x2a\x9f\x94\xee\xd8\xe0\xd4\xf2\x73\x69\x7e\x43\x63\xa9\x75\xff\x6a\x7b\x80\xd5\xb4\xec\x53\x55\xbf\x63\xb4\x2b\x71\xcd\x48\x42\x40\x1d\x38\xb5\xe0\x0c\xc9\x7b\xfd\xa4\x0e\x45\x66\x53\x68\x3b\xc8\xe6\xda\xde\x7d\xcf\x98\x5a\x97\xb0\xb5\x77\x6c\x4d\x72\xca\x13\xa1\x47\x4e\x4e\xb2\xec\xcf\xcd\x42\x87\x86\xdd\xd0\x24\x6d\x73\xa6\x37\x7a\x79\xcb\x8d\xa7\x20\xe2\x26\xc1\x94\x89\xbd\x10\xce\xdd\xe7\x4b\x49\xfa\xc2\xcf\xa2\x07\x12\x9c\x6a\x10\x8a\xa1\x64\xbe\x9d\x80\x9c\x4d\x31\x14\x73\x60"}, -{{0x57,0x56,0xe7,0x52,0xdf,0xf6,0x9e,0x3e,0xed,0x84,0x8e,0x4a,0x49,0xc7,0xa8,0xba,0xca,0x12,0x15,0x4f,0x94,0x31,0xde,0xc3,0x56,0x26,0xef,0x8d,0x75,0xa4,0x45,0x14,},{0x59,0x10,0xef,0x00,0xa5,0xb3,0x54,0x14,0x3c,0x46,0x56,0x1d,0xa6,0x2c,0x41,0xaa,0x13,0xd2,0x9c,0x18,0xdc,0x61,0x53,0xbf,0x8e,0x50,0x2e,0x01,0x14,0x00,0x77,0x28,},{0x81,0x57,0xd8,0x33,0x4d,0xed,0x1a,0x32,0x69,0x9b,0x35,0x0a,0xc0,0xd4,0x12,0x00,0x28,0xcd,0x8e,0xf8,0x18,0x94,0x48,0x93,0x48,0x50,0xe5,0x0e,0xe4,0x99,0x9d,0x8f,0xa2,0xcd,0x25,0x76,0x46,0xd9,0x2f,0xba,0x5d,0x66,0x2a,0x82,0x3e,0x62,0x20,0x8a,0xb4,0xfb,0xe0,0x17,0x14,0xa8,0x48,0xa0,0xb9,0x0b,0x55,0xad,0xcd,0x24,0x69,0x02,},"\xeb\x21\x90\xa3\x21\x9c\x79\x2b\x66\x66\xb2\x75\x27\x33\xad\x9f\x86\xfc\x39\x01\x55\xc4\xb4\x38\xbe\x19\x69\x59\x38\x3b\x25\xf3\xa7\x49\x53\x0d\x5a\x4b\x15\xeb\xe2\xc1\x8d\x99\x17\x8e\x6d\x45\xbb\x4a\xa2\x12\x0f\x95\xa3\x52\xe0\x40\x6c\x63\xac\x86\x72\x48\xd9\xef\xba\x12\x42\x31\x06\x48\x73\xc8\x2f\xe9\x95\xdd\x03\x1c\x7c\xbc\x7d\x15\xec\x19\x1f\xbb\x6c\x47\x4d\xc4\xc7\x77\xe8\xf4\x57\x84\x1e\xb4\x62\x48\x41\xc1\x52\xd1\x5e\xde\x26\xe7\x84\x79\xa6\xa2\x5f\xfa\x33\x55\x63\xf1\x06\x4e\xf0\x95\x58\xb9\x10\xe2\x60\x84\x18\x82\x0f\x49\x55\x4b\x67\x0c\x6b\xab\x34\xd1\xd6\x09\x84\xde\xa5\x0e\xd6\xa3\x75\xf4\x5a\x74\xbe\xad\xfb\x04\xbd\x93\x00\xbd\x59\x4e\x2e\x20\xea\x5d\x30\x52\xbb\x7d\xdc\x51\xa9\x49\xa0\x04\x79\x72\x68\x2e\xbe\x66\xd3\x8a\xac\x62\x92\x72\x70\xde\x42\x15\x0d\x58\x22\x1d\x03\xb8\xac\xe3\x58\x99\x33\x48\x7b\xf2\x3d\x29\xc5\xc2\xc8\x43\xae\xfa\x2e\x1c\xa2\x2f\x9d\x16\x80\xf8\x0c\x76\x6d\x14\x3c\xe5\xec\xef\x25\x3a\x74\x5c\xb7\x1e\x72\xf6\x50\x4a\xd9\x11\xf7\xcb\x4a\x81\x9c\xd0\x74\x86\x3a\x92\x70\x69\x29\xa3\x14\x2f\x8d\xb7\xac\x16\x41\x02\xac\x2c\xa0\xd2\xe1\x9a\x72\x5e\x1b\x5f\x81\xf4\x43\xc7\x3e\x04\x84\xf2\x6a\x45\xa3\xae\xf8\x4f\x1f\x3f\xa0\x4a\x4a\xc6\x95\xd2\xda\xb6\xef\xba\x45\x6a\x28\x1a\x39\x73\xcc\x18\x6e\x68\x0a\x66\xdf\x52\x1a\x4d\x1f\x9e\xdf\x4d\xfb\x27\x4a\x42\x70\x97\xbf\x86\x32\x81\xcf\xb0\xed\x80\xf8\xd7\x67\x66\x38\xd6\xcd\xac\x93\x78\x43\xef\xbc\xfc\xe9\x1d\xe1\xdf\x6c\x52\xb5\x94\x57\x1b\x93\x15\x60\x0e\x4b\x65\x52\xde\xfb\x84\x37\xa8\x07\xba\x21\x29\x8e\x3d\x97\x22\x12\xba\x31\x46\x92\x91\x7f\x40\x07\x53\x11\xac\xd0\x09\x39\x52\x41\xb9\xf1\xb2\x56\xc5\x15\x73\x5d\xc6\x74\xf8\xe8\x66\xd1\xee\xb4\xc3\x28\x54\x8a\xee\x71\x23\x1c\x4c\x9d\x5b\xd2\x2e\x39\xde\x88\xd1\x9f\xab\xf4\x9f\x0b\x98\x69\xcb\xf8\x35\x21\x4b\x15\x52\x2a\x93\xd3\xa5\x00\x7b\x11\xf0\xb5\x0e\x52\x28\xd4\xee\xbb\x45\x71\xb3\x5d\xa8\x4f\x4f\x68\x7e\x3f\x43\x79\x3d\x54\xf3\x82\x5b\x37\xa5\x09\xea\x56\x4b\xdf\x21\x7f\xf4\xad\xf6\x84\x7b\xbe\xa4\x31\x6a\x1d\xbc\xc7\x44\x8e\xcd\x53\x63\xea\xab\xc1\x28\xde\xcf\x05\x4e\xe1\xa0\xee\x2d\x87\x19\x79\xf8\xa6\x3b\x26\x92\xb0\x9f\x6e\x98\x6a\x13\x8e\x7f\x68\xf6\x0a\xa4\x26\xa1\xc9\xb0\x1a\x49\x02\xe1\x3b\x17\xbc\x83\x12\x41\x0c\x28\xbe\xd2\x9b\x60\x1b\x0f\xc9\xf3\xbc\x2d\x22\x3f\x87\x52\x51\x10\x0f\x86\x9c\x6b\x58\x44"}, -{{0xb9,0x04,0xac,0xb1,0x9e,0x5c,0xf8,0x72,0xd3,0x64,0x0c,0xd1,0x8d,0xdf,0x3c,0x0b,0x66,0x57,0xe0,0x11,0x7c,0xe6,0x59,0xdb,0xf5,0x02,0x59,0x01,0x5d,0x3f,0xbf,0x32,},{0xe0,0x4a,0x8a,0xa5,0x6d,0x18,0x18,0x48,0x3b,0x10,0xd0,0xa7,0xc9,0x19,0xe1,0xd5,0xd8,0x00,0x1e,0x35,0x51,0x0e,0x1e,0xc6,0x2f,0x71,0x14,0xdb,0xe8,0x1a,0xe0,0xbe,},{0x9a,0xaf,0x8a,0xc9,0x71,0x40,0xd5,0x50,0x8d,0x58,0xf5,0xac,0x82,0xb7,0xfd,0x47,0xe6,0xb1,0xf6,0x8a,0x7c,0x78,0xa2,0xac,0x06,0xf0,0x41,0x6e,0xf8,0xe9,0x91,0x95,0x3f,0x62,0xc4,0x7f,0xd5,0xfb,0xc6,0xc1,0xe0,0x1b,0xae,0x1c,0x92,0xa3,0x3e,0xf5,0x2b,0x7e,0xfa,0x5f,0x17,0xbb,0x86,0x33,0xbd,0xc1,0xae,0xeb,0xce,0x31,0x8f,0x0f,},"\x83\xf4\x12\x4d\x5a\xf9\x55\x13\x9b\x1b\xc5\x44\x1e\x97\xc5\xfa\xc4\x91\xb4\xea\x91\x14\x07\xe1\x54\x20\xa0\x34\x7e\xd7\xfa\x1f\x88\x19\xe3\x6c\x8e\xd5\x74\x0c\x99\xd4\x50\x5a\x78\xb6\x19\xd5\x60\x74\x9a\xf5\x0b\x05\x73\x51\x08\x16\xd6\x13\x22\xcd\xa9\x76\xa5\xd4\xca\x32\x05\xf5\xf0\xe6\x0e\x75\x9a\x5d\xf1\xa0\xbd\xf3\x6d\xfe\x97\x17\x90\x6a\xc5\x7c\xbf\xc9\x70\xab\x43\xb6\xfa\x18\xe6\xc0\x00\x6c\x84\xfc\x72\x54\x47\x0a\x0b\x77\x47\x27\xbf\x5f\x8e\x67\x94\x23\xa5\x31\xe4\x1c\xb5\x31\x0f\x9b\xcb\xf5\xa5\x44\x5e\xbc\x39\xfb\xd9\x09\xce\x11\xe9\x7b\xc2\xf6\x6a\x4a\x1b\xb6\xc2\xf1\x67\xf2\xc6\xe8\x0e\xb9\xb8\xb7\x2d\xf3\xe8\xcf\xd4\xe5\x14\x48\xdc\x14\xc0\xb8\x37\xf2\x94\x96\x93\xd1\xd0\x54\xc8\xf9\x5b\xff\x7f\x1e\x36\x45\x67\xd0\x34\xf2\x22\x3e\x15\x94\x77\x2a\x43\xdc\xfe\x05\x97\xfd\x6d\x13\x3b\x3f\x2e\x96\xff\xc5\x66\x7d\xd5\x92\x8f\x23\xec\x3c\x75\x0f\x84\x59\x93\xa3\x4e\x97\x76\x15\x9a\x68\x30\xd6\xfd\x90\x13\xee\x7a\xea\xa1\xfc\xcd\x69\xb9\x6d\xf2\x84\x70\x4f\xd0\x88\x88\xb1\x5b\x64\xe2\xe9\x0d\x57\x8c\x5c\xfc\x0f\x95\x69\x3f\x6a\xb6\x5c\x69\x47\x44\x6a\x85\x7c\x02\x9c\x7c\xa6\x60\x80\xb7\x54\xc7\x73\x4b\x78\x99\x8a\xbe\x9b\x7c\xc6\xef\xd0\x9a\x44\x18\x19\x4d\x88\xb3\x4e\xc6\xc3\x3a\xf6\x30\xdb\x81\xde\x5b\x99\xfe\x65\xaa\xc8\xb7\x33\x62\x37\x91\x19\xc7\x00\xd1\x07\xed\xfc\x19\xf2\x70\x76\x04\x68\xee\x8e\x5f\x15\x5d\x9a\x34\x7e\x57\xb5\x93\x0f\x32\x7a\x8d\x11\xc6\x67\x4d\xdd\x02\x0f\x9e\x7d\x9b\x76\x1d\xba\x5b\x83\xa8\x73\x02\xf1\x83\x3e\x5a\xbd\x49\x52\x6d\x66\x39\x1e\x5b\xf0\xe3\x5b\x44\x53\xd6\x30\xbf\x7d\x0a\xdb\xfe\x50\x1a\xef\x81\xe6\xc5\x93\x8f\x92\xcb\x75\x2f\x5f\x14\xd2\x80\x6f\x90\xae\x15\x46\x05\x1c\xcc\x7f\x91\x3c\x5d\x6a\x38\xff\x3b\x7b\x9a\x23\x66\x2e\xf1\xf0\x08\x08\xed\xb2\xfa\x31\xec\xba\x5c\x8d\x33\x87\xe8\x75\x41\xcd\x06\x16\xed\xbf\x3a\xaa\x35\xa5\x37\x92\x28\x61\xf4\x4c\xbd\x9f\x99\x2b\x82\x46\xd9\xc6\x4c\x41\x98\x81\x70\x1a\xb4\x3f\x7f\xd4\x64\x21\x0d\x80\x2b\xa6\x56\xd9\x5c\x0f\x24\xa3\x45\x99\xb2\x0b\x1e\xc2\x00\x11\x48\x5c\xfc\xb3\x18\x6b\x7b\xcf\x69\xd7\x45\x81\xa7\xa3\xee\xd6\x13\x4c\x4e\xec\xd6\x55\x74\xa4\x32\x0d\x9c\x57\xa8\x49\xc4\xe7\x8c\x8a\x5c\xe8\x25\x05\x00\x4a\x54\xf1\x9d\x4b\xdc\x82\x23\x40\x1b\x34\x94\x6b\x7d\x66\xe4\x7e\x63\xcf\x9d\x0f\x57\xd0\x94\x54\x91\x38\x4b\xc6\x86\x8c\x4b\x47\x86\x90\xe5\x50\x02\x1d\xf1"}, -{{0x8a,0x35,0x01,0xb7,0x69,0x53,0x60,0x3c,0x90,0x33,0xe3,0xbc,0xbf,0x3e,0xc3,0x78,0xd2,0x57,0x01,0x1a,0x6c,0x50,0xb8,0x97,0x62,0xd4,0x91,0xea,0xa7,0x2c,0x5e,0x0d,},{0x77,0x8f,0x20,0x19,0xdc,0xd8,0xdb,0xb8,0x6c,0x67,0x37,0xcc,0x8d,0xc1,0x90,0xc5,0xa0,0x4c,0x50,0xb5,0xbf,0x45,0x88,0xbc,0x29,0xfa,0x2a,0x47,0xaf,0x25,0x26,0x72,},{0xa8,0xa3,0x09,0xba,0x52,0x12,0x5e,0x76,0xa4,0xa6,0x1e,0xb4,0x3f,0xd4,0x13,0x5c,0x41,0xab,0x11,0x79,0x9b,0x91,0xcc,0x54,0xff,0xc9,0xc6,0xa2,0x0f,0x05,0x0c,0xc5,0x95,0xb2,0x81,0x43,0xc8,0x74,0xbd,0xb9,0x28,0xbe,0xed,0x26,0x1d,0x9c,0x0f,0x12,0xaa,0x19,0x2e,0x66,0x40,0xbf,0xda,0xd5,0x4b,0xa0,0xd4,0x78,0x42,0x6b,0xce,0x09,},"\xe6\x09\xf1\x22\x4a\x6a\x45\x11\x40\xcb\xc0\x25\x4d\x43\x2c\xe5\xfd\xdd\x08\xa8\xe9\x12\xf8\x1c\x41\x2f\xdf\xd5\x18\x2f\xf6\xac\x2f\x13\xc5\x76\xc8\x14\x5b\x15\xf2\x5b\x40\x9d\x85\x3f\x91\x44\x09\xe4\xe0\x2c\xef\xc3\x9d\x9b\xef\x4a\x2a\x06\x04\x98\x57\x0b\x2d\x3a\x28\x38\xc9\xb0\xb8\xe3\xaf\x4f\xc3\x7e\x19\x15\xf8\x04\xa8\x01\x88\x58\x5b\x30\xb6\x8a\x3f\xfb\x2e\x96\x0c\x73\x20\xe8\x27\xd2\xfe\x36\xe6\xa3\x28\xcc\x6e\x78\x06\x34\x8a\xdb\x0b\x77\x3b\x78\x4d\xe5\x29\xbb\x6f\x64\x75\x1b\x21\x05\x85\x94\x94\xfd\x49\xdb\x0b\xc7\xf6\x2d\xf4\x6b\x9d\x7c\xe6\x76\x97\x5c\xc5\xf4\x38\x56\x49\x84\x36\x81\x2e\x04\xf2\x6f\xb8\xb8\xab\x7e\xba\x12\xf1\xd5\x67\x22\xeb\x82\xeb\xfa\xfa\x47\x35\x97\x7a\x26\x68\x1c\xb0\x3f\xa4\xbc\x69\x51\xab\x9c\xbd\xf7\x87\xe3\x27\x8f\x2f\x57\xf2\x9e\x12\x09\x5f\x8c\xa2\xa1\x78\xcf\xa7\x57\x13\x37\xf0\x27\x42\x37\x66\x9f\x97\x65\x7d\x4b\xad\xb3\x94\x36\xd7\x86\x49\x25\x80\xfd\x55\xd8\x6b\xe3\xa0\xcd\x17\xd1\x60\x57\x01\x7b\xaa\xae\xa0\x0c\x1e\x14\x55\x21\x59\xbc\xab\xc0\xe6\x66\xba\xd3\x41\x8e\x4e\xc1\x3b\xfe\x16\x3b\xe2\x56\xf0\xc8\x9b\xc2\x34\x4a\x8d\xdf\x99\xca\x81\x60\xb1\x89\x87\x5a\xd3\x22\xd9\x0f\x58\x13\x25\x28\x1d\x53\x89\x96\x5c\x0a\x7b\x7b\xca\xe2\x29\x4a\x3c\xbe\x35\xa4\xe4\xe8\x3b\x54\xc4\x27\x63\x53\x96\x0f\xad\x11\x85\x32\xd4\x9b\x70\x76\xf2\x5a\xd1\x90\xab\x56\x94\x91\x4f\x71\x08\xb0\xab\x69\x69\xa1\x91\x28\xfb\x0a\xef\x00\xe6\x5a\x04\xfc\x83\x2d\x07\x69\x61\x67\xb9\x34\x2b\x35\x5e\xc5\x77\x37\xca\x37\xcb\xff\x3b\xb3\x19\x31\xcb\x58\x71\x2a\x4c\x46\x89\x52\xc6\x45\x9d\x56\x7a\x26\xe7\x95\x01\xe4\xe3\x1b\x1b\x09\x53\x53\x76\x32\x02\x9e\x9b\x49\x0f\x72\xe5\xa6\xe0\x57\xdd\xb4\xb3\x17\x56\xfd\x97\x04\x21\x8b\x1b\x8f\x4d\xcb\x54\x30\xc0\x25\x04\x2f\x47\x16\x9b\xfc\x7c\x80\xd7\x1c\xab\x8c\xa0\x7f\x34\x0a\xfa\x00\x8a\xbb\xe2\xe3\xa0\xab\xe1\x41\xda\x8d\x41\xca\x6b\xd6\x9d\x36\xfd\xb1\x1a\x41\xce\x0b\x72\xfa\xbc\x00\xd9\x7e\xa6\x05\x27\x00\x10\xb2\x59\xdf\x8e\x10\xdd\x22\xdc\x17\xc1\x39\x90\xa0\x5f\x02\x33\xe3\xca\x85\x6b\x40\x97\x1c\xb3\xe2\x1c\x8b\x39\x50\xb1\x3f\xc8\x4e\x1f\x26\x6c\x2a\x6f\xbe\xce\x88\xd5\x97\x25\xc3\xcf\xb2\x22\x5d\xbc\x1e\xe9\x5b\x68\x6d\xb7\x04\xfc\x93\x7b\x76\x6f\x0a\x9b\xfe\x95\xa4\x2b\x90\x10\xf1\x22\x9c\x61\x0d\x7e\xde\x09\x57\x12\xc8\xf0\xf1\xfb\x00\x47\xc0\x40\xa8\x70\x30\x6c\xd8\xdc\x74\xc4\xda\x51\xbf"}, -{{0x42,0xb5,0x36,0x52,0xd0,0x8b,0x5d,0x76,0x6e,0x66,0xad,0x8f,0x3e,0xbf,0x69,0x3c,0xfd,0x77,0x90,0x7c,0xad,0xd9,0x8b,0x54,0x66,0xdf,0x77,0xdf,0xa2,0xc6,0x37,0xad,},{0x88,0x46,0x3b,0xb8,0xa4,0xb6,0x38,0x8d,0x92,0x4c,0xb8,0x62,0x09,0x83,0x41,0x95,0x43,0x5d,0x79,0xd7,0x7f,0x8c,0x02,0xf4,0x6b,0xbd,0x16,0xd8,0x2e,0xfe,0x42,0xb3,},{0x30,0xc4,0xb9,0x9e,0x68,0xec,0x33,0x51,0x30,0x8f,0xbc,0x76,0xd9,0xca,0xf0,0xaf,0x62,0x21,0xb5,0x96,0xb7,0x01,0x7f,0xe1,0x0c,0xc6,0x33,0x02,0x3b,0xa9,0x7f,0x02,0x38,0x96,0xfe,0x32,0x2b,0xaa,0x34,0x76,0x60,0x61,0x0e,0x05,0xfa,0x49,0x3d,0x21,0x8f,0xa3,0x60,0xf1,0x8d,0x93,0xe2,0x75,0xd1,0xef,0xf6,0x66,0xb6,0x3d,0xb2,0x04,},"\x9e\xe9\x13\xc7\x4e\xe3\xc5\xe8\xc9\x0d\x64\xb8\xae\x3a\x60\x04\x9f\xc7\x65\xe1\x76\x06\x0b\xcd\x1c\xd0\x9f\x0e\xda\x60\xbf\x23\xba\xdb\x8a\x1c\xaa\xc3\xd6\x6e\xbc\x52\x68\x14\x6e\xe4\xa5\x4e\x1e\xb2\x31\xed\x25\xef\xf9\x5b\x90\xa6\xe9\x83\x37\xa5\x40\xa3\xf4\x84\x49\x79\x4a\x48\x73\xbf\xc2\xe8\x47\x28\x96\x6b\xb7\xc6\xff\x67\x6a\x2f\xf5\x73\x11\xc1\xc2\x5e\x15\xfb\xf3\xd4\x0e\x9f\x25\xab\x5d\xb9\x1f\xdd\xb7\xa0\xae\x43\x6c\x8e\xc0\x70\x75\x4b\x6d\x74\x3a\xa1\xd6\x04\x8f\xb5\xbd\x7f\x5b\x8e\x4c\xca\xd2\x03\x28\x38\x95\x30\xf1\x13\x74\xa4\x89\xb1\xd5\x05\x31\xa3\x9c\x9b\x32\xb4\x03\x69\x62\x60\x06\xd2\x64\xa9\x9e\xec\x4f\xac\x13\x41\xf4\xe7\x46\x79\x45\x7b\x41\x8e\x6b\xbf\xba\x23\x3f\x1c\xa1\x58\xf7\xb2\x9d\x40\xd5\x03\x01\xf9\xd9\x25\x36\xfd\xc5\xc2\x3f\xe5\xde\xe4\xd6\xdf\x0e\xbf\x13\xdf\xa3\x75\x4a\x14\xc8\x56\x00\x9a\xde\xa1\xdd\xa4\x09\x30\x4c\x1f\x60\xd2\x53\x30\xfb\x10\x95\x79\x47\xa0\x05\x08\xf2\xfd\x76\x42\x2e\xac\x69\x4c\xc3\x9f\xa8\xae\x7f\xcc\x77\xa0\x2f\xd9\xee\x5f\x91\x0d\x93\xe8\xaa\xc6\x8f\x14\x5d\xd8\x78\x87\x6b\xa8\xed\xa0\xa4\x9f\xcb\x20\x9c\x34\xea\x22\x0d\x4d\x06\x05\x54\x6f\xc4\xa8\x09\xba\xf0\x10\xd5\x33\xe4\x5d\x17\xb0\xe1\x6a\x46\xe9\x1e\xa6\xfe\xc2\xcd\xc5\xa8\xb3\xec\x50\x14\xb2\x5e\x92\xd8\xe5\xc9\x28\xab\x06\x99\x3d\x4f\xe2\x3a\xc8\xd4\x5c\x89\x03\x78\xdd\x13\x3f\x00\xed\xb9\x37\xc0\x71\xf7\x5c\xfc\x13\xa4\x02\xe3\xe4\x29\xa8\x48\x65\x2a\x17\x5c\x9b\x6f\x6e\xac\x86\xf6\x18\x8a\x44\x48\xa9\x6c\xe2\x87\x2e\x5f\x65\xf9\xbd\xb8\x71\x66\xc9\xb8\x7a\x7e\x95\x8e\x80\xbb\x65\x66\xe3\xfc\xf8\x71\x19\x0c\xf4\xa8\x67\xe6\x12\xcf\xc1\xe4\x37\x1d\x2b\x73\xd2\xa0\xad\x0a\xa4\x00\xba\x69\xe6\x63\x36\x23\x3b\x0f\x3c\x52\xb8\xa6\x8b\xca\x05\x12\x56\x01\x25\x50\x46\xe6\xf4\x9d\x68\x8d\x2d\xb8\x5c\x7b\x82\x12\x70\x51\x6e\x3c\x06\x13\xf3\xf2\x3f\x9c\x57\xcb\x4c\x87\x14\x28\x5c\xdf\x95\xe1\x06\xa3\xb5\xaf\xca\xeb\x81\xb7\x2f\x34\x3e\x87\xbd\x92\xf1\x58\x1d\xcf\x9a\xa9\x0a\x02\x4f\xa4\xa1\x04\x80\x59\xe3\x0d\xe8\xff\x0d\x16\x79\x4d\xcd\x74\x5d\x2b\x2d\x53\x4c\x52\x0f\x82\x78\x53\x86\x74\xa9\x34\xc6\xf1\x4a\x84\x28\xe3\xda\x01\x8a\x36\xe4\x5a\xa5\x82\x7c\xf4\xb1\x52\x84\x34\x6f\xd6\x93\x63\x14\x92\x19\xbb\x0d\x1b\xc9\x27\xd8\xd1\x93\xc4\x82\x69\x2f\x97\xdc\x88\xd8\xed\x33\x7d\x0c\x9d\xc9\x9c\x7a\x5e\x11\x1d\xce\xd4\x22\x50\xd5\x80\xe2\x06\x92\xbb\x7b\x88"}, -{{0x14,0xcf,0xe0,0x0f,0xa7,0x19,0x0a,0xe8,0x10,0x88,0x8a,0xe2,0xbb,0xd0,0xff,0x64,0x12,0xcf,0x1f,0xd4,0x08,0xa3,0x08,0x29,0x43,0x83,0xa1,0x94,0x53,0xb5,0x90,0x73,},{0x4e,0x61,0xaf,0xe8,0xc1,0x74,0xb6,0xee,0x1a,0x29,0xfa,0x09,0xcf,0x87,0xb4,0x00,0x81,0x39,0xf1,0x07,0x0b,0xc8,0x53,0x1b,0x6d,0x06,0xf5,0x4c,0x95,0x62,0xa4,0xf3,},{0xf7,0x85,0xa4,0x6f,0x69,0xbb,0xd0,0x99,0xfa,0x01,0x11,0x24,0xba,0x90,0x32,0xc1,0x89,0x74,0x2c,0x9e,0x00,0x1d,0xbb,0x87,0x81,0xd8,0x22,0x33,0x45,0xa9,0x56,0x9d,0xc1,0x44,0xca,0x69,0x4d,0x90,0x24,0x5e,0x0e,0x51,0x3e,0x88,0xab,0x02,0x3f,0x7f,0x0f,0x99,0xb7,0x41,0x61,0x59,0x75,0x8d,0xd0,0x34,0xe7,0xa8,0x9c,0xff,0x36,0x00,},"\xbc\x66\xf8\x01\xda\xa8\x29\x85\x8e\x74\x02\x93\xd4\xd2\x18\x7b\x8e\x1a\x5a\xfb\xa5\xfd\x67\xb1\x09\x56\xc6\x53\x46\xac\xa9\x44\x29\xd3\x2e\x4c\xfb\x35\x84\xab\x0e\x00\x5d\x0d\xd7\x42\x78\x1d\x47\xe8\x94\x47\xc4\xe1\xd8\x1b\xf7\xe6\x15\x4f\x8f\x73\xaf\x03\x36\x1a\xd5\x6e\xa3\xc0\x60\x00\x75\x4b\x9f\x32\x7d\x4e\xde\xac\xc4\xd3\x48\xaf\xb5\x48\x23\xe1\xc9\xd4\x9c\xd8\xff\x2b\x19\xf4\x20\x21\xb4\x0d\x58\x0c\x39\xce\x3d\x24\x36\x61\xb8\x54\x21\xfe\xc9\x15\xba\x9d\xd2\x76\x2f\x85\x0b\xd2\x08\xfd\xbf\x20\xff\xab\xa5\x6a\x46\x86\x60\xf1\x7c\x00\xfb\x1c\x0f\x4e\x85\x27\xa5\x09\xdd\x4e\xec\x13\x36\x0c\xf6\xe3\xca\xc5\x42\xb8\x75\x18\x2f\x2a\x7c\xe7\xbe\x0a\x33\x30\x2f\xe2\x6d\x36\x29\x62\x93\x84\xe3\x5c\x06\x78\x9d\xe6\x34\xe9\x0e\x96\x4f\xbd\xa8\xcb\xba\x98\x11\x1e\x22\xe8\xd0\x76\x26\x84\x26\x6a\xab\x76\xae\xba\x4a\x38\x07\x78\x69\x68\x14\xa1\xe3\x11\x94\x3c\xb3\x50\x58\x92\x64\x0c\x44\xe3\xaa\xc4\x53\x0c\x50\xac\x60\x4a\x8d\x2c\xcc\x7c\xea\xbf\xfe\xa4\xaa\x3d\x7f\x48\xa6\x6d\xcd\x75\x88\xb8\x02\x09\xdb\xc1\x73\xf0\xc6\x63\xe8\xfc\x87\xa3\x6e\x89\x2e\xc9\xa3\xff\x8f\x60\xd2\xe0\xd8\x70\x4e\x5b\x6c\xbb\x87\x32\x75\x15\x1a\xd4\xcc\x00\x57\x16\x50\x31\x90\x50\x39\x65\x1c\xa1\x0a\x95\xc6\xfd\xa3\xb2\x78\x27\xa6\x57\xef\x9a\x5f\xc3\xeb\x5b\x53\xca\xc6\x1d\xda\xf5\xa4\x17\x04\xc8\x78\x57\x0c\xbc\x3c\x41\xc4\x75\xb1\x17\xc0\x5e\xab\x0b\xb1\x96\xbc\xb7\xc4\x33\x34\xde\xbd\x64\xb9\xe3\x74\x50\xd2\x3f\x5c\x10\x16\x1e\xc5\xab\x4f\xcc\xd7\xcf\x30\x8e\x2a\x99\x95\xcc\x9e\x57\x8b\x85\xe8\x28\x5a\x52\x08\xb9\xef\xd4\x2a\xf9\xcf\x2a\xc2\xb3\xb7\x46\x42\x54\x88\x9a\x21\x87\x31\x7e\x32\x49\x97\x09\xb9\x13\x95\x3a\xd4\x6f\x1c\x23\xe1\xb6\xb5\x6f\x02\x4c\x4a\x7d\x48\x46\x11\x92\xc0\x1c\x56\xc5\x4c\x56\x47\x91\xec\x0a\x67\xb6\x1a\xcb\xf9\x57\xe6\xd0\xd7\xda\x80\x53\xed\x13\xa4\x18\x93\xd7\x67\xfc\x57\x37\xcd\x19\x55\x53\xda\x5d\x5b\x07\x06\x5f\x47\xd7\x2a\x35\xc4\x2b\x00\x1e\xb6\xdb\xd0\xf8\xe7\x7a\x4b\x76\xa6\x26\x61\x92\x64\x7f\x41\x55\xea\x11\xbd\x12\x37\xba\x77\xc8\x7c\x62\xbf\x4b\x01\x14\x9f\xc5\x8b\xc2\x8f\x0b\x5a\x28\x64\x85\xd3\x71\x7d\x32\x39\x64\x04\x62\x18\xe7\x0c\x7e\x38\xb7\xd5\xe7\x4b\xa6\xb1\x2b\x02\x2f\x18\x19\x7d\x92\xc1\x3b\xca\x89\x33\x5c\x85\x6c\xbc\x57\x56\xaa\x3b\x64\xec\x1f\x46\xe3\x96\xb1\x16\x1c\x87\x1c\xd2\xdf\xde\xd1\xa4\xec\x91\x92\x74\x29\x37\xc0\x70\x45\x31\xc7"}, -{{0xac,0x0f,0x7f,0x04,0x18,0xde,0x67,0xe3,0x48,0xfa,0x6d,0x56,0x86,0xc4,0x6d,0x21,0xca,0x72,0x62,0x2e,0xe6,0x9e,0xaa,0xbe,0x00,0xd5,0xc9,0x07,0x5a,0x34,0xf1,0x79,},{0xfe,0xab,0xde,0x08,0xf0,0x0a,0x2b,0x68,0x2b,0xce,0x9d,0x45,0x99,0x0b,0xf4,0x5a,0xfc,0x95,0x83,0x39,0xdc,0x44,0x10,0x6d,0xad,0x33,0xb2,0xc4,0x90,0xef,0x70,0x90,},{0x75,0x91,0xcf,0x82,0x57,0xbe,0xad,0x39,0xa1,0xad,0x3b,0xa1,0x91,0x8d,0x51,0x8e,0x67,0x24,0x35,0x6b,0xf6,0x25,0xa5,0x73,0xea,0xe5,0x01,0xd1,0xaf,0x94,0x6c,0x13,0xc2,0x90,0xcb,0x63,0x15,0x6e,0xc9,0xd3,0x62,0x72,0x6e,0xe5,0x0b,0x39,0xfc,0x0a,0x7a,0x2b,0xbd,0x69,0xd4,0xa8,0x1b,0x75,0x93,0x2a,0x90,0xf8,0xc7,0xac,0x7d,0x03,},"\xe8\xd0\xe8\x32\x53\x35\xe0\xf3\x5a\x85\x46\x7b\xee\xd1\xe1\x1c\x6a\x20\x78\xc3\x5a\xe4\xa4\xa1\x05\x43\xed\xe4\x0c\x17\x12\xbc\x95\x20\x12\xd2\xf8\xfe\xc1\x05\xae\xf7\xc6\xc6\x5b\x36\x34\xb4\xa7\x4b\x22\xb4\x98\xb9\x13\x50\x7d\x1f\x6c\xfd\xe8\x38\x58\xe6\x83\x0c\x0a\xf4\xf4\x64\xa6\x89\x9d\x5c\x4e\x27\x9a\xff\x36\x75\x4c\x21\xda\x80\xa1\xbb\xd1\xdc\xf4\x62\x20\x37\x5b\x1e\x11\x2a\x5a\x72\xf1\xab\x6e\x8f\x64\x19\x42\xf6\x6d\x9b\xbd\xbb\x17\x9c\xf0\x13\x9e\xa8\xde\xb0\xf4\xb8\x14\xf5\x0c\x51\x33\x29\xa1\xa0\xe2\x67\xc4\x43\x3a\x23\x31\x82\xbc\x4a\x2a\xcb\x2c\x6d\x4f\x00\xb2\x40\x94\xd3\xbd\xc0\xeb\x81\xcf\x37\xd3\x82\x60\xc2\x10\x7d\xd9\x49\x06\x13\xd2\x76\xee\x1f\x72\x26\x6c\x6e\x4a\xcc\xa5\x24\x98\x11\xa0\xf8\xa7\xda\xe6\x6a\xed\xb7\x5c\x3d\xf4\xc8\xca\x3c\xb5\xd9\xc5\x67\xba\x54\x1e\xe5\xa9\x14\x0c\x50\x58\x72\x72\xaf\x34\x53\x0a\xb8\xb0\x8b\x9e\xc0\x32\xea\xc0\x60\x39\xe6\x92\x63\x0e\x2d\x55\x4d\xf7\x7c\x1a\x03\x88\xb3\xca\xaa\x3b\xe3\x75\x4a\x84\x96\x1f\xb2\x99\xe4\x02\x22\x71\x58\xce\x36\x3e\xac\x26\x47\x8d\x47\x97\x75\xe5\x68\x5a\xdb\xf8\x28\xbb\x35\x5e\x3c\x89\xcc\xe2\x41\x50\x3c\x15\x36\x64\x32\xba\x94\xcd\x3c\xd9\x54\x79\x14\x4b\x63\x6e\x0d\xe7\x0b\x3f\x16\xd1\xa3\xca\x51\x8e\x39\x90\x09\xa4\xc2\x47\xa7\xf9\x63\x67\xc7\x14\x66\x08\xaa\xcc\x00\x14\xfc\x35\xb8\x4a\xf9\x93\x3f\x09\xba\xbb\x89\x93\x7a\xbb\x8c\xed\x11\x18\x91\x34\x3d\xdb\x79\xf6\x0b\x78\x89\x8a\xb5\x93\x8f\x8b\xa3\x81\x4b\xd8\x00\x26\x05\xb1\xdf\xd2\x97\xfa\x07\xc4\x75\xa0\xd4\xf8\xf4\x45\x1a\xcd\x70\x7d\xe8\xaf\x6c\x0e\x88\x18\x83\x3a\x3a\xbe\x5c\x96\xd1\xa8\xc6\xc9\x6e\x2c\xb6\x33\x28\xeb\xa4\x4d\xd1\xd3\x46\x84\xe4\x12\xf2\x88\xe0\x65\x20\x9d\x11\xeb\x80\x94\xd2\x2e\x4c\xc8\x02\x62\x9c\xcb\xa3\x39\x26\xbf\x1a\xd3\x6a\x62\x85\x13\x8a\xbe\xe0\x5c\x5a\x39\xa4\x75\xf3\xfd\xd0\xb3\xec\x8c\x37\x0c\xd9\x57\xa8\x37\x9e\xc2\xcd\xaf\x03\xe8\x95\xc1\xba\x12\xb4\x49\xd6\xcd\x8b\xe0\xf3\x5d\x99\xe2\xb7\xfb\xaa\x92\xdd\x54\xe6\x4e\x7c\x35\xce\xb8\x8a\x71\xa6\x80\x52\x7c\xb3\x73\xaf\xe1\x4c\xdd\x15\x8a\x0b\x90\xbf\x2d\xae\xc8\x0d\x2e\xdb\xdc\x31\x28\xcd\x6b\x63\xfa\x53\x2a\x1c\x27\x8c\xdf\xe0\xf8\xeb\xb4\xab\xba\x5e\x1a\x82\xbc\x5c\x3f\xed\x15\xc5\x79\x5b\xd9\xff\xb5\x76\x08\x2c\xc4\x79\xfa\x1b\x04\xc5\xc5\xaf\xca\xd2\x69\xa0\xf1\xad\xdf\xe7\x60\x42\xc3\xa8\xf1\xf2\x53\x77\xb6\xcb\x72\xec\x16\x14\xeb\x63\x83"}, -{{0xb5,0xa7,0xc7,0x67,0x93,0x63,0x80,0xb3,0xe9,0x87,0x51,0xca,0xfd,0x3e,0xa8,0x9b,0x38,0x8a,0x32,0xcf,0x82,0x8b,0x32,0x1c,0x5b,0xd0,0xcc,0x8d,0xd8,0x5b,0xaf,0x00,},{0xbe,0x7f,0xa6,0x5f,0x1f,0x6b,0xe5,0x10,0x27,0xf8,0xb8,0x48,0xdb,0x7a,0x8c,0x40,0x49,0x61,0xbf,0x1e,0x21,0xa2,0x3d,0xf2,0x3b,0xb8,0xce,0x05,0x85,0x0c,0xda,0xa1,},{0x60,0xe4,0xd2,0x3f,0x1f,0x08,0xfc,0xe4,0x66,0xc9,0x91,0x5d,0xde,0xd9,0x32,0x56,0xb5,0x2b,0x32,0x7e,0x5f,0x81,0xfb,0xb3,0x1d,0x1d,0x10,0xd3,0x21,0xc3,0x90,0x36,0x6e,0xf0,0x01,0xfd,0x75,0x9a,0xa9,0xd0,0xa5,0x51,0x62,0xd5,0x36,0x4d,0x91,0x8b,0x48,0xc7,0x32,0x7e,0x77,0xcf,0x53,0x58,0xbc,0x43,0x19,0xe3,0x25,0xcd,0xd6,0x08,},"\x6b\x67\xc7\x95\xd6\x6f\xac\x7b\xac\x84\x42\xa6\xc0\x99\x2c\xb5\x75\x88\x43\xb3\xe3\x93\x9e\x3c\x27\x6c\x6e\x90\x08\xda\x82\x00\x76\x77\xbf\x9e\x67\xe9\xac\x5a\x1a\x0f\x48\x6b\xea\xc0\xd8\x56\x19\x1f\xae\x25\xa1\x27\x39\x2b\xed\x46\x9b\xc7\x8d\xeb\x0c\x4b\x89\x3f\x67\xf1\x71\x6d\x83\x50\x90\x77\xe4\xa1\xbf\xd4\x13\x6d\x03\x15\x2d\xcc\x3b\x76\xd9\x52\x49\x40\xa6\x06\x4c\x66\x9f\xbf\x51\xf6\xb9\x10\x34\xb6\xd5\xf2\x89\x86\x78\xa1\x3a\x24\x70\xf6\x64\x1e\xc8\x02\x45\x7c\x01\x02\xc3\xeb\xf6\x34\x5c\x32\x7e\x74\x1b\x80\x64\x4b\x3a\x99\xbf\x72\xb5\x9a\xb8\x01\x6f\x35\xd2\x51\x88\xa0\x85\x75\x0d\xc0\x60\xe5\xa8\xd5\x24\xae\x21\x3f\x07\x8f\x28\x8c\x7b\x34\xbc\x41\xf3\xce\x35\x6b\xf2\xda\xfd\xd2\xe0\xdb\x4f\xb8\xd7\xc2\xc3\x19\xf9\x90\x60\x05\x97\x17\x02\xe4\x9c\xa6\x2e\x80\x50\x54\x0d\x41\x21\xd2\x42\xf2\xee\xab\x1b\xd1\x34\xe6\x0b\xf1\x1b\x3e\xc7\x1f\x77\x65\xa9\x7c\x0e\x09\x84\x55\xe5\x9d\x22\x35\xd6\xb3\x7e\x7c\x9f\x5b\x21\xfa\x11\x2c\x3b\xa3\x9e\x4e\xa2\x00\x61\x4f\x58\xdf\xb3\xeb\x7b\x83\x6f\x0b\xec\x1d\xdd\x43\x8d\x14\x22\x45\x0a\xe7\xde\xd1\xdf\x9d\x71\xe5\xd9\xbc\x8f\xa3\xb6\xe6\xf7\x84\x46\xce\x7c\x79\xd0\xbc\xfb\x1c\x2d\x26\xc6\xfe\xce\x68\x68\x2d\xff\xc6\x0a\x9c\x6e\x0a\xd0\x5f\x2a\x09\xf2\x1d\x75\x23\x25\x1c\xb0\xc3\xd0\x8e\xfb\xbf\x8a\xc1\x63\x39\xd7\x17\x02\x4d\x67\x60\x24\xc1\xee\x3c\x1f\x62\xc5\xae\xab\x7f\xff\x93\x7c\x57\x45\x4d\xf7\xbd\x96\xf9\x84\x4a\x2a\x39\x99\x58\x41\x8a\xaa\x6f\x18\x48\xbe\xbf\x7b\xf1\x29\x2c\x24\xeb\x5c\xd8\xea\x56\x34\x0c\x5b\xeb\x26\x88\x02\x4a\x69\x53\x27\x5b\xe6\xef\xd1\xb7\x1b\xa8\xbe\x6e\xb7\x7f\x0c\x65\xa7\xc5\x11\x1b\x96\xc4\xc1\xf3\x9c\xb7\xaa\xf8\x3f\xda\xae\x8d\x14\x8d\x7a\x8a\xf4\x0a\xe9\xe6\x51\x91\x9f\x7c\xe2\x8c\x8b\x2b\x6e\x45\xe4\xd3\xd5\x6f\xdd\x54\xd0\x0c\x24\x12\x79\x0c\xbd\x6f\x80\xe1\x08\x19\xe0\xb8\xf3\x7c\x84\xfa\x00\x49\x88\xad\xaf\xcc\xbb\xc2\x1c\x63\xd6\xbf\x2e\x73\x2d\x9d\xd6\x3b\xd4\x9b\x04\x12\xb9\x67\x4e\x1e\x88\xf6\x14\x2f\x7f\x86\x7f\x1f\x26\x89\x1b\x22\x43\x04\x23\xce\xc4\xdb\x91\xb6\x1c\x2a\xbc\x5c\x8f\xbd\x46\xb8\xb9\x35\x96\xfc\x51\x60\x68\x31\x36\xe2\x11\x29\x82\x27\x96\xeb\x5e\xa0\x88\xe0\xa7\xd8\x12\x1b\x25\x57\x2e\x3e\xc3\x77\x43\xd1\xff\x6d\x8d\x1c\x35\x36\x43\x9a\x10\xe8\x4a\x66\x5f\x2c\x75\xee\x73\xcd\xc6\xff\xac\x4c\xc2\x87\x24\x46\x9f\x79\x70\xb4\x75\x07\xdf\x3e\x1b\x14\xd4\x77\xae\xc2\xbb\x20"}, -{{0xe1,0x36,0xf3,0x98,0xa6,0x05,0xd1,0x34,0x57,0x84,0x8c,0xea,0xd0,0x7c,0x72,0x86,0xf4,0x2e,0x2f,0x28,0xdf,0x8c,0x12,0x8a,0x3d,0x0b,0xb7,0x2b,0x29,0xaa,0xcc,0x19,},{0x6a,0xa5,0x04,0x5a,0x66,0xf7,0x72,0xa5,0x71,0xfe,0x3e,0x42,0xd1,0x17,0xef,0xcd,0xf6,0xc4,0x95,0x91,0x99,0x61,0x86,0x01,0x2f,0xa9,0x8f,0x7c,0x48,0xe0,0xcd,0xa7,},{0x75,0xa4,0x5c,0x6b,0x95,0x66,0x89,0x98,0x29,0xb4,0x1e,0xe5,0x17,0xb7,0x04,0x5a,0x47,0x3a,0x4f,0x7a,0x26,0x41,0x43,0x9b,0x5d,0x7c,0x56,0x73,0xe0,0x0d,0x8f,0x5c,0x06,0x6f,0x12,0x91,0xf8,0x5d,0xea,0xda,0x05,0x02,0xbd,0x16,0xe9,0x70,0x9f,0x82,0x7d,0x47,0x51,0xf2,0x87,0x38,0x62,0xe8,0x21,0x9e,0x57,0x74,0x6a,0x19,0xa9,0x00,},"\xd3\x28\x57\x9d\xe4\xc5\x37\x2f\x3b\x38\x2c\x48\x01\x1b\x2d\x4c\x60\x29\xf9\x04\xf3\xa3\x3e\x07\xd0\x83\xd7\xe2\xb0\x37\x56\xaf\x2c\x4c\x97\xa2\xd6\x6c\x10\xec\x41\x54\xd8\x74\x79\x20\x42\xb6\x46\xe4\xaa\xe5\x10\x1d\x50\x1b\xd1\xbf\x6f\x51\x17\x51\xd0\xaa\xf8\x21\xcd\x7c\x0b\x3e\xe6\xd0\xd7\xc6\x90\xa2\x77\x7f\xe1\x6b\xdc\x7e\x49\xb7\xda\x4b\xbb\x4c\xce\x3b\x61\x8e\xe9\xb6\xf2\xe3\xa1\x92\x40\xcd\xb7\x07\x33\xb9\x84\xb1\xc9\x40\xec\x66\x96\x0b\x72\x8c\xbb\x87\x4b\x80\x64\x31\x23\x72\x2d\xb9\xdb\xbe\x88\x32\x20\x08\x93\x1b\x1c\x89\x4e\xf5\xd2\x10\x99\xe6\x3e\x7c\x65\x00\x7a\xcd\x61\x78\x4d\xb4\x99\x4a\x2f\xb4\x0c\x3e\xfe\x9c\x47\xfa\xd6\x37\x63\xdd\xe0\x6f\xa0\x17\xa2\x6b\x82\xe7\x1b\x9d\xaa\xbc\x4f\xf0\xf6\xc7\x9b\x8c\xa7\xcc\xb4\xdc\x20\x31\xbe\xf1\x08\x73\x67\xc7\x08\x69\x74\xa0\x05\x66\xde\x41\xa7\x1e\x11\xd9\x93\xab\xe4\x33\x56\x98\x92\xb8\xf7\x5d\x76\x37\x99\x32\x45\xc8\x84\x47\x8a\xbe\x3f\x95\xf4\x4b\x0a\x4b\xbe\xde\xfe\xf8\x90\x6b\x75\xe0\xd3\x40\x20\xae\x53\x64\x55\xb0\xe0\x6f\x9b\xfe\xe1\x1e\xc9\xb8\x60\x4b\xac\x2c\xc6\xeb\xe0\x8c\x8f\xd5\xf5\xcc\xcc\xcb\xc1\x61\x7b\x7c\xf6\x9a\x3c\x51\x2e\x1f\x0b\xdb\x58\x5d\xf5\xe1\x27\x43\x06\x1f\x7c\x20\x53\xbc\x37\x14\x43\x61\xc0\xb3\x5f\xd3\x9d\x56\xb1\xef\xaf\x92\xc6\x10\x36\x01\x93\xec\x20\x59\x8b\x82\x85\x80\x50\xa6\xd9\x9e\x08\x2b\xce\xfd\xbd\x53\x18\xee\x5e\xfb\x3b\x26\x0f\x32\x76\xf3\xc7\x3f\x9c\x24\xce\x0c\xda\x33\xc7\xac\xc5\x0c\xa5\xdd\x61\xbd\xb8\x5d\x79\x38\x25\xf6\x73\x2a\x6e\x33\x0c\xe6\x72\xac\x44\xfe\x6b\x2b\x9a\xfe\x6e\x2e\x96\x5c\x02\xd2\xa1\xfe\x0b\x57\xcb\x1b\x31\x7c\x1d\x31\x3e\xfd\xc3\x56\x49\x2f\xe8\x96\xfd\x14\x9d\xae\x51\xc9\x5c\xcd\xbb\x7d\x11\xf7\xd6\x10\xe0\xc6\xe2\xfd\x3e\x57\xfc\xfe\xf1\xc5\x7c\x71\x19\xa0\xaf\x6c\x78\x21\xfe\xcd\xb8\x9d\x80\x30\x2b\x49\xfa\xd4\x17\x43\xf3\xd2\xd7\xa0\x75\x15\x4b\x31\x43\xe5\x1a\xeb\x94\x7d\x4b\x5e\x8b\x7e\x4c\xa8\x6f\xec\x3e\x80\xbd\x9a\x78\x6e\x4e\x46\xed\x1e\x6e\x9f\x7e\x0b\x63\x52\x66\xd9\xfa\x09\x7a\xa9\xe2\x0f\x32\xe3\xd2\x77\x2d\x7c\x1f\x00\x8b\xcd\xd3\xf9\x2c\x72\x83\xc5\x77\x90\xc3\x62\x2c\xba\xd3\xca\x35\x80\x3c\x45\xc8\x69\xdc\x37\x7f\xf3\x6b\xd7\xc0\xe6\xf1\xbb\x89\x2f\x73\x29\xa6\xe0\x8d\xf1\xdb\xeb\xc8\x1d\xc7\xb1\x15\xf8\x52\xe3\x6a\xe5\xd9\x28\x72\x5f\xa7\xc6\xfb\x9f\x28\xb0\xfb\x39\x4f\x9e\x38\xfd\x87\x62\x5c\x5f\xa2\x3a\xab\xa4\x70\x54\xe8\xcf\xea"}, -{{0x97,0xb6,0x70,0x2e,0x24,0x68,0x05,0xdb,0xcf,0xc7,0xfa,0x42,0x4a,0x8c,0xaa,0xbc,0xf2,0x62,0xd4,0x66,0xa0,0x5e,0x0d,0xd2,0xd4,0xe7,0xc3,0x74,0xd5,0x7d,0x52,0x51,},{0xa7,0x16,0xc3,0xd5,0xce,0x78,0xf4,0xd9,0xc5,0xbe,0xe3,0x44,0x7d,0xda,0xf4,0x88,0x1c,0x98,0x6e,0xfd,0xf6,0x67,0xac,0x89,0x77,0xb4,0xfb,0x69,0xb5,0xa7,0x11,0x0a,},{0x90,0x00,0x55,0x41,0xdc,0xc1,0xd7,0xab,0x83,0x7f,0x4d,0xe5,0x39,0x3f,0xad,0xd6,0xa9,0x2b,0x26,0xa7,0xd9,0x3a,0xf3,0xf6,0x69,0xe0,0xf1,0xbf,0xd6,0x21,0xcb,0xd0,0x0c,0x8a,0x23,0x05,0x6d,0x2d,0xa6,0x78,0x65,0x57,0xc8,0x28,0xa4,0x9b,0xe1,0xe4,0x02,0x1d,0x99,0x31,0x12,0x35,0xac,0x0d,0x4d,0x56,0xee,0xfc,0x7c,0x95,0x36,0x05,},"\xea\xa8\x6c\xf7\x6f\xcb\x65\xc6\xf9\xfc\x20\x8a\xc3\x6f\x28\xb2\x00\xd3\xb4\x03\xac\xa7\x32\x07\x46\x1d\x8d\x96\xaf\xa2\x46\xd7\xc6\x9d\x17\xa7\xa9\xbf\x77\xf0\x55\x43\x56\x3a\x7d\x3e\xca\x1d\x40\x79\xe2\x29\x38\xab\xa1\xf6\xe9\xe0\x4b\x49\xfb\xc8\xed\x6f\x63\xb5\x99\x73\x0d\xe9\x97\x98\x31\xc0\x2f\x8c\xba\x61\xe5\x55\x60\xd7\x11\x0d\x4c\x6e\x61\x67\x97\x06\xa7\x15\x5d\x5a\x67\x3c\x54\xd1\x6f\xe4\xd2\x28\xc2\xec\xa7\x54\x6f\xaa\x13\x39\xf2\x6d\x7a\x0b\xb4\xee\x33\x96\x11\xaf\xde\xc9\xa6\x8f\x5f\xf5\xb5\xd2\x03\xb6\x00\x53\x3a\xd5\xa3\xb3\x68\xc8\x5d\xa1\x15\x63\xf0\x98\xcc\x26\x87\x1e\x7f\xa9\x9a\xef\xd3\x8c\xc2\x61\x51\xdb\x3b\x0b\xae\x38\xdb\x6a\x87\xb6\x78\x9e\x58\x40\xb1\x08\x84\xaf\x51\x1f\x3e\xcb\x3e\xcb\xf9\x4f\xf8\x6f\xdb\x90\x55\x05\xa8\xc3\x4b\x2a\xa6\x1f\xf2\xec\x9e\xc8\xfe\xbd\x1d\xfe\xd0\x96\x5b\x6f\xc5\xb9\xf8\x86\x9d\xc3\xa4\x75\x59\x97\x4a\x88\x22\x99\x67\x06\xda\xef\xbc\x6c\x5b\xf9\x84\xce\x06\xb0\xd3\x2b\x31\xcf\x9d\x8a\xd1\x36\xae\xd4\xb0\x52\x58\x6d\xce\x70\x73\xb7\x67\xb2\x34\xe4\xa3\x7b\xeb\xbc\x39\x3d\xd2\xe0\xf7\xd1\x55\x17\x35\x48\xc3\x8a\x15\x83\xef\x94\xe0\xaa\x84\xe7\xfc\xe0\x4f\xcc\x9b\x4e\x30\x0a\xd0\x99\x44\x9a\x49\x23\x2a\xbd\xcf\x3d\x1a\x6e\x6f\xca\xb6\x96\xf5\x99\x6f\x9b\xd1\xb9\x48\x5d\x07\x47\x55\xac\x5b\x42\x97\xfe\xe3\x12\x4c\x7c\x03\x97\x6a\x40\xd5\x70\xbe\xae\xc2\xfa\xc9\x92\x33\x9f\x88\x5f\x74\xd4\x0e\xd4\xac\x87\xa4\xf4\x0c\xef\xbc\x48\x64\xf4\x4c\x36\x83\xaa\x8f\x10\x26\xe2\xc3\x7a\xef\xfc\xeb\xfd\xfe\x24\xdd\x0b\x01\x9c\x36\xa7\x98\x88\x20\x30\x04\xb2\xad\x83\xe8\x92\x21\xf3\xf6\x36\xf4\x55\xbb\x64\xe1\x7d\x17\x54\xc7\xc6\xdd\x7f\xc0\x9a\x0d\x65\xdd\xdd\xed\x46\x22\xfc\x4f\x9f\xba\x07\x2b\x45\x10\x34\x35\xe1\x02\x20\xa5\x86\xf1\x52\x26\xd2\xeb\x37\x7f\x40\x64\xd3\xff\x37\xcb\xb4\x70\x5a\x1f\xaa\xf5\xb3\x48\xf8\xc0\xef\x7f\xd1\x56\x4d\x42\x86\x88\xf5\x8f\x33\x92\x96\x7c\xf3\x96\xa8\xff\x2f\xd9\xe7\xb5\x17\xb7\xd6\xa5\xed\xe7\x44\x03\x73\xd8\xcc\x1a\x83\x99\x00\xe8\x4d\x42\x25\x42\x83\xd9\x69\x9c\x7c\xa3\x7e\x47\x76\x92\xa3\x49\x40\x08\xb8\x04\x44\xc5\xcf\x61\x4c\xbb\xc1\x69\xbf\xb9\x29\x63\x03\xc6\x45\xe2\xce\x28\xd1\x68\xdc\x6c\xba\xef\xae\x9c\x73\x19\x1f\x57\x15\x1a\xa4\x73\x00\x9d\x29\xe1\x80\x0b\x10\xf4\xc4\x98\x60\x9b\xa1\x15\x20\x98\x5c\x78\x09\x20\x58\x69\x6f\xdb\xca\x9c\x02\x0e\x2d\xfb\x8a\x04\x3a\x3d\xe8\xe4\x52\xd5\x8c\xd1\xad"}, -{{0xd1,0x52,0x8c,0x14,0x06,0xa6,0xe4,0x94,0xa0,0x2f,0x63,0x53,0x05,0xfa,0x74,0xd7,0x45,0xc6,0x93,0x27,0xfd,0x31,0xb7,0xd2,0xc2,0x62,0x3d,0xe2,0xc0,0x30,0xed,0x85,},{0x0c,0xfe,0x36,0x9c,0xf9,0x3d,0xaf,0x6d,0x53,0xef,0x02,0x8d,0xdb,0x9f,0x00,0x04,0x43,0xb0,0x97,0x2f,0xe2,0x53,0x2f,0x83,0xa4,0x1c,0xe6,0x57,0xc1,0x83,0x6c,0xa3,},{0xb8,0x39,0x9b,0xc3,0x32,0x6c,0xba,0x0a,0x93,0xa4,0x24,0x97,0x16,0x8b,0xf5,0x7f,0x91,0x06,0xee,0x43,0xd3,0x9b,0xf0,0xfc,0x86,0x68,0x51,0x99,0xdc,0x6e,0x0a,0x13,0xb9,0xc7,0x24,0xef,0x17,0xe7,0x88,0x2a,0xf8,0xc2,0xeb,0x70,0xf6,0xc9,0xe4,0x2d,0xfa,0x2f,0xbf,0x0c,0x1c,0xb5,0x00,0x2b,0x58,0xf1,0x08,0x66,0x19,0x73,0x3e,0x02,},"\xab\xb3\x67\x3f\x3f\xa1\x7a\x33\xa7\xaf\xf7\x6e\xac\x54\xe7\x68\x7c\x04\xbc\x84\xf7\x66\x65\x1a\x8b\x24\xba\x22\x94\x79\x08\xb0\x4c\xa4\x59\xfe\xb9\x8a\xce\x7c\xab\x1e\x74\x33\xa6\xa6\xbe\xff\xd8\xd9\x50\x4e\x29\x91\xda\xa0\x64\x4d\x61\xb8\xb2\xe4\x54\x48\xf5\x4d\xf8\x81\x3f\x50\xc4\x18\xb4\x8f\x49\xe1\x03\x4e\x85\x1c\xbe\xc3\xef\x0a\x18\x50\xef\x72\x67\x33\xaf\xaf\x68\xe1\xa4\x61\x04\x16\x51\xc1\x38\xd5\x4e\x4e\xf7\x81\x87\xaf\x9a\x73\x42\xf7\x12\x87\x27\xf9\x03\xbf\x4f\xc5\xef\x3e\x40\xc6\x4e\xc2\x6f\x89\x2f\x59\xad\xd9\x8f\xe3\x94\x76\x5a\xaa\x7d\x09\xca\xe8\x1b\x9f\x69\x9a\x9d\xd8\xbf\x2e\x2f\xe8\xe1\xec\x78\xfc\x88\x4e\xaa\x0d\x2d\xbd\xbf\xb8\xc1\x68\x83\x3e\xe0\xd2\x18\x03\xcc\x35\xdc\x62\x8d\x7c\x07\xe0\x44\x04\xfb\x60\xe8\xc4\x90\xa8\xdd\x34\xed\xbc\xba\xaf\x80\xcc\xda\xe3\xf7\xd3\x73\x9e\x0e\x89\x70\x23\xee\xb5\xb1\xa8\xc0\x0a\x96\x73\xc5\x92\x58\x24\x0d\xdd\x44\x20\x65\x0f\xe5\x77\x1f\x7e\x28\xcb\x23\x99\xf5\xe1\xe0\x2a\xd0\xb6\x43\x2d\x9b\x49\x60\x8f\xcf\x0b\x1c\x0d\x7c\x41\x2a\x44\x52\x55\xb8\xba\xdc\x53\x21\xc2\x4c\x1a\xc9\x2c\x79\xa0\xba\xcc\xb9\xde\xff\xed\x02\xd1\x2f\x55\x36\xcd\x59\x5d\xc6\x60\x83\xb3\x3a\x36\x03\xa9\xd1\x6e\xce\xa2\xbf\x38\xc4\xf2\xaa\xf5\x70\xf3\x0d\x21\x16\x2b\x2e\xfd\x7e\x4d\x5e\xbf\x1e\xca\xe9\x58\x8e\xee\x36\xdd\x9d\x3d\x8e\x3b\xe7\xbc\x6d\x4b\xc2\x18\x56\x22\xf1\x1d\x1d\xa7\xc4\x9c\x93\xe6\x23\xac\x56\xfe\xe7\xe3\x70\x6d\xb8\x31\x3c\xf9\x26\xbe\x92\xe5\xc8\xa5\x39\xfd\x16\xb0\xf4\x38\xda\x8e\x51\xa5\x1f\x2d\x27\x64\x03\x56\x12\x4e\xf7\xbe\x2f\x91\xff\xa1\x79\x6a\x91\xb1\x23\x01\x93\x4d\xde\xf0\xc7\x93\x8a\x7a\x45\xf3\x6f\x53\xb6\x32\x2d\x9c\x8f\x9d\x27\x5e\x1c\xd2\xc0\xf1\x29\xf8\xab\x8d\x74\x15\x5b\x5d\x9e\x5c\x15\xc0\x15\xb0\xb0\x00\x03\xb2\xbd\xdf\xa0\xbc\xfc\xc6\x93\xa1\xdf\xcb\x4f\x53\xda\xec\x12\x6d\x16\x69\xf3\x3f\x39\xad\x05\x51\x9e\xf7\xc5\xce\x40\xe6\xf4\x57\x3c\x24\x7a\x32\xc4\xa0\x16\x28\x31\x35\x2f\x6d\x55\x8f\xf5\x83\x6a\x53\x17\xdb\xc4\x51\x5b\x3d\xf2\x69\xa8\xac\x76\xd6\x43\x6f\x26\x4b\x64\x56\x1e\x79\x68\xb5\x82\x21\x08\x48\x7b\x04\x5c\x92\xd6\xc6\x14\x2a\x1c\x28\x55\xb3\x8b\xee\xbd\x64\x25\x65\x12\x3c\xc8\x27\xcb\x18\x31\x19\x9e\x6f\x12\xa7\xe4\x23\x68\x56\xb9\x4d\xad\x73\x8f\x69\xd1\x10\x6e\x77\x35\xd7\x11\xf7\xc6\xa3\xa3\x37\x80\x41\xfc\x7a\x21\x10\x3b\xbf\x86\x69\x07\xd4\xed\xdd\xaf\xa0\xe7\xf1\xbb\x5f\xfd\x41\xa6\x0d\x64"}, -{{0x51,0x23,0x40,0xf9,0x61,0xf1,0x42,0xd1,0x91,0x5e,0x85,0xfe,0x4f,0xa0,0xf5,0x51,0xf8,0x08,0x92,0xe7,0x5a,0xcc,0xce,0x7c,0xd1,0x86,0x9e,0x6e,0x2c,0x9e,0x80,0x15,},{0x0c,0xa0,0x26,0x04,0xfa,0x87,0xe2,0xc2,0x05,0x06,0x25,0x1f,0x07,0x92,0xcd,0x21,0x25,0x85,0x6f,0x0a,0xb1,0x6d,0x66,0x3f,0x28,0x11,0x96,0x3b,0x1f,0x2d,0x81,0x72,},{0x6b,0xb4,0xd9,0x75,0xaf,0xae,0xf4,0x1e,0xa9,0xef,0x08,0x5a,0x68,0xc5,0x68,0xa0,0x5d,0xa3,0x7e,0xf2,0x1d,0xad,0x46,0x4e,0xd8,0x6a,0xc0,0xd4,0x08,0x0e,0x7d,0x01,0x29,0xfb,0x02,0x31,0x31,0xec,0xa5,0xf7,0xad,0xb2,0x58,0x6a,0x18,0xbe,0x40,0x56,0x2f,0xa2,0x76,0x4c,0xa8,0x07,0xe6,0x70,0xa0,0x59,0x6a,0x5c,0x54,0x7b,0xc0,0x01,},"\xaf\x37\xb2\xc7\x58\x7a\x8d\x5b\xc8\x95\xcd\x35\x77\x46\xab\x03\x55\x2a\x0a\x56\x1a\x29\x3d\xc7\x16\x4e\x39\xb6\xa1\x33\x3a\x92\x0b\xb6\xda\xca\x60\x06\x67\x6e\x99\xbb\x7e\x92\x8f\x9e\xa3\x91\xe5\x48\x02\xa8\xd3\x15\x96\x28\x9f\xb9\xbf\xe3\x00\x00\xcf\x52\xeb\xf0\xc1\x24\xa5\x89\x5b\xce\x33\x98\xc1\xbf\x53\x56\xbe\x82\x61\x9b\x8d\xdc\x15\xa7\x7c\xa9\x22\x49\x4b\xdb\x04\xf5\xc2\xe1\xb6\xe8\xff\x77\xae\x74\x9f\xaf\x2b\x8a\x41\xd8\x22\xc1\x7c\x06\xdf\xb7\xa5\xf9\x43\x4d\x8b\xd7\x15\xec\x87\x78\xe8\x0b\x81\xd2\xe8\xd0\x62\x98\x74\x86\x90\xc6\x55\x52\x83\xc9\x8b\xb9\xb1\x9b\x92\x46\x66\x7b\xc4\x10\x46\xff\x98\xc2\xc3\x5d\x16\x1e\x1f\x4d\x69\xd2\x54\xec\x5a\x07\x6f\x25\xbd\x5c\x7e\x2c\x98\xca\x3c\x09\xd8\x08\x33\x96\x2c\xf9\x66\x02\x87\x88\x40\x96\xeb\x30\xc4\x6c\x54\x17\x41\x06\xaf\x4e\x29\x79\xa1\x12\xf3\xe8\x94\x4e\xaa\xf7\x66\x9c\x40\xd5\xaf\xb9\x1a\x02\x4a\xbb\xeb\x14\x66\x4e\x30\x89\x03\xe4\xd2\x6d\x70\x09\x44\x6e\xe2\xe8\x30\xab\x5e\xca\x0d\xbb\xc5\x13\xfb\x4e\x04\x35\x1d\xf2\xf6\x74\x18\x64\xfb\x23\x71\xb2\x50\x2b\xe4\x3d\xc1\x5f\xc0\x44\x31\xff\xf5\xeb\x8d\x4b\x68\xd7\x24\x62\xae\x32\x2e\x57\xba\x2d\x4a\xdd\xdf\x15\xa1\x90\x2c\x21\x13\xae\xbd\x3b\x5d\x61\x29\x17\xc1\xbb\x73\xe7\x08\xad\x54\x18\xe7\xd4\x5e\x4b\x72\x80\xfc\x88\x96\xab\x80\x85\x3f\xf5\xf8\xe9\x8f\x26\x55\x3f\xc7\x8e\x30\xb3\xb0\xd7\x27\xbf\x6d\x06\x4a\x8f\x32\x88\x87\x68\xc5\x1e\xbb\x61\xb2\xc6\x00\xb4\x02\x8a\x77\x06\x0f\xeb\xbb\x02\xeb\x3d\x20\x17\x80\xe7\x45\x66\xc8\x6a\x34\x03\x18\x36\xbc\xe9\xea\xda\x81\xe5\xd0\xf3\x39\x60\xcb\x2d\xf0\x8a\xff\x3c\x97\x49\x21\xfc\x9b\x7d\x3a\xa7\xc8\x1e\x9c\x67\x1e\xd6\xd3\x3e\x7a\xe5\xed\x03\xa5\x41\x7d\x7e\x5c\xd6\xfa\xac\x91\xb5\x4b\x8f\x79\x2f\x48\x28\x3c\x60\x64\x7d\xe3\xda\x81\x6c\xa9\x75\x6c\x5b\xfe\x1b\xb8\xb5\x97\x9e\x57\x54\x01\xbd\xa3\x4e\x9c\xbc\x4d\x77\xe7\x11\xd6\xb7\x3b\x82\xda\x19\xda\x47\x3b\x55\xe8\xe7\x2d\x34\x1b\x2d\x85\x03\xe4\x86\x09\xbe\x0f\xe2\x91\x44\x4c\x28\x36\x69\xe5\xde\xad\xea\xf5\x2a\xa8\xec\x48\xda\x83\xf5\x32\x8c\xc0\x99\xfb\x41\xf8\x2b\xec\xdd\x58\xd0\x4b\x1d\x66\x20\x3d\x73\x7b\xed\x06\xcf\x21\xc9\x78\x19\xac\x13\xed\x71\x1c\xa2\x17\xa5\x7c\xf7\xd8\x0f\xf0\x82\xaa\x1a\x1c\xf8\xfe\xa5\x55\xcd\x2e\x47\xe4\xdd\xab\x5e\x3f\x99\x41\xad\x4f\x77\x5f\x49\x41\x9d\xca\xdb\x5b\x00\x4b\x68\xca\xf4\x5b\x27\xef\x49\xba\x14\xfb\x52\xb0\x9f\x1b\x18\x5b\xe9\xf9\xc7"}, -{{0xb1,0xb6,0x36,0xe9,0x57,0x57,0x4c,0x21,0xa9,0x57,0xa4,0x5b,0xd1,0x95,0xc6,0xf9,0xfe,0x4c,0xc1,0xc5,0x7e,0x84,0x13,0x4d,0x39,0xb4,0x2e,0x1a,0x84,0x32,0x9e,0xdb,},{0x95,0xe7,0x7b,0x15,0xdd,0xa4,0x7c,0xaf,0x69,0xb7,0x28,0x88,0xdd,0x69,0x96,0x1b,0xac,0xbe,0xc3,0xbc,0x75,0x35,0x30,0x03,0xe8,0xbf,0xf0,0xa4,0x3d,0xdf,0x4b,0x7a,},{0x76,0x3c,0x7d,0x0d,0x46,0x87,0x8e,0x5c,0x7e,0xcf,0x71,0x04,0xfc,0x1f,0x22,0x30,0xe4,0x61,0x78,0xa2,0x7c,0x75,0xf1,0x96,0x16,0x9c,0x02,0x79,0xed,0xb0,0x1c,0x28,0xfc,0xde,0x3b,0x0d,0x5b,0x86,0x35,0xcf,0xe3,0x39,0xfb,0x23,0x27,0x74,0xb2,0x20,0x6d,0xab,0x8a,0x46,0x0c,0xe4,0x17,0xab,0xf4,0x90,0xbb,0xfa,0x78,0x5c,0x02,0x05,},"\xe2\x5d\x32\x9c\xad\x83\x64\xd2\xde\xc2\x43\x73\xe9\x2d\x9d\x50\xfc\x7a\xbe\x8f\xdc\x3d\x0b\x4e\xe5\x7e\x1c\xfa\x5b\x7c\xd5\x8c\x23\xbe\x91\x8f\x05\x17\x9b\xa8\x41\xb6\x1e\x18\x00\x34\xca\x7e\x74\xd4\x9b\x0a\x1a\x2c\xeb\xb4\xbe\x65\x34\x4c\x91\x3c\x46\xd3\x26\x52\x33\x6e\x6b\xda\x4e\xfa\x3f\x58\x73\x0d\x39\xa6\x33\xa1\x4c\xa3\xd9\xa6\x2a\xbb\x0a\x73\x98\xcc\x29\xaf\xf9\x16\xee\xea\x2e\x7c\xaa\xc8\x08\x45\x56\x2f\x73\xd4\x03\x0f\x9c\xab\x0b\xf1\xc6\x40\x7f\x54\x01\x51\x3e\xf8\x7f\xe6\xdc\x09\x9d\xbc\x5d\xfc\x33\x52\x91\x1c\x07\xaf\x6c\x52\x3b\xef\x4c\xca\x78\x37\x96\x59\xe8\x80\x3f\x58\x59\x04\xee\x6e\xf6\xfd\xe7\x73\x66\xd9\x6d\x2c\xcf\x24\x8a\x53\x20\xd9\xb8\x29\x8b\x2a\x73\x36\x38\x79\x10\x7a\x02\xb4\x7f\x57\x21\x3a\x85\x20\x3a\xbb\xca\x5a\x41\x95\xf8\xaf\x3e\x35\x93\xed\x2f\xa3\x50\x4b\xb7\x6a\x3e\x1b\xe2\x4b\x66\xd3\x55\x66\x29\x32\xcb\x67\xdc\x88\x50\x3a\xfa\xf7\x62\xbf\xf7\x41\xba\x1c\xac\xe9\x7a\xc5\x8b\xaf\xad\x5d\x36\xc3\xaa\x02\xe0\xcb\xe2\x0e\x5f\x3d\xc8\x09\x2c\x51\x2e\xaa\x9c\x49\x43\x47\x4a\xad\x41\x99\x00\x76\x72\x1a\xd3\xf5\x3f\xb0\x8a\xc2\x29\x82\xed\x9b\x15\xc7\x51\xa9\xe2\x33\x82\xf6\xa6\x9c\x72\xe6\xe2\x44\xe0\xeb\x68\x1e\x6d\xd2\x28\xd3\x77\x4f\xcc\xb3\x7e\xb6\x23\x2f\x82\x5d\x16\x9a\x2a\xc8\xb7\xe1\x8a\x42\xcd\xaa\x4f\x2c\xf0\x58\x90\xbb\x0c\x59\x8c\xf8\xc3\x1f\x82\x9e\xf8\xca\x24\x35\xbd\xcc\xeb\x0e\x61\x93\xad\xa7\x84\x1e\xe6\x92\xf3\x0a\xed\xf8\x8b\x62\x73\x11\xb1\x38\xac\x78\xb3\x91\x3e\x06\xf7\xc3\x21\xca\xfb\x39\xd9\x01\xdf\xe1\x74\x30\xb1\xa2\x0b\xc4\x37\xa5\x55\xa5\x78\xfa\x31\xe4\xb6\x80\x79\x54\x45\x6b\xd4\xb0\x4d\x5d\x88\x79\x87\xbd\xf0\x4e\x0f\x14\xaf\x31\x41\xb2\x4c\x3a\x7b\x9a\xc7\x5a\xa3\x2e\x2f\xcd\x21\x71\xa1\x26\x09\xe1\x5e\x73\x09\x4f\xd0\x92\x21\xb4\xd2\x70\x90\xe7\x32\x19\xb6\x48\xbc\xaa\xbf\x38\x07\xc9\x28\x0b\x6c\x4a\xd7\x50\xa4\x68\xbe\x0e\x1a\xd3\xe6\xe6\x30\x16\xcb\x5c\xec\x3a\xad\xdc\x56\x89\xc2\x95\x5a\x2a\x8d\x5b\x89\x84\xd7\xc4\x43\x76\xfd\xd9\x4d\x3f\x5f\xf1\x29\x8f\x78\x17\x2b\x56\x59\x13\x70\x4e\x90\xe5\xac\x03\x8c\xb1\x72\x0e\x19\xb0\x80\xf8\x1b\x53\xd6\xa4\x5d\x45\x28\x53\x07\x11\xb6\x3d\xfe\x1e\x47\x81\xc2\x4d\x74\xae\xb2\xbd\x8a\x73\xfd\x2a\x99\x3c\x5b\x08\x91\x39\x21\x96\xac\x32\xc5\x23\x69\x99\x60\xd8\xb2\x3e\x01\x66\x4c\xf9\x02\x1d\x93\x92\x80\x50\xca\xf9\x7f\xb9\x85\x55\x45\x80\xe3\x33\x36\xa4\x56\x32\x47\xdf\x59\xef\x6c\xae\x53"}, -{{0x10,0xca,0x41,0x3d,0x70,0xeb,0x3d,0xb6,0xe3,0x37,0xf0,0xf1,0x1a,0xbc,0x07,0x5c,0x95,0x85,0x9e,0x82,0x5f,0x87,0x61,0x76,0x07,0x69,0x52,0xd2,0xf1,0x88,0x80,0x30,},{0x50,0x28,0xba,0x38,0xaf,0xec,0xc2,0x42,0x63,0x5f,0x6e,0x35,0x3d,0x5f,0x4a,0xfd,0x12,0x3f,0x86,0x0a,0x04,0x25,0x22,0x0e,0x96,0x65,0x52,0xa0,0x57,0x88,0x08,0x23,},{0x6a,0xec,0x02,0xdc,0x6b,0xdf,0xcb,0x67,0xf0,0xef,0xc1,0xfd,0x31,0xe2,0x3e,0x69,0xe3,0x71,0xab,0x38,0x02,0x50,0x5b,0x32,0x01,0xa9,0x5d,0xd5,0x25,0x41,0x7e,0xd1,0xa1,0x28,0xdb,0x4e,0x18,0x2c,0xb3,0x7c,0x28,0xf6,0x28,0x06,0x66,0x70,0x99,0xa8,0xad,0x48,0x0b,0x0a,0xc9,0xe9,0x4c,0x2a,0x7d,0x5a,0x0e,0x96,0xe2,0xa7,0x36,0x0d,},"\xea\x7f\xaf\x79\xf6\xff\x5d\x78\xa8\x23\xa7\x54\x34\x71\x34\xf1\xb3\xc3\xe9\x1c\xe5\x18\xfd\xd6\x33\xfe\xb4\xf0\x5d\x12\x5f\x05\xcb\x54\x33\x6e\xf5\x60\xe9\x2d\xeb\x68\x51\x12\xa5\xff\xcd\x3d\xfd\x39\x64\xb2\x75\x8c\xe4\x78\x5f\x6a\x34\xbf\xeb\x39\x78\x4f\x0a\xee\x55\x95\x5a\xeb\xd1\x2d\xdd\xa6\x41\xd0\x57\x69\xf7\x44\x02\xf7\x06\xda\xd2\x01\xc4\x4c\x91\x08\x1c\x7d\x7f\x65\xe7\xaa\x42\x46\xde\x6d\xc3\xed\x64\x96\xd1\x0f\x4a\x41\x20\x60\xd4\x93\xba\xc9\xae\xd5\xbe\x4f\x6d\x74\x22\x9e\x3c\x55\xeb\x68\x76\xe3\xbb\x2e\xd4\x1f\xa4\x50\x4b\x66\x70\xdd\xa8\xc7\x98\xf6\xda\xa2\x80\xd1\xaa\x72\x02\x11\x74\xf6\xc0\x1a\xec\x49\xb3\x21\xd8\x7f\x53\xac\xbc\xad\xcc\x46\x07\xd5\xb1\xe4\x5d\x63\xfc\x48\x1a\x6d\x90\x57\x6c\x87\xc1\x88\x0b\x2e\x8f\xf3\xe5\x90\xa9\x6b\xee\xe1\x80\x47\x68\xc7\x56\xbe\xb8\x6b\xf1\xde\x8a\xdc\x40\x8b\x1b\x8d\x66\x6f\x74\xba\x28\x63\x08\x22\xf9\x2d\x18\xb0\x56\xae\x37\xce\x02\x93\xee\x61\xb9\xe8\x0f\x33\xac\x26\x96\x71\xbd\x62\xa4\x05\x9b\x24\xf7\xc1\xa4\x40\x80\x74\x40\xd5\xd5\x38\xa6\x54\x58\xad\xc8\x15\x87\x24\xb2\x5c\x12\x12\x7a\xa0\x34\x9e\x55\xf6\xe5\x5b\xc9\x20\x78\xfd\x1e\xf2\x74\xc2\xaa\x79\x19\x05\x76\x6b\xe3\x94\xa2\x62\x8f\x7b\xbd\x1a\x32\xda\x5e\x48\x74\x46\xbb\xef\xae\x88\xfa\x6c\xf3\xf7\xb4\x99\xf1\x31\xfa\x19\x31\x3d\x13\xb2\x80\xad\xca\x50\xf7\x78\x02\xd1\x73\x31\xb3\x81\x68\x3b\x5e\x7e\xda\xb9\x94\x73\xed\xd3\x1d\x77\x44\x34\x88\x21\x41\x35\xfd\x6f\x26\x44\x50\x93\xe9\xe2\xaf\xf7\xd7\xe8\x92\x33\x7f\xdc\x87\x79\x06\x5d\x4d\x97\xd6\xd6\x73\x57\x67\x94\x95\x8d\xbf\xa6\xc5\x0b\x1b\x13\xac\x39\x60\x7c\x1e\x66\xef\x96\x29\x76\x10\x71\x15\x5f\xbc\xa6\xf3\x6e\xb0\x2c\xee\xae\x16\x36\x7f\xea\xc0\x74\x76\x90\x8c\x84\x7c\x9a\x53\x3e\xf6\x8c\x94\x31\x1f\xa0\x89\xff\x28\xfb\xd8\x78\x09\xb0\xd3\x87\x6b\x43\x1d\x9a\x18\xb2\x02\xf9\xa4\x04\x9a\x05\x77\xb8\x17\x76\x10\xdd\x02\xe5\xc5\x20\xec\xa9\x55\xe8\x03\xc3\xad\x4f\x50\x97\x6f\x7c\x2e\xa8\xaa\x3e\xe4\x83\x6a\x19\x85\xdf\x0a\x4f\x16\xef\x46\x98\x15\x95\x41\x98\x97\x99\x35\x60\xaf\x82\x65\x1c\x2b\x49\x4e\x68\x0b\x37\x80\x2e\x75\x37\xef\x68\xa5\x75\xc3\x4f\x85\x88\x06\x3e\xe0\x19\x72\x06\xd9\xa3\x2b\xb4\x89\x0e\x7c\x21\x6a\x4d\x33\xfe\xca\x36\xb5\x49\xe5\x32\xfe\xa6\x85\x56\xe7\x54\x0a\x4f\xb1\x69\xd4\x9f\xc5\x53\xb2\xe6\x70\x0a\xe4\x2d\x9a\x51\x6e\x68\x16\x0a\xcf\x6b\x27\x0c\x77\xca\x5e\xc2\x6e\x5a\xd5\xdc\x75\xc2\xc3\x93\xe2\x99"}, -{{0x1f,0x0a,0x10,0xa2,0xcb,0x11,0x19,0x17,0xb9,0xa6,0x7a,0x2a,0x1f,0x38,0xfb,0x86,0xf8,0xed,0x52,0x60,0x7d,0x1d,0x65,0x3a,0x45,0x7d,0x7f,0x47,0x18,0xd9,0xa7,0xde,},{0x70,0xc0,0x75,0xb2,0xe9,0x4c,0x4c,0x02,0xf4,0x5e,0x73,0x04,0x4f,0x24,0x39,0x97,0x41,0xb1,0x61,0xfe,0xb6,0xf6,0x9e,0xab,0x63,0x54,0x17,0x28,0x2a,0x4a,0x93,0x68,},{0xa4,0x24,0x5a,0xa3,0x39,0x5e,0x7b,0xad,0xa2,0xbc,0xdf,0x16,0x03,0x14,0x7c,0xc5,0xf3,0xf0,0xba,0x91,0xf4,0x0f,0xda,0xd8,0xf6,0xd3,0x71,0xc3,0xeb,0xef,0xb4,0xc1,0x50,0x1d,0x07,0x87,0x5b,0x57,0x6f,0x40,0x79,0x78,0x06,0xa4,0x84,0xc7,0xa3,0xf7,0x05,0x69,0xe2,0x32,0xb0,0xc9,0x9d,0x29,0xca,0x23,0xa2,0x33,0xb6,0x8e,0xdb,0x0c,},"\x4f\x6a\x43\x4b\xd5\xfc\x77\xf0\xf1\xb7\x04\x9c\x91\x85\x3c\xcb\xd8\x94\x39\x96\x2a\x60\x78\xa6\x74\xb8\x67\x54\x3b\x6b\x7d\x10\x55\x2e\xc1\x75\x8c\x52\x83\x04\x2b\xd6\xb4\xce\xa8\x8c\x95\x20\xdb\x04\x74\x6f\x08\x9c\xf3\xa2\x60\xfb\x0f\x33\x85\x8e\xfd\x6f\x68\x0d\xe5\xb7\x2d\x98\x76\x32\x4b\xa5\x90\x29\x91\x38\xf8\x5a\x76\xf5\xbe\x0e\x05\xe8\x85\x9c\x02\xb2\x35\x12\x55\x9c\x8b\xea\xfc\x9c\xfe\x90\x1b\x28\x3e\x15\xd1\x6c\x79\x2e\xb0\x3b\x92\x88\x0f\x6f\xf9\x7a\xa3\x8e\xee\xad\x3f\x4f\xd6\xc0\xa9\x21\x43\x23\xaa\x39\xa1\xc1\x65\x15\xe3\x0d\xbd\x08\xb8\x33\xee\x40\xa8\x14\xa2\x88\x09\xc8\x70\xe1\xd0\xa6\x2c\x37\x93\x2d\x54\x08\xfc\x6a\xfc\x63\xe7\x9a\x65\x5c\x5f\xe3\xd4\x02\x6e\xf0\x9e\x02\x99\xfb\xde\x5a\xb3\x4f\xce\xab\x14\x13\x0d\xc4\xbe\x00\x7e\x8e\x64\x44\xd7\xaa\xae\xc6\x2c\x87\x3d\xf7\x7e\x80\x10\x74\x3c\x31\xe8\x75\x7f\x1e\xae\x9e\xdb\x55\x97\xa1\xb5\xd8\x4b\xd7\x7a\xe7\x64\x2e\x1a\xca\x99\x87\x3a\x15\x2f\xfd\xe0\x68\xa8\xe4\xad\x92\x40\xb9\x03\x33\x27\x95\xe4\x0b\xb3\x28\x65\xe5\xce\x03\x43\x07\xa6\xc9\xfe\x33\x9a\x1c\x93\x77\x0d\xf5\xca\x46\x32\x9f\x6b\x09\x41\x97\x85\xcb\xf2\x84\x7b\x0c\x68\x32\x83\x71\x23\x85\x3a\xd9\x52\x65\x32\x65\xc5\xb5\x74\x0d\x19\x4e\x00\xf2\x3f\x9e\x96\x67\x91\xf0\x05\xf8\xbf\x55\xc3\x88\xc2\xbe\x9e\x21\x53\x89\x25\xf8\x55\x5e\x0d\xbd\x83\xbe\x07\x3d\xf7\x65\xaf\x49\x40\xe5\x9a\x37\x90\xb9\x83\x6b\xab\x79\x09\xe5\x67\x6f\xbf\x1c\x21\x26\xfe\x22\x6d\x78\x1a\x44\x33\x0c\xc0\x1d\x32\x83\x0f\xf8\xae\x00\xb9\x79\x2e\x39\x8c\x2c\xbb\x4f\xb8\x3a\x10\x05\xc2\x45\x54\x9a\x89\x06\x3f\xbe\x06\xc6\x2a\x48\xda\xc4\x3c\x51\x01\x24\x99\x94\xe9\x5e\x37\xf2\x4c\x1d\x8b\x3b\xc6\x73\x53\x8c\x46\x05\x5f\x80\x0d\xb1\xc0\xf9\x56\x86\x9b\x6b\x29\x7d\x99\x0f\x44\xf0\x5b\x50\xc7\xad\x6b\x85\x6f\x46\x21\x28\x58\x47\x1d\xd0\xd3\x93\x72\xb0\xdb\x75\x15\x73\xdd\xb6\xb5\xb5\x6b\xa0\x1e\x37\x1c\x78\xfe\x58\xdc\xd1\xbe\x53\x11\x2a\x6a\x73\xda\x9a\x6b\xac\x75\xd3\xc3\x9a\x1a\x70\x5a\x36\xf6\x40\xfc\xfa\xd8\xcd\x04\x07\x75\x94\xd5\x96\x85\xf6\xe3\x0d\xe7\x1d\xfd\x4a\x44\xc4\xe7\xc0\x4d\x6e\xc7\xc2\xe8\xbe\x12\x78\x5b\xb0\x5b\x29\xb3\x91\x51\xd3\x29\xf5\x87\xfd\xc3\x81\xc2\xdf\x0c\xef\x73\xfe\x0e\x3f\xd9\x20\x8d\x7c\xcb\x6e\x08\xd0\x2f\x42\xd1\xfe\xed\x27\x56\x1d\x5e\x32\x3a\xa1\x48\x62\x4e\x55\x2a\xbe\x87\x53\x2d\xe1\x5b\x7f\x42\xc2\x2c\x98\xe4\x05\x25\xb1\x74\x7c\xbd\x75\x8b\xfb\x26\xfd\x3e\xed\x3b"}, -{{0x7f,0x05,0xba,0xac,0xf1,0x67,0x58,0x3c,0xf2,0xfe,0x95,0x62,0xa5,0x06,0x99,0x1e,0xd9,0x87,0xf6,0x8f,0xfb,0x71,0x56,0x7c,0x7c,0xcc,0xe3,0xfc,0xc5,0x9b,0x78,0xb0,},{0x0d,0xec,0x39,0x52,0x85,0x2b,0x96,0xfd,0x75,0x58,0x7e,0x97,0x74,0x3f,0x9e,0x41,0xc0,0x9f,0xbe,0x6b,0xa9,0x81,0xbf,0xce,0xb4,0xeb,0xb8,0x89,0x2d,0x98,0x6a,0x16,},{0x0d,0xee,0xd2,0xdf,0x82,0xac,0xf4,0x52,0x9c,0x40,0x8a,0x02,0x93,0x1f,0x67,0x6b,0xec,0x5c,0xb7,0xad,0xe8,0x4e,0xbd,0xcd,0x57,0x8f,0x70,0xf9,0x71,0x38,0x2c,0xf3,0x11,0xbb,0x83,0x09,0x73,0x00,0x45,0x6a,0x55,0x8b,0xc4,0xc0,0x9d,0x89,0x83,0xff,0x13,0x49,0x3f,0xd6,0x11,0xeb,0x66,0xc0,0x43,0xbf,0x01,0x9b,0xad,0x6f,0x33,0x02,},"\xa2\x7d\x1e\xab\x05\x15\x09\x20\xde\xd1\xb1\xc2\x57\x8a\xf5\x82\xb2\x94\xf7\x83\x7f\xe4\xfb\x1a\x31\x69\xc2\x5e\xfb\x70\x63\x4b\xa6\x6c\x7e\x29\x91\xb3\xe7\x5c\xc5\x12\x48\x26\xa0\x3e\x05\x72\x59\xb5\xcb\x70\x62\x28\x78\x0c\xbc\x82\x75\xc3\x39\xf8\x34\x0e\x40\x2a\x66\x50\x32\xa4\xab\x65\x78\x27\xb1\xc3\x48\x1f\x75\x66\xd3\x69\x73\x5b\x82\xdb\x76\x28\xc0\x22\xb2\x12\x73\x0d\xb1\xe4\x7c\x9b\x2d\x9b\xc4\xd8\x1b\x23\x42\xd8\x9c\x6e\xaf\xc3\xe0\xb6\xde\x50\xd4\x84\xcc\xef\x11\x23\x8c\x8e\x2d\x24\x0d\xd5\x95\xdc\xef\x8b\x2f\xc5\x7b\x54\xff\x9a\x8a\x74\x11\x1f\x61\xf8\xa6\x52\xf2\x0e\xa0\x12\xc1\xad\xe3\xe2\x80\xec\xde\x29\x4c\x0e\x35\x71\x71\x90\x16\x2e\xc6\xa2\x26\x5e\x7e\x6f\x3f\x07\x04\xcf\x8a\xb1\xa0\x3e\x5c\xc9\x53\xe2\x92\x62\x91\xcc\xd4\xb0\x59\x0d\x5c\x20\x56\x8f\x94\xf9\xff\x0f\xe2\xab\x78\xcf\x9a\xe2\xc3\x8b\xcd\x49\x1e\x51\x8f\x23\xe9\xb6\x36\xf8\x80\x61\x5f\xc5\x60\x78\xe5\x12\xd7\x57\x7e\x09\x49\x7c\x11\x83\x45\x3d\x50\x81\xfd\x47\x37\xf2\x80\xec\x5e\x26\x7c\x45\x86\xb7\x8b\x70\xff\xfd\xfd\x73\x0d\x80\x9d\xf5\x60\xf2\xe3\x77\x21\x91\x84\x7b\xbc\x3f\x60\x4f\xb7\xf8\xca\x49\xee\xd3\x18\xb5\xe7\xd1\xf2\xb8\x3a\x10\xda\x0c\x85\x94\xb3\x39\xb6\x87\x1a\x57\x72\xdd\x64\x16\x8e\xcc\x27\xe2\x40\xa4\x5c\x76\x72\x5e\x7d\x55\xbe\xf3\x7e\x13\x5e\x3d\x9e\x0e\x34\xe3\x6c\x16\xe3\x4d\x77\x45\x9a\x55\x2f\x40\x74\xd0\x67\xa3\x1a\x3e\xd2\xa4\x8c\xde\xa4\x89\x5b\x10\xbd\xf1\x65\x6f\x4b\x7a\x41\x3c\x6a\x08\x8c\x64\x9f\xc9\xd7\xbc\x56\xab\xf6\x44\x35\x49\x12\x14\x19\x2a\x66\x70\xcb\x8b\x9c\x91\x7f\x8e\x1b\xc7\xb2\xcf\xce\x78\xd2\x8f\xbc\x3a\xfc\x2a\x50\xe9\x82\x13\xe7\xe0\x26\x37\x8e\x4e\xa7\x11\xd1\x51\xad\xaa\xa7\x19\xbe\xb8\x97\x46\x56\xc1\x0e\xbc\x7d\xe4\x6b\x19\xec\x82\x95\x1e\xf4\x6a\x8c\x68\xe7\xf4\x36\xe1\xb3\xeb\xed\xb2\xd0\x9b\x05\x75\xc9\x91\x4e\xad\x27\x96\xb5\x3e\x00\x61\xe2\x12\x99\x4a\xc5\x02\x6a\xea\x81\xec\x37\xc8\x13\x78\xf4\xcc\xfc\x46\x77\x00\x08\x79\x68\x59\x7d\xa3\x8f\xed\x52\xfa\x48\x09\x3a\xe4\xba\x10\x66\xc3\x1e\x3c\x7d\x85\x08\x09\x5b\xb4\x5c\x28\x01\x20\xf4\xaa\x69\xa2\x4f\x3e\xfe\xf1\xf7\x67\x98\x5a\xa1\xa3\x0e\x14\x08\x56\xf7\x6d\x15\x20\x73\x28\x78\x48\x7b\xe5\x3f\x71\x2d\xbd\x7d\x77\x9e\x31\x51\x01\x58\x8f\xd7\xdb\xdb\x13\x2f\x92\xc2\x75\x75\xac\x14\x86\xf1\x76\xc7\x90\x66\x1b\x01\x48\x39\x4e\x92\xff\xa3\xae\x6f\x8a\xfb\x2f\xaa\x2b\x7f\x4f\xbd\x0a\xd9\x1e\x75\x9a\x70\x2b\x3c\x70\x2b\x4d"}, -{{0xd0,0x0c,0x21,0x64,0x26,0x71,0x0d,0x19,0x4a,0x3d,0x11,0xcf,0xc9,0x0a,0x17,0xa8,0x62,0x12,0xe7,0xa0,0xe5,0x4b,0xaa,0x49,0xb0,0x16,0x9e,0x57,0xff,0xf8,0x3d,0x61,},{0xcf,0xe6,0xae,0x89,0x03,0xc6,0xc7,0x01,0xaa,0x30,0x46,0x95,0xc6,0x51,0xbf,0xd8,0x50,0x33,0x1f,0x9a,0xd4,0x81,0x63,0x3a,0xe3,0x70,0xc8,0x6d,0x7b,0xd1,0x3f,0xb9,},{0x15,0xc4,0x5c,0x19,0x42,0x97,0xe8,0x87,0x02,0x9f,0x49,0xd8,0xbd,0xf9,0xd6,0x10,0xdd,0x8c,0x34,0x79,0x9e,0x1e,0x92,0x30,0x26,0x9e,0x7a,0x58,0x92,0x89,0x38,0xcf,0x39,0x6a,0x02,0xcd,0x42,0x20,0x54,0x90,0x39,0x1e,0x1c,0x64,0x35,0x3f,0xb0,0x6b,0x9f,0x8e,0x9b,0x81,0x8a,0x9a,0x36,0x1c,0x20,0x4a,0x38,0x69,0x95,0xbf,0x3b,0x03,},"\x82\xf9\x78\x41\xb3\xba\x22\xdd\x9a\x44\x50\x83\x7e\xa7\xbf\x8d\x27\xa9\x73\x14\x70\xca\xbb\x0c\x20\x78\x03\x4b\xf2\x4e\x4c\x1a\x62\x90\xc0\x3f\x40\x02\xb8\x6f\xa0\x9f\x07\xb5\x20\x9f\x1f\x53\xd0\xec\xf4\xd9\xe9\x22\x3b\xec\x12\x5a\x95\x45\x51\xfe\x8b\xff\x71\x8f\x5e\x26\x48\x68\xe2\x07\xf7\x01\x19\x4e\x41\xde\x39\x97\x1f\xd3\x85\xf4\x9a\x4b\x4a\xdd\xa9\x11\xeb\xa5\x52\x59\xfc\x68\x36\x65\x32\x73\xf6\x56\xf4\xaf\x60\xb2\x06\x64\x95\x6d\x4f\x21\x35\xd9\x0d\x09\xe9\x03\x7d\x53\x66\xa0\x25\x34\x44\xe0\x22\xc7\x21\x2a\xf5\xfd\x4f\xcc\xd7\x42\x37\xd2\x88\x53\x38\xe2\xfd\x72\x15\x22\xde\x67\x63\xc2\x54\x90\x28\xc6\x23\xb9\xcf\x38\x7d\x23\x4a\xb5\xe7\xfc\xbe\x5a\x47\xc6\x85\xb7\x9e\x75\xa5\x7b\x09\x57\x40\x82\xa0\x22\x21\xdf\x64\xa2\xe8\x41\x61\x80\x87\xe7\x22\xa2\x1b\xac\x1b\xa4\xf0\xd7\xd8\x7b\xdc\x51\x0a\xaa\x8f\xbd\x10\x75\x7f\x6c\x02\x9c\xa8\x20\x37\x1f\xc7\x4c\x3b\xc5\x0b\xd8\x98\xc5\x5d\x81\x67\xf7\x3a\xda\x37\x7a\xec\xc9\x16\x29\xd6\x4c\x36\x0c\x2c\x24\x1c\x5c\xb4\x2e\x3a\x51\x8c\x5d\xab\xf0\xf4\x18\xb2\xa7\xf3\xd8\x2e\xef\xd9\x20\x26\xd3\x1e\x8b\x81\x60\x35\x8e\xae\x82\x1f\x73\x0e\xca\xfe\x7a\xce\x64\x7b\xff\x87\x41\xde\x2f\x6a\x13\x1d\x11\xc9\x69\xe9\x78\x7c\xfe\x6a\x2f\xab\x37\xbf\x8d\x1c\x7f\x4a\x2f\x36\x4d\x2f\x1a\x76\xef\x04\x6c\x18\x43\xe6\x3e\xc0\x0c\xf7\x92\x0f\xfa\xae\x56\x1e\x73\x70\xb7\x19\xfc\x16\xfc\xeb\xca\x3c\xfd\xfa\xba\x43\xf4\xf0\x90\xc4\x6f\x47\x73\x03\xa6\x60\xee\x88\xdd\x4e\x89\xbf\x14\xb9\xf8\x04\xb6\xfd\x49\x5c\xb1\x41\x27\x53\x47\x4a\x05\x6a\x0d\x89\x31\xcd\x9c\xcb\xd6\x4f\x8f\xcc\x7a\x31\x23\x46\x7c\x5d\x47\xf6\x90\x67\x9e\x88\x71\x28\x80\x93\x73\x4f\xd6\xa1\x32\x60\x38\x65\x81\x56\x41\x36\x96\x59\x4c\x13\x4d\x73\x88\x7f\x34\xee\x67\x60\x9a\xe8\xff\xb3\x26\x6c\x16\xd8\x7f\x15\x34\x5a\x47\x6f\x72\x95\x0c\x15\x87\x96\xa8\x8b\xbb\x44\x4f\x1a\xa8\x09\xca\xd8\x75\xb8\x5f\xb9\x15\x1a\x0e\x2e\xef\x2e\x00\xe8\x0d\x6b\x7a\x9b\xa4\x06\xc0\x51\x9e\xff\xdd\x94\x12\x62\x32\xfd\xf6\xf1\xe7\xb9\xbb\xc0\x36\x2a\xa7\x75\x16\xfd\xf9\x39\xe7\x90\x6a\xab\x01\x30\x71\x28\xcf\x82\x4c\x10\x2c\x09\xb9\x29\xc9\xb2\xd7\xaf\x8f\x85\xb7\xd7\xf9\xa8\x38\xb2\xae\xd0\xc6\x97\xe8\xbd\xfe\xe6\x6e\xe0\x16\xbb\x1b\xf3\x5e\xff\x6b\x2f\x7e\xf4\xb9\x1b\x1f\xc0\x4f\xac\x9f\x11\x6e\x2e\xdf\xf4\x0f\x95\xc1\x5b\x77\xc3\x1e\xe5\x22\xf3\x93\x7c\x7f\xa0\x04\x7d\x62\x25\xe0\xc8\xe5\x5e\x27\x8c\x81\x03\x91\x1f\xea\xb2\xb7\xf4"}, -{{0xdd,0x12,0x39,0x72,0xe6,0x28,0x58,0x4a,0xcc,0x46,0x29,0x3b,0x8e,0x4c,0xe2,0xb2,0xdd,0x46,0x9c,0xc4,0xed,0xe1,0x4e,0xf3,0x95,0x21,0xcf,0x08,0x37,0x35,0x85,0xb3,},{0x35,0x22,0xf7,0xae,0x59,0x6e,0xed,0xb2,0x17,0x03,0x5d,0x95,0x39,0x5e,0x44,0x8d,0xbd,0x6f,0xfb,0xf4,0x25,0x85,0xea,0xeb,0x30,0x70,0x26,0x54,0x1c,0x78,0xa6,0x51,},{0x89,0x65,0xa8,0x89,0xd5,0x4c,0xd8,0x07,0x6d,0x35,0xbc,0x2e,0x12,0xb0,0x09,0xd5,0x6b,0x07,0x04,0xc8,0x94,0xf9,0x12,0xa0,0xd1,0xd3,0x07,0x20,0xc2,0x32,0xfe,0x44,0x04,0xbf,0x30,0x09,0x54,0x1e,0x8f,0x32,0x83,0xe8,0x9e,0xa8,0x6f,0x67,0x8a,0xfb,0xdf,0x1c,0x21,0xc9,0x24,0xb2,0x3a,0x52,0xb4,0xca,0x6d,0x63,0xf4,0x8f,0xc2,0x03,},"\x2b\x28\x57\xf4\x52\x80\x17\x3e\x2e\x0e\xf9\xd5\x94\xe6\x08\x3f\x1d\xc7\xa6\x54\x92\x97\x5b\x83\x7d\xef\x6c\xad\xd8\xc8\x54\x50\x31\xee\x9d\x68\x36\x9a\x93\x93\xcc\x7b\x79\x2f\xeb\x98\x04\x0b\x21\xf1\xeb\x84\x66\x5f\x87\x85\x37\xce\x41\x2e\x9d\xb6\x80\xd2\x9f\xbd\x8f\xfc\x77\x31\xea\xe9\x1a\x20\xb4\x75\x48\x99\x62\x04\xfb\x06\xad\x74\x0e\x78\xf0\xfc\x59\x0b\x67\x91\xdc\x7a\x0f\x26\x59\x28\x6c\xc1\x6d\x02\xc5\x11\x7b\x56\x58\x36\xb4\xb8\x73\x8c\xf4\x0e\x28\x5c\x69\xc5\x0e\x41\x29\x11\x29\x23\x67\x35\x2d\xfd\xae\xd9\x98\x2d\x0f\x89\x9a\x23\xc0\xab\x51\x81\x2b\x3e\xc6\x78\xf6\x88\x2e\xa4\x27\xcd\xc9\x3a\xb4\xb2\x48\x24\x37\x70\x54\xaa\x25\xd8\x22\x46\x65\x33\x40\x07\x8c\xf1\x1d\x14\xa5\x1f\x0e\x68\x6d\x7e\x01\x8b\x36\x74\x16\x68\xfc\xe7\x45\x8d\x16\x92\x93\x36\x1d\xd1\x6b\x3d\xeb\xbe\xd1\x9e\x1b\xef\x7c\x36\x93\x4e\x20\xf3\x3a\x09\xad\x3e\x82\xb5\x3a\xb4\xe9\x4c\x25\x5d\x04\x18\x98\xb9\x77\x37\xdf\x99\x58\x4a\xf1\x4e\x40\x40\x58\xd0\xc9\x3b\xca\xe7\xbb\xbc\x06\x39\x5a\x2a\xef\xbd\xef\xa7\xb2\xed\x17\xce\xbd\x15\x13\xfa\x39\x0f\xe9\xa9\xb0\xce\x68\xce\xcc\x2b\x9e\x12\x9b\x7a\x29\xf4\x9b\x6d\x18\xc2\x8b\xac\xd3\xaf\x39\xdc\x39\xca\x97\x2f\x0e\x0d\x06\x85\x5d\x57\xc2\xb5\xfc\xac\x2f\x79\xcb\x8c\x05\x79\x9e\x4f\x65\x73\x46\x68\xda\xd6\xaa\x7a\x43\xa1\x18\x56\xe2\x3b\x1e\x73\x2d\x00\xe5\xfe\x38\x85\xb7\xda\xd4\x2e\xc1\x8a\xc8\xe0\x96\xa0\x80\xf7\xd5\x50\x70\xfd\xcf\xf6\x07\xbc\x0b\x85\x2d\x8a\x08\x0d\x2a\x74\x05\xd5\x94\x14\x69\x5f\x2e\xb7\xfb\x0a\xca\x23\xc8\x63\x57\x42\xf8\xae\x57\xf1\x37\x80\x31\x6e\x28\x08\x72\x37\x4e\x69\x29\x59\x8d\x02\x8a\x33\xc0\x5d\x83\x1c\xda\xbd\x02\x94\x93\xc3\xcc\x85\x9f\xff\x1a\x67\xd5\x62\x16\xf0\x2a\x22\x95\x66\x53\x65\x88\x7a\x35\x0a\x80\xaf\xaa\x0c\x36\x7a\x74\xd3\x70\x1a\xe8\x8f\x59\xd8\xa9\xd3\xa1\xdc\xe0\xcf\xd2\xea\xbe\x2a\xf5\x06\x5a\x1c\x7f\xca\x4a\xad\xcf\x8e\x51\xe7\x56\x12\xa1\x37\x1b\x4d\xc8\xff\xc0\xc0\xb9\xc4\xfa\xdb\x2f\x08\x1e\x2e\x03\x2d\x96\x81\x8e\x55\x73\x7a\xdd\xe3\xe1\xac\x12\x1f\x56\xcc\x86\xfb\x58\xa0\xa5\x82\x69\x2f\x62\xce\x58\xac\xce\x17\xaa\xfe\xc7\xbc\xb7\xe4\x4f\x83\x92\x58\xcd\x4a\x85\x1f\xc0\x13\x44\xee\x9f\x1b\xd0\x3e\xb9\x43\x44\xf4\x77\x86\x93\xc1\x71\xdd\x28\x92\xb2\x42\x6a\x88\x29\xab\x0c\xfe\x33\xa7\xd4\xa3\x6e\xb4\x01\x7f\x7f\xcf\xd2\x41\x34\xab\x8a\x45\xf2\x37\x17\xcd\x13\x8a\xa6\x00\x01\x72\xe3\x7b\x40\x64\xdc\x9b\x6d\x1e\x1e\xf3\xaf\x84\x97\x1d"}, -{{0x33,0x35,0xea,0x92,0x81,0x17,0xcf,0xee,0xfb,0xee,0xae,0x14,0x60,0x03,0x88,0x1b,0xdc,0x88,0x89,0xd6,0x58,0x0e,0xed,0x13,0x52,0x37,0x08,0x20,0xad,0x1f,0x58,0x4f,},{0xcb,0x20,0xd4,0xfd,0x75,0x61,0x84,0x80,0x13,0x11,0x1c,0x3e,0x97,0x61,0x7f,0x34,0x18,0x1d,0x2e,0x7f,0xbc,0xf1,0xbb,0x2a,0x2c,0xd2,0xe8,0xc1,0x77,0x5b,0x8b,0x03,},{0xf7,0xc3,0x9f,0x92,0x47,0xd2,0x2f,0x01,0x89,0x99,0x24,0x7f,0x0e,0x00,0x05,0xcd,0x63,0x07,0x6c,0xcf,0x2f,0xee,0x41,0x63,0x42,0x1f,0x86,0x40,0x7a,0x41,0x69,0x8c,0x40,0x58,0x16,0x64,0x73,0x51,0xc0,0x4e,0x93,0xb5,0x44,0x15,0xb6,0x2f,0xc0,0x3f,0xc8,0xc2,0x5e,0x20,0xf7,0x54,0x1d,0xab,0x03,0x19,0x7d,0xc9,0x00,0xb2,0x9c,0x0c,},"\x0f\xa7\xf6\xa6\xfc\xa9\x81\x42\x9b\x57\x2a\x67\x04\x87\x1b\xed\x14\x0d\xab\x93\xee\x19\x92\x00\x6e\x9a\x3b\xb2\xe6\xcc\x9a\x09\xd4\xc9\xcf\x17\x06\x6b\x32\xff\x7e\xf5\xb6\xb2\xe7\x91\x11\x78\xed\x74\x62\xc4\xc1\x75\x60\x31\x71\xca\x61\x36\x68\xb3\xbe\x19\x3d\x94\xc3\x52\x1e\x58\x89\x13\xb5\x94\x8b\x55\x0b\xe9\x9d\x82\xd9\x66\x19\x7d\x71\x0a\xcf\xd9\x59\x14\xcf\x3e\x19\x75\x36\xe8\x3e\x68\x23\x0d\xc3\xd6\x7e\x67\xdc\xdb\xde\xe0\x4f\x0d\x9c\x48\x02\x37\xec\xd2\x8f\x74\x33\x8d\xb5\xf3\xf6\x97\xd3\xd0\x7f\xf3\x36\x13\xbb\xce\x54\x2a\xcc\x9a\x7f\xed\x5d\x12\x49\x0b\x9b\xfe\x1d\x10\x95\x40\xf8\x63\x80\x0d\xd3\x56\xda\x84\x1a\x45\xa3\xcd\x8a\x08\xa9\x45\xbf\xa3\xaa\x98\xe1\x71\x23\x12\xc4\xc0\xf0\xd9\xdd\x64\xf6\xef\xcf\x73\x6b\xd9\x7d\xea\xfc\xa9\xdc\xaa\x3f\x06\xd8\x7f\x2e\xd7\x2a\xeb\x6a\x94\xf3\x28\x00\x00\xc4\xbf\x72\x8a\x01\xc1\x86\x2d\xaf\xd9\xfc\x5c\x7d\x5a\x46\xec\x7d\x3a\x87\xaf\x59\xa1\x1d\x87\xf7\xff\x84\x40\x7d\x37\x01\x0e\x1d\x94\x6c\xf2\x25\xd6\xb3\xb1\xed\xee\x2e\x8b\xbf\x1e\x07\x9e\x47\xfb\x1f\x66\x66\x93\x94\xfb\xf2\xfa\x68\xfc\x56\xfc\x89\x82\x0a\x68\x09\xc2\x51\xdd\x62\xf5\xb8\x65\xc5\x47\xb1\x4f\xbd\x3a\x19\x50\x42\x44\xff\xbc\x7e\x52\x40\xf8\x8d\x43\x60\xf9\xca\xca\xaf\x5f\x82\x43\x3d\x33\x44\xfc\xae\xe0\xac\xde\xb7\xbe\xb9\xc0\xb3\xc7\x69\xea\xc9\x20\xef\x4f\x09\xab\xc2\xa2\x09\x55\x12\x04\x59\x43\xec\xcc\x53\xb1\xc0\x3e\xd2\x4e\x56\x7f\x3d\x7a\x71\x97\x7c\xab\x98\x40\xce\x89\x8e\xe5\x8e\xd5\xc7\x3f\x6a\xde\xa8\x23\x39\x4c\x5c\x8e\x36\x58\xa6\xbf\x5a\xcb\xbf\x00\x55\x99\x2c\x31\x2c\x26\xc7\x9c\x5c\xfb\xea\x38\x60\xb8\x76\x4a\x6d\x8f\xfe\x44\x91\xf8\xa5\xb8\xa2\x15\xe0\x11\x7a\x9a\x68\x16\x4a\xee\x25\xf8\xc0\xbb\x38\x11\x95\xb2\x40\x0b\xcb\x46\x44\xeb\xce\x1c\xde\x5a\x9a\x26\x58\x2c\xab\x9d\xc7\xf4\x3c\x33\xea\xe3\x50\xdb\x65\xaa\x7d\xd2\x2a\x07\x9b\xdd\xdc\xf5\x6d\x84\x8d\xeb\x0c\xfa\x50\xb3\xbd\x73\x2d\x9d\xa9\xe8\xd8\xab\x79\xe9\x34\x69\xde\x58\x02\xb6\xdf\xf5\xac\x2a\xa8\x48\x2b\xb0\xb0\x36\xd8\xf9\xd5\x95\xb8\xea\xd9\x4b\xb8\xd7\x41\x8e\x2e\xa4\x31\x92\xef\xcb\xfc\x05\xc4\x67\xbd\xe0\xa8\x68\xa5\x16\xa7\xc1\x4a\x88\x9b\x72\xc5\xb7\x3e\x7d\x85\xc2\xba\xe9\x02\xe4\xe6\x8d\x1f\x3c\xea\xb2\xb2\x77\x3a\xf5\xbb\xae\xe6\xa0\x0d\x08\x06\x3e\x78\x33\xcd\x4e\x29\x53\x47\xe5\x8f\x5d\x1b\x33\x97\xf6\x40\xc1\x59\xcc\x60\xa6\x74\xa2\x27\xb4\xcd\x8c\x10\xf1\xdb\xae\xd5\x16\xcc\xac\xdd\x29\x5f\x11\xb0\x81\x47"}, -{{0x32,0xa1,0x88,0x3e,0xff,0x57,0xa3,0xa7,0xec,0xdb,0x31,0x02,0x21,0xee,0x83,0xc4,0xde,0x92,0xb7,0x22,0x15,0x96,0x13,0xec,0xf8,0x16,0xe3,0x82,0x43,0x7b,0x60,0xb9,},{0x82,0xdd,0x1a,0x03,0xe5,0x85,0x20,0x62,0xba,0x4a,0x8b,0x6b,0x3b,0x93,0xc5,0xe9,0xc4,0x3f,0xf6,0x99,0x5b,0xd2,0xaa,0xc7,0x26,0x06,0xfa,0xc8,0x58,0x02,0xc6,0x82,},{0x83,0x09,0xcb,0xe7,0x2f,0x80,0x4b,0xd9,0x52,0x1d,0xef,0x5d,0xad,0x4d,0x8b,0xc1,0x38,0x86,0xb1,0xd4,0xf6,0x62,0xc9,0xbb,0x5b,0x97,0xba,0x47,0x90,0xf4,0x4b,0x80,0x1f,0x31,0x95,0xea,0xd0,0xd4,0xdd,0xb6,0x60,0x81,0x8e,0xcb,0xf9,0xa6,0x83,0xca,0xcf,0x85,0xf1,0xdc,0xc9,0xe8,0x2c,0x09,0x11,0x6d,0x73,0x36,0x58,0x09,0x1a,0x00,},"\xed\x2b\x12\x3b\x5d\xd7\xf5\xe7\x18\xe0\x26\xc7\x9c\xfa\x61\x11\x92\x49\x02\xd1\x89\xa4\x06\xef\x2b\x2e\x56\xa9\xee\x55\x73\xa7\x6d\xdd\x1d\x06\x29\xeb\xcd\xec\xf2\xaa\xa7\x4e\x84\xfc\xd0\x20\x8f\x14\xee\xa2\xe1\x71\xe7\xc8\x60\x8b\x81\x8f\xef\xf4\xdb\xea\x52\xdb\x35\x42\x27\xd0\x23\x25\x0b\x1f\x01\xcb\x4c\xc8\xc5\x21\x32\xa9\x8d\x4a\xcf\x55\xa5\x4f\xee\x81\xe0\x94\xae\xd6\x6f\xa0\xd6\xb6\xa2\x00\xb6\xb8\x74\x14\x40\x22\x78\x53\x8b\x90\x52\x9a\x8c\x60\x3d\x92\x7e\xdd\xda\x97\xbc\x4b\x8c\xb9\x5d\x04\xb5\x33\x7f\xa2\x2c\xea\xfc\x8b\x34\x0c\x46\xfe\xf6\x71\x98\xd1\xfd\x98\xd8\x9c\x65\xcd\x08\x9e\x23\xf5\x3d\xbd\xca\x96\x77\x98\xb5\xcd\x92\x32\x05\xad\x51\x1e\xdf\x70\x6f\x12\x25\xf4\x64\x8c\x98\x5e\x00\x9e\xf8\xa2\xf6\xa0\x11\x7c\xdb\xe1\x4e\x75\x31\x2d\x8a\xc1\xf0\x3d\x04\x6b\x37\xcd\xee\x7d\x69\xc0\xf2\x5c\xcf\x18\x14\x5a\x68\x8a\x8b\x3c\xa8\x87\x5f\xe8\xd9\x0b\xaf\x86\xd4\x39\x69\xe4\xd6\x10\x21\x4f\x1a\xc5\xdb\xba\x87\xa1\xef\x10\x37\x7e\x40\xd7\x80\x6f\xd9\xd2\x34\x57\xfc\x9d\xf2\x98\x99\x23\x9f\xd1\xd2\x78\x84\x96\x81\xa9\x43\xad\x9c\x91\xfd\x1b\xbd\x92\xb7\x3c\xb1\x77\xa8\x78\xf9\x05\x9e\xe0\x7a\xf7\xa8\x73\x16\x13\xe3\x3d\x59\xdf\x3d\x97\x79\x60\x79\xd5\x63\x1e\xd8\x5e\xb2\x24\x51\x06\xa5\xff\x6a\x2b\xca\x40\xdf\x5c\x6e\x87\x47\x3b\x2c\x08\xc2\x21\x2f\x56\xfc\x29\x33\xa9\x69\xa3\xc9\x58\xd3\x7c\x53\x43\xba\x27\x60\xc8\x13\xa7\xa5\x16\x5d\x23\x1c\x5f\xea\xae\x62\xb7\x55\xdf\x49\xfe\xca\x80\x04\x1a\x65\x35\xf7\xe0\x3b\xc4\x8e\x5f\x27\xf9\xbe\x26\xef\x53\x67\x3e\xb7\xc3\x7a\x2b\x64\x74\x4a\x6c\xf1\x7e\x88\x77\x34\xae\x01\x0b\xf4\x0e\xea\x03\xcd\xa2\x12\xf5\x12\xfb\xa0\x58\x59\x47\x17\x96\x40\xbc\xc4\x54\x4b\x8d\xeb\x4e\xad\x12\x9b\xc3\x32\x28\x00\xad\xf9\x88\x18\xf9\x95\x74\xbe\xfd\x9b\x00\x16\xd4\xee\xc8\x1a\x8e\x78\xdc\x3a\x2a\xf1\x3c\xab\x01\x64\x9a\xe2\xe3\x3d\x51\x6b\x9d\x42\x08\xad\x66\x13\xd8\xe2\x78\xc3\x93\xba\xa8\x82\x34\x0e\xf4\x61\xff\x4f\x94\x42\x3d\x55\xcf\x3c\xed\xd2\xa6\xb5\x6e\x88\x36\x55\x31\xdd\x29\xd6\x82\x73\xad\xbf\xe3\x69\x40\x2e\x6a\x7c\xee\x05\x3d\xa1\xf1\x00\x54\x00\x91\xa0\x09\x29\x25\x29\x83\x44\x90\x24\xb1\xc3\x39\x11\x10\x65\x00\x82\xf0\xe7\xdf\xdd\xb8\xed\xc2\x04\x2f\x3c\x17\x13\xc6\x94\x4b\xa5\x14\xee\x74\x07\xd3\x2b\xf0\x6c\x85\x8e\xfe\xc4\x2a\x78\xbe\xe9\x77\x46\xe5\xb4\x87\x91\x41\xa1\x3d\x9f\xc5\xcb\x12\x3b\x78\x32\x73\xb8\x4d\x57\xad\x35\x26\xb7\xda\x3c\x68\xb8\x39\xef\xd2\x3f\x5f"}, -{{0x22,0xec,0xef,0x6d,0xab,0xe5,0x8c,0x06,0x69,0xb8,0x04,0x66,0x49,0x73,0xe4,0x57,0xc0,0x5e,0x47,0x77,0xf7,0x81,0xc5,0x25,0x22,0xaf,0x76,0xb9,0x54,0x81,0xa9,0x14,},{0xd4,0x78,0x40,0x10,0xef,0x04,0x03,0xed,0xdc,0x5a,0x62,0xd5,0xd4,0x5b,0xb2,0x43,0xb8,0x0b,0x4b,0x9d,0x69,0xc3,0x9c,0xa3,0x87,0xc6,0xf5,0xcb,0xa0,0x28,0x64,0x0f,},{0x5d,0x0d,0x2a,0xf6,0x78,0xb3,0xd1,0xb6,0x77,0x51,0x6d,0x08,0xa7,0x9a,0xaf,0xd3,0x6e,0xc6,0x7c,0x14,0xca,0xf5,0xbc,0xda,0xae,0xaa,0xcc,0x51,0xa1,0x4f,0xb8,0x05,0xcf,0x29,0x04,0xe8,0x72,0x1d,0xb2,0x71,0xb2,0x0d,0xf7,0x09,0xbe,0xe1,0xa4,0xfb,0xfe,0x62,0x56,0x50,0x73,0xb2,0xa7,0xe9,0x42,0x72,0x44,0x61,0xf9,0x27,0x93,0x0d,},"\xc5\x35\xc1\x3d\x77\x9f\xc0\x98\x59\x73\xd6\xbc\xd5\x52\xd8\x17\x34\xe9\x2b\xdf\x10\x99\x4b\x00\xcd\x4d\x53\xce\x36\x5f\xad\x8c\x7c\xfa\x96\x20\x6a\xdb\x62\xd4\x56\x7b\xe5\xe4\x66\x31\x32\x38\x53\xe3\x8c\xe4\xbd\xc1\x6d\x7b\x8f\x63\x2a\x3a\xd9\xe0\x26\x19\xef\xf3\x71\x74\xea\xc3\xf0\xbf\x2f\x7a\x75\x17\xd4\xb8\x2d\xe6\xaa\x1a\xf0\x06\x38\x19\xd5\xe1\xf9\x27\x8f\xb4\xf2\x4c\x8c\xc0\x02\xaf\xb1\x5f\x33\x4c\x04\xfa\xdb\x00\x30\x30\x13\xc0\x16\x67\xf4\x93\x2a\x6c\x4b\x97\xd3\x9c\xd4\xa4\x59\x85\x06\xc0\xbd\x74\x0e\xa9\xf1\x16\x96\x35\x7d\x7d\x17\xfe\x4d\x75\xf9\xd7\x42\x41\xa7\xaf\x71\xf9\xd8\x69\xef\x6c\xd6\x95\x68\x7c\x03\xfc\x34\xad\x65\xa6\x8a\x48\x88\xa1\xa7\x41\x26\xcb\x55\xcf\x7d\xa9\xcb\x4a\x67\x17\xf6\xeb\x88\x48\x40\x89\xd2\xc5\x18\x9a\xe3\x81\xf2\x5e\x7b\x3b\xc3\xb2\x3d\x0c\x9d\x9f\x9c\xdb\xbe\xec\xfd\x1e\x72\xa0\x5e\x67\xbb\x48\x3a\x97\x64\xd9\xfc\x75\xad\x69\xe4\xab\x12\x70\xfb\x40\xf3\x95\x8f\xea\x4d\xa5\x59\xb4\x39\x80\xb2\x46\x81\x31\x3e\x85\x91\xe6\x85\x46\xa3\xbf\x76\xee\x34\xb3\x39\x70\x92\x95\xa8\xd4\x6f\xb2\x43\x2d\xda\x2f\x22\x18\x12\xdf\x69\x28\x95\xe6\x7c\xb2\x9c\xbf\x6f\xf4\x50\x2b\x43\x9a\x4e\x9e\x43\x63\x9e\xc0\x67\xbc\x90\xae\x81\x4a\x29\x3a\x7b\xd4\x69\x68\xe6\x56\x78\x76\x42\x30\x0a\x0f\xf2\x69\x7e\x33\x13\xf6\xa4\x18\xd3\xd1\x2a\x5f\x7c\x51\xa4\xc5\x7b\x63\x38\x5f\x2d\x2a\x21\xd5\xd1\xd7\x63\xfc\x8d\x1b\x93\xc1\x34\x35\xf9\xe4\x7e\xe7\xa4\x25\x98\x0a\x6a\xe6\xf1\xa9\xd0\x07\x60\x74\x76\x78\x3c\x6d\x0c\x78\x87\x38\x0f\x86\x8c\x65\xb3\x82\xd4\xcc\x8c\x04\x47\x8b\xbd\x79\xa1\xd9\xa9\x64\xb7\x81\x71\xd6\xbc\xf0\xb8\xee\xc5\x0a\x06\xa4\xea\x23\x4d\x1c\x23\x46\x5d\x3e\x75\xb8\x8b\xc5\x40\xda\xde\x74\xed\x42\x67\x5b\x07\xf7\xcf\x07\x82\x11\xe9\x07\xf8\x6d\x0d\xc4\xb9\x78\x62\x3d\x9f\x08\x73\x8a\xf9\x28\x69\x5e\x54\x2e\xc2\x98\x0e\x55\xa1\xde\x49\xe2\x52\x47\xfa\x0a\x09\x67\x81\x18\xe3\x93\x0b\xc4\xd2\x4b\x32\x14\xd6\xdc\xfb\x6e\xbd\xf4\x90\x6c\x92\x8d\xeb\x37\xbb\x9b\xa2\x9c\x8d\xe1\xbb\x94\x18\xdb\x71\x8b\x28\x53\xba\x57\xad\x8c\xae\x46\x77\xad\xdf\xd1\x8b\x6c\x7e\x8c\x24\x26\x21\xb3\x5c\x7f\x0e\xfe\x8d\xd5\xeb\x26\xff\x75\xfd\x57\x48\xb1\xd7\x83\xf6\xd6\x8a\x7d\x9d\x56\xda\x2c\x1a\x97\x8a\xc2\x5f\x84\xfb\xb2\xbe\x55\x68\xd9\x1e\x70\x93\x82\x21\xc1\x02\xae\xe6\x04\x09\xbc\xbe\xc0\xc8\x2e\x12\xdd\xb4\x25\xee\xb6\xec\xd1\x15\x51\xec\xd1\xd3\x3d\xda\xe8\x71\xae\x0c\x8f\x24\xd0\xd1\x80\x18\x73\x2b\x5e\x0e"}, -{{0x8d,0xe8,0x63,0x30,0xb2,0x56,0x09,0x5e,0x11,0x14,0xb6,0x52,0x9b,0xed,0xce,0x18,0x2c,0x16,0x6f,0x67,0xa9,0x15,0x39,0xce,0xbc,0x4b,0xec,0x25,0xad,0xd7,0xa4,0xa9,},{0x33,0xcb,0x05,0x4b,0x55,0xbb,0x79,0x0a,0xc0,0xf3,0xaf,0xdd,0x9a,0x6e,0x7c,0x05,0x0e,0xfe,0x90,0x06,0xc2,0x4f,0x60,0xb8,0x04,0x4f,0xd0,0x8a,0x5c,0x10,0x6c,0x11,},{0x6d,0x01,0xd2,0x37,0xdd,0x2b,0xb4,0x18,0x8d,0x29,0xbf,0xde,0xc3,0x87,0x97,0x6a,0x71,0xbe,0x7a,0xdf,0xbf,0x9e,0x23,0x63,0x9b,0x21,0x6d,0x0a,0xa0,0xc1,0x19,0x32,0x23,0x5e,0xdc,0xcb,0x3b,0x42,0xad,0xcd,0xb6,0x29,0x1a,0x0d,0x29,0x9a,0xed,0x64,0x8d,0xe8,0xb1,0x95,0x79,0x49,0xb9,0xd1,0xcf,0x2e,0x50,0x49,0x30,0x30,0xa4,0x0f,},"\x39\xe6\x1e\x0e\xcc\xec\x92\x9c\x87\xb8\xb2\x2d\x4f\xd1\x8a\xea\xbf\x42\xe9\xce\x7b\x01\x5f\x2a\x8c\xac\x92\xa5\x24\x48\xa4\x2f\xed\x4c\xba\xdc\x08\x5b\xbb\x4c\x03\x71\x2a\xe7\x2c\xfc\xb8\x00\xb9\x78\x35\x06\x69\xb0\x99\x00\x84\xf2\xda\xb7\x6e\xca\x60\x6d\x1a\x49\xfc\x55\xc5\x29\xe1\xe7\xda\xdf\x39\x12\x2d\xd5\xbd\x73\x38\x93\x85\x8b\x05\x23\xef\x62\xdf\x4f\x13\x4c\xf6\xc2\x6e\xed\x02\xfd\xbc\xb3\x0c\xe4\x74\xb1\xad\xa3\xf0\x60\x76\x9f\x93\x4b\xbe\x68\x6c\xce\xbd\x60\x88\x3e\xce\xc9\xce\x3f\xfb\x8a\xc4\xa0\x67\x8c\xdc\x5b\x00\x5a\xe3\xdb\xa7\xe4\xfe\x8b\xc0\x45\x73\x99\x57\xd8\x49\xf6\x9c\x14\x74\x05\x7b\x42\x8c\x54\x25\xf3\xcc\x25\x16\xe8\xbb\xe3\xbe\x81\xaf\xd4\xe7\xb5\x75\xab\xe8\x8c\x87\xf2\xf0\x3b\x56\xf6\x9f\x9e\x3b\x61\xb3\x78\x81\x20\xda\xa4\x95\xef\x0e\x50\xeb\x97\x0a\x64\x5c\x13\xd2\x13\xc7\xcf\xb7\xd0\xad\x55\x5c\x92\x0a\x1e\x5d\xbc\xb4\x67\x97\xd9\x39\xfe\x04\x01\xf5\x47\xbf\xd1\x75\x43\x22\x1a\x53\x01\x0d\xe0\x1f\x25\xb6\x45\x19\xc8\xf0\x39\x63\xe4\xb9\xca\x58\xb0\x11\x36\x27\xc0\x5b\x96\x08\xee\xaa\x7b\x9a\xe6\x30\x5c\x96\x18\x81\x60\x00\x0e\xe3\xa7\xad\xe9\x6e\x0b\x4b\xde\x9d\x0e\xd6\xa0\xce\xd7\x65\xd7\x86\x84\x0a\x48\x17\x5a\x6e\x09\x0a\x38\xaf\x6a\xde\xaa\x14\x86\xa9\xcb\x5c\x8c\x8c\x92\x23\xee\x0a\xe4\xc6\xc0\x26\x91\xa3\x54\x7e\x32\x58\x2a\x5b\x70\x59\xd2\xee\x66\xfa\x9c\xd9\x65\x61\x5c\x31\x5b\x47\x6f\xd8\x61\x27\x9c\xd1\xdd\x76\x07\x74\x3f\xc5\x56\x12\x96\x31\x2f\x11\xe4\x65\xca\x40\xbc\xe3\xcf\x0b\x1f\x1d\x5a\x30\xaf\x60\x87\xde\x4d\xe9\x6c\xe4\x39\x65\xa4\x6c\x4f\xcc\xa1\x5f\x28\x11\x49\xb5\xc1\xa0\xc8\x8f\xdb\xf2\x74\x09\xa1\x34\xed\x4f\x1f\xb7\x30\xfa\x19\x18\x16\xea\x78\x4d\x98\x6c\xc9\xec\x4b\x69\x44\x02\xde\x1d\xcc\xa9\xcc\xc6\x4f\xbd\x07\xb0\x7e\x54\xe9\x31\xde\x82\x7a\x84\x24\x60\xca\x0b\xf6\xb0\x4e\xbb\x57\x1f\xa7\x77\x87\xe3\x88\x4b\xe2\x2f\x1e\x40\x2c\xf2\xb8\xa9\x6a\x5d\x39\x77\x0e\xc4\xa8\x43\x03\x61\x42\xa0\xbe\x97\x0b\xb1\xab\x16\x5a\x63\x74\xdc\xf4\x3d\xeb\x8b\x98\x30\xb2\xc4\x9d\xb9\xcd\xfe\x4b\x52\x42\xe3\x6f\x95\xe0\xc3\xe0\x77\xe8\xd2\x38\xfa\x6a\x8a\xc0\xd5\x86\xbf\x61\xb8\x24\x8f\xb3\xa7\x9a\x27\x0a\xb2\x2b\xe8\xa9\xda\x05\x5f\xf3\xd5\xbb\x2d\x1c\xa9\xbc\x25\xf7\x01\x4b\x96\x40\x77\x19\xde\x34\x4c\x3e\x73\xb8\xc1\x14\xf7\x92\x07\x5a\x5c\x22\xfd\xd4\x16\x15\x4d\x34\x94\xec\x3f\x02\xfb\x11\x2e\xe5\x73\x7f\x70\x70\x4c\x1b\x6b\x07\xea\xcb\xf9\x45\x62\xca\x7b\x90\xdd\x84\xd9\x8c\x3e\xdf"}, -{{0xba,0xb5,0xfa,0x49,0x18,0x7d,0xa1,0xca,0xb1,0xd2,0x91,0x90,0x00,0x19,0xe6,0xcb,0xaf,0xec,0xcd,0x27,0xbf,0x7e,0xcb,0xf1,0x26,0x2a,0x70,0x05,0x16,0xe7,0xc2,0x9f,},{0xf6,0xfb,0x19,0x85,0xec,0x59,0x1f,0x69,0xe3,0xba,0xc8,0x07,0xb2,0xea,0xbf,0x26,0x39,0x90,0xcd,0xfa,0x09,0xb1,0x78,0x09,0xe4,0x8e,0x38,0x5d,0xa0,0x65,0xec,0x21,},{0xe3,0x16,0x03,0x8d,0x6a,0xa1,0x5b,0x1c,0x1b,0x61,0xc1,0xa1,0x6b,0x36,0x90,0x4f,0xe8,0xa2,0x89,0xc8,0xd6,0x02,0xbe,0xcc,0x51,0x4d,0x99,0x22,0x00,0x86,0xb2,0x67,0x85,0x9f,0x5b,0xf6,0xe9,0xc0,0x86,0x35,0x59,0xac,0x62,0x3a,0x56,0xd7,0x53,0x23,0x44,0xe8,0xd2,0xf2,0x8b,0x3f,0x9d,0xf9,0x20,0x89,0x70,0x8b,0x1b,0x05,0x90,0x08,},"\x5c\xf8\xff\x58\x7e\x52\xcc\xcd\x29\x84\xf3\x47\x91\xee\x68\x43\xe7\x70\x17\xc3\xb5\x5a\xd4\x5c\x44\x45\x09\x65\xb7\x5d\x83\x6e\x78\xfb\xd7\xa1\xd1\x72\x9e\xff\x6d\x6d\x34\x0a\x90\x3f\x3c\xf1\x7d\x9e\x2a\xec\xaa\xff\x2a\x32\x1f\xcd\xde\x0a\xbc\xfb\xbc\xbc\xc0\x9f\x40\x86\xf8\x12\xc4\x6e\xfb\x01\xb7\x83\x43\xaf\xbe\x48\x30\x9f\x91\x74\x78\x45\x5f\x32\x00\x0c\x6a\x69\xf7\x9f\xe2\x11\xb9\x9f\x03\x7f\x59\x56\xd7\x22\x75\xa7\xfe\x7b\x45\x29\x6b\x5f\x73\x9a\xa4\x51\xff\x05\x75\xbc\x70\x58\x85\xaa\x56\x31\xb0\xd0\x85\x0b\xc2\xb1\x2c\x41\x92\x43\x5a\xe5\xd2\xf5\x2b\xc5\x43\x86\x49\x7c\x4a\x24\xb8\xb6\xdb\x51\x6b\xe0\x9d\x8c\xcf\x1e\xca\x78\x5b\xde\x97\xe9\xbe\x1a\xc0\x64\xf0\x94\xe2\xaf\xcc\x30\x7c\x0e\x06\xb4\xc5\x64\xcd\x9a\x9a\x95\x30\x5b\x37\xb8\x1f\x43\x46\x11\xdc\xa5\x5c\xaa\xa0\x31\xe8\x84\x95\xd5\xdc\x5a\x04\xff\x5f\xaf\xdf\x0a\x82\xa0\xc0\x3a\xff\x1b\xfb\xf4\xff\xeb\xae\x71\x82\x4e\x35\xe7\x51\xb0\x92\x70\x00\x76\x69\x86\x0b\x58\x00\x35\x65\x9e\x23\xac\xe7\x6b\x3b\x36\x9f\xa3\x06\xf2\xbe\xd9\x57\x99\xfa\xfa\xbc\x2e\x69\xc1\x41\xbe\xb0\xba\xca\xc7\xea\xa3\x47\xe7\x7b\xe5\xaf\x3f\xcd\xbe\x7b\x36\x4a\x7f\x9a\x66\xd5\xe1\x7a\x07\xdf\x62\x02\xfd\x98\xc1\x4b\xfe\xe2\xca\x6f\x07\x45\x65\x1f\x0c\x85\x50\xf9\xff\xff\xca\xfb\x96\xff\xb3\xf1\x03\xe6\x52\xe7\x8f\x53\x91\x6c\xd6\xf1\xdd\x05\xb3\xfe\x99\xb3\x42\x01\xb0\x7e\xac\x26\x52\xf5\x25\x35\x71\xfd\x38\x22\xc6\x95\xd2\x65\xc7\xdf\xdd\x6c\x6b\x14\xa8\x0b\x6e\x87\x18\x3e\x6e\x03\x2e\x5f\x24\x01\xcd\x23\x8c\xdd\x37\x69\xbb\x6e\x39\x08\x23\x43\x8f\x56\x73\xea\x9a\x47\x9e\x5c\x63\xfe\x07\xa0\x7f\x4e\x14\xf5\x77\x57\xc4\xd7\xd2\x2b\x35\xd7\x1c\x44\xea\xad\x48\x73\xc8\xec\xa6\xf6\xb2\x1d\xcf\xa9\x55\x20\xff\x96\x14\xab\xf7\xa0\xe1\x88\x53\x09\xf2\xce\xd3\xbc\xdf\xc3\x19\x36\x3a\x2d\xa4\x6d\xed\x79\xa5\xcc\x7b\x6f\x69\x38\x3f\x94\xab\x35\xc2\x50\x62\x9c\xb9\x15\xd6\x67\xb6\x28\x11\x86\x75\x48\x95\x80\x3e\x4b\x95\xe7\x41\x82\x89\xa6\xac\x3b\xcd\xb6\xe1\xe7\xf6\xf1\xdc\x38\xe7\x7d\x28\x19\x14\xcc\x40\x4f\x97\xcf\xf1\x4f\xb2\xc4\xfd\x81\x41\x2d\x10\x1c\x1b\xfb\x36\x8c\xe5\x93\x11\xe8\x92\xa8\xb9\xcd\xca\x86\x93\x6f\x3b\xca\x7e\xc7\x91\x63\xed\xdf\x1c\xee\x68\xf4\x9f\x1e\xba\xa2\x7e\xc5\x0f\x49\x0d\x61\x60\x1c\xa3\x5f\x8d\x6e\xd2\x66\x05\x4a\xeb\x9b\x19\x9f\x93\x3b\xff\xd6\xe0\x05\x0f\x26\x1b\x4e\x13\xd5\xeb\xfe\x2c\xaa\x65\x57\xc3\x2d\xde\xae\xeb\xc2\xa1\x1f\x0a\xa2\x33\x24\x0d\xa1\xc7\xe4\x0f\x76"}, -{{0x74,0xca,0x12,0x2a,0xb6,0x0d,0xe5,0x0c,0xdc,0x04,0xa8,0xe2,0xed,0xa4,0x5d,0x96,0x31,0x06,0x1b,0xf1,0x87,0xd3,0x16,0xbe,0x5b,0x7c,0xc0,0x6f,0x02,0x0c,0x48,0x3e,},{0x78,0x7d,0xef,0xd4,0xfb,0x24,0xa3,0x99,0xbd,0x2a,0x4e,0x76,0xdf,0xf7,0xd6,0x03,0xed,0x0a,0xcb,0x32,0x69,0x81,0x3e,0x4d,0xf6,0x90,0xbb,0xf5,0xb2,0xbc,0x69,0x6e,},{0xbc,0xb4,0xb8,0x50,0x69,0x60,0x11,0x99,0x7e,0xb5,0xdf,0xe1,0x43,0xf1,0xa3,0xd5,0x62,0x8e,0xf1,0xa5,0x40,0x76,0x91,0xee,0x48,0xc7,0x9d,0x69,0xab,0xe4,0xd5,0x33,0xf8,0x17,0xad,0x73,0x13,0xb5,0x79,0x5e,0x46,0xe5,0x95,0xf3,0xae,0x3a,0x91,0x65,0xb1,0xb6,0xfd,0xda,0xe8,0x61,0x64,0xff,0xcb,0xa3,0x76,0x24,0x98,0x37,0xf6,0x09,},"\xa8\x0b\x46\x07\x9f\xa7\x75\xf8\xc1\xa1\x9f\xa0\x82\x9b\xe6\x66\xbd\xfd\xca\x07\x9c\xad\x43\xd7\x0e\x08\x42\x18\x3b\xc0\xdb\x95\x46\x8a\x53\x9f\x0d\xb2\xae\xa3\xab\x9c\x70\x73\xb4\x5d\x22\x8a\x9b\xde\x23\x28\x97\xa6\xeb\x6f\xc9\xed\xf7\x36\x5e\x71\x01\xba\x97\xc4\x46\xa5\x19\xa3\x64\x9c\xf5\x27\xc8\xa6\xde\x72\x51\xb9\x28\x06\x81\x5a\xc2\xfa\x00\x82\xef\xf7\x5e\x25\x82\xcb\xca\x7e\x1e\x4d\xa2\xa4\x46\xea\x23\x3e\x7c\xf7\xce\xdf\xb0\xe2\x39\x8e\xb6\xe1\x1b\xba\xef\xe3\xf7\xec\x89\xf5\xd7\x3d\xd3\x4b\xd4\x7f\xbc\xb4\xd7\xb2\x2f\x2a\xae\xe3\x73\x78\x56\x51\x84\x11\x35\xcd\x86\x61\xa7\x01\xb2\x10\x84\xa3\x16\xde\xac\x30\x74\xe2\x4a\x2e\x35\xa0\x33\x0f\x7d\x14\x79\xb9\x32\xf2\x85\x27\x7c\x18\xa4\x41\x78\x72\x24\xfb\xbe\x46\xc6\x2e\x83\x4a\x18\x51\xed\x23\x79\x98\xd4\x8d\xce\x20\xba\x11\x4d\x11\xe9\x41\xbe\x29\xd5\x6d\x02\xf7\x37\x0c\x8f\x6d\x6d\x7e\x50\x24\x8d\xcd\x8e\xc8\x9d\x3b\x22\xf4\xf5\x87\x78\x12\x9f\xaf\xd4\xbb\x92\xed\xe1\x77\x14\xbf\x02\x2a\x5b\xf9\x2b\xe4\x79\xf1\x8e\x63\x85\x2e\xcd\xcf\x8c\x42\x11\xf5\x30\xdd\x30\xf7\x9c\xbf\x4b\xfa\x57\x37\xf0\xba\xd3\xb0\x10\x60\x67\xf4\x13\x27\xc3\x18\x9e\x6f\x20\x6f\x0d\x4f\x3c\x70\x4b\xf2\xbd\x0b\x16\x1f\x01\x8f\xd2\x1c\xdd\xfb\x41\x8b\xac\x4d\x52\xef\x02\xc4\x1c\x87\x92\xe4\x13\xb0\x4f\x08\x36\xce\xa1\xf8\x6c\x92\xe5\xd5\x70\x3b\xee\x2b\x5c\x58\x99\xe2\x85\x99\x20\x24\xf6\x4e\x0d\x16\xc6\x0a\xd0\xfd\x92\x54\x79\x32\xd0\xc5\xcb\x98\xd8\xda\x22\xfe\xeb\xdb\xba\x8d\x1d\xe1\xe7\xe9\xbb\x21\x9a\x92\xeb\x6c\x1c\x69\x8d\x3b\x33\xa3\x7f\x9b\x81\x97\xd2\x6b\x55\x0f\xeb\xd2\x60\x1e\x7a\x64\x3e\xa7\xe1\xd9\xe4\x48\xae\x03\x7f\x62\x9a\x30\x6c\xe4\x17\xae\xb7\x9f\x2e\x3c\xa4\x4d\x8d\xb3\x84\x8a\x81\x1f\x18\x46\x81\x1c\xbc\xb8\x74\xf8\xaf\x09\xe0\xfd\x01\x73\xcf\x17\x5f\x30\x41\x15\x47\x6b\xf2\xc6\xc2\xd2\xf3\x32\xeb\xa5\x34\xf4\x6a\xae\x80\x1c\x26\x92\xc2\xd2\xfa\xdd\xfe\xac\xc0\xf1\xda\xce\x44\x0a\xbc\x2a\xe5\xe5\xa4\x9d\x57\x8f\xd7\xf9\xde\x2a\x84\x1a\xd6\xb6\x76\x9c\x32\xb1\x44\xce\xea\x16\xd0\xf3\xc0\xcb\x3a\x8e\xe6\x94\xc3\x8c\x28\x07\x35\x95\x09\x6c\x81\x37\x62\xcc\x2c\x5e\xc4\xb0\xd8\xd7\x23\xdd\x66\x08\x53\x27\x8f\xc7\x2f\xd6\xbd\x9d\x12\x72\x93\x3d\xd2\xa3\x8e\xd9\xd0\x4b\x13\x90\xff\xe4\xb2\x94\xa6\xff\xfa\x72\x1e\xe3\xbb\xa3\x3a\x03\xa1\x49\xc4\xa0\x34\x52\x65\xc0\x1c\xe0\x15\xe9\x4d\xb4\x19\xcf\xf7\x04\x98\x52\xee\x00\x00\x48\xa8\x57\x58\xf6\xd7\xb1\xc5\x9c\x50\x89\xee\x01\x8e\xd0\x9b\x52"}, -{{0x65,0xee,0xa9,0xff,0xb7,0x56,0x12,0xbd,0xe1,0xd9,0xba,0x3e,0xa4,0xfb,0x5e,0xda,0x0a,0xa6,0xf2,0x55,0x6a,0xb1,0x5b,0xf1,0x81,0x7c,0xee,0x3b,0x95,0xbb,0xba,0x12,},{0x5b,0x39,0x36,0xdc,0x74,0x9b,0x6b,0x92,0x39,0xf1,0x57,0x98,0xac,0xca,0xfd,0x88,0x4c,0x36,0x59,0xee,0x01,0xb2,0xd1,0x7d,0x74,0xfc,0x7d,0xa7,0x82,0x74,0xe7,0xe6,},{0xba,0xa7,0x11,0x31,0x55,0x35,0x8c,0x92,0x4f,0xed,0x57,0x48,0x8a,0x65,0x67,0xf8,0x72,0x38,0x50,0xa9,0xf5,0xc0,0x3a,0x0d,0x7d,0xe8,0x5f,0xcc,0xd8,0xfb,0x4d,0x17,0xd7,0x75,0x35,0x23,0xb0,0x0c,0x0d,0x8a,0xdb,0x88,0x4d,0xc0,0xc8,0xa7,0xa4,0x4d,0xc2,0xa6,0x00,0x83,0xaa,0x5b,0x3c,0x5b,0x94,0xa8,0xd8,0x80,0xf2,0xa9,0x4d,0x09,},"\xc0\x69\x36\x32\x3c\xe3\x25\x3c\xac\x5a\xb4\xf6\xb8\x32\x70\xcd\x4c\xfe\x85\xd0\xbf\x8b\xac\x1e\x1b\x8d\x5f\x0b\x15\x3f\x54\x1c\x8e\x8e\xd9\x5f\x28\xd5\xc8\x5a\x23\x15\xcd\x93\x1b\x7c\xf3\xed\xae\x50\xf9\x28\x30\x59\x91\x62\x80\x4b\x13\x63\xd3\xac\x0d\xa0\xab\xd0\x97\x51\x02\x3b\xdd\xc1\x62\x88\x94\x4e\x61\x6d\x21\xd9\x12\x71\x97\x8b\xb7\x82\xd3\xeb\xed\x7f\xa6\x12\x84\xc7\x49\x0d\x27\x59\x3c\xa8\xa3\xd5\xb4\x75\x62\x33\x07\x01\x0a\xbc\x1f\xbf\x79\x3a\x81\x6a\xaa\xb5\xe0\x92\x4d\xec\x79\xd6\x04\x98\x96\x5c\xf7\xf8\x0a\xb5\x9f\xc0\x29\xf7\x82\x16\x67\x55\xb7\x2b\x86\x90\x75\x43\x4a\xb6\x06\xcc\x87\x0a\x7c\x0b\xc8\xbf\x29\xae\xe0\x33\xfa\x9c\xc1\x22\xed\x7c\x8e\x06\x9b\x54\x7d\xba\xe2\x59\x01\xb9\xe2\x49\xb4\x1f\xea\x0b\xf8\xda\xf3\x82\x68\x66\xbc\xae\xd2\x75\x3b\x5e\x91\xae\x93\x7e\x71\x7b\x50\x8a\x0a\xcf\x4c\x3b\x06\x1f\xf0\xcb\x9c\xfd\x38\x0e\x24\x94\x50\x09\x51\xa6\x62\xfd\x49\x28\xfc\x5f\xca\xf6\xc1\x8e\x84\xb1\xd3\x78\xe4\x9b\xd9\xd5\x96\x86\xd0\x87\xeb\xd5\x52\xd0\x7f\xa9\xba\x81\x6f\xa5\x40\x2c\xa9\xe7\x25\x2a\x64\x8d\x10\x6c\xfe\x6c\x43\x1c\xc2\xa0\x53\xe2\x29\x46\x37\xcd\xb9\x9d\x96\xab\xe6\x89\xed\xab\xc5\xca\x07\x0f\x77\xc1\xec\xd1\xd5\x2d\x53\x85\x28\x9f\x17\xce\xd7\x68\xc3\x97\x16\x71\xb9\xc0\xb2\xf8\x55\xb8\x46\x1c\x1e\x74\x6c\x7b\x38\xf7\x78\x96\xb8\x5a\xfb\xbe\xdd\x08\x37\x5f\xe9\x22\x98\x46\x14\xdd\x84\x9f\xe2\xcb\x89\xae\x71\x49\xdc\xd1\xd3\x7f\x49\x36\xe6\x7b\x14\x40\xbe\x72\xe0\x09\x39\x8b\xe6\xf0\x83\xbf\x96\x11\x48\x0b\x59\x2f\xe2\xf0\x11\x8e\x25\x3d\xb5\xd2\xe9\xe4\xb4\x54\x1c\x11\xda\x00\xf7\x16\x1a\x73\x6e\x5f\x0b\xb9\x34\x20\x8e\x3e\xf4\xe0\xb9\xa5\x22\x58\x20\x3f\x06\x0d\x18\xa1\x95\x15\x9e\x5e\x26\x8a\xa2\x80\x53\xc8\x34\xf7\xbd\x5d\xb9\xbd\x71\xf5\x07\xd9\x13\x70\xb3\xff\xca\xbb\xd4\xac\xb3\x07\x1d\x3f\x6d\x52\xc3\x49\xac\xf3\x50\x95\x34\x8c\xeb\xf5\xa8\x6f\x8c\x59\xdd\xc9\x65\xef\xf6\x10\xac\x42\x58\x04\xc0\xe2\xf6\xbe\x42\x85\x3f\x5b\x46\x43\x4a\x2c\x31\xd9\xac\x99\x53\x9b\xfd\xc0\x4e\xcf\x2f\xef\xd0\x45\x98\xfa\x63\xc1\x39\xff\x6c\x6d\x88\x41\x0e\x73\xbd\x32\x8c\xc4\x34\x9a\xb4\xbb\x86\xf2\xe2\xed\x7c\x73\xde\x96\x52\x0e\xf7\x73\x0e\xf3\x83\x45\xe0\xf9\x72\xa8\x4c\x53\x88\x10\x36\x87\xe6\x8c\x50\xf9\xd8\xc9\xaf\x90\x3b\xc6\x32\xd4\x32\x04\x06\x2a\x4f\x50\x2e\x21\x4c\x07\x05\x9c\x2c\xbe\xf7\x2a\x54\x11\x0d\xbf\x73\xe4\x25\x40\x2d\x17\xe9\x78\xec\x19\x9b\x51\x8c\xec\x03\x10\xbf\xbf\x7d\x9a\xd3\x00\x43\x4a\x4a"}, -{{0x08,0xda,0xbd,0x4e,0x5c,0x11,0x9e,0xa9,0x07,0xce,0x45,0xf0,0xa7,0xaf,0x9e,0x62,0xc0,0xc3,0xf1,0xc9,0xec,0x61,0xad,0x10,0x56,0x7d,0x79,0x36,0x28,0x54,0xc5,0x57,},{0x94,0x54,0x06,0xb8,0x5d,0x7b,0x32,0xe0,0xb1,0xab,0x12,0x00,0xb9,0x42,0x22,0xde,0x1a,0xaa,0x68,0x62,0x4c,0x60,0xbb,0x47,0x16,0xb0,0xbc,0xe9,0xdf,0x00,0x57,0x71,},{0x33,0xad,0xbf,0xcd,0x4e,0xd4,0xfa,0x67,0xc5,0x8b,0x5c,0xb5,0x9e,0x16,0x98,0x71,0x48,0x69,0x78,0x12,0x66,0x0b,0x35,0x31,0xff,0x6a,0x21,0xc7,0x49,0xb9,0x60,0x16,0x60,0xba,0xee,0xe2,0x48,0x9b,0x82,0xb4,0xcd,0xe1,0x32,0xb6,0xe6,0x2f,0x2f,0x90,0xd8,0xf9,0x92,0x78,0x60,0xaa,0xad,0x25,0x28,0x1d,0x03,0xeb,0x17,0xa9,0x52,0x0f,},"\x6c\x47\x19\xa5\xa2\xa6\x89\x48\x35\xc4\xac\x1e\xd6\x91\x59\xe5\xeb\xb5\x69\x2a\xd8\xea\xad\xa4\x39\xf7\x9e\x96\x68\x4b\x36\xce\xcf\xb4\x4b\x89\x01\x56\x31\x66\x3e\x06\x44\xf6\xc7\xab\x71\x39\x89\xd7\x42\xda\x27\x42\x72\x53\x31\x8a\x52\x43\x2d\xfa\xb2\x12\x1d\x1e\x92\x33\xea\xd7\x19\xe2\xc8\x6a\x6b\xe0\x73\x63\xd0\x02\x17\x3f\x20\x54\x46\xca\x95\xfc\x17\xb2\x46\x35\x82\x7f\xe3\x15\xf2\x22\x40\x8e\x45\xe8\x33\xf2\x9f\xf0\x8f\xf3\x1d\xac\x58\x3a\x4b\xec\x70\x76\xd5\xcc\x78\xcf\xc9\x44\x51\xcb\xf4\xf7\xe2\xfc\x5b\x5e\xd8\x07\x0f\x4e\xf8\x08\xbe\x1d\x8a\x68\x0e\xcd\xff\x59\x01\x0f\x39\xb1\xde\x80\xbe\xf1\x71\x9f\x1e\x21\x8e\x0c\xe0\xa1\xe3\x93\xa5\x66\xc5\x17\x64\xd2\x37\x0d\x95\xa6\x11\x91\xd8\xf7\xaf\x74\x0d\xc2\x08\xfa\x78\x31\xb2\x10\x67\x05\x12\xcd\x73\x76\x6e\x60\x9e\x9b\x78\x00\x21\xeb\xb2\x0c\xc8\x79\x0d\x8d\xa5\xf1\x0f\x5b\x6a\x11\x4a\x1d\xb8\x8f\x66\x76\x65\x01\x80\x2d\x9c\x36\x6e\xa3\xfa\x6f\x1b\x1e\x1e\x8b\x04\x20\x94\x34\x13\xcc\x6f\xea\xb2\x8c\x6b\x68\x3c\xd2\xb3\x33\x06\x9c\x89\x51\xbc\x45\xe8\xa1\x3b\xd5\x22\x57\x83\x51\xc8\x82\xf7\xc3\x42\xfe\x43\x31\xb9\x21\xf5\x33\xc9\x2e\xc0\x4a\x49\xb2\x92\xbc\x56\x9d\xdc\xef\xca\xb5\x72\x7f\x9b\x56\x25\xb1\x67\xa9\x02\xdc\x89\x6d\x8b\xc7\xd8\xe9\x99\x20\xf5\xdb\x8d\xd7\x67\x83\x9c\x43\xe3\xcd\xf9\x47\x08\x0d\xec\x95\x42\x14\xa6\xfb\xbe\x04\x87\xa2\xf3\x2c\xd1\x7a\x6b\x00\x03\x70\xbd\x41\x44\x84\xfb\x73\xc5\x10\xea\x01\x24\xc6\xcf\x0f\xe5\x6c\x08\x46\xa7\x9b\xfc\x59\x77\x9d\x3b\x07\xa1\xbd\x2c\x7f\xb7\xe2\xd0\x03\x9f\x0b\xd2\x1c\x8a\x30\x8f\xb0\xf5\x8f\xdb\xf9\x4e\xfa\x08\x57\xac\x3b\xdd\xdd\x86\xd5\x76\x3e\x20\x5e\xe1\xb2\x21\xf0\x60\xce\xdb\x8b\xc0\x5f\x03\x1b\x60\x6c\xc7\x4d\xad\xc5\xdb\x04\x23\x27\x48\x86\x5a\x73\xd6\xcc\xdd\xb4\xd5\xe9\x30\xd5\x28\x34\x8c\x5b\xe9\x08\x8b\xfe\x34\x45\x84\x87\xa6\x7b\x19\xa1\x8e\xca\x25\xc0\xd3\xfb\xe2\x19\x5e\xb9\x17\x07\xb6\x5d\x91\x61\xea\x93\xed\xdd\x64\xa6\x34\xb2\x32\x80\x19\x5f\xdb\x0d\x13\x88\xf6\x99\x8e\x18\x58\xa4\x5b\x88\x69\x99\xb8\x44\xe6\x79\x5d\x83\xd3\x18\x37\xe4\x41\x1f\x71\x69\x92\x26\xde\x1b\xa0\x24\x56\x08\x00\x0d\xcf\x22\x3d\xd1\x83\x59\xb7\xc6\xd4\x59\xa6\x5d\xbe\x66\xc9\x0f\x5c\xb8\xc0\x91\x22\x18\x7a\x30\x46\xa1\x6d\xd1\x79\xc3\xf4\x37\x3e\x57\xcf\x5e\xe0\xea\xb6\xa2\x12\xcc\x9e\xd8\xb5\x4b\xf3\x7f\x1d\x27\xfb\xd7\x98\x48\xe4\xec\x1f\x56\x72\x43\xab\x87\x40\xa0\x51\x49\xd9\x60\x2e\xad\xa9\x20\xa4\x6d\x61\x0d\x3c\xc8\x23\xb5\x64\x98"}, -{{0xe0,0xf7,0xd0,0x08,0x24,0xc5,0xf3,0x70,0x1e,0x55,0x17,0xa4,0xab,0xc1,0x3e,0x2f,0x2c,0x0b,0x13,0x8c,0x83,0x69,0x77,0x84,0x3b,0xbd,0x1e,0xef,0xfa,0xbd,0x96,0x8a,},{0x52,0xfd,0xda,0xe3,0xe0,0x18,0xa6,0x84,0x73,0xb3,0x16,0x8d,0x07,0x64,0xcf,0xe2,0x74,0xdc,0xc8,0x34,0xc9,0x0a,0x91,0xfb,0x4f,0xe7,0x4b,0x93,0x9d,0xd2,0x38,0xb1,},{0xcc,0xdf,0xe1,0x8a,0xd6,0xd0,0xb6,0x5d,0x08,0x6d,0x63,0x2f,0x83,0xcc,0x46,0xff,0x3b,0x3f,0x2c,0x07,0xbb,0x8e,0x76,0x9d,0x0f,0xb4,0xe8,0x2d,0xf8,0xa3,0x87,0x3f,0x9a,0xee,0x35,0xfd,0xd1,0x8a,0x57,0x83,0x60,0x31,0x80,0xa9,0x5c,0x9f,0x74,0xce,0xd9,0xdb,0x51,0x46,0xaf,0xcf,0xbb,0xdd,0x40,0xdf,0x29,0xe0,0x42,0x01,0x20,0x0c,},"\xb3\x9e\x3a\xc7\x5a\x22\x1a\xdc\xce\xd0\x9a\x85\x91\xac\x5e\x2f\xe1\x5d\xfe\xd5\xb9\x19\xcb\xaf\x14\xc6\x5e\xb7\xcd\x93\x08\x6d\xde\xe3\xf7\x47\x25\x47\xe6\x6d\xdc\x70\x06\x2b\x97\x62\x97\xd1\xa3\xc1\x70\xee\x52\x5c\x9c\x53\xba\x93\xa4\xc4\xfd\xb2\x35\x72\xb7\xca\x6e\xd1\x38\x53\xe7\x0d\xb1\xd7\x2e\xde\xb9\x94\x4b\xbc\x35\x4a\x52\x0e\x77\xae\x59\x1f\x31\x80\x92\xef\xd5\xe6\x6d\x9c\x09\x81\xc4\xa4\xbd\xa9\x8a\xa4\xe5\x90\x45\xff\x9c\x4b\x4c\xa3\xac\xb2\xff\xd8\x93\x20\x1c\x70\xb3\x4a\x77\xf2\x4e\xda\x54\x54\x9d\xc8\x4a\xd1\x34\xa3\x55\x32\x55\x38\x15\x88\x8a\xe3\xdd\x9e\x24\x1e\xc4\xeb\xbf\xf8\x6f\x8c\x1e\x8a\xdb\xaa\xc4\xb9\x1a\xfd\x18\x22\x8c\xbb\xd5\xdd\x80\x5a\xca\xbf\x0a\x1e\x29\x0c\xe5\xdd\xa0\x25\x1a\xdf\xb3\x7c\xb7\x14\xc1\x39\xb5\xa3\x24\x2d\x88\xc6\x44\x84\xa3\x76\x55\xcc\x8f\xcb\xec\xff\xa9\x7f\xbd\x14\xd6\x4d\x51\x2b\xf8\xf6\x30\x5f\x89\xc5\x09\x22\xde\x54\x16\x92\x15\x8f\xb5\x47\xfd\x53\x9f\x1e\x58\x77\xcc\x64\x94\x95\x16\x63\x32\xea\x2b\x68\x5c\xfa\x3f\x60\x20\x19\xdf\x2a\xb2\xc2\x5e\xd9\x6b\x68\x74\x5e\x9a\xe8\x9c\x94\x8d\xa1\x1a\xd8\xa8\x30\xdf\x8b\x00\xf2\xe6\x68\x19\x2d\xad\xf2\xc5\x62\x0d\x35\xc6\xe8\x1a\x28\x53\xf8\x41\xe3\x75\xa0\xd9\xfc\xa2\xd2\x96\xef\xce\x2a\xc3\x8d\x40\xb0\x30\xb5\x75\x60\xae\x6e\x83\x41\x33\x9b\x3d\x3c\x2d\x06\x11\x64\x12\x43\x19\x59\x86\x88\xfc\xa6\x18\xfc\x64\xc9\xe8\xf5\xf8\x31\x09\x7a\x05\x3a\xf1\x9d\x7d\xbd\x61\x21\x8d\x92\x67\x42\xc2\xe9\xa4\x2a\x79\xcc\x1b\x14\x89\x12\x72\x2d\x8c\xd5\xca\x79\x3a\x1a\xd7\x3b\x5f\x14\x1b\x41\x80\x9c\x2f\xc0\x53\x0b\x76\x30\xe8\x03\x90\xc6\xb3\x38\xc7\x18\x68\xda\xcc\x59\xbf\x46\x3f\xfc\x48\x90\x16\xbf\x67\xf9\xc9\xd5\x55\x3c\x1e\xde\x17\x15\x28\x13\xfe\x0b\x26\x4b\x65\xdc\xa1\xb2\xb3\x8e\x4b\x80\x9f\x8c\x97\x25\xac\x5b\x1d\x8d\x2e\x56\xbe\xc9\x64\x9f\xe5\x5c\x75\x83\xff\x23\xb0\x43\xd6\xf3\x76\x86\x28\xf1\xf0\x51\x63\x37\x82\x4a\x5a\x56\xb4\x09\x52\x0a\x6a\x6c\xb7\x7e\x4f\x5f\xc2\x0b\x9f\x68\x99\xe0\x0a\xb2\x2d\xb1\x0d\x18\x2f\x09\xb8\x1e\x94\xf3\xad\x56\x8a\x0b\x81\x24\x4d\xf3\xf1\x85\x5c\x6e\xf2\x22\xa4\x1a\x51\xb6\x2a\x46\x49\xbb\x82\x69\x0a\xb6\x5f\xac\xac\x0d\x81\xd6\xfe\x02\x60\x11\x70\xa8\xdb\x62\xcb\xc5\xec\x99\x55\xd7\x71\x1a\x1c\x39\x65\x6a\x9f\x6e\x1f\xb6\xbc\x18\x3d\x9b\xea\x15\x03\x53\x1f\x17\x36\x27\x68\xbb\x84\x1f\x9d\x21\xf1\x3a\x2c\x99\x1e\x55\xdf\xf7\xf2\xb3\x36\xe2\x9e\xb2\x95\x07\x63\x8b\xdc\xad\x7b\xb3\x1c\x69\xe9\x09\x20\x7e\xba\xbc\xc6\x53\xff"}, -{{0x6a,0xcd,0x93,0x9e,0x42,0x22,0x26,0xcc,0x54,0x43,0xd4,0xaa,0xbf,0x58,0xc1,0x1a,0xf6,0x50,0xcb,0x40,0xb9,0x64,0x8b,0x4d,0xa3,0x8b,0x92,0x7b,0xff,0x9a,0x58,0xdb,},{0x4c,0x0b,0x91,0x75,0x6b,0x9e,0x20,0x6f,0x78,0x63,0xb1,0x55,0xff,0xc5,0x50,0x9b,0xb5,0x24,0x77,0xce,0xac,0xd0,0x1c,0xa0,0x11,0x43,0x51,0x53,0x67,0x86,0x46,0xcc,},{0x79,0x99,0x58,0x77,0xed,0x24,0xc7,0x91,0x68,0x4f,0x29,0x84,0xbd,0xf9,0x60,0x9c,0x3f,0x7b,0x57,0x6c,0x57,0xd1,0x62,0xee,0x62,0x2d,0x4c,0xe8,0xf3,0x6d,0x9c,0x55,0x73,0x16,0x9d,0x88,0x01,0x21,0x6f,0x1c,0x46,0xff,0xe2,0xf6,0xe2,0xc0,0x90,0x48,0xe4,0x7d,0x4b,0xeb,0x99,0x7e,0x9a,0xbc,0x4a,0xbb,0x12,0x9f,0x9b,0x79,0x69,0x0a,},"\x82\x50\xd5\x31\xcf\x2b\x66\xaa\xc2\xb3\x78\xd5\x4b\xc5\x7f\xd3\x29\xad\x5a\x41\x4a\x59\x92\x55\x89\x8b\x3c\x3b\x45\xbf\x9c\x0d\x2c\x77\x54\x75\x66\xb6\x60\xee\xcc\x76\xa6\x95\xa2\xd6\x08\xab\xf1\x1a\x5f\x6d\xb3\xe6\x07\xfd\x5a\x21\x71\x4b\x0f\xad\x5d\x81\x4c\x01\x5e\xbf\x48\xbb\x73\xad\x75\xda\x9c\x03\xc4\xaf\x54\x89\xe7\x82\xb6\xbf\x79\x08\xa1\xbd\x52\x8d\x7c\xe7\x88\xa1\x8b\xa3\x52\x8e\x35\x37\xaa\x7b\xbf\x75\xf6\x52\x4b\xbd\x19\xa5\x30\x4b\xa2\xa4\xa3\xee\x58\xc4\x1f\xec\x31\x32\xee\x65\x01\x64\x12\x15\xef\xf7\x46\xd7\x80\x0c\x4d\x33\xf5\x2b\xe8\x35\x7e\x0e\xe7\x58\x04\x1d\x91\xcf\xe4\x3c\x60\xc3\xce\xdc\x09\xb0\xd4\x6d\x4c\xfb\x9a\xe2\xa0\x23\x9b\x6f\x33\xc6\x94\x1c\xff\x35\x37\x26\x70\xee\xf5\xc8\x85\x9a\xb6\x5b\x6e\x9f\x7e\xbc\xe3\x2f\xa1\x5a\x9a\x47\x7a\xec\xdc\x96\x83\xa1\xe3\x3a\x1e\xdc\xdc\x90\xd4\x20\xa3\x1e\x78\xc1\x53\xd2\x60\x20\x87\x1d\xaa\x4f\xff\x28\xac\xc3\xf1\x1a\x72\x06\x78\x88\x06\xb6\xfa\x02\x34\x68\xea\x5a\x3d\x18\x6d\x10\xf0\xdd\x56\x77\x96\x66\x3b\xa3\x7c\x83\x2f\xe7\x5a\xae\x7d\xcc\xeb\xf3\x19\xf9\x36\x00\xc4\x6a\x22\xf5\x72\x23\x81\x2d\xdd\x0a\x68\xd7\x6b\xaf\x5e\x27\xa9\xfc\x8b\xd6\x8c\xc1\x0b\x5b\x51\x51\xd6\x2b\x41\xf9\x34\x8e\x21\xb7\x15\x35\x2f\x26\x30\xb6\x17\xf8\x13\xb0\xc2\x89\x96\x28\x59\x04\xcf\x29\x4e\x9c\x28\x56\xb1\x7b\xa3\x5f\x9a\x82\x19\x8b\x82\x14\xa0\x35\xe2\x89\x6d\x65\x68\xbe\x42\x39\x2c\xce\xf3\x2c\xd4\xeb\xfe\xeb\xf1\x2b\xe0\x12\x52\x06\xbb\xe8\x93\x36\xd3\xe7\x62\x99\x1d\xfa\xb6\x8f\xc9\x9d\xc1\x64\x9b\x89\x13\x83\xdb\x31\xfa\xb6\x49\xe6\x28\x82\x3f\x45\x98\xcb\x63\x6a\x38\xfe\x1d\xf7\x3e\x68\xd7\x42\x5f\xc5\xd2\xeb\x55\xa0\xfd\x1b\xc9\xf5\xce\xaa\xbd\x6d\xd4\x1f\x23\xe4\xf0\x86\xc6\x92\x63\x3d\xc3\xc4\x61\x9a\x97\xab\x0e\xad\xa1\x71\xf8\x4a\xdf\x20\xec\xc8\xec\xd4\x7c\x51\xcc\xa3\xe5\x9d\xd8\x09\xb0\xae\xaa\x73\x0d\xf9\x4b\xe3\xba\xcf\xd8\xee\x88\x8b\xba\x9d\x57\x08\x50\x65\x2c\xd4\xd5\xe6\xc5\x52\xa5\x7e\x9f\x48\xa2\xb0\x6a\xac\xdc\x70\x8d\x84\xa3\x76\xfb\xc6\xc9\x4b\xa6\xbf\x64\xa5\xf0\x18\x80\x0a\x7c\xc8\x51\x24\x5a\xed\xb2\x03\x78\xb3\x29\xac\xeb\xb2\x97\x7c\x13\x98\x08\x2b\x3a\x0e\x5e\x2a\x9c\x24\x84\xfa\x30\x1d\x30\x37\xa8\x22\x4d\xdc\xc0\x95\xb1\xdb\xd8\xa2\x31\x5b\x55\xbf\x33\x18\xc2\x78\x10\xef\xc3\xd8\xe2\x5f\xa7\xa8\x78\x9b\x73\xa4\xf5\x50\x59\x08\x0b\x08\xab\xb3\x69\x9b\x7b\x86\x26\xcb\x2a\x78\x0d\x97\xcc\x1c\xa8\x03\x28\x51\xba\xf4\xed\x8b\x64\xfc\x43\x30\x86\x5f\x84\xcc\xb1\x2a\x3d\xae"}, -{{0x4d,0xef,0xf6,0x47,0xcb,0xc4,0x5e,0xca,0xed,0xc3,0xf7,0xdd,0xf2,0x2c,0x16,0x7a,0xf2,0x4e,0x3d,0x63,0xda,0x22,0xb0,0xe6,0xa5,0xb8,0x43,0x9c,0x0f,0x3b,0x19,0x34,},{0x0c,0x27,0xc9,0xd7,0x7a,0xc8,0xc7,0x25,0xbb,0x06,0x63,0x93,0x3a,0xb3,0x0d,0x1a,0xad,0x09,0xcb,0xcf,0x2c,0xd7,0x11,0x6c,0x60,0x85,0xa8,0x49,0x9f,0x70,0x14,0x02,},{0xdd,0x54,0x89,0xfd,0xe4,0xba,0x87,0xd1,0x17,0x3d,0x4c,0xee,0x06,0x82,0xaf,0xdd,0x4b,0xad,0x80,0xdd,0x77,0x0e,0xa7,0xd0,0xdc,0xeb,0xaf,0x21,0xac,0xc6,0x1d,0xd6,0x32,0x4a,0xca,0x29,0x5e,0xd0,0xe2,0x3a,0x91,0x5e,0xcf,0xda,0xd5,0x0f,0x17,0x5e,0xbc,0x51,0x6f,0x1b,0xe5,0xb6,0xd8,0x7d,0x90,0xbb,0xe3,0x86,0x22,0x49,0x53,0x02,},"\xd6\x20\x1e\xbc\x21\xce\xc1\xe9\xbc\x28\xf9\x57\xc9\xd0\x29\xcc\x38\xf9\xe8\x5e\x06\xdf\xc9\x0b\xf2\x97\xe6\x1f\x2b\x73\xb4\x07\xd9\x82\xa6\x6b\x91\xe9\x4a\x24\xe9\x1d\x06\xab\x8a\x5c\x07\x9d\x0f\x69\xbe\x57\x88\xea\x8f\xea\xce\xbd\x91\x72\x91\x19\x22\x33\x86\x2e\x6a\xcd\xa1\xe8\xcf\x9a\x48\xbf\xfb\x54\x91\xdd\x65\xaf\x54\x1b\x6c\x72\xaf\x68\x1a\x81\x82\x3d\x98\xa0\xab\xee\xb6\xba\x9f\x95\x46\x5b\x84\x11\xf9\x9e\x11\x9c\xd2\x84\x79\xda\x98\x42\x59\xbd\xf8\x6c\x9f\xef\x3c\xca\x34\xe2\x24\x69\x1f\x18\x3c\xf0\x95\x03\x77\x27\xda\x9c\xad\x29\xf2\x42\xf8\x3e\xb4\xf7\x36\xe2\x7f\xdf\x67\x01\x8d\x71\x1b\x74\xc4\x5b\x29\x55\xa6\xa7\x6e\xc1\x53\x30\xdf\x5b\xad\x80\x30\xc6\xb3\xa8\x8d\x72\xf2\x84\x47\x65\x2a\xc8\x90\x2b\x5b\x76\xcb\xf6\xb9\x45\xce\xab\xfe\xc0\x4a\x9b\x8c\xb3\x0f\x43\xd9\xeb\x77\x3e\x67\x05\x59\x4f\x0d\xe1\xb7\x0f\x1a\x20\xc9\x9f\xc4\xb1\x22\x1f\x8c\x81\xb0\xbc\x30\xda\x12\xcd\x5d\xea\x8f\x4d\x90\xf1\x3a\x81\x1a\x2c\xc1\x1a\x96\x84\x6a\xaf\xb4\xc4\x2a\x00\xe9\xae\x7d\xa2\x56\xa0\xd2\x2b\x19\x8a\xfc\x25\xcc\x10\x41\xd2\x4e\x05\x6c\xf3\x87\x60\x1d\x7b\xf7\xeb\x31\x82\xd6\x05\xfe\x5e\x63\xb1\x8d\x53\x1a\x5f\x84\xe5\xdb\xd0\x18\x4a\x76\xc6\xc4\x67\xa8\x26\x3a\x98\xb5\xc0\x05\xfc\xb2\xaa\xf9\x89\xf5\xcb\xd0\xa9\xd9\x03\xfc\xfc\x60\x9d\x6e\x57\xd9\xc4\x39\x02\x1c\xea\x93\xe4\xc4\xe9\x91\xf1\x93\xca\xf3\x24\x37\x70\xb3\x25\x78\x74\x80\x76\xb7\xf4\xcb\x97\xf1\x7c\x17\xa7\x9b\x82\x25\x3c\x24\x23\xdb\x69\x8c\xd0\xa3\x3a\xb3\x3b\xb0\x9b\x0b\x08\xcb\x8c\xea\xdc\xa1\xe2\x9c\x5d\xe2\xfc\x12\xb2\x40\x7b\x6c\xc5\xaf\x5a\xe9\x76\xdd\x3e\xc6\x30\xd8\x33\x9b\x7d\xd1\x1f\xa3\x4c\xaa\xc1\x50\xc7\xc4\x79\x1d\x8c\x42\x7b\x0a\xd9\x2e\x05\x29\x06\x7a\x88\xd5\x20\x11\xe1\xe0\xa1\x82\x99\xb9\x69\x89\x6f\x8b\x83\x60\xf7\x5c\x45\xc4\x96\xda\x47\xb0\x9b\x45\x0f\x98\x22\xbc\xbc\xd4\x3f\x42\x93\xc5\x16\x80\x2b\xf7\x47\xc4\xab\xee\xdf\xaa\x3e\x79\xcb\x91\x03\xd3\x77\x0f\x56\x07\xb7\x75\x16\xe5\xb1\xce\x0f\x64\xb6\xee\xc7\xbe\xc3\xc6\x47\xc0\x06\x95\x6d\xc5\x5b\x6c\x79\xf6\xaf\xb3\x9d\x1f\xc3\xec\xf1\x1b\x97\x4b\x44\xae\xdb\x72\xae\xd1\x31\x66\x35\x08\x3c\x21\x24\x50\x2e\x5c\x72\xd8\x6e\xca\xb6\xac\x90\x24\x3e\xb3\x9a\x6a\xa9\xcb\x94\x80\xda\x38\xe1\xed\xb8\xd2\x8f\xf9\x09\x24\xc0\x5d\x5d\x21\xaf\x5a\xf9\x59\x57\xb8\x02\x07\x81\x37\x87\x11\xa2\x9d\x09\x20\xac\xad\x8c\xcb\x39\xa3\x11\x69\x32\x78\xc9\x90\x0b\x47\x0d\xa2\xbd\x4c\x12\xa0\x1d\x73\x96\x26\x44\x01\x7b\x60\x34\x71\x3b\x2a"}, -{{0x5a,0x19,0xbf,0x6c,0x94,0x1f,0x39,0x4e,0x93,0xbd,0x36,0x25,0xfb,0x81,0xcd,0x9d,0xa8,0x1c,0x90,0x20,0xb1,0xc5,0x31,0x25,0x7a,0x7b,0x59,0x57,0xbb,0x07,0x92,0x11,},{0x20,0xe8,0x69,0x9d,0x08,0x7c,0xe5,0xe8,0x15,0x1d,0x28,0x05,0x3d,0xce,0x66,0xc2,0x3f,0x28,0x08,0x1f,0x35,0xbd,0x26,0x81,0x9b,0xbe,0x85,0xd3,0x8a,0x09,0xd7,0x02,},{0x2a,0x2f,0xd6,0x05,0x4e,0xf4,0xe7,0x9b,0x72,0x19,0x1a,0x0c,0xcb,0xd2,0xb1,0x8a,0xeb,0xab,0xe8,0xb9,0xa7,0x18,0x61,0xde,0xd9,0x8b,0x7c,0xdc,0xb6,0xa6,0x25,0x53,0x28,0xbc,0x1a,0xec,0xb0,0xc9,0x33,0x57,0x21,0xa9,0xa9,0x6e,0xe4,0xb5,0xb4,0x3f,0x90,0xd3,0x22,0xec,0xf8,0x35,0xf7,0x8b,0x26,0x4d,0xae,0x6e,0x38,0x7b,0xfb,0x04,},"\xf7\x21\xca\x3a\x32\xc1\xe8\x1c\x9c\x6f\x46\xd5\xe1\xfb\x50\xe7\xce\x2f\x4e\x70\x93\x33\xca\x2b\x55\x0d\x52\x13\xb6\x77\x3d\x67\x0c\xa5\x9a\x2b\x50\x86\xa4\x43\x84\x3a\xc5\x08\x13\xb2\x44\xc9\xc9\xfa\xc6\xd1\x19\x69\x89\x27\x81\x35\x12\xc8\x4f\xe3\x0a\x89\x55\x30\x10\x13\x8f\x91\xe8\x17\x6f\x5c\xf2\x57\x89\xd7\x28\x1d\xdb\x83\xa2\x46\x70\x5d\xcc\xb9\x99\xc4\xcd\x0a\xe2\x19\xc6\x45\xf6\xd7\x1d\x45\x1a\xe1\xf8\xd2\xf9\x89\x1a\xf8\xcc\xce\x03\xf4\x38\x55\x9f\xb8\x36\x67\xb8\x07\x7f\xbe\x43\x5a\x74\x4a\xf0\x19\xd6\xd1\x39\x9f\xd2\x13\x7f\x5a\xfb\x8e\xf3\xf4\x7b\xcf\x73\x5e\x7c\x9e\xd8\xa5\x4b\xa0\xc1\xc6\x56\xb6\x65\x0b\xb3\x0a\xdb\x1d\x57\xec\xd2\x07\x46\x39\x49\x42\x31\xa2\xe9\xe2\xf9\x85\xed\x84\x22\xee\x03\xcb\x3f\xd7\x38\xc7\x35\xa1\xb8\x28\x06\x04\x74\x60\xed\x84\xf7\x46\x8c\x3c\x64\xb3\x5d\xb0\x6b\xc5\x8d\xe4\xbb\xa4\x63\xe6\x38\xa9\x41\x33\xdf\x10\x6a\xc4\xf4\x70\x36\x1c\xcd\xe4\x41\x57\x29\x9d\x22\x5b\x17\x79\x88\x91\xba\xf5\x92\x19\x86\xa2\xba\xe3\x26\xdd\xa0\xb8\x96\x17\xc6\x77\xbd\x14\x08\xba\x27\x48\xba\xa6\x7c\x8a\x2c\x5a\x96\x9b\xc0\x0c\xb4\x0d\xbf\x49\x0e\x07\xe2\x2c\x91\x3a\xfd\xde\x63\x04\xa0\x7f\xc9\xe6\x08\x46\x99\x24\x56\xbf\xb0\x66\x3a\x09\xde\xf6\x8d\xef\x67\xa1\x6d\x29\xe9\x8c\x7b\x55\x35\x18\x48\xa8\xcf\x92\x31\x0c\x74\x63\xc4\x75\xf2\x49\xc6\xf7\x55\x7f\xd0\xd7\x55\xca\x88\xf8\x77\x84\x7f\xe0\x76\x57\x56\xac\x34\xa2\x3f\x78\x40\xd9\x5c\x3d\x29\x4e\x66\x3b\xb1\x51\x8b\x75\x92\x7c\x41\x07\x57\xe0\xf5\xc0\x7c\x5a\x7f\xb2\x15\xdc\x72\x07\x43\x3e\xbf\x79\x1e\xdf\xce\xc9\x0e\x93\x0f\x8e\x3b\xa9\xdb\xbb\x98\x54\x13\xc2\x23\xbe\x87\x87\x3b\xd3\x23\x99\x75\x81\x80\x4d\x88\x96\xda\x38\x6a\x6e\x91\x20\x05\x0a\x0e\xae\xd3\x12\x40\xaa\x17\xc7\xb6\x69\x4c\x30\xcb\xcc\x3c\x69\x56\xa6\x82\x0f\xc9\xab\x21\x87\x55\x33\x96\x3d\xc3\xb0\xd8\x83\x58\x27\x12\x76\xc6\x05\x65\x28\x91\x0d\xd9\x89\xae\x0c\x33\x0d\x17\x98\xf7\xd8\xe7\xd1\x18\x4b\x84\xa8\x14\x34\x32\x5b\x8c\x30\x2e\xdf\x60\x1d\xc5\xe6\xf8\x47\xfb\xac\xbd\xee\xff\x78\xc6\x62\x1d\x1d\xaf\xdc\x23\x9b\x18\xb8\xc1\xaf\xdc\xb4\xb9\xda\xbd\x5d\x3a\x92\xa9\x32\xea\x15\x99\x54\x6e\x62\x5f\x96\xd6\xec\x6f\xb1\xcc\xcb\x76\xb4\x76\xb3\x30\xac\x59\x25\x9c\x63\x4f\xac\x9b\x3f\xa7\xde\x7a\xe7\x05\x37\x73\xb5\xbe\xfa\x00\x1b\x04\x92\x9f\x74\xb7\x12\x41\xe1\xb2\x57\x69\x6d\x65\xa2\x6c\x1b\x4a\xc8\x6b\x7b\x1f\xbd\x69\x57\xfb\x9b\x95\x08\x4c\xe7\xd7\x00\x90\xf5\x5d\x44\x53\x46\x94\x30\x5e\x91\x76\x9a\x82\x94\x13\x04"}, -{{0xb5,0x06,0xc0,0x1d,0x69,0x74,0x6e,0xb4,0xbc,0x63,0x58,0x72,0x0e,0x43,0x8a,0xd3,0x30,0xc8,0x8b,0x60,0x5a,0xad,0x65,0x2f,0x47,0x99,0x57,0x3a,0xb0,0xa1,0xaa,0xf9,},{0x7a,0xc8,0xb6,0x88,0x63,0xbd,0x69,0x15,0x15,0x83,0x78,0x9d,0x86,0x4a,0x73,0x57,0xe3,0xa0,0x45,0xfa,0x86,0x52,0x2a,0x9d,0xaa,0x6e,0x26,0xfb,0x79,0xed,0x6d,0x23,},{0x17,0xa1,0x9d,0x26,0x91,0xb7,0xb0,0x46,0xd7,0xb1,0x96,0x69,0xad,0x73,0x14,0x0d,0xb9,0x2f,0x0c,0x97,0x8c,0x7f,0x61,0xbc,0x38,0x67,0xd9,0x2c,0xa9,0xd4,0x75,0x80,0xa0,0x38,0x0b,0x59,0x01,0xba,0xd8,0x2a,0xf4,0x5f,0x67,0x6f,0x74,0x28,0x73,0x01,0x98,0x0f,0x71,0x87,0x1a,0x42,0x26,0x1d,0xbe,0x08,0x02,0x95,0x03,0x36,0xe6,0x0b,},"\xf7\xfc\x18\x06\x6e\xd0\x4b\x30\xe6\x33\xd9\x86\x5d\xa3\x21\x4b\xec\xa6\x0b\xd7\x96\x01\x9c\xd7\xec\xc9\x18\x66\xf9\xef\x24\x46\xc1\xfa\xb0\x6d\x86\x51\xbe\x7f\x10\x1a\xec\x7b\xb8\x4e\xe2\x1e\x71\xad\x02\x02\x15\xfc\xfb\x36\xf2\xd1\x1e\x45\x79\xac\x39\xf8\xe2\xb1\x29\x0e\x38\x96\xd5\x22\xbc\xf5\x13\xaa\xa0\x67\x71\xf8\x6e\xe2\x28\xcf\xf3\xa2\x0a\x1f\x10\xc5\x64\x33\x95\x89\xbb\xa9\x60\x53\x44\xc0\xa6\xe6\x82\xad\x5b\xa4\x0d\x10\x41\x94\x1b\xc4\x6f\x98\xb9\xd0\x9c\xa1\x7f\x8f\x04\x4e\x98\x3b\x8a\x49\x08\x93\x3d\xf2\x26\x3c\xf7\x88\x11\xc2\x4c\x8f\x48\x14\x35\x4f\x6f\x4c\x68\xb7\xee\x7b\x78\x30\x82\x93\xbf\x78\xfd\x0f\xf1\x22\xf0\x95\xc1\x4a\x73\xa5\x97\x97\x17\x2a\xe0\x5c\xfc\xec\x19\x56\x3e\xb1\x8d\x2b\xc5\x30\x0e\xd4\xbf\x6b\xdc\x44\x3e\xa9\xb8\xbc\x1c\xbe\xde\x94\xca\xb9\x05\xed\xa5\xa6\xa9\x31\x59\x7d\xe4\x02\x14\x6f\xac\x9c\xf8\xcd\x6a\x8d\x10\x46\x69\xf9\x13\xfa\x83\x40\x01\xca\x4d\x09\x0f\xb7\x94\x9d\x31\x09\xa6\x3c\x05\x49\xb0\x3f\x15\x1b\x71\x17\xc4\xf4\x69\x74\xba\x59\xc6\x82\x96\xed\xfd\xde\x76\x92\xee\x43\x2a\xce\xf7\x61\x06\x47\xe0\x95\x78\x65\xe6\x2c\x1a\x0c\xf0\x56\x59\x82\x3a\x55\x45\x2d\xd5\xe4\x71\xb3\x1c\x5a\x49\xab\x05\xb5\xaa\xfd\x5a\x0e\x53\x0e\x89\x6b\x58\xcc\x52\x2e\xcf\x19\xe5\x2e\xc8\x2f\xa1\x47\xf9\xe3\x85\x17\x4c\x7e\xc3\x3d\x1d\x9b\x86\x93\x4a\xeb\x4f\x6c\x57\x00\xf7\xd5\xeb\x33\xff\x73\xc9\xfc\x6a\xa4\x7d\xf5\x1e\x09\x22\x9e\x6a\xe8\x94\xe8\x6c\x81\x8b\xef\x06\x5f\x82\x59\x71\xa4\xcb\x90\xad\xfe\xfb\x31\xeb\xd9\xd1\xb7\x94\x22\xdc\x98\x68\xf9\xf7\x4e\x7a\x32\xcd\x40\x71\xef\xb6\x9b\x27\x23\x3e\x6e\x5c\x60\xde\xdc\xd5\x32\x1c\x03\x0a\x46\xcd\x26\xf5\x60\x2c\xac\x74\x7e\xe4\xb5\x22\xd8\x57\xa3\x32\x1a\x03\xf4\x03\xa6\x00\x62\x50\x40\x63\x61\xe4\x88\x15\xaf\xba\x77\xce\x08\x90\x34\x41\x84\x5b\xa8\x72\x25\xd8\xb2\x40\x46\x74\x5d\x40\x65\x64\x5a\x1b\x98\x41\x0c\xac\x48\xd1\x37\xcb\xbb\x8a\xb1\xeb\xa5\x0d\xa9\xc2\x31\xe9\xac\xf3\x22\xa6\xdb\xec\x0e\xf4\x16\xa4\x46\xc3\xb6\x10\xd9\x35\x69\xfd\xf4\x5a\xa6\xcd\xc1\xb6\x40\xd8\xf3\x01\xd7\x86\x93\xb2\x82\x6c\xc6\xed\x46\x85\x68\xad\x9a\x0f\x94\xaa\x9b\x9f\xb9\x2f\x7e\x78\xd4\x84\xfd\xf5\xd8\xd4\x5c\x99\x1e\x28\x07\x4d\xcd\xd6\x80\xd3\xb1\xf1\x89\xef\x6b\xdc\x32\x0e\xe6\xe6\x4d\xd1\xf8\x0d\x92\x64\xd8\x30\x42\xd2\xc4\x3d\x83\x58\x1e\xf0\x39\x4b\x1b\x5d\x1f\x69\xf3\xbb\xbf\x04\xb7\xc8\x08\xba\x34\xc1\x58\x0f\x16\xf7\x65\x37\xb6\xa7\xeb\xd0\xa1\x90\x8b\xe9\x49\x4d\x3f\xca\xa9\x87\x1d\xb1\x57\x50"}, -{{0xe1,0xcc,0xb8,0x0a,0x26,0x2f,0xf8,0xaf,0x1e,0xda,0x07,0x5c,0x97,0x2c,0x8e,0x94,0x1e,0x77,0xce,0xf5,0x7b,0xdb,0x0a,0x82,0x57,0x2c,0x28,0x20,0x0b,0x49,0x3c,0xa3,},{0x3d,0x37,0xe2,0xa5,0x02,0x7e,0xff,0xde,0xe0,0x7f,0xa5,0x11,0xe4,0x23,0xb2,0xbc,0x56,0xed,0xce,0xa0,0x75,0xb4,0x16,0x49,0x76,0x67,0x25,0xc6,0xb3,0x0a,0x10,0xf4,},{0xfd,0xa3,0x4b,0x65,0x2b,0x79,0x74,0x6f,0x89,0x7e,0x22,0x2d,0x37,0xb7,0x7a,0xa2,0x50,0xd0,0x2c,0x52,0x7c,0x48,0x33,0xdf,0x80,0xea,0x41,0xd5,0x21,0x89,0xd5,0x07,0x00,0xe1,0x28,0xb7,0x8e,0xe8,0x14,0x9c,0x9b,0x19,0xf3,0xab,0xf7,0x55,0xac,0xef,0x53,0x48,0xf5,0xfb,0xaf,0x1c,0xeb,0x41,0xc0,0x38,0x90,0x6a,0xc5,0x94,0x60,0x01,},"\xcf\xdc\x54\x97\xb0\x23\xaf\xa6\x2a\x7f\xe5\x92\xca\xa9\x2b\x87\x5c\x77\x05\x74\x78\x34\x00\x2f\x77\x84\xff\x16\x61\x89\x39\x88\x15\xd4\xe8\xa7\xa0\x03\x8e\x1f\xda\xdd\xde\xba\x51\x05\x73\x27\xad\x19\x60\xe8\x59\xce\xe5\x65\x26\xbb\xb4\x12\x7b\x6a\x5f\x90\xd0\x4d\x08\xb1\x5e\xee\x66\xc9\xcc\xf8\x8b\x4b\x7d\x1e\xe9\xd3\xb8\xb8\xc6\xf4\x2d\xb3\xc3\x4e\x59\x04\x8a\x15\xc6\x04\x1f\x14\x2c\x40\x79\x36\x8b\x7b\x11\xe2\x99\x70\x11\x8b\x99\xe5\x67\x0a\xe3\x1f\xcc\xfd\xff\x13\x99\x14\x2e\xe0\x6b\x2e\x3e\x2b\x3c\x97\x07\xdd\x64\x11\x97\x86\xe2\xfa\xb4\x7e\x0b\xad\x2c\xc8\xb5\x58\xd9\x63\xbb\x48\xa4\x9a\xd2\xc6\x37\xdd\x35\xb2\x5d\xb5\x4b\xc5\xa2\x63\x02\x22\xfa\x2a\xce\xce\x9c\xe1\x2a\xb0\x81\x30\x77\xf7\x65\x9f\x50\x74\x42\x9c\xa6\xb4\x94\x33\x10\x32\xae\x79\x2a\x59\x9c\x42\x5e\xe2\x97\x45\x1d\xcf\x5e\xe1\x95\x29\x03\x12\x74\x2e\x64\x7a\x77\x95\xb8\x4d\xcc\x66\x4d\xda\xe2\xa1\xfb\xf8\xc4\x54\x8a\x37\xfd\x82\xd8\x10\xe2\x14\x5f\x01\xdf\x1a\x6d\x3b\xcc\x42\xa9\x1a\x10\x76\x8e\x09\x1f\x3d\x69\x32\x9a\x7b\xad\x6c\x07\x2c\xac\x6d\x89\xaf\xa3\x1c\x02\x90\x56\xd6\xb6\x22\x12\x16\x5c\xeb\xcd\x49\xac\x67\x2e\x38\x30\x26\x7a\xf9\xf2\x8e\xa3\x19\xbd\x04\x2f\x6c\x59\xde\x47\x01\xe5\x82\x48\x73\x6c\x8d\x97\x6a\xcf\x93\xb9\x9d\x2f\x46\x47\xa5\x47\xd3\x92\x44\x7a\x48\xda\xc1\x11\x81\xe1\x6b\x15\x01\xa9\x4c\x93\x16\xe5\xa6\x7c\x99\x0b\x35\x81\x0b\x4c\xda\x04\x73\xa6\xa4\xe5\x76\x14\x21\x58\x68\xe2\xe0\x02\xc6\x05\x8b\x42\xe4\xee\xec\x84\x13\x9d\xc1\x9e\xdf\x5f\x80\xae\xef\xfa\x4f\x5b\x07\xe8\xfd\x23\x13\x9e\xdd\xa3\x18\x99\xeb\xe6\xfe\xe7\x86\x43\xce\x68\x6b\x29\x63\xa3\x20\x72\xbd\x3b\x3b\xba\x68\x48\x5a\x05\xc2\xcc\x04\x56\xc3\xda\x50\xc7\xc8\xc6\x51\xa3\x06\x6d\x13\xa3\x66\x0b\xd4\x7a\xb6\xdf\xec\x49\xe0\x15\x57\xa6\x74\x28\x96\xaa\x4b\xc6\x36\x3a\x79\x7d\xba\xd1\xa4\x09\xcd\x4a\x50\x91\x1e\x70\xea\x00\x7a\xf8\xe9\xb1\xbb\x7e\x3a\xb5\x62\x15\xa5\x75\xc9\x0f\x73\x9c\x2d\x48\xb3\xb3\x46\x94\xb5\xac\xdf\x07\x98\x0a\xe5\x28\xde\x06\x21\xed\xfa\xc8\xb8\xfa\x84\x95\x4d\x56\xdb\xb4\xd0\x30\x82\xb9\x84\xf1\x3e\x5d\xbe\x9c\x71\x12\xff\x97\x16\xf5\x50\x53\x06\x46\x62\xce\x0f\xb8\x1e\xa3\x5f\x98\xfd\x2c\xd5\x11\x37\xa4\x6f\x64\xe0\xc1\xca\xf4\x4e\x54\x07\xdc\x96\x17\x60\xb2\x59\x7f\x7f\x92\x00\x61\x7d\x47\x13\x40\xcf\x15\x17\x6c\x3d\xa8\x80\xfe\x4e\x0e\x93\xa7\x2f\xb9\x49\x26\xfa\xed\x86\x5d\xfd\xc7\x72\xe1\x85\x29\x2c\x1e\x36\xb1\x21\x17\x81\xc3\xe9\x38\xe3\xd4\xf2\x4e\x29\xaf\x51\x7a\x37\x96\x83"}, -{{0x4f,0xc5,0x12,0xef,0xd8,0x6e,0x3a,0x63,0xb3,0x95,0xea,0xff,0x1b,0xa0,0x11,0xe1,0x59,0x0f,0xb9,0x32,0x6a,0xd3,0xff,0xed,0xe7,0x87,0x6d,0xcc,0x3e,0x9f,0xab,0xdc,},{0x26,0xc2,0xa2,0x2f,0x9b,0xfa,0xd9,0x06,0x06,0xdc,0x61,0x3f,0xf1,0x07,0x02,0x1f,0xcd,0xdb,0xec,0x72,0x37,0x06,0x66,0x60,0xb4,0x88,0x96,0x43,0x49,0xe0,0xc8,0x28,},{0x82,0xc8,0x24,0xa7,0xd1,0x13,0x9e,0xc7,0x3a,0xe1,0xd0,0x23,0xad,0xf6,0x28,0x11,0x44,0x1e,0x96,0x82,0x87,0xf1,0xa5,0x80,0xb8,0x59,0xcd,0x66,0xcb,0x33,0xb5,0x8e,0x40,0x9b,0xde,0xb2,0xa8,0x74,0xbf,0x4c,0x23,0x61,0x0b,0xd4,0x4f,0x69,0x31,0x47,0xf2,0xf7,0xc2,0x9d,0x44,0x3a,0x90,0x50,0x84,0xf3,0xea,0xaf,0xd9,0x33,0x0e,0x04,},"\x07\xcd\x1e\x9b\xfa\x38\xa7\xd8\x85\x34\x65\xa9\x3c\x77\xab\x4f\x30\xfa\xf9\x14\xe4\x8b\xc4\x76\x3b\xa0\x7b\xf9\x6b\xa8\x08\xc1\xf5\x9a\xd4\xce\x9b\x7d\x92\x1f\xbb\xc7\x79\x65\x9d\x7c\xa3\x6e\xdb\x7d\xd3\xac\xf7\xa2\x94\x52\xa8\x45\xb4\x9f\xb6\x54\x3a\x3b\x6c\x5c\x1c\x29\x3a\xff\x61\x84\x85\xa1\x0e\xea\x60\xee\x96\x49\xac\x9d\x48\x1e\x69\x49\x96\x7d\x39\x38\xb5\x2f\xe0\x9c\x36\xb9\xad\xe0\x75\x81\xdb\x4e\xb5\x42\xa9\x7f\x5a\xc8\xac\x73\xd3\xee\xa1\x84\x72\x25\x56\x76\x0c\xf4\x83\x09\x05\x64\x55\x30\x61\xb9\x0a\x0b\x6d\x2d\xff\x47\x07\xbe\x76\x39\x37\xa1\x05\x94\xa8\x2b\x76\x6b\xb2\xcf\x6d\xaa\x52\xfa\x8d\x7b\x48\xf3\x21\x27\xc4\x31\xad\x9a\xae\xd3\xbf\xde\xb9\x9a\xd4\x21\x18\xa1\xb4\xde\x7b\x99\x21\x34\xed\x9c\xda\xd0\xb5\x29\x6d\x19\x7a\x48\x5e\x49\x3e\xcf\xec\xa3\x65\x3a\xd2\xce\x0f\x92\x41\xaa\xbc\x09\x6d\x7c\x4b\xa6\x03\xba\x7d\xdd\x07\xa8\xb2\x57\xfe\x52\x32\x76\x41\x70\x73\xa6\x5f\xa4\x43\x42\x56\xfd\x1f\x23\x9e\xc1\xde\x5d\xa1\xa0\xa8\xc5\xe6\x86\xee\x14\xd9\xdf\xa4\x38\xc5\x3b\x99\xc9\x54\xaf\xab\x2f\x79\xe6\x0b\x71\x26\xf2\xcb\x58\xa2\x6e\x29\x0d\xa1\xdc\xcf\xc3\x01\xf2\x39\x74\x8e\xde\x7b\xcf\x1b\xb7\xcc\xb4\x72\x0e\x69\x2f\x57\xe5\x3e\x6f\x59\x07\x53\x99\xe1\x08\x0a\xc8\xaa\x9a\x61\xa5\x68\xc4\xc5\x69\xd3\x6e\x76\xa2\xd7\x27\x1f\x2c\x44\xde\x4e\x36\x3a\x8c\x91\x6a\x4e\x44\x6b\x02\x7b\x64\x39\x2e\x90\xce\xab\xf6\xb6\x07\x1b\xc4\x7a\x13\x79\xb6\xaa\x63\x44\x76\x3b\x2a\x0e\x7f\xf7\xc4\xa2\x7b\xff\x31\x06\x72\x1c\x25\x3e\x4c\x1d\x67\xc3\x7f\xa3\xd7\xc1\xec\xd0\x55\xb8\xe9\x29\xd5\x2a\x8e\x45\xed\x89\xfb\x18\x0f\x74\xb5\x52\xfe\x06\xf0\x66\xc7\xe4\x31\x8c\xa2\xf9\x15\x94\x6e\x83\x20\xd5\x80\x65\x61\x47\x2f\xb8\xff\x7f\xa8\x07\x2d\x8e\x6f\xd1\xce\x63\xcf\x87\x38\x2f\x7b\x94\x04\x54\x0c\x1d\x40\x6c\x70\xb2\x26\x85\x36\x77\x09\x26\x45\xce\x99\x69\x22\xe7\x34\x5d\xc0\x7f\xb7\x33\x9f\x9a\x54\xff\x07\x35\x2d\xd2\xb9\x93\x06\x3c\x2c\x83\xd1\x28\x1a\x4f\xd1\x78\xe5\xa5\xf8\x0a\x5b\x33\xc2\x29\xd0\x57\x83\x67\xd4\x41\x92\xe9\xa4\xd2\x1e\x97\x34\xd3\xbd\xa0\x83\xb7\x0f\x47\x10\x3f\xd1\x25\x17\x70\x21\xdf\x3e\x53\xd7\x99\x86\xef\xea\x2d\xc0\x4f\x02\xc0\xac\x27\x87\x88\x31\x9e\xf3\xa9\x13\x2e\x62\x32\xea\x6d\xb3\x9c\xa5\x87\x08\x55\xf9\x59\x2f\xff\x6c\x20\x9a\xd2\xf1\xc2\x9d\xd1\x68\x55\x28\x98\x97\x9e\xcf\xf8\xc8\x11\x27\x24\x8f\x83\x10\x51\x53\x00\x65\x61\x29\xd9\xb7\xac\xbb\x7e\xd1\xe4\x6b\xc9\x8c\x04\xd1\xa3\x5b\x18\x91\x37\x38\xe9\xdd\xe4\xd2\xb0\x65\xf4\x18\x42\x42\xd8"}, -{{0x0b,0x7d,0xfa,0xd0,0x5b,0xa6,0x65,0x11,0x1e,0x16,0x81,0xbd,0xc0,0xbc,0x8b,0xa9,0x73,0x76,0x7c,0xb8,0x58,0x77,0x02,0x0a,0x2d,0xbf,0x91,0x83,0x25,0x57,0x1d,0x9f,},{0x95,0x05,0xd9,0xe8,0x6d,0xce,0xf5,0x6c,0x9d,0xb7,0x6f,0x28,0x62,0xb9,0x0e,0x1f,0x27,0x73,0x20,0x2f,0x17,0x50,0x40,0x5e,0x7e,0xe5,0xae,0xd0,0xfc,0x54,0xf8,0xb9,},{0x41,0x5a,0xdb,0xb2,0xf2,0xb9,0x84,0x05,0x77,0xfd,0x18,0x41,0xf9,0xaa,0xe2,0x52,0xaf,0xe8,0xf5,0xa7,0x22,0x36,0x01,0x7d,0x50,0xdb,0x22,0xd2,0x28,0xcd,0xee,0x9f,0x5b,0x3e,0x8f,0xe9,0xa1,0x7a,0x4d,0x4e,0x98,0xb7,0x34,0x13,0x81,0xe8,0xd8,0x62,0x5c,0xdc,0xea,0x95,0x6d,0x25,0x3b,0x74,0xe0,0x2d,0xac,0xb8,0x49,0x20,0xa0,0x09,},"\xc4\x3f\xd3\x4b\xb1\x42\x4c\xca\x4e\x4d\xfb\xa7\x5c\x28\xbe\x80\x18\x44\x44\x6c\xa0\x89\x02\x08\x85\xc7\x48\x38\x25\x47\x16\x4a\x9d\x4a\x7f\x95\x70\xd3\xd1\x71\xad\x69\x81\xab\x50\xee\xee\x08\xa4\xa6\xc6\x6d\x76\x99\xd2\x3e\xdb\xe1\xfa\xaf\x44\x66\x0c\x72\xf4\x55\x2d\x87\xd2\x65\xac\xe8\x79\x28\x23\x47\x4b\x90\xa5\xd7\xf7\x40\x1d\xeb\x93\x77\x62\x7f\x60\xb0\x36\xb3\x6e\x04\x4e\xb7\x6b\xf1\x32\xfd\xdf\xcc\x0e\xf5\x70\x4a\x63\x3d\x84\x5e\x96\x2b\x47\x51\x7f\x0b\xaa\x34\xd3\xd6\xe9\xa8\xb9\xf8\x16\x8b\xcd\xc8\x4c\x6d\x2b\x30\xc6\xf3\x43\xe7\x53\x57\xf7\xf2\xc0\x03\x9b\xd2\x54\xb2\x44\xd3\x6c\xd6\x16\x75\x58\x1f\xb8\x34\x57\x0e\xd4\x11\x3a\x78\xe6\x06\xf1\x45\xa1\x11\x99\x2c\x2c\x6b\x61\xc4\x26\x76\x28\xec\x87\xcd\x88\xc3\x6a\x3c\x84\x70\x6e\x44\xae\x96\xa9\x6e\x0c\x84\x80\x31\x85\x46\xd6\xea\x6a\x6d\xf1\x8a\x2b\x4f\x19\xf8\x36\x0c\xfb\xce\x4e\x9d\x1c\xf1\x01\x1f\xfe\xa5\x63\x3a\x66\x61\x9a\xa4\xa6\x5c\xf6\x9b\xe4\x45\x96\x17\x94\x5e\x43\x59\xa9\xd4\x32\x60\xca\x1a\x20\xf4\xed\x7c\x1a\xe5\xff\xff\x3b\xd9\x22\x94\xea\x70\xab\xba\xe0\x38\x5b\x09\x35\xcd\x1c\x0e\xb5\x18\x30\x29\xc5\x85\xa0\x29\x4b\x79\x99\xe3\x2e\xf7\xa2\x90\xfc\xb0\x95\x67\x5d\xc4\xf6\x01\xe8\xf2\xc9\x6f\x35\xb7\x34\x9a\x37\x05\x75\x09\xf4\xec\x70\xc9\xf5\x0f\x60\x11\xf1\xf5\xe6\xb0\x61\xc0\x91\xd1\x1c\x0e\xd5\xde\xc8\xec\xe8\x81\xaa\x34\x05\x08\xf6\x96\xd9\xe9\xcc\x72\x98\xe6\xbc\xcd\x7c\x21\x0e\x2c\xe0\xde\xd8\x35\x92\xa3\xcf\xa1\x3e\x80\x78\xfd\xb3\x25\x8b\x39\xf1\xd1\x1c\xdf\xe0\x96\x70\xc1\xe6\x0a\x39\x10\xa4\xff\xf5\x1c\x6c\x7f\x7d\x66\x24\xf4\xc9\x3d\xf8\x88\x8c\x52\x6f\x48\x4f\x9b\x13\xe0\xa7\xf6\x29\x64\x78\x39\x78\x68\x4e\x29\x26\x79\x80\x0e\xd5\xeb\x28\x0e\x28\x7c\x7e\x63\x9e\x85\xfa\xa5\x3f\xba\x2f\xa2\x04\x5c\xe2\x7d\x8f\xb3\x08\x36\x07\x26\x55\x0d\xf9\x75\x2d\xb3\x05\xf8\xf0\x66\x47\x97\x0d\x01\x46\x91\x99\x9a\xfa\x97\xb6\x19\x3f\xfc\xc6\xd5\x32\xf4\xfa\x69\xe1\x33\xa1\xd1\x0f\x30\x47\xfc\x00\x38\x1f\x49\x97\xbb\x84\xe5\xb6\xcd\x60\x28\xc6\x21\x32\xcf\xc0\x24\xbf\xeb\x98\x03\x01\xf2\x95\x12\xbb\xd1\x09\xd0\x89\xac\xe1\x82\xcf\x9c\x2f\xfa\xb1\xb1\x7e\xb0\x0b\x6e\xb4\x6a\xe1\x98\xda\x99\x3f\x5e\xfe\x7c\x1d\xc2\x2d\x25\x04\x7c\x1e\xe5\x24\x65\x17\xe7\xf5\x75\x8f\x99\x6a\xbd\x83\xf1\x3d\xa2\x2c\x13\xdd\x20\x5e\xe1\x91\xb5\x5a\xfd\x48\x31\xef\x07\x8b\xb6\xea\x07\x3a\x62\x5b\xc9\x7c\x81\x29\x61\x60\xbb\xf2\x55\x9b\x27\x5c\xc3\x7c\xcf\x01\xb9\x1f\xd8\x7d\x4d\x99\xa3\x67\xaa\x99\x78\xda\xdd\x06\x89\xf8\xa6"}, -{{0x78,0x18,0x8d,0xf8,0xc7,0x54,0x78,0x56,0x21,0xe2,0x7a,0xe5,0x8e,0x10,0x0d,0x50,0x80,0xe1,0x6e,0x0a,0x15,0xe2,0x77,0x05,0x1f,0x95,0xf0,0x80,0x90,0x0e,0xc0,0xd3,},{0xa1,0xbd,0xee,0xe9,0x8b,0x07,0x57,0xba,0x9c,0x2d,0x84,0x09,0xb8,0x74,0x24,0xe6,0x4e,0x42,0xf9,0x93,0x2a,0xcf,0xa9,0xbc,0x71,0xfb,0x3f,0x8c,0xa0,0xe1,0x1d,0x52,},{0xb9,0x41,0x14,0xed,0xa4,0x6c,0xcf,0xc2,0x2a,0x44,0x71,0xa6,0x4d,0x79,0x08,0x92,0xe5,0x9c,0x5d,0x50,0x56,0x18,0xeb,0x0e,0x70,0x13,0x92,0xc7,0x09,0x61,0x3e,0x2d,0x50,0x3a,0x5c,0x2b,0x66,0x60,0x1e,0x63,0x6a,0x3c,0x1c,0x7d,0x49,0xb1,0xac,0x79,0x8d,0x90,0x89,0xb0,0xf9,0xcc,0xd0,0x57,0x9b,0xb9,0x06,0x34,0xd0,0xbd,0x75,0x0e,},"\xcf\x70\xcc\xa5\x7f\xeb\x1b\xee\xfe\x98\x5a\xd5\xaf\x9d\x43\x48\xd3\xa4\x6a\x63\xde\x10\x75\x38\x1f\xb3\x63\x9a\x04\x4f\xd6\xe6\x09\x1f\x5d\xb9\xc9\x4d\x39\xbe\x0f\x13\xad\xe6\xd9\xa0\x74\xe6\x7b\xa7\x06\xb3\xa8\x80\x62\x95\xf6\xb6\x54\x86\x57\x28\xc5\x8c\xa6\xe9\x41\x9d\x5d\x04\x3f\x21\x10\x81\x4b\xbf\x36\xfc\x40\x70\xe4\xd9\x45\x49\x65\xc2\x51\x20\x2c\xa3\x95\xef\xe3\xfd\xbd\x54\x4f\xeb\x18\x7e\x34\xca\x3c\x80\x79\x51\x79\x55\x2f\xce\x9a\xa8\x04\x43\x0e\x5b\x6c\x86\x85\x34\x1e\x91\xd5\x88\x9f\xbf\x3f\x98\x19\x04\x62\x0f\xfe\x70\x13\xf5\x3b\x93\x9e\x17\x44\x3d\x61\x4e\x7e\x6b\xb5\x7a\xd6\x74\xf3\xb4\xb0\x01\x63\x05\x26\xcf\x73\x02\xa7\xd0\xaf\xe7\xdc\x24\xd6\xda\xde\xf6\xfe\xba\x3f\x96\x97\x3a\xa5\xb8\xd6\x27\x52\x62\xe4\x30\xa8\x2f\x67\x86\x96\x97\x1a\x8b\x60\xe3\x8d\x3b\x2b\xcc\x17\x0d\x5b\xc2\x03\x02\xa3\x9c\x59\x6d\x27\xfe\xe3\x9e\x5d\xa5\xb1\x0e\xa9\xf3\x82\x29\x9e\x19\x81\x97\x17\xa7\x18\xd3\x7d\x15\x5f\x13\x92\x31\x82\xb5\xb7\xa1\xc5\x4c\xa1\x09\xb2\x2c\xa8\xe8\xb2\x6c\xa5\xca\x3f\x3b\x90\x62\x21\x94\x61\xba\xce\x97\xe8\x90\xc9\x4e\x41\xca\x3d\x84\x58\x7f\xbd\xf6\xe2\x40\xc3\x5c\xca\xb7\x1d\x58\x47\x7d\x28\x16\x8e\x93\x37\x26\x86\xd4\x2a\xad\x32\x4a\x3f\x16\xaf\xe0\xe9\xb8\x9e\xe2\x0e\x48\x5f\xe6\xc8\x64\xb5\x01\x3b\xa8\x83\x99\xee\xaa\x15\x98\x35\xa8\xb2\xbb\x2f\x25\xf5\x79\xca\x3b\xae\x67\x5c\x63\xda\x1b\x50\xd9\x9d\x4e\xd9\x78\x69\x2e\x56\x00\x23\x3f\x38\xab\x7e\x7a\x5a\xe0\xfb\xf8\xc0\xb6\x9c\xc3\x8b\xd3\x0e\xab\xd9\x77\xef\xa0\x5e\xe2\xc8\x35\x14\x30\x2b\xd4\x0c\x4b\xdc\xe7\xa4\x11\x0a\xfb\xb6\x57\x9c\x62\x0e\x97\xf8\xcf\x2e\x9b\xab\x2d\xcc\x7c\x33\xf1\x96\xe5\x7f\xe7\x61\xa0\x50\x12\x28\x94\xb7\xa7\x5a\x92\x95\x31\x99\x6d\xda\xad\x78\xde\x1d\x4d\x92\x4c\xd9\x3a\x61\xdf\x22\x77\x76\xbc\x1c\x39\xfb\xb8\xde\x1c\x44\x38\x86\x8b\x6a\x3a\x2c\xd9\x4c\x07\xb2\x9e\x3f\x6b\x23\xcc\x7e\x0b\x63\x68\x90\x09\xd9\xd0\xba\xe1\x60\x6b\xaf\xc7\xa8\x08\xf2\xd2\xfa\x25\x62\xb8\xdc\x09\x38\x42\xc0\x1f\xdb\x84\x0d\xa4\x86\x0a\xce\xd3\xfc\x52\x5c\xa3\x34\xed\xcf\x65\x94\x8b\xc4\x16\xf9\x8c\x45\x0f\x00\x12\xa6\x10\x7d\xd7\xf8\xed\xe4\x0e\x1c\x48\xc9\xe8\xa5\x65\xa8\x10\xb9\xcf\xd2\x03\x56\xdb\x19\xf1\xdb\xde\x59\x89\x21\x33\x2e\x0d\x81\x3f\x0c\xb8\x76\x84\x37\x03\x88\x77\x2f\xf3\xcb\xfc\xbf\xa2\x99\xc1\x98\xc9\x7b\xfb\x96\x17\x76\x8a\x05\x16\x1f\x41\x69\xff\x5d\xe5\xd9\xf4\x00\x62\x09\x0f\xb8\x82\x98\x4d\x9d\x5c\x7a\xa7\x8e\xdd\xcb\x96\x34\xe4\x66\xb8\x85\x3d\x51\x2b\x4a\x54\x6d\x74\x23"}, -{{0x73,0xcb,0x02,0xb0,0xbf,0x26,0xa0,0x15,0xda,0x1d,0xc3,0x01,0xfc,0x12,0x5d,0x7e,0x6c,0x30,0xb6,0x3c,0x9e,0x6e,0xee,0x9e,0x06,0x5d,0x4e,0x84,0x71,0x32,0xc3,0x25,},{0xac,0x9e,0x3d,0xd2,0xce,0xb9,0xb2,0x3e,0x74,0x8c,0x04,0xba,0x75,0x77,0xfe,0xdf,0x7c,0xea,0xb9,0xed,0x87,0xdc,0x43,0x0b,0x5f,0xe2,0x2e,0xac,0x50,0x95,0x0e,0x0d,},{0x1a,0x5d,0xd4,0xc8,0x91,0xc8,0xe1,0x32,0x57,0x01,0x87,0xc2,0x3b,0x9a,0x1e,0x4b,0x26,0xf0,0x54,0x60,0xe8,0x75,0x67,0x38,0x19,0x39,0x6d,0xf5,0x61,0xc8,0xaf,0x0e,0x48,0x33,0x3b,0x62,0xc7,0x77,0x29,0xd4,0x9f,0xc4,0x0e,0x17,0x4a,0x7f,0x3c,0x21,0xf8,0x5e,0xf4,0xd3,0x39,0xce,0xb8,0x0b,0xd2,0xe0,0x37,0xd8,0x03,0xaf,0x56,0x0e,},"\x0a\x2b\x61\xba\x35\xe9\x6e\x58\x19\xb8\x8b\xfd\xb2\x8b\x7c\xe0\x2e\x64\xae\x9c\xf5\x72\xb2\x1f\x13\x55\x2c\x0d\xb1\x0f\x39\x60\xd4\x4b\xa3\x47\x2f\x43\xab\xc4\xe6\x29\x5b\xdf\x79\x0b\xd9\x33\xba\x39\x75\xfd\x44\x65\xfa\x3e\x2f\xe2\xdb\x02\xb6\x37\x77\x52\x22\x3d\xec\x98\xfc\xb2\x40\x4f\x3a\xba\x43\x26\x5a\x6f\xa7\x97\x6b\x6c\x6c\xb6\x86\x8b\x88\x1b\xd6\xf3\xd2\x5c\xd9\xd6\xf7\x0e\x51\x2f\x80\x89\xc8\xef\x26\xfd\x58\x24\x50\x53\x77\x9e\x59\xc4\x72\x5a\xef\xa2\x64\x67\xc9\xf5\x00\xe1\x7f\x3e\x15\x73\xf1\xa8\x55\xe9\xb8\xb2\x19\x25\xea\x05\x27\xf3\xce\x8d\x88\xfb\x54\xa4\x7a\xbe\xed\x14\xf3\x99\xcc\x2d\x9f\x1f\xe5\x46\x65\xfa\xe0\xa8\xf0\xc6\x88\x72\xa6\x00\x04\x6d\x1d\xc3\x63\x97\xd3\x10\xce\x39\x3f\xce\xaf\xe8\x7c\x17\xeb\xe1\x22\xfd\xb5\x43\xae\xa7\x10\x85\xba\xec\x98\x27\x3f\x41\xac\x96\x69\x8c\x15\x0c\xf9\x11\xd0\xe5\xde\x23\x92\xd8\x48\x41\xd0\x12\x76\xae\xfb\xfe\x99\x95\xe1\x0a\x6d\x46\xef\xdc\x26\x78\xd4\x56\xc9\xf3\x6b\x2e\x10\x11\x4d\x11\x87\xe7\xac\xa7\x39\x03\x7e\xa5\x1f\x85\xfd\x62\xa2\x94\x29\xba\x52\x9c\xdd\x8a\xd9\x13\x47\x49\x74\x87\xed\x7e\x87\x09\xd4\x77\x6e\xf6\x86\x70\x79\x2d\x06\x15\xbc\x96\xda\x51\x78\xd6\x06\xdb\x63\xe4\xe5\xcb\x17\x2a\xcf\xbc\x1c\xbe\x20\x26\x93\x50\xf1\xb6\x05\xf3\x5d\xcd\x47\x91\x35\xbd\x30\xfb\x4b\x5a\x39\x17\x6c\xff\x74\x4d\xdb\xb3\x06\xc9\xe7\xb4\x16\x7d\xe0\x37\x9a\x61\x66\xbe\x5a\xaa\x74\xd7\x15\x7f\xac\x95\x7d\x88\xdc\x57\x59\x7c\xfe\xf2\x3e\xb5\x10\x8b\x3c\xe5\x3f\xc6\x32\xda\xd1\xb9\x72\xa2\x9d\xa5\xde\x32\xd2\x0d\x8e\xce\xde\x67\xff\x00\xda\x4a\x08\xa0\xcc\x1a\x98\xbe\xe7\xa9\x4e\x3c\xb3\x2f\xee\x94\xae\x25\xa4\x13\x54\x47\x02\xc3\x7b\x3e\x17\x78\xa0\x70\xcd\xd4\x84\x0b\xd3\x9f\x5f\x45\x79\x51\x92\xa8\x67\x86\x38\x76\xed\x0d\x13\x0d\x46\xe2\x91\x39\x35\x08\x28\x09\xf7\xe1\x5a\x49\x67\x10\xf2\x55\xd7\x83\xda\x3d\x01\x6a\x65\x4c\x15\xff\x5d\xf9\x07\xa3\xcc\xaf\x37\xcf\xe1\x1c\x8c\x3d\x49\x65\x07\xd6\x76\x0c\x05\x38\x20\xf0\xf5\x94\xc3\xd0\x1c\xa2\x69\x17\x8a\xca\x52\x5a\xb2\x82\x1e\xf5\x5f\x92\xd8\x5f\xe6\x85\xea\x34\x47\x2e\xd1\x39\x81\x71\x06\x4d\x74\xa4\x22\xec\x91\xd1\xa6\x70\x61\x8f\xc9\xf3\x24\x24\xbc\xb1\x1a\x77\xf6\xfb\x4e\x2f\xef\xd2\xc4\xe8\xa7\x3c\x45\x28\x86\xe9\x31\x66\x4d\x1a\x83\xbd\x92\x73\x29\xc0\x4d\x25\x0b\x83\x52\x1d\x7d\xc1\x3c\x91\xce\xe1\xec\x05\x0e\x11\xd4\x2a\x4b\x0c\x8c\x06\x9b\x61\xc4\x42\x2d\x3a\x49\xc0\x7e\xff\x29\x05\xb7\xbc\x7f\x4a\x5b\x43\xe6\xb0\xd6\x1d\xfb\x50\xe4\xee\xa2\xe9\x0d\x29\x8a\x78\x1d\x05"}, -{{0xdb,0x05,0x60,0x63,0x56,0xba,0xcf,0x23,0xaf,0xf6,0xcd,0xdd,0x42,0xb2,0xc6,0x94,0x35,0x2b,0x5a,0x0f,0xec,0x56,0x0a,0xff,0x54,0xd9,0xbd,0x97,0x10,0xef,0xe0,0x6a,},{0x32,0xa5,0xc7,0xcc,0x49,0x09,0x78,0x6b,0x48,0xa5,0x3f,0x31,0x09,0x3f,0x54,0x9a,0x9f,0x17,0x30,0xca,0x66,0x90,0x38,0x3f,0xdb,0x5f,0x14,0xc2,0x66,0x6e,0x31,0x32,},{0x53,0x09,0x9b,0x76,0x6a,0xdf,0x29,0x44,0xb6,0x82,0x13,0x74,0x84,0x2c,0x25,0xd6,0xe6,0x7b,0x0c,0xcd,0xe9,0xc6,0x37,0xfe,0xcb,0x11,0xb8,0xb8,0xb0,0x72,0x03,0xe3,0x07,0x57,0x32,0x80,0x5f,0x4f,0x14,0xae,0xae,0x73,0xbd,0x62,0xe3,0x08,0xb5,0x88,0x7d,0x68,0x9e,0x29,0xcd,0x89,0xb2,0x3a,0x47,0x69,0x43,0x11,0x07,0x17,0xb1,0x00,},"\x1b\xc9\xc2\x83\x3f\x37\xcd\xf1\x35\x6f\xad\x16\x67\x68\x64\x27\x17\x70\x1b\x38\xa0\xab\x0c\x2f\x58\x1a\x26\xd2\x22\xd6\x5c\xce\xe4\xbf\x0f\x6d\xfe\x64\xd3\x3b\xc0\x23\x9f\x71\xd4\xb8\x26\x44\xb0\x16\x25\xa1\xa3\x5f\xe7\x98\x67\x62\x39\xe0\xca\x77\x9e\xf2\x31\x38\xee\xbe\x3b\xd1\x9d\xe2\xd8\xf7\xc1\x5b\x4d\x96\xf1\x3e\x51\xbc\x63\x3b\xea\x5d\x61\x22\x5b\xca\x1d\x63\x39\xba\x53\xe8\x1f\x7d\x8d\x24\xc5\xd6\x0f\x04\xce\x8c\x72\x67\x61\xd2\x64\x58\x4f\x1c\x7e\x5b\x5b\x69\x92\x45\x6c\x1c\x76\x89\x2d\x63\x52\x11\x1e\x3b\x92\x6f\xe0\x25\xc0\x00\x9d\xb6\x7c\xe0\xdd\xc7\xf7\x64\xe0\xc9\xad\xb0\x48\x1b\xc2\x79\x54\x84\xd9\x63\x73\xa9\x62\xa7\xb7\x4a\x55\x96\xf5\x27\xa7\x34\x76\x49\x8c\x78\x23\xdf\xfa\x6c\x85\x43\xb0\x79\x71\xb5\xaa\x27\x1c\x12\x25\x5e\x09\x18\xdd\x73\xf5\x0c\x30\xc9\xa8\x5a\xc7\xc2\x99\x3d\xd6\x55\xda\x59\x43\x12\x63\xf5\x91\x4b\xe7\x06\x37\x4b\xe9\xc0\x75\x85\xc2\x87\x13\x28\xb4\xdb\xc3\x94\x01\xc9\x57\x07\x38\x7e\x6e\x06\x9d\x44\xb9\xd8\xfb\x05\x8f\x22\xe3\x15\xaa\x0d\x5b\x4f\x11\x68\xfc\x10\x79\x62\xb0\x64\xf7\xd8\x45\xaf\x8e\x21\x31\x95\x1d\x1c\xd6\x6d\xc8\x4d\xba\x46\xd2\x00\xaf\x4f\x4c\x5f\x51\x22\x1b\xc9\xb2\x19\x69\x42\xf8\xb4\x0e\x7d\xdb\xc9\xae\xb3\xd9\xaf\xc0\x71\x25\x95\x13\x13\x5a\x01\x6f\x28\x66\x09\x9f\xa1\x0f\x4c\x3b\x73\x50\x0b\xd5\x5c\x47\x7b\x24\x15\xe1\x0a\x27\x9b\xa1\x10\xd2\x94\xf3\xdd\x18\x42\x17\x7d\x0b\x4b\xfb\x17\x34\xdd\x0c\xcb\x7e\x39\x4b\x43\xd1\x6f\x0b\x75\x48\x36\x22\x80\xf4\x34\x76\x4d\xa5\x7f\x19\xed\x3e\x30\x2e\x53\x70\xfb\xa4\x96\x64\xc2\x30\x05\x74\x33\xcc\x64\x7e\xb2\x7c\xd2\xc7\xc1\x8c\x7d\x66\x90\x6f\x08\x82\x46\xc2\x2f\x7f\x79\x03\x99\xde\xb4\xc5\xfb\xb9\x06\x18\x17\x69\xbe\xf5\xaf\xbe\x8a\xd1\xf5\xde\x55\xbe\x58\x8f\x52\xf6\x9c\x54\xd4\xef\x5a\x96\x9a\x0d\x99\x5c\x27\x40\x7b\x23\xed\xd9\x24\x3d\x24\x99\xfd\xf2\x94\x73\xb1\x95\x5c\x84\xb3\xf7\xcb\xdc\xd8\x1b\x76\x56\xec\x0b\xe9\xe0\xfd\xb3\x38\x13\x56\x96\x0f\xd0\xca\x70\xe7\xea\x74\xb6\x46\xfc\xd3\x13\x94\x8e\x6d\xdb\x47\x60\x94\x76\xfb\x6f\xa4\x84\x2f\xa7\x88\xa0\xd5\x7b\xe3\xb0\xa6\xca\x18\x19\xf7\x16\x14\x76\x00\x43\xec\x49\x04\x88\x19\x39\x96\x8a\x43\xb5\xd1\x92\x8f\x84\xa5\x91\x90\x93\xbc\x38\x41\x58\x81\x71\xa9\xcd\x39\x0f\x8f\xcd\x61\x53\x8b\x54\xe6\xef\x99\x77\x05\x73\xe1\x98\x6d\x15\x0f\xa9\x6b\x7a\x07\xe1\xd1\x94\xaf\x1c\x0b\x40\x55\x00\xac\xb3\xd1\x0e\x3b\xe6\x47\xc8\x98\x62\x00\x6f\xa7\x85\x83\xe7\x61\x66\x84\x29\x20\x16\x0e\xb5\x7f\x0b\x2a\x6e\xdf\x19\x3c\x44\xc5\xee\xac\xf4"}, -{{0x1d,0x13,0x9b,0x1a,0xd0,0xc3,0xaf,0x1d,0x5b,0x8b,0xe3,0x1a,0x4e,0xcb,0x87,0x8e,0xc6,0x67,0x73,0x6f,0x7d,0x4f,0xa8,0x36,0x3a,0x98,0x09,0xb6,0xd1,0xda,0xbf,0xe3,},{0x24,0x28,0xcf,0x1d,0xeb,0x20,0xfb,0xad,0x1f,0xdc,0x66,0x5d,0x82,0x5b,0x61,0x41,0x22,0xdf,0x10,0x1f,0xbe,0x14,0x73,0xa7,0x99,0x96,0xba,0xf6,0x96,0x74,0x34,0xb8,},{0xdd,0x64,0x5e,0x51,0xed,0xab,0x04,0xdb,0x31,0xe3,0x31,0x72,0xcf,0x27,0xac,0xee,0xed,0xcc,0x04,0x63,0xa9,0x63,0x91,0x4a,0x0e,0xac,0x8e,0xfd,0x5a,0x34,0x34,0x1f,0x6b,0xbc,0x52,0xe0,0x42,0xba,0xaf,0x3b,0x40,0xc8,0x9a,0x57,0xef,0xb6,0x45,0x74,0xe6,0x96,0x77,0xfc,0xe9,0x55,0x24,0x6c,0x1f,0xc0,0xf2,0x69,0xef,0x81,0x90,0x00,},"\x8d\xf2\xd2\xdf\x9b\x98\x4d\xa8\x44\x33\x48\x6a\x81\x3c\x98\xc5\x97\x3a\x69\x6c\x11\x62\x46\x10\xb2\x3a\xa4\x38\x08\x34\x64\xf6\x5a\x76\x79\x66\x15\xb7\x28\xc2\xed\x4e\x60\x71\x58\x55\xaf\xc2\x39\x45\x0d\x5b\xc0\x91\x1f\xf2\xa8\x52\x30\x20\x5c\x6f\x13\x49\xba\x5b\xd8\x7e\xa6\xf7\x20\xdb\x6b\xa7\x0b\x77\x42\x17\x88\xe0\xc6\x54\xae\xbc\x23\x07\x4c\x5f\x41\xd2\x29\x07\x72\x14\x0d\x98\x1a\x6b\xc4\xfe\x70\x9a\x26\x8e\x64\x17\x2a\x02\x6b\x27\x01\x18\xb4\xdb\x51\xab\x6a\x13\xc9\x9b\x06\x31\x86\xd8\xd5\xb3\x38\xe9\x77\xed\xdc\x6b\xb5\xfd\x7d\xd5\x7d\x98\x45\xa3\xc3\xfe\x76\x17\x7d\x57\x38\xdc\xa1\x6a\x8f\x91\x02\x85\x75\x00\x17\x4f\x23\xff\x4c\x3b\xf3\xc8\x53\x6f\x11\x58\x0e\xf8\x51\x4a\x40\x9f\x5b\xbc\x9c\x02\x96\xf1\x2e\x34\x78\xd4\x08\x7f\x95\xef\xaa\x6c\x63\x60\x71\xd2\x11\x57\xbf\x11\x77\x4b\xbf\xe7\x69\x33\x06\xca\x72\x13\xda\x47\x13\xeb\xaa\xab\x35\x54\xed\xf0\x80\x11\xa5\xff\x73\xda\x12\x03\x75\xae\xd1\x96\x28\x67\x0f\x28\xab\x24\xb6\xf5\xd5\xa1\xd5\x70\x48\x0f\x65\xd3\xc1\x52\xbf\xf1\xb4\x7b\xf0\x66\x69\x29\xcb\x7c\x99\xd9\x03\x3f\xaa\xe8\x53\x4f\xc3\x5d\xa7\x30\xb8\x11\xeb\xcc\x25\xae\x10\xa1\x95\xaa\xb1\x2c\x32\x6a\xa4\x5b\xf8\x05\xc6\x2d\xd4\xcd\x5f\x86\x86\x23\xc0\x4a\x8e\x1c\x6a\xa7\x2f\x1e\xa4\x40\x0c\x60\x86\x7d\xff\x62\x2f\x31\x64\x34\xf1\xec\x89\x50\x3c\x6f\x9f\x65\xc1\x37\xb4\x94\x4c\xbc\xb3\x5f\x08\x6c\x74\xcc\xea\xfa\x22\x42\xac\xca\x6f\xfe\x61\x1c\x4b\x55\x87\xf5\xb7\x5f\xfa\xd3\x49\xf0\x0b\xf9\x6e\x4a\x58\x0a\x87\x5b\x92\x65\x40\x69\xb6\x2e\xea\xc0\xbf\x78\xe5\xae\xdd\x71\x86\x9e\xe0\x5b\x9a\x94\xe1\xc9\x8e\x35\xa9\x78\x00\xa4\xa2\x12\x20\xb0\x39\xcd\x5e\xbb\xb7\x56\xd4\x0b\x40\x42\xe2\xc8\x4a\x2a\xe9\x81\x82\x51\x1d\xae\x8e\xd3\xb8\x9f\x4f\xa0\x0f\xb8\xed\x94\x63\x16\x45\x97\x10\x05\x2a\xd4\xc0\x2f\x63\xdf\x05\xd3\xbb\x1a\xce\x33\x67\x21\x51\xbd\xf5\xda\xb4\x6c\x7b\x58\x3d\xb3\x73\x89\x9d\x4f\x03\x5b\x6c\x11\x12\x58\xb4\xe5\xa9\xe7\x07\xa1\x1d\x21\x5e\x44\xe6\x8e\xf1\xa6\xf0\x53\x80\x9a\xa5\x1b\xd9\x02\xe1\x3c\xa9\x9c\x1b\x1c\xec\xc8\x3b\x9c\x23\x5c\x71\x0e\x79\x7d\x2b\x1a\x24\x9b\x2e\xa0\x79\xb5\xc1\x67\x4e\xd7\x16\x9f\x1b\x6e\x67\xf1\xac\x77\xf8\x6b\x74\x32\x98\x96\x93\x35\xa7\x72\x44\x0f\x7f\xbf\xa7\x25\x13\x50\x0d\x84\x16\x61\x14\xa8\xfd\x54\x13\x94\x64\xd4\x2b\x99\x55\x30\xd3\x23\x70\xb6\x9b\xff\xc7\x58\x9d\x6d\xcc\x97\xe0\xbf\x17\x85\x6c\xc3\xbf\x41\x64\xdb\xec\xcc\x8a\x88\x1d\x41\x4d\x6a\x62\x02\x92\x76\xc5\xf8\x13\x7c\x0b\x3c\x68\xbc\x8f\x4b\xd4\xe7\xcf\xf6\x5e\xf2"}, -{{0x4d,0x22,0xe3,0x31,0xe0,0xcf,0x6f,0x6a,0x27,0x2d,0xb4,0xd2,0x06,0x87,0xff,0xb0,0x59,0xf1,0x22,0x5d,0x81,0xe4,0x11,0x23,0xb8,0xc8,0x9b,0x07,0x4d,0xe7,0x6a,0x3b,},{0xb1,0xe4,0xcf,0xae,0xad,0xd6,0x7b,0x12,0xd7,0xb9,0xdb,0xfc,0x0f,0x88,0xed,0xd0,0x37,0x3f,0x9a,0x88,0xc7,0xfa,0x33,0xfb,0x7f,0x2b,0x1e,0x47,0x5e,0xcc,0xb6,0x1b,},{0xc3,0x66,0xb8,0x02,0xf6,0x82,0xfc,0xd7,0x05,0x25,0x26,0x4f,0xb1,0xa3,0xcb,0xcd,0x0e,0xe3,0x5e,0xcf,0xf5,0x97,0x7c,0x2a,0x55,0x4d,0xa9,0x39,0x22,0x9f,0x17,0x81,0x9a,0x96,0x1e,0xa7,0x4c,0x3d,0x7a,0x78,0x81,0xac,0x5c,0x1f,0xa1,0x6b,0xf9,0x84,0xd9,0x45,0x6a,0x13,0x88,0xd3,0x46,0x3c,0x44,0x94,0x42,0x9b,0x1d,0xc4,0x54,0x02,},"\x9c\x8e\x3f\x5b\x4d\x70\x40\x30\xe1\xba\x71\xf0\x2e\xfc\x4b\x87\xd6\xff\xfb\x55\xbc\x3d\x8d\x03\x81\x8f\x91\x56\x24\xfc\xf7\x01\xc5\x4a\xdf\xaf\xa2\xb6\x94\xb8\x77\x51\xcb\x9f\x69\x91\x8c\x0f\x05\x0f\x4c\x10\x5d\x5c\xcb\x40\x10\x0b\x28\xdf\xd4\xf4\x11\xd5\x91\xc1\x20\x19\x17\x6a\xc2\x01\x6b\xfb\xfd\xf0\xdd\xf1\x1d\xb8\xa7\xe3\x9a\xa7\xb9\xe2\x16\xf6\x67\xc0\xa1\x5f\xb9\x77\xea\xa9\xba\x3b\xc4\x55\xcc\x58\x94\x5f\x3e\x94\x4b\x8a\xc2\xfb\xf4\xd2\x4f\xe7\xe1\xe6\x19\xcd\xbe\xee\x3e\x5e\x12\xa9\xa5\x27\xd2\x8f\x5f\xd7\xcf\xd9\x22\x0f\x13\x08\xd8\x97\xb6\xd4\x31\x4a\x5a\x01\x87\x86\x4a\x2d\x62\x1c\xf1\xb2\x84\x42\x61\x24\x7b\xf5\x20\xba\xfa\x9b\xf2\x26\xe1\x15\x68\x1e\xcd\x77\x42\x79\x80\xcd\x12\xb0\x8c\x35\x9c\xec\xd1\xde\x3f\x55\x45\xf8\x07\xf8\x1e\xd7\x63\x02\xff\xd6\x47\x7f\x89\xb9\x58\xcd\xf1\x29\x54\xcf\x70\xc1\x42\x53\x29\x93\x83\x16\x47\xea\xca\xb0\xb4\x80\x7b\xfd\xad\xb4\x38\x9d\x7d\xff\x2c\x4e\xf0\xef\x5a\x5c\x61\xd0\xdf\x76\x2e\x2e\x90\x80\xa7\x18\x1c\xec\xd0\x6a\x53\x19\x9f\x0d\xfe\xf7\x02\x62\x7a\xde\xcf\x5f\xcd\x9b\x3e\x68\xc7\x23\x33\x16\x17\x27\xf8\x71\xc7\xd1\xc4\x30\x51\xff\x1c\x92\x1f\xd5\x3b\x64\x22\x38\xb9\x78\x80\xd6\x4e\x25\xfa\xc5\x12\xab\x95\x4b\xed\xbc\xa5\x40\xf5\xb2\x00\x91\xec\x72\xe6\x7f\x88\x77\x0a\xfc\x32\xf2\x12\x5c\xa0\xda\x4f\xe8\x7b\x56\xaa\xc9\x17\x7f\x1f\x4f\x67\xc8\x51\x72\x5c\x5e\x8a\xfe\x64\xf6\x64\x79\x98\x33\xfd\x79\x10\x0b\x77\xea\xd2\x58\x38\x87\x9f\xff\x47\x47\xaa\x0d\x56\x72\xec\x0a\x94\x34\x81\x34\xbd\xbd\x4b\xb3\x9b\x0c\x67\xa0\xcd\x30\x60\x2e\xdf\x4f\xec\x6f\x7a\xf0\xcc\x2b\xda\xe1\x26\xce\xa8\x42\xdf\xaa\x43\x91\xdc\x5d\xde\xa9\x38\xe1\x79\x21\x68\x24\x0c\x2d\x8b\x25\x35\x2f\x9f\x3a\x64\x42\x35\xce\x36\xfe\xfe\xb6\x99\x2a\xd8\x8e\x28\x7a\xd2\xd8\x5b\xd8\x50\x39\x6f\xc2\xe5\x17\xa1\x52\x09\xf5\x92\x0a\xc9\x8c\x53\x2b\x1f\x4d\x86\x9b\xeb\x08\xbb\x03\xcf\x7c\x91\xaf\x3f\xfc\xed\x68\xd5\xfb\xfe\xf8\x6f\xf9\x4e\xce\x6e\x2e\xad\x34\x84\xce\x08\x0d\xb1\x7b\xbe\x40\xf1\xdb\x43\x2e\xc1\x65\x0e\xd2\x4f\xdd\x25\x0f\x33\x45\x74\x5c\x9b\x7b\x91\x98\xc9\x10\x9a\x37\x26\x1f\xc5\xec\xbb\xb1\x2f\x83\xa0\xe1\x22\x0a\x18\x67\xd4\x5f\xdd\xfe\xa8\x1d\xcf\x75\xf4\xec\x7f\xdb\x52\x50\xe5\x77\x54\xd6\xde\xa2\x70\xb6\x28\xa7\x95\x30\xec\x28\xb6\x19\xbc\xa9\x49\x3e\x63\x05\xcf\xc4\x41\x4c\x1c\x1d\xe3\x38\x9e\x89\x01\x97\xc8\x5f\x28\x40\x4f\x3f\xa9\x6a\x1e\x2f\xd9\x20\x6b\x47\x2e\x8a\x0a\x0d\x32\xaf\x55\x60\x6b\xb0\x83\xf7\x6a\x19\xb8\xea\xe3\x47\x9a\xe5\x1d\x98\xa9\x9a\x62"}, -{{0xa5,0x22,0x8f,0xf9,0xbb,0xb6,0xf2,0x32,0x32,0x7e,0xb8,0xd8,0x79,0xd7,0xf8,0xb2,0x77,0xca,0x72,0xba,0xe1,0xf9,0xa9,0xd0,0xe2,0x60,0xdd,0x90,0x57,0x1d,0xb4,0xf9,},{0xd8,0x2f,0x6a,0x69,0x74,0xf5,0x1c,0x88,0x08,0xd9,0xd6,0x17,0xf4,0xce,0xc2,0xd8,0xa3,0x7e,0xb1,0x1a,0x14,0x23,0x7c,0x9a,0xb9,0xcf,0x11,0xeb,0xc8,0x0f,0xf6,0xc0,},{0x97,0x65,0x0f,0xae,0x3f,0x59,0xca,0x76,0x47,0x7f,0x25,0x47,0x16,0x77,0x49,0xc5,0x83,0x02,0x48,0x88,0x32,0x25,0xe3,0x54,0xff,0x46,0xc7,0xe3,0x81,0x96,0x52,0x20,0xd9,0xbe,0xf2,0xc2,0x05,0x7c,0x7d,0x19,0x90,0xf0,0x8b,0xca,0x4c,0xfd,0xe8,0x77,0xff,0xf2,0xb4,0xaa,0x81,0x3d,0x9c,0x4b,0x84,0xfb,0x79,0xec,0xed,0x81,0xef,0x05,},"\x1d\xf7\xa6\x83\x5e\x33\x10\x98\x3e\xe7\xec\x73\x11\x25\xf5\xb5\xcf\x11\x7a\xf0\xe3\x6b\x36\x85\xbf\x54\xac\xe1\xc4\x8c\x46\x30\x05\x60\xa4\x5e\x9f\x9b\xdd\x96\xa0\xbc\x4d\x14\xe8\x9d\x4b\x57\x21\xa2\xca\xff\x66\x18\xb1\x82\xed\xb1\x20\x2f\x3d\x0c\x5d\x11\x8d\x09\xb6\x18\x12\xc0\x10\xe8\xb1\x96\x34\x45\x41\xcd\xee\xfe\x5f\xd1\xf9\x61\xc5\xdd\x75\x45\x95\x55\xab\x72\xef\x2a\xa7\xa7\x59\xa4\xf3\xad\x3c\xae\xd4\x4f\x4c\x9a\x8e\xf9\x5b\x76\xed\x9a\x99\xb5\x5d\xd8\xa2\x60\xba\x08\x01\x0d\x29\xff\x81\x9f\x2a\xf3\x51\x3c\x1a\x64\x0d\x6c\xcd\xde\x49\x99\x20\x5f\x9f\xca\x88\x57\x11\x5d\x8b\x5d\xb9\xf7\x0a\x62\xe5\xee\xa0\xd5\xaf\x06\x5d\xe1\x53\xf2\xed\xed\xee\xc6\x3e\x15\xc8\xe0\x9a\x92\x58\x21\x82\xac\x07\xd8\x1c\xa6\x3c\xa4\xaa\x59\x7a\x22\x20\xe7\x04\x81\x95\x7d\x41\x52\x64\xe2\x58\xbc\x26\x3e\x1c\xc3\x6e\x53\x47\x8a\xac\x5c\xa0\x16\x94\xcc\xb0\x9b\x4f\xfd\x84\x73\x99\x72\xc7\xdc\xcf\x3d\xef\xea\xfd\xed\xe1\x62\xab\x6c\x58\xa1\xdf\x27\x37\x1e\x3f\x54\x93\x06\x7f\xc9\xe2\x06\x7e\x57\x96\x23\xc0\x09\xfc\x82\x5e\xef\x0e\x01\x0f\xd1\xcc\xf2\xa8\xd3\xfb\xbb\x31\x56\xf9\xdf\xde\x0c\x7c\xbb\xaf\x84\x33\x09\x85\x17\x49\x1b\x78\xdb\x96\x98\x61\x4e\xa4\x0e\x0b\x1e\x6a\x1e\x36\xb9\x00\x45\x3a\x16\xea\x27\x6f\x34\x42\xbb\xd2\x7a\x7e\xcb\x98\x15\x11\xf5\xc9\x20\x9e\xb0\x96\xe2\x85\x88\xb6\x5b\x96\xb5\x01\x88\xc0\x38\x1f\xf7\x12\xbc\x06\xb2\xc6\x55\xcc\xa0\x75\x1c\x09\x5d\x80\x16\x25\x15\x85\x85\x1e\x67\x74\x34\xdc\x3e\xfd\x08\x7a\x12\x68\x0f\xc2\x2e\x5b\x83\x10\xa1\x0e\x32\xca\xac\x9b\x71\xc8\x76\xee\xd3\x1e\xf0\x9f\x7f\xa0\x12\xba\x08\xdf\xd2\xad\x68\xc1\xe1\x47\xf5\x05\x98\xe5\x50\x46\x7e\xf9\x9f\x29\x5a\x31\x8f\xaa\x50\x7e\xbe\x77\x6c\xe5\x5c\x4d\xa1\x64\x32\x3c\x30\xa5\xe7\x2d\xbe\x02\x7c\x3c\xcf\x96\xc7\x01\x97\xa6\xfb\x1b\x74\xaf\x13\x3a\x8b\xe2\xb0\x3c\x1b\x99\xfd\x25\xb3\xce\xd5\x1f\xe3\x88\x20\x21\xa3\xaf\xd9\x22\x9f\x64\x1b\xc6\xca\xd4\xe1\xd3\xcb\x6e\xd9\xb6\xb6\x8a\x25\xf1\xe1\x39\x72\x89\x98\x1f\x78\x92\x4b\xff\x24\xc8\xde\xe6\xa1\x8a\x04\x21\xfa\x32\xae\x3a\xb6\x0a\x0d\x93\x3a\x6a\xf4\xff\x70\x48\x74\xb0\x9b\x07\x39\xe2\xf2\x9d\x8f\x25\x2d\x79\x05\x5f\x89\xd3\xbf\xf1\x0a\x22\xc5\x4a\xc3\xd8\xaf\xee\xce\x81\x83\x53\xa6\xab\xe2\xb7\xfb\x8e\x8e\x0d\xa5\xb7\xac\x1c\xfc\x98\x5d\xf9\x75\x80\xb1\x82\x11\xa4\xe3\xed\xff\x95\xaf\xdd\xa0\x61\x54\x7d\x3a\xe0\x40\x6d\x32\x86\xcd\x30\x5b\xdf\xd2\xc3\xab\xf8\xf7\x4a\xf9\xa0\x34\x20\xe5\xb0\x3f\x82\x5e\x9c\x53\x90\x7e\x13\xa5\x81\x21\x74\xbe\x42\x89\x86\x45\x14\x9d"}, -{{0xc0,0x4d,0xc0,0x9f,0x11,0x9d,0x67,0x0f,0xb1,0xea,0xe0,0x13,0x6f,0xcc,0x06,0x08,0x5f,0x29,0x0f,0x4a,0xd1,0xaa,0x1f,0xfc,0x9c,0x16,0x0e,0xa5,0xcf,0x47,0xf0,0x9d,},{0xff,0x49,0x8c,0xe8,0xc9,0xdb,0x78,0x67,0xf6,0xd0,0x27,0x64,0x52,0xa4,0x66,0x72,0x48,0x87,0xe6,0x17,0x2f,0x66,0x81,0x67,0x1b,0x8a,0xe0,0x35,0xf5,0x86,0x5e,0xa3,},{0x4b,0xd1,0x9f,0x3d,0x9c,0x51,0x16,0xec,0x6a,0xe0,0x02,0x4d,0x0f,0x24,0x6d,0x2c,0xe2,0x50,0xd9,0xe0,0x63,0x4a,0x23,0x2b,0xa0,0x6f,0xd3,0x56,0x6a,0xed,0x55,0xcb,0xe5,0x9f,0x12,0x33,0x2c,0xba,0xd6,0x5d,0x43,0x49,0xa9,0xd2,0x2e,0x7d,0x6e,0x46,0xd2,0xfb,0xdc,0x71,0xd5,0xc8,0xf9,0xda,0x15,0xdf,0xbf,0x17,0xba,0x22,0x51,0x07,},"\x1e\x42\x29\x7f\x8a\xee\xf2\x9a\x84\x2e\x0e\x21\xf5\xdb\xae\x06\x8e\x2c\x9d\xda\xa6\xfd\x34\x8e\x48\x88\x1f\x0d\x42\xc5\x0b\xf0\xec\xf1\x70\x6b\x94\xa5\xd1\x98\x17\xca\x02\xd8\x3e\x9a\xb2\xf9\x9d\x8b\xfa\xaa\x5c\x85\xad\x39\xa1\x50\xb2\x25\xad\x3e\xaf\xa0\x67\x81\x5b\x74\x67\x2f\xe0\x26\xc3\xcc\xc6\x77\x25\x54\x40\xb6\x84\xa7\x6e\x12\x8c\xa2\xcc\xc4\x29\xf1\x52\x57\x7d\x25\xb6\x9f\x40\xdb\x58\x2d\x49\x47\x9a\xfa\xe6\x80\x71\x2d\xc0\xfd\x1f\xe1\x41\x88\x39\x68\x7c\xa6\x0c\xdd\xe9\x74\x14\x04\x62\xf9\x61\x48\x29\x5d\xf1\xce\x43\xa9\x77\x35\x1c\x77\xf2\xf0\xb0\x9a\x6b\x26\xd6\xfe\x96\x5f\xce\xae\x17\xd7\xb8\x62\x03\x71\x40\x24\x28\x54\x4f\xdf\x91\x69\x0b\x44\xe9\xaf\xc2\xe9\x08\x8c\x83\xca\x48\xdc\x85\x76\xf6\x28\x72\x47\x98\xdc\x90\x32\x31\x74\xc4\x49\x96\x59\x65\x02\xa3\x5d\xf8\xb9\x82\xc5\x70\xa6\xcb\x51\xb9\xa1\x97\xd4\x31\xaf\x33\xf0\x2b\x80\x01\x15\x67\xfe\x50\xcf\x45\xac\x11\x1b\x3d\x55\x6f\x8c\x8c\xe5\xae\x8c\x99\x72\xf2\xa9\x93\x6b\x1a\x01\x2b\x9c\x33\x9e\x30\xc9\x73\x12\xb6\x5e\xa5\x9c\x10\x0f\x79\xd7\x95\xb8\xa2\x4b\x31\xa0\xa9\x7d\xc2\x5c\xce\xd6\xb8\xff\x5a\xe1\x45\x33\x9a\x04\x8c\xa1\x2a\x57\x90\x17\xfa\xe8\xd5\xcb\xcb\x61\xd5\x2e\x31\x4d\xd7\xc2\xe7\x20\x10\xc4\x72\x17\xb1\xd0\x68\x78\xbf\x28\x18\xca\x18\x8e\x8e\x30\x79\x60\xc1\x68\x9d\x7d\xfc\x02\x02\x97\x3c\xd2\x9f\x2f\x7b\xa7\x43\x46\x9e\x68\x5e\x0e\x70\x4b\x04\xba\xca\x4f\xab\x54\x88\x44\x8a\x92\x2e\xab\xf4\x0b\xe5\x81\xc1\x99\x4d\x74\xd1\x3a\x36\x6c\xe8\x57\xfb\x40\xa6\xe0\x5d\xa8\x55\x36\x94\x17\x2c\xc3\xfd\x28\x06\x2f\x53\x82\x50\xaa\x8c\x11\xf6\x81\x39\xe7\x9c\xd1\x19\x1b\xa3\x31\x4b\x5c\xea\x08\x64\x43\x7e\xd2\xe4\xb6\xfb\xd7\x5b\x9d\xed\x09\x87\xb4\x1c\x20\x2a\x58\xec\x02\x54\xd9\xd3\x71\xa7\x95\xf1\xdb\xec\xdd\xac\x11\x2b\xe8\xd0\x9e\x2d\x7b\x9c\xa5\x75\x2f\x40\x6c\xff\xb9\x11\xca\x36\x45\x0b\xc0\x5f\x1e\xc1\xca\x3c\xa8\xd3\x51\x24\xd1\x28\x6c\x55\xf1\x0f\x61\x33\x4e\x46\xec\xe4\x18\x3b\x92\x21\x9a\x9d\xcd\x0e\x5e\x78\xef\x2a\x76\xcf\xe9\xa9\xab\x37\x95\xdf\xdc\xb4\x4f\x63\xd4\x5f\x5f\x48\xff\xb4\x15\x61\x33\xad\x2e\x99\x50\x88\x4c\x5b\xbd\x2c\x1c\xb8\x72\x9e\x40\xa8\x78\x7f\x78\x49\x69\xfa\x88\x0c\x07\xff\xcc\x97\xd5\xc0\xd2\xd4\x88\x08\x5e\x91\x16\xd7\x10\x7c\xd5\xdb\x16\xce\xcc\xde\xad\x55\x02\x5e\xea\x2e\xde\xe9\x3c\x1b\x10\x64\x27\x61\x8e\xe0\x9d\xc3\xda\xd1\xe0\x56\x76\xa2\x36\x80\x69\xc8\x04\x5c\x3e\xbc\x6c\x67\xaf\xa5\x2d\x59\x39\x82\x48\xef\xcf\x15\xe9\x04\xc7\x14\x23\x04\xff\x61\x97\x1f\x4d\x9b\xf6\x46\x0c\x1d\x64\x17"}, -{{0x67,0x91,0xbd,0x74,0xd3,0xb4,0x62,0x0e,0xf5,0xf1,0xff,0x56,0x40,0x64,0x32,0xc2,0x6a,0xb6,0x46,0xf6,0xd5,0xe9,0xdd,0xa6,0x84,0x2e,0xd6,0x90,0x52,0x27,0x53,0x92,},{0xda,0x99,0x15,0xa7,0x55,0x2f,0x11,0x0f,0xae,0xa1,0x2d,0x47,0x92,0x0a,0x09,0x60,0x14,0x43,0xd4,0x00,0x0a,0x9c,0x7e,0x21,0x8d,0x5b,0xa7,0x2b,0x74,0x98,0x9f,0xa6,},{0xb1,0xe8,0xd4,0x81,0x06,0x5b,0xd5,0x12,0x1b,0xb3,0xbf,0x56,0x96,0x00,0xbc,0xc2,0x6d,0xf4,0x0c,0x49,0x9f,0xba,0xa9,0x54,0xb3,0x9a,0x61,0x9d,0xc4,0x0b,0x95,0x90,0xc3,0x17,0x56,0xb8,0xb6,0x3f,0x86,0x01,0x51,0x69,0x4b,0x95,0x76,0x5d,0x69,0x7b,0x2e,0x1a,0xde,0x08,0x06,0xe9,0x2a,0x06,0xc4,0xa5,0x59,0xe9,0x0f,0xcf,0xa5,0x06,},"\x36\xa2\x0e\x66\xbb\x29\x15\x51\x61\xad\x85\xee\xfe\x89\x3b\x53\xac\x5a\xde\x16\x5f\x08\x9a\x77\x19\x0b\x0c\x23\x9d\xec\x8a\x20\x16\x85\xb0\x76\xb4\xde\xd4\xa1\x0a\xa4\x59\xb9\x80\xa8\xcc\xa4\x7d\x5f\x8d\xe4\xd2\xa6\x62\xe4\x46\xd5\xf7\xfb\x70\xed\x9b\xe0\x5d\xb1\xcc\xea\xdd\x13\x0b\x33\x46\xd9\x40\x9f\x9d\x6e\xf5\x28\x24\xc7\x64\xac\x6f\xb1\xcd\x15\x6d\xbd\x6a\x47\x3a\xe7\x22\xd0\xeb\xb2\x56\x38\xc5\x12\x65\xa2\x2f\xeb\xbb\x14\x96\x7d\x6d\xd8\x25\x3c\x1d\x03\x88\x95\xc6\x73\x7f\x06\x7c\x8f\x73\xc3\xc1\xcb\xe6\xcd\xa4\x36\x96\x32\xd7\xf4\xc9\xac\xeb\xe8\x7d\x05\x71\xc8\x1a\x58\xcf\xd7\x2c\xce\x4a\x5c\xf5\x3a\x1e\x75\x25\x9f\x4c\x99\x3e\x67\xef\xc8\xd9\xc3\x57\x6c\x43\xaf\x04\xa5\xca\xf3\x3d\x85\x6f\x7f\x27\x55\xd3\xa9\x75\xab\x2b\x68\x5c\x6f\x65\x68\x0c\xba\x9a\xc8\x79\xf3\xa8\xc9\xa4\x76\x5b\x87\x9c\x0a\xde\x1e\x4b\xd0\xd4\xa7\x0b\xb6\xf9\x2b\x24\xd4\x29\xdc\x74\x6c\xc7\x8f\x84\x81\x1f\x07\x6f\x32\xc6\x1e\x35\x85\xcc\x8a\xad\xe9\xb0\xca\x15\x22\x4b\xfb\xfe\x18\xbe\x10\xa3\x36\x43\x60\x0f\x66\x12\xbf\x01\x3f\x0e\xfc\xca\x83\x72\x46\xa0\xee\x5b\x03\xc0\x2f\x15\x73\x62\x4c\x4a\x44\xa9\x0f\x9e\x42\x3d\x4e\x56\x06\x1a\x71\xd0\x14\x4f\x5a\x88\x7a\x8c\xd4\xa9\xd6\xf2\x47\x90\x4e\x26\x79\x59\x51\x95\x9d\xa1\x21\xc8\x3c\x6c\x94\x1e\x2b\x6b\x9a\xb7\x62\x09\xff\xe9\x17\x85\x91\xea\xd6\x82\x30\xb9\x4a\xe9\x7d\xf5\x8f\x9f\x17\x24\x28\xc9\x50\x67\x59\x8a\xc5\x82\xff\xb9\x50\x84\x0d\x82\x66\x30\xc4\x62\x5f\x5d\xea\xdd\xec\x13\x05\x20\x3b\x4d\xb6\xb9\x45\xf9\x91\xed\x7c\xd3\xd6\xfa\xbc\xa5\x1e\x21\x66\xad\xad\x0a\xad\x51\x17\x33\x6d\x52\xd5\x94\x22\xf0\x13\x5c\x8f\xa8\xcd\xd0\x88\x4b\xe7\x35\x86\xbf\x28\x4e\x5d\xdd\xdb\xcb\x95\xb4\x11\xf9\x85\x68\x52\x6f\xbe\x71\xa5\x59\x2b\x56\xad\x5a\x73\x45\xf2\x87\x4d\xb1\xd5\x7b\xea\xb4\x3e\x8c\xc6\x95\x47\x52\x06\x29\xf0\xee\x76\xdb\xf4\x32\xa3\x76\xfa\xd2\x8b\xfc\x77\xe1\x4d\x84\x0f\x0c\x02\xd4\x78\xf1\xe2\x33\x7c\x23\xb8\x9e\x73\xe5\x27\x91\x08\xb5\x60\x9b\x18\xe8\x0d\xb0\xde\x11\xcf\xa9\x4e\xcf\x72\x39\xbc\xff\x59\xc5\x41\x18\xe4\xed\xe4\xfb\xfc\x08\x23\xae\x54\x60\x16\xf7\x74\xc5\x21\x98\xa9\x63\xb5\x54\x5a\x34\x89\xb8\x9d\xf7\x62\x6f\xd1\x1e\xd4\x65\x8d\x71\x5a\x46\x57\x99\x40\x35\xd4\x03\xb3\x37\x0d\x14\xee\xd9\x71\x8d\x59\x8d\xb6\x75\xf0\x42\x59\x2f\xea\x89\x05\x65\x44\xb3\x2e\x5b\x9c\x80\x62\x82\x8a\xaa\x3c\xf5\x9c\xb4\x76\xad\x36\xdb\x1d\xaa\x24\x82\x22\x7a\x9b\x7a\xfb\xc1\x53\xce\x93\x25\x3d\x1b\x39\xda\x95\xeb\x96\xf8\x31\x28\xff\x25\x54\xa5\x47\xe3\x4e\xea\x4a\x00\x00"}, -{{0x23,0x4c,0xe4,0xd3,0x9b,0x5e,0xba,0xbe,0x9a,0x2c,0x1e,0x71,0x97,0x0d,0x71,0x81,0x38,0xdc,0xb5,0x30,0xcf,0xd2,0x96,0x02,0x34,0x27,0xd8,0x92,0xbf,0x88,0xf8,0xa4,},{0xcb,0x73,0x93,0x0d,0xb4,0x21,0xf6,0xd2,0x45,0x36,0x83,0x7b,0xd0,0xbf,0xf6,0xfa,0x75,0xbb,0xd1,0x41,0xc9,0x8a,0x40,0x5d,0x42,0x44,0xa3,0xc4,0x24,0x55,0x07,0x79,},{0xf6,0xd0,0x60,0xed,0x7d,0x18,0x27,0x3f,0x18,0xf7,0xa6,0x9c,0xd1,0xd8,0x12,0x6e,0x47,0x8e,0x88,0xa1,0xd7,0x29,0x4f,0xf6,0x04,0x08,0x46,0xd4,0x61,0x07,0xc3,0xe4,0x1a,0x42,0x3b,0xab,0xb2,0x41,0x71,0x39,0xfe,0x58,0x7d,0x29,0x10,0x27,0x1a,0x35,0x7f,0xe5,0xbf,0x57,0xc9,0x2e,0xe3,0xa7,0xb7,0x75,0x33,0x72,0x9d,0x0a,0xc2,0x0d,},"\x77\x73\x0c\xf8\xc8\xf9\x6b\x91\x87\x90\x2a\xcf\xf9\xff\x0b\x21\x74\x6c\xca\xf0\xa3\x82\xa7\xb3\x43\xd1\xc7\x20\x27\xae\x3c\x31\x68\xa7\x3a\x6b\x8f\x49\xbc\x87\x98\x14\x1e\x15\xc2\x73\x2b\x6a\x6b\x3f\x75\x7f\x8a\x8e\x86\xc7\xa4\xba\xcb\x39\x55\x1c\x54\x87\x4d\x6b\xf7\x16\x89\x7e\xe4\xaf\x13\x25\x3a\xa5\xbb\x79\xa1\x92\x10\x4f\x44\xdc\xb3\xde\x96\x07\x45\xa8\xe6\xaa\x98\x80\x52\x4a\x62\x9f\xb5\x10\xa4\xce\x4c\xbd\xa7\xe2\x95\x7d\xff\x1d\x62\xe7\x05\x60\x6a\x2c\xc8\x4f\x91\x85\x0b\xea\xac\x5e\x58\x46\xe1\x42\x0b\xc9\x1d\xcd\xd2\x42\x7b\x69\xcf\xa4\x6a\xe3\x8a\x4f\xef\x41\x46\xea\xe3\x5f\x9c\x22\xe9\x67\xcb\x14\xa1\xaf\x9c\xab\xf8\x3b\x18\x04\x65\xbe\xd6\xef\x2c\xda\x38\x2a\x84\xd9\x99\x4a\xad\x65\x5d\x89\x52\xe0\xfb\xb0\xf9\x6f\xc8\x08\x9f\x2e\x74\x89\x49\x7f\xac\xdc\xd6\x56\xa8\xa4\x51\xb9\x28\xc1\x1e\x7a\x40\x75\x07\x2a\xaf\xbf\x17\xd8\xf1\x05\x4c\x91\x96\x28\x8d\xed\x3a\xe2\x1f\x9a\xfd\x58\x10\xa1\x00\xd8\xe4\xd8\x4c\x4a\x35\xa9\x8b\x30\xd3\xe1\x85\x24\x43\x8d\xd4\x40\x2d\xfd\x8e\x76\x75\xf0\x9d\x08\x0c\xd9\x15\xf1\x4a\xf4\x37\x2f\x7c\xe5\x83\x84\x97\x2d\x5d\x11\x10\x79\x65\x1b\x2a\xcf\x39\xd2\xa1\x67\xc6\xa0\x0b\x2b\x17\xce\x0b\x26\x87\x91\xbd\x2b\xe5\x17\x8f\xe0\xf8\x2d\x64\xda\xcd\xde\x37\x7a\x1e\x8b\xe9\xe7\xd8\xdf\xc8\x2b\x08\x64\x45\x37\xbd\xc8\x70\xc5\x81\x92\x86\xfd\x51\xf6\x79\x2d\xc5\xf6\x7b\x54\xbe\x33\x6d\x44\xd5\x4f\xeb\xf8\x1b\x8d\xf8\xde\xc5\xd8\x68\x6d\xb1\x2f\x16\x4d\x0e\x8f\xf1\xaa\x2c\x16\xba\xcc\x98\x06\x01\x0e\xc8\xe9\x11\x96\x59\x7e\xf0\x6a\x4c\xf1\x70\x7d\xef\x50\x67\xa0\x48\x89\xd8\xe4\x8a\x9b\xc2\xc0\xbe\xf6\x64\xf5\xac\xd1\xb4\xf5\xbc\x2d\xa7\xda\x43\xdc\xb5\xf9\x63\x24\x5b\xa5\x52\xfd\x49\x30\x01\xd8\x70\xa9\x51\x7a\x17\x9c\x2f\x0d\xe8\x5b\xe0\xc6\x82\xd0\x57\x48\x8e\x35\xc7\x81\x6f\xf4\xba\x52\x9a\xef\xd7\xc6\x60\x91\xf2\x06\xf5\xf4\xd7\x5c\xac\x8b\xd2\x09\xec\x2f\xa5\x5b\xe7\x4a\xf2\x31\xe2\xf3\x89\xdc\xc2\xd6\x68\xbf\x69\x5e\xd2\x67\xc3\x59\x4b\xad\x9e\xfc\x00\x21\x7c\x7a\x0e\x9e\x7b\x6a\x56\xa3\x30\x79\xa3\x0e\x73\xc3\x73\x3f\x2d\x24\xef\xec\xdd\xe8\x7f\x72\xf9\x48\xd2\x77\xd6\xb6\xd5\xb0\x35\xb4\xc5\x31\x80\xd2\x3d\x66\xcc\x0f\xf1\x7c\x15\xdd\x46\x85\x85\xe3\x89\xd9\x1a\x4c\x97\xfd\x80\x11\x0b\x21\x8a\x0b\xf7\xa5\xe0\x35\x3f\x46\x09\xd2\xcf\x01\x8a\x06\x55\x71\x00\x1c\x78\x88\x55\x5e\xed\xbd\x36\x22\xc3\xb1\x76\x9c\xd1\x3f\x33\x37\x47\x72\xaa\x6c\x8a\x8f\x58\x81\x02\x01\x7d\x4e\xe4\xe5\x0d\xcb\xbd\xb1\xd6\x10\xc3\x26\x70\x93\x4a\x6d\x9e\x6d\x9b\x78\x4b\xbf\xe7\x18\x62\xbb\x38"}, -{{0x10,0x3d,0x11,0x8c,0x7d,0xd6,0x5d,0x07,0xe8,0xd5,0x58,0x2e,0x45,0x04,0x2a,0x75,0x79,0x24,0x17,0xc6,0x92,0x00,0x1e,0xe6,0xbd,0x9a,0x92,0x7b,0x2b,0x3d,0x90,0x16,},{0xb4,0x5c,0xc9,0x45,0x14,0xa6,0xad,0x67,0x24,0x96,0xcd,0x4e,0xb9,0xfd,0xaf,0xc1,0xd4,0xa1,0x67,0x07,0x2c,0x68,0x74,0xdc,0x8f,0xf1,0x6d,0x76,0x1f,0xb6,0x69,0x86,},{0x2f,0xaf,0xc1,0x3c,0x43,0xaf,0xe5,0x05,0x43,0x72,0xb9,0x23,0xd2,0x4f,0x29,0x2b,0x28,0x3a,0xfc,0xa3,0xac,0xa3,0xb3,0xe4,0x32,0x38,0x06,0x84,0x96,0x17,0x13,0xc8,0xd2,0x3e,0x86,0xb3,0x58,0x04,0x95,0xdf,0xba,0xe4,0x24,0xb7,0x67,0xe4,0x79,0x5a,0x0f,0x92,0x2f,0x71,0xb5,0x0f,0x5d,0x7a,0x36,0x9a,0xb8,0xc6,0xe8,0x80,0x42,0x0c,},"\x5a\x8e\xe0\x79\x18\x6b\x51\xcf\x46\x29\x83\x4d\xe0\xc6\xbd\x73\x34\x85\x50\x39\xa7\x63\x1d\x68\x87\x65\x2a\x77\x28\x99\x59\x72\xe3\x62\xc1\xc4\x09\xf0\x84\xf5\xaa\xf2\x98\x6a\xe3\xf5\x36\xbe\x00\x70\xc4\xba\xf4\x59\xef\x60\xa0\x15\xef\x9d\x70\xdf\xa3\xea\x96\x71\x1c\xbb\x18\xe9\x2a\xf5\x0c\x52\x7d\x7e\xd4\x57\x87\x7a\x07\xab\x83\x72\x15\x18\xc8\x9f\x7a\x86\x41\x91\xb1\xe9\x74\x33\xb7\xc6\xcd\x63\x4a\x83\x2e\x19\x89\x1e\x76\xc6\x21\x22\xa4\x9d\xbf\xfd\x83\x49\x8a\xa4\x16\xac\xcc\xb7\x73\x7f\xe7\x5f\x4f\xb2\xc3\x53\x28\xe6\xf6\xec\xec\xaa\xa4\x2e\x43\xdb\xa5\xbc\x96\x89\x67\x3d\xab\x96\xf0\xbe\xfa\x3c\x83\xeb\x41\xd4\xd8\x87\xb3\xa1\x17\xd0\x55\xe3\x0b\xb8\x7f\xbe\x7c\x71\x94\x72\xf6\xc7\xa4\xcc\x45\xf6\x28\xf5\xfa\xdd\xc4\x8c\xa3\x44\xf7\x7b\x73\x3c\x0e\x3b\x9f\x50\x79\xdb\xd0\x7a\xf3\xa3\x84\x7a\xf1\x41\x71\x9c\xca\x2f\x6a\x76\x65\x52\xb4\x5d\x0f\xdc\xdb\x98\x68\xf2\xc7\x62\xb6\xd4\x93\x3b\xa1\x08\x36\xf9\x5b\xff\x71\xcb\x88\x04\x00\x24\xc9\x05\x34\xc4\xd7\xa9\x5a\x23\x03\xb0\x4c\x29\x61\x01\x2a\xf5\x8b\xc7\x84\xa9\x63\x27\xbb\xfe\xd0\x39\xd0\x80\x2a\x05\x26\x2d\x8e\x66\x3b\x78\x50\x8e\x92\x50\x8b\xc1\xf2\xea\x2b\x9b\xe7\x58\x0b\xde\x10\xa4\xd6\x63\xd0\xd2\x5b\x0e\x97\x3b\x8c\x5d\xed\x59\xde\xbf\x19\xbb\x04\x4a\xff\x1c\x60\xc7\x0e\xa1\xae\xfe\x85\xf6\xd1\x5c\x2c\x1b\x84\x75\x3b\x59\x57\x6a\x49\x47\x3d\x65\xaf\x3e\xd9\x41\xa3\xd5\x14\xb5\xc4\x52\x2c\x14\x1b\xdb\xee\xd9\xcb\x33\x96\x95\xb2\xe0\x2d\xc0\x70\x00\x86\x7f\x1b\xf8\xed\x8c\xfd\x3b\x1a\xfe\x68\x8f\xbc\xa8\x0e\x2f\x9b\xa5\xc0\xb1\x88\xa1\x9a\xda\xff\x66\x86\xca\x0f\xf0\xed\xd4\x44\x66\x12\x91\xfa\x27\xca\x1f\xc5\x29\x42\x9a\x5d\x8f\xf7\x9e\xd2\x02\x7c\x60\xff\xe3\xb2\xc0\x3f\xb8\xa6\x6a\x39\x85\x41\x7b\xa4\xac\xe7\xd1\x4f\xd0\xe2\x37\x1e\xdf\x5d\x71\xbc\x02\xb9\x05\x27\x67\xc7\xf7\x2c\x4e\x6f\x3f\x30\xe0\x63\x82\x76\xb9\xc4\x20\xaa\x43\x33\x09\x5d\x31\x31\x30\x33\x09\x05\x82\xe3\xac\x4d\x9f\xd3\x20\x31\x20\xba\x25\x14\x97\x3a\xb9\xd1\xc7\xfc\x42\x29\x01\x16\xb5\x1d\xae\x9f\xd5\x79\x41\x0a\xe0\x78\xed\x32\x0a\x5a\x1b\x49\xaa\x7b\x5f\xef\xcd\x75\x63\x95\x21\x3a\xf8\x64\x1e\x29\xb0\xeb\xb5\xb8\x3e\x37\x80\xe5\xd1\x0e\x9d\x3d\x11\x99\x81\x48\xf6\xc6\xf8\x6c\x4d\x4e\xb2\x52\xe2\x8c\x70\xfa\x3a\x55\xc4\x3d\x4d\x7f\xaa\xfc\xbc\xdd\x45\xad\x26\x37\xf2\x15\xe8\x15\x49\xeb\x8a\x4c\xde\x47\x15\xb7\x10\x72\x07\x50\x3a\x79\x59\x50\x60\xb8\x3a\xce\x8f\xeb\x67\x3b\x99\x79\x68\x46\x9d\xd9\xb4\xad\x6a\x7e\xa8\x1c\x6e\x61\x81\x00\x33\xf3\xed\xfc\x13\x7d\x97\x42\x09\x57\x5c"}, -{{0x47,0xee,0xe2,0x02,0x4d,0xbe,0x09,0x95,0x3e,0x98,0x1f,0x69,0x86,0x52,0x0f,0x66,0x60,0x82,0xaa,0x9e,0xf4,0x89,0x2d,0xfd,0xfb,0xdb,0xd2,0x50,0xd2,0xa1,0xdf,0x28,},{0x9f,0x13,0xcd,0x8e,0xbf,0x50,0x80,0x34,0x79,0x75,0x15,0x9f,0x36,0x02,0x96,0xa7,0x16,0x40,0x14,0xd8,0xd0,0x69,0xe8,0x31,0xda,0xb0,0x33,0x26,0x07,0x99,0x7c,0xde,},{0x5d,0xef,0xae,0x0e,0x17,0x3e,0xcc,0x18,0xd5,0xf0,0x1e,0xc9,0x29,0x1b,0xe1,0x60,0xd5,0xea,0xbf,0xf6,0x3f,0xd5,0x42,0x3f,0x2b,0xc6,0x6e,0x3f,0x64,0x08,0xc1,0x96,0x35,0x35,0x02,0xdc,0xef,0x21,0xef,0xfa,0x4b,0x9c,0x14,0xbf,0x27,0xb6,0x87,0xd1,0xb6,0xe8,0x6b,0x2a,0x20,0x5a,0x89,0xeb,0x35,0xc3,0x76,0xa3,0xa3,0x25,0x69,0x0d,},"\xc1\x33\xf0\x33\xcf\x3b\xec\x6c\xd1\x92\x12\xea\x47\xdb\xec\xb1\x3f\x2c\x60\x18\xf9\xe0\x87\x8a\xc8\x84\xbf\xb5\x75\xc0\xf5\xd3\xfc\x5b\x49\x99\x58\x0e\xb8\xac\xbc\xaa\xc8\x3a\xe9\xac\x9b\x44\x3e\x6d\x1c\xff\x44\x9c\x36\x89\xb4\x33\xd5\x09\x00\xb2\xe8\xb7\x1d\x00\xe1\x19\xc8\xb8\x75\x09\x4b\xda\xb9\x16\xad\xaa\xb7\x5b\xcc\x85\x29\x59\xd8\xd7\x59\x79\x5b\xbd\x6b\x36\x0e\xe4\x84\xaf\xe4\x7b\x1a\xd2\x83\x91\xf2\x5a\xfb\x8d\x4e\x3a\xfe\x0c\x5b\x60\x04\x98\xa1\x28\x33\xfe\x2a\x1a\x54\x83\xdf\x94\x0b\x17\x3b\xa0\xd9\xd8\xc4\xd1\x32\x1f\xa4\xb7\x33\x33\x4b\x0f\x6d\x87\x8a\x0e\x5a\x76\xf4\xf1\x80\xac\x11\x9a\x82\x08\x2a\xcb\x14\x88\xe4\x9b\xbc\xa7\xa0\x36\x9c\x19\x1b\xd6\xd0\xc5\xd4\x45\x65\x68\x21\xa9\x9c\xcb\xc9\x45\x94\x9e\xca\x81\x36\xcc\x6e\x12\x7d\x9d\xe9\x2e\xf6\x4f\x17\x4a\x6c\x04\xc8\xb5\xe5\x24\x95\xf0\xdd\x67\x4b\xb5\xca\x12\x8a\x92\x09\x96\x8f\xd4\x50\xdc\xe3\x19\x91\x3f\xd6\xa3\x0c\x33\x82\x79\x81\x63\xe6\x58\x5f\x58\xef\x20\x8b\xe4\xd0\xc6\xa2\x51\x3a\x75\x23\x88\x39\x7a\x4a\xe4\x44\x83\x8c\x84\x66\xdb\xc3\x6f\xbc\x36\xae\x08\xbe\xc8\x8e\xed\xa1\x31\xc1\x4d\x06\x36\x6b\x67\x31\x51\x45\x41\x00\xde\xa1\x11\x81\x50\xfb\xe4\x41\xb1\xe7\x82\x6e\x54\x5d\x98\x68\x24\x2e\x89\x9f\x5e\xa5\x3e\x43\x4c\x37\x93\x6c\xe6\xfd\x06\x14\x62\x83\xe8\xfb\xd5\x36\x48\x0d\xe5\x5a\x16\x10\x2c\x44\x75\x4b\xc5\x54\xd5\xbc\x2d\xe2\xf2\x5e\x19\xe5\x67\xa0\x23\xdf\x46\x40\xe7\x4f\xf3\xa4\x9e\x4d\xd3\x0e\x0e\x25\x58\xb3\xdb\xc2\xaa\xb9\x2f\xdd\x5e\x79\x42\x5e\xcb\xc4\xc6\x99\xfe\x1f\x16\x19\x65\xf1\xd0\xb4\x5d\x8b\xda\xb5\x2e\xc9\xbf\x7a\x69\xd8\xaa\x0b\xd1\x71\xe7\x55\xce\x7b\x8d\x07\x18\xf7\x26\x7a\xfb\x73\x3e\xfc\xa5\x4b\x21\x3e\x6f\x5a\xda\xb4\xc9\xd7\x6c\x86\x7f\xcb\x69\xae\x05\xc7\x4b\xd2\x15\x16\xcf\x34\x2c\x61\x61\xf6\xfc\x9e\xcc\xac\xf9\x70\xeb\xce\x54\x0c\xd8\x92\xbc\x10\x6c\x6b\xd5\x63\x61\x02\x98\xb7\x09\x68\xf0\x91\xbc\xc6\xe1\xf7\xab\x4a\x5b\x2c\x63\x74\xa1\x90\x3f\x4d\x3a\xd5\xe1\xbd\x86\x43\xa9\xc2\xf8\x78\xc3\xd7\xa4\xdc\x49\xef\x31\x97\xed\xbc\xda\x7b\xb9\x1e\x7e\x06\x60\x60\x87\xd4\xe9\x81\xbf\xab\x93\xa6\x02\x49\x77\x96\x2e\x45\x26\x25\x17\xf3\x38\xb6\x85\x7e\xec\x21\x58\xa2\x97\xb2\xaa\x91\x52\x4b\x67\x7a\x21\xaa\xc5\x7b\xe0\xb6\x3a\x80\x74\xfe\x54\xe7\xa9\xdc\x70\xc5\xa5\xc3\xde\x72\x8b\x9c\x17\xec\x12\x12\xab\x11\x30\xeb\x17\x62\x2c\xd7\xb2\x2a\xb6\xeb\xa9\x18\x5e\x8d\x67\xbe\x6c\x47\xa2\xe5\xad\xc6\x63\xd4\x64\x2c\xc1\x20\x22\x2e\x29\x9f\xe1\x34\xfd\x7f\xcd\x00\xad\xab\xcf\xaa\x64\x2f\xe2\xe0\x8d\xd5\x2e\x2c\x3f\x32"}, -{{0xb6,0xc8,0x8b,0x4c,0x90,0xfd,0x19,0xa1,0x49,0xd3,0x81,0x67,0x19,0x53,0xb9,0xb1,0x6d,0x42,0x8f,0x63,0x61,0xcf,0x50,0x3a,0x11,0x04,0x77,0xe2,0x97,0xf8,0xd2,0xf8,},{0x8e,0xbf,0xb0,0x84,0xf9,0x97,0xb2,0xea,0x79,0x32,0xa2,0x35,0x3b,0x2c,0x8b,0x16,0xbd,0x82,0x5e,0x1a,0xf5,0x87,0xa8,0xeb,0xc5,0x1a,0x6c,0x45,0xae,0xa3,0x43,0xae,},{0x74,0x47,0xa2,0x01,0x81,0xb0,0x2c,0xf1,0xb6,0xad,0x52,0x95,0x69,0xce,0x43,0x7c,0x2a,0x05,0x08,0x11,0x6f,0x50,0x20,0x5c,0x41,0xe6,0x37,0x8b,0x74,0xfe,0x2f,0xc5,0x36,0x30,0xaa,0x0d,0xc4,0xb8,0x0c,0x31,0xcb,0x26,0xc8,0xf0,0x9b,0xf8,0xfa,0xb2,0x7e,0x3a,0xbc,0x8f,0x1f,0x60,0x4a,0x5e,0xc0,0x66,0x31,0xa8,0x4f,0x6f,0x2e,0x06,},"\x7f\x4b\xf4\xf5\x21\x73\xef\xf0\x72\xf8\x18\xd0\xaa\x97\xe6\x93\x5d\x8b\xac\xcf\x48\x39\x66\x32\x53\xb2\x41\x4f\xe6\xb1\xf3\x4c\xf4\x3a\xb1\x20\x15\x5a\x1a\x3a\xea\x7b\x48\x19\xdd\xd1\x03\x16\x73\xb8\xa7\xa6\xbd\x0b\x9d\xda\x4a\xde\xfe\x69\x2a\x56\x16\x2c\x64\x61\x80\x79\x42\x64\xc5\x12\x21\x15\xeb\x90\xa6\xd3\x05\x4f\x08\x43\x02\xdc\xe3\xd8\x36\xac\x3d\xe8\x20\x63\x8b\xd8\x9a\x86\xbf\x0a\x4c\x01\x54\x7c\xfd\xc5\x43\xd6\x76\xfe\x16\x39\xef\x72\xc5\xb8\x45\xc4\x94\xe0\x78\x14\xce\xc8\xa4\x7d\x03\xdf\x73\xbe\x4e\x33\xc0\x5a\xfe\x9a\x19\x0d\xda\x04\x33\x60\x49\x6b\xe4\xcf\x3a\x63\x19\xda\x9a\xb0\x64\x81\x67\x7f\x1a\x43\x74\xd6\x0d\x3d\x3b\x63\x94\xf8\x84\x3c\x86\x9b\x0f\x41\xa1\xe8\x1c\x2b\x1a\x54\xbf\x5a\xac\xbd\x98\x20\x7c\x8d\xba\xcb\x36\x42\x2a\x3a\xa0\x13\xd5\xe8\x49\xe0\x44\xaf\x92\x85\x45\xc0\x46\x09\x7c\xaf\x14\x9d\x97\x02\x15\x11\x5d\xea\x0b\x5a\x85\x40\x1f\xf6\x72\xe0\x2e\xd4\x0b\xd0\xf5\xa4\x40\xcd\x56\x49\x40\x53\xc8\x96\xc3\xbd\x32\x60\x63\x49\xf7\xcb\xe7\xec\xe2\xa2\x23\x0c\xf2\x36\xda\xc5\x9f\x78\x17\x96\x5f\x3f\xa8\x0f\xb4\x8a\xa3\x0b\x0b\x19\xef\xa9\xa9\x65\x91\x64\x6b\xd2\x5e\x67\xc1\x85\xf7\x7e\x21\xd6\x63\x0b\x28\x8d\x4e\x55\x14\x6b\x2a\xbc\x15\xe9\x50\x88\xd9\x36\x08\x07\x75\x61\x81\x54\xbb\xdd\xa1\x15\x70\x2a\x2a\xfd\x6f\xd5\xf5\x6b\x92\x3e\x18\x88\x33\xec\x44\x89\x44\xd3\x02\x83\xe3\x37\x25\x42\x42\xc5\x81\x2d\x72\x45\xa4\xe9\x26\x70\xbc\xe3\x54\x6e\xfa\xed\x22\xd2\x74\xe1\xe6\x04\x8b\x5a\x0f\x01\xef\xbf\x89\x5d\xc4\x24\x94\xba\xf1\x74\x71\x85\xcb\x1a\x4b\x88\xfd\xf1\xe6\x09\x9b\xaa\xbc\x6a\x5a\xb5\xa2\x72\x7b\x1e\x24\x87\x89\xd1\x70\xca\xa2\x44\x96\x71\xa8\xf6\xe0\x94\xc1\x13\x32\xea\x0a\xc2\xaf\xe8\x81\x32\xc6\x44\xff\x88\x3d\x0c\x49\x9a\xd7\x6a\x93\xdf\x47\x2f\xa0\x13\xea\xa2\x7a\xb4\xda\xd6\x79\xd2\x51\x1b\x50\x49\xc4\xe9\x8b\xaa\x2e\x7b\x00\xa5\x34\x89\x1e\x29\x02\x65\xed\xb0\x76\xf7\xdc\xa8\xe6\xfe\xf3\xf4\x33\x03\x4a\x16\x57\x5f\x0e\x53\xda\x45\x77\xe6\xb1\x3f\x0c\xb0\xd7\x85\x87\x0d\x0d\x09\x8d\x5d\x80\xf4\x13\xa2\x68\xba\x84\xe0\x43\x1a\x78\x69\x23\x77\x13\x78\xcd\x57\xb8\x19\x22\x58\xe2\x63\x3c\xdb\xe0\x3c\xc3\x16\xa0\x95\x09\x70\x52\x6f\xd3\xe0\x93\x76\xbc\xef\x0d\x03\xb7\x07\x4e\x59\xa5\xa8\x4f\xc6\x4e\x79\x5a\x81\x21\x56\xd9\x60\x56\x76\x50\xbb\x1e\x14\x24\xb3\xcc\x9a\x4d\x99\xd5\x7b\xa8\x58\xdd\x1a\x0c\xad\x35\x32\xe9\x98\x14\x6e\x79\x26\x40\x45\xe2\x8e\xbb\xfd\x75\xa4\x26\xb0\xbb\x85\x1a\x24\x4a\xd6\xbe\x7b\xd5\x76\x5a\xf4\x93\xdf\xc4\x4e\xe3\x78\xcd\x04\xda\xf3\x91\x7e\xef\x2a\x62\x06"}, -{{0x79,0x49,0xa9,0x47,0x2f,0x72,0x5c,0xe7,0xc6,0x8d,0x7e,0xa8,0xfc,0x16,0xe1,0x3d,0x9e,0x0e,0x0a,0x58,0xf5,0x8c,0x24,0xf9,0x22,0x8c,0x88,0xe8,0x02,0x64,0x09,0x0d,},{0xa3,0x70,0xf8,0x28,0x33,0xf8,0x8b,0x4f,0x5f,0x53,0x10,0xb9,0x18,0xe6,0xaf,0x93,0xbb,0x72,0x4b,0xfb,0xdf,0x3c,0x02,0xc5,0x03,0x78,0x0b,0x2c,0x83,0xab,0x6c,0xc6,},{0xe0,0x28,0x98,0xcc,0x7c,0x30,0xee,0x01,0x64,0x82,0x47,0x49,0x7b,0xe8,0xa9,0xc6,0x37,0x85,0x93,0xdc,0x88,0x20,0xbf,0x7c,0x17,0xff,0xcd,0x18,0x11,0x8a,0xf0,0x98,0x79,0xa7,0x69,0xf5,0x39,0xdd,0x92,0x37,0xe9,0x68,0x21,0x16,0x66,0x34,0x99,0x8f,0x94,0x6d,0xa6,0x5e,0x6d,0xba,0xd8,0x27,0x15,0x11,0x66,0x9e,0x2d,0x6c,0xad,0x02,},"\x95\x53\x86\xb9\x2d\xd6\xbf\x92\x60\x1b\xf8\x1e\x84\xd2\x51\x44\xb5\xfc\x0b\xcd\x7d\x23\xc7\x6e\x7d\xeb\x5f\x5b\xa6\x31\x6b\xb6\x1a\x5d\x8e\x74\x18\x5b\x01\x29\x67\xf0\xa4\x43\x8b\x53\x16\x96\xde\xb4\xb8\x10\x10\x89\xe0\xc0\x48\x2a\xdf\x13\xc0\x61\x31\x91\xb9\x77\xf7\x7b\x04\x19\x81\x41\x47\xf5\xda\x64\xa1\xd3\xbe\xb1\x27\x5b\x98\x49\xd1\x29\x7b\xa8\x53\x2a\xe0\xa6\x47\xa8\xac\xe3\x95\xae\x0e\xd0\x0f\x67\x34\x8c\x5e\xe5\xea\x19\xb5\xf1\xc5\xbd\x2e\x62\x28\x18\xe8\xad\xcb\xa3\xc1\x7c\x27\x98\x7e\x4e\x3d\x6d\x91\x0a\x56\xc7\xe5\x14\x9d\x3f\x55\x74\xfc\x06\x00\x9b\xf4\xdd\x3e\x37\xcf\xe3\xeb\xda\x2c\x21\x16\xd3\x66\xdd\x88\xce\x5e\xa7\x2a\xb3\x87\x49\x05\x85\x44\x3b\x08\x6e\x8a\xa3\x8d\x11\xd3\x82\x0b\x72\xc6\x58\xe4\x63\xcd\xb5\x9c\x53\x93\x01\x1d\x4a\x8f\x4c\xb6\xa1\x95\x22\x93\x04\xe7\x62\x39\xfa\x5e\x8c\x2c\xbe\x0f\x39\xdc\xad\x13\x8a\x0e\xcb\x3c\x51\x57\x9e\xc9\xa1\x20\xa5\x16\x07\xee\xfe\xbf\xa5\x9a\x44\x62\x0e\xa5\xb1\x91\x60\x87\xea\x33\x85\x33\xfc\x13\x2f\xf2\xe4\xa4\x3d\x05\x2f\xd0\x8b\x6b\x1b\x24\xfb\x67\x2f\x73\xc9\xb9\xba\x20\xb7\xc1\xc4\x1e\xa2\x4d\x91\x2d\xe9\xb5\x55\xb6\xe5\x68\x2b\x97\x06\x08\xff\x22\x9a\xd3\x08\x6f\x43\x1f\x9b\xe1\x90\xec\x39\x22\x4b\xa2\xed\x8a\xcb\x4c\x8e\xac\x85\x82\xe2\x3a\xaa\x79\x82\x7c\x44\xe2\x48\xc5\xba\x09\x2d\xda\xc0\xf2\xf7\x96\x84\xaa\x93\xfc\x06\x10\x73\xe1\x82\x1a\x56\xaf\xb9\xbf\xec\x95\x2d\xf2\x71\x9a\x9c\x7a\x40\x3e\x6a\x93\xf7\xa6\x56\xd7\x4b\x61\xc1\xd1\x90\x83\xf8\xd3\xf1\x9e\x65\x9f\xa2\xb7\x18\xe0\xbd\x04\xb6\x93\xd6\x3d\xaf\xb8\x6a\xdb\xee\x5d\x87\xc7\x5b\x7d\x12\x91\x22\xf1\x78\xa0\xe6\x69\xeb\x03\x5c\xa4\xd8\xeb\x45\x39\x7f\x18\x51\x26\x4e\x2c\xf0\xa0\xcd\xd3\x07\x20\xc5\xe1\x39\xcd\x6a\x57\x3f\x1f\xa2\x41\xca\xe9\x42\x58\x05\xac\x79\x60\x3e\x8d\xe3\x50\xef\xdb\x0b\x9b\xc9\x5b\xa7\xb0\x85\xc1\xed\x92\xc1\x2a\xcf\x53\xf5\xd4\xa1\x13\x75\x98\x00\x8f\x2a\x36\x72\xc8\x4e\x5f\x76\x9a\x25\xc7\xa4\xa1\x65\x79\xd8\x62\x88\x77\x49\x72\x60\x6e\x4e\x7d\x85\x26\x3a\xd2\x17\xe0\xdb\xcf\x34\x3f\xe5\x54\xc1\x09\xc5\xd9\x40\x9b\x79\x39\x07\x3a\xc5\x5a\x03\x42\x0f\xec\x28\x9b\x11\x4a\x5c\x54\xc2\x0b\x45\xea\x69\x93\x85\x33\xad\xe7\xb3\xae\x85\xe1\xa7\x83\xdd\x97\x89\x7c\x3a\xe8\x25\x41\x83\xcc\x54\x04\x5c\x2a\x18\xec\xbe\x52\x16\x91\xf2\x61\x9d\x9b\x8f\x1f\xb3\x47\xca\x05\x5a\x7b\x0b\x4c\x24\xf6\x4d\x17\x73\xe0\x14\x16\x44\x1e\xfe\x15\x99\x23\x21\x7a\x84\x87\x4b\x9c\x4e\xc2\x65\xcd\xaa\xb6\x43\x90\x80\x68\x49\x78\x12\xc1\xaf\x15\xc1\x88\x07\x1e\x78\xf5\x97\xfe\xdf\xce\x91\xc5\xd4\xc6"}, -{{0xd6,0x8a,0x5e,0x3c,0x47,0xee,0xdb,0x30,0x99,0xdf,0xfc,0x80,0x4c,0xf1,0x9c,0x5e,0x74,0xbf,0x7b,0xf5,0xf0,0x1f,0x54,0xd4,0xd9,0x1d,0x75,0x74,0xf3,0xd3,0xdc,0x7c,},{0x46,0x46,0x7f,0xe9,0xce,0x3a,0xcf,0xd0,0xd7,0x43,0x46,0xbe,0x21,0xc4,0x62,0x16,0xdb,0x81,0xae,0xce,0x6c,0xe0,0x30,0x8f,0xb8,0xdc,0x63,0x86,0xfc,0x34,0x46,0xcf,},{0x89,0x6f,0xc3,0xca,0xba,0x7f,0xd3,0xfc,0x28,0x5d,0x5e,0xdd,0xdd,0xc0,0x12,0x0c,0xd4,0x6d,0xa7,0xc6,0xef,0xab,0xe6,0x6b,0x15,0x0b,0x00,0x27,0x60,0xb8,0x41,0x4a,0x89,0xac,0x9e,0x7f,0x1f,0x7b,0x7c,0x7b,0x33,0x59,0x8f,0x61,0xf4,0x57,0x18,0xe4,0xff,0x4a,0xc3,0x68,0xff,0x12,0x96,0x14,0xb4,0xfe,0x92,0x19,0xf2,0x37,0xb0,0x09,},"\x59\x6c\x03\xd0\x87\x3f\x57\x2f\x45\xc3\xb1\x6f\x0e\xf4\xb5\x2a\xd2\xbf\x59\xec\x76\xd3\xc0\xe5\x34\xd6\x2c\x1f\x84\x16\x4d\xda\xa4\x25\xfb\x85\xc9\x54\x84\x85\xb7\x06\x46\x77\xe9\x9d\x04\xc3\x9b\x6e\xba\x04\xc9\x66\x39\x7b\xa6\xa5\xf4\xeb\xaa\x69\xa2\x41\xdf\x95\xa6\xe4\x45\x02\x50\x9d\x63\x50\x55\x7e\xbf\xea\x60\x26\x4b\x62\xad\x7f\x74\xd1\x6e\x5d\x25\xd4\x59\x70\xcf\xeb\xeb\x33\xe7\xb1\xba\xc3\x34\x8d\xd0\x3a\x8e\x99\x13\x3b\x26\xbb\xfd\x7a\xa7\x22\xc2\x58\x7f\x72\xd5\x52\x6e\x98\x0d\xa9\xee\xbd\xf1\x08\x21\x1d\xae\x50\xbb\xe8\xc6\x5f\x9a\xbe\xe6\x9a\x1b\xbf\x84\xc0\x3e\x40\x44\x8b\xab\xad\x03\xd3\xcf\x3b\x7d\xe4\x88\x7d\x2b\x47\x73\x77\x02\x79\x64\x82\xd2\x26\x5c\x56\x6b\x0f\x62\x3b\x53\xc8\x67\x1b\xd3\x71\x9e\xde\xc0\xff\xd5\xf4\x9b\x49\xb0\x72\xc1\x56\x4a\x57\xf9\xba\xb6\xb9\x2d\x1f\x06\x8d\x75\x66\x39\xa4\x33\x14\x52\xe6\x1a\xa7\xb2\x18\xa8\x8b\x9d\xb7\x7a\x19\xfb\x82\xf1\x3e\x98\x68\xed\xb7\x98\xd5\xbe\xec\xa5\x5d\x1a\xb0\x95\xb3\x16\x22\x5f\x3f\x63\x90\xf8\x95\x78\xf0\x16\x04\x28\x74\x7b\xcd\x21\xbe\x6a\xe1\xd8\x69\x91\xb4\x8e\xf8\x0d\x56\x92\x50\x85\x8f\xeb\xf3\x27\x6b\xd5\xde\x3d\xb6\x5a\x24\x5c\x8b\xdc\xf1\x48\x8c\x48\x25\x96\x89\x45\x78\x6b\xed\x63\xf3\xd1\x3f\x14\x09\x36\x3b\x94\x85\x60\x47\x68\x58\xb3\x96\xbc\xe5\x88\xe4\x0b\x31\x1d\xdf\xc2\x2a\xd6\x22\xca\x7d\x1e\x69\x56\x14\x64\xdd\xa5\x00\x9e\x63\x8a\xa5\xec\x9f\x4c\x03\x92\x93\xaa\xec\x75\x00\x1f\xfc\x68\xa7\xcb\x3a\xe0\x18\x74\xdc\x7f\x39\xd7\x50\x27\xf5\x9a\x28\x96\x5f\xc1\x95\x30\xc0\x75\x2f\xe9\x9b\x15\x3d\xa7\xc0\xe5\x42\xbd\xa7\x6c\xa1\xe1\x0b\x7e\xa1\x58\xef\xb4\xd8\x21\xfb\xc6\x5e\x72\x71\xad\x99\x41\x09\x53\x15\x44\x7a\xbc\xad\x08\x80\xa0\x07\x5d\xd0\x4b\x13\x25\xc7\x26\x33\xac\xbc\xb2\x61\xfc\xb4\x07\xc2\x64\xa3\x4d\x70\xbf\x1f\x04\x4f\xee\xad\x06\x9a\xf5\xa8\x7d\xd3\x52\xf4\xbd\x81\x10\xfa\x17\x8a\xdb\xd8\xdb\xf2\x3c\x6b\x57\x5c\xdd\x5d\xf2\x2c\xc9\xa5\xcd\xd3\x7d\x9c\x8f\xaa\xb8\x1a\x4c\xb3\xfb\x5c\x4f\xe7\xff\x62\x9d\xba\xa9\xfc\x06\xb8\x0c\x1f\xb6\x91\xc2\x86\x55\x95\x5c\xfe\x5c\xa4\x41\x49\xb1\x50\xb3\xcf\x14\x0d\x9a\xca\xcb\x14\x31\x3a\x72\xc8\x40\x98\xde\x72\xba\xcc\x02\x72\xd7\x9e\xd6\x61\x7f\x72\xde\xc8\x8e\x19\xb8\x44\x25\x49\x2a\x42\x9e\xc6\xd2\xec\x08\xb8\x63\x46\xdf\xbf\x20\xea\x2a\x36\x19\xe7\x7b\x6a\xc6\x42\x30\xeb\xe2\x5f\xa0\x06\x7a\xbb\x5f\x33\xee\x49\xad\xc7\xc4\x4b\xda\x70\x46\xd7\xf2\x24\xf2\xe7\xa4\x89\x56\x83\xfc\xa8\x68\x4e\xd6\xa0\x31\x84\x4f\x57\x86\xbc\xda\x48\xb5\x04\x23\x94\x48\x7b\x52\x40\x2a\x09\x90\x77\x88\xa1\xe1\x40"}, -{{0x31,0xe8,0x2b,0xc1,0xcc,0x5c,0xed,0x21,0xcd,0xc8,0xbf,0xc2,0xdb,0xbb,0x97,0x6b,0x08,0x78,0x0a,0xfc,0x69,0x44,0xaf,0x7e,0x88,0xe5,0x0e,0x67,0x87,0x4d,0x84,0xf1,},{0x8d,0xf9,0x77,0xe2,0xb0,0x40,0xac,0xeb,0xd3,0xda,0xfd,0x67,0xb8,0x7f,0x92,0x16,0xe8,0xc3,0x71,0xbe,0xce,0xd6,0x18,0xfe,0xf3,0xa4,0x96,0xd6,0x51,0xa5,0xd7,0xb5,},{0x24,0x07,0x02,0xac,0x6c,0x68,0xd5,0x97,0xd2,0x22,0xda,0x94,0x9d,0x0c,0x47,0xd1,0x6b,0x39,0x0a,0x47,0x7d,0x1f,0xb5,0x79,0xe9,0xd8,0x94,0x8a,0xdf,0x9b,0x3b,0x6a,0x7f,0xd4,0x45,0x8a,0xe6,0x38,0x5b,0x7e,0x2b,0x68,0x4a,0x05,0xb5,0x5c,0x63,0xfa,0x6c,0xd0,0x87,0xbb,0x90,0x11,0x3c,0xba,0xb8,0xe4,0xaf,0x14,0x2f,0xcf,0x81,0x0e,},"\x69\xd4\x61\xb6\xb7\xa8\x66\xe9\x4c\xd5\x9a\x5a\x23\xbb\xa4\xa1\x27\x66\x02\xf0\x42\xba\xa8\x50\xd5\xb2\x92\x49\xd6\x74\x3a\xda\x04\xd3\xd9\x38\x21\x9a\xbb\xc2\x2a\xda\x66\xa1\x77\x81\x97\xf7\x0b\xf8\x0b\x59\x7a\x8b\x4a\xe0\x0b\xdb\x87\x68\x12\xd3\xab\x4e\xc0\x11\xdf\x73\x34\x1c\x85\x05\x3e\xeb\xcc\x2d\xf0\xac\xfc\x21\x54\x82\x83\xb5\x53\xec\xde\x01\x54\x82\x8e\xd5\xaf\x47\x57\x19\x85\xf8\x97\x67\xb0\x05\xb6\x22\xc9\xe7\xc0\x79\xdd\xe6\x94\xe4\x9d\xc0\x55\x0c\x79\x18\xcc\x51\x5c\x27\x4d\xbd\x9c\x54\x69\xd2\xf1\x8e\xcd\x90\xde\x66\x4e\x03\xca\x41\xe5\x3b\xe2\x0b\x96\xe2\x5a\xf4\x0c\x54\xab\x0f\x7c\xbe\x9e\x05\xca\x3f\xa5\xa3\x7c\x1a\xa8\xeb\xfb\x64\x44\xa3\x2c\x49\x6e\xfc\x68\x15\x7c\x69\xf3\x58\xc1\x5f\x6a\xc0\x9d\x46\xef\xef\x9a\x68\x5d\xf7\xe8\xdd\x63\xb3\x04\xbd\x3c\x63\x8c\xcf\x53\x2f\xe9\x01\xf1\x1c\xf9\x7c\x5b\x1c\xbe\xd3\x3c\x70\x63\x7c\x72\x1b\x02\x89\xad\xf6\xbb\x6d\x87\xc3\x04\x79\xfa\x92\x6e\x04\x30\x74\x30\x2b\x76\xf1\x15\x7d\x0a\x81\xde\xc4\x93\xe8\x7a\x3c\x64\x3e\x7a\x20\xb7\xa4\x15\x25\xa3\x8d\xb0\x4e\x78\xda\xe5\xe7\x79\x70\x66\xbf\xae\x2c\xf4\x48\xa4\x47\xe9\x00\x4c\xce\x8e\x41\xf0\x98\x79\x91\xfa\xd3\x03\x11\xdd\xaa\x45\x9a\x26\x44\xf4\xb9\x41\xc0\x68\xc0\xd6\xc0\x77\x1a\xfc\xf4\x2b\xf9\x13\x9a\x68\x4d\xa2\x98\x48\x6e\xcf\x67\x52\x3b\xf8\x50\x9a\x45\xba\x5c\xb8\xb3\x86\x4a\xd2\x2c\x0c\x6a\x82\x8c\x6d\xb7\x2e\x37\x1d\xe4\x10\xb4\x7d\xac\x49\xae\x9d\x3b\x57\x02\xb1\x73\x9b\x8d\x76\x0c\xe9\x86\x11\xc0\x7d\x88\xdf\x5f\x04\x68\x38\x08\xa2\x1a\xfc\x2e\x61\x71\x3f\xc2\xc0\x25\xcb\x25\xfc\xc4\xee\x94\x18\x41\x08\x3b\x22\xf6\x1e\x26\x56\xfb\x3b\x8d\xad\x41\xc2\x62\xc8\x9d\x2f\x17\x61\x03\x09\xf2\xd5\xc2\x95\x89\xa2\xdf\x61\xe5\x51\x49\x89\x50\x32\xca\x98\x1e\x45\x57\xe1\x30\xa2\x37\xfc\x08\x26\xfc\x87\x25\x29\x86\x1b\xbb\x83\x28\xd6\x73\xf3\x9b\x58\xb7\x3d\x06\x0e\xc5\x96\xbf\x22\xe7\xee\x08\x1f\x44\xe9\x2c\x02\xa5\x67\x76\x79\x52\x0e\x2a\x2b\x4d\x22\xc7\x7f\x2b\x21\x2d\x5a\xaf\x05\x0b\xf2\xc1\x41\xe3\xe2\x8b\x85\x71\xd4\x32\x19\x37\x42\x62\x35\xc7\xa6\x46\xd6\x47\xe3\xef\xe1\x83\xc2\x7b\x74\x92\x56\x5e\xca\xcd\x7f\x43\xc6\x7a\x74\x45\x3f\x47\x80\xe8\x87\x11\xba\x2d\xd4\xa3\x94\x1b\x12\xdd\xd3\x90\x92\x70\xfb\x3d\xeb\xd4\x22\x43\x6a\xb6\x16\x6f\x08\xc9\x9c\x88\x6c\xc0\xe8\xe3\xce\xcd\x06\x42\xe4\x42\x85\xb8\x86\x4a\xa4\x16\x94\x3c\x5a\x18\x69\x74\xf4\x64\x53\x5a\x87\x0a\x01\x28\x61\xbc\x2e\x58\x71\x49\xca\xe9\x71\x62\x4e\x61\xc3\x1d\x8a\x50\x7e\x3a\xd8\x27\x73\xe7\x23\xbc\xb7\x5d\xf5\x4b\xef\x84\x7a\x40\x7b\xcb\x7b\x1d\x57"}, -{{0xcc,0x56,0xbc,0x7c,0xdf,0xa6,0x11,0x92,0x4e,0x72,0xb0,0x7f,0x68,0xab,0xc6,0xca,0x5b,0x85,0xff,0x8b,0xba,0xcd,0xff,0x40,0x6e,0x51,0xba,0x72,0x0d,0x09,0xa8,0x66,},{0x5f,0xfe,0xe2,0x21,0xab,0x4d,0x0f,0xe6,0xf4,0xc9,0x34,0x6c,0x5e,0x5a,0x4b,0x8a,0x63,0x6a,0x6a,0x0b,0xad,0xce,0x96,0x67,0xbe,0x73,0x9f,0x4c,0x9e,0x67,0x33,0xc1,},{0x9b,0x86,0xa1,0x92,0xb6,0x4f,0x4f,0x04,0x4f,0xfb,0xf8,0x7b,0x41,0xc7,0xee,0x52,0xf7,0xa7,0x21,0xaa,0x32,0x0e,0x7b,0xad,0x64,0x25,0x99,0x59,0x90,0x31,0x5c,0xdd,0x50,0x2b,0xe4,0xe1,0x11,0x60,0x19,0xd1,0x31,0xa9,0x21,0x8d,0x19,0x61,0x4a,0xd9,0x55,0x43,0xb1,0x88,0x9a,0xf0,0xa9,0x7e,0xd4,0xd2,0x56,0xdc,0x33,0xd7,0x6e,0x08,},"\x08\x83\x04\xf2\x2e\x1a\x28\x60\x62\xde\xfb\xeb\xb1\x82\x7a\x64\xb7\x6a\x14\xe8\x70\x15\xe7\xf6\x46\x17\x87\x77\xab\xa7\x97\x04\x68\x8d\x7b\xf3\x2e\x1e\xfa\xc9\x7a\x9f\xc3\x39\x81\x0e\xbd\x3d\xf9\x3e\x4e\xa0\x24\x68\x69\x53\xed\x91\xfa\x6d\x2a\xb6\xe0\x7e\xc7\x81\x1a\x6d\x91\xca\x91\xb0\x98\xdb\x47\x25\xdf\x65\x84\x6a\x95\xb8\x08\x63\x5a\x8d\x0c\x5f\xe5\xac\xe2\x5f\x07\x80\xe8\x96\x17\x7b\xc1\xbb\xa1\xcd\xb4\x44\x92\x51\xc0\x1b\x48\x2f\x02\x38\x62\xf8\x8e\x07\x2e\x79\xcd\xe5\xdb\xd6\xc1\xd9\xad\x9c\x07\xc6\x06\xf5\xdf\x85\xa6\xec\xa2\x96\x6c\xbf\xe0\xa1\x67\x39\x68\x11\x2f\x26\xa3\x17\x05\x3f\x16\x7f\x61\x1a\xf2\x97\xef\xa8\x02\xe0\xa9\x4b\x3e\x1f\x33\xa2\x7b\x73\xe5\x59\x7a\xbb\x22\x41\x15\xeb\xe7\x5e\x29\x4a\x1b\xcd\xcd\x97\x92\x55\xb0\xa8\x02\x65\xc0\x89\xaa\xa7\xd6\xbe\xd2\xe3\xd0\xc9\x18\xf5\x6f\x4a\x55\xf4\x48\xd8\x63\x36\x5c\x6c\x58\x46\xfb\x9b\x2b\x9b\xb5\x5f\x6b\x7c\x6d\xff\x58\x47\xb7\x1b\xfd\xd4\xbb\x5b\x9b\xb2\xe4\x24\x9b\xc0\x24\x3a\x02\xab\x4d\x22\xba\x78\xa4\x3d\x18\x21\x95\xae\xd7\x8f\xec\xe8\x4c\xb1\xdd\xae\xb9\xef\xf6\x81\x56\x04\x5b\x29\x32\xe6\x38\xd7\x73\x1d\x0e\x8b\x4c\x9c\x8c\x38\x3b\x0d\x6d\x39\x2d\x21\xfc\x64\x07\x62\xc8\x7d\x36\x92\xb1\x81\x0b\xcc\x4a\x42\x39\x2f\xf1\x3d\x45\x16\x9e\xcb\xf0\x13\x50\x55\x09\x31\x05\x09\x8c\x86\x9b\x68\x88\x7e\x93\x4e\x2b\x9d\xa5\x23\x2a\xc6\xc9\x37\x38\x00\xf7\x0b\x64\xec\x64\xa4\xaa\x0c\xa0\x44\xc0\x77\x7c\xa3\xa3\xac\xaa\x13\x8c\x14\x24\x96\x72\xa5\x5b\x24\xdd\xfe\x4d\xc3\x57\x57\x32\x41\xe1\x4a\xd0\xac\x16\x47\x5a\x8e\x38\x67\x88\x6d\x41\xee\xa3\x5f\xe7\x93\x2b\xa9\xae\xaa\x0c\x86\xc9\xeb\x6d\xb7\x80\x80\x49\xad\xe7\xb5\xcc\x1a\x40\x82\x2c\x66\xde\xa9\x3a\xd2\x2d\x44\xb9\xe4\x29\x04\xb5\xb8\x36\x84\xae\x29\x31\xfe\x36\xc6\x08\xff\x70\x96\xf1\xb0\x9f\x81\x1b\x02\x67\x28\x04\x40\x6e\x08\xed\x9e\x77\x45\x67\x6c\xe0\x47\xf0\xf7\xf6\x47\x08\xe4\x9b\xb7\x87\x54\x72\x0b\x8a\xa2\x26\xf5\x55\x6a\xbf\x05\xb5\x65\x84\x64\x52\x92\xda\xd0\x8e\x24\x73\x63\x9a\x8c\xe5\x47\x5e\x0c\xe9\x19\x2f\x8b\xa2\xdd\x32\xce\x14\xc9\x19\x75\xab\x60\x2f\x7c\x13\x53\x8c\x52\x95\x2d\x03\x96\x15\x8c\x7c\xc6\xb9\x42\xbe\x7d\x92\x3e\xeb\x52\x3a\x73\xb5\xb4\x11\x96\x6d\x14\xac\x96\xe5\xb0\x96\xa5\x29\x32\xa4\x16\x29\x2e\xcc\xdd\xb9\x10\x71\xc8\x85\x60\xe7\x0e\xcd\x4f\xe2\xfe\x24\xd5\x23\xfa\xfc\xb9\x8e\x40\x21\x50\x2f\x41\x90\xa0\x51\x5e\xdc\xb2\x40\x19\xea\xca\x09\xec\x26\x15\xa9\xbf\xde\xb6\x0e\xb3\x54\xc8\x4a\x1f\x3c\xec\x7f\xfd\x7e\x65\xa5\x51\x5d\x47\x95\x9a\x4c\x4e\xc4\x8d\x80\x21\xb1\x75\x4a\xe2\xbf\x84"}, -{{0x7a,0x57,0xf2,0xdd,0xa0,0xad,0x03,0x38,0xab,0x9a,0x13,0xc9,0xa3,0x49,0x7e,0x9c,0x75,0x23,0x8c,0x15,0x31,0x58,0x97,0x89,0x22,0x7c,0xd2,0x74,0x9b,0xc6,0xe9,0x50,},{0x6f,0x73,0x8d,0xc5,0xe7,0xd9,0xe2,0x40,0xc9,0xf4,0xd0,0xc0,0x6a,0x5e,0x02,0x17,0x47,0x56,0x8b,0x69,0xa7,0x5d,0x50,0x7a,0x2e,0x0b,0xe7,0xea,0x61,0x35,0x26,0xc5,},{0x98,0x91,0x23,0x76,0x1d,0x93,0x56,0x32,0x78,0xfd,0x0a,0x78,0xae,0xd6,0x4e,0x2d,0xe6,0xf4,0xa7,0x00,0xfc,0x9a,0x70,0xd2,0x18,0x77,0x48,0xac,0x06,0xd9,0xc2,0xc3,0x77,0xd1,0x99,0x5f,0x89,0xc7,0x72,0x7f,0xe2,0xf1,0x20,0x78,0x4e,0x41,0x71,0xc4,0x2d,0x63,0x53,0xac,0x3d,0x4e,0x3f,0x62,0x0c,0x63,0x9c,0x75,0x78,0x6c,0x46,0x0a,},"\x8c\x85\x75\xa1\x1d\x2f\xf2\xc2\x38\xe4\x19\xcc\xb0\x06\x33\xd0\x4e\x8b\x8b\xd7\x74\x29\x01\xd5\x88\xdd\x6a\x2f\x00\xaa\x12\xf0\x8a\xe4\x1d\xca\xa9\x33\x8f\x8c\x47\xe9\x53\x12\x19\x2c\xf6\xb2\x45\xa0\x0c\xe6\x88\xa0\x29\xda\x56\xdd\x1b\x1d\xeb\x0d\x34\xb5\x41\x4f\xe1\xc2\x1d\x6b\x63\xd0\x6b\x85\x34\xac\xe8\xe8\x66\xc9\x33\xfd\x7c\x5a\x65\xed\xa9\x5a\x17\x37\xa9\xec\xdb\x17\x85\x91\x49\xac\x69\x69\x51\xb8\x2c\x23\x0e\x82\x75\xe9\x6d\xd0\x2f\xd4\x55\xea\x67\x53\x79\xe6\x7b\xa6\x34\x84\xb6\x28\x38\x31\xfe\x3f\xfe\x52\xd6\xec\x49\xb7\x09\x10\x67\x05\xc9\xd1\x9b\x85\x9d\xe9\xfd\x20\x08\x87\xcb\x44\xd8\xfd\xfe\x69\x61\xfa\x4c\xa2\x34\x09\x44\xc7\x64\xc7\x04\x49\x12\x08\x25\x7e\x73\x54\x82\xaf\x8c\xb6\x90\x41\xdd\xe6\x85\x24\x1d\x3f\xbf\x46\xfd\xa0\x57\x24\x8b\x89\x87\xbe\x1f\x80\xb5\x4e\xb5\x40\x09\xf3\x24\xdc\x45\x0e\x88\x6e\x79\xf9\x12\x58\x5b\x91\xc9\xdf\xaf\xe9\x01\x22\x62\xc4\x71\x40\x3b\x1e\x8b\x5c\x31\xfc\x53\x75\xa1\xdd\xf9\x9b\x68\xed\xf9\xed\x70\xaf\x85\x94\xf7\xd8\x4b\x2c\xc4\x91\x1f\xe9\x05\x00\xc6\xee\xbf\xba\xc0\x85\x55\x35\x50\xe3\x5b\xd2\xe5\x25\x14\xe9\x79\xe7\x24\x1e\x9f\x8e\x34\xcd\xf8\x51\x3a\xbe\x72\x51\x0d\xff\x3c\xfe\xc7\xe2\xbc\x64\x88\x64\x1c\xfd\x0a\x65\xae\x0e\x09\xeb\xe9\x9b\x15\xb2\x9d\x45\xea\x67\xa5\x7a\xad\x55\x4d\x4f\x8b\xfc\xe1\x38\x6a\xce\x22\x88\x39\xe3\xa8\xa5\x34\x14\x0e\xec\x3d\x37\xd5\x1b\xe3\x61\xf5\xea\x18\x83\x73\x9f\x56\x61\x5f\x75\xb0\x55\xa0\x6a\x91\x47\x1b\xe9\x8b\xc9\x45\x37\x83\xc3\x58\x38\x2b\xd0\x55\x5a\xe9\xeb\x0b\xdc\xd6\x66\x29\xa6\x11\xfc\x1a\x11\xc6\x53\xc8\x22\x14\x58\x7d\xec\x12\xba\x12\x0e\x25\x13\x07\x0f\xe6\x9e\x98\x2f\x7a\x80\xad\x15\x9f\x6a\x32\x5d\x97\x7d\x01\xd0\x50\xd1\x16\xa6\x2a\x4f\x8a\xca\xb6\xc3\xd6\x9f\xf6\xc8\x78\x21\x3c\x60\xa9\x48\x45\xca\xe1\x06\xde\x6c\x5d\x6f\xe2\x50\x8d\x94\x56\x5b\x7b\xa7\x5d\x58\xd1\xad\x47\xd7\x6a\x20\xde\xfa\x75\x68\xcb\x7f\xd6\x6f\x57\xcf\x37\x74\xa2\x1d\x3f\xfa\x7d\x8a\xa6\xd8\x6d\xc2\x84\xb7\x0e\x0f\x17\xe7\x63\x0b\xfc\x10\xcd\x1f\xc9\xa8\xd9\xc5\x92\xd3\x9f\x24\xa7\xb5\xc8\xe8\xaf\xf3\x53\x57\x7e\x6a\xc9\x00\x86\x90\xc7\xa1\x59\xa7\xe8\x3b\xe5\xa6\xae\x8f\xca\x96\x44\xbd\xdf\xa3\x7a\x92\xb0\x70\x55\xf9\xfa\xc9\xfa\x97\xfb\x3e\x8f\x5f\x4d\x91\x7d\xda\x5c\x6d\xc6\xea\x34\xb6\x4d\x30\x24\x05\xbc\x38\x06\x2e\x07\xce\x93\xa1\xa8\x8a\xed\x5f\xba\xf9\x95\xa0\x9b\x45\xb2\x8a\xd4\xa6\xb2\x73\xde\xc1\x41\x3c\x54\x04\x52\x9d\x82\x5b\x5e\xdc\x2e\x27\xa3\x90\xeb\x7e\x8c\x2b\x43\x90\x5e\x11\x6d\x88\x7a\xb5\xfb\x99\x3d\xfe\x15\x0e\xbd\xcf\x81\x7a\xe6\x2e\x03"}, -{{0x32,0xef,0x6d,0x78,0x9a,0x1e,0xa3,0x93,0xf1,0xbf,0x9f,0x11,0xde,0x34,0xf5,0x7d,0x65,0x3c,0x4e,0x77,0xd5,0x1e,0x60,0x50,0xfe,0xf4,0xe8,0xd7,0xbf,0x18,0x3d,0xb5,},{0xc1,0xaa,0x18,0x1e,0x62,0x0f,0x60,0x52,0x5c,0x2b,0x17,0xda,0x8d,0x29,0x0b,0xae,0x5d,0x33,0x9e,0x17,0xea,0xbc,0xea,0xb5,0x8c,0xd7,0x6a,0xe0,0x66,0xf4,0x11,0x79,},{0x88,0xf3,0xa6,0xe0,0xbb,0xaa,0x3e,0x06,0x0b,0xc9,0xd9,0x1f,0xe2,0x96,0x8c,0x61,0x12,0x6b,0x20,0x31,0x7f,0x59,0x84,0x2e,0x4a,0xe4,0x87,0x11,0xcd,0xba,0xf6,0x2c,0x6c,0x02,0x07,0x40,0x5d,0x1c,0x48,0x49,0x95,0x02,0x71,0xf0,0xaa,0xa7,0x59,0x30,0x91,0x10,0x9e,0x47,0x8d,0x13,0xf3,0x56,0x96,0x4f,0x7d,0xba,0xb7,0x29,0xaf,0x00,},"\x11\xa9\xc3\xc1\xba\x7c\xfb\x61\xad\x10\x33\x05\xc2\x58\x86\xde\x9f\x88\x15\xc6\xc2\x1f\x17\xa8\x73\x3a\x02\x4f\x94\x97\xda\x05\x40\xdb\x36\x03\xa6\x71\xaa\xe8\x37\xdb\xbb\xa1\x9e\x19\xf8\x2d\xdf\xc8\xaf\x85\x59\x80\xa7\x01\x25\xfc\x61\xcd\x7f\xfd\x10\x77\x7e\x36\x6e\x5e\x95\x69\x92\x7a\xf0\xf2\x45\xd4\xf3\x9b\x3f\xd0\xf4\x58\x79\xc2\x53\x40\x14\x12\x85\x5e\x57\x61\x90\x5e\xd6\xef\x31\x8b\x6a\x06\xea\x6e\x9f\x90\x6f\x9b\xd0\x16\xbc\xb6\x94\xa0\xdf\x65\xa0\x16\xbd\xfe\x84\x5a\x09\xf2\x3e\x50\x86\xc5\xaa\xf3\x75\xef\xeb\x86\xda\x51\x23\x9d\xdc\x35\x0b\xac\x0c\xdb\x03\xb8\x74\xdb\x15\x07\xe6\xad\x4e\x2c\x9f\x46\x02\x8c\xa2\x38\x83\x63\x54\x14\x93\xb6\xcb\x92\xc1\xdf\xca\xa3\xef\xd6\x8c\x6b\x4e\x91\xef\xb4\x67\x51\xd2\x3f\x4c\x48\xa9\x73\xf0\xa5\xc7\xc6\xfe\x2a\x12\x69\xd2\xa6\x9e\x9f\xc4\xab\x8b\xa3\xb9\x2f\x79\x64\x49\xba\x3d\xc7\x02\x45\xed\x50\x5c\xc0\xee\xee\x16\x36\x64\x7a\x68\xc7\x67\x9d\x0b\x6d\x65\x1b\xba\x35\xc2\x9b\x81\x47\x8d\x17\xca\x36\x85\x70\x7a\xd6\x16\xe6\xe5\x60\x43\x81\xf8\x4e\xe5\x2b\x25\xad\x02\xfc\x0d\xfb\x85\x43\x2e\xfb\x1f\xec\xd0\x90\xc0\x2a\xd0\x02\xc1\x85\x7f\xce\xd8\x8f\xdf\xb2\xff\x26\xdd\x0f\x50\x18\xfb\x47\xd8\x13\x58\x1f\x65\x08\xca\x63\x7c\x73\x65\x17\x7c\x51\x3d\x1e\xe0\x58\x79\xa6\x5c\x5b\x67\x6b\x3a\xa8\x73\xa1\x93\x5c\x54\x37\xea\xdc\xb6\x6d\xfb\x05\x2a\x5e\x7c\x3e\x81\xd4\x4b\x3d\xaf\x69\x8f\x42\x24\x4e\xe2\xee\x4b\x6e\xd2\xb7\xe6\xe5\x6e\x61\xff\x9c\xb4\x5e\x71\x9f\xd7\x46\x19\x8b\xf2\xa7\xde\x6d\x25\xaf\x3b\xc6\xc7\xb0\xed\x8a\xbe\x3c\xb3\x89\xaf\xd8\x4f\xfa\x2a\x23\x0d\x93\xbc\x0c\x29\xd5\xa9\x41\x9c\xbf\xf1\x1b\x78\x83\x32\x99\x21\x48\x0b\x58\x44\x65\x5d\x99\x6c\x7c\xab\x29\xdf\xb2\xa3\x92\x7b\x82\xba\x7c\x30\x6c\x45\x77\xb6\xf8\xb5\xdb\xe2\xaf\xaf\x9b\xf1\x4a\x8f\x95\x54\xcd\x01\xa6\x9a\x99\x1b\xf2\x12\x82\x8d\xe1\xe6\x31\x72\xe8\x33\xde\x06\x69\x8c\xdb\x3b\x28\x71\x63\x80\x31\x45\x72\xbf\x5b\xcf\xd3\x4e\xf5\x2a\x6f\xad\xda\x87\xba\xbe\x6b\xac\xdb\x20\xce\x63\xc7\x25\xcb\x0f\xf6\x1f\xe3\x0c\x1b\x51\xdb\xda\x2c\x26\x25\xf9\x9d\xfe\xb0\x29\xa3\xe5\x8c\xba\x7d\x01\x90\x51\x11\xca\xf4\x2f\x27\x02\x5e\x72\x0e\x18\xee\xb0\x7d\xae\x91\x55\xc5\x5a\xa3\x00\xe2\x2e\xb5\xe9\x4d\xc7\xa0\xa8\x4e\xe6\x7d\x91\xa9\x60\xae\x08\xca\x63\x2d\xbb\x17\x37\xfc\x9a\x43\xdb\xcf\xb3\xa8\x79\xeb\x9f\xbf\xfd\x72\x99\x33\x8e\x26\x4b\xc1\x23\x7a\xb6\xa5\xbc\x2a\x26\x3c\xfa\x99\xe8\x54\x44\x39\xd9\x63\x31\x63\x9f\xe9\x40\x8e\x54\xa3\x50\x61\x0f\xf0\x1d\xe3\xf8\x57\x99\xad\xeb\x73\xd8\x2b\xe9\x38\x07\x4d\xea\x85\x8e\xa6\x36\xb6\x3a\xbd"}, -{{0x0a,0x55,0x25,0xa4,0x59,0x8f,0x60,0x99,0x2f,0x86,0xba,0x1a,0xb9,0xee,0xe6,0xe2,0x67,0x56,0x22,0xf9,0x43,0x28,0x4f,0xc0,0x55,0x3e,0x44,0x46,0xac,0x5a,0x4c,0x53,},{0xdb,0x60,0xd7,0xea,0x29,0xf8,0xd6,0x0d,0xad,0x33,0xd0,0x2e,0xc5,0xf4,0x22,0x32,0x05,0x7b,0xd1,0xc4,0xbd,0x61,0x80,0xa2,0x42,0xcb,0x7a,0xb6,0xf4,0x42,0x67,0x81,},{0x8f,0xa6,0xb0,0xae,0xac,0x71,0x13,0x2a,0xd8,0x82,0x97,0x58,0x68,0xf1,0xbd,0xb8,0xc1,0x1f,0x1a,0x6c,0x1b,0x9c,0x54,0x59,0x4e,0x0e,0x46,0x28,0x6e,0xa6,0xc9,0xa5,0xd6,0xd5,0xb0,0xea,0xea,0xca,0x9a,0xe3,0xaf,0x74,0xe7,0x23,0x26,0xb3,0xb6,0xf2,0xea,0xa8,0x93,0xc0,0xec,0x42,0xa4,0x9c,0x56,0xef,0x51,0x4f,0x75,0xc7,0x7f,0x01,},"\xf7\x87\x32\x1b\x42\xc0\x8d\x40\x52\x44\x9a\x48\x85\x93\xd8\x85\xb4\xe0\xc3\x4a\x5d\x64\x14\x9f\xa8\xb9\xc8\x5e\xe5\x4b\xcb\xec\xb5\x09\x09\xb2\xa8\x6b\x88\x25\x8a\x10\xe0\x7e\x8f\x8c\x2d\x06\x8a\x89\xfb\x16\x5a\x6a\xce\x7e\x64\x99\x8b\xa5\x7d\x89\xd9\xbf\x2b\x8b\x38\xa1\xf6\xd8\x36\x4a\xee\x05\xce\x33\x48\xbe\xd4\x8b\x88\xc2\x47\x3b\xf5\xf2\x66\x5f\x51\xca\x07\x3a\x53\x05\x35\x8e\xaa\xd4\x36\x5d\x58\xb8\x3b\xc9\x81\x4e\x25\xf5\x4c\x37\xcd\x9b\x68\xa8\x08\xa5\x7d\x6c\x2d\x7d\x7b\x6d\xeb\x5f\xe2\x0f\x4f\x96\xfe\x72\x5f\x8d\xe6\x5c\x29\xa4\xf1\xcc\xef\xd7\xc2\xc6\xf2\xfc\x01\x16\xd5\x86\x76\xac\xbc\x58\x69\x1c\x79\xc2\xb0\x06\x78\x5a\x09\x75\xa3\x1d\x8d\x3c\x94\x91\x61\x59\x6a\x06\x8a\xaf\x22\x26\xab\x84\x25\x50\xe9\xc0\xb2\x61\x0a\x29\x53\x1d\x1f\x3f\x7f\x00\x82\x6b\xb6\xc7\xdb\xe0\x4e\x28\xae\x1b\x9f\xf6\xf8\x88\xa4\x9d\x82\x81\x2f\x45\x2e\x1b\x32\x74\x0b\x23\x4d\xdd\x96\x42\xe1\x8f\x32\xad\x9a\x9a\xf7\xf8\x95\x25\x28\x67\x4a\x2c\xda\x25\xb4\xf7\xba\x86\x70\x07\xff\xa7\xf7\x8f\x16\x3d\xb8\xf3\x69\x14\x95\x6b\xfa\xec\xd5\x0f\x6d\x1a\xf4\xee\x13\x32\x75\xa8\xea\xab\x94\xbb\xc0\xae\x52\xb6\xd9\xb2\x83\x26\x34\x23\x2e\xc0\xe8\xb5\xf8\x02\x2d\x3e\xf1\xea\xd9\xb7\x9e\xf9\xa1\x65\x64\x27\x71\x94\xf2\x38\x0d\x90\x21\xe1\xf1\x7b\x18\x4b\x8d\x3a\x7a\x34\xd1\x51\x39\xa3\x9c\x77\x28\xc2\x2e\x1a\x3a\x67\xa2\x7a\x6c\xa4\xb8\xa8\xa0\x63\x6c\x60\x54\xd0\xf7\x41\xf0\x46\x67\x36\x19\xfc\x6b\x07\x0e\x62\xff\x48\x62\xf5\x9d\x26\x90\x07\xf3\x43\x13\x39\x63\x7a\x89\xf5\x64\xc0\xdb\x3d\x9b\xcf\xcd\x19\xfc\x25\x13\x8a\xc6\x6d\x47\x4d\x80\xf4\xad\x79\xf6\xd1\xe7\x84\x44\x08\xe8\x80\x34\xee\xaf\xf4\xa7\x90\x33\x8d\x54\x6b\xfc\xd7\x42\x4c\x11\x9e\x21\x1f\x36\x3c\xb8\x9c\x88\x87\x49\x34\x6a\x89\xd3\x2f\x02\x3b\xb6\xb0\x36\x6a\x1e\xde\x43\x25\x03\x2a\xa3\x5f\x52\xe9\xdf\x93\x8a\x50\x27\xeb\xee\x96\x88\xae\x48\x0d\xde\x1a\x9c\x9b\x42\xd1\xa9\xc0\x8f\x71\x92\x23\xdf\xae\x1c\xfc\xd4\x9d\xd1\x05\x3a\xaa\x38\x1c\x24\xcc\x9c\x7a\xbf\xcf\x8f\x6d\x86\xd6\xaf\x72\xee\xf0\x53\x04\x41\x2f\x3d\xb2\x58\x5a\xa9\xe0\xf3\xa4\xf1\xb6\xd7\x10\xd0\x2a\xb1\x1d\xb1\xfc\x90\xad\x4d\xe2\x5d\x04\x29\x9f\x31\x29\xc2\x12\xe9\xcb\x73\xc0\x04\x79\x53\x45\x5b\xf9\x8e\xc8\xfd\x26\x74\xe4\x7b\x94\x99\x57\xde\xed\xa0\x18\xba\xdc\x9f\x2f\x68\xa1\xb1\x8e\xf5\xc5\x83\xb0\x95\xe0\x8d\xd9\x06\xda\x5f\x22\x0d\xa0\x29\xb9\xc4\x00\xe3\xca\x91\xc7\xcb\xd8\x7f\x34\x30\xc7\x42\x33\x7f\x61\xcf\x54\x74\x5b\x06\x22\xbc\xb9\x07\x62\xc6\xba\xfe\xf8\x7e\x1e\xc8\x88\xc3\x64\xfa\xd6\x46\xc3\x3a\xcc\x22\xaf\x54\x38\xb8\x4c\xd5"}, -{{0x2d,0x5d,0xdf,0xfa,0x2e,0x58,0xc9,0x04,0x51,0xea,0x05,0xde,0x47,0xb8,0xc4,0x92,0x34,0xe2,0x6c,0xed,0x54,0x85,0x4e,0x3a,0xce,0xf1,0x1d,0x8e,0xe6,0x85,0x2d,0xa7,},{0x7b,0xfd,0x1c,0x8a,0x4a,0x0b,0xbb,0x46,0x06,0xd2,0xe5,0xbc,0x09,0x0f,0x56,0xb2,0x0d,0x58,0xf2,0x20,0x4b,0x6a,0xed,0x83,0x1d,0x3d,0xf4,0xd4,0x06,0xb4,0x76,0x05,},{0xce,0xd9,0xd6,0x10,0x10,0x33,0x9c,0x47,0x1d,0xdf,0x9f,0xef,0xca,0xa8,0x2d,0x1e,0xab,0x3a,0x2e,0x0e,0x60,0x27,0x85,0x53,0xb4,0xdd,0x9f,0x39,0x5b,0xe5,0x81,0x49,0xc9,0x15,0x94,0xe5,0x61,0x8b,0x0b,0x10,0xbf,0x3a,0xab,0x94,0xf1,0x59,0xb5,0x30,0xf6,0x44,0x63,0xee,0xd6,0x6f,0xa2,0xac,0xe5,0x4f,0xd9,0x25,0x72,0xa0,0x6a,0x0e,},"\x4f\x1c\x5b\x4e\x6f\xac\x3b\xaa\x3e\x90\x10\xf3\xbf\x29\x3c\x77\x9e\x61\xfd\x7b\xbe\x05\xa5\x86\xf5\xaa\xf0\x80\x26\x37\x16\x27\xa2\x09\xac\xd1\x88\xaf\xb2\xdb\xe0\x31\x15\x47\x94\x05\x59\x71\x16\x40\xf7\x8a\xea\x9a\x62\x81\x89\x62\xf4\x45\xa8\xe7\xed\x6f\xe6\xc5\xf4\x91\x62\xe7\x43\x5d\x1b\x62\x5b\x88\xba\x39\xda\xb0\xad\x56\xfd\x2c\x0a\xd6\x51\x26\x61\x36\x2b\xf7\x8a\xfe\x5a\x14\x16\xb6\x47\xf3\xb8\x8a\x05\x6c\x9e\x72\x89\xc9\xb0\xcc\x3a\xfb\x43\x40\x21\x98\x56\x34\x93\xe7\x37\xb1\xda\x05\x25\x06\xb6\xc9\x30\x6d\x75\xad\x66\x93\xdb\x6d\x15\x71\xf9\x6f\x6f\x52\x99\x0c\x4d\xf1\x96\x65\xa6\xbb\x63\x07\x3f\xdd\x9f\x55\x59\x68\x96\xa2\xe9\xc2\x62\x2f\x2b\x0c\x2c\xc9\x9d\xdd\x1b\x64\x9f\xb0\x31\x80\x58\xd7\x47\x94\xe3\x8e\xc6\x57\xeb\xc8\x2a\xbd\x5b\xed\xf8\xb3\xf4\xbb\xa3\xbb\x6c\x99\x35\xfd\xf6\x82\x65\x02\xb7\x69\x04\x6b\x36\xd9\x6d\xc6\x95\xd7\xc8\x54\x04\x28\x4d\x2a\x2a\xb7\xfc\xf3\xb0\x2f\x68\xa1\x49\x3d\xd3\x83\xca\x63\x39\xfa\xc1\xcd\xe4\x7f\x53\xc5\xe0\x26\xd0\x86\x9f\xaf\xfe\x40\xab\xdb\x98\x19\x52\x30\xf1\x7d\x0c\xfa\xa5\x33\x31\x5a\xfd\xbf\xe7\xd1\xaf\xc3\xa6\x15\xb4\xf7\x50\x90\x23\x3a\x50\x3f\x88\x61\xe3\x23\x74\xe1\xea\x95\x57\x67\x42\x31\xd9\xd7\x37\xd4\x77\xb3\x3f\xf8\x2a\xc0\xb2\xc0\xba\x93\xc1\x1f\xb5\x23\xe6\x13\x61\x8e\xd3\x70\x52\x4a\x60\xf4\xd4\xc8\x36\x94\xc0\x33\x60\x6d\x1d\x06\x9d\x54\x4d\xcc\xd3\x90\x0c\x37\xa3\xb3\x36\x3e\xfb\xcf\x66\x97\xf9\xf7\x62\xb3\x3b\x12\x94\x58\x39\x53\xfc\x53\x77\x3e\xf5\x67\x26\xee\xb4\x70\xeb\xe9\x21\x49\xb7\x36\x48\xa1\x61\x61\xd4\x94\x12\x0a\x31\x8b\xfb\x08\x0c\xc3\x8e\x49\x96\xf4\xb2\x63\xff\xe7\x8c\x78\x77\xfe\x13\xc2\xfc\x55\x21\x9f\x44\x26\x0e\x8f\x25\x3b\xdd\x37\x9d\x87\x0e\x6c\x91\x04\x8b\x1d\x8d\x4e\x88\xb8\x82\x18\xb2\xb0\x49\xfe\xf5\x3b\x2a\xe1\xf8\xc9\x21\xed\x2b\xcb\x43\x46\x69\xe3\x97\x5d\xcc\x3f\xe4\x52\x0c\xa8\x02\x48\x42\xf7\xff\x2b\xa1\xe2\x2c\xfe\xb5\xd4\xc9\xe4\x35\xea\xda\x60\x1f\xf1\x83\xb2\x63\x64\xee\xe1\xfa\xa5\x9d\x19\xe6\xaa\x4f\x09\x75\x23\x84\x96\xa7\x09\xe4\x6b\xf6\x83\x36\xb0\x68\xbd\x80\xb3\x46\xf1\x1f\xaa\x38\x17\xa0\x7d\x1c\xbd\x84\x38\x2b\x21\x02\x98\x6f\x29\x5a\x13\x98\x07\x7b\xa2\x91\xd6\xb5\xf5\xbd\x86\x0e\xc6\x17\x72\x73\x46\x8f\x0e\xe0\xf2\x59\x1b\x57\x5c\x43\x66\xe1\x89\xb2\x24\xe9\xff\xa3\x5b\xc7\x8a\x4a\xa8\xc0\x69\x54\xfe\x33\xd0\x80\xff\xc0\xb2\x3e\x20\x9f\xd0\xe7\x94\x21\xf1\xbd\xe8\x18\xa8\x68\x90\xcf\x17\x22\x36\xdb\x21\x16\x57\xd1\x00\x31\x19\xfe\x91\xd4\xe2\x7c\x52\x4c\xcc\x11\xfa\xde\x0a\x25\xf5\x7a\x7a\x1d\x67\x7e\x1d\xa0\xb9\xc0\x43\xd0\x2f\xca\x38"}, -{{0x4d,0xf5,0xe1,0x1d,0xec,0x80,0xec,0xd8,0x82,0x83,0x75,0x54,0xfa,0x31,0x35,0xb9,0xd5,0x02,0x9d,0xf4,0x20,0x27,0xaa,0x3b,0x3c,0x92,0x92,0x46,0x32,0x9f,0xee,0x96,},{0xef,0xd9,0x28,0x89,0x8f,0xa1,0x44,0xc2,0xd1,0xc8,0x33,0x4f,0xa2,0xe6,0xb5,0xb6,0xa3,0x25,0xa7,0x10,0x2a,0x2c,0x34,0x4a,0x14,0x55,0x41,0xee,0x9a,0x6c,0x04,0x6d,},{0x62,0x54,0x5e,0x6c,0x07,0x80,0x1f,0xde,0x95,0xb4,0x61,0xe2,0xe7,0x53,0xc4,0xb6,0xc8,0x4c,0x25,0x12,0x4e,0xb3,0x30,0xa2,0x72,0x59,0x89,0xd5,0xe3,0x40,0xdc,0xef,0x0c,0x74,0x56,0xd4,0xc7,0xc6,0xa1,0x78,0xa2,0x21,0xb6,0x32,0x83,0x48,0x25,0x3d,0xb7,0x87,0xa9,0xe5,0x51,0x0a,0xb9,0xcc,0x27,0x85,0x15,0xae,0x3e,0x58,0xfb,0x01,},"\xfb\xd6\xf3\x71\xb4\xc8\xb1\x52\xc9\xce\x0c\x63\x96\xa7\x7c\x0f\xe4\x80\xbc\x02\x00\x7f\x33\x6a\xc5\x8f\xd4\xad\xdd\xa9\xd6\x98\x55\xac\x9e\x93\xa4\x5d\x3e\x35\x0f\x41\xff\x50\x2a\xa1\xd8\xfe\x15\x9c\xe8\x9b\x06\x48\x02\xa0\xa1\x89\x0f\x6a\x40\xa7\xef\x57\xc6\xe5\xe5\xed\x04\x02\x80\xdf\x07\xe7\xf4\x8f\xe8\x19\xbe\x63\x17\x67\x10\x75\x7c\xb6\xe4\x40\xb4\xf7\x8b\x57\x59\xdc\xe0\x28\xbf\x58\x5b\x3c\x3f\xec\xa1\xcf\x59\x81\xda\xda\xdf\xd2\x7e\xa1\x24\xaf\x45\xef\x63\x85\x42\xa8\x61\x7f\xf4\x9f\x94\x70\xac\x22\x85\x94\x3c\x7c\x3b\x11\x63\xb9\x03\x95\x5a\xb9\x9b\x6e\xab\x17\xf4\xd4\x9f\xfa\x87\x20\x7a\xbb\xfc\x11\x1c\x4b\x91\xf5\x41\x3d\xfc\x9b\xea\x31\x84\x3d\x11\x5d\xde\xb1\xda\x40\xb4\x5f\x58\xf4\x7c\x41\x7b\x5e\x77\xd5\x81\x89\x34\xe7\x30\xeb\xa9\xc4\x55\x7b\xbf\x48\xcb\x7f\xd4\xe6\x64\x55\x8a\xf4\xfb\x44\xee\x3d\x94\xc1\x6e\x88\x36\x31\xf3\x84\x76\xf4\x83\x7d\xb9\x4d\x54\x12\x2f\xa1\x34\xca\x51\xa5\x25\xaa\xd5\xe2\x4b\x76\x01\x8f\xee\x9a\x2e\x8f\x60\xe2\xbb\x48\xd2\x4a\xb8\xb1\x46\xf8\x4f\xfa\x98\x20\x12\x0e\x7c\x50\xd4\x5c\x0c\xfb\xe3\x5c\x8c\x31\x41\x9b\x07\x8e\x90\x71\x2c\xfe\x93\x4c\x3b\xe3\xa9\x4f\xf2\x15\x88\x73\xae\xfe\x34\xdc\x6e\x36\x90\x2b\x16\x75\xe1\xa4\x7c\xb6\x08\xdf\xe9\x60\xfb\x4d\xa8\xd2\xa8\x49\x0c\xc3\x8e\xba\xdc\x73\xa1\x00\x3c\x49\x41\xfd\xa8\xfa\xe9\x44\xa1\xde\x8e\x3b\x10\xef\x6d\x9e\x67\xce\xec\x74\x59\x77\xd3\x33\xac\x9e\x71\x21\x41\x21\xed\xe8\x89\x22\x95\xe2\x77\x99\xf2\x06\x67\x5a\x9d\x54\xac\x12\x15\x9d\x3a\x1f\x95\x4f\xd0\xee\xff\xbd\x30\xa3\x19\x04\xfb\x2e\xee\x77\xa8\xaa\x9d\xc4\xcc\xbb\xe2\x85\x10\x96\x14\x6a\x4c\xe0\xe8\x1f\xb9\xc6\x24\x98\xdb\xd8\x3b\xf8\x3b\x55\x02\x9a\x5e\x90\x00\x86\xb9\x53\x1c\xe3\x24\x7a\x98\xf8\x65\x4e\xfd\x8f\xe7\xa8\x36\x43\x1f\x75\xda\xf0\x86\x8f\x01\x08\x32\x6e\x23\x02\x6d\x2d\xb4\xa7\x21\x24\xec\x4e\x39\xd4\xbb\xf3\xd8\x46\xc9\xf5\x1c\xa3\xcc\x31\xeb\x1d\x02\xc2\xba\x32\x1e\x46\x19\xf2\xb6\x59\xc0\xbf\x0f\xe5\xc1\x9b\x21\x3f\x3c\x79\x12\x4f\x36\x43\xf7\x4d\xd0\xff\x9c\xe5\xd2\x77\x27\xbe\x6c\x69\x58\x15\x9c\x16\x44\x04\xf4\x33\x01\xfe\x17\x42\xe2\x79\xde\x9e\xfd\x44\x1e\x73\xe4\xea\x7a\x84\x25\x87\xa7\x9d\x11\x5d\x36\xec\xa9\xc0\x3c\x90\xff\x0d\x14\x74\x74\x10\x9f\xc2\x0a\x91\xd7\xb3\xcc\x22\xeb\xcb\xb8\xc7\xf7\x1b\xd6\x1e\x8c\xae\x47\xc5\x05\x0c\xec\x1d\x48\x49\xa1\xd4\xa8\xe7\xa6\xf8\x45\x54\x84\x37\x70\x6c\x25\x33\x1c\x9e\x57\xc2\xcc\x6d\xa1\x17\xf2\xe5\xa0\xf4\xb3\x68\xc4\xcb\x20\x62\x65\xc4\x17\x8e\x06\x55\xff\x67\x5f\xfc\x1d\x4c\x58\xec\xeb\x9e\xdb\x4d\xa3\xad\x2c\x5f\x62\xcd\x13\xab\x48"}, -{{0x85,0xd3,0x23,0x30,0xe2,0xe0,0x73,0xa4,0x60,0x30,0xca,0x0e,0xe2,0xdf,0x2f,0x8e,0xb8,0x74,0xa9,0xfd,0xdf,0x56,0x24,0xc8,0x03,0x17,0x75,0x11,0x1f,0x11,0xee,0xa2,},{0x6e,0xa7,0xde,0x2e,0xd5,0xea,0x5c,0xdf,0x50,0xbf,0xff,0xee,0x77,0xf7,0xbd,0x2f,0xcc,0x21,0xd4,0x86,0x66,0xbb,0x1f,0x48,0x90,0xc7,0x6a,0x69,0xcc,0x7b,0xa4,0xe8,},{0x41,0x43,0x63,0xfe,0xad,0x6e,0x59,0xa3,0x43,0x8c,0xe5,0xa3,0xa2,0x77,0xd6,0x2b,0xdd,0x00,0xfa,0x2e,0xfa,0xc6,0x46,0x3d,0xd1,0x3f,0xcd,0xde,0xd9,0x3a,0x7f,0x10,0x8a,0xe1,0xf5,0x28,0xff,0xc8,0xff,0x4e,0xca,0x33,0x1d,0xab,0x91,0xae,0x5b,0x14,0x16,0xe2,0xdd,0xb7,0x3b,0x6d,0xaf,0x85,0x3b,0x03,0xc8,0x1e,0x99,0x36,0x56,0x0a,},"\xae\x61\x07\xf3\x8f\xf9\x4e\xd0\x32\x79\x03\xcb\xaf\x6c\x3e\x3a\x34\x98\xc4\x7a\xbb\x29\x89\xa8\xb3\x7b\x3a\x19\xdf\x88\xc6\xde\x79\x0a\xcc\xb4\xb7\x25\x81\x77\xb9\x15\x1d\x1f\xe0\x40\x63\x57\x7d\x3c\x3a\xcd\xb4\xc9\x29\x96\x8a\xfd\xad\x6f\x25\x2a\x67\xed\x4c\xa8\x9d\x06\x0f\x1a\x46\x53\x98\x3f\x7a\xb5\x8d\xdb\x93\xe2\x87\x8f\xba\xb0\x63\x7d\xbb\xeb\x95\xd2\x5c\x59\x86\x83\x9d\xe2\x74\x8d\x9f\x34\x02\x7a\xee\xbf\x1d\x9e\xb9\x36\xcb\x67\x70\xe0\x8d\x45\xb8\x09\x5b\xac\x9c\xbb\x71\xdb\x14\xe8\xa3\x42\x22\xb1\xf2\x23\x7b\x9f\x0b\xc9\x76\x6a\x23\x1a\x6d\x10\x27\x99\xf7\xc0\x81\xd5\x00\xfb\xea\xde\x60\x3c\xdc\xdd\x7d\x5b\x96\x5f\xba\xce\x4b\xe5\xc2\xcd\x93\x2d\xcf\x5f\x6e\xd3\x17\x22\xf4\x1d\x5a\x36\x3b\x34\xba\xbf\x3f\x63\x6f\xb3\x03\x82\x4a\xa7\x01\xdf\xe1\xd3\xe4\x12\x63\x07\x8c\x1e\xbb\xdc\xb1\xf7\x3f\x12\x45\xb8\x3e\x3f\xa7\x0a\xb8\xe3\xf1\x41\x3e\x6b\x06\xbd\xae\x02\x2b\x71\x4d\x60\xa4\x01\xd5\x74\x80\xdc\x64\xe7\xaa\xc6\xd3\xde\x85\xfc\x94\xd8\x53\xca\x13\xb7\xe6\x74\x15\x57\x9d\x5c\x67\x21\x23\xa5\xaf\x19\x4b\xee\x14\xae\x35\xdc\x27\x24\xff\x20\x9f\x11\x66\x63\x86\x61\xf8\x81\xb1\x19\x4a\xa4\xe3\x1b\x42\xa5\x27\x96\x47\x81\x59\x15\x04\xba\x76\x10\x3f\x97\xb7\xf5\x52\x03\x15\x47\x3e\xc9\x4b\xb0\x17\xa1\x66\x67\xb2\x2a\x85\x76\xa7\xcc\x2a\xc0\xb7\x75\x63\x03\xc7\x56\xf0\xdd\xaa\xe9\xd0\x18\x9e\x6c\x8d\xe3\x49\xf9\x19\x57\xc7\x2a\x52\x9e\x9f\x7e\x9b\x94\x56\x52\x48\x40\xba\x02\x34\x4f\x55\xad\x3c\x11\xa0\xb2\x59\x90\x14\x39\xf2\x65\x5a\xb9\xf8\xc6\xc8\xe8\xe9\x60\xc0\x57\xd9\xc7\xda\xfe\x42\x5c\x75\xd4\xa3\x3b\x80\x1d\x45\x47\xcd\x05\x51\xa6\x80\x2a\x80\x05\xdd\x72\x42\x47\x64\xdc\xf5\x7e\x4a\xa2\x22\x90\xea\x4f\x5b\xaa\xc5\x1d\x79\x39\xc0\x53\x42\x88\x2e\xe1\x43\x80\xef\x2d\x47\x04\xb4\x19\x49\xb2\x28\x2a\x1e\x1a\x3f\xa7\xdd\xea\x9f\xe8\x3b\x9f\xc5\x1d\x4e\xef\xa2\xeb\xac\x72\x2e\x4c\x0a\x7c\x59\x9b\x69\x25\xf0\x1b\x8a\x20\x66\xdc\x0c\x26\xf9\x21\x96\xf4\xf5\x03\xe8\x87\xc1\xe6\xef\xb0\x93\xf1\x53\x13\x87\xbd\x88\xc6\x91\x99\x7b\x9b\x89\xe3\xcd\xf7\xda\x12\xd3\x73\x41\x83\xa4\xb6\x12\x6b\xe9\xe0\x77\x47\x04\xb5\x29\x65\x9b\x55\x48\xf1\xb8\x75\x12\xcc\x18\x78\xca\x4e\xf5\x59\x90\xb4\x83\xc9\xaf\x6a\xa9\x76\x35\xf4\xf0\x79\x49\x72\x70\x65\xab\xf2\x1e\x21\xe3\x29\x90\xb1\xa7\xd0\x7d\x74\xe0\x2d\x9b\x07\xec\x63\x99\x31\xbf\x9e\x2c\xa3\x94\x1f\x2b\xa6\xb5\xef\x14\xdc\xc2\xa2\x47\xd2\x11\x7e\x9c\xb4\x1e\xfa\x3f\xcc\xa2\x47\x16\x64\x14\x52\xbe\xed\x2f\x92\x65\x7c\x2f\xb7\x31\xf0\xb9\x4e\x8c\x89\x2a\x81\xbb\xa9\x1f\x63\x9d\xf4\x37\x96\xac\xd3\x01\x3a\xc0\x44\xf6\x08"}, -{{0x66,0x59,0x0d,0x36,0x99,0x84,0xc6,0xf5,0xad,0x3a,0x89,0xc7,0x8d,0xdf,0xca,0x10,0xa0,0xa7,0x65,0x79,0x95,0xdc,0x01,0x88,0xb6,0xb5,0x7a,0xc3,0x16,0x47,0x31,0xa4,},{0x98,0x87,0x3a,0xb1,0x33,0x46,0xee,0x48,0x67,0x7c,0x4f,0x86,0x12,0xdb,0x31,0xeb,0xd1,0x3d,0xb5,0x8b,0x2b,0x03,0x4f,0xd1,0x55,0xaf,0xa8,0x72,0x0f,0x4e,0x93,0xe8,},{0xf0,0xdb,0x63,0xa1,0xbc,0x76,0x24,0x16,0x1c,0xa0,0x06,0x38,0x53,0xb2,0xde,0xe4,0x5f,0xcc,0xd2,0x24,0x71,0xe0,0x12,0x36,0x6f,0x86,0x8a,0x4a,0x9c,0x74,0x65,0x4e,0x13,0xf1,0xa3,0x15,0xad,0x83,0x91,0x6e,0xbf,0xb8,0xdc,0x31,0xa4,0x20,0xf8,0x3c,0xf6,0x45,0xc4,0xc9,0xd1,0x6b,0xb4,0xd5,0xd9,0x9d,0x23,0xc7,0xb4,0x3e,0x23,0x00,},"\x2e\xc1\xc6\xb0\x82\x97\x37\x83\x2c\x9c\x79\x8a\x92\xeb\x49\x0b\x23\xd3\x34\xc3\xbb\xe6\x27\xcb\x58\x2d\x17\xa9\xe4\x29\x60\xef\xcd\xc7\xd3\x47\x50\xe0\xb4\xaa\x86\x4c\x20\x4f\xb8\xd6\x2b\x47\x99\x2e\x91\xdb\xfc\xfd\x69\xf5\x1d\x93\x7d\xc0\x6c\x48\xc0\xad\x43\xe8\x59\x83\x71\xcd\x0e\x3b\xbc\xe4\x16\xbf\xd4\x4b\x09\x44\xb9\x93\xaa\x29\x93\xfd\xea\x48\x71\x34\xcd\xe4\x22\x77\x72\x3e\x06\x83\xec\x98\xe6\x95\x95\xe9\xb7\xb1\x4c\x8c\xf9\x61\x7a\x1e\x30\xdd\xb8\x06\x0e\xac\xba\x48\xd8\x82\x53\xb1\x65\x33\x61\x08\xde\x0c\xb0\x2f\xf2\x0f\x54\x24\xb5\x67\x83\x08\x69\xc9\xb4\x32\x9c\x99\x45\xf0\xbf\x2f\x3c\x7a\xcd\x1e\x77\x43\x58\x93\x0c\xd8\x90\xfd\x9c\xb8\x64\xd9\x50\x93\x5a\xd8\xa4\xa3\xbe\xcc\xae\x8f\x83\x3f\x63\x56\x19\x13\x71\xc3\x26\x33\xdc\xf8\x82\x70\x9b\x0d\x98\xbd\x80\x7b\x38\x3a\xed\x8d\x7b\xb0\x97\xb6\xe2\x62\xef\x70\x0c\x9d\x76\x8f\x4b\x56\x90\xe3\xa1\xa8\xf2\x17\x55\xd6\x58\xdb\x2d\x1b\xfd\x2f\x70\x71\xe0\xca\xec\x7c\x2c\x53\x81\xc5\xef\x5c\x2c\x22\x81\xc6\xbc\xed\xc8\x67\x39\x0b\x90\xf3\xb2\x7b\x0f\x0f\x64\xa3\x36\x58\x57\x8a\x5c\x0d\x66\xe2\x11\xe6\xff\xf6\xe8\x64\x88\xac\xf8\x2b\xc0\xf5\xe2\x66\x4b\x83\x69\x90\x46\x03\x7c\x0d\x33\xd3\x40\xff\x98\xed\x62\x63\x35\x4c\x24\x27\x31\x36\xff\x0e\x4f\x0f\x23\x3a\x6c\x82\x54\xfc\x0c\x90\x76\x43\x30\xe3\xb1\x05\x7b\x1e\x66\x6d\x5e\xcd\x5a\x2e\xfe\xaa\x6a\x10\x5b\xfc\x85\x84\x31\xb8\x8e\xd7\xfe\x55\x1e\xb3\x2a\xc0\xaf\x27\xc6\x6a\x98\x03\xa3\xbc\xf8\x76\x34\xc6\x6c\x70\x66\xdd\x01\x97\xa3\xcb\xd2\xd6\xf4\xe6\x5c\xfd\xb8\xf3\xda\xf9\xf3\xca\x5c\x4f\x4e\x0a\xdd\x45\xf5\x54\x1a\xa1\x8d\x04\x1f\x70\x6e\x4f\xa8\x7c\x34\xe9\xa2\x23\xd8\x85\x72\xeb\x50\x08\x3e\xe8\xc7\xc4\x75\xdf\x56\x8b\xc7\x3b\xd0\x8c\x0f\x0d\xea\xa3\x74\xaf\xb1\xc1\x78\xd0\xdd\xdb\x23\x6e\x15\xa8\xbc\x23\x85\xed\x3f\x52\xb8\x76\x1e\x63\x78\x87\x40\x7a\x20\xae\xc3\xe9\x9e\xc8\x30\xda\xe3\x16\x7e\xf0\xcd\xb3\xf3\xff\xd2\x00\xd8\x3b\x75\xb7\x49\x69\x0b\x9e\x25\xe2\x17\x1d\x07\x2c\xa5\x6f\x71\xba\xec\xd2\x1f\x7d\x45\xa1\x2c\x91\xb2\xc0\xfb\x3f\xea\x3b\x15\x8e\x54\x64\x82\x84\xbb\x00\x95\xb3\x62\x44\xb0\xb1\x21\xf9\xf1\x38\x4c\xe9\x00\x43\x65\xe7\x77\x2f\xa3\x08\x28\x25\x0f\x51\x98\x5f\x1b\x17\xb2\xd2\xf8\x0a\x33\xe8\xfc\x6d\x85\x65\xea\x15\xcd\xaa\xcd\x42\xa8\x7b\xd7\xc9\x40\x8b\x1f\xe1\xc7\x70\x66\x5b\xdd\xed\x75\x4b\xc2\xff\x2e\xf9\x1b\x97\x3a\x86\xb9\x9f\x10\x59\xc6\xf2\x27\x24\x6a\x69\x8b\x38\x54\x15\x09\xdd\x54\x49\xfc\xe6\x0d\x38\x62\x24\x18\x3b\x7d\xce\x1b\x38\x84\xf7\xba\xe1\xc2\xe4\xeb\x59\x45\x10\xb5\xca\x58\x52\x79\xd9\x04\x1d\xf8\x81\x7b\x06\x19"}, -{{0x41,0xcf,0x07,0x1f,0x48,0x42,0xec,0xd4,0x94,0x19,0x1b,0x8c,0xf2,0x8c,0xc0,0x92,0x31,0x85,0xef,0x1b,0x07,0x45,0x8a,0x79,0xa5,0x9a,0x29,0x6d,0x35,0x49,0x82,0x2e,},{0x6d,0xc8,0xe4,0x46,0xdb,0x1d,0xa3,0x53,0xb5,0x8d,0x0c,0x45,0xd8,0xb4,0xd8,0x16,0xba,0x59,0xe2,0x5b,0xb6,0x80,0x71,0x2d,0x62,0xd6,0xd3,0xdb,0xf7,0x8d,0x06,0x98,},{0x41,0x05,0x2b,0xc4,0x17,0xb2,0x4d,0xc4,0x83,0x83,0x96,0x6a,0xf0,0x14,0x3f,0x9c,0x0b,0xa8,0x5b,0xbe,0xfb,0xda,0xf7,0x91,0xb1,0x6a,0x4d,0xad,0x1f,0x57,0x0e,0xb8,0x07,0x03,0xc0,0xa2,0xcd,0xeb,0x2f,0x7a,0xd6,0xdc,0xd3,0xfa,0x7b,0xdb,0x5c,0x22,0x5e,0x86,0x9c,0xd8,0xfb,0x27,0x8d,0xff,0x06,0x67,0xd3,0x8a,0xcc,0xf3,0xdb,0x08,},"\xda\xeb\x5f\x0e\x84\xf1\x59\x0b\xca\x2b\x9d\x97\x19\xef\x5d\x1c\xfa\x79\xe0\x58\x34\x46\x33\x2f\x18\xe9\xe4\xfe\xb0\xb1\xf1\x53\x40\x29\x7a\xc9\xad\x67\x24\xc8\x5b\xb1\x65\x58\xea\x54\xeb\x5d\x70\x2a\x47\x24\x8b\xad\xc6\x25\x2a\x80\x43\x71\xb7\x4c\xfe\x10\x62\xd1\xdb\xa1\xec\x68\xfd\x1d\x4d\xd0\x29\xcb\x55\x03\x4b\xbf\x61\x06\x82\x51\xef\xf3\x98\x36\x36\xf6\xde\xbd\x57\x27\xbe\x91\x99\x3b\x3e\x4d\x0a\xbc\x96\xec\x19\x64\x21\xa4\x7b\x78\x93\xf8\x39\x86\xd6\xc0\x32\x3f\x0d\x19\xaa\xf2\xcd\xe9\xd3\x56\x5c\x10\x4c\x9d\x31\x76\xec\xb5\xed\x5e\x17\x3f\xee\x52\xb5\xa0\xc4\x2b\x6a\xb2\xfc\xb1\xcc\xba\x96\x49\xc2\xc6\x7c\x52\x0e\x9b\x96\xce\xa6\x93\xdf\x3e\x58\x60\x9a\xd6\xa0\xbd\x52\x2e\xfa\xaf\x03\x85\x8d\x24\x5d\xd0\xa3\x8f\x84\xa2\xfb\x10\x20\xf4\xdd\x97\xc3\xae\xef\x0e\x24\x47\x7d\x30\xd2\x56\x70\x1e\x90\x0b\xef\x26\xa8\xa6\x26\x9a\xb6\x60\xd7\x42\x93\xa2\xbf\x1d\x20\xc2\xcf\xae\xbb\x7c\x28\x20\xf5\xf5\xb0\x74\x53\xbb\x69\xee\x76\x9b\x52\x39\x15\x39\xf0\xc6\x06\xd2\x2e\xb3\x92\x3e\xe6\xf5\xa1\xd4\x60\x50\xaf\x90\xf0\x11\xf8\x51\xac\xe7\x63\x27\xd3\xd1\x8c\x48\x17\x0a\x9a\x25\xb0\x4b\x77\x0f\xd9\x38\xef\x8a\x30\xb7\xbd\x03\x39\x1d\xd3\x6c\x51\x6b\x62\xf0\xcb\x78\x67\x07\x40\xe0\x0e\x69\x59\x5c\x41\x8d\x96\x72\x53\x82\x0b\x75\x4c\x4f\xd6\x66\xe3\xcc\xe1\x6e\xe0\xc9\x41\x83\xbb\xea\x70\x6f\xe2\x98\xe1\xc9\x9d\xdb\x82\x12\x17\xed\x90\x08\xcc\x8e\x8b\x83\xbc\x8b\x81\x99\x15\xb0\x7b\x14\x6f\xe7\x45\x02\x4a\xc3\xc4\x61\x16\xcb\x4c\xce\x5e\x32\xec\x5d\x75\x24\xa2\x38\x8d\x9f\xe2\x97\xeb\x02\x81\x1a\xf4\x54\x6f\xcd\x58\x60\xe1\x4c\x0d\x13\xf0\x3d\xd7\x5a\x42\x49\x61\x59\x00\x07\x8a\x3c\x35\x8c\x53\x42\x96\x2b\xc1\xbe\xac\xf6\x8c\x24\x68\x21\xa4\x59\xab\x53\x21\xec\x9f\x57\x4f\x49\xd1\x03\x89\xf4\x0f\x14\xdd\xfc\x85\x13\xff\xe3\xde\xaa\x73\x36\x03\x5a\x67\x5f\xa5\x85\x8b\x49\x0c\x5d\x24\x77\x80\x06\x4a\xdb\xaf\x75\xa7\x63\x35\xee\xc9\xab\x91\x87\x71\xb0\xb1\xdf\x51\x47\x64\x2a\xef\x4a\x16\x6a\xb1\x72\xed\x60\x1f\xed\x21\x0f\x6c\x0c\xff\xd9\x18\x69\xf7\x49\x0b\x57\xe7\xc6\x52\x41\x86\x3e\x7e\x8c\x0a\x26\xeb\xa6\x3b\x53\x42\xd0\xfd\x82\x14\xac\x73\x1e\x1c\x43\x8d\x01\x77\x11\x5f\x6a\x19\xe0\x93\x5c\x7a\xf6\xbc\x7d\xbe\xb7\x55\x11\xd9\xbd\x8e\x63\xe3\xe2\xf4\x7a\xb0\xdd\x1c\xed\xd7\xb1\x80\xd7\x4a\x4b\x44\xd4\x61\x19\x7a\xef\xdd\x36\x20\x46\x51\x66\xa3\x9b\x45\x39\x50\x43\xce\x88\x74\xcd\xd7\x2c\x60\x2b\xd3\xd2\xee\xcb\xad\x34\x66\xb5\xcb\x1a\xa4\x1a\xe9\x2a\x8a\xfe\xf2\xd7\x64\xce\xc0\xc4\x49\xd2\x7e\xfa\xc4\x37\x93\x8f\x28\x0b\xea\x9c\x50\xa5\x82\xe5\x7c\x27\xf9\xb3\xde\x87\x2f\x0c"}, -{{0xa2,0xc8,0xe1,0x61,0xa8,0xd9,0xd6,0xe8,0x88,0xc3,0xd0,0x9b,0x0b,0x97,0x27,0x37,0x30,0x7a,0x2c,0xbd,0x2a,0xcd,0x7c,0xcd,0x80,0x4d,0x24,0x31,0xac,0x6c,0x58,0xd2,},{0x3a,0x32,0x57,0x75,0x88,0x67,0x32,0xde,0xca,0x40,0x68,0x57,0xa8,0x05,0x60,0x10,0xaa,0xea,0x28,0x75,0x54,0x5b,0xa6,0xf3,0xdf,0x30,0x75,0x45,0x71,0x38,0x69,0x92,},{0x56,0x0d,0x01,0xb9,0x4d,0xf1,0x1d,0x83,0x34,0x77,0x52,0xff,0x51,0xb3,0x54,0x5e,0xf5,0x5c,0x56,0x32,0xae,0x7c,0x8e,0xfb,0x11,0xaa,0xdd,0x83,0x12,0xde,0xf7,0x25,0x62,0xe8,0xf5,0xd7,0x5e,0xce,0x10,0xad,0x46,0xbc,0x96,0xc8,0x60,0xde,0xec,0xe3,0x9e,0x63,0x4a,0x5f,0x50,0x65,0x4d,0x4c,0xdb,0xa8,0x4a,0x8e,0x6f,0x70,0x24,0x0a,},"\x83\xa3\xbe\xbc\xac\x5f\x28\xc5\x43\x3e\x3c\x4f\x1e\x7b\xf5\xd2\xe4\xdc\xd2\xf5\xe5\x9d\xbe\xe0\xa8\x3b\x07\x02\x57\x15\x35\x07\x46\xf8\x56\x75\xf1\xdf\xea\x37\x4a\xa7\xd7\x94\x28\x7b\x89\x2e\xf9\x09\x7f\xf6\xd2\xe1\x22\xf0\xa6\x56\xfb\xa0\x79\x8c\xdc\xfc\xb3\x64\x5d\xfc\xfd\x78\x8c\x74\x0c\x0f\xd0\x45\x20\xe7\xa0\x6a\x02\xa0\x58\x29\x63\x0a\x2b\xf0\xcd\xfe\x2e\xcc\xa0\x09\xec\x44\x04\x99\x46\xbb\x1d\x23\x26\xdd\xd6\x1d\x7e\xc6\x40\xbf\x69\xeb\x44\xfb\x23\xcc\x1f\xf4\x78\xc5\x70\xc7\x5d\xb7\xe7\x66\xe3\x5b\x7c\x43\xdb\x73\x68\x0d\x14\x07\xa9\x43\x99\xfb\x62\x1b\xaf\x38\x45\x74\x5c\x1c\x4e\xd0\xb9\xf0\xb4\x85\xbe\x2d\x53\xc5\x68\x54\x5d\xdf\x18\x77\x5a\x83\x7a\x05\xd9\xc9\x15\x7b\x08\x4e\x8c\xd0\x1f\xc3\x24\xf0\x7f\x11\x68\x77\xe4\x07\x5d\xba\x24\x32\xc8\xa7\x75\x2e\x9e\x93\x95\x86\xad\x93\xf0\xc0\xaa\x5e\xda\xc9\x4b\x8d\x82\xe5\x44\x99\x97\xb1\x5b\x8c\x89\x61\x58\x9c\x44\x28\x21\xaa\x83\xb6\x02\x39\xec\x5f\x15\x8c\x3f\x5e\x9e\xc5\xbe\xa5\x11\x5d\x5f\xed\x61\x91\x8e\x8f\xcd\x5b\xce\x61\xc7\x77\xf2\x0b\x6b\xfe\x80\x3a\x69\xc6\xfc\x79\x4a\xb8\xc5\x7d\xf2\x71\xda\x86\x38\x72\xa6\x13\x35\xb1\xfa\x29\xf4\x60\x8f\xf0\x37\xf7\x12\x06\x98\x09\xca\x64\x2a\x03\x07\xc7\x9a\xa9\x2e\x10\xcb\x89\x3a\x29\xd1\x72\x01\xa0\xb6\xd1\xb4\x6a\x72\x12\xb3\xba\xec\x97\x03\xc0\xb0\x39\x2b\xa6\xb7\x6e\x5c\x9c\x10\xf8\x35\x99\xb8\x1e\xa2\x22\x83\xf9\x54\x7a\xac\xda\xa7\xf3\x08\x96\xd1\xff\x73\x1e\x11\xfb\x9e\x56\xad\x06\x03\x04\x17\x11\x98\x05\xba\xb6\x35\x21\x49\x6c\x3b\xb9\x2a\x12\xf5\xe5\x5a\xfc\xf6\x0e\xd4\x21\x77\x37\xf3\x04\x6b\x16\xca\x50\x66\x57\xa6\xd6\x96\xd7\x5a\x6d\x8e\x18\xe9\xef\xe2\xb0\x8c\x8b\x1f\xa0\x72\x82\x38\xe2\x7c\xfb\x32\x21\x66\xee\xe4\xee\x76\x96\x8b\x77\x7b\x50\xee\x6a\x2b\x80\x4e\x1e\x9b\x46\x01\x66\x20\x13\x2b\x65\x88\x71\x8d\x97\x8c\xa2\xc0\x02\x69\x79\xc4\x00\xd3\xc5\x33\x67\x51\x21\x0f\x0b\x00\xd2\x69\xec\x8f\x4e\x2f\x95\x59\xe1\x80\x33\x2d\xd2\x70\xe5\x0c\xc9\x46\x5c\x55\x58\x93\x63\x55\x52\x1b\xc3\xc9\x56\x0f\xc1\x9e\xc1\x42\x42\x12\x1e\x6b\xb2\xff\xf8\xf5\x03\x37\xfc\x26\x4a\xcf\x1a\xc1\x70\x43\x28\x33\x4b\x3b\x52\xcb\xa9\x6d\x93\x03\xb1\xb5\xdb\x85\x9d\xae\x31\xd8\x0f\x17\x11\xfb\xa2\x51\xe1\x0b\x4d\x12\x21\x28\xf9\xfa\xff\x68\x72\xd0\xc0\xb8\x1e\xef\x59\x54\x1f\x83\x2b\x0a\x9d\xf3\xa4\xcd\xd5\x91\xc8\x77\x36\xb1\xae\xcf\x24\x2c\x27\x5a\x10\xc3\xfd\x67\x83\x9d\xad\x4e\xf3\x99\xb9\x49\x4e\xcd\x77\xf7\xba\x5b\x5d\x4f\x2c\xa3\x04\xe5\xb2\x29\x21\x30\x7c\xb1\x8f\xa6\x4a\xa3\xd0\x1c\x44\x11\xc8\x36\x9c\xce\xde\x46\x5e\xe3\x69\xee\x63\x7d\x43\xd2\x88\x26\xbf\x60\xdd\xde"}, -{{0xd3,0xd1,0x88,0xb3,0x90,0xba,0xcc,0xd9,0x50,0x24,0x52,0x61,0x46,0xb8,0x2b,0x91,0x84,0xe1,0x97,0xe4,0x6a,0x93,0x40,0xa0,0xe6,0xec,0x18,0xbf,0x75,0xbe,0x7f,0xc5,},{0xd8,0xf7,0x94,0x94,0x8a,0xa6,0x98,0x61,0x00,0x21,0x4e,0x9b,0x7b,0x90,0x24,0x42,0x08,0x06,0xb4,0xc6,0x78,0x46,0xd5,0xbd,0x50,0x61,0x13,0xb3,0x53,0xa2,0xea,0x3d,},{0x16,0x97,0x6b,0x26,0x7d,0xe9,0x6e,0x38,0xdd,0xdc,0x84,0x78,0x07,0x5f,0x6b,0xdd,0x71,0x59,0xe5,0x63,0x34,0xb2,0xd2,0xd1,0x92,0x09,0x46,0x29,0x4f,0x33,0xcd,0x6b,0x7f,0x9c,0x50,0xf8,0x05,0x7f,0x49,0x6c,0xab,0x5d,0x94,0xbb,0x4d,0xca,0x26,0x2f,0x9f,0x0f,0xdf,0x9b,0x1b,0x64,0x74,0x1f,0x4b,0x72,0x2d,0x32,0xef,0xa8,0x22,0x03,},"\x5e\x65\x65\x8e\x42\x03\x75\x43\x3f\xd7\xc1\xf6\xbe\x67\x88\x41\xe5\x81\x04\xf1\x0b\x4c\x67\x63\x59\xd8\x4f\xce\x79\x92\xf5\xc5\x75\x57\xd7\x38\xf8\x30\xb5\x05\xfa\x0c\x2b\x9e\xab\xf8\xd1\xa9\xf8\x1f\xe8\xf3\x15\xd6\x62\xe2\xb8\x4c\xe9\x52\x99\xeb\xf4\xe5\x03\xb5\xe1\xf7\xf8\xcd\xb6\x68\xae\x73\x3f\x3d\x0c\xdd\x4c\x74\x2a\xb5\xf2\x72\xbe\xa4\xf1\x8d\x18\x3e\x89\x23\x84\x76\x62\xf9\xa3\x9c\xd4\xb1\x4e\xc7\x6d\x11\x03\x2f\xe5\x73\xc2\x62\x01\xae\xf6\x66\x01\xce\xc6\x83\xe3\x4b\x89\xaf\xd9\x64\xe9\x87\x80\x1c\x70\x6a\x85\xe2\x7b\xab\x33\x70\x1c\xd1\x09\xbc\xf0\x7b\x27\xca\x67\xf0\x22\xc4\x94\xa0\x4c\xbe\x5a\x9c\x6d\x63\xaa\xd9\x36\xcd\xf1\xa1\x80\xfd\x05\x86\x51\x98\xb9\x6f\x06\xa7\x8d\xa9\x57\x99\xd3\xaa\x4d\xf3\xb1\x70\x03\x3c\x69\xe8\xfb\x04\x28\x8c\x35\x46\x55\x3b\x57\x9c\x0a\xe3\x93\x80\x62\xd3\xd8\x42\x1c\xfa\x66\x26\x85\x29\xbe\xc0\x27\x1e\x53\xb4\xee\x7d\x09\x9e\x71\x48\xa8\x02\xdf\x80\xfe\x5e\xed\xee\x1c\x90\x3a\xe8\xed\x4d\x64\x0e\xad\x76\x12\x62\xdd\x40\x14\xf2\x5f\x93\x97\xba\x3f\x1c\x08\xd8\x3a\x3c\x48\x5c\xfb\x55\xf8\x99\x19\xaa\x97\x2d\x6b\x7e\x77\x11\xbe\x9e\x30\xc1\xeb\x96\xa0\xc3\x84\x53\x09\xfb\x23\xdb\xc7\x5b\x69\x91\xdd\x6e\x48\xcd\xde\x90\xe0\x4f\x22\x8e\x8c\xcf\x3b\xa2\x3f\x27\x47\xcf\xb9\xd3\x38\x1a\x93\x05\xf8\x16\xf2\x6c\xdd\xe4\x1c\x02\x20\xfa\xd2\x28\xff\x6a\x8b\x09\x5c\x77\xb6\xba\xe8\xfa\x33\x68\x14\x27\x24\xbf\x1f\x5e\x0f\x6f\xbc\xa5\x32\x0c\x21\x5b\x6b\xa8\x6b\x91\xe3\xa8\xac\xf7\x50\xe9\x3f\xa7\xea\xa6\x5c\x4f\x78\x5e\xf8\x42\x1a\x19\xc1\xe2\x7b\xc2\x4b\x42\x8e\x08\xa9\x02\x42\xab\xac\x9b\xd4\xaa\x03\xc6\x56\xf8\xf4\x6d\xc4\x0b\x36\x15\x2c\x1b\xd0\xde\xf1\xac\xfc\x0d\xa1\x0a\x2f\xa1\xdc\x3d\xa7\xac\xe5\xa8\xfd\x76\x22\x7b\xb1\xa6\x02\x39\x0f\xe5\x7a\xfd\x32\xef\xe2\x81\xf2\xea\x6b\x2e\x4d\x25\x45\xcb\x88\xd2\x30\x8d\x72\x69\x1c\x9a\x52\xb4\xca\x25\x23\x1a\x01\x07\xf2\x5d\x11\x7c\xc9\x35\x39\x76\x21\xc6\x83\xbd\xc8\xf2\x2e\x81\x03\x40\xf2\xcb\xac\x4c\xea\xa3\x46\x86\x65\x26\x18\x79\xf0\x07\x42\x00\x74\x3e\x0d\xe5\xf3\xe5\x83\x08\xb9\x8b\x04\xb8\xc7\x14\x8a\x4e\x00\x4e\x66\x7e\x83\x2b\x00\x84\xb5\xf2\xbd\xc6\xfd\xc9\x59\xf2\xfc\x28\xa8\xd3\x1d\x9a\x9e\x78\xe5\xd5\xf9\xc0\xb1\x19\xe5\xff\x1f\x68\xf7\xc0\xda\xf0\xc0\xf1\x69\x47\xcc\xa5\xb7\xce\xd0\x96\x01\xe2\xeb\xed\x28\x2e\xf2\xbf\x8f\xe9\xa2\x7e\xd2\x7f\xc5\xbc\xda\x8a\xed\x6c\x71\xbe\xe3\xe7\x75\x10\x04\x47\x26\x89\xbb\xf6\xd9\xd0\x79\x52\xa2\x42\xff\x87\x0d\x7c\x3f\x5e\x1f\xfc\x2c\x1f\x40\xfc\x9a\xb7\x57\x9b\x39\x2b\x55\x4f\x3d\xc5\x88\xc0\x3a\xb9\x57\x43\x1f\xe5\xd0\x2c\xbc\x71\x1a\xd4\x89\xfe"}, -{{0x61,0x91,0x7a,0x97,0x5c,0xb7,0xec,0x56,0x4c,0x70,0x8a,0x56,0x53,0x88,0xc5,0x72,0x36,0xa6,0x6b,0x69,0x7d,0xcd,0x5a,0x7f,0x10,0xba,0xe6,0x71,0x57,0x2a,0xc7,0xf0,},{0xec,0xc0,0xf0,0xb9,0x92,0x76,0xe5,0x28,0xf8,0x2b,0x42,0xf2,0xef,0xce,0x85,0x79,0xf8,0x3e,0x63,0x8c,0x6a,0xce,0xfd,0x07,0x28,0x28,0xc0,0x4e,0x43,0x4f,0x55,0xaf,},{0x6a,0xbb,0x3e,0x37,0x7b,0x5c,0x80,0xb7,0x4f,0x77,0x21,0x9c,0x1a,0x9e,0x09,0x6f,0xba,0x0e,0xb6,0x89,0x90,0x81,0x7a,0xcf,0xf1,0x2d,0xba,0x7f,0x61,0xc7,0x7c,0xcf,0x59,0x5f,0xb6,0x60,0x85,0x52,0x00,0x3c,0xea,0xd0,0x6c,0xa1,0x31,0x7c,0x9c,0xd5,0x1a,0xc4,0x72,0x4b,0x29,0xf4,0x09,0x21,0xfb,0x92,0x84,0x33,0x76,0x87,0x64,0x01,},"\x6e\x97\x0e\x0b\x1c\x92\xa7\xf4\x96\xa8\x2d\x8a\xe8\x0c\xfd\x0c\xce\xf1\xd2\xc7\x99\xd4\x17\x28\xf3\x5d\xdc\xd6\x03\xb4\x21\xc2\xa5\xab\x3b\x48\x9e\x78\xf4\xb6\x22\x97\xde\x43\x7c\x5a\xd1\xa9\x68\x3f\xf8\x7f\xa2\x8e\xb3\xcc\x38\xce\x24\x2a\xf5\x94\x19\xf9\xfd\x43\xfc\xaa\x54\xfc\x39\x89\x92\xf8\xc8\xe3\x1f\x2b\x33\xdc\xcc\xd0\xee\x11\xba\x7b\x38\x8e\x8d\x2a\x36\xea\xd0\x67\xc6\xbe\xce\xd5\x89\x0a\xb7\xd4\xa9\x4f\x55\xda\xb9\x21\x28\xa0\xf8\x14\xc0\xe6\x89\x71\xdf\x57\xbd\x50\x78\xa7\x40\x31\x75\xc7\xc2\xfd\xd4\xa5\x24\x47\x15\x3a\xb3\x74\x56\x72\x9a\xee\x33\xe5\xfc\x93\xdb\x8e\x7f\x48\x03\x09\x87\x5e\xcf\x6d\xb0\x7c\xe7\xf3\xca\xc5\xde\x49\xe3\x61\x27\x5c\xa5\x0b\x6b\x71\x9f\x4b\x71\x5b\x3e\x30\x86\x3c\xbb\x3b\x71\x64\xba\x9e\xb9\x6e\xf3\x30\x4b\x19\xad\x4d\x74\xdc\xe4\xbd\x25\xe7\x7b\xbb\xbe\xff\x1e\xe7\xd1\xfb\x55\xb9\xc4\xf7\xfc\x4c\xd9\xbd\x55\x10\x8a\xfc\xf9\x9c\x1a\x41\xcd\x6f\x6b\x1a\xdb\x29\x7b\x10\x6c\x8b\xa2\x4e\x31\x34\xf8\x7d\xd8\xef\xe5\xcf\x85\x49\x22\x91\xb9\x4d\x66\x00\x95\x8c\x28\xb9\x12\x2f\xe6\xe0\x1b\xd3\xe3\x29\xe4\x2d\x19\x26\xb8\x9f\x7a\x8c\x40\xa4\x98\x67\xe5\xaa\x3a\xd7\x49\xbd\x98\xda\xe7\xd0\x06\xb4\x53\x60\x9e\x7d\xae\x26\x36\x4d\x91\x72\xbe\x72\x83\x33\x01\x21\xed\x2b\x40\x27\xe0\x88\x51\x18\x74\x3a\x6e\xa0\xcb\x7d\xc2\x74\x09\xa9\xb2\x82\x0b\xcc\x24\x2e\xa1\x0a\x00\x93\x7b\xf8\x49\x20\x1e\x0f\xb6\x19\x94\x21\xf1\x63\xe9\x79\x4f\x2d\xd4\xb3\x32\x01\x4a\x09\xd3\xee\x80\x71\xda\x78\x77\x47\xf9\x90\xf5\x17\x99\x19\x02\x7d\xdf\xf7\xca\xb0\xf5\x5e\x9a\xfa\x8e\xcc\xb1\x6c\xc2\xdd\x3c\xbb\xea\xd7\xff\x7e\xc8\x18\xc2\x53\x39\x3f\x74\x87\x41\xf5\x54\x07\xf7\x40\x8e\xe3\x3a\x42\xae\x2d\x6e\xcb\x3f\xb6\x00\xa7\x1f\x30\xab\x63\x06\x06\xe5\x53\xb4\x36\x78\xe5\x98\x54\xf3\xa2\x94\x7b\xcf\x4e\xa0\xfc\xfe\xdc\x31\x4d\x83\x70\xd1\x26\x63\x95\xfd\xa3\xc9\x10\x5e\x97\x59\x52\xf6\x0e\x30\x86\xbb\x82\x48\x15\x13\xd6\xfe\x8a\xdb\x4f\x95\xef\xb9\xa9\x5b\x66\xd4\x80\xd2\xbb\x17\x10\x78\xcf\x40\x68\x4a\xc6\x9a\x78\x9c\x7f\xb7\xfa\x42\x53\x33\xd7\x05\xdb\x00\x06\x67\x55\xdf\x72\x8d\xe0\x2d\xf2\x5b\xae\x34\xf1\xd7\xd4\x9c\xaf\xfc\x51\xe9\xba\x2b\x10\xb9\x8f\xe4\xcd\x9d\x22\xb7\x76\x4e\xd9\x31\xed\xb5\xf0\xb5\x54\x49\x6e\x99\x53\x91\xe0\xaf\x0b\x8d\x1c\x7a\x82\x95\xa8\xd1\x5a\x7c\x65\x56\xd2\x9c\xb1\x9e\x08\x55\xca\x50\x5a\xd0\x1d\x2a\xa3\x09\x28\xa8\x4b\xc4\x89\x59\x57\x6d\x81\x2d\x9b\x27\xb8\xe8\x88\x79\xfa\xa2\x80\x6c\x08\x41\x36\x0e\xcd\x0f\xe8\x3f\x5b\x84\x8f\xc1\x2f\x65\x8f\x1e\x7f\x40\xe5\x61\xc2\xe7\x8d\x3b\x01\x25\x21\x0a\x92\x06\x1c\x2d\xb2\x1b\xa6\x60\xe8\x60\x8f\xf5"}, -{{0x7b,0xa2,0x5f,0x27,0x97,0xa2,0x83,0x6f,0x37,0x9d,0x6b,0xbc,0xbe,0x9a,0xbf,0x4f,0x2d,0xef,0x5e,0x52,0xf7,0x2b,0xd9,0xe0,0xb0,0x06,0x57,0x10,0x22,0xfa,0xc2,0xf3,},{0x6c,0x2e,0xd4,0xe8,0xc0,0x12,0x4d,0x5d,0x05,0x40,0x79,0x6d,0x39,0x45,0xd1,0xde,0x71,0xaa,0x69,0x69,0xe6,0xab,0xea,0x0f,0x1b,0x0e,0x6f,0xc4,0x29,0xc7,0x04,0x6f,},{0xf1,0xf5,0x90,0xa9,0x07,0xba,0x98,0x0e,0xb0,0xd6,0x48,0xab,0x4d,0xed,0x5f,0x92,0xfa,0xf7,0xcb,0x85,0x1d,0x81,0xd8,0x58,0xa7,0x8f,0xa6,0xb7,0x7c,0xbb,0xe1,0x2f,0x64,0xd2,0x0d,0xf5,0x27,0x71,0xa7,0xd5,0xe5,0x39,0xa1,0x52,0xd7,0x31,0xe1,0x90,0x3d,0x42,0x11,0xfd,0xcf,0xef,0x9a,0x48,0xb4,0x6c,0x8f,0xd5,0x39,0x4c,0xa0,0x09,},"\x17\x1a\x34\x09\x87\x80\x97\xb3\xb2\x2b\x2c\x00\x66\x0b\x46\xe5\x42\xc2\x16\x4c\x00\xbb\xee\x54\x55\x48\x37\x94\x0e\x70\xf0\x3d\xa9\x91\x6a\x40\xf9\xbd\xe8\x28\x8f\x45\xe4\x7b\xef\x7f\xfe\x4e\x55\x7c\xd4\x47\x40\x45\xe7\x40\xfd\x95\x9d\x98\x4f\x4e\xc8\x1d\xa8\x8d\x44\xa3\x73\xc1\xed\xa0\xcf\xc6\xb0\x8e\x35\x13\x73\xd3\xb8\x2a\xb0\x90\x2d\xf8\x06\x3f\xd9\x08\xe7\x03\xe0\xcb\xec\x41\x0a\xb5\xcd\xfe\xaa\xe0\x01\x88\xce\x2a\xd4\x2b\x8b\xf0\x4f\x7d\xaa\x5f\x0e\xe3\x33\xa6\xf9\x31\x1b\x4a\xd9\x81\x09\x52\xd5\xd5\xa6\x4b\x20\xf3\x7e\x84\x54\x15\xfc\x3c\xdd\x61\x6f\xeb\xec\x50\xdb\x29\x6f\xb3\xf3\xbb\x7f\x6b\x36\x6b\xbe\x52\xe4\x89\x7a\x05\x61\x7b\xf7\xc9\x81\xa6\x2e\xdc\xbb\xbe\x5d\xa4\xc3\x9c\xaf\xa8\x69\xaa\x2b\x27\x34\xe6\xcf\xed\x90\xed\x8b\xe7\x59\x49\x39\x0e\xe4\x45\x66\x89\x24\x55\xb8\x90\xcf\x56\x8b\x94\x5a\xab\xb7\x58\xd3\x85\x4b\xe6\x53\x9f\x3b\x86\xbf\x01\xd1\x88\xe4\x8c\xf2\x62\x6a\x0d\x7d\x38\x17\x03\xbe\x6e\xd1\x29\x0d\xfb\x94\x7b\xc2\xe0\xf8\x3d\xbc\x58\x70\x30\x80\xd7\xf5\xb9\xef\x19\xae\xf9\x30\x90\x8f\x68\xf0\xc8\x00\x10\xa9\x40\x1b\x30\x3a\x9f\x6d\xa8\x05\xbb\x8a\x0e\xd0\xf3\x94\x13\xee\xfe\xdf\x91\x9f\xfd\x8e\xa6\x39\x1b\xf9\x5d\x42\x29\x60\x4e\x49\x45\x7b\x8e\x23\xbe\xc6\x11\x48\x4c\xc7\xf9\x83\x2d\xd9\x5b\xdc\x3a\xd1\x77\xc0\x50\xf4\xab\x63\x3d\xcd\xb3\xe6\x91\xf5\x90\x28\x73\xb3\x8c\xb0\x72\x0b\x91\x13\x35\x7f\xe0\xcf\xb9\x8a\x68\xcc\xcb\x5d\x5f\x08\x09\xd5\x9a\x37\x5c\xf7\xb5\xa2\x75\xd4\x3c\x4c\x34\xff\x68\xe4\x48\x52\x6e\x8e\x1a\xad\x44\xe2\x00\x08\xa2\x32\xaf\xbc\xf5\x32\xa4\x2b\x50\xa0\x25\xa1\xb2\xee\x4e\x07\x7e\xb0\x12\x5a\x59\x3d\x51\xa2\x00\xec\x20\xd8\x72\xc0\x58\x38\xad\x36\xaa\xae\xec\xcc\x3e\xd9\xef\x41\xf6\xd1\x22\x67\x02\x17\xd5\xc0\x8f\x6e\x13\xc1\x72\x19\x45\x89\xac\xc3\xc5\x9f\x7e\xf7\x90\xc7\xc8\x5a\xa6\xd5\xeb\x69\xd4\xc8\x9a\x72\xf5\xe7\xc9\x24\x69\x85\xc1\xac\x0c\x5d\x19\x7f\x76\xa7\x3e\x37\x74\x83\x9d\x4a\xa2\x09\x6a\xca\x19\x0a\x30\xf4\xaa\xc5\x40\x57\xb6\x4f\x35\x8e\x0e\x06\x40\x0c\x0d\xf2\xf8\x76\x41\x2d\x34\x48\x4c\x43\x44\xf4\xd7\xc8\x66\x51\x7d\x3e\xfb\xa4\xa9\x0f\xa7\x14\x4c\x9b\xa5\xdb\x33\x61\xdb\x57\x69\x40\x3e\xc8\x16\x26\xa5\x11\xf9\x3e\x30\xf8\x58\x6e\xad\xfc\xaf\xd9\xa3\x6e\xcf\xf8\xd2\x4b\x42\x07\x9a\xda\x8e\x57\x9a\xc3\x08\x51\x17\x7b\xce\x90\x38\xb0\xe1\x30\x00\x72\xd6\x8e\xfd\xd7\x23\xf6\x35\x50\x64\x84\x32\x75\x81\x5a\x66\xb9\xd7\x3a\x12\x99\xaa\x59\xa1\x81\x2f\x64\x52\xfb\x41\x15\xea\x2b\x1f\x9f\xf4\xa9\x96\x90\x59\x6e\x3f\x20\x22\xd8\x1e\xd8\x74\xdd\x67\xe6\x18\x9c\xa0\xe6\x8b\x93\x04\xe9\x93\xa9\x5b\x66\x66\x5e\x0d\x07\x4c"}, -{{0xd1,0xe1,0xb2,0x2d,0xe5,0xe0,0x4c,0x9b,0xe4,0x65,0x1d,0xd7,0x39,0x95,0xa3,0x66,0x6c,0xb5,0x35,0x2c,0x65,0xac,0x7b,0x70,0x51,0xb3,0x66,0xfe,0x1a,0xc0,0xc3,0x10,},{0x12,0xfe,0x56,0xf1,0x01,0x2d,0x5c,0x12,0xf1,0x35,0xed,0x59,0x82,0xf3,0x82,0xae,0x5f,0x11,0x43,0xbc,0x90,0xe8,0xcb,0x8c,0x93,0x05,0x17,0x54,0x55,0x1e,0xe9,0x0a,},{0xab,0xaa,0xb4,0xfa,0x6a,0xeb,0x0a,0x0b,0x34,0xee,0x0d,0x61,0x3a,0x0a,0xf0,0x49,0xed,0xb4,0xce,0xdb,0xfe,0x9d,0x3b,0xeb,0xe9,0xc0,0x06,0x18,0xb1,0x15,0xb9,0xd1,0xfa,0x52,0x4e,0xc3,0x49,0x5e,0x13,0x30,0xb0,0x93,0x61,0x81,0xea,0xbb,0x14,0x29,0x9f,0xac,0xcc,0x40,0xea,0xa8,0xcc,0xa5,0x7e,0xd3,0x24,0xb7,0xa6,0x42,0x0c,0x0e,},"\xc7\xf2\x18\xb5\xaa\x7a\xae\x17\x99\x62\x5a\x56\xc4\xd7\xd7\xb0\x26\x37\xe5\x72\xf1\x41\x1a\x61\x22\xf1\x13\x79\x1a\xa3\xc6\x28\xe8\x19\x60\x2f\xb4\xf0\x33\x5a\x61\x23\x01\x3f\xa6\x4e\x9f\xdc\x4e\x4a\xe4\x97\xbd\x16\x9c\x2f\xa7\x7b\xc2\x36\x12\x97\x17\xf4\x62\x88\x6b\x41\x08\x93\xfa\x78\x09\xcb\xfd\xc8\x92\x22\x3b\x40\xee\x04\x1e\xbd\x4e\xc7\xdd\xab\x55\xbe\x60\x81\xa1\x64\x66\x43\xa9\x12\x0b\xaa\x46\x28\x9a\xcb\xa1\x5b\x3b\x48\xaf\x3b\x7a\xde\xcd\x69\xf4\x3e\xed\xe7\x9d\x9b\x19\x57\xe1\xd8\xc3\x12\x9e\x0f\xa0\x57\x9d\x3d\x39\x53\x70\x46\x1b\x0e\x12\x55\xc9\xca\xa9\x4e\x47\x25\x60\x1c\xb9\xd0\xe2\xd6\x02\x44\xd1\x5b\x64\xe1\xf7\xbc\x90\x15\x59\x0a\xd0\x99\x1f\x12\xf8\x26\x73\x11\x20\x6e\x9e\xb5\xd1\x6a\xdd\x0b\xa5\x21\x8f\xce\x5f\xff\xe1\xc9\xce\x5f\xfe\x1f\x73\x11\x32\xf4\xb1\x2c\xac\xb0\x2f\x97\x45\x17\x10\x84\x6b\x7f\x82\x4f\x4f\xa9\xe0\x89\x19\x26\x64\x69\x78\x9c\x00\xce\x0d\x94\xd3\x8f\xa8\xfe\xc3\xf5\x1f\x2f\x88\x6e\x9d\xb0\x9b\x80\x44\x70\xb1\x9e\xc9\xe8\x06\x63\xf1\x55\xb4\x98\x4d\x2b\xbd\x0b\x2c\xe9\x93\x02\xe0\x6c\x64\x44\x4b\x69\x6e\x31\x29\xfc\xef\x34\xc3\xdd\x00\xf7\xab\x5b\xed\xa7\x47\xa3\xfc\x63\x39\x19\x2b\x74\x0f\x35\x69\xb6\x7d\xbd\x6f\xfa\x39\xe2\x71\xfa\xa4\x00\xd9\x61\x6b\xff\x86\xec\x49\xa6\x59\xde\xf2\xe7\xf5\xd4\x51\xf2\xa2\xb3\x5e\x66\x2a\x6e\x7c\xc2\x2f\x1e\x5c\xdc\xde\x8a\x59\x98\x81\x35\xb7\xe7\x65\x62\x74\x3c\x1e\x6a\x09\x99\x01\xb3\xef\x97\xcb\xff\x23\xf2\x09\xbd\x70\x88\xc2\xf0\x32\x45\x27\x9a\x1d\xc7\x8d\xdd\xc1\xbb\x0c\x1d\x35\x10\x03\x57\x88\x21\x26\xb3\x28\xd3\xd9\x4e\x08\x71\xb6\x0b\xe2\x53\xfd\x1b\x6e\xcf\x03\xc1\xdb\x73\x1d\x9e\xed\x0e\xdf\x2b\x26\x43\x23\x07\x80\xa4\xd6\x6e\x99\x17\x9a\xad\x1b\x82\x40\x2e\x55\xf6\xd7\x85\xeb\xc8\x0f\x8d\xd2\xfd\x2b\xeb\x09\xf3\x10\x35\xdf\x62\xc1\x7f\x42\x8e\xd0\xb2\xd5\x65\x08\xdb\x31\xe6\xd2\xdd\x5f\xb6\x9e\xbe\xee\xa3\x25\x70\x70\xcf\x2f\xe6\x7d\x42\xd2\x88\x16\xa5\x5d\xba\xe0\xb1\x85\xdb\x44\x21\xbb\xfd\xae\xfc\x79\xc0\x8c\xdc\x1a\xcc\xf7\x16\x42\x56\x2e\xc7\x00\x36\xda\x2b\xba\xfa\x4a\x89\x19\x54\xc4\xee\x40\x49\xb5\x5c\x64\x0e\x91\x93\x0e\x39\xe3\xef\x10\x18\xdc\x16\x47\xf2\x69\x42\xc6\xdb\xdf\x4d\x56\xe4\x1e\xb2\xc8\x98\xc8\x21\xfa\xc1\x7c\xc2\x73\xe8\xe4\xaa\x56\x08\xa8\x12\xcf\x4b\x82\xf9\x60\x19\xc2\x52\xd5\x6e\x78\x05\x29\x8c\xcb\xe8\xce\x40\xb0\xbd\x0f\x93\x3b\x88\x4c\x0f\xaf\x97\xa9\x58\xb2\x04\x08\xb8\xa5\x29\x7c\xce\x55\x27\xb2\xca\x21\x28\x06\xe7\x2a\x32\x64\x45\x7a\x7f\xac\x86\x62\xb8\x2c\xa2\x33\xe1\xc7\x75\x8d\xc6\xe4\xf1\xb9\x99\x58\x63\xf2\x5f\x74\x7b\xce\xe4\x3b\x63\x9b\x1f\x8f\x20\x26\xd2\xd2"}, -{{0xdf,0x29,0x4e,0x47,0x7b,0x1b,0x91,0xc5,0xac,0x5b,0x98,0xc3,0x30,0xd2,0x22,0xd7,0xcd,0x2d,0x53,0xe7,0xd0,0xbc,0x0c,0xa4,0x03,0xdf,0x4e,0xc7,0x53,0x27,0xa2,0x74,},{0x5f,0x0b,0xd2,0x2f,0x2f,0x18,0x96,0xd1,0x56,0x3b,0x4f,0x69,0x40,0xc7,0xdf,0x89,0xef,0xc2,0x58,0xc0,0xff,0x6c,0x2f,0xcd,0x67,0x4d,0xaf,0x4f,0x59,0xfc,0xdb,0x60,},{0x99,0x45,0xab,0x73,0xb5,0x85,0x62,0xb3,0x55,0xda,0xbc,0x4e,0x2b,0x6b,0xe7,0xe0,0x5f,0x37,0xf8,0x95,0x71,0x44,0x0c,0xcc,0x32,0xc1,0xa9,0x47,0x37,0x09,0x5b,0x78,0x66,0x74,0x7d,0x21,0x00,0x70,0x00,0xa0,0xf0,0xe3,0x51,0x11,0x4b,0x88,0xe0,0x13,0x8b,0x55,0xdf,0x44,0xfe,0x72,0xeb,0xe9,0x59,0x14,0x10,0xe7,0x07,0xfa,0x9d,0x02,},"\x3e\x42\xd6\x68\x40\x96\x30\xcb\xb8\x48\x12\xac\x7f\xf1\x15\x4f\x70\xfc\xa8\xbd\xff\x3f\x1a\x04\x0f\xa3\xaf\x86\x8a\xa1\xc4\xe9\x15\x08\xb1\xae\xfd\xf5\xc3\xa8\xb4\xb0\x77\xa4\xd1\x62\xd2\xc0\x5b\xd3\x64\xfb\xbe\x8c\x5a\x08\x31\x4c\x2e\x07\xdf\xfb\xd6\xe8\xdd\x2e\x08\xa0\xdc\xc9\x6e\xa9\x2d\xdd\x4c\x97\xf7\x9d\xb9\x42\x5a\x6c\x6b\x34\xc4\x60\x43\xd0\x9a\x68\xb7\x68\x72\x36\xa9\x18\xd2\x1a\x56\x16\x10\xa1\x3a\xc5\xe4\x46\xe0\x88\x1b\xb2\x6c\xc8\xe2\x8a\xad\x16\x54\xf8\x67\xad\x82\xae\x33\xf8\xf7\xa7\x8a\x65\xbe\x57\x69\x94\x75\x51\x6a\x1a\x87\x46\x84\x3e\x93\xa1\xa2\x94\x35\x46\x24\xfa\xc0\x4d\x45\x2c\xcf\xbe\x4f\xdd\x92\xa9\x51\xaa\xa0\x7d\x26\x67\x6d\x5c\xb0\x77\xa5\x00\x0d\x43\x9c\x12\x42\x76\xc0\xdb\xcf\x86\xe7\xaa\x15\x3c\xc2\x4b\x5a\xff\x67\x7c\x6b\xad\xc2\x61\xc2\x89\xf4\xa4\xae\x51\x9b\x2e\x2f\xff\x31\x2f\xbf\x0f\x5b\x4c\x46\x98\xf6\xae\xdd\x8f\xcb\x1d\x23\x48\x94\x2d\xe3\xfb\x73\xba\x27\xf6\xdb\x14\xc2\xf0\x91\x80\x35\x6e\x5f\xca\xe1\xad\xf6\x5e\x22\x42\x5f\x8c\x27\xf1\x9e\x98\x94\x83\x50\x6e\x5d\xf5\x7a\x1b\x61\x3a\x22\xe3\x45\x03\x8b\x3e\xa9\x1c\x0f\x78\xff\xff\x46\x38\x3f\x38\xc7\x22\x25\x35\x8a\x34\x57\x0d\x6f\x66\x4a\x17\x45\x4a\x15\x16\x13\xf0\x1c\xba\x77\x7f\x62\xec\x83\x18\x75\xec\x5e\x27\xd2\x57\xf1\x80\xb6\x36\x6c\xb1\x83\x10\x7c\x40\xf5\x0b\x01\xb2\xb9\xbf\x91\xb3\xb5\x54\x9e\xd9\x31\xa3\x53\x7a\xa4\x16\x89\xf7\x2b\x25\x7a\x6a\xa3\x9c\xdc\x6f\xce\xdf\x14\x39\x83\xbe\x5b\xff\xe3\xae\x2b\x29\xf8\x2f\x88\x21\x22\xd6\x6a\x79\x25\xf5\xa7\x10\x82\x6c\x0d\xad\xb7\xe4\xfa\x4e\xc0\x79\xba\x2e\x76\xda\xda\x43\x3f\x30\x77\xcb\x1e\xf7\x46\x13\xfc\x5d\xbf\x82\x58\xb6\xda\x7c\x73\xc8\x66\x37\x24\x57\xed\x50\x0f\x97\xf9\x90\x7e\x1f\xc2\x63\x53\xc7\x0b\xa3\xbd\x9c\x36\x15\x1d\x46\x86\x5d\x2c\x65\x98\x65\x62\x48\x5c\xf8\x42\x1f\xeb\xbe\x77\x7c\x73\xe6\xcd\x00\x26\xd6\x6d\x35\x12\x8b\x9f\x8f\x33\x26\x4a\xeb\x56\xbd\x3e\x4b\x8d\x1f\x52\x66\x41\x1e\xf3\xb2\x3b\x76\xb3\x6d\x4c\x9d\xf3\xc5\x12\xfd\x56\x0c\x2b\xe5\x2a\xc5\x23\xc1\x93\x77\xad\x2a\xdc\x0e\x8c\x30\x9c\xf5\xbb\xf7\x2d\x9e\xb8\x5d\x65\xa9\x48\x47\xd4\x97\xd8\xd1\x02\x42\x4f\xb8\x43\x81\x66\x6e\xcb\x1c\x35\xa3\x72\x5d\x7d\x9e\x92\x84\xfd\xeb\xb6\xb3\x62\xaa\x6a\x9c\x6f\xb3\x7a\xba\x87\x35\x7f\x57\x4c\x0e\x63\xb4\x49\x7d\x49\x8f\xfb\xb7\xd0\x69\x2d\x78\x4b\x4b\x18\xce\x9f\x91\x50\xc1\x46\xd3\xd1\x8c\x38\x2e\xda\x04\x93\x8c\x69\xd0\x77\x8f\x29\x02\xd5\x23\x5a\x56\x52\xb9\x7c\xef\x6d\x5f\x60\xda\x6b\xd7\xed\x4f\xf9\x7c\xd9\x4d\x49\x39\xca\xca\x3b\x6b\xaa\x3c\xfd\xac\x04\xcd\xa9\x55\x96\xf4\x67\xcb\xc6\xcb\xcd\x92\x64\x16\x77\x43\xea\xc1"}, -{{0x70,0xc6,0x85,0x9f,0x08,0xcf,0x42,0xb4,0xbd,0xa9,0xeb,0x62,0x97,0x9d,0xff,0xb7,0xcb,0x08,0xeb,0x3d,0xab,0xe9,0x3f,0xe9,0x4b,0x01,0x38,0x46,0x17,0xcf,0x67,0x30,},{0x40,0x1c,0x9e,0x20,0x33,0xe2,0x25,0x9f,0xb6,0x38,0x3b,0x3e,0x8b,0x9e,0x17,0xb3,0xf2,0x06,0x27,0x46,0xbb,0xe6,0x48,0xcf,0x48,0x45,0x16,0xdb,0x0f,0x2f,0x1b,0x06,},{0x0f,0x03,0xa4,0xf1,0x5c,0x33,0x9b,0x4f,0x7b,0x88,0xb4,0xe2,0x1a,0xd9,0xe3,0xd6,0xbb,0xf3,0xef,0xfb,0x7b,0x67,0x8f,0xfa,0x50,0x0d,0x47,0x38,0x3b,0x71,0xa7,0x45,0x4f,0x62,0x90,0x7b,0x56,0xf5,0x9f,0x9b,0x9a,0xf6,0xd5,0xb2,0xa0,0xfc,0x1c,0x73,0x7a,0x64,0x10,0x51,0x95,0x08,0x98,0x99,0xf5,0x7a,0x2c,0x9d,0xba,0x50,0x9e,0x0a,},"\xdd\x06\x09\xea\x15\x99\x21\x39\x5d\x11\xfb\x2d\xa8\xea\x4f\x74\x7d\x7f\x74\xb5\x80\x52\xe0\x1c\xad\x40\xa2\x71\xfa\x0b\xbe\xed\x91\x02\x0f\x4f\x0c\x08\x46\xc4\xf0\x77\x78\xa6\xaa\x76\x8e\xb5\x17\x12\x29\x4e\x9e\x1f\x32\xa6\x02\xb1\x52\x51\x4f\x5e\x6d\x39\xf9\xe0\x8f\x7a\x78\x12\xbd\x90\x0c\x10\xa9\x14\x69\xe4\x7e\x8a\x78\xe5\x4c\xd4\xbd\x7c\xfe\xde\xde\xc1\x71\xef\x37\x3f\x1c\x4f\x9b\xbc\x2c\x81\x40\x2f\xb1\x4e\xd0\xbf\xac\x8d\x04\x3f\x11\x7d\x61\x24\x52\x1a\xfa\xe0\x91\x6a\x51\x0d\x56\x8a\xcf\xa3\xaa\x33\x01\xbc\x97\x9a\xc2\x8d\x55\x1d\xbb\xea\x6c\xea\xc4\xc2\x12\xaa\x8c\x84\x92\xb3\x61\x3a\xe7\x39\x5d\xd4\x12\x5f\xc4\xc2\x5d\x5b\x4d\x99\x23\x08\x21\xd4\xb1\x7e\xc2\xee\x6b\xe7\xd6\x04\x19\x5a\x21\x54\x33\x3b\x97\x35\x26\x58\x0c\xa7\xef\x9e\x30\xc6\xc1\xdd\x42\xef\x2a\xfe\x42\xb1\x1b\x1a\xa4\x9b\x9c\xca\xba\xca\x17\x09\x1e\xeb\x38\x0e\xc5\xe3\x4a\xd1\xe3\x82\x7c\xc6\x0d\xac\xf1\x44\x28\x6c\x78\x92\x59\x0b\xd2\x67\x1a\x8d\xc5\xf3\xa7\x02\xc1\xde\x7c\xd3\xb4\x2c\x1b\x15\x0b\x09\xc3\xe5\x8e\xf6\x94\x3b\x45\xd8\x9d\x41\xdf\x36\x1f\x1d\x5c\x25\x56\x55\x91\xb6\xac\x8d\xea\xa7\x36\x76\x53\x1f\x6e\x5a\xbe\x58\x04\xb0\x09\x7f\x8d\x45\xea\x29\x39\x17\x73\x33\xca\xce\xf1\x2e\x4b\x71\xfe\x49\x36\xba\xfe\x00\x74\x7a\x89\x30\xbc\xea\x55\xb8\xfd\x84\xa0\x1f\x6d\xf8\x4e\x7a\xcb\x93\x1f\xc7\xc0\x1d\xdf\xd6\x3d\xee\xc3\xad\x3e\x69\xdf\xa2\xb7\x35\x50\x58\x3d\x57\x47\xee\xe9\x6c\x55\x36\x36\x87\x97\xe2\x47\xf2\x3f\x53\x7d\x79\x07\x9a\xb6\xda\x31\x41\x02\xc7\x44\x3d\x41\x96\x0e\x3a\x3d\x8c\x35\x9c\x4a\x4e\xc6\x26\xfc\xc4\x4e\x11\x0e\xa7\x44\xd4\x17\xaa\x85\x0d\xb8\xec\xdb\xfe\x34\x0a\x96\x2d\xb0\xd8\xc5\x7d\xc5\x17\xbe\x8b\x40\xd1\x4d\xe9\x7b\x1e\x9e\x04\x26\x44\x7f\xde\x0a\x04\xe5\x06\x79\xc5\x3b\xa1\xaa\x3c\xdc\x38\xc7\xed\xe6\xdb\x6c\x05\x4b\x1e\x9c\xe7\xde\xad\xaf\x93\xeb\xdd\x47\x07\x91\x53\x5f\x3e\xcf\xab\xf3\x41\x63\x55\xf7\xa1\x8a\x38\xaf\xe6\xbf\xe5\x07\xef\x08\xc4\x37\x3a\x4a\x69\xde\xe1\xfc\xb6\x5b\x16\x31\xa0\xde\x14\x88\x64\x9d\x0b\xb2\x67\x9a\x9a\x45\xf6\x78\x20\xb2\xa4\xa1\xe5\xa5\x48\x07\x2d\xa7\x03\x2d\x17\x25\x55\xe7\x88\xcc\x98\x60\xeb\xb3\xc0\xc3\x59\x49\x37\x51\xb0\xc2\xc9\x50\xa7\xfc\xf4\x80\x3c\x14\x7f\x93\x40\xfc\x93\xd8\x5f\x1e\xfa\x57\xb3\x90\x81\xb9\x2d\x93\x47\x3f\xd2\x35\x16\xc4\x95\x0e\xd4\xb2\x9a\x2e\xd3\xa0\x42\xae\x3d\x92\xa1\xe5\x2c\xb7\x09\x63\x6f\xc7\x27\x2f\xd7\x47\x20\x8b\xee\x2b\x16\xd1\x91\xe4\xc6\xde\xb2\x76\x72\xaa\x34\xe4\x39\x14\xcf\xf2\x05\x5c\xa4\xee\x8b\xa3\xe1\xdc\x58\xa6\x79\xc7\xf7\xde\xe2\xc1\xd5\x3e\x28\x75\x09\x70\xf5\x7d\x85\xea\xb1\xc2\x6b\x89\xbb\x73\xe0\xb1"}, -{{0xc5,0x96,0x29,0x61,0x81,0x5b,0x57,0xcd,0x16,0x24,0x03,0xce,0x08,0xe4,0x10,0x5d,0xdb,0x8a,0xae,0x2d,0x3f,0x53,0x3f,0xb4,0x9c,0xc2,0x36,0xb5,0xff,0x50,0x4d,0x6e,},{0xdb,0xad,0xe7,0x22,0x36,0xba,0x12,0xd4,0x97,0x7b,0xa4,0x6c,0x36,0x4b,0xb6,0x9a,0x88,0x7f,0xf4,0x02,0xde,0x91,0xd4,0x7a,0xfa,0x9b,0x93,0xc9,0x5b,0xe7,0x1e,0x7e,},{0x81,0x01,0xba,0xef,0x00,0x4e,0xb6,0xf5,0xad,0x4d,0xe0,0x97,0x9f,0xf3,0x6d,0x34,0x39,0xb8,0x21,0x2b,0xdc,0x92,0x89,0x42,0xe4,0x31,0x91,0x5b,0x3f,0xd1,0x8b,0xc2,0xad,0x67,0xb2,0x6f,0x18,0x94,0x1d,0xcb,0x16,0xd2,0xc2,0x91,0x91,0x42,0x1e,0x77,0x9f,0xed,0x62,0x2f,0xd9,0xf5,0x82,0x64,0x4e,0xaa,0xdb,0x3f,0xe5,0xc0,0x98,0x03,},"\x4a\xe4\x14\x8d\x79\xca\x94\x25\x59\x2a\xa2\x40\xbd\x15\x34\x24\xa3\xbf\x4a\xe2\x73\x95\x87\x2c\xe5\x72\x8a\xc7\x61\x35\x96\xa7\x7d\x5c\xe8\x56\x5d\x8d\x6e\x1b\x59\x35\xb3\x90\x6c\xaf\xe1\xff\x88\x8e\xbc\x98\x15\xe0\x4a\x62\x4d\xfc\x4c\x69\x07\xb8\x5f\x6f\x1a\x0d\xbd\xdf\xf6\x2e\x91\x51\x22\x0d\x47\x44\x62\xcb\x9f\x13\xd8\x9d\x3a\x93\xa0\x0b\xa2\xb6\x0f\x7e\x7c\xa6\x3d\xa1\x7a\x63\x79\xd6\x73\x55\x1e\x79\x0b\x59\x11\x72\x7c\x90\x6d\xc9\x4f\x86\xd8\x27\x75\x46\xc1\x56\x4a\x45\x57\x3a\x77\x43\xbb\x8a\x13\x8c\xde\x87\xb3\xb2\xf2\x8e\x5e\x24\x59\x40\xa5\x1e\x7c\x45\x8c\xf8\xc5\xf0\xa7\x02\x75\x96\x25\x53\xe0\xd2\x39\x0d\x17\x1d\xb4\x4c\x2f\x7a\x5c\x9e\x9f\x93\xb9\x0f\x7a\x5f\x54\xf1\x91\xb0\xd8\x75\xba\xd7\xe0\xbe\xb9\x80\xc2\xa3\x36\x5c\xd7\xb9\x20\x87\x24\xf4\x65\x44\x18\x11\x7e\x16\xef\x71\x34\xe3\xe2\x79\x4b\x6f\x9e\x80\xec\xab\xec\xa3\x25\x4e\x70\x4c\x21\xb7\xad\x30\xc5\xde\xe0\x17\xea\x25\x33\xfc\xd9\x42\x51\xe5\x5a\xe7\x5a\x8c\xc6\xdb\x66\x74\xb3\x9c\x88\xca\x42\x00\x60\x43\xd6\xbd\x9b\x00\xec\xf6\x4c\xea\xfe\xeb\x40\x2b\x1f\x22\xfd\x89\x1f\x2d\x11\xc5\x15\xc1\xab\xa6\xa2\xd4\xc0\xbd\x21\x81\xa4\x8e\x43\xfd\x1c\x0a\xf9\x1f\x9b\x7b\x7d\x37\xf3\xdc\xd9\xe4\xc0\xa7\x59\x74\x84\x67\xd3\x48\xa8\xb1\x16\xdf\x6a\x4e\xac\xf1\x78\xae\xcc\xcd\x30\x66\xe9\x2d\xca\x45\xda\x7a\x3e\x31\x9f\x37\x71\xeb\x34\x90\x02\x21\x93\xc5\xb6\x52\xf0\x45\x68\x7e\x17\x05\xf2\xe5\x69\x1c\x13\x4b\xe4\x00\x63\x53\xd7\xec\xd0\xe9\x18\xd5\xde\x0f\x3b\x87\x80\x9f\xca\x4a\xcf\xab\x94\xe1\x14\x8f\xf7\xcf\x07\xf7\xcf\xd0\xc7\x45\xdd\x2b\xe0\x1a\x24\xa5\xe0\x69\x28\x06\x98\xbc\x3f\x54\x00\xa6\xdc\xd0\x8e\x44\x59\x5c\x03\x88\xe4\x48\x33\x76\x8f\xc4\x91\x04\xee\x11\x5b\xdc\xb0\x2b\xfb\xda\x17\x9d\x16\x4c\xe9\x69\x93\x66\x29\xf2\x33\x56\x01\xb5\x6f\xe8\xf7\x85\xcc\xa3\x80\x5f\x04\x03\x87\x2c\x62\xf7\x3c\x3c\xe8\x05\x63\xd0\x70\xe9\x76\xd8\xec\xc5\x11\x24\xe2\xca\xce\x7e\xe1\x86\x99\x04\x7c\xb0\xf8\xfb\x8d\x9c\x59\xb8\xa6\x0d\x12\xc0\x8a\x09\xfc\xe5\x8f\xd9\x2c\xd3\x6d\xb6\xa8\xe8\x9d\x11\x8c\xf8\x8a\x92\xdc\x8a\x26\x00\xbd\x95\xf5\xa8\xe8\x5d\xb5\xcd\xbb\x24\x9c\xa8\x12\xca\x20\x9c\x76\x18\x05\x1c\x45\x64\xa3\xa0\xe1\x92\xb7\xe4\x59\x92\x45\x6c\x87\xd1\x74\x12\xc1\x1a\xde\xad\x52\x6a\xb8\xdb\x21\x45\x2f\x74\x71\xd1\x7f\x2e\xbc\x90\x01\x54\x50\xed\xf4\xf0\xa4\x4f\xb2\xf4\x90\x5f\x74\xd7\x02\x75\xcc\xd8\x9b\x93\xa6\x50\x47\x3c\x02\xa7\xda\x0c\xbc\x67\x91\x5c\xeb\x7a\x1e\xa5\x9f\xa8\x88\x44\x72\xdc\x91\x7e\xe9\xd2\x46\x33\x9c\x59\x26\x84\x3e\xcf\x53\xfa\xfd\xc5\x6a\x69\x56\x01\xa2\x76\xc2\x3a\x84\x3e\x4d\x30\xf8\x9c\x97\xc9\xee\xe6\xdf\xc7"}, -{{0xde,0xe6,0x86,0x6c,0x78,0x74,0xc1,0x27,0x02,0x9e,0x96,0xe0,0x25,0xbf,0xfd,0x35,0xfc,0xfd,0xf4,0xdc,0x36,0x96,0x6c,0x15,0xee,0x62,0x93,0x36,0x80,0x13,0xd3,0x79,},{0x08,0xc9,0x4d,0xa3,0x51,0xbb,0x2b,0xee,0x72,0xe6,0xe1,0x96,0xbe,0x74,0x88,0x07,0x58,0x37,0x62,0xc5,0x29,0x6e,0x05,0xb1,0xe5,0x29,0xc4,0x7c,0x6b,0xba,0xce,0xc6,},{0xb7,0x8e,0xbd,0x6d,0x65,0xb1,0x75,0xd4,0xbb,0xd3,0xd9,0xa2,0x08,0x2a,0x0e,0xfe,0x6e,0x99,0x1c,0xb2,0xe4,0x03,0x52,0x1e,0xec,0xe0,0x0f,0x41,0x8f,0x2e,0x95,0x6b,0x66,0x90,0x78,0x80,0x65,0x8b,0x9e,0x8e,0x47,0x69,0x96,0x53,0xd1,0x59,0x13,0x23,0x80,0xd9,0xce,0x11,0x09,0xaf,0x9c,0x27,0x57,0xda,0xf4,0xcd,0xf1,0x8c,0x9c,0x0a,},"\xf1\xaa\x19\x77\xf5\x31\x1b\x53\x8b\x94\x0a\xe4\x42\xa3\xab\xc8\x9a\xac\xcd\xcd\x0a\x79\x38\x0a\x24\x25\x8d\x4a\x9f\x1c\xe6\x38\xfc\x2f\x5b\xa2\xe5\x3f\x8e\x1f\xa6\x17\x6f\x17\x8d\x90\x24\xa7\x78\x94\xc2\x8c\xad\x42\xd6\x29\xc7\x93\xd6\x8a\x02\xbe\x94\x11\xb5\x27\xac\xad\xae\x7e\x5c\x38\x51\xba\xbb\x45\xb5\xfe\xce\x32\x9e\x29\x03\x4c\xd4\x25\x71\x08\x37\x27\xf3\x5a\xec\xad\x7c\x9b\xe5\x95\x4e\xc6\x4e\x8f\x6e\xca\xb7\xcc\x05\x90\xe5\x41\x56\xa4\xe1\xa4\x53\x03\x84\x9f\x78\x97\xe7\x2c\xf2\xfb\xcd\x84\xf5\x6c\x72\xf9\x41\xdb\xb0\xb0\x9a\x32\xe6\x38\x6f\xbe\x18\xa4\x3b\xb9\xbd\x8b\x79\x3e\x4b\x9e\xdd\x53\x21\x03\xea\xb5\x4d\x62\x71\x17\xd2\x81\x39\xb6\x4e\x60\xfb\x0b\x81\xd0\x90\x01\xbb\x24\x04\xd9\x25\xe2\x65\xba\xbd\xc6\x9f\x96\xb1\x35\xe9\xe6\xab\x7f\xeb\xb1\xed\x30\x75\xd6\xaa\x2a\xbd\x2b\xbf\x9b\x65\xfa\x9b\x3b\x71\x91\xef\x37\xb6\x33\x60\x59\x10\xee\x88\xf6\x6e\xad\xa7\x9f\x00\xf5\x36\xd3\x80\xb8\x2f\x2f\x4b\x59\x85\x11\x2d\xe0\x04\xa5\x66\x03\xf4\x43\x6d\x8f\xf3\x00\xf4\x2b\xf5\xac\xdc\x7a\x4b\xf1\xea\x9d\x41\x96\xc4\x80\x49\x5b\xac\xb0\x06\x76\x30\xfc\xc0\x00\xb4\xf2\x79\xdd\x3f\x30\xf3\x53\x27\x60\x92\xd1\x52\xc3\xf4\x3e\xfd\xc0\x41\xde\xaa\x0b\xc5\xaa\xab\xa7\xf8\xbb\xd8\x5e\x69\xc1\x37\x42\xd6\x78\xdb\xb6\x53\x60\xaa\xf7\xb5\x48\xa0\x44\xc0\xec\x60\xa5\x7a\xf6\x50\xbc\x31\x97\x3f\x83\x2f\x96\x12\x65\xbc\x23\x18\xf8\x07\x75\xaf\xd5\x1f\x55\x19\x4c\x42\x42\x3f\x7b\xf4\xe0\x05\x2f\x98\xcb\x20\x69\x13\xff\xea\x48\x86\xec\xd2\x7a\x41\x79\xb1\x37\x73\xf9\x47\x50\x2e\x18\x1b\xf1\xa1\xf2\xc6\x2c\x6f\x08\xc2\x03\x59\xf0\x6d\xf2\xb1\x81\x27\x04\x3b\x10\x70\xd0\x19\x4e\xf5\xe5\xbf\xd3\x7d\x22\x79\x84\xcf\xb1\x09\x89\xf2\x1c\x71\xad\x0f\xe3\xb8\x12\x27\xd3\xa7\x17\x89\x45\x5e\xda\x38\x3c\x22\xf4\xd2\xfc\xc7\x25\x79\xf4\x65\xe0\x66\xf3\xd3\x8b\xef\xc0\x24\xef\xef\x6c\x2e\x32\x96\x49\xce\x43\x4d\x62\x73\x67\xa9\x00\xd0\x7f\xe6\x23\x42\x35\xc8\x46\x56\xea\xc5\xdd\x0d\x78\x8c\xf4\xcb\x31\x87\x18\x24\xd6\x6a\xe4\xbc\x89\xed\xeb\xa1\xb3\x67\x01\x29\x84\x53\xe8\xda\x1e\x69\xcf\xb8\x68\x09\x5c\x3b\xe6\xed\x21\x82\xda\x1c\xff\x49\x05\xaf\xd2\x07\x31\xac\x1e\xd9\x84\x16\x47\x37\x90\x3c\x7d\x8b\xb0\xad\x16\xae\xcf\x2f\xae\x33\x74\x04\xfe\x35\x66\x45\x15\xd9\x3b\x70\x1e\x2f\x87\x86\x64\x45\x4c\x0d\xec\xd1\xc6\x55\x8a\xda\xce\x3c\xdb\x22\x75\x07\xa5\x16\x06\xf0\xa5\x4d\xf8\xdf\xaa\x42\x02\x05\xdd\x57\xc6\x52\x42\xff\x24\xa4\x05\xef\x85\xc9\x2d\x60\x28\x86\x93\x2b\x35\xfa\xbe\x9c\x3b\xce\xbf\xc6\x23\x56\x39\xe8\x73\xfc\x2d\xd0\x84\xc5\x2c\xd6\xa7\x41\x3b\x83\x1d\x1c\xc9\x99\x31\x37\x3a\xab\xd8\x47\x62\x0e\xb6\x9b\xb0\xfa"}, -{{0x52,0x36,0x23,0x55,0x59,0x95,0xba,0xaf,0x2a,0x27,0xad,0xcb,0x1e,0xba,0xfa,0xa8,0x02,0xd2,0x3e,0xf7,0xab,0xfa,0x97,0x75,0xf2,0xc9,0xbf,0xa0,0x7d,0x64,0xe0,0xac,},{0xd3,0x4d,0xea,0xe6,0x52,0x3e,0x61,0x9d,0xd1,0xbf,0xc8,0xf3,0xc4,0xca,0x4b,0x78,0xb3,0x68,0xc0,0xf7,0x20,0x03,0x5e,0x14,0x4c,0x3f,0x2f,0xc1,0x05,0xd4,0xce,0x21,},{0xb1,0x87,0x17,0x29,0xfe,0xc8,0x3a,0xea,0x0a,0xaa,0x47,0x2b,0x70,0x0a,0xcd,0x09,0x48,0x13,0xfb,0x7d,0x57,0xb9,0x09,0xe0,0xea,0xaf,0x21,0xee,0x93,0x18,0x47,0xad,0xde,0xdd,0x2b,0xe8,0x53,0x3d,0x0c,0x30,0x5c,0xb9,0xcf,0xe5,0x08,0x0e,0x76,0xc2,0x80,0x8b,0x6e,0x51,0xc9,0x82,0x62,0x90,0xdd,0xb7,0xb9,0x4b,0x6f,0x7d,0x58,0x0b,},"\x05\x53\xe6\x9e\xf2\x11\x65\x2d\x62\xbf\x28\x1b\xfb\xdd\x37\xbe\x22\x76\x9d\x81\x97\x46\x36\x1c\x7d\x65\xdd\xd0\xfa\xd6\x77\xcc\x04\x38\xb3\x01\xd1\x51\x45\x78\xe0\xda\x58\xe5\x5f\x72\x9f\xa8\xe6\x6d\xde\xb7\xf9\x73\xa8\x18\xd2\x4e\xd8\xfe\x02\x7b\x84\x91\x17\x9d\x07\x77\x3f\xb5\xd2\xbb\x96\xaa\x85\xd6\xb3\x75\x04\x54\xe5\x0d\xe9\x1f\x9b\x88\xae\xe8\xaa\x68\xe6\xbb\x53\xed\xc6\x66\x77\xb4\x1e\x60\x1a\x46\xab\x4b\xb1\xe6\x56\xe7\xfa\x5f\x01\x79\x93\x36\x80\xa6\xec\x95\x04\x27\x5e\x7a\xdf\x7a\x32\x48\xe6\x3a\x0f\xc9\xc1\xea\x5a\xe9\x6c\xd0\xc6\x5a\x89\xa7\x7c\xec\x2b\x1f\xd8\xf4\x53\x7e\x82\xc1\xc4\x88\xa6\x9a\x0e\xf6\x4f\x58\x73\x4d\x9e\x73\x47\x8e\x1d\x1f\x12\x31\x14\xef\x66\x08\x5e\x0b\xa3\x19\xcb\x81\x0b\x66\xaf\x96\xd1\x30\x8b\x1a\x2b\xd9\x2b\xa2\xc2\x65\xaa\x30\x9e\xcd\x55\x57\xd4\x02\xc3\x80\x2c\xae\x8d\x7e\x95\x00\x7f\xe6\x10\xc2\xaa\x75\xfc\x66\x19\x6c\x3f\xad\xfe\x99\x7d\x6d\x59\x98\xe1\x8d\x26\x0e\x9d\xa3\x1d\xa9\x21\x8c\xba\xd1\x03\xcb\xfc\x2c\x75\x47\x76\x5d\x67\xe8\x1f\x24\xac\x83\x02\x2e\xf5\x1c\x6c\xc5\x08\x64\x36\x6a\x35\xf6\xb9\xb9\xaf\x94\xe8\x4c\xaa\x9f\xd3\xd7\x67\xc8\x31\xf0\x96\x7a\x61\x46\x2f\xbc\xfc\xc8\x03\xf1\x2e\x37\x39\x03\x9a\xcd\x5d\xbe\x93\x66\xf0\x5a\x33\xdb\xea\xf3\x60\xe2\xdd\xcb\xe5\xc4\x43\xf8\x0e\xf2\xad\x62\xe0\x3c\x1d\x5b\x70\xcd\xea\xb4\xa7\xdd\x41\x55\x30\x64\xc8\xd1\x52\x70\x9d\xef\xf8\x20\x76\xb9\x07\x11\x92\x37\x6f\x51\xd4\xc2\xc7\x1a\x84\xe8\x9f\x2d\x94\x01\x32\x0c\x2e\x45\x9b\x3e\x24\x3c\xca\x7c\x26\xfd\x09\x8c\x26\x4a\xc8\x8e\xf6\x38\x92\x1d\x98\x0b\x0a\xe9\xe5\x12\xd3\x72\x03\x7d\x81\xad\xc4\x81\x26\xd7\xc9\xe4\xb5\xaf\xa5\x7e\xc2\x65\xd4\x01\xb9\x65\x3e\x92\x8a\xfb\x7d\xff\x9b\x48\xe2\x95\xe4\x70\xd6\xb5\x2e\x88\xb3\x9d\x0a\x40\xcb\x8e\xba\x24\x9f\x8b\x13\xd8\x11\x13\xdb\x1d\x3e\x01\xef\x75\xc7\x22\xf2\x69\x48\x8e\x96\x3c\xc8\x18\x27\x04\xf8\xca\x01\x8e\x73\xdc\x07\x14\xe9\xa9\xfc\x79\xbc\x43\x63\xc2\x8c\xb3\x98\x43\x74\xf7\x3b\x2a\xa8\x78\x6e\x74\xe0\x15\x95\x07\xa2\x98\x83\xfe\x0e\xd1\xc6\x00\xf5\x25\x88\x5f\x2f\x10\xea\x00\x6c\x39\xe5\x9b\x92\x5b\x76\x5b\x1e\xde\x53\x42\x57\xa1\xf4\x0f\x28\x46\x58\x4f\x06\x97\x46\xb5\x2f\x56\x00\x43\x0a\x28\x63\xd7\x93\x60\x95\xfb\xc2\x2a\x6a\xda\x67\x4d\x41\xb3\x74\xe2\xb8\xb9\xa1\x9f\xa7\x12\xb5\x94\x45\x33\xbb\x6d\x6e\xc4\x3b\x89\xd4\x97\x1b\x70\x20\x5a\x6a\xcd\x72\xa8\x99\xda\x12\x61\x82\x04\xdb\x0c\x3e\x82\x67\xb8\x45\x79\x16\x93\xe0\xae\x6a\x35\xf1\x4d\xa1\xf8\xf4\xdd\x17\x4b\xce\x03\x18\xfb\x5a\x00\xf6\x72\xed\xe4\x23\x04\xcf\x04\xa6\x27\x60\x57\x75\x90\xf2\x7e\x2d\xfa\x6e\x5e\x27\x95\xd6\x60\x53\xb3\x0a\xf7\xf1\xbf"}, -{{0x57,0x5f,0x8f,0xb6,0xc7,0x46,0x5e,0x92,0xc2,0x50,0xca,0xee,0xc1,0x78,0x62,0x24,0xbc,0x3e,0xed,0x72,0x9e,0x46,0x39,0x53,0xa3,0x94,0xc9,0x84,0x9c,0xba,0x90,0x8f,},{0x71,0xbf,0xa9,0x8f,0x5b,0xea,0x79,0x0f,0xf1,0x83,0xd9,0x24,0xe6,0x65,0x5c,0xea,0x08,0xd0,0xaa,0xfb,0x61,0x7f,0x46,0xd2,0x3a,0x17,0xa6,0x57,0xf0,0xa9,0xb8,0xb2,},{0x90,0x3b,0x48,0x4c,0xb2,0x4b,0xc5,0x03,0xcd,0xce,0xd8,0x44,0x61,0x40,0x73,0x25,0x6c,0x6d,0x5a,0xa4,0x5f,0x1f,0x9f,0x62,0xc7,0xf2,0x2e,0x56,0x49,0x21,0x2b,0xc1,0xd6,0xef,0x9e,0xaa,0x61,0x7b,0x6b,0x83,0x5a,0x6d,0xe2,0xbe,0xff,0x2f,0xaa,0xc8,0x3d,0x37,0xa4,0xa5,0xfc,0x5c,0xc3,0xb5,0x56,0xf5,0x6e,0xdd,0xe2,0x65,0x1f,0x02,},"\x2c\xc3\x72\xe2\x5e\x53\xa1\x38\x79\x30\x64\x61\x0e\x7e\xf2\x5d\x9d\x74\x22\xe1\x8e\x24\x96\x75\xa7\x2e\x79\x16\x7f\x43\xba\xf4\x52\xcb\xac\xb5\x01\x82\xfa\xf8\x07\x98\xcc\x38\x59\x7a\x44\xb3\x07\xa5\x36\x36\x0b\x0b\xc1\x03\x0f\x83\x97\xb9\x4c\xbf\x14\x73\x53\xdd\x2d\x67\x1c\xb8\xca\xb2\x19\xa2\xd7\xb9\xeb\x82\x8e\x96\x35\xd2\xea\xb6\xeb\x08\x18\x2c\xb0\x35\x57\x78\x3f\xd2\x82\xaa\xf7\xb4\x71\x74\x7c\x84\xac\xf7\x2d\xeb\xe4\x51\x45\x24\xf8\x44\x7b\xaf\xcc\xcc\xec\x0a\x84\x0f\xec\xa9\x75\x5f\xf9\xad\xb6\x03\x01\xc2\xf2\x5d\x4e\x3b\xa6\x21\xdf\x5a\xd7\x21\x00\xc4\x5d\x7a\x4b\x91\x55\x9c\x72\x5a\xb5\x6b\xb2\x98\x30\xe3\x5f\x5a\x6f\xaf\x87\xdb\x23\x00\x1f\x11\xff\xba\x9c\x0c\x15\x44\x03\x02\x06\x58\x27\xa7\xd7\xaa\xae\xab\x7b\x44\x6a\xbc\xe3\x33\xc0\xd3\x0c\x3e\xae\x9c\x9d\xa6\x3e\xb1\xc0\x39\x1d\x42\x69\xb1\x2c\x45\xb6\x60\x29\x06\x11\xac\x29\xc9\x1d\xbd\x80\xdc\x6e\xd3\x02\xa4\xd1\x91\xf2\x92\x39\x22\xf0\x32\xab\x1a\xc1\x0c\xa7\x32\x3b\x52\x41\xc5\x75\x1c\x3c\x00\x4a\xc3\x9e\xb1\x26\x7a\xa1\x00\x17\xed\x2d\xac\x6c\x93\x4a\x25\x0d\xda\x8c\xb0\x6d\x5b\xe9\xf5\x63\xb8\x27\xbf\x3c\x8d\x95\xfd\x7d\x2a\x7e\x7c\xc3\xac\xbe\xe9\x25\x38\xbd\x7d\xdf\xba\x3a\xb2\xdc\x9f\x79\x1f\xac\x76\xcd\xf9\xcd\x6a\x69\x23\x53\x4c\xf3\xe0\x67\x10\x8f\x6a\xa0\x3e\x32\x0d\x95\x40\x85\xc2\x18\x03\x8a\x70\xcc\x76\x8b\x97\x2e\x49\x95\x2b\x9f\xe1\x71\xee\x1b\xe2\xa5\x2c\xd4\x69\xb8\xd3\x6b\x84\xee\x90\x2c\xd9\x41\x0d\xb2\x77\x71\x92\xe9\x00\x70\xd2\xe7\xc5\x6c\xb6\xa4\x5f\x0a\x83\x9c\x78\xc2\x19\x20\x3b\x6f\x1b\x33\xcb\x45\x04\xc6\xa7\x99\x64\x27\x74\x1e\x68\x74\xcf\x45\xc5\xfa\x5a\x38\x76\x5a\x1e\xbf\x17\x96\xce\x16\xe6\x3e\xe5\x09\x61\x2c\x40\xf0\x88\xcb\xce\xff\xa3\xaf\xfb\xc1\x3b\x75\xa1\xb9\xc0\x2c\x61\xa1\x80\xa7\xe8\x3b\x17\x88\x4f\xe0\xec\x0f\x2f\xe5\x7c\x47\xe7\x3a\x22\xf7\x53\xea\xf5\x0f\xca\x65\x5e\xbb\x19\x89\x6b\x82\x7a\x34\x74\x91\x1c\x67\x85\x3c\x58\xb4\xa7\x8f\xd0\x85\xa2\x32\x39\xb9\x73\x7e\xf8\xa7\xba\xff\x11\xdd\xce\x5f\x2c\xae\x05\x43\xf8\xb4\x5d\x14\x4a\xe6\x91\x8b\x9a\x75\x29\x3e\xc7\x8e\xa6\x18\xcd\x2c\xd0\x8c\x97\x13\x01\xcd\xfa\x0a\x92\x75\xc1\xbf\x44\x1d\x4c\x1f\x87\x8a\x2e\x73\x3c\xe0\xa3\x3b\x6e\xcd\xac\xbb\xf0\xbd\xb5\xc3\x64\x3f\xa4\x5a\x01\x39\x79\xcd\x01\x39\x69\x62\x89\x74\x21\x12\x9a\x88\x75\x7c\x0d\x88\xb5\xac\x7e\x44\xfd\xbd\x93\x8b\xa4\xbc\x37\xde\x49\x29\xd5\x37\x51\xfb\xb4\x3d\x4e\x09\xa8\x0e\x73\x52\x44\xac\xad\xa8\xe6\x74\x9f\x77\x78\x7f\x33\x76\x3c\x74\x72\xdf\x52\x93\x45\x91\x59\x1f\xb2\x26\xc5\x03\xc8\xbe\x61\xa9\x20\xa7\xd3\x7e\xb1\x68\x6b\x62\x21\x69\x57\x84\x4c\x43\xc4\x84\xe5\x87\x45\x77\x55\x53"}, -{{0x03,0x74,0x9c,0xa2,0x04,0x58,0xa3,0x5a,0x37,0xa8,0xd7,0xa2,0x6f,0x95,0x9f,0x0d,0x59,0xf6,0xdc,0x99,0x73,0xfa,0x36,0x3c,0x1f,0xf8,0xca,0x4e,0x63,0x8c,0x2c,0xd3,},{0xea,0xeb,0x94,0xf4,0x06,0xbd,0xe6,0xa7,0xcf,0x8b,0xde,0x2a,0xdf,0x30,0x81,0xf8,0x37,0x5b,0x87,0xd9,0x33,0x5d,0x49,0x6c,0x71,0xd0,0x42,0xcd,0x2e,0xaa,0x16,0x6c,},{0x78,0xa3,0x87,0x7e,0x02,0xbd,0xfd,0x01,0x5e,0x7f,0x86,0xa3,0x27,0xa4,0x8c,0xc3,0xa5,0x23,0x0b,0xbd,0xb1,0x24,0x3f,0x1a,0x8c,0xf2,0x27,0xf7,0x8a,0xb5,0xe7,0x68,0x0d,0xe3,0x01,0xa9,0x15,0xdc,0x11,0xb3,0x36,0xfb,0x5f,0x65,0x66,0x84,0x8b,0x42,0x50,0x0a,0xdb,0x5d,0x67,0x39,0x69,0x12,0x2b,0xa8,0xf0,0x05,0x3c,0xd3,0x06,0x0b,},"\xee\xf5\xce\xeb\xd0\x44\x5e\x9c\x91\x81\xaf\xf9\xc6\xf2\x66\x01\x28\xfc\xfb\x63\x69\x1a\x42\xcf\xa4\x43\xd6\xa6\x49\xef\xc5\xfa\xd8\xc2\x08\x03\x76\x3e\xe9\x7d\x1d\xba\x08\xe6\x3e\x08\xa2\x61\x6d\xa0\x50\x77\x48\x9f\x2f\xa2\xc5\x6b\x75\x34\xf9\x40\x26\x19\x25\x1f\xdf\x9c\x32\x0d\xe7\xaf\x10\x9e\x2f\xd8\xb2\x56\x5c\xe8\xa7\x52\x4c\x94\x05\xec\x0f\x8f\xca\xa7\x14\x9a\x6d\x21\x0e\xfd\xe8\x3b\x11\x1c\xf8\x2d\xc0\x83\x5c\xf9\x4f\x20\xcd\xb0\x21\xb7\x3b\xd2\x62\x66\x65\x55\xe6\xd6\x27\x07\xb4\x6e\xe4\x2f\xa9\x00\xb4\xf4\xf7\x05\xde\x33\xd3\xdb\xdc\x68\xa8\x8d\x1a\x4d\x0a\xe9\x33\x56\x6d\xb6\xc6\x23\x7e\xc8\xab\xe1\x02\x4d\xac\x4b\x7f\x46\xd4\x07\xbe\x16\x59\x4d\x90\x46\xc7\x31\x2d\xda\x66\x14\xd9\xbc\xdb\x01\xfb\x83\x24\xfc\x62\xb8\xee\xaf\x0a\xbc\x23\xcd\x57\x0e\x30\x4f\xca\x08\xe8\x8c\x73\x5e\x5d\x31\x59\x24\x09\xce\xb5\x83\x86\x2e\x6b\x0a\x76\x77\x29\xf7\x55\x6f\xa2\xc0\x53\x64\x4d\x36\xc8\x33\x7c\x02\x74\xe7\x49\x20\x29\x82\xfb\x4a\x17\x1a\xca\xc1\x96\xc0\x2b\x7f\x16\xa8\xda\x49\x07\x1c\x8a\xb8\x07\x6d\xd5\xd3\xab\xad\xfe\x3a\xf8\x2c\xa8\x5d\xa0\x2d\xcc\x1c\x4a\x6f\x2e\x19\x30\xbe\xe2\x00\x9e\xee\x0d\x97\x1e\x40\xdd\x12\x17\x5c\x8d\x00\x69\x4f\x03\x25\xa3\xb3\x13\x3c\x0d\x0b\xd3\x82\xa5\x19\x4f\xb2\x14\x22\xce\x67\xc7\x8a\x5a\x6e\x15\x37\xe3\xb9\x7d\x5e\x20\x4e\x5d\x19\x56\x96\x39\x0f\x77\xd1\x90\x24\xc1\xbf\x6b\x51\x25\xa0\xcd\xbf\x7b\x98\x80\x03\x61\x81\xc9\x8e\x1a\xc2\xe5\x16\x5b\xd4\x96\xcf\x99\x74\x51\xa1\xc1\x21\x02\xe6\x69\x46\xb1\x67\x6a\xbd\x4c\xbd\xd2\xc1\x16\x73\xf4\xf2\xcd\x5f\x3c\x9a\x43\x4d\x74\x7f\xa0\x5b\x40\xfb\xc7\x22\x68\xb4\xeb\x28\x42\xe4\x74\x1f\x51\xb7\x70\x9b\x6a\xcc\xc4\x7f\xca\xf7\x0d\x9c\x1c\x4c\x35\x86\x71\x19\xd8\x1c\xb3\xff\x1f\x16\x08\x11\x33\xf1\x65\x9a\xed\x85\xf6\x3b\xc9\x01\x98\x9e\x26\x17\xfc\xce\x15\x3c\x29\x78\xd7\x08\xfd\x02\x44\x9a\xe4\xd5\x38\xd1\x22\xdd\xb8\x52\x7c\x0a\x76\xa1\x02\xee\xff\x6e\xdb\x65\xdb\xa2\x98\xd3\xc2\x17\xf6\x55\x18\x14\xed\xde\xec\xe1\xae\xf5\xf3\x71\xa5\x4f\x12\xbf\xfd\x6b\x49\x61\x81\x9a\x0f\x24\x4f\xf0\xd7\xd8\x69\x4c\x14\x42\x2d\xe9\x82\x2c\x13\x17\x9e\x4e\xeb\x81\x59\x50\x79\xb9\xdd\x2a\xd1\xe7\xc3\x9b\xd3\x03\xcc\x44\xae\x3f\x36\x34\x88\x15\x77\xa2\x66\xfd\x6b\xb7\x91\x78\x12\xb9\x99\xdc\x80\x9d\xc0\x9c\x3d\x70\x19\xda\xcd\x28\xe4\x30\x13\xa2\xf9\xe4\xf9\x4b\xb0\xbf\x71\x24\xef\x09\x17\x83\xf7\x96\x39\x7f\x64\x63\xbf\x1e\xfb\x39\xcd\x46\xf3\x79\x0a\x1d\x9b\x6a\x7c\x30\xf1\x49\xb5\xe6\x6c\x29\x37\xe3\x9c\xb9\x74\x4d\xdc\x66\xab\x56\x1b\xad\x4e\x6f\xa8\x53\x4d\x69\x88\x38\x22\x64\x3d\x63\xd8\xbd\x7b\x18\x16\x21\xa2\x67\xe9\x55\xe7\x58\xd1\x79\x2b\x44"}, -{{0x53,0xcb,0xd6,0xf6,0x8c,0xee,0x27,0xb9,0xf7,0xbc,0x05,0x9b,0x80,0x3b,0x44,0x79,0x49,0xbb,0xc9,0xc5,0xd5,0xa3,0x86,0x52,0xd7,0x78,0x9c,0xa1,0x54,0x20,0xde,0xa1,},{0x61,0x16,0x99,0x0b,0x53,0x31,0xe2,0x16,0x5f,0x82,0x74,0x3f,0x01,0xd8,0xe7,0xbd,0x5d,0x70,0x88,0xb3,0x01,0x59,0x83,0x3f,0xa7,0xb9,0x39,0xcf,0xb1,0xcc,0x04,0xd7,},{0xd8,0x25,0x04,0x40,0x5f,0xf1,0x6b,0xa6,0x44,0x3d,0xc4,0x82,0x36,0x72,0x63,0xa8,0xe2,0x00,0x36,0x0a,0xca,0xaa,0x83,0xfc,0x4e,0x4b,0x72,0xbd,0x24,0x9f,0x16,0x10,0x3e,0xc7,0xe5,0xa7,0xe9,0xca,0x17,0x19,0x8f,0x88,0x8e,0xac,0xa1,0x6b,0x74,0x0c,0xc3,0xf5,0xc3,0xb7,0xb6,0x17,0xa3,0x4b,0x94,0x91,0xc3,0xed,0x76,0xaa,0xb3,0x0d,},"\x30\x6f\x8e\x1d\xf0\xa4\xca\x78\xbd\x77\xe8\xe1\x19\x1c\x94\xde\xaa\x82\x64\x83\x55\xc2\xae\xcb\x7e\x82\xfc\x56\xd6\x4c\x50\x46\x19\x24\x7e\x7c\xf8\x94\x33\x28\xd1\x1f\x3d\xb4\xb1\xdc\x14\x8e\x8e\xf6\xf6\xc3\xbc\x35\x59\x69\x66\x2a\x28\x1a\x65\x57\x63\x91\x24\x2b\x7b\xd5\xa6\x2f\x8f\xa7\xac\xb6\x04\xe3\xa3\x44\xae\x1a\x9d\x73\x2a\x25\x43\x15\xf3\x1a\x04\x64\xc1\xe6\x58\x74\x62\xd2\x92\x12\xc4\x0e\x5e\xcf\x06\x1e\x26\x9a\xa0\xb9\x03\x90\xba\x41\x04\x07\x21\x68\x4b\xf2\xaa\x95\x82\xd8\x30\x66\x22\x1d\xb6\x0d\x0f\x7a\xe2\xf1\x49\xa3\x6e\x16\x95\x27\x04\xfb\x1f\x3a\x98\x2e\xac\x6b\x45\x83\x66\x5c\x63\xe5\xa8\x99\x6f\x24\xa5\x66\xdd\x50\x6a\x33\xd4\xec\x8a\x02\xb2\xbd\x34\xb7\x14\xc7\x45\x00\x0c\x01\x28\xa3\xc8\x9d\x94\x25\x06\xd1\x2f\x4b\xeb\x90\x0e\x29\x03\xcd\xb3\x4b\x35\xca\x9b\x6d\x3a\xd9\xb3\x50\xac\x99\xf4\x1d\xb3\xac\xfe\x7f\xe5\x5a\x28\xc0\xf0\x06\xb8\x44\xc9\xdc\x48\x53\xfd\x98\x53\x5a\xda\x79\x41\x6d\xca\x5f\xee\x58\x03\xa2\xd9\xf5\xd6\x8e\x6b\x80\x53\x9f\xf3\x02\xe9\x73\xf2\x4e\x9b\xc8\x8b\x7c\x41\x94\x11\x7d\xdb\x9f\x93\x2b\x32\xd5\xec\x74\x86\x8a\x13\x63\x1e\xce\x68\x81\x4b\x93\x14\x21\xdc\x89\x02\x49\x57\x03\x41\xf4\xb4\x23\xe8\x6e\x8e\xe0\x81\xb2\x27\x02\xf6\x49\xa6\xc7\xa0\xb7\xbd\xf5\xfb\x75\x62\x02\xbd\x10\xb0\xbb\x22\x15\xc7\xd6\x59\x7e\xff\xd8\x52\xf0\xb8\x9a\xbe\xc1\x5e\xa8\x22\x57\x68\x9d\xf8\x1e\x33\x82\x54\xf9\x3e\x81\xcb\xf0\x61\x72\x9d\x48\x3e\xb5\xcf\x64\x98\x05\xd7\x8e\xd8\x92\xdd\x0b\xd2\x48\xca\x1e\x25\x2b\xea\x51\x84\x7e\x1e\x82\xd3\x9a\xf5\x80\x50\xdc\x4a\xfb\xf9\x11\x5a\x3a\x60\x49\x3e\x8c\x0b\xa2\xe8\x6e\x08\x98\xcd\x0d\x43\x08\x91\xb9\xeb\x0a\x40\xf8\x74\x31\xe2\x5f\x41\x53\x8a\x03\x0f\x88\x4f\xab\x36\xad\x11\x16\x5d\x26\x7e\x8d\xd9\x4d\xcb\x05\xb9\x3a\x5a\xe7\x79\x69\x43\x0e\x18\x10\x13\x4e\x15\x72\x51\xb9\x82\xdf\x34\x3d\xff\xae\x61\x23\xa9\x9a\xa0\x56\x2d\x5d\xf7\x24\x08\xf1\xa6\xe2\x9c\x40\x59\xa5\xa8\xaa\xa4\xe6\x21\x52\x8f\xc6\x3a\x9c\xbe\x1f\x4c\x0f\xef\x25\xfe\x3f\x8e\x18\x15\x77\x74\x09\x7a\x9d\x91\x02\x0a\x90\x06\xb6\xc8\x60\xec\x1e\xe1\x0d\x52\x1d\x20\x3a\x1f\x8b\xb8\x25\x61\x29\x6f\xaa\xd4\xb2\x20\x3d\xa5\x3b\x20\x7a\x45\x9b\x29\xc1\x8b\xc0\x64\x93\x32\xb1\x80\x7c\x13\xca\x61\xac\xfa\xf9\x07\x79\xfe\xbb\xc7\xf3\x24\x21\x64\x79\x7e\x6f\x57\x2c\xb1\x5a\x9b\xe5\x88\x73\x43\x45\x5e\x26\xb9\x10\xc8\xbe\xfe\xe4\x2a\xeb\x04\x7f\x9a\xbe\x6b\x37\x50\xdb\xd7\xde\x99\x20\x2a\x0b\xb5\x76\xce\x14\x89\xe6\x1c\x1f\x5d\x27\xc6\x79\x2e\x63\x21\x8e\xdb\xfd\xb9\xb3\xdc\x51\x5b\x42\x54\xd8\x2c\x85\x9e\x52\xce\x6b\xd7\xad\x29\x6d\xd0\xe3\x70\x9d\x4c\x46\x63\x62\xf9\x02\x65\xe9\x9d\xa7\xd0\xb7\x01"}, -{{0x8b,0x65,0x74,0xf6,0xd7,0x39,0x69,0x81,0xe2,0x23,0xa4,0x83,0x7b,0xc3,0x39,0xc3,0xfd,0x65,0x94,0x19,0x84,0x5a,0x21,0x21,0xbf,0x85,0xbe,0x2e,0x69,0x5d,0x86,0x0d,},{0xe3,0x81,0x1a,0xca,0x70,0x63,0x4f,0x5a,0x9c,0xe4,0xb5,0x92,0xa1,0x7b,0xb5,0xcf,0xda,0x53,0x44,0x24,0x22,0xe2,0x03,0xcd,0xa9,0x50,0x4c,0x9d,0x65,0xb2,0x63,0xe8,},{0x2f,0xd0,0x90,0x54,0x75,0xa2,0xce,0xc3,0xe7,0x6f,0x99,0x09,0xb8,0xaf,0xd8,0x3b,0xeb,0x8d,0xae,0xfa,0x77,0xaf,0xcd,0xa3,0x4c,0xb4,0xf1,0x17,0x28,0xef,0x15,0xfc,0x9c,0x1d,0x7f,0x6f,0x6a,0xff,0xfc,0x28,0xf3,0x87,0x4f,0x91,0x3e,0x17,0x98,0x0f,0x0e,0x8e,0x3d,0x5a,0xd2,0x39,0x51,0xdf,0x2b,0x32,0xef,0xaf,0x62,0x19,0xce,0x0d,},"\xa4\x8a\xac\xc0\x49\x5f\xa0\xf1\x25\x9b\x27\x86\x5d\x3d\x75\xdc\x52\xc2\xc8\x28\xea\x8c\x4c\x2a\xd7\x85\x77\x07\x2f\xef\x72\x70\xf6\xa4\xd5\x82\xbb\x7b\x96\x2f\x4c\x3f\xd1\x49\xa6\x0a\x06\xbc\x8e\xfd\x29\x70\xef\x03\x14\x8d\xdf\x61\x98\xb9\xb6\x95\xa6\x9f\xad\xb5\x34\x09\x51\xcb\x75\x39\x8a\xc5\x1a\x4f\xd5\x54\x30\x37\x8c\xd5\xda\x88\x85\x21\x0b\xfd\x21\x46\xf9\x5c\x62\x76\x32\xfe\x8b\xe0\x6d\xe0\x1a\x7c\x27\xb8\x9d\xee\xfd\x67\xef\xc6\x9c\x9b\x5c\x62\xb3\x81\x08\xf7\x76\x22\x91\x43\xda\xe6\x60\xc1\x0c\xbe\xa3\xcd\x4f\x7e\xe5\x3d\xc3\x69\x2e\xd0\x11\x77\xe4\xa6\xf7\xe4\x24\xb5\x66\x6f\x7f\x49\x5f\x2a\x65\x60\x2c\x7d\x08\xc5\xd5\x72\x23\x4a\x56\x7c\xb6\xc3\x8a\xfd\x79\xca\xb5\xc4\x03\x6d\x62\x63\x7a\xef\xab\x55\x88\x76\x9a\x44\x8a\xb4\xc6\x5e\x24\x55\x4b\xd4\x15\x80\x50\xe0\x9e\xb5\x8f\x99\xab\x40\x77\x7b\x03\x56\x70\x9b\x7c\x02\x5a\xe5\xae\x54\x22\xac\xf8\x74\x44\x93\x1a\xe4\xd9\xa8\xb3\xd9\x44\x76\x88\x11\x28\xba\x1e\xb7\x32\x8f\xaf\xc7\x5f\x6b\x9d\xac\xc9\x6d\x3b\x64\x87\xdd\xef\x7c\x59\x26\x2d\xca\xda\x42\x6a\xac\xb1\x39\x22\x93\x54\x11\x56\x62\x35\xe0\x58\x37\x26\x22\xd8\x85\xbd\x0c\xc0\x49\x58\xdc\xfb\x17\xe0\x8f\xcd\x7f\x14\x7e\x20\x15\x6c\x8e\x26\xaf\x85\x53\x0f\x55\x11\xa6\x8d\xb4\x3d\xaf\xc4\xe6\xa2\x3f\x66\x7d\xf3\x74\x3e\xed\xd7\x1a\x3f\x07\xf7\x6f\x94\xd1\x68\x8a\xfc\x84\x63\xbf\xa5\xa4\x39\xae\x31\x14\x69\x94\x8e\x74\x47\x06\x4f\x0b\x05\x06\xf3\x67\x19\xc1\x34\x66\xa1\xb9\x87\x76\xd9\x67\xec\x58\x20\x8b\xa6\x74\x03\x73\x03\xdf\xc6\x19\x0d\xa7\x83\xff\x27\x30\x3b\x86\xb5\xfc\x32\x11\xf0\x1c\x91\x5e\x83\xa6\xad\x01\x21\x44\x79\x11\xcb\xe1\xcf\x69\x6f\x61\x8f\x60\x23\x66\x43\xf2\xe9\x4e\x15\x5d\xb6\x57\x18\x29\x44\xc1\xa4\x3b\xdc\x7b\xd5\xea\xf3\x48\x1f\xe1\x28\x40\x92\xcb\x37\x89\xa8\x92\xbd\x79\xa1\x11\xfd\x41\x01\x43\xcf\x91\xae\x33\x28\x60\xb1\xd2\x9a\xa0\x41\xd1\x77\xb5\x0d\x6c\xc2\xb9\x66\x0d\x32\x8c\x0f\x23\x0a\x35\x15\xe6\xa0\xd6\x88\x70\x9c\x0c\xd3\x47\xad\x2f\xf3\x2d\x61\xd1\xe1\xe9\xba\x76\xf8\x1e\x87\x3a\x6c\x42\x0f\x17\x07\xf3\x84\x1d\xb5\x19\x6c\xb5\x3f\x50\x6f\x00\x06\x35\x2c\x7c\x44\xc0\x80\xf3\x09\x68\x01\xa5\x7a\x49\xcf\xe8\x42\x05\xbd\xd7\xa9\x80\x1f\x84\x3c\xf2\x6b\x95\x58\xa2\xdb\x78\x8e\xf1\xb2\x37\x91\x5d\x58\x7b\x9b\xa9\x77\x98\x90\xf6\x1f\xdc\x91\xe0\x3e\x4f\x4c\xdb\xef\xe4\x17\xcc\x22\xd5\x22\xa8\x6a\xdd\xdb\x53\xf3\x74\x74\x50\xab\x62\xb5\x76\x56\x5d\xb3\x2e\x0c\xd4\x42\x76\x54\x7d\x9a\x16\x65\x3c\x27\x96\x59\xdd\x4d\x17\xec\x04\x82\x7c\x53\x3e\x33\x39\x0f\xe9\x4f\x79\x35\x09\x25\x6d\xb6\x75\x31\x73\x6a\xb3\xfc\xee\x2a\x30\x1a\xc3\xf0\xa2\x4d\x3b\x10\x8d\x7e\x75\xc3\x2a\x5a\xba\x36\xd6"}, -{{0x29,0xb2,0x88,0x1b,0x8c,0xaa,0xdb,0x33,0x6e,0x78,0x80,0xc5,0x10,0xb8,0x00,0x85,0xf4,0xb1,0x22,0x18,0x60,0xb3,0x01,0xeb,0x45,0x25,0x65,0x07,0x52,0xa6,0xd2,0x89,},{0x0c,0x5c,0x44,0xed,0x29,0xd2,0x1b,0xca,0xde,0xe2,0x1c,0xbd,0xe6,0x1a,0x9c,0xdb,0x6d,0x59,0x36,0x00,0x9b,0xa2,0xf5,0xb2,0xe7,0x77,0xc9,0x24,0xdd,0xfb,0x67,0x51,},{0x99,0xe9,0x96,0xe8,0x5a,0x49,0x4f,0x19,0x80,0xcb,0x07,0xde,0x9c,0xa6,0x16,0x5e,0x7d,0xe1,0x04,0xd3,0x9f,0xe3,0xc3,0x22,0x67,0x35,0xc5,0xda,0xa5,0x69,0x51,0x6f,0xca,0xf1,0xb6,0xe4,0xdf,0xad,0x0d,0x38,0x9b,0x6d,0xb0,0xec,0x8a,0x8f,0x20,0xdd,0x2c,0x60,0x26,0x56,0xb5,0xe7,0x61,0xc8,0xf3,0xa6,0x55,0x83,0x82,0x15,0x19,0x09,},"\x19\x74\xa2\xe2\xb4\x79\x49\xf4\x67\xa9\x31\xd1\xd9\xdd\x5c\xe1\x16\xe9\xf5\x03\x0a\xd0\x9a\x8c\xc7\x28\xd1\xae\xb1\x48\xbb\xf9\xac\xf5\x98\x74\xda\x80\xe7\x08\xd5\x3c\x66\x8f\x2f\x14\xd7\x52\x20\x71\xe9\x09\x80\x84\x27\xb2\xab\x5a\x05\xf8\xb9\x4f\x21\x50\x5c\xd2\x6a\xbc\x53\x45\x89\x78\xc7\x84\xd4\x79\xea\x6d\xab\x10\x5c\x4f\x79\x84\xa0\xfb\x97\x90\xe5\x06\x24\xf4\x73\x4b\x55\x19\x05\xaa\x5f\xfa\x60\x18\x4c\xd2\x01\xcf\x2b\x26\xc9\x79\x5d\xa6\xe7\xe0\x8d\x6a\x0b\xc7\x72\x24\x00\xfe\xf9\x4f\xc2\x10\x38\xbe\x89\xd3\x4b\xcd\x14\xc4\x27\xb8\x5b\x68\x66\x73\x71\x96\x15\x2d\x4e\xeb\x66\xd0\x5b\x24\x5a\xe8\x4b\xdc\x77\x87\xc1\x4a\x8b\xec\x2e\xea\x53\x60\xf0\x42\x43\x3d\x70\x79\x44\x67\xd4\x73\x93\xb9\x37\x57\xf3\x31\xcf\x2b\x53\xc6\x60\xd7\x1c\x29\x58\x2a\xee\xa7\x9b\x12\x52\x7a\x28\xb0\xc5\xe1\x10\xdf\x6f\x85\x4e\xea\xd9\xa2\xb0\x0d\x42\x54\x2c\xa8\x27\x6b\xb8\xbf\x98\x8b\xaa\xb8\x56\x59\x96\xfe\xe5\x0c\xf3\x1b\x24\x59\xc4\xc5\x0a\xb4\x75\x26\x5e\x83\xe2\x28\x5d\x43\xfe\x1f\x75\x2a\x55\xb2\xdb\xc4\x9f\xca\x04\xa8\x10\xf0\x41\x3b\xf6\xbd\x81\xb7\x9a\xc6\x4e\xe1\xf8\x9b\x97\xbd\x7d\x26\xd6\x25\x12\x27\x3e\x24\xa6\xba\xb2\xd5\xf7\xd2\x22\x6b\xaa\xab\x7b\x11\x12\x09\xbb\x03\x73\x3d\x8a\x60\xdf\xa3\x1a\x51\x6f\x4a\x8c\x76\x99\xd8\x28\x5c\x10\x65\x15\x9a\x6c\x73\x31\xc1\xde\xfb\x47\xa3\x0e\xf5\x85\x8c\x50\xb7\xd0\x45\x12\x4a\x09\x81\x3d\x1c\xfd\xa5\xc9\xcc\x3b\xb5\xbf\xae\x73\xc9\x84\x19\x7f\x8f\x85\x7f\x18\x6c\x41\xab\x87\xfb\x79\x62\xb6\x31\xf4\xd0\x07\xcf\xbe\xe2\x21\xfc\x65\x72\x78\x4a\x55\x11\x94\xc1\x97\x77\xb0\x8e\x6b\x59\x67\x57\xe7\xcb\xa7\xa0\xe2\x7f\xe4\x53\xf9\x0d\xc5\x9c\xc0\x8c\x64\x72\x43\x1c\x02\x0e\x8d\xd0\x91\x75\x90\xe7\x9c\x1f\x20\x73\x83\xaf\xb3\x90\x76\xad\x24\xda\x8e\xe5\x24\x86\x73\x94\x53\xa2\x59\x0e\x51\xbf\xc8\x9b\x13\xc2\x03\x3c\xfa\x5f\x89\x03\xcb\xe9\x96\x1a\x85\x98\xba\x55\x62\x32\x86\x9d\xfa\xb4\xd5\x6e\xdf\x4f\x05\xe8\xb7\x7d\x05\x87\x18\x95\xe6\x3b\x53\x51\xf7\x6c\xb2\xd2\xc8\x38\x5c\x10\x9d\x73\x06\x19\x2a\x25\x44\x6e\x4d\x62\xdc\x7d\x62\x4f\x0c\x66\x73\x98\x6b\xe0\x62\x8b\x2c\x2d\x73\xeb\x94\x1d\x35\xa3\x43\x30\x90\xf5\x9b\x28\xa5\x97\x9d\x56\xdb\xc9\xfd\x69\x73\xf6\x36\x47\x64\x2c\xd9\x03\xb0\xcf\x7a\x6a\xcd\x33\x0d\x87\xe2\x29\x27\x10\xde\x99\xe0\xc1\x79\xca\x78\x92\x9c\xca\xec\xfa\xed\xbf\x27\x42\x41\x4f\x17\x6b\x60\x90\xc0\xd5\x9a\x9d\xb7\x81\xc9\x96\x7e\x28\xfa\x4e\x77\xd2\xa0\x82\xe4\x2f\x52\x16\x91\x67\xe9\x2d\x4f\xdd\x82\xe2\xcc\x05\xdd\x91\x84\xc7\xdf\xee\x49\x0a\x23\x7f\xda\xd4\xdf\xeb\xc0\x18\x68\xe0\xa4\x35\x3a\x29\x54\xd0\x90\x92\x84\x61\x82\x1a\x7a\x84\x8d\x1b\x60\x81\x7f\xc3\xbd\xef\xa1"}, -{{0x42,0xaf,0xe8,0x9d,0xac,0x83,0xe7,0xd3,0x89,0x96,0xc0,0xdb,0xce,0x0c,0x98,0x74,0xc0,0x09,0x27,0xba,0xbd,0x77,0xca,0x8c,0xea,0xc3,0x4e,0x56,0x44,0x74,0x28,0x2b,},{0xa4,0xc5,0xf5,0xe3,0x80,0x3f,0x0a,0x03,0xd5,0xc1,0xc9,0x06,0xca,0xec,0x9c,0xc6,0xd2,0x85,0x14,0x07,0xf1,0xca,0x29,0xf7,0x2a,0x45,0xf2,0x33,0xe6,0x65,0x62,0x44,},{0x4f,0xba,0x2d,0x6c,0xc1,0xb7,0x19,0x3d,0x35,0x62,0xf8,0xc8,0xbf,0xe6,0x90,0x5c,0x82,0x9d,0xb2,0x65,0xa5,0x42,0x7c,0x5c,0x26,0x57,0x14,0x78,0x5b,0x83,0xf6,0x95,0x14,0xc5,0xe3,0x0e,0x28,0xb5,0x66,0x84,0xc8,0x2d,0xae,0x26,0x37,0x58,0x1b,0xf3,0xf4,0xef,0x27,0x14,0x20,0xbc,0x7e,0x60,0x10,0x61,0x3a,0x38,0xfa,0x10,0x1a,0x0d,},"\xe7\x10\xa1\x63\xad\x28\x85\xae\xb7\x65\x8e\xb3\x74\xf1\x18\xb7\x68\x42\xec\x36\xef\x3b\x01\x0c\x3c\x6b\x95\x59\xe8\xb1\x60\xc2\x62\x8d\xed\x0b\x85\x11\xeb\x49\x07\x18\x0d\xa4\xb6\x21\xe9\xaa\x4a\x32\x22\x88\x88\x8a\x1c\x09\x13\x0f\x69\xf8\x90\x59\x7a\x92\x93\xe7\x4f\x92\x89\xbd\xaa\x5c\x91\xb6\xfd\x24\xaa\x04\x4a\xb9\xfc\xb3\x40\x2f\x7a\xbc\x48\xd2\xab\x7b\x38\x80\xa0\x48\xda\xa4\x48\x64\x5a\xd2\xec\xb5\x5b\x3c\xae\xe2\xd6\x8a\x8b\xed\xb5\xd1\x86\x5d\x5e\x21\x1d\xe3\x9b\x0e\xaf\x22\xe5\xda\xf1\x0f\x71\x68\x20\x3a\xa1\x5b\x85\xaa\x47\xbb\xd3\xcc\x41\x69\xcb\xc1\xfe\x80\xb4\x70\x0b\x62\x58\x71\xed\xab\xcd\x4f\xe7\x4a\x3e\x96\x55\x69\xce\x24\x5c\xfc\xde\x42\x09\xcc\x8a\xbc\xd6\x79\x7d\x44\x18\x5b\x4f\x96\xc0\x18\x1b\xbd\x27\x00\x87\x83\xe9\x35\x8a\x53\x94\xfe\x3a\x34\xa0\x68\x71\xd3\x79\xda\x35\xb2\x0b\xb5\x7e\xef\x9e\x55\x24\xee\x79\x12\xa6\xf4\x1b\x4a\x1f\x68\x4c\x39\x19\xcf\xcd\xc0\x0f\x45\x80\xba\xf9\xe0\x9d\x31\x6c\xef\xa0\xf4\x65\xdc\xa5\xd8\xee\xc5\x14\xe9\x5e\x5a\x57\xbb\xcd\x27\xe4\x1f\x81\x19\xb2\x64\xae\x14\xa3\x19\xd8\xc3\x85\x9b\xab\xf1\xf4\xa6\xb6\xb7\x7e\x44\x2c\x86\x1d\x6e\xe2\x8a\xd1\x2b\x82\x36\x2e\x90\xdb\x0c\x36\x72\xb0\xe0\xd9\xff\x58\x14\x6f\xd1\x59\xaa\x8f\xa9\x9d\xc7\x55\xfc\x85\xb9\x0c\xf9\x41\x92\x79\xc0\x62\x4b\x93\xe7\x5e\xda\x0e\xf7\xc0\x96\x95\xae\x93\xbd\x72\x82\x41\x93\x77\xb7\x6c\xa8\xbd\xc0\x52\x1c\xfe\xe6\xf6\xd7\x29\xc3\xad\xff\x89\x46\x87\xb1\x77\xef\x19\x52\x9a\x6b\xda\xce\x70\xb6\x85\xc6\xd7\xa5\xd7\x4a\x08\xe2\xa9\xe7\x24\x03\x59\x75\xc8\x0d\x18\xcb\x36\x94\x70\xde\x72\x99\xcb\xd6\xb0\xa2\x7c\x92\x32\xc7\xea\xba\xc8\x6d\x50\x93\xa6\x5f\xfe\x0b\x40\xd4\x0b\xef\xe8\x0b\x68\xcd\x9d\xce\x1e\xa1\xe6\x57\xe4\x5e\x9c\x49\x9d\x0b\x69\x0f\x74\x45\x5f\xb4\x70\x96\xed\x8c\x18\xd1\x51\x7f\x90\x44\x29\x01\xa6\xc4\x10\xb7\xf6\x41\x5f\x20\xae\x48\xc5\x8a\xde\x8d\x67\x5b\x6c\x05\x8d\xf1\x6a\xe7\x69\x8f\xce\xae\x95\xaa\x77\x1b\x4c\xd8\x8a\x0b\x3f\x22\xc5\x1f\x98\xc7\x1c\x1e\xb4\x6b\x26\x4b\xf9\x7a\x30\x0e\xcb\x1f\xd2\x62\x26\xad\x8e\x87\xa0\x58\xcf\x3e\x70\x8e\x26\x0f\x56\x6b\x68\x53\x14\x04\x51\x33\xf4\xa5\xe8\xfb\xc3\x45\x61\xb9\xa0\xf1\xff\x93\x39\xf5\x52\x31\x07\x6b\x73\x6b\x6e\x11\x52\x43\x19\xa2\x72\xbd\x44\x53\xa0\xaf\x14\x93\xda\xa0\x91\x67\xe8\x46\x43\xd2\x07\xa0\x2f\xee\x98\xfb\x22\x3b\x01\xa9\x9a\xa5\xce\xf2\xb7\x00\x1e\x47\x0f\x6f\x94\xa5\xdc\x20\x8e\xdf\xc0\xcb\x8c\xf3\x11\x4a\x91\x96\x00\xf0\x61\x17\x2f\x0e\xfe\x03\x90\x36\xbf\x4d\xdd\xbf\xd0\xd4\x5f\x91\x44\x3b\xf2\x6f\x8e\x15\xed\x7d\xb8\xe5\x5f\x08\x6a\x4a\x45\x83\xf4\xbd\xa0\xf5\x56\x28\x4d\xcf\x71\x29\x2f\xe7\x0f\xca\xa8\x25\x9b\x9f\xaf\xf3"}, -{{0x10,0xf0,0x09,0xaa,0x88,0x7d,0x91,0xce,0xd8,0x09,0xaf,0xe1,0x92,0xd7,0x8e,0x47,0x99,0xd9,0x03,0x77,0x62,0xf4,0xa9,0xd3,0xa4,0x29,0xfd,0xe0,0xf3,0x9f,0x7b,0x7a,},{0xcf,0x51,0x16,0xb9,0x21,0x21,0x2e,0x9b,0x78,0x82,0x9a,0x02,0x63,0x46,0x36,0x91,0xc6,0xfb,0xcc,0xdc,0x0c,0x11,0x8b,0xe1,0x41,0xc9,0x6f,0x8c,0x88,0x05,0x3d,0xd3,},{0xc3,0x7b,0xb7,0xb7,0x3b,0x11,0x05,0xbe,0x08,0x6f,0xf3,0x07,0x69,0x72,0x07,0x72,0x62,0xdf,0x4d,0x73,0x32,0xf6,0x08,0xc7,0xb2,0xb9,0xd9,0x78,0xd4,0x74,0xcb,0xbc,0x27,0x10,0x46,0x08,0x00,0x35,0xf3,0x96,0xee,0x36,0x47,0x9b,0x7a,0x67,0x11,0xc6,0x8e,0x25,0x61,0xc7,0x41,0xc0,0xec,0x5f,0xc9,0xec,0xa1,0x73,0x4e,0x81,0x1f,0x04,},"\x2e\xdf\x14\xd6\xcd\x56\x89\x6e\xea\xa7\x70\x21\x1c\x49\x84\xbe\xd8\x0e\xca\x8d\x65\x34\xd5\xd5\x10\x88\x4f\x55\xf1\x1f\x99\xff\xa9\xf8\x9b\x58\x6f\xfe\x7b\x1e\xc7\xea\xab\x6a\x9d\xc1\xa2\x4a\x3e\xe3\xc7\xa6\xab\x44\xad\xe9\x91\x78\x83\x26\x4e\xde\x2f\x13\x61\xbe\x7d\x7a\x38\x17\xf2\x9d\xec\x95\x81\xc3\x19\xf1\x8f\x95\xd5\xbe\x26\xd9\x11\x8b\xe6\x78\x34\x00\x37\xa6\x8a\xbf\xc5\xef\xbb\x9a\x3f\x3f\x38\x78\xaa\xe3\x72\x1f\xfe\xf5\xbb\x6a\x26\xc7\xb1\xa3\xa5\x6d\x2b\xda\x6c\x6e\x86\x0e\xb4\x1f\xd8\xd8\x37\x11\x74\xd9\x1c\x74\xc5\xeb\x67\xc3\x85\x5c\x63\x0d\x64\x1d\x2e\x57\x1a\x9a\x51\xc6\x40\x2c\xfe\x18\x42\xce\xf3\x89\x80\xcb\x8d\x0a\x64\xbc\xc8\x9b\xe3\x18\x9e\x68\x11\xf4\x7e\x8f\x4d\x00\x63\xa5\xb1\x60\x1f\x44\xfd\xa2\x0c\x1c\x4c\x2f\xc4\x9c\xbe\x27\xa4\x13\x7d\xc4\x63\x8c\x2a\xd2\xd0\xa5\x47\x47\x47\x22\x9c\x56\x8e\x38\x05\x43\x1f\xa3\x6e\xeb\xa7\x85\xf7\xb9\x78\x44\xb5\xe3\x19\xfa\x6a\x09\xcc\x5a\xe8\x40\x34\x74\xbb\x91\xdd\x89\x6c\x1e\xc2\xba\xc7\x3d\x2e\x50\x5e\xfc\x62\xbd\x50\x2b\x5c\xeb\x08\xd1\x6e\x83\x2e\xc5\xdc\x4f\x98\xb5\x1b\x9d\x07\x38\xb9\xfb\x28\xf3\xab\xe8\x96\x6b\xf2\x23\x75\xa0\xb2\x2c\x47\x1a\x9e\x58\xe3\xfd\x70\x0d\xe1\x5c\x52\x96\x37\x3c\x1b\xc9\xd4\x64\x0e\xb7\x81\x6e\x1d\xc9\xc8\xce\x86\x19\xa8\x11\x83\x00\x9e\xc9\x74\x87\x1e\x8f\x0a\x97\x72\xed\xe0\xa6\x38\xb3\x57\x4b\xf7\x5d\x8f\x55\x98\x7f\x3c\xfa\x6f\xec\x68\x97\x0b\xfe\x00\xb2\x3b\x59\xfb\x5b\xf4\x99\x6e\xa5\xd7\x70\x4f\xcf\x2e\xff\xcc\x0f\xd7\xf3\xd8\xe6\x05\x60\x08\x09\x7f\x26\xca\xff\xd5\x41\x5a\x28\x2a\x27\x6a\x9b\x26\x45\xe5\xca\xb1\x29\x68\x87\x2e\xb0\x52\xf4\xd7\xc1\x0c\xc7\xc2\x1d\x51\x61\x81\x8b\xb4\x4c\xc8\x56\xb0\xde\x76\x9d\x55\x9c\x55\xdf\x64\xad\x9a\xdc\x16\xc0\xac\x65\x83\x8f\x66\x0d\xa8\x13\x86\xb7\x0b\x93\x52\x5e\xc2\xf4\x0f\x6f\x63\xf8\xea\x5d\x48\x30\xb9\x64\x6c\x46\x18\x3b\xb4\xe6\xf2\x70\x47\xbd\xa2\xa5\x46\xbd\x34\xbd\x4d\xb5\xfb\x88\xfd\x8a\xb7\xc7\x5f\x65\x2e\x15\xd5\xaa\xa6\xb4\x6a\x8a\xcf\x6e\x44\x8b\xf2\xdd\x64\xde\xe3\xc1\x05\x64\x7c\x7f\x83\xad\x20\x0d\x80\x97\xc4\x44\xa1\x58\xd8\x5a\x54\xf0\xe5\xdb\xb1\x2b\x43\xde\x94\x3a\xf1\xa8\x18\x56\xac\x96\x9f\x52\xa0\xbd\x45\x43\x81\xbd\x26\x50\x41\xa2\x69\x1d\x1a\x4a\x0d\x81\x9f\xa7\x90\x92\xc8\x80\x35\x21\xfa\x53\x68\x9a\xb8\x52\xf1\xfb\xab\xe0\x0c\x94\xb7\xf6\x82\xd1\x21\xcf\xf5\x43\x91\x32\x25\x29\xc8\xd5\xad\x7b\xbb\x98\xea\xfe\x30\x0a\xb9\x22\xf1\xc8\x92\x40\xa1\xe6\x33\xcf\x56\xa7\xb0\x2f\x74\xa2\x92\x14\xe5\x69\xa0\x57\xbd\x58\x5e\x40\x4d\x7c\xd5\x35\x20\x41\x45\x6e\x6c\xf9\x0c\x15\x34\x2e\x02\x56\x70\xf4\xfc\xcd\xf9\x87\x83\xb6\x85\x32\x14\xca\xc3\xfa\x80\x8a\x66\xc2\x7b\x65\x3c"}, -{{0x45,0x78,0xc6,0x5a,0x7c,0xa4,0x8f,0x27,0x74,0x05,0x0a,0x7b,0x0c,0xe7,0xa4,0xfd,0x5a,0xd4,0xe6,0x96,0xb2,0xb8,0xaf,0x23,0x96,0x16,0x4a,0x1c,0x7e,0x1b,0x7b,0xd7,},{0x15,0xbf,0x9d,0xbd,0x3b,0x81,0x73,0xe6,0xf0,0x3d,0xcf,0xd5,0x75,0xd9,0x09,0x84,0x5f,0x03,0x8e,0xaa,0x09,0xc5,0xd9,0x08,0xfe,0xf9,0x08,0xa9,0x74,0x58,0xb3,0xef,},{0xa1,0xc2,0x42,0xb4,0x5e,0x94,0xfd,0x18,0x0f,0x05,0x4c,0x71,0x01,0xe5,0x5b,0x39,0x65,0x68,0xf4,0x83,0xdb,0x6f,0x0d,0xfc,0x41,0x68,0xb6,0x9b,0x59,0xd3,0x85,0x81,0x4c,0x19,0xeb,0x30,0x75,0x23,0x7d,0x1f,0xbb,0x1f,0xee,0xbb,0xfe,0xa5,0x0c,0x56,0x81,0x3c,0x8c,0x39,0xc2,0x27,0x52,0xe0,0x2d,0xb7,0xe5,0x7f,0x3e,0x3f,0xbf,0x0d,},"\x50\x6f\x32\xb9\x68\x14\x24\x3e\x4d\xd8\x87\x0a\x8f\xd6\x0d\xde\xf0\x9b\xb8\xc5\x63\x15\x10\x70\xd9\xbc\xb2\xb1\x60\xa3\xea\xbd\x71\xa0\x44\xd7\x1e\xc9\x3f\xba\x95\x28\x8e\xd6\xfe\x1a\x7b\x92\x16\x51\x60\x43\x07\xd6\x5a\x45\xec\x5d\x3f\x26\x31\xac\xe4\x0e\x58\xd5\x3c\x72\xe5\x26\x88\x6e\x16\x97\x2f\x6e\x0d\xb9\x4d\x57\xb5\x56\x34\xfd\x39\xd5\x5e\x9b\xb7\xf2\x12\xaf\xab\x00\xf7\x74\x64\x09\x26\x7e\x8d\x56\x5f\xf5\xc2\x25\x73\x33\xc3\xd0\x41\x52\x17\x4f\xe1\x2d\xe6\xa5\x7b\xea\x05\x7d\xc2\x19\xe2\xfb\xa5\xf1\x91\xed\x81\x41\xc0\x18\x96\x9d\xe1\x94\x72\xd6\xaa\xf7\x63\xf1\x9e\xc5\x54\x70\x2b\xb3\xdc\xbe\x13\xca\x9b\x23\xb2\x41\x8c\x99\xe7\x18\x38\xa8\x8c\xf4\x54\x72\x8c\xf9\x20\x8a\x16\xc8\x4e\xa3\x98\x29\xb4\xba\x9b\x4c\x77\xe1\x76\x11\x2b\xfe\x1b\xf3\x5f\x95\xc4\x02\x8c\x7d\xb8\x0b\x36\xfa\xa2\x9d\x2b\x89\xe9\xe8\x62\xf3\x10\x00\x06\x5f\x13\x9b\x3d\xa7\x7d\x9d\x86\x85\x30\x57\x4b\x7e\x39\x1e\xd9\x7b\x34\xf8\x78\x16\x4f\x6b\x8d\x87\xb4\x06\xc7\xdc\x78\x60\xa5\x17\x5f\x92\x0e\x5a\x62\xdc\x1f\xc8\x2e\xd8\x45\x25\x43\xb1\x07\x36\x0d\x35\xd2\xb4\xc4\x23\x9e\xab\x46\x6d\x32\xbf\xda\x34\xf5\x10\x37\xa6\xfa\xe7\x6f\x6d\x8b\x83\xe8\xf7\xf4\x89\xdd\x4c\x1b\x49\xc3\x8f\x53\x57\x6e\x62\x17\x2c\x17\xde\xe3\x66\x5f\xde\x8c\xbf\x01\x5a\xf9\x66\x5b\x0f\x1d\xa2\xfb\x77\xb1\x34\xf0\x4b\xe2\x71\xe4\x02\xf3\x15\x37\xc2\xfc\x05\xc2\xf9\xb6\xfc\x3f\xfe\x47\xde\x33\x69\x13\x38\x67\xc6\x9d\x10\xe7\xf5\x37\xba\xe4\x56\x7d\x46\x8e\x0f\x2e\xd8\x06\xfe\x33\x5f\x93\x9c\x75\x99\x4f\x36\x3c\xe3\xb7\x0d\xaa\x7d\x5b\xd2\x31\x7c\x83\x38\x51\xfd\x8c\xc9\x72\x51\xec\x41\x90\x23\xd9\xd0\x17\x4d\x84\xd5\x60\x9a\x69\x18\xa1\x74\x0e\xb1\xe3\x09\xbd\x12\x73\x66\xde\xb9\xc5\xab\x12\x99\x2e\x99\x02\xe0\x15\xfe\x58\xd6\xad\xbf\x52\xd2\x2a\x76\x0a\xcd\x63\xe1\xed\xd8\xf1\x38\xe9\xfb\x01\x37\x18\x86\x01\xe1\x97\x8e\x7d\x04\xfb\x2a\xda\x2b\x2a\xee\x12\xf4\x9f\x28\x36\xc6\x84\x2d\x88\xcf\x48\xc8\x66\xe3\xd3\x3f\xcd\x26\x9c\x27\x5c\x89\xc2\x5e\x36\x69\xca\x90\xde\x7b\x67\xa7\xe7\xa3\x82\xcb\x7e\xfa\x47\xe9\xc2\xbf\x76\x57\x1c\x79\xa2\x50\x85\xef\x02\x04\x87\x15\x2f\x06\xbf\xa1\x33\x01\x5a\x1b\x8f\x1c\x0f\x6a\x9f\x0e\xae\x1b\xa6\x2b\xf1\x04\xf1\xc1\x6a\xc1\x4e\x1e\x96\xc4\xeb\xdf\x06\x1e\x0c\xc7\x10\x1d\x38\xda\x7e\x9e\x09\x94\xda\xf0\xf3\x22\xaa\x3c\xfe\xf9\x1b\x61\x6c\x2d\x00\x06\x89\xab\x18\xed\x45\x26\x8d\xcd\x27\x50\x94\xf6\x56\xba\x3c\xf5\x15\x26\x10\x24\x74\x1f\x74\x44\xab\x7f\xc4\xde\xcc\xe1\x67\x56\x03\x2a\x1b\xe2\x70\xff\x0b\x03\x17\x54\x2b\xa0\x26\x62\x26\x0a\x37\x6f\xc9\x12\xcb\xb0\x29\xca\xc5\x45\x15\xf5\xa5\x51\x36\x4f\x6a\x99\xff\xad\x0b\x9c\xbc\xd0\xe6\x93\xb7\xa5\x21\xcb"}, -{{0xc2,0x1e,0x70,0xc4,0x6e,0xde,0x66,0xe6,0x8a,0x88,0x73,0xbb,0xc6,0x4b,0xa5,0x12,0x09,0x30,0x3a,0x0a,0xc4,0xfc,0x49,0xb1,0xd8,0x3e,0x81,0x93,0xad,0x46,0xc0,0x37,},{0x9f,0xbf,0x80,0xa4,0x25,0x05,0xd2,0xc9,0x52,0xf8,0x9f,0x45,0x58,0xc3,0xe6,0xd1,0x87,0xa7,0xbc,0x1e,0xf4,0x46,0xb2,0xe3,0x73,0x23,0x43,0xc1,0x3b,0x33,0xd2,0x00,},{0x0a,0xe3,0x43,0xbb,0x84,0xe3,0xa2,0x99,0x07,0x8e,0x24,0x34,0xba,0x22,0x00,0x22,0xf3,0x16,0x0f,0x96,0x8a,0xc0,0x44,0x82,0xbf,0x8c,0xad,0x13,0xb4,0x23,0xf2,0x67,0x0f,0x01,0xfb,0x5f,0x7b,0x32,0xc5,0x97,0x52,0x0f,0x84,0x60,0x7e,0x0f,0x79,0xc0,0x75,0xfa,0x70,0x78,0xe6,0xe6,0x9d,0x3c,0xec,0x31,0x92,0x65,0xd4,0x66,0x08,0x0b,},"\xf5\x5a\xa5\x70\xce\x4f\xc9\x5f\x73\xf5\x17\x20\xd2\x54\xe4\x69\x5f\xcd\xc8\x1a\xaa\x04\x01\x30\xc7\x68\x7f\x03\x9b\x8b\xa5\x9e\xd8\x57\xce\xb2\x9c\x12\x10\x25\xa8\x57\xfe\xac\xb4\xa0\x1f\x38\xe0\x11\x78\x31\x0a\xe6\xe3\x5c\x99\x8e\xbf\x89\xdd\x79\x05\x7b\x4a\xfc\x6d\xb3\x40\x60\x1c\x81\x70\x3c\x87\xa8\xc4\x0e\x5c\xeb\xb0\x44\x1d\xf7\x8a\x6d\xe1\x3a\x44\x7c\xb0\x16\xc6\x5e\x74\x1b\xb7\xdf\x30\x4d\x83\x05\x6b\x72\xc6\x82\xc7\x31\xfa\xc0\xa0\xc7\x0b\x78\x11\xca\x14\xa5\x01\x54\x61\x30\x99\xc2\xc4\x37\x52\x1c\x40\x4b\x63\x61\xde\x36\x21\xf8\xea\x56\xb0\x8e\xbf\xdb\x07\xb4\xf2\xbb\x8b\xa2\xec\xc1\x64\x33\x6d\xa8\xef\xc9\x42\x76\x6e\xf0\xc7\x4d\xfd\x3b\x49\xe0\x87\xe9\xa2\x7a\xe5\x4a\x7a\x2b\x98\x28\x1b\x9a\xf9\x3d\xc1\x1a\xa2\xf0\x92\x24\xab\x5a\x73\x0f\x02\x18\xf4\xa6\xe1\xea\x48\x85\xa7\x7f\xbd\x93\xa1\xc5\x82\x77\xd9\xe0\x1b\xe7\x3a\x25\xcd\xa9\x18\xfc\x27\xdd\xdb\x45\x3a\x5d\xa6\x90\x2a\xd0\x2b\xa0\x57\x75\xc6\x7e\x07\xbe\xa4\xdf\x86\x91\x34\x66\x74\x43\x65\xc1\x32\x6e\x0a\xb5\xe1\x25\x4c\x17\x96\x74\x47\xd5\x91\xba\x5e\xd1\xb6\x3a\x42\x54\x3b\x87\xfe\xd4\x14\x59\xa0\x89\xbc\xea\xff\x21\x98\x02\xa8\x7a\x87\x2a\x76\x3e\x69\x23\x33\xce\x1c\xc7\x39\x78\x25\x08\x4b\x2b\x83\x1e\x93\xd8\x0d\x67\x37\xf3\x29\x80\xf2\xf3\xae\x82\xc6\x21\x90\xfe\x3f\xa7\x00\xc5\xb7\x32\x9d\x6d\x50\x04\x2b\xdf\x83\x1f\x37\x54\x8f\xcc\x80\xb1\x1f\x57\xcf\x20\xf6\x7a\x3b\xb6\x51\xa7\xbe\xff\xcc\x48\xb7\x0d\x17\xeb\x60\xf7\x25\x9c\xc5\x3b\xf7\xff\x60\x80\xeb\x2b\xd0\x92\x3b\x04\x83\xaa\x30\x65\xa8\x95\x5f\x01\xd2\x3b\xa8\x09\x51\xe0\xae\xfd\x2a\x93\x72\x19\x15\x72\xbc\x52\x91\x6a\xa2\x2a\x2a\xec\x39\x37\x67\xfa\xfd\x08\x68\x39\xe2\x36\xfe\x04\x60\xce\x6d\x63\x9c\x7c\xe6\x9f\xe7\xf9\xd3\xaa\xd2\x13\x05\x73\x44\x35\x70\x44\x3b\xe6\xba\xb9\x3a\x06\xa5\x4b\x8a\xc2\x9b\xf3\x3f\xf9\x94\x9b\xc9\x21\x58\xe6\x92\x4b\x6b\x68\xec\xda\x5f\x6f\x3a\xaf\x42\xb3\xd2\x2d\xf6\xd5\xe6\x7d\x5c\xb3\xab\x71\xeb\x8e\xe0\xb0\xe6\x67\x32\xe1\xda\xca\x6c\xd6\x0d\x9a\xa7\x43\x05\xfc\xd5\x70\x07\x6d\x22\x8d\x44\x6d\x5e\xe5\x42\xb1\x04\x88\xbf\x8a\xa9\x88\xf4\x51\xfa\xeb\xe7\x4a\xb6\x69\xd6\x04\xd9\xdd\xb1\x51\x06\x62\x0e\xa0\x2e\x8d\xb3\x8c\xe6\x39\xb5\x74\x78\x12\xbb\x90\x48\xee\x8b\xf7\x2b\x1a\x95\x1a\x05\xdf\xfa\xc9\x54\x17\xcb\x43\xb0\x6d\xce\x61\xee\x3d\xa6\xf2\x83\x2e\xe8\x3b\x2e\x72\x88\xdd\xd6\x2e\xeb\x58\x93\xf7\xf2\xf6\xc8\x09\x0d\x99\xe3\x36\xc9\xf9\x06\x9e\x18\x15\x98\x58\x41\xbd\xd5\x05\xb5\xf8\x3d\x89\x5e\x87\x95\x93\xda\xde\xe7\x2c\xeb\x97\x65\x69\x9b\xf8\x0b\xd0\x6a\x5c\x55\x33\x1b\x25\x45\x52\x7d\x0c\x7c\xae\xce\x96\x58\x4c\xe3\xec\x7f\xe0\x22\x60\xf2\x0b\x8a\x1c\x06\x35\x76\x3f\xf4"}, -{{0xf2,0xc1,0x05,0x77,0xf7,0xdf,0x77,0xf0,0xc1,0x15,0x7a,0x8c,0x33,0x1a,0x7b,0xd2,0xae,0x63,0x86,0x67,0x0e,0xb6,0x5f,0x0f,0xae,0x12,0x23,0x31,0x69,0x0f,0x82,0x8a,},{0x0d,0x4c,0x34,0x0f,0xc2,0x31,0xaa,0xfb,0x3b,0x6f,0x74,0xb8,0x9b,0xce,0xf7,0xee,0xaa,0x0b,0x04,0xf2,0x93,0xec,0x85,0x44,0x24,0x7b,0xfc,0x3f,0x2d,0x57,0xc1,0xe0,},{0x60,0xb7,0x03,0x11,0x5a,0x32,0x2a,0xb8,0x92,0xc2,0x76,0xbf,0xd1,0x8f,0x70,0xa9,0xeb,0x0c,0x73,0x23,0xe2,0xc0,0xa6,0xeb,0x5f,0xc7,0xe3,0x30,0xb0,0xbc,0x3b,0x07,0xa5,0x78,0xa0,0x82,0x84,0x62,0x64,0xf0,0x32,0xc6,0x19,0x1d,0x04,0x0b,0xd9,0x8e,0x5d,0x5a,0x4d,0x4f,0x07,0x6f,0xb9,0x06,0x2a,0xcd,0x36,0xbe,0xa4,0x0c,0x91,0x02,},"\x38\xea\x1e\x02\x8a\x49\x3d\x1c\x60\xec\x70\x74\x9f\x14\xd4\x36\xeb\x3a\x2b\x2d\xe5\x4f\x21\x3d\x01\xa6\x45\xb5\x80\x43\x0e\xcd\x8e\xce\x6b\x55\x69\xcc\x01\x7a\x49\x43\xe5\x59\x5c\x5e\xd6\xe4\x8c\x94\x43\xf2\xfa\x5e\xb2\x22\x7f\xfe\x56\xd2\x11\xf2\x69\xbc\x8f\x6f\xa9\xee\x8c\xd5\x6f\x6b\x84\x70\x53\x92\x08\xaf\xe2\x9a\xb0\xa1\x95\x04\x4d\x95\x7b\x31\xf9\x3e\x18\x4a\x9c\xbe\xf1\xa1\x4e\x14\xf8\x08\xbb\xf5\x89\xac\x77\x70\x08\x4f\x99\x8e\x1b\x25\x4d\xa5\x9c\xa6\xd3\xe6\x2e\x7b\xe1\x79\x07\x16\xd2\x56\x0f\x01\x5f\x39\x9c\xbb\xce\x48\xcf\xd0\x39\x1e\xad\x19\x93\x44\x6f\x6b\x24\x93\x97\x7d\x93\xd7\xb0\x9a\x07\xa7\x9a\x59\xce\x15\xdc\xe7\xa1\xda\x9c\x64\x6f\x45\xaf\x2c\xca\xd5\x5b\xa1\x58\xe6\x38\xc4\xa3\x0c\x5d\x30\xe9\xac\x6e\x3a\x33\x39\xc2\x43\x42\x6d\x86\x49\x1b\x2d\x92\xda\xc1\x47\x8e\x8d\x74\xff\x0b\xf1\x49\xbd\xb5\xe0\x9e\x3f\xb6\xb8\x26\x2e\xb0\x68\x79\x81\x55\x4a\xe2\xcb\x47\x19\x63\x39\x07\x9d\xa0\xa1\xa5\x72\x39\xc1\x9b\xf7\x81\xf6\x2f\xda\xf4\xe3\x15\x60\xa8\x43\x17\xef\x03\x04\x92\xcf\x1b\xb1\x30\x5b\xa8\x51\x8e\xba\xf2\xb4\x34\xd3\x64\x16\x72\xc8\xf6\xea\x2d\xef\xa6\x96\xdc\x7e\x4f\x39\xef\xc0\x8d\x28\x8d\x1c\x96\x6a\x6c\x71\x48\xc0\x12\xee\xc4\x39\xf7\xe1\x2d\xba\xb5\xb8\x7c\xfa\x44\xc9\xae\x19\x00\xf8\x38\x6f\x24\x44\x4e\x10\x92\xb2\x3a\x27\x4c\x13\x8e\x95\xc6\x61\xe9\x37\x7e\x8a\xd2\xd1\xfc\xaf\x19\x39\xec\x9a\x63\x2a\x87\x3f\x7e\xad\xbe\x68\x7b\x4a\x03\x3b\x92\xa4\x77\xf2\xe0\x2e\x9e\xd9\x2c\xe4\xf9\x5c\xf1\x70\xb3\x90\x15\x18\xa0\x62\x14\x3e\x56\xdb\x05\x4d\xf4\xe4\x43\x15\x44\x78\x5a\x6d\xfa\x24\xee\xc0\xf0\xde\x7a\x69\x9c\xcf\x28\x6d\xad\xfa\xd8\x59\x03\x61\x22\x50\x76\x4f\x25\xcd\xea\x81\x27\xd0\x07\x8d\x55\x48\x25\xea\x6e\x73\x71\xc4\x38\xbc\x46\xf2\x9f\xb8\x93\x7f\x8d\x9a\x39\xcf\x88\x49\x05\x2d\x43\xec\xbf\xf6\xc4\xa3\x76\x2a\x5f\x40\x0c\x15\x14\xe8\x5e\x91\x38\x4f\xef\x9b\x40\xf4\x31\x4e\x22\x3a\x9d\x68\xc5\x26\xac\xc7\x02\x27\xd6\x2b\x8b\x63\x7a\x34\x2d\xf1\x13\xd3\x18\x20\x2c\x51\xed\xd3\xc1\xef\xd1\xff\x20\xb1\xff\x07\x8b\x32\x06\x8e\x79\x4d\x92\x81\x33\x03\x7f\x1e\x3a\x34\x68\x9e\x62\x9e\x43\xfd\x2b\x8e\x88\xea\xb5\x0d\x7e\x7a\xb0\x64\x70\x14\xab\x5e\x4a\xd5\x82\x00\x65\x67\xef\xf7\x2b\x5a\xf2\xda\xc5\x36\x89\x2c\xcc\x87\x1f\x8a\x80\xb5\xcb\x79\xd9\x0b\xcc\x6b\x77\xd4\xcd\x08\xf8\x76\x18\x4e\xf5\x8c\x06\x4a\xe4\x30\xbb\x79\xa6\xb9\xe9\x6b\x0a\xd8\x73\x68\xaa\x83\x8a\x8d\xcc\xff\xac\x0c\xd8\xce\x9e\xa0\xd0\xec\x4c\x4b\x0f\x42\x67\x34\x16\x65\x9c\x98\x49\x92\xcf\x53\xb1\xe4\x45\x43\x10\x07\x64\x0d\x47\xec\xe2\x6d\xee\x4a\x29\x43\xaa\x70\x97\xdd\x35\x6c\xff\x47\x54\xf2\x1a\xc0\x7f\x6b\x3f\x73\xc4\x69\x05\x55\x12\xf3\x7a\xba"}, -{{0x04,0x1a,0x97,0x90,0x6b,0x59,0x56,0xb9,0xd3,0x40,0xf2,0xe0,0xd7,0xa1,0xdc,0xbf,0xef,0xe6,0x63,0xe9,0xbb,0x40,0x26,0xf8,0xcc,0x1a,0xe7,0xe2,0xa1,0x4d,0xe2,0x7e,},{0xf3,0x82,0xd3,0x2e,0x88,0xc3,0xa7,0x2c,0x7c,0xad,0xda,0xfc,0xf8,0xaa,0x69,0x9e,0x21,0xdb,0x7a,0x6b,0xf4,0xed,0xd6,0xe4,0x9a,0x00,0x5a,0xad,0x70,0x2e,0x6a,0x79,},{0xa2,0x3f,0x03,0x2e,0x66,0x92,0xa0,0xe8,0xbf,0xee,0x5b,0x2d,0x30,0xb4,0x14,0xcb,0x16,0xc3,0x5a,0xd0,0x8d,0xa3,0x1f,0x69,0x6d,0x46,0x1a,0x02,0x85,0x78,0x22,0xc4,0xef,0x35,0x7f,0x0c,0xcf,0x31,0x02,0x5a,0x4d,0xc9,0x5c,0xed,0x30,0xa9,0x94,0xf4,0x1e,0xdd,0x1d,0x08,0x7a,0xfc,0xaa,0xf3,0xe8,0xe8,0x75,0x70,0x83,0x20,0xf8,0x0c,},"\x71\xa7\x59\x57\x41\x15\x44\x97\x5a\x48\xcf\x10\x3a\xa1\xf8\xe2\xad\x15\x24\x44\x59\xcd\xc0\xe3\x36\x96\x6e\xb8\xb2\x6c\x97\xf2\x16\x9e\x5d\x78\x53\x70\x37\xef\xc0\x77\xe8\x6f\x06\xe0\x5e\x9c\x1d\xc3\x41\x82\x88\xc0\xa2\xbe\x6b\xa3\x4b\x3a\x04\xab\x20\xba\xe7\xf3\x62\x10\x94\xb8\x7d\x78\xa7\xea\xcb\x86\x4d\x40\x78\xcb\x4e\xfc\xba\xc5\xad\xd9\x37\xa2\xc6\x01\x2e\xe1\xa8\xb2\x56\xcc\x27\x6b\x65\xd5\xe9\x2b\x4d\x00\xb9\xb1\x1f\xad\x88\x49\x91\xde\xc4\xc1\xcb\x9d\xce\x18\x63\xc8\xb0\xa2\x10\x16\x1a\xe6\xb3\xf8\xbf\x9c\xc4\xdc\xe4\xad\xfd\xc8\xed\x57\xd8\x3e\x95\xab\x9d\xd2\xd9\x26\x58\xdf\xbd\x3a\xfa\x99\xe3\xf8\x95\x1e\x2a\xd7\x4a\x14\x8f\x6f\x59\x7e\xb2\xc9\x45\xc1\xf1\xb9\x44\x61\xae\x07\x45\x48\x1f\xd0\xed\xf8\x38\xc6\x28\x60\x35\xe3\x6f\x01\x12\x38\x87\x5d\xbb\xa2\x28\x9d\x3d\x6a\x39\x42\xa7\xf9\x55\x4c\x64\x43\x05\x24\x4d\xdb\x77\xc1\x17\xcb\x4b\x56\x23\x77\x29\xdd\xe4\x28\xb8\xbb\x42\xdf\x9c\xe2\x9e\x14\x4d\xfc\x96\xcf\x6c\x67\x67\xb1\xee\x6d\x05\x3c\xe4\xf8\xbb\x20\x56\xab\x78\x10\xaa\x13\x68\xa8\x91\x0f\x2f\x69\xe0\x61\xc1\x9d\x88\x47\x18\x4f\xed\x53\x4f\x98\x75\x8d\x70\x3a\x76\x88\x5f\x91\xeb\x75\x2a\x21\x95\x4a\x10\xc6\xf6\xb4\xda\x10\x46\x4d\xed\x36\xb0\x00\x89\xf6\x62\x91\x54\x21\xbf\xda\xd4\x96\x75\x36\x89\xcc\xd0\x3b\x62\x40\x21\x08\x07\x61\xe6\x81\x76\xb1\x06\x97\xda\xc8\x78\xe4\xc3\xdb\x2f\xd0\xb2\x8c\x65\x53\x35\xd9\x80\x16\xf1\x9f\x26\x5b\xb0\xb2\x43\x4c\xb4\x63\x78\x44\xd9\x1e\xd0\xce\x05\xed\x25\x91\xfd\x99\x89\x65\xf8\x3f\x31\x97\xd1\x0e\xef\x44\x88\x50\xe7\x92\x03\x27\x24\x70\x1d\xa3\x05\xcb\x6d\x79\x46\x69\x48\x3f\xc3\xdc\x6f\x68\x6b\x18\x3e\x29\x99\x13\x0c\x8f\xc0\x05\x8d\xca\xbb\xc9\x18\x8f\x26\xb2\xd6\x3e\xbd\x6c\xb1\xe1\x8a\x09\x7c\x77\x04\xa5\x9b\x5e\x18\x7e\x01\x42\x59\x3b\x70\x83\xf7\x40\x0a\xfa\x9b\x1b\xf0\xc1\xcc\x6c\x35\x6b\xc4\x33\x4a\xf7\x72\xe6\x71\x53\xb4\x5b\x33\x1b\x99\x09\x20\xc2\x4e\xed\xe2\xc6\xe3\x23\x70\x3f\x52\xec\xd6\x07\x35\xb2\x3b\xf2\x2b\x81\xee\x77\x59\x27\xc3\x7e\x53\xda\xd7\x59\x6e\xa6\x5a\x73\xbb\x96\x77\x5f\x3b\x87\xc8\xb3\xc0\x88\xec\x69\x5b\xc3\xa7\x50\x2c\x0c\x51\x0f\x02\x0b\xf9\xac\xa3\xcb\xb7\xa2\xc0\x11\xc6\x7f\xf2\x7d\x63\x4c\xaf\x1d\xcf\xc5\x8e\x5e\x39\x7e\x66\x58\x25\x22\x72\x01\x1c\x8f\xfd\xd6\x42\x30\xa9\x32\x41\xff\xf6\x83\x72\xc4\xba\x85\x38\x2b\xbb\x22\x93\x09\x65\x29\x22\xdb\x68\x83\x66\x31\xe5\x5b\xe6\x9a\xb6\xad\xb8\xe4\x33\x53\x57\xfc\x92\x3e\xfe\x15\x4a\xfc\xc2\x22\xd6\x0d\x07\xf5\x69\x90\xa3\xe5\xa2\x14\xb2\x27\xae\xcf\xf2\xcd\x1b\xb6\xf0\xc7\x9f\xf5\x45\xf7\x0a\x61\x61\x41\xa9\xd5\x3f\x92\x2a\x02\x44\x3f\x7d\x2a\x46\x89\xc3\x5b\x09\x5d\xd3\x94\xd5\x0b\xf4\x9f\x96\x80\xa5\xf7\xd9"}, -{{0x4b,0xc5,0xe0,0x5a,0xa0,0x03,0xa4,0x49,0x2f,0x4b,0xad,0x10,0x2a,0x53,0x90,0xf7,0xce,0xba,0xb3,0xd3,0xec,0xa9,0x15,0x21,0x42,0xad,0x5e,0xf7,0xd8,0x40,0x30,0xae,},{0x67,0x51,0xd3,0xad,0x8b,0xb6,0xc6,0x4d,0x6a,0x17,0xd7,0xe4,0x47,0xa2,0x7d,0xa2,0x2f,0x5f,0x04,0x03,0xf4,0x37,0xba,0xc9,0x44,0x9f,0x13,0xcc,0x85,0x3d,0xd8,0x40,},{0xa2,0x4f,0xee,0x11,0xf7,0xec,0x6d,0xa3,0xe9,0xdf,0xaf,0x6c,0x85,0x8a,0xc0,0x04,0xb4,0x53,0x1a,0xbd,0x1c,0x9d,0x3b,0xb6,0x4f,0x40,0xdd,0x24,0x7f,0x00,0x35,0x93,0x50,0xe4,0x3b,0x2d,0x4b,0x8f,0xbe,0xc5,0xf6,0xb2,0x41,0xec,0xf9,0xf1,0x10,0x14,0x85,0xcf,0x41,0x87,0x35,0xb0,0x5f,0x71,0x20,0x18,0x33,0x5b,0x20,0x06,0x83,0x08,},"\xa8\xf7\x94\xdb\x17\x95\x66\x7d\x28\xd2\x4b\x70\xac\x22\x00\xa6\x23\x9a\x34\xe2\x43\x8c\xed\x1d\x03\xf9\x7e\xd4\x8b\xeb\x4d\x6b\xea\x67\xc1\x43\x38\xf7\x73\x64\x19\xdc\xd2\xa2\xa7\x97\x37\x26\x57\x2e\x6a\xfe\x7e\xdf\xef\x22\xc9\x9b\xe8\xb0\x69\xf0\x4f\x6d\xc6\x1a\x13\xb3\x43\xc6\xe5\x85\xab\xad\x22\x14\xd8\x5c\x36\xf0\x29\x96\xfa\xbb\x46\xbb\x91\xb5\x17\x6a\xc7\x08\xe4\x9a\x0b\x05\x30\x17\x04\x8f\xbb\x55\x45\x3f\x2b\x82\x08\xd6\x67\x8d\x1a\x8c\xf6\xa1\xee\x9a\xd7\xa9\x1e\x38\x03\x25\x63\x5d\x1e\x23\x6a\x6c\xa1\xd6\xcc\x7f\x6b\x59\xf2\xa2\xbf\x18\x4f\x5e\xe4\x51\xd6\x79\x9f\x69\xba\x11\xa0\xcd\x6b\xc0\x4b\xe8\xa3\x51\xa8\x0e\x72\x5b\x5f\xc4\x56\x3e\x45\xbd\x47\x49\xec\xbc\x45\x20\x52\x29\x10\x5b\x9d\xe7\x32\x61\x49\x85\x27\xf3\xd4\xec\xfb\xb5\x83\xff\x53\x27\x53\xd0\x7c\x38\x52\x6b\xb4\x82\xd1\x71\xa2\x61\xb9\xcf\x89\x90\x6a\x7d\xea\x8c\xbd\x7e\x72\x6b\xa3\x1e\xa6\x88\x03\xa6\xb0\x04\xf6\xdc\xd1\x9e\x67\x19\x50\x46\x37\x38\xcc\xa7\x8b\xb0\xdf\xfa\x3d\x64\x57\xe4\xae\xca\x65\x7e\xc6\x49\xb9\x7e\xe3\x0e\x97\xc8\xcb\xe6\xce\x43\xc2\xaa\x9a\x69\x95\x8e\x9d\xc8\x81\xe4\xaa\x7b\x32\x78\x07\x4e\x78\x7a\xce\x5f\xb6\x01\xd7\xfa\xf7\xca\x51\x03\xec\xbb\xd3\xbd\x55\x4e\xb1\xb0\x66\xf8\x29\x6d\x2c\xc5\x7e\x8c\x8a\x32\xe9\xc0\xe6\xa9\x26\x96\x4d\x6d\xf2\xd8\x64\x58\x64\xb3\x22\xc3\x22\xf1\xca\x80\x73\xce\xdf\x2b\x55\x67\x11\xa7\xa2\x0b\x77\xc0\xa1\xed\x27\x7a\x9a\x6c\xa2\xc0\x71\x54\xe8\x63\xfe\xf5\xa4\x04\xe3\xe8\x9f\x0d\x7f\x30\xf2\x18\xec\x4d\xe7\xa5\x3a\xeb\x9c\x41\xee\xaa\xf6\xce\x74\x96\x49\xc9\x99\x8f\xd6\x2b\xcb\xa2\x87\x23\x38\xe1\x9c\x94\xe5\x9d\xd5\xe2\xdd\x77\x6f\x53\x71\x9d\x21\x74\x69\x76\x93\x2e\xf1\x1a\xbf\x7a\x32\xae\x6b\x07\x44\x66\x5d\x0e\x0c\xe5\x13\x95\x5a\x9e\x68\x53\x1d\x8e\xe4\xde\x9a\x8d\x35\xdd\xfb\x88\xeb\x5a\x48\x6a\xd6\x31\x37\xe8\x89\x2f\xd7\xc6\x89\xd4\xf9\xe7\x02\x1b\x11\x73\xbb\x37\x52\xa5\xee\xcf\x29\x92\xe3\xfd\x46\x42\x26\x3c\x7b\x3d\x81\x5c\x29\xb4\x66\xab\x69\x28\x5f\xfe\x4b\x8d\xaf\xcb\xf3\xd0\x1d\x63\x55\x53\xab\x75\x75\xa7\xa3\x47\x1e\xdc\x7b\xe4\x12\xd3\xd0\x1e\x6f\xe8\xe3\xcd\xc3\xfa\x04\xd2\xa7\x59\x93\x81\xe2\x2b\xba\x49\xc5\x53\x9d\x79\xc6\x2b\x52\xbb\x0e\xca\x33\xf7\x42\x55\xe4\x1a\x95\x26\xa8\x92\x89\xb1\x5f\x18\x50\xd9\xaf\xa8\x7e\x6b\x6f\xa1\x27\x10\x1c\x1a\x6d\x88\xd4\x33\xe0\xc8\x6a\xa6\x0b\xba\x8f\xe7\x10\x0e\xd6\x1d\x5a\x9d\x00\xa0\x07\x64\x51\x3e\xb1\xc7\xf5\xf5\xc3\xb3\xef\xc4\x53\x2a\x36\xb4\x07\xfe\x2d\x17\xcf\xb4\xe6\xfc\xd6\x04\x9c\xff\x3a\x35\x56\x23\xa3\xa4\x13\x90\xea\x48\xf4\x21\x20\xd8\x97\x94\x91\x11\xbe\x3d\x16\x9b\x2d\x2e\xf4\x5b\xdb\x89\x4f\xe2\x0b\x1a\x95\xef\x66\x14\x94\x27\xa9\xd8\xf8\x0a\x9b\x2e"}, -{{0xa3,0xbe,0xd9,0xfe,0x23,0x54,0xbd,0x28,0x60,0x14,0x9a,0x3d,0xb7,0x5a,0x85,0xb1,0x29,0xcf,0x83,0xe9,0xd7,0x3e,0x63,0x17,0xba,0x70,0x54,0x52,0x19,0x33,0xf8,0x96,},{0x5a,0xc0,0x3b,0x4f,0x13,0xd9,0x1d,0x06,0x6b,0x2c,0xe3,0x59,0xe9,0xbb,0x1d,0xfb,0x6b,0xfa,0x5a,0xfa,0x38,0x2f,0xd1,0xcc,0xd7,0x2a,0xef,0x11,0x76,0x07,0x9f,0x89,},{0x33,0xbc,0x1e,0x0b,0xf1,0xb4,0x93,0xe0,0xcf,0xb7,0xea,0x40,0x48,0x0a,0x14,0x23,0xe0,0x91,0xf7,0x14,0x57,0x45,0x01,0x31,0x73,0x78,0x7d,0xf4,0x7a,0x10,0xdb,0x24,0xc1,0x65,0xd0,0x05,0x96,0xfa,0xb7,0x0e,0x68,0xc9,0x4c,0x10,0x4e,0x8a,0x74,0x07,0xcf,0x69,0x5c,0xd3,0xfb,0xe5,0x85,0xb5,0xb1,0x76,0xb8,0x5c,0xcc,0xa4,0xfd,0x08,},"\xdb\x85\x38\x08\x68\x6d\x6d\x21\xf4\xc5\x7b\x54\x1e\x5a\xd6\x33\x94\xd4\x65\xe6\x00\x78\x64\x3c\xab\x1e\x06\x5c\x9f\x30\x6c\x50\x00\x78\xf0\xcc\x41\xef\x0f\x95\x42\xb5\xfe\x35\x6a\xec\x47\x77\xef\x8a\x95\x55\x4c\x97\xb6\xa4\x40\x99\xe9\xbd\x64\x04\xfb\x0b\x2e\x41\xf9\x19\x14\xb0\x74\xd1\x22\x37\xcd\x44\x2e\xbd\x40\xb5\x1b\x8b\xc8\xbb\xe4\x37\xa2\xc5\x33\x32\xd2\xbe\xb2\x28\x1b\xf7\x32\x4a\x0c\xf5\xb7\x41\xbb\xf9\x8d\x1e\xb9\x85\x8b\xe9\x26\xe9\x15\xa7\x8e\x8d\x31\x4b\x41\x44\xf3\xd2\x0d\xfc\x6c\xb7\xf4\x8c\x23\xaf\x90\xf8\x71\xc6\xcd\xa9\x08\x45\xa4\x1a\xff\x17\x07\xa8\x7b\x4e\x55\x16\xf1\x8e\x8b\xd7\x68\x3c\xfd\x74\x07\x08\x03\xe8\x88\x33\x8c\x9a\x18\xf7\x92\xc8\xd3\xa7\x04\x17\x0f\xf9\x82\xbf\xfc\x9e\x8e\xc9\xea\x5d\x1a\x62\x59\x2f\x16\x88\xd4\xf2\xb0\x1e\x11\xf9\xf8\x87\x74\xc4\x7a\xc1\xd5\x8f\x69\x0b\xcf\x28\x8c\xf8\xa4\x73\xd3\x50\xa8\x23\x9d\xf9\xd3\xa6\x28\x81\xda\xdd\x33\x85\x31\xfd\xce\x76\x15\x80\x7c\xe9\x65\x49\x6d\x6f\x35\xd6\xc0\x42\xf0\xce\x7f\x21\xef\xe5\xce\x64\x25\x18\x59\x41\xed\x56\x36\xb8\xae\x91\x3a\x75\xd2\x1a\xb9\xdb\xdb\x3c\x3b\x66\x87\xa4\x5e\x04\x49\x38\xa9\xf1\xc1\x3a\x33\x0e\xa9\x76\x1e\x28\x3e\x61\xd4\xa3\x20\xe1\xf5\x59\x88\x2f\x34\xb6\x07\xfe\xfe\x32\xc3\x43\x17\x4a\xbc\xdc\x77\xb0\x65\xa9\x29\x04\xb4\x2d\x96\x1d\xb8\xed\x91\x6c\x01\x46\x4f\xfd\x43\xf9\x3c\x10\x77\xf1\xdf\x7e\xe6\x50\x31\xcf\xe0\x5d\x78\x0d\x01\xd0\x8e\xe0\x36\xf2\x2a\x2b\x05\x12\x19\x3b\x0c\x0f\x38\x01\xe0\xa0\x20\x8e\xef\x24\x5c\x9e\x51\x93\x52\xd2\xb0\x09\x63\x82\xf2\xcb\xa0\x6e\xb2\xa0\x1d\xac\xf6\x19\xea\xbb\xc8\x83\xc5\xd4\xf2\xfd\x7c\x34\x23\x17\x9c\x0f\x5f\xfd\xaf\x8c\xaf\xff\x5c\x46\xb3\x4a\x09\xc3\xc5\x0e\x29\x49\xc0\x60\x00\x20\x7d\x70\xd3\x7d\x65\xa7\x43\x07\x5f\xdc\x2b\xe6\x2d\x41\x2a\xa6\x3e\x36\x37\x06\xca\x90\xe6\xef\x44\xe1\x52\xea\x4d\xc5\xc2\x89\x3e\xcd\x08\xd7\x96\xd4\x1f\x17\x22\x54\xc3\xd1\xd1\x4b\xb0\x67\xb5\x3a\x08\x97\xbb\xd7\x3c\x99\x54\xd9\x64\x8b\x2a\xf1\x0d\x9c\x27\x03\xe3\x8b\x6c\x62\x46\x9f\x6f\x95\x8a\x1c\xa0\xa3\x20\xc1\x23\x39\xe9\x0c\xf7\x68\xc8\x7b\x47\x38\xc2\x19\xf8\x09\x3b\xff\x4c\x2c\xfd\x29\x45\x9f\x6d\x32\x81\x34\x93\x78\xe9\x15\xa3\xb0\xe7\x24\xc7\x4d\x2b\xd7\xa8\x51\xac\x7c\x6b\x48\xe8\xaf\xc7\x12\x4f\xdc\xbc\xab\x5f\xf8\x0d\x1d\xee\x30\xa6\xc0\x24\xcb\x43\x31\x97\x23\x66\xeb\xab\x26\xbb\xb9\xf6\x08\xca\xac\x7e\x51\x91\x4d\xf0\x58\xb9\xb3\x74\x5d\x98\xc5\xd2\x7e\x97\x10\x54\x75\xec\x01\x73\x77\xe6\x31\x61\x98\xec\xe4\xec\x59\x09\xf0\x4f\xc2\x7e\x7b\x38\x2e\x66\xad\xb6\x2a\xc8\xa9\x77\xf3\x76\xfd\x5d\xae\x43\x4f\xb5\x51\x75\x24\x9c\xa1\xab\x6b\xb0\x2d\xec\x06\x96\xf0\x89\xbe\x34\x54\x88\x7a\x0c\x32\x36\x1d\x17\x2b\xd2"}, -{{0x88,0xa2,0x4f,0x0d,0xf3,0xae,0x29,0x14,0xdf,0x79,0xda,0x50,0xec,0xf8,0xec,0xb4,0x2f,0x68,0xc7,0xba,0xad,0x3b,0x6c,0x3a,0x2e,0x0c,0xc9,0xc2,0x5d,0x09,0xd1,0x42,},{0x12,0xe6,0x60,0x3f,0x71,0x3b,0x23,0x05,0x35,0x85,0x68,0x71,0x00,0x18,0x68,0x5e,0x14,0x15,0x53,0xc4,0x75,0x91,0x39,0x6f,0xb4,0x25,0x9e,0x42,0xdc,0x53,0xb9,0xc9,},{0x17,0x07,0xcc,0x00,0x91,0x86,0xbf,0x3f,0x03,0xf7,0xbb,0x9e,0x3c,0xd4,0xcf,0x6b,0x73,0x7b,0x7a,0x6b,0xaa,0xde,0x7f,0xc6,0xc3,0xff,0x5c,0x12,0x25,0xdb,0xb2,0xba,0xf5,0x4f,0x47,0xc8,0x5e,0xaf,0xa1,0x32,0xc3,0x1e,0xac,0xa0,0x3e,0x6a,0xec,0x14,0x47,0x73,0x3f,0xac,0xd3,0x71,0x49,0xb7,0xc6,0xcf,0x0c,0xd4,0x1f,0x61,0x14,0x04,},"\x65\x4e\x9e\xdc\x69\xfe\x63\x4c\x23\x08\xba\x8c\x46\xa9\x55\xe8\x82\x45\x62\x86\xea\xe3\x59\x3c\xae\x73\x9c\x44\x86\x6c\x0d\xe9\xed\xcb\xbf\x0d\xb1\xc4\x41\x49\x66\x84\x67\x70\x9d\xc9\x70\x62\x98\xdd\x2e\xac\x33\x01\xda\xba\xd5\xbd\x8e\x93\xc5\xe8\xa9\x3f\x19\x4e\x0f\xc1\xd9\xf3\x76\xc1\x44\xc2\x93\xae\xfd\xa0\x86\xb2\x21\x8f\x2e\x9d\xfd\x7c\x2d\xc5\x2b\xa3\x3e\xb2\x29\xdc\xf7\xbb\x68\xce\x0f\x87\x6c\x5f\xd4\xe8\x1a\xfd\x80\x16\x9f\x73\xcf\x26\x4e\x5d\xc0\xce\x16\xe1\xb8\x76\xcd\x11\xc7\xad\x89\x05\x8e\xe0\x82\x0c\x40\x00\x5d\x01\xf1\x19\xf8\xbe\x6f\x1a\xfb\xe2\x4c\xa4\xae\xdc\x18\xe9\x78\x96\x82\x7c\x3e\xd6\x7f\xc4\x56\x30\xe7\x90\x3b\x7f\xee\x9c\x99\x0e\x36\x19\x37\xbf\x4e\xa0\xa4\xd8\xd1\x6c\xf6\xd9\xcf\x03\x81\xe9\x06\x5e\x36\x25\x14\x8f\x8a\xe0\x49\x1a\x03\x41\xd0\xff\x9f\x72\x7b\xe1\xf3\x10\xca\x1e\xc3\xf0\x10\x4a\xa0\x54\x32\x17\x84\xdd\x24\xd5\x3c\x98\x5b\x28\xd4\x40\x82\xf8\xe1\xc1\x08\xa4\x41\x09\x63\x8f\xf5\x11\x6e\xdd\x85\xae\xb8\x6b\x6e\xa5\x12\xa1\x9b\x60\x2e\xdd\x9d\x21\x10\x70\xd0\x44\xaf\x5b\xed\xb6\xc8\x52\x7b\xa3\x49\x1e\x34\x5b\xac\xc1\x30\xb3\x69\x60\x28\x2a\xe7\x37\xb8\x5c\x76\x92\x74\xf0\xf7\xc5\x88\xf4\x0e\x66\x25\xb2\x36\xbd\xc1\xa3\xb8\x73\x20\x46\x0e\xee\xad\xa2\x78\x12\x4b\x56\x68\x87\x4f\x39\xf5\x9c\x2e\x6a\xa2\x08\xc3\xb6\xa9\xb8\x45\xc4\xd0\xa2\x7a\x05\x46\x78\x6f\xa1\x3e\x51\xcc\x98\xb7\x3f\xd7\xee\x32\x7b\x62\x15\xec\x6b\x62\x9f\x4c\xc7\xe4\xbd\x3c\x0a\x3d\xb7\x8a\x21\xff\xfe\x24\xc7\x04\x38\x71\x6b\xc3\x7b\x8d\xa7\xc5\xff\x7c\x36\x88\xa9\x03\x39\xc2\x2e\xb5\x0b\x7c\x2c\xd3\x6b\x68\x83\x1f\xd5\x93\x91\x75\x68\x9b\xd3\xe2\x2c\x38\x81\xaf\x33\x7e\xe1\x44\x35\x70\x9e\x35\x10\x40\xef\x3d\xa9\x55\x72\x4e\x51\xc2\x4a\x5e\x2c\x09\xf8\x91\x80\x83\x93\xfb\xf8\xef\x7f\x1f\x5f\x02\x98\xde\xeb\xdc\xd8\xd6\x66\xcb\xcf\x3e\x86\x6c\x71\x89\x99\xab\x6b\x1f\xee\xc9\xc4\x7e\x02\xe7\xd6\x35\x40\xf8\x99\x63\xd5\x42\xc5\xd0\x1f\xb6\xfc\x30\x76\x89\x68\xae\x81\xb2\x0c\x35\x4b\x40\x00\xc1\x32\x77\x47\x64\xd6\xd4\x43\xad\xd6\x4f\x6d\xd7\x48\xf5\xfb\x5b\x7f\x6e\xba\x40\x1d\xb4\x31\x8b\xe9\x93\x98\x9f\xcc\x25\x77\x96\x1f\xa5\xad\x31\xf6\xa2\xa9\xd6\xa7\x55\x28\x58\x65\xcd\x5d\xc3\xa8\x8c\xfb\x5a\xba\x7d\x92\x3b\xaf\x78\xb5\xd1\x31\xb4\xc2\x14\xdf\x55\xb6\x17\x1f\x45\x20\x9e\x21\xca\x66\x45\x49\x0d\x3a\x36\x44\xdd\xa6\xdc\x92\x9c\x7c\x40\x95\x76\xd3\x71\x64\x75\x5e\xf8\xaa\xf3\xdc\xd4\xd2\x27\x75\xee\x7d\xea\x0e\x56\x5b\xd5\x47\x27\x92\x1c\x64\x9b\xc5\x1f\x20\xc1\xf6\x8c\x1f\xde\xac\x45\x5c\x67\xd7\x1a\x1c\xb8\x83\x7f\x46\x91\x44\x8b\xf0\xbf\x04\x4a\x46\xf1\x68\x5f\xbe\x22\xb1\xe0\x18\x77\xf7\x47\x7d\x34\x99\x40\x8c\x4c\x31\x65\x10\xce\x2e\x55\xb9\x80\x05"}, -{{0x18,0x4d,0x0c,0xe2,0xe9,0xdb,0x7f,0x25,0x7a,0x8b,0xf4,0x64,0x6d,0x16,0xd2,0xc5,0xef,0xc2,0x70,0x2c,0xed,0x02,0x6b,0x69,0x06,0xd3,0xc8,0xc0,0x11,0x8f,0x22,0x61,},{0xe9,0xda,0xb8,0xfd,0x9d,0x94,0xdc,0x9b,0x24,0xcc,0x79,0xc6,0x35,0xcc,0x57,0xce,0x66,0x51,0x89,0x82,0xba,0x3e,0x24,0x47,0x24,0x07,0x41,0xba,0xc0,0x73,0x0e,0xc5,},{0xb1,0xe3,0xbf,0x5f,0xa7,0x4d,0x7e,0x44,0x2c,0xed,0x9a,0x98,0xd9,0x27,0xd8,0xc4,0x5e,0x0e,0x64,0xd8,0x74,0xf8,0xea,0x59,0x20,0xa3,0x60,0xa4,0xbf,0x42,0xd8,0x3c,0xe1,0x8a,0x92,0x4a,0xc7,0x96,0xe1,0xa7,0x7d,0x1b,0x02,0x08,0x29,0x4b,0x50,0xf8,0x22,0x17,0x7f,0xdb,0xdd,0x45,0x8c,0x74,0x35,0x6f,0xcf,0x6b,0xd7,0x94,0x51,0x06,},"\x6a\x9b\x87\x6b\x0b\xf4\x18\x9b\x3c\xc1\x5f\x9e\xb4\xfb\xe7\x93\x2b\x55\x77\x89\x2a\x22\x20\x0c\xe1\x07\x15\x68\x53\xd6\xd3\xca\x36\x3f\x02\x5a\xd7\xa2\xd8\x62\xaa\xdc\x74\x2d\x94\x15\xbd\x8d\x1f\xca\x13\xc9\xdc\xa3\x58\x60\x44\xe5\x5a\x8c\xf5\xde\xe1\xce\x56\x45\x76\xe3\xe8\xe3\x65\x54\x05\x46\x50\x1b\x34\xca\x67\x5c\xf2\x00\xe0\x77\x1a\x81\x8c\x73\xd3\x7f\xcd\xa8\xcb\x15\xe4\x8d\x5a\x0b\x9e\xa3\xbe\xec\x0f\xf6\x61\x0b\x2a\x8a\x21\x4c\xa4\xf7\xef\xac\x0e\x71\x38\x10\x52\xd9\xbf\x3c\x00\xc3\x29\x59\x34\x74\xeb\xd0\xa6\x87\xa0\xb4\x1d\x14\x4b\x5e\x7a\xb1\x41\x2b\x97\x0a\x74\xba\xba\x4d\x27\x4b\xb0\xdb\xfd\xb0\x2b\x11\xf7\xf6\x39\x64\xba\x6f\x3b\xa0\xad\x23\x34\x1d\x08\x3b\x91\xa4\x30\x82\x39\xe3\x3d\x50\x82\x43\x96\x12\x65\x88\xde\x72\xa2\x39\x0c\x1c\x0f\xc0\x67\x47\xc2\x87\x72\xf6\x30\xbf\x4d\x14\x3f\x7a\x11\x59\xf0\x28\xc0\x93\x40\x48\x94\xe6\xd1\x6f\x63\x46\x35\xd4\xfc\x33\x0f\x3d\x7a\x73\x13\xef\x75\x6f\x5d\x49\xd8\xf6\x20\x5e\xb1\xc7\x92\xa9\x49\x5d\xa1\x31\xb4\x33\x45\xa0\x09\x0c\x12\xca\x56\xe6\xad\xac\x5b\xe0\xcb\xca\xc3\x60\x9d\x69\xf7\x24\x15\xf6\xc3\x7f\x3c\xfb\x2c\xf7\x6b\x3e\x65\xf3\xc9\x3a\xc9\x2b\x63\xf2\xba\xa4\x66\x24\x90\x75\xbc\xa6\x9d\x4c\x1d\x1f\x3a\xde\x24\xab\x31\xef\xfc\xb9\x04\x69\xc2\x4b\xb4\x10\xab\x47\x23\xe1\xb7\xe1\xc8\x8b\x3a\x36\x43\x35\x63\xf7\x1a\x99\xaa\xd5\x8f\xe8\x05\x68\xf9\xc1\x02\xda\x89\xba\xd9\x79\x63\xe7\x7d\x66\x22\x48\x31\x66\xf3\xae\x26\x1f\x32\xa5\x2a\x86\x10\x1e\xbd\x64\x5f\x61\x42\xc9\x82\xe2\xcd\x36\x25\xcf\x8b\x46\xb9\xb2\x89\x12\x46\x92\x0f\x69\x7f\xca\xed\x39\x7c\xb9\x22\xc2\x74\x94\x51\x67\xa0\xe6\x19\xb0\xb5\x06\x37\x76\x06\xdb\x04\x57\x83\xb0\xb8\x8e\xa0\x4e\x93\x2d\x21\xff\xc0\x64\xa1\x2a\x40\xeb\xe9\xb4\x80\xf1\xa2\xc7\xdd\xd3\x95\xa9\xb1\x5e\xfd\xc4\x95\xc9\x71\x4f\x36\xfa\x99\x6f\x79\xf8\xeb\x8e\xfa\x52\xd9\x9a\x24\xab\xfe\xf4\x3b\x32\xa2\x37\xc5\xbc\x00\x18\xda\x3b\x16\x2f\x59\xb8\xd3\xd4\x74\xe2\xce\x08\xfa\x80\x24\xc5\x8a\xcc\x0a\x99\xff\x61\x4e\x6c\xd7\xfd\xd9\xca\x4e\x8f\x41\xa1\x44\x9a\xa6\x18\xd0\x33\x37\xe8\xa3\x74\xd5\x60\x55\xb2\x07\xa9\xdb\xe6\x9f\x59\x48\xf9\x01\xca\x7d\xb0\x41\x0f\x01\xaa\x37\x3d\x9e\x02\x27\x62\x35\x99\xbc\x21\x28\x45\xb0\x06\xe9\x42\xfa\xbc\x58\x2c\xd7\x26\xdb\x5c\x44\x3e\xb2\xdf\xfb\xc9\xe3\xe7\xf0\xe5\xcb\x67\x44\xf7\xad\x71\x60\x50\xfd\xf2\xc6\x0c\x7c\x77\xc2\x53\xab\x74\x5d\xb9\xc8\x55\x26\x55\x68\x3e\xa7\xea\x68\x0a\xa4\xaf\x34\xdf\x13\x25\xc2\x9b\x88\x74\xb6\x1b\xe2\x3d\xe4\xff\xba\x25\x42\x4f\x46\x19\xec\x68\x2c\x26\xb3\xa6\x7b\xda\x9b\xc4\xc9\x4b\x79\xa9\xfc\x4d\x82\xd3\x40\x49\x5b\x43\x7a\x1c\xbd\x6b\x60\x30\x7c\xfc\xb1\x00\x26\xf9\x64\xa0\x17\x62\x3e\x33\xdb\xf2\x33"}, -{{0xd0,0x2b,0xbf,0x70,0xd5,0x13,0x51,0xe3,0xb4,0x7a,0xd8,0xe5,0xed,0x26,0x3d,0xbf,0x55,0x6d,0x14,0x98,0xfa,0x9b,0xd5,0xdb,0xd9,0x9f,0xb4,0x26,0x90,0x09,0xdc,0xed,},{0x8c,0xe4,0xb5,0x9f,0x94,0xce,0xd6,0xec,0x96,0x14,0xd6,0x7d,0x30,0x66,0xd9,0xd3,0xa0,0xdf,0x7a,0x46,0xb3,0x7b,0x4c,0x17,0x25,0xef,0x1e,0x57,0xbc,0x68,0xa0,0xd1,},{0x6e,0x7c,0x66,0xac,0xc9,0x54,0xff,0xd9,0xdd,0x4c,0x1c,0x63,0x35,0xab,0x4f,0xe7,0x9d,0xbb,0xed,0x78,0x2c,0x4a,0x47,0xec,0x30,0xd8,0x48,0xd8,0xbb,0x2b,0x4f,0x10,0x69,0xdc,0x62,0xe5,0x22,0xa1,0xe8,0x01,0x7f,0x54,0xa6,0x34,0x5e,0x17,0x28,0xc0,0x73,0xaf,0x64,0x47,0x85,0x6d,0x8c,0x1e,0xd3,0x58,0x78,0xb5,0x71,0xe5,0x23,0x0d,},"\x55\x45\x60\xf7\xa7\xfd\x1a\xe7\x75\x8a\x2f\xce\x7d\x78\x0f\x6b\x3f\x04\x3d\x3a\xf8\x9d\x4f\x19\xef\x57\x3c\x34\x99\x75\x54\xdf\x24\x3f\xaf\x2a\xaa\xb6\x5b\x2a\xfd\xd2\x86\x10\xd4\xa5\x1e\x9a\x4b\x46\x4d\xb6\xdb\x09\xeb\xf7\x3b\x7d\x24\x05\x4c\xc9\xb1\x28\x14\xbb\x29\xee\x99\xe1\xa7\x3b\xd6\x03\x89\x83\x60\xf9\xdc\xf0\x1e\x67\x08\x36\x28\x6f\x82\x36\xed\x8c\xef\x07\x5f\x3d\x56\x33\x12\xc1\x6c\x73\xfc\x37\xee\xdf\x25\x2f\x8f\x42\xd3\x0a\x13\xe7\xfb\xa3\xb1\x65\x23\x8c\x7f\x81\xea\xae\xb5\x31\x90\xf3\xec\x3b\x5d\x63\xf0\xee\x03\xe3\x98\x7e\x39\x0d\x1d\x81\xe8\x27\x7e\x9f\x6c\x1e\xe6\xec\x4e\xc3\xfa\x0d\x72\x0e\x9f\x53\xf9\xc2\x6f\x04\xaa\x2e\xd2\xb5\xef\x31\x60\x89\x59\x99\xea\xce\x29\xcf\x5d\xc2\x54\xad\x71\x10\x6b\xb7\xe8\xbc\x29\xa5\xb1\xd2\x41\x25\x93\xd0\x81\x94\xe8\x8e\x16\x59\xa7\x31\x59\xa2\xa2\x20\x33\xab\x06\x6e\x8d\x3d\x8c\x3b\xc8\x6b\x7b\x01\xde\x81\xa8\xc6\x60\x47\xb0\x7f\xe2\x4e\xd2\x40\x31\x8b\xa3\x7b\xa3\xef\xb6\xcf\x63\x26\x04\xca\x4f\x44\x6a\x75\xfd\x8e\x70\xc4\x53\xf0\xc6\x0e\xe1\x6e\xca\xf5\x24\xe7\x03\xf4\x7d\xf5\xc2\x82\xca\x32\x89\xb3\xaf\x61\xde\xe4\x70\x9e\xe0\x85\x32\x3b\x1e\x5c\x8a\x6b\xc0\x76\x62\x01\xc6\x35\x03\x14\x46\x89\x1f\x34\x94\xe9\xdb\x20\xdd\x4e\x9e\x08\x38\x24\x9a\x67\xe1\x38\xd1\x3e\xe2\xc9\x6f\x61\xe7\x71\x06\x15\x42\xaa\x16\xef\x20\xd8\x1e\x3a\x0f\x4e\x45\x21\xa6\xcd\x6c\x92\xfc\x26\xfe\xef\x03\xb6\x6c\x70\xe0\x35\xca\xfc\xc1\x9c\x96\xfb\x9d\x82\x91\x8f\xe1\x97\x78\x0e\xff\x0e\xda\x6e\x25\x12\xc5\x6e\x2a\x73\xd7\x70\x32\xb7\x68\x91\x9b\xea\x97\x72\xf5\x98\x9c\x8b\x6c\x65\xc3\xd1\xe9\x7a\x21\x80\xcc\x3a\x37\x57\x9d\xa7\x0c\xe9\x80\x6a\xc1\x28\x5a\x3e\xab\x41\x5c\x06\x07\xd8\x8c\xb8\x65\x42\xea\xb9\x0b\x9d\x2d\x67\xfa\xff\xfc\xad\x23\xa7\x14\x00\x0e\xe5\x9e\xd6\x8c\x95\x6e\x81\xc4\x45\x42\x88\x82\xf9\x7a\xf7\x4d\xb3\x62\xe4\x5c\x0d\x1b\xd8\x85\x6e\xed\x16\x6e\x4a\xec\x4b\xfd\xf9\x5e\xad\xb2\x51\xe2\xa1\xef\x80\x48\x52\xa9\xea\x77\xd3\x45\x77\xfe\x70\x83\x1a\x92\x8b\x10\x1b\x60\xac\x61\x3e\x7b\xa2\xe6\xba\x0a\x94\x01\x3a\x64\xc2\xf8\x21\x9f\xd3\x0b\xff\x40\x90\x99\x66\x7a\x78\x6f\x99\x32\x7b\xb0\x3e\x2f\x21\x87\xf4\x45\xb4\x6b\xee\xda\xb6\xd3\x25\xaf\xd9\x04\xe3\x95\x43\xe9\x3f\x4b\x6c\x54\x43\x24\x9d\x74\x4b\x2d\x1a\x43\xe1\x41\xe4\x76\x8b\xd4\x0a\xab\xe4\x05\x72\x44\xe1\xea\xdd\x9d\xae\xc1\x75\x71\x9e\x51\xa0\x93\xac\xe3\x2f\xe8\x2b\x2e\xac\xb5\xec\xb0\xda\x6c\x1f\xfe\x98\xc8\xce\xe7\x88\x6e\x30\x16\x70\xdf\xf8\x71\x13\xef\xed\x42\x82\x47\x1a\xfb\x6b\x8a\x0f\xdb\x50\x5e\x2e\x8e\x7d\xbc\x1a\x08\xa2\x2e\x96\x80\xbd\x09\x8b\xf1\x27\x58\x02\xbd\xb4\x59\x41\x3a\x3b\x23\x7d\x77\x13\xa1\xbb\xf5\x97\xe6\xad\xf2\xb6\x0e\xaf\x82\x37\x91\xb3"}, -{{0xaa,0x0f,0xda,0xe2,0xa5,0xa4,0xc9,0xc0,0x45,0x21,0x91,0x30,0x04,0xcd,0x89,0xef,0xbc,0x88,0xb2,0xda,0xdf,0x5a,0xbb,0x24,0x6f,0x3c,0xa7,0xf6,0x92,0x35,0x44,0xaf,},{0xbf,0xfc,0xb1,0x7c,0x35,0xc1,0x30,0x4c,0xdd,0x9d,0x62,0x4f,0xf6,0x9b,0xee,0x60,0xec,0x7c,0x9e,0xc3,0x27,0xd1,0x23,0x50,0xd7,0x0f,0xac,0x12,0xb4,0x7c,0xc2,0x5c,},{0xf9,0x37,0x29,0x89,0x69,0xca,0x34,0xd9,0x75,0x84,0x44,0x89,0x07,0x35,0x8b,0x0f,0x47,0x84,0x1f,0x30,0x23,0xaf,0xc7,0xef,0x76,0x81,0x52,0x1c,0x5b,0xe0,0xf5,0xe5,0x62,0x8a,0x8f,0x60,0x7e,0x2f,0x31,0x63,0x6e,0xf6,0x36,0x46,0xb0,0xe9,0x89,0x8a,0x72,0xad,0x35,0x57,0x06,0xd2,0xc8,0x06,0x0f,0xbc,0x64,0x0e,0xfb,0x3d,0x66,0x05,},"\xb1\x41\x84\xcf\xdc\x4a\x5f\x0c\x7f\x83\xf9\x4a\x83\x2f\x58\x85\x07\xe2\xd7\x2a\x89\x32\x98\x70\x07\x85\x71\xd2\x08\xa0\xc4\x96\x0c\x2f\xdc\x4c\x23\x6c\xf8\x82\x29\x98\x1d\x12\xb1\x0a\x1b\x68\x84\xc8\x65\x0d\xda\xf1\xd4\xb2\xeb\x98\x15\x75\xb1\xe0\x19\xfe\x3f\x60\x42\x36\x76\xf8\x85\x6a\x99\x2c\xce\x36\xd6\xd0\xa3\xd0\x26\x63\x1c\x8c\x1e\x1f\xfe\x34\x13\x4b\x29\x6f\x40\x84\x2b\x6d\xf4\xf8\x6f\x83\x3e\x01\x75\xba\xe5\x0e\x86\xbf\x85\x6d\x1e\xe7\x99\x25\xf4\x34\xb8\xbf\x2c\x84\x51\x9f\x1f\x5d\x25\x38\x60\x49\xce\x3c\xa6\x17\x77\xe3\x0b\x70\x0a\x60\x2d\x39\x52\x50\xb6\x0f\xc6\x4a\xc6\xf8\xdb\x02\x7e\x8d\xa8\xb9\x55\x0f\x24\xed\x11\xa1\x1d\x9f\x9f\x9c\x5e\x0a\xf1\x45\xb8\x65\x97\x51\xac\x6b\x55\x86\x1f\x63\x88\xa6\x43\x36\xb3\x1e\xfe\x45\xc0\x80\x2d\x76\xa5\x34\x86\xa8\x1e\xba\x07\x31\x4b\x4d\x96\x1c\x14\x1a\xb3\x4e\x2f\x76\xed\xac\x0e\x6d\xe3\x14\x22\xdf\x79\x2a\xf0\x81\xe7\x69\xc7\xed\x05\xda\x9a\x5a\xf2\xfd\xf3\x6f\x14\x17\x69\x90\x8b\x70\x09\x37\xf0\xe1\x06\x8c\x13\x1f\x17\x6e\xb9\x6c\x67\xaf\xdb\xe7\x8f\x40\xd8\x60\x07\xfb\xcd\x47\xe4\x9e\x2e\x4c\x4c\xe0\x49\x93\x6a\xdf\xf1\xce\x3e\xac\x42\xb9\x6b\x34\x29\xb5\x62\x6b\x1a\xa6\x2a\xcd\xe0\x7f\x45\xa1\x3c\xe1\xbd\x21\x1f\x32\xbd\x7e\xfe\x47\x90\xc8\x37\x1e\xbf\x87\xc1\x64\x47\x7a\x5c\x9f\xa3\xe7\x8c\x2f\x88\x07\x7b\x09\x73\x44\xcf\xfa\x03\x1c\x44\x29\xc7\xf4\x2d\xca\x07\x73\x78\x50\xee\x7a\x76\x9b\x36\xd0\xf0\x62\x5a\xdf\x12\x0e\xa2\x3f\xf4\xe3\x93\xa4\xfd\xcb\x65\x58\xdb\xf9\xb2\x66\xa0\x32\xe3\xb0\x59\x9b\x9d\x66\x92\xfc\xeb\xd8\x15\xa3\x89\x76\x07\x85\x63\x25\xfc\xd0\x11\x5d\xc3\x10\xdb\x3a\x87\x92\xfb\xeb\xd3\x99\x49\x4c\x83\x71\xe5\x85\x72\x7b\x3d\x63\x24\x14\x49\x68\x93\xd0\x38\x13\xba\x1f\x99\x66\x1b\xce\xb9\xdc\x18\xec\x5d\xc2\x7f\x52\x67\x03\x18\x68\x77\x69\xfc\x67\x8d\xdc\x7e\x40\x22\x7c\x20\x05\x22\x01\x3f\x5c\x0e\xec\x0e\x47\x81\xe6\xfc\x15\x3a\x0c\x2f\x4f\x3f\x95\xe5\x17\xc8\x41\x99\x24\xab\x39\x99\x2a\xf8\xc1\x94\x65\x05\x7f\x13\x44\x86\x69\x6b\xa7\xfd\x46\x51\x76\x8b\x4e\x74\x9e\xf3\x6f\x02\x44\x46\x17\xcf\x97\xf0\xa4\x23\xe4\xc1\x3b\x7b\x66\xba\x2b\x6c\x45\x68\x78\xb0\xb5\x0c\xe2\xee\x5e\xc5\x64\xed\x88\x54\xf7\x82\xaa\x1d\x1c\x6a\xa7\x60\xf2\x52\x2c\x7d\x97\xb9\xb1\xab\xe0\xba\x81\x09\x59\xd7\xaa\x40\x3a\x99\x37\x5a\xa3\xe3\x9a\x11\x5d\x1f\xc6\xfe\xdd\x00\x2f\x38\x30\xa5\x0a\x83\x7d\xc7\x20\x32\x9e\xc0\xc7\x3d\x5b\xfd\x50\x03\x85\xc7\x36\x83\x82\x87\xe1\x92\x01\x52\x5d\x18\x9c\x3a\x08\x4c\xd5\xa3\xf3\x59\x87\x5e\x3b\x83\x25\x28\x9c\xed\x18\xb6\x3b\x00\xff\x9c\xd0\x70\xc3\xe6\x74\x44\xbd\x3d\x83\x46\x17\x40\x85\xcc\x45\x13\x5c\xaa\x0c\x67\xb3\x22\x6e\x4a\x52\xe9\xa1\xc5\x5a\xed\x7e\xc5\xfa\xde\x6b\xf1\x6c\x19"}, -{{0x71,0x62,0xfe,0xf0,0xac,0xa4,0x97,0x4b,0x09,0x4a,0x6a,0x08,0x05,0x43,0x95,0xf8,0x77,0xff,0x94,0x33,0xf1,0xe3,0x3e,0x20,0xe8,0x8e,0xaa,0x90,0xf9,0x38,0x99,0x7d,},{0xa2,0x80,0x64,0x0f,0x13,0x9f,0x45,0xc3,0x5a,0x48,0x71,0x53,0x7e,0xef,0xe6,0xef,0x9d,0xb0,0x2d,0xe7,0x85,0xee,0x9f,0xd5,0x4f,0x80,0x5f,0xb5,0x7d,0x37,0x46,0xef,},{0xae,0x16,0x1c,0xce,0x95,0x40,0x33,0x84,0xb6,0x5c,0x6b,0xc9,0xb3,0x93,0xeb,0x07,0x25,0x64,0xc3,0x5f,0x3a,0x6c,0x04,0xfa,0x51,0x7a,0xb0,0x68,0xbc,0xd2,0x37,0x67,0xcc,0x0c,0x8e,0xdd,0x92,0xb1,0xa1,0x3a,0xe9,0xa9,0xce,0x48,0x64,0x13,0x7f,0xb8,0x9c,0x1f,0x37,0xb7,0x48,0xcf,0xc9,0x13,0x4b,0x67,0x41,0xba,0x1b,0x22,0x28,0x0d,},"\xc9\x0f\x45\x0b\xda\x1c\x6e\xfd\x8d\x12\x78\xde\xbd\x7a\xe0\x3e\x2e\xac\x27\x40\xa5\xa9\x63\xfc\xf9\x6c\x50\x4e\x31\xd4\xd6\xfc\xc5\xe2\xb5\x2a\x25\x18\xd2\x74\x1c\x55\xe9\x59\x18\x67\xb2\x42\x32\x28\xf9\xc1\x9f\x33\xc6\xf3\x87\x05\xc6\x20\x36\xd4\x80\xff\x53\xdf\x12\x07\x7e\x38\xfd\xb0\x73\xc6\x73\x10\x5d\xa1\xe1\x16\x19\xba\x53\x21\xa7\x1b\x5f\x49\x93\x23\x4a\x11\x94\x8e\xa1\x10\xcf\xa2\x42\xbc\x23\xfa\xc9\xaa\xe4\x62\x60\x6e\x39\x64\x1c\xa7\x14\x7e\xeb\xba\x1e\xec\x55\x3f\xce\x94\xe5\x3e\x4e\x01\xb0\x73\xdd\x78\x0a\x2f\xf6\x78\xb3\x15\x72\xca\x11\xee\x08\x77\xe7\x56\xbc\xdb\x66\x53\xe5\xe1\xb4\xcb\xfb\x56\x9a\x9d\x60\xe3\xee\x33\x61\x82\xdc\xb9\xb2\x5d\x1b\xe6\xdb\xf9\xb5\xc7\x14\x6d\x77\x55\x85\x83\x4c\xab\xde\x02\x78\xae\xe5\xd5\x7c\x85\xe9\x83\xf8\x4d\x88\x33\xa9\xe1\x5b\xcc\x11\x19\x8e\x1c\x1d\xa6\xba\x59\x28\x21\x29\xf1\xdb\x96\x6f\x54\x60\xc8\xfb\x65\x30\xfb\xc3\xa9\x8a\x31\xfc\x0f\x4e\x9b\x33\x73\x66\xee\xc1\xdc\xe1\x08\xc8\x26\xd4\x90\x45\xab\xfa\x12\xee\x88\x79\x7f\x08\xf0\x68\x3f\xef\x77\xed\xaa\x35\x43\xb9\x1c\xb1\x18\xe4\x24\xd9\xc4\x08\xda\x54\x74\x31\x12\x51\x07\xd9\xb0\x74\x4c\x24\x43\xce\x99\x17\xe1\xe3\x28\xd8\x18\x50\xba\xbb\xc9\x4d\x92\x0a\x1d\x06\xe5\x24\xdb\xb6\xc2\x3d\xd8\x2e\x17\x87\x82\x2d\x71\xc4\xcd\xc4\x09\xae\x85\xba\x4d\xeb\x58\x1f\x93\x47\x48\xf7\x5e\x7a\x76\x9b\x9d\x68\xc4\x58\x9e\x59\x4e\x65\xcb\x6c\x8f\x49\x03\xff\xba\xbd\x5a\x32\x6e\x89\x44\x1a\x54\x2f\x8a\xc2\x64\xcc\xc6\x4e\x95\xa8\x98\x2a\x71\x0b\x6c\x56\xff\x7d\x10\x91\x6a\xfc\x40\x9e\xa8\xa4\x1b\x74\x67\x9d\xd6\xa7\x66\xf5\x9c\x52\xb9\x30\x5b\xa7\x33\xb1\x3c\x9e\x81\x1e\xe1\x30\x83\x92\x5f\x42\x00\x68\x2b\xd0\x5d\xea\x33\x95\x32\x52\x29\x70\xaa\x14\x9d\x00\x4a\x2e\xa2\x0f\xf4\x61\xe9\xec\x0f\x3b\x62\x56\x5c\x1a\x10\x62\x59\xc8\x36\x60\x5c\xc2\x7c\xad\xc9\x51\x5c\xb9\x97\x9e\x89\xaf\x28\x7c\x02\x7d\x75\xed\xbf\x87\xd5\xcf\xf6\x3a\x7f\xec\x9b\xd1\x0e\x78\x77\xab\x9b\xf8\x68\xd7\x34\xbd\x3a\x23\x74\xce\xf7\x02\x5c\xc4\xda\xb7\x10\xe2\x54\x80\x66\x85\xa1\x36\xec\xd0\x3e\x36\x77\x03\x46\x51\x3a\x15\x14\x5b\x89\x0e\xee\xf4\x7b\x80\xea\x08\xe4\x6c\x81\xd2\x02\xe5\x33\xe9\xa0\x6a\x38\xa6\xf7\x6e\xf5\x7a\x9c\x73\x6e\xc7\x8d\x00\xb8\x08\xe3\xff\xd9\xc7\x9b\x9d\xc7\xa2\xe5\x89\x90\x76\x56\xc9\x32\xab\x8a\x8b\x57\xda\x1a\x49\x5b\xa7\x45\x20\x15\xe7\x92\x4b\x52\x69\xab\x1f\x67\xbd\xb4\x3a\x35\x83\x14\x87\xab\x90\x02\xf5\x2d\x78\xb1\x34\xcd\x37\x51\x92\x5a\xaa\xb0\xb4\x5c\x8e\x6b\x0f\x2b\xf0\xcc\x9a\x46\x59\x31\x71\x08\xfb\xa9\x13\x6a\xab\xb0\x92\x1a\x58\xfb\xb9\xb5\x0e\x51\x24\x3f\x9b\x53\x18\x47\xdc\x96\x57\xe9\x6f\xba\xf7\xaa\x69\x8f\xe6\xfe\x44\xf9\x05\x90\x14\x4c\x70\x33\x72\x50\xc5\x8b\xc5\xdd"}, -{{0xde,0xa1,0x80,0xc9,0x1b,0x53,0x3a,0xaf,0x73,0x6b,0xc5,0xd3,0xc8,0xe4,0x74,0xd5,0xe5,0xd4,0x75,0xb7,0x5b,0x92,0xcd,0xe6,0xbd,0x1d,0x10,0xf3,0xb8,0xf5,0x5a,0xd4,},{0x30,0xb2,0x0f,0xb3,0x20,0xb0,0x0e,0x77,0xc4,0xe0,0xa8,0xeb,0x37,0x30,0xaf,0x3c,0x0b,0x1c,0x5f,0x5e,0xd9,0xee,0x2b,0x05,0x62,0x70,0x7e,0x4f,0x55,0xc4,0x93,0x8b,},{0xd0,0x83,0x33,0x3f,0xb8,0x4e,0x79,0xc9,0xb3,0x3e,0x55,0xe8,0x19,0x2d,0x57,0x1f,0xfc,0x8d,0xc5,0x07,0x45,0xb6,0xb5,0xfd,0xd8,0xc4,0x4d,0x92,0xa6,0x3f,0xd1,0x78,0xc4,0xe5,0x7c,0x2a,0xb3,0xa1,0x21,0x1c,0x0b,0xa2,0xd3,0x9d,0xa3,0x0b,0x06,0x62,0x9d,0x8d,0x1c,0xc1,0xd9,0xf2,0x59,0x32,0x63,0xd5,0x24,0xfa,0x5a,0x2e,0xbc,0x03,},"\x60\x61\x44\xb7\xd4\xf9\x6b\xef\x7f\x11\x2b\x6d\x41\xbc\xb5\x00\xd2\x13\x6c\x13\x4c\xed\xa2\x20\xe2\x4d\x0f\x15\x24\xec\xa1\x2c\x30\xf2\xb1\x02\xc7\xf3\x78\xd6\xbb\xa2\x59\xc5\xb4\xa5\xef\x8e\xc9\x30\x9d\x5c\x8d\xa7\xe8\xd2\xde\xd3\x79\x2a\xee\xea\x21\x08\xf7\x7d\x66\xb2\x30\x45\x93\x8e\xd6\x47\x51\xf2\x0d\x48\x32\x6b\xe2\xfb\x99\x62\x8c\xfb\x18\x73\xd7\xdd\x27\x58\x1c\x10\x5e\xc1\x32\x49\xa9\x52\xa5\x07\x84\xb8\xb3\x4c\xb3\xb2\xc1\xa0\x04\xfa\x8b\x62\x8a\x07\x67\xfa\x9a\xbf\x05\x8d\x95\x5d\xf8\x5d\x13\x4a\x0f\xc7\xf4\xb7\xd7\xfb\x0c\x8d\x31\xbc\xe3\x45\xdd\x0a\x42\x82\x14\x5a\xfb\x2f\xf1\x97\x51\xf2\xcc\x3a\x1c\xae\xa2\x42\xba\xaf\x53\x87\x49\xbf\x38\x80\x00\xe3\xdc\x1d\x73\x93\x59\xdf\xeb\xae\x64\xae\x1e\x10\xfb\x6f\xc1\x7c\xc9\xfb\x95\x05\x35\xc2\xde\x12\x95\x87\xa8\x68\x59\xb7\xbe\x36\xdf\xe9\xb6\xc1\x14\x1b\x25\xe0\x91\x5c\x8d\x4a\xa1\xcc\xea\xe7\x04\x6b\x3d\x7c\xfa\x94\x0b\xc9\x8d\x4d\x69\xfc\x5a\x30\xdd\xe1\xde\xe4\x2f\xb5\x27\x22\x81\xbf\x8f\x8e\x7f\x3e\x1a\x04\x39\x7f\xb4\xf3\xad\xef\xc5\x75\x32\xdd\xbd\xe3\x68\x33\xa6\x76\xe6\xf3\x9c\x82\xaf\xf6\xbf\x48\x32\xec\x97\x1e\x03\xbe\x38\x29\xc0\x2a\x20\x3c\x82\xd9\xeb\x8c\x16\x30\xee\x96\x93\xf4\x5d\x26\xf5\xf5\x1a\x31\x03\xca\x64\xd4\x68\xec\xea\xc1\xb2\x9a\xf4\xc4\x2e\xb2\x16\xd7\x6e\xc8\x99\x48\x36\xb4\xbe\xc7\x64\x89\xca\x50\x70\x68\x0c\x2c\x2e\xb4\x57\x21\x0a\x77\xc4\x7f\xdc\xbf\x60\x01\x72\x07\x3a\x53\xf1\x45\x3b\xb5\xc8\x04\x39\xc8\x82\xf0\x73\x6d\xe4\x06\x37\xb4\xf5\xab\x1f\x76\x1f\xf3\x55\xc6\xe9\xbd\x4a\xbd\xe7\x56\x0d\x5f\xc1\x13\xc8\x30\x15\x9a\x1b\x77\xc4\xe8\x7b\xc2\xc6\x98\x80\xa4\x0c\x58\x05\xec\xc8\xaa\xaf\x57\x57\x5b\xcc\xd8\x17\x7f\xc6\xb8\x35\x69\x23\x3c\x0f\x5c\xa2\x23\xac\x40\x13\xca\x10\x6c\xac\x28\x54\x70\x6a\xea\xd7\x14\xfa\x29\xf2\x86\x0a\x5f\x97\x53\x26\x8a\x36\x71\xd9\xf5\x9c\xde\x60\x48\xcf\x0b\x89\x86\x05\x0f\x7f\x54\x9e\x4f\xd7\x55\x7f\x2f\xc3\xfc\xdc\xcd\xdc\xef\xda\x58\x6a\x64\xb3\x00\x6e\x58\x25\xf2\x7c\xa3\x16\x87\xca\xf6\x63\xbd\x90\xa0\x5b\x11\x52\xd7\xc8\x8d\x7f\x10\x51\xa9\xd7\x91\x74\x86\x51\xd8\x88\xa6\xa1\x2f\x22\xd6\xc8\xc3\xf7\x8c\x2b\x86\xea\xf5\x39\x4b\x4e\xf7\xee\xfb\x89\x79\x7b\x25\xe5\x42\xdc\x93\x10\x2d\x02\x1a\x1d\x0b\xed\x6a\x7d\xcd\xd8\x10\x2b\x8f\x04\x30\xa0\xbc\x21\xd9\x04\xa3\xc9\x34\x6c\x01\x83\x43\xdd\x99\x37\xcb\x35\x25\x00\x07\xa2\x84\x82\x5d\xb0\x8e\x9a\x11\xfe\xe3\x1c\xff\x7a\x31\x4c\x48\xc4\x2d\x8b\x31\x4a\xcc\x27\x82\x2a\xf0\x3d\x19\x54\xc7\xcc\x8b\xf9\xad\x4e\x9e\x98\xf4\xad\x4e\xfb\x35\x52\x88\xda\xa8\xc9\x0d\xe9\x03\x7e\x64\xa7\x86\x1f\x5e\xe4\x3a\xda\x9f\x0f\xcc\xde\x34\xd0\xbc\xf5\x02\x88\x55\x0f\x70\x0f\x21\x5a\x79\x44\xa5\x38\x0e\x2a\x8e\x3f\x04\xf2\xb4\xf5"}, -{{0x9d,0xaf,0x6d,0xbb,0x7f,0x76,0x29,0x66,0xe7,0xa5,0x7c,0x2e,0xc1,0x99,0x6e,0x9f,0x5b,0x55,0x5b,0x98,0x66,0xb8,0xe3,0x1d,0xea,0xab,0x43,0x56,0xeb,0x13,0x81,0x6e,},{0xf0,0x21,0xb5,0x5a,0x36,0xd9,0xfb,0xfb,0xf2,0x97,0x8b,0xc0,0xdf,0x73,0x6b,0x28,0x9c,0x82,0x41,0xd6,0x43,0x53,0x09,0x84,0x1a,0x13,0x4b,0x07,0xd4,0x7c,0xe4,0xed,},{0x49,0xb6,0xbc,0x46,0xb7,0xab,0xb5,0x69,0x4d,0xa9,0x42,0x15,0xef,0xc4,0xb3,0x0e,0xea,0x04,0xae,0x2e,0x73,0xeb,0x2d,0xa8,0xe8,0xc9,0xef,0x9b,0xe2,0x22,0x24,0x98,0xb1,0x7e,0x13,0x93,0x96,0x46,0xc2,0x9e,0x32,0xd6,0x45,0x58,0x46,0x40,0x64,0x15,0x90,0xb1,0xbb,0xdb,0xfe,0x24,0xf3,0x6c,0x6f,0x69,0x4b,0xf8,0x72,0x38,0xee,0x04,},"\x54\x45\x23\x90\x0d\xaa\x67\x78\xc0\x39\x1a\xe4\x04\x4a\x51\xc0\xc4\xa5\xe4\x44\x13\x3f\xbd\x77\x47\xd5\x39\xa7\x44\xfa\x60\xab\x5d\xc5\x4e\x18\x19\xdc\x8e\x56\x89\x9c\x56\xef\xd7\xef\x3d\xa3\x41\x79\x0e\xcc\x49\x64\x5e\xf3\x25\xc6\x56\x8a\xe9\x71\xd3\x0d\x21\xbb\x7f\x23\x46\x4f\x46\xa2\x4b\x80\xd4\x9b\xb9\x3c\x6e\x91\xde\x79\xb2\x43\x31\xd0\x70\x7f\x43\xd0\x66\x5d\x01\x97\x74\x3a\xdf\xf6\x90\xd6\x15\xa1\xc9\x25\x87\x77\xfc\x47\xd0\x21\x71\x42\x42\x6a\x47\x34\x89\x2e\xb6\x22\xab\x8e\x50\xbb\x12\x8e\xc3\xa8\x95\x26\x6a\x38\x61\xa3\x97\x68\xbc\x76\x09\x6f\x58\x1f\xd0\x82\xdf\x9b\x72\x23\xe8\x5a\x8a\xfb\xdb\x5c\xaa\x49\x22\xaf\x2a\x01\x4b\xf8\xa5\xcd\x11\xe5\xc5\xea\x93\xe9\x1c\xd4\x6d\x5a\x1b\x99\xb8\x5a\x26\x70\xe3\x21\xde\x2e\x32\x25\x5a\xfd\x67\xfe\x2c\x37\xfd\x93\x2c\xac\xa2\x2d\x24\x1f\xaf\x4c\xce\xfe\xff\x58\xd6\xbd\x04\xcf\xaf\x11\xde\xdd\x29\xc8\x71\x9f\xfc\xb0\x2e\xf6\x5c\x5d\x3e\xb7\x8b\x4f\xc0\xd1\x70\xa2\xe3\x43\x2c\xc8\x12\xf0\xd0\x41\xd9\x76\x0c\x13\xc1\x2f\x7c\x7f\x2f\x84\xfe\x5e\x0f\x70\x0c\x10\xb1\xa6\x9c\xa4\x66\xa7\x0b\xde\xff\x8d\xbe\xc7\xd3\x18\xfb\x09\xdd\xd8\x27\xef\x61\xca\xa6\x91\x0b\xbc\x06\x1c\xbd\xa2\xb5\x27\xef\x2e\x59\xed\x4c\x17\x22\x99\x72\xf8\x95\x67\xd7\x05\xde\x92\x31\x92\x4b\x41\xbb\x6e\x7c\x01\xfe\x85\x42\x64\x47\x4f\xa7\x6b\x1f\x88\xcd\x57\xea\xc3\x11\x17\x1a\xf1\x03\xd2\x30\x78\x42\x4a\x12\x67\x5f\x2f\xa3\x6c\x2d\xe0\xbf\x53\xc2\x95\xfe\xeb\x31\x57\xde\x95\x89\x22\x98\x6e\x32\x51\x3d\xfa\x33\xb3\x5e\x15\xc3\x94\xa1\x1c\x0f\xcc\x55\xb8\x2d\x6d\xd0\x59\x7c\xdd\xd2\x7e\xde\x7d\xe1\x29\x85\xa6\x16\xe6\x40\x26\xbe\xfb\x5d\x69\x04\x82\xb3\xff\x22\xc0\xdd\x21\xf2\x7a\x08\x6d\x37\xa0\x49\x9e\xa3\x6f\xe2\xc4\xb5\xa9\x59\xd1\x0e\x9a\x61\x0c\xab\x1f\xe0\xd2\x8c\xf1\x01\x3d\xca\xe6\x3d\x8f\xde\xe0\xec\xbd\x8b\x4e\x19\xd5\xd0\x40\xe2\xfa\xd7\xd0\x41\x3a\x38\xe8\xc4\xe7\x35\x52\xad\x46\x04\x7b\x5b\xbd\xd1\x5c\x09\xcc\x0d\x34\xe4\x8b\x91\xfd\xba\xe2\xa9\xd1\x62\xd4\xb2\x1e\xe2\x0a\x1e\xf5\x35\xea\x88\x35\x95\xbc\x49\x51\x69\x2a\x67\x16\x34\x54\xc7\x36\x7f\x13\x4b\xf6\x45\xd4\x8f\x99\x69\xe3\xd4\xf0\xf9\xea\xf4\x14\x4c\xe9\x80\xa0\xa2\xe3\x34\x2c\x74\x6c\x2b\xdc\x3c\xcd\xc2\xf8\xa7\xda\x57\xa0\xe8\x02\x87\x82\xd3\x0a\xf5\x85\x7d\x9e\xfb\x37\x66\x6d\xf6\x5d\x7c\xc3\x84\x71\x66\x61\xe6\x1f\xf5\xc0\x97\x52\x59\x5e\x94\x11\x2c\xa1\xa8\x40\xd6\xe4\xf6\xec\x0e\x55\x49\x4c\x5b\x44\xf7\xc0\xf0\xd4\xa9\x9c\xd7\x09\x05\xbf\x84\x85\x56\x17\x48\xf4\xdc\x0f\xd7\xa4\x4a\x1b\x13\x91\x13\xc3\x8a\x1e\x8e\xb5\xc7\xa2\x0f\x3e\x95\x2e\xae\xa8\xce\x38\xb2\x07\xc2\x8e\xd9\x72\x71\x8f\x03\x1f\x47\x7c\x62\x07\xce\x43\x3c\x51\x5f\x5a\xc2\x84\x0f\x49\x74\xf1\xf1\x69\x89\x62\x6c\x76\xbc\x98"}, -{{0x71,0x86,0xf8,0xd1,0x68,0xd9,0xdd,0xf1,0x7e,0xdb,0xaf,0x0e,0x7b,0x1a,0xbc,0xb2,0x6d,0xa3,0xe4,0xc0,0x27,0x2d,0x98,0x79,0xc7,0xfd,0xff,0x64,0x21,0xc4,0xea,0x50,},{0x96,0xb4,0xa6,0x56,0x23,0x20,0x29,0xfc,0x1b,0x83,0x64,0x70,0x3c,0xbe,0xa7,0xa5,0xd7,0x38,0x75,0x18,0xa8,0x8c,0xed,0x1a,0x91,0x5e,0xc8,0xd8,0x86,0x84,0x81,0x32,},{0xa9,0xc0,0x49,0x9f,0xc2,0x16,0xa1,0x45,0x32,0xd7,0x36,0x36,0x5c,0x63,0x55,0xf9,0x38,0xf8,0xd8,0x19,0x4f,0xa1,0x13,0x28,0x48,0xf8,0x3e,0x49,0x04,0x54,0xd4,0xbb,0xf6,0x92,0x69,0xf1,0x22,0x59,0xfc,0x6c,0x07,0x4c,0x10,0x15,0xe4,0x25,0xe4,0xf4,0xf2,0x7c,0x02,0x9c,0x93,0x33,0x49,0x51,0x36,0x1a,0x35,0xad,0x11,0x76,0x54,0x0e,},"\xa3\xe6\xcb\x6b\x84\xcc\x5c\xf1\xfb\x1a\x84\x8b\x4b\x8e\xa7\xcb\x7c\x87\xe0\x44\x57\x50\xc6\x1f\x9a\xa5\xd7\x7d\xed\xdf\x94\x94\x63\xec\xd3\x9b\xfc\x71\xf2\x61\x0c\x2a\x94\x24\x84\x7f\xb7\x6f\x84\xc5\xda\x1f\xa1\x0e\xf7\x18\xa3\x45\x66\xce\xc1\xb3\xe8\x99\xe7\x25\x2e\x8d\x4d\x34\x60\x16\x49\x8f\xf1\x19\x97\x27\x50\x06\x16\x60\xba\xed\x31\x28\x27\x58\x31\x81\x07\x3d\x1d\xc7\x4b\x76\xc4\x30\xca\x30\xd4\x09\xe4\xe8\x43\x9c\x0f\xc4\x8c\x00\x68\x06\x29\xd4\x3a\xe2\xa7\x7d\x69\x22\x8f\x7f\x8a\x12\x53\xaf\x15\xbd\x2c\xb6\xbb\x1c\x16\x96\x55\x0c\x4c\x79\x0f\x44\x98\x69\x63\x0a\xb9\x2b\x9c\x11\xcd\xe1\xf9\x61\xaa\x21\x03\xec\x23\xf7\xd9\xf0\xfe\x9c\x3c\x41\x32\x58\x2e\xfa\x79\xa6\x6a\xe3\x42\x6e\x51\x05\xb8\x0b\xfe\x5e\x04\xdc\x8b\xb1\xe3\x8a\x31\x10\xcd\x72\x98\x4b\x3e\xf0\x2a\x0c\xa6\x2a\xb6\x38\xcb\xcf\xbc\x8a\x6b\x59\x3d\x26\x13\xdc\x06\xec\x86\xfe\xe3\x4f\x65\x18\xd4\xa3\xfb\xdc\x15\x72\x37\x17\x45\x64\xda\xeb\x66\x74\xcd\xc3\x4f\x4d\x65\x37\xcf\x81\xd8\xaa\x9b\xdd\xbf\x3a\xed\xa3\x12\xda\xae\xee\x33\x6f\x9e\xd8\xbf\xf8\x1e\x29\x4b\xc7\xd4\x4d\x25\xcd\x78\x70\x72\xe6\xcb\x41\x4b\x65\xfb\x7a\x84\x6f\xc0\x65\x36\x7b\xa8\xe3\x7b\xef\xfd\xf0\xb7\xba\x8f\x98\xcd\xf1\xeb\x87\x0f\x4e\x8b\x71\x30\xfa\x34\x29\xd2\xe2\x4b\xce\x59\x94\xda\xf1\xaa\x65\xe5\xf6\x03\xb6\x31\x05\x3d\xc5\x10\xb2\xf0\x97\xe8\x6e\x9b\x9b\x55\x23\x02\x75\x79\x68\xd0\x13\x6e\xe6\x75\x4c\x42\xa3\x2c\x99\x0a\xdd\x9c\xb5\x29\xbc\x89\x75\x1d\xfa\x4e\x5e\x3a\x0b\xad\xaf\x4c\xc4\x0b\x6a\x09\x50\x7f\x9f\xcd\x24\xc3\xca\x72\x25\x95\x99\xc6\xee\x58\xd8\x57\xb3\xa1\x89\xe0\x48\x90\x2e\x88\x5a\x36\x07\x42\x60\x93\xcb\x0f\xab\x43\x7c\x0f\xb0\xed\x2f\x1e\x96\xe9\x44\x1a\x7e\x95\x4f\xe3\xef\x76\x46\xe2\x6a\x39\xa0\x70\x33\xd0\xa1\x55\x5d\xfe\xed\x9a\x6f\x57\x79\x4a\xf3\xa2\xab\xf0\x05\x7e\x9f\x85\x3a\xe5\xc3\x01\x38\xfd\x80\xe2\xf2\x9c\x2f\x4a\x93\xad\x31\x45\xda\x10\xa3\xe3\x1c\xe9\xff\x97\x86\xac\x65\xd8\x60\x37\xd9\x8b\x7a\xa6\xd1\x1d\xe8\x80\x00\x10\xe1\x33\x86\x9e\xb6\x7a\x50\x39\xb9\xb8\xfe\xb6\xef\x90\x3d\x0c\xc7\x46\x41\x26\x07\xda\x72\x5c\xe2\xdc\x6a\x35\x21\x09\xdb\xc6\xa5\xe4\x0b\x17\x0c\x23\x05\x0b\xc4\xfb\x1e\xfa\x0c\x34\xfe\xc0\x0e\xae\x32\x19\xc2\x90\x40\xe8\xf5\x97\x8c\x93\x84\xee\x91\x5d\x8c\x93\x98\xdd\x12\x0d\x5c\x3c\xba\x38\xf8\x52\x6b\x06\x19\x7c\xb2\xc2\x61\xde\xc7\xd7\x26\xae\x13\x0f\x9b\xee\x17\x26\x17\x00\xe9\x99\x31\xfa\xc4\xb4\xdc\xa0\xf7\x58\x70\x1a\xcb\xf3\x70\x7d\x47\xdf\x53\x21\x13\x0e\xc1\x0b\xb3\xb1\x30\x78\xc4\xdc\x5d\xe3\x47\x0f\x15\x8b\x57\xdb\xeb\x87\x8b\x3a\x85\x24\xe0\xed\x2c\x95\x47\x54\x5f\x0f\xdd\xf1\x31\x25\xe4\x5b\xb2\x3d\x6a\x7b\x38\x3a\x18\x7f\x4c\x5d\x54\xa7\xb4\xc8\x3d\x59\x57\xf2\xcd\x7e\x6f\xbc"}, -{{0xe8,0x6e,0x8c,0x62,0x56,0x6e,0x15,0x75,0x3b,0xd5,0x57,0x7e,0xaa,0xe7,0xf2,0x41,0x05,0xb7,0x40,0x55,0xa2,0x56,0x29,0x58,0x07,0x08,0xbf,0xc8,0x3a,0xeb,0xf0,0x6c,},{0x8c,0x8c,0xe8,0x82,0xd5,0xf7,0x65,0x86,0xd8,0xdd,0xcc,0xc5,0x57,0x9b,0xcc,0x1c,0xdf,0x4c,0xfd,0x71,0x62,0x30,0x4c,0xb1,0x0e,0x76,0x96,0x02,0x6e,0x70,0x7f,0x17,},{0x54,0xd2,0xfd,0x44,0xac,0xf9,0xe2,0x09,0xbc,0x7e,0x43,0x33,0x72,0xbd,0x73,0x07,0x4d,0x07,0x80,0x6a,0x77,0xc6,0xce,0x22,0x8e,0x9b,0xe9,0x94,0x41,0x8b,0x00,0xc7,0xec,0xbc,0xb7,0xac,0x00,0x6c,0x29,0x4a,0xec,0x9d,0xe6,0x68,0x57,0x2a,0xdd,0x51,0x7c,0x06,0xb4,0xeb,0x4f,0xe2,0xff,0x35,0x23,0xbf,0x04,0x3d,0xf4,0x4d,0x3d,0x0d,},"\x12\xfa\x63\x1b\x0e\x48\x2e\x9b\x9d\x63\x3e\x94\xb8\x2d\x8a\xb4\x36\xfe\x54\x8e\x5b\x95\xda\x92\x62\x46\x23\xd1\x3f\x2c\x70\xda\x77\x5b\xa1\x36\xc5\x22\x9c\x16\xa0\xc7\xa6\xfa\x91\x4b\x2f\xed\xa5\x64\xe1\x72\x19\xe4\x73\x70\xf9\x51\x5b\xb1\xd5\x9d\xe6\xe9\x58\x62\x04\xd9\x43\xdc\x56\x0d\x73\xe2\xe7\x57\xf7\xeb\x39\xbb\xc7\x11\x1b\xb4\x6b\xc6\x43\xc1\x3f\x60\x21\x12\x73\x9b\xec\x77\x8d\x7d\x4f\x49\xd0\x92\x56\x3d\x68\xf5\x77\x6e\x43\x0e\x3b\x0b\xf2\xdc\x1b\x01\xbe\xb3\x04\x01\x96\xda\x63\x02\x90\x8b\xfe\x91\xe0\xfc\x38\xe0\x4c\x15\x0e\xf9\x07\xdc\x73\x6c\x44\x5f\xf2\x1f\xdb\xd2\xdc\x1e\xac\x0a\x0f\x5d\x00\xa3\x0a\xf0\x28\xaf\xe2\xff\x61\x16\x2b\x75\x8c\x7d\xa9\xa7\x76\x66\x6a\x11\x23\x59\x43\x1c\x48\x85\x6a\x87\xca\x82\xd3\xdd\x1c\x8a\xf3\x76\x59\x86\x35\x43\x2b\xf8\x91\xbe\xcb\xc3\x3a\x8f\xda\x44\xce\x88\x3e\xa8\xaf\x4a\xd8\xb9\x1a\x92\x61\xce\x76\xb9\xe9\x39\xc4\x61\xfa\xc5\x3a\xe0\xf0\x76\xe8\x2d\x87\x9a\xac\xe8\xf3\x8f\x12\x0b\xc9\xb0\x4d\x81\x25\xed\x24\xbc\xd7\x79\xd9\xd2\x43\x86\xb1\xdd\x20\x17\xeb\xee\x81\x97\x37\x6e\x8c\x36\xfa\x3a\xef\x8c\x1e\x71\x3e\x2b\x8b\xce\x49\x66\xd8\x48\x88\x68\x1b\xa7\x84\x95\xfb\xd1\xd6\xcc\xa5\x86\x26\xe6\x85\x4c\xda\x60\x6b\x83\xd6\x29\x3d\x01\xe8\xe3\xe1\x3b\xbf\x4a\xac\x85\x1d\x9a\x1e\x00\xd0\x02\x4e\x26\x99\x3b\x0b\x30\x91\xbe\x7e\x80\x61\xbc\xbb\x3c\xbb\x23\x02\xce\xab\x96\x89\x7a\x8e\x1f\xf3\x67\xec\x86\x25\x69\x3c\xf3\x15\x34\x12\x4a\x9d\x5d\x72\x5b\xca\xe0\x01\xd6\x7b\xc2\x11\x1d\x0a\xb8\x11\x1f\xa1\xd2\x4e\x4e\xd0\x6d\x63\x58\x3c\xe6\x90\xf2\xa0\x46\x26\xd7\x91\xd2\x9e\x3e\x31\x5a\x41\x5b\xf2\xe8\x53\xa5\xf2\x97\x4c\x83\x3a\x3f\xe2\xe2\x90\x9c\xf6\x69\xc7\x3c\x1f\x59\x39\x2d\x30\xc3\x7f\x3b\x9c\x5a\x3d\xdc\xfd\x75\x62\x1f\xda\x36\xe4\xba\x2f\x16\x14\x78\x58\xf6\xf2\x06\xb9\xa1\x40\xf1\xdd\xc1\x46\x6c\x9a\x53\xed\x73\xf8\x24\x90\xbc\x95\x32\x2c\x95\x5f\x61\xd1\x1c\xb5\x1d\x5e\x8a\x58\xc6\xb3\xcb\x0f\xdf\x04\x19\x76\x32\x01\xbe\xea\x93\xa8\x51\x2b\x14\x05\x24\x5b\xfc\x38\x41\x55\xad\xc5\xce\x77\x8a\xa7\x4d\x00\xa3\x22\x72\x64\x65\x11\x9a\xf7\x95\x01\xf0\x40\xdd\x0a\x7a\x84\x06\x00\x01\xca\x89\xd2\xfe\x5e\x9c\xf9\x77\x9a\x54\x7e\x3e\xbd\x3b\xf8\x64\x29\x90\xa3\x69\x0e\x2b\x2c\x3e\x54\xcb\x7e\xee\xea\xbc\x24\x2b\x4d\xd9\x92\x74\xc4\x25\xa8\x67\x93\x1c\x92\x9c\xa7\x08\x08\x60\x1c\x39\x08\xcf\xd7\x88\x86\x7d\x68\x7d\xc3\x66\xe9\x76\x35\x0c\x9e\x70\x58\x4b\xd3\x90\xd6\x7e\xeb\x7c\xfe\xa2\x6c\x42\x68\x6d\x3d\x96\x20\xf6\x2f\x64\x10\x4e\xf4\x1e\xd1\xd1\x30\xd7\x9e\x32\x59\x38\x48\x62\x96\xb7\xab\x2d\x2a\xdb\x78\x52\x67\x43\xe4\x00\xac\xb2\xb7\xaf\x09\x62\x8d\x68\xcf\x94\x75\x10\x16\x25\xc2\x0e\x1d\xc0\x51\xd7\x3c\x99\x7c\x95\x2e\x12\x81\x2c\x80\x5b\x68\xff"}, -{{0xa5,0xca,0xb2,0x72,0x7e,0x2f,0x13,0x1a,0x4d,0x63,0xfa,0xce,0xe7,0x99,0x33,0x66,0x63,0x93,0x0a,0xa0,0x7a,0xfd,0xa6,0xbd,0x5a,0x8e,0x98,0x5a,0x02,0xde,0xb1,0xea,},{0xac,0x35,0x5f,0x95,0x26,0x0f,0xbf,0xea,0x77,0x8c,0x55,0xb5,0xaf,0x8b,0x3f,0xd1,0xf2,0x4d,0x26,0x93,0xda,0x35,0xde,0x4e,0xe5,0x08,0xa2,0x7e,0xd3,0x50,0x39,0x1f,},{0x13,0x8c,0x7a,0x8e,0xca,0x5b,0x5c,0x37,0x15,0x88,0x13,0x84,0x3c,0x9a,0x90,0x4e,0x5f,0x53,0x0a,0xd9,0x71,0xee,0x43,0x2a,0x44,0xf3,0x44,0xf8,0xc6,0x4b,0xbf,0xaf,0x10,0x2f,0xf4,0x1d,0xaa,0x5c,0xf7,0x22,0xa4,0xbc,0x66,0x40,0x58,0x87,0x59,0xb8,0xf3,0x6f,0x9c,0x05,0x9e,0xab,0x93,0x6c,0xc4,0x5e,0xd4,0x79,0x63,0x94,0xa0,0x02,},"\x48\x34\x39\x15\x4d\xd5\xe5\xd1\x09\x85\x7c\x24\xd1\xc4\xe7\xfb\xbe\xfd\x2f\x38\x65\x1d\xa8\x12\x89\xf2\xad\x3d\x61\x54\x30\x65\x38\xb8\x2a\xc7\xdb\xa9\x21\x0e\x74\x07\x76\xed\xe4\xcc\xf5\x1d\x4f\x63\x09\x4b\x03\xe4\x6a\xd3\xaa\x3c\x31\x94\x7d\x8c\x36\xce\x6f\x94\xe8\x52\x96\xbd\xed\xcc\x1e\xad\x62\xea\xa1\x44\x1e\xcd\xe0\xa2\x25\xd0\xbf\x02\xed\xca\xcf\x86\x50\x14\x89\x9a\xf6\x6d\x98\x08\x04\x0c\x2d\x02\x00\x0a\x0f\x5c\xe4\xf1\x68\x3c\x1a\x49\x52\x76\xd9\xc4\xd7\x28\xc9\xec\xd6\xf0\x78\xdb\x8a\x0c\xfc\x26\x71\x87\x23\x85\x62\xab\x1a\x1e\xa2\x81\x3f\xb4\xf1\x2e\x87\x8e\x1b\xa1\x43\xf4\xd0\x6a\x3b\xc8\x10\x0c\x35\x50\x11\x8d\x69\xda\xe6\x7b\x55\xed\x69\x2a\xcf\x94\x44\xda\xa5\xc3\xe3\xc0\xa9\x8e\xe2\x8c\xf1\x72\xde\x0c\x58\x4c\x9f\x2e\xc9\xbb\x6e\x9b\x57\xf5\x72\xa8\x6f\xf8\x72\x9f\x65\xf4\xc6\x5b\x7f\xea\xcc\xaa\x21\x72\x0e\xd7\x9e\x90\x61\x8b\xca\xfb\xfd\x95\x33\xda\x85\x23\x2b\x45\x08\x83\xaa\x91\x9f\x82\x7f\x04\xc4\xa9\x7b\xf5\x13\x90\xd4\xf8\x56\x9c\x19\x17\x26\xf4\x4f\x7e\x39\xfb\x3d\xb7\x3b\xfc\x41\x5b\x6f\xfc\xa8\xb9\x1a\xca\xad\x69\x23\x85\x72\xf1\x4b\x49\x98\x5e\xa0\x3c\x98\xd7\xb1\xd4\x4b\x3a\x65\x54\x76\x5b\x19\xab\xf9\xb2\x52\x74\xe9\x7e\x46\x34\xe4\xb0\xf9\xe8\x02\xeb\x6f\x74\x3f\xff\x95\x07\x57\xee\x01\x3a\x69\x88\x22\x18\x81\xa7\x44\x3f\x1f\x32\xbc\xcb\x00\x7e\x99\x37\x9c\x7c\xa4\xf9\x06\xd5\xfe\x11\xcb\x12\xf6\x6b\x53\xa3\xd2\x1a\xc9\x47\xbe\x0c\x81\x50\xbc\xd0\x4f\x1c\x81\x6b\x3f\x0c\x07\xc5\xfb\xc0\x90\x5a\x71\x36\x95\x68\x49\xda\x03\x83\x6d\xae\xc2\x5c\x3e\x1a\x06\xec\x3a\xeb\x20\x56\x48\x17\x6f\x89\xf4\xa2\x91\xfa\xc4\xf1\xd3\x89\x9f\x56\xc9\x06\x5e\xeb\xb8\x76\x8b\x84\xb3\x1b\x7c\xc0\x31\x08\xbd\x08\x88\x33\x8d\x17\x74\x99\x49\x70\x29\x2d\x93\x50\x31\xfe\xa3\x35\xd9\xe7\x90\x8f\xe0\x25\x48\x89\xc0\xb1\x71\xcf\xe0\xaf\x2e\x6f\xde\x7a\x5e\xa3\xde\x1f\xdc\xda\xe5\x37\xb6\x31\x31\x19\xc2\x7f\x77\x20\x24\xef\x36\xe4\x5c\x8b\x89\xf2\x6c\x93\xd9\xee\xa1\x37\x25\xe1\x2d\x81\x0c\xf9\x82\x4a\xea\x04\xcb\x80\x2d\xa7\xe4\x58\xe8\x42\xca\x37\x5e\x36\x71\x34\x6e\x00\x89\xde\xc5\x71\xbe\x16\x9b\x0d\x90\x96\x6b\xf3\x68\xfe\x36\x98\xfd\x3e\x72\xbf\x16\x24\x9d\xd9\x00\xaf\x6d\x29\xff\xa4\x83\x51\x36\x0f\x12\x24\x17\x14\x58\x5f\x7a\x9b\x4c\x7b\xaf\xc9\x52\x22\x67\x35\xde\x14\x62\x74\x3d\x78\xab\xad\x0f\x67\x11\xf2\x49\x5f\x33\x13\xad\x4e\x0b\xa2\x16\xb0\xde\xa5\xdc\x15\x16\xa9\x54\x9f\x7d\xfc\xfe\xb9\x3e\x59\x1a\xbe\xda\x5e\xa3\xc7\x04\x59\x06\x52\x3b\x40\x86\x8c\xa5\x73\x5d\x6a\x33\x71\xc3\xc2\x94\xc1\x11\x26\xd0\x97\xf4\xc7\x08\xe9\x04\x64\xc1\xad\x91\x42\xfa\x0b\xed\xf0\x7d\xfc\x5f\x4c\xb6\x7d\x6e\xd8\x0f\x1b\xfe\x72\x68\x3c\xfb\x2a\xd6\x65\x30\xdc\x43\xd7\x02\x3f\x37\x90\xff\x42\xd9\x5b\xd8"}, -{{0xcb,0x63,0x19,0x61,0x37,0x79,0xa4,0xef,0x66,0xbe,0x14,0x14,0x4b,0x28,0x40,0xad,0x01,0x67,0xc0,0x3f,0x3b,0x8d,0x04,0xff,0x59,0x2c,0xd1,0xd2,0xd7,0x22,0xe3,0x30,},{0x18,0xeb,0x03,0xf0,0xa3,0x34,0xb0,0x80,0xe1,0xaf,0x43,0x99,0xd8,0x37,0x6d,0x83,0xc5,0x33,0x31,0x6d,0xc6,0x87,0xcf,0x34,0x1f,0x0a,0xfa,0xb4,0x50,0x96,0x52,0x99,},{0xc1,0xb3,0x99,0xcd,0xc1,0x98,0xe9,0xa1,0x59,0xe6,0x84,0xfc,0x26,0x68,0x6d,0xe6,0x60,0xda,0x54,0xcf,0xe3,0x12,0xca,0x73,0x45,0xdf,0x0c,0x7d,0x15,0xa3,0x57,0x43,0x01,0x44,0x10,0xbd,0x2f,0x6c,0xd1,0x1e,0xef,0x33,0xa8,0x9b,0x3d,0x15,0xcb,0xc1,0x7c,0x7a,0x35,0x89,0x37,0xfd,0x99,0x72,0x05,0x05,0x1f,0x92,0x57,0xc2,0x56,0x09,},"\x87\x4a\x6c\x81\xd6\xdb\x71\x33\xa7\x91\x69\x76\x0c\x84\xd3\x6e\xea\x3d\x42\xea\x08\x92\xb7\xc8\xdd\xe8\x44\xa3\xa6\xb6\x0a\xa9\xf2\x66\x07\x26\xc9\xc4\xdd\x26\xa0\x1f\x4e\xd0\xdc\x1c\x53\xba\x60\x05\x46\x3f\x7e\xa6\x4a\x1e\xc6\x39\x53\xbc\x3d\x81\x05\x2a\x2f\x10\x84\x38\x9a\x77\x06\xdf\x74\xed\x41\x36\x08\x2a\xb5\xc6\xe8\xc7\xf4\x11\xdf\x9d\x3a\x0f\x3c\x40\xf5\xa6\x0e\x2d\x21\xa8\x54\x8e\x7a\x25\xde\xe3\x40\x30\xb3\xc3\xe7\x5c\xaa\x93\xdd\xaa\x9c\x19\x0c\xb6\xde\xda\x24\x13\xd5\x4e\x37\x3d\x43\x53\xdb\xa4\x3d\x39\x49\x1a\x2f\x56\xc8\xb3\x6d\x45\x01\x6f\x77\xd7\x47\x16\x91\x63\x45\x39\xe7\x6c\x4f\xb4\x19\x13\x47\x2b\x0a\x23\x05\x4f\x54\x8f\x54\xb1\xe7\x10\x9c\x8b\x65\x21\xb5\x7a\xe9\x81\xd0\x50\x31\x6a\x33\xc4\x9c\x71\x16\x26\x8d\xcc\x4b\x78\xc2\xba\xe5\x3a\x3a\xe4\xdd\x17\x8b\xb8\xb7\x6b\xb3\xbe\xfe\x19\xe4\x1a\x2c\xf1\x2c\xeb\xb7\x11\x68\xf9\x71\xf2\x02\x46\x1c\x63\xf7\xd6\xee\xf1\x07\xf5\xb1\x03\x0e\xdd\x4e\x75\x00\x9e\x91\x16\xc3\xcd\x0e\x8b\xdd\xc2\x99\xb4\x1f\x1a\x45\xe7\x84\xef\xa6\x46\xda\xda\x64\x06\x8e\x92\x48\xec\x98\x8f\x23\x26\x34\xad\x3d\x5a\xab\x19\x56\x0e\x83\x0a\x5b\xd6\x65\x45\x7c\x94\x29\x5e\x1a\xf0\x16\x0f\xbc\xe2\x72\xef\x48\x45\xdd\xf0\xc4\xf2\x4d\x97\x6f\x51\x86\x90\xea\x1f\x82\xff\x4d\xfa\x48\x13\x64\x1a\x67\x59\x8e\xa9\x84\x01\xe0\xff\x10\xa0\xe5\x82\xe2\xb9\x08\x67\xb4\xe6\x23\x2c\x34\xea\x49\x9c\x16\x99\x09\xa4\x41\x26\xf3\x77\xd8\xcc\x1c\x11\x90\x58\x66\x34\x0e\xfd\x1e\x7b\x07\x7d\xc7\x45\x6d\x59\xc9\xb9\x6a\x12\x4a\xac\x3b\x33\xbb\x22\x74\x41\xbb\x7a\x52\xe6\xc3\x14\x0d\x7a\x4f\x67\xca\x05\xbb\xc9\x3c\x93\x77\x5b\x92\x91\x19\xa2\x24\xed\x8f\x39\x00\x58\x20\xf4\x20\xcc\x6c\x53\x0e\x61\xe2\x0a\xdc\xa0\x1e\x93\x9c\xc0\x31\xdf\x49\xcd\xb1\xec\x8f\xf4\x93\xc9\xef\xbc\xad\x34\xc5\x71\x08\xef\xd7\x64\x55\x89\x66\xfb\x14\x70\xb0\x74\x5e\x69\x66\x19\x1a\x9a\x9e\x44\x58\x1b\x09\xfa\xf4\x69\xf9\x51\x53\x72\x03\xd9\x26\xbc\x8a\x55\xd0\x80\xa8\x05\x18\x1d\xd7\x29\x6e\xd2\x0a\x81\x82\x68\xf7\x55\xea\xa6\x6b\x08\x22\x42\xf4\xd0\x20\xf7\xcd\x67\x20\x89\x04\x84\xc0\x1c\x75\x7f\xe3\x5d\x87\xb5\xbc\x90\x6d\xea\xcc\x2e\x30\x71\xde\x46\x01\xbc\xf0\xdd\x6b\x83\x7c\x43\x31\x06\x04\x7f\xd8\xec\x9b\xd0\xe9\x8c\x9e\xe8\x06\xf7\xec\x8c\x5a\x10\xea\x21\x36\xf1\xf9\x0f\x90\x0b\x85\x3f\x95\x3f\x00\xb0\x76\xbd\x1e\xbd\x92\x9d\x08\xa3\x8b\xec\x68\xd8\x66\x43\x50\x47\xbc\xb6\x72\x1e\x06\xb6\x40\x85\xdc\x05\x58\xc1\xfa\x85\xa2\xc8\x3b\x0c\xaf\x4c\x81\x60\x84\xf1\x0a\x4c\x58\x85\x29\x5b\xca\x15\xff\x7c\x18\xe5\x96\xc6\x2c\x92\xee\x99\x21\xa2\x7c\x29\xd1\x95\xbd\x28\x22\x13\xff\x36\x60\xb6\xe7\x54\x6b\x4e\xaa\x77\x7c\xe3\x9f\xc5\xd2\x04\x84\xc7\x1e\xd6\xca\x06\xf9\xb7\x7a\xb1\xd8\x72\x39\x3a\xb2\xd1\x02\x55"}, -{{0xb2,0x98,0xad,0xf3,0x8a,0x67,0x08,0xf8,0xd1,0x8f,0xf1,0xed,0x96,0xbf,0xba,0xb4,0x21,0x54,0x0d,0x09,0x6c,0x4e,0x43,0x51,0xb9,0x22,0x09,0xb5,0xe6,0xaa,0xab,0x65,},{0x77,0x0e,0xdf,0x42,0xb8,0xa0,0x39,0xc6,0xca,0xb9,0xba,0x65,0xeb,0xfb,0x13,0x5a,0xbc,0x2d,0xa3,0x14,0xa4,0xc3,0x09,0xf4,0x6a,0x8f,0x32,0x5b,0x52,0xd0,0x65,0x93,},{0xe5,0x5f,0x8d,0x30,0x41,0x22,0xdc,0x17,0x5c,0xf0,0x27,0x46,0x74,0xfc,0x9d,0xed,0xfe,0xc2,0xb5,0xf8,0xa2,0xee,0xb1,0xe3,0xe7,0xf8,0xe0,0xdf,0xba,0x0d,0xac,0x2d,0x32,0xf4,0xe7,0x04,0xce,0x91,0xcd,0x59,0x91,0x84,0x13,0x3c,0x3b,0xf1,0x06,0x3d,0x2f,0xae,0x63,0xd7,0x3a,0xcc,0x57,0x72,0xd7,0x18,0xd8,0x11,0x83,0x31,0x86,0x02,},"\x9d\xf4\xd5\xd7\x56\x5d\x2c\x05\x22\x62\xdd\x34\xd6\x00\x7d\x86\xd9\xc0\xf0\x7c\x70\x89\xaf\x61\x19\xe3\x04\xf4\xd8\x01\x1d\x7e\xaa\xd7\x7b\x3e\xf7\x0c\xc2\x80\x84\x7d\x59\xf2\x97\x20\x2b\x7e\x18\x61\xae\xf3\x34\xbf\x38\xde\x14\x74\x0e\x80\x73\xc9\x55\xa8\x51\xd2\xcf\x3d\xad\xc3\xed\xce\x15\xbe\x49\x0e\xaa\x84\x5b\xa5\x53\xfc\x6e\x87\x46\xe5\x29\x15\xe6\x55\xaf\x4b\x86\xc6\x29\xd4\xc5\x22\x78\x36\x35\xd4\x64\xa2\x82\x57\x77\xd8\x9d\x70\x97\x67\x7e\xf0\xe5\xee\xae\x38\x53\x7e\xcb\x65\x6e\x3b\x28\xdd\x07\x35\x8f\xd9\xfb\x2c\xd4\x62\x51\x72\x86\x65\x9a\xef\xc7\x9d\x37\x4d\x1d\x13\xed\x93\x96\x7c\x53\x0c\xde\xa4\xf3\x14\xa0\xf9\x1d\x62\x89\xb4\xc7\xa4\x27\x9b\x6f\x4c\x4a\xbc\xa3\x33\x57\xf6\x9e\xd8\x4b\x91\x19\x63\x7a\xdb\x7c\x18\xe6\x94\xcb\x3c\x56\xe7\x36\x37\xda\x91\x07\x35\xd4\x3c\x38\xaa\x80\x86\x67\x5a\x06\xad\x37\x0e\x57\x26\x88\x1d\xa5\xe1\xa1\xdc\x61\x44\xd6\xa6\x2a\xff\x7f\xb0\xc3\x52\xd8\x8d\xc9\x71\xa3\xd7\x2d\x30\x71\xe1\x4b\x47\x42\x53\x56\xaf\x1b\x01\x92\x33\x53\x82\x61\x45\x1a\x99\xa6\xcf\x4a\x07\xce\x9a\xb1\xc3\x99\x0d\xe6\xab\x8d\xe2\x11\x6c\x75\x61\x05\xc5\x12\xb7\xa3\xee\xb3\x15\x7b\x15\x8b\x32\x1e\x44\x4e\x80\x6d\x89\x0b\x38\x90\xed\x9d\xdc\x86\x9f\x17\x11\x72\x3b\xb9\x9a\x72\xbd\xb9\x23\xd1\x31\xba\x4e\xdb\xfb\xb6\xda\xe9\x9a\x5c\x7b\x32\x8d\x31\x0d\xf9\xa6\xd1\xdc\xd8\x59\x18\x96\x28\x33\xe8\x9e\x20\xf5\xc5\xe6\x33\x3a\xc8\x61\x09\x4a\xe9\xe7\x99\xc8\x64\x1b\x9b\xae\xa1\x1a\x2e\x0e\xc2\x34\xbe\x59\x30\xe0\x28\x80\x85\x9c\xde\xc0\xd9\x78\x23\x7c\xbe\xa5\xc7\xc3\x2c\x11\x1b\xaf\xdd\x4b\xfb\xff\xe4\xfb\x34\x85\xef\xfe\xcd\x51\xbd\x19\x5a\x71\x40\x4c\xa5\xb5\x9a\xfa\x25\x2d\x7b\x5f\xf9\xd0\x30\xf4\x8c\x6f\xaa\xdb\xdb\xa9\x18\xf2\x1a\x0c\xd3\x9a\xf5\x69\x66\xdc\xcf\xa2\x5f\xb5\xa5\xcf\x9a\x4b\x26\xa7\xf5\x44\x1d\xf6\xe3\x20\xe3\x4b\x27\x39\x3d\xe2\xec\xfb\xd6\x9a\x15\x94\x90\x9a\x6c\x68\x5e\xc6\x45\xfc\xf3\x04\x8d\x01\x48\xfa\x38\xd3\xe8\xa6\x4d\xc3\xc2\x1a\xe4\x4d\xa7\xe4\x6a\x5e\xa7\x93\x6c\x2b\xa0\x83\x68\x9a\x78\xca\x3a\xc6\x0b\x87\xbe\x6d\x23\xea\x40\xf5\x96\x15\x83\x74\x28\x42\xe3\x75\x25\xa4\x9c\x5f\xe8\xfd\x15\xd7\xb0\xc9\xe8\xfc\xcd\x07\x93\x6d\x19\x53\x82\x12\xf7\x37\x3d\xbb\xf3\xdf\x7d\x46\xad\xf9\xd9\xf5\xdb\x09\x52\x4c\x65\xb8\x83\xae\x6f\x6c\xef\xa2\x4b\x19\xec\x48\xce\x28\xcf\xa7\x34\xd9\xbd\x6e\x77\x83\x7d\x1a\x14\xd6\xa1\x9d\x34\x5b\xfb\xea\x55\x9e\x7e\x6b\xfb\x71\xdd\xad\x83\xcd\x8d\xee\xab\x68\x7f\xe7\x3c\x05\x74\x88\xf8\xf2\xb3\xe2\xe2\x6d\x13\x00\x9f\x4d\x23\xe6\x61\x9a\x23\xc0\x69\x2a\xf7\x66\x69\x21\x7d\x5e\xbd\x46\x08\x5b\x39\x88\x90\xe5\xc9\x1f\xdb\x4d\xb5\xba\x40\xe7\x77\x3d\x51\x8d\x3c\xf0\x0c\x0a\x5b\x5a\x4b\x0f\x1b\x85\xd6\x29\x16\xa5\x9e\x56\x07\xb7\xb1\xeb\x80"}, -{{0xe9,0xcf,0x16,0xd6,0x96,0xf6,0x3b,0x59,0xe5,0xe2,0x5c,0x9e,0xe2,0xd7,0x5b,0xb0,0x5e,0xd2,0xba,0xa5,0x91,0xa7,0x55,0x7f,0x9f,0xb1,0x29,0xcf,0x98,0x3d,0xe0,0xba,},{0x6d,0x1a,0xe3,0x85,0xe8,0x0a,0x39,0x55,0xe8,0xd0,0xc5,0x93,0xa8,0x1f,0x43,0x1c,0xd4,0x32,0x67,0x1e,0x78,0xcd,0xba,0xfe,0x83,0xfe,0x58,0xdb,0xcd,0xb9,0x85,0x60,},{0x81,0x12,0xac,0x37,0xea,0xfb,0x74,0x9d,0x3f,0x4a,0x1e,0xa1,0x48,0x43,0x79,0xdf,0x3e,0x38,0x3b,0x01,0x9c,0x12,0xde,0x85,0x15,0xe3,0x49,0xe4,0xf6,0xf9,0x98,0x63,0x2e,0x30,0x96,0x83,0x47,0xa1,0xd1,0x5b,0x09,0xda,0x2e,0xb8,0x00,0xb0,0x3d,0x81,0x9d,0x20,0x2b,0xd1,0x0a,0x6a,0x46,0x3b,0xb0,0x2b,0x36,0x6d,0x68,0x55,0xfe,0x0e,},"\xa1\x0f\xea\x8f\xc9\x3e\xcc\xfe\x2a\x6b\x78\x26\x07\x95\x63\xad\xf8\xaa\x9a\x66\x64\x44\x93\x22\x00\xcc\xa9\x44\x7d\xd0\x27\xc5\xc7\x20\x4e\xa6\x2b\xf8\xf5\xe2\xe3\x91\x45\xac\x39\x48\xab\x3f\x31\x86\x88\x7b\x30\xbc\x60\x23\x30\x24\xb4\x83\xf3\xf5\x19\x03\x6a\x3e\x94\xc8\xd7\x51\x0a\x85\x3a\xc6\xe2\x0c\x6e\x52\x6e\xe3\xcd\xb7\x6d\xe6\x63\xf6\x73\x05\xad\x80\xdf\x23\x42\xc8\x50\x1b\x4f\x4a\x8e\xe3\x66\x5a\x79\x8f\xc4\x37\xdd\x81\x4e\x4e\x47\xe7\xa4\x66\x89\x0e\x0f\xfa\x8f\x51\x0f\x3e\x6e\x19\xc9\xc9\x69\xf7\x0a\x76\xe5\xcf\x30\x54\xd1\x7d\xe4\x59\xac\x8e\xe9\x95\x50\xbd\x38\x31\x9f\x36\xe4\x33\x43\x4a\x92\x6a\xd6\x8b\x96\x1e\x0c\xa1\x0a\xdd\x4b\xa9\x92\xb3\x65\x06\x60\xa2\xc3\xc2\x6f\x5d\x74\x0a\x31\xaf\xb7\x76\x3f\x54\x2f\x72\x3b\x8a\x3c\x92\xd8\xae\x92\xa5\x67\x76\x4e\xfc\x70\x53\x03\x12\xba\xab\xdd\x3f\xbb\xd5\x27\xfe\x0f\xcb\xca\x3f\x6a\x70\x64\xcd\xde\x18\x56\xe9\x7a\xb7\x86\xaf\x7d\x70\x22\xa9\xd4\x6a\x33\x8e\x8e\x17\x54\xaf\xd9\xad\xac\x85\x6a\x38\xde\x2a\x4c\x97\x66\xde\xe8\xdb\xc7\x09\xb0\x67\x1a\x6a\x6e\x6e\x1e\x5d\x12\x07\x4d\x22\x24\x5c\xd7\x3b\xee\xeb\x1b\xd8\xec\xfc\x1e\x85\xa2\x1b\xde\x25\x3f\x7c\x46\x5a\xbc\x1f\xea\xa9\x61\xc0\xff\x5c\xff\x2d\x89\x64\x72\xae\x17\xab\x84\x88\xe3\x3f\xfe\xfd\xb7\x2c\x10\x5e\x20\x4f\x94\x4a\xda\x51\xee\x13\x98\x1a\x13\x6c\x0f\x38\x42\x6e\x3e\x49\xb0\xe9\x18\x41\xc3\x27\x94\xd5\x2f\x13\x35\xdf\xa6\x37\xf1\x51\xc7\xe4\x0f\x9b\x83\x0a\xed\x53\x9a\xc5\x73\x1b\x81\xcd\xe3\x26\x4d\x22\xbe\xad\x31\xa6\xcc\x68\xd1\xa7\x31\x43\xb5\xba\x48\x16\x13\x92\x32\xf3\xf7\xf9\x79\x83\xf4\xec\xba\x64\xc4\x95\x53\xbe\x9d\x6d\x94\x3f\x91\xdf\xe0\x3d\x1e\xe8\x61\x8c\xd4\x0d\x2f\xb7\x23\x8a\x31\xd1\xbc\x38\xe7\x6a\x55\x1f\x9e\xee\x22\xe7\x3a\x27\xd7\xa4\x8b\x40\x87\x72\xea\x72\xc3\xed\x63\x7b\xb4\xb1\x68\xf9\xd7\xae\xad\x94\xea\x03\xbc\x11\x10\x99\x01\xc8\x89\x92\x7d\x51\xcd\xac\xf9\x62\x12\x59\x62\x55\x99\x79\xd3\xe4\xc8\xe3\xb5\xae\x58\x2f\x2d\xba\xd4\x99\x88\x02\x85\x6c\x4d\xf6\x9e\x8f\xb5\x49\x17\xe2\xf3\x6b\xb6\x7a\x19\xa2\x6e\x9a\x9a\x94\x85\xbc\xe9\x8d\xbf\xff\x0d\x2b\x02\xb9\x37\x7a\x91\x37\xa7\x34\xe5\x7b\x5c\xe6\x65\x05\x30\x17\xe9\x92\x67\x7a\x1a\xa0\x79\x24\x0d\x2c\xf9\x63\xcd\xf9\xbf\xea\x8d\x46\x00\x91\x23\x2d\xaf\x89\x80\x1f\xd7\x51\x71\xa6\x19\x5a\x5c\x04\x68\x15\x91\x4b\xe1\xf6\x28\x68\x78\x3d\x6f\x2c\xf2\x8a\xf9\x37\x8d\x6c\x68\x93\xe7\x5d\xe6\x41\x11\x1c\x68\x47\x27\xef\xfa\x31\xb8\xbc\x9b\x0a\x01\xdb\x9c\x9e\x81\xcc\xd8\xf4\xd4\xe8\x75\xd4\xbd\x90\xd2\x53\xf5\x89\x89\xa8\xa5\x2a\x20\x3a\x77\xa4\x96\xd6\x97\x98\x6b\x03\x1e\x9f\x69\x9b\xc6\xa1\x6c\xd5\xf9\xc3\x60\x18\xeb\xda\xa3\x6b\xad\x0e\x01\x4f\x4c\xf3\xb4\xb7\x46\x17\x1b\xf8\x93\x14\xe8\xb7\x2c\xbd\x47\xcc\x61\x6a"}, -{{0x23,0x8a,0x6d,0x49,0x79,0x32,0x1a,0x14,0xa9,0x97,0x23,0x6f,0x45,0x85,0x04,0x6c,0xf7,0xa0,0x5c,0x0a,0xdc,0x6b,0xa1,0xfd,0xb1,0x9e,0xc2,0xa3,0x2f,0x62,0xbe,0xeb,},{0x0b,0x4b,0xa6,0x74,0xe4,0x01,0x66,0x5b,0x67,0x90,0xcf,0xda,0x08,0x07,0x04,0xcd,0x90,0xe2,0xf3,0xd3,0xef,0xab,0x25,0x3e,0xd8,0xdc,0xfb,0xd1,0x8e,0x40,0x67,0x89,},{0x29,0x42,0xf7,0x08,0xc0,0xed,0xe4,0xcb,0x0d,0xde,0xf1,0x3b,0x85,0xd7,0x1d,0x72,0x13,0xe0,0x38,0x3d,0xd2,0x94,0xf5,0x34,0x13,0x5f,0xd6,0x9c,0xaf,0xbc,0xfc,0x0e,0x33,0x09,0x0a,0x2a,0x0c,0xa3,0xfa,0x57,0x2c,0x72,0xcd,0xf5,0x59,0x2d,0xe9,0x03,0xb1,0x58,0x44,0x95,0xab,0x63,0x99,0x81,0x50,0xf2,0xb3,0x93,0xa3,0xb3,0x40,0x0c,},"\x97\xcd\x61\x9a\x22\x51\xed\xa9\x16\x64\x64\x31\xd4\xcd\x15\x98\xc2\xd4\x4d\x06\xaf\x3e\x48\xbd\x18\xe3\xde\x7f\xb4\xbd\x4f\x78\xe0\x0a\x69\xee\xab\xde\x3f\x82\x06\x5c\xfe\xe6\xcd\x71\x1f\x07\xd2\x26\x37\x16\x1f\xf6\x85\xf6\x5a\x7d\xdf\x54\x55\x31\x97\xfd\x31\xc5\xc6\xb7\x1d\x9e\x36\x5a\x94\x1d\xce\x4c\x3e\x22\x5d\x19\xcc\x63\x3a\x7e\x12\x86\x2c\xd2\x3e\xbb\x7c\x74\xa7\x04\x85\x0f\x76\x1a\xc0\x24\x1b\xe5\x17\xce\x7c\x36\x09\x36\xce\x07\x25\x0d\x9f\x2e\xb2\x78\x71\x15\xee\xc3\x77\xe1\x13\x4d\xc0\x8f\x44\xeb\x0a\x2a\x2a\x27\x16\xf0\x01\x44\xa4\x9f\x01\x2a\x57\xb3\xcd\x06\xef\xeb\x3f\xae\x92\x0f\x28\x5c\xff\xd9\xa4\x01\xa0\xb9\x86\x59\x4e\x17\xb2\xc9\xc8\xfd\xab\x83\x5d\x9f\x3f\x5d\x47\x4b\xe7\x33\xc1\x92\x5e\xe6\xf0\x93\x86\x71\x10\x66\xc3\xfc\xd6\x45\xee\xb0\xfb\xe7\x05\x41\x69\xeb\x70\x9d\x4a\x3f\x0d\x16\xf2\x8a\x1f\xf5\x06\x6c\x84\x2b\xc6\x3e\x35\x9e\x92\x48\x5b\x38\x75\x7f\xf4\x6c\x27\xf7\x9d\x0c\xdc\xf0\xe1\x6e\x97\xe3\xc7\xb7\xe2\x17\x8d\xff\xd2\x70\x28\x2d\xd6\x12\x05\xd5\x85\x4d\x84\x1f\x0e\x3f\xc0\xe4\x82\xcc\x1e\xe4\x85\x52\xcf\xe6\x58\x93\x5b\x54\x27\xc3\x66\x23\x0a\xef\x79\xae\xf4\x02\x1d\x6f\xab\x5f\x18\x75\xcc\x84\x9e\x32\x1a\x75\x50\x0e\x9e\x1b\xa5\xdd\x59\x6b\x43\x8c\xf8\x8b\x23\x5b\x01\xa6\x76\x25\xc4\xbf\x84\xd0\x72\x4a\xe6\x88\x0a\x37\x85\xe3\x3b\xd9\x23\x5f\xd0\xf5\x98\x18\x04\xd2\x1c\xbd\x63\x3c\xb1\x80\xf3\x44\x56\x46\x02\x07\xa2\x90\xa2\x54\xd9\xfe\x61\x06\x3d\x40\x63\x4c\xa3\x87\x2f\x09\x35\xfa\x28\x32\x87\x95\xca\x41\xb0\x06\xa2\x11\x1f\xc5\x93\x2b\x1e\x77\x9c\xe9\x66\xcc\x47\xad\xb7\xc0\xdd\x98\x73\x33\xba\x75\x29\xa1\xa4\x99\x6c\xe9\xf5\x6e\x05\x19\x81\xfe\x1f\x55\x3e\x57\x8f\x43\xc3\xba\x94\xbe\xac\xc9\x3c\x3e\x73\x96\x67\xc7\xa7\xc6\xfa\x27\xe1\xe0\x81\x69\x5d\x20\xba\x70\x5c\x3f\x10\xb2\x0d\xf5\x30\xcb\xb0\xec\xb8\x74\x56\x50\x11\x09\x68\x70\x19\x31\x84\x52\x78\x5d\x38\xe7\x66\xb3\xcd\x35\xb0\x07\xd7\xe3\xcf\xe0\xb2\xcc\xa8\xaa\x6e\xf7\x39\x55\x99\xdc\xb9\xc4\xd2\x8b\xcc\x35\xc7\x6d\xfc\x35\x34\x3c\xb1\x34\x8b\xa3\xe9\x62\xf1\x0e\xe8\x6f\x86\xf5\xb6\xd4\xca\xe2\xe8\xc2\xb1\x85\xe3\xea\xa1\xae\xb8\x7b\xcf\xcf\x2f\xb7\x6c\xc7\xfc\xc6\x89\x50\x71\xb1\x68\xe8\xb7\xf6\xca\xa0\xfd\x63\x98\xe7\x78\xcc\x07\x91\x2f\xf5\xd6\xe6\x10\x21\xa8\xa5\x9a\xe0\x35\x21\x60\xf5\x6d\x54\x88\xfe\x2f\x2a\xcc\x94\x03\xda\x9a\x9f\xfc\x66\x1c\x1e\x9d\xc5\xbe\x88\xc4\x20\xdb\x0f\xd7\x7d\x84\x5d\xc8\xdd\x9d\x8e\x58\xf9\x96\x1b\x79\xaf\xc6\x86\x24\xba\xa8\x6a\xa6\x43\xa8\xa3\xc7\xed\xf7\x1d\x55\x3c\xc0\xd3\x22\x4a\x60\x69\xec\x67\x4f\x52\xda\x29\xa1\xcb\x60\xc4\x19\x23\x01\xa2\x43\x47\xa8\xaa\x83\x26\x26\x9e\x0a\x14\x78\x0c\x95\x83\xcd\xff\x51\x59\x27\xfd\x5b\xef\x52\x8f\x9d\x23\x78\x7a\xeb\x80\x3d\x70\xeb\x91\x6b"}, -{{0x59,0xd5,0x01,0x39,0x3d,0xc5,0x99,0x97,0x23,0x81,0x07,0x06,0xfa,0xd7,0xd6,0xef,0xd1,0x63,0xc4,0x47,0x10,0xc7,0x41,0xc1,0x85,0xc2,0x7e,0x04,0x25,0xe3,0xc0,0x5b,},{0x82,0x65,0xd4,0x3c,0xfb,0x07,0x35,0xb5,0xd7,0x25,0x0f,0xcf,0x0f,0xcb,0xd1,0x54,0xbf,0xc0,0xee,0xcb,0x13,0xb7,0xad,0x93,0xb6,0xb0,0x29,0x40,0x58,0x8b,0x84,0x3b,},{0xe6,0x46,0xf1,0x64,0xcf,0xed,0x8c,0x2e,0x06,0x07,0x10,0xdc,0xfb,0xc3,0xe9,0xfa,0x5e,0xb3,0x96,0x37,0x68,0x13,0x19,0x01,0x84,0xe3,0x46,0xf5,0x2b,0xb0,0xba,0x57,0x46,0xcc,0xb6,0xb5,0x95,0x22,0xb1,0xaf,0xf9,0x83,0x0f,0x2f,0x98,0xb9,0xe5,0xda,0xfc,0xd8,0x32,0x07,0x78,0x83,0xc4,0x4e,0x8a,0x35,0x38,0x8f,0x71,0x8b,0xf4,0x0c,},"\x56\x4e\xd2\x2c\x17\x2f\x5c\x3a\xfb\xb0\xb9\x5a\xd2\xfc\x64\xe4\xbe\x6d\x4d\xb1\xeb\xb8\xd3\x99\xc4\x3a\x5e\x16\x04\x8e\x7f\x87\x32\x18\x1e\x5d\x0e\xed\x8e\x63\x8e\xf2\xa5\x5a\xa0\xd7\xb6\x81\xfe\x02\xbb\x54\x23\xaf\x94\xbd\x35\x2d\x3c\x2d\xde\xc0\xf8\x47\x60\xa4\x11\x2b\x4f\xe0\x17\xcf\xbc\x50\x2f\x95\x43\xcf\xa4\x1f\xb2\xaa\xe7\x5a\x3a\x08\x1f\x8c\x49\x90\x33\xd1\xfa\xe5\xd9\xc5\x0c\xb4\x4d\xbc\x63\x60\x5a\x54\x39\x8f\xbf\x07\x98\x52\xeb\xa8\x6f\x2f\xdf\xc2\x72\xd0\xc4\x17\x9d\x7c\x13\xcb\xc1\xc2\xa3\xda\x0b\x82\x84\x5c\xf1\xa4\x6e\xbb\xe3\x1e\x79\xb6\x00\x97\x33\xc7\xbf\xe7\xaa\x4f\x9f\xfd\x71\x9c\x77\xdc\x7d\x74\x8e\x49\x2e\x14\xee\x5e\x41\x79\xbf\xa9\xe6\x49\xcf\x0d\x89\x53\x41\x86\x38\x5e\xe9\x94\x10\x05\x1d\x66\x56\xe6\x23\x43\x8c\xc7\xb2\xe7\x07\xe4\x8c\x84\x91\x55\x49\xae\x8d\x67\xa3\x06\xc6\x7b\x10\x6b\x7a\x25\xf4\x5f\x8e\x10\xdd\x7d\xd3\xea\xac\x31\xf1\x05\x22\x57\xeb\x6a\x75\x76\xb6\x85\xcb\x9e\x6c\x1c\xd0\xd7\x3c\x7a\x3c\xed\x5a\x8d\xd2\x73\x08\xae\x00\xf9\x5e\xab\xda\xe9\xd1\xc4\xaa\x89\x34\xe2\x42\x4c\x93\x28\xa5\x22\x8f\x4f\x82\xdd\x4a\x66\x55\x6d\x82\x17\xc5\xa2\x2b\x2b\xeb\x86\xa2\xa4\x34\x13\xee\x5e\x10\xf8\x83\xf2\xcd\x6c\x2e\x87\x49\xb5\x50\x88\x42\xec\xae\x5f\xfc\xcb\x79\x6d\x96\x33\xe8\x7e\xf4\xa9\x6c\x0d\xf7\xef\x47\xb2\x83\xd0\x96\x72\x3b\xa3\x13\x5b\xad\x75\xb2\xe1\x9e\xc0\x4f\x70\xa4\x78\x42\x8a\xd5\xd0\xaa\xc0\xdd\x2a\xb9\x90\x59\x13\xe7\xe5\xad\xe4\x08\x80\x1d\x5d\x3c\x54\xd9\xcf\x7b\x8f\x0f\x0c\x5e\xb0\x54\xc1\x47\x5c\xc2\x10\xa2\xc7\x98\xd8\xbd\x89\x93\x2f\xf9\xf3\x60\x42\x18\x58\x05\x3a\x70\x7b\x8b\xbd\x32\x05\x5c\x44\xb2\x07\x12\xa2\x67\x8a\x9a\x6a\xf9\xe3\x6d\x04\xdc\xff\x44\xf4\x31\xcf\x19\x30\xcd\x18\xfc\x93\x5d\x22\x67\x77\x5c\x69\x09\x67\x25\xed\x89\xa2\x91\xdd\x60\xe2\x1a\xc0\xb0\x12\x87\x34\x07\x29\x92\x82\x3e\xf8\x7b\x5e\xfa\x6c\xc5\xb0\x50\x17\x7f\x55\xf4\xce\xc9\x2a\x08\xa6\x5b\xca\xdc\xab\x9a\x41\xc3\x60\x86\x37\x0b\x7b\x9d\xd6\x29\x8a\xc7\xb0\xae\x6a\x09\xc9\x71\x0a\xbb\x46\x76\xa8\xfc\x87\xa3\x65\x12\x90\x14\x4b\x6b\x30\xef\x4f\x6f\xbe\x5b\x9a\xd2\x52\x37\xfe\x06\x05\xe3\xb9\xf1\x8a\x77\x18\xac\x9f\xca\x6f\x32\x5e\xa5\x5f\x49\xa8\x07\xfb\x80\xa2\x40\x2a\xe1\x34\x23\x08\x0d\x32\x77\x58\x64\x90\x23\x79\x8d\x57\x28\xe0\xdc\x64\xac\x88\xa6\xe2\x94\x5d\xbb\x3e\x3f\xfa\x9f\xdb\x4c\x7b\x58\xfb\xa3\xf5\xfb\xd6\x7c\x68\x6b\x29\x71\xbb\xd8\xba\x4d\x27\x5d\x57\x3e\xb7\x96\xeb\x91\x46\x77\x5d\x8c\xdc\xd5\xfd\x3e\xb5\xa8\x8e\xa5\xa9\x30\xec\x32\x44\xe6\xa3\x7c\x81\xf6\xa2\x55\x4e\x5b\xa7\x87\xf0\xe4\x53\x19\xfe\x4b\x8a\x2f\xfb\xfe\xd5\x07\x70\xe7\x82\x7b\x3e\x7b\xc2\xb4\x4c\xe5\x12\xae\x60\x51\xb6\xf9\xf1\x39\x31\xea\x6a\xcc\x09\x6b\x8d\xcb\x01\x96\xbe\x42\x24\x84\xdb\x5f\xcb\x29\x9d"}, -{{0x83,0x9f,0xb1,0x32,0xe6,0x92,0x50,0xca,0x1a,0xd9,0x45,0x10,0x08,0x7f,0x92,0xce,0x06,0x87,0x69,0x21,0x3a,0x19,0xb2,0xa6,0xc8,0x94,0x90,0xf1,0xf5,0x78,0x80,0x7a,},{0xeb,0x58,0x66,0x19,0xb4,0x4a,0x15,0x37,0x9a,0xcc,0x46,0x21,0xa2,0xac,0x71,0xea,0x58,0x97,0x00,0x26,0xc2,0x8e,0x24,0x09,0xfc,0x1b,0xa2,0xbd,0x8b,0x23,0x6d,0x1d,},{0x66,0x43,0x7b,0x6b,0xc0,0x5e,0x75,0xdd,0x16,0x26,0xc3,0xc4,0xff,0x1f,0x72,0xe6,0xdb,0x38,0x1b,0xa1,0x59,0x09,0x48,0xf8,0xf1,0x6a,0xd4,0xd6,0x6e,0x59,0x91,0x65,0x9a,0xa8,0x44,0x05,0x56,0x8c,0xfb,0xc0,0xa7,0x7c,0x02,0x5e,0x59,0xe4,0x3f,0xd5,0x3a,0xb9,0xff,0xab,0xba,0x7b,0x25,0x8f,0x78,0x79,0x62,0x39,0xf9,0x0d,0x45,0x01,},"\xc5\x72\x32\xfe\x32\xf1\x1e\x89\x4b\x43\x7d\x40\x45\x62\x07\xcc\x30\x6d\xb4\x81\x69\xb2\x0e\x07\x81\x10\x3a\xff\xe8\x02\xf5\xaa\xbe\x85\x82\x95\x2c\xa8\xe9\x57\x45\xe9\x94\x0d\x53\x5e\x00\xff\x65\xab\x3c\x64\xbe\xd3\xd1\x17\x3a\x0f\x3d\x70\xce\x4e\xbe\x2b\x50\xd0\x48\xbb\x47\x16\x4d\x2a\x2c\xd9\xd9\x5a\x10\xcf\x0d\x07\x3e\xd1\xc4\x1b\x3d\xe3\x33\x52\x8e\xe3\x29\x68\x22\x3a\x0d\x84\x7c\xad\xbb\x5b\x69\xf3\x82\x16\x4e\x9a\x28\xd2\x3e\xc9\xbd\xe9\xa8\x28\xe8\x77\x1c\x9e\xb4\x92\x20\xaf\x54\x18\x55\x08\xaa\x07\x3a\x83\x91\x95\xf1\x03\xbc\x2f\x32\xfe\x04\xf9\x51\xca\x45\xbf\xbf\x30\xd2\xfb\x81\x14\x05\x6a\x73\x6a\xdd\xf2\x7e\xcd\x9a\xf0\xf6\xe5\xe9\x7e\x57\x73\xc4\xfa\x90\x22\x68\xc3\x2a\x15\x14\x10\x95\x5f\x3c\x76\xaa\xe2\x55\x54\x9e\x0f\x03\x3f\x89\xe1\xa7\x8f\x26\x5c\xba\xb6\xbe\xb7\x51\x6d\x4b\xad\xc4\x9c\xda\x45\x88\x31\x62\x25\xb4\xc8\x5e\xa9\xfa\x99\xc7\xd6\x76\x6e\x94\x90\xc4\x9d\xe5\x9d\xa7\x17\xf6\x67\x65\x35\x30\x07\x1d\xd2\xf0\xc5\x3e\x31\xd8\x76\x81\x56\xfe\xb0\x8f\xaf\x00\xdb\x0a\x04\x53\x3d\xf9\x79\x57\xa8\x4a\xa4\x6a\xeb\x7e\x36\xc0\xb0\xbe\x69\x01\x89\x46\xf1\x53\x8a\x6a\xea\x71\xdf\x53\x6f\x14\x42\xc2\x44\x4a\x43\xa0\x43\xd0\x46\xab\xde\x1a\x78\x2b\x0f\x4f\x5c\x6a\xa7\x20\xaa\x60\xaf\xed\x94\x7c\x0c\xee\x47\x7d\xbe\xc0\x05\x57\xb3\x72\x12\xd9\x33\x57\xca\x2b\x6b\x6f\x82\x71\x5b\xa0\xe4\x84\xf6\xda\xf2\xd0\xb7\xa9\x8c\x03\x35\x19\xce\x38\x26\x35\x86\x79\x6d\x5d\x31\xcb\x2b\xc3\xd1\x12\x5b\xc0\xcc\xd3\x29\xa5\xc2\x1f\xd2\x7a\x21\x8d\xed\x60\x7a\x0e\x75\x15\xb5\x71\xf1\x92\xc3\x3f\x5f\xba\x51\x4a\xfe\x4d\x45\x81\x00\xf3\xcc\xba\x3f\x38\xeb\x43\x0b\x4f\xc8\x8f\xae\xf9\x99\xfa\x71\xee\xe4\x88\x22\x89\x03\xbe\x29\xf2\x4d\xf8\x1d\xc9\x11\x04\x4e\x92\x4c\xda\xa0\x17\xcc\x7d\x87\xe5\x6a\x6c\xba\x87\x60\x85\x9b\xd6\x3d\xd2\xd4\xf5\x81\xb9\x55\xec\x92\x4a\x49\xaf\xb4\x7c\xa0\xd6\x3e\x78\x26\xfd\xc7\x12\xb4\x94\x3b\x73\x9e\x18\x57\x75\x5a\x33\xc6\x50\x36\x75\xfd\xde\xae\x06\x27\x06\xe3\x4f\x74\x4f\xd9\x32\x64\x8a\x56\x08\xce\x60\x8a\x61\x99\x57\x83\xf3\x33\x9c\xa3\xfe\x10\x7e\x19\x72\x74\x4b\xf6\xd4\xed\xaf\xbf\x47\xce\x02\x1e\x05\x82\x1f\xb1\x24\xc7\x08\x39\x30\xe6\x8e\x6f\x5c\x32\xd2\xd9\xfc\x4a\x88\x4c\x0b\xc8\x84\x04\xe4\xcf\xe3\xc1\xa2\x42\x0d\x41\x82\x3a\x38\x5f\xb3\x28\x8d\xb6\x5c\x89\x54\x5f\x6e\x73\xf0\xd8\x00\x4b\x2b\xa1\x2a\x4e\x07\x72\x75\x23\xef\x08\x56\x70\xda\xff\xaf\x41\xc2\x8a\x4c\x11\x57\xbd\xd2\x45\xe6\x87\x50\xdd\x20\x0e\x02\x3a\xf9\x0c\x67\x56\x1e\x0f\xe4\xba\x34\x0c\x43\x3f\x75\x5e\xef\xab\xd4\xb0\x39\xbf\xc3\x23\xdc\x11\xad\xb7\x5a\xec\xc4\x48\xa8\x69\xc7\xf2\xa5\x8b\x9d\x86\x17\xc6\x4b\x8f\x89\xfc\x58\x3f\x8c\x94\x8e\x2d\xf0\x25\x1a\x6c\x7d\x8c\x73\x8c\x3b\x5a\x42\xb7\x49\xad\x5e\x8e\x98\x6b\xd8"}, -{{0xad,0xc1,0xe5,0x6c,0x3a,0xc9,0x4e,0x6c,0xda,0x04,0x11,0xcb,0xc3,0xce,0x2a,0xf1,0x28,0xd1,0x85,0xa2,0xa2,0x73,0xbd,0xb2,0xaf,0x8d,0x7e,0x50,0xfb,0x96,0xb5,0x26,},{0x5d,0xcf,0xec,0x1f,0x91,0x12,0x75,0x15,0x64,0xec,0xb6,0x07,0x15,0xeb,0xb2,0xc5,0x17,0xb5,0xec,0x37,0xb2,0x53,0x4f,0xd6,0x32,0x99,0x24,0x42,0x9b,0x7f,0xd5,0xc5,},{0xf0,0x2e,0x5d,0xbc,0xb6,0x87,0x04,0xaf,0xad,0x03,0xac,0xa8,0x10,0x61,0xdb,0xdb,0x99,0x85,0x70,0x04,0x9f,0x10,0xce,0x65,0x0e,0xc7,0xa2,0xef,0xf1,0x5c,0x79,0x3d,0xdf,0x5a,0x27,0x2c,0xb6,0x83,0xc2,0x2c,0x87,0x25,0x7c,0x59,0xbd,0xef,0x39,0xef,0xea,0x79,0xbd,0x67,0x95,0x56,0xea,0x15,0x05,0xed,0x00,0x36,0xcb,0x46,0x04,0x0c,},"\xd4\xf9\x59\x47\x4e\x0b\x89\xe2\xdc\xd0\x20\x66\x98\x4f\x88\xd7\x39\xdd\x11\x34\xa3\x33\x09\xf0\xa8\xb7\x80\x2e\xaf\x01\x33\x03\xc1\x35\x15\xdf\xeb\x46\x1e\xa3\xd2\x48\xe9\x98\xb9\xa4\xe5\x4d\xae\x5b\x00\x19\x0a\x45\xe7\x0d\xc6\x7e\x98\xf3\xd4\xcf\x90\x6c\x21\x4d\x4f\x63\x6d\x29\x52\x92\x5e\x22\xb1\xa8\x6a\x1a\xab\xb3\xa8\x92\xa9\xf8\xed\x45\x4f\x39\xc6\x3d\x35\xb7\x1e\x87\xa2\xda\x55\xa8\xe1\x67\xac\x83\xa8\x66\xad\x16\x7a\x17\xae\xd1\x83\xc0\x85\x18\xc1\x5e\x6b\xe3\x48\x58\xb4\xce\xe2\xb8\x42\x73\x14\x76\x0f\xff\xdd\xd5\x92\x38\x54\xb1\x74\x7f\x79\x6e\x1a\x52\x49\xfb\x30\x44\x89\x4e\xd6\x46\x82\x9f\x65\x43\x16\xee\x52\xf4\x01\x0c\x8d\xd3\x21\xfa\x1d\xec\x39\x7e\x50\x14\x5e\xd9\xe3\x16\x86\xfd\x52\x03\xf7\x23\x3b\x8d\xa7\x80\xac\xaa\x91\xee\x0b\x5b\x47\x20\x78\x66\xaa\xd8\x5f\x83\x7e\x03\xb4\xe6\xf6\xde\x8c\x04\xac\xaf\xd7\x07\xbd\xc1\xdd\x45\x50\x0a\xb5\x64\x80\x1b\xee\x9a\x58\xec\xe3\x60\xd0\x04\x82\x8b\xaa\xf5\x23\xe2\xf5\xab\x69\x32\x6a\x03\xaa\xbe\x01\x08\x78\xfd\x43\xff\xaa\x56\x87\x22\x44\xd7\x68\x1f\x16\x18\xe6\x23\xe3\xd4\x74\xc7\x3a\xf8\xb0\x80\xa6\x18\x21\xa5\x74\xef\x2f\xd7\x52\xd2\x3b\x60\x5e\xc5\x21\xc1\x9c\x15\x50\xde\x98\x0c\x09\x4d\x05\xe0\x23\x8f\x3e\x00\x8e\x6b\x19\x5a\xbf\xdd\x40\x28\xee\x1e\xe1\xd6\xc6\x6a\x76\xf1\x78\xf0\xb4\x31\xe4\xaf\x44\xdd\xcc\xfc\x52\x90\xed\xff\x36\xec\xe6\x3e\x83\x85\x56\x70\x13\xf4\x3a\x2a\xeb\xb6\x7e\x3e\xf4\x06\x30\x8c\x20\x48\x8a\x76\xd5\x8a\x21\x4f\x31\x39\xd9\x83\xb1\x9a\xfb\x12\xe3\x28\x36\x07\xfd\x75\x10\x7b\xd3\x1f\xeb\x62\x56\x17\x4b\x7a\x18\xae\xca\xc9\xf8\x56\x25\x82\x01\x8b\x0e\x6d\xe4\x05\x35\xe3\x5b\xef\x2b\x56\x25\x53\x88\x51\x29\x39\x75\x62\x90\x0d\x34\x17\xf9\x8c\xdd\x1e\x29\xd7\x31\xff\x48\x93\x3f\x29\x52\x95\x81\x63\xba\x67\xd5\x95\x61\x81\x1b\x83\x77\x2b\xd0\x57\x10\xb6\xe3\xcc\x04\x34\x60\x99\x37\x50\x72\x23\xab\xb7\x1a\x6a\x8c\x83\x8f\xec\xdb\x1d\x2d\x37\xc9\x5d\xc8\x06\xf6\x5f\x3f\x96\x63\xd9\x9f\x06\xe6\xc0\xf3\xc3\x2e\x95\xaf\x1d\xd7\x08\xe8\x11\x08\x63\x6a\x26\xb9\x68\xe9\x83\x39\xc7\x41\x28\xb6\xcf\x67\x13\x35\x88\x4a\xc7\x2f\x75\xb6\x37\x19\x5e\xa9\xec\xa0\x53\x60\x89\x96\xc3\x2e\xd4\x45\x41\x0f\x67\xfa\x10\x4b\x39\xf0\xfd\xf3\xc9\xb5\xc6\x15\x7b\x76\x80\x37\x56\xb2\x7f\x4c\x3b\xa1\xb4\x7f\x32\x85\x76\x24\x8e\x9b\xc5\x3e\x7b\x8a\xb0\xb2\xed\x97\xc2\xf9\x99\x8b\xcc\x7d\xfe\x39\xe2\x64\xaa\xd3\x0c\x6c\xfe\xf2\xb5\x55\x3f\xfb\x5a\x69\x9a\xa4\xbd\x0e\xab\xe4\x38\xce\x05\x22\xcc\x91\xfe\x4e\x72\xbf\x7e\xac\xba\x47\x71\xcc\xf6\x3a\x37\xaa\xfc\xad\xbf\xbf\x99\xdd\x76\xb8\x5b\x80\xee\x07\x5d\x3a\x7d\x1a\x90\xa5\x5b\x77\x29\xa5\x41\x6e\x5b\xe6\x96\xbf\x9f\xb7\xf3\x15\x8c\xfd\xb5\xcf\xda\xcd\xde\x81\x72\xee\x1a\xb9\x48\x6e\x24\xcc\xea\xd2\x9b\x45\x7a\xcf\x43"}, -{{0xdb,0x89,0xdf,0x6a,0x23,0xd8,0x90,0xb7,0xf0,0x02,0x60,0xe8,0x1f,0x4a,0xd9,0x8f,0xd0,0x94,0x40,0x36,0x51,0x31,0xe8,0x5e,0x22,0xc7,0x95,0x1a,0x18,0x7b,0x02,0x18,},{0xc9,0x67,0x63,0x67,0x2e,0xe4,0xa2,0xcc,0x5a,0x93,0xb6,0xa6,0x83,0xdf,0x9b,0x5d,0xe4,0xd9,0x38,0x6a,0x79,0x08,0x35,0x68,0x1d,0x12,0x17,0xd1,0x92,0x96,0xbd,0xc8,},{0x80,0xb7,0xfc,0x8b,0x6a,0xe6,0xee,0xce,0x81,0x66,0xb7,0xea,0x53,0x4c,0xb5,0xb2,0x14,0xc9,0xea,0x99,0x73,0x92,0x1e,0xd0,0x5d,0xe4,0x0c,0x78,0xe1,0x4f,0x16,0x2b,0x09,0xe9,0x78,0xca,0x6d,0x86,0xee,0x43,0x4d,0x98,0x4b,0x8b,0x00,0x70,0x40,0x9d,0xd2,0xad,0x11,0xb5,0x31,0x78,0xe2,0x39,0xda,0xb5,0xbc,0x39,0xc7,0xba,0x46,0x0d,},"\x54\xc1\xc5\x11\x1e\x08\xc9\x82\x45\xba\x4f\x13\x18\xba\x1d\xb1\xdc\xc7\x4d\x14\xa5\xc9\x8a\xb9\x68\x9c\xba\x1c\x80\x2c\x68\xbc\xfc\x81\xfd\x87\xff\xc6\x1c\xaa\x94\x2f\x66\xd7\xe5\x15\x7f\x65\x53\x8c\x7e\x7b\x33\x17\x04\x84\xb4\xb6\x54\x3f\x36\x20\xff\x29\x63\x8b\x64\xd4\xda\xe7\xb0\x22\x21\xcf\x77\x83\xf1\x87\xec\x42\x31\xe6\xb6\x94\x6d\x82\x76\x20\x74\xf0\x9c\x32\x78\x1c\x2f\x38\x46\xde\x3e\x82\x17\xf6\xe1\xb6\xe0\xd2\xb5\x59\x5d\x74\x2e\x2c\x4e\x32\x5a\x28\x41\x92\x40\x44\xdf\xcf\x12\xb4\x79\xeb\x69\xf1\xbb\xd4\x0e\xab\xdd\xd1\xff\x54\xa9\x18\x4d\x36\x6d\xff\x9d\x8f\x2d\x86\x3e\x37\x8a\x41\xf1\x0c\xd1\xda\xe9\x22\xcd\x7f\xbb\x2a\x54\x4e\x47\xea\xbf\x47\xca\x0a\x38\xab\xba\x34\x45\x49\x19\xbb\x9a\x4e\xf0\x44\xbf\xb9\x7b\x70\x8c\x2f\x74\x28\xd6\x8f\x9c\x57\xc0\xee\x7e\x79\x25\xf7\xa2\xb5\xc6\xe7\xdf\x82\xbb\x26\x80\xc8\x62\xdc\x7c\xc6\x8b\x0f\x54\x53\x0e\x64\xaf\xe2\x76\x3d\x9c\x7b\xaf\x45\xcc\x6f\xe6\x12\xd1\xf7\x82\x77\x39\xc4\x41\x13\x98\x88\x8f\x73\x67\xc3\xd4\x37\x79\x07\xac\xc0\x6a\x06\xf9\x3f\x88\x72\x26\x79\x8f\x48\xaa\x54\x64\xf6\x01\xc2\xc1\xed\xda\x77\xed\xfe\xb9\xb9\xb5\xd5\xf9\xcb\x6f\xed\x37\x90\x05\x47\x47\x7f\xca\x1d\x09\xab\x52\xd6\x3e\x49\x1f\xeb\x12\xfd\x6d\xc8\x05\xa7\x8c\xee\x3b\xaa\xde\x43\x52\x98\x20\x61\xde\xa5\xa2\x65\x3d\xb8\xe7\x60\x77\x72\xe8\x34\xb3\xa5\x05\xc1\x6d\xd6\xe7\xc7\x1b\x91\x1e\x84\x2e\xba\x92\x5d\x77\xa3\x3c\x5c\x57\xce\x11\x84\x09\x80\x78\xca\x2e\x6a\x3f\x69\xaa\x6a\x14\x63\x9d\xc9\x7b\x4b\x30\xc9\x9d\xc4\xfa\x3e\x2c\xf6\x3c\x70\x1c\x30\x6c\x5e\x25\x3c\x51\x13\x85\x4c\x18\x5e\xbc\x8b\x47\x98\xf6\x8d\x1f\xd7\x80\x05\x4d\x3e\xed\x2f\x39\x4c\x45\x43\x04\x96\x6b\xdd\xbd\x12\x28\x08\x34\xec\x9b\x40\xc1\xe9\x8b\xc2\xd9\x8f\x48\x45\xf6\xeb\x44\xf2\x53\x15\xee\xdb\x3b\x79\xff\xca\x41\x80\xc1\xbd\xdd\x97\xd0\xc9\xaf\xfb\xac\x58\x81\x49\x37\x68\x26\x80\x07\x6f\xe5\xa3\xba\xbb\x65\xd2\x8f\x25\x17\x03\x6c\x0c\xfb\x42\xf0\x29\x3e\xb2\xac\xb1\x39\x49\xfe\x91\xe0\xad\x06\x78\xaa\x24\x3d\x77\x34\xa8\x9d\x99\x78\x70\xbf\x9a\x6a\x58\x4e\xd6\xe6\x28\x16\x3e\x39\xd8\xaa\x61\x0d\x46\xb9\x28\x5b\x9e\x1d\xd7\xe8\xf8\x07\xfd\xf5\xca\x2b\xbf\x6d\xe5\xe5\xe6\x8a\xf7\xcb\x7e\xbd\x43\xec\xce\x22\x7c\xd7\x0c\x7b\xf4\xee\x14\x33\xed\xfc\xfe\x88\x66\x14\x67\x0c\xdd\x19\x63\x43\xfb\x91\xe1\x54\x16\xd2\xf6\xac\xba\xe3\xea\xdc\x03\x02\x31\xee\x9d\x2e\xcc\x52\xa8\x8c\xe8\xdc\x7d\x09\x8e\x7f\xac\x77\x68\x5b\x4e\xb5\x40\xe3\x01\x93\x07\x14\x32\x21\xb8\xef\x77\xf3\x63\x2c\x89\x3d\x55\x6e\x0b\xb7\x43\xa1\x96\x3e\xc1\x58\x86\xc8\x54\x5e\x87\xc9\x5c\xc8\x25\xf2\x00\xd0\xf3\xcf\x4f\x55\xa3\xd6\x60\xa5\x36\xa2\x3a\xef\xcc\x42\x8a\x43\x20\x34\x85\xee\x84\x34\x2f\x5c\x00\x1e\xe8\x40\x4e\x75\x90\x17\x00\x62\x82\xab\x8b\xa8\x90\x3e"}, -{{0x00,0xe6,0xbb,0x17,0xaf,0x3c,0x2d,0xf6,0x52,0xb3,0x4f,0x9a,0xbe,0x19,0xf9,0x90,0x19,0x07,0x42,0x33,0x68,0x6c,0x71,0x14,0xe3,0xa0,0xed,0xf0,0x83,0x09,0x93,0x4f,},{0x7b,0x82,0x32,0xa6,0x6c,0xec,0x2f,0x91,0x5a,0xaa,0x79,0x51,0xd2,0x9d,0x2b,0x9e,0xe9,0x3d,0x32,0x1d,0x15,0xb2,0x03,0xc5,0x1e,0x61,0xe8,0xce,0x83,0xd1,0x87,0xf8,},{0x04,0xb3,0xb8,0x50,0x1e,0x39,0x6c,0x4a,0x78,0x8e,0x14,0xac,0x49,0xf6,0x17,0x4c,0xdb,0x5c,0x85,0x5e,0x65,0x12,0x03,0xcf,0x68,0xd1,0xef,0xa8,0x9a,0xa5,0x86,0x78,0xd4,0xd1,0xf3,0x03,0xa9,0x87,0x7a,0x37,0x86,0xd2,0x03,0xc3,0x55,0xb0,0x9d,0x52,0x86,0xc1,0xca,0x0d,0xf0,0x4a,0x89,0xaa,0x06,0xcc,0x3f,0x9d,0x0f,0xd3,0x05,0x04,},"\x06\x32\x81\xe4\x1e\x8b\xa9\x70\x3e\xd0\x9e\xf3\xbf\x0e\xa4\x6e\x4c\xab\xdd\x6e\xbd\x76\x9d\x05\xdc\x04\x5d\x4f\x99\x0d\x69\xfc\x55\x41\x30\xa4\xe6\x1a\xa2\x1e\x2d\xe4\xc9\x2d\xb4\x8a\x20\xa3\x7b\x17\x47\xa7\xea\xc5\xeb\xb2\x73\x5a\x89\x38\x19\x7f\x13\x9f\xad\x14\x97\xb3\x51\xad\x06\x4c\x0f\x18\xf8\xfa\xf1\xfe\x11\xf6\x39\x79\xa6\x99\x68\xe2\x4c\xf9\x1e\x58\xa3\xab\x03\x26\x69\xe4\xef\xee\x27\x4f\x96\xb5\x8b\xe7\xd9\xe3\x91\xf3\x6f\xcf\x07\x09\xb2\xcb\x2d\x22\x69\x4a\x6c\xeb\x17\x24\x69\x45\xeb\xb3\xbc\x7f\x0f\x03\xbf\x0b\x08\xdc\x96\x26\xe3\xe7\x15\xc9\x91\x67\x1d\x53\xeb\xb9\xae\x83\xa7\xd0\x8d\x44\xf6\x36\x35\xc4\x0f\x8d\x48\x17\xf5\x8d\xe9\xeb\x77\xcb\x25\xb2\xac\xd6\xde\xf9\x69\xab\x56\x9e\x97\x4a\x8a\xda\xc1\x1a\x86\xb5\x8f\xe6\xc1\x00\x67\x49\x9f\xc9\x14\xdf\xf5\x69\x02\xcb\xc3\x93\xa7\x1c\xc2\x5e\x8f\x05\xc0\x3c\x94\xf1\x3b\x84\xa2\xb0\x1a\x58\xc1\x0d\xbc\xbb\x60\xeb\xce\xe4\x87\xf5\x29\x17\x74\x66\x29\x99\x25\xda\x50\xe2\xda\x5b\x55\x57\xf0\xae\xee\x3f\xd7\xf4\x7b\x5c\x2e\x3f\x84\xce\xfa\xb4\x67\x96\x91\x39\x4d\xd1\x22\x30\x3b\xb7\x69\xaf\xb3\xad\xfe\x83\x58\xb0\x2b\x67\x92\x73\xb3\x5a\xbd\xc6\x40\x25\x76\xcc\xce\x5e\x10\x44\x2a\x13\x7e\xf9\x45\x69\x39\xb2\x89\xef\x4e\x41\x7b\x1c\xc6\x23\x9f\x7c\xee\xdd\x68\xf1\xa8\x26\x41\x80\xe0\x68\xb4\x96\x6f\xd6\x7f\x2b\xad\x6e\xdd\x8b\x4a\x1e\x8d\x2b\x54\x2d\xaf\x26\xdb\x83\x1f\x1f\xb5\x1e\xb8\x6f\xfa\xde\xcc\xd9\xac\x3d\x66\x4f\x34\x6e\x7d\x04\x6c\x33\xa5\x72\x84\x1e\xa8\x33\x4e\x7f\x2f\x41\x7a\x05\x71\x2a\x9e\x33\x4e\x48\x7f\xd3\xae\x17\x54\x55\x16\x2f\xe8\xf4\x9c\xc0\x26\xa6\x40\xc6\xcf\x93\xcf\x58\x87\x50\x52\xf4\x1c\xc9\x82\x06\x15\x65\x3e\xa2\xd0\x84\xc8\x96\xea\xfe\x5a\xd4\x72\x55\x79\x65\x30\x84\x99\x4f\x95\x6d\x5c\x94\x59\x0a\x24\x09\x58\x1b\x6f\xc8\x6e\x40\xaa\x58\xbf\x6e\x60\x57\xa6\xf9\x0a\xf3\xb8\x7a\xea\xf3\x29\x94\xa5\x5a\x54\xf7\x9b\xdf\x3d\xbb\xf5\xce\x0f\xf8\x12\xe4\x86\xb0\x54\x5d\x9e\x9c\x2b\x0b\xce\x0d\x4c\x36\x47\xb1\x82\x72\x62\x49\x88\x34\xe1\x98\xa3\xec\x70\xf3\xb0\x3d\x6a\xad\x2c\x49\xeb\x80\xb5\xe2\x05\x14\x39\x22\x5f\xd9\xce\x94\x68\xd6\x9a\xf7\x0a\x26\x2e\xe3\xb8\xb6\x2a\x8e\x5b\x41\x34\x6d\xa3\x01\x2f\xfb\x45\x81\x6b\x7b\xec\xb0\xe7\x9a\x60\xbf\xf7\x16\x36\xa3\xe4\xbb\x1b\x35\xca\xf1\x95\xf5\x51\x17\x28\x0f\x78\x72\x17\xb3\xca\xa2\xe7\x93\x72\x6f\xc5\xa7\x4d\x11\x60\xdc\xad\x86\x89\x04\xc1\x97\x38\x11\x34\xed\x8c\x3d\xb3\x75\x0b\x75\x56\xf6\x9c\xcc\xe1\x8b\x77\x38\x8b\x58\xc5\xb8\x11\x3e\x59\x0a\xd6\xea\xc5\xb9\x1e\xce\x5a\x67\x05\x02\x5c\x80\x35\x3c\xeb\x1e\xd8\x4a\xaa\x1c\xc4\x8a\x41\x6b\xc0\x16\xae\xf1\x73\xbb\x80\xb2\xba\x28\xc5\x79\x60\xc6\xb0\x11\xb6\xb4\x95\xa3\xf3\x31\x1e\x79\xfe\x46\xbd\xb6\xa4\xc3\x81\xfb\x9d\xc4\x62\x8b\x0a\x83\x02\x35\x58\xf1"}, -{{0xfb,0xdd,0xf6,0xe6,0x1e,0x20,0xd8,0x06,0xe5,0x59,0x17,0x75,0x6d,0xe6,0x0d,0x0c,0x9a,0x99,0x97,0x6f,0x64,0x67,0x16,0xff,0x2f,0xf1,0x31,0x2c,0x54,0xdd,0x97,0x1d,},{0xac,0x53,0x8f,0xab,0xad,0x43,0x80,0xe6,0x0e,0x97,0x71,0x26,0xe7,0x69,0x5e,0xed,0xa5,0x41,0x7d,0x85,0xf7,0xd2,0x3d,0xb2,0x1b,0xd0,0xad,0x11,0x11,0x16,0xf0,0x5d,},{0x8c,0x9b,0x77,0xaa,0x0f,0x1c,0xf5,0x2e,0x8f,0x7a,0x91,0x8b,0x21,0xb4,0x68,0xe6,0x23,0x35,0x91,0x1b,0xc5,0x93,0x06,0xb3,0x0c,0xe7,0x7b,0xf6,0x92,0xc1,0x10,0x59,0xb0,0xee,0x9c,0x5d,0xaa,0xf6,0x83,0x9b,0xb8,0x13,0x73,0xc6,0x1d,0x28,0xd0,0x72,0x70,0x2b,0x59,0x5e,0x4d,0xce,0x28,0xcb,0x99,0x38,0x22,0xb2,0x48,0x13,0x04,0x0b,},"\x3e\x99\x53\xca\x55\xd0\xcd\x23\x3b\x98\x83\x3e\xb1\xbc\x79\xd3\xb5\x5f\x18\xc8\xfa\x1c\x42\x02\x7b\xca\x25\x57\x91\x53\xb5\x5d\xa0\xc5\xa1\x78\xb8\x38\x69\x56\xd9\xa5\x41\x83\xb2\x4c\x91\xdc\x4b\xe9\x94\x84\x72\x37\xd3\x66\x6a\x0a\x01\x30\xfe\x19\x92\x4b\xc0\xee\x50\x89\x6c\x35\xa2\xe1\x6a\x29\xe2\xe2\xac\xf1\x80\xbd\xd9\x37\x93\x54\x68\x7f\x0e\xce\x68\x82\xd2\x6e\x98\x0e\x68\x66\x98\x04\x3b\xb1\xb0\x12\x13\xaa\x64\x4a\x4f\x8d\x61\xf9\xb6\x13\xe6\x2e\xaa\x35\x76\xce\xa0\xb0\xb8\x3f\x05\xce\x25\x58\xff\x63\x56\x49\x5c\x45\xed\xe4\xa8\xf6\x5b\x81\x4a\xb8\xa7\x30\x94\x03\xdf\xd4\x3c\xbe\xa9\x08\x93\x93\x9b\x78\x00\xaa\x00\x23\x2b\x5f\x6b\x77\x14\xeb\xdc\xd8\xbc\xf3\x4a\x5a\x7e\x82\x2a\xc7\xb1\xb0\x99\xac\x61\x5f\x13\x5f\x8c\x35\x1d\xc4\x1a\xe5\xf6\x6d\x5f\x9c\x26\x00\x45\x4c\xa0\x1c\x00\x9b\xa6\xde\x04\x16\x2a\xe5\xf1\xf2\x70\x89\x3c\xa3\x90\x7a\xff\x7f\x78\xe0\x33\x96\xe3\x2b\x62\x2f\xf3\x40\x53\x7b\xf1\x23\xe5\x59\x95\xe9\x20\x96\x09\x33\x0b\x2e\xee\x51\x12\x74\x84\xa4\x0e\x25\x07\x00\x82\x3f\xeb\x0b\xc9\x7b\xb5\x09\xff\x73\x26\x75\xde\xc3\x2e\xcb\x63\x5e\xd9\x2c\x7d\x78\xfe\x30\x50\x20\x0c\xf1\xd9\x41\xd6\xb3\x88\x80\x0a\x84\x19\xd9\x6a\x59\x5e\xce\xd5\xec\x4e\xfd\xcb\x6f\x98\x7f\x54\x72\xa5\xc4\x30\x58\xd3\xa3\xa7\xbb\x56\xd7\x98\x03\x65\xed\x43\xdb\xc2\xbe\x48\xf1\xd1\x8c\xe7\x6a\x89\x18\x54\x26\xfd\x5c\x69\xdf\x7e\x92\x91\xab\x78\x23\xc2\x3a\x76\x94\x1e\xd3\x83\x6a\xac\x7b\x58\xc0\xd5\xfb\x6b\x63\x6c\x42\x47\x1a\x4d\x17\x03\x51\x6f\x03\xe9\x35\xf3\x1f\x19\x54\x50\xe5\x37\xb2\xa0\x7d\x54\x5b\xa4\xb6\x8a\xfb\x06\x38\xc6\x5b\xb0\xff\xaa\x0c\xfd\x69\xd7\x10\x48\x19\x79\x66\x19\xd4\x83\xa0\x24\x5b\x4f\xd9\x01\x7f\x62\xa7\xd3\xa5\xfc\x3b\x72\x89\xd7\x57\x35\xf2\x87\xca\x0a\x95\x1a\xd5\x83\x44\xb2\xab\x7d\x7d\xf8\xdb\xd7\x92\x2a\x5a\xbb\x8d\x7c\x2e\x79\x14\x7e\x6d\x36\xee\x31\xf9\x30\x47\x3b\x07\x27\xdc\xfd\x58\xd6\x44\xd7\xd7\x0a\x0e\xd3\x1c\xa6\xa1\x3e\xd9\xdb\xd2\x24\x49\x2e\xfd\xa1\x9e\x4f\x8e\xed\x46\x18\x0f\xe7\x50\xf0\x7b\xbe\x8e\x99\x85\x4d\x13\xf5\x8b\xa9\x68\xce\x38\x59\xd6\x11\x89\xcd\x2b\x66\x7f\x3b\x2d\x06\x65\xb5\x74\xc4\xba\xc1\x9d\x9e\x37\xe5\xb7\xa8\x0e\xb3\x34\xe3\x68\x10\x53\x0a\xa5\xd1\x76\x63\x93\xf8\x11\x5a\x52\x09\x0c\x91\x82\x34\x28\xc8\x97\xa5\xf3\x5e\x12\xa8\xaf\x2c\xd4\xfb\x13\x90\x7c\xa6\x60\x3a\x4f\x76\xf5\xc2\xe0\x23\x74\xa8\xdc\x3a\x47\xc1\xbe\x6f\x1d\x1c\x8e\xbc\x59\xb3\x6d\x1c\xfa\x0a\xb2\x3e\x9b\x0a\xe9\xb0\xe6\x37\xee\xed\xb9\xc6\x6b\xea\x62\xdc\x63\x0c\xde\xfa\x71\x82\x39\x61\x7e\x31\x18\xe5\xb6\xde\xb7\xc2\x94\x47\x52\x82\xe8\xab\xe2\x4f\xd5\xa5\x4b\x78\x6f\xff\x90\x28\xc5\xa0\x33\x38\x4e\x4b\xc8\x01\x4d\xec\x8d\xa1\x00\xa9\x4b\x17\x8e\xf8\x8e\xc3\x57\xb6\x6d\x2b\x90\x98\xab\x64\x79\x16\x96\xb1\xa6\x6b"}, -{{0x8a,0x55,0xe7,0x7b,0xb0,0xc8,0x74,0x0b,0x8c,0x2e,0x8d,0xdf,0xdf,0xdb,0x40,0xf2,0x7e,0x45,0xfe,0x81,0xfe,0x45,0x71,0x11,0xbf,0x1c,0x87,0x30,0xea,0xb6,0x16,0xb4,},{0x9f,0xf1,0xfd,0x0c,0x50,0xeb,0x24,0xf9,0x9f,0xe2,0xf7,0x71,0x1d,0x52,0x87,0x2d,0xfc,0x90,0x03,0x80,0xdd,0xdc,0xdb,0x86,0xfe,0x6f,0x4a,0x5f,0x35,0x0a,0x87,0x43,},{0x8a,0xae,0xba,0x53,0x5c,0x51,0x1c,0x31,0xd3,0xf8,0xe9,0x5c,0xb0,0x77,0xa9,0xa7,0xec,0x7d,0x08,0x44,0x1e,0x53,0x42,0xa6,0xab,0xe0,0xbf,0x2a,0x5d,0x7f,0xc9,0x30,0xb4,0x3d,0xac,0x3d,0x1e,0x8e,0xf2,0xcb,0x03,0x45,0x52,0xeb,0x4d,0x08,0x39,0xbc,0x8b,0xf2,0x94,0x55,0x1d,0xd2,0xd8,0x0c,0x53,0xfd,0x62,0x79,0x35,0x1a,0xc2,0x0c,},"\x20\xfb\x41\x4e\x26\x4a\x95\x47\x84\xf1\x12\xba\xce\x7e\x04\x74\xb3\x9c\xb3\xc9\xe5\x3d\xee\x0a\x21\xf4\xcf\x6d\x4a\x99\xb9\x34\x7d\xdf\xfb\xe2\x81\xa6\xc2\x30\xa7\x5d\x63\xa7\x2f\xd0\x5f\x6d\xb5\x3e\xa7\x01\x4e\xf7\x70\x9d\x18\xff\x97\x0f\x48\x5f\xe8\x3b\xa1\xd3\x71\x47\x33\x8a\xde\xd6\xda\x4c\xfd\xac\xc1\xe6\x9d\x2f\x3e\x0e\xf3\x62\xf4\x7b\x5b\xcf\xb7\x8a\x1e\x17\x9e\xb5\xc5\xb1\x06\xc8\xd8\x2a\x0a\x0b\x29\x0d\xf0\x75\xab\x27\x43\x69\x29\xcd\xe6\x56\xf0\x23\x09\xf9\x57\x50\xeb\x67\x65\x83\x26\x2e\x5f\x2f\x69\xf0\xff\x72\xa8\xe0\x57\x26\x63\x82\x26\x92\x05\x31\x87\x40\xbf\xe0\x6b\xf5\xc2\xcb\x45\x33\x90\x8e\xf9\xf9\xf2\x86\x9a\x75\xb9\x53\x35\x79\x82\x0e\x3b\xc0\xca\xff\xd6\x46\x17\x1c\x82\x86\xc3\xa4\xab\xa1\xff\x09\x15\xd9\x36\x11\x20\x5e\x23\x0f\x39\xff\x4c\x4c\xaf\x3f\x33\x3e\x75\x3f\xce\x2b\x71\x21\x3e\x53\xd6\x08\x41\x5e\xe1\x7f\xd4\x82\x12\xee\xdd\x88\x40\xf3\x37\x10\x1e\xf0\xd0\xb6\xf7\xbe\x4b\xff\xc0\x6e\xee\xfe\x80\x66\xdd\x27\xa0\x54\x1a\x46\x88\x31\xac\xdd\xc4\x90\x2e\x2f\xef\xef\xbe\xd1\x9c\x30\x8e\x56\x21\xe0\xbf\x46\xbc\xd5\x38\xaa\x13\xfa\xf0\x4d\x38\x07\x59\xc0\xe1\x07\xe9\x12\x00\x18\x39\xdf\xd0\xb6\x35\x44\x0e\x96\x38\xf5\x37\x7c\xa8\x45\x0f\x35\x0c\x01\x12\x9e\xe3\x37\x64\x41\x5c\x53\xcb\x2f\xfb\xf9\x68\xdf\x78\xb7\x42\xfd\x06\x65\xe7\x8a\x34\xab\xf4\xde\xcd\x1f\xd3\x86\x28\x9a\x13\x64\xe6\x45\x55\xee\xc5\x8b\x0a\xf9\xa4\xcd\x6b\x36\xd1\xd5\xc6\x11\xa2\x84\x6d\xfb\x55\x89\x34\x4b\xbb\xb0\x25\x60\x24\x1b\x74\xb9\x93\xa2\x5b\xef\x50\xfb\x1e\x73\x19\x08\x6e\x6a\x23\x98\x63\x00\x83\x4e\xd2\xdb\xa9\x8a\x16\x87\x21\xc2\xf7\x84\xdf\xb8\xd3\x80\x0d\x06\xa0\x54\xae\xf1\x4d\x17\x72\xb6\xc5\x74\xaf\x25\x63\xd1\x93\xef\x2e\x51\xbd\xc6\x2d\x2a\xbc\xe2\xee\xbe\xad\xa7\x92\x03\x49\x8e\x66\x86\xc2\x87\xf3\x7b\xd8\x8a\xeb\x16\x6f\x7d\xff\xc3\xe6\xad\x02\x94\x11\x7e\xf6\xee\x9d\xa8\x47\x9e\xd8\xa1\x6f\xe9\xbe\x24\x6d\x26\x68\x04\xf2\x96\x58\xdb\x75\xe7\xa0\x87\x3b\xe7\x1d\xc7\xd4\x07\xe3\x9f\xab\xd6\x6f\x98\x8b\x45\x74\x77\x42\x7f\xad\x81\x30\xf0\x9a\xb6\x65\xf1\x59\x7c\x90\x46\xe7\x37\x3a\xf9\xa8\x35\x2a\x86\x83\x0c\xb9\x2a\x80\x44\x88\x70\x0f\xe6\x89\x19\x24\xfe\x2a\x72\x01\x73\x3d\x95\xe5\x91\xee\x0a\x1f\xef\x1c\x26\x36\x07\x8d\x37\x0e\x7a\xd3\xb6\xa9\x44\xfe\xd2\xcf\x2b\x30\xab\xa2\xd5\x6f\x34\x95\xb2\x84\x9c\x03\xbb\x61\x4f\x48\xbc\x4e\x50\x7c\x39\x5a\x6c\x35\xd3\xee\xd4\xc7\xbe\x8e\x68\x0f\x2d\x45\xa3\x10\xb1\x87\xeb\x88\xcf\x0e\x8e\xd4\xde\x7d\x37\x24\x6a\x50\xa6\x36\x7b\x97\xee\x37\x84\x32\x2c\x0b\x71\x13\x1a\x28\x31\x98\xda\x48\x04\xde\x75\x1d\xcf\x70\xc4\xba\xd0\x0d\xd9\x8d\x87\x3a\x69\xdd\x1a\x09\xcf\x69\xdd\xfa\xd7\xae\x60\x35\x00\xb6\xa4\x62\x25\x80\x98\xd8\xb6\x6b\x85\x29\x35\x94\xe2\x08\x82\x9b\x52\x28\xfa\xe2\xfa\xfc\x39"}, -{{0x16,0x3b,0x0c,0xb6,0xa1,0x2e,0x8f,0x07,0xb0,0xc2,0x9d,0x6a,0x63,0xf6,0xa6,0x52,0xce,0x49,0x72,0x70,0xb5,0xe4,0x6f,0xcf,0x83,0x3c,0x99,0xbd,0x84,0x3f,0x8c,0x64,},{0x68,0xa3,0x5d,0xe4,0xba,0x6f,0x0f,0x82,0xec,0xf4,0xb1,0xe0,0xdf,0x8e,0x24,0xcb,0x4f,0x18,0xf2,0x10,0x3f,0xf0,0x4d,0xc1,0xb5,0x33,0x39,0x91,0xb6,0xd3,0x14,0xba,},{0x17,0x73,0x8f,0x57,0x26,0x55,0x07,0x80,0x65,0x1d,0x60,0x19,0x9f,0xda,0x39,0xd9,0xc4,0x76,0x8d,0xb5,0x91,0x7e,0x32,0x39,0x36,0x31,0xc5,0x4a,0x41,0x9d,0x59,0xf1,0x8e,0xf9,0x60,0xdd,0xd4,0x39,0x38,0x0d,0xab,0xc3,0x14,0x76,0x1b,0xd0,0xcd,0xb5,0x7c,0xce,0x48,0x1e,0x61,0x09,0xfe,0xd0,0x95,0xde,0xa6,0xe8,0x65,0xaa,0x67,0x0b,},"\x56\xa1\x60\x3f\x72\x5b\xe0\x76\x13\x05\x8c\xdb\x3a\xcd\xc5\x23\x54\xe3\xbb\x1f\xf2\xbe\xd1\x3f\x89\x51\x75\xb1\x5c\x8c\x5a\x90\xff\xbe\x46\xb1\x1a\x06\xcf\xe3\x62\xda\xdf\x73\x23\xc9\x40\x41\x72\x55\xaa\x7a\xa5\x43\x12\x10\x3e\x71\x46\x3d\xaa\x0b\x5c\xda\xeb\xd0\xbe\x72\x3c\x73\x22\x73\xe3\xc3\xf5\xbf\x7a\xa3\x51\x9d\x69\xdf\x6f\x47\x70\xda\xa1\xdf\x82\x80\xbb\x3c\xd2\xc7\x14\xac\x03\x02\x00\x54\x65\x79\xf5\x6c\x60\xb9\x1a\xe1\x1f\x4c\xf8\x74\xa3\x5f\xc5\x9b\x35\x4b\xed\x80\xf5\x6e\x11\xa6\xcd\x62\xa8\x8c\xe6\xb4\xf6\xbf\x39\xd6\x4c\xe3\xd8\x04\x09\x82\x5f\x90\x16\x2c\x3d\x96\xd1\x0e\x47\x86\x07\x36\x5f\x7a\x24\x1e\x71\xaf\x98\x00\x42\xfe\xc2\xd6\x88\x91\xe0\xc8\xa3\x7c\x58\xec\x4e\x60\x0f\xd5\x81\xe7\x90\xb0\xaa\xe8\xe0\x9f\x35\xd4\xcc\x18\x76\xdf\x43\x4b\x80\xee\xe0\x53\x69\xf8\x48\xfc\x49\x30\x57\x7d\x16\x84\x27\x58\x88\xf3\x25\x9c\xb4\x73\x76\xc5\x16\x9c\x99\x37\xf8\x55\xa9\x6a\x9e\x74\x8a\xd0\xa6\x9a\xe4\xab\x2f\x2f\x17\x44\xa3\x92\xf9\xac\xc6\x20\x99\x75\xb7\x84\x98\x4c\xb1\x2f\x98\x29\x2c\x36\xa5\x32\x21\x99\x4a\xbc\x56\xf9\xa6\x6d\xae\x45\x60\xb7\x93\x56\xff\x47\xe1\x28\xc0\x79\x6a\x7f\xb0\xe0\xbb\xc9\x60\x0a\xf4\x8e\x49\xea\xa9\x42\x7c\xf6\xeb\x66\x20\xb1\x0c\xd2\xc0\x85\xb0\xb3\x42\x00\x4d\x5b\x0d\x3e\xdc\x11\xd2\x92\x42\xa4\x63\x87\x80\x76\x2c\x9d\xc6\x06\x9b\x66\xbd\x84\x97\x3b\x50\x11\x96\x1c\xe5\x6d\xb5\x8b\xda\xf4\x8e\x6b\xe1\x2a\xb9\xad\x24\x41\x62\x97\x00\x4d\x02\x91\x4b\x95\x9f\x54\xe0\x92\xf8\xcd\x43\x65\xfa\x6a\xb7\x8d\xdb\xff\x4c\xe8\xda\xd4\xe2\xf5\x3a\x05\xc0\xcc\x49\x9b\xfb\x47\x81\x4a\x27\x13\x55\x1d\xcd\x19\xd4\x47\xf6\x27\x57\x6e\xa4\xea\x4b\xbd\xa8\xba\xe1\x8a\x64\x65\xce\xd7\x47\xea\x17\x18\x0b\x00\x9f\x01\x21\x21\x60\x48\x2b\x04\x33\xaa\xc6\x8e\x67\x64\x4d\x00\xf4\x1f\xdf\x99\x90\xb9\xe1\x11\x17\x63\x4d\xeb\x13\x9b\x1a\x40\xad\x3f\xce\x42\x99\xa1\x7f\xe1\xdd\x22\x53\x01\xc7\xf8\xd8\x01\x0a\x79\x6d\xc7\x9c\x13\x30\x7d\x3f\xf9\x92\xa8\x8b\xe6\x64\xd4\xc8\x86\xd6\x8c\xa9\xe4\x47\x0c\xfb\xe6\x3e\xbf\xfc\x42\x40\x10\xe3\x72\xb6\x92\x2a\xa9\x5c\x80\x1d\x1e\x94\x06\xda\x4b\xc1\x88\xca\x82\x06\x64\x05\xbc\xdb\x3e\xaf\xc9\x37\x62\x9b\x32\x63\xdc\x7d\x50\xee\x52\x78\xcc\xec\x6f\x11\xd5\x51\x7f\x56\xbc\x26\x9c\x87\x36\x91\xe7\xeb\x53\xfa\xef\xf0\x75\x64\xab\x46\xb4\x03\xf1\x5d\x9e\x0e\x69\x24\x86\xee\x09\x8e\x7b\x51\xb4\x28\x13\x46\x9b\x82\x35\x04\x22\x33\xca\x3f\x9c\x4f\x8f\xf2\x4a\x57\x1f\x47\xe0\xad\xf9\x14\x4a\xea\x48\x8a\x2d\x2d\xd0\x01\xe3\x1f\xc9\x61\xe0\x5c\x3e\x85\xf0\xd9\x81\x40\x7c\x87\x31\x58\xbb\x0d\x35\xba\xfe\x4b\x60\x42\x2e\x67\x55\x1e\x97\x01\x65\xce\x3f\xc5\x99\xd0\xfc\xc9\x2b\x16\xac\x36\xa9\x2b\x2c\x1d\xc6\xb3\xf0\x33\xfe\x31\x0c\xd1\x96\xda\x04\xa4\xe6\x39\x03\x11\x77\xcd\x27\xd7\xc2\xfb\xec\x65\xa0\x0b"}, -{{0x8c,0x83,0x93,0x81,0xb6,0xa7,0xce,0x26,0x49,0xc1,0xea,0x46,0x4a,0xe3,0xc2,0xd3,0xfd,0xb1,0xec,0x66,0x6d,0x7b,0x4b,0xe4,0xe2,0xa9,0x41,0xab,0x6d,0x65,0x57,0xa7,},{0x5c,0x72,0x4a,0x30,0xc6,0xfb,0x32,0x81,0x53,0x43,0xa8,0x0d,0xde,0xe6,0xee,0xe5,0x44,0x51,0x64,0x18,0xea,0x95,0xe1,0xba,0xc8,0x0a,0xfc,0x80,0x40,0xd6,0x3f,0xc6,},{0x5d,0x21,0x10,0xd1,0xd2,0xf3,0xed,0xd6,0x83,0xbd,0xfd,0xbe,0xa3,0xff,0xa7,0xcf,0x55,0x28,0xa4,0x0b,0x8b,0x3d,0x8d,0x8c,0x9b,0xfd,0x22,0xae,0xac,0x28,0xba,0xd4,0x71,0x66,0x6e,0x06,0x2f,0x7d,0x38,0xce,0xda,0x8b,0xb3,0x73,0x97,0xa1,0xc5,0xc3,0xf7,0x33,0xb5,0x37,0x96,0x70,0x45,0x70,0x64,0x78,0x43,0x7d,0x4d,0x18,0x7a,0x0a,},"\xcb\xcf\x89\xc3\x54\x89\x64\xc3\x8d\x70\xfd\x8f\x68\xe8\xec\xe3\x6c\xc3\x97\x55\xc9\x71\xd1\x4d\x7e\x05\x6f\x39\xb0\x23\xef\x16\x6d\x17\xf2\x43\x85\x22\xf0\x10\xd6\xd8\x35\xd8\x86\xe7\x1f\x47\x4c\x67\x27\xa4\x22\x1f\xd0\x3a\x75\x74\x57\x82\x89\xed\x54\x93\xac\x4c\x09\x47\xe3\xf4\x28\xd8\xfe\x06\x40\x06\xa2\x56\xce\xf2\x18\x11\xd7\x26\x78\xf5\xdf\xc6\xba\x66\xac\x29\xec\xd1\xb3\x2f\xf5\x55\x7c\xb0\x8c\x5f\x13\x05\x59\x21\x7a\x04\x13\xb7\x59\xc2\x4d\x83\x38\x8a\x2b\xb9\xb2\x9b\x6b\x91\xd1\xf3\x10\x1e\xd6\x25\x21\x1e\x4d\x73\x80\x51\x93\x47\x8c\xf9\x95\x39\x6c\x10\xb1\xc5\xaf\xfa\xcb\x00\x89\x9d\xa0\x4e\x3c\xce\x19\x3b\x49\x4e\x2a\x93\x3c\x4e\xeb\xe0\xa3\x7b\xfb\x8f\x1b\x83\x71\xbd\xe5\xfd\xa0\x9e\x80\x4e\x94\x0f\x34\x48\x96\xa5\x29\x46\x7a\xde\xe4\x5a\x8f\xeb\xf8\x5a\xb0\x36\xca\xb8\x80\x14\x3b\xe4\xf5\x9b\x77\x41\xd8\xe4\x50\x27\x8b\x06\x36\x55\x78\xd4\x0b\x19\xdc\xec\xc6\xe1\xee\x3d\xa3\x4a\xb2\x90\x13\xfa\x3a\xf7\x72\x92\x72\x96\x21\x10\xe3\x85\xab\x9a\x02\x2f\xae\x41\x46\xf8\x97\x16\xf7\xba\xb9\xd3\xdc\x68\x2f\x4f\xac\x77\x36\xd3\xe0\x89\x73\xc6\x85\xbb\xb2\x75\xbb\xf8\xf2\x17\x41\x9e\x5c\xae\x02\x19\xeb\xa5\x16\x6a\x5d\xe1\xb1\x1e\x3f\x9a\x90\x8b\x8a\xc7\xe6\x5b\xcd\x62\x3f\x8c\x18\xbb\x02\x4f\x60\x5d\xcb\xac\xda\x79\x0d\x83\x62\x95\x74\x44\xa9\x5c\x13\x0a\x37\xee\x9d\x56\x3d\x0c\xbb\x4c\xb2\xb0\xff\x71\x59\x1d\x93\x90\xb6\xc8\xfc\x28\x75\x3a\x0e\x40\x2d\x64\x87\xcf\xac\x60\x71\x35\x92\x7d\x89\x26\x75\x12\xb3\x4f\x87\x70\x57\xd9\x27\x1b\xcc\xc0\x24\xdf\xed\xcc\xc6\xc3\x2e\xdf\x75\xc8\xb7\x55\x1c\xdf\x80\x15\x4e\xe8\xe0\x8a\x0c\xc4\x30\x44\xe1\x03\x6b\xae\x01\x7e\xb4\x8b\x65\x02\xc7\xa9\xd6\x0c\x8b\x37\x0c\xf3\x79\x9c\x46\x4f\x96\x4a\x69\xee\x65\x95\x01\x22\x3e\x78\x9a\x64\x97\xb6\x34\x96\xdf\x1a\xda\x2e\x80\x8d\x24\x34\xfc\x8b\xb9\x79\x4e\x5e\x2a\x20\xbb\xf4\xd6\x92\x5c\xb3\xc5\xbb\x14\x84\x2f\x19\x20\x09\x05\xba\x93\x54\xe0\x0d\xc3\x3c\xff\x5b\x42\xd4\xe9\xd9\x66\x8b\x34\xe6\x61\xd4\x4b\xef\x76\xfe\xfe\x2e\xd5\x1f\x94\x42\x3a\x93\x3a\xc9\x4f\x15\x23\xbf\x37\x82\x3a\x23\x8d\x61\x6c\x6b\x17\x97\x34\x41\xe3\x5f\x94\x05\xa0\x4d\x99\xea\xa8\xf5\x04\x53\x4c\x8b\x5f\xa5\xe8\xe3\x35\xc7\x43\xbc\xf2\x1f\x5d\x49\x2b\x71\x12\xe0\x0f\xd8\x64\x2c\xb1\x2b\xfe\xc8\x49\xdf\x62\x12\x0d\xbb\x06\xbf\xc2\x94\x6a\x56\x01\xe2\x5b\xe7\x50\x11\xc6\xf0\x0c\x65\xd3\x5f\x44\xa4\x6a\xf9\xe4\xf7\x80\x9e\x57\x89\xa3\xa6\x1b\xa0\xa3\xb2\x13\x89\x04\x97\x29\x6c\x81\xe4\x2e\x88\xf0\xec\x0f\x5d\xef\xc1\xf5\xd3\x9f\xf2\xa4\x8b\x7e\x30\x26\xc9\xe5\x47\x20\x2e\xdc\x7e\xb7\x38\xc3\x4a\xd3\xa1\x5d\x37\x3e\xf8\x2a\x4c\x1d\x18\x1f\x28\x5a\x98\xbd\x33\x14\xc2\xc1\x94\x7c\x9e\x2c\x60\xac\xa5\x17\x50\xee\x7f\x94\x3c\xaf\x0c\x4e\x1e\x5c\x7d\xf7\x29\x1e\x97\x3b\x1f\x93\x6b\x73\x70\x76\x19"}, -{{0xaa,0xbb,0xb2,0xef,0xed,0xb5,0x99,0x42,0x4a,0x5f,0x3e,0x08,0xf9,0x0f,0xa8,0x82,0x6c,0x5c,0x92,0x17,0x0b,0xe5,0x01,0xa1,0x18,0x1f,0xe8,0xe8,0xdf,0x97,0x4e,0x0e,},{0xce,0x73,0x19,0xef,0x88,0xb2,0x42,0x42,0x06,0x66,0xca,0x69,0x7b,0xa8,0x50,0x1d,0x27,0x4e,0xc4,0xa5,0xdc,0xf8,0x44,0x59,0x66,0x08,0xb9,0xdd,0x5a,0x8a,0x3a,0xcd,},{0xa0,0xb1,0x9c,0xfa,0x6c,0x80,0xde,0x77,0xbf,0xcd,0x32,0x10,0x30,0xbf,0x8c,0x03,0x89,0x3e,0x2b,0x21,0xac,0xe6,0xc6,0xba,0x1f,0xf7,0x40,0x8e,0x6f,0xf0,0x7d,0x84,0x7e,0x6b,0x2b,0x68,0x8d,0x4f,0xd5,0x1a,0xa9,0x32,0x70,0x1d,0xb6,0x40,0x2e,0xf2,0x23,0x22,0xe6,0xe9,0xfc,0x7e,0x32,0x0a,0xbb,0x4d,0x24,0xe1,0xac,0xc6,0xcf,0x06,},"\xfc\xc1\x5c\xc5\x79\x70\x56\x9e\x9c\xcf\xa5\xa7\x78\xfc\x7a\xed\x71\x97\x8a\x3f\x56\x24\x57\x7b\x6f\x57\xfa\x3f\x16\x7e\xa2\x23\xef\x31\x76\x4c\x48\x8d\x05\x9d\x06\x53\x1d\x01\x6b\xcb\x17\xd5\x44\xd4\x69\x77\xaa\x24\x1f\x8e\x07\xaf\x47\x87\xa0\x81\x0f\x98\xd7\x66\x46\x0c\x08\x41\xad\x81\xb8\x8f\x4d\x5d\x81\x64\x48\x5a\x12\x58\xa9\x46\x22\xc5\x49\x24\x28\xd6\xd5\x75\x94\x37\x15\x76\x6c\x2b\x0a\x86\x5b\xed\xba\x16\x7d\x5d\x34\x0e\xdb\x57\x9c\x47\xaa\x32\x45\x9b\x8f\xc9\x8a\x79\xbb\x0b\xed\x1c\x96\x0b\x4c\xcb\x7f\x2d\x4b\x56\x81\xa2\xa7\x0d\x50\x5b\x85\xb8\x1e\x3d\x99\x67\x27\x14\xe4\xea\xb4\x1f\x3a\xb0\xca\x87\x4f\x41\x71\x86\xfe\xb6\x9e\xd1\x3f\xb9\x11\xf4\x9d\x15\x84\x75\x8b\x2d\x18\xb4\x67\x3e\xdf\xae\x49\x5e\x68\xda\xd5\x13\xa7\xac\x0d\x47\xb2\x75\x3c\xb4\xed\xa7\x8f\xb4\x31\xf0\x4d\xda\x8f\xe8\x03\x0d\x7b\xb4\xe8\xdb\xcc\xb9\x69\xd7\xf5\x80\xd9\xc1\xef\x93\x5d\x07\x4d\x7a\x41\xd1\xf8\xb9\xdc\x45\xc9\xa2\xe4\x10\x6a\x55\x29\xa9\x8b\x95\x52\x9a\xb0\xed\xea\x0b\x57\x22\xdd\x68\x6f\x5a\x7f\x3c\xd8\xfb\x26\x24\xab\x26\xc4\x2d\xf1\x1f\x51\x0a\x10\x3d\x8a\x92\x98\x30\xad\x85\xf5\x21\x24\xe3\xd5\x82\x7b\xa6\x0b\xfb\xcd\x73\x6c\xb6\xc5\x90\xee\x77\x7e\xad\x7a\xa2\x22\x4d\x7a\xe4\x6d\x25\x7a\x90\x40\x72\x47\x96\x0c\x9c\xb0\x38\x60\xae\xaa\x7f\x54\xc1\xa8\xe1\x11\x60\xd1\x1b\xb4\x73\x06\x5e\x19\xb7\x07\x21\xc8\xf0\x72\xe1\x90\x9d\x53\x9e\x9a\xc9\x41\x85\x90\x4b\xbb\xfe\x54\x87\x37\x54\xae\x1c\xa7\xbc\xed\x6f\x40\x56\x1a\xf4\xb5\x05\xf0\x3a\xc9\x72\xa6\xf0\xbf\xa7\x3b\x5f\x83\x2f\xe2\x3b\x89\x8b\x2b\xbb\x05\x74\xa6\x66\x2e\xe9\x3b\x3b\x36\x0d\xa1\xec\x7e\x83\x8e\xb2\xc7\x7c\x7c\xb7\xfc\x16\x4f\x7c\x46\x27\x01\x04\x89\xc8\x58\x90\x07\x52\xc9\x2d\x9d\x75\xad\x54\x71\x67\xe4\xbd\xd1\x1a\x07\xd2\x8b\x65\x1a\xa3\x0f\x16\xa8\x50\xe0\x60\xdd\x28\x82\xfb\x82\x09\x19\xa3\x98\xe8\x05\xeb\x63\x69\x9f\x4f\xf5\x95\xf9\x91\x52\x47\x31\x64\x1e\xce\x25\xfb\x3f\x8e\x89\xad\xa5\x01\x19\x2b\x1e\xdd\xae\xcb\xac\xc8\xb8\x98\x52\x8f\x2d\x5b\x33\x12\x69\x4f\x5e\xc2\xdc\x91\x42\xe1\x51\x3f\x77\x7a\x5c\x83\x34\x09\xc1\x71\x63\x3f\xf9\xfa\x26\x09\xd0\x49\x7f\x5d\xf4\xfb\xf4\x8e\xf2\xb7\x7d\x55\xe2\x55\x19\xd2\xee\x79\xb5\xfe\x9d\x8f\xa4\x60\x00\xde\xcd\xb4\xf2\x5d\xfb\x3f\x2b\xaf\xb1\x9f\xbe\x2c\xbd\xac\x00\x2a\x35\x9a\x95\x4b\xc6\x9b\xdf\xe2\xfb\x36\xad\xfd\x9a\x15\x09\xf3\xe3\xa4\xc6\xb1\xf3\xf3\x6e\x7c\xf8\x0d\x58\x3d\x44\x0f\xf2\xa1\x44\x64\x30\x98\x97\x4d\x71\x49\x3e\xcb\x64\x17\xc0\xb8\x06\x5b\xd2\xc2\x1c\x1e\x34\xaf\x09\x24\x3f\xb4\x9e\x9d\x35\x29\x7e\xb0\xa5\x2d\x56\xdd\x27\x0f\xea\x6d\xc5\xc0\x80\xa0\x55\x99\xf7\x85\x81\xe9\x0f\xd8\xcc\x4c\xd1\x1a\x50\x5e\xdd\xe8\x4b\x89\x2d\x89\x53\xbd\xbb\x23\x79\xd3\x3a\xad\x64\x65\x8a\xe2\x06\x07\xdd\x35\xb0\xbf\x3a\x26\x37\xd2\x0c\x3f\x86"}, -{{0xc2,0xe0,0x74,0xfa,0xa2,0x34,0xe9,0x9a,0xb2,0x0a,0xdb,0xbe,0xae,0x11,0xb8,0x10,0x97,0x23,0xb7,0x08,0xc5,0x45,0x86,0xdf,0x65,0x2b,0x40,0x2c,0x35,0xcd,0xd1,0x27,},{0x5e,0x52,0x4e,0xce,0x1c,0x69,0x6e,0x70,0x5a,0x35,0x14,0xdd,0x00,0x82,0xb8,0x40,0x79,0x5a,0x59,0xc3,0x6a,0x96,0xcb,0xc4,0x82,0xbf,0xf5,0xab,0x4e,0xf5,0x15,0xd1,},{0x65,0x7c,0x38,0x26,0xb3,0x48,0x3f,0xd4,0x2a,0xb6,0xdf,0x86,0x9d,0x1b,0x77,0xa8,0xc4,0xdf,0x67,0xa6,0xa5,0x90,0xc7,0xc6,0x77,0x29,0x69,0xe3,0xdf,0x33,0x12,0xae,0x06,0x54,0xfb,0x83,0x84,0x7a,0xf2,0x21,0x93,0x5a,0x05,0x12,0x29,0x16,0x36,0xec,0x05,0x95,0x70,0x08,0x79,0xeb,0xdb,0xa8,0xa1,0x46,0x7c,0x53,0xd4,0x0c,0x23,0x06,},"\x31\x29\x03\x38\xe4\x6d\x1c\xc2\x5c\xe9\x9c\xba\xcc\x40\x16\x03\x41\xb7\x85\x82\x3c\x82\x3c\x4a\xb9\xba\xee\x3b\x61\x25\x79\xf1\xc0\x11\x71\x67\x96\xe5\x6e\x26\x93\xf6\xdd\xad\x43\x92\x2a\xa7\x84\x7c\xbb\x41\x48\x10\x16\x51\xbb\xe6\x2d\x50\xbe\x90\x82\x5e\x8e\xab\x77\x7a\xa4\xb8\x02\x6d\xc5\x38\x5a\x97\xd3\xdf\x76\x16\x01\x91\xf9\x22\xcd\xd2\xf0\x7b\xa5\xf8\x5e\x95\xf4\x5d\xb2\x29\x28\xf9\x07\x34\xff\x52\x0c\x44\xdc\x8f\xe3\x90\x3b\x4c\x51\xcd\x23\xe0\x64\xf0\x1c\x82\x9e\xc7\x4f\xbf\xfe\x25\xfd\x0d\x36\x9d\x27\x65\x74\x0f\x43\x85\x6b\xd7\x39\x8a\x19\x11\xad\x74\x98\x36\x16\x0f\xd9\x8d\x04\xb2\x8e\xe8\x7e\x11\x1d\x40\x71\x8b\x5a\x16\x6f\x05\xc9\xa4\x71\xa4\x15\x66\x55\x70\x69\xf7\xa1\x4d\xe9\x88\xbb\xbf\x67\x77\x52\x1f\xcb\xa6\xdd\x65\xde\x4c\x06\x67\x4a\x11\x85\x3a\xf8\x3a\xcc\xb7\x0f\xb3\x28\xdd\x8f\xd6\x10\x5a\x7d\xf5\x26\x9c\x9f\xae\xc8\xd9\x00\x14\x7e\x92\x8d\x97\x0c\x36\xcd\x83\x4b\xd6\x05\x4f\x70\x65\x0d\xfa\xce\x94\xb7\x62\x9d\x16\xe3\x70\x3d\x76\x6c\xe7\x63\x8d\x0a\xd1\xe1\x7b\x77\x46\x9b\x95\x8d\x2b\xa2\xa1\xe6\x31\xa1\x63\x5e\xfd\xcb\x00\x6e\xbc\x6e\x5d\x8b\x9f\xaf\x7e\x5f\xb9\x89\xdc\x08\x96\xc5\x61\xa2\x6f\x3c\x25\xf0\x55\x71\x6b\x36\x71\x38\xea\x5d\xa1\xf8\x1d\xc7\x2c\xff\x7a\x55\xaf\xae\xe5\x83\x9e\xf5\xaa\x82\x2b\x29\x70\xaa\x18\xa8\x98\x21\x63\xbf\x5e\xed\x1b\x67\x7c\xca\xac\x12\x24\xff\x6c\x6c\xf2\x56\x37\x47\x80\xae\x65\x80\x3b\xf5\xc6\xe2\x3c\x80\xba\xcd\x76\xec\x3e\x2d\xdd\x3a\xb7\x19\x97\x50\x64\x48\xe1\x9d\xb1\x98\xef\xad\xc9\xf7\x57\x49\x1f\x1b\x09\x72\xc8\x2d\xb2\x94\x10\xe1\xe8\xbb\x67\xbb\xb2\x3d\x53\x56\x3b\x88\x07\xe5\xe0\xc2\xe3\x2e\xe5\x96\xb5\xb4\x40\x23\x28\xf9\xe1\x79\xe9\xce\x85\x6d\x3b\xd1\x99\xd5\x8d\xe6\xc5\xc2\x52\xe7\xa6\x12\x4d\x81\xfc\x9e\xea\xf2\x3d\x34\x7d\x2a\xb8\x89\x17\xaa\x68\x44\x50\xdd\x58\x30\x35\x16\xc1\xa4\xd2\xbd\xcd\xde\x22\x0c\x9a\xe3\x79\x0f\x29\x8d\x7d\x38\x4b\x70\xc2\xfe\x25\x88\x07\x84\x8f\xc3\x53\x20\xb5\x78\xb3\x35\x03\xb7\x5f\x38\xa1\xdf\x63\x0b\xd3\x3e\x6a\x85\xa4\xdd\x4d\xf9\xf6\xe5\x5a\x6e\x68\x67\xc7\x38\x01\xe5\x93\xe1\xd5\x91\xdb\x89\xba\x9a\x9a\xf0\xfc\x29\x2e\x06\xfb\x51\x5a\xc8\xa5\xe8\xe3\x43\xa8\x21\x33\x55\x75\xba\x48\xfb\xaa\xe3\xfb\x12\xde\xea\xae\xe6\x0f\x4b\x3d\x31\x7e\xc0\xa5\x54\xdd\xd4\x25\xc8\x49\x32\xc2\x7a\x7a\x12\xf2\x9d\x63\x71\x51\x07\x83\xbd\x75\xe6\x0e\x2f\x6d\xa2\x00\x52\x06\x9e\xd7\x1e\x69\x5a\x94\x31\x82\x19\x3c\xb6\x85\x1a\x7d\x2f\xa3\xc6\x66\xc1\x93\x02\x80\x15\xac\x8b\x7e\x7d\xaa\x6c\x52\x04\xf7\x7a\x62\x32\xb8\x8b\x4a\xbf\xfc\x53\x62\xfd\xe7\xde\xc3\x6b\x9d\x45\x48\x80\x84\x92\x83\xb1\x15\x63\x39\xea\x2e\x8c\x3b\x10\xe5\x1b\xfa\xbd\xf7\x25\x78\xc7\x26\x41\x9a\x38\x54\x2c\xf8\x64\x9d\xf9\xa0\x90\x9f\x58\x2d\xeb\xad\x5f\xd8\x9d\x8c\x81\xf8\x3d\x9e\x42\x3e\x75\x03"}, -{{0xb9,0xda,0x4e,0x6a,0xf0,0x7e,0x39,0x8a,0xb4,0xd2,0x17,0x52,0xa3,0x2c,0x8f,0xfa,0x9b,0xe0,0xc3,0x10,0xd3,0x50,0x59,0xfb,0x66,0x1b,0xd7,0x3a,0xfa,0x97,0xe2,0xa8,},{0xf8,0x62,0x80,0x3c,0x96,0xcc,0x42,0xad,0xc8,0x25,0x28,0x84,0x54,0x72,0x30,0xb9,0x70,0x04,0x7b,0x7e,0x5d,0xa9,0x96,0x26,0x0c,0xcc,0x02,0x40,0xab,0x71,0xa6,0xec,},{0x62,0x5e,0x1f,0x42,0xc8,0x74,0x34,0xa2,0x5d,0x62,0x2d,0x80,0xd1,0x25,0x32,0x80,0x6a,0xfb,0x25,0x09,0x33,0x24,0x49,0xe6,0x96,0xb6,0x5e,0x1e,0x58,0x88,0x50,0x8f,0x11,0xc4,0xac,0x25,0xf5,0x9b,0x8d,0x94,0xd0,0xbf,0x27,0xe4,0xc8,0xd1,0x86,0x70,0x07,0xc4,0x08,0xda,0x57,0x30,0x82,0xdc,0xf1,0x9d,0x15,0xa9,0xd5,0xcc,0xcb,0x0c,},"\x6b\x95\xaf\x0e\xeb\xb6\xa0\x8a\xfa\xda\xa1\x96\x21\xf7\x6a\x83\x9b\xe8\x08\x51\xc6\xdd\x31\x5e\x82\x76\xf5\x01\x99\x5d\x4c\xe6\xd1\x34\xdf\x5e\x79\x8e\xd5\x17\xa2\xf0\xe6\x2a\xa1\xd6\xc9\x8c\x36\xef\x14\xbb\x1e\x5d\xdf\xc9\x8d\x5a\x7f\xcc\x81\x14\x0a\x13\xc2\x0d\x2c\xa0\xc4\xb4\x0e\x6e\x6a\x03\xee\xd8\xc8\x99\xf9\xd1\xf7\x92\x46\x81\x52\x19\x9f\x4b\x95\xa4\x32\x66\x89\x47\xa5\x1d\x7b\x8e\x10\x4d\x8d\x1f\x12\xaa\xcd\x96\x7e\x08\xb0\x8c\x41\xc3\xc8\xca\x3f\xee\xda\xa5\xb8\xb6\x3b\xce\xc0\x61\x38\x64\xd9\x53\xd8\x11\x43\xec\x81\x42\x5b\xde\x29\x16\x4a\x08\x76\xf2\x3f\x37\xac\x9a\xc9\x47\x36\x72\xce\x11\xa0\x8b\xd5\x47\x6f\x6f\x66\xd6\x65\xe9\xad\x61\x7e\x34\xeb\x32\xee\x56\xff\xa4\x59\xf2\x0d\x1b\x93\x53\xd7\x82\x12\x98\x54\x57\x50\xc6\xef\xf3\xe7\xd4\x07\x3d\xc3\x18\x5e\xde\x03\x91\xcc\xe0\x57\x5f\x8b\xa6\x37\xd8\x00\x06\x8d\x9d\x7e\x54\x03\xba\x70\x38\xd2\xdb\x77\xda\x14\x47\x84\xf2\xe8\xea\x76\xae\xdf\xe5\x21\xe7\xdc\x6a\x67\x4e\xde\x35\x57\x95\x95\x99\x3f\xb2\x0d\x44\xb4\x05\x27\x83\xf5\x6c\x8c\x0b\xbd\x04\x40\xb6\x9e\xab\xde\x84\x46\x8d\xd1\x3c\x67\x1f\xb1\xbb\xd5\xcb\x02\x2c\x2a\x4f\xcf\x35\x42\xd8\xb3\xbb\x51\x8e\x5a\xde\xbd\xdc\x84\xe7\x14\xb1\x3b\xe5\x2c\x56\xb2\x82\xb4\x2a\xc0\x89\x2a\x54\x59\x28\x1b\xe7\x16\x07\x29\xf4\x11\x2c\x7d\x99\xdf\x9b\xe5\x43\x4f\x82\x3a\x9c\xe0\x50\x17\x89\xde\x1d\x55\x0a\xd5\x0b\xb1\x8c\x8d\x89\xa3\x36\x68\x27\x0b\xff\x7b\x91\xff\x11\x8f\x5c\xd9\x90\x9a\xdd\xde\x90\xc0\x24\xa3\xad\x71\x39\x15\x17\x46\x74\xf2\x8a\xaa\x9f\x94\xa3\x22\xba\xa5\x43\x73\x8e\xda\xb4\x97\x33\x12\xb5\xbf\xa1\x21\x55\xde\xbc\xee\x16\x3c\xfe\x2b\x04\xac\x9c\x12\x2a\xc8\xa4\xe1\xbc\x41\x8c\x14\x95\x5d\x96\x10\x45\x5b\xd9\x45\xe9\x79\x3b\x91\x62\x67\xc9\xc5\xf9\xe5\x3a\xc0\x45\x18\x92\x6e\xc9\x8e\xcb\x84\xa4\xf0\x44\x5d\xcb\x12\x36\xc7\x6c\x3a\x67\x8c\x69\xab\xe4\xe9\x2c\x22\x97\x1d\x62\x21\x72\x01\xa1\xbd\xf0\x5c\x04\xdf\x84\x20\xa3\xde\x6a\x91\x7a\x85\xe7\x1e\x2b\x97\x25\xe7\x7b\x52\x29\x15\xd4\xc9\x94\x60\x77\x63\x7c\x2d\x88\x13\xf0\x10\xb9\x49\x1c\xf0\xed\xdc\x3d\x46\x68\xcc\x0f\x8b\xc8\xa6\x83\x57\x9b\xe5\x43\x93\x4d\xa2\x85\x3a\x16\xf5\x71\x57\x24\xf7\x79\x81\x9f\x44\x43\x9e\x1d\xeb\xca\xa4\x27\x0d\x9b\x85\x94\xba\x4c\x86\xe1\x06\x3b\x3c\xe4\x79\xd7\x1a\x54\x09\xbe\xf2\x7e\xf4\xe5\xc1\xd1\xc9\x6e\x8b\xe1\x38\x65\xaf\x7b\xb4\x3f\x09\x16\x2c\xcb\xc8\x3a\x2c\xa9\xe9\xb8\xa2\x32\x4e\x6d\x99\x65\x75\xee\xfe\xd3\x7e\xf4\x99\x08\x18\x57\x38\xb8\xea\xe4\x3f\x8a\xdc\xa3\x30\xc9\x9b\xc6\x6c\xc1\xfd\x52\xc5\x30\xd7\x37\x1c\x60\x86\x9c\xe4\x2c\x19\x7d\xca\x0a\xd1\x28\xb8\x5f\x61\xc8\x75\x8f\x0d\x54\x2f\x3d\x32\x98\xb6\x5e\x93\xc6\xe8\xa6\x8f\xa0\xe9\xa1\xd5\xe8\xc5\xfe\xc8\x05\xb8\x3a\xff\x43\x90\xe1\x15\xeb\x64\xf3\xf0\x78\xa0\xb9\xb6\x6c\x27\x38\x43\xfc\x6c"}, -{{0x14,0x3f,0x7b,0x42,0x47,0xd5,0x49,0xf6,0xb7,0xc0,0x91,0x72,0x66,0xc5,0x0f,0x96,0x2c,0x28,0xa2,0xea,0x24,0x76,0x2f,0x53,0x7a,0xa0,0x6a,0xd1,0x5e,0x40,0xb3,0x5a,},{0xc9,0x95,0x9f,0x90,0xa2,0xd5,0xfe,0xac,0xba,0xe2,0xc4,0xc8,0x03,0xde,0xd5,0xde,0xab,0x86,0x98,0x76,0x37,0x06,0x43,0x37,0xaa,0x2a,0x0b,0x0d,0xde,0xf2,0xfd,0x86,},{0xc1,0xcf,0xae,0x58,0x51,0x57,0x13,0xea,0x72,0x8c,0xfa,0x09,0x09,0x0e,0x89,0x42,0xf8,0xdf,0x18,0x62,0x1b,0xa7,0x09,0x0e,0x3a,0x33,0x76,0xc3,0x80,0x27,0x75,0xa1,0xec,0xaf,0x43,0x6b,0x18,0x49,0x78,0x04,0x1e,0xbb,0x75,0x22,0x6f,0x97,0x0d,0xf7,0x1d,0x6a,0xd3,0x53,0xc0,0xfb,0x46,0x50,0x23,0xf9,0xe2,0x98,0xf6,0x4a,0x70,0x02,},"\xe2\x74\x20\x23\x47\xa0\xd0\x57\xa4\x8b\xf2\xa1\xf6\xe9\xf6\xcb\x42\x56\x07\x9d\x80\x03\x74\x09\x3c\x02\x0c\xbf\x52\x0e\x5f\xa2\x7f\xe9\x96\xff\x07\xf3\x3a\xd3\xb2\x1f\x74\xab\x0c\xd9\x3c\x86\x47\x5f\xf3\x7c\xf6\x22\xd3\xf9\xfa\x4d\x13\xbc\x99\xf0\x13\xe8\x50\x2b\x24\xe4\x6c\xc8\x7c\x47\xe6\xb2\xc3\x66\x2b\x50\xe9\x79\xa0\xf3\x45\xb7\x84\xff\x21\xa8\xa4\xd9\x2a\xdc\x65\xe8\x6e\x33\xb4\xdb\xe1\x7f\x52\x8c\xcd\xf5\xb4\x86\x46\x64\xba\x94\xff\xdb\x7c\x7d\x24\x12\xb4\x38\xe6\xe4\x3f\xa9\x66\x81\x47\xee\x33\x28\x22\x4d\x1f\x52\xa3\xf5\xb5\x43\x59\xb4\xf7\xfe\xf6\x9a\xf8\xf8\x67\xb4\x78\xf1\x30\xa1\x47\xbe\xa4\x2e\xd3\x98\x03\xbc\xbc\x25\x57\xbc\xa8\xc3\x99\x9f\x1d\x24\xf0\xa6\xb0\x3c\x98\x84\x60\x11\xf9\xec\x74\xf6\x66\x41\x7b\x95\x02\x0e\xb1\xfb\x2f\xb8\x8b\x63\x12\xe5\x00\x8c\xff\x03\xe2\xd7\x7a\x26\xaa\x53\x2d\x17\x80\xb5\x07\x7f\x9e\x8b\x82\x86\x74\x45\x5d\x6b\xc9\x57\x97\x5f\x7b\x2a\x50\xe7\xfd\x7c\x16\x12\xce\x02\x36\x2e\xfa\x4c\x55\x5a\x1e\xef\x68\xec\x34\xa5\xc0\x06\xa6\xda\x00\x8a\x31\xd4\x19\x3d\xc2\xcc\x64\x76\x85\xad\x3c\xfa\x3b\xd7\xc5\x60\xb7\xae\xd4\x5f\x0f\x1a\x3d\x1b\x5b\x36\x22\x68\xde\x53\x28\x57\x05\x5a\xb9\xd1\xd5\xd8\x58\xd9\xae\x9a\x75\x9a\x51\xbb\x94\x78\xe8\xf0\xee\x93\xc9\x84\xb5\x76\xb8\xb4\xab\x46\x02\x80\xbe\x3d\xe2\x05\xa3\x2f\x1d\xc3\xd5\x72\x92\x3f\xb2\x13\xac\x15\x12\xd8\x0e\xb5\xad\x5c\x18\x94\x4b\xe7\x7f\xc1\x7d\xef\x13\xa6\x1b\xbd\x31\xbc\x71\xac\xc2\x3d\x25\x0e\xc5\x89\x4e\xbc\x21\x4c\xfe\xc0\xc1\xb9\x06\x51\x6d\x32\xd8\x36\xad\xc8\x38\x80\x2e\x8d\xe3\x0d\xd7\x6d\xf6\xe6\x1c\x1b\xc4\x38\xb6\x8d\x2b\x02\x5a\x84\xf2\x11\xfa\xcf\x3f\x13\x84\xd2\x61\x2d\x0f\xae\xf5\xd1\x71\x31\xcf\xe0\xcf\xe8\x33\xfe\x95\x0e\x47\x9b\xc2\x9c\xbe\x7f\xd6\xda\x0c\xce\x30\x7c\xf0\xb1\xbd\x92\xc8\x0e\x87\x8e\x43\x2f\x63\x6e\xa0\xcd\x42\x48\x0c\x07\xe8\xb8\xe5\x7e\x69\xb2\xf9\x38\xb7\x81\x20\xf6\xaf\x4a\xbe\xbf\x7d\x4b\x05\xca\xcd\x6e\xed\x85\x44\x91\xc0\x29\x75\x5c\x4e\x66\x33\x89\x93\xed\x2a\xc2\x5d\x19\xa0\xc5\xb4\x0f\x5e\x32\xc8\xa8\xb1\xbc\xe3\x69\x71\x81\x86\xc9\x1d\x60\xed\xff\x24\xa8\x37\x7a\x99\x69\x75\x75\x99\x06\x7d\xd3\x12\x63\xa0\x6d\x6a\x61\x15\x47\x81\xf2\x96\x11\xab\x81\x2f\xf8\x2e\x81\x37\x39\x64\x62\x63\x70\x4c\xd6\x04\x63\x57\xa2\x3c\x04\x5e\x24\x07\xb7\xa8\x95\x08\x25\x93\x91\x31\x4f\x2f\xbe\xe4\x9a\xef\x08\x55\xc6\xe5\xe6\x3d\x91\x2a\x19\xdf\x15\xb1\x1e\xce\x34\xe2\x76\xdc\xb8\x8b\xf2\xf2\xe4\x75\x63\x58\xf3\x4a\x0e\xe3\x95\x2b\x68\x6f\xcd\x17\x57\x8a\x88\x41\x76\xd3\x4e\xa2\x91\x6c\x5d\x9f\xcd\x00\xeb\x9e\x0a\xa9\xf2\xcf\x0f\x16\xe2\x56\x4b\xfd\x28\xb6\xab\x59\x68\xb8\x44\x8f\x06\x83\x20\xe4\x18\x71\x60\xf8\x66\x57\x81\xb1\xe2\xed\x9d\x04\x9e\x1b\x54\xa7\xd7\x27\x20\xff\x9d\x4f\x07\x30\x51\x99\x6a\x9d\xb6\xf0\xc6\x82\x1c\x42\x4f\xa5\x1d"}, -{{0x0d,0x1f,0xe9,0xd8,0xb9,0xa2,0xf0,0x4c,0x22,0xbb,0xb0,0xed,0xea,0x38,0x33,0xa0,0xce,0x43,0x33,0x93,0x47,0x53,0x1f,0xdb,0x67,0xed,0x51,0x3a,0x13,0xd3,0x6b,0x39,},{0x67,0xc4,0x9f,0x41,0x0f,0x48,0x53,0x29,0x3d,0x0c,0x4d,0x39,0xf4,0xc1,0xb3,0xd6,0xc6,0x10,0x3c,0x5c,0xfe,0x20,0xa9,0xa5,0x9b,0x53,0x93,0x20,0x43,0x51,0x73,0x69,},{0xb0,0x57,0x25,0xe7,0x37,0x1e,0xd0,0xa9,0x1e,0xbc,0x89,0xf3,0xc3,0x0b,0xaa,0x99,0x18,0x37,0x63,0xed,0xb4,0xce,0x34,0xfe,0x90,0x1a,0xf3,0x73,0x1e,0x00,0x1c,0xc5,0x4f,0x28,0x71,0x18,0x91,0x5e,0x90,0x36,0x5d,0x91,0xac,0xa8,0xfe,0xb1,0x70,0x87,0x69,0xf9,0xf1,0xd6,0xee,0xf5,0xaa,0x11,0x3b,0xee,0x00,0xb5,0xef,0xab,0x27,0x04,},"\x64\x21\x7a\xc8\x41\xfd\x4d\x64\x59\xbf\xc4\xa4\x9b\x88\x01\xd6\x92\x9b\xf1\x9b\x40\x8e\x8a\x53\x79\x0c\xeb\x51\xec\x34\x1f\x9b\x46\xa3\x51\xe8\xc2\xe5\x9d\x88\x7e\x1e\xac\xcb\x91\x42\x31\xcd\xca\x1d\x3e\x5c\x47\xd1\x66\xb4\xcd\xb9\xb5\x8c\x01\x3c\x59\xa3\xbd\x28\x3a\xd1\x0f\x6b\xd6\x2c\x0f\x15\xf7\x64\xce\x14\xf3\xb2\x65\xf5\x37\xc6\x3e\x73\xb6\xc4\xfa\x65\xe0\x6c\xe1\xe1\xf4\xae\x0d\x11\x48\x9d\xd2\x60\x2f\x95\xfc\x40\x2b\x77\x12\x05\x2a\xbc\x84\xbd\xc7\x78\xc1\x9f\x10\x00\x1b\x4e\x0d\x5f\xbe\x46\x30\x90\xe8\x3e\xf4\x38\xfe\x06\x8f\x3b\xb6\xfb\xc2\xc1\x39\xaf\x06\x78\xed\x2a\x11\xfa\xa1\xb9\xe4\x9a\xaa\x46\x20\xab\xfc\x08\x43\x9f\xbf\xe2\xc6\x18\x40\x76\x9e\x5f\xda\x26\x77\xf8\xe2\xf0\xa1\x45\x64\xf9\xf5\x04\x23\x2a\x9f\xc0\xd9\xda\x47\x1e\x67\xfb\xc5\x74\xc3\xd5\x6d\x2a\xeb\x93\x7a\x58\x6e\xd5\x58\x35\x56\x30\x8a\x99\x8e\xb1\xdc\x47\x6a\x01\x4f\x5a\x08\x22\x8d\xbe\xd9\x5a\x12\x08\xbc\x1d\x1f\x5d\x76\xb4\xe8\xd0\xb2\x43\x4b\x99\x5a\xd4\x58\xe4\x29\xee\x61\x42\xa0\xc9\x71\x76\x8c\xc4\x0c\x40\xbc\xb0\x8e\x96\x03\xf0\x96\x11\x47\x44\x71\xb3\x85\x9d\x7f\xd5\x84\x21\x9f\x02\x65\x7b\x43\x0e\x9e\x56\x95\x5b\x34\x67\xac\x56\xff\x2e\xab\x22\xcc\x49\x84\x89\x03\x6a\x57\x41\x20\xe2\xdb\x76\x9a\x3b\x21\x50\x03\x89\x14\x2c\x78\xa8\x7d\x06\x9f\x0e\x25\x76\xca\xfd\xa8\xcd\xdd\x79\x15\xa9\x22\x87\x73\xd2\xac\x9a\x07\x5c\xb3\x87\xf2\xa8\x98\x61\x72\x13\xb2\xcc\x50\x59\xd1\x19\x41\xbc\x4f\xe5\x86\x41\xe7\xc1\x75\x02\x67\xe5\x3e\x99\xc4\x21\xcb\x4c\xf2\x1d\x09\x8c\xa2\xd1\xf4\x16\x44\xf7\x90\x89\x83\xeb\x17\x4a\x23\xa7\x81\xcf\x15\xef\x38\xeb\x91\x16\xed\xa4\x12\x3a\x15\x22\xf5\x3b\x81\xfb\x73\x68\xe8\x07\x5f\xb8\x38\x59\xd2\xcf\x98\xd9\x21\x53\x5a\x70\x9f\xaf\xa9\x87\x3c\x4a\x03\x9a\xae\x68\x2f\x7e\x62\x86\xb8\x99\x25\x7c\x09\x24\x01\x6c\xa5\xbf\x6d\x31\x69\x09\x92\x11\xa9\xa4\xa6\x74\x5c\xdd\x31\x98\xf1\x33\x7f\x60\x92\x82\x27\xce\x3c\x7d\x60\x96\x0b\x53\xde\xdf\x01\x1a\x89\x40\xf5\xc4\x68\x20\x7a\x38\x94\xbb\x08\x72\xb3\x33\xcc\xde\xc9\xd5\xec\xd9\x11\xec\xbb\xb9\x6c\x9b\xc4\xbd\x48\x75\x32\x0e\x4d\x3e\x9c\x02\xd9\xdc\x76\x10\x9e\xc4\x5e\x61\xd1\xcf\x5a\xc7\x29\xf2\xe3\x4a\x96\x47\xb9\x5b\xce\x70\xb0\xc6\x33\x17\x1a\xda\xf0\xdf\xdb\x5a\xfb\xa4\x03\x5b\x3c\xce\x8c\xb7\x14\x1a\xd1\x42\xbb\x7a\xdd\x4f\xc3\xf9\x61\xd4\x2d\x72\x03\x75\x4a\x4e\x31\x32\x21\xd4\x87\x83\x1e\x32\x94\x7d\xa9\x11\x38\xab\x64\x8b\x59\x52\xef\x69\x56\xe2\x7a\xa5\xd2\xc1\x75\x79\x4b\xf8\x1e\xf2\x77\xfa\xa6\xb9\x05\xe1\x45\x02\x86\x68\x87\xd8\x78\x80\x60\x6e\x81\xb2\x7a\xf0\x1b\xb2\x63\xec\xf2\xc5\x82\x05\x85\xea\x6c\xe8\xd8\xb3\x91\xd8\x6f\xce\xda\xdc\xd1\x1f\xdb\xb5\x66\xfd\xf1\x47\xf4\x02\x01\x0f\xc3\x5f\x51\x57\xe0\x36\x14\x6b\x37\x36\xc8\xa4\x33\x59\x12\x7c\x26\x1f\x6b\xf0\xca\xd3\xbd\x8a\x34\xcb\x15\x09\xf7"}, -{{0xc1,0x0b,0x5a,0xc6,0x05,0x5a,0x1d,0xdb,0xca,0x28,0x55,0x2e,0x5c,0x72,0xeb,0xd0,0x52,0x78,0xc9,0x22,0x39,0xb2,0xfc,0xd0,0xc1,0x35,0x36,0x51,0xa8,0xe5,0x59,0xa0,},{0xb2,0x18,0x3e,0x1b,0x00,0x81,0x6d,0x29,0x30,0x5f,0x74,0x68,0xe7,0xe4,0x5e,0xed,0x3f,0xd8,0xf2,0x3c,0x15,0xb3,0x05,0xf9,0xfd,0xa9,0x3e,0x81,0x2d,0x65,0xbc,0x27,},{0x8a,0x9a,0x32,0x17,0xfd,0xf0,0x64,0x3a,0xaa,0xa5,0xc8,0xfb,0x2a,0x88,0xa5,0x56,0x39,0x88,0x59,0xb8,0xfe,0xef,0xbc,0xb4,0x8c,0xcd,0x88,0xe5,0x85,0xa1,0x67,0xc9,0x4d,0xbb,0x5c,0x0c,0xad,0x24,0xd1,0x5b,0xca,0xbb,0xc1,0xed,0xb2,0x1f,0x02,0xa8,0xc4,0x57,0xc5,0x61,0x20,0xa3,0x23,0x4a,0xc3,0x35,0x77,0xb9,0xaf,0x2d,0xdc,0x01,},"\x35\x94\x90\x5f\x9e\xa4\x64\x61\x5f\x41\xb8\x7a\xbb\x9d\x16\x73\x37\xf2\x9d\x45\xd9\x7f\x7a\x14\x64\xec\x9f\x2e\xe5\x0f\x90\xf2\xe6\x73\x39\x87\x4d\x3f\x20\x93\xbe\x92\x26\x10\x77\x01\xec\x1a\xab\x94\x1c\x4e\x05\x9f\x1b\xb2\x6c\xe8\x6e\x14\x8d\x1d\x9f\x0d\xa2\xa2\xa0\xf9\x82\x9a\x36\x4f\xb4\xf1\x3f\x58\xb9\x60\xd0\xf8\xd7\x23\x23\x28\x3c\x44\x90\xef\xdf\x57\x87\x86\x45\x89\x0f\xf7\xbc\x50\x65\xda\xd6\xe5\x1d\xd1\xe5\xb9\xa5\x07\x51\x50\x97\x8b\x33\x67\xf1\xba\x84\xe4\x5f\xf1\xf1\x27\x6c\x57\x6e\x4b\xc7\x2b\xe8\xaa\x8e\x40\x5f\xc2\xb2\x7f\x81\x46\xb9\x99\x84\x5f\xaa\xa0\x59\x5d\x3c\xb7\x0e\x5d\x37\x12\xed\x54\xa0\xfb\x3e\x32\x2d\x45\x38\x0b\x5d\xe3\x60\x9b\x96\x7b\x95\x9b\xca\x5a\x58\x3c\xc5\x20\xcd\xcb\x7b\xcb\xb8\x29\xaa\x25\xd7\x93\x20\x95\xec\xb3\x03\x92\x3c\x25\x60\xaf\xc3\xfd\x73\x24\xb7\xb7\xac\xd0\x89\xa9\xf0\x0c\x03\xa7\x3d\x04\x3d\xc0\xcf\x0b\xa0\xd8\x41\x1e\x2b\x1b\x18\xd2\x1d\x2a\x32\xa7\x26\xa5\x30\x59\x14\x0f\x78\x4f\x7c\xed\xf2\xf3\x3c\xec\x66\xfe\x4a\xd5\xcc\x9e\xac\xcb\xe4\xae\x10\x03\x6a\xc3\x52\x3b\xac\x70\x0a\x11\x3a\x98\xb5\x98\xe6\xdf\x03\x04\xc6\xfa\x32\x12\xac\xc0\x4c\x4e\x3c\x7f\x66\x87\x36\x2e\xf8\x6d\x61\x7c\x6d\xd4\x83\xf8\xd8\x0c\xea\x66\xd1\x95\x11\x27\x42\x8a\x61\xc1\xe1\x55\xa6\x85\x0b\xb2\xaf\xb7\xf9\x1c\x82\xd7\x3e\xb2\xb0\x54\x3e\xe8\xfc\x1f\x38\xe1\xdc\xdb\x3c\x50\x3d\xdc\x9b\xa0\x81\x24\x56\xa5\xce\x2e\x11\xd5\x56\x48\x7a\x64\x69\x74\xa7\xbb\xf8\x6e\x80\x6c\x58\xc6\x8c\x42\x69\xa7\xc9\xbb\xca\xc0\xff\xef\x98\x35\xb3\x3d\xc4\x49\xa7\x54\x79\xec\xd2\x3f\x6d\x14\x9c\x1e\x5e\xa8\xb6\x92\x08\xff\x36\xe5\xfb\xd6\x82\x95\x55\x03\x18\xbf\xa0\xd3\xb1\xd6\xc1\xad\x42\x70\xbc\xab\x09\x04\xae\x53\x49\x1f\x9b\x1c\xa5\x02\xe0\x12\xee\xd7\x7c\x42\x7d\x49\xa0\x96\x2f\x10\x55\x12\x5d\xd7\xb5\x37\x33\xd8\x52\x89\x34\xb5\x58\x0d\xd5\xfd\x5b\xbe\x85\x49\x78\xba\xe3\xd2\x5b\xb4\xae\x94\x4e\x90\x65\xe8\xe2\xe0\x79\x46\x51\x8a\x6f\x54\x8e\x36\xe0\x56\xbe\x82\x4d\x9e\x02\xa7\xa3\xea\xad\xd3\x79\x29\xf5\x81\x01\xcb\x18\x53\xbe\x3d\x75\x47\xf5\x8f\x49\xe3\x8b\x01\x8a\x74\x8d\x3f\x19\xc4\x85\x82\xab\xbd\xbe\x95\x3a\x8a\x25\xba\x9d\x36\x5d\xea\x83\x59\x35\x89\x9c\x19\xfb\x0b\x51\x90\x6a\xa9\x72\xc5\xac\x45\xe9\x9c\x40\xb3\xb7\x6e\x35\xd3\x27\xe3\x21\xe8\xae\x23\x06\xa6\xeb\x3d\x8c\xb6\xec\x2f\xa5\x39\x9a\xdd\x19\xea\x00\x28\xa0\x17\x92\xc0\x8e\x27\xc1\x6c\xf4\xf8\x5a\xaa\xae\x72\xf9\x86\xb0\x99\xf9\xeb\xe4\xad\x0b\x25\xd0\x6d\x3d\xe4\x4a\x8b\xfa\x52\x84\x4b\xe4\xa9\x39\x44\x83\x3c\xe2\xad\xd5\x1b\xb5\x54\xb3\x56\xa7\xdc\x49\x74\x8d\xd4\x5a\xe7\xec\x9e\x8d\xb4\x26\xc9\x7a\x25\xda\x5e\xdd\x3b\x62\x1e\x4a\xdb\xde\x48\x19\x7a\x33\x14\xde\x1c\x50\xf4\xd6\x00\x20\x27\xdd\x75\x19\xdd\xe3\xe1\x57\x29\xe4\x86\x95\x5a\xc4\x0d\x9d\x66\x87\x6f\x90\x66\x8c\x68\x9d\x8a\xb5\x98"}, -{{0x06,0x1b,0xdd,0xab,0x28,0x0b,0x0f,0xdc,0xb2,0x6b,0xfd,0x9a,0x0f,0xc7,0x21,0xf6,0x8f,0x88,0x34,0x3b,0x5d,0x39,0x83,0xa1,0x6b,0x6d,0xfa,0xa5,0xe7,0x69,0x69,0xf3,},{0x81,0x55,0x78,0xbb,0xa6,0xe7,0x07,0x0e,0xbd,0xec,0xa1,0x17,0x56,0x8b,0xd7,0x7e,0xbf,0xf9,0xe1,0x4c,0xb8,0xbc,0x20,0x0c,0x32,0xbd,0x87,0xdb,0x1f,0xb3,0x7d,0x6c,},{0xb8,0x32,0x97,0xcc,0xdd,0x6d,0x00,0x98,0xeb,0xf5,0xd1,0x32,0xd1,0x74,0xde,0x19,0x58,0x31,0x1a,0x76,0x6b,0xcc,0x4d,0xa1,0x5f,0x86,0x4d,0x80,0x1f,0x38,0xe0,0x9d,0x61,0x3e,0x7a,0xa8,0xc3,0x36,0x30,0x27,0x35,0xd7,0x5b,0xe4,0x16,0x6d,0x73,0xb0,0x18,0x4b,0x0e,0x0b,0xc5,0xef,0x39,0xed,0xbc,0xcb,0x6e,0x0e,0x61,0xaf,0xeb,0x0c,},"\xee\x76\xb4\x0c\xd4\x29\xea\xc7\xbc\x12\x83\x9c\xa2\xf7\xcd\x31\xf1\xe0\x09\x8a\x39\xc5\xfc\x19\x80\x5b\xe0\x33\x1f\x44\x79\x9e\x31\x8d\x12\x57\x1f\x06\xe2\x99\x37\x53\xa3\x68\x5c\xd2\xa9\x6b\x23\x01\xe2\x00\x24\x20\x9a\xdc\x5a\xdf\x74\x79\xff\x90\xc4\x77\xc3\x69\x5a\xbb\x99\xbd\x28\x57\x9d\xbc\x78\x31\xa1\x92\xbe\xed\x0c\xe1\x7b\x03\x8b\x20\x76\x48\x00\x65\x3a\xf7\xaf\x02\x4e\x2a\x10\x4e\xd0\xf3\xe5\x2d\x4b\xbd\x3e\x10\x9c\xf1\x26\x29\x1f\x49\xb0\xa2\x1b\xe4\x33\xc1\xc5\xa2\x58\x9e\xa5\x72\x99\x7f\x63\xd2\xbb\x39\x72\xd5\x32\xbe\x35\xa0\x47\x1e\xf0\x57\x3d\x79\x5c\x07\x2b\x6a\x86\x85\xb9\x5e\x47\xb0\x9e\xa9\xf4\x75\xd9\x3b\xf1\x2b\xbd\x77\xb7\xd2\xbf\x5d\x5b\xdd\xf0\xae\x02\x37\x53\x71\xd1\xd7\x99\xea\x92\x04\xbe\x38\x9e\x6a\x8e\x5d\xee\xdc\xd4\x92\x02\xe9\x2d\xf7\xc3\xe7\x61\xf9\x2e\xf8\xd7\x9f\xa7\x38\xd2\xc5\xbc\x28\x0e\xd3\x28\x79\x83\x2f\xf2\xb0\x26\x42\x45\x89\xcd\xbd\x52\xd1\x5b\x60\xf2\xaa\x35\x26\xb8\x98\x84\x9a\x34\xa8\x5f\xf1\xc4\x7d\xc6\x55\x4b\x85\xac\x76\xaa\x79\x35\xcb\xf3\xf7\xbc\x80\xad\x00\x91\x92\xa8\x75\xca\x20\x9b\x40\xfe\xb0\x47\xcc\x44\x69\x68\xf9\x70\xda\x47\xb8\xcd\x67\xda\x7e\xb4\xe5\x4a\x0e\x5a\xb2\x0c\xb3\x5b\xc6\xfb\x7f\x13\x30\x7c\xe6\x7e\xb6\x20\x4a\x67\xce\x9b\xb1\xd1\x39\xc1\xb4\xbd\x5d\xbe\xd5\x80\x10\xc8\x7b\xf8\x31\xe6\x52\x2e\xe1\x82\xda\xd9\x45\x80\x4b\x76\x7c\x4d\xf2\x55\x4f\x15\xb9\xe9\xaf\xd2\x59\x9e\xf2\x58\xc6\x7a\x22\xca\xeb\x92\xa5\x79\x88\x00\x6b\xbc\x72\xc1\x04\xfa\xc7\xe5\x41\x3c\xd3\xd3\xb8\x02\xc8\x3e\x63\x9e\xaf\xe2\x12\xa3\x8b\xb7\xef\x77\x9a\xf1\xa9\x4e\xe1\x37\xf6\xc6\x06\x67\xbc\x48\xf2\x7b\xf4\xa2\x22\x41\xbc\x44\xbb\x60\x33\x83\x62\x39\xbd\x6e\xaf\x3e\x2e\x22\x31\x87\x84\x1e\x46\x41\xb0\xf4\xe9\xff\x8d\x5a\x41\xdd\xbe\xab\xb4\x13\x8f\x6b\x58\x5a\xce\x0f\xb6\xb5\x3d\xc3\xc9\xed\xc0\x37\x3b\x60\x47\xf2\x7d\x83\x5e\x8e\x24\x66\x44\xfd\x83\x2c\xcf\xe0\xdf\x25\xc3\xd7\xda\x18\x7c\x9f\xa0\x54\x20\xd4\x34\x55\xf2\xd0\x8b\x57\x19\x29\x38\x6b\x59\xc6\xe0\xe1\x0a\x35\x60\x1d\xa8\x99\xb1\xb4\xdc\x3d\x95\xb6\x7d\xd9\xa8\x38\x18\xb0\xa3\x18\xbf\xdd\xa0\x64\x64\xb4\xa4\x2d\x3c\xb9\x85\xf3\x0e\xc9\x7d\x6a\x2a\xf1\x32\x91\x15\x5d\x60\xce\xc5\x7c\xbd\x58\xd5\xcf\xcb\x35\xc1\x85\x35\xe8\xd2\x99\xb5\xb0\x07\x59\x08\x92\xea\x94\x9d\x1b\x13\x7a\x62\xb3\x9a\x43\x6c\xd7\xe5\xb9\xf8\xd1\xb6\x93\x8d\xba\xa6\x2c\x22\x68\xd4\x59\xc6\x22\x0a\x3e\x6f\xcb\xf8\x0b\xa0\x11\x8a\xcd\x23\x42\x56\x3f\xbd\xbc\x1f\x7c\x9d\xba\x7e\xa2\xc0\x72\xaf\xc8\xae\x21\x28\xe3\xeb\xca\x06\x44\xff\xd8\x16\x3e\x80\xa1\xa5\x57\xd9\xd3\x90\x34\xcc\xd9\xdb\xd1\x2c\x88\x55\xa6\xf9\x16\x5b\x08\x01\x83\x9c\xf6\xe0\x7a\x9f\xba\x4c\x64\xd9\xc0\x99\xe1\x54\x10\xe2\x90\xe6\x77\x03\x1b\x65\xcf\x7d\xeb\x00\x79\xbd\xad\xc5\x73\xcc\x05\x6d\x76\x66\xd9\x5d\x03\x3a\x0b\x6b\xdb\xa7\xec"}, -{{0x2c,0xab,0x5b,0xf5,0x5f,0xfa,0x91,0x4e,0x9a,0xd0,0x76,0x22,0x19,0x0d,0x34,0x3e,0xc5,0x5c,0x13,0xcd,0x91,0xb3,0x88,0xcb,0x75,0x00,0xff,0xe0,0x6d,0xf7,0xc1,0x80,},{0xb6,0x1e,0x43,0x2b,0xb9,0x7c,0xba,0xe3,0x88,0xa2,0x57,0x8a,0x74,0x84,0x99,0x8e,0x00,0xe9,0xad,0x3d,0xdf,0xd6,0xca,0xb8,0xd3,0xa5,0xfc,0x5b,0xa0,0x43,0x07,0xc8,},{0x4c,0xf0,0x8f,0x4f,0xab,0xbd,0x06,0xdc,0xcb,0xcc,0xe2,0xa7,0xa5,0x94,0x1f,0xe9,0xaf,0xdd,0xc4,0xd2,0xd0,0xbc,0x80,0x80,0x2e,0x93,0xb1,0x2c,0xb1,0x35,0xd3,0xac,0xf6,0x51,0x1e,0x0f,0xe4,0x11,0x3c,0x5e,0x3c,0x55,0x41,0xb2,0x7d,0x3a,0x21,0x50,0xa7,0x57,0x74,0x2a,0xc6,0x5f,0x95,0xa9,0xce,0x66,0x73,0xff,0x0c,0xd2,0x1c,0x0f,},"\x2c\x2d\x04\xdc\x3a\xd1\x98\x23\x59\xec\xd5\xbc\x3e\xe0\x35\xf3\x49\x8e\xed\xff\x61\x04\xa9\x3c\x60\x2a\xf2\x17\x9a\xeb\x2c\xb1\xf4\x1c\x5c\xdb\x0a\x77\xb1\x24\xf9\x46\xaa\x8a\x82\x4a\xa3\x07\x6c\x2e\x1a\xcf\xd4\x8f\x68\x07\x0b\x26\x27\x6a\x65\x6b\x4a\x47\x58\xab\x15\x1a\x6a\x9c\x41\xbd\x74\xe0\x9b\xbd\x9a\xdc\xce\x1e\x87\xa0\xa8\x0d\x17\xfd\x92\xe8\x5e\x4b\xda\x47\x2c\x98\x8b\x6b\xb1\x18\x3b\x7e\xe5\x9a\x09\xd8\x05\x70\x46\x6d\xb9\x0d\xd3\x74\x95\x79\xc4\xeb\x19\xab\x75\xfc\x15\x2e\xcd\xcd\x68\xcd\x10\x78\xef\x06\xe5\x93\xc7\x35\x16\xfa\x82\x91\x48\x1a\x66\x7d\x3f\x95\xbf\xeb\x14\x4b\xab\x59\xd6\xdd\xc7\x3a\x27\x95\xc1\x01\x7e\x09\x53\x6b\x31\x62\xe4\xbc\x58\xf8\xea\xd3\x89\x57\x01\x8c\xfe\xc7\x2b\xad\xbf\x22\x81\x9a\xb0\xb4\x06\xc6\x47\x30\xfc\x73\xfd\x9e\xe6\x1f\x74\x18\x7e\xda\x91\xed\x4e\x79\x93\xe6\x68\x84\xaf\x43\xef\x4c\x6b\xf7\xf7\xc3\x79\xe8\xf0\xf6\x3d\xcb\x80\x41\xe2\x6b\x8b\x82\x92\xb6\xb6\xd1\x90\xe4\xad\xf4\x30\xfa\x82\xdd\x74\xc5\x73\x85\xb9\x19\xc4\x46\xdb\x37\xb5\xe8\x76\x7e\x4a\x0c\x95\x01\x3b\xe8\x9b\x2b\xc4\xe9\xfd\x62\x75\x4a\x84\x44\x18\x40\x09\x68\xae\xd2\xdd\x32\x8d\x7b\x1d\xc9\x1e\x1a\x2b\x30\x09\xdc\x7a\xd1\x40\xa0\x68\x6f\x67\x31\x68\xa6\x0e\x88\xd8\x0c\x52\x0f\xc2\xdc\xfc\x56\xca\x9d\x4b\x0c\x88\x85\x90\x99\x23\x07\x14\xde\xc8\x3d\x26\xb4\x63\x05\x54\xdc\xb9\xc4\x90\x18\x95\xf7\x8f\x38\x34\xb0\x97\x66\xb6\x7a\x46\x5d\xe8\xc9\x49\x00\x65\xbf\x56\x83\x39\x24\x33\x99\xfd\xc9\xd5\x10\x03\x24\x66\x7c\x5a\xb2\x8f\x35\xc0\x0f\x61\x25\x63\x8e\x61\xda\xb7\x0d\x1e\xec\x48\x95\x1d\xe0\xfb\x3f\x7b\x23\xd3\xcd\x98\x24\x37\xc6\x34\x73\x41\x5b\xef\x37\x4a\x66\x32\x96\xf2\x98\x6b\x1a\xe9\x57\x9b\x9f\xfc\xe7\x1e\xc3\x5e\xec\xa1\x16\xd1\x94\xf8\xfb\xa9\xa4\x5a\x91\xba\xe2\x7a\xc4\x55\xdb\x71\xa6\xb0\x1a\x72\x9d\x0c\x13\x5f\xcd\xcb\xc2\x3e\x50\x4a\x29\x43\xc0\x0a\xa4\x20\x70\x51\x9d\x9c\xd7\x7a\xe6\x75\x4f\x31\xeb\x46\xa3\xe5\xbe\x9e\xeb\x3f\xc8\xd3\x1f\xf1\x82\xda\x9b\x08\x7b\xe3\x46\x2c\x84\x59\x12\x6e\x86\x29\x09\x23\x2f\xd5\xf2\xd8\x9c\x01\x81\x59\x57\x61\x1e\x6a\xe7\xca\xa9\x8b\x60\x53\x77\x6a\x77\x15\xc2\xf9\x3c\xcf\x03\x08\x87\x03\x0c\x56\xc2\xb8\x22\x6d\xae\x29\x77\x99\x5a\x6d\x3f\x1e\x9d\x79\x11\xa9\xc9\xd2\xa3\x03\xf0\xe0\x1f\x32\x33\x8e\xfd\xaf\x8e\xe6\x3f\xc4\x1b\x25\x39\x9c\xff\xd0\xb3\x5f\x7e\xe5\x67\x6b\xd8\xfd\x3d\xa2\xcb\xee\x4a\xe2\xea\x98\x08\xd7\xe7\x35\x83\xd9\x94\x33\x99\x31\x46\x67\x4a\x40\x40\xf4\x2f\x63\xd1\xb3\x13\x5c\xc7\x97\xa8\xd8\xf0\xb8\x85\x73\xa3\x28\x90\x69\x6c\xac\x94\x39\xd1\xe1\x5d\x19\x6d\x90\x90\xb6\x2b\x6d\xb7\xe6\x3c\x96\x47\x2d\x94\x6e\x66\x8c\xbd\xa1\xf4\xdb\x88\x93\x00\xcd\xcc\x25\xe8\x4c\x9f\x38\x57\xd1\xd9\xe5\x32\x41\xcf\x62\x5f\x39\x09\xaf\x1c\x8a\xaf\xf4\x30\x9f\x68\xf6\x54\xb7\xa1\x5b\x67\x71\x1c\x5b\x7f\x9d\xe7\x67\x75"}, -{{0xdd,0x7b,0x59,0xa3,0x3d,0x97,0x0b,0xef,0x62,0xe0,0xe2,0x1a,0x7b,0x6e,0x4c,0x30,0x96,0x06,0x86,0xf1,0x7f,0x49,0xaf,0xdb,0x4a,0x9f,0x4e,0x80,0x8e,0x35,0x5c,0x7f,},{0x53,0xa0,0xe5,0x72,0x77,0xd9,0xbb,0xee,0xcf,0x99,0xc4,0xd1,0x38,0xfd,0x66,0xfa,0xfc,0xae,0xc7,0xbc,0x5f,0x56,0x7f,0x83,0x20,0x80,0x0c,0x4e,0x58,0x4f,0xf8,0x2e,},{0x87,0x29,0x4d,0x22,0xd4,0xad,0x0d,0x08,0x14,0xe2,0xd6,0xd5,0xfa,0xf5,0x57,0x49,0xe9,0xb3,0x98,0x03,0xb4,0xd4,0xb7,0x87,0x9e,0x60,0xb7,0x77,0xc1,0xfc,0x41,0x58,0x4f,0xe1,0x51,0x35,0xba,0x11,0x23,0xff,0x5f,0x20,0x0d,0xb3,0x5a,0x34,0x68,0xdd,0x4d,0x58,0xda,0xd7,0x7b,0xd9,0x6e,0xe2,0xb8,0x88,0xa5,0xa8,0xb1,0x8c,0x32,0x04,},"\x75\x58\x03\x67\x93\x05\x18\x16\x8b\x0a\x76\x4d\x09\x58\xbe\xc4\xfc\x46\xcf\x59\x19\x99\xeb\x37\x37\xe4\x2a\x02\xea\x72\xd2\x10\xda\xad\x53\xe5\x4a\x7c\x2c\x13\x4a\x6d\x47\x83\x37\xd2\x63\x33\x68\x54\x81\x70\xed\xef\x0d\x85\x17\x9f\x30\x23\xe1\x50\x38\x68\xa6\xe5\xe2\x77\x5e\x41\x2a\xc0\x5f\x05\x89\xd4\x2a\x37\x7e\x75\xaa\x6b\x8f\x52\x20\xa7\x69\x9a\xe8\xaf\xf0\x10\x94\xec\x46\x9d\x63\x61\xd3\xe8\xf3\x86\x15\xed\xcd\xa4\xd2\xd5\x28\x9a\xcf\x73\xdb\x64\x56\x98\x57\x80\xc9\x2e\x07\xf6\x2c\x77\xa9\x09\xfb\x6e\xf5\x98\x82\x20\x62\xbd\x57\x2b\xf7\x05\x8d\xcb\x83\x5e\xf3\x44\x3d\x3e\x47\xb5\xc6\x03\xd9\x27\x36\xdd\x1d\xf2\x6b\xe4\xb9\x28\x3b\x76\xe3\x21\xd5\x5c\xe2\xb6\x38\xcd\xe2\x25\x77\xca\x59\xc9\x63\xc2\x47\x95\x56\xc5\x75\xcc\xb0\xd6\xd1\x8c\x80\x4e\x2e\xb0\x1f\xf5\x35\x81\xeb\x04\x0f\xfd\x2c\xc4\x67\x60\x73\x7a\x74\x67\x2e\xa6\xbf\x78\x05\x8a\x6a\x0a\x1f\x5e\xbf\x56\xde\xcb\xf9\x4b\x54\xaf\xb2\x3c\x11\xd3\x41\x79\xbf\x09\x76\xb4\x15\x80\x17\xd4\x07\xc9\x5a\x40\x1f\xa6\xf9\x62\x4d\x77\x13\x5e\xae\x81\x41\xeb\xea\x9f\x35\xd5\xf5\x1b\x3d\xed\x99\x5c\x7f\x70\xc0\x25\xb0\x94\xad\xef\x2b\x07\x1f\x97\x11\x55\xd7\x79\x6d\x61\x3a\x55\x0d\x09\xe7\xf4\xdf\xc3\x45\x17\xb3\xf8\xfa\x43\x93\x28\x6a\x2b\x22\x80\x17\xda\xf2\xe0\x15\x38\x7e\x13\x52\x7f\x63\x66\x1d\x3c\x13\xe7\x8e\x90\xfb\x29\x55\xee\xe3\x45\x73\x91\x19\xb7\x91\xf0\x5b\x07\xc8\xf4\x2a\x43\x6e\xfc\xad\x1e\xc5\xea\x10\xf3\x08\xf8\xe2\x3c\xa9\x8b\xc6\x5a\x5f\xd9\x39\x3e\xfa\xaf\xe5\xcd\xef\xba\x81\x05\x81\x70\xcc\x54\x93\xc0\x0c\xed\xf2\x54\x09\x74\x35\xd2\xe2\xfd\xe5\x5f\x86\x6b\xb8\x2d\xbd\xfb\x91\x54\x34\x49\x74\x86\x63\x59\x16\x7b\x46\x6c\xaa\x90\x9b\x91\x53\x0c\x9c\x7e\xe8\xc5\x3f\xa9\x01\x64\xbb\xd0\xb1\xfa\xdb\xdc\xd0\x81\x27\xf1\x9b\xe5\x03\x30\x71\x51\x8d\x3c\xf1\x0a\xe6\xbd\x6f\x98\x27\xe1\x20\x6f\x5e\xc0\x95\xc1\x98\x61\x70\xe8\xd5\xd8\xe7\x2e\x57\xd4\x22\x87\x01\xdf\x2a\x48\xc9\x54\x87\x30\x56\xcf\xdf\xba\xaf\xb1\x0e\x46\xa0\xc1\xf1\x44\xb1\xa0\xea\xcd\xd2\xcb\x66\xbb\x91\x2a\xc4\x71\x78\x7d\xab\xe4\x83\x53\x85\x91\x20\xb0\x34\x03\x56\x7c\x41\x5d\xdb\x88\xfc\x0d\x7f\xba\x40\x69\xbb\xfe\xf4\x06\xee\xd7\x24\xa1\x1a\xbc\x04\x1e\x8e\x7b\xeb\x66\x3d\x0d\xc9\x9d\xce\xf3\xac\x6a\x14\x90\x07\xb4\x2d\xd1\xf2\x2a\x77\xdd\x52\x90\x18\x14\x32\x51\x72\x22\x4a\x27\x78\xf3\x66\xfb\x9e\xb0\x2c\x81\x2b\x84\x2a\x42\x84\x25\x61\xc6\x8f\x2a\xc2\x31\xc2\x6c\xe9\xe8\xb1\x9a\xe9\x1e\xbf\xad\x3c\x0e\x9f\x66\x36\x3a\x13\xec\xd8\xb8\x97\xa3\xd0\x0a\x26\xd2\x57\x64\x8d\x56\xc6\x74\x74\x41\xca\x1c\x6e\xe9\x9f\x08\xdd\xad\x25\xd1\x16\xdf\xad\xab\x03\x83\x00\x0d\x3d\x72\x25\xcf\x2e\xff\x70\x76\xb2\xad\xab\x95\x22\x29\x25\x55\xf3\x19\x32\x06\x78\x60\x00\xd4\x2c\xa3\x4d\x70\x8d\xc0\x42\x84\xa9\x4d\x17\x4c\xc9\x2f\x10\x2e\xfd\xdf\x31\x48\xc2\x99\x69\x16\xd4"}, -{{0xd8,0x80,0xd2,0xfb,0x06,0x26,0x2f,0x57,0xab,0x87,0x78,0xe3,0x3d,0x16,0xb4,0x73,0x06,0x09,0x78,0xa6,0x54,0x9c,0xdb,0xcd,0x55,0x86,0xba,0x81,0x05,0xf5,0xac,0xa8,},{0x0d,0xe4,0x86,0xd2,0x11,0x5f,0xaf,0x2d,0x54,0x72,0x66,0x77,0x2e,0x43,0x0f,0xd9,0x72,0x7b,0xdc,0xac,0xe6,0xec,0xbf,0x2f,0xe2,0x3a,0xb6,0x0f,0x7b,0x52,0x54,0xb1,},{0x4c,0x00,0xa7,0x16,0x68,0xd3,0x21,0x3c,0x29,0xc7,0x04,0x1c,0x5a,0x03,0x7e,0xdf,0x13,0xc6,0x51,0x4b,0xd0,0xeb,0xc8,0x80,0xc9,0x09,0xca,0xff,0x15,0x06,0xa4,0x5d,0x27,0x80,0x9f,0xb7,0x4e,0x66,0x02,0xea,0x2a,0xad,0x0f,0x84,0x28,0x31,0xb7,0x4f,0xb3,0xd6,0x90,0x0c,0xcc,0x52,0x06,0x52,0xda,0x28,0x36,0x8f,0xd9,0x0c,0xa3,0x0e,},"\x11\x47\x43\xe8\x2a\x09\x93\xce\xc9\x70\x50\x67\xab\xd7\x7c\x16\x8b\x53\x67\x7e\xde\x5c\x15\x9f\xad\x36\xf0\x6f\xc1\xa1\x4a\xcd\x77\xf8\x83\x79\x9e\xd9\x88\x3f\x99\x15\xae\xa6\x38\xec\x17\x41\xf3\xf4\x21\x58\x55\xfb\x5b\x07\xdf\x37\x93\xbb\xe5\xb5\x68\xeb\x35\x94\x39\x1a\x9e\xf5\x72\x7f\xab\x93\xe5\x74\x69\xb3\x7d\xe1\x25\xb1\xe9\xf2\xe6\xfe\x2c\x3d\x1a\x10\xec\xf8\x7b\x6c\x0a\x66\x5c\x6d\x46\x0a\x17\x0e\xef\xb9\xbf\x71\x6c\xd8\xfa\xea\x97\x64\xf5\x79\xff\x34\xeb\xfa\x9c\x4c\xfb\x34\x70\x6d\x8d\xd7\xc9\xeb\x1d\x10\xb2\xdf\x46\x0a\x46\xbb\x57\x89\x43\x0b\xf4\x49\x15\x8b\x58\x24\xf2\xa3\xa7\xb9\x18\xb3\x3a\xcf\x2d\x9e\xbe\x90\x21\x6d\x1b\x7c\xbf\x4a\xf7\x70\xc5\xdb\x95\xfc\x62\xff\x3a\x3c\x38\x5c\x3a\x82\x17\x85\x3b\x73\x46\x63\x4a\xaf\x30\x60\x72\x88\xdb\x0c\x48\x3b\xd4\xc2\x22\xeb\x33\x2c\xb8\x9d\xc4\xa2\x17\xe6\x33\x4a\x26\x84\x13\xa3\x90\xbb\x37\x1a\xec\x35\x5f\xbe\x4c\x73\x6f\x7d\xa7\x5f\x9c\x88\x75\x41\xa2\xb7\xd0\xda\xc0\x18\xb6\x13\x8f\x02\x1e\x77\x26\x6d\xde\xce\x84\x68\x45\x2a\xda\x39\xf5\xe6\x3d\x02\x09\xb9\xd6\xda\xbf\x97\x54\x13\x25\x6d\xca\xa1\x5a\xc1\x4b\x60\x68\xe1\x77\x05\x6c\x7b\xf0\xf0\xf7\xc8\x84\xa3\x40\x20\x32\x29\x8c\xd5\x59\xa6\x31\x20\x39\x40\x06\x32\x32\x7f\x9c\x0e\x76\x3e\x52\x79\x8c\xb1\x77\xda\x44\x75\xe4\xb2\x40\x5c\x15\x7c\xa4\x27\x74\x11\x08\xd3\x3e\xd0\xb7\xa3\xf5\x34\x38\xce\x6b\x72\x5c\x6d\xd5\x81\x4a\xf5\x1c\xfa\x45\xdb\xce\xd5\x57\xf7\x26\xdb\x13\x0d\x55\xcd\xe7\x53\x3b\xc2\x09\x2d\x6b\x69\x9c\x2c\x87\x0a\xf2\x82\x73\x1e\x18\xd6\x51\xae\x85\xb3\xdb\x4b\xa0\x28\x53\xf8\xc8\x7f\xd5\xe3\xab\x69\xbc\x57\xb0\x8b\x81\xf8\x3c\x23\x9c\xcf\x22\xe8\x17\xe2\xad\xa4\xd0\xad\x14\x48\x7e\xd1\x46\x12\xc8\xb0\x97\x3e\xc0\x65\x0a\x55\xf6\xbf\x9a\xf4\xae\x92\x56\xad\x35\x46\xa3\xf6\x7d\xd3\x5d\x98\x7e\xf2\x19\x09\xa9\x4c\x50\xf0\xef\x06\x40\xe7\x55\xb1\xc4\xe1\xa0\x12\xaf\x0d\x31\x76\x6e\xeb\x5d\xf3\x1c\xd1\x04\xc6\x4e\xb6\x2e\xb4\xef\xb1\x39\xcf\x30\x57\x69\x40\x1d\x21\x3f\x96\xa4\x88\xd5\xee\x7e\x3c\xe3\x2b\x01\x92\xee\x8f\x08\x31\xbf\xbe\x8f\xe9\x5d\xe9\x56\x88\x6b\x52\x4d\x33\x19\xb7\x3f\xd5\x6d\xc6\x0e\x9f\x1c\x72\xd7\x81\x55\xa9\x7c\x6f\x43\x69\x7b\x20\x46\x6b\x3e\x7a\xeb\xd3\x57\xb9\x16\x96\xe7\x34\x8f\x45\x99\xb3\x4f\x35\x91\xed\xdf\xce\x2a\x7b\xd8\x49\xab\x16\xf7\xb4\x3e\xbb\x16\xe2\x3d\x6f\x52\x10\xef\xa3\x0a\xb3\xba\x8d\x32\xc4\x06\x62\xb8\x66\x2f\xd9\x11\x54\x4b\xc2\x45\x8c\x65\x69\xef\x75\xa9\xb9\xdf\x6a\x0f\x6d\x80\xd6\x58\xba\x86\xb2\x41\xca\x19\xce\x9a\x6f\xcf\x01\xd3\xda\xa9\x5a\xfb\x59\xc3\xd8\x9a\x18\xb9\x48\x62\x13\x94\x32\x7f\xc5\xe9\x20\xa7\x5f\x98\xf5\xe2\xb3\xd6\xc9\x5f\xd8\x52\xad\xf5\x67\xb6\xd3\x7c\x54\xd2\x97\x08\x56\xa5\x99\xf7\x49\xe2\xc5\x5d\xac\x7c\x23\xe3\xfb\x1a\x63\xbb\x4c\xc4\x7b\x8b\x94\xf3\xd5\x89\xac\x4b\xee\xf0\xaa\xd4\xe6\x29\x2f"}, -{{0x58,0x58,0x71,0x94,0x1c,0xc2,0x82,0xe3,0x33,0xd5,0x7b,0xbf,0xc3,0xd4,0xae,0xda,0x86,0x2c,0xfa,0x0a,0x37,0x50,0x30,0xcd,0x59,0x4b,0x36,0x92,0x84,0x8c,0x5f,0x00,},{0x4f,0x34,0x38,0x16,0xcd,0x48,0x05,0x0b,0x67,0x8d,0x3a,0xdf,0x70,0x00,0x88,0x77,0xc9,0xfc,0xf5,0xcb,0x66,0x2c,0xc4,0xad,0x2b,0x93,0x86,0x4c,0x02,0x09,0x07,0x07,},{0x29,0x88,0x56,0xe5,0x70,0x18,0x8a,0xef,0xca,0xd8,0x1b,0xb9,0x70,0xf0,0x76,0x96,0x57,0x70,0xc2,0x67,0x62,0xfe,0x29,0xe6,0x55,0x4d,0xc7,0xaf,0xcd,0xb8,0x01,0x72,0x3b,0xf6,0xc7,0x63,0xb4,0xcc,0xd6,0x5f,0x4e,0x15,0xd7,0xd8,0xea,0x38,0xfc,0xf6,0x7e,0xa9,0xd2,0x85,0x90,0xc7,0x92,0x55,0xc1,0xcf,0xeb,0xa7,0xb5,0xe4,0x5a,0x00,},"\x65\x1c\x10\x1b\x3e\x2d\xfe\xf0\x78\x3c\xe9\xf6\x1b\xd0\xa8\xbd\xc9\x30\x7a\xc0\x48\x8b\x9d\xd7\x0c\xd9\x0a\x7e\xd8\xf1\x79\xa7\x89\x35\x55\x62\x95\xb9\x1c\xc2\xb9\x72\x11\xe3\xb9\x81\xb8\xda\xfc\xb3\xd0\x6b\x76\xd0\xb6\xed\xa7\xfc\x61\x94\x5c\x0e\xe2\x65\x2c\x5a\xc4\x54\x25\x64\x96\xcb\x82\xf9\x8c\xc1\xcc\x92\xd8\x18\x93\xb1\x08\x2b\x31\xb4\x7e\x6d\x22\xa2\xde\x60\x9d\xe4\xce\x8d\x7c\xc4\xf4\xa1\x52\xc4\x7f\x41\x0d\x7f\xc3\x7d\x38\xcc\xd6\x29\xa4\xb3\x3e\x62\x21\x89\x60\x81\x79\x7d\x07\x53\xdd\x4f\xaa\x8a\x8b\x44\xd6\xc4\x67\x71\x66\xdf\xb4\xd5\x21\x54\x46\x36\x0a\x3c\x28\xd8\xf6\x8e\x38\xab\x54\x60\x8b\x98\x82\x1b\x83\xc1\x87\xb5\x39\x3a\xd8\x74\xa7\x6f\x4f\x5d\x72\x94\x93\xa1\xfd\x74\xcc\x77\x19\xca\xea\x99\x1d\x22\x9c\x5d\x0c\x8c\x4c\x5f\x89\xd8\xe4\x34\x5f\x4f\x52\x21\x43\x13\x41\x0b\x8c\x06\xb3\x31\x5f\x45\xed\x0c\x2f\x91\x38\xab\x96\x6a\xec\x0a\x64\x5b\x6d\xba\x76\x38\x0a\x53\x91\x23\xe0\xf3\x3b\x97\xf3\xd0\x60\x39\x4a\x30\x53\x58\x1f\xfd\xef\x3e\x6d\x36\x53\x11\x66\xb5\x53\xa9\xdd\xe0\x31\x05\xc0\x4a\xf6\x97\xd9\x5e\x95\x21\x7f\xd6\xdc\x96\x8b\xf3\xb4\x48\xd5\xf3\xa8\xe4\xf5\xae\x7e\xdc\x30\xec\x78\xb1\xae\xa4\xf0\xdb\x18\x9a\x94\x9a\x12\x21\x38\xcd\xfb\x5f\x96\x93\xdb\x00\x4b\xae\xd1\xa4\x21\xdc\x44\x12\x2f\x32\x72\x87\xf7\x27\xcf\x98\x9f\xca\xe3\xcf\x3b\xe3\xe3\xdd\x9b\x9f\x53\x50\x2c\xf5\xd9\xfb\x18\x6d\xe7\x91\xd3\x10\xd1\x22\x86\x9c\x9f\xc3\xb6\x95\xde\xc1\x60\x74\x77\xf3\xe1\x49\xe5\x2b\x63\xcf\xdf\xb0\xd9\x83\xe8\x9a\xf2\xf7\x5a\x8f\x48\x98\x43\xec\x05\xc5\xea\x5f\x0e\x72\x1a\xca\xb3\x87\xc6\x80\x25\xf2\x0a\xbe\x0d\x27\xb4\xce\x29\xf4\xa6\x4f\xb7\xf8\xe8\xa3\x32\x87\x3d\x3e\xd1\x21\xfb\x49\x34\x14\xb8\xcb\x0c\x00\xad\x3a\xb6\x16\xc5\xbe\x52\x41\x47\x1a\xde\xe9\xf8\xf4\x69\x74\xea\xe8\x4a\x4a\x8c\xe6\xfa\xbb\x7f\x5d\x9a\x6b\x75\xa7\xe6\x70\x45\x6f\xcd\xcd\x1d\x98\x2e\x8f\x82\x7a\x4b\xbb\x69\xde\xc7\xe3\x05\x3d\xfe\x83\x5b\x70\x30\x1b\x7b\x76\x3f\x00\x04\xbc\x90\x6e\x14\x55\x42\xf4\x87\xb4\xdb\xa2\xed\x56\x1b\xd1\xa2\x03\x06\x23\x6a\xf4\xb3\x6e\x40\x68\xe8\xc0\x07\xb9\x45\x4f\x87\x41\xa5\xf8\xf0\x79\xec\x1d\xb8\x83\x5e\xb6\x54\x42\x90\xd6\xad\xb5\x2a\x70\xd7\x67\x5d\x85\xdf\x4a\x9a\x12\x55\xbf\xd9\x36\xc3\x31\xfe\x51\xc0\x97\x7d\x12\x4b\x5a\x50\x6d\x29\xc6\xee\xc3\x3c\xaa\x25\xd8\xeb\x28\x95\x2d\x6f\xfb\x9d\x6e\x3d\xa8\x90\x38\x2d\x88\x87\x96\xd3\x74\x60\x7f\x66\x43\xb8\x9e\x73\x26\xd9\xed\xc4\x9a\x0f\x53\xbd\xcb\x8c\xc7\x6f\xfd\x39\x3a\x77\x06\x52\x2d\x04\x17\x00\x36\xcc\xb6\x63\x30\xdb\xac\x9d\xa7\xe6\x16\x8c\xaa\x88\xcb\x62\x18\x1e\x55\xa7\xb6\xd5\x21\xa2\x11\x5e\x23\xe2\x02\xee\x24\x80\xb5\x87\xbe\x45\x01\x44\x79\x79\xa8\xd7\x36\xf9\x01\x2e\xcf\x00\xe6\x7b\x31\xe8\x10\x4f\x6e\x7d\xf0\x8a\x96\x83\xcd\xc8\x9c\x03\xa4\xe3\x7e\xe2\x29\x28\xd4\x5f\xa1\x90\x94\xe0\xd6\xe7\xb4\x0b"}, -{{0x05,0x88,0xac,0xd4,0xe0,0x9b,0xa9,0x02,0x74,0xc8,0xf3,0xd1,0x57,0x5b,0x2b,0xf3,0x64,0xa7,0x76,0x88,0x4a,0x9a,0xeb,0x41,0x03,0x41,0x5e,0x16,0x3b,0xa0,0xbf,0x81,},{0x3e,0xca,0xe6,0x97,0xb4,0x25,0xd8,0x7e,0x34,0xa1,0xd9,0x44,0x09,0x8e,0x3d,0x32,0xe2,0xc1,0xec,0x56,0xc3,0x62,0x7d,0xf8,0x0b,0xa2,0xb8,0xa4,0x3d,0xdc,0x19,0x03,},{0xa1,0x11,0xb9,0x70,0x6d,0x24,0x2c,0xd3,0x6d,0x6e,0x87,0x41,0xcb,0xb0,0x97,0xb9,0xe2,0xff,0xfa,0x40,0xf4,0x3f,0xd6,0xf2,0xd3,0xd9,0x16,0x93,0x66,0x73,0x32,0xb5,0xf2,0xdb,0x5e,0xe3,0xea,0x20,0xb8,0x32,0x91,0xb8,0x40,0x57,0x95,0xb7,0x4d,0x63,0x3d,0x46,0xf4,0x75,0xab,0x7c,0x47,0x61,0x71,0x18,0x53,0x5b,0x80,0x51,0xd9,0x07,},"\xf8\x28\xf8\xc9\xda\xd2\x98\xc5\xb7\x19\xda\xa8\x52\xb1\x7e\x76\x25\x98\xa7\x0f\x4e\xcd\x16\xa2\xfc\x59\x6e\xb0\x26\x38\x99\xe9\x83\xd4\x4e\xdc\xc7\xbd\x24\x0c\xb0\x76\x10\x60\x0a\xe9\x6a\xac\x0d\xfc\x3b\xe3\x87\xb6\x16\x85\x08\x99\xb5\xcf\x44\xe1\x76\x7f\xfa\xca\x3d\xf3\x81\x58\x59\x84\x24\xf8\x07\x14\x14\xc7\x04\xe6\x0b\x42\x2a\xd7\x73\x77\xfa\x7f\x6a\x8c\x5d\x0e\xbc\x02\x35\xe2\xd4\x3a\x98\x4f\x3a\xdf\x75\x9e\xb1\x04\x47\xf3\xc2\xf6\xb8\x0d\x5a\x11\xef\x41\xd3\xa0\x98\x52\xc0\x93\x2a\x1b\x9a\xc2\x3e\x6f\x40\xa1\x67\xde\x21\x04\x1b\xec\x88\x85\xf9\x43\x3e\xb8\x0b\x95\xc9\x78\x59\x58\x04\x6c\xdb\x7b\xf1\x47\xa7\x99\x47\x82\x3b\x41\x49\xae\x05\x21\xd7\xe5\xaa\xbc\x15\x64\xfa\x40\x44\x10\x6e\x2e\x39\x2e\x9c\x34\x44\x57\xe9\x92\x93\x76\xea\x9b\x42\x29\xc6\xe7\x73\x8f\xe7\x90\x08\xd5\x54\xc4\x29\x39\x69\x14\xc3\x63\x87\xf5\x79\xb4\x6b\xab\x14\x6f\x6a\x95\x10\xeb\x6f\x8c\x85\x55\x1c\xbd\x84\xc7\xdc\x0d\x0b\x1c\x01\x0c\xcb\xa5\x96\x3a\x7f\x39\xf1\x81\xe4\x4d\xbc\x98\xe4\x95\xaa\x63\xc0\x10\x59\xcb\xe6\xa9\x9b\x07\xb4\x49\xe7\x75\x9c\x9a\xf9\xe0\xf8\xd9\x05\x4a\x67\xa3\x48\xfa\x19\xd7\xf9\x1e\xc0\xa4\xd4\xf2\xc7\x02\x6c\x3b\x84\x92\x59\xa3\x50\x41\x7f\xd8\x6c\xab\x21\x42\xe4\xcf\xe3\xc0\xaf\xbf\x25\x18\x2a\x2d\x52\xbd\x2e\x0b\xc9\x20\xe8\x50\x80\x83\x2b\x91\xb9\x27\xb6\x29\x48\xa6\x7c\x31\x7e\xb0\x90\x91\x46\x1d\x49\x3e\xea\x5f\xfc\x47\xbf\x08\x55\x82\x96\x82\x58\xa3\xc8\xdd\x81\xa8\x58\x27\x0b\xdd\xaf\xe7\x92\x56\x84\xa1\x5f\xfb\x51\xbc\xfa\xab\x93\x1a\xfa\x46\x5e\x30\x90\xe8\x6b\xe4\x1e\x35\x47\xcb\xa2\x34\xb8\x5f\xe7\xdb\x70\x04\x96\xa5\x05\x00\x2d\xf3\xca\x4e\xae\xc7\xb9\x62\x78\xc7\xd1\xa7\x7d\xb8\x34\xa9\x17\x97\xbb\xb8\x26\xd0\x92\xaa\x28\xb4\x95\x45\xed\x3b\x1e\xda\x23\xbe\x11\xa3\xf5\x28\xb9\x55\xcb\x0c\x4f\xa6\x6e\x16\xe9\x57\xe5\x70\x4c\xf3\x19\xe5\xf7\x9c\xc0\x9f\x2d\x05\x4e\x6d\xaf\x19\xe2\x92\x6b\x11\xe1\xe4\x13\xff\x82\x2c\xa1\x41\xf7\xc3\xd3\x85\xae\x95\xdd\x20\xb3\x46\xe5\x83\xcf\xb0\xc2\x29\xec\x39\xcf\x88\x9a\x54\x19\xcd\x37\xbc\x18\x4e\xf5\xfb\x14\x46\x22\x08\x0a\x30\x2d\x9d\x77\x45\xc4\x51\xf7\xd8\x82\x42\xcc\x26\xb9\x16\xa3\x56\x9a\xbc\x7d\x1f\x21\x6d\x57\x79\x7a\x47\x2b\xc6\x21\x76\x17\x58\xe8\x40\xeb\x8e\x29\xbc\x8e\xfc\xb7\xaa\xfc\x7c\xf8\xf4\xe5\x93\x30\xd3\x5e\xe1\x07\x49\x6d\xec\x6e\x71\x4b\x1f\xa4\x30\x98\x37\xbb\x47\xeb\x3a\x06\xb4\x60\x4d\xd2\x07\x33\xcc\x0e\xaa\xc2\x64\x9e\x18\xc0\x73\x42\xef\x55\xd1\x9b\x8d\x03\x95\x91\xac\x28\x69\xac\xc3\x4b\x6c\x3c\x1c\xa3\xcf\x26\x3f\xf8\x4c\xa4\x3a\x5f\x64\x65\xba\x34\x88\x8c\x10\x90\x13\xb3\x2b\xfc\x0d\x0d\x15\xf5\xa7\x6c\xec\x27\x0a\xb3\xac\x9a\x10\x63\x31\x31\x2f\x5a\x0a\x84\x28\x2c\x3a\x3d\x4a\xea\x1e\x7c\xf5\x3d\xbf\x8b\x24\x0b\xdd\x11\x1c\x34\xd2\xa9\x3d\xfd\x12\x58\xfe\x92\x67\x13\x3f\x75\x54\xdc\xc2\x1a\x8f\x43\x9c\x16\x5d"}, -{{0x7d,0x14,0x02,0x3e,0xb4,0x8b,0xbd,0x43,0x76,0x49,0xa2,0x41,0x87,0x79,0x05,0xa3,0xc9,0x32,0xf1,0x46,0x40,0xf2,0x9a,0x0f,0xb1,0x34,0x11,0x4e,0x8f,0x33,0xf5,0x82,},{0xea,0x5c,0x11,0xb4,0xb2,0xc5,0xef,0x4a,0xb7,0x06,0xcc,0xa3,0x47,0x50,0x43,0xc9,0x58,0x18,0xeb,0x56,0x5a,0x79,0x7e,0x33,0x68,0x8a,0xfe,0xac,0xd6,0x8a,0xdc,0xca,},{0x31,0x33,0x9d,0xce,0x23,0x33,0x6d,0xf5,0xb2,0xb1,0x93,0x52,0x2a,0xa3,0xdd,0x2d,0x41,0x14,0xa6,0x6a,0xf1,0x65,0x62,0x89,0xc9,0x52,0xbc,0x11,0xc9,0xb2,0x10,0xf7,0x7a,0x54,0xd4,0x61,0x61,0xf4,0xe0,0xc5,0x2b,0x30,0x13,0xe4,0x0b,0x9e,0x9e,0x84,0x27,0xd8,0x51,0x32,0x5b,0xd7,0x1c,0x4d,0x99,0x35,0x3e,0xee,0xd7,0x51,0x08,0x0d,},"\x90\x01\xdb\x31\xf2\x79\xbe\x50\x53\x19\xb8\xe7\x2b\xde\x11\x99\x51\x29\x80\xdf\x65\xf0\xd8\xa9\xb4\x93\x04\x67\x41\x3a\x99\x7b\x97\xa3\x62\xb5\x72\xa4\xb4\x4b\xc9\x40\x48\x7f\x18\xb2\x08\xce\x6a\xc5\xc6\x87\x16\xd3\xaf\x1b\xce\xf1\x70\x38\x3b\x5c\x4b\x5c\x47\xe4\x47\x37\x72\x6f\x93\x83\xbc\x4f\x14\x47\x68\xbf\x5c\xaf\xb4\xe9\xdf\xe3\x97\x61\xe6\xed\x47\x89\x71\xd1\xc7\x0e\x6d\xab\x2f\xd0\x49\x9d\xff\x92\x93\xb2\x39\xd1\x6c\x96\x02\x61\xc6\x82\x18\xb9\xf5\xb1\xbe\xe6\x90\xf0\xd2\x40\xc1\xb3\xdb\x71\x1f\x9e\x82\x1f\x08\x09\xbb\xeb\x9a\xaf\x24\x9c\xcb\x16\x8c\x67\xd9\x65\x56\x2d\x24\xf8\x48\x51\x61\x40\xbf\xd9\xfc\x05\x0d\x4f\x20\xda\x5a\x17\x94\x46\x8a\x9c\x07\x25\xea\x5c\x66\x9d\x5c\x63\x0d\x93\x10\xe5\x74\x51\x07\xda\xd3\x72\x61\xb5\xd9\x1e\x38\xe0\x85\x12\xe6\xf3\x73\xec\x5d\xca\xd5\xca\x09\x07\x29\x07\xc8\xfb\x7b\xf3\xb9\x26\xc3\x33\x94\x90\xb3\xf5\x1f\x76\x44\xe7\x3a\xe2\xec\x01\xd6\x1b\xe7\xc6\x52\x65\x36\xb4\xff\xd1\xab\x68\x49\xfe\x0c\x2f\x40\xd3\xbd\xa2\xa4\x9e\x55\x50\xb8\xdf\x97\x90\x81\xda\x85\x16\x8d\x0f\x71\x58\x2b\x90\x36\x77\x52\x6d\x1f\x1b\x15\x11\xe1\x38\xb6\x84\xfc\x46\xaa\xc8\xbd\x80\xc3\xde\xf7\xee\x81\x38\x19\x04\x61\x80\x7c\x55\x36\x12\x5c\xb0\xe2\xc3\xd0\x83\xa1\x87\xc7\x26\x9c\xb5\x31\xec\x36\x78\x78\x7b\x32\x55\x5c\xf0\x4a\xb0\x93\xc9\x00\x2e\x7d\x79\x2b\x4d\x93\x3f\x2e\x30\x70\xf3\x9a\xc8\xcc\xf8\xd5\xf5\x45\x5f\x12\x10\x9d\x8a\x8a\xeb\x4e\x21\x2f\xad\x4a\x70\xb1\x47\xc0\x4a\x7b\x91\x84\x60\xb1\x31\x63\x76\xe6\x40\x20\x85\x95\x17\xeb\x7e\xe3\x0c\x29\x0b\xe8\xb8\xd6\xf9\x67\x39\x15\x25\x6c\x3b\x04\xb9\xd9\x05\x4b\x52\x33\x8e\x0d\x36\x07\x85\xe4\x6a\x18\x28\x44\xc5\xc3\x76\x6a\xea\x8e\xd3\x11\xb2\xd4\x81\xc0\xb7\xb2\x11\x4e\x41\x8e\xd1\x7f\x8d\xeb\xf0\x1a\x83\xff\x37\x51\x70\x24\xee\x9e\x28\xe0\xc9\x0d\xce\x6d\x05\x9f\xfe\xe4\x13\xd2\x7c\xd6\x27\x83\xa8\xb8\xb5\x01\x6a\xd2\x76\xe3\x9d\xfd\x8f\x8f\x3d\xdf\xc4\x28\x10\x18\x18\xce\x50\x7f\x00\x3e\xb5\x8c\x9a\x5c\xc8\xb1\xaf\xf0\x5a\xab\x8f\x0d\x7f\x1d\x1f\x6d\x4b\x87\x1d\xbc\xed\x1f\x3d\x28\x66\x23\x97\x52\xfb\x13\xf6\xe1\x80\x34\xbb\x2b\x5a\x66\x35\xca\xa6\xec\xc4\x62\xe0\x58\xeb\xe2\xfa\x65\x1d\x3d\x0f\x36\xe2\x0a\x31\xf7\x65\xe4\xb9\x58\x27\x0b\xd8\x25\xc6\x81\x8a\xac\x1a\xd7\x56\x31\x35\xae\xed\xf1\x4a\x2b\x6d\x39\x8b\x6e\x34\x00\x84\x01\xb2\x18\x46\x18\x20\x07\x1c\x5a\xf7\x78\x46\xcb\x9c\x32\x81\x90\xc0\x61\xd5\xaa\x6e\x0e\xcd\xe7\xef\x58\x56\xb0\xe6\x81\x4f\x83\x3f\x70\x40\x96\xdf\x08\x25\xfa\x4b\x46\xdc\xda\xcf\xa2\x7c\xd8\x7b\xd7\xbf\xef\xf7\xf8\xca\xe1\x66\xa3\xa0\x4d\x43\x7c\x7b\xe7\x16\xc4\x90\x45\xc7\xbd\x3d\x13\x49\x62\x7c\x9c\xbd\x04\xc1\x5f\x00\xa6\x96\xe3\xcf\xfb\xb4\x5a\xf2\x91\x22\x62\x7e\x7e\xd3\x3b\x42\x49\x91\x3b\xec\x00\xf0\xe2\x8a\xa1\x12\x98\xcc\xe8\xb6\x49\x08\x1f\xe3\xb1\x69\xb4\xaa\xea\xca\x48\x5b\xda"}, -{{0xe8,0x30,0x6b,0xad,0xa6,0xd5,0x5e,0xb1,0x88,0xd9,0xf7,0x5c,0x81,0x5c,0xc9,0x14,0xe9,0x3c,0x9c,0x72,0x22,0x39,0x1c,0x15,0xbb,0xae,0xaf,0x93,0x54,0x43,0x79,0x35,},{0xbf,0x27,0x98,0xb8,0xe5,0x54,0xf5,0x1e,0x22,0x86,0xc3,0x03,0x4a,0x88,0xe5,0x77,0xff,0x23,0xfa,0x32,0xa6,0x72,0x44,0xea,0x82,0x45,0x91,0x2e,0x8b,0xf4,0x6d,0xa4,},{0xcc,0x66,0x27,0x30,0x8e,0x2f,0x42,0x43,0x83,0xfa,0x70,0x59,0x4f,0x57,0x57,0x91,0x60,0x05,0x40,0x02,0x7a,0x27,0x51,0x61,0x9b,0x28,0x3a,0xff,0xea,0xeb,0xc9,0xc9,0xd2,0x9a,0xc6,0xdb,0x28,0x6d,0xd2,0xc1,0xb5,0x96,0x58,0x7b,0x87,0x8d,0x1d,0xf4,0x78,0x1d,0x43,0x6b,0xb5,0x70,0xc1,0xc0,0xf0,0xd3,0x33,0x68,0xdc,0x66,0x52,0x0b,},"\xd7\x04\x38\x09\xc3\xe3\xdc\x00\xb1\x7e\xfd\x52\xc9\x13\x0b\x11\xb7\x86\xf1\xe2\x57\xb5\xe2\x2f\x81\xa7\xfa\xae\x60\x0b\xbc\xdf\xd5\x18\x53\x7f\xe8\x52\xc6\x42\x35\x97\x62\xfb\x75\xe8\xad\x85\x92\x49\xe6\xab\x49\xce\x1b\xb0\x4f\x24\x92\xf2\xaa\xc3\x54\x46\xba\x6e\xb0\x3e\x76\xde\x3a\xbd\x2d\x5f\xc7\xe6\x14\x68\x43\xad\xd0\x42\x86\x0a\x4a\x16\xb5\x9b\xdd\x7d\x03\x83\x78\xa3\x5e\x1a\x04\xb1\x21\x7a\x55\x71\x0d\x93\x7e\x2c\x90\x32\x23\x2e\xa2\xcd\xd1\xd2\x5a\x0b\xff\x71\xef\x5d\x3e\x0c\x05\x6b\x29\xcb\x92\xf6\xdf\x69\x2b\xde\x14\xdf\xa5\x0e\x13\x2b\xeb\xd8\x9e\x9f\x18\x33\x88\x0b\x65\x7a\x78\x1e\x94\xec\xb6\x03\x04\x17\x56\xe5\x51\x7d\x44\x23\xc5\x6f\xad\xc1\x3e\x2b\x31\x80\x88\xfe\xdd\xf3\xb5\xc8\x3c\x20\xb4\x6f\xdd\xbb\xa9\x23\x05\xe4\x86\x06\xda\xb7\x48\xce\x38\x48\xb8\x43\xf4\x71\x1f\x37\x0c\x3e\xc7\xd5\xe1\x9a\xb4\xc0\xac\x1a\xe1\x5a\xaa\xf2\x3d\x65\xfe\xce\xda\xbc\x08\x04\x9b\x9e\x29\x11\x3e\x57\x61\xed\x9d\x1c\x62\xeb\x07\x5c\xab\xb2\x67\x4c\xdb\xe1\xe3\xa8\x89\xba\xe4\xb1\xdd\x31\xb6\xa5\xb2\xea\x1b\x8d\xed\xcc\x3c\x51\x5e\xdc\x44\x67\xc3\x02\x31\x17\x6c\xd4\x4b\xec\x8a\x05\x79\x51\xab\x5c\xd3\x9a\x96\x23\xf8\xaf\x84\x73\xcd\x27\xd9\x33\x02\xbf\x8a\xa6\x24\xc9\xc3\xc5\x79\x9d\xa1\xdc\x49\x44\x94\xef\x8f\xf1\xdb\xe0\x18\x7e\xa5\x16\x26\x70\xb8\xd0\x98\xc3\xa9\x49\x19\x39\x8d\xad\xf7\x9e\x6c\x24\x91\xc4\x44\x39\x2c\x29\xcd\x50\xd5\x74\x35\x06\x32\x90\x84\x2b\xfa\x0e\x85\x30\xfa\xeb\xc0\x06\xd6\xea\x78\x01\x11\x7e\x0a\x3f\x01\x9e\xe2\x8f\xb3\x79\x22\x35\x40\x2e\x2f\x69\xb8\x7a\x43\xdc\x22\x7f\x9d\xe3\x16\x02\x97\x56\xc3\x16\x7d\x64\xa3\xa3\xf6\xd7\x31\x60\x33\x1d\x5a\x18\xee\xe5\xb0\xe6\xe2\x2a\x66\x3e\xfd\xcc\x8d\x67\xaf\x3b\xce\xd0\x41\xea\x84\x3a\x56\x41\x60\x3e\xc7\x2e\xfd\x64\x4e\x17\x3d\x19\x9a\x8c\x83\x0b\x2e\xa5\xfe\xc0\x37\x80\x27\xc3\x72\x25\xaf\xcb\x60\x4c\x4c\xdc\xf4\x09\xbe\x1c\x50\x9c\x9a\x37\x7b\xe0\xd0\x52\x41\x07\xc6\xd9\x2b\x5f\x09\xa2\x9e\xfb\x71\x09\x29\x56\x70\xbb\x1a\x1d\xd3\xea\x00\x8b\xb7\x91\x85\xf0\x9b\x98\xf0\x20\xc4\x3f\x14\x39\x68\x5b\x96\xf6\x19\x93\x11\xa0\x90\x87\x0f\x0d\x9b\x10\xd4\x95\xcd\x41\x0a\xa9\x5b\x7e\x53\x74\x9b\xe3\xa6\xc0\xfb\xc7\x29\xf9\x6c\xf8\x56\x43\x97\xb0\x9c\x13\x51\x40\x16\x82\x5f\x72\xf1\x4e\xb9\x32\x94\xd7\x01\x0a\xcc\xfd\x11\xf1\x7a\x6a\xc8\xf5\x44\x26\x3d\x60\x38\xd5\xc7\xdb\x29\x48\x62\x91\xb3\x0e\xa4\x9b\x6b\x54\xcf\x88\x82\x6d\xd2\x52\xcd\x9d\xbb\x57\xd8\x41\xb5\xa4\xcf\x70\x2a\x32\x64\xfa\xa4\xdc\xcc\x86\xab\x14\xda\xf1\x24\xef\x3d\x53\x35\xa6\x87\x8d\x06\x5c\x6b\xa2\x99\x91\x04\x57\x65\xee\x55\x42\xcc\x9f\x5d\x9f\x35\x4d\xcd\x2c\x6e\x0c\xf7\xff\x3a\x30\xf6\x49\xb5\x91\x2d\x97\x1d\x63\x35\x78\xf1\xe9\xf2\x63\x87\x4d\x05\x65\xc2\x47\x30\x1d\xcb\xd1\x5d\x76\x21\x1a\xe2\xd3\xd5\x06\xfc\x64\xde\xb7\xe0\x42\x56\x5d\x43\x8e\x2b\xfb\x24\x92\x43\xb7"}, -{{0x36,0x3c,0x1e,0xa7,0xc3,0x2e,0xa3,0x28,0xa0,0x55,0xaf,0x7b,0xd8,0xb3,0xbf,0xd2,0x04,0xfb,0x0b,0xbd,0x4b,0xf4,0x2f,0xfe,0x26,0x2f,0x3a,0x5e,0xbd,0x54,0xda,0x55,},{0x7a,0x83,0xec,0xca,0x51,0xef,0x6e,0x5a,0xa0,0x43,0xa5,0xce,0x04,0xd9,0x28,0x8a,0xdd,0x49,0xa2,0x77,0x54,0x8b,0xd3,0x01,0x6b,0x69,0x3f,0xfa,0x79,0xa2,0x2e,0xdc,},{0x5f,0xd1,0xe5,0xf9,0x92,0x2a,0x12,0xf6,0x36,0xb7,0x2a,0x7d,0x62,0x17,0x09,0x1f,0x94,0x8a,0x55,0xbc,0xb1,0x82,0x6b,0x8f,0xca,0xf9,0x9d,0x26,0x41,0x6c,0x7a,0xb1,0x35,0x1c,0x10,0xf4,0x09,0x3f,0xfd,0x8a,0x2a,0xf8,0x69,0x14,0xa0,0xa9,0x81,0x84,0xec,0x7e,0x06,0xd2,0xde,0xe8,0x7f,0xdc,0x0f,0x4a,0x47,0xf8,0xc6,0x3c,0xf5,0x01,},"\xc4\x1c\x1e\x1f\xb7\x59\x54\xa0\xae\x0e\xbc\x29\x09\x0b\x9f\xc5\x33\xe6\x93\xe7\xc7\x10\x5c\xfe\x40\xef\x52\x6e\x4e\x12\xa7\x40\x52\x21\xf2\x18\xc7\xac\x01\x9e\x1d\x4c\x92\xda\x28\x53\xf2\xd7\x26\xaa\x62\x27\x79\x24\xdf\x0c\x34\x3f\xc3\xd4\x7c\xd5\xa9\x9a\x3e\x27\x9b\x26\xa1\xb1\x3b\x1f\x2a\xa3\x6f\x7c\xcb\x4b\x54\xfb\xef\x18\xbd\x87\xa5\x5f\x1b\xc4\x0c\xe7\xb2\x02\x91\x45\xee\x7a\xab\x39\x17\x95\xac\x68\xde\x61\x99\xf5\x05\x94\xfc\x79\x61\x1b\x85\x13\x1c\x14\x30\x21\xf2\x6f\xa3\x58\xda\x0c\x7c\x6a\x65\xdd\xe0\x76\xda\xb4\x88\x67\x5b\x72\x23\x09\xe5\xed\x97\x46\xd1\x8a\x89\x30\x99\x06\xa7\xa9\xdf\x23\x7d\xd2\x7b\xd5\x90\xcc\xc7\x7c\x40\x2e\xf6\xe1\x9c\xa6\x3c\xc8\x6b\x85\x16\x03\x30\xee\x6e\x1f\x1f\x47\xa2\xff\x80\x7e\xef\xad\xc0\x09\x63\x52\x0a\x1c\x60\x0a\x3e\x45\xaa\x7f\xb2\x55\x4f\x47\xd8\x97\xbd\x86\xd8\x1c\x3b\x08\x77\x10\x12\x22\xfa\x78\x50\xb8\x0c\xe3\xbc\x06\xc9\xe5\x8c\x0c\x96\xe3\x2f\xec\x85\x30\xc9\xfa\x1e\x41\x63\xf0\xef\x84\x56\x95\x2b\xf6\xdd\x58\x04\x5a\x36\x3d\x61\x88\x0e\x9a\xc9\x76\xa3\x60\x3e\xf7\x7a\x4c\x39\x5e\x6a\x07\xe3\x42\xf6\x02\x3b\x8a\xf1\x02\x25\xcf\xf2\x40\xef\xc0\x36\x6a\x79\x9f\xd8\x6e\x9d\x06\x20\x60\xd8\x72\x40\x33\xbd\xf6\x75\x88\xcd\x73\xac\x28\x4d\xe4\xc6\x94\x3c\xf4\x5e\xe4\xf7\x5f\x59\x37\xd9\x7d\x78\x10\x5f\x0b\xbe\xce\x04\xd3\xdc\xb5\xe4\x24\xef\xf8\x9b\x77\x3e\x5d\x6b\x4f\x37\xef\xa9\xa0\x65\x4c\xb3\xef\x34\x52\x78\xa6\x2d\x87\x6c\xfe\xf9\xa3\xdc\xdc\xeb\x70\x81\x44\x18\x77\xeb\xd5\xfa\x30\xc9\xd9\x54\xe3\x68\x4f\xa4\x76\xa4\xf4\x85\xd4\x26\xfd\x3c\x8c\x32\xbe\xa0\xf9\xcc\x20\xb1\x5e\x8f\xdf\xc3\xca\x4b\x30\x2c\x07\x4f\x50\x81\x32\xd1\x5d\xe6\x25\xc1\x0a\xe0\x73\x78\x11\x46\x3d\xcc\x55\xfc\xc4\x01\x4b\x20\x20\x8f\xff\xce\xfa\x9d\xd4\x52\x11\x9b\x16\x52\xde\x41\x34\x8f\x69\xf2\xc4\x88\xf5\xcc\x18\x56\xd6\xe7\x8a\x5c\xbe\x3e\x37\x3d\xd4\x59\x8e\x2d\x39\xf8\x76\xeb\x94\xe0\xb0\x1b\x21\xfa\x91\x29\xef\x41\xb6\x39\xf4\xe0\x5e\x69\xde\xb1\x83\x5e\xd4\x4b\x91\x12\xa6\x86\x2a\x5b\xce\xa0\x72\xc6\xe1\xb8\xf0\xf0\x58\xf4\x6b\xac\x2a\x84\x5a\x58\x2d\x14\x8f\x17\x76\x0b\x9e\x0a\x2b\xa6\x0b\xbb\xf3\x88\x4a\xf9\x4d\xd4\xc7\xec\x9d\xb0\x8e\x9a\x5b\xcc\x6d\xde\x13\x46\x44\x2e\xe1\xf4\x70\x7d\x1f\x79\xb6\x9b\xa8\x67\xf4\x18\xdc\x27\x91\x73\xf7\x7a\xdb\xc5\x8a\xb8\x5e\xa3\x93\xb9\xdc\x68\x26\x19\x00\xc1\xca\xa8\x2d\x2f\x50\x47\x4c\x42\xae\xc9\x11\x31\x42\x78\xc0\xaf\xfa\x2a\x6b\x6c\x36\xd1\xff\x88\xf3\xb4\x9f\xb2\xb7\xc3\x39\xd2\xa7\xc2\xb3\x04\x9f\x8c\x0a\x08\xd1\x6a\x9e\x8d\xf9\x3d\x13\x0d\xa4\x84\xbd\xba\x6d\xbe\xc5\x34\xcd\x51\x09\x7a\x04\x82\x21\x10\x6b\xab\x48\xd6\x7f\x95\x1b\x75\x05\xa1\x48\x48\x92\xb8\x57\x79\xc5\xa3\x11\x17\x02\x12\x4d\x95\x7a\xcf\x2d\xc3\x52\xef\x9b\xa2\x47\xbc\x80\xe2\xce\x96\x26\x9c\xe8\x5e\x78\xb9\xeb\xda\x98\x90\x76\xdd\x5f\xf7\x3e\x1e\xb2\x75\xe5\xd7"}, -{{0xdb,0x22,0x28,0xff,0xff,0xa9,0xd2,0x53,0x4a,0xef,0x91,0x8f,0xb8,0x5b,0x82,0x1a,0xd3,0x60,0xe2,0xd3,0x9d,0xec,0x5a,0xeb,0x2d,0xb0,0xdf,0x02,0x49,0x7f,0x94,0x16,},{0x6d,0x01,0x95,0x77,0x7f,0x81,0x05,0xff,0x52,0x3b,0x79,0xc5,0x9e,0x3c,0x30,0x81,0xfe,0x89,0xdb,0x6f,0x87,0x03,0x3f,0x09,0x4f,0xa5,0xa9,0x40,0xce,0xf8,0x4b,0xb4,},{0x82,0x18,0x9d,0x34,0x0b,0xc1,0x1c,0xea,0xa4,0x00,0x41,0x0e,0x08,0xba,0xe9,0xd9,0x01,0xaf,0x05,0x91,0x25,0xe9,0x53,0x78,0x6f,0x8a,0x04,0x3d,0xdf,0x11,0xf7,0xb2,0xf8,0xe3,0xb6,0x17,0xac,0xcd,0x78,0xe2,0x93,0x9a,0xdf,0xab,0xf2,0xd2,0x47,0x1f,0xaf,0xd6,0xf5,0xbc,0x45,0xb1,0x40,0x75,0xb3,0x28,0xe3,0x4d,0x80,0x75,0xb2,0x07,},"\xfc\x07\xcd\x99\x04\x0f\x13\xe5\xa8\x4f\x94\x74\x6d\x6b\xb8\x68\xf7\x52\xb4\x48\xb6\x2d\x99\x59\x3e\xf2\x9e\x43\xcc\x82\x45\xf0\x47\x0f\x65\x55\x2d\x64\x32\x20\xf6\x71\x92\x85\xe1\x5c\x37\xa6\xd1\x74\xae\xf7\x60\x88\xcc\xda\x5f\x88\x68\x5b\x52\xda\xe2\x84\xc6\x5b\x38\x0d\xa3\x45\xa2\xe1\xaf\x2e\xd7\x64\x80\xd2\x69\xcb\x93\x4b\x43\x17\x62\x0b\x79\x2e\xbb\x39\xb2\xa6\x78\x24\x7d\x6d\x81\x5f\x2a\x5c\xb9\xaa\x56\x0e\x4b\xf6\xde\xba\x4c\x0a\x0d\xdc\x82\xd0\xe5\xa5\xa6\x5a\xcb\xc4\x78\xe1\xec\x6b\x06\x4d\x7b\xb7\x38\x8a\x73\xf6\xed\xa3\x0b\x0b\x6b\x73\xdd\x8f\x87\x92\x63\xad\x1a\x03\x48\x67\x1d\xcf\x21\x1c\xb9\x6e\xd0\x8e\xd5\x2f\x33\x17\xda\x68\x18\x5d\x6b\xb2\x58\x9d\xc1\x1d\x75\x5d\x47\xa3\xb6\xf6\xa0\x38\x6a\x85\x94\xd9\x57\x0b\x2e\x9b\x0d\x4b\x5e\x13\xdc\xcd\x9b\xb7\xac\xbe\xf0\xab\x27\x6a\x7a\xeb\xe1\x29\x31\xbe\x67\xf1\x0d\xe2\x67\xa0\x29\x89\x53\x01\xf5\x66\x25\x30\xad\x8a\xb3\xd2\x30\xb3\xb6\xd7\x09\x3a\xcd\xfb\xf2\x74\x75\x7a\x90\x78\xe2\x0c\x23\xbc\x82\x2d\xef\xfa\x61\x00\x54\x86\x10\x2c\x01\xab\x82\xbd\xc8\xcd\xcf\x1b\xb3\x7f\x9b\x56\xd3\x9e\x50\xfd\x5a\x68\x95\x41\x6e\x76\x7f\x4e\x36\xc1\xa4\x17\x78\x90\x81\x25\xb5\xca\x3f\x92\xa9\x0d\xa9\xad\xdf\xf1\x55\xfb\x1f\xd7\x76\x88\x08\xa8\x0f\x20\x3e\xd7\x37\xef\x00\x77\x63\xbd\x2f\xea\x9f\xf2\x8c\x84\xb4\x35\x51\xc9\xfc\x43\x8f\xfc\x47\xfc\xfc\xf6\x4d\xc7\x70\x06\x13\xaa\x8b\x3a\xf8\x63\x3a\xe8\xb6\x98\x74\x37\xc0\xaa\x47\x81\xbe\x1e\x82\x13\x96\xc5\x36\xcb\x30\x05\xd0\x55\x49\xb1\xcb\xa7\x01\x35\xaf\xb7\xfe\x30\x68\x96\x1c\xad\x3a\x14\x63\xcc\x0b\x55\x60\x68\x4e\x27\xbb\xa7\x7a\xef\x41\x9d\x82\x38\x68\xe0\xce\xba\xd1\xf1\xce\x0a\xe9\x02\x74\x4a\x15\x2d\xd2\x94\x51\xa1\x7e\x28\xa8\x9a\x71\x58\xa1\x83\x6e\xfc\xe4\xa3\xe5\xc7\xd1\xfa\xa4\xc3\x87\x5b\xc4\x6c\x4d\x9b\xe2\x2d\x66\xd3\x66\xac\x6f\x59\x53\x8a\x00\xb2\x75\xb0\x2f\xac\x6d\xa7\x55\xa8\x54\x08\x19\x97\xd5\xd1\xd0\xe6\xe5\x68\xa5\x95\x8c\xf3\x34\xc5\x18\xcd\x51\x7a\xb9\xd7\x3c\x48\xd6\xcb\xc4\xae\x4e\xea\x43\x53\x11\x3e\x7e\x4a\x7c\x05\x92\x0e\x68\x6b\xf0\x7a\xfb\xfb\x8d\xd2\xec\x4f\x18\xfa\x71\x38\xe5\x7d\x33\x2c\xd7\xa4\x22\x8f\xea\x73\xbc\x09\x25\x2f\x24\x42\x72\x94\xeb\xd3\x64\x5e\xe0\x99\x6c\x2e\x85\x1a\x8a\xa5\x1a\x7c\xd9\xfc\x2e\xab\x47\xc0\xab\x21\x3f\x4f\x51\xd2\x16\x09\x1e\xd0\x89\xe4\x59\x2e\x9b\xb0\x82\x8b\x85\x8f\x84\xf6\x0b\x93\xad\x84\xa0\xa2\x28\x27\xcb\xd2\x74\x14\xb7\x81\x32\x2a\x04\xd3\x96\x08\x28\xf6\x38\xdf\x28\x34\xc7\xf7\x83\x9d\x70\xdb\x12\x6b\xee\x5a\xf2\xee\x75\x59\xa8\xac\x4c\x01\xa6\xc3\x91\x39\x6a\xf9\x3f\xa0\x60\x89\x40\x29\x7d\xdf\x89\x00\xc5\xdd\xb4\x66\x34\x0a\xe5\x1c\x60\xc7\xea\xd7\x62\x44\x7e\x76\xd8\xbc\xcb\x57\x39\x97\xcf\x66\x14\xd1\x88\xa0\xb9\xa2\xf5\x6e\xed\x9b\x0f\x9d\x46\x3a\x19\x78\x7f\x40\x92\x58\x1a\x65\xc6\xbf\x78\x1b\x93\xc5\x60\x87\xe5\x4e\xe1\x34\x3a\xab"}, -{{0x66,0xb5,0x0f,0x69,0x2e,0x39,0x5e,0xb8,0x33,0x86,0xe0,0x27,0xc8,0x2c,0xe3,0xfd,0xee,0x3b,0xd8,0x99,0xb0,0xd3,0x17,0x9d,0xb0,0x86,0xfb,0xf5,0x24,0xf5,0x74,0x59,},{0x44,0x85,0x36,0xe9,0x82,0x40,0x84,0x37,0xce,0x89,0x67,0x40,0x53,0xe3,0xc5,0x89,0xc9,0x8c,0x09,0x5c,0x60,0x02,0x1a,0x11,0x81,0x78,0xc6,0x26,0x1d,0x88,0x10,0xfe,},{0xbd,0x13,0xf6,0x36,0x2c,0x07,0x07,0x89,0x22,0xf3,0x0c,0x63,0x30,0x75,0x1b,0xf6,0xe7,0xcf,0x42,0xa7,0x69,0x16,0xee,0x65,0x3e,0xb1,0x7a,0xcc,0xff,0x1f,0xbb,0xca,0x35,0x25,0x8c,0x4c,0xbc,0x58,0x2a,0x5e,0x8c,0xc9,0x4f,0xd2,0xc7,0xed,0xeb,0x53,0x76,0x2f,0x1f,0xc2,0x31,0x23,0xd7,0xf4,0xf1,0x45,0x40,0x9b,0x31,0xcd,0x38,0x02,},"\x74\x28\xa9\x64\x21\x2b\xcb\xe8\xdf\x7d\x59\xe4\x8e\x92\x34\x80\xaa\x0e\xe0\x9b\x91\x0d\x04\xef\xb6\x90\x36\x62\xef\xc3\x10\x7a\xc8\xfd\xc0\xc5\xf3\x92\x72\x74\x0c\xd8\x77\xe1\x6c\xd7\x1c\x54\x92\x38\xc3\x37\x22\x0c\xe2\xf6\xb5\xa1\xfc\x6f\x7b\x0a\x1c\xd4\xed\x21\xd9\x38\x89\x08\x1e\x34\xfb\x7f\xde\xcf\x41\x78\xbb\xd4\x31\xe6\x11\xe5\x39\xd9\x00\xc3\xd0\xac\x3d\xc7\x10\x7b\x36\xb4\x1d\x6d\x0d\x5d\x32\xc1\x97\x27\xf9\x08\xb6\xeb\x36\x7f\xeb\xb3\x52\xa4\x93\x58\x1f\xf1\x28\xb5\x6c\x4c\xaf\x6f\xb8\xe0\x99\x81\xf0\xd3\x79\x57\xd1\x28\x20\x17\xfb\xb8\x07\x61\x4c\x20\xf4\x65\xdc\x02\xb0\xcd\x96\x99\x83\xbd\x5a\xe1\xeb\xf6\x57\x8d\x7f\xf3\xce\xff\x32\x0e\x25\x56\x21\x99\xde\xe9\x34\x75\x7c\xc1\xf5\x8d\x55\x40\xc4\x1a\xac\x1c\xe4\xf2\x11\xf0\xb8\xec\x41\x07\x17\x40\x30\xe7\x02\xbc\x6a\x8a\x9c\x85\xc5\x05\xc9\x31\x6a\xef\xea\x3e\x43\x72\x24\x2d\xe0\x19\xb3\x5e\x2b\xd3\xc5\xa9\x56\x52\x19\x71\xc1\x06\xa3\xad\xbb\xc1\x3c\xdc\x4f\x7f\x9d\x3c\x58\xb9\x6a\x34\x4b\x4a\xc3\xef\x6b\xd8\xac\xa6\xed\x98\x76\xb4\x3e\x64\x97\xfa\xf7\xfa\x4c\xf2\x7f\xbc\xb6\x65\x73\x0c\x09\x1e\x13\xaa\xf7\xe9\xef\xe7\xdd\x10\xe1\x4e\xb1\x9a\x92\x00\x42\x42\x10\xec\x8b\x8f\xba\x7e\x69\x44\x4c\xe1\xa9\xe3\xa7\xb2\x6c\x11\xf6\xb7\x14\x5b\x69\x83\xa7\x80\x57\x76\x48\x40\x31\xbf\xf5\x2e\x81\xae\x76\x9b\x70\xa2\x82\xb0\x94\xff\xb5\xfb\x55\x25\xdc\x1a\x87\x2e\x20\x7e\x82\x7a\x2e\x11\xf4\xec\xf7\xb5\x30\x8c\x74\x8a\x92\x78\xea\x7b\xd6\x61\x88\x19\x44\x00\x43\x0c\x8c\xd5\x96\xeb\xb8\x72\x21\xe5\x36\xf6\xaf\xe1\xf1\x50\x5d\x6a\x59\xf4\x1d\x16\xa2\xf0\x14\xe1\xcf\xa5\x13\xf7\xa6\x97\x31\xd7\xbf\xdb\x2a\xff\xce\xfe\x05\x37\xd4\x2c\x79\x6e\x3f\xd2\x7e\x41\xb7\xca\x72\x05\x1b\xef\x28\xbb\x7b\xde\x70\x10\xdc\xfe\xd8\xaa\x16\xef\x67\x6d\xb6\xe5\x20\xc3\xce\xf8\xd6\xf5\x8a\x9a\x28\x13\xcf\xf0\xf7\x04\x1f\x87\xfb\xfb\x84\x31\xe0\x20\xed\xe1\xd4\xea\xf1\x9e\x23\xb9\x83\x44\x5c\x59\x15\xb5\x4a\xdf\xb5\x57\xfc\x20\xd0\x05\x8f\x40\xf5\xe0\x98\x25\xdb\xa8\xd8\xf2\x0c\x00\xf4\x3b\x3a\xee\xbb\x61\x57\xbe\x32\xec\x54\x62\x7d\x5d\x42\xab\x81\x3c\xf9\x7f\x09\x5d\x26\xdb\x80\x36\xc1\x2e\x82\xcb\x96\x3e\x80\x01\x16\x7e\x61\xab\x39\x3b\x4c\xca\x75\x5e\xce\xa8\x69\x95\x4e\x32\x3f\xa5\x26\x2c\x5f\xda\x3e\x0b\xe9\xa5\x1e\x5a\xf5\x1f\xa6\x44\x48\x24\xfb\x83\x7c\xc6\x7b\xe5\x37\xa8\x75\x69\xc3\x0c\xf0\x11\x4d\x39\xa0\x39\x42\xde\x4e\x1c\xd5\x23\x35\x5d\xab\x1a\xf3\x60\x80\xa9\xa9\xa5\x48\xbe\x1c\x2a\x7f\xbe\x54\x33\x77\x23\x15\xd2\x83\xe5\x15\x6d\xf6\x48\xbe\xe4\xb7\xdc\xda\x74\xf1\x59\x05\xd5\x42\xbe\x54\x87\x3c\x15\xc5\x3f\xf4\x2a\xca\xbf\x8c\x56\xf2\x57\xd7\x64\x72\x2d\xb4\xe9\xc7\x18\xe1\x20\x98\xa3\x45\x74\x86\xa6\xc9\x47\xac\x2d\xe0\xaf\x53\xe8\x2c\xf9\x50\xbb\x37\xca\x29\xc8\xda\xdf\xa3\x64\x6d\xb4\x98\x2a\xf5\x72\xd3\x9b\x26\x8c\x7f\x96\xb0\x3e\xf6\xb6\x53\xc8\x79\x45\xf2\x9b\xc5"}, -{{0x55,0x32,0x8b,0xe4,0xb3,0x70,0x82,0x27,0x33,0xff,0x39,0x89,0xa6,0xa3,0x28,0x2d,0x65,0xfe,0x8f,0x20,0x7a,0xb7,0x27,0x0d,0x7c,0x2e,0x72,0x7c,0xa3,0xcf,0xaa,0xc4,},{0x51,0x8e,0x02,0xee,0xf5,0x2f,0x5a,0xae,0xbd,0xe3,0xd1,0x08,0xea,0x79,0xec,0xad,0xfc,0x4d,0x99,0x4c,0xe1,0x95,0x36,0x21,0xe5,0x4b,0x7b,0x3b,0x12,0x1f,0xf8,0xff,},{0xf5,0x8d,0xb1,0x9f,0xd8,0x34,0xe1,0x51,0x94,0xc3,0xc0,0xf8,0xa6,0xa5,0x0e,0xbc,0x4c,0xf0,0x74,0xe8,0x0e,0xa2,0xe7,0x0c,0xda,0xf1,0xe1,0x69,0xbd,0x51,0xeb,0xd0,0x99,0x0b,0xad,0x77,0xc4,0xfa,0x20,0x8b,0x8d,0xd1,0xe2,0xc8,0x57,0x4c,0x01,0xb5,0xf5,0x96,0xc8,0xdf,0xa6,0xbb,0x8e,0x6a,0xe3,0xa4,0x7f,0xf4,0x12,0xe7,0xe2,0x09,},"\x6c\x24\xc9\xaf\xbb\xf1\x2d\xca\xee\x6f\x10\xe4\x08\x92\x52\xf2\xc6\x0b\x2a\xb9\x3a\x02\xc1\x60\x2f\xb5\xde\x4c\xe3\xbd\x92\x3e\xb0\x2f\xe1\x03\x9f\xdc\x15\x99\x6a\x44\x69\x15\xe7\x67\xde\xe0\x17\x6d\xdd\xb7\x8e\x9d\x6b\xbf\x06\x96\x75\x77\x5a\x82\x9d\xd8\x08\xd3\x76\xb0\xcf\x79\x20\xbf\x1a\x66\xe1\x30\x3b\xa5\x24\x19\x78\x5f\x25\xf2\x8b\xb3\x38\x99\xeb\xde\x84\x0c\x0a\xb1\x4b\x91\x9a\x65\x80\xcb\xaa\xc3\xa8\x05\x62\x7b\x9c\x4a\x77\xba\xa1\x6f\x82\x5a\x9e\xac\x2d\x6d\x36\x41\x65\x14\x93\x37\x0e\x50\xee\xe9\x4c\x74\x04\x97\x64\x36\x56\x05\xab\x4d\xac\x1a\x03\x02\x27\xa3\x30\xaa\x17\x8f\x2f\x8d\xa3\x77\xaf\x73\xf0\xbb\x04\x0b\xac\x12\x36\x6e\x65\xe0\x59\x10\x55\xf9\xf2\x3e\xac\xa3\x5e\x96\x88\xd8\x37\xa3\xc0\xd9\x9c\x16\x8f\xd8\x86\xac\xc9\x22\xcf\x37\xa7\x11\x8e\xf8\xa4\x4b\xb0\xa4\xfa\x42\x88\x04\x93\x09\xa7\xdc\x1b\xed\x80\x62\x1e\x10\x63\xe3\xe5\x92\xc0\xfb\xa4\x2d\x73\x98\xeb\x15\xf7\x40\x28\xac\x15\xd7\xed\x65\xa6\x36\x8a\x13\xb7\xf9\x56\xd1\x95\x47\xeb\x50\x6c\xe7\xec\x90\x73\x4e\xb9\x49\xcf\xf1\xd9\x8c\xe4\x14\xf1\x0a\xdc\xba\x8c\x00\x73\x20\x01\x87\x50\xa7\x1b\xd3\x6d\x3b\x6b\xfd\x61\x27\x05\x45\x08\xe3\xef\x65\xd9\x98\x48\x51\x4d\x33\xd6\x8b\x58\xe3\xa4\xb2\x24\xf7\x9b\x6e\x34\xdd\x48\x03\x40\x46\x7f\xe7\xf0\x25\xcc\x88\x21\x3d\x80\x8f\xbb\x5b\x91\xe2\xe4\x3c\xf9\xd9\x50\x64\x07\x98\x65\x92\x73\xd4\x7a\x25\xf1\xf0\x13\x2f\x68\x82\xfa\xad\xba\xfb\xa2\x8f\xee\x5f\xa1\x72\x72\xc1\xa9\x00\x11\x72\xb3\xab\x6f\xf2\xc3\x15\xf2\x6c\x07\x73\x44\x05\xb5\xee\x8b\x5e\x4f\x08\xe1\xe3\xb8\xae\xa0\x19\x46\x7f\xb0\x71\x88\x7f\x19\x19\x01\xa2\x1c\x59\x76\xc1\xca\x8a\xaf\x0a\x1d\x4a\x2e\x69\x8e\x76\x23\xe9\xbb\xe9\xca\x2a\x67\xa1\x53\xa1\x6f\x89\x5e\x6d\xd9\xea\x92\x44\x41\xb4\xbd\x0b\x67\x45\x52\xe3\x98\xb8\xd9\x70\x34\x3a\x9b\xc7\x76\xa3\xa3\xfc\x1a\x86\x60\xc5\x62\x5d\x60\x81\xb5\xd8\x7f\x0f\x8a\xc9\xf0\x7a\xb5\xab\xe7\x7c\xdb\x8e\x30\xd2\xfd\x1f\x6f\x46\x52\x5c\x75\xdd\x0d\xd1\xca\x32\x81\xcc\x89\x34\x6f\xb3\xe6\xd7\x38\x8e\xbe\xe1\x54\xcb\x59\xbd\x9e\x95\xed\x6a\x41\xd5\xdf\x66\x8b\x59\xea\x13\x78\x68\xeb\x12\x0b\x8a\x2c\xfd\xf4\x67\x44\x14\xfd\x27\x96\x99\xf2\x8b\x5a\x5c\xcc\x2e\x2f\xc8\x02\xa4\xc9\xe0\xb8\x5b\x76\xf2\x0f\x6b\xce\x2a\x49\x54\x88\x6f\xc4\x02\x67\x0a\x71\xef\xd2\x61\xf5\xdd\x7b\xca\x16\x88\x4a\x28\x7c\x62\x2f\xd4\x45\xf6\x8d\x44\x15\x1c\xc0\x13\x4b\x22\x9d\xa3\x8d\xaa\xab\x81\xb5\xc9\x60\xd5\x77\x00\xca\x92\xb2\x6d\x0b\x14\x21\x34\xce\x94\xb7\xbe\x6c\x18\x61\x0e\xa2\x13\x6f\x8b\xa8\x32\x9a\x2e\x8c\x00\x0b\x8f\x02\xfe\x05\xbc\xf7\x2c\xb7\x1f\x8c\x72\x53\x5f\xfc\xd8\x18\xe3\x8e\x79\x92\xa8\xf0\xc3\x2a\xc6\x21\x77\xd1\x52\x2a\xe5\x52\xc6\x0c\x1e\xe6\x16\xb7\x5e\x4b\x34\x42\xe7\x96\x57\xe4\xa3\x33\xc0\xb3\xd7\x44\xea\xf2\x60\xd0\xc3\x36\x93\x16\x86\xa6\xd6\x68\xc6\x4f\xef\x44\x00\x52\x35\x2c\x2b\x25\x8c\xfb\x65"}, -{{0x7d,0xa0,0x5f,0x04,0xe5,0xd3,0x8b,0x98,0x9b,0x83,0xf7,0x2f,0x7a,0xb2,0x6c,0x13,0x87,0x76,0x75,0x8f,0x4f,0x57,0x7e,0x49,0xdc,0x73,0xd6,0x01,0x3f,0xf4,0x37,0x59,},{0xb1,0xde,0x51,0x67,0xf4,0xd3,0x30,0x80,0x4e,0xec,0x9e,0xb5,0x65,0xef,0x40,0x55,0xf1,0xb6,0x4d,0xd9,0x5e,0x1c,0x9b,0x27,0xc6,0x7f,0xfe,0xf9,0x14,0x82,0xcc,0xa8,},{0x05,0xf1,0x17,0xf9,0xbc,0x3e,0xa5,0x5d,0x45,0x5e,0x9e,0xf1,0x35,0xe9,0x2e,0x76,0x65,0xd1,0x80,0x70,0xd8,0xf5,0xe3,0x75,0xdf,0x67,0xbe,0x18,0x17,0xce,0x14,0x35,0x7a,0x55,0xe7,0x01,0x66,0xf3,0x26,0xb7,0x7d,0x85,0x24,0x32,0x27,0xcf,0x67,0xd8,0xf2,0xe0,0xbf,0x84,0x40,0xca,0xbf,0xb0,0x52,0x75,0xb3,0x73,0xf1,0xe1,0x19,0x0e,},"\xa6\xa8\x61\xd8\x94\x7c\x5c\xd6\xad\x08\x19\x60\x2e\x32\xea\x76\x81\xc8\xf7\x30\x10\xee\xe5\x53\xe5\xde\xfb\xf7\x98\x20\x98\xb5\xf7\xb3\x99\x24\xbb\x79\x59\xad\x64\xc3\x03\x26\xbe\xd5\x60\xbf\x51\xe9\x98\x3c\xda\x5d\xff\x4f\x31\x1e\xea\x24\xcb\xe6\x8c\x61\x06\xce\xac\x9b\x84\x3a\xa4\xe2\xad\x1b\x6f\x8a\xe1\xe4\xf9\x68\x71\xfc\x02\x5b\xe4\xa6\x16\x38\x5f\xf2\xd4\xb7\xf5\x68\x29\xab\xef\xaf\x6a\xac\xbb\x78\x0d\x6c\xbb\xc9\x51\xb6\xe0\x5a\x78\x7f\x88\x5e\x33\x25\x61\x16\x65\xec\xc9\x24\x27\x4a\xa5\x31\xbc\x13\x3f\x62\xc7\x6c\xb3\xad\x14\x8f\x3c\x95\x79\xa8\x15\xa1\x42\x00\xb7\x64\x8d\xae\x0b\x07\xb3\x27\xd3\xbf\xcc\xdb\x6f\xe3\xb6\xcb\xd7\x0e\xa6\x5e\x6c\x0c\xc2\x51\x6a\x89\x66\x96\xd0\x7b\x2e\x77\x71\x3b\x0b\xee\x3b\x92\xfb\x1b\x6f\x75\xb0\x82\x0a\x5c\xb6\x2c\x5f\xe6\x20\x40\x03\x94\x3e\x24\x85\x71\x66\xfb\xdf\x57\x1f\x11\x5d\x45\xf4\x2e\x75\x90\x1d\xf8\xb1\x2c\x32\x61\x8a\xac\xb0\xd2\x42\x86\xc8\xd3\x03\x96\x05\x1f\xc2\x72\xaa\x17\xf4\xd2\xd4\x74\x61\x15\x2a\xac\xd3\xfa\xa2\xb7\xb2\x08\x31\x22\x78\xe8\x09\x24\x05\x92\xd1\xd1\xaa\x58\x5c\x56\x28\x0e\x66\xff\xd9\x2b\x57\x17\xd0\xcd\x1e\xb9\xfb\x74\x01\xde\xf8\x79\x48\x7c\x37\x4e\x5c\x53\x0b\x6f\xeb\xf9\x11\x12\x25\x74\xd2\x4f\xe1\x04\xb4\xf4\x5c\x7c\x60\x1e\x6c\x91\x7d\x3c\x18\x82\xc1\xad\x3c\x55\x5d\x8f\x2c\xe9\x55\xb5\xa1\x0d\xb0\xd5\xa8\xb8\xac\x7a\x62\x66\xb2\xe6\xb2\x7a\xd0\xee\x34\xf4\x7a\xd8\x57\x36\x7d\x52\xf7\x09\x6d\x4b\xac\xef\x0e\x46\x72\x54\x88\x42\x4b\x93\xb8\x9a\xcd\x42\x9f\xfb\x5e\xf3\x3a\x0b\x08\x1d\xd0\x94\x79\x67\x91\x96\x02\x3c\x39\x67\xf4\x4a\xd4\x1e\xb1\xa2\x39\x55\x27\xfd\x3b\x79\x76\x8f\x1b\x88\x5f\x04\x29\xb4\x95\xab\x60\x52\x56\x91\xbe\x84\x65\x06\x32\xa2\xf6\x6c\xb6\x3a\xd5\xbf\x2f\x6a\xe7\x0b\x66\x8c\x5a\x19\x3f\x74\x99\xfc\x4f\xc4\x2c\xf8\xcb\x30\x8c\xe5\x02\x9a\x50\x27\xba\xbe\xf5\x5d\x19\x25\xec\xfb\xa9\xf2\x7e\xb6\x08\x16\x19\xed\x0d\xf8\x56\x9f\xd8\x0e\x9d\xa1\x04\xdb\x39\xb5\xb8\x14\x0b\xfe\xbe\xbd\x29\x08\x54\x40\x06\x58\x19\xde\xba\x8d\x46\x9a\xe8\xb3\xea\x6d\x3b\xac\x58\x91\xf9\xa4\xdd\xfb\x7f\x1f\x06\xd1\x3c\x31\xa0\x7e\xe5\x3f\xb5\x4b\xc9\x7b\xd0\x86\x96\x39\x4c\x38\xe7\xf3\x68\x0c\x0f\x02\xf9\x75\xf4\x69\x92\x11\x47\xa4\x09\x85\x90\x97\x81\x3b\x4c\x3f\xa4\x3d\x17\x4a\xc4\x02\xf1\xa5\x28\xcb\x5f\xc4\xb8\x07\x51\x84\x32\xef\xf3\x34\x07\xa1\x11\xca\x3a\x3d\x7e\x9e\x84\x13\x5a\xba\xc8\xa8\xf5\x2e\xa6\x31\xc8\x6d\x74\xa1\xc6\xe5\x74\x9e\xdd\x14\x91\xc0\x02\x4e\x7d\xe7\xfe\x52\x85\x68\x29\xb7\x2f\xd1\x3d\xa6\x3a\x1a\x23\x43\x34\x9d\xf6\x62\xab\x31\x63\x53\x60\x32\x34\x6e\x53\x47\xf0\x43\xff\xf5\x28\xbf\x67\x15\x09\x22\xff\xf2\x02\x6b\xab\x74\x2d\xb9\xca\xe7\xcb\x2e\x3c\x74\x58\x07\x19\x65\x2c\x28\x44\x7c\x5e\x20\x98\x23\x17\x97\xee\x6e\xf1\x23\x1f\x57\x92\x05\x4b\xc3\x35\x9a\x32\xc8\x6d\x2f\x94\xf8\x5f\xa7\xd4\xa7\x41\x9d\xd2\x41\xff\x66\x2a"}, -{{0x1b,0x8e,0xc6,0x58,0x80,0xed,0xbf,0x03,0x9a,0x13,0xe9,0x70,0xb1,0x5a,0xa6,0x7e,0x19,0x2a,0xa0,0x2c,0xa6,0x5c,0xff,0x9a,0xda,0x17,0xd4,0x55,0x8f,0x40,0x13,0x7d,},{0x12,0xc1,0x19,0x1e,0x4d,0xe3,0xbd,0x44,0xd0,0x39,0x07,0x01,0x53,0xad,0xb7,0xb5,0x81,0xf6,0x00,0xe9,0xa1,0xdd,0x69,0xaa,0x89,0xf2,0x77,0xc7,0x06,0x9e,0x76,0xf8,},{0xbf,0xf2,0x69,0xa3,0x5d,0x6c,0x8e,0x55,0x2c,0xe7,0x16,0xd1,0x63,0x81,0x81,0xce,0x85,0x83,0xb4,0x5c,0x0e,0xc5,0x93,0xb4,0xe5,0x8c,0x40,0xac,0x76,0xe7,0xf8,0x5c,0xa1,0xda,0xff,0xfd,0x68,0x54,0x1e,0x62,0x3a,0x1e,0x35,0xa7,0xc0,0x97,0x26,0x88,0xb2,0x5e,0xed,0x72,0xf4,0xda,0x57,0xec,0xa1,0x68,0x57,0xa8,0x26,0x3c,0xaa,0x0b,},"\x37\xf1\x8b\x7f\x64\xc5\x13\x34\x79\xd6\xda\xe3\xbe\xf6\x79\xcd\xc2\x1e\xce\x3f\x5b\x57\x9a\x6a\x9c\x3f\xa2\xe5\x9e\x9b\xe8\x7d\x20\x09\xf7\x4e\x1c\xfd\xac\xcb\x1c\xe3\x7d\x00\x70\x23\x69\xbd\x16\x9d\x94\xfd\xcf\x85\xaf\x9f\xa3\x21\x7d\x27\xe6\xed\x6d\x1d\x8e\x5d\xf7\x61\x5e\x8e\x37\xea\x55\xde\x1f\xd0\xb0\x6d\x77\xb4\xc8\x3b\x92\x9d\x80\x58\x6f\xa0\x69\x4b\xe7\x2e\xc8\xb3\x65\xad\x2c\xbc\xdd\x2b\x1a\xd8\xcf\x7f\x03\x6d\xfa\x4d\xaa\x1a\x90\x36\xcd\xb1\x20\x43\x22\x27\xb1\xf0\x7b\x88\x66\xb1\x22\x12\x03\x09\xeb\x91\x4a\xb8\x4c\xdd\xeb\xa1\xde\xc4\x8a\xb9\x26\x36\x72\x85\x88\xfe\xdb\x3a\xaa\xd7\xe7\xdb\xb2\xac\x30\xe6\x3c\x6f\x5f\x90\xfc\x6c\xe6\x2d\x6d\x3b\xd8\x8b\x0d\x5a\xac\xfa\x61\xde\x9f\x32\x67\xb3\x00\x91\x7b\x57\xa4\x80\x36\xab\x20\xc9\xa0\x54\x46\xb8\x76\x74\x94\xaf\x24\x9e\x7d\xe7\xbc\x50\x7a\x22\x07\xcc\x95\x6f\x71\x84\x55\x5a\x7d\x5d\x88\x83\xbb\x4b\x3e\x93\xf2\xdc\xfc\x57\xb0\xda\x86\x38\x65\x8d\xcd\xce\x88\x5d\x44\xd9\xcc\x68\xb1\xd8\x17\x0a\x36\x77\xcc\x5e\x50\xcb\xf3\x3d\x54\x3e\xba\xe4\x47\x7d\x92\x39\xcf\x83\x38\x4e\xc5\x9b\x42\x33\xe8\xff\x33\x43\xf0\x6f\x30\x18\x77\x72\x9a\x53\xd4\x20\xbf\x01\xc6\x2e\x66\xab\x7f\xe5\x5d\xd8\x7e\xe8\x23\xa5\x8f\xcb\x87\x87\x0e\x1f\x52\xe8\x79\x17\x7c\xd4\x39\xc5\x33\xf5\xa2\x23\xe5\xa3\x43\x6f\xe9\xd6\x42\x65\x48\xda\xcf\xc8\x6a\x08\x46\xd3\xed\x23\xac\x04\x25\x63\xe8\x87\xff\x46\xaa\xd0\x05\xf4\xe1\xde\xe3\xee\x0e\xe4\xc2\x7a\x72\x51\x70\x9a\xe4\x0a\xbc\x5e\x25\x68\x64\xe4\x78\x5a\x4e\xdd\x8b\x2a\xdf\x1b\xc5\xb4\x01\x8e\x28\xd0\xb1\x75\x86\x7b\x02\xd0\x52\xa6\xe1\x7e\x41\x1a\x3d\x8b\xeb\x2a\x42\x08\xb7\x6c\xc6\x21\xfd\x18\xbe\x14\x8e\x23\x5d\x55\xaa\x71\x27\x70\x65\x57\xde\xc0\x53\xa1\x3f\x1a\x47\xdf\xda\x40\x5b\x3f\xe5\xbd\x28\xef\x5d\x34\x86\x19\xf5\x1e\x59\x5e\xf5\x05\x5f\x83\x9e\xfa\xf1\x10\xe4\x90\x16\x31\xac\x31\xa0\x2f\x4f\x7e\xe4\x24\xa3\xa2\xc3\xe0\x0d\x26\x02\xd2\xcc\x1e\x49\x29\x06\xee\xa4\x20\xa9\x26\x82\x38\xac\x66\x22\xa0\x89\x74\xe5\x73\x02\x92\xe6\xed\x51\x02\x56\xef\xde\x66\x7e\x0d\x9a\x0f\xf2\x21\x3f\x54\x12\x0c\xcd\x81\xff\xaa\x6b\x7c\xc4\x81\x41\xa2\xb7\x29\x85\x2a\xf5\x83\xd2\x6a\xa5\x1f\xbd\xe6\x7b\xe4\xdf\x14\xe5\x20\xc2\x25\x7a\x73\xc5\xc2\xe3\xc3\xd8\x7d\xfb\x25\x36\x11\x75\xfd\x18\xab\xd7\xe9\x9a\xa0\x9b\x85\xf8\x8f\x19\xc8\xd8\x2d\x45\x85\x8f\x31\x44\xc5\xdf\xb7\xa4\x9e\xde\x45\xb4\xef\xd8\x71\x05\x92\xa3\x72\x06\x36\xe7\xe8\x89\xc7\xe2\x2a\xd1\x3b\x2d\x44\xbb\x7e\x2b\x47\xb2\x96\x3a\x5f\xa3\xf2\x55\x7b\x85\xbc\x0c\x69\x3d\xe3\xd2\x2e\xf9\x46\x4f\x7b\x81\x4a\x20\xa4\x67\x6a\xd2\x6f\xca\xa0\x35\x44\xc6\xaa\xd4\x12\x83\x09\x5f\xcd\x12\x10\xaa\x8c\xc0\x29\xff\x5a\x26\x00\x5a\x89\x12\x26\xc2\x98\xe9\x4a\x52\xaa\x71\x33\x91\x3e\xc9\xd2\x2a\x5b\x2a\xc0\xbc\x6f\x15\xb2\x51\xd0\xb9\x38\x89\x21\x3c\xd1\xb1\xe5\xc6\xfd\x08\xf1\xa8\xf5\xcb\xd4\x21\x53\x29\xa3"}, -{{0xe7,0x53,0x88,0x02,0x6a,0x6a,0x6d,0x6c,0x6d,0x19,0x9e,0x36,0x29,0x93,0xa5,0xb1,0x04,0x49,0x01,0xe1,0x8a,0x76,0xc2,0xfa,0xc7,0x26,0x1a,0x6d,0x1c,0x19,0xa4,0xf3,},{0xb9,0xce,0x14,0x25,0x1c,0x0c,0xdf,0x3b,0xdd,0xb2,0x06,0xdc,0x6b,0x8b,0x2b,0x7f,0x5b,0x7e,0x4d,0xd1,0xbe,0x2c,0xe1,0x86,0x3f,0xf1,0x88,0x06,0xae,0x00,0xf1,0xee,},{0x6d,0x0f,0x83,0xd9,0xc5,0x5d,0x84,0xbc,0xf9,0xa8,0x61,0x47,0xd9,0xb6,0xba,0x9a,0xd5,0x37,0x83,0x2f,0xd0,0xf9,0x9d,0xae,0x7e,0x72,0xc8,0x13,0x9a,0xfc,0xb3,0x0c,0x7b,0x24,0xf6,0xb2,0x92,0xe3,0x2f,0x98,0x47,0x09,0x75,0x51,0xb7,0xfb,0xfd,0x51,0x0c,0x84,0xe8,0x9b,0xe9,0x82,0x54,0x44,0x14,0x57,0xbd,0x08,0xe5,0xf0,0x53,0x02,},"\xb9\x9c\xdc\x84\x72\x11\xc0\x66\x42\xdd\x11\x1b\xc5\xe0\xbe\xca\x53\xa7\x4f\xfb\xa2\xe3\xac\x93\xaf\xb4\xb0\x94\x75\x18\xe8\x32\x35\x27\x33\x0a\x4e\xfe\xfb\xe4\xba\xfa\x00\xba\xfe\xcb\x43\x4a\xb1\xe5\xb7\xce\x65\x65\x6f\x7a\x4f\xd8\x56\xaa\x6c\x38\x5e\xd8\xd7\xbd\x62\x85\x58\x0d\x7d\xd6\x08\x82\xe6\x9c\x19\xda\x07\x69\x09\xd6\x47\xde\x09\x5a\x80\xe9\x8a\xd8\x9b\x81\x4a\xad\xcb\xbf\x6f\x03\x3c\x49\x20\x2f\x65\x6c\x09\x10\x50\x39\x59\xcf\x97\xcd\x0f\xa8\x2d\x5f\x6d\x22\xfb\xa3\x38\x99\x51\x29\x4c\x4f\x7c\xdc\x21\xeb\x82\x44\xbd\x65\x60\x63\x7a\x5e\xca\x62\xa8\xeb\xa1\xf4\xa9\x33\xd1\x87\xa7\x5f\x86\x71\x16\x43\xaf\x35\x88\x31\xc8\xc1\x6a\x9a\x0f\x09\xe2\x53\xb2\x39\x5e\x9c\xb3\x71\x61\x1e\xec\xdd\x66\xb4\xab\x52\x1a\xa9\x4b\x3f\x20\x23\x7e\xae\x41\xcd\x10\xc5\xe2\x1a\x45\x2d\x48\xe7\x48\x18\x7f\x35\x4a\x67\xad\xf6\x81\xb0\xfe\x61\xcd\xae\xc9\x4a\x5e\xaf\x01\x26\x9f\xce\xb5\x70\xd5\x14\xff\x3c\x55\xff\x1d\xba\x2f\xd2\xdf\x17\xf8\x6a\x8a\xeb\x74\x78\x38\x11\x3d\xee\x94\xa4\x3b\x13\x84\xcb\xe1\x33\xcd\xf6\x42\x7e\x8d\x12\x2e\x4e\x93\x37\x04\xda\x6e\x26\xcf\xce\xe9\x7f\xe3\xf6\x29\xb6\x0b\x91\xb2\xdd\x86\x38\x67\xfa\x79\x80\x1e\x2b\x91\x6e\xc4\xc0\xfb\x62\xe0\x71\x59\x42\x1e\x65\x79\x74\x30\x7a\x1d\x02\xf7\xf2\xed\x47\x24\xa8\xb5\x21\xa8\x61\xf5\x5f\x35\x52\x1e\x8b\x2e\x1a\x84\x90\x4c\x42\x8c\xfc\x5b\x60\x14\xbb\x0f\x8b\xa8\x43\x4c\x22\x09\xbd\x40\xac\xa3\x11\x30\xdb\x97\x74\x33\x33\x59\x7d\x23\x51\xd5\xf6\x81\x17\x41\xf6\x26\x88\x97\x3b\xd7\x73\xd3\x02\x66\xfd\x1e\xfb\xd8\x9d\x47\xa9\x64\xf9\xd0\x19\x97\x15\x3d\x08\x7d\x92\x69\x66\x16\xdd\x10\x3a\x93\x4c\xcb\xac\x4c\x1d\x14\x2f\x20\x75\xd4\xe2\x2c\x3d\xa4\xa0\xe9\x73\xb2\x38\x63\x19\x62\x87\xb7\x91\x74\xfa\x29\x75\x5f\xc6\xd9\xb5\xe1\x00\xac\xe0\xa4\x59\x75\xe5\x03\xb2\x54\xd3\xf1\x95\xc2\x61\x71\x09\x10\xfe\xf1\x06\x89\x2c\x08\xbb\x29\x6d\x23\x0c\xde\xa9\xf5\xa1\x1f\x91\xac\xaa\x6e\x7c\x05\xe9\x2c\x28\x1d\x2b\x31\x55\xfe\x44\x80\xb0\xaa\x5e\x0d\xb4\x1d\x10\xe0\x5c\xfd\xef\xa4\x36\x40\x51\xcb\x75\x5d\xc7\x2f\xfa\x97\x8c\x00\xb9\x4a\x5f\x21\x2d\xc6\x91\xf8\x39\xb4\x9d\xe9\x7e\x01\x39\xd6\x5e\x8d\x73\xb2\xb2\x89\xb2\x6a\x12\xc6\xcc\xd8\xed\xc0\x4a\xdb\x45\x2a\xf7\xff\x09\x4a\xa9\x01\xea\xf5\x76\x51\xeb\x1b\x87\xb8\x33\xd0\xa0\x9b\x4a\x4a\x64\x62\xf4\x06\x64\x62\x37\x69\xe9\x50\x79\xf3\xc9\x62\x85\x0c\xc3\xb4\x01\xbb\x00\x58\xb8\x47\x5b\x10\xc8\x62\xf3\x2f\x30\x0a\x2b\x14\x3b\x3d\xea\x26\x9d\xdc\xbe\xa7\xbe\x7d\xd2\x42\x6d\x0d\x42\x04\xeb\x66\xa3\x9f\x13\x18\x82\x2d\xcb\x9c\x56\x13\x98\x63\x7f\x4a\xb8\xde\x19\x67\x68\xac\xe7\x4f\x34\x8c\x01\x2d\xd1\xba\xbe\xc1\x7f\x53\x00\xff\xe0\xd7\xaa\xae\xaf\xef\x7d\xb6\x50\xa8\xf2\xf3\x09\xa9\x79\x3f\x52\xc6\x85\xc7\xe1\xd5\x13\x32\x74\x91\x57\x84\x89\x9c\x48\x1d\x48\x5c\x9b\xd3\x0e\x99\xfc\xdc\x97\xd9\x6e\xf0\x74\x87\xda\x66\x3b\xef\xe6\x82\x99\xdf"}, -{{0x5b,0x32,0x3f,0xc0,0x1a,0x16,0xc4,0x5d,0x10,0x64,0x66,0x7d,0x2e,0xa4,0xa7,0xea,0x59,0xd2,0x03,0x42,0x56,0x2d,0x12,0xfb,0xc5,0x98,0xd5,0xaa,0x73,0x00,0x68,0x8e,},{0xd4,0x14,0x1b,0x45,0x5d,0x30,0x16,0x42,0xba,0xda,0x28,0x14,0xaf,0xcb,0x16,0x20,0xd5,0xeb,0x56,0xd9,0x2b,0x11,0x85,0xfe,0x5d,0xad,0xef,0x55,0x96,0x25,0xfa,0x71,},{0xe2,0xef,0xf6,0x07,0xf0,0x22,0x7a,0x29,0xd5,0x82,0xd6,0x9f,0x34,0x58,0xac,0xad,0xd3,0x22,0x6f,0xce,0xaa,0xc0,0xab,0xbd,0xae,0xd5,0x26,0x75,0xc5,0x16,0x30,0x07,0x3c,0xd3,0xa9,0x01,0x70,0x7e,0xcf,0x05,0xe8,0x93,0xf2,0xc3,0x6d,0xaa,0xf0,0xcc,0x49,0x01,0x11,0x69,0x46,0xb5,0x77,0x0d,0xc0,0x38,0x12,0x5f,0x6d,0x13,0x1b,0x09,},"\xad\x24\x66\x9e\xf5\x5c\x54\x0a\x8e\xd1\x62\xce\x1d\x28\xf0\x17\x60\xa6\x07\x19\xa0\x37\x73\x36\xeb\x00\xb1\xec\xbe\x6f\x61\x60\x1c\xd5\x64\xf9\x2c\x95\x68\x04\xf9\xbe\xd4\xe1\x47\x6b\x94\xe5\xea\x8c\xca\x80\xcb\x49\xa3\x04\xef\x85\x1f\x7f\x67\x5a\xbe\x58\xe6\x68\x1d\xc0\x12\xad\x55\xe5\x1b\x02\x1d\x98\x28\x56\x9d\x0b\xcc\x9e\x05\x27\xa3\xfc\x03\xc8\x91\xd1\x7a\x90\xe6\x33\x7a\x1e\xa6\x7f\x2f\x08\x81\x05\x87\x69\x38\x37\x08\x1e\x4c\x08\xa3\xd7\x2c\x53\x6c\x21\x40\xda\x20\x0b\xa4\x56\xc3\x76\xf6\x1d\x05\x65\x1f\x0c\x5f\x39\x57\x11\xf4\x1c\x0d\x6e\xae\x98\xc9\x06\x76\x4d\x1e\xbe\xf3\xf9\x04\x6c\xb7\xc8\x62\x26\x40\xfc\xaf\xaf\xbf\xb8\xf6\x2e\x1c\xd3\x2c\x66\xee\x1c\x55\x50\x94\x89\xa5\x38\xab\x61\x29\x99\xe7\x99\x7b\x77\x9c\x64\x22\xef\xf1\x09\xda\x4d\xf8\x29\x20\x93\x0d\x8d\x36\x3d\x78\x30\x90\x87\x95\xa3\x88\x8f\x25\xd6\x67\xe1\x4d\x15\x5e\xd4\x45\x81\xbe\x43\x0f\x79\x73\xb5\x74\xe2\xbc\x0b\x13\x4c\xf1\x39\xfb\x4b\xb0\x1d\xbd\xa4\x1b\x67\xb9\x81\x47\xd8\x01\x2f\x40\x67\x7f\x4b\x80\xce\x4a\x53\x4c\x90\xad\xea\xbf\x48\x4b\x21\xfa\x99\x4b\x7a\x17\x5f\x8a\x8b\x8a\x40\x75\x56\x44\x78\xdd\xb0\x50\x24\x58\x0b\xab\x03\x8c\xd9\xea\xa1\xdf\xda\x55\x2f\xb3\x12\x29\x42\x9b\x61\x4f\xa1\xd8\x0c\x52\x61\x4e\x84\xfa\xa2\x21\x7f\x26\x0f\xf7\xcc\xea\x8c\x7b\x06\xe3\xd7\x7f\xf8\x74\xeb\x81\xfc\x85\x97\xe5\xfc\xdc\xec\x95\x1b\x5f\xe6\x4a\x1a\xf8\x6e\x73\x19\x3a\x88\x24\x69\xeb\x3b\xa3\xc3\x82\x73\x4b\x28\x87\xb4\x19\x31\x6e\xa4\x48\xaf\xc2\x82\x47\x8c\x25\xf7\xbc\xa1\x84\x29\xcb\xbf\xfd\x88\x71\x17\x7c\x5e\xcc\x7d\x8a\xa9\xa1\xb9\xec\x87\x19\x2d\x29\xa5\x25\x39\xc0\x81\xc3\x59\x33\x32\x44\x4c\xbe\x66\x87\x2c\xf3\xd0\xe1\x97\x29\x2b\x82\xb0\xbe\x5f\xcd\x85\x8c\xd6\xca\x48\xb5\x3e\xe5\xb6\x16\x41\xbc\xaa\xf3\x1d\x81\x9c\x7e\x1c\xed\xaf\x9e\xe6\xb0\x7e\x09\xca\xed\xfb\x30\xb9\x20\x4a\x1d\x4d\xdb\x70\x56\x0c\xbe\x1e\xb0\xc0\xec\x43\xf1\xd1\x78\x20\x1b\x29\x08\x19\xfc\xdc\x92\xc6\x3e\x0d\xb6\x0f\xb8\x7d\xff\x00\xe5\x12\x64\x8c\x89\x58\xa8\x47\xef\xc3\x63\x46\x07\x3f\x1a\x4f\x1f\x23\x17\x06\x0f\x1c\x54\x3e\x6f\x01\xb4\x24\x85\xbe\xeb\x56\xca\xb3\xba\xb2\x6e\x6a\x0c\xa6\x93\x58\x02\xc7\x62\xb7\x99\x15\x9e\x32\x0f\x36\xb5\xe8\x3d\x4a\xca\x89\x62\xaa\x2c\x3c\x2b\x7a\x38\x70\xe9\xe0\x47\x31\xf3\x94\x8c\xf9\x41\xe2\x1d\x50\x96\x4e\x5d\x63\x5a\x35\xa5\x3e\x29\x98\x11\xb8\xca\xdf\xcb\x44\x16\xc5\x75\x98\xa3\xfd\x05\x41\x09\x10\xdb\xc0\xea\x2c\x78\xfd\xb9\x25\x74\x99\x7d\x58\x79\x62\x79\xea\xaa\x78\xb3\x6d\xce\xf1\xc9\xa1\x29\xee\xff\x82\x39\x9a\x26\xd0\x08\xff\xa3\xbf\x04\x18\xff\x7d\x39\xb6\x42\x7f\x34\x18\x95\x02\x4d\x16\xe2\x2a\x0c\x62\xa8\x2b\xeb\xa2\xe2\xba\xc2\x3d\xee\x18\xcf\xcd\x5d\xb2\x39\x7f\x37\x8c\x53\x67\x30\x90\x82\xc4\x4e\xb4\x3c\xed\xc1\x52\x20\x25\x3a\x62\x32\x03\x99\x66\x5f\x71\x34\x9c\xc1\xb9\x44\xf5\x8c\x73\xa1\x0a\x0b\xbf\xd4\xca\xf1\x28\x91\xe3"}, -{{0xbe,0x1c,0x11,0x2f,0x78,0xcf,0x13,0xae,0xfc,0x5c,0xe7,0xe3,0x37,0x64,0xac,0xa4,0x48,0x1f,0x9f,0x88,0xb0,0x18,0xe1,0x22,0xdb,0x9f,0x8d,0xac,0x14,0x62,0x46,0x05,},{0xae,0x38,0x99,0x36,0xbb,0xf6,0xd1,0x6e,0x3c,0x1e,0xeb,0x64,0x74,0x29,0x89,0x70,0x86,0x6e,0x12,0xec,0x9c,0x1d,0x6a,0xea,0x2f,0xd9,0xdb,0x6b,0x56,0xaa,0x59,0xc4,},{0xf5,0xfc,0x5a,0xcb,0x17,0xe9,0x95,0x7e,0xa3,0x04,0xf1,0x23,0xb6,0x50,0xe1,0x44,0xc9,0xe4,0x37,0x72,0x83,0x50,0x9d,0x43,0x1d,0xa6,0xa2,0xbb,0xd5,0x27,0xbe,0xb3,0x82,0xc9,0xf5,0x87,0x45,0xa3,0xe5,0x6d,0xcc,0x65,0x5b,0xd2,0xeb,0xb7,0xae,0xef,0xc9,0x3e,0xdc,0x3f,0x20,0xd8,0xd3,0xc3,0x79,0x23,0x03,0x1e,0xec,0x0c,0xb4,0x07,},"\xd7\x7f\x9a\xee\xa0\xfe\x98\xed\x7f\xb7\x4d\x58\x2a\x40\x2b\xcb\x79\x31\x47\x4b\x4a\x95\xd5\x23\xf3\xfb\x76\x9f\xb7\x09\x7d\x2b\xe4\xc6\xec\x10\x52\x14\x01\x63\x22\x25\x53\xaa\x8f\x4f\x89\xe4\x21\x73\x00\x14\xec\x73\x46\x97\x20\xce\xa9\x67\xf8\x8b\x6a\x48\xd0\x2a\x2d\xdc\x1a\x12\x1f\xdf\xfb\x8a\xe1\x27\x73\x8e\x29\x3c\x4d\x6b\x1b\x74\xad\x03\x84\x4d\xe6\xbf\xe8\x21\x50\x6b\x3a\x7a\x81\xd1\x9c\x37\xa7\xf0\x1c\xa4\x81\x47\x12\x19\xef\xe2\xa7\xb9\x2c\x4b\xd2\xac\x07\x74\x3b\x49\x75\x69\x64\x41\x71\x4b\x84\xd6\x3c\x54\x9d\x7a\x6f\xb6\x1f\x16\xfb\xcd\xb7\x2b\x91\x4d\x78\x82\xd0\x91\xf9\x70\x6d\xa3\x8c\x1a\x81\xa1\xc6\xa4\x0f\xbe\xc0\xd8\xe2\x38\xb5\xd5\x6d\x46\x0e\x90\x9f\x85\x47\x9f\x7a\xd8\xb1\x19\xf3\x54\x55\xe3\x40\x10\xca\xa7\xe5\xd0\x1f\x38\xe3\x01\xad\x37\xe8\x00\x5f\x6e\xd2\x9e\x4a\x10\x2d\xb3\xf6\x1d\x84\x09\x3f\x78\xc4\x9a\x96\x48\xc9\x77\xbf\x4d\x5b\x68\x9f\x71\xf4\x06\xf8\xad\x7b\x9a\xeb\x1a\xe2\x21\x33\xa8\x4c\xe1\xb2\x78\xb2\xcd\xde\x46\x59\x01\xb2\x3a\x17\x9d\x07\x2a\x80\x87\x9d\x0a\x24\xd2\xaf\x19\x7b\x32\x2a\x07\xbf\x5d\x40\xee\xab\x3a\xf1\x21\x17\xf1\x30\x21\xdf\xc1\x68\x1a\xba\x5c\x08\x3f\x25\x96\xe3\x7f\x11\x23\x42\x2b\xbd\xca\x3b\x2c\x32\xcb\x59\x4f\x56\xc3\x25\xe0\xc5\x64\xa1\x73\x32\x88\x05\x34\x59\xc6\x24\x88\x92\x5c\xd8\x0e\x7c\x94\x4d\xb9\x98\xc3\xc7\xbe\x54\x6b\xf8\x9d\x7a\x51\x1c\xcd\xba\x4b\x80\x9e\xee\x0f\xc2\x87\x3d\xad\x72\xb4\xcf\x3b\xa0\x51\x28\x9b\xb3\xf4\xe9\x92\x57\x32\xe4\x5a\xe7\x74\x10\x58\xc8\xfd\x11\x59\x9d\xd8\x43\x92\x7e\x3d\x14\x59\x8b\xb8\x30\x52\xd3\x35\x69\xcf\xb0\x2a\xf0\xc8\x8f\xa7\xae\xa4\xbb\x46\x84\x1c\xd2\xdd\xbd\xf5\x98\x8f\xcf\x32\x5f\xf1\x04\xa5\xdf\xc4\xa3\x0d\x26\x9d\x2a\x94\x97\x30\xc3\x61\x3b\xdd\xd3\x67\x3b\x42\xf6\x09\x0e\x6a\x60\xe4\xa2\x53\x06\x24\x63\xa6\x5d\x7e\x7f\xc0\x03\x0b\xba\x76\x9c\xa3\x44\xbf\xa9\xac\x82\x3f\x58\xcb\x5c\xee\x8a\x5f\xc0\xca\x37\x22\x8d\xe5\xa4\xd9\x3e\x0e\xcf\x7f\x10\x82\x16\x59\xa2\x26\x1f\x7e\xf1\x59\x6e\xda\x4e\x41\x1c\xf3\xc9\x66\x9d\x81\xde\x74\x54\x7c\xe4\xbf\x83\x3e\xb4\x32\xf3\x85\xce\x90\x38\xfe\x84\x8a\x8c\x96\xda\x7f\x01\xfd\x95\xbe\xa0\x6d\x1d\x74\x7c\x8a\xe7\x36\x49\x5b\xba\x22\x85\xbe\x5c\x32\xaf\xea\x44\x95\x20\xcf\xe8\xe1\xce\x25\xf9\x07\x7e\xd0\xec\x0f\x65\x98\xa9\xb8\xf7\x38\x6f\x15\x35\x81\x70\xcc\xef\xc3\xd5\xff\xb0\x09\x28\x81\x54\xde\x87\x7c\x24\x09\xae\x5f\xd8\xfe\xf0\x09\x3f\x1c\x36\xb3\xa8\xf5\x47\x43\x2c\xd0\xf6\x2c\x40\x33\x24\x2a\xd9\x92\x1a\x8f\x11\xc0\x0f\x36\x6d\xa9\x39\x69\x30\xa8\x0c\x99\x7d\xf4\x29\xa4\xf5\xf4\xe4\x5c\x7a\x6d\x7e\x02\xaf\x03\x31\x86\x75\x7c\x73\xcb\xe6\x4d\x2d\x4e\x78\xea\xaf\xe2\x75\x39\x52\x80\x35\xf2\xcf\xcf\x8e\xaf\x0a\x42\xbd\x25\xf8\x8b\x2f\xc6\x9e\x42\x66\x8f\xae\x66\x77\xc9\xac\x90\x91\xd9\xd1\x5a\x41\xf3\xac\xe6\x5d\x90\xa0\x22\x98\x73\xdc\xf2\x54\x25\x6c\xca\x44\x9e\xd4\xc1\x7d\x54\x35\xba\xe4"}, -{{0xbd,0x85,0x23,0xed,0xa8,0x99,0xb9,0x84,0x23,0x0e,0x32,0x88,0x75,0xb9,0x67,0x2e,0xdc,0x9f,0xcd,0x24,0xea,0x5c,0xc1,0x2d,0x7b,0x57,0x2d,0xa4,0xbe,0x01,0xfb,0x7b,},{0x02,0xb7,0x34,0xeb,0xbe,0x88,0xc1,0x3b,0xfa,0x95,0xa5,0xd9,0x64,0xfc,0x7e,0xf9,0xd3,0x95,0xbd,0x63,0x03,0xf0,0x65,0xdc,0x4e,0xe1,0x7b,0x3a,0xc1,0x54,0x8b,0x7b,},{0xfc,0xfc,0xdb,0x08,0x8d,0xcb,0xd0,0xa5,0x1b,0xd3,0x01,0xe3,0xe1,0x56,0x16,0x71,0x93,0x5d,0x8b,0x6f,0x71,0x9c,0x5d,0x92,0x69,0x06,0x40,0xd3,0xc9,0x1e,0x77,0x5b,0xf4,0x05,0x41,0x32,0xef,0xc0,0x5a,0x21,0x22,0xfc,0x20,0x9d,0xb3,0xc3,0x34,0x32,0x33,0xff,0x8a,0xec,0xeb,0xd5,0x2d,0xaa,0x2b,0x3b,0x21,0xee,0xb1,0x5f,0xd1,0x02,},"\x16\xc2\x16\xc9\xbe\x9f\x0d\x4b\x11\x54\x10\xbd\xfd\x15\x93\xc8\xe2\x62\x22\x1a\xb9\x7a\x2a\x39\x5a\x12\x19\x8f\x95\xc3\x02\x05\xb0\x89\x62\xd4\x89\x31\x18\xba\x9f\xf9\x9a\xb1\xc7\xa6\xe1\xf2\xf1\x75\x19\x10\x70\xac\x94\x53\x27\xad\x6c\x47\x0b\xab\xf7\x92\x8b\x07\xdd\x78\x8c\x85\xb6\x4b\x71\x2e\x0a\xae\x6c\x0e\xa2\x02\x81\xe4\x2f\xd5\x61\xe8\x3e\x3f\xba\xc6\x7f\x14\x00\x0e\xe5\x6d\x98\x1d\x2a\x2f\x0b\x9c\xa0\x0a\x9e\xa4\x7c\xa2\xf6\xfc\x8d\xca\x10\x35\xfc\xeb\x14\x2c\x3f\x26\xf2\x0e\x3c\x73\x22\x07\xff\xff\x11\xb7\x96\x95\xbd\xaf\xa4\x15\x21\x4a\x44\x99\x30\x23\x26\x60\x5c\xf0\xb8\xc8\x2f\x2b\x11\x39\x2e\xcc\x90\xcd\x74\xa7\xb4\x11\xb6\xd9\x07\xa3\xd5\xc1\x30\xc8\x79\xb7\xcf\x88\x0f\x22\xbb\xd7\xf0\xe9\x59\x33\x71\x8e\x96\xd7\xd1\x6c\xae\xa9\xf2\xc3\x9e\x89\xb1\x3c\xd5\x22\x66\x27\x36\x04\xa9\x6b\x51\xd6\xe3\x4f\x70\x67\x35\xdd\xd9\xfc\xa4\x4d\x09\xcd\x86\xbb\x72\x17\x60\x0e\x0d\x34\xd4\x16\xac\x24\x9f\x2e\x41\xbd\x0f\x4a\xbc\xbd\x25\x80\xad\xae\x21\xd7\xeb\xa5\xfa\x44\xf3\x9d\x78\x0f\x17\xeb\x85\xcc\xbe\xf5\x8f\xef\x90\x3a\x28\x0d\x95\xf8\xf3\x21\x07\x89\xfa\x12\xe1\x20\xe2\x1b\x6e\x8c\xad\x91\x78\x35\xbb\xdc\xc3\xb0\x7e\x84\x69\x39\x54\xe2\x3a\x94\xf9\x9f\x93\x7d\xdb\x0d\x4a\x18\xd4\x2c\x3e\xa8\xfc\xa7\xd1\xea\x6e\xd5\x3a\x00\x24\x6f\x99\xea\x52\x0e\x64\x05\xbd\x2a\xa5\x49\xb0\x6e\x7d\xa7\x22\xc1\xba\x74\xaa\x1c\x13\x6e\x8e\xa5\x8b\xaa\xf8\xd3\x76\x58\x69\x3f\x3e\x0b\x44\xf6\x31\xdd\x6d\x08\xff\xdf\x4f\x09\x18\x9d\x30\x35\xa3\xf0\x34\x68\xe2\x96\x96\xef\x05\xe0\x2c\xc1\xaa\xbf\xec\xbd\xa2\x30\x1b\x54\x0c\xb0\xeb\x0a\x75\xbc\xce\x73\xdb\x92\x73\xa9\x16\x1a\x98\xad\x89\x8f\xcd\x65\x79\xfb\x7e\x4b\x32\x79\x54\x4f\x2e\x0b\xd7\x74\xdd\x1a\x81\x57\xda\xa8\x8a\x70\x32\x11\x67\x70\x3c\x60\xa6\x08\xa4\xb5\x42\x16\x59\x03\x75\xe5\x97\xfe\x21\xae\xa9\x7b\x52\x18\x5d\x0e\x37\xa5\x3b\x63\x88\xa7\x07\xa2\xbc\x24\xac\xf9\x44\x25\xf8\x4f\x3d\x56\xbc\x9f\x7e\xe7\x41\x2a\x9e\x18\x33\xad\x55\xb7\xea\xe6\xda\x58\x16\x98\x16\x63\x83\xa2\xeb\xa8\xb6\xf5\x39\x20\xf5\x17\xa5\xc8\x0b\xd3\xe0\x3f\xaa\xd4\x08\x7e\x3e\xe8\xfe\xc9\xa7\x9a\x01\xc7\x79\x51\x21\x33\xd7\xb6\xe5\xf1\xde\xc7\x66\x30\x0d\xc4\x05\xcc\x21\xa8\xc5\x83\xfb\x73\xbc\x90\xcf\x24\x38\x5b\x08\x60\x49\xd3\xbf\x20\xc3\x00\x98\x3c\x0b\x35\x15\x38\xdc\xcb\x22\x7a\x14\xfa\xfd\x23\xac\x4b\x26\xbe\x81\xa2\xb1\x20\xcf\x21\x6f\xc5\x83\x54\xf9\xdc\xbf\x05\xf6\x63\x39\xad\x6d\xdc\x2c\xac\x14\x67\x7b\x90\xe2\x47\xeb\xb6\xc5\xc2\x29\x00\x7d\xc6\x0f\x37\x4a\x06\xd4\x04\xeb\x23\xeb\x1e\xc4\x99\x07\xc6\xe8\x81\x62\x9e\x18\x67\x26\x8c\xa6\xff\xfa\x59\xaa\x3c\xa8\xf6\xc2\x95\x16\x2b\x95\x36\xc2\xbe\x22\xbb\xe3\xb7\x23\x80\xef\x11\xb6\x1b\x35\x7a\x62\x53\x10\x0e\x30\xa5\x86\x81\x8b\xa0\x03\xfa\x3f\xfd\x1f\xc9\x19\x88\x1c\x05\x02\x2f\x94\x84\x85\x98\xf2\x17\xfe\xa2\x22\x50\x72\x20\xd1\x08\xa2\x8f\xc7\xbc\x39\xa8\xa1\x1c"}, -{{0x33,0xa8,0x5a,0xe1,0x50,0xbb,0xf5,0x52,0xf4,0x16,0x63,0xb2,0x15,0x21,0xc2,0x96,0xd2,0x46,0xdd,0x6c,0xf8,0x19,0x5d,0xf8,0x51,0xc6,0x95,0xbd,0x15,0xf4,0xa5,0x02,},{0xc8,0xc9,0xc4,0x25,0x21,0x00,0x8d,0x5e,0xff,0xf5,0x76,0xc7,0xe4,0xa5,0x60,0x83,0xce,0xd9,0xa9,0x28,0xda,0x6f,0xd5,0xcf,0x93,0xfd,0xa5,0x72,0xa5,0xa2,0xd0,0xc0,},{0xbb,0xe4,0xcd,0x63,0x67,0x6e,0x26,0xd6,0x75,0xa1,0x91,0x15,0x1d,0x30,0xdb,0x72,0xb5,0xb8,0x4d,0x46,0x1e,0xec,0x65,0x64,0xaf,0x86,0x7a,0xb4,0x1b,0xae,0x99,0x31,0x14,0x78,0x85,0x51,0x9e,0xc9,0xd7,0xe6,0xc8,0x18,0x74,0x3c,0x8e,0xf6,0xd5,0x16,0x7b,0x35,0xb4,0x21,0x36,0x3c,0x09,0xb3,0x57,0x36,0x7f,0xe8,0xde,0x44,0x3a,0x06,},"\x93\x7e\x05\xf2\xf1\xfd\xbd\x41\x73\x15\x53\xe7\x7c\xf1\x81\xb5\x07\x97\x58\x94\x0a\xee\x8e\x92\x62\x3f\xb1\xd5\xf0\x71\x28\xb7\xd7\xf1\x7e\x48\x42\x70\x7a\x56\x2c\x45\xba\x69\x26\x4c\x0f\x73\x0a\x82\x1c\x7d\xb6\xbf\x82\x99\x0d\xc6\x51\x26\x9b\x29\x6c\x33\x51\x79\x11\x30\x53\xd6\xf8\x5b\xb0\x96\xb2\x91\x11\x65\xfa\x39\x00\xcb\x10\x24\x16\x48\x7b\xa8\x07\x86\x79\xc6\xb3\x36\xdf\xf3\x87\x63\xc0\x8d\xcd\x20\xfa\x66\xdd\xa4\x5c\x57\x5d\xf1\x50\xd8\x51\x16\x5a\x48\x04\x97\x38\x30\xf4\x36\xdf\x60\xb8\x13\x19\xf9\xcf\xb5\x64\xc0\x65\x28\x96\xed\x5f\x18\x49\xcb\x33\x54\xf5\x0f\x00\x12\xf2\x86\xe8\xa3\x0c\x21\x35\x28\x69\x34\x74\x00\x4e\x85\x04\x01\x2b\x94\x55\x60\xc0\x74\xa6\xa1\x63\x43\x2c\xf4\xac\x4b\xa7\x17\x5c\xf2\x60\x05\xdb\x71\x99\xee\x96\xd8\x93\xcd\x1a\xad\x3f\xdf\x5d\x57\x46\x0e\xf0\x2d\xda\x6d\x3a\x14\x08\x25\x19\x6f\x3f\x8e\x2f\x37\xda\x36\xb6\xfd\xad\x18\x4f\x27\x40\xf1\x16\xde\x75\x8a\x92\x91\x70\x30\xc5\xfb\x80\xf0\x26\x24\x96\xd2\xdf\x93\xc7\xe2\x76\xf2\x5d\xa7\xdb\xed\x8e\xb8\xdd\x4c\x56\x3a\xba\x55\xb8\x2a\xf6\xba\x3a\x70\xca\x5f\x85\x8b\x44\xa0\x33\xcf\xb7\x95\x60\x4d\xde\xe7\x46\xe7\xc8\xae\x79\xd2\x72\xfb\x9a\x23\x41\xa2\xa2\x02\xdf\x5e\xac\x08\xde\x75\xad\x80\xc6\x58\x0d\x92\xb1\x69\xf2\xe1\x31\x88\x57\xb1\xb1\x42\x1c\x30\xf3\xdd\x46\x10\x93\xde\x2d\x34\x5e\xde\x74\x04\xb7\x2a\x45\x0d\xe0\x7b\x16\xee\xe6\x8c\xe6\x28\x87\xb6\xea\xa4\x36\xee\xe6\x84\xbe\x75\xce\x0e\x1f\x96\x26\x3e\x8d\x87\x36\xf9\xba\x00\x0d\x88\xe9\xe5\x86\x0f\x32\x8a\xe1\xe2\xdc\x73\x09\x9d\x32\xfc\xeb\x1b\xd2\xc0\x12\x36\x98\xa4\x9b\xea\xd1\x90\xa0\x0e\xc9\xa6\xf8\x71\x33\xed\xdd\x45\x31\x6f\x65\xeb\x0d\x32\x9b\x07\xb9\xa6\x6b\xb9\xfe\x42\x58\x8b\xf7\xb8\xd0\x6e\xfe\xc1\x98\x6b\x82\xa0\x81\xed\x3f\x68\x02\xe9\xbe\x73\x46\x47\x84\x55\x9a\x4f\x2c\x09\x7b\xa1\x4b\x0b\xfd\x5d\x7e\x0a\xff\x65\xcb\x69\xab\xd0\x3f\x86\x16\xcd\x7e\xdf\x7e\xc3\x68\x21\x9e\xdc\xf8\x93\xe9\xee\x71\xda\xd9\xf1\x8d\x79\xe5\x68\x26\x5d\xdc\x67\x16\x22\x32\x13\x23\x5b\xb9\x28\xe9\x08\xde\xa8\x27\x78\x4c\xd1\xaf\x39\x6d\x59\x0c\x81\xf4\xea\xcd\xfc\xf8\x9c\x5c\xac\x96\xfa\x05\x00\x64\xa2\x28\x41\xea\x71\x5f\x8c\x89\xd6\xd5\xaf\xbf\x59\x7a\x4d\x00\x5d\xbc\x6b\x13\x85\x6d\x33\x5b\x42\xa9\xa8\x2e\xdc\xb9\x49\x83\x5c\xca\x20\xb0\xa2\x3d\xe5\x1c\xc3\xae\xc3\x55\x66\xef\xf0\xc5\xae\x1a\xb3\x75\x13\x20\xd2\xc3\x10\x49\x52\x38\xed\xa3\x83\xc3\x8a\x41\x63\x15\x2b\x88\x15\x69\x0b\x8f\xf0\x15\x03\x5d\x1d\x00\xea\x4a\x0d\x6c\xaf\x32\x4b\xb7\x1a\x66\x4a\x1b\xed\x31\x48\x07\x84\xa6\x8f\x43\x8c\xaa\x35\x9e\x8d\x26\x73\xc8\x57\xd4\xb8\xc0\xb6\xc6\x95\x84\x7b\x86\x80\x0e\xa3\xd7\x34\xb5\xec\xc4\xd5\x2b\x50\x7a\xc6\x9b\x3a\x67\x78\x91\x60\x16\xeb\xc2\x31\x5f\x44\xc9\x0b\xf0\xc3\xe7\xda\xe0\x1d\x49\xcb\xc3\x03\x40\x2b\xbc\x63\x4a\xe1\x19\x1f\x3f\x6f\xd6\x3d\x30\x3b\x0c\x0b\xe0\x33\xa4\x7b\x90\xf8\xd3\xa7\x7f\x0a\x44"}, -{{0xba,0x9e,0x68,0x62,0x04,0x97,0x5c,0x3b,0xde,0xd4,0xc1,0xe9,0xf7,0x4c,0x7e,0x4c,0x7a,0x7e,0x3c,0x99,0x81,0xd0,0x1b,0xfc,0xa0,0xad,0x01,0x15,0xc3,0xf0,0xf5,0xc3,},{0x49,0x90,0xfc,0xe6,0x95,0x2e,0x8b,0x7d,0x0a,0xfc,0xf4,0xbf,0x9d,0xba,0x9b,0xce,0x1b,0xc4,0x81,0x5e,0x37,0x51,0x1d,0xa7,0xc2,0xad,0x48,0x92,0x58,0x1d,0xe0,0x3a,},{0xc7,0xd2,0x3a,0x58,0xe2,0xfb,0x2a,0x8d,0x4b,0x8e,0xd1,0xe9,0xea,0xe9,0x1e,0x11,0x29,0xc2,0xaf,0x8b,0xd0,0x5f,0x0b,0xd5,0x72,0xab,0xeb,0xbe,0x0f,0x30,0x82,0x59,0x25,0xf0,0xdf,0x71,0xcf,0xb7,0x21,0x8c,0x68,0x6e,0x55,0x48,0xd9,0x42,0x77,0x10,0xa6,0x90,0x36,0x6b,0xa8,0x55,0x41,0xc7,0x91,0x01,0xa5,0x8a,0x10,0xe8,0xaf,0x0a,},"\x46\xbb\x48\x95\x2a\xe5\x8f\x2b\xf5\x8f\x5b\xe8\xdf\x4f\x31\x6b\x50\xf3\x63\xec\x84\xee\xd8\xf8\x2f\xf4\xc0\x4b\x06\x92\xd0\x3a\xef\x26\xe8\xe1\xe6\xc9\x54\x9a\x22\x47\xd5\x40\xa6\xe2\x2f\xeb\x11\xe5\x7f\x4b\x80\x8a\x20\x97\xe8\xa7\xb6\xb3\xb7\xaf\x37\x69\xe6\xd8\x1d\x64\x88\x6e\x69\x62\x37\x2f\x4f\x39\xe4\x9c\xd4\x6c\x1b\x5f\x73\x5f\x38\x0f\x7c\x27\x7d\x09\x97\x76\xed\x1a\xea\xa5\x7a\x35\x9c\x0a\xa8\xc7\x2f\x40\xeb\x91\xa1\xbf\x07\xea\x15\x7f\x5d\xdb\x30\x40\x9d\x6e\x3a\xf9\x89\x90\xce\x7f\x30\xaf\xfd\xac\x5e\x22\x01\x06\x46\xdc\xa9\x6a\x54\x00\x60\xfc\x90\x8a\x31\x25\xb0\x00\xad\x1e\xd3\xa0\xf2\x55\xcd\x34\xf1\x5d\x7d\xd1\xfd\x68\x1c\x3c\x35\xa1\xcd\x65\x20\x56\xec\xc5\x26\x4d\x39\xaa\xf7\x2a\x9b\xb8\x3a\x55\x1c\xc9\x34\x88\x7a\xe1\x07\xaf\xdf\xef\x06\x32\x17\x27\x0d\x95\x96\x89\x14\x18\xbd\x46\x1b\xba\x63\xde\x65\xbe\x06\x7b\x1b\x78\x64\xfe\x46\x48\x4c\x7c\x9e\x96\x34\x9a\x7c\x03\xa8\x0f\xa0\x55\x05\x0a\xa1\x8a\xce\x2a\x44\xb4\xa0\x3c\x94\x78\x24\x17\x2b\x30\xe2\x10\x11\x15\x94\x43\xca\x3c\xef\xaf\x69\x6a\x7a\xa8\xf9\x80\x11\x26\x0c\x94\x36\xbf\x48\x99\x1f\x41\xd4\xd5\x07\xb9\x6c\xe7\x32\x3e\x53\x1a\xdc\xf6\x63\x47\xc5\x5c\x88\x55\x67\x3a\x9f\x2e\xc8\x9b\x5c\x80\x24\x46\x06\x17\xec\x72\x71\x77\x3b\x36\xd6\x4f\xc1\x4e\xb5\xd8\x26\x52\xc5\x3a\x30\x31\x45\x72\x27\x09\x3d\x11\x8f\xd8\xeb\x93\x84\xe8\x02\x29\x04\x1a\x96\xa6\x49\x34\x50\xf9\x7e\x67\x36\x26\x3a\xbf\x1e\xcd\x9e\x9f\xb9\xa4\xf0\xf6\xd6\x67\xfa\x82\x41\x51\x48\x5e\xdc\x37\xb3\x4a\xcf\x3d\x8c\x35\xf9\xc1\xbe\x48\xb5\xe9\x6a\x12\xaf\x8e\x2d\x35\xc2\x3a\x03\x58\x0f\x21\x1d\xa6\x31\x6b\x34\xc5\x6b\xee\x87\x2d\x47\x64\x1b\xca\x77\xda\x64\x0f\xdb\xba\xd5\xa9\xad\x8a\xb9\xdc\x79\x57\x91\x3d\xa7\x34\xad\x37\x49\x2b\xa4\xde\x8c\xf1\x36\xcc\xcd\xeb\x6b\xa3\xf1\xbd\x3f\x00\x3b\xe7\x26\x3c\x4f\x2a\x40\xc3\x3f\x24\xca\x33\x39\x59\x6e\x6c\x34\x28\x33\x81\x00\xeb\xcc\x07\x22\xd4\xf5\x0d\x30\xb3\x3b\x91\x2d\x4e\x7c\x1a\x9f\xe6\x5f\x66\x58\xa6\xf2\x39\x14\x0a\x62\xc3\x26\x1e\x10\x39\x2e\xd1\x93\x0a\xa9\x17\x65\x2d\x3b\xd2\xbe\x4e\x8a\x08\xab\x97\xe1\x45\xb9\x20\xab\xb3\x1e\xe4\xbc\xd5\xa0\xd7\x1f\x63\x81\x80\xf6\x1c\x24\x58\x23\xa3\x99\xa7\x34\xa4\xdc\xde\x09\x97\x88\x02\x45\xed\x71\xeb\x9b\xc6\x5e\x3c\x6f\xc9\x5a\xb9\x20\xb8\x02\x4c\x17\xd4\x4c\xed\x00\x37\xd0\x4a\x13\x3c\x26\x41\x78\x2f\x1d\x62\x2d\xf4\x52\x69\xb4\x91\xd3\xfa\x2a\x12\x27\x57\x9e\xaa\x38\x6d\xe3\xe7\xde\x7b\xc4\x55\xc6\xa1\x54\xee\xe5\x72\x7f\xff\x04\x37\xa2\x00\x76\xc5\xc3\xb0\x57\x7c\xac\x5b\x4b\x69\x34\xe2\x69\x38\x02\x22\x46\x1a\x60\xf9\x54\xe4\x89\x79\xc0\x67\x12\x17\xf1\x6f\x70\x27\x98\x30\x34\x12\x10\x93\x18\x6c\x78\x70\x5f\xc2\x7d\xc9\x2e\x2e\xda\x41\x16\xa6\xbf\x7d\x23\xe0\x54\x8d\x62\xb6\x7b\x25\xc4\x1e\xd0\x61\x92\xbc\x26\xef\x13\x97\xbf\x16\x01\xf3\xa6\xe2\xa0\xe7\xf6\x61\xfb\x05\x05\xee\x38\x2f\x27\xae\xc2\x80\x5a\x3e\x21\x17"}, -{{0x59,0x07,0xa8,0xc0,0x84,0x04,0x38,0x75,0x23,0x8e,0xdb,0xdc,0xb7,0x83,0x2f,0xbb,0xa4,0xc0,0x5e,0xa3,0xc5,0xf8,0x8a,0x96,0xf1,0xfb,0xf9,0x50,0x40,0x1e,0xc1,0x64,},{0xe2,0xf4,0x95,0x09,0xd1,0x00,0x7f,0x61,0x8e,0xfe,0x4f,0x1f,0xd6,0x7e,0xaa,0x6e,0x2a,0xb1,0x8a,0xfb,0x2d,0xec,0xce,0xd5,0xa0,0xb2,0xba,0x83,0x63,0x78,0x92,0x60,},{0x8c,0x49,0x12,0xc0,0xf8,0x85,0xd7,0x6c,0x91,0x40,0x59,0x50,0x53,0x73,0xa6,0x4b,0xdd,0xd6,0x7d,0xd4,0x68,0x36,0x9a,0xb9,0x18,0xf2,0x3e,0xa2,0x8e,0x04,0xc1,0x91,0x77,0xa8,0xd4,0x61,0x14,0x4f,0x0a,0x8b,0x51,0xd2,0x15,0x17,0x6c,0xb0,0x8b,0xd6,0x53,0x01,0xc3,0xc4,0x62,0x37,0xb6,0x1b,0xb1,0x49,0x8c,0xa7,0x9d,0x4b,0xe7,0x0e,},"\x43\x3b\x24\x78\xe1\x8f\xad\x5c\xb8\x10\x67\x06\x1d\x22\x55\x28\x22\x97\x78\x30\x78\x85\x47\x54\x60\xfb\xe3\x13\x7a\x5b\x44\x02\x48\x94\xdd\xbe\x56\xfa\x6e\xd0\x21\x49\x6f\x07\x86\xe4\x2b\xc6\xc2\xd2\x79\x7e\xa0\xa6\xbf\x35\x5e\x88\x11\x5f\xaa\x55\xcd\x92\xed\x42\x13\x3d\x9d\xcd\xa6\xb9\xeb\xf6\x3c\xe4\xa9\x94\xd1\xa8\x2d\x2a\x49\x26\x75\x58\xbe\x54\x18\x2a\x6f\x85\x11\x2b\xd1\x2b\x24\x7a\xda\xcf\x14\x05\xfc\x7e\xc7\xa0\x15\xd4\x3a\xb4\x0b\x82\xc6\x77\xf7\xf8\x5a\x0e\x48\x19\x7c\x5b\x96\x57\x61\x99\xf4\xc3\x34\x3f\xf7\x65\x4d\x52\x3a\x30\xc4\x3a\x05\x4c\x3e\x46\x44\x51\x27\x80\x34\xb7\xf1\x96\xc3\x66\x76\x8c\x62\x8a\xf9\x4f\xc0\xcc\xfc\x9a\x29\x55\xf9\xd3\x23\x38\xb9\x44\x78\x0f\x8e\x32\x70\x85\xb1\x03\x78\x18\x68\xe4\xfb\x79\xd5\x61\x22\xd7\xf3\xf5\xab\x30\x9e\x5d\x63\x4a\xdd\x15\xda\x38\x2c\x0d\x23\x58\xe6\x47\x18\x2b\xe4\xde\x6e\x9a\x9e\x43\xe6\xa3\xa3\xb8\x21\x5b\x20\x4d\x95\x07\x61\x0d\x46\x16\x21\x00\x0f\xb1\x89\x37\x07\xaf\x7d\x25\x95\xbf\xef\x8a\x8c\x5c\x5c\xd0\x8f\x30\x9a\x5f\xb5\x5e\x45\x51\x9a\xea\x9b\x84\x74\x8c\xa5\xc6\x72\xbf\xec\xd3\x0d\x25\x65\x12\x34\xa3\xcc\x31\x9b\x43\xdf\xce\xfc\x1a\x07\xb5\x5b\x4a\xca\x71\x4c\x2e\x7e\xf9\x63\x8f\xe7\x88\x4a\x77\xb2\x22\x53\xa0\x1a\x22\x29\x50\x0e\x9c\xe1\x0f\xda\x73\xa8\x43\xc1\x9c\xc0\x96\x26\xd2\x45\x6c\x22\xa9\xc9\x01\x88\x1d\x52\x1f\x4b\x15\xd2\xf6\x13\xcb\x46\x9d\x30\x4d\x57\x92\x23\xbc\x5f\xf7\x38\x04\xdf\x63\x71\x51\x7e\xba\xa5\xb6\x77\xea\x91\x0f\xf1\xa0\x2a\x26\xfa\xfe\x48\xfe\xf4\x69\xed\x79\x9b\xed\x6d\x56\xce\x96\x18\x34\xa2\xed\xc2\xe2\x3c\x0d\x94\x26\xec\xcd\xcc\x93\x4f\x4c\x22\x0e\x37\x81\x5f\x7c\x33\x4b\x73\x83\x60\x7d\x43\x05\x20\x94\x6a\x88\x1a\x08\x32\x5b\x41\x64\x97\x9d\x5e\x82\xcd\x81\x34\xd7\x8c\xec\x48\x61\xc0\x19\xf6\xde\x30\x1c\x1b\x9a\xec\x52\xbb\x98\x20\x33\xfb\x79\xb2\xe9\x73\x1b\xab\x29\x68\xbc\x3f\x93\xfa\x56\x04\xb8\x93\xc6\x02\x8c\x20\x4c\x36\xbb\x8c\x6b\x07\x4b\xe2\x8c\x96\x4d\x28\x49\xb5\xbb\x19\xd7\xe0\xba\x24\xe2\x2a\x20\x4d\x4f\xda\x83\xb1\x01\x31\xd3\x83\xf1\x0b\x13\x6b\xd0\xdb\xa3\x9e\xc2\x6a\xf3\x0e\x3f\xfb\x4d\xbc\x0c\x92\x1f\x0c\xc9\x91\x07\x15\xd5\x1c\x81\xfe\x4c\x62\x95\x0e\x85\x55\x49\xa1\x7c\xd7\x3a\x09\xac\x91\xe0\x6d\x46\x15\x18\x37\x6d\x0f\xcf\xa1\x23\xdf\x0a\x83\x71\x03\x45\x8d\x9c\xe2\x21\x80\x8d\x1f\x9e\xf2\xed\xc5\xcd\x2e\x68\x23\x14\x5b\x52\x48\x94\xea\x48\x52\x6d\x98\x5e\xef\xd3\xf6\x06\x79\x39\x95\x48\xe1\xed\xea\xdb\x53\x95\xb4\x3d\x87\x04\x4b\x2b\xfe\x7c\x60\x37\x02\x9b\x34\x6a\x40\x22\x27\xea\xb8\x1f\x33\x3e\x10\xe7\x7f\x1d\xbc\x06\xa2\x11\xd4\x3b\x82\x55\x86\x76\xc2\xdc\xff\x90\x82\xb1\xdd\x53\x36\x8d\xf0\x02\xde\x13\x29\xaf\x30\x00\xb1\x71\xa6\x91\x43\x89\xbb\x80\xec\x0c\x9f\x3e\x41\x2a\x44\x1b\x80\x0a\xfc\xeb\x04\x86\x70\x9a\xda\xc6\x6c\xaf\xee\xf2\x48\x83\x93\x31\xf5\xd8\x92\x19\x7e\x25\x42\x0f\x1e\x37\xd7\xc0\x24\x7f\x66\x9f\x5f\xcb\xf0"}, -{{0x60,0x20,0xae,0x27,0x3e,0x0e,0x05,0x37,0xba,0xc8,0x81,0xd7,0x54,0x9d,0x92,0x3e,0xb1,0xcc,0x20,0x0d,0x49,0xca,0x65,0xd4,0xbe,0x63,0x5e,0x39,0x17,0x3d,0xf9,0xda,},{0xda,0xaf,0x0e,0x69,0x9a,0x12,0xa9,0x2c,0x16,0xe0,0xde,0xd3,0xeb,0x34,0x50,0xa3,0x63,0x11,0x82,0x45,0x77,0xe3,0x61,0xf0,0x56,0x96,0x60,0x33,0x00,0x16,0x62,0x97,},{0xb1,0xba,0x88,0xfe,0xd7,0xe5,0xf4,0xb7,0x57,0xf3,0xfa,0x4d,0x1e,0xd9,0xb1,0x9e,0x49,0x8e,0x5d,0x2f,0x5e,0x6c,0xd4,0x6e,0x42,0x6f,0xe8,0xf0,0x39,0x88,0x2f,0x1b,0xe7,0x7a,0xc9,0xe5,0xa9,0x26,0x5c,0xbf,0x7e,0x3c,0xd2,0xa9,0xe9,0x92,0x6c,0x18,0x19,0x91,0x43,0x79,0x8d,0xa5,0xbe,0x47,0xa4,0x08,0x64,0x40,0x49,0x6b,0xa0,0x0f,},"\x6a\x80\x11\xde\x09\xaa\xc0\x0d\xb1\x6f\xf7\xe5\x5c\x2d\xe6\x7d\x8c\x98\x83\xfc\xb2\x04\x0d\xed\xbc\x1e\x32\x1c\xab\xa7\xbb\x03\x69\x71\x53\x01\x76\xd1\xdb\xba\xa9\x27\x52\x0b\xdf\xcc\xbe\xd8\x84\x01\x26\x04\x3e\xdc\x44\xcb\xb7\xfa\x35\x28\x68\x0e\x5f\x1b\x56\x64\x95\x1d\xc9\x01\x09\xae\xa4\xb9\xc3\x36\xca\x04\x3d\x82\x21\xa4\xc8\xd2\x01\x16\x56\xbf\x94\x4e\xfd\x36\xba\x0a\x10\xa4\xb3\x89\x19\x60\x55\x75\x0b\x0e\x38\x8f\xb5\x28\x70\xbb\xec\x8c\x55\x19\x81\x31\x44\x39\x45\xc0\x9f\x3a\xac\xe3\xe6\x91\x50\x14\x37\x40\x73\x26\x6f\x34\x88\x74\x42\xd7\x4f\x46\x8f\x8d\x70\x78\xbb\xa0\xbd\x81\x4c\xd6\xdd\x42\x3c\x97\xb5\x69\x05\x58\x7b\x15\x2d\x1f\xcf\xba\x0e\xb9\xfd\xe2\x11\x26\x91\xda\xfa\xf4\xf9\x21\x56\x2f\x24\x1b\x62\x84\x10\x01\x83\x4f\x6c\xe3\x66\x85\xf8\x2a\x8f\xaa\x3b\x7a\xfa\xd7\x3a\x5e\x59\xbf\x5f\x9e\x71\x3e\x59\x16\x3f\x31\xdb\xe6\x96\x11\x8a\xf3\x35\x06\xd2\xff\xea\x3d\x9c\x15\x56\xfb\x15\x2f\xd2\xb3\x21\xc3\x17\x57\xd0\xc3\xc0\xf6\x0e\xe1\x13\xed\xac\x02\xd6\x7e\xfb\xb3\x03\xdc\xe6\xfa\x88\xf7\xb9\x74\x6c\xa1\x10\xe6\xa0\xcd\x09\x9c\x08\x31\xf5\x3c\x55\xc2\x8b\x6c\x82\xaf\x44\x64\x56\xb8\x42\xb2\xc9\x50\xa5\x53\xee\x2c\x76\x5e\x97\x29\xe6\xb0\xc5\x46\xbf\xc2\x6b\xd6\xd4\x2d\x06\xb2\xed\x5d\x4c\x8c\xbb\xc7\x5f\x2a\x3a\xd8\x12\x93\x95\x79\x3d\x97\x9c\x03\x1f\xce\x7e\x20\xb3\x8b\xd8\x9c\x9b\x62\x47\x48\xb2\x01\x34\x23\xce\xba\xda\x02\xcd\xe2\x05\x2d\xa5\x66\x4c\x6c\x64\x26\xcb\xfc\x88\xf8\x4f\xf6\x02\xe2\xe2\x0d\xf9\x67\x8f\xbb\xa5\x77\xa4\xc1\x34\x51\x7e\xe0\x50\x68\x11\x51\x58\x0f\x7c\x5c\x97\x87\xb9\x6e\x55\xc4\x07\x5a\x26\xf4\xf8\xcc\xff\xbb\xb6\xea\x18\xde\x1b\x2c\xc8\xc4\x49\x6b\x16\x04\x27\x70\xb7\xec\x6e\xb5\x42\x9e\x7a\xc1\x89\x12\x32\xaa\x4e\x47\x46\x7f\x4e\x9a\x98\x5d\x80\x54\x7e\xcc\x4c\x6f\xd9\xf5\x97\x63\xed\xe9\x16\x71\xf2\xaa\x57\x36\xa5\xd1\x48\xe3\xa8\xff\xc8\x8e\x61\x25\x3a\x85\xb0\x95\x36\x54\x95\x8e\xb2\xd6\x94\x01\xcb\xea\xe7\x75\xf8\xcb\x8c\x3c\xa4\x2d\x21\x69\x3e\xbe\x29\x88\x38\xdf\x94\xc1\xd7\x7b\x12\x6a\x12\x05\xcc\x47\xd5\x0d\x53\x67\xb6\xf2\x76\xec\x8d\xb6\xb9\x53\x24\xa3\x1e\x8f\xd2\xed\x2e\x43\x42\x0c\x4a\xd0\x2e\xa2\x77\xdd\x94\x8a\x55\x19\x3d\x0f\x0b\x4d\x1c\xf2\x83\x86\xc7\x25\x97\x5c\xe5\xc1\x2d\x2a\x6f\x35\x67\x3c\xc2\x2a\x06\x94\xcc\xa4\xda\xf6\xaf\xbf\xd3\x26\xd8\x8c\x18\x50\xf8\x34\xc4\x2f\xf0\xe2\x92\xba\x4f\x13\xe5\xef\x07\x74\xa5\x96\xd3\x39\x04\xc0\x26\x2d\x31\xdf\x2c\x58\x4a\x0a\x4f\x45\x3f\x6a\xe4\xa8\x8a\x27\x5f\x7d\xe7\x9c\x13\xae\x1a\x73\x11\x5b\xe0\x2f\x42\x5c\x6f\x17\x7a\x1e\xc4\x63\x9c\x42\xa7\x92\x80\x9a\x2b\x09\x19\xeb\xd3\x21\xe3\x16\x00\x1d\x5b\x2f\x84\x89\x4f\xce\xbd\x50\xa1\xdc\xf4\x4d\x70\x2b\x92\x45\x32\xfc\x0e\x4d\x3f\x9f\xf8\x48\x6c\x0e\xd1\x80\xee\xcc\x3e\x09\xe2\x27\x2a\x94\xdc\x7d\x24\xa4\xe8\x7a\x93\x1f\xe2\x49\x5c\xbf\x99\x2c\x0a\xae\x92\x01\xe0\x79\x62\x98\xf9\x36\x3d\xba\xc4\x75\xe8\xed"}, -{{0x93,0x2a,0x20,0x0e,0xce,0xe7,0x22,0x3f,0x24,0x14,0x62,0x83,0xa4,0x04,0x8c,0x67,0xa6,0xa2,0xd2,0xfc,0x4b,0xa0,0xf9,0x24,0x8b,0xdf,0xfd,0x82,0xc6,0xcc,0xe3,0xcb,},{0xec,0x9b,0xfb,0x7a,0x6d,0x04,0xe7,0x26,0xfc,0x1e,0xa0,0xc4,0x24,0x61,0x0d,0xcb,0x79,0x67,0xbf,0x15,0xd6,0xd6,0x62,0x68,0x58,0xd4,0x11,0x19,0x8d,0x40,0xe2,0x39,},{0xcd,0x1e,0x4b,0xdf,0x4a,0x3e,0x4a,0x31,0xd6,0x52,0x54,0x33,0x3c,0x8c,0xc4,0x08,0x7e,0x4c,0xc4,0x0b,0x02,0xe2,0xa3,0x47,0xd0,0x9a,0x3d,0xde,0x69,0x84,0x90,0xc0,0x87,0xd7,0x10,0x9a,0xd0,0x20,0x9c,0x53,0xe9,0x87,0x58,0x9c,0xbf,0x3c,0xe2,0x64,0x12,0xa2,0xb0,0x2c,0xb8,0xa3,0xbc,0x93,0xfe,0xc7,0x5a,0xb5,0xd2,0xc3,0x87,0x03,},"\xdf\x95\x32\x07\x04\x82\x13\xaf\xb8\xe2\xaf\x45\x2c\x88\x9a\x21\xca\x13\x6a\x68\xc9\x29\xbd\xc8\x24\xf9\xa8\x9a\xc5\x96\xdc\xb9\x00\x19\xa4\x6f\xb6\x82\xbc\xfd\x96\x2f\xcc\xb2\x7d\x00\xba\xf8\xec\xca\xf9\xd9\xa7\xd8\x18\x3c\xab\xd7\xdf\xa5\x06\xf7\xba\xfb\x49\x35\xab\x04\x59\x31\xff\x8f\xae\xb7\x16\x31\xf9\xed\x6b\xb8\xf8\x47\x3a\xd6\x29\x0d\x7c\xf5\x19\xdb\x31\x0a\x44\x42\xc4\x61\x11\x8f\x67\xd1\xa6\xd1\x03\xba\xe6\xf2\x69\x7c\x94\xb7\x42\x6d\x9e\x02\xe3\xcb\x95\x22\xfd\x0b\x44\xae\xf6\x00\xc9\x62\xfe\xff\x58\x73\xd9\x8c\x27\x90\x88\x7b\x8e\x88\xd1\x60\x82\x4f\x1b\xba\x22\x01\x76\x39\xf8\xdc\xe6\x8f\x74\x34\x80\xde\xea\x1f\x92\xaa\x1f\xd4\x13\x5d\xd0\x64\x57\xa6\x0f\x36\xb7\xd7\xf5\x17\xd4\x0c\x94\xc0\xdd\xdc\x2e\x46\x58\x47\xd9\x09\xb9\xf6\x82\x45\xff\x2b\x42\x1d\x59\x19\x00\x1a\xae\x5a\xef\x24\xe0\x2c\x00\x2d\xa9\x07\xe8\x60\x5f\x16\x0e\xa6\x09\x6b\x58\x0b\x75\xce\xa0\x22\xd4\x02\xf7\xf5\xfd\xc4\x64\xf8\x7f\x78\xc7\x90\x6a\x01\xe8\xe4\x8f\xb5\xb3\x51\x74\x61\x2b\x48\xac\x8b\xc7\x50\xe0\xf3\xae\xb0\xa1\x2f\x7d\xfc\x09\xb0\x84\x2c\x17\x80\xa5\xfd\x9c\x54\xaf\xb9\x39\x9b\x94\x08\xba\xac\xcd\xa2\x0a\xfb\xe3\xd6\x82\x24\x8d\x7b\xf1\xef\xde\xf4\x90\x5a\x31\x9b\x0f\xfb\x10\x8b\x75\x3b\x71\xcc\x97\xe9\xe2\x1e\xc9\xb3\xdd\x28\xce\xe0\x39\xd9\x41\x8a\x11\x35\xf0\xad\xd0\x92\xaa\x66\x31\x2e\xa2\x91\x33\x00\xd1\xcc\x89\x16\x52\x43\x02\xbd\x3d\x1b\x09\xe6\xb2\x9c\x68\x57\xcb\xdc\x56\xef\x4b\x3f\x35\xd8\xee\x67\x72\x08\xef\xfa\x84\x6f\xdb\x06\x6b\x05\xeb\x71\x7b\x4d\x45\x12\x0c\xab\x72\xa7\xdb\x7a\x7c\xa8\x46\xe8\x7b\x16\xb6\x90\x47\xeb\x76\xd8\xf1\x8d\xa8\xe1\x39\x9e\xc0\xa8\xc9\xc3\x28\xcb\xe6\x0e\x0b\xf4\x20\x44\xd2\xeb\xf2\x81\x8b\x3c\x04\x75\x88\x45\x2f\xcd\x2b\x3e\xfc\x1e\x10\x09\xae\x07\x68\x87\x27\xdb\x8f\xb6\xdf\x2a\x2f\xe7\x5d\x1c\xf2\x2f\x32\xba\xc0\x9c\x82\xa6\xa3\xd7\xee\xd7\xd0\x05\x08\xcb\xe5\xb7\x24\x60\xec\xfc\xdd\x3e\xe9\x11\xef\xe5\x89\x8d\xbd\x8e\x4c\xe8\x59\x13\x26\xdd\x15\x22\xf9\xd2\x55\xda\x86\x1b\xf9\xeb\x2a\x1d\x57\x25\xd7\xd5\xd4\x27\x34\x03\x41\x94\x5e\x7b\xca\x8c\xf2\xff\x8a\x99\x74\x50\x95\x3e\x77\xd2\x03\x68\x3e\x4b\x0d\xaf\xc3\x30\xe0\x56\x72\xd2\xec\xd1\x3a\x3f\x44\x2d\xf1\x37\x04\x4e\x0f\x55\x6f\xfb\xce\xff\xea\x26\xcb\xae\x26\xcb\xa6\xf2\x56\x8c\xf3\x9f\x90\x84\x89\xe1\xa9\x2e\x76\xaf\xbf\x29\x79\x95\xda\x4b\x2c\xb1\xab\xc9\xee\x1f\xe4\xdc\xa5\xaa\x83\x8b\x2f\xbd\xc1\x09\xe8\x9b\xef\x3c\xe5\xa3\x6e\x5b\x2f\x71\x2a\xc4\xc8\x89\x43\x82\x48\xfa\x5a\x21\x50\xca\xc6\xc9\x77\xb5\xe0\x54\x3f\x40\x10\xb7\x31\x47\x32\xfd\x18\xe7\xfd\x59\x82\xe8\x32\x76\x51\x9e\x78\x72\x5e\x5a\x5e\xeb\x86\xf4\x89\x20\x84\xae\x52\xda\x38\x49\xc2\x28\xc8\x09\xed\xbf\x69\xa2\xcc\x47\xc4\x78\xd1\x87\x19\xf1\x11\xd7\x37\x88\x7c\x7a\x2e\xb3\x25\x08\x98\xdb\x34\xe5\xe5\x07\x6f\xab\x9f\x4a\x9e\x6e\x19\x29\xa3\x48\x08\x36\xde\xa0\x7b\xa4\xd6\x3f\xce\xfc\xe5\x54\x34\x30\xa8"}, -{{0x5c,0x48,0x3e,0x83,0x7e,0xb0,0x1e,0xd5,0xa4,0xad,0x5d,0xb3,0x79,0x26,0x99,0x82,0x4d,0xf1,0x3e,0x57,0x6b,0xe9,0x67,0xd1,0x21,0x15,0xc8,0x5e,0x02,0x86,0xe6,0x28,},{0xfe,0x1a,0xa8,0xb0,0x69,0xda,0x56,0xe6,0x76,0xef,0x3a,0x57,0xd9,0xbb,0xa8,0x83,0x05,0xea,0x03,0x28,0x08,0xee,0x63,0x52,0x73,0xb3,0x7c,0x5c,0x63,0x5d,0xef,0x4e,},{0xc1,0x7c,0x2f,0xbf,0x8c,0x00,0xbc,0xea,0x30,0x35,0xbf,0x0a,0x62,0xd3,0x02,0x29,0xdb,0x74,0x2c,0xab,0x11,0x99,0x67,0x7c,0x7e,0xb4,0xeb,0x0e,0xf5,0xc7,0xb5,0x1a,0xd4,0x87,0xa4,0x97,0x1b,0x63,0x1e,0x79,0x4a,0x58,0xbb,0x08,0x23,0xcc,0x0f,0xe6,0x26,0x10,0xfd,0xa6,0xa9,0xe0,0x3f,0x8c,0x4c,0x33,0x81,0xcb,0x15,0x4c,0xef,0x0b,},"\x58\xd5\xe2\xcd\x89\x9b\xa9\x85\x37\x8b\x3e\xc3\x3e\x9a\x86\x98\x22\xb2\x3d\x5d\x89\x6a\x28\xf4\x24\xfc\xd6\xe4\xcc\x28\xb8\x0d\x4a\xaf\x2d\xe8\x04\x36\x7e\xfd\xf5\xe4\x23\xb1\x23\x4d\x82\x1d\x63\xac\x05\xea\xed\x12\xc7\x3e\x8e\x36\x08\xaf\x0d\xdc\xcc\x83\x86\xb7\xd8\x42\xb1\x2e\x60\xd3\x0c\xed\xe3\x25\x53\x94\x5e\x78\x29\xe9\xb2\x3f\x5c\xcc\x2e\x71\x03\xa0\x8f\x2c\xdd\x9e\x75\xa7\xb3\x6f\x5e\x63\x72\x0e\xf0\xd4\x9b\x25\x92\xbe\xf3\x74\x02\x68\xc8\x9c\x86\xa6\xcb\xdf\xe2\x01\xde\x0d\xb9\x98\x5c\xeb\x19\x39\x9c\x9a\x1d\x5b\xb0\x58\x6a\xf3\xc8\xcd\xf2\x71\x32\x99\xeb\x04\x43\xa5\x41\xa4\x73\x84\x60\x72\x43\xc5\x4a\x05\x91\x50\x58\x36\x7d\x3f\x2d\xb3\x80\xed\x31\x7a\x8c\x12\xc7\xa6\x3e\x80\x9c\x2e\x84\xd4\xac\xb9\xd9\xee\xf5\x4c\x6f\x5a\xf7\xab\x59\xcb\x91\x68\xb1\x06\x8f\x9d\x2c\xcd\x97\x8f\xe7\x21\xba\xd6\x8a\x66\x9f\xfe\xde\xa3\xe9\x2c\x76\xb3\x2e\x31\x66\x65\x8e\xe3\xbd\x0d\xeb\x1b\x08\x41\x94\xce\x35\xd9\xa7\x41\xc5\x7f\xc2\x24\x1e\x68\xef\xaa\x65\x32\x0b\x23\xa1\xdd\x19\xea\x8b\x7e\xc8\x1e\x76\xf1\xe9\x16\x3f\x95\x92\xee\xee\x5a\xf8\xec\xed\x02\x72\xf3\x35\x12\xd0\xd4\xca\x06\x7f\x05\x55\x1b\x26\x53\x96\xe1\x00\x14\x78\x3c\xac\xac\x79\x43\x7b\x19\x84\x2d\xe6\xab\x91\xb9\xd9\x23\xbb\xeb\x50\x33\x25\xbc\x54\x86\x9f\x66\x3e\x6e\xa4\xae\x68\x97\x70\x1b\xe7\xe1\x1d\x16\xcd\xfa\xe0\xee\xe8\x61\x86\x20\x00\xe7\xa4\x16\x07\x81\x54\x7e\x42\x52\x6a\xf5\x1b\xa9\x69\x8d\x23\x4a\xaf\x51\x0d\xa8\x1a\x0d\xbf\x26\x43\x66\x15\x3d\x7a\x6d\x5e\xb3\xfb\x08\xb9\xbb\x5e\xa0\x65\xc2\xf5\xe5\xb6\xbb\x67\x9d\x2e\x21\x0b\x5b\x40\xe2\xbc\x82\xf7\x8d\xc9\xab\x58\x24\xb7\x4a\xad\xad\xd8\x9b\xf8\xa8\xb7\x3a\x0a\x2f\x43\xac\x74\x83\x78\x92\x1a\x73\xa2\x52\x70\x4a\x4a\xdb\xf7\x40\xcb\x99\xc1\xe1\x59\x4c\x37\xac\x9a\xcc\x19\xf5\x23\x15\xc6\xa8\x46\xa5\x7b\x36\x12\x8c\x64\xd7\x67\xaf\x44\xe9\xc8\x63\x05\xbf\x18\xba\x7c\xd5\x26\x80\x52\x3a\x3b\x10\x2f\xba\x6f\xe5\x55\x67\x06\x9d\x20\x47\xcb\xdd\x96\x05\xea\x12\xc8\x87\x7d\x39\x9c\x1e\x66\xe3\x38\x17\x73\x1f\x50\xb8\x4f\x81\x7d\x1f\x07\x60\xa4\x0f\x97\x46\x86\x18\x93\x41\x05\xeb\x00\xec\x50\xc7\x6d\xb3\xc5\x3f\xcf\x43\xfe\x17\x02\x90\x7d\x9a\x75\x6b\xcf\x43\x9f\x88\x31\xd0\xbf\xac\x92\xe7\x05\x8f\xb1\x57\xbe\x3e\x59\x1d\x37\xeb\x34\x16\x5e\x3c\x6f\xc6\x0e\x72\x29\x4c\x08\x3e\x47\x76\x26\xf9\x00\x1c\x1d\x73\x7c\x29\x03\x77\xdf\xa5\x8e\xa4\xea\xd3\x02\x8f\xc7\x62\xce\x8a\x3a\xfe\xc2\xe6\xe1\x32\xc6\x62\xdf\x60\x34\xab\x55\x4f\x93\xef\xac\x65\x7a\xd3\x4f\x61\x07\xd3\x47\xfc\x5c\x5e\x53\xf3\x73\x3e\x17\x8b\x76\x01\x4d\x2f\x9b\xbd\x06\xef\x2d\xfe\x60\xe2\x08\x3d\x88\x65\xf7\xf5\xb2\xac\xc0\x25\xd9\x12\xe5\xcf\x6c\xda\x6e\x79\x81\x43\xe9\xdb\xbc\x70\xa0\x21\x1d\x8e\x40\x03\xd7\x8b\x38\x3d\x66\xa6\xad\x29\x71\x7c\xa2\x4e\xdd\xef\x7d\xf7\xcd\x3a\x7e\xf6\x52\xab\xa5\x48\x7a\xfe\x5d\x02\x6c\x9b\x10\x28\x07\x29\x4e\xb2\x7d\x98\x24\xee\xb6\xb4\x0f\x08\x3d\xe7"}, -{{0xb0,0xd0,0xab,0xdd,0x84,0x44,0xe1,0x0f,0x29,0x37,0x54,0xac,0x9f,0x16,0xe3,0x1b,0xdc,0xdd,0x97,0xb7,0x06,0x71,0x28,0xaa,0xe8,0xe4,0xd7,0xf1,0x12,0x89,0xe2,0xcd,},{0x1c,0x78,0xcc,0x01,0xbe,0xa1,0x53,0x52,0xb6,0x3c,0x56,0x97,0xf1,0xcf,0xe1,0x2f,0xfd,0xd1,0x6d,0xdc,0x1d,0x59,0xe7,0x79,0x51,0xb6,0xe9,0x40,0x8e,0xe2,0x28,0xad,},{0x64,0x40,0x8b,0xdd,0x2d,0x0f,0xc8,0x92,0xa5,0xb6,0x2b,0x5a,0xcf,0x8e,0x3b,0x3c,0x73,0xc0,0xb5,0xc4,0xfa,0x2a,0x72,0xe3,0x9d,0xd6,0x08,0xd4,0x93,0x7f,0x93,0x32,0xf7,0x3e,0x14,0xd0,0x8b,0xad,0xc6,0x27,0x01,0x14,0xd1,0xf1,0xa5,0x56,0xcc,0x6e,0xe8,0x48,0x8a,0xbb,0x90,0x7f,0x79,0xae,0x17,0x5c,0x35,0x2e,0x9f,0x11,0xee,0x05,},"\xaa\x27\x6c\xc5\x43\xfc\xc6\x2d\x70\xa7\x04\x60\x8d\x98\xce\x51\xb6\x45\xb5\xc2\x4a\x64\x0a\x5d\xf1\x0a\x55\x91\x41\x7d\x10\x89\x26\xdf\x3f\x0c\xe1\xb9\x21\x03\x33\x09\xeb\x8d\x86\x59\xf4\x89\xfd\x6f\x79\xaa\x1b\xf4\x88\x2d\x72\xac\x69\xcc\x58\xd3\xbc\xe0\xfa\x89\xb1\x64\x11\xe9\x75\x3e\xb4\x0c\x6c\x4d\x59\x8d\xc8\xf4\xab\xb0\xbc\x48\xf1\x37\x03\x71\x32\x6c\x9a\x86\xbb\xc2\xac\x62\x14\x47\x8e\x78\xa3\x84\x08\xbd\xda\xfa\xa9\x59\x26\x00\xc4\x9a\x12\x9c\x05\x39\x2f\x8a\x7d\x64\x2b\x49\x13\x7a\x20\xf3\xfe\x9f\x11\xee\x17\xcf\xa3\xaf\xd2\xaf\x71\x56\x5e\x9c\x40\x08\x0b\x60\xcd\x0d\xbc\x37\x8e\xda\x06\x2c\x7c\xbc\x7f\xe9\x72\xbd\xe4\x50\x9a\x1d\xe9\x5f\x14\xdf\x48\x2f\x48\xaa\xcc\x46\x3c\xd5\x94\xf6\x6d\x64\x8d\x37\x94\x73\x8a\xd6\xab\x49\x6e\x2d\xa5\x0b\x0d\xb2\xba\x7b\x65\x91\x85\xe4\x58\x7f\x18\x2e\x83\x3d\xe7\x50\xfa\xac\xdd\xf2\x1a\xf5\xe0\xcf\x4c\x9a\xf3\x85\xb0\x4f\x7b\xe2\x31\x49\x8a\xd0\xb7\x42\xd5\xa8\x7c\x06\x11\x5d\xb2\x30\x97\x3a\x51\x42\x7f\x20\x2f\xa3\x9a\xfb\x98\x28\xb5\xf0\x3f\xa3\x27\xcb\xd5\x2d\xfe\xc6\x6d\x71\xea\x31\x98\x65\xdc\xf6\x81\x0f\x18\x58\x47\x2d\x8b\xea\x3e\x44\x7a\xdf\xb4\xb6\x07\x58\xe8\x6b\x48\x13\x37\x09\x73\x2d\x2b\xcf\x51\xc7\x6c\xaa\x84\x7b\x65\x37\xfc\xb0\x5b\xb8\xc8\x7d\xc5\xe9\xfb\x02\x2b\x32\x60\xc1\xd7\x1b\x14\x98\x59\xc9\x66\x3d\xbd\xae\x6a\x7b\xbf\xd6\xde\xb9\xd1\x23\x80\x9c\x24\x14\x01\xaf\x10\x71\x9c\xf9\x1a\x6b\xed\x16\x08\x4c\x44\x46\x07\x35\x9e\xd8\xf0\x18\xdb\x11\x15\x11\x89\x2b\x46\xbd\xac\x6c\x9c\x61\x38\x41\xde\xd8\x86\xb9\xde\xc0\x6c\x01\xe8\x04\x87\xe4\x8f\xbe\x77\x8e\x9e\x97\x50\x8f\xfd\xa0\x57\x78\x53\xaa\xbd\xca\xca\x8b\x0b\xab\x6c\xe4\x15\x57\xaa\xb9\x63\x1c\x96\xd6\x09\x77\xe3\x57\x18\xb6\x05\x95\x27\x3f\xdb\xa1\x40\xf5\x50\x0a\x8d\x35\x76\xf5\xa9\xfc\x8f\x3c\xa4\xc0\x2c\x16\x7a\xf2\xe0\x3d\x25\x75\x0b\x42\xad\xb0\x3b\x14\x17\xf2\xb6\xd2\x19\xbe\x5f\x84\x29\x33\x1a\x26\xa4\x49\xb5\xd4\xdb\x2b\x1a\x09\x15\x2e\xea\x2b\x25\xd2\xdf\x7e\xf6\xfe\x0a\x32\xe2\x5f\xae\x79\x36\x0a\x9a\xee\x15\x11\xfd\xa8\x06\x45\x50\x93\x7a\x71\x30\x97\x19\x30\xc6\x73\xbb\x35\x8e\x5f\x55\x95\x1f\x50\xb1\x46\xd8\x5d\x38\x3f\x3e\x01\xc1\x51\xec\xe6\xc0\x6d\x83\x67\x01\x25\x32\x80\xfd\xcf\xf4\xe1\x39\xd3\x31\x9a\xb2\xe2\xca\x71\xbc\xc3\xfa\x0f\xaf\x7c\x70\x2c\x9c\x60\x4e\x56\x51\xde\x4a\xf5\x70\x0e\x9e\xde\x72\x58\xb9\xbc\x14\x8d\x55\x95\xcd\x34\x17\x0e\x3e\x5c\xf2\x92\x82\x83\x90\x90\x8f\xda\x96\x1f\x22\x30\xac\x0b\x8c\xac\x64\x73\x97\x32\x70\x6c\xe2\xd5\xe5\x9a\xbd\x6d\x5e\x20\x7b\xda\xfe\xa7\x4d\x28\xd7\xa7\x58\xf2\x20\x0e\x4e\x00\xa0\xbc\xf0\x30\x6a\x3c\xab\xda\x47\x02\x4f\xab\xea\xe4\x88\xab\x5c\x32\x37\x15\xcf\x3c\xa7\x72\x0a\xf9\xeb\xbf\x85\x82\xe1\x15\x8a\x09\x9d\x73\x6b\x56\x9b\x9d\x40\x29\x58\x17\xea\x25\x54\x06\x8b\xef\x32\x44\x2c\x11\x1e\xc8\x14\xc6\xed\x41\x59\x19\xba\x73\x52\x63\x34\xdf\x30\xba\xc6\x66\x08\x4e\x56\x01\xc2\x28\x1c"}, -{{0x49,0x84,0x97,0xfd,0xcc,0x6a,0x10,0x58,0x91,0xe0,0x23,0xff,0x32,0xd7,0x5f,0x7c,0x37,0x48,0xd8,0xc5,0x2d,0x87,0xdd,0x3b,0x27,0x75,0xae,0xfd,0x81,0x60,0xa1,0x43,},{0x2d,0x79,0xae,0x9c,0xee,0x4a,0xc6,0x27,0x5b,0x05,0x74,0x9c,0x43,0x8e,0xbe,0x55,0x2b,0x41,0x3d,0x87,0x3c,0xc0,0x7f,0x14,0xf5,0xfa,0x13,0x01,0x77,0x21,0x4c,0x54,},{0xb0,0xa3,0x6a,0x2c,0x93,0x47,0x56,0x34,0x8e,0xb4,0x7c,0x25,0xa3,0x2c,0x3f,0x2a,0x5d,0xdb,0xd5,0x8f,0xcc,0x72,0xa0,0x8c,0x3c,0xea,0xd1,0xa2,0xd9,0x00,0x33,0x5c,0x30,0x01,0xe3,0x5b,0xfe,0x1f,0x3f,0xb5,0xa5,0x55,0x00,0x9b,0xa8,0xe9,0x68,0x74,0x49,0x4b,0x97,0xe8,0xb0,0x97,0x00,0xed,0xcb,0x1f,0x25,0x84,0xb9,0xd0,0xfe,0x03,},"\xbe\x38\xbc\x8c\xdf\x46\x19\x0e\x30\x4a\xb5\x3d\xd2\x9c\x2b\xc4\x09\x54\xfd\x4c\x6d\x2b\xb9\x90\xf9\x3b\x2b\x5c\x69\x1f\xdf\x05\x27\xc2\x60\xf5\x06\x61\x87\xf2\xd0\xf3\x1f\x43\xa0\x8b\x36\x0e\xa1\xed\x82\x00\x65\x17\x64\xb8\xfa\x49\x59\x5a\x15\x94\x10\x9e\x49\x67\x59\xab\x66\x23\xfa\x33\x37\x8d\x80\x0e\x61\x17\xe0\x79\xe1\x3f\xe8\x5c\x81\xb6\x3e\xbe\x24\x7b\x3d\xf6\xc1\x58\x4b\xc7\xcf\xfb\xdf\xa4\x5f\x2a\x2c\xe7\xc2\x37\xaa\xaf\xef\x8c\xbc\xa7\x0b\xca\xbc\xe0\xb8\x47\xd5\x51\xf4\x6a\x7d\x15\xce\x2a\x0d\x3d\x54\x5a\xba\xcc\x59\x30\x01\x0c\x53\x64\x88\x87\xd4\x76\xe0\xd1\x3a\x34\xfc\x1c\x54\xdf\x09\xd1\x06\xed\x75\x8d\xee\xdc\x76\x1d\x55\x7a\x73\xb2\xbc\xdd\xde\xfb\xa4\xed\x00\x59\x97\xb1\x92\x79\xb9\xd2\xde\x37\xd0\x41\xfe\x01\x3e\xef\x05\xa2\xe1\x1c\x9a\x23\x4e\x87\xcc\x0e\x16\xc0\xc6\xda\x42\xaa\xa5\xbf\x99\x64\x17\xbf\x64\xe5\xb7\x85\xd6\x7d\xc3\x25\x47\xc1\xf0\x52\x17\x8d\x69\x4c\xf2\x0f\x16\x98\x58\x9e\x7e\xd4\x9b\xe2\x9d\xd5\x9f\xd5\xc0\x1b\xa1\xd9\xf5\xfb\x06\xa7\x58\x95\xb7\xb1\xe1\x58\x95\x09\x7e\xbd\xe8\x4c\xad\x63\x03\xaa\x0a\x86\xdb\xc3\x24\x74\x7d\x97\x24\x5d\x70\xc5\x20\x3b\xe0\x1b\x06\xcb\xde\x06\xae\x03\x72\x04\xd2\x37\x30\xcd\x69\x61\x89\xf7\xac\x26\x7c\xf2\x02\x17\x99\x29\xce\x54\x10\xe0\xe3\xad\xe5\x13\xd2\x20\x1b\xfd\x20\xfe\xfa\x40\xb4\x47\x6f\x27\xbf\x90\x7c\x76\x2e\xb7\x26\x2a\x5b\xe1\x3c\xfc\x04\x7a\x84\x6d\x20\xa9\xf2\x31\x1b\x64\x69\xb0\x6a\xb5\x45\xf0\xec\x9f\xc4\x46\xea\x25\x0c\xd3\xb7\x3a\x7b\x6b\x96\x0c\x10\xca\x4c\x2d\x6c\x64\xa1\x56\xa1\x8c\x9f\xb8\x10\xe4\x9a\xfd\x0c\x36\xda\xab\x8b\x8b\x85\x66\x43\xa4\xcc\xaf\xa9\xad\x88\x6e\x91\xe5\x44\x53\x5b\x8e\xdd\xa2\x7c\x90\xc0\x6a\xb6\xbc\xc5\x36\x28\xbe\x18\xd7\xd6\x36\x9c\xa1\x80\x1f\x91\xc2\xe0\xb9\x5f\x36\xd7\x02\xf7\x72\x34\xb4\x10\x07\x19\xc0\x59\x95\x1e\x45\xb1\xf9\x16\x98\x39\x34\xe3\x2b\x4d\x4d\x8f\x29\xc0\xa3\x73\xf8\xd8\xf0\x91\x8b\x96\x78\x65\xcd\x0e\x4b\xec\xa0\x13\x27\xc9\x9d\x5f\xde\xd4\xc1\xa6\x9a\xc2\xd4\xd9\xb7\x8f\xfb\x83\x05\x67\x00\x21\x04\x02\x50\xcc\x27\x73\x7e\x75\xdf\x75\x76\x0f\xec\x8b\x8d\x30\xb2\x45\x65\x4f\x3c\x12\xf1\xf7\xce\xa0\xbc\xe7\x8a\xb3\x69\x35\x78\xaf\x3e\xa6\x1f\xfc\xcd\xf9\xba\xf7\xc3\xea\x65\xb8\x8f\xc8\x54\x12\x81\x26\x47\x67\x96\x89\x2c\x66\x3b\xd1\x45\x18\xc9\x91\x86\x29\xa1\x09\x5f\x61\x4e\x04\x92\x44\x6c\x3d\x84\xb1\x6e\xc9\x4f\x7e\xca\xda\xeb\x6b\x65\x9b\xbb\x48\x67\xb5\x79\x06\x17\x14\xfd\x5b\xb0\xfa\xa4\xad\x6b\xe0\xff\xb3\x88\x8b\xea\x44\x7e\x4e\x34\x38\xc8\xf0\xea\xe6\x44\xfb\xd4\x5a\x38\x02\xdc\x40\xec\x45\x1b\x21\x2b\xd5\x92\xda\xcd\x4d\xa9\x66\x86\xdc\x8b\x20\x24\x25\x7f\x25\xe9\xc8\x30\xbf\xf7\x95\xee\xe8\x5d\x87\xa0\x90\xc1\xa4\x23\x21\xe7\x10\x55\x57\x64\xed\x82\x57\xc9\x41\x5c\x7f\x22\x4b\x53\x75\x58\xce\xfd\xc6\x15\x12\x9f\x28\x35\x02\x67\xc0\x1b\xa0\x40\x3e\x07\xf5\xc6\x06\x7f\x91\xc8\x5a\x2c\x50\xc8\x66\xdc\x43\x88\xaf\x38\xd2\x16\x02\x03"}, -{{0xd9,0x62,0xa6,0x71,0x9e,0x5c,0xc7,0x72,0x4c,0xa4,0xa1,0xd5,0x59,0x53,0x68,0x12,0xb4,0xe2,0x2a,0xa7,0xbc,0xb1,0x3e,0x4f,0xb1,0x72,0x2d,0x28,0xe0,0x45,0x21,0x7c,},{0xa9,0x44,0x59,0x2d,0xbc,0x7d,0x77,0x03,0x9d,0x72,0x02,0x56,0xc3,0xfd,0x34,0x0d,0x34,0xdb,0x89,0x2a,0xb1,0x3e,0x48,0x12,0xd6,0x62,0xe2,0x84,0x0c,0x28,0xb6,0xd0,},{0xdf,0xb9,0xb6,0x35,0xac,0x0e,0xdf,0x83,0xb7,0xb5,0x9d,0x0b,0x84,0x09,0xaf,0x47,0x5f,0x66,0xfc,0x99,0x46,0xaf,0x0b,0x7c,0x63,0xab,0x8c,0xf5,0x92,0x9d,0x47,0x01,0xa1,0xbf,0x66,0x95,0x9c,0xde,0x62,0xfb,0xcf,0x59,0xa4,0x8a,0xb3,0xbb,0xaf,0x0b,0x9a,0x61,0xb6,0xe0,0x0b,0x21,0x81,0xeb,0x93,0x42,0x82,0x07,0x0a,0x5d,0x53,0x00,},"\xa6\xaa\x7a\x19\x0d\x00\x3a\xb1\x75\x33\x2b\x8f\x58\xe7\xca\xeb\x69\x08\x54\xd9\xdb\x56\xdb\xb6\x95\x7b\x3f\xb6\x54\xe2\xe0\xda\x99\x1f\x31\x54\x21\x42\x04\x13\x5d\xf1\xe1\x10\x43\x17\xc9\xe3\xc5\x8e\xed\xff\x1f\xc6\x1a\xba\x57\x74\x4c\x0c\x7e\xf4\x86\x00\x0a\x70\xb2\xc1\x42\xeb\xad\xdc\x07\xab\x06\x5e\x2a\x85\x5d\xaf\x19\x8a\x68\x03\xac\x24\xef\x37\x24\x48\x7c\x13\x51\xdd\xed\xa0\x51\x39\x13\x45\x7d\x76\x86\x0d\x78\xa9\xb6\xbc\x3d\xba\x66\xc4\x0e\x5f\xc3\x49\xa8\x73\xad\x60\x65\xce\x7d\x7f\xdc\x2c\xc4\x83\xb3\xae\xfb\xf2\xf0\x3d\xd6\x69\xbd\x9c\xb8\xf6\x3c\xee\x47\x78\x5c\xac\xb0\x9d\x87\x2c\x9a\xeb\x83\xe9\x86\x84\x05\x25\x43\x24\x03\x79\x82\xe0\x86\x13\x45\x5d\x95\x21\xd8\x8e\xa2\xfd\xa0\x20\xbe\x73\x0c\xfc\x8c\x07\xcb\x0b\x37\x61\x4c\xcb\xa2\xfa\x3e\xc4\x98\xb8\x15\xbb\x5a\xdb\x99\x6e\x84\x8b\x38\xc0\x15\xa6\xa5\xc7\x52\xeb\xda\xc7\xb9\xee\xd8\xb6\x96\x19\xd8\xc8\x46\xb6\x6f\x78\x16\xd1\xdf\x1e\xbc\x21\x07\x1c\xef\x0b\x25\x1e\x2e\xab\x59\x82\x7f\x6d\x60\x55\x08\x43\x70\xfd\x27\xc2\x03\xe8\x6a\x18\x9f\x1e\xe1\x1e\x84\x03\xab\xdc\xbd\x1f\x45\x34\x1a\x82\x05\x25\xd8\x63\x7d\xc4\x84\xa5\x18\x5d\x65\x51\xcb\x88\x2a\x96\xb9\x98\x1a\x5f\x1a\x82\x1f\x27\xb6\x56\xff\xf9\x0e\x7f\x69\xbf\x28\x6f\x75\x2f\x97\x0f\xfc\xa5\xc5\x3e\x08\x50\xb2\x0b\x94\xf9\x43\x16\x27\x09\x4a\xce\xa9\x12\xa8\x80\xb7\x49\xa6\xf8\x0b\xb2\x06\xcc\xaa\x74\x6f\xa7\x0c\x83\x3c\x9f\x32\x30\x89\xce\x05\x58\xc9\xdc\x20\x0d\x57\x39\xd1\xe4\x99\x63\x4f\x2c\x16\xe5\x4b\x7f\x6d\x78\x19\xc4\x70\x71\xb6\x0b\xd5\x4d\xd0\xf2\x73\xa3\x19\x75\x0f\xd3\xc5\x10\xa4\x9a\xb5\x6f\x63\x0c\x7c\xe6\xd8\x02\x3d\x97\x86\x23\x46\x85\x9b\xc0\xb4\xd6\x05\x22\x49\x69\x70\x89\x03\x76\x03\x01\x40\x9c\x60\xab\x25\x17\x56\x11\xf0\xbe\x98\xb2\x3a\x8c\xd8\xac\x53\x5e\x35\x13\xbc\x77\xe1\x45\x21\x93\xda\xdf\x44\x35\xe6\x3c\x36\x29\xb6\x66\xa5\xea\x4c\x4b\xad\x36\xea\xca\xd2\x60\x14\x04\xea\xbd\x8d\x9a\x07\x95\x6e\xc2\xb4\xb7\xbb\x63\x36\xed\x75\xb8\xdf\x8f\x16\xde\x42\xc0\xfc\xae\x93\x65\x2e\x3c\x40\x7c\xbd\x45\xe8\xd4\x13\xef\x51\xe8\x54\x2d\xf6\x25\x12\xee\x79\x3e\x41\x35\x8a\x1d\xe1\x92\x46\xc6\x58\x6b\x3c\x14\x07\x41\x04\x21\xf6\xe8\x65\xc7\x5a\x9f\x4a\x6a\x47\x88\xf8\x4a\x9c\x78\x1d\x8f\x80\x24\xbf\xdb\xe2\x5b\xdc\x7d\x4b\x69\xcb\xaa\x77\x19\x62\x8c\x0b\x07\xec\x2c\x4a\x23\x4f\xff\x4a\xc3\xd4\x93\x5b\x9c\xe4\xc8\xa1\x69\x47\xab\xe7\x95\x1f\xf8\xd9\xac\x92\x15\xe3\x38\xfa\x0f\xe9\x12\x41\x76\xd1\x7b\xac\x1e\x05\x59\x2c\x43\x98\x68\xae\x5a\x4f\x75\xfd\x1e\xa8\x2a\xa4\x54\xc2\x0a\x93\x9d\xed\xa7\x29\xa0\xe1\x96\x46\xce\xbd\x82\x20\x49\xc8\x25\xc7\xe3\x1c\x6e\xfa\xd4\x5e\x30\x6f\x2d\x9f\x05\x69\xe0\x71\x73\x31\xf4\x80\x04\xc2\x6e\xbf\xe6\x8f\x38\x43\xe9\x0f\x80\x67\x03\x2d\x21\xe7\x86\xc8\x53\x9e\x01\xbe\x3c\xea\xc5\x95\x4a\x05\x46\xc8\x4b\x73\x4d\x99\x94\x56\xa7\xc4\x5f\x8c\xeb\xaa\x47\x8e\x54\x80\x07\xf9\xd3\xaf\x83\x6f\x75\x4d\xe4\x12\x3f\x2f"}, -{{0xe1,0xd1,0x41,0x65,0x18,0x92,0x1d,0x07,0xc8,0xc3,0x9e,0x29,0x73,0xd8,0xea,0x12,0x49,0xca,0xa8,0xbf,0x65,0x9c,0xc3,0x6c,0x79,0x37,0xf8,0x4e,0xce,0x7a,0xd4,0xfc,},{0x48,0xbd,0xcc,0x3f,0x1a,0x5b,0x80,0x58,0xed,0x9a,0x32,0xef,0x1c,0xc4,0x8c,0xf7,0xa8,0xab,0x76,0xa6,0xe4,0x51,0x9e,0x5a,0x82,0x85,0x52,0x41,0xad,0x6f,0xff,0x8a,},{0x42,0x32,0xd2,0xa4,0x81,0x08,0x4d,0x11,0x96,0xdb,0x62,0xf2,0x2d,0xc7,0x4c,0xf2,0xea,0xf2,0xdb,0x0d,0xf0,0x5a,0xd7,0xcd,0xde,0x67,0xbf,0xc2,0x9b,0xff,0x56,0xcd,0xe0,0x19,0xac,0x9f,0x03,0xd8,0x1f,0x18,0x27,0xeb,0x1e,0x3b,0x0a,0xbe,0x02,0x04,0xca,0x7f,0x77,0xfa,0x87,0x4a,0xb5,0x26,0x83,0x54,0xff,0x08,0xbb,0x7f,0x48,0x00,},"\x3d\x26\x3d\xe1\xab\x91\xe8\xdd\x7b\x31\x7f\x7a\x27\xfb\x60\xa6\xe1\x83\x8c\x0c\x79\x3b\x03\xab\xbe\x70\x82\xb6\xbd\xa0\xc7\xc4\x60\x62\x26\x21\x92\xc8\x8b\x65\xc0\x26\xc1\x74\x58\x4d\x29\x64\x97\x10\x42\x9a\xe4\x4a\x46\x14\x0b\x4c\x82\xc8\xa0\xb7\x4d\x56\xa0\x04\xf8\xe2\xf5\xc1\x8f\x84\xf0\x46\x41\x53\x77\x2f\x83\x12\x63\x3f\xc6\xad\x28\xa7\xd9\xfb\x55\xf7\xd7\x8c\xd6\x48\x8c\xa5\x81\x17\xea\xf9\x23\xfa\x28\x87\x5e\x2b\x31\x89\x89\x31\x85\xaa\x3c\xcd\x04\x4d\x3f\x11\x0e\x2e\x7c\xab\xdf\x6f\x81\x4b\x9f\xdd\x67\x33\xbd\x5f\x30\x7a\x87\xbc\x73\xb6\x25\x0d\x58\x83\x93\x6d\xeb\x1d\xb0\xe0\xaf\x1b\xe7\xab\x32\x9b\x5c\x6b\xd9\x35\xbd\x8f\x8d\xc8\x88\xf0\xd1\xc4\x64\xed\xbc\x02\x3c\xbc\x08\x07\x53\xee\x8f\x79\x9f\x10\x72\xba\xd1\x14\x4d\xfa\xa6\x15\xa5\x9e\x2a\xed\xc6\x62\xe8\x3c\xb1\xf8\xe5\x20\x96\xa7\xee\x48\x3b\xf8\x73\xb2\x5a\x0c\x04\xc1\x85\x1a\x0e\x87\x37\x50\x63\xaa\x1a\x94\xfa\x83\x5c\x05\x26\x40\x36\x6b\x79\xf7\x35\xd3\x28\x61\x97\xab\x32\xeb\xdb\x51\x23\xf6\xb4\x7a\xd3\xf4\x42\xc4\x4c\x53\x0a\x68\xf8\x51\x27\x59\xe9\xcf\x38\x6f\xba\x07\xb8\x06\x4b\xc8\xfe\x83\xe2\x45\x49\x5e\xc4\x5f\x89\x38\xf8\x25\x9d\xc8\x01\x62\x05\xf7\x8d\x39\x54\x44\x2e\xc1\xb4\x45\xd8\x3d\x95\xad\x18\x05\xa5\xe0\xe8\xb3\xd5\x6b\x87\x0a\x20\xda\x18\xd7\x4f\x26\xf5\x50\xa9\xc7\x53\x4a\x41\x44\xdc\xbc\x1c\x3c\xdb\xbe\x47\x0c\xc1\x53\x90\x50\x43\x08\x8f\xac\xf1\xd3\x03\x55\x9d\xe4\x1e\x96\xc0\xab\x40\x9b\xb3\x6d\xcf\x38\xcc\x90\x38\xa6\xa4\x90\x8d\xea\x82\xa6\x53\x19\x5c\x16\xf2\x90\xa7\xc3\xac\x48\x76\x36\xcc\x5b\xcb\x18\xd1\x5a\x14\xac\x62\x4c\x70\xb6\xf6\x46\x2b\xf2\x49\xe0\x00\xce\xe9\x24\x01\x8b\xdf\x7d\xde\x39\x11\x4c\xb4\xf6\x52\xe1\x22\xe8\x74\x4d\xa2\x8b\x05\x89\xe1\x28\x4d\x70\xd9\xf1\x06\xde\x16\xd0\x73\x64\x80\x80\xe6\x43\x7f\xf3\x84\xe6\x81\x77\xd5\xcb\x71\x8e\x2c\xe3\xf1\x7b\xa1\xe9\x90\xae\x3c\xe9\x40\x66\x01\x30\xe9\x37\x50\xb8\x2e\x2f\xb4\x1a\xa3\x69\x77\x45\x68\xd7\xcf\x28\x67\x25\xe3\xc5\x8f\x63\xe7\x3f\x86\x97\xae\xec\xc7\x17\xc5\xcf\x1a\xf7\xad\x74\xf4\x46\x29\x2c\x90\x5d\x84\xe2\x2b\x23\xd4\xe0\xd2\x60\x4b\xff\x48\xfe\xfc\x40\xc6\x20\x4b\x5e\x34\xc0\x42\x29\x2e\x53\xbe\xc9\x36\x01\x59\xa5\xcd\x97\xb2\xdf\x57\x86\xb8\xf5\xa2\x92\xc0\xb3\x9d\x14\xa8\x70\xa4\x58\x8e\x67\xbd\x12\xb2\xc2\xf7\xa4\x40\x84\x62\x85\x1d\x2a\xa7\x87\x97\x1d\x93\x15\x19\x0f\x42\xcc\x58\x8a\xf0\xd2\xdc\xd9\x1f\x31\xbb\x71\x5e\x92\x50\xf1\x19\x28\x14\xf7\xb8\xa2\x1f\xef\x45\x17\xb0\xcf\x8b\xb8\xa1\xa1\xa5\xf5\x00\xee\x21\x9d\xfb\x46\x13\x2e\xfe\x8e\x90\xbc\x49\x09\x3a\x55\x59\xf9\x68\x1b\x4f\xb5\x9e\x5b\xa9\xef\x3f\x05\xd3\x4e\xed\x03\x4c\x14\xd7\x7e\xe9\x5e\xbd\x76\xff\xa5\xaf\x0b\xef\xcb\xa1\x8f\xdf\x93\x2a\xf4\x85\x45\x10\xb7\x5d\xb0\x0a\x72\x57\xb2\x34\x88\x7d\x49\x60\x7d\xfd\x16\x18\x0d\xb5\x16\xc7\xa2\x0c\xcf\xca\xed\xa6\xae\xdf\xb6\xa2\x37\x7f\xbf\x31\xe6\x7b\x51\x76\x55\xdb\x73\xca\x29\xe1\x18\x62\x4d\x60\x80"}, -{{0x2b,0xf7,0x4f,0x00,0x4d,0x7d,0x0a,0xf7,0x3a,0x83,0xea,0x20,0x8c,0xc2,0x06,0x72,0x3d,0x18,0x8f,0x4c,0xf6,0x07,0xbc,0xad,0x4b,0x69,0x80,0x26,0x8f,0xf2,0x1f,0xa7,},{0x8f,0xdc,0xd9,0x93,0x52,0x43,0x8b,0xeb,0x52,0xf0,0xd1,0x74,0x2b,0xae,0x71,0x84,0x45,0x12,0xdd,0x06,0x85,0xaa,0xf1,0xc9,0x09,0xe3,0x8f,0xc4,0xb5,0xaa,0xb6,0xcc,},{0x3e,0xb5,0xb3,0x39,0xe1,0x91,0xa3,0xb6,0x16,0x85,0x45,0xda,0x5f,0xb0,0xca,0x9b,0xe2,0x09,0x04,0x39,0x19,0xb9,0xc7,0x0a,0x07,0xb4,0xa7,0xa3,0xbf,0x64,0xb1,0x02,0xf6,0xff,0xd6,0xd2,0xb0,0x25,0x59,0xdc,0x68,0x1e,0xd3,0xb9,0xc8,0x22,0x97,0xb2,0x01,0xdc,0x25,0xc4,0x97,0x38,0x80,0xe1,0x55,0xe1,0x3a,0x29,0x42,0x6e,0xb4,0x0d,},"\x89\x8e\x43\x03\xea\x5b\xeb\xd2\x00\xa5\xf7\x56\x2b\xe5\xf5\x03\x26\x40\xa3\xf5\xcc\xfa\x76\x42\x92\x04\x5a\x1a\x36\x8d\x02\xaa\x59\x10\x77\xd8\xf3\x04\xf7\x4d\xbd\xfc\x28\x07\x34\x45\x4e\xd8\xc2\x72\x7a\xff\x39\x2c\x10\x8c\x52\x6e\x52\x7e\x67\x2c\x53\x97\xb2\xd7\x7c\x01\xf7\x74\x1e\xf8\xdc\xc2\x51\x0e\xe8\x41\xb5\x9d\xd1\x0f\x4e\x1d\x3a\xc5\x01\xaf\x7c\xbd\xb8\x5b\xa3\x11\x29\xc2\x62\xfd\xe1\xa0\xc8\xbc\x83\xd6\xff\x94\x4b\x6b\xae\x3f\xa7\xfb\x62\x58\x7c\x68\x1d\x8e\x34\x29\x65\xc5\x70\x5f\xd1\xa6\xab\x39\xe5\xa0\x77\x0e\xe7\x79\x8d\x9f\xb6\xc0\x01\x8a\x51\x4d\x53\xaf\x84\x8d\xb6\x04\x7c\xd0\x2d\xb3\x52\xd5\x56\x3b\x53\x66\x23\x73\xb9\x71\x93\x5a\x1a\xc2\xb7\xb6\x36\x1d\xac\x67\x48\x77\x18\x13\xf7\x74\x93\x16\x69\x49\x61\xb9\x40\xff\x38\x05\x81\x1a\x49\xfa\x27\xa9\xba\x45\x7a\xd2\x88\x48\xc6\x97\x05\x0e\x01\x88\xd0\x77\x3e\x17\xfb\x52\x19\x4e\x19\x0a\x78\x72\xa3\x98\xf3\x1c\x0f\x0a\xe0\x65\x37\xa2\x73\xff\xb5\x0c\x2c\x81\x64\x45\xab\x88\x28\x11\x92\x2c\x06\x21\x55\x6c\x46\xa3\xa0\xec\x40\xbf\xed\xb4\x11\xe9\x0b\x6d\xb1\xdd\xd4\xbb\xeb\xb5\x7d\x10\xdf\x56\x6a\x63\xd7\x26\xa3\x33\x08\x51\x4c\xe3\xb4\x99\xd5\xe5\x26\xc2\x2b\x95\x6d\x8b\x99\x91\x3d\xcb\x13\xe4\x37\xe9\x47\xb6\x66\xc4\x1c\x54\xd8\xb3\xae\x23\x56\x64\x7e\x80\x17\xab\x67\x83\x86\xc9\x27\x21\x9a\xe7\xbd\xdc\x0d\x82\x12\x65\xf9\xdc\x4f\xf3\xf8\xce\x5b\xe6\x0f\x8e\x9d\xef\xc5\xca\x33\x50\x68\xee\x29\xfe\x83\x04\x91\x7b\x78\x87\x84\xa2\x38\x8a\x32\x01\x92\xf9\x32\x5d\x0e\x6c\xff\xfe\xa2\x1e\x6e\xaa\x29\xe7\x70\x7f\x63\xa9\xea\x4f\xbb\x25\x58\xe3\xd0\x83\x5b\xab\x1f\x52\x36\x10\x37\xae\x59\xe5\x03\xee\x96\xb9\xd7\x08\xa4\x7a\x3a\xe4\xba\xd1\x13\xe2\xa4\x60\xa2\x69\xcc\xf2\x5a\x00\x03\xcb\x3e\x68\xa5\x51\x86\x4e\x59\x84\x09\x14\x79\x11\x26\xf9\x54\x78\x8b\x25\xb5\xaf\x5a\xaf\x58\x6e\xbb\x87\xfa\x5f\x37\x7b\x4d\x7d\x7f\x84\xc0\x00\xdd\x2c\xb4\x40\xe2\x14\xd3\x8d\x5e\xcf\x70\xf2\x0e\x98\x81\x82\x8e\xda\xa1\xdb\xec\x37\x09\x3d\xb9\x60\x68\x6c\xa1\x23\xf1\xec\xba\x63\x36\xb3\x7f\x46\xcf\x76\x5b\xe2\x81\x4b\x9e\x67\x05\xbc\x9d\x6a\x49\x31\x81\x18\xc7\x52\x9b\x37\xc8\x4e\xc8\x8d\x58\xa8\x45\x3d\xcb\x69\x2c\x9a\x36\x01\x6b\x94\x8e\xbe\x6f\xb2\xc1\xd0\xad\xf5\xf1\x98\xee\x30\x97\xa6\xff\x0b\x8e\xeb\xba\xd8\xb0\x76\x93\x30\xb1\x86\x89\x51\x6b\xc0\xfe\x66\x8b\x0d\x05\xe3\xa5\x84\xfc\xf8\x9c\x49\xdb\x50\x1d\x61\xc2\xde\xf7\xed\x37\x22\x07\x01\x93\xa5\xb6\x83\xc5\x08\x7e\xf2\x74\xce\x6a\x19\x3d\xd4\xa3\x03\x53\x6c\x67\x93\x4b\x46\x60\xa8\x41\xee\x1b\x44\x6a\x68\x92\xb1\x4d\x0b\x0a\xa3\xe9\x8f\xdf\xfd\x43\xc7\x97\xad\xd3\x65\x83\xf7\x4c\x94\xd0\xe2\xd6\x8e\x2d\xe8\x18\xd9\xaf\x20\x05\x98\xf0\xb2\xbe\xae\x16\x9c\x8d\xfb\xc4\xd3\x97\xe6\xd1\xce\xb6\xda\xa6\xc9\xf6\xbb\xf4\xf8\x31\x1b\xa2\x6f\xfb\x19\x4d\x44\x21\x6c\x51\x30\x52\x67\x07\x4e\x85\x6a\x1d\x6e\x92\x27\x80\xf4\x79\x8e\x2f\x22\x02\x23\xff\xf1\xdc\x37\x0c\x8e\x34\x51\x4a\xba\x42\xdf\x51"}, -{{0xf5,0xf7,0xd5,0xb7,0x3c,0x5a,0x65,0x30,0x1b,0x5b,0x4c,0x67,0x10,0xed,0x12,0xc1,0x6e,0x79,0x03,0x17,0x7d,0xb7,0x92,0xca,0x71,0x5e,0x23,0x38,0x9d,0x05,0xd8,0x3e,},{0x7c,0x47,0x62,0xe9,0x79,0xf0,0xc7,0xe2,0x07,0xbe,0x18,0x43,0xe2,0x66,0x6a,0xca,0x27,0xea,0x89,0xbf,0xf5,0xb6,0x1d,0x57,0x3c,0x98,0x5f,0xc7,0x02,0x5e,0x1e,0x28,},{0x58,0xfb,0x39,0x2f,0x82,0xd5,0xe5,0x2f,0xf0,0x72,0xcc,0x77,0xef,0xe0,0x48,0xf2,0x23,0x52,0x50,0xc7,0x11,0x25,0xee,0x82,0x1c,0x5f,0x3b,0x39,0x3b,0xcf,0x2f,0xa4,0x6b,0xe4,0xc5,0xd8,0xca,0xf1,0x3c,0xb5,0x19,0xef,0xe0,0xc2,0xfa,0xd9,0xee,0x23,0x1a,0xe9,0xb6,0xfd,0x1f,0xd5,0x09,0xc9,0x8c,0x69,0xc2,0xd3,0x6c,0x75,0x3e,0x0e,},"\x7c\x93\x18\xd5\x6e\x63\xf1\x65\x35\x43\x6f\xa4\x5a\xfe\x27\x8e\x74\xe6\x18\x81\xbb\x46\x89\x97\xd0\x41\x8b\xc7\x20\xb6\x30\xda\xdb\x81\x28\xb4\xb6\x5c\xa6\xe9\x21\xe5\x01\x81\x3d\xf9\xfe\x03\xb4\xef\x0a\xae\x80\x35\xdd\x08\xc5\xf8\x20\xce\x5d\xf1\x2e\xe1\x18\xd9\xc3\x6d\x3b\x15\x1a\x52\xc3\xf9\x6a\xe1\xca\x4c\x82\xfd\x19\xda\x66\x9d\xdb\xa9\x4f\xeb\xf8\xea\xc8\xc4\x2b\x44\x7b\xab\xc8\xa6\x0b\x36\xe8\x03\x62\x4f\x7d\x20\x47\xbd\x8d\x8a\x15\x36\x87\xf1\x0d\xc1\xca\x82\x10\x0b\x7c\x87\xd3\x23\x70\xec\x8f\x26\x71\xed\x7d\x06\x7c\xc8\x05\x87\xca\xb8\xdb\x3a\x71\xce\x5e\x40\x63\x27\xf7\x63\xec\x1b\x3c\x16\x67\x70\xa7\x55\x36\x63\x0c\x81\x5f\xd8\x26\x75\x82\xd1\xb5\x05\x1f\x0f\x82\x1c\x02\x15\x0b\x2e\xef\x34\x9b\x50\x59\x03\x14\xaa\x25\x70\x79\x3f\xa6\x4a\x76\xed\x2e\xd8\x3d\x2b\xa1\xf9\xb9\xf1\x16\x31\x54\x61\x2b\x49\xa6\x4a\xd8\xd5\x57\x3c\x25\xb1\xcd\x37\xc4\x1a\x44\xe3\xdf\x78\xf1\x05\x3d\x90\xb0\x68\xf0\xd3\x7a\xe0\x0c\x4a\x32\xb1\xa3\xff\x87\x4c\x41\xda\x4a\x70\x43\x39\x2f\x18\xef\xe5\x51\x8d\x76\xe8\x8b\x41\xce\xd6\x9e\x6f\x4c\x01\x4f\x06\xeb\xc5\x14\x6e\x61\xe8\x2f\xae\x1c\x49\xc3\x7c\x39\x4f\xea\x34\x19\x9a\xb8\x6c\x11\xa4\x46\x7a\x37\x4e\x40\x25\x5a\x05\xd4\x26\x97\x14\x30\xd5\x6c\xdb\xa2\x5a\x21\xad\x77\x9c\xc7\xf6\x2d\x22\xcd\x87\xb6\x0f\x08\x91\xbd\x85\x6a\x51\x7e\x14\xb7\x2a\x9a\xc7\x67\x2e\x4e\x8f\xb3\x74\xa9\x75\x8a\xb0\xc4\xe5\x96\x4a\xae\x03\x22\x89\x73\xf1\x73\xa5\xd4\x2a\xef\x9d\xb3\x37\x36\xc3\xe1\x8d\x8e\xec\x20\x4a\x1a\x17\xb9\xd0\x45\x93\xde\xa4\xd8\x04\xcb\xc8\x1b\x9a\xc5\x45\x80\x50\x49\x55\x39\x99\x9a\x99\x85\x48\x7e\x7c\xa1\x1c\x37\x58\x2e\xf8\x5c\x84\x1e\x8f\x06\x5e\xa9\x8f\xdd\x6b\x1c\x60\xde\xa1\xec\x28\x83\x52\x15\x68\x85\x6a\x6e\xbb\x27\x49\xf2\x07\x2e\xb4\x34\x48\xbe\x07\x05\xed\x47\x7c\xf4\xb2\x00\x48\x65\x21\x7d\xe5\xfa\xdb\xe2\xa0\xf9\xd6\xb8\x4b\x3f\xe7\xf7\xbf\x6c\x77\x53\x74\x96\x24\x6e\xc7\x96\xb8\xef\x2c\x04\xf6\x8a\xb5\xb1\x4f\xce\x0c\x6d\x28\x7b\x83\x62\x27\xd9\xf0\x8f\xa0\xee\x19\x72\x2f\x67\x98\xa5\xd8\x28\x0d\x10\x7c\xfc\x1b\xd5\x92\xd9\xdd\xc7\x24\xea\x86\xfc\x39\xdc\x94\xa3\x94\x01\x9e\x3a\x3d\xe9\xe0\xd1\xc7\x35\xe8\x62\xde\x2b\xb9\x52\x5b\x5f\xb4\xbd\x12\x12\x12\xbf\xaf\xf9\xff\x58\x6a\xc3\xc7\x5c\x5a\xce\x74\x6d\x9c\xa3\x07\xf7\x95\xff\x26\x97\xf2\xb4\x1a\x63\x46\xed\x23\x39\x7e\xb3\x88\x98\x69\x1e\x6f\x66\x84\x16\x37\xd0\xab\x0d\x96\x83\x09\xe0\x19\x40\x02\x30\x90\x15\x41\x6e\x74\x47\x2f\xe3\x24\x25\xd4\x5f\x07\xc7\x71\x19\x18\xb1\xe5\x79\x0f\x57\x2c\xe4\x44\x10\x42\xd4\x26\x03\x37\x92\x29\x7b\x5f\x81\xe0\x80\x9b\xd9\x69\x1f\x0a\x50\x5e\x32\x59\xfc\x03\xc9\xff\x10\x7e\xb9\xb4\x87\x95\xf4\x9f\xb0\x9c\x1b\xab\x56\x59\xd3\x9f\xfe\xcb\xdc\xc4\x03\xe3\x80\x3d\xc0\x12\x43\x8c\x2f\xb3\x6f\x68\x30\x15\xc5\xdf\x04\x82\xcb\x7d\x7f\xc5\x75\x73\x64\xa0\xa3\xc1\x0d\x0e\x12\x59\xc0\x1f\xcc\x4d\xd5\x49\x4b\x52\x90\xa6\x94\xae\xa3\xf6\xfa\xe5\x47\xac\x57\x6f"}, -{{0x43,0xd4,0xbe,0x6d,0xe9,0xcb,0x00,0x89,0x8e,0x99,0xdd,0xcc,0x2e,0x15,0x30,0x11,0x0f,0xa2,0xcb,0xc4,0x37,0x6c,0x48,0x5e,0x9c,0xa5,0x7f,0xd6,0x55,0x86,0xd8,0xa3,},{0x36,0x32,0xad,0x38,0x9b,0xe2,0xfa,0xb3,0xfb,0xa0,0xd8,0x04,0xbf,0x63,0x45,0xcd,0x32,0x2e,0xdd,0xd6,0xa7,0x5d,0x8c,0x37,0xfd,0x4b,0x5b,0xa1,0xc9,0xc2,0x5e,0x8f,},{0x86,0xae,0x93,0x25,0xf8,0x0b,0x98,0x86,0xc8,0x38,0x1f,0x96,0xa1,0x8c,0x21,0x20,0xe6,0xdb,0x01,0x6a,0x0d,0x6c,0xa2,0x82,0xed,0x93,0xba,0x9b,0x61,0xca,0xec,0x02,0xde,0x88,0xef,0xca,0x8b,0x8e,0x91,0x6a,0x4b,0x16,0xa5,0x85,0x25,0xa2,0xf6,0x8d,0x21,0xe5,0xfb,0xe6,0x7d,0xb4,0xc4,0xd6,0x20,0x95,0x95,0xc4,0xab,0xc3,0x2b,0x09,},"\xd9\xd5\x5d\xab\x0f\xa6\xda\x76\xb6\x8e\x84\x1c\x24\xd9\x71\xba\xc1\xf7\x9a\xf5\x13\xd8\x34\xe4\x26\xa5\xd0\x81\x14\xce\x8b\x54\xce\x8b\x7a\xfe\x01\x6b\x0f\xad\x03\xee\x74\x50\xc6\xc3\x09\x71\x73\x68\x1a\x4b\x2e\xb9\xf9\xc1\x79\xa8\x8e\x7c\xc3\x68\x13\xf2\xf5\xd1\x5f\x79\x98\xaf\xa9\xfd\x4e\x54\x6c\x73\xbb\x42\xe7\xf9\x52\x2b\xe6\xaf\xab\xca\x8c\x7b\x64\xfe\xd0\xe2\x92\xe4\x37\x5f\x3e\x1e\x5f\xd9\xfc\xb5\x39\xf4\xe5\xe5\x43\xfb\x6a\x11\xa0\xdf\x32\x1e\x70\x08\x4a\xaa\xbb\x70\xa9\x95\x0c\xee\xe3\xd8\x79\xc3\x86\xef\xca\x1e\x59\xc3\xcb\x7c\x45\xb5\x60\x09\x5e\x7a\xf0\x0f\xf5\x2f\x8a\x1a\xaa\x9c\xcf\x09\x2f\x0b\xb8\x06\xd9\x76\x10\x74\x2a\xc5\x82\xa3\xab\xbe\xdd\xf3\x9f\x49\xd2\x29\xd3\x2a\x11\x86\xd0\x21\x51\x8d\x74\x72\x8d\x13\xd9\x62\x63\x5d\x63\xba\xa6\x74\x3b\x12\x6b\xf4\x58\xfa\x2a\xc7\x56\xfb\xf8\x80\x96\xc8\xd3\x34\x0c\x62\x23\x90\x53\x4a\x74\x3f\x18\x64\xd5\x4d\xea\xb5\xe5\x53\x63\x72\xce\x5a\xc9\x37\x62\x28\x74\x14\xea\xe1\x58\xa7\x6b\xf8\x1d\xf5\x41\x7c\xf4\xc0\x47\xbe\x3a\xc1\x47\x5c\x51\x7e\xbd\x3a\xc1\xd1\xd1\xbd\xda\x11\xb3\xf9\x9c\x18\x17\x3e\x03\x0a\xcd\x51\xd2\xb5\xcf\x79\x51\x65\x09\x41\x54\x05\x07\x75\x11\xbd\xd9\xcb\xe1\x7d\x04\xf4\x78\x05\xe9\x8d\x0d\x14\x5e\x60\xa5\xd0\xe0\xf4\x53\xcd\x9b\x5c\x1a\x24\xf1\x2b\x75\xe8\xcc\x34\xd5\xe0\x06\x91\xff\xac\xbf\xf7\x88\xfe\xa8\x34\xd9\xd7\x79\xc1\xe6\x10\x29\x4d\xce\x19\x17\x0d\x28\x16\x0c\xff\x90\x9b\xea\x5a\x0a\xa7\x49\x40\x17\x40\xea\x3a\xf5\x1e\x48\xb2\x7c\x2b\x09\xf0\x25\x44\x42\x76\xc1\x88\xc0\x67\x1a\x6d\xa9\x4b\x43\xd1\xe5\x25\xe6\xa4\xa8\xa1\xa7\x3d\xfe\xdf\x12\x40\x18\x46\xba\x43\x06\x8a\x04\x09\x2b\x12\x91\x22\x70\xd2\xb6\x0d\xf6\x09\x97\x79\x75\x6b\x8b\xbb\x49\xec\xe8\x2d\x55\xf0\xf8\xdb\x1b\x80\xfb\x4b\x59\xbb\xa8\x60\xbd\x18\xc7\x5d\x6c\x83\x4d\x69\x44\x2a\xe0\x31\x4c\xf2\x39\x9f\x53\x92\xa3\xc6\x72\x8c\x63\xe5\xc5\x16\xc4\x22\x2a\xac\x60\xf9\x16\xdd\x63\xd1\xd0\x51\x7e\x8e\xb1\x0b\xd0\xe1\x5e\xb9\x06\x14\xde\xb2\x96\x40\x3a\xd1\x5b\x8c\x12\xb9\xe9\x71\xef\x2f\x01\xe5\x9f\xc3\x5d\x90\xc5\x5a\x8e\x20\xe9\x43\x7d\xd4\x34\xb2\x6d\x5c\x2c\x6e\xc2\xd5\x3a\xce\xc1\x7e\x81\xe4\x78\x31\xdc\x2d\xe8\x21\x83\xd7\x13\xb5\x9a\x4d\x1f\x46\x96\x9d\xdc\xdd\xaf\x27\xf4\x4e\x5a\x31\x1a\xaa\xc3\x9c\x3d\x5a\x97\xbc\x90\xca\xd7\x12\xf4\x6f\x85\xe6\xc8\xfb\xf5\xd5\x8d\x8b\xc3\xec\x27\xd3\x10\xa9\xea\xf2\xc3\x69\xcb\x00\x64\x97\x70\x39\x0a\x3f\x98\x8f\x36\x2e\xfc\x15\x5f\x56\xa1\x46\xa6\x26\x50\x54\x7e\x91\x53\x25\x07\x01\xee\xad\x1b\xd0\x1c\x89\x46\x22\x72\xdf\xaf\x0a\x43\x1a\xf4\xbd\x7c\x3d\xb4\x51\xad\xa6\x03\x23\x3f\xda\xd3\xaa\x89\x99\xaa\x21\xe2\xd3\xa4\x3b\x0b\x56\xfc\x6a\x91\x24\xd3\x35\x98\xb3\x73\x7f\x4e\x5c\xb2\x58\xbe\xda\x75\x6a\xd2\xe1\x7d\x06\x91\xd1\x5d\x41\x6b\xb7\xcb\x07\xec\x8d\x8c\x7a\xf5\xde\x80\xe5\xb9\x39\x4e\x32\x0c\x4c\x6e\x43\xef\xaa\xe6\x84\xad\x00\xf6\xdd\x20\xa8\x75\x0e\x95\x9c\x2f\x04\x20\x6f\xc0\x23\xaa\x19\x0c"}, -{{0x7d,0x01,0x0d,0x76,0x0f,0x24,0xe5,0xa2,0xde,0x34,0x08,0x9c,0x9f,0xdb,0x19,0xc3,0x3b,0x15,0x5b,0x0a,0x37,0xca,0x45,0x5a,0x5e,0x5b,0x1d,0xae,0x7a,0x07,0x31,0x76,},{0x4c,0x87,0x7b,0x3c,0x49,0x71,0xfb,0xb5,0x51,0x16,0x6e,0x21,0x4d,0x1c,0x76,0x24,0xc5,0x22,0x77,0x90,0x3c,0x59,0xa5,0x62,0xa8,0x0b,0x91,0xa8,0x54,0x83,0xfb,0x47,},{0x55,0x70,0x61,0x38,0x79,0xae,0x22,0x77,0x8b,0xd5,0x4f,0x14,0xfb,0x6e,0x8c,0x02,0x56,0xa7,0x1f,0x3d,0x79,0xc3,0xe5,0xcd,0x8e,0x41,0xae,0xa8,0xcf,0x77,0x3e,0x24,0xd2,0x9f,0x1f,0x1b,0x24,0xf8,0xc8,0x0d,0x29,0x49,0xe8,0x20,0x14,0x65,0xdb,0xde,0x89,0x40,0xb1,0xfa,0xb6,0x48,0x3b,0x08,0x5d,0x41,0x8e,0x25,0x10,0x14,0x20,0x0c,},"\x86\xe2\x11\x55\x72\xbf\x4c\x01\x3e\x6b\x4b\x04\xd0\xb0\x3e\x60\x6e\xe7\x0d\x92\x9c\xb8\xec\x36\xf4\xe2\xf3\x55\xdb\x3b\x5e\x15\x73\xd6\x58\xd1\x7b\xb1\xa3\x10\xc1\x69\x89\xa1\x6b\x95\x58\x92\x2e\xe4\x93\xf3\x59\x04\x21\x03\xc4\xdc\x1b\x40\xdf\xf7\x70\x99\x01\xfd\x58\x30\x13\x3f\x42\xc4\x65\x1e\xca\x00\x8b\x49\x9e\xe4\xf8\x4c\xd4\xec\x1e\xda\xa7\x82\x56\xed\xb6\x2f\x24\x02\x1a\x00\x76\x25\x69\x19\xe4\xe2\xce\x0a\x5a\x20\xf9\x21\xc2\x78\xcc\x29\x91\x59\x64\x4b\x5e\x3a\x3b\xbd\x08\x9d\xcb\xbe\xba\xd3\x76\x6a\xea\x77\xe9\xf0\x8e\xe5\xf7\xd4\xc1\x9d\x81\x70\xbc\x3d\xe1\xba\x77\x9a\x76\x99\x14\xf9\x65\xdb\xde\x2b\x61\xba\xd2\x14\xc5\x08\x18\x60\x41\xf7\x6c\x25\xbe\x95\x76\x56\xf5\xcf\xb7\x33\x4e\xb8\x38\xa3\xcf\xbc\x55\xcf\xba\xb6\x7a\xdf\x15\x52\x61\x99\x41\xb8\x35\xcd\x3e\x34\x10\x3b\x18\xb4\x91\x31\xe8\x20\x96\xf0\x5f\x57\x0b\x89\x98\x04\xba\xb8\xb6\xcb\xad\xdb\xbc\x02\xf9\xf3\xb5\x59\x73\x6d\x99\xca\x7b\x02\xd3\x26\x8f\xa2\x73\x99\x6f\xcf\x05\x71\x97\x7d\x1c\xc3\x00\x8c\x4e\xf8\x48\x97\x0e\xe3\x50\xb1\x58\xc4\x7e\xc2\x77\xad\xd4\x74\x2f\xa2\xbc\xbe\xa9\xbd\x55\x49\xc7\xbc\xa0\x38\x02\x0e\xce\x68\xf1\x88\xc1\xea\x3a\x62\xdd\x9a\x07\x3d\x4c\x13\x8c\xa8\xa9\xac\x04\x08\xdc\xfd\x46\xe3\x6b\xdf\xf7\x39\x88\xa5\x8b\x96\x17\xca\xa0\x8b\xd4\x1b\xf3\xe8\x12\xe7\x82\x4f\x0f\x7e\x81\x46\xa4\x44\xf3\x6b\xf5\x3a\x1c\xd8\x92\x03\x9c\xcd\x33\x5f\x5a\x2e\x79\x74\x5e\xac\x96\x14\x8c\x2a\x29\x99\x47\xf1\xb2\xe3\x28\xa3\x78\x9b\xf1\x3c\x6d\x73\x50\x6f\x3b\xdc\x68\xea\x48\xab\xf0\x02\x27\x0f\xe4\xee\x9e\xf9\xed\x6b\x10\xc2\xfb\xb4\xff\x12\x75\xb9\xd7\xdd\x35\xd8\xa5\x2e\x37\x17\x58\x57\x4c\xb4\x66\xc5\x7b\x5a\xbc\x24\x29\x76\xbe\xfc\x8d\x98\xa0\x13\x1b\x9b\xb8\x46\xb2\x19\xe4\x66\x91\x86\xa8\x3c\x05\x6c\xd8\x08\x06\x61\xde\x16\xb5\x1c\xe5\x76\x7b\x22\xe9\xa9\x32\x42\xbf\x8d\x32\x05\xc6\x6a\x67\x3c\xe7\x83\xd1\xc0\xd3\x7b\x63\x00\xfb\xf0\xd6\x12\x79\x40\xf8\x8f\x18\x19\xc4\x50\xdc\xc9\x05\x43\xed\x79\x4f\x1f\xd4\x4e\x65\x39\xfe\xba\xf1\x9a\x4c\xc9\x88\x70\x01\x4d\x7c\xca\xd7\x4d\x18\x76\xa1\x23\xec\xd1\x45\x51\x6c\x74\x3b\x4b\xba\x62\xd8\x21\xca\x9a\x79\x51\xe0\xdf\xb2\x3f\x38\xd9\xe3\xa3\x65\xfd\x83\x22\xf2\xee\x47\x99\xe9\xff\x11\xe1\xc5\xc3\x0b\x55\xa3\x55\xc8\xa5\xde\xea\x81\xa5\x45\xe3\x47\x05\xab\x56\xd1\x7b\x1f\xa0\x6e\xd7\x64\x15\x55\x67\x02\xf3\x64\x80\x82\x46\xf8\x63\xc3\x19\xf7\x5c\xdf\x6b\xd7\x48\x43\x8d\x1a\x2e\xaf\x42\x06\xc5\x60\xbf\xaf\xc2\x35\x67\x9a\xd6\x04\x9c\x1a\x01\x52\x6f\xcb\x9a\x3c\xe1\xb1\xd3\x9b\xe4\xdf\x18\xb1\x5f\xa0\xea\x55\x27\x2b\x17\xeb\xde\xdf\x6c\x30\x49\x8a\x8a\x14\xf2\x04\x2b\xe1\xc2\xcd\xb0\x9e\x9e\xf3\x84\x6d\x66\x59\xa9\xf6\xd6\x73\xdf\x9a\xfb\x7e\xde\xd0\x4b\x79\x3d\x97\x31\xf0\xac\xcc\x41\x46\x8d\xc1\xf3\x23\x6c\x99\xac\xad\xee\x62\x39\xc3\x61\xb8\xbd\x7e\x2d\x0c\xfe\x8b\xb7\xc0\x66\x87\xe0\x8e\x76\xb7\x1a\xd5\x7a\x03\x61\x79\xf2\x91\xd0\x96\xae\x2f\xa0\x81\x8e\xf4\xbf\x48\x66"}, -{{0xaa,0xaa,0xbb,0x7c,0xe4,0xff,0xfe,0x4d,0xc3,0x57,0x47,0xba,0xea,0x2b,0xc5,0xf0,0x50,0xbe,0xf0,0x6e,0xe0,0xc1,0xfd,0x63,0x2a,0x06,0x7f,0xec,0xe1,0xef,0x4f,0xb5,},{0x82,0x0a,0x24,0x42,0xd5,0xf4,0x5f,0x3c,0x79,0x14,0x78,0xe0,0x98,0xfb,0x3b,0x06,0x8d,0xa5,0x2e,0xc4,0xe8,0xda,0xde,0xc8,0x50,0x65,0xc3,0x56,0x59,0xf4,0x37,0xe0,},{0x05,0x0a,0xe8,0xae,0xce,0xec,0x96,0x27,0xb8,0x01,0x37,0x35,0x7a,0x22,0x96,0x2a,0xc8,0xb4,0x50,0x48,0x66,0x17,0x08,0xd3,0x94,0xd0,0xa5,0x1a,0xad,0xc3,0x81,0xfe,0x85,0x35,0x02,0x3d,0x6e,0x1b,0xda,0x0e,0x72,0xb3,0x49,0xb5,0x0b,0x26,0xda,0x7c,0x3a,0x30,0x85,0xe8,0x1e,0x9d,0xd6,0xcf,0x12,0x78,0x68,0xfc,0x5b,0xae,0xab,0x01,},"\xf9\xd2\x85\x97\xa3\xe2\xb6\x4b\xa3\x27\xac\x5c\xd2\x9f\x08\x1e\x74\xbf\x46\x1b\x2e\xb2\xd3\xcf\xd9\xd5\xe9\x21\x58\xd2\x1d\x1d\x2a\x47\xab\x50\x98\x1c\xb1\x9f\xe3\xf8\xc6\xfe\x48\x82\x49\xb1\xc4\x9f\xb8\x97\xa0\xfe\x21\xab\x54\x04\x41\x4f\xd9\x14\x87\x5c\x22\x0f\x1c\xbc\x12\xf5\xc3\x8c\xfb\xa7\x9f\x7a\xc3\x03\xa5\x23\x1a\x37\x2b\x02\xfa\xd6\xc8\x46\x2f\x8c\xc4\x9f\x0f\x64\x96\x5b\x65\x1d\xcc\xef\x0b\xb9\x60\x82\x15\x09\x08\x49\x17\x7b\xe4\x7b\x2d\x30\x72\x94\x4d\x36\xe8\x56\xda\x18\x5c\x7b\x3a\x68\x9f\x7e\xde\xf9\x88\x33\x8e\x09\x63\xed\x31\xa6\xb0\xa8\x0d\x5c\xb0\xb1\xcc\xcf\x6f\x39\x48\x37\xaa\x6f\x8b\x2f\x3d\xa5\xef\xbd\xf4\xd3\x60\xd4\xbf\x4d\xd7\x08\xce\x64\x45\x58\x7d\x94\x2b\x79\x76\x1c\xe9\x51\xb1\xbb\x4d\x90\x50\x70\x36\x18\xa6\xd9\x30\xa8\x0c\x69\x57\x6f\xc4\xaf\x30\x6a\x2a\x56\xdb\xd8\x84\xa0\x5a\x1e\x4e\x9f\x31\x36\xcd\x0b\x55\xae\x47\x4b\xb5\xd3\xd0\xfb\xc9\xb0\x33\x9c\xec\x34\x4f\xdd\x08\x5c\x19\x28\x10\x14\x81\xc6\x87\x94\xf5\xc8\x90\x13\x71\x08\xce\xa7\x91\xd2\x1f\x81\x68\x3d\x3e\x1a\x9e\xec\x66\xac\xe5\xc0\x14\xd8\x9e\x69\x80\x8e\x5f\xa8\x3d\x38\x12\xee\x68\x0f\x5a\x99\x71\x68\x1b\x8a\xdc\xd4\xa1\x6e\x9a\x4c\x16\x5b\x5e\xf9\x93\x2c\x5e\xd8\x25\x23\x7f\xd5\x03\x7b\xcb\xef\xe4\xcb\x11\x56\x4f\xa7\x07\xc8\xa9\x32\x90\x75\x14\x14\x89\x1b\x1e\xdd\x33\x13\xc6\x5f\x8b\x91\xc2\xe9\x25\xa3\xc1\x2a\x9d\x3a\xa4\x5f\xd5\xa6\x67\xb7\x83\x93\xc3\xe3\x9d\xf8\x8a\x8f\x0d\x11\x48\xb5\x31\x1e\x3d\x87\xc4\xa9\x2e\x0a\x3f\xb9\x15\xbc\x90\xd5\x55\x8d\x05\xb4\x75\xa8\x83\x47\x78\xaa\x94\x3e\xa3\x9b\x8e\xaa\x95\xad\x18\x32\xe5\x91\x6e\xa3\x10\x2d\x7d\xe0\xb8\x36\xcd\xe8\xf3\x75\x9d\xbb\x3b\x9d\x56\xea\x81\x7b\x3e\x49\xc9\x83\x21\x02\x77\xc2\xc7\xc5\xb0\xdb\x18\x74\x22\x53\x2f\xca\x98\xa2\x8b\x3b\x65\x9c\x6b\x81\x5a\xc1\x26\xfa\xdb\xe2\xf4\x00\xc7\x3e\x9d\x2d\xed\xcb\xbd\x2d\x3a\x36\x5f\xfa\xd7\xe6\x66\xc8\x96\xe3\x1e\x61\xb3\x84\xed\x3a\x9f\xcf\x12\x90\x53\x8d\xf1\x1b\x94\x74\xc6\x28\x1c\xc5\x92\xc7\x1c\x88\x08\x86\x8b\x42\x92\xc1\x7e\xce\x6b\x3e\xdf\x5e\x35\x42\xa7\x0b\x91\x15\x93\xe9\x3f\x35\xec\xd9\x72\x9b\xd8\x88\x0a\x24\xea\xf4\x1f\xbc\x65\x74\xdf\xe1\x67\xec\x2d\x0e\x7a\xb3\xdf\x5e\xc3\x4b\x8b\x55\xd5\x48\xab\x93\x73\x8a\x2e\xea\xf2\x1c\x88\x4c\x5c\x85\x51\xdb\x2e\xdf\x2b\x04\x9f\x1a\x2a\x84\xfa\x72\xac\x89\x78\xa4\xc2\x78\x09\xf2\x09\xc1\xb2\x19\x5a\xff\x50\x4f\x69\x98\x56\xcc\x4f\x22\xd4\x4e\xbd\xd0\xfe\x50\x37\x44\x68\xd0\xb1\x79\x2e\x57\x4b\x51\x10\xa1\xf4\xcd\x0e\x22\x1e\x82\x4a\x78\xdd\xc4\x84\x5f\xeb\x46\xd6\x6d\x63\x3d\x23\xcd\x23\xf4\xb6\xfb\xe4\xc8\xce\x16\xcd\x1a\xf6\x15\x36\xda\x5f\xa6\x7b\x10\xac\x75\x55\xa6\x8c\x0e\x0b\xdb\xf2\xf8\xd7\x23\x09\xd9\x95\x51\x6b\x81\x18\xbf\x43\x83\x5d\x0a\x01\xc0\x8f\xfe\xba\x3e\xa3\xed\x05\xcd\x2d\x54\xf0\xea\xbc\xda\x05\xd0\x03\x7d\x52\xca\xed\x3b\x19\x37\x4f\xaf\x73\x99\x90\x94\xf7\x90\x55\x92\x4b\xea\x9a\xec\x44\x70\x13\x5f\x5e\x8b\xf1\x83\xc9\xd1\xc9"}, -{{0xe9,0x5c,0xc2,0xa4,0xd1,0x19,0x3b,0x75,0x39,0xfc,0xbb,0xea,0xae,0xed,0x98,0x5b,0x6f,0xb9,0x02,0xdd,0x0e,0xfb,0xd6,0x38,0x74,0x57,0x55,0x0d,0x0d,0x6a,0x2f,0xea,},{0x72,0xa1,0xff,0x1e,0x9b,0xb1,0x1c,0x8d,0x88,0x96,0x8a,0x7b,0x16,0x96,0x37,0xad,0xee,0x43,0x8e,0x22,0x63,0xf0,0x06,0xdc,0xa4,0xfe,0x02,0xfe,0x06,0x6c,0xba,0xd3,},{0x1b,0x8d,0x7c,0xc2,0xad,0xf3,0x6c,0xae,0x16,0x31,0x25,0x0c,0x82,0x43,0x1b,0xd8,0x84,0x37,0x16,0x3a,0x63,0x49,0xad,0x96,0xe7,0xa8,0x64,0x44,0x7e,0x9f,0xee,0x75,0x3a,0xc3,0x65,0x5c,0x98,0x35,0xb4,0xd1,0xec,0xbb,0x30,0x6c,0x63,0x8b,0xa5,0x40,0x2a,0xd0,0x2b,0xa6,0xd2,0x25,0xd9,0x68,0x82,0x88,0x9f,0xe8,0xd2,0x04,0xa6,0x04,},"\x84\x26\x74\x39\x20\x1b\x05\x91\xdb\x60\xc0\xf1\x7a\x9c\x15\xe4\x54\x09\x29\x56\x52\xd5\xf5\x5b\x87\xfb\x35\x19\x67\xc8\x46\xa5\x67\xf5\xce\xba\xae\xd1\x76\x2b\xff\x54\x85\xf0\x48\x53\xca\x92\x69\xf4\x64\x09\x4e\x51\x2d\xf1\xf0\x2e\x13\xe5\x17\xb1\xda\xa5\x8d\x34\xca\xa2\xd5\xff\x9f\x9e\x79\xbc\xaf\xb4\xce\x96\xe8\xa0\x89\x25\x8a\xd6\x13\x43\xb4\x46\x62\x8e\xbc\x4f\x5b\x2a\x84\xd0\x3b\x72\xef\x3f\x73\x85\x89\xfa\x13\xc4\x25\x19\xa8\x28\x29\x9a\x3f\xae\xc0\x35\x03\x7b\xc1\x0b\x44\xe3\xbd\xfe\xd9\xe0\x87\x07\x17\xcb\xaf\x31\xbe\xf8\xb2\x2c\x4e\xa1\x6e\x81\x57\xfc\xbc\x63\xee\xfa\x39\xed\x82\x2e\xfd\x42\x15\xc2\x47\xdd\xa4\x87\x86\x27\x7e\xc0\x30\xa8\x6c\x0e\xf4\x85\x1d\x67\x3c\xfe\x75\x2d\x06\x77\x88\x3c\x2c\x45\x20\x38\x97\x0c\x09\xbd\x48\x17\x14\xbc\x3f\xbe\xcf\xa4\xff\x2a\x3c\x24\x56\x95\xd7\xec\xc2\xf4\xde\xc7\xf5\xed\xe0\x4f\xf6\xdb\x43\xe2\xbb\x91\xc0\x66\xb6\x49\xef\x73\xfd\x3b\xe8\x60\xcb\x83\xfa\x80\xb0\x74\x14\x9f\x43\x1e\xeb\xb9\x17\xec\x84\x78\xda\x87\x0c\x11\xe3\x17\x70\x38\x59\xf9\xf2\xf4\x00\x8a\x6c\x7c\x75\x4b\x06\xe1\xf7\xd2\x47\x96\x89\xda\x84\xe8\x89\x22\xf3\x82\x74\x98\x5e\x11\xce\x13\xcd\xbd\xb0\xf2\xec\xe6\x8f\xb6\x02\xad\xe0\x3d\xd5\x49\xa3\x62\x49\x1f\x4a\x20\x3f\xf8\x07\x44\xf6\x63\xc5\x23\xa0\x26\xb4\x31\xaa\xd4\x5c\x58\x29\xe0\x29\xad\x62\x56\xd1\x27\x6f\xd7\xb7\xa1\x2d\xdb\xf1\x72\x7d\x9e\x23\x3f\xb5\x34\x45\x73\x70\xa4\x26\xe5\x6f\xb3\x9c\xf4\x04\xa3\xec\xbf\x0c\x4b\x50\xbb\x52\x2d\xce\x98\x1e\x08\x30\xfd\x84\x06\xe6\xd9\x72\x5c\xeb\x1d\xdd\x3a\x19\x47\x93\x7d\x90\xe0\x4d\x76\x8a\xe1\xd1\x26\xe2\xae\xac\x21\xb8\xc9\xef\xc5\x4c\x40\x96\x1b\x7f\x4e\x9e\x88\x02\x5f\x7e\x0b\x9d\xe9\x01\xeb\xf0\x04\x9e\x74\x1b\x79\x79\x97\xd8\xdb\x78\xe9\x28\x3b\xbb\x5f\x90\xf3\x5a\x2c\x4d\xee\x27\x31\x42\xec\x25\x8c\x02\xad\x0e\xcc\x61\xcc\x5c\x9f\x12\x13\x2d\xb2\x8a\xf4\x1c\x1f\xb7\x8e\x52\x4b\xe5\x32\x7b\x5f\xfc\x35\x96\x27\x79\xfb\x11\xff\x0c\x5d\x3e\xe0\xa3\x1f\xf4\x7e\x73\xb1\x72\x9d\xfa\x46\xe8\x98\x6b\x1b\x89\xab\xc8\x8a\xd0\x6a\xbd\x5b\x6f\x76\x6d\x23\xab\xf6\x42\x25\x78\x94\xeb\xdf\xa7\x9e\x63\x09\xf1\x27\x23\x74\xee\x94\x33\x67\x7b\xa1\x3e\x45\x1b\xaa\x95\x33\x0e\x66\x0c\x80\x52\xae\x87\x2e\x0e\x32\xe2\xb2\xd1\x28\x6d\x01\xa0\xab\x58\x10\x42\x4e\xd8\xb9\x40\x54\x65\xbd\xeb\xa0\x3b\x69\x83\x84\x67\x6f\xe5\xea\x46\x4a\x03\x44\x6c\x4f\x7c\xd7\xb4\x33\x12\xec\xf1\x51\x36\x04\x64\x57\x1a\xd2\x86\x10\x58\x1f\xba\xdb\x94\x5a\x1d\x68\x18\x1d\xeb\x40\x3a\xa5\x6e\xba\x0b\xb8\x40\x32\x8e\xee\x36\x10\x3c\x7d\xe0\x73\xa6\x87\x9c\x94\x1c\x75\x54\xc6\xf6\xf2\xa0\x80\x80\x9e\xb0\xe5\xbd\x0e\x13\x0f\x29\xa2\x29\xe9\x30\xdb\x01\xfe\xca\xc2\xe0\x36\xbd\xf0\xe0\x01\xe2\xa8\xea\x32\x64\xf8\x64\x9d\x5b\x60\xc2\x91\x03\xf0\xb4\x9c\x24\xc9\x7f\xac\xaf\x7e\x81\x06\x9a\x2b\x26\xab\x3f\x93\x3f\x42\x7d\x81\x27\x2c\x6c\x8b\x7c\xd0\xdf\xb7\xc6\xbb\xe9\xc0\xea\xab\x32\xbb\xda\x22\x18\xb9\x62\x3a\x21\x19\xaa\xb1\xf3\xeb"}, -{{0x77,0xad,0x0f,0x94,0x2c,0x37,0xf0,0x31,0x3e,0x6b,0x04,0x56,0xda,0xba,0xec,0x81,0xb2,0xd6,0x1f,0x6c,0x11,0x8d,0xdb,0x29,0xea,0xf3,0xac,0x5b,0xf1,0x95,0x04,0xd4,},{0x69,0x2d,0x2d,0xa5,0xa9,0x5f,0x48,0x61,0x1a,0x6d,0xa8,0x9c,0xfb,0x3b,0x35,0x40,0xf6,0xaa,0x0c,0x85,0x0d,0x6d,0x98,0xde,0xea,0x87,0x0e,0x39,0x7f,0xed,0xe3,0x28,},{0x69,0x6b,0xd5,0x52,0xdd,0x01,0xdb,0x80,0xb3,0xd6,0x7d,0x61,0xee,0xb7,0xec,0xc5,0x68,0x78,0x40,0x4a,0xb1,0x19,0x44,0x2a,0x1c,0x74,0x22,0x99,0x2c,0xfa,0x35,0xae,0xa9,0x20,0x82,0x5d,0x2d,0xaf,0xd8,0x92,0xad,0x7e,0xb6,0x82,0x5a,0xd9,0x99,0xae,0xe5,0xc8,0x3b,0x7b,0x50,0x79,0x06,0x53,0x4f,0x91,0xac,0xe7,0x59,0xc5,0x51,0x0c,},"\x87\xe6\xde\xad\x2c\x85\x54\x9e\x3d\x8d\x25\x88\xa0\xa3\x36\x06\x03\xa6\x24\xfb\x65\xae\xbb\xc1\x01\xbf\x7f\x1f\xec\x18\xd0\xb2\x8f\xbd\x5d\xba\xee\xd3\x87\x52\xcd\xf6\x35\x5c\xe8\xdc\x84\xe1\x8a\xc1\xa4\x39\x3d\x2a\xb8\x88\x88\x2c\x4f\xf1\xc9\xc8\x13\x7f\x83\xbe\xe3\x63\x36\xbc\xbf\xbb\x72\xd5\x04\x9e\x0a\x40\x08\x74\x51\x4f\xdc\x36\x33\x04\x6e\x89\x38\x3d\xde\xd9\x3c\xa3\x1f\xde\x0d\x89\x8e\x11\xe9\x26\x8d\x3d\x5c\x24\x06\x66\xed\x55\x27\x61\x3d\xa7\x9f\xb7\xe4\x96\x25\xb4\x4c\xde\x78\xb4\x1c\x67\x90\x2e\xb0\x21\x6b\x3a\x7a\x3e\x56\x0e\x26\x1d\x71\xd7\x64\xaa\xcf\x15\x95\x9c\x17\xfc\xd6\x17\x6f\xb2\x5e\x24\x9e\xe6\xbb\x1b\x3b\xd7\xbd\x90\xf6\x0b\x0b\x0f\xfa\x03\x15\xa0\x65\xa2\x4b\xba\xe8\xf2\x55\xbf\x29\x8d\x7e\x4d\x44\xf0\xb4\x30\xc4\x15\xb4\xfb\x36\xcf\xa6\x62\x6a\x83\xf4\x9a\x25\x67\xf6\x24\x4f\x40\xe9\x23\xad\xd1\xd4\x9a\x72\xf5\x7b\x15\x30\xf5\xb3\x79\xde\x3a\x91\xc2\xe9\xa1\xac\x79\xab\x37\xbc\x3b\x9b\xa7\x3d\x88\x28\x13\x6b\xcc\x87\xd2\xc0\x11\x90\xde\x54\x57\xfa\xcd\x90\xf3\x69\x55\x3f\x7a\xc5\x21\xc5\x67\x2b\x08\x67\xdf\xa8\xda\x3b\x95\x2a\xd9\x5b\x67\xda\xb9\x9b\x48\x20\x57\x2f\x2d\x4a\x29\x8e\x95\x18\x63\x77\x79\x28\x9c\x03\x1b\x79\x3d\xee\x85\x9c\xde\x7b\x24\xad\xd6\x49\xff\xf8\x71\x24\x8a\x66\x02\xd2\x51\x62\x79\xda\x60\x58\xcb\xb6\x96\xfa\x8b\x1d\x89\xa2\x0d\x20\x99\xe6\x46\x44\x32\x10\x48\x3e\x5d\x41\x34\xe9\x28\xfa\xeb\x38\xa3\xb5\x08\x19\x9e\x0d\x69\xbb\x55\xee\x34\x77\x42\x05\xc0\xa6\x12\x05\xb5\x0b\x08\xfe\xbe\xaa\x40\x1e\x6e\x3a\x51\xa2\xbf\x98\xef\xac\x78\xb7\xae\x2b\x85\x2c\x53\x95\xa1\x2c\x40\xe2\xc7\xdd\x1b\x20\x25\x04\xb5\xa7\xd2\xf7\xe4\xfd\x4f\x86\x10\x93\x0d\x28\x68\xcb\xa8\x86\x43\x39\xe0\x41\xda\x21\xc0\x71\x5f\x41\xb2\xb2\x3d\x14\xd0\xb5\x45\x48\x0b\xc3\xbd\x7d\x72\x15\xcf\x2f\x81\x6a\x33\x32\x08\x1e\xca\xa0\x8c\x0f\x8b\x99\x52\x52\x51\xf5\x72\x31\xb6\x75\x0c\x2d\xbd\x11\x09\xac\x41\x60\x48\x6b\x76\x83\x24\xb6\xba\xc8\x7e\xf5\xa2\x26\x44\x8c\x43\x12\x40\x32\x8f\x42\xcc\xa5\x86\xbe\x7a\xff\x3c\xbe\x76\x05\xfa\x34\x15\x14\xfc\xcf\xb9\x66\xaf\x3d\x45\x30\xe8\xcd\x90\x37\xa1\x1c\xe5\x93\xc2\xd3\x83\xe1\x03\x5a\x0c\x2e\xda\x09\x8d\xe9\x0d\x50\xc5\x18\x4a\x9c\x01\xb5\x7f\x26\xb9\x4d\xed\xd1\x45\x4c\x34\x06\x37\xec\xcc\xee\x70\x62\x57\x54\xa3\x28\xc6\x5f\x42\x64\x5b\x5e\x1a\x56\x55\xee\xf9\x7d\xfb\x1c\x63\x08\xed\xf4\x9f\xa3\x68\xd1\x7d\x17\xe0\x6a\xdc\x51\x2b\x39\x73\xea\x65\x2a\xc4\x0a\x99\x78\xe1\xbb\x1b\x2f\x86\xc5\xa9\xff\xbf\x60\xdc\xc4\xf6\xbb\xc9\x8a\x64\xf4\xde\x65\xe7\xec\x61\x72\x1e\xde\xb0\xe5\x23\x84\x56\xf7\x61\xd2\xd1\x29\x3a\xf0\xde\x9f\x79\x3b\x11\xd8\xca\xdf\x01\xa9\x43\x19\xa0\x2a\x42\x73\xff\xc4\xd3\xff\xa7\xb3\x4d\x74\xfd\x2e\x0b\x10\x0f\xca\x58\xb5\x32\x5f\x90\x7a\x74\x91\x93\xe7\x51\xd6\xc1\x16\x68\x7a\xee\x37\x47\xb5\x94\x60\xd4\xef\x15\x6e\x72\x47\x6e\xae\x1b\x84\x55\xd7\x6e\x71\xb3\x06\xb9\x81\x29\xb7\x2f\xe1\xcb\x5e\xb4\x05\xa7\xc2\xf4\x32\x7f\x38\x62\xd4"}, -{{0x29,0x32,0x14,0x69,0xee,0x9f,0x2b,0xb1,0x65,0xa0,0x69,0x64,0x03,0x32,0xb4,0x89,0xbf,0x5c,0x3f,0xab,0x68,0x2e,0x93,0xda,0xe9,0xd8,0x63,0x17,0xbf,0x50,0xc5,0x2c,},{0x96,0xf7,0x30,0xf8,0xef,0x89,0x70,0x26,0x8d,0xba,0x0f,0x75,0x70,0x41,0x0b,0x61,0x88,0xa1,0xa3,0xc8,0x63,0x97,0x74,0x09,0x13,0xd5,0x3a,0xda,0x26,0x2a,0xb8,0x7e,},{0x4e,0x1a,0xff,0x84,0x63,0xbc,0xa1,0xb7,0xde,0xb1,0xd3,0x77,0x3d,0xf2,0xe7,0xa0,0x68,0x64,0x11,0x1b,0x6d,0xc4,0x2a,0x62,0xae,0x98,0xde,0xb2,0x31,0x39,0x43,0xb3,0x15,0x3e,0xe4,0x66,0x96,0xb1,0x5c,0x24,0xef,0xc2,0xa8,0x08,0xaa,0xba,0x81,0xc7,0x8e,0x3d,0xfa,0x4d,0xfb,0x50,0xca,0x9f,0xe8,0x44,0x45,0xea,0x68,0xbc,0x8e,0x0a,},"\x9c\x71\x2c\x83\xd5\x4f\x2e\x99\x3c\xa6\x8a\x96\x32\x84\x60\x04\x49\x9c\x51\x95\x44\x8d\xdc\x49\x1c\x3a\x0d\x2e\x3a\x66\x6d\x6b\x33\x09\x8e\x48\x64\xfd\xf8\x6e\x61\x9d\x50\xf1\x0b\x7c\xc6\xc3\x9b\x3f\xf2\x80\x1a\x94\x91\xf6\xfa\x97\xc5\xf1\xc4\xaf\xa7\xae\xff\x31\xd7\x38\xf9\xa7\x68\xa7\x9c\x73\xb2\x55\x77\x31\x0f\xb0\xad\x4f\xaf\x85\x43\xa0\x98\xf8\x59\x57\x1b\x61\x48\xe8\xb5\x29\x26\x44\x57\x57\xd5\x54\x9f\xd2\x5a\x26\x51\x85\x31\x56\x63\x79\xd1\xc2\x74\xe6\xc6\xa9\xd6\x41\x32\xe4\xac\x25\xac\x9a\xf9\x38\x1b\xcb\x88\x53\x32\x11\x3f\x43\x01\x4a\x13\x9a\x81\xf8\xd4\x3c\x8a\x6a\xb5\x4c\x11\xa5\xc9\x2e\x06\x19\x1c\x1e\x51\xb7\x57\xac\x9f\x11\xe3\xdc\x15\xdb\x44\x86\xd1\x67\xff\x9f\x2d\x65\xe2\x3e\x6c\x96\x22\x3d\x9a\xff\x8d\x10\xd1\x50\x2c\xf3\xdb\xce\x5e\x35\x7e\x6b\x12\xdb\xe9\xb7\xe9\x97\xc3\xd0\xa5\x07\xd3\xba\xe3\xcf\xef\x1f\xfc\x8d\x05\x6e\xf7\xdc\x72\xdd\xc1\xc8\x1e\x31\x0a\xd2\x05\xbe\x16\xe7\x7f\x27\x38\x35\x4b\x10\xb4\x84\xd3\x07\x6c\x27\xe6\xb4\xf1\x66\x38\x85\x81\xf3\x50\xbe\xfe\x22\xfb\xb0\x82\xb5\x41\x21\xee\x59\xec\xc7\xae\x5d\xec\xe8\x98\x82\xac\xf2\x6c\xb7\x47\xff\xaa\x3e\x2d\x05\xa6\x96\xf6\x0f\xd9\xe8\x29\xc7\x09\xd8\xf0\x2d\xaf\x53\x7b\x23\x69\xb8\x91\xfe\x6c\xcb\xf8\xdf\xcd\xd7\xf4\xa3\x64\xb1\x99\x85\xbe\x7e\xde\xc6\x7d\xdc\x1d\xb7\x13\xc0\xa9\x0f\xaf\xa4\x88\x37\x77\x25\x62\xde\xac\xc2\xd2\xa0\xe7\x89\xe1\x8a\x8b\x5b\x3b\xd9\xe0\x83\xea\x92\xff\xfc\x31\x83\xd5\xd4\x14\x15\x32\x59\xb3\x3a\x43\x29\xcf\xc8\x08\x24\xeb\xcb\xe0\x44\xa7\xe3\x3a\xb8\xa2\x4f\xde\x54\xbd\x95\x20\xae\xa2\x84\xb0\xc4\xc4\xfa\x94\x27\xd2\x51\xc0\xdd\xd0\x13\xec\xdd\x82\x90\xef\x55\x65\xf6\x08\x50\x8e\x36\x35\x89\xe5\x29\xd8\x4f\xf0\xf2\x6f\x9e\xcb\x03\x05\x2d\x58\x97\xfa\xbc\x91\x7e\x56\xe6\x01\xb6\x4a\xbf\xe5\xa1\x7c\x39\x50\x28\x9d\x0c\xdc\xaf\x1f\x60\x05\xa9\xf8\x10\x6f\x43\xe1\x7a\xdc\xaa\x2d\x1e\x26\x91\x66\x76\x2f\x80\x54\xde\x05\x13\x5d\x5d\x13\x93\xd7\x00\x0a\x15\xb8\x7b\xd6\x88\x46\xa8\x9d\x5b\xc2\x28\x63\x32\x51\x51\xaa\xc8\x43\xf7\x22\x78\xae\x6f\x4a\xf7\x2a\x4e\x44\x9a\xdb\x7e\xae\x6d\x43\x6a\x1e\xc7\xe5\x8e\x59\xb7\xb8\xbb\x9e\xf0\xdd\xaa\xa0\x01\x82\x6f\x8d\xcb\x44\x64\x79\xde\xaf\xd8\xb8\xd5\x42\x04\x1c\x19\xa0\x5b\x1e\x0e\xe4\x7b\x46\x40\x91\x0c\x31\x93\x0c\xa4\xe2\x0b\x10\x57\x58\xec\x75\xf1\x95\x03\x56\x94\x7f\x62\x61\xd0\x03\x7f\xe3\x07\x73\xa3\xec\xe6\xa9\x6c\x8d\x54\x33\x33\x3d\x82\x2c\x27\x77\xef\x7f\xf8\xbe\x60\x33\x34\x5b\x50\x55\xd5\x8f\x5e\xb3\x72\x9a\xf5\xae\x88\x24\xf3\x31\xee\x07\x31\xc8\x9b\x20\xac\x11\x8f\x55\x04\x27\xcd\x95\x8a\x55\xf6\xb1\xa2\x88\x8a\x08\x7b\xb7\xdb\x55\xbf\xc7\x3b\x29\x42\x9b\x44\x48\xdb\xe9\x11\x9c\x45\xa8\x73\x39\xb4\x49\x7a\x69\xa4\xcf\x83\x3e\x8f\x37\x70\xcc\xe5\xe0\x1f\xaf\x5e\x73\xbb\xaf\x62\x76\x83\xc0\xa2\x8c\x73\x05\x2f\xbe\xce\x20\x30\x43\x38\x9d\xfb\xfd\x45\x49\x5e\x51\xda\xb8\x6a\x25\x2e\x5b\xc1\xb4\xb7\xfe\x28\x07\xe3\xd0\xe2\x36\x3b\xea\xb5\x1c\x67\xfb\x31"}, -{{0x04,0x65,0x77,0x50,0x49,0x7e,0x68,0x15,0x2c,0x43,0xce,0x34,0xa5,0x8d,0x21,0x06,0xe6,0x4c,0x55,0x7c,0xd7,0xa8,0x4e,0xf0,0x5d,0x9e,0xb8,0x2e,0x6b,0xcb,0x05,0xf5,},{0x3b,0x3a,0x19,0x47,0xb4,0xcb,0xf6,0x0b,0x82,0x6d,0x60,0x9f,0x19,0x2d,0xc2,0x30,0xaa,0x9b,0x9b,0xaf,0x4c,0xd6,0xa6,0x09,0x2e,0x49,0x5f,0x1d,0x2e,0x47,0xad,0x62,},{0x7e,0x2e,0xae,0x5a,0x29,0x3f,0x41,0x83,0x91,0xf6,0xd8,0x5a,0x79,0x94,0xb0,0x7c,0x45,0x22,0x80,0x01,0x7e,0xe6,0x53,0xbf,0x61,0x7a,0x8d,0x5b,0xe2,0x4c,0xbb,0x5d,0x0e,0xfd,0xfb,0x7f,0x7f,0x00,0x13,0x12,0x26,0x0f,0x34,0x4e,0x6f,0xb9,0x15,0xad,0x8d,0x7d,0xe9,0xc0,0x51,0x98,0x27,0xc0,0x57,0x26,0xf9,0xce,0x25,0x45,0xdd,0x0b,},"\x29\x48\x22\x7a\x89\x0f\x6f\x84\x5b\x77\x5e\x62\xc5\x3a\xf3\x80\x50\x64\xa1\x57\x64\x46\xf0\x85\xd9\x0f\x8b\x9a\x5e\xd6\x8d\xf1\xea\x39\x3c\xe4\x79\xc4\x41\x41\x49\xa9\xec\x5a\x17\x10\x36\x42\x4d\xff\x03\x44\xb4\x95\x8f\x61\x32\x29\x8d\x0e\x24\xc9\x26\xd2\x8a\xd9\xd7\x9f\x98\xc6\xe6\xbc\xf1\xc5\x76\x76\x06\xec\xd2\x91\xc6\xad\x47\xb4\xf9\xfb\x2b\x02\x01\x15\x5a\xda\x62\x7b\x7a\x1f\xd5\xb0\x74\x19\x87\x40\x83\x05\x9e\xb5\x2b\x2f\x6e\xc2\x28\x18\xb7\x82\x46\x22\x8f\x3f\xe6\x35\x5d\xfd\xa7\x0e\xbb\x9b\xbe\x73\x22\x93\x78\x73\x63\x99\x55\x7c\xe2\x4b\x30\xbf\x64\x5a\x14\xe2\x25\x6f\x70\x01\x9b\x33\x36\xb2\x03\xfb\x77\xc6\xec\x94\xa7\xa2\x63\x48\x88\xfe\xea\xd4\xd7\x2c\x23\x91\xe9\x9e\x8c\x8d\x53\x3f\xd8\xa4\x2b\x08\xc1\x1f\x88\x7a\xb2\xde\xb6\xeb\xbf\xe3\xd2\x51\xde\x63\x53\x6c\x36\xcd\x53\x42\x23\x98\xe5\x44\xcf\xf8\x7b\x07\xa6\x33\x49\xfc\x50\x85\xdd\xe9\x3a\x1b\xfd\x71\x71\x13\x3a\x20\x43\x98\x1f\x60\x75\x22\xc8\x13\x3c\x63\x42\x8d\x1b\x92\x62\x6c\x79\xb7\x35\x8e\x70\x21\xcf\x1f\x41\x2a\x78\xaf\xa7\xcb\x3f\x59\xff\xef\x92\x79\x88\x5a\x5b\xdb\x24\x66\xac\xd3\x4c\xd5\x15\x80\x83\x0b\x83\x51\xeb\xd4\x40\xa9\x66\x23\x90\x7a\xd1\xf4\xb5\x62\x03\xf5\xe1\x59\xa4\x29\xe3\x54\x6e\xad\x0c\x01\x1d\xbe\xd0\x90\x28\x71\x7e\x3c\x3d\xfe\xd3\x91\x97\x76\x4d\x4d\x24\x5e\xf2\x28\xb9\x80\x44\x71\x8e\xf4\xd8\x82\x2f\x21\xb2\xc5\x68\x50\x38\x47\x3b\xf9\x3d\xc0\x93\x74\x51\xeb\x02\xd3\x1a\x46\xc8\xdc\x7e\x94\xc3\xe8\x67\x8c\x83\xb9\x8a\x43\x81\x8f\x12\x5b\x52\x8b\x47\x6a\xad\x31\xd1\x58\x4f\xfd\x48\xf1\x49\xe5\x73\x6e\x58\xf9\x42\x05\xd3\x88\x9e\x56\x7e\x4d\xd1\xea\xc2\xfa\xc1\xf8\xf4\xdc\x54\x0e\x53\x22\x46\x0f\xb9\x40\xe1\x2e\x93\xc4\xc9\x8d\xed\x19\x41\xc1\x90\x4f\x96\x7f\xb4\x64\x36\x84\xc1\x9a\x4d\x5c\x44\x1d\x60\xb0\xe9\xf4\x08\x55\xe5\x23\xfe\x7f\x99\x10\x76\x57\xa6\x80\x76\x27\x5b\xf8\x4b\x7c\x69\xa3\xf2\xb3\x85\x5b\xc8\x02\x6b\xa9\xb0\x0b\xc6\xfe\x34\xb9\x9d\xa0\x63\x17\x00\xa6\x7f\x52\xb3\x4e\x17\x96\x33\x98\x87\xa4\x83\x05\x12\x1d\x53\xab\x44\x40\xfc\x4b\x5c\x9b\xf7\x23\x94\xd5\xed\x37\x2f\xf1\x8c\xa3\xf0\x07\xbd\x02\xdf\x65\x1d\xc3\xac\x43\x82\x75\xf1\xa3\xe5\x24\x22\xb8\x6c\x45\x86\x76\x6a\x21\xcd\x89\xf8\x05\x80\x5d\xbb\x44\xfd\x89\xfe\x24\xfb\x2c\x0b\x40\xd1\xb7\x54\xc3\x35\xdb\xaf\xfc\x3b\x3b\xb8\xbb\x46\xc7\x4c\x36\x37\x45\x04\x04\x2d\x86\x78\x92\x27\x59\x98\x62\x31\x2e\x99\xca\x89\xeb\x50\x4c\xc3\xd7\x5d\x19\x49\x5a\xa8\x6b\x20\xb2\x73\x6b\x12\x1b\xb2\x07\x5c\x88\xed\x4a\x3f\xbd\xaa\x6b\x2c\x3f\x76\xd1\xff\x55\x25\xd3\xa2\x86\x3e\x4d\x83\xc7\x2b\xfe\x01\xe1\x02\x78\x80\x94\x74\xe1\x82\x2d\xe2\xd9\x62\x83\x48\x93\x20\x02\x96\x11\xaa\x9d\xff\xc4\x82\x9d\x66\x86\x9e\x63\x49\x4f\x9a\xad\xe7\x0b\x77\xa7\xb8\x0f\xbc\x93\xe3\xde\x4d\x93\x59\x13\x75\x2d\x04\x5e\x13\xb3\x12\xc5\xd0\x82\xf6\x24\x2d\x49\x85\xb0\x53\xb3\x78\x3e\xb0\x2c\x66\x14\x96\x3d\xc0\xd5\x5d\x4c\xbe\x88\x7b\xae\x29\xcc\x18\x97\x9e\x5e\x2e\xa9\x45\xbc\xd4\x0d\x89"}, -{{0x8b,0xd9,0x90,0x70,0xc5,0x0a,0x9f,0xa4,0x18,0xef,0x7f,0x75,0xc0,0x01,0x29,0x91,0x6a,0x41,0xc8,0x60,0x70,0x96,0x1c,0xcb,0x2b,0x20,0x2b,0xe1,0x8c,0x2d,0x10,0xd7,},{0xdd,0xd7,0x33,0x08,0xfc,0xe8,0xca,0x65,0x52,0xd0,0x39,0x42,0x8c,0x7a,0x1a,0x94,0x92,0x33,0x20,0xa3,0x1c,0x0f,0x58,0x0d,0x3c,0x23,0x52,0x80,0xf0,0x3c,0x18,0x30,},{0xb1,0x4a,0x7b,0x26,0x20,0x12,0xc5,0x90,0x9e,0x21,0xd5,0x87,0xfb,0x4f,0x29,0xa9,0x09,0x3c,0x8e,0x1c,0x29,0x99,0x81,0x6a,0x82,0x11,0x8f,0xef,0xbf,0x10,0xe6,0x8e,0xa8,0x98,0xbf,0x0d,0xa1,0x8e,0xbf,0xd0,0x34,0x1e,0xa8,0xf8,0x2a,0x18,0x44,0xc8,0xe0,0xdd,0x53,0x06,0xe5,0x09,0xb9,0xd0,0xc3,0x5b,0x47,0x3a,0x7d,0x20,0x95,0x07,},"\x48\x5f\x8d\x68\x0f\x79\xee\x2d\x82\x8b\xe7\xd0\x18\xa6\x5e\x0b\x64\xb0\xf0\x18\x48\x19\x86\x3e\x71\x10\xee\xa8\xf2\x99\xa7\x2c\x4d\xc8\x7f\x8e\xe8\xa8\xae\xaa\x81\xaf\x91\xdc\x71\xad\xea\x79\xfc\x97\x97\x42\x1c\xcc\x64\x6e\x6c\xd5\xdd\x48\xb4\xde\xc1\xde\x96\x86\x93\xfb\xce\x0d\x00\x21\xa3\xd9\x8d\x38\xa8\xbb\xc5\x81\x95\xe6\xdf\xc3\xb5\xe1\x46\x1b\x2a\x59\x41\x03\xe8\x0a\x29\x44\x1d\x5a\xaa\xf8\x89\xe3\x1c\xc8\x65\x14\x1f\x0c\x6b\x2c\x8c\x81\xf7\x21\x67\x9e\xa2\x39\x4e\xc6\xe4\x08\x1e\xc2\x03\xc2\xea\x39\x7d\x94\x84\x75\x7a\x7a\x0e\xcd\x53\xe6\x52\xdb\x9d\xf1\x7b\xea\x0e\x32\xfe\x8b\x2c\xbc\xe0\xd1\xd9\x7b\x96\x1e\xd7\x4e\x8e\x62\x2b\xcd\xd3\x55\x8b\x7c\x48\x69\x5a\xdf\x18\xaa\xe6\x11\x0e\xa9\xa3\x39\xb9\xda\x40\x7a\x9e\xda\xf2\xab\x08\x1a\x68\x1e\x18\x32\xcc\x21\x5b\x1f\x08\xa6\x7d\x55\x9a\x47\x44\xaf\x7c\xd5\x03\x18\xc2\x06\xee\x91\x15\x75\x82\xf8\x2e\xb6\xc0\xfc\x29\x02\x7b\x44\x61\xc3\x07\x33\xb8\x16\x9d\x14\x81\x32\x2c\x48\x60\x50\x9b\xa0\x96\xba\xcb\x71\xa5\x79\x24\x67\x51\xd5\x67\x54\x0e\x41\x43\x1e\x14\xf1\xb4\x6e\xf1\x6e\xba\x27\x61\x04\xbc\x01\x65\x0d\x5c\x49\x26\xe4\x7c\x9c\x60\x40\x78\x4b\x04\x3c\xd0\xaa\x48\x54\xef\xe8\x79\x7f\xd0\x46\x2d\x45\x39\xf3\x80\x35\xae\xf0\x8b\x45\x77\xc1\xa9\x11\x8d\x00\x4b\x6d\x01\x86\x2f\x52\x76\x77\x6d\xfe\xf1\x37\x18\x64\xf1\x55\xac\x0f\x07\x83\x89\xc2\x05\xcf\x05\x38\xd8\x5f\xa3\x48\x24\x4d\x7a\x42\x29\x11\x31\x0f\xf6\xc1\x01\x32\xb1\x59\x8b\xb4\x45\xc7\xe2\x07\x7b\x76\x3c\x47\x3d\x1e\x7a\x61\xa3\x8b\x64\x92\x9a\x64\x8b\x60\xb2\xe5\x43\x54\x37\x39\x22\x4b\x40\xfb\xf6\xd8\x7f\x10\x79\xc3\x0b\xc8\x73\xac\x38\x99\x1d\x51\xb8\x9e\x9d\x26\x1c\x4b\xcc\xb3\x75\x35\x5c\x07\x2c\x1e\xa2\x0e\x4f\xf9\x1d\x55\xd9\xf7\x54\x4e\x90\xd1\xc6\x64\x6c\x59\xaf\x72\x42\x4d\x8a\xaa\x8e\x0a\xed\x07\xb3\x88\x9d\x4e\x45\x0c\x12\x09\x68\x4c\xe1\x38\xd0\xc9\xda\x07\x95\x25\xf5\xaa\x02\x05\x0a\xf5\x70\xe4\x31\x5c\x2f\xa8\xb0\x99\xb7\x76\x5b\xfb\xb8\x94\xfa\xd3\x59\xb8\xe2\x48\x04\xec\xe0\x52\xac\x22\xa1\x91\x70\x53\x35\xe9\x88\x40\xa6\x24\xe4\xcb\xf3\xa1\xa1\xa3\x27\x81\x27\x85\xb2\xc0\xf5\xd6\x38\x14\x57\xb7\x2f\xdb\x63\x3e\x81\x93\x8b\xbb\x54\xb8\xc3\x7c\xcc\xb5\xd5\x9c\x58\x27\xc7\x68\x3a\x52\x47\x54\x49\x77\xe9\x84\x44\x21\x78\xd0\x85\x29\x06\xca\x6f\x94\x5c\x42\x29\xeb\x08\xad\x27\xe6\xc2\x75\xd7\xb4\xec\x8d\xc2\x5f\xb2\x81\x93\x37\xe5\x3e\xad\x6c\x7a\xa7\x87\xf9\x1a\x7d\xc6\xdd\xaf\xd5\x36\xee\xfc\xbd\xec\x2c\x50\x16\x7b\xe3\x43\x06\xa8\x2e\x16\xd5\xd5\x2b\x3b\x1b\xe0\x08\xa7\xa6\x11\x27\x4c\xe2\xcf\x8d\x62\xe3\xb9\x00\xc0\x99\x43\xbe\x70\xcc\xc7\x7b\x07\x06\x37\xc2\x50\x61\xd6\x1b\xe9\x10\xee\xf5\x0d\xf1\x87\x44\xc3\x3e\x76\xf6\x70\x1e\x0a\x8f\xf6\x29\x7f\xa6\x7e\x4b\x41\x08\xc1\x37\x56\x72\x7a\x9d\x74\xbc\x9e\x17\x98\x3e\xec\x08\xf8\x66\xb7\xc7\xff\xb3\x7f\x3c\xcb\x01\x41\xa8\x0f\xef\xf6\x32\x2b\x2a\xc6\x2b\x84\xce\x27\x97\xfd\x98\xd6\xff\x26\x9a\x41\xa0\xc3\x84\x82\xdb\x67\x98\x62\xa3\x8c\xd2"}, -{{0x1a,0xf4,0xcf,0x6d,0x24,0xab,0x37,0x82,0x86,0x7d,0x96,0xa1,0xc2,0x75,0xce,0xeb,0x02,0x2c,0x69,0x1a,0x30,0x8e,0x62,0x45,0x66,0x5d,0x61,0x6b,0xf6,0x7c,0x2c,0x32,},{0x19,0xd3,0x17,0xea,0x98,0xd3,0x5b,0xa5,0xfa,0x67,0xc1,0x2e,0xcf,0xb3,0x27,0x50,0xdf,0x27,0x5d,0x7a,0x45,0xb8,0xe2,0x11,0xa7,0xac,0x47,0xed,0xe7,0x71,0x2d,0x9f,},{0x7e,0xb4,0x6c,0xd0,0xde,0x31,0x55,0xb4,0x37,0x47,0xd7,0x32,0xf1,0x04,0x5d,0x8e,0xf7,0x44,0x92,0xad,0x82,0x7a,0x22,0x45,0xbd,0x17,0x10,0x28,0x28,0x44,0x2e,0x43,0xa0,0xce,0x7e,0x8b,0x26,0x8e,0xd7,0xfd,0x8d,0x3e,0x7b,0x28,0xf0,0x72,0x79,0x5d,0xa3,0xe0,0x70,0xf1,0x2b,0xc4,0xe2,0x3e,0xae,0xf5,0x7b,0x85,0x3c,0xee,0x88,0x0a,},"\xf4\x45\xfd\xcf\xe2\x8c\x17\xbd\x44\x27\xae\xa5\x67\x6c\x0e\x12\x80\x84\x15\x97\xe9\xd6\x6d\xe7\xd7\xa7\x17\x23\x11\x09\x39\xbe\xd0\x0f\x4e\xba\xf9\x60\x3d\x53\xc9\xcb\xf6\x27\x1b\xe5\x47\xaf\x29\xb2\xa0\x45\xec\x41\x28\x8a\x7b\xb7\x9d\x66\x2d\xc2\x10\xe2\x15\x95\x7f\xa8\x46\x88\xc9\x16\x54\x3e\x56\x17\xf5\x60\xe4\xd3\x8f\x73\xba\xef\xc3\x7e\x11\x91\x4e\x47\xc5\x15\x06\x78\x51\xe8\xed\x21\x39\x3e\x13\xdd\x19\xed\x9b\x73\xd9\x89\x45\xfc\x82\x6a\x25\x8e\x95\x7d\xc0\x83\xdd\x8e\x53\x5c\x30\xa5\x4b\x42\x66\xdd\x71\xd1\x13\xce\x85\x6b\x46\x28\x2a\x18\x03\x36\x27\xa9\x8e\x64\x72\xcc\xb4\x63\xed\x3d\x96\xfa\x7b\x35\x5d\x3b\x2c\x2a\x2b\x60\x10\xdd\x14\xf4\xea\x39\x65\xdd\x87\xbe\x1c\x42\x9b\xde\xa8\x30\x0b\x4b\x0b\x44\x45\x86\x35\xb4\x97\x9f\x5e\x3e\x8e\xb5\xc6\x18\xd4\xe1\x3e\x1d\x68\x8b\xf8\x8c\x7e\x4a\x3d\x93\x8e\x84\x33\x6d\x67\xbe\x68\xdf\x34\x35\xc5\xc9\x90\x86\x32\x1c\x02\xe1\x3b\x4a\x12\x52\x4b\x34\xe4\x6a\x0b\x4d\x27\xf3\x0d\x7e\xd4\xf5\xce\xcb\x36\xde\xad\xf0\x9e\x7e\xfc\xc7\x55\xca\x66\x75\x68\x29\x79\x14\xc6\xbc\x24\x06\x27\xd9\xd0\x9a\xac\xf8\x54\x15\x41\x2c\x06\x35\x62\x34\x53\x27\x8d\x9b\xf0\xe1\x0e\xec\x65\xfc\x72\xaf\xff\xfa\x93\x92\xdc\x78\x81\xd1\xe5\xc7\x60\xa4\x02\x80\xf1\x6b\x14\x75\x12\x7b\x91\xb6\x9c\xcb\x65\xdc\x4b\x35\xde\x10\xf9\x43\x25\xc0\xcb\xe1\xc4\x70\x19\xa2\xea\xf2\xb4\xba\x92\xd7\x85\x22\x9a\xac\xfa\xd1\x82\x6e\xbb\xde\xbe\xfb\x7d\xad\x4b\x05\xf8\x82\x43\xe1\x5f\x27\x97\x66\xe3\x32\x1d\xd8\xdb\xa6\x50\x44\x4d\x81\xfb\x08\x78\x76\x7a\x9c\x63\x53\x4b\xb4\xba\x21\x28\x5a\x24\x16\xcb\x8f\x85\x6d\x11\xa9\x6e\x0a\x8c\x8d\xe1\xe1\xa7\x51\x32\xf1\x56\x4c\xd9\x94\x99\x56\x90\xbb\xed\x2e\xe1\x54\x53\x7f\xb6\xf2\x79\xfb\x09\xc8\xde\xa6\xf6\xaf\xab\xc6\x28\x56\xe3\xd1\x28\xfd\xfa\x79\xfc\x49\x76\x19\x3b\xb9\xb3\x36\x86\x1e\x47\xb5\x6d\xc2\x58\x23\x93\xd2\xe5\x44\x65\x1a\xc8\x5b\xc5\x8e\x9e\x6a\x94\xdc\x4c\x39\xc4\xef\x72\x53\x8a\x14\xf8\x56\xcd\x95\xc3\xe2\x79\x0a\xde\xe0\x3a\xb2\xe5\x2c\xa0\xae\x47\x1d\xe5\x02\xcb\x19\xe6\x76\xaf\x35\xf5\xf9\x3d\x84\x0f\xef\x96\x06\xcb\xe9\x2d\x8b\xc2\x50\x06\x10\x5d\x92\x34\x45\x88\x83\x88\x42\xc3\xbe\x50\x5c\x73\x50\xe3\x51\xb7\x35\xe6\xcc\x6f\xb7\x92\x75\xb2\x7b\xd9\xeb\xd3\x6b\xa4\xd0\x60\xac\xee\x73\xb5\xa3\x15\xce\xff\xab\x86\xd0\x6f\x21\x68\xa6\x70\x65\x57\x81\x96\xa0\xed\x04\xa4\xdd\x71\xd6\x73\x48\x37\xdb\x08\x38\x57\xab\x1e\xb5\xe0\xee\xc4\xff\xba\xc9\x54\x4f\x4e\xc1\x9b\xde\x19\x4d\xf8\x4b\x1c\x84\x83\x41\x57\x4b\xf1\x0d\xae\xe8\x5b\x81\x78\x19\x6f\xb6\x08\x12\x3a\x80\x81\x71\xd7\x3c\xe4\x20\x6a\xd6\x52\x16\xad\x1a\x5c\xbd\xe4\x0b\x19\xd6\xae\x7f\x40\xdf\x97\xab\x84\x32\xe2\xc5\x3a\x50\x4e\xd1\x22\xe2\x5f\xb7\xa5\x1c\x14\x35\x4a\xb3\x92\x8e\xde\xb3\x9c\x29\xeb\x24\x6b\x74\xa0\x76\xf8\x9d\x03\x50\x4f\x40\x1b\xd1\x76\xb5\xcf\xfe\xe4\xb9\xdb\x09\x7c\x45\x76\x4f\x51\xaa\x37\x67\x04\xb5\xa7\xf2\x10\xb3\xf1\xa9\x05\xe2\x5d\x67\x00\x2f\x65\x57\xeb\xb7\x49\x73\x7c\xda\x31"}, -{{0x2a,0xac,0xc8,0x19,0x7f,0xf8,0xfa,0xe1,0xc1,0xcf,0x38,0x62,0xe3,0xc0,0x4a,0x21,0x78,0x29,0x51,0xf8,0xe4,0x8e,0x40,0xb5,0x88,0xf8,0xbc,0x74,0x60,0xc3,0x0a,0x03,},{0x9a,0x1b,0x01,0xe2,0x15,0x4f,0x1c,0x36,0xa8,0xe1,0x6b,0x79,0xee,0x7d,0x2d,0x05,0xb8,0x71,0x2e,0x0d,0x27,0xa0,0x61,0xa6,0xd4,0x1d,0x47,0x57,0x78,0xb0,0xdf,0x8c,},{0x64,0x7c,0xdd,0x6c,0x1a,0x67,0x29,0x0e,0x57,0x67,0x6a,0x78,0x11,0x3a,0xaa,0xdc,0xa6,0x9a,0xc5,0x7b,0x99,0x77,0x15,0xc5,0x09,0x89,0x5b,0x8c,0x5c,0x94,0xe8,0x2c,0x0b,0x6a,0xce,0xcc,0xf3,0xba,0x8b,0xd7,0xcf,0x61,0x75,0x2b,0x1b,0x19,0xd1,0x3b,0x49,0xf1,0x5f,0x8b,0xfa,0x04,0x6e,0xb4,0x42,0xa5,0x5c,0xd5,0xba,0xb1,0x42,0x02,},"\x5d\x82\x75\x2c\xe5\xda\x31\x80\xfa\xf4\x78\x7a\xed\xfb\x19\x29\x4b\x43\x48\xa1\xd9\x20\x2c\x85\x39\x83\x31\x32\x3e\x0f\x42\xb0\x83\x52\x27\xe6\x8e\x11\x56\xf2\xd4\xba\x2f\xe4\x50\xe6\xd6\xef\x2b\x92\xd8\x9b\xbb\xe4\x09\x6e\x12\xca\x83\x97\xeb\x2f\x45\xe6\x76\xf1\x67\x3a\xa4\x1c\x95\x9f\xcd\x30\xd5\x57\x88\x53\xb5\xdb\xd1\xc0\xd5\xb3\xa0\xf0\xd8\x70\xec\xa7\x1e\xa1\x33\x90\x11\x1b\x25\x8f\x65\x48\xb3\x2f\x37\xa0\x5e\x97\x44\xa6\x56\xfd\x77\x8d\x65\x72\x19\x65\xc6\xd9\xb3\x28\x60\x0b\x45\x70\x47\x70\xe0\x4b\x09\x97\x90\xaa\x78\x84\xf0\x0d\x7b\xb7\x65\x9e\x33\x72\x10\xbd\xc2\x3e\xaa\x71\xd7\xb0\x16\x03\x0a\xca\x62\x23\xb5\x56\x9b\xdf\xc2\x90\x81\x1a\xac\x40\x95\x24\xdc\xcb\xf9\xba\xbc\xbe\x4b\xf2\x09\x46\xb5\x44\x31\x7c\xa6\xf2\xf9\x18\x31\xc7\x9f\xb2\x73\xb6\x40\x4e\xb4\xe6\x1e\x1f\x7b\x10\x6e\xbd\x0d\xb9\xf2\xb1\x97\x4d\x2f\x03\x1b\xce\x25\x80\x36\x06\x55\x2c\x34\x41\x65\x5e\xfc\xf2\xc7\xea\x52\xad\xcb\x30\x99\x3d\x85\xf2\xdd\xa7\x96\x03\xe9\x41\x5a\x02\x32\x45\xa6\x6c\x07\xa9\x56\x93\x31\x46\xf5\x3c\x99\x3c\x08\x89\x18\x08\xb8\x16\x6b\x30\x72\x1f\xbd\x1f\x8a\x1b\x93\x7d\x14\x07\x0d\x78\x6e\x9e\xb4\x51\xf2\xab\x51\x42\xf8\x3a\x60\xf3\x5d\x76\xad\x8b\x81\xd6\xa5\x7c\xf3\x68\xfc\x6f\xca\xcc\x0c\x47\x58\x44\x0d\x9c\xd5\x95\xb1\xb0\x94\x2a\x36\x55\xe2\x50\xda\x98\x3b\x72\x41\x54\x6d\xcf\xbe\x0a\xe8\x10\x77\x65\x02\x95\x40\x9f\xf9\xe9\x09\x77\xfb\x99\x60\xcb\xf4\x0a\x2a\xf5\x17\x74\x02\xba\x2f\xaf\x50\xdb\x6f\x1a\x73\x65\xcf\x99\xe9\x92\x42\x9e\x38\xdb\x43\xea\x83\xfd\xdc\x95\xa6\x48\x67\x6c\x0b\x16\xbc\x95\x2b\x15\xde\x99\xd5\x2f\x6b\x52\x33\xda\x4e\xae\x19\x78\xe8\xba\x25\xe6\x23\x5a\xfb\xc5\x11\xc7\x6c\x4c\x87\x4c\x92\x37\x92\x2b\x1c\xef\x08\x47\xd0\x7a\x80\x20\x0c\xba\xe3\xc7\xc8\x1f\xcb\xd0\xd1\x72\x52\xed\x8c\x61\xad\x19\x54\xfc\x86\x2e\x1e\x04\x44\x4c\x32\x08\x6f\xee\x38\x0d\x1c\x17\x54\x13\x22\xb9\xa6\x0d\xa6\x62\x35\x2e\x21\x0e\x9a\xe2\x15\xe3\x53\x29\x6d\xb9\x22\x33\x9a\xa1\x7d\x21\x73\xec\x31\xf1\xc5\x30\xa2\x4b\x1f\x34\x8a\x31\x57\x2e\x14\x69\xca\xac\x80\x8f\x9c\x76\xec\x27\x31\x87\x3b\x80\x3e\xad\x3e\x54\xea\x24\xbc\x24\x49\x9b\x97\x04\xb3\xbd\xce\x81\x38\x9b\x9d\x14\xd4\x95\x27\xc0\x4b\x3b\xb9\xe3\xba\x6d\x94\x6c\xea\x58\xcf\x78\x6d\x4d\x28\xb8\x9b\x41\xc5\x82\x74\x03\x5a\x86\x90\x5a\xd9\x57\x58\xc3\x16\x13\x66\xab\x93\xda\x81\xe6\xb4\xc8\x08\x36\x4e\x08\x7d\xae\xea\x4c\x4c\x5c\x2a\xa6\x87\x19\x37\xc5\xfe\xab\xa2\x14\x9f\x01\xf7\x38\xf4\x53\x96\xe6\x6e\xa8\x06\x32\x21\xe1\xc8\x1c\x05\x25\x5b\xa5\x64\xad\x44\x0c\xb5\xd0\x7c\xbd\x4b\xab\x94\x1e\xa5\x93\x24\x49\x30\xbc\x5c\x28\x9b\x31\x65\xd3\xec\x88\x47\xeb\xc4\xb6\x74\xc0\xa4\x9f\x91\x69\xad\xef\x78\x6d\x77\x67\xbc\x8f\x21\x3d\xb7\xd9\x5c\x06\xe9\x9b\xc1\x1e\x20\x00\x55\xb6\x5e\xb7\x9a\xda\xa0\x1b\xcd\x2c\x85\xda\x43\xce\x63\x70\xe1\x2e\x34\x9b\xf6\xd4\x75\x48\x7a\xff\xdf\x92\xe2\x0a\x3a\xcd\xed\x1d\x76\xf9\xe8\x3e\x91\x9e\x98\xde\xf1\x95\x07\x2a\x50\xd0\xc5\x71\xdd\x25"}, -{{0xff,0x86,0x21,0x56,0xc7,0xea,0xb6,0x81,0xc9,0x5e,0xff,0xf8,0x00,0x3e,0x00,0xa1,0x4f,0x1f,0x0d,0x50,0x5d,0x55,0x07,0xe6,0xe5,0xb3,0x91,0x79,0xdf,0x9b,0x1c,0xda,},{0xe1,0xb8,0x9f,0xb3,0x11,0x14,0xea,0x46,0x10,0x7f,0xfd,0x03,0x29,0xf1,0x06,0x64,0x28,0xde,0x54,0x70,0x8e,0xdb,0xec,0xf3,0xed,0x9d,0x47,0x08,0xcd,0x14,0x3f,0xe2,},{0x4b,0x81,0x37,0x04,0x2d,0x67,0x84,0x75,0x7d,0x4a,0x9c,0x06,0xbc,0x74,0x32,0xf4,0x80,0x9b,0x1c,0x6a,0x90,0x35,0x42,0x73,0x6d,0x9a,0x57,0x66,0x8c,0x20,0x84,0x5c,0x17,0xd4,0x68,0x55,0x70,0x85,0xc5,0x7f,0xb6,0x32,0x13,0xda,0xd3,0xbe,0x0f,0xa3,0x6a,0x11,0x8f,0x7c,0x1a,0xef,0xf2,0x56,0x2f,0xf4,0xb8,0x88,0x8c,0x26,0x90,0x0e,},"\xb3\xd1\xdb\x72\xa6\xa9\x85\xec\xd7\x0a\x2c\xff\x6c\x18\xc1\x79\xe2\x17\xd4\xf4\x10\xfd\x39\x34\x96\x96\x85\x90\x1b\xd0\x71\xbc\xe6\xc2\xfb\x67\x63\xe1\x0c\x6f\xa1\x6e\x75\xa1\x17\x60\x66\xb8\xec\x81\xae\x3a\x80\x39\xe7\x1d\xc2\xcd\xc6\x4a\x40\xfd\x62\xb7\xce\xe7\xbe\x4b\xa0\x33\x2f\xe4\x5d\x0b\x60\x15\x86\x52\xe3\x3f\x8d\x3a\xff\x3c\xb4\xd6\xb0\x21\x74\x4d\x0d\xd1\x78\xb1\xbf\x0a\x1c\xc1\xd3\xfe\x93\x21\xbe\x28\x42\x1e\xb8\x82\x63\xa1\x24\xf4\x97\x92\xd0\x79\x47\x5a\x8c\x55\x5f\xf5\x69\x08\x73\x51\x4b\x5d\x48\x3e\x53\x21\x7e\x0c\xbb\x12\x86\x2b\x85\x0f\xe3\x90\xc8\xf8\x30\x08\x08\x6e\x64\x9a\xc9\x04\xb0\x18\x35\x0a\xb4\x91\x57\xee\x9b\xca\xe6\xc0\x7a\x4b\x87\x8b\x48\xe2\x5e\x98\x4f\xbb\x4d\x36\xb6\x1d\x68\x9b\x13\x46\x8a\x28\xd1\xe3\x87\xe0\xe8\x86\x57\xf8\xc8\xac\x95\x86\xa6\xe2\x6c\xf9\x4d\xff\x6f\x82\x64\xe3\xff\x62\x58\x86\x5c\x6d\xcf\x85\x7b\x00\x14\x78\x86\xe1\x75\xdf\x04\x32\xe3\x2f\x04\x40\x0e\x29\x9f\x21\x18\x83\x12\xb3\x2d\xfc\x05\x0e\x7b\x7e\x87\xee\xaa\x0c\xba\xac\x6b\xe9\x93\x7a\x5e\x0c\xc3\x11\x13\xde\x7c\x8b\x23\x3e\x1c\xe8\xe5\xd9\xc5\x64\xfb\xe9\xf3\x7b\xbd\x41\x1d\xf7\xa5\xe4\x4e\x6c\x7e\xbb\x67\x6d\x85\x89\x4d\xcc\xf4\x86\x5e\x4d\xda\x0c\xad\xef\x2b\xbc\x55\x00\x0b\x3a\x29\xf1\xf7\x1e\xf4\x46\x1d\xdc\x3b\x33\x1d\x91\x56\x65\x34\xc5\xd6\xd8\x4c\x73\x13\x76\x29\x53\x20\xf8\x0a\xdc\x90\x28\x8f\x99\x53\x55\x4f\xcd\xf9\x21\x3d\xe6\xa9\x05\x21\x0d\x4c\x80\x64\xaf\x91\xcd\x98\x32\x5e\xf9\x18\x98\xd3\x3d\x70\x03\x82\x02\xe3\x2f\xb6\x70\x9c\xa3\xd7\x88\xfe\xcb\xd1\xb8\x41\xfa\x4e\x5e\x90\x62\xd6\x42\x67\xc3\x5c\xfd\x44\x4f\xb6\x9e\x2f\x60\x47\xf5\x8b\x1c\x2a\xf4\xcc\x7e\x4c\xac\x2f\x89\x08\x88\x36\x05\x92\x11\x3e\x96\xad\x3a\x85\x7e\xd0\x5e\xaa\xba\x6f\x91\x53\xef\x89\xb9\x3e\x00\xe8\x74\x37\x33\xec\x47\x2d\x9b\x0e\xec\x1c\xd8\xfa\x52\x42\x5c\x4a\x26\xbd\x7d\xf7\x3a\x27\x12\xbe\xbe\x51\xae\x3b\x25\xeb\x78\xdb\x82\x14\x90\x31\xfe\x7b\x28\x1a\xf6\xcb\x77\x14\xed\xf8\x9d\xe9\x15\xf3\x47\x0f\x15\x3e\xed\x7f\x45\x62\x43\xbb\x90\x34\x2e\x19\x0e\x64\x7f\x39\xe0\x46\x88\x3c\xe2\x8a\x89\x20\x03\x31\x5e\xa3\x79\x42\x9e\x95\x82\xa9\x35\xeb\x78\x96\x33\x96\xd1\x36\x84\x5f\x86\xc4\x66\xe8\xfa\xf2\x27\x2f\x43\xff\xef\xc2\xad\xa5\x60\x1f\x8a\x6b\x2a\xc4\xcc\x6b\x92\x82\x09\x17\xf2\xe0\x39\x3c\x8f\xaf\x98\x2d\x6c\x5f\x4f\x23\x0e\x27\xce\x22\x78\xa7\x23\x77\x47\xfa\x85\xa9\xc8\x57\xbf\x18\x02\xc3\xea\xe0\xd2\x35\xb5\xad\x58\x49\x7d\x66\xa0\xd3\xa9\xba\xeb\xcc\x41\x7f\x18\x33\xe9\xcc\x44\x60\xf9\x75\xd7\x28\x58\xcd\x11\x8d\x7a\xaf\xaf\x1c\x87\x82\x97\xca\xcf\x71\xac\x75\x67\x6d\xc1\xb4\xfb\x51\xc1\x77\x58\x10\xd0\x35\x37\xf2\xd7\x66\x27\x8b\x99\x71\xbb\x97\xd3\xc4\x9b\x51\xfe\xb2\x6d\x37\x5e\x0c\xb9\x10\x95\x74\xa8\x16\xf8\x4e\x76\xfc\x7e\xf0\x72\xd5\x79\x3c\x2f\x65\xab\x2e\xfd\x90\x52\xe6\xb8\x56\x9f\x28\x05\x86\x1c\x31\xa7\x34\x4a\x3c\x44\x06\x9a\x94\x32\x0d\x27\x4e\x27\x12\x71\xea\xfa\x3b\xfe\x64\xde\x75\x37\x84\x6a\x01\xe5\x1f\xda\xe0"}, -{{0x58,0x26,0x19,0xab,0x3c,0xf5,0xa3,0xae,0x77,0x66,0x88,0xbf,0x6d,0xba,0xcb,0x36,0x33,0x0a,0x35,0xad,0x75,0x24,0xe4,0x9e,0xf6,0x63,0x68,0x77,0x64,0xcf,0x6e,0xc7,},{0x20,0x02,0xea,0x0a,0x38,0xa3,0x27,0xe0,0x38,0x4a,0xea,0xe4,0x68,0xdb,0x0f,0x6c,0x85,0x16,0xa6,0x96,0x09,0xaf,0x9e,0xee,0x93,0xe9,0xec,0xb9,0x4b,0x44,0x9c,0x66,},{0xfe,0x97,0x01,0xda,0x1a,0xa8,0x1c,0x55,0xba,0xc3,0x36,0x38,0xf7,0x75,0x54,0x2b,0x80,0x44,0x80,0xf3,0x4b,0x7b,0xfc,0x78,0xda,0x99,0x16,0xe5,0x24,0x6a,0x60,0x4d,0x39,0x0b,0xf9,0x20,0xc8,0x72,0xa7,0x79,0x24,0x24,0x6e,0xe8,0xd0,0x39,0x3b,0x20,0x2e,0x7b,0x25,0xb2,0x48,0x4f,0x65,0x4a,0xc3,0x67,0xcb,0x09,0x25,0xec,0xe3,0x05,},"\xca\x74\x28\x4f\x11\xc5\x6e\x25\x98\xd7\x8a\x4e\xcd\x03\xb4\x0e\x01\x7a\x55\x81\x76\x01\x2b\x26\xfd\xf6\x95\xc3\xde\x98\xa7\x4f\x8f\x40\xa4\x7d\x79\x78\xed\xc2\x4e\xe8\x09\x2b\xfe\x5e\x61\x59\x68\x34\xde\xed\x1d\x9d\x34\xa0\xf5\xcd\xae\xbe\x34\x21\xaa\x19\xe0\x12\xde\x86\x5b\x9e\xe1\xb7\x34\x79\xb2\xbd\x1a\xc9\x82\xf9\x7e\xd9\xc7\xcd\x20\x45\x9c\x60\xfb\xb1\x1e\x1e\x2b\x4e\xac\x5d\xb6\x84\x4c\x71\xd7\x29\x49\x50\x2b\xba\x50\x3a\xce\xc9\x05\xad\xba\x25\xf6\xb1\x19\xea\xf9\x63\x9f\xa8\xab\xb3\x02\xdf\xf9\x93\x2d\x85\x0c\xc4\x4c\x57\xcf\x90\xb2\xe5\x8a\x8b\x52\x51\xc1\x26\xa9\xe2\x8f\x5c\x76\x1b\x62\x80\xe2\xcd\xdd\x79\xcb\xd6\x8e\x53\xff\x4a\x62\x26\xd3\xbd\x4c\x96\x1b\x9b\x9e\x43\x45\xa2\x54\x58\x62\xc7\x97\x38\x66\xf0\x42\x0b\x89\x8e\x7b\xae\xa9\x0e\xa4\xee\x00\x40\x42\xef\x38\xa1\xfd\x95\x6a\x72\xfd\xf6\xfd\x43\x25\x7d\xa9\xfd\xb9\x66\x80\xef\x4f\xdf\x9e\x94\x3d\x26\x5c\xdc\xf2\xe5\x2e\x32\x01\xd5\x40\x8b\xc6\xce\x10\xe5\x70\x0a\xdf\x12\xb5\x5b\xa1\x4a\xa8\x29\xd8\x69\x1c\x31\xf2\x4f\xc4\xa5\x1c\xe6\xfa\xa1\xf3\xef\x2e\xad\x78\xe5\xe7\x53\x44\x6a\xd3\xfa\x4a\x84\xc1\x93\x97\x9a\xeb\xc8\x30\x9b\xad\x60\x81\x4f\x48\x59\xb9\x31\xd7\x04\x14\x76\x44\x91\xc6\xc9\xed\x8d\xb6\x73\xc5\x43\xd3\x51\x85\xcd\x28\x88\xaa\x21\xc1\xa9\x20\x34\x27\xe0\xac\x0b\x1f\xe3\x4c\x0e\x4a\x40\x01\xe0\x95\x6c\x13\xcb\x59\xa3\xba\xf8\x7c\x21\x09\xa8\x88\xa4\xc9\xe7\xaa\x48\x17\x67\xd8\x02\x0f\xf3\x5d\xd7\xc5\xcc\xec\x7c\x08\xe9\x71\xa7\xe2\x18\x13\x8c\x90\x54\x6a\x7d\xdf\x36\xad\x11\x4b\xe5\x85\x57\x43\x2c\x2d\xdf\x34\xce\xd3\x37\x9f\x70\xd4\x40\x7e\x58\x79\xf9\x84\x2f\x38\x17\x17\x05\x1b\x16\x85\xaa\x7a\xb0\xad\x38\x54\x1e\xc1\x68\xf5\x1c\xb6\x88\xf3\xcd\x1a\x01\x9a\x33\x6c\x9f\x4f\x3f\x82\xde\x78\x5c\x07\x48\x67\xfd\xc8\x80\x0f\xc7\x6f\xba\x04\xc8\xad\x8d\xe1\x0d\x2e\x9b\x43\x05\x81\xbe\x44\xc4\x1e\xcc\x8f\xc8\xa6\x16\x31\x43\x99\xd1\x8c\x64\x79\xf5\x7e\x57\x3b\x22\xa6\xee\x5c\xe2\xdc\xc0\x89\x48\xa0\xde\x1f\x0d\xd2\x5b\x65\x71\x5a\xb1\x8c\x70\xc7\x62\xfc\x3d\x7d\x60\x0c\xad\x63\x22\x60\x38\x50\x9c\x19\xab\x35\xb5\x49\x3e\xee\x73\xa7\x03\x73\x1e\xc5\x35\xc9\x0c\x6f\x06\xd9\x4d\x3e\x5f\x7e\x51\xa0\x9f\x9f\x8f\x42\xc5\x01\xb8\x50\x46\x86\x36\x5c\xee\xe9\xe0\xfe\x00\x13\x29\xf3\x03\x52\x21\x46\x71\x7c\x6a\x12\x58\xd0\xf1\x57\xcb\xea\x4b\x5a\x5e\x3d\x13\xbc\x90\x7e\x95\xfd\x6e\x8a\x71\x89\x6a\x02\xc3\x10\x6b\xd2\x6a\x51\x00\x51\xf1\xb3\x02\x58\xab\x27\xf8\x75\x67\x3b\x13\x37\xee\x36\xb7\x1a\x37\x6e\x0f\x9e\x78\x09\xa6\x7c\x67\xd9\xac\xc1\x6c\x25\x1d\xcb\x8c\x92\x6c\x8e\x93\x25\x16\xd3\x8b\x72\x33\xea\xc6\x15\x9c\x59\xca\xd0\x30\x7c\x59\x0e\x71\x31\xb6\x22\x19\x14\x5a\xaa\x35\x5b\xfb\x4a\xcb\x6a\xf0\xa5\x50\x00\x06\xcd\xd8\xb8\x13\xfe\x19\x08\x60\x2e\x08\x74\xc9\x62\x2b\xb3\x76\x73\xba\x1a\xcb\xa4\x14\x23\x16\x67\xbc\xc4\x90\x7a\xc8\x71\xf8\x7e\x6c\xe3\xf5\x91\xc1\x91\x71\x05\x7a\x9f\x45\x7f\x53\x62\xae\xda\x10\x5d\x18\xfb\x84\xf7\xd0\xf0\xa7\xda\x7e\xf8\xda\x91\x14"}, -{{0x2b,0xbd,0x83,0x0c,0xe7,0xde,0xf3,0xfe,0xce,0xa1,0xec,0xd6,0xea,0x0a,0xe9,0xc9,0xf4,0xfa,0x8f,0xfc,0x3b,0x1f,0x19,0x38,0xc5,0x05,0x05,0x1b,0xab,0x40,0xcf,0x7a,},{0x0f,0xdf,0xed,0x8d,0xe3,0xc1,0xea,0xf8,0x91,0xce,0x37,0xe3,0x4c,0xb4,0xa2,0x44,0x1c,0xbb,0xae,0x08,0x83,0x38,0x3d,0x70,0xde,0x24,0x64,0x85,0x0b,0x4a,0x64,0x2a,},{0x13,0xeb,0xc9,0x79,0xa8,0x87,0x10,0xe3,0xc5,0xf3,0x45,0xcf,0xbb,0x82,0x48,0x13,0xb3,0x08,0xa9,0xd5,0xc6,0xde,0xe3,0x28,0xbf,0xd2,0x35,0xa9,0x7d,0xe7,0xb3,0x26,0xde,0x6c,0x73,0x8f,0x96,0xf6,0x98,0x31,0x94,0x92,0x09,0x99,0x68,0x52,0xdd,0x9c,0x09,0x8d,0x58,0x08,0x41,0x87,0x09,0xf2,0xbf,0x51,0x0d,0x46,0xb7,0xf0,0x36,0x06,},"\x5f\x1e\xde\xaa\x3c\x0b\x2a\x63\x31\x1d\x97\xf1\xc5\x4e\x7e\x2f\x68\x71\x70\xe6\xb4\x6e\x21\x69\xcb\xf5\x6c\x66\xf2\x31\xbf\xc4\xa5\x76\xbd\x2b\x84\x20\xbf\x35\x7d\x3a\x90\xf8\xf3\x2e\xa1\xad\x99\x39\xb4\x67\x25\x4b\x66\xa1\xdf\x1f\x5b\x4c\xba\xc6\x3a\x5c\x27\x24\x26\x0d\x24\xd8\xdf\x8e\xdb\x58\xae\x24\x7a\x25\x91\xe9\x20\xb1\xa4\x20\xcf\x8d\x85\x39\xea\x57\xdb\x0d\xad\xff\x1a\xd3\xe9\x8c\x31\x72\xd0\x33\x16\x3c\xb4\x34\xa7\x66\xb0\xc1\x18\xa5\x6a\xbd\xcc\xe7\x9c\x82\xaf\x7b\xac\x74\xed\x0e\xa0\x24\xac\x4c\xe0\x22\x2d\x0a\xa9\x14\xf4\x32\x09\x2b\x1b\x51\x78\x04\xdb\x59\x18\xa8\x45\xe9\xcc\xa5\x5a\x87\xdb\x7c\x28\x52\xf7\xdd\x2e\x48\x36\x01\x85\xcc\x44\x2c\x79\x30\xaf\xe1\x5d\xd6\x22\xcc\x02\xbc\xd1\xee\x77\x8b\x59\x70\x5f\x14\x33\x32\x41\x58\x8a\x52\x2d\xe2\x44\x07\xe8\xe6\xe1\x0d\x5e\xf3\xa8\x8e\x3a\x3c\x44\x38\xc1\x7f\x75\x04\x67\x4f\xd7\xe4\x18\xcb\x2f\x77\xad\x0a\x56\xd2\x38\x67\x03\x15\x5e\x9a\x40\x1c\x43\xdd\xb5\x1e\xad\x55\x20\xaa\x7b\xa0\x38\xe7\xde\x53\x31\x41\x8a\xd5\x52\xbd\xcd\x18\x5f\x50\x3a\x85\x48\xf5\x5b\x63\x86\xe4\x68\x7c\xa5\x15\xf7\xc0\xee\xa5\x70\x98\x3b\xfb\x24\xbe\x16\xf7\xb3\x00\x3f\xb7\x56\xe3\x26\x56\x2f\x2a\x32\xfe\x65\xff\x84\x4c\x39\x84\xc7\x2e\x40\xdd\x49\xe4\xf3\xae\x8c\x0f\x81\x9a\x79\x39\xb2\xe7\x36\xe3\x81\xf5\x82\x3c\xbc\x61\xb2\xed\x01\xd9\xb0\x5c\xf8\xb1\x46\x48\xa4\x8b\x0d\x7c\xbe\x88\x2a\xc1\x6c\xad\xd8\xc4\x2a\xa2\xc7\x02\x46\x34\x7b\x4d\x84\x95\x36\xa7\xac\x22\xc7\x20\xda\x3c\xf1\x78\x72\x5e\xe5\x57\xa9\x2c\x25\xb1\x2b\x8b\x95\x6d\x3b\xf4\x80\x2e\x9e\x8a\x15\xb5\xab\x75\x42\x35\xcc\xa0\xe5\xb7\xe5\x5e\x4a\xec\xe4\x5a\x47\xe0\x84\xce\x14\x47\x44\x05\x98\xef\x5d\x4f\x5f\xdc\x2c\x98\xa5\xad\x13\x6c\xff\xbf\x87\xd3\xcf\x52\xf6\x73\x8c\xca\x79\x48\x35\x60\x92\x07\x8f\xdf\x25\x45\x77\xf5\x59\x69\xa0\xc6\x52\x46\xda\xc8\x09\xa2\xfc\xa1\xf6\x0a\x1d\x92\x98\x77\xb9\xa6\x54\x0e\x88\xa9\xe6\xe9\x15\x59\x38\xd2\x2c\x68\x7e\x63\xb3\x87\x53\x4d\x38\x5e\x89\x61\xe5\x88\x67\x43\xf9\x5f\x4a\x70\x80\xd9\x16\x62\x45\x17\xb1\x53\x36\x03\x0a\x46\x71\x4b\x16\x8b\x83\xd6\xf9\xcc\xe0\x60\x66\x49\xc0\x1f\x0a\x1d\x0a\x2a\x53\xf5\xe3\x78\xf6\xaa\x98\xc3\x84\xaa\xfb\x3e\xef\xdb\x34\x21\xfa\x3a\xc9\x8a\x0d\x3a\x9c\x02\x9c\x23\x00\xae\x02\x41\x06\x7d\x1a\x4f\xc9\x2e\x43\x86\x88\xea\x88\x9f\xcb\x1a\x1a\x9e\x86\x34\xb9\x16\xc6\x0b\xaa\x0c\x18\xbf\xcd\x13\x9b\xfe\x30\x17\xbf\xbe\x16\x29\x13\x43\xce\x86\x05\xbb\x78\x72\x55\x8c\x6b\x5f\xd5\x6d\xfd\x22\x15\x77\xed\xcf\xfa\xa8\xbd\xa3\x4d\x7a\x11\xab\x8c\xb2\x78\x28\x8e\x58\x34\x84\x26\x76\xfc\xcf\xfa\xa9\x11\x1b\xce\xd2\xb3\x57\x5f\xdd\x49\x62\x1b\x76\xe8\xd1\x29\xb6\x17\x00\xee\xab\x03\x14\xef\x94\xd5\x50\x50\x6a\x4b\x8d\x1e\xe6\x55\x08\xd8\x9d\x0e\x99\xe9\x33\x6b\x41\xd9\xf7\x4a\xa4\xd7\x22\x11\x4d\xe0\xf3\x1e\xcf\x00\xb0\x97\xf5\x3c\x9a\xca\x9c\x7a\x28\x5b\x58\xa3\x5d\x70\x29\x8c\x5c\x34\xf7\x4b\x4a\x70\x53\x08\x03\x31\x00\x34\x9f\x0c\x62\xf9\xc2\xeb\xf7\xde\xad\x0a\x77\xb2\x98\xeb"}, -{{0x1a,0x7a,0x3c,0x2f,0x54,0x81,0x13,0x1b,0xe5,0xf8,0x68,0x45,0x6a,0xa2,0xfa,0x90,0xe5,0x6d,0x52,0xcb,0x72,0x1c,0x71,0x84,0xeb,0xff,0x06,0xfe,0xd2,0xfe,0x68,0x5d,},{0x7c,0x2a,0xd0,0xf2,0xa5,0x70,0x55,0x03,0x26,0xfb,0x50,0xa8,0x50,0x83,0x58,0x21,0x67,0x6d,0xe1,0xde,0x12,0x7f,0x6d,0xe1,0x67,0x02,0x99,0xd8,0x14,0xf6,0xe3,0xce,},{0x97,0x61,0x60,0xfb,0x5b,0xbd,0xab,0xe5,0xc8,0x96,0x2f,0x23,0xba,0xba,0xcf,0x0b,0x0a,0xb4,0x1c,0x2b,0xb1,0x3e,0x9c,0x0d,0x44,0x90,0x67,0xb7,0xde,0xcc,0x7d,0xb4,0xe9,0x4e,0x76,0xa7,0x1b,0x9c,0x0a,0xc4,0xd6,0xaf,0x38,0x7a,0x72,0xa8,0xcd,0x73,0xe3,0xbc,0x63,0xb7,0xed,0x65,0x0b,0xee,0xbf,0x17,0x42,0x4c,0x49,0x0b,0xd6,0x0d,},"\xc6\x28\x34\xd9\xd5\x5d\x1a\x44\x03\xe9\x25\xd0\xa5\xb5\x52\xda\x17\x4c\x02\xf4\xe9\x45\xde\xc3\x38\xc1\xbb\xb2\xae\xb4\xff\x40\x02\x0e\xf7\x0f\xf5\x05\x20\x5c\xf8\x81\xb6\x29\x96\x0a\xbd\x62\x76\x4e\x5a\x54\xf2\xb5\x10\x56\x67\xb1\x1c\x7d\x5b\x7a\x4c\xcc\x3f\x48\x8b\xdd\xdb\x95\x8a\x7b\xe9\x54\x62\x07\xe6\xc4\x67\x18\x97\xc0\x53\x50\x8e\x1f\xd8\x32\x22\x13\x0a\x79\x33\x97\x6d\x2b\xec\x61\x4e\xd8\xf9\xb6\xa6\xb9\xf4\xef\xb2\xa5\x8b\x9d\x00\x5b\x94\x3e\x42\xf1\x71\xb7\x09\xa7\x31\x30\x70\xcb\x2e\x06\x8d\xa3\x9c\xf9\x99\x22\xb6\x9e\x28\x5c\x82\xad\x97\xf2\xd6\xc7\x79\x22\xca\xe2\xb5\xe3\x20\xe8\x35\x77\xc0\xd0\x88\x76\x1e\xc8\x81\x52\xc2\x97\x49\x29\x78\xa9\xd7\xa3\xff\x67\xed\xe4\x4c\x2a\x70\x7c\xf3\xe2\x35\x2e\x23\x2f\x53\xc8\x78\x2b\xa4\x89\x28\xa9\x7f\x8a\x36\xb2\x0a\x41\x68\x16\xe9\x45\x79\xb9\xd7\x25\x0a\x29\xdc\x84\x70\xf6\x3a\x70\x58\xe2\xd2\xa9\x9d\x6f\x0c\xcb\x53\x0d\xf5\x96\x95\x05\xef\x5c\x78\x44\xeb\x16\x7d\x20\xf4\x12\xa5\x08\xfa\xb1\xf8\xcd\x9c\x20\xc5\xeb\x9a\x41\x7a\x54\x12\xb5\xda\x6a\x57\x13\x57\x59\xfa\xb1\x7f\x63\x14\xf6\x8d\xf3\x5b\x17\x72\x42\x14\x43\x67\x6f\x31\x25\x79\xaf\x6b\x14\x11\x53\x5a\xda\x8f\x76\x01\x2b\x69\xbb\xeb\x60\xb2\x89\x7e\xe6\x60\x7c\xb3\x69\xcd\xf5\x2f\x4f\x6d\xdf\x88\xcd\xb2\x63\x0d\x78\x89\x6f\x13\x61\xfe\xa2\x2a\xe6\x34\x21\x76\x96\xff\x11\x4f\xb4\x2d\xbe\x4f\x43\x46\xf1\xbe\x5b\x57\xad\xb3\x84\xae\x7e\x49\xb4\x1f\x74\xb3\x1b\x9a\x62\xbc\x69\xdc\xa1\x65\x89\xc6\x34\xeb\x9d\x7c\x6c\x94\xf8\xec\xe4\x4b\x60\x62\x8f\x98\xe1\x02\x4c\xf3\x2e\x3e\x3d\xd6\xdc\xe5\x5a\x12\x22\x53\x2f\x49\x0d\x63\xe6\xa2\x75\x28\x1c\x0f\x3a\x6c\x10\x18\x91\xb8\xd5\x7a\x45\xde\x11\xde\x35\xeb\xb1\x51\xc0\xdc\xd7\x5e\x6c\x05\x0b\x3c\xd8\xba\xba\xe8\x45\xc3\x9f\x66\xc3\x6c\x77\xcd\xe0\x5b\x68\x3e\x4f\xb0\x10\x3d\x93\xe7\x65\x93\x35\xc8\x7f\xc0\xe3\x23\x5b\x2e\x82\x48\x8c\xda\xbe\xb5\xc5\xc8\x75\x80\x87\x45\xee\xa9\x2d\xe8\x6b\x8e\xfc\xb6\x3e\x16\xd0\x82\x91\x9a\xee\x2e\x92\x89\x9c\xb0\xbc\xf1\xc1\x42\x15\x77\xa4\xa0\xd9\xdb\x09\xee\x1f\x9f\xeb\x92\xa5\x38\x21\x03\xcf\x7c\x32\xcf\xe4\x63\x72\x5a\xe4\x86\x6d\xaa\xfe\xda\x05\x34\xc1\x69\xf8\xf9\xbe\x40\x4f\x3b\xaa\xe1\x23\xfa\x76\x8a\xce\x46\x17\x8d\x4b\x9b\xbc\x5b\xd7\xae\xec\x79\x03\xb0\xa5\xbc\x57\x53\x89\x86\xee\x09\xe0\x7e\x32\x07\x7b\x3b\x9d\xe5\x0d\xd1\x96\x7a\x37\x2c\x38\x5a\xc8\x86\x28\x7c\x18\x45\x1a\x64\xef\xb3\x7d\x05\x6f\x9f\x41\x94\xc0\x8b\x1e\x3e\xc9\x70\x22\x26\x7b\xf0\x04\x3c\x13\xd2\x6b\x9c\xe1\xf5\x39\x05\xf6\xe4\x1b\x3d\x99\xdc\x81\xb3\x31\x90\x9b\x72\x26\x66\xef\x24\x32\xe6\xaf\x8a\x45\x31\x07\x53\x12\x30\xce\x4a\x1a\xf8\xee\xd6\x26\xda\x22\x3d\xa7\x6b\x46\x50\x7e\x33\xd7\xcd\xbd\xe0\x2d\x41\x10\x40\xc8\x9a\x11\xd9\x51\x56\xed\x4a\xc2\x60\x5b\x82\x69\x39\xc6\xcf\x87\x7b\x4e\xe7\x36\xc5\xda\x77\xcf\x46\x50\xa9\x99\x7a\x3b\x9c\xf4\x6a\x82\xba\x2b\xc0\x13\x33\xc0\x44\x78\xb5\xc9\x2e\x24\x98\xbd\x00\x2f\x01\x31\x40\xae\xdb\x30\x1b\x95\x99\x3d\x1d\x75\x08\x70\xd9\x88"}, -{{0x19,0x1a,0x1d,0x90,0x32,0x1c,0x7f,0x4e,0x74,0x94,0xbb,0x98,0x29,0x09,0xa9,0xeb,0x40,0xc3,0x34,0x1d,0xd3,0x2a,0xe4,0xd9,0x67,0x50,0xb7,0xd0,0x29,0x66,0xb4,0x0f,},{0x95,0x62,0xd9,0xe2,0x13,0xf1,0x45,0xc4,0x56,0x93,0x5b,0x70,0x31,0xc6,0x80,0x66,0x9f,0x8b,0xbd,0x31,0xa4,0xc2,0xed,0x3c,0x91,0xc4,0x00,0x2a,0x56,0x29,0xe9,0x7b,},{0x74,0xcb,0x02,0x8d,0xc6,0xb7,0x5b,0x37,0xa1,0xda,0xea,0x1c,0xf8,0x84,0x65,0xdb,0x83,0xa0,0x09,0x3f,0xec,0xb2,0x2d,0x99,0xba,0x85,0x5e,0x9a,0xb5,0x9d,0x05,0xcb,0x22,0xc8,0x7d,0x0b,0x09,0xdf,0x7c,0x11,0x62,0x13,0xba,0xa8,0xf1,0x89,0xb2,0x70,0x3f,0xf9,0x53,0xcd,0x20,0x2e,0xb9,0xde,0xa3,0x97,0x6e,0xe8,0x8f,0x5f,0xa7,0x03,},"\x85\x89\x0d\xb4\xe2\xfb\xce\x09\x3d\xde\x5a\x80\xbf\x8f\xe0\x9a\x98\x4b\x83\xa4\x9b\x7c\xcb\x5d\x4b\x06\xcd\xaf\xdd\xd3\x82\xe4\xb8\xa8\xa5\x05\x30\xe8\x2c\x20\x06\x12\xc9\xd7\xd8\xa0\x89\xbc\x8a\xa8\x45\xc3\xcf\xcc\x38\xa6\x19\x5d\x21\xc2\x61\x8c\x3d\xba\x2b\x57\x09\x20\xec\xcf\xcd\x23\x6f\x17\xf0\x8d\x81\x42\x68\xf8\x82\x24\x2d\xdf\x07\x02\xda\x87\x85\xf4\x07\xaa\x8f\x86\xfe\xcf\xa9\x03\xc4\x8d\xa8\x3f\x83\x97\x77\xeb\x6b\x4a\x2b\xbf\x5d\xf7\xa4\xda\x53\x47\x5a\xf1\xff\xe4\x4b\x5f\xe0\x07\x2b\x8f\xbf\x3d\x26\xe6\xd8\x9e\xa6\x7d\x8a\xc8\x45\x94\x92\x89\x0a\xda\x65\x7e\xb3\xdc\x24\x92\xb8\x8d\xe1\x75\xb4\xbb\xa1\xa5\x08\x06\x4d\x61\x96\x74\xaa\xae\x2a\xf0\x9d\x31\xa5\xc2\x7c\x8d\x5d\x5a\x29\xb0\x37\x79\xf4\x28\x6b\x89\x66\xce\x40\x7e\x6f\xf6\x92\xfb\x94\x25\x20\xa9\x93\x8d\x69\xcc\x70\xac\xb0\x6b\x01\x4b\x6d\xfc\x19\x83\x42\x06\xcf\x1a\xc6\xc4\x48\xae\x6f\x07\x80\x25\xb5\x5f\x3d\x82\x72\x01\x26\x8a\x92\xad\xd9\xad\x17\x8e\xf7\x6a\x29\x89\xfe\xdc\x6e\x39\xf4\xeb\xb9\xf9\x6c\x9b\x83\x52\x69\x4f\xa5\x4f\xa0\x22\x01\x9c\x0e\xc0\x01\x2d\x0d\x76\x9e\x23\x67\x80\x3f\x92\x5f\x17\x5f\x9f\xb9\xcb\xec\x4a\x0c\x9c\x1e\x2c\x83\xea\x57\xe6\xa9\x2a\x17\xf5\x55\xca\xb9\x34\x27\x1e\x72\xc8\xcc\x32\x15\xfc\xb8\x7c\x20\x53\x9b\xf1\x42\x77\xb1\xbf\xbd\x6e\x58\x80\xef\x95\x3f\xc7\x5f\x23\xc0\xdd\x4f\xcc\x1e\x0b\xe3\x40\xaf\x94\x7d\xe0\x2e\x87\x7f\xd5\xc7\x7d\xd1\xdf\x7b\x41\x4b\x5c\x0b\x40\xc7\x49\x56\xa5\x45\xa1\x15\xb0\xc6\x99\x3a\xb2\x33\xb7\xe7\x2c\x82\x2b\x6b\x33\x81\xbb\x1f\xc1\x08\x75\xbf\xfe\x3e\x2e\xd1\x19\x0f\xa3\x3f\xc1\x5d\xa0\x83\x79\x4f\xcc\x2c\x5b\xf5\xa0\x79\x09\x06\x3c\xb2\x89\xa0\x8a\x2c\x8a\x33\xd3\x43\x84\x2c\x2d\x6a\x3c\xfa\x2a\x16\xca\x2e\xaf\xca\xb7\xea\x10\x0d\x1c\x71\x4b\xaa\xbb\x71\x49\xf0\x7e\x25\xde\xe3\x23\xe7\x80\x75\x7d\xfa\x80\x16\xfa\xa7\xc0\x62\x62\x22\xc3\x65\xf8\xf2\xf6\x68\x7d\x1d\xed\x23\x4f\x79\x9c\xc5\x0d\x1c\xd2\x6b\x4c\xfa\x40\x45\x91\x70\x56\xfc\x79\xc3\xb8\x8b\x2b\x19\x08\xe3\x72\xdf\x66\xda\xc8\x73\x46\x31\x64\x83\x49\xbc\x37\xfa\x34\xb2\x5f\xff\x3b\x07\x47\xb6\xbc\x16\xb9\x4e\x3e\x58\x95\xe4\xbb\xd9\x3d\x47\x8a\x6c\x1f\x75\xe4\xfa\x30\xfa\xa9\x22\x04\x9e\xd4\xc5\x0f\x12\xf4\xb3\x12\xa8\x97\x4d\x0f\xed\x8d\x44\x25\x5d\xcb\x2b\xf0\xfe\xbe\x47\xfb\x3f\xb8\xed\x99\x03\xb5\xba\x4c\xa1\x8e\x3c\xc6\x76\x2c\xfa\x1e\xaf\x04\xdf\xa9\x44\xd4\x96\xe0\xfe\x8b\xb7\xdc\x04\x54\x51\x39\x6b\xfa\xba\x54\x85\xd9\xd5\xf3\x91\xa9\x54\xc3\x71\x42\x53\xcc\xd9\xb1\x99\x64\xd4\x28\x06\x80\x72\x07\x83\x03\x6b\x3a\xbf\xaf\x28\x84\x58\x3e\xa5\xbd\xbc\xf6\x9d\x08\x89\x7a\xb2\x88\x31\x46\x35\xab\xb4\xc2\x96\x4b\x71\xad\x92\x91\xfe\xb5\xb6\x1f\x80\xe9\xb0\xcc\x07\xf9\x12\xa8\xe5\x59\x8d\x55\x48\xde\xfe\x0e\xea\x1c\x44\x85\x73\x71\x0a\xac\xdd\xb1\x52\xf9\x3c\x7c\x6f\xd3\xf7\xe4\xed\x9f\x74\x42\xa6\xb9\x00\xf2\x3c\x3c\x54\x4c\xe5\xc9\xba\x5f\x5e\x92\xaa\xfd\x11\xc9\xff\x5f\x79\xc0\x8b\x9d\x04\x5f\xef\x07\x97\x06\x25\xf6\x2e\x2f\x43\x34\xa4\xd6\x64\xca\xf7"}, -{{0x62,0x85,0x63,0xaa,0x3e,0xe2,0xfc,0x61,0x1b,0xcf,0xf7,0x8b,0xfb,0x2a,0x75,0xe9,0xfd,0x87,0x80,0xe8,0x7a,0x93,0x94,0x99,0xa6,0x1b,0xea,0xa6,0xa4,0xb7,0x19,0x13,},{0xda,0x20,0x61,0x6e,0xe4,0xa4,0x1c,0x2e,0xbf,0xdc,0x50,0xab,0x54,0x95,0x3b,0x6d,0x38,0x7b,0x06,0xc6,0xde,0xf7,0x57,0x96,0xb0,0x88,0x09,0x56,0x5c,0x6c,0xf8,0x05,},{0xc9,0xa6,0xaa,0xa9,0xb4,0xe1,0xcc,0xe1,0xb5,0x84,0x45,0x72,0x5f,0x61,0xf5,0x52,0xc8,0xfb,0x45,0x83,0x1f,0x03,0x48,0x27,0x98,0xf0,0x1f,0x66,0x3e,0x99,0x83,0xdb,0x1a,0x82,0xfd,0x33,0xab,0xa3,0xec,0xcb,0x96,0x22,0x64,0x26,0xd5,0x0a,0xe1,0x7c,0xc5,0x12,0x74,0xce,0x18,0xa3,0x88,0x60,0xf4,0x0b,0x2f,0x82,0x36,0x1b,0x5c,0x03,},"\x05\x6f\xb9\x54\xfb\xe6\xa6\x01\x4f\xad\xac\x1e\x1a\x9f\x56\xcc\x08\xaf\x37\x34\x8e\xba\xf6\x92\x06\x83\x38\x4e\xfa\x47\x62\x6c\xcd\xdf\xea\xd2\xd5\xe9\xe8\xcf\xff\x45\xf7\xac\x63\xde\x63\xf6\x9d\x12\x84\x8c\xe3\xc0\xef\x1f\x53\x0a\xde\x43\x0f\x0a\xfd\x5d\x8e\xcf\xd9\xff\xd6\x0a\x79\x74\x6a\x2c\x5b\xee\xdd\x3e\x67\x24\x99\x82\xf8\xb6\x09\x2e\xe2\xd3\x40\x47\xaf\x88\xa8\x1f\xea\xb5\xd5\x2b\x47\xd5\xb3\xf7\x6c\x20\x41\x72\x5f\x6f\x81\x32\x93\x05\x0a\xaa\x83\x4b\x01\xa3\xa5\x8f\x69\xaa\x4a\x8c\xa6\x1f\x5b\x74\x6f\x60\x0f\x3d\x45\x2c\x62\x82\xff\xdc\xa4\x42\x9b\x93\x38\x96\x7b\xa3\xa7\x26\x66\x90\xae\xc7\x5e\xbf\xbf\x7b\xe9\x8d\x99\x9b\x03\xed\xdc\x72\x92\x58\x1b\x0d\x69\xe3\x0a\x03\x51\xa1\x51\xdb\x70\x41\x2b\x0b\xfd\x43\xd3\xba\xa9\xd4\x56\xcb\x3e\x0b\x4f\xc1\x9c\xb0\x9e\x6c\xad\xcb\x6d\x3f\x3b\xe5\x13\x7c\xc7\xa8\xd3\x21\x9e\xc2\x03\x6e\xc6\x70\xed\x7e\xc5\x23\xb1\xb1\xc6\x87\xb5\x46\x53\x07\x88\x2f\xe3\x8d\x74\x72\xd0\xba\x87\xa4\x71\x86\x83\x09\xd2\xf7\x73\xff\x24\xc8\x7d\x39\xc1\x6b\x70\x8a\x4e\xd9\xaf\x43\xf7\x4c\x8d\x85\xcf\xe8\xab\x54\x06\x90\x7e\x94\x1a\x14\x97\x0e\x20\x9c\x29\xff\x7e\xd8\xa2\xf9\x35\xae\x41\x70\x9f\x27\x0d\x0d\x08\x55\x5e\xf7\xaf\x2e\xdf\xe4\x0d\xf3\x99\x22\x3c\x78\x5a\x43\xe7\xf3\x69\x15\x89\xe2\xea\x4c\x03\x6f\x11\xd0\x3d\x7d\x1e\xea\x14\xf6\x20\x03\x53\x25\xcf\x2b\x33\xba\xf3\x86\x39\x3e\x8a\x97\x2a\x7a\xf6\xcd\x9b\x85\x43\xb3\x2e\x25\x33\xd1\xfc\xc3\x17\x7f\xd9\x6d\x1e\x13\xbf\x8b\x68\xde\xb2\x22\xf9\x44\x97\x26\x5d\x3c\xcb\x34\x57\x51\xbd\x5b\x66\x90\x78\x08\x19\x98\xd6\x08\xca\x5f\xdc\x13\x48\x39\xd4\xed\x2b\xeb\xb2\x95\x2f\xea\x5a\x39\xc6\xf0\x33\xc1\x55\x8f\x69\x8c\xe4\x94\x6e\x4f\x6c\x08\xaf\x87\x4f\x27\x35\x7f\x87\x0e\xbe\xeb\x21\x99\x97\x6f\xfa\xef\xac\x95\x1f\x8e\x17\xfe\x7d\x08\x21\xe1\xb9\x2a\x90\xaa\x4e\x9d\xef\xd3\xfa\xfd\xa0\x52\xa4\x44\x47\x6d\xb1\xce\x38\xa9\xe1\x76\xe8\x41\x18\x9a\xbd\x8f\xec\xde\x0f\xbc\x5c\xb5\x5f\x51\x1f\x5f\xde\x07\xea\x97\xde\xb3\x9b\x7a\xa8\xdc\x84\xa3\x94\x6a\x6c\xf9\x26\xd3\x9b\x95\xc1\x1a\xf9\xd6\x4d\x98\xb8\x07\xf4\x70\x4d\x0a\x2b\xda\x97\xda\xd9\x88\x1a\xda\x1b\xf6\x63\x63\x66\xe6\x0a\x52\x2b\x48\x21\x04\x78\x61\xc7\xaa\xe2\x14\x6a\x02\xee\xf6\xb2\x5d\x51\x37\x1a\x0f\x17\xd2\x4b\xc1\x87\xdc\xdd\x05\xd5\x41\xc2\xf7\x22\x01\x42\x79\x15\xa3\x92\x8c\xd3\x78\x68\x91\x03\xac\x50\xb3\x3f\x87\xa4\x7e\x8c\xdf\xa6\x87\xa5\xf0\xaf\x8a\x56\x73\x1d\xab\xe6\x62\xf4\xf2\x83\x6d\xe0\xba\x8f\xaf\xd8\x6a\x38\x54\xbc\xa0\x12\xd7\x08\x8a\x00\xb9\x85\x4c\x2d\x3c\x70\x8d\xdf\x58\xfa\xa3\x55\xa8\x9a\xfc\x2c\x80\xf3\xf5\x33\x6d\xa0\x1d\x72\xa2\x77\x1a\x05\x58\x13\xfb\x35\x33\x0f\x7d\x2e\x01\xb1\xd1\x2d\xaa\x95\xed\x55\xd3\xbd\xc5\xdf\x77\x39\xcb\xc3\xca\x09\x7a\x41\xb6\xb2\xbd\x7f\x0f\xf9\xdd\x1d\x86\x58\x98\x3b\xa3\xff\x79\x20\xc1\x5f\x29\x2a\x1e\xf9\xfc\xad\xa1\xc6\x07\xec\xb4\x5d\x3a\x73\xc9\xff\xd4\x2f\x3e\x16\x02\x2f\xdf\xe1\x27\x44\x92\x63\x95\xf7\x4f\xb3\x11\x17\x93\xfa\x92\x81\x82\x1a\x66\xa0\x1d"}, -{{0x91,0x41,0xf7,0x9e,0xd3,0x0b,0xf6,0x00,0x61,0x1a,0x13,0xf3,0x67,0xb4,0x03,0x96,0xf2,0xec,0x83,0x9c,0x56,0x12,0xbb,0xf1,0xe6,0xe4,0x97,0xf8,0x39,0x54,0xbc,0x88,},{0xf1,0x4e,0xda,0x96,0x26,0x40,0xbe,0xcb,0x66,0xc4,0xd1,0xf1,0xa0,0x21,0x11,0x02,0x51,0x91,0x7b,0x8b,0x1d,0x34,0x82,0x82,0x98,0xd3,0x21,0x45,0xba,0xf6,0xe5,0xd9,},{0xcf,0x20,0x2d,0x7f,0x2f,0x9e,0xd1,0x17,0xf4,0x29,0x50,0x2b,0x2a,0x5a,0xff,0x54,0xa7,0xf7,0x51,0xd2,0x17,0x15,0x15,0xa4,0xd2,0x03,0x75,0x34,0x46,0xdf,0x0e,0xba,0xc8,0x69,0x84,0xc8,0x8b,0xd4,0x2b,0xd1,0xfb,0x8d,0xcb,0x40,0x87,0x76,0x72,0x2a,0x38,0xf3,0x2c,0xce,0xb2,0x5f,0x32,0xa2,0x5d,0x73,0x93,0xf1,0x38,0xee,0xdf,0x0a,},"\x8f\xec\xaa\x7a\xe9\xa3\xd4\xa4\x85\x1a\x66\x36\x2b\x36\x6e\x16\x7b\x9f\x43\x00\xfd\xab\x20\x56\x54\x75\x19\x87\xf0\x85\xde\x61\xbe\xc9\x34\x4a\xa8\x6f\x5e\x5c\x64\x77\x51\x4c\x28\x04\xce\xd7\xac\x0c\xd0\x62\x85\x29\xa3\xa1\x59\x92\x36\xed\x67\xbe\xbe\x1f\x2e\x95\xaa\x15\x1f\xe0\xf3\xb3\x01\x1a\x1d\x4b\xe9\x90\x1c\xaf\xab\x2f\x18\x91\x90\x4d\x4b\xff\x01\x28\xc1\xd3\x5e\xce\xcb\x32\x2b\x3c\xc0\x1d\xac\xc5\xae\x3d\xca\x69\x14\xa7\xd3\x4d\xa8\xc9\x65\x7b\x95\x0f\x89\xd1\xd6\xae\xc3\x29\x9b\xb6\x90\x11\x10\x71\xfa\x87\x28\x27\x74\x94\x3d\x96\xa4\xab\x7c\x3d\x6d\xe7\xd1\xbf\x11\x93\x63\x06\x8c\xc8\x2d\x45\xe4\xb7\x64\x54\xc6\x08\xbc\x35\x66\xb7\xf9\xb3\x85\xcc\x7e\xb3\x8e\xe4\x29\xaf\xc2\xda\x99\x66\x9f\xc5\xc1\xbe\x82\x16\x1a\x1b\x0c\x33\xf7\xba\x9a\xd4\x41\x9d\x20\x62\x97\x19\x01\xdb\x00\x3b\xfa\x23\xc4\x47\x14\x99\x5c\xb0\x6b\xfa\x96\x6e\x50\x23\xaa\x93\x46\xfd\x37\x5a\xe2\xa1\xe8\x40\x84\x31\x4d\xf3\xf0\x8c\xe2\x08\x00\xc2\xc2\xad\xfb\xb8\x13\x66\xf6\xb1\x04\x24\x3d\x62\xd5\x04\x1e\x72\x73\x43\x3f\x17\x58\x1b\xf9\x3f\x4c\x61\x46\xfa\x96\x6f\x63\x8a\xb0\x7e\xa1\x66\x94\xa7\xce\x30\x5c\xc6\x09\xa6\xe1\x06\x23\xff\x7f\x6c\x79\x16\xb6\xe4\xdb\xde\xbb\x7b\x52\xec\xa7\xf0\xd5\x18\x7f\xf6\x64\xd7\xc3\x70\xed\x22\x88\x6a\xa2\x67\x13\x29\xd9\x28\xe0\xa3\xbe\xa3\xb4\x71\x1a\x12\x8b\x9a\xab\x90\x26\x6f\x86\x51\xd2\x20\xb9\xcc\x1c\xbf\x5b\x1c\xe7\x26\x59\x31\x80\x36\x90\xd3\x29\x1c\x01\xea\xd4\xdb\xc3\x32\x9a\x97\xe8\x5c\x4f\xe1\xd3\x56\x60\x8c\xc9\xe6\x0b\x05\xbc\x14\x83\x8a\x86\x08\x27\x9a\x00\x61\xde\x28\xff\x7b\x8e\x81\xf5\x9c\x8a\x8c\x55\x23\x92\x4c\x4c\x48\x5e\x6e\xa8\x0a\xc8\x17\x50\xbb\x0e\x41\x9e\xfc\x78\x58\xcd\x4a\xf5\x0c\x8b\x8c\x80\x65\x0f\xac\xab\x4d\x82\x58\xf9\xca\xfa\x03\x10\xa0\x07\xcc\xcb\xc4\x18\x5c\x82\xfd\x14\x6d\xf1\xd8\x11\x87\x9d\xa3\x65\x0d\x57\x16\xf1\x00\x4b\x71\xd2\xc7\xf2\xbd\x65\x03\xc3\x54\x58\x9f\x86\x02\xc9\x50\xa1\xf5\x13\x9f\x81\x14\x60\x75\x28\x80\xa3\x41\x11\x66\x30\xe4\xff\x84\x94\x8e\x74\xa9\xeb\x35\x0d\x64\xd8\x29\x30\x02\x20\x02\x33\xf2\x09\xb1\x7d\x78\x89\x7c\x7c\xe6\xce\x29\xe2\x9f\x82\xd4\xad\x6c\x61\xeb\x79\xf5\x73\x9c\xb6\x68\xb2\x1a\x74\x55\x55\xc9\x6e\x19\x52\x68\x45\xe8\x2c\x6e\xd2\xb1\xc6\xbd\xd6\x36\x4b\x8f\xc7\x9b\xa9\xa3\x2d\xbd\x3f\x8b\x97\x5e\xb9\x23\x62\x39\x58\xae\x0d\xaa\x4f\xfa\x13\x92\x17\xc0\x0e\x02\x1f\x93\x7e\x9b\x79\x1c\x37\x99\x1a\x35\xe5\x23\x1a\x19\x14\xc0\x45\xa7\x87\x43\x2f\x97\xb8\xe2\x06\x3d\xb1\x05\xe1\x4d\xa9\x79\xc1\xc4\xcb\xa7\x85\x21\x0e\xb0\x20\x11\x33\x4b\x23\x0c\xfb\x68\x31\x99\x8c\xcc\xe2\x53\x86\xf4\xf3\xba\x0d\xce\x20\x06\xe9\xc3\x94\x0b\x4d\x5a\x56\xaa\xcc\xdc\xab\x02\x71\x86\x89\x81\x63\x60\xf1\x88\x52\xfd\x19\x98\xa9\x9f\xce\x9a\x04\xda\x3f\x5e\x23\xaf\x94\xc6\xe8\xa5\xba\xdf\xd3\x93\x04\xb9\xe2\xa3\x76\xa1\xf9\xba\xc0\x9a\x85\xbd\x04\x24\x76\xe2\x6b\x58\xec\x73\xf1\x23\x6d\x41\xab\x4b\x4e\x7a\x54\xde\xf9\xd6\x6a\x38\xf8\xe5\x46\xde\x7b\x38\x8e\x1e\x7d\x66\x81\xe5\xe2\xa0\x96\xf1\x60"}, -{{0x69,0x5c,0x96,0x0b,0xbb,0x0d,0xd5,0x7f,0xfa,0x36,0x15,0x1c,0x85,0xde,0x73,0x51,0x54,0xfe,0x5a,0xd5,0xf5,0xfc,0x77,0xd0,0x05,0xa0,0xa3,0x20,0x11,0xde,0xb3,0x0c,},{0x34,0x12,0x5e,0x4e,0x21,0xf7,0x89,0xed,0x0e,0x11,0x80,0xc1,0xf6,0x36,0x9c,0x72,0x1d,0xca,0xe9,0x85,0x9b,0x6f,0x7b,0x04,0xf9,0x57,0xe5,0x10,0x01,0xee,0xde,0x8a,},{0x4a,0xf4,0x1c,0x55,0x4d,0x99,0x08,0x12,0x68,0x6c,0x32,0x9a,0x87,0x5c,0x41,0xee,0x24,0xb4,0xa7,0xfd,0x7b,0x3d,0x4f,0x8c,0x8d,0x52,0x75,0xf2,0xe7,0xcb,0x24,0x2b,0x25,0x8b,0x58,0x58,0xa4,0x66,0xde,0x59,0x5c,0xe2,0xa2,0x17,0x7e,0x35,0x1c,0x7f,0x08,0xc7,0xfc,0x4e,0x0b,0xf9,0x7e,0xc5,0xfb,0x2d,0xcb,0x82,0x52,0xd2,0xc9,0x0a,},"\x37\x06\x69\x6c\x7a\x90\x66\x90\xd0\xd3\xb7\x1e\x7e\x21\x1c\x7b\x06\x71\x68\xf3\xa8\xf1\xed\x98\x4a\x0a\x5e\x60\x78\x59\x76\x62\xe4\xe7\x88\x9d\x52\xdb\x0f\x78\xe0\xd5\xef\x0e\x5f\x7a\x0a\x0f\x42\x63\xb6\x84\x8b\x07\x25\xca\xa4\xb1\xce\xa6\x98\x74\x09\x51\x1c\x8e\x5e\x98\x2d\x3f\x5b\x82\xbb\x56\xa4\xa7\x94\x71\x21\x93\x7f\x8e\x10\x5c\x5a\x14\xb5\x3e\x6c\x37\xcc\x71\x6b\x1e\xba\x92\x24\x21\x82\x8b\x04\x6f\x68\x56\xc4\x4f\xab\xf1\x3a\x75\x16\xc6\x2a\x5f\xf9\x85\x68\x45\x0c\xee\x78\xb1\x40\x33\x50\x47\xbf\x1c\xa7\x7e\x15\x49\xa8\x94\xfe\xeb\x07\x80\x45\xe4\x64\x18\x32\x25\x3b\xf6\x95\x48\x54\x52\xec\x36\x90\x65\xa6\x00\x29\xa6\xc9\x07\x7a\x37\x9d\xb2\x04\x85\xea\x2e\xdb\x6c\x96\x95\x47\xbb\x26\x53\x28\x9b\xc6\xe8\x1f\xfc\xb8\x4b\xdb\xf7\x73\xdd\xea\x4b\x37\x50\xe9\xa7\x23\x95\xd1\x17\xf6\x44\xb0\xe2\x20\x61\xd4\xf3\xbb\x7c\x5b\x61\x2e\x4b\x70\x39\x5e\x07\x79\x51\x6b\x46\x65\x91\x16\x90\x2f\xd0\xfb\xcd\x23\x40\xee\xa4\x5e\x9c\x23\xdb\x25\x64\xa5\xe1\x1d\xc7\x9e\x8f\x4b\x33\x2a\x44\x3e\xc3\x5a\xad\x96\x04\xfe\x79\x12\x52\x08\x82\x95\xe8\x4f\x65\xa3\x07\x31\x25\x50\xd9\xeb\xf6\x1f\x36\x7e\x4a\x0f\x2b\x56\x23\xe5\x3e\xf6\xbc\x13\x28\x25\xfc\x24\xeb\xee\x4e\xbf\x33\x8c\xbf\xb5\xdf\x69\xb3\x2d\x03\x0d\x44\x7c\x44\xf3\x13\xba\x96\xfe\x07\xbb\xfe\x5b\x01\x66\xea\xec\xbc\x61\x9b\xb6\xb2\xe5\x92\x40\x10\xba\x3e\xc1\x50\xff\x6a\x69\xfe\xc4\xde\xd9\xc4\x42\xf9\x8c\x15\xe7\x7f\x31\x9b\x48\x43\xb3\xb7\x48\xb5\xd2\x60\x89\xa7\x6c\x2b\x83\x4f\xf9\x3c\x41\x3e\x04\xca\x95\x50\xcd\x21\x1c\xe2\xd6\xa5\x83\xd7\x82\x57\x50\x66\xdb\x6d\xd3\x3e\x8d\x5e\x83\x74\x35\x5d\x06\x8a\x5e\xb9\x6f\x8b\x3d\xa8\xdd\xdf\xb5\xba\xf5\xc5\x96\xda\xaf\x55\x6a\x8f\x2c\xb5\x78\x1e\x50\x42\x32\x7f\x92\xae\x06\x21\xea\xe0\x88\xb5\xf0\x13\x59\x2e\x77\x87\x3a\x81\xd7\xe0\x68\xd7\xb8\x33\x7d\xb9\xf1\x09\xa8\x35\xb4\x75\xe5\xca\xf7\xce\xa5\xaf\x3b\x4a\xd6\xd9\x0b\xaa\xf1\xc7\x36\x55\xec\x67\x67\x47\xfc\xdd\x41\x77\x5b\x4f\xbe\x39\x24\xc3\xf4\x1d\x8a\x73\x75\x28\xd1\x2d\x61\x56\x65\x3a\x22\x35\x8c\x68\x21\x42\x6b\x2c\x0a\x33\xe1\x63\x4c\x62\xc7\xc8\x38\x56\x49\xbc\x23\x3e\x7d\xaf\x94\x39\xf0\x9d\xb9\xbd\x11\xea\x01\xe2\x8b\x77\xec\xbb\xc4\x59\x0e\x29\xfd\xcf\x0f\xdd\xe1\x52\xf6\x47\x81\x32\xfe\x4c\x3a\x5b\x45\xa7\x30\x5a\xf6\xe3\x81\xca\xdd\x72\x49\x6e\x66\xbb\xb8\x66\xce\xa4\x7f\x7e\x7d\x7e\x63\x34\x16\x00\xaf\x3f\x49\xce\x9c\x9e\x4e\x37\x39\x4d\xf5\xdf\x71\xdc\x10\xcd\x39\x1f\xdc\xb8\xa1\x93\xdc\x98\xfc\x19\x05\x9f\xa3\xac\x23\x0e\xc5\x47\x6b\xf9\x4d\x85\x55\x6a\xce\x6e\x1b\xa3\x24\x21\xbf\x59\xdc\xbe\x05\xc5\xe1\x5d\x34\xc6\x64\x4e\x27\xd0\xa0\x2b\xe9\x7f\xa8\x38\x7e\xe0\x37\x06\xf2\x2a\x8f\x4b\x3b\x40\x40\xad\x7d\x3f\x8a\x86\x97\x1a\x20\xa0\x9e\xc8\x1b\x76\x96\xd8\x34\xc5\x26\xb8\xe5\x1c\xb9\x7d\x27\x64\x3f\x9a\xbf\x5e\x29\xff\xd0\x33\x3f\x95\xde\x15\xd1\x10\xc2\x06\x4c\xa4\x94\x67\xc1\x4e\xf2\x27\xf4\xba\xbf\x1a\x55\xe7\xb1\xcd\xa0\x42\x9c\xff\x25\x6b\xe3\x1c\xf1\x16\x71\x9a\x81\xb9\xc5\xfb\x75\xfd\xf6\x4e"}, -{{0x25,0xcb,0x17,0xfc,0x33,0xd2,0xbf,0x83,0x84,0xae,0x4d,0xf2,0x0c,0x1f,0xad,0x5c,0x35,0xfd,0x76,0x5a,0xff,0xde,0x04,0xb5,0x25,0x6d,0x4d,0xe0,0x1c,0xa8,0xde,0x14,},{0xb8,0x6c,0xa3,0x12,0xfe,0x59,0x85,0x20,0xc6,0x4b,0xe5,0xc7,0x2f,0x5b,0x23,0x81,0x65,0x07,0xf6,0x9e,0x07,0x0f,0x82,0x8e,0x02,0xd2,0xaf,0xcf,0xe1,0x1b,0xfa,0x01,},{0x8c,0xcb,0x0d,0xbc,0xf7,0xcc,0x03,0xe8,0x3e,0x21,0xc5,0x74,0x74,0xaf,0xd3,0xad,0x88,0x98,0x09,0x7b,0x97,0x2e,0xde,0x17,0x5a,0xca,0xae,0x48,0xe3,0xec,0x17,0xb2,0xdb,0x06,0xfc,0x82,0x77,0x6b,0x07,0x51,0xc0,0xf9,0x56,0xfd,0x71,0x96,0xf3,0xd1,0xc9,0x63,0x21,0xa6,0xcf,0x3d,0x89,0x24,0x15,0xd8,0xf8,0xee,0xb4,0xa1,0x41,0x08,},"\x4b\x4a\x71\xcb\xf8\xcb\xaf\x57\xa7\x7d\x4e\xa1\x88\xa6\xf9\x64\x84\x0f\x0d\x71\x4a\x5f\x38\xa0\x95\xa1\x3b\x4e\x57\x12\x97\xa8\x8b\x79\x24\x17\xd1\x61\x84\x42\x7f\x90\xe0\x43\xdd\x8a\x55\xb7\xf1\xc1\x3e\x00\xdf\xa6\x05\x16\x44\x5c\xbe\x77\x06\x8c\x79\xc8\xc3\x5e\xbe\xac\x33\x0c\x33\xf1\x12\x1d\x05\x73\x1a\x8f\x51\x32\xd6\x48\x00\x73\x27\x46\x41\x19\x5a\x75\x20\x21\x16\xff\xf1\xc3\x18\x81\x71\x78\xfd\xd7\x68\xbb\xdf\x10\x5f\xa0\x69\xc7\xa3\xd1\x43\xfd\xf5\xd1\x7b\xfa\xd7\xc0\x62\x4e\x52\x92\x06\x8f\xd7\xbb\x6d\x30\x3b\x4a\x27\xcb\x20\xa4\xe6\x18\x75\x07\x67\x87\xd1\x9f\xa6\xf7\x29\xc9\x4d\xc0\xba\x9b\x8c\x0b\xfd\x98\x66\xda\x5c\xb2\xe7\xa2\xcd\x2e\xdb\xdc\x95\xac\x34\x9e\x5e\x5c\x21\x72\xe5\xa4\xcf\x7b\xd9\x0c\xab\xe2\xc6\xe2\x24\x59\x80\xbd\x72\xd0\xf6\xf5\x47\x98\x81\xe8\xc4\xc3\x54\xf6\x8a\xa7\x28\x41\xd0\xc7\x3b\x98\x6b\xa5\x10\x21\x20\x31\x61\x02\x6e\xe3\xd7\x29\xdd\xf1\xa0\x49\xff\xe9\xeb\x25\x43\x98\x02\xf0\x30\x11\xd1\x44\xe5\x0b\x02\xbd\x4a\xca\x5e\x55\x06\xd3\x2f\xcf\x69\xe3\x2f\x54\x25\x44\x79\x8f\x4e\x87\xf7\x2b\xdf\x24\x33\xb1\xff\x32\x59\x29\x2e\x1d\x90\x81\x2c\xff\xd7\x9f\x6a\x54\x32\x70\xba\xf2\x4a\x3c\x39\xdd\x35\x98\xe1\xc6\x61\x61\x29\x22\x52\x2f\x38\x7d\x51\x59\x76\x92\xf3\x14\xc4\xd5\xac\x4b\xf1\x88\x3a\x61\x46\x36\x33\x6a\x55\x44\xd5\x9f\xf4\x1d\x1e\x0d\xbc\xf8\xe6\x62\x7e\x7c\x80\x85\x64\x63\x22\xdf\xc2\x0c\x33\x2c\xbd\xf3\x53\x70\xd4\x7d\xca\xbb\x80\x2e\x17\xca\x84\x78\x0e\xec\x66\x1c\x90\x4d\x5b\xfb\xc2\x40\xad\x6a\x14\xa7\x53\x3f\x71\xa2\x75\x00\xc6\x1d\xd3\xe4\x73\x98\x38\x87\xa8\x68\x35\x18\x7a\xbb\x0d\xf0\x8f\xa6\x2c\xda\x69\xdc\xe8\x6e\x21\xfa\x5a\xe9\x54\xc2\x2e\xdd\xb6\x0e\xe3\x13\x15\x04\xa6\x9b\x50\x48\x6a\x17\x76\x70\x91\x88\x37\x60\x63\x8a\x29\xc3\x80\x30\xe1\xe0\x5f\xdb\x28\xe1\x58\x63\x30\x10\x38\x5a\x62\x06\x13\xcc\x10\xd5\xa5\xf3\x50\x95\x5f\x4a\x34\x7c\x65\xed\xdd\xb7\xe2\x51\x59\xda\x8d\xcc\x26\x55\x92\x8a\xd6\xf6\xd8\xc4\xc1\xab\xb8\x17\xd7\xfe\xf3\xba\xe5\xde\x04\x02\xed\xde\xe7\xb5\x15\x21\xce\x28\x0a\x66\xb7\x96\x14\x0f\x56\xaf\x9b\xc2\x0e\x46\x58\x75\xce\x26\x28\xa8\xa1\x04\x77\xce\x9b\x2e\xac\xc7\xd8\x6f\x88\x27\x24\x57\xbf\xd4\x43\xe7\x12\x52\x69\x96\x25\x43\x80\xf0\x13\x52\x27\xe9\xfc\x15\x1c\x86\x95\xe9\xcc\x64\xd2\x72\xb2\x56\xab\x95\xc9\xa9\xf5\x68\xe9\x37\x16\xe0\xe5\x3d\x29\x88\x2e\x3c\xe7\x42\x61\x25\x7a\x02\xcd\x49\x7c\x37\xd7\x64\xd9\x0f\x7f\xd4\x78\xa1\x7a\x89\x0a\x8b\x2e\xa6\x1a\xb8\x1f\x68\x69\xb1\x20\xa2\xf6\x48\x4a\x88\xc1\x51\x95\x33\x91\xec\xa4\x45\x01\x53\x77\xb3\xa5\xdf\xfe\x4c\xfb\xac\xfb\x5b\xab\x2c\x47\xf6\x54\xf7\x2a\x9d\x19\xcb\xc4\xd2\x95\x37\x19\x84\x05\xe3\xa0\x4b\x4b\xfe\x11\xbc\xdb\x5c\x1f\x30\xd9\xac\x02\xf5\x48\x49\xc5\x7a\xa9\x6f\x7b\x56\x63\x61\x16\xf2\xbb\x6f\x25\x83\xd9\xaf\x94\xc8\x6a\xff\x5c\x13\x7f\x63\xce\x54\xe8\xf0\xc2\x1b\x6c\x25\xc1\xf0\x47\x2a\x22\x9c\x90\x81\x7e\x61\x62\xea\xc7\x1c\xcd\xa3\x09\xa1\x64\x3b\xd6\x31\x2a\x52\x63\xa2\xef\xe6\x46\xdf\xfe\x79\xeb\xd8\x15\x7a\x28"}, -{{0x49,0xe2,0x4d,0x16,0x99,0x83,0x37,0x26,0xb1,0x8c,0x78,0xea,0x65,0x68,0x40,0x1a,0x97,0x1e,0x1c,0xa3,0x9d,0xd0,0x6d,0x75,0x63,0xac,0x8b,0x42,0x50,0xd4,0xa9,0xf5,},{0x71,0xcf,0x05,0xe9,0x0d,0x30,0x1a,0x6d,0x9f,0xad,0x7f,0x0b,0x38,0xec,0x8b,0xb0,0x44,0xfc,0xfd,0x97,0xc8,0x49,0xb0,0x4c,0x00,0x36,0x25,0xde,0x29,0xbe,0x86,0xbb,},{0xa0,0xb6,0xa2,0xaf,0x15,0xb6,0xbe,0x9e,0x95,0x1e,0xf3,0xf3,0x2c,0xbd,0x1c,0x67,0x02,0xe8,0xe0,0x17,0xfb,0xd3,0x15,0xa3,0xf2,0x59,0x9c,0x3f,0x1a,0x11,0x86,0x5d,0x46,0xe7,0x84,0x59,0xa0,0xd7,0xf7,0xbe,0x04,0x6a,0xae,0x29,0x3c,0xad,0x09,0x13,0x7e,0xc8,0x47,0xe2,0x69,0x28,0x10,0x6d,0x9a,0xa3,0x5e,0x09,0x82,0xb9,0x92,0x02,},"\x6d\x26\x05\xf6\x1e\x1a\x04\xb6\xae\x18\xc2\xc2\x5a\xe1\x00\xdd\x42\xa6\x1e\x66\x4e\x2d\xb5\xc3\x4d\x7a\xd1\xf8\x4a\xc5\x07\x55\x2b\x74\x1c\x20\x86\xc1\x7c\x85\x2b\xab\xe0\x7a\x91\xe1\x29\xa5\x06\xee\x59\xed\xb9\xce\x73\xbe\x1b\x1d\x06\xd1\x20\xec\x36\xa1\xe9\x4c\x62\x81\x05\x4e\x78\xce\xb1\xbd\xef\xfb\xcb\xf4\xf0\x10\x51\xed\x38\x1b\xfc\x8a\xd1\x76\x9f\x41\xe2\x40\xbf\x60\x59\xd9\x70\x4c\xac\xec\x66\x66\x11\xf4\x1e\x4d\xd4\x38\xb7\xf5\x02\x42\xea\x86\x75\x6b\xb1\xf8\x1e\x59\x42\xc0\x92\x12\x9f\xbc\x6d\xe4\x95\x5d\x28\xdf\xf3\x52\x37\xdb\x30\xe4\xa5\x03\x6a\x99\x14\xc9\xf8\x4d\xbd\x8c\xcf\x82\xba\x2b\x1b\x3b\x55\x54\xa2\xb7\xa7\x4c\xb0\xb2\xa1\xe1\x96\x33\x45\x28\x6e\x25\x8d\xc8\xe7\xd5\x67\x18\x03\x5f\x95\xf3\x13\x81\x1c\xfb\xd8\x52\xa0\xf8\xf4\x9a\x29\xef\x93\x3e\x7c\xda\x7e\xd9\xc7\xe8\xb1\x62\xcd\xba\x1a\x82\x26\x2c\xd4\xdf\x7c\xf8\xea\x4b\x58\x6d\xb4\x3d\xcc\x1e\x37\x64\x59\x8e\x9c\xa4\x66\x73\x82\x2b\xaa\x2a\xd8\x7f\xb1\x4b\x6f\xdb\x9e\x20\x32\xd0\xca\x51\xc2\x6c\x5e\xf3\xd9\xf7\x97\x85\xfa\xc2\x49\x1c\xdb\xf7\xc3\x99\xf3\xcd\x17\x74\xc1\xa6\xb1\xe4\xa6\x7f\x54\x36\xd8\x0d\xb0\x25\xf8\xfb\x64\x09\xe2\x75\xbd\x0e\xd5\x08\xb5\xe0\x39\xed\x2e\x4e\xec\x8b\x0f\x4d\x5b\xe9\x9d\xca\xfa\x6a\x14\x01\x25\x27\x32\xa6\x5b\x37\xc9\x43\xc0\x7e\xf3\xac\xbc\xfb\xb3\xdc\x06\xda\xd0\xa8\x8f\x2f\x5e\xb5\x51\xa3\x99\x7a\xd6\xc6\xee\xd9\x5e\xdd\x9a\x0a\xf4\xa2\x88\xd5\xe4\x32\x86\xb2\xac\x07\x29\x77\xc4\x36\xb7\xc5\xff\x7a\xb6\x1c\x94\x84\xf2\x57\xf5\x8e\x01\x0c\x9b\x6a\xd4\x15\x81\xd7\x42\xcd\x19\x75\x2c\xde\x54\xd2\xb4\x20\xd6\x43\x65\x4e\x90\x96\xa8\x1e\xb9\xdc\xf8\x04\xc7\xc2\xed\x0e\x38\xd1\x3a\x5c\xe3\x99\x78\xcd\xd0\x2b\x25\x35\x09\x45\xde\x78\xfe\xec\xc0\xc2\xc2\x2f\xfd\x70\x5c\x3b\xa8\x11\x32\x65\xc7\xb9\xa7\xc8\xdd\xb5\x91\x78\xbd\x21\xd7\xf6\xc3\x1c\x6b\xe2\xc3\x67\x49\xee\x0f\x9a\xb8\xbc\x1d\xcf\x5d\xa5\xcb\x2d\x2d\x59\x62\x35\x8f\x71\xf9\x6a\xb3\x79\x2a\x25\x2a\x51\x9e\x41\x53\x51\xf4\x3e\x7e\x12\x03\x5b\x03\x28\xf2\x82\x08\xcf\x4b\xe5\x29\xd2\x99\xaa\x5c\x12\x8c\x9d\x5e\xd5\x75\xbf\x90\xc5\x35\x05\x69\xea\xa6\xf2\xd5\x52\x1d\xe1\x18\x03\x09\xf6\x86\xc9\x7e\x9a\xd6\xfa\x1e\xc1\xdd\x86\x27\xae\x89\x51\x58\x1c\xf6\x04\xb8\xb9\x17\xc5\xba\x43\x4a\x63\x7b\xe1\xbc\x8b\x79\xf4\xac\xaf\x77\x95\xf4\xe5\x1a\xab\xdb\x88\x50\x77\xbc\x4f\x3c\x68\xfc\x33\x18\xde\x58\x23\xd7\xe0\x80\x4e\xe9\x95\xb7\x03\x87\x95\x0f\x79\x93\x53\x68\x23\x00\xd4\xe7\x97\xf3\xca\xd6\x11\xb4\xc5\x62\xc8\x64\x0f\xf2\xb3\xfe\x29\x29\x16\xa9\x70\xfb\x98\xc1\x47\x5c\x1f\x4e\x27\xb9\xb3\x3c\xfe\x0d\x3a\xd9\x32\xa1\xeb\xe6\xa2\x7f\xc3\xb4\x46\x62\x29\x54\xae\xe1\x68\x36\x68\xc8\xbd\x4a\x3f\x90\x3b\xe5\xc7\x7d\xfd\xb8\xe8\x91\x4c\xed\xc5\x1f\x65\xfe\xd2\xd9\xc4\xd0\x3e\x13\xa6\x68\xd4\xc7\xea\x5e\x31\x88\x3e\x1b\x3d\xb6\x43\x63\xe2\xac\x5c\xc5\x4b\x54\xce\x69\xc6\xad\x52\xf8\x74\x99\x9b\x5d\xd2\xc5\x78\x2f\x03\xc3\xd5\x15\x05\xdf\x53\x6a\x1f\xe0\xd8\x60\xd3\x3e\xab\xed\x64\x1a\x94\x00\x89\xf1\x29\x7d\xd0\xf5\x7f"}, -{{0xf8,0xff,0x97,0x03,0x2a,0x34,0xcf,0x99,0x99,0x08,0x80,0x58,0xaf,0x56,0xff,0x70,0xb6,0xac,0xb2,0xed,0xf7,0x59,0xe1,0x31,0xfa,0xec,0x84,0x40,0xfd,0xec,0xf6,0xc4,},{0x54,0x38,0xb4,0xe3,0x3f,0x1c,0x5e,0xa1,0x12,0xfb,0x1b,0xaf,0xef,0x40,0x59,0xbf,0x09,0x5a,0x11,0x40,0x9b,0x64,0xd4,0x6b,0xfb,0x4d,0x25,0x47,0x3c,0x1c,0x08,0x74,},{0x50,0x9e,0x9e,0xad,0xfe,0x8d,0xde,0x79,0x14,0xac,0x20,0xca,0xfc,0x0b,0x0a,0xf2,0x2b,0x84,0xdd,0x8a,0x21,0x0a,0x48,0x12,0xcd,0x8c,0xae,0x39,0xb0,0xa2,0x72,0xe5,0x3e,0x02,0x24,0x6d,0xc8,0x93,0x9e,0x92,0x26,0x92,0x03,0x36,0xe1,0x40,0xb3,0x15,0x32,0xd0,0x68,0x13,0x7a,0x34,0x16,0x1e,0x59,0x9a,0x86,0x94,0xa9,0x5d,0xdf,0x01,},"\xdf\xb4\x1f\xb9\xd5\x37\x02\xcb\x2b\x9e\x3f\xfc\xad\x4e\xa6\x02\x71\x6f\x71\x8a\x7e\xa3\x3e\x21\x84\x3e\x2a\x6c\x05\x2c\x70\xc6\xc5\x14\x85\xd7\x2b\x53\xa5\xbb\x4e\x34\xe0\x3e\x3e\x1d\x1a\x52\x51\x8e\xb3\xe7\xf1\x8f\x2a\x1e\x1c\xaf\x78\xac\xb2\x11\x60\x89\xbe\xd4\xc6\x17\x13\x8e\x71\x6a\x91\x43\x1f\x2c\xf6\x44\xa1\x21\x0f\x6d\x19\x20\xd2\x85\x99\x42\x64\xd6\x46\x6b\x0d\x8d\x2c\x62\x63\x80\x44\x61\x6f\x57\x6e\xdc\x7d\x0d\x93\xcb\x66\x01\x31\xd4\xbb\x50\x87\x5e\x15\x36\x40\x12\x3a\x96\xf1\x5b\x75\xa5\xbc\xee\x46\xd5\xcc\x5e\xb1\xa4\x31\xc5\x9d\x2e\xad\xdf\xd5\x53\x15\x02\xfe\xb1\x55\x1b\xf7\x79\x1c\xd5\x98\x9d\x17\xd1\x02\x96\xd0\x1b\xa3\xae\x3e\x38\x4c\x67\x45\x26\xca\xb6\x2a\x7c\x24\xc0\xff\x67\x7d\xe7\x1c\xa1\x72\x62\x1a\x28\xa8\x5e\x01\xee\xfe\x07\xf6\xee\xf9\xc3\xec\xfd\x7f\x94\x98\xac\x42\xf4\x6a\x43\x71\x6f\x61\x53\x18\xa3\xb2\x87\x57\xc3\xa1\x5f\x4f\x1c\x38\x22\xae\x7a\x75\xc2\x03\xa2\x98\x25\x8d\x75\x36\x38\xcf\x42\x5e\x15\xbb\xc4\x62\x02\xb0\x93\xb8\xe4\xf3\xe6\x70\xfb\xb6\x63\xdb\x2b\x69\xc8\xfb\x0f\x62\x50\x74\xd8\x5a\x44\xd3\x50\xe0\x42\xbb\x1b\x74\x02\x1d\x19\x29\x97\xa2\xc2\x7d\xd6\xc8\x63\x48\x41\xd1\x00\xa0\x34\x4b\xae\xd7\x50\xa3\x9f\xf5\xdc\xd9\x84\x8d\xfc\xf0\x9e\x5c\x8c\x47\x96\x7b\x96\x55\x6e\x23\x32\xca\x17\xd8\xe4\x2d\xd8\xf3\x93\xa5\x44\x5a\x37\x22\x44\x60\x0b\x30\x01\xb8\xfe\x86\xc4\x5e\xaf\xc6\xe7\x38\xaa\x7e\x11\x7b\x4a\x79\xfa\x2e\x6b\x00\xf4\x64\x92\x8d\x18\x56\xc8\x3e\xcf\xe8\x7d\xd3\x4d\x15\x8f\x5c\xb4\xe4\xf4\xd6\x10\xf5\x97\x17\xec\x79\x0b\xd3\xff\x87\x20\x40\xb6\x7e\x8d\x39\x39\xe8\x04\xe3\xb5\xdb\x98\x5a\x09\x56\x21\xcb\xcc\xd6\x86\xc0\x93\x4e\xce\x3e\x27\xab\x2c\x6c\xe3\x3f\xb5\x2b\x11\x1f\x48\xe4\xf2\x74\xbd\xf3\x20\xd0\xb0\x23\x84\xc8\x3c\x49\xe1\xa0\x41\xbd\x23\x19\x10\x9c\x85\xa0\x6d\x80\x48\xa9\x93\x35\x7a\xbf\xd8\x11\xac\x2f\x38\x05\x9d\x07\x7a\xcb\xc3\x6a\xa9\x66\xc0\x28\x90\x37\x48\x62\x5f\x92\xe8\xf7\x9d\x51\xbd\xa1\x0f\x78\x52\x29\x77\xf7\x6e\xc4\xe8\x85\xe4\x9a\x46\xc6\x8d\xe0\x9f\x3d\xa8\xf8\x6b\x71\xae\x64\x23\xbd\x29\xde\xef\x1c\xc6\xa1\x13\xea\xc1\x15\xa6\xcd\xe2\xcc\xd0\x11\xfc\x1c\x0f\x0e\x34\x27\xf4\x3c\x3e\x96\xfc\x41\x56\xed\xf6\x2d\xdf\xb7\xb0\x83\x6b\x88\x8b\xab\x3c\x43\x45\x05\x5a\x6c\x41\x78\xe9\xe2\x28\x29\xfd\x8c\xfc\xe3\x9b\x0b\x84\x44\xeb\x26\x48\x7c\xc9\xdc\x82\x60\x6f\xea\xad\xaf\x49\x78\x69\x4e\x65\x64\xf2\x72\x9c\x1b\x13\xab\x37\xc9\x07\x2d\xb4\xe9\xde\x94\x0e\xe5\xf1\xd0\x58\x84\xae\x7f\xd9\xd9\xec\x9c\xb7\xde\x56\x34\x76\x00\xa8\x8d\xea\x92\x08\xa6\x34\x19\xfc\xe2\x9e\xe5\x00\x55\xa3\x74\xa8\xf2\x2f\x9a\xe2\xbe\x98\x05\xa9\xf4\x76\x15\xaa\x59\x57\x6b\x44\x04\x2f\xf1\x26\xa8\x98\x24\xe3\x6a\xd6\xbc\x58\xe0\x6b\xb9\x0f\xbe\xef\xba\xe5\xd6\xd7\xd6\x24\x30\xf3\x73\xb6\x29\x6f\xbf\xcd\x4d\x66\x20\x16\x83\x53\x58\x3f\xbd\x3d\x5a\x29\x2b\x95\x72\x51\x75\x34\xe2\xfb\x0b\xee\xf2\xfa\x98\xa4\x64\xe5\x91\x03\xe7\xa0\x42\x87\xf1\x5d\xad\x0f\xac\x54\x97\x0e\x77\x15\x07\x8d\x63\xec\x26\x36\x2f\x6f\xba\xbc\xdd\xea\xf7"}, -{{0x2e,0x4c,0x39,0x21,0x9f,0xc9,0x2a,0x53,0x8e,0x48,0xe9,0x5f,0xbf,0xcf,0xef,0x30,0xf5,0xa2,0x1b,0x78,0x94,0x0b,0x81,0x05,0x3b,0xda,0xd4,0x60,0x2b,0x4c,0x96,0x90,},{0xf8,0xee,0xd8,0x92,0x17,0x66,0x20,0x43,0x4c,0x7f,0x0e,0xc5,0x3d,0xcf,0xf3,0x98,0x63,0x10,0x9e,0x7c,0xa4,0xd0,0xb3,0xc6,0xc4,0xb5,0x64,0x10,0xbe,0x01,0xe5,0x37,},{0x39,0x45,0x20,0x12,0x2b,0xb0,0xa5,0x64,0x64,0x8a,0x7a,0x8b,0xc8,0xdc,0x73,0x63,0x6c,0x51,0x77,0x46,0xa3,0xc8,0xa0,0x5b,0x90,0x1e,0x72,0x52,0xfe,0xf0,0xe5,0x02,0x3d,0x90,0x99,0x1e,0x31,0x1b,0x53,0x82,0xd4,0x91,0x00,0xe5,0x26,0x33,0xc7,0x0f,0xe9,0xc2,0x6c,0x14,0x50,0xe0,0x60,0x3e,0x6d,0x45,0x22,0x99,0xaf,0x4d,0xae,0x07,},"\xc8\x7d\x1f\xba\x9d\x94\xa6\xa5\x40\x89\x80\xfc\x80\x83\x98\x0f\xd2\xd2\x52\xfa\xe5\x40\xf6\xee\xc1\x9e\xd6\x74\x6c\x29\xe3\x39\xa1\xc2\x9f\x6f\x53\xbc\x23\xfd\x6b\xfa\x43\x85\x07\xef\xf5\xda\xf9\x03\x40\x3c\xda\x70\x7b\x4d\xc5\xe8\x44\x80\x5d\x6b\x1c\xeb\x4a\xff\xf4\xb2\x32\xe8\xe6\x9d\x7d\x27\x1f\x3c\x06\x7c\x48\x54\xf3\xd9\x4f\x27\xfe\x32\x55\x81\xfa\xca\x79\xd1\xf0\x2a\x26\x29\x0a\xd2\x3a\xf7\x11\x00\xc1\x2c\x09\x15\x76\x47\xca\x9d\xa4\x3d\x76\x90\xdd\xcd\x94\xdb\x65\xe0\x00\x98\x9c\x87\x8b\x75\xa0\xff\x22\xd2\xc7\x09\x62\x59\x4c\x9b\x08\x08\xf2\x78\x46\xcc\xac\x85\x67\xbc\xe5\xd2\xe3\xb7\x60\x28\x09\xf2\x3b\x59\xcd\x71\x8a\x08\x05\xd1\x08\xf3\x1a\x63\x2a\x05\xb8\xdf\xa5\x03\x5a\xb9\x46\x1a\xeb\xa4\x16\x00\x9d\x74\xfd\xf9\xe0\x07\x20\x28\x56\x89\x0d\x2c\xff\x80\xfa\x24\x0b\x97\x8a\x48\x27\x0f\xcb\x2f\x47\x36\x97\xbc\xba\x8e\x73\x0a\x55\xc2\x87\x61\x91\x9a\x23\xbe\x41\xda\x27\xff\xea\x09\xe3\x55\x9c\xaa\xab\xf9\x51\x9e\xc0\x8e\x1f\xfa\x86\x81\x7a\xa3\xe8\x87\x4f\xa8\x16\xe7\x71\x8c\x5b\x2f\x34\x49\x67\xba\x1b\xc2\x81\x9c\x4f\x04\x5a\x97\xb4\x05\x44\xea\x61\xd7\x17\x08\x3c\xca\xf1\x1e\x9d\xdc\x04\xa3\x59\x8e\xf1\x81\xe7\xbe\xf4\xac\xef\x45\xb6\x55\x1b\x47\x8a\x0d\x77\x31\xc4\xf0\x8c\xe5\x80\x2f\x78\x25\x8d\x41\x90\x17\x66\x10\x76\xd7\xd6\xd2\xef\x39\xe5\x7c\xf9\xcd\x93\x97\xdc\xc5\xde\xbf\x64\xab\x82\xb6\x61\x59\xf5\x78\x31\x6e\x74\xcd\x49\xf5\xad\x2c\x6f\xef\x83\xcf\x08\x68\x3b\x95\x70\xa9\x46\xad\x49\x03\xdf\x4e\x96\xec\x00\x8e\x14\xa5\x01\xfa\x93\x86\xbd\xaf\x2a\x63\x99\x3c\x6c\x9b\xdf\x23\x1f\xd0\x9e\xa6\xf9\x6e\xf4\xd4\xe2\x9a\x3a\x33\x27\xcb\xf7\x4e\xa8\x31\x05\x4e\x66\xca\x86\x68\x0c\x6c\xe5\x3b\x66\xf9\x46\x5d\x06\xb3\xfa\x07\x98\xbb\x69\x05\xae\x38\x45\x59\x34\xf2\xfb\x7e\x0b\xa4\x72\x32\x89\x89\xf0\x01\x30\x86\x71\xcc\xcb\x56\x6d\x22\x2c\x72\x16\x5b\xb3\xa7\x44\xfb\x98\xe2\x21\x0f\x96\x20\x68\x0d\xf3\xe3\xcd\x14\xa8\xbd\x94\xb5\x74\x5c\x00\x16\xdd\xa7\x7f\x05\x9f\x26\x05\x3b\x64\xcf\x45\x23\xc3\xd4\x29\x11\x2f\xb6\xb3\x28\x39\x8b\xc6\x30\xa2\xe9\x06\xb9\x5a\x6c\x57\x80\xcf\xdc\x06\x41\xbe\x47\x51\xbe\xbd\xdf\x77\x24\xdc\x9c\x27\xe7\x8d\x60\xed\x0f\xd7\x36\xd5\xab\xd8\x89\x29\xc1\x79\x5d\x47\x3a\xbd\x2b\x03\x20\xc5\x40\x47\x57\x28\x82\x18\x67\xa4\x09\xa2\xff\x13\xcc\x44\xce\x35\xe5\x98\x1e\x9f\x6b\x87\xa2\x8d\x4f\xa8\xb8\x67\x5e\x50\x3f\xae\xfc\xa7\xc1\xd7\x98\x47\x37\x87\x1f\xe9\x19\xac\x41\x4e\xea\x26\x5e\xe3\x1f\x9f\x78\xf5\x21\xf3\xf4\xf8\xd0\x0c\x3f\xb7\x91\x71\xf3\xc6\xa5\xdb\xf5\xe1\xac\x8b\xf6\x3b\x4c\x3d\x8d\x8b\xc1\x21\x03\x6e\x9e\x55\xbb\x70\x2e\xa6\xc8\x6e\x92\x5e\xc0\xb9\x84\xde\xd2\xc7\x1f\x3b\xfd\x49\x32\xe6\xc4\x1b\x58\x2f\xd0\x2c\xa5\x9f\x53\xce\x29\x74\x45\x78\x5c\xc4\xca\xc2\x47\xb0\xb8\x4e\x7f\xa0\xbc\xdc\xf7\x9b\x3e\x4a\x15\x5f\x98\x78\xc1\xf6\x43\xbe\x9c\x42\xf7\xa4\xf2\x72\x60\x44\x45\x05\xc1\x84\x5b\xd5\x3b\x55\x0a\x31\xd7\x95\x3c\xc7\x38\x86\x1f\x46\xbd\xf4\x87\x0f\x3a\x77\xac\xe1\x91\xab\xd6\x3c\x45\xad\xb1\x53\x90\x9f\xb5\x9a\xb5\xdb\x9b"}, -{{0xf0,0x92,0xe6,0xbe,0x8d,0x2d,0x9a,0xd0,0x69,0xa3,0xe2,0xb9,0x76,0xd2,0x44,0xe3,0x4c,0x15,0xc2,0x8c,0x48,0xd3,0x2f,0x55,0x60,0xa5,0x41,0x85,0xd1,0x50,0x15,0x02,},{0xcf,0xeb,0x3e,0x74,0xe4,0xb5,0xc8,0x35,0x6a,0x81,0x75,0x7b,0x8f,0x1b,0xe4,0xb4,0x29,0xfc,0x18,0xfc,0xaf,0x49,0x7c,0xbf,0x8d,0x8b,0xc0,0x48,0x0f,0xf9,0x78,0xf9,},{0x63,0xcd,0x4c,0x0b,0xa3,0xbe,0x93,0x97,0xcc,0x0f,0x3c,0x1a,0xf3,0x48,0xec,0x4b,0x8a,0x91,0xe4,0x2f,0xee,0x67,0x5d,0xa1,0xd0,0x59,0x00,0xb9,0xa8,0x6c,0x13,0x8f,0x91,0x74,0xeb,0x99,0x6b,0xbd,0xf3,0x1c,0x42,0x95,0xe0,0xc5,0x78,0xac,0x0f,0x9d,0x53,0x76,0x41,0xa2,0xaf,0xd5,0xdf,0xf9,0x3a,0x39,0xc5,0xcd,0x9d,0x3c,0x48,0x0b,},"\x2c\x25\x5f\xb2\x5d\x45\xb0\x86\xc0\x71\xe0\x3e\x52\x5b\x4d\x72\x85\x78\xfb\xb6\xb0\xc6\x0d\xa9\x41\xe6\xbf\x2a\x48\x98\xb2\xd5\xb6\x98\x8c\x53\x30\x27\x85\xab\x7a\x3b\xc4\xbb\x2c\x20\x5a\xcd\x27\xd6\xa4\xcb\xdd\x1a\x0c\x08\x89\xde\xd7\x84\x26\x4c\xb7\xc0\x28\x89\xc5\xc7\x11\x3f\xc9\x0b\xbb\xcd\x31\xff\x00\x14\x32\xc0\x53\xf9\x71\x07\x3c\xf6\x71\x2f\x66\x7f\xce\x46\x98\x77\x6b\x98\xcc\x54\x44\xc6\x92\xab\xd1\x28\x81\x98\xbe\x5a\xd5\x67\x46\x09\xf7\xe1\x39\xad\x1b\x9c\xcb\x94\x3f\x8d\xfd\x9d\x12\xc5\x4e\xce\xe2\x78\x34\x1b\x2e\xe1\x27\x79\x91\xca\x62\xcd\x3b\xfe\x12\x8d\x13\x92\x96\x4e\x95\x88\xe2\xf9\x7c\x32\x17\x04\xa3\xde\x10\x61\x88\xc5\xeb\x33\x5a\xa5\xa1\x9a\xcc\x90\x67\xb4\xa9\x41\x29\xb9\xd1\xa6\x16\x7c\x4b\xbf\xb5\x6f\xb9\x76\x84\xcb\xbd\x72\x0c\x86\x86\x9e\x00\x20\xab\x07\x76\xcd\xc9\x95\x4f\xeb\xa8\x62\x12\x4b\x07\x3f\xba\x8d\xe9\xea\x9a\x38\xea\xcf\xa0\x03\xae\x4f\x1c\xdc\xbf\x15\xc3\x2f\xb6\xb9\x70\xc7\x31\x15\xdd\xff\xcd\x4f\xa3\xb7\x18\x46\x11\x0e\xde\xc2\x57\xfc\xae\xd6\x11\x36\x04\xf7\x19\x25\x72\x57\x72\x64\xb9\x90\x5c\xa6\xae\xd8\xda\xec\x13\x84\x03\xca\x41\xaa\x95\x42\x78\xa5\x72\x0b\x26\x7b\x90\xca\x16\x3a\x9b\xdf\x44\x7e\xad\xe8\xde\xb7\x69\xa3\xb4\x92\x37\xa7\x35\x16\x97\x7c\x28\x73\x45\x55\xdd\x23\x4c\xa7\xde\x49\x99\x26\x1b\xc7\x96\x0f\x53\x6b\xa8\xa3\x5a\xd3\xd0\x2c\x75\xf1\xc2\xbe\xa0\xa0\x61\x2e\x7d\x49\xc4\x03\x97\xdd\x6a\xf5\xff\x58\xba\xe6\xa6\x4b\x6a\x77\xe9\x81\xf9\x2d\x15\x9e\x0b\x2b\xd2\x05\xab\x15\x70\x52\xf4\x70\x17\xa3\xe1\x8a\xec\x94\x4d\x04\x65\xee\x00\x17\xe9\x61\x48\xa6\x12\x9f\x74\xd3\xcc\xb4\x89\xfe\xa1\x3a\x15\xa9\xb9\xac\xed\x58\xc6\xee\x0e\x6e\x84\xe0\x5f\xda\xdf\xae\x07\xb3\x34\xa9\x8f\xc3\x7f\x7e\x51\x1c\xd5\xa4\x4e\x9c\x74\xe4\x78\xd3\x49\xe3\x0e\x29\xae\xb4\x6a\x4d\xf0\x1e\x43\x07\xfe\x65\xe1\x39\x4a\x75\x8f\x6a\xda\x2f\xb1\x20\x22\x5c\xcd\x50\xa4\x90\x13\xe6\xc9\xf1\x75\xaf\x90\xf3\xfc\x8c\x57\xe7\xa6\xa9\x69\xa9\x16\xc3\xf1\xaa\xcc\x22\xf3\xe0\x1a\x07\x0c\xc4\x8e\x6f\xd8\x78\xe2\xbd\x07\x3d\xf9\xee\x6f\x05\x9b\x98\x56\x84\x04\xfc\x7e\xae\x7d\x4b\xf6\xfa\x16\xc0\xc8\x03\xc6\xbe\x84\xe8\xb7\x9c\x67\xaf\xfc\x8c\x88\xca\xbd\xee\xbc\x11\x34\xbb\x23\x86\xe2\x2b\xa4\xd2\xe9\xe0\xf3\xe1\xab\x3a\x0d\xac\x7c\x80\xdd\xee\xd7\x73\xcd\xa0\xc4\x1d\xc9\xde\xfa\x67\xfe\xa3\x77\x69\xcb\x4a\x1e\x15\x22\xd7\xe0\xb3\xd7\xc4\x63\x8b\xcd\x98\x31\x53\xd4\x78\xbe\x5e\xcf\x2b\x6a\xb1\xb4\x01\x24\xe4\x22\x2b\x8c\xaa\x46\x47\xbd\x50\xd7\x4d\x20\x39\x43\xab\x20\x93\x8d\x5f\x27\xd9\x08\xa6\x73\x67\x40\x46\xce\x2e\xf1\x8e\x85\x8b\x0a\x01\xa7\xe7\x53\x0d\xed\x0f\x8c\xc8\x9e\xf0\x9b\x73\xca\x59\x7c\xf7\x3a\xfb\xc9\xa2\x71\xa4\xd2\x3c\x92\xfe\x59\x18\x83\xc4\x40\x10\x9c\x4e\xf4\x16\x67\x0b\x7f\x2c\x59\x05\xb7\x7f\x65\xf5\x6d\x09\xd4\x02\x50\x35\x6f\x9b\x1d\xbc\xaf\x1e\xe2\xc0\xb6\x36\x96\xf8\x4d\x68\xdd\xbe\xa1\x60\x08\x51\x51\xa9\x52\x62\x74\xd7\xb8\x46\xcc\xeb\x6c\x43\x48\x09\x84\x84\xde\x3b\xb7\x23\xae\x5e\x85\x27\x6d\xf4\x9f\x56\x34\x13\x0f\xf9\x05\x75\x4f"}, -{{0x01,0xa2,0x47,0x94,0x3a,0xfe,0x83,0xf0,0x36,0xb6,0xb6,0x0f,0x23,0xd9,0x77,0x74,0xfd,0x23,0x20,0x8e,0xdc,0x31,0xcf,0x3d,0x88,0x20,0xe9,0xdc,0x63,0x66,0x11,0x03,},{0x8c,0x97,0xa5,0x8b,0xe0,0xe8,0x47,0xc4,0x8a,0x6a,0x39,0x87,0xcf,0xe2,0x50,0xa8,0xd7,0xb0,0x7d,0x97,0xf9,0x61,0xf6,0xb7,0xb7,0x9e,0x7d,0x80,0x42,0xb8,0xbd,0x7b,},{0xed,0x2c,0xed,0x1a,0x4f,0xdd,0xb3,0x44,0x2a,0x63,0x73,0x48,0x17,0x9a,0x6a,0x5b,0xee,0xdc,0xb4,0x4c,0x8e,0x98,0x8c,0xa2,0x6f,0x78,0x93,0x6d,0x2c,0x8d,0xb5,0xc5,0x16,0xd5,0x4b,0x8c,0x4f,0x08,0xd9,0x1d,0xd7,0x04,0x2a,0xb6,0xab,0x26,0xd8,0x7f,0x23,0x0e,0xb2,0xb2,0x15,0x6f,0x3c,0xe2,0x99,0x4f,0xce,0x7c,0x2b,0x0f,0x10,0x0e,},"\x08\xd8\x14\x95\xda\x77\xf4\x07\x25\x5c\xc4\x1a\x81\x8e\xef\xa7\x27\xe2\xc4\x7a\xe4\x11\xf4\xb5\x41\xf0\x1f\x81\x1d\x90\x6d\x55\xfb\x1e\x3c\x9c\x48\x4d\xf3\x05\x65\x36\x4d\xe9\xdc\xb9\xfe\xa0\xaf\x66\x11\x2f\xe7\x5f\xd1\x1a\xe8\x1d\x26\x41\xb5\x47\x58\x9f\x8b\x97\x4a\x97\xe7\x97\x6e\xd6\x92\xaa\xd6\x40\xed\xd2\x88\xbd\x86\x3d\x11\xc4\xca\x98\x36\xf9\xd7\xc1\x15\xc3\xd9\x88\x30\xd6\x42\x47\xcb\x6f\x8f\xb6\x03\xc6\x98\x11\x33\x55\x2a\x32\x04\x04\x19\x61\xbd\xd8\x3e\x2f\x9d\xeb\xa7\x70\xc0\x39\x4f\x9b\x60\x2a\x45\x35\x51\x07\x49\x21\xa3\xde\x28\x32\x13\x69\xd7\xf8\xca\x64\x0c\x45\x10\x9e\x8f\x52\x2c\x97\xed\x9f\x35\xb9\x27\x7a\x35\x0e\x29\x59\x31\xb4\x2e\x01\x35\xe9\x4a\x92\xfe\xd3\x63\xd6\xca\xe3\x92\xf7\xc4\x51\x99\x32\x7e\x24\xb4\xcf\xa5\x89\x8a\xb5\x99\xae\x7b\xd5\x0b\xd3\xa0\x0c\x0d\x00\x7e\x95\xfa\xf8\xf2\xae\x10\x38\x02\xca\x7e\x53\xb2\x79\x18\x4d\x06\x90\x5f\x57\x48\xca\x8b\xe1\xf7\x2e\x66\x8c\xb8\x32\x83\xdd\x00\x40\x64\x91\xf8\xb9\xb4\xe5\xa9\xd4\xa5\x43\x8b\x2f\xa4\x37\x1e\x0b\x05\x68\x6f\x87\x57\x5b\xaa\x79\x6e\x30\x2f\x08\xff\xc4\x25\x66\x27\x50\xa3\x3a\x0c\x9c\xfa\xa4\xb4\xd7\x04\x1f\x92\x64\xfe\xd7\xbe\x4f\x9f\xde\x2c\xac\x68\xa2\x15\x82\x36\xf6\xac\x43\x04\x7e\x91\x1f\x4c\x4e\x8b\xc6\x63\xfd\xd5\x05\x17\xdf\xaa\x8f\xbc\xd2\x19\xdd\x7a\x0e\x93\x69\xf4\x3d\x0d\xd2\x5b\x4f\x0c\xf9\x30\xf2\x0b\x7b\x7c\x6d\xb9\xd5\xbe\x0c\x6e\x19\x60\x94\x1a\x3e\x04\xd1\x41\xc0\x3e\x59\x61\xaa\x33\xe9\x02\x44\x77\xd5\x33\xc9\x95\x37\x87\x96\xbf\x22\x92\xad\xe9\x22\x69\x5b\x14\x56\x9f\xc3\x39\xb3\xd9\x08\x5c\x63\xfc\x6e\x5b\xef\x4d\x99\x0c\x80\x33\x3a\x6b\x57\xaf\x47\x8f\x93\x8e\x3e\xe7\x38\xb1\xd1\x29\xbd\x97\x6a\xfe\x68\x61\x28\xbc\xac\x08\xcc\xbe\xb0\x34\x9b\x9b\x53\x73\x13\xbc\x7b\xf5\x91\xc6\x5d\x4a\x71\x23\xad\x30\xbd\xbe\x14\x86\xb4\x28\x08\x47\x48\xb6\x50\x7f\x6f\x5e\xf6\x7c\x26\xca\x86\x2c\xf7\x26\xaa\xc1\x40\xb8\x61\xae\x0d\xc7\x4b\xb3\xc0\xb4\x89\x78\x9f\x17\x14\x5e\x9a\x85\x5a\x3e\x2b\x5d\xaa\xc4\x18\xd8\x35\x37\x33\x23\x9e\xf6\x9c\x7b\x56\x5b\x53\x03\xeb\x87\xbd\x7f\x64\x9a\xbf\x40\xa2\xf1\x35\xa2\x9e\xd2\x7e\x3b\xe4\xc1\x2c\xd6\xdd\xd2\xe5\x41\x8a\x99\x97\x43\x83\x66\x3f\x58\x49\xbf\x3c\xe5\x53\x2b\xf6\x4a\x80\xaa\x52\x11\x91\xd2\x53\x90\xbc\x19\xa4\x5e\xed\x1d\x3f\xec\xa1\xd9\xfc\xc0\xdb\x03\x1b\xfb\x48\xe4\x50\xbe\x3d\x45\x93\x35\x6d\x5b\xa0\xf3\x10\x47\xb4\x57\x74\x5f\x21\xe3\x2e\xbe\xa3\xca\x6c\x35\xf0\x5d\x78\xd8\xc3\x16\x40\xb0\xfe\xcb\x94\x01\x16\x56\x75\xc7\xf9\xcb\xb1\x9b\xc4\xb5\x67\x7c\x2c\xce\xdc\x4e\x7a\xaf\xb8\x41\x84\xc1\x91\x99\xac\xa0\xdb\x21\xcf\x50\x67\xdc\x3a\xf7\x69\xbc\xc6\x29\x35\x5f\xf7\x25\x7a\x9e\xfd\x71\xa6\xa9\x2d\x13\x0d\x35\xab\xee\x6e\x70\x60\x5b\x5c\xab\x93\xc0\x28\xfa\xc3\xaa\x23\x44\xba\x86\x1a\xc1\xe8\xce\x9a\x4b\x07\x0c\x3d\xf7\x40\xd2\x8c\x5e\xce\x0f\x1b\xc3\x1c\x2d\x7d\x1e\x5e\xcc\x76\x10\x44\x80\x93\x91\x33\xa1\x86\x60\xe4\xa3\xe4\x84\x6b\x25\x17\xbe\x3b\x8e\x7a\xfa\xfe\x07\x83\x91\xd8\xaa\x8e\x5c\x30\x13\x7e\x85\xd9\x4d\x64\xa2\x79\xfb\xee"}, -{{0x91,0xfd,0xef,0xcd,0xbc,0x99,0x0d,0x3e,0x8e,0xeb,0x60,0x17,0x04,0x34,0xda,0x10,0x83,0x1b,0x03,0x08,0x1f,0x6a,0xfd,0x0d,0x7e,0x12,0xb1,0x00,0x11,0xe0,0x2a,0xef,},{0xc5,0x8d,0x3e,0x20,0xb8,0xd4,0x7b,0xa4,0x55,0xb9,0x12,0x57,0x2d,0xc8,0x40,0x81,0x5e,0x3d,0x88,0x5f,0xa5,0x91,0x7d,0x1d,0xa4,0x84,0x08,0xb9,0xa9,0x56,0x40,0x98,},{0x51,0x01,0x12,0x22,0x3b,0x33,0xa5,0xab,0x15,0x64,0xf7,0x53,0x71,0x91,0xcd,0x29,0x2a,0x9d,0xbd,0x5a,0x32,0x3d,0x7a,0xdd,0x05,0x84,0xc1,0xb0,0xad,0x00,0xd0,0xac,0x71,0x99,0xc3,0xfb,0x75,0x8e,0x91,0x3f,0xf3,0xd7,0x16,0xc2,0xe9,0x0d,0xd9,0x0d,0x4e,0x8f,0x59,0x95,0x1e,0x87,0xef,0x8b,0x78,0x21,0x4a,0x51,0x75,0xc4,0xe6,0x08,},"\x5b\x0c\x1a\x3a\x95\xe0\xba\x74\x74\x76\x6c\x9b\xad\xfa\xe3\x4a\xb8\x60\xe0\xa6\xc0\x33\xa2\x2f\xba\x72\x11\x27\xf5\xbb\xee\xe8\xe2\xcb\xde\x1a\x1d\xfe\xb1\x8d\x55\x1c\x95\x99\x4d\x21\xe3\xeb\xc6\x8a\xfa\xe6\x85\x44\x4a\x3a\x41\x95\xbc\x75\x55\x38\x90\x3a\xcf\xa6\x71\x55\x92\xdd\xe2\x56\xe7\xa1\xb4\xc3\x63\xec\xa7\x1e\xf0\xf3\xa4\x8a\xe3\x44\x2d\x50\xd5\x66\x1b\x39\x40\x96\xb7\xec\x27\xbb\xf5\x29\x53\xf3\x04\x0c\xd2\x5b\x78\xce\x47\x55\x27\xe0\xcc\x59\xf1\xef\x9a\xe2\xe0\x59\x04\x31\x58\x2b\x2d\xf8\x14\x14\x99\x82\x9a\x2c\x5f\x7b\xbe\x35\x98\xe4\xc9\x6c\xc0\x1e\xde\x2f\x43\xb6\x56\x05\xb4\x88\x59\x37\x09\xc0\x94\xb5\xa0\x42\xb2\x85\x55\xfb\x52\x27\xa6\xd1\x56\x37\x6f\x3f\xf0\x7b\xd5\xc8\xbc\x68\x04\xd3\x9a\x32\x82\xac\x59\x70\xba\x08\xae\xbf\x75\x42\xb8\x45\xf6\xb5\xc2\x38\xc2\xce\x20\x44\x3f\x7f\x77\x55\xd7\x5f\xe4\xfa\x16\xb9\x64\x4c\xa3\xe2\x1d\x91\xa9\xa8\x7c\x68\x61\x15\x74\x8a\x16\xc0\xae\x4a\xe4\xe1\x6d\x1c\x71\xae\x60\x0b\x39\xcd\x25\xe5\x63\x3b\x39\x9f\xee\x7f\xf2\xe3\x62\xbe\xd2\x51\x25\xc6\xfd\x5c\x7f\x5f\xfa\x2d\xa2\x35\x3f\xd3\x5b\x78\x4a\x1b\x1b\x03\x19\x77\x47\x58\xb7\x39\x0c\x44\xdc\xc9\x2f\xca\x42\x01\xdf\xe1\xa3\x75\x69\xde\x05\xf0\x66\x4d\x08\xb9\x0d\x6e\x2b\xad\xc2\x1b\x92\xf9\xce\x87\x21\x42\x35\x7b\x96\x15\x08\x0a\xb7\x65\x9a\x24\x6f\xf0\x85\x2a\xdb\x17\xdf\xda\x70\xcf\x17\x54\x15\x7b\x13\xbc\x03\x2b\x4c\x5d\xeb\x8e\x10\x68\xb4\x69\x2b\x93\x16\x5d\xa3\x5e\xfc\x9d\xa8\x6a\xcb\xe6\xf8\x0f\x01\xbb\xc2\x6f\x57\x5e\xc5\xaf\x5b\x05\x0e\x98\x28\xaf\xde\x6c\x3b\x78\xe7\x33\xeb\x5a\x91\x24\x92\xf7\x65\xbc\xad\x73\x1b\x95\xe3\xab\x88\x96\xb6\x17\x58\xbf\x91\x3b\x9a\x15\x68\xf9\xc5\xb4\x60\x33\xcf\x45\xdc\xc1\x75\x0d\xa2\x06\x6c\x60\x8d\xc3\xd3\x43\x73\x8e\x84\x8d\xc3\x90\xcd\x47\x44\x32\xe9\x91\xd7\xaa\x2c\x5b\x27\x81\x42\x1e\xfe\x55\xe3\x6b\x0b\x42\xc1\xf4\x9a\xe2\x77\x48\x0b\x0f\xc5\xff\x68\x5b\xb5\xa3\x1b\xe3\xa0\xfa\x44\x82\x38\x16\x07\x70\x37\x54\x8a\x5c\x9b\x0e\x1c\xc6\xc6\x35\x04\xa4\x07\x57\x9a\x36\x32\xb3\xc9\x6f\xcd\x0d\xe5\xea\x1e\x4d\x6e\x87\xc0\xca\xf7\xb6\xca\xe3\x12\x0d\xb8\xb1\xf4\x61\x5c\xe6\xa7\x5a\x81\x65\x4f\x39\x04\x28\xb6\x4c\x21\x3e\x72\x7e\xec\x3a\xe7\xf9\xf4\x2d\xb9\x06\xf4\xde\x1f\xda\xdd\x34\xa3\xda\x2a\xeb\x12\xb4\xd9\xa1\x85\xf4\xa6\x0c\xb0\xc2\x67\x45\xf5\x30\xb4\x81\xfc\x97\x6a\x09\x3c\xe2\x4a\x30\x91\x6a\xf6\x05\xee\x94\xb0\x87\x85\x19\x3a\x94\x9d\x56\x9c\x4b\x7e\xf5\x96\x03\xbb\x62\x43\x60\xe7\xb4\x08\xd9\x8c\xa5\x09\xda\xf5\xa9\x2a\x6d\x40\x15\xbd\xb6\xf9\x7a\xd4\xff\x0c\xf0\x5c\x8f\x0c\xd5\x47\x6a\x93\x44\x26\xa0\x59\xf2\x44\x44\x46\xe5\x86\x4f\x08\x9e\x0f\x06\x75\x61\x59\x10\x66\x2d\x7c\x1e\x79\xa6\xc7\x5f\xa3\x14\xb7\xba\x2c\x64\x3b\x0d\x37\x65\x3e\xef\xe5\x93\x17\x2d\x1d\x33\x2c\x8d\xd6\x44\x92\xea\xf1\x04\xfb\x19\x57\xba\xa5\x20\x49\x44\x2d\x10\xb5\x6a\xf8\xea\xe8\xff\x82\xcd\x8f\x46\xa0\x49\x4b\xec\x2f\xcb\x9f\xad\xf1\x0c\xf7\x1a\x6e\xec\xd0\x54\x7d\xaf\xdc\x7a\xdb\xaa\x45\x03\x78\x3f\x94\x3a\x46\xb4\xad\x0e\x6d\xd7\xf2\xca\xb5\x56\x17"}, -{{0xef,0x00,0xb3,0xc1,0x81,0xf6,0x32,0x7d,0x02,0x25,0x67,0x51,0xcb,0x51,0xc2,0xc3,0x6c,0x0c,0x0a,0x78,0x07,0x63,0x40,0x54,0x8f,0x5b,0xc0,0x70,0xd8,0x6d,0x9e,0x26,},{0xdb,0x14,0xcd,0x32,0x58,0x8f,0xd7,0x41,0xe8,0xf4,0x2e,0x51,0x21,0xcc,0x81,0x1a,0xd4,0x50,0x63,0xf2,0x81,0x41,0xe8,0x3c,0x66,0x8f,0x07,0xd9,0x12,0x28,0xf0,0x49,},{0x13,0x9f,0x9c,0xb9,0x9b,0x99,0x5b,0xe6,0x58,0x8c,0xdd,0xb5,0x05,0x16,0x94,0x83,0x8f,0x9d,0x82,0xa6,0x07,0x61,0xfd,0xe3,0x04,0xb0,0x02,0x7f,0xf8,0x65,0x84,0xbf,0x65,0xc7,0x3c,0xc6,0xd2,0x53,0xe5,0x60,0xf6,0x55,0x25,0xdf,0x04,0xbf,0xe1,0x46,0xc8,0x3b,0x42,0x26,0x9c,0xf3,0x78,0x0f,0x8b,0xc3,0x92,0x43,0x78,0x94,0xae,0x01,},"\x7d\x6a\xbe\xc7\xa1\x1a\xf6\x73\x24\xce\x17\xb1\xd2\x0b\xb4\x0c\x66\x8a\x21\x9b\xc9\x5d\xf0\x5e\x32\x5d\x86\xf8\x87\x95\xe2\x64\xd4\x54\xfc\x5f\xa7\xd9\xc8\xaa\xfe\x77\xe9\x0a\x6a\xf6\xb5\x74\x53\xd8\x5b\x97\x0b\x55\x2a\x85\x6b\xa6\x59\xab\x31\xbd\x8a\x66\x0e\xb7\xd3\x58\x7b\x45\x3e\x5c\x5f\xc6\xb7\x94\x72\xb2\x6e\x8f\xf7\xdd\x6d\xb6\xbe\x35\x72\x54\x8b\x0d\x75\x4e\xd4\xd9\x85\xb8\xd9\x96\x5f\x88\xb9\x52\xfc\x4f\xa3\xb7\x61\xcc\xff\xc3\x53\x54\xdb\x0e\xb9\xc5\xa1\x71\x71\x8a\x8a\x55\x92\x87\x02\x13\x82\x7d\x36\x91\xba\xe7\xfd\x9c\x63\xf2\x05\x03\xe0\x43\x19\xb5\xe9\x53\x57\x9d\xe4\x7e\x3e\xf8\xe1\x62\x85\x49\x50\x3c\xb4\xf6\x87\x1b\xa2\x5d\xb8\x73\x47\x08\x0e\x53\x1a\x51\x7a\x8b\x72\x21\xe6\xad\x84\xdf\xf8\x32\x56\xd9\xab\x9a\x43\x3d\xe8\x71\xb9\xcb\x9c\x50\x44\x58\x9e\x67\x20\x6b\x31\x7a\x52\x06\xae\xba\x96\xc9\x2f\xd6\x09\x40\x71\xc6\x44\xfe\x52\x65\x8d\xed\x92\x20\xcf\x6a\xbd\x50\xe2\x30\x5a\x1c\x90\xfd\x66\xaa\xcf\xb3\x8e\xb0\x5e\xaf\xf6\xca\x5f\x85\xf4\x29\xcd\x57\x71\x6e\xb8\x77\x39\xa0\x2b\x64\xcf\xfa\x08\xc4\xf6\x85\xb0\x03\x10\xb5\xb4\x84\x49\x20\xdf\x21\x5a\x9f\x24\xa1\x76\x13\xae\xf8\x5f\xec\x94\xf5\x11\xdc\x8a\x42\x94\xed\xdc\xea\x11\xc0\x8c\x0b\x39\x9a\x23\xd9\x16\x38\x3e\x29\xad\xeb\x98\xc6\x5d\x41\xc7\x05\xa5\x7f\x84\x05\x20\xfa\x80\x8d\x7f\xd2\x5f\xdc\xe1\x59\xf7\xa0\x84\xd0\x62\x97\x4b\x30\x13\x2a\x57\x12\x42\xba\xff\x41\x96\x24\x6d\x6d\x75\x7b\x31\x2e\x9d\x60\x85\x53\xd2\xdc\x53\xb6\x23\xb2\xe9\x5c\x75\x38\xfb\xc5\xde\xb6\x2b\xa7\x37\x76\xd8\x5e\x51\x18\xfa\x1a\x30\x2d\x4d\x07\x6d\x99\xe1\x00\xf0\xdf\x11\x9c\x33\xfc\x66\xcd\xfe\x6f\xd4\x4d\x71\x99\x7b\x78\xc8\xf7\x89\x0c\x70\x73\x46\x05\x62\x20\xd1\xe9\xde\x88\xbc\x17\x3c\xf0\xb7\x6c\xb3\x02\x87\x7e\xc1\x6a\xf4\x6e\x4c\x31\x63\x9f\x54\xee\xdc\x16\xda\x9d\x9e\xb0\xad\x95\xbd\xa5\x45\xdf\xc4\xa7\x32\xb6\xda\x98\x14\x13\x6a\xb1\xb9\x39\x2a\x07\x1b\x02\x24\x73\xb3\x49\x05\x57\x69\x8b\x77\xe7\x44\x7a\xc8\x59\x0d\xca\xf4\xf2\x42\xad\x3d\xfb\xc0\xdf\x71\x6c\xc0\xea\x75\x36\x26\x97\x3d\xf0\x8d\x93\x5d\x17\x8e\x33\x12\xfb\xe2\xa7\xba\x9c\x50\x93\xc5\x3b\x92\x55\xea\xca\x29\xb7\x25\x78\xe3\xba\x1b\xdf\xaf\x0c\x9e\xce\x21\xa5\xdf\xf6\xea\x42\x15\x24\xf7\x0f\xc1\x90\x4e\x9a\x2c\xf7\xc5\x18\xbf\xcc\x7e\x36\x73\xee\x87\xff\x27\xe1\xca\x2a\xc3\x2b\xcb\x40\x91\xcb\x34\xa8\x2a\x71\x56\x3f\xf6\xa6\xa1\x5d\xa0\xeb\xd5\xbd\x10\x25\x6c\xe9\x60\xf4\xea\xa7\xfe\x35\xe1\x28\x88\x60\x50\xd0\x49\xfe\xc3\xa4\xab\x16\xd5\xb0\xc1\x07\x26\x7e\xae\x1a\xb8\x01\xea\x5b\x91\x98\x38\x39\xda\x1c\x48\x8c\x12\xf8\x64\xd7\xc3\xa7\x7f\x2b\x6a\xe2\x7d\x54\x01\x09\xf6\x8d\x78\x36\x4b\xb6\x27\x18\x3b\xd5\x03\x91\x75\x47\xaa\xf3\xb3\xa1\x80\x9d\xa0\x25\x77\xb3\xf0\x3a\x9a\x3f\x5a\xf4\x8c\x88\x02\xe2\x97\xc8\xbb\x63\xdb\x6a\x86\xd3\xea\x72\x7a\x6d\x71\x48\xb3\xaa\x44\x4b\x8d\x16\x8f\x38\xc6\xc8\xf2\x40\x88\xa4\x9a\xf3\x31\x77\xa3\x44\xad\xab\x2c\xf6\xe0\x8e\x0c\xb0\x37\x1e\xd5\x2b\xde\xad\x13\x2f\x77\xe7\xae\x3e\xe5\xd8\xfb\x17\xaf\xc0\xa0\xbb\x73\x11\xb9\x56\x0b\x67"}, -{{0xd0,0x71,0xd8,0xc5,0x57,0x8d,0x02,0x59,0x49,0x93,0x2a,0xa6,0xbf,0x6a,0x80,0xb1,0xcc,0x41,0x2f,0x10,0x6f,0x91,0x57,0x4e,0xe2,0x46,0x54,0xb4,0x45,0xee,0x9a,0x97,},{0x9b,0xcb,0xf7,0xd2,0x21,0x2f,0xb6,0x2c,0xcc,0xf8,0xb6,0xc7,0x68,0x03,0xa5,0xea,0x24,0x40,0x9d,0xa6,0x28,0x7e,0xfb,0xb8,0xb1,0xf0,0xc7,0xb3,0x0e,0xbd,0xd9,0x3e,},{0x0c,0x29,0x7a,0xbe,0x0f,0xd8,0xeb,0xcc,0x6b,0x77,0x19,0x98,0x75,0x5e,0x2c,0x6b,0xe0,0x7c,0x81,0x2b,0x5a,0x80,0x54,0x49,0x57,0x06,0x31,0x70,0xca,0x69,0x43,0x2e,0x72,0xb6,0x0d,0xaa,0xe3,0x22,0x95,0x8a,0x22,0x38,0xcd,0x6a,0x46,0x28,0x94,0xa3,0x87,0xee,0xf6,0x5b,0xf9,0x6f,0x63,0xf5,0x4c,0x08,0x56,0x87,0xa5,0x02,0x75,0x0e,},"\x3e\x8e\xe7\x0e\x51\xe5\x6e\xf5\x7f\x6e\x66\xb3\xa8\x84\xaa\x04\xa7\xb4\xd4\x59\x9f\xb9\xb4\x39\x96\xb3\x93\xa8\x68\x09\x35\x12\xea\x74\x1a\x0c\x6a\x94\xf4\x0c\xe4\x98\x62\xd2\xfd\x1f\x75\x51\xf4\x64\x7a\xbd\x80\x75\xbc\x1b\x74\x2a\xd4\x0e\x29\xa6\x04\x61\x30\x12\x24\xfe\x8f\x76\x92\xb1\x47\x72\x78\x2b\x4e\x89\x6b\x63\xfe\x05\xab\xd5\xff\x53\x14\xf9\xec\x80\x75\xf2\x8d\x90\x8c\xca\xaa\xce\x5e\x90\x5e\xa7\xf5\x7a\x49\x1b\x99\xb3\x59\x1e\xea\x54\xa6\xb7\x81\x91\x67\x74\x9d\x38\xa0\x47\x62\x06\x76\xa1\xa7\xaf\x11\xf4\x85\xa5\x5b\x7c\x87\x9e\x68\x50\x38\x08\x58\xc8\xf4\x5c\x0c\x1c\xcb\xd7\x40\x6e\xd0\x99\xd8\x4a\x74\x71\xb9\x35\x0c\x4d\xdb\x28\x47\x0b\xf5\xbf\x32\x7d\x5b\x3c\x22\xd8\x99\xb4\xc6\x60\x83\x9e\x10\x4a\x06\x22\xae\x85\xc8\x4a\xa9\xfc\x7f\x0a\x2c\x7c\xeb\x6e\x69\x1c\x49\xc0\x64\xb5\x31\x34\x99\x68\x3e\x8e\x03\xb2\x11\x5e\xda\x7d\xda\xd5\x5a\x49\xf9\xfb\xe6\x25\x44\xf9\x14\x51\x1c\xfb\xec\x6b\x84\xdb\xde\x7e\x80\x90\x9b\x45\xfb\x10\x50\x2e\x2c\xaa\xa7\x21\x24\xfd\x94\x56\xa3\x87\x2f\x95\x92\x70\x7e\x9a\x4c\x50\x12\xda\xa9\x72\xea\xf6\x5f\xab\xe5\x53\xde\xbe\x82\x57\x01\xef\xef\x5c\x75\x6b\xb4\x65\xe9\x66\xab\x68\xdd\x52\xf3\xdd\x00\xa4\x5c\xf6\xdc\x3f\x19\xb8\x6b\xb0\xdb\x4a\x86\xe4\x66\x98\x85\xa0\x74\x69\x6a\x67\xd8\xea\x21\x18\xc7\x66\xef\x62\x5f\x8a\x98\x02\x6f\x9f\x4a\x3c\x5c\xcc\xf9\x84\x6f\xdc\x90\xed\x93\xec\x7c\x1f\x3c\x70\x86\x95\x4f\xa2\xf0\xa4\xca\x96\xd4\x01\x84\xaa\x57\x54\x55\x27\xa1\xf9\x65\xc1\x1d\x84\x3c\x90\xc5\xa5\xe0\x8d\x7c\x11\xf2\xd5\x61\x00\x4e\x90\x57\x48\x52\xeb\x50\x46\xaa\x1e\xa7\xb6\x10\x09\xfd\x5d\xd7\xd6\x24\x2a\x8d\xf5\x8a\x9e\x8e\x55\x5c\x7f\x4c\xdc\x13\x0d\x69\x01\xbf\xe6\x79\x7f\xdc\x6c\x39\xbe\xec\xfb\xba\xb6\x62\x5b\x2e\x4f\xb9\xd8\x00\x02\x76\xd4\xa9\x4f\xc6\xfc\x10\x51\xfe\xff\xf5\xad\xeb\x72\x4b\x87\x09\x0d\xb0\xa2\xc6\x97\xd0\x56\x66\x4d\x99\x1f\xad\x80\xdc\x80\xfa\xb7\x00\xb1\xf1\xf2\xee\x27\x73\x4e\xbc\x26\xb2\xa6\x41\xc3\x2a\x0c\x91\x1b\x27\x0a\xc7\x6b\x0d\xa5\xc0\x89\x14\x97\x1c\x91\x12\x46\x3a\x70\x70\x9c\x0d\xda\xc7\x91\x00\x16\xf9\x13\xf6\x21\x00\x86\xd7\x25\x5c\xef\x11\x95\x57\x10\xf6\x51\x88\x9c\x83\x62\x1d\xd8\xa4\xfc\xd5\x36\x63\x02\xd6\xc9\xb5\x6e\xef\xcf\xac\x85\xc1\x4a\x94\x78\xb6\xd7\x18\x07\x54\x28\x80\x07\x60\x51\x5c\xab\x5f\x3d\x44\x55\xe2\xb9\x70\xdf\x9f\xe4\xbe\x83\x83\xd7\x04\x83\xbb\xdd\x75\x60\x71\xf5\x3b\x2f\x9c\x27\x5c\x7c\x85\x12\xd1\x63\x51\x8f\xe5\x55\x83\x75\x14\xc8\x67\x76\xc9\x47\xf2\x9a\x77\x57\x02\x87\x44\x6b\x69\xbe\x40\xc8\xd4\xab\xbd\x65\xef\x25\x07\x24\x9b\x5a\xec\x33\xac\xb7\xb8\xbd\x3f\x35\xbc\x85\x9b\xa4\xe3\x7b\xdb\x49\xcf\x91\x3d\x93\x98\x9c\x44\x38\xd2\xab\xcf\xa3\x88\xcc\x89\xd7\x8a\xc0\x62\x70\x65\x64\x92\xe7\x52\x8f\x29\xbd\xfe\x8c\xbb\x9b\xfa\x9e\x73\xc1\xda\x01\x3f\xc3\xce\x21\x05\x65\x76\x13\xff\x62\xbb\x0c\x3b\xf4\xde\xe3\xb0\xd2\x65\x9c\x72\x6e\x7b\xcd\x9e\x97\xec\xce\x92\x47\xd4\x60\x0d\xfe\xaf\x60\x44\x4e\xd8\x62\xb0\x0b\xa1\x1e\x70\xea\x88\xd4\xf0\xb6\xb5\x39\xfc\x9f\x36\xbb\x2a\x1a\x9e\xd2\xb3"}, -{{0xe9,0xd4,0x86,0xc2,0x9a,0xe8,0x11,0xb9,0x42,0xe1,0x0d,0x81,0xf0,0xa6,0x71,0x63,0x17,0xb8,0x42,0xc2,0xc5,0xbf,0xde,0xf5,0x5c,0xc4,0x32,0xb7,0xfc,0xae,0xb8,0x18,},{0x43,0xa5,0x2d,0x15,0xb9,0xf7,0x31,0xd7,0x37,0xb1,0xc4,0xdb,0xc3,0x22,0x27,0xa4,0x80,0x96,0x30,0x91,0xd2,0xc6,0x28,0x6f,0x48,0x2e,0xf1,0xe8,0x36,0x70,0x54,0xe5,},{0x65,0x19,0x1a,0xa8,0x85,0xdd,0xab,0x9f,0x67,0x27,0x18,0x79,0x95,0x2f,0xc6,0xaf,0xfe,0x41,0xca,0x20,0xeb,0x3b,0xcd,0x86,0x67,0x31,0x61,0xb0,0x3b,0x53,0x26,0x94,0xd6,0xdd,0x88,0x90,0x8e,0xb1,0xb1,0xee,0xc0,0x03,0xcf,0xcb,0xe6,0x14,0x6b,0x45,0x38,0xe2,0x1d,0xf5,0x59,0x69,0x91,0x2a,0x0d,0x7d,0x88,0x18,0xad,0x79,0x59,0x0d,},"\x14\xfe\x1e\xd5\xbb\xbd\x76\xcc\x73\xdc\x56\x50\xbd\xa9\x2d\xe8\x63\x26\xe2\x4d\x2f\x1f\x62\x24\xba\x85\x68\x94\x4d\x6f\xe3\x44\x26\x75\xdb\x96\xf1\xd8\x49\x8f\x16\x34\xff\x9b\x6e\x50\xcb\xa9\xdb\x4e\xb0\xb0\xb0\x21\xb2\xbe\xcf\xce\x4b\xef\x33\xc4\xce\x0e\x32\xc8\xa9\x83\x89\xec\xa9\xe0\x59\xa6\x62\xd6\xf0\x37\xc5\x4a\xa4\x0c\x76\xcd\xee\xe8\x56\x50\xf0\x89\xea\x56\xe1\x38\x3a\xb0\xf5\xc3\x6f\x6d\x66\x45\xff\x7e\x87\x66\x73\x01\xf9\x44\xfd\xc2\xed\x35\xb0\xd2\xc3\x5c\xb2\xe4\xb4\x56\x36\xe7\x49\x8e\x92\x7f\x58\x46\xb3\xe1\xed\xfb\xd1\x60\xa4\xae\xf3\x32\x0c\x34\x28\x49\x6b\xda\xaf\x7d\x3e\xd5\x6e\xf0\xb7\x25\x4a\xc5\x97\xbe\x58\x9a\x70\x58\x44\x16\x30\x0c\x1a\xdc\xfb\xa4\xf2\x2c\xfd\x4c\xd6\x61\xe1\xf5\x0f\x15\x5d\x17\x2f\xa5\x74\x8d\x29\x6b\x29\xcd\xd7\xeb\x81\x21\x48\x3f\xf1\xd9\xfe\x95\x3f\x94\x51\xc7\xc7\xa5\x42\x00\x72\x85\xee\x72\x46\xbc\x0f\xde\xa9\x38\x81\x40\x29\xab\xce\x05\x7a\x0e\xcb\x97\x4b\x12\xd3\x60\xea\xb6\xaf\xd3\x07\x97\xd6\x14\x45\xad\x2b\xac\x7e\x52\xbc\xe4\x34\x63\x15\xf7\x8e\xb8\x75\x42\xd5\x95\x28\xb2\xf6\xc5\x6d\x66\x24\x1c\xb4\x42\x03\x3f\x64\x3d\x3d\x2a\x67\xcb\x63\x7d\x8d\xa9\x5d\x4f\xd1\x23\x4b\x03\x1a\x3e\x51\x72\x3a\x1d\x26\xe6\xf5\xca\x07\x98\x73\x21\xad\x11\xa9\x0f\xcc\x1d\x4e\x2b\x0b\x89\x66\x50\xc3\xa7\x51\x8d\x56\x55\x29\xbe\xa8\x06\xa0\x5d\x44\x7e\x08\xd2\xa6\xa3\xdb\xf1\xa3\x69\x15\xb2\x95\x7c\xa5\xb4\x0e\x58\xb9\x7a\xd0\x36\x97\x35\xc4\x28\xbd\x6d\x69\xbd\x21\x00\x44\xb6\x51\x41\x8d\x98\xb0\x59\xd9\x0c\x83\xe4\x60\x11\xf4\x1c\x03\x2c\x56\x55\xa5\xef\x21\xac\x2c\x8c\x2b\xc9\x4b\xe0\x7e\x45\x42\x6a\x7a\xe5\xd4\x7b\x45\xf2\x7c\xf4\x28\x9c\xa4\xdd\xab\xe0\x8a\x12\xb9\x10\x20\x7d\xab\xb3\x4a\x46\xab\x75\xce\x69\xb5\x8e\x7e\x17\x66\x4b\xf3\x35\x9a\x8f\xb6\x8e\xb0\x32\xc9\xea\xa6\xdf\x87\x38\x29\xf0\xe0\x84\x85\x53\xf7\x32\xe1\xc3\xc0\x84\xb3\x2b\x7a\xf7\x50\x74\xe7\xbb\xaa\x4e\xb5\xd7\xea\xd7\xaf\xf9\x75\x80\x10\x9b\x60\xf4\xc7\x92\xf9\xe2\xa6\x51\x37\xb0\xaa\x48\x17\x5b\x81\x15\xd9\x13\x05\xf4\xc7\x7e\x2d\x08\xe7\xe8\xd7\xe7\x78\x5c\x96\x68\x42\xc2\xe3\x50\xfe\xd4\xf9\xe3\x3b\xf6\xe1\x84\xc5\x50\xb4\xb0\x6e\x95\x74\x14\xed\xf5\x2f\xa0\x79\xe8\x19\x73\x45\x84\x61\xfb\xb9\xb7\xd7\xd3\x4b\xef\x15\x03\x57\xf4\x32\xca\xac\x3a\xe9\xf3\xdc\x96\xeb\x5a\x2d\x12\x3e\x09\xed\xa1\x70\x2e\x1d\x10\x70\x17\x7b\xb2\x20\xc4\x23\xc0\x96\xec\x24\x42\x43\x85\xc6\x79\xbe\x02\xef\x84\xd0\x9e\xd1\x02\xf4\x9c\xad\x3b\x1f\xd6\x70\x67\x9a\x39\x71\x4f\xf1\xd6\xe4\x22\x8d\x8d\x7d\x0e\x19\xed\x0e\xba\x13\x2f\x21\x28\xd4\x7b\xaa\x56\x9a\x8e\xcb\x7b\xd4\x8a\x82\x62\x82\xf9\xcf\xcb\xf6\x0d\xde\xce\xaf\x1d\x02\x13\x2c\x8a\xff\xed\x3a\x03\xd2\x34\x0d\xeb\x78\x7c\xd6\x49\xc5\x1c\x6e\xcb\x9f\xf7\x5d\x7a\x7b\x4e\xf9\xb1\x51\x39\xcf\xea\x27\x62\xab\x18\x61\x51\x97\xa6\xb5\x1f\x6e\x75\xdb\xd0\x45\x73\xa2\x44\x80\x94\xd0\xcd\xeb\x0f\xe4\x58\x58\x83\xff\x9b\x68\x82\x4a\x04\xb8\x3e\xc9\x1c\xf8\x4a\xcd\x6a\x74\x46\xcb\x1f\x5e\xe3\x7d\x5d\xf8\x0f\x17\xcb\x2b\xdc\x3f\x31\x22\xa8\xfa\xf7\x6e\xbd\x06\xcf\xe8\x17"}, -{{0xe6,0xfa,0x10,0xdb,0xb4,0x78,0xe1,0xe3,0x6b,0x35,0xdf,0xeb,0x02,0x50,0xf6,0x3c,0x08,0x51,0x50,0x70,0xae,0x79,0xb2,0x2f,0x04,0x7e,0x27,0x17,0x08,0xd6,0x4f,0x5c,},{0xe0,0x2e,0x1f,0x2b,0xd8,0x79,0x2e,0xf4,0x83,0x48,0x1c,0x6d,0x11,0xf7,0xc7,0xc9,0xdb,0xde,0xec,0xc9,0x85,0x94,0x32,0xe7,0xf2,0x79,0xe9,0xd1,0x73,0xd3,0x11,0x64,},{0xc0,0x3c,0x47,0x03,0x59,0x12,0x7e,0x9d,0xe3,0xaf,0x0e,0x0e,0xd7,0xd3,0xb1,0x9f,0xae,0xe0,0xec,0x14,0x0b,0x79,0xc2,0x99,0xe2,0xcb,0x6d,0xac,0x0a,0x3e,0x7e,0x31,0x41,0x41,0xcc,0x85,0x4b,0x45,0x96,0xce,0x4c,0x51,0xc7,0xb0,0xde,0xc8,0xa5,0xc8,0xcf,0x09,0x36,0x20,0x53,0x61,0xd5,0x36,0x5f,0x4b,0xcc,0x07,0xc4,0x28,0x7c,0x07,},"\xad\x31\x60\x75\x8d\x8c\x08\xa6\x61\x52\x5c\x95\x28\x0a\x37\x18\x87\x49\x69\x85\x9f\x1c\xc9\x18\xe3\x4f\xec\x00\x8a\xcf\x23\xb8\x89\x6e\x8d\x50\xc3\xc0\x51\x23\x31\xdc\x89\x78\x0f\x8b\x10\xfc\x34\x9c\x67\x5c\x4c\xd8\x2a\x5d\xf8\x58\x6b\x43\xc8\x64\x44\x8f\xac\x00\xb8\x47\xb9\xc9\x80\x54\xab\x79\x3f\x63\xc7\x1a\xa5\xe5\x24\x8e\x22\xd0\x69\xbd\x3f\x85\x2a\x3b\x8c\x6e\x2a\xc8\xef\x86\x1d\x90\xbc\xd9\x84\xbf\xca\x87\x58\x3e\x59\xe9\xa7\x46\x8f\x29\xb8\x08\xdc\x2f\xe5\x30\x2a\x98\x9d\x6f\x2e\xcd\xe7\x58\x5c\xd9\xbe\x4e\x4c\x76\x1c\x4d\x4b\x3e\xea\xf4\x69\x9f\x65\x56\xef\x03\x9a\xf2\xb8\x0f\x94\x07\x60\x5a\xc3\x97\x35\x1d\xd8\x55\x95\x58\x44\x95\xba\xa1\x77\xb0\x8c\x88\xd2\xec\x1f\xc4\xe3\x2d\x1c\x0b\x8d\x7e\x7a\xc5\x83\x9d\xfb\x92\x3f\x09\xb3\x23\xe7\x8e\xce\xb7\xe9\x6c\x06\x04\xb0\x1a\x19\xe4\x9c\x9b\xea\xf4\xf2\x5e\xc4\xa8\x4c\x1a\x08\xf2\x38\x0e\xdd\xc3\xa7\xf0\x12\x18\x49\x59\xcc\xd1\x9e\xcb\xba\xc6\x5e\xac\xa1\x55\xce\xe9\xec\xfe\xc1\x1e\x7f\xee\x05\x8e\x17\x4f\xc4\xed\x7c\x67\x9f\x2c\x15\x63\x1d\x4e\x15\x27\xbc\xdb\x0e\x3b\xb0\x81\x5f\xfd\xff\xc0\xc8\x56\xbe\xf0\xdc\x0f\x5c\x82\x37\xf7\x09\x8e\x26\xbd\xb6\x9e\x87\x82\xd1\xca\x51\x11\xec\x3c\x7e\xdb\x42\x5d\xff\x80\x32\x02\x6c\xba\x3d\x2e\x08\x1b\x71\x31\x0d\xb9\xba\xda\xd1\xad\x02\xf1\xec\xcc\x53\x7d\x87\x4c\xd1\x8c\x6b\xb0\x12\x21\xf7\x1e\xe6\x62\x50\xd9\x4c\xf8\xec\xce\xaa\x96\xd3\xc5\x7e\xea\x2b\x0a\x8e\xc7\x24\x29\xd7\x60\x64\x88\xbd\xf1\x9e\xc3\xbb\x16\xe5\x08\x67\xc7\x93\x7d\xef\x09\xfc\x78\x3f\x20\xa2\xa5\xec\x99\x25\x3d\x6b\x24\x0d\xf4\x67\x7d\xd2\xd5\x27\x7b\x01\xc5\xb8\xe5\xbd\x6c\x7d\xf0\x87\x42\x05\xbc\x8c\x2f\xff\xdb\xa1\x31\x46\x74\xd3\x1c\x9b\x2c\x91\x99\x22\x8e\x19\xe0\x42\x18\x34\xc1\x65\x7d\x06\x98\x28\x69\x16\xc7\xe3\x92\xf0\xab\xd5\x54\x5b\x96\x3a\xc1\xff\xa9\x97\x21\x61\x6c\x23\x79\x6f\x85\xc3\x4a\x5c\x66\x4a\xe8\x1d\x16\xb2\x16\xa5\xb0\xcf\x5b\xc6\xb5\xa9\x08\x29\x72\x85\xd6\x16\x44\x12\x8f\x88\x6f\x38\xaf\x9e\xdd\x25\x19\x3d\x7e\xcc\x77\xa7\x99\x94\x27\x8d\xa0\x71\xf5\x44\x95\x93\x7f\xee\xf5\xa5\x19\x57\x52\x7c\x3e\xec\x7c\xb0\xb4\xe8\xaa\x7a\x4e\x85\x6d\xef\xd5\x7d\xd9\x23\x34\x15\x1b\x98\x6a\xa6\x9c\xa6\x92\x60\xd1\xe2\xd7\xb5\x3c\x05\x67\x7e\xe0\xd2\x16\xb2\x8d\x03\x62\x52\xdd\x30\x06\xde\xbe\x1b\x65\x74\xa2\x5e\x6b\x19\xdf\xb4\x8f\xa6\x43\x16\xaf\x8f\xd6\x8d\x78\x93\xb3\x97\xe7\xdb\x57\x80\xab\x27\xbf\x87\x26\xff\xf6\x05\xd3\xb4\x6d\x80\x05\x95\xb4\x62\x4b\xee\x30\x2c\x96\x43\x26\x03\x4b\x52\x34\xd1\x75\xdf\xdc\xc2\xce\x88\x2e\x65\xb3\xd9\x3a\x04\x38\xf6\x92\xe9\x69\x5d\xe1\xf2\x4c\x70\xa7\x9b\xee\xd2\x54\x15\xec\x5a\xae\xcf\x33\x91\x95\x3b\x2f\xfd\x45\x3a\x8f\x04\x67\x56\x1a\x4a\x47\xee\x14\x4a\x43\xfd\xff\x83\xdf\x2b\xea\x5f\x66\xa7\x22\xb5\x2a\xbe\x86\x13\xf2\x0c\x59\x4a\xf0\x98\x2e\xb3\xf0\x45\x05\xa5\x24\x61\xdd\x03\x4d\xa8\x6c\x36\xca\x16\x21\x77\x05\xc0\x48\x23\x91\x1d\x72\xa2\x47\x69\x51\x76\x33\x56\x28\x86\xf2\x50\xf2\xcf\x78\x8b\x8f\x32\x86\x4a\x94\x74\xf5\x7e\x62\xe5\x7d\xe8\xfd\xaf\x95\x9a\x6b\x72\x28\x74\x40\xa8"}, -{{0x05,0x8e,0x36,0x80,0xb8,0xfc,0xc0,0xaa,0x14,0x90,0x08,0x9c,0x11,0x24,0x67,0x7f,0x98,0xd7,0x4b,0x1b,0xfb,0x71,0xee,0x86,0x63,0xf0,0x25,0xf0,0xd9,0x46,0xcd,0x20,},{0xec,0x72,0xce,0x0e,0x82,0xc6,0xa3,0xb2,0x12,0x43,0xd2,0xf0,0x0e,0x9e,0x88,0x3a,0xdb,0xc5,0xcb,0x63,0xb3,0xd9,0x36,0xef,0xa5,0x0c,0x07,0xcb,0x92,0x91,0x48,0xe2,},{0x57,0x34,0xec,0x50,0xa7,0xf8,0x2e,0x48,0x53,0x6b,0xdc,0x43,0x70,0xcf,0xef,0x2e,0x15,0x0a,0x63,0x1d,0xab,0xaf,0x89,0xed,0xcf,0x0f,0xda,0xbe,0x4f,0x58,0x39,0xf4,0xf5,0xfb,0xd8,0xdf,0x8e,0xc4,0xa3,0xac,0xd4,0x0a,0x8b,0xfb,0x96,0x3d,0x18,0x55,0xff,0x92,0x74,0xdb,0xc3,0x31,0x65,0xb5,0xe6,0xd3,0x7a,0x23,0x9d,0xac,0xe9,0x03,},"\xe6\x3d\x14\xf5\xbe\xa7\xa1\xab\xb8\xfe\xe6\x97\x74\x6c\x22\x80\xdf\xd0\x62\x2d\xe7\x35\x72\x26\xcc\x07\x42\x72\x2a\x32\x29\xbe\x12\x6b\x08\x3e\x86\x8a\xea\xf0\x7d\x2f\xc9\x7a\xdc\x33\x42\x70\x96\x74\x19\x3c\xa2\x81\x74\x4e\x85\x0e\xa1\x54\x40\x05\x0a\xec\x93\x0e\x45\xd7\xa8\x7b\x8a\xc8\x01\x5c\x89\x67\xc2\x00\x33\xa5\x32\xd2\x95\x91\xb1\x35\x58\x6c\xe0\xfd\xd2\xe6\x68\xb5\xc8\x64\xb3\xbd\xe7\x0c\x7e\x71\x9a\xd2\x41\x93\x12\x51\x86\x19\x33\xff\xbf\xa9\x64\x83\xff\x82\x85\x67\x48\xc5\x6d\xc2\x6e\x25\x7d\x69\x2e\x51\x34\xd8\x2f\xc7\x19\x1c\x11\x0d\x95\x90\xd3\xfc\x75\x1c\xd6\x36\xb0\xc4\x6f\x44\xf8\x80\x3e\x59\xe2\xf9\x3f\xa0\xcb\xe2\x47\xa1\xa6\x25\xb4\xbc\x2c\x7b\x1f\xdc\xeb\x5a\x2b\x22\x59\x1f\xa6\x13\x7c\x54\x04\xdf\xec\x6a\x69\x63\x9e\x3f\x63\x2b\x59\x76\xab\x9f\xe1\xc6\x3a\xa3\xda\x9d\x52\xb0\x44\x00\x8f\x3a\xe4\x4b\x7c\x36\x4f\x08\x56\x64\x32\x3a\x88\xeb\x45\x83\xe8\x71\x40\xf7\x63\x78\x2b\xff\x88\x19\xcf\x74\x1a\x87\x5d\x50\x6c\x92\x9d\x34\xbb\xd4\x30\x07\xde\x4b\x18\xf6\x87\xa7\x58\x11\x11\x28\xb1\xdb\x86\xfc\x5a\xd2\xfb\x9f\xca\xd1\x2c\x9d\xd2\x8f\xee\x5a\xd1\x0d\xe0\x73\x9f\x8e\xfd\x9b\xff\x66\xf8\x40\xb1\x1b\x3f\x91\xc5\xe0\x7c\x21\x45\x2c\xab\x24\x24\x2b\x6e\x32\x16\x5c\xd1\xe6\x95\x72\xbf\x21\x6e\x86\x04\x53\xda\xd2\xfd\x12\x9c\x33\x37\x58\x58\x0b\xb7\xd0\xf1\x95\x09\x74\x5e\x85\x14\x63\xd1\x27\xa5\xf9\xbe\x21\xfe\x54\x9c\xae\x55\xd5\x6b\x8b\xea\x80\xbf\xaf\xda\xc1\x0a\xcd\x83\x8e\xa8\xaf\x31\xc0\x07\xdc\x32\xbf\xd7\x40\x82\xd9\x11\x0a\x3e\x91\xe6\x1e\x03\x57\x58\x7e\x4e\xd3\x28\x27\xad\xe9\xb6\x91\x0a\x98\x8c\x1d\x3b\x2d\xd2\x2c\x0e\xe7\x6e\xf3\x5f\xe1\x5e\x09\x94\x04\xa4\x5d\x4b\x2a\xca\xb9\x12\x3e\xcc\x45\x55\x0a\x40\xfa\xf8\x33\x6b\x46\xc6\x30\xa9\x08\x03\x58\xff\x8b\x8e\x58\xaf\x0b\xcc\xbd\x35\x01\x0c\x1e\xcc\x12\x81\x66\x55\xa5\xec\xeb\xa9\x5a\xd3\xf5\x03\xa1\x8e\xc5\xbe\xce\x3a\x33\xf4\x69\xdf\xe9\x17\xe1\xc5\x5e\xf1\xd8\x1e\x5a\x75\x56\x1e\x6b\xbd\x99\xc6\x53\xa6\xd0\x95\xb9\xf3\x87\x91\x1e\x40\x33\x2f\x62\x16\xf9\x56\xa3\x5c\xf7\xd9\x9a\x9f\xdd\x0c\x44\xc5\x1e\x90\xa5\x64\xf1\xc3\x6b\xf3\xd4\x0a\x7f\xaf\x4b\xa2\x8b\x1a\x12\x0b\x32\x05\xfb\xac\x1a\x98\x56\x92\x90\xbe\x37\xc5\x8b\xbd\x74\x5c\xe0\xfb\x74\x83\x52\x70\xab\xa2\x25\x2a\xda\xec\x15\x7d\xc4\x24\x61\x22\x1a\x2c\xff\x68\x7b\x9e\x65\xce\xb5\x7c\x2d\x77\x70\x0a\xea\x63\x20\x48\x6c\x5b\x1b\xec\x9c\xc5\x3e\x7e\xf9\xe4\x8f\xcd\x1b\x77\x83\xac\xbe\x75\xa6\xbe\x02\x67\x27\x88\x12\xdb\xf3\xd2\x57\x6c\xf7\xad\x39\x11\x27\x1a\xce\xbe\x0f\x2c\x04\x60\x2a\x08\x0c\x8b\x96\xc1\x20\xfd\x86\xfd\xa2\x82\xaa\x4e\x1c\x13\x1f\xe9\x7c\x90\x7c\x15\x85\x5f\x87\x75\x5f\x51\x1c\x03\x7b\xef\xad\x0f\x56\xb3\x9f\x32\xa2\x13\x3a\x22\xf3\xd5\xa9\xbe\xc3\x44\x3f\x29\xa6\x94\xe9\x7f\xe0\x5e\x10\xfb\x8e\xf9\x99\x13\x02\xb9\xe0\xd8\x4d\x92\x9a\x19\xeb\x03\x47\x1f\x3a\x86\x13\xd3\x93\x68\xe1\x58\x83\xa7\xe4\x97\x0b\x53\xcb\xaf\x29\x29\xd8\xde\x43\x1b\x48\xb4\x35\xd7\x53\x3c\xaa\x2e\x36\xce\xab\x6c\xdd\xb3\x46\xe5\x35\xe5\x15\xc4\xb3\xdb\x76\xde\x07\xd9\x85\x54\x14"}, -{{0x51,0xba,0x3a,0x4f,0x3d,0x85,0xd1,0x54,0x8c,0x2f,0x24,0x94,0xa3,0x51,0x1f,0x3b,0x95,0x15,0x66,0x3d,0x7e,0x85,0x37,0x0f,0xb6,0x15,0x02,0x37,0xe9,0xbc,0x98,0x0b,},{0x77,0x49,0xde,0x02,0x10,0xbc,0xe0,0x6d,0x48,0xf5,0x9b,0x95,0xae,0xb1,0x52,0x8f,0xd9,0xb4,0xe5,0x2c,0xdd,0xe2,0x2f,0xb8,0x19,0x3b,0xed,0xd5,0xdf,0x12,0x81,0x7c,},{0x16,0xfb,0x29,0x0c,0x91,0x3b,0x20,0xeb,0x1c,0x3d,0x7b,0x79,0x82,0x49,0xeb,0x84,0x59,0xd4,0xbe,0xe8,0x12,0x5d,0xb2,0xb3,0xf1,0xda,0xab,0x8a,0xf9,0xd9,0xa7,0x00,0xed,0x79,0x8a,0xdd,0xd8,0x02,0xdf,0xcd,0x29,0x7a,0x41,0x25,0x93,0xcd,0xa7,0xbe,0x99,0x79,0xa1,0xf0,0x93,0x50,0xe8,0x6f,0x69,0x8a,0xc3,0x38,0x0e,0x34,0x1d,0x07,},"\xd1\x8d\x0c\xbf\xc1\x6d\x0f\x9b\x67\xf2\x53\x9a\xd6\x20\x7c\xd9\x21\x7a\xd5\xed\x03\x33\xcd\xdb\x10\x41\xe0\xac\x2b\xdd\x92\x02\x76\x62\x96\x52\xb4\x9c\xbc\x98\x02\x59\x3e\xc3\x64\xea\x79\x5a\xbc\xd1\x58\x20\x85\xf5\x5b\xc6\x6c\x48\xfd\x3e\xed\xe6\x18\xd6\x36\x96\x17\x10\x0e\xae\xcc\xc1\x5f\x24\x9d\x6e\xee\x5b\xb2\xc4\x3c\x01\xb0\x62\x3f\xe6\x03\xce\xee\xe4\x9b\x40\xfb\x7c\x53\xfc\x68\x47\x36\x73\xc0\x9b\x1a\xc7\x7e\xa9\xbe\xb7\xe8\x53\x03\x79\xa8\x6d\x69\xec\xd1\xff\x11\x81\x3f\xbb\x88\xf6\x92\xf0\x5e\xf1\x32\x07\x42\xb4\xfe\x7e\x06\xd5\xba\x71\x65\x66\x46\xcd\x75\x00\xde\x19\xbb\x93\xd8\x44\x53\x66\x03\xf4\x0b\xd4\xae\xea\xf0\xc4\xdb\xc0\xac\xfd\x20\x2b\x28\x6b\x64\xaf\xb8\x3d\x4a\x37\x8d\xd4\x5e\xe3\xc1\xdf\x6b\x3e\xf1\x6b\x8b\x1a\xcc\xbc\x04\x06\x32\x50\xec\x47\xb8\x6a\xe5\xa7\x1d\x1d\xab\x38\xb5\xeb\x80\xd6\x63\xfa\xa7\x88\xf8\xb5\x9a\x75\x4c\x0f\x9c\x9f\x6d\x90\x62\x52\xaf\x46\xab\x1f\xff\xed\x27\x6d\x23\x88\xdb\xe7\x0d\x96\xba\x67\x47\xd1\xfe\xd4\xfc\x0b\x55\x29\x3d\x5f\x78\x7b\xda\x0c\x0d\xf4\x6a\x73\xf4\xaa\x7d\x29\xe1\xc9\xcc\x85\xcd\x04\x3e\x3d\xff\xe0\x57\x46\x2c\xa5\xfe\x5c\x64\x70\xe7\x39\x27\x6f\x8b\x53\x4c\x01\x72\xe4\x60\xf3\x40\x48\x7a\x56\x94\x68\xaa\x58\x90\xcc\x14\xf2\x0d\x67\xd7\x9c\x66\x1e\x87\xfe\xba\xc6\x27\x59\x71\xc3\x73\x08\x07\xeb\xf1\x75\xe0\xde\x10\x49\xbe\xe6\x7c\x89\x5e\x57\xb7\x1a\xb8\xa2\xf3\xcf\x36\x41\xfd\x54\x8d\x09\x41\x4f\x5f\xc3\x02\x6a\x0a\x35\xf6\xba\x95\x16\x73\x94\x49\x41\xcb\x23\x6f\x3d\x19\x76\xdc\x69\x07\x7d\x95\x14\x50\xe7\x66\x03\x16\x98\x8f\x6f\x2a\x6f\xbb\xff\x3b\x37\xce\xaa\x02\xfd\x6f\x02\x73\xbd\x80\x31\x85\xa1\x09\x03\x9c\x63\xf2\x51\x9b\x98\x3d\xaf\x65\x54\x25\x3b\xed\x54\x97\xc0\xb0\xbd\xaa\x0b\xd4\xa1\xfa\xc9\x00\x26\xad\xe3\xe4\x0c\x55\x4c\xff\x2c\xcb\x36\x99\x0e\x71\x55\x67\x08\xc5\xc4\x03\x92\x56\xff\xc7\x33\x7e\x5f\xea\x11\xf5\xe9\x0d\x3e\x4d\x93\x35\x91\x79\x11\x6a\x85\xc2\x41\x36\xca\x34\x83\x5c\xd3\x40\x12\xe4\xd7\xdd\xc7\xb7\x21\xc2\x46\xc7\x37\x00\xe2\x76\xdc\x2f\xf9\xf2\x77\x0b\x43\xc8\xe8\x0a\x17\xf0\x1d\x32\x68\x0b\xae\x22\x8e\x64\x23\xa8\x80\xc3\xfb\x99\x6a\xb8\xd2\x21\xbc\x62\x74\xac\x5f\xa7\x70\xd2\x05\xfc\x87\x8f\xba\x9b\xbd\x77\x6a\x3d\x79\xed\x77\x04\x89\x50\xf3\x6d\xc0\xaa\x3c\xcd\x28\xe4\x75\x6a\x99\x19\x04\xae\x05\x1b\x8a\x4b\x7d\xe3\xa1\xf2\xad\x0f\xb4\x5a\x33\xd0\xc6\x82\x25\x84\x1f\x8e\xb6\x5b\x6a\x16\xe9\x5f\x89\x35\x91\xe1\xaa\x73\xa6\x4f\x0d\x2e\xe9\x38\xab\x69\xad\xcc\x8c\x59\x51\x8b\xec\x50\x1c\x39\xf1\x39\x17\x4b\xbb\x00\x69\x9e\x1a\x0f\x0e\x0d\x88\x9a\xae\x54\x3a\x55\xe6\xac\x56\xd5\x20\x4c\x1a\xde\x1f\x27\xd8\x2a\x6a\x95\xe1\x4b\x2d\x69\x09\xdd\xa7\xbf\xaa\x7f\x48\x7f\xb6\x19\x59\x01\x4b\x78\x79\x5c\xb4\x63\x9f\x09\xf0\xd3\x29\xfe\xb3\x5c\xcf\x52\xed\xc2\xdb\x72\x19\x14\xe4\x23\x30\x68\x89\xa4\x83\xfe\xe8\x76\x36\x0e\xe3\x26\x33\x53\x19\x07\x0c\x56\x4f\x3a\x8b\x95\x3f\x52\xf4\x15\x13\xa2\x26\x08\x83\xc3\x8d\xd9\x78\xa2\x48\x60\x4a\x41\xbd\x4b\xfc\x9e\x84\x18\x4d\xc9\xe8\x4d\x25\x89\xf4\xaf\xff\x84\x17\x82\x4c\xe5\xad\xba"}, -{{0x7d,0xde,0xc5,0x26,0xa4,0x97,0x1d,0x89,0x12,0xa6,0xbd,0x43,0xc6,0x9f,0x92,0xed,0x86,0x44,0x2b,0x15,0xf4,0x2f,0xba,0xbb,0xf2,0xd1,0x7e,0xff,0x98,0x99,0x31,0x61,},{0x0d,0xfe,0xff,0xb2,0x76,0x23,0x09,0xb4,0x73,0x4e,0x4c,0xe2,0x52,0x3c,0xf1,0x86,0x31,0x49,0xf7,0xe1,0x9a,0x7c,0x14,0x7e,0xc0,0x89,0x9e,0x11,0x0c,0xa9,0xd8,0x7d,},{0x9e,0x60,0x3b,0x01,0x5f,0x42,0x87,0x1b,0x78,0xeb,0x27,0x52,0x3f,0xbb,0x7c,0xe9,0x62,0xfc,0xa3,0x2a,0xe2,0x70,0xe8,0xe1,0x2d,0xca,0xdd,0x25,0xaa,0x85,0x2b,0x89,0x1f,0x6f,0xef,0x77,0xb5,0x9a,0x54,0x6c,0x9a,0x7a,0x7c,0xac,0xb5,0x5e,0x1d,0x32,0xad,0xc8,0x05,0xae,0x5f,0x61,0xa6,0x9e,0x67,0x64,0xc7,0xc0,0x82,0x92,0xeb,0x03,},"\xe8\x77\x4a\x45\xd4\xd8\xf8\x6d\xda\x5c\x08\x80\x2b\xa2\x47\x2e\xf3\xc8\xd3\x6c\x7f\x38\x3a\xc0\x46\x12\xa4\x64\x38\x2e\x9d\x6c\x07\xd8\xd3\x58\x22\xc5\x3f\x43\x88\xf5\x15\x36\x14\xfe\xfa\xf4\x63\x74\x74\x7b\x9d\x4f\xd4\x46\xa8\x64\x76\x9a\x4c\xad\xe8\x43\xc1\xea\xb8\x57\x43\x19\x11\x2f\x01\x79\xd2\xea\x9e\x3c\x19\x5d\xc0\x68\xf0\x69\x74\x62\xb9\xe0\x7c\x87\x94\x87\x0f\x8f\xb8\xff\xc0\x81\xe4\x58\x6a\xfb\xcd\xba\x7a\x4f\x59\x25\xe9\xfd\x9e\xc9\x42\xd8\x43\x47\x33\xc2\xdd\xd5\xe2\x9b\xbd\xfc\x73\x42\xb9\x28\x68\x71\x9b\x54\x40\x88\xa4\x8e\xba\x4c\x82\xf1\x87\xdd\xca\x8f\x47\x46\x25\xa7\x1c\xf6\xb7\xaa\x5f\x08\x1c\x74\xf7\x40\x8f\x53\xb7\x81\x63\x6e\x7e\x9d\x29\xb0\x7f\xdb\x6d\x9c\x35\xe5\xeb\x38\x2d\xb7\xa3\x1a\x8b\xa5\x16\x91\x5d\xf8\xde\xe9\xe1\xad\x3f\x18\x28\x43\x68\x3e\x8d\x1d\xc5\xd8\x66\x9d\xbf\xcf\x09\x54\x1a\x43\xc0\xa0\x46\x13\x38\x1a\x5b\x5e\x4e\x71\xb2\x3c\x5a\xd0\x9b\x8e\xaa\x51\xcb\x93\x8d\x0c\x75\x2c\xc3\xd3\xa1\x0f\x10\xb4\x2b\xe8\xee\x7f\x6b\xda\xc8\x07\x85\x68\x43\x49\x46\xbb\xf5\x6d\xa7\x0e\x7d\x54\x15\x7a\x6e\xfd\x48\x46\xeb\x15\x52\x78\xc9\x4c\x38\x88\x65\x8a\x7a\x2f\x8e\xa3\xba\xc1\x47\xaa\x89\x16\x92\xae\x8b\x23\xf1\xaf\xe7\x1e\xcf\xde\xca\xa6\xc1\x13\xb5\xca\xaa\xa1\x93\x98\xc7\xdf\xe7\x3f\xac\xb4\x15\x5f\xd6\xba\xc1\x8d\x5d\xf2\x12\x9e\x8b\x29\x07\xec\xee\x15\x1b\xdd\x14\x7a\x7c\x3e\x46\xea\x72\x75\x4d\xe3\x2c\xeb\x06\x6d\x9d\xb1\xc2\x6e\x80\xdf\x36\x31\x29\x2b\x16\x17\x4c\xfa\x6f\x1d\x9c\x08\x28\xb8\x49\xc2\x2d\x29\x65\x1a\x73\xe9\x10\xd9\x27\x58\x77\xf4\x64\xce\x93\x26\xc6\xe4\xed\x6b\x07\xdc\xb3\xa3\x53\x63\xc1\xaa\x64\x72\xe0\x2c\x5c\xd8\x55\xe3\x8a\xab\xe9\x65\xac\xe9\xf3\xf5\xa4\xf5\xde\x03\x00\x86\x94\xcb\x90\xaf\xe4\x16\xc9\xd4\x86\x88\xde\x7f\x75\xcf\xe2\x43\xff\x7f\x41\xe0\x59\x31\x09\x34\x90\x3d\xb5\x68\x84\x45\x08\x26\x2c\x89\x9d\xfa\x75\x0c\xd6\xa2\x82\x98\x24\xba\x02\x7a\xea\x1b\x6d\x01\x77\x72\x6a\x34\x3a\xdd\x4e\xcd\xc5\xf7\xe6\xe9\x09\xab\x7d\xe6\x15\xef\x28\x07\xf9\xe7\xd7\x1c\xe2\xf7\x8a\xcf\xf5\x7e\xba\x79\xc3\xf5\xe0\x7c\x8b\x66\x1c\x1e\x30\x27\xf8\x17\x6d\x28\xbf\xef\x76\x7d\xd6\x8d\x4e\x5d\x62\x8f\xec\x0b\xfe\x88\x79\x93\x41\xf3\x06\x12\x87\x34\xfa\xd2\x02\xaa\xfc\x9f\x11\x12\x3f\xb3\xe3\x63\xd1\x0a\xee\x0d\xb5\xe2\x7a\x15\x70\xdf\xae\xe4\x7e\x24\xda\x47\x3b\x07\xfe\xe5\x9a\x6c\x93\xf0\x98\x1d\xbe\x32\x5c\xd8\xcc\x2d\x2e\xd7\xdc\x17\x16\x6b\x26\x7c\x1b\x11\x05\x36\xf2\x63\x6b\xba\x34\x75\x1a\x78\xf7\xf6\x29\x81\x82\x44\x2d\x83\xc1\x23\xbb\xee\x4f\x50\xc5\xb0\xfa\xcf\xf0\x3e\x7c\x55\x6e\xd9\xe6\x4c\xa2\x7c\x4b\xca\x5a\xb0\xde\x0d\x5f\x9c\x2c\xbb\x54\xcc\x2d\x94\x73\xa3\x2d\xf9\x99\x39\x0a\xc2\xff\xee\xd3\xd4\xcb\xa3\x49\x73\xdc\xec\x3f\xba\xba\xfc\x4d\x54\xca\xe4\xe7\xe8\x5d\x4a\x6e\x8a\xfe\x45\xca\xcd\x71\xe0\xf2\xe6\xd0\x4b\x4f\x9d\x3b\xcf\x43\xd3\xfa\x41\xe9\x98\xcc\xbe\xd0\xf1\x50\xd5\xca\x1d\x52\x72\x93\x2d\x93\xec\xa1\x04\x95\xc6\x83\x34\xfa\x32\x68\xf3\x1d\xe5\x22\xcb\x12\xa7\x44\x9f\xfb\x5c\xb5\xe8\xf1\x46\x2c\xd9\xb5\x17\x70\xcc\xaf\x58\xb1\xe0\xd8\x2e\xf9\x29"}, -{{0x0b,0x65,0x90,0xdd,0x7c,0x2f,0x15,0xf9,0x4a,0x56,0xe2,0x40,0x16,0x93,0x63,0xc2,0x67,0x32,0x30,0x2b,0x9d,0x44,0x0b,0x53,0x27,0x23,0x00,0x2e,0x15,0x5d,0x02,0xd9,},{0xcd,0x18,0xe0,0x32,0x57,0x7c,0x55,0x76,0xf2,0x23,0xf3,0xe3,0xd8,0xa1,0xfa,0x8e,0x9a,0x87,0x0f,0xef,0x09,0xe9,0x40,0x9f,0xaf,0x40,0xd7,0x14,0x3e,0x52,0xfc,0x44,},{0x64,0x2d,0x81,0xac,0xf3,0x8c,0xf0,0x99,0xa8,0x33,0xa7,0x4f,0x2d,0x80,0xb8,0x54,0x48,0xec,0x2b,0x1a,0x5d,0xdc,0x64,0x47,0x0b,0x21,0x3d,0x54,0xb7,0xbe,0x61,0x33,0x68,0x9a,0x71,0x94,0xf5,0xd8,0x97,0x92,0xe1,0x6e,0x5d,0xf7,0x55,0xa4,0xfd,0x9e,0xf4,0x68,0x9e,0xa9,0x52,0x92,0x6e,0x0e,0x4e,0xcb,0x3b,0xd4,0x81,0xfd,0x91,0x02,},"\x71\xfe\x0f\xd5\x5d\x5e\xd1\x20\x6f\x28\xee\x16\xe4\x19\xfa\xb6\xfa\x66\xa2\x51\xfa\x6b\x06\x01\xda\x26\x1e\x42\x9f\x55\xb8\xd5\xae\x3f\x3c\x52\xa1\x7f\xe1\xec\x73\x4b\x81\x0a\xb6\x3a\xad\xe4\x44\x70\x39\xca\x0a\xe4\x68\x7c\x24\x35\xf5\x61\xe4\x6c\x5b\x30\x97\x17\xab\x31\xe0\xf6\x40\x76\xb2\x16\x92\x11\x57\x2b\x74\xe1\x8a\x1f\x45\x25\xa6\x4f\xa7\x17\xa5\xed\xf1\x49\x75\x81\x29\xcb\x04\x03\x5e\x7e\x20\xba\x40\x05\xb7\x48\x09\xde\xc6\x44\x50\x4c\x24\x54\xa7\x7f\x99\xb2\x0c\x53\x74\xf3\xce\xe7\xd8\xc6\xb6\x8b\x24\x3c\xaf\xb3\x00\x98\xdc\xe9\x04\x90\xfd\xc3\xb9\x2f\x54\x94\x8f\x42\x46\x39\xe1\x9f\x8f\x20\x20\xd1\x55\x13\xda\xef\xad\xd9\xe9\xb1\x2a\x84\x76\x1e\x5e\xce\xa0\x88\xad\x56\x1f\x06\x20\x9f\xd4\x42\x3f\xcd\x00\x3f\xbc\xd1\x87\x3e\xa5\x49\x63\xa2\xfa\x07\xc7\x47\x6b\x13\x88\xf9\x01\x5d\x9e\xac\x30\x5b\xea\x5a\x3d\xe1\x94\xf5\x5a\x17\xb4\x2d\x59\x9e\x5c\xe6\x2c\x8b\x7c\x19\xe7\xe7\x09\x61\x37\xb9\xd0\xa6\x5e\x63\xc1\xa3\xb8\x45\x38\xca\x65\x36\x9a\x20\xe8\x82\x2f\xff\x5e\xcb\x57\xfc\x09\xb4\xe6\x84\x5b\x4f\x24\xd4\x88\x69\x71\xac\x1a\xc2\x8c\x77\x58\x0e\xa5\x67\x2a\xd1\x4c\xe4\x44\x17\x19\xc2\x14\x54\x6d\x07\x36\xcb\x7a\xd0\xbd\x9f\xb5\xb2\x6c\x6d\x9c\x53\x6b\xf8\xc8\x57\xae\x42\x57\x7b\x36\x34\x1d\x39\x2b\x43\x32\x3b\xda\xe7\xdf\xaa\x49\x19\x86\x87\x2a\x23\xd8\x27\xc6\xef\x8b\x57\xe7\xd0\x0f\xea\xe3\x83\x4c\x46\x64\x00\xaa\xd1\xd3\x67\x82\x39\x84\xaa\x02\xd2\xef\x49\x29\x14\xae\x11\x27\xe7\x55\x1b\x81\x25\x59\x37\x83\x05\xe4\xfd\x52\xd8\xbc\x7e\x41\x57\xec\xca\x45\x1f\x43\xee\x9f\x54\xc8\x21\x53\xc7\xdb\xfa\xf7\xec\x35\x23\x87\x73\x05\x1b\x4e\x58\x7d\xb1\x36\x95\x7e\xc5\x71\x38\x2b\x90\x59\x0b\x5d\x10\x26\x02\x45\x80\x96\x6b\x72\x52\xd2\xcd\x3f\x4f\x16\x25\xc4\x85\xba\x90\x6b\xff\x17\x59\x92\x18\x89\x78\xf2\xd6\x27\x4f\x3a\x03\x17\x49\xba\x7e\x70\x2f\x56\x54\x7e\xdc\x96\xec\x26\x7b\x84\x89\x28\x80\xd7\x50\xd7\x31\x0e\xbf\x6d\xb2\x41\x25\x3c\xab\xe4\xb2\x5a\x97\x74\x58\xc6\xff\xc9\xe3\x53\xe6\x2a\xdf\x05\xe6\xef\xc0\xfc\x1e\xbe\x89\xf5\x27\x70\x5b\xcc\x26\xb7\x01\x28\x56\x10\xd9\x8a\xa3\xbf\x23\x87\x2b\x69\x96\xd3\xde\x48\x0e\x8d\x09\xd7\x83\xc4\xa0\x8c\xd3\x83\xc9\x01\x26\x35\xaa\x68\x97\x8b\x50\x06\x81\x8b\xbd\xe4\x4f\x29\x87\x47\x9b\xcb\x2b\x71\x1c\x1b\xee\xed\x27\xcf\x09\x97\x0a\x16\x4e\x45\x4f\x71\x08\x22\xee\xf5\x55\xc1\xc7\xbf\x9f\x76\xd5\x25\x4c\xe2\x20\xc9\xaa\xa7\x16\x84\x7a\x24\x94\x88\xf9\xcd\xb4\x4c\x48\xf4\x52\xab\x52\xc4\x0f\x6d\x03\xad\xc8\xbf\x3f\x19\x7b\x25\xe3\xd1\x27\x83\x0e\x74\xfd\x81\xeb\x14\xf7\x54\x20\x5b\x3a\x48\x44\xc5\x96\xb6\xe3\xa9\x93\x6a\xd6\xfd\x9e\x80\xa1\x63\x20\xb3\x81\xc3\xff\xc7\xb6\x9e\xab\x54\x53\x6f\x55\xab\xe2\x2c\x91\xd8\x98\x40\x8e\x88\x0c\x6d\xbf\x0f\xa5\x64\x8d\x51\x77\x72\xca\xa5\x35\x3b\x25\xdb\x60\x50\xd7\x53\xfa\xf1\x98\xec\x1d\x37\x5d\xe0\xfa\x72\x18\x0a\x93\xba\xb0\x3d\xed\x77\x16\xcb\x87\x50\x5b\x68\xac\x6a\x35\xe7\x3d\x0f\xcf\x34\x45\x7e\xff\x82\x17\x89\x52\x14\x2c\x7b\xac\x9d\xfd\x87\x2a\x9a\x82\xf8\x5b\x24\xb8\x8f\xa4\x2d\x4b\xe0\xa0\xca\x0b\x2c\x70\xf4\xc6\x22"}, -{{0xc6,0xd9,0xac,0xc5,0x17,0x5f,0xa2,0xb8,0x96,0x5c,0x15,0x8c,0x56,0xba,0x0a,0x5a,0x66,0x6a,0xd2,0xc7,0x40,0xcd,0x5b,0xb6,0x79,0xbb,0xa9,0xb1,0xdc,0x50,0x92,0x84,},{0xf5,0xcf,0xca,0x21,0x1b,0x02,0xfb,0xa7,0x72,0x03,0x47,0x70,0x3b,0xf1,0x63,0x1c,0xb3,0x08,0xfa,0xbc,0xda,0xa6,0x74,0x29,0x52,0x7c,0x5b,0x7b,0x67,0x6d,0xba,0xef,},{0x4d,0x2c,0xe7,0x07,0x09,0x0b,0x0f,0x3f,0x41,0x46,0x2f,0xd7,0x5b,0xd6,0x09,0xa2,0x72,0x4f,0xad,0xfe,0x5c,0xa3,0x90,0xe3,0x13,0xa4,0x2c,0xab,0x42,0x86,0x8e,0xd6,0xe9,0xa8,0x91,0x4d,0xc1,0x39,0x09,0xc0,0xd6,0xf6,0x1e,0x63,0x71,0x29,0x57,0xc7,0x6f,0x3b,0xd8,0xb7,0xf5,0x53,0x49,0x71,0x5a,0x3a,0x31,0x75,0x15,0xc0,0x71,0x08,},"\xf2\x45\x10\x0c\xd2\xd3\x16\x48\xf5\xf3\x51\xbd\xa5\x64\xc9\xdb\x4a\x35\x82\x0c\xc3\x0e\xf6\x51\x33\x7c\x4c\xd8\x88\x07\x05\x69\xd1\x17\xa9\x34\xb9\xc9\x18\xe5\xdf\x8b\x37\x44\xdd\x66\x20\xcc\xbc\x49\xf6\xb3\xe5\x78\x2a\x30\x33\x9d\xbb\x9c\xbe\xd0\x5d\xd2\xb3\xb8\xc5\xbf\x15\x46\xe7\x0a\xf6\x36\xe6\x61\x5c\x48\xb2\xc3\xc2\xd1\x9f\xe3\x54\x20\xdf\x53\x14\xf6\x3c\x48\x12\xb5\x8e\x82\xa2\xa6\x0b\x18\x02\xf3\x8e\x50\x5c\xe7\x48\x01\x7a\xfa\x97\x7d\x3f\x9b\x1b\x6b\xea\x21\x92\xac\xec\x73\xbd\xce\x12\xd6\x5e\x68\x4d\xa4\xd8\xb4\x1f\xa9\xa8\x6f\x11\x08\x6e\xdc\x2d\x52\x96\xf6\x7e\xfc\x53\xac\x84\x07\x0f\xde\x13\x69\x3e\xb2\x31\x8f\x5a\x8c\x3b\x11\x7c\x23\x34\x22\xad\xcd\xd3\x52\xf3\x28\xf0\xec\x69\x9a\x46\x50\xc9\x3f\x9b\x4a\x7d\x79\x5d\x7f\xc2\x62\x2a\x03\xd9\x9b\x64\xf7\xb3\xdc\x31\x94\xf6\xc3\xb1\xb6\x9d\x99\x07\xce\x09\x24\x01\x07\x3f\x47\xa2\x8f\x47\x99\xd2\x29\x09\x2a\x1b\x07\x41\x29\x95\x4b\xe8\x0c\xa4\xa3\xe6\x58\x2e\xe0\x5c\x30\x2c\xac\xb7\x43\x1d\x1c\xa6\xa4\x51\xaa\xed\x72\x78\xab\xc7\xf7\x85\x75\x24\x1c\x2a\x2e\xea\x2e\x84\xcb\xf9\xa3\x34\xdf\x40\x21\x09\xc0\x28\xe3\x45\x47\x3a\x13\xaf\x9b\x00\x8e\x20\xbc\x8c\xf0\xbc\xef\xbb\x7a\xa7\x27\xec\x85\x6e\x99\x25\xb4\xdd\xd9\x9d\xeb\xa8\xf2\x52\x91\x1a\x59\x01\x54\xb5\x79\xa8\xaa\xa3\x1f\x07\xdd\x50\x25\xdf\x5c\xd8\xa0\x9f\x74\x29\x64\xcc\x8c\x36\x5d\x8a\xff\x4e\xb1\xd7\x9f\x6e\x5a\x07\xda\xc5\xf4\xed\xe9\x2b\x4e\x2e\x61\xd3\x4c\xc2\xd4\xf0\xaa\xaa\xb0\x37\xad\x5f\xdb\x95\xde\x6c\xd5\x98\x4e\xba\xf7\xcc\xe7\xf0\x8d\x0c\xa0\xdb\xbe\x48\x3c\xe3\xcb\x35\xcd\x79\x0c\xa0\x42\x70\x65\xa3\x4d\xf7\xf4\xc2\xaf\x86\xef\xe9\xb7\x65\x71\x3a\xff\x25\x7f\x5c\x1d\x54\x70\x95\x27\xad\x18\xac\x33\xab\xcd\xee\xdb\x20\x80\x64\xeb\xae\xa4\x83\x5b\xe4\x94\x2b\x8f\xc6\x66\xad\x1b\x79\xb6\x65\x13\x09\xe5\xea\x1d\xa3\x02\xd7\xfb\xa2\xe9\x9f\x0e\x63\x19\xe8\x2b\x99\x05\xa1\xea\x48\x2b\xa0\x43\xb6\x80\x0b\x33\x0d\xc4\x8b\x33\x13\xf5\x9b\xb2\xf9\xe8\xa7\xf0\x7e\xb1\x80\x0a\x70\x27\x45\xdb\x14\xc6\x29\x9a\x98\x2d\xad\x89\x79\x54\x44\x5b\x7d\x98\xeb\x58\x37\xfd\x70\xbf\x19\x0c\x64\x95\x52\xc8\xe8\x6f\xeb\x7f\xf5\xb3\xed\x8e\x0a\x06\x70\x4d\x45\x53\xa3\xc2\xdd\x74\xf1\x8e\xa8\x23\x3a\xe0\xa5\x0d\x91\x4f\xe0\x8f\xbc\xd3\xa1\x43\x5f\xed\x56\xa9\xf3\xa7\xef\xfa\x14\x0f\xb5\x52\xdd\xd2\x1d\xff\xff\x7f\xa4\x73\x32\xdd\xfc\x1e\x53\x17\xf4\x17\x7d\x5e\x2f\x11\xa0\x6e\xc8\x4c\xcf\xb8\x9b\x65\x4e\xa8\x1b\xd4\x2d\x7e\x07\xa3\x87\x30\x1d\x0f\x40\x26\x4a\xbb\xf9\xf9\x10\x7b\x30\xed\xe8\x64\xcc\x76\x90\xc0\x6d\x2e\x24\x7a\x06\x0b\xb2\x24\x4a\xd7\x8e\xd5\xc5\x51\x5a\x1a\x2a\x61\x2d\x61\xe3\xd9\x31\xe2\x8b\xc9\x39\xb4\xd3\x43\x5e\xee\x4f\x73\x31\xb1\xf0\xf8\x53\x75\xd8\x2a\xc9\xa7\x7c\x43\x74\x00\x32\x05\x17\x46\xdc\x92\x69\x45\x8c\x14\x7d\x18\x8d\x84\x40\x19\x54\xa4\x89\xcb\x4f\xbf\x9b\xf8\x4b\xa7\xd8\xf1\x00\x90\x3c\xe6\x78\x31\xb4\x05\x4d\x0f\x58\xcd\x88\x3d\x54\x2c\x49\x33\x10\x3f\xf0\x70\xcd\xfc\x9d\xbb\x0f\xcc\x31\xef\xca\x46\x6e\x77\xa3\x3f\x1a\x81\x3d\xa6\xdc\x0c\x7c\x31\x58\x5e\x8f\x4f\xef\x1e\xbf\x42\xfb\xd1"}, -{{0x7d,0xfa,0xe4,0x16,0x41,0x9d,0x7b,0x0d,0x4f,0xc1,0xf8,0x23,0x84,0x0c,0x3e,0x4b,0xd4,0xad,0xcd,0x4d,0xc2,0xdc,0x17,0xb3,0x86,0x37,0xac,0xed,0xac,0xbd,0xbb,0x45,},{0xbc,0x51,0xd7,0x74,0x59,0x31,0x31,0x7e,0x1e,0x34,0x6e,0x2e,0x7c,0x92,0x03,0x91,0x81,0xb6,0xbf,0x38,0xee,0x2f,0x5a,0x44,0xfb,0xe2,0x33,0x9c,0x4f,0x95,0x2a,0xb9,},{0xda,0x34,0xb1,0x98,0x3e,0x8c,0x55,0xe4,0x1f,0xda,0x8e,0xc8,0xab,0xf2,0x3b,0x36,0x7a,0x0d,0xa6,0x06,0xc8,0xcd,0xbb,0x1e,0x8b,0x57,0xe0,0x34,0x3c,0x05,0x57,0xa5,0xf0,0xe8,0x15,0xe7,0xf2,0x2f,0x86,0x05,0xae,0x93,0xb2,0x7d,0x03,0x77,0x6a,0xc1,0xf7,0xde,0x3d,0x79,0x2e,0xa2,0x93,0x3a,0xc2,0x2d,0x2d,0xc2,0x3b,0x32,0x3d,0x0c,},"\xec\x84\x3d\xc4\xdd\xa6\xe9\x02\xe9\xbe\x31\xb7\x0f\x11\x76\x3b\x75\x7a\xb6\xce\x73\x34\xdc\x00\x76\x4b\x2d\x08\x4e\x9d\xaf\x24\x84\x48\x59\x84\xee\x28\xa2\x83\x0f\xcb\x94\xc5\x41\xcb\x46\x94\x40\x03\x67\x31\xde\x80\xff\x56\x0f\x53\x0c\x9d\x9e\x6e\x1f\x7d\x9c\x4c\x5b\xdf\x50\xb0\x4f\x54\x03\xc2\x9f\x76\xd7\xe3\x6e\x00\xbb\xea\x35\xdb\x1c\xc6\x0d\xa8\xd7\x76\x52\x62\x66\xc3\x32\x4c\xe7\xef\xec\x64\x50\x85\x96\x09\x26\x68\x56\xd7\x01\xa4\x7a\x48\xde\xe8\xbf\x37\x40\x95\x65\xc7\xfb\xfa\x99\xa2\x04\xe5\x53\x0c\x97\x1c\x60\x5b\x44\x30\x5d\x5c\x74\x67\x89\x41\x14\x25\x3c\xf4\x3c\xdd\xf1\x8b\x62\x96\xdd\x25\x4a\x4d\x96\xac\x70\x00\x91\x81\x86\xdf\xd4\xbf\x45\x4e\xd3\x09\x74\xc5\x53\xd0\xae\x15\x1a\xd4\xcf\x54\x0c\xec\xaa\xa0\xb5\x94\x8b\x09\x85\xa9\xc7\xb6\xe7\x81\x59\x32\xba\xc1\x17\x32\xfc\x7d\x10\x26\x7f\x6b\xf8\xf1\xe7\xc0\x8d\x65\x0e\x56\x7b\x4e\xdd\x15\xae\x79\x58\x41\x0e\x42\xf1\xf5\x37\xfa\x73\x2f\x72\x7a\x26\x83\x88\x32\x1d\x53\x44\xc4\xe7\x8b\xb9\xa7\x4e\xab\x9d\x6a\xbf\x96\x89\x65\xc6\x66\x93\xd5\xf1\x12\xdd\x4c\x14\xfd\xfd\xd9\x60\x05\xea\xa6\x75\x7f\xa2\xcc\x10\x13\xfe\x43\x27\xab\x09\x99\xd1\x17\xf3\xdb\xf3\x25\xb0\x7c\xd4\x54\xd4\xb1\x41\x99\x1e\xf7\xe2\x3d\xb5\xee\x24\xbe\xda\x35\x88\x4a\xa3\x70\x48\x08\x64\x8a\xa4\x3c\xd6\x25\x62\x59\xf7\xd3\xdb\x5e\x05\x53\x11\xf2\x53\xe8\xb5\x7a\x4c\xda\x5a\xfe\x0b\x0a\xdf\xc3\x64\xe1\x60\xca\x37\xe8\xde\xc6\xb9\x5a\xa6\x15\x2e\x5d\x5d\xa6\xeb\x91\xbe\x0e\x44\xff\xe8\xe4\x95\x33\x26\x7b\x7e\xb7\x95\xf5\xf8\xe0\xb2\xc3\x5b\x29\xdf\xbc\x87\x58\x5f\x22\xbd\x5b\x90\x9d\xfd\x6a\x5e\xdc\x0e\x3a\x9d\x97\xb0\xc4\xf3\xad\xc5\x1e\x96\x99\x37\xc0\x8f\xd6\x5f\x53\x7a\xac\xda\x8f\x11\x27\x5a\xf0\x2c\x33\x54\x54\x26\x30\xf3\x92\x0c\x39\x3f\x5c\x42\xb9\xfc\x63\x3d\xe9\xd9\x4c\x72\xe3\xf2\x00\x02\x34\x9a\xd0\x41\x80\x35\xb3\xf2\x5f\x02\xca\x92\x8e\x5b\x2d\x40\xa7\x7a\x1c\x3e\x56\x22\x1f\x4b\x9d\xb0\xc2\x5b\x09\x6d\x6e\x5d\x0f\xe7\x58\xda\x2c\x69\x05\x3e\x8d\x08\x6d\xef\x4e\xdc\x6e\x34\x53\x78\x3f\xfc\x63\xa4\x96\x01\x22\xd9\x23\x67\x1a\x90\x60\x08\xba\xc1\x05\x61\xae\x62\x19\xd2\xb5\x1d\x53\x67\xbf\x13\xcc\xab\xf5\x93\x1b\x9f\x18\x6e\xb1\x09\xba\xcd\xe4\x0e\x1a\xf2\xb5\x64\x81\xe0\xc6\xdc\x6f\x5c\x54\x73\xf8\x00\x1c\xf3\x71\x91\x9a\xcb\x40\xce\xc5\xb9\x62\xeb\xba\x80\xe3\x2d\x6e\xba\xc4\x80\x6d\x04\xd2\x47\x68\xc2\xad\x2e\x3f\x92\xa8\xcb\xe4\x77\x54\xf9\xbf\x61\x59\x53\x52\x2b\x26\x3d\xc2\x49\x37\xfb\xd9\x32\xc8\xc4\x59\xeb\x8b\x10\x94\x43\xaf\x6c\x19\x5a\x59\xfd\x27\x21\xb0\x12\x56\x28\xf2\xb8\x14\x3c\xf3\xc1\x28\xbc\xec\x13\x92\xef\xd1\x6b\x73\x4c\x10\x71\x6d\x96\xba\x7d\x1f\x41\x39\x17\xcc\xaf\xa5\xbf\x5f\x83\xf5\x24\xfe\x84\x06\xa1\x52\x11\x5e\xa7\x70\xe1\x74\x5e\x82\xe8\xb5\x1d\x75\x2b\x8b\xd7\x85\xdf\x48\xbf\xc1\x20\x41\xbf\x87\x4f\xc7\x3a\xfb\x42\xca\x5d\x69\xc6\x41\x64\x79\xce\xb4\xaa\xa0\x49\x2b\x6f\xf2\x1e\xe1\x2d\xb2\x21\x3a\x42\x86\xfd\x56\x05\xc9\x3a\x7b\xb8\xa3\xb0\x71\xb0\xb2\x5f\xb0\x1d\x77\xab\xbc\x87\x71\x48\x94\x70\xa1\x07\xaa\xda\xe9\xf6\x40\xc2\x4d\xfd\x53\x28\xf6\x0f\x4b\x7d"}, -{{0x70,0x94,0x16,0x07,0x49,0x97,0xb9,0xc9,0xaf,0x4d,0x37,0xa0,0x11,0x39,0xe8,0xa3,0xf9,0xf2,0xce,0x5d,0x72,0xa5,0x7d,0x80,0x5e,0x82,0x2a,0x81,0x18,0x6d,0x01,0x7e,},{0xae,0xe1,0x10,0xf1,0xf4,0xd4,0x6e,0xa6,0x06,0x49,0xd7,0x86,0xb1,0x50,0x05,0x2e,0x28,0x7a,0x9d,0xa6,0x01,0x22,0xc4,0x7b,0x09,0x08,0xfa,0x8b,0x2c,0xa2,0x8a,0x80,},{0x8e,0x4b,0x41,0xf0,0x97,0xd8,0x36,0x14,0x18,0x4b,0xa7,0xf5,0x2b,0xa2,0xfd,0x9f,0x05,0x65,0xf8,0xa6,0x37,0x21,0xef,0x55,0xf9,0x31,0x62,0x82,0x6b,0x9f,0x0a,0xc0,0x70,0xc0,0xe2,0x86,0x4b,0x5f,0xfd,0x8e,0xcc,0xc1,0x8e,0xfa,0xd1,0x8b,0x2c,0xe8,0x4b,0xe5,0x7c,0x0b,0x4a,0x41,0xc5,0x2e,0x20,0xef,0x37,0x72,0x23,0x77,0xc6,0x0f,},"\xed\xda\xa3\x69\xc0\xe3\x1a\x1f\xcc\x1d\xa4\x6f\x65\x36\x24\x42\xa0\xcc\x21\xc7\xdc\xdd\x5c\xd9\x0e\x0a\x2e\xe9\xf2\x51\x10\x81\x2b\xa1\x14\x93\x1c\x86\x8a\x70\x86\x07\xac\x16\x08\x4d\x79\x71\x5d\x13\xb3\x38\xc0\x5c\x6a\xef\x73\x43\xe7\xda\xd2\x82\xf9\x6f\xe2\x81\x93\x18\x8f\x0c\xc8\x93\xc7\xdc\xe8\x05\xfd\x3a\x7c\xd2\x68\xb7\x28\x94\x16\x0b\x52\x45\xfe\xd9\xfa\x99\x43\xb7\xc8\x0a\xdb\x3c\x2d\x1a\x35\x3d\x8f\x12\xdf\x25\xa3\x1d\xde\x7f\xa3\x85\xbb\xec\x35\x1d\xa6\x6f\x15\x30\x32\xe1\x77\x56\x27\x3f\x8d\x54\xe9\xa3\xb9\xea\x25\xae\x67\xd1\xe9\xc1\x8c\xc6\x8b\xe6\x01\xe3\xd6\x82\x82\x81\x8c\xe0\xe7\xcf\x88\xa4\xd1\x33\x64\x53\x02\x17\x32\xf0\x8d\x9e\x76\xcd\x23\x63\x79\x29\xb0\x91\x1d\x5f\x86\x14\xf4\x84\x2e\x67\x0c\x14\x28\x60\xaf\xc2\x65\xc5\x01\x72\xb1\x3b\xfd\x35\xad\x8f\xc5\x4b\x28\x65\x7d\xa3\x2b\xac\x15\x3b\xa9\xaf\xfc\x89\x7a\xfb\x3c\x72\x1f\x48\xca\xa4\x62\x40\x58\x57\x10\xb0\xf2\xd2\x4d\x5f\xf4\x96\x5d\x1d\x10\xf1\xa0\x7b\x06\xab\xea\x6a\x08\xe1\xd6\xf1\x50\x0d\xa1\x2c\x43\x4a\x6d\x77\x8c\x94\x10\x67\x10\x80\x00\x47\x5c\xe8\x31\xbc\xfe\x2d\x0a\xfe\x40\xb7\x41\x9d\x07\x05\x9b\xc0\xcd\x8d\xce\x4b\xe9\x58\x7f\xf2\x9a\xd8\xbf\x0b\x26\x8a\xe2\x3c\xe0\xda\x5b\xb5\xbf\x74\xff\x0b\x2b\x31\xb8\x21\x12\xa9\xfd\x5a\xbd\x9b\xfd\x0a\x90\xe6\xf4\x72\x35\x48\xc6\xbb\x2f\x99\xdc\x06\x1b\xa3\x2e\xba\x2d\x53\xe6\xbc\x79\xbf\x44\x1b\x23\xfb\x74\x60\xde\x04\xe8\xe8\xef\xbc\xd4\xd4\xcc\x73\x55\xde\x9e\x3b\x08\x61\xa6\x81\xb9\x83\x83\x9d\x44\x88\xe5\x51\x75\x1f\x23\xe9\xa6\xe2\xe4\xd4\x43\x27\x3b\x9e\x0f\xe6\x4d\x8a\xcd\x1c\x74\x8b\x55\x59\x43\x82\x23\xdd\x21\xb5\x18\x31\x89\xe0\xf3\xc0\xe8\xed\x41\x4c\x03\x56\xba\xb7\x7a\x65\x4d\xe1\xa5\x77\x14\x62\xef\x14\x34\x49\x70\xa4\x91\x51\x1a\x72\x29\x14\xf4\xa8\x9f\x4f\x1a\x82\x7e\x18\xcd\x84\x47\x9c\xc9\x25\x92\xea\xdf\x8d\xe2\xdf\x82\x4b\x97\x6d\xcb\xd2\x84\xa3\xba\x64\xbc\xdb\x0d\xf1\x5e\x8f\x41\xc0\xb2\x47\x15\x86\xb2\x6a\x06\x35\x3d\x90\x50\x28\x23\x5c\x1c\x6e\x5c\x45\x87\x22\x27\x25\xaf\x08\x3e\x11\xe7\x9c\x94\x3a\xa4\x44\xd4\xaa\x41\x21\x8d\x3e\x97\x43\x36\xe3\x72\x81\x3e\x99\xe2\xb0\xc5\xf0\xae\x81\x0f\xfe\xd9\xa7\xa3\xd6\xcb\x74\xc5\x47\x3d\x99\x0a\x59\x11\x32\x9b\x8e\x82\xec\x6b\xf2\xbd\x43\x21\xbb\x48\x73\x70\xf8\x73\x9e\x7a\x2a\x4a\x53\x43\x08\x33\xd4\x5b\x9f\xe3\xde\xb9\x3f\x79\xfc\x6a\x51\xd5\x63\x69\x5e\xcd\xb9\x78\x58\xd2\x13\xda\x58\x44\x34\xb7\xc7\x15\x46\xaa\xe8\xd9\x67\xe1\xc6\xd0\x08\x2b\x10\xd4\xa7\x2d\xe1\x74\x2e\x53\xc4\xb2\xf9\x2e\xb8\xb5\xc8\xc3\x5a\xb6\x53\x5e\xa8\x10\x0b\x37\x92\x4a\x0a\x91\xd2\xa7\x28\xd0\xf5\x64\x24\x37\xaa\x66\xc8\x2a\xb7\x4b\x5d\x07\x45\xec\x08\xf7\x70\x5c\xb8\x1f\xa0\x79\xd8\x9e\xcd\xc9\xaa\x1f\x8d\x7d\x82\xdc\x77\x46\xd3\x46\x15\x34\x3a\x69\x25\xdc\x31\x8f\x35\x2a\x2b\x45\x01\x24\x38\x42\x4f\x90\x98\xfd\xdf\x6e\x61\xfd\x1f\x8f\xb4\x9d\xa4\x0b\x3e\xec\xe8\x9a\x1a\xf1\x99\x6d\xe7\x0c\xd1\x69\x6c\xbf\xd9\xe3\x01\xea\x5f\x44\x37\xc7\x1a\xc2\xa0\x32\x25\x4c\x14\x0a\x90\xe8\x5f\xb8\xff\xc4\x66\x7f\xa1\x39\xc1\xee\x9b\xbf\x12\xee\xd9\x06\xa9\x67\xbc\x09\x21"}, -{{0x3d,0xcb,0x7a,0xe7,0xd9,0xf0,0xf1,0x41,0xf1,0xd9,0xf0,0x78,0x83,0x63,0x5b,0x91,0x3e,0xd2,0x9f,0xb6,0x1d,0x0f,0x74,0x1c,0x9a,0xfd,0x05,0xa2,0x7b,0x04,0x5b,0x06,},{0xae,0x62,0xb7,0xee,0x1b,0x8d,0xb5,0x76,0x4d,0xaf,0xdd,0xd9,0x72,0x4a,0xcc,0x10,0x6d,0x6c,0x0a,0x4d,0x1e,0x85,0xd8,0x90,0x6f,0x75,0x84,0xb5,0x58,0xf5,0x77,0xdf,},{0x09,0xa1,0xe6,0xfe,0xdf,0x97,0x1b,0x3e,0xdb,0xfa,0xef,0xbe,0xb8,0x9a,0xa5,0x39,0xca,0x0b,0x02,0xb3,0x7e,0x7a,0xc4,0xea,0x89,0x20,0xd6,0xd4,0x34,0x8e,0xe0,0xcf,0x9a,0x2d,0x5e,0x96,0xfc,0xe5,0x17,0xc6,0x65,0xe7,0xc3,0x83,0x68,0xba,0xf2,0x49,0x79,0x24,0x9a,0x95,0xb7,0x0e,0xa7,0x43,0x6c,0x00,0x78,0x5f,0x16,0xa3,0xae,0x09,},"\x38\x11\x6a\x57\x26\x69\x07\x0d\xd5\x86\x32\x18\xc9\x1a\x77\xa4\xab\x47\x55\x36\x88\x48\x8c\x79\x28\x38\x50\x9e\x9a\xba\x25\x06\x7a\xdb\x7e\xa4\x24\x98\x48\x00\x9d\x91\x4a\xe9\x87\xa6\x03\x23\x48\xc1\xc0\x68\x1c\xf9\x77\xa9\x55\x2d\xd6\xbb\xf4\xe6\xff\x32\xac\xc9\xfa\x61\xcb\xee\x25\xa3\x93\x07\x65\x0f\x8b\xa6\xa7\xce\x42\x1e\xf2\xf7\x1b\xcc\xc0\x95\x81\x38\xf9\x32\x4c\x86\xbf\x2e\x52\x8f\xa3\xe4\xd1\xb1\x9f\x9f\x2c\xa5\x26\x84\x09\xb8\xcc\x19\xc6\x2d\xd9\x79\xb8\x96\x97\xe4\x57\xed\x2d\x98\xbd\x20\x96\xf6\x2d\x3d\x9e\x24\x73\x88\x79\x59\x27\x80\x3e\x79\xab\x71\xd4\xf7\x2f\x56\x8e\x94\x5a\x8a\x16\x21\x59\xd9\xb8\x48\x36\xe4\x58\x56\x44\xd4\x97\x9f\x61\x4a\xad\xa7\x3a\xd4\x13\xa8\x33\x91\xe9\xcf\x88\x0c\x42\xac\x2a\x98\x34\x3b\x6a\x82\xcd\x2b\x61\x58\x14\x56\xf6\xde\x5c\xeb\x24\xfe\x46\xb7\x62\x5d\x52\xab\x2c\x2c\x32\x4a\xc7\x47\x03\xd1\x5e\x15\xf1\xae\xff\x80\x55\xd2\xf7\x39\xf7\x36\x3e\x16\xec\x1d\x78\xbe\x2c\x62\x99\x43\x6c\x8c\x8d\x33\x6b\xd2\x92\x71\xa8\x97\xa6\xec\x93\x2e\xd0\x87\x25\xbe\x21\xb2\x8f\x9a\xa1\x4e\xaf\x4f\x71\x85\x31\x54\xdb\x14\x58\x7c\x93\x0a\xb3\xeb\x02\x27\xad\x7f\xfb\x45\xb3\xba\xa6\xa9\x99\x49\x9c\xc8\xa6\xe4\x5b\x1a\xb4\xd0\xb3\x39\x78\x2b\xcd\x9c\xfb\xcf\x88\xcf\x7e\xae\x89\x1c\xc8\x41\xe9\xc8\x8a\x1f\x6a\x69\x1f\x39\x48\xa6\xbc\x85\xba\x7f\x46\x11\x64\x2e\x84\x22\x3c\x3b\x17\x89\x46\xdd\xbe\xdd\xcf\xcd\xef\x4a\xe4\xc4\xe1\xa8\x14\xb9\xb1\xf0\x2b\x1e\xaa\x82\x4d\xb9\x3f\x44\xb2\x7d\x14\x20\x6b\x34\x04\x65\xa1\xce\xfc\xf5\x35\xc6\x3e\x55\xc4\x28\x72\x24\x26\x27\x33\xd9\x8a\xaa\xa1\x54\xf3\xad\x42\xcd\x85\x46\xa4\x61\xce\x0d\x46\xd8\x86\xd3\x46\x1a\x21\x50\xcb\x45\xdb\xe5\x64\x73\xff\x63\xd3\xdc\x7a\x2b\x95\x7b\x82\x39\x69\xf1\x9b\x59\x68\xe8\xb4\x24\xc8\x79\x74\x19\x26\xd8\x2c\x63\x86\x75\x3b\x0f\xa1\xf0\x80\x28\x4e\x55\x78\x94\x23\x63\xaa\xde\xb2\x1f\x8e\x1e\x89\x09\xfa\x6c\x38\x07\x64\x14\x9b\xc9\x15\xb2\x28\x60\x4e\xfc\x56\xd9\x2e\x4b\xeb\x72\x0e\xdc\x74\xc4\xd7\x8f\x92\x5d\x6c\xfd\xf7\xba\x2f\x14\xb5\x62\x37\x75\x81\x0d\x2d\x07\xbd\x38\x8c\x57\x3e\x36\x52\x3f\x21\x57\x38\xe6\x91\x14\xdc\xf8\xd8\x0f\x17\x0b\xfa\x67\x6e\x31\xfb\x62\x6a\x7d\x44\x9e\xd9\x66\x47\x36\x34\x75\x97\x0c\x8c\x47\x80\x97\x09\xbc\xb5\xe7\x20\x0f\x2a\x22\x7c\x7c\x8e\x7b\x00\x0f\x30\xc0\xbd\xe6\x1d\x67\xbd\x68\x95\x36\x16\x29\xa3\x6c\x8f\xdd\x5a\x56\xb8\x1e\xfb\xac\xf1\x5c\x1b\x35\x30\xa0\x8c\xde\xd5\xb1\xfd\x45\x7f\xbd\x2f\x03\x04\x2f\x56\xf1\xb3\x7e\xd1\x5c\xdb\x91\x2f\xa0\x29\x8c\x27\x67\x25\x08\x7e\xe2\x7d\x3c\xf2\x55\x0f\xe6\xe8\xa0\x33\x0a\xf4\x17\xf4\xf5\xba\xf0\x36\x27\xed\x67\xc5\xf8\x32\x33\x63\xab\xac\x5a\x1f\xe3\x48\x23\x18\x0e\x3e\x0e\x20\x80\xf7\x5b\xfd\x91\xc2\x07\xcf\x6b\xaa\x9a\x22\x9c\xf4\x43\xdd\x44\x2c\x59\x02\xe0\x67\x3f\x32\x52\xb8\x52\x63\x46\x58\x58\x72\xf6\xcd\x36\x60\x25\xa5\x69\x92\xb7\x0e\xde\x39\xbc\x8d\x32\x2f\x9c\x22\xa1\xdc\x59\x9e\x9f\x0d\x52\x4c\xb6\xd2\xea\x5a\xe2\x87\x8e\xf6\xbe\xd4\xb7\x02\x80\x7f\x1e\x1e\x73\xeb\xf2\x90\xeb\x6c\x0e\xeb\x85\xc1\x37\x16\xf6\x26\xaa\x90\xd3\x64\xb4\x90\x48\x37\xce\x05"}, -{{0x29,0x73,0x11,0xdd,0xef,0xfe,0xc9,0xd2,0xbe,0x68,0xef,0x7b,0x2a,0x20,0xfe,0x2d,0x27,0x7e,0x1d,0x8e,0x51,0x64,0x8b,0x03,0x57,0x2a,0xda,0x27,0xec,0x1f,0x9f,0x43,},{0x6a,0x6c,0x28,0xe7,0x61,0x64,0x0c,0x40,0x08,0x33,0x3a,0xae,0x5a,0x33,0x66,0x30,0x2e,0x2f,0x46,0x77,0xa9,0x53,0xba,0x48,0x2a,0xb6,0xfb,0x4a,0x1d,0x70,0xb4,0x47,},{0x4b,0xf0,0xb9,0x2c,0x6e,0xe4,0xea,0xce,0x5e,0x8e,0xb1,0x03,0x70,0xff,0x9d,0x9c,0x68,0xa5,0x74,0x9d,0x59,0x89,0x9d,0x04,0x32,0x7a,0xaa,0x38,0xf8,0xf8,0x25,0xe0,0x32,0xe5,0x97,0x42,0xb3,0x7d,0xe2,0x31,0x07,0xa3,0xec,0xdd,0x3f,0x7a,0x0d,0x08,0x12,0x26,0x14,0xb7,0x8f,0xdd,0x37,0x29,0x3c,0x8d,0x05,0xe2,0x8f,0x5f,0x71,0x08,},"\x26\x52\xac\xfc\x3b\xdf\x09\xa5\x99\xec\x67\x86\xbb\xd9\x4f\xe5\x77\xcf\x57\x8e\x02\x63\xcc\x68\xd9\xf5\x7a\x6c\x83\x45\x8f\x80\xac\xd8\xa7\x5e\xf0\x30\x40\xa6\x35\x67\x2b\x96\x8f\xf2\xaf\xdb\x28\x8d\x28\xb9\x99\x6f\x64\x15\xb2\xf3\x17\x5e\x9e\xa3\x7a\xeb\x05\xdf\x81\x81\x2e\x38\xa4\xc9\x76\xeb\x92\x85\x6c\xed\xb9\x1a\x26\x9a\x46\xfc\xa5\xdf\x9b\xd7\x30\xfd\x84\x45\x2b\x4b\xd9\x35\x77\xc6\x1f\x42\xc1\x41\x13\x97\x98\x82\xa8\x6a\x9f\xe6\x32\xe4\x75\x6a\xfd\x89\x81\x6f\xc4\x67\x0a\x31\x05\x03\xfd\xaa\xd2\xdb\x76\x4c\x37\x21\x21\x3c\x3e\x60\xf2\x9c\x26\x68\xd4\xde\x8f\x42\xb0\x87\xf2\x5c\xd5\x6c\x69\xa4\xe4\x8f\x13\x4f\x55\x98\xcf\x14\x5b\xe6\x38\xa5\xc2\x31\x88\x63\x32\x90\x61\x72\x9a\xac\x91\xda\x6a\x19\x1f\xd7\x74\x88\x0c\xf9\xcb\x55\x5e\xec\x15\xb0\x04\x4f\x10\xe5\x43\x3f\xb4\x6a\x9b\x88\x92\xda\x8f\x6d\x24\xf1\x42\x58\x8b\x70\xff\x0b\x49\x20\x0c\x50\x6b\x88\xbe\xd4\x49\xad\x10\xd3\xf9\x2c\x2b\xae\xda\x6b\xbf\x58\x67\x6c\x5b\xbc\x67\xd3\x1f\x64\xfb\x12\xe8\xd5\xe7\x88\x76\xd5\xc8\x49\xfc\x31\x4b\x2c\xf8\x01\x0c\x51\x02\x04\xc8\x63\x3d\x0c\xc3\x18\x56\xec\x6a\x11\x4e\xa8\xa8\x9c\x48\x92\x7b\x07\xa3\x1a\xb8\x42\xc9\xb8\x35\x2d\x93\x67\x34\x51\x41\xa9\x9b\x40\x04\x9d\x5c\x48\xe7\xd2\x7c\xab\x42\x7a\xde\xfd\x1f\x0f\xc1\x13\x6b\x35\x3c\xb0\x1c\x3d\xef\x91\xff\xfe\xe8\xad\x91\xe8\x8f\x4b\xb7\xd2\x61\x5c\x0d\xcc\x95\x34\x4c\xd0\x19\x50\x93\x8e\xcb\x14\xb8\x44\x6b\x56\xa0\x6b\xf2\xf2\xf6\x5f\xb8\x73\x5e\x8a\x7b\xc9\x6b\xb4\x6c\xe9\xca\xc7\x1a\x88\xeb\x8f\xda\x5e\x69\xd6\x9e\xb2\x9a\xa4\x2a\x01\x6b\x85\x83\x89\x3e\x9d\x72\x77\xcb\x13\x59\xc5\x68\x7e\xed\xcd\x59\x9d\x8a\x46\xe6\xc1\x49\x63\x63\x7d\xb0\x4a\x92\x9f\x4b\xc7\x93\x04\xac\x2d\xae\x73\x3b\x3a\x83\x9e\xb7\x4f\xbe\x3d\xe5\x04\x2f\xd6\x55\xea\xec\xb1\x5f\x39\xb2\xfe\x16\xda\xd8\xa6\xff\x8d\xbc\x05\x4f\xed\x51\x28\x2a\x85\x6e\x9d\xa6\x31\x6f\xac\x6d\xb5\xd5\x6f\x77\xf1\x8d\xa8\x41\x2e\xb3\x77\xe5\xb1\xb8\xf4\xcb\x13\x54\xec\xfe\x8f\xe8\xfd\x54\xe6\x2d\x76\x7a\x80\xde\x04\xcb\x76\x20\x22\x9a\x88\x31\xdb\xc9\xec\xd4\x57\x8f\xfa\x2f\xf0\x6b\x54\x45\xe4\x40\xd6\x9a\xab\xc9\x4c\x47\xbd\x17\xf2\x2b\x69\xf5\x2e\xea\xe5\xcf\xcd\x01\xa5\xca\xfe\x05\x80\x07\x2a\xe9\x16\x6b\x95\x74\x3d\x68\xc3\x56\x4c\x5a\x7e\x46\xf2\x4b\xc4\x8a\x89\x8a\x1a\xb2\xeb\xe6\x3f\x36\x85\x1d\x2a\xac\xfa\x0c\x4f\x32\xd9\x93\x77\x1d\x31\x4e\x72\x5a\x43\xd9\x80\x5d\x13\x71\xcf\x72\x3e\xf1\x61\xd4\x2e\x63\xff\xca\x68\x8d\x7f\x0e\x21\xef\x5b\x3f\x9a\x56\x1a\x62\x10\x70\x2b\x85\xfb\xd1\xf8\xca\x75\x38\x9c\xc7\xa2\x27\x39\xba\xe4\xde\xd9\x37\x57\xf1\x52\x0d\xc3\x88\x44\xa1\xa8\x8b\xe8\xe0\x96\x45\x05\x91\x48\x80\x7b\x93\x37\x70\x87\x8c\xb8\xa9\xad\x92\x11\x31\x71\x31\xe6\x93\x24\x53\x2f\xd0\x27\x9b\x83\x18\x5b\x62\x8f\xc2\xf9\xe2\x15\x00\x38\x46\x93\xfa\x29\xf2\x6b\xd1\xb9\xc3\x01\x60\x13\x67\x66\x5f\x05\xf3\x72\xda\xb4\xe3\x10\x77\x26\xcd\x3f\x63\x9c\xa6\x2b\xf6\x3a\x75\xf7\x7e\xaa\x75\xf7\x13\x61\x57\xad\xa2\x37\x4e\x65\xfb\x4f\xd3\x49\xb4\x5e\x25\x44\x1f\xd2\x1b\x13\xe6\x91\x13\x66\xb9\x7c\xfb\x4d\x6a\xd5\x22\xb8\x50\xad\xf4\x0c"}, -{{0x4d,0xb2,0xb5,0x81,0x44,0xa8,0xd2,0xd0,0xec,0x03,0xbb,0x9b,0xc2,0x9b,0x4c,0xa8,0x93,0x85,0x4c,0x80,0xb6,0x4a,0xfa,0x4a,0xf7,0xa9,0xc9,0x36,0x93,0x5e,0xcb,0x04,},{0xfc,0x5c,0xd7,0x50,0xe1,0x74,0xed,0x71,0x8b,0xd9,0x38,0xfa,0x8e,0xd9,0x9a,0x1b,0x9d,0x55,0x6b,0xa7,0x67,0x0f,0x2a,0x77,0xda,0xf1,0xc7,0x20,0x11,0x37,0x32,0xa5,},{0x42,0x45,0x17,0xaa,0xdd,0x85,0x3c,0xe3,0x98,0x57,0x59,0xa3,0x27,0xe7,0x76,0x0d,0x91,0x56,0xd3,0xb2,0x73,0x45,0x38,0x3f,0x0e,0x4a,0xd6,0x66,0x1e,0xe4,0xa3,0x72,0x4d,0x18,0xd8,0x20,0xf6,0xc5,0x57,0xf8,0x27,0x97,0xbe,0xb6,0x2d,0x2f,0x08,0x54,0x33,0x74,0x4f,0x89,0xa2,0xd8,0x52,0x93,0x79,0x64,0x81,0x86,0x2e,0xf8,0xa4,0x0f,},"\xc8\xd1\xdb\xc9\x36\x91\x1e\x12\x2c\xee\x18\xf9\x2b\x16\xa3\x9a\x2e\xef\x08\x23\xb2\x27\xf8\x98\xcd\xf5\x84\x2b\x93\xd5\x9f\xc0\x02\xed\xb5\x49\x8a\x20\x87\x2e\x19\x55\x4e\xf7\x39\x99\xeb\x3a\x7b\x3e\x2f\xdd\x90\x70\xe1\xef\xa9\x22\x8e\x9e\x93\xb2\x9a\x86\x8a\xe3\x79\x9e\x4e\x57\x23\x24\x83\x6b\x1a\xd5\xaa\x81\x2b\xf0\x0f\x84\x5b\xc2\x17\xeb\xbc\x3f\xab\xdc\x4e\x1b\x6e\x51\xef\x9e\xfa\xc2\x77\x0a\xa0\xa4\xa1\x1e\xe5\x2a\xb9\x56\xac\x64\x48\xaa\x26\x29\xcb\x61\xdb\xb1\xf1\xed\xb3\xbd\xe9\x9b\x48\x76\xda\x39\x2a\x6e\x0b\x9a\x0c\x31\x84\x9a\x58\x90\xae\xa9\x52\x2f\x56\xd0\x15\xa1\x93\x50\x15\xb9\x1b\xf4\xc6\xa0\x01\x1d\x23\x77\xd6\x71\xc3\xd0\xd7\x53\xc2\x7f\x8c\x76\xe4\x05\xd0\x23\x0f\x1f\x4b\x9b\x88\xfc\xeb\xba\x1e\xaf\x13\x77\x72\x35\xe5\x53\x24\xb7\xd3\xf8\x1e\x68\x61\x09\xd9\x1c\xe6\x89\x53\x0b\x90\xd2\xc5\xc7\x1d\xd1\x87\x72\xb3\x85\xd6\x2c\xcb\xfd\x2e\x08\x9a\x1b\x67\x09\x83\xf6\x0c\x21\xc4\x45\x5c\xb9\xd1\xa0\xdc\xaa\x74\xc8\x74\xe3\x52\x11\xf8\x22\x7f\xf7\xc2\x34\xdf\xf8\x5e\xc0\xb0\x7e\x36\x8c\xfa\x50\xa3\x43\x57\x83\x95\xa1\x4c\x68\xf1\xf8\x9b\xd4\xec\xbc\x17\x2e\xf8\x05\xe5\x83\x1e\xc8\x94\x75\xfc\xc8\xd6\x85\xca\x92\x55\xa7\x7e\x3b\xa3\xc1\x47\x50\x8e\xc9\x2d\x7b\xcc\xe8\x79\xaf\x0a\xbd\xd2\x41\x6b\x67\xb5\xf5\x05\x07\x33\x79\x14\xf3\x90\xbb\xe0\xb4\x50\xb6\xa2\xf1\x15\x93\x72\xc4\xbc\xce\xa3\x82\xce\x3d\x6d\x9f\xb2\x51\x5e\xcf\x79\x30\x05\x9a\x05\x52\xb7\x5f\x97\x88\x62\xbf\x97\xe8\x32\x5a\xf2\x4d\x1b\x8c\xe9\x51\x2b\xfc\x7c\xef\x88\x42\x32\x04\x23\x41\xd8\x2f\x9b\x5d\xad\x2e\x50\x2a\xc6\xac\x79\x5f\x99\xda\xc7\xfc\x60\xe3\xb8\x63\x9d\x0e\x15\x00\xde\xad\x4e\x78\xac\xa1\x09\x95\x7d\x57\x7a\x13\xc1\x92\x5d\x74\x03\xc1\xac\xf9\x89\xa9\xde\x67\x11\xe2\x3c\x67\xbf\x87\x22\xf5\x51\xb7\x74\xca\xda\x93\x1b\x5f\xd9\x73\x43\x4e\x3b\x71\x72\x81\x98\x83\xe7\x0c\x52\x78\x5e\x3b\x49\xd3\x23\xd0\x56\x36\x64\x11\x58\x64\x0d\xcf\x6a\x4c\x20\x0e\xb2\xc1\x3b\x1b\xee\xb2\xdc\x36\x03\x52\x47\x0d\x15\x38\x6e\x59\xe6\xfa\x60\x36\x7e\x5e\x7f\x17\x2b\x21\x15\x9d\x5e\xe7\xca\xb0\xd7\xf5\x86\x82\x39\x85\x8e\x2a\x93\x55\x04\x80\xfe\x8f\xb4\xdc\xaf\x4f\x22\x4c\x4b\x2a\xd5\x44\x87\x91\x63\x2d\xf3\x0e\x8e\x5f\xb9\x98\xb3\x5e\xa9\xae\xc8\xc9\x34\xa4\x40\x3a\xef\x82\x18\x7c\xa1\xab\xf8\x2a\x34\x4d\x00\xff\xb9\x93\xd9\xff\x34\x61\xd6\xfe\xcd\xaf\x5d\x3b\x48\x1e\x0d\x31\x15\x3d\xbf\x6a\xed\x28\x8c\x8a\xdd\x06\x4e\x83\x31\x55\x01\x41\xbd\x5f\x7a\x7e\x04\x7b\x86\x07\xd8\x46\xa6\xbf\xb7\x2d\x68\x34\x46\xa4\x45\x11\x46\x06\x25\x0d\x8d\x2d\x3a\x8b\x95\x08\xbb\x07\xd4\x62\x3c\xdf\x17\x88\xb5\x49\x9e\x9c\xb9\xa1\x37\x98\x49\xbf\xa1\x9c\x9a\x9f\x4c\xd3\xd9\x25\x3a\xdf\xfd\xa2\x5f\x47\xc8\x11\xbe\x83\x3b\x02\xf3\x32\x7e\xbb\xa8\x37\x30\x19\x5d\x61\x4b\xae\x6f\xe4\xe7\xa3\x83\x08\x15\xd2\xaf\x40\x0d\x20\xa9\x41\x7a\x09\x5e\x7e\x8e\xea\x10\x44\x91\x7c\xbe\x51\x2c\x40\x18\xd6\x56\xe2\xdb\x67\xbb\x98\x9c\x00\xe1\xe5\x07\x62\x3e\x82\x78\xd7\x29\x92\x5b\x84\xfb\x5c\x18\x6a\x7b\xac\x18\x9e\x6d\x6a\xb1\x4f\xd7\xb6\x2f\xdc\x63\x2b\xeb\xb5\xf7\x7c\xb5\xcc\x2f\x70\x7d\xf4\x05\x30\x99"}, -{{0xc8,0x20,0x41,0x3c,0x24,0x56,0x74,0x71,0x04,0x66,0x2e,0xf4,0xdf,0xf3,0xac,0x23,0x3a,0xc4,0xb9,0x1a,0x76,0xd3,0xc4,0xea,0x75,0x44,0x90,0xbc,0x9b,0x1e,0x29,0x1f,},{0x89,0x93,0xce,0xa2,0xf7,0xf2,0x80,0x6c,0x77,0xb3,0x98,0x1b,0x54,0xbf,0xa9,0xbf,0x17,0x62,0x15,0x1b,0x41,0x8e,0x5e,0x72,0x53,0x71,0xca,0x2c,0x04,0xd2,0x23,0xee,},{0x7e,0xf7,0x0e,0x4a,0x14,0x95,0x4d,0x50,0x9f,0x11,0x7f,0x4b,0xd0,0x1b,0x22,0x0b,0xcc,0x19,0x2d,0x3b,0x5f,0xdf,0xc3,0x48,0x2f,0xbb,0xc3,0xb6,0x9d,0xc0,0x68,0xa7,0xc4,0x76,0x1d,0x1b,0xeb,0xc2,0x31,0x7d,0x6d,0xb7,0x4f,0x90,0x6a,0x15,0x56,0x42,0xb0,0xa3,0xc6,0x59,0x2b,0xdc,0x72,0xe6,0x4e,0xac,0x6f,0x20,0x3f,0xb7,0x4e,0x02,},"\xd2\x99\x2f\x83\x92\x4a\x59\x48\x87\xe6\xef\x13\xf2\xae\x80\x8f\xc8\x63\x9c\x7b\x2c\x99\x4f\xaf\x0f\x79\x5e\x36\x01\x6d\xab\x77\x00\xa0\xee\x53\x01\x70\xf0\xb9\xfe\x98\xab\x75\x88\xce\x03\xbc\x50\xc2\xba\xe6\x5e\x05\x26\x47\xe7\x56\x73\x5b\x35\xd0\xb5\x9c\x96\x4e\x91\x7d\x8c\x83\xe2\xf9\xfe\xcc\x4c\xb0\x55\x64\x28\x7f\x0e\x34\xc9\x49\x40\x05\xe2\x5b\x1a\x8b\x1b\x94\x2b\x54\xd8\x90\x35\xf1\xb1\xc3\xc9\x45\xfc\xc8\x4e\x4a\x39\xef\xa2\xca\x50\x95\x9b\x45\x9a\xf7\x4d\x21\xb6\x24\x2e\x2f\x56\x51\x8f\x70\xe8\x67\x92\x57\xc0\x89\xd2\x6c\x3b\xb7\x92\x68\x7c\x92\x33\x55\xb2\xc1\x8e\xe2\x13\x6d\x40\xcb\xa4\x5a\xcb\x64\x24\x0d\x96\x67\xf3\x9d\xba\x36\x39\xb6\x51\x6d\x4c\x49\x47\x57\x3e\xf4\xce\xd8\x76\xb5\xb2\xea\x34\x89\xea\xea\x53\x9f\x55\x7f\x58\xda\x20\x46\x91\xa7\x6e\x29\xc9\x4b\x8b\x05\x38\x23\x2c\x5f\x7d\x0b\xb0\xfd\xd0\x16\x91\x04\x31\x35\x4b\x3e\x1e\x7c\xe6\x2a\xd4\x36\x91\x7c\xd5\xc3\x15\xa5\xbe\x9b\x97\x1c\x80\xf9\x7b\xc9\xd5\xc1\x56\xff\xd6\x4f\xd4\xe3\x1d\xa5\x60\x83\xe0\x2a\x0c\x8f\xce\x55\x4d\xb6\x86\x74\xcb\x62\x70\x0b\xa9\x51\x75\x2b\x82\x9b\x03\xc5\x42\x32\x74\x12\xee\xc9\xcc\xc6\xa5\x0a\xdf\x47\xbb\xee\x15\x44\x66\x82\xda\x2f\xea\x42\x04\x89\x36\xd7\x63\x06\x0c\xd8\xf5\x39\x65\x26\x16\xdf\xa8\x08\xd6\x23\xff\x77\x7b\x41\x13\x65\x2e\x78\x9e\xc0\x25\xb8\x5e\x04\xef\xe8\xad\x4c\x96\x0b\x19\x0b\xf4\xa5\xa6\x32\x4d\x6f\x57\xc1\xad\x22\x01\x8c\x83\xcd\x7e\x7e\x09\x7f\xc6\x7b\x80\x26\x9c\x13\xb4\xdd\x97\x01\xca\x98\xf9\x87\x69\x58\xba\x76\x89\xc6\xf6\xf1\x0a\x73\x2a\x64\xbe\xf2\x2e\x8b\x98\xbd\x30\x4d\x5d\xbf\x4f\xb1\xf9\xe4\xca\x53\x9a\x5c\x4a\xa6\x19\xc4\x4d\x6f\x58\xf8\x24\xb2\xdb\xae\x77\xb7\xe8\x3b\x56\xdb\x5e\x5a\xa7\xb0\xae\x9c\xe1\xcd\x10\xa6\x9f\x04\xa8\x0f\x13\x79\xeb\x0c\x47\x4e\x47\x82\xdf\x0e\x3b\xa6\xa1\x48\x22\x6b\xd1\xa6\x62\xd9\x5e\xe2\xd6\x7c\x52\x07\x33\x3c\xb1\xd5\x41\x76\xd9\xe5\x06\x45\x94\x79\x02\x9f\x31\xdc\xac\xe2\x69\x93\x8f\x6b\xc5\x62\x78\x78\x41\xdc\xfe\x10\x1f\x4d\xb6\x0b\xd6\x60\x16\xe1\xee\xbb\x6b\xfb\xd9\xcd\x83\x04\x2d\xd1\x37\x9a\x46\x4f\x40\x5a\xaa\xe3\xc1\x18\x07\x84\x8c\xc4\xf9\x5c\x3c\xc6\xfa\x92\xab\x4e\xa5\x30\x58\x34\xeb\x86\xb8\x73\xfa\x30\xed\x1f\x7f\x47\x0b\xf6\x63\xf1\xa7\x0c\xf9\xe6\x0a\xb6\x80\xcd\x1d\xbb\xd0\x3a\xc0\x43\x3b\x3d\x4b\xb4\x82\xf8\xb3\x44\xd4\x6b\x3a\xa9\x34\xb8\x63\x3f\x57\x09\x0b\xea\x5f\xcc\xca\x64\x88\x79\x98\x35\xf1\x33\xf8\xbc\xf6\xe8\x87\xca\x59\xd1\x90\x76\xd6\xca\x19\xd4\xe2\x83\x49\x05\x1e\x01\x6b\x03\xe9\xa9\x20\xf4\x12\x0f\xb5\x23\xd1\x37\x1d\x0e\x38\x46\x73\x19\x54\x3f\x12\x7e\xd9\x14\xb4\x3a\xd0\x62\x22\x6a\x53\x65\x82\xdb\x72\x8c\xcd\x76\xe9\x83\xf1\x17\x66\xa8\x86\x3c\x2f\x42\x4f\x65\x50\x8d\xcb\x26\xfe\x0c\x5a\x80\x0c\x35\x09\x39\x60\xa1\x21\x97\x6e\x30\x51\xe2\xef\x1a\x2a\x99\xc1\x2f\xb7\xbd\x8b\xc0\x37\xa4\x39\x68\x68\x06\xeb\x72\x01\x7a\x07\x1a\x91\xb3\xe3\x9c\x90\xe8\x6b\xc3\x35\xf9\xbb\x54\x3b\x12\x7c\x98\x86\x73\x8c\xb5\x38\x06\xb9\xcb\x3c\x25\x94\xc7\xef\xfc\x2a\x59\x20\xaa\x83\x4b\xe6\x5c\x49\xf4\x79\x64\xe8\x9e\xec\x74\x72\x8d\xe7\x71\xf3\xd6\x75\xde\x9d\x1e"}, -{{0x67,0x69,0xcc,0x8e,0x12,0x56,0x17,0xc2,0x2c,0xe5,0x72,0x37,0xa4,0xfc,0xa1,0x50,0x7f,0x94,0x12,0x34,0x66,0x1d,0xf7,0x43,0x28,0xd0,0x4a,0xb6,0x2e,0xf8,0x6c,0x47,},{0x05,0x11,0x2c,0xa6,0x0b,0xaf,0xf7,0x9b,0x49,0x16,0xc1,0xbe,0xe2,0xb9,0x39,0x0c,0x04,0x7a,0xf0,0x8c,0x35,0xeb,0xb3,0xc3,0x81,0xb9,0x74,0x8d,0x1d,0xd4,0xc4,0xfd,},{0xd3,0x9d,0x85,0x3d,0x2c,0x2c,0x5d,0x21,0xb5,0x87,0x1e,0xa5,0xa7,0x5c,0x04,0x10,0x48,0xd9,0x3a,0x47,0xdc,0x59,0x9a,0x5f,0xdd,0xc0,0x85,0x62,0x85,0xce,0x63,0x6f,0xcd,0xfd,0x85,0x64,0x08,0x3d,0x06,0xff,0x28,0x4a,0x52,0x4b,0xc6,0x33,0xcf,0xdf,0xc3,0xb0,0x37,0x16,0x3d,0x67,0x4c,0xb9,0xbb,0x5b,0xa3,0xbc,0x25,0xbe,0xd0,0x0e,},"\x68\x54\x89\x73\x9b\x98\x56\x47\x49\x58\x7f\xf1\xac\x96\xba\x68\x2d\xa3\x0b\x40\xa4\xde\x24\xf5\x4e\xc8\xb0\x83\xdd\xa4\x53\x33\x16\x21\x67\xcb\x3f\x97\xb2\xc7\x31\x4c\xe7\xa3\xf3\xf3\xd3\x19\xcc\xc3\x5b\xb6\xa9\xf0\x07\x7d\x56\x31\x61\xe2\x81\x46\x9c\xf0\x89\x68\xd9\xdc\xf7\xae\x5f\xff\x83\x0a\x5d\xb0\x0b\xc3\x80\x10\xe6\x66\x2d\x49\x4f\x3c\x86\x47\xc4\xf7\x0c\xe2\xd2\x9a\x9d\xa8\x46\x10\xa0\x80\xb5\x75\x9a\x3b\x58\x20\x52\xdf\xde\x66\xe4\xa7\xfa\x5f\xb2\x7f\x06\x50\x73\xfe\x72\x3d\x83\x70\x1d\x5b\xac\x06\xca\x43\xb4\x6d\x1e\x58\x09\x76\x70\xc1\x94\xa1\x3a\xf8\xb5\x73\xa3\x79\x1a\x96\x61\x55\x7c\xbc\x04\x27\x57\xab\x8a\xdd\x0e\xf7\xcf\x4f\x35\x43\x5a\x42\x12\x35\x3f\xcb\x3c\x20\x3c\x73\xdb\xc9\xd2\x68\x52\xd0\xe9\x17\x32\xe3\x62\x1c\xe8\x28\x92\x9c\xdc\xa4\xd9\x19\x20\x48\x75\x19\x22\xed\x22\x5e\xab\x29\x00\xcf\xf9\x71\xa2\xa2\xd3\x42\x46\x36\x48\xbb\xb1\x94\x43\x19\xa8\xef\x6d\x43\xdb\x62\x48\x0f\xbf\x1d\x72\x57\xd2\x26\x94\x53\x97\x93\xf2\x5c\x92\x79\x17\xca\xab\x25\xc1\x19\x3a\x2d\x2b\x23\xbb\x5c\xb8\x56\x9a\xef\xff\x4f\x0c\xa4\x23\xd1\x9b\xbd\x46\xfc\x5e\xf7\x52\x4f\xf8\xcb\x70\x6f\xfc\x47\x07\x65\x09\xc0\x5a\x81\x58\xaf\x77\xf9\x8d\xf6\xa9\xb5\xcb\x32\x44\xab\xa4\xb5\xc5\xf9\xce\x59\x7e\x7d\x29\xba\x07\x01\x3d\xca\xc1\x91\x1b\x6d\xe7\x11\x3c\x73\x6a\x40\x05\xc4\x59\x99\x29\x79\x01\x9a\x45\xb2\xdd\x80\x2a\x07\x66\x09\x09\xeb\x4c\xe2\x05\x40\x81\x70\xd8\x25\x45\xda\xcb\xa8\x68\x6d\xbd\xe9\x27\xdb\xc9\xc7\xd9\x62\x05\x8e\x9a\x95\xea\x66\xb8\xdf\xd3\xea\x43\x53\x57\xa9\x3c\x73\x94\x8c\xd3\x55\xf6\xac\x65\x52\x32\x3f\x17\xc2\xa6\x78\x66\x2b\xc0\xe9\x72\x6a\xd5\xa5\x25\x1d\xd2\x76\x47\x40\x4c\xbf\xe6\x1c\xea\xaf\xdc\xfc\x08\xa4\x75\xff\xd8\x7c\xb7\xf5\x97\xe5\x6a\xc1\x67\x04\x09\xdd\x94\x08\xae\x47\x70\x42\x0c\x6e\x5e\x6d\xd8\xe7\x48\xfe\x03\xa7\x2d\xc1\x28\x03\xd0\x27\x71\xd9\x2f\x47\xe6\xe7\x17\xcc\xc1\x44\xfc\x03\x72\x75\xb6\xf7\x45\xdd\x30\xda\x1a\x45\xd2\x9d\xb6\xd9\x07\x3e\xee\x50\x09\xcf\xd5\x46\x27\x33\x41\x4a\x49\x5f\x34\x9d\xb0\xb6\xdb\xf2\xce\xa9\xcc\xd5\x72\x38\xed\x5e\xe9\x1a\xd8\xbc\x86\x17\x9a\xd5\x69\x5a\x85\xa5\x04\x84\xe6\x17\x75\x1d\xe5\xef\x7a\x7d\x8a\x8d\xb9\x50\xa9\x8a\x6b\x7f\x7d\xee\x9d\x42\xa5\xdf\x69\x2f\xcc\xf5\x55\xc9\x40\xdc\x39\xcf\x2e\xac\x48\xcb\x9d\x15\xcd\xa1\x4d\xd2\xa7\xec\xc0\xb7\x6e\xbe\xc6\x8a\xd4\x17\x7d\x11\x17\xe0\x77\x66\xc4\x85\x90\xd4\x3c\xa7\x66\x28\x68\xeb\x97\x90\xac\x29\xf4\xf2\x39\x2b\x9a\x93\xf8\x97\x59\xe7\xba\x54\x6b\x92\x5b\xd8\x6f\x80\x7d\x8d\x16\xc7\xe6\x37\xdc\xc6\x66\xe9\x05\x90\xbf\x43\x0d\x98\x6a\x67\xf1\xb0\xc7\xc2\xc9\x49\x30\x84\x58\x69\xed\x8d\x8a\xdd\xe1\x8f\xc1\x88\x74\x56\x88\x1b\x4b\x26\xb5\x3d\xcb\xa7\xa5\x26\xf0\xec\xa1\x4e\x8b\xb6\x89\xd6\x6f\x0a\xa1\xb2\x53\xc3\xdc\xfc\xf5\x95\x40\xd5\xd2\xf5\xad\x61\x7f\x52\xc3\x09\x38\xa5\xa9\x2e\xa3\x85\x07\x7d\x75\xaa\x4a\xc0\x7a\xfc\x2b\x35\xfb\x8c\x1d\x5e\x78\xeb\x29\x5f\xc2\x0f\xe3\x7c\x41\xac\x06\x95\x9d\x3a\x17\x97\x84\x3a\xd7\x05\x6c\x1b\x41\x2d\xd0\xb4\x80\xaa\x3b\x39\xbc\xc2\x05\x87\xd9\xa0\xfe\xf9\x2c\x6c\x95\x0e\xbc\x5b\xb8\xe1\x42"}, -{{0x1d,0xf7,0xac,0xfb,0x96,0x33,0x04,0xe5,0x1e,0xc4,0x71,0xca,0xf1,0x81,0x10,0x25,0x56,0x78,0x3c,0xb7,0xd9,0x1e,0xad,0x30,0xbd,0xc2,0x53,0x4d,0x07,0x8a,0x14,0x88,},{0x05,0xa3,0x1f,0xfc,0x70,0xe4,0xe3,0x56,0x9f,0xc2,0xbe,0x11,0x0c,0x64,0x3a,0xd5,0xf0,0x87,0x91,0x3c,0x7a,0xa4,0x76,0xdc,0xd8,0xd6,0xe4,0xbc,0x7e,0xc2,0x2d,0x24,},{0xb1,0x81,0x93,0x8d,0xe1,0x01,0x42,0xf3,0x24,0x07,0xb4,0xe7,0x86,0xcd,0xdd,0xe9,0x32,0xeb,0x11,0xdb,0xc0,0xbf,0x0e,0x5a,0xc5,0x09,0xfa,0xe7,0xa5,0xbc,0xc3,0x29,0x61,0xfe,0x34,0x48,0xf9,0x12,0xc8,0x50,0x0f,0xc6,0xdb,0x4e,0x1d,0x32,0x62,0xa8,0x3c,0x9d,0xbe,0x76,0x9b,0xb8,0xc3,0xa7,0x61,0x00,0x0f,0xe3,0x6c,0x0d,0x71,0x04,},"\xb0\xc3\xee\xb5\x7f\x14\x60\x6a\xb7\xab\xea\xb2\xee\x05\x73\x84\x3c\xa2\x2e\x6d\xb2\xfd\xf2\xc9\x06\x4c\xea\x51\x98\xdc\x58\x30\xeb\x15\x8d\xa8\xe2\xda\xa8\x88\x57\xaf\x8b\x8e\xef\xcc\xf0\xc2\x6c\x3e\xc0\xf3\x30\xe9\x2c\xff\x06\xbc\x05\xa2\x9b\xfc\x99\xf9\x40\xb6\x1f\x3c\xfb\x29\x64\xb3\x37\x09\x7a\x65\x50\xa3\xe9\xa3\x28\xc8\x5b\xe6\xf1\x60\xd2\xc0\xa5\x7f\xf6\xf1\xb3\xc5\xff\xcc\xa8\x90\x89\x42\x5a\xb6\xbe\x01\x72\xe1\x75\xba\xf4\x0c\xf1\x2b\x24\xa8\x15\xf7\x0f\x29\xa3\xa4\xcd\x0a\x6a\x13\x2f\x12\x00\x97\x75\x2f\x4b\xc7\x43\xed\xe0\x8f\x5f\x21\xd4\x2f\x28\x2f\x76\x71\xf7\x78\x3e\x27\xb2\xa8\xe2\xc1\x46\x92\xf1\xe0\xe5\xde\x82\x85\x5d\xab\xf9\x8a\x1a\x63\x97\x60\x06\xff\xbf\xe5\xf5\xa5\x79\xb4\x60\xe2\x6d\x06\xbd\x54\x28\x42\xa5\xf9\x26\x1b\xbf\x26\x04\x51\xd2\x32\x1c\x50\x89\x32\x01\x3c\xc6\xe9\x04\xf7\x9b\x5e\x46\x86\xd0\x33\xe1\x2c\x7b\xbd\x7e\xb1\xc9\x23\x79\xc5\xec\x34\x1b\xf6\x45\x7a\x3f\x17\x26\x4a\x7c\x27\x8b\x27\x50\x1e\xca\xed\xc3\x61\xeb\xa8\x44\x44\x23\x42\xb4\xb1\x0f\xa9\x4d\x26\x58\x65\x11\x6a\xcf\x43\xfc\xbe\xc9\x65\xd2\xab\x4b\xbb\xe6\x14\xc4\xf9\x0a\xb6\xb3\xe0\xd5\x38\x3f\xa0\x49\x88\xbf\xbb\x26\x03\x07\xdd\xe2\x2d\x84\x09\x8b\x63\x31\xd1\x55\x14\x1a\x92\x7b\xb7\x8d\x66\x4b\x34\x1d\x2f\x2a\x93\xe2\x91\xcf\x79\xba\xae\xcd\x26\x12\xf6\xb1\x04\xf3\xfc\x81\x37\x3a\x7c\x6a\x04\x5b\x59\x24\xbf\x95\x0c\xd5\x42\xf7\xb7\xac\xce\xf3\xaa\x7d\x72\x5d\xe0\x53\x05\x5d\x95\x1b\xd7\x68\x11\x13\x92\x59\x66\x38\xae\x09\x71\x70\xf4\x49\x2b\xa5\x0a\x46\x8f\x8e\x34\x77\x63\xdb\x61\x2d\x3c\x7d\xe7\xe5\x64\x59\xb2\x6e\xe0\x29\xc6\x30\x82\x7a\x35\x3a\xee\x73\xde\x68\xd6\xd7\x2b\x27\xaf\xd7\x5d\x22\x16\x45\x27\x94\x5c\x72\x26\x84\x4f\xab\x15\xb8\xdc\xc9\x14\x34\x9e\x31\x41\xc6\x13\x16\xad\xc8\x94\xde\xdc\xdc\x84\x39\x84\xd9\xc7\xfe\xae\x39\xdb\x33\x2d\xc3\x93\xe9\xe8\x96\x1b\xbd\xe0\x71\xc3\xd2\x85\x8b\x3c\xb5\xf3\x3b\x16\x4a\x15\x61\x6c\x6f\xe1\xbb\xc2\x4a\x35\xf2\x13\x36\xd2\x61\xc5\xd8\xcf\x75\x9e\x27\xe2\x2c\x91\x01\xc4\xae\xbd\xe3\xe1\x26\xcf\x64\x6c\xa7\xb2\xe0\x31\x28\x09\x5c\x59\x76\xbf\x3f\x6e\x49\x1a\xf0\xf0\xb6\x40\xc7\x31\x09\x66\xac\x59\xc5\x9f\xbc\x5b\xfe\x05\x48\xf8\x8e\xe6\x1a\xd9\xec\x40\xc1\xc0\x6d\xd2\x9d\x79\x4c\x44\xa3\xea\x22\xc3\xd4\x76\x26\x22\xec\x1e\x8b\x33\x3e\x45\x07\x4d\xb9\x37\x41\xfd\xa1\x93\xc9\x11\xf6\xdb\x58\x79\xe5\x5e\xe3\x6e\xf6\x02\x61\x4a\xe6\x4a\x5c\xde\x9d\x83\x06\xd2\x2f\xbc\x4a\xe9\xc8\x81\xa5\x94\xbd\xe6\x79\x61\x25\xfc\xb6\x28\xb9\xf3\xb6\xfb\x3f\xfd\x51\x1b\x35\x3f\x14\x6a\x27\x27\x2a\xfd\x3e\x5d\x28\xb7\x7f\x58\xa6\x7f\x1f\xd2\x72\x85\xc2\x5e\xcc\x1c\xcf\x64\xe3\x8d\x21\xf3\xb9\xff\x22\xe0\x0e\xe9\x00\x62\x9e\xf1\xa6\x3e\x71\x3f\x25\x88\x83\xdd\x91\x1f\x30\xc0\xd3\x98\xb7\x4b\xd7\x97\x14\x9b\xe5\xe2\x69\x67\x22\xda\x09\xd5\x2d\x4e\xbf\x3c\x67\x39\x29\xd2\x98\xaa\xc3\x4c\xe0\x5b\xea\x08\xea\x9a\x42\x4e\x93\x45\x9c\x2e\xb8\xfc\x22\x22\xc3\x1c\xc1\x3d\x80\x3b\x90\xa8\xa7\x0b\xcd\x0a\x30\xc2\x09\x21\x1d\xc2\xcc\xc8\x5b\x0b\xcd\x45\x82\xc6\x95\xf5\x8d\x80\xbf\x6e\xc4\x71\xa2\x50\x5f\x68\x84\x7a\x75\xf6\xe9\x11\xfd\x87"}, -{{0x7e,0xd8,0x7c,0x36,0xdf,0xdb,0xae,0x60,0xc9,0x40,0xa3,0xb3,0x25,0xc1,0x9f,0xde,0xd8,0x14,0xd7,0x6a,0x54,0x48,0x20,0xa3,0x2f,0x28,0x6a,0x5c,0x0a,0xd7,0x1d,0x72,},{0x3c,0x4a,0xc5,0x10,0xb3,0x62,0x22,0xc2,0x52,0xa2,0xdc,0x1a,0xfc,0xb4,0x0f,0xb0,0xeb,0x85,0xbc,0xa9,0x03,0x91,0x19,0x6a,0x58,0x83,0xaa,0x2c,0xc9,0x12,0xb2,0xdf,},{0x57,0x9b,0x38,0x12,0x4b,0xd0,0x59,0x1a,0x59,0x7c,0xc9,0xa3,0x89,0x12,0x7c,0xea,0xf5,0x51,0x56,0x07,0x73,0x63,0xed,0xb8,0x11,0xd0,0xb6,0x55,0x52,0xac,0xfc,0xc6,0x77,0xb2,0x72,0x94,0x21,0x99,0xca,0x25,0xab,0x79,0x0d,0xe6,0xe0,0x84,0x60,0x3a,0xd1,0x05,0x2e,0xc2,0x10,0xcf,0x6f,0xcb,0x14,0x17,0x28,0x90,0x67,0xce,0x3c,0x08,},"\x62\xd3\x13\x91\x2a\xbb\xb0\x06\xb7\x77\x4a\x67\x37\x71\x4a\x34\x99\x70\xce\x04\x21\x11\x2f\x40\x04\x63\xd3\xdb\x0e\x2f\x7f\x12\x8d\x7b\x96\x93\x9f\x43\xc1\xe7\x10\x7b\x51\x18\xa7\x7c\x11\x96\x83\xd8\x66\xb7\xe3\xd7\x2a\xc2\x1f\x6b\x42\x72\xb4\xbe\x92\x89\xb6\x55\x6f\xe3\x1b\x60\x51\xa0\xb4\x2e\xd5\xea\x0c\xf3\x47\x69\x6d\x30\xfb\x8b\xff\x6b\x8b\x57\x27\x19\xde\x19\xa2\x31\xcc\x85\x45\x9a\x99\x0c\x37\x80\x1f\x08\x37\x18\x6c\xef\xbb\x55\x21\x56\x96\x66\x96\x7c\xd4\x24\x3d\x73\x07\xf1\xb0\xb2\x4c\x8e\x2b\x9b\x69\x23\x17\x30\x4f\xbe\x3d\xd0\xa2\x63\x65\x01\x91\xb3\x52\x16\xf5\x29\x16\x57\x3a\xf9\x05\x24\xf9\x1d\xb1\xa9\x24\x71\xd7\x58\xc9\x2d\xc6\xd1\x4d\x1a\x4b\x26\xf4\x1b\x40\x40\x3c\xa8\x7d\xcf\xab\xdc\xa4\x7b\x9f\xc2\x53\x35\x78\xf1\x61\xf3\xb0\x19\x9b\x5c\x69\x8e\x08\x07\x04\xb2\x1c\x9e\x61\x52\x69\xfc\xd0\xd4\x04\x39\xed\x8b\xc3\xbd\xfb\xc9\xaf\xb4\x4c\x11\xfa\x89\x27\x5f\x0e\xaa\xa5\xd0\x8f\xa9\x59\xd6\x37\x8d\x0d\xb8\x99\x10\xd4\x8f\x2d\x86\xa1\xeb\xfc\x5c\xbf\x10\xeb\x2d\x5a\xad\xf5\x1b\xbd\x83\x44\xff\x8b\xbb\x5b\x8a\xfe\x05\xa4\x50\x11\xb5\xe4\xb7\x2e\xb8\x64\xad\x26\x3e\x8a\x03\xa6\xc7\xf9\x8a\xee\xb3\x54\xf7\x30\xa3\x18\xaa\x30\xfb\x56\xd3\x3d\x80\x74\x8c\x98\xeb\xec\x15\x87\x8c\xcf\x3c\xe8\x22\xf6\x9d\x34\x56\x84\x3c\x40\x0d\xc5\x6b\x48\x1a\x95\xe6\x88\xb8\xa4\x73\x5b\xf3\x84\x3f\x58\x33\xdd\xa0\xef\xe0\x9e\x71\x75\xb5\x67\xc6\x61\x38\x7a\xfd\x2e\xbc\x07\x9a\x48\xe3\x49\x67\xec\x97\xb9\x27\xdf\xa5\x81\x88\x8f\x23\x1a\x98\xa7\xed\x33\x10\x3b\xfa\x8e\x8f\x9b\xa6\x51\x35\x27\x90\x0b\x39\xb8\x62\x31\xda\x79\x11\xa2\xfc\x93\x58\x88\xa7\x5f\x11\x29\x58\x4a\xff\xf2\x02\x52\x49\xc4\x18\x8f\x09\x05\x2f\x85\x68\x77\x06\xd0\x5e\x29\x91\x44\xd4\x0d\xe8\x89\x8b\x7c\x8b\x2d\xfe\xf0\xc3\x70\x85\x73\xd8\xb0\x56\x3a\x6b\xd0\xa5\x04\xc0\xb6\x74\x57\x02\xb1\xb5\x71\x21\xc6\xf0\x40\xaf\xf2\x71\x98\x94\x8b\xa6\x9c\x21\x25\x3a\x28\xd3\x9e\xba\x72\x62\x19\xbe\xda\x1f\x82\x09\xfb\x83\xe9\xad\xb0\x7a\xd4\x09\xfb\xd6\xd2\x55\x65\x88\x9a\xb4\x51\x23\xf9\xd9\x45\xec\xd7\xd9\xca\x70\x28\xec\xe0\x92\xe3\x5f\xbb\x7c\xb3\xf3\x28\x12\x6e\xfd\xda\xc5\xd8\x59\xf2\xb2\xc6\xeb\x09\x01\x33\x69\x0e\x20\xc1\x7d\xea\xf3\x88\x26\x85\xf0\x7e\x9e\xd2\x65\x3b\x80\x3b\x9b\x38\x3b\x70\x74\x8a\x1f\xa9\x2c\x86\xf8\x6d\x6c\x47\xea\x87\xb1\x0b\x12\xe3\x63\xba\x50\x80\x60\xf4\x7c\xe2\xa2\xf3\xb6\xa3\xee\xfc\xd4\xda\xcf\xc7\x1c\x41\xf4\x36\xfe\x0c\x2b\xc3\x4d\x4b\xaa\xd4\x95\x74\xe7\x44\x3c\x12\x6a\x58\x9f\x6e\xf7\xbc\xa4\x49\x54\xf0\xbb\x28\xec\x71\x51\xb0\x51\x1c\x23\xc6\xbc\x42\xd5\xe8\x59\x83\xec\x16\xbb\x5f\x50\xa3\x82\xd6\x88\x15\x0a\x49\x60\x9c\xbd\xe5\x69\x8e\x86\xdc\xbf\x02\x12\xc2\x29\x22\x99\xdc\x4d\xcf\x87\x42\x9f\x6c\xd2\xee\xc8\x09\x48\xce\x86\x7e\x25\xc9\x45\x84\xcd\xc6\x4b\x09\x90\x29\xeb\x85\x4e\xdc\x26\xea\x21\x42\x1e\xff\x48\xcf\x4e\x41\xf4\x9e\x2d\x89\x47\x8d\xef\x06\xc4\x2b\xea\x22\x0a\x13\x3e\x50\xf5\xc7\x44\x64\xc7\xe7\x3f\xb1\xc1\xa7\x7c\x50\x7c\xf6\xcd\xa8\x5b\xe4\x02\xb7\xe6\xd6\xd2\x1e\x81\x0d\x6d\x0b\x59\x72\xb9\xfe\x77\xe5\x4e\x74\xae\xe1\xf3\xbb\xfd\x6e\x7d\xe6\xb5\xc0"}, -{{0x6a,0x29,0xf8,0x1b,0x8d,0x9a,0xa4,0x8a,0x1b,0x23,0x36,0x4e,0xac,0x8f,0x6a,0x4b,0xdd,0x60,0x7a,0x84,0xcf,0xe8,0xe8,0x8d,0x90,0x17,0x5d,0x80,0x64,0x3a,0x58,0xa8,},{0x4c,0x3b,0xe3,0xa2,0xa8,0x42,0x5f,0xf3,0x1c,0x3a,0x0d,0xb4,0xa5,0x2a,0x0c,0xb1,0x41,0x6c,0xeb,0x48,0xcc,0x3e,0x4c,0x28,0xa4,0xf2,0x28,0x4a,0xb3,0x46,0x07,0x15,},{0xdf,0x09,0xcb,0x9b,0x87,0x8d,0x3d,0xc9,0xe5,0x42,0xdb,0xac,0x28,0x94,0x3e,0x28,0xe4,0x1d,0xce,0xcb,0x92,0xcb,0x7e,0xa4,0x40,0x09,0x88,0x5e,0x46,0x49,0x97,0x43,0x33,0x05,0x61,0xba,0x1d,0x36,0xae,0xdd,0x46,0x76,0x75,0xfd,0xca,0x2b,0xaa,0xa4,0x70,0x1b,0x6f,0xad,0x97,0x9f,0xd8,0x39,0xc4,0x70,0xd1,0x3c,0x82,0xda,0xa9,0x05,},"\x78\x76\xa3\xf4\xeb\x69\xbb\x7e\x54\xe9\xff\x95\x4e\xbd\x3b\x10\xb9\x3a\x4c\x1a\xfe\xae\x92\xfa\x03\xc1\x03\xcb\x63\x13\xa2\x01\xc5\xb3\x3a\x9a\x72\x23\x75\x5c\xb5\x10\xe2\x5e\xc5\x82\xb5\x4e\x81\xb8\x49\x56\xf6\xc5\x3f\x1f\x08\xa6\x3b\xf0\xc4\xa2\x61\xaf\x45\x0e\x52\x3f\xe8\xf6\x1d\xdb\x3c\x0e\xea\xb8\x75\x10\x72\x68\x88\x01\xb2\xa4\x73\xb7\x1a\x2e\x38\x70\x8d\xa6\x8c\x2f\x37\x92\x5c\xb0\x5a\x20\xc4\x28\x3b\x3a\xf9\x7b\x6f\x0b\xa6\x5a\x54\x03\x55\x43\x75\xe2\x15\xd9\xe3\xaa\x1b\x0f\x9f\xdb\x0f\x84\x99\x23\xed\xbd\xaa\x0a\xb4\x81\xc5\x45\xa5\xdf\x8f\x51\xd1\xf6\x8b\x22\x35\x07\xea\x0e\xcc\xfa\xeb\xb5\xfc\xcf\x5e\x3d\xfa\x65\xa4\x4e\xea\x50\x45\x68\xa8\x81\x80\xa0\x60\xbb\x06\xc5\x15\x57\xb8\x1e\x66\x7b\x4b\x04\xe3\x21\x0f\xa4\xc3\x79\x87\x6c\x49\xf3\xe5\x6b\xf2\xbe\x1c\xf5\x19\xa7\x41\x83\x93\xd2\x40\xdc\x8a\x22\x4c\x6c\x38\xac\x2a\xb9\xd8\xfa\xdf\xc5\x36\x20\x30\xc7\x93\x0c\x3c\xe7\x79\x5b\x14\x7c\x26\xc8\xa2\x8c\x65\x34\x29\xd9\x0a\x17\x3a\x86\xa8\xb1\x8a\x00\x9e\x62\xae\xf6\xec\xa9\x5d\x39\xbd\xbe\x45\x64\x77\x78\xa2\x53\x2a\x41\x5a\xe1\x9b\xad\x23\x11\x29\x12\x78\x42\xfe\x1d\x0f\x11\xfa\xb4\xa1\xcf\x0b\x17\xe4\x98\xcd\x59\x52\xc9\x39\xe0\x90\x09\x02\x87\xb1\x44\x89\x5d\xff\x00\xce\xc8\xd6\xae\xda\xf6\x24\x81\xa4\x17\x83\xe0\x21\x08\x2c\xe3\x52\x06\x3e\x62\x81\x1f\xd9\x99\x90\x10\x4d\x8a\x46\xcd\xca\xee\x2b\xab\x45\x8e\x52\x47\xfb\x02\x3e\x92\x33\x30\xa4\x28\xc7\xbc\xfd\x20\xb0\x8f\x52\x0e\x89\x46\xdd\x65\x83\x47\x35\x2a\xe0\xc4\xbe\x73\xc3\xd5\xec\xcd\x11\x14\x9f\x3a\xb7\xb8\x05\x2c\xfd\x95\xc3\x5d\x41\x64\x54\x6f\x5d\x8f\x37\x75\x17\xa7\xf4\x32\xc0\xd5\x56\x3a\x7b\xcc\x7b\xd1\x19\xd3\x42\x1d\xfe\xba\xae\x84\x45\x99\xb2\x9b\x38\x3b\xb8\xd5\xdb\xf1\x40\xd9\xbd\x47\xa0\x78\xb7\xae\x7c\x6a\xa8\x7b\x1e\x29\x23\x6c\x9f\xcf\xd6\x54\xb7\xf8\x09\x79\x4c\xcc\xb2\x61\x58\x8e\x18\xde\xc6\xc4\x04\x6a\x93\x40\x67\xd0\xdf\xa0\x37\x91\xd0\x3d\x83\xb7\x18\xac\x4d\x24\xdc\xe7\x85\xa3\x02\x8d\xe0\xc9\x59\x2d\xba\x7c\x5c\x58\x45\x18\x4a\xfc\x9c\x0d\xfc\xf9\x40\x95\x86\x0f\x0e\xb8\x02\xeb\xea\x20\x17\x8e\x78\xb5\x64\x2e\x5d\xd6\x1c\x33\xb3\x97\x69\x05\x2d\x9d\x85\x4d\xce\x90\x2f\x47\x6e\x21\xf9\x6c\x65\x0b\x46\x3b\x7b\xc3\xd0\xff\x29\x96\xb6\x5c\x57\x83\x1f\x8b\x7c\x0f\xb9\x15\xf4\xdd\x72\x26\xac\x95\x5c\xbc\x7d\xfb\x03\xf9\xb7\x58\xdd\x3e\x0d\xfc\xe2\xe0\xe5\x80\xc9\x1a\x30\xc7\x83\xff\x56\x7b\x17\xf1\x2d\xfd\x5d\x31\x37\x64\x6e\x20\x01\x1c\xdc\xaa\xe1\x11\x02\xdc\x71\x68\x86\xcb\xf1\x23\xc0\x94\x88\xb1\x73\x63\x6a\xbd\x54\xe9\x62\xca\xee\xc9\x7d\x5e\xb9\x40\x68\x2e\x70\x3b\x73\x0f\x61\x56\x2c\xd1\x4b\x9e\x65\x61\xb5\xe9\x3f\x60\xcd\x0e\x1e\x86\xd1\xa1\xb4\x71\x9c\x5b\x50\x82\x42\xbd\x6b\x2d\x9a\x54\x8f\x59\xbb\xb8\x75\x07\x59\x69\xef\x20\x32\xf3\x19\x6b\x8a\xec\xcc\x45\xa4\x4d\x9d\xbd\xaf\x87\x8e\xd1\x6f\x1d\x85\x5e\x89\x18\xed\x65\xa4\x5e\xe5\xc7\xfa\x32\xa1\xec\x69\x32\xa1\x59\xcf\xb5\x0f\xfc\x87\xbe\x06\xdf\xcf\x72\x28\xae\x88\x70\xcc\xd3\x57\xfc\x65\x6e\x33\xfa\x4b\x6b\x8b\x7d\x1a\x72\x15\x55\x3c\xab\xac\xc7\x0a\x39\xc9\x80\xb9\x71\xe5\x1a\x17\xed\x63\x18\xb4\x3b\x29\xbb"}, -{{0xef,0x12,0xdf,0x47,0x9d,0x98,0x3a,0xd9,0x6e,0x8b,0xa6,0x53,0x30,0xb3,0x6d,0x49,0xaa,0xdb,0x98,0x31,0x64,0xe1,0xc0,0xb4,0x52,0xb5,0x60,0xde,0xd1,0xd0,0x8d,0x60,},{0xf7,0x61,0xcf,0x28,0x26,0x92,0x7a,0x7c,0xda,0x8c,0xb0,0x4f,0xaa,0x2c,0x59,0xf8,0x42,0x5a,0x8f,0x7d,0x39,0x8f,0x76,0xe8,0x67,0x02,0x1c,0x95,0x1f,0x07,0x38,0x09,},{0x4c,0x80,0x10,0x86,0x6d,0x91,0x15,0xf0,0x52,0x93,0xb9,0x34,0xca,0xc6,0x81,0x04,0xcc,0x2c,0x34,0x37,0x56,0x8c,0xb9,0xd5,0xc5,0x70,0xb1,0xa8,0xbe,0xe7,0x06,0x60,0x30,0x75,0x53,0x70,0x33,0xbd,0x70,0x8a,0x9c,0x9f,0x3d,0x1e,0x25,0x19,0xa9,0x15,0xb1,0xc4,0xae,0x4c,0xcd,0xdf,0xcf,0x0e,0xd0,0xc0,0x49,0xd3,0x42,0xa0,0x2e,0x02,},"\xe5\x8f\x34\xda\xea\x75\x5a\xc4\xe4\x13\x33\xd6\xf0\xed\x01\x35\xf7\xdb\xce\x50\x30\x9b\xb1\x95\x6b\xc7\x1a\xcb\x12\xc7\x70\x67\xa6\x47\xff\xd8\x6a\xa5\x87\x0c\x0c\x00\x07\xe8\xf9\x95\xa2\x2b\x88\xc4\x67\xde\x22\x54\x44\x54\x42\x01\xc5\x57\x49\x5e\x25\x3e\x33\x19\xcc\x5c\xa3\x76\xd3\xe7\xcc\x1e\xb4\x67\x34\x6e\x52\xad\x95\x6a\x6f\xa7\x33\x72\x0b\x17\x11\x7b\x5b\x75\x85\xe4\xd5\x59\x40\x9a\xae\xfa\x95\x58\x0f\x91\xe5\x02\x01\x5f\x49\x7c\x5c\xdc\xb7\xd4\xd5\x61\xf5\x44\xef\xa3\x5c\x1e\x2a\x53\xb7\x2b\xdd\xec\xee\xc2\xd1\x05\x0f\x17\x7d\x48\x0f\x68\x74\x05\x66\x4d\xfd\xde\xc0\x6e\xee\x4b\xd1\x47\xa9\x12\xfd\xbf\x74\xf2\xa9\x5d\x1f\xd1\xe1\x12\x68\x69\x4c\xe4\xd4\xec\x4f\xff\xd6\xdd\xb3\x25\x4d\x36\x0f\x23\x6f\xab\x4d\x1a\x17\xf8\xd0\xd1\xa5\x11\xf9\x44\x69\x2f\x23\x96\x39\xae\x03\xd6\x4f\xac\xec\x65\x38\x42\x7a\xb7\x1f\x71\x27\xf4\xa2\x76\xf9\xbc\x45\xbb\xa6\x11\xdf\xcc\xe6\x44\x6c\xc1\x39\x68\x97\x6c\x8b\xb6\xd6\xfe\x21\x06\xd7\x05\x92\x2d\xca\xc9\x56\x96\x6a\x76\xd4\x8f\x2a\xff\x4b\x86\x51\x4e\x39\xa6\x7e\x16\x43\xfc\xc3\x21\x85\x80\x24\xe6\x93\x18\x98\x33\xc8\xad\x59\xb4\xb6\x25\x29\x8e\xba\xfe\x64\x62\x6b\x48\x0f\x32\x6f\x13\x40\x72\x3c\xb3\xd3\x83\xf4\xfc\xcb\xfc\x23\x7a\x3f\x4c\x4f\x7e\xcf\x0b\xa4\x36\xb3\x2c\x2f\xe3\x51\x79\xda\x93\x11\x1b\x48\xcc\x9e\xa2\x42\x02\xbd\xc1\xb2\xfb\x60\xa4\x31\x9d\xfd\x98\x64\x47\x0f\x73\xf5\x41\x37\x20\x6e\x0b\xf0\x07\xf5\xae\x88\xa8\x87\x47\x00\x8a\x60\xf4\x78\x9a\xd1\x67\x72\x4f\x17\x9c\x02\xb6\x3a\xed\x00\x25\x73\xd2\x8a\x6b\xcf\x88\xe0\x7c\xe8\xda\xea\x5d\x5f\x1a\xcf\x48\x7b\x4c\x5c\x16\xc2\xbf\xe1\x12\x31\xea\x5e\xa7\x63\xe8\xf3\x32\xcc\x73\xda\x1b\x2f\x8c\x19\x8e\xa8\x17\x3f\xd3\x3d\x4b\x2a\xe6\x9e\x5d\x4d\x1a\xad\xdd\xf2\xfd\x82\x1b\x85\xbe\x45\x15\x19\x62\xd1\xf9\x9d\xf8\x13\x08\x61\x88\x52\xad\x7c\xf4\x1d\x72\xda\x08\xa1\xb3\x9d\xf7\xd8\xb9\x94\xb4\xdd\xff\x37\xf9\xdf\xe8\xf3\x8c\xe3\x0e\x91\x06\x1d\x95\xd5\x8f\x7a\xe8\x26\xb0\x23\x85\x27\x2e\xc0\x9f\x01\xa7\xb3\xe4\xb3\x91\xd0\x9b\xce\xd6\x65\xda\xd6\x95\x05\xb4\x19\xda\x84\x81\xbc\x37\x92\xbf\x8b\x8e\x7a\xd6\x4b\x63\xf2\x45\x66\x6c\x8c\x32\xfd\x5c\x1b\x1b\x48\xc9\x95\x1e\x1c\x21\xa1\xeb\x5f\x50\x7c\xff\x13\x7c\xfb\x86\x2c\x2c\xc9\x87\x66\xe8\x78\xc9\x30\xa0\x83\x82\x8c\x9d\x8d\xb1\x8b\xf1\x67\x16\x68\x5f\x39\xd6\x57\x2a\x8c\xa8\xb2\xa5\x14\xf7\x70\x03\xd4\xe7\x5b\xc1\x54\xae\xbf\x14\x10\x37\x78\xf3\x65\xb1\xc3\xf0\x35\x41\xdd\xbd\x07\xd6\xe2\x3e\x56\x76\x2d\x97\x1e\xb0\x29\x83\xe9\x3c\x4e\x01\xba\x4b\x8a\x21\x78\x92\x8c\x43\x37\xd3\x02\xf3\x1c\x9c\xcb\x75\xb2\x49\xa8\x2d\xc9\x68\x21\xe9\x5a\x03\xab\x6b\x77\x0d\xf2\xc3\xdf\xdb\xf1\xfe\x97\x73\xf8\xbc\x1b\xc5\xb3\xaf\xa0\x44\x0b\x10\x25\x78\xf3\xd2\x13\xc8\xd0\x19\xcf\xf1\x24\xf7\x5c\xe4\xac\xcc\x8c\x66\x7f\xeb\x27\xc7\x51\xa6\x12\x00\x74\x81\x31\x04\xe0\xcd\x07\x0c\x9f\x5e\x45\x1d\xcc\xff\x4c\x80\xd7\x11\x07\xc9\x75\xab\xfa\xc0\x7d\x4d\x27\x0c\x72\x7d\x8a\x2f\xec\x34\x9b\x53\x39\x68\xe2\x71\x89\x2d\x2b\x62\xc1\x25\xfb\x79\x74\x60\x3c\x30\x5e\xa3\xbf\xa3\x0f\xb6\x10\xfc\x5a\x23\xeb\x68\xa8\x40\x64\x44\x39\x1a\x52\x13\x37"}, -{{0xf7,0x31,0x31,0x7c,0xf5,0xaf,0xfe,0x58,0x70,0x4c,0x4d,0x94,0x97,0xae,0x86,0x0b,0xbf,0x73,0x9d,0x0f,0xd9,0x6b,0x7c,0x02,0xef,0xb6,0x77,0x7b,0x3c,0x85,0x8a,0x19,},{0xd7,0xd6,0x38,0xae,0xcc,0xe1,0x46,0x1e,0x31,0x42,0x55,0xaa,0x29,0xd9,0xa6,0xb4,0x88,0xae,0xa1,0x39,0x6e,0x96,0x82,0x69,0x5a,0x47,0x0e,0xff,0x23,0xf3,0xed,0x84,},{0x2a,0x4f,0xea,0x98,0xf9,0x24,0x01,0x71,0xa1,0x82,0x3f,0x2f,0x69,0x35,0x20,0x62,0x67,0x2e,0x6c,0x6e,0x66,0x52,0xd3,0x88,0xa8,0x77,0x14,0xd6,0x47,0x99,0x5d,0xf7,0x5b,0x6e,0x1e,0xd1,0x74,0x6a,0xf2,0xad,0xf4,0xe8,0x06,0x13,0x5d,0x60,0x75,0x4e,0x60,0xfe,0xa0,0x32,0x12,0x8e,0x35,0xab,0xc1,0xf1,0x61,0x51,0x81,0x12,0x5f,0x0b,},"\x16\xf5\x1c\x59\xe9\xae\xfc\x26\xb0\xda\x5e\x00\x85\xeb\x2e\x2f\x1f\x85\x6d\xef\x97\x25\x76\x9e\x3a\xf1\x2f\x86\x09\x05\xae\x13\x3f\x65\x07\x4d\xa7\x6d\xbf\x25\xc6\x7f\x62\x57\xd2\xdc\x66\xc0\x5f\x9b\x31\xae\x17\x7b\x69\x92\x9f\xc1\x83\xb5\x88\xc5\x19\xbc\xa1\x47\x96\xa0\x89\x6d\x29\x05\xfd\x94\x2d\x7a\xb4\xa3\xfd\x95\x41\xa5\x52\x9f\x72\x9c\x58\x51\x41\x9b\x5f\xbe\xf7\xb1\x34\xd6\x76\x2e\xb9\x7e\x8a\x95\x1a\x8f\xf5\x2a\xa0\xd7\xe6\x74\x44\xd0\x6b\x07\xaa\x55\xe4\xeb\x9a\xb8\x92\xf4\x7b\xfd\x11\x1d\xf5\xb6\x2f\x6f\x3f\xd1\xa5\xed\x84\x12\x5f\xee\xbb\x77\xda\x63\x7c\x05\xd5\x26\x5c\xed\x11\x3d\xfe\x87\x82\xdb\xd1\xce\xcd\x2c\x6c\x03\x2b\x8f\xa8\x85\x5b\x3a\xe7\x8d\xe7\x4f\xaa\x5a\xa2\x0a\x76\x14\x63\xc2\xa3\x0b\xe6\x6b\xd3\x8c\xde\xc7\x5f\x89\x57\xcb\x94\xc1\x13\xa4\x5d\x54\x6d\xaf\x47\x5d\x89\xaa\x14\x82\xf8\xd2\x80\x3a\x23\xc9\x39\x20\x20\x15\xa0\x8e\x94\xb1\x32\x72\x8f\xbe\x8f\x60\x19\xd7\x16\x8a\x08\xa5\x93\x01\x70\xe5\x63\x9d\x11\x0e\x47\x39\xdb\x85\xe6\x1e\x64\x49\x59\x44\xb5\x42\x3a\x74\xad\x5a\x8a\x0a\x51\x06\x12\xec\xe6\x55\xce\x18\x86\x40\x51\x52\x5b\x90\x8e\x0b\x19\x29\x0a\xbe\x8b\x11\x82\xc4\x8c\x70\x0d\x35\x05\x15\xfd\x34\x99\x56\xe8\x08\x73\x27\xf3\x0b\x6f\xc3\xf1\x31\xc2\x14\x4a\xbb\x3f\x0e\x9c\xa3\x31\x17\x2b\x35\x06\x4a\x82\x81\x1a\x68\xe2\xcf\x36\xb4\x3e\x3a\xd2\xe8\xdf\xa5\xb1\xce\xf5\x0e\x2a\x60\x29\x3f\xc5\xf6\x35\xc9\xa9\x99\x8d\x8c\x1a\xd2\x96\xe7\xc7\x8f\xc0\x58\x20\x22\xd6\x30\x67\x18\x6b\x65\xe7\x64\x82\x8c\xc0\xf5\xf7\x63\x2d\x5e\xef\x86\x3e\x6c\x6d\x90\xe3\x8c\xcc\x87\xd7\xb7\x47\xfa\xc8\x49\x1d\x63\x2c\xf7\xf5\x4b\x9a\x9e\xed\x16\xee\xbe\xc0\x1b\x6c\xc3\x3d\x24\x63\xf7\xf9\x50\xd8\x28\xb5\x5e\xe3\xf7\x7c\xbe\x97\x4f\x48\x94\x8e\xb7\x57\xae\xd4\xe0\xdb\xb0\x0a\xd9\x5e\xe0\x13\x23\x48\x6e\xba\x3c\x8d\xa8\x86\xed\x7f\x57\xbb\x40\x0d\x63\xa1\xb2\xeb\xea\xa2\xe7\x0a\xdf\x03\x79\xe3\x39\x30\x01\xba\x62\x6c\x0d\xd5\x4b\x7f\x0c\x9a\x25\xaa\xe6\xc9\x87\x5d\x4e\x76\x22\xf3\xed\x42\x8f\xb3\x12\x4b\x29\xc5\xdb\x9a\x7e\xf1\x6e\xbd\xdd\x68\x05\xf0\x95\xf5\xe7\x69\x82\x3c\x43\xf2\x62\x86\x8f\xf4\x3e\x3e\x05\x25\x74\x6d\x94\x97\xaf\x12\x4a\x01\xdf\xf6\x1e\xc7\x18\xaf\x3b\x5b\xb7\x46\xfc\xc0\x8a\xeb\xd1\x66\x84\xd4\x56\xae\x79\x32\xff\x5e\xd7\xd6\xb0\xf1\xb2\x5c\x7a\xde\xef\x59\x8b\x5d\x58\x87\x75\x90\xac\x1d\xc0\x59\x75\x15\x67\x96\x99\x87\x74\x08\x1e\x5b\x66\x82\x2a\x94\xa6\xa8\x02\xc3\xa2\xcd\x9f\x48\x9e\x16\x28\xaa\xf4\x65\x2b\xe1\x18\x4b\x0f\xc7\xc5\xee\x7f\x97\xce\x08\xb9\x23\x3b\x4b\x83\xd9\x36\x7b\xe5\xf4\xaa\xe9\x78\x25\x93\xa3\x52\x65\x15\x4d\xea\x4c\x37\x5c\x16\xf0\xca\xf6\xdc\x45\x94\xd2\xbd\xbf\xc3\x37\x5b\xb2\xa0\x43\x2c\x48\x2f\x13\x94\x1c\xe2\xaa\xab\x4d\x83\xe7\x4d\x11\x6f\x5d\xe4\xab\x28\xf8\xdc\x3d\x1c\xd1\x9d\x27\x1e\x56\xe1\x03\x98\xbd\x1d\xf5\xc8\x70\xfc\xbf\x93\xa7\xd1\xdf\x39\x39\x54\x7c\x10\x7b\xfd\x90\x64\x3f\x6f\x50\x01\xae\x7e\x06\x39\x7a\xe1\xa2\x71\xbb\x82\xa1\xf3\x8e\x09\x7b\xec\x66\x74\x66\xb8\x0e\xe3\xe5\x0d\xd4\xfc\x9d\x5d\x54\xf1\x8f\xaf\x7a\x5b\x55\xa8\x83\x45\x94\xef\x0c\xb7\xe5\x08\xbb\xd2\x8f\x71\xfd\x34\x23\x5b\xbf\xd3"}, -{{0x49,0x8e,0x5a,0x21,0xa9,0xb0,0xc3,0x47,0xba,0x83,0xa4,0x7a,0xc1,0x00,0x69,0x45,0x7f,0x57,0x83,0xc2,0xe1,0xe6,0xe4,0x64,0x00,0x45,0xe5,0x94,0xb1,0xc6,0x93,0x32,},{0xfb,0x39,0x48,0xc8,0x11,0x99,0x56,0x91,0x05,0xcc,0x1b,0x7d,0x9c,0xeb,0x3b,0x41,0xa3,0x43,0xbb,0x00,0x57,0x55,0x38,0x59,0x2e,0x09,0x84,0xf4,0xf4,0x71,0x0a,0xbe,},{0x28,0x60,0x83,0x0c,0xcd,0x1d,0x41,0xd9,0x50,0x76,0x81,0x6a,0x39,0x84,0x24,0xf7,0xb7,0x39,0xc4,0x9f,0xda,0xcf,0x56,0x54,0x52,0x9d,0xa8,0x5f,0xe3,0x56,0x55,0x84,0xf6,0xaa,0xc2,0x61,0x4c,0x63,0xf7,0x74,0xb6,0x1d,0xb9,0x08,0x1f,0x14,0x10,0xfb,0xa8,0xe5,0x0a,0xb3,0xb4,0xc3,0x9d,0xc0,0x63,0x14,0x24,0x3f,0x3f,0x0d,0x8e,0x0f,},"\xe4\xfb\xea\x86\x4a\xa5\x11\x90\x82\x66\x45\xd2\xf7\x72\xcb\x0f\x9e\xdd\xd3\x03\x44\x73\xfa\x31\x77\xc7\xaf\x9a\x5d\x41\xe1\xa7\x3a\xd5\x78\x4c\x70\x96\x55\x9f\xcd\xdb\x7b\x7c\x85\x89\x1c\xf2\x4e\x82\xc5\x88\xd7\x47\x74\xff\xca\xc0\xc6\xb4\xee\xbc\x2f\x3f\xa4\x3e\x9d\x45\xf2\x59\xd6\x75\x64\x03\x0c\xfe\xea\xb9\x23\x6c\x66\x5b\x65\x0a\xf0\xc9\x2c\x87\x51\x89\xf5\xf9\x38\x35\x04\xb1\x53\x60\xa0\xb9\xa5\xa0\x0d\xa3\x1f\x63\x5b\x96\xf6\xc7\x3e\xf4\x7b\x6b\x06\xf0\x28\x11\xd1\xd1\x9c\x2e\x8e\x53\x55\x0c\xe2\x2e\x42\xec\x50\xa1\xeb\x2e\xa2\xf4\xcd\x03\xc4\x42\xd4\xaa\x43\x68\x94\x23\x8c\xeb\x18\x35\xfe\x99\xb2\x40\x35\x8a\xa0\x56\x2c\x24\x96\x98\xa3\xf1\x23\xc2\xc1\x7e\x59\x10\x10\xbd\x6f\xdf\xcb\xd7\xdb\xe7\x0b\x04\x52\x05\x02\xec\xe3\x7a\x9a\x1d\xfa\x1a\xe3\x37\x04\x17\xb0\x04\x21\x7a\x5b\x8f\xe9\x90\x3c\x9a\x3b\x9f\x4b\x6d\x5c\x46\xc0\xed\x0c\x53\x8c\xec\x22\xf2\xdf\xcb\x2a\x28\x0a\x42\xad\xc4\x89\xcf\x2e\x06\x29\x12\xbe\x99\x28\xf0\xc0\x60\x89\x1e\x43\x20\x91\x17\x75\x26\xf1\xb3\xa9\x68\x06\x9d\x4a\x57\xad\xe8\x28\x55\x98\x10\xae\x03\x60\x68\x1f\xf9\x93\x29\xfa\x0f\x59\xe7\xe5\x9c\xdf\x87\xf9\xf3\x3c\x40\xe9\x70\x31\xb9\xf8\x1d\x48\xfc\x12\x28\x6e\xfb\xb3\xd4\xe5\xa6\x2e\xf5\x7b\xc0\xd5\x2d\x53\x3b\x99\xc5\x10\x6a\xa7\x9c\xfe\x17\x93\xa9\x08\x51\x85\x96\xc3\x83\x48\x3e\xc4\x9f\xf9\x8e\xc5\x57\xbf\xff\x74\x90\xa4\x6d\xaf\x67\x14\xf2\xc2\xc3\x2f\x57\x93\x2c\xa0\xd7\x30\xf0\x3f\x38\x1d\x69\xde\xcd\xbd\x9a\x7a\x6d\x4a\xfc\x62\x40\x65\x43\xc8\xeb\xe9\x0a\xc7\x6e\x6a\xfa\xbd\xb8\x24\x92\xa2\x06\xa3\x69\xe0\x42\x86\xd3\x13\xe1\x11\x07\xd8\xcd\x9b\x4b\xf6\x8f\x81\x5d\xba\x4e\x99\x0b\x04\x9d\x79\x21\x6d\x36\x53\x13\x83\x42\xcd\x11\x8b\x13\x0f\x66\xb0\x06\xf3\xd8\x9a\xc3\xcf\x89\x83\x70\x48\xb0\xf8\xa6\x2d\x94\x05\x1d\x2e\xab\x89\x1a\xc5\xf4\x78\x88\x87\x9d\x88\xe5\x46\x67\x6d\x1d\xae\xeb\x4d\x17\x5d\x3f\x04\xa9\xd7\x4f\xfc\xdd\x47\x74\x60\x16\xf8\x4a\xd0\xd1\x12\xaf\xb5\x9a\xd1\x21\x87\xe9\x4f\x22\x53\x5d\x77\xe9\xe0\x51\x6f\xa4\x21\x85\xc1\x97\xba\x77\x4b\x39\x32\x27\xf7\x41\xfe\x68\x27\x3f\x42\x3f\xb0\xe0\xe0\x47\x4b\xfd\xaf\x2d\xa7\x8a\xeb\x1c\xd5\xb9\x8c\x1d\xc0\x83\x21\x24\x74\x2a\x47\x54\x12\x5f\xc7\x8b\x19\xc5\x59\xa5\xb3\xf7\x71\x1e\x06\x8c\x44\x0c\xc0\x46\x9a\x1c\xfa\x5c\x18\x64\xbe\x18\x73\x5a\xa8\xbc\xd4\x06\xc4\x37\x1e\xb8\x57\x75\x4d\x90\x8b\xf3\x79\xb9\x1f\xcb\x24\xe3\x43\x96\xbf\x87\xc1\x9a\x04\xa8\x3d\x59\xda\xe7\x1f\x3f\x38\x39\x82\x9d\x06\x22\x13\x01\xef\x59\x56\x96\xe7\x19\xd5\x6b\x79\x52\x0a\x0e\x50\x99\x29\x83\x3b\x1d\x80\x4a\x6a\x0e\xa4\x04\x00\xbb\x45\x02\x8c\xe5\xd3\x69\x33\x88\x3e\x17\x40\x6e\x27\xa8\x10\x90\x57\xb1\xa1\xa5\xe5\xda\x21\x0a\x69\x21\x99\x4f\x46\x7a\xb4\x1a\xa8\xf0\xd8\x87\x75\xa8\xa8\xeb\xb4\xec\x77\xd7\xc8\x0e\x45\xa7\xbb\x42\x2a\x4c\x00\xc9\x05\x83\x91\x14\x65\xe6\xb5\xf0\xfd\xcd\xea\xb7\x28\x71\xca\x54\x2e\x1d\x1a\x2c\xa9\x4d\xf4\xed\x2e\xab\xf9\x0d\xed\x00\x45\x29\x03\x24\xa9\xff\xfb\x30\x14\x54\x70\x20\x9f\x38\x26\x58\x09\x89\x34\x91\x99\xdc\x5a\xb8\xd4\xa2\x5d\xf7\xa0\x52\x9c\xf9\x14\x71\xe3\x08\x42\xab\xfa\xcd\x44\xab\x78\x1d\xfc\x13\x95"}, -{{0xc2,0x4c,0xbf,0x40,0x1a,0xd0,0x3b,0xd8,0x8d,0xcc,0x7b,0x51,0x9e,0xcf,0x62,0x4d,0xb2,0x22,0x3e,0x99,0x02,0x89,0x30,0x9e,0x1e,0x9f,0x1f,0x8f,0x61,0x27,0xc6,0xc9,},{0xa7,0x46,0x66,0xf3,0x57,0x20,0x9f,0x71,0x89,0x90,0x37,0x88,0xf1,0x07,0x56,0x3e,0x50,0xc0,0x51,0xc3,0xd4,0x0c,0x3f,0x3d,0xad,0x10,0xd3,0xc3,0xcf,0xf1,0xe6,0x78,},{0x58,0x1e,0x6c,0x85,0xae,0xc6,0x23,0xb6,0x2b,0x3d,0x4c,0x9b,0xc9,0xc7,0x77,0x59,0xd5,0x49,0x27,0x22,0xe2,0x52,0xd4,0x4c,0x1f,0x8a,0xda,0x9d,0xa2,0xec,0xc6,0x7c,0x17,0x08,0x32,0x73,0xaa,0x09,0x1b,0xba,0xc0,0x46,0xae,0x63,0xc7,0x88,0x93,0x15,0x2e,0x14,0xd9,0x26,0xc4,0x1a,0xe3,0x5f,0x0e,0x6e,0x39,0x59,0x49,0x6b,0x13,0x06,},"\xe7\xfa\x35\x9e\x6a\x09\xb2\xc5\x4a\xab\xed\x3b\xba\xbf\xb7\x28\x53\xa8\x05\xaa\xbc\xf4\xd1\x8d\xda\xd3\x9f\x03\xf3\x46\x01\xe5\x5b\x6c\xe2\x63\xc9\xa3\xca\x6a\x3e\x5f\x14\x25\xc8\x21\x92\x8c\x61\xe7\xf7\x50\x91\x9b\xd3\xaf\x32\xbc\xb7\xb9\x4d\x45\x9a\x7a\x9a\x35\xf6\x1c\x94\x17\x92\xe2\xcc\x2e\x43\x27\xbe\xb3\x44\xa8\x41\xa0\x7f\x32\x06\x8a\xf1\x02\xb3\xde\x61\xea\xb6\x4e\xf6\xd5\xe6\x90\x62\xe3\x93\xab\x5e\xdf\x6a\xc9\xef\x7b\x38\xd4\x9a\x01\xbe\xf0\x00\x3f\x42\x11\x74\xc8\x88\x59\x75\xc0\x18\x32\x89\x9c\x31\x35\xe7\xa8\x6e\x5b\x55\xd9\xb1\x32\x8b\xb4\x28\x9b\x5c\x40\x20\x0f\x49\xe5\x52\x3b\x3c\x46\x1d\xc7\x17\x5e\x14\x65\x02\x22\x97\xc3\xd3\x80\xf2\xb1\xfe\xf3\x9c\xb8\x2c\x00\xfd\x16\x0f\x44\x7e\xb5\x12\x63\xfa\x25\xb4\xdf\x0f\xca\x41\xec\x0c\xa2\xec\xe7\x47\x22\x01\xaf\x86\xc3\x03\x8c\x49\xdf\x09\x9a\x9a\xef\xa1\xf8\x8d\x0e\xdf\xd1\x7c\x0b\x3c\x86\x04\x66\x29\xc0\x94\x54\x05\x4a\xa0\xfb\x2c\x69\x49\xdd\x9c\x13\x01\x85\xdf\xa5\xd9\x03\x89\x1e\x08\x74\x2c\xd0\x42\x94\x03\xf5\x7f\x40\x52\x15\x8b\x2f\x40\x1d\xa4\x75\x68\x54\xe4\xaa\xf0\x24\x22\x1e\x37\x51\x3c\xf6\x77\xee\x6a\x0b\x15\x9f\x50\x1d\x37\x7e\xa3\x2e\xb7\x1e\x77\x80\x04\xf2\x72\x03\xcd\x6d\x55\x3f\xda\x5d\x65\xe1\x87\x94\x77\x04\x6f\x3e\xa3\xd1\xd7\x5c\x9d\x0d\x30\x31\x14\x56\x70\x9c\xc7\xf6\xab\x68\xc7\xb0\xd5\x2b\xe4\x0f\x04\xcf\x65\x56\x55\x32\x32\x85\x31\x83\x29\xe8\x4c\x6a\x5b\x07\xe0\xce\xed\x5f\x78\xf7\xf1\xfa\x62\x29\xbe\xf8\x78\x79\x3c\x58\x47\x28\xab\xf4\x51\x0b\x7f\x27\x79\x4b\x59\x42\x91\x62\x54\xc5\x89\xa0\x9c\x8e\x91\x1f\x0b\x95\x42\x11\xa6\x36\x99\xa7\x52\x14\x7f\x2a\x4e\x1a\x18\x95\x66\x44\xbe\xa2\xca\x26\x92\xba\x18\x22\x80\xe0\x4a\x72\xdd\x89\xb0\xd1\x26\x85\x00\x93\x8f\x34\x7b\xf4\x3f\x2a\x24\x2e\xe9\xb9\xa6\xba\xac\x9b\x35\x0d\x65\x6f\xb1\x9e\xc8\x34\xab\xe3\x16\x44\x40\xf2\xd2\x07\x1f\xe5\xe3\x2c\x8e\x4c\xf9\x05\x53\x9b\x83\x9c\xee\xca\x26\x20\xfc\xb2\xa0\x87\xf7\x80\xe6\xc7\xf5\xe0\x5c\x50\x68\x88\x25\x0e\xa7\xc8\x56\xfb\x30\x98\x32\x00\xaa\x8f\x78\xfc\x17\x71\x05\x4a\xda\x0f\x3f\xac\x38\xae\x2f\x33\xdc\x4a\x4f\x85\x1b\x76\xed\x74\x0c\x09\x62\xa7\x6a\x4d\xe4\x40\x80\xdc\x62\x0a\x44\xad\x8f\x23\xd3\x46\x2b\x79\x2a\xb3\xaf\xb1\x9c\xb8\xa9\xf4\xd9\xe5\x9a\xd7\x65\xa7\x71\x89\x9d\xa8\xcb\xec\x89\xe5\x07\x7e\x85\xc0\xc9\x31\x26\x37\x6c\x94\x1b\xef\x1f\x8b\xb9\x92\xd3\xa3\x5f\x27\x07\x25\x84\x6f\xb2\x52\xf8\xb5\xfb\xb7\x56\x7e\x40\x6a\x1b\x53\xb6\x19\x76\x9e\x63\x2b\x2b\x40\x87\xcd\x4c\x27\x6e\x5d\x58\xff\x2b\x56\xe8\x9e\xde\xc4\x8c\xe5\x3a\x52\xe3\x29\xca\x15\x59\x53\x8f\x10\x90\x2c\x01\xa8\x5f\xbb\x3c\xd7\x2e\x6b\x82\x91\xe5\xfe\x63\x9b\xee\x9d\x47\xd3\x4c\x24\x9a\x7a\x07\xd7\xa1\x42\x7a\x01\xf6\x3d\x60\x98\x4c\x45\x0b\xef\x81\x9b\x19\xf6\x5e\x26\x14\xfd\x9c\x2f\xae\x7b\x92\x31\xa0\xbc\xa4\x14\xed\x94\xa5\xee\x7e\x66\x32\x7d\x2a\x99\xc8\x48\x78\xb7\xbe\xe0\x87\xe8\x91\xf2\x53\xfa\x1f\xec\xe3\x13\x64\x8c\x06\xc4\x5d\xb2\xd9\xf3\xbc\x85\x99\x93\x7b\x75\x2d\x38\xce\x50\x63\xd0\xed\x9a\x43\xec\x9d\x40\x15\x89\x3d\x43\xbf\x5b\x2d\x1c\x60\x47\x85\x10\x46\x89\x68\xb7\x96\xf0\x15\x37\x89\x59\x54\x41\x72\x2a"}, -{{0x8b,0x3d,0xcd,0xe4,0xab,0xbf,0x4e,0x62,0x11,0xc4,0xa5,0x1c,0x4b,0x02,0x68,0x00,0xa8,0xa2,0xa0,0x61,0xcb,0x38,0xa2,0xec,0xc7,0xc9,0xcf,0x11,0x3f,0x92,0x70,0xbf,},{0x51,0x45,0x35,0x58,0x0f,0x0d,0xe3,0x59,0xbb,0x0d,0x41,0xf2,0xef,0xdd,0xaa,0x04,0xc2,0xec,0x95,0x01,0x19,0xf3,0x16,0x34,0xb2,0xc1,0xa3,0x2f,0x19,0x5f,0x69,0x68,},{0x4f,0x3d,0x4d,0x22,0x85,0x03,0x01,0x7e,0x74,0xa6,0xbb,0x58,0xaa,0xfa,0xe3,0x5c,0x3f,0x37,0xbd,0xee,0x4f,0xf6,0xbe,0x2e,0x62,0x40,0xb5,0x08,0x2f,0xed,0xdb,0x22,0x27,0x35,0xe1,0x2f,0x31,0xe0,0x56,0xfa,0x68,0x54,0x47,0xe5,0x38,0x48,0x03,0x00,0x7e,0xa7,0x91,0x0e,0x60,0x5c,0x1b,0x78,0x11,0x8c,0xd5,0xac,0xc5,0x87,0xa6,0x06,},"\x48\x14\x25\x02\x7d\xa6\x72\xb6\xf2\x6c\x91\xb8\x0e\x55\x58\x2c\xae\xf4\x7b\xb1\x5a\x2d\xe8\xfc\xa8\x52\x22\x17\x85\x18\x0b\x20\xa7\xfd\x6d\x49\x07\xb5\x88\x1c\xc1\xd6\xe3\x9a\xb9\x61\x2c\xc7\x4d\x69\x77\xe9\x14\x1f\x70\x87\xbb\x27\xab\x30\x84\xa2\x62\x85\x58\x6f\x84\x11\xdb\x1f\x50\x3a\xdf\x52\xdc\xb2\x5a\xb8\xff\xfd\x2e\xc1\x50\x4c\x17\x77\xb9\xd6\xdd\x4a\x29\xe2\x01\x9e\x5c\xba\xe1\xb7\xeb\x26\xf9\x5b\xbe\x07\xd9\x0c\x2f\x6f\xb0\x88\x4a\x59\xa8\xd5\x8d\xde\x51\x16\xed\xc3\xbc\x34\x9d\x37\xc1\x60\xb2\x7b\xef\xbe\x5a\x5c\x18\x1c\xe7\x25\x63\x92\x35\x4d\x22\x1b\x58\xc4\x7e\xb0\xbb\x10\x92\x9e\x74\x21\x79\x5f\x4b\x7a\x7c\x27\x5e\xdd\x08\xc0\x88\x56\x87\x72\xe9\x93\x21\x8d\xd6\xf3\xc2\xcb\x4a\xc6\x57\xa0\xa3\xf9\x1f\x31\x26\xb9\x91\xad\xf6\xcb\xe7\xd1\xb1\x9b\x8c\xd8\x3b\xe3\x60\x2e\xd1\x8f\x03\x96\x33\xfb\xd2\x38\x7b\xda\x69\xe2\xcf\x03\x87\xd8\x64\x4d\x97\xb3\x03\xfb\x00\x63\x9a\xee\xe7\xae\x46\x3f\x6f\xe1\xa2\xc4\xb8\x9a\xeb\xa3\xe9\x09\x4c\x11\xfc\x29\x11\x4b\x20\x28\x3f\x28\x7c\x6d\xd2\x8c\xb0\x98\xda\xe8\xda\xbc\x48\xe8\x5b\xb5\x9c\x0d\xc6\xe7\x8c\x95\x66\x05\xcb\x7c\xf0\x69\x42\x35\x3e\x7a\x22\xe9\x6f\x80\xa3\x7a\x66\xf7\x18\xd9\xe4\xdb\x8c\x52\x45\x2a\xa0\xa3\x57\x72\xe8\x1b\xa2\xb3\x03\x20\x5b\x41\x2d\xd2\xbf\xc1\x5c\xe9\xb4\x36\xf9\x9f\xbb\x32\x12\x6b\x63\xce\x9c\xb4\x31\x99\xf1\x57\xd8\x17\x51\xa7\xc4\x93\x7d\x13\xaf\x4c\x58\x29\x52\xb5\xd6\x06\xb5\x55\xb0\x46\xbf\x1d\xe0\x6c\xf3\x9b\x63\xa8\x02\x87\x37\x18\x03\x60\x9a\x38\x7e\xe8\x0f\x3a\x5d\x88\xb9\xd6\x21\x96\x50\xed\x17\xd3\xcc\x18\x3b\x2c\x70\xd5\xeb\x94\xe3\xbc\x52\xae\xa7\xaa\x7f\x53\xbe\x0e\x20\xb8\x97\x2f\x14\x3d\x8e\x20\x16\x2e\x80\x3e\xdb\x4a\xa8\x3d\x55\x53\xfd\xd5\x53\x39\x8b\x0f\xa1\x76\xb9\x59\xcb\xa1\x40\xd6\xe9\x80\xc9\x25\x1b\x0f\xa0\xb6\x5e\x90\x84\x17\xf8\x2f\x45\x1f\xf9\xf2\xde\x6b\x9c\xa5\xe3\xb5\xf4\x1b\xa4\x0d\x05\xa5\x4f\x3d\xab\x48\x86\xaa\xcc\xa0\x5c\x9c\x27\x98\x13\x9a\x4c\xb3\x3e\x96\xa9\x14\x94\x74\x99\x10\xa1\x7c\xe8\xb3\x92\xfc\x0f\xc7\x76\x29\x74\xd7\x9d\x33\xdb\x92\x4b\xfe\xf8\x65\x5a\x72\x37\x76\xff\x87\xf9\x50\xfd\xc5\x68\xb1\xe5\x26\x53\x45\x41\xf5\x72\x72\x3b\x84\x06\x63\xc1\x91\x88\xc4\x24\xf7\xc4\x89\x23\x5a\x42\x4b\x09\xfe\x25\xc3\x07\x27\xea\x1c\xb0\x49\x53\xd7\x06\xd6\x8b\xfe\x12\x10\x0e\xf6\xf6\x4c\x35\xc6\xb8\xde\x67\xed\xf0\xe3\xad\x01\x4a\x40\x0e\x82\x1e\xa3\x40\x24\x32\x19\x99\x86\x7b\x43\xc8\x2c\x45\x01\x84\xb7\x8f\x74\x25\xce\xbd\x73\x19\xdc\x6f\x65\xd3\x60\x66\x5d\xfb\xe7\xc3\x66\x74\xda\xc3\xa5\x4e\x96\xda\x91\x0c\x02\xd3\x64\x07\x80\xb2\x2d\x51\x2c\xa0\xe3\xca\x35\x87\xb9\x4e\xa9\xfc\xd7\xa3\x1b\x4a\xf6\x9f\xd6\x20\x7c\x68\xfe\xd2\x5f\x89\x92\x1c\x1c\xdc\xde\xfd\x1c\x09\x02\x04\x49\x2b\xff\x9b\xbb\x52\xe0\x88\x85\x82\x9d\x01\x2b\xc2\xdf\xb4\xfe\x8c\x35\xe5\x9c\xd1\x3b\xcb\x8e\xad\x34\x19\x3c\x40\xb0\x3e\xe4\xd8\x25\xee\x13\x22\xff\x4e\xf0\x71\x27\x95\x74\xcb\xae\xe7\xc0\x7f\x14\xbe\x60\x6b\x9c\xd0\xe2\x61\x11\x1e\xf2\x0d\x96\x81\xd7\x6c\xf7\x8c\x89\xa8\xc3\x97\xd6\xb8\xdc\x77\x8f\x49\x84\x16\x6a\xd5\xdf\x3a\x81\xaa\xf2\xe6\xde\x09\xf7\x00\x19\x5a\xe2\xc1\xd4\x60\x96\x47"}, -{{0xd4,0xa7,0xa9,0x52,0x4d,0x30,0xa6,0x33,0x7c,0x0a,0x0b,0xe9,0x5c,0xa9,0x05,0x91,0xde,0x98,0x88,0x03,0x8e,0x3e,0x59,0xe1,0xb2,0x5a,0x41,0x81,0xef,0x94,0x66,0x29,},{0x9f,0xc3,0xeb,0xd1,0x39,0xcc,0x5b,0x7c,0x0e,0x05,0xaf,0x47,0xbf,0xf6,0x61,0x9b,0x81,0x28,0x15,0xbb,0x01,0xce,0xec,0x39,0x2a,0x3f,0xf0,0xae,0xc3,0x81,0x1d,0x2c,},{0xd1,0x57,0x88,0xbc,0xd8,0x8d,0x1d,0x81,0xb9,0xe6,0x1d,0x4f,0xe2,0x6e,0xa4,0x9e,0x66,0x81,0x9a,0x59,0xd2,0xae,0x48,0x32,0x32,0x1b,0x81,0x4d,0x50,0x62,0xfa,0xdb,0x87,0x80,0x7d,0xb6,0x85,0x2e,0x1d,0x82,0x95,0xe3,0x1a,0x29,0x1b,0x1e,0x78,0x5d,0x01,0xd8,0x34,0x89,0x5f,0x88,0xf4,0x00,0xdf,0x88,0x32,0xc1,0x60,0x7b,0x5b,0x0c,},"\x17\x19\x80\xc0\x3f\xdf\x7a\x72\x7b\xd5\xba\xb3\xba\x09\x45\xe6\xad\x5f\xaf\x0a\x7f\x50\x6a\x56\xd1\xd0\xed\xd9\xa3\x06\xb3\x15\x8d\x84\x32\x66\xd3\x09\x1f\xc1\xe4\x22\x81\xdf\x97\x55\x9a\x22\x01\xf5\xbd\xdd\xfe\x68\x3d\x0e\x10\x28\xd1\xd9\x5b\x2f\x31\x3b\x48\x4c\x39\x2f\xfd\xb1\xcd\xf8\x85\x08\xaf\xde\x3d\x6f\xd2\xa1\x28\x88\xba\xce\xde\xb7\x9f\xf3\xdb\x40\xc9\xac\x0e\xc3\xfb\x90\x1b\x22\x86\x98\xad\xf8\xd8\x45\xff\x4f\xce\x10\xde\x55\xd4\x24\x36\xdc\xe9\x30\x97\x3a\x34\xbe\x05\xd1\x40\x1f\x33\x4d\x4c\xe8\xe3\xa7\x93\x79\x9e\xaf\xdb\x94\xd0\xf2\xab\x09\x50\xb0\x79\xe6\x65\x3e\xeb\x49\x9f\xc7\x44\x7c\xcb\xee\xed\x8d\xbd\x54\x56\x80\x8c\xd7\xa3\x8f\x9a\x15\xa2\xa9\xc7\x38\xd6\x13\x34\xca\xb8\xce\xeb\xbb\xf4\xa4\x81\x4d\x94\xc6\x18\x59\x17\x87\x84\x60\x4e\x0c\x21\x54\x59\x7e\x72\xcf\x58\x7c\xd1\xf5\xda\xfe\x59\x22\x05\x18\x90\xe7\x6d\x61\x6d\x8c\xd5\xb0\x5d\x64\x78\xd0\x62\x6e\xa8\x3c\xe8\x08\xc4\x61\x43\xe6\xfb\x06\xb4\x18\x2d\x22\x8d\xa8\xf6\xd4\x13\x9e\xca\x5b\x8f\x3b\x1b\x98\xaf\x68\xc5\x9b\x4b\x5a\x53\xc1\x36\xee\x90\x43\x2a\xca\x2b\xb9\x15\x52\x9d\x26\x36\x79\x49\x82\x62\x33\xb4\x3e\x55\x80\x4b\x55\xfc\x9f\x21\x5e\xb0\xb0\xb7\x92\x91\x46\x5b\xb3\x4e\xda\xea\xdf\xfa\xbf\xe6\xcf\x41\xbc\x07\xb5\xdd\x4d\x01\x42\xf0\x36\x1f\x05\x8e\xe1\xb3\xb9\xfc\xc1\x96\xeb\x9b\x35\xb1\x34\xbe\x3d\x1d\x23\x20\x04\x48\x9e\x8f\x69\x93\xf6\x25\xa6\x30\x15\xbc\xd3\xf1\xe8\x75\x88\x32\x48\x58\xcc\xfb\x77\x0d\xdd\xd8\x94\xbf\x29\x7b\xd7\x63\xef\x58\x28\xe2\x1f\x5c\x89\xaa\x98\xcf\xbc\x1c\x08\x2d\xd7\xfb\xaa\x43\x07\xbd\xa4\x0b\x4a\x75\x8c\xa8\xf3\x9f\x4e\x4a\xae\xd3\x09\x04\x12\x68\xdb\xcf\x0a\xf3\x2d\xe0\xd7\xfa\x90\xa5\x23\x96\x3b\x78\x0b\x6a\x93\x2c\xf8\x94\x99\x02\x5f\x0e\x0d\x04\x74\xc7\x43\x48\x94\x75\x10\xe6\xc5\xec\x7c\x9e\x05\x06\x6e\xeb\x4a\x73\x52\x0c\x3d\x92\x7c\x39\xac\x26\xad\x75\x96\x32\x5b\x2c\xc4\x7c\x5e\x82\xa7\x75\x45\x5b\x7a\xf0\x31\x20\xb1\xcf\xbf\xd6\xec\x3f\xc0\xc3\xbe\x60\x78\xb0\x0c\xfd\xf8\x34\x2a\xe8\xbf\x14\x71\x59\xf5\x0e\x9d\x56\x4e\x2f\x68\x30\x6d\xae\x3c\xae\xdd\x10\x19\xf3\x23\xc4\x78\xa1\xe1\xf6\x75\x98\xdd\x83\x4b\xd1\xd1\xa8\x73\x3f\xd7\xfd\xd8\xa8\x76\x52\x6c\x53\x15\x18\x93\x6e\xdb\x72\xd0\x16\x56\xb3\x44\xc7\xd6\x5a\xc1\xce\xe3\x7c\xe5\x99\x7b\xa4\x8d\x3f\x4d\x06\x4d\x88\x05\x7e\xfe\x9a\x48\x2d\x9e\x00\xab\x5c\xae\xb5\xac\xa2\xd6\x60\xe3\x37\xbd\x15\x48\x73\x65\x69\x79\x56\xa5\xe4\x7b\x02\xab\xdc\x30\xd8\xe3\x53\xfe\xd4\xe1\xac\x41\xd2\xbc\x21\x20\x02\x11\x43\x63\x59\x35\xc6\x20\x18\x6a\x52\x2b\xde\x54\xbe\x04\x46\xfb\xd2\xdc\x88\xb5\x63\x04\xb3\xa6\x42\x27\xd0\xac\xd5\xf8\x5a\x6b\x67\x87\xa3\xad\xcf\x2d\x7c\xfc\x86\xc6\x34\xb4\xd7\xab\x43\x15\xb9\x7d\xe9\xe6\x66\xcf\xf3\xff\x1b\x88\xf3\x29\x5e\x7b\xab\x9e\x9f\xd4\x6f\xaf\xdd\xb4\xf5\xfa\xc5\x1c\xc0\x17\x01\x29\xc6\x51\xb4\xef\x4d\x39\x50\xd6\x94\x2f\xf0\x20\xd1\x66\x8a\x52\x8b\xde\x1d\xa9\x36\xc0\xec\x1a\xe0\x9e\x84\xf8\x20\x58\x61\xff\xf4\x91\x50\x2a\x87\x2c\x81\x54\xa9\x6e\x7e\xa2\x5e\xda\x95\x5a\x7f\xd2\xe4\xb4\xc7\xa8\xd2\x73\xf6\x0b\xc7\x4f\xab\x7b\x49\x68\xca\x6f\x75\xda\xea\x50\x40\xf8\x39\xfd\x56\xc2\xa9\x80"}, -{{0xd0,0x8f,0x4b,0xab,0xba,0x3b,0x53,0x65,0xfa,0xf7,0x38,0x79,0x5c,0x9d,0xa4,0x5d,0xb1,0x86,0x2c,0xb2,0x8b,0x93,0xeb,0x66,0x35,0xd1,0x32,0x0d,0xa0,0xf4,0xd9,0x37,},{0xef,0x31,0xb4,0x54,0xf7,0x34,0xe5,0x2b,0x34,0x38,0xee,0x2f,0x1c,0xbc,0x35,0x63,0x1b,0x19,0x69,0xde,0x54,0xac,0x98,0xfe,0x46,0x33,0xf2,0xf5,0x00,0xac,0x87,0x12,},{0xac,0xeb,0xe4,0xc8,0x6f,0xa9,0xfe,0x2c,0x1a,0x5c,0x57,0x6a,0xc0,0x50,0x1e,0x8a,0xb0,0xf6,0x40,0xfa,0x40,0x38,0x05,0x36,0xfc,0xf9,0x50,0x59,0xd5,0x3d,0x4a,0x35,0x55,0xd2,0x20,0xac,0x36,0x35,0x87,0x17,0x5e,0x4b,0xde,0x16,0x3c,0x0d,0x00,0x65,0x0a,0x12,0x96,0x3d,0x46,0x76,0x6c,0x99,0xbb,0x62,0xbf,0x75,0x73,0xe2,0x87,0x0c,},"\xa3\x94\xd8\x85\x4c\xeb\x5c\x43\xaf\xee\x1a\x48\x92\x6b\xbd\x66\x85\xaa\x8a\xec\xfd\xcf\x85\x41\x33\x33\x39\x74\xd6\x24\xbf\x2f\x1f\x9c\x30\xf0\x05\xbb\xf3\x4c\xee\x3a\xfe\x2b\x29\x06\x00\xee\xae\x6f\x1d\xd1\x2a\x0c\x34\x6f\xbb\x2a\xb9\xc9\x16\xc5\xd5\xd8\x0d\xcd\x87\x88\x78\x75\xa0\xac\x84\x76\x78\x03\x9f\xdc\xd3\xa9\x79\x35\x41\xf5\xd6\x75\x14\x3a\x6a\xba\xdc\x3b\x18\xf0\xfe\xf5\x10\x8c\x19\xc2\xdb\xfb\x59\x71\x0e\xef\x98\x66\xa4\xf3\xf2\x97\xa0\x9e\xe4\x8c\x68\x03\x00\x7d\xd6\xba\x8f\xd4\xbe\x84\x1c\xfb\x10\xff\x05\x14\xc3\x0f\xc4\xdd\x49\xa3\xcd\x43\xbb\xd1\x6e\x46\x04\x43\xa1\x1a\xfe\x64\x9e\x90\x1d\x63\xd8\x9a\xf5\x98\xaa\x68\x6b\x2f\x60\x7e\xc1\x1f\x35\xe1\x7a\x79\x8a\x42\x13\xb7\x5a\x38\x78\x8d\xa4\xf2\x7c\xf2\xb0\x2c\xad\xdf\xe6\x1c\x37\x29\xa8\x7e\xc6\xe6\xb0\x98\xf6\x8e\x7a\xed\x28\xa8\x00\xc4\x84\xdf\xa0\x13\x04\x01\x20\x8f\x98\x6d\x79\x2f\x54\x63\x5a\xdd\x28\x48\xe1\x51\x26\x2a\x36\x5e\xb2\x1e\x27\x27\x19\x1e\x1f\x70\x0f\x3b\xf5\xc7\x3b\x0f\xb4\xc5\x46\xd0\x04\x8a\x15\x5c\x18\x71\x79\x20\xfc\x04\x25\xc8\xc8\xfa\x8f\x16\x7c\x43\xa2\x77\xbb\x36\x6e\x0a\xd7\x02\xc8\x9b\xc5\xaa\x06\xfd\x47\x09\x43\xbe\x05\xcb\x9e\x32\x59\x78\x72\x29\x71\x4c\x30\xa4\xe8\x7b\x00\xa6\x33\xaa\xf7\xbe\x6b\x58\x75\x01\x0d\x12\xe1\x07\xc9\xa5\x26\x1c\xa5\x62\xd6\x70\x25\xbe\xa0\xfe\x22\x34\x63\xed\xb9\x2e\xa0\x1c\xca\x92\xc4\x4f\xf2\x4d\xa9\xd8\xa8\x0a\x64\x21\xf3\xd4\x13\x5d\x64\x7d\x1b\xb0\xfd\x98\x8c\x46\xc8\xa1\x70\xce\xb4\xf3\x3f\xff\x9c\x0f\xfb\x6a\xba\xd1\x09\x2c\x84\xdf\xad\x82\x90\x89\x8b\x24\x95\x16\xa2\x92\xe8\xda\x96\xfd\x51\xa8\x10\x05\xee\xcf\xde\xbb\x05\x93\x30\x99\x27\x7d\x07\x3a\x48\x0c\x3f\x9e\xb8\xaa\x11\x96\x8c\x4d\x8d\xc0\x78\x7a\x9a\xec\x3e\x05\x27\xb7\xfe\x4c\x06\x35\x41\x13\x35\xa1\x81\x16\x89\xe8\x8f\x6d\x5c\xed\x0d\x40\xd6\xb4\x8b\x7f\x2d\x99\x29\x52\x93\x48\x94\x15\x30\x76\xa8\xd3\x73\x72\xfa\x00\xd9\xce\xfc\x5c\xf8\xc2\x6a\xdb\x5a\xcf\x32\x5a\x01\xcd\x00\x5a\xb8\xd4\x74\xa5\x2d\x67\x11\x40\x78\xc6\x51\x6a\xef\x80\x4b\xba\x19\xb8\x87\xa2\x8e\xd5\xe4\x6e\xe9\x99\x5e\x5a\xd3\xa8\x2f\xb9\xcd\x93\x28\x34\x33\x68\x09\x21\x11\x4b\x4d\x9a\xf8\xfc\xb6\xb2\xb5\x35\x83\x9c\x36\xde\x8d\xf1\x2b\x17\xea\x6d\xdc\xfc\xb3\x33\x4f\xf4\x0e\x6c\xf0\x4c\xcd\x5c\xa6\x40\x3b\xa0\xb6\x2b\x4c\xb7\x1b\xbd\xe9\x1d\x8b\xab\xda\x69\x15\x2c\x9c\x93\xae\x76\x9b\x55\x29\xc8\xd5\x2f\xd9\xa6\x90\x9a\x15\xe1\xa0\x60\x1a\x71\x46\x49\xc9\x6e\xc9\x96\xc1\x70\x6d\x10\x21\xb9\x74\x87\x98\x0d\x7b\x2c\x2a\x39\xbb\xb0\xe4\x70\xd8\xe4\x6a\xc4\xaa\x60\x9a\x09\x22\xc9\xbd\xc0\x16\x12\xea\xde\xac\xcd\x5f\xa5\x23\xb2\xa8\xd0\xe6\x2f\xfe\x56\x28\x16\x47\xd6\x1f\xff\xbb\xc8\x40\x53\x57\x45\xd1\x44\x25\x9c\xc8\x13\x00\xfe\x99\xdf\xbf\xfe\xa6\xb0\xb9\xbc\xd2\x84\x73\x98\x2d\x32\xe9\x3e\xd4\x66\x34\xa9\x98\x79\x06\xd6\xf4\x89\x39\xd8\xdf\xbf\xb3\x7d\x33\xb8\x88\xdb\x60\x8c\xb2\xff\xe3\x9a\x8c\xf6\x7b\x72\x64\x46\x11\xc7\xd3\x2a\x4a\x8d\xf6\x12\x46\x8c\xd5\xe5\xd7\x5f\xbb\xa7\x9e\x63\x8a\xa1\xda\xa2\x8c\x4e\x0e\xeb\x9a\x63\x7f\xf8\xa0\x8b\x65\xf7\xa7\x61\x24\x14\xdf\x76\xbc\x7b\x0b\x56\xb5\x53\x7d\x66\x6f\xac\xfd\xda\xf6\x5a\xf1"}, -{{0x8f,0x47,0x4f,0x88,0xcf,0x86,0x3c,0x48,0x54,0x56,0xa5,0xa2,0x15,0x52,0x81,0xff,0x27,0xb2,0x84,0x59,0xf6,0x3b,0xc4,0xf1,0xdb,0x00,0xe0,0x03,0x10,0x64,0xf6,0x49,},{0x43,0x14,0x4a,0x32,0x9d,0x75,0x1d,0x04,0xe0,0x71,0x69,0xb7,0x79,0xee,0x92,0x0d,0xd0,0x29,0xcb,0x44,0x5b,0xf3,0x76,0xba,0x3a,0x66,0x85,0x72,0x18,0x23,0x44,0xa3,},{0xf6,0x1f,0x78,0x07,0xc3,0x3e,0x19,0x6d,0x0f,0xe1,0x82,0xef,0xa4,0xd4,0x51,0x6a,0x98,0x15,0xdd,0xd4,0x49,0x53,0x8b,0xba,0xa6,0xb8,0x6b,0x69,0x01,0xa0,0x5f,0x5d,0xdd,0xa0,0x60,0x1e,0xc9,0x0f,0x39,0xf1,0x55,0x47,0x79,0xdb,0x7a,0x09,0xa6,0x05,0x72,0xef,0xfd,0x4d,0x12,0x8d,0x0d,0x3c,0x2d,0xd4,0xe8,0x83,0x57,0x4b,0xc6,0x0b,},"\x84\x08\x91\xd9\x48\xec\x19\xc8\xc7\xf7\xc9\xd3\xc4\x77\x53\x62\xa5\x44\xa0\xec\x97\x45\x7a\xb5\xd1\x4e\x12\x5d\xc5\x4b\x59\xc8\xdc\x9a\x63\x5e\x7b\xad\xb6\xbe\x73\xc3\xa5\x8d\xc0\xe9\x92\x9f\x2b\x42\x0d\x83\x56\xd6\x17\xc3\xd4\x1b\xfe\x69\xb4\xe1\x58\xd4\xbf\x08\xfb\x17\xe6\x88\xd3\xcf\x3c\x94\x8b\x69\xb3\x5f\x0b\x6d\xb6\x62\x72\xa8\xeb\x2b\xd4\x10\xd6\x50\x9f\x6c\x82\x8b\x6a\x20\xd6\x58\x6e\xaf\x85\x76\x01\xed\x9d\x60\x54\x79\x9c\x25\x32\x0e\xba\x80\x77\xfe\x1a\xe2\x26\x71\xb3\x3a\x15\x88\xff\x2b\x23\x5d\x3c\x71\xa2\x7c\xe5\xc6\xc6\x6e\x18\x88\x91\x98\xd1\x16\x93\x36\x76\xbc\x4f\xb0\x71\x0d\xb7\xff\x1a\xc2\xf2\x0c\xe3\x69\xbe\xf5\x6b\x43\xcd\x1d\x40\x6c\xef\xda\xcf\x00\xf1\xf3\x48\xb8\xca\x7a\xa6\x14\xdb\x11\xa3\xa6\x40\xfd\xb5\x93\x89\xd1\xa6\xa3\x94\x75\x5c\x13\x3f\x1b\x01\x9c\x83\x08\xca\x5a\x95\x1e\x73\xb8\x10\xa1\x80\xf6\xff\x25\xb2\x9d\xbb\xcc\xef\x4c\x13\xa9\x75\x03\x39\x39\x07\xa2\xdb\xa0\x96\xa8\xce\x5c\x86\xc0\xee\x6f\x97\xc1\x44\x1b\x8d\x63\x31\xcb\xa5\x3b\x19\x60\x6b\x42\x1a\xf5\x2f\x65\xf9\xc6\x63\xe6\x3d\x39\x82\x71\x8f\x94\x8c\x6b\xae\x96\x1b\x8e\x4b\xf8\xcd\x9e\x31\xcd\x09\x92\x8e\x4e\x80\x61\x65\x97\xcc\xfa\xdc\xb8\xa6\x14\x15\x49\x33\xbc\x37\x58\x9c\x85\xc7\x76\xe3\x4e\x5a\x90\x66\x0f\x59\xa6\x5b\x5e\x93\xad\x43\x88\x42\xf9\x82\xd0\x2b\x04\x1e\x6d\xbd\xdf\x17\x10\x99\xf8\xdb\x70\x99\x57\x31\xa0\xdb\x8c\x46\x25\xc9\xbc\xa7\x10\x80\x59\x61\xfb\x17\x6d\xae\x81\x97\x68\xfc\xad\x7f\xf9\xbf\xce\x36\x40\x3c\xa7\xf7\x83\xe7\x61\x37\x26\xd7\xdc\x59\xf2\x4e\x24\x7c\xf1\x50\x68\xff\x3b\x19\xc7\x25\xfa\xd6\x5e\xa8\xe8\xa7\xf7\x22\xd5\x28\xc9\x5f\xce\xf1\xc0\xcc\x79\xd1\x8e\xf0\x7c\xee\x8b\x01\x1e\xea\xbd\x99\x21\x63\x4d\x76\xa6\x1a\x8a\x3c\x89\x31\xb8\x27\xe8\x18\x98\x81\xf8\x1f\x7a\x17\x5f\x21\xfb\x03\x78\xb8\x18\x8e\x58\xbd\xb2\x01\x7b\xef\x39\x0f\x18\x00\xd9\xd7\x4f\x26\x3a\x81\xdf\x8e\x67\x52\x2d\x09\x2e\x77\x5d\x01\xe0\x04\xe7\xf8\xd8\x28\x1a\xe2\xc2\xfd\xf8\xc3\xa4\x45\xf9\xef\xf7\xfd\xf1\x3f\x26\x1a\x77\x3d\xdf\x2d\xd9\xcc\x6b\xa5\x58\x5d\x99\x0c\x99\x5e\x6e\xb8\x9d\xff\xd9\xff\x0a\x9d\xbb\x76\xce\x5e\x10\xdd\x02\x72\xd5\x00\x14\x97\x88\x13\x66\xf5\xd6\x36\xa9\xcc\xea\xa2\x83\x22\x8d\x3a\xc6\x14\xdb\x21\x7a\xb8\x91\xd6\x68\x9d\xbe\xb9\x50\xe1\x20\x0c\x3d\xe5\x3b\xc5\xda\x07\xf1\xd3\x63\xda\xe9\xbe\x6e\xc3\x6e\xda\x6e\x68\x7d\x26\x29\x0f\x7a\xbc\xa2\x68\xa7\xfa\x03\xd9\x31\x88\x64\xed\xa9\xa1\x1e\x3b\x26\x14\x06\x05\x92\x0a\xc1\x3a\xde\xc1\xb5\x54\x8c\x9a\x7a\x32\x15\xa5\x87\x6b\x7e\x94\x1a\xfa\x1c\xb5\xd7\xf7\xf0\xc1\x16\x30\xcd\x42\x9f\x3b\x2b\x37\xdc\x76\xc6\xcb\xea\x4f\x3b\x72\x6a\xa8\xa5\xf8\xb9\xf7\x05\xb0\x5d\x7e\x94\x51\x95\x6f\x8a\xf1\x3c\xe0\xa8\x59\x55\xc7\x13\x5d\x64\xad\xe5\x49\x6e\xa5\x42\xe7\x0f\x8d\xa5\xb5\x73\xaa\xf1\x37\x08\x5d\xc9\x6c\x69\x27\x09\x96\x95\x67\x26\x68\xb3\xc7\xc6\xf9\x3c\x97\x7a\x4e\x8e\x9e\x77\x02\x95\xf2\x0d\x52\xdf\xf1\x87\xf8\xdb\xb2\x5e\xe7\xe7\x74\x02\x4e\xb9\xbe\x08\x12\x1e\xd7\x4b\x6d\x54\x62\xf4\xbb\x7d\xc2\x00\x38\x74\xca\xa3\x1b\xb7\x59\x5c\xd9\x3a\x99\xeb\xe1\xef\xf9\x28\xbb\x5f\xcb\x9e\x9c\x89\xdd\x31\xd4\x87\xfc\x0e\x20\xbb\xe1\x50"}, -{{0xe4,0x2b,0x30,0xd4,0x9c,0x43,0xc4,0xfa,0xd8,0x3d,0xd5,0x1f,0xdc,0x2a,0x4a,0xc5,0x90,0x13,0x27,0xad,0xd8,0x00,0xb6,0x69,0x72,0xc8,0xc7,0x0b,0xde,0x18,0x0a,0xdc,},{0xf7,0x34,0xaa,0xfa,0xa4,0xdb,0xaf,0x31,0x5c,0x25,0x8c,0xca,0x8b,0xbc,0x1d,0x4f,0x34,0xe8,0x36,0x01,0x10,0x98,0x74,0x22,0x2a,0xa0,0x55,0x89,0xf3,0xa6,0x63,0x5f,},{0xff,0x8e,0x07,0x6e,0x34,0x3c,0x8b,0x73,0xaa,0x45,0x3b,0xfe,0xe9,0xb2,0xba,0xb6,0xd5,0xc2,0xf7,0x4c,0x35,0xe1,0xba,0xd1,0xe5,0x2a,0xe7,0x77,0xd6,0x9f,0x79,0x76,0x40,0x83,0xf9,0x94,0x36,0x8a,0x1a,0xc8,0x51,0xa6,0x41,0xcd,0x24,0x70,0x08,0xa3,0x4f,0x3b,0x60,0x89,0x62,0xf4,0xdd,0x51,0x09,0xac,0x71,0xcc,0xe9,0x78,0xec,0x02,},"\x0d\x49\x70\x51\x86\x1e\x22\xd8\xa9\xc6\x0e\x5f\x7d\xe6\xc8\x95\xcb\xa3\x35\xb2\xe8\x2e\x60\x21\x18\xad\x83\x42\xb4\xd4\xed\xaa\x80\xf9\x5e\xfb\xb5\x9c\xfd\xa1\xfc\xc0\x29\x17\x25\x70\x0e\x8a\x81\xbb\x12\xa0\xb8\x62\x3b\x1f\xe2\x89\x1b\x8d\x98\xf7\xa8\x4c\x59\xfd\x92\xf8\xa7\xad\xfc\x06\x50\x42\xf7\xf4\xfd\x7e\x1a\x79\xf5\x5a\x1d\x4d\x5e\x54\xe0\x4e\x67\x2f\x1c\x9e\x4c\x4c\xd8\xd0\x00\x3f\x3c\xd5\x4b\x76\xe2\x16\x3d\xd7\x37\xac\xb2\xde\x5c\x26\x3a\xc1\x02\xa4\x8f\x69\x6b\x60\xca\xf9\xbe\x39\xc6\x65\xcc\xe1\xe0\xf3\xd4\x98\x55\x3f\x57\x90\x61\x88\x9a\x5e\xc5\x60\x3e\x4d\x14\x1c\xfd\xed\xe8\xe7\x31\x75\x72\xcf\xe7\x6a\x0f\x48\xe4\xae\x06\x06\x2c\x91\x57\xb5\xea\xac\x34\x68\x93\x81\x92\xdb\x4b\x16\x10\x5c\x73\x64\xa9\x44\x32\xb2\x15\xa7\x17\x97\xfe\xe1\x4c\x3c\x9c\xe2\xf7\x46\xed\x79\x03\x02\xfc\x41\xdc\x49\x2d\x37\xd9\xef\x02\x4a\xb5\x1d\xa3\xbd\xaf\x0f\x81\xd9\xa9\x30\xaa\x0e\x02\x5c\x04\xfd\x71\x02\x6b\x6a\xfe\xb7\xed\x01\xa9\x1a\x1e\xfd\x6c\x39\xf5\xe4\x47\xc6\x6d\xd3\x8a\x76\x56\xc6\x13\xd0\x21\x26\xf3\x58\x5d\xfa\xa0\x2d\xf9\x30\x25\x3f\x83\xbd\x42\x19\x64\x63\xeb\xc5\x0f\x8c\xfc\x94\x9e\xd3\x50\x39\x2e\x61\xce\xec\x13\x09\xda\x15\xa4\x32\xf8\x0d\xfe\x94\x8e\x26\x1c\xe6\xd8\x42\x1c\x54\x59\xcd\x21\xf3\xff\xa2\xed\xb5\x00\x98\x2b\x2a\xbf\xa5\x2e\x82\x43\x7c\xa2\x30\xf6\x09\x11\x63\x20\xd9\x89\x3e\xb8\x2a\x14\xdf\x72\xb7\x73\x66\x67\x51\x6f\xc0\x12\xb2\x8a\x03\xc9\xdd\x88\xea\x43\x08\xd8\xce\xea\x44\xcc\x60\x44\x54\xcd\xfa\x2c\x79\x76\x15\xbc\x0a\x6b\x3e\x00\x89\xaf\x0a\x81\xbe\x54\xd1\xb1\x10\xa1\x3a\xb9\x11\xb4\x52\xc3\x42\x80\x0c\xee\x2a\xd2\x39\xa2\xb1\x88\xa7\xfa\x87\x5e\x94\x1d\xaa\xeb\xcf\xc8\x8b\x70\xae\x4b\x1c\x57\x5c\xdb\x6e\x6d\x89\x44\x81\x36\xf6\x0e\xe8\x1c\x70\x3c\x47\x82\x2d\x2c\x0e\x50\xc7\xf1\xe8\xb7\xfc\x7e\xbd\x80\x78\x9f\xcd\x7e\x06\xc7\xe5\x0b\x5f\xc8\xb7\x76\xe8\xb9\xa4\xcd\x59\x05\xa2\x90\x69\xbc\x3a\x55\x8d\x7c\xab\xce\x2a\xf4\xf3\x10\x76\x7d\x5b\x11\x7e\x30\x76\xb3\xa0\xd5\x27\x17\x55\x43\xb2\xcc\xea\x28\xd5\xf7\x16\xfa\xc3\x2e\xfe\xd3\xd2\xe0\x27\x6b\xe4\x4a\x89\x56\xfc\x82\x40\xf2\xdb\x33\x97\x61\x4f\x2f\x2d\xa0\x21\x66\x69\x4e\xc6\xa7\xfe\xec\x6e\xce\x39\xd7\x2b\x64\xbb\xc6\xb4\x76\xa4\xf8\x4f\x8d\x87\x93\x80\xa3\x84\x88\xe4\xd6\xe5\x8c\xac\x03\x90\xae\x25\xa5\xfc\xb7\x3d\x47\x41\x4b\x4c\x26\xbb\xb9\xb4\xcc\x66\xe4\x25\x94\xbd\x56\xd8\x41\xa3\x60\x92\x34\x91\xd1\x17\xbe\x2c\x6e\xb2\x32\x0f\x3c\x61\x75\xe4\x4e\x27\xb6\x65\x3c\x5d\xac\x6f\xae\x73\x60\x0b\x67\x96\x0d\xca\x50\xaa\x85\x5a\x89\xe0\xff\x51\x1e\xa0\x4f\x14\x3e\x89\xf1\xda\x02\x84\x76\xbe\x4b\xf6\xd9\x4c\x80\xff\x72\x63\x39\xe8\xbc\xfb\x7d\xd9\xf8\xcf\x20\x22\x59\xc0\xac\xb6\x27\x6c\x28\x1e\x38\x47\xc2\xcc\x8d\x2f\xba\x84\x43\x8d\x2d\x3c\x60\x31\xf2\xa7\xb9\x5c\x1d\x8f\x9f\x3c\xc8\x6a\x5e\xff\x65\xcc\x01\x1d\xe9\x5a\xd8\x96\x85\x8e\x1f\x7f\x6d\x6b\x94\xbf\x49\xdf\xff\x5d\xe2\xd7\xfd\x71\xef\x10\x81\x34\x28\x5f\x61\xae\x47\x54\x83\x44\x2d\xc9\x0b\xf0\x13\xfa\xed\xf3\x77\x1c\x47\xc5\xb9\x6d\xc3\xcf\x8e\x48\x51\x00\x60\xad\x8d\x45\xfd\x54\x61\x62\x27\x80\xd8\x69\xd4\x61\x7b\x57\xfe\x3c\xb5\xcc\x02\x03\x15\x3a\xae"}, -{{0x5c,0xb5,0x14,0x21,0x74,0x82,0xbf,0x42,0xf6,0x11,0xfc,0xec,0x36,0xa5,0x28,0x68,0x07,0xc2,0xbd,0xbb,0x56,0x96,0x76,0x91,0x35,0x3f,0x54,0x31,0x0e,0x1a,0xd5,0x53,},{0x28,0x06,0x99,0x00,0x3d,0x5d,0x3e,0x1c,0x05,0xad,0x10,0xfb,0x10,0x95,0x9b,0xbc,0x59,0x5c,0xfe,0x21,0x30,0x69,0x96,0x5c,0xd8,0xcf,0x39,0xdd,0x42,0x6a,0x05,0x68,},{0xd5,0x3e,0xe2,0xe0,0xf0,0xfd,0x65,0x7b,0x20,0x52,0x47,0x8f,0xd1,0x5d,0xf1,0xd3,0x8f,0xe0,0xe9,0x3a,0x54,0x83,0xeb,0x4a,0x6e,0x7d,0xe9,0x3d,0x02,0xa4,0xcd,0x54,0x4d,0x8f,0xdd,0xdc,0xea,0x82,0x2b,0x71,0x57,0x6e,0xd0,0x28,0x53,0xd9,0xa6,0xb1,0x4e,0x1a,0x54,0x8a,0xef,0xe9,0x0d,0x92,0xf8,0x83,0x79,0x2b,0x7f,0x1d,0x86,0x09,},"\x2f\x57\x25\x8c\xca\x79\x32\xe5\x8b\xed\x54\x6c\xb0\x04\x11\x15\xbb\xad\x23\xd1\x83\x46\xef\x7a\xb5\xe3\x11\x00\x82\xb3\xa9\x71\x2f\x6c\xbe\x12\x70\xe6\xdc\x0c\xea\x33\x64\xa0\x6a\x5f\x2f\x28\x3e\xc3\x9b\x63\x05\x8d\x34\xd5\x99\x79\x07\x2f\xcb\xbd\x7a\x5d\x0f\x44\x2b\xbd\xf0\x82\xd5\xbf\xe2\x99\x8a\xeb\x51\xbd\x26\x12\x78\x03\xe5\xc7\x96\xc3\x88\x43\x20\x0a\xe2\xf6\xe6\x05\xaf\x31\x2f\x54\xfd\xff\x17\xed\x1d\xfa\xa8\x9d\x28\xfa\x67\xdc\xe4\x62\xde\x4f\xe2\x52\x68\x21\x2b\x28\x2e\x22\x2a\x44\x3e\x2f\x31\xe2\x69\x05\x41\x71\xaa\x73\xc7\x19\xa8\x96\xcd\xb7\xa5\x39\xdf\xd1\xd4\x29\x91\x97\x81\x97\xd7\xc4\xf2\xd3\x0a\x64\x1b\xe3\x4b\xf1\x38\x0a\x4f\x4d\xc6\xd9\xb1\x01\x63\x66\x36\xa4\x96\xbe\xb3\x57\xe3\x47\xc1\x66\x65\x16\xdf\x8e\xb5\x60\xa0\xe0\xd1\xe1\x52\x9c\xe3\x6a\x60\xe0\x0e\xd2\x78\xda\x38\x02\xbe\x19\x23\x42\x98\x9b\xb6\x11\xb4\xe3\xcb\xd9\xc3\x7e\x8c\xce\x07\xef\xc1\x2d\x29\xbe\xfd\x7e\x2f\x3a\xdb\x13\xd2\x8f\x70\x8d\x97\xb6\x3e\x10\x74\x82\xc8\x62\x95\x6d\x7c\xe8\xdf\xc2\xaf\x5c\xac\x8d\x51\x65\x92\x67\xb0\xbb\xed\xdd\x5e\xfa\x41\x4d\xde\xab\xd1\x7b\x23\xca\x6e\x84\x3f\xf4\x9e\xff\xc8\x2a\x5d\x07\xe3\x6a\x83\xb6\x7c\x2a\xd7\xe4\x8e\xb9\x99\x0b\x42\x1c\x55\x58\x00\x9b\xd6\x93\x4e\x86\xd5\x4a\x8a\x6a\xc4\x07\x87\x96\xe3\x05\xc7\xcc\x81\x0d\x3f\x66\xea\x6b\x95\x04\xfe\x0a\xe6\x75\x7c\x50\x4c\x55\x52\x53\x0a\x6f\x8b\xbb\x52\x40\x9b\xe0\x79\xd8\xe4\xa2\x8a\x6f\xd7\xdc\x89\x35\xf8\xeb\x94\x98\xad\xc0\xf2\x3d\x08\x07\xec\x86\x29\x5f\x48\x98\xf5\xd0\x5e\x15\x0b\xdc\x43\xaa\x8b\x7b\xdc\x89\x3a\x0a\x68\x4c\x30\x63\x89\x8b\x6c\x95\xe7\xd5\x6a\x4c\x10\x26\x90\x43\x8e\x9d\xf9\x97\x58\xa9\x0f\x47\xc6\x08\xda\xcc\x4c\xa2\x40\x26\x6f\xab\xa3\x5f\xa1\xeb\x2e\xaa\xbe\x28\x8d\x2c\x2a\xd5\x0b\x6c\xbf\x10\x7c\x00\x25\x75\xe9\x1f\xf4\x72\xa4\x41\x79\x40\x66\x7b\xe8\x18\x01\x73\x85\x4c\x93\xdf\x84\x46\x4b\xcd\x31\x2b\x7a\x7a\xe4\xdc\x2b\x90\x59\xfb\xe6\xf8\x3f\x53\x80\x64\x25\xbd\xff\x03\x1c\x6a\xed\x6e\xfa\xfd\x9d\xe8\xdc\xd0\xdf\xab\xea\x8e\x6f\xa6\x81\xe9\x91\x93\xfb\x3c\x64\x7e\x44\x21\x12\xc9\xa2\x3f\x59\x6e\x65\x41\x1d\x8d\x6b\xfc\x39\x23\x00\x4e\xce\x91\xea\x6d\xeb\x88\x11\x11\xb1\xdc\x29\x94\x3f\x57\x89\x81\xee\x8c\x3b\xce\x85\x25\xf7\x85\x65\xf3\x4b\x85\xff\x20\x01\x5f\xea\xe8\x46\xf9\x5b\x18\x70\x0b\xc5\xcd\xf1\x4b\x2d\xb6\xca\xc6\x98\x14\xd6\x3d\x74\xbf\x20\x32\x93\x03\xe5\xca\x9f\x04\x73\x1f\x68\x81\xce\xc6\xd3\xab\xf8\x7f\x5e\xac\x08\x73\x4f\xaa\x34\xcf\xf4\xd3\xcd\x9a\x4a\x11\xd7\xb1\x2f\x73\x25\x3b\x4d\xd0\xa4\x31\x78\xf0\xd3\xc1\x9c\x0c\x40\xd9\xed\x91\x8d\xd1\x76\x46\xf6\x16\xaf\x79\xfd\xf6\x19\x42\x62\xf0\xfa\x4f\x71\xb3\x18\x7d\xed\xca\x48\xd9\xcb\xcc\x19\x93\x1a\x15\x19\x67\x74\x56\x25\x6e\xd3\x83\x54\x56\x7c\x3a\x67\x57\x1c\xdf\x82\x17\x0a\x2c\x85\xbd\x2c\x5e\x68\xe0\x5a\x0f\x3b\x93\x90\x3f\x19\x1b\x89\x4f\x84\x94\x6f\x89\x00\x05\x68\x05\x4c\x1c\xea\x9f\xd0\xb8\xbb\x55\x01\x95\x06\xc5\x43\x41\xc2\x49\x31\x98\x45\x48\xba\x45\x8a\x4d\x81\x30\x89\x89\x6e\x86\xa2\xdc\x33\xd9\x46\x04\x00\x3f\x35\x4a\x7c\xc9\x41\xc7\x54\xaa\xea\x24\x25\x3c\xbe\x4c\xf2\x14\x7f\xfe\xc5\xe7\xb9\x50\xcb\xf2\x8e\x28\x44\x81"}, -{{0x87,0xd3,0xba,0x95,0xc4,0x0d,0xf8,0x00,0x69,0xb1,0x79,0x7d,0xdf,0x68,0xe8,0x66,0xe6,0x6d,0x46,0xc5,0x1f,0xde,0x60,0xe7,0x68,0xa9,0xdb,0xc5,0xc9,0x2f,0x57,0xa9,},{0x2b,0x81,0x2b,0x2c,0x9b,0x60,0xff,0x31,0x97,0x5c,0x42,0x9a,0x86,0x73,0x6d,0xcc,0x17,0xa5,0x8d,0x3d,0xc1,0xda,0xa3,0x46,0x23,0xa4,0xbb,0xcb,0xe2,0xcc,0x05,0x81,},{0xfa,0x0d,0x12,0xcd,0x53,0x23,0x6c,0x41,0x08,0x6b,0xea,0x8c,0x0c,0xc6,0x0b,0x77,0x64,0xa3,0xed,0x72,0xbd,0xeb,0x9d,0x1a,0xe5,0xee,0xac,0xb4,0x88,0x11,0xfe,0x52,0x97,0x62,0xa2,0xc6,0xf2,0xbb,0x06,0xd9,0xb3,0x18,0x21,0x8d,0x96,0x8f,0x64,0x44,0x35,0x49,0x7a,0x1b,0xd0,0xd0,0xd8,0xc1,0x61,0x2a,0xb8,0x99,0x6d,0x98,0xd7,0x07,},"\xe1\x12\x56\xf8\x2a\xd7\x6f\x3f\x4a\x49\xd7\xba\xd3\xce\xd8\x71\x8d\x36\xd2\xf2\xbb\x3d\x31\xbb\x61\xed\xd1\xec\xbc\xee\x66\x21\xfd\x2e\xee\xd3\xe3\xde\xb5\x97\xb1\x49\xff\x71\xb8\x51\xf6\x1c\x8c\x68\x19\xe1\x31\xf9\xa2\xaf\x76\x73\xc3\xf2\x07\x02\xac\xfd\xc8\xb8\xf9\x06\x4b\x41\x5c\x9a\x3e\x35\x56\x8e\x37\x1d\x74\x0a\x38\x12\x7c\x1f\x27\xb3\x91\xb4\x5d\x07\x04\x5a\xea\xf0\x0a\x54\xe5\xb7\xfa\x54\x8a\xfb\x5f\x96\xfe\xb5\xf5\xb4\x4f\x60\xcd\x17\x07\xe8\xfa\x95\x67\xf7\x80\x6e\x15\xf6\xa0\x1a\xa0\x20\x77\x73\x3f\xe7\x38\xb0\x8f\x21\xef\xbc\xf9\x8c\x19\xd5\xb9\x70\xe6\x16\x3e\x5f\xe8\xf4\x80\x0e\xf9\xed\x22\xa0\xf9\xb5\x12\x6f\xf1\xeb\x1c\x7d\x65\x01\x9c\x8b\x44\x03\x91\x92\x70\x29\xb8\x13\xda\xb7\xc7\xe8\x63\xd4\x82\x29\xf8\xdf\x85\x39\x43\x45\xfc\xc8\x8a\x30\x0f\x60\xa8\xd5\x16\xd8\x77\xa5\xa3\xa7\xe3\xc4\x9a\x9e\xb0\x6c\xd9\xf2\x66\x5c\xe2\xa8\x90\x22\x96\x2b\x1d\x49\x59\x2b\x09\xc7\x54\x3d\xa8\x35\xce\x63\xbc\x9a\xbb\x82\x21\x45\x76\x2b\x71\xcb\xe1\x50\x29\x2c\xe5\xc8\x70\x4e\x5a\xd3\x4f\xb4\x59\x2f\x97\x20\x44\xe4\x3e\x69\xf0\xe1\x67\x2d\x6c\x83\xcf\x25\xaa\xc6\x8e\xfe\x3d\x27\xaf\x2a\xd3\x42\x74\xb9\xd2\xb7\x77\x42\xd9\xc6\xdf\xbd\x57\xf9\x2f\xf6\x4d\x3e\x4c\x67\xc5\x41\xd8\x50\x2a\x7d\x03\x18\x95\xaf\x85\x31\x9a\x4e\xae\x2d\x25\x43\x35\x83\x5e\xff\x11\xe7\xa3\x67\x1a\x6a\x0d\x21\xb7\x2c\xe1\xfc\x2a\xcb\xa1\xa9\x20\x18\x38\x34\xbc\x0a\x4b\x73\xf6\x39\xff\xcb\x0f\x6b\x81\xcd\x92\x0f\x2e\x94\x20\xd6\x12\x16\x6d\x56\x82\xa0\x60\x60\xea\x0b\x6f\xa6\x95\xfe\xcc\x77\x04\xbb\xe4\xb0\x52\xaa\x3e\xc8\xf7\x20\xf7\xd4\xf3\x2e\x8a\xff\x86\xb8\x0b\x8c\x1c\xc1\x27\x64\xa0\x48\x74\x03\x7c\x31\x03\xe9\xdf\xec\xb8\xf7\xab\xcb\x0e\x07\x3b\x23\xe6\x7c\xa0\xa9\xb1\xfc\x72\x99\x3a\xbf\x31\xdb\xc2\x4a\x8f\xee\x09\x5b\x32\x51\xc2\x26\x26\xaf\x5d\xd1\xb6\xd3\x4b\xe5\xea\x06\xa0\x2a\xe1\x76\xc7\xb8\xcb\x9d\x06\x35\x01\xbe\x6f\x61\x20\x82\x88\x9f\xdb\xdc\xbf\xad\xc3\x3a\x0d\x31\x1b\x08\x0b\x8d\x64\xe4\x9f\x16\xb1\x6d\xd8\xed\xd3\xb2\xed\x11\x93\xa7\x4e\x5b\xe5\x07\x60\x9b\x04\x27\x27\xcc\xf0\x8a\xfb\x05\xcc\x6c\x50\x52\x4e\xf0\xe2\x66\x46\x21\xdc\x8b\x05\xb1\x5f\xfa\x81\xab\x6f\x7e\x3c\x8a\x5b\xb3\xea\xb1\xf6\x8e\x36\x56\xc1\x19\xd9\x69\xe4\x14\x4c\xf3\x28\x5a\xf2\x3c\x04\xdb\xec\xc0\x38\xae\xfd\x91\x83\xc4\xe7\x24\x47\xb2\xaa\xa8\x31\x5f\x46\x96\xce\x6d\x1e\xf4\x29\xba\x0e\x5c\x3d\x5f\xfa\x7f\x05\x0b\xe3\x9c\x7f\x61\x2f\x4e\x10\xf8\xef\x07\x0d\xf7\x2f\x8a\xdd\xbe\xaf\x33\x39\xc1\xad\x8b\x5f\xc3\x9a\x2e\xcf\x29\xa8\x7f\x82\xe2\x9a\x01\x17\xba\xac\x66\x25\xad\x5c\x80\xcf\xe7\x59\xfa\x1d\xbc\xfa\xa1\x2b\x37\x44\x77\xd8\x0b\xfc\xf0\x67\x96\xc3\x0f\x2c\x39\xcf\x03\x03\xd0\x0d\xc5\x6a\x32\xd1\xd0\x39\x59\x2d\xdb\x06\xc2\x2a\xa0\x68\x84\x1c\x0b\x46\xfd\x48\xdf\x8f\xbb\x74\x92\xcc\xbc\x59\x0c\x56\x3c\x8f\xec\xce\x42\x63\xc8\xc7\x53\x92\x18\xbb\x97\xb3\x57\x11\x53\x7e\x98\x81\x95\xdb\xf5\xbc\xd5\xcc\xaf\x06\xfa\xf5\x08\x47\x09\x77\xa5\x35\x8e\x6f\x02\x60\x83\x49\xfb\xb9\x9a\x23\xfb\xe3\x6b\x8c\x97\x15\x5a\xdc\x24\x6a\xd7\xd9\x3a\x8c\x20\x3f\x75\x44\x6c\x83\xc4\x34\x2c\x35\xba\x10\x4e\xcc\x67\xe6\x69\xdb\x4a\x95\x46\x6e\xe6\x8f\x45\x8a"}, -{{0x7c,0x27,0xae,0x47,0x07,0x2b,0x0c,0x9b,0x9c,0x2c,0x35,0x1f,0x13,0x27,0x89,0x98,0x95,0xef,0xa5,0x36,0xc9,0xc0,0x67,0xd0,0xe0,0xce,0x8e,0x82,0xe6,0x29,0x27,0x93,},{0xf9,0xfe,0xbd,0x12,0x1e,0x17,0xdb,0x72,0x29,0xb5,0x67,0x09,0x02,0x18,0x49,0xc3,0x5d,0x69,0xfa,0x08,0xb5,0x06,0x20,0xe6,0x67,0xf8,0x42,0xec,0x7a,0xc7,0x82,0xdc,},{0x32,0x71,0x96,0xdd,0xd4,0x3b,0xb6,0x02,0xd0,0x4d,0x19,0x64,0xcc,0xc0,0x59,0xed,0x62,0x7c,0xef,0x0a,0x88,0xd8,0xad,0x91,0xbe,0x49,0x31,0xf1,0x7c,0x25,0x0d,0x55,0x29,0xf5,0x52,0x79,0x4a,0x3e,0x26,0x9d,0x17,0xa6,0x3b,0xd3,0x29,0x33,0xeb,0x5e,0x51,0x9c,0x1d,0x50,0x65,0x74,0x77,0x0a,0xe4,0xa7,0x29,0x64,0xe0,0x6f,0x7d,0x00,},"\x15\x47\x87\x6a\x98\x8d\x1b\xe7\x14\xa4\x2f\xb9\x1c\xb0\x37\x63\xf1\x91\x3a\x89\x2e\xcb\xd4\xde\x2c\xcf\x83\x44\xd2\x07\x58\xb7\xb6\xd0\x02\x59\x10\x1f\xe9\x72\x25\xb2\x97\xf8\x7b\xfe\x22\x20\x04\x32\x5d\xb7\xf6\x32\xce\xaf\xfb\xd1\x34\xc9\x6c\xbd\x57\xe9\x85\xbe\xc8\x43\x4f\x81\xa4\xee\x6a\xf8\x5c\x3f\xad\xe5\x0e\x4c\x4e\xf2\x0c\xb0\x39\x35\x45\xe4\xd4\xa8\x6e\x1f\xa3\x9a\xaf\x33\x3f\xe4\xde\xd0\x54\xbf\xc0\x50\xa8\x98\x3a\x03\xdd\x1e\xcf\x2b\x5e\x95\x17\xba\xf9\xe1\x15\x21\x29\xa8\xa7\x59\x35\x71\x1e\xdb\x20\xaf\x5c\x8c\xf9\xc6\x94\xa3\x3c\xee\x45\x1c\xd9\x50\xb2\xff\xf0\x8e\x31\x58\xc5\xcf\xb7\xb1\x5c\xb3\xe9\x0d\x46\xf4\x94\xb6\xa1\x08\xd8\x88\x8d\x5e\xc2\x9a\x33\xc0\x66\x02\x3b\x49\x77\x09\xb2\xd9\x40\x1f\xea\xf2\xe7\x4f\xf2\x6c\x16\xd3\x6c\x39\xe6\x51\x7f\xf9\x54\xbd\x98\xbc\xe7\x70\x06\x71\x98\x8f\x66\xe8\x51\x07\x64\x4b\xa2\xea\x00\x7a\x13\x01\x8c\x1c\x14\x4e\x3c\x5b\xb8\x0d\xb9\x51\x1f\xcc\xa4\x10\x1b\xf4\x9f\x8c\x80\xff\x3c\xa7\xd2\x98\x25\x7c\xbf\xea\x62\x9f\x83\xd5\xe0\x66\x39\xd3\x1f\x63\x9d\xb4\xb8\x72\x6c\xbe\x22\x4d\x75\x88\x29\xba\xb1\x09\x05\x17\x1c\x9c\x0e\xc3\x70\xd5\x80\x31\xef\xe4\xcc\x5a\xe7\x2a\x49\x5a\xcf\xf6\xcb\x2e\xd9\xee\xc6\x58\xba\x11\x70\x88\xdd\x3c\x6e\xd1\xdf\x8f\x9c\xb1\x0b\xd4\xfe\x0e\x5e\x8a\xd9\xf5\x03\x4e\x34\x65\x2d\x98\x66\x8d\xb1\x5c\x85\x33\x39\x3a\x6e\x9e\xc0\x87\x0c\x35\x66\x6c\xe5\x4e\xfe\x2b\xcb\x45\xc3\x4a\x72\x30\xe6\xa7\x00\x67\x63\x49\xc7\xb3\xab\xf3\x1d\xe7\xb7\xb0\x52\x1f\x89\xb3\x0a\xc4\x03\x4c\x2a\x4b\xa8\x21\x8e\xef\xdf\x8d\x2a\x5c\x1f\x8e\xd9\xb7\x01\x57\x9e\x47\xaf\x8a\x52\x9a\x95\xa1\xff\x64\xd8\xfd\xb8\x85\xc3\x68\x39\xb4\xc5\xf6\xd7\x2a\x99\x25\x7e\x86\x78\xdc\xcf\x31\x27\x54\xb9\xd4\x61\x9b\xee\xce\xb8\x25\x52\x6d\xe6\x22\xbd\x96\x76\xfd\x5f\x35\x76\x93\xab\xab\x07\x8b\x9e\x03\xae\x21\xe8\x7c\xa1\x61\xe7\x78\xaf\x77\x09\x6e\xaa\xc2\xd2\xd3\x2b\xfe\xc8\xec\x94\xaf\x79\x65\xf6\x1d\x68\xef\x66\xa4\x52\x3c\x1c\xc7\x0c\x95\x19\xb0\x75\x0b\x3c\x9e\xed\x5a\xeb\xa9\xf0\xa9\xb7\xef\x52\xcd\x4a\x2d\xe2\x9b\x39\x5b\x70\x5f\xa5\x3f\x02\x8f\xa7\x66\x15\x9f\x20\xe7\x5f\x4d\x38\x4e\xc4\xfd\x66\xdf\x06\xe7\x44\xc9\x9a\xc8\x8c\xb8\x49\xc2\x85\x75\x7c\xc5\x57\xe2\xee\xdd\x86\x95\x9d\xa2\xc1\xb8\x1f\x5b\x27\x15\xa6\x51\x98\x48\x90\x1a\xe4\xf8\x9d\x09\x13\xc8\xde\x57\xc5\x3d\xad\xf2\xe5\xe1\xaa\x2a\x9c\x5f\x46\x4f\xc7\x61\x0e\x8e\xf5\xf5\xcd\xd8\x20\x3a\x67\xa9\x3c\x33\xa0\x6d\xab\x35\x8d\xc5\xae\x23\xed\xfe\xe6\x33\x42\x62\xf4\x7b\x19\xb1\x13\xd6\xca\xfe\xda\xc1\xb4\x39\x02\x53\x9d\x74\xfb\xa2\x9a\xaa\x7b\xce\x68\x88\x4b\x72\x61\x6a\x05\x42\xc9\xfc\x69\x54\x7c\xd1\x9a\xe1\xdf\x01\x72\x3a\xbd\xda\x65\xe9\xbf\xac\x5d\xa0\xd0\x42\x40\xc6\xa2\x17\x5c\x00\x62\xe4\xe1\xed\x8a\x5b\x39\x7a\xfc\xd4\xde\x38\xe8\x62\x09\x27\x2c\x7a\x42\x4b\x5a\xe8\xd5\xa4\x0b\x48\x4c\xe1\xb4\x70\x4a\xf2\x83\x16\x09\xad\x0f\x36\xe9\x0e\x07\xb2\xaf\xed\x01\xdc\x05\x57\x4a\xd3\x97\x17\x23\xc5\xb5\xc1\xdd\xd4\xfc\x8b\xd2\x63\xbc\xdf\x56\x8a\xf7\x5e\x73\xd8\xab\xd1\x00\x8c\x9e\xc7\x12\xf8\x0f\xfc\x65\xac\x34\xe2\xa7\x93\x04\xea\xde\x1d\x2a\x1d\xff\xec\x0e\x4c\x98\xc3\x58\x24\x68\xf3\x20\xbf\x8f\x66"}, -{{0x08,0xed,0xdc,0xb5,0x62,0x5a,0xe1,0x9f,0xfe,0x7b,0x49,0xa7,0xdc,0x82,0x9c,0x89,0x3c,0x75,0x38,0xb0,0x88,0x5e,0x18,0xf9,0x8d,0xb7,0x8c,0x8b,0xeb,0x56,0x9c,0x26,},{0x83,0x47,0x8b,0x1c,0x58,0x57,0x6a,0x0d,0x18,0x34,0xb2,0x8d,0x46,0xfb,0x80,0x51,0x6d,0x6f,0xb6,0xf9,0xf5,0x91,0x69,0x4b,0x44,0x35,0x2e,0xec,0xd1,0xe7,0xe8,0x9a,},{0xec,0xe7,0x53,0x22,0x99,0x51,0x54,0xb2,0x92,0x43,0x7e,0x47,0xd3,0x8a,0x6a,0x70,0xaf,0x37,0xe2,0x02,0x07,0x16,0xfd,0xe4,0x6b,0xfd,0x39,0x3b,0x3d,0x36,0x9b,0xdd,0xb5,0x32,0x53,0xb5,0x56,0x62,0x1c,0xfb,0x34,0xc8,0xa9,0x02,0x54,0xe1,0x32,0xfd,0x28,0xec,0xd0,0x98,0x43,0x34,0x13,0xa2,0x1b,0xd3,0xa9,0x79,0x8c,0xa1,0xf3,0x09,},"\x01\x5b\x1d\x3e\xeb\x00\x92\x9e\xa8\x0b\xd8\x68\x7d\x18\x28\x6f\x0a\xdf\xe6\x45\xcc\xf2\x5a\x22\xb5\x06\x19\x21\xe2\xa0\x30\xfc\x76\xd0\x33\xfb\x53\xd0\x93\x7c\x69\xb3\x1c\x5b\xe4\x99\x13\xca\x1f\x2c\x3d\xca\x12\x1b\x2b\x87\xc5\x9b\x3c\x84\xc7\xae\x52\xaf\x19\xc6\xb9\xfa\x1b\xd6\x75\xfb\x6d\xd8\xb3\x29\xd5\x66\x87\x86\xdc\x78\x83\xe2\xd2\xe8\x58\x6f\xf4\x12\x8b\x90\xde\xe8\x4b\xe0\xab\x54\xd6\x81\x3f\x7a\x8c\x61\x34\x75\x71\x73\x98\x17\x75\xde\x84\xc4\xdd\x39\xe3\x36\xf8\xa4\xef\x8d\xca\xde\xc9\x43\xe9\x0d\x42\x1b\x22\x9c\x11\x78\x5f\xcd\x3f\xe9\x63\x03\x74\x58\xe7\x6c\x82\x0b\x3b\xc2\xc9\x47\x60\x01\x26\x2b\x26\x1d\x28\xb6\x5b\x48\x9d\x76\xb4\xbe\x23\x65\xe4\xa8\x0f\xa8\x71\xb0\xa5\x3b\x6a\x5f\xb2\x43\x68\x82\x35\xac\xc5\xf4\x77\x4d\xb1\x5d\x47\xb4\x2d\xd6\xc8\xd9\xe1\x2d\xcb\x0b\x5d\x98\x0d\xab\x0f\x3a\xd8\xa4\x96\xf7\x6e\x50\x06\xc2\xca\x82\x67\x5f\xf1\x94\xca\xf8\x07\x0d\x04\xbd\x38\x4f\x97\xe5\x83\xe7\x3c\xbc\x4f\x7f\x25\x73\x10\xa6\x1b\x1c\x80\x62\x32\x2d\xce\x81\x15\xf6\xdd\x93\xee\xe8\xa9\x3f\xfa\x5c\xab\x66\x34\x11\x6e\x1a\xb7\x05\xfa\x86\xc4\xa8\xea\xa5\x56\xc6\xc8\x9d\xbc\xad\x01\x04\x36\xbf\xfe\x45\x18\x22\x49\x1f\x1e\xa8\x6c\x20\x20\x7e\x4d\x12\xdf\xa3\x62\x61\x6c\x58\x9f\x97\x10\x7e\xa5\xd8\xbd\x8a\x72\x15\xc6\x00\xff\xc7\x0b\x80\xe2\xab\xb1\x5a\xcb\xe4\xbe\xcc\xa2\x0d\x72\x15\x5a\xbc\x3d\xbe\x8e\x37\xcf\xd7\x3f\x74\x20\xf2\x1c\x9b\xcd\x0c\x32\x73\x51\x3b\x50\x49\x67\x08\x74\xd5\x51\x9b\x3b\xc1\xdb\x52\x3c\x1d\x7e\x90\xc1\x65\x96\x7c\x4c\xb2\x84\x5a\x2e\x8b\x47\xb5\x88\x92\x54\xf5\x8a\x9b\xbb\x82\x6f\x94\x52\x1c\xdb\xd0\x41\x6f\x5f\x18\xff\x78\xa3\xfd\x0d\x7a\xb8\x97\x90\x62\x64\x48\x3c\xde\x64\x2d\x8e\x70\x3f\xd8\x2e\x5a\xe7\x0a\x9f\x97\x8f\x64\xee\x80\x52\x05\x54\x85\x05\x28\x58\x1c\xa9\xa0\xb3\x8c\x19\x6f\xd1\x66\xda\xe5\x87\x9b\x3f\x72\xf5\x9c\xde\x91\xcc\xa2\xc8\xbf\xaa\x47\x8b\x98\xd6\x24\xcd\x34\x72\x44\x02\xde\x57\x8e\x57\x54\x82\x5c\xe2\x27\xd2\x87\x1b\x45\xa5\x11\x71\x49\x51\x5b\xff\x81\xa9\x23\x24\x6f\x3b\x72\xd0\x7b\xd4\x58\x12\x5c\x70\xa1\x4d\x87\xc3\xfd\x13\x39\x2a\x3b\xda\x65\x53\x01\x6e\x8b\x2d\x07\xbd\xe9\x03\xcf\x68\x7b\x44\x5c\xfd\x6f\x76\x14\x92\xeb\xa4\x65\x22\xad\xa8\x4a\x96\x15\xd8\xda\x34\x98\xb2\x58\x06\x72\x69\xb7\x88\xe5\x59\xb6\x59\xd4\xb4\x8a\x87\xd8\x80\xd6\x37\x8b\xe6\xa8\x87\x46\xf3\x5b\x32\x2b\x04\x78\x45\xaa\xdc\x52\x3b\xea\xff\x30\x70\xf7\x21\xc3\xc0\x71\xea\xa3\x19\xb7\xa4\x7c\x1b\x20\xd3\x00\xdc\x03\x21\x90\x9b\x66\x9e\x57\xd3\x9a\x1c\xe2\xfd\xbe\xaa\xfa\xc2\x13\x50\xec\x2d\x6e\x6d\x5b\x88\x01\x86\xc0\x28\xa8\x61\x47\x4d\x50\x76\xa4\xad\xc5\x03\x2f\xec\x91\x40\x78\x7c\x36\x80\x6e\xf7\x9c\x72\xe3\xa1\x9d\x8c\x8b\x70\xbd\xaf\x20\x72\x95\x54\x2d\x96\x82\x5a\x5d\xe7\xdf\xe1\x08\xef\x57\x45\x99\xb8\xf1\x84\xc6\x3a\x5a\x13\x1d\xb1\x9b\x3b\xe5\x3f\x69\x9c\x10\xfc\x4c\xa7\xc6\x3f\x35\x00\x21\x1b\x35\x6a\x0a\xc6\x64\xdd\xfc\x1a\x92\x52\x59\x00\x26\x39\x5b\x47\x9b\xe9\xa5\xe4\x75\x84\x23\x56\x0b\x65\xbb\xce\x5b\xba\xde\x49\x3b\x13\xd0\x0c\xf8\xc1\xd3\xb7\xe9\x22\x13\x67\xe8\xf0\xea\xda\xb6\xe6\xd1\xb5\xff\xfd\xe7\xb2\xd7\x41\xfc\x2c\x83\x02\x24\xff\xf7\xff\x14\xae\x5c\x07"}, -{{0x22,0x73,0x94,0x2d,0xb3,0xe5,0xd3,0x22,0x1e,0x80,0xd9,0x94,0xfd,0x5e,0x11,0x63,0xaf,0x55,0xf5,0x45,0x5a,0x8e,0x52,0xbe,0x85,0x2d,0xd3,0xad,0xf7,0x62,0xb4,0x40,},{0xbc,0x58,0x67,0x4e,0x99,0x6b,0x6f,0x3e,0x32,0x20,0xb3,0xe9,0x4f,0x00,0x67,0xbb,0x0e,0x9b,0x0d,0x97,0xd9,0xe1,0x05,0x9c,0xf1,0x39,0x97,0xa1,0x93,0xac,0x03,0x2a,},{0x87,0x4d,0xde,0xce,0x08,0xf3,0x0b,0x30,0xf0,0xd4,0xc8,0xb3,0xed,0x7c,0x61,0x51,0x49,0xb8,0xaa,0x74,0x0d,0xaa,0x34,0x7b,0x55,0x95,0x8f,0x1e,0x21,0x19,0x04,0x4f,0x69,0x5a,0x21,0x06,0x96,0x90,0x50,0x64,0x48,0xd8,0xe7,0x35,0x2b,0x90,0x46,0x51,0x1d,0x7f,0x39,0xa5,0x41,0x5b,0xb9,0xc5,0x70,0x50,0xfc,0x17,0x05,0x5c,0x38,0x08,},"\x8a\xa0\x50\x9e\x4b\x91\x41\x86\xff\xff\x07\xae\xb9\x7a\x04\xb5\x46\x27\x2d\xa2\xf9\xea\x7b\xfa\x65\x9a\x24\xcb\x50\x96\x6c\x23\xeb\x65\x42\xe4\xf2\x2d\xeb\xe3\x3b\x65\x76\x92\x45\xc4\xd1\xb5\xdc\xf3\xe6\x99\xc7\x0c\x5c\x2b\xaa\xd9\x73\x4e\x9d\x1e\xfe\x54\x48\xab\x71\xc8\x94\x6a\xec\xce\x52\x68\xd2\x6f\x19\xcf\x60\x5e\xb3\xbf\x38\xb0\xb3\x32\x26\x94\xac\x0d\xcb\x76\xb0\xf9\x46\x84\x2f\x6c\x5c\x68\xd7\x63\xfc\xe7\x47\x01\xbd\x6b\x78\xe7\x1c\x8c\x31\x42\xad\xd4\xed\x46\xe0\x96\x9b\xb9\x55\x5b\xe0\x36\x02\xd5\x62\xe4\xc8\x9f\x3a\x91\x99\x40\xe8\x83\xa9\x69\x40\x54\x2f\x27\x79\xfb\xf9\xec\x0a\x28\x5d\x9d\x8a\x72\x36\x01\x46\xe3\xff\xbd\xb7\x8d\x21\x03\x16\x03\x8d\x95\xd6\xab\x75\x71\x65\xaa\x94\x3c\x03\x3e\xeb\xb3\x21\xc0\x5a\x39\x95\x69\xbc\xf6\x6b\x4d\xdb\x0b\x2e\x0e\x33\xc4\x79\x3d\x81\x7c\xcf\xf5\x7f\x99\xb3\x18\x9c\x60\xd5\xd7\xb9\x41\x9d\x1e\xbc\x94\x3a\x79\xd4\xd8\xc3\x94\x56\x61\x80\x59\x4f\x55\x9a\x80\x52\x9c\xc1\xba\x28\x87\x7a\xf8\xf5\xc0\x50\x3e\x94\x3c\xd3\xaa\xd9\x98\x11\x64\x52\x72\xda\xfb\x49\xb9\xb3\xe6\x10\x7e\xb5\xe5\x18\x6e\x16\x08\x75\x71\x26\x05\x3d\xeb\xce\xc7\x5d\xd9\x56\x5c\xee\xa0\x6a\x13\x91\xa8\x22\x6d\x1f\x45\x93\x79\x22\x40\xcc\xd9\x7c\x67\xa6\xc2\xb1\x34\x4c\x22\xc9\x1f\x42\x03\x3a\xde\xf5\x28\x61\xf3\x2a\x4e\x07\x12\xa9\x17\x87\x9a\x0b\x05\x18\xb5\x42\x4b\xcd\xc0\x54\xb4\x4e\x97\x2e\xd2\x4d\x01\x68\x9f\x4f\x27\xf5\xf1\x76\xf0\xa5\x78\xab\x2d\x3c\x08\x78\x27\x2e\x8c\x08\xc2\x15\x82\x11\x86\x54\x12\x4d\xca\x39\x58\x53\x37\xc1\x3c\x18\x65\x81\x4c\xaf\x09\x96\xca\xdf\xa6\x5b\xe5\x80\xde\xe3\x22\xeb\xcc\xda\x70\x4b\x22\x80\x58\x26\x04\x06\x7d\xc3\xc6\xb1\xf7\xd8\xa2\x69\x78\xa6\x5c\xff\xd1\xed\x31\x96\xa2\xb0\x65\xfb\x3c\xaa\x79\xe6\xb5\xb6\x6c\x13\xd7\xbd\x7d\x0e\xc1\x4a\x3a\x4d\x58\x41\x3f\x21\x2f\x47\x1e\xca\xad\x3a\x84\xaf\x35\xe5\x98\xa8\x9f\xb3\x44\x7d\x33\x24\xf0\x20\xfb\xf1\xb7\x3e\x2a\x98\x6e\x0d\xa1\x6c\x01\x83\xbf\x92\xa3\x98\xc4\x19\xa0\xf9\xf3\x05\x37\xbe\xa0\xdf\x8d\xf2\xdc\x53\xc1\x54\xe8\xea\x16\x06\x89\xe7\xbb\x4d\x72\x9d\xd8\xab\x90\x03\x14\x27\xaa\x39\x45\x86\x3a\x85\xe8\x96\x52\xb9\x35\x38\x05\x16\x6f\x7c\x0a\x18\xc9\x39\x95\x4b\x27\x87\xc3\x70\x94\xf9\x25\x12\x72\x2e\x52\xb0\xc9\x76\xb9\xe4\x2a\xf4\x03\x9d\x2c\x05\x78\xff\x14\xfa\xe1\xd8\xc2\xd1\x39\x6b\xeb\x2d\x6a\xa6\xeb\xd5\x54\x74\xa9\x34\x98\x67\xa0\x3f\x3a\x99\xd7\x87\x80\x63\x4a\xb4\xb3\x5c\xfe\x1b\x87\xa9\x13\x32\x52\xa6\x98\xbc\x40\x7d\x63\x84\x28\x70\xe2\x2c\xcf\x39\x33\x62\x0a\xc0\x42\x3c\x3d\x1f\x68\x1d\xd7\x3c\x01\xd0\x6c\x3b\x94\x15\x06\xc9\x8e\xed\x9b\x78\x68\xe0\x17\xb7\xf9\x97\x16\xb0\xb7\x7f\x11\x32\x1e\x5a\xb2\x3d\xbf\xcf\xca\x93\x50\x84\x5e\xe1\x80\x44\x4c\x50\xff\x0a\x9c\x96\x5f\xcb\xf7\x77\x70\x8e\x4f\x34\xcc\xc6\x37\xc6\xa0\x8d\x85\x43\x84\xf8\xd3\xe2\x51\x69\x56\xc1\x51\xd0\x31\xbb\x1c\xbe\x71\x2a\x5e\xf9\xee\x16\x61\x92\x28\xbd\x29\x6f\x2a\xfe\x58\x2d\x99\x53\xd5\x90\xd1\x8b\xb2\x05\xf7\x0f\x84\x4c\x16\xc0\xa2\xd8\x31\x80\x37\xd4\x3d\xd8\x0f\x65\xc6\xa7\x53\xf2\xa8\xe2\x7c\x89\xc8\x3e\x7e\xd7\x0c\x52\xf7\x06\x2d\xfb\xb1\xf5\x44\xaa\x23\x6b\x5c\x70\x4e\x7b\x39\xce\x0a\x55\xfd\x46\x52\x80\x83\xca\x61"}, -{{0xdb,0xfa,0x45,0xab,0xaa,0x55,0x41,0x52,0x38,0xb1,0x28,0x76,0x34,0xd5,0xee,0xc4,0x02,0xda,0xdf,0x62,0x2e,0x27,0x0c,0x04,0xa8,0x91,0x4c,0xed,0x27,0x0a,0x72,0xbe,},{0xc0,0xfe,0x32,0x35,0x81,0xea,0x29,0x67,0x50,0x79,0x7e,0xb5,0x50,0x8c,0xa1,0x9a,0x58,0x3b,0x53,0x7f,0xa7,0xdf,0x45,0x29,0xf0,0x80,0x4a,0x33,0xc1,0xa4,0xbe,0xf4,},{0xa4,0x62,0xa9,0xba,0xa5,0x6d,0xc0,0xf7,0xa7,0x1b,0xf8,0x7b,0x95,0xf4,0x8d,0x64,0x20,0x22,0xd9,0xd1,0x73,0x3e,0xe3,0x68,0x37,0x77,0xa3,0x78,0x22,0x28,0xac,0x85,0xfc,0xd8,0x30,0x26,0xbe,0x4c,0xa9,0x7a,0x34,0x5b,0x08,0x4f,0x50,0x87,0x4e,0x91,0x24,0xe1,0x6b,0xa1,0x7d,0xea,0xd4,0xad,0x85,0xc0,0xe5,0x6f,0x16,0xef,0x18,0x04,},"\xe2\x6e\x8d\xcb\x44\xe6\x41\xfc\x20\x08\x0e\x95\x47\x4b\xd3\x9d\x71\x6c\x5a\xfe\x5a\x1f\xfb\x05\x6d\x1e\xaa\xb0\xc4\x9f\x85\x70\x71\x7d\xb6\x43\x7a\x03\x22\x8a\x9a\xd9\xf4\xbb\x0b\x34\x3b\x95\xe1\x60\x23\xc0\x80\x7e\xb2\xa1\x51\x06\xa6\xeb\x12\xdc\x76\x68\x3e\x69\xdd\xa3\x36\x31\x48\xc5\xd7\xdd\x97\x13\xaf\x6f\x87\xa0\x94\x10\xea\x8f\x76\xb6\xb7\x8a\x11\x44\x29\xbc\x85\xf7\x84\x81\x2f\xca\x31\xac\xb0\x30\x95\x52\xcc\x18\x8c\x6e\x96\x97\x09\x3c\xf4\x04\xc6\xf0\xf4\xab\xe8\xa1\x60\x86\x73\xfd\xfa\x5e\xb7\x8f\x65\xfc\x1d\x49\xcd\xec\x40\x94\xb1\xbd\x23\x4a\x46\xe0\xec\x62\xa4\xb6\xd3\x1b\x82\x96\x11\x54\x01\x27\x87\x6b\xff\x4c\x17\x3d\xe0\x58\xcf\x61\x00\x4b\x01\x4a\x7b\xdf\x79\x3d\xfd\x6b\x63\xc5\x07\xd2\xb2\x3e\x0f\x56\xbc\x2f\xe6\xba\xf6\x37\xce\xe4\x0d\x18\x99\x22\x95\xd8\x48\xef\x49\x8f\x8a\x16\x1b\xd8\x7e\x60\xc9\x1f\x97\xa9\x1e\x9e\xf3\xf6\xd9\x7f\x2b\x2d\x21\x04\xba\x6f\xdd\xd6\xc6\x80\x70\x62\x73\xda\xe8\x7e\x6e\xec\x1a\xf2\xa4\x59\x84\x98\x50\x69\xe8\x09\xe8\xde\x32\xc1\x28\x89\x29\x9a\x32\xd4\x0f\x38\x77\x45\x99\xac\x33\x24\xb7\xcb\x0a\x4e\xa6\x32\xc5\xf9\x10\xad\x87\xf5\xad\xbf\xa5\xc3\xbb\x20\x49\x82\x79\xfd\x53\xc1\xc2\x67\xfe\x0a\x84\x77\x30\x85\xda\x26\x6b\x25\x3c\xd8\x53\xdf\x7e\x96\x35\x58\xcb\x06\x88\x07\x80\x97\x34\x23\xc5\x64\xcd\x0b\xcd\x6b\x93\x33\x4c\x19\x59\x53\xd7\xcd\x89\x9f\x8a\x54\x7d\x1a\x1a\x0a\x8d\xef\xf1\x38\x1b\x43\x21\x57\x47\x28\xcf\x71\xb9\x6f\xf2\x09\xe8\x99\xda\xa8\xf1\x3f\x41\xb2\x30\xe1\x7b\xff\xdf\xdd\x2a\x89\x43\xaa\x5d\x21\xe5\xf3\x6e\x1d\xa0\x7e\xdd\x6c\xee\x92\xdc\x48\xb5\xb2\xa7\x58\x01\x46\xa9\xba\xf7\x13\x95\x0c\xe6\x76\x25\x5a\x89\xe3\x4f\x87\x87\x54\x7d\x62\x86\x8d\xb1\x4b\xa4\x65\x94\xda\x31\x0d\x7e\x2d\x9e\x7c\x7d\xbe\x17\xdb\xd7\x1e\xb4\x7c\x56\xc5\x72\x1d\xc9\x6d\x69\x64\x70\x57\x37\x94\x80\x94\x11\xcd\xfa\x27\x6b\x05\x9d\x00\x07\xc2\x5d\x74\xb2\xa6\x7d\x38\x24\x6d\xe1\x1e\xf4\x6d\xfe\x26\x70\x92\x6f\xe4\xb6\x36\x56\x23\x1b\xc7\x26\x8b\xba\x23\xf3\x78\xe8\x4a\x42\x8c\x3c\xbf\x45\xcc\x53\x96\x78\xfd\x46\x7c\xd3\x3d\xd0\x75\x7c\xfa\x02\x4e\x54\xda\x1f\xf5\x4c\xe8\x20\x22\x9b\x77\x8b\x18\x4b\xe1\xfa\x2e\x84\x68\xcc\x19\x95\x59\x40\x73\x5e\xaa\xa8\x84\x02\x2f\x64\x18\xb0\xb1\xf2\x6b\xcc\xf1\x69\xf1\xbc\xac\x7d\x82\xa3\x5a\xb6\xef\x84\x7e\x1d\xba\x53\x7d\xca\xff\x57\x25\x0a\x8d\x1c\x71\xfa\xcb\x13\x4c\xd0\x6b\x01\xc4\x53\x19\x13\x27\x45\xdc\x48\x88\x88\xa1\xd7\x76\x1b\x84\x86\xa3\x7e\x69\x88\xa1\x12\x0b\xcc\x16\x82\xdb\xfc\x89\x14\x3f\xc3\x5b\x46\x93\x5d\x8a\xcf\x6e\xf3\xc4\x2f\x0f\x4b\xf6\x79\xdf\xd6\xff\x44\xb6\xad\xa2\x6b\x01\xa9\xf8\x9f\x37\x4c\x7d\x2e\xe4\x8d\xfe\x1a\x41\x0e\x89\x7c\xdf\xd9\x7f\x62\x6d\x26\x68\x50\x28\x14\x40\x07\x93\xb3\xb0\x7c\x87\x20\xbb\xdd\xc5\x9c\xb0\xf9\xde\x96\x4a\xe0\x75\xb4\xaf\x3d\xd4\xba\xf6\xd0\xe4\xf9\x4f\x29\x4e\x81\x09\xd6\x57\x7c\x4f\x8a\x9c\x7a\x5f\x7d\x69\x4b\xf8\x8f\x1a\x5e\xa7\xeb\xa0\xa6\x6d\xa6\xc7\x70\xc0\x8b\x3a\xbf\xfc\x53\x4d\xf2\x19\xdc\x3e\x33\x23\xb0\x22\xe9\x6c\xc8\x60\x02\xb1\x89\x18\x1a\x1d\x2b\x52\x7d\x27\x95\x0b\x7f\x42\x5a\x47\xda\x40\x13\x77\x8b\xd0\x0b\x71\x10\x59\x22\x20\x49\x21\xe9\xdc\x69\x2c\x23\x3f\x7b\xaa\x04"}, -{{0xef,0x64,0xe1,0x7a,0x53,0xf7,0xfb,0xca,0xfe,0x3e,0xa4,0x68,0x76,0x84,0xa0,0xda,0xdb,0x18,0xd0,0x37,0x35,0xa4,0x0a,0x53,0xb3,0xed,0xb0,0x49,0x07,0xee,0x61,0x62,},{0x91,0x86,0xe6,0xbc,0x14,0x29,0x61,0xc4,0xd3,0xeb,0x36,0x9e,0x9e,0x11,0x57,0x82,0x92,0xde,0x5b,0x6a,0xf5,0x34,0xd4,0x23,0xff,0x24,0x0f,0xa2,0x6e,0x21,0xa7,0x81,},{0xf5,0x8f,0x39,0x6b,0xa2,0x7e,0x06,0x7a,0x5f,0xe0,0x03,0xe3,0x85,0x58,0x2a,0xe3,0x49,0x0e,0x05,0x95,0x77,0x15,0xd7,0x04,0xda,0x0d,0xa6,0x3a,0x64,0x19,0xd2,0xe4,0xf6,0xdc,0x66,0xb7,0xe8,0x8e,0x42,0x8a,0x6f,0x21,0xb9,0xea,0x20,0x22,0x99,0xa3,0xc3,0x6b,0x24,0x2b,0x0e,0xa0,0x64,0x76,0xff,0x12,0xd0,0xb6,0x58,0x0c,0x04,0x03,},"\x68\x82\x45\x6c\xc3\xd1\xad\x0d\xaa\x9b\x88\xef\xf0\x96\x9f\x15\xe9\x7b\x48\xd0\x51\x96\x7e\x13\x90\x84\x72\x25\xf2\x6a\xc2\x55\x59\xf0\x24\x6b\xf7\xd6\x83\xfa\x28\xec\xed\xad\x21\x49\x1d\x77\xbd\x26\x96\xfa\x83\x5d\x0f\xd1\x19\x88\x4f\xec\xe9\xd8\x03\x69\x1b\x2f\xd3\xde\x17\xee\x08\x7c\x74\x00\x7a\x7d\xe9\xbc\x65\x34\xbb\xfe\x95\xfd\x32\xe9\x7c\x37\x5f\x4c\xb6\x57\x31\xaa\x1e\x83\x46\xbe\xa2\x1b\xe9\xf2\xc3\xdc\x87\x4a\xf0\x43\x19\x06\xcc\xbc\x2c\x60\x01\x27\xf4\xd3\xb0\x69\xeb\x09\x1d\x16\x5e\xc4\x53\xe6\x72\xe9\x3c\xae\x8b\x72\xf0\x33\x71\xd8\xb8\xa8\x24\x4e\xc4\xec\x2e\x09\xf3\x1d\xf4\x02\x06\xa2\xb1\xc8\x4c\xaa\x1b\x99\x3c\xc6\x75\xfd\xe1\xc7\x9b\xd4\xa7\xd1\x59\x74\xfa\x29\xce\x2e\x89\x2c\x28\x99\xcf\x48\x2c\x3d\x96\x63\xf6\xd2\xa7\x97\x84\xf4\x1c\x1f\x58\x66\xd3\x7c\x85\x46\xf3\x57\xd5\x64\xd3\xc4\x21\x8d\xfa\x6d\x20\xb6\xc2\x82\xb4\x00\xfe\xdd\xe5\x24\x39\xd4\x72\x21\x2c\x57\x67\xa3\x5d\xa5\x20\x10\x32\xda\x87\x30\x96\x8b\x07\x20\xe8\xa6\x04\xde\x6c\x1b\xaa\x3f\x4e\x89\x6a\xc2\x61\x4f\xb1\xab\x6e\x3f\x6c\xf3\x87\xa8\xeb\x2f\xf8\xa9\x21\x47\xab\x34\x92\x38\x43\x2e\x50\x9d\x82\x9c\xb7\x5b\x2c\x17\x65\xc5\x12\x21\x84\x8e\x25\xaf\xff\x5f\x16\xe4\xdd\x0c\xd5\xc9\xf7\x13\xc4\xaa\xab\x2c\xe8\x36\xf8\x49\x45\x06\xb5\x30\x9d\xc2\xb0\xae\x74\x5b\xb9\xc4\x79\x80\x98\xfb\x86\x41\xd5\x20\xa0\x8b\x02\xf7\x5a\xd8\x0d\xbc\x2c\xe2\x9e\x89\x0b\x4d\x72\xa3\xff\xb2\xa1\xcb\xd5\x38\xe1\x22\x9f\x57\x9c\x29\xae\x66\xbc\xa8\x5e\x0f\xa0\x8c\x86\x47\xa1\xab\xcf\xe8\xa4\x9f\x5e\x50\x8d\x4d\x24\x95\x55\x66\x23\xd9\x26\xce\x49\xef\xa4\x35\x0a\xaa\xab\x5c\xec\x2c\xd8\x85\xbe\x1d\x63\x47\x5e\x3b\xab\x7c\x7c\xdc\x8d\x65\x61\x73\xb8\xd4\x56\x02\xf4\xb3\xd2\x81\x24\x1d\x17\x19\x03\x27\xb2\x4c\x38\x36\xb1\x93\x11\xa1\x93\xaf\x86\xa6\x76\x8f\x04\x85\x2a\xb0\x6e\x67\xc8\xea\xd5\x91\xcd\xcb\xf3\x78\x9c\x61\x32\x09\xcf\xe0\x3f\x58\xc0\x30\x5f\x63\x20\x3b\x48\x7f\x7c\x5f\xc0\x98\x87\x7e\xc9\x8a\x68\x9c\x9d\x35\xaf\x81\xe8\x40\x78\xd6\x6f\xe9\xe4\xec\xcb\xb1\xcc\x6c\x71\x99\x1c\x03\x01\x7b\xb8\x11\xf4\x1f\x07\xde\x68\xfa\xd1\x94\x14\x60\x61\x32\x4f\x3d\x0e\xf2\x17\xa5\x4c\xf3\x8f\x7a\x62\x5a\x38\x86\x9f\x67\xd0\xb7\x43\x1d\xf9\x37\xcd\xe3\x49\xc1\x75\xce\x8b\x26\xac\x88\xd3\x9a\x43\xe2\x79\xb0\x18\x76\x4e\xfa\x4d\xd6\x27\xcb\xf5\x91\xf6\x20\x9c\x4a\x5b\xb1\x9e\xbf\xa7\xc7\x13\x55\x92\xd0\x2e\x50\x1c\xae\x5e\x6b\x31\xc9\x0e\x72\xfa\xab\x47\xf7\xdc\xed\x2c\x48\xad\xf8\x84\x43\xb3\xed\xe6\x0c\xef\xb0\xd6\x37\x9d\x69\x22\xec\x43\x7f\x08\x6b\xad\x62\x17\xd4\xd4\xff\xef\x18\xe2\x25\x23\x66\x4b\xf4\xe9\xca\x1e\x65\xa2\x8c\x2a\x7a\x60\xc5\xf6\xbc\x90\x6b\x73\x7c\x29\x93\x5f\x90\x97\x46\x30\x48\x57\x5b\xef\xd1\xa2\x54\x9d\xc4\x74\xb1\x3e\x68\xae\xec\xf1\x66\x04\x3e\x07\x5a\xac\x51\x55\x40\xf8\x31\xb4\x30\x66\xce\xf9\x32\xe6\x3d\xcd\x5b\x37\xb6\x15\x78\xc3\x5b\x09\xe4\x5c\xc2\xa8\xde\xf5\x71\x03\xed\xfc\x5f\x64\x98\x31\xa8\x96\x1f\xe4\xa4\xb3\x72\x1f\x1d\x6d\xf4\xea\x9f\x03\x38\x81\xb4\x74\x30\x0e\x0f\x12\xcb\x9c\xd3\xba\xbd\xcf\xfb\xb9\x18\xdd\x9b\xb0\xe2\xf5\xb2\x10\x33\xe4\x30\x23\xa0\xd2\xe6\x6d\xa3\xab\x0f\x07\xee\x98\x8b\x16\x88\x9c\xa5\xd5\x1a\xbd\xc0\x5f\xde"}, -{{0x33,0x47,0xdc,0x47,0xbb,0x3d,0x2e,0x5d,0x02,0x86,0xac,0x06,0xa5,0x4f,0xd9,0x21,0xc9,0xe9,0x6b,0x68,0x99,0x86,0x2a,0x54,0xe5,0xcc,0x81,0x15,0xd3,0xd0,0xba,0x99,},{0xd0,0x0b,0x64,0x5d,0x86,0xdb,0xb7,0xe5,0x24,0x75,0x7e,0xc7,0x78,0xc6,0x2b,0x7e,0x60,0xd0,0xb6,0x57,0x68,0x83,0x33,0x8c,0x9b,0x67,0xc2,0xc7,0xe4,0x50,0x92,0x68,},{0x9a,0xb4,0x29,0x9b,0x17,0x72,0x93,0x44,0x75,0x0b,0x69,0xdc,0x60,0x37,0x36,0x8c,0x98,0xf4,0x7b,0xe6,0x27,0xfb,0xd9,0xad,0xfd,0x8d,0xb3,0x9f,0x99,0x64,0xdd,0xb7,0xbc,0x92,0xd6,0x74,0xc7,0xbe,0x74,0x07,0x56,0x39,0x6b,0xaa,0xee,0xac,0xbf,0x74,0x94,0x7b,0x61,0x91,0xc6,0xed,0x1f,0x5d,0x32,0xa6,0x3d,0xf3,0x6d,0x54,0x26,0x01,},"\xe2\xf4\x8e\xdf\x9d\x64\x33\x20\xab\x99\x1c\x8f\xf9\xf6\xaa\x75\xfe\x06\x6e\x7d\x88\xff\x1e\x47\x2a\x5a\xc9\xc5\x18\xde\x1f\xb6\x29\x83\xb1\x00\x7f\x64\x22\x80\x91\x17\xbd\xbe\x8a\x0e\x57\x87\xf6\x6b\xb0\x57\xd2\x7f\x12\x9a\x20\x0b\x40\x57\x6e\x17\x19\xcf\x9e\x98\xfc\xb7\x2a\xf9\x4b\xb8\x2e\xe7\x0f\x37\x19\xa2\xe2\xcd\x9b\x64\x77\x7c\xea\x5e\x44\x64\x59\x87\x4b\x74\xbf\xbf\x56\xb2\xd2\x52\x64\x00\x59\x2a\x9b\x45\xa5\xcb\x79\x80\x92\xb6\x0a\x81\xb7\x1d\x82\xf0\x68\x5f\xae\x7f\x81\x0b\x52\xd2\x26\xad\xac\x7a\xd8\xa9\x18\x3f\x09\xfe\xbe\xe9\xd2\x50\x46\xc0\xfe\x30\x66\x81\xac\xe2\xbf\xf9\x1b\x34\x82\xb0\xbc\x30\xb2\x02\x1c\x43\x41\x64\x5d\x67\x51\x34\xfe\x30\x81\xc5\x1e\x5c\x59\xe4\x0b\x37\x5a\x14\x34\xf6\x3b\x42\x6e\x30\x53\x0d\xa9\x35\x3b\xb2\xa9\x42\x32\x20\x43\x4a\xe5\x9d\x7b\x6f\xdc\x14\x3f\x49\x82\xeb\x8c\xfa\x77\x51\xb7\x5b\xf3\xe9\xc9\x13\xc7\x3b\x76\x0b\x07\xd3\x95\x31\x0c\x59\xf3\xb7\x7e\xbf\x12\xed\x2d\x7b\x03\x59\x0d\x33\x17\xaf\x17\xdf\x42\x1e\x78\xb0\x84\x9f\xd5\x6d\x94\x5c\x56\x96\xa0\x40\xfc\xaa\x78\xa9\x3e\xcc\x16\xd5\xac\x34\x45\x06\x36\x11\xf3\x01\x3e\x9a\x3a\xe2\xe1\xc2\x70\xdd\x01\xa8\xff\xe3\xe6\x12\x6b\xc1\xe4\xc9\x5f\x65\x47\xa8\x65\x1f\x26\xb6\x40\x4e\x39\xee\x4c\xe7\x61\x89\x18\xf3\xf9\x37\xa5\x25\x73\xec\x27\x7b\x77\x1e\x91\xad\x09\x6f\xa1\x5c\x7a\x34\x0a\x80\x9b\x47\x03\x18\xa4\x63\x64\x23\xeb\x48\x88\xa1\x21\x60\xc4\x66\x3f\xce\x29\x96\xd6\x38\x89\x6c\x83\x9b\x2c\x7a\xd4\xb3\xa9\xb2\xe6\xcb\x71\xe9\x12\xfe\x39\xb8\x43\xc6\xe0\x83\x2e\xca\x22\xde\x93\x8b\x50\xae\x86\x3e\x48\x58\x2c\x10\x85\x12\x32\xf7\x5e\x52\x25\xb8\x89\x6b\x5a\x47\x0f\x81\x8b\x6f\xa3\x9e\xb7\xbb\x59\x03\x57\x67\x86\x12\xd2\x5f\xe1\xa4\x0e\xa1\xb9\xd7\x1d\x88\x09\x09\xc1\xbd\x4a\xd1\x76\xcc\x0c\xef\xfd\xce\xe7\x09\x9e\x78\x82\xa7\xc9\x07\xe4\xbe\xc7\x98\x30\xc6\x77\x1a\xcb\x89\x94\x4b\xd5\x4a\x51\x65\xb3\x18\x70\x91\x69\x21\xb1\x98\xac\xd4\x43\x2e\x7e\xed\x8c\xe1\xde\xb3\x45\xb1\x07\xed\xa7\x60\x26\x6f\xcb\xda\x3b\xa5\x22\x94\x00\xa3\x03\x60\xa4\x64\x5c\xa8\xdb\x38\xc3\xd5\xf4\xa8\xde\xf1\x57\xbb\xdb\xbf\x2c\x1f\xa1\xdc\x6b\x05\x14\xa4\xf5\xa0\x36\x4f\x92\x83\x81\xb4\x0f\x95\x57\x9a\x26\x46\x7f\x22\x82\xa8\xa2\x55\x75\x84\x02\xac\x9c\xa8\x0e\x89\xb9\xcc\x68\x60\xa3\x4b\xb3\xf9\x0c\x32\x37\x65\x7c\x21\x29\xea\x48\xc8\x52\xb9\x25\x69\xe8\x11\x06\xbc\xe4\x61\xe2\x02\x44\x54\x82\x1a\x91\x75\x92\xd1\x99\x1b\x5b\x69\xf2\x7b\xbe\x01\x99\x77\x52\x8a\x2f\xc0\x11\x92\xc5\x6b\x4a\xea\x87\x3c\xf8\xc5\x8d\xfd\x7c\xb4\xb0\xe9\x17\xe8\x7a\x87\x04\xc9\x92\x82\x0f\x98\xd7\x74\x04\xd3\xf1\xd2\x05\x0c\x67\x43\xf6\xe9\x3c\xdb\x51\xa6\x1a\xa6\xf4\x5b\x35\x1b\x26\x46\x1d\x13\x29\xf3\x15\x12\x72\xac\x39\x62\x34\xd0\xd6\x7c\x17\x8a\xcf\x91\xfc\x51\x0d\x86\x42\x9c\x69\xa8\x7f\xdf\x10\x11\x55\xda\x8d\x94\xde\x67\x22\x23\x8a\x6f\xb1\x70\x16\x86\x2b\x11\xd5\x02\xc6\x67\xee\x9c\xa0\xaa\xbe\x1c\x20\xb9\x77\x89\xf1\x86\x7a\xdd\x78\xb8\xb8\x7e\x9a\xb5\x19\x34\xc0\xb4\xa1\x6c\x2c\xbc\x4d\x2e\xfe\xdb\x79\xc0\x5b\x23\xe0\xcf\x78\x92\x01\xac\x75\xfe\x07\x6d\x31\x5f\xcb\xac\x20\xba\x0d\x31\xe4\xdc\x61\x69\x27\xd6\xea\xb1\xb1\xc8\x7a\x1c\x9c\x77\x8e\x4b\xd2\x85\x29\x58\x74"}, -{{0xff,0x15,0xd6,0xe7,0x4e,0x28,0xe4,0x1d,0x05,0xa8,0x66,0x3a,0x70,0x2f,0x03,0x8d,0x5b,0x85,0x78,0xc4,0x27,0x5e,0x77,0x2b,0x73,0xba,0x44,0x0b,0xc5,0xf5,0x5a,0x06,},{0x47,0x47,0xe2,0xe9,0xb8,0x26,0x37,0xb3,0x84,0x4b,0x85,0xf7,0x5b,0x59,0xf7,0x13,0x6b,0x7f,0xdb,0x1a,0x62,0xe7,0xb7,0x0d,0x6a,0xac,0x17,0xb3,0xc5,0x75,0x2f,0x2f,},{0x42,0xc1,0x29,0x5f,0xaf,0xe2,0x6d,0xe3,0xea,0x34,0x92,0x6b,0xf1,0xef,0x80,0xbc,0xaf,0xe4,0x7b,0x21,0xb9,0x0e,0xae,0xd1,0x96,0x35,0xed,0x75,0x38,0xd7,0x67,0xcb,0xf3,0xa1,0xe5,0xde,0xda,0xab,0x82,0xad,0xf7,0x51,0x20,0x37,0x3e,0x92,0x32,0x02,0xf7,0xfd,0xa0,0x82,0x67,0x84,0x29,0x2e,0xba,0x8b,0x23,0x8b,0x6c,0xb8,0x83,0x04,},"\xce\x7b\xf9\x72\x84\x4f\x51\x84\xae\x8e\xac\x87\xb1\x2b\xe9\x20\x2c\x72\x39\x96\x1d\xc2\x3c\xd4\x1f\xf5\x5b\x9b\xfa\xac\x0c\xc0\x6f\x3f\x1d\xec\xfa\x95\x71\x09\x5c\x8e\x82\xb4\xeb\x6f\x8a\x1c\x52\xc8\xd3\xde\xaa\x61\xa9\xaa\x94\xe2\xec\xd9\xab\x5b\x80\x63\xf2\xda\x6d\x80\x15\xdf\x0a\x51\x44\xfa\x3a\x48\xe3\x05\xad\x9f\x41\xea\xa1\x1c\x4d\x74\x85\x43\x74\xec\xbf\x38\x2e\x30\x02\x57\x9a\x9a\x24\x9e\xfa\x1e\x1c\xa0\x4d\x33\x84\x47\xd7\xf2\x20\x67\x03\xe6\xca\xbf\x5b\xbd\x33\x2b\x42\x57\x3b\xcb\xd3\xb6\xf7\x1b\x7c\x3b\xf7\x3d\x4c\x77\x4a\xa0\x1e\x86\x68\x41\x43\x28\x29\xd0\x7f\x96\xe1\xf6\x1a\x20\x21\x6d\x96\x8c\x90\xe3\xed\x11\xf6\x63\xf7\xd6\x27\x16\x22\xfe\xfc\xf3\xab\x68\xf3\x44\x32\x85\x15\xd5\xcc\xe2\xce\x85\xe8\xbf\x3d\x1d\x09\x04\x36\x92\xe1\xfb\x8b\xbd\xdc\x07\xa4\xab\x0a\x3e\xef\x8c\xa6\xa4\x20\xe7\x4b\xff\x8d\x3d\x71\x55\x96\xaa\x82\x16\x82\x95\x4f\xe8\x96\x29\xae\x27\xc1\xbb\x03\xb6\xaa\x09\xf3\x6a\x39\xa3\xe3\x7b\xa9\x81\x32\xf4\xe2\x38\x88\xf9\xf3\x35\xe7\xbe\xaa\x2c\xb2\x72\x7a\xcc\x3d\x27\x77\x30\x9b\x85\x29\x52\x32\xe5\x4d\xa8\x8e\xbb\x6f\x10\x53\xd6\xde\x79\xac\x66\x09\x85\x2e\xb9\x3a\x0a\x35\xbc\x1a\x7b\xdc\x22\xd6\x28\xbc\x86\x12\x4d\x69\x6c\x3f\x98\x28\xb6\xf8\xb9\xaa\xde\x1a\x65\x21\x61\x77\x48\x6c\x25\x2a\x4b\x42\xd9\x0a\x4e\x0f\xea\x20\x93\x48\x9e\x24\x4d\x80\x8e\xf7\x02\x1a\x97\xd5\x60\x8c\x0a\xe1\xd6\x63\xc7\x75\xe8\xbb\x9e\x9a\x73\x15\xf1\xfe\xb6\xd1\x29\xb5\xa5\x41\xea\x59\x29\xa2\xc6\x33\xb6\xd8\xc3\xc4\x54\x41\x71\x79\x46\xcf\x87\x3e\x9b\x4c\x51\x21\x80\x13\x5d\x54\xf0\x53\xab\xe4\x4c\x6d\xf3\x9b\x7b\x06\x2e\xf7\x24\x01\x62\xcb\xd0\xb8\x51\xaf\xe5\xf9\x15\x36\xa9\x49\x94\x18\xe8\xbf\xf4\x99\x64\x73\xd8\x05\xeb\xc1\xae\x48\xda\x2d\x0b\x12\x9e\x8e\x82\x52\xf1\xd5\x3c\x32\x8f\x32\xdb\x25\x2d\xe3\xbe\xfb\xe5\xf3\x12\x80\x12\x11\x43\xa8\x00\x4a\x4c\xae\x63\x1c\x82\x74\x09\xe5\x20\xe3\x94\xcd\x0f\x89\x50\xcd\x4c\x3c\xf3\xf3\xdb\xd4\x95\x2a\x4d\xfe\x69\x87\x5f\x56\x53\x89\x06\x1a\xd0\xa0\xce\xe6\xb6\xaf\xf0\x9c\xec\xa2\x6d\x99\x0e\x89\x6a\x2a\xba\x9f\x3b\x26\x01\x5b\x63\x42\x37\x68\x68\x4c\x03\xed\x0d\xe6\xce\xe7\xac\x5b\xbd\xf9\xf4\x85\xc2\x27\x5c\xd1\x2a\xef\xa8\xf9\x07\xb8\x51\xa0\x2d\x51\xc3\x4f\x12\x1b\x77\xf3\xa5\x6a\x9e\xbd\x1d\x65\xff\xe8\x9b\xee\x38\x1f\xf2\xa7\x48\x0e\x89\x68\xcf\xf2\x5a\xc8\xd0\x4e\x14\x9a\x9d\x50\x27\xd1\x4b\x88\xf8\xae\x26\x04\xd2\xac\x22\xac\x67\xd1\x3e\x90\xad\xa6\x20\xc2\x04\x6d\x28\x29\x93\x84\xd0\x95\x9f\xb7\x6e\x22\x58\x87\x96\xce\x42\x7a\xae\xaf\x4e\x2a\x8a\xae\xc3\xe8\x7f\x84\xcc\xd0\x82\x52\x4c\x96\xd7\x66\xee\xc6\x6f\x0b\xec\x3e\x79\x95\x58\x14\x5f\x09\xd3\x30\x13\x4f\x1c\x63\xf3\x70\x53\xcd\x4b\xdc\x1c\x37\xfd\xe9\x72\x91\x85\x75\x51\xf5\x0a\xc8\xe1\x5f\x06\xac\x1c\x73\xda\xa1\xe8\xc5\xbc\x92\x77\xe3\xd6\x9c\xb4\x4a\x32\x37\xec\x57\xdb\xbc\xcf\xdf\x66\x85\xad\xa2\x0b\x74\xa1\xbc\x6b\x74\xab\x05\x69\x0e\xaf\x9b\xd0\xc4\xbe\x17\x04\x2f\x5c\xd3\x20\xcd\xd6\x13\xdc\x08\xd2\x9a\xf3\x46\xaa\x41\x91\xce\x0b\x4f\x85\xbb\x2a\xd7\xf3\xba\xc7\x38\xa9\x37\x7e\xc6\xb8\x40\x62\xcc\x70\xfc\xa9\xec\xfb\xe1\xf5\x7f\xe5\xb2\xce\x7a\x4f\x73\x9c\x81\xca\xbc\xde\x04\x64\x51\xdd\x61\xce\x1d\xbc"}, -{{0x1e,0xd3,0x7b,0x61,0x0b,0x8b,0x35,0x41,0x7d,0x04,0xe5,0x9a,0xaa,0xda,0xc6,0x88,0xff,0x81,0xf1,0xe5,0x07,0xc8,0x9b,0x4f,0x40,0x01,0x60,0x94,0x19,0x08,0xcb,0x8c,},{0x48,0xe8,0xcb,0xeb,0x12,0x40,0xbd,0xeb,0xf0,0xa2,0xd9,0x29,0x53,0xaa,0x89,0xb2,0x82,0xc4,0x9a,0xab,0x2c,0x38,0xae,0x69,0x04,0x4c,0x51,0x51,0x5c,0x33,0x00,0xd5,},{0x86,0x08,0x81,0x5e,0x10,0x59,0x0d,0x55,0x04,0x87,0x4d,0x89,0x99,0xfd,0x6f,0x09,0x62,0x6f,0x95,0x0b,0xe2,0x0c,0x91,0x2c,0x27,0xc9,0xde,0x6e,0x79,0xb0,0xfa,0xf7,0x77,0xa5,0x33,0xbd,0x5b,0xb6,0x67,0xab,0x51,0x3a,0x49,0x45,0x8e,0xcd,0x67,0x87,0xa0,0x9e,0xc0,0xdf,0x6c,0x9c,0x9d,0x63,0x33,0xc5,0xe3,0xae,0x61,0xea,0x37,0x0a,},"\x1e\x67\x67\xdf\x97\xdb\x1c\xfb\x40\x88\xda\x7b\x20\x0d\x9f\x59\xec\x8d\xd4\x53\x3b\x83\xbe\x30\x9f\x37\x65\x00\x31\x06\x57\x27\xcd\x52\x02\xce\xf4\x84\x26\xa5\xf3\xa1\x1d\x50\xb3\x81\xf8\xbc\x22\xff\x10\x18\x27\x35\x9f\x2d\x0a\x61\x0a\x4f\x75\x54\x64\xa0\xc8\x91\xcb\xd9\x8d\x2d\xcb\x41\xd9\x77\x9d\x28\x8f\xcf\x1f\xea\x62\xe5\x21\x63\xae\x67\xe9\x04\x28\xb8\x63\x98\xef\xa2\x18\xf1\xb9\x82\x08\x1f\xc5\x13\x30\x5f\xd3\xe8\xec\xe7\xf9\xac\xb0\xe1\x0e\x00\x1d\x2e\xd2\x99\xa4\x8a\x80\x87\x0b\x3d\x5d\x8a\xb9\x00\x63\x09\xb3\x15\x91\xca\xf0\x58\x33\x80\x07\x3a\x2d\xb6\x1f\x45\x25\x4a\xb9\x65\xb5\xe4\x67\x2c\x4b\xfa\xa8\x6e\x33\x6c\x49\x27\x85\x52\x72\x9f\xb2\xda\x76\xff\xe5\x02\xec\x61\xe1\x69\x6c\x7f\xc9\xef\x19\xf7\xcc\x2a\x27\x75\xb2\x97\x00\xcb\x38\x42\x94\x06\x3a\x17\xfe\xd4\xfc\x63\x5b\xc1\x32\x82\xa9\x0d\xad\x0c\x00\xaa\xdb\xcd\x56\x9f\x15\x6a\x85\x4f\x8b\xa9\xe7\xd6\x07\xd2\x0f\x2e\x9e\x53\x37\x98\x11\x61\xd8\x04\x64\x46\x68\xd0\x64\xfa\x63\xdc\xeb\x9f\x58\x01\x35\x3d\x0a\xb9\xf4\x1d\x1d\x8b\xdc\x76\xc1\x3a\xb2\xf0\x23\xea\x01\xad\xbc\x4c\x81\x68\xd9\x39\xe9\x8f\x64\xfd\x89\x19\x38\x4a\xbe\x76\x70\x92\x63\xc0\xcd\x7c\x3e\xfa\xdc\x28\x01\xcc\x4a\xbd\x80\xa0\x9b\xb3\xed\x6b\xb7\x8c\xd6\x20\x96\x9c\xd3\x5c\x6a\x3a\x5d\x01\x48\x5e\xad\x4c\x45\xeb\xb6\xac\x6a\x83\x21\x2a\x7c\x76\x67\x54\x27\xb2\x1d\xa8\xa7\xa5\x04\x7b\x30\xa6\x10\x0c\xda\x02\x47\x6c\x18\x6e\x6c\xe4\x0d\x27\x68\xa9\x42\xc9\xf8\x73\x05\xe9\xd3\x63\xb5\x24\xc0\x09\x4a\x9e\x2e\x29\xf5\x85\x89\x4c\x0a\xdb\xfc\xd6\x06\x90\xfc\x7f\xb0\xa9\xc7\x17\xcf\x43\xb4\x84\xfd\x45\x15\x1b\x13\x04\x16\x9c\x26\x92\x1d\xb2\x27\x6e\xc0\x5a\xd2\x2a\xd1\x66\x85\x4f\xd2\xf9\x40\x85\x77\x8c\x47\x0d\xc4\x52\xe5\xcf\xa4\xae\xe0\x4f\xac\xb7\x70\x52\x6e\x1f\x24\x8d\x3d\x15\xc2\x72\x80\xfd\xfa\x1f\xd2\xc1\x04\x4b\xcb\xc8\x81\xc3\xd9\x98\x15\xc9\x7f\xbe\xa4\x61\x10\xbe\x02\xda\xb7\x74\xf3\xa6\x10\xe5\x80\x2a\xbf\x36\xa4\x98\x75\xc6\x82\x63\x8e\x0a\xe4\xcc\x82\x77\xc5\xe9\xaa\x73\x07\x44\x5e\x6b\xbc\xbe\x54\x9e\xec\x2a\x45\xb1\x59\x7f\x74\x47\x10\x7b\x62\xe2\xce\xe0\xa5\xfc\x51\xbe\xae\x3e\x1f\xe9\xbe\xfb\x18\x85\xd9\xb3\x0f\x9b\x4f\x1f\x56\x20\x6d\xee\x0d\x67\x77\x9c\x57\xf4\x84\xc8\xc3\xc8\x99\xa5\x15\xa9\xd1\xc1\x0f\x60\x59\x84\x0c\x1c\x73\xd3\xf0\x5b\xcb\x88\x59\x0c\x52\xf7\xda\x39\x18\x38\xdc\x2e\x73\x22\x8f\x09\x81\xc2\x89\xa4\xc2\x7f\x0c\x75\x7f\xaf\x7b\x3b\x89\x14\x6e\x33\xda\xfa\x49\x0d\x9e\x0f\x92\x75\xb0\xcf\xa6\xa7\x71\x0a\x73\x83\x14\x59\x59\x5b\xf7\x32\x11\x2b\x62\xfc\x86\x4c\xa4\xc8\x29\x78\x4a\x3f\x16\xee\xc4\xe1\x8f\x93\x69\x18\xa7\xb9\x89\x16\x69\xe9\x33\x22\x3f\x74\x5f\xda\x56\x2b\xc0\xa4\xe6\x1e\x3d\x14\xea\x45\xdf\xc3\x27\xe2\xfc\x0c\xdf\xe6\xf2\xf9\x75\x46\xc9\x0f\xce\x82\xf5\x22\x29\x14\x80\x11\x1a\x1e\x6b\x93\x88\x27\x2c\x0b\xe2\x8d\x20\xed\x84\xbb\x84\xd4\x9b\xc1\x99\xcd\x59\x99\x48\xb8\xf2\x03\x9d\x07\x82\x7a\x3f\x40\x75\xd3\xa6\x7e\xe5\x72\xa0\x13\x79\xa3\x62\x13\xfe\x11\x6e\x76\x8b\x41\x14\xe8\xa4\xb3\x13\x4c\x38\x18\x96\x07\x72\xd7\x27\xb0\xca\x6f\x7c\x99\x7c\xa9\x98\x43\xb7\xeb\x02\xff\xc0\x13\x97\x1c\xbe\x0e\x6e\x60\xd4\x97\x73\xf1\xe8\xc0\xb3\x06\x06\x13\x1c\xb1\x0c\x3e\x04"}, -{{0x84,0x36,0x44,0x78,0xec,0x94,0xbd,0x25,0xc4,0xbd,0xb8,0x2d,0x29,0x62,0x29,0xe6,0xda,0xce,0x2b,0x13,0x59,0xd6,0xd2,0x1b,0xe2,0xb3,0xaf,0xcd,0x7b,0xda,0x19,0xc7,},{0xa1,0x81,0x4f,0x8c,0xe0,0xfc,0x3b,0x23,0x60,0x93,0xa5,0x0f,0x46,0x8c,0x13,0x16,0x21,0x1f,0xe6,0xc5,0x2e,0x23,0x45,0xd9,0xf0,0x76,0x6b,0x36,0x88,0xa0,0x3c,0xad,},{0xb4,0xc2,0x32,0x1a,0xde,0x3c,0x19,0xed,0x4e,0xd4,0xc6,0x39,0xd5,0xa4,0xd6,0xf2,0xbe,0x8e,0x2f,0xb1,0x3b,0xb7,0xbd,0x62,0x5a,0xd6,0xdc,0x87,0xe2,0xc2,0x0f,0x93,0xad,0x6b,0xe7,0xb7,0xe4,0x27,0x11,0xa8,0x78,0xdb,0x9d,0x76,0x05,0x4b,0xfd,0x7b,0xc2,0x5e,0x37,0x74,0xa9,0x3d,0xa1,0x54,0x3c,0x9b,0x4f,0x66,0x33,0xb0,0xbe,0x09,},"\x7b\xb7\x29\x3d\xe5\x5f\x05\x8f\xb2\xec\x22\xb6\x87\x26\x05\x43\xdc\xaa\x90\xf1\x40\xb9\xf4\x5e\xdd\xd4\xbc\x22\xe4\x09\x77\xe0\x0e\xd3\x3c\xd1\xef\x1b\xba\x13\xc1\xd0\x99\x08\x59\x00\x55\x69\xa8\x07\x67\xe4\x86\x4a\x2c\xd2\x88\xc8\x13\x93\xe0\x4a\xd9\x71\x78\x2e\x2b\xc4\x93\x10\x8c\xbe\x80\xda\xcf\x0b\x7b\x9c\xd5\x34\x98\x84\x07\xa4\xf9\x32\x7e\xc8\xe9\xc4\x04\x32\x84\xef\x6e\xe5\xa2\x6a\x5b\x41\x77\x65\xd3\xea\xbb\x48\xa0\x07\xe7\xc7\xf3\x29\x87\xd7\x0a\x13\x9a\xc4\x16\x78\xcd\xf7\xa5\x5c\xb8\x0c\xf9\xdb\x5e\xaa\x45\xf3\xde\x0f\xbf\xba\xdf\xfc\x40\x99\x63\x70\xe4\x8b\x1f\xf5\xed\xd9\x79\x40\xe7\x50\x79\x21\x64\x83\x6a\x4a\x5a\xc2\xe3\xff\x53\xe4\x8a\x1e\x55\x6d\xb9\xad\x0c\x5c\x0b\x94\x4f\x4a\xee\x51\x9a\x2b\x0a\x88\xbb\x1c\x1f\xc7\x45\x45\x24\xcd\x57\xaa\x53\x50\x98\x62\x43\xd3\x4f\xc5\x8e\x24\xe8\x19\xec\x0b\x85\x45\xd8\xdf\xcf\x6b\x20\x31\x14\x41\xd3\xa3\x5d\x3e\x71\xb3\xe3\xec\xd7\x88\x4d\xda\x84\x33\xa4\x05\xe3\xd9\x96\x90\x00\xc8\x20\xa8\x9b\x95\xd1\x97\x84\x1d\x98\xae\x73\x4a\x2e\x81\xda\xf6\xa7\xdc\xf5\x6c\xb2\xfc\x26\xf2\x16\x5a\x5f\x42\xb8\x6c\x7e\x9e\x5b\x11\x16\x17\x00\xa1\xab\x98\x31\xf3\xfa\xe5\x8e\x14\x20\x8b\xe1\xbf\x33\xb5\x8e\xcc\xe8\x1b\x0c\x6b\x7e\x02\xf8\x8a\xdf\x9a\xb0\x30\x26\x3e\x2c\xc9\xb6\xe3\x3e\xbc\xa3\xf4\x95\x49\x2e\x32\xbf\xe3\x72\x53\x7d\xe6\xc6\xb8\x76\x44\x82\x8f\x74\x94\x2a\x02\xb0\x07\xf1\x4c\x3f\xc5\xdb\xde\x76\x33\x3d\x36\xd0\x76\x31\xb7\xa9\x92\x4f\x71\x75\x50\x04\x06\x97\x92\x3f\xa7\xb9\x54\x6b\xfb\x02\x17\x02\x4e\xa3\xf2\x52\xb5\x15\xb5\xd6\x4a\x62\xc4\x8e\x02\x7c\xef\x67\x50\xbe\xda\x49\xa0\x24\x47\x03\x9b\x25\x0a\x0b\xda\x07\xdc\x06\x24\x91\xa6\x62\xe2\x68\x74\xc8\xd0\x0f\x80\xe6\xcf\xc8\xb3\x0f\x2c\x3b\xf7\x72\x0b\x57\xf2\x61\x5f\xc4\x78\xfe\xfa\xa6\xd3\x17\x05\xb4\x3c\x5a\x54\xf7\x58\x66\x6b\x30\x2a\x8d\x34\x95\x31\x31\x94\x1b\x79\x57\x73\x04\x76\x79\x4d\x0b\xd9\xd2\xdf\xa7\x2f\xd2\x03\xf2\x2d\xf5\xec\x6b\xba\xac\xe8\xb9\x39\x4b\xeb\xda\xea\xa5\x61\x46\x10\x11\xb4\xfc\xa6\x18\x5c\x9a\x38\x28\x3f\x54\x03\xfd\xac\x32\x6d\x1f\x73\x4c\x6a\x5d\xed\x67\x24\xd9\xf3\x84\xae\xbd\x6c\xab\xfc\xbe\xc1\x2a\xba\xb9\x82\x0d\x08\x07\x32\x51\x5e\x05\x00\xcf\x5d\x3e\x2f\x9e\xf8\x0a\x4d\x76\x46\xa7\xda\x9e\xff\x41\x0f\x50\x7c\x69\x87\x3b\x32\xd5\x40\xec\x32\xb2\x83\xef\x31\x79\xa4\xc6\x32\xb3\x66\x57\x6d\xff\x05\x8f\xaf\x8c\x8c\x70\xbc\x69\xbe\x80\x89\x82\xec\x14\x97\xae\x89\x11\xb0\x01\x65\xa6\x66\x95\xf4\xd3\xb9\x87\xe7\x39\x0b\x5c\xf8\x78\xe3\x5e\x67\x65\x41\x28\x5e\x4e\x13\xdf\xae\xb2\xf3\x68\xcb\x51\x1b\x77\x8b\x10\x6a\x42\x87\x78\xa1\xb8\xf2\xa7\xd2\xe0\x93\x51\x9b\xc9\xb5\x18\x8e\x38\xc6\x79\x3e\x96\xbd\x0d\x30\xe2\xa3\xdb\x9e\xe1\x46\x8c\x3d\xc8\x7c\xc3\x65\xc8\x10\xf9\xdb\xdf\x01\xa4\xb5\x14\x21\xf6\xfc\x8d\xfd\xa3\xa1\x6e\x2d\xa7\xca\x71\x59\xb6\x86\xa5\xe1\x67\x33\x89\x37\x88\x2f\xf7\x15\xd3\xe7\x50\xd9\x58\xfc\x9e\x4b\x1f\x05\x53\x12\x92\x99\xaa\x84\x30\x18\x3e\x50\x6c\xd7\xf2\xb2\x79\x07\x6e\x0e\x1c\xca\x97\x49\xcf\x12\x3c\xe5\x07\xfe\x07\xdd\xbb\xc4\xdc\xca\x6c\xdb\x9e\xf1\xb8\x33\xf6\x1d\x4b\xff\x00\xbe\xc0\x12\x15\x8f\x43\x2c\xeb\x75\xb4\xf2\xed\xb1\xbb\x84\xe5\xeb\xb9\x25\x9e\x09\xf9\x62\x5c\xe3"}, -{{0x00,0xdb,0x37,0xad,0x2a,0x19,0x5f,0x08,0xa0,0x84,0x40,0xd0,0x59,0x25,0x9e,0x53,0x9f,0xeb,0x40,0xb4,0x74,0x92,0x82,0x55,0xe7,0xc9,0x4e,0xbc,0x3b,0x05,0x03,0x8c,},{0x04,0xf8,0x8b,0xf6,0x39,0xe0,0xf7,0x1a,0x57,0xd0,0xd0,0xaf,0xff,0x5f,0xe9,0x7d,0xde,0x38,0x09,0xff,0x28,0xec,0x68,0xeb,0x6f,0xc4,0x23,0xf4,0xfa,0xff,0x43,0x90,},{0xf4,0xd1,0xc8,0x0f,0x5e,0x7b,0x91,0xc5,0xc7,0xa8,0x2a,0x68,0x2d,0x49,0xba,0x6f,0xb1,0x9d,0x40,0x0a,0x29,0x97,0x48,0xa0,0xc9,0x69,0xbb,0x99,0x81,0x69,0x98,0xbe,0x63,0x4e,0x84,0xda,0x78,0x58,0x1b,0x06,0xe3,0x47,0x0e,0xfe,0xc3,0x98,0x04,0xfe,0xd9,0x3d,0x29,0x73,0x9f,0x04,0x39,0xa8,0x09,0x5a,0xc4,0x0d,0x9d,0x38,0x5e,0x04,},"\x5a\x94\xf7\x29\xd3\x0d\xd8\xaa\xe2\xa5\xc8\xc2\x85\x47\xbf\x45\x06\x29\x5d\xc6\x1b\xfe\xad\x97\x27\x74\x60\x82\xd4\x3b\x0f\x81\x14\xc8\xc1\x8c\x5e\xda\xf2\xfe\xc7\xca\xe8\x19\x35\x63\x38\xf0\xbf\x11\x5a\x17\xb0\x38\xac\xfd\x7c\x96\xba\x62\x62\xca\xbd\x57\x10\xfc\x0e\xfb\x43\xd1\x3d\xf4\x06\x5b\xec\xbf\x1b\x9e\x27\x9c\x03\xec\x9b\xbf\xed\x54\xd9\xa1\x3f\xe0\x6a\x55\xa3\xbd\x05\xc8\x07\x85\x8b\x41\xe1\x8d\xbd\xe1\x3b\x09\x07\xd4\x03\x41\x32\x26\x2d\x9c\x2f\x4d\x2d\x37\x6e\x16\x09\xad\x28\x0d\xe2\x0b\xa7\x09\x84\x4d\xbd\x12\x95\x02\x57\xf1\xb0\x7e\xf8\xcc\x33\x37\xc0\x1a\x70\x26\x93\xfb\x4d\x92\xd0\x47\xe6\x98\xc3\xa6\xdd\x46\xc4\xa9\x2a\x10\xd4\xc7\x80\xe5\x2e\x50\x25\xe0\x9d\x56\x53\x5d\x7e\xeb\x9f\xe7\xf0\x33\xe6\xe9\x26\x0a\x68\xf9\xd5\x4b\x6f\x37\xcc\x06\x96\x56\xe3\xbc\xee\x06\x92\x2b\x34\x96\x81\xa8\xe7\x75\x1c\xde\xcb\xe1\xec\xb6\x63\xfb\xc6\xf7\xc8\x61\xf8\x53\xdc\x31\x0f\x33\xde\xfa\x98\xee\x34\x3a\x68\x63\x2e\xc2\x2c\xaf\xec\xb7\xf3\x21\x2f\x81\xe7\x0b\x71\x84\x3b\x9f\xe8\xc8\x6a\x68\xb5\xc8\x6f\x03\x22\xd3\x48\xa7\x6d\xa7\xf1\xba\x0c\xa3\xcd\x7b\x6f\xd1\x5f\xf8\x92\x92\xb3\xf6\x36\xcd\x08\xcf\x62\x5c\x74\xd5\x10\x2c\xab\xb5\x71\xa3\xdb\xa8\x6a\x1c\x92\xf4\x1c\x72\x03\xb4\x49\x42\xf5\xa2\x46\x25\xac\x37\xd7\x7e\x49\xa5\x7f\x11\x82\x38\x69\x9d\x80\x7c\x25\x0d\x5b\xf4\x6f\x7a\x3c\xec\x57\x79\xa6\xe5\xae\x1a\x6c\xa1\x60\xcf\xf3\x7f\xb3\xb7\x83\x88\xfe\x9c\x03\x0c\x40\xe7\x15\x46\x01\x08\x1a\x51\x7f\xc0\xaa\x18\x02\xcd\x3b\x84\x5b\x94\x6e\xfe\x94\xaa\x8b\x9e\x03\xf6\x8a\x80\xde\xd0\xdf\xbf\xad\x4d\xae\xe4\x0f\xa8\x38\xc1\x33\x84\x1a\xe8\xa3\xce\x0d\x79\xfa\x8a\x2b\x94\x34\xba\xc5\xe1\xda\x6e\x0c\x71\x93\xe8\xde\xa4\x35\xa0\x3a\x85\xf7\x61\x84\xf7\xeb\xe2\xaa\x74\x9b\xe9\x41\x31\x04\xa1\x78\x68\x9b\xa6\xd2\x7e\x94\xfc\xcf\x61\xeb\x3a\xba\x0e\x6a\x5a\x63\xaf\x0c\xa8\xf0\x5a\x35\xcb\x63\x70\x51\x94\xe4\x4d\x92\x93\xde\x39\x29\xb0\xd9\x2b\xe6\xf8\xe6\x27\xc3\x50\xa8\x3f\xc9\x00\x0a\xa9\x5b\x93\x82\x0b\xe9\x79\x5c\x80\xb5\x66\x2c\xd7\xb3\x48\x22\x32\x80\x61\x35\x6d\xc5\x80\x57\x8d\x1a\x35\xb1\x01\x40\xdc\xd2\x48\xe4\x85\x31\x04\xd2\xc5\xb2\xc1\x3f\xf6\x83\xdd\x5c\x30\x79\x4b\xe4\xa7\x68\x58\xaf\x1c\x0d\x9a\xf3\x47\xce\x1d\xcd\x97\x2e\xe4\x9a\xac\x12\xbb\xcd\x89\x9c\x93\x29\x87\x1d\x3e\x7a\x06\x83\xd1\x75\x77\x9a\xfe\x35\xf2\x6a\x2d\x24\x8f\xd7\x80\xea\x85\x1d\xc4\xba\x6d\x21\xf8\xa1\x71\xaa\x6c\xb8\x69\x7d\x9d\x11\x21\x61\x54\x03\x07\xcd\x54\xf9\x31\x77\x5d\x70\xb3\x3d\x3b\x6d\xe1\x09\x1f\xc1\x75\x05\x31\xc0\x8f\xa7\x0f\x7b\xe3\x8a\xa1\x10\xd6\x74\x6b\xb5\x65\xdb\x7b\x47\x0f\x90\x08\x50\xfb\xbf\x1c\x66\x2f\xd6\x13\xe4\xf3\xa5\x68\x95\x49\xe3\x10\x7e\x9b\x0f\x17\xde\xf7\xa5\xbd\x7f\xd7\x59\x6c\x4d\x04\xc7\xf4\x8c\x77\x9f\xc3\x5e\x09\x33\x5e\x1d\xf7\x84\x08\x4e\x55\xd8\x55\x1d\x1f\xf4\x9d\xe5\xb3\x11\xcd\x35\x0f\x34\x7a\x0b\xd2\x86\x3a\x2a\x30\xe6\xea\x18\x3a\xd2\xe3\xee\xde\xbc\x18\xdd\x28\xc6\xa5\x96\xe6\x93\xdc\x33\x89\xf7\xd9\x0b\x71\x3e\x3a\x85\xa6\x25\x16\x30\x5a\x70\x66\x7f\xc1\xfb\x3c\xb1\x0e\x8a\x95\x57\x50\x27\x39\x43\xc5\x68\xe1\x07\x69\xce\xf7\x81\x99\xdf\x44\x50\xdb\xc4\x90\xfe\xf1\xb3\x04\xb0\x52\x22\x1b\x2d\xb9\xc4\x4f\xe0\x03\x45"}, -{{0x6c,0xa1,0xa1,0x48,0x2a,0x07,0xf2,0xa6,0xc5,0x7f,0x04,0x11,0x97,0xb3,0x4a,0x51,0x19,0xe6,0x89,0x03,0xcf,0x6d,0xfb,0x51,0x71,0x1d,0x95,0x50,0x97,0x31,0x63,0xc0,},{0x80,0x34,0xa5,0x5e,0x3b,0x6e,0xd7,0x99,0xf4,0x9e,0x2e,0x70,0x3a,0x81,0xf4,0xac,0x02,0x57,0x3c,0x44,0x5d,0x76,0x5e,0x30,0x69,0xbe,0x42,0xf0,0x9c,0xbd,0x18,0xad,},{0xdd,0x9b,0xdb,0xad,0xd9,0xfd,0xc8,0x1c,0xe2,0x30,0x28,0x8c,0x4a,0x06,0x8d,0xf0,0x7e,0x18,0xb4,0xc7,0xcc,0x51,0xc0,0xca,0x48,0x11,0xdf,0xbd,0x04,0x76,0x5c,0x56,0xbc,0x88,0x32,0x40,0xe4,0x6e,0x3a,0x42,0xc0,0x1d,0x8d,0x24,0x24,0xfb,0xc3,0x32,0xb7,0xc5,0xa1,0x7b,0xce,0xb1,0xf6,0xe8,0xda,0xd0,0xbf,0xe5,0x62,0xca,0xd3,0x02,},"\x08\xfd\x84\x87\x50\x3c\x3f\x32\x96\xb6\xf1\xb6\x4d\x6e\x85\x90\x6f\xd5\x98\x6c\xf9\xc5\xd9\xfa\x8a\x59\xd9\x2f\x44\xe6\x47\x0a\xf3\x4b\xcd\xef\x33\x6f\xfd\xc8\x64\x56\xec\x7a\x7b\x57\x61\xf1\xad\xea\x02\x73\x26\x63\x0e\x68\xab\xc6\xb8\xcd\x5d\xdf\x40\xb6\x41\xa2\x59\xad\x02\x43\x21\xbf\x3e\xf9\x8e\x76\x32\x79\x71\x49\xc4\x92\xd5\x35\x94\x75\x2c\x55\x0d\xfb\xc4\xfa\x6b\xf4\x71\x76\xf4\x23\xa2\x70\x56\x93\x94\x7a\xa9\x0d\x68\xdd\xc8\xef\xb6\xcb\x9d\xbe\xca\xfd\x28\x30\xd0\x4f\xd9\x3b\x1e\x9e\x7c\x12\xb9\x3e\x0d\x0f\x3e\x26\x34\x90\x0f\x25\x86\x0d\xda\xdb\xae\xce\x17\x80\xff\x2d\x3f\x3d\x9f\xb8\x38\xfd\x0d\x5d\x66\xf8\xaf\xb3\x05\xff\x1a\x1a\xed\xca\x2b\x97\x4b\x63\xe4\x3f\x5b\x3c\xc9\xdf\xed\x1b\xcf\x11\x99\x91\x76\xed\x95\x85\xac\x82\x9b\xc6\x79\x4e\xf3\xac\xd8\x72\xe8\xd2\xe9\x26\x08\xb3\x20\xf8\x94\x99\x6a\x56\x2e\x1e\xb1\x77\xe2\x1b\xe5\x7c\x22\xc4\x1e\xc2\x59\xa3\xdf\xf9\xc7\xc9\x49\x1d\xb8\x38\xd7\x6c\xf9\xb0\x38\x31\x11\x59\x8e\x35\x7f\x44\xba\xbe\xbf\x12\x1b\xdb\x24\xee\x9d\x55\x7b\x7d\x5a\xf4\x91\xa0\xa0\x36\x5c\x90\x36\x1f\xe4\xf7\xe3\xd1\x3a\x17\xda\x3a\x39\xfd\x43\xf6\x90\xdf\xb0\xb2\xd8\x60\xca\xb4\x19\xf7\x75\xab\x71\x52\xcd\xc8\xf2\xaf\xdc\x50\xe8\xd5\xda\x5d\xa0\x17\x06\xee\xa2\xa2\xff\xad\x4b\xab\xee\x8b\x03\xda\x33\x6a\x4d\x84\x3d\x9d\x7e\x0a\x93\xf3\x6a\x92\xe6\x61\x0a\x36\x8b\x63\x13\x3f\x05\xa3\xfd\xc5\x5e\x3e\x1a\x44\x0b\x0f\x87\xa5\x33\x64\xc1\xd3\x72\x42\xc5\x7a\x10\x9e\x6d\xf6\x93\x45\xb0\x1c\x21\xc1\x08\x9e\x79\x0a\x66\xf4\xf3\x38\x0d\x3b\x76\xff\xb4\x20\xdf\xe1\xe6\x20\x0e\xac\xe5\x79\x26\x5a\x42\x7f\xbd\x35\x55\x14\xef\x95\x3e\x1a\x6e\x96\x8e\x37\x02\x1b\x3c\x6a\x29\x0d\xcd\x02\x93\xda\x67\x68\xda\xd7\xc6\x63\x11\x63\x30\x51\xc0\xac\xcb\x0b\x91\x65\x46\x4d\xfd\xdf\xde\xd2\x3b\xd1\x3e\xf9\x08\x74\x4f\x9c\x21\x11\xdc\x15\x31\x42\xd2\xf1\x05\x34\xd8\x93\xfe\x0b\x54\x5f\xec\x53\xfd\xb3\xb3\x5b\x51\x83\x98\xb0\x2a\xb2\x17\x91\xfa\x97\x7e\x30\xcf\x4b\x40\x4e\x7a\x29\x9d\x37\x87\x10\x8b\x83\x6a\xa0\xd5\x9c\x11\x4f\x1f\x36\x71\x9a\x7a\xcf\x85\xac\x99\x4d\x9c\xb7\x23\x06\xf2\x58\xf7\x8a\xc0\xa3\xb6\xc0\x53\x43\xe0\xb7\xa9\xaa\x72\x6e\x52\x26\x7e\xdf\x97\xf4\x97\x2f\x76\x64\xf4\x37\x20\xad\x33\xce\x6e\x61\x54\x40\xe3\x65\x37\xcb\xc5\x69\xbd\x6f\xf9\x4f\xfd\xae\xa5\x1e\x06\x02\x9d\xae\x78\xc5\xb9\x15\xc5\x37\xca\xea\x6f\x15\x04\x14\x79\x79\xb8\xaa\xae\x0b\xcd\x96\x18\x43\x7e\xbe\xd0\xb5\x5e\xfa\xec\x32\x0e\x84\xc7\x59\x59\xa3\x7a\x26\x0a\x02\xd4\xef\x1b\xb6\x26\x41\x52\x0f\x1a\x03\xdd\xea\x8c\x4c\x1d\xe8\xd7\xfa\xc5\x8d\xa4\x08\xb0\xab\x47\x57\xa1\x35\xf1\xd0\x75\xc9\xf7\xc9\x9f\xb9\x9d\xb9\x42\x7c\xe9\xb0\xd6\x26\xcb\x1a\xc1\x89\xad\x86\x63\xd7\xa7\x14\xfb\x5c\xd1\x58\x5c\x3b\xf9\x9a\x0a\xa4\x6d\x76\x39\x78\xd0\xb1\x2d\x65\xc4\x38\xbb\xb7\x3f\xea\xa5\x1b\xa2\x6a\x45\x9e\x7b\xea\x25\x43\x94\x66\xc0\x86\x13\xe4\x25\x40\xc8\xc6\xd5\x43\x67\xf2\x21\xfc\xce\x0c\x5e\xb6\xaf\x2f\xaa\x18\x1e\xa2\x15\x21\x80\x9b\xe7\x56\x49\xcf\x8d\xee\x76\x71\xdb\x7f\x94\x8f\x34\x6c\xbd\x03\x02\xbf\x9a\x06\xea\xbc\x72\xe2\xe5\x12\xb3\xdf\x88\x5f\x6d\xaa\x39\x8f\x93\xe3\x6d\xae\x2d\x6a\x04\x47\x81\x21\xf9\x77\x87\xd4\xce\xdf\xf6\xdb\x09\xaa\xf1\x0f\x27\xb1"}, -{{0x27,0x84,0xdf,0x91,0xfe,0xa1,0xb2,0xd2,0x1d,0x71,0x3d,0xe2,0xed,0xc6,0x65,0x24,0x51,0xa0,0xc1,0x59,0x54,0xb8,0x65,0x60,0x62,0xea,0x1d,0xed,0xc2,0x44,0x5b,0x2a,},{0x95,0x56,0xdb,0x53,0x70,0xf8,0xfb,0x3c,0x74,0x78,0xde,0x03,0xd2,0x3d,0xf1,0xcd,0xa9,0x6f,0x27,0x40,0x11,0x8e,0xfd,0xd3,0xd1,0xa9,0xfa,0x4c,0x3b,0xfe,0x88,0x49,},{0x17,0xd1,0x71,0xd9,0x46,0xde,0x35,0x16,0x15,0x84,0x07,0xe1,0x32,0xcc,0x1a,0xce,0xca,0xef,0xd6,0xd0,0x92,0x11,0x2b,0xe6,0x53,0x99,0x95,0x23,0xe2,0x0b,0xd4,0x95,0xf7,0xb7,0xf6,0x00,0xe8,0xd5,0xa6,0x71,0x33,0x0d,0x32,0x69,0x3d,0x60,0x19,0xc0,0x8d,0x2d,0x00,0x3b,0x17,0x6e,0x63,0x19,0xc3,0x53,0x94,0x20,0x0e,0x02,0x7d,0x0e,},"\x2e\x3b\xc5\x4d\xf4\x16\x74\x1d\xbe\x79\x16\xad\x25\xf0\x4e\x48\xd5\xa9\xd7\x7a\x62\x3e\x57\xf9\xcd\x61\xec\xb4\x4f\x09\xf7\x68\x33\xeb\x2a\x3e\x9a\xb7\xaa\x89\xff\x5d\x2d\x56\x0c\x07\x17\x7d\x85\x4d\x7c\x49\xcb\xef\x49\x2b\x7f\x4f\x7e\x56\x7d\xe1\x27\x51\x24\xe1\x6c\xa4\xa7\x98\x01\x62\xfa\x0f\xd1\x62\xa8\xe5\xfd\x6f\x35\x61\x70\x07\x03\x4b\xce\xec\x57\xc8\xfa\xf7\x66\x4f\x4b\x3b\xaf\xfd\xea\x8d\x8f\xc2\xba\x22\xd5\x85\xe9\xe2\xd7\x39\xf5\xff\xc9\x9b\x4e\x0d\xbe\x9c\x36\x86\x54\x7e\xa0\x48\x15\xa5\x9c\x4a\x25\xb5\xf2\x39\x06\x68\xe4\x18\xba\x0f\xcb\xdf\x4c\x4a\x51\xf3\x39\x05\xc7\x4f\xbb\x83\x0a\x19\xf9\xbc\x86\x36\xdb\xaa\xff\x20\x99\x95\x44\x79\x96\xd2\xe5\xb1\xc3\x77\xb4\xcb\x87\xa4\xe1\xef\xe1\x2d\xe3\x4d\x33\x59\x9f\xf3\x97\xb7\x40\x17\xd7\x11\xed\xd3\xe7\x72\x15\x5b\xe5\xa4\x40\x6e\x74\xcb\xe2\x93\x1e\xf5\x13\x59\xaf\xd5\x1b\x5b\x1a\x7b\x3e\xa2\x2e\xe8\xed\xa8\x14\x76\xbc\xc1\x7e\xa7\x68\x0f\x6f\x31\x04\x70\x3b\x9f\x2a\x35\xcf\x26\x27\xeb\x74\x1d\x1a\x30\xaa\x4b\xee\xf6\x57\x9e\xc7\xd0\xb0\x7a\x4e\xf3\x2a\xbc\xb4\xd7\x56\x97\x0f\x70\xa3\x67\x8e\x17\xe6\xe5\x73\x18\x90\xae\xbc\x8c\x92\xb9\x56\xd4\xb3\xb5\xfe\x2a\xdf\xd7\x9b\x21\x1a\x18\x83\xdf\xc8\xc9\xa4\xb1\xb9\xc8\xc1\xbb\x26\x5e\x1f\x3d\xd3\x92\x44\x5e\xa5\x9b\x59\x0a\x01\x95\x51\xf8\x12\x18\x49\xf4\x35\xb3\xac\x1b\x29\x90\x2f\xc8\x39\x25\x54\x05\x6b\x93\x90\x3d\x5f\x26\x3b\x3d\x54\x08\x43\xd6\xaf\xa7\x5a\x2a\xd8\x30\x4b\x76\x90\xde\x99\xa7\x34\xc3\xd1\x30\xb6\x95\x47\xb1\x8b\x09\xe9\x8c\xbf\x25\x27\x30\xe4\xae\xdb\x6d\xc4\xb5\x8b\x22\x43\xfe\x55\xe8\x09\x39\xd3\x7b\x0a\x59\xd7\x22\x26\xd8\xa2\xcc\x51\x53\x09\x5e\x15\x99\x4a\xd6\x21\x95\xaa\x31\x0f\x2a\x64\x26\x67\x6b\x66\x1e\x47\xb9\xfc\xff\xfa\x04\xd6\xdc\x62\x5f\x29\xf4\x4c\x7c\xf6\x20\xb3\x78\xa6\x5d\x23\x83\x44\xb3\x80\x44\x8c\xd1\x19\xcc\x7f\x37\x3f\x62\xcd\xfa\xd6\x41\x49\x90\x63\x53\xf3\xa5\x41\x07\xc5\xdb\xa6\x5e\x3c\xc4\x94\xb0\x53\x1f\x4d\x64\x74\x93\x63\xf2\x30\x73\x8b\x2c\xfe\xed\x98\x35\x20\x22\x7d\xd5\xbc\x43\xbe\x59\xb3\x26\x8e\x28\x32\x16\xf6\xe9\xc7\x5e\x0c\x1c\x71\x27\x2e\x54\xfd\xb2\x9c\x78\x58\xd2\x87\xd1\xef\xa1\x91\x7b\xe3\x7c\x8e\xea\xb5\xe4\x4c\x3a\xd7\xb3\x6e\x8a\xc9\xf6\x69\x91\xeb\x82\xa5\x14\x8e\x59\x72\x03\x4a\xd0\x1c\x62\x61\x5a\x45\x15\x45\x79\xfa\x50\x86\x9e\x7b\xe9\x87\x6b\x56\x56\xea\xad\x2e\x43\x02\x5a\x62\xdd\x13\x4b\x61\x2d\x8f\x4d\x5e\xbc\xf8\x05\x6e\x19\x8b\x71\x34\x38\xe8\xe0\xe3\x47\xca\xfb\xfc\xb8\x9e\x39\x4a\xa3\x30\xd4\xc7\x88\xd4\x9c\x65\x8f\xcf\xc8\x0b\x3e\x00\x78\xf0\xe8\xe1\x9a\xa9\xb8\xfe\x8e\xb0\xba\xb9\x3d\xe7\x85\xd0\x43\xe0\xf4\x75\xae\xb6\x0d\x62\xe3\x8f\xb1\xf8\x38\x4a\x00\xb7\xa9\x02\xda\xee\x13\xd2\x13\x62\x69\xe5\x08\x01\xb8\x0a\x65\xb2\xf9\x13\xcf\xe3\xff\xb3\x65\xd9\xaa\x2f\xd1\x93\x72\xa0\xb0\x22\x56\x95\x44\x4e\x4b\xc5\x48\x71\xd1\x08\xe0\x9c\x7e\x1c\x2b\x42\xdc\xbb\xac\xce\x24\xea\x5b\xd5\xbf\x1f\xcf\x4a\xc6\x97\xa3\xfe\x09\xa5\x46\x77\xb7\xa8\xdc\x8d\x5e\xec\xb8\x6c\xc7\x92\xee\x9b\x6f\xea\x2d\xe1\x6a\x47\x32\x69\xfd\xc6\x5d\xbb\x73\xc2\x58\xc8\x21\x44\x04\x07\xc6\x42\xf7\xd3\xd3\xf5\xc7\x08\xd5\x53\x32\xda\x83\x43\x10\x6c\x19\xb2\x30\xa5\x14\x27\xf3\xb7\x71\x91\x6a\xe3\x68\x8b"}, -{{0x4b,0xb7,0x92,0x36,0xfa,0xda,0x31,0x44,0xb6,0x82,0x96,0x49,0x9b,0xa4,0x4a,0xe5,0x34,0x07,0x4c,0xa9,0x4d,0x4b,0x58,0x1e,0x5e,0xdc,0xff,0xfe,0x13,0xb3,0xad,0x19,},{0x0a,0x83,0x99,0xf1,0xe5,0xa4,0x23,0xdc,0xf7,0xb2,0x5b,0x2f,0xb0,0xac,0x9e,0x1e,0x95,0x48,0x14,0x8b,0xea,0x84,0xd0,0x21,0xe0,0x42,0x87,0x60,0xe0,0x5d,0x58,0xbf,},{0x69,0x8f,0xab,0x68,0x51,0x0d,0xb8,0x12,0x1a,0x46,0x5d,0xb7,0x7e,0x4f,0x8b,0x58,0x6a,0xee,0x89,0x58,0x16,0xe6,0x3b,0xbf,0x0b,0xeb,0x24,0x2d,0xb4,0xe8,0x4c,0x15,0x7f,0x4b,0xe2,0x01,0xae,0x65,0x64,0x51,0x7a,0x87,0x0d,0x17,0xf6,0x0c,0x85,0x83,0x70,0xc0,0x1c,0xca,0x17,0x18,0x9c,0xb4,0x18,0x9e,0x81,0x43,0x91,0xd1,0x50,0x0d,},"\xad\x81\xab\xf6\x93\x7a\x7a\xcd\x7f\x18\x37\xf0\x4d\x3f\x10\xe7\x08\xc6\x1a\x5f\xbe\xde\xee\x4d\xb7\x6e\x15\x98\x57\x03\x84\xe6\xef\xec\xe9\x7c\x92\x5d\x2e\x5c\x34\x88\xca\xb1\x0b\x5b\x52\xb8\xa5\x48\x6e\x99\xd8\xff\xe8\x6c\x19\x81\xa1\xf1\xd5\x32\xdc\xd4\xd4\x89\xe5\x54\x6d\x86\x65\x32\x98\xe7\xa5\xf9\x6e\x81\x44\x55\x2d\xda\x8a\x18\xe7\x5b\x5f\x73\x55\xb1\x35\x41\x62\x11\x06\xe4\x97\xe5\x1a\x56\xd8\x65\x9d\x19\x8f\xe1\x00\x37\xe2\x21\x28\xaf\xc2\x71\x4a\x2c\xb5\xa1\x2c\xc5\xdb\x09\x68\xa3\x43\xef\x91\x8e\x87\x69\xdd\x6a\x3e\x5b\x9e\x32\xaa\xb6\x6c\xb0\x23\x9e\xbe\x4c\x17\xf1\x82\x18\xe2\x52\xeb\xa6\x16\x2e\x97\x70\x49\xeb\xac\x0b\x38\x04\x8b\x3a\xaf\xb7\xd4\xd7\x22\x63\xe9\x21\x28\x99\xa3\xbf\xe0\xa6\x9c\x99\xe2\x2a\xc6\x1c\x5e\x96\x12\x45\x63\x03\xd9\x24\x58\xb5\xc5\x02\x91\x6c\x34\xa8\xee\x5c\xd9\xa5\x82\xa5\x25\x76\xb6\xdc\x9d\x7d\x4c\x64\x2f\x21\x29\x98\xbf\x33\x58\xd4\xa8\xc2\xea\x67\x68\x6e\x55\xd4\x89\xf6\xa7\x6e\x6b\x07\x0e\x6e\x99\x5a\x74\x53\x26\xc9\xaa\x63\x63\x0a\x00\x33\xad\x30\x72\x1a\xa6\x5f\xac\x60\x4a\x6e\x58\xc7\x50\x72\x1a\x56\xca\x67\x60\xc9\x41\x34\xd6\x11\xfa\xb4\xd3\x54\xe4\xf6\x6a\x29\x67\x7b\x1a\x66\x66\x01\xe9\xda\x79\xf2\x13\xf5\x82\x03\x74\x33\xc0\x7f\x94\xd5\xf0\xde\x6a\xa9\xfa\xa0\xb3\x2f\x7b\x02\x3f\xb9\xfc\x13\x5a\x26\xf9\x70\x52\xac\x80\xb3\x9b\x30\x6a\xed\x13\x92\x6c\x28\x54\x19\xa2\x9b\x20\xe2\x37\x0d\x8a\x09\x5b\x32\x25\x8f\xa9\x89\x34\x89\xee\x21\x08\x9c\x75\x2e\xc0\x62\xe1\x20\x35\x9e\x2f\x35\x15\x12\x82\x54\xc8\x09\x8c\xca\x65\xa9\x1a\x02\x2d\xd0\x57\xa2\xc2\xa1\xb6\xb8\x5d\x13\x7c\x3c\x96\x7d\xcb\x70\xaa\x17\xa2\xff\x4b\x37\x67\x8b\x38\x29\x02\xf0\xf9\x31\xee\x74\x3f\xc3\x98\xac\x1b\x8c\x10\x46\x98\x67\x30\x84\x79\xe4\x0d\x7f\x2f\x04\xa4\xb0\x4c\x44\x89\x15\x84\x88\xdd\xb7\xbe\xc5\xa4\x7f\x20\xff\x35\x6d\x99\xa1\xb3\xe9\xd0\xb7\xfe\x9b\x0a\xd9\x49\xf2\x98\x96\x0e\xfa\x4d\x97\x28\xf8\x10\x1c\xf5\x3d\xa3\xbf\xfd\xd9\x52\x4b\xf4\x40\xa5\x8b\x32\x73\x8d\x0b\x62\x93\xe8\x53\xf4\x66\xff\xd4\x2c\x56\x07\xac\x9e\x35\x3b\xa0\x3e\xfb\x57\x8c\xc9\x96\x3d\x8a\xaa\x9d\x2e\x26\x6d\x1d\x2a\xe9\x29\x6f\x30\xc9\xef\x44\xec\x69\x10\x30\xd5\x96\xa4\x01\xb6\xce\xe7\x2a\x54\x0e\xf3\xc4\x2e\xc0\x17\x42\x66\xba\x54\x01\xf3\x54\xad\xc8\xe2\x54\x04\x43\x7e\x88\x8b\x08\x28\x69\x39\xbe\xde\x30\x8a\xcd\x30\x32\x7e\xbf\xf0\x62\x70\x09\x7c\xc2\x94\xf0\xa0\xf3\x9f\x9a\xa3\xc6\x65\x85\xca\x47\xe6\x0c\x4b\x8e\xa3\x60\x89\xeb\x8a\x90\x88\xbb\x18\xb0\x34\x31\x35\xbb\x6a\x45\x6d\x2f\x6a\x3b\xf3\x90\x72\x3e\x78\xb4\x2c\x03\x7c\x2d\xe2\xe1\x43\x2c\xaa\xd3\xa5\x94\x02\x12\x94\xd4\x3f\x5b\x15\xa2\xe8\x19\xdc\x74\x8e\x45\x1d\xe4\x00\x68\xc8\xf0\x32\xf1\x3b\x47\x11\x37\x70\x12\xed\xcd\x4f\x11\xde\xc1\x11\x1b\x12\xeb\x6e\x1b\x00\x63\x38\x18\x70\x6d\x71\x32\xd9\x91\xce\x20\xdf\x3b\x92\x1d\xb2\x18\x5e\xe2\x5b\xb6\xf5\x82\x75\x76\xec\x01\xad\x89\x0f\x79\x79\x3b\xaa\x35\x8c\x2b\xbf\xb6\xfa\xad\x11\xd8\xcb\x0d\x0d\x2d\x2b\x29\x81\xfb\xf4\xe3\x72\x34\x9f\xc6\xa0\x1c\x36\x07\x7b\x59\x32\x5f\x70\x2b\x38\x00\x59\xa6\x5c\xf2\xf5\xea\x98\xd6\xbd\xc8\x15\x20\x53\xb8\x5b\x28\xc8\x1e\x41\x3c\x4c\xac\x7e\x22\x6c\x13\xdb\x32\x67\xd2\x18\x30\xf0\xe5\x43\x11\x02\x91\x70\x05"}, -{{0xaf,0xd7,0x65,0xe6,0xaa,0xc0,0x14,0x6d,0x48,0x11,0xef,0x95,0x97,0xbc,0x3f,0x44,0x76,0x3f,0x03,0x37,0x8b,0x7b,0xe0,0x33,0xd6,0xe6,0x4c,0xa2,0x9d,0xec,0xae,0xf9,},{0x6b,0xb7,0x61,0x23,0xd9,0x25,0x89,0x22,0x68,0x6c,0x53,0xfb,0x69,0x17,0xb9,0xa4,0x59,0xca,0xbd,0x30,0xbe,0x8c,0x43,0x97,0x0d,0x80,0xf5,0x35,0x0c,0x2d,0x98,0xef,},{0x3d,0xc9,0x19,0x4d,0x50,0x81,0x14,0x19,0x04,0x9e,0xaa,0x07,0xb6,0x55,0xb7,0xd4,0x06,0x4b,0xcb,0x0e,0x7f,0xb5,0xf9,0xe5,0x32,0x6b,0x5f,0xc8,0x56,0xfc,0x0a,0xb8,0x70,0x59,0x73,0xae,0x10,0x01,0xdf,0x55,0x37,0x39,0x77,0xdd,0xe2,0xd9,0xb8,0x10,0x79,0x55,0x14,0x14,0xad,0xc7,0x1c,0xc8,0x52,0xd4,0x99,0xb0,0xcf,0x82,0x4f,0x07,},"\x18\x3b\x10\x92\xc7\x90\x4e\x47\xa1\x42\x03\x17\xa2\x5d\x0f\x59\x11\x0a\xa8\x4d\x6b\x34\x19\xad\x45\x68\x65\xc4\x3b\x29\xe9\xd1\xda\xcf\x75\x5d\x9e\x5c\xf9\x4c\x55\x91\xd5\xd9\x12\xd0\x5c\xa9\xa5\x2d\x01\x5d\x6e\x8f\x5d\xc9\x4e\xfd\xce\x0d\x7c\xf5\x65\x12\x03\xb1\x1e\x54\x27\xa9\xf6\x79\x42\x9e\x00\x41\x4a\x48\xea\xb1\x3f\xd8\xe5\x8b\x87\xeb\xa3\x9d\x10\x25\xd6\xa1\x8b\x2c\xdc\xbe\x14\x74\x36\xdb\xf3\x8a\x1c\xe8\x64\x13\xae\x31\x87\x65\xe1\xbb\x1d\xf7\xe2\xb3\xbe\x97\xe9\x04\x08\xb1\x17\x17\xcf\x45\x9b\xcd\x0f\x3c\xac\x58\xb4\xa0\xd3\x5b\xff\xb5\x33\xe2\x0d\xf3\x74\x51\xc1\x14\x01\xce\x1d\xab\x02\x05\x5c\x7e\x08\xc5\xec\x46\x39\x0c\xd6\x17\xa6\xb5\xf2\x2f\x65\x18\x30\xa1\x11\x2a\x06\xed\xe4\xc4\x0a\xb7\x95\x78\x51\xd6\xc6\x6f\x17\x1c\xd1\x62\x41\x59\x09\x00\xb8\x52\xa3\xd0\x19\x95\x7b\xe1\xb7\xbb\x7a\xcb\x89\x23\xf2\xa3\x57\xc3\x26\x44\x56\xcf\xca\x9b\x42\x9d\x71\xfe\xcb\x7e\xda\xe3\x9b\x25\x2b\x4e\xb6\x10\xe8\xc7\x18\x83\x56\x99\x75\x4b\x8d\x41\x24\xb4\x92\x48\x8e\xde\x62\x61\x0c\xce\x44\xb5\x92\x18\x66\x3b\x6c\x96\x46\xa1\x4a\x84\x17\xed\xdb\xb6\xf4\xfb\xe5\xa4\xbb\xbb\x48\x2b\x37\xa4\x45\xe3\xc1\x6b\x65\xa1\x41\xcd\x3e\x12\xa5\xb2\xc0\x48\x1d\x61\x4d\x6d\x20\x84\x79\xb9\xb2\x09\xb8\x28\x85\x4d\xae\x0e\xa1\xed\xed\x50\x65\x55\xfe\x18\xe1\x85\x40\x05\xcf\x00\x1a\x80\x77\x08\x34\x98\xd2\x7f\xad\xf1\x18\x28\x6b\x53\xb8\x97\x4d\x69\xfa\x28\x25\xbe\x8c\xa3\xd6\x03\x6a\x92\xca\x52\xf9\x1d\xde\x6d\x5b\x1f\xfe\x28\x88\xf4\xd6\x07\x79\xfa\xd1\xfb\x41\xd8\xc0\x71\x40\x49\xaf\x68\x1b\x75\x5f\x2d\x42\x04\xee\xcd\x09\xe0\x77\x21\x0a\x48\xa1\x95\xe7\x2c\x80\xe1\x27\xc3\xd4\x87\x50\x95\xc6\x57\x0a\x1f\x78\x09\x59\x07\x52\x8c\xf7\x74\x6f\x31\xd9\x71\x11\xc6\xf4\xcb\x25\xb3\x74\x12\x99\xa7\x57\x48\x22\xd4\x6b\x6e\x79\xed\x23\xc2\xfe\x05\x7b\x3a\xc7\x29\x0b\x46\x0b\x16\x6e\xe9\x0a\x45\x56\x2e\xff\xed\xcc\x6b\xa8\xf4\x79\x5f\x73\x95\x81\x8d\xb5\x6b\x6e\xdd\x59\xca\x2c\xc4\xae\xa1\x84\x1f\xd9\x56\x5b\xec\xd6\xc0\x81\x04\xcd\xee\x26\xba\x9d\xe2\x00\x77\x3d\x09\x1b\xc7\x7a\x57\xc5\x47\xf1\xa6\xba\x0a\x2c\xd7\x17\xab\x32\x56\x1d\x74\x22\xea\x72\x35\xad\xb0\xcb\x36\xbf\x5c\xbd\xf8\x8f\xca\xe0\x66\x30\xa1\x56\x47\xd9\xa3\x57\xb4\xe0\xe5\x02\xd2\x73\xf3\x79\x6a\x51\xe0\xbc\x3f\xed\xbf\x7a\x1e\x64\xaa\xd7\x22\xaa\xc5\xfd\x02\x2f\xa7\x9d\x60\xfc\x70\x73\x25\xf1\x27\xeb\x1f\x03\x86\x87\x95\xcc\xdc\x0b\x4c\xb2\x6f\x20\x23\xd1\x52\x15\x3a\x97\xa2\x60\xbf\xf1\x17\x45\xd2\xe2\xcc\x0b\xf8\x60\xd4\xa6\xe3\x58\xa6\xd8\x17\x6d\x2a\xc1\x78\xa9\xae\x1a\x2d\xc7\x5e\x8b\x49\x04\x08\xff\x7c\xdf\x99\x13\x29\xf3\x3c\xb0\xc0\x5e\x1e\x35\x69\x25\x08\x7e\x0b\x8d\x96\xa5\x23\x51\xd1\xd1\x77\x68\xeb\x13\x4c\xdb\x21\xa1\x54\x6a\xae\xdc\xc6\x87\xdf\xa1\xb2\x2e\x92\xfb\x52\x41\xa8\x36\x77\xa1\x53\x44\x5b\x77\xd5\xe7\x03\x50\x8e\x2a\xbc\x58\x8a\x9f\x42\xe5\xbc\x71\x06\x73\xe4\xdd\x8a\xd7\x03\xfa\xb2\xd7\xdb\x1e\xb8\x42\x26\xc8\x9d\x87\x62\xa7\x09\xe3\xe9\x13\x8a\x1f\xa7\x90\xf2\x92\x9b\xff\x61\xbc\x1e\xa6\xe8\xaa\x1a\xd0\xe3\x88\x7d\x70\xa5\x6d\x4e\x65\x47\xfc\x60\x6a\x50\xd3\xbe\x3b\xd6\xdb\x03\x66\x3e\x00\xca\x9e\x4f\x24\xfe\x8c\xbf\xd7\xd8\xc9\x73\x8d\x63\x67\x55\x4b\x7b\x60\x1f\x74\x19\x0b\x59\x70\xa3\x98"}, -{{0xeb,0x34,0x71,0x45,0xf3,0x39,0xed,0xd8,0x02,0x78,0x5b,0x6f,0xbe,0xcd,0x5c,0xb8,0x08,0x89,0xac,0x7c,0xe4,0xeb,0xad,0x2f,0x67,0x07,0x67,0x65,0xdb,0x93,0x9b,0xca,},{0x99,0x4a,0x45,0x6e,0xad,0xa0,0x30,0x20,0x92,0x1c,0x3d,0x10,0x9c,0x13,0x5e,0xb9,0x61,0xfc,0xd4,0xa0,0xa4,0x00,0xba,0xfd,0x32,0xca,0x06,0x1b,0xbc,0x86,0x25,0x43,},{0xfd,0xbd,0x15,0xe1,0xe6,0x46,0x9d,0xf7,0x20,0xd9,0x55,0x2c,0xb5,0xdd,0x17,0x7b,0xcb,0xd2,0x92,0xfc,0xda,0x83,0xcd,0x93,0xc8,0x8d,0x01,0x14,0x91,0x2d,0xc8,0x70,0x31,0x09,0xba,0xc0,0xd4,0x59,0xac,0xe9,0x95,0x7d,0xf2,0x29,0x3a,0xc1,0x6d,0x40,0xd5,0x14,0x89,0x35,0x56,0x85,0x32,0x99,0xb9,0x7b,0x4f,0xd4,0x13,0x7a,0x3d,0x00,},"\x5b\x8b\x31\xba\xf8\x84\x83\xf0\x95\xb5\xd0\x2e\x17\xd8\xb7\xb4\x6c\xf4\x64\x60\xe6\x4c\x6b\x02\xc5\x6d\x8d\xaf\xe3\x48\x23\x70\x6c\xb5\xc1\x5f\x33\x8a\xd9\xb5\x65\x86\xa9\x49\x71\x1a\xa7\x31\x2c\xc9\x34\x50\xd2\xfb\x9a\xf4\x61\x3f\xc3\x07\x93\xa6\x31\xa5\x5c\x14\xe5\x3c\x0c\xb1\x5f\x06\x11\x63\x99\x39\x8c\x8d\xd6\x18\x76\xc6\x29\x15\xf9\xf9\xe4\xcd\xf8\xf7\xd8\x9a\xde\x12\x9e\x6d\xde\x7d\x63\x67\x1a\x18\x63\xf5\xda\x8f\x42\xea\x64\xc0\x79\xec\xb9\xa2\xc1\xb1\xdd\x9a\xda\xe6\x0e\x96\xb9\xcb\xbc\x76\x24\x53\x2a\xa1\x79\x75\xeb\xa1\x7a\x7a\xf0\x2b\xfb\x21\x9a\xac\x02\xb3\xd4\x30\x6c\xd3\x89\x33\xa8\x50\x60\xcd\x62\xab\x51\x3a\x39\x65\xb0\x91\x50\xa4\x88\xc9\x2b\xf7\xca\xb0\x48\x2e\xee\x56\x46\x3f\x01\x39\x00\x9b\x9f\xbb\x3f\xf4\xec\xae\x21\x1f\x42\x8b\x5b\xfb\x88\x76\xf0\x04\x98\x3b\x90\xc4\x47\x84\x6c\xa4\xb7\x45\x66\xe9\x79\xbc\x30\xc9\x5e\x99\xfa\xab\x69\xa3\xeb\xbf\xe4\xda\x60\x34\xc8\x2d\x63\xe9\xc5\xcc\xaf\x84\x86\xaf\x3b\x5e\x0d\x38\x14\x22\x93\x8b\x0c\x22\xf5\x16\x95\x5b\xdc\x36\x94\x31\x73\xf5\x83\x27\x08\xa3\x3c\xf5\x2d\x88\x75\xd9\x7f\xde\x58\x5b\x49\x17\xe4\xad\xec\xdd\x1e\x79\x85\x67\x62\x03\x3a\xf2\x2f\x25\x4b\x50\xce\x9d\x0c\x70\x0e\x77\xa7\x31\x55\x4f\xa0\x11\x3a\x0c\x66\x66\x83\xf3\xfd\xb1\x9e\x3a\x42\x63\x02\x23\x0b\x63\xe3\x3a\x78\x5e\xf2\x4a\x92\x89\x45\x5b\x3b\x8f\xc6\x18\xff\xfe\xf4\x9c\x2c\x6e\x48\xfd\x4b\xb4\x22\xf5\x04\x14\x9d\xe2\xb4\xc0\x35\x5c\x36\x34\x08\xe6\x6d\xa8\x1c\xbb\x58\x15\x52\xa4\x11\xe3\x64\xfe\x3e\x4c\xa9\x6d\x70\x72\xab\x07\x2e\x75\x68\xc1\x3d\x35\xe4\x1c\x78\x25\xa1\x3a\x5c\x68\xfb\x9f\xb5\x98\x8b\xbb\xfb\x9a\x0b\x51\x16\x57\x64\x66\x0c\xdf\xa2\x41\x1f\x3d\x42\x16\x5d\xa1\x87\xc5\x8e\xde\xf0\x10\x5a\x6d\xb1\x77\x42\x05\x43\xe9\x58\xd5\xd5\xe8\xa3\x71\xf7\x98\x70\x51\xc4\xe1\x78\x6d\x01\x8e\xb3\xd7\x32\xc2\x10\xa8\x61\xac\xaf\x67\x1b\xe9\x5b\xb6\x3f\xbc\x88\xbf\x8b\xe7\xbe\x53\x90\x93\x9c\xd9\xfb\x2a\xcf\x39\x81\xdd\xa6\x1b\x78\x7a\x7b\xbd\x78\x46\x8e\x1d\x32\xca\x46\xaf\x8f\xb3\x2a\x18\x46\x3c\x18\x0f\x52\x4b\xe1\xda\x91\x0d\xa5\x50\x8d\x42\xa0\x05\x17\x41\x22\x7c\x9b\x62\xde\x6d\x19\xb3\x3c\x0b\xd4\x80\x67\xb0\x35\x85\x9a\xd9\xbd\xc2\xdd\xd9\x7b\xef\xca\x31\xe6\x5a\x88\x6c\xfc\x75\x3a\xfc\x4f\xf2\xa7\x21\x2a\x89\xd3\x7c\x04\x6c\xdf\x39\x99\xc0\x51\xff\x13\x96\xbd\x99\xcb\x54\x94\x56\x39\xeb\x64\x62\xdb\x9e\xce\x84\x07\x7b\x0b\x3d\x6b\x3d\xf3\x95\x2d\xd3\x67\x56\xc6\xda\xb2\xab\xc2\x5a\x51\xbf\x32\xc1\xe9\xcd\xd0\xa7\x28\xa7\x98\x5f\x7b\x7e\x0d\x9c\x1a\x6f\x66\xce\x12\x16\x37\x3d\x25\x2d\xaf\x59\x58\xf2\xe8\x97\x3f\xd2\x68\xfa\xd0\xef\xe2\x51\xce\x76\xfe\x47\xbd\x0a\x4d\x0c\x4f\x10\x17\x94\x9d\x4c\x2b\x16\x71\x72\x18\xe1\x49\x15\x4e\xd6\xfb\xe5\x6f\x86\xd8\x2e\x19\xef\x0a\x91\x63\x19\x12\xf2\xa8\xf3\xde\xbb\x00\x76\x6b\x61\x77\x80\x2f\x4b\x2e\x79\xf6\xe7\xbf\xa9\xc6\x2c\xfa\x2f\x75\xcd\xb6\x04\x92\x63\x0a\x85\xc9\xb4\x31\x77\xd2\xdd\x9b\xa8\xd0\x54\x8a\xbe\x24\x92\x3a\xe8\x44\x3e\xea\xdc\xd0\xf5\x8a\x7b\x82\xdf\xf5\x0d\x88\x40\x03\x88\x9c\xb5\x60\xf7\xac\x53\xe7\x10\xa7\x55\x75\x36\x24\x64\xb1\xaa\x43\xd2\xa9\xb2\x2f\x2b\xd2\x16\x2d\x30\x2f\xaa\x74\x52\x34\x4c\xe7\xad\xe9\x98\x36\x87\xb6\xc6\x8e\xca\x47\xdd\xdb\x28\x9b\x15"}, -{{0x32,0x08,0x83,0x7d,0x15,0x54,0xb6,0x51,0x1a,0xdd,0xa0,0x9c,0xba,0xe5,0x65,0xda,0x78,0x43,0x9a,0x47,0x2a,0x5d,0x1b,0x10,0x7c,0xe0,0xa9,0xb1,0xd7,0x75,0x7d,0xb7,},{0x9b,0x52,0x5e,0x35,0x36,0x8a,0x92,0x1e,0x3a,0x2e,0x9a,0x35,0xa4,0xde,0x9e,0xa4,0xc4,0x36,0xca,0xba,0x27,0x12,0x3e,0x5c,0x36,0x9e,0x2a,0x6c,0xf5,0xc9,0x0a,0xb6,},{0x70,0x9d,0x1c,0xa9,0xca,0x2f,0x74,0x2a,0xb9,0xdd,0x0b,0x04,0x93,0x35,0xf5,0x44,0xcf,0xfb,0x2f,0x1a,0x36,0x93,0xd5,0xf5,0x3f,0x8b,0xa0,0x83,0xb9,0xb0,0xd8,0x6e,0x52,0x08,0xfa,0x8e,0x1e,0x81,0x56,0xc9,0xcc,0x22,0x42,0x77,0x5a,0xbb,0x7e,0x15,0xaf,0x30,0x85,0x86,0x8e,0xf4,0x57,0x63,0x4e,0x99,0x26,0xc4,0x04,0xec,0xf3,0x0f,},"\x43\x6a\x3c\x31\x76\x3f\x93\xd4\xd5\x46\xc6\xd1\xec\xfb\x7a\xe4\x59\x16\xaf\x75\x4f\x83\x9d\xcf\xe9\x6d\x6b\x69\xc6\x12\x14\xd0\x16\xfc\x84\x2f\x56\x46\x2a\x3f\x07\xf6\x61\xb2\xe2\x50\x5a\xcf\xaf\x48\x2a\x0b\x0f\x4f\x55\x01\xee\xc4\xb2\xd2\xd7\xd4\x44\x54\x4d\xe0\x00\xb9\x90\xf4\x36\x3d\x3f\x98\x3f\x5d\x4e\x09\x30\x97\x52\xff\x57\x9c\x73\x20\xc9\x15\x95\x1c\xc3\xa1\xe3\x23\x8c\x1b\xa7\xa1\x91\x30\xea\xbf\x6a\x37\xf5\xf0\xbc\x56\xe2\x52\x42\xf7\x52\x06\x1f\x3c\x63\xac\xad\x99\x2a\x75\x01\xe9\x67\xde\xb9\x25\xb3\x0e\xd1\x05\x43\x1e\x58\x21\x02\xfa\x4f\x30\x8c\x2f\x06\x83\x61\x2b\x56\x68\x6d\x52\xda\xed\x69\x43\xa7\x21\x9f\x3b\xee\xa2\xe0\xa2\x92\x42\xe8\x6d\x55\x62\xff\xab\x83\xb5\x6b\x26\x33\x26\x66\x4e\x02\x9e\x96\x1e\x70\x17\xd8\xe8\x9f\x5e\x3e\x1d\x10\xf5\x93\x28\x54\x55\x0c\xe6\xe5\xcd\x76\x97\x1f\xd2\x35\xcf\x9c\x00\x27\xd0\xcf\xed\x33\x15\xc2\xcb\xf1\x85\x08\x62\x4d\x8a\xcf\x04\x7f\x9b\x96\x8f\x90\x7d\x9e\x6f\x4c\xfa\x5e\x45\xc8\x0a\x27\x2c\x2d\xbb\x62\xc5\xd4\x19\x45\x80\xdf\xab\xed\xd8\x2c\xb4\xd7\x64\x92\x34\x4b\xe9\x6c\xcf\x5d\xaa\xf6\x1e\x6b\x2b\x55\xef\xdb\x3f\x65\x21\x0a\x3d\x6e\x1f\x36\x98\x87\xca\x0e\xa0\xd5\x8c\x3d\x14\x6a\xe3\xcf\x9b\x00\x00\x76\x88\x41\x15\xfa\x51\xb5\xfd\x66\xbe\xc0\xcc\xbf\x0d\x29\x20\x19\x6a\x7d\x7a\x38\x44\x5f\xbe\xd2\x2d\xfc\x75\x64\xdc\x56\xf6\x0d\x6e\x29\xe5\x92\x48\x53\x74\xc6\xbd\x1e\x5b\x15\x93\x1b\x69\xca\x6e\xe6\xb3\xaa\x25\x25\xc2\x35\x85\xf0\x92\x9f\x31\xcb\xd1\x1f\xb1\xa5\x33\x02\x16\xb9\x0a\xe5\xa6\x56\xdf\x7a\x07\x4c\xec\x64\xe5\x98\x18\x4f\x50\x3f\xb2\x3c\xc0\x5e\x65\xda\x9a\xe7\xe8\x44\x1f\x40\xe2\xdc\x26\xb8\xb5\x6d\x2c\xb5\x23\xa7\xc6\x35\xdc\x08\x47\xd1\xcd\x49\x8a\xbf\x75\x6f\x5a\x13\xea\x14\xf8\xfa\xb2\xc4\x10\xb1\xa4\x70\xf4\x9a\xa8\xdc\xa4\xac\x02\x56\xb1\x18\x00\xde\x0d\xd0\xec\x42\xb1\x42\xc5\x61\x12\x8d\x35\x7e\x78\x3b\x12\xf6\x1c\x66\x8f\x5e\x6e\x06\xb7\xb4\x8b\x7b\x22\x54\xde\x5b\xdc\x18\x04\xb7\x23\xd5\xfd\x6a\x0f\x4b\xc7\xc5\x9e\x7c\x50\x54\x18\x26\x13\xbb\xd2\xfa\x92\xb4\xc1\xda\x16\xbc\x8c\x97\xe1\x6b\xcb\x0d\xbf\x8c\x92\xb7\x48\x99\xb3\x7f\x31\x87\x57\x14\x0b\x6c\x4f\xd5\x35\xe2\xe1\xe0\x57\x0a\x50\x81\x8c\xf7\x8f\xb9\x88\xe1\xf4\xce\x40\xe7\x6e\x8f\xe3\xd6\x97\xd7\xa4\x58\x50\xf2\x93\xce\x17\x0f\xd8\xab\x07\xcf\x15\x34\xea\x5f\xfa\xd3\x4f\x6f\xcf\xa4\x2d\x0d\x21\xa9\x1d\xfb\xfe\x05\x97\xc7\x3f\xd9\xb9\x76\x76\x14\xeb\xdf\xd0\x2c\x3a\xc0\xc4\x9a\xd1\x0c\x94\xbe\x59\x69\xee\x08\x08\xc0\xa3\x0b\x2a\x1e\xaa\x90\xea\x43\xb8\x57\x5c\x30\x56\xf4\x23\xcd\x4b\x6f\x34\xae\x51\xc2\x22\x37\x65\xa9\xea\x21\xf6\x45\x73\xc1\xa1\x39\x61\x32\x12\x46\xe3\xb5\x34\x9e\xe0\x48\xfb\x62\xd5\xfb\x61\xb1\x71\x43\x91\x18\x25\x62\xb9\x15\x98\x36\x0e\x5f\x9b\xf4\xac\x80\xdb\x24\x64\x32\xaf\xb3\xa4\x3d\x34\x96\x50\xde\x03\xd3\x43\xc2\xe9\x7a\x8e\xef\xd1\xbf\x30\xc1\x0c\x25\x86\x7f\x53\x26\x6b\xd1\xf0\xdc\x14\xae\x1a\x6b\xe9\xef\xde\xcf\xf6\x7e\x7d\x29\x2c\x6c\xdf\xc9\x0d\x80\xb8\x86\x66\x8f\x04\xc2\xa0\xf5\xad\x7f\xa1\x7c\x17\x8b\x6e\x9b\x45\xa1\x1f\x4d\xdf\xe2\xd6\x69\x60\xa3\xf7\x51\x35\xad\x5e\xd1\x54\xe5\x13\xe1\xa5\xd1\x38\xe7\x37\x1e\x84\xd7\xc9\x24\x53\xe6\xc6\x2d\xc5\x9b\x8e\x1f\xa9\x3d\x77\x3a\x25\x40\xd9\x1c\x25\x7c"}, -{{0x4e,0xc6,0x82,0x9b,0x43,0x99,0x70,0x56,0xd9,0x96,0x85,0x38,0x9b,0xd5,0x3c,0x52,0x8d,0xe7,0xe5,0xff,0x27,0x15,0xd6,0x5c,0x95,0x66,0x19,0x82,0x6e,0x3f,0xb5,0xb5,},{0x7d,0x92,0x2d,0x57,0xfd,0xb1,0x27,0x92,0x87,0x9a,0xec,0x4e,0x8c,0x65,0x14,0x63,0xec,0xe0,0x64,0x49,0x2c,0x72,0x17,0x53,0xd2,0x2e,0x11,0x55,0x09,0xfe,0xd7,0x06,},{0x15,0x9c,0xa4,0x04,0xf7,0xf7,0x41,0x17,0xc5,0x16,0x3c,0xf4,0x04,0x11,0x09,0x49,0xeb,0x57,0xae,0x2d,0x76,0x62,0xb1,0xff,0x41,0x78,0xcc,0x67,0x56,0xe9,0x0a,0xda,0xea,0xb7,0x1b,0x06,0x4c,0xe1,0xdf,0xf4,0x57,0xb2,0xdb,0xa7,0xe2,0xdc,0x13,0xc2,0x17,0xbc,0xae,0x8a,0x61,0xfc,0xf8,0xce,0x14,0x87,0xa6,0x49,0xc2,0x57,0xff,0x07,},"\xed\x26\xb4\x13\x0d\x4e\xbf\x3f\x38\x61\x49\x1a\xa3\xdd\x96\xa4\xeb\x69\x75\x21\x73\xfa\x6c\x84\xca\x65\xdf\xc9\x91\xc7\xfe\x44\xe0\x2b\xd6\x16\x50\x25\x2a\x1d\x23\x78\x66\x82\xec\x38\xc1\xfe\xe8\x2c\xc3\x50\xdb\x7c\x3c\x39\x49\xa1\xc9\x35\xff\xeb\xd7\xba\xa2\x4f\x35\xa3\x93\xfb\xd2\x7e\x7c\x34\xc2\xf9\xff\xda\x60\xa1\x8d\xf6\x6c\x3e\x46\x5d\x90\xed\x48\xfb\xba\xd3\xfa\x79\x47\xde\xe7\xe6\x59\xa3\xee\xad\xb8\x87\xf0\x96\x3f\x6b\xdd\x76\xc3\x6c\x11\xae\x46\xd0\x88\xee\x50\xbc\xa8\x18\x7a\x0a\x88\x32\xdb\x79\x84\xb7\xe2\x7c\xbe\x6a\xbf\x12\xd2\xc9\x4f\x33\x7e\xc7\x8c\xb3\x8b\x26\x24\x1b\xd1\xa3\xd2\xf5\xfa\x44\x07\xfd\xd8\x02\x27\xd2\xb1\x70\x14\x4b\x41\x59\x78\xe3\x72\x01\xd0\xfc\xf4\x31\x74\xb9\xd7\xb2\x11\x5d\x5e\xb8\xbc\xec\x27\x6a\x77\x5a\xea\x93\xf2\x34\x0d\x44\x25\xd3\x4d\x20\x47\x49\x4d\x91\x7e\x0d\xbe\x37\x85\x7e\x6c\x99\x85\x9b\x71\xc9\x14\xaa\xd5\xe5\x4f\x7b\x2b\x03\x3e\x59\x4e\x27\x2c\xc5\xcf\xe9\x19\xf8\x88\xe5\x5c\xb6\x15\x7a\xff\xcf\x35\x72\x46\xd0\x0b\x53\x2c\xc4\x71\xb9\x2e\xae\x0e\xf7\xf1\xe9\x15\x94\x4c\x65\x27\x93\x15\x72\x98\x53\xda\x57\x2c\x80\x9a\xa0\x9d\x40\x36\x5f\x90\x87\x5a\x50\xd3\x1c\xa3\x90\x0d\xa7\x70\x47\xc9\x57\xc8\xf8\xbf\x20\xec\x86\xbd\x56\xf9\xa9\x54\xd9\x98\x8e\x20\x6b\x44\x4c\xa5\xa4\x43\x45\x21\xbf\xc9\xc5\xf3\xa8\xa0\x61\x47\xeb\x07\xd1\x1d\xfe\x11\x71\xec\x31\xff\x55\x77\x15\x88\xb3\x33\xee\xe6\x21\x5d\x21\x6c\x47\xa8\x56\x6f\xbb\x2b\x18\x97\x46\x46\xac\x5a\x92\xc6\x99\xd7\x75\x84\xc0\xde\xfe\xfd\x2d\xfa\x58\xfc\xa2\x71\x99\xe4\x1e\xc5\x8a\x24\x63\x20\xb3\x5f\xaa\xb7\x5b\x97\x95\x19\x24\x22\x6d\xa4\xab\x28\xf0\x1b\x47\x07\x8e\x71\x2e\x4f\xd9\xf7\x7b\x25\x1c\x96\x67\x85\x8c\x28\xe3\x2e\xf1\xcd\x01\xfc\xbe\x43\x5c\x54\x2d\xba\xd0\xa8\x4a\x13\xcd\xbb\x57\x75\xe6\x2d\x81\x1d\xc6\x90\xd9\x55\x5c\x37\xf1\x5f\x91\x76\x7a\x56\x13\x57\xdf\x10\x6e\xef\xe0\x56\xe7\x36\x06\x70\x65\x0f\xb8\x18\xfc\x6a\xdc\x59\x97\x3e\x9a\xd5\xcd\xcd\x80\x98\x07\xab\x56\x39\x7f\x3c\x13\x94\x87\x32\xd9\x8d\x67\x6f\x4a\x44\x70\xa9\x5d\x8b\x51\x82\x37\xe2\x26\xf0\xcc\x5f\x47\x65\x16\x4a\x5c\x3e\xf0\x50\x71\x4b\xe0\x2a\x12\x6b\xe8\xf6\x65\x46\x48\x15\x81\xb9\xe9\x4a\x26\xaa\xd2\x4c\x69\x3b\x7f\xdb\xc1\x8a\xcd\x3e\xd7\xcf\xc4\x7d\x8a\xb2\x67\x45\xd7\x8e\x70\x1d\x0c\xf0\x5d\xd8\x44\xb5\xb3\x45\xa2\x9d\xab\x68\x4c\xbc\x50\x92\xba\x02\x2e\x3c\x58\x2d\xfc\x04\x4c\x31\x00\xad\x02\x75\x66\x97\xa8\x49\x82\x29\x15\xa1\x6e\x2a\x2b\x81\x0e\x68\x15\xf5\x44\x21\xd2\xf3\xa6\xff\xf5\x88\xc0\xd9\x01\x3c\x76\xf3\x3e\x09\xbe\xae\xef\x60\xd8\x77\x42\x30\xe8\xce\x71\x31\x28\x9a\xef\x2a\x40\x68\x6c\x81\x9f\xb2\x04\x0b\x06\x12\x4d\x3d\x9a\xa4\x19\xd5\x67\x88\xf1\x7f\xa7\xed\x9b\x9b\x57\xce\xaa\xd1\x33\x7a\x01\x01\xbe\xa0\x44\x0c\xff\x74\x5d\xdd\x97\x22\x05\x5d\x1f\x9b\xcf\xb0\x09\xce\x2c\x2f\x41\xa9\xe7\xe8\x68\x06\xb8\x72\xcd\xc2\x05\x9b\xc8\xec\x68\xf5\xee\x56\xc4\xba\xcf\x4b\xbd\x30\xea\x4c\x71\x55\x86\x4d\x60\x0c\x0e\x2e\xee\x73\xb3\x19\xbd\xa4\x37\x2e\x9c\x60\x3c\x77\x2c\x25\x89\x0c\x76\x10\x48\x99\x89\x47\x5d\x37\xa7\x7a\x45\x74\xa2\xba\x55\xbf\xd9\xc9\xcf\xd1\x46\xfb\x97\xe6\x16\x5d\xcc\x19\x55\x9f\x4f\x85\xdf\xca\x2f\x97\xf3\x70\x2e\xd8\xfa\x6b\x3c\x2a\x97\x41\x97\x4a\xa0\x7a\xb6"}, -{{0xb1,0x50,0xa7,0x89,0x29,0xed,0x1e,0xb9,0x32,0x69,0x21,0x3e,0x1e,0xbc,0x22,0xe2,0xe4,0x0a,0x60,0x1b,0xdb,0x00,0x54,0x99,0xb7,0xbe,0xb0,0x58,0x91,0x7c,0x53,0x40,},{0x28,0x86,0x6b,0x6d,0x1c,0x39,0x3c,0xb0,0x8e,0x46,0x4c,0xf5,0x57,0x14,0x40,0xa6,0x49,0xe5,0x06,0x42,0x38,0x0d,0xdf,0x4f,0xfb,0x7a,0xd1,0x50,0x48,0x5c,0x10,0x8e,},{0x27,0x6d,0xd0,0x96,0x2e,0x6e,0xe6,0x4f,0x05,0x92,0x44,0x1a,0x8a,0xf0,0xe5,0xef,0x8f,0x93,0xbf,0x0b,0xae,0xba,0x20,0x50,0x4b,0x9d,0xb4,0xf9,0x5a,0x00,0xb9,0x39,0xea,0x38,0xde,0xf1,0xc7,0x97,0x86,0x28,0x98,0xca,0xbe,0x9d,0xc4,0x64,0x4f,0x0e,0x67,0x7e,0x87,0xc0,0xa3,0x3b,0x87,0xb6,0xa4,0xd2,0x2a,0x80,0x7d,0x0e,0x1e,0x02,},"\x1b\xf5\x5d\x27\xf9\xdd\xe6\xc4\xf1\xc0\xdd\xd3\x60\xa2\x5d\x94\x93\xc0\xff\xdc\xa7\x4a\x7e\xd5\xe5\xa5\x14\xe9\x55\x15\xcd\xa4\xaa\xd8\xf4\x5c\xd6\xed\x79\x01\xf8\xf2\x24\xa6\x3b\x38\x12\x1c\xbe\xac\x2f\x56\xda\xe2\x10\xdd\x05\x37\x50\xcb\x20\x75\x14\xa8\x89\x1e\x24\x5a\x5d\x07\xe7\xde\x78\xa2\xe3\x81\x44\x63\xf1\x48\xd2\xac\xb7\xdc\x71\xf9\x95\xc9\x29\x9a\xd0\xd6\x26\x6c\xfe\xfc\x94\x26\x96\x57\xfd\x47\xcf\x53\x12\xb9\x2a\xf2\x75\x06\x51\xc4\x79\x63\x6c\x9d\x36\xae\xf0\x8f\x7d\x11\x95\xe7\xfa\x1b\xa3\xab\xb5\xdc\xb9\x01\x36\xb0\xfb\x9a\x37\x66\x8b\x87\xa2\xdb\x88\xd1\xe2\xb6\x44\x0d\x3e\x6e\x60\x1e\x6d\x4b\xc1\x0c\xf1\xcb\xdf\x1d\x61\x69\xc0\xdc\x2c\x4a\xec\xde\xb6\xcd\xd4\x56\x7d\x42\x50\xb2\xaf\xa7\x15\xb1\x66\xc9\x46\x7f\x90\x7d\x3f\xa5\xa6\xda\xf2\x00\xb3\x09\xc1\x09\x37\x68\x30\x49\x9c\xaf\x31\x49\x00\x1c\xf3\x33\x94\x48\xca\x3d\x76\x52\x25\xd6\xb3\xc1\xcd\x26\x7c\xba\x93\x6e\x7a\xa4\x83\x25\x39\x46\x6f\xd2\x0c\xbb\x38\x32\x3c\xbb\x22\x28\xa2\x71\xf2\xd2\x82\x56\x1c\x73\xed\x79\xa1\xad\x04\x69\x8e\x27\xef\xe3\x93\x23\x5f\x34\x56\xc2\x95\x40\x7d\xa0\x96\x0f\x00\x34\xd8\xde\xef\xd1\xc1\x85\x73\x6f\xd3\xea\xf1\xf9\xa1\xe3\x2f\x09\x17\x4c\x1f\xe1\x27\x20\xb7\xc9\x6f\xeb\xdb\x33\xe0\x1b\x1b\x6a\x1c\x63\x71\x50\x19\x4b\xe4\xff\xab\x15\x9e\x45\xb2\x45\x85\x57\x68\x46\xbb\x64\x27\x4e\xca\x7b\x39\xa3\xed\x93\x57\xde\x7b\x08\x42\x13\x02\x4a\x9e\x85\x89\x26\x36\x00\xa2\x86\x7c\x2a\x7c\xf8\xb9\x90\x76\xa1\x2a\x07\xbd\x7d\xf8\xd5\x27\x7b\xb0\x4a\xd7\x2e\x63\x9b\x77\xea\xca\x1e\xc5\x8e\xf9\x63\x7e\x9a\x23\x76\xba\x87\x8a\x45\x72\x35\xa0\x6f\x78\xfd\xf0\xe0\xd9\x25\xcb\x2f\xd2\xa3\x8c\x77\x18\x8f\x60\x37\x2e\xf6\x00\x97\x92\x42\x43\x99\xc9\xb6\x79\x28\xda\x2e\x3b\xa9\x1c\xbd\xe4\x07\xe7\xe8\x76\xba\x98\x13\x9e\xd2\x2c\xa3\xb9\x83\xbe\xde\x00\x00\x52\x87\x96\x44\x8e\x4a\x10\x55\xac\xb2\xde\xaa\x56\xbc\x30\x82\x54\xc5\xbd\x49\x8c\x27\x5e\xce\xdc\x13\x57\xef\xe1\xfd\xa0\x1d\x34\xd9\x16\xdd\x4d\x86\x47\xe5\x77\x19\x95\xa6\x53\xe0\xf8\xa5\x28\x4c\xc7\xbf\x73\x15\x7b\x33\x49\xd5\x9e\x6f\x92\x0c\xad\x6c\xdd\x17\x19\xf0\x38\x02\x5c\x43\x00\xe0\x21\x0c\xe2\x49\xfa\xf3\xc8\x2d\xe1\xfd\x1c\xda\xbe\x61\xc1\x4e\xcb\x1d\xf0\x0c\x5c\x46\x6a\xa6\xa0\x12\xa9\xc1\x0d\xcf\xe5\x9b\x7e\x9d\x3b\x15\x5d\xab\x6c\x7b\x7c\x16\x08\xc1\xed\xd5\x1d\xbd\xad\xf6\xba\x58\x76\xb5\xe6\x0f\xdf\x7f\x19\xe6\xef\x71\x2c\xd1\xa7\xdd\x3a\x06\x2a\x65\x74\xa7\x43\x6b\x31\x9e\xfb\x94\x4e\x42\x23\xf5\x42\xb2\x50\x2c\x1b\xa9\x76\xbe\x91\xe0\x5b\x0f\x85\xa0\x9f\xd7\x93\xbe\xca\x88\x33\x75\xfb\x67\xcd\x13\x3f\x52\x84\xd8\x99\x84\xff\x3c\xaf\xa7\xe1\x1a\x9d\x85\xe7\x89\x32\x32\xa5\x24\xec\x54\xb2\x0f\x97\x5d\x3c\x0a\x11\x43\xa0\xef\x41\x17\x6b\x70\x51\xea\x91\xd4\x0c\x5f\x44\xfd\x9e\x10\x05\x58\xbf\x12\x12\xa7\xb8\x91\xe6\x8b\x55\xca\x61\xf4\xbe\x94\x52\x66\xd9\xa1\x00\x7a\x14\xaa\xeb\x68\xc4\x8e\x25\x7f\x0f\x46\x31\x0a\xd1\x64\x81\x46\x7e\xc1\x77\x35\x35\xd5\xfc\x08\x49\x15\xf5\xd0\x04\xba\x0d\xc7\x59\x1d\x21\x23\xc6\x22\x07\x90\x9d\x84\xf2\xb3\x82\xf5\xef\x12\x75\x9a\x95\xcd\x3f\x51\x89\x80\x6e\x27\x39\x60\xae\xe1\x62\xc0\x0f\x73\xe7\xfa\x59\x36\x39\x57\x65\x4b\xb1\x91\x6b\x57\x09\xbb\x0a\x9d\x04\x05\x14\xae\x52\x84\x95\x1e\x6b"}, -{{0x9f,0xc7,0xc4,0x9c,0xb8,0xc4,0xf0,0x97,0x2d,0x6e,0xd9,0x70,0xae,0x2c,0x6a,0xc3,0x37,0xe6,0x75,0x42,0x5c,0xc8,0xdc,0xe7,0x30,0xfc,0x41,0x44,0x43,0x02,0x93,0x5d,},{0x47,0x82,0x52,0x0b,0x06,0xf9,0x33,0x44,0xaa,0x76,0x67,0x80,0xe5,0x44,0x01,0x36,0x3d,0xfd,0x7d,0x96,0x7c,0xc3,0xbf,0x06,0x48,0x8a,0xf9,0x09,0x20,0xa3,0x0f,0x85,},{0x5c,0x78,0x3a,0x86,0x0a,0xa6,0x68,0x18,0x4d,0xd2,0x2c,0x4f,0x9a,0x54,0x6b,0x5e,0xc9,0x6e,0xba,0xd2,0xe4,0xaf,0x00,0xf9,0x68,0xc6,0x88,0x67,0x13,0x54,0xe0,0xcc,0x9b,0x57,0x2c,0x73,0xbc,0x6f,0x19,0x93,0x7a,0x05,0xf1,0xba,0xf3,0x43,0x47,0x63,0x96,0x5c,0x96,0xe1,0x03,0x40,0x7f,0x0e,0xb6,0x42,0xc5,0x64,0x41,0x54,0x29,0x0b,},"\x82\xbc\x2c\x70\x0d\xb2\x22\xa4\xac\x91\x4a\xa2\xbe\x8f\xa2\x8e\x42\x20\x67\xf9\x4f\x33\x44\xf5\x36\x2b\xeb\xaa\xbe\xd7\x61\x2b\x0e\x46\x4a\x73\xa6\xc4\x56\x90\x35\x64\xb1\x53\x93\x48\x51\x40\xdd\x0f\x3a\xff\x90\xaa\x6e\x16\x61\xdd\xf6\x82\x85\x0d\x04\x90\xaf\xc3\xd7\x35\xde\xa0\x5b\xa4\x7c\x85\xd9\x7e\x83\x35\x33\x51\x4c\x19\x8b\x4c\xf6\xe6\x6d\x36\x0e\xe5\xbf\x00\xe1\x4a\x3a\xab\x1a\xd0\xe7\xb8\xab\x2a\xac\xc9\x64\xd4\x28\x30\xc7\x84\x53\xdf\x19\x55\xbb\xed\x1c\xd6\x8a\xda\x3d\xb0\xec\xdb\x60\x1a\xd7\x66\x7d\x5c\x5e\x2f\xd4\x9e\x36\xf7\x32\x8e\xaa\x33\x7d\xbd\x6f\xf7\x0e\x78\x98\xa3\xf9\x8c\x15\x9d\x04\x5a\x24\x27\xad\xe5\x33\x3c\x88\xfc\x4a\xfd\x38\x19\xdc\x82\xf4\xda\xa3\xc5\x23\xcb\x57\xe3\x5a\x2a\x5a\x72\x5d\x63\xd4\x02\xba\xef\x51\xe5\x1f\x1e\xf4\xf8\xf9\xa5\x95\xc9\x37\x9c\x9a\xba\x87\x3f\xb4\xe7\x65\xa9\x31\xda\x09\x14\x8a\xba\x6e\xc5\xb4\x48\x59\xb0\xe8\x1f\xf9\xfc\x22\x95\x98\xac\x9f\xbd\xb0\xbd\xbd\xdb\x56\x92\xa5\x22\x22\xdf\x52\xea\x38\x7b\xbb\xf3\x6a\xd6\x4d\x19\x46\xbd\x28\x2e\x32\x3f\xf4\x82\x2a\xd9\xda\x89\x7f\xf7\x3f\x01\xb3\x90\xcf\xe2\xe6\x4d\xe4\x92\xd5\x5d\xe7\x7f\x5d\x7d\x00\x60\xa6\x87\x2a\x01\x83\xcc\xba\x61\x0f\x53\x27\x4c\xcb\x29\xce\x6d\xce\x6a\x03\x6c\x53\x17\xa1\xed\x2a\x7c\x10\x68\xc1\xb2\x46\xfc\x1d\x58\x81\xd0\x0d\xe0\x6e\xb4\x01\xcf\xf9\x5e\x6b\x69\x14\x86\x99\xdb\x13\xe9\x4b\xb5\xb2\x80\x21\x2d\xff\x54\xc7\x0e\x56\xde\x23\x5a\x5f\x14\x00\xb5\xbe\xa5\x67\x72\xd0\x60\x17\x0f\x1d\x06\x57\x32\x15\x61\xe4\xb4\x91\x07\xeb\x96\xd9\xb3\xbc\x5a\xdf\x45\x1c\x2a\x52\x4e\xba\x4d\xb0\x03\xb7\x7b\x63\x2a\x5d\x89\x82\x7a\x62\x24\xcc\x79\x8e\x09\x6b\xa2\x7f\xb3\x3b\xf6\x1e\x3b\x8e\xaf\x18\xd0\x01\xae\x8e\xb5\x2f\x85\xc9\x0d\x9e\x12\x54\x48\x03\xe6\x7f\xf0\x20\x47\xe0\xd2\x3c\x22\xe7\xf8\xb9\x80\xc0\x1c\x3d\x48\x24\xb2\xa9\xa1\x4a\x2e\x8f\x67\x2a\x7b\x0c\xe0\x3b\xdb\xb3\xbd\x56\xd7\x54\xa0\x96\x4d\xb0\x1c\xa8\x99\xd4\x88\x00\x15\x08\x65\x7b\x7b\x02\x2c\xcf\x04\x2c\x38\xfc\x19\x49\xd0\xe0\x0a\xf4\xd3\x01\xd4\xf0\x0c\x3d\xea\x20\xe3\x08\xa0\xf9\xdc\xac\xb4\x32\x22\xb3\x82\x41\x44\xaf\x77\xbe\x18\xa5\x04\xaa\x8d\x26\x8b\x8a\x56\x00\x72\x5e\x7c\xc5\xf3\xa2\xe6\x25\x6a\x80\x74\xd1\xae\xbc\xa1\x23\xea\x53\xa0\x76\x7a\x92\xe1\x78\x3a\x49\x83\xc5\xef\x3d\x7d\xd7\xf0\x2a\xa9\xd1\xf4\xf9\xaa\xc6\xce\x25\x45\x93\xf0\x87\x92\x01\x4f\xb8\x67\xea\xf8\x79\xb8\x8a\x4e\xfb\x18\xe8\x9b\xa1\x10\x06\xad\x09\xd8\x54\x31\xcc\x26\x57\x5b\x53\x8d\x8e\x78\x90\x64\x6c\x59\x88\x64\x7c\xc1\x05\xd5\x82\x90\x7a\xe6\x25\xe0\x9c\xd0\x89\xf4\x72\x49\xe8\x18\x14\xda\x14\x04\x4c\x70\x14\xe8\x0e\x7a\x8e\x61\x9c\x7b\x73\x5f\x70\x16\x16\xb6\xa3\xc6\xf4\x92\xcd\xc6\xed\x46\x3e\x71\xa3\xd2\x22\x91\x48\x2d\x90\xa1\xde\x6f\x09\x7c\x4a\xe2\x54\x87\x61\x84\xc5\x62\xb1\x65\x75\xb9\xd0\xd1\x93\x13\xed\x98\x86\x4f\x49\xfe\x2e\x1d\x07\x4a\x21\x21\x1b\x2b\x2a\x6d\x27\xdd\xb2\x86\x11\x52\x0d\x5f\x71\x23\x05\x8f\xd0\x07\xbb\x01\x00\x1d\xef\x07\xb7\x92\xbb\x05\xbb\x74\x1c\x12\x9c\x6a\x36\x37\x6c\x38\x53\xb8\xbb\x4f\x66\xb5\x76\x0c\x8e\xb4\xec\xc7\x30\x6b\xa3\xa9\x0c\x70\xda\x47\xc9\x65\xf6\xdc\xcb\xdb\x61\xa7\xfd\xa1\x8e\xe9\x67\xcf\x8c\x5f\x05\x03\x11\x09\x2d\x0f\xde\xea\xed\xd1\x26\x5d\xef\xdd\x66\x0a\xbe\x70"}, -{{0x08,0xbf,0x05,0x9b,0x4d,0xa9,0xaa,0x7f,0xfc,0x70,0x2f,0x5b,0x23,0x04,0xc4,0xf9,0x6c,0xa4,0x9b,0x7d,0xab,0xb6,0xaf,0xb4,0x1d,0xc9,0x1c,0x0f,0x00,0xc6,0x5b,0x78,},{0xa6,0x28,0x9b,0xa2,0x8e,0x80,0xe8,0xd1,0xa3,0x19,0x22,0x3e,0x41,0x65,0xdc,0x0b,0xce,0x73,0x52,0xaa,0xf2,0x42,0xf7,0x0c,0xc9,0x68,0xd2,0x1d,0x77,0x75,0x28,0x32,},{0xe2,0x47,0x65,0x86,0x01,0x37,0x68,0x9a,0xad,0x50,0xeb,0xee,0xfc,0x8d,0x6d,0xb8,0xe9,0x36,0xa4,0xcb,0xa6,0x2c,0xe8,0x7a,0x7f,0x58,0x02,0x09,0x38,0x4a,0x9d,0x7e,0xec,0x90,0x70,0x90,0x5f,0x60,0xad,0x63,0xa7,0xbe,0xfd,0x7c,0x70,0xf0,0xae,0x7c,0x81,0x09,0x16,0x9a,0xee,0x4e,0x51,0x8f,0xce,0xbf,0xac,0xa7,0x23,0xc5,0xb2,0x07,},"\xbd\x4f\xb2\x8a\x1d\xd0\x8b\x07\xba\x66\xe1\x7f\x0c\x4f\x21\x85\x3f\xef\xef\x1c\x9d\x20\xba\x79\x77\xf1\x54\x64\x1e\xa1\xa1\x8b\xec\xf6\xbb\xb8\x03\x88\x88\x62\x94\xe0\x75\x6a\x3c\x50\x8f\xfd\xfe\x90\xb5\x1e\x13\x56\xd1\x12\xd8\xcd\xe5\xee\x2c\xc6\x33\x2e\x61\xd1\x69\xcc\xc8\xcc\x93\x49\x94\xf1\xbb\x56\x0f\xa4\x66\x0c\x0b\x0f\xd4\xe8\x14\x9a\x22\x5e\xd4\x88\x3e\x68\xfb\xb6\x9d\xa7\xaf\x8a\x52\x4b\x17\x14\x1c\xcb\x76\xb5\x0c\xd8\xe1\xb6\x7d\x3c\xe0\x37\xde\xd7\xdf\xa5\x9b\xc7\xc2\x67\x42\x26\xec\x7e\x07\xb7\x8e\xa3\xf7\x82\xfd\xa3\xe5\xf1\xe9\xca\xea\xb6\x08\xca\x38\x7c\x30\x46\x54\xf8\x01\xd0\x0e\x10\xa7\xc2\x9f\x4b\x0d\xa3\xe5\xf8\x95\x13\xa9\x80\x37\x71\x9a\x1a\xef\x4c\x25\x06\xc1\x77\xaf\x54\x51\xa0\x07\x57\xa5\x9f\x16\x22\x9c\x4f\x44\x14\xdf\x51\x58\x0d\x48\x21\x0d\xab\xc9\x37\x73\x70\xb6\x06\x8a\x88\xe8\x1d\x3a\xd1\xbe\xd4\x98\x51\x55\xc3\x60\x0f\xf4\x87\x68\xb9\x03\x02\x2f\xe0\x2a\xe4\x80\xf2\xe6\x32\x9f\x0b\xcc\x91\xd7\x5f\x5c\x6a\x09\xfd\xf7\x7b\xde\x90\x49\x9f\x3c\xa3\x95\xcb\x20\x06\x2a\x09\x84\xad\x6a\x01\x41\xfd\x01\xc2\xd5\x4d\xfb\xb1\xee\x58\x46\x10\x64\x07\x73\x43\x9a\x16\x58\xd2\xc9\xf8\x62\xf1\x83\xbf\xef\xb0\x33\xa3\xbe\x27\x18\x12\xf1\x3c\x78\x70\x46\x57\xe7\xfb\x4f\x85\x01\x75\xfc\xd6\x3d\x3e\x44\x05\xd1\x92\x24\x2c\x21\xf2\x7c\x51\x47\x7f\x32\x11\xa9\xce\x24\x8e\x89\x2b\x42\xfb\x6d\x85\x82\x0f\x41\xb8\x97\x83\x6f\x20\xf8\x5a\x13\x11\x53\x4b\x5c\x40\x4f\x8b\x7a\x4a\x03\x19\xbc\x6c\xec\xaa\x57\xfe\x4d\x4f\x20\x60\x7c\x99\xc2\xdf\x22\xfa\x06\x76\xf9\x9d\x1b\xd8\x78\x86\xc9\x28\xc4\x98\x8c\x6e\x78\xc5\x7d\x75\x83\x30\xe6\x92\x2c\xbe\x03\xc1\x03\x40\x25\x3d\x0d\xd4\x83\x79\x2c\xe7\x5e\x6c\xd0\x9d\x12\xfb\xbb\x04\x1f\x02\x05\xe6\x5a\xd2\x5c\xe7\xc1\xb2\x4e\x77\xee\x8d\x6f\x91\x5e\x3b\xc3\xe1\x0d\x09\xfb\xd3\x87\xa8\x4b\xda\xab\xfd\x1c\xed\xb5\x2c\x0b\x17\x33\xb5\xf4\x70\x88\xc0\xd3\x5e\x0e\xf4\x58\xc8\x54\x14\xc2\xb0\x4c\x2d\x29\xf6\x3f\x77\x58\x61\x31\xee\x65\x53\x0f\x20\x9b\x51\x8a\x0f\x25\x7a\x07\x46\xbb\xd5\xfe\x0a\x2e\x0c\x38\x8a\x6c\x48\x0e\x1b\x60\x71\x4f\xee\x1c\x59\x41\xbb\x4e\x13\xf7\x07\xea\xc4\x87\xa9\x66\x6a\x72\x3b\x57\x93\x13\x4a\x26\x8b\x77\x59\x77\x86\xc3\xa3\x19\x3b\x46\xd3\x55\xdd\x08\x95\xfc\x62\x16\xc5\x36\xa5\x42\xff\xd7\xd7\xb0\x80\x10\xc8\x6f\x54\x7a\x5d\xaa\x38\x33\x5a\x8b\xfa\x26\x55\xd5\xf7\x1b\x4d\x88\x07\xf5\x0c\x85\x45\xc5\x83\xdd\x0b\x69\x00\x22\xee\x65\x87\x3a\xea\x3e\x8f\x1a\x56\x5f\x3b\x0e\x4e\x02\x95\xfb\x0d\x32\x1f\x5c\x0b\x39\x7f\x2f\xd0\x52\x8f\x86\xa0\xd1\xb7\x07\xf7\x37\xb1\x75\xc6\x9e\x9e\x7a\xe3\xc8\x4d\x4b\x2c\xf3\xa3\x8a\x63\x1a\xa8\x03\x2b\x3e\x65\xbb\x45\x28\xf6\x6d\x0b\xfd\x34\x47\x3e\xd0\x10\x1d\x2a\x61\x25\x5b\x21\x5b\xc1\xcb\xab\x9a\x26\xd2\xb9\x69\x32\x4b\x77\xc8\xa5\x46\x4e\x5b\x23\xdf\x6c\x51\x12\xf9\xd1\x7c\x58\x7d\x95\x55\x9d\xe2\x12\xad\x24\x1d\x8b\x12\x60\x50\xe5\xfd\xdf\xcc\x83\x9a\x7e\x5a\xa2\xfd\xa1\xca\x20\xc0\x91\x0d\x86\x34\x18\xf1\x95\xb3\x8a\xdf\xcc\x36\xe9\x2f\x23\x96\xac\x31\x44\xb5\x37\xb3\x0f\xbe\x4d\xde\x61\x49\x02\xf8\x99\x78\xb7\xfb\x42\xcd\x99\xf1\x3d\x99\xc4\x5c\x73\x4f\xb8\x2c\x32\x59\xf9\x0b\x88\xfd\x52\xbd\xcb\x88\xf7\xee\xec\xdd\xe4\xc2\x43\xd8\x80\xba\xc7\x61\x4e\x15\xcf\x8d\xb5\x99\x3f\xfa"}, -{{0xdb,0xbd,0x0f,0x7e,0xcb,0x64,0x82,0xcb,0x01,0xc4,0xdb,0xdc,0x38,0x93,0xc0,0xdb,0x81,0xe8,0x31,0x35,0x3a,0x5b,0x01,0xcc,0x75,0xd3,0xb1,0x1f,0x2f,0xf3,0xc5,0x9c,},{0x2d,0x4e,0x58,0x8d,0x31,0xa3,0x84,0xb1,0x78,0x58,0xc0,0xd7,0x84,0xf6,0x71,0x2b,0xaf,0xd0,0xb4,0x12,0x04,0xcf,0x8f,0x0d,0x57,0x97,0x3e,0x59,0xc7,0x70,0xd3,0xda,},{0x96,0xc0,0x03,0x61,0xfb,0x71,0xc5,0x23,0x05,0xe1,0xab,0x77,0x07,0xe0,0x46,0x52,0x03,0xeb,0x13,0xdf,0x3e,0x06,0x55,0xf0,0x95,0xfb,0x33,0x19,0x42,0xa4,0x0b,0x15,0x58,0x41,0x43,0xb3,0x70,0xa7,0xdd,0x57,0x61,0xfb,0x03,0xc0,0x75,0xd0,0x4a,0x83,0x48,0x66,0x1c,0xce,0xa9,0xad,0xa5,0x33,0x65,0xb5,0x00,0x08,0x7d,0x57,0xec,0x0c,},"\xe0\xff\xf3\x59\x75\xeb\xa7\x8d\xa2\xb0\xff\xcc\x5c\x1b\x66\x36\x00\x88\x8e\x82\x55\xcd\x20\x8f\x6d\xce\x7e\x88\x95\x3b\x71\x42\x93\x73\x89\xa3\x37\xae\x82\xf4\xcf\xe3\x2f\xcb\x34\xf5\x52\xa4\x8f\xa8\x89\x9e\x1a\x65\x9e\x3e\xd3\xd3\xd2\x90\xef\xc9\xa0\xf7\xde\xdf\x33\xe2\x1d\x04\x8d\x8d\x91\x07\x57\x03\x7b\x76\xe8\xa7\xee\x9e\x4e\xca\x30\xf5\x29\xdd\xc0\x2c\xef\xfc\x26\xd6\x4f\xda\x73\x03\xcc\x0d\x89\x40\xe9\xef\x59\xdc\x98\x3c\x12\xcc\xd1\xd2\x71\x7e\x64\xd3\x00\x6a\xf8\x2a\xb1\x5b\xb8\x78\xbb\x89\xd1\x75\x8b\xe4\x43\x10\x42\x06\x38\xb9\x6a\x0b\x5e\x1e\x65\x00\x9d\x69\x39\x5d\x02\x7a\x5d\xa4\xa8\x5e\x90\x1b\xe9\xaa\x2c\x0b\x3a\xcc\x50\x8e\xe1\x85\x74\xc1\xb2\xfa\x9b\xd5\xd7\xae\x7c\x7d\x83\x07\x12\xda\x5c\xbf\x26\xbe\x09\xa3\x12\x84\x70\xa1\x2a\x14\x90\x9a\x80\xa2\x66\x65\x9b\xef\xda\x54\x8f\xd2\xb2\x2f\x24\xc5\xfd\xc2\x06\xed\x3a\x4e\x75\xf5\x32\x06\x82\xed\x0e\x4c\xe8\x17\xd6\x3d\x5c\x7f\x1e\xe2\xb4\x40\x64\x33\x55\xbe\x65\x42\xf5\x9d\xc6\xc4\x5a\xb1\x57\x72\xf2\x21\x9a\x81\x2e\xf7\x52\x76\x42\x01\x5b\xc7\x5f\xe4\x5b\xa9\x69\xe8\x10\x0c\x26\x8e\x24\xce\xef\x92\x05\xa8\x3a\x3f\x7b\x5a\xe8\x00\xad\x06\xe0\x95\xb9\xb1\x39\x21\x94\x89\x79\x3a\x7b\xce\x84\xeb\xeb\x65\x4a\xb6\x66\x9e\x28\x55\xcc\xbe\xb6\x94\xdd\x48\x65\x15\x05\xb9\x59\xd3\x2a\x77\x02\x0b\x86\x95\x33\xe3\x25\x6d\x40\x68\x5a\x61\x20\xba\xb7\x94\x48\x5b\x32\xe1\x16\x92\x56\xfb\x18\x8f\xe7\x6e\x04\xe9\xef\xa6\xd1\x0d\x28\x6a\xe8\x6d\x6f\x1c\x87\xe8\xfc\x73\xad\x9b\x59\xfe\x0c\x27\xee\x92\xa4\x64\x15\xb3\x9d\x78\x6d\x66\x32\x5d\x7f\xa6\xfd\xa7\x12\xf1\x99\xda\x55\x4f\xc1\xc8\x99\x44\xa4\xe8\x4c\x19\x6e\x97\x9a\x80\x75\x53\x71\x8c\xb8\x1c\x07\x6e\x51\x1e\x60\x9d\x5c\xac\x23\xd8\xf4\x5b\x38\xb9\x4b\xcf\xcf\x15\x8d\x0d\x61\x60\x22\x38\xd5\x2e\x3a\xe8\x4c\x81\x53\x22\xf5\x34\xf2\x54\xe6\x33\x89\xae\x15\x5d\xee\x2f\xa9\x33\x96\xf0\xea\x49\x9d\x5d\x08\xc2\x47\x59\x08\xc6\x48\xbd\xdc\xee\x59\x1e\x13\x37\xe9\x42\x1d\xc5\xa2\x57\xce\x89\xcc\xce\x4c\xee\xa8\x09\xd7\xe8\x71\x34\xe0\x39\xdb\x1b\xe5\x98\x19\x6d\x30\x89\xfd\xcf\xa8\x97\x8e\x02\xc1\x55\x58\x32\xda\x0a\x72\xb0\x8a\xd0\x7c\xdd\x07\x26\x27\x40\x9c\x87\x39\x37\xb0\xe8\x35\x71\x5b\xaa\xf2\x60\x8b\x23\x95\x32\x74\x67\xcf\x69\xa1\xcd\xcc\xe6\x37\x24\x18\x38\x3e\x7b\x89\xc8\xdf\x4d\x53\x1f\x58\x51\x49\x50\x9e\xad\x1e\x41\xb6\x62\x7f\xea\x81\xc7\x95\x8c\xb4\x9d\x2d\x3c\x3e\x2f\xc6\x91\xe0\xb8\xcf\x72\x67\x9c\x08\xb8\x90\x46\x54\x53\x1b\xc4\x36\x8f\xb6\x17\xac\x75\x57\xd9\xdb\x8d\x32\x9d\x77\xe4\x8d\x8f\xb4\xde\x73\xab\xe7\xcb\x93\x88\x27\x4a\xf5\x85\xf8\x75\xc0\xda\xb7\x93\xe4\x35\x35\x18\xbb\x24\x69\x53\x42\xaf\x0f\x5d\xf5\xbe\x4e\x9c\x7a\xd2\x15\xbe\x90\xe2\x55\x40\xda\x34\x89\x71\x7d\xd3\xd2\x92\x54\x58\x5a\x45\xc1\x3e\x6d\xcc\x7e\x9c\x8a\x3a\x79\xff\x75\x5c\xbe\x46\x5b\x25\xe2\x3a\x1d\xa6\x08\xe1\x08\x4f\xec\x83\xbf\xf8\x0c\xfb\x74\x42\xb1\x46\x01\x87\x30\x7a\xcd\x75\xe3\xf2\xd1\x28\x43\xa7\x70\x94\xac\xc3\x28\x88\xfb\xe5\xf1\xfc\x24\xc6\x15\xd1\x9a\x06\x53\x91\xd4\x17\x64\x74\x64\x42\x46\xb5\x34\x3d\xa7\x76\x26\xa2\xd4\x83\xfe\x20\x4f\x83\x93\x28\x77\x5b\x71\xa4\xcb\x56\x72\x73\xe1\x69\x64\x0a\xf9\x3d\xde\x3e\xca\x91\x16\xf4\x00\xe2\x3a\x7a\xd3\xd8\xfc\x3a\x28\xe5\x65\xf1\x25\xd6"}, -{{0x74,0x8b,0xb3,0xcd,0x47,0x71,0x37,0xbc,0x88,0x0e,0xa7,0xc6,0x1d,0xf2,0x5c,0x1d,0xac,0x6e,0xbe,0xc9,0xe6,0xc3,0x19,0x3d,0x81,0xff,0xa6,0xf7,0xa8,0x1e,0xc6,0x67,},{0x10,0x6f,0x28,0xcf,0xed,0xf0,0x96,0x45,0x42,0x26,0xb3,0xb0,0x1f,0xc2,0x4a,0xb1,0xc9,0xbb,0xd7,0xf2,0xb0,0x97,0x3e,0x56,0xfe,0x2f,0x4c,0x56,0xa0,0xb1,0x47,0x5b,},{0xe1,0x3c,0xa8,0xe5,0xce,0x7c,0x26,0x80,0x90,0x90,0x8d,0x61,0xcf,0x2f,0x0a,0x3e,0x45,0x72,0x41,0x2b,0xf5,0xad,0xfc,0x5a,0xdd,0xfe,0x88,0x55,0x6f,0x14,0x8b,0x5f,0xcb,0xe3,0xe1,0xbc,0x65,0xff,0x16,0x11,0x7d,0x35,0xc9,0xd5,0xdc,0x3b,0x11,0x71,0x98,0xf8,0x84,0x92,0x5b,0x40,0x35,0xb2,0xc0,0xde,0x6c,0x40,0x2e,0xd4,0x7a,0x01,},"\x00\xde\x6d\x99\x0c\x84\x33\x8a\x39\x8f\xda\x5f\x4a\x2c\xca\x73\x3c\x56\xb2\xa2\xea\x39\x6c\x2f\xe6\x67\xc2\x68\xe3\x81\x45\x87\x85\x39\xbd\x41\xbc\x14\x0a\x2c\xdf\xe7\xe1\x83\x60\x41\x10\x48\xcc\xa6\x0f\x35\xce\x51\x09\x91\xdf\x26\x1c\xbf\x66\x90\x39\xd9\xd2\x56\x87\xa0\x7f\xc0\x47\x6a\x41\xf5\x0e\xcc\xf3\x81\x53\xee\x6a\xe9\xff\xd3\x92\xb2\xbe\xc0\xcc\x67\x10\x1e\xc3\x69\x6d\x7a\x2e\xc8\xcb\xd4\x47\xb6\xa6\xea\x06\x3d\x33\xec\x12\x8a\xe8\xb5\x75\x77\xde\xe1\x7b\x97\x16\x25\x63\xf1\x5e\x42\xb5\x5c\xa4\xbe\xdb\xdf\xb6\x31\xa9\xf6\x26\x2f\x94\xae\x35\xbb\x35\xf7\x95\xc3\x5a\x01\xde\xdb\x46\x45\xa7\x3c\xfa\x6e\xd9\xee\x52\x1e\x46\x31\xfb\x17\xbb\xc0\x6e\xe5\x73\x16\xbe\x52\x74\x27\xc8\xaa\x55\xc6\x31\x18\x74\x62\xd4\xb2\xc8\x82\x2c\xa4\xe1\x8b\x7a\x5d\x4c\x11\x4c\x11\xdc\x22\x06\x9b\xc8\x32\x65\x6d\x5f\x4d\x39\x54\x87\x18\xc5\x1f\x5e\x4f\xc8\x28\xf6\x0e\x37\xf0\x13\x07\x50\x52\x65\xac\xb2\x2d\x5e\x8d\x76\x7b\x9a\xa7\xb8\x66\xa1\x57\xc6\x43\x87\x3e\x09\x08\x4a\x1a\x40\x4a\x7b\xb5\x8c\xcc\x4b\x5a\x39\x0f\xd3\x06\x01\xc8\x96\x93\x5e\x35\x56\xf6\x0d\x2d\xc6\xbd\xff\xe4\x7d\xa0\xa6\x87\xc8\xec\xe1\x24\x1f\xf6\xc0\x7d\x77\x61\x11\xca\x65\x98\xfc\xa9\x68\xcb\x6a\xfa\x0a\x14\xa3\x4a\xb8\xf5\x4b\x95\xd3\xd8\x47\x3a\x17\x4b\xc7\x25\x52\x3f\x86\x74\xdf\xb2\xb1\x0f\x87\x42\x07\xfe\xe1\xb0\x8b\x42\xda\x1f\x58\x65\x53\x05\xa3\x59\x75\x7a\xa0\x25\x1f\x14\x13\x8e\xed\xbc\x28\x0c\xbd\x38\x5b\xf4\xbb\xf5\x53\x01\x14\xcc\x43\xb0\x47\x47\x79\xe2\x04\x96\x2f\x85\x60\xd4\xaa\x42\x3e\x17\xe6\xae\xca\xce\x66\xc8\x13\x78\x4f\x6c\x89\x8b\x5b\x9c\xb7\x46\xa9\xe0\x1f\xbc\x6b\xb5\xc6\x60\xf3\xe1\x38\x57\x4f\x59\xb9\x74\x54\x45\x48\x6c\x42\x2b\xc0\x6a\x10\xcc\x8c\xc9\xbc\x56\x45\x8e\xf8\x5e\x0e\x8a\x02\x7c\xb0\x61\x7d\x03\x37\xdd\xda\x50\x22\x0b\x22\xc5\xc3\x98\xf5\xce\x05\xec\x32\xf0\x9b\x09\x0f\x7c\xf6\xc6\x0f\x81\x8c\x6b\x4c\x68\x30\x98\x3e\x91\xc6\xea\xdf\x1e\xae\x4d\x54\xbd\xe7\x54\xf7\x5d\x45\x0a\xe7\x31\x29\xf6\xc4\xff\x5c\x4c\x60\x6f\x7c\xad\xbf\x4f\x78\xa1\x8d\xb2\x96\x1c\xc8\xc8\xdd\xab\x05\x78\xcf\xed\xfc\xf9\x5e\xf0\x88\x8a\xfd\x38\x55\x37\xd1\xd0\xa0\x76\x48\xa5\xce\x25\x22\xd0\x63\x35\x07\xd7\x75\x93\xe1\xa0\x36\x6d\x1e\xce\x84\x3d\xe6\x98\x67\xd7\xac\x44\x2b\xa7\xda\xd2\xa9\x0b\x59\xd8\x98\x4e\x4a\x94\x6b\xbe\x5f\x17\x2d\xa4\x27\x63\x8b\x2b\x61\x20\x90\x41\xff\xf5\x0e\x60\xec\x02\xec\x2c\x0b\x1d\xc4\xbe\x2e\xdd\x13\xe8\x7b\x64\xd1\xd1\x66\x31\x14\x57\x3c\xf5\x8a\x17\x73\x9f\x46\x3a\x1c\x3d\x6b\x21\x23\x39\x01\x83\xb5\x05\xc8\xee\xff\xb2\x05\x39\xbd\xfe\xeb\x40\x77\x6d\x20\xc4\x59\xba\xc4\x56\x99\x68\xfc\xaf\xe4\x4e\xa4\xcd\x62\x4a\x84\xbf\xcc\xd7\x87\x6d\xd7\xbf\x55\xf8\x3a\xc7\x04\x0e\x30\xf3\x26\xdc\xe3\x25\x58\x8e\x1b\xa5\xbc\x07\x90\x26\x5d\xfd\xba\x09\x83\x9e\xef\x57\x16\x41\xe8\xa1\x23\x4b\x6c\xfc\x3a\x36\xa8\x66\xbd\x6b\x92\xcd\x71\xec\x74\xe0\xd4\xde\xb9\xe7\x4d\x15\x82\x01\xaa\x50\x2f\x07\xc8\xba\x34\x8a\xc2\x6a\xaf\x9b\x3d\x07\x0c\x9a\x40\xb5\x2a\x44\xe9\x32\x55\x2b\x67\xa2\xdf\x05\xa7\xf0\xf0\x3c\x61\x7b\x48\xdc\x27\x82\x36\x6a\x23\x1e\x0c\x4e\x39\x38\xa4\x27\x4b\x36\xaa\x94\x50\xff\x93\x6b\xe1\x32\xdc\xb6\x92\x83\x8d\x65\x4c\x94\x54\x2c\x6e\x04\x7a\x7f\x78\xba\x71\x19\x19\xf9\x08\xa1\x5b\x30\xb9"}, -{{0x39,0x3d,0x44,0xdd,0x0d,0xed,0x71,0xfc,0x08,0x47,0x7b,0xd2,0x5e,0xd0,0xe6,0x62,0x9f,0xa7,0xf8,0x8f,0x08,0x2e,0xbc,0xef,0x09,0x18,0x98,0xe5,0xc9,0xe3,0xd5,0xb8,},{0xc5,0x2a,0x99,0x3b,0x80,0x2d,0x84,0x54,0x0d,0x27,0x54,0x79,0xa1,0xaf,0x5e,0x28,0x7d,0x19,0xea,0x13,0xb3,0x80,0xfa,0x30,0x68,0xd2,0xf2,0xc6,0x8e,0xb9,0x7a,0x09,},{0x84,0xc7,0x16,0xe6,0x0d,0xe6,0x7b,0x02,0x0c,0xc1,0xa6,0xa2,0x4e,0x65,0x49,0xfe,0x56,0xc6,0xd9,0x41,0xa8,0xed,0xea,0xe4,0x07,0x62,0x66,0x66,0xc3,0x1c,0xb6,0x0d,0xee,0x6b,0xe5,0xa7,0x1e,0xbd,0x76,0xba,0xf7,0x1b,0x75,0x11,0x4b,0xcc,0xfd,0x37,0xd1,0x63,0xa9,0x68,0xbb,0xee,0xc1,0xf7,0x69,0x72,0x15,0x12,0x96,0xc4,0x7e,0x07,},"\x14\x2b\x6e\x82\x50\x13\x62\xd5\x5a\x04\xb8\x9d\x54\x1a\x79\x68\x63\xd7\x78\x38\x40\xd3\x4c\xbd\xfc\x51\x6a\x3c\x84\x77\x2f\x92\x44\x6f\x5f\x0d\xf4\xc4\x5c\x6e\x0d\xc8\xec\x1e\x9b\xb0\xff\x7e\xc1\x69\x6a\x09\xcd\x7a\xe3\x4c\x10\xf8\xe6\x1a\x9a\xca\xbd\x43\x03\xf0\xa9\x24\x72\x37\x62\x1c\x49\x0e\x8d\x9d\x0f\xe4\x44\x82\xc5\x60\xd0\x51\xb8\x2b\x07\x4a\xc3\xd8\xe4\x9b\xb2\xac\x71\x5a\xc4\xcd\xe3\xd4\x70\x9d\x0e\xa3\xaf\xc5\x1b\xfd\xef\x4b\x65\x67\x71\xfb\xd5\x5f\x89\xda\x9f\xa6\xdc\xaa\x62\xcb\xae\x56\x12\x08\xd9\x8c\xfa\x24\xcb\x81\x25\x2b\x89\x5f\x6a\x4a\x92\xc8\xe4\x07\xaf\x6c\x1f\x1e\xf4\x9d\x8d\xde\x15\x4f\xbc\xb1\xca\x45\x7a\x20\x4b\x5e\xa5\x43\x2e\x4d\x71\xfb\x7e\xb2\x4d\x43\xf6\xfe\x25\xe7\xb4\xc6\x59\xb0\xee\xbc\x4c\xbc\xc8\xb3\xcf\xde\x07\xc8\xf0\x7b\x18\xa5\x15\x70\xe7\x16\x3e\x33\xb3\x17\xb6\x13\x60\xf9\xce\x08\xd9\x5d\xe2\xc3\x15\x6a\xf1\xcc\xc9\xb5\x5b\xcf\x81\xea\xbf\x3c\x40\x43\x40\x46\xbb\xe8\x2e\x02\x99\x2a\x2a\xc8\xb3\xb4\x25\x68\x0a\x23\xd9\x34\x72\x6c\xb1\xb7\xbf\x26\xce\xb5\x2a\x39\x02\x2c\x00\xac\xf4\x25\x25\x71\x67\xb8\x21\x18\x5f\x68\xe3\xed\x17\x90\x3d\x8d\x22\x27\x54\x98\xc3\x9a\x9e\x8d\xf8\x84\xec\x00\x55\x8d\xcf\xa4\x3b\x8a\x11\x9c\x2e\x85\x3b\x9a\x03\x18\xbb\xea\x08\x7f\x9c\xec\x17\xca\x49\xb7\x08\x17\xb8\xd7\xc1\x70\xa8\x90\x6f\x3e\xe9\xe8\xf8\xcb\x27\xa1\xd0\xf5\x75\xab\xfa\x62\x7e\x88\xf0\x8c\xa4\xb9\x3c\x32\x97\xc4\xf3\x17\x07\x2f\x42\x1c\x5e\x60\x2e\x2f\x83\x1d\xfb\x82\x55\x1b\xdc\xe8\xd7\x12\x16\xf0\x5c\xf9\xa2\x77\x3b\x90\xfc\x93\xb9\xd8\x55\xa9\x1e\x35\xad\xe3\x32\xa5\x06\x1f\xdb\x82\xb3\x09\xba\xb4\xf5\x6e\x2d\x58\x6a\x84\xc6\x74\x81\xd1\x90\x2c\x26\x1b\x3f\x97\xdc\x30\xb1\x84\x61\x9d\xf9\xfd\xfc\x7a\x32\x9d\x06\x1a\x41\xdf\x33\x22\x02\x13\x3d\x8e\xae\xed\xdb\x4c\xfc\xee\x53\x53\x6e\x07\xaa\xd1\x15\x53\xdc\xf5\xed\x1e\x94\x9d\x45\x35\x5f\x9e\xf4\x2c\x78\x32\xb0\xde\x7c\x2f\x15\x26\xfb\xef\x86\xb6\x36\x49\xb6\xb8\x5a\xe5\xca\x86\xf0\xce\xa6\xdf\x9c\x12\x6c\x1d\x79\x48\x9c\xc3\xbf\xc6\xe8\xbf\x03\x46\xeb\x30\xd0\x16\x43\xc0\x10\x15\x0c\x5c\x8d\x0e\xb5\x01\x0a\x46\x11\x22\x15\x13\x79\x91\x08\x5e\x57\x49\x3b\x22\xe8\x35\x26\xb7\xb1\x72\xc6\xc7\x34\x1c\x40\x32\x1e\x9c\xeb\x7c\x82\xbf\xba\xa4\x8f\x3b\xd8\xf5\x13\x72\xd9\x6d\x47\x44\x4f\xf0\xd8\xbb\x2e\x5f\xd2\x65\x14\xeb\x63\x91\x05\xe3\x38\x95\xfd\xc4\x1f\x6d\xf1\xfb\xfd\xcb\x08\x46\x6e\xc2\xd2\x17\xfc\x99\xfb\x01\x2f\xe6\x54\x0c\x0c\x5a\x59\x66\xed\x3e\x66\xfa\xb1\x20\x2a\xb9\xda\xff\xe8\xe2\x7e\x8f\x74\x62\x82\x8d\x66\x26\x59\xea\x3b\x2c\x60\x8c\xf6\x8e\x30\xdb\xac\x62\xff\xd8\x22\x9f\x4a\x53\xf5\x9a\xe1\x68\x33\xb8\x1a\x15\x91\x61\xf1\x93\x69\xf6\x0f\x51\xc4\x3a\x21\x7e\xfc\x5e\xfd\x6a\xb7\xa9\x1f\xe2\x49\xc7\xb8\xa0\xc1\x4e\x9f\xae\xa5\x33\xde\x13\x38\x49\xa9\x24\x47\x67\x6f\x6c\xc1\x8b\xef\x4f\xec\x7f\x37\x31\x97\x59\xce\x80\xea\x3e\xac\x18\xfa\x2d\x9f\xa0\x23\x09\xe1\xce\x93\xac\x6c\xf4\xcd\x2c\xb2\xc9\x5f\x1e\x2a\xff\x7b\x2a\x88\x56\x40\x5a\x7b\x8e\xba\xbe\xb4\x90\x6d\x9b\x97\x34\xda\x9f\xb5\xe5\xd3\xf3\x22\xbb\x5b\x55\x9f\xa6\x1e\xc8\xf5\x15\xdb\x90\x65\xab\x4b\x91\xa7\xa3\x1d\x5c\x62\x50\x61\xc2\xfd\x2b\xcf\xe1\x7f\x94\xbb\xde\x47\x76\x30\x2b\x8a\xef\x3d\x5b\x52\xdb\x3b\xc7\x3a\xe4\xa3\x0c\xc4\x41\x7a\xcb"}, -{{0x71,0x19,0x36,0x40,0xa0,0xa2,0xb2,0x2f,0xb2,0x2d,0x00,0xa8,0x0b,0x33,0xa5,0x51,0x4f,0x3d,0x10,0x00,0x03,0x4f,0xcc,0xd8,0x85,0xd8,0xea,0x86,0x38,0xf0,0xb0,0xf8,},{0xb1,0xd3,0x6f,0x72,0x3b,0x70,0x86,0xd9,0x23,0x11,0x9f,0x46,0x75,0x9b,0x39,0xfa,0x1e,0x40,0x38,0xc6,0x41,0x8c,0x37,0x9b,0xa9,0x8b,0x58,0x40,0xc7,0xea,0x50,0x68,},{0xa9,0x70,0x2a,0x33,0x95,0xac,0xd2,0x0d,0x75,0x43,0x73,0x09,0x5d,0xc6,0x14,0x45,0x58,0x4d,0x8e,0x57,0x10,0x80,0xe1,0x79,0xad,0xcb,0xa3,0x10,0x6b,0xb0,0x6a,0x7c,0xe4,0xd4,0x60,0xf1,0x26,0x1a,0xef,0x86,0x43,0xab,0x16,0x34,0xf4,0x7c,0x94,0x14,0xa3,0x2e,0x18,0x3a,0x32,0x76,0x91,0xe6,0x58,0x43,0xdd,0x6c,0x05,0x50,0x72,0x07,},"\xe0\x28\x79\x48\xbb\x85\xa3\x98\xe6\xaf\xfa\x2d\x25\xfc\xff\x8b\xdb\x93\x26\xf5\xd1\x4f\xde\xb6\x05\x49\xf5\xfb\xf0\xc1\x81\x6f\x11\xcb\xdd\x4e\x90\xfe\xa0\x39\xdc\xa6\x0f\xaa\xd1\x69\x60\x03\xf9\x15\x15\xc9\xb2\x72\x88\x2c\x95\xc9\xa4\xab\x6e\x27\x77\xbd\x92\x7e\x7d\x84\x42\xae\xa6\xce\xa6\x19\xc9\xb1\x52\x55\xfe\xd6\x12\xb5\xcc\x31\x58\xfc\x70\x5b\xb7\xa5\x06\xf4\xaf\xec\xf4\xe3\x4e\xd5\x17\xb2\xc1\x2b\x83\x62\x61\x0e\x5e\xa2\x70\x48\x5c\xcc\xb3\xc9\xaa\x97\xec\xd6\xcb\x19\x63\x09\x00\xf0\x7d\x94\xcb\x29\x3c\xb6\xe0\x89\xa9\xa7\x7c\x01\x94\x07\x3a\x7f\x71\x77\xb0\x23\x0d\x25\x76\x3a\x2e\xf9\x8d\x47\x70\x4c\xb2\xc3\xaf\x4c\x3c\x1b\x49\x56\x31\xb4\xa5\xb2\x1b\x2e\x56\xbf\xf2\xed\xe0\x3e\xa4\xfe\x7c\xf8\x29\x17\x34\x7e\x3a\x9d\x4d\xbe\xef\x37\xd1\xcf\x17\x61\x5a\xda\xa0\xfd\x17\x05\x79\x69\x91\x7d\x47\x8d\x03\xcc\xd8\xf8\xb8\x8e\x5e\x5a\xca\xe6\x73\x2a\x81\x61\xdf\xb5\xf7\xd0\x21\x23\xc8\xd5\xa5\x65\xcf\x4d\xd9\x8d\xfc\x9a\xaf\x5a\x33\x50\x58\xa9\x41\xca\x43\x07\x3f\x26\x59\x61\x5a\x72\xfe\x78\xc1\x01\xc4\x1a\xed\x07\xf3\xbc\xf9\x80\xb0\xa5\xb3\xfb\xaf\xdb\xbe\xa9\x2f\xd8\x89\xcf\xd5\x3d\x40\x32\x78\xbc\x15\xa5\x9a\xa1\x40\xc2\xd7\x73\xb8\x88\x9b\x96\x3d\xce\xa3\x65\x36\x2e\x42\x6e\xf4\x60\x98\x45\xc9\xbc\xe9\xf8\xae\xb5\x91\xd1\xa4\x69\xb0\x72\xb4\x12\x09\xf5\xa8\xb6\xdc\x23\x95\xad\x90\x60\xeb\x2e\x37\x09\x78\xae\x33\x11\xd1\xcf\x0a\x8f\x20\x51\x42\xd4\x36\xba\xb6\xb9\x59\x43\xa9\x7c\x23\xe6\x1b\xd1\x4b\x2d\x95\x67\x2c\xb9\x32\x5e\x9a\xb1\xfc\x9e\xee\xaa\xcc\xd5\x8b\x9f\x4a\xc1\x55\x0b\xde\xc8\x44\x9b\x03\x60\x39\x49\x6c\x5f\x07\xa5\xed\x64\xd5\xd8\x51\x71\x69\x01\x44\xdb\x5c\x81\xc8\x1c\xbc\x4c\x16\x71\x8d\x52\xc4\xdf\xd1\x95\x8c\xa5\xc9\xc8\xba\x58\x2c\xd9\xd7\x06\xf2\x7a\x74\x74\x4c\x3a\x05\xbf\x1c\xcd\x51\xf1\x09\x20\x10\xd3\x6f\x15\x78\xb5\x78\xae\x0e\x9f\xfa\x47\x07\x90\x55\xef\x94\xfa\xbc\x9f\xf7\x2f\x73\x8b\xef\x68\x46\x1e\xb3\x40\x4c\xce\xe9\x53\xf5\xee\x86\x4c\x97\x4c\xe7\x0e\x90\x37\xe3\x38\x8f\xba\xf2\x88\x9e\x13\x66\xca\xa0\xf6\x51\xe2\x1b\x33\x9e\x3d\x56\xb9\xd9\x5a\xc3\x0b\x35\x92\xa9\x48\x91\x2c\x90\xbf\x54\x47\x3c\xeb\xc4\x67\xb0\x9a\x39\x43\xdc\xac\x48\x68\xac\xb5\xb3\x5e\xa6\x91\xef\xf4\xd8\xcc\x1c\xda\x0c\x6c\x0a\x9c\x16\x9a\x4e\xe1\x00\x41\xf3\x5f\x43\x3f\xb5\x3d\x26\x06\x7b\x29\x10\x56\xb1\xda\x69\xff\x46\xfb\xea\x1c\xa7\x21\x36\x59\xa9\x90\xd5\xd5\xdf\x14\x06\xb0\x93\xda\x2a\x33\xc8\xdf\x95\xab\x3c\xe8\x11\xaf\xb9\xc9\x8c\x5b\xfd\x7c\x4e\x98\x1b\x3e\xa9\x4e\xef\xd2\xe2\xfe\x95\x70\x7d\x89\xf3\x07\xfa\x76\x82\x8b\x5c\x67\x74\x95\x0a\xee\x80\x62\x67\x14\x25\x6e\x19\x7d\xc7\xda\x97\x21\x58\xc7\x68\xbb\xee\x7f\xbd\x16\x9e\xc1\x5b\x4b\xb7\xbe\x72\x97\x6d\xbe\xd3\xe5\x12\x76\x6e\xf2\x2e\xf3\xb8\x12\xbc\xac\x4a\xa3\x11\x5a\xfe\x83\xd3\x12\x84\xaf\x8e\xac\xea\x4e\xe4\x9a\xfd\x42\xd9\xc4\x4f\xff\x2d\x86\x1c\x08\x62\x9b\x55\xda\xe0\x0f\xf6\x74\xfb\x02\x8e\x73\x8b\x05\xdc\xb3\x8a\xea\xa6\x96\x3c\xc3\xfa\xaf\xc7\xb6\x92\x45\xa2\xa1\x22\xa9\x6d\xd2\xf0\x3a\x82\x4d\x72\xb0\xfe\x0d\xd7\x98\xdf\x5c\x4b\xb7\x5a\x87\x32\x4e\x76\x4a\x50\xa5\xff\x52\x54\x7a\xda\x8f\x8f\x88\xe6\xf3\x8a\xee\x49\xd5\x8d\xdb\x01\x26\x48\x85\x4c\xd5\x9d\x0e\xc9\x7b\xc3\xd5\x8d\x0a\xd4\x49\x1f\x08\x59\x07\x67\xce\xb1"}, -{{0xbf,0xc9,0x62,0x6c,0x91,0xf3,0x48,0xfd,0xaf,0x46,0x9d,0xef,0x23,0x02,0xe9,0xe3,0x8f,0x90,0x51,0xe7,0x34,0x9e,0x48,0xf8,0x50,0xcf,0x35,0x2a,0x83,0x31,0xa2,0x8b,},{0x4e,0x81,0x93,0x06,0x1c,0x9d,0x65,0xa8,0x2b,0xcb,0x25,0xda,0x08,0x9b,0x4a,0x80,0xba,0x41,0xb3,0xdd,0x2f,0x8e,0xd1,0xdc,0x81,0xe1,0xcf,0xd0,0x3c,0x84,0x91,0x15,},{0x66,0x02,0x42,0xc1,0xdc,0xf3,0x29,0x13,0x69,0xc6,0x5c,0x9d,0x7f,0x89,0x87,0x2e,0xab,0x48,0x22,0x00,0xe3,0x44,0xb2,0x96,0xe3,0x36,0xa0,0xa2,0xe6,0x31,0xfa,0x79,0x60,0x24,0xb6,0xe1,0x11,0x9c,0x27,0xd5,0x22,0x64,0xa4,0x98,0x15,0xdd,0x78,0x19,0x27,0xa7,0xdf,0x46,0x7e,0x88,0xb8,0x01,0xe6,0x84,0xfc,0x60,0x22,0x96,0x25,0x0e,},"\x2f\x11\xf4\x0b\x2a\x19\xf6\x40\xc0\x04\x4c\x7b\x13\x96\x80\xc3\xc3\xb6\x9f\x00\xff\x9f\x6a\x41\x86\xfd\x7d\xed\x56\x9c\x1d\x8c\x57\x20\xf1\x9d\xd3\x5c\x78\x16\xd0\x8a\x94\xc0\x82\x04\xe4\x76\x43\xe2\x64\xd4\x25\xe2\x1c\xef\xb8\x31\x29\xc9\x09\xa3\xd7\x8c\xaf\x72\xc4\x6b\xf1\xa7\x29\x76\x5e\xf4\xb8\xca\x80\x3f\xda\xf8\x05\x2f\xfc\x6c\xc4\xa6\xb5\x79\xa1\x60\xb7\x03\xb1\x53\x55\xc6\xfc\xd3\xb9\xa2\xec\xbc\x26\x7e\x60\xdd\x59\xf6\xa2\xb1\x94\x20\xe5\x57\x27\xa8\x0b\x0b\xb6\x41\x67\xc8\x3b\xa0\xc8\x05\xde\xed\x49\x1d\x93\xe7\x23\xf3\xb4\x32\x63\xd1\x74\x20\xb8\x5b\xe8\x6c\x16\x5c\x55\x27\x79\xdb\x96\x0e\x0a\xa9\xeb\x4d\x9f\x3a\x16\x4a\x5a\x21\xfa\xb3\xf5\x09\xa8\xf0\x19\x9a\x69\x43\xc4\xb2\x23\xcf\x9d\xac\xa7\xe1\x10\xe0\x56\xa8\x1d\x9c\xe0\xe0\xc0\x2a\xc2\x65\xee\xac\x05\xec\xd8\x44\x48\x46\x8a\x4d\x12\x2b\x87\xa3\xe0\x4c\x28\x37\xe4\x3d\x21\x27\x04\xfd\x41\xe7\xf3\xd1\x98\xa2\xe7\x6b\xec\xa0\xe7\x02\x9c\x43\x2a\x06\x54\xec\xd4\x4f\x98\x4c\x5d\xf0\x67\x41\x96\x4d\x83\x72\xc8\x6e\x16\x2a\x8c\x54\x18\x84\x9b\x41\xe5\x71\xfe\xb8\x3e\xb4\x2f\xbb\xcd\xdb\x8a\x08\x21\x43\x90\x9e\xaa\x50\x12\xb9\x79\x93\x1d\xc7\xe3\xcc\xcb\x44\xc7\x91\xe0\x4b\x80\x65\xee\x63\xf0\x56\x1d\xa1\xbb\xf3\x7b\xf6\x50\x34\x77\x87\x9c\xfb\xaf\x6d\x9d\x7d\x9a\x74\x75\x55\x3f\x53\x53\x5f\x84\x7a\x76\xdc\x3b\x2b\x7a\x3d\x1d\x47\x0b\xbe\x17\x12\x4a\x88\xe0\x3f\xe9\x94\xba\x10\xc2\x42\x21\xe3\x9e\x3d\x0f\xf5\x3c\x79\xe2\xfa\xaf\xa1\x90\x12\xd5\xef\x19\x2b\xc6\xd5\x26\x0b\x66\xf9\x97\xb6\x44\xcf\x48\xd9\x9f\x38\x99\xd7\xc4\x85\xe6\x84\xaa\x1e\x6e\x30\x85\x5c\xf7\x5c\x2d\x80\xc7\xa3\xee\x43\x54\xfe\x13\xc6\x76\x09\x1c\x86\x67\x37\x3d\x30\xe6\x0f\xf8\xe0\x9f\xed\xef\x17\x5a\x1a\x87\x39\x5f\xef\xa0\x72\x2b\xf6\xc0\x1c\x65\x55\xcf\xf0\x68\x89\x2a\xfe\x94\x86\xcb\x1f\xcc\x5f\xb6\x64\x1e\x82\xd8\x70\x79\xba\x5d\x7a\x9c\x13\x93\x55\xd6\xc1\x4c\x50\x7d\xbd\x59\x47\x24\xb5\x53\x51\x10\x09\x65\xbe\x9e\x5d\xbf\xa7\x70\x88\x78\xc4\xb2\x9f\x4d\x54\xc2\x17\x74\x6e\x32\x6a\xb2\xa5\x4f\x99\xb8\x81\xd7\xda\x5b\x11\xed\xb0\x8a\x6d\x79\xd8\x85\x69\x1b\x1f\x70\x85\x51\x73\x10\xb3\x09\xcf\x9b\x1b\x71\x4a\xab\xc5\xc1\x7a\x50\x9b\x14\x0b\x89\xb3\xf9\xdc\xee\x50\xca\xb4\x41\xbf\x5a\xd3\xbb\xc2\x99\x90\xf6\x27\x40\x61\x70\xa7\xa1\x0f\x2d\x47\xdf\xc9\x25\x61\x54\xf9\x62\x30\x8e\x76\x9a\x2a\xb1\xb2\xa0\x0e\x27\xe3\x27\xf0\xd1\xfa\x16\x4d\x1e\x38\xea\xd5\xce\xaa\xe2\x38\xba\x52\x6f\x54\xb8\x1b\x45\xde\xa6\xc8\x97\x41\x86\xb1\xb6\x72\x5f\xa4\xc8\x3e\x62\xf3\xe2\x54\xf7\x29\x87\x1b\xda\x4d\xc4\x44\xbc\xe7\x8f\x09\x03\xfa\x31\x8e\xaa\xc8\x22\xa9\x55\x32\xab\x01\x9e\x9c\xfc\x56\x19\xe2\xc2\x06\x7f\x25\x8f\x43\x75\xd2\xe0\x22\x2e\xa5\xbf\x96\xa2\x53\xa2\xa3\xfa\x9e\xea\x02\xc3\xee\xcc\xb0\x28\xc7\x6b\xc6\x0d\x38\x29\x8b\x95\xb9\xaf\xe6\x60\x31\xb1\xa2\xa2\x61\x52\xfd\xaa\x7e\xf4\xf8\x37\xab\xb5\x11\x85\xdf\x8b\x2e\xf8\x5a\xd2\xc9\xbe\x6d\xfb\xa7\x5e\x37\xdc\x7d\x12\xe1\x78\x7f\xc5\x5f\x86\x6f\xd0\x66\xf1\x22\x91\xdf\xf1\x97\x6a\xfc\x10\xda\x91\x31\x01\xe7\x04\x95\xd8\x78\x33\x48\xd6\x11\xb0\x11\xec\x67\x1c\x0d\xa7\x37\xbf\x96\x2c\xdc\xc9\xe4\xa8\x00\xb5\x13\x93\x5a\x56\xd0\x84\xea\x64\xa7\xd4\xe8\xe9\x9e\xe9\x44\x0a\x73\x61\x32\xe4\x2c\x90\x95\x03\xc2\x22\x4a\x14\x1b\x25\xce"}, -{{0x39,0x3b,0x76,0x94,0x82,0x37,0x5b,0x82,0x14,0x27,0xa6,0x6d,0x16,0xe4,0xf5,0x51,0x85,0xb7,0xa3,0xb7,0x33,0x8f,0x1a,0x06,0xf6,0x7c,0xdf,0xa7,0xe3,0x5c,0x54,0x1c,},{0x84,0xaf,0xd7,0x06,0x78,0xff,0xa8,0x5a,0x9f,0x65,0x74,0xcb,0xcf,0xe3,0xb1,0x5d,0x04,0xa9,0xfd,0x15,0x01,0x6f,0xf8,0x55,0x0a,0x98,0x7c,0x4b,0x95,0x1c,0x71,0x22,},{0x31,0xf9,0x8c,0x0a,0x08,0xfd,0xa8,0xe7,0x35,0xb5,0x73,0x66,0xaa,0x1b,0x83,0xb9,0x3d,0xae,0x63,0xb5,0x81,0x0c,0x82,0x1d,0x99,0xcb,0x39,0xdf,0x52,0x1f,0xea,0xc0,0x7f,0x3c,0x41,0x0b,0x27,0xba,0x33,0x07,0x75,0x7d,0x60,0x49,0xf2,0x24,0x54,0xfb,0x6d,0xe9,0xe2,0xc3,0xc2,0x43,0x8d,0x68,0x31,0x90,0x97,0xd1,0x12,0xcf,0xdb,0x07,},"\x8a\xe8\x05\x3e\x03\xbe\xbe\xae\x54\x40\x43\xb8\x41\x4b\x38\x53\x64\xad\xd1\x67\x37\x37\xcf\x8a\xb2\x01\x93\xd4\xaa\xbc\x8a\x78\xe1\xd6\x9b\x9c\x7e\x52\x72\x9e\x69\x30\x78\x06\xe9\x27\xce\x38\x07\xb0\x7c\x68\xc8\x33\xc4\xfc\xf1\x6d\xb1\x5e\x7d\xce\x60\x4d\x17\x98\x91\x5f\xd4\x21\x16\x89\xb4\x86\x46\x42\x50\x2d\x38\xe9\x1b\x19\x97\xb7\x18\x23\x31\x8b\x69\xab\xe5\xbe\xd6\xf5\xe3\x01\x5b\xfb\x22\xdf\x30\xdb\x37\x1f\x22\x60\xc5\xc2\x2e\xba\x60\xdf\x39\xb3\xed\xd3\xc4\xd7\xa1\xe1\x11\xcd\x9b\x8a\xa4\x6f\x67\xbd\x0c\xf3\xa7\x17\xaf\x06\xec\x0c\xe5\x67\x02\x8e\x06\xe4\x79\x79\x34\xad\x69\xb1\xf5\xbe\x44\x0f\xf3\x7a\x8a\x03\x4b\x15\x33\xfa\x94\x64\x24\xac\x59\x54\x00\xad\x27\xd3\xbe\x76\xdc\x89\xba\x9d\x6c\x49\x93\x9a\x09\xf2\xe4\x01\xc8\xf2\x0f\x7f\x7b\x4b\x9e\x63\xb9\xd5\x52\x01\x53\x4a\xb4\xcc\x7b\xe8\x85\xf0\x43\x2a\x2c\x66\x73\xd2\xe7\x65\x19\x4d\xff\xd9\xb6\x09\x6d\xd2\xb2\x84\x39\x18\x75\x09\x59\xa8\xdd\xe4\xa3\xab\x40\x7e\xb2\xf7\xe1\xa4\x9c\x25\x97\xe3\x08\x05\xf8\x48\x0d\xd0\xcc\x82\x72\xa3\x20\xc0\x0a\xa2\xb2\x10\xf5\x76\xe4\x25\x77\xd3\xaa\x41\x97\x03\x69\x7c\xa4\x06\xd4\x3a\x1a\x4f\x99\xb0\x73\x36\x64\xf6\xd6\xb2\x40\x3c\xba\x1b\xdc\xc5\x1f\x54\x1c\xf2\x42\x36\x07\x05\x70\x54\x07\x55\xc7\xa8\x63\x1f\xcc\x2f\x18\x93\x8f\xa1\x1b\xc2\x91\x15\x5b\x39\xd7\xa7\x62\xa1\xff\x4d\xca\x97\xb4\x48\xf7\x0e\x2d\x3d\xe4\x47\xcb\x08\xf9\x18\xea\x20\xcb\x43\x3f\xa1\x15\xe3\x08\x80\xc9\x6c\x8c\xf5\xf0\xeb\xbc\xf4\x82\x30\x9d\xb6\xdc\x1f\xb6\x4e\x17\xc0\x4d\x7c\xdf\x7a\x90\xf4\x01\x4d\x15\xae\x76\x96\xb4\x44\x23\xb0\xba\x08\x4e\xed\x4d\x3f\xb2\x8c\x1e\xfb\x39\x82\x8a\xca\x2f\x40\xca\x6d\xf3\x42\xc2\x0e\x95\xf8\x00\x6b\x27\x67\xa8\x3f\x50\xc3\x1f\xcc\x15\x81\xa0\x97\x53\xe7\x82\x91\xf0\xd9\x93\x1d\x99\x2a\xd3\x60\x44\x73\xce\xb8\x85\xec\xbe\x78\x57\xcc\x52\xad\x55\x85\x33\x4d\x14\x85\xd0\x22\xe1\x06\xb7\x1c\x29\xbd\xfc\xf2\x3e\xe8\xa4\x75\xdf\x2c\x09\x05\x32\x35\x6a\x6f\xfc\x02\x23\x23\x17\x98\x8a\x2c\xbc\xfb\xc2\xa3\x6b\x4b\x48\x3c\xb4\x45\x10\xe8\x55\x99\xb6\x12\x59\x6b\x62\x65\x72\xb0\x99\x6d\x8a\x61\xc0\xee\x3e\xff\xf1\xf7\xc7\x1c\x05\xfb\x5a\x8d\x8c\x5d\x09\xd9\x24\xeb\xaa\xc8\x80\x04\x51\xc9\xdb\x24\x56\x71\x0a\x27\x9d\xfe\x2d\x22\xf6\xae\xa9\xde\x31\x80\x1d\xc7\x42\x53\x43\x62\xb0\xe8\x10\xe9\x9e\x84\x1d\xbb\x7f\x0c\xf9\xaf\x1a\xef\x54\x2a\x52\xc7\x76\xcc\x51\xf2\x87\x36\x8f\xbe\x6a\xd6\x51\xfa\xd5\x78\x7e\xf7\x7c\x73\x53\x5f\x3d\xfb\x36\x18\xcc\x8f\x0d\xbb\x54\x9d\xdc\xa9\xb9\xbf\x91\x13\x5a\x34\x56\x00\x1a\x46\x21\x5a\xde\x38\x8e\x7c\xeb\x9f\xcd\xfd\x0d\x2d\x0a\x03\x56\xaf\xbe\x2c\xec\x1c\x2e\x78\xb4\xd9\x98\xd4\x55\x4f\x46\x21\xf1\x15\x1d\xd3\xff\xd3\xba\x4c\x0b\xc8\x52\xf3\x11\x75\x8c\x5d\xca\x42\x5d\x18\xba\x15\xa8\xd6\x7c\xa4\x01\xd0\xe6\xcf\x28\x0c\xb8\x83\x84\xa2\xda\xd4\x9f\xae\x39\xba\x2a\x77\xb4\x67\xb3\x23\x8a\xa2\x8c\xfd\x13\x7e\x5c\x5c\x0f\xf9\x00\x0f\x8b\x06\xa2\x19\x2e\x16\x29\x20\x69\x22\x65\xdb\x24\xab\x6a\xed\xe5\x35\xe3\x1c\x20\x93\xbe\x57\xeb\xf8\x80\x5d\xf1\x78\x89\x14\xf3\xa8\x84\xf8\x84\x17\x90\x15\x80\x8d\xb4\xd3\x02\x0f\x3e\x78\xbc\x34\x28\x5d\x23\x37\x62\xe8\x99\xeb\xff\x28\x42\x82\x15\xe2\x44\x40\x4d\xe2\x91\x72\x8f\xbf\x41\x24\xce\x5b\x24\x35\x26\x0a\x8e\x34\x11\x80\x07\x5a\x56\x51\xe6"}, -{{0x26,0xcb,0xc2,0x51,0x0e,0xe6,0xea,0x39,0x0a,0x2c,0xb9,0x48,0xa0,0x15,0xd1,0x31,0xab,0xf4,0xc0,0x95,0x49,0x15,0x62,0x0b,0x78,0x16,0xae,0xcf,0x4e,0x11,0xda,0x6d,},{0x14,0x5e,0x8d,0xd2,0x2b,0x44,0x00,0x28,0x9d,0xaf,0xb6,0x26,0xd9,0x5a,0x94,0xc2,0xf3,0xb6,0x9c,0x65,0x19,0x77,0x17,0xcb,0xdc,0xd8,0x50,0x98,0xc5,0x49,0x21,0x07,},{0x67,0x10,0xd0,0xdd,0x00,0x54,0x5b,0x44,0x4c,0xf7,0x14,0xb7,0x91,0x44,0xfe,0x79,0xf3,0x8c,0xb1,0xc0,0xf5,0xb7,0x42,0x48,0xd4,0xf0,0x1f,0xe3,0x60,0x11,0x7a,0x26,0xff,0xed,0x4a,0x3b,0xf2,0x13,0x23,0xb2,0x8a,0x39,0x3a,0xe9,0xde,0xe0,0x7d,0x69,0xe5,0x83,0xe3,0x16,0xc6,0xa5,0x73,0xd3,0x7c,0x64,0x4a,0x8d,0x62,0xc4,0x05,0x06,},"\x9c\xeb\xe2\x4b\x4f\x8a\xde\x86\x43\x0e\x27\x9a\x3c\x43\x3e\x4a\xe1\x7e\x00\x88\x52\xa2\x4f\x08\x69\x0c\xbc\x3d\x75\xe3\xb7\xf2\x00\xda\x89\x7c\x25\xf7\x48\x3b\x37\x63\x7d\x4b\xc1\x10\x08\xd9\x22\x4c\xd5\x81\xfb\xc0\x38\xad\xad\xa0\x2d\x27\x1e\xd2\xa5\xd2\x85\xd8\x43\xa0\xf8\xb7\x9e\x37\x94\x5d\xc3\x5b\xc2\x64\xbe\xcd\x80\x43\x07\xe1\xd4\x42\x18\xa6\x43\xe4\xb5\x9a\x93\x11\xde\x98\x5d\x24\xb4\xc2\x6f\xb1\x46\x03\xbe\x5d\xba\x18\x39\xee\x0c\x8d\x2e\xde\x6c\xb5\x0a\xf6\x7c\x80\x45\x19\x03\x7b\x1b\x16\x63\x31\x8c\xfc\x6e\x75\xd0\xf0\x51\xdb\xb5\xd3\xea\xf3\xaa\xd1\xf7\x8e\xf0\xcf\xf4\x8d\x5c\x55\xb2\xfd\x25\xdb\x15\x39\xd0\xf0\x2d\xae\x9f\x25\x14\x8a\x8d\x33\x8b\x97\x87\x9b\xbd\x39\xdf\x96\x1a\xa2\xc3\x96\x31\x5a\x2a\x86\xcc\x78\x35\x81\xe6\x7e\xa8\x44\xac\xfe\x86\x45\x42\x8a\x27\xb8\xd3\x2e\xa3\x06\x4e\x3b\xf6\x2d\xcf\x58\x01\x0e\xc4\x34\x88\x62\xfa\xc2\x5e\x3d\x9f\xcd\x4e\x5d\x65\xbe\x59\x90\x5d\x81\x6d\xfb\x96\x49\x92\xba\x7a\xce\xef\x8c\x20\x75\xa3\x12\xe5\xff\xc4\xf9\x53\x0e\xa2\x0f\x77\xf9\x3e\x81\xcf\x8a\x01\x9d\xc3\x94\x56\x34\x36\x4b\xab\xf7\x97\x72\x04\x5a\x0d\xba\xa7\x7c\x47\xa2\x2b\x77\x22\x3b\x70\x4d\xeb\xd2\xd0\x03\xf6\xa5\xc7\xbf\x6b\x19\xcd\x2c\x49\xb6\x14\xfd\x4d\x47\xfd\x25\x1f\xe6\x22\xcb\x98\x17\x85\xc1\x46\xbd\xb7\xc1\xd2\xea\x02\xb1\x16\x92\x3b\xf9\x8a\x1a\xfb\xb7\x85\x8a\xdf\x2d\xf9\x38\xa7\x90\xec\x1f\x90\x74\xad\xb8\xd1\xaf\xb5\x63\x3f\xa9\x61\xa8\x47\x64\x01\x0d\x3b\xde\xd1\xc0\x33\xd2\x5a\xbd\xb4\xb0\x0f\xb0\x5e\xd7\x64\x0f\xae\x61\x87\x9d\xf8\x8f\x0b\x09\xe3\xab\xd0\x57\xb9\xa5\x21\x08\xa9\xbc\x98\x5f\xb7\x3a\x5f\x29\xd8\x4d\x1c\xa6\x92\x1b\x62\xf1\xb7\x03\xc7\xee\xb4\x81\x5d\x9d\xd6\xd0\x66\x73\x8d\xb1\x18\xba\xf6\x1b\x04\x22\xf3\x88\xf1\xbf\xc9\xe3\xa9\xbe\xd8\x3a\x1a\x72\x7d\xcc\x26\x6a\x99\x88\x36\x48\x46\x80\x7f\x4d\x55\x18\xbc\x2e\xdd\x0e\xcb\x34\x13\xc2\x6f\xd0\xc7\x9b\x75\xd8\xcb\x5b\xcd\x85\xc0\x6f\xcc\xea\x4d\x03\xfb\x89\x88\xdf\xf3\xed\x0c\xc9\xdb\xae\x78\xd6\xae\x8d\x5f\xc4\x02\x46\x17\xa2\x3f\x52\xbd\x61\x53\x85\xd4\xee\xe0\x8f\x91\x34\xeb\x3b\x25\x0c\x8f\x82\x2b\x47\xd9\x1e\x8c\x4d\x4c\x29\x29\x80\x16\xe6\xfc\x81\xf1\xf1\x09\x92\x53\xd7\x94\x5e\x07\x98\x95\x5d\xa0\xdd\xe1\x4e\xbb\x93\x4e\xcf\xae\xea\xba\xe8\x78\x83\xe1\xcc\x39\x80\x67\x40\x0f\xe4\x62\xa2\xc4\xe9\xf2\x32\xdb\x5c\xdd\x61\xeb\xa9\x49\x18\x8c\xf0\x1b\x23\x8b\xe7\xad\xa9\x38\xf0\x02\xdc\x3a\xe3\x1f\xdf\xd4\x25\xc8\xd4\x6e\xa0\x32\x32\x3a\xaf\x20\xdd\x3d\xe2\x50\x7d\x36\xbb\x45\xfb\xb9\x1c\x40\x96\x9a\x9e\x5d\xa2\x0f\x7f\x93\x6b\x0f\x4b\x13\x7b\x62\xfe\x2b\xa3\xa6\x67\xbc\x03\x62\xd9\x3f\xc5\x0d\x3f\x22\x95\xe1\x67\xfc\xba\xb0\xfb\x3a\x39\xb7\xcb\x02\x4b\x57\x8f\x94\x90\xf7\x34\xb2\x8c\x9c\xcf\x71\x92\xf1\x83\x94\x7d\x5a\x51\x3e\xfa\x49\x16\xe4\xd8\x2b\x2a\xb4\xba\x7e\xc2\xff\xba\x21\x3c\xe8\x2a\xd6\xed\x3b\x10\xe4\x85\x53\xe7\x33\xc9\x40\xaa\x9b\x9c\xe7\x13\x37\xc6\xc2\x80\x5d\xfb\x8d\xd6\x61\x8b\x6d\x40\x90\xa3\xd6\xcc\x96\x3e\xce\xa2\x6d\x1c\xdc\x2b\xf5\xac\x99\x9c\x11\x27\x61\x68\xa9\x31\xd8\x16\x46\x9d\x79\x08\x3c\x24\x08\x1a\x50\xdc\xbd\x22\x27\x52\x38\x52\x67\xce\x1b\xfc\x1d\xb7\x6b\x15\x54\xad\x57\xe3\x47\x52\xb7\xf8\x98\x31\x47\xc1\x16\xd4\xa3\xfa\xe6\xf6\xd5\x7e\x65\x4f\xed\xd7\x37\x8d\x2b\x49\x89\xea"}, -{{0xb1,0xf5,0x9e,0x3c,0x23,0x80,0xd7,0xaa,0x41,0x4d,0x0b,0xf9,0x08,0x93,0xa3,0x8d,0xdd,0xfc,0x29,0x38,0x59,0x30,0x3d,0x16,0xf0,0x0d,0x9e,0xae,0x6c,0xb3,0x45,0x0e,},{0x84,0xe3,0xf5,0xf7,0x2f,0x19,0x09,0x5b,0x0f,0x53,0x38,0x48,0xa5,0xa9,0x1d,0x0f,0x07,0x43,0xb8,0xe3,0xa3,0xe2,0xf5,0x2f,0xcb,0xd7,0xeb,0xe7,0xc5,0xb5,0xa9,0x98,},{0x60,0xaf,0xc1,0xe9,0x91,0xfd,0xd2,0x7c,0xc4,0x72,0xb9,0xac,0xc9,0xd4,0x05,0xb4,0xd2,0xb9,0x13,0x08,0x92,0x90,0xb3,0x11,0xc4,0xfa,0x89,0x1a,0xe2,0xee,0xa0,0x56,0x71,0xfd,0xe7,0xa0,0xef,0x86,0x55,0x7b,0xd8,0x67,0xd1,0xc0,0xb7,0x47,0xca,0xf3,0x52,0x29,0xd6,0xef,0x52,0x8f,0xe3,0xe0,0xd0,0xbc,0xf6,0x30,0x38,0x0e,0xa9,0x0e,},"\xc6\x17\x4c\x9a\xd3\x68\x5d\xd6\x48\x63\x60\x17\x83\x7b\x8d\x99\x22\x00\x31\x9e\x9a\x5a\x0d\x26\xd9\x4d\x2d\xa7\x5e\x2c\x3a\xff\x46\xf4\x2d\x7b\x3a\xba\x47\x2b\x7f\x86\x0b\x0f\xe1\xf6\x95\x52\x97\x31\xfd\xc8\xcf\x0d\xa7\x05\xd1\xd0\x9a\xca\xd0\x4f\x01\x08\x37\xec\xef\x41\x9d\x57\xe9\xea\x6c\xac\xf1\x68\xc5\x21\x56\x96\xf4\x71\xf3\xca\xa8\x97\x60\x7c\x62\x9d\x44\x3d\xe0\x99\xd3\x17\x53\xc2\x46\x77\xd8\xd7\x5f\x4b\xf1\x72\x46\x81\x8b\x58\xad\xc0\x42\x4b\x76\x2a\x19\x1e\xf3\x9a\x70\x76\xa5\xad\x12\x61\x4c\xf5\x4c\x47\xeb\x09\x08\xbb\x86\x65\x18\xc5\xfa\xc1\xca\x2d\x2e\x5b\x65\x75\x20\xa2\xb3\x69\x5c\x6f\xb3\x60\xf1\x6f\x4a\xb3\x57\x99\x8e\x4c\x0e\x97\x23\x1d\x6f\x89\xc9\x68\xdc\x29\xec\xc1\xaa\x91\xfa\x0d\x75\x43\xb5\xd2\x24\x7b\x0d\x85\xe4\x87\x43\xab\x7c\xc8\x15\xcf\xda\xa8\x2b\xf6\x8c\xa6\xd3\xe2\x25\x0b\xfd\xa2\x70\x24\xd6\x1b\x47\x4c\x6b\x81\x54\xac\x8d\x1b\x5a\x36\x20\x97\x82\x51\x5c\x16\x46\x68\x0d\x37\x06\x9b\x8b\x44\x12\xf9\x51\xb0\x25\xa4\xd5\x43\x62\x5d\xd0\x22\x90\xbf\x03\xc6\x73\x46\x13\xf9\x9b\x7a\x4c\x3a\xf5\xc5\xf9\xe9\xac\x34\x74\x46\x5e\x64\x84\x23\x01\x8d\x40\xa6\xad\xbe\x88\xa3\x30\x1d\x3d\x25\x9b\x04\xee\x44\xcc\x05\x62\xee\x0d\xed\x4f\x5e\x26\xad\x97\x7a\xb5\x63\x1f\x85\x76\x8d\xbc\xe5\x3f\x61\x6c\x02\x9a\x8b\x8f\x93\x3e\x2a\x92\x64\xb1\xc8\x1f\x51\x7e\x9f\xf5\x8a\xb9\xf4\x5a\x23\xee\xed\x42\x04\x35\x8f\x8f\xff\x0c\x8f\x97\x5e\xf1\xdf\xa5\x77\x6a\x5f\x77\x93\xba\xe2\xf2\x81\xd7\xb0\xcb\xef\x24\x0b\x3f\xc6\xbe\x05\x88\x21\xea\x2b\x80\x0f\xff\xe5\x5a\x7d\xe0\xaf\xc9\x3e\xde\x9c\x60\xc8\xde\x00\x5a\xbb\x9a\x2c\x88\xf4\xe6\x1e\x8d\xeb\x31\x70\xf1\x07\x8a\x36\xe2\xd8\xf2\xa5\x82\x39\xbd\xee\x49\x6e\x90\xd1\x37\xd2\x11\x0f\x0a\xd8\x57\xa8\x8b\x35\x27\x66\x4f\x78\x19\x39\xe0\xb2\xf7\x66\x34\xff\x9f\x6c\x57\xe1\xc4\x3f\x58\x24\x31\x71\xcd\x86\x2e\xf4\x28\x45\x76\x17\x2a\xf1\xf6\xc3\xbd\x37\xd5\xd7\x4b\x28\xa7\xa9\x86\x98\xbd\x74\xe5\x7b\xbc\x14\x2e\x67\xf7\x03\xf9\xd6\x2c\xde\x76\x1a\x02\x26\x8f\xec\xb3\x43\xfc\x01\x41\x88\x36\x41\x4f\x12\x22\xca\x24\xbc\xdd\x69\xd0\x05\x90\x1d\xa2\xa0\xf9\x44\x65\xe4\xd4\xba\x68\x89\x88\x16\xbf\x7e\x3e\x4b\xb7\x9c\x8c\xa5\x99\x7f\xba\x9a\x8d\xf8\x4f\xaa\x2d\x24\xb0\x44\xc4\xea\x61\x02\x9a\x46\xcb\xa7\x03\x42\x1e\x36\x1d\xfa\x52\xca\xaf\xf3\xbb\xaa\xb7\xfd\x75\x3f\x28\x56\xd7\xc0\x83\xae\xb9\x76\x8d\xa1\x1d\x82\x1e\x2d\x30\x9f\x7a\x73\x5c\x39\x96\x92\xda\xc2\xf2\x62\x84\x6b\x89\x1b\xf6\x46\x1a\xf2\x3c\x8c\x7c\xe1\xd4\xd9\x03\x2c\x3c\x14\x0f\x73\x9e\x55\x84\xc3\x6f\x05\xea\xf4\x34\x9f\xf4\x54\x5f\x28\x3a\x4e\x0f\xea\x49\x43\x0a\x1b\x18\x0d\x08\x71\xe3\x74\x2b\x88\xcc\xb5\x91\x12\x4f\xc4\x27\xed\x67\x3b\x5f\x27\xb0\xb0\xa6\xf5\x4a\xf2\x2b\xa4\xa6\xd1\xc6\xc1\xdb\x2a\x1f\xca\xa6\xd8\xa0\x30\x8b\x77\xef\x2d\x0c\x61\xbb\xf5\x1b\x95\xf1\xe8\xb6\xab\xc5\x04\x1d\x97\xb6\xb6\xf1\xb5\x69\xb3\xf6\x3c\xec\x05\xcb\x56\x7a\xae\xa1\x06\x72\x70\x96\xee\x8a\x9e\xa8\x7b\x88\x04\x90\x1f\x7e\x88\xa7\x40\x9c\x66\xf1\x52\xde\x9d\xbf\xcb\xe3\x19\x52\xe6\xfd\x83\xb2\x87\x7a\x77\x5f\xae\x42\x5b\x38\x51\xe0\xef\xf8\x79\x2f\xfb\x38\x48\xf8\x4a\x65\xcc\x31\x72\x53\xb2\x72\x47\x5e\x71\x7e\x49\xe9\xc6\xff\x6b\x78\x59\xd1\x1b\xba\x7c\x44\x28\xc8\x2d\x17\x89\xe0\xdc\xa5\xbc\xad\xca\x2f\xdb\x25\x9e\x98"}, -{{0xdb,0x46,0x1b,0x9f,0x70,0x7e,0xb2,0xcd,0x77,0x48,0xc4,0x4c,0x99,0x56,0x2f,0x13,0x02,0x39,0x74,0x89,0x35,0x3d,0xf5,0xf3,0x03,0x79,0x7f,0xe0,0xd0,0xb5,0x8d,0xe1,},{0x63,0x51,0x16,0xda,0x8b,0xa5,0xa3,0x6a,0x37,0x77,0x28,0xe2,0x86,0x18,0xe7,0x5c,0x55,0x92,0xae,0xcc,0x18,0xe3,0x40,0x11,0xc4,0xc4,0x25,0x91,0x97,0x0b,0x73,0x66,},{0xdd,0x04,0x9c,0xa7,0x9b,0xeb,0x9e,0xac,0x32,0x5a,0xcf,0x44,0x67,0x2f,0xf5,0x78,0xa9,0x68,0x50,0x2f,0xe1,0xbc,0xf5,0xea,0x19,0xd5,0x2c,0x0f,0x67,0x78,0xc7,0xf1,0xc7,0xbb,0xf7,0x42,0x74,0x79,0x07,0x78,0x6e,0x60,0x81,0x23,0x91,0x1a,0x92,0x07,0x78,0xd2,0xf9,0x59,0x6f,0xe2,0x9b,0xe7,0xcc,0x28,0xfd,0x00,0x9d,0x7c,0x44,0x0e,},"\x1a\x2a\xc8\xc1\xb9\xea\x09\x9b\x83\x1a\x68\x12\xd2\xb4\x26\x13\x09\x05\x8e\xa5\x88\x3d\x70\xb1\xc6\x07\xb9\xcd\x3f\xdf\xdb\x86\xe7\x99\x02\xb0\xfe\x89\xe8\x0e\xa7\xc4\x78\x20\x76\x74\xb2\xd8\x03\xb0\xb9\xca\x14\x7f\xfe\x62\xe5\x94\xf5\x06\xc7\x96\xd6\x89\x97\xce\x48\x2b\x51\xa4\x6e\x49\xb4\xa5\xd8\x58\xcd\xea\xe2\xc6\xec\x9b\x69\x41\x98\xe6\x82\x2f\x0e\x33\xed\x57\xbe\xdb\x03\x35\xc7\x89\x0a\x72\xa7\xee\x3c\x23\x82\x3b\xe7\x9b\x7f\x94\x71\xe0\x33\xc7\x9a\xee\xd5\x2e\x57\x60\xfb\x0c\xcb\xb9\xd3\x8f\xde\xd8\xb4\x73\x83\xc1\x91\x03\xce\x44\x70\x58\x34\xc5\x9d\xdd\x86\xf7\x03\x39\x48\x61\x2d\x66\x62\xf5\x16\xce\x4e\x39\x9f\xf2\x03\x63\xcc\x72\x81\xa6\x9b\x2d\x5c\x30\x7b\x10\xb7\x04\x15\x01\x84\xec\xe3\x2f\x39\x0d\x77\x2c\xcf\xa7\x84\x83\xbb\x77\xa9\xfb\xa8\x44\x25\x36\x69\x84\x17\x1c\xc2\xbb\x60\xb0\xec\x6c\x62\x8d\x4e\x90\x30\x74\x6d\xac\x1c\xab\xca\x60\xf0\x56\x83\x81\x33\x46\xa1\xa5\xbc\x14\x72\x75\x49\x79\x5c\x1c\x92\x68\x69\xe1\xaa\x25\x09\x3d\x59\x1b\x43\xe0\x86\xe4\x3a\x04\xd1\x70\xd9\x42\xc4\x16\x5e\x1c\x5c\xe7\x6c\x3e\x64\x97\x3d\x91\x36\xf9\x32\x5b\xee\x82\x16\x82\xf1\x04\x3e\x95\x1b\x02\x76\x7f\x3f\xb4\x58\xd0\x24\x49\xad\xd3\xe8\xa6\x6e\x51\x6f\xdb\x1e\xd5\x80\xe0\x56\xe0\xf7\x8e\xe3\x3f\xd9\xee\x32\x80\x91\x2f\xae\x07\xfe\x1e\xa0\x25\x27\xcd\x00\x1d\x6f\x6f\x2f\x89\xee\x64\x9f\x51\x74\x14\xd5\x6f\x57\x35\x9a\x84\x68\x91\xf0\x22\x2c\x32\x1d\x7e\x70\x81\x79\x95\xa8\xcd\x8e\x94\x76\x0b\x6e\x74\x83\x2b\xab\x68\xd5\x5b\xc4\x64\x18\x84\x22\x1f\xd2\x9f\x12\x2d\x87\xa9\xa8\x68\xb6\xa6\x06\x0c\x87\xb2\x38\x2c\xf7\xbb\xdd\xa4\xcd\x6a\xaa\x1b\xbc\x8e\x6d\x63\x4a\xb5\x80\xc8\x65\xf5\xad\xd6\xa1\xd5\x4e\x61\xa6\x07\xdc\x2c\x37\xb0\x8a\x8c\xba\x6e\x61\x0c\x12\xcf\xeb\xef\x9c\x98\x9e\xef\x3b\x78\x2a\xcb\xd1\xbc\xec\x5f\x04\xe8\x35\xca\x10\x12\x98\xb5\xe9\xbd\xd8\x81\x3a\x71\xb0\xd4\x69\xfc\xf1\x27\x27\xd3\xde\x1c\x3f\x97\xdd\xbc\x6a\xb2\x65\x84\x40\xdd\x64\x21\x01\x9b\xc6\x8f\x35\x6d\x6f\x25\x53\x68\x65\x85\x1d\x92\xd9\x0f\xe9\x96\x9c\x3b\x7c\x35\xa2\xe8\x8c\xe1\x53\x47\x6e\xc3\x97\x3a\xf9\x35\x9f\x16\x77\xa4\xca\xf1\xcc\x48\x1c\x71\xbd\x90\x22\x8f\xf5\xfc\x6d\xd8\x3b\x8a\x69\x9f\xfe\x51\x49\x29\xf5\xc9\x5c\xb4\xf0\x4b\x00\xdd\x18\xa2\x87\x2c\x41\x86\x8d\x3b\xeb\x76\x49\x8d\xdc\x92\x34\xb6\x3f\x59\x9d\x70\x71\x80\x1d\xb2\xc2\x87\x8f\x7b\xef\x4f\xfd\xdd\x81\x32\x26\xf0\x6d\xb8\x4e\xb3\x02\x17\xa7\x18\x30\x82\xe3\xc1\x24\x2b\xb6\xd0\x1c\xd3\xa6\xce\x27\xbf\xf1\x6b\xfb\xfd\xd7\x5b\x7e\x51\x04\x31\x2c\x49\xc4\x3a\xad\xfc\xd5\xb4\xed\xba\x0f\xf5\x0d\x28\x90\xca\x3c\xd9\xcc\xa3\x3e\x4f\xc6\x94\xc0\x57\xc4\x7e\xbe\x1c\x20\xa4\xad\x11\x5f\x98\x5d\xc7\x44\x2c\x6f\x6d\xa7\xbe\x53\x0b\x69\x02\x28\x9c\xab\x9c\xa1\x39\xc6\xb2\x4c\xb8\x0f\xfd\xd7\x82\x32\x4e\x60\x2c\x45\x91\x0d\xb6\x3d\x8b\x5c\x44\xca\x29\xd2\x7f\x56\xdb\xf0\x01\x86\xba\x58\x3c\x34\xe1\x60\x31\xdf\x35\x75\x46\xb3\xab\x9a\x3d\xd6\x5e\x91\xd7\x12\x8c\x93\x91\x95\xe6\x46\xa0\xf0\xb8\x9b\xf5\xdf\x04\xba\x23\x3d\x6a\x12\xa2\x71\xf7\xe0\x4a\xa4\x5c\xda\x99\xb4\xa5\x5a\x21\xcb\xbb\x73\x85\x15\xe3\x2c\x56\xaa\xc2\x49\x62\x32\xb1\x00\x8a\x67\x61\xc8\x04\x5a\x1f\xe0\xf9\xa3\x64\x40\x47\xb5\x96\x6a\x58\xa6\x00\x46\x6c\x1b\x1d\x11\xdd\xad\x5a\xa5\x73\xc4\x3e\xbd\xa8\x87\xe1\x6a\x05"}, -{{0xf5,0xc0,0xa7,0xf8,0xf6,0x58,0x4c,0x5d,0x2f,0x2e,0x1d,0x08,0x10,0xe8,0xe8,0x61,0x03,0xe4,0xe2,0xd4,0x5c,0xf9,0xa7,0x21,0xd8,0xc4,0x7f,0x67,0x49,0x33,0x96,0xa4,},{0x3c,0x6d,0x6c,0xce,0x49,0x63,0x31,0x41,0x07,0x86,0x96,0x13,0x1a,0x8d,0x84,0xed,0x82,0x3f,0x30,0x66,0x4b,0x28,0x9a,0xf9,0xdd,0x30,0xc6,0x40,0x7f,0x6f,0x03,0x13,},{0xd4,0xc3,0x0a,0x48,0xc4,0x52,0x3b,0x1f,0x84,0xb1,0x4b,0x65,0x7a,0xf8,0xf8,0x59,0x75,0x5b,0xba,0x63,0x59,0x98,0x8b,0x67,0x5c,0x6d,0x85,0xdd,0xf3,0x54,0x62,0x82,0x0d,0xa4,0x76,0xd8,0x4f,0x6c,0x40,0x2e,0x65,0xb0,0x20,0xd9,0xe8,0xa2,0xc2,0x85,0xc1,0x67,0x08,0xae,0x58,0xd1,0xf8,0xdb,0xc6,0x57,0x82,0xa8,0x98,0xa6,0x65,0x08,},"\xd6\x8a\xbc\x60\x9a\x7a\x0c\xe2\x56\x69\x9e\xb1\x70\x43\xde\xfe\x1e\xb8\x22\xc9\x70\x8f\x65\x71\x8a\x06\x58\x1f\xab\x21\x10\xec\x2d\xb0\x92\x13\xbb\x9e\x0f\x36\x12\xce\x4a\x3f\x8f\xdb\xe7\x57\xa9\xf0\xeb\x2c\x3e\xba\x43\x8a\x90\x88\xb1\x8f\x6c\x5c\xaa\xbb\xe5\xc8\x2f\x7a\x9a\xb2\xfe\xcf\x0f\x58\x59\xd1\x75\xe1\x39\x26\x30\x33\x74\x24\x58\xf8\x2a\x6f\x38\x75\x6c\xd5\xbc\xdf\x9e\x07\x36\xdb\x2c\xab\x20\xa0\xcd\x3f\x0f\x1c\xdb\xea\x85\x56\xd8\x49\x09\x35\x8d\xd8\xf6\x9f\x0d\xac\xd4\x9a\xbf\x8a\xc1\xbf\xe7\x59\x40\xd6\x93\x9e\x6a\x55\x38\x5b\x5a\xce\x7c\xe1\xfd\xe1\x20\x67\x9a\xb6\xea\x7a\x89\xd1\x42\x68\xd2\x9f\xfb\x46\xdf\x10\x5b\xf3\x90\x92\x42\xc6\x60\x5f\x3e\x3e\x2a\xb7\x44\x89\x37\xd6\xdb\x2b\xa0\x54\xc7\xb1\x4f\x43\x2d\xb4\x1d\xc1\x8a\x5b\x95\x73\x36\xb7\xf5\x2d\x97\x8e\xc0\x3e\x7d\x57\x64\xe9\xbd\x2f\x4b\x68\x95\x8d\x93\x7b\xf2\x98\x23\xb2\x7e\xfb\x31\xe2\x5b\x43\x92\x5c\x4d\xac\xbe\x67\x18\xa6\x0f\xea\x3b\x32\x70\xe7\xb7\x6b\x0d\xe0\xe7\x0f\x7f\xa3\xc1\x2c\x21\x5e\xf7\x2b\x95\xdc\x1b\x52\x76\x23\x81\x79\xdf\xc5\x2f\xc4\x88\x59\x64\x9f\xa5\x82\xd0\x5a\x60\xdf\x68\x59\x9a\x1c\xee\xa6\x4f\x64\x12\xd3\xf8\x49\x8a\xe2\xce\xdb\x12\x42\x45\x88\x3a\x24\x0b\xc0\x85\x1f\x0e\x32\x49\x65\xbe\x12\x04\x86\xe1\xea\x89\xa0\x18\x2d\xfa\x8e\xab\xd3\xb8\xfa\x66\xa9\x9c\x51\x49\x13\x89\xf3\xc8\x3a\x3c\xdb\x42\x67\xf3\xe4\xdb\xc9\x8f\x0c\x44\x85\x6b\x04\x4d\xc8\x8d\x90\xee\xee\x84\x15\xbf\x73\xde\x17\x1a\xfe\x84\xbe\x90\x35\xe0\xdc\x4c\x80\xcf\x04\x22\x46\x9f\xe0\xc9\xbd\x1c\x6a\xa6\x54\xa5\x9b\x5e\x34\xee\xd3\x51\xcd\xa2\x87\x12\x69\xac\x47\x8e\x8d\x38\x2e\x74\x0e\x9a\xc7\xab\x4d\xdc\x4c\x0d\xef\x0a\xea\xb7\x97\xb6\xf1\xa4\x27\xb8\xe4\xa8\x49\x7a\x0b\x97\x97\xda\xdc\xd3\x5c\x41\x4f\xd5\x5b\x78\x31\x30\xf6\xcd\xed\x38\xa4\x4c\x1a\x89\x28\x83\x07\xeb\x84\x25\x48\x41\x37\xa8\xae\xdb\x03\x0d\x54\xb6\x16\xa8\x2e\x3c\x5a\xcf\xfb\x08\xd6\xcc\x1a\x61\x74\x5c\x29\xaf\xc6\x8a\x0c\x18\x38\xb1\x39\x15\x9c\x5f\xa6\x67\x4d\x66\xb9\xe3\x38\x11\x5a\xad\x4b\x1b\x47\x10\xaa\x5d\x95\x17\xbc\xf7\xe1\xcb\x12\xd4\xe6\xa5\x1c\x11\x78\x9f\xdc\xae\x9d\x9b\xbe\x78\xf6\x9a\x33\xe5\x2d\xf1\x83\x3c\x87\x6b\x02\x68\x7a\x40\x4f\xac\xad\x32\x84\x1c\xb2\xd5\x25\x54\xe7\xb8\xe2\x20\x9e\x3f\x88\xfd\x94\x8c\x1e\xcf\x83\x95\x7c\x96\xf4\x3b\x03\x4b\xed\xa6\xc4\x76\x09\x6b\xcb\x09\x30\x1a\xd6\x1f\x83\x67\xcc\x43\xe1\x56\x13\x18\x62\xb4\x2e\xce\x28\x5b\xec\x2d\xcc\x2d\x02\xd0\x94\xd0\x42\xa1\x60\x72\xeb\x22\xab\x98\x88\x01\x3b\xe8\x23\x71\x56\x94\x00\xec\x1f\x8e\xc7\xe7\x91\x08\xc4\x1b\x85\x33\x65\x26\x8f\xa4\xcf\xbc\x62\xc4\xac\x12\xcc\x98\xd2\xec\x38\xa8\x7d\x60\x85\x85\x95\x67\xc0\xf2\x7d\x6d\x43\x1a\x04\x6e\x88\xa9\x81\x55\x58\x66\x07\x05\xfd\x05\xeb\x06\xc6\xc0\x5e\x5b\x7d\x62\x34\x7c\xee\xe2\x7d\xff\xed\x71\x41\x54\x0d\x60\x8c\xb9\x75\x07\x5a\x96\x44\xac\xc6\x32\x84\x39\xf9\xfa\x68\x2b\x22\x6b\x18\x61\x54\x54\x90\x11\xc3\xb0\xf0\xff\x4f\x74\xca\xa7\x1c\x19\x44\xe4\xcb\x83\x6c\xe8\x51\xd9\xb5\xd9\xe7\x27\xc5\x53\xe3\xc7\x23\xcf\x98\xc2\x73\xe5\x67\x5c\xab\x89\x9b\xb6\x6f\x46\x33\xa7\x6d\xea\x35\x73\x41\xf9\x83\xc5\x3d\x91\x58\xad\x31\x9a\xda\x75\x40\x8b\x41\xc0\x6f\x26\xb7\x43\x5b\x80\xdc\x3b\xc0\xaa\xf2\x2a\x83\x3d\xde\xdc\xd6\x78\x5c\x87\xd1\x96\xb0\xaf\x2c\x9a\x43\xd1"}, -{{0x1a,0xb9,0x46,0xc0,0xc1,0xae,0xbf,0x9c,0xa3,0x7c,0x2f,0x4e,0x2a,0x4b,0x33,0x7d,0x5b,0x1e,0xbc,0xcd,0x24,0x73,0x4c,0x9c,0xb2,0xa1,0x60,0x8c,0x88,0x1e,0x57,0x57,},{0x9a,0xfc,0x63,0xdf,0xce,0x0d,0x48,0x9b,0x40,0x90,0x7a,0xee,0xd6,0xdf,0xfe,0x4c,0xd8,0xef,0x5a,0x6f,0xfa,0x22,0x98,0x95,0x56,0x44,0x5c,0xbf,0x9b,0x35,0x19,0xc2,},{0xbf,0xab,0xde,0xa4,0x18,0x10,0xa5,0x3f,0x8e,0x52,0x7a,0xcd,0x66,0xec,0x10,0x6c,0xe2,0xae,0x1a,0x67,0xff,0x6a,0x9b,0x52,0x2e,0x0f,0x08,0xfb,0xbf,0x12,0x52,0x68,0x2c,0xb3,0xa1,0xdc,0xc8,0x75,0x60,0x19,0x44,0xcb,0x88,0x00,0x0f,0x72,0xe1,0x39,0x07,0x00,0x79,0x03,0xa7,0x7c,0xd0,0xdb,0x03,0x16,0xd4,0x19,0xac,0x38,0xc2,0x04,},"\x9b\xb0\x71\xb6\x2c\x04\x06\x4b\x0c\x96\xe2\x43\xdd\x19\x8c\x39\x71\x7b\x25\xc9\x94\x48\xc2\xc0\x02\xb8\x4a\x99\x20\x4c\x5a\x6e\x23\xb4\xb9\x12\x02\x86\x75\xbf\xdc\x4d\xf9\x3c\x5b\x2f\xb8\x08\x81\xa2\x3e\x0d\x44\xba\x18\xbd\xe9\x91\x21\xee\xe8\x6a\xdc\x6f\x84\x28\x19\xd6\xeb\xc7\xa2\x88\x99\x2d\xa3\x28\x58\x05\xa8\xb8\xb6\xfb\xcd\x22\x67\xb6\x86\xb3\xe1\xbf\x79\x60\xb4\x5f\x24\x4f\x85\x2e\x82\x49\x29\x44\xe3\xd6\x18\xbc\xc4\x51\x4c\x17\xf7\x22\xba\x49\xac\xa7\xf2\xf3\xbb\x4e\x91\xf9\x40\xe9\xce\xf0\x15\x65\x0c\x3e\x40\xb0\xc8\x55\xa1\x7c\x42\xf1\x1e\x3a\x34\xac\xc8\x52\x87\xdb\xe0\xf9\x09\x3c\x00\x37\x3d\x50\xc0\xb3\x06\x4a\x5a\x5f\x2b\x1e\x89\x20\x65\x17\x52\x82\x95\xfd\x87\x17\x03\xa8\xe7\x62\xb5\xe7\x6f\xb9\xb7\x47\x3d\x21\x49\xb8\x5b\x94\x61\xf5\x58\x7e\xd7\xe7\xfc\x8b\x50\xaa\x09\x87\x6d\xee\xb6\xe2\x37\x07\x85\x02\x14\x2c\xec\x6b\xdd\xc7\x01\x40\xfe\x1d\x1f\x16\x58\xd5\xd3\xe9\x10\xfd\x70\x36\xa2\xf9\x24\xb4\x99\xdb\x17\x56\xf7\xc8\xce\x0d\x5f\x0d\x04\x5b\x39\xbc\x81\xc5\xc2\xf1\xa7\x61\xf5\x2f\xf3\x93\xe0\x64\x9b\x8d\xb0\xbd\x88\x54\xbd\x02\x6b\xe2\xc7\xc3\xcd\x63\x52\x6b\xa5\xa8\x0d\x48\x33\x5f\x03\x38\x32\xd6\x33\x76\x07\x1b\x63\x08\xf0\x59\x60\xcb\x3f\xc9\xfa\xc9\x32\xed\xd8\x37\x6d\xae\x51\xf2\xc6\x61\xf7\x5b\x7c\x6f\x4a\xc8\x56\x75\x3a\xca\x62\x06\x28\x77\x60\x9f\xc4\xa0\xff\x60\x67\x02\x82\xc0\x5e\x88\x2d\x1a\x03\x5b\xf9\x89\x0c\xab\x29\x6a\xc7\xa8\xdf\x24\x4c\x56\xf4\x90\x25\x0f\x02\x00\x54\xb8\xaf\x51\xbe\x4f\xc3\x18\xbe\xba\x50\x62\x32\xbf\x45\xe1\x7f\x5c\x74\x0c\xf0\x9d\x37\x51\x5a\x8b\xc8\x94\xbc\x95\x5c\x8a\x46\x08\x77\xc7\x85\x4f\x8b\xe3\x63\xb2\x19\x33\xe1\x62\x87\xae\x0c\xb7\x0f\x22\x2d\x4e\x36\xb8\xb4\x24\x97\x55\x59\xbb\x4b\xfc\x8d\xd1\xd5\x1b\x3c\x0f\xaf\x4a\x53\xe3\x02\x19\x6f\x9f\xed\xb5\x32\x87\xd0\x93\x15\xdf\xff\xa2\xbc\x4b\x3a\xcf\xf1\x37\xf9\xa7\x6d\x68\x56\x21\x7f\x79\xcb\xb2\x54\x33\xfc\x97\x89\x9f\xd6\x54\x0f\x18\x08\x8e\x84\x41\x7e\x48\x33\xe4\xa9\x1a\xab\xa4\x65\x8a\xe9\xad\x7f\x76\x0d\xd9\xc5\xb7\x19\x1a\x0d\x3c\x05\x54\x1b\x83\xc0\x25\xa7\x99\x21\x38\xe6\xd1\x08\x0d\xa1\x4c\x2c\x88\x7c\x6d\x67\x0a\xab\x37\x4d\x43\x6c\x27\x2f\x9e\x96\xf8\x5a\x9c\x42\x33\x79\xc0\xd4\x7c\x46\xdf\x6d\xe3\x34\xea\x20\x57\x15\x8d\x33\x23\x1e\x14\x26\xa6\x6d\x3c\x70\x82\x7a\xad\x55\x11\xb8\x46\xe0\x3b\x94\x92\x3d\x5f\x94\xba\xf1\xf8\xcf\x11\xa8\x61\x37\x3a\x5b\x80\xad\x5e\x31\x7e\xc2\xa5\x29\xe9\x4e\x63\x6c\xdc\x3a\xa2\x9e\x5d\xac\x20\x5a\x0c\x13\xf6\x8f\xb1\x98\xcf\x94\x56\xe6\x39\x0a\xea\xd4\xd9\x78\x2a\x10\x38\xf6\x47\x8d\x33\x9a\x81\xba\xe7\xaf\x2a\x04\x15\x1c\x2f\x22\xe8\xd3\x9f\xe0\x71\xe1\xa5\x21\x68\xd5\x7c\x84\xc3\x62\x93\x41\x3f\x8e\x6f\xf6\x93\x4f\x05\xe7\xef\xad\x6f\xa1\x20\xc8\xc1\xc3\x8a\xd1\x88\x6a\x3d\x00\xbf\xc3\x06\x45\x92\x03\xc0\x2c\xdf\x4f\x06\x65\x2b\xc8\xfa\x0e\x8b\x9c\xc7\x79\xd4\x3f\xbb\x78\x9e\x7d\xad\x5d\xc9\x9f\x41\xd4\xcc\x58\x8c\x1b\x65\x42\x6a\x4e\x77\x38\x9e\xdd\x04\x97\x75\x78\xf8\xf3\x16\xbc\xdd\x94\x61\xd6\x66\x47\x2c\xdd\x27\x6a\xa5\x69\x72\x1c\x65\x23\x22\x56\xba\x1c\xf0\xe7\xf5\xea\x55\x32\x17\x29\xbb\x0e\x03\x86\xa7\x7b\x86\x55\x32\x02\x46\x96\xed\xde\xf4\x85\xb7\xd7\xb2\x8c\x15\x73\xb9\x34\x7e\x41\x4d\x42\x61\x99\x54\x82\xe3\xb3\x12\xde\x13\x31\xf8\x4e\x75\x48\x60\x7a\x84"}, -{{0x04,0xbb,0x88,0x7a,0x8a,0x31,0x84,0xff,0xc7,0xea,0x09,0xc9,0xbc,0x7c,0x1f,0x7c,0x34,0x11,0x55,0x6a,0x7c,0x7c,0x39,0x8c,0xb8,0xb2,0xd9,0x8f,0xfd,0x9e,0xe8,0x66,},{0x6a,0xb1,0xe4,0xae,0x4a,0xa0,0xd3,0x89,0x89,0xae,0xef,0xa8,0x05,0xb5,0x78,0x80,0x6e,0x2e,0x97,0x1a,0xc7,0xac,0x05,0x40,0x99,0x58,0xbf,0xe6,0x00,0x71,0xf4,0xa7,},{0xcd,0x84,0xf5,0x5e,0x5e,0xf4,0x53,0x19,0x24,0xc5,0xa2,0x18,0x1e,0xc8,0x7a,0x64,0x54,0x13,0x88,0xc1,0x05,0x94,0x06,0xbc,0x07,0xd5,0x31,0x57,0xa1,0x68,0xe2,0x03,0xcc,0x8a,0xa0,0xf0,0x06,0x9d,0x53,0xff,0x58,0xa9,0x5b,0x8a,0x8c,0xaa,0xfd,0xad,0x26,0x36,0x3c,0x7d,0x0f,0x80,0x45,0xc4,0x35,0x9e,0x97,0xb4,0x36,0x02,0xc6,0x06,},"\xb7\xab\x0c\x81\x63\xf4\x78\xc6\xca\xbf\x2b\xbd\x7c\xa3\x7c\xb0\x24\x56\xd7\x6e\x52\x7e\xea\x1b\x0d\x26\xdb\x24\x2e\x37\x87\x76\x32\x98\x5a\x3e\x3c\xa4\x1b\x52\xe2\x1d\x79\x01\x7b\xff\x81\xee\x55\x1a\xd7\x2a\xf2\x77\xb4\x10\xe4\x2a\xf8\x22\xc6\x08\xcd\x69\xd0\x0b\xf4\x40\xb7\x5b\x78\x7a\x8c\x91\x5d\x70\xb6\xc6\x37\x6c\x3f\x67\xfa\x64\xd6\x12\xa1\xb4\x49\xa7\xe2\x13\x4d\x9c\x23\x23\x01\x57\xd5\x76\xe0\x6a\x66\xa8\x42\x2a\x61\x1e\x2a\x0f\x09\x72\x86\xc1\x99\xea\x2a\x16\x28\x61\x86\x4b\xd0\x35\x07\x6a\xb2\x0b\xba\xe2\xb4\x40\x8a\x2c\x64\x33\xcb\x23\x43\x3a\x88\x9f\xe6\x59\x8f\x47\xbe\x53\xbb\xd2\xc8\x0f\x07\xa8\xfc\xcb\x8a\xae\x51\x11\x61\xe6\x09\xda\x4d\x18\x0a\xce\xa5\x44\x81\x1e\x94\x49\xc5\xdc\x22\x50\xe3\xe5\xa0\xcd\x41\xda\x33\xa2\xda\x63\x2e\x60\x38\xbd\x86\xf1\x6d\x5b\x7c\x1b\xe4\x9f\xc6\xdb\x49\x90\x76\xca\x91\xf7\xaa\x02\x8f\xe3\x85\x29\x70\x0b\x21\xd0\x72\xd2\xb7\x5d\xcc\x8b\x43\x78\x1d\x4b\xc4\xd3\xbb\x58\x4d\x9d\xa0\x1c\x3e\xcc\x85\xb1\xe9\x3f\xce\x04\x5d\xad\xce\xea\x51\x06\x46\x8b\xdf\xe5\xf7\x0d\x66\xa4\xfa\xd6\x0e\x4f\xb8\x64\xec\x15\xea\x50\xf6\xcb\x79\x72\x23\xc8\xc7\x56\xf7\xa1\x93\x1a\x39\x46\x4e\xbb\xb9\x67\x9f\x6b\x01\x68\x7c\x17\x4e\xaa\x32\xb9\x68\xb9\xcf\xac\xe8\xc1\x67\x12\x0a\xa7\xbd\x02\x42\xf0\x03\xa0\xc3\x77\x70\x25\x51\xb3\x0d\xa2\x48\x8e\xb2\x94\x40\x52\x93\x4a\xef\x4b\xfe\x11\x5f\x0a\xb7\x40\x5a\x3d\x5f\xa9\xbd\x79\x6b\x37\x17\x42\xbc\x11\x4a\x9b\xf2\x8c\x5b\xd2\x56\x26\x29\x5c\xe2\x61\xa6\xa8\x3e\xf6\x0b\x77\xd2\xd3\x2d\xd7\x10\x5f\xc8\x36\x64\xaa\x89\x76\x5b\x3f\x81\x91\xee\xee\xd8\x78\xf2\xeb\xff\x2f\xb9\x76\x63\xa6\x18\x77\xc0\x93\x93\x3b\xbd\x07\x31\xe6\x37\x57\x57\x1b\x0e\x37\xca\xc9\x9e\xd0\x1f\xd2\x14\xcb\xd4\xfe\xb9\x77\xe8\x56\xe0\xa1\xa7\xef\x0c\x40\x8c\x20\xe0\xdd\xaf\x1f\xd8\xf0\x28\xcf\xa0\x8c\x85\x0f\xa7\x09\x0d\xca\x8c\xdd\xe0\xcb\x69\x03\xda\x18\xc6\x29\x0c\x66\xa1\xc0\xae\x0a\x08\x4b\xf2\x50\xc5\x1a\x9d\x03\x5e\x5b\x16\xec\x61\x66\x36\xaf\xb9\xb5\xbc\xe3\x6a\x77\x5f\xe2\x17\x5b\xcc\x2e\xe0\x72\x20\x83\x4e\xeb\x31\xca\xee\x50\xe9\xf8\x06\x3f\xb1\xfc\x84\x68\xae\x25\xe3\x96\x67\x89\xa6\xd8\xdf\xfe\x08\xa6\xf7\xa1\xe6\x72\x6f\x93\xae\x74\x82\xde\x02\x62\xbb\x1f\x8d\xe0\xc9\x5a\x99\xec\xb9\x56\x84\xd4\x4b\x3f\x1a\x33\x2a\x18\xd2\xcd\x3d\xcf\x25\x3c\x33\xd7\x35\x52\x2f\x79\x6b\x65\x1c\x9a\x63\x3a\x8e\xbe\x95\xd0\x2b\xc0\x46\x58\x25\xee\x54\x1a\x7d\x92\x7b\xb5\xb9\x0a\x6d\xb5\x49\x9f\x8d\x99\x3a\xb4\x04\xb1\x65\x0b\x75\xe7\x92\xa7\xc8\x34\xeb\x41\xf0\x47\x01\x38\xb0\xf5\x78\xa0\x4c\x9b\xa5\xad\x95\x0a\xc7\xc9\xb5\xd3\x28\xf3\x40\x8b\x64\x5a\xd9\xc6\xbf\x19\x6d\xd9\x61\x44\x55\x96\xbc\x78\xf2\x84\xb8\x91\x4b\x2a\x8c\xf9\xb7\xbd\x3a\x71\x6d\x8f\x14\x4b\xb6\xb1\x5d\x83\x10\x23\x71\x3b\x5e\x41\xfd\xa9\xb5\x87\xff\x9d\x6c\xc4\x3c\x08\xd3\x5a\x70\x7f\x49\x52\x83\xe1\xac\xe9\x60\x48\x7e\x7f\x02\xb7\x54\x3b\x68\xa7\x31\xa2\x9b\xf3\xbe\x14\xb6\xe9\xc3\x71\x74\xa9\xf4\x6f\x56\x11\x99\xdb\xd2\x7b\x46\xbf\xe6\x22\x43\xe0\xc1\x1c\x0e\xdf\x13\xb6\x4f\x41\x1c\x8e\x8e\xce\xd3\x5d\x84\x28\xf7\x9f\x10\xea\xcf\xfb\x72\x34\xe5\x46\x41\x3d\x1e\xb0\xfa\xd8\x8c\x0e\x93\x85\x93\xb4\x3b\x5e\xe0\xe4\x28\x5d\x4d\xdd\xf5\x29\x5d\xbf\x1a\x3d\xdb\xe9\xf4\x13\x4d\xd7\x6d\x3d\xe7\x04\x62\xc2\xf0\x4f\xe0\xae\xbd\xf5\x9a"}, -{{0x97,0x76,0xa4,0x67,0xfa,0x14,0x00,0x73,0x54,0x12,0xa7,0x9b,0x49,0x5f,0x9f,0xca,0x07,0x8c,0xe1,0xd8,0x7a,0x85,0x30,0xd8,0x5c,0x26,0x05,0x5d,0x3a,0x39,0x44,0x88,},{0xc7,0xdb,0xe0,0xe4,0x1c,0x0a,0x31,0xc0,0x94,0x27,0x93,0xff,0xd1,0x42,0xd8,0xb9,0x5c,0xc8,0x2e,0x5c,0xaa,0x92,0xa3,0x79,0xba,0x23,0xf6,0x44,0xed,0xf2,0x24,0xda,},{0xe1,0x31,0x7b,0xa2,0xa1,0x23,0xae,0x3b,0x29,0xe7,0xb6,0x0e,0x8e,0x93,0xbe,0xed,0xd7,0xa0,0x84,0x51,0xa0,0x13,0x69,0x5b,0x6d,0xcf,0x35,0x8e,0x40,0x34,0x02,0x6d,0xc7,0x40,0x37,0xaf,0xbd,0xd2,0x17,0xff,0x4b,0x14,0x8b,0x02,0x91,0x38,0xf4,0xbc,0xc8,0xf9,0x83,0x6a,0xbb,0xae,0x7e,0x62,0x76,0xe9,0xe7,0x69,0xdb,0xd8,0xf0,0x07,},"\xd7\x85\x53\xa1\xb7\x05\x5b\x58\xb2\x13\x10\x1b\x1c\x84\xc5\x3e\x16\x4e\x39\xc6\xe9\xd3\x6d\xb4\x3f\x30\xe1\x9e\x2a\x12\x5a\x9a\x67\x70\x9e\xaf\xef\x96\x4f\xa5\xba\xb7\x26\x1d\xdb\x3a\x8a\x01\x88\x45\x7d\xfb\xf5\x15\x9c\x40\xe5\x1d\xa8\x20\x84\x83\x24\x57\x81\xd7\x13\x1e\x23\xa8\xbe\xe5\xe5\x06\x33\x18\x16\xb9\xde\xee\xfe\x6e\x55\x6e\x3f\x0c\x95\xc6\x68\xd1\xbe\xdb\x7d\xa6\x35\x06\x54\x58\xad\x20\x46\x70\x12\xf5\x9f\x17\x13\x52\x06\x80\x20\xce\x3c\x75\x87\x86\x93\xf6\x43\x7b\xc4\xa0\x9f\x13\xb9\xb0\xf0\xcd\xda\xf1\x69\x1b\x87\x2f\x82\x00\x80\x93\xeb\xfb\xe2\x33\xd0\x31\x3e\x72\xc8\x63\x2d\x7d\x17\x93\xf0\xb8\x1c\x76\x88\xf5\x44\x70\x33\x0f\x04\xe6\x48\x60\xe6\x44\x6b\xfc\x6d\x96\xc8\x75\x69\xbf\x18\x2f\x0f\x43\x85\xaf\x48\x5d\x42\x99\xca\xc0\x4e\x06\xba\x47\x34\x65\x56\x6c\x47\x7f\x07\xb9\xdb\x27\x7a\xb4\xa9\xde\x2f\xb2\xde\xd0\xa5\x01\x1c\xd0\x6d\x67\x5c\x08\x00\xb3\x4f\x55\xbc\xf3\xec\x72\xd2\x1c\xa1\x50\xc8\xbf\x23\x61\x28\x7b\xe8\x1e\xfa\xbb\x96\xd8\x68\x8a\x1d\xee\x3f\x43\x0f\x06\xf6\x37\xdf\xd0\x6f\x15\x14\x64\xa0\x5c\x95\xf5\xfe\x76\xaf\x2e\x06\xd0\x12\x3f\x69\x48\xa2\x6b\x3b\xe8\x35\x04\x5a\xa2\x68\xcc\x1b\xe9\x76\x69\x71\x07\x77\x02\x08\xa7\x56\x8f\x02\x5c\x2d\x53\xc7\x19\xe5\x24\xcc\x36\x9d\x9b\x4a\x33\x7d\x8f\xd1\xef\x34\x5b\x9b\xca\x57\xfb\xd7\xb6\x5a\x6b\x99\x7c\xad\x3f\xce\x4c\xf0\x6f\x2c\xa4\x3e\xbe\x29\x86\xd0\x96\x82\xd4\x7c\x92\x2b\x2c\xb7\x56\x9d\x98\xde\x97\xa6\x16\x4f\x54\x70\xee\xc7\x1c\xed\xa5\x20\xcc\xec\x77\x32\xbd\x01\x68\x9e\xf8\x16\x56\xe9\xf6\xd0\xc5\x8a\x89\x55\x58\xae\xe8\x63\xf5\x46\x9e\x7a\xb9\x79\x15\xbf\xe0\xb8\x0a\x06\x4c\x65\x9b\x18\x30\x31\xf7\xf1\xa8\x6f\xb1\x1a\x9d\x52\x8c\x28\x15\xdc\xaa\x2f\x0d\xec\x3d\x21\xa8\x82\xe1\x06\xe2\x04\x93\xee\x0a\xcb\x77\x08\xea\xa2\x91\x25\x74\xae\x97\xbb\x28\x8b\x41\xfc\x09\x25\x05\x3a\x29\xb0\xbf\xbc\x0e\xba\xe8\xd6\x3c\xc0\xb4\x6e\x37\x38\x04\x6c\x5a\x20\x25\x30\xbc\xb1\x5b\x18\x7a\x72\x85\x4a\xa2\xd8\xa7\xa7\x6c\x89\xa8\x9a\x5d\xb4\x60\x32\x07\x4e\x1b\xd7\xde\x77\xef\x20\x65\xa0\x8f\x38\x9d\x78\x3c\xf7\x59\xeb\xd5\xa6\x3a\x44\xd9\x19\xf9\x48\xf5\x60\xc3\xe9\x4c\x42\x39\xe2\x74\xe0\x51\xa2\x04\x85\xa4\x30\xcb\xd5\x29\xf3\x13\xd9\xf7\xed\x67\x9a\x34\x18\x7b\x24\xf8\x41\x30\x87\xa9\x02\x1e\x47\x31\x73\x0f\x5f\x46\x1f\xc5\xaa\xd6\x65\x4d\xfa\x1c\x05\x04\xd2\x61\x24\x70\x7e\x63\xee\x57\xf9\x31\xb2\x78\x59\x08\xf8\x6b\x10\x4b\x3e\xcb\x96\x00\x02\x51\xd0\x6c\xe1\xfa\x45\xe4\xcd\x6d\xf9\x1a\xc1\x5b\xbf\x7c\xa3\xc3\xeb\x8e\xe0\x82\x76\x12\xa2\x9e\xcb\x7a\x36\xd5\x47\x0c\x40\x50\x51\x82\xfa\x9a\xc9\x13\x57\x0d\x0c\x10\x50\xd9\xa4\x34\x55\xcb\x7b\xdc\x17\xd1\x69\x80\x5f\x01\x89\x56\xf8\x54\xf8\x91\x9b\xbf\xb7\x19\xe1\x86\x7b\x36\xa6\x4a\xab\xcd\xb8\x07\xf4\x8d\xcc\xc0\x67\x2f\x67\x88\x74\x50\xb3\xf3\xe9\x58\xd7\x84\x99\xe0\xd1\xab\x36\x8a\xa4\x94\x42\xe5\xe8\xa3\x32\xbf\xfd\x44\xc1\x69\xea\x67\x62\x9c\x85\x72\x4d\xb6\xf1\x58\x6b\x6c\x6b\x5b\xe4\x86\x4d\xfd\x53\xda\x7c\x0f\x7b\x8b\xb3\x57\x31\x16\xbe\x50\x77\xd3\x32\xbd\x12\xa6\x30\x0f\x3a\x68\xa8\x98\x66\xb4\x79\xec\x2b\xaa\x27\x7f\x9f\x56\xf6\xe1\xd4\x9d\x74\x1e\xb3\x22\x03\x5f\xf8\xcb\x1d\xe8\x5c\x8d\xc8\x7a\xc8\xe6\xe4\xc5\xd2\x0b\xfb\x6d\x31\x7a\xb1\x25\x93\x0c\x42\x60\x9b\xe3\xae\x82\x24\x2a\x9e\xf0\x56\x88\x58\xd8"}, -{{0x09,0xd8,0x12,0x26,0x97,0x12,0x6d,0xfc,0x7e,0x11,0x68,0x5a,0x04,0x12,0x3f,0xdf,0xb4,0x7c,0xcd,0xdb,0x44,0x99,0xd8,0xa3,0xae,0xf4,0x18,0xcb,0x65,0xae,0xd7,0xa7,},{0xf8,0xdd,0xb1,0xc0,0x0f,0x6e,0x0f,0x4b,0xea,0xa6,0xfc,0x38,0xe5,0xd0,0xa5,0x77,0x5e,0xe2,0x8c,0x80,0xdb,0xde,0x3f,0x0c,0x79,0x30,0xa3,0x3a,0xad,0x71,0x50,0xf3,},{0x18,0xcf,0xaf,0x6d,0xc8,0xe4,0xe8,0x58,0x2b,0xce,0xfe,0x0c,0xdc,0x6f,0xce,0xfe,0x6a,0x4a,0x87,0xea,0x62,0x95,0x85,0xf3,0x7d,0x2f,0xba,0x44,0x6b,0x3a,0xeb,0xd4,0x52,0x42,0x63,0x82,0xda,0x0d,0x49,0x1c,0x39,0xcb,0x7d,0x54,0xd2,0x73,0x00,0x5d,0xc1,0x32,0x12,0x15,0x68,0xd2,0xab,0x67,0x45,0x20,0xad,0xda,0x75,0x23,0x84,0x0d,},"\xa0\xd8\xd8\x79\x8e\xba\x22\xf5\x67\x60\xc3\x06\x43\xe9\xfc\x67\x95\x54\x7e\xa5\xf2\xf2\xbb\xd1\x1c\x03\x92\xb2\xeb\xf7\x11\xac\xa2\x2f\x08\x24\x19\x9f\xc3\x18\x8a\x45\xbd\xff\xde\x70\xec\xe9\xab\x15\xa5\xea\x89\x62\x2a\x58\x71\xe0\xef\x76\x85\xd1\x0f\x12\x74\xcc\x19\x5b\x4f\xda\x81\xf8\x79\xd1\xe9\xbf\x42\xf8\x73\xb2\x0a\x85\x9c\x23\x3f\x9e\x49\xad\xbf\x05\x77\x31\xe1\x13\x35\xe9\xb6\xd8\xed\x0e\x06\x9e\x13\x4e\xc4\x61\xca\x88\x90\xd7\xb0\x47\x3c\x40\x5e\x8a\x9d\x95\xd1\x57\x11\xb1\x24\x76\x10\x37\x62\xc6\x26\xd9\xf2\xaa\x5d\xd5\x19\xbd\x82\x5b\x60\xb3\x23\x4e\xbf\x65\x1e\x0d\x19\x33\x37\x1c\x52\xbf\xd8\xce\x33\xfc\x36\xbb\xa3\x28\xf7\xf3\xf2\xcc\xc0\x10\x00\xa8\x99\x04\xaf\x37\xe4\xe1\xe9\xe1\x5f\xff\xab\x5c\x2b\x0c\x47\xf3\x7c\xdc\xb0\x68\xdb\x33\xac\x36\xa5\xf0\xd6\xde\x12\x03\xfb\xf8\x94\x93\x24\xbd\x3e\xfd\xa0\xf9\x88\x9d\xb0\x0d\xa2\x31\x7b\x49\xfd\x18\x69\x99\xdf\x7f\xcd\xc3\xcb\x4e\x1d\x18\xfa\xa2\x54\x56\x1c\x25\x11\x78\xb8\xd3\x3f\xdc\x9d\xcc\xd8\xd2\xd7\x21\xb9\x3a\x53\x6c\xcd\x3c\x0e\x9c\x85\x63\x37\xf1\x95\xee\xe7\xda\x9a\x7f\x6b\x0a\x42\xb7\xc5\x41\xc6\xa6\x8c\x59\x5b\xf3\x47\x04\xd9\xfe\x3a\x56\xd2\xec\x84\x81\xd5\x77\xc9\x6e\xcc\x08\xb8\xe4\x0a\xcd\xbf\x05\x0e\x20\xc6\x83\xf3\x9c\x41\x4e\x8c\xbf\xcf\x4a\x01\x52\x31\x4c\x05\x98\x7a\x83\xbd\xe3\x02\x5b\x73\x5c\xca\x30\x23\xab\xc5\xfe\xb7\xe0\x0d\x02\x36\xb4\xf2\x4b\x15\xe6\x79\xdb\x05\x2c\x8d\x2f\xdd\xb3\xbe\xf8\x66\x3a\x6d\xf8\x19\xa9\x81\x55\x27\xa1\xa2\xf6\x0a\x0f\xa4\xe5\x07\x8d\xdc\x6d\x43\x5f\xe8\x92\x87\xb3\x0f\xfd\xeb\x5d\x9a\xe0\x5d\x1a\x86\x90\xfb\xc7\x59\x0a\xad\x57\xd4\x3d\x22\xc1\x2a\xce\x2c\x81\x96\x88\x8e\x35\x4e\x9f\x78\x2f\x5d\xbb\x44\x14\x9e\x83\xfb\x8b\xbc\x9d\xa6\xd8\x9c\xe2\x06\xc1\xe2\xb6\xb2\xb2\x8f\x93\x3f\x3e\x5f\xf1\x17\x5a\x31\xa8\xff\x5d\x31\xe6\x5c\x8b\x00\xc5\xba\x46\x22\x24\xa1\xe0\x9d\x4f\x09\xcb\x40\xfc\x87\xc3\x6e\x7d\x28\x5c\x77\x4a\x96\x97\x62\x03\x65\x18\x28\xe7\x83\x62\x88\x47\xac\x51\x2e\x5d\x1c\x35\xb3\x5b\x03\x01\x71\xf9\x23\x96\xf5\xff\xaf\xf5\x85\xce\xad\x04\xb6\xae\x21\x0d\x80\x70\x7c\xc6\x83\x2d\x98\xa2\x0d\x3a\x94\x76\x48\xda\x26\x04\x93\x7f\xef\xd2\x5a\x9f\xe0\xfc\x5c\xac\x08\x3d\xdd\x7d\x20\x75\x30\x7f\x4f\x38\x26\x64\xf6\x87\xdc\xe8\xc6\x55\xde\xd9\xc1\x2d\x48\xff\x76\x01\xdf\x2a\x48\xd3\x7f\xe2\x14\x97\x08\x44\xc0\x75\xf2\xea\xb0\x02\x05\x9f\xc2\x27\x1e\x61\x7c\x96\x57\xa0\x1b\xec\x1d\xd3\x8f\x6c\x28\xba\x8a\x61\x7b\xd3\x08\x51\xe3\xf9\xdb\xac\x90\x44\x18\xdf\x1d\x02\x15\xad\x45\xdf\xc9\xf0\x2b\x5c\x5e\x9f\x9b\xbc\x6d\xe8\xb0\x7a\xf0\xbd\x1f\x7f\xa8\x92\x25\x44\xf1\x2d\x2a\x3e\x1a\xad\xff\x7e\x9c\x6b\x93\x32\x0c\x3a\x61\xef\x33\xda\x07\xeb\x87\xb1\x61\x7f\x9e\x77\xd7\x70\x2e\x55\x8b\xc7\xd8\x12\x2e\x0d\xfe\x2a\xe8\x3e\x83\x6c\x5b\x1a\x62\xaa\x58\x5c\x0d\xff\xe7\x16\xf7\x46\x3c\x0b\x33\xda\x5b\x1e\xda\x55\x6a\x1e\xf1\xe4\x50\x42\xc7\x9b\xdd\x3e\xc3\xcb\x88\x63\xa7\xbc\x1b\x0f\x7e\x1c\x05\xbd\x99\x20\xf0\x5b\x4e\xda\x86\x51\x77\x05\xed\x07\xf6\xdc\xa7\xbb\x00\xae\x04\x56\xe6\x78\x7d\x9f\xae\x8e\xde\x4e\xcd\x0b\xc5\x72\xeb\x5c\xc6\xd1\x9e\x89\x1f\x1b\xcb\x22\x9e\x94\x09\xe0\x65\x74\xc7\xdf\x05\x81\x73\xcb\x58\xc3\xfd\xf2\x0f\x3f\xf1\x7c\x37\x05\xaf\x62\xd9\xb7\x22\x5c\x57\x43\xf6\x00\x60\x7f\x77\xcb\xe7\xd6\xe7\x61\x8a\xbc\x79"}, -{{0x10,0x20,0x1b,0xf0,0x08,0x43,0x67,0x59,0x0d,0xe6,0x74,0xcc,0x0e,0xd2,0x64,0x8e,0xc2,0x5d,0x3b,0xa8,0xdb,0x40,0xd0,0x0e,0xde,0x15,0x33,0x98,0x50,0x8b,0xc1,0x26,},{0xba,0xdb,0xd0,0x5e,0x5f,0x79,0xe3,0x11,0x69,0xf7,0x40,0xba,0x46,0xa5,0x89,0x10,0xa1,0xb7,0x77,0x05,0xaf,0x45,0x71,0x7b,0x2a,0xf8,0x08,0x56,0x45,0x7c,0x58,0xc9,},{0xf1,0xd9,0x96,0x58,0x8b,0x29,0x8f,0x27,0x1e,0x97,0x0c,0xeb,0xd2,0xa1,0xb3,0x39,0x97,0x9c,0xd2,0x9d,0xdd,0xee,0x36,0x45,0xd0,0x7f,0xab,0x8a,0xb4,0x65,0xdd,0xe3,0xe9,0x86,0x67,0xec,0x01,0xad,0x7f,0x1c,0x0a,0x65,0x92,0xe0,0x69,0x7e,0x66,0x5c,0x72,0xfd,0x38,0x14,0xdb,0xe1,0x89,0xed,0x5f,0x4e,0x76,0xc7,0x94,0xe5,0x38,0x09,},"\x7b\xb1\x47\x06\x17\xd1\x1e\x45\xeb\x60\x2a\x82\x9a\xd7\x73\xee\x2b\xb7\xe6\xb8\x8d\xa4\xc0\x4a\x72\x16\xa4\x50\xf8\x49\x93\xa4\x98\xcb\xd3\xb9\x25\x40\x28\xf2\xf9\x9f\xc2\x1a\x23\x28\x8b\xdc\x1e\x15\x1a\x72\xa9\x13\x0c\x3d\xed\xda\x1b\xbb\xcc\xd4\xe6\xc0\xf4\x8a\xe9\xf3\x53\x18\xcb\xef\xc9\x59\xf4\x05\x04\x5e\x6e\x0b\x5f\xb2\xe7\x38\xf2\xb7\x65\xbe\x11\xb1\xb6\xa0\xf1\xe8\x31\x95\x49\xd9\x5f\xa8\xd1\xdf\x81\x67\xcd\x4a\x77\x17\xae\x16\x36\xa9\xdf\x54\xd9\x6e\xaf\x2d\x63\x23\x69\x00\xfd\x11\x33\x82\x52\xa5\x00\x8d\x5d\x48\x0e\x2b\x1e\x98\x61\xd1\xf7\x06\x88\xc4\x7e\xae\x46\x89\xda\x01\xa4\x7d\xa3\xdf\xb6\xd2\xba\xb3\xcd\xf5\x05\xee\x5d\x80\x1a\x15\x2c\x26\x70\x93\xd1\x7e\x9b\xf7\x13\x7a\x6e\xe7\xb8\x34\xd0\x08\x55\x00\xe4\x01\xc1\x7f\x32\x86\xc1\x57\x5d\x1c\x01\x00\xfa\x98\x07\x63\x0c\x4a\x99\x06\x54\xc1\xe7\x1a\x8b\x71\x56\x27\xbb\x13\xd4\x42\xc8\x4a\x44\x98\x44\xc4\x04\xb8\x72\xbf\xba\xc7\x18\xa4\x8d\x0e\xa0\x94\x5c\x77\x16\x6a\x53\x13\x9b\x0f\xf0\x09\x81\x34\x76\x4f\x9e\xcd\xb8\x8e\xab\xe0\x7c\xcb\x2c\xce\xd4\x95\x5e\x08\x24\x9b\x2f\x57\x70\xad\x41\xfc\xcd\x7b\x5b\xb3\x72\xe6\xc3\x37\x67\xe0\x7f\x5b\xe7\xd1\x07\x12\xde\x81\x84\x1b\x13\x4e\x19\x3d\xf0\x77\x6a\x0f\xc1\x56\xff\x5d\x0e\x96\xf4\x0a\x70\x47\x53\xe1\x14\x5e\x9f\xa0\x83\xc4\xdd\xee\xf4\x41\x62\x34\xf6\xe1\xa2\x38\x2c\x8e\x5b\x3a\xd4\x05\x45\x8e\x89\xd2\xf4\x93\xa4\xd7\xc2\x9a\x23\xde\x21\x07\x48\x5b\x7f\x56\x35\x01\x24\xe7\xe0\xd6\x95\xc5\x22\xb6\xde\x7a\x92\x47\xa2\x92\x4c\xe6\xf2\x86\x32\x36\xc1\x0c\xc2\x12\x64\xad\x54\x59\x0d\x31\x47\x63\xea\x1a\x19\xaf\xac\xd9\x0e\xba\x95\x58\x70\x40\x7e\x8c\x63\x65\xa1\x43\xa5\xc1\xb9\xa8\xbe\x5e\x4a\x4d\xca\xdb\x72\xe0\xd4\x76\x49\xbd\x53\xab\xd4\x6b\x5c\x69\x60\xea\xe2\xca\xb7\x73\x75\x3c\xc0\xe0\x4e\x99\x41\x4b\xc2\xcb\x30\xf4\x8b\xb5\x41\x39\xd0\x66\xe4\x3e\x2f\x0e\x1a\x4a\xe9\x63\x85\x8b\xef\x96\x7d\xf8\xc8\x41\x40\xd2\xd0\x92\x02\xb4\x06\xd5\xd8\x5c\xb7\xa9\x6c\xc5\x7f\x23\x3e\xb2\x18\x7f\xfd\x02\xf9\x4e\x92\x29\x7b\x5e\x69\xd9\x69\xd3\xa5\x93\x6e\xfe\x49\x29\x14\x4f\x25\x8b\xfb\x39\xdd\x0c\xe2\x63\x59\xc4\x54\x9f\xc2\x18\xa0\xaa\x54\xf3\x1b\xd5\x51\xb8\x78\x1a\xcb\xbf\x61\xcb\x3f\x73\x2c\xda\xf6\x22\xc6\xa6\x91\x88\xcf\x55\x7a\x3a\x92\xed\x15\x3e\x69\x12\x5a\x40\x90\xac\x45\x15\x36\xa0\xe9\xa6\x3a\x41\x78\x29\x10\xff\xcc\xb4\xe8\x50\x02\x11\x23\xff\xd1\xf3\xbf\x39\xc7\x34\x60\xa6\x5c\xcf\xe4\xdb\xa9\xbd\xef\xb5\xd5\xf4\xda\x6c\x46\x9a\xa1\x32\x2f\xa2\x70\x43\x23\x83\x63\xee\x72\x91\x86\x88\xd7\xca\x1c\x4c\x29\x52\xe4\x30\xd5\x63\x25\x6b\xb8\x6d\x35\x0a\x35\xee\x82\xe0\x15\x04\x74\x7f\x31\xd0\x2e\x03\xae\xdd\xa5\x46\xd0\xf1\xb2\xf4\x51\xb8\x70\x82\x16\x02\xd0\x0e\x81\x90\x36\xad\xe5\xa7\xc7\xfc\xd2\x1a\x6d\xe6\xaf\x35\xb1\xf9\x63\x2a\x70\xaf\x65\xdf\x64\x45\xf6\xfa\xdf\xbc\x0f\x41\x67\x55\xc8\x24\x66\x40\xe5\x6b\x85\x6b\x66\xdd\xd9\x2a\x60\xc0\x35\x38\x22\x1d\xc8\xfb\x14\x2c\xe2\xdb\xac\xdb\x74\x25\xf3\x3c\xb8\x5d\x85\x0c\xc0\x2c\x31\x5c\xfc\x11\x1f\x6f\x65\x1d\xde\x1b\xdb\x67\xfb\x20\x8e\x1f\x6b\xde\x78\x4d\xdc\xf7\xbd\x18\xc8\x05\x1a\x2e\x0b\xbf\x10\x18\xb8\xf3\x95\x36\xc5\x89\xde\x65\xea\xdc\x6c\xf3\x79\xb7\x7c\xad\x13\xf9\x08\x9c\xb3\x23\xfb\x2e\x94\x3d\x06\xcd\xd1\x07\x05\xc1\x21\x13\x4c\x65\x48\xdc\x53\x41\x5f\x8c\x37\x0e\xc6\x90"}, -{{0xc4,0xaa,0x42,0x52,0x46,0xb5,0x17,0x3f,0x5e,0xf8,0x98,0x15,0x2e,0xca,0x3d,0x09,0x2b,0xb4,0xc2,0xdd,0x02,0x85,0x3f,0xcf,0xc7,0x17,0x83,0x99,0xf4,0xe2,0xf7,0x58,},{0x29,0xb7,0x7a,0x30,0x75,0xf4,0x19,0x24,0x3c,0x0c,0x1b,0xc3,0x96,0x59,0xd7,0x31,0x17,0xac,0x00,0xe5,0x5e,0x8d,0xe3,0x8f,0xe9,0x82,0x9a,0x87,0x9c,0xc5,0xb8,0xa0,},{0x5d,0x85,0x45,0xa4,0xbe,0x3f,0xd6,0xda,0x25,0x78,0xc2,0xec,0xcb,0x64,0x8d,0x83,0xfc,0xfe,0x58,0x71,0x33,0xfa,0x7a,0xe4,0xa1,0xcf,0xca,0x9a,0xe6,0xda,0xa4,0x92,0x59,0xc9,0x52,0x04,0x4a,0x85,0xa2,0x0b,0x6f,0x53,0x24,0xf8,0x27,0xdb,0xa2,0xd1,0xa8,0x38,0x8c,0x40,0xa9,0x28,0xb9,0x50,0x91,0x3c,0x63,0x4f,0xb3,0x09,0x27,0x07,},"\x7d\xf9\x78\xa1\xf4\x97\x68\x38\xff\xed\x74\x49\xa4\xdc\x13\x8b\x60\x4f\x4b\x2a\x4a\xe6\x89\xce\x75\x01\x8e\xbc\xcd\xab\x2e\xaa\x0b\x60\x76\x8f\x72\x08\x25\x7f\x2b\x28\xe7\xaa\x09\xbf\x6c\x05\x88\x8d\xa4\x6f\xd3\x96\xd1\xc8\x03\x01\x17\x50\xe3\x0e\xb4\x84\x87\x0c\x88\x06\x97\x76\x96\xf1\x2e\xbb\x9f\xee\xb4\xca\xf9\x2a\x02\xdb\xaa\x22\xbb\xff\x63\xf8\x42\xc3\xba\x14\x7b\xca\x7c\x00\x31\x42\x78\xac\xd0\xdb\x17\x35\x69\xf4\xe3\x65\x27\x95\x8e\xf6\xf1\x00\x2b\xd3\xcd\x01\xf4\x07\xa8\x65\x31\xed\xcb\xd9\xf3\x1b\x3a\x4a\xb8\x80\xa4\xf5\xb5\x2b\x42\xd0\xd4\xa1\xba\x66\xa2\x09\x86\x51\xae\x3e\x6c\x91\x51\xf4\x02\x73\x28\x5f\x7f\x6a\x4e\x81\x60\x6b\xf9\x80\xf6\x89\x50\x4b\x42\x08\x0f\xdb\x97\xc7\x28\x46\xfb\xa9\x04\x7c\x7e\x66\x0b\xa5\xc6\xbf\x12\x6a\x9a\x59\x9e\x25\x71\xfa\x13\x50\x5a\xf7\x58\x1b\xfe\xbc\x16\x51\x3f\x5c\x94\xdc\x71\x93\x7e\x6e\x61\xb3\xea\x10\x93\x9b\x02\xea\x10\x85\x9f\x32\xd7\x91\x2b\x9e\x38\x06\xab\xef\x61\x85\xfc\xff\xa6\x88\x21\x47\x80\x05\xcb\xfc\x1d\x63\x7d\xd0\x20\x42\x56\x20\xa3\x18\x07\x48\x98\xbd\xc3\x09\x31\xc5\x9a\xc0\xc6\x6c\x4d\x12\x38\xb0\x97\xcd\x5b\x17\x0f\x08\x44\x35\xd4\xba\xe4\x8a\x03\xd9\x2f\xd4\x8f\xc2\xca\xa4\xff\xc5\x05\xf1\xbc\xa5\x16\xfb\xd6\xe4\xf8\x88\xcc\xed\x98\x2a\xe0\xdd\xb8\x8f\xc2\x8a\xa6\x97\xb7\x07\x1d\x01\x5b\x0a\xcb\x28\x09\xb0\x1d\x1d\x9c\x7e\x7b\x53\xee\xe6\x82\x4c\xc3\x7c\xce\x5b\x69\x93\xd8\x8d\x83\xea\xfc\x2e\x92\x8a\x6f\x14\x7d\xb6\xeb\x80\xb1\xa6\x9f\x01\x60\x5b\x04\x6b\xd2\xfd\x1d\x92\xc5\x45\x9d\x6d\x33\x98\xa9\xca\xa2\x99\xdd\xd0\xc3\xba\x2e\x08\x94\x13\x07\xb1\x20\xcc\x13\x99\x2f\x70\x03\xac\xed\x14\xa4\xa4\xd9\x23\xbb\xb1\x2f\xc3\x93\xff\xcf\x92\x0b\x9f\x6d\x47\x75\xe9\x4d\x4a\x51\x22\x67\xfd\x26\xa6\x99\x7c\x60\x62\xb4\xc9\x90\x0f\x98\x62\xb9\xea\x0c\x8d\x7d\xf1\x9f\x05\xc2\xb6\x04\xaf\x5b\x98\x64\xfb\x27\x54\xa8\x07\x3b\xbb\xfb\x18\x23\x3e\x6e\x15\x0f\x72\xa5\x25\xe3\xa5\x76\x0f\xcd\xa7\xd3\x2a\x60\x03\x4f\x95\x6e\x3c\xbd\x34\x36\xc2\x00\x83\x0b\x3e\x7a\x14\x57\x12\x20\xbc\xb6\x27\xd5\xa4\xbe\x72\xc2\x0b\x23\x35\x1b\x2d\x92\x06\x02\xa5\x1c\x3e\xb3\x2c\x12\x37\x03\x9d\xfb\xff\x43\xc9\x87\xfd\x85\x63\x77\x7f\x0e\x5a\x39\xf8\x14\x6c\x16\x4b\xdf\xfc\xe4\x4f\x3b\x13\xee\x74\xd6\x4b\xfd\xcf\x98\x03\xf0\x3d\xd0\x17\x2a\xc4\xfa\x4b\xf6\xc7\x83\x9c\xb1\x1f\x3d\x34\xba\xef\x0e\x32\xb5\x49\x42\xfc\x4f\xa3\x8f\x47\x3e\x29\x66\xf4\x91\x1c\x0e\x80\xd7\x69\x37\xb2\x5b\x76\x32\x27\x5b\xa8\x83\x09\x63\x5a\x60\xdf\x13\x54\x89\x20\x8d\x3e\x73\x4b\x67\x2e\xda\x7d\x2b\xa2\x15\x79\xab\xa8\xd8\x86\x0e\xa7\x64\xfd\x67\xea\xf9\xc3\x8e\xa7\x63\x7d\x1b\xad\x57\xb2\xf3\xd7\x82\xb9\x1e\x1d\x5d\x92\xac\x30\x0b\xdb\xa7\xab\x91\x13\xce\x91\x3d\x0c\x79\x3c\x12\xa9\xa7\x26\xe3\xfc\xab\x05\xcb\x47\x99\x77\x87\x16\x40\x63\x0d\x45\x9e\x69\xe8\x1c\xa5\xcf\x56\xdd\xb2\xa0\x61\x1d\x61\xd4\x81\xc1\xb8\xce\xf3\x80\x4b\xd4\xe5\x75\x4a\x61\xeb\x49\xb1\x7e\xf2\xb0\x3c\x83\x05\x7b\x5d\x20\xd8\x82\x05\x8c\x00\xf5\x4b\x6c\xca\x86\xbe\x95\x35\x0d\xd7\xbc\xb2\x5e\x4c\x1c\x46\x58\xf4\x52\x29\xc8\xbb\x9f\x5c\xdf\xcc\x44\x79\x5c\x97\x8e\x33\x88\xd3\x25\x76\x01\x06\xe5\x2b\xe9\x83\x4b\xd8\x1f\xfc\x5c\x62\x48\x6b\x6f\x33\xc2\x74\x59\xdf\x17\x8e\xb9\x46\xe7\xa8\x2d\xb9\xce\x0d\x29\x5b\x92\x5b\xb6\x12\x6d\xd5\x5c\x31\xf4\x9a\x68\xdc\xef\xc7"}, -{{0xf1,0x3c,0xaf,0xde,0x6f,0x39,0xb9,0x63,0xdc,0xa9,0x66,0x26,0x86,0x2f,0x4f,0xbc,0x5c,0x2e,0x00,0xdd,0xf0,0x8b,0xec,0xea,0xc7,0xa6,0xe2,0xfc,0xa9,0xe1,0xcc,0xf7,},{0xc1,0xb0,0x1a,0x91,0xe8,0xee,0x0b,0x9f,0x19,0xa7,0x2e,0x5e,0x7e,0x0a,0xef,0xcf,0xdc,0x44,0xa1,0x57,0x47,0x4e,0x99,0xfe,0xeb,0xd0,0xff,0x55,0x2d,0x73,0xb2,0xac,},{0x6c,0xa9,0xf8,0x0a,0x62,0x50,0x1f,0xaf,0x31,0x9f,0xb8,0x4a,0xf4,0x71,0xf6,0x76,0xae,0x3f,0xff,0x85,0x56,0x5c,0x97,0x98,0x1f,0x14,0x57,0xcb,0xb8,0xc4,0x9f,0x97,0xb2,0x66,0x31,0x6a,0x99,0x2d,0xb0,0xd4,0x2b,0xc5,0x02,0xf0,0x95,0xa5,0xf2,0xd9,0xa4,0xe1,0xcf,0xac,0x0c,0xc9,0x35,0xd3,0x88,0x2c,0x8a,0x3a,0x0e,0xa6,0xe1,0x0e,},"\x2b\xee\x73\xb7\x4f\x1b\x76\x22\xeb\x09\x6a\x28\xd8\x3a\x81\x9b\xce\xc2\x2d\x99\x99\xa3\x20\x62\x10\x3d\x60\x4a\xe6\xd7\x8e\xdf\x8f\x89\x38\x95\xd2\x22\x0a\xb7\x56\x90\x41\x0c\x58\xaa\xb5\x90\xa9\x8d\xdf\xf2\x3a\x94\xd2\x35\x0f\x88\x9e\x53\x46\x42\x00\xa5\x27\xd5\x4d\x62\x57\x11\x07\xb2\x7e\x57\x4f\x54\x2e\xba\xc2\x49\xb8\xe2\xe3\xce\x08\xd1\xbd\x27\xbd\x8d\x29\xf2\xe6\x12\x43\xde\xef\x0e\x69\x38\xe5\x2e\xe2\x99\x2f\xf2\x18\x7d\x7a\x7f\x52\x82\xed\xd9\x8f\xc4\x98\x5b\x61\x9a\xcb\x80\xaa\x9d\x03\xd6\xcb\x84\xb8\x21\x10\x6f\x40\xd6\xe5\xf4\xc3\x87\xab\x0a\xf6\xf2\x06\x61\x5d\x0a\x17\x5f\x7e\x60\xee\x27\x55\xae\xa3\x46\x75\xfd\xd8\x23\xeb\x24\x10\x9a\x9b\xd8\x18\xea\x2d\x9d\x9b\xd1\x99\xcf\x8d\xfe\x79\x62\x4b\x03\x72\xae\x85\xe9\x8c\x60\x20\x02\x34\xbd\x41\x3f\x4a\x62\xce\x68\xa4\x7b\x6c\x9b\x12\x85\x7c\x0d\x39\x9a\x44\x8e\x5a\x52\x80\xe9\xf2\x2f\x9b\x12\xea\x2c\xd3\xc6\x87\x13\xe7\x7d\x0a\x11\xf3\x62\x8d\x8e\xc5\xe0\x60\x63\x90\x31\xd3\xb6\x40\x02\x1c\x9c\x38\x80\x9d\xc5\xf4\x2d\x2e\x1c\x2e\x23\x46\xc8\x6e\x24\xee\xdc\x59\x84\xa1\x15\xa4\x2d\xe8\xde\x7e\x35\xc9\x91\x75\x39\xe8\x98\x85\xca\x91\x6e\x07\x2a\xfd\x5d\x46\x84\x6b\x2a\x93\x59\x61\xc2\xfe\x28\xe9\xeb\x3c\x8f\x89\x6b\x86\xfc\x12\x0c\xbd\x3a\xf2\xaa\x13\x9c\x49\x9d\x29\xcf\xc3\x69\x9d\xb7\x9c\x14\x48\x4e\x9e\xc2\x57\xa5\xf6\x43\x44\xb7\xad\x1e\x3d\xfb\x34\xee\xe7\x65\x4c\x6b\xf1\x2f\xd3\x8f\xbb\xa8\x0f\xe1\x76\x2a\xab\x57\x11\x2b\x3a\x94\xe2\xbe\xe7\x90\x41\xd1\xe8\x84\x40\xf8\x5f\xb7\x2d\xde\x68\xd4\x9e\x84\xbc\xed\x99\x8a\x2f\x63\x35\x44\x6e\x4a\x83\x5e\x70\xc5\xf8\x27\xfb\x3a\xd7\x82\x3d\x5f\xbe\x3b\xe5\xf6\xec\x7e\x43\x4e\xe5\x24\xcc\xd9\xff\x5b\x7e\x72\xa3\x2d\x09\x1a\x7e\x17\xc8\xb1\xae\x41\xa1\xaf\x31\x79\x3c\xce\x91\xd8\x4c\x36\x22\x67\x89\x69\xc8\xf5\x17\xdc\x26\xe3\xcd\x61\xd2\x44\x69\x12\x28\x3f\x93\x53\xbb\x5a\xd0\x3c\x11\x1c\x62\x33\xde\x31\x4c\x61\xb8\x31\xcb\xf3\x8b\x04\xfe\x58\xcf\x44\xf1\xd2\xd0\xb4\x5f\x25\xa6\xb4\xe0\x25\x68\x59\xcd\x5d\x83\x0f\xac\x5e\xc3\xc8\xd7\x63\x98\x55\x9e\x9b\x26\x01\x0f\x5e\x1d\xa5\xf2\x5d\x22\x00\x93\x54\x53\xff\xac\x5a\xea\x51\xf7\xe8\x1e\x72\xec\x8e\x5f\x04\xd2\xf8\x85\xc7\xb4\x5c\x63\xf6\x44\x56\xcf\xe2\x31\xb8\xcb\x24\xaa\x16\x20\xa9\x02\x63\x9c\xa7\x8d\xd3\x91\xaa\x4a\x3d\x03\xe1\x19\x75\xc8\x90\x7f\x96\x4f\xd5\x5d\xf9\xbb\xb1\x40\xe3\x8d\x6d\xb9\x32\x56\xb4\xb3\x9c\x2b\x7b\xcb\xe3\x5b\x11\x82\x6b\xbf\x8c\x08\xf1\xdc\xb4\x8e\xdc\x4b\xfb\x70\x46\x2a\x35\xea\x8c\xd8\xcb\xa7\x9f\xab\x8b\x4c\x44\xe7\x3b\xe7\xec\xfa\x11\x21\x66\xf6\xdc\xab\x70\xd8\xbb\x55\xd8\xb8\x42\x8c\x2d\xa7\x1a\xac\xa2\xfc\x3d\x90\xf3\xcc\x5e\xd0\x15\x51\x35\x8d\x60\x78\x9b\x9d\x57\x1e\xfe\x10\x89\x20\x27\xfa\x37\x40\x4a\xaf\x59\xec\x1c\x2d\x71\x11\xec\xc3\x59\x24\x67\xed\x1d\x9b\x8a\xba\x8e\x22\x9e\x32\xd2\xa0\x0c\x19\xdb\x71\x87\xfb\xcb\x12\x20\x61\x96\x1c\x1f\xda\xca\x30\x7e\x9c\x9c\x9d\xe9\x72\xad\x51\x40\x2f\xa6\x7d\xc1\xc2\xa4\x03\xb3\xc5\xe8\xb1\xe2\x46\x86\x2d\x6a\xd6\xa4\x98\xdb\x6d\x76\x1f\xb5\x66\xf6\x06\x59\x42\xb6\x0a\xd4\xb4\x30\x9d\x18\x2b\xc5\x15\x4c\xfc\x36\x86\x31\x85\xa8\x7e\x23\xab\xaa\x1d\x54\x1a\xb7\x63\xa4\xa1\x06\x6c\x0a\x7a\x8c\x3d\x82\x1a\xe3\x2f\xd3\x1c\x88\x92\x40\x10\x46\xd0\xa2\x0e\x91\xa6\x47\x79\xf4\xbd\xa8\x11\x20\xaf\x3f\xb3\x48\x6d\x3f\xc0\xa7"}, -{{0xc8,0x46,0x34,0x42,0x61,0xa3,0x48,0x65,0x39,0x38,0x34,0xbf,0xaa,0x3a,0x15,0xa3,0xf5,0x3a,0xc9,0xe1,0x38,0x33,0xb0,0xb2,0x87,0x12,0x27,0x81,0xb7,0x9d,0xe3,0x92,},{0xeb,0xad,0xe0,0x22,0x61,0x95,0xae,0x25,0x4b,0x61,0x15,0xe2,0x16,0x96,0xa9,0xc6,0x5a,0x19,0xd5,0xe0,0x40,0x44,0x31,0x31,0xc2,0x2b,0x89,0xf0,0x2f,0x69,0xab,0x78,},{0xd5,0xe4,0x1b,0x47,0xad,0x0f,0x34,0x00,0x70,0x97,0x70,0xed,0x43,0x91,0x9b,0xaf,0xdf,0x24,0x38,0x1b,0x66,0x15,0x44,0xe5,0x1d,0x8b,0x5c,0xee,0x9e,0x97,0xb3,0x67,0x6a,0x4c,0x0f,0xfa,0xeb,0xb2,0xcb,0xd2,0xdb,0x79,0x85,0x32,0xb6,0x5c,0xf6,0x54,0xa5,0xb6,0xc1,0x66,0xef,0x88,0x6c,0xb0,0xfb,0xbf,0x4a,0x4f,0x84,0x4c,0x44,0x0b,},"\x5a\xbd\x13\xe9\x5b\x6e\xe1\xd5\x51\x47\x68\x28\x22\x00\xa1\x4f\x7d\x1a\x57\x1f\x34\x68\xe2\x2e\xfe\xc9\x93\x46\x30\x66\xa3\x7a\xec\x83\x73\xe5\xfb\x49\x95\x64\x19\x1f\x32\x94\xa9\xb3\x0a\xfb\x5f\x1a\x34\xd4\xd8\x8a\xbc\x3e\x9b\xc3\x03\xc1\xab\xa0\x5b\xd8\xfa\xca\x90\xee\x35\xd9\x7a\xc3\xdd\x91\x06\xf6\xfa\x3c\xa8\x1a\x38\x10\xec\xce\xfa\x6a\x20\x9e\xa3\xf3\xfc\x30\x49\xdc\xb1\xb0\x03\xc7\x28\xf7\xf6\x37\x4c\xa9\x8c\x58\x2d\xe6\xdb\x1a\xf7\x60\xf0\xa0\x21\x33\xca\x4a\x01\x03\x24\x30\x4d\x26\xa0\xe5\x0a\xf0\xd1\x3c\x13\x4d\xa3\x4a\x03\xa4\x1e\x83\xec\x8f\x10\xea\x5b\x85\x9b\xec\x1f\x51\xb0\x1c\xab\xb2\xd1\x6c\x1f\xc5\x2b\x05\x8f\x8e\x5d\xef\xae\xde\x12\x81\x71\xc2\xe0\x26\x90\x23\x16\xf8\x71\xb3\x5e\x32\x92\x65\x6f\x0e\x5b\x39\xbb\xbc\x81\xd0\xc0\x83\x0e\x6a\xc0\x1f\xac\x9b\x45\x39\xf4\x7f\x9a\xcf\xbd\x58\xb7\xab\x9f\x5a\x12\x56\x00\xf2\x51\xa2\x71\xd7\xbf\x16\x7f\x29\x54\xca\x8e\x1e\x0c\x96\xe1\x6b\x06\xe8\x30\x7d\xf8\x8b\xb8\xe9\xd5\x7d\x5b\xa0\x44\xf2\x7f\x3e\xaf\xf8\x1d\x9f\x15\x05\x54\xaa\x71\x22\xfd\x10\xd1\x1f\x35\xd2\xbe\x2b\x16\x24\xe3\xe1\xa1\xd7\x7f\xea\x4c\x5c\x7f\x8b\x98\x3e\x94\x5b\xa8\xc0\x8d\xc1\x54\x5b\x3e\x6b\x29\x73\xad\x04\x1c\x44\xd0\x61\x7e\xcc\xc8\x71\xa3\x82\x1a\x9f\xfe\xa9\xdb\x7c\x2b\x0d\x05\x5d\xa5\x5d\xe0\xb3\x50\x63\xe4\x22\x5a\xee\x6b\x22\x5a\xb2\xa7\x90\x6a\x8e\xe3\x29\xd1\xb3\x97\x2e\x0d\x1f\x70\x81\x7c\x50\xcc\xfe\x94\x03\xd1\x2a\xd6\x2c\x94\x92\x3b\x9a\xa2\xd7\xf8\x5a\x8d\xda\x47\xbe\x4d\xce\xc0\xdc\x2b\x0b\x58\xf7\xac\x19\x0a\xe0\x57\x9b\x9b\x13\xbb\xb8\xb1\x6a\x31\xb0\xab\x4d\x6f\x27\x91\x25\x3a\xb4\x75\x1b\x53\x6b\x88\xd3\xb4\x93\x7c\xc3\xa1\x10\xaa\x82\xa6\xff\xed\x68\x53\x52\x4b\x66\xb3\xef\xfc\xd2\xf6\x3c\x6f\x96\x45\xce\xa1\x3a\xa2\x3c\xd1\xc9\x9d\x9f\xfd\xa4\xcd\x3a\x9c\x5d\xf4\x5e\xc7\x47\x26\xc3\x47\x11\x28\xb7\x08\x9f\xbd\x82\x69\x4d\x2d\x3f\x08\xdc\x93\x06\xc0\xfc\x9c\xe7\xc8\x01\x13\x8e\xb1\xec\xb7\x56\xe5\x71\xe9\x05\x9b\x75\xed\x03\xf9\x2a\x31\x50\x2f\xbe\xb5\xfe\xc5\x1d\xe9\x35\x90\x10\xc4\x39\x7d\x28\xb6\x5e\x35\x6e\x38\x00\x1d\x0d\x51\xac\x96\x00\x72\x8c\x78\xb5\x76\x6e\x0f\x21\x79\x38\xb4\x10\xe7\x85\xb4\xc0\x1e\x86\xa3\x45\x2b\xcb\x38\x84\xac\xa4\x75\x40\x85\x9c\xc4\x9b\x00\x0f\x0b\x61\xfd\xbe\x72\x75\x25\x74\xb2\x7a\x22\xd4\xc4\x04\x13\xa4\x3b\x31\x09\x24\xb1\xbb\x14\x0f\xc9\xfd\xaa\xe2\x66\xd6\x59\x30\xe3\xf2\x34\xfe\x84\x1d\x82\xb2\x61\x76\xff\x86\xc5\xd2\xbd\x8d\x96\x5c\x52\xd7\x28\x06\x4e\xbd\xf6\x8d\xc8\xe4\x83\x49\x41\x80\x1c\xca\x0b\x2f\x25\x6d\x4f\x6c\x3d\xd1\x9d\x35\xd5\x36\x2b\xbf\x9b\x8a\x3a\x1c\x86\x3e\x09\x26\x89\xdd\x28\x52\xad\xd4\x88\xbf\x42\x68\x5b\x11\xe1\xe1\xad\x57\x45\xd0\x75\x62\x8d\x73\x1f\x91\xcf\xd7\x49\x15\x9e\x2e\x1c\x83\x7f\x4e\xf8\x3d\x80\xea\x1d\xd9\xbd\xed\x5f\x88\x01\x8c\xe1\xd4\xb3\x37\x1f\x95\x43\x53\xf3\xd8\x94\x37\x00\x62\xc0\x96\x5d\x67\x98\x6d\xbc\x48\x17\x15\xf4\x2d\xd2\xc9\x16\x07\xab\x8b\x5f\x0d\x89\xf6\x6e\x68\xd7\x3d\x50\xd6\x40\x52\x4d\x72\xe6\x91\x34\xb8\x87\x29\x8e\x5c\xd8\xc4\xb9\x05\xba\x5e\xfa\x0e\x9d\x68\x52\x14\xb8\x42\xf5\x0a\x2a\x39\x83\xa1\xaf\x58\x5a\xf2\xca\x43\xdb\xcf\x02\xc4\x08\x97\xae\x2e\x1a\xb5\x1d\xbc\xe5\x70\x34\x5e\x8e\x13\x5f\xb7\xb4\xeb\x0a\x1d\x6a\x0b\xb5\xa8\xa1\x80\x7e\x42\x5b\x2d\x62\x83\x60\x76\x80\x58\xe6\x1a\xd1\xcf\xaa\x20\x99"}, -{{0xfa,0xaf,0x55,0xd3,0xc2,0x97,0x14,0xb6,0x5c,0x22,0x81,0xe2,0xc2,0x2d,0x61,0x34,0x97,0x1a,0x2e,0x74,0x00,0x8f,0xb9,0x40,0x89,0xa7,0x73,0xee,0xeb,0x44,0x83,0xa6,},{0x39,0x86,0x2e,0xac,0x6d,0xd5,0x2e,0x38,0x1b,0xb3,0x4d,0xc1,0x96,0xba,0x8a,0x37,0x4d,0xcb,0x7d,0xf6,0xcb,0x14,0x0f,0xd0,0xcf,0xa6,0xcf,0xa3,0x9b,0x8c,0x75,0x3f,},{0x5b,0x00,0x83,0xf7,0xa8,0x20,0x61,0xc6,0x5c,0xf6,0xc7,0x56,0x40,0xc8,0x1c,0x28,0xe8,0xd6,0xd2,0xe8,0x7f,0x6d,0x57,0x95,0xc9,0xaa,0x3b,0xb3,0xe3,0x90,0xe9,0x19,0x90,0xe8,0x2d,0xb6,0xf0,0x7e,0x61,0x4f,0x50,0x7a,0x56,0x0a,0xba,0xa1,0xec,0xa6,0x56,0xc6,0x78,0xdd,0xca,0xe8,0x19,0x82,0x51,0xe6,0xaf,0x0b,0x76,0xb8,0x8d,0x0d,},"\x94\xe6\x61\xc2\x52\x40\xa8\x9e\x82\x3d\x7f\x5d\xc0\xe6\x92\xed\xdd\x13\x70\xc3\x5a\xc4\x4d\x5a\x8c\x87\x98\xd0\xc9\xaa\xfd\xf0\xbb\xfb\x54\x92\x60\x56\x8d\xba\x1c\x69\x08\x6b\xee\x63\x6b\xe8\xed\xcc\xd3\xcb\xb2\x70\x16\x24\x4d\x54\xd7\xed\x2f\xeb\x7f\xa6\x46\x14\xd4\x54\x49\xd7\xe0\x58\xe7\x1b\x30\x6c\x22\xe6\x91\x1c\x2a\xc7\x42\x07\xba\xe5\xa8\x4d\x0f\xc2\x47\xbe\x49\xd3\x56\xe5\xd4\x35\x3b\xa5\x58\x6b\x6e\x4b\x2b\x97\xce\x9e\x23\x77\xb6\xee\xd9\x2c\x84\x9e\x67\x69\x44\xae\x90\xdc\x42\x08\xe3\x00\xe1\x9c\xc9\x1d\xc2\x6b\xbd\xd5\xa3\x0c\xfa\x92\x81\xa1\x5e\xfd\x87\x30\x66\xf8\x5a\xf3\xa2\x6f\x31\x06\x23\xe0\x09\x80\x48\x53\xcc\x68\x55\x90\x3e\xa6\x4a\x90\x98\x97\xe3\x15\xe7\x3d\x31\x29\x48\x98\x0e\xf6\x28\x9d\xb2\x1a\x5e\xbb\xec\x8c\x8e\xfe\x20\xd1\xd5\x3d\xfa\xad\x6d\x9f\x42\x96\x53\x2e\x88\x7c\x37\x35\x01\x05\xa6\x33\xab\xc7\x73\x18\x87\x51\xb2\x8c\x3a\x08\xf1\xb5\xee\x04\x72\xde\x46\x27\xe6\xb6\x1b\x68\x27\x8d\xd5\x1c\xed\x6a\x61\xec\xf3\x88\x86\xe4\x53\x39\xdc\x6c\x60\xc3\x1e\x85\x0e\xf8\x29\x6a\xe8\x0f\x9d\x31\x70\x17\x76\xeb\x9a\xf2\x16\x93\xf4\xc5\x2e\xc0\x62\x62\x57\x38\xd4\xe3\xaf\xbf\x71\xd1\xc8\x1f\xc4\x84\x63\x60\x36\x3e\xa5\x41\xa9\x76\x62\x3a\x5e\x4e\x6b\x6a\x67\x23\x7e\x92\x37\x17\x3f\x1a\x1d\x54\x33\x02\x85\x88\x85\x71\x4c\x2a\x59\x1d\x0a\x78\x62\x82\xa0\x28\x5a\x37\x11\xf7\xbc\x2b\x63\xca\x79\x87\xe9\xae\x7d\x02\x03\x55\x55\xcf\x3b\x6a\xd6\xf7\x1c\xa9\x8a\xa9\x28\x88\x3b\xf8\x1d\xd6\xf8\x64\x93\xea\xab\x56\x37\xb4\xdd\x56\x9d\x1e\xe8\xde\x6a\x44\xbc\xed\xb6\x2b\x97\x06\xb1\xdb\x89\xe3\xf0\x5d\xf1\x63\x10\x01\x7d\x89\xef\x3e\x4b\xc0\x99\xb7\x21\xa5\xc8\xd3\x80\x43\xd6\xe4\xa2\x2c\xf0\x40\x09\xc0\xfc\xee\x6b\xe6\x99\x37\x82\x99\x54\x94\x1b\x8b\x4a\x1e\xbf\x4d\xae\xa0\xd7\x74\xd0\x78\x2b\xe1\x76\xc8\xe5\x91\x90\x77\x56\xc2\xcf\x75\xde\xa6\xf7\x87\x7d\xd6\x87\x5b\x8f\xe1\x01\x2f\x30\x50\xcf\xb1\x28\x9c\xf0\x88\x66\x7e\x15\x22\xee\xed\xc9\x27\xac\x86\xbf\xe2\xc4\x07\x43\x2b\x4a\x81\x3a\x6a\x7a\x55\x04\xe9\x99\x20\x6d\xb1\x82\x7e\x25\xfa\xfd\x70\xce\xd3\x6d\xb3\xb2\x81\xb6\xf7\xb1\x4e\xd5\xba\xa0\x57\x23\x15\xa9\x39\xc5\xbf\x4a\xbb\x13\x3d\x2e\x7b\x16\xd5\x2d\xe2\x08\x17\xaf\x05\x5d\xf5\xf1\x41\x20\x77\x34\x61\x0a\x0c\x6e\xeb\xed\xaf\xff\xd9\xcc\x9f\x06\x9b\x67\xf9\xa1\xc0\x45\x4b\xe4\x1d\x54\xc1\x38\xbe\x54\x2e\x5e\x38\xcf\xe2\xf2\x93\xf7\xd2\xd3\xdf\x66\x97\x7a\xcb\x36\x6a\x42\xc1\x9b\x31\x85\xac\xfa\x1b\x36\x3c\x61\x31\xa4\xa8\x11\x1c\x3b\x1f\x4f\xd7\xac\x40\x6d\x0e\x69\x10\x3b\xa1\x5b\x8c\x4b\xf2\x9b\xc2\xed\x9c\x45\xcf\xd1\xd2\x79\xd8\xd9\x31\x44\x4b\x2b\x18\x49\x25\x2b\x8a\x70\xee\xd8\x0f\xd2\x60\xed\xf5\xa3\xc0\x1b\x96\x90\x16\x0d\x23\x11\x85\x1d\x21\xc9\x30\x2d\x98\x59\x86\xea\xee\xb3\xae\x2c\x07\xc7\xc7\x67\x20\x94\xf9\x1d\xb0\xbd\x50\xbe\x37\x7e\x4d\x1e\xb0\x7e\xe7\x6a\xf4\x9d\xc1\x36\xa1\x45\xa1\x1b\x17\x2f\x08\x11\xfe\x73\xd6\x25\x9b\xe3\x70\xc4\xdf\xca\xb6\xf1\x9e\x4a\x64\xb1\x51\xd0\xa6\xdb\x80\x50\xc3\xde\x2c\xc3\x25\xf5\xc5\xf6\x59\x4c\xf6\x24\x8e\xb0\x81\x20\x95\x39\xe0\x8c\xa3\x42\x29\x84\xe7\xbf\x80\x3d\xe3\xa4\x19\xb1\x44\x23\xf1\xe5\xa5\x42\x24\x04\x2c\xe4\xf0\x54\x88\xa6\x04\x4f\x40\x42\xbd\x64\x9b\x1a\x08\xce\x10\xc2\x00\x6e\xa7\x6e\xfa\xb4\x64\x1f\xef\x28\x97\xef\xd7\x24\xe6\x05\x4a\x3b\xd1\xa6\x9e\x39\xa4\xa5\xe2\xd5\x02"}, -{{0x6d,0x78,0x55,0xe3,0x0f,0x7a,0x13,0xe2,0x37,0xb0,0x67,0x14,0x43,0x46,0x43,0x4b,0xb4,0xb0,0x51,0x78,0xc7,0xd8,0x8d,0x49,0x2e,0x79,0x02,0x7c,0x4b,0x0f,0x3c,0xdd,},{0x72,0x73,0x29,0x38,0x28,0xef,0xa3,0x49,0x82,0x23,0x92,0xdb,0xba,0xb0,0x78,0x79,0x57,0x7e,0x1a,0x77,0xa6,0xfd,0x6a,0xfe,0x33,0x75,0x3a,0x9e,0xec,0x88,0xc4,0xaf,},{0x0f,0xe2,0x8e,0xad,0xd9,0xe5,0xdd,0x57,0x4b,0x3f,0xaa,0xea,0x81,0x0d,0x44,0x52,0x2c,0x8b,0x1b,0xfb,0xb3,0xe3,0xd5,0x7e,0xd8,0x89,0xfa,0xed,0xec,0x91,0xd0,0xe1,0x4a,0x86,0xb9,0x14,0xc4,0xc7,0x66,0xf1,0xbf,0x9b,0x8f,0x18,0xb0,0xdb,0x89,0x0d,0xb6,0xc1,0xb1,0x25,0xd5,0x78,0x04,0x33,0x36,0x19,0xb1,0xe0,0x72,0x0a,0x33,0x00,},"\xf8\xb9\x36\xe7\x93\xb0\x17\x58\x0c\xc0\xe9\xcb\xda\x2a\xcb\x64\x74\x50\x7f\x4b\xca\x3a\xfc\x87\x83\xec\x46\xee\xb8\x2c\xcd\x4d\xd2\x52\x56\x76\xaa\x6a\xb5\xc0\xdc\xf7\xd7\x5f\x7e\x03\x11\xe6\xfe\x6b\xf2\x72\x63\xf8\x57\x8f\xeb\x55\xc5\x61\x2d\x1f\x28\xe8\x88\xb7\x66\x56\xc4\x1c\xcd\x8a\x70\xb9\xbc\x60\x4b\x42\x72\x4f\xa2\xbc\x41\x1d\x44\xc3\x1a\xb6\x8c\xe8\x4f\x83\x93\x39\x9e\x34\xd5\x40\x85\x79\xc2\xba\x29\x21\xf2\xf8\xd1\x14\x87\xaa\x7e\x52\x55\x7f\xee\xd9\x67\x57\x19\x9d\x3a\xae\x63\x77\x77\x01\x54\xb1\x7f\x35\x77\xc7\xac\x3d\x8c\x76\xcf\x74\x61\xb5\xe8\xd4\x2a\x71\x85\x07\x8e\xd4\xf8\x62\xfc\x57\x50\x2f\x61\x50\x75\x30\x7b\x6e\x10\x3c\x77\xc1\xf6\xc8\xbd\xa7\xaa\x17\xe4\x35\xe2\x1b\x94\x9a\xf4\x4d\xff\x5a\xa3\x0a\x62\xda\x71\x2f\xa9\x96\x6a\x61\x2f\xfc\xa1\x48\x71\xfd\x6f\x86\x0b\x4a\x96\x14\x01\x2c\x53\x69\x91\x0e\x0f\xfd\x6f\x0f\xbd\x88\x9a\x9c\x25\x7c\x32\xbd\xcf\x90\xbb\x80\x62\x7c\xb2\x72\xec\xd4\x59\x98\x97\x55\x59\x55\xe1\xfe\x08\xcd\x7e\xbb\x21\xc0\x71\xbe\x0f\x48\x98\x96\x96\xcb\x39\xaa\x82\xad\x11\xba\xa5\xd4\xac\x61\x3a\xbf\x1b\x6d\xb8\xa2\x0e\x68\x68\x36\x22\x28\x33\xf8\xb6\xdd\x2f\x00\x06\x22\x7b\xe4\x8e\x85\x80\xdc\xc8\xde\x62\x0d\xac\xb2\xf6\x5a\x69\x36\x75\xd6\xcb\x45\xba\x5d\xd1\xaa\x70\xdb\x76\xbc\x64\x1d\x4f\xb5\x67\xec\xbc\x71\x11\x44\x2e\x29\x41\x58\xbe\x57\x5c\x71\xdd\xc2\x6e\x94\xf4\x12\x66\xa2\xfd\x3a\x0d\x43\x57\x81\xfc\x09\x46\x48\xfa\xdf\x5f\x17\xcd\x41\xab\x89\x58\x21\x89\x4e\xc0\x80\x6b\x26\x2c\x39\x35\x34\xfe\x66\xf2\x1e\x37\x83\xc1\x4a\x96\xc8\x8f\x2e\x06\x53\xfe\x32\xe7\x5d\xce\x8a\x46\x3b\xb9\x7e\xed\x6c\x16\xf3\xf3\x22\x81\x69\xab\xb5\xb4\xbf\x9e\xa3\x27\x8c\x1f\xf0\xf8\x6e\xae\x71\x38\x9b\x64\x33\xac\xd0\x97\xee\xfa\x9e\x6e\x05\xf4\x95\x5c\xd5\x17\x83\x0b\x8d\x98\x70\xcc\xb5\x22\x74\x15\xe5\x0f\x23\xf6\x47\x32\x17\xa7\x45\x09\x64\x70\xdc\xa9\x3d\x2b\x34\x67\x3c\x5d\x6a\x57\xed\x02\xc8\xe0\xca\xe1\x19\xb3\xf3\x29\xd8\xab\x64\x98\x49\x4c\x29\x21\xbb\x6f\x49\x6d\xd0\x83\x81\xe7\xd3\x9f\x2d\xb5\x76\x3b\x14\xa2\x82\x1b\xef\xcc\xa0\xa9\xfd\x31\x25\x45\xde\x68\xab\xf2\x06\xd1\x2d\x8e\x02\xe7\x3b\xc7\xe3\xcb\x79\x6e\x7e\xe2\x6c\xc6\x3d\x74\x1e\xfa\xfc\x53\x45\xf8\x13\x29\x51\xbc\xfb\xfd\xdf\x63\x1f\xb7\xcb\x43\xef\x35\xb9\x45\x3c\x93\x90\xeb\x23\xb1\xf9\xd8\xb1\xc7\x2d\xeb\xd2\x4f\x09\xa0\x1a\x9d\xc6\x0e\xe6\x81\x53\x06\x18\x83\x57\x78\x1a\xf6\xe1\x82\x0a\xa3\x5e\x4e\xc1\x21\xb7\xca\x34\xd7\xde\x76\x11\xb2\x46\xa3\xe7\x03\xed\x48\xc7\xeb\x03\xa6\xfe\x8f\x85\x2e\xe7\xd3\x25\x45\xc9\xd8\x52\xd6\x4d\x5d\x75\x93\x0e\x5f\x1e\xbe\x21\xa3\x07\xef\xa7\x62\x2e\xda\xce\xd6\xd8\x79\x02\x6f\x0f\x85\xa9\x11\x20\x12\x80\x37\x05\x58\x22\x69\xd3\x9f\x14\x32\x34\xdf\x89\x09\xab\x3d\x94\x8e\x76\xd3\xda\xaa\x24\x22\x6d\x9a\xc6\x01\xee\xf2\x77\xfd\x2c\xfc\x4a\x19\xae\xdf\x43\x87\xa2\x16\x17\xb0\x3e\xc3\xd3\x84\x5a\x38\x55\x4f\x5e\x97\x03\x6e\x56\xec\x1c\xe6\x60\xdf\x9c\x06\x2c\x2c\x99\x3b\x77\xc5\xba\x6a\x6d\x05\x23\x1d\xae\x37\x64\x18\x3c\x3e\x96\xaa\x53\x9c\xfb\x34\x15\xfb\x16\x3c\x64\x5b\x23\x03\xb2\xd6\xd4\xbd\xa8\xca\x6c\x72\xbc\x03\xd5\x30\x5f\x9b\x11\x8e\x92\x5e\x27\xd2\x9a\xb7\xdc\xb1\x96\x47\x0e\x63\x39\x63\x1b\x23\x80\x74\x4c\x04\xd1\xda\x34\x8f\xc0\xfe\x27\x42\x77\xf8\x2f\x95\xbd\xfb\x0b\x64\xb4\xcf\x3b\x51\xe5\x71\xc0\xdd\xb3\xb5\x3c\xa6"}, -{{0x7e,0xe4,0xe7,0xe9,0x8c,0x6a,0x40,0xf0,0xe7,0x44,0x13,0xf2,0x40,0x39,0xbd,0x22,0x0d,0xf1,0xf8,0xc7,0xf0,0x15,0x52,0x8d,0xbf,0x52,0x84,0xab,0x9f,0x7c,0x82,0xe2,},{0x4d,0x5a,0x80,0x0f,0x9b,0x22,0x07,0x0e,0x01,0x6e,0xe2,0x3a,0xf8,0xa3,0x10,0x90,0x2b,0x36,0x9d,0x58,0x9a,0x84,0x7f,0x34,0x5c,0x2e,0xa2,0x96,0x8d,0x6d,0x09,0x24,},{0xac,0x3b,0xfe,0x3a,0xdf,0x94,0x1c,0x93,0x4d,0x33,0x49,0xc4,0x92,0xde,0x70,0xd5,0x16,0x6b,0xe3,0x89,0xf9,0x55,0xbe,0x87,0xc2,0x88,0x3f,0x41,0xf2,0xda,0x14,0x6c,0x91,0x06,0x51,0xa3,0xb4,0x52,0xc2,0xd7,0x39,0xdc,0x9b,0x53,0x1c,0x57,0x45,0x56,0x5e,0x69,0xd9,0x83,0x59,0xf1,0xd7,0xd9,0x3e,0xbd,0x36,0xd7,0x0a,0xbb,0xf0,0x0d,},"\x8f\xb0\x13\x73\xc4\x2e\x69\x61\x4a\xea\x99\xaf\x49\x32\x37\x85\xf3\x38\x61\xb9\x4e\x90\xf5\x65\x38\x9e\xbf\x70\xe2\x19\xf5\xde\xc7\x32\xe0\x01\x0b\x58\xf7\x29\x05\x30\xdf\x22\x2a\xc9\xc7\x3e\x1c\x2e\x92\xa5\xe6\x06\x1d\xe5\x59\x0c\xaf\x9c\x0d\x50\x21\xd7\x29\xea\xa1\x15\x41\xfa\x1d\x08\x21\x60\xbe\xaf\x61\x1e\x7c\xfd\xc0\xeb\xb3\x15\xd3\x88\xe5\x38\xb4\xb5\x02\x8f\x9b\x30\xd3\xd9\x73\x34\x7f\xfd\x44\x26\x3e\xef\x08\x3b\x81\xb2\x1b\x82\xec\xa5\x75\x6a\x49\x4b\x1d\x81\xc0\x7d\xe8\x49\x50\x6d\x3e\x3b\x66\x87\x97\xa5\xc5\x44\x25\x4d\x4e\xbe\x5c\xf8\x17\x1b\x39\xf8\x72\x4c\xbc\x41\x89\x29\x1b\x3c\x53\xc2\x1e\xce\x49\xa1\xd7\x39\x56\x3c\x65\xb4\x90\x25\x93\x56\x47\xa7\x30\x3a\xe0\xef\x7f\x6d\x24\x55\x46\x45\xa4\x28\xdb\xbb\x42\x44\x9f\x53\x99\xe3\x6d\xc7\x87\xb7\xd6\x95\x8a\x02\xee\xbb\xb8\x36\xe5\xe5\x3e\x26\xe4\x87\x23\x9d\xe9\x4d\x1d\x25\x0e\x79\x43\xac\x0e\x22\xd9\x27\x50\xa0\xcf\x34\x73\xbe\x1a\x62\x25\xcb\xe7\x95\x45\x04\x82\x69\xf6\x23\x7e\xc9\xf9\xec\x30\x7e\x8a\x34\xb7\xbb\x34\xcd\x49\x06\xe4\x31\x62\xa3\x70\x8f\x32\x9c\x5b\x98\x9d\x7a\x7f\xcd\xe1\x09\x9a\x54\x25\x46\xfe\x9c\x33\x18\x2b\xa5\x1b\x84\x3e\x96\xd1\x1c\x79\xe9\x1a\xd2\x1f\x71\x70\xe2\x57\xfd\xc2\x81\x8e\x12\xf9\x16\x8a\x97\x4c\x96\x8a\x4d\x27\x3f\xa3\xff\xa9\xf3\x5f\xf9\x05\x98\x0e\xaa\xd3\x72\x1c\xae\x80\x2b\xee\x36\x21\x0b\x40\xb9\x93\x19\xbb\x66\x99\x82\xe9\x43\xb2\x70\xa4\xc4\xd0\xa9\x2e\xcb\x5b\xba\x2d\xd8\xb4\x0a\xc3\xd2\xf0\x32\x5c\x46\x9d\x5e\x9d\x48\x3f\x52\x41\x97\x40\x10\xc5\xc0\xda\x33\x5f\x16\xe9\x62\x19\x6c\x2e\xf1\x4e\xb2\x4a\xaf\xbb\x31\x1b\xfd\x5f\xa8\xdc\x8d\x2d\x61\xe6\x87\x8a\xd2\xcc\xe0\xdc\x99\x39\xe4\x45\x22\x72\x3d\x42\x7e\xf3\x2f\xb4\x3b\x96\x7f\x5e\x44\xfc\x66\x57\x92\x79\x6f\x8c\xf9\x34\xf0\x1c\x32\x5d\x63\xd5\x83\xdc\x3c\xa9\xd4\xfc\xc7\x57\xd9\x17\x85\x80\xda\xef\x53\xaa\x3a\xb2\x1d\x2c\xe4\x35\x95\x5d\x1c\x6d\x47\x63\x8c\x5e\xdb\x62\xff\x55\x61\x69\x3d\x1c\xbd\x10\xec\x9e\x39\x9a\x71\xbf\x9d\xb1\xc9\x96\x9f\xd5\x9e\x4e\xeb\x31\xaa\x59\xbf\x39\xe9\xf1\x84\x17\x8d\xef\x72\x46\xed\x4b\x8f\x4b\xe5\xba\xda\xa5\xdb\x4a\xf8\x67\xf4\xf2\xec\x39\xa1\x37\x04\x20\x2c\x87\x84\xfa\x16\x8c\xe9\x6f\x9c\xfa\xc7\x10\x17\x23\x62\x75\xfd\x85\x7c\xc3\xc5\x1a\x9c\x7a\xc2\x56\x21\x5e\x14\xb8\x43\xf7\x21\x4d\xc9\xf8\x24\xb9\x1d\x1a\x51\x70\xd0\xef\x1d\x37\x69\x6f\x93\xee\x96\x6a\x2b\x7d\xec\xe2\x2b\x4f\x3a\xfd\x39\xc1\x6d\x60\x1e\x5f\xf8\x40\x8d\x45\xc1\xa6\xce\x71\xf0\x60\x97\x6c\x5b\xe4\xc0\x42\xb1\xb7\x38\xdf\x95\x80\xba\x5a\xe7\x78\x80\xa7\x0c\x0b\x94\xf0\xe1\xc9\xf9\xaa\x34\xc0\x90\xd6\x12\xd5\x7a\x9b\x93\x1f\x50\xa1\x25\xfa\x35\xce\x40\xa2\xcb\x7f\xaa\xd5\x30\xf8\x09\x08\xc7\x3c\xb7\x82\x58\xaf\xd2\x63\x13\x90\x04\x1d\x92\x61\x7e\x9b\xf6\x4c\xe9\x6e\x8e\x4a\xc7\xf3\x12\x6d\x8a\xf8\xa0\x4c\x75\xff\xd4\x38\x76\x9d\xe0\x6f\x74\xc2\xfc\x20\xcc\x81\x92\xda\x35\x3e\x79\x06\x12\x83\xbb\xa0\x8a\x8d\x24\xe6\xe4\xe2\xe8\x3b\xa5\xb0\x8e\x42\x75\x22\x60\x62\x14\x8d\x8a\x02\xaf\xad\x65\xb6\xf6\x27\xcf\xbd\x29\xb7\x1c\xa1\x8a\xee\x5b\x1f\x97\x16\x9b\xf0\x22\x8b\x37\x6f\x41\x06\xb5\x0f\xd9\x1a\x38\xa6\x62\x11\xd6\x9e\xbb\x4a\x7a\xf0\xe1\xc2\x21\x7f\x1b\xa0\x14\xd1\xe0\xcd\x17\x50\x8d\x58\x15\x5d\x16\x3d\xd9\xde\x2f\xe1\xc6\x4c\x7f\x88\xd5\xb5\x53\xe9\xba\x1e\x1f\x25\x43\x0d\x7e\x12\x5b\x07\xa8\xc2\xed"}, -{{0x1f,0x28,0xd9,0x09,0x1d,0x19,0x6c,0xba,0x3d,0x45,0x52,0xe5,0xa3,0x37,0xa4,0xd8,0xaf,0x3f,0x29,0x5e,0x62,0x9e,0x4b,0xa6,0xfe,0x99,0x70,0x31,0x20,0xae,0x41,0xe0,},{0x81,0x4d,0x34,0xbf,0x28,0xee,0x6d,0x90,0xf0,0x39,0x59,0x90,0x41,0xdb,0x81,0x0f,0x7c,0x9d,0xaa,0x91,0x8e,0x03,0xe9,0x61,0x97,0x41,0x4b,0xc9,0xaa,0x31,0xec,0xdc,},{0x5b,0xe5,0x52,0xfa,0x73,0x1e,0x83,0x67,0x93,0xf6,0xdd,0xa8,0x95,0xdc,0x9b,0x1e,0x2c,0xcd,0x66,0x9d,0xe1,0xc8,0x43,0xe0,0x0e,0xa6,0xfa,0x3c,0x5e,0xbf,0x97,0xa3,0x4b,0x26,0xf1,0xf3,0xac,0x7f,0xf2,0x22,0x5e,0xe4,0xa7,0xe4,0x30,0x07,0x2c,0x13,0xda,0x40,0x66,0xdc,0xdc,0xc0,0x5b,0xa2,0xb5,0xf6,0x1a,0x6e,0x8d,0x21,0x07,0x09,},"\xa6\x94\x68\xbc\x33\xeb\xfe\xf0\x61\x5c\x64\x3c\x49\xda\xc6\xe0\x4f\xdb\x6c\xfb\x8e\xc4\x58\x57\xbb\xb7\xa2\x7e\x52\x8f\xd6\x31\xfc\x34\x11\xba\xee\x65\xcc\x1f\x94\xfc\xc9\x4a\xed\x4a\x43\x32\xfa\x68\x61\xe0\x65\xe0\x61\x63\x54\x17\x09\xd7\x97\x28\xe0\x1b\xe2\xb1\x40\xa0\x22\xc8\x3e\x7b\x23\xb9\xed\x2a\xd2\x83\x21\x69\xdf\xc9\x56\x90\x91\x3c\xf3\x72\x01\x30\x65\x70\x80\xc9\xd5\xa7\x82\x7e\x56\x60\x75\x74\x52\xc5\xfc\x3d\xcd\x80\xcc\x6b\xe0\x98\xc6\x29\x22\x6d\x54\x66\xe0\x2b\x97\x12\x6b\xe7\x4a\x14\x52\xee\x16\x81\x50\x95\xde\xb4\x2b\xf0\x65\x66\x71\x50\x28\xc1\x18\x25\x82\x0a\x8a\x23\xc6\x0d\xa2\xb6\x8d\xd9\xa5\x5d\xad\x2a\x29\xa4\x96\x44\x43\x81\x7c\x07\xd7\x76\xb2\x44\xb1\x51\x86\x81\x9a\x3b\xbe\xd4\x14\xab\xf4\x57\x9a\x3e\xce\x3a\x3d\xc7\xb1\x05\xd0\xa9\xdb\xa3\x7b\x9e\xaa\x78\xbe\x8e\x46\xe1\x69\x8b\x59\xb0\x94\x0b\x01\xf3\x8b\x28\x3c\x33\xa9\xa4\xb1\xd4\xf8\x14\x4b\x16\xee\xb5\xfc\x0a\x7a\xf0\xd0\x81\x69\x66\x45\xa1\xea\xb3\xa7\x87\xcb\xcf\x88\xfa\xd9\x3d\xd6\xcd\x46\xd2\x95\xa8\x79\xa1\x77\x50\x33\xa9\x85\x63\x82\x2e\xf1\xf6\xb6\x9a\x58\x1e\x49\x73\x6c\x8d\x70\x1b\x44\x53\x96\x93\x40\x52\x1e\x4a\xd4\xbf\x94\xb9\x11\xb0\xe2\xd8\x6f\x34\xee\xce\x4a\x63\x85\xff\x1f\xe6\x32\x20\xcd\x3c\xc5\x92\xf3\x6d\x6c\x49\x1f\xa1\x8f\x7c\x14\x04\x36\x0d\x2a\x77\x53\xfe\x07\x3e\x09\xa2\xfc\x42\xa4\xbb\xea\x55\xbc\x96\xd7\xf0\x5c\x98\xae\xd2\xcc\x4a\x9f\xae\x8f\xd4\xa0\x19\x7f\xf0\x1f\xa7\xf0\x04\x6e\x3c\x3e\xb5\x9a\xaa\xbc\xa3\x13\xa4\xdd\xaa\x5d\x20\xd2\x7c\x2c\x5f\x1a\xc6\xd8\x7f\xd3\xcb\x4b\xd3\x5a\x1e\xc7\x5d\x10\x4f\x7c\x36\x73\x31\xa3\xe2\x95\xe5\x3c\x4e\x80\xba\xe1\x4b\x97\x92\xd0\xd5\x26\xf7\x40\xd4\xff\x03\x6f\xaf\x54\x87\x96\x7f\xfa\xbe\x8e\x88\x3d\x3f\xb0\xd1\x6f\xaa\xdb\x28\xe1\x28\x5d\xed\x41\x57\x0c\x0b\x07\xc2\x55\x9b\x53\x1e\x0f\x92\x54\xef\x88\xe5\xb1\x0f\x64\xf4\x83\x9a\x9a\x0b\x6c\x3c\x7f\x1b\x78\x50\xf4\xad\x9b\xf0\x99\x9a\x7f\x2a\xe7\xc4\x5a\x65\x8e\xa5\x30\x36\xfc\x70\x19\x98\x42\xb8\xe4\x9e\x60\xf9\x67\xde\x1f\xf3\xab\xff\xf6\xcd\x73\x5b\x7c\xd8\xb8\xf9\xe2\x48\xf1\x56\xf6\xc6\x54\x38\x69\xeb\x99\x82\x3d\xae\xa8\x8d\xeb\xaf\x79\xf0\x1e\x65\x21\xec\x63\xfe\x72\x72\x4e\xe3\xc8\x22\xb8\x8b\x39\x68\xb2\x48\x52\x09\x15\x83\xc4\x9a\xb3\xc1\x5f\xa1\xf7\x9b\x18\xd9\x8f\x04\xd9\xb6\x84\x1c\x9a\x7c\xa0\xde\x2f\xcc\x02\xf9\x5d\xd6\x49\x49\x2e\x8b\x56\xa3\x1e\xc1\xe2\x44\x33\x7a\xf6\xaa\xae\xde\x8b\xf9\x9f\xc8\x14\xef\x57\xc0\xd5\xe0\x8c\x3c\x7e\xcc\x18\x97\x98\x0a\xa1\x69\xa9\x92\x6d\x20\x69\x8d\xf6\x93\x0e\x21\x10\xcb\x46\x0f\x49\x39\x01\x00\x74\x10\x95\xf8\xed\x00\x41\x2a\xe6\x96\xd9\x8e\xfe\xfd\x29\x0d\xa5\xf7\xd0\xb7\x28\xd2\x0a\x1e\xbf\xa6\xbd\x7d\x27\x0f\x28\x1a\x98\xc7\xb1\xe4\x08\x43\x51\x25\xaa\x48\x3c\x6b\x7d\x63\x3f\xf7\x58\x8a\x94\x16\x58\xf6\x12\x95\x44\xd6\x29\x45\xb9\xb8\xaf\x71\xa8\xc6\x2c\x0a\x50\x07\x6c\xb8\x54\x1b\xa7\xe4\xbd\xe4\xed\xe4\x41\x72\x2c\x6e\xb9\xdf\x8c\xfd\x06\x56\x33\x9e\x86\xd2\x26\xab\xae\xa0\x5e\xa0\x47\xf6\xb8\x30\x77\x01\xf6\xc9\xa4\x4c\xc9\xcb\x83\x7b\x8e\xb6\x24\x45\x92\x5e\x8a\x88\x81\xd2\x53\x8f\xcb\x2b\x24\x9e\x4e\xe8\xb6\x86\xec\xfb\x49\xc4\xdf\x86\x40\x1d\x24\x9a\xac\x35\x84\x1e\x91\x40\x04\xf9\x45\x5d\x3f\xde\x37\x5d\x20\xa0\x1f\xba\x27\xb1\x97\xa6\x98\xd3\x84\xc7\x65\x05\x10\x68\x01\x62\x7e\x83\x36\xbd\x2d\x76\xd7\x61\xa8"}, -{{0xc6,0x4d,0xd2,0x0d,0x42,0x62,0x75,0x26,0x19,0x8a,0x22,0x64,0x76,0x90,0xc8,0x95,0xb5,0xb4,0x5b,0x69,0x8f,0x57,0xa6,0x9d,0xfb,0xe4,0x8d,0xbd,0x42,0x6a,0xa4,0x70,},{0x2e,0x01,0xd4,0x04,0x16,0xf7,0x8a,0xcd,0xdb,0x34,0xb8,0x44,0x5e,0xa4,0xfd,0x0a,0xb3,0xfa,0x9e,0x66,0x43,0x04,0x47,0x52,0x21,0x3f,0x07,0xc7,0xf0,0xff,0x43,0xa0,},{0xde,0xac,0xc8,0xc2,0x32,0x18,0x72,0x76,0x76,0xd5,0x40,0xa2,0x3b,0xda,0xd7,0x81,0x02,0x11,0xe6,0xd5,0x7a,0xd2,0x94,0xc3,0x7d,0x4b,0x1c,0x9a,0xf6,0xb3,0x37,0xa5,0x3f,0x78,0x80,0xd2,0xba,0xfa,0x73,0xb3,0x05,0x08,0xc0,0x08,0x42,0x6b,0xf8,0xd7,0xc9,0x65,0xa1,0xf4,0xa4,0x22,0xa1,0xbc,0x7d,0x6a,0xd6,0x22,0x6f,0xd1,0x97,0x06,},"\x82\x1b\x9f\x7c\x16\x10\x4b\x53\x3b\xd1\x27\x18\x4f\xd7\x2a\xde\x09\x2b\x13\xbb\xd9\xac\xee\xd2\x9b\x8d\x10\xf1\x66\x88\x92\x2d\x16\x5f\x89\x31\xd5\x3d\xf5\x90\xfb\x71\x3b\x67\x4d\x80\x5c\xe0\xc9\xd6\xce\x6c\x43\xba\x69\x68\x19\x1d\x12\xbf\xa0\x8a\x8c\xe2\x2e\x8f\x33\x6b\x2b\x49\x1a\xf2\x5d\x1b\x16\x06\xf9\x30\xca\xeb\xe5\x22\x39\x2a\x87\xd4\x2c\xe7\xbc\x16\x7a\xa7\xb6\x10\x59\x72\x20\xaf\x31\xa6\x65\x35\x30\x71\xe8\xd9\xe5\xf4\x20\x78\xb9\xc3\x88\xbf\x04\x02\x58\xe2\x1f\x9c\x3a\xb3\x8c\x04\x27\x61\x8b\x2c\x28\xd3\x43\x0d\xf2\x79\x21\xbf\xc5\x84\x87\xb3\x46\x19\x78\xbf\xa8\xbf\x58\x6c\xfe\x83\x58\xe0\x92\xf8\xf4\x74\x66\xe7\x62\x45\x1d\x50\x16\x4a\x0d\x74\x36\x0f\x66\xb4\xcd\x3a\x35\x75\xda\x01\xda\x23\x75\x24\x30\xc0\x35\xda\x85\x9f\x57\x7d\xe2\x22\x90\xaa\xb4\xed\x7f\x34\xd2\x67\x40\x6a\xb5\x47\xeb\x44\x5c\xc6\x4d\xf5\x30\x19\x42\x7f\x4e\xb7\x2b\xca\x55\x39\x71\x53\xd0\x1c\xcf\x7e\xc9\x7d\x7a\x96\x7d\x9a\xff\x46\x23\x1d\x2e\x20\x27\xb3\x8f\x3b\x41\xbd\x2c\xb1\xb7\x98\xa4\xae\x88\xab\xf4\x89\x62\x16\xd3\x15\xbd\x53\x83\x02\x42\x59\xe5\x97\x42\x80\x2a\x91\x1b\xad\xcf\x84\x73\xdb\x91\xaf\x31\x97\x33\x32\x0c\xb9\x52\x1e\xf9\xce\x43\x72\x67\xb6\xea\x17\xbc\xaf\xe5\xd0\x90\x3b\x12\x3a\x35\xc9\x88\xf4\x98\x34\xf6\x1d\xd5\x52\x64\x0a\x32\x76\xda\x26\xaf\x17\xec\x21\xa2\x02\x96\x58\x6d\xd6\xf4\xb3\x6c\x7a\x4f\x0b\x89\x9d\x70\xb4\x2a\xf8\x9e\x29\x37\x01\x32\xed\xfb\x72\xd6\x83\x41\x94\xa1\x60\x93\x60\xb1\xf1\xfe\xab\x89\xb9\x6b\x8e\x8f\x0f\x68\x98\x7c\x57\xcc\xe0\xba\xb7\x68\x11\x37\x18\xfb\x17\x09\xde\x2d\xf3\x21\x77\xd4\x40\x85\xda\x5e\xfd\x9d\xa7\x0e\x1a\x85\x8c\x92\xf2\x45\xac\xfe\xe6\x4b\x71\xf3\xeb\x16\xe0\x4f\xc1\x39\x89\xe6\x93\x37\x99\x97\x01\xdd\x73\xab\xc2\x66\xc9\xfd\x4c\xff\x91\xa0\xfd\x04\xfb\xd8\xb1\x3b\x12\xe6\xf4\x50\x38\x57\x15\x84\x8e\x00\x7f\xa0\xd4\x63\x11\x9f\xd7\xde\x63\x25\xb6\x40\x04\x2b\x65\x42\x12\xe0\xdb\x8d\xa1\xad\xeb\xd2\xa7\x58\x9f\x77\xee\x4f\x75\x2d\x28\x2c\xa1\x11\x9c\x43\x1b\x17\xad\x0a\x02\x1e\xf2\xbf\x95\xe5\xac\x47\x04\xe6\x2d\x70\x39\xd0\xe6\x51\xe4\x56\xd6\x0e\x63\xba\xde\x40\x1c\xca\x77\xc9\xa8\x91\x63\x17\x4d\x50\x22\xd7\x45\xab\xdc\x76\xb9\xff\xe2\x54\x41\x55\x23\x5e\x30\x63\xe6\xe4\xae\xec\x44\xed\x5d\x8a\xb4\x08\xd9\x66\xfe\xc1\x20\x16\xc1\x30\x73\x0b\xbc\x55\x87\x32\x06\x5d\xa8\x00\xa7\x0c\xbf\xb0\xfc\xcc\xa4\x5d\x00\x28\xcb\xfd\x96\x32\xdd\xb2\xf0\xed\x12\xed\xae\x7b\x93\x0b\x10\x6c\x9d\x12\x85\xa4\xb8\x70\xde\x75\x07\x99\x9c\x74\x79\x3d\xd4\x97\x40\x87\x19\xc8\x98\xab\xe4\x9f\x7f\x33\xa3\x3e\x69\xb5\x0f\xa5\xaf\x94\x80\x06\x85\x66\xd1\xfd\xdf\x44\x82\xd7\x97\x04\xad\x8e\xf1\x1b\x88\xb4\x2c\xc6\x9f\xce\x8a\x55\x7b\x5b\xa5\x10\xe7\x08\xb9\x37\x51\x23\x03\x85\x68\x27\x0d\xe4\x07\x23\x2e\x95\x62\x1e\x2d\x04\x57\x0b\xec\x2c\x41\xec\xcf\xd8\x55\xb2\x1f\x0c\x9b\xba\xa2\x3b\x5c\x58\x15\xfc\x88\x8f\x7f\xbe\xd4\x82\xc3\x20\xff\xa1\xe0\x63\xe8\x7b\x55\xbc\x8f\x7e\xee\xa3\x74\x06\x3a\x9b\xe6\x5f\x7e\xd9\x22\x5b\xf6\xca\x34\xcf\xa3\x11\xb7\x9f\x3a\x25\x8c\x25\x2e\x63\x45\xed\x6a\xc8\x47\x48\xf4\x68\x07\xa5\x5d\x4b\xa4\x12\x66\x16\x9c\xd2\x62\xd4\xf7\x22\x79\xef\x0c\xaa\x77\xff\x44\x93\x35\x32\xbd\x13\x74\x75\x6c\x23\xec\x85\xf5\x5e\xfe\x9f\xc2\x33\x1f\x26\xf8\x81\x62\x9f\x80\xc2\x69\x2f\x7f\x53\xe4\xbc\x6f\x22\xef\xb4\x54\x57\xa2\x23\xf0\xd1\xc4"}, -{{0x0f,0x8e,0x9f,0x35,0x26,0xb4,0xfa,0xea,0x92,0x76,0xf2,0x2a,0x17,0x79,0xe6,0xf8,0x27,0x09,0x80,0x8f,0x6d,0x0c,0x61,0x2a,0xdf,0xe3,0x2a,0x6e,0x8a,0x06,0x10,0x05,},{0xd4,0x8c,0x3f,0x0f,0xde,0xf3,0x82,0xd1,0xd8,0x03,0x13,0xe8,0x46,0xfc,0xa9,0x5e,0x41,0x81,0x76,0xbb,0x5d,0xfa,0x9d,0x39,0x8c,0x1d,0x21,0x24,0x77,0x6f,0x69,0x0a,},{0x2f,0x59,0xa2,0x93,0x60,0x73,0x91,0x38,0x34,0xeb,0x15,0xa0,0xe0,0xbc,0xb9,0xaa,0x80,0x40,0x89,0x46,0x8f,0x24,0xdd,0x1b,0x2d,0x37,0xa1,0x93,0x4a,0xe9,0xba,0x10,0x20,0xff,0x64,0xb7,0x2e,0xec,0x03,0x26,0x8d,0x0a,0x7c,0x01,0x2c,0x4e,0x79,0x63,0x00,0xf6,0xdf,0x7a,0xdd,0xa0,0x1c,0x8b,0xc5,0xe9,0x01,0x5c,0xcd,0xee,0x1a,0x00,},"\x0c\xcd\x37\xc4\xcf\xd8\xe7\x0c\xa3\xbb\x39\x46\xd0\x9d\x70\xd0\xf6\xa4\xb8\x1d\x6d\xfb\x07\x9d\x78\x73\x74\x80\x71\x58\x98\x80\x92\x73\x82\xf7\x43\x6a\x6e\xf8\xf5\x1c\x25\x54\x73\xdd\x01\xfe\xb5\x2c\x8e\xdb\xe4\xd3\x25\x57\x13\xe6\x8d\x64\x0f\x3d\xcf\x15\x8f\x2b\xfb\x9f\xbe\xcf\x71\xf0\x71\x9d\xfe\x8c\xe6\xb6\x01\x28\x1b\xa6\xc2\x0a\x56\xb4\xf8\xe7\xca\xa4\xaa\x9f\x86\x8f\xbf\xc5\xe4\x32\x1c\x22\xd6\x5f\x03\x82\xc4\x89\x6b\xf9\xbe\xbe\x35\x46\x94\x9e\x81\x85\xa4\xd8\x17\xe4\x5b\x5d\x12\x93\x95\x38\x21\xbd\xd9\x8e\xc2\x59\xf6\x4a\x3d\xe5\x38\x65\xb1\x49\xea\x01\xc8\xf6\x83\xec\xda\x61\xda\x5d\xc1\x0e\x7e\xbd\xdd\xfe\x74\x84\xf5\xeb\x10\x31\xb7\x91\x65\x87\xca\xa3\x99\xa0\x6b\x6f\xea\x4c\x5e\x6e\x0b\xe6\x50\xfb\xdf\x06\xc1\x03\x6d\xf2\xcc\x35\xf6\x2e\xa0\xea\x71\x3f\x52\x80\x9d\x77\xf4\x7c\x2e\x55\xc9\x23\x92\x48\x16\x80\xb6\x33\x20\x56\x22\x69\x13\xb0\xce\x88\xa6\xc5\x5a\x26\xbd\xb5\xb8\xba\xb3\xcf\x46\x95\xa8\xc5\x22\x30\x2c\x4e\xba\x37\xd3\x1f\xf7\x7e\x58\x30\x1b\xcc\xfc\x7c\x7b\xe8\x58\x0c\x63\x42\x68\x79\x95\xf4\x4a\xcd\x19\x09\x65\xae\x0d\x7b\xf0\x66\x95\x92\xb6\xad\x88\x74\x3e\xbb\x36\x0c\x73\xe0\x48\x4a\x23\xd2\xf9\xe9\x9e\x9e\xb0\x38\xdc\xbd\x87\xca\x9b\x1a\x49\x8f\x1b\x2d\x35\xfe\xdd\x7f\x8e\x1f\x7f\xd8\xca\x52\x64\x86\x91\x1e\x07\x6a\xea\xb4\x87\x7b\xba\xcf\x37\x8a\x28\x55\xf9\xc5\xac\x03\x91\x30\xdc\x69\x0e\x17\x7d\x67\xb2\x44\xcc\x8a\xd0\x32\x37\x9e\xf7\x1f\xe0\x5e\x9c\x86\x13\xd8\xf5\xd6\xea\x3d\x4e\x3e\x47\x22\x20\x29\xcc\x00\x42\x53\xbe\x47\xf8\x7f\xb5\xe3\x31\x4c\x48\x98\x13\x4b\x87\xac\xf1\x0b\x25\x38\xba\xd8\x97\xbd\xc5\x01\x2d\x8f\x97\x62\xc8\x71\xb6\x53\xd4\x00\xfe\xe0\xce\xed\x5e\xf6\xbd\xd1\x6f\xaf\x3f\x0a\xbd\xbd\x72\xcd\x0a\x12\x94\x05\x46\xf0\x99\x5f\xf1\x4b\x0f\x1b\xd5\x48\x56\xff\x74\xc3\x6e\xb4\xf2\x2d\x72\x87\xae\xfd\xc6\x09\x99\x8c\x1f\x41\xbc\xc3\xbb\x3a\x5f\xa4\x92\x34\xf4\xfa\x8e\x92\x9c\xd0\xf5\x54\xb3\x15\x39\x5d\xae\x87\x3c\x61\xca\x70\xe0\x41\x0c\x2f\xd5\xa1\x15\xd2\xa6\xff\x1f\x1c\x94\xb2\x7b\xa4\x50\xb8\x19\x4b\x21\xf0\x95\xc6\x1a\x5f\x21\x5e\x3c\x84\xf5\xd4\x3f\x0e\x73\x62\x86\xd3\x3b\x8c\x47\x81\x4d\xb9\x79\xf9\xdc\x00\x91\x98\x46\xbe\xe6\x85\x33\x7d\x99\x55\x5a\x24\x47\x2e\x6b\x00\xb3\xf4\xa1\x43\x11\xa6\xc7\xc9\x04\xba\x58\x89\xda\x6c\x1d\xdc\xc1\x11\x75\x80\xf5\xfb\xc4\x1f\x2b\x8a\x42\x68\xcf\x0e\x9f\xa5\xbf\x41\x25\x34\xc9\xe4\x05\x2a\xac\xb5\x04\xcb\x86\xe2\x14\x7a\xb8\x02\x3d\x58\x80\x0b\x76\x3f\x9a\xbf\x9d\x04\x40\x78\x8a\x51\xdf\xe5\xcb\xd4\x42\x30\xba\x52\x28\xf1\xf5\x96\x0e\xa3\xa4\xe4\x04\x4d\x36\xda\xf8\x11\xcb\xdb\xec\x5d\x69\x64\x63\xd8\xe9\x41\xf2\x72\x17\x56\x3b\xb4\x4a\x21\x18\xa4\xf5\xac\xd6\xe7\x94\xde\x17\xe0\x28\xcb\xde\xef\xde\xf2\xcb\xf0\x3d\xd3\x2e\x78\x99\xe6\x5a\x1c\xf8\x39\xf5\xd9\x0e\x1f\x8c\x36\x4b\x57\x7f\xe3\x10\x53\x53\xf6\x67\x68\xdb\xf7\xaf\x0c\x52\x1a\xa8\xa4\x9f\x7a\x22\x08\x2d\x88\xf9\x01\x49\x8c\x90\xb9\xd7\x77\x7e\xd2\xf9\xf0\xe8\xa5\x52\xd8\xa1\xfa\x5e\x96\x32\xed\x85\x32\x58\xc9\xc2\x15\xb6\xdb\xb4\x11\x1d\xcf\xca\x55\x4b\xfb\xc9\xbb\xa2\x2f\x88\xbc\x55\x55\x2c\x6d\x86\x25\x56\xd7\x41\xda\xd5\x9f\x21\x5e\x37\x28\x83\x46\xca\x7d\x7f\xd8\xc6\x5a\x38\x0d\x72\x0c\xaf\xf9\xef\xa1\x49\xf3\xfd\xa2\x32\xda\xa5\xb1\x2e\xf1\x1c\x0a\xf0\x86\x2b\xd0\x22\x9e\x07\x5a\x3c\x6b\x60\xef\x0b\xbb\x3d\xad\x7f\x29\x08"}, -{{0xfe,0x7c,0xdc,0x79,0x66,0xd0,0xff,0xb9,0xc7,0x6f,0x4a,0x18,0xe7,0xf0,0xbf,0x90,0x69,0x0e,0xb7,0x6d,0xc3,0xd3,0xd5,0x08,0x84,0x64,0x8e,0x2e,0x39,0x37,0xd0,0x20,},{0xa1,0x2e,0xe9,0x81,0x2d,0x6a,0xf6,0xaa,0x48,0x79,0xfa,0x72,0xbc,0x0a,0x69,0x80,0x4e,0xa1,0xa8,0x5f,0x9b,0xc4,0xa2,0x6a,0x5b,0xa7,0xcf,0xbb,0x91,0x4d,0x0d,0xd9,},{0xb5,0x2d,0x03,0xfd,0xeb,0xcd,0x42,0x97,0x37,0xef,0x70,0x92,0x06,0x87,0x21,0x1f,0xbb,0x4c,0x04,0xf8,0x1e,0x35,0x5c,0xec,0x70,0x72,0xc5,0x05,0x41,0x75,0xd2,0xed,0x77,0xf3,0x8f,0x46,0x6f,0x00,0x14,0x22,0xda,0x8f,0xcd,0xf0,0x67,0xdb,0x14,0x51,0x00,0x7c,0xab,0x60,0x7f,0x04,0x9c,0x2e,0x26,0x07,0xb5,0x7d,0x44,0x71,0x3c,0x04,},"\xdc\xb9\x1c\xf1\x55\x46\x1a\x60\xdf\x07\xee\xc2\x9d\x98\x61\x6e\xd1\x72\x8b\x34\xef\xa9\xe1\xf7\x44\x5a\x91\x58\xa8\xf8\x8d\x7f\xaa\xae\x0e\x24\x72\x5a\xef\xf2\x63\xc3\xf7\x4f\x0c\x68\x4f\x18\x58\xf0\x5b\x69\x95\xd2\x84\x6b\x6a\x83\x2f\x67\x08\x5a\x42\x76\xd8\x66\x1a\xeb\xd3\xbf\xcc\x73\x18\x1f\x1f\x51\x02\x93\xb6\xde\x5e\x4b\xb2\x3f\xf2\xdc\xa1\xdf\x60\x8c\xb1\x4a\xe5\x22\xac\x4b\x51\xe1\xf9\xb9\x73\xab\x8b\xaf\xcd\x53\x4e\x71\xc5\x71\x81\xb1\x18\x96\xee\x10\x61\xfb\x36\x9c\xa4\xd2\x93\x9d\x1e\x57\x06\x0d\x9f\x4d\xb0\xa5\xc0\xb0\x7d\x52\x68\x7f\x15\x78\x17\xe6\x3e\x2f\xe7\xeb\xcc\x3e\x7c\x95\xef\xe0\x5b\x85\x99\x10\xc9\x5e\xed\xe8\x6d\x14\x39\x9e\x61\x62\x48\xa2\x8c\x24\xc4\x14\xdb\xb6\x93\xaf\x9b\xe4\x35\xa3\xa9\xcd\xc3\x3e\x0e\x2a\x58\x69\x18\xd9\x1b\x8a\x85\xce\xdd\x16\x12\xd7\xc1\xa2\x17\x92\xbd\xd4\x3a\x91\x5b\x15\x7e\x04\xbb\x3a\x44\xec\xbe\x23\xfa\x49\xcc\x55\xda\xab\xbe\xaa\x15\x5a\x73\x7f\x76\x5b\x8d\xdb\x0f\x3b\x15\xd4\xec\xf2\xce\xf7\x05\x4c\xa7\x3e\xc8\x7d\x91\x75\x2c\x2e\x99\x19\x5c\xdb\x19\x58\x84\x4f\x14\x4e\xda\xb8\x2a\x97\x54\x9f\xc9\xce\xc0\x8e\x87\x11\xcf\xf8\x63\xb6\x3f\xc2\x31\xa7\x7f\x76\x2e\x5c\xd9\xda\x9d\x59\x40\x92\x52\xe9\x9a\xb0\x4c\x42\xbc\x57\x09\x7e\x46\x4e\x3c\x6a\x48\xd8\x02\x41\xe6\x32\x5e\x3e\x40\x94\x98\x9b\x34\xc0\xe8\xb3\x2b\x1a\x78\x29\xd5\x4d\xf3\x2a\x05\x0e\xe8\x7d\x8f\x7c\x4f\xe3\xe4\xf4\xf7\x04\x9d\x1f\xee\xcd\xbe\xa6\x71\x08\x35\x0d\xb4\xe8\xed\xbe\x3c\x3f\xf8\xab\x2a\x25\xd1\x47\xb1\xc1\xc5\x82\x1b\x0f\x8c\x21\x04\x2d\x65\x5d\xb8\x31\x69\x1f\x59\x98\x3f\x27\xd2\xed\x1d\x49\x06\xc5\x44\xe2\x4e\x79\xbe\x68\x65\x3c\x9b\x22\x9a\x7f\xb6\x1e\xf5\x45\xba\xb1\x6e\x98\x81\xcb\x4d\x92\x65\xe2\x93\x59\x0a\x0b\xc2\xdc\x86\xba\xd2\x30\x07\xff\x40\xc9\x58\x61\x92\x3b\x49\x82\x41\xc1\x0d\x26\xbf\x48\x48\xf6\x2b\xa7\x38\x3f\x64\x9d\xc3\x8a\xf1\x84\x0d\x0d\xe9\x28\xa9\xbf\xee\x5e\x11\xb5\x14\x34\x16\x3a\x7a\xb1\xed\x53\x74\x15\xf1\xe9\x32\x85\xe3\x69\x92\x05\x72\x01\x58\xf9\x55\x7d\x86\x41\xed\x2b\xf4\x85\xb8\x21\x2c\x8f\x82\x66\x8b\xac\x3c\x22\x8e\x69\x24\xc1\x7d\x0d\x98\xf2\xe6\xd9\x23\x43\x71\xc4\x42\x5e\xb7\x58\x68\x9f\xdb\x0d\xc1\xce\xa1\x39\x4a\x28\x62\xe8\x7b\xb3\x8e\x62\x4c\x34\x79\x91\x68\x61\x32\x78\x22\x5f\xb5\xe1\x9c\x92\x47\xad\xa3\x55\x54\xf2\xc4\xad\xdb\xb6\x1d\x5a\x50\x2a\x70\x81\x27\xd6\xef\xbc\xa8\xf7\x35\x09\x0b\xdf\xdd\x88\xdb\x29\xfb\xd1\x4b\x69\xab\x12\x62\xf0\xc3\xe2\x6d\x26\x3a\x59\xc5\xae\x46\x39\x06\x53\x83\xd5\x25\x0b\x54\xcf\x59\x2b\xb7\xad\xfe\xaa\xe0\xd2\xfe\x81\x6b\x63\x81\xe8\x6e\xa2\xd1\xc7\x18\x13\xcb\xc3\xd8\xfe\x2d\x31\xde\x7b\x30\xfb\x6e\xc2\x29\x4f\xe4\x53\x6a\x36\xc6\xa1\x83\x5a\x71\x62\xab\x4b\xf8\x9d\x19\x46\x61\x19\x65\x7b\x0e\x46\x45\xae\xf5\x03\x50\x5b\x4d\x55\xdf\x97\x7b\xd2\xc9\x0c\x64\x40\x6f\x49\x70\xd5\xcf\xf2\x45\xb8\x35\x32\x2a\x6f\xbe\x23\x4e\x5e\xfb\xb5\xea\x45\xe8\xf0\xd3\x97\x3b\xe4\xaa\xa2\xaa\xda\xab\x07\x7d\x6c\x9b\x25\xbd\x44\x94\x40\x9e\x93\x47\x9d\x2d\x15\x07\xf6\x6b\xc8\xbe\xf8\x29\x99\xa1\x3c\x79\x43\xb4\x72\xb9\xe6\x1e\xc2\x9d\xeb\xef\xbf\x22\x41\x42\x3e\x0f\xaa\x42\xc1\xa3\x38\xa7\xa6\x13\x1d\xed\x93\x5b\xa0\x3a\x28\x66\x2e\x68\x59\x33\x68\xdd\xe5\x4b\x46\x2f\x2a\x5f\xb7\x46\x18\x5f\xf5\x50\x3e\x69\xba\x36\xbf\x16\xf7\x14\x58\xcd\xd0\x57\xe5\xc1\x72\x67\xf6\x74\x98\xd6\x52\x86\x0b\x46\x5e"}, -{{0xf6,0xc9,0xab,0x5e,0xa7,0x5f,0x29,0x4e,0x8e,0x0c,0x07,0xc4,0xc0,0x9e,0xd8,0xee,0xa3,0x11,0x3b,0xdf,0xc2,0xef,0x75,0x9e,0x20,0xa2,0x64,0x57,0x16,0x04,0x10,0x8d,},{0xb1,0x2f,0xf5,0x5b,0xd3,0xec,0x42,0x61,0x0e,0xac,0xea,0x28,0xb3,0x13,0xa1,0x6e,0x19,0xc9,0xe8,0xb4,0x7c,0x2b,0x15,0x17,0x09,0x91,0xbe,0x08,0x8d,0x65,0xcf,0x63,},{0xa7,0xf9,0xd0,0x8b,0xa1,0x41,0x83,0xef,0x24,0x7f,0x2c,0x25,0xfe,0xcc,0x2b,0x83,0xed,0xa6,0xde,0x58,0x02,0x2e,0x46,0x6c,0xe7,0x8f,0xcf,0x50,0xf7,0x1c,0xe2,0x61,0x62,0x44,0x65,0x62,0xee,0xa4,0x5d,0x63,0xa2,0x1c,0x3b,0x22,0x56,0x1f,0xd4,0x68,0x00,0x58,0xac,0xb8,0x25,0x40,0x7a,0x15,0x40,0x8f,0x27,0x13,0x61,0xa1,0x46,0x0f,},"\x71\x62\x3b\x39\x74\x3e\x39\xc7\xe0\x86\x38\x80\x6d\x46\x8a\x1a\x8a\x6f\x35\xc2\xae\x38\x8e\xef\xc2\x73\x74\xbb\x52\x53\x88\x14\xc4\xb3\x6c\x9b\x8e\x38\x9a\xd8\x31\x83\xde\x02\xa1\xbb\xd0\x32\x57\x34\xe4\x61\x87\x54\x09\x23\x37\xd3\xe7\xdc\x12\x56\x92\x8e\x35\x28\x87\x0c\xa7\xf0\x06\x13\xa2\x5b\x71\xbb\x15\xd1\xd9\xea\xaf\xf9\xf2\x26\x9b\x71\xc1\x97\x69\xe0\x03\xce\x84\x56\x14\xb2\xec\x95\xed\x28\xca\x85\x5b\x52\x21\xd4\xcb\x80\xa6\xca\x94\x66\xaa\x33\xe2\x51\x0d\xdf\xf7\xdc\xe1\x86\x15\x9d\xa7\x0f\xc8\xb1\xfb\xac\x12\xa2\x6e\x1f\xc0\x94\x22\x76\x89\x2a\xd6\xe9\xb0\x03\xf5\x69\x59\xbd\x31\x3a\xf2\x89\xe7\xa0\x53\x2a\x66\x4b\x76\xb9\x6b\x91\x98\x54\xe0\x65\x0c\xb8\xc5\x2e\xc4\xc5\xfb\x50\x53\xaf\x2f\x0c\xf8\xc0\xf2\x2a\x52\x3f\x9e\x2c\x64\x19\xdf\x8d\x0b\x71\x4e\xe3\x77\x68\x00\xeb\xfa\x70\x77\x60\x84\x66\x7d\x6d\xcf\x54\x1f\x14\xcf\x16\x62\x62\xe0\xf6\x4c\x42\x76\xae\x28\x88\x5e\x6c\xfd\x09\x7b\x70\xc0\xd6\x18\x6e\xa5\xdb\xd0\x33\x32\x3c\x98\x76\x13\xda\x08\x64\x5d\xe0\x72\x08\xba\xe1\x2a\x17\x8d\x8f\x7f\x65\x0a\x25\xaf\xbd\x70\x1c\x85\xa1\xba\x63\x9e\xf9\xf1\x21\xc4\x0c\x5c\x12\x9a\x47\x37\x34\x33\x86\xa4\x81\x83\xff\x3c\x59\x13\x89\xd8\x9e\xcd\xa5\x26\xcf\xfb\x26\x74\xf1\x7b\xb1\xc2\x30\x90\x55\x4b\x13\x40\x84\x97\x96\xa6\xd4\x44\x46\x0b\xb4\x19\x42\x7e\x93\xe6\x58\x5b\x0f\x4f\x06\x5a\xd8\x7e\xe6\xed\xf5\x4b\xe6\x18\x8a\x1d\xd5\xac\xe1\x36\x4d\xef\xa5\x61\xf7\x4e\x26\x76\x9c\x9b\x29\x1e\xe7\x55\x52\x76\x50\x1c\x6a\x49\x08\x0d\xa0\x92\x4f\x37\x92\xc2\xa7\x28\xa5\x20\x07\xb1\xc0\x7c\x95\x57\x8f\xed\xaf\x40\x39\x96\x23\x9e\x9c\x55\xa9\xa4\x4c\x3d\xfc\xc3\x7c\xdf\x03\xfb\x48\x5d\xb5\xa0\x8d\xff\x15\xa7\xa4\xf7\xb7\xf1\x54\x74\x2e\x84\x31\x56\x4d\xc1\x7d\xbd\x43\x2e\x10\x33\x7c\x22\x76\xfc\xfd\x9d\x70\xf7\xc3\xd5\x70\x39\x3a\x0c\x19\xf6\x40\x51\xc7\x3a\x87\x0e\x20\x55\x84\x10\x65\x31\xd1\xfd\x2a\x1d\xd1\xc9\xd0\xfc\xe1\x4f\xfa\xaa\x07\x7b\xb7\xe2\x60\x25\x1e\xed\x6c\x62\xbc\x6e\xdc\x24\x22\x51\x94\x40\xc2\x24\x4e\xba\x38\x40\x46\xb0\xed\xda\xa6\xcf\x2c\x1c\x7e\xee\xbf\xcd\x78\xfc\xae\x18\xb8\x22\x90\x55\x2b\x59\xc0\x46\x3d\xc4\x50\x61\x8b\xa6\x7c\x77\x0d\xec\x0e\x22\x9b\x84\x60\x93\x6c\xa8\x19\x56\x2b\xcb\x36\x96\x9c\x8f\xf7\x0b\xf1\x13\xc1\x16\x71\xe0\x0b\x94\x13\x55\xbf\x01\xad\x54\xb0\x5c\xfe\x2a\x04\x8b\x38\x72\x8c\xbd\xd1\xb4\x98\x09\xe1\xf2\x07\xac\xa3\x09\x8d\x99\x42\xee\xc4\x7d\x6c\x9d\x41\x3b\x37\xc9\x14\xfe\xdd\x38\xac\xd5\xff\xe4\x96\xca\xc7\x57\xc2\xef\x8b\x77\xbd\x84\x03\xd1\x4b\x1f\xc9\x8a\x90\x3f\xe2\xb9\x79\x46\x82\x33\xa7\xf2\xae\xd6\xf8\xd5\x09\xd8\x74\xe1\xdc\xe0\x51\x49\xaf\x9d\xf3\xfe\x45\x95\xc7\x1e\x8b\xc4\x63\xde\xe9\x38\x4d\x5e\x05\x05\xd2\xa6\xb0\xa2\xb8\xa1\xed\x62\x16\xaa\xae\x9d\xcc\x76\x02\x48\x7a\x4c\x08\x51\xfd\xf0\x96\x29\xc1\xe9\x91\x18\x80\x9a\x95\x44\xa6\x57\x7a\xf9\xf9\x15\xd1\xe6\x5d\x81\x62\x20\xc4\x8c\x84\x90\xfa\x9b\x70\xda\x42\x2a\xd6\x80\x02\x23\xd6\xd8\xc3\x40\xf9\xea\xb2\xcc\x7e\x14\x93\x62\x12\x4a\x30\x0b\x40\xcb\xb8\xc0\xa6\x5d\xa3\x01\xdb\xba\x93\x1b\xa5\x64\xf3\x59\x73\xca\x8b\xf2\xd1\xed\xb5\x6c\x19\x46\x61\x95\x5b\x3b\x68\x38\x1f\xa1\x5d\x4b\x8d\xc6\xad\xa1\xa5\xce\xbd\xa3\xa4\xcc\xc5\x51\x23\xe0\x05\x7f\x4f\x82\x10\x41\x93\x7d\xd5\x49\x20\x9c\x82\xe1\x16\x57\x0b\xc9\x08\xa2\x8e\x32\x99\xa9\x44\x14\x43\x49\x8f\x74\xb3\xcc\x88\xe1\xa6\x2d"}, -{{0x43,0x10,0x3d,0xf0,0x1a,0x48,0xa0,0x3c,0x57,0xf3,0x2f,0x52,0xd7,0x0c,0x68,0x49,0xee,0x44,0x58,0x0b,0x2a,0xb4,0xee,0x72,0xd5,0x48,0xd8,0x48,0x13,0x4f,0x7c,0xeb,},{0xa3,0xcb,0xe0,0xd6,0x4b,0x05,0x60,0xbc,0xb5,0xae,0x00,0x90,0x01,0xe3,0x14,0xd9,0xec,0x90,0x79,0x01,0xdd,0x74,0xa8,0x04,0xa0,0x05,0x90,0x22,0xed,0x9c,0x6d,0x04,},{0x19,0x54,0x47,0xbe,0xb1,0xde,0x4a,0x7e,0x36,0xea,0x89,0xa6,0xce,0x3c,0x99,0xbc,0xc8,0x94,0x11,0xdf,0x5e,0x0b,0x15,0xf7,0xba,0x0b,0x1d,0x11,0x0c,0x45,0x6a,0xbc,0x6b,0x3f,0x5f,0x1d,0xa6,0x10,0x6e,0xd8,0x87,0x86,0x4b,0xa5,0x6a,0xab,0x46,0x6a,0x8a,0x63,0xb3,0x35,0xcf,0xcf,0x4c,0x64,0xd6,0x5c,0x0e,0x6f,0xb4,0x80,0xb4,0x01,},"\x73\x8c\xbf\x06\xd0\x0d\x4d\xcd\x5e\x5f\x24\x3a\x1c\x18\xdd\x5e\xc2\x02\x78\x88\x46\x95\xa1\xcf\x3b\xea\x67\xbb\x5b\x05\xdd\x7e\x60\xa2\xa2\x4f\xd3\x25\xbe\x6b\xf4\x6b\x46\x28\x73\xec\x90\x7f\x9d\xe8\x8d\xc2\xc7\x62\x62\x0b\x7e\x0e\xf7\x27\x65\xd4\xbd\xa6\x62\x45\x49\x93\xc8\x28\xa1\x74\x6e\x9e\xd8\xd1\x9d\xff\x43\xc4\xc4\x85\x27\xac\x84\x5f\x21\x86\xa4\xad\x7c\x1d\x99\x2a\x16\x24\x5c\xd5\x73\x07\x3e\x09\x40\xdc\xee\xd3\x68\x11\x0b\xb5\xfd\x0a\x4c\x88\x34\xce\x88\xa7\x71\x25\xb9\x14\x73\x93\xc8\xb5\x8c\xb1\x6e\x5e\xbd\xc1\x82\x44\xeb\xfa\x48\xba\xba\x46\x97\x3f\xdc\xd4\x85\xb1\xb2\xe5\xf3\xb0\xe7\x09\x92\xcf\x19\x99\x58\x06\x38\xd8\x7f\x1f\x5b\x27\xc4\xd7\xf9\x1d\xec\xf3\x7d\xe2\xe7\x34\xe3\x19\x55\x35\xc6\x31\x08\x2b\x3e\xba\xa8\xce\x30\xa9\xc2\xc2\xdb\x01\x6d\x7d\x35\x47\xe6\x21\x61\x88\x50\xe2\x20\x40\x03\x8d\x0f\xe0\xfa\xea\x2f\x9b\xf5\x10\xb6\x82\xc4\xfd\x14\x75\x0e\x89\xb4\xc1\x99\xef\x0c\x99\x05\x00\x54\x3e\xee\xab\x5f\x0b\x50\x7a\x31\x31\x99\xc2\xa2\xa0\x26\x2d\x6d\x81\x4c\xbc\x09\x33\xc5\x92\xe2\x56\xc3\xe2\x9d\x52\x4b\x06\x6e\xa5\xa4\x54\x33\x61\xa1\x04\x50\xe0\xaa\x67\x5c\x61\x40\x8f\x30\x7f\x26\xee\x58\x96\x9d\x63\x27\x8f\x13\x5b\x7d\xcb\x66\x6b\x93\xf2\xca\xcf\xd8\x38\x73\x47\x1e\x97\x4a\x28\x6b\x09\x02\x3f\x50\x15\xfa\x1a\xaf\x18\xbf\xbf\xa5\xf7\x43\x85\xd0\xdf\x6b\x9a\xdd\x51\x6f\xfc\x0c\x31\x13\xe3\x7e\x09\x78\x38\x64\x6a\xc9\x30\x54\xff\x4d\x96\x02\x06\x67\x44\xba\x33\x96\x95\x3f\xd7\x81\x68\x13\x01\x70\xbb\x27\x5c\x15\x2b\xdd\x36\x6f\x73\x06\x5c\x0a\x7a\xd7\xad\x00\x75\x8c\xb9\x9a\x7a\xc1\xb7\x80\x9d\x26\xdf\xaa\xc7\x58\x46\x82\x01\xee\xb6\x0d\xea\x36\x8c\x33\xf2\x57\xaf\xe2\xf1\xb4\xc0\x2e\x37\xba\xfe\x40\xf5\xd7\xfd\x40\xc8\x7d\x1c\x56\xa0\xcb\x28\xe9\xd2\x83\x69\xa3\x92\x4b\xce\xf8\xb6\xd9\x99\xdc\xf4\x29\x4d\xd8\xc4\x14\x3d\x75\xc6\xc2\x5b\x5a\x45\x44\x48\x8d\xde\x72\x52\x48\xc7\x8d\x93\xc1\x5b\x81\x5b\x01\xcb\xd0\xf3\x1d\x1b\x00\xac\x04\x83\x7e\xf8\x5b\x40\x03\xfc\x96\xd4\x45\x7a\xc5\xa0\x23\x62\x3e\x67\xb6\x6d\xa4\x70\x0a\x08\x59\xf8\x3f\xdc\xcd\x3c\x7a\xae\x09\xde\x09\xa0\x57\xe0\x0d\xb4\x4a\x2a\x6a\xac\xaa\x21\x74\x6a\x49\xb8\x22\x46\x89\xa5\xcc\x18\x54\xba\x3d\xc4\xaa\x2a\xa3\x45\x24\xe7\xa5\xa8\x9d\x11\xee\xa3\x56\xaa\xea\x5e\xf5\xfb\xf5\x42\xc9\x9f\x54\x4d\xb9\x40\xf5\x08\x68\x38\xee\x2a\xb2\x18\xb8\xd3\xf2\xe1\x07\xd0\xb2\x9d\x4b\x04\x83\x0e\xed\x79\xc0\x76\x8e\x02\xc2\x84\x4b\x3c\xba\x32\x68\x95\xf4\xab\x38\xa3\x99\x4b\x83\xab\x30\x60\x0f\xf5\x11\xcc\xb5\x95\x99\x2f\x8c\xc0\xd2\x95\x48\x07\x97\x2d\xa3\x65\xb0\x6f\xbd\xab\x53\x9b\x2e\x03\x59\x8b\x34\xe5\x3c\xfc\xf9\x39\x90\xb9\x7a\xac\x1d\x32\x97\x83\x36\x6d\x45\x1f\x97\x2b\x8d\x8a\x00\xb6\xb8\xec\xdb\x37\x27\x96\x44\xce\xc1\x44\x7c\x09\x98\xee\x4f\x70\x90\xf3\x4c\x9c\xc8\x53\x05\x90\xca\xe7\x65\x36\x0a\xad\xb0\xab\x31\x35\x00\x49\x41\xc9\x23\x02\xcb\xb2\xb3\x50\xa1\x4e\x8f\x30\xaf\x53\x25\xc2\xb4\x38\x00\x5e\x3a\x9d\x45\x85\xe6\x32\x65\xc3\x27\xba\x72\x57\x54\xb3\x32\x56\x91\x7f\xb9\x65\xae\x9f\x02\xed\x21\x26\xb4\x81\x47\x3d\xc0\xe9\x31\xc2\x52\x2b\xf0\x0f\xe6\xa2\xec\x95\xc7\x92\x24\x7b\x1e\x03\x39\x61\x12\xf7\x83\x07\x0e\x2f\xe6\xc2\xcb\x98\x22\x50\xd1\x3f\x2d\x54\x60\xc7\x44\xfd\xe4\x53\x23\xe6\x31\xcc\xcb\x54\x0c\xd7\x25\xf2\xc5\x5a\x70\x58\xf2\x30\xe8\x2b\x79\xf3\x66\xaf\xcb\xb0\x25\xb4\x92\x55\x43\x95"}, -{{0xf9,0x13,0x9e,0x57,0x9f,0xa9,0x6e,0xbd,0x62,0x87,0xdb,0x3b,0xab,0xcd,0xa6,0x0f,0x92,0xe7,0x31,0x53,0x56,0x6f,0x92,0x4c,0xb5,0xde,0x04,0xde,0x44,0x93,0x48,0x1e,},{0xc0,0x6c,0xe3,0x35,0x53,0x3a,0xf8,0xd8,0xf3,0x37,0xf2,0xb3,0x8e,0x0a,0xaf,0xa2,0xce,0x9b,0x27,0x22,0x3c,0xd9,0xdd,0xc5,0xef,0x32,0x02,0x7f,0x04,0x88,0x9b,0x7f,},{0x05,0x1d,0x8d,0x7f,0x0b,0x68,0xd2,0xee,0xc7,0x2c,0x81,0xad,0xfc,0xfb,0x31,0xae,0x85,0x58,0xf6,0x0a,0xb6,0x3c,0x9f,0x56,0x52,0xa8,0xdf,0x63,0x8f,0x66,0x6f,0x1e,0xbc,0x0c,0x6e,0x0b,0x41,0x19,0x53,0xbc,0xda,0x6b,0x51,0x51,0xb2,0xb9,0x3a,0x39,0xe3,0xc5,0x33,0x0a,0x85,0x73,0xe1,0x68,0x79,0x22,0x72,0xab,0xd3,0x6c,0x81,0x0a,},"\xb3\x30\x76\x4d\xdc\x62\x8e\x4a\xd6\x7a\xa4\x98\x2a\xe8\x6d\x45\x81\x07\x1c\x19\x3e\xc3\xc5\x8f\x81\x3d\x79\x21\xb8\x4d\x2a\x54\x56\x2b\xd8\x74\x17\xae\x1d\xe5\x90\xa1\xa4\x8c\x4e\xc7\xd5\x56\xad\x93\x1d\x65\xc0\x54\x3f\xdf\x06\x07\xc7\x49\x85\x9e\xe1\x2f\x99\x52\x02\x0c\x19\x5c\xf8\x74\x60\x95\xe1\x08\x7c\xc6\xc3\xc8\xef\x9d\x24\x05\x25\x60\xce\x81\x3d\x61\x39\xb7\xa7\x5c\x8f\x4b\x8e\xa3\x0a\x9c\x4a\xb8\x88\xd0\xa6\x34\x1c\x99\xab\xd3\x5e\x09\x03\xbf\xe5\x6c\x93\x15\x23\x40\xc4\x12\x76\xd7\xf2\x4e\x09\x12\xb1\x2a\x4d\xb3\xd7\xee\x44\x84\xdf\xa5\x3a\xfc\x0b\x1a\xea\x14\x09\xd1\xe0\x32\x8a\xa1\xc8\x60\x41\x27\xca\x2e\xb1\xa5\xe8\x1b\xf3\x1f\x8c\x7a\x51\xc6\x05\x2c\x53\x4e\xfe\x6b\x3d\x0e\xe7\x4f\xf5\xa9\xb1\x1c\x61\x57\xe3\x64\x77\xef\xa9\x38\x2f\x57\x51\xbe\x8c\x8c\x64\x54\xc4\x46\xd6\xf8\xdc\x7e\x92\x95\x25\xcc\x3d\xe7\x8c\xb1\xba\x4a\xba\x9b\xd4\xbe\x15\x26\x10\x43\x75\x82\xc9\x65\xee\xa4\x8c\xbd\x4c\xaa\x6f\x30\x8f\x85\xf4\xf8\xd0\x06\xa0\x42\xf6\x19\x20\x07\x62\xe1\xbb\x9b\xa4\x22\xe6\x54\x75\xb3\x3a\x94\x94\x29\x8c\xfb\xb7\x5a\x15\x2b\x36\xd2\xa0\x55\x01\x80\x77\x05\xb9\x52\x76\x53\x50\xcd\x14\x14\x1d\x35\xd4\x98\x66\x92\xd6\xc3\xbc\xfc\x6d\x61\xdf\x00\x52\xa6\x20\xaa\xb8\xcc\x13\x20\x5e\x75\x4c\x16\xf9\x3e\xca\x79\x20\xbb\xea\x51\x57\xef\x11\x2f\x0b\x64\xc1\x05\x4f\x90\xa5\xdd\xc1\x75\xa8\x9e\x29\x24\x2f\x57\x64\x6e\x74\xcc\x88\x5e\x81\xa1\xcc\x14\x4c\x3d\x78\x2d\x11\x52\xa9\xe4\xcf\xe7\x6c\xb3\xff\xab\xe7\xdb\xe6\x03\xfb\x38\x69\xec\xa8\x69\x96\x98\x70\x9c\xc8\x7f\xc9\x61\xc1\xe2\x99\xcf\xca\x22\xe3\x24\x2e\xae\x78\x8c\xff\x11\xbf\xca\x61\x02\x67\x45\xf4\x97\x62\x25\xb2\x6e\xe2\x00\xc4\xf1\x91\x0c\x4b\x83\xdf\x5c\xe4\x6e\xf4\x87\xd7\x48\xd9\xc4\xc5\x02\x14\x1b\x78\x74\xca\xf4\x1e\x5a\x29\x7b\x24\x8c\x2b\xac\x69\x90\xa1\x5b\x07\xb4\xcf\x81\x0e\x59\x28\x74\x42\xd9\xa3\x69\x6c\x02\xe8\xd7\x32\x4d\x3c\xf7\x30\xdd\xa5\x40\x53\x6b\xeb\x13\xcf\xde\xae\x61\x80\xdd\x74\x84\x83\x2d\xfa\x94\xe9\x4a\xa6\xcb\xa1\x17\xaa\xe1\x72\x70\xf4\x8f\x93\xb2\xf9\x8a\xe9\x58\x17\x18\x16\x3f\x44\x63\x54\x6c\x0a\xe0\xf2\x79\xc3\x6b\x92\xbe\xe6\x6f\x1c\xa2\xd6\xa4\xf7\x26\xd2\xdf\xee\x0b\xc1\x1c\x1d\x8a\x1f\xa6\x2c\x3c\xc8\xab\xa2\x66\xb9\x87\x59\x28\x6c\x10\x68\x48\x3b\x23\x76\xb4\x03\xc8\x87\xfb\xb6\x57\xdc\x0f\x25\x5d\xea\x90\xdb\xd2\x33\x08\xf7\xe0\xe8\x42\xb4\x98\xa8\xdf\xc7\xc9\xcd\x5a\xef\x0e\x87\xd5\x6b\xe4\x0d\x50\xfc\x1d\xd4\xc0\xaa\x7d\xee\x55\xae\xbe\x4d\x6b\x6a\x52\x05\x39\x62\xb8\x7b\x0f\x2e\xe0\x9a\x90\x81\x61\x55\x33\x3d\x5c\x57\xa1\x47\x24\xe0\x01\xbc\x3d\xed\x17\x84\x3b\x76\xe2\xc4\x7a\x17\x63\x39\xc8\xde\xfc\x54\xb5\x5b\x23\x58\xae\x7d\x01\xb0\xf6\xe0\x8f\x31\x21\x6a\xe9\x03\x40\x69\x41\x68\xa5\xa7\x9e\xe8\x83\xea\x78\x58\x00\x7d\x17\xc3\x73\x59\xc9\x9d\x65\x97\xef\xe4\x60\xc1\xa2\xf7\x73\x8a\xc3\x2c\x5e\xb5\xe3\x9e\x50\x0c\x49\xc0\xdf\xf9\xc4\x65\x9e\x8c\x50\xcc\x5c\xa7\x9d\x8b\xa4\xe5\x97\x2d\x67\x22\x54\x68\xfb\xa6\x41\x67\xa6\xb2\xc6\xf3\x68\x93\x5c\x7a\x04\x9d\x35\xd3\x55\xc7\x67\x25\x20\xd3\xc9\xe4\xe4\x3c\x67\x1c\x3c\xb8\xde\xe2\x59\x04\x74\x95\xde\x0f\x56\xdd\x71\x91\xd5\xbd\x4b\xbd\x29\x51\x7e\x36\x47\x92\xff\x89\xd3\x37\x99\xb6\xe7\x81\xc2\x01\x93\xf5\xa3\x16\xfb\x40\xde\x74\xfe\xe2\xac\xc2\x5e\x47\xf5\x12\x21\x4d\xe3\xb1\xe9\xb3\x82\xa8\x69\x29\xc1\x57\x3d\x37\x24\xc2\x50\x17\xc0\xe5"}, -{{0xc8,0xee,0x95,0x4d,0xb5,0xa1,0x1b,0x29,0x2e,0xd9,0x77,0x64,0xfa,0xe6,0xb2,0x83,0x05,0x1d,0xb5,0x7d,0xcd,0xc0,0xaa,0x0d,0xf5,0x39,0x3b,0xb6,0x0c,0x11,0x2e,0xd3,},{0x5c,0x2f,0x81,0x82,0x4e,0x99,0x75,0xdd,0x7e,0xa3,0x53,0xbc,0x66,0x80,0x7d,0xed,0xc7,0x61,0x03,0x49,0x79,0x4e,0x2f,0xc0,0x8e,0x5a,0x31,0xe0,0x02,0xe3,0xfe,0x07,},{0xf3,0x07,0x7a,0x75,0x10,0x1e,0x12,0x1e,0x5c,0x3e,0x77,0xd8,0xed,0x97,0xb5,0x78,0xd2,0x39,0xbd,0x42,0x18,0x03,0xd3,0x45,0x5b,0x56,0x54,0x40,0x5a,0x4c,0x58,0x6a,0x60,0x92,0xe1,0x3a,0x85,0x29,0xba,0xce,0x46,0x8a,0x30,0x57,0x84,0xb3,0x73,0xe4,0x33,0xfe,0xe4,0xa3,0xdf,0x89,0x56,0xbe,0xfa,0x01,0x2f,0xd8,0xa8,0xee,0xd1,0x0c,},"\x7b\xa3\xfb\x56\x83\x15\xaa\x81\xe2\x1f\x19\x77\x80\xed\xc2\xc6\xea\x26\xd8\xd0\x6a\x43\x78\x91\x2f\xca\x23\x01\xcf\x1e\xab\x3d\x80\x3c\x84\x69\xde\xdd\xf3\x76\x70\x3d\xdb\x7c\xe0\x6a\x77\xda\xb2\x0e\x02\x34\x4f\xad\xcc\x50\x02\x2a\xb3\xc7\x13\xcd\x03\xc1\xda\xa9\x3f\x1c\x7e\xa5\x72\x62\x9f\x61\x0b\x5e\x3c\x51\x41\x1b\xb8\xc1\x96\x94\xbb\xce\x90\x3c\xac\x47\x05\xf9\xb5\xdd\x0f\x47\xbc\x5d\x0a\xa3\x25\x3f\x90\x88\x70\x29\x90\x27\xff\xbd\x34\x49\xee\xba\xd4\x53\x32\xb5\xd0\xc4\xf5\x33\xdb\xed\x18\xa9\x9a\x24\x98\xb9\x16\x4e\x24\x5f\xb6\x5c\x0a\xfa\x0b\x05\x37\x03\xa0\xcf\x95\x94\x0a\xc7\xa0\x19\x5d\x4f\x70\x46\x60\x9c\xf0\x43\x71\x33\x87\x06\xb9\xb1\x98\x6c\x0f\x11\x81\x75\xd2\xcd\xfc\xe7\x4a\x6f\x88\x65\x98\x25\x85\x4e\x94\xec\xe5\x8f\x51\x57\x63\x6d\x62\x35\xb7\x6d\x32\x74\x5a\x2a\x81\xa9\x67\x1a\x8f\x86\x02\x7b\xa9\xe0\x17\x63\x88\x8f\xc1\x71\xce\xf7\xc4\x51\xc3\x60\x72\xbc\x74\x99\x83\x9d\x43\x1c\xf1\x8c\xd7\xc6\xc9\xfb\xa3\xaa\x71\x2a\x05\x43\x28\xcc\xd6\x2b\xe4\x82\x0a\xbd\x5e\x78\x21\x62\x76\x46\x11\xd4\x53\x9b\xa2\xce\xbd\xc2\x09\xb3\xf4\xe4\xb6\x9c\x3d\x64\x07\x3e\x92\x0d\x21\x52\x14\xfb\x0f\xda\x44\x18\x5a\xad\xa5\xc3\x61\x27\xa1\x5b\xa1\x5c\xa2\x8a\x3a\xd0\x86\xe9\xd0\x33\x66\x86\x9c\x60\xc3\xfb\xce\xbd\x86\x9d\x2e\x40\x64\x3e\x83\x3f\x89\x48\x03\xf9\x80\xa2\xda\x7e\xa4\xe5\x9c\xe4\xd7\xc0\x6f\xd2\xaf\xf0\x87\xee\x7b\xcf\xdd\xaa\x3b\x32\x81\x7c\xe6\x3a\x63\x58\x7d\xba\xfe\xf3\x80\x01\x3a\x6f\x1e\xe3\x73\x4b\x94\xca\x3d\xf9\x64\x4d\xd0\x43\x43\x02\xec\xb3\x24\xaf\xe3\x5f\x46\x5c\x9c\x1c\x93\x1b\x27\x29\x4f\xc6\xee\x02\x72\xde\x22\x42\xae\x90\xd7\xf2\xe0\x67\x02\x7e\xf8\x64\x2e\x8f\x17\x1e\xd8\x80\xff\xab\xce\x8a\x20\xa1\xb3\xe3\x39\xad\x4e\x3f\x1a\x90\x01\xf2\x0f\x90\x02\x61\x88\xfd\xe3\x4b\x21\x7a\x6e\x26\xaa\xff\x18\x42\x2b\x7f\x84\x3d\x0f\xdd\xa3\x21\xc3\x19\xc7\x78\xf2\x31\x37\xf2\x0c\xcc\x1b\xda\x18\x90\xe5\xbc\x91\x6a\x54\x56\xd0\x68\xd3\x7b\x5a\xcc\x63\x47\x72\x0c\x56\xa5\xa4\x91\xbc\x34\x8d\x6c\x84\x8a\x9c\x8f\xec\xfe\x58\xc9\x2b\x1f\x30\x2f\xe1\x49\x19\x71\x8c\xd5\xe7\x8b\x7f\xd6\x01\xd0\x9d\xc0\x1e\x69\x04\x86\x1e\x8d\x68\xb3\xc5\x75\x35\xb6\x13\x66\x76\xcb\xc6\xe8\x39\xaf\x0d\xd7\x39\xdb\x89\xa7\xab\xd9\x13\xfd\xf6\xb0\x0e\x9c\xa0\x26\x02\xde\x6c\xa0\xaf\xd0\x91\x3d\x99\x2f\xba\xa8\xff\x82\x2b\x9d\x9b\x09\xdd\xa7\xa2\x9b\xe9\x19\x10\xd8\xfa\x3c\xaa\x2a\x5e\x51\x83\x46\xc1\x67\xc9\xf5\x19\x41\xcf\x73\x53\xf3\xf3\x4c\x1d\xab\x33\x48\x5d\x0a\x8c\x19\xda\xf9\x51\xfd\x3e\xf2\x0d\x0b\x11\x9d\x80\x38\xdf\x90\xc1\x14\xa2\x5a\x5b\x93\xae\x40\xec\x44\xb9\xa5\xd2\xbc\x1c\x65\x17\xc6\x82\x50\x0d\x4c\xdc\x19\x71\x42\xbe\xc3\xaf\x82\x32\xc0\x71\x42\x8d\xc5\x4c\x0d\x30\x45\x42\x72\xe7\x33\x6b\x0b\x58\x88\xa6\xe8\xfe\xcd\xe8\x59\xe2\xac\xcb\x7f\xb0\x94\xac\xc5\x4f\xfa\x48\x1f\x76\x23\xd9\x44\x69\x1f\x04\xfb\x36\x13\xa9\x95\x49\x80\xf1\x7e\x2a\xd2\x17\x3d\x68\xcf\x0e\xc1\xb6\x7d\x8a\x91\xd6\xec\x82\x94\x6b\xcf\x05\xcb\x90\x68\x1a\x71\x62\x7b\x59\x02\x38\x33\x4e\x3d\x5a\xb9\xda\x6a\x08\x9b\xd7\x26\x24\xdf\x90\x74\xcd\xd2\x30\x9e\x04\xdf\xca\xe0\x32\x81\x2f\xe8\x4f\x9d\xb8\x82\xcd\xea\xae\x69\xee\x5d\xaa\x5a\x66\xff\x42\x7f\xc4\x52\xed\xd0\x76\x9b\x6a\xab\xcc\x13\x9d\x0f\x70\xaf\x8b\x97\x43\x0e\x64\x4f\x58\xa4\x12\x87\xa9\x3f\x63\x1d\xed\xa8\x2c\xa0\x71\x6d\x79\x75\x4c\x5c\x50\x3e\x52\xa6\x65\xda"}, -{{0x6d,0xbc,0x55,0x9e,0x4a,0xb1,0x93,0xee,0xbf,0x70,0xc5,0xc3,0x2d,0x79,0x7b,0xe0,0x0b,0x73,0x11,0xe8,0xe6,0x69,0x1d,0xa9,0xaf,0xcc,0x18,0x72,0x91,0xf2,0x50,0x1c,},{0x38,0xa7,0x03,0x44,0x76,0xfb,0x93,0x82,0xf1,0x41,0x77,0x68,0xc4,0x21,0x62,0x95,0x1a,0x26,0x36,0x90,0x2c,0x38,0x98,0xc0,0x29,0xbe,0x27,0x8a,0xb4,0xc3,0x1f,0x31,},{0x31,0xf1,0x6a,0x7c,0xaf,0x2b,0x74,0xf6,0x5e,0x05,0x7c,0x93,0x33,0xa1,0xa2,0x63,0x3d,0xac,0x73,0x46,0x33,0x8f,0x79,0x85,0x10,0x73,0x0e,0xb8,0xd5,0xd3,0x25,0xfc,0x10,0x80,0xdd,0x5a,0xad,0x5f,0xce,0x05,0x34,0xe9,0x54,0x3f,0x3c,0x93,0x58,0x68,0x04,0x46,0x4a,0xf5,0x88,0x6e,0x86,0x44,0x12,0x9c,0x77,0xeb,0xaa,0x48,0x5f,0x01,},"\x88\xee\x23\x65\xf7\xcf\x9d\xe3\x3a\xcd\x53\x56\x49\x68\xb2\xdc\x7f\x73\x70\xb7\xe7\x03\x3f\x4c\x66\x3a\x88\xc2\x5f\x60\xf7\xf7\x11\xd6\x19\x08\xeb\xf1\xf5\xbb\x72\x83\x55\x53\xc8\xaa\x8c\x8e\x4f\xcd\xec\xd3\x79\x78\x23\x82\x89\xbf\x6c\xa8\x48\x76\xd2\x28\x21\x7a\x28\xd8\x1b\x0b\x45\x7c\x92\x2e\x91\xec\xba\x8d\x3e\x1d\x2e\x66\x59\xc2\xb0\xae\xa0\x51\xb9\xc2\xe0\x9c\x7d\xfe\xb5\x1d\x30\xed\xe7\x67\x57\x03\x41\xff\xac\x1e\xcf\x0d\xe2\x0c\x82\xd1\xe9\xed\x07\x75\xde\xac\x72\xda\x7c\x2d\xec\x23\x48\x65\xde\xc8\x3f\x67\x15\xe1\xc3\xc5\x9d\xe2\x03\x3c\xc2\x4d\x86\xbc\x2d\x31\xaa\x16\x64\x96\x86\xed\xe0\xdb\xbd\x89\x64\xc3\xa6\x4a\x3d\xca\x55\x88\xd7\x24\x8b\x1f\x24\xdf\x8d\x75\xf0\x9a\xac\x62\xc0\x78\x28\xca\x43\x1a\x3a\x2d\x77\xa6\x0c\xc9\x3c\xfa\x34\x95\xca\xbe\xb1\x90\x4e\xd5\xb5\x63\x98\x4e\x8c\x20\x77\x7b\xac\x87\x74\x10\x8a\x64\xed\xa5\x8f\xb3\x20\x24\x4a\x3a\xdd\x3e\x3e\x7a\x76\xcd\x13\x7c\xfa\x4a\x09\xb6\xe6\xe9\x30\x11\xea\x0a\xe6\x51\x71\xaf\x13\x07\x11\x76\x6c\xd2\x5b\x3c\x74\xec\x54\xc0\xbd\xfa\x02\xb3\x12\x0a\xc2\x90\x87\xeb\xac\x98\x37\xfc\xa6\x5b\xa9\x71\xbc\x42\x81\xdd\x55\x7c\x50\x0e\x22\x5e\xa6\x6c\x3c\x3f\xd5\x22\x06\xc1\x9a\x9f\x93\x95\x46\x31\x69\xf8\xc7\xa8\x46\xbd\x9f\x83\x4d\x7f\x33\x7d\x0b\x61\xfb\x30\xbc\xe2\x94\xf4\x78\xae\x1f\x1d\x97\x7e\x45\x4e\x43\x3e\xe8\x72\x9f\xb0\x65\xcc\xe0\x3f\xb2\xe4\x35\xdc\xbc\xbf\xba\x01\x53\x7e\x7a\x67\x62\xe5\x5e\x7e\xd2\x25\x28\x30\x37\x04\xbe\xb5\xae\x38\x1f\x2e\x18\x10\x56\xf2\x51\x33\x27\x3c\xf1\x7d\xdf\x2b\x06\xe2\xd9\x47\x7f\x2c\x09\x75\x5f\xc8\xd9\xc7\x3c\xb3\x31\x00\x46\x8c\x64\x13\x1c\x68\x6c\xac\x79\xfd\x38\x45\x01\xe5\x0f\x8b\x0b\xee\x28\xba\x39\x58\x3f\x42\xe4\xfd\x37\x99\xe2\x4f\x60\xda\x5f\xd3\xc7\x79\xaa\xbf\x69\x9f\xfd\x23\x21\xed\x04\x5a\x85\xbc\x64\x24\xf6\x0f\xdc\xc4\x9c\x1c\xb3\x1f\x24\x9a\x42\x36\xc0\x94\x91\x76\x81\x81\xb9\x21\xf5\x86\x02\xfd\x41\x5c\x1e\xde\xb2\x6f\x39\x32\x4a\xdd\xff\x14\x77\x13\x24\x73\x7c\x67\x20\xcc\x92\x39\x1b\x94\x9d\xcb\x42\x12\xbd\x69\x31\xd4\xde\x51\x40\x1e\x7f\x95\x3b\x7b\x03\x6b\x22\x3f\x0a\xf7\xa8\xe4\x08\xb0\x4e\xa6\x35\xa2\x3f\xa0\x70\x9b\xa0\x42\xa5\xd9\x92\x95\x4c\x09\xd8\x58\x1d\xcc\xcf\x52\x56\x8a\xd2\x7a\x1c\xc7\x1d\x18\xaa\x27\x40\xf6\x21\x21\x2e\x7f\x4c\x5e\x5e\x5e\x5e\x45\x32\xd9\xa6\x7e\xc2\x77\x3a\xc2\x1c\x8a\x4b\x00\x2d\x65\x24\xf6\x18\x2d\xd3\x71\x73\x5d\x2c\x2a\xbe\x6c\x95\xc2\x81\xc6\xfb\x1e\x97\x6b\xc1\x7e\x38\x3f\xd5\x2a\xea\xaa\x9f\xbd\x4a\xbb\x82\xa2\xcc\x65\x39\x5f\x8c\x2c\xc7\xd8\x18\x2a\x0d\x25\x0c\x68\x5c\xfc\xba\x93\xa9\x51\xee\x7c\x50\x3c\x6e\x3e\xec\x23\x6c\xe3\x3e\x08\x6c\x61\x07\x28\x73\x7c\x1c\x3b\x3a\x24\x25\x2d\xa7\xf2\x16\x72\xd9\x28\xeb\xda\x99\x3a\x94\xc4\x58\xab\x99\x0f\x5d\x19\xd8\x00\x23\xc3\x6a\xa1\x6e\xaf\xca\xb1\x43\xf3\x52\xe9\x7d\x64\x09\xf3\x24\x99\x41\x11\x9b\xfd\x9f\x5f\x90\x84\x72\x4d\x9e\xba\xd3\x83\xb1\x0f\x34\xd3\x3a\xc8\x30\xcc\xe9\xe5\xcb\x8a\xec\xee\x6f\x40\x30\x1c\xbb\xe3\x09\xfd\x06\x15\x34\xa7\xd0\xc3\xed\xaa\xea\x02\xa1\x71\xd8\xb2\x34\x9d\xbe\xec\x62\x85\x20\xac\x33\x4a\x5b\xfe\x28\xa9\xd5\xf4\xc0\xd7\x40\xf7\xc7\x2d\x4d\x72\xd8\x9a\x97\x32\x6a\x03\x00\x2d\x1e\xf3\x85\x22\xbc\xd3\x7b\x42\x84\x7a\x31\x4b\xd8\x43\xec\x88\xd1\xf2\xf9\xd3\x9f\x57\xf2\xf1\xa1\x3d\x01\x40\xa8\x84\x74\x50\x44\x8c\x88\x0b\x3a\xe7\x65\x31\xe9\x5c\x43\x92\x97\x32\x50"}, -{{0xc9,0xd4,0x16,0x83,0x0a,0xe2,0x02,0x8f,0x21,0x75,0xd2,0x2b,0x61,0x4c,0x79,0x19,0x8c,0x67,0x0c,0xfa,0xa0,0xe7,0xa3,0x61,0x50,0xef,0x0f,0xee,0x21,0xa9,0x5c,0xe6,},{0x6e,0x3e,0xb4,0xd0,0x18,0x73,0x07,0x2d,0xf9,0x46,0xf1,0x79,0x2f,0x71,0x06,0x33,0x08,0x95,0xe7,0xa7,0x6d,0xd9,0xae,0x27,0xf8,0xa9,0x88,0x03,0x94,0x90,0xfd,0x4b,},{0x47,0xfa,0xad,0x4e,0x65,0x52,0x93,0xed,0xa1,0x56,0xb2,0xa1,0xfa,0xbb,0xfb,0x7e,0x00,0x9f,0xc2,0x90,0xaa,0xfe,0xdb,0xd5,0x65,0x21,0x14,0xa4,0x78,0x53,0xbc,0x77,0xa8,0x23,0x3a,0x2b,0x17,0x9f,0x60,0x54,0x77,0xd7,0x87,0x87,0x8c,0xbb,0x15,0xea,0x61,0x24,0xdf,0x8d,0xc5,0x7b,0x2c,0xe7,0xbe,0x7d,0x18,0xb7,0x16,0x2f,0xb5,0x0d,},"\xff\x9a\xd4\x83\x7c\xd0\xbb\x77\xd6\x21\x0f\xdd\xdc\x75\x5e\x6c\x0f\x1a\x73\xc2\xbc\xd0\x3f\x7a\x58\x69\xe7\x34\x2c\xfd\x73\xcf\x70\x86\xf8\x65\x56\x15\x60\x27\x7b\xf6\xc3\x42\x1a\x91\x2d\x67\x65\x8b\x1f\xa9\x70\x57\xc4\x96\xf4\xbe\x8e\xdc\xbe\x18\xb5\xec\xd0\x8a\x1e\x7d\xb2\x52\x23\xab\xda\x20\x8f\xa5\x31\xf4\xb2\x80\xaa\x03\xb0\x4b\x60\x60\x34\x11\xd3\x74\xba\x7c\xbb\x02\x0b\xb9\xa8\xce\x4c\x0e\x45\xa7\xe1\x32\x14\x48\x43\xc3\x1f\x8b\x45\xc5\x8e\xb3\xea\x85\x3c\x2c\xeb\x61\x37\x6e\x9d\xf8\x1d\x97\x78\xe7\x21\xad\xac\x77\xb5\x03\x54\x93\x7f\x34\x37\x2f\xcc\xd5\x75\xe8\x8d\x9d\x05\x8e\x43\xdf\x94\x2f\x2c\x43\xb5\x23\xc8\x09\x8e\x6d\xd9\xe6\xbd\x21\xd5\xa6\x49\xb4\x72\xd4\x1e\x34\x5f\xcd\x5e\xfd\xdd\x49\xea\xb3\x02\x70\xcd\x87\x88\x40\x4f\x28\x51\x6e\x09\xd3\xac\xc4\x00\x48\xb3\x9d\x32\x46\xf7\x57\xe4\x82\xe1\x45\x9c\x62\x6b\x79\x9e\x04\xd0\x67\x27\x13\x73\x71\xe1\x20\xaf\xb9\xfe\xc3\x9a\x25\xf4\xe6\x76\x4b\xf9\x79\x2f\xe4\x92\xee\x0f\x21\x0b\x57\xdb\x9e\xbb\x9e\x8e\xf4\x1b\x02\xc7\xfe\xe9\xed\xd4\xb6\x17\x4c\x57\x0d\xe0\x20\xa3\x91\x28\x71\x33\xfe\x8c\xcb\x41\xa8\x3f\x91\xbd\x22\x38\x2b\x21\xe1\xd7\xeb\xc2\xc7\xe5\x01\x8e\xf5\x14\x2d\x82\x63\x7d\x02\x62\x0f\xbc\x05\x69\xcc\x09\xc4\x4e\x91\x11\x12\xbb\xae\x99\x06\x4d\x68\xd1\xc6\x9e\x77\xc9\x93\x0b\x0d\xe0\x30\xc8\xc1\xd7\x48\xc4\x14\x05\x9d\x5e\x29\x9b\x7e\xdc\x08\x94\x06\x51\x89\x4b\x30\x3a\x2b\x32\xdd\x2c\x36\x5a\x06\x7c\x97\x23\x58\x55\x94\x64\x4d\x3e\xe8\xde\x1a\x51\xfa\xea\x0e\x65\x0f\x21\x24\x88\x5a\x94\xcb\x99\xeb\x90\x3b\x7d\x45\x79\xbd\xe5\x91\x49\x7d\x95\x39\x30\xd3\x63\xdd\xdb\xda\xc6\x27\xb9\x7a\x91\xf4\x96\x82\xdf\x8e\x72\x50\xa7\x07\x3d\x38\x3a\x7a\x22\xcf\x11\x3f\x28\x58\xce\x6b\x63\x2a\x28\x92\xc4\xe8\x8a\xa9\xa0\xd2\x89\xeb\x57\x62\x9b\x00\x8d\x3b\x1b\x60\x81\xe6\xfe\x5d\x3c\x0a\x6c\x80\x21\x89\xb5\xf1\x08\xe7\x66\x31\x9e\x15\xb3\x3e\xaa\x5b\x8c\xed\x40\x27\xea\xec\x83\xb4\xac\x68\xb1\x4b\x82\x98\xbc\x51\xcd\x8e\xb3\x80\x9b\x7a\x2d\x68\x4f\xe3\x2b\xbd\x9f\xab\x5c\x91\x8e\xeb\x17\xcc\x44\x4d\x73\xf7\x30\xd4\xc8\xcc\x05\x7b\xd3\xa2\xf1\xf0\xae\xbb\x61\x63\x29\x34\xe6\x17\x02\x16\x88\x29\xcd\x7e\x91\xde\x81\x50\x96\x29\xd0\x1a\x8c\xde\xfe\x0d\x1a\xc4\x9e\x21\xf0\xc5\xfb\xe1\xb2\x24\x48\x27\x26\x8a\x0a\x27\x35\x7e\x15\x8b\xd7\x68\x84\xa2\x1e\x7f\x1f\xac\x1b\x62\x72\x16\x6d\x5a\x9f\x64\xf9\xb6\x72\x98\x9a\x87\x62\xf5\x12\xbf\x1d\xf4\xb2\xab\x69\x97\x65\xf2\xcd\x83\x96\xf4\x76\xe7\xf5\x99\x95\xde\xe7\xd8\x90\x20\x7e\xff\x0f\xd2\x72\x63\xec\x23\x2e\x37\xcf\xed\xfe\x7c\x44\x05\x55\xd4\xca\x74\xe5\x2d\xa2\x46\xc4\xb8\x37\x57\xbe\xaf\xd2\xab\x2a\x51\xef\xe1\x60\xbb\x02\xb9\x8c\x26\xd6\xb2\xc3\xf0\xc1\xaa\xcb\x2f\x3c\x34\xa5\xb2\xa3\xb6\x6f\xee\x17\x5b\x78\x75\x48\x07\x3d\x8b\x57\x77\xc6\xbe\x88\x0b\xdc\x19\x6b\x33\x74\xa2\x15\x4f\x94\xd9\x36\x0f\x77\x55\xac\x68\x15\xa2\x8a\xf2\x96\x27\x1e\x22\xa8\xf2\x35\x43\xc7\x49\x55\xa6\x09\x12\x5b\x02\xa5\x69\x21\x80\x11\x42\x02\x95\xcc\xf0\xd7\x35\x69\x99\xa5\xb8\x95\xcc\x88\x48\x3f\xad\xf7\x97\x0c\xec\x6c\x64\x24\x0f\x70\x79\xfd\xb1\x5f\xfc\x5c\x42\x27\xe5\x39\x26\xd2\x78\xba\x0f\xed\x3c\x39\x93\xbc\x86\x82\x28\x23\xdd\x58\x1a\x32\xab\x2e\x3a\x07\xf7\x94\x30\x22\x4b\x27\x4e\xad\xd8\x45\x59\x8a\x7d\x1d\x89\x67\x6a\xaf\x23\x67\x77\x74\xb7\xb0\x58\x3b\xcc\x83\x59\x9d\x15\x5d\x14\xb0\x9a\xdc\xf4\x9e\xd5\x05\xe8"}, -{{0x2d,0x27,0x7d,0xd5,0x5f,0x57,0x19,0x5e,0xc0,0x72,0xb4,0x7c,0xb1,0x44,0x8c,0xb5,0x82,0xc8,0x35,0x73,0x9e,0x6c,0x98,0xba,0x71,0xab,0x12,0x8f,0x70,0xce,0x6b,0x79,},{0xdf,0xa9,0x25,0x93,0xef,0x0f,0x0d,0x97,0x4a,0x11,0x37,0x83,0x0a,0xd1,0x38,0x48,0xaf,0xef,0x3b,0x81,0x0c,0x2a,0x21,0xbf,0x77,0x91,0x78,0xce,0x4b,0x3a,0xb9,0x74,},{0x73,0xc1,0x06,0x06,0x49,0xa7,0xc0,0x14,0xed,0x01,0x94,0x58,0x51,0xb5,0x3e,0x28,0x53,0x24,0xe6,0x0d,0x06,0x1c,0x83,0x1d,0xda,0x41,0xf0,0x33,0xb5,0x65,0x83,0x06,0xa1,0xf1,0x12,0x32,0x7a,0xfe,0x93,0xca,0xa9,0x21,0x02,0x07,0x30,0xaa,0xe0,0x06,0x9c,0x9a,0x2b,0x45,0xee,0xf5,0x5c,0xbb,0x4a,0x5a,0x9c,0xd4,0x6c,0xda,0x80,0x08,},"\x14\x54\x9e\xdd\xd5\xf2\xb7\x90\x5d\xda\x19\xd7\x4a\xb2\x07\xaa\xc6\xfb\x3e\x3d\xf3\x29\x5d\x84\x52\x31\xef\x3a\xea\x6e\x1f\x04\xee\x03\x3c\x90\x38\xdc\xb4\xbd\x3d\x5e\x45\x2c\x54\x83\x4d\x0f\xf2\xb7\xde\x3f\x32\x2e\x56\x26\x94\x9c\xd6\x1d\x6e\x89\x01\x38\xff\x0e\xa8\xad\x84\x6e\x8f\xe8\x87\xae\xe1\x5f\xc4\x8b\xbe\x4f\xba\x42\x45\x5f\x5c\x17\x45\x7a\xe7\x89\xb4\x05\xaf\x85\x96\x11\xfe\x1f\x87\x46\x18\x5a\x65\xae\xf2\x13\x4e\xa4\xd8\xf3\x98\xd4\x8d\xf7\xc1\xbb\xa4\x30\x44\x08\xae\x7e\xfb\x35\x29\x24\x09\xd5\x08\xdd\x55\xce\x21\xde\x8c\x28\x16\x0d\xc9\xe8\x77\x70\x0c\x76\x3d\x06\xb0\x1b\x85\x42\x05\x2d\x7d\xdb\x63\x35\x54\xe3\x58\x42\x79\xc7\x96\x93\x70\x23\xc8\xea\xc3\x72\x77\xbe\x2b\x82\x04\xff\x3e\x0e\x10\x31\x19\x0a\x01\x01\x4c\xf5\xf5\xb4\xd7\xad\x99\x67\x27\xf9\x75\x31\xe0\x35\x5b\x87\xc9\xe6\x11\x52\x5a\xad\x07\x99\x58\xe9\xaf\xe2\xab\x10\xe4\xa3\xe7\xa1\xb6\xba\x0a\xff\x81\x5d\xa2\xcd\x81\xea\x9e\xb9\xf5\x36\x98\x66\x33\xf3\x16\xdd\x06\xc2\x50\x3c\x6b\x19\x8d\xc5\x93\x04\x80\x7b\x98\xb4\x29\x35\xf5\x1f\x63\x7d\xdb\x59\xe2\x33\xfe\xd5\x66\x43\x9c\x1f\xe9\x6c\xda\xaf\xa4\x9f\x44\x12\xd0\xc1\xe6\x54\xd8\xc6\x90\x42\x47\x0b\x3a\x59\xac\xb6\xbf\x67\xe4\x0b\x38\xa7\x70\x67\xd5\x99\x7b\x8d\x35\xed\x61\xd6\xeb\x3c\xc7\x8b\x8b\xdc\xb9\x57\x4b\x1c\xed\x9f\x6f\x33\x9e\x9e\x38\xf9\x41\x46\xef\x63\xf0\x49\xe6\xb8\x02\xbf\xed\x2a\x51\xab\x42\xe7\xd4\x89\xf3\x16\xff\x4d\x1c\xd8\x98\xbc\xf8\x50\x56\x51\x68\x74\x40\x74\x9c\x0f\xb7\xa5\x7d\xbe\xff\x72\xe6\x46\x89\xfa\xa4\x1c\x07\xb4\xad\xe5\x99\x33\xd2\xfa\xc6\xd5\x73\xde\xb7\x39\x54\x9e\xb7\x5f\x1e\x6f\x73\x85\xd8\xc6\x14\x28\x94\x97\x3e\xd6\x85\xeb\x8e\xd0\x80\xc2\xa4\x9f\x3a\xc6\x57\x11\x61\xaf\x96\x63\x5a\xd0\x57\xdf\x14\x86\xd3\x96\x77\x3a\xc8\x98\x32\x10\x97\x89\x86\xe1\xbf\x21\xa2\x08\x06\xd6\x67\xa4\x8a\x55\x5a\x96\x32\x21\xd5\x06\x14\xa8\x97\x6b\x2e\xec\x97\x51\x2d\xb1\x1a\x35\x81\x94\x49\x2a\xb5\x45\x58\x01\xba\xa1\x4a\x51\x1b\x26\xeb\x0c\x68\x28\x9d\x79\x05\x23\x71\x2f\x2f\xf8\x70\x98\x92\x69\x5c\x4d\xb9\xad\x31\x0d\xf8\xc6\xee\x7b\xd8\x3c\x87\x1f\x05\xae\xc3\x3b\x7a\xd3\x26\xf4\x46\x69\x2a\x42\xf7\x22\x23\x76\x24\x6d\x53\x6a\x32\x6c\x4d\x73\xeb\x57\x2f\xea\xda\x11\xb8\xac\x71\x14\xf6\xcb\x44\x4c\xa2\x78\xfc\xf0\x7b\x97\x0d\x2a\xd4\x65\x37\x2a\x68\x7d\x36\xb7\xda\xac\x47\x87\x48\xec\x6a\x93\x2d\xa2\x08\x43\x94\x8e\xfa\x39\x30\x97\x81\x42\x72\xe5\xca\x1c\x73\xe7\x11\x97\x3a\x52\x68\x3f\x98\xc0\x1e\x55\x24\x1c\x15\x4d\x28\xe3\x8d\x3e\xdf\xad\xe2\x30\x3a\x4e\x7c\x45\xc2\xa7\xa1\xc9\x96\xee\x11\x37\xaf\x86\x4a\x98\xb6\x98\x09\xfc\x92\x14\xee\xa8\xcf\x3a\xfe\x84\x2f\xee\x3e\xb9\xa9\x32\x2c\x3b\x82\xfd\xdb\x05\xd4\xd1\xa2\xde\x09\xc1\xce\x72\x73\x44\x53\xa8\xdd\x3a\x89\x20\xd0\xd0\xac\x96\xef\x77\x8b\x9e\x02\xc6\xa3\xf1\x28\x72\xe1\x7d\x3a\x81\xba\x75\xfd\x23\x3b\xaa\xdb\xe2\x16\xea\x0a\x58\xe9\xdd\xa0\x08\x40\x87\x02\x08\xae\x41\x35\x40\x03\x0b\x3c\x05\xe5\xd0\xb8\x32\xdf\x87\xc8\xee\x7f\x15\x34\x87\xaa\x11\xba\xd9\xf1\x39\xc7\xdd\x4b\xcf\x41\x8f\x4b\xcb\x95\xbe\xe8\x57\xd0\xe9\x60\x84\x47\x23\x87\xcb\x39\x12\x7a\x94\x71\x34\x50\x19\x63\xa7\x07\x1b\xdb\x34\xde\x69\x61\xbe\x2b\x6b\x06\xe4\x03\xe7\x59\x18\xe6\xf6\x9d\x08\x02\x1c\xf2\xa8\xac\xb8\x0a\x01\x11\xf4\xd5\x06\x10\xc1\x52\xd3\x9c\x66\x21\xc0\x57\x8a\xc6\x89\x95\x9b\x1c\xe6\xf3\x76\xf4\x3d\x18\xaf\x06\x2e\x4a"}, -{{0x42,0x80,0x66,0xc5,0x24,0x45,0x72,0x6d,0x0e,0xa2,0x00,0x7e,0x50,0x46,0x37,0x27,0x4d,0x84,0xee,0x23,0x23,0x25,0xb5,0x05,0xf2,0xc5,0x16,0x35,0x7f,0x80,0x75,0x83,},{0xdd,0x40,0xfe,0x8f,0x67,0xc6,0x65,0x61,0x3b,0x3c,0x45,0x9f,0x6a,0xce,0x8d,0xc2,0x8d,0x34,0xe0,0xe7,0x7e,0x2f,0x6a,0xa0,0x60,0x59,0x28,0x19,0xbe,0x6a,0x9d,0x68,},{0xc9,0x38,0x82,0x9f,0x59,0x8b,0x1f,0xf1,0xb8,0x18,0x33,0x60,0xd2,0x23,0xf4,0x3c,0x59,0x47,0x30,0x60,0x68,0x76,0xa9,0x9a,0x3f,0x31,0xb2,0x06,0x5d,0x04,0xe6,0xf0,0x75,0xd1,0x39,0x6b,0x3c,0x8c,0xff,0xb0,0xe1,0xe2,0xea,0xab,0xda,0x7d,0xa5,0xe7,0x89,0xcc,0xd1,0xc0,0x20,0x83,0x5f,0xe3,0xa7,0x1d,0xcd,0xb6,0xaf,0x03,0x96,0x0c,},"\xe2\x79\x6c\x50\xd9\x3d\xf8\x12\xbc\xa4\x1b\xf2\xa1\xe1\xdd\x73\x7d\x8c\xf6\xf6\xb4\xf7\x62\x42\xe3\x91\x78\x18\x67\x58\xcb\xae\x08\x84\xe6\x0c\x6b\x4a\xaa\xdd\xae\xc9\xa8\x99\xa9\x12\xe5\xc5\xb9\x80\x4d\x7b\x04\x97\xba\xb4\x45\x8c\x58\x5d\x4f\x25\x92\x22\x49\x8c\xe9\xe8\x0e\xb6\xa7\x97\x9b\xbe\xd6\xd5\x2c\xc3\x80\x72\xf7\x45\xcb\x2c\x63\xe6\x63\xbc\x3b\x9d\x6c\xaf\x01\x2a\x60\x7f\x6d\x3b\x70\x6e\x15\x57\x57\x87\x17\xec\xbb\x97\x1a\xeb\x7c\x48\xe1\xdf\x95\x71\x1c\x55\x0e\x00\x69\x93\xbf\xfb\xa9\x11\xcb\x64\xad\x52\xd5\x17\xed\x18\xbe\x82\x36\x9e\x81\x58\x19\xd3\x17\x59\x47\xd4\xa3\x5b\x2c\xc7\xb9\xdc\x6c\x10\x05\x13\x26\xb3\xf1\xdc\x1e\xdb\x1b\x68\xba\x01\x5f\xf7\xca\x1d\xc3\x61\xd8\x96\x7a\xbc\xff\xd3\xc3\x1f\x7d\x6b\x0c\xb1\x39\x6a\xe5\x41\xf2\x97\x59\xc4\x13\x0b\xe5\x2e\xcc\x11\xd9\x92\x61\xc3\x65\xbf\x7c\xde\xc7\x81\x49\x4c\x5f\xa0\x52\x6d\xb4\xdb\xbe\x66\x0a\x43\x2b\xe5\x60\x43\xc6\x6e\xa0\x7c\x25\x62\x7a\x5f\x72\xb7\x81\x23\xdc\xf9\x86\xff\x71\xed\x1a\xff\xd1\x65\x9b\x13\x93\xd9\x62\x1f\x71\x1d\xfa\x63\xea\xda\x38\x34\x30\x79\x70\x58\xf1\x56\x6a\x00\x05\x2d\x67\xba\x53\xc1\x23\x7b\x56\x91\xde\x3b\x03\x9f\xd4\x47\x6f\x11\x51\xe5\xed\x5f\x5a\x98\x67\x2f\xa3\x3a\x1d\x85\x4f\xa0\x15\x66\xb3\x32\x31\xd4\x6a\xcd\x7f\x34\xb8\x03\x44\x79\x98\x18\x53\x76\x4d\xab\x87\xf4\x98\x44\xcb\x62\xc6\x3d\x53\x6f\xac\xa9\x20\x44\x7d\x8c\xd1\xe8\x11\x3e\xdb\xc8\x3e\x4a\x6b\x78\x15\xe1\x80\xcd\x78\xb9\x33\xd9\x68\x7f\xd5\xbe\x99\xd0\x51\x8a\x44\x66\x29\x89\xbc\x64\x01\x11\x24\xf1\x87\xd4\x39\x79\x99\x4a\x95\xe0\xc9\x03\xa0\x06\xc1\xc0\xbe\xf1\xc0\xf3\xdf\x1e\xb7\x00\xf9\x80\xc2\x8c\x3c\x1e\x99\x7d\x0c\x56\xd1\x13\xda\xe1\x96\x88\x2b\x05\x01\x8f\xca\xb3\x14\xd8\x11\x7f\xaf\xba\xbe\x77\x00\xb9\x32\xd4\x7c\x57\x36\x2b\x20\x35\xed\xdc\xe2\xd2\xef\x33\x64\x1e\xa9\x0c\x3e\xa3\xfe\xc6\xea\x5b\x87\xe1\x61\x01\x4c\x4f\x82\x14\xfd\x03\xce\xbf\x94\xab\xe1\x22\x53\x7a\x98\x70\x32\x39\xdf\x58\x21\xc5\xab\x63\x3f\x98\x36\x5c\xc6\x36\xe3\xf1\xd2\xf7\x4e\x0f\xf8\xf1\xfe\xe0\x6a\x3f\x73\x90\x7e\xe5\x04\xb3\x10\xfd\x52\x24\xad\x4d\x05\xcd\x23\xc3\x56\xdf\x8b\x34\x64\x72\x98\xc4\x98\x28\x72\x5b\xa5\xfd\x60\x61\x1e\x82\x9b\x63\x37\xbc\xc9\xdc\xf8\xe8\x97\x1c\xab\x3e\xe9\xc2\x63\x37\xd3\x8d\xfd\xfa\x03\x6b\xf6\x09\x6b\x63\x5a\xc1\xbd\x55\x25\xec\xd3\x77\xa1\x52\x72\xa8\xac\x9b\xbe\xf1\x33\x10\x7a\x42\x25\x8d\x8b\x19\xec\x69\xdc\x42\x61\xbe\x53\x00\xa2\xd2\xd5\xca\x99\xf3\x1e\xfd\xf2\x59\xf9\xd0\x79\x86\x9a\x34\x41\x37\x79\xf3\x02\x88\x24\xd7\x47\x68\x6c\x46\x0f\xfc\x49\x6f\x20\x10\xf4\x03\xe9\x03\xe2\x7a\x87\xdd\x07\x5a\xe0\xa7\xf1\x68\x94\x16\xd3\x1b\xcc\x15\xf4\x90\xca\xf9\x75\xc4\x0e\x71\x5d\x54\x99\x03\xe8\xbc\x0f\x7d\x91\x41\xe0\x20\xf4\x10\xf3\xca\x2b\x2c\x07\x97\xca\x0d\xc8\xd7\x39\x2b\xff\x24\x35\x28\xc7\xf3\xbe\x13\x89\x97\x18\x5a\x4b\x36\xf4\x53\x76\xd9\xfd\x70\xba\x20\x98\x9d\x2d\x1a\x91\x1d\x4b\x98\xd1\x60\xd2\xb8\xde\x59\x2d\xe2\xf4\xc0\x4f\x35\x86\x0d\xf3\x20\xc5\x48\x44\x0d\x5e\x3a\x34\x6a\x14\xd3\xa6\x3f\xe4\x85\xc2\x88\x91\x26\xb7\xf4\x1d\x55\xa6\xeb\x23\xd5\x62\x0b\xab\xf8\x56\x4a\xa7\x9d\x15\x6e\x98\x3f\x36\xd9\xed\x49\x8d\xa9\xca\x88\x8d\x94\x6b\x53\xcc\x47\x68\xa5\x89\x2d\x52\xd5\x41\x52\x69\x60\x28\x25\x24\xba\x61\x94\xda\x65\x94\x1d\x1e\xa3\x0f\x80\x6b\xb6\xd9\x7c\x74\x88\xb9\x3f\xd0\xa7\x70\xa9\xb1\x5e\xfc\xd1\x2c\x5c\x46\x94"}, -{{0x31,0x45,0xbc,0x68,0xd8,0x29,0x79,0x40,0x8e,0x46,0x57,0xb7,0x75,0xf1,0x50,0xc6,0xd2,0x8a,0x32,0x4d,0x74,0x6e,0xa6,0xde,0x90,0xfd,0x72,0xb1,0x7a,0x25,0x79,0x82,},{0xc7,0x76,0x18,0x6c,0xe4,0x7f,0x30,0xad,0x08,0xfa,0x1d,0x2c,0x61,0x6a,0x36,0x44,0x66,0x5b,0xa5,0x4f,0xf7,0x30,0xfc,0x2f,0x4d,0xb1,0xdb,0xa3,0x8d,0xde,0xed,0xca,},{0x24,0xa4,0x33,0x33,0x76,0x83,0xbc,0x71,0xa6,0xca,0x3b,0xcc,0xd8,0xcc,0x24,0x00,0xc2,0x44,0x64,0xfa,0x67,0x71,0x4b,0x46,0x51,0x5f,0x2a,0x14,0x32,0x71,0x27,0x05,0xd5,0x70,0x61,0x4d,0xb6,0xd2,0x6b,0xbb,0xd3,0xf0,0x26,0x7c,0x14,0x27,0xca,0x1c,0x2f,0x40,0xdc,0x9a,0x6f,0x1f,0xb0,0xf0,0xfc,0x71,0x4a,0x02,0xe2,0x4b,0x47,0x08,},"\x2e\xa8\xdc\xe1\x48\x7f\x45\xd6\xff\x8e\xb8\x3c\x54\xfb\x7e\xdd\x76\xad\x6e\x60\x8b\xb8\xda\xf1\xa1\x82\x3d\xa4\xf4\xe4\xe9\x86\x31\x73\x89\x7c\x19\x7a\xc6\x58\x04\x82\x3b\xca\x95\x09\x1f\x59\xe8\x6d\x63\xc1\x8d\xbc\xdb\x85\x74\x3f\x88\x93\xee\x69\x4d\x81\x56\x01\xf8\xf2\x2f\x4d\x7d\xf0\x87\xf0\x11\x4b\xb2\x6c\x37\x95\xe1\xfe\x4b\x7f\x4a\x8f\xa3\x1f\xd9\xf4\xff\x10\xfe\x5d\xd4\x52\xc5\x4c\x55\x78\xc7\x52\xf8\x88\x21\x30\x76\xbe\x46\x7b\xa3\x0d\x2e\x2f\xbb\xee\x87\x7c\x4b\xe9\xb6\xec\x4f\x04\x02\x1c\x00\x6f\x92\x66\x31\x19\x43\xca\xb7\xce\xa9\x9a\x2a\xce\xbb\x69\xee\xc3\xe6\x18\xc1\x31\xf9\x74\x30\x07\x5f\x79\x75\xe3\x9f\x26\xd5\x31\x51\x78\xb6\x9a\x1d\xdf\x73\x17\x61\x05\x1b\x93\xfb\x8d\xf7\xe0\xe8\xb4\x1e\x82\xe7\xf4\xf7\x5e\x91\xd6\xc8\x90\xb1\x4c\xa5\x33\xe0\x94\xeb\x8e\xa4\x48\x6d\x38\x71\x85\x96\x6c\x98\x29\x5d\x3f\x58\xb1\x7e\xef\x6c\xc3\xb4\xd0\x7e\x93\xa3\xd9\xf4\x77\x2e\xe5\x2f\x18\xa5\xbb\x30\xaa\x39\x72\x85\x0e\x65\x81\x70\xbd\xdb\x67\x6f\x33\x26\x6c\x9f\xd1\x0f\x59\x90\xba\xd8\x91\xf0\xce\xb7\x82\x73\x6b\x40\xf0\x1b\xd8\x65\x09\xb0\x63\x04\xa9\x6d\x93\xda\x23\x3d\xbe\xd1\x8a\xfa\x18\x18\xaa\xf5\x7a\xf9\xbd\xbc\x86\x7b\x39\x7f\xf2\x35\xa8\x3e\x85\x72\x24\xb1\x50\x65\x22\x5e\xec\x03\x9d\xd4\xe2\xd6\x9a\x04\xee\x10\xbe\xa0\x69\x50\x41\xed\xa5\x9b\x05\x8e\xc0\x5f\x49\x04\x8e\xe3\x24\xd1\x6c\x4d\x61\x07\xb6\xec\xd0\x48\x75\xeb\x74\x4e\x93\x65\x47\x1b\x4c\x5f\xe6\x61\x1b\x26\x18\x93\xf9\xd2\xb1\x28\xe1\x35\xf9\x2e\x47\x41\x56\xb2\x71\xb3\xc8\x2e\x9a\x76\x63\xda\xd4\x95\x3d\x30\xe1\x0e\xda\x08\x62\x60\x7d\xec\x33\x72\xb3\x99\x70\xf2\xa8\x4b\x12\xf6\x0e\x6d\xae\x7f\x31\x79\x90\x86\xd3\x8a\x7e\x34\x94\x84\x19\xc1\xb0\x7f\x44\xc2\x15\x9c\x86\xb8\xc0\xcf\xe8\x74\x7f\xc2\xba\xd5\xbf\x47\x53\x56\xcf\xe6\x9d\xe2\xdc\x6a\xd5\xa5\x19\xfd\x65\xc1\x25\x64\x70\x1c\x05\xf7\xc2\x77\xec\xaf\xcf\x4c\x87\xb1\x48\xdf\x1f\x98\x79\xa9\xae\x44\x3c\x55\xae\xa5\x21\x38\xc6\xfa\x01\xef\x0c\x3a\xbb\x5f\x2d\xf9\x0a\x57\xab\x66\x24\x17\x8c\x73\x7b\x54\x91\x5b\x7a\xa2\x9e\xa7\x8e\x8e\x49\xef\x5a\x81\x6d\x8a\x92\xc2\xf8\x1b\x8a\x19\x63\x27\x79\xc8\x92\xd6\x6f\x75\x3d\x51\x8c\x41\xcc\xcc\x9e\x59\x3e\x50\x74\x26\x25\xbc\xaf\xa4\x68\x80\x5c\x37\xa2\x1f\x8e\x29\xa6\x96\x0d\xdf\x5c\x5e\x5c\xa1\x4a\x7b\x05\x2a\x7b\x60\x15\x69\x7a\x02\x10\xed\x6f\x01\x43\xe6\xb4\x84\xc3\xf5\xb3\xb4\x72\x6c\x60\x7d\x07\xbf\xb3\xd5\x4a\x09\xc9\x80\x43\xf2\x1d\xcc\x5c\xc2\x0b\xb4\x75\x4e\x2e\x5a\x73\xb2\xf8\x06\xc2\x20\x4b\x72\xf3\x6a\xb9\xe9\x6a\x62\xc6\x27\x7c\x0a\xd6\x6b\xe7\xab\xff\xc1\x63\xb4\xe8\xfa\xfc\xef\xf5\xe2\x02\xe5\x94\x3f\x4f\x0e\x6b\x92\xb4\xdd\xb9\x53\xcb\xb7\x91\xf8\x31\x66\x03\x69\x38\xe6\xc4\x4a\xd9\x1a\x59\x6a\x55\x73\x44\x0f\xb3\x07\x41\xe6\x60\xb6\xcd\x5f\x86\xff\xa7\x46\xe6\xe9\x72\xb8\x05\xc1\x0b\x7b\x7b\x9a\x63\xc0\x55\x1d\xb8\xeb\x4f\x84\x00\xcd\xe2\x86\x8c\x0d\x0d\x4e\xb4\xcf\x11\x7f\x8e\xc4\xab\x97\x44\xfc\x58\x79\xde\xa7\xf0\xef\x16\xc2\x91\xd5\x5c\x17\xf0\x8b\x73\x1b\x7c\x65\xd0\xc4\x41\xb6\x3b\xc8\xff\x5e\x94\x90\x4c\x02\x6a\x13\x61\xda\xcc\x80\xa9\x3a\x9b\x9f\xba\x3b\x40\x36\x17\xae\xb9\x4a\x56\x85\x41\x84\x80\x11\x95\x42\x34\xae\xad\x70\x0f\x03\x4c\x47\xc7\xde\xf8\x77\x90\x52\x55\xf1\x8b\xdb\x9a\x25\x7c\xe5\xbd\xcf\x0e\x17\x67\x0c\xda\xaf\x13\xb1\xc7\xe0\x9d\x58\xf9\x2a\x96\x63\xaf\x23\x9e\x22\x07\x8e\x18\x0a\x23\xcc\xb6\xf6\x4d\x64"}, -{{0x5a,0x25,0xea,0x5e,0x18,0x2d,0x9b,0xf8,0xe9,0x30,0xa2,0x0b,0x6c,0xf5,0x5e,0x24,0xe8,0x38,0x62,0x78,0x9b,0x38,0x39,0xb1,0xce,0x9a,0x71,0xe9,0x38,0xc4,0x2d,0x37,},{0xc9,0x81,0xfc,0x36,0xf1,0xa6,0xd5,0xf7,0xd4,0x51,0xcd,0x5e,0xf3,0x9c,0xd3,0xab,0x02,0x08,0x7f,0xcc,0x6a,0xf2,0x7d,0xd7,0x8e,0xa8,0x27,0x49,0x7e,0x77,0x9e,0x21,},{0xa4,0xf3,0x5b,0x49,0xd7,0xe1,0x98,0xe5,0xd3,0x26,0xe3,0x53,0xfb,0xb0,0x1f,0xa1,0x3b,0x6a,0xe2,0x60,0xd1,0xe4,0x8e,0x30,0xc1,0xb9,0x67,0x73,0x7a,0x5e,0x79,0x93,0x6c,0x97,0xca,0x2b,0xa7,0x99,0xca,0x34,0xe5,0xe7,0x88,0xce,0xa5,0xac,0x8e,0xd1,0x0d,0x5c,0xd1,0x5d,0xae,0x53,0xe4,0x24,0x32,0x32,0x1c,0xc2,0x6d,0xc9,0x98,0x09,},"\x21\x4d\xd1\x92\x7f\x2c\xac\xd9\x88\x87\x14\x24\x9b\x85\x43\x46\x02\xac\x78\x45\x3b\x4a\xf5\x38\x6e\xee\x39\x29\x5d\x3d\x5a\x22\x67\x80\x6e\xb0\xcf\xf2\xc1\x32\xd3\x64\xc2\x42\x0d\x04\xe3\xf6\xcc\x0a\x96\x7b\xf0\x5a\x10\xff\xcf\x12\x17\xbb\xf3\x15\xe7\x5b\x98\x06\x0f\xd4\x58\xd6\x7e\xba\xad\x93\x80\xf4\xad\xc4\xdb\xdf\x74\xcb\xf1\xc6\x47\x92\x02\xbd\xd7\xfe\xd3\xa9\x46\x69\x7d\xc3\x84\x44\xd8\x8b\xfe\x51\xd4\x1d\x7a\x9b\x38\xda\x60\xb8\x50\xc5\x6b\x48\xba\x98\x4f\x6a\x18\x89\x51\x49\x55\xc0\xda\xdb\x69\xa8\xc7\x36\xcc\x76\xcd\xc4\x9f\x13\xf8\x5a\x8b\xfb\x79\x28\xff\x0a\x0c\x0c\x03\xf1\x7c\x74\xb5\xe1\x06\x2d\x75\x53\xfb\xeb\x9d\xd3\xd5\x08\x1d\xe1\xdf\xd8\xa6\xa9\x97\x66\x97\xc6\xa2\x59\xbc\xf7\xd4\xbe\xf1\xc2\x1e\x0a\xaf\x32\x98\xb0\x42\x1b\x91\x9f\xdd\xfc\x1d\xcb\x3e\xc6\x83\xd8\x6f\xf3\xd4\x23\xd7\x1c\x8f\x2d\x72\x3a\x42\xff\x68\xd8\x2e\x9f\x39\x17\x49\xb8\x29\x98\xdc\xfa\x11\x21\x60\xf5\x2a\x41\x3a\x23\xd9\x5f\xc4\x2c\x3b\xd2\x23\x84\xba\xd7\x77\x54\xa7\x10\xd8\xb9\xf8\x4a\xe0\xa8\x02\xfc\x46\x50\x9e\x7f\x2b\x07\x07\x90\x12\xb4\x3b\xfe\xea\xb7\x19\xbd\xe5\x6f\x00\xe5\x9b\x8e\xdf\x1c\x47\x28\x83\xb1\x98\x5b\x2f\xa6\x99\xa1\xae\x90\xcf\x45\xd7\xac\x58\x0c\xeb\x5f\x27\x97\xde\xf5\xb8\xbf\x4f\x2b\x9b\x35\x19\xa7\x27\xb9\xf2\xcd\x12\x56\xa2\xf0\x76\xed\x22\x96\x49\x5b\x5c\x2d\xf7\x88\x7f\xf8\x9e\x88\xe2\x36\xa1\x4c\xde\x63\x24\xf4\x3d\x68\xd9\x01\x72\xb0\xb8\x8b\xd2\x88\x03\xe9\x99\xdb\xed\xcc\x50\x1d\xb6\x54\x54\x4e\x17\x1e\xc1\xf9\xf3\x2d\x4d\x33\x21\xd5\x89\x39\x2e\x03\xca\x65\x9f\x96\x75\x2e\x1f\x08\xa5\x5d\xb5\x53\xd8\x66\x98\x55\x41\xf5\xbe\xf8\x4c\xe2\xee\x32\x3e\x17\xd1\xf7\xdc\x16\x4b\x50\x51\x5a\x28\x7d\x53\x05\xfc\x28\xc5\x98\x3b\x9e\x53\x98\xb2\x40\x7a\xe4\x72\x96\xfe\x4a\x48\x1d\x22\xff\xb4\xb8\x65\xa6\x6b\x97\xa6\xc2\x79\x35\xdd\x8e\xb8\x69\x94\xb7\x9d\x36\x83\x63\x71\x3f\x10\x1d\xc3\x7f\x42\x9e\xee\x0f\xee\x24\x41\xc2\xdc\x17\xbf\x43\x92\x4f\x0c\x04\x4f\x14\x32\x90\xea\xf3\xf9\xee\x4d\x94\x6d\xbe\x45\x83\x1a\x0d\x83\xc0\x76\xe7\x51\xc1\x4f\x3b\x1a\x72\x67\xf5\x44\x6c\x18\x86\x98\xd2\xb4\x6d\x87\xe6\xf3\xb2\x0b\xb3\xfd\xaf\xe2\x4c\xc0\x96\xbc\x31\x2d\x86\x78\xb3\x8a\x80\xc3\xf0\x52\xa0\xc9\x6d\x5a\xd8\x7a\x5d\xd8\xc1\x33\xcc\x9a\x15\xbe\x33\x57\x4c\xd9\x43\x08\xc2\x4d\xec\x1a\x9b\xdf\x18\x9b\xa6\x87\x19\x9f\x72\xef\x67\x09\x87\x8e\x10\xf8\x7b\xd8\xa0\x3d\xc8\x4c\x8f\xa9\x64\x20\x28\x58\x98\xca\x32\x11\xd8\xb0\xcc\xef\x64\x01\x1e\xc2\x4f\x38\xe5\x74\xda\x34\xda\xb9\xd2\xf0\x02\x10\x52\x27\x89\x0f\x92\x48\x8c\x62\x1e\x57\x13\xe4\x7d\xbc\xb1\xa8\x2a\x6d\xa6\x0d\x8b\x22\x01\xeb\x29\xd4\x94\x49\x33\x60\xed\x5a\x3f\x4b\x52\x25\xea\xe7\x70\x7e\xe0\xb4\xc0\x40\x73\x05\xc1\x67\x54\xc7\xf6\x30\xfc\x85\xc1\x3e\x49\x17\x04\x7b\xcf\xf3\xb2\xa2\x93\xfe\x95\x55\x06\xc7\x26\x4e\xa6\x5b\xf3\xa9\xb2\x5a\xcf\x34\x36\x00\xd8\xfa\x0c\x7c\x1a\x29\x0d\x02\x71\x10\x1b\x7f\x40\xb9\x6e\x7f\xda\xf2\x9d\xef\x9d\x93\x27\xa5\xae\x05\x44\x6c\xb5\xa6\xd3\x22\x45\x3a\x8b\x09\x8b\xcf\x3a\xee\x1f\x70\x4e\x14\xd0\x0b\xe3\x42\xb8\x93\x4d\x19\xe5\x29\x21\x88\x72\xea\x3a\x2f\xb2\x12\x4b\x52\x66\x7c\x01\xfc\xa5\x84\x1c\x66\xe1\xe6\x4a\x1e\x68\x0e\x09\xba\x18\x6e\x04\xd1\x05\x18\x6c\xf6\xeb\x72\x8b\x9d\x50\x2a\x66\xb8\x29\xfb\xc9\x92\xa3\x88\x10\x04\xec\xdc\x80\xad\xfd\x04\x4e\xda\x88\x0f\x8a\xf7\x2a\x14\xfb\x55\x0d\x7c\xc7\x41\x94\xa9\x45\x20\x7d"}, -{{0x42,0x33,0x5c,0x30,0xb3,0xf6,0xb3,0x59,0xce,0xf5,0xaa,0xb6,0xa3,0xce,0x28,0x58,0xa1,0x51,0xb7,0xa4,0xfd,0x78,0xd2,0xfd,0x3e,0xe3,0x6f,0xc2,0x9d,0x24,0x94,0x04,},{0x30,0x1c,0x51,0x5a,0x02,0xa4,0xc6,0x6b,0xc6,0x40,0x10,0x80,0xc6,0xca,0x79,0x23,0xb7,0x83,0x1e,0x3c,0x9a,0x72,0xb5,0x5b,0x14,0x02,0x7e,0xb2,0xe7,0xb3,0xb1,0x52,},{0x67,0xb0,0xf1,0x74,0x49,0x03,0x9e,0x8c,0x79,0x7b,0xf9,0x13,0xaa,0xe6,0xe4,0xf0,0xbb,0x99,0xc7,0x4d,0x6d,0x10,0xc9,0x73,0xb9,0x90,0xff,0xe0,0x3e,0x7e,0xe4,0xab,0x5b,0x35,0x80,0x6d,0xb1,0x5a,0x98,0xc0,0x84,0x6a,0x82,0x7e,0x7b,0xcd,0x53,0x9c,0xd3,0xbc,0x09,0xdd,0x11,0x8a,0xb3,0xe5,0x26,0x63,0xa3,0x57,0xb1,0x29,0x91,0x07,},"\x6d\xa2\x25\x1e\x6f\x55\x95\x36\xb0\x9b\xfa\xfb\x81\x60\xa2\xe8\x10\x2d\x31\xf8\xb5\x93\x24\x08\x3e\x52\x27\xb2\x0c\x3e\x5c\x3a\x06\xe2\x39\x67\x68\xdc\xa3\xec\x76\xdc\x7f\xc0\xeb\x3d\x14\x5e\x62\xed\x07\xfc\x1a\x8b\x1b\x2e\x34\x70\x13\xa0\x52\x72\x74\xd0\xb2\x34\xfe\x72\x50\x26\xa9\xd1\x28\xf8\xdf\x20\xdb\xfa\x3b\x65\x03\x81\x8e\xde\xbd\x7f\x24\x93\x40\x80\x94\x5a\x7e\x1e\xa0\x22\x73\xfe\x48\xb6\xed\x1e\x83\xfd\x16\x8d\x79\x73\xfb\xb7\x94\x1b\x40\x37\xd3\xcd\xa5\x55\xe0\xe8\x9c\x2b\x94\x3f\xb1\xe2\x07\x65\xac\x7d\x4f\xa3\x77\x7f\x35\xa0\xa8\xbc\x11\x8f\x59\x9c\x84\x7b\xe3\xfd\xb2\xd8\xe2\x01\xae\x12\xa3\x0b\xde\xfb\x03\x4f\xf2\x4e\x3e\x2e\x70\x1a\x0d\x17\x33\x73\x40\x78\xbd\x1f\x9a\x69\xbb\xc6\x67\xe4\x61\x21\x1f\x2c\x76\x9d\x29\xdb\x7c\x4d\x62\xd6\xb1\xb9\x2b\x56\xf5\xf1\x8a\x93\x1a\x92\x60\x64\xb7\x8d\xa1\x46\xe1\x8b\x48\x13\x9b\x9b\x39\x86\x2a\xec\x37\xbc\xce\x12\xcb\x78\x94\x29\xe6\x8e\xa3\x81\x12\xd0\xb5\xcc\xe3\x0b\xd2\xd2\x6c\x5f\x7f\xd4\x15\xda\xf7\xca\x31\x7b\x33\x68\xb7\x61\x7d\x45\x25\xe5\xbc\x97\xd9\x46\x1d\x5d\x64\xf6\xb5\xd3\x18\xd0\xbc\x3b\x76\xf2\x5b\x06\x05\x42\x69\x09\xf2\xaa\x0c\xd6\x67\xa4\xf0\xe0\x75\xb9\xa9\xfb\x2e\x9a\x6c\x82\x70\x4d\x8a\x9f\x16\x66\x84\x4e\xdc\x32\xf6\x3a\x3d\x4e\x0f\xd9\xfd\xba\x30\xb5\x1b\x33\x36\xb9\x6e\x9e\xae\x39\x2a\x34\x2d\xe4\x9e\x9b\x5f\xa0\xf9\xb9\x01\x71\xbd\xe0\x9c\xf1\xe9\x46\x49\x91\x40\x00\x81\x59\xeb\x18\x65\x56\x3c\x28\x39\x4b\x03\xa8\xd7\xa5\x52\x27\x1b\x28\x76\x68\x75\x66\xb8\x0f\xd3\xbe\x2b\x66\x33\x2f\xca\xd1\x96\xca\xb8\x52\x7c\x56\xe2\x15\x36\xa1\x41\x65\x2c\xdc\x7f\xa7\x45\xb2\x6a\x33\x1d\x78\x7b\x93\xe5\xe8\x16\xd8\xd8\x51\xa5\x8f\x6a\xc0\x7a\x58\x27\xfc\xdf\x47\x2e\x86\x85\x43\x3a\x40\xca\xc0\xc4\x9a\xa5\x69\x31\x9a\x2e\x57\xb4\x1c\x99\x98\x16\x5e\x69\x72\x3b\xa7\x7e\x5c\x04\x23\xc4\xb4\xca\x07\x18\x7b\xb7\x44\x2e\x7d\x31\xca\xac\xb2\x77\x00\xc7\x1a\xe4\x8c\xd0\x55\xed\x2f\xe4\xda\x36\x3f\x44\x82\x11\x24\xcc\xa1\xbf\x2e\x63\xd9\xb8\xab\xd2\xfa\x41\xb1\x42\x2f\x52\xd5\x58\xbc\x5f\x11\x0c\x86\x3c\xc6\x00\x86\x49\x84\xed\x25\x9b\x73\xcd\xdd\x57\x96\xb3\x29\x79\xed\xdf\x76\xa0\x7b\xc5\x9b\x73\x68\xc4\x8e\x12\x9e\xcc\x0d\x45\x35\xdc\xce\xe2\xc3\xb8\xe5\x6d\xe5\x0e\x6f\x5c\xc6\xea\x51\x5c\xd6\xa0\xeb\xdf\x1c\xa7\x9a\xa2\x79\x48\x21\xad\x2e\x10\x9e\xdd\xa4\x50\xc9\xfc\x3c\x84\xd8\xc9\x6b\xc3\x8d\x4b\x43\x7a\x73\x8f\x81\x8b\x4d\xdc\xb6\x84\x38\x3c\x09\xb1\x1b\x36\x05\x2e\x9d\x2f\x76\xa6\x1e\xb4\xd6\x20\x49\xce\xd5\xf6\x16\x62\xc4\xb9\xec\xd2\x4a\x67\xf4\x51\x9d\x46\x52\x8c\x5b\x2e\xb2\x10\x05\xf4\x9c\x73\xa3\x37\x0c\x68\xe3\x7a\xc2\xb1\x8d\x48\x1f\xa1\x0f\x96\x71\x4f\xe0\x5c\x16\x8d\xf1\x1c\xda\x54\xf1\x4f\x49\x37\xe9\xfc\xe1\xf5\x16\xc0\x37\x1b\x36\xa2\xc0\xa0\x50\xba\xc7\xfa\x51\x22\xa6\xe3\x5e\xc9\xc4\x04\x36\x58\x5f\x31\x6e\x6c\x91\x1b\xdf\xd7\xdb\x4b\x80\xb4\x30\x64\x79\xb8\x2a\x2b\x24\x3a\x52\xb2\xd2\xb6\x27\x42\xed\x11\x28\x27\x90\xcf\x6f\xdc\x7c\x9c\x82\x43\x64\xcf\x25\x63\x6a\x85\x51\x50\xbd\xdb\xdf\x7e\x64\x0f\x9f\x95\x2a\x94\x7e\xc7\x97\x49\x25\xe8\x24\x50\x68\xb2\x92\x10\x1b\x1f\x4b\x20\x18\xe8\x5d\x07\x8c\x2f\xee\xf4\x49\x23\x49\x72\x9a\xd4\xac\xb3\x8f\x1c\x7c\x02\x70\xb6\x1d\x3d\xfd\x76\x36\xc6\xcb\xf1\x81\xe4\xc8\xa0\xe6\x4f\xa0\x61\x32\x55\x3c\x2b\x9d\xb7\x01\x9e\x3b\x3c\x48\x5d\x8d\x5b\x7d\xfd\x5f\x51\x5e\x4d\x71\xed\xe5\x35\xae\x7f\x2a\xae\xdc\x23"}, -{{0xbe,0x6b,0x2b,0xab,0xdd,0xd2,0xdc,0xa1,0xb0,0xe1,0x0d,0x12,0xd2,0x0a,0x9c,0xe2,0x9c,0x67,0x85,0xda,0xc1,0xd6,0x0f,0x2e,0xdf,0xa9,0x4a,0xc2,0x78,0x4b,0xa7,0x66,},{0x39,0x8f,0x22,0xf0,0xef,0xbf,0x8c,0x38,0x35,0x5e,0x47,0x91,0xbf,0x67,0x08,0x98,0x95,0x1f,0xbb,0xd5,0x51,0x8f,0x0e,0x2a,0x60,0x5d,0x46,0x00,0x23,0xf6,0x13,0xf0,},{0x70,0x2a,0xb9,0xac,0xbf,0xa7,0x5e,0xa2,0xad,0xbe,0x4b,0xe2,0xb6,0x84,0x76,0x25,0xae,0xb4,0x09,0xee,0xf9,0x59,0x6f,0xab,0xe3,0x9d,0x2c,0x53,0x3a,0x03,0x43,0x1e,0x5e,0x57,0x95,0x52,0xe8,0xa6,0x4f,0xc4,0xfb,0x7d,0x92,0x6a,0xa8,0xff,0xfe,0x06,0x40,0x69,0x84,0x64,0xc4,0x45,0x4c,0xe3,0x5f,0xe8,0x3f,0xf2,0x63,0x05,0x1a,0x01,},"\x5c\x92\x95\x88\x1b\x7a\x67\x06\x69\xb0\x4c\xbe\x0d\xab\xd8\x96\x93\xb7\x7f\x7c\xce\x0d\x4a\x33\xf5\x2e\x02\xeb\x26\x95\x9e\x71\x3d\x9a\xef\x5f\x95\x44\x2b\xdf\x91\x72\x83\x83\x32\x52\x02\xaa\xcc\xc0\x37\x47\x7e\x36\x66\xfa\xca\xf2\x4e\xac\x95\x34\x87\x9a\xa3\xef\xe1\x8f\xfc\x1a\x5c\x54\xe3\x9c\x76\x87\xd0\x93\x7b\x24\x71\xba\xb3\x89\xb6\x46\xcb\xe6\xb3\xe5\xd5\x96\x1e\xa6\x3b\xd4\x52\xb4\x74\x33\x44\xce\x4c\x79\x33\x74\x52\x37\x95\xc7\x81\xee\x84\xd5\x11\xe2\x94\x11\x19\xba\xd1\xf4\xa7\x46\xed\x9d\xba\x89\xc8\xd0\x75\x1a\x64\x02\x71\x86\x35\xf6\xe3\x1d\x9e\x18\x68\x1c\x69\x56\xc5\x37\x32\x51\xd3\x5f\x53\xba\xa1\x98\x7c\xd4\x48\xc9\x03\x1a\x07\xf3\x2c\x80\x29\x11\x9d\xe3\xa9\x16\x31\xde\xde\x1d\x93\x3e\x0f\xa3\x26\x29\xaf\xe1\xb4\x2e\xb5\x91\xc2\x2f\x87\x33\x1e\x93\xcc\x08\x3c\x23\xf6\x4a\x6e\x5e\x58\x6f\xf3\x1c\xc0\x4e\x42\x3c\x56\xae\x3f\x6a\x73\x94\x6c\x48\xde\x4d\x85\xab\x00\x17\xba\x24\x45\x6d\x69\xb5\x9d\xca\x6d\x40\x3b\x64\xb0\x7c\x40\xd3\xb9\x0e\x12\x23\x21\x5e\x3f\x7e\x87\x6c\x67\x01\x11\x1e\x37\xe5\x17\x77\x08\x87\x31\x0c\xa8\x56\xf0\x09\xa0\xd6\x06\x54\x83\x5d\x94\xe6\x58\x7a\x43\x9d\xa5\xdb\x0a\x0c\x37\xd7\xc9\xd3\x7c\xa1\xd7\x03\xe1\xb3\x22\x76\x31\xad\xac\xaa\x79\x42\x1a\x1c\x43\x9d\x60\x34\x9a\xe5\x77\x41\xb7\xa8\xad\x09\xec\x29\x31\x23\x03\x0b\xf6\xba\xc0\x68\x9e\x53\x1c\xa7\xe7\x27\x18\x22\x3f\x9e\xa4\x3b\xec\xb0\xee\x9d\x9c\x1a\xb8\x45\xed\x1c\xae\x44\x3e\x3c\x5d\x4a\x9b\x1e\xde\x6d\xb3\x41\x7c\x3a\xce\x28\x11\x43\xf4\x2d\x85\xf5\x99\xb3\xb9\xd3\xd0\x5f\xa0\xed\x07\xc1\xec\x35\xff\xab\x03\x05\x16\x8b\x4e\x56\xe5\x8a\xfa\x06\x17\xf9\xa8\x6b\x1b\x5b\x20\x1d\xcc\xb0\x72\xb4\xce\xf0\xbb\x7b\x95\xc5\x2d\xae\xef\x9d\x9e\x74\x24\xa5\xc0\xf1\x48\xf9\xff\xe6\x0a\x5b\x23\xe0\xff\x82\xc7\x30\x99\x2a\xc9\xc1\x7f\x97\xf0\x65\xcf\x0a\xd5\x37\x7e\xac\xcb\x31\xd8\xbb\x92\x3b\xd2\x60\xea\x11\x9e\x6f\xa9\xbd\x69\x83\x48\x2d\x70\xd9\x21\x91\x02\x40\x2d\xc6\xa3\x49\x91\x93\xd0\xc1\xcd\x3e\xd2\xa6\x69\x21\xa9\x8d\xf6\x9b\x79\x14\x13\xf4\x97\x0b\xbc\xe0\x4f\x63\x9a\xf9\x09\xc6\x4f\x45\x60\xdb\x0a\xf6\x00\x3d\xc4\x62\x19\xe8\xad\x2b\x37\x2f\x8b\x5f\x81\xcf\xaa\x04\x1a\xb7\x1a\x34\x8c\x93\x1e\x8d\xfd\xbc\x40\x9c\x22\xd7\xee\x6e\x07\x62\x6e\x10\x4e\xc6\xcc\x7c\x6a\x41\x16\x17\x7f\x93\xaf\x16\xf1\x24\xf1\x96\xda\xb6\x19\xb6\xf6\x98\xc2\xd1\x91\x85\x8e\x96\x0c\x2e\x94\x7b\x51\xf3\xac\x48\x38\x75\x9c\x21\xfe\xf7\xeb\xae\x35\xda\x24\xf5\x5e\xbd\xa9\xb9\x87\x9a\xea\x17\xa6\xd8\xd9\x27\xde\x48\x7b\x17\x5f\xd7\xfa\xa2\x14\x38\xa2\x09\x23\xdd\xbb\xca\x72\xe6\x72\x69\x34\xbd\x6c\x21\xe8\x11\x80\x19\xf6\x5b\x38\x10\xa0\x7f\xa2\x7b\x1c\xba\x64\xd0\xf3\x9f\x0b\xfd\x49\xdc\xfa\xfd\xef\xe3\x79\xbd\xea\x82\xf3\x1a\x9c\x39\xf7\xe8\x1d\x29\x43\x37\xd1\x0f\x1e\x9d\x8b\x50\xeb\xa4\x58\xce\x7b\x75\x3d\x36\x96\x85\x38\x51\x3e\xdd\xb0\xe8\x45\x34\x41\x1c\x4a\xf3\xf0\x21\x46\x10\xee\x39\x01\xa0\xeb\xf3\x16\x17\x3c\xca\xf1\x5c\xd7\xee\x49\x6d\xbf\xc2\x46\x5e\xb8\x34\xdf\x62\x02\x9d\x62\x1f\xe9\x11\x82\x4d\x79\x87\xdf\x2d\x46\x34\x6b\x4d\xce\x1e\xce\x7d\x19\xd5\x51\x18\xc0\x37\xc9\x95\x51\x11\xd0\x7f\x1f\xc3\x62\xc7\x39\xf1\xea\x5b\x27\x5c\x71\xc0\xae\xbf\x59\x65\x5e\x2d\xef\x16\xe1\x23\xb3\xeb\x25\x26\xc3\xca\x5e\x83\xcb\x24\xd5\xb6\x8d\x7a\xc4\x0a\x67\x59\x33\x84\xc5\x63\xaf\xe0\xb5\x52\xad\xaf\x60\x80\x50\x35\xbe\x97\xb8\x06\x76\xad\xeb\x15\x76\x52\x08\x33"}, -{{0xb1,0xe4,0x7c,0xa3,0x1c,0x64,0xb6,0x8a,0xaf,0xaf,0xb4,0x43,0x51,0x2e,0x66,0x78,0x7c,0x65,0x92,0xf3,0x34,0xaa,0x78,0xfa,0x21,0x9a,0x3d,0x93,0xc3,0x3a,0x4a,0xb3,},{0x58,0x11,0x9b,0x38,0xe6,0xa1,0x48,0xa9,0x36,0xbc,0x5f,0x92,0xf4,0xf2,0x9b,0x98,0x2f,0xf2,0xcc,0xa6,0x4a,0x5a,0xff,0xa1,0x4c,0xa1,0xb6,0xa6,0x2f,0xe3,0x28,0xc4,},{0xdf,0xac,0x86,0xdf,0x58,0x6e,0xc3,0x4c,0x7c,0xfe,0xa5,0xd5,0xa6,0xcd,0x11,0x40,0xe5,0x0b,0x6b,0xf0,0x50,0xf8,0xe4,0x1a,0x19,0x0e,0xbf,0xd3,0xb1,0x43,0x2b,0x95,0xa5,0x7d,0x56,0x52,0xdb,0xae,0x8f,0x53,0xe0,0x37,0xae,0x32,0x6e,0x7f,0x18,0xcf,0xef,0x7c,0x77,0x9f,0x40,0x34,0x6f,0x7c,0x0d,0x86,0x44,0x61,0x05,0x93,0xf2,0x09,},"\x76\x7e\xc1\xb3\xda\xf2\x04\x38\x7f\x3f\xd3\xb2\x00\x10\x78\x1a\xfb\x1f\x38\xf6\x14\x47\x42\x13\x28\x7f\xff\x11\x30\x7f\x5f\xf5\xae\x7e\xc9\x45\xa2\xb9\xb4\x87\x00\x49\xd4\x53\x2f\x8f\x61\xc1\xa7\xb5\xf2\x11\xfc\xa2\xe6\x7c\x37\x4d\x96\x21\x9d\x8e\xa9\xde\x73\xf0\xe3\x87\x04\xfc\x94\xc0\xe9\xe7\x2f\x2e\x15\xda\xba\x3f\x88\xf7\x49\xb1\xed\x70\x26\x60\xdb\x1a\x35\x2a\x26\x67\xd4\xdf\xd4\xe0\x0a\x18\xef\xa4\xc6\x60\x9e\xe9\xc9\xa8\x8a\xda\xcb\xbb\x98\x5d\x3d\xe8\xdd\xd1\x7d\x4e\x4e\xb7\xcf\x74\xa1\xda\x91\xed\xb3\x90\x85\x2e\xa4\xcb\x9a\x42\x4f\x7f\xa2\x22\x9e\x08\x30\x33\xa3\x40\x59\x11\x7e\x5e\xfa\x7b\x66\x13\xd7\x5e\x58\xb7\x02\xc6\xce\xe5\xd0\x04\xe8\x59\x9b\x97\x50\x3a\x5f\x10\xc4\xc4\xe5\xb9\x57\x73\x71\xd3\xd0\x5b\x2d\xfb\xf7\xcb\xef\xe6\xd0\x92\xd6\x5c\xbd\x40\x51\x38\xd9\xb0\x4c\x51\x86\x23\x59\x83\xfa\xb6\xd4\xce\x85\xb6\x36\x27\x62\x06\xd7\x4a\x2e\xe7\xdb\x61\x64\xda\xc4\x7c\xce\x78\xf5\x0d\xb9\x9a\xf6\xac\x6e\x70\x64\xc1\x3a\xab\x79\x3b\xe8\x7e\x66\x28\x9c\x94\xa0\x9f\xb0\xa3\x1d\x97\x97\x1e\xdd\x74\xea\x9c\x0c\xe8\x74\xd2\xb7\xd6\xc4\xab\xae\xff\x07\xf8\x70\x22\x51\x51\x94\x6a\x5c\x47\x6f\x6b\x97\x89\x96\xb8\x7d\x8c\x98\x46\x06\xc7\x91\x28\x7d\xa6\xba\xd0\xaa\x44\xb0\x13\x0b\xe8\x86\x71\xa5\x56\xe2\xde\x35\xc4\xcb\x03\x8e\xe7\x81\x27\x35\x30\xac\xe0\xa1\x04\xc2\x78\x09\xae\xe0\x33\xc8\xbf\x90\x29\xd9\x0f\xe7\xba\x06\xaa\xa9\x4e\x16\xa5\x2c\x64\x3d\xfd\x92\xa7\x62\x4f\xbb\xee\x77\xa7\x15\x8b\x2c\xc1\x51\xbd\x3f\x61\xa1\xa7\x6f\x32\xb2\x84\x89\x30\x7a\xcf\x0d\xd8\xc2\x6c\xc4\xad\xbb\xb8\xde\x43\x0d\xb4\xe4\xf5\x83\x08\xb6\xab\x90\x45\x61\x11\xde\xac\x29\x78\x17\x2f\xe1\xfc\x0c\xe4\x98\x08\x8a\xdd\x4c\x31\xc2\x1f\x24\x27\x90\x25\xfe\xb4\x8c\xbb\x7a\x92\x0c\xff\x2d\x28\x71\x05\x87\xaf\x52\xc8\x44\xdb\x8a\x7a\xeb\x7d\xf1\x0d\x43\x41\x1a\x3c\x8e\xee\xbb\x40\x6d\x6e\xfc\xb1\x92\x48\x88\x7d\x45\x0b\x57\x3d\x90\x30\x5e\x1f\x23\x75\x3e\x89\x05\x11\xdc\xc7\x7c\x74\x0e\x31\x6a\xd7\xf5\x2d\x49\x02\x07\x3d\xb3\x99\x8e\x4e\x4a\xcc\x4e\x01\x88\x5b\xd1\x18\x8e\xcd\x61\x65\xae\xde\xd1\xe7\x78\x70\x2b\x6a\x6a\x79\xa9\x49\x99\x10\x2d\xf7\x20\x18\xf7\x92\xf8\xf1\x62\x00\x7e\x81\x2a\xef\x8f\x95\x6e\x12\x32\x82\xbb\xdb\xd0\xc3\x56\x12\xc2\xd3\x47\x3f\x94\x4c\x6d\x76\xbe\x9e\x86\xff\xfa\x46\xcc\xb1\xae\x13\x50\x5a\x4a\x81\xf3\x1b\x84\x26\xb8\xb6\x0d\xe8\xe8\xa7\xc1\x6d\x1e\x16\x65\xb2\x71\x43\x46\x65\xc4\x42\xa9\xc6\xa9\x77\xce\x98\x6f\x69\x93\xb7\x43\x9a\xf0\x3b\x40\x2e\xea\xff\xf1\x45\x6d\x15\x15\x26\xd9\xc5\x8f\x51\x5f\xd2\x48\x5e\x0c\xbb\x32\x4a\x50\x3a\x8d\x49\x13\x44\xcd\xb2\xaf\xf4\xc4\x1a\xa8\xe2\xed\x66\xe5\x80\x83\xbf\x0d\x2f\xbf\x48\x77\xc8\x5a\x4b\xcd\x6b\x9c\xbb\x82\x12\x42\xc9\x41\x47\xe5\xfd\x8b\x7d\xd7\x92\xad\x0a\x28\xd4\x9d\x41\x10\x0b\x43\x1b\xb4\xd8\xc7\x83\x3d\x85\x05\xdd\x9e\x26\x49\xf9\xca\x70\x51\xbe\x68\x71\x2e\xf3\x63\x71\x02\x03\x6b\x00\x26\x49\x47\x3c\xe2\x59\x67\x7d\x82\xc6\x06\x28\x95\xe1\x61\x92\x8b\x75\x2f\x13\xc9\x1a\x45\x95\x5e\x80\xf0\x07\xde\x69\x0e\xdf\x8a\x0e\x5e\xee\x44\x22\xe1\x62\xb9\xd2\xb4\xa9\x21\xd3\xa6\x48\x45\x79\x3a\xa2\x22\x9e\x9c\x23\x9e\x57\xa6\xb1\xa9\x0a\x52\x54\xc3\x51\x2f\x99\x34\x53\x15\xac\x7d\x34\x57\xf9\x15\x42\x96\xc6\x68\x22\xab\xe1\x84\xd6\x4e\x57\x2b\x9c\x38\x49\x29\x58\xe2\x1b\x02\x92\x67\x54\x10\xe7\x34\x8b\x2b\x71\x8a\x0b\x75\x92\xca\xee\x94\x58\x1a\x94\x8d\x2f\x41\xfa\x03\xc6\x1e"}, -{{0xfb,0xd5,0x5f,0xa7,0x43,0xc3,0xa5,0x91,0x0b,0x38,0x57,0xdd,0x0b,0x6a,0xa5,0x84,0xf3,0xb2,0x38,0xde,0x05,0x6b,0x76,0xab,0x76,0x17,0xae,0xb5,0x26,0x38,0xfe,0xf6,},{0xa7,0xa1,0x63,0xc4,0x18,0x3b,0xd8,0x4b,0x75,0x6d,0xf3,0xc8,0xaf,0xdf,0xb9,0xcd,0x5b,0x24,0x23,0x52,0xd9,0x49,0x9e,0xbd,0xab,0x90,0x78,0x5c,0x3b,0xd6,0xdb,0x2d,},{0xef,0xfb,0x29,0xda,0x69,0x85,0x97,0x1c,0x20,0x2e,0x24,0x50,0x30,0x1d,0x49,0x71,0x1b,0xed,0x25,0xfa,0xd8,0x5f,0x61,0x99,0xd1,0xeb,0x1e,0x71,0x91,0x4d,0x96,0x4c,0xbe,0x18,0xe3,0x4c,0xc3,0xe3,0x28,0x72,0xcd,0xec,0x02,0x6b,0xd1,0x19,0xa4,0x1c,0x1c,0x07,0xca,0x41,0xe8,0x2a,0xcb,0xa6,0x2f,0xb0,0xa7,0xc8,0x2a,0xed,0x80,0x0c,},"\xbf\x52\x52\xb2\xae\xca\x11\x63\x77\x1f\x76\x62\x78\x76\x80\x66\xf2\x19\x71\x35\x7e\xa7\x99\x61\x58\xa8\xd6\xe9\x08\xdd\x59\xb5\x99\x71\x34\x9f\xa1\x78\x82\xcb\x92\x24\xb9\x72\xd0\xff\xab\xe8\x55\x10\xdc\xf2\x5a\x9f\x9f\x9b\xde\xfa\xd2\xf4\xca\xdf\xbb\xda\xcc\x1f\xca\x9d\x94\x8c\xb5\x41\x2f\x47\x4c\xad\x23\xb5\xb9\x19\x9b\xf3\xc7\x37\x06\x41\x33\x9b\x75\x0e\x1f\x78\xc2\xad\xb4\x60\xaa\x5b\x21\xb1\xfa\x8f\x97\x71\x4a\xbb\x4e\xd5\xe9\xcb\x51\xd6\xde\x55\x81\x66\x18\xab\xd3\xfd\x2b\x28\x6b\xc1\x1c\x67\xba\x01\x12\x93\x73\xd4\x35\xb3\xe7\xe3\x91\xba\x37\x26\x14\xda\x83\x22\x87\x5e\x46\xa6\x75\xb6\x45\x15\x60\x24\xca\xd2\xdd\x13\xf9\xa0\x81\x61\x6b\xf1\x31\xa2\x43\x58\x89\x4e\x0e\xfa\x1d\x56\x64\x8f\xfb\x42\xef\xb5\x40\x31\xda\x7f\x37\xd1\x97\x61\x51\x55\xae\xdb\x69\xc4\xe7\x09\xc8\xbb\xbe\x7f\xbf\xcb\x59\x83\x47\xac\x5d\x0c\x63\x84\x07\x84\x7b\x28\x1c\xf1\x16\x43\x30\x97\xf5\x66\x21\x58\x71\x9f\xcd\xd3\x7b\xeb\x48\x92\x68\xce\x71\xde\x7d\x70\xed\x92\x5f\x74\x3f\xc6\x3a\x71\x5f\x7e\xee\x75\x49\xfd\xb9\x09\xcc\x45\x4c\x98\x8b\x30\xae\x4d\x77\xd6\x2f\x65\xa0\x7e\x2c\x8f\x93\x62\x38\x5d\x02\x8a\x60\x31\x08\xc9\x45\x87\x2f\x5e\x1a\x97\x41\x98\x78\xed\x49\x54\x2e\x28\x8e\xf0\x7b\x5c\x90\xf5\xc4\x15\x9e\x16\x23\x03\xd0\x80\xf6\xac\x2b\x05\x8d\xdc\xac\x60\x74\x6f\x9e\x1c\x9e\xc1\xdf\x8e\xda\x42\xd6\x27\x38\x58\x6d\x3f\xdd\x65\xdf\x55\xf4\x37\x4f\x32\x94\xe0\x86\x8d\x41\xef\x0b\xb1\xfd\x55\xe0\xcb\xf1\x95\xbb\xfc\xfc\xde\x5b\xdb\x41\xfa\xd9\xa0\x47\x7e\x4c\x90\xca\x27\xfa\x8c\xf5\x03\x36\x2a\x33\xfd\xec\xa5\xa4\xf0\xff\xea\x26\xe8\xd7\xe1\x34\xfa\xd3\xb1\xec\x3d\x05\x60\x55\xbb\xa5\xe6\x5d\x81\x15\x3e\xe8\x31\x87\x3b\x93\x8d\xf7\xd2\xc8\x3c\x2a\x52\xb3\xc2\x21\x82\x7f\x96\x1b\xd0\x08\x36\x22\x32\xd8\x82\xa0\x41\x2a\x04\x7a\xfd\xfb\x85\x97\xc8\x65\xa2\xaa\x2c\x2c\xf5\x18\x99\x34\xa8\x3e\xe6\xb7\x52\xa6\x26\x94\x1e\xdc\xe0\xc2\x0b\x6f\x7a\x69\xf1\xcf\x12\xf9\xa3\x31\xcd\xfa\x9e\xda\x24\xc8\xde\xfa\x76\x9c\xcc\xe2\xef\x74\x6c\x30\x7d\x8b\xb0\x48\x91\xfc\xef\xd4\x9a\xf3\xe6\xf9\x69\x91\xa7\xa2\x0f\x27\xb6\xc0\xaf\x12\x18\xbe\x31\x79\x1d\x1d\x02\x93\xe0\x81\xb9\x0a\xf3\xb9\x2e\xcb\x17\x5e\xc8\xc7\x89\xf7\xa8\x64\x2e\x04\x1e\xc3\xa6\x1a\xae\xfe\xf6\x2a\x80\x7d\x1a\x50\x54\xad\xf8\x32\x3b\xed\x94\x22\x41\x62\x37\x32\xa2\x05\x1d\xc0\x1f\x9a\x20\xa2\x9a\xa4\x8b\x3f\xdf\x26\x5d\x0b\xa6\xc1\x38\xfb\x57\x93\xe2\x87\x50\x02\xe7\xde\x3f\x5c\x3f\xf7\xe8\x3a\xd2\x7d\x11\x1c\x84\x8b\x7e\x6e\x2e\x5a\xd5\xf2\x8e\xb7\xc3\x63\xf9\x5f\x96\x0c\xbc\x42\x13\x36\xce\x98\x5f\x94\x6b\x05\x15\xb1\xbd\xd3\xa8\x32\xc3\xfe\x90\x3f\x7b\x44\xe2\x0c\x92\xea\x80\x82\x6f\xbf\x97\xe2\xa4\xfc\xaf\x2d\xb1\xa0\x86\x98\xdd\x62\xed\xd0\xa8\x45\x89\xd7\x46\x2c\x44\x7b\x4a\x89\x6f\xe0\x08\x60\x04\x24\x96\xbd\x51\xb1\x92\x5c\xb7\x9c\xc3\xb8\x29\x01\x6a\x4c\x7e\x62\x79\x0f\x80\x58\xc5\x46\xf2\x14\x5a\xaa\xef\x4d\x4b\x1e\x27\x3f\xf6\x13\x00\xf8\x00\x8e\x94\x6b\x62\x2f\x60\xe5\x05\xf5\xf6\x29\x0d\x51\xeb\x99\x7d\x20\xfc\x3f\xbb\x3e\x99\xed\xd6\x8f\xf5\xcc\xe9\xe8\xc2\x83\x88\x1c\x36\x4f\xf2\x15\xcb\x50\x04\x5e\x60\xf4\xa7\xee\x45\xb6\xc9\xd8\x64\x47\xf3\x81\x41\xd3\x42\xdb\xc5\x30\x8f\x8c\x66\xef\xc4\x7f\x7c\x45\xf6\xd2\x5e\x65\x64\x30\x9a\x86\x2d\xb9\x0f\x4d\xf3\x31\x78\x7e\xcd\xd8\x9d\x3a\xaa\x46\x05\x3e\x29\xf1\x02\x62\x4d\xdf\xe8\x0e\x8a\x3f\x99\x28\x7c\xec\x19\xfa\x83\xe4\x4d\x55\x7c\x04\x41"}, -{{0x5d,0x66,0xce,0xb7,0xc6,0xe5,0x8c,0xac,0x91,0xe2,0x88,0x27,0x91,0x70,0xe8,0x18,0xe7,0x87,0x18,0x0c,0x6b,0x42,0xdf,0xa1,0x68,0x78,0x7d,0xd0,0x7f,0x80,0x9f,0xa4,},{0xef,0xc9,0xb3,0x5d,0xb8,0x1f,0x34,0x61,0x98,0xa7,0xac,0xc6,0x9f,0x65,0xfd,0xfb,0xf4,0xc2,0x2e,0x68,0xdd,0x76,0x12,0xe3,0xb8,0xec,0x68,0xd3,0x78,0x55,0x3b,0x8d,},{0x6e,0xf2,0x64,0xab,0xf8,0xb0,0xe5,0xc2,0xd7,0x93,0xb2,0xc7,0x52,0x79,0x61,0x4a,0x39,0xc7,0x75,0xeb,0x2b,0xcc,0x08,0x91,0x06,0x7a,0xbc,0x61,0xf6,0xd6,0x44,0xa6,0x9f,0xf8,0xf8,0x14,0xa3,0x05,0x22,0xcc,0xa9,0x05,0x36,0xf0,0x12,0xc6,0x28,0x3a,0x76,0xc3,0x2b,0x89,0xee,0xe1,0xbd,0x9a,0x43,0x36,0xf4,0xfd,0xda,0xc8,0xdc,0x0b,},"\x94\xd7\x2f\x6d\xec\x4f\x7c\x92\x06\xb4\x15\x10\xce\x71\xa0\x29\x55\x60\x4f\x3c\x5d\xe8\xe4\x47\xd5\x87\x18\x65\xa7\x58\x98\xa4\xd2\x07\xa2\x6c\xf3\x3d\x10\xca\xf0\x5a\x0b\x6e\xd0\xd3\x89\xfe\xe9\xed\x49\x27\x50\x98\xa8\x8e\x1c\x0d\x83\x04\xe8\x1b\x40\x74\x21\x4c\x7a\x5c\xe1\x57\xeb\x26\x17\xef\x04\xe1\x32\x4b\xa9\x42\x12\x9f\xaf\x32\xc3\x1c\xb4\xaa\xe4\xa5\x91\x6c\x75\x08\x08\x72\x68\x56\xf7\x18\x0e\x57\x97\xed\xe4\x43\x62\xd7\x47\xd7\x0c\xec\x15\x9d\x3b\x6a\xce\xc6\x3a\x51\x4c\x7e\xf3\x1b\x2e\xcd\x16\xdb\x7f\xe6\x8e\xa9\xc5\xea\xd9\xd8\x70\x92\x18\x00\x34\x8f\x69\x54\x12\xf3\x09\x3e\x61\x98\x5a\x31\xea\xdb\x79\xb5\x9d\x91\xdd\x9a\x37\xf8\xd4\xef\x7a\x5d\xdf\x22\x3d\x4b\x24\x77\x4c\x2e\x44\xe3\xf2\x71\xff\xb8\x50\x0d\x59\x53\x81\xb3\xdf\x2e\x8e\x6b\x79\xee\x65\x53\x5a\x51\x9a\x43\xea\xa5\xe5\x2b\x25\x6c\x26\x43\x30\x5e\x31\x70\xcb\xe5\x76\x06\xa0\x54\x5f\x85\x86\x56\x5c\xfb\x75\xbf\x5e\x95\x64\xc6\x2a\xf0\x5f\x15\xee\x6e\x62\xaf\xee\xf8\xc2\xc7\xa9\xda\xe2\x35\xc9\xed\xd1\xd7\xc2\x5c\xf4\x9a\xdc\x03\x3e\xe7\xb5\x83\xf5\x18\xbc\x16\x8e\xa4\x88\x36\xb5\x0f\xfe\xdd\x20\x32\xb3\xf6\x30\xcc\x56\xda\xad\xd5\x13\xeb\xda\x86\x48\x23\x61\x0f\xc6\x7a\x72\xb9\xa7\xd8\x11\x71\x05\xc1\xc7\x1d\x85\xa9\x6b\x1d\x27\xa4\x41\xfa\x1e\x7c\x6c\xf8\x02\x33\xa4\x9f\xe0\xe7\x6a\x40\x27\x8d\x06\xe3\x43\x47\xd8\x7b\xe7\x7b\x98\xde\xd5\xe2\xa3\xea\x1a\xfb\x13\xbe\xe1\xe6\xcd\x6c\xa6\x3b\xe5\x4f\xcf\x88\xa2\x0c\xcb\x7a\x9f\xc3\x24\xbf\x61\x43\x20\x1b\x44\x48\x3b\xcc\x96\x40\x33\xda\xb7\x1c\xf8\xf2\xa5\x91\xfc\x05\x0d\x57\x24\xe9\x5a\xa5\x0d\x32\x89\x6e\xec\x0f\x3b\x34\x31\x1d\x2a\x99\x34\xe9\xf8\x52\x97\x7e\x25\x3f\x15\x30\x4c\xae\x24\x16\xc2\xc4\xfc\xd8\xf1\xfe\xcc\x3f\x1f\x64\xbb\x79\x75\x99\x29\xab\xb0\xe8\xe8\xf5\xf7\x29\x3d\x69\x1a\xf2\x2a\xbd\x3b\x2a\x67\x70\xb0\xcf\x14\x46\x08\xf2\xd6\x2c\xc7\xe5\x2b\xfe\x33\x3b\x2e\xd2\xde\x39\xb9\x9a\xfd\x37\xe3\xac\xf0\x7e\xda\x37\xdd\xf0\xdf\x02\x9b\xff\x2e\xc2\x25\x44\xb6\x0b\xd7\xdb\x23\x8d\xf1\x97\x5f\xfa\x00\x75\xa8\x2a\xbd\x8d\x6b\x05\xb2\x67\x18\x0b\x87\x0e\x21\xab\xf3\x69\x81\xae\x77\x68\xde\x53\x99\x3b\x30\x4f\x1c\x54\x53\x87\x2f\xdf\xa8\xed\xad\x45\xf8\x00\x1a\xa0\xe7\x34\x2b\x3b\x58\xec\x0f\x38\x9d\xcb\xc2\x71\xfb\x0f\x90\x00\x62\x87\x57\xab\xba\x58\xc0\x57\xe1\xa0\x89\x9f\x6f\xaf\x15\xf3\x74\x0f\x31\x43\xf5\xc0\xb7\xa9\x15\x96\x80\xde\x8c\x55\x72\x66\x44\x1b\x3b\x01\xca\xac\x12\xec\x27\x8f\x5a\x10\x25\xdf\x53\xed\xb6\x13\x4c\x96\x66\x3a\x96\x66\xae\x3b\xaa\x90\xfc\x83\x51\x11\xef\x05\x1b\xd9\x12\xf6\x79\x67\x44\x91\x13\xb6\xa8\x5f\x71\xdf\x8c\x60\x37\x72\x4e\xb8\xfc\x7d\x83\x19\xbc\x03\x85\xbe\x9b\x0e\x99\xe9\x5f\x9a\xed\xca\xe8\xd4\x5a\x51\x44\x76\xf0\x5b\xcd\x72\x35\xc0\x13\xeb\xc3\xae\xa9\x12\x3c\x67\xaa\x6f\x3b\x79\xc8\x5e\xa5\xdb\x15\x9e\xef\xad\xfb\x75\xa5\x0a\xc6\xb9\x5b\x49\x6b\x55\x72\x58\x1a\x76\x11\x2f\xf6\xdb\x26\x3f\xc1\x4c\x58\x18\xaa\xd5\xbc\xa3\xb2\xcb\x3a\xc8\x11\x6d\x42\x94\x82\x78\x1e\x06\xf6\x1e\x75\x63\xe6\x50\x5e\x51\xc8\xff\x99\x8b\xf8\x4a\xed\xb5\x20\x2e\x2f\x9f\xf4\xc2\x68\x98\x20\x29\x6c\xc6\x96\x03\x09\x1b\x8b\x81\x8f\xbe\xb2\xaf\x5f\x4c\x57\x06\x0d\x98\xc1\xa9\x04\x84\x3a\x70\xbf\x97\x5b\x3c\x3c\xa6\x03\x1a\x4c\xad\x5b\x4b\xbf\xba\x7e\x9b\x47\x49\x1a\xb7\x40\xd9\xeb\xe4\x1d\x76\x88\x10\xcb\x8c\xc5\x1a\x93\x7f\x7e\x3b\x22\xe3\xcf\x07\xce\xae\x0c\xe2\x08\x31\x49\x5a\xfc\xdd\x8c\x1a\x98"}, -{{0x62,0xed,0x86,0x82,0xbd,0x3a,0xb3,0x96,0x6e,0xba,0x3b,0xff,0xb7,0x75,0xa3,0x18,0xa0,0x3d,0x99,0x93,0x19,0x79,0xe9,0x9f,0xeb,0x2d,0xdb,0xd6,0x94,0x55,0xa0,0xef,},{0xd3,0x2a,0xda,0x17,0x8b,0x3e,0xc7,0x70,0x0c,0x47,0xdd,0x6d,0x36,0x53,0x22,0x03,0x3f,0xe4,0x31,0xc3,0x02,0xb4,0x6f,0x8d,0x58,0x79,0x8e,0xd8,0x33,0x71,0x56,0x6b,},{0x3d,0xa8,0xd1,0x4d,0xc4,0xe7,0x1f,0xe6,0xc3,0x2e,0xde,0x46,0x37,0x88,0xe4,0x1b,0x82,0x6b,0x4e,0x21,0x60,0xba,0x10,0xc9,0x5f,0x1c,0x8a,0x27,0x49,0xaa,0xd8,0xf1,0x2e,0x98,0xae,0x24,0x68,0x30,0x3b,0xaf,0x69,0x08,0xbd,0xb3,0x5e,0xf3,0x8a,0x5e,0xcd,0x77,0x74,0x1e,0x72,0xee,0x3a,0x42,0x7f,0xd9,0x04,0xda,0xe6,0x6f,0xcf,0x03,},"\x9e\xb1\x3b\xc7\xfa\xcf\x51\xa1\x80\x54\x1e\xc1\xdc\x5f\x5a\xcb\x14\x8c\x8d\x5e\xad\xcd\x2c\x4e\xf0\x68\xbc\xdd\x11\xb3\x49\x25\xea\xbf\xaf\xab\xfe\x82\xa2\x84\xbc\xba\xee\x13\x81\x15\x2a\xf8\xe5\xe0\x9f\x03\x7c\xf1\xbb\x64\x84\xac\x18\xe3\x73\x59\xbf\xaa\x4c\x87\xaa\x07\xd3\xd1\x4e\xd0\x89\xb0\x53\x91\x0d\x1f\xa4\x73\xf7\xbc\xe1\x43\xe2\xa5\x9c\x4d\xaf\x99\xb6\xc6\xe4\xe9\x29\x1d\x97\xc8\x64\x71\x2a\xf3\xea\xba\x53\xce\x25\x17\xa4\xf7\x5c\xd7\xec\xf2\x78\xf3\x4e\x22\xb7\xdf\xfd\x08\x8f\xa5\xec\xad\xc0\xdd\x22\x13\x5e\x42\xa5\x36\xc6\x84\xf2\x19\x5d\x31\x5f\x69\x24\x57\x1e\x46\x3f\x5c\xfc\x11\xb9\xf9\xd0\x5a\x7e\xa1\x1b\x98\xa1\x69\xa1\xe3\x93\x60\x97\x3c\x50\xad\x45\xc7\x49\x1b\x57\x13\x8e\xc0\x50\xf4\x3c\xbd\x5d\x17\xeb\x3f\xe0\x01\x3e\x3d\x28\xd5\x26\x05\x4e\x07\x63\x31\x52\x24\x6f\x16\x55\x4f\x30\x54\x74\x9e\xea\x68\x7b\x9c\x37\x1b\x40\x9c\xd3\xec\xef\xb1\x11\xa1\xd6\x00\x40\x73\x44\xe6\xd6\xec\x38\xc6\x0f\x6e\x54\x5a\x92\x38\x2e\x46\xc4\xd1\x13\x12\x5d\xbe\x5b\x98\x26\xe1\x27\xf1\x01\x81\xa3\x5a\xcf\xff\x28\xab\x37\x64\xca\x7f\x23\x8f\xf4\x79\xfd\xbc\x45\xb7\xa2\xad\x0f\xf5\x38\xc8\xac\xd0\x01\x8d\x44\x70\xfe\xbc\xc6\xa3\x07\x65\x1c\xb5\x83\x2f\x32\x6b\x19\x24\x1b\xe9\x86\x7e\x4e\xca\x6a\xe3\x6f\x0e\x2d\x83\xfd\x77\xb9\x72\x02\xb3\x64\x71\x6e\x36\xd1\x89\x5a\x36\x85\x3e\x7e\x76\xe8\x8f\x62\xdb\xbf\x77\x26\xc2\x18\x05\x69\xc6\x66\x73\x83\x7a\xd7\x2f\xf9\x36\xcf\x0e\x2f\xdb\x9e\xc6\xaf\xcc\x79\xf8\x82\x9e\x15\x7f\x95\x22\x88\xf4\xe0\x0d\x04\x10\xa7\x22\x53\xbf\x60\x5e\xdd\xce\xb0\x14\x40\xde\xe5\xdd\x32\xb5\xa8\x03\x43\x9f\x03\x8c\x06\xaf\x1c\x90\xb2\x7b\x5f\xe9\x84\x3c\x27\xae\x76\x60\x9c\xbf\x83\x28\x35\xc0\xe3\xc4\xbb\x59\x97\x6c\xce\xde\x44\x87\x86\xd9\x1e\x43\x8e\x07\x75\xc0\x6a\x92\xd0\xf0\xb8\xdc\x0e\xf6\x82\x60\xf7\xdd\x9e\x68\x71\xc4\xd0\xc0\xc0\x94\x63\x85\x26\x15\x21\x85\x16\xf4\xa6\xde\xbf\xdb\x46\x27\x3b\x28\x33\x82\xcd\x9c\xa7\x44\xab\xf9\xfd\x43\x91\x94\xb8\xcf\x1b\xdb\xb3\x17\x5c\xa9\xc5\x7a\x1c\x37\x3c\x41\xfc\xe9\x2b\xd5\xfc\x01\x2b\x19\xa0\x69\x8a\xef\x37\xba\xf8\x06\xae\x09\xad\xd8\xcb\x97\x2a\x9e\xf9\xa7\xa5\xa9\xb1\xfd\x9a\x41\xd8\x54\xc3\x0c\xca\x13\x96\x14\x0e\x20\xc2\xb9\x86\x54\xfe\x6e\x51\x1b\x62\x6a\x43\x91\x5b\x22\xfb\x2d\xad\x74\x7b\xa7\xfe\x74\x60\xd8\xce\xbb\x20\x06\xfe\xa1\x9b\x32\x84\xb0\x9c\x06\xa6\xf5\x2f\x17\x9a\x32\xbe\xb5\x63\x57\xb9\x29\xa6\x59\xf0\xfe\x6a\x26\xb6\x97\x03\x3d\xef\x58\xba\x60\x3f\x43\x0f\x74\xaa\x35\x07\x09\x81\xdb\x74\xcc\xf1\x91\x90\xa1\xfb\x05\x14\x4e\xc0\xa0\x9a\x51\xe5\x47\x65\x06\x97\x30\xb0\x9a\x7a\x23\x31\xff\xb3\xde\x2a\x7e\x02\xc5\xe1\x84\xda\x40\x13\xdf\xe9\x37\xc3\x71\x11\x75\x24\xf7\xb2\x10\xba\x60\xe2\x69\x2d\xcd\xce\xf3\x6a\xb2\x27\xb4\xc4\xf0\x2a\x9f\x48\x89\x72\xb8\x47\xf0\xd6\xb5\x9d\x02\xee\x54\xfe\xde\x88\x21\xdb\x6c\xf7\x31\xcc\x8a\xc8\x95\x35\x0a\xc5\xcd\x4d\x6b\xaa\x3a\xd0\x36\xf0\x6f\x20\xd1\x0a\x14\x0c\x4a\xd3\xd1\x0c\xa9\x85\x53\x2e\x31\x60\x46\x27\x73\x38\x5a\x2e\xb5\xe4\x64\xd5\x28\xe1\xe5\x9c\x29\xf6\x6b\x3d\xe5\x9e\x9e\xa2\x8a\xf3\xf9\x7b\xfc\x55\x89\x03\x57\x52\xa5\xa5\x52\x3d\xec\xd2\xdf\xf0\x1f\xc0\x0f\xf3\x1b\x30\x15\x2f\xf5\xda\xfa\x33\x1c\x6a\xb1\x58\x73\xaf\x41\xaa\x96\x0a\xac\xe7\xd2\xcb\x4f\x95\xc2\x3d\xf4\x4b\x9e\x6c\x6e\x2f\x86\x78\x8a\x87\x2f\xd3\xa5\xcb\xe4\xac\xc9\x58\x10\xda\xa0\x9d\xcc\x1d\xf9\x33\x46\x5e\xf0\x40\xc5\x3d\x9d\x95\x9f\x9d\xad"}, -{{0x4e,0x57,0xf0,0x31,0x1f,0xff,0x0e,0x5d,0x53,0x88,0x49,0xb1,0x21,0x6f,0x69,0x5b,0x1a,0x52,0x77,0x94,0x17,0x08,0x20,0x4d,0xb2,0xf0,0xc1,0x5b,0x3c,0x73,0xc8,0x2a,},{0xe3,0x37,0x1f,0xe2,0x36,0xad,0x2f,0x6f,0x42,0xf9,0xe1,0xfa,0x4e,0x1e,0xda,0x2c,0x3e,0x29,0xc3,0x6c,0x8a,0xd2,0x21,0x8a,0x3c,0x03,0x79,0x82,0xf0,0xb5,0x79,0xec,},{0x4f,0xdc,0x7b,0x6e,0x28,0x27,0xf6,0x4b,0xa3,0xc0,0x33,0xc7,0xfb,0x6d,0x1b,0x35,0xdd,0x68,0x0f,0x53,0x29,0x99,0xa0,0xd7,0x7a,0xeb,0x27,0x6c,0x31,0xbd,0x9e,0x39,0xc6,0x70,0x97,0x8b,0xe4,0x72,0x43,0xc1,0x13,0x22,0x3a,0x57,0xaa,0x10,0x23,0x31,0x50,0x67,0x8b,0x40,0xdb,0x78,0x59,0x1c,0x04,0xd0,0x8d,0xf5,0x7a,0x70,0xa2,0x09,},"\x05\x2a\x1f\x41\xeb\xfd\x4b\xf6\x5e\xfb\x0e\xc8\xe7\x4d\xd7\xb3\x06\x5e\x9c\x48\x2c\x49\xb9\x92\x62\xe6\xdf\xa8\x40\x7d\x9e\x31\xed\x34\xd2\x29\xba\x41\xfc\x49\xa9\x4a\x13\x09\xf9\x90\xa9\x9c\xb9\x90\x2f\xb8\x4f\x4e\xde\x91\xbb\x64\x71\x45\x64\xa9\x13\xd5\x74\xd4\xa3\xc2\x86\xf0\xa1\x92\xa7\x8c\xe2\xd5\x5a\xae\x5c\x9f\xb0\x57\xff\x36\x12\x00\x18\xb2\xa8\xb5\x4d\x98\x08\x55\x37\xea\x64\xae\xa9\x99\xd5\x32\x1c\x78\x80\xb3\x6a\xb4\x30\x18\xea\x2c\x92\xa5\xe6\x83\x50\xd3\xde\x85\x26\xe2\xc8\xbc\x91\x41\xf4\x34\x9a\x18\xa3\x4f\x21\xde\x0a\xbb\xf2\x93\x09\x87\x56\x7f\x0a\xaf\x8e\xb1\x91\x45\x58\x0d\x71\x30\x6c\xe8\xa6\x9e\x79\xf8\xee\xa2\x6c\xfa\x0b\x8b\xeb\x49\xcc\x5a\xa2\xbc\x77\xb7\x97\xd4\xf8\xd5\x03\x26\xff\xb9\x37\x39\x9e\x94\xfd\xec\x85\xe1\x92\xf1\x27\x2a\x80\xe9\xa0\xeb\xba\xf5\xd0\x1f\x1b\x97\x06\x08\x02\xbd\x4a\xf3\x4c\x0f\x7d\x7e\x98\x54\x3f\x9d\x66\xd6\x0e\x0e\x6b\xc0\xbf\x9c\x99\x0b\xe3\x1e\xea\x19\x78\xff\xd1\x67\x33\xa8\xab\xe4\x95\x58\xb3\xad\xd0\xdc\xe6\xde\xfd\x64\xdc\x04\x3f\x15\x19\xb1\xe9\xbe\x66\xe0\x6e\x41\xec\xab\x16\x8c\x83\x39\xa8\x5e\x0b\x91\x38\x18\x64\x4e\xa7\xc5\x33\x44\x68\xfd\x71\x96\xa0\x1e\x1d\x4c\xe8\xdd\x1e\x7e\xe3\x13\xdd\x53\x50\xb8\xdc\xe4\xf5\xd7\xa6\xac\x09\x85\x7c\x4d\x3d\x0f\x10\xa3\xd9\x06\x26\x09\x75\x45\x92\xad\x10\x77\xb2\xe2\x09\x6f\xc9\xe5\xb1\x97\x8c\x98\xb5\x66\x0d\xdf\x51\xb4\x6e\xde\x9f\x9d\xcd\x41\xb2\xef\x44\xe7\x9f\x6d\xaf\xf7\xd3\x62\x68\x70\xe2\x24\x3c\xaf\xb2\xf4\x36\x79\x39\x10\x9e\xd9\xc0\x14\x84\xb7\x9e\xaa\x30\xa1\x89\x1e\xa1\x8f\x98\x4e\x16\x1d\xcd\xd1\xbd\xa3\x71\x34\xbf\x67\x35\xd2\xb2\x14\x9b\x48\x98\xda\xcb\xfd\xa6\x1e\x60\x02\xd7\x2a\x6f\xc5\xd2\x1f\x10\x98\x21\x32\x31\x13\x2d\x56\xdf\x68\xd6\xa9\xbf\xdf\x4e\xdd\xc0\x52\x4d\xb8\xfd\x8f\x24\x88\x52\x04\x9a\x68\x25\xa5\xed\xd2\x36\x0c\x00\x9a\xf2\x4f\x0a\x94\xc5\x07\x9d\xdf\x6f\xe7\x96\x94\x5f\xf9\x84\xaa\xc3\x64\x11\xce\x80\xd9\x87\xc6\xed\x67\xb6\xb0\xdd\xb6\xd4\x17\xf6\xe8\x09\x99\x1e\x72\x9d\x14\x7d\xd0\xd2\x1a\x09\x32\x41\x36\x3c\xf4\xef\x3b\x8e\x3b\xa0\x2d\x48\x66\x33\xb6\xb2\x17\xf5\x49\x3e\x2e\x43\x2b\x8c\x2e\x27\xd0\x0c\x5b\x56\xc9\xb6\x5f\x9a\xed\x49\xce\x93\xd7\x7e\x7d\x0b\xf5\xf9\x2f\x92\xf5\xbb\x4b\x59\x5d\x66\xf8\x87\xa4\x88\x01\x33\xf9\x70\x46\x3a\xb8\xb7\xf3\xd8\xc7\x94\xc0\x40\x6e\x88\xe3\xea\xb9\xae\x65\xf1\xa1\x85\xd6\xe3\x9e\x2d\xd6\xab\xb8\xa9\x3d\x2a\xc4\xb9\x20\x83\x98\xda\xb8\x9d\xbc\x07\xa4\x1a\x50\x26\x40\x26\x41\x2d\xa0\x22\xb5\x8f\x48\x9d\x4d\xba\x31\xfb\x88\x2f\xec\xb1\xff\x8c\xa1\x82\x0d\xda\x18\x65\xaf\x15\x51\xe4\x6c\xd6\x18\xb4\x4c\x4e\x6e\xb3\x03\x7a\x93\x33\xfd\xcc\xef\x4b\x89\x51\x89\xe4\x39\x0e\x93\x14\x5d\x26\x4c\xa5\xf4\x52\x02\xa3\xeb\x28\x53\x59\x3f\xee\xd6\xc6\x6d\xbb\x28\x8f\xf3\xa3\xc0\xfa\x83\x2b\x2a\xa7\xe5\x29\xb5\x56\x88\x97\xb3\x14\x94\x02\xa9\x07\xe7\x41\xe1\x01\x1c\xe0\x73\x1c\x91\x5f\x91\x44\x6a\xa0\xd5\xca\xf0\x59\x5f\x18\x16\x43\x4f\xa4\x57\x6d\xb3\xbc\x31\xe1\x0c\xc2\xaf\x33\xf6\x13\xf0\x3c\xa7\xb9\x49\x1a\x0a\x34\x05\x25\x27\x1a\xb5\x37\xf6\x2a\x11\xa8\x4d\xa0\x1c\x7f\x55\x81\xad\x57\x38\xc3\x72\xb5\x33\x5b\xab\x9b\x2b\x9d\xc2\xfe\x91\xe9\x33\x30\x4d\x94\x01\xba\x8e\x1c\xe8\xdc\x55\xc4\xfb\x46\x6b\x3a\x8e\xd7\xf5\x3a\x12\x2b\x83\x81\xd8\xf2\x90\x47\xd7\x26\x4d\x06\xfb\x51\xec\x3e\x70\x07\x1f\x27\x36\xa4\xe7\xe1\x53\x7a\x52\xfa\x25\x6a\x04\xee\x86\xfa\xd2\x7a\xd2\xd2\x8a\x9b\x36\x29"}, -{{0x39,0xf0,0x55,0x6b,0x1c,0x5d,0xca,0xb3,0x87,0x10,0x41,0x81,0xbb,0x30,0x4d,0xe0,0xcf,0x81,0x59,0x20,0xb9,0x72,0xe8,0x71,0xd5,0xf0,0xfb,0x41,0x6d,0x8e,0x61,0x6a,},{0xd8,0x5f,0xb7,0x6e,0x78,0xc3,0xd5,0xbb,0x7c,0xa6,0xb0,0x5b,0x31,0x01,0x91,0x82,0x1a,0x4a,0x7d,0x2d,0x9b,0xdf,0x02,0x29,0x2c,0xc7,0xae,0xa5,0x64,0x2e,0x48,0x19,},{0x01,0x66,0xaf,0xed,0x5a,0x8f,0x7c,0x3f,0x7a,0xd6,0xf3,0xfd,0xd2,0x93,0x8e,0xff,0x00,0x89,0x8e,0xab,0x81,0x5c,0x54,0x55,0xac,0x90,0xfb,0x51,0xf6,0xe1,0x85,0x4f,0x0c,0x07,0x53,0x19,0x4b,0x76,0x29,0x59,0x4c,0xc1,0x27,0x1b,0x00,0x34,0x31,0x22,0x1c,0x57,0x4b,0x0c,0x0d,0x19,0x08,0x2f,0xee,0xda,0x51,0xb0,0x84,0xae,0x5e,0x03,},"\xa8\xd0\x34\xe1\x70\xfc\x22\xb5\x7a\x44\xaa\x62\x69\xed\x1f\x01\xcb\xa8\x01\xf3\x98\xdf\x1a\xdf\xe7\xdf\x04\x4d\x5f\xa4\x68\xbb\xfa\x8a\xf4\x74\x9a\xb5\x0d\x24\xd6\x2e\x31\x3a\xc0\xe7\x3a\x64\xb4\x28\x2b\x74\x62\x6a\xf2\xb4\xa4\xb5\x4c\x27\x4e\x5a\x6b\xc2\x80\xb6\xdc\x25\xdc\xfe\x07\x81\x4c\x9c\x81\x6d\x2f\x9e\x36\xc0\x5b\x9b\xfe\xdf\xf7\xc6\xb0\x3c\xdd\xeb\xd4\x73\x5e\x09\x93\xd3\xc3\xfd\xc6\x54\x04\x43\xc6\x00\x5e\x90\x0b\x40\x35\xe1\x40\x8a\x85\x01\x6a\xa1\xb8\x92\x02\x99\x0e\x5d\x84\xed\x99\x81\xc2\x9b\x77\x20\x6d\x7c\x11\x30\x52\xa2\x02\x98\x12\xc6\xea\x13\xaa\xe8\xbe\x0a\xca\x7a\x33\x06\xbf\x61\x72\x42\x29\x8e\x68\xbe\xcd\x0d\x5d\x16\xc8\x88\x7f\xd1\x95\x0b\x77\x85\xa4\x6b\xb0\x22\xb3\x9f\x76\x07\xcd\x89\x13\x71\x8b\x30\x17\xfc\x3f\x86\xd6\x93\x3f\x75\xee\xc5\x19\x1a\xd1\xf1\x98\x9a\x8d\x26\x17\x86\xf5\x6b\xe4\xa9\x88\x37\x0d\xb8\x29\x61\xa9\xfc\xc9\x53\x54\x2e\x51\xc2\xe0\x86\xdb\x0e\x02\xb4\xfc\x34\x66\x94\xab\xd9\x05\x9d\x5b\x11\x72\x26\x47\x66\x9e\x7f\x17\xb7\x45\xa6\x0b\x02\xf7\x33\x9f\xcc\x99\xbc\x35\xd5\x9f\xd0\xb9\x8b\x60\xc3\x14\xab\xd4\xbf\x8a\xa4\xb7\xea\xe0\x9d\xd0\x09\x7a\xcb\x91\x89\xf0\x2c\xf8\x5a\x25\x1a\xc9\x2a\xaf\x69\x1b\x15\xcd\x4a\x33\xb5\x8d\x76\x63\xab\xd0\xb0\x44\x43\x33\x04\x4a\xf5\xce\x20\xfd\x71\xcb\xaf\xfc\x0d\x29\x83\x58\x19\xf4\x92\x93\xfc\x26\xe7\xf9\x78\x7f\xc3\x68\xc4\xd3\x5c\xae\x92\x74\x7f\x21\xca\x1f\x3e\xfd\x87\xa0\xd8\x10\x41\x99\x41\x64\x82\xd0\x7b\xfe\xc1\x28\x1c\x66\xf5\x65\x28\x5b\xf6\x72\xd5\xe7\x48\x64\x00\x66\x0c\x01\x75\x55\xe9\xfa\x2b\xf6\xa4\xe7\x02\x7f\x0e\x7e\x5f\x44\x3e\xd6\x58\xb7\x5b\x59\x06\x12\xab\xde\x0d\x80\xd1\xa2\x6c\xb8\xbd\xe7\x6b\x99\x6e\xff\x6a\x74\xe3\xda\xfc\x59\xeb\x1b\x58\x4f\x45\x97\xa2\x39\xcd\x83\x9f\xa1\xf1\xb7\xbd\xa1\xa2\x4d\x15\x0c\x4e\x24\xb9\x1c\xec\x01\xee\x53\xa3\xac\x85\x2a\x91\x2d\xe1\x95\xa3\xc2\x9d\xd7\x07\x9a\xa7\xe8\x8a\xa8\x1e\x9d\x31\xb8\xfc\xcd\x43\x5e\xda\x11\x3c\x3f\x82\x45\x8b\x7f\x79\x33\x57\x2b\x77\x67\x53\xc9\x22\x40\xcc\x03\x61\x58\xa4\xba\x0e\x56\xef\xed\x53\xec\xb5\x3f\xc0\x93\xfe\xad\x14\x34\x34\x85\xae\x5d\x91\x05\xbb\x16\x3f\x26\x25\x14\xe4\x8b\xe7\x41\x59\xc9\xfa\xbc\xb7\x1d\x1a\x42\x80\xd9\xed\x70\xd7\xe4\x2b\x75\xf7\xfd\xad\xd0\x2d\x69\x19\x8f\x5f\x46\x5b\xf6\x04\xcb\x42\x54\x41\x7b\xac\x37\x14\xb3\xa9\x9e\x6f\x1a\xce\xc9\xe3\xb3\xd0\x97\xf9\x72\xfb\xc3\x6f\x2e\xda\x39\x26\xd5\x61\x12\xd4\xe9\x09\x7d\x89\xbd\xc3\x59\x37\xb9\xa3\x15\x8e\x7c\xdd\x5d\xa4\x01\xe1\x80\xd3\xed\xe6\xb1\xff\x02\x86\x41\x92\xeb\x72\x97\x81\x53\x4f\x49\x64\xdd\xf2\xaf\x11\x80\x0d\x8b\x5b\x6d\x01\xb2\x09\xaa\x33\x69\x36\x6c\x19\xa2\x8c\x79\xa8\x7d\x21\x74\xec\x22\xfb\x14\x89\xa6\x75\x5c\x34\x8a\x99\x6d\x0a\xa5\x6e\x0f\x60\xd5\x8e\x26\xbe\xfa\x23\xa8\x6b\xef\x4e\x35\x29\x51\x2e\x30\xa9\xd1\xc5\xe4\x88\x50\x18\xcb\x97\xae\xb7\xc9\x3c\x5c\x41\xca\xa3\x42\x36\x57\x5c\x22\x6f\x3b\x23\x5e\xdd\xba\x36\x4e\x28\x5b\x6e\x35\x27\x07\xbb\xb3\xb3\x39\xbb\xf2\xa6\x3a\x9c\xb9\xbd\x33\x3a\x77\xe7\x9b\xd5\x8a\x48\xe1\x4c\xe5\x88\x6e\xd0\xcd\x07\xc2\xd1\x65\xa8\x1b\x5e\x6a\x31\xa8\xae\x78\x06\xbc\xf2\xe0\xc4\xec\x29\xa9\x67\x72\x5e\x57\x7f\x17\x41\xee\x68\xf3\x45\xf5\xf7\xab\x0f\xad\x31\xc8\xb4\xb1\x8b\x43\x1c\x49\x77\xd5\xc5\x84\x00\x4b\x45\xf7\xcd\x19\x61\xaf\xfe\x87\x38\xe2\x4c\x38\x26\x10\xef\xe9\x98\x35\x3d\x7e\xba\xf9\x19\xb2\x79\xbb\xb6\x91\xc3\x05\x2b\x8b\x2c\x5f\x09\x80\x8e\xf3\xa6"}, -{{0xba,0xb3,0xff,0x7a,0x44,0x48,0xd8,0xa0,0x3d,0x8a,0xcf,0xdb,0x91,0x3f,0x77,0xfe,0x77,0x80,0x43,0x95,0xc3,0xe5,0x4e,0xc2,0x35,0x11,0x79,0x27,0xe3,0x2b,0x50,0xd5,},{0x54,0x97,0x5e,0x35,0xe5,0xb1,0xd0,0x32,0x3f,0x2d,0x6f,0xb5,0xc6,0x15,0x8b,0xf6,0x65,0x4b,0x08,0x4f,0x76,0xbb,0xdc,0xfd,0x72,0x34,0x92,0x29,0xe8,0xe4,0xa6,0xe8,},{0xd6,0xb4,0x13,0x5f,0xc7,0xac,0xb3,0xd7,0xcd,0xf9,0x87,0x89,0x6d,0x91,0xb8,0xa9,0x0d,0xb5,0x84,0xd8,0x93,0x3a,0x6f,0x30,0x29,0xe3,0x26,0x1e,0xc1,0xc3,0x90,0xcb,0xac,0xfa,0xaf,0xef,0xf4,0x43,0xb6,0xda,0x4f,0xdb,0x1d,0x84,0xc6,0x4a,0x54,0x56,0x0f,0xef,0xfa,0x2f,0x1c,0x7a,0x91,0xbd,0xe9,0x73,0x02,0x22,0x92,0x3b,0x67,0x03,},"\xb6\x47\xb6\x7c\xf0\x1c\x2c\xac\xc3\x9d\xe5\x96\x9e\x19\x9b\xe6\xd9\x32\x01\x67\xa4\xce\xbb\xf1\x62\x59\x50\xb1\xe6\xb7\xad\xf5\xca\x24\xd1\x34\x95\x68\x86\x5f\xbb\xfd\x90\xf5\x13\xf0\x5f\x79\xf7\x0a\x63\xa2\x38\x73\xdc\x7a\x19\x5d\x4b\x28\x5a\x08\xf3\x0e\xe0\x61\xd0\xb8\xe6\xb4\xd6\xbf\x9b\x2e\xcf\x2c\x69\xf3\xd5\xa0\x7a\x67\x30\x53\x7c\xca\x4a\x4e\x4c\x7e\xe6\x84\x70\x2b\xff\x88\x3f\xab\x8b\xca\xf8\x93\x11\xc5\x49\x8b\xcc\xb5\xa0\xf7\xc8\xd4\x9b\x54\xf4\x82\xff\xfb\xca\x6e\x7d\xa2\x62\x45\x2b\xa5\x9a\x57\xa6\x87\x9d\x81\xb7\x3c\xd7\xad\xf7\x2a\x3b\xe2\x8a\x37\x3c\xd6\x33\x10\x40\x84\x61\xc2\x1b\x90\x7f\x63\xe0\x86\xb2\x92\xff\x02\x83\x3e\x8a\x2f\x46\xad\xbd\x67\x1d\x02\xb0\x3a\x69\xac\xa2\xe1\x1d\x28\x7c\x52\x2a\x95\x45\x20\x44\x2e\xce\xfa\xa9\x05\xdb\xfc\xc8\x25\x4c\x58\xc3\x95\x4a\x89\xbf\x56\xcb\xe0\x1a\xd5\x63\x19\x71\xeb\x39\xeb\x43\x2a\x85\x4e\x69\x19\x29\xdf\x7e\x48\xb9\x00\xca\x6e\x74\x0a\xcc\xf5\x78\xb3\x17\x95\xb4\x9a\x6c\xa7\x74\xbd\x8b\x99\x31\x06\xa9\xc4\x94\x8c\x18\x71\x49\x48\x31\x59\x90\xa5\xf1\x91\x69\x24\x20\xf2\x89\x32\x8a\xb7\x13\xec\x19\xb7\xea\x89\x4d\x16\xe6\x47\x61\x00\x87\x1c\xf3\x16\x8e\x4f\x93\x5b\x55\x05\xd1\xed\x5b\x0a\xa2\x9b\xe3\x6f\xa3\xa3\x46\xac\x3e\x76\xf1\x43\xc4\x6c\xa6\x91\x23\xb7\x9c\x36\x39\x9a\x0d\x2e\xd3\x02\x77\x24\x94\xad\xf4\x42\xbb\xaf\xbc\x4d\x01\x53\x26\x92\xc7\x85\x9d\xf0\x4d\x2c\xa7\x8b\xa5\x5d\x77\xfd\xf3\xe5\xad\x99\x37\x86\xa2\x4c\xff\x21\x99\xbb\x49\x38\x78\x73\xcc\x41\x4b\x4c\xf1\x13\x7a\xbb\x7e\x94\xae\x3d\xdb\xf9\x7f\x53\x4a\x18\xfc\x5a\xe5\x85\x23\xa3\xcc\x52\x28\x3d\xc7\xb0\x16\xf3\x1c\xd6\x55\x79\x81\xc5\x07\x6c\x77\x4f\x30\x3a\x47\xc4\x27\x87\x0e\x20\x7e\xd8\xbd\x66\x64\x0f\xf0\x92\xdb\x50\x3f\xa1\x24\xbf\xdc\xf0\x20\x05\x1d\xad\xd1\x06\xdd\x24\x58\x40\xb3\x19\x10\xb8\xa9\x06\x0d\x59\x86\xf0\x2b\x60\xaa\x5e\x33\xb4\xd7\x55\x09\x12\xcd\xc5\x77\x6c\x77\x2a\xac\x93\xae\x19\xc7\x3b\x7e\xcf\xca\x38\x9e\x62\x76\x81\xa8\x78\x1e\xb4\x7d\x84\xe9\x34\x60\xba\x89\x1d\x3f\xf6\xea\xdf\x8f\x2a\x90\x3c\x38\x34\x74\xbe\xaa\x42\xb9\x0e\x03\x22\x36\xdc\xd8\x98\xd0\x2a\x40\xef\xb4\x4e\x47\xea\xd5\x2b\x75\xb0\x9c\x7d\xa1\xcd\x6a\x2d\xfd\x4d\x1c\x04\x52\xde\x69\xf6\xac\xac\x1a\x68\xdd\x78\xda\xf9\x72\xae\x26\x08\x21\xe2\xec\x52\x2f\xb5\x74\x9b\xeb\xe0\xad\xb4\x52\xbf\xa4\xfa\xa1\xe9\x79\x11\xc1\x29\x9f\x16\x56\x8d\x68\xee\xf4\x05\xf4\xb1\xcd\xac\xab\xed\x59\xf7\xb0\xfb\xce\xab\x71\x9a\x34\xb2\x99\xf5\x8a\x4a\xe8\x15\x4f\x98\xf4\xd9\xf4\xf1\x40\xb1\xf0\x85\x00\x69\x46\x72\x5e\x7c\x29\xbb\x0b\xc6\xcc\xf2\x53\x44\x97\xc6\x1d\x4c\x16\x12\x62\x4a\x61\xd7\x0d\x26\xc3\xef\xb7\xd7\xc3\x51\x84\x86\x57\xf7\xf8\xee\xbf\x8b\x99\x07\x47\x74\x0e\x6f\x91\x0c\x97\xce\xf1\x50\x37\x57\x65\xc8\xc0\xb3\xb4\x49\xc0\xd0\x9d\x66\xf0\x08\xe6\x7c\xfa\x76\xea\x2b\x68\x08\xb6\xfe\x63\x2e\xaf\xe0\x58\x7f\x37\xe3\x6b\xe9\x8d\xcb\x17\xa3\xf4\xa1\x5b\x65\xa9\xf6\xfc\xf9\x64\x2b\x52\x52\x20\x77\xb1\xfb\x4c\xc3\xc0\x8d\xf4\xb4\x67\xca\x71\x6d\xb1\x6b\x73\x7f\x78\x2c\xdf\x38\x71\x70\xa5\xf1\xf6\xa7\xae\x0a\xb3\xf5\xb7\xc5\x85\xe3\xb0\x65\x5a\x64\x56\xa5\x03\x59\x5c\xe8\xea\xea\x25\x37\x85\x5e\x7f\x0d\x50\x61\xbc\x29\xb4\xe6\x7d\xaa\x82\x46\x3c\x19\x0e\x9f\xdd\xd5\x2f\x83\x22\xdd\xb4\xe0\xf2\x6b\x68\x77\x82\x28\xeb\x57\xe1\xa1\x85\xb7\x02\x5d\xa1\x49\x87\xd4\x4b\xaa\x76\x7b\x22\xee\x7f\x4c\x84\x59\x10\x32\xe8\x8e\xc1\x2e\xb8\xc5\xa4\xb9\xe1\x57\xec"}, -{{0x48,0x6c,0x7b,0x43,0x6c,0x1d,0x43,0xd6,0xb7,0x03,0x51,0x22,0x83,0xc1,0x66,0xdc,0x86,0x3e,0x5a,0x33,0x80,0x2f,0x4e,0xa6,0x5f,0xc7,0x38,0x77,0x89,0x02,0xd0,0x14,},{0xb5,0xdc,0x94,0x7d,0x64,0x33,0x7c,0xae,0x82,0x12,0x2b,0xd6,0x8c,0xc8,0x08,0x40,0x59,0x6d,0xe3,0xbe,0x56,0xcb,0xd0,0xc8,0x33,0xaf,0x3f,0xaa,0x3a,0xdc,0x37,0x76,},{0x31,0xf9,0x5c,0xbb,0x74,0x63,0xb8,0x75,0x28,0x65,0x42,0x27,0xbb,0x13,0x97,0xbf,0x10,0x65,0xb4,0xf5,0x76,0x80,0x80,0x78,0x20,0x7d,0xfa,0xf0,0x6d,0x12,0x4b,0x41,0xf4,0xc3,0x18,0xf4,0xa9,0x31,0x5a,0x66,0x08,0x5b,0x9e,0x56,0x8a,0x71,0xe4,0x14,0xed,0x94,0x14,0x51,0x73,0x10,0xc6,0x99,0x94,0x6d,0xb0,0xc9,0x76,0x28,0x52,0x07,},"\xaf\x03\x60\x53\x67\x2d\xcf\x3a\xa2\x6e\x28\xec\x6a\xa6\x42\xce\x28\x4b\x89\x6c\x69\x88\x7d\xfd\xcf\x08\x24\x51\x5e\xb0\x84\x8d\x9d\x97\x0c\xa2\x72\xdf\x77\xa8\x6b\x3f\xf6\xdd\xaf\x3c\xba\xdd\x3a\xb6\x28\x3b\xc3\x7c\xdf\x7a\x56\x07\xd5\xdf\xc7\xcf\x96\x32\x92\x99\xcc\x53\xed\xbb\xe6\x57\xfd\xfa\x2c\xa2\x44\x67\x05\x0a\x0a\xeb\x8c\xff\xd7\xd3\x3d\x54\x3e\xc2\xc1\x91\xcc\x0b\xce\x89\xac\x37\xd3\x32\x93\xb1\x88\x8c\xcb\x76\xc2\x8a\xdc\x67\x1a\x49\x35\xa8\x46\xd9\x07\xe4\xad\xd0\x11\x0f\xeb\xbe\xe5\xae\xc8\x0f\x9d\x2f\xf7\x4e\x2a\xf4\xfd\xbe\xbb\xcf\x49\x10\x5a\x64\x69\xd7\x38\x00\x06\xb2\xca\x44\x36\x48\x14\x45\x4e\x44\x5e\x36\xdc\x00\x12\xf3\x39\xc9\x68\x54\xf8\x36\x44\x2a\x05\xa5\x0b\xec\x90\x73\x27\xf7\x4b\xa9\xf6\xfd\x79\x0f\xf0\xad\x37\x83\xd2\x97\xbd\xcc\xa7\x64\x60\x78\x37\x03\xeb\x5f\x2b\x1f\x51\xb0\xa7\x40\xce\x7a\x8f\x00\xa3\x87\xe3\x63\x62\x70\xa9\x71\xfa\x8f\x15\xb4\x49\x67\x30\xd8\x8a\xdd\x80\x7a\x7f\x7e\x98\x7c\xd4\x15\x95\xa2\xe7\x43\x5d\xf5\x19\x55\x76\xa3\x5f\x5e\x91\xb2\xfc\xfa\xc9\x4e\xd5\xd7\x76\x63\x78\x3b\x61\xe6\x67\x1d\x34\x83\x8b\x6b\x56\x44\xfb\xc1\xc5\x39\xfe\x15\x9b\x77\x92\xdb\x96\x7e\x83\x52\x61\x8d\xda\xca\x0c\xde\x73\x43\x7b\x59\xe7\x80\x1b\x49\xeb\x46\x09\xb1\x05\x77\xca\x26\x92\xdd\x6f\x9d\x5e\x9d\x4b\x5e\x5e\x62\xc5\x91\x3e\x7b\x87\xe6\xb3\x47\xbe\x61\x53\xb1\x71\x99\xc9\x16\xa1\x3f\x8a\x88\x5b\x37\x8e\xf0\x9e\x13\xca\xe4\xd8\xb0\x79\xd7\xd5\xcb\x90\x94\x19\x9b\x0f\x20\x53\x3c\x90\x08\x3b\xc3\xac\xb2\x66\x76\x97\xee\xd2\x2e\x36\x70\xab\xb4\xa5\x53\xe9\x95\xc9\xdd\x95\x94\xe5\x92\x39\x1a\x00\x04\xb6\x55\x65\x44\xf3\x56\x12\xc4\x97\x13\x59\x57\x7c\x47\x63\x82\xca\x53\xb3\xf2\x62\xa5\xe3\x3e\xd2\x6e\xec\x80\x9f\x4f\xdb\xa4\x89\x8a\x11\x36\x75\xcb\x6a\xf7\x17\xdb\x62\x57\x9f\x39\x80\xb2\x14\x63\xbe\x02\x9c\xb4\x16\x0f\xe5\xd2\x57\xc4\x6c\xd6\x66\x4f\x98\x61\xac\x50\xfe\x05\xc1\x44\x05\x7d\xce\x2f\x8d\xf1\x53\x2a\xa7\xaf\x58\x9f\x41\x27\x06\x01\xce\xf0\x6b\xbe\x4f\x35\xc3\x1c\x78\x2b\xb3\xcf\xff\x7d\x5a\xb6\x4a\x14\xec\x41\x73\x61\xf1\xd3\x2c\xbd\x38\xb6\xbd\x0e\x02\x50\x5d\x14\x16\x30\x2b\x85\x05\xae\x2a\x96\xe8\xd5\x33\x9c\x34\x6c\x2b\x06\x62\xd3\x50\x25\x9c\x50\xc5\xe4\x87\x95\x91\x4e\x6f\x88\xe9\x7c\x81\x1c\x39\x3b\xdf\x9a\xec\x7e\xf8\x20\x47\xca\x28\xee\x97\x1c\x17\x5c\x27\xe3\x6e\x10\x97\x27\x96\x0d\xdf\x1a\x1b\x97\x6a\xb4\x4f\x48\x51\x60\x7b\xd9\x66\x80\x8a\xc4\x6d\x54\x00\x31\x28\x29\x7f\x5f\x44\x87\x10\x8d\x6a\x02\xe7\xa1\x64\x13\xd2\xb7\x5e\xcb\x42\xfd\xdf\xb6\x69\xc8\x01\xd2\x3d\xe5\x0a\x6f\x7b\xf6\x58\xf7\x53\xc6\xb2\xb3\xb4\x7c\x06\x40\x10\x5d\x0a\x80\x1b\x32\xa1\x94\x3c\xdc\x15\xc8\x86\x55\x5e\xb7\x5b\xb7\x92\x7b\x93\xc3\x5c\x5b\xe1\xf9\x8b\x19\x6c\xaa\xc2\xda\xd9\x91\xb1\x04\x4e\xa8\x63\x94\x4d\x54\xd8\x83\xab\xc3\xc6\xde\x66\xed\x86\x8e\xe8\x4b\xcf\x9c\x34\xcc\xdb\x80\xfc\xd9\xcc\x04\x02\x74\x77\x32\xcd\x63\x0b\xbf\xa3\xbb\xe8\xb0\x38\xdc\x1d\xbd\xaf\x43\x6d\x9a\xc0\x0c\x02\xd5\x28\xec\xe2\xe7\x91\xee\x31\x2a\x86\x8f\xeb\x2f\x58\x7c\xa4\x4d\xb5\x73\x13\x84\xfa\x18\x31\x14\x20\x61\xb2\xea\xd2\xb8\x0c\x66\xbd\x2f\xa5\xdc\xca\xbe\x6a\x25\xf2\xa4\x93\xfe\xaa\xcd\x23\x1d\x2f\x40\x96\x46\xb9\x42\xa5\x78\x54\x5e\xa4\xfe\xea\x9a\x73\x47\x3f\x79\xdc\xf1\x3e\x0c\x9f\x1b\x49\xfd\x89\x12\xec\x48\x73\x28\x04\x5b\xd0\xfa\x22\x89\x22\xee\x6e\x97\x3e\x61\xf6\xe9\x33\x65\x29\x65\x78\xdc\xc2\x1c\x36\x14\x79\xee\x2d\x24\x87\x9f\x2e\x9b"}, -{{0xa6,0xe6,0xad,0x2c,0x37,0x9c,0x6f,0xcc,0xad,0xb4,0xa4,0x9b,0x23,0x2a,0x91,0x42,0x61,0x8e,0xa3,0x01,0x03,0xc3,0x3c,0x22,0x6f,0xf6,0x28,0xbc,0xfd,0x81,0xf4,0x26,},{0xf7,0xc4,0x32,0x3f,0x5c,0x41,0x9d,0x9b,0x3f,0x34,0xa8,0xeb,0x42,0xae,0x7f,0x1f,0xaa,0x23,0x33,0x07,0x90,0x30,0xc5,0xd6,0x4f,0x9f,0xfb,0x1e,0x9b,0x16,0x00,0x2d,},{0x07,0xd9,0xfc,0x24,0x4f,0xda,0xb0,0x01,0x59,0xeb,0xec,0xc5,0xa0,0x08,0x83,0x45,0x3f,0x08,0x31,0x01,0x71,0x76,0x9d,0x29,0x70,0x01,0xe8,0x77,0x01,0x0e,0x3e,0xce,0xd9,0xfb,0x60,0xec,0x91,0xcb,0x4d,0x88,0xe7,0xba,0x40,0xc5,0x30,0xb1,0xf9,0x23,0x79,0x78,0xcc,0xd9,0x6d,0x5c,0xba,0x9e,0x4f,0xa2,0x7e,0x2a,0x0a,0xd9,0xd6,0x0c,},"\x2e\x85\x76\x76\xa5\xbb\x1c\x6e\x9e\x94\x50\x7f\x83\xc6\x0a\x67\xf5\x47\xc5\xde\x9e\x94\x56\x6b\x19\x7a\x6a\xf6\xcf\x47\x52\xe9\x3d\xbd\xef\x6b\x9f\x66\xd1\xfe\xbd\x95\x7e\x42\xa7\xf5\xad\x64\xef\x1d\xbc\xc4\xfe\x69\xae\x95\x25\xd1\xa4\xde\x67\x05\x4c\x88\xf2\x9c\x06\x47\xba\xcf\x8b\x82\xf3\x21\xff\x99\xfe\x9e\xed\xc9\x92\xed\x34\xc1\x17\x7f\xc5\x42\x12\x27\xcc\xac\x10\xfe\xb9\xce\xd4\x08\x2f\x56\x58\xda\x63\x71\x47\x23\x97\x97\x37\xe7\xdc\xbf\xe2\xe8\xb5\xd5\x0f\x91\xdf\xca\x83\xe7\xf9\x5f\x35\xd1\xad\x8d\xd5\x11\x44\x50\x2f\x3d\xf6\x72\x43\x26\x11\xf0\xe7\x66\xa9\x0d\xcc\x2a\x57\x39\xc8\x05\xd9\x5f\xe5\xb0\x41\xde\x9d\x7f\xb4\x7b\x44\x04\xaf\xc8\x03\xa3\xbd\x48\x04\xc7\x81\x7e\xbc\x5b\xdf\xef\x8a\xdd\x9e\x25\x0b\x50\x96\x6c\xa8\x93\x9b\x22\xb3\xc6\xff\x93\x6e\xaa\x65\x9a\x24\x0c\x0c\x84\x8b\x81\x0a\xce\xcf\x61\x81\xe0\xe4\xdb\x8e\x4c\xf8\xfc\xce\x7d\xe5\x59\xcb\xe8\xaf\xa9\xdb\x84\x99\x57\x09\x11\xa3\x88\x7e\x85\x0e\x50\x9c\xdb\x70\xde\xbc\x34\x77\xd1\x21\x75\x01\x4f\x79\xf8\x1b\xa1\x13\xd0\xb7\xb3\x35\x11\x8f\x85\xcf\x59\x99\x6f\x80\x67\x58\xeb\x90\x3c\xc4\x50\xf5\x2f\xee\x10\x2e\xfc\x01\x44\x1e\x9a\xe5\xfa\xe7\x4c\x23\x1d\xfd\x85\xeb\x6b\xad\x17\xd6\xb7\x0e\x93\x85\x84\xfa\xcb\x21\x72\xcb\x03\xbd\x5e\xa0\x7b\x7f\x0d\x37\x1f\xfa\x35\x1c\x0e\xe4\xef\xe9\xba\x4a\x3f\xd5\x43\x87\x46\x55\xe7\xd3\x9c\x53\xae\x86\x32\x98\x02\xe5\xc3\x85\xe9\x28\x3a\x29\x73\xca\xb8\xcf\x7a\xc7\xff\x0f\x91\xd1\xd4\x8b\x58\xab\xfd\xad\x65\x8d\x81\x2f\x07\x88\x16\x76\xbd\x22\x6b\xfe\x95\x7d\x7d\xf3\x0c\x41\x30\xa4\x48\x35\x4a\x6b\x94\x40\x5a\x41\x16\x50\xa9\xc8\xfc\x85\x11\x55\xec\x5a\x8a\x3e\x3b\x67\xae\x0c\x4b\x5c\xb8\x9b\xb7\x3f\xc8\x29\x74\xbe\x62\xda\x73\xf0\xe2\x30\x92\x93\x7d\x40\x5b\xa4\xaf\x6c\xab\x94\x65\xea\x43\xa6\x25\x3f\x44\x57\x08\x2a\x06\xac\x12\xb7\x5e\x88\xec\x68\x44\x87\xf9\x07\x63\x73\xfa\xb8\x89\x28\x59\xd8\xe8\xba\x43\x14\x23\xaa\x80\x5a\x22\x0c\xbf\xda\x43\x1b\x32\xb1\xe0\x31\x21\xf7\xfd\x4d\xe1\x85\x91\xf2\x50\x5c\xc0\xf5\xb2\xb1\xa7\x60\x5f\xbc\xc6\x37\x57\xb0\x7e\x29\x9f\xef\x5a\x2b\x73\x65\x23\x0c\x2e\x92\xa2\x59\x62\xc2\xe8\x01\x2a\xd3\xfa\x9e\xe9\x48\x82\x70\x96\x25\xba\x68\xc7\xb2\x13\x66\x4a\xe2\x53\x2b\x60\x9d\x7c\x9a\xa0\xe8\x3d\x49\x3d\xbc\xe7\x63\x2f\x35\x58\x0e\x06\xd3\x11\x1c\xed\x32\x0d\xd0\x19\x04\x41\xf6\x2d\x9e\x35\xf5\x0d\xe5\x9c\x27\x2f\xb0\x0f\x56\x8a\x00\xb0\x74\x6c\x33\xa9\xbd\x24\x90\xc0\x74\xb9\x1c\xdd\xc4\x87\xef\x2e\x45\xa0\xf0\x30\xe0\x8f\xdc\x18\x17\xbc\xa8\xa9\xce\x29\xd2\x92\x79\xe7\x55\xde\xbc\x28\xdf\xad\xc3\xc4\xd1\xb4\x58\x48\x6e\x3c\x8d\x0c\x43\x18\xe7\xe6\xf9\xeb\x5a\x36\x53\xb3\xf7\xc4\x95\x07\x07\x7c\xd5\xeb\x81\xf1\x0b\x88\x10\x7c\xc0\xf9\x31\x69\x32\xab\xe9\xb6\x4e\x88\x86\xd0\x68\x56\xa8\x5b\xe6\x3b\x0c\x2b\x47\x5c\x0a\xfc\xb0\x69\x44\x26\x86\x0f\xb2\x4b\x5c\x17\xab\x6a\xb7\x73\x3d\x5e\x64\x1b\xe7\x4f\xd5\xf6\xa1\xff\x18\xd2\xf9\xa4\x27\x70\xfb\x30\x75\x0f\x56\xf4\x85\x4e\x38\xd5\x8a\xef\x18\xa2\xa6\x1c\xbf\xb4\x9e\xe5\x76\xed\x97\x73\x7b\xc2\x8d\xf3\x26\x8a\x33\x41\x75\x51\x3d\x97\xaf\x00\x9c\xbb\xcf\xdf\xad\x50\x39\xd6\x9b\xb4\x6f\x70\x88\x67\xd9\xb3\xce\x0b\xf2\xf5\x69\xe3\xcf\xbc\xf6\x13\x6f\x88\x70\xd2\x52\x08\xb2\x1a\x3e\xdc\xb7\x33\x93\xdf\xcd\x41\x72\xc1\x40\x2c\x41\xf3\x6e\x3f\x82\xa4\xea\x6d\xcd\x89\x16\x86\xba\x66\xe1\x43\x20\xaa\x0e\x22\xba\x0c\x1e\xf0\x33\xd6\x62\xcd\xb8\x60\xcd\xfa\x3a\x40\xf6\xcc\x53\x2a\x08"}, -{{0x9b,0x6d,0x7e,0x28,0xeb,0x05,0x15,0x97,0x32,0x4d,0xce,0xb7,0xa1,0x89,0x41,0x24,0x67,0x25,0xe8,0x8d,0x53,0xab,0x2c,0x34,0x77,0x11,0x05,0x33,0x0c,0xf1,0xf4,0xae,},{0x88,0x72,0xa5,0x0b,0x5f,0xe3,0x62,0xf8,0xea,0xd1,0xd4,0x0e,0x20,0x45,0xf0,0xd4,0x0b,0x2e,0x7b,0x50,0xb5,0x9d,0x80,0x90,0xbc,0x47,0xad,0x68,0xeb,0xee,0x09,0xed,},{0xc6,0xdc,0x5c,0xa1,0xe8,0x56,0x00,0x15,0xb4,0x93,0xaf,0xe2,0x66,0x6c,0xcf,0x6f,0xef,0xa8,0x03,0xd8,0x52,0x6c,0x83,0x7f,0xe7,0xf1,0x23,0xc7,0x99,0x14,0x27,0xab,0x03,0x0d,0x7c,0x77,0x0e,0x45,0xf6,0xde,0x84,0x81,0x52,0x3b,0x94,0xec,0xe9,0x7f,0x3f,0x16,0x1c,0xf5,0xb8,0xc7,0xae,0xa3,0x9f,0x5a,0xd8,0x26,0xbf,0x8d,0x0a,0x02,},"\xd1\xe1\x98\x7b\xff\x65\xf6\x2a\xd6\x76\x24\xc6\x65\x79\x24\xf5\xd6\x73\xb7\x82\x4e\xbe\x40\x40\x26\xc0\x56\x2d\xed\x31\x43\x44\x0b\xe6\x37\xf9\x8c\x9e\x01\xa6\xaf\xdf\xa9\xa4\x7d\xd4\x9c\x7c\xba\x6e\x3f\xd2\x3e\x45\x52\xf7\x63\x2b\x14\x38\x0b\x27\xcd\x3e\x96\x06\xcc\xe3\x50\xf1\x52\xab\x12\x6b\xea\xd0\xa5\xd3\xbc\xe4\xd4\x20\x92\xd9\x34\xc8\xca\x33\x7e\x98\x7e\x11\xd8\x6c\xfb\xfb\xd2\xac\xc3\x22\x3b\xd1\x67\x44\xa9\x27\x72\x8f\x48\x53\x72\x17\x5c\xc6\x94\xdf\x30\xa7\x3f\x9d\x33\x76\x5f\xf0\x14\xef\x00\x8d\x58\x63\x21\x03\x38\xcc\x34\x82\xcc\x27\xea\x31\x7e\xec\x92\x1b\x0c\x56\x8c\x38\xab\x27\xc4\xa5\x64\xe8\x02\xb1\xb9\x46\x68\xc6\x51\xe2\x0a\x0b\x55\xf3\xa7\x9d\x21\x5f\xc3\xa0\xd0\x49\x04\x01\x09\x32\xc4\xcc\x68\xc2\xa9\xe7\xd0\x0e\x5d\x38\xd8\x2d\xf5\x52\x06\xba\xb9\x5c\xf6\x97\xbe\xbc\x72\x06\xee\xde\xf6\xfd\x18\xd9\xa2\x0c\x2c\xbb\x28\x5b\x00\xef\xa7\x69\xa0\x8d\xab\x2b\x3a\xba\xdf\x00\xd1\x98\xb4\xf1\x92\xdd\x44\xbc\xb9\x14\x31\x82\x3a\xe6\xfd\xf9\x84\x58\xec\xa3\x9c\xd2\x92\x63\xf0\x99\x93\x03\xe7\x0d\xc6\x94\xfe\x01\xc5\x3a\x11\xc1\xd1\xc3\x4c\x1e\xe5\x06\x8a\x20\x1d\xbe\x7e\x10\x08\xd7\x64\x35\x89\x68\xb4\x02\xaa\x39\x85\x49\x50\x7f\x7b\xd1\x85\x08\x00\xe4\x11\xb1\xc4\xe2\x8d\xdc\x04\xa8\x59\xe1\x79\xbe\x8a\xd7\xe6\x67\x0e\x50\x9d\xb0\x27\xad\x7e\x51\x7e\x44\x25\x95\x4f\x5a\x80\x74\x14\xa6\xda\x26\x7a\x76\x4e\x71\x2a\x99\x84\x65\x06\x49\x82\xd8\x51\xa2\x65\xea\x3c\x4d\xfb\x74\xf9\x92\xa7\xcc\xcd\x9a\x82\x68\x7f\xa6\x1c\x32\x2c\x4f\x58\x9e\x86\xb8\x82\x52\x13\xbf\xa9\x51\xda\xe6\xaf\x35\x4a\xce\x18\xf0\x73\x99\x5a\xdc\x95\x83\x9d\xac\x01\x65\x51\x1d\x61\x75\x37\x91\xa5\x3e\x48\xe3\xa8\x27\x3d\x44\x82\x3d\x25\x96\xf2\xa2\xdb\x2e\x5f\x1a\xe5\x97\x22\x1b\xa7\xf3\xeb\xaf\x4a\x7b\x28\x88\x39\x50\x02\xbd\xaf\xf5\x1f\xa5\x4b\xfb\x97\x9d\xe1\x03\x14\x04\xca\x77\x89\xfe\x09\x5d\x4d\x17\xf0\x7a\x35\x55\x6b\x10\xfe\x8e\x14\x17\xc8\xa6\xa6\x31\xc2\xed\x36\xcb\x7a\x0e\x61\x81\x77\x62\x89\xc3\x44\x81\x4d\x42\x13\x1a\x73\xb1\x2f\xaa\x35\xd7\x78\x14\xc6\x81\xa6\x01\x37\x4b\xa7\x1c\xb9\xad\x53\x15\xfa\xd4\x2d\x3a\xcf\xc7\xc1\xd6\x28\x81\x02\x56\xda\xf7\xd8\xc3\xc9\xa2\xe5\xbd\xcf\xb7\x70\x08\x2f\xa6\x38\x16\x89\x58\x52\x3a\x1c\x3b\x03\x5d\xbc\x6d\x5a\xdf\x26\xdf\x89\xa7\xcc\xab\xed\x3e\x7d\xd3\x77\xc1\x6d\xa8\x41\xf1\x3c\x68\x94\xd4\x3c\xeb\xb4\xe3\x90\x22\xf1\xcc\xec\x22\x74\x44\x5c\x78\xb3\xad\xc7\xbb\xf7\x0d\x89\x0b\x80\x23\x6c\xc4\x46\x8f\x95\x69\xc5\x9a\x7e\x33\xb5\x70\xe6\x70\x38\x0d\x24\x4e\x4e\x31\x0e\x11\xc3\x92\xf1\xe3\x34\x05\x4b\x92\xc8\x38\x6c\x16\x1c\xe0\x41\x09\xb0\x37\xbd\x62\x8d\x91\x9d\xcb\x62\xda\x14\x35\xbf\x94\xe8\x8b\x0a\x88\x46\xd4\x86\xd1\x67\x78\xf7\xa3\xb8\x80\xe6\x60\xf4\x41\xfd\xf8\x6e\x56\xb8\xaa\x06\x61\xf5\x5a\xae\xce\x27\xf9\xdd\xaa\x0e\x2a\x22\xc2\x15\xb0\x40\x53\x97\x26\xb9\x85\x39\x15\xa1\x59\x2d\xff\xea\xe3\x2d\x7b\x5b\x67\xeb\x62\x05\xbb\x0b\xd7\x27\x9f\x78\x8d\x5f\x83\x3c\x40\x66\x78\x0c\xa0\xa4\x2d\x3e\x4e\x1a\xa2\x2b\xd0\x6b\xb5\xee\xd8\x9b\x94\x13\x77\x1e\xca\xb6\x44\xca\x72\xd1\x29\x1d\x00\xf7\x40\x90\x1a\x73\x11\xdc\x03\x67\x15\xd2\x3e\xbd\x9a\x59\x89\x16\x28\xf0\xd8\x7e\xd4\x89\x50\x2f\x06\xd7\x5b\xbd\x11\xcd\x16\x02\xa3\x5e\xe7\xe1\x33\x35\xd6\xa1\x44\xb0\x88\x30\xe6\x69\xc0\x2e\x65\x2f\x3f\x10\x0d\x39\x3e\xf9\xb4\xac\x05\x32\x14\x39\xbc\xe6\xce\x36\xff\xc5\xab\xca\x89\x0b\x87\x96\xcc\xb5\xe1\x63\x03\x55\x9c\x5d\x91\x17\xf0\xf3\x1d"}, -{{0x70,0x09,0xed,0xd0,0x79,0x50,0x96,0xed,0xc4,0xfe,0xd5,0x5a,0x17,0xcc,0xf4,0x84,0x13,0x1e,0x60,0x8c,0x6d,0x5d,0x66,0x96,0xbf,0x33,0x76,0xe2,0x69,0x24,0x95,0x9b,},{0x77,0x57,0x4b,0xf0,0x69,0x52,0x71,0x45,0xe7,0x2d,0x3e,0x85,0xce,0x7d,0x4f,0xcd,0x67,0x1a,0x33,0xe0,0xa7,0x1e,0x6b,0xf0,0xda,0x7e,0xa4,0x71,0xdd,0x6e,0x86,0xa4,},{0xb7,0x01,0xb8,0xf9,0xa4,0x34,0xe0,0x6d,0x71,0x9a,0xd2,0x5d,0xcc,0x54,0x06,0x0c,0x79,0x86,0x64,0x7f,0x44,0xf3,0x88,0x4b,0xcb,0x6e,0x5e,0xe1,0xd7,0xa4,0x46,0xcc,0x26,0x5c,0xec,0x02,0x9b,0x53,0x7d,0xa7,0xf2,0x52,0x33,0x26,0x55,0x8a,0xc9,0xba,0x34,0xf4,0xcc,0x2a,0x97,0xcc,0xa3,0x45,0x2e,0x70,0x56,0x2e,0x7a,0x8f,0x55,0x04,},"\xb1\x2c\x12\x47\x05\x39\x54\x7c\x2d\xe6\xbc\x4e\xea\xc7\xb6\x3e\x50\x8e\xd7\x10\xf3\x56\x37\xd9\xfd\xd2\xdc\xca\x32\x2a\x7a\x50\x71\xda\xb2\xb2\x84\x5e\x30\x79\x28\x06\x03\x5c\x9f\xcd\xaf\xe2\x78\x3e\x3b\x67\x7d\x6b\xe5\xaa\xc7\x0b\x33\x91\x0a\x2b\x95\xe8\xb5\xd5\x9b\xda\x61\x59\x35\xa4\x17\xb7\xae\x19\xa7\x85\x37\x74\xe8\x9a\x12\xaa\x54\x7b\x41\x92\x97\x9a\x01\xef\x6e\xf3\x2a\x40\xde\x79\xd6\x80\x05\x7a\x83\xa0\x74\x61\x7c\xa6\x50\x1f\x59\xe7\x35\x64\x92\x7c\x38\xb5\x8c\x19\x58\x5a\x2c\x03\x65\x9c\x02\x6e\x4d\xe3\x80\x6d\x6c\x1c\xa8\x95\x8d\xee\x47\xbc\xb8\x89\xe7\x6d\x2c\x3a\x9a\xb5\xb8\xb6\xaf\xb2\xe8\x42\x29\x80\x56\x56\x7b\xf9\xb5\x89\x57\x41\x54\x83\x33\x62\x33\xef\x49\x20\xfa\x57\xf4\x96\xe1\xf0\x34\x8c\xca\x20\x36\x64\x96\xfa\xb3\xa7\x5b\xf4\x21\x4e\xce\x47\xa4\x5f\xea\xa1\x39\x2d\xb3\xf2\x54\xd9\x6a\x7f\x37\x40\x2c\x98\x11\x14\x0d\x73\x58\xb4\xef\x8f\x20\xa2\x98\xee\xef\x90\x4e\x37\xd6\x8f\x37\x8d\x33\xcb\x96\xd0\x0c\x03\x10\x9f\xc8\x3f\xd0\x6a\x87\x6c\x92\x48\x2f\x61\xab\x79\x14\xeb\x7c\x2e\x5e\x84\x06\x6e\x0e\x91\xe2\x1e\x42\xe9\xbe\x23\xdf\x12\xb5\xc7\x47\x97\x3c\xb8\x64\x42\xc3\x22\x91\xd3\xd1\xae\x71\x9b\x36\xa6\x2f\xaf\x3a\xba\xa2\x05\x3a\x31\x3f\x62\x5d\x85\xc5\x1a\x51\x98\x57\x19\x15\xef\x8a\x2b\x19\x9b\xa3\x7d\x25\x88\x45\x75\xba\x1b\x72\x84\x4c\xab\x43\x28\xb5\x7f\xab\x1e\xc9\x74\xee\x8e\xa1\xdf\x7c\xa9\xc7\x8a\x4d\x3a\x03\xbc\xb0\xab\x41\x69\xbf\x06\xa3\xa4\x38\xd9\x56\x6c\x6c\x50\x1d\x8d\x9c\xcc\xcb\x1a\xc2\x6b\x4d\xa4\xae\x1a\x9d\x8e\x8b\x9d\xf6\x62\x82\x1a\xd9\x75\xc9\xb0\x15\xfe\x26\xf6\x89\x8d\x22\xab\x91\x2f\x0e\x40\x5a\x5b\x27\xcf\xd3\x9d\x65\x7d\xcd\x92\xcd\xeb\xe6\x79\x19\x02\x71\x34\x84\x40\x6d\xdd\xce\x71\x18\x87\x31\xe4\x43\x19\x38\x1a\xf2\x7d\xaf\x76\x79\x22\x73\xb8\xc3\x52\x51\xd1\x1b\x83\x6a\xfe\x8b\x3c\xe9\xb4\x02\x73\xf6\x91\x5e\xbe\x6b\xc9\x5a\x75\xbb\x94\x1a\x42\x92\x09\x86\x7f\xba\x87\x64\xbf\x6c\x40\xdb\x6e\xec\xb4\xf2\x17\x47\x83\x7c\xf6\xae\x7f\xbf\xe3\x6d\x50\x23\xdf\x7f\xce\x2c\x0c\x3c\x57\xaf\x28\x98\x88\x53\x13\xc5\xc4\xbd\xa3\x5c\x7d\xa6\xcb\x29\x93\x2f\xb1\x99\x1f\x62\xbb\xb0\x80\xb3\x2e\x20\x50\x61\x93\x11\xae\x69\xab\xb3\x02\x2d\x91\x3f\xa9\xea\xbd\x5d\x5c\xb4\xdc\x54\xd7\x5d\xca\x63\x8c\xda\x9a\xf3\x31\xc0\xcf\x4d\x20\x07\xb6\xca\x39\xf6\x55\xa6\x1c\x01\x03\x9f\x12\xa4\xb9\x78\x2b\xc3\x9a\xec\x4d\x22\xef\x00\x93\x38\x8d\xd7\xd5\xb5\x6d\xfb\x8a\x7f\x9d\x86\x69\x00\x4e\x28\x78\xdd\x8a\x6d\x76\x85\x7c\x08\x45\x24\x50\x68\xfe\xe1\xc5\x31\x96\x31\xe7\x8d\x37\x85\x16\x5c\x70\xaf\xd6\x52\x99\x30\x13\x78\x55\x1e\xbf\x61\x35\x84\xc6\xa7\x62\x0a\x0e\x3b\x67\x79\xf3\x8c\x09\x40\x06\x24\x97\x00\x8e\xb2\x33\x87\x08\x68\xc2\x1c\xcc\xac\x23\x95\x01\xb6\x3b\x74\x9a\x85\x60\x2c\x28\xa0\x95\xca\xfc\x74\x9b\x05\x11\xa6\xc8\x78\xed\xb3\xb7\x80\xea\x17\x4d\x07\xb1\x21\xe3\x15\xa8\x26\xdd\xa6\xec\x8d\xc5\x43\x63\xe2\xcd\x2e\x63\x05\xa1\x94\x82\x5c\x0e\xa9\x0e\xfd\x7a\x9f\xd8\x9c\xd9\x7b\x99\xc4\x30\x0b\xd3\xbf\x93\x53\xd8\x2f\xbc\xce\xea\x71\xb4\xee\x3f\x1a\xae\x95\x39\xb4\xcc\xe9\x0c\xa4\x77\x59\x7c\x17\x4e\xf2\x0f\x4b\x9f\x4e\x62\xd0\x9a\x57\x0d\x31\x35\xaa\xbe\xe9\x55\x1f\xa6\x09\x83\x95\x8c\x0b\x7b\x8c\x37\x44\x55\x3e\xe1\x4e\x7f\x3c\xd1\x03\xa1\x92\x51\xc9\x9b\xf6\x38\x4a\xbb\x60\xa7\x6a\xfc\x66\x58\xb8\x0d\xfc\x51\x10\xad\xc4\xc7\x32\xfe\x0e\xe3\x29\x33\xfb\x28\x48\x28\xe0\x08\x88\x7a\xef\x80\xf6\xf8\x13\x34\x04\x46\xc0\x21\x7c\x12\xee"}, -{{0x12,0xfe,0x8e,0x5c,0xe2,0x0c,0xaf,0xaa,0x32,0x79,0xda,0x7b,0x34,0xaa,0x87,0x75,0x2e,0xad,0x67,0x9f,0x15,0x61,0x28,0xaa,0xef,0xb4,0xaf,0xa5,0xdb,0x4f,0x2a,0x6f,},{0xe7,0x7f,0x44,0x20,0x6b,0xb0,0xc4,0xc5,0x9a,0x28,0x70,0xcf,0xc2,0xec,0xac,0x63,0x36,0x2d,0xee,0xcb,0xe8,0x11,0x5d,0xe5,0xcb,0x1a,0xfc,0x2d,0x9a,0x3d,0x47,0xf1,},{0x04,0xea,0xf9,0x00,0x96,0x6e,0x09,0x92,0xd3,0x6e,0x3c,0x22,0x0a,0x4b,0xd4,0xd8,0x2b,0xcc,0x6e,0xb9,0x98,0xed,0x05,0x1d,0xbc,0xb9,0x16,0x0b,0xcd,0x35,0x74,0x09,0x73,0x6b,0xcf,0xf7,0xe6,0x63,0x0e,0x96,0xf5,0x53,0x8a,0xec,0xa6,0xab,0x8b,0x0d,0x0b,0xd8,0x2c,0x0c,0xd7,0xc4,0x54,0x99,0x17,0xfe,0xbb,0x9c,0xba,0xda,0x08,0x0c,},"\x6b\x80\xcc\x6f\xbb\xd3\x32\xf8\xc6\x19\x7c\xdf\x2e\x6d\xc1\x9a\x21\x30\xfa\xa2\xec\x93\x8e\xf5\x58\xb8\x84\xba\x4f\xa5\xe1\x13\xe5\xb3\xe4\xb1\xaa\xf5\x1b\x69\x5f\x13\xef\xfe\x13\xf7\x7d\x39\xca\xb3\xc0\x7d\x04\xd6\x6d\x43\x0d\x99\x74\xb1\xda\x3d\x39\xdf\x12\x78\xc0\x0d\x6b\xcb\xfd\x4b\xae\x75\xb8\xc0\x76\x40\x4d\xbb\xb8\x34\x48\xfb\x49\x3d\xf6\x70\x00\xf9\x7d\x24\x7e\x8f\x23\xdc\x08\x1f\xce\x99\x2b\x65\xa2\x1b\x35\xd7\xbd\x7f\xa7\xdc\xcc\x54\xa5\x60\xaf\xd1\x4b\x1e\xc4\x36\xc1\x09\x46\xf6\xaa\x59\xea\xe1\xbe\x3e\xcf\x31\x1d\xef\x51\xe4\x6b\x6b\x4d\x1d\x08\x0d\x17\x84\xb2\x33\x4b\x80\xcf\xba\x72\xcd\x93\x1f\x55\xec\xd2\x98\xb0\x5d\xc8\x36\xab\x12\xd0\xad\x8b\x5d\x6e\x9b\x1e\x3c\xea\x3d\x84\x33\x68\xee\xf1\x9f\x5c\x14\xc6\xbb\xad\x94\x14\xcc\x7a\x4d\xb6\xa7\x26\xe4\xfc\xae\xd4\x44\x40\xa0\x19\xfe\x12\xa6\x05\x73\x40\x3c\x0e\x66\x2d\xc9\x02\xd1\xc8\x73\xff\x30\xc9\x31\xba\x7e\x43\xa3\xb3\xbf\x71\xd5\xb0\x94\xea\x50\x49\x71\x64\x7c\xa9\x43\x56\xf0\xa5\x3e\x44\x4b\x4c\x00\x8e\xe5\x97\x72\x04\x22\x1b\x40\x0d\xee\xc3\x7f\xc2\x73\x45\x25\x45\xf8\xf2\x18\xbe\x98\x87\x25\xbc\x38\xc8\x5d\xf2\x12\xea\x73\xdc\x0b\xc7\xcb\xba\xc9\x07\x98\x2f\xef\xad\x68\x0f\xbd\x97\x5c\x20\x93\xa7\xfe\x8e\x6b\x37\xc1\xcc\xed\x87\xf8\x1d\xaa\x57\x29\x1a\x5a\x18\x47\x6d\x11\xa1\x8e\xc4\xb5\xcb\xce\x5d\x55\xac\x9b\x62\x4b\x04\x84\x30\xf2\x54\xf6\x71\x07\x85\x06\xe6\x98\x9d\xf7\xc0\x92\x56\x52\x50\x39\x08\x5a\xb7\xc1\x30\xc2\x40\x00\x4a\xbb\xb3\xaf\x6b\x48\x1c\xc1\xa0\x61\x7e\x57\xe3\x88\xee\x4b\x1f\x05\x2f\x34\xa0\x03\xfe\x6b\xb2\x02\xcb\x87\xd2\x74\x1b\xd8\xe3\x45\x4c\xa7\x3d\x2f\x61\x20\x11\xec\xc7\x4d\x88\x34\x35\x10\xa6\x3c\x93\x13\xdd\xc3\x6c\x25\xd3\xfb\x03\xe1\x88\xf5\x60\xbd\x02\x9c\x80\x15\x85\xce\x55\x29\x88\xdc\x55\xb7\xd8\x52\x2a\x33\x96\xc0\x1d\x5e\x71\x5a\xe2\x6c\x62\x2c\x64\xfe\xd5\xb9\x8e\x9c\x55\x9e\x4a\xa7\x8d\x1e\xd3\xb7\xb8\x90\xd4\x77\xec\x8c\x50\xa0\xff\x10\x7a\x3f\x83\xb0\x7b\xd3\x5e\x9c\xe9\xa0\x8b\xcf\xc0\xf1\x68\xee\xc7\xaa\x31\x1f\x71\xc6\x6a\x71\xce\xb9\xd5\xa2\x19\x9a\x14\xbe\x36\x86\x5c\xa8\xd0\x7e\x18\x6b\x13\x92\xb9\x29\x0c\x57\x80\x04\xd5\x84\xf1\x91\xc8\x2a\x53\xd8\x50\x89\x0b\xcc\x0d\x12\xdf\xf8\x40\xe0\x43\xdd\xdc\x2e\x67\x0c\x83\x60\x20\x92\x4f\x58\xc0\x44\xb2\x18\x76\x3c\xa6\x19\x82\xbc\x33\x2d\x24\x7b\x2a\x00\x8a\xb5\x70\xb6\x56\x5a\x06\x89\x2a\x26\xcf\xb0\x85\x3d\x79\xda\x28\xef\x8b\x91\x0a\x93\x29\x54\x4b\x79\x2a\xe4\x45\x6b\xa7\x76\x50\x66\xb9\xd1\xb4\xa3\x00\x21\x04\x48\x66\x0a\xe4\x8b\x50\x44\x41\x01\x7c\xdd\xd1\xf6\xf0\x09\x38\xb1\x07\x2c\x8a\xb8\x24\xad\xfe\x8a\xe3\x49\x23\xc8\x2e\xec\x75\x4b\xee\x1a\x65\x50\xab\x1d\x3d\xa0\x86\xe3\xae\xbb\xf2\x11\x69\xc4\x44\x69\xe0\x3b\xba\xe0\xd7\x2c\xe8\x63\x45\x77\x84\xcf\xe1\xdf\xc2\x76\xf1\xaf\xad\x9e\xe5\x3e\xba\xb5\xa3\xc6\x57\x2e\xb1\xca\xe0\x99\xa4\xa5\xfe\x19\x31\x92\x90\xe6\xa1\xb8\xb0\xe7\x54\x1e\xd7\x35\xb3\xf2\x1b\x1e\x2c\x75\x09\xf8\x7f\xd1\xfe\xd0\x00\x07\x47\x9b\x3c\x1b\xb7\x84\x32\x46\x63\x02\xd2\x46\xd8\xd0\x31\x99\x63\x07\x26\x0a\x0c\x41\xa0\xe3\xec\xd1\xe7\xfd\x83\x4d\xac\x11\xa1\x3e\xb0\x36\xb3\x9c\x36\x99\x66\xfd\xef\x39\x4c\x18\x3e\x54\xe7\xb0\xcb\x3d\x0c\xeb\x19\x8b\xd0\xe6\x6c\x00\xd3\x8d\xb7\x03\xaa\xce\x30\xcb\xbd\xab\x36\x9d\xfd\x1d\x9e\x51\x4d\x09\x68\xf1\x00\xc9\xf0\x7c\x31\x50\x89\xad\xb3\xad\x02\xe5\x9c\x04\xb9\xbe\x46\xe9\x9f\xbf\x5a\x62\xc6\xbb\xec\xdf\xf5\xb3\x81\xe5\x51\x27\x82\x4d\xdb\x18"}, -{{0xee,0x9b,0x6c,0x2e,0x0c,0x9b,0x01,0x47,0x2c,0xe3,0x2d,0x54,0xd1,0x76,0x2a,0xb0,0x30,0x33,0x17,0xd7,0x6d,0x3a,0xa7,0x8f,0x5e,0x08,0xa9,0x02,0x4c,0xa1,0xe0,0x83,},{0x01,0x6d,0xf0,0xf7,0x17,0xbc,0xb7,0xad,0xf6,0x26,0x95,0x8d,0x83,0xbf,0x8a,0xa3,0x25,0xc7,0x05,0x18,0xc6,0x8b,0xc7,0xef,0xd8,0x42,0x53,0xb7,0x5d,0xb0,0x87,0x88,},{0x4b,0x00,0x1d,0x96,0x42,0x83,0x5d,0x72,0x13,0x8d,0x68,0x01,0x98,0xe6,0xaf,0x70,0xb5,0xde,0x7a,0xf0,0x15,0x13,0x1e,0xa7,0x26,0xf4,0xe5,0x1b,0x5e,0x8b,0x6d,0x48,0xc2,0xa6,0xca,0x8e,0x87,0x09,0xcc,0x82,0x22,0xa5,0x04,0x7c,0x09,0xa6,0x6e,0x51,0x8a,0xc5,0xe8,0xb6,0xe5,0x35,0x48,0x94,0x82,0x61,0xf0,0x70,0x1f,0x68,0x73,0x08,},"\x77\x2c\xc2\x5c\x3b\x69\xbb\x3f\xf5\x65\x56\x64\xef\xa4\x78\xac\x41\x4a\xdf\xae\xa7\x0a\xc4\xa2\xa8\x87\xed\x39\x68\xc5\x4d\x34\xdb\xf1\xbe\x32\xcc\x9a\x9b\x54\x20\xa4\xad\x3c\x9a\x87\x7b\xc8\xcc\xec\x94\xad\x47\x3a\xa7\xa3\xc7\xde\x08\xa0\xfd\xb5\xed\x1e\x89\x87\x2b\xe7\x81\x70\xbe\x22\x1d\x27\x97\x76\xbb\xc6\xed\x9c\x5a\x67\x16\x89\x80\xd5\xea\xf8\x95\xe1\x34\x0f\x5d\xfa\xa3\xdf\x62\x2d\x65\x44\xb3\x99\xd7\x49\x45\xfd\x13\xbb\x11\x73\x62\x1e\x05\x61\x51\x46\x40\x13\x7a\xa7\xbc\x9c\xb7\xde\xbe\xff\x2c\x62\x69\x77\xd4\x47\x26\x3b\x7e\x57\xd4\x3d\x69\xef\xb2\x30\xcd\x25\x86\x5e\x4d\x92\x48\x28\xf5\xe3\x6f\x96\x4e\x40\x3e\x34\x93\xf3\x0d\x6d\xfe\xa6\xca\x3b\x78\x10\x75\xb5\xe3\xb2\x5c\x05\xac\x50\xe5\x55\xf1\x5b\xa1\x2b\x0e\x05\x9b\xff\x99\x64\x84\x12\x9d\xb6\xea\xfd\x88\x99\x3d\x6f\x0b\x7e\xcd\x15\xdc\xe2\xfc\x99\xf8\xb8\xe4\x35\x16\x35\x2d\xdb\x46\x1a\x04\xb9\xff\x34\x86\x45\x2e\x6a\xa6\xa5\x4b\x2d\x10\x62\xa7\x71\x42\x50\xcd\x2a\x88\xff\x6c\x4c\x17\xb6\xcc\x66\x52\xd8\xc5\xac\x27\xd4\x44\x3a\xeb\xf3\xd5\xfb\xaa\xee\x45\x21\xec\x76\xf0\x41\x3d\xb6\x44\x21\xec\x8d\x69\x49\x62\x67\x25\xfe\x56\x16\x0a\xb3\x07\xc0\xe7\x39\x06\xc4\x51\x55\xef\xab\xb4\x72\x22\x02\x1f\x22\x0d\x32\xbd\x3d\xb0\x71\x2a\xbd\xe2\x59\x9e\xa4\xff\x79\x97\x17\x81\x1d\xcd\xf8\x18\x2d\xf6\x71\x6d\x2a\x03\x8a\xee\x15\xd7\x78\xda\x55\xac\x20\xf0\x1f\x25\x30\x9c\xea\xd5\xb5\xb7\xb2\x23\x22\xe1\x82\x8e\xa7\xc9\x1a\xe6\x66\xf2\xdc\xd6\x84\x07\x31\x48\xe3\x1b\xb2\x24\x7d\x5f\x93\x50\x6e\xa8\x08\x52\x27\xad\xc9\xae\x19\x82\xe9\x50\xf0\x06\xa9\xda\x15\x8b\x9c\xec\xff\x89\x29\x76\x1c\x84\xf9\xd9\x76\xfd\xcd\x31\x7f\xfe\xd3\x6c\xbf\x6a\xcd\xa3\xe5\x0c\x9b\x73\xbd\x2c\x80\x85\x40\x9d\x11\x9b\x64\xce\xd7\x34\x9a\x26\x74\x26\x2a\x83\x2b\xec\xb0\x3c\x2e\xdc\xca\xc0\xec\x54\x12\x4e\x82\xf8\x10\x18\x17\x92\xda\x49\xea\x10\xbd\x94\x1f\x98\x95\xa0\x69\x59\xfd\xe0\xd3\xb0\xae\x84\xc3\x9d\xf0\x53\x90\xab\x33\xc3\x6c\x79\xca\x22\xe6\x59\x4d\x7f\xc6\xe3\xf8\x69\x22\xd7\x8e\xb7\xf5\xc2\x54\x95\xd8\x22\xa3\xb4\x10\x51\xb2\x4e\x57\xa7\x6f\xcf\xc1\x65\xcd\xe6\xd0\x96\xcc\x7b\x7e\x9d\x05\x5f\xe8\x64\xd5\x29\x42\xd6\x29\xa8\xac\x26\x1b\xe1\xdc\xd3\xa2\x1f\x89\x5f\x49\xb6\x7e\xe4\x7e\xab\x7c\xf1\x64\x4d\x57\x1d\x5f\xf3\x8c\x17\x9f\x5c\x6a\x54\xa3\x61\x2f\xb3\x47\x53\x41\x2a\x1b\x95\xbf\x62\xff\x31\x79\x80\x4f\xfb\xb9\x90\x51\xf2\xb0\x80\x56\x3a\x4a\xe0\xf2\x7c\xf9\x96\xea\x8b\xe3\xba\xe0\xa4\x33\x9d\xcc\xdf\xf6\xb6\x67\x15\x59\x26\x6e\xaf\xf4\xef\xf6\x82\xb8\xde\xe8\x9c\x9d\x2d\x45\xac\xdb\xec\x4a\xa6\xce\xcd\xbd\xb1\xd2\x84\x60\x9e\x65\xef\xb7\x7b\xb8\xf1\xa5\x1f\xc4\xd4\x56\x8a\x70\x5f\xb9\xc9\x7b\x23\x03\xc1\x46\x7d\xff\x8c\x8c\x5e\xe2\x75\x59\xb9\x3a\xd1\xc5\xb9\xc5\xc6\xc7\xc5\x29\xfa\x8c\x55\xc7\x5e\xbb\x59\xb2\xa8\x18\xaa\x9b\xda\x1e\x9e\x79\xbc\x66\x02\x97\x72\xf8\xae\xa1\x1b\xad\xd3\x22\x65\x65\xd5\x4f\xd0\x1b\xda\x8c\xb2\x70\xe7\x0d\xc9\x33\x9b\x46\x90\x0b\x58\x18\xe9\x32\x07\x5b\xe6\xc2\x8e\x73\xa1\x91\xd0\x2c\xbd\xc7\x45\x4b\xe1\x23\x87\xb0\xd4\x7a\x1a\xb1\x42\x32\xd2\x34\x2a\x6f\x15\x18\xea\x97\x09\x8b\x81\x5a\x1c\xa3\xf9\xc7\x0b\x25\x72\x2b\x1b\xcd\x7d\xac\xda\x63\x56\x22\xfc\x8e\x72\x95\x9f\x57\xf7\x67\xea\x56\x3d\xa4\xc1\x58\xee\xf7\x20\x01\x09\xf6\x14\x16\xc2\xe7\x04\x39\x92\x30\x62\x43\x7b\x1d\x08\x2a\x8c\x7f\x43\x94\x71\x3c\x1b\x7b\xa0\x58\x7b\x84\x1c\x11\x44\x75\xee\x3f\xf0\x59\xdf\x8c\xfa\x12\xa3\x21\xd9\x01\xcb\x47\xf5"}, -{{0xa3,0xd2,0x35,0x05,0xd0,0x7c,0x5f,0x93,0x7f,0x13,0x63,0x9d,0xbd,0x81,0x8e,0x85,0x14,0x52,0x34,0xee,0x70,0x17,0xec,0xee,0x86,0x36,0xc7,0xba,0x76,0xeb,0xef,0x5b,},{0xfd,0x7f,0xdb,0x3d,0x02,0x2b,0xa3,0x6e,0xad,0xfe,0xd0,0xda,0xaa,0xe5,0xbf,0xf0,0x45,0x05,0x40,0x3f,0x17,0x14,0x73,0xe4,0xd3,0x61,0xee,0x8d,0x15,0x0a,0x0e,0xb4,},{0x67,0xa6,0x67,0xee,0x0d,0x62,0x54,0xca,0x0a,0x8f,0x21,0x25,0x82,0xc0,0xcb,0x8b,0x6e,0xd9,0x7c,0xc9,0x67,0xdb,0x02,0x12,0x96,0xad,0x6a,0xa9,0x9f,0x0a,0xd3,0xa9,0x44,0x97,0x8c,0xfd,0xaf,0xf1,0x3f,0xe5,0xf8,0xc6,0xe8,0x8c,0xbd,0x83,0x1a,0x54,0x73,0xd0,0x74,0x2e,0x37,0x34,0xb3,0xe2,0xdf,0x00,0xff,0x32,0x40,0xa5,0xde,0x02,},"\xbc\x29\x8e\xd6\x98\x92\x90\x40\x28\x72\x5e\x21\xb1\x14\x46\x2d\x89\xd8\xc0\x06\xdc\x88\x4b\x17\x87\x56\x83\x8a\xf4\x95\x4f\xf0\xf1\xb7\x95\x17\x30\x7a\x25\x8a\x0e\x76\x81\xe8\x79\xac\x47\xd7\x92\x02\x30\xb0\xcc\x1d\x66\x17\x1e\xb2\x14\xd7\x7c\xd9\x7f\x61\x7c\x40\x5e\x6c\x21\x72\xfc\x58\x9f\x16\x25\xcc\x5e\x1b\x59\x31\x10\x53\x1f\x6e\xb5\x3f\x1e\x6f\x48\x6d\x19\x64\x61\x24\x47\x75\x0a\x04\x1f\xe5\x1b\x33\x2e\xb3\xfb\xc7\x11\x61\x6c\xe3\x5f\x04\x04\x42\xb4\x31\x63\xb8\x0b\x75\x1e\x21\xec\x12\x45\xf1\x2e\x48\x83\xc7\x9d\x3b\x41\x32\x82\xc6\x9b\xfc\x6a\x46\x5d\x1e\x78\x96\xba\xb0\x38\xdc\x89\xb4\xcf\xc0\x32\xfc\xcd\xfc\x87\xb0\x7f\x06\x11\x0e\x1f\x50\x6a\xcc\xa8\x15\x7a\x32\x25\x43\xbf\x1e\xd8\x90\x67\x27\xf2\x8d\x0d\x68\x9b\xcd\x7d\xd3\xdf\x85\x93\x52\x04\xa9\x04\xab\x3f\x7a\x0d\x99\xc1\x6e\x5a\x54\x2c\xc2\xbc\xde\xbf\x5b\x50\x2d\xba\xbe\x33\xb9\x72\x48\x0e\x02\xe7\x1a\x43\x8a\x19\x80\xa8\x76\x6f\x10\x8b\xd8\xad\x51\x10\x42\x23\x99\x4d\x9b\xfb\x3c\x3a\x4b\x7a\x59\x23\x8c\xe2\xef\x7d\x72\x88\x38\x3f\xfb\xf2\x91\xe1\x60\x2b\x38\x4a\xf6\x07\x00\xd7\xda\xf0\xe8\xfe\x60\xf8\xca\xed\xe4\x3d\xb0\x6b\x3f\x4c\x8c\xff\xf7\x49\xae\xaf\xa4\x6f\xc6\x1c\x49\xb2\xd5\xa4\x12\x04\xcf\x86\xf0\x49\x25\x4d\x80\x9e\x94\x98\xaa\x9d\x4c\xfd\xb9\x4a\xcb\x2b\xab\xfc\xf7\x86\xdd\xfb\x03\x69\x15\x16\xb3\x83\x8b\x0d\x4f\x20\x1c\xb2\x59\x1e\xdb\xb0\xb0\xf6\x74\xe1\xe2\x82\x03\x16\xb7\x2e\x81\xb4\x8c\xc5\xa6\xb2\x93\x38\xbc\x36\x68\x1f\x8f\x7d\xca\x43\xee\x6c\x0b\xd2\xe4\x02\xaf\xbf\x96\x77\x97\x51\x64\x53\xbc\x01\xbe\x86\xbf\x42\x29\x9d\x1b\x73\x6a\x0d\x97\xbb\xc9\x22\xf5\xa7\x8a\xf2\xdf\x42\xe6\xf8\xc2\x8e\x95\x3f\x2c\xea\xda\xff\xc5\xe9\x30\x64\x04\x1e\x42\x5a\xd6\x97\x5f\x88\xc7\xaa\xdf\x81\xc3\x68\x69\x1a\x58\x1e\x88\x5f\x2a\x6b\xa7\x2e\xd6\x8b\x8f\xef\xbc\xd6\xce\x36\x86\x26\xd4\x48\x92\xa2\x02\x70\xb5\xf7\x09\xc2\xe3\x4b\x83\x35\xd4\x2e\xeb\xd6\x7a\x24\xdf\x73\xf4\x54\x55\xc4\x19\x44\x18\x7b\x66\x92\xf0\x54\xb2\xfc\x95\x91\x37\x3f\x19\xfc\x71\xaa\x7f\xa2\x7d\xf6\x00\x6a\x1d\x54\x9b\xbf\xae\x7d\x3c\x3e\xb3\x6e\x5a\xb2\xaa\xa1\x0a\xa5\x53\x8d\xa7\xef\x36\xc8\xff\x35\x4b\x60\x58\x13\x40\x04\xd6\x60\xa4\x03\x63\x21\xca\xad\x00\xa3\x0b\x1c\x49\x8b\xa3\xd8\x08\xc4\x40\x5e\xf7\x96\x18\xfc\x22\x12\xa7\xb8\x33\x96\xa3\xd7\xce\xdc\xeb\x86\x3c\x66\x37\x4d\xc4\x69\xae\x18\x3c\x7e\xd7\x4b\x3e\x70\xd6\x37\x4a\x06\x2d\xe0\x37\x9b\x21\xcf\x25\xd3\xc4\xc5\x76\x21\x15\xcd\xfe\x75\x55\x45\xe8\x9a\xd4\x05\x2b\xb0\x27\x9d\x93\x8e\x90\xde\x3a\xbf\x50\x44\x10\xca\xad\x72\xb7\xc2\x9f\x53\xd0\x1d\x9d\xd7\xf2\xec\x5e\x45\x9a\x04\x59\x2b\xdd\x66\x41\x66\x13\xe6\xed\xd0\x04\x56\x9e\x0e\x6c\x98\x82\x7b\x8c\x1d\x70\x02\xa6\xd1\xbf\x30\x3e\x18\x25\x95\x01\xdd\x89\xf6\xee\x94\x76\x6d\x18\xaf\x81\x04\x63\xeb\x13\xb2\xef\xdd\xf1\x72\x3a\xf7\x35\xa8\x87\x16\xe1\xfc\xb4\xb7\xb4\x3c\xb9\x7e\x1c\xc9\x03\xb2\x40\x8e\xf4\x53\xad\xa4\x16\x47\x86\xf0\x08\x45\xfb\xfa\x1f\xfc\xa5\xcc\x3e\x1c\x4b\xd9\x94\x0e\x7d\x99\xae\xf9\x19\x16\x6d\x05\x8b\x51\x45\x3c\x9c\x14\xfb\x9f\x32\x51\xec\x5f\xe4\xf1\x53\xc7\x0a\x44\x92\xdc\x34\x96\x29\x61\x86\xf2\x3a\xd4\x7e\xba\xd1\x3c\x66\xe6\x87\x27\xce\x50\xba\x94\x87\xf1\x80\x18\x90\xb6\x93\xef\xeb\xfc\x37\xbb\x5d\x95\xf8\xaf\x54\x8e\xc8\xd6\x49\x82\x89\xe5\x5f\x98\x83\xfc\x5b\xe8\x4c\x25\x6d\x2b\xc5\x48\x49\x38\xc7\x09\x82\x0d\x9b\x6b\x80\x59\xc0\xaa\x42\x67\xdd\xe6\x90\x78\xe4\x87\xc8\x86\x5c\x0b\x13\x0a\x0c\xa8\xca"}, -{{0x6e,0x26,0x51,0x05,0xee,0x71,0x71,0xd1,0xbd,0x79,0x3e,0xff,0xd8,0x7d,0x1e,0x2c,0x79,0x45,0x0d,0x5e,0x18,0x8b,0x57,0xbe,0x3a,0xa1,0x62,0xe2,0xa5,0x25,0x28,0xad,},{0x1f,0x40,0x3c,0x7a,0x75,0x50,0x31,0xc1,0x3c,0xa6,0x3a,0xf5,0x76,0x35,0xdc,0x6e,0x2c,0x4f,0x23,0xbd,0x6b,0x1d,0x67,0xca,0x65,0xda,0x68,0xb0,0x99,0x43,0xc5,0x54,},{0xb5,0xa8,0x3a,0x11,0x7a,0x60,0x34,0x5a,0x67,0xe4,0xa6,0x65,0xf3,0x7d,0xe7,0x22,0xa6,0xec,0x03,0x91,0x38,0x29,0x38,0x99,0x59,0xf3,0x76,0xee,0x62,0x64,0x77,0xe6,0x54,0xac,0x8d,0x72,0x0f,0xc7,0x27,0xd4,0xbb,0x8f,0xe1,0x54,0x4f,0x5d,0x0b,0x0b,0x85,0x05,0x14,0x29,0x0b,0x24,0x27,0x3c,0x4c,0xd4,0xb7,0x3a,0xca,0x4a,0x53,0x00,},"\xf8\xb9\xd4\xb0\x27\xeb\xb1\x0e\xe5\x11\x81\x9e\x6e\x56\xfb\x1b\xa9\x58\x40\x18\x41\x8d\x82\x88\x5a\x38\xa4\x49\x08\x60\x07\xb8\x78\x5b\x51\x05\xca\xf7\x82\xbf\x9b\x36\xda\x03\x9c\xc6\x0e\x22\x7c\x7e\x16\x14\xf2\x9b\x64\x0b\x1e\x9b\x22\x74\x7e\xea\x7a\x67\x25\x61\x4e\x89\xe0\x78\x3e\xbe\xbb\xb7\xee\x55\x7e\xf3\x6b\x2b\x46\xcf\x64\x61\xe5\xbe\x2a\xd1\xd7\xa7\xc2\x71\x1a\x47\x5c\xa4\xfb\xc3\x30\x92\xba\x42\x56\x67\xe3\x4d\x09\x00\x60\x51\x8f\x2f\xec\x63\x6b\x04\x91\x23\x87\x6a\xb2\x1c\x8b\xd9\xc5\x0d\xcc\xb9\x84\xca\x01\x1a\x02\xee\xa0\x20\x56\x4f\xa8\x21\xfc\x36\x2b\xfe\x39\x2a\xab\x50\xc2\x73\xfc\x7b\x5a\x04\x21\x88\xe3\x31\x62\x1b\x9d\x2f\x74\x3e\x5c\x8c\xf3\xab\x1f\xaf\xfa\xfe\x2a\x00\x04\xc8\xef\x7c\xdf\x5e\x6d\xbb\x5e\xb5\x44\xe4\x28\x9f\x71\xa6\xfd\x15\xc6\x38\xce\x29\xd2\x8e\xfb\x9c\x03\x9e\x47\x74\x29\xa3\x49\x7a\x83\x82\x7e\x76\xce\x77\xa4\x98\x16\xd9\x0b\x41\xa8\xe1\x52\xf3\x7a\x09\xe6\x34\x0d\xfe\x06\x9a\x4a\xc6\xf2\x7d\xd2\xea\xc7\x47\xfd\x21\xe3\x15\x20\x88\xc1\xb1\xec\xd3\x2a\xc6\x79\x92\x74\x90\x75\x04\x88\xc2\x91\x78\x51\x47\xb6\x3b\x0b\x8f\xf1\x1d\x18\x9b\x90\x49\xb8\xa3\x96\xb6\x93\x2f\x85\xbd\x6a\x15\xef\xf9\xf0\xce\x18\x08\x41\x1a\xf0\xf9\xc8\xe6\xe9\x7b\x81\x4f\x11\x0b\xd4\xdf\x13\x86\xa9\x79\x7d\xc5\x11\xf0\xaa\xb6\xab\x65\x07\x1d\x9e\xa8\x36\x53\x2c\xec\x51\xb9\x2c\xa7\xfb\xdb\x8d\xe1\xc8\x43\x66\x58\xde\x2e\xb6\x5e\xdd\x86\x04\x4f\x6c\x1a\xba\x31\x78\x64\x7a\xd6\x78\x61\x2e\xe7\x4f\x04\x6c\xa3\xc7\xfe\x2f\x39\xc0\x9d\xd2\xe0\x7d\xf2\xb4\x22\x70\x85\xfe\x93\x6e\x79\x4d\x22\xfd\x5f\x40\xa2\x5f\x08\x77\x15\x80\xac\x80\x1d\x98\x89\xf5\xa7\x6a\xea\xe1\xf0\xcc\x4a\x9e\x1e\xdb\xdd\xa3\x75\x0c\x74\xc8\x50\x52\x4b\x32\xf4\x49\x33\xfd\x88\x3b\x53\x72\xbf\xb7\xe7\x61\xe0\x69\xfe\x7c\x1c\x0e\x7f\xbd\x4a\x7f\x58\x46\x7e\xa6\x88\x3f\x9d\x5b\x7f\x66\xd3\x86\xb0\x49\x9b\xb6\xfb\x5e\xad\x89\xc9\xa1\xfd\x2c\xce\xb9\x73\xe2\x87\x9b\x5d\x03\xea\xa4\x52\xe1\x60\x22\xd5\x96\x17\xda\xa0\x48\x6f\x4d\x4c\x11\x78\x07\xfd\xa8\x49\x9d\xfb\x7a\x28\x6f\xd2\xf7\x1a\x8e\xb5\xfe\x64\x06\x5c\x41\xe4\xe1\xe2\x36\x2a\xb4\xe4\x77\x96\x9e\x3a\x40\x8a\x24\x7e\x3a\x56\xfc\x86\xf2\xb0\x1e\xf8\xd3\xcd\xda\x87\x25\x82\x34\xbc\x7f\x25\xb6\x69\x07\xf3\x64\xb3\x7b\x62\x45\x29\x6c\x4f\xdf\x49\x9f\x20\x23\x7f\x48\x64\x85\x2f\xc5\xd8\xcd\x5d\x05\x41\x8b\xe8\xb1\x38\x59\xee\x9a\x43\xe1\x7e\x1f\x57\xa4\xc3\x5e\xa2\x82\xed\x68\xeb\xcd\xa6\x82\x81\x74\x24\x5a\x49\xc6\xcb\x65\x90\xeb\x1f\x2d\xcf\xb0\x07\xbf\xa1\xc3\x20\x77\x95\x6d\xa9\xac\xbe\x3e\xf0\x72\x37\x99\xfd\xb8\x69\xd8\xde\x30\x70\x6a\x9c\x02\x68\x14\xd1\x6a\x01\xe0\x33\xc9\x1b\x59\x07\x0d\xfe\x44\x5c\x5b\x84\x8a\x51\x66\x12\xe5\x13\x1f\xe8\x48\x69\x21\xe3\x6b\x8e\x7e\xf1\x57\xa8\x88\x22\x88\x6c\x68\x1b\x5d\xa7\x1f\xea\x94\xd9\x57\xda\xfe\xc2\x6f\x41\x47\xa3\xb2\xac\x38\x3a\x5f\x47\xc8\x58\x5e\xb1\x7a\x8a\xc6\x57\x90\x64\x1b\x42\x18\xd7\x55\xf8\xbe\xa4\xd9\x7a\xe2\xa4\x5b\xdc\xdc\x23\x23\x62\x94\xd8\x52\xc9\x5d\x08\x40\x6d\x2e\x9b\xd3\x0c\x32\x64\x52\x53\x8c\x1f\x5e\x50\x04\xd4\xa1\xa8\x27\x20\xda\x32\xe5\x9d\xc3\xab\x18\xea\x08\xa0\x58\xf7\x91\xd2\x44\x18\x55\x60\x86\xc1\xe4\xed\xce\x89\x82\xaa\x23\xb1\x18\xfb\x26\x6e\x60\xb5\x42\x78\x0a\x69\x33\xad\xd9\x13\x26\x55\x12\xc0\x7b\x11\x49\x78\xd4\x4a\xf7\x3b\x20\x30\xec\x47\xb0\x6f\xd0\x9d\xda\x8c\x4f\x1d\x4e\x31\x37\x75\x46\x8c\x45\x1f\x9e\xe6\x11\xe9\xcd\x4c\x08\x45\xc2\x50\x19\x48\xa7\xb1\x4e\xf1\xd4\xb5\xcf"}, -{{0xc4,0x37,0x0d,0x2a,0xaf,0x35,0xac,0xd1,0x58,0xfc,0x0d,0x16,0x22,0xa3,0x99,0xc9,0x9f,0x41,0xb9,0xda,0x4e,0x97,0x0b,0x35,0x4e,0x5b,0xa0,0x5c,0xbe,0x84,0x4c,0xa8,},{0x35,0x45,0xd7,0xd4,0xc9,0x5c,0x3d,0xb6,0xa5,0x45,0x30,0x53,0x7a,0xfa,0xfa,0x4d,0x86,0xdd,0xec,0xf9,0xcc,0x7e,0x66,0xc3,0x19,0xba,0x9f,0x7d,0xd7,0xd0,0x7e,0xe7,},{0x9f,0xeb,0xab,0x5a,0xe1,0x61,0xd6,0x92,0xa6,0xa3,0x94,0x50,0x0a,0x28,0x90,0xd2,0x1c,0x7f,0x0e,0xe2,0x6f,0x46,0x40,0xaa,0xba,0x4f,0xe6,0x6b,0x90,0xb8,0x9e,0xdc,0xb8,0x0e,0xa4,0xcd,0xca,0xbb,0x4d,0x2c,0x3a,0x5c,0x41,0x54,0xe8,0xff,0x20,0xd0,0xe2,0x37,0xfe,0xfd,0x00,0xc7,0xba,0x97,0x82,0xe1,0x74,0x8f,0x64,0x88,0xac,0x01,},"\x61\x9f\x57\xde\x2b\x1d\xba\xee\x20\x9a\x82\x5d\x8c\xa9\x7f\x84\xee\x49\xeb\x12\xa0\xb1\x3d\xcd\xd2\xb3\xa4\xee\x45\xe0\x17\x6d\x47\x4c\xf0\x94\x60\xc8\x31\xa8\xae\x1d\x3f\x39\xbe\xeb\xd0\x88\x08\xb3\xed\x17\x61\x21\x3b\xa9\x53\x42\x18\x60\xcc\x07\xe2\xdb\x31\x2e\x68\x0d\xf0\x3e\x60\xa6\x87\x02\x64\xab\xca\x8f\xd5\x13\x01\xe1\xc1\x56\x20\x23\xd8\x02\xcc\xd5\xc7\xd1\x96\xdb\x39\xfb\xb8\x30\x4b\x0e\x59\xe3\x33\x16\x41\x92\xec\xc3\x33\x38\x7e\xef\x69\xc7\xa7\x8a\x5d\x11\x25\x88\x62\xd6\xc2\x81\xb1\x9c\x0b\xd3\x36\xcd\x3e\xdb\x2f\x9f\xaa\xd4\x02\x1a\xc2\xf2\x05\xc1\x68\x14\xb3\x85\x48\x43\x3f\xf9\xed\xdf\xd6\x11\x33\x77\x97\x69\xdc\x69\xaf\xac\x65\x8a\xfc\x1d\x1b\x41\x6d\x39\x0a\xd5\xb4\x5a\x1a\xd5\xcc\x4b\x00\xb4\xb2\x78\xfb\xe4\xb5\x9d\x52\xe6\x1a\x6a\x5f\xd0\x02\x41\xc6\xcb\xc3\x82\xd2\xd6\x21\xa3\xde\xd0\x02\x01\x9b\x33\x05\x60\xe3\x61\xfa\xab\x28\xf4\x1d\x1a\xf9\xc9\xc0\x02\x0f\x2b\xaf\x99\xe8\xd8\xee\x58\xe3\x12\x22\x02\x14\x7c\x0a\xdc\x57\xd6\x70\xc5\xb3\x80\xaf\x59\x4c\xc7\xed\x57\xb8\x7e\xc6\x67\x4a\xb6\x3f\x3a\x98\x49\x75\x3b\x94\x62\xaa\xb5\xde\x88\xc9\x48\xa8\xb1\x09\xaf\x4d\x49\x54\x92\x7a\xac\x58\xbe\xe9\x53\xbe\x0d\x8d\x7d\x71\xaa\x11\xd1\x1f\x1a\x87\xb1\x47\x7b\x91\x70\xbd\x73\x5c\xfc\x24\x49\xf0\x51\xb8\x2b\xc5\x9b\x0b\xee\x76\xa1\x72\xe8\xd3\x26\x70\xf5\x1d\xdd\xdb\x80\x4a\xd1\x10\xa5\x65\xe3\x84\xcd\xb7\x6f\xad\x04\xcf\xf6\x78\x93\x09\x1e\x41\xe6\x9c\xfd\xf7\x0e\xa9\x26\xc2\x63\x69\xa5\xb6\x19\x3b\x19\xab\x0a\x62\x55\x8d\xa5\x5f\xfa\xfe\xb8\x78\x97\x57\x71\x06\x44\xaa\x19\xf4\x74\xbe\x4a\xda\x9d\xc1\x84\x9b\x07\xd5\xe1\x7b\x85\xf9\x21\xe1\x01\x6a\x54\xaa\x60\x95\x77\x72\x53\xa7\x34\x26\xfc\x78\x64\xb9\x95\x5f\x04\x90\x70\x23\xdb\x20\x7f\x85\xdd\x21\xa6\x51\x06\xcf\x0d\x62\x23\x85\x87\x0c\x34\xc2\xda\x9a\x11\xe4\x72\x63\x95\x12\x1e\x4a\x67\x61\xfb\x52\x22\x29\xd9\xe5\xcc\x9d\xab\x35\xae\xb8\x7d\x0d\x79\x69\x3c\x00\x6f\xde\x1c\xfa\xf1\x16\x20\x8b\xba\x96\x20\x59\xcf\xc0\xd2\xd6\x37\x0a\xac\x77\x48\x36\x2e\xe6\xa0\xa3\xca\x7b\xf1\x33\xeb\xcf\xa2\x0f\x1c\x4e\xd8\x30\x7f\x80\x0c\xca\x7e\x6c\x4b\xea\xa3\xfb\x2a\xb0\x86\x12\x53\x64\x28\x5c\x44\xed\x1a\x73\x7a\x67\xcb\xf3\xb7\x63\xc9\xf8\xb1\x42\x7e\x89\xdf\xa9\x6d\x29\x0e\x9d\x48\x42\xfe\x63\x16\xaf\xef\x83\x4c\xd8\xcd\x1f\xdc\x1f\x12\x4c\xa3\xfe\x26\x26\x6d\xa6\x2e\x27\x5c\x0b\xf7\xfc\xc8\xe5\xf9\xbb\xa6\xc0\xd3\x8e\x23\xfa\xfa\xb1\xe0\x49\x48\x17\x94\xc1\x4f\x4a\x8c\x53\xbe\x1c\x96\xf7\x69\xc9\xb1\x3e\xac\xa3\x9a\x0e\x49\x36\x6d\x2c\x9f\xfe\x8f\x20\x63\x60\xa9\xd5\x03\xde\xc5\x98\x62\x11\x12\xe3\x77\x67\x13\xe7\xfc\x06\x49\x43\x3e\x25\x7e\x50\x3a\x54\x60\x59\xa9\x89\xda\x89\x15\x7d\x76\x47\x60\x05\xfd\x90\xe4\xb0\x7a\xaf\x0d\xb0\xbc\x0b\xc0\xb6\x7d\xb8\xdc\xba\xdf\xf3\x93\x74\xe1\xaf\xae\x55\x16\x34\xe0\xe3\x28\x31\xad\x0e\x5f\xa7\xd5\x21\x6f\xa7\xc6\x44\xf7\x3e\x1e\x8e\x07\x23\x83\x94\xa4\x16\xc1\x69\xaa\x9d\x53\x03\xf4\x69\xa5\xd4\x07\x43\x08\x72\x1f\xfd\xde\xff\x65\x59\xe5\xad\xf0\xc2\x77\x3b\x3f\x52\x64\xe7\xaa\xa8\xc2\xdb\x88\x8e\x28\xe8\x15\xc7\x10\x69\xc3\xb4\xce\x6c\x29\x03\x4c\x0a\xb3\xb5\xc1\x9a\x80\xa9\xd8\xc2\xe8\x74\x81\x35\x31\xc4\x22\x75\x2a\xd6\x2b\x3c\x5a\x1a\x3d\x6c\x5a\x5d\xb5\x87\x27\x06\x93\xaa\x75\xd5\xf1\x72\xee\xdd\xf4\xeb\x83\x9b\xd7\x93\xaf\xfb\x1c\x79\x6a\x1d\xf0\xe4\x42\xdd\xf9\x9b\x78\x0a\xa4\x1e\xea\x0f\xe6\xf8\x65\xbb\x53\x9c\xa5\x3a\xa4\x5d\xb9\xa8\x56\xcb\x75\xd0\x15\x1d\x35\xed\xea\x80\xf2\x94\x6d"}, -{{0xbd,0x3d,0xe1,0xa1,0xd1,0x64,0xbd,0x6e,0x9b,0xe0,0xa6,0xd1,0x07,0xf7,0x03,0xa6,0xdd,0x91,0x4c,0x86,0x67,0xcd,0x34,0x1d,0x13,0x9f,0x19,0x57,0x8d,0x93,0x3b,0x16,},{0x9b,0x02,0x49,0x64,0xbd,0xfa,0x85,0x2e,0xb2,0xd4,0x14,0x4f,0x35,0xb7,0xcd,0xc2,0x67,0x81,0x14,0x3c,0x2b,0xd7,0xf6,0x60,0x23,0x3f,0x8b,0x8a,0xa3,0x60,0x71,0xee,},{0x13,0xcc,0x15,0x8f,0xd0,0x61,0x79,0x2f,0xce,0xd1,0x56,0x87,0x95,0x98,0x25,0x1d,0xd0,0x1d,0x57,0x5b,0x40,0x0f,0xe3,0xe3,0x9a,0x70,0x08,0x63,0xaa,0xe8,0xdb,0x1f,0x91,0x97,0xfa,0x50,0x1c,0x0c,0xf9,0x93,0xe4,0x4d,0x6a,0xc5,0x51,0x80,0xb8,0x69,0x83,0x8e,0x8a,0xe2,0x4b,0x21,0x4f,0xa3,0x5e,0x24,0x4b,0x7a,0x6c,0xff,0x6d,0x0d,},"\x17\x69\xfc\xdb\xf5\x12\x47\xed\x4c\x83\xa0\x0b\xbb\xf0\x2f\x44\x28\xda\x6f\xce\xdd\xd0\x16\x1a\x02\xfc\xcd\x15\x00\x97\x06\x65\xe1\xc7\x63\x0a\xd2\x2e\x3d\x97\x49\xc7\x92\xe7\x1a\x26\x0c\xff\xf6\x05\x32\x56\xe0\x2f\x5b\x47\xbb\xa1\x4b\x76\x1a\xe5\x3c\xa7\x21\x9e\xd2\x80\x1d\x2d\x78\x8e\x26\x41\x9f\x36\xc8\x1e\xf9\x2c\x23\x03\x68\x37\x35\xc8\xa1\x75\x6a\xda\xb6\xa4\x87\x92\x31\x53\xe4\x35\x60\x3c\x96\xb2\x39\x55\x3e\xdf\xde\xb0\x93\x29\x8f\x7a\xe7\xdc\x90\xf1\x6a\x7e\x56\x64\xb9\xe4\xc0\x2b\xa7\x31\xa2\x3c\xf2\x23\x4e\x25\x0a\xc9\x74\x26\x33\xa9\x32\xa9\x48\xbb\x83\xdc\x3d\x79\x4d\x05\x9f\xed\xf4\xec\x86\x18\xc7\x43\x3c\x5d\x8f\xe5\xe6\x2c\xf0\x7b\x57\x68\xc4\xd9\xb2\x61\xc7\x15\x36\x80\x4f\xe2\xe7\xca\x70\x98\x87\x65\x21\xd5\x76\x77\x36\x14\x24\xe4\x7f\x1b\x95\x92\x37\xf9\x07\x10\x42\x1f\x5b\xc4\xf1\x09\xf7\xd4\x89\xc7\x55\xe9\x4e\xef\xdf\xb3\xc8\x5b\x90\xec\x01\x31\x81\xa2\x3b\xb9\x53\x5f\xee\xa4\x94\x1d\x0a\x06\xa5\x40\xbd\x6b\x58\x8e\x55\xb7\xf3\x57\x57\x14\x9c\xa3\xe6\x40\x96\x5e\x1a\x0f\xf7\xf3\xc8\x25\x92\x59\x95\x7f\xf5\xda\xb9\xfb\x87\x32\xea\xe7\x19\xb6\x24\xa4\x49\x28\x78\x17\x9b\x5a\x83\xab\xe5\x1c\xaf\x02\x08\x3d\x73\x7c\xeb\x4f\xcf\x04\x2f\x2e\x60\xba\x02\x97\xac\x72\xb8\x7f\xe3\xe1\x4b\xa5\xfb\xc5\x4b\x48\x09\x10\x73\x89\x68\x23\xbf\xa2\x89\xce\x8e\x16\x87\x3b\x48\x81\x2c\x32\xbf\xea\x5f\xf6\xbb\x22\x1d\x1e\xa5\x46\x3d\x32\x5b\xbe\x31\x1e\x7f\xd1\xe7\x83\xde\x65\x0b\x79\x52\xea\xe4\x61\xd6\x3b\xc7\x47\x05\x22\xaf\x5b\x77\x89\xf8\xfc\x2e\xb1\x92\xd2\xcf\x77\x6c\x5c\x24\xb4\x4e\x29\xcd\xb0\xcc\xcb\x1d\x90\x36\x14\x38\xe4\x95\x0f\xf3\x4d\xbc\xb3\xcb\x0e\x81\xcc\x45\xf8\xd0\xff\x57\x09\x49\xf7\x80\x84\xe1\x06\x0f\xf5\x59\x4a\xd5\x16\xf5\x0f\x1c\xb0\xa7\x65\xe1\xc0\xe0\x38\xd5\x94\x3b\x93\x6e\x4a\x8b\x49\x33\x54\xe7\x9a\xbc\x91\x7b\xb9\x27\x12\x66\xee\xba\x77\xa9\x3a\x65\x7f\x9a\xd8\x7b\x29\x1a\xc7\xea\x38\x6f\x5d\x4f\xcb\xc5\x82\xe7\x2d\x5c\x23\xd9\x2b\xa9\x44\xb0\x06\x4c\x20\xe3\xe2\xdc\xf5\x04\xbc\xc7\xc6\x96\x6c\x63\xf2\x08\x08\x43\x60\x0b\xa3\x13\xec\x27\xcb\xa9\x5e\x7e\xf3\x18\x16\x8c\x90\x67\xdc\xe8\x6c\x1e\xf0\xd5\xd9\xeb\x7a\x61\x58\x48\x9d\xf3\x2e\xd5\x8b\x69\x31\x03\x08\x18\xf0\x07\x05\xa0\xdc\x55\xd3\xdb\xf8\x00\x6a\x85\x46\x64\x1b\x18\x65\xd9\x19\xbc\x24\x22\x02\xcb\x3a\xe3\x00\xbf\x86\x53\xe3\xb3\x78\x94\xc3\xdc\x0e\x47\x7b\x9d\x7c\x41\xba\xf8\xd3\x88\x7c\x2e\xb5\x9b\x1e\x4d\x50\xbb\xb6\xf1\x79\x2a\x1c\x93\x67\xc6\x5c\xdb\x45\x0c\x2d\xfa\x21\x45\xe6\x11\xa9\x7a\xd8\x1c\xff\x1f\xd8\x3c\x6c\xf7\x23\x09\x47\xea\xff\x4c\x21\xdc\x1b\xaf\xb7\x1e\xc4\x1e\x5b\xc7\x2b\x37\x45\xec\x3e\x38\xbf\x59\x30\xc1\x26\xd0\x60\xf0\xc5\x0a\x89\x5f\x00\x9a\xa1\x8e\x87\xf2\x17\x4f\x58\xab\x53\x79\xa7\x21\xfd\x83\xaa\xd5\x51\x7f\xd9\x9d\xff\x14\x6e\xde\xea\x61\x52\x12\x35\xe2\xf1\xa1\x6e\xe5\x83\x03\xe0\x91\xbe\x8d\x57\x90\x94\xc1\xd8\xa2\x0b\xc7\x4a\x55\x0d\x77\xc0\x0d\x08\x75\x71\x51\x7a\x63\xcd\x41\x26\x93\x3a\x4f\x09\xa0\x70\xbf\x8e\xa4\xff\xb8\x46\xa9\x78\x0e\x97\x34\x04\x3b\xac\x4c\x0f\xf4\x7b\x1a\xfc\xcf\x52\x93\xac\x14\xbc\x73\xeb\xf6\x71\x29\x65\x7e\x4b\x8a\x8b\x33\xdd\xac\x7b\x0f\x4d\x71\x9d\x2d\xc6\x5d\xf6\xea\x0a\x3f\x24\xcf\x44\xc8\x33\x8e\xd6\x01\xa3\x93\x9c\xa3\x58\xfc\x4b\xe1\x3e\x8e\xde\x02\x75\x39\x71\x2c\xa2\x3e\x3f\xfb\xa7\x06\xe8\xfd\xd6\x2a\x07\x4e\xe0\xad\x74\x20\xf7\x80\x60\xcc\x96\xfb\x2a\xbf\x30\xe9\xea\xa2\x41\xc0\xf8\x7e\xbb\xe3\xec\x73\x51\x75\x96\xf7\xc3\xc5\xa8\x0c"}, -{{0xf6,0xae,0x51,0x6a,0x51,0x29,0x6f,0xc5,0x23,0xce,0xa5,0xf0,0x08,0xcf,0xbd,0x09,0xe7,0x3f,0x78,0xb6,0xfd,0xd3,0xb6,0x94,0x26,0x12,0x80,0x41,0xa5,0x60,0x4c,0xf9,},{0x37,0x6c,0x82,0xba,0x7b,0x87,0xaa,0x77,0x41,0x87,0x27,0xdb,0x33,0xd3,0x26,0xae,0x75,0x8b,0xf7,0xa1,0x35,0xc1,0x04,0x60,0xcd,0x8b,0xf8,0xfe,0xb8,0x3c,0x2b,0x10,},{0x0f,0xe4,0xdd,0x7e,0x1f,0x60,0x8e,0xe8,0x2b,0x7f,0xe8,0x63,0xd1,0xb0,0x3a,0x81,0x84,0x3c,0xe2,0x0c,0x76,0x2c,0xd8,0xbb,0x24,0xef,0xd4,0x6b,0xa0,0x25,0xff,0xf3,0x33,0x1d,0x87,0x57,0x52,0xca,0x72,0x20,0xc5,0x3d,0xd3,0xc7,0x1f,0x2b,0xc1,0xe2,0xc6,0x4a,0x2f,0x9c,0x58,0x86,0x5a,0x2a,0x24,0x48,0x09,0xf4,0x13,0x4e,0x53,0x07,},"\x83\x42\xf2\x5a\xc4\xb1\x7e\xba\xd6\xf7\x9b\x9a\x03\x31\x75\xc7\xf2\x8a\xf0\x9e\x65\x8e\x8c\xb9\x8c\x29\x4f\x15\xc3\xc8\x34\x26\x29\xcb\x2a\x32\x47\xdf\xc8\x75\xb8\x2f\x5b\x38\x0c\x5d\x11\x42\x6a\x2e\xeb\x62\x45\x0b\xd8\x85\x65\x01\x07\xc6\x83\x62\xa3\xb7\x2c\xe8\x23\xf2\xd1\x59\x42\xb7\xdd\xa3\x01\xd2\xfb\x63\x8f\x30\x2a\xa9\x57\x0b\x47\x91\x1d\xad\xd3\xbd\xdb\xfe\xd5\x54\xc1\xc8\x0b\xd7\x18\x07\x8b\x8b\xd2\xc9\xc3\x14\xa5\x16\x6f\x26\x5e\x82\x66\xee\x2d\xb3\x57\x56\x1a\x55\x85\xc4\x14\xa7\x84\x0b\xfa\xe6\x09\xd7\xcd\xdd\xe1\xfa\xde\x85\x56\x0f\x23\xd6\x38\xef\x3d\x52\xe5\x1f\x5c\xf3\x13\xa0\x72\xc5\xea\x0f\x81\x7f\x72\x81\xe2\xcb\xa5\xc5\xc8\xd2\x6c\x92\x85\x92\xb8\x1f\x0f\xf8\xcd\x18\xdb\x5a\x2c\x41\xd8\x80\xd7\x44\x73\x86\x3c\x7b\xbd\x00\x56\xfa\x4d\x4a\xfa\xbd\x17\xa3\xb8\x9d\x97\xd3\xfe\x5d\xc0\x6b\x0f\x61\x2a\x1d\x66\x42\x39\x23\xba\x8d\xfb\xb8\xec\x82\x46\x62\x4d\x83\x78\x4e\xba\x4f\x57\x36\xba\x38\x5e\x44\x22\x96\xc8\xcb\x0f\x1b\x68\xe0\x33\x42\xb2\xc6\xc1\x03\x34\x6f\x6d\xd7\x40\xe2\x6c\x3d\x13\xca\xef\x80\x1d\x1b\x26\x21\xd8\x9f\x06\x93\x91\xa0\x78\xd4\x3a\xe6\xff\x12\xee\xca\x66\xbc\x32\x63\x7b\x45\xf0\xac\x62\x7c\x2d\x7b\xbf\x8a\x49\xd9\x46\x81\x75\xe2\x68\x85\xe0\x28\x21\xd3\xa3\xba\xa2\xc3\xe3\xa6\xbb\x96\xb5\x75\x26\xe2\x24\xcf\x3d\x85\x9f\x66\x95\x73\xcb\xd5\xc8\x73\x93\x74\x61\x56\xf3\xd1\xc7\xa8\x03\x08\xdc\x1f\x24\x05\xbf\x0d\x40\xbe\x1c\xa7\x3b\x76\x7d\xed\xf4\x03\x13\x37\xc0\x81\xbf\xa3\xae\x6e\x54\xf6\x02\x3f\x42\xf0\xcb\xd8\x77\x62\xdb\x55\x91\x3c\x70\x72\x06\x03\x40\x10\xdf\x2a\xa8\x75\x3d\x03\x0f\x03\xc2\x67\xe7\x1a\x9d\xd2\xc6\xc1\x9d\xe3\xe1\x85\x1a\xbf\xac\xbb\xd5\xdd\x5b\xf8\x96\xfa\xb8\xe4\x15\x31\x7b\x49\xf1\xe4\x09\x6e\x3d\xa9\x9a\x5b\x5d\x0a\x3c\x42\xda\xf9\xde\x94\x84\x7c\x1e\x53\xc8\x81\x8a\x5b\x84\x33\x23\xf5\x01\xe3\xa7\xfa\x68\xdf\x89\xa5\xf4\x1f\x2c\x62\xc3\x8d\x17\xf2\x50\xb0\x2a\x67\xfa\xe4\x7d\xaf\x06\x3f\x55\x89\x42\x37\x7e\xf8\xa8\x90\x52\xf1\xa2\x15\xd7\x68\xf7\x91\x3a\x7e\xc1\x4e\x98\xb8\x1e\x4b\x2c\xcf\x26\xba\xca\xd6\xf3\x96\x64\xaf\xc0\xe9\x1a\x3c\xad\x69\x1d\xb2\xbf\x56\xa7\xab\x66\x77\xb4\x95\x96\xdb\x88\x7c\x97\xde\xf4\x35\x08\xa7\xa2\xec\x2a\xb7\x55\xec\x36\x8e\x2e\x53\xd1\xe1\x6b\x60\xff\xf0\x9c\x3b\x52\x26\x3f\x0f\x7c\x1e\xa9\xcc\x35\x37\x31\x97\xe9\x5c\x11\xe6\xd2\x2f\xa9\xd8\x29\x9c\x42\x37\x36\xf5\x81\x4f\x1e\x79\x8d\x22\x75\x18\x60\x0d\xf6\xa7\x90\x35\x8d\xea\xe3\x8d\x56\x39\xe1\x98\x3f\xe0\x18\x43\x6e\xa5\x8b\xa8\x46\x75\x48\xc9\x29\xef\xbb\x16\xdf\xea\x41\x02\x25\x3a\x35\x0f\xb8\x4d\x98\x31\xc4\xc2\xcb\xcb\x76\xe1\x8d\x7f\x3e\x95\x36\x41\xad\xa4\x14\x21\x39\x30\x91\xe6\x3d\xfe\x66\xde\x24\xc9\x92\x32\xc7\xd6\xa2\x83\x7a\x48\x98\x3c\xf5\xb1\x63\x31\xce\x00\x05\x0d\x1c\x71\x39\x58\xff\xce\x5f\x2e\x93\x48\xc5\x2f\x53\x12\x05\x79\xa7\xc9\xa1\x60\x08\xd1\x34\x83\x8e\x59\x61\x29\xc7\x02\xfc\xd2\x11\x48\xbd\xf9\x17\x4d\x48\xe2\xda\x0a\x8a\x66\x35\x9e\xde\xe0\x1c\x50\x09\xef\x67\x42\xfe\xc4\x1c\x1a\xce\xcd\x03\xef\xe1\xcc\xc9\xb1\x30\xd6\xe5\xac\x92\x57\x6a\x85\xcc\xb7\xcf\xc7\xd0\xe4\x23\x31\x06\x17\x29\x31\xa0\x86\x99\x79\x0b\xc4\x1a\xcf\xbb\x73\x1a\xdb\xb2\x6d\x56\xb3\x9a\xaa\x5b\x33\x3b\xc1\xa1\x0e\x2c\x70\x64\xca\x86\x11\x9d\x8c\x71\x71\x48\xf9\x24\x41\xaf\x24\xcd\x2a\xa8\xf5\x7c\x86\xba\x38\xa5\x9a\x10\x0b\x92\x76\xdf\x38\x27\xec\x7f\xb4\xd3\xfa\xf5\x8b\xe3\x1c\x6e\xca\xfd\x69\xcf\x1c\x64\x10\xa4\x9c\xd7\x08\x1f\xf6\xe9\xfc\x39\x7c\x2d\x20"}, -{{0x83,0xf7,0x89,0x90,0x0f,0x04,0x0d,0xc6,0x2f,0x4d,0x18,0x78,0x4c,0xb6,0x4b,0x63,0xc8,0x8e,0x8d,0x18,0x00,0x16,0x96,0xbb,0xeb,0x47,0x07,0xc4,0x69,0xd1,0x1a,0x5b,},{0xed,0xfc,0x2b,0xab,0x7e,0x79,0xf4,0x00,0x37,0xfe,0x4d,0x90,0x41,0xde,0x48,0xda,0x9a,0xee,0x8f,0x97,0x80,0x98,0xd7,0xb0,0xae,0x17,0x92,0x90,0x25,0xe4,0x27,0x3d,},{0xea,0x65,0x82,0xcc,0x23,0xe0,0x46,0x09,0x17,0xf7,0x82,0xd9,0x64,0xe3,0xbb,0x6d,0xcd,0xe0,0xae,0xea,0xc4,0x2c,0xc1,0x49,0x19,0xd3,0x6c,0xe7,0x8a,0xa0,0xaf,0xd9,0x80,0x72,0xf5,0x4c,0x79,0x5f,0xbf,0xd7,0xa4,0x1d,0x99,0xd7,0x06,0x06,0xc2,0x8a,0x5d,0xcf,0x19,0xbe,0x38,0xa0,0xce,0x2d,0x09,0xbb,0x8f,0x84,0x4c,0x31,0xbf,0x00,},"\x6c\x11\x2a\x20\xd3\x06\x57\xab\x5f\x8c\x5c\x04\x47\x8d\x6c\x42\xd1\xc6\xbd\xef\x38\xcd\x4f\xe0\x06\xac\x2a\x57\xe2\x90\xff\x29\x28\x78\x96\xee\xa8\xc3\x0a\x01\x39\xc1\x8f\xc8\xc9\x75\x64\x56\x3e\x86\xc8\xd3\x40\x56\xa6\x71\x9b\xfe\x47\x9d\x9e\x87\xe8\x1b\x19\x45\x23\x31\xbf\xa1\x54\x80\x68\x82\xe5\x03\x9a\x20\xc9\xe9\x54\xb1\xfc\x7c\x01\x5d\xcf\x58\x15\xbd\x7c\xf7\xb6\x35\x7d\xf9\x28\x0b\x9b\xd4\x3f\x89\xff\xc9\x19\x45\x32\x3b\x5a\xcb\x2a\xe0\x02\x54\xd4\x16\x28\x68\xd1\xc8\x3e\xc6\xe0\xfc\xbe\x7a\x8a\xb9\x25\x41\x92\x14\x9c\x6b\xc9\xe5\xfe\x35\x06\x94\x16\x5d\x66\x38\x33\x1e\xb2\x4e\x3b\x13\x90\xc6\x98\xc4\x83\x83\x78\xc0\x1b\x2c\x61\xa3\xeb\xe2\xc0\x60\xb9\x8b\xa6\xee\x02\xb5\x19\xb4\xea\xc1\xe0\xbc\xc0\x9b\x23\x24\xcc\xf5\xb1\xa7\xfe\x8f\xd0\xb1\x54\x5a\x94\x27\x83\x2a\xbb\x25\x74\x4e\xeb\x36\x32\x6b\xe6\x4e\xfe\xd3\xa7\xb0\x7d\x63\x0a\x21\xc3\x08\x1b\x55\x26\x1c\x35\x32\x87\xc6\x6c\x57\x66\x3a\x99\xdb\x46\x6a\x5d\xee\x22\x74\x6b\x81\xc7\x50\xef\x85\xbe\x51\x14\x3e\x22\x1e\xcd\xf1\x14\xfe\xf1\xb3\x08\x2f\xf5\x4f\xd0\x44\xbc\x88\x4b\xfb\x3c\xc5\xc5\x33\x59\x97\x00\x98\x67\xce\x94\x91\xa8\x0f\xe6\x96\x82\x5f\x99\x42\x6d\xef\xab\x6a\x49\xba\xdc\xde\x40\x3f\x58\xe8\x31\x79\x66\x21\x07\x47\xb5\x67\x75\x4d\xe5\x30\x76\xb3\xec\xbf\x65\x34\x6c\xb8\x39\x05\x83\x2e\x16\xd0\x1b\x50\xb9\x3d\x37\xeb\x9b\xfe\x20\x17\x2a\x31\x63\x0d\x25\xf3\x21\x7d\x87\xd9\x34\x65\xfd\x8a\xc5\x54\xcb\xbb\x39\xd9\x82\xea\xd7\x21\x93\x91\x23\x4c\x88\x9f\x0b\x92\xa2\xe0\x41\x3d\x86\x6c\xac\x08\x7d\x62\x8c\xe3\x1c\x61\xc6\x32\x3e\xcb\x8e\x68\x95\x55\xaf\x10\xde\x2b\x65\x6e\x6a\xea\x2c\xde\x93\x2e\x24\x1f\x6d\x1f\x8a\x9e\x33\x16\xcf\x13\xf1\x35\xac\xef\x83\xa0\xc0\xcf\x22\xf9\x5c\xa8\x18\xe6\x1f\x92\x76\x87\x74\xc6\x30\xe0\x92\x5b\xe9\x9d\xbd\x32\xb4\x99\xc0\xfe\x7d\x84\xa4\x2e\x39\x32\x87\xf6\xf5\xce\x3d\x0b\x27\x1f\x17\x00\x45\xa6\xd4\x8e\xab\x31\x6f\xe1\x7b\x18\x58\xb1\xff\xee\xe9\x08\x88\xf3\xa3\x7a\x24\x80\xdf\xd0\x4a\x4a\x86\x29\xf8\x68\xb5\xc0\xa8\x0e\xe1\xf0\x37\x19\xf3\xa4\x7d\x40\x95\xbe\xf1\x0e\x02\x34\xfc\x30\x0e\x2a\xf4\x82\x28\x5d\x78\x93\x79\x68\x31\x9d\xa9\x4b\xeb\x6c\x40\xe0\x78\x57\x7c\x02\x4f\x3a\x5c\xda\x00\x84\xe2\xf8\x55\xa9\x39\x6a\xaa\x9e\xe9\xbf\xaf\x2c\xc7\x71\xfe\x68\xc4\x0b\x62\x9e\x8d\xcf\x11\x5e\xf0\x3e\x75\x7a\x2a\xc9\xee\xf0\x73\xf1\xbd\xf9\xc5\xa4\x41\x00\x31\x55\x8a\x6d\x38\x2b\x5f\x16\x02\x4b\x15\x1b\x1c\x01\xee\x78\x17\x41\x3a\x3c\x4d\xe9\xdd\x64\x78\x78\x5b\x81\x10\x1d\xf5\x52\x24\x30\x05\x87\x80\x20\x7e\x79\x0f\x61\x2d\x78\xe5\x70\x5c\xee\xd4\x6b\x0e\xc0\x75\xe7\xc1\xdc\x07\x3b\x17\xb2\xb4\x3d\x72\x53\x59\x27\xbf\xd2\x71\xe9\x2e\x3c\x93\x63\x8e\x40\xa9\x60\x1d\xc2\xc1\xab\x76\xd9\x1a\x41\x03\xdf\x65\x7d\x91\x1c\x82\x9e\xe8\xa5\xf7\x47\xf7\x64\x2f\x5a\x91\x5a\x5f\x40\xf6\x30\xb4\x30\x39\xc7\xd4\xbd\x2a\xd2\xb3\x21\x29\xd9\x4e\x5b\x2f\x03\xad\x4a\x3d\x45\x57\x7e\xb8\x1f\x36\x9c\x9e\x3e\x2a\x4f\x6a\x8e\x41\xac\xf8\x28\x3b\xe5\x84\x25\xea\x99\x3b\x8e\x98\xee\xa6\x33\x05\x56\x64\x86\x18\xda\xd9\x8f\xa2\x55\x62\x0d\x83\x6d\x3c\x7f\x29\xb9\x07\x89\x58\x49\x28\x61\x67\xc7\x18\x1e\x2c\xaf\x55\xc2\xc1\x84\xa9\xa9\x11\xf8\xe4\x1c\xb0\x42\xe2\xcd\x48\xb0\x54\x4e\xa7\x9f\xe2\xef\x38\x1e\xbc\x5b\x15\xe3\x9a\x9b\x5c\x6d\x99\x8f\xae\xaa\xa7\x77\x3c\xfe\xc0\x84\xc0\xbf\xae\xd1\xbc\xab\x96\x3a\x4e\xf3\xd9\x4d\xbb\x3d\xfe\x72\x4c\x04\x0c\xe4\xd1\xe2\xee\x7f\xc2\xda\x4b\x25\x12\x7c\xe3\xa5\xdf\x69\x3f\xcf\x5a\x6e\xd1"}, -{{0x43,0xbf,0xf3,0xcd,0xd5,0x30,0x7e,0xd7,0xd2,0x5c,0xf9,0x6f,0xdb,0xba,0x64,0xab,0x18,0x11,0xc8,0xbb,0x93,0x4e,0x21,0x87,0xea,0x7f,0xfc,0x01,0x8d,0x85,0xe0,0xf2,},{0x00,0xf1,0xb5,0xd3,0xca,0xc6,0xe5,0x6c,0xa5,0xf8,0x94,0xd4,0xcd,0xbf,0x9b,0xeb,0xd9,0x68,0xd2,0x4d,0x5e,0xff,0xa5,0x05,0x8b,0x0e,0x20,0xbb,0x08,0x98,0xf6,0xf1,},{0xa6,0xb5,0x6b,0x76,0x86,0xdf,0x1d,0xc5,0xf4,0xed,0x54,0x4a,0x4d,0x97,0xe6,0x70,0x36,0x19,0x5a,0x32,0xb2,0x2e,0xcd,0x5d,0x31,0xea,0x17,0x30,0xe6,0xed,0x8f,0x81,0x0d,0x25,0x8b,0x44,0xc0,0x8e,0xa4,0x5f,0x03,0x2b,0x93,0x74,0x41,0xb7,0x2c,0xd0,0xdc,0x37,0x55,0x6f,0xd7,0x87,0x4e,0x9f,0xe6,0x4f,0x15,0x76,0x5c,0x52,0x10,0x03,},"\x64\x6f\x8b\x34\x18\x2d\x5e\x60\x2b\x51\xca\x73\x29\x34\x7c\x0e\x19\x8c\xb7\x47\xe4\xda\x0a\x6b\x80\xf3\xf6\xf9\xf3\x36\xf6\x70\x8d\x85\xcb\x42\x9a\xb2\xd6\xbe\xd3\x5d\x50\x13\x12\x9c\xd1\x00\x14\x2c\xdd\xce\xe8\x63\x51\x79\x02\x1b\x3e\x24\x92\x2b\x81\xae\xf1\x3c\x13\x70\x28\x69\x39\xd6\x3d\x6b\x6a\x41\x95\xed\xa1\xd8\x12\xca\x51\x82\x04\x76\x8f\x87\x34\x8c\x68\x89\x55\x2c\x63\xd1\x37\x2c\xde\x6a\x5e\x9d\xaa\x7f\x84\x45\xec\x8d\x61\x30\xa3\xf5\xae\xf0\xed\xea\xce\x01\x0b\x6c\x7f\x0b\x9d\x24\x16\x2a\x8d\x04\x45\x4b\x81\xd4\x8e\xa9\x09\x7b\xd8\xdf\x09\x34\x59\x71\x9c\xcb\x54\xaa\x10\xf5\x1c\x24\x6a\xa9\x9c\x58\x0b\xea\xf9\xc9\xc5\xbc\x60\xfa\xf0\xae\x5c\xec\x7f\x51\x37\xf6\xc5\xc1\x44\xdf\x45\xd1\x2e\xe9\x95\xad\xcc\xf2\x5a\x9d\xb8\x1b\x85\x58\xbd\xfb\x65\x83\x01\x86\xe7\xb9\xd4\xee\xd9\xf6\xb4\xd7\x32\xb1\xb5\x82\x2d\x03\xeb\x01\x7c\x07\x24\xf4\x8f\x87\xba\xaa\xe1\x04\x5d\x6f\xdb\x12\x5c\x91\x34\x06\x4f\xaf\x18\xdb\xed\x58\xd8\xfb\xac\xea\xcd\x4f\x09\x7d\xf9\xb3\x42\xe5\xc4\xa5\xbc\x85\xb2\x95\x97\xd4\xb6\x40\xf1\x55\x1c\x5b\x62\x4a\xb2\x1b\x48\xe9\x4a\x90\x30\x04\x9b\xe1\xf0\x5a\xa8\x51\xd0\x82\x7e\xaf\x87\x00\xdf\xe1\x47\xfd\xcd\xee\xdb\xc9\x8c\x4f\x15\x77\x4f\x01\x20\xfb\x59\x70\xa2\xf8\xb2\x17\x94\x34\x0b\x62\x83\x79\xa8\x02\xb9\xf7\xc0\x68\xb0\xdf\x63\x19\x3e\x51\x0f\xc7\xb2\xaf\x97\xee\x38\xde\x47\x92\x97\x85\x53\x55\x28\xd3\x50\xd8\x86\x20\x61\x0c\xfd\xb5\x5d\x24\x9e\x38\xfb\x73\xc8\x28\x71\x13\x91\x9c\xe3\x32\x67\xd7\xdb\x92\x4e\x49\x19\xa4\x4e\x6e\x29\xa9\x0d\xbe\x3b\x7b\x0d\x39\x21\x16\x3f\xeb\x5a\xc1\x05\x62\x4e\xd8\x52\xbe\xce\x35\x38\xe9\x91\x93\x30\x0c\x89\x33\x45\x69\x93\x50\xa8\xf9\x9e\x8c\x6a\x41\x09\x5f\xc9\xfc\x08\xda\x07\xf7\x57\x11\xf7\xdf\x03\x44\x06\xde\x14\xed\xd8\xe2\x2a\x63\x3a\x86\xe4\xa5\xa5\xc9\x75\xac\x5d\x34\x89\x1c\xcc\xfc\x85\x43\x77\x1f\xfa\x08\x0e\x0b\x45\xd6\x5a\xb8\x30\xa3\x61\xac\x4c\x42\x62\x94\xd3\x68\x5e\xa8\xc2\x60\x39\xc7\x1c\x90\xfc\x3f\xb5\x12\xbe\x9f\xc9\x48\x07\xd7\x6d\xbd\xaf\x8f\xfa\xa4\xfb\xf9\x84\x9d\x68\xe8\xa5\x7d\x30\xc4\xa0\xb9\x73\x5c\x23\xf0\x8e\xf2\xe2\x84\x45\x84\x67\xe1\x5d\x66\x53\x62\xcb\x64\x6f\xde\x69\x37\xec\xba\x53\x09\x12\x64\x63\x83\x57\xa7\x22\x42\x5b\xc6\x2d\x1e\x30\xec\x5f\x0d\xd8\xfe\xa2\x6b\x2e\xa4\xa8\x49\x00\x35\xde\x43\xf2\x74\x84\x6f\xb0\xcf\x02\x09\xec\x74\x37\xf3\xc3\xd0\xa5\x60\x37\x3d\x03\x4e\x5f\xd7\x9e\x25\xb6\x42\x4d\x9b\x2c\x17\x61\x63\x2b\x35\xa1\x21\x32\x52\x18\x27\x34\x5c\x55\xe4\xe7\x14\x2d\xd6\xfe\x94\xd6\x20\xfe\x51\x5c\x15\x3e\x83\x95\xb5\xd1\x30\xc7\x44\x13\x9b\x6a\x92\xef\xd3\x7f\x22\xba\x13\xfe\x4c\x09\x53\x73\x55\x0e\x2e\x4f\xcb\xa0\x32\x5b\x3e\xa3\xb9\xfe\x25\xcc\x7d\xd9\x2c\xbf\x42\xe1\x5f\x45\x54\xb7\x7a\xc2\x7a\x4a\x34\x63\x82\xff\x61\x00\x45\x15\x08\xd6\x02\xcf\x64\x3f\x60\xb6\xca\x42\x86\x35\x6f\x21\xa3\x11\x0d\x4e\x2c\x8a\x89\x62\xa7\x80\xfc\xff\x43\x9b\x3a\xa8\x04\x99\xdf\x27\x0f\xc3\xe6\xca\xd8\x89\x33\x48\x87\x2f\x0f\x70\x2f\x93\x90\x00\x0c\x7f\x6e\x06\x27\xd2\xbb\xb7\xb7\xce\xf5\xc4\xda\x25\xda\xdf\xea\x80\x32\xe5\x02\x32\x97\xa7\x0a\x65\x8e\x9a\xe7\x3b\xdd\xc3\xb2\x27\xa1\xc1\x17\x41\x13\x3f\x01\x2f\x0f\x48\xfe\x26\x44\x6f\xa6\x7e\x64\x72\x0f\xc8\xdc\x97\xf3\x0d\x0d\xd0\x26\xf6\xdc\x21\x64\xea\xd8\x57\x82\x4a\x0a\x7a\xeb\x20\xf1\x15\xd5\x0d\x1b\x65\xdd\x5d\x82\xe0\x9a\xbe\x83\x4e\x8c\xa8\x89\x57\xe3\x99\x84\x82\x49\x55\xa1\xa1\x3e\x3b\x94\xa0\x01\x57\x18\x6d\xcd\xc2\x89\xe3\x4b\x67\x8c\x91\xcb\x2a\x1a"}, -{{0x06,0x3b,0x90,0x25,0xe3,0x21,0xe9,0x72,0xd6,0x53,0xa0,0x62,0xbe,0x34,0xf9,0x93,0x65,0xaf,0xfd,0xcc,0x98,0xec,0x9f,0xf4,0x3e,0xf4,0x22,0xbe,0x0f,0x80,0x44,0x60,},{0x10,0xd0,0x1a,0x63,0x01,0x2a,0xc0,0x99,0x56,0xba,0x9e,0xd6,0x1d,0xf3,0x5b,0xb7,0xaf,0xe3,0x65,0x8b,0xb3,0x00,0x48,0x52,0xe4,0x71,0x74,0xbd,0x07,0xdd,0x4d,0xe7,},{0x85,0xc8,0x1d,0x6b,0x0d,0x85,0x78,0xfa,0x58,0xe1,0x3a,0xb3,0x91,0x00,0x15,0x28,0xb4,0x6a,0x1d,0x63,0xa0,0x32,0x7c,0x7a,0x4a,0x04,0x08,0x7f,0xc6,0x68,0x75,0x8a,0xa6,0x5c,0x01,0xd5,0xa1,0x50,0xf9,0x35,0x67,0x4e,0xf3,0x07,0x50,0x7e,0x6f,0x4c,0x91,0xe1,0xfc,0x35,0x00,0xb2,0x6f,0x64,0x9b,0xee,0xa8,0x7d,0x27,0x56,0x37,0x04,},"\xa7\xee\xd2\x96\x52\x84\x4e\xe0\x04\x9b\xaf\xb2\xcf\x63\x40\x29\x71\x02\x0d\x7e\x65\xc1\x0b\x91\xac\x57\x26\xee\xa8\x6f\x40\xdb\xc5\x3c\x3f\x0a\xbe\xde\xba\xf6\xcc\x44\x9b\x4f\xea\x48\xc0\x15\xfe\x4d\x90\x7b\x3e\x55\x05\xcf\xf5\x0a\x12\x18\x19\xa2\xe4\xa8\xa2\x96\xd5\x75\x10\x15\xbb\xcd\x7e\xf6\xfb\x7c\x27\x27\xbb\x00\x0b\xe1\x34\x2a\x7d\x14\xbc\xa9\x79\x04\xed\xfe\x8b\x18\xdd\xb6\x39\x33\x41\x83\x27\xa5\xaf\x81\x7e\x95\xba\xd7\x4e\xb7\x90\x20\x36\x15\xd0\x82\xe7\x14\x93\xea\xd4\x7c\xcc\x09\x01\xa2\xca\x9f\x50\x13\x3c\x44\xef\x85\x08\xd5\x1f\xb7\x3c\x61\x6f\x01\x47\x53\x22\x45\x82\x2d\xd1\x02\xb3\x37\xa1\xb2\xaa\xe2\xef\xc7\x2d\xca\x7a\x94\x19\xd5\x98\xa6\x47\x52\x33\xdc\x1a\x4e\xe0\xec\x6d\x05\xda\x12\xa2\xb2\x87\xcb\x77\xff\xaf\xdd\xe2\xd0\xac\xc2\x81\x99\x93\x3e\x66\x21\xee\xc1\x6a\xb4\x24\x51\x70\xcf\x02\xda\x80\xd4\x92\x26\x31\xa2\x32\x72\x91\x51\x65\xad\x88\x72\x27\x50\x03\x5d\x2a\x09\x77\xbc\x79\x1d\x14\xfb\x3d\x8c\xb0\x2b\xc7\x7f\x7c\x71\xbe\x52\x42\x62\x9a\x4c\x9a\x58\x8d\xfd\xde\x95\x78\x49\x4d\x8b\xaa\x4e\x68\xf5\x19\x4b\x80\x02\xc8\xe3\x78\xa0\xe8\x33\xb7\xc1\xa9\x69\x81\xc4\xfb\x05\xe4\x57\xff\x48\x26\x0b\x72\x49\x3c\xbc\xb8\x2a\xe1\x16\x73\xd1\x4c\xee\x85\x28\x8f\x63\x70\xbd\x4b\xca\x92\x51\xa7\xe2\x14\xc3\xeb\x79\xe7\xbb\x6f\xce\xbb\x16\xc9\xe0\x56\xf2\x9b\x62\x72\x74\x3e\xfa\x6f\xe8\xbf\xd2\x55\x97\xce\x86\x89\x8a\xb3\x05\x9e\xb0\x23\x1c\x73\xb5\x30\x59\x03\xfd\x13\x19\xbd\xf4\x9e\x59\x9d\x8b\xbc\xd7\x4a\x8b\x97\x67\x30\x8b\x61\x56\x3c\xcb\xac\xd3\x8f\xc5\x0c\x83\xab\x44\xca\x75\x9d\xc9\xb6\x5b\x2a\x4b\x54\x7c\x50\x97\xf2\x20\xc1\xc8\x8b\x2b\x0a\x48\xf6\x5f\x91\xfe\x78\xb1\x50\x12\x78\xe1\xe3\x04\xde\x58\xb4\xc8\x2a\x5c\x39\x99\x81\x09\x8a\x17\x84\xeb\x90\x42\x50\x18\x59\xf2\xa9\x3f\x31\x7e\x41\x77\x2f\xd5\x2f\x97\x2e\x51\xb0\x7e\xd9\x4d\x31\x4e\x1d\x1a\xf4\xed\x82\x90\x9a\x0b\xef\x67\x1f\x54\xb5\x5d\xb7\xb7\x0d\xa1\xf7\x18\xc8\xe6\x48\xae\xdd\x6d\xa6\x4b\x05\x77\x05\x26\xf1\x2b\xc4\x3f\x68\xb9\x55\x48\xda\xc5\x08\x09\xa6\x87\xdb\x97\xd7\x3f\x06\xf4\x7e\xd0\x88\x31\xb6\x0a\x28\xe9\x82\x92\x06\x32\x05\x8f\x0e\x6c\x90\xc0\x18\x7f\xf4\x45\x64\xf8\x1e\xfd\x8f\xd9\x3e\x32\x7b\xc6\xd8\x0b\x49\x0e\x08\x8b\x9a\x10\x03\x6c\x80\xdc\xda\xd4\x9d\x2b\xe0\x74\xfb\xba\x31\xe0\x6f\x71\x80\xe5\xad\x1c\x88\x23\xd6\x09\x66\xa9\xce\x15\x50\x3c\xe6\x0d\xd4\x0e\x91\xee\xf2\x35\x9d\x83\xd7\x0d\x98\x40\x1d\xde\x7b\xe3\xc6\xb0\x7e\x57\xd4\xe4\x7d\x04\x21\x76\x33\xd8\xe2\x63\xca\x34\x8f\x81\xfb\xe9\xa4\xa6\x2f\x45\xd7\x7c\x84\x3b\x6b\x1a\xd2\x84\x66\xd9\xda\xfb\x1b\x91\x0b\x34\x8e\xd8\x7c\x68\x6c\xab\x29\x2d\x48\x0c\x19\x1d\x18\x7b\x40\x4a\x9b\x1d\x13\x2b\xa4\xe2\x93\xd3\xad\xa9\x91\x72\xac\xc1\x21\xfe\x66\xb8\x45\xb9\x8b\x16\x0c\x58\x23\xf6\x01\xc7\x75\x8f\xb2\x6c\xae\xe8\x57\x01\x59\x5b\x2d\x52\xca\xa2\xf5\x68\x8a\xa2\xbf\x2f\x6c\x4b\xb6\x37\xf8\xe0\x0f\x49\xab\x6c\x26\xbc\x6a\xd8\x9e\x13\x67\xfd\x28\xe4\x91\x7d\x25\x08\x93\xa7\xb3\x2d\x39\x66\x0b\xde\x8d\xb4\x9f\x08\x6f\xb7\x39\xe5\x60\x12\xc3\x6b\xea\x0b\x26\xcf\x6d\x93\x57\x94\x0b\x00\xd5\xa4\x52\x8f\x90\x59\xaa\xf0\x86\x69\xe5\xf4\x6c\x99\x5e\x60\xf8\x87\xb5\xc4\xab\x88\xac\x74\x42\xed\x01\xa1\x4c\x6a\x42\x00\x6b\xaf\x1f\x34\x3f\xef\xe3\xe4\xac\xa8\x43\xa3\x24\xe1\x76\xb2\xfe\x7e\xc7\x88\x3d\x1c\xbd\x06\x8b\xc2\xfc\x96\x2f\xfa\x60\x24\x4f\x65\x4c\x77\xac\x56\x50\x81\x7d\xc0\x84\x46\x55\x45\xa9\x23\x0a\x74\x82\x6b\x0c\x50\xeb\x85\x25\x2a\x88\x6f\xf2\xb1\xaf\xea\xf8"}, -{{0x88,0x3c,0xc1,0x38,0x17,0x57,0xb0,0xfe,0x04,0x55,0xb7,0x7b,0xc9,0xcd,0x0d,0xd4,0x64,0xd2,0xb4,0xbf,0x0c,0x7a,0x3c,0x0c,0x2d,0xc7,0x75,0xfb,0x78,0xaa,0x37,0x32,},{0x83,0xa8,0xb6,0x69,0xcc,0xd0,0x12,0x45,0xce,0x3b,0x81,0x8d,0xcb,0x1b,0x58,0x8f,0x86,0x53,0x58,0x50,0xe6,0xc7,0x10,0xc7,0x92,0x17,0xfe,0x43,0x98,0x24,0xf3,0xfa,},{0xc7,0xcf,0xd5,0xc9,0xfe,0x93,0x0d,0x15,0xa1,0x1e,0xbb,0x34,0xe3,0x43,0x1f,0x48,0x9d,0xa0,0x10,0xeb,0x19,0x3e,0xdb,0xfa,0x6f,0x23,0xd5,0xd1,0x4d,0xd8,0xfe,0xab,0xd7,0x88,0x0d,0x2d,0x5a,0x56,0x00,0xd3,0x85,0x46,0xce,0x3b,0xc6,0x4a,0x86,0x29,0x1a,0x1c,0xe3,0x1f,0x27,0x2f,0xf0,0x20,0xdf,0x8c,0xb6,0xa0,0xfd,0x4d,0x3a,0x0d,},"\xff\xec\x29\x3d\x12\xea\x63\x6c\xa4\xc4\xa0\xa5\xe2\xdb\x15\x34\x26\x39\xc4\x76\x67\x4d\x2e\xbd\xab\x4a\xef\xd4\x04\x6b\x5d\xdb\x56\xae\xb2\x10\xc1\x19\xaf\xdf\xb8\xa8\x91\x28\xa3\x4f\x6d\x77\xf2\x61\xed\xea\x07\x72\xa2\xf8\xdb\x14\x0a\x26\x40\xfd\x8e\xca\xdb\x0b\x47\x92\x16\x9b\x6b\x28\x10\xae\xe2\xc5\xcd\x83\x52\x88\xbf\xf4\x93\xbc\xeb\xee\xea\x28\xa7\xa2\x48\xc3\x61\x16\x54\x0f\xa7\x17\x36\xd6\x6b\x0a\x47\x5b\x5f\xa9\x2c\x0d\x46\x00\x2f\xca\x7a\x1e\x69\xd1\xb5\x9e\x81\xa3\xa6\xd4\xf3\x39\x76\x9d\xae\xb2\x0b\x5f\x9d\x75\xc4\xc2\x8f\x69\x21\x32\xd2\x8d\x3c\x56\x4c\x09\xfe\x3d\xcc\xa0\x35\x9c\x3c\x63\xec\x37\x7a\x33\xf9\xee\x87\x4d\x8a\x78\x9d\x77\xc9\x6a\xc0\x5f\xdf\x3a\xb3\x8b\x2c\x82\x74\xa9\x02\xef\x8b\xb7\xf4\x67\xfc\x7e\x07\x3c\x77\xb1\xdb\x5f\xc8\xef\x96\x6c\x12\x0c\x4d\xae\x3f\xb7\xf5\xb7\x4a\xbb\x99\x01\x66\xc8\x12\xa5\x25\xd1\x23\xf7\x6e\xd5\x12\x12\x50\x80\xa1\x53\x4f\x3d\x8b\xdc\xcc\x54\x1f\xc9\x75\x90\x28\x75\x46\x09\x6f\xc8\x80\xbf\xcf\xdd\x00\xe6\x5c\x0e\xbf\x4a\x09\xfd\x64\x76\xce\x1b\x7c\x8f\xaa\xa5\xa1\xcc\x27\x86\x71\x9a\x30\xd8\x25\x58\x11\x18\x47\x52\xa8\x8b\x08\xac\x9f\x0f\xf1\xd6\x26\x2f\x25\x86\x94\x0a\xfe\x1f\xe4\x5e\x0b\x56\x34\x48\xa5\x5f\x30\x30\xe4\xc3\x9c\x1f\x3f\x86\xa7\x33\x67\x03\x80\xea\xb0\x88\xe3\x93\xde\x09\xd1\xf5\x08\xd2\xfb\xca\xfc\x64\x9a\xea\xe6\xb8\xc3\x0e\x32\x9e\xc3\xfd\x28\x29\xbe\x6d\xb0\xab\x8e\x63\x7e\xa1\x09\x5b\xdc\x3d\xf3\xac\xc2\x3d\x3c\xf7\x05\xa9\x54\x2c\x19\xe5\x90\x92\xec\x41\x3a\x4e\x2b\xd5\xde\xd2\x8c\xd3\x4d\xdb\x3d\x32\x94\x9a\xa4\x87\xf1\xc3\x37\xd6\x97\x9c\xf5\x12\x62\x2d\xbf\xb7\xda\x1c\xbb\x1c\x7e\x5a\xbe\xea\x70\x09\xe2\x94\x3f\xfb\xa2\x25\x2e\x1d\x86\xec\xa9\xd6\xd5\xc2\x46\xcd\x2e\x13\x4a\x3e\x5d\xad\x37\xef\xef\x71\xce\x39\x7a\xda\xfb\xd9\xe7\x2b\x3f\x9a\x86\xff\x0f\x5d\x81\x2c\x46\x22\x5b\xeb\xd0\x70\x3b\xc5\xcc\xe9\xc6\x45\x82\x00\x8f\x7e\x55\x8c\x40\xa3\xb3\x52\x20\x96\xd1\xaa\x2b\x61\xbc\x90\xcd\x88\xc6\x28\x5d\x94\x20\x87\xd8\xa4\x66\x5a\x0e\x64\xd3\x57\x2f\x74\x68\x9b\x4f\x24\xef\x40\x0d\x74\x1b\x57\x14\x06\x13\x47\x14\x44\xde\xcc\x65\x4a\xf0\xff\xb2\xed\xfd\xf9\xfd\xd0\x75\x09\x81\x90\xb3\x4c\xde\x28\xdd\x16\x68\x72\xc6\x08\x65\x67\xa6\x87\x61\xce\xf2\x5d\xa4\x0b\xd4\xc3\xd3\x4f\xdd\xd7\x2e\xe5\x65\xb0\xb9\x37\x67\x8e\xe8\x43\x49\xd1\x16\x0f\x5f\x07\x05\xf8\x95\xd0\xf1\x41\xce\x8f\x51\xa1\xe4\xfd\x2d\xc4\x70\x4b\x52\x7a\x40\x25\xa9\x39\xcb\x2b\xb7\x88\x57\xeb\x18\xd7\x88\x72\xed\xc9\xee\x70\xe6\x0b\x2a\x42\x70\x0a\x19\x8f\x4f\xff\x6c\x31\x92\x51\x68\xbe\x07\x7d\xc2\x3c\x32\x2a\xbb\xca\x97\x36\x1f\xec\xaa\x3f\xcb\x19\x6e\x65\x6c\x12\x8f\x39\x82\xfe\x11\xe5\x51\xa4\xa0\x88\x5d\xa6\x0d\x39\x7d\x0e\x40\xd0\xd8\x97\x26\x2f\x1b\x4b\x67\x2f\x78\xa2\xd2\xad\xfc\xdd\x6e\x15\x25\xc2\x6e\x71\x95\xfb\x9a\xc6\x06\xbb\x1b\xa4\xa9\x89\x08\x03\xb4\xbd\x84\x34\x6a\xe8\xd8\xc7\x19\x6c\x90\xae\xcc\xb2\x96\xa4\xc3\xeb\x4e\xfa\xcb\xfc\xb6\x2e\x38\x3b\x8a\x49\x4a\xc7\x23\x56\x2d\x0d\x8c\x37\x91\x87\xa9\x2e\x3b\xda\x6b\x15\x69\x47\x6a\xed\x21\xae\xd7\xa0\x56\xb4\xa5\x82\x67\x44\x01\x7c\xc0\x06\x0b\x4d\x55\xfa\x87\x72\xb5\xb1\xc1\x5f\x57\x48\xad\x72\x98\x00\x5a\xec\xbc\xbd\x90\xa3\xe5\xc6\x15\x9a\x86\x74\xab\xbb\xa3\x79\x14\x41\x50\x02\xb5\xa6\xef\x5d\xf3\xc6\x49\x42\x6e\xa1\x27\x5a\x01\xd8\x0a\xdf\x49\x0a\xc5\x46\x06\x2d\x93\x99\x9a\x6d\xcc\xac\xb9\x6a\x09\x04\xad\x33\xd9\x05\x76\xdc\x6a\x21\xb6\x72\xe8\xff\xb0\x66\x13\xfb\x3f\x14\xe6\xcb\xdd\xe8\x8c\x24\x37\xc9"}, -{{0x5e,0x40,0xa7,0xaa,0xbb,0xb0,0x83,0x0a,0x9a,0xb0,0xfd,0x79,0x69,0x0e,0xe0,0x43,0x39,0x01,0xc6,0xcb,0x06,0x76,0xab,0xe4,0xbb,0xa0,0x6f,0x5b,0xbe,0x58,0xfa,0xc2,},{0x4d,0x4f,0x28,0xfe,0x09,0xc4,0xaa,0xbf,0xca,0x01,0xef,0x6e,0xe7,0xfd,0x63,0x72,0xfb,0x62,0xdb,0x61,0xaa,0xee,0x82,0x7c,0x43,0xfd,0x1a,0x6d,0x1c,0x25,0x90,0x32,},{0x59,0x76,0x72,0xab,0x8d,0x3a,0x60,0xde,0x54,0x56,0xfc,0xc9,0xc3,0x82,0x53,0xf5,0xf3,0x7b,0x80,0xe7,0x4a,0x00,0x7c,0x9f,0x6d,0xb9,0x09,0xd2,0x7d,0x0e,0xad,0x16,0x27,0x89,0x24,0x49,0x94,0xf3,0x5b,0x80,0xd6,0x1b,0xe1,0x99,0xc4,0x17,0xc7,0xea,0x90,0x1b,0x98,0xcc,0x63,0xfe,0x3c,0x50,0xfc,0x3c,0x63,0x38,0x49,0x0f,0xa2,0x06,},"\xfd\x4e\xc8\xb3\x4f\xc6\xb7\x43\x81\x3f\x59\xe2\xfd\x1f\xef\xa8\x70\xf5\xa9\x70\xe2\xeb\x75\x16\xef\x7c\x30\x6f\x4b\x82\x3f\xfe\xe9\x2d\x60\x1f\x76\x5d\x79\xca\x14\x6a\xba\x8b\xc6\xe7\x98\x44\x55\x99\x35\xcd\xdc\x24\x26\x49\xc0\x59\xec\xf2\xdb\x84\xfd\xc2\x19\x36\x66\x88\xa8\x8f\xc2\x5b\x85\x1c\x36\x61\xe5\x19\x88\xc2\xbf\x73\xbb\x8e\x3d\xc1\x6d\x22\x41\x5a\xb1\xa7\xb3\x55\x79\xda\xac\x73\x25\xe3\x19\x15\x7d\x7d\xa5\xfe\xe8\x7c\x93\xa4\xdf\xcb\xaf\xc9\x2f\xba\x7e\x17\xcc\x68\xe3\x90\x37\x33\xc6\xc8\x01\x57\x2d\x90\x73\x20\xb2\xfe\xb5\x17\x10\xe8\x56\xa1\xf7\x6f\x85\xa7\xee\x1a\x11\xe6\x2d\x2e\x45\xa3\x52\x93\x8d\xd8\xcf\xc2\xbc\xcb\x90\x2d\xea\x44\x4f\xaa\xae\x6d\x84\xc5\xf3\x91\xe1\x0a\xef\x76\x92\x8a\x45\x15\x3d\xb6\xcd\x25\xa2\xbf\x35\x3d\x80\xd9\x7b\xf4\xb3\x80\x86\x05\xe8\x98\x00\xd2\x98\x40\xea\x60\x97\x8d\x9e\xc9\xb2\xc3\x02\x74\x98\x88\xf9\xde\xbc\x84\xdd\x1e\x2a\x79\xaa\x0b\x6b\xa0\x2a\x03\x91\x93\x08\x1b\xdb\xff\x05\x99\xa1\x4d\x91\x8c\x0c\x8d\xea\xc4\xf6\x0b\x6e\x99\x47\x4a\xb5\x30\x11\x74\x10\x34\xfe\x2a\x20\xcf\xf4\xe0\xf0\x23\x42\x4c\x8e\x57\x97\x76\x8a\xd5\x3d\xf6\xd0\x1a\x24\x01\x1f\xa9\x0f\x0b\xb1\xd5\x06\x9c\xdb\x36\xb4\x50\xf4\x33\x11\x0c\x2c\x56\xf3\x4a\x1d\xe4\x26\x09\x14\xcd\x46\x96\xb1\x4a\x09\xc0\x26\x8b\x2a\xe2\xe9\x8e\x6b\x4e\x99\x2b\x91\x25\xf8\x78\xf1\xac\x09\x82\x31\x70\x62\x83\x88\xf0\xf6\xe2\x56\x25\x9c\xa7\x86\xbb\xe1\x44\x88\x4c\xb2\x98\xcc\x04\x3d\x02\xf5\xc3\xdc\x68\x4f\x78\x7f\xaf\x16\xc1\x0f\xdd\x84\x37\xa8\xc3\x09\x74\x63\xbd\xb9\x9b\x78\x03\x0f\x94\x74\xfc\x5c\x99\x51\xdc\x75\x26\x49\x05\x86\xfe\x1c\x2d\xb0\x54\x11\x34\x14\x60\x23\x9d\x5e\x8b\xc5\x30\x65\x90\x2b\x95\xfb\xa2\x82\xc2\x76\x65\xe8\x69\xa1\x9d\xae\x84\x60\x6d\x17\x26\x67\x51\x55\xd3\x80\x39\xb9\xe5\x5d\xb4\xd5\xce\xec\x95\xcd\x6d\x87\xf8\x5e\x99\xdd\xe5\x4a\x04\x76\x1e\x6e\xad\xa6\x61\x9d\xa8\x95\xb6\x54\xfe\x38\x45\xe8\xa6\x0f\x3a\x3b\x32\x48\x3d\x6d\x27\x97\x8a\xf5\x45\x02\xb2\x20\xe4\x78\xdb\x78\xcf\xf7\x7a\x9c\x97\xfb\x79\xfb\x5a\xcf\x56\x28\x9f\x38\x1a\xcb\x10\xde\x64\xc3\xf2\x38\x42\xb1\x2b\xf5\xf1\xb2\x83\xbd\x25\xd4\x8d\x09\x12\x8f\xb5\x5d\xda\xe2\x55\xbe\xb7\xc6\x6a\x74\xcf\x6f\x06\x95\xa4\xf8\x28\xcb\x29\xe4\xaf\xdb\xb3\xb4\x2a\x23\x5d\x4f\xdb\x66\xb9\x63\xac\x8f\x68\xe8\x2b\x00\xa1\xc4\x50\x08\x63\x29\x62\x47\x17\x8c\xfd\xef\x80\x3b\xb7\xb1\x14\xf0\xc0\x32\x76\xf6\x71\x66\x9a\x08\x7d\x92\x28\xa3\x7a\xe7\xb9\x9b\x06\x15\x49\xc1\xcf\x8e\xc1\x72\x46\xea\x1e\xe0\x3d\xbc\x88\xbf\x42\x64\x16\xd5\x86\x57\x2f\xf1\x0a\x31\x45\x60\x6f\x27\x84\xe4\x35\x7b\xe4\xed\xee\xc6\xc3\xa7\xbf\x11\xbb\x5b\x0e\x90\xcf\x50\xed\xaf\x89\x1e\x51\xd2\x63\x57\xbf\xc8\x53\xce\x23\xb2\x99\x15\x5c\x82\xc1\x03\x1d\xfa\x64\x07\x4d\x72\xa0\x9d\x29\x72\x0e\xad\x6e\xbb\xbf\x75\xd5\x73\x8e\x32\xcd\xa6\xb6\x46\x6a\x8d\xef\x6b\x50\xa1\xed\x9b\x86\x5a\x9a\x88\xa0\x80\x18\xac\xb5\x01\xa4\xde\x9d\xb5\x4d\x05\x22\xce\x9c\xec\x7a\x06\xbd\x9a\x5f\x86\xb0\xb4\x6c\x07\xbf\x3e\x7f\x5a\x42\x6f\xf6\xb4\xbb\xe1\xe0\x03\x13\xa5\xac\x27\x19\xa9\x59\xed\x44\xee\x0a\x44\xbd\x97\xda\x6d\xb2\xcb\x97\x1b\xd6\x83\x34\x90\x89\x49\xed\x85\x0f\xbf\x73\xd0\xe0\x20\x49\xda\x18\x1c\xce\x9c\x2d\x9c\xa1\xb6\x24\xc8\xd8\x7c\xf9\x04\xeb\x82\x1d\xc7\x95\x92\x95\xda\x57\x77\x92\x06\x60\xb4\x3c\xcc\x25\xcd\x38\x9f\x15\x7f\x67\xfa\x03\x90\xfe\xac\x97\xa7\x52\xc1\xac\x20\x4c\x21\xdf\x56\xbb\x0f\x4f\xc0\x16\x41\xb4\x80\xaf\x2b\x89\xb5\xd1\x6d\x4a\x0b\xcb\x0a\x50\xb8\x2b\x0e\x04\x84"}, -{{0x3a,0x34,0x13,0x6a,0x97,0x34,0x80,0xd9,0x70,0x06,0xdc,0x27,0x93,0x58,0xe6,0x60,0x62,0x93,0xd8,0xcb,0xc1,0xa4,0x4e,0xe5,0x52,0x33,0xaf,0x2b,0x52,0x64,0xb9,0x0c,},{0xe5,0xef,0xfd,0x92,0x1b,0xe8,0xee,0xc5,0x30,0x75,0x2f,0xcc,0xc5,0x76,0xef,0x0d,0x9b,0xcd,0xe4,0xb3,0x2c,0xc6,0x49,0xd3,0xf7,0x95,0x47,0x17,0x56,0x28,0x60,0xcc,},{0x42,0x5f,0x27,0x22,0x12,0x83,0x57,0x55,0xad,0xcc,0x05,0x22,0xc6,0xf6,0xe0,0x5f,0x68,0x00,0x8a,0x3b,0xe9,0xba,0x59,0x74,0xe4,0x20,0xc4,0xc5,0xcb,0x56,0xe6,0xc5,0x5d,0xec,0x0d,0xe3,0x47,0xb1,0x6c,0xae,0xf8,0xbd,0x33,0xb7,0x1b,0x44,0xc8,0x35,0x7d,0x05,0xb6,0x32,0x1d,0x7b,0xf4,0x93,0xd2,0x58,0x61,0xdb,0x48,0x7b,0xd6,0x03,},"\x98\x1c\x8e\x10\x90\xe3\x96\x95\x1b\x07\x2e\xf8\x49\x70\x62\x02\x08\x97\xbf\x7d\xd7\xad\x50\x5b\x4d\x6d\xc1\x1b\x3e\x1d\xbc\xb0\xda\x24\x99\x84\xa1\x40\xe1\x64\xfc\x2e\x02\xb3\x1d\xa3\x98\x46\x55\x4a\xa8\x90\x5b\xc8\xb3\xdf\x8a\x76\xbf\x60\xeb\x5f\xfc\xf2\x2c\x97\xb6\x71\x22\x7d\x24\x90\x71\xda\x8f\xf6\xbb\xa7\x5b\x2f\x76\x68\xce\xc1\x9a\x89\xe6\x47\x5a\x12\x46\x3d\xab\xf3\x68\xb3\xca\x24\x45\xbb\x30\x35\xcc\x00\xfa\xe8\x5b\x70\x72\xfb\xcf\x59\x54\x01\x75\x5b\x80\x51\xe6\x09\x70\x65\xae\x42\x9f\x18\xee\xb1\x3f\xfa\x6d\xde\x59\xdf\x6f\x3c\x20\x6b\xfd\x9c\xe1\xf8\xa8\x00\xc8\x59\x0a\x40\x21\xd1\x60\xf6\x6d\x67\x40\xa3\x69\xae\x83\x56\x17\x53\x8b\x58\x90\x23\x1f\x13\xc5\x66\x7b\xaf\x51\x0a\x60\x6b\xda\xa8\x4b\x8d\x10\xee\x60\x15\xe1\x2a\x4c\x1e\xc0\xbd\x04\x21\xa2\x94\xc5\x1c\xf6\x3b\x5d\x1f\x05\x8e\x11\x53\xdc\x42\x5d\x10\xce\xe8\xb1\xb0\x84\xd6\xc2\x93\x47\xe9\x6f\x0f\x31\xb8\x39\x60\x7d\x07\x8b\x79\xa9\x0c\xa3\xd1\xf0\x63\x80\x7a\x46\x3b\x7c\x32\xf4\x5a\x53\x44\x98\xd7\x1d\x47\xed\xc3\xb1\x7a\x4d\xff\x27\xfe\xdc\xff\xab\x30\x1f\x34\xf1\xa6\x4c\x02\x78\xa5\x35\x89\x34\x9a\x23\x3a\xf3\x0b\x1e\xc1\xae\x41\x0f\x7b\x16\x30\xc7\x14\x5c\xa4\x2c\x96\x63\xf5\x12\xe8\xa5\x78\x26\x7d\xc9\x5e\x83\x28\x9c\x17\x03\x2e\x09\x78\x2e\x2f\xe8\xe1\x6e\xfb\x87\xf0\x3c\xa0\x3b\x11\x95\x61\x4f\x89\x96\x1c\xa3\x93\x9d\x3b\xdf\x73\x72\x21\xa2\x2d\x7a\x18\xec\x30\xfc\x12\x6d\x0c\xa6\x63\xe8\x8d\x60\x60\xd0\x4c\x6a\x44\xe5\x61\x6e\x55\x6e\x07\xd6\xd4\xa8\x47\xf1\x71\x1c\xf4\x37\x17\x81\x0c\x70\xaa\x4b\xe7\x30\x27\x8b\x3b\xd6\x55\x5c\x95\x4d\xc6\xed\xb0\x9d\xb0\x8f\x0e\x21\x18\x03\x59\x62\x80\xf3\xc7\x86\x8d\x23\x42\xcc\x23\x08\xea\xae\x4d\xa1\x91\x35\x14\x66\x4b\x1d\xb9\x62\xe9\x9c\x8a\x8c\xff\xe5\x79\x31\xf5\xdf\xcd\xdb\xc1\xcb\xb3\x6c\xe1\xc8\x42\xe2\xdd\xde\xad\xfd\x7e\x7d\x0a\x50\x48\xcd\xcb\x96\x1b\x14\xf3\x5f\x43\x5e\x73\xa6\x83\xc8\xce\x25\xc8\x16\x81\x25\x66\xfd\xf8\x17\xe0\xd3\x36\xae\x0b\xd2\x47\x32\x85\x12\xb2\xa8\x56\x76\x32\xbf\x20\x55\x3d\x9b\xd6\xfe\x15\x7f\x22\x0f\xfb\x0b\x46\xeb\xae\x89\xa7\x04\x59\x72\x8a\x57\xee\xd1\x79\x62\x56\xf1\xbd\x50\xb6\xd5\x47\xea\x3e\x25\xfa\x59\x13\xd3\x89\xa2\x25\x83\xe9\x15\xeb\x49\xde\x35\xa9\x7b\x5a\xcc\x52\x1d\xb0\xd0\x05\xc2\x95\x75\xe1\x66\x11\xa7\x55\xf2\x1a\x3a\x5a\x82\xa2\x0a\xa9\x00\xa7\x07\xce\x36\x82\x54\x92\xc3\xca\x15\x39\x5f\x17\x00\xb4\xaf\xab\x94\xda\xa7\xa0\x2f\x14\x53\xb1\xf9\xa6\xbd\x36\xef\xb2\x04\xd9\x28\xee\x1f\x4d\xcc\x86\x0f\x3a\x85\x9b\xad\xc0\x06\xfb\x30\x5f\xa1\x23\xd4\xc7\x9b\x23\xa2\x0e\x32\x29\x5d\x04\x0a\x7f\x8f\x6c\xac\xa2\x5d\x83\xf7\x1c\x62\xe3\xaf\x78\x36\xef\x76\xb9\x3a\x83\xd3\xc3\xb4\x93\xaf\x14\x17\x53\xda\x19\xe4\xcd\xcb\xa5\x66\x17\x27\x10\x34\xb4\xf4\xf3\x94\xc7\xc6\xb7\xd7\x96\x66\xf3\xaf\xb6\x92\x24\x4f\x06\x1c\x69\xa8\x88\x1d\x1b\x52\xb8\x84\x9f\xb5\x34\x99\x0a\xc2\x39\x19\x09\x47\x1e\xbb\xb7\x28\xe2\x9c\xd2\x0f\x42\x23\x54\xc4\x30\x97\x17\xeb\xff\x3e\xfd\x18\x33\x37\x08\x06\xd5\xbf\xb5\x3c\xa2\xda\x31\x6d\xac\xb5\x0a\xb7\xfb\x73\x96\x73\x23\x5a\x1d\xc5\x3a\xa8\x89\x30\x72\xd5\xb9\x1c\x9f\x6d\xb8\x3f\xc4\xea\x41\xd1\xee\xf4\x9a\xc2\x8a\xfc\x1c\xed\x8f\x36\x18\x90\xab\x9f\x77\x9d\x19\x30\x82\x83\x1c\xb8\xc4\x2f\xb2\x79\x2b\xee\x3b\x26\x29\x6b\x62\x95\xeb\x78\xa8\xd8\x53\x11\x76\x61\x62\x4e\x11\xf7\xf5\x7a\xfd\x60\x85\xa7\xb9\x12\x36\x79\xfd\xac\xa1\xcf\x2a\x78\xd3\x80\xbc\x4c\x36\x0a\xa7\xc3\xcb\xfd\xe0\xc0\x09\x1f\xe5\x3e\x22\x19\xc0\x70\xf2\xf0\x2f\x14\x83"}, -{{0xcf,0x33,0xe7,0x97,0x4d,0x8f,0x0b,0xf8,0x99,0xac,0x5b,0x83,0x4c,0x7c,0xf9,0x64,0x79,0xce,0x1c,0xfd,0x45,0x3a,0xf0,0x7f,0x97,0x05,0x27,0xf3,0x6a,0xa8,0x5c,0x1f,},{0x57,0x8f,0x60,0x33,0x8b,0x1f,0x04,0x1a,0x97,0xd3,0x19,0xfe,0xcf,0xa3,0x0c,0xfa,0xed,0x36,0x93,0x03,0xcc,0x00,0xb3,0xec,0x8c,0x5c,0x99,0x04,0x11,0x58,0xe2,0x0c,},{0x97,0xa5,0xb6,0xd2,0x68,0xa5,0xb4,0x17,0x5f,0xb0,0x6f,0x1f,0x37,0xd0,0xa6,0x33,0x51,0x92,0x96,0xed,0xc3,0x00,0x11,0xc9,0x54,0xd8,0xf0,0xb9,0xbb,0xe2,0x64,0x18,0x00,0x39,0x6c,0x4b,0x35,0xd4,0xb0,0xd7,0xd2,0xa1,0xd1,0x7c,0xbb,0xeb,0xdc,0x55,0xa8,0x09,0x46,0x2d,0x6c,0xc1,0x9a,0x6f,0xad,0xbe,0x1b,0xd1,0xba,0xe8,0x8a,0x01,},"\xe8\x13\x14\x4b\xd1\x16\xf6\xac\x36\x38\x92\x17\xb5\x17\x1a\x90\x2f\x06\xb7\xdd\x7b\x14\x4d\xf4\xf9\x09\x15\x53\xc7\xc7\x83\x57\x53\xa2\x96\xcb\xb0\xd7\xfa\xb9\x9c\xef\x77\xb6\x1f\x34\xa0\x4c\x8a\xf0\x4e\x7d\x5d\x1f\x96\x13\x02\xde\x89\xe2\x00\x5f\x29\x9f\x5a\x4a\xa1\x79\x24\x61\x7d\x00\x66\x93\x93\x77\x45\x53\x9c\x30\x48\xee\x36\xb8\xc2\x3a\xfe\xc0\xaf\x9f\xea\xa0\x06\x6c\x8a\xf8\xe0\xa7\xf0\x90\x93\x49\x82\x10\xf6\xd8\xdc\xc0\xaa\xad\xa5\x66\x87\x86\x91\x0f\xf7\xc5\xb3\x48\xd4\xcc\xd6\xee\xef\xfa\x3a\xcd\x18\x16\xd9\x01\x1a\x4c\x40\x25\xf6\xc2\xfd\x2c\x02\x0a\x10\x59\x36\x27\x52\x0d\x4d\xd9\x9e\x07\xc6\x2d\x2d\xbe\xbe\x84\x13\x9e\x1c\x7d\x86\x7c\x09\x35\x74\xfa\x60\x1e\x4e\xe3\x07\xac\x92\x6e\x5d\x36\xb6\x2d\x7e\xd8\x4a\x26\x15\x88\xb7\xe2\x88\x3c\x79\x26\x61\x2b\x4c\xc6\x7e\x2b\xb7\x25\x44\xa1\x0d\x6b\x49\x29\xc8\x8e\xf6\xc4\x7c\x26\x25\xd2\xf6\x81\x6b\xd7\x3c\x3b\xae\x89\xd2\xe0\xc8\x61\x71\xac\x4b\xd0\x80\xae\x55\x5d\x62\x74\x0d\x1d\x2a\x76\x1c\xed\x86\xdf\xc3\x28\xec\xc2\x7e\xe3\xdb\x6d\x40\x41\x08\xef\x4e\x0b\x64\x90\x62\x53\xb4\xc0\xa7\x71\xad\xef\xed\xc8\xa2\xc5\xb5\x3c\x42\x5a\x70\xcd\x6f\x63\x95\x6f\x7a\x0a\x61\x9f\xdf\xbf\xd0\x0a\xa0\x78\x41\x8e\xb4\x65\x2f\x8b\xc6\xf3\xc2\x53\xbe\xec\x98\x38\xb7\x7f\x9c\xbe\x2e\xf2\xb8\x05\x5c\x57\x73\x53\x9e\x35\x6b\xd8\x19\x26\x06\xec\x10\x1e\x3f\x60\x58\xb1\xdd\x08\xa6\x8f\xdb\xc5\x49\xdf\xe6\xb7\x72\x5d\xc2\x54\x9e\x8e\x3f\x90\xdc\x5b\xe3\xcc\xfb\x0a\x38\xba\xf9\x37\x7c\xb3\xf6\x50\x1d\x2e\x15\xcc\xb3\x55\x6a\x89\x5c\xcb\x23\xf0\xb6\xdf\x9f\xe5\x93\x11\xcf\xf5\x53\x74\xc3\xfb\x3a\x32\x98\x1c\xa2\x6a\xb4\x26\xf3\x66\x3d\x04\xe3\x16\x7e\x53\xa5\x37\xb7\x58\x9a\x9f\xb7\x36\x79\x09\x0a\x20\x55\x32\xc1\x32\x90\x66\x34\x33\x4a\x7e\x87\x49\x79\x3f\x8c\x59\x3f\x3f\xd6\x27\x8c\xe0\x05\x03\x83\x48\x7f\x3b\x24\x50\x67\xaf\x94\x88\x1a\xa1\xae\x96\x8d\x0c\xae\xba\x5f\xa5\xc7\xbe\x5f\x4e\x4b\x72\x57\x51\x86\x95\xd8\x9b\xcc\xde\xc5\x07\xb9\x67\xb4\xfd\x64\xb6\x89\x3b\x3e\xe7\x80\x3c\x1d\x36\xea\x8a\x02\xfc\x42\x6f\x9a\xfc\x8e\x9f\x24\x32\x15\x27\xec\x98\x44\xbc\x3c\x54\xa0\xf7\x66\x7e\x03\x43\x00\xbb\xb4\xfb\x02\x0f\x6d\x5b\xb9\x54\xe7\xb5\xa3\xa7\x06\xa4\x93\x9d\xb3\x3c\x15\x48\x92\x64\x34\x76\xa2\x91\xd4\x7d\xc1\xe6\xf7\x2c\xe9\x1d\x13\x6f\x11\xdb\x26\xb9\xc9\xba\x73\x6e\x40\xdf\x0a\x15\xc1\xa8\x91\x49\x99\x6b\x25\x1d\xd9\x88\xb3\x90\x04\xe6\xef\x41\xbd\xc0\x61\xdb\x58\x0b\x7b\x74\xde\x2a\x65\x18\x10\xbd\x89\x17\x53\xb9\x73\x86\xd7\xf8\xcb\xdb\xb6\xec\x38\x6f\xa2\xc3\x42\xf5\xef\x20\xe6\xe3\xa8\xbb\x4d\x51\x49\xa7\xd4\xde\x12\x24\xdf\xf1\xd1\x72\xc8\x75\x70\xf7\x76\xd5\xef\x45\x95\x9b\xe0\x93\x8a\xd7\x9f\x5d\x33\x95\xcb\x27\x21\x62\x71\x22\x88\x7b\xd7\xa8\x98\x3b\x64\x77\x97\xbd\x41\xd8\x82\x64\x1c\x81\x43\x1c\xe8\xd9\xb3\x06\x7a\xde\xc4\xcd\xe9\x26\xc5\x13\x13\xf0\xcf\x84\xc5\x29\x25\x62\xdd\x49\x08\x64\x2d\xd2\x45\x28\x84\x84\xc5\x56\x8a\x78\x7d\x0c\xed\x36\xa3\x52\xf0\x32\xda\x4f\x7e\x4d\xe0\x6b\x11\x47\x3f\x65\x0e\xec\x65\xdd\xa9\x96\x39\xaf\x2d\x42\xd8\x4e\xe2\x30\xf4\xf8\x36\x23\xd9\xc9\xaa\xa3\xb1\x6b\xda\x10\xdd\xaa\xd2\x5a\xf5\xc1\xc1\x0f\x81\xc8\xc5\x1c\x81\x1a\x3a\xa3\xe3\xdb\x58\xa7\x02\x5e\x43\x80\xe2\x85\xda\x47\x4a\x61\xba\x59\x17\x3f\xf0\x42\xa4\x6a\x79\xab\x18\x4b\x07\x01\x08\x41\x6f\x9d\x61\x58\xcf\x96\xd0\xe6\xdb\x44\x76\x14\xa0\xd9\x08\x9e\xbb\x6a\xee\x4e\xf1\x07\xbe\x45\x93\xd7\x1e\x79\xf6\x79\x86\x68\xa7\x40\xae\x4b\xac\x5a\xc7\x59\x4e\xcb\xd5\xdc\x82\xe7\xd0\xf9\xcb"}, -{{0x51,0xb1,0xad,0x0f,0xfc,0x21,0x49,0x7a,0x33,0xdb,0xdb,0x85,0xea,0x2b,0xc1,0xce,0x3d,0x0c,0x2d,0x95,0xd9,0x46,0x1a,0x39,0x09,0x73,0xfe,0xe3,0x77,0xfc,0x75,0xf4,},{0xba,0xd0,0x41,0x25,0x75,0xd3,0x80,0x13,0x01,0xed,0xee,0x6b,0xc0,0xf2,0x76,0xe7,0x87,0x35,0x7b,0x41,0x22,0xf5,0x2d,0xe9,0x81,0x88,0x58,0x51,0x88,0x42,0x49,0xcb,},{0xcf,0xb6,0x5b,0x6f,0xf0,0x37,0x7c,0xef,0x51,0x1f,0xd9,0x7b,0x90,0xc3,0xec,0xb8,0x08,0x33,0xf1,0x42,0xa7,0xcf,0x50,0x22,0xce,0xd3,0x0b,0x3f,0xb7,0x86,0x20,0x86,0xd0,0x13,0x39,0xb8,0x86,0x6a,0x23,0x8c,0xb0,0x70,0x27,0x6e,0x19,0x44,0xb5,0xfe,0x32,0xcc,0x40,0x99,0x47,0xcb,0x91,0xde,0xb1,0x43,0x2c,0x29,0x1b,0x60,0xfb,0x0d,},"\x78\x82\xe8\x6e\xf3\x40\x2f\x6d\xbc\x65\xcc\xe8\x31\x5b\x39\x76\x5f\xaa\x4b\x1f\xc8\x76\xfa\xd5\xf8\x22\x0c\xb2\x2a\x7d\xf2\xe3\x58\x0e\xab\x3a\x7e\x8f\xa7\xfb\xb6\xb5\x94\x82\xca\x0e\x36\x4a\x13\x13\x96\xdf\x79\x2a\x32\x41\xa0\x60\xe4\x41\x43\xb6\x76\x74\x93\xc6\xbf\x75\xf1\x87\xa9\x64\x3a\xa1\x1e\x11\xeb\xa7\xb0\xa8\x0f\x0a\x68\xb9\xf1\xb7\x9f\x75\xb6\x6c\xc5\x9d\x9d\xa7\x79\x55\xfd\x7e\x87\x99\xf9\x9d\x6e\xb0\x8f\x90\xd3\x18\xf4\xef\xcb\xfe\x71\x15\x9b\x10\xa8\x3a\xa5\xfd\x69\xbb\x75\x33\x6f\x5d\xf2\x96\xea\x06\x0a\x42\x6c\x95\x45\xdf\x94\x0b\xc1\x45\x4e\xfc\x1f\x9d\xc9\x65\xf1\xf2\x2d\x94\x73\x03\xfb\x8e\xc1\x24\x07\xff\xf6\xb1\xdb\xe4\x7e\x34\x21\xc3\x17\x64\xfd\x90\xc8\x3a\xc7\x11\xd1\x99\x26\xe2\x29\xa0\x64\xc6\x1f\xe3\x67\x6a\xf3\x00\xa1\x71\x6f\xab\xe4\xe3\x84\x22\x64\xad\xb3\x2e\x0d\x9c\x9f\x5d\x4a\x65\xd0\xd7\xb5\xc3\x77\x0d\x73\x7e\xe1\x3c\xbe\xd2\x1d\x7a\x1d\xa3\x6a\xaf\x7e\xc0\xf3\x6f\xcc\x47\x6f\x65\x96\x81\xe5\x16\x0a\x5a\x1f\x49\xe7\x59\xb9\xd0\xfc\xd4\xfd\xb8\x54\xec\xcd\x99\x17\x2a\x47\xd2\xc4\xef\xbe\x0b\x37\x57\x63\x1d\xf1\xba\xe1\x75\xf0\xfa\x74\xdd\x04\x8b\xb6\xa5\xfe\xd8\x43\x02\x84\x34\x9d\xa3\xd6\x7d\xf2\xa6\xf7\xe8\x26\x9b\xc7\x9f\xb2\xc5\xd5\xed\x60\x84\xe9\x07\x6f\x45\x5a\xb6\x38\x91\x90\x46\x36\x9a\x44\x6d\x57\xfc\xad\xa7\x01\x1c\xc7\x71\xbf\x6d\x87\x4a\x8e\x5d\x23\xc6\x87\x74\x7d\xe4\x1d\xd0\x4b\xff\xc7\x17\xd6\x12\x81\x83\x84\x6e\xb5\x94\xb3\xcb\x1c\x1a\x8a\xa0\x4f\x0d\x7e\xba\x53\xaf\x39\xcb\x1d\x4e\x6f\xec\xf3\x11\x3b\xd8\x42\x24\x16\xf4\xc4\x40\x37\xae\xee\x9e\x0f\xdc\x51\x7c\x48\x73\x1f\xd0\x4e\xe9\xc9\x9f\x5d\xbc\xa3\xd5\x74\x50\x9d\x7b\xaf\x32\x88\xf2\xc2\x30\xa0\x2d\x17\x03\xbd\xb1\x61\x1c\xde\x2a\x76\x6d\xac\x19\x3d\xe1\x67\x44\x3d\x20\x09\x0d\xc3\x4d\x29\x27\x7a\x86\xb1\xe9\x98\xb2\x45\x64\x51\x17\xe5\x11\x1f\x12\xf1\x46\x06\xc5\x54\x46\xdd\x91\x2d\x34\x75\xc1\x98\x76\xe1\x9a\xc5\x36\xd3\x17\x87\x6c\x4b\x0a\x2e\x0f\x98\x61\x61\x29\xa5\x68\x37\x32\xa4\x23\x17\xc5\xe8\x09\xdc\xa9\x56\xb2\xab\xb4\x84\xad\xa8\x10\xa1\x5c\x81\xcc\x85\x62\xb5\x55\xda\x94\x58\xf9\xb4\x43\x38\x49\x02\x30\xc7\x40\x4f\x3d\x48\x61\x1f\x84\x12\x7e\x73\xe2\x77\xd8\x8c\x62\x21\x2d\x2a\x3a\x35\x1f\xc6\x76\x65\xb1\x8d\x77\x21\x62\x30\x63\x2c\xbc\x78\x12\x88\xe1\x5c\xeb\xf3\xec\x33\xa7\x20\x5e\xb2\x2b\x9a\xbe\x4c\xdb\xc7\xdd\xba\xaa\x53\x64\x08\x75\xeb\x76\x3f\x52\x2c\x36\xcf\xff\x2e\xb2\x3e\xe5\x86\xd7\x75\x28\x62\x59\xfa\x94\xa4\x4f\xa7\xec\x01\x50\x96\xa2\xa4\x46\xb6\x73\x2b\x80\x02\x42\x67\xfe\x3d\x5d\x39\xd1\xc4\x85\x09\xb3\xec\xaa\x2e\x24\xe5\x4d\xe4\xd6\x1c\x09\x7b\x70\xf7\x53\xb5\xaf\x9a\x6d\xb6\xf9\x75\xd2\x5f\x4f\x83\xd0\x6f\x87\x9e\x17\xef\x7c\x50\x9a\x54\x14\x44\xba\x3e\xb6\x86\x78\x38\x09\x0e\x22\xda\xfd\xbb\x0e\xb3\xb0\x56\x5b\xe1\x57\x9c\xee\xcd\xed\x20\xf5\x44\x25\x6c\x7c\x4e\xde\x3b\x62\x84\x3c\x65\xb0\x46\x6b\xe6\xb7\xe2\x73\x05\xb9\x63\xca\x91\x4e\x3b\x7d\x21\x73\x61\x18\xed\xb3\xd6\x58\xd9\xd7\x6f\x50\x9d\xb3\xb9\xca\x2e\xae\x28\x96\x4a\x4b\x3b\x3c\x38\x4a\x81\xa4\x89\x0e\xe9\x6f\xbe\x93\x4a\x6f\x2a\xec\x8e\xeb\x6c\xfe\x59\xac\x9d\x3b\xbc\x16\x46\xba\x32\xa1\x14\x2f\xee\x59\xfe\xd6\xfb\x7b\xbc\x04\x98\xcc\x27\xde\xad\x41\x3b\x7b\x43\x51\xec\x20\x63\x43\xc0\xab\x89\xfc\xf8\x72\x43\xb1\xab\x45\x0e\x58\xff\x11\xa1\x14\x0a\x38\x3f\x19\x6a\xa3\x97\x6c\xe1\x7c\xf3\x45\x30\xf0\x49\xa1\xde\x90\xe3\x17\x53\xcd\x85\xe7\xf1\xfd\x5c\xf2\x04\x26\xc9\x37\x9f\xeb\x8c\x31\xb4\xbf\xec\x35\xea\x5a\x78\x95\x3d\x75\xc5\xcf"}, -{{0xfa,0x2f,0x46,0x1c,0xe8,0xc7,0x12,0x62,0x18,0xc4,0x7c,0x91,0x56,0x9e,0x87,0x99,0x79,0x7c,0x83,0x36,0x8f,0xc8,0x42,0xb6,0xe1,0xc2,0x2f,0xd5,0x2a,0xec,0x70,0xbf,},{0x6b,0x89,0xb2,0x3f,0x1e,0x11,0xa7,0x5a,0x53,0xf9,0x92,0xf6,0xca,0x57,0x75,0x00,0x8c,0x6e,0x9e,0x7e,0x49,0xc0,0xd8,0x51,0x0b,0x0e,0x83,0x69,0xb7,0xa2,0x0b,0xcc,},{0x84,0xf7,0x9d,0x9e,0x8f,0x30,0xe5,0xbb,0x63,0x62,0x23,0x97,0x14,0x55,0x6b,0x04,0x73,0x6f,0xa4,0x44,0x65,0xca,0xba,0xad,0x23,0xbe,0xaf,0x5a,0x99,0xfc,0x45,0x1a,0xd4,0xae,0x5a,0x18,0xc7,0xf6,0xf9,0x64,0xfa,0x41,0x03,0x92,0x16,0x01,0x8e,0xc5,0xa2,0xac,0xca,0xe1,0x07,0x5a,0x6b,0xb3,0xa6,0xec,0xbc,0x1f,0xca,0x02,0xb9,0x04,},"\x79\x9b\x39\x80\x2a\x18\x27\xe4\x5c\x41\x12\xfe\xe0\x26\x03\x4c\x0e\x59\x8a\xff\xce\x2c\x55\x0c\x19\x3f\xee\x73\xf1\xdf\x8c\x30\xc8\xd3\x87\x33\x40\x08\x8c\xe8\x59\xde\x34\x71\xe9\xd0\x57\x68\x6c\x82\x9b\x54\x08\x79\x5e\x08\xb3\xdc\x7a\xa3\xb6\x37\xc7\xde\x9d\x21\x72\xad\x03\x33\xc1\xbe\xa8\x61\xa6\x23\x2f\x47\xf0\x5a\x10\xbf\x5d\xf8\x08\x15\xa2\x71\x25\x6e\x37\xe8\x08\xa0\xe6\x2f\x1f\x07\xd9\xe1\x0e\xbb\x94\x7d\x3e\xfa\xbf\x8a\x28\xfa\x9d\xcc\xd9\xa1\xd5\x99\xf5\xfd\x61\x65\x50\x8e\xfd\x67\x9c\xf3\x56\x01\x50\x58\xbf\x4b\x34\x11\x8f\x83\xaa\x3e\x5b\xc2\xce\x19\xec\xa8\x4f\x71\x83\x98\xad\xbc\x0a\x52\x76\xcf\x9d\x8c\xaf\xfc\x27\xe3\xe6\xab\xbe\x34\x5b\x0e\x9e\xcf\x89\xc6\x77\x1b\x0e\x75\xd4\x08\xba\x2f\xbb\x90\xfc\xfd\x70\xc5\x3f\x2e\x4d\x52\xba\x54\xd9\x78\x4c\xf7\x1c\x34\x9e\xf6\xf1\x4a\xe4\x97\x0d\xef\x6e\xfb\x5f\x30\xe9\x84\xd6\x01\x6a\x19\x6d\xea\xec\x7e\x04\xb4\x76\x19\xc4\x8b\xf4\x9d\xc0\x2f\x7f\xef\x3e\x13\xb7\x56\x17\x4e\x90\xd0\x5f\xcb\xdd\x5e\x13\xf0\xe4\x34\xef\xd5\x42\x1b\x09\x1d\x51\x79\x00\xed\x0d\x57\x85\x96\x88\x62\xb4\xbf\xe5\x09\x3a\xb6\x72\x17\x18\x0d\x97\x55\x4c\xcd\x9c\xc3\x14\x29\x32\x6c\xab\x42\xf3\xf8\x39\x80\x60\xc1\x9d\xb4\x88\xb5\xd1\xc8\x0b\x29\x09\x0a\xfd\x1c\x6b\xac\x36\x42\x26\x48\x00\x21\x1b\xc2\x78\xfc\xb9\x9d\xae\x9d\xbf\x49\xda\xf1\xb2\x4a\xb5\x69\xdc\xbb\x87\xd4\xd3\x54\x73\x35\xe3\x5d\xb9\x84\x00\xcd\xfc\xe6\x79\x06\x82\xe9\x36\x00\x22\x0e\xc4\x99\x24\x5f\xa4\xee\x15\xd8\x43\x83\x1b\x56\xcc\x26\x41\x80\x25\xbf\x87\x00\x16\x05\xc6\x69\x1c\xa6\xbd\x40\xa4\xe2\x48\xc3\x09\x80\x1b\x76\xa7\x95\xed\xe8\xad\x53\x08\xbc\xb6\xd1\x75\x4a\xb3\x37\x1f\x00\x03\xbb\x8c\x4e\x4e\x47\x19\x54\xe2\x8b\x1e\x98\x66\x37\x9f\x82\xe1\xfb\xac\xb7\x9d\x50\xad\xdd\xad\x5b\x97\x78\xb5\x58\xcd\xdb\xb0\x03\x8a\x5f\xf3\xd5\xc9\x55\x7b\x96\x5d\xe3\xa7\x08\x2c\x45\xa8\xec\xf3\xe7\x72\x1e\xb6\x90\xb6\xc7\x1f\x3d\x89\x75\xd5\x30\x0f\x67\xc4\xdc\x4a\x73\x68\x46\xe4\xcc\xd2\x6f\x93\x46\x3d\x5b\xc6\xf4\x6e\xdc\x48\x86\x64\xbe\x96\x96\xbe\x12\xb0\x2d\xd1\x04\xd1\x0c\xc6\xb1\xd8\x2e\x81\x17\x81\x12\x14\xa6\x48\x7d\x17\x36\x7e\x39\x5a\xde\x2e\xf6\xb2\x6a\x17\x83\xa7\xe2\xf2\x45\x21\x3b\xc0\x3a\x75\x5d\xf3\xee\x8e\xf9\xf1\xef\xf9\x72\xc6\x91\x90\x65\xcb\x7b\x75\x66\x78\xd4\xdd\xfd\x19\x3e\xdd\xc0\xb4\x2e\x86\x89\x61\x36\x43\x14\x6d\x74\x28\xca\x37\xbf\x31\xbd\xf1\x4e\x31\x86\x78\x58\xf3\x9d\x23\x23\x70\x9e\xb3\xb7\xd7\xf4\xe3\x97\x02\x23\x78\x42\x4b\xde\xe9\xbc\xb7\x4e\x9d\x5d\xfd\x37\x1f\x47\x34\x99\x8f\xc1\x8d\xf4\xcd\xfb\x4b\x5c\x21\xc2\xe5\x0f\x8d\x6c\x15\xbc\x14\xbf\x4f\xda\x6c\xeb\x9d\x80\x82\xca\xe4\x32\xdf\xc9\x8b\xfb\x3e\xcd\x16\xb8\xd7\x4f\x83\x0b\x64\x2b\x04\x28\x75\xe9\x21\xb0\x54\xbd\x1a\xaa\x58\x1f\x60\xd7\x18\xdf\x66\x9f\x56\xdc\x2f\x10\xd4\x78\x99\x77\x22\x16\x2e\x83\x94\x0e\x61\xa1\xb6\xe4\x2d\xf2\xa4\xa3\xa7\xcb\xcd\xd6\x11\xce\x96\xcb\xcf\xb5\xa9\x5c\xc4\x73\x23\x1c\xa1\x3c\x06\x09\xd0\xce\x1a\xe5\xdd\xb5\x46\x6d\x6d\x65\xee\xfa\xd9\xda\xf2\xa3\x69\x01\xbc\xc9\x45\x84\x7d\xa1\xed\x6e\x2e\x24\x0e\x84\x8b\x23\x1b\x7d\x0e\x1a\xcd\x06\x54\x3e\xc9\x3e\x76\x8e\x59\x98\x5d\x7e\x96\xc8\xc3\x1f\xcd\x12\x10\xf0\x96\x42\x71\xe2\x18\x77\x52\x5c\xb1\x34\xbc\x35\x36\x25\x7d\xbb\x11\xd3\x0a\x3c\x4f\x94\x9f\xb8\x2a\xe0\xc3\x1c\xcd\xfe\x41\x94\x32\x51\xe5\x0a\xa4\x35\x53\x92\xac\x30\x9e\xf6\x0f\xc1\x74\x32\xa2\xbe\x4b\xdb\x2f\xcb\x28\x60\x7c\xc4\x5a\x52\xb6\x00\x16\xbb\x1d\x2e\x23\x97\x2f\xf2\xc2\xa2\x47\xd7\x25\x58\x5b\x1e\xf2\xb1\x5f"}, -{{0x1b,0xe2,0x94,0x9d,0x51,0xe7,0x20,0x81,0x75,0x82,0x62,0x13,0xee,0x6a,0xe3,0xc0,0x91,0x17,0x27,0x42,0xe8,0x8c,0xaa,0x02,0xed,0x0f,0x31,0x3e,0xcb,0xe5,0xd9,0x10,},{0xd7,0xbf,0x47,0x48,0xd6,0xdd,0xed,0x5b,0x57,0xa2,0xab,0xf7,0x97,0xfa,0xcc,0x56,0x0b,0x48,0x56,0x3d,0xfd,0x9d,0xcf,0xf4,0xbe,0x52,0x2c,0x71,0x7a,0x6c,0xfd,0xa9,},{0xf4,0x1f,0x2e,0xf6,0x59,0x5f,0x17,0x66,0x0b,0xb2,0xfe,0x93,0xe5,0x1f,0xc6,0xfa,0x9c,0x31,0xda,0xdc,0x9d,0xb9,0x0c,0x3f,0x46,0x60,0x7a,0x7f,0xb4,0x80,0x0b,0xb7,0x5a,0xd9,0x63,0x25,0xdc,0x7e,0xab,0x78,0x24,0x72,0xb0,0x4d,0xa6,0xd8,0xe6,0xfe,0x64,0x65,0x5d,0xea,0x55,0x1f,0xbd,0x50,0x49,0xe8,0x76,0xce,0x5a,0x40,0x5f,0x02,},"\x04\x5e\x2b\x0e\xc7\xbb\x20\x3a\x49\xbd\xcb\xa9\x41\xe2\xb7\x3c\x23\xc1\xfe\x59\xa1\x7d\x21\xa0\x12\x4e\xa2\x4b\x33\x7f\x92\xab\x9c\x92\x3a\x20\x57\x6b\x62\xd5\xd0\xf6\x24\xe7\x93\x2c\x11\x5b\x54\x74\xe0\xa4\x6a\x4d\xc9\xec\x51\xf6\xa0\xce\x8d\x54\x74\x4d\x1d\x52\x09\x33\x20\xe3\x9b\xe2\x03\xf7\x4a\x0f\x5d\xfa\xc5\x2c\xf0\xf9\x95\xc6\x6d\xf2\x91\x4b\x68\xad\x87\x1f\xbe\x81\x52\x5a\xd2\xd8\x8a\xc6\x99\x33\xa7\x5a\xea\x74\xac\xe4\xe3\x63\x43\xdd\xc0\x6d\x32\x08\xf1\x6d\x80\x5f\x5d\xd7\x86\xb4\xda\xaa\x16\x67\x48\xcf\xee\xc5\x71\x4c\x85\xc1\x04\x78\xb5\x97\xac\x7f\x6a\xe2\xc9\x88\x91\xe3\x8f\xd4\x14\xaa\x81\x1b\x76\x21\xd8\x05\xeb\x8f\xcc\x46\xcf\x4d\x56\x8a\x8a\x92\x58\x7c\xbb\xc1\xae\xcc\x12\xf1\x0d\x90\xac\x1e\x01\xae\x98\x6d\x14\xfe\x82\x95\x1c\x68\x2c\xea\xc8\xc9\x25\xfc\x66\x54\xd8\x38\xac\x93\x53\xae\x2f\x93\xf3\xc8\x8b\xf7\xb8\x2c\xbc\x43\xb1\xe4\x9e\x5c\xeb\xfb\x19\x49\xad\xe4\xb2\x2e\x4b\xcf\x1b\x40\x0c\x0a\x8f\xa8\xa6\xfe\x76\x70\xf6\x9f\xc3\xfa\xec\xd4\x80\x5b\x8c\x95\x4c\x01\xa5\x40\xd1\xa1\xe7\x88\x43\x6e\xae\x07\x3a\xe9\x56\xda\xe3\x17\x69\x05\xa8\xf0\xa3\xc6\x0f\xd9\x80\xda\xb4\x19\xd4\x1e\xc0\x6e\x52\x73\xfb\xb1\x3d\xb9\x38\x1f\x89\xb6\x63\xcc\xc4\xbd\x75\x3f\xd9\x0f\x14\xa7\x7b\x3d\x81\xc4\x5d\xd3\x56\x1c\xd1\xfa\x0e\x94\xd2\x34\xce\xf9\xd7\x85\x9a\x2e\xc9\x42\xbf\xc1\x88\x49\xd7\xf2\xad\xa3\xa5\xd6\x57\xbc\x19\x3d\x2e\x14\x91\x68\x2f\x16\x65\xa5\x34\xb1\xac\x20\x83\xb7\x38\xbe\x8f\x9e\x96\x3f\x59\x41\xed\x48\x3c\x6a\xcc\x82\xe9\x59\xb8\x1b\x8a\xf0\x2f\x47\x1c\x08\xf5\xf8\xb1\x2e\x10\xe0\x08\x19\x28\x98\xa4\x45\x02\x02\xaf\x73\x15\x92\xe7\x4e\xfe\x2a\x94\x8e\x51\xd0\x6e\x44\xde\x9b\x95\x6b\x7b\xc9\xa6\x9b\x6e\x74\x68\x7a\xb2\x06\xde\xc4\xd3\x5b\x31\x73\xfb\xc4\x38\x82\x9d\x50\x64\xbf\xbc\xf7\x43\xc1\xe2\xd4\x6f\x62\x8f\x2e\x51\xc6\x26\xd8\xe4\x16\xd7\xbe\x6e\x55\x5a\x24\x96\x91\xab\xb1\x67\xf1\xd9\x2f\x4f\xa3\x39\x2f\xde\x24\xe9\x93\xce\x7f\xf5\xc1\xb8\xe1\x57\x7a\x7c\x0e\x73\x02\x5c\xc6\xfc\xd7\x27\xa8\x2e\xf0\xc1\x29\xe9\x1e\x55\x33\xe0\x21\xa3\xcd\xbb\x99\xd5\x4b\xf7\xcd\xcd\x3f\xf1\x19\x15\x4f\x3f\xad\x92\x42\xb6\xed\x35\x0d\x10\x37\x2c\x97\x6f\xf3\xa4\x37\xd0\x97\x86\x7d\x9b\xfb\xa9\x1d\x84\xbd\xa5\x5a\x6b\xcd\x6e\x36\x41\xb2\x13\xa2\x18\xb3\x04\x15\x89\xc5\x5a\xfb\xb3\x44\xde\x6e\x97\xd8\xc3\x5b\x5c\x86\xcf\x3b\xe0\x63\xf9\x01\xff\xee\xa8\xcc\x91\x06\x99\x67\xd2\x34\x60\x35\xa9\x1e\xb5\x70\x6a\x3b\x53\xf6\xd1\xc3\x4d\x4d\x21\x16\x70\x6b\x65\xc2\x98\xec\x57\xde\x82\xab\xc4\x00\x3c\xe8\xcc\x5e\x0b\x88\xff\x71\x0d\xda\x1d\xce\xf6\xf1\x54\x27\x71\x06\xb8\x3e\xb4\x6c\x04\x5b\x08\x2d\x11\x3b\x36\x1d\x6a\x62\x58\x08\xc9\x13\x05\x84\xdf\xc9\x67\x07\xef\x89\x55\x90\x7b\xaa\x61\xcf\x88\xc6\x6b\x6d\x1f\x60\x58\x11\x19\xcb\x62\x17\xa8\x52\x15\x73\x36\x17\x8c\x68\x5e\x6e\xd4\x85\x26\xed\x5c\x4e\x3b\x79\x67\xd5\x1f\x99\xdf\x68\x76\xa1\xac\xfb\x84\x5c\x57\x1b\x89\x86\x56\xe5\xe3\xbc\x73\x98\x0b\x9b\xed\x11\x98\x86\x63\x59\xc9\xe9\xb1\xef\xa9\x15\xf8\x10\xd1\xef\x8a\xd6\xcb\x3f\xc2\x1f\xbf\xe6\x54\x30\x6d\xe6\xca\x13\xa3\xa6\xa4\x8e\x7a\x13\xed\x87\x46\xac\xbd\x07\xf4\x8e\xb0\x0c\x36\x37\x4b\x1e\xb4\xf3\xf0\x1c\x19\xe2\xe8\xd3\x7e\x9f\xc0\x64\xb3\x3c\x0d\x66\x9b\xba\x55\x4d\xdc\x68\x21\xa7\x7b\x40\x89\xca\xbd\xca\xfc\x97\xf6\x0e\x60\x50\xbc\xa4\x44\xae\x8c\xfc\x44\xd9\x3c\x40\xef\x53\x18\xbe\xe6\xf8\xcf\x0c\x06\x7b\x85\xcd\xdd\xc4\x59\x74\xa4\xea\xcf\xc3\xef\x51\x31\x5b\xa0\xf3\xf6\x29\x68\xc7\x00\x3a\x7f\xf4\x44\x61\x24\x00\xb1\x59"}, -{{0x3b,0x6b,0xa6,0xd5,0xcc,0x9c,0xd6,0x24,0x1d,0x8b,0x00,0x97,0xa3,0x72,0x2e,0x4d,0x06,0x6f,0xea,0x3d,0x56,0x0a,0xea,0xb4,0x67,0x3e,0x86,0xf1,0xf8,0xec,0x60,0x26,},{0x8c,0xa6,0x52,0x07,0x17,0xcf,0x36,0x3c,0x4c,0xef,0xfa,0x76,0x32,0x8a,0x0a,0x16,0x6f,0xf8,0x3e,0x45,0xca,0x7d,0x19,0x1c,0xc8,0xef,0x6c,0xa6,0xe5,0x24,0x33,0x67,},{0x78,0x8c,0x9f,0x45,0x54,0xdd,0xba,0x5c,0x7d,0x64,0xba,0x75,0x9e,0xc4,0x56,0x94,0xec,0x79,0xfb,0x85,0xe8,0x23,0x68,0xa0,0x74,0xbd,0xd8,0xdf,0x34,0x42,0x13,0xa5,0x6d,0xd0,0x9f,0x33,0x4c,0xd9,0xac,0xb9,0x41,0xbe,0x28,0x3d,0x98,0xc4,0xb1,0x5d,0xcf,0xec,0xd1,0x4e,0x93,0xf6,0xa2,0xe3,0xcb,0x0c,0x1a,0xa2,0xde,0xe7,0xd9,0x0b,},"\x36\xde\x93\x0c\xc8\xe1\x88\x60\x83\x6a\x0c\x82\x9d\x89\xe9\x63\xa5\x8b\xdd\x9c\x6b\x6e\xf5\xbc\x61\xf7\x59\x92\xd2\x07\x52\x42\xdc\xa2\x3e\x28\xde\x20\x5a\x33\xdf\xea\x86\x1f\xc4\x4a\x32\x62\x8e\x8e\x7c\xdd\x3e\xd7\xff\x49\xea\x6a\x70\x97\xe0\x09\x0c\xfd\x9f\xf5\xec\xab\x1d\xe8\x22\xfc\x0a\x4c\x37\x76\xdd\x56\xc1\x91\x92\x04\x51\x6a\x94\xce\xc5\x63\x8d\xa1\xd9\x9e\x52\xb8\x66\xf5\xec\x41\x62\xa9\x12\xed\xb4\x1c\x1e\x92\xed\xfc\x35\x3f\x67\x05\xe1\xc1\x2c\xd4\x1c\xb6\x2d\xed\x4a\xd8\x15\x79\x40\x05\x9b\xfc\xf5\x07\x19\xd3\xf2\xad\x00\x84\x85\x40\xce\x89\xf3\xf9\xaf\xa6\x10\xcc\xba\x5e\xcc\x37\xe3\xe2\xc1\x53\x4f\xcb\x38\xfc\xd3\x9a\x2d\x14\xd5\xb5\xda\x6f\xea\x24\xe0\x06\x65\x4e\x30\x90\x47\xa2\x9c\xad\x0a\xe4\xda\x8e\x70\x8f\x97\xa1\x8c\xad\x5f\xbd\xc9\xac\x84\x40\x0c\x53\x2c\xed\x54\x88\x86\x53\x9e\xdd\x6c\x54\x10\x74\x79\x0a\xe4\x50\x2f\xdf\xe9\xf3\x27\x3a\x87\x6a\x21\x86\x23\xa2\x57\x06\xa1\x52\x5e\x67\xe5\x7a\x16\xd2\x2c\x21\xb6\xa4\x5e\x23\x84\xe2\x87\xac\x44\x52\xae\xc4\xe0\x63\x05\x6b\x4c\x17\x8a\xb0\xe5\xb2\xa5\xba\xd3\xf4\x63\xc4\x72\xc4\xea\x1f\x9c\x1a\x66\xe5\x27\x04\x73\xa8\x35\x09\x4e\x8f\x0e\xef\x68\x0c\xd7\xb2\x0d\x0e\x70\xf4\xd6\xc9\x58\xfe\xe0\x8a\x93\x60\xaa\x60\x66\x88\x8f\x4d\xd7\xce\x5e\xc2\x22\x59\xfa\x0b\x53\xfe\x92\x71\xc0\x83\xc6\xfc\xdb\x72\x83\xb0\x90\x61\x08\x8c\x52\xf7\x1b\xfd\xd2\x77\x7c\xe0\x80\x1f\x41\xa6\xc4\xce\x90\xef\x13\x1d\xe1\xe1\x83\xcb\x89\x49\xce\x32\x3c\x9e\xb1\x3a\x4b\x0c\xac\xf9\x9d\xef\xdf\xdb\x68\xd5\xed\x1f\x68\x91\xb4\x8e\x21\x04\x76\x68\xd6\x9d\xe8\xa8\x0f\x8e\x56\x34\xde\xd0\x87\x36\xa4\xfb\x54\x10\xcd\xea\x9c\x72\x59\x6e\x36\xdf\x68\x41\xf2\xee\xa4\x68\x50\xc8\x74\x73\xc8\x95\x54\x02\x05\xb0\x92\x19\x60\xff\xa5\xd9\xd8\xff\xb8\xe2\x9c\xde\x96\xa3\xed\xe0\x15\xac\xbc\x26\x97\x40\x04\xd3\xe4\x38\xa8\x5b\x2e\x33\x85\xf6\x4d\x18\x14\x00\x39\x41\xff\xd3\x63\x99\x2d\x39\x40\xc6\xe6\xd8\x1f\xf8\xe4\x5f\xce\xd6\xd3\x6c\xe1\x98\xd8\xcc\xbe\xfe\xe4\x32\xa7\x7d\x8f\xca\xdd\x73\xfb\x79\x9f\x6b\xaf\xef\xb5\x1a\x2d\xa7\x98\x72\x1c\x3d\x46\x5b\x16\x3e\xf1\x3e\x6e\xcc\x65\xe6\x03\xb2\x89\x3e\xe4\xcc\x9e\x1c\x6d\x1d\xe7\xa6\x5c\xab\x5c\xbd\xf5\x36\x85\x5e\x28\x8c\x3c\xcd\xa8\xd2\xfa\x3c\xe1\x0c\xf4\x93\x58\xa2\xef\x4e\xf0\x76\xe5\xbf\xa9\x1b\xbc\xf3\xd9\x66\xdf\xa3\xdc\x6e\x71\x2f\x19\x56\xd4\xe5\x8a\xa3\x6e\x71\x2d\xd3\x34\x71\x69\xb1\x9c\x8d\x44\xbe\xc5\xbc\xb7\x30\x77\x8f\xcc\xcc\x58\x9e\xd5\xd3\x50\xd4\x4c\x17\xbd\xe2\xee\xbb\x6f\x5e\xc5\x9f\xb2\x40\xd6\x7d\x81\xae\xa9\x26\x7f\x34\xf1\x5e\xee\x2d\xe3\xf4\xfa\x67\x39\x14\x79\xbd\xbb\x43\x0f\x48\x43\x70\xfb\x0e\x08\x95\xb9\xae\x06\x5b\xbd\xd4\x3e\x23\x0c\x62\xac\x07\x18\x4e\x8b\x06\xb2\x4b\x8b\x97\xec\x02\xdc\x6f\x37\xef\x61\x64\x1e\xd5\x6e\x3f\x5e\xb8\xd2\x08\x0b\x51\x44\xef\x76\x0b\x51\x87\x52\xe1\x97\x54\x79\x2e\x19\x34\x3a\x38\x55\xe1\xe2\xf7\xa7\xdc\x62\x35\x17\xee\xd2\xf5\xd2\x65\x48\xa6\x8e\xb8\xff\xd7\xbf\x70\xf7\x8f\xd1\x86\xdb\x63\x49\x28\xbb\x98\x13\x8f\x2b\x8f\xe8\x44\x81\xcc\x53\xf5\xaa\x35\xe2\x66\x6c\x63\x25\xe1\xd2\xb8\xac\x5e\x2d\xf2\x93\x5b\x7f\x64\x13\x95\x2d\x10\xd6\x07\x6f\xfc\x75\xbb\x6a\xf6\x3b\x29\xb0\xb9\x66\x3b\xec\x37\x24\x7b\x66\xb5\x08\xdd\xe4\x1f\x2f\x11\xb8\x43\x33\x55\x9d\xfa\xc7\x3f\x76\x1b\xcd\xa8\x4a\x48\xd2\x66\x07\x3a\xef\x16\x38\x46\x08\x49\xe7\xa1\x72\x06\xa2\x5f\x68\x00\x77\x0b\x91\x4c\xc0\x26\xba\xf9\xe3\x25\x59\x14\xe1\x32\x58\x44\x1c\xef\x35\xad\x1d\x66\x83\x3e\x98\x7e\xbe\x44\x31\xe6\xa6\xbb\x22\x2c\xbb\x65\xaf"}, -{{0xdd,0x99,0x87,0xb1,0x8f,0x9a,0x92,0x2c,0x0f,0x6f,0xea,0x18,0xeb,0x00,0xb8,0x96,0xc7,0xa2,0xd3,0x09,0x3d,0xb3,0xea,0x31,0xd3,0x84,0x21,0xda,0x0d,0xe5,0x12,0x31,},{0x57,0x39,0x21,0xa9,0x55,0xfe,0xb6,0xdd,0xe4,0x1b,0x05,0x5c,0x8d,0xac,0xac,0xcd,0x1d,0xb7,0xfe,0x9e,0x36,0xb5,0x09,0xd3,0xc9,0xe3,0x6f,0x97,0x35,0x75,0x23,0x24,},{0x3e,0x9f,0x2b,0x00,0x7c,0x0e,0x29,0xec,0x87,0x59,0x95,0xa6,0x30,0x9b,0x97,0x3d,0xeb,0x8b,0xaf,0x11,0x3d,0xed,0x13,0xf1,0xe0,0x00,0x3e,0x9b,0x9b,0xf9,0x39,0x16,0xa4,0xdf,0xe4,0x79,0x37,0xda,0xdf,0xc7,0x8a,0xa6,0x63,0xc5,0x5f,0x67,0x4e,0xc3,0x5c,0x38,0x46,0x25,0x8f,0x18,0xe7,0xbb,0x93,0xfb,0xba,0x3e,0x82,0x6a,0x1f,0x0d,},"\x48\x16\x2f\xdc\x3a\xbf\x73\x19\xc6\xca\xab\x60\xcb\x8d\x05\x20\x87\x5c\xb4\xee\x8a\x07\x09\x27\x83\x16\x7d\x47\x33\xff\xe5\x20\x4e\x5f\xeb\xe7\xd2\x91\xe9\x53\x6b\xde\xa3\xdf\x06\x37\x15\x9a\x65\x3e\x09\xfd\x99\xaf\x66\x1d\x83\x00\xae\x74\x1a\x3e\x91\xa8\xbd\x85\xea\xd0\x5d\xc7\xd9\xe6\xf9\x29\x32\x33\x16\xed\xc4\xca\x62\x4e\xa7\x81\x8b\x25\xbd\xc0\x61\xf7\x14\x92\xfd\x22\xd4\x65\xab\x22\x6f\xd9\xa1\x0d\x8b\xab\xfc\x07\x4c\x68\x6c\x43\x6c\x24\xa3\xa5\x3f\x8f\xf3\x89\xce\x9c\xa1\xdb\xc8\x90\x74\x45\x88\x92\x41\xf8\xfd\xa3\xa7\xa3\xf5\x02\x4f\xa8\xcb\x0d\x04\x4b\xda\xf6\x71\x6d\x98\x3a\x6d\x83\x98\x14\xff\xe7\x0d\xdc\x55\xbb\xba\x11\xac\x97\x88\x7b\xdb\x4d\xad\xa9\x65\x65\xbb\x07\x5d\x5f\xc1\xd3\xc5\x24\x4b\x9f\xff\x77\xde\x58\x72\x9a\x05\x9a\x91\x1f\xb3\xe0\xeb\x16\x4f\xb8\x42\x9e\x26\x56\x85\xd1\x4a\x63\x23\x30\x46\xd2\x0e\xcf\x28\x9c\x55\x72\x31\x69\xa9\xd6\x3d\xda\x0d\x52\x55\x15\x3d\x9e\xf4\xa6\x1b\x92\x12\xf4\xb8\x20\x69\x7a\xe7\xc3\x08\xcf\xab\x40\x3b\x2c\x34\x31\x90\x62\x26\xe4\x5c\xe2\x19\x20\xdf\x52\x01\x60\x9d\xaf\x83\x0f\x28\xad\x79\x60\x05\xa9\xbd\x8e\xba\x62\x0c\xf8\x39\xc3\xba\x22\x7b\x96\x3c\x7b\xd0\x91\x48\x22\xdf\x2c\xa0\x3c\x22\x54\xd0\xcb\x8a\xca\xe0\xd5\x9e\x4c\x3e\x0e\xc2\x15\xc8\x36\x96\x9d\xcd\x1d\x49\xbf\xe1\x97\xe2\xf3\xee\xa3\xfa\x8a\x37\x3b\x55\x8d\x0f\xb9\x06\x3c\xf1\x56\x8e\x73\x9a\xad\x8f\x09\xfb\x43\x7c\xaf\xb5\xa2\x72\x37\x5f\x43\x60\x64\xee\xe1\x1b\xd9\x03\xd3\xaa\xea\xb4\xe3\xfd\xcd\x36\xbd\x20\x76\xee\xa1\x79\xa4\xf0\xd4\xfb\xc8\xdf\x42\xbf\x26\x60\xf0\x8d\xe7\xd5\xc6\x39\x7c\xae\x10\xb7\x27\x74\x58\xaa\x6c\xfa\x01\xe8\xa6\x73\x7e\xb1\x26\x22\x78\x56\x64\x66\x91\x68\x1c\x10\x6a\x15\x7a\x26\xae\xd2\x1b\x1a\xaf\x0e\xd2\x76\x64\x21\xcf\xc3\xd1\xc7\xdd\xfb\x72\xfc\xdf\x4b\x8b\x49\x0f\xc0\x9a\xce\x49\xae\xdd\x77\x12\xb2\x1a\xc5\x6f\x86\x01\xf6\x25\x56\x3c\x78\x43\x06\xf3\xb9\x17\x4a\xdd\xf7\x64\xe0\x51\xaa\xdf\xe1\x28\x31\xaf\x96\x69\xe6\x2c\xab\x12\x1c\x74\xdf\x34\x37\x24\x42\x9d\x6c\x26\x66\x02\x71\xc3\x2f\x40\xcf\x7c\x2d\x08\xbd\x0a\xfc\xc7\x28\xde\xf4\x13\x5d\x4e\xb5\x5b\x6a\x3e\x76\x29\xd8\x06\x86\x4a\x85\xb3\x6a\x32\xb9\xb2\x1a\xc0\xd3\x96\x80\xa2\xae\x4e\xc4\x18\x97\x09\x17\x8e\x34\x94\x97\xf3\x93\x99\xfb\xc7\x8b\x3c\x6c\xfa\xca\x6e\xde\xa7\xc3\x3d\xda\x3c\xc1\x1e\x43\x84\xf1\x58\x3d\x6c\xfc\x6b\x58\xf4\xea\xa2\xbc\x56\xab\xa4\x2f\x73\x8a\x42\x9b\x93\x58\x08\x50\xde\xe3\xfd\x25\x39\x94\xf8\xb0\xfa\x66\xee\x8e\x27\x3d\xec\xab\xd5\x32\x09\x5f\xb0\x4a\x4a\x3c\x34\x0a\xf0\xe5\x5b\x57\xef\xab\x43\x63\x0f\xc0\x2e\xf2\x0b\x42\x5c\xa2\x18\x7e\x3c\x6c\x5e\x10\xf1\x2d\x61\x8f\xd2\x43\xa2\x24\xf6\x50\x1e\xbe\xb9\xd3\x21\xc6\x38\x5b\x81\x27\xef\x9c\xdc\xd0\x97\xce\x7f\xa0\x21\xcf\x40\xd2\x1c\x39\x91\x23\x43\xf6\x7a\xcc\xe1\x82\x5e\x3a\x51\xb8\xa7\x18\xe8\xc3\x40\x62\x2f\xff\x65\xfe\x00\x53\xd2\x4a\xa3\x35\x1b\x6a\x24\x00\x18\x5d\x7a\xeb\x88\xe8\x7a\xc4\xa1\xd3\x94\x90\x9d\x49\x41\x4a\xef\xc2\x2b\xa0\x09\xaf\xf6\x96\x2c\x92\x17\xd7\x55\x69\x4e\x4d\x6a\xa8\xa5\xd6\xa8\x03\xce\xbb\x15\xde\x8f\x54\x16\x34\xb6\xfc\xeb\x0c\xac\x79\xdd\xa8\xa1\x8e\xef\xbb\x53\x7e\x70\xff\xe9\xaa\x5a\x6a\x6a\xaf\x92\x40\xfa\xc2\xea\xcb\xfb\xef\x01\xad\x6b\xdf\x50\x75\x87\x80\xf8\x6a\x4e\x48\x89\x85\x36\x2d\x58\x25\x01\x1f\x5e\x8b\x66\x42\x5a\x61\x6b\x7e\x10\x4e\xb2\x3f\xe8\xf1\x00\xcb\x02\x49\x82\x36\x62\xbd\xa3\xda\x47\xa4\xc3\xc1\xca\x2f\x91\x4b\x25\xb9\x73\x85\x34\x02\x60\x47\xdf\x6d\x7f\xf6\x31\xdf\x2c\x41\x31\xf6\x80\xe1\x37\x43\xc9\xcc\xf2"}, -{{0x38,0xd2,0xef,0x50,0x9f,0x93,0x05,0x1f,0x14,0x51,0x67,0x73,0x7c,0x22,0xe1,0xa5,0xbf,0xe8,0xf4,0xa9,0x1e,0xba,0x0b,0xb8,0x7c,0x39,0xce,0x04,0xa8,0x9b,0xae,0xc6,},{0x01,0x11,0x5f,0x6d,0x89,0xa5,0xda,0xab,0x54,0xf8,0x92,0xbb,0x4a,0x4b,0xda,0x1c,0xe5,0xd8,0xf6,0xc9,0xc8,0x8a,0x50,0xce,0xe8,0x3b,0xd9,0x87,0xa2,0xc0,0xdd,0xf7,},{0xde,0xc4,0x62,0x53,0x50,0x9b,0x11,0xe4,0xb5,0x2a,0x6a,0xe4,0xf3,0x66,0xb6,0x80,0xdf,0xfc,0x28,0x0d,0x0a,0x04,0x4f,0xc0,0xcb,0x79,0x0b,0x6e,0x75,0x13,0x81,0x46,0x1e,0x1e,0x60,0x2a,0x89,0xe3,0xb3,0xd3,0x06,0x4c,0x40,0x7f,0x60,0x2f,0x1c,0x22,0x40,0x4b,0x68,0x23,0xbd,0x24,0x67,0x54,0x93,0x14,0xa0,0x00,0x01,0x66,0x4a,0x08,},"\x42\x7b\x5a\x01\xe8\x59\x7f\x04\xfd\x42\x2f\x0a\x66\x2d\x0b\xe2\xdf\xa8\x53\xed\x5f\x9d\x3f\x60\xff\x90\xf2\xc5\xee\x08\xbb\x59\xfd\x03\xd4\x02\xb7\x54\xca\xf5\x4d\x00\x58\xf5\xa2\xcf\x87\xaf\x4f\xef\x21\x77\xd5\x9e\x18\x22\x62\x93\xfd\x2a\xf3\x76\xbc\x98\x7b\xf7\xb3\x20\xb9\xd1\xe2\x49\xab\x9e\xfb\x75\x07\x8e\x6d\x3d\xf2\x9e\x03\x50\x47\x76\x35\x43\x44\xaa\x69\xe7\x2e\x1e\xbc\x52\xa3\xc3\x8a\x4c\x2a\x16\x73\xb4\xe9\x74\xa2\xe4\xe1\x2a\x2e\x78\xea\x3e\x3f\xe5\x0c\x53\x63\x0d\x09\x6d\xa3\xe2\xfe\x82\x99\xf7\x1a\x1b\x44\x1b\x4c\xf0\xca\xeb\x93\x7a\xfa\x4a\x0e\x39\x15\xcc\xab\x39\x96\xc9\xf6\xa8\xf4\xfd\x37\x54\x3e\x8f\x75\x90\x0c\xfd\x47\x17\x53\x70\xef\xb8\x52\xa5\xf6\x9d\x67\x36\x83\xf9\x98\xfd\xcf\xf8\x5f\xf8\xf3\x2b\xaa\x80\x70\x66\x60\x44\x22\x02\x7d\x51\xa4\x35\xdd\xf9\x88\xed\x2f\xd8\xeb\x19\x1f\x10\xb4\x68\x07\x42\x00\x08\x75\x6e\xb4\xe3\x00\xc4\x09\x9c\x2d\x64\x50\xbc\xc6\xa4\xe7\xd0\x67\x31\x56\xb8\x37\xf0\x50\x63\x38\xf3\xd1\xb5\x73\x4b\x16\x6c\xa5\xcc\x2f\x24\xa4\xef\x02\x6c\xda\x2c\x4a\xe3\x10\x5b\x63\xca\x85\x70\xd1\x85\x46\xcf\xac\xb8\x60\x42\x96\x6a\x00\xef\x52\xc7\x29\x90\x19\xf6\x8a\x2d\xf0\x8c\x8b\x70\x4e\x85\xe7\x13\xc3\x48\xd7\xf1\x67\x76\x60\xe1\x8e\xba\xb5\x9b\xf4\xe1\x2e\x6f\xf2\xd7\x83\xd8\xd5\xd4\x2a\xab\x6e\xf0\x17\xb7\xa1\x96\x6a\xee\x8d\xc1\x4d\xda\xbe\xd4\x9b\x4b\x64\x3d\xf4\xe9\xb0\xb6\x03\x83\xc7\xd8\xb4\xb8\x8c\x65\xa8\x98\xc1\xc7\x7d\x43\xd6\xbd\x68\xb2\xa5\x74\x3f\x1f\xed\xd6\x54\xdc\x84\x49\x6d\xa0\x2c\xeb\x69\xb9\xb4\xd3\xa8\xe0\x0c\xcd\x72\xe7\xc7\x5f\xc5\x0a\x8d\xd0\x87\xe1\x83\xe6\xc1\xf5\x79\xba\xeb\xc5\xc6\x3f\x28\x07\x93\x67\x91\xb5\xfe\x48\x47\xcd\xcf\x15\x17\x74\x23\x52\x05\xcd\x2d\x7b\x8b\xf4\xae\x88\x19\x22\x5e\xa7\x08\xb7\xba\xac\x66\x99\x8f\x0c\xba\xb2\xc7\xdd\xf2\x51\xf3\xb1\xde\x10\x17\xd3\x97\x69\x22\x05\xee\xa6\x39\xf1\x2d\x77\xbe\xef\x6c\x13\xbb\x12\x10\x0f\xf8\x90\x64\x70\xbc\x7b\x21\x29\x80\x53\xbe\x1a\x61\xb7\xb3\xa4\x99\xed\xc3\x10\x99\x6c\x8b\xc0\x87\x19\x07\xca\x46\x8e\x89\xed\x31\x1a\xdc\xa2\xe2\xb8\x29\x30\x97\x5b\x3e\xfb\xbf\xc0\x3c\xdd\xf4\xd9\x48\xc4\x76\x5e\x8c\x10\x59\x08\x82\x16\x9a\xcd\xdb\x8f\x8c\x36\xd8\x4c\x2d\xac\x3b\x79\x8e\x7a\xbf\x84\x47\x12\xfa\x45\x8d\x27\x7c\x24\xe8\x14\x04\x7d\x74\x23\x19\xa8\x34\xdd\x9f\x92\x7a\x2b\x44\x85\xef\x13\x74\x5f\x7a\x60\xdd\x6b\xb3\x37\x93\x63\x04\xc9\x7d\x3f\x9f\x14\x4e\xb2\x9b\xb6\x95\xb8\xdc\x31\xb9\xd8\x49\x10\x61\x1d\x28\xd5\x81\xca\xa9\x36\x5d\x6d\xff\x52\xd4\x10\xa4\xad\x52\xbd\x12\x17\x29\xff\xf5\x28\x88\xf4\xda\xae\x17\x07\xf6\xf5\x6d\xac\x61\xff\xb9\x96\x1c\xda\x71\x76\xaf\x44\x60\xa6\xd5\x54\x2a\x20\x44\x6f\xb5\x14\x7f\xce\x72\x72\x04\xce\xc6\x89\x9b\x9a\x3d\x4f\xf6\x22\x6b\xb8\xa1\xc7\x8e\x36\xfc\xdd\x9e\x50\xc0\x40\xd7\x2d\x0f\x40\x07\xd3\xfa\x9a\xa7\x67\xe4\xab\xd0\xad\xd6\x2f\xdb\xcc\xde\xff\x67\x21\xeb\x25\x9e\x00\xa7\x21\x63\x20\x06\xbe\xde\x0d\x17\x3d\x38\x34\x4d\xea\x44\xf9\x6b\x67\xd9\xa2\xee\xa1\xd2\xaf\x5f\x74\x8e\x8e\xbd\xb4\x41\xbf\xb4\xe5\x8e\x2d\x42\xfe\xc7\x40\x56\x6a\xcf\x73\xa3\x03\x35\x8f\x7d\x89\xc8\x15\x8c\xf2\x1f\xe8\x5b\x0d\x4a\x41\x7e\xbd\xc8\x6d\x04\x69\xf6\xb9\x1c\x24\xad\x61\x0d\x48\x6d\xed\xc2\x18\xb2\xce\x7a\x8b\x96\x75\x47\x23\x15\x1f\x0d\x00\x76\xff\xf9\xf1\x9d\x11\x2d\x9c\x05\x92\xfb\x8d\x92\xc9\x9d\xcb\x8d\xdf\xaa\x46\xfb\xe0\xd9\x2d\xf4\x6b\x8c\x00\xca\x43\x45\xad\xb6\x9a\x5a\xca\x69\x4a\x86\xcf\x30\x64\x64\x51\xbb\x17\xba\x6e\x60\x7a\x91\x2b\xf1\x09\xd5\xfc\x2d\x3e\x27\xd0\x0d\x94\x56\x00\xa8\xa5\x7c"}, -{{0x43,0xbf,0xb3,0xdb,0xe4,0xd9,0xbd,0xaa,0x82,0xb3,0x54,0xdd,0x59,0x63,0x34,0xe6,0x60,0xd7,0x6f,0xc0,0xb2,0xeb,0x69,0x89,0x93,0xae,0xf3,0x76,0x7f,0x1c,0x7c,0x7f,},{0xd0,0x0a,0xec,0xef,0xf0,0xce,0xb8,0x32,0xc2,0x51,0xd1,0xfe,0x6b,0xcb,0xea,0xea,0xcb,0xb4,0x11,0x3f,0x52,0x81,0xba,0xba,0x4e,0x87,0x8f,0x7b,0x95,0xf9,0x3f,0x07,},{0xa9,0x99,0x55,0x23,0x02,0x0a,0x0d,0x22,0x2b,0xc4,0x8f,0x98,0xd0,0x55,0x04,0xe3,0x06,0x8f,0x30,0x4a,0x6d,0x19,0x70,0x06,0xcc,0x9c,0x03,0x5e,0xea,0xde,0x09,0x9e,0x7a,0xa9,0x7e,0x90,0x89,0x4e,0xad,0x17,0xe8,0xc3,0x0b,0x0a,0xa4,0xa9,0x80,0x88,0xf0,0x38,0xb9,0x22,0x44,0xc4,0xb2,0x0f,0xde,0x96,0x4f,0x85,0x34,0xe8,0xfb,0x03,},"\x3f\x3e\xed\xdc\xae\xf4\xe1\x66\x2a\xdb\x66\xbb\x1b\x20\x7d\x79\x3f\xcb\xef\x81\x50\x05\xe8\x26\x43\xed\x70\xc9\x85\x54\x03\xda\xc2\x8b\x52\x07\x27\xa9\x01\xa5\x32\xd2\x8b\x9b\xd1\x34\x8d\xb2\xf8\x96\x7b\xbb\x8c\x90\x98\xb0\x7f\x57\x0a\x2e\xae\x1e\xe4\x82\x64\x0c\x0b\x67\xa5\x2a\x38\x61\x21\x33\xa1\x5e\x25\x8e\xde\x38\xcd\xa8\x78\xff\x36\xed\x32\x1d\xff\x87\xcc\x6a\x01\x38\x3b\xa8\x40\x67\xd6\x0a\xf4\x17\x76\xac\xf8\x0a\x8a\x4e\xac\x77\xf7\xd8\x7c\x37\xa7\x04\xa3\xe2\xac\xa1\xe8\x81\x5e\x49\xfb\xca\xb7\x97\xc8\x56\x52\x95\x38\xbe\x07\xd5\x16\x96\x32\x1f\x69\xb0\x9b\x5d\xc5\xa1\x5e\x5f\x0e\x4c\x22\xd2\x28\x37\xf6\x2e\xe4\xc8\xbc\x7f\x25\xa9\x48\x7b\x96\x2c\xc2\x0f\x13\x3f\xcb\x87\x0e\xd1\x25\xcc\xa5\x85\xd1\x81\xbd\x39\xf9\xdf\xa6\x61\xf1\x9b\xe7\x6d\xa7\xf6\x5f\x22\xfb\xbc\x80\x75\x2a\xeb\x39\xe8\xd5\x9e\xd9\x6e\x14\xf5\x95\xd0\x49\x29\x40\x2b\x50\x29\xc6\x0c\xee\x37\xc0\x21\x7b\xc5\x31\xd8\x0d\xb3\x41\xda\xce\x3c\xce\x76\xe6\x43\xaa\xc5\x38\x87\x47\x3e\xdc\x6e\x19\xcb\x39\xfe\xcf\x6a\xf4\x24\xa2\x06\x63\x93\xd1\xc3\x3f\xc7\xb9\x36\x76\xd7\xe6\x10\x5b\x9b\xfc\x96\x7d\x1e\x29\xaf\xdc\x4c\xf1\x5b\xca\xfa\x09\xc2\x95\xa6\xf9\xde\xee\x33\x1a\xb3\xb0\xd4\x93\x12\x6e\x2b\x2f\xff\xb4\x2a\x6b\x68\xe7\x9e\x13\x8d\xb5\x50\x82\x72\x62\xe4\x87\xa8\x3f\x37\xf0\x1d\xd7\x92\x2b\xe7\x5e\x92\xfc\xf5\xd9\xd4\x80\x3b\x3a\xc2\xf3\x5d\xa2\x10\xfb\x38\xb2\x63\xb0\xff\xb6\xc2\x70\x8d\x4b\x55\xb7\x57\xaf\x52\x07\x7a\x7e\x31\x84\xd0\x1e\x82\xf6\x4d\x32\xcc\xe4\xfd\xee\x0f\x8d\x4e\x36\x4b\xcf\xb9\x58\xeb\xbf\xdb\xb6\x22\xb3\x8b\x51\xe9\x30\x27\x1c\x7b\x1b\x70\xaa\x9d\x4b\xb3\xaa\x4b\x99\x7c\x52\x14\x4d\x3a\xa6\x21\x62\x57\x3a\x3a\x1d\x9c\xe4\x6c\xdb\xee\xb8\x44\x9f\x12\x25\xc4\x49\x63\x1e\x88\x97\x52\x1c\xd0\xf6\x37\xb7\x21\xa1\x25\x2b\x8a\x10\xab\x0b\xe8\x70\xaf\xbc\xd8\x9d\x58\xb2\xeb\xb6\x32\x11\x95\x0c\xad\x7a\xb8\x2c\x81\x95\x02\x6b\x50\xea\x8b\x77\xb9\xe9\x0e\xd5\x59\xaf\x44\x84\x30\x88\x51\xa3\xa1\x56\x71\x68\x53\xa8\xac\x4e\xcb\x8c\x5c\xc7\xd9\x35\xb0\xf4\x66\x12\x41\x43\xb1\x17\x7f\x05\xd0\x8b\x97\xd1\xad\x54\x2e\xd2\xc2\x46\x5a\xf1\x85\xe7\xdb\x42\xb6\x9c\xb8\x02\xa7\x17\x94\xa3\x13\x98\x83\x02\x96\x70\xc9\x56\x74\x2a\xaa\xd7\x90\x7a\x71\xd9\x59\x85\xfc\x1d\x45\xb6\x59\x97\xb4\xec\x6c\xe8\x25\x5d\xe9\x59\x27\x0a\xfa\x7d\xe9\x0f\x29\x29\xde\x63\xf9\xb1\x72\x11\xd7\xf1\xae\x82\x0a\xda\x9c\xe3\xe4\x86\x49\x17\x9d\x60\xb0\x14\x94\x93\x48\x1f\x01\xd4\x59\xdb\x7d\xad\x05\x26\xb5\xbd\x9f\x4b\x33\x80\xd2\x5b\xa2\xc5\x02\xba\x8f\xa3\xc4\xd4\x13\x1b\x46\x62\xad\xde\xfb\x41\x82\x7f\x75\x9f\xa7\x1d\x44\x7d\x5f\x02\x92\x45\xf4\x8c\x62\x2e\xb7\xc6\x8c\x8e\x71\x08\x1f\x7f\x78\x9d\xe7\xa2\x83\xd2\xed\xa8\x3a\x7d\x17\x22\xa0\x5f\xb7\x2e\x17\x60\xc2\x40\x40\xc4\xd8\x34\xde\xf5\xdf\x5f\x74\x2e\x02\xb3\x04\x51\xc8\x93\xbc\xf7\xd7\x71\xdb\x78\x4c\xbb\xda\xec\x87\x6d\x8a\xc8\x67\x43\xb5\x29\xa2\x92\x00\x7a\xc7\x53\xc9\x9a\x57\x99\xcc\x32\x4f\xe5\xeb\xb5\x44\x8a\xb5\x54\xb1\x0d\x41\x36\x97\x4a\x12\x54\x2d\x25\xc6\x14\x7c\x67\xc5\xd2\x33\x6c\x9d\xb7\x5c\xba\x2f\xd6\x08\xcd\x43\xab\x95\xbe\xac\xd0\x43\xa1\x34\x9c\xef\xa8\x28\xe2\x3b\x5f\x0b\x6e\x0e\x29\x51\xf3\x35\x3b\xb9\x2b\xfd\x1f\x0a\x49\xc3\x3f\xb3\xcf\x37\x99\xa0\xb5\x43\x19\x8a\xd5\xd0\x3d\x26\x3c\x1a\x06\xc3\x5a\x26\xad\xe1\x51\x84\x91\xc8\xc1\xd2\x7a\x2d\xb0\x33\x80\x89\x32\xcd\x1c\x47\xb5\xa1\x26\x98\x5a\xcb\x8d\x88\x83\x60\xee\xcc\xfe\xb3\xbf\x51\xb0\xd1\x89\xb4\x19\x04\x40\x40\x4d\x12\xfb\xa6\x5d\x0a\x7a\x14\xc6\x20\xc5\x55\xf8\x22"}, -{{0x51,0x4e,0x07,0x0b,0x01,0x90,0xd1,0x8c,0xbe,0x98,0x1a,0x5a,0x15,0x1e,0x77,0x53,0x39,0x8a,0x27,0x2b,0xcf,0x01,0x48,0x13,0xad,0x37,0x97,0x22,0xc3,0x6e,0x13,0x3d,},{0x6f,0xbd,0xe0,0x47,0x4c,0xc4,0x81,0x0e,0xff,0xa5,0x0a,0x07,0x82,0x0c,0x96,0x5a,0xa0,0x03,0x95,0xff,0x3a,0x5b,0x3e,0x2e,0xdd,0x7d,0x35,0x6b,0x7d,0x6a,0xef,0x2b,},{0xb6,0xc3,0x55,0xc9,0x58,0xb5,0xba,0xa7,0xeb,0xe9,0x77,0xa9,0x3f,0xcf,0x53,0x95,0x89,0xa3,0x66,0xd4,0x01,0x60,0xe4,0xe0,0x31,0xb8,0x8a,0xb9,0x64,0x02,0xc7,0xbd,0x57,0x7f,0xf6,0x35,0xfc,0x07,0x78,0x24,0x23,0x59,0x8d,0xca,0x43,0x66,0x81,0x24,0xa8,0xb2,0x87,0x51,0x0e,0x2c,0xfd,0x07,0xa1,0xe8,0xf6,0x19,0xf6,0xc8,0x54,0x0a,},"\x83\x14\x55\x76\x2a\x5d\x80\x09\x7b\xb2\x84\x50\x42\xf4\xc8\x76\xe7\x10\x85\x35\xbe\xd6\x83\xe8\xc4\x46\x19\xd0\x81\x54\xa2\x29\x44\x4b\x10\x1e\x3e\xd7\xc0\x15\x07\xe8\x70\x94\x14\x46\xaf\x97\x8c\x0f\x53\x41\xd1\xac\x1d\xd1\x5b\x14\xe8\x96\x67\x12\xdf\x19\xf5\x2f\xeb\x51\x03\xcf\x62\xb6\x63\x27\x56\x44\x6c\xc7\x54\xdf\x00\xa3\xf6\xdd\x71\x99\x68\xa2\xce\xf6\x6c\x3a\xdf\xb7\xd1\xfc\x49\x1f\xbb\xf3\xd5\x92\x94\xab\x34\x61\x9e\x17\x6d\xb0\xd4\x46\x15\x1e\x37\xea\xa3\xda\xf1\x72\x40\x6e\x98\x3d\x9d\x23\xa6\xb6\x9e\x92\x97\x60\x30\xf5\xac\x70\x40\xad\x51\x14\x12\x9f\xea\xf9\x7a\xf1\x5b\x22\x96\xfa\xe7\x04\x92\xdb\xbe\xb2\xb4\x82\x76\x87\xfb\x79\x87\x15\xc9\xbb\x2c\x32\x55\x7a\x81\xd8\x91\xb8\x97\x05\x29\x00\x70\x71\x59\x75\x1f\x07\xdb\x07\x4c\x77\xf0\x71\x96\x71\xf1\x76\x66\x89\x02\x9a\x3c\xdd\xf3\x9d\xf3\x48\x3c\xf2\xb0\x4f\x71\xc2\x5d\xe0\x5f\xc2\xd0\x2b\xb4\x8e\x53\x9e\xaf\x1a\x32\x16\x46\xcd\x80\xef\x2f\x0a\xc7\x03\xf4\x5e\x73\x89\x53\x08\x00\xe5\xd4\x17\xcc\xea\x8a\x5c\x08\x66\x82\xf0\x47\x45\xd5\x0b\x5d\xfc\x8f\x6e\xdc\x87\xa9\x5c\x7d\x20\x2a\x9c\xfd\x99\x87\x14\xb7\x46\x92\x0e\xbb\xe2\x33\x5b\xca\x1a\x01\x71\x76\x20\x16\xf5\xe4\xbd\xa8\x9c\x57\xd0\xed\xc6\x91\x0c\x6d\x22\xc8\xf9\x09\xda\x3d\xb1\x35\x2f\x0c\x8b\xd1\x8f\x3b\x5a\xac\x25\xf1\x93\xb8\x94\x70\xf9\x76\xbc\x4f\x1a\xff\xb3\xc6\x6b\xc5\x87\x6c\x6f\xe2\xac\x75\x08\x53\x3d\x97\xbb\xcf\x77\x11\x9d\x9a\xae\x19\x3f\x07\xe0\xb6\x4b\x46\x1c\x9c\x6c\x3b\x9d\x29\x3b\xd3\x7d\xe3\xd8\xe1\xab\x1e\x8d\x87\x2c\xd9\x4e\x6c\xf0\xeb\x68\x43\x9f\xdc\xd3\xb2\x5c\xe8\x48\x34\x60\xbd\x8b\x7c\xce\x88\x9f\xb7\x22\xb4\x36\x1e\x11\x8d\xa9\x83\xef\x4a\x9e\x45\xce\xbc\x0c\x1b\x82\x29\xea\x53\xe6\xf5\x55\x05\xf6\x44\xe0\x9a\xca\xa4\xc4\xb8\xcc\x64\x0b\x2c\xd2\xb3\x12\xe1\xc3\xa2\xc0\x26\x69\xe1\xf9\xc0\x63\x11\xc7\x8d\x36\x00\x09\xdb\x9e\x67\xc3\x9b\x49\xd1\xe5\xd7\x70\xc0\x1d\x28\x4b\x0a\x17\xa4\x1b\x4e\x7c\xa7\x45\xd6\x65\xec\x07\x50\x0e\x4d\x9f\xc8\xeb\xc1\xcc\x6a\xf5\x3a\x3f\xc7\x6b\x0c\x3f\x14\x31\xd4\x98\x43\xf2\x0e\x18\x27\x82\xc8\x2b\x3b\x5a\xae\x36\xfe\x20\xca\x64\x26\x18\x06\x8b\xe2\x33\xd4\xb5\xef\x9e\xae\xff\x40\x15\x36\xdc\x59\x3a\x2b\xc1\x83\x44\xf5\x5a\xc5\xd5\xfc\x7b\x3e\xb5\x06\xd1\x1c\xb3\x75\x33\x00\x63\xc6\x20\xc5\x33\x4d\x72\x3c\x7d\x1f\x04\x28\x16\xbc\x47\x85\xb3\x5a\xc0\xe6\xf1\x74\xf7\x36\x87\x8b\x7b\x49\x16\x58\xca\x67\xd8\xfc\xab\x53\x8f\xc6\xec\xd2\x77\xea\xd9\x0d\x95\x4b\x46\x0d\xa4\x25\x3a\x1c\x3a\x30\xb3\xd8\x92\x8f\x69\xac\x98\x76\xa2\x89\x19\x69\xfc\x2d\x06\xa6\x68\x99\x2b\x8e\x21\x15\xdf\xe5\x35\x8a\x71\x24\xba\x7c\xcf\x42\x1d\x80\x54\xea\x04\x34\x44\xcd\xeb\x40\xb7\x16\xdc\x7a\x36\x59\xa3\xca\x94\x34\x72\x93\x48\x90\x60\xe2\xcf\x67\x12\xa2\xa6\xc7\xb8\xad\x14\x67\x85\xfc\x40\xcc\xb9\xda\x28\x78\x30\xd0\x11\xd0\xd2\x4d\xf3\xe7\xaf\xbe\x97\x2d\x6f\x41\x7d\xe5\xcd\x75\xf2\x59\xea\x07\xca\xfd\xde\x20\x5f\xc0\xa3\x65\x13\x5c\x23\x2c\xbd\x7c\x1b\xc5\x39\xfa\x4b\x7e\x1c\xce\x35\x18\x52\x37\xc2\x3f\x80\xae\x97\xc1\x86\xd0\xd3\xb1\x05\x03\xd5\x98\x4a\x20\xec\x41\xc3\xcd\x04\x2c\x28\xa4\xc3\x1f\x95\x74\xb0\x6a\x87\x2b\xf9\x59\xab\x0a\xdd\x1f\x5d\xee\x14\xa1\xe7\x41\xef\x23\x8d\xfc\xde\xc0\x85\xaa\x08\x8d\xcf\x39\xa3\x6d\xda\x8f\x2a\x85\xed\x0d\x36\x2c\xcb\x00\x5d\x02\xe5\xac\xcc\x09\x2a\x37\x6d\xc1\x1a\x56\x61\x70\xd5\x83\xdb\x35\xf1\xde\x0b\xe3\xf1\x59\x08\x59\x6e\x9b\x78\x1a\xc8\x1b\xe0\x7b\x9b\xd2\xaf\x46\xc5\x6f\xb4\xd9\xd8\x42\x76\x01\x1e\x46\x18\xb7\xf7\x6f\x96\x79\x4c\xd0\xfd\x57\xed\x41\x4b\x63"}, -{{0xbc,0x79,0x0a,0x73,0x85,0xdd,0x1d,0xdd,0xc7,0x62,0xe3,0xb2,0x02,0x21,0xdc,0x07,0x8b,0x6c,0x3d,0xa8,0x98,0x6d,0x41,0x80,0x94,0x07,0x27,0x25,0x7c,0xfd,0xcd,0xf1,},{0xc9,0x26,0x46,0x26,0xf6,0x8f,0xed,0xb5,0xb3,0x9c,0x28,0xf0,0x30,0x45,0x3b,0x54,0xd0,0xd5,0x1a,0x98,0xb1,0x77,0x21,0xf2,0x61,0x1d,0x7f,0x27,0x7e,0xf4,0x8b,0x81,},{0x6d,0x6b,0xd6,0x5f,0x37,0x26,0x79,0xfe,0x9d,0x94,0x5f,0xf5,0x65,0x16,0x33,0x3e,0xce,0x0b,0x7a,0x25,0xb1,0x5a,0xd2,0x48,0x73,0x81,0x67,0x0e,0x53,0x6f,0x52,0x46,0x77,0x5e,0xb3,0x9a,0x11,0x4d,0xb2,0xb9,0xcd,0x50,0xf3,0x12,0xb3,0x60,0xd9,0xd0,0xbe,0xa2,0x95,0xdc,0x37,0xb8,0x17,0xb3,0x32,0x89,0x0a,0xdb,0x65,0xe4,0xc4,0x01,},"\x14\x3d\xd7\xbf\xbf\xf2\xad\xc7\x1f\x5d\x12\x3d\x47\x4e\xa0\x69\xdf\x14\xae\x92\x3e\xd9\xbf\x8f\x98\x91\xe6\x0b\xae\x43\xf0\xc9\xf5\x55\x37\xac\x9d\x1a\xe5\x23\xce\x4e\xcf\xd3\x3b\x20\xae\x44\x5e\x9c\x42\x63\x72\x05\x0f\xa5\x21\x7c\x1e\x4f\xb0\x13\x53\xeb\xf2\xe3\x29\x04\xef\x7e\xef\xcf\x72\xe8\x02\x3b\xae\x06\xbb\xb6\x40\xcf\x77\x7d\x5b\x0e\x11\x52\x7b\xc8\x35\x49\x3a\xd6\x98\x0a\x15\x7b\xb2\xd5\x0b\xe2\x33\x65\xe7\x2c\xbf\x0b\x3f\x20\x9e\xf0\xc4\x4a\x00\xb4\x1a\x62\x26\x24\x88\x09\x6c\xae\x5a\x69\x6b\x4d\x64\xcb\xad\x34\x50\x0d\x41\xfb\x4e\x4b\xc7\x0f\x8b\xf6\x21\x44\xd0\x1c\x22\x75\xd6\xd2\x9f\x5d\xe7\x5b\x17\x21\xd5\x04\x6b\x68\x29\x16\x44\x43\xeb\xfd\x9c\x17\x81\x31\x9d\x88\xf5\x40\x10\xed\xc2\x96\xab\xbe\xd0\x2b\x7d\xad\x9b\xa5\x85\xb5\x52\xe0\x00\x5d\xcc\xa4\x00\xbf\x4f\x45\x9e\xed\x7d\xb8\x6e\xa8\x61\x2b\xe9\xe9\x18\xdf\xd4\xe2\x70\x0c\x47\x10\x08\x32\x83\x62\x6f\xac\x75\x44\x17\xe0\x08\x7d\x26\xba\x14\x5d\xfc\x45\xb1\xc9\xbf\x7b\x4d\xd7\x0e\x6c\x50\x87\x47\xef\x80\x5c\x9a\x02\x42\x5a\xeb\xc6\x42\x1e\x0d\xeb\x6a\x79\xd8\x9a\xce\xee\xe0\x1e\xce\xcc\x9f\x3c\xa3\x65\x38\x38\x26\x58\x4c\x43\x0e\xbd\x39\xec\xf0\xa7\x28\x66\xae\x0a\xce\xca\x5a\xd4\xf0\x40\x5b\x67\x77\x9c\x04\xc5\xde\x03\x30\x61\x4d\xa3\x47\x0b\x80\x5d\x78\x7c\xe7\x9a\xc5\xa6\x96\xdd\x6f\x6b\x55\x39\xb1\xa6\x51\xb4\x24\xce\xfb\x19\x49\x1d\xa6\xe0\x88\x92\x23\xcc\x98\x39\x8b\x42\xc0\x04\x14\xff\x8d\x6c\x06\x27\xeb\x97\xcf\xf2\x0a\x8c\xbe\x7f\xcc\xb4\x1d\x81\x0f\xcf\xe8\x58\xca\x74\x75\x24\x7e\xf6\x28\xe8\x4a\x09\xd0\x12\xfe\x12\x23\x5b\x38\xc1\xcc\x9d\x82\xe2\xb6\x9d\x01\xd6\x21\x8c\xfd\x48\xe8\x5f\x26\xae\xad\xd1\x95\x40\x8c\xdd\x4c\x2f\x80\x6a\x89\x04\x1f\xd0\x31\x7f\xb1\xa7\xb6\x20\x9f\x90\x42\x70\xd3\x4e\x60\x61\x95\x04\x72\x88\xb0\xfb\x11\xa5\x72\x29\x38\xf6\x7c\x22\xb3\x13\xf7\xf7\x4b\x20\x25\xc7\x5b\xcd\x1e\xcc\x5a\x9a\xdd\x4a\x64\x0a\x41\xf2\x99\x6e\xb6\x6e\x5a\xf1\x96\x19\x8d\xb5\x8a\x3f\xb9\x93\x8f\x34\x9f\x92\x2a\x24\xd8\x6f\x4e\xd8\xa9\x6a\x09\xa1\x96\xc2\x4d\x6d\x01\xed\x76\xf3\x81\x6c\x05\xc4\xf2\x6b\xac\xa9\xb9\xd6\xdc\xc7\x9b\x58\x0d\xfb\x75\xd6\xc9\x05\xd4\x80\xda\xd7\x69\x51\x85\x4b\xda\x1c\xaa\x7f\x4a\x81\x95\x43\xae\xd0\x1a\xe9\x56\xbf\x30\x58\xfe\x8b\x3c\x7d\x5d\x72\x49\x62\xf1\xa6\xa8\x31\x43\xdd\xad\x27\x4f\xda\x3a\xd5\x78\xe9\x8a\xa9\x67\xc4\x10\xee\x57\x57\x5e\xf0\x1c\x02\x58\x56\x0f\x0a\x1f\xa4\xb7\x93\x27\x79\x6d\xe9\x94\x20\xcf\xd0\xa4\x15\x50\x63\x60\xf1\x24\x2c\xcc\x58\xa6\x88\x09\x27\x75\x0d\xbb\xff\x13\xd7\xc1\xb4\xed\x51\x9c\xda\x35\x72\x10\xf1\x2f\xb0\xd1\xc4\xd4\x8f\x04\x11\xbd\x7e\x05\x8c\xc4\xcb\x93\xd3\xc7\x75\x97\xe2\x65\x3f\xfa\x28\x2d\x3c\x2f\x12\x8a\xc3\x3a\x23\x7a\xf2\xfc\xbc\x9e\xf9\xc8\x11\xf3\x78\x14\xba\x2b\x0b\x85\x09\x3d\x0f\xd1\x8b\x8c\x6f\xb0\x9a\x43\xce\x52\x25\x4d\x23\xd5\x5f\x32\xe1\xd3\x24\x2a\xed\x1f\x23\xd9\xcf\x20\x4a\xa0\xdf\xd4\x4a\x34\x6f\xe0\x9e\x55\xa4\xa0\x6c\xf1\xbe\xf8\xbb\xf3\x7b\xa1\xf1\x59\x8a\x58\xae\xf8\x95\x01\xec\xba\xc0\x45\x35\x43\xe4\x80\xed\x0a\xdd\xe9\x0c\x84\x1d\x95\xeb\xd6\xeb\x23\xba\xa9\xf7\x0f\x83\xc1\x49\xea\xb3\x2d\x09\x13\xc7\x9b\x09\x93\xd0\xe1\xd3\x57\x4f\x0f\x54\x2e\x56\xa2\x06\x16\xcf\xe4\xa8\xbd\x7a\xae\xeb\xe0\xb0\x83\xdc\x2c\xe0\x14\x61\x78\xc0\x74\x82\xa0\x11\x29\xbc\x6f\xef\xdc\x81\x41\xc1\x38\x48\x94\xb6\x9c\xbe\x2f\x29\xda\x18\x8f\x7f\xd4\xac\x34\x1a\x2d\xf6\xfd\x90\xde\xe6\xa4\x46\xd2\x74\x63\x24\xc7\x5c\x1e\xf5\xb1\xac\xe1\x87\xd3\xbc\x16\xd7\x05\x59\x89\x29\x75\xd7\xe4\x71\x38\xf0\x40\x63\x85\xea"}, -{{0xdb,0x3a,0x44,0xdf,0x40,0xd2,0x55,0xa2,0x5c,0xf2,0x3f,0x53,0xc4,0x52,0x23,0xb7,0xd8,0xf1,0xf1,0xf1,0x11,0xba,0x07,0x40,0x6b,0x71,0xe1,0x84,0xa8,0xcd,0x06,0x12,},{0x6b,0x12,0xbd,0x95,0x80,0xae,0x20,0x7a,0x9b,0x0b,0xaa,0x82,0x87,0xb8,0xbb,0x86,0x66,0x93,0x73,0xee,0x5e,0x5a,0x62,0x5a,0xb4,0xa6,0xef,0x2d,0x08,0x71,0x25,0x97,},{0xcc,0x28,0xb5,0xef,0x4b,0x97,0x73,0x63,0x7f,0xae,0x7e,0x5f,0x08,0x4b,0x69,0x94,0xaa,0x35,0x98,0xf8,0xf4,0xa6,0x5d,0x0b,0xb2,0x01,0xd1,0x72,0xd8,0x61,0xa3,0x01,0x49,0xb3,0x33,0x8d,0x3c,0x3a,0xb7,0x5b,0x32,0xb2,0x55,0x95,0xcd,0x8b,0x28,0x96,0x30,0xc3,0x37,0x6a,0xcd,0x10,0xba,0x2a,0xb2,0x6b,0xc1,0xab,0xa9,0x00,0x84,0x0e,},"\x52\xdd\x8b\xa4\xff\xfa\x34\x4d\x1e\x08\x11\xd9\x67\x5c\x31\x3f\x9c\xc0\xe5\xa1\x38\x47\x86\x91\x98\x9d\x2b\x7f\x73\x89\x02\x50\x68\xfa\x35\xf7\x4f\x9a\xea\xf1\xe9\x56\x65\xec\xf8\xd5\x70\x7f\x75\xf6\x5f\x22\x56\xee\xa9\x33\x98\xbe\x59\xc0\xd5\x38\xf5\xe8\x58\x4b\xfb\xb3\xa2\x40\xf5\x01\x6d\x79\x27\x23\x4c\xb3\xea\xc3\x5b\x39\x1b\x8b\x53\xf2\x0e\xd8\xba\xe0\xba\x11\x08\x96\x94\xbf\xea\xde\x11\x07\x16\x56\xd4\xcf\x18\xef\x2d\x36\x81\x92\xe0\x4e\x08\xe3\x02\x4f\xc1\xd2\xfd\xa6\x31\x2a\xfc\xa6\x8d\x10\xc9\xc3\x36\xa0\xe3\x68\x50\xbe\x1a\x4f\x35\xb0\x33\xa8\x5a\x2a\x95\x49\xf2\x67\x3a\x99\x5f\x2a\x9a\xb4\xbd\x46\xc8\xfd\x2d\x83\x8e\x64\xf7\x61\x71\x34\x27\x32\x9c\x9a\xf5\xe4\x21\x1a\x22\xab\x20\x8a\xaa\xb8\x0e\x19\x4c\xd0\xf6\xa5\x02\xb3\x08\xfe\xd6\xc5\x83\x51\x78\x01\xa4\x8e\xd4\x33\x0e\x2f\xad\xdc\xd4\x18\x09\xc3\x91\x9b\x30\xe8\x4d\xb3\xc6\x87\x31\x03\x1e\x79\x85\x7d\xd9\xf9\x7f\xfd\x12\x54\x7d\xa7\x06\x67\x98\x07\x41\x51\xec\x88\xa5\xfa\x96\x3b\x9d\x9d\x83\xba\x2f\xee\x13\x58\x33\x95\x0e\xf7\xbc\x62\xb3\x40\x1e\xa1\x1b\xb3\x6f\x25\x56\x1b\xc0\x52\x2b\xb0\x2d\x8d\xad\x05\x43\xf6\x3d\x54\x7b\xe7\x7d\x0a\x4c\x9b\xf6\x5d\x42\xf3\xa2\x76\x14\x4d\x2e\x47\x4e\x29\x42\xf3\x79\x02\x21\xe2\x6f\xba\xe7\xca\x91\xef\xd8\x59\x21\x99\x08\x35\xfa\xfb\x6d\xc6\x74\x63\x5c\x96\x01\x82\x10\x38\xb5\x27\x11\x34\x3d\x1a\xa2\x5f\x1c\x46\xba\x4e\x3c\x6e\x71\x2b\xac\x19\xe5\x3e\xae\x30\xe5\x24\x6e\x4f\x04\xdd\xf2\xac\xdb\xb3\x41\x63\xc2\x43\x67\x76\x90\xbe\x0b\xf2\xe3\xfa\x16\x48\x70\xb5\xe6\xf5\x36\xb2\x2f\xb8\x9e\x5e\x8e\x1d\x87\xcd\xb3\x40\x44\x97\x7e\xd2\x83\x6e\x54\x4d\x7b\xa4\x93\xdd\x42\xa2\xb6\x49\xbc\xf3\x13\xc5\xb3\x9a\x1d\xbf\xff\x3e\x7f\x2a\x59\xad\xe8\x7d\x3e\x7b\x25\x8f\x58\xe5\x65\xfd\xba\x3e\x4d\x92\xb1\xed\xb8\xbf\xf5\x4d\xc4\x9d\x86\xc5\x3c\x03\x0c\xf5\x8b\x97\xef\x06\x6d\x24\x1b\x54\x05\x30\x21\x39\x05\x73\x9d\x8e\x1a\xa7\x2e\xd9\x0f\x68\x5d\x39\x58\xea\xa2\x42\xb0\xcb\xf7\xa2\xeb\x97\x6e\xe9\x6a\x63\xe6\x67\x86\x46\x41\x69\xa7\x42\xd4\x57\xe4\xd9\x11\x7c\x7d\x66\x42\x84\x45\xa4\x69\x30\xc2\x8b\xa7\xa2\x65\x82\x41\x80\x5e\xbe\x72\xc7\x8e\x02\x03\x5d\x26\x3a\x21\x1e\x59\x0b\x49\x0c\xdb\x84\x41\x50\x62\xee\xd1\x4f\x13\xb8\xa1\xa9\xe7\x7c\x8d\x7b\x75\x51\x5b\x18\xfb\x85\x38\x6e\x4a\x7e\x05\x39\x80\xd3\x0f\x48\x99\xe8\x38\x63\xbe\xe8\x75\x58\x58\x87\xc5\xf4\x8b\x51\x6c\xcb\x73\x1c\x4b\xca\xa3\xdf\x07\xd0\x47\x95\x81\x40\x96\xc7\x9d\x7c\x5f\xdc\x4d\xab\xf5\xe2\x6a\x4c\xa1\x83\x8e\x0e\x5d\x87\xdb\x71\x30\x9b\x81\xea\x7c\xe4\x61\xe5\xe4\x4c\x7a\xb2\xf1\x05\xad\x75\xc5\x43\xc1\xe9\x17\x9c\x36\xa5\xfa\x55\x5e\xc9\x22\xff\xed\x1b\x76\xd2\x58\x01\xdd\x74\xf8\x0c\xd0\xa6\xba\x7b\xc2\x0d\xb0\xad\x58\x0b\x7b\xbb\x9d\xdc\xfd\x93\xad\x1c\x5f\x20\xf3\xe2\x7c\x3e\xa3\xa1\xe7\x1e\xb7\x4f\xf5\xf9\x44\xcd\x3b\x98\xf6\xd0\x45\x29\x59\x30\x11\xc4\xae\xce\xf6\xdc\xaa\x60\xfb\x18\x36\x8c\xb1\x2b\x6e\x39\x1b\x3f\x5d\xf7\x65\xcb\xab\xff\x15\x89\x8c\x84\x79\x6f\xc2\xb5\x3f\xa4\x90\x0d\xad\x03\x4a\x13\xb0\xce\x14\x45\xad\xda\x4e\xf7\x19\xbe\x74\x14\x19\xe2\x31\xe9\x2f\x1f\x66\x7a\x32\x84\x2a\x42\xdb\x79\xbd\x7a\x01\x4a\x80\x9c\x81\x59\x6e\x82\x62\x73\xd1\x6f\xe5\xd4\x04\x58\x24\x2a\xe1\x0e\x12\xe6\x0b\x34\x89\x53\x0c\x66\x22\xb5\xbb\x44\x45\x4f\x29\x61\x6e\x47\xe9\xa2\x97\xce\x1c\xa0\x74\x13\x7f\xd9\xae\x13\xe3\xee\x8e\xdb\xcf\x78\xaf\x26\x54\x59\xdb\x1a\xf3\x42\xdc\x0b\x2f\xc8\x09\xbd\xa0\x15\xb5\xa8\x2b\x2b\x7c\x54\xef\xe4\xe5\xfc\x25\x2e\xb1\x3d\x66\xe8\x08\x93\x6f\x19\x10\xf4\xc4\x8b\xe0\xef\x7a"}, -{{0x77,0x96,0x4d,0xad,0x52,0xb5,0x79,0xb8,0x96,0x67,0x53,0xda,0x31,0x86,0xd1,0xc5,0xe9,0xd3,0x3d,0x33,0xa4,0xdb,0x38,0xbc,0x0d,0x7a,0x1a,0x6c,0x11,0x2c,0x13,0xc2,},{0xfc,0x25,0x12,0x5e,0x78,0x29,0xf6,0x42,0x34,0x37,0x5e,0x52,0xae,0x9f,0x77,0xae,0x10,0x13,0xf9,0x9d,0xf5,0xf9,0x96,0x5a,0xd2,0xaa,0x16,0x58,0x95,0x96,0xd0,0x91,},{0x3d,0x1b,0x4b,0x4e,0x82,0x0d,0x25,0x0b,0xe2,0xa8,0xfa,0x97,0x1e,0x59,0x9e,0x1e,0x98,0x97,0x75,0x28,0xb2,0xf9,0x30,0x18,0x96,0x81,0xa9,0x3b,0x05,0xe1,0xa7,0x06,0xfc,0x80,0xef,0xfa,0x94,0xe9,0x29,0xbc,0x43,0x92,0x16,0x56,0x89,0x73,0x88,0x28,0x8a,0x9b,0x29,0x27,0x1f,0x37,0xa1,0x4b,0xe0,0x14,0xb8,0x73,0xc6,0x8f,0xc9,0x04,},"\xc3\x39\xe7\x18\xa7\x57\xf3\xf3\xbd\x1b\xab\xdd\x2e\x00\xaa\xa5\xcd\x7f\xc9\x00\x5e\xe3\x4b\x6f\xdc\x09\xd7\x1f\xbd\x9c\x92\x89\xab\x1d\xd1\x4d\xba\x2c\xad\x58\xcb\x80\x51\x16\x77\x7b\xd8\x0c\x85\x96\x64\x33\xad\x46\xf9\xca\x6e\x54\xf1\x3d\xd3\xca\x7e\x56\xe4\x7f\xea\x41\xe5\x48\x8a\x45\xad\x53\xbc\x5d\x65\x74\x27\xe1\xd7\x93\x8f\x55\x19\xf1\xb0\x9f\x5b\xdd\x98\xaa\xe5\xac\x96\x43\xef\x78\xeb\xa4\x93\x49\x25\x33\x9a\x15\x5d\xc6\x68\x28\x57\x10\x02\x09\x7a\x11\xa5\xce\xe7\xb5\x1a\x44\x1b\x75\x6b\x0c\xe6\x5b\x77\x9a\xfe\x19\xda\x6a\x18\xef\xc1\x45\xf6\x09\x0c\xe7\x70\xde\x9e\x0e\x91\xf5\x43\x27\x0a\x09\x85\xea\xb4\x75\x29\x3c\xcf\xdd\x31\x41\xc4\x14\x2e\x47\x22\x23\x3b\x26\x74\x99\x44\x76\x41\x23\x5d\x72\x8b\xd7\x5c\xd1\xad\xc0\xdb\x14\x2f\x73\x31\xad\xdd\xf8\xc5\xee\xa3\xd5\x76\x40\x5d\x86\x99\x15\xb5\x60\xf9\x64\xe3\xe0\x00\x3c\x91\xf5\xe9\x6b\xff\xbe\xee\xc7\x3e\x51\x02\x4e\xf5\x2c\x55\xc6\xdc\xb5\x4d\x58\x20\x3e\x62\xf4\xdd\xb6\xe1\x37\xeb\x08\xe1\xbf\x13\x26\x01\x8a\xfd\x1a\x86\xca\xb6\xc8\x41\xe0\x66\x1c\xe0\xa1\xa7\xae\x96\x7f\x24\xc1\xa7\x7f\xc7\xca\x50\x5f\x72\xe5\xf7\x93\x6e\x39\xc6\xf4\x83\x7e\x25\x95\x19\x5a\x69\xcd\x67\x65\x10\xa7\x16\x1a\x4d\xc5\xe3\x18\xf3\xd4\xf3\xac\x0a\xf0\x3f\x8c\x4a\xe5\xbc\xe3\x93\x24\xe9\x73\x8a\xea\x49\xf0\x02\xd3\x2d\x16\xde\x23\x17\xe9\x5a\x9f\x32\xee\x60\x4e\x13\xdb\x80\x38\xb2\x64\xcf\xc1\x7a\xed\x29\xc9\xde\xbf\x81\x91\xde\x9e\x0e\xfc\x95\x1a\xd6\xd5\x48\x67\x06\x8c\xf5\x0a\x26\x9c\x37\xa2\x41\xf8\x52\x06\x78\x8d\x23\x14\x31\x77\xf6\x59\xcc\xa6\x6c\xfc\xe0\x3b\xc0\x50\x22\x55\x33\x7f\x16\xb3\xda\xd6\xf7\x91\x32\xab\xf8\x0f\xf1\x2b\x6d\x22\x81\xe6\x37\xeb\x6c\x71\xf7\x6e\x26\x33\xa1\x14\x56\x52\x40\xee\xd0\x0f\xab\xea\x9e\xd8\xde\x28\xc8\x32\x21\xf8\xcb\x48\x5f\x51\x2d\x90\x08\xbf\xc7\x4a\x36\x6d\x4c\x2b\x4e\xd1\x72\xd3\x67\xe0\x24\x7c\xb6\x50\x98\xc1\x10\x28\x2e\x83\x1d\xf8\xe9\xbd\x4f\xbd\x5f\x4d\xd2\xb7\xf2\x42\x0c\x23\xb8\x5a\x63\x7a\xa2\x26\x2c\x3c\xb8\x84\x05\xf7\x07\x30\xc9\xab\x4c\x9d\x0f\x22\x7e\xe4\xfa\x4e\xf9\x1e\xfe\x9a\x59\xb3\xe6\xd8\x43\xdb\x87\x9f\x56\x50\x05\x9e\x99\xf0\xe4\xa0\x38\x68\x38\xe6\xf9\x87\x6f\x67\xd5\x0f\x89\x83\x2d\xda\x5f\x30\xa9\xcb\xfd\x71\x01\x34\xf9\xb5\xb5\x46\x27\x49\x6a\xa3\xa4\x32\x12\xb0\x7f\x03\xdb\x11\xd3\xd4\xf8\x75\xd4\x1d\x1f\x4a\xc4\x59\x69\xdd\xef\x69\xf8\x1a\x06\xd2\xb0\xc6\x46\xc9\xcd\x93\x1c\xf2\x50\x2f\xef\x0d\xd3\x2a\xbb\xf0\x95\x1e\xd3\x03\xf5\x28\x48\x25\x93\x43\x97\xfc\x22\xe7\x86\x98\xd3\x5a\xd8\x1d\x82\x25\x6b\xf9\xe1\x54\x00\xa1\x09\x16\x23\xa9\x82\x6f\x1e\x57\x79\x23\x67\x41\x7e\xf0\x25\x86\xd6\x4e\x65\x0d\xa9\xac\xe2\xf1\x8a\xa0\xa1\x26\xd8\x67\xca\xc4\xb5\xd4\xc9\x1b\xf5\x20\x9e\x53\x59\x55\x63\x86\xf8\x27\x08\x3e\xb5\x3e\x8b\x47\x09\xff\xfa\xbe\x92\xc6\x1d\x78\xff\xb5\xda\xf1\x02\x74\xe2\x42\xa7\x00\x91\xf3\xf9\xb9\xd5\x96\xc1\x25\x8c\x9a\x63\x38\x4f\x4b\x05\xb0\x28\x66\x12\x22\x18\x1c\x0f\xca\x96\x5f\x0a\x2c\xb5\x6e\x4b\x55\x6d\x6f\xbf\xf7\x1b\x64\xd9\xb3\x58\xda\x31\xaa\x37\xc7\x4f\xf5\x96\x2f\xb8\xd9\x6a\x38\x3d\x04\x97\x24\xc1\x9e\x24\x9c\x9e\xdb\xb2\xa3\x75\xb2\x3c\xe3\x10\x4d\xa0\xec\x58\xd2\x63\x5b\xa0\x3b\x55\x42\x3f\xa2\xdb\x7e\xb3\x49\xa4\xfc\x58\xa1\xef\x54\x0e\xe9\xa0\x2c\x2e\x70\x3c\x68\xd7\xf8\x47\x5f\x43\x4d\xdd\x32\x00\xdb\x1f\x06\x74\x57\x91\xa3\xac\xc3\x16\x0d\xba\x50\xa3\x93\x44\x7f\xfe\xef\x6d\xc7\xb9\x8f\xb0\x66\x84\xcc\x90\xfd\x85\x20\x3d\x11\x9d\xcd\x81\x99\xe4\xd9\xa8\x9a\xe3\x46\x7a\xe4\xbb\x19\xfb\x71\xcf\x74\x70\x29\xc2\x40\x96\xf9\xa5\x0e"}, -{{0x5c,0xaf,0xd8,0x17,0xa4,0x41,0x0c,0xcb,0x27,0x12,0x17,0x23,0xef,0x32,0x07,0xc1,0x73,0x1a,0x08,0x61,0x94,0x5b,0xe9,0x62,0x71,0x4c,0x0e,0xd9,0x50,0x38,0xa1,0x95,},{0x4e,0xa0,0x86,0xbe,0x43,0xec,0xe1,0xc3,0x2d,0x08,0x05,0x9b,0xba,0xdc,0x9e,0x9a,0x2b,0x2f,0x4f,0x3f,0xe3,0x70,0xf1,0xf5,0xcc,0xd7,0xdb,0xde,0xc0,0xaa,0xf3,0x03,},{0x28,0x85,0x15,0xfa,0x72,0x59,0xf1,0xeb,0x58,0x7f,0xe8,0xa2,0xc4,0x03,0x43,0x4c,0x46,0xf8,0xd7,0xe7,0x5b,0x6d,0x22,0xbb,0x38,0x96,0x56,0x6c,0x01,0x7d,0x09,0xb6,0x98,0xc2,0xc8,0x07,0x79,0x9c,0x2f,0x65,0xf9,0xcd,0xb4,0xeb,0x58,0x15,0x1c,0xcf,0xc4,0x8d,0x10,0x80,0x61,0xa6,0xb3,0x14,0x84,0x32,0xb2,0xbf,0xc1,0xcd,0xab,0x05,},"\x50\xb2\xf0\x53\x42\x41\x80\x46\xd1\x6a\x30\xbe\x4f\xc6\x2b\x67\xda\xf6\xc1\x8d\x2a\x74\x24\x2b\x7c\xb5\x5b\xa9\x0a\xd2\x0b\x6c\xaf\xdd\x60\x15\x57\x37\xc2\x9d\xe4\x8a\xa5\xd7\x99\xfe\x54\x95\xfe\x59\xdf\x5a\x9b\x8c\x0a\x8e\x54\x18\x90\x47\x63\xfb\xad\x83\xea\x69\x86\x65\x1b\xac\x31\x11\x79\x39\xce\xf4\xe0\xc7\x99\x30\xd5\x2d\xfd\x7d\xb4\x3c\x31\xad\xda\xe3\xcf\x93\xe3\xef\xc5\xa9\x16\xef\xd0\xd6\x5f\xdc\x30\x90\x9f\xa3\x56\xcc\xbc\x52\x47\xd7\xaa\xa0\x67\x13\x1b\x6b\x48\x20\xfd\x02\xf8\xe3\x95\xf5\xa9\x70\x4c\x9b\xdd\x75\x60\xa6\x11\xd6\x25\x59\xa8\xdf\xe1\xd2\x85\x9c\x52\x48\x6c\xc1\x1e\xd3\x33\x19\x92\x48\x8f\x41\x75\x20\xd9\x20\xdc\x73\xa3\x2d\x4f\x08\x11\x00\x82\x50\x0f\x5a\x96\x2a\x30\x69\x32\xc6\xa7\x80\x29\x55\xce\xda\xd7\xab\xf5\x3b\x0f\x19\xfe\x47\x94\xa3\x1d\x6b\x85\x53\x80\x28\x43\x06\xcc\xff\x71\xa4\x00\x78\x59\xa2\x32\x8b\xb1\x90\x24\xc4\x3e\x10\xd7\x70\x64\xd8\x66\xd9\x62\x2d\x14\x2c\x27\x35\x4b\x84\xac\x3b\x4f\x82\x32\xf7\xa2\xf8\xaf\x64\x09\xd5\xcc\x75\x7a\x18\xef\x81\x3d\xfa\xf4\xb9\xbc\x04\x0c\xb0\x06\xd7\x7f\x14\x36\x41\xaa\x20\x36\xac\x7b\xc9\x28\xdc\x96\x58\x5d\x9e\x36\xc7\xbc\x9c\x56\x4d\x25\xf1\xc2\xcc\x0b\xea\xb9\xd5\xf2\x07\xe8\x4b\x21\x5f\x1e\x7a\xa6\xfc\x32\x82\x37\xb7\x9c\x39\x92\x3a\x4e\x09\xc7\xc7\x3d\xc6\xb2\x4b\x14\x16\x29\x4d\x79\x8a\x4e\xd5\xf7\x58\x33\x6d\x91\x5a\x87\x0a\x7d\x6b\x75\x92\xb5\xb8\x8a\xac\xe2\xdc\x5f\x26\x7b\xdb\x49\x11\x41\xcb\xba\xe2\xa6\x77\x40\x7c\xc0\x95\x5f\x96\x19\x62\x59\x93\x04\xba\x0b\x83\x96\x71\xa5\xc0\x00\xe9\x20\x10\x8a\x05\x29\x80\x87\xe4\x97\x70\xae\xee\xaa\xb3\x63\x27\x24\xcb\x0f\xc2\x28\x57\x96\xdc\x41\x48\x14\xfd\xa7\x8a\x54\xe6\x7f\x00\xa0\x2f\x77\xd3\xcc\xde\x1e\xd9\xd7\xb1\xde\xf1\x4e\xa1\xf6\x19\x10\xbd\xf3\x0a\x11\x96\xfc\x63\x51\xb6\x22\x54\xd6\x44\x5e\x6c\x90\x44\x5b\x16\xef\xaf\xe2\x89\xa2\x78\x4b\x92\xe4\x2b\x78\xa4\xa9\x00\xc3\x5f\x55\x63\x0b\xbb\x77\x62\xff\x9e\xb7\xfe\xf7\xd0\x4c\x90\xb9\x57\x1c\x4f\xc7\x60\xa4\x10\xdb\xfc\x25\x29\x91\xd0\xba\x27\xf2\xd4\x14\xfe\x64\xee\xfd\xff\x4a\xbc\x18\x81\x7c\x97\x06\xc6\x31\xbf\xa2\x03\x82\x1d\x3b\x92\xcb\x33\x8b\xaa\xf5\xd1\x23\x2b\x46\x26\x47\x95\x4d\x09\x02\x46\x2f\xb1\x69\x6e\x99\x1f\x07\xfa\x9c\x3d\xbc\xf2\x87\x29\x60\x83\x1b\x4d\xed\x92\xa4\x21\xcf\x21\xb7\x53\x16\x5f\xf3\x09\xef\xe2\xef\x54\x38\xc0\x12\x70\xd1\x0c\x6a\x03\xd3\x4f\x71\xeb\xc2\xda\xb1\xda\x90\xda\xa3\x57\x98\x4d\x24\x62\xbc\xb3\x5e\xe3\xde\x55\xc3\xa5\x5f\x8b\x98\xae\xc2\x11\x4f\x74\xc8\x43\x41\xa6\x41\x27\x86\x3c\x12\x0b\x5e\xca\xd9\xe3\x29\xa5\x75\x6a\xe4\xa2\x55\x5d\x84\x92\xcd\xa8\x35\x22\x5a\x8d\xeb\x3f\x9c\x15\x58\xf0\xd4\x25\xbc\x17\x2f\xf7\x64\x0c\xc7\x9d\x97\x80\x04\x16\xfd\x62\x94\xcc\xcc\x70\xcd\x1c\xf5\xb6\xa8\xe2\xaa\x07\x28\x9b\xd5\x22\xbf\x99\xdc\x96\xc3\x6b\xfe\xe8\x0e\x84\x6f\x5d\xd7\x46\xdd\x4c\x50\x03\xe4\xbf\x7d\x29\xef\xee\xa7\x50\x8a\x01\x61\x23\x68\x82\xc9\xa8\x2a\x56\xaa\x2c\x25\x74\x66\x96\x52\xc6\x30\x92\x3a\xb4\x70\xdd\xb9\x5d\x45\x6f\x7b\x8e\x8f\x07\x59\x9b\xa0\xd1\xd3\x8b\xc7\xf8\x17\x6e\x3f\xdf\x02\x09\xbd\x6f\x75\xd4\xcc\x11\x80\x3a\xfb\x18\x56\xcb\xc0\xe9\x1c\x73\x73\x0e\x4f\xb9\x8f\x3c\x94\x8a\x87\xd5\xa7\xed\xcc\x0a\x6a\x8a\xc8\x10\xea\x3e\xaa\x6e\x06\x3c\xec\x5f\x55\x66\xcd\x6d\xed\xc5\x37\xdb\x6d\x68\x6b\x80\x21\xf6\xea\x82\x5a\xd7\x47\x5e\xc7\xf1\xc5\xdb\xde\x45\xd3\xff\x4b\x5e\xe5\x1c\x0d\x04\xf1\xd7\x40\x18\xeb\x91\xe5\x04\x0d\x01\xc8\xb7\x1a\x4a\xab\xbd\xe6\x09\x4d\x4a\xfe\xcc\xb1\x8d\xfc\xde\xd7\x3e\xa7\x5e\x3b\x9f\x8c\xe1\x67\xdf\x62\x09\xae"}, -{{0xd5,0xca,0xc8,0x55,0x21,0xaf,0x78,0x1f,0x3d,0x5f,0x66,0x86,0x2a,0x04,0xb0,0x87,0xd0,0xcc,0xdc,0xac,0x92,0x6c,0xfe,0x9e,0x74,0x7b,0xe8,0xd5,0xc2,0x63,0x3f,0x78,},{0x10,0x0d,0xcc,0x53,0x03,0x9b,0xf0,0x5e,0xa0,0xa9,0xf5,0x88,0x82,0x12,0x69,0x3d,0x4f,0x9e,0x0e,0x75,0x25,0x95,0xbb,0xcd,0x02,0x06,0x10,0xe0,0xae,0x21,0x35,0x96,},{0x5d,0xc0,0x33,0x63,0x41,0x4e,0xea,0xc0,0x08,0x6f,0xb6,0xfe,0xba,0x44,0x21,0x7c,0xef,0x4c,0x52,0x0d,0xb6,0x19,0x26,0xdf,0x68,0x0c,0xa6,0x02,0xdc,0x11,0x00,0x3c,0xe6,0xaf,0xbf,0x3d,0x13,0xc8,0xc5,0xb0,0x52,0x73,0xd2,0x14,0x15,0xe6,0x7c,0x14,0xa2,0xee,0x5d,0x0b,0x1d,0x53,0x52,0x41,0x9a,0xb9,0xb3,0x9c,0x00,0x3a,0x51,0x0c,},"\xd5\xe7\xdd\x59\x49\x09\x37\x5a\x4b\xe0\x8e\x74\x82\x5d\x59\x8d\x53\x5b\xf4\x6e\xc0\x84\xde\x52\xb5\x73\x91\xc1\x27\xef\xf5\x22\x4a\xb2\xd1\x94\xdf\xb2\x66\x33\x47\x8d\x02\xfb\xda\x74\xd1\xdc\x58\x21\xf7\x91\xbf\x96\x2d\x8d\xad\x9e\x4e\xf2\x42\x24\x89\x19\x07\xb0\x18\x9c\xcc\xc8\xb1\x33\xd3\xaa\x20\x78\x92\x6d\xae\xf2\x89\x8c\x19\xc2\xe0\xbf\xe0\x20\x41\xa9\x04\xb9\xf0\x4b\xe7\xcb\x50\xae\xd0\xd9\x62\xd1\xad\xd2\x0b\x40\xa8\x8a\xb7\xab\xad\x62\x6c\xf4\xda\x0a\x78\xf9\xf5\x36\x85\x50\x1f\xdf\xa5\x85\x43\xdd\xf2\xea\x0e\xea\x69\xe7\xba\x16\x0f\x8a\x17\x7a\x25\xfc\x21\xe8\xa2\x9c\x66\x16\x33\xe3\x0e\x52\x3b\x0e\xc0\x1b\x2a\xee\xe2\xd4\x26\xe4\xae\xad\x45\x74\x88\x10\x8f\xe5\xf5\x69\xcf\x6e\x2f\xdb\x68\xc2\x8f\x2b\x30\x52\x82\x35\x77\xcd\x93\x4e\x7b\x06\x2c\x8a\x34\x24\xcd\x43\x67\xfb\x31\x5b\x74\x4c\xa3\x52\x55\xd7\xf1\xaf\x4e\xdc\x9b\xc9\xd8\x83\x71\x23\xd9\x79\x03\xb4\x3d\xf3\x67\xc7\xd4\x18\xc7\x93\x47\xff\xaf\xe7\xc7\xb1\x72\x4b\xba\x34\xed\xe8\xd3\x56\x8d\xb5\x05\x98\x3e\xad\x47\xf6\x2b\x56\xe3\x61\x8c\x11\xdb\x8f\xf0\xbf\x49\x2a\xc6\x75\x97\xd2\xf9\x6a\x6f\x42\x0f\xf9\x85\x34\x1b\x78\x6a\xd6\xce\xae\xdd\x10\x5d\x0d\x15\x63\xb2\xd5\x35\x43\xd7\x8e\x72\x56\x72\x5d\x20\x4e\x82\xed\x3a\x2e\x6a\x6e\x83\xdf\x61\xfc\x28\x2a\x62\xca\x06\xe6\x21\x74\xb5\x5b\xef\x40\xa0\xbd\xf8\xd2\x3d\x1c\x33\x0c\x71\x44\x14\x85\xee\x85\xe7\x0c\xed\x12\x1e\xac\x60\x7f\x58\x06\x78\x16\x3e\x4b\xd7\x5c\x67\x09\xff\x3b\x41\xde\x80\x59\x4b\x9e\x2f\x2a\xa2\x78\xfe\xfc\x21\xd7\x3e\xe3\xf7\x28\x54\xb9\x58\xd9\xa8\xf6\x3e\x3d\x70\xf7\xfe\xad\x8c\x3d\xca\x8e\x71\xbf\x4b\x9c\x2a\x36\xf2\x12\xb3\x2e\xb3\x29\x2e\x63\x55\x80\x38\x65\x59\xee\x1a\x11\xdf\x15\x29\x3a\x0c\x21\xcd\x73\x60\x86\x98\x46\xba\x5b\x7b\xa8\x5c\x99\x4f\x5b\x2f\x9c\xc5\x0e\x5e\xea\x8e\x4b\x36\x91\xd8\x86\x06\x2a\x18\xcf\xb1\x82\xf1\xe8\xb6\x11\xfe\x1b\xc2\x63\x15\x9c\xb8\xa0\x86\x78\x7c\x81\x1b\xea\x48\x12\x53\x00\x08\xc7\x0c\xa0\xc4\x7e\x64\xeb\x2f\xba\xd5\xb0\x27\x27\xa6\x6f\x2c\xdd\x6d\xde\x86\xf5\xd2\xa9\x64\x5a\x1e\x9a\xa6\x6e\xe0\xe1\x5b\x97\xf5\xfd\x22\x95\x96\xee\x02\xe6\x61\xca\xb9\xa5\x4e\xee\x1b\x81\xf9\x8f\xe2\x56\xed\x6c\x54\xfe\xaa\xa0\xba\x04\x7e\xea\x35\x33\x44\xf6\xe5\xc6\x2b\xe1\xe9\xd5\xc0\x9a\x2a\x69\x94\x11\x11\x0c\x56\xd1\x94\x9e\x90\xc0\x7b\x19\x38\xba\x95\x55\xac\x1b\xe8\x51\x1b\x51\x02\x18\xd7\xcd\xe7\xe1\xd7\x4a\x68\xaf\xb6\x42\xf8\x17\x15\xfe\x9e\x6c\x96\xc5\x03\x81\xae\x5a\x9d\xf3\x06\x51\x87\x85\xdc\x4d\xbc\x3a\x64\xf6\x0f\x24\x5c\x56\x4b\x80\x29\x51\x2f\x38\x1b\x56\xee\x78\x77\x03\x42\x68\x03\xc8\x0a\xb1\xc3\x11\xf4\x77\xb8\x91\x70\x8b\x59\xfa\x74\x8f\x32\xde\xbf\x54\xd2\x41\x37\x71\x97\x8c\x26\x5c\x9b\x87\x11\x4a\xdf\x25\xb8\x33\x7a\xa9\x3b\x0e\x63\x2a\x5b\x6e\xda\x47\x4b\xec\x16\x32\x81\x59\xfb\xed\x06\x7b\x00\xb8\x7a\xdd\x61\x96\x54\x92\xec\xcc\x6f\xd3\x46\x1c\x10\x00\xe4\x03\x7a\xb1\xe8\xac\x89\xa8\x52\x4f\x78\xae\x09\xd3\x08\xea\x6c\x94\xff\x88\x37\x32\xb7\x12\xee\xc0\xef\x07\x71\x8d\x33\xc0\x11\xb9\x39\x8f\x8c\xfe\xa7\x33\x07\x5a\xf3\x31\xfb\x3f\x97\xcd\xc1\xe8\xc9\x9f\x6a\x10\x72\x5a\x68\xc5\xc5\x8f\xdd\x8b\x0b\xaa\x50\x22\x7f\x34\xd7\x3d\x23\x90\x52\x03\x69\x8e\xaf\xf6\x26\x65\x4c\xe8\x3d\x86\x51\x08\x49\x9b\xe6\x86\x1f\x61\x41\xbf\xa6\x21\x9d\x7a\xb8\xb5\x84\x51\x91\x99\xf8\x80\xcf\xa1\xb2\x6d\x91\x94\xd3\x01\x71\x1c\x30\xfb\x44\x6d\x6e\xa7\x64\xa4\x31\x0f\x70\xe4\xb8\x59\xcf\x95\xfd\x44\xaa\xf8\xc1\xe2\x40\xe8\x0a\x71\x61\x1d\xbc\xf5\x2d\xa5\x8e\xdc\x32\x03\x11\xde\x38\x8d\x5d\x9d\x76\x9e\xb5\x9b\xe0\x93"}, -{{0x15,0x9a,0x9e,0xdd,0xea,0x5d,0xe6,0x34,0x03,0x98,0x7b,0x56,0x70,0xdb,0x6f,0xac,0x98,0xff,0xe5,0xec,0x3a,0x6c,0xf0,0x15,0x16,0xee,0x2c,0x70,0xce,0x3b,0x3b,0xe0,},{0xf6,0x1f,0x4a,0x04,0xa5,0xa1,0x2c,0xca,0xec,0xfa,0xf4,0x4c,0x1c,0x9c,0x18,0x88,0x47,0x5a,0x2c,0x89,0xfb,0x02,0xf2,0x6b,0xb8,0x1a,0xb5,0xf7,0x8f,0x4c,0xe3,0xa8,},{0x05,0x43,0x71,0x2c,0xef,0xa2,0x9a,0x22,0x0d,0x90,0xf8,0x1b,0xaa,0x4e,0x4c,0xf7,0x7a,0xc6,0x52,0x08,0xb2,0xd5,0xce,0x9f,0xd1,0x7c,0xe2,0x14,0xad,0x4a,0x93,0x7b,0x7f,0xc5,0xc7,0x86,0x41,0x3b,0x58,0x05,0x1c,0xca,0x3b,0xb8,0xb2,0xeb,0x55,0x65,0x7d,0x89,0x57,0x2b,0xc5,0x0e,0xa2,0xe5,0xec,0xdc,0x55,0x50,0x88,0x49,0x16,0x03,},"\xd1\x95\xe5\x90\x0d\xd3\x93\x14\x81\xbc\x01\x2e\x77\xbf\x06\x0a\xaf\x31\xcc\xcb\x0f\xe1\xa6\xc4\x0e\xaf\x28\x6a\x61\x66\xa1\x66\xb1\xea\x37\x05\x34\x26\x28\x4b\x92\x0c\x67\xfe\xe1\xd4\xb9\xd8\x6f\xb8\x61\xcc\x6e\xdd\x34\xe1\x0c\x52\x23\x37\x34\xd9\xcd\x92\xf5\xdb\xf4\x33\x51\x2e\xd2\x55\xac\x6b\x26\xe5\x6f\x5c\x66\x4b\xcc\xb2\x60\x69\x2c\xf4\x9d\x08\x36\x3e\xe9\x4e\x33\x6a\xcc\x48\x96\x00\xa6\xaa\x51\x2a\x04\x0f\x10\xeb\xf1\x8f\x7d\x2c\xbe\xe9\xca\xd1\x4c\x4f\xf8\x73\x77\xa3\x26\x34\x19\xd8\x29\x75\x29\x40\x1f\x15\x33\x7a\x4c\x4d\x23\x25\xed\x7d\xef\x76\x3a\x0d\x47\x9c\xaa\x40\x82\x66\x83\x4d\xa2\x42\xf3\xa1\x6b\x79\xa4\x58\x66\xb9\xd9\xd7\x1a\x48\x29\x31\x76\x74\xcf\xf7\xae\x6c\x8c\x58\x7b\xa4\xd4\x98\x0e\x81\x86\x13\xd3\xad\x82\x50\x7a\x7a\xb0\x32\xbb\xf9\x9c\x5e\x9b\x64\x03\x71\xbb\x41\xb9\x1e\x96\x5d\xc3\x1e\x8c\x7d\x4b\x3b\xaf\xd4\x95\x70\x52\x7f\xaa\xa8\x7a\xbb\xf6\x41\x6c\x47\xb1\xb1\xb0\x9d\x34\x01\x25\x31\x26\xcb\x24\x6a\xe4\x5a\xcf\x5f\x10\x0b\xb1\xf9\x2f\x11\xa5\xc6\xc9\x37\xe0\x58\x8d\x8b\x14\x6b\x3e\x4d\x3c\x7e\x5b\xf5\x74\x84\xe9\x84\xfe\x3a\xfc\x47\x72\xf2\x4e\xbf\x89\x4c\xdb\x39\x83\x7f\xbd\x46\x9a\x92\x1a\x96\xac\x5a\xf5\xe0\x70\xf6\xc9\x62\x4c\x58\x8e\x9d\x4f\xe6\xdd\xfe\xed\x1f\x8f\xe2\x0e\xb9\xc4\x60\xce\x6e\xe3\x8b\xf4\x71\xdd\x56\xdc\xf2\xe3\xee\x99\x8b\x8e\x7f\xdc\xf6\x12\xe7\x8a\x2e\x7c\x71\x73\xc0\x16\x09\x82\xbe\xde\xcc\x2c\x62\x1e\x5f\x66\x11\xb4\xef\x21\x02\xe3\x2e\x7c\x29\x80\x3a\x7e\x25\xfe\xe1\x51\x24\x31\x58\xa7\x6e\xe5\xd8\xc1\xbb\x2e\x7d\x8c\x88\x87\x1b\xa4\x33\xc5\xe5\x41\xc2\x60\x26\x93\xd9\x01\x10\xbe\x79\x5b\x52\x3a\x8f\xad\xb6\x05\xd8\xe3\xd7\xe4\x93\xfe\x24\x5d\x9c\xc5\x32\x0d\x32\xb8\x5d\x61\x35\xa4\x4b\x11\x68\x72\x94\x14\xc2\xca\x21\x56\x0f\xb4\xfe\xec\xde\xef\x0c\xf7\xd8\xe0\x71\x27\x4e\x88\x56\xc0\x04\x03\x3e\x80\x01\x3c\x73\xaf\x71\x77\xc3\x19\x78\x16\xa5\x03\x2d\x90\x59\xb1\xb6\xe4\x15\x2c\x38\x61\x92\xdd\x54\xb9\x0f\x9d\x30\x8b\xe9\x8e\xd7\xd0\xca\x9d\x12\xe8\xaa\xf6\xf9\xd8\x69\x38\x6a\xa9\xdb\xb0\x15\x93\xd3\x7e\x72\xf0\x90\x12\x4d\x34\x55\x29\x8e\x9b\x4c\x9e\xc3\xca\xe7\x3b\xb8\xee\x41\xeb\x63\xe3\x8c\x56\x13\x3e\xfd\xba\xf4\x49\xb8\x4e\x1e\x49\x1e\x49\x6f\x1c\x70\xa4\x4d\x06\x99\x86\xba\x88\x18\x42\x20\x69\x06\x1b\xb6\xeb\xcb\x7b\x20\x54\xe6\x3d\xf3\x81\xba\x03\xc6\xa7\x67\x4a\xbd\x61\x05\x0d\x69\x3d\x41\xbf\xe3\xca\x50\x46\xc6\x5f\xfb\x06\xa0\x74\x98\x09\xe5\x8d\x4c\x93\xa9\xff\x69\xed\x30\x95\x0b\xde\x1f\x99\x21\x6f\xff\x29\x9f\x22\xf1\x6b\x07\xc2\x54\xc2\x65\xae\x0b\x12\xe3\x13\x16\x3c\xcd\xf5\x03\x6d\x49\x05\x5f\x9a\x96\x67\xb0\xb7\x12\x92\xbc\x3b\x62\x60\xcb\x87\x56\x8f\xd2\x67\x17\x0b\xc9\x40\xc3\x33\x29\xd7\x29\xc9\xe3\x2d\x0f\x91\x80\xb1\x34\xbf\xf8\xae\x93\xb1\xbf\xeb\xfa\x38\x42\xfe\xf2\x0b\xc0\x4a\x29\x7b\x00\xa8\x4a\x0f\x42\x8d\x5f\x42\xfa\xb8\x61\x42\x99\x6d\x4a\xd9\xef\xab\xc4\x98\x52\xf8\x81\x2f\x3b\xfb\x5e\x57\x53\x9e\x21\x86\xeb\x8a\xe2\x29\x58\x0b\xc6\x04\x48\xac\xde\xf5\x72\x3c\x88\x15\x88\xb5\x37\x89\xf0\x5b\x91\xe0\x22\x89\x22\x32\x52\xd7\x53\xf7\x98\x13\x77\x9a\xce\x70\x5e\x04\xae\xd1\x52\x65\xd3\xbd\xf2\xa2\xe4\xb1\x56\x54\x77\x0a\x27\x58\x54\xe6\x4c\xf4\x43\x90\x60\x7a\x45\xd7\xbb\xa9\xaf\x3e\x1a\x2e\x28\x30\x67\xfc\xd6\xe6\x33\xaa\x2d\x24\x03\xbd\x81\xf7\xc7\x92\x76\x55\x10\xb5\x98\x41\x2f\x6b\xda\x07\xb2\xa9\x45\xb9\xf6\xd4\x6a\xb2\xf7\xc3\x20\x07\x5b\xc6\xb6\x0a\x80\xda\xa4\x4a\xf3\x91\xf4\xcd\x56\x21\x31\xbb\xdd\x40\x7d\x66\xf8\xdb\x12\x59\xbd\x76\xfa\x7e\x4d\x52\x64\xe1\x45\x54\x6c\x94\x2d\xfe\x90\x07"}, -{{0xed,0xa0,0xfe,0xac,0x0f,0x2a,0xfe,0x01,0x74,0x49,0x15,0x52,0x48,0x7f,0x39,0x62,0x17,0x13,0x32,0xb8,0x22,0xdc,0x3d,0xa4,0x26,0xf9,0xa5,0xf6,0x2b,0xef,0x7b,0x8d,},{0xef,0xf2,0x7c,0xb5,0x1f,0x4d,0x39,0xc2,0x42,0xf3,0x23,0x01,0x9a,0x12,0x34,0x81,0x8e,0xf2,0xe4,0xcd,0x1b,0xda,0xbc,0x0f,0x2d,0x8d,0x21,0x34,0x58,0xdc,0x47,0x1a,},{0x6c,0xbc,0x7e,0x6f,0x5e,0x12,0x14,0x5b,0x01,0x68,0x7a,0xd9,0xca,0x6b,0xf6,0xe4,0x7f,0x94,0x17,0xc2,0xce,0xfa,0xd3,0xfb,0xd6,0x8f,0xd6,0x5d,0xd7,0x4f,0xaa,0x97,0x50,0xcb,0xa9,0x92,0xde,0x4c,0xeb,0xcf,0xcd,0x35,0x80,0x8c,0xbb,0x3f,0xf1,0x2c,0x8d,0x93,0x07,0x99,0xaf,0x36,0xef,0xe7,0x97,0x6b,0xf2,0xfe,0xa7,0x9e,0x3e,0x0e,},"\x90\x11\x19\xda\x4e\xd1\x81\xaa\x9e\x11\x17\x0b\x20\x62\x6e\x00\xab\xf0\xb5\x48\x24\x5e\x3d\xeb\xf9\x4b\xf5\xed\x50\xae\xef\xe9\x42\xb4\x02\xcc\x99\x48\x94\x78\x52\xde\xdf\x2b\x53\x04\x01\x76\x65\x74\x9c\xd4\x7c\x21\xfc\x65\x2e\xe9\x95\x67\x9f\xf9\x31\xe3\x0e\x94\xaf\x98\xb4\xa9\x8f\xd4\x4e\x84\x9e\x98\x47\x0f\xe0\xa7\x6c\xe8\x0c\x61\xf8\x3f\xb4\xe8\x5b\xa5\x23\xee\x3f\xd2\x5d\xb0\x00\x05\x3b\x49\xd0\x93\x0e\x3b\x07\x9e\x86\x6e\x15\x3f\x7d\x86\x36\x7f\x23\xa4\xc4\xab\xc6\x3b\x30\x75\x46\x1e\x90\xe4\xfd\x89\x6d\xa0\x49\x2e\x27\xd7\x14\x94\x1e\x96\x7f\x52\xc9\x3f\xfa\xec\x44\x80\x3f\x57\x87\x7d\x86\x6e\xb5\xf8\xc5\x28\x17\x85\xaa\x48\x26\x79\x2e\x39\x64\xc6\x65\x90\x82\x1e\xea\x66\x75\x20\x74\x26\x40\x18\xa5\x71\xf5\xb0\x13\xb3\x8e\x15\x2c\x95\xc0\x24\x8a\xe6\x03\x68\x22\xa6\x7a\xfc\x9e\x02\x69\x45\x73\x15\x2b\x86\x4c\x56\xc2\xf7\x30\xa0\x82\x10\xf8\x5e\xc4\x6f\x98\x4a\x64\x3d\x51\x6a\x15\xfc\xfa\xa8\x48\x40\xf5\x12\x04\x7d\x11\x0e\x07\x18\xd2\x93\x95\x5f\x01\x58\x25\x7f\xba\x0d\x78\xeb\x7d\xf2\xf0\xb7\x7e\x6e\xeb\x76\xdb\x5e\x71\x70\x73\x10\xe8\x27\x36\x1c\xd4\xe1\x19\x74\x0e\x63\x92\x2d\xb4\x2c\x2c\xeb\x5e\xe1\x75\xd5\x0d\xec\xc7\xb7\x49\xfd\x23\x25\xbc\xe1\xe6\xa8\xf7\x10\xff\xcc\x1e\x1c\x9b\x33\xc3\x80\xe5\x2a\x64\xda\xa9\x58\x5f\xab\xe4\x06\xd9\xcf\x24\x48\x8f\xe2\x6f\x3a\x49\x5f\xb0\xab\x50\xe1\xe2\xba\xd8\x23\x81\xaa\x22\x43\x10\x99\xcc\x8a\x56\x98\x13\xd7\x9c\x9d\x78\x56\x9c\x0d\x95\xda\x9a\xad\x2b\xfb\x57\x75\x8d\x52\xa3\x75\x27\x52\xe0\x23\xd6\x51\xc9\xcb\x66\xa4\x12\xa5\xc8\x0f\x6b\xa5\x47\x93\xf7\xec\x87\xb4\xc5\x98\xfe\xd2\xce\x24\xab\xd7\x60\x87\x08\x89\x5c\x46\x72\x73\x59\xff\xec\xa6\xd6\xc6\x2e\x10\xa6\x78\xca\xa7\x18\xb4\xcd\x26\x32\x92\xcf\xef\x53\x5b\x9f\xbe\x27\x56\xb7\x39\x6d\x69\x7b\x31\x46\xc5\x51\xe6\xaa\xc1\xf5\xf1\xc2\x4b\xe9\xb6\x7a\x1e\x2a\x2a\xff\x74\x53\x01\xba\x6a\x21\x22\x17\xc5\x3d\x68\x16\x81\xbb\xb4\x01\xbf\x4a\x43\x65\x6f\x5d\x15\xcd\xe9\x69\xc1\x78\x00\x99\xa3\x32\x37\xeb\x19\xa3\xb8\x58\x5d\x6b\x5d\xea\x2f\xb5\x77\x84\x5f\x25\xee\x2a\x82\xcc\xf4\xb2\x85\x02\xf9\x0f\xe8\x0b\x8c\xdc\xdf\x2c\xcf\x93\xc4\x34\xc0\xe6\xaa\x5d\x87\x52\xa4\x43\x43\xc2\xb1\x8d\x20\xfe\x40\x04\xc4\x70\x38\x65\x93\x56\xf8\x7a\xbe\xd5\x44\x50\x34\xd8\xe2\xd3\xd1\x47\x68\xf5\xef\x31\x2c\xf1\x02\xa9\x88\x46\x83\xbc\xc0\xcd\x8a\x71\xe3\xec\x36\xfb\xb6\x33\x4a\x1b\xba\xed\x5d\x2b\xf1\x04\x16\xd8\x2b\xd6\x53\x04\x75\x38\x0a\xb6\xe2\x57\x7b\xbc\x69\xce\xbd\xa7\x5f\xaf\x02\xad\x82\x7b\x54\x51\x82\x13\x20\x6f\xd4\xcd\x66\xf2\x52\xb2\x34\xac\xa9\xee\xde\x7e\x3e\xeb\x81\x5d\xdc\xd8\xd5\x19\xc5\xd7\xf5\xd9\xd1\xfb\x9c\xa0\xfa\x44\x67\x99\x00\x95\xfa\x46\x22\x0c\x20\xa2\x07\x1d\xfc\xaa\xd5\xf0\x24\xda\xe3\x41\x6f\x7c\x49\x2d\x75\x74\x88\xc4\x9a\x2e\x4d\xf4\x83\xbc\x9b\x80\x09\x8e\x0d\x5d\x68\x3f\xac\xb8\xc9\x60\x82\x9d\xff\x09\xb3\x03\x36\x9d\x46\xcb\x57\x33\x1f\xf2\x17\x91\xee\x25\xd6\xbe\x7d\xec\x7e\xba\xf1\xb3\x24\x79\xa7\xf5\x14\xdc\x64\x71\x05\xc9\x44\xc3\x6f\x7d\xbf\x0a\x5b\x58\x91\x28\xdb\xaa\xa4\x21\x71\xd6\x42\xf2\x5a\x98\x1c\xe1\xf8\x37\x9f\x91\x69\x0b\x36\xaf\x77\x46\x48\xd5\x62\x4c\x08\xdb\xd0\xa9\x0f\x70\x87\x16\xdf\xab\x20\x24\xda\xe8\x65\xb9\xc4\x9a\xb2\x74\x73\x82\x6c\xd4\xa0\x10\xbf\xdb\x52\x01\x1d\x8c\x7c\xb3\xf4\x21\xca\x8c\xa3\xcd\x04\x86\x88\x91\x88\xe6\x7d\xf0\x0f\xb8\xc2\xa6\x43\xe7\xad\xb2\xf8\x27\x9f\x76\x3e\x5b\x9a\x81\xb6\xdf\xc3\xf7\x21\xfc\x5f\x68\x49\xf6\x67\x36\x78\x8c\xc5\x57\xc4\xeb\xc6\xfc\x68\xd6\xf6\xac\x77\xbe\xdd\xa8\xac\xb3\x62\x24\x3b\xda\x74\xe7\xb2"}, -{{0xec,0x05,0x9f,0xc6,0xbe,0x98,0x3c,0x27,0xec,0xa9,0x3d,0xdc,0xdc,0xb5,0x3a,0xf7,0x28,0x62,0x55,0xda,0x91,0xe2,0xa5,0x6a,0x68,0x4f,0x64,0x1e,0xc2,0xd0,0x9d,0x6e,},{0xff,0xc6,0xcb,0x75,0x1c,0x70,0x07,0x1b,0x65,0xec,0x2a,0xc6,0xb4,0x5f,0xd1,0xd5,0x5f,0xe8,0x36,0x96,0x5f,0x80,0xb3,0xe7,0xc7,0x84,0xfc,0x70,0x4a,0xcb,0xdf,0x69,},{0xa7,0xb8,0x8e,0x5a,0xbf,0x13,0x28,0x24,0xbd,0xde,0x77,0xc5,0xf8,0xdf,0x94,0xab,0x26,0x48,0x1f,0x6b,0xee,0x66,0x0e,0xa1,0x62,0x24,0x70,0x82,0xa2,0x50,0xd3,0x90,0xc7,0x1d,0x32,0x0a,0xd0,0x60,0xd8,0xef,0x34,0x1f,0xb6,0x9a,0x48,0x32,0x94,0xf0,0xd6,0xde,0x72,0x6f,0x0c,0x86,0x2f,0xa3,0x7e,0xa4,0xbc,0x6d,0xab,0x52,0x15,0x09,},"\xd1\xac\x63\x25\xa4\xe6\x90\xfa\x79\x53\x68\x83\xd5\xc2\x0e\xac\xb7\xd9\x64\xc0\x17\x8f\x74\x2c\x2b\x23\x72\x7d\xeb\x62\x64\x5a\xf7\xc8\x19\x22\xa0\xe7\x2e\x5e\x30\xb5\x83\x9a\x2e\xd5\xe5\x67\xec\x31\xce\x22\x41\x15\xb8\x2d\x2b\xf2\x51\xb7\x39\x3f\x01\xb0\xd0\x3a\x60\x2b\xc1\x20\xae\x62\xaf\x7f\xbc\x37\x9d\xfc\xf9\x5b\xbb\xba\x98\x4a\xab\xa3\x4f\xe2\x12\xac\x99\x00\x33\x28\xb8\x32\xc3\x53\x2d\x42\xee\xe1\xe1\x87\x4d\xc2\x2a\xd6\x7d\xb6\xc9\x1d\xbb\xfb\x2b\x45\x78\x5d\xbc\xd3\x99\x17\xd3\x6f\xb4\x8c\x1b\x5d\x6f\x38\xbd\xda\x5d\x28\xfb\xba\x64\x17\x55\x75\xaf\xea\x46\xc8\xed\x67\x57\xff\x30\x16\x4e\x0d\xf2\xe7\x21\x76\xe8\xb6\xc9\xdb\x5b\x5e\xf3\x90\xb7\x2f\x2d\x4d\x94\xe3\xb6\x6f\x0d\x44\xa7\xe0\xf0\x6e\x89\xde\xbc\xdf\x13\x63\xc0\xe7\x5d\x50\xdb\x5b\xb7\x01\x90\xd1\x9f\x66\xa3\x9c\x6f\x7d\xba\x70\xdf\xcd\x4a\x9f\xed\x02\xc2\xf1\xd0\x67\xe7\xc7\x88\xc5\x8f\xdb\x3e\x17\xa2\x37\x7c\xe4\x86\xec\x65\x82\xf3\xba\x99\x7b\xb5\xf7\x0c\xd6\x21\x00\x29\x56\xf5\x13\x1a\xa3\xa1\x61\x7c\x0c\xeb\xcc\xd9\x39\x1d\xe1\x30\x7c\x85\x97\x0a\x8b\xc1\x55\xf5\x19\x87\x26\x68\x45\x0c\x91\x48\x86\x89\xf5\x3c\x2c\x1a\x7e\xd5\x3f\x38\x8c\xb1\x3a\x2c\x38\x96\xfe\x5b\x7d\x3a\x0d\xc1\x68\x3f\x27\x66\x4c\x8b\xea\xea\x68\x0c\x8c\xc5\x4a\x90\xe4\xc6\xf9\x9f\xbf\x05\xf2\xc2\x2d\xf6\x0d\xe9\xae\xc8\x0c\x79\xb7\xd6\x62\x07\x05\x06\x67\xb4\x52\xd7\x85\x7f\x9a\x8c\xa7\x23\x28\x0d\xac\x79\x92\xe2\x07\x92\x67\xec\x3a\xd9\x11\x40\x46\x42\xc4\xe3\x26\xbf\xb9\x6b\x43\xc8\x94\x34\xba\x4b\xc7\x8c\x25\x2f\x4d\x4c\xa8\xd1\x3a\x88\x74\xc6\xfc\x82\x52\xea\x0b\x56\xc6\xbc\x78\x68\x47\xd4\x31\x83\x06\xe1\xc6\x52\xc4\x52\x58\x5e\xef\xd0\xbd\x9d\xd3\xc1\x48\xa7\x3b\xa8\x6e\xed\xea\x94\x5f\x01\x67\x13\xed\x7d\xf0\x85\xd0\x06\x66\x89\xe7\x92\xda\xcb\x2b\xfc\x1e\xb5\xc8\x24\x37\x2a\x26\xc5\xe9\x44\xaa\x74\x44\xac\x97\x73\xd4\xa1\x92\x1e\x49\xbd\xd4\xf8\xf6\xd7\x88\xc2\x63\xfe\xe0\x4c\x7b\x44\x4c\x53\x05\xed\xb6\x33\xe1\xff\xe0\xba\x4e\xa8\xda\x01\x1a\x62\xf2\xbb\xfe\xf4\xb8\x95\xad\x3f\x22\x4c\x3b\xa3\xbf\xf0\xc9\x5d\x75\x75\x0c\x9b\xcc\x66\xff\x8a\x20\xb6\xc2\x4b\xde\x75\x81\xa7\xec\x38\x66\xf8\x71\x6f\x78\x1f\x46\xdc\xad\x45\xa9\xeb\xcb\x6e\xd4\x69\x53\x36\x83\x97\x01\x17\x35\xd4\xb5\x2d\x00\xe8\xdb\x39\x79\x95\xdb\xdb\x3d\x4f\x42\x54\x68\x7f\x04\x68\x8a\x26\x8c\x30\x5b\x2b\x1f\x62\x2c\xf5\x1b\x17\x47\x75\xba\xd7\xf6\x67\x4a\xdc\x2e\x58\xe0\x5c\xce\x86\x5f\x12\xd7\x56\x9c\x8e\x9b\x35\xbc\xdf\x3c\xcc\xe6\x33\x0d\x08\xce\x53\x40\xa7\xc6\x30\xf2\x7a\x6c\x80\x86\xb5\x14\x6b\x29\x2f\xcb\xf5\x0f\xf6\xaa\xae\xf8\x84\x8a\x70\x7b\x25\x43\xc6\x18\xd1\x7b\xd9\x76\xc2\x40\xbc\x79\xd3\x3e\x00\x4e\x49\x53\x48\x29\x15\xe7\xe6\xef\x94\x96\x4b\xde\xa4\xe0\x2d\xd7\xc2\xf4\x75\x23\x5f\x2b\x99\xe4\x32\x29\xc9\xac\x3a\xba\x0d\xb5\x9a\xc2\xda\x03\xa9\xee\x4f\x37\xdb\xf2\x47\xa3\x3e\x6d\xfe\x5b\xe7\xc7\xf8\x25\x84\xf0\x4a\x46\xd4\x9f\x66\x21\xda\x31\xb9\x1a\xc3\xda\xa4\xd6\x8d\x48\xa5\x66\x59\xb4\x48\xc0\xed\x36\x5c\xb4\xaa\x0c\xfd\x90\x88\x53\xdf\x5b\xbf\xa8\x8e\x60\xe1\x0a\x5a\x00\x2c\x32\xab\x33\x33\xf2\xc3\x9b\xbf\x3e\xe0\x1a\x4a\xa6\x0d\x2d\x01\x42\x3e\x60\x97\xdc\x54\x30\x5f\x81\xa2\xd9\x3e\x2f\x6b\x4e\x8b\x35\x19\x71\xcb\xf2\x45\x7d\xc7\x6e\x1f\xb8\x92\x93\x38\x47\x98\xef\x28\x23\x4e\x9b\x1a\x47\xde\xdc\x23\x36\xf8\x6b\x8e\x13\xc4\xae\xf7\x90\xf5\xa1\x12\x39\xc7\x47\xd9\xd8\x65\xc9\xa1\x5a\xde\xb0\x71\x07\x02\x67\xe5\x34\x62\x56\x64\x8a\xdc\x0f\xa4\xdb\xdf\xd7\x87\xca\x14\x65\xfc\x24\x0a\x32\x4c\x3c\xaf\x29\x31\xda\x41\x49\x9e\x27\x5f\xd4\xb3\x5f\x6d\x08\xdb"}, -{{0xf1,0x6a,0xbd,0xbc,0xc0,0xbc,0xc6,0x1a,0x1a,0xee,0x3a,0xbd,0x87,0x67,0xab,0x52,0xe5,0xf7,0x99,0x99,0xbb,0x77,0xa3,0x97,0x6c,0xbc,0x82,0x67,0x0d,0xfd,0x2f,0x73,},{0x10,0xf4,0x51,0x71,0x9d,0xb0,0xfd,0x21,0x37,0x6e,0x22,0x8a,0x41,0xc3,0x03,0x5c,0x8c,0x2b,0xc4,0x2e,0x5a,0xaa,0x92,0x6f,0xe6,0x08,0x87,0x8d,0xbb,0x0d,0xc7,0xab,},{0x33,0xd8,0x05,0x29,0x08,0x69,0xb8,0xe0,0x4f,0xf0,0x89,0xfa,0xa2,0xd1,0xfa,0xb8,0x37,0x43,0xba,0xda,0x68,0xad,0xe5,0xb3,0x8a,0xe5,0xf0,0xcc,0x58,0xc3,0x37,0x4e,0xba,0x43,0x94,0x3c,0x1f,0x51,0x10,0x67,0x8e,0xb3,0x9b,0x46,0x58,0x61,0x18,0x22,0xa2,0x6d,0x35,0xff,0xe1,0x9e,0x9c,0xfc,0xb9,0xba,0x95,0x89,0xe4,0xec,0x31,0x05,},"\xbf\xac\xd7\xdd\x4e\xea\x46\x7d\xcc\xe4\x04\xf4\xa3\x52\x0a\x45\xb9\x4e\xba\xa6\x22\x19\x7d\x02\xd6\x15\x29\xd2\xb3\xbf\x27\x3c\x4e\xe1\xfb\x95\xa1\x80\xc8\xf8\x7d\xe1\x90\xa2\xe5\xea\x70\xb8\x4a\xe1\xeb\x6f\xd4\x44\x7d\x8a\x3a\x8d\xed\x10\xf6\xed\xe2\x4f\x0e\xb9\x2b\xd3\x0b\xc6\x5d\x48\x71\xe8\xf5\xda\x08\xcb\xe8\xcd\x3c\x0a\xc6\x4f\xd5\xa5\x7a\x6b\x06\x4a\x89\xd5\x15\x9b\x42\xf8\xb3\xe5\xa1\x83\x8c\x9c\xb1\x9d\x88\x10\x6c\x07\x73\xa2\x75\xcd\x2a\x1d\x60\x99\x30\xbf\x6b\x30\xae\xca\x62\xb9\x7e\x31\x9b\xbf\xa9\x34\xf4\xd0\xa1\xe6\xac\x80\xba\xeb\xcb\xa2\xd8\xea\x4b\xed\x9c\xa8\x56\x2b\x4a\xcb\x56\x97\x9b\xf8\x85\x32\x4a\xc4\x0a\xb4\xa5\x0b\xfb\x9f\x34\x90\x49\xfc\x75\xa0\xe0\x3d\xe4\xcc\x43\xea\xe3\xc6\xa6\xcf\xfb\x5f\x6a\xe6\xc9\x45\x04\x41\x5e\x6c\x7e\xd3\x04\x5a\x93\x2f\x47\xfd\x20\xb9\xf3\x48\x3a\x77\xb6\xd4\x49\xd8\xdf\xd4\xa6\x38\xdb\xf5\x6f\x03\xf0\xf0\x31\x87\x90\x59\xb2\xfb\x49\x76\x79\x43\xf4\x6b\x38\x72\xe2\xde\x56\x7d\x5f\xef\x80\xb0\x29\x25\xe9\x86\x3e\x0f\x1d\x31\xa8\x0f\x4e\x64\x51\xc3\x25\x69\x4b\x80\xcf\x1f\x19\x18\xc6\xe4\x98\x87\x8e\xdc\x47\xc4\x53\x0c\xac\x46\x6f\x1a\x29\x4d\x55\xdf\x09\xaf\x4f\xdc\x80\x72\xad\xb1\xbf\x26\xca\x8c\x92\xf9\x12\xa2\xb9\xfe\xbc\x8b\x97\xb5\x8c\x1e\x9d\x32\xc7\x80\x32\x30\x52\x97\x2b\x6f\xbd\x53\x30\x4c\x05\x19\x3c\xae\xb6\x7c\x5b\xd3\xe6\x74\x79\x72\x5d\x29\x7d\xff\xb0\x68\x90\xab\xf8\xcd\x9e\x42\x45\x8e\x16\x8a\x61\x18\xf9\x05\xb1\xd5\x34\x86\x01\x6f\x85\xdc\xd9\x8d\xd3\x39\xe3\x46\x05\x33\xd0\xb8\xa4\x9f\xae\x6d\xc1\xa0\x71\x72\x5e\x6a\xe5\xf2\x94\x47\x9e\xe3\xbd\xca\xeb\x74\x06\x18\x41\xfb\x26\x08\xe8\x8a\x49\xfd\x0f\x38\x95\xb1\x8f\x85\xb9\x0f\x72\x41\xdd\x13\x87\x71\x00\x53\xfa\xa6\x2b\xae\x75\xe9\xae\x39\x36\x9c\x1c\x02\xde\x5d\x19\x24\x2e\xfa\x16\xe1\x1d\x44\xa4\xba\x57\x78\xce\x77\x22\xa9\x1c\xec\x0b\xc0\xa0\x8c\x06\x9b\xdf\xa1\x30\xd1\xc6\xc4\xb5\x6c\x6e\x93\x54\x24\x03\xcc\xf2\x76\x84\xde\xf5\x7d\xef\x26\xdf\x86\xce\xd5\x71\x28\x2d\xc9\x60\x97\x46\x18\xf0\xa7\x4a\x0c\xde\x35\xb6\x53\xcc\x6e\x77\x30\x43\x1b\x82\x5f\xfb\x9b\x8a\xaa\xb3\xc7\xa3\x97\xc9\x92\xbc\x2f\xa2\x32\x70\xfb\x11\xee\x43\x1a\xfd\x5f\x9a\x64\x44\x83\x01\x11\x73\x99\x3f\x19\x48\x5d\xd3\xcb\xdd\x18\x7b\xd3\xd9\x95\xeb\xf0\x03\x1b\x1b\x0d\xe4\xa8\xde\x9c\x14\xeb\x6f\x78\x0e\x36\xb8\x92\x57\x56\xb9\x79\x06\xa1\x96\x9d\x85\xe9\x67\xd8\x80\xe6\xe7\xdd\xa4\x2f\xd3\xc3\x00\x19\xf1\x1d\x70\x81\x07\x1e\xee\x66\x26\x42\x28\x36\xbb\xed\x27\xd4\x6d\xd0\xdf\x1f\xeb\x66\x10\xdc\x85\x9f\x51\x3c\x0b\xc6\x53\xd7\x02\x20\xfe\x04\x8d\x2e\x97\xc2\xe0\x6a\xf5\x30\xe1\x1b\xdc\x70\x29\xbc\xcc\x5c\x92\xed\xec\xef\x5e\x4a\x2e\x0b\xe2\xd2\x51\xf4\x41\x5d\xca\x3e\x55\xb3\xa8\x50\xf2\x63\x0b\x87\x9e\x4e\x03\x6c\xe8\x63\x3b\xf2\x09\x20\xb6\x80\x94\x21\x59\x29\xac\xcc\x7b\xe4\x0c\x57\x78\xbc\x55\x4e\x6e\xdd\x7e\x54\xc9\xe1\x45\xb2\xee\x07\xb6\x5d\x06\x1c\x11\xde\x0e\x83\xf3\x81\xce\x4f\x57\xc6\x48\x3f\x51\x06\x93\x63\x51\x10\x74\xc7\xa5\x77\x35\x3b\x45\xc6\xeb\x71\x19\x9d\xce\x50\x59\xfd\x2c\x46\x11\xb0\x54\x23\x8a\xaa\xdf\x2b\x6b\xa5\x34\xbf\xff\xc2\x72\x2a\xe3\xe3\x1f\xf7\x9a\xe2\xeb\xca\x99\xcc\x35\x07\xf8\xa0\x33\xcf\x4f\xea\x70\xc5\x2f\x7d\xb5\xde\x44\x2b\x42\xb8\xd4\x1e\x99\x01\x2e\x42\xca\x0e\x85\xa9\xfb\x6d\x4f\x16\x5b\x33\x0d\xe6\x38\x3c\x57\x26\xef\xca\x2f\xe9\x71\x34\x00\x02\xf5\x62\xdc\x6c\xb8\xf2\xfa\xf0\x66\x57\x25\xe0\x97\x79\x9d\x09\x60\x91\x86\x4d\x66\xa9\x50\xa5\x79\x09\x53\xee\x16\xb9\xea\x58\x20\x09\x21\x87\x08\xc4\xac\xcd\x81\x38\x13\x58\xa2\xc6\x89\xa0\x41\xd0\x2d\x78\x61\x21"}, -{{0xbe,0x79,0xd1,0xae,0xea,0x86,0xe8,0x6f,0x39,0x81,0x37,0xe6,0x2f,0xfd,0x79,0xe5,0x0e,0xff,0x9f,0x31,0x3f,0x25,0x19,0x2f,0x89,0xe5,0x2f,0x0b,0x4b,0xbd,0x5d,0x32,},{0x18,0x7d,0xac,0x85,0x5c,0xa4,0x42,0xfd,0x9a,0x3d,0xdc,0x32,0x89,0xc2,0x4e,0xb2,0xd2,0x6f,0x7a,0x40,0xfb,0x29,0xd8,0xe7,0x44,0x31,0xb2,0x50,0x22,0xc3,0xa0,0xcc,},{0x6d,0xab,0x59,0x3b,0xb1,0xd4,0x48,0xc9,0x74,0xa6,0x5c,0x6a,0x0b,0x6f,0xad,0x22,0xb4,0x73,0x26,0x32,0xd0,0x04,0x89,0x17,0x6e,0xf1,0x26,0xaa,0x59,0x01,0x09,0xe0,0xa7,0x23,0xa1,0x13,0x10,0x7b,0x53,0xe1,0x7d,0x69,0x0a,0x0d,0x40,0xb0,0xfa,0x33,0x6c,0xc8,0x7f,0xd5,0xfc,0xe8,0xf5,0x41,0xac,0xce,0xc6,0x7f,0x7d,0x1e,0xbc,0x06,},"\x6d\x63\x2a\x7d\x3c\x9b\xe5\x36\x49\xd0\xd1\xa5\xee\xdf\x51\x9a\x41\x3b\x13\xac\x64\xe9\xad\x85\x4d\xfa\x04\xf2\xe1\x73\x29\xd8\x22\xbe\x57\x3d\x9e\x35\xac\x06\x6f\x02\x22\x13\xa3\x44\x62\x0b\xba\x28\x9f\x53\x31\x69\x55\x84\xd1\x34\x3e\x81\x54\x05\xae\xab\xe3\x86\x1d\x63\xb3\xa5\xb9\x2b\x8c\xd8\xee\xed\x22\x80\x22\x2a\xbd\xe3\x0a\x1b\xcc\xd3\xf3\xe4\x11\xaa\xb9\x22\xfa\x1b\xaa\x09\x7a\xa5\xc7\x80\xd0\xea\xef\x94\xea\x10\xfe\x21\xf7\xd6\x39\xb7\x6d\x47\x88\xae\xb5\x92\x4a\x9d\x26\x2d\xcb\xc5\x68\x8a\x3e\x43\x54\x4b\xec\x08\x8c\xa2\xe0\xd0\x6d\x77\xa7\x1f\xb6\x41\xd5\x52\x26\x61\x44\x52\xb1\xe0\x80\x7a\x9f\xcd\x3c\xa6\x9b\xf7\xf2\x5d\x80\x41\x47\x0c\xeb\x7b\x21\xea\xd0\x3e\xc0\x37\xa1\x62\x9b\xd5\x00\xaa\x23\x3b\x59\xbe\x44\x97\x82\x10\xb6\xa3\x66\xf2\x23\xac\xfa\x07\x97\x95\x40\x07\xb0\x0e\xfb\x4f\xfa\xdb\x5f\xc9\x2b\xdb\x37\x86\x3e\x50\x2d\x7d\x70\x68\x10\x39\xed\xf3\x37\x70\xdf\x3d\x1d\xe3\x43\xdc\x35\xf2\x26\xd5\xe7\x39\x44\xba\x02\x55\xe2\xa8\x8e\xf6\xc4\x1e\x47\x2b\x21\x45\x67\xc2\x49\x59\x4a\x50\x87\x8b\x67\x31\xc1\xae\xb5\xb1\x0f\xa9\x1f\xa7\x6a\x37\xe1\xf9\xf1\xc0\x0f\xdb\xfe\x34\x85\xde\xd5\x4a\x00\x9a\xb6\x13\x39\x27\x11\x56\x68\xb5\x9f\x51\x15\x50\x8d\xa9\x37\x0f\x6b\xc9\x2a\x11\x85\xc0\xd5\xca\x01\xd2\x91\xe1\x8c\x54\xac\xfa\xca\x73\x8b\xd7\x19\x68\xa3\x42\xa0\xcb\xa6\x2e\x4b\xb1\x04\xa5\xbb\x37\x9f\xc8\x3e\xe1\x82\x0d\x1d\xb9\x80\x25\x3d\x6c\xb3\x83\xe9\x5a\xf1\x5f\x53\xc8\x5d\x17\x58\x90\xdd\xe5\xe4\xed\x03\xd2\xd0\x13\x5e\x3d\x60\xb1\x82\x93\xf5\xb5\x64\x1e\xf8\x3c\x6e\xce\x3d\x52\x59\x8f\xc6\x35\x36\x86\xe6\xf7\xb0\x9f\xde\xc1\xf6\xf1\x53\x67\x2d\x34\xb4\x89\xb4\x8a\x0d\xb9\xe4\x2c\xed\xa7\x17\x55\x48\x1c\x04\x70\x16\xc2\x25\x34\xe9\x0c\x6d\x20\x1e\xd7\x85\x96\x02\x63\x6e\xa7\x7a\xe8\xc6\x73\x4b\x7c\x4c\x5b\xd9\x95\x79\xc5\x08\x73\x1c\x72\x46\xa2\x95\x86\xe4\x06\xe1\xd9\x32\xf6\x71\x30\x71\xd4\xbe\xa6\x3d\xc5\xe2\xa3\x76\x1e\x16\x02\x4d\x2c\x32\x84\xf7\x09\xa1\xf2\xba\x08\x5e\xad\x32\x00\xc7\x04\x62\x75\xcb\x96\xb6\x1a\x60\xb5\xac\x55\x9b\xc4\x88\xbd\x10\x64\x67\xc3\xde\x50\xbf\x5d\x74\x0d\x05\xc9\xcd\x70\x1d\x65\xb7\xda\xea\x29\xe6\x4d\xd5\xa9\x7a\xdb\x6b\x5c\x82\xcf\x7f\x23\x01\x7a\xa7\xca\x1a\xc9\xa3\x9e\x58\x27\xeb\x47\xe2\x0d\x35\x9b\x67\xc7\xd4\xe1\xa8\xe3\xe2\x7c\x52\xd3\x3d\x93\x03\xa5\x92\x62\x34\x84\xd7\x97\xb4\x02\xcb\xb4\x58\xd1\xac\x2e\xa5\x3e\x1c\x4f\x7a\xbb\x70\xcc\x02\x95\x54\xa2\x34\x57\x4d\xef\x9b\xc3\xb0\xd3\x83\x5d\xc3\x14\x90\x2e\x25\xab\xb2\x2d\xfd\xed\xdc\x67\x9a\x3c\xc8\xf0\x73\x40\xb1\x5f\x57\x62\xf4\x40\x7f\x38\x03\x42\x55\x4e\xd0\xc6\x2f\x73\xb6\x18\x16\xea\x8c\x52\x94\x61\xe1\xbf\x0e\x9d\x1c\x2d\x5e\x4c\x57\x46\x33\x6b\xc0\xe1\x32\x87\x3c\xde\x0d\xc2\x15\x8b\x54\xfa\x1b\x67\x8a\x00\x6b\x4d\x95\xed\xa8\xa9\x55\x71\x42\x73\xb7\xcc\x5c\xf2\xad\xd9\x09\x4d\x46\xe4\x9a\xbc\x09\x6a\x45\xf4\x18\xe2\xed\xbe\x99\xdd\x85\x29\x11\x68\x80\x64\xdf\x7c\xf0\x61\xd0\x7a\xee\xf4\x27\x95\x69\x0f\x48\xc9\xba\x19\x56\x54\x75\xd5\x46\x8a\x9e\xf4\x5d\x7b\xf7\x5f\xd7\x11\x82\xdd\x6e\x64\x01\x38\xf1\x82\xa6\xa0\xc6\xcb\xbd\x00\xc4\x95\xc4\x38\x95\x30\xac\x8e\x67\x96\x0e\xb5\xc5\x76\x3f\x54\x84\xea\xb1\xc1\xab\x85\x01\x40\xda\x04\x2b\xa4\x7e\xd8\x52\x88\x00\xd4\x17\x87\xf0\x75\xfe\x0d\x85\x50\x1a\x7a\xb7\x66\x35\xd0\x34\x10\xd2\x86\xc0\xe1\x7d\xb4\x02\x3a\x76\x39\x74\x68\xcc\xb0\x91\xcc\x5a\xc1\xf6\x43\x45\x87\x91\x3e\xab\x92\x2b\x50\xca\x55\x67\x01\x6d\xde\xa3\x2f\xb5\x32\x55\xbe\x67\xf2\xdc\xf9\xff\xa8\x5d\x11\x7f\x1a\x65\x5f\xa7\x0d\xd3\xa5\x4c\xf9\x91\x53\x1f\x19\x13\x0e\xaa"}, -{{0x26,0x99,0x52,0x17,0x2c,0x3f,0xa9,0x76,0xde,0xfb,0xf4,0x0b,0xd6,0xed,0xd8,0xf1,0x5c,0xfd,0x4b,0xe1,0x0c,0x75,0x8e,0x37,0x41,0xd7,0x41,0x62,0xd8,0xea,0x22,0x9a,},{0x4a,0xea,0x57,0xc7,0x21,0xe3,0xdc,0xca,0x82,0x39,0xe9,0xad,0x9b,0x22,0xc1,0x9b,0xab,0x8d,0xf7,0x2c,0x88,0x79,0x3b,0x24,0xd8,0xdc,0x47,0xcf,0x97,0x40,0xfc,0xf8,},{0x3a,0xc8,0x0d,0x1e,0x8f,0x68,0xb4,0x05,0x8c,0x3a,0x04,0xda,0xd7,0x18,0x73,0x73,0x95,0x9f,0x26,0xa2,0x70,0x02,0x49,0x6f,0x8a,0xfa,0xac,0xcd,0x8b,0xea,0x09,0x01,0xc5,0x4c,0xab,0x87,0xb2,0xa2,0x30,0x2e,0x1f,0x36,0x25,0xc2,0xb0,0x6c,0x7e,0xbc,0xf3,0xce,0x96,0xde,0x3a,0xfd,0xf0,0x0f,0x51,0x94,0xa3,0x5e,0x05,0x52,0xc7,0x0e,},"\x7c\xcb\x6a\x05\x70\xc5\x33\x73\x7b\x9a\x53\x4a\x34\x1a\x7a\x96\xdc\x76\x52\x8b\x99\x7a\x9b\x48\xe6\xe0\xfd\xe1\x0f\x47\x4b\x27\xec\x98\x99\x12\xd1\x76\xca\xb7\x42\xd8\x9a\x84\x8b\x36\x66\xe9\x27\x7d\x69\x5b\x02\x2f\xd5\x3a\x9e\xb8\x9e\x88\xc7\x20\x39\x9e\x24\xed\x25\xdb\x9e\xb3\x5d\x6d\xa0\x09\xe9\xf0\x24\xef\x8e\x65\x51\x65\xbd\xef\x1c\x0d\x79\x7c\x74\xf0\x19\xcd\x59\x1a\x04\x42\xa1\x2d\x1c\xa8\x93\x83\x6c\xa2\x62\x8b\x33\xe8\x54\xf3\x42\x8e\xec\x4a\xa5\xed\x84\xf4\xbd\xd2\xee\xf8\xb6\xd2\x25\xca\xf9\x49\x6d\xf9\xed\xff\xd7\x35\xea\x54\xdb\x1b\xde\xa8\x83\xad\x5d\x47\xeb\x0b\xd4\xa6\x65\x3f\x0a\xb0\x37\xf0\x40\xa4\x15\x17\xa7\x74\x1f\x91\xe8\x2f\xdb\x6f\xda\x04\xf0\xdf\xa1\xbc\xf8\xb9\xb3\x7b\xf2\xbf\xbd\x87\x32\x7a\x63\x6f\x90\x7f\xdf\x96\x8d\x01\x89\xd1\xa1\x18\x09\xc4\x23\x0b\xa6\x9d\x5c\xbd\x84\xf5\x61\xbc\xac\x3a\xd0\x02\xe5\x58\xc5\xb9\xb0\x97\xa0\x19\x02\xf2\x9c\xe3\xf1\xec\x26\x41\x53\xd6\x68\xc7\x8b\x84\x51\x05\xb9\xcd\x2e\xf3\xc9\x43\x53\x1b\x75\xaa\x42\x8f\x17\x9e\x4b\x34\x18\xb1\xd5\xa4\xaa\x7a\xb1\x20\x3e\xfa\x49\x5c\x87\x69\x62\x8e\xb1\x06\x3a\x93\x7b\x73\xe4\xb5\xcd\x0c\xda\x33\xda\xb0\x1a\x50\xc6\x4f\xeb\xd9\x75\xc5\x7a\x1e\x84\x15\x08\xe8\x60\x60\x94\xd0\x82\x4f\xdd\x96\xcc\x6c\xfa\x18\xfa\x82\x09\xb3\x0f\x0a\x2a\x78\xea\xc9\xa7\x67\x17\x6f\x57\x3e\x78\xc0\x68\x80\x9b\x19\x9a\x69\xac\x6d\x33\x5d\x7c\x92\x09\x99\xc4\x0c\xba\xd8\x7c\xf4\xcc\x7c\xa5\xc6\x44\x29\x1d\x75\xad\x7a\x74\xbc\x1e\x63\x92\xd1\xce\x31\x1e\xcf\xd2\xeb\xc9\x16\xe3\x9e\xb6\xaa\x3e\x7d\x89\xfb\x80\x5a\x27\xa5\x5f\x17\x89\x12\xb1\x57\xbc\x01\xa0\x55\xf6\x7a\xef\xa7\x8e\x55\xc8\x06\xcb\xd9\xc0\x1b\xaf\x8e\xf9\x2c\xad\x22\x60\xb4\xbb\x14\xcf\xe6\x17\x82\xde\xe5\xc5\x99\x72\x50\x69\x41\xc4\x62\xa4\xda\x7e\xb8\x99\x53\x1c\xf9\x96\xbc\x98\xba\x36\x29\xef\xfe\x6f\xcd\x17\x06\xd1\xb4\xee\x4f\x2a\x14\xe9\x21\xbd\x40\x8f\x30\xe1\x2e\x73\xfb\x7a\xa8\x60\x53\x6b\x03\xe7\x7c\xa9\x37\x82\x32\x81\xa1\x64\x53\xfe\x82\x79\x35\x94\x32\x01\xe6\xec\x14\x3a\x67\xee\xfa\x4f\x94\xe9\xab\xf9\x4f\x7e\x3d\x41\xb7\x0a\x82\xbe\x69\xde\xd8\xa5\x30\x60\xc2\x30\x5f\x42\xf6\x2f\xe6\xa2\xf7\x04\xb6\x7a\x1e\x8f\xdd\xc7\xd9\x8b\xa7\xf3\x45\x71\x19\xb3\x11\xd4\x49\x66\x3e\xd9\xe3\x20\xd6\x18\xdc\x23\x68\xd4\x95\x08\x75\xb9\xc3\x8c\x5d\x8c\x03\x10\x4e\x2e\x32\xc4\x32\x5d\xed\xd2\xbc\x26\x7e\x2a\xcc\xb0\x11\x20\x18\xe9\xc5\xa8\x00\x7c\xca\xb2\xf6\xd7\xc7\x37\x79\x20\x02\xac\xb7\x30\xd7\x2e\x9f\x73\x08\x29\xeb\xc4\x2c\xa5\x64\xc1\xd9\x27\x1b\xf1\x86\x9c\x4d\x35\x83\x55\x89\xb7\x43\x1e\xf7\xa3\x1a\x07\x00\x60\xfe\x4a\x08\x9f\xb1\x1f\x2d\xd3\xdc\xe6\x5a\xe0\xfb\x45\xbc\x3a\x28\x60\x91\x7d\x93\x3b\xa2\xd0\x90\x56\x9e\xf5\xed\x43\xbc\x25\x32\xdb\x87\x9e\x0f\x1f\x22\x5e\xad\xcb\xef\x1c\x03\xd9\xed\x78\x29\x9e\x23\x3e\x4c\xf0\x7b\x06\x4a\x7b\xaa\xc3\x4c\x5a\x0c\x19\xfc\x3a\x55\x42\x08\x9f\x70\x16\x7b\xe2\xf8\x5b\x4a\x10\xe7\x78\x52\x52\x23\xbe\x8f\xfd\x5c\xff\x96\x48\xb1\x00\x5a\x09\x8b\x4b\x39\x24\x39\x8f\xb0\xbc\xab\xcc\x6e\xdf\x30\xc0\x61\xec\xe7\xae\xa3\x5f\xe9\x8a\x92\x03\xf8\x71\x13\x69\x53\x0f\xeb\x5e\x67\xbb\x2d\x4f\x59\xd9\xc8\xbc\x99\x38\x54\xdd\x47\x47\xcd\xe3\x99\xbd\x0e\x63\x74\x0c\x1c\xc8\x39\xad\x0f\x09\x8a\x38\xa8\x0b\xea\xdd\x64\x8e\x14\x36\xde\xee\x60\xe9\x31\xe6\x8f\x52\x97\x9c\xe4\x9f\x30\x1f\xe3\x9a\xfb\xb6\x15\x35\x20\x91\xc8\xb6\x58\x5f\xe8\x84\x47\xed\x6e\x59\xa0\x20\xb2\xbb\xe6\x6a\x94\x23\xae\x52\x28\xc2\x03\xbf\xd4\x84\x7b\x51\x81\xe2\xc3\xb4\xda\xd8\x3a\x6d\x4f\xa7\x69\x85\xee\xf7\x6a\xdd\xe3\xb3\x4e\xdb\xdd\x28\xd6\xa0\xb4\xa4\xee"}, -{{0xcc,0x31,0x38,0xe5,0x02,0xa5,0xff,0x6f,0x80,0xd2,0x46,0x36,0x6e,0x84,0xd6,0x5c,0x59,0xf1,0x2d,0x4f,0x49,0x63,0x97,0xe6,0xeb,0x99,0xb5,0x26,0x7b,0x8c,0xbe,0x2a,},{0x9e,0x2d,0x3e,0x88,0xaf,0x7b,0x52,0xdd,0xcf,0x00,0xe6,0xd0,0xc7,0x75,0x9c,0x12,0x38,0xb8,0xfb,0x3e,0xb1,0x44,0x21,0xfe,0x82,0xc3,0x48,0x33,0x43,0x78,0x35,0xbd,},{0xa2,0x70,0x0e,0x38,0x95,0xed,0x0c,0xc2,0xaa,0xf0,0x12,0xa4,0x0b,0xc7,0xbd,0x0b,0xd2,0x9d,0xd7,0x9c,0x69,0xc0,0xb4,0xa6,0xed,0xd0,0x53,0x0c,0xf3,0xe2,0x67,0xc0,0xf8,0x2d,0xd8,0x4e,0xda,0xf1,0x74,0x4d,0xc4,0x11,0xd6,0x2c,0x00,0x28,0x71,0x52,0x58,0x82,0x2d,0x7b,0x63,0xd3,0x97,0x05,0x61,0x2b,0x3f,0xad,0x4b,0x5e,0xfb,0x04,},"\x58\x5e\xcf\x2f\x09\xeb\x92\x3d\xf2\x0a\x85\x55\x64\x2a\x2b\xc0\xb6\x8c\x6a\x5f\xcf\xd6\xb8\x40\x1c\x4a\x0c\xba\xbb\x4c\x6e\x6a\x20\x67\x62\xb7\xa3\x9f\x2c\x54\x55\xd7\x80\x8e\xbf\xbe\xd5\x6d\x67\x60\xa4\x31\xc7\xd2\x0c\x2d\xc6\xef\x1b\x73\xca\xa3\xc4\x94\x88\xe3\x0b\x1c\xa2\x52\x0a\xd2\x0b\x26\xa1\x97\x00\x78\x0e\x5e\xf3\xce\x01\x44\x38\x8d\x84\x07\xb6\xa7\x0c\x1c\xda\x37\xdb\x7f\x12\x09\x1d\x89\x2f\x2e\x91\xad\x40\x78\xbb\x4d\xb1\x76\x2e\x46\x28\x5a\x7b\x66\x4b\x2a\xd3\xa3\x4d\x26\xd8\xa9\x4d\x64\x58\x7a\x84\x52\x77\x22\xea\x83\xcb\x8a\xa8\x89\x84\xe1\x48\x97\x43\xb4\x21\x4e\xa6\x04\x1a\xa1\x8e\x55\x20\x09\x54\xef\xc7\xed\xb3\x19\xdf\x94\x7e\xfb\xfc\x6c\x8d\x0f\xea\x48\xa1\x31\x61\x34\x65\xd8\xf4\xc4\x94\x98\xf2\x26\x91\x45\xc6\xda\xe5\x04\x78\x05\x25\x98\xe1\xca\x3b\xe0\xe3\x36\x11\x57\x1f\xa3\x84\x77\x1e\xee\x40\x2c\xc2\xb1\xd8\x48\x36\xc8\xf1\xad\x28\xf2\xad\x23\xde\xe9\xff\x1d\x7e\x1f\x25\x21\x63\x58\x74\x11\x5d\xef\x4d\x93\xe8\x9b\xe7\x61\x80\xbc\x55\xf7\x61\x14\x43\x60\xa8\xb2\x22\x89\x2d\x64\xd1\x57\xcc\xb5\xd8\xf4\x85\x5d\xca\x56\x70\x14\x95\xa0\xe1\x00\x2d\x34\x0a\x4a\x46\x15\x6b\x9b\x7f\xe0\x6b\x7c\x07\x59\xe0\xb6\xdf\x55\x9b\x69\x1e\xde\x78\xb5\x5a\xf6\x4e\x7c\x8d\xd9\x08\xb7\x88\xdd\x6b\xa3\x5a\x90\x2c\x81\xdc\xeb\x37\x88\xb6\x15\xde\x22\x5a\xfa\x58\xa8\x11\x81\xab\x24\xa7\x37\x05\xee\x83\x8b\x6e\x86\x3f\xe1\xbc\xc2\x6c\x1b\x94\x32\x39\x23\x0c\x27\xc6\xb3\x97\xb2\x3d\x13\xde\x6a\x02\xc9\x7f\x36\x45\xda\x91\xd4\x13\xf9\x16\x47\x3b\x01\x8a\x61\x59\x4b\x6f\x51\xce\xa4\x44\x57\xda\x1e\x3d\xbb\xba\x6d\xe1\x68\x66\x65\x7e\x92\xef\x02\x02\x71\x8a\x84\xad\x03\x33\xe8\x33\x6b\x05\x2b\x00\x47\x33\xe8\xe9\x5e\xc1\x3e\x5f\x91\xb3\x80\x6a\x98\xd3\xdb\x72\x9f\xb7\x35\xb8\x14\x7c\x4a\x98\x2a\x2d\x5b\x4e\xfa\xe9\xc0\x9d\x0a\x9b\xf8\x91\xcb\xbc\x3c\x8f\x53\x1e\x76\xe4\x04\x4e\xc9\x1f\x4d\x7c\x5c\xf7\x73\x10\xe2\xb2\xcd\xe2\xe0\x7c\xcf\x3e\x0a\x19\xdd\x6a\xe1\xb3\xfc\xb2\xdf\x42\x18\x6e\x9c\x72\x92\x2d\x2d\x4c\xe5\x1b\x30\x6e\x81\xb1\x6c\xfc\xf8\xf0\x0d\x51\x3f\xbd\x2c\x52\x39\xb4\x5a\xfc\x65\x4f\x6f\xe2\x1a\xcb\x7e\x8a\x0c\x9a\xa8\x7b\x0b\x60\x50\x74\xdf\x95\x76\xa6\xdd\xd9\x00\xac\xa5\x67\x61\x7c\xb7\x96\x56\xb3\xb5\xec\xb9\xff\x68\xb2\xf6\x24\x1e\xd0\xd0\x24\xac\x27\xaa\x6e\xb4\x86\xb6\x9f\xdc\x0a\x0d\xb9\x20\x96\xab\xf8\x60\x02\xde\xc7\xaf\xd8\x47\xa0\x06\xa3\xf6\x95\x5b\x49\x56\x90\x53\xbe\x9f\x1d\x0a\x49\xb7\x93\xa5\x41\x1e\x59\x16\xf4\x18\xec\xab\x95\x32\x43\x55\x3b\x66\xe6\xba\xdc\x4e\x90\x9b\xe0\xef\x5c\xc7\xc6\xd2\x71\x99\xec\x3f\x21\x42\x3b\xc4\x57\x73\xfb\x40\xb9\x7b\x61\x18\x5b\x57\x08\x0e\x8f\x0b\x89\xa3\xea\x57\xc8\x44\x4a\xb2\x7e\xcf\x70\x06\xa7\x66\x04\x7e\xef\xf5\x4d\x85\x56\xcf\xed\x23\xde\xf1\xda\x2c\xc8\xae\xbb\x48\xc9\x4e\x77\x9e\x82\x03\xae\x2c\x90\x2b\x51\xde\x0e\xde\x04\x56\xfb\x73\xfb\x4d\x5f\x51\x4a\x4c\xeb\xc4\x7f\xec\x3f\x94\x84\x69\xa5\x45\xc6\xbc\x57\xb4\x13\x8d\xb3\x4e\x7c\xc0\x06\xde\x26\xef\x50\x7b\x54\xd2\x81\x47\x56\x7a\x8c\x29\xac\x1e\xce\xf5\xbb\x84\xfb\x99\xac\xeb\x23\xa2\x02\x94\xd7\x4a\x85\xae\x36\xb3\x34\x50\x66\x8a\x5c\x26\x09\xd3\xa9\x39\x34\x58\x6f\xf9\x0c\x3b\x6d\x27\x32\x9e\xee\xf3\xa7\x54\xe9\xa9\xcb\xd5\x61\x7e\xf3\xb0\x93\x97\xbd\xc9\x71\x37\x07\x66\x58\x9a\x12\xd8\x90\x05\x0d\x16\x51\x45\x8b\x3f\xc5\x33\xc8\x43\xbf\xfd\xf9\x75\x4d\x93\x2c\x4e\xd7\x61\x1d\x4d\x27\xc3\x2a\x08\x75\x55\xb5\xea\xa3\x7a\xe9\x0c\x49\x79\xef\x54\x29\x9c\x42\x0a\xb5\xe2\x9a\xe2\x84\x5d\x4d\xcf\x21\x78\x92\x0a\x86\x51\x75\xfb\x9c\xc0\xe6\xb8\xc5\x24\xb1\xee\x49\x58\x05\xd5\x17\xbf\xe0"}, -{{0x5c,0x69,0x2c,0x68,0x11,0x98,0xb1,0x72,0xdf,0x2f,0xac,0x2a,0xec,0x3f,0xcf,0x70,0x15,0xc2,0xbb,0x68,0x30,0xf2,0xa9,0x8e,0x30,0xa3,0x96,0xb6,0x4a,0xf4,0x28,0x0e,},{0x33,0xb1,0x69,0xd4,0xca,0x27,0x10,0x40,0x92,0x6e,0xa8,0x78,0x35,0xe5,0x06,0x6f,0x9f,0x05,0x78,0x2f,0x08,0x7f,0xca,0x7a,0x55,0x6f,0x7b,0xf4,0xcb,0xa2,0xe8,0x86,},{0xad,0x8f,0x37,0x9c,0xaf,0x41,0xf7,0x2d,0xcc,0xad,0xc3,0xe9,0x15,0x35,0x7a,0xb0,0xcd,0x30,0x4e,0x10,0xf4,0x12,0x0e,0x0d,0xbb,0xfa,0xac,0x01,0xbf,0xfa,0xf2,0xbe,0x89,0x3f,0x70,0x07,0x2d,0xc9,0x64,0x06,0x91,0x81,0xbe,0xc1,0x7f,0xe0,0x25,0x10,0x55,0xb2,0x1e,0x23,0xde,0xe4,0x36,0x3b,0x27,0xef,0x1f,0xff,0x67,0xaa,0xfe,0x06,},"\xb1\x60\xee\x3a\x93\xcf\x6b\xc3\x45\x6e\x5b\xd0\x19\x7c\x09\xaa\x76\xc2\x25\x80\x52\xf9\xa3\x4d\xbc\x2e\xd5\x89\xf8\xdb\xe5\xff\x99\x69\xa6\x1c\xfe\x84\x6b\x2f\x67\x39\xdc\x7d\x4a\x14\x96\xe9\xad\x58\x60\x5b\x5a\x27\x58\xca\x07\x8c\x55\xa9\xfc\x1c\x4e\xeb\x54\x91\xa8\x4b\xfd\x46\x8a\x2c\xeb\x14\x1a\x77\x34\x93\xa9\xb3\xee\x82\x8b\x5d\xde\x9c\x00\xc2\x36\xff\x01\x56\xe4\xe2\xe4\x5f\xa0\x79\x31\xda\x68\xbb\xd2\x03\x0a\x88\x14\x05\xc4\xf7\x87\x28\x81\x3a\x5e\x04\x81\x24\x04\xc2\xa1\x9c\x9b\x87\xb1\xcf\xe9\xaf\x95\xe2\x73\xec\xf9\xc5\x18\xc5\x39\x35\xf8\x42\x56\x3b\x19\x2f\xae\x12\xa7\x3c\xef\x08\x5f\xe1\x9e\x89\x9e\x5b\xa0\x89\x79\xe3\x11\xfb\x28\x6f\xbf\xc7\xb2\x48\xaa\xbd\x40\xdc\x61\x61\x0e\x1d\x4f\xc9\x80\x6d\xd2\x12\x92\x39\x2d\xb2\xdb\x40\x42\x6c\x5d\x19\x6a\x48\x9c\x5d\xb7\x7e\x3e\x9c\xf0\xbd\x04\x1e\x3c\x23\xb5\xba\x1d\xb7\x81\xa1\x07\x90\xbe\x1f\xe0\x7a\x2b\x00\xca\x3a\xf8\x9c\xbd\x46\xef\xce\x88\x0e\x1e\xf2\x8b\x0c\xd7\x9d\x53\xb4\x2c\xd8\x0e\xaa\x13\x7e\xff\x7d\xf9\x0b\xcb\xcf\x95\xc9\x85\x8d\xc0\xcc\xc6\xd8\xca\x8a\xe3\x54\x7b\xdb\xf9\xff\x90\x24\xf3\xcf\x17\x01\x15\xeb\x28\xbf\x12\xb7\xd3\xb7\x01\x46\x0f\x48\xd1\xb4\xb2\x3d\x7f\x6f\xf7\x2f\xfd\xc9\xa6\xc5\x26\x24\xd1\x53\x12\xd7\xf1\x9d\xdb\x60\x26\xa1\x5e\xb5\x42\x95\xd3\x31\xfd\x79\x50\x91\x03\xbc\x59\xa3\xb6\xe1\xba\x7a\xc8\xc1\x12\xe4\xde\x28\x17\xe5\x1c\x1e\x16\x50\x7b\xa6\x6f\x25\x47\xbc\x89\x9f\x69\xc1\x20\x7a\xe5\xe3\x7b\xdb\x0e\x16\x1b\x15\xb6\x12\x30\x5b\xc0\x94\x0f\x9d\x1b\x38\x2a\x37\xec\x2d\xa6\x39\xa6\xec\xba\x1b\xcd\xfc\x51\x21\x4c\x32\x23\xc1\x1b\xba\xb7\x9f\x3f\xae\x3d\x55\xe2\xd4\xbe\x58\x4f\xd7\x60\x1e\x4e\x2e\x55\x8b\x3b\xe5\x70\x71\x15\xa6\x1f\x5a\x81\x5e\xc2\x4a\xac\x18\x09\x34\x57\xbc\x46\xc0\x5c\xfb\x7a\x3f\x25\x33\xea\xda\xdc\x9e\x6c\x1f\xe3\x10\x77\x9e\x69\x7f\x68\x30\x35\xce\x57\x87\x3d\xf5\x5d\x79\x1f\x6d\x2f\xb0\xe2\x10\x7e\x68\x66\xf8\x39\xc3\xa1\x26\xe9\x02\x38\x65\xce\xd1\xbc\xf6\x77\x99\x55\xaf\x54\x7e\x1d\x87\xeb\x32\xa9\xbf\x32\x28\x57\xfd\x12\x6b\x0c\xdc\x5d\x5e\x90\x4e\xb7\x6c\x67\x06\xe3\xc8\x97\xae\xfd\x6e\x47\x56\xfb\x8a\xca\x81\x70\xca\x5b\x39\x66\x90\x89\xaf\x1b\xb1\x41\xa2\x5d\x6b\x8b\x06\x03\x4d\x8b\x11\xab\xf1\xff\x8f\x8d\x43\x37\x58\x46\xfa\x8f\xa8\xa3\x4b\x5f\x26\x48\x20\x74\x4d\x31\x14\x9b\x7d\x57\x32\x6c\x59\xb1\xdb\x74\x13\x16\x78\xf6\x34\xe7\x23\x2c\xa5\xea\x51\x88\x76\x0a\x70\xdc\x35\xdc\x89\xf8\xe4\x53\xb4\xc6\x5b\x77\x2c\x2b\x6b\x62\x76\x8d\x83\x73\x23\x65\x51\xba\xaf\x24\xd3\xc3\x04\xc4\x1b\x62\xc3\x6e\x6a\x33\x83\xb3\xa1\x63\xb7\x3e\x78\xd8\xba\xdb\x75\x74\x1e\x50\x01\xd4\x19\xd3\x0e\x2e\xd7\x7c\x30\x96\xe8\xd8\xdf\x71\x3b\x93\x76\x2c\x97\x07\xbd\xd0\xf3\x65\xa8\x74\xb9\xda\x8a\xb7\x10\x49\x5d\xd5\x6a\xea\x93\xbb\x77\xfb\x22\x26\x35\xc6\x3b\xce\x9f\x63\xaf\x91\xfa\xc8\x9c\x66\x98\x6b\x8e\x21\x76\xdd\x45\x1d\x58\x33\x94\xc1\x90\x7c\xba\x17\x25\xf0\x6d\x25\xd1\xd0\x91\x2b\x3e\x5c\x6c\x7d\xcd\x34\x35\x8f\xad\x59\xdb\xc6\xf6\xb1\xc2\xef\x33\xd3\xca\x82\xf4\x35\x18\xfe\x4f\xf3\x13\x78\x01\x6e\x57\x8a\x7b\xab\x0b\x77\x67\x6e\xba\xe0\xd4\x8d\x08\x89\xd6\x90\x29\xd2\x09\xf2\x83\xce\x8f\xe0\xec\x23\xcd\x83\x2a\xdc\x12\xa9\xc3\xe3\xae\xc2\xd6\x03\x66\x95\x55\x6d\x93\x13\xf1\x2a\x89\x9d\xd5\x9a\x66\xbe\xf2\x8e\xde\x17\x5f\x8a\xae\xee\xb2\x94\x2b\xb9\x08\x92\xa0\x4b\x44\x0d\x04\xb6\x6f\x5e\xef\xf6\x1a\xda\x72\x79\x02\x94\xce\x55\xc8\x6c\x6d\x92\x78\x5d\xdd\x26\xc7\xa7\x31\x60\x3b\x06\x9c\x60\x3c\x92\xe4\xfe\x8f\xf7\x82\x54\x4c\x8e\x89\xb4\x0b\x8b\x55\xf9\x0e\x2a\x5e\x9a\x0f\x33\xc7\xfe\xc7\x7d\xad\x81\x52"}, -{{0x9d,0x5f,0x85,0xd2,0xe7,0xdf,0xd0,0x3b,0xb6,0x89,0xd9,0x00,0x28,0x5f,0xd4,0x46,0x15,0x38,0xa5,0xf2,0x71,0x0a,0x13,0xed,0x21,0xc7,0x75,0xf6,0xef,0xf6,0xb3,0xff,},{0xb8,0x67,0x97,0xe4,0xbe,0x02,0x86,0xae,0x39,0xe4,0x4d,0xf0,0xa0,0x0c,0x01,0x6d,0xb4,0x55,0x5e,0xf8,0x6f,0x2f,0x05,0xd0,0xa3,0xed,0x89,0xd8,0x9a,0x4c,0x3e,0x5e,},{0x17,0x6b,0x95,0x92,0xf8,0xc2,0x51,0x35,0x29,0x2a,0xdd,0x4d,0xaa,0xcc,0x9c,0x4f,0xaa,0x21,0xd4,0xf4,0x9b,0x27,0x84,0x80,0xc4,0xe8,0x88,0x1c,0x01,0x62,0x4d,0xf9,0xa3,0x7e,0x23,0xe1,0x8e,0x84,0xca,0x32,0xd0,0xd8,0xcb,0x85,0x10,0x54,0x22,0x2f,0x10,0xa4,0x95,0x41,0x9f,0x19,0x7e,0x7b,0x3d,0x18,0xdf,0x0a,0xdf,0xb1,0xb3,0x07,},"\xf7\x0b\x5b\x05\x3a\x46\x72\x51\x2c\x24\xb3\x16\x83\x92\xf6\xa1\x7d\xd7\x7d\x86\x89\xc2\x1c\x86\xef\xc2\x58\x29\xa1\xa0\x4f\xab\x4f\x76\xc8\x52\x16\x84\xd3\x20\x10\x45\x59\x07\xa2\x69\x08\x67\x7b\x40\xdc\x69\x47\xd6\x54\xf2\x91\x4c\x30\xec\xee\x72\x4f\xa6\x84\x46\xb5\x9d\x09\x1e\x25\x8f\xc8\x62\x41\x1c\x96\x4d\x66\x8d\xef\x83\x03\x4b\x62\x7e\xd4\x16\xdc\x19\x0b\xb5\xa2\x63\xa6\xff\x8d\x55\x9e\x13\xb8\x93\x62\x25\xfb\x4d\xab\x4f\x7b\xda\x04\x68\xe5\x47\xe7\x08\xcb\x04\xce\xbe\x1e\x5c\xfc\x69\xf7\x6a\x1d\x28\x3f\x28\x16\x82\x86\xf2\x4e\xce\xa5\x53\x5e\x44\x90\xa0\xc5\x55\x67\xa7\x34\x5e\xf9\x53\xce\x42\x6b\x20\x9a\x3d\xe3\xdf\x59\x5e\x80\xee\x61\xe5\x72\xa2\x78\xab\x02\x21\x95\x51\xb7\x3d\xa4\x19\x84\x80\x82\x85\xa8\x35\x98\xa0\x2d\x9b\x28\x67\x12\x10\x00\x4e\x31\xd8\xaf\x92\x42\xc1\x6f\x90\xd5\xea\x8f\x63\xa1\xff\x66\xcf\xe6\x0e\xcb\xe5\x37\x24\x5f\xa1\x2a\x9b\x15\x41\x15\x29\x58\x06\xea\x2d\x11\xf3\x67\x17\x82\xb9\xaf\x4f\xa8\x6a\x12\x88\xe1\x23\xcf\xd2\x40\x9a\x5d\xc9\x8f\x41\xb8\xf6\xdf\x29\x9b\xbc\xc4\xbb\x64\x47\xdc\x03\xa6\xd6\x0e\x9b\x2c\x5b\x8f\xfc\x40\xd9\x83\x95\x6b\xe9\x77\x68\xdd\x06\x12\xd4\x7c\xbf\xa7\x57\x1c\x99\x69\x85\x6c\x15\x2c\xd3\xb4\x73\xac\xe0\xb8\xa1\x44\xaa\xc2\x09\x5c\x0f\x72\xf1\xd3\x14\x71\x52\xb9\x08\xef\x66\x26\xd5\x22\x28\x19\xb2\x0b\xb3\x35\x0a\x46\x45\x2f\x67\x54\x90\xc2\xa8\x21\x50\xee\xc4\x0d\x75\xb6\x6a\x32\x5d\x6e\x92\x9a\x90\x5a\xde\x1e\x31\x60\xab\x95\x01\x81\xef\xc6\x6e\x59\x23\x08\x65\xd5\xe5\x99\x69\x8a\x8a\x3f\xf5\x60\xc4\xc6\x01\xa7\xa9\xa5\xda\x3b\x5d\x89\xbc\xa9\x3f\x7c\xf5\xbc\xf5\xbd\x5e\xcf\xf8\xf1\xa1\x85\xc8\x22\x0e\x4c\x77\x82\x1e\x62\xad\xf9\x5a\x03\x7f\x2d\xf7\xce\xf4\x3a\x4c\x60\xac\x75\x80\x1e\x9f\xcc\xdc\x5b\x08\xee\xd3\x28\xdd\x93\x10\x09\x04\x11\x56\x45\xec\x1e\xe0\x85\xcc\x77\x8b\x0f\x4e\x46\xe1\x72\x98\x98\x4a\x70\x2e\xce\xb3\xe1\x52\x83\xd8\x20\x00\x4f\x74\xa0\x79\x52\x0d\x63\xa7\x5f\xae\x33\xec\x3f\x4b\x83\x64\x69\xe1\xaa\x99\xea\x24\x4a\xf1\xfb\x08\xb0\x0a\x8c\x9d\xfd\x03\x30\x8d\xfc\x20\x23\x5e\xa9\xc8\x28\x3f\x4d\xa4\x7c\xfb\xcd\xbd\x03\x1a\x02\xd1\x64\x16\x0f\x2a\x58\x98\x67\x00\xb1\x95\x26\xd4\x1e\x4d\x7f\xd4\x58\x43\x4d\x72\x64\xbc\x8e\xb6\x42\xe6\xd8\xdd\x27\x59\xce\x2b\x85\xc9\x7b\x37\x02\xe7\x0d\xa7\x1f\x18\xed\xc5\x3e\x91\x40\xa6\x45\x62\x7e\x02\x78\xe8\xe7\x05\x39\x03\x74\x84\xdc\xd1\x8c\x62\xfa\x33\x07\x17\xd6\x14\x8a\x0d\x62\x3f\xf8\xb6\x5e\xa8\x56\x7e\xc7\xfa\x04\xc8\x92\xe3\xa1\xec\xee\x96\xe8\x32\xf4\x15\x50\x74\xc8\x3c\xbc\x93\xe9\x8c\xc6\x7f\x1f\xa1\x12\xaa\x06\xe9\x91\x5f\xa4\xd2\xde\xa9\x31\x55\x1e\x7c\x62\x3a\xa8\xa3\xa7\x61\x9e\xa2\x4f\xf9\x14\xe2\x64\xf3\x1f\xc7\x3d\xfa\x8c\x43\x0a\xc4\x6c\xe1\x6d\xc9\x68\xc5\xa4\x08\x5d\x5c\x38\x0d\x30\xcd\xc6\xf4\x3d\xee\x80\x6f\x38\xd1\xdf\x42\x0a\x06\x55\x74\x14\x47\x37\x05\x6d\xaa\x62\xf0\xc0\x98\xc9\xc5\x2f\xcc\x04\xcc\xa6\x42\xc4\x5d\x68\x73\x45\xa0\x94\x61\x3d\x4a\x3c\x6c\x87\x88\xbf\xa2\x18\x53\x8a\xd7\xec\xe1\xbd\xb6\xc9\x39\x24\xee\xc4\xba\xaa\x3e\xb1\x5d\xc1\x49\x4d\x65\xff\xa1\xa2\x3f\xf8\xe9\x85\x26\x34\x08\xfb\x02\xbf\xe3\x9a\x8c\x55\xb3\x00\xb1\xa0\x2e\xd3\x6c\x67\x14\xdd\x5a\xb7\x50\xd4\x7f\x02\x1f\x65\xe0\x8c\x63\x5f\x1d\x6b\x7b\xaf\x39\x6c\xb4\xf9\x3d\x56\xc1\xca\x46\x1b\xb1\x2e\x94\xde\x7e\x5d\x98\x65\x9a\x8a\xf0\xbf\x01\x9f\xc4\x22\x80\xe1\x11\xe0\x48\x00\xff\x80\xe0\xc1\x57\x15\x0e\x16\x56\x09\x45\x42\x81\xb2\x00\x07\xe3\xed\xfa\xa1\xea\x85\x44\x65\x54\x7a\x00\x6a\x4c\x32\x36\x41\x14\x95\xda\x16\x60\x98\xaf\x28\x23\xa4\x59\xcf\x10\x0a\x1f\x3c\x92\xc6\x39\x0c\x60\x66\xcd\xbf"}, -{{0x4a,0xaf,0x2d,0x13,0x28,0x84,0xf3,0x0d,0x11,0x27,0xcf,0x18,0x7e,0xe0,0x93,0x88,0xb4,0xa5,0xc4,0x4a,0x9a,0x92,0x67,0xe6,0x72,0x83,0x17,0x39,0x89,0x51,0xfb,0x61,},{0x83,0x72,0x7e,0x92,0x57,0x34,0x91,0x28,0x55,0x9e,0xbf,0x75,0x9f,0xdc,0x82,0x12,0x2c,0xce,0x76,0x74,0x66,0x39,0xc0,0xad,0xa9,0x76,0x1f,0x0d,0x60,0xb9,0x40,0xb1,},{0x5f,0x11,0xdf,0x39,0x06,0xa7,0x12,0xa9,0x53,0xf4,0x7c,0x85,0x98,0x06,0xb5,0x23,0x73,0x58,0xd0,0x8b,0xa9,0x5e,0x49,0xf9,0xe5,0x30,0xa3,0x71,0x65,0x83,0x5e,0x93,0x59,0xd9,0x76,0x9d,0xc2,0x1f,0xbb,0x4d,0x44,0x49,0x7b,0x93,0x90,0x5b,0xca,0x8d,0x99,0x17,0xc7,0x28,0x49,0x3f,0xee,0x3a,0xcd,0x5b,0x52,0x1d,0xbd,0x1e,0x24,0x08,},"\xd7\x3e\xaf\x11\x41\x3b\xf4\xd5\xbc\xcf\x6a\x2e\x80\x9c\xd6\x83\x2a\x51\x82\x3a\xa2\x2b\xd1\x6e\x09\xcf\x56\xff\x04\x5e\xef\x2d\x1a\xda\xdd\xa5\x0c\x2e\xbd\x67\xbb\xc4\xd7\x0e\x49\x3c\x96\x8c\xb4\xde\x49\x77\x06\x5d\x44\x63\x30\x06\x94\xc9\xca\xa5\x72\x06\xd6\x66\x46\x93\xd8\x46\x2c\x3c\x57\x6b\x52\x5c\xc7\xac\xf7\x9f\x26\xf9\x05\x5a\x1b\xcf\xa7\xd0\x77\xf4\x5e\xbe\x0b\x2d\x48\x1e\xbd\x63\xf7\x34\x0a\x33\xe4\xab\x68\xf1\x60\x49\x75\xec\x1d\xfe\xc4\x5a\x79\x1a\x2a\xbb\x10\x44\xd7\x5a\x4d\xb5\x5a\xdf\x59\xb8\x39\x4e\xbd\xe6\x82\x4c\x21\x14\x5b\x00\xef\x3b\x1b\x08\xed\x11\xfd\x51\xdd\xa5\x14\xed\x7e\x21\xe5\x4d\xba\xf6\xab\xb6\xd9\xe3\x17\xfc\xf9\xfd\x37\x5b\x18\x76\x4e\x64\xac\x9b\xe5\xb0\x8f\xec\x3b\x78\xab\xba\xb1\xd1\x2a\x2a\xb0\x9d\x55\x9a\xcd\xc7\x13\x3f\xb2\xe0\x00\x8e\x0c\x11\x4b\x7c\xad\xb4\xbf\x76\x30\x78\x67\x4d\x03\xe9\xc8\x07\xbe\xc1\xe2\xca\x71\xad\xcd\xaa\x31\x0d\x58\x7f\xa5\x69\x50\xfc\x0f\xb2\xe9\x79\x04\x3d\x50\xf9\xae\x23\xfa\x8f\x82\x1c\xd9\xd6\x23\x27\x89\xd0\xee\xcc\xfc\x4f\x47\xe3\xad\x80\x4e\x25\xcf\x5a\x42\x5f\x94\x37\x7d\x17\x87\x48\x33\xe6\xae\x36\x38\x17\x8c\x78\xb7\x95\x19\xd6\x4d\x97\x93\xf4\x50\x46\x06\xa0\xea\xb6\x87\x07\xf6\xe1\xf7\xcc\xcb\x51\x5b\xe3\xd1\x20\x1b\xcd\x19\xf2\xf0\xe2\x55\xc7\x22\xea\xb1\x2b\x43\xaf\xf8\xc8\xc5\x56\x11\x25\xfb\xca\x1f\x65\x42\x07\x6a\x06\x15\x2e\xb7\xe4\xb0\x78\x63\x24\xc2\x49\x5e\x79\xd7\x9c\x0a\x8e\x29\x5b\xb2\xe3\xdf\xd0\x5a\x90\x33\x19\x00\x65\xa2\x84\x55\x2a\x6e\x73\x60\x06\xac\xe4\x1f\x97\xcc\x43\x4a\x25\x12\x05\x1b\x72\x7c\xe5\xbc\x9c\x4a\x75\x52\x9e\xc5\x3d\xd7\xd1\xf1\x26\xe7\x93\x85\x77\x47\xb5\xba\x8d\x03\x15\x5d\x45\x55\xf5\x9e\x8b\xaf\x2f\x0c\xdb\xa8\x71\xac\x16\x0e\x75\x19\xa8\x52\xdb\x00\x4f\x70\x16\x41\xa4\x0a\x42\x2d\x4c\x38\xb6\xc0\xc3\xcc\x8f\xbb\xd0\x53\x22\xdd\xc0\x00\x1f\xb8\x67\x28\x6e\x29\x6c\xbd\x69\x86\x2c\xbc\xcc\x74\x47\x03\x8e\xb3\x0f\x8a\x81\x23\xb7\xb3\x13\x73\x98\x47\x02\xc3\xbe\x45\x7a\x4b\x8c\x54\xe6\xe5\x28\x04\x85\xa2\xc4\xff\x84\x52\x1f\x29\x8d\xde\xb3\xb3\xb2\xbc\x91\xf1\x14\xdd\xce\x67\x03\x02\x48\x04\x44\x69\xdc\x06\xf3\x62\xf2\x91\x9a\x3f\xec\xe5\x08\x23\x75\xd0\x40\x80\x37\x6f\xe2\x19\xd9\xb4\x57\x5b\x1c\xf1\xc9\xec\x4d\xca\xc5\x74\x9f\xc7\x78\xf5\x15\xdd\xa1\x3f\xa0\xd5\x86\xc2\x64\xb9\xbb\x61\x50\x33\x10\x76\x2c\x78\x9c\xa1\x16\x08\xd2\xfe\xe6\x74\xc7\x0a\xc4\xfc\x6d\x5e\xbc\xf6\x8c\x4a\xb8\x9b\xd8\x45\x55\xfc\x00\x75\x23\xc2\x8a\x7e\x1d\xd0\x8a\x98\x62\x04\x4d\x52\x45\xb9\x1a\x87\x78\xec\x9e\xe9\x84\xa4\x1a\x9e\x13\xb7\xab\xd6\x57\xae\x2a\x46\xae\x86\x01\x52\xc6\x44\xac\xd9\x53\x67\x67\x8f\xf6\x4c\xc5\x40\x06\xe3\x66\x14\x80\x5e\xd6\x18\xa7\xc6\xd0\xfd\x33\xa9\x08\x52\x30\x90\x84\x1c\x23\x0a\xf0\x98\x46\xd1\x32\xbb\x4c\x6b\x60\xe2\x44\x1f\x9d\x3c\x49\x87\x14\xf4\x70\xf6\xbc\x03\xa8\x0d\x14\xa2\x94\xb5\x65\xd1\xd5\xe7\x81\xcf\xfc\xb1\x30\x4e\xfd\xbb\xc7\xbf\xea\xbd\xed\xc8\x57\xac\xc4\x2e\x27\x62\xbb\xf9\x7a\xf8\x39\xa1\x66\x75\x2d\xa2\x95\x67\x28\x17\xf1\x0d\xbd\x47\x2d\x38\x1f\x53\x16\x55\x55\xac\x82\x22\xa7\x85\x35\xa8\x68\x05\xf1\xbe\xd4\x22\x88\x9f\x20\x61\x09\xaa\x74\x77\x2e\xdc\x0b\xb5\x1e\x8a\x98\x40\xcf\x62\xc9\x2f\xa6\x35\xb9\x0c\xae\x07\x6d\xd5\x0e\x5a\xed\x9d\xea\xc8\x43\xfa\x8a\x6b\x53\x99\x88\x28\x5f\xf1\xad\xab\xe4\xc7\xb8\x3d\x9e\x29\xac\x2d\x94\x09\x2d\xaa\xfe\xc9\xf6\x67\x36\x89\xba\x9e\x92\x52\xd8\x64\xd7\x57\x7a\xa8\x95\x05\xd3\x31\xfe\x78\x09\x86\x12\x77\x00\x2a\x0b\x44\xa9\x6b\xa6\xae\x4a\x52\xb3\x54\x8b\xf2\x68\xe7\x77\x78\x0c\x00\x20\x9b\x24\x5f\x8b\x14\x17\xee\x5e\x70\x1a\x12\x33\x4a\xd5"}, -{{0x4b,0xc7,0xda,0xab,0xc5,0x40,0x7c,0x22,0x6d,0x19,0x20,0xdb,0x4a,0xfd,0x21,0xb2,0xa5,0xb3,0xe5,0x9b,0x8e,0x92,0x46,0x05,0x3f,0x6a,0x1a,0x6a,0xfa,0x54,0xe7,0xe7,},{0xdc,0x53,0x98,0x85,0xfc,0x7b,0xee,0x00,0x2a,0xc5,0xde,0xba,0xe1,0x6b,0xdd,0xbe,0x4b,0x55,0x3f,0xa1,0x5e,0x81,0xee,0x79,0x88,0x76,0x94,0x0f,0x38,0xcf,0xc4,0xc5,},{0xa7,0xa6,0x48,0x88,0x39,0xbb,0xae,0x04,0xde,0xc9,0x2f,0x96,0xd7,0x28,0xc4,0x64,0x68,0x5d,0x7a,0x96,0xdf,0x51,0x2b,0x00,0x51,0x16,0x3d,0x22,0x53,0x8f,0x74,0x54,0x6f,0xa9,0x86,0xb1,0xb6,0x0a,0x6d,0x8c,0xc7,0x66,0xa2,0x6c,0x69,0x84,0xc9,0xcd,0x26,0x88,0x39,0x58,0x98,0xe2,0xb2,0xae,0x72,0xdc,0x6a,0x2d,0x5a,0x9f,0x75,0x0e,},"\x6a\xcc\xe9\x98\x43\xb2\x41\xaf\xe6\xed\xd5\xd0\xab\x78\xd0\xfb\x21\xc8\xc3\x5a\xff\x88\x13\x89\xd5\x05\xf2\xf1\xdd\x91\xaf\x1e\xb2\xad\x22\x92\x54\x92\x7c\x7f\x0e\xcf\xb7\xa8\x14\x16\x90\x57\x3a\x65\x5d\x69\x85\x3d\x74\xd0\x70\x8b\xf8\xb1\xe6\x0a\x03\x96\x30\x28\xa6\x25\xb7\x9f\x3d\xfe\xa2\xb1\x13\xff\xca\xb4\x6f\x3c\xfd\x4a\x62\x1e\x8f\xd8\xff\x0a\x96\x81\x43\xb0\xae\x03\xcc\xb6\xf4\x2e\x25\xe2\xd7\x4d\xbf\x51\x5b\xc3\x58\x69\x9b\x63\x50\x09\xb0\x1d\x61\xfe\x59\x7f\x1d\xc2\xc3\x5a\x7b\xa4\x55\x52\x78\xee\x0e\xa4\x56\xc7\xd3\x5f\xa8\x75\x7a\x41\x79\x24\xb1\xd0\xa8\x35\x1f\x22\x6a\x13\xec\x29\xd0\x25\xb4\x26\x96\xec\x1d\x99\x25\xb7\x69\xcd\x59\xc8\xe2\xf9\xcd\x3c\xe4\xe5\xc0\x20\xe0\x51\xe7\xa3\x6f\x3f\x97\xc1\xe8\xec\x71\x97\x4b\xc1\x6a\xc4\xde\x46\x51\xad\x4d\xf2\xe9\xc0\xee\xd6\x86\x92\x42\x24\xfe\x6d\xe6\xc6\x0d\xd4\xac\xc2\x6e\x0a\xab\xd8\x0c\x21\xd5\x09\xd9\x59\xb8\x0b\x43\x53\x95\x8d\x00\xe4\x4c\x51\x1d\x23\xbc\xf4\x45\x52\x60\x8b\xfa\x56\xa9\xc5\xae\x79\xde\x62\xbb\x23\xf1\x1d\x74\x0f\x48\x24\x0c\x27\xe1\x01\x99\x97\x51\xf2\x53\x47\x42\xc0\xa6\x91\x3f\xf6\x4b\x68\x3a\x18\x99\x5a\xbc\x39\x3f\xeb\x9d\x57\xc7\x1f\x49\xa0\x80\x55\x72\x98\xcc\x40\x5d\x11\xb7\x98\x8d\x71\x16\x84\x0c\x5a\xda\xf5\x3b\xc6\x72\xb4\x69\x23\xcc\x45\x7c\x70\x39\x94\x0a\xd4\xd5\xbf\x07\x3c\x6c\x88\x6b\x13\x39\x52\x59\x26\xd2\x81\xdb\xd1\xa7\x97\x39\xb2\xe3\x64\x14\xcb\xd3\x21\xb1\x85\xfc\x88\xf1\x8d\x2f\x81\xc8\x09\x97\x5b\xe9\xa0\x93\x64\x4c\xc5\x59\xed\x2a\xe5\xcc\x0e\x35\xcb\xdd\x18\x11\xf7\x02\x86\x05\x7a\x3f\x70\x30\x67\xed\xdd\xf5\xeb\x16\x90\xa7\x42\x7b\xb7\x3f\xe3\x02\x4e\xd0\xdb\x82\xa5\xce\x8f\x17\x16\x42\x8a\x76\xfd\x29\x2b\xa9\x9a\x30\x0c\x4b\x2f\x36\x0d\xa2\x12\x46\x17\x59\x0b\x10\xe3\xb1\x62\xa6\xe6\x7d\xd5\xd5\xa5\x9b\xcc\xa1\x0f\x61\x0f\xa0\x64\xaf\xfd\x55\xf8\x48\x3b\x98\xa6\x8d\x07\x6f\x27\x8a\xbf\x88\x8a\x08\xa0\x14\xe0\xea\x49\x91\x80\xfb\xc7\x98\x40\xce\xed\x13\xcc\x6b\x24\x58\xbf\xab\x9b\x0d\xd7\xae\x9d\x86\x46\x1f\xe2\x15\xe7\xc9\xf6\x3f\x76\x8c\xee\x4a\x88\x2d\xf0\xdd\x84\xe3\xeb\x4f\x2d\x7f\x6b\x18\xfa\x57\xd8\xbc\x7d\x9a\xfb\x63\xc2\x1a\xc4\x65\xe7\x90\x3b\x9b\xfb\x86\x38\xa2\x93\x61\xf7\xeb\xfc\x6e\x54\xe5\x46\x5a\x6c\xef\x46\x3a\xe2\x26\x43\xae\x41\x02\x58\x77\x9c\xa7\x4b\x70\x40\x1a\x94\x55\xa4\xd1\x57\xd7\x4a\x70\x29\xef\xe6\xb5\x19\xa8\xc4\xbe\x69\x67\x56\xe0\x45\xae\x40\x81\xb7\x7d\xd6\x03\x1f\x0d\x25\x0f\xa7\x61\xe6\x0f\x85\x9d\x90\x63\xfc\x10\x5a\xa0\xa1\xa7\x45\x0a\xf1\x53\xe7\x05\x47\x77\x77\xc4\x42\x58\x6d\xf4\x07\x40\x2b\xa2\x38\x75\x2f\xae\xf7\x4f\x33\x45\xc2\x6a\x45\x33\xbe\x9a\x61\xf5\xfc\x6b\xde\x48\xe3\xcb\xa7\x5c\x04\xd6\xf7\xb3\x33\xe3\x70\x06\xdd\x0c\x94\xfd\x3b\x6a\x13\x0b\xd6\xfc\xdb\x3c\x6a\xbe\x21\xca\x60\xeb\x43\x1c\xc2\xd8\xa2\xec\xe7\x16\x9d\x2d\xcf\xce\x27\x60\x82\x56\x57\xfd\x4c\x26\xf3\xc3\xb8\x30\xac\xdf\xd5\x08\x01\x1d\x14\x76\x4b\x3b\xe9\x17\x15\x57\x1a\x31\x83\x01\x8e\x0d\x22\x1f\xb9\x53\x2b\xb2\xe1\x71\x1e\x72\x5a\x27\x3a\xe0\xcc\x2f\xac\xcb\xa7\xd5\x50\x49\x29\x45\x9c\x99\x25\x17\xb0\x5c\x1d\xdd\x03\xaa\xcc\xd9\x37\xb8\x6e\xb6\x7b\xc8\x20\x2d\x01\xca\xb3\xd4\x89\x58\x6e\xea\x1a\xcc\xa7\xdc\x20\xcd\x0b\x64\x75\xc2\x58\xff\x67\x36\x61\x49\x6a\x22\xea\x96\xb8\x9d\xb4\xbf\x3f\xca\xae\x3b\xb0\x4f\x67\xdb\x09\x6a\x47\xff\x7e\x1e\xe2\x39\x56\x2d\xc1\x0d\x40\xf0\x53\x94\x4f\x3d\x7b\xcc\x3f\xf4\xc0\xff\x76\x56\x54\xba\x5e\xa6\x4f\x0e\xa6\x3e\x45\xa2\x1d\x9b\x12\x94\x9f\x14\xf7\xea\x70\x74\xe9\xb6\x59\xc5\xc5\xd4\x48\x16\x84\x2d\xe8\x96\x98\xa8\xfc\xca\xce\x43\xeb\x6b\x41\x35\xe0\xb3\x33\xac"}, -{{0xf2,0x6a,0xf2,0x10,0xe3,0xb2,0x01,0x73,0x99,0x0c,0x77,0x45,0x92,0x2c,0xdf,0x94,0x24,0x77,0x3a,0xbb,0x37,0x4d,0x77,0x7a,0x51,0x2c,0xf5,0xb9,0x7b,0x3a,0x00,0x0d,},{0x54,0x58,0x6a,0xbf,0x04,0x11,0x76,0xe0,0x6a,0xec,0x5b,0x60,0x10,0xe1,0x90,0x91,0x6d,0xa5,0x4a,0x8c,0x4b,0xde,0x28,0x8c,0xf2,0x4d,0x8c,0x10,0x7c,0xb3,0xb7,0x30,},{0xce,0x45,0x45,0x30,0xb9,0x22,0xba,0x5e,0xa1,0x62,0xf1,0xa4,0x52,0xe0,0x5c,0x00,0x36,0x3a,0x49,0xa9,0xdb,0x8a,0x56,0x94,0x97,0xc0,0x0c,0xaf,0x1c,0xbe,0xa9,0x91,0x80,0x77,0x05,0x54,0xed,0x4e,0x31,0x40,0xdf,0xca,0x45,0x55,0x15,0x9e,0xbf,0x48,0xef,0x5d,0x2a,0x50,0xf3,0x94,0xae,0xbd,0x78,0x21,0x16,0xed,0x65,0x69,0xa4,0x09,},"\x88\xe2\x6d\xa3\x5c\x54\x88\x4b\x47\x14\x6f\x4e\x3f\x01\x4a\xb6\x5b\x3d\x71\xaa\x7e\x3c\x33\x91\xad\xbe\xb1\x9e\xf2\xe7\xb9\x30\x2e\x28\x19\x91\xb2\x61\xb6\xa0\x99\x2e\x2e\x89\xa4\x9f\x48\x0c\xa2\xd8\xe6\x84\xb1\x2f\x9b\x15\x09\xb3\x8f\x6a\x7a\x98\xa5\xdd\xb4\xc2\xd8\x69\xfd\x03\x18\xe9\x8e\xcd\x8f\xd9\xdf\x49\x1b\xaf\x99\xa9\x29\x4d\xe4\x9e\x1c\xf8\xdd\x41\xee\x85\x73\x0a\xf0\x25\xa7\x01\x14\x3e\x4f\x0c\x8e\x3d\x92\xd5\x5b\x59\xca\x7d\x4a\x6c\x89\xad\x76\x0d\xff\xc0\xc2\x18\x92\x09\x50\x8e\xf6\xc2\x21\x4e\xdf\x99\x67\xb1\x7d\xef\x12\x3d\x86\x92\xc9\xe4\xe2\x0b\x1e\x98\x26\x88\x08\x70\x4f\x5f\x9f\xe1\xa6\xd6\x05\x5e\x32\xc8\x72\x56\x4b\xd1\x7e\xdb\x73\x59\x57\x86\x29\x01\x7f\x0c\x30\xfe\xab\x8b\x50\x4e\x22\x89\x23\xad\xc7\xe8\x1a\xe2\x0a\x85\x2d\xb0\xad\x67\x6a\x78\xe0\x81\x33\x6d\x6b\x04\x02\xf9\xcd\xc5\xd5\xe9\x01\x28\xca\x94\x5d\x10\x51\x5c\xa0\xc5\xef\x03\xf7\x31\xb1\xd4\x0a\x71\x07\x41\xd4\x1c\x1d\xd1\xca\x16\xb1\x06\x0f\xeb\xf2\xa0\x53\x2e\x6f\x5d\x76\x51\xef\x44\x63\x75\xec\x18\x09\x0c\xb8\x41\x8b\x82\x02\xf2\x5a\x03\x89\x03\x1b\x30\x7f\x22\x3c\x5b\x5f\x6a\xfe\x36\xa9\xad\xc1\x06\x8f\x2c\x6e\x0e\xa5\xb2\xb6\xcf\xeb\x8d\xc0\x04\xf7\xb8\x29\xc8\x04\x39\x06\x9b\x81\xa7\xbd\x90\x74\x77\xc6\x13\x5e\xf2\x82\xb7\x71\xf1\x41\xdb\xe7\x5a\x0f\xa0\x56\xe0\x6b\x8a\x1a\x1f\x98\xc2\x5f\xa5\x4d\x14\xc8\xfd\xb4\x2d\x65\x02\x59\x5c\x59\xd2\x5b\xac\xf1\xa1\x9a\xde\xfc\xc1\x31\x70\xf7\xa4\x31\x7b\x6a\xb6\x10\xb6\x09\xd4\x14\xb0\x07\x3e\xa0\x4a\xc2\x9e\xb1\x0e\xe7\x3c\xd7\x1a\x4c\xa6\x04\x09\xf8\xe7\x60\xe6\x0f\x93\x95\x10\x10\x0d\x0c\x8c\xd7\x6f\x26\x4b\xb3\x78\x11\xf9\x7a\xa5\x29\x9a\xc0\xb1\x2d\x41\x68\xff\x38\xec\xdf\xa8\x0b\x1e\x5c\x1b\x3b\xbd\x4d\x40\xd3\x54\x47\x35\xdf\x71\x67\xeb\x15\x8a\x9a\x9a\x23\x4d\x44\x5f\x1d\x66\x3d\xed\x71\x71\xed\xc6\x8d\x17\x2c\x92\x21\x4b\x82\xef\x13\xfe\x6b\x8c\x43\xaa\x89\xb7\x39\xb4\x99\x0a\xe9\x47\xa3\x4f\x02\x0a\x8d\x89\x43\xb0\xf7\xa5\xd6\x1d\xfa\x76\xad\xde\x02\x72\xe9\x8c\x11\x59\xc0\xfd\x8a\x1d\xe3\x3f\x2c\xef\x8e\xdd\x32\x85\x7b\x21\x89\xed\x96\x12\x80\x57\xeb\xde\xa8\x1f\x7a\x3a\x3d\xff\xe1\x89\x3b\x5b\xa8\x77\x55\x6c\x90\x38\x3f\xa2\xc5\xa6\xfd\x68\x0e\x8a\x67\xde\xe4\x80\x2d\x90\xdf\xe9\x71\x62\x3a\x7b\xe2\x2a\xb3\xca\x56\x06\x7b\x1e\x5c\x69\x4a\xa8\x4c\x19\xf1\x6d\x69\xe2\x84\xdd\xfa\x03\x9c\x10\x8d\x04\x35\x81\x38\x12\x39\x0d\x8e\xbc\x1e\x50\x13\x81\x76\xf2\x59\xdc\x0f\x26\xbc\xa1\x3b\xc9\x43\xf5\x0d\x5a\x35\x00\xb1\x8d\x59\x35\x74\xc6\x20\xfc\x09\x7a\xce\x43\x0f\xb8\x07\x28\xd3\xa1\xaa\x64\x4e\x50\x4b\x10\x09\xad\x67\x53\x6c\xeb\x01\x1f\x2a\x35\x7d\xbd\x00\x9e\x4a\x63\xf5\x24\xd5\xb5\x95\x7f\x33\x15\x67\xc5\xb4\xd1\x85\xa6\x1d\xf2\x2d\x70\x71\xd3\x1a\xe9\x21\x41\xe1\x99\xc1\x22\x89\x51\x5a\xed\x80\xc9\x10\x21\x45\x6b\xcd\x45\xcc\xc6\x34\x03\x7d\xcf\x69\xb4\x1d\x6b\x1f\xf5\x34\x71\x01\x0d\x99\xf1\x87\xf0\x46\x54\xf4\x36\x22\x28\x78\x71\xfe\xe6\xdc\xf5\xf3\x02\x3c\xbd\x09\x13\xd9\x9a\xff\x43\xfa\x95\xb3\x2e\xa2\xb1\x33\xb4\xc9\xac\x4b\x01\x7b\x7c\xf8\xf9\xbe\x50\x86\xfe\x92\xb4\x2c\xb8\xdb\xed\x5b\x63\x0b\xf0\x97\xc1\x8e\x2e\x55\xc3\xdd\x93\x27\x1e\x09\xc2\xd1\xcc\x6a\xf8\x7d\x83\xfd\xef\x3c\x3e\x3c\x4c\xba\xfb\xea\x9b\x60\xfd\x5e\x9c\xf0\x01\x1d\xe2\xe9\xe2\x6f\xbf\x09\xaf\xee\xf5\xc6\x98\x02\xa6\xc4\x6b\xdf\x54\xc1\x45\x86\x29\x44\x17\x3e\x01\x7e\x30\x14\x9e\xa5\xc0\x3c\x7a\xef\xa2\x8a\x9c\xac\x77\x67\x00\x2e\xa3\xfe\xfb\xde\xae\x5b\xae\x00\x5c\x37\x0d\xbc\x06\x42\x44\xd5\xb9\xbe\x55\x00\xa3\x57\x26\xa9\x9b\xc9\xe8\xc2\x75\x2d\x51\x0e\x13\x9a\xf2\x25\x58\x00\x98\xc8\x18\x9a\xa9\xc5\x20"}, -{{0x39,0xbf,0xfe,0x00,0x7f,0x8d,0xf7,0xce,0x4e,0x56,0xfd,0x17,0x6b,0x10,0x2b,0x92,0x3b,0xa4,0x8a,0xeb,0x82,0x69,0xfd,0x0c,0xd5,0x20,0xc2,0x3a,0x7b,0x23,0x6e,0x6c,},{0x95,0x32,0x63,0x68,0x00,0x01,0x0b,0x3d,0xd4,0x01,0x2e,0x34,0x1f,0xca,0xd6,0xd2,0x9a,0xfa,0xd4,0x84,0xe6,0xfd,0x73,0x6e,0x89,0xd5,0xbc,0x02,0xba,0x0a,0xc8,0x53,},{0xa2,0x7c,0xca,0x4b,0x9f,0x5b,0x95,0xad,0x0e,0x44,0xe4,0x74,0x0c,0x15,0xde,0xae,0xb9,0x3f,0x22,0xa9,0xb2,0x54,0xeb,0xbd,0x23,0x29,0x36,0x5a,0x00,0x96,0x6c,0x9f,0x4e,0xc1,0xe5,0x5c,0x58,0x94,0xe7,0xbf,0xc2,0x3d,0x39,0x8d,0x39,0x70,0xb9,0x46,0x5e,0x98,0xa8,0xd2,0x3e,0x72,0xda,0xe8,0xe3,0x50,0xda,0x35,0x31,0xae,0x69,0x08,},"\x7a\x8c\x20\xbf\x2e\xff\x69\xaf\x8b\xad\x6b\xdf\xab\xc7\x90\x9c\x58\xce\x74\x6c\xc4\xdf\x78\xb6\x9b\x33\xc1\x05\xba\x3b\xd8\xda\x75\x24\x47\x58\xb5\x17\x2d\x5c\x45\x01\xbc\x39\x97\x01\x85\xee\x3d\x43\x70\x83\xa9\x95\x9f\x81\xe7\x66\x5b\x82\x9a\x69\xa5\xd7\x2e\x03\x4d\x35\x1a\xdd\xdc\xeb\x3d\x3f\xff\x58\x99\x88\xdf\x18\x2b\x46\xfa\x53\xd2\x6e\x7c\x9e\xac\x06\x22\x15\x78\x8f\x23\x37\xbf\x90\xf0\x17\x7d\x8c\xa7\x44\xf9\x5f\x28\xfe\xa8\x54\x59\x3c\x43\x62\xc8\x2e\x9d\xed\x19\xb9\x04\xff\x99\xd2\xbe\xa8\x24\x32\x82\x2e\x52\xc3\xda\x6d\x46\x2d\xa7\x54\xff\x1f\x8b\xd1\x09\x94\x2d\xf5\x1d\xba\x25\xb7\xcd\xe8\x38\xd5\xf5\x24\x23\x9f\x13\x31\xf4\x63\x19\x4e\x10\xff\x56\x79\x5b\x29\x68\x78\xfe\xb1\xf5\x5d\x43\xec\x7d\xaf\x0c\xa5\xab\x3d\x68\x4b\x55\xbb\x0a\xa4\xc7\x20\xd4\xb5\xc2\xe8\x30\xc8\x58\x69\x4d\x3d\x0f\xdb\xaa\xd0\xbf\x67\xd8\x73\x18\x2d\x95\xb2\x41\x2f\xce\x5e\x7b\x00\xfa\x6b\xfc\x38\xb1\x32\xef\xb9\x6f\x87\xbc\x6c\x10\x07\x0a\x57\x16\xec\x9b\x33\xa2\x69\x2c\xdf\x5b\xc4\x1c\x7f\x73\x7e\x28\xc4\x22\x03\x17\xa4\x89\xb7\x32\x3d\x5e\x20\xf6\x5d\x37\x5d\x76\x9f\x9e\x79\x37\x6f\xd0\x2d\x85\x36\x86\x71\xe7\xe0\x81\xeb\x75\x3f\x88\x85\x45\xeb\xe5\xc0\x00\xb2\xf8\x01\x43\xeb\x35\x8d\x43\x18\x5e\x2f\x1c\x29\x4b\x9f\x29\xc8\xbb\x91\x48\x2d\x43\x87\x49\x4a\xad\x17\x6d\xeb\x85\x54\x0f\xd0\x05\xc9\x7d\x13\xe6\x66\x3f\x09\x94\x4e\xb4\x3a\x46\xe6\x23\x67\x94\xbf\x6e\x21\xf8\x1d\x0a\x42\x09\x0f\x9c\xce\xf9\x0a\x6c\x48\x07\xb5\xff\x54\x13\x00\xe5\x93\x48\x81\xa8\xd9\x21\x96\xb4\xce\xe8\x5d\x28\x09\x2a\x82\x8e\xa3\xbf\xc6\xb7\x45\xad\x21\x9b\xe9\xf5\xe9\x57\x41\x17\xd0\x79\xe0\x2f\x4b\x74\x8e\x2c\xc0\x1a\x32\x82\x6a\x37\x08\x23\x19\x14\xd2\x77\x2c\x76\x41\x19\xfd\x99\xd5\x3a\xb5\xb5\xa2\xe9\xd8\x91\xa4\x8a\x9a\xaa\xac\xc2\x63\x38\xb1\x82\x48\xdb\x8a\xb2\xd5\x25\xda\xf1\x5f\xf5\x3a\xcb\xc3\xaa\x98\xd4\xf2\xd4\xa3\x37\xbb\xaf\x6d\x1b\xe2\x19\x85\xa4\xaf\x60\x0e\x29\xbb\xb4\x2c\x8d\x89\xe6\xb3\x89\xc6\x6f\x42\x27\x0c\x3a\x0b\x05\x1b\xdb\x62\x38\x81\xe0\x2f\x2f\x42\x94\xce\xc3\x47\x63\x86\x74\x7a\xba\xe6\xc7\x70\x0b\x8f\x9b\x03\x87\xcd\xdf\xb7\x36\x68\xfb\x57\x69\x3d\x84\x74\x19\x6b\x33\xab\xd1\x2d\xce\x59\xa5\x7c\xf7\x2e\xe6\xcc\x1d\xdb\xaa\xdf\xb1\x9e\x90\xaf\x81\x31\xb3\xa9\x0f\x98\x67\xf4\xc7\xe1\x5b\xdf\x9e\x21\x84\x77\x01\x6b\xd0\xad\x3b\xe8\xdd\x05\x96\x71\xff\x65\x6c\xbd\x4e\xd8\x98\x08\x6d\xe4\xd4\x23\xf3\xdf\xb2\x70\xbb\xf1\x9d\x9f\x53\xf7\xf6\xf2\xd2\x2c\x6a\xc9\x02\x5c\xba\xdb\xa4\x42\xe3\x1d\x98\x11\xe3\x7e\x84\x7d\xbd\x48\x4d\x80\xcf\x74\x30\x39\xff\xa7\x04\x84\x70\xfb\xdc\x60\x80\xf6\xd3\x81\xdc\x7e\x3f\xa2\x71\x22\xdf\x53\xcc\x06\x39\x4e\xa6\xfc\x44\x6e\x1b\xa7\x25\x38\x73\x3e\xd3\xab\xb6\x85\xf1\x6d\xfd\x5c\xcf\x58\x5a\xe8\xfb\xf9\x95\x4b\x50\xf1\x0b\x7e\x54\x32\xa2\x2b\x36\x94\x06\xa9\xb7\x08\x89\x61\xf0\xae\x20\x74\x95\xae\x71\x85\x39\x6d\xcc\xf2\x92\xdc\x46\x3f\x41\xf3\x76\xa1\xca\x89\xee\xfb\xae\x19\x26\x91\x52\x03\x1b\xfd\x81\x52\x88\xe8\xb5\xba\xf3\x48\xc4\xf8\xff\x3d\xff\x4f\xd6\xd1\x08\xf8\x71\xda\xa3\x52\x11\x0f\xa6\x41\x88\xb0\x1b\x85\x26\xa8\x45\xaa\xed\x13\x3e\x45\x6b\x4c\x83\xc4\xfd\x4b\xbb\x16\x5b\x40\x90\x30\x7e\x8e\xb1\x7d\xf1\x76\xc3\x22\x52\x0f\x37\x59\x9c\x21\x05\xaa\x81\x20\x75\x83\x94\xa4\x22\x24\x73\x47\x67\x64\xcf\x0a\xf7\xc5\x51\x83\xeb\xa9\x68\x3d\x72\x70\x63\x14\x43\xf3\xc5\x1f\xb8\xab\x0c\x13\x0a\xc4\x36\xab\x60\x3f\xf4\xf1\xd8\x65\x6c\xdb\xed\x22\x9a\x20\x2b\x40\x00\x8e\xa1\x0b\x17\x15\x42\xf7\x4a\x70\xb7\xbb\xac\xc4\x01\x6b\x7f\x63\x6a\xa8\x96\x33\xb7\x66\x80\x58\xf1\x33\x12\xf5\x7c\x51\x62\xd1\x8e\x39\x9e"}, -{{0x3c,0x40,0x80,0xcd,0xa0,0xfc,0x3c,0x03,0xb6,0x14,0xd9,0x80,0xf2,0xff,0x83,0x1f,0x5b,0xe0,0xe7,0xa9,0x81,0xd5,0x38,0x1a,0x16,0x18,0xe0,0xb8,0xfd,0x00,0x17,0x76,},{0xf1,0xc3,0x26,0x9d,0x87,0x04,0x02,0xca,0xa4,0x38,0x82,0x13,0x5d,0x9d,0xba,0xdb,0xbb,0x16,0x2d,0xfc,0xa0,0xb3,0xda,0xd1,0x97,0xe6,0xb8,0xa7,0xee,0x67,0x9a,0x70,},{0xc9,0xd4,0xa4,0x72,0x8b,0x8f,0xdd,0x24,0x0d,0x9c,0x49,0x8a,0xa3,0x5d,0xe9,0x5a,0x4b,0xbd,0x51,0x78,0x5b,0x73,0xc8,0x40,0x3f,0xdf,0x04,0x0d,0xfa,0xed,0x94,0x47,0xef,0xad,0x00,0x69,0xb6,0x7c,0x78,0x3d,0x4b,0x81,0xd9,0x66,0xbe,0xf6,0xe3,0xd9,0xa8,0x08,0xa0,0x58,0x4b,0x98,0xec,0x2b,0x18,0x32,0x2c,0x4c,0x92,0x0e,0xb0,0x0a,},"\x0c\xee\xbc\x0e\x8a\x47\x72\x0f\x25\x83\x5e\x2b\x9a\xcf\x89\x1b\xcc\xa4\xbd\xa3\x86\x37\xf3\x63\x27\x44\x58\xba\xa9\xe2\xbb\xaf\xed\xd0\x93\x8f\x56\x88\x73\x4e\x22\xac\x50\xfb\x12\x0f\x66\x5f\x6c\x4c\x61\xc6\x53\x17\x39\xb9\x29\xac\x83\xcd\x77\xf8\x96\x3b\x75\x44\x88\xb9\xb8\x59\xc1\x38\x53\x63\x7c\xf0\x25\xc1\x4e\x8f\xdd\x11\x8f\xaa\x14\xcf\x39\x30\xce\xb3\x5f\x10\x4d\x95\x44\x1e\x56\x48\x94\x40\xf6\x20\x41\xef\x1a\xa7\xc4\xb0\x8b\x28\x07\xe3\x2b\xb9\x58\x4b\x90\x04\xd7\x6e\x76\x53\x33\x48\x50\x6d\x64\xf1\x12\xe1\xff\x6f\x93\x8f\x64\x22\x30\xbf\x38\xaf\x01\x0e\x41\x98\x72\x70\x24\x8b\x13\x63\x5a\x35\x67\xb3\x55\xbb\xa5\xb5\x74\x48\xc6\xd1\x3b\x74\xf3\xbe\xbf\x61\x79\x15\x82\x10\x28\xfc\xa5\xde\xfa\x4c\xe5\x42\x4c\xa1\x91\xcd\x54\xa2\x29\x44\xa3\xd9\x40\xe4\xee\x2e\x2b\xa5\xd5\x04\xc8\x5f\x95\x9b\x51\x4c\x4f\xab\x41\xcc\xb5\x74\x3d\x9c\xb2\xf9\xbf\x33\xd1\xd8\xc2\xa5\x86\x9e\x9f\x46\x60\xc3\xfb\x22\x4b\x39\x14\x1e\x31\x10\xc9\xee\x8a\xeb\x87\x1e\x14\xc6\x2c\x6b\xe3\x8f\xb9\xa4\x56\x8d\x73\x68\x10\xbb\x9d\x20\x73\x17\x8b\x6c\x7e\x87\xe3\x58\x2e\xfc\x62\xb5\x3c\x23\xc5\xd4\x65\x20\xba\x33\xff\xb3\xa9\xca\x64\x9e\xf2\x6f\xe7\x4a\x3c\xff\x61\x88\x42\x73\x26\xb8\xc9\x6f\x74\x35\x4c\xb3\xec\xaa\x61\x1b\x12\xcd\xed\x56\x5e\x59\xfe\x1f\x8f\x40\x00\x97\xe9\x3e\xa8\x59\x51\xb5\xb4\xe9\x00\x9e\xea\x7d\xb9\x37\xe4\x34\x9c\x4e\x5e\x00\xc4\x45\x6c\x6c\x5f\x4e\x57\x41\x1b\xaf\x4e\x46\xe7\x00\xac\x40\x02\x57\x76\x5f\x48\xda\xb0\x3e\x43\x9f\x76\xc1\x49\x9b\x51\x08\x04\x7c\x83\x01\x09\xdc\xe7\xf7\x40\xd1\x39\x37\x87\xe2\x9d\x37\x16\xd3\xc4\x7e\x75\x5c\xb8\x28\xe7\xd4\x40\xa9\x71\x97\x51\x97\xeb\xdb\x3f\x9b\x73\x7b\xa1\x1f\x7f\xd0\x38\x6a\x95\x92\x49\x01\x7d\xe7\x23\x4d\x5e\x5a\x9b\x47\x3b\xb9\x58\x3a\x37\x42\xc7\x74\xee\x55\x2a\x12\xa1\xf3\x6e\xb3\xf2\x6c\x88\x5b\xed\x22\xe9\x1c\x74\xcf\x32\xa8\xdd\x3e\xdb\x08\xb6\x74\xbf\x38\x6e\xf4\x27\x72\x79\x12\xd5\x7c\x5f\xaf\xaa\x1c\xfe\xb7\x40\xcd\x52\xb9\xde\xe9\x95\xe3\xd0\x16\x1c\xd9\x21\x3f\x38\xfd\x68\x1d\x53\x8a\xb8\xbf\x97\xb7\x45\xf5\x49\x80\x03\x0e\xf8\xb7\x26\x96\xd4\xe2\x74\x73\xfb\x0f\x1a\xcd\x5d\x0a\xae\x02\x97\x21\x16\x80\xea\x0f\xc5\x9d\x7b\x6d\x51\xc6\x32\x92\x58\x5a\x1d\x55\x3d\x0c\x89\x54\xb4\x2a\x4b\xd6\xfc\xd3\xa4\x95\x75\xbf\x5c\x88\x95\x3f\x1f\x4e\xa7\xfe\x0e\xd7\xa5\x79\xd1\x69\x7e\x64\x5e\x2a\x61\xc6\x9d\x1a\x56\xbc\x60\x5b\xb0\x40\x60\xa2\x77\x8d\x50\x9a\x8a\xad\xbf\x35\xd9\x46\x97\xcc\xee\x9d\x35\x43\xdd\x01\x28\x1a\x03\x1f\x2a\x0e\xb3\xa9\xeb\x13\xae\x56\xff\x44\xfa\x0a\xed\x4f\x34\x88\x74\x7d\x6a\xf8\x20\xf3\x98\x9b\x71\x33\xf4\x49\xea\x56\xd3\xa7\xf7\x31\xe7\x91\xb7\xed\x2a\x5d\xb9\x39\xbb\x75\x35\x2d\xe7\xda\xec\x50\x66\xfd\x57\x55\x71\x65\xad\xff\xa6\x31\xcd\x3f\x96\x7c\x3c\x7c\xfc\x11\xcc\x1f\x14\xfa\x23\xde\xfe\xc3\xeb\x02\x39\xb4\x5e\xd6\x01\xa3\xa8\x07\x8c\xcf\xc7\xf8\x38\x09\x02\xa8\x59\xee\x9c\xe2\xdb\x79\x5e\xfa\xca\x0a\x01\xdc\x08\x79\xd5\x06\xac\x97\xd1\x07\x04\xd7\x75\x7b\x3c\xcf\x3b\x37\xc3\x39\xb4\x2d\xb2\x37\x82\x27\x80\x23\xe4\xc2\xe7\x7d\x74\x24\x6c\x9e\x54\x41\x49\xa5\x5c\x0c\x92\x0e\xbf\x29\x86\xb4\xc5\xb4\xb3\x57\x2f\x74\x8c\x4b\x15\xc7\xf8\x63\x99\x9b\xc5\x13\x2a\xda\xd0\x97\x61\xeb\x76\x50\x50\x19\x76\x9f\xb5\x54\x22\xf6\x03\x18\x4e\x24\xc0\xd4\xf3\x76\x19\x87\xb5\xc5\x0f\xea\xfc\xce\x53\x30\x2a\x3a\x41\x5e\x20\xf5\x6a\x05\x48\x03\xe5\x53\xba\xcd\x24\x2a\x5e\x13\x64\xaa\x3b\x2d\x7c\xb3\xbc\x1e\x1b\x86\xa4\x74\x31\xcb\xd3\x96\x95\xb6\x7f\x55\x4c\x46\x45\xb7\x23\x69\x04\x09\x4c\x11\xaa\x1b\x40\x32\x6b\xa9\x1b\x8b\xf4\x87\x3e\x9a\x4d\xe0\x4e\x2b\xf4\x62\x59\x72"}, -{{0x45,0x43,0x8f,0x91,0x46,0x5d,0x74,0xa2,0x82,0x5b,0x0f,0x66,0xa3,0x5b,0xd7,0xc8,0xd0,0x05,0x86,0x54,0x79,0xb3,0xdc,0x10,0xa9,0xb5,0x6f,0x29,0x7d,0x31,0xb9,0x26,},{0xf0,0x92,0xb5,0x88,0x03,0x30,0x87,0x1e,0x5a,0xaf,0xdd,0x3c,0xeb,0x38,0x50,0xee,0x7e,0x09,0x41,0xa2,0xa1,0xdc,0x89,0xf4,0xfb,0x47,0x71,0xd7,0x5a,0x22,0xf6,0xf2,},{0xd9,0x28,0x7b,0x7f,0xec,0x01,0x7f,0x2e,0xa4,0x0a,0x14,0xa1,0xf6,0x2d,0xca,0x78,0xb0,0x2a,0x3d,0x66,0x32,0xdf,0x7c,0x60,0xeb,0xd9,0x0f,0xc5,0xe4,0x92,0xc5,0xc6,0x2c,0x43,0x16,0x6b,0xf8,0x56,0x58,0xfb,0x30,0xa0,0x8b,0x57,0xa5,0x81,0x31,0x21,0xb8,0x03,0x97,0x57,0x1a,0x31,0x2b,0x6d,0xd1,0x1b,0x65,0x39,0x20,0x54,0x16,0x02,},"\x30\x71\xd4\xb7\x20\xdf\x10\x93\x65\x99\x67\xcd\x4e\xef\xef\x2e\xf9\x67\x84\x75\xf7\xde\xc5\x8f\xec\xec\x1d\x92\x8d\xea\xf8\x02\x45\x7a\x19\x34\xe6\x04\x55\xf4\x96\xcf\x42\x51\x82\x0e\xd6\x0a\x3d\x81\x33\xb6\x24\xd3\x3a\xf2\x6a\x26\x27\x84\xb5\xa2\xfb\xa7\x3c\xca\x2a\xa5\xe5\x19\xe1\xf5\x39\x58\x47\x80\x64\x98\x64\xba\x5f\xbc\x1f\x01\x1d\xdd\xac\x38\x1f\x8d\x48\xd0\xd6\x0c\xe8\x23\x17\x01\x17\x3c\x9d\x2a\x30\x7a\x76\x30\x2e\xbc\x69\xdc\xbc\x93\x0d\x28\x43\x14\x75\xb5\x16\xf9\x8f\x77\x8e\xd2\xe1\xff\xf2\x72\x90\x9a\x27\x2c\xc3\xfb\xb6\xb3\x1c\x80\x41\xa3\x7c\xb7\x77\xe0\x62\xe4\x96\x49\xaf\xad\x12\xc1\xb5\xf7\xfc\xb8\x06\x5a\x99\xe7\x42\x33\x62\xad\x16\x90\x60\x31\x26\x5d\xb7\xe8\xb8\x97\x51\xf8\xa4\xa4\x07\xf2\x50\x26\x50\xfe\xd7\x53\xe4\x2c\x8c\x91\x1e\x50\xb9\x4b\x38\x00\x69\x5b\x0e\xba\x7d\xff\x06\xb7\xa7\x10\x11\x7e\x49\x20\xd4\xb1\xc6\x05\xa3\xeb\xf3\x2e\x06\x96\x67\x16\xed\xa1\x4b\x30\x42\x99\x8a\x3c\x7a\x5e\x9f\x83\x54\x2d\x7d\xde\x65\xe5\x28\xbe\xd6\x10\x1d\xeb\x33\x1d\xeb\x94\xcd\xd4\x60\x44\xbe\xf8\x8c\x09\x7b\xaf\xd4\x0d\x69\x21\xa7\xc4\x84\xc8\xf9\x66\x84\xdc\x37\x16\x71\xd9\x4e\xee\x7c\xbe\x5d\x58\x77\x15\x31\x4c\xff\x0d\x18\x77\x27\x2d\x81\x90\xa9\x0e\x18\xbf\xb3\x21\xd5\x2b\xf7\x47\x05\x13\x7b\x2a\xbf\x91\x65\x73\x17\x67\xa1\x3a\xdc\x9c\x85\xe0\x39\x7b\x47\xae\xf9\x6b\xad\xb2\xca\x7f\xcb\x82\x93\xb0\x1f\xd1\xde\x31\x6e\xe1\xe6\x5f\x35\x6b\x9d\x6e\x8e\xa1\xfd\xd8\x37\xbd\x96\x08\x11\x49\xea\x2d\xcd\x73\xc4\x88\x1f\x32\xb7\xde\xeb\xc3\x71\x5e\x2d\x7c\xdb\x64\x3e\x0d\x98\xf4\xe8\x46\x50\x8b\x04\xb3\x24\x39\xff\x14\xb1\x16\x4f\x46\x84\x6d\xf9\xaf\xae\x44\x46\x4c\xf5\x50\x10\x4c\xd3\xaa\xb3\x81\x75\x40\x47\x0a\xaa\x2a\xb9\x55\x9a\x68\xb7\xff\x6b\x1b\x9c\x0c\xe9\xf5\x86\x9c\xbd\xcd\xd6\x17\x09\x09\x42\xe3\x53\xb4\xc7\x7f\x09\x39\x58\x96\xbe\xcd\xdf\xf1\xab\x7f\x07\x58\x6a\x51\x4d\x81\xfb\x09\x63\x61\x55\x75\x66\x87\x0f\x16\x91\x98\x34\x85\xa8\x0c\x34\x13\xda\x98\xb8\xd1\x9c\x78\xe6\x37\x9f\x94\x3e\x5b\xd5\xa5\x69\x7a\xa3\x3c\x5e\x6b\xfc\xfb\x7b\x8d\xf1\xe1\x57\x4e\xe4\x16\xfa\xb3\xc8\xa7\xd0\x88\xb3\xa0\x57\xcf\x86\x53\x21\xb7\x4e\x61\x03\x52\x6d\xd9\xad\x15\xca\x5a\xd3\xc0\xf6\x97\x18\xe2\x70\x81\xd4\xb3\x4a\x7c\x6d\x1a\xab\x6b\x96\xc0\xa7\x54\xb9\x89\xb4\x94\x06\x38\xc9\xed\xe3\xd1\x7b\xd4\x9f\x65\xbf\x78\x3d\xc8\x5f\x1c\x4b\x14\x48\x76\xcd\xbd\xb2\x28\x2a\x95\x64\xaa\x81\xb5\x70\x92\x08\x0d\x64\x48\xfb\x65\x80\xec\xf0\x9f\x82\xa7\x55\x01\x0d\x55\xd4\xa5\xe4\xf3\x05\xe2\x59\xdb\xe9\x95\x08\xb4\x79\x25\x0d\x80\xec\x17\xc8\x76\x0a\x93\xe0\x5a\x29\x57\x1f\x68\x56\x07\x30\x22\xc8\x70\x69\x13\xc4\x6a\x2e\xfd\x2e\x9c\xaa\xe4\xff\xa1\xb4\x22\x2e\x3d\x70\xe9\x79\xe8\x1a\x71\x95\x1d\x7c\xb8\x30\xbc\xbc\xf9\x01\xaf\x24\x4f\x64\xe4\xad\x9f\x52\xfa\x3b\x62\x03\x1e\x35\x16\xda\x50\xbc\x2b\xce\x78\xeb\x9d\x61\xbf\xed\xd9\xb3\xf5\x7e\x89\x35\x5f\x17\x7d\xb6\x16\x2b\xf6\x1d\xa0\xe4\x54\xc3\x42\x88\xb9\x67\xc3\xfb\x4c\x34\x1b\x32\xd4\xd1\x3a\x31\x98\x69\xb8\xe3\x60\x46\xf9\xe3\x38\xb5\xf3\x6a\x1f\xc1\xa7\xed\xa7\xd7\xb0\xd4\x38\xe0\xa7\x5d\x84\xbb\xe4\xd6\x8c\x87\x9a\xda\x80\xdd\xe2\x3f\x71\x55\xb5\x32\xcc\xcf\x7a\x63\xf1\xbe\xdf\x84\xf8\x2f\x44\x0c\x9e\xc3\xcb\x0e\x45\xf3\x2c\x92\xf7\x64\x38\xf5\xb4\xb9\x10\x44\x1e\x67\x38\xaf\x3f\x5d\x20\x50\xd5\x79\xee\x96\xb8\x8f\x3b\x00\x81\x0a\xb1\x26\xff\x3a\x8f\xef\xd9\x71\x04\x43\x24\xdd\x4e\xb3\x44\x7d\xac\x5b\x77\x80\x9c\xda\x8c\x71\x68\x25\x49\xd7\xcf\x2d\xce\xe3\x40\xed\xcf\x94\x94\xac\xa4\x29\x01\xe2\xc1\x1e\xd9\x77\x90\xaf\x48\xbc\xea\x29\x52\x1e\xf0\xe3\xd0\x3c\xda\xde\xcd\xc8\x94\xdd\x07\x56"}, -{{0x72,0xcf,0xce,0xf4,0xc9,0xd6,0xa1,0x98,0x6d,0x19,0x03,0x11,0x84,0x0e,0x55,0xcb,0xaf,0xac,0xc8,0xa6,0xeb,0x5e,0xcc,0x72,0x93,0x4f,0xda,0x53,0x5b,0xdc,0xff,0xb2,},{0xa9,0x44,0x64,0xd8,0xcc,0x8f,0x3e,0x43,0x39,0x39,0x47,0x64,0x9f,0x91,0xc2,0x75,0x23,0x27,0xe4,0x0d,0xac,0xa1,0x1a,0x99,0x70,0xc5,0x18,0x1e,0xda,0x37,0xd6,0x06,},{0xdb,0x72,0x70,0xac,0xce,0x78,0xd7,0xfb,0x09,0x08,0x0a,0x32,0x79,0x41,0xbc,0xe7,0xeb,0x14,0x5b,0x9e,0x36,0x61,0x86,0x6a,0x86,0x83,0xf9,0xa1,0xa3,0xde,0x97,0xfb,0x02,0xb0,0x25,0xdb,0x9e,0xc7,0x6f,0xf3,0x25,0x60,0xfe,0x63,0x88,0x27,0x74,0x2e,0xa2,0xf4,0xeb,0xef,0x6b,0x7c,0xce,0x44,0xf9,0xaa,0xee,0x43,0x4f,0xd7,0xc1,0x08,},"\x66\xa6\xcb\xe8\x8a\x8a\xb9\xa3\x38\x47\x79\x7f\xc4\x80\xb2\x44\xe8\xa2\xb8\xec\x79\xe8\x0b\xc2\x63\x77\x53\xde\xb3\x6f\xa3\x01\x4f\x84\x3e\x22\xa4\x7d\xb0\xa3\x17\x78\x38\x5e\xc1\xf4\x55\x67\x2e\x0d\xff\x6c\xa2\x1c\xa4\xcf\xd2\xb9\x89\x47\x1b\x7f\xfc\x30\x78\x28\x13\x8b\x0a\xd4\xe6\x47\xc2\xd1\x3c\xef\x72\x44\x69\x05\x4a\xbd\x37\x40\x24\x5a\xea\x4b\x78\x9e\x24\x4e\x95\xcf\x9e\xcf\xd0\x8a\x0d\x13\xc7\xce\xd3\x93\x33\x27\x27\xa7\xf3\xd8\xfb\xda\xbd\x93\x9d\xe2\x8c\xaa\x41\xcc\x96\xc7\x08\x11\x98\xe2\x26\x53\xd9\x4e\x02\x4a\x61\xf5\xf3\xdc\x5a\xa3\x7f\xa9\xad\xdd\xc9\x6c\xf1\x69\xd3\x50\x62\xa0\xa2\x9b\xa4\x5a\x53\x9c\x87\xa6\x8a\x3a\x03\x04\x36\x13\x09\xd2\x13\xe6\x14\xee\x83\x73\xda\xfb\xa2\xa7\xd6\xed\x7d\x2a\xd3\x77\x04\xc0\x94\x6e\x4d\x09\x3e\x2d\x94\xd0\x61\x36\x4c\xc1\x23\x10\x63\x72\x91\x03\xa7\x7c\xcb\x50\x18\x91\xbb\xc3\x18\x54\x57\xbb\xd2\x86\x9e\xb6\x3d\xc6\x0f\x19\x6f\x10\xa3\x8b\x7b\x36\xcb\x3f\x64\x3d\x35\xdd\xbf\x43\x8a\x44\xbf\x0c\x8f\x57\x0f\xad\x41\xbd\xde\x26\x7f\x0f\xfc\xf1\xf2\xf9\x27\xd6\x26\xd1\xb0\xd9\x80\xa0\xce\x22\x3f\x2f\x00\x54\x84\x5a\xfe\x41\xd3\x9d\xe5\xa4\x57\x21\x9f\x27\x6c\x67\xe6\x9b\xe2\xd5\xc9\xe0\x70\x13\x16\x39\x56\x1c\x26\x75\x1f\xb0\x64\x35\xe0\xe4\x2e\x25\x08\xc5\xf4\x9c\xd1\x2b\x51\x7c\x98\x33\xff\x97\xf5\xe5\x1e\x1d\xce\xaf\xa9\x42\x6d\x3d\xc5\x2f\xd1\x37\x9c\x64\xcc\xaa\xbb\x26\xdb\x1a\xf6\xde\xd7\x15\x36\x28\x84\x2f\x0c\xbd\xbb\xbd\x6a\xa0\xcf\xa5\x40\x7f\x40\x94\x96\xc0\x65\x32\xdb\xea\xc9\x4d\xab\x9b\xab\xa0\xb3\xc9\x88\xfa\x03\xd3\x6f\x91\x1d\x80\xe4\x9b\x37\x0b\x68\x37\x03\x7f\xf2\x49\xe7\x6d\x69\x2c\xd1\x77\x37\xe0\xd0\x79\x65\xd3\x3f\x17\x04\x2b\xbc\xd1\xe9\x90\xe0\x40\xf7\x19\x36\xf6\xfc\xa2\x54\x2a\xe3\x37\x48\x36\x77\x87\xc0\x1b\xde\xa7\x5c\x9a\x0e\x66\x15\x02\x81\xc4\x68\xfe\x5c\x73\xaf\x9e\x5b\xec\x37\x2d\x50\x20\xc3\xd3\x7f\xa1\x03\x5a\x67\xe2\x24\xd0\x95\xf0\x66\xa5\x1f\xe1\xf6\x81\xc3\x07\x39\x39\x27\x2f\x6a\xf7\x75\x0e\xd8\xd1\x83\x49\x17\x8a\xb4\xa2\xee\xb4\xe9\xca\x82\xbb\x67\x29\x6e\x98\x90\xf3\x16\xc9\xd9\x49\x59\x53\xd6\x84\x36\xeb\x1c\x1a\x2f\xb6\xa1\xcc\xa4\x5a\x8e\x88\xa0\x9b\xdd\x65\xa5\x55\x80\x25\x61\x8b\x36\xd7\xf3\xcb\x38\x9d\x2e\x2a\xb1\xed\x23\x32\x28\xec\x92\xa3\x27\x97\x8c\x0a\xdc\xed\xdb\x6c\x96\x32\xd3\xab\xd7\x97\x16\x21\x71\x37\x54\x75\x8e\x21\x01\x3a\x0c\x3d\x00\x9b\x6e\x31\x93\xcc\x15\x2c\x57\xef\x73\x10\x7b\xd4\x35\x7d\x52\x8b\xe4\x08\x73\x02\x7b\xf1\x84\x0f\x68\x55\x36\x08\x0f\x12\xc5\xff\xa9\x3c\xa6\x29\x73\x67\x80\xe0\x15\xe8\x6d\x19\x09\xf0\xd8\xf3\x72\x01\x0c\x9c\xb7\x2c\x09\x89\x84\x5f\xc8\x83\x15\xe6\xb9\x37\x0d\xc9\x2d\x36\x83\xef\x44\xd3\xf7\x5f\xc9\x6c\x4b\x0e\x89\xe1\x3d\x68\x2d\x19\x88\xb6\x85\x71\x3e\xad\xa8\x42\xbe\x9d\x2b\xbe\x2a\x76\xbb\xa1\x5d\x38\xcb\xaf\xb6\x5c\x40\xc2\x15\x9b\x0c\xee\xb0\xd7\x69\xb9\xbe\x35\x55\x40\x73\x4f\xf3\x77\x36\xc0\xf0\xfa\xcb\x95\x15\x93\x09\x36\x5b\x96\x46\xbc\x4b\x34\x4f\xb1\x9a\x5c\x16\x39\xa8\x8e\x87\x31\x7b\xfb\x3b\x5e\x7b\x51\x30\xfa\x7d\x56\x43\xed\x4d\xa0\x64\x30\xc8\xa0\xc1\x85\x8c\xcf\x2f\x9a\x6e\x3d\x62\x01\x22\x53\xf0\x12\x2d\xba\xb4\xa3\x54\x75\xa6\xf6\x55\x89\xb2\xb0\x95\x99\x28\x26\xe4\xf1\xb5\x8f\xa0\x50\xb8\xf9\x5c\x4f\xeb\xa3\xfb\xaa\xdd\x2c\x22\x44\xad\x4a\xbd\x41\x01\x39\xad\xf4\xc1\x53\xcb\x5e\x69\x33\x7a\xf1\x76\xa7\x83\x7e\xea\xea\x99\xbd\xcd\x59\x38\x5a\xfd\xed\x34\xff\xba\x80\x63\xa3\x5f\x4f\x55\x8e\x4e\xeb\x48\xf1\x48\x7b\x56\xb1\xf8\xd1\xf7\x30\x67\x62\x1c\xb5\x48\xc8\x08\x75\x3e\x35\x26\xa2\xf2\xaa\xbd\xe1\x26\xbe\xa5\x21\xcf\x67\x3d\xea\xfa\x79\x2c\xa5\xbd\x22\x12\x79\x5b\xd6\x6b\x86"}, -{{0xa6,0x33,0x7e,0x4d,0x3b,0x1a,0x49,0xb1,0x26,0x31,0x67,0x78,0xc6,0x13,0x51,0x6c,0x03,0xac,0x88,0xc9,0x6d,0x92,0xff,0x5c,0xc7,0xe0,0xc8,0x52,0x7c,0xce,0x1a,0x62,},{0xf5,0xea,0xc4,0xfe,0x0e,0xa1,0xa5,0xf2,0x36,0xb4,0x9d,0xa3,0x3a,0x24,0xe2,0xf3,0xa8,0x3d,0x4b,0x26,0x0c,0x54,0xd3,0x41,0x6c,0x64,0x4e,0x05,0xc8,0x38,0xbf,0x51,},{0x78,0x13,0x76,0xc9,0x51,0x2f,0xa3,0x3c,0x45,0x70,0x47,0xa1,0xf4,0xf0,0xda,0x31,0x76,0xe6,0x0e,0xe4,0x77,0x82,0x86,0x9b,0x7e,0x9f,0xa5,0x84,0x1d,0x96,0x4f,0x3c,0x1a,0xd6,0x6b,0x70,0xc1,0x14,0xb1,0x77,0x1c,0x32,0x4c,0x83,0xff,0x6c,0xd9,0x97,0xae,0xfc,0xcd,0xc5,0x9c,0x11,0x4d,0xb9,0xf2,0xf3,0xca,0x7d,0x84,0xa7,0xb6,0x0f,},"\xe3\x34\x30\xc3\x8c\x4a\x40\xb3\xc6\x6e\x20\xcf\x3b\x70\xe9\xfe\xa8\xcc\x50\x76\x1f\x2a\xfe\x24\x9e\xc0\x59\xc0\x7b\xc3\xb3\x7e\x5b\x94\xf4\xa4\x3e\x31\x00\x99\xb1\x9a\x85\xf5\x9d\xff\x73\xa7\xe4\x95\xc4\xdf\x31\xf7\x47\x80\xcd\xef\x7b\xd6\xe4\x7c\x39\x4c\x18\x91\xea\x30\x52\xe3\xcc\xf5\xd8\x4b\xae\x08\x2d\x24\xba\x71\x78\xac\x65\xd2\x29\xad\x18\xa8\x49\x40\xf6\xb4\xdb\xc5\x96\xee\x63\xc1\x81\xb5\x7b\x5b\x49\x69\x89\x79\xc1\x86\x32\xfa\x82\x1c\xa6\x1e\x35\xa0\xd0\x35\x1f\xe1\x3d\x69\xe0\x6d\xdc\xc8\xd6\x66\xdc\xa2\x45\x02\x17\x7f\x34\x4e\x2f\x44\x05\x75\xd3\x9e\xbf\xe5\xe7\xf1\x06\x53\xb6\x5b\xef\x29\x1d\xc8\x13\xa0\x43\x4c\x97\x5d\xe1\x64\xc1\xa7\x6b\xf6\xfc\xef\x98\xf2\x31\x81\xc0\x09\xb9\x18\x30\xb6\x18\xe4\x87\x48\x47\xd2\xe2\x1b\xbd\xb9\x3f\x20\xcd\x8b\x1f\x4b\xaa\xdf\x99\x42\x8a\x22\x67\x43\x86\xa6\x68\x15\x2b\x4b\x90\x39\xff\x06\xab\xcf\xe3\x34\xa0\x62\xf7\x94\x05\x61\x72\xec\xbc\x07\x94\xdf\x98\x27\x1b\x9a\xcf\xe4\xb7\xda\x55\x3a\x87\x63\x42\x37\x63\x00\x09\xa0\x5b\x25\x7c\x18\x4c\xbe\x23\xd9\xcd\x5a\x03\x86\x58\x01\x0f\x57\x48\x99\xf3\xb2\xd1\x54\xd1\x85\xee\x67\x23\x09\x13\x65\x0c\x3a\x05\xb5\x4a\x2e\xdc\x24\x3a\x42\x87\x39\x8e\x37\x69\x28\xea\x9c\x6b\x2c\xba\xf3\x71\x25\x25\x40\xe2\xb8\x04\x3f\xcf\x55\x68\x13\x19\x6a\xe5\x72\xc2\x7c\xfb\x5a\x46\xab\xb9\x72\x9a\xf2\xdc\xfc\x29\xe0\x33\xdd\x11\xf3\x3e\x86\xcc\x6a\xc3\xbc\xe6\xf3\xf9\x57\x7d\x36\x78\x1a\x69\xed\x7e\xaf\x8c\x82\x63\xa0\xf1\x8e\xba\x0f\xe8\xa4\x81\xf3\xe1\x5a\x55\x59\x94\x34\x19\x5f\x7c\xb0\x57\xdd\x36\x4e\xaa\x07\xdd\x0d\xfd\x26\x6b\x80\x7f\x53\xa2\x07\x0f\xd7\x91\xe8\x72\x42\x2f\xd9\x07\x13\x4f\x4a\x8a\x78\xa8\x76\xbd\xcb\x03\x1a\xc8\x60\xdf\xe0\xbb\x57\xe1\x05\xdb\x82\x87\xb3\x1a\x60\x4e\xb7\x12\x69\xbe\x5b\xa2\x29\x98\x5c\xea\xbc\x2b\xdf\x16\x5a\xc7\x41\x65\x0b\x1f\x01\x3a\x66\xc9\xbd\x24\x3d\x03\xa8\xb1\xc5\x08\x13\x81\xcb\x92\xe2\x3f\x90\x57\x77\x1f\xc0\x7c\xa3\x2d\xff\x1d\xb9\x4f\x5a\xdf\xd2\xf4\xff\x9a\xf3\x1d\x25\x0d\xd4\xf8\x6b\x22\x59\x2f\x60\xa7\x45\x75\x15\x62\x13\xf1\x08\x46\xc7\x46\xa9\x20\xfe\x39\x85\x1b\x32\xfe\x4c\x8b\x87\x58\x76\x5b\xc5\xb8\xb9\xd5\xb9\x92\x63\xdf\x36\xf9\x78\x88\x05\x3f\xd1\x0f\x1d\x68\xf5\x77\xae\xd5\x59\xbc\xfd\xe7\x44\xbc\x65\x11\x07\x6c\xaf\xd6\x89\x44\xa0\xed\x10\x55\x2d\x11\x34\x4b\xc7\xe4\xd9\xef\x93\x6d\xac\xce\xd5\x27\x43\x31\x32\x95\x9b\x1c\x73\x24\xad\x1c\x4c\xbc\x3a\x1a\x73\x6b\x1f\x02\xaa\xe8\xe0\x61\x1a\xe2\x3f\xdd\x47\x4f\x5b\x8e\xe7\x05\x6f\xcb\x5a\xf6\x13\x3e\xcc\x08\x4b\xb9\xf1\xf5\x0c\xbd\xac\x66\x24\x44\x37\xb4\x34\x8f\x4e\xdf\xe2\x37\xfc\x3c\x38\x29\xab\x94\xeb\x4f\x14\xca\xb1\xcc\xd6\xca\xee\x36\xfa\xdc\x20\xa3\x10\xcf\x06\x90\x62\x2c\xdc\xa8\x48\xae\xd0\x3f\xf4\x03\xa6\x63\x3f\x4f\x65\x79\x94\xb7\x80\xdd\x60\x48\x14\x9c\x3b\xfb\xc1\x78\x89\xe3\x7d\x90\xb1\xe5\x42\x0e\xb3\xd4\x59\x6b\x91\xba\x11\xbc\x02\x29\xc6\x5d\x05\xb9\x3c\xd7\xe0\x45\x4d\x1f\x3c\x6e\x1e\x80\x71\x98\x37\x92\xc4\xd4\x36\x8d\x07\x78\xae\xf4\xe1\x23\x33\x5f\xd2\x96\x2c\x65\x7b\xd0\x51\x35\x71\xa5\xfc\xe2\x11\xde\x62\x87\x4f\x27\xca\x10\xdc\x15\xba\x2d\x44\x5f\x1c\xf4\xbe\x5f\x83\x3c\xf0\xb5\x64\xc0\x22\x57\x6b\x98\xc0\xa2\x43\x49\xb6\x70\x85\xf9\x22\x02\x67\x5d\x7d\xac\x48\xb9\x5e\x3b\xfd\x65\x55\xa9\xec\xb7\xc7\x2f\x08\xbf\xec\x0d\x22\x02\x22\x49\x2f\xdc\x96\x36\xf0\x36\xec\x45\x08\xa3\x65\xb7\xb7\x09\x79\xf9\xeb\x4a\x72\x63\xa8\xba\xcb\x1c\x1d\x01\x55\x73\x86\x46\xcd\xd4\x6a\xb9\x23\x4a\x17\x03\x11\x50\x0d\x0b\xae\x6e\x55\xa8\x63\xbd\xaa\x56\xf5\x16\x45\xad\x85\x29\x7a\x73\x81\xf8\xd2\x0c\xf9\x6c\x47\x4d\x1b\xb8\x1f\xce\x13\x2b\x14\x55\x5d\x1a"}, -{{0x10,0x7d,0xa9,0x8d,0x0e,0xe8,0xe7,0xc0,0x0f,0x6d,0x41,0xec,0x26,0x59,0x44,0xce,0x67,0xef,0x8c,0x8f,0xfb,0x51,0xf4,0xf1,0x1f,0x4e,0x5f,0x1a,0x27,0xfb,0xe8,0x05,},{0x3b,0xec,0x34,0xb1,0x61,0xb1,0xbc,0xff,0x00,0x9f,0x8c,0xfc,0x50,0xd8,0x4c,0xeb,0x6a,0x2d,0x5b,0x20,0x3b,0x52,0x38,0xa8,0xaa,0xd8,0xa8,0x36,0x18,0xb4,0x42,0xe7,},{0x53,0x25,0x2b,0x92,0x3a,0xd1,0x9c,0xc3,0x97,0x84,0xd3,0xa9,0xae,0x59,0xd6,0x2a,0x63,0x00,0xdc,0xc5,0x0a,0xc8,0xfd,0x07,0x13,0xcb,0x58,0x84,0x45,0x01,0xd8,0xd3,0x80,0x5a,0xfa,0x0f,0xda,0x64,0xc7,0x3e,0xa0,0xf6,0x0e,0x6a,0x8b,0x34,0x45,0xbf,0xff,0xe6,0xca,0x6b,0xfd,0xc8,0x7e,0x12,0x8b,0xaf,0x99,0xbf,0x62,0x68,0xfc,0x09,},"\x1a\x7b\x7f\x3e\x1c\x7c\x41\x49\x2a\x7c\xe7\x99\xef\xdb\x2d\x9d\xc2\xf2\x48\x9c\x84\xae\x28\xbb\x7d\x08\x4f\x32\xec\xa8\xfb\xb0\x66\x88\x5a\xc6\xf2\xef\x74\x49\xe7\x12\x26\xa8\x2e\x9f\x15\x37\x72\xa9\x93\xeb\x6b\x6b\xca\x64\x91\xd2\x6a\xca\x5d\xee\x98\xb7\x7a\x1d\xdc\x59\x92\x2b\x31\x45\xc4\x47\xde\x73\x7f\xaf\xac\xba\x5a\x75\xf2\xa8\x01\x37\xb5\x59\x46\x97\x22\x0d\x19\x61\x76\x74\xa6\x91\x13\xfd\xf7\x7c\x34\x3a\xf2\xb7\xe3\x86\x1b\x5b\x78\x22\xf5\x8d\x60\x08\x9c\x3c\xa5\x4c\x74\x9d\x27\xf8\x83\x79\xc0\x67\x59\x8f\x06\x39\x39\xba\x86\x31\xd1\xf5\x2d\xc9\xab\x45\x50\x45\xfb\x36\x0c\xc2\xa5\xb6\xb0\x12\x7f\xac\xfc\xf5\xb1\xb4\xc3\x3e\x3f\x19\x4f\xc9\x24\xb8\x54\x16\x8c\xb1\x16\x9a\xb1\x09\x97\xb4\x38\xb7\x1c\x80\x87\x83\x47\xbe\x88\x7a\xf4\x48\x10\x13\x4b\x51\x4c\x80\x69\x08\x20\x1a\x3d\x3e\x6d\x0c\x56\x12\x0c\x43\x14\x87\x4d\xc2\x94\x4d\x84\x44\xf0\x1b\xaf\xa3\x4a\xa6\x2e\xce\xf0\x98\x15\x45\xe5\xd0\x2f\x40\x16\xc0\xb1\x64\xfc\x05\xae\x18\xf5\x35\xc3\x1b\xf2\x0b\x86\xf3\x1f\x7a\x79\x4a\xba\x14\x89\x84\xc3\xff\x43\x3d\xc2\x22\xc4\x43\xb5\xd2\x6c\x1f\x66\xe6\xc5\xf1\x9d\x19\xcd\x6e\xad\xd4\xdc\x94\x10\x1b\x2f\x52\xb5\x8c\x9d\x45\x90\xcb\x10\xdb\xc5\xd6\xea\xcd\x11\xd4\x2e\xd0\x9f\x15\xbd\xe4\x4e\xe9\x27\x1d\xef\x29\x2f\x73\x1b\xf3\xb4\xac\x6c\xd1\x27\xe4\x88\x4c\x2c\xb3\x0b\x28\x5f\xc9\x24\x76\x38\xa2\x99\xe4\x16\x52\x06\x24\xd1\xec\x8d\x0d\xf2\x49\x89\x39\xc7\x19\xa9\xe7\xbd\x29\xa3\xc5\xc3\x2a\x3e\x82\x41\x36\x8d\x6e\x4f\x90\xfe\xa2\x9d\xc3\xa3\xf1\x47\xea\x9f\x76\xc5\x78\x0e\x73\x14\x3f\x55\xd3\xde\xc7\xb6\x63\x41\xd3\xf3\xea\xc1\xd9\x8f\x8e\x7d\x4e\x87\x75\x09\xb4\x43\x8c\x3a\x52\x46\x6d\x24\x2a\x10\xb4\xc2\x7c\x4a\x0d\xb9\x23\x2d\xad\x01\x14\x14\xeb\xfb\xd5\x79\x06\xf1\xa4\x10\x20\x7b\x52\x6b\x0d\x1f\x1b\x69\x86\xb3\xeb\xd7\x55\x0a\x2b\x3c\x15\xfc\x24\x09\xc7\x62\x6e\x0d\xd3\x30\xef\x67\x22\xe3\xba\x48\xb1\xd9\x20\x56\x52\xac\x19\x4c\x21\x47\x3c\xe2\x58\x55\x9d\xb5\x11\xef\xad\x3e\x5d\x55\xf2\xa7\x96\xd6\x5a\x6a\xb9\x7d\x86\x31\x06\x2a\x59\x3a\x13\xaa\xa0\x95\xdb\xc9\x3e\x62\x17\xce\xd6\x19\xcb\x16\xa5\x7e\x74\x43\x55\xa1\x6b\x15\xe7\x7d\x49\x79\x11\x92\x99\xbb\x04\x3e\x48\xfa\x3e\x61\x54\x60\xe1\x64\x88\x29\x84\xa2\x23\xd4\x18\xca\x95\x34\x0c\x5b\xfc\xda\x67\x3f\xcd\x13\xb2\x9f\x2c\x47\xd2\xf9\x7e\x3e\x8c\x61\x3b\x6c\x58\xdf\x0e\x62\xcf\x23\x06\x1d\x6f\x54\x5b\x75\x50\x33\xfd\x3d\xc1\x40\x5e\x5f\xef\x35\xa1\x3e\x01\x5f\x98\xb1\xcc\x42\xf7\x1b\x99\x68\x1f\x96\x81\x25\x82\x29\xa4\x47\x3d\x86\xea\xbb\x0c\x17\x92\x79\x41\xe5\x0c\x08\xf3\x4a\x76\xb4\x3b\xcc\x6d\x04\x2e\x56\x32\xef\x9c\xcc\x91\xb6\xe6\x95\x0f\x5d\x30\xf6\x70\xfb\x39\x02\xc3\xd4\x09\x31\x5a\x40\xb0\x82\x1c\xe8\xa9\x9a\x97\xfe\xca\x54\x78\xbf\xd7\x82\xe7\x87\x67\xb3\x11\xf3\x74\x16\x3f\x58\x96\xb0\xbe\xb9\x58\x38\xe6\x45\x87\x8c\x64\x99\x03\x85\x12\x3b\x61\x57\x5d\xd8\x42\xdc\x76\x35\x4b\xac\x9c\x6d\x5a\xcd\x99\x35\xb6\x09\xbc\xcc\xb8\x46\x3d\x39\x22\x5d\xa1\xaf\xb8\x91\x1d\x36\xe6\x09\x89\x2d\xd1\x72\x38\x52\xab\x9f\x82\x75\x8f\x3f\x1e\x4d\x28\xdc\xf0\x2c\xb0\x6e\xed\x26\x84\x4a\xae\x68\x82\xed\x44\xbc\xe4\x4a\xbc\xd1\xdf\xba\x63\x34\x18\xc9\xf1\x55\x87\x9c\x97\xab\x27\xf8\xae\x23\x83\x30\x39\x2b\xe5\x49\x1a\x07\x86\x62\xda\xaa\x02\xa3\xd5\x45\x8b\x77\xc5\x49\xc4\x9b\xe2\x01\x24\x5e\x7a\xae\xc0\xd9\x4e\x54\x37\xbe\xca\x6e\x5a\xb0\x46\xd6\x94\xe9\x6b\xf5\x1e\x04\xfb\x44\x37\x9b\x2b\x9b\x80\x16\x75\xfe\x14\x77\xf3\xe0\x89\x87\x4a\x60\x11\x71\xd8\xb6\x8f\x02\x02\x01\x46\x01\xa5\x3f\x81\x2f\x53\xe5\x81\xc3\xb9\x63\x12\xb3\x6b\x9e\xe0\x4f\xff\x11\xd9\xea\xb4\xe4\x51\x48\xdc\xc8\xf0\xfa\xb1"}, -{{0x8b,0xc2,0x29,0xfc,0x23,0x46,0x53,0xb1,0x3c,0x92,0x47,0x10,0xcb,0x46,0x8b,0x8f,0xa9,0xb2,0x80,0xe2,0xad,0xb4,0x9c,0xb4,0xb3,0x6b,0xf5,0x9d,0x6f,0xa4,0xa6,0x39,},{0x46,0x14,0x69,0x75,0xdf,0x67,0x04,0xcb,0xf4,0x53,0x20,0xa5,0xe6,0xcb,0x6d,0xe8,0x13,0x46,0x9f,0x31,0x31,0xe6,0x1d,0x44,0x7b,0xbc,0xa1,0xa4,0x77,0xa0,0xc5,0x57,},{0xd2,0x43,0xb8,0x7d,0x13,0x97,0xd5,0x94,0x13,0x9d,0x83,0xc3,0x9a,0xcf,0x85,0x01,0xd0,0x73,0xbd,0x4b,0xe7,0x18,0xb4,0xc2,0x06,0x98,0x07,0x29,0xe7,0x20,0xa4,0xc5,0xb0,0xea,0x91,0xa2,0x8e,0xa1,0x26,0x04,0xa9,0x87,0xe6,0x95,0x91,0xc5,0x43,0x04,0x9f,0x29,0x73,0xbb,0x91,0xc1,0x70,0x21,0x3c,0x32,0xa6,0x4a,0x0f,0xac,0x82,0x04,},"\xba\xe2\xdc\x7f\x94\xab\x5c\xcd\xca\xa8\xcf\x49\xed\xbe\xf0\xf6\xd7\xae\xb1\xfa\x89\x07\x80\x05\x33\xaf\x44\x92\x61\x11\x94\xe5\x6c\xef\x37\xb1\xf0\x33\x30\x37\x38\xae\x2c\x3b\xc4\x58\x8f\x5c\xb3\xd5\x5f\x34\x5b\x9a\x40\x7e\x78\x77\x42\xa0\x6a\xf0\xb6\xee\x20\xde\xe3\xdf\xe9\xc9\x1d\x76\x2a\x3e\xbd\x19\xae\xd0\x79\x07\xbb\xb9\x1c\xd7\x76\x32\x65\x40\xde\xd9\xf7\xff\x7d\xda\x76\x61\x5f\x97\x8e\x94\x90\xf4\x06\xed\x2d\x91\x16\xe2\x09\x3f\xa7\x85\xe9\x71\xb5\x06\x2d\x31\xcb\x40\xff\xf9\xe3\xc5\x51\xa7\x3b\x20\x24\x5d\x46\xdf\x4d\x7f\xd1\x30\x3a\x28\x18\x01\x72\xd9\xa2\xbf\x55\x93\xc4\x79\x17\xb5\x86\x90\x91\x7c\x1f\xb0\xe1\xe2\x99\x4d\x1f\xa9\x77\x35\xae\x37\x8d\xe6\xea\xfd\x5c\x1a\x25\xab\xaf\xa3\xcf\xd2\xdf\x7a\xea\xbd\x6e\x68\xfc\x44\xed\xf8\x2f\xc8\x36\x94\xe5\xd8\x41\xa1\x5b\x14\x56\x8b\x61\x10\xbe\x64\x4b\xf2\x2b\x71\xfc\x47\xd7\xf0\x7e\x16\x66\x95\x7d\x0f\x87\xda\x17\xf1\x3f\xcd\x63\xc1\xc2\x96\x6f\x68\x7d\x25\xdc\xbd\x99\x63\xf0\x1e\xff\x13\x2d\x5f\x2b\x86\x67\x78\x16\x58\x8c\x12\x3e\x94\x57\xbe\xfc\xce\xd2\xd3\xcd\x1d\x1b\xeb\xe8\xdd\x8f\xbb\x15\x87\xe5\x53\xcb\xcc\x4c\x87\x62\x06\x4c\xd3\x2e\xf7\xa1\x70\x24\x10\xf7\x7f\x15\x24\x0d\x7e\x2b\xb5\x82\xc6\x78\xc0\xda\x88\xef\x45\x22\x83\x0b\x14\x36\x60\xac\x9c\x43\x4d\x95\x77\x2e\x6e\xee\xed\x60\x14\xae\x16\x82\x4c\xcd\xc4\xdf\x2d\xf6\x4a\xeb\x69\x80\xb5\x1d\x11\x89\x85\xdc\xbb\xd1\x96\x1f\x31\x5e\x6a\x94\x33\xf0\xb9\x6b\x1e\x63\x51\x25\x7e\xad\x83\xe0\x5b\x4c\xc8\x9c\x92\x4b\xf8\x35\x58\xba\x7d\x2e\x7c\xa3\x7c\x03\x17\x9a\x8f\x85\xb8\x31\xe7\x21\x7b\xf4\xc5\x53\x83\x87\x61\xd3\x26\x02\x85\x3b\x81\x59\x3b\x0e\xbf\x8e\x4b\x9f\xfa\xf0\xec\x40\x5b\x2a\x83\xaf\x7d\xe5\x55\x4d\xaa\xd2\x8b\x58\x2e\xe0\x8b\xd8\x4b\x37\x55\x50\xca\xe0\x8a\xe4\xa5\xbd\xa7\x15\x81\xfc\x3b\x7b\x54\x49\x8c\x4e\x1a\xfb\x96\x6b\x4a\xf1\xd9\xc8\x43\xa6\xb2\x5b\x34\xe0\x4c\xfd\x9b\xd2\x37\x42\x44\xf1\xfe\x20\xec\x62\xbe\x3c\xcf\xab\x4e\xde\xf7\x9e\xd6\x4e\x6b\x71\xaa\x92\x28\x12\x7c\x63\x59\xea\x1c\x4a\x80\x87\x89\x08\x96\xff\xa4\x6e\x00\x92\xde\xc7\xef\xbc\x96\x0a\x17\xb7\x70\x91\x6f\x95\x40\x70\x13\x2e\x26\xd9\x8d\x97\x74\xa2\xac\xdf\x80\x9d\x58\x6d\xf0\x25\x2f\x67\xcf\xe8\xd9\x85\xa3\xe2\x48\xdb\x0f\x90\x73\x1a\xce\x7a\xbd\x99\x9c\x74\x6b\x69\x64\x8d\x5c\x3b\x4b\xd6\x11\x37\xe0\x8f\xcc\x8b\x2e\xfc\x56\x76\xbc\xd8\x56\xa1\x3b\x36\x21\x51\x47\x4c\x4a\x1e\xfd\xed\xc5\x92\xcf\x3e\xad\x1a\xba\xbc\xd4\x8e\xe2\x04\xd2\x77\x26\xad\x1b\xda\x4f\xe4\xb0\x9a\xb5\x10\x89\xd0\x16\xde\x6b\xa2\x59\xea\x81\x80\x7f\xaf\x21\x1c\x87\xe4\xc9\xef\xbf\x6a\x4c\x75\x3e\x08\xf7\x80\xed\x55\x33\x8c\x0f\xde\x14\xfb\x99\xb3\x07\x22\xb5\x59\x4b\x3a\xbe\x02\x04\x7f\x46\x62\x42\x42\x1f\xb8\x11\x76\xc9\xc4\xf0\xfd\x2b\x5e\x7c\x5a\x0f\x65\xa0\xc5\x9a\xa8\xc3\xa9\x86\x08\x7d\xe7\xba\x40\xba\xca\x77\xbd\x36\xac\x21\xce\x34\xe9\xfe\x97\xfa\xcc\x4e\x29\x83\x30\xee\xce\x1c\x8e\xc6\x23\xe6\x6a\x4b\x0f\x23\x42\xd2\xc5\xa0\x2c\x5f\x5a\xbd\xdc\x5f\xf1\xf1\xf2\xd0\x3c\x1d\x4e\xe9\xb4\xb3\x42\xed\x3b\x1c\xc2\x65\x61\xf3\x21\x7b\xf8\x50\x0e\x08\xf0\x27\x57\x1c\x53\xc9\x23\x26\x05\xa5\x3f\x2b\xda\x02\x4e\x39\x92\x91\x63\xa8\xe0\x07\x91\xac\x06\x56\xbb\x07\x83\x82\x5e\x71\x05\xff\xa9\xd9\x09\x69\xdc\x09\x4a\xf4\x6f\x70\x2e\x85\xcc\x11\xe4\x42\xb3\xd5\x53\x4c\x1d\x32\x75\x20\x7d\x6d\x29\xa9\x42\xc3\x58\xed\x5f\xa0\x75\x57\xc3\xc0\x14\xcf\x54\x1f\x9a\xae\xea\x60\x25\xb4\x1e\xcd\xd8\x48\x51\x2b\xa2\x5e\x72\x1e\x43\xd3\x29\x18\x5f\x8f\x94\x89\x2e\x9e\x2d\x5e\x7c\xbb\x99\xe7\xad\x25\xf6\x9e\x5b\xef\x73\x2c\xfc\xeb\x07\x86\x11\x55\x3c\xc7\x83\x77\x37\x5e\x74\xe6\x6f\x1b\x9d\x8d\x20"}, -{{0x3e,0xdb,0x50,0xff,0x07,0x4e,0xf9,0x71,0x7f,0x4f,0xb0,0xb6,0xce,0x25,0x2b,0xf4,0xbd,0x04,0x9c,0x90,0x83,0x77,0x5f,0x52,0x9e,0xaf,0x51,0xe9,0x75,0xcb,0x32,0x45,},{0x4b,0xc2,0x1f,0xe0,0x3e,0x67,0x9a,0xbb,0xfc,0xd8,0xc5,0xea,0x2b,0xcc,0x4d,0x83,0x8a,0x78,0x7d,0x48,0x40,0xc3,0xbc,0x39,0xde,0x4b,0x04,0xc4,0x17,0xc7,0x68,0xa5,},{0xde,0xb3,0xd9,0xfc,0x7b,0x2d,0x86,0xab,0x4b,0x92,0x6f,0x99,0x52,0x79,0x70,0xab,0xb5,0x18,0x38,0xbc,0xc2,0x91,0x9e,0x94,0xcd,0xa3,0x37,0x1f,0xd0,0xe7,0x69,0x3f,0xe3,0x7e,0x0c,0x40,0xe1,0x23,0x3b,0x09,0xff,0xa9,0x03,0xa0,0x34,0xdd,0xe2,0x87,0xc0,0x23,0x7d,0xc5,0x94,0xf5,0x3a,0xbc,0x87,0x84,0x48,0x69,0xdc,0xe9,0x20,0x02,},"\x97\x5e\xce\x4e\x81\xf0\x01\x5f\x5a\xc3\x04\x46\x09\xd0\xac\x3a\x8d\xf9\x14\x5b\x50\xc4\x28\x89\xdd\x31\x2f\x56\x3c\xf6\x12\x6e\x36\xff\xfa\xf2\x1e\xb6\xb8\x4f\xbd\xa1\x5a\xa8\x5c\x66\x14\x5f\x75\x41\xe5\xb4\x1a\x8e\x81\x70\x0b\xe3\x56\x22\x4f\xc1\x09\x32\x7a\x69\x19\x66\x56\x73\x53\x4f\x5c\x8a\x4a\x00\x17\x50\xb1\x99\xdb\xfd\x63\x06\x91\xaf\x55\x2d\x4d\x26\xa9\xd9\xaf\xb3\x3a\x16\xaf\x39\x11\x54\x12\x4b\x53\x42\x6c\x9f\x69\x50\x57\xb1\x81\x4f\xd6\xd3\x10\x29\x8a\xf6\xc8\x30\x68\x6a\x4a\x00\x7a\x14\xe0\x05\x7b\x72\xfb\xad\x5b\x80\x3a\xd3\x53\xd1\xc3\xfd\xb8\x90\xa9\xc8\x18\x08\xe8\x9f\x22\x91\x87\xbc\xb4\x4f\xee\x16\xa4\xeb\xca\xd5\xeb\xa4\x59\xb0\x28\x27\x2a\x56\x2c\x05\x07\x9f\xa7\xae\x3e\xca\xe8\x04\xa9\xe8\xc4\xf3\xf3\x15\x81\x3c\x5e\xe0\x84\x1b\xbc\xcf\xe4\xa9\x56\x23\xb5\x17\xa4\xb4\x2b\x2c\x6d\x97\xa3\xbf\x26\xac\xdb\xe2\xe9\x79\x63\x3f\x02\xaa\xc4\x66\x52\x6a\x3e\xbb\x14\xda\x19\xbc\x95\xf2\xc3\xfd\xf6\xbd\xb0\x8b\xe8\xbd\xe9\x7a\x86\x4c\x90\x7e\x91\x8c\x67\x9a\xb7\x26\xf8\x01\x77\x14\x58\x40\x21\x6b\x9d\xc3\xf9\x81\xef\x17\x87\x4f\x08\xb2\xfc\x66\x11\xa6\x34\x6c\x3d\xa6\xa5\x5e\xcf\xa7\x53\xc9\x91\x9f\x4f\x19\xe3\xc7\x90\x93\xbf\xd7\x8f\x86\x15\x98\xe4\x66\x6e\x1c\xab\x68\x8e\x46\x04\xd4\x6c\x9c\x58\x2e\xad\xb9\x2c\x98\x8f\x47\x8d\x16\x0f\x5a\x15\x18\x2b\x33\x40\x20\x17\x97\xd0\xb9\x55\x28\x2e\x4a\x21\x7b\x50\xb1\x4b\x10\xc9\xf4\x90\x67\xea\x3e\x84\xe5\x27\x4d\xca\xec\x74\x47\x4c\x57\x07\xc2\x8b\xba\x0d\xb8\xcd\xe3\xe8\x38\xd7\x31\x3c\x17\x1b\x85\xff\x2b\x9a\x3d\x2b\x16\x7e\x90\x61\xf8\x4d\xf3\xb1\x3b\xdd\x08\xb2\xd5\x01\xe5\x37\x92\xd6\x80\x54\xd0\x48\xab\xfe\x3b\xce\x98\xd9\x78\x25\x6f\x2f\xd2\xc6\xc4\xe7\x6f\x39\x68\x8c\xcc\xf0\xfe\x14\x9a\xf9\xd3\x47\xe7\xb0\x40\xef\x24\x1d\xd5\xa5\x3e\xaa\x5e\xab\x35\xa1\x8c\x68\xc7\x54\xa0\x6b\x03\x39\x9b\xbe\x56\xa2\x52\x68\xc8\x29\xa5\xba\x82\xb2\x81\x92\x04\x1d\x3b\xd2\x44\xeb\x08\xbf\x78\xe7\x6d\xef\x87\xcd\x09\xf3\x2b\xea\xc9\xbb\x63\x98\x23\xb3\x69\x67\xa5\x74\xd8\x96\x0d\x1b\xd0\x34\x35\x67\x9d\x93\xed\xdc\x55\x80\x63\xc5\x40\xb9\xc2\xf6\x09\xfe\xd2\xe2\xe3\x57\x6d\x19\xe6\x20\x9e\xab\x46\x6c\x20\x67\x91\xc3\xaa\x19\x96\x23\xfb\xae\x7d\x34\x97\xe8\x0f\xdd\x3f\xcb\xaf\x5b\x89\x11\x0e\xd7\x22\x44\x23\x4b\xe8\x5c\xca\x4b\x27\xa0\x9b\xb7\x0a\x26\xec\xe4\xeb\x8d\xd9\x70\xa2\x6e\x5b\x04\x36\x1f\xa5\x0e\x90\x38\x0e\xd6\x5f\x41\x4c\x1b\xe9\xf5\x06\x4f\x71\x42\x91\x16\x26\x7e\xdd\x69\x76\x42\x2a\xd9\x2d\xeb\x2b\x80\x4a\x92\xe8\x1c\x9f\x65\x22\xa0\xf3\xb5\xd8\xad\x36\xb4\xf8\x7d\xb5\x16\xa2\x28\x73\xe6\xf2\x72\x84\xf2\xca\x36\x0a\x2f\x40\xff\x3d\x8e\x23\xde\xc8\xef\x8a\x17\xa4\x3a\xcb\xb6\x12\x71\xa7\x27\xcb\x86\x90\xd2\x9b\xb8\x20\x16\x73\x6b\x31\x02\x62\x01\xdd\x3d\x38\x8d\x2c\x64\x3a\x73\xcf\xbd\x0a\x94\xe2\x05\x51\xfb\x5f\x8e\x1f\xfc\x39\x74\x12\x72\xaa\x23\x08\xdc\x8d\x21\x33\xa3\xfa\x9c\xf1\x09\x79\x6d\x69\xd2\xcc\x8a\xdd\xc4\x4a\xe2\x52\x77\x81\xee\x99\x3a\xf2\xa6\x37\xa8\x72\xf0\x2a\xff\x47\x4a\x70\x73\xf2\x9d\x9c\x89\x50\x77\x01\xfe\xcb\xbf\xd5\x10\x13\x53\x53\x7e\xba\x17\xc2\x96\x69\xda\xc0\x42\x7e\x38\xe2\x2d\xfa\xac\x91\xfc\x20\xd9\xe3\xfe\xe7\x91\xf4\x62\xa8\x63\xbb\x19\x08\xfb\x1e\x42\x04\xb6\x88\x80\x31\x4d\xda\xca\xaa\x35\xa1\x7a\xf5\xf5\x7a\x39\x9f\x19\x31\xe7\x8f\x5a\x37\x45\x4f\xd3\x8c\x57\xa6\x8e\x8d\x36\x78\x48\xa9\x73\x45\x18\x9c\x70\x07\x7f\xd1\xaa\x07\x54\xe7\x03\xe3\x52\x61\x80\x63\xb9\xe3\xfa\xf3\xb1\x4b\x5f\x0b\x27\x11\x36\x33\xc5\xd1\x73\x63\x74\x1e\x96\xa6\x7e\x81\x64\x01\xe8\x09\x8c\x17\xbf\xfe\x9c\x6f\x35\x87\x64\x6f\x40\xe9\xfd\xb6\x81\x9f\xd2\x2a\x74\x3a\x7a\x6e\x10\xfe\xba\x11"}, -{{0xcd,0xa4,0xba,0x93,0x94,0x0a,0xa0,0xc0,0xc3,0x15,0x0b,0x39,0x29,0xb9,0x5e,0xe7,0x76,0x9c,0xe4,0x3f,0xd9,0x8e,0xca,0xff,0x9c,0x4a,0x50,0x9e,0x73,0x6d,0x5c,0x8e,},{0xf4,0xc7,0xa2,0x5f,0x1a,0x74,0x3d,0xaf,0x41,0x41,0x7e,0x47,0xe0,0x27,0x53,0x7f,0x24,0xf4,0x81,0xbd,0x1a,0x75,0xe6,0xb1,0xd3,0x3e,0xc4,0xc8,0x2c,0x55,0xa2,0xd3,},{0x31,0x04,0x8d,0x33,0x4a,0xf0,0x5a,0x4f,0x27,0x5f,0xf8,0x27,0x54,0x4e,0xa2,0x96,0xa4,0xa7,0x75,0xfa,0x59,0xef,0xa0,0x00,0xc5,0x76,0x13,0xfa,0x6e,0x5c,0x49,0x3c,0x3a,0x9b,0x79,0xe8,0xce,0x56,0xe7,0x22,0x5b,0x0f,0xa3,0x26,0x20,0x4f,0x03,0x36,0xc2,0x13,0x53,0x5a,0xe5,0x89,0x17,0x7a,0x8e,0xae,0xdb,0x6d,0xf8,0xb2,0x02,0x03,},"\x3a\x1d\x66\x8c\x66\x88\x41\x48\x96\xa7\x69\x7f\x3c\x2e\x43\x10\x98\xed\xfc\x45\x7e\x04\xd2\xda\x86\x95\x68\xad\x5b\x33\x10\xe5\x9e\x4c\x72\x7c\x90\x3c\xbf\x18\x17\x40\x88\x02\x31\x9a\x8c\x23\x1b\x58\x02\x3d\xfa\xe4\x94\xc0\x13\xaf\x0f\xdb\x78\xc9\x1d\x5b\x45\x7f\x8c\x47\xa3\xdc\x31\xd8\xc8\x59\x4a\xa0\x8f\x14\x62\x03\xfa\x2c\x28\xb3\xdd\x79\x6a\x11\xa9\x7a\xde\xde\x6a\x7a\x70\x9b\x5a\x19\x18\xef\x1b\xea\x83\x53\x3c\x78\x34\x73\x70\x33\x56\xf5\xbe\xea\x7f\xd1\x8a\xc4\x4e\xc6\x89\x04\x95\xed\x17\x0d\x03\xf1\x5b\x41\x86\x08\xa7\xd9\xef\xd5\x2f\xa1\x09\x18\x63\x80\x51\xc4\x48\xd9\x8d\x57\x24\xf5\x67\xc8\xc6\x7f\xd5\xb6\xec\x8c\x3d\x63\x60\x08\xb9\xba\xe5\xe8\xb1\xe9\x84\xf8\xff\xb8\xb6\x4b\xee\xbd\x63\x45\xa1\x05\xc1\xc1\x08\x31\x32\xfd\x45\x08\xd6\xac\x0d\x4e\x91\x45\x50\x12\x10\xe5\x17\xd9\xb2\x24\x78\xe2\x15\xb6\x02\x59\x9f\x80\x37\x62\xdc\xd5\xa4\x09\xb3\x46\x0e\x7f\x34\x0f\x47\xef\x77\x28\x1a\xd2\x38\x3d\xe0\x8c\x5b\x80\x95\x38\xaa\xec\x92\x2b\xfc\xa0\xd6\x75\x2f\x14\x79\x72\x64\x6d\x0a\x8d\x83\x40\x77\x2c\x87\x1d\x3b\x34\xab\xc0\x60\x37\xde\x3a\xb4\xe3\x71\x29\x86\x5d\x5b\xa7\x0b\x6f\x3c\xc9\xa0\x59\xef\xb7\xdd\xdc\x38\x82\xf4\xfc\xfe\x13\xf4\x48\xc9\xbc\x66\x48\x88\x58\x96\x03\xba\x98\x68\x3a\x93\xb4\xb3\xb1\x01\x49\x92\xa5\x5c\x8e\x4e\xa1\xba\xf9\xcc\x00\xd1\xba\xdf\xf5\xfd\x7f\x5d\xa5\xe3\x07\xfb\xd1\xb4\xc9\x84\xe0\xfa\x0e\xde\xc5\xd3\x0b\xfe\xf5\xf4\x77\x30\x12\x63\xb5\xd7\x52\x00\x1b\x85\xdd\x52\xdf\x3b\x4a\x7a\xc2\x3b\x93\x0a\x91\xc0\xa4\x57\x65\xa6\x64\x88\xd8\xeb\x59\x01\x85\x70\x60\x06\x7b\x82\x37\x81\x88\x54\x92\x88\xdd\xc6\x18\x31\xe5\xb6\x84\x1b\x34\x4c\xae\x22\x50\x04\x22\x19\xcf\xb4\xac\xe0\x23\xe6\x91\xf9\xe4\x8d\x00\x6e\x9a\x07\xc6\x7d\x24\x68\xf9\x35\x93\xb4\xaf\xc1\x61\xc0\x76\x8b\x6c\xeb\x74\x4c\x24\xc9\x23\xda\x34\xaf\x3d\x5e\xd5\x77\xcc\x7f\x85\xd4\x91\x56\x0f\x4c\x0b\xcb\xcd\x1d\x5e\x34\x21\xbd\x1c\xcf\xaf\xb3\x73\xd6\x51\xbd\x61\xed\x71\xc0\x9e\x99\xf6\x12\x00\x17\x04\xd0\xc6\x30\xd8\x54\x7b\xd9\x70\xb6\x6e\x7f\x5c\xe7\xa0\x14\xe0\xff\x5a\x33\x7d\xc5\xc5\x6a\x99\xf1\x31\xb9\x12\x91\x40\xee\xea\x39\x39\x7c\x48\xca\xa9\xa8\x08\x6f\x9f\xd9\x91\x50\xbe\x7e\xf8\x7b\x6d\x4b\x94\xb1\xbd\x52\x87\x8b\xf3\xbb\xfc\xce\xac\xc2\xcc\x45\xe8\x97\x1c\x3a\x4d\x4a\x3e\xb8\x6a\xf9\x87\x4d\x4f\xa5\xe7\xca\xa7\xf4\x5d\x15\x53\xff\xbb\x41\x64\x5b\xf0\xf5\xe9\xb2\x97\x72\xe3\xdc\x08\x1b\x25\xb5\x2e\x1c\xb7\xe2\x16\x74\x83\xd5\x4f\xba\x69\x0d\xdb\x29\xd5\x46\x2d\x2a\x27\xa3\x5d\x85\xf0\x07\xad\xed\xe2\xa3\xdd\x72\x81\xf6\x54\x33\x6a\xfa\xfb\x73\x70\x78\x2b\x29\xca\xd6\x43\xd9\xd9\xdb\x2f\x05\xf2\x81\xb5\x3e\x13\x3e\xc3\x0e\xec\x09\xfb\x0d\x06\x1b\x74\x58\x1a\x2b\xd2\x79\x0b\x13\x73\x91\xf1\x93\x28\x88\x0f\x64\xc5\x3b\xe7\x00\xd0\xfa\xdd\xb7\x0d\xc1\x65\xd2\xd6\x2e\x67\x1e\xb9\x44\x9a\x2e\x6e\x9d\xf2\xc1\x6d\x8f\x49\xfa\x4b\x5b\x84\x30\x9f\x73\x35\x13\x3d\xbe\x87\x2c\x5a\x8f\xdc\xfb\xc4\x98\x0a\xbf\xb3\xc9\x59\x7d\x5d\x66\x7a\xd2\xf6\x88\xc7\xab\x24\xc9\xe4\x40\x29\x8d\x72\xb2\x8b\x0f\xcd\xe9\xc6\xf0\x71\xbc\xcc\x93\xe8\xdd\xbb\xa7\xb6\x0a\x0b\x54\x4a\x2e\x06\xc3\x9c\x67\x23\xd4\xf7\xdc\x18\x5c\x21\x13\x5f\xd1\x3a\x72\x77\x0b\x97\x61\x19\xe4\x9a\x1f\x81\xed\x47\x6b\xe0\x7c\x44\x3d\xe0\xb0\xee\x76\xfb\xd9\x19\x38\x93\x28\xb3\xeb\x86\x07\xbc\x2f\xe3\x8f\x85\x74\x5e\x28\xad\xb7\x48\x2b\x70\x1c\xcc\x66\x90\xe4\xae\x5a\x93\x32\xea\x44\x61\x31\x79\x38\x7d\xc6\xfc\x47\xc1\xd1\xec\x36\x60\x35\xe9\x91\xe1\x40\x43\x23\xbd\xbb\xf5\x35\xf1\xc3\x3c\xf5\x7b\x67\x23\xf1\x3c\xa6\xca\x32\x9e\x2a\xaa\x4b\x46\xb4\x26\x07\x33\x99\x06\xc7\xef\x49\xb3\x2d\xb8\x2c\xdf\x6a\x87\xad"}, -{{0x21,0x7e,0xcd,0x6a,0x7f,0xcc,0x98,0x71,0x92,0x10,0xc3,0x4c,0xc2,0xe1,0x4f,0x5e,0x2d,0x6b,0x5a,0x22,0xf2,0x68,0xc1,0x4b,0xc4,0xd8,0xa7,0xf2,0x81,0x72,0x00,0xc3,},{0xd5,0x91,0x91,0xce,0x28,0x2d,0x72,0xfe,0x3a,0xc4,0x58,0x78,0xe2,0x4b,0xb2,0xf2,0x8c,0x40,0x9b,0xa0,0x5d,0x76,0xce,0x9b,0xcf,0x22,0xf5,0x0b,0x0c,0x77,0x86,0x75,},{0xa0,0xb1,0x69,0xe8,0xe9,0xce,0x55,0x75,0x55,0xe0,0x33,0x4a,0x0d,0xe7,0x43,0x8e,0x55,0x36,0x75,0x48,0x9e,0xa4,0xba,0x9c,0xc6,0x3a,0x23,0x4d,0x00,0xde,0xd8,0xab,0x69,0x67,0xa3,0xbe,0x90,0xef,0x69,0xe0,0x76,0xdb,0x9e,0xa3,0xd5,0xca,0x23,0xb3,0x24,0x8d,0xd2,0x59,0x91,0xee,0x1f,0x4d,0x80,0x62,0x0b,0xf4,0xdb,0x43,0x8f,0x0e,},"\x9b\x53\x37\xe7\x8f\xb3\x82\xf2\x2e\xa6\x0e\x03\xc0\xbf\x3e\xe4\x70\x0b\x69\x78\xa9\x1e\xe6\xac\xdf\x6a\x40\x9e\x49\x18\xd1\x68\x48\x81\xfa\x1d\x11\x8c\x08\xc9\xf6\xf2\xca\x0c\xab\x56\x74\x02\xc9\x50\x10\xe7\xab\xdf\xe8\x48\xae\x79\xba\x24\x9a\xdc\xb9\x6e\xae\x1d\xfa\x08\x43\x95\x21\x39\xcf\x49\xb5\x88\x64\x78\x95\x69\x1a\x2e\x98\x80\x46\x6b\x7e\x77\xe5\x4f\x6f\x60\x81\x5e\xbf\xd5\xe5\x74\x8f\x41\x3c\x0e\x15\xf9\xd5\x76\x79\x9b\xcf\x31\x28\x47\x10\x63\x6f\x6e\x9d\xc7\x87\x85\x00\x79\x6e\xed\x80\xc8\xaf\x4b\xe2\x96\x19\x52\xea\x80\xbb\xed\x14\x04\xbd\x5d\xae\x9e\x6d\x05\xfd\x4f\x32\x5a\x3b\x83\xcd\x45\x28\xa0\x86\x9c\xef\x84\xb4\xd3\x0e\x02\xf9\x41\xd7\x49\xa8\xda\xc9\x7b\xb3\xfa\x83\x9d\x25\x73\x9b\x97\xec\x37\x45\x36\xbd\xea\x50\x04\x84\xa9\x41\xdb\x9f\x22\x99\x97\x06\x58\xd4\x11\x48\x29\x5c\xa0\x84\x6c\xa2\x36\x62\x38\xb6\x20\x1a\x48\xb3\xe4\x47\xed\xbe\xa7\xa4\xc8\xf7\x10\x20\x14\x27\x69\xe1\x5f\xa7\x2a\xe5\xf2\x87\x14\x0b\xc5\x95\x3b\x8a\x9a\x24\x2d\x20\x5f\xc0\x19\x09\x1f\x2a\xbe\xd0\xfd\xa4\x7f\x52\xd5\x9a\x02\x04\xce\x74\x01\xc1\x82\x9b\x58\x57\xb9\xa0\x91\x6f\xce\xbe\x2e\xef\x99\x1c\x41\x3a\xcd\x71\xb1\x8d\x85\x90\xd6\xb6\xd0\xfb\x39\x94\x30\x26\x78\xc2\x9f\x2b\x6a\x53\x02\x3f\x91\x87\xe4\x6c\x36\x79\x0b\xce\x73\x87\x3c\x54\x5a\x72\xbe\xb5\x53\x29\x4b\x1e\xe5\xd0\xd0\xdf\xf2\x39\xe2\x8e\xc6\x3b\x01\xe4\xd8\xfe\x0d\x6e\x69\xb1\x60\x1e\xfa\x24\x11\xf0\xc0\x60\x1e\x7e\x4f\x65\xc9\x84\xf8\x29\xf0\xdc\x2a\x84\x21\xe7\xf6\x6d\x93\x30\x53\x71\x51\xc7\x24\x3c\xa5\x24\xd7\xa5\x47\x35\xc6\xe3\x44\xf1\xfc\x93\x8e\xae\xea\x27\x79\xc9\x40\x89\x1d\x6d\x01\xaa\x55\xf4\x0c\xc1\xad\xba\x12\xe8\xa6\x7a\xd9\xa2\x7f\xe6\x3f\xb4\xf3\x8d\xc0\xf0\x18\x41\x92\x57\x18\x42\x72\x55\xbd\x66\x5d\x5e\xb3\xbc\x86\x98\x96\xdb\x86\x25\x20\x4a\xd4\xb0\x2f\x5a\x22\xaa\xee\xad\x6e\x30\x04\x71\xfe\xa6\x1d\xbb\x1b\x55\xc0\x71\x36\x5c\x58\xb1\x51\x1f\x38\xb0\x9a\x46\x71\xbd\x66\xb3\xfe\xdd\xa9\xc8\x7e\x43\xd1\xeb\xf3\x01\x76\x4e\x18\xfc\x0c\xf1\x6b\x2d\x2d\x67\xed\x23\x9b\x39\x3a\xc7\x19\x68\xa9\x03\xc0\x24\x77\xfb\x2d\xf9\xef\x01\xdb\xfc\x31\x67\xde\x72\x65\xf8\x91\xe4\xfd\x24\xd0\x2c\x63\x10\x35\x19\xb8\x6a\x70\x85\xb1\xec\x2f\xb4\x19\xdb\x76\x6b\xee\x7a\x64\x1a\x4b\xe4\x29\x61\x4a\xb8\x9f\x20\xf9\x75\x34\x10\x72\xbf\x04\x41\x9f\xb6\x9b\xe7\xa9\xee\x71\xa5\xb4\x9a\xf8\x3e\xd3\x22\xba\xc6\x8a\x42\x9f\xf5\xc5\x20\x67\x73\xbe\x54\x38\xb6\x5e\x53\xf6\x09\x72\x9f\x4f\x6a\x21\xc1\x33\x39\x11\x26\x4d\x63\x92\x70\x17\xe8\x13\x6b\x47\x25\xcd\x1c\xc9\x64\xe0\x8c\xa0\x93\x3a\x56\x1e\x7e\x3f\x59\x87\x76\x83\x30\xe2\xe5\x4f\x8d\x72\x8f\x59\xed\xfe\x2c\x91\xc4\xf9\x9a\xef\x97\xd1\x85\x59\x19\x5a\x3d\x8e\xb3\x15\xdf\xf9\x6f\xe2\x76\xda\x71\x37\xef\xf9\x30\x57\xac\x73\x1e\x06\xa6\x0a\x58\xbd\x8a\x9a\xe8\xc7\xcb\xaf\xf0\xcb\x33\x72\xc6\x8d\xaa\x17\x5c\x42\x8d\x52\xf1\x07\x3a\x38\xbf\x29\x46\x5d\x2a\x71\x28\xbb\x40\x07\x40\x06\xed\xcb\x72\x5a\x83\x1d\x81\x28\x64\xef\x43\xf3\xb8\x66\x7c\x9f\xb7\x10\x93\xa1\x67\x30\x49\xde\xc0\x5e\x09\x16\x9d\x86\xfe\xe9\x2d\xf2\x86\x00\x8a\xd9\x90\x65\xa2\x92\x97\x97\xa9\x13\xd0\x23\x3f\x4d\x1a\x95\xa2\x20\xbd\x91\xc1\x1d\xd9\xc4\x56\x85\xdc\xad\x38\x57\x80\xa0\xc4\x8b\x9c\x4a\xd2\xd6\x63\x03\xe8\xde\x4a\xf1\xdb\x3c\x04\xe4\xa3\xdd\x42\x19\xfe\x77\x3f\x83\xa8\x92\x4b\x0f\xcb\xff\xfc\xf2\x64\xab\xce\x32\x83\x29\x24\x03\x6b\xfa\xbb\xa6\x54\x6b\x1d\xf4\xe3\xf7\x88\xed\x8a\xd5\xc2\xcd\x92\xb2\x64\x1b\x47\x09\x0a\x10\x3c\xf5\xbd\xc4\x6d\x8b\x21\x43\x17\x47\x57\xda\x80\x1c\x36\x0a\x7a\xa1\x07\xfa\xc6\x54\xb3\x4c\x86\x0b\xd5\x4f\x76\xbb\xf4\x3c\x48\x47\x8d\xf4\xfe\x7a\xa5\x9c\xf9\x1d"}, -{{0x08,0xd1,0xd0,0x6f,0x3e,0xc2,0x9e,0xb5,0x22,0x93,0x90,0x7b,0x70,0x5e,0xc5,0x6c,0x5a,0xb3,0x54,0xfb,0x78,0x67,0x37,0x73,0xae,0x61,0x25,0x30,0x94,0xb8,0x9e,0x82,},{0xc1,0xb9,0x9a,0x87,0xad,0x15,0xbd,0x46,0xf6,0xc8,0x48,0x45,0x2a,0xf0,0xfa,0x3c,0xcc,0xcb,0x5c,0xdf,0x6e,0x34,0x8d,0x81,0x6e,0x36,0xc5,0xd0,0xfc,0xa6,0x6e,0x66,},{0x0b,0x8e,0xdc,0xb8,0xb1,0x5a,0x8c,0xd0,0x74,0xc4,0x1d,0xc2,0xa1,0xba,0x29,0xd9,0x64,0x8d,0x6a,0xcb,0xdc,0x33,0x83,0x14,0x70,0x7e,0xca,0x6f,0xb4,0x71,0x4c,0x99,0x54,0x3b,0x49,0x07,0xb9,0xf8,0x5e,0x57,0xee,0xcf,0xfe,0x0f,0x7a,0x6b,0x70,0x73,0xa8,0x09,0x46,0xf8,0x08,0x75,0x53,0xf4,0x68,0x31,0x09,0x27,0x3a,0x60,0x4a,0x08,},"\x12\x0b\x35\x57\x3c\x34\x91\x4b\x37\x30\x51\x88\x0d\xa2\x7e\xd2\x41\x37\x7f\x0e\x78\x97\x2c\x98\xd0\xfa\xeb\xaa\x76\x7e\xb7\xa7\xc7\xe7\xc6\xfc\x34\x05\xa4\x33\x6e\xf9\x5b\xc5\xda\x92\x25\xbb\xd0\x9e\x9e\x11\xf2\xa1\xbf\x14\x2a\xf4\xe8\xa0\xf9\x24\xd3\x23\xdd\x5a\x49\xdf\xe5\x84\xf0\x90\x43\x9c\x08\xe5\x15\x11\x34\x4d\x47\x0c\x62\x00\xac\x7e\x7c\xa1\x50\xd0\x88\xa9\x1e\x47\xc4\xc9\xff\x74\xe3\x8a\x42\xa3\x32\x15\x5d\x81\x52\xae\x4a\xbd\x11\x61\xad\xca\x93\x4c\x23\x4c\xe4\x60\xaf\x87\x89\xe5\x3f\x10\x9d\x7d\x31\xee\xde\x0a\x90\x9b\xd1\x93\xfc\x8d\x3c\x2c\xfe\xc1\x0b\x14\x3c\x31\x47\x67\x11\xbb\xec\x27\xe1\x96\xa5\x49\x85\xbc\x34\x71\x67\xac\xd2\x33\x50\x88\x27\xba\xd3\x6e\x54\x8c\x88\x06\x42\xb8\x6a\x28\xc6\xd3\x40\x4b\x51\x1d\xa2\x4f\x11\xdf\xaf\x6a\x8f\x46\xdd\xcb\xc9\xde\x9e\x39\x15\x97\x66\x9b\xdd\xfc\xa6\x56\x0f\x91\xac\xd3\x45\x9f\x32\x9b\xb0\x71\xdd\x80\xda\xdf\x35\xf0\xe5\x0d\xf5\xb1\x0f\x88\xd2\x67\xac\x9d\x30\x62\x33\x0d\xd9\x9a\x6b\xcf\xa1\x31\x87\xf4\x5c\x0c\x21\x4d\xcd\xe2\xcd\xf9\xc3\xba\x4d\x59\xe6\x33\xa3\x54\xa4\xe2\x77\xc6\x77\xbb\xdf\xa2\x41\x91\x17\x9c\xbc\xaf\x05\xa1\x0d\x40\x78\xd8\xad\xd9\x3b\xc9\xed\x8f\x6c\x6c\x49\x97\x57\x40\x36\x55\x34\x1f\x90\x4e\x37\xd9\x27\x75\x0c\x69\x9c\x26\x9d\xc9\x0d\xc2\x6d\x00\x56\x25\xc3\xf4\x12\x4b\xff\x66\xfe\xca\x59\xd4\xab\xff\x41\x72\xba\x3d\xf4\x5a\x87\x43\x02\x23\x10\x30\xfa\x78\x33\x84\xf5\x09\x99\xe3\xc4\xba\xa5\xea\xdb\x45\x14\x52\xc8\x88\xb5\x19\x27\x2e\x90\xf7\x3c\x68\x72\x76\x8e\x0d\xe2\x0e\xe2\xe5\xf9\x50\x2f\x35\xe4\x9f\xec\xc2\x8b\x75\x20\x18\x87\xfe\xd2\x81\x8e\xff\x54\x53\x98\x39\x2f\x5e\x5b\x68\x76\xbc\x55\x6a\xc1\x3a\x19\x03\xad\xa1\xb9\xd7\x25\xb0\x4a\x14\x20\x4b\x59\x9e\xc3\x3d\x62\xb7\xdc\xae\xea\x8c\x52\x87\x7b\x2c\xfd\xc3\x55\x8a\x91\xd2\xc9\x15\x75\x00\xa3\xbb\x6d\x45\x2e\x5e\x2f\xf0\x93\x29\x4f\xc4\x33\xcb\xd6\x34\x65\xbb\x19\x13\x07\xed\x80\x1a\x15\xb8\x5d\xc2\xff\x0b\xb3\x83\x12\xf8\xb8\x17\xa4\x36\xd4\x22\xcf\x46\x07\xc6\x4e\xe7\x03\x59\x23\xdb\x6b\x96\xa3\x89\x99\x10\x14\x9b\x0d\xa4\xaa\x3e\x96\x68\x5d\x71\x63\xaa\xcf\x9e\x61\x9d\xc6\x08\x13\xce\x4f\x34\x4f\x30\x79\xb4\x3f\x18\x7f\xa3\x1b\xda\xcb\x9a\x1d\x77\x20\xb9\x39\xd5\xbd\x24\x1b\x96\xa1\x77\xd7\xb7\x76\x8f\xfe\xbf\x79\x04\x4c\xd2\x95\x6d\x6f\x88\xdb\x1c\x24\x3a\x10\xfe\xde\x68\x14\x85\x2c\xf4\x04\xb2\xcd\xcf\xa7\x74\x07\x6d\xc1\x25\xc7\x0a\x57\xc6\x90\x7e\x99\xaf\xe3\x96\x22\xae\x11\xf5\x57\xe7\xd3\x4b\x39\xaa\xaf\x45\xf8\x34\x05\x8d\x2f\xe5\xf1\x5b\x5e\xb7\x0a\xc1\x5a\x90\xa3\xde\x58\x50\xab\x1d\xcb\x48\xb0\x6b\x6c\xca\xa4\xb4\x2f\x85\x7e\x71\xec\x00\xb8\xa3\xd8\x97\x4b\x0b\xea\x68\xfa\x0f\x66\x55\x92\x11\x5b\x4f\xa5\x55\x72\xcf\x0b\x07\x38\x64\x1f\xc8\x68\xd4\xa2\xe7\x14\xdb\x3a\xd7\x21\x9a\x82\x3d\x54\xb7\xf7\xc2\x65\x6b\xa5\xc5\xee\xbe\x35\x94\xc7\xdb\x12\x29\x8c\x16\x25\x1d\x98\x45\xbf\x2f\x78\x00\xb4\x19\x0b\x74\x6e\x21\xb0\xc1\xa5\xc4\x7a\x3d\xf9\xa0\x59\xce\x09\x56\x67\x4e\xb7\x03\xde\xcb\x0a\x00\x45\x43\x7d\xa4\xda\x10\xf2\x86\xd7\x20\xd1\xb9\xdf\x05\xfb\x24\x41\x5d\x68\xe0\x65\x57\x0e\x6b\x31\x50\x31\x42\xd0\x33\x35\xa8\x07\xbd\xca\x30\x89\x2e\xdb\x5f\x55\xf8\x98\x9d\x9e\x64\x96\x59\xc0\x74\x4c\x54\x33\xbf\xb4\xde\xeb\x11\xc2\x62\x6a\x86\x50\xe5\x4d\x4d\x39\x8b\xa1\x9b\x64\xf6\x8b\xed\x06\xd7\xfc\x40\x8f\x47\x0a\xc7\x04\xe2\xac\x92\x2a\xc1\x41\x1f\xee\x24\x54\x3e\x56\xf2\xf5\x0b\x6b\x08\x95\x3d\xc5\x6a\x7a\x75\xed\xae\x43\x0a\x6d\xf2\x8a\x22\x7a\xda\xc9\x1b\xa2\x6f\x0e\x19\x85\x95\x32\x77\x39\xcb\xa3\x03\xe9\xaa\x39\x3e\xa6\x61\x8a\x84\xf8\xf5\x03\xd0\x05\x6e\xe8\xd8\x7e\x37\x96\xe0\x36\xcc\x51\xcc\xb7\x91\xde\xb7\x95"}, -{{0xf0,0xc8,0x5c,0x76,0xb1,0x53,0x2e,0x89,0xae,0xa9,0x75,0x15,0x6d,0xdd,0xb1,0xd3,0xd0,0x66,0xf6,0x40,0x9f,0x84,0x1b,0xb4,0x41,0x09,0x22,0x72,0x5f,0x26,0x9d,0x86,},{0xfd,0x75,0xfc,0x75,0xc3,0x6f,0x83,0x49,0x8d,0x8f,0x08,0x27,0xf0,0x1d,0x3b,0x45,0x7f,0x8b,0xc4,0xd9,0xdc,0x55,0xe4,0xa4,0x62,0x74,0xdd,0xf0,0x03,0x4f,0xe1,0x6f,},{0x42,0x18,0xfe,0x4c,0x1d,0xce,0x79,0x5c,0xa9,0x2a,0x49,0xa6,0xf4,0x79,0x8e,0xb5,0x41,0x2d,0xc8,0x25,0x86,0x03,0x14,0xec,0x46,0x9f,0xed,0x45,0xde,0x3a,0x7b,0xf8,0xea,0x55,0xe8,0x53,0xa3,0x49,0x58,0x4b,0xd9,0x5a,0x82,0x6a,0x58,0x5a,0x50,0x3f,0xd5,0x0b,0xfe,0x4c,0x63,0x5e,0xf1,0x83,0xd0,0x73,0x01,0x36,0x7e,0x90,0x10,0x0a,},"\xae\x2e\xb0\x18\xd4\x8d\xbd\x4f\x21\x0b\x16\x77\x8b\x5b\xd2\xfd\x14\xc9\x4e\x6b\xbf\x2b\x3f\xf8\x55\x18\xe5\x60\xab\x8d\x3e\x72\x20\x1f\x43\x34\x20\xf0\x0f\x11\xbc\x78\xe0\xe9\xf3\x72\x08\x75\xb2\xe9\xdc\x11\xe0\x43\x25\xb8\xb3\xf0\xd4\x65\xdd\xab\x21\x51\x1c\x45\x7d\x6a\xca\xd8\xf2\xfd\x5f\xdc\x0d\x28\x23\xfe\x6c\xaa\x66\xa1\x91\xa3\xb6\x32\x6b\x32\xa1\x6b\xef\xd6\x4d\x15\xb3\x61\xa4\x15\x13\x64\x1b\xce\xba\x26\xbf\xe9\x3b\xdf\x85\x4a\x4f\x8f\x8a\x0b\x29\xf7\xe2\x82\x62\xe2\xd6\xe9\x8a\xa2\x4a\xc2\x7f\x6f\x78\x83\xac\x01\xa7\x4c\x40\xcc\xe9\x47\xeb\xac\x70\xe9\xfe\xf2\xa1\x6e\x62\x89\xe4\x68\x95\x0e\x39\x1e\x9e\x24\xef\x58\xe8\x8a\x44\x37\x72\x69\xce\xba\xfe\xd8\x98\x7d\x22\x0d\xca\xe2\xd8\xb1\x26\xb6\xbf\x81\x21\x67\xd0\x23\xd9\xba\xac\x95\x0d\x9d\xb8\xcf\x52\xde\x63\x06\xbd\x48\x99\x96\x10\xc0\xa4\x33\xfa\x9e\x17\x71\xcb\x83\x2d\x41\x97\xaa\x34\x0d\xd0\xcc\xd0\x74\x4f\xc6\xb6\x2f\x90\xbd\x3e\xbb\x53\x08\xca\xb5\xf9\x40\xe2\x91\x64\x23\xcf\x0f\x3b\xf0\x80\xc0\x6a\x94\xf0\x26\x91\x04\x60\xdd\xa8\x09\x37\x4e\x64\x57\xf0\x64\xf1\x78\xe3\x08\xe7\xa1\xb5\xaf\x4d\xef\x31\x90\x07\xd0\x41\x77\x8c\x3d\x6a\x41\x9f\x51\xba\xdf\x87\x66\x38\x79\x30\x2b\x53\xff\x26\x9d\xf4\x42\xd0\xe0\x5c\x95\x8d\x5b\xaa\xcc\xee\xd7\xf5\xf8\xaf\xc8\x11\xc1\x89\x00\xee\x3b\x0f\x61\xe5\xdc\xcf\xd5\xda\xc8\x53\x32\xd3\x2e\xbb\xa3\x71\xaa\x2d\x47\xa6\x06\xf5\x95\x46\xe4\xbb\xb6\x05\xa7\x46\x77\xb1\x9a\x0f\xe8\xe9\x5f\x9f\x77\xc0\xb8\xb7\x1d\x07\xe9\x83\x00\x4d\xc2\xab\x2c\xb3\x79\x3a\x32\x3c\x10\x8d\xfa\x79\x70\xda\x00\xdb\x19\x86\x74\xbd\x34\xbf\x73\x10\x76\x7f\x76\xa2\x24\xe0\x7b\xdb\xc6\x2b\x9d\x07\x8c\xbc\x75\x36\x7e\x2e\xba\xa2\xc5\xd2\x74\xbf\x34\x27\xf2\xa0\xcc\x5d\xbe\xf0\xaf\x4e\x63\xad\x88\x9e\x13\x1b\x12\xbc\x8c\xa3\x2d\x82\x7f\x72\x60\xb0\x44\x9d\x04\x43\xfa\x28\x84\x40\xef\xd1\x36\x4e\x3c\x98\x49\x47\x7e\x73\xee\x0b\xa4\x24\x0d\x49\x2a\xf5\xce\x13\xc3\x45\x61\xb4\x50\x10\xc1\x09\xd8\x42\xc1\xfe\xd1\xbe\x3f\xa9\xe1\x84\xaa\xa1\x40\x64\xf4\x3f\x6d\xea\x0b\x65\x9c\x5b\x97\x89\x3c\xf2\xa4\x33\xbc\xfb\x1d\x2a\x87\xeb\x56\x4b\xd9\x09\x2c\x26\x66\x70\x47\x31\xf8\x3e\x56\x43\x4b\x2a\x42\x99\x65\x0c\x70\x60\xf9\xff\x7e\x8a\xad\xcb\x45\x93\xf6\x09\x18\x8d\x8b\x46\x76\x46\xcf\xe9\x52\x70\x06\x7a\x1d\x35\xcd\x75\x9f\xe5\x81\xaf\x4e\x62\x60\x2c\x02\xef\x14\x74\x41\x43\xeb\x42\x4f\x2d\x9f\x33\xa6\x02\x88\xc1\xb2\x5f\x08\xe4\xb2\xf5\xfe\xae\x06\xcb\xcc\x2b\x20\x52\xbf\x38\x4e\x1a\x6f\xcd\x84\x71\xce\x5e\x56\x58\xd7\x7f\x40\xc3\x5c\x41\x5e\x2a\x9e\x09\xfb\x58\x3b\xb7\x47\x12\x58\xe7\xc8\x06\xf3\xc2\x18\x22\xdd\x10\xf5\x6a\x64\x0c\xdc\x00\x12\x8d\x3b\xa5\x56\xba\x51\xdc\xaa\xb4\x7c\x3b\xaf\x9f\x01\x97\xd3\x66\x3d\xe8\xd0\x93\xe8\x31\x73\x32\x5d\xef\x1e\x83\xa2\xf5\xf5\xac\xf1\x2a\xe0\x9f\x3c\xe9\x6c\xd8\x88\x03\x4d\xcb\xe6\x14\x7d\xc5\x99\x83\x62\xa4\xbc\x40\x6d\x28\x84\x6a\xb1\x50\x3c\x17\xc9\x4f\x9a\xfd\x90\x3c\x9a\x58\xe1\xce\xbb\x4a\xbb\x4f\xf6\xf2\xa4\x10\x24\xe0\x6d\xca\xad\x14\xf5\xb7\x0c\x1b\x26\xe6\x9f\x96\xec\xf1\x4b\x8d\xa3\x1c\x62\x1f\x9a\xd4\xe3\x0a\xeb\x98\x23\x78\x67\x1f\x7d\x1f\x2c\x4b\x57\x2c\x41\xbb\x88\x30\x84\x0a\xc5\xdd\xce\xd8\x81\xf8\xff\xf2\x10\xc3\xc7\xf2\x36\xd8\xc5\xf2\xcf\xda\xcd\xa2\x98\x93\x30\x2f\xde\x15\x28\x2d\xb5\x40\xcb\x54\x37\x37\xdd\x77\x85\x25\x69\x22\x1f\xdd\xcd\xd6\x8d\x87\xe2\x40\x21\x79\xd3\xa5\xa7\x77\x34\xc2\x75\xa1\xd5\x60\xa4\x62\xf4\x03\x18\xbb\x68\x19\x83\x7d\xa3\xd3\x05\xeb\x49\xb3\x86\x50\xef\xdc\x8f\xe4\x09\xd4\x0f\xb9\x4c\xd5\xdc\x3e\xb0\x27\x38\xf3\x88\x52\xf6\x71\xa0\xc4\x14\x14\xb7\x6f\xb4\x36\xf3\x41\x7b\x8e\xf3\x00\x92\x1c\x00\x9e\xbb\xd7\xcf\x8e\x11"}, -{{0x18,0xe2,0x68,0xb1,0x5a,0x25,0x01,0xdd,0x4c,0x97,0x9d,0xc1,0x03,0xca,0x6a,0x84,0x22,0x16,0x13,0x2b,0x3b,0x50,0x81,0xd7,0x75,0xf8,0x86,0x40,0xf8,0x9c,0x80,0x41,},{0xb3,0x4e,0x19,0xc1,0xe2,0x08,0xfb,0x48,0xa8,0x85,0x07,0x9d,0x9f,0xbf,0x37,0xc7,0x4f,0x92,0x71,0x09,0x60,0xf8,0x32,0x15,0x4f,0xab,0x18,0x57,0x0c,0xfb,0x4c,0x1d,},{0xf2,0xdc,0xfc,0x06,0xef,0x1d,0x8e,0xcc,0xd8,0xe4,0x0b,0xdf,0x01,0x30,0x7d,0xd1,0x96,0x83,0xf2,0x14,0xd4,0xf0,0x84,0xe6,0xb6,0x93,0x4f,0x63,0x72,0x78,0x30,0x0d,0xbb,0x18,0x89,0xf2,0xd3,0x7f,0x53,0xb3,0xae,0xf2,0x6f,0xbb,0x3e,0x36,0xbd,0x75,0x98,0x5f,0xa7,0xc8,0xea,0x6d,0xdf,0xfa,0x72,0xc8,0xe4,0x06,0xf2,0x4b,0xb2,0x0e,},"\x42\x4b\xdc\xf0\xb2\x56\x00\x14\x39\xd1\x69\x58\xff\xf6\x48\xcf\x7a\x86\x04\xaf\x22\xcf\xa5\xb4\x43\x31\xb4\xdc\x35\x6d\xff\x25\xcc\x05\x63\xda\x9d\x64\x01\x33\xac\xb7\x0b\x6a\x11\x76\xc4\x82\xdb\xc9\x40\x8c\xd6\x79\x3d\x56\xbc\x29\xcc\x40\x88\x23\xd3\x88\xed\x88\xb2\x4c\xeb\x66\x21\xdb\xac\x00\x23\xee\x69\xf7\x6f\x82\x96\xa7\x39\x52\x11\x68\x5b\x3c\xea\xa9\x95\xf0\x35\x5d\x9a\xad\x3d\x97\x35\x8f\x4a\x37\x9e\x59\x20\xec\x54\x5f\x46\x96\x21\xcf\x76\x8a\xbf\x55\xd2\xa5\x54\xc9\x49\xb0\xed\x70\x18\x7c\x22\x05\xad\x03\x29\x85\xc9\xb5\xb2\xe4\xba\x57\xe0\xb4\xa4\x7d\x34\x45\x12\xb8\x4b\xfe\x9f\x3a\xa5\x60\xfe\x6e\xcf\xc5\xbd\xf8\xc3\xb4\x18\x45\x29\x35\x73\xf8\x1e\xd3\xb7\x0e\xdc\x63\xa3\x0c\x70\xcd\xa3\xf4\x55\x90\x13\x13\xf6\xd2\x3d\xb3\x09\x47\x8f\x03\xe3\x4e\x71\x35\x6d\x83\xfa\x5d\xb9\x28\x0c\xc2\xb4\x36\x9c\x3d\x24\xdd\x90\x38\xf2\x47\x59\x6c\x39\x1e\x48\xb2\xf3\xf8\x90\xa1\x41\xca\x1d\x12\x07\x7c\x69\x34\x47\x35\xa5\x9b\x1d\xd4\x07\x6b\x22\xe1\x61\x89\x99\x1e\x5f\x1b\xe4\xfb\x76\x95\xaf\x90\xeb\xea\x5d\xf2\x86\x13\x5c\xec\x2a\x6e\x99\xaa\x1d\xda\x32\x8e\x62\xc0\xdf\xb6\x37\x42\x20\x2d\x63\x62\x4d\xcc\x0c\x5c\xf1\xa5\xdf\x79\xe2\x87\x8d\xbc\x71\xfa\x96\x57\x66\x01\xaf\x22\x84\x4f\x54\x57\x33\x12\x6a\xf7\xd3\x98\x4c\x3e\xd2\x52\xe6\xa8\x76\x44\x5c\x92\x25\x9f\xbb\x47\x0a\x10\x56\x9b\x49\xe5\x79\x1f\xd0\x18\x2c\xfe\x1c\x3f\x88\x29\x7f\xac\xc8\xc3\x1a\x53\x32\xf1\xf4\xeb\x49\x58\xdb\x13\xb6\xc0\x79\xaa\x9c\x94\x94\x87\x26\x34\x03\x19\x0c\x83\xc1\x1a\x43\x19\x1f\xfe\xc6\x02\x3f\xb3\x4c\xfa\xb2\x52\x5b\xeb\x54\x6c\xf9\x20\x0a\x96\xf5\x85\x4b\x2f\x78\xec\xb2\xd9\xa5\x3a\xa9\xd2\x87\xa9\x0d\x4d\x41\x0a\x63\xad\xa0\xe9\x75\xd3\x04\xd5\x14\x83\x53\x46\x3f\xa8\x05\xb4\x80\x5f\xb4\x68\x7e\xd8\x85\x7d\xfc\xe4\xbc\x6e\x80\x83\x3c\x8f\x9a\x79\xcd\x4f\x02\x9a\x2d\x80\x2b\xfd\xc8\x19\xed\x0c\x0a\xc8\xf2\x10\x23\x28\x7f\x2b\x4b\xaf\xbc\xc8\x99\x93\xfe\x46\xd5\x2a\x9c\x62\x46\xde\xad\x61\x7d\xf7\x97\xd4\x8e\xe9\x85\xf0\xf0\xdf\x9a\xa8\x2e\xa2\x0e\x0d\x0d\xb2\x8a\x25\x4a\x9a\x25\x3f\x39\xf9\xcf\x01\xe3\xdb\x8f\x3e\xbc\xf7\xcb\x97\xce\xc5\x8c\x4e\xfe\x03\x12\x69\xb4\xb3\x7e\x4c\xbb\x36\x1f\x73\xab\x4b\x49\x80\xbd\x90\x08\x49\x53\x88\x44\xc5\x2c\xb3\xac\x75\x83\xb8\xf8\x96\x53\xa0\xde\x65\xa8\xbe\x91\x58\x2c\x55\x23\x9c\xb8\xf5\xd5\x31\x8a\x88\xd1\x60\xe1\xc8\x71\xe5\xea\x7e\x75\xf5\xa6\x9c\xba\x85\x38\x22\x1a\xb4\x2c\xe2\xa2\xc4\xd9\xc3\xb7\xec\x85\x7f\x23\x0d\x57\x37\x31\x13\x36\x86\xae\x8a\x7e\xd6\x40\xf4\x2f\x31\x02\x94\x89\xe4\xe6\xaf\x2b\x3e\xa4\xc7\x94\x8e\xd5\x37\xc0\xc5\x90\x67\x26\xc2\xb6\x25\xfd\x5f\x94\x9e\x3a\x7c\xf3\xb6\xe9\x98\xec\x76\x1d\xd6\xe2\xb5\x17\x1a\x68\x74\x97\x52\xe7\x21\xb7\x88\xc3\x47\x7f\xa1\x90\xcd\x6e\xa8\x1d\x57\x9d\xce\x64\x62\xd9\xc6\x62\xad\x89\x62\xe7\x93\x38\x71\x0c\xc8\xd2\x73\x8a\x5f\xb0\x4a\xdf\xdb\x3f\x14\x32\xcf\xd8\x0e\x2e\x96\x7d\xa0\x00\xd8\x3a\x0f\xa8\x5a\xba\xe2\x95\x2f\x3f\x36\x83\xe2\x54\xd8\x68\xf4\xbf\x80\x9e\xb2\xe3\x00\xe7\xb2\x09\x73\x4a\x3c\x89\x4e\x96\x6b\x16\x08\x8d\x5e\xd3\x54\xbf\xfb\xff\xbb\xf2\xec\x2b\xe9\x3a\x32\xa8\xbe\x5c\xfa\x18\xfa\x56\x53\x01\x2e\xda\xe5\xaf\xd8\x70\x9c\xa5\x5c\x0c\xf2\x3a\x55\x0d\x34\xca\x0f\x32\xd8\xf6\x66\xfb\x47\xa1\x2f\x2b\x73\x53\xa4\x0c\x53\x79\xf7\x53\x66\xc1\x3f\x4a\xb9\xf1\x4c\xf8\x0a\x94\xe1\xf1\x3d\x8b\x09\xb7\x6f\xd8\xd1\x4f\xfa\x53\x8f\x31\xfd\x8a\xeb\x49\xd3\x34\x33\xf4\xdf\x7c\x2c\xa6\x73\x99\x57\x9f\xe9\x90\x78\xaa\x72\x1d\x6b\x6f\xc0\xc5\x0e\x8a\x91\xfc\x71\xca\x25\xea\xc1\x37\x6f\xc6\x71\xbf\x61\x53\xe7\x20\xb2\x5c\x7e\x97\xa3\xd4\xef\x84\x42\xac\x67\xac\xf5\x8b\x50\x4b\x67\x15\x8f\x91\x30\x25"}, -{{0x3c,0x39,0x3f,0x9d,0xf1,0xfb,0x0b,0x1e,0xec,0x09,0xb7,0xf2,0x70,0xb8,0x59,0x82,0xba,0x0f,0xd5,0xe4,0xb1,0x79,0x5e,0x1a,0x7f,0xa9,0x91,0x37,0xfe,0xe2,0x4d,0x7d,},{0x97,0x4f,0xe2,0x37,0x30,0xfc,0x17,0x94,0x56,0x70,0xfb,0xc1,0xf8,0x0b,0x93,0xf9,0x45,0x93,0xc8,0xd4,0x4b,0xc7,0x5d,0x18,0x9a,0x6b,0xbf,0xaa,0xba,0xf5,0xdb,0xd9,},{0x22,0x33,0x3e,0x56,0x41,0x0f,0xdc,0xbf,0x84,0xf6,0xa8,0xde,0x74,0x13,0x37,0x69,0x16,0x84,0x49,0x5b,0xa6,0x9e,0xff,0x59,0x6d,0xb9,0xc0,0x3a,0x28,0x12,0x10,0x88,0x1e,0x6c,0x91,0xef,0xa9,0x1b,0x21,0x83,0xc0,0xea,0xc9,0x16,0x15,0x28,0x17,0xa7,0x8c,0xa7,0x24,0xba,0x7c,0x8b,0x51,0xbb,0x4c,0xaa,0xde,0xa9,0xa3,0x41,0xeb,0x0e,},"\x54\xd8\xb8\xd5\xfa\xc2\x8c\xff\xa7\x7a\x09\x16\xd6\x33\x3c\x16\xed\xbc\x8b\xb7\x4a\xa0\x6e\x56\xdc\x00\xe4\x7e\x39\x29\xe4\x08\x64\xb8\x84\x0d\x91\x20\x79\x59\x7e\xac\xd8\x1d\xae\x43\xe2\x78\x5d\xfc\x68\x9f\x3e\x85\xf8\xc6\x65\x81\xef\xc5\xe8\x53\xd1\xfa\xaa\xc7\x44\x40\x0a\xb0\x8c\xbd\xb5\xd1\x61\x46\xfa\x60\xf9\x99\x05\xed\x84\xfd\x29\x36\xdd\x73\xf4\xbc\xa2\x57\x2b\x7c\xf5\x16\x05\x60\xff\xaa\x68\xda\x7a\x67\xe4\x0e\x08\xa7\xbb\x7a\xef\xc4\x04\x3e\xbe\xd5\xfe\x80\xa4\x14\x81\x7e\xdf\x2c\x63\xf6\x2f\xac\x0d\x47\x44\x6e\xd0\xbb\x58\x40\x58\xf4\x87\x2f\xec\xff\x62\x15\x59\x31\x1a\x27\x0a\xea\x37\xa6\x29\x68\x64\xe8\xd1\x68\xbf\x1e\x2f\x55\xcd\x3b\x27\x6e\xdf\xa6\x12\xb5\xd9\xc3\x36\x2e\x61\x8b\xe6\xe8\x2a\x6e\x5f\x82\x66\x79\x24\xf3\xd1\xd3\xdf\x82\x5f\x9d\x23\xf4\xd6\x14\x2d\x31\x00\xdf\xc7\x0f\x70\x60\x3a\xbf\x3f\xda\xda\xca\x69\xef\x6a\x18\xef\x90\x92\xb3\xc4\x1e\xc6\x58\xab\x27\x21\x6f\xc6\x14\x7a\x08\x0a\xcd\xa6\x0a\x84\x19\x84\xee\x83\xf4\x1a\xc4\x2a\x80\xea\xac\x91\xff\xfc\x82\x28\x39\x1e\xf5\x83\xab\x3e\xdd\xcf\x87\x65\x23\xc2\x02\x81\x35\x53\x00\xd8\x6c\x11\xa4\xe7\xc1\xad\xe8\xe5\x05\x60\xf4\x39\x06\xc9\xbc\x8c\xa5\xfb\xf8\x33\x9f\xbe\xbd\x02\xe3\x3e\x85\x18\xbe\xe5\xe8\x06\xb8\xc1\x0f\x82\x77\xf4\x10\x66\x47\x35\xa2\xbf\x55\x68\x39\x63\x54\x92\x45\x2e\x6c\xa0\x79\xde\xb9\x75\x1c\xfc\x67\x97\xf4\x9b\xca\x96\x13\xff\x2e\x7f\xdd\x36\x46\xf7\xc5\x23\x6a\x36\xbd\xf0\x05\x17\x45\xe5\x95\xdc\x00\x72\xfd\x66\x51\xd5\x76\x27\xa6\x00\x4c\x0f\x0c\xfa\xe8\x56\xbb\xc2\x8a\x12\x31\xcb\x83\x96\x65\xff\x04\x15\x2e\xc3\x1c\x00\x7b\x3e\x2e\xd0\xa9\x73\xb2\x4c\x93\x14\x9c\xe7\x01\xe6\xfd\x65\x39\x20\x6a\xe9\x1b\xec\x4c\xe6\x5a\x89\xdb\x26\xc7\xd3\x8c\xec\xb8\x91\x9f\x96\xfb\x6c\xb8\xf6\xc1\x93\x9d\x90\xfb\x3f\x90\xb8\x87\x78\x9f\x29\x57\x5a\xb2\x0e\x0b\x08\xbc\x35\x81\x53\xd8\xc0\x35\x21\xdc\x89\x18\x70\xb5\xf7\xee\xdc\xc1\xe6\x2b\xee\x7d\xa0\x63\xae\x66\xff\x0a\x4b\x7d\x98\xd1\xcb\x75\x8f\x69\x74\x3c\x3d\xb3\xae\x2a\x2c\x9b\xe1\xbe\x09\x4f\x17\xcd\x28\xf9\x2d\x8c\xcb\xca\x98\x3c\x74\x9c\x75\xc6\x10\xf8\x40\x83\x6e\x2c\x43\x0c\xcd\xef\xf0\xaf\xa5\x44\x44\xf1\x2b\x4a\x4f\x00\x2c\x60\x94\x51\x83\x42\x44\xc0\xc0\x7d\xf8\xe1\x22\x02\xa6\x5f\x94\x44\x7c\xd4\x90\x3a\xcb\x60\x6d\x77\x25\xa8\x6e\x4a\x23\x43\x98\x4e\x67\x9c\x4a\xf1\xb3\x67\x9c\x75\x5e\xa5\x0d\x0a\xbe\x2f\xcc\x0c\x1c\x33\x51\xa9\xee\x19\x6b\x46\x44\xc4\x24\x22\x2b\xe9\x9e\x2f\xb3\x73\xf9\x64\x1e\x3f\xae\xbf\xf4\x31\x70\xeb\x03\xfb\x8e\xc4\x55\x7d\x15\x1a\x55\xfa\xb6\xc4\x99\xd4\x44\xc8\x4b\xe8\x9f\x24\x47\x68\x2d\xe4\xe6\xf6\x35\x34\x75\xef\xcb\x8f\xc5\x32\x56\x76\x3a\x94\x8d\xc7\x5c\x51\x5f\xa3\x53\x54\x5d\x0c\xba\xd2\x9d\xf5\xe9\xdb\x5c\xc4\x57\xed\x30\x86\xcf\xfb\x3d\x75\xe8\x46\xc4\xe8\xd8\x81\x47\xfc\xd0\xd8\xaa\x5a\xba\xb4\x9b\x5e\x05\xc3\xd7\xfe\xef\x63\x79\x43\x34\x7a\xd3\xf4\x92\xee\x35\x6e\xf3\x48\x81\xcf\xd8\x5a\xbc\xe8\xa1\x44\xce\x77\x61\xe2\x84\xe8\xb8\xcb\x08\x96\x60\x49\x04\x7a\x99\x6e\x23\x55\x9f\x77\x6b\x1a\x9f\x41\xcb\xa3\x95\x41\x08\x48\x6e\x29\x27\xbe\xb6\x43\x3a\x36\xff\x8b\x2f\x03\xaa\x74\xb3\xd2\x09\xc4\x88\xe0\x77\xf9\x24\xf2\x31\xe2\x83\x45\x94\x2c\x7d\xcc\x2e\x61\xd7\xc9\xb5\x22\xb6\x59\xfc\xb5\x36\x62\xaf\xf3\x64\x8f\x66\xda\x3e\x83\xe5\x9b\x0d\xaa\x90\xb9\x4c\x51\x5d\xad\xab\x10\xd5\xa8\x39\xcb\x3a\x2f\x1d\x3c\xd0\x92\xde\x55\xd9\x95\x13\x8c\x3a\xc0\xb9\x07\xaf\x15\xac\x63\xec\x18\x74\x11\x43\x27\xe2\x19\x71\x34\x5e\xf1\x70\x31\xd5\x26\x17\xe7\x84\xda\x37\x71\x43\x9b\xe2\xe8\x41\x48\xbc\xfe\xa1\x32\xbd\xe1\x0e\x6f\xda\x54\x7d\xcb\xb1\xc4\xd8\xf7\x4d\xdc\xe1\xfc\xcf\x82\x13\xe0\xda\x6e\x97\xb8\x1f\x75"}, -{{0xf8,0x66,0x9c,0x88,0xf1,0x68,0x5b,0xbf,0x04,0x80,0xcc,0x92,0x21,0xac,0x2e,0xad,0x8f,0x55,0x1b,0xfa,0x87,0xec,0xba,0x2f,0xd4,0xdd,0xf3,0xba,0x34,0x76,0xeb,0xda,},{0x34,0x72,0x3f,0xb8,0xe2,0x53,0xad,0x9c,0x71,0xce,0xfd,0xe0,0x36,0x28,0xd2,0x04,0xe5,0x35,0xde,0x47,0x9e,0x10,0x48,0xe5,0x18,0x87,0x62,0xa1,0xf3,0x37,0xfe,0x5f,},{0x37,0x46,0xda,0x6c,0xd8,0xca,0x10,0x8b,0xee,0xf0,0x64,0x87,0xbe,0xe6,0x35,0x84,0xf8,0x12,0xc8,0xe0,0x69,0x5f,0xc8,0x63,0xb8,0x6e,0x5d,0xb1,0x32,0x38,0x0b,0x62,0xff,0x85,0x44,0xf6,0xf3,0x74,0x82,0x5b,0x0e,0x3e,0xa0,0x62,0x0e,0xf8,0x54,0xc1,0x33,0x11,0x14,0xd6,0x67,0xdf,0x1f,0x9e,0xa7,0x76,0xc3,0x96,0x38,0x70,0x29,0x0d,},"\x5b\x49\x41\xbe\xec\x22\x41\xc9\xfb\x76\xd8\x48\x4f\x4f\x3f\x3a\xb4\xff\xe8\xec\xc8\xe7\xae\xc7\x6d\xe2\xab\x8c\x36\x85\x84\xd7\x51\xb0\xd3\xfe\xb8\xa1\xdc\x81\x68\xcd\xc6\x94\x96\x8f\x66\xb2\xa0\xb0\x52\xaf\xbf\x8b\xe3\xa7\xd9\x51\x63\xe9\xda\x91\x41\xc5\x9c\xa5\x59\x76\xc2\x92\xc5\xc7\x4d\x31\x31\x8d\x6a\x91\xe7\x81\x7c\x5a\x8b\x2f\x81\x21\x18\xcb\xeb\xa3\xa1\x33\x23\xcd\x97\x48\xbf\x86\xed\x1a\x85\xdd\x4e\xbc\x0d\xf4\x95\xcf\xa3\xd4\x62\x74\x34\xbf\x14\xaa\xe8\xab\x67\x81\x46\x7a\x56\xd9\x65\xd1\x0e\x63\x71\x98\x9d\xfa\x0f\x6b\xc0\xf7\x85\x9f\x37\x71\xeb\x90\x04\xb3\x43\x67\xdb\x27\x05\xdb\xd6\x0f\xa8\xf7\x89\x5c\x1e\xad\xf5\x9f\x53\xda\xb1\x68\xb4\xf9\x36\x39\x79\x02\x55\x01\xdd\xd9\x68\x0d\xeb\xc0\x7c\xd1\xca\x4a\x09\x97\x87\x6e\x92\x11\xf3\x07\xd9\xb7\xb9\xd9\x04\xe4\x8d\x28\x61\xa7\x78\xb8\x79\xad\x59\x0a\x9a\x2f\x14\x1b\xd5\x68\xe3\xa1\xbb\x24\x94\x62\x8e\x9e\xc0\xc6\x42\x55\xae\xea\x6f\x0e\xed\xca\x30\xad\x38\xa1\xf3\xff\xec\x3b\x2b\x5e\x94\x2e\x21\x94\x01\x04\xe9\x14\xd1\x1a\x44\xc0\x0f\xdd\x47\xda\x3e\x55\x13\xaa\x85\x30\xae\xe2\x47\xc9\x5c\xa6\x6d\x08\xa2\x60\x8c\x75\xba\x98\x58\xda\x14\xf9\xa8\xa3\x2b\xe7\x13\xd3\x09\xe0\xf5\x84\xc8\x1e\xf5\xbe\x04\x0e\x00\x65\xf0\x7b\x77\x5a\xe1\x75\xdf\xe2\xc8\xb9\x0a\x88\xcc\xda\x17\xfa\x4f\x21\xc7\x7e\xad\xf5\xd2\x5b\x6e\x40\x4b\xf0\x04\x47\x9e\x05\xa0\x1a\xc0\x04\x2b\x89\x93\x7e\xb2\x78\xc1\xc3\x4f\x33\x02\x8d\xb7\x80\xba\x3b\x61\x79\x18\x59\x5a\x39\xc0\xfc\xad\x67\x4b\x85\xc4\x0c\xac\x8d\x34\x5b\x7c\xa0\xbb\x48\xa2\x8e\x66\xc4\x4d\x8b\xb5\xf2\x79\x41\xe4\x0b\x0e\x9c\x70\x97\x97\x6c\x62\xdf\xef\x50\xc9\x8f\x17\x56\x6c\xcb\xac\xc8\x7c\xb0\x3b\x94\xdf\xdf\xaf\x32\xf1\xe5\x6f\xfa\x63\x9d\x63\x61\x1e\x21\x3c\xeb\xf5\x4c\xd0\xa3\xe2\x17\x2d\x81\x1c\x0e\xbd\x75\xb1\xa8\x64\x62\x64\xdd\x8b\x1a\xbd\x46\xe5\x48\x97\x2a\x1b\x26\x2c\xd9\x5d\x51\x15\x36\xdd\xdc\xb4\x97\x29\xfe\x7b\xd0\x0b\x38\x38\xbd\x2f\x20\xa1\x42\x64\x0e\xdb\x1b\x6e\x76\x5b\x65\xda\x72\xe7\x23\x32\x61\xc8\x89\x2e\x2f\x49\x49\xbb\x51\xf3\x2a\x1a\x5a\x3e\xe1\x49\xbe\xa2\x6f\xdc\xed\xb9\x91\xd2\xcd\x12\x66\x37\xe2\x97\x1e\x9b\x6f\x0b\x78\x5d\xf2\x8a\x48\xf3\x01\x70\x73\x49\x42\x3f\x44\xe8\x46\x22\x89\xd7\x25\x49\x82\x30\x48\x9d\xf1\xb5\x1b\xe3\x0f\x08\xd7\xe3\x25\x05\x65\xc6\xef\x82\x4b\xc5\x3a\x1b\xa7\x4a\x57\xa2\x5c\x06\x86\xad\xcb\x6c\x82\x5a\xb1\xca\x70\xc8\xa5\xd4\x6d\xbb\xc6\xfa\x60\x74\x61\xe2\x6d\x16\xfe\x93\xbb\x3d\x3a\x94\x3a\x3d\xc0\x5f\x30\xea\x6d\xc8\xbb\x12\xd7\x08\x21\xd3\x20\xf1\xad\xf1\xce\xba\x4b\xe6\x57\x19\x4f\x7f\xcc\xd2\x19\x90\xf8\x62\x9d\x74\x46\x01\xcf\x52\xea\x6d\x94\x05\xaa\xa2\x87\x8f\x1e\xec\x40\x03\xb4\x5a\x42\x18\xd8\xf8\x0b\xb0\xf5\xaf\x04\x73\x26\x48\x77\x52\xe2\xb7\x6d\x68\x87\x25\x20\xbb\xea\xe7\xb3\x09\xd7\x82\x82\xa0\x73\xfe\x0b\x1a\x1a\x7a\x98\xda\x23\xdf\x68\xca\xf8\xc2\x69\x9b\x1c\x7d\x0f\x47\xbd\x7d\xe2\xc0\xbb\x23\x36\x99\x63\xe6\x8a\x69\x74\xc8\xe2\xb5\x95\xb8\x29\x3a\x9f\x4d\x98\xdf\x7e\x9a\xe3\xad\xd2\xa3\xf6\x4e\x83\x03\x97\x39\x64\x2d\x19\x22\x04\xe8\x5e\x6c\x48\xd5\xd6\x71\xf6\xc7\x5a\x0a\x89\x57\xed\xbb\x74\x18\x76\x20\xf2\xab\xa9\x9c\x1c\x62\x58\x4c\x59\xac\x00\x64\x7e\x3f\xb4\x02\x92\xb9\xdc\x1a\x33\x46\x86\x85\x53\x39\x2f\xd3\xf1\x1d\x6d\xc6\xf5\xf2\xf4\xe8\x5e\xe2\x51\x25\xcd\xd6\x44\x74\x3c\x7d\x45\x28\x1e\xda\xc6\x38\x4c\x77\xcb\x98\xa6\x7d\x9a\xe6\xfc\x9a\x0a\x76\xb9\xf6\xfa\x69\x6f\xdf\x4a\xce\xab\x5f\x79\x4e\xe5\x21\xb1\xe5\xa0\xee\x57\xaf\x53\xbd\xf1\x76\x80\x1b\x4f\x45\xcf\xb3\xca\xe3\x28\x72\x34\x23\x4b\x77\xce\x21\xed\xf8\x68\x0d\x68\xc4\xa8\xee\xcf\x1b\x03\x53\x7e\xa5\x69\x9a\xcb\x56\x27\x77\xe4\x2a\x48\x6f\xe7\xcd"}, -{{0xce,0xcc,0xc6,0x83,0x11,0xfc,0x45,0xb6,0xc2,0xa2,0xf1,0xff,0x9c,0xdd,0xe0,0x07,0xec,0x78,0x7f,0xdf,0x25,0xd0,0x2c,0xcd,0x2a,0x1c,0xad,0x9d,0xe3,0xfb,0x4c,0xff,},{0x6f,0x80,0x47,0x34,0xef,0x92,0x82,0x41,0x80,0xda,0x71,0xe5,0x5c,0xf3,0xbf,0x1a,0xfe,0xf6,0x5b,0xcf,0x56,0x09,0x62,0xe0,0xb0,0xac,0xbb,0x2d,0x8c,0xca,0x59,0x84,},{0x3c,0x44,0x62,0xaa,0x47,0x01,0x01,0x32,0xdb,0xb2,0x63,0x11,0xe4,0x44,0x72,0x72,0x79,0xed,0xad,0xe1,0x5a,0x4d,0x66,0x2c,0xf6,0x47,0xf3,0x27,0x5c,0xf3,0x25,0x3e,0x6d,0xe9,0x33,0x38,0x30,0xe0,0x51,0x7a,0xa5,0xfa,0x7b,0xc2,0xd0,0xe6,0x3e,0xa2,0x59,0x7a,0x94,0xb0,0xfe,0x92,0x70,0x6e,0xcd,0x17,0x2c,0x5e,0xc5,0xc7,0xf0,0x06,},"\xba\xc1\x86\xd9\xfe\x5a\xbd\xa7\x9c\x3a\x35\xa7\xa3\xc2\xea\xe6\xae\x6a\xb2\x82\x47\x91\x27\x70\xc8\x4e\xfd\x04\x8e\xbd\x3a\xba\x57\xc3\x7c\xf4\xc6\xc7\xf3\x0a\x79\xf6\x8a\x3f\x76\xb2\x0c\xd8\xc6\x63\x1f\xcc\x96\x67\x05\x22\x08\x0e\x6b\x62\xe8\x87\xae\x6f\x44\x36\xd4\xca\xf5\x69\x43\x13\x1c\x52\xdd\x28\x2b\x25\x1c\xd0\x75\xf1\xf7\xf8\xe0\xbd\xb6\xbe\xdf\xc9\xa0\x79\x6f\x55\x79\x04\x2b\x56\xe6\x93\x74\x96\x1b\x11\xdf\xd6\x1b\x12\xde\x2b\xb7\xd4\x9b\xfc\x50\x9c\xdb\x31\x38\xf3\x35\x6a\x0d\xde\xd9\x8f\x53\x01\xb7\xc4\xa7\x48\xbf\x89\xb2\x3d\xf4\xf7\x47\x2f\xf8\xb1\xf5\x05\xd7\x65\xc6\xff\x82\xdb\xad\x74\xb9\xd7\xae\xf2\x2f\xbc\xca\x0b\x7f\x35\x04\x2f\x9a\x76\x2b\xd0\x69\x02\xbb\x21\xc7\xf9\xf7\xf6\x6b\xef\x38\x90\x1d\x75\x01\x2d\x61\xd7\x44\xde\xe7\xaf\xd8\x9f\xc7\xe9\x08\xc4\x06\x85\xbd\x44\x0a\xed\xa4\x20\x4d\x00\x6f\x26\x30\x7d\x82\xa4\x96\x96\x31\x15\xf9\x0e\x09\xf7\x66\x88\x29\x1f\x4a\x67\xd6\x41\x1f\x76\xd1\x66\x17\x87\x5b\x2b\x99\x82\xdf\xdc\x5e\xe9\xb8\x3b\x98\x17\x00\x93\x19\x11\x0b\x54\x04\xc6\x31\x16\xfb\x6e\x94\x64\x84\x6f\xa0\x09\x55\x56\x32\xf0\x76\x98\x4c\x15\xe1\xf6\x08\x17\x33\xa0\xd4\x6f\x2d\x6a\x3c\xeb\xf7\x9e\xd9\x02\x0c\x9d\xec\x8d\xf1\x58\xa3\x34\x1f\x39\xea\xa5\xfc\xf1\xcf\x42\xa9\x48\x49\xb2\x35\x2c\x1a\x1e\xcd\x4f\xb8\x14\xc2\x0d\x07\xdf\xda\x31\x2b\xd4\xf2\xf5\x8c\x15\x76\xb4\xaa\x31\x5c\x96\xc8\x78\x6a\x4c\xfb\xb7\x36\xb2\xd2\x3c\x38\xb1\xd8\x1c\x46\x44\xea\x36\xaf\xa0\x76\xe0\x55\xbe\x59\x17\xcd\x7a\x92\x35\x0a\x7e\xd6\x6a\x5a\xb2\x25\x3f\x55\xc4\xfd\x1a\x0d\x0e\x6d\x4e\xda\xb5\xf7\x12\xed\xb4\x40\xc0\x6f\xac\x8f\x07\xe6\xd7\x3c\xc9\x0b\x2b\xa7\x13\xd7\x3c\x73\x80\x23\x61\xce\x46\xa4\xeb\x5e\xd1\x06\x0c\x4c\xf5\x32\x07\xd3\x01\xf0\xfc\xd4\xf0\xc9\xd1\x58\x0d\xb2\xfc\x10\x59\xd3\x72\x07\x64\x38\xa0\x11\x92\xa7\xf9\xfd\x6f\x78\x83\xf5\x64\x22\x86\x6f\xd9\xf0\xaf\xe5\x3f\xdc\x91\x0a\xfa\x5a\x75\x1c\xbf\xa3\x77\x59\x25\x79\x16\x5c\xb5\x6d\xc3\xeb\x4d\xce\x67\xe3\xdb\x33\xa9\x81\xa5\x6b\x7d\x9f\x7b\xde\xa7\x4f\xba\xea\x34\x78\xe6\xab\x2c\x64\x4f\xd7\x77\xb8\xbf\xa7\x2a\xa0\xf0\xa5\x21\x98\xd3\x6e\x5b\x63\x4d\x2c\x9a\x11\xb7\xfe\x0a\xb2\xf9\xa4\x09\x01\xc5\xb1\x48\xa0\x19\x2e\x95\xa1\x70\xba\xf7\xd5\x35\x0f\xe0\x1e\x56\x95\x42\xb9\x34\x85\xa4\x19\x71\x44\x34\x85\xfa\xf5\x7f\x67\xf5\x6d\xfe\x2c\x58\xe5\x39\xc9\xf9\xb4\x49\xc3\xf9\x12\x49\xa1\x0c\x1a\x1b\xe7\xe0\xb3\xea\xbe\x8e\xe0\xba\xb1\xf1\x1f\x89\x61\x4d\xce\xd4\x18\xc6\x2a\x07\xa0\xb5\x9a\x13\x70\xd6\x53\x1b\xa1\x77\x09\x1c\x6a\xd5\x95\xfb\x59\x48\x82\x04\xf6\x33\x44\x73\x6e\xa1\x01\x7a\xff\xbe\xb7\x53\xa9\x97\x86\xb1\xeb\x64\x51\x0e\x2e\x71\x7e\xc9\x0e\x02\x74\x4b\xc3\x52\xd3\xf1\xb2\xab\x7b\xe0\xeb\x65\x62\x3d\x04\xfb\x3a\x04\x6c\xe7\xf4\xda\x69\x7d\x82\x98\x28\xa5\x2c\x7b\x04\x3b\x2a\x82\xec\x97\xfb\x04\x1b\xf5\x19\xb4\xde\x31\x6f\x4e\x2f\x5b\x0d\xb6\x2a\xed\x0e\xed\x95\xca\xd4\x32\x0c\x19\x47\xc3\x5f\xd8\x84\x7a\x58\x67\x87\x28\x83\x56\x11\x19\xc0\x1b\x00\x89\x21\x3d\x84\xdb\x99\xd4\x39\xf0\xf6\x44\x4d\x87\x83\xdd\x4b\x64\xbe\x35\x77\xcd\x46\x1c\xf7\x53\xc8\xe6\x1c\x91\x2d\xe2\xe5\xd7\xa7\xe2\xba\xef\xa2\x58\x97\x5d\x16\xef\x31\x17\xda\x59\xa6\xc8\x93\xf3\x33\x91\x87\xdf\x31\x68\xb8\x9f\x0f\xb0\xb2\x19\x8b\xb6\xf1\x59\x4b\xb8\x8f\x3d\x61\x0f\xce\xc3\xe3\x6d\xe0\x4a\xe1\x03\x28\x11\x2e\x6f\xf7\x4f\x5a\x8c\xe6\x8d\x40\x71\x74\xb4\xc0\x69\x1c\x76\x02\xea\xb1\xbb\x10\xf3\xc4\x9d\xd2\x2b\x84\x50\x78\x2d\xea\xe9\xa7\x31\x5e\x3b\x88\xde\x79\xcd\x15\xe6\xc9\x26\x81\x65\xed\x3a\x0f\xb3\xf8\x9b\x18\x3e\x1a\x21\x21\x52\x00\x3f\x32\xa2\x66\x5d\x37\xcd\xd7\xf6\xb5\x6c\x24\x53\xe5\x58\x0c\x4d\x21\xf9\x98\x3f\x38\x79\x8e\x9b"}, -{{0x7b,0x30,0xb4,0x2d,0xc2,0xc6,0x70,0xa1,0x95,0xfe,0x2a,0xf8,0x79,0xfc,0x5d,0xe3,0x74,0x02,0x45,0x88,0xfe,0x3d,0xe4,0x3e,0x2d,0xd5,0x08,0x44,0xf4,0x8f,0x42,0xbe,},{0x82,0xa2,0xac,0x60,0x79,0xf2,0x12,0xb5,0xee,0xdd,0x0c,0x19,0xe9,0x39,0x4f,0xaf,0xac,0xd7,0x4d,0x71,0x6f,0xde,0xfb,0xfc,0x6c,0xb8,0xa7,0xea,0xf4,0x1c,0x03,0x62,},{0x0a,0x63,0xb8,0x4f,0x46,0x93,0x5f,0xaf,0x3e,0xa1,0x64,0xb0,0x0a,0xf2,0x27,0xb0,0x08,0x68,0xa0,0x3f,0x56,0x12,0x93,0x5e,0x18,0x61,0x9a,0x84,0xa2,0xe5,0x7b,0x88,0x51,0xd7,0x46,0xe6,0x3f,0xd9,0x10,0x07,0x87,0xf5,0x33,0x8d,0x51,0xc1,0x07,0x3c,0x2f,0xc5,0x30,0x30,0x99,0xe1,0x87,0x3e,0x5e,0x3d,0x3e,0x5c,0x03,0x6f,0xbe,0x01,},"\xc6\x68\x7a\xef\xeb\xc5\xc8\x16\xd1\xa3\x34\x53\xbe\xca\x50\x20\xd3\xa9\x7c\xda\x1d\xac\x56\x62\xf0\xaf\x72\xba\xd4\x44\xe2\xfd\x11\x76\xa7\xb0\x4c\x1b\xd0\x9d\x83\x26\x18\x20\x9b\xf3\xe3\x3e\x52\x35\x38\xd6\xda\xa7\x53\x04\x6e\x87\x1d\xd3\xb3\xc7\xac\xad\x33\xe7\x9c\x1b\xb7\x89\x64\x07\x86\x5d\x16\x8d\x4b\xc3\x75\x7b\xde\x4f\x82\x3c\x08\x77\x86\x26\xf8\xc7\x1f\xb7\xcf\xcf\xdf\x03\xa8\x24\x97\xbd\x8b\xe7\xd8\xf8\xef\x64\x90\x30\xb5\xf3\x6a\x33\x94\x59\x96\x8e\x24\x6a\x1e\x42\x08\x53\xda\xce\x41\xca\x85\x0a\x4e\xea\xe8\x34\xae\x11\x96\x10\xca\x4c\xd0\x66\x2a\xac\x39\x62\x15\x86\x99\x80\x27\xef\x2f\x61\x48\x5c\x02\x85\x06\x71\x4a\xe0\x9c\x76\x39\x9d\x87\x3e\x80\x81\x58\x57\x8a\xa5\x9e\x82\x12\xf5\x88\x65\x31\x9f\x9e\x0d\x2b\x8d\xa7\xad\x52\x9e\x0a\xc1\xf1\xeb\x43\x5a\xec\xfd\x35\xf5\xab\xb9\x2b\xea\x50\x73\x49\x6b\xf4\xc0\xbf\x15\xba\xa2\x73\xbf\xc5\xc3\x10\x44\x74\xa2\xdc\xf1\x32\xc3\x33\xeb\x36\xec\x2c\xbf\x04\xfa\x95\x80\xb7\x68\xf5\xce\xa7\xb5\x61\x7e\x58\x80\xaf\xf6\x32\x01\xc2\x74\xd6\x69\x74\x3e\x1b\xc5\x56\xb0\x67\x90\x2e\xee\x29\xd2\x91\x11\x28\x89\x69\xcf\xfa\x87\x9f\xc9\xcb\xf6\x6f\xbf\x93\x26\xd9\xd9\x25\xac\x41\x02\xfa\x9f\x1a\x06\x08\x1a\xde\xc0\x79\xcb\xc9\x67\x46\xd7\x9b\x63\xa0\x12\xed\x77\xd8\x2c\x9f\xfd\x4e\x3f\x16\x1f\x6c\xea\x28\xcc\x23\xfa\xc2\xa5\x43\xf5\xb1\xd0\x64\x4e\xc0\x48\x38\x32\x7b\xcc\x65\x2b\x85\x8f\x93\xff\x46\x3f\x7e\x94\x9e\xec\x8c\x9d\xb6\x56\x9a\x86\x98\x4f\x83\x1d\xf6\xac\x6d\x95\xf3\x8f\x46\xce\xbb\x6e\x65\x83\x65\x7f\xac\xd2\x10\x8d\xbc\xd0\xaf\x23\xab\x01\x01\xa1\x30\x1b\xeb\x48\xa4\x4c\xac\xcb\x91\x09\x44\x73\xd7\xe5\xa5\xc8\x8c\x64\x4f\xd3\x42\x05\x73\xb6\x78\xf1\x7b\x51\x74\xcb\x14\xe9\x0f\xac\x69\x4d\x1d\xbc\x6c\x96\x32\xb5\x97\x4a\xef\x28\xac\x08\xd7\x20\xb2\xea\x30\x44\x0d\x2a\xfb\x04\x93\xb4\x0d\xb2\x4e\xfb\xdb\xf5\x3c\x43\x09\x21\xe5\x2a\x10\xb5\x46\x61\xe1\x49\xd1\x65\x59\x1a\x7c\xf9\x1d\x65\x08\xea\x47\x2f\xb3\xbe\x16\x39\x5e\x30\x31\x2f\x19\xb8\x7c\x47\xe4\x68\x04\xa0\xfa\x29\xb5\x6b\x5a\xc9\x50\x67\x7b\xc6\x02\x38\xb5\xe9\x9e\x03\x0b\x1e\x55\x21\x46\xa0\xe8\x8c\x29\x4c\xfc\xa8\x35\xc1\x01\xc5\x5f\x34\x23\x87\x4c\xc1\x28\x75\x6e\x73\xa5\xde\xbe\x8e\x97\xfe\x21\x66\xb6\x5c\xb4\x46\x42\x77\x0c\x6d\x1d\x23\x90\xaf\x1b\x0f\x31\xb9\x58\xc8\x30\xe9\xac\x4f\xe2\xf5\xad\x59\x05\x82\xfb\xb8\x92\xbf\x94\x95\x84\x47\x7e\xf7\xbd\xe2\x3f\x7d\xd0\x2b\x63\xf7\xc2\x90\x88\xa5\x72\x51\x00\x91\x32\xff\xbb\x78\xed\x14\xde\xfb\xef\xd9\xfd\x31\xfd\xca\xb0\x3b\xa8\x0a\x23\xf3\x33\x98\x37\x60\xab\xad\x4f\x16\xdd\xf9\xdd\x44\x14\xf0\x4d\x00\xdb\x56\xba\x72\xd6\x3a\x3a\x13\xd2\xc4\x42\xf5\x49\xfd\x66\xc9\x88\xd2\xe4\x60\x1d\x13\xb5\x2f\x77\x50\x0d\xd6\x92\xbe\xc9\xd6\xbd\x3b\xaf\xa9\x24\x2f\xdc\xfa\xeb\x69\xb9\x8b\x0b\x57\x89\xb2\x80\x38\x40\xde\xc6\x37\xb4\x9a\xf4\x38\x1a\xe3\xfa\x42\x9f\xb5\x34\x61\xa0\xc6\x74\xeb\x5a\xa1\x8d\xbd\x60\x7a\x2b\x77\xa9\x6d\x3a\xb4\x64\xec\xd9\x74\x92\xf6\xde\x46\x0c\x9f\x11\xb5\xc1\x75\x6c\xb5\x9c\xb1\x34\x8d\xfd\x77\x95\x6b\x71\x90\x7c\x54\x82\x1e\x30\x3c\xb8\xb1\x49\x06\xc0\x03\xe3\x48\x4b\xe4\xea\x05\xa6\x90\x1d\x69\xb0\x74\x85\xe8\x58\xf7\xb4\x71\xc6\x35\xf9\x03\x95\xb9\xa3\xe2\x24\x7f\x1a\xd1\x2b\x11\x8f\xfa\xfc\x72\x21\xa5\x7b\x10\xe3\x19\xb6\x1a\xf1\xc1\x36\x06\xa8\x16\x16\xce\x3f\x1d\x62\xba\x93\x2f\xf4\xe6\x3e\x74\xb8\x42\x55\xe3\xaf\x52\x10\xbb\xd5\x71\xbd\xa4\x4c\xbf\x44\xb7\x14\x42\x2c\xb4\x5c\x2e\xf2\x1f\x98\x13\x1b\xa9\x6b\x7e\xdb\x9b\x03\xe3\x3d\x7d\x18\x8d\x5b\x8d\x90\x4c\xb4\x13\x6f\xe2\x69\xdb\x14\x69\x88\x16\x8e\x7e\xe2\x45\x35\x63\x54\xf0\x02\xa5\xea\x8b\x35\xa3\xa9\x9e\x83\xa1\x32\x72\x27\x41\x44\xb3\x3a\x60\xca"}, -{{0x66,0x56,0xf4,0xd4,0x71,0x81,0x57,0xc4,0xba,0xc3,0x8f,0xf7,0xab,0xe5,0xeb,0x1f,0x81,0x2c,0x0b,0x98,0x6d,0x9c,0x01,0x4a,0xba,0xd5,0xb0,0x9a,0xa6,0xc8,0xee,0x4a,},{0xf3,0x08,0x78,0x98,0xe4,0x52,0xbe,0x9e,0x30,0xae,0xcc,0x4e,0x8f,0xfe,0x0c,0x01,0x16,0x98,0x88,0x68,0x3f,0x62,0xa4,0x5b,0x8d,0xa3,0x82,0x99,0x01,0x4f,0x5b,0x4a,},{0x9c,0x2c,0x39,0x91,0x5a,0xed,0x6a,0xdd,0x00,0x4e,0x7d,0xd6,0x84,0xee,0x3d,0xcd,0xd1,0x0d,0x87,0xa4,0x87,0xf6,0x77,0xe7,0x3c,0x2b,0xce,0x0f,0xca,0x7d,0x50,0x87,0x96,0x46,0x41,0x50,0xa5,0x2a,0x44,0x0f,0x52,0x37,0x85,0x0a,0x00,0x9c,0x72,0x16,0x2d,0x9d,0x29,0x85,0x47,0x0a,0x33,0x49,0x0e,0x66,0xd3,0xc4,0x01,0x70,0x4c,0x05,},"\x94\xd9\xe5\xe5\xa7\xb7\x05\xd9\xd9\x76\xfe\x71\xe9\x4d\x3f\x7f\xa7\x86\x6a\xfb\xf7\xec\xe4\x24\xf1\x36\x32\x77\x99\xb2\xb2\x06\xce\x4e\xf4\xc3\xf3\xe7\x05\x55\x3a\xfc\x8f\xd5\xc1\x95\x2a\x4c\x16\x65\x8d\x4a\x78\xaf\xbb\x9a\x97\xf2\x71\x93\xc6\x5b\x65\xb8\x2e\x8f\x3b\x71\x51\x5f\xac\x82\x64\x0e\x0f\x8a\x5f\xb3\x5a\xe6\xfc\x6a\x3d\xb0\x51\xa2\x2d\x4a\x53\x00\x41\x3e\x6e\x33\xd1\x9c\x20\x13\xc2\x98\x3a\xca\x8a\xd6\xce\xc2\xce\x64\xa8\x14\x16\x4f\x06\x1a\x1a\x3c\x5a\x86\x10\xa7\x65\x0b\xfb\x54\x23\xd4\x36\x2c\xe0\x22\x06\xdb\xe4\xa6\xfa\x82\x6f\x03\xb4\x2a\xc3\xcd\x9e\xa4\xc6\x51\x40\x1b\x3c\xea\x82\xc3\x99\x3f\x6a\xf8\xb2\xc9\xe2\xe6\xff\xe6\x92\x80\xab\x3f\x09\xfb\xe9\x0d\xd5\x47\xcc\xda\x9d\x9e\x8e\x8a\x53\x7b\x3b\x36\x05\x54\x22\x7e\xd0\x70\x9f\x29\x31\x98\x98\x2e\xfb\x5e\xfb\x0e\x73\xe0\x00\x42\xd1\xa0\x63\xb5\x74\x52\x02\x7d\xce\x1a\x39\xe4\xb0\x06\x8f\x58\xb1\x11\xec\x5d\xc1\x42\xbf\x41\x9a\xd8\x93\xd5\x4f\x42\x60\xcb\xde\x76\x28\xf7\x83\xde\x84\x96\x38\x03\x06\xa4\xef\xf6\xd8\x28\x69\x10\x42\x59\xc9\x4c\x54\xad\x5a\xa8\xb0\x67\xc4\x24\x96\xcb\x88\xdd\x31\x15\x0e\xa0\x4d\x49\x9b\xfa\xc9\x1f\x4b\xb3\xe6\x8a\xf5\xaf\x7a\x56\x8a\x3e\x4c\xe7\xf1\x70\xd9\x86\x01\x16\x3f\x49\x52\xf1\xd2\x5e\x12\xe0\x0e\xf0\xa2\xd8\xf1\x11\xaf\xdb\x0f\xaf\xba\xd2\xbf\x8e\x8b\x9d\x49\x36\x3f\xca\x68\x18\x36\x17\xb5\x41\x27\x0d\xda\x46\x09\xb2\x61\x67\x29\xab\x1b\x8c\x42\xdb\xdd\x7b\xf9\x86\xaf\x8f\xba\x52\xe7\x33\xe4\x2b\xa0\x3c\x89\x2e\x1e\x1e\xc0\x6a\x90\xb1\x63\xf5\xa7\x9f\x61\x65\xeb\x73\x16\x97\x2a\xc1\xad\xbf\xcf\x1d\xca\xb0\x78\x47\xef\x82\xc2\xca\xb1\x01\x5d\xbb\x50\xaa\xdc\x79\xfe\x11\xc8\x32\x09\x8c\xac\xc3\x98\x20\xab\x08\x5b\x69\x63\xbd\x42\x16\x0e\xd6\x61\x3b\xae\x5e\x20\x1f\x17\xc0\xfd\x7f\x32\x35\x7a\xe3\x50\xce\x9c\xbb\xe9\x26\xfa\x42\xdc\xbd\x42\x2a\xc1\xbf\x09\xa1\x9a\xd1\xf6\x94\x69\xe4\xd1\xdc\xb1\x24\x11\x8e\xd4\x52\x2d\x35\x3c\x17\x42\x98\x65\x0f\xf8\x83\x82\xfa\x2f\xdb\xb2\x86\xc4\x5b\x18\xa9\xba\xf6\xf6\x76\x3a\xc2\x0c\x9c\xa4\x76\x7d\x34\x8c\x4b\x8d\xed\x63\x00\x76\x65\x7b\x85\xb1\x4c\x11\xae\x27\x37\xea\x29\xa4\x35\x15\xb7\xf0\x56\x74\xa0\xcd\x3e\xd4\xbf\x6a\x3d\x18\x9a\xe9\x72\x21\x8f\x87\x7c\xd8\xaa\x69\x49\x9d\x5a\x08\xc9\x9e\x44\x06\x94\xcc\xac\xcd\xf1\xf6\x42\xe1\x4e\x90\x10\x5b\xee\x6d\x98\xed\xee\xab\x3b\x4f\x33\x9f\x30\x01\x88\xae\xc0\xc1\x6b\xd6\x45\x21\xd9\x28\x73\x98\xe6\x48\xdb\x94\x33\x0e\xd8\xf6\xb9\xab\x6c\x7a\xd9\x3f\xfc\x43\xe8\x79\x2e\x63\x7c\x61\xbf\xf7\xd8\x56\xe5\x4e\xf4\x98\x73\x84\xe3\x12\xcb\x57\x01\x7a\x50\xea\xe5\x95\x2a\xbe\x19\xd8\x99\x9c\x8c\x82\xdf\xc4\x57\x98\xcc\x17\xc8\xd9\x49\x6b\xf5\x20\xec\xc5\xb7\x7f\xe2\x84\x91\x55\x66\xc4\x56\x85\xc3\x04\xa2\xac\xd5\x25\xef\x12\xc8\x6f\x38\xae\xf5\x54\xd8\xa2\x38\x47\x37\xcc\x41\x33\xfb\x7e\x2b\x65\xc1\x3b\xef\x31\x66\x8a\x6c\x2f\x60\xee\xcd\x84\x12\xee\xff\x7f\x6b\x60\x5c\xbe\x95\x08\x3e\x23\x3e\xc1\xa7\xbb\x36\xde\x23\x6c\x8a\x71\xba\x28\x72\xbe\x94\x6c\xd3\xb3\x89\x35\xf5\xda\x64\xc8\xfe\xc8\xe1\x4f\x45\xcc\xf6\x12\x4b\xab\x7f\x70\x56\x7c\x2f\x2b\xfd\xd5\x66\x67\x60\x95\x72\x03\x7c\x76\x14\x6c\x99\x17\x07\x65\x9b\x57\x09\xb0\x74\xe3\x45\x1f\x92\x1a\x2d\xf2\x83\xb9\x6a\xa2\x6a\xb4\x76\x62\x50\x16\xf1\x81\xad\x64\xc9\x91\x9c\xf4\x1d\x71\x4a\x1a\x9a\x5e\x2b\xb2\x6b\xaf\x87\x70\xb2\xeb\xa7\x7b\x77\x8a\x33\x26\x77\xa7\x57\x2e\xe3\xa2\xb1\xdc\x05\xf7\x35\x6b\xdc\xae\x5f\x55\xe3\x53\x29\xe3\x4c\xaa\x79\x43\x0b\x27\x0c\x03\x61\x60\xdc\x9f\xca\xab\x5b\x25\x45\x43\xac\x94\xb2\x46\x81\xf1\x71\x72\xb6\x15\x9d\x16\x62\x1d\x7a\xd0\xee\xbd\x89\x5a\x1e\x1d\x09\xb9\x16\xa8\x6f\xb4\x8e\x4c\x91\x66\x10\x57\xee\xe9\x5c\x08\x70\xed\x54"}, -{{0x14,0x38,0x3e,0x6e,0x56,0x04,0xc9,0x9c,0x24,0x8d,0x39,0xbe,0x51,0xd1,0x64,0xb1,0x34,0x42,0xb0,0x5e,0x51,0xd7,0x8e,0xcd,0x99,0x93,0x64,0x22,0x1a,0x45,0x03,0x6b,},{0x2f,0xc1,0x61,0x38,0x22,0x0a,0xb7,0x4b,0x3b,0xd4,0x46,0xf8,0xa7,0x14,0xb5,0x8d,0x54,0x63,0xd4,0x0d,0x43,0x67,0x92,0x50,0x07,0x47,0x4c,0x5b,0x9e,0x35,0xd4,0x94,},{0x45,0xe8,0xed,0x1a,0x75,0x1d,0xfc,0x3b,0x9b,0x7b,0xd7,0xa1,0x0b,0xf5,0xbd,0xcf,0x8c,0xa4,0x61,0x86,0x5a,0x49,0x0c,0x10,0x5f,0x10,0x45,0x29,0x41,0xcf,0x87,0x72,0x12,0x14,0xbf,0xbf,0x3a,0x35,0x60,0x6b,0x7c,0xe3,0x5d,0x6f,0x70,0xaa,0xf2,0xd5,0xea,0xdc,0xc0,0xde,0x03,0x5e,0x9b,0x2f,0x6d,0x7b,0x86,0x2f,0xc2,0x84,0x90,0x04,},"\xc4\x75\x3b\x7f\x7a\x6f\x6d\xea\x25\x15\xc6\xe3\xd2\x95\x61\x50\x6f\x4f\x36\xe0\xde\x84\x99\x92\x21\xf2\x28\xe2\x0b\xd5\x12\x8e\xd9\x3b\xdb\x8d\x11\x93\x23\x7d\x8e\x29\x41\x69\xa2\xbc\x44\x8a\xf9\xdd\x36\x06\x63\x01\xef\xb7\xfe\x12\x31\x35\x3c\x06\x23\xff\xe1\x11\x5d\xeb\xb6\x90\x5a\xc6\x94\x6e\xe3\x82\xa2\x7c\x3c\x09\xe1\xb1\xf5\xc1\x14\x93\xdb\xa3\x7d\xa0\xff\x6e\xea\x75\xd9\xfa\xb0\xee\x92\x6d\x70\x1d\xac\x2f\xc5\xb7\xef\x57\x88\x80\xa5\xd5\xee\xec\xad\xc1\xf4\xbc\xc4\xcd\x4e\xc6\xf2\xf1\x4f\x52\xa8\xc1\x64\x07\x2e\x6f\xde\x5a\xb2\xee\x9c\xee\x0b\x48\xe5\x1a\xf0\x55\xf9\xfe\xc7\xc6\x37\x50\xfe\xdf\x72\x33\x2b\x23\x86\x3a\x1e\x54\xc5\x2b\x46\x1a\x21\x50\x6d\xfd\xfc\x63\x88\x0e\x22\xd8\x9c\x89\x44\x12\x66\x6c\x92\x98\x21\xc0\xe4\x39\xe7\x45\x41\x5f\x71\x79\x69\xe6\x05\x85\x54\xd6\x4b\x94\x7a\x4f\xc9\xd1\x6a\xca\xe3\xe4\x9a\xec\x08\x80\x1a\x09\xd9\x72\xf7\x9e\xad\x68\xd5\x29\x76\x80\x69\x73\x5c\xaa\x74\x2b\x45\xa5\x83\x05\x81\xb8\x0c\xa0\x61\xa6\xc1\x51\x5e\x3f\x7d\x5a\x93\x37\x87\x8c\x19\xfc\x94\xee\xf2\x26\x98\xea\x6c\x4d\x05\xf9\xed\x41\x1b\x6b\x8f\x05\x2b\x5f\xf1\x5d\xc2\x3a\x64\xbe\xea\xae\x99\xf8\x48\x93\xde\x3d\xf9\x40\xa4\xe0\xb8\xe9\x93\x93\x01\x39\x05\x2d\x99\xbe\x47\xbc\xa8\x77\x5f\x85\x63\xbd\x40\x26\xb7\x13\x43\xd5\x19\x68\xf2\x33\x75\x28\xf4\xc9\xdb\x8b\xbd\x0a\x29\x8a\xf0\x4b\x27\x69\x5d\x86\xb7\xf7\xba\x6c\x4c\xcc\x62\x73\xfe\xbc\xd8\xf7\x5c\xff\x26\x69\x95\x24\x4f\xc1\xfa\x13\xd8\xd8\x43\xf0\xbf\xf4\x9c\xc2\xd5\x08\xf4\xa2\xb3\xaa\xd1\xd9\x5f\xb2\x2a\x2b\xc6\xad\x1b\x96\x6b\x08\x12\xd9\x90\x70\xbb\xa0\x7c\x92\x3e\xe4\xd0\x81\x07\x48\x6d\xc0\x1a\x06\xdb\xa6\xf1\xd5\xf1\x05\xac\xea\xde\x33\xb1\x66\x51\x0e\x42\x7e\xbb\xce\x52\xa3\xe7\x83\x1f\x0f\x78\xa3\xc6\xe0\x72\x60\x83\x34\xd8\x02\x1c\x33\x8a\x73\xcc\x0c\x47\xf1\x9c\x9f\xae\x40\x3b\x97\x16\xd0\xd1\x5f\xbd\xf6\x46\x6b\x08\xf6\xac\xce\x3f\x50\xa7\x03\xb1\xde\xa8\xd8\x26\xdf\x84\x2c\xa1\xba\x20\xd2\x9f\x45\x48\xac\xfc\x75\x4c\xf0\x11\xf5\x70\x68\x1b\x59\xe4\xda\x25\x38\x5e\xbd\x6d\x5c\x3a\xdc\x93\x05\x29\xe1\x66\xce\x67\x05\xf6\x01\x02\x10\xdb\x10\x64\x62\xb3\x33\x32\x04\xe7\xad\xad\xee\x66\x06\xa5\x62\x06\xb4\x7e\xef\x20\x74\xb1\x16\xe2\x2a\x61\x54\x18\xec\x2c\xdc\x33\x1f\x1e\x19\xe0\x7e\x8a\x37\xb9\x2d\x69\xdf\x07\x34\xe0\x85\xda\xee\xb9\x01\xec\x6e\x8c\x35\xf1\x03\xf1\xd8\x6e\xf0\xd2\xa2\x65\x2b\x01\xd1\x83\x59\x7e\x4c\xfd\xee\xdf\xe5\xdf\x9a\x7e\xf6\x6a\x1c\x79\x6a\x37\xa2\x71\x13\xb9\x44\xdd\x7b\xa1\x7c\x46\x00\x15\xab\x8a\xce\x45\x1c\x57\x85\x0e\xc6\xc2\x90\xc5\x4e\x51\x13\xf5\x5e\x99\xa8\xe6\xe4\x71\x1e\x3b\x78\x17\xbf\x91\xa5\xad\xb3\x7f\xb9\x46\x1b\xe6\xb1\xb5\x5d\x58\x60\x46\xe4\x2a\x54\xc5\xde\xf4\x07\x6f\x1f\xf6\xc3\x1b\x80\x6f\xc6\x02\x47\x43\x56\xaa\x28\x99\xea\xe7\x0f\x5e\x5a\xbf\x1f\x75\xa7\xf2\x4c\x13\x4c\xde\x11\x79\x3b\xb1\x62\xe0\x3a\x58\x3d\x5b\xe0\x46\xac\xc7\x34\x56\xd1\x2d\x50\x9d\x92\xf7\x70\x57\x68\x68\x6f\x6c\x71\x4a\x4e\x57\xec\x88\xb7\x13\x98\xe2\x3e\x83\x5d\x6d\x65\x47\x22\x59\x96\xb7\xed\x08\xf3\xb7\x44\x3b\xb1\x7c\x89\x94\x09\x49\x3d\x0e\xfe\x84\x55\xbe\xc8\xe8\xc2\x84\xa3\xb1\x49\xa5\xb4\xca\x63\x1e\xa6\x20\xb1\xbb\x81\x7c\xed\xab\xa5\x0b\x04\x44\x11\x84\x9d\x26\x0a\x6f\x2a\x0d\x3f\x2c\xce\xec\x38\x42\x71\x9a\x5e\xa4\xfe\x18\xdd\xe0\xd4\x2d\xcb\x33\xad\x21\xe6\x45\x33\x25\xaf\x6f\x3c\x00\x9f\x2b\xb9\x78\xd3\x0c\xee\xae\x9a\xa4\x92\x8b\xf7\x37\x67\xcd\xa9\x29\x2a\xb8\x93\xce\x5f\xa3\xaa\x4c\x23\x21\x63\xb4\x5c\x64\xed\x79\x77\x77\x9b\x1c\x0c\xaf\xcf\xc2\xb9\xfa\x08\x4a\x32\x4f\x11\x3a\xde\xec\x21\x8b\x47\x35\xb6\xb4\x64\xdb\x6d\x46\xc2\x79\x1a\xf3\x45\x5f\x1c\xa5\xea\x1e\x9a\x04\x8c\x05\x1a\x54\xdf\xa0"}, -{{0x59,0xb0,0x72,0x63,0xb2,0x2c,0x0a,0x38,0xbb,0xc5,0x91,0x05,0x95,0x94,0xb2,0xbd,0x92,0x7e,0x80,0x59,0x61,0xdd,0x07,0xe1,0xf9,0x42,0x45,0xb2,0x3a,0xa2,0xe0,0x16,},{0x0b,0x1e,0x4c,0xf5,0xaf,0xf2,0x78,0xec,0x65,0xb4,0x05,0xf5,0x10,0x8e,0x1b,0x5b,0x18,0xa9,0x69,0xad,0x1f,0x1e,0x63,0x81,0x91,0x2c,0x82,0xd6,0x98,0x90,0x7c,0xba,},{0x88,0x6d,0xa3,0x3e,0x35,0x53,0x28,0x5e,0xa5,0x9c,0x14,0x31,0xb6,0xe8,0x6e,0xa4,0x9b,0xb6,0x8b,0x2e,0x0e,0xfd,0x2b,0x15,0x7e,0x77,0x91,0xb7,0x4f,0x35,0xa2,0x42,0x1b,0xb3,0x59,0xf3,0xdc,0x1e,0x4c,0xe5,0xf1,0x1f,0x73,0x65,0x2e,0x03,0xbf,0xc0,0xb4,0x29,0xc5,0x8f,0x0f,0x2d,0x74,0x18,0xc7,0xc2,0x0b,0xce,0x2e,0x2d,0x19,0x01,},"\x08\xce\x0d\x4d\xb5\xc2\xaa\x50\x0a\x19\xef\xbc\x8d\xc8\x54\x92\x50\xf7\xdd\x46\xa7\xa9\xa5\x40\x74\x17\xb3\xd5\x18\x20\xe4\xb0\xd6\x12\x75\x58\x3f\x56\xf8\x97\xfd\x94\x2b\xdd\x73\x11\xad\x6b\xaf\x73\x81\x28\x56\x7a\xf6\x55\x8d\x75\x90\x6a\x02\xc4\x34\x3a\x99\x55\xd5\x9b\x11\x08\x8c\x58\x8d\xc7\xdd\x08\xf6\x79\x65\xc5\x60\x2a\x56\x92\x8d\xda\x4a\xe1\x64\x29\x31\x63\xb5\x17\xca\x17\xde\xd0\x4f\xe4\xab\x2f\x97\x89\x13\x0a\xe9\x6a\xb2\x31\xf0\x7e\x09\x01\x5b\x78\xf3\x84\x8c\xef\x43\x5d\xb0\xad\x9f\x35\xe0\xfb\xc9\x85\x1e\x3e\xcf\xc9\xfb\x18\x6d\x14\xd8\xda\x4d\xda\x45\xd0\xb3\xeb\x3e\xe4\x50\x0c\x10\x1e\x31\x94\xb5\x72\x14\x06\x89\xcd\x75\xda\x12\x87\xb2\x54\xf3\x74\xe3\xd9\x33\x26\xae\x5f\xaf\x11\x40\x18\xac\x71\x4b\xd0\x03\x75\xd9\x2a\x8b\xb6\x59\xc3\x29\x12\x83\x1f\x4f\x20\x77\x6e\x9e\x2c\x25\x02\x9f\x0a\xff\x39\xfd\xda\xc7\x24\x15\x43\xa0\x36\x6b\x84\xde\x7b\x1f\xf2\x3e\x8e\x4d\xc0\x93\xdf\x0d\x2d\xd5\xe5\x3e\x68\x47\x94\x8c\xf3\xd0\xff\x3f\x56\x4a\xd9\x4d\x9c\xc0\x0a\x5e\xa5\xb6\x95\xe4\x08\xbf\x50\xf5\xba\xb2\xf6\xea\x87\xba\x8a\xd3\xa1\x94\x01\x95\xcf\x1b\xc2\xb5\xb3\x48\x47\xad\x3a\x5e\xff\xb8\xa7\x82\x3d\xe9\x1e\xf1\x63\x38\x69\xd1\xf0\x46\x43\xaf\x4d\x82\x6a\x59\xe7\x8b\x9d\x18\x63\x12\xb3\xd9\x72\x26\x36\x54\xac\x55\x87\xb8\x0b\x71\x76\x46\xf3\x10\x03\xdb\x81\xac\x70\x86\x0d\x3f\xc8\xcd\x3a\x6a\x0a\x0d\x57\x6d\x25\x73\x1e\xf7\xb8\x96\x62\x63\xd7\xa0\x5b\x55\x00\x9e\x8a\x23\xda\xc0\xf9\xa2\x1a\x24\xb0\x6e\x13\x90\x0e\x44\x44\x46\xfd\xfe\x56\xcb\xc1\xa0\x26\xdf\x41\x06\x6b\x20\x1b\x14\x81\xe5\x61\x58\x92\x6c\x0c\x9e\xa9\x0f\x0c\x64\x5a\xab\x4b\xef\x12\xd4\xe0\x72\xcb\xfd\xc3\xc3\xd5\xe0\xc7\x2c\xf8\x8f\x16\x6d\xe0\x48\x87\x4f\x35\x34\xe0\x40\xc6\x2b\x16\x62\x82\x1b\xdd\x16\xb0\xe8\x58\x28\x17\x46\x1c\xb2\x68\x92\x79\xb4\x46\xd7\x0c\x8a\xc2\x0a\xd0\x3e\x59\x8c\xad\x49\x08\xc5\x2c\x35\x0d\x42\x43\xee\x8a\xed\xb8\x7a\x4a\xf9\x77\xf7\xdb\x57\xcd\x94\x7b\x47\xd6\xbb\x51\x40\x9d\x80\xd8\x1f\x6d\xb0\x3c\xb9\xa6\xa6\xb7\x98\x12\xf4\x70\x69\x0a\xfc\x18\x36\xa5\x31\x33\x80\x94\xcf\x26\xd3\xc1\x23\x2f\xd5\x60\x5d\x8f\x8c\x55\xb6\xf8\xa2\xa7\xef\x1e\x0c\x78\x15\x55\x94\xb2\x37\x95\x6d\x2a\xba\xd6\xa9\xad\xcd\x58\xe1\x1c\xcd\x35\xcc\x99\x5b\x9a\x0a\xec\xbf\x7f\x57\x41\xac\x05\x1b\x04\xef\x6b\x97\x44\xb5\x6f\xcc\xb4\x63\x98\x52\x8b\xb3\x1f\xbe\x84\xe0\x78\x84\x3e\x69\xbf\x33\x88\x98\xcd\xef\x69\xad\x41\x87\x23\x95\xe4\x6b\x59\x39\x04\x82\x55\x47\xe0\x0b\xda\xf2\x21\xf8\xfa\x58\x7e\xa2\x03\x7f\xfb\x9a\xc9\x30\x7d\xd3\xf8\xf3\x5e\xc5\x38\x6b\xa9\x66\x33\x3e\x2a\xc8\x72\x7b\x0e\x1b\x80\x61\x2d\x3c\x7f\x2c\xb8\x8b\xaa\xca\xdf\xe2\x16\x3b\xc3\x8c\x88\x84\x2e\x76\xa3\x94\x57\x1d\x40\x61\x0e\x8a\x29\x76\x02\x79\x37\x63\x29\x6e\x3e\xab\xf7\x20\xe9\x84\xb2\xed\xd2\x8c\xf5\xc4\xe0\xf9\xa0\xf7\x6a\xce\xba\x28\xcc\x1f\x1b\x69\xff\x1d\x35\xb4\xbd\x33\x47\xb7\xf9\xa9\x5a\x4c\x1e\xa1\x07\x34\xe1\xc9\x18\xeb\x96\x24\x9d\x0c\xc7\x0b\x47\x7f\x6f\x23\x80\x9b\xbd\xa9\x01\xd5\x3f\x48\x5a\x71\xf5\x08\x60\x02\xc1\xb7\x1e\xfc\xc4\x1c\xb1\xae\xb5\x12\x2a\x3f\x3b\xfc\x96\xc5\x1a\x55\xd7\x5c\x02\x98\x42\x88\xbe\x65\x78\x87\x85\x4c\xfa\x73\x89\x74\xbc\xd5\x44\x01\x46\xf9\xbb\x14\x04\x0d\xe5\x4f\x54\x44\xad\x43\xb7\x9a\xf9\xbd\xb2\x4e\xd6\xa4\x8e\xb2\xfd\xee\xd7\x1f\x31\xf0\xec\xe1\x02\xe9\x18\xe9\x56\x35\xc7\xa0\x38\x63\x3e\xe3\x48\xd8\xb5\x78\x16\x52\xd5\x05\x9d\x21\x5a\xc9\x7f\x30\xea\x20\xd2\x77\xeb\xbf\x15\x24\x69\x05\x42\x8a\x7b\xec\x02\xb8\xf9\x26\x31\x5b\xad\x67\x23\xfd\x64\xd7\x1f\xc9\x5f\x33\x33\x64\xcb\xe9\x0d\x46\x46\x33\x3c\x40\xdd\xa6\xd1\xd4\x33\xb7\xc1\x95\xa7\x58\xdb\xb4\x03\x8a\xf5\xdc\xc7\x23\x2d\x45\x47\xf5\x40\xe3\x94"}, -{{0x5c,0xc1,0x15,0xd8,0x39,0xe0,0x58,0xcd,0xb6,0x51,0x8e,0xe9,0xc1,0x61,0xc0,0x04,0xd8,0x8b,0xd3,0x90,0x8d,0x3c,0xf6,0xd5,0x2c,0x8f,0x29,0x6a,0x1a,0x07,0x6b,0x9b,},{0x1e,0x8f,0x33,0x05,0xbf,0x2f,0xa1,0x1b,0x17,0xd9,0x24,0x16,0xab,0x0e,0xa7,0x62,0x39,0x6d,0x88,0xf2,0xf9,0x70,0xef,0x0b,0x10,0x0e,0xd3,0xbf,0x5c,0xc1,0x34,0x40,},{0x03,0x71,0xc2,0xd6,0x4c,0x5e,0xc0,0xc8,0x27,0x6c,0xa5,0xff,0xa6,0x15,0xef,0xf4,0x2f,0x9e,0xff,0xfc,0x58,0xdd,0x8e,0xcf,0xcf,0x67,0x62,0x0a,0x9b,0xcb,0x38,0xfa,0xf1,0x18,0x93,0x2b,0xf2,0xcd,0x5b,0x92,0x05,0xfa,0x55,0x13,0x34,0xdf,0x2a,0x75,0x7c,0x59,0x77,0x44,0xf7,0x91,0xf3,0x71,0xfb,0xed,0xd9,0x8b,0x21,0xf7,0x34,0x05,},"\x53\x3e\x49\xc1\xd5\xf3\x3c\x5e\xc4\xbe\x84\xc6\x19\xf4\xec\x64\x9c\x25\xfd\x70\xbd\xcf\xe2\x57\xa6\x3c\x33\x73\xa4\xd0\x89\xc8\x9a\xf6\xee\xb7\x16\x0d\xd7\x7a\xb6\x6b\x1e\xe7\xe1\x08\x50\xab\x4f\xc1\xf3\x51\x32\x33\x2b\x53\x78\x9b\x2b\x01\x40\xc4\xf2\x0f\x97\xf2\x14\x20\x72\xd6\x24\xaf\xf7\xaa\xd3\x24\xaa\xcd\x06\x8c\x03\x5a\xff\x52\xfa\x71\x2f\x4e\x74\x83\x2d\xe0\x31\xb2\x64\x23\x14\xd1\x71\x10\xde\xe6\xfb\x85\x76\x2d\xc3\x0d\x7e\x97\x78\x2f\xd1\xfb\xff\x71\x79\xf0\x09\x17\xf5\x5a\xf7\x50\x3a\x5b\x7e\x23\xc6\xea\xdb\x65\xe1\x04\xf1\x51\x7b\x66\x24\xc9\xe5\x20\x4b\x3f\xd2\x9a\x65\x85\xe9\x2c\xe3\xa3\xee\xe2\xc5\xae\x17\x79\x20\xf7\xb4\xab\x2c\xac\x87\xd6\x72\xab\x6b\xaa\xc1\x18\x6d\x90\x4a\xea\x34\x98\x53\x4e\xb5\xab\x23\xe4\xac\x4c\x0d\xdb\x0d\x82\xa5\xae\x53\x1d\x76\x54\x9d\x36\x76\x28\x57\x7b\xac\x42\x35\xe8\x97\xd9\xfe\x20\x55\x22\x04\x7d\x21\x4f\xf6\xcc\xf3\x11\xc4\xe3\x97\x82\x7d\x97\xf2\x86\x8e\x70\xac\x17\xd2\x8e\x33\x49\x99\x74\x4d\x35\x93\x76\xa4\x82\xfd\xcb\x41\x4b\x02\xb2\x68\x7b\x96\x2e\xe8\x08\x6e\x57\x3f\xe0\x00\xdc\x51\xde\xe0\x68\x79\xc6\x84\xe2\x5f\x94\xce\xe5\xe8\x61\x34\x7e\x7b\xe7\xfc\xa5\x49\xa0\xf7\x65\x13\x6a\x2f\x4b\x88\xfe\xde\x07\x02\x4d\xd2\xfc\xe1\xf6\xd0\xc0\x35\x4d\xa1\xa1\x6e\xf3\x66\xb3\x15\xb3\xf7\x23\x30\x31\xf9\x79\xb7\x0e\xac\x6e\x23\xbf\x3b\x34\x9e\xfb\xd0\xe4\xf5\x3f\x4d\x5c\x41\xfc\x00\x42\x76\xa5\x96\x70\x65\x9f\x69\x05\xef\x03\xd2\xfc\x09\x8d\x58\x9f\xcb\xc1\x32\x82\x82\xfa\x22\xb1\x0d\xb8\x3c\x5d\x70\x86\x59\x94\xfd\x19\xd7\x60\xa3\x9d\x47\x6e\x02\x33\x0d\x2c\x6d\x19\xe7\x42\x26\x7d\xd3\x65\xbb\xe1\xfe\x5c\x71\x1a\x95\xb1\x84\x50\x8c\xe4\x8c\x1c\x96\xd7\xe6\x39\x90\xb4\x08\xd4\x50\x89\xbe\x79\xe3\x2f\x9c\xb0\x16\x2f\xd1\xe7\xd0\xd1\x9d\x97\xd0\xae\x78\xff\x82\x4c\xc6\x98\x94\x86\xc0\xbd\x03\x83\x52\x55\x1f\x37\x49\x9e\x9e\x98\x26\x80\x4e\x9d\x26\x24\xad\x0c\x7b\x75\x34\x56\x0f\x45\xfd\x7d\x32\x4b\x8e\x51\x7e\x01\xc9\xb2\x74\x3c\x14\x97\x9c\xfd\x51\x2b\xc3\xfe\x66\x72\x79\xb3\xa2\x77\xfb\x46\x3e\x9d\x73\x49\xb6\x4f\xfc\x9f\xe6\x08\x84\xc2\x1e\x48\x10\x81\xed\x70\xe6\xda\x5a\x35\x39\xc4\x48\x97\x1f\x0d\x97\x87\x28\x9f\xcb\x00\x80\xf2\x19\xe9\x94\x49\xf8\x29\x8c\x42\x47\x5f\x87\xfd\x10\xae\xb5\x09\xc5\x30\xcf\x6a\x57\x74\x8e\xb8\xf3\x56\x21\x61\xfa\x48\x75\xea\x95\x3f\x09\x65\x9c\x7d\xf7\xa9\x95\x0f\x03\x17\x46\x7c\xb4\xe5\x36\x6e\x19\x6e\x32\xf5\xe2\x69\x67\x33\xa2\x5e\xac\xbd\xe4\x92\x10\x49\x07\x62\x06\x0e\xa2\x31\x37\x0d\x40\x90\x42\x9b\xb0\x6b\xb8\x67\x39\x9e\x8d\x37\xbf\x5d\x21\xa0\xe7\x21\x47\xe4\x96\xcf\x3b\x7d\xd6\xfe\x6e\x5e\xde\xa9\x66\x8d\x80\x21\x90\xa9\x1c\x60\x0e\x29\x52\x3f\x8e\xb9\x04\xe4\x8b\x70\x41\x2b\xc1\x0a\x70\x20\x98\x4c\x5f\xf0\xf5\xf3\x83\xf2\x14\xae\x59\x4d\xc8\x59\x71\xe4\x80\x37\x28\x48\xd0\xd7\xe7\xcc\x5c\x18\xff\x88\xba\x9b\x26\x2d\x78\x84\x69\x8a\x41\xc6\xc7\x81\x9c\x03\x19\xfd\xc6\xbb\x07\xb9\x1d\xc1\x69\x4d\xaf\xe3\xaf\x37\xa5\x38\xbf\x2b\x2d\x8c\xac\xb2\x7d\x24\xcd\xc6\xea\xdb\x8c\x6a\x2e\x6b\x7d\xf8\xa4\x65\x4a\xe9\x37\x85\x0c\x89\x0a\xd9\x30\x98\x0a\xfc\xc1\x49\x2d\xb8\xa0\x16\x8c\xbc\x9f\x10\x65\x7e\xb4\x8d\x2a\xc8\x7f\x51\x75\xd2\x3c\xae\xd4\xb5\xe6\xf1\x0b\xbe\xaa\x5e\x33\xfc\x5f\x64\x18\xd6\x3b\xa3\x74\xab\x1a\x3c\xbd\x36\xb7\x29\xdd\xbd\xab\xa9\x89\xd4\x64\x5e\x3a\x66\x13\x0b\xae\x41\x7c\xad\x08\x6d\xad\xd3\x08\x43\x35\x25\x14\xc3\x75\xf2\x57\x1a\xba\xf9\x3e\x9a\x07\x71\xfa\x10\x3a\xe9\x25\x85\xb0\x4f\x55\xc4\x34\x76\x9b\x43\xd6\xd2\x2f\x75\x3f\x93\x06\x03\x6e\x53\x52\x4f\x6f\x4d\x9c\xcb\xd2\xc3\x03\x17\xa8\xe8\x99\xf3\x16\x14\x90\x35\x89\x4d\xa9\x45\xb7\x6d\x90\x82\xbf\xee\x32\x8e\x7a\x31\xb6\x63\x28\xee\x8b\x94\xe0\x68\xc7"}, -{{0x75,0xa5,0x03,0xf4,0x8f,0xfc,0x22,0x16,0x17,0x67,0x25,0x19,0x11,0x1b,0xf9,0x0d,0xa3,0x9d,0xa9,0xea,0xb2,0xe2,0x91,0x4f,0xd3,0x75,0x5f,0x10,0xf5,0x39,0x36,0x68,},{0xf6,0x80,0xcc,0x0f,0x63,0x58,0xcd,0xcf,0x53,0x7a,0xa7,0x11,0x28,0xcf,0xad,0xfc,0x0f,0x3a,0x89,0xc1,0x00,0xaa,0x34,0xbc,0xd2,0x42,0x7e,0x24,0x8b,0x6e,0xd5,0x0b,},{0xdf,0x28,0xe3,0xe6,0x30,0x36,0x08,0x67,0x86,0x4b,0xc4,0x1e,0x43,0xfd,0x7d,0xde,0xb5,0x28,0x76,0xdc,0xe9,0xb2,0x34,0xa3,0xfc,0xc3,0xd8,0x54,0x9d,0xb0,0x11,0x2e,0x17,0x63,0x90,0xa6,0x85,0xeb,0xd4,0x84,0x93,0x6e,0x25,0xc0,0x8c,0x8a,0x38,0x78,0xa3,0x7b,0x3c,0x4e,0x23,0x9a,0xd0,0xa0,0xe5,0x01,0x99,0x37,0xff,0xbc,0xd4,0x07,},"\x7b\x01\x09\x04\x23\x23\x6c\xb4\xb1\x3c\x41\x77\xfc\xe5\x2a\x7f\xf6\x58\x05\x88\xcc\x2e\xb5\xa3\xf3\x9f\xf5\xd0\xc7\x3e\x01\xe0\x1b\xf7\xbd\x74\xaf\xe4\x15\x12\x50\xc3\x91\x42\x6e\xa5\x07\x27\x1b\xea\x1d\x6d\x85\xf0\xb2\xfe\x35\xc4\x05\x00\xf9\x8d\x06\x56\xc6\x38\x8f\xc9\xef\xba\x18\x37\xdb\x22\xdf\xa2\x9d\x89\x26\x76\xf5\x0e\x57\x5f\xe8\x9f\xd2\x93\x89\xd0\x9d\x08\x0b\xad\x67\xba\x54\x4c\xac\xab\xf5\xa7\x73\x82\x37\xc5\x5e\x28\x75\xed\x49\x16\x30\x2a\x2b\x4d\xc4\x96\xe7\x42\x73\xbf\x05\x19\x11\x37\x81\x0e\x50\xe4\x81\x95\x26\x0b\xab\x6d\x81\xf9\xc8\x05\x62\xee\x73\xcc\xb9\x33\x3c\xd9\xb6\x1d\xaf\x5b\x00\x38\xa4\xe6\xc5\xc9\x58\xa9\x1f\x68\x50\x8c\x1d\x88\x25\x19\xc1\xaa\x4f\xfc\xc5\x35\x62\x46\x3a\x0a\xe3\x01\x63\x69\x6f\x84\xb9\x7c\xcb\xd8\x67\x98\x20\xed\xd3\x61\x7e\x7b\x89\x6e\xef\xfe\x34\x1e\xc6\xb5\xb0\x3f\x73\xb6\x25\xd7\x41\xc6\x55\xfe\x6e\x82\xd1\x1d\x47\x8a\x7d\x54\x3f\xf6\xc0\xfa\x3a\x3a\x8c\x94\xa6\x16\xfb\x84\x70\x70\xd1\xfb\xdd\xe6\x01\x0f\x02\x6b\x08\x9c\xd8\x63\xc3\xbd\x29\xb1\xc4\x26\x9f\x77\x65\x9e\x51\x57\x28\x89\x0c\x97\x3b\xe8\x7f\x0b\x83\x3c\xa5\xaf\x6b\x4c\x31\x33\xad\x4f\xa4\xf9\x16\x55\xc6\xad\xb5\xb7\x23\x5c\x27\xfe\x34\x82\x84\xf3\xf1\x33\x66\xa6\xa0\x3a\xd2\x2b\x87\xc6\xf5\x58\x4b\xde\xae\xa4\x8c\x70\x32\x5d\x6e\x33\xa4\x75\xf5\x05\x11\x06\x38\x75\x19\x2a\x87\xed\xc3\x88\x08\x9b\x84\x39\x53\x90\xc2\xa3\xad\x89\xa2\x25\x95\xdc\x4a\x71\x5a\x42\xa2\xc0\xef\xde\xf6\x7b\x35\x4b\x34\xfc\x75\xca\x98\xdf\x91\x3e\x75\x9e\x51\xc7\xf6\x25\xdd\xd5\x98\xac\x22\xd4\x21\xde\xcb\x57\xbe\xbd\x54\x22\x0e\xc6\xda\xa5\xec\xe7\x69\xd2\xe0\x1b\xe7\xb6\xbe\xe2\xff\x5a\x0b\x06\xb3\x2d\x6d\xa1\xd7\xbc\x05\x7e\x3a\xbf\xaa\xb2\x42\xa3\xf7\xe6\x64\x6a\x15\x9e\x4f\x50\x5e\x46\x62\x98\x2b\x13\xd0\xcc\x1f\xba\x91\xd1\x03\x09\xa4\x2d\xc1\x08\x7c\xf1\x0d\x36\xe3\x1f\x17\x06\x15\xa0\xac\xb5\x08\xbf\x68\x3e\x2d\xe0\x0c\x87\x64\x0d\x30\x4a\x94\x7b\xc4\x97\x1f\xf3\x61\x9c\x72\xab\xd8\x3c\x7b\x2c\xbb\x34\x64\xc4\x04\x0c\x26\x62\xb5\x85\x08\xb7\x46\x80\xcf\xa6\xde\x06\xe8\xd2\x1e\x3b\xec\x85\x11\x19\x93\x12\x68\x00\x09\x07\x1f\x70\x6b\x7b\x13\x3a\x24\x87\xd5\x74\x5f\xfa\xdd\x5d\xc0\xeb\x2b\x55\x3d\xf4\x40\x78\x7f\x01\x1d\xda\x37\x71\x9f\xa7\x13\x15\xe8\xb2\x91\xef\xd7\x7d\xa3\xba\x14\xfb\x99\x5f\x03\x57\x1a\x3d\xb5\x22\xb6\x3c\x60\xbe\x56\x19\x94\x16\x99\xb3\x92\x22\xb5\x9d\x0f\x23\xe5\xeb\x37\xea\xd4\xb7\xf7\x50\xed\x4a\xbf\x4d\xb8\x7c\x70\xda\x66\x5b\xef\x4d\x7a\x29\x21\xb2\xc9\x98\x97\xf2\x32\x1c\x9b\xe6\x07\x5e\x74\x4c\x82\x28\x63\x9a\xb7\x36\xdb\xeb\x2b\xea\xb4\x40\xc1\x56\xa3\x9a\x2e\xfd\x26\x1d\xb5\x08\x55\xe3\x04\xd9\xcf\xeb\x99\x14\x1c\x61\x35\x58\x10\x9f\x21\x47\x4d\x27\x2a\x2d\x90\x6d\x48\x93\x93\x4a\xff\x8e\x08\xa4\xfc\xee\x96\x4a\x5c\xd0\x07\x32\xfd\x33\xaf\x29\x84\x9c\x8d\xfc\xa6\x59\x79\x42\x18\x57\x18\x5c\xf6\x29\xf8\x68\x07\xa8\x59\x73\xd3\x44\x0a\x6b\xf8\x11\xa5\x8d\x04\x13\x87\x24\x98\x11\xec\x04\x7e\x5e\x8b\x34\x3b\x23\x87\xd0\x18\x1e\x0d\x0b\xd4\x61\xef\x10\xe8\x16\x4a\xae\x35\x7d\x9b\x29\xdc\x0a\xce\x3e\xc6\xd7\x43\xae\x34\x54\xab\x9f\x84\x2a\x28\xd5\x71\x02\x17\xdf\xfe\x50\x34\x4e\x8d\x93\x2f\x18\x01\xb0\xe8\xf9\x66\x19\x8e\xf1\xc9\xcc\x69\x69\xf3\x47\x34\xaa\x6a\x63\xae\xaa\xb4\x33\x9f\x75\xd3\x4f\xfa\x8a\xcb\x93\x7e\xd9\xc7\x30\x92\xa3\x09\xa9\xb8\x4a\x25\x01\x1e\x31\x14\xc2\x65\xe4\xf6\x02\x33\x7e\xb6\x99\xb5\xa2\x2d\x57\x2b\x03\xe4\xda\xd0\x3b\x04\x61\xc0\x0d\xb9\x67\x9b\x72\xfc\x5b\x49\x3e\xf4\x48\x6f\x85\x53\x5d\x81\x3a\x58\x08\x03\x85\xaf\xd4\xe8\xd8\x71\x82\x80\x34\x33\x4b\xfe\x44\x1d\x18\x98\x4e\x4d\xfc\xde\x02\x44\x03\xb5\xae\x66\xcc\x50\xa4\x73\x01\xb5\x7f\x9a\x32\xf7\x40\xbd\xc7\xff\x1d"}, -{{0xd8,0xaa,0x2a,0x0a,0xa5,0x14,0xfd,0x84,0x5f,0x7a,0xa6,0x6b,0x83,0xc0,0xea,0xbb,0x9c,0x16,0x02,0x3a,0xbc,0x16,0x95,0x77,0x34,0x50,0xb2,0xbb,0x33,0x25,0x22,0xf2,},{0xe4,0xe8,0xd6,0xb2,0x98,0x24,0x8c,0x15,0xfe,0x08,0xf8,0x7a,0x3b,0xc6,0x08,0x4b,0xf2,0xd6,0x4d,0x7f,0x1e,0x4b,0x2d,0x51,0x59,0x9e,0x9f,0xad,0x9c,0xc9,0x10,0x92,},{0x14,0x6f,0x65,0xd4,0x3e,0x71,0x55,0x42,0x89,0x4b,0x79,0x00,0xa2,0xf8,0xcd,0x4b,0x17,0xd3,0x87,0x0a,0x61,0x00,0xe3,0x7d,0xe0,0x05,0xb0,0xdb,0x5d,0x81,0x51,0x24,0x6d,0xe4,0xee,0x38,0x42,0xd3,0xeb,0xca,0x20,0xa5,0xda,0x22,0xa3,0x63,0xa7,0x57,0x5e,0x7a,0x55,0x12,0x82,0x95,0xf2,0x72,0x11,0x48,0x4a,0xf5,0x7c,0xd5,0x31,0x09,},"\x08\xde\xb3\xb8\x32\xf5\x2d\x65\x56\xf7\x8c\x3f\x0a\xbe\x46\xf1\xef\xe4\x5e\x3d\x5d\x88\xe7\xf8\xed\xf8\x03\x67\x0c\xe4\x61\x29\x21\x74\x9e\x9e\xce\x63\xfd\xc9\xbe\xf2\xba\x48\x38\x12\xbb\x62\x2b\xe7\x44\xd4\x04\x04\xfd\x6e\x09\xc9\xe1\xcb\x7c\xe1\x9d\xe8\x1a\x9d\xad\xf5\x56\x35\x2e\xe8\x98\x10\xc7\x6a\x9b\x10\x47\xac\x62\xb1\x6e\xbb\x7d\xa2\x3d\xdc\x2d\x4a\xb7\x6a\x02\x05\x61\xd0\x2d\x41\xb5\x8b\x94\x95\x3a\x23\xfa\xaf\xdd\xd7\x81\xb7\xdc\xa7\xb7\xfb\xee\x70\x6e\xc1\x0a\x73\x12\x5b\xf7\x44\x36\x05\x6b\xf3\xb4\xf2\xa0\x70\x1c\xfe\xf0\x5b\xeb\xd3\xdd\x8e\xef\x30\x6c\x1a\xc1\xb0\x09\x50\x88\x1f\xf0\x5a\xb5\xc8\x24\x8a\xd1\x09\x6a\xc9\x1d\x52\x6a\xe5\x9b\xa0\x58\x3b\x27\xdb\x7d\x1e\x39\x0f\x57\xa5\x88\x9e\x27\x99\xa4\xa1\x51\x9b\x15\xd9\x3d\xbf\x0b\x21\xd4\x50\x87\x3c\x76\xba\x52\x04\x61\xe8\xbb\x5c\x83\xc9\x01\x2e\xac\xd5\x57\xbe\xa6\x40\x58\x6e\xfc\xb8\x69\x00\x76\x47\xd4\x49\xf9\x1c\xcd\x52\xaf\xe3\xa8\x94\x77\xde\x7c\x2b\x64\x7e\xcc\x9b\xf9\x67\xfb\xf5\x76\x9d\x74\x88\x94\x47\xd9\x52\x2d\x9e\x80\x69\xc3\x49\x9a\xf6\xa8\xa1\x09\x7a\x95\xd3\xbc\xc5\xf8\x34\x33\x93\x44\x84\x31\x4c\xb3\x07\x58\xb5\x25\xfe\x53\xe9\x07\x21\xdf\x5c\xbe\x03\xd9\x6f\x0d\x0f\x98\x52\x1f\x01\xa5\xfb\xe5\x7c\xe8\x80\x4d\xbd\x18\xf8\xf5\xea\xc8\xf7\xdb\xb5\x8c\x41\x78\x9a\x44\x43\x3f\x8a\x8d\x12\x45\xd2\xad\xda\x8c\x78\xd8\x81\xc6\x5e\xa6\x61\xab\x17\x8d\x4f\xc2\x63\x4c\xd6\xcb\x51\x4a\xb6\xf2\x54\x3e\x91\x12\x18\x3f\x3f\xf7\x3a\x3f\x45\x01\x06\xb0\xee\x8a\x34\x7a\x80\xcb\x82\x4a\xc1\xf8\x01\x64\xe3\xbb\x51\x23\x69\x8d\xe0\xe7\x47\x35\x9c\xa3\x5a\xca\xa3\xba\x0c\x94\x3b\xea\xcd\x7a\x9b\xdf\x8f\xf7\x39\x78\xe9\xfb\x00\x20\x45\xe8\xfe\x56\x48\xcc\x0f\x9c\xfa\x88\xb0\xd8\x12\xe8\x1a\xa6\x2e\x0d\x9c\x73\xfe\x61\x3a\xfd\x95\x39\xbc\xb6\x15\x72\x1f\xb4\x97\xd6\x2f\x65\xc8\x3b\x87\xa6\xd2\x14\x3f\x9b\x1c\x88\x0e\xc8\x67\x1b\xd4\x2c\x8d\xe9\x57\xb1\xa6\x8e\xe4\x92\x26\xff\x71\x7c\xcc\x6e\x74\xf2\xee\xe4\x9c\x30\xde\xa5\x3f\xec\x3c\xd4\xd9\x0f\x2c\xcc\xd8\xf9\x7c\x55\xd5\xc7\x52\x45\x4b\xe2\xba\x7b\x6f\xf2\x03\x0b\xe6\x7e\x0d\xf5\x0c\x5e\x88\x38\x43\xe7\x16\x12\xf2\xb9\x53\x59\x54\x3e\x2b\xa1\xbf\x2e\x98\xde\xbc\xf5\x76\x8f\x2b\xe6\xfd\x50\x4d\x97\x83\xce\x92\x1a\x81\xe0\x94\x16\xdb\xcf\x2b\xb6\x55\xa9\x24\xb1\xef\x01\x12\xd6\x71\xf0\x84\xa5\xb6\x90\xb0\xb6\x4a\x8b\x9b\xf5\x03\x33\xc3\x59\xff\x3f\xef\x19\x96\x94\xf9\xb6\x29\x24\x24\xf0\x06\x66\xce\xf6\xd0\x6d\x16\x1a\x79\xe3\xa1\xb9\xb9\x62\x9e\xea\x53\x50\x5f\x5e\x36\xae\xad\xfe\x0d\x75\x96\x72\xb0\xff\xe4\x98\x39\x7d\x90\xa5\x5d\x99\x44\xb3\x05\x41\xa7\xe1\xbd\xac\x53\x02\x06\x40\x13\x7d\xc2\x52\xae\xf6\x22\xf3\x81\x9d\x36\xab\x49\x8d\x76\x3e\x43\x27\xba\x85\x80\xdd\x9f\x7e\x5f\x47\xc2\x4c\xc9\x92\x87\x34\xb7\xe6\x21\x12\xc5\x7e\x3e\x0c\xfe\xde\xcd\xcb\xac\xcb\x0c\x45\xaf\x82\x19\x45\x5e\xe7\x22\x3c\x71\xe7\xe2\x04\x10\xc5\x24\x4e\xb8\x27\xaf\x2f\x39\x35\xce\x47\x55\x44\x47\x47\xaa\x94\x5f\x4c\x26\xdb\x3a\x29\x85\x19\xe7\x5f\xc6\xba\xce\x91\x52\x99\x72\xe8\x69\x1b\x69\x4d\x30\xaa\x8b\x5e\xc4\xc1\xa0\x28\xd3\xbd\x10\xbd\x0c\x8a\x40\x8f\xb7\xd9\xd7\x03\x49\x55\x53\xec\xea\x59\x8d\x06\x22\xdc\xc7\x4d\xe4\x89\xba\x71\x95\xcd\xae\x8d\x5c\xff\x98\x55\x92\x18\x37\xb5\x28\x43\x3e\xe5\x5c\x0b\x70\x90\x85\x7a\x0c\x27\x84\xd9\x31\x0b\x48\x25\xa7\x99\x3a\xd9\xc6\xf1\x8f\x83\xbc\xa5\xcc\x6a\x25\x04\x71\x68\xa8\x37\x6b\x06\x2e\x3a\x48\xea\x90\xca\xd8\x8e\x33\x11\x87\xc2\xb6\xf2\x81\x42\x6f\x81\xf7\x88\x04\xa8\x95\xc4\xec\x06\xc3\x41\xfe\x84\x6a\xf4\x52\x7e\xa2\x60\x69\xdc\xf6\x1d\x81\x3f\xdd\xf0\xfc\x43\xc7\x07\x35\x0b\xfb\x2f\xc1\xcf\xfc\xee\x7d\x7c\xcd\x7d\x75\xf7\xa4\x65\xa3\xd1\x4d\x57\x30\x2c\x14\x6a\xba\x3e"}, -{{0xde,0x8f,0x1c,0x99,0xe7,0xf8,0x55,0x6d,0xf2,0x0b,0x59,0xb8,0x50,0x4c,0xff,0x7c,0x6c,0x52,0x41,0xa8,0xae,0xeb,0x30,0xb9,0x2e,0xab,0x97,0xbf,0x48,0x1d,0x0f,0xe9,},{0xe4,0x63,0x79,0x1d,0x0f,0x56,0x7e,0xe7,0x3a,0xbb,0xf4,0x7d,0xd5,0x71,0x67,0xa5,0x35,0x61,0x3b,0x05,0xcd,0x48,0xd9,0x2e,0xbc,0x7d,0x24,0xe6,0xeb,0xff,0x95,0x73,},{0x30,0xab,0xc4,0xe4,0xe4,0xb3,0x88,0x58,0x1e,0x66,0x8b,0xd4,0x09,0xee,0x18,0xa6,0xed,0xe8,0x1a,0x13,0x6c,0x28,0xa2,0x92,0x4d,0xf5,0xfc,0x00,0xd7,0xc2,0x80,0xd9,0x78,0x62,0xae,0x3a,0x67,0xa9,0x35,0xce,0x49,0x23,0x64,0x13,0x5e,0x65,0x9a,0xdb,0x5f,0xba,0xbe,0x68,0x98,0x16,0x59,0x1f,0x49,0xac,0x50,0x22,0xa3,0x87,0xcc,0x09,},"\x38\xd9\x3e\x5c\x98\x01\xdb\x90\x17\x97\xec\x75\xc6\xdd\xdc\x65\xae\x79\x80\xde\x21\x0b\xed\x43\xb3\x3e\xb4\x4c\xdc\x6d\xc9\x93\x3f\xb6\xbe\xc7\x42\x1d\xb1\x0f\x0a\x59\x32\x0b\x9e\x64\x2a\x21\xf1\xdd\x23\x56\x01\xfc\xd6\xc5\x3b\xe4\xa8\x77\xf4\xfe\xd3\xfa\x4a\x0a\xd4\xdc\x6e\x9b\x39\x1b\xcf\xa4\x34\x90\x69\x25\xba\x45\xec\xc5\xb4\x35\xd9\xab\x8c\xfa\xfc\x39\x4b\xdc\xca\x9b\x07\xd5\x66\x83\x93\x44\x6e\x34\x00\xe9\x03\x94\x35\xa1\xdc\x78\xcb\xc0\x88\x07\xa3\xfb\x24\xca\x8b\x19\xf6\x4e\xa0\x8b\x8b\xf6\xc2\x0a\x19\x5b\x51\xff\x80\x15\xf3\xe7\xc9\x1d\x08\xe4\xbc\x62\x41\x55\x95\xa5\xa8\x82\xfb\xa6\x51\xdc\x3a\x67\x51\x87\xaf\x61\x82\x49\x74\x7b\x46\x80\xd1\xd1\x5a\x20\x2e\xa9\xdf\x48\xb1\xc2\x14\xfd\x40\x34\x66\xfd\x1a\x26\x5f\x2d\xef\xaf\x8e\xd5\xa6\xbf\x0e\xb0\x8d\x18\x64\xf2\xa2\x8e\x94\x72\x14\x3c\x6f\xd1\x03\xb6\xb1\x08\xc0\xd1\xd1\x36\x3b\x99\xf9\x20\x2d\x11\xf0\x20\x56\xc2\x79\xcc\xa3\x15\xdb\x1a\xb6\xd3\x10\x18\x45\x8f\x57\xba\x33\x16\xcd\x27\x38\xe8\x0c\x49\x2d\x85\x7c\xb1\x74\x99\x25\xe3\x31\xc6\x58\x58\xb5\x09\x83\xcd\x98\x38\xcf\xd2\x18\x8a\x5e\x8f\x05\xb4\x71\xfd\x3c\xdd\xcd\x30\xd9\x69\x01\x19\x40\x20\xf1\x15\xfb\x46\x9a\xb5\x84\x90\x06\xdf\xfa\x2d\x54\x3a\x13\xb3\xb5\x06\xed\x65\xcc\x45\x75\x32\xb8\xaa\x3e\xe3\x1d\x9d\x8d\x9e\x52\x98\xd7\xac\x70\x7a\xc1\x5b\x82\x7a\x57\x8c\x81\xd4\x34\xf8\x4c\xb1\xb5\x61\x20\xd6\x67\xb2\xaf\xe6\xd1\x53\x0a\xfd\xdf\xb9\x66\xd9\x53\xbe\x7e\x32\xdf\x07\xde\x38\x9e\x2d\x04\xb2\x32\xd3\x51\x2c\x7d\xb9\x35\x8f\xc9\x44\xd1\xb1\x18\x07\x8e\x69\x99\xe8\x91\xbb\xfa\x4a\x43\x29\xf6\x5d\x80\x71\x88\xb5\x98\x58\xc4\x31\x21\x1b\x29\x57\x6f\x44\x96\x13\x8b\x7c\x0c\x12\x8f\x7b\xef\x5f\x79\xb0\xf4\x46\xfc\x6b\x4a\x0e\x20\xbc\xa4\xc4\x0a\x83\x57\x1a\x36\x64\x4a\xbf\xfa\xbd\x49\xcb\x58\x5f\xd0\x64\xc8\xe5\x09\xd9\xa0\xfc\xff\x46\x26\x76\xf0\xeb\xcb\x61\xce\xc6\x1e\x51\x2b\xe6\xf1\x82\xab\xd5\x9e\x09\xf6\x42\xaa\x61\x96\x34\x85\x34\x82\xec\xe8\xf8\x98\x00\xf9\xc5\xbc\xfb\x84\x14\x31\xca\x06\x91\xed\x8d\x80\xe0\xa2\xfc\xb7\x97\xa0\x36\x89\x7c\xfb\x65\x37\x58\x6b\x31\xc0\x0b\x79\x65\xef\xdd\xfd\xa7\x28\x61\x84\x50\x26\x45\x91\x57\xf7\x9e\xba\x1b\xca\xf6\xcd\x41\xd6\x18\xae\xb1\xbd\x8d\xa1\xbe\x98\xf0\xcd\xc7\xf2\xe0\x9b\x90\x3d\xe4\x9c\x0c\x1b\xe9\x1d\xcc\x17\x7b\x29\x80\x96\x83\x6d\xce\xa4\xf6\x01\xdd\x86\x69\x15\x55\x12\x83\x25\x43\x8b\xd9\xcc\xbf\xc0\xe7\x77\x92\x0a\xe8\xbb\xd5\x76\x34\xc6\x10\x4f\xe6\x9a\x3a\x72\x01\x2a\x23\x60\xb6\xe5\x52\x55\x0c\xff\xb4\xe2\xf0\xb4\x1f\xe1\x55\x37\xee\x0e\x6f\x37\xe7\x88\x0f\xb4\xd1\x2b\xef\x6c\xad\x26\x6c\xe5\x8d\xf9\x81\x6b\x35\x96\x0c\xd0\xbf\x86\x52\x86\x2e\xe7\x89\xcc\xc3\x1a\x7e\xfc\x21\xa8\x1b\xda\x46\x14\x6b\x11\x1f\xcf\xd9\x4f\x04\x85\x6a\xb6\x1a\x55\x7b\x1f\xf7\xc8\xe4\xea\x6d\x9c\x4b\xcd\xd9\x3b\x15\x1a\xa0\x84\x61\xc5\x68\xde\xfb\x2a\xef\xdf\xce\x96\x39\x4d\xc8\x22\xd4\xef\x6c\xc4\xb9\xa3\xe6\xc3\x32\x03\x9f\x65\x38\xaa\x0d\xf8\xde\x81\x26\xd9\x0c\x31\x2f\xf4\x96\x88\x74\x86\x11\x15\x65\x53\x43\x46\xa7\x46\x26\x25\xd6\x3d\xf6\x9f\xcb\x57\x41\x90\x6f\x19\xe0\x0f\xc8\x00\x3f\x08\xb9\x59\x85\xc3\x8b\x86\x74\xaf\x42\x3c\xa5\x6d\xe5\xf8\x81\xb5\x9c\x46\x62\x43\xa7\xad\xba\xdb\xa2\x9c\xaf\x57\xfa\x77\x71\x22\xe6\x18\x23\xb4\xe7\x08\x18\x2a\xaf\x37\x20\x6d\x7d\x5e\xd0\x51\xc1\x2a\x5c\x0f\x6b\x43\x71\x04\x3f\x56\x2c\xdc\x02\x9d\x5e\x1b\xa9\xb2\xbf\x5f\xfb\xf1\xf5\xf5\x23\xdb\x06\xfe\xca\x42\x7d\xb7\xa0\x88\x19\xff\xb2\xd0\x58\x52\x42\xe2\x0d\xa5\x8e\x32\x0b\x16\xb1\x6e\x44\x8d\x8b\xe0\xef\x74\x02\xd2\x4a\x71\x94\x25\x71\x33\xbd\xc9\x82\x31\x4d\x83\xad\xbc\xd1\x2e\x8a\xf3\x13\x03\x42\x6c\x59\xff\xd8\x26\x9c\xe4\xb9\x87\xca\x9b\x6f\x0f\xfd\xbb\x4d\x1d\x12"}, -{{0x07,0x36,0xf8,0x01,0x72,0x0a,0x94,0x7c,0x5c,0x2f,0x32,0x58,0xce,0x0d,0x51,0x1c,0x3e,0x17,0xe9,0x4e,0x37,0xb3,0x0a,0xdf,0xa5,0x20,0x95,0x92,0x11,0x71,0xd4,0x00,},{0x4f,0x69,0x42,0x55,0x92,0x0d,0x0c,0x38,0xde,0x6e,0x72,0xe1,0x65,0xc3,0x3a,0xee,0x76,0xb1,0xcb,0xf6,0xf4,0x83,0x7a,0xa5,0x90,0x14,0x75,0x66,0x7a,0xcd,0x28,0x26,},{0xc0,0x3c,0x03,0x14,0x85,0x12,0x79,0xed,0xcd,0xe9,0x70,0xc2,0x3e,0xfa,0x23,0x6f,0x23,0x5e,0xda,0x96,0x0d,0x2c,0x27,0xd3,0xca,0x94,0x6f,0x65,0x0c,0x20,0x0b,0x4e,0xba,0x04,0xbe,0x66,0x8f,0xf6,0x2e,0xaf,0xfa,0x6c,0xea,0x35,0x1a,0xbd,0xfc,0x54,0x40,0x1d,0xcc,0xce,0x3d,0xba,0x78,0x00,0x4a,0xec,0x95,0x81,0xa2,0xcc,0xf4,0x0f,},"\x7f\x87\xb5\x1f\x6e\xad\x2d\x44\x02\xa3\xbd\x3c\x37\x69\xa2\x67\xac\x8e\x82\xf7\x79\xad\x7b\x98\x6d\xec\x82\xcb\xfc\x1e\xa5\x12\x91\x88\x43\x26\xd9\x22\x69\x67\xcb\x66\xa9\x68\x73\x18\x4f\x0e\x83\xb3\xab\x25\xa5\xab\x2f\xa8\x05\xfe\x3a\x0e\x7b\x19\x0a\x62\x2d\x46\x1b\x78\x30\xa3\xf6\x97\xc8\x31\xc2\x9e\xa7\xc0\xcd\x4b\x68\xd8\xe7\x7a\xa6\x97\x11\xcf\x86\x4d\xc1\xd5\x39\x4f\x48\x45\xe2\xfb\xb5\x07\x64\x04\xe0\x9a\x88\xb7\x9f\x05\x67\x05\x51\xbc\xe2\xef\x54\x68\xb7\x9d\x57\x88\x8b\x98\x52\xa4\xbb\x47\x9a\x4f\xd0\xbe\xb6\x81\xfd\x52\x3f\xc5\xbf\x44\x58\xab\xbc\x38\xec\xe7\x2e\x10\x6e\x00\x22\x20\x15\xa5\x7e\xbe\xc5\x5b\xf4\x75\x13\xe2\x5c\x3c\x45\x54\x84\x3b\xda\xcb\xcf\xe9\xf1\xb8\xd0\xae\x35\x4e\x48\xd0\x3f\xde\xbd\xf2\x0d\x65\x5b\x52\x68\xd8\xbb\xbf\x33\xb1\x28\x89\x10\xf0\x44\x4f\xcd\x56\xc0\xda\x7b\x89\x03\x36\x2b\x7e\x37\xa8\x64\x65\x42\x77\xcf\xfb\xe6\xc6\x08\x57\xf0\xb3\x51\x4d\x22\xa4\x0b\x9d\xd2\xd3\xfe\x5c\xae\xa5\x50\x7a\x0d\xe3\x05\x1b\xb3\xa4\x01\x5f\xa0\xfe\x4c\x46\x2b\x98\xfe\xf2\x35\x7d\xcf\x6b\x97\xdc\x75\xde\xf3\x82\xf9\x01\xf9\x6f\x4a\x04\xa3\xef\xc6\x02\x54\x20\x0a\x2c\x4c\xdc\x8a\x58\xb2\x5d\x94\xe3\x29\x54\xea\xff\x15\x11\xac\x46\xe3\x60\x66\x63\xb6\x87\x5f\x13\x64\x99\xda\x6a\x76\x90\x97\x87\x9a\x6e\x08\x34\xd5\x64\xfa\x7f\xdb\x99\x58\x11\x83\xed\x0c\x9d\x48\xfd\x19\x5d\x7e\xcd\x9f\x4d\xd4\x86\x55\x65\xfd\x17\xa0\x08\x71\x8d\xcd\x76\xf6\x8a\x54\xe5\x16\xa2\xb7\x30\xed\x3d\xba\x5c\x2c\xf4\x06\x30\xbb\xfe\x7f\xa0\x3b\xb7\xcd\xd9\x67\x69\x54\x95\xa7\xc8\x6e\x2e\x84\xcb\x01\x7e\xc6\x96\x01\x92\x46\x31\x59\x5a\xff\xaa\x8c\xfd\x04\x8d\x14\x26\x7c\x73\xe5\x4c\xfa\x53\x90\x47\xe7\x17\x69\x1e\x39\x97\x37\xfa\x50\xcc\x48\x44\x96\x12\x57\xc9\x3d\x72\x53\xd2\x32\x26\xb7\xcd\x0d\x1b\xd3\x1f\x3f\x0d\x2d\x89\x2d\x07\x3d\x8c\x50\x73\xc6\x02\xf6\x1a\x04\xd6\x43\x7c\x39\x03\xeb\x4a\x64\xa0\x1f\xbc\xc0\xc7\xe1\x59\x20\x1c\xdc\x4a\xa4\x2e\xf3\xb1\xff\x9c\x78\xfc\x27\x5c\xfb\x11\xa0\x5f\xfe\xd8\xf9\xf2\x2d\x85\xba\x92\x4d\x8d\x32\x23\x1c\x25\x4d\x89\x8d\xa7\xf0\x67\x9a\x64\xca\xb8\x40\x26\x90\x6e\x9e\x85\xf9\x5e\xfd\x8e\xe2\xa1\x72\x56\x33\xf4\xde\x2b\xa6\x7d\x99\xaa\x7f\x05\x50\xaf\x13\x9e\x9f\x8c\x52\x93\x78\x67\x27\xd8\x26\x30\x29\x6d\x5d\xaa\x9e\x83\x0a\xa1\xb3\xb5\xb3\x02\xb8\xb6\x62\xac\x83\x2e\x92\x13\x01\x6b\xa4\x93\xa0\x3a\x28\xcc\x3e\x95\x40\xd0\xd6\x5a\xcd\xdb\xfe\x12\x52\xb5\xc1\x6a\x84\xa4\x45\xce\x75\x41\x5c\x6c\xd8\xab\x16\xfe\x5e\xef\x11\x70\x97\xd7\x1e\xb5\x67\x6b\x9a\x95\xb3\x58\x82\xa7\xc3\x50\x6b\xc5\xd0\x2f\x03\x91\x0a\x63\xd4\x68\x46\xb2\x13\xc3\xc9\xbb\x2f\xc3\x4e\x6c\x69\x01\x7d\x20\x65\xa1\xad\x3c\xe3\xfd\x14\xab\x00\x14\xf5\x84\xe5\x7e\xa9\xd9\x03\xe4\x0a\xce\xb2\x30\xa8\x69\x3f\xa2\xe6\x36\x41\xc2\x54\x38\xff\x7a\x16\x38\x76\x04\x38\x84\x4c\xdf\x00\x11\x80\xf5\xb1\x77\xbe\x69\xed\xf7\xef\x66\xb3\x93\x12\x80\x52\x14\xcb\x17\x70\x6c\xef\xe5\x45\xbe\x5a\x77\x01\x9a\x5e\xc5\x2b\xbf\x78\x85\x0f\xa3\xd9\x7d\xe2\xd4\xd7\x4a\xa6\x8b\x58\xca\x81\x2a\x1b\x15\x6a\x0c\x40\x01\x12\x9f\x06\x72\x32\xa6\xec\x91\xa5\xed\x42\x70\xf2\xa4\xc6\xef\xee\xe7\x87\x00\x47\x70\xc8\x59\xe4\x50\xe8\x37\xef\xb0\x4d\xc9\x98\xbd\x27\x3c\x27\xa0\x98\x55\xe4\xec\xa1\xa2\x2a\x9b\x88\xc1\x7b\xdb\xf2\x53\xa7\x97\x61\x07\x0a\x76\x81\x7a\x7f\x74\xff\x3f\x07\xfb\x71\x8b\xff\xa0\xb4\xf3\x26\xf2\x84\xe6\x2f\x83\x68\x32\x42\x7b\xe8\x2f\x48\x33\x73\x51\x5b\x9b\xf5\x9a\xf4\xa7\x6a\x57\xe2\xf4\x0b\x91\x03\x4d\xd5\x68\xec\x14\xac\x10\xe2\x30\x9b\x87\xe2\x92\x2f\x9c\xd9\xfc\x1a\x46\xa4\x7e\xd3\xbc\x7e\x1b\x9f\xeb\x9e\xe0\x67\x07\x3f\xa5\xdc\xe2\xa6\x75\x30\x52\x6d\xe6\x7e\xe0\xe5\x09\x66\x3c\x44\x46\x7e\xeb\x59\x42\x01\x03\xeb\xcd\xff\xa7\x09"}, -{{0xfa,0x75,0x65,0x04,0x91,0x04,0x74,0x28,0xd3,0x63,0xb5,0x82,0x22,0x22,0x12,0x2d,0xff,0xb5,0xa9,0xfd,0xdc,0x60,0x3c,0x33,0xc8,0xa6,0x08,0x61,0x83,0x75,0xdc,0xf3,},{0x98,0xc9,0x64,0x1f,0xa9,0xdf,0xa8,0xea,0x13,0xe0,0xd1,0xc7,0x16,0xb8,0x67,0x9e,0x26,0x4b,0xe1,0x5d,0xd2,0xd4,0xc0,0x6a,0xb4,0x3c,0xbe,0xe4,0x79,0x16,0xee,0x01,},{0x1e,0xff,0xbf,0x92,0x99,0xa1,0xb9,0x35,0x4f,0xe1,0xf1,0xde,0xc1,0x76,0x65,0x95,0xea,0x76,0x7a,0xb8,0xe4,0xda,0x9b,0xb5,0x7b,0x4f,0x69,0xbc,0xbd,0x8c,0xb3,0xd8,0x6f,0x76,0x83,0x92,0xf5,0x9b,0x39,0xfa,0xfa,0x8a,0x21,0x0a,0x65,0x09,0xfe,0x0d,0x60,0x08,0xd6,0x35,0x61,0x11,0xad,0xfb,0x37,0x99,0xc1,0xd5,0x59,0xc2,0x63,0x09,},"\xf5\x4e\x41\xb9\x39\xe3\x7d\xf1\x7c\x7d\x60\x43\xfd\xed\x14\xa9\x15\xd9\x34\xe8\x67\xc3\x45\x26\x9f\xdc\x01\x77\xf5\xbd\x10\xc4\x34\x8f\x31\x9e\x0a\xb9\xa6\x4c\xc0\xb7\xd4\xe0\xc9\x1c\xa9\xaa\xda\xab\x2e\xdc\xba\x54\x4f\x14\xed\x2c\xb5\x39\xca\x89\x75\x09\x7d\x87\x92\x70\x95\xb4\xeb\xd4\x90\x34\x43\x40\x06\x1e\xd9\x3c\x38\x16\x7e\xda\xa0\x96\xa2\x30\xdb\x59\x62\x4c\x67\xfb\x9a\x1e\x1d\xda\xc4\x02\x13\x3f\x4d\x47\xcf\xc1\x1e\x2f\xae\x6b\x3f\x3c\x50\x01\xcb\xa9\xa8\xae\xd9\x00\x73\x10\x32\x40\x22\x7e\x71\x6f\xf7\x1b\xf6\x8a\x59\x1b\xa2\xce\xff\x2d\x31\xb8\x6e\xf2\x1a\xb0\x12\xec\xcd\x40\x9a\xd5\xc2\x9d\x65\x9a\x1b\x37\xc4\xd8\x55\x05\x30\x41\x40\xfb\x2c\x34\x37\xa2\x06\x86\x8b\x13\x52\xc1\x02\xbb\xfa\x3b\x9a\x76\x52\x2a\x2b\xfc\x54\x06\xb2\x57\x69\x6d\xe7\x4e\xe7\xd3\x15\xc8\xe9\x9c\xaa\x96\xbd\x83\x80\x06\xc6\xda\x2a\x42\x33\x31\x5a\x85\x6a\xcb\x8e\x80\xc3\x31\x68\xb3\x33\x55\x1d\x91\xd0\x74\x05\x57\x34\x13\x0b\xd7\xd1\x4c\x56\x81\x1e\xba\xbf\x7d\x5a\x25\x0e\x60\x72\x59\x3d\x9f\x2f\x8b\x97\xc1\x2a\x70\x3c\x2c\x47\x9c\xb0\xb1\x5b\x7a\x27\x75\xc9\xdc\xd2\xca\x46\x24\x67\x23\x68\xa2\xe6\x14\x54\x67\xf3\xbe\x66\x15\xf9\x3b\x81\x20\xa0\xa1\x2d\xa1\x56\x06\x63\xa2\x6a\x61\x73\x19\x66\xb4\x4b\x29\x9e\xbf\xad\x2a\x95\xc6\x23\x60\xf3\x9c\xe0\x5d\x95\x58\xe3\x05\xee\x23\xa5\x2f\xa5\xce\x20\xf6\xbe\x5e\x26\x2a\xff\x3a\x86\x4d\x5d\xda\xbe\x23\xff\x94\x3f\x71\xd5\x99\x84\x93\xd9\x9f\xe2\xac\x23\x74\xb4\x64\xa6\x91\x83\xc3\xbc\x4f\x1d\xdb\x88\x36\x11\x14\x9d\x7d\xdb\xf1\xe8\x38\x0b\x54\x43\x35\xe2\xb8\x93\x95\x05\x4c\x9f\x25\x58\xdf\xc5\x6e\xa9\x3f\xf1\x4d\x0f\x15\xd2\xe0\xbd\x89\x37\xa5\x56\x38\x7d\xe9\x6e\x41\x8d\x8b\x3a\x7d\x66\x6f\xb1\x90\x36\x4b\x2c\x21\x90\xd3\xc2\x5f\x17\x52\xd5\x48\x3d\xcb\xb5\x96\x00\x64\xf0\xc8\x7f\xcf\x8f\x31\x3d\x28\x78\x1c\x11\x4a\x16\x9b\x69\x0a\x87\x01\xc5\x0d\x89\xc7\x73\x24\x53\x1c\x0f\x84\x9d\xba\xd1\x63\x3d\x92\x5a\xcd\x06\xc1\x6a\x9c\xea\x19\xa4\x34\xeb\xc4\x2a\xeb\xb1\xfd\xb9\xb0\xba\xcc\x93\xce\xc3\x99\x19\x94\x36\x64\xea\x1a\x95\x84\x06\xff\x9e\x49\x35\xc9\x2c\xa7\xc3\x97\x08\xf9\xca\xb7\x10\xa5\x83\x09\x6b\x4e\xd9\xf4\x8d\x9e\x09\x06\x47\x24\x0d\x76\xec\xcb\xab\xa5\x91\xf5\x5f\xe7\xe3\x6d\x72\xc2\x17\x27\xac\xba\x0f\x80\x30\x95\x4e\x62\xbc\x58\x0b\x8b\x67\x0c\x44\x57\xc3\x40\x3e\x36\x9a\xc2\x0e\x66\x0d\x66\x2f\x7f\x6a\x41\x42\x13\xea\x43\xf7\xc0\x10\x50\x09\xc1\xde\x81\x7a\xdf\x6f\xfd\x9c\xca\x3b\x45\xa6\x3a\x82\x22\x81\xc6\xe2\x77\x2f\xd7\xb7\x80\x96\x03\x18\x4b\x48\x79\xb1\x8c\x88\x79\x03\xf0\xfc\x8d\x8e\x1e\x2d\xbf\x6e\x77\x2f\x0b\x2d\x9b\x8a\x29\x92\x7a\xcc\x81\x71\x4a\x22\x56\xad\x8d\x7b\x73\x30\x52\x7d\x7d\xbf\x8b\xef\xd8\x2f\x8c\x9b\xb4\x01\xcf\x0a\x90\x24\x9a\x64\xca\x6f\x88\x33\xdb\x31\xbd\x03\xb9\xe7\x94\x6d\x06\xdd\x04\x38\x3d\x7c\x08\x2d\x70\xae\xb3\x7f\xf8\x4c\x2b\x05\x7d\x97\x3b\x89\x4b\x4a\x03\xec\x7b\xf0\x31\xae\xa6\x56\xa1\x90\x84\x88\x89\x4a\x4a\xda\x3f\xd7\xfa\xdf\x91\xed\xe9\x55\x0d\x38\x41\x5f\x82\xa0\x94\x55\xc0\xf4\x32\xfb\x55\x98\x71\x32\xf0\x00\x42\xaf\xd6\x0e\xa5\x1d\x1f\x1c\x6c\x1a\xfe\x0c\xf8\x7c\x34\x6e\x31\xe6\x3e\x26\xf4\x9b\x13\x71\x77\xb2\xd4\x7a\xb3\x0f\x07\xce\xa0\x71\x93\x12\x74\xcf\x01\x08\x36\xd6\x83\xff\xf3\xbe\x71\x34\xc7\x8b\x8b\xfd\x8b\x1b\x8f\xc2\x04\x9e\x18\xcc\xb1\xe1\x8a\x0a\x95\x85\xa7\xd8\xa1\xe2\x54\x92\x60\x86\x68\xc9\x6d\x62\xa0\xac\xa8\xef\x90\xe0\x48\xd2\x03\x78\xc1\x08\xd0\x6b\x03\xfe\x3e\xc4\xad\xb2\x75\x28\xae\x08\xf7\xde\xd9\x48\x78\x93\xae\x64\xca\x4b\x93\x92\x02\xaa\x4c\x17\xaf\xe7\x18\xcd\xca\x49\xff\x96\x16\xd0\xcd\xf8\x33\x4b\x6a\xee\x2d\x6d\x20\x94\x7c\xa4\xbd\x7d\xf5\x31\xdd\x1d\xa9\x95\x81\xff\x72\xea\x56\xfe\x62\xca\xa2\xc9\x5e\x35\x87"}, -{{0xe1,0xc1,0x29,0x46,0xd2,0x21,0xa1,0x94,0xf2,0x2f,0x27,0x62,0xc0,0xe5,0x1c,0xbe,0x3f,0x98,0xb9,0x14,0xa4,0x7d,0x3d,0xc4,0x1a,0x1f,0x45,0xc5,0x43,0x70,0x63,0x7c,},{0x10,0x40,0x81,0x36,0xa6,0x8f,0xc5,0x6c,0x7d,0x3b,0x36,0xb7,0xfe,0xf1,0x22,0x09,0x4d,0xe0,0x81,0x03,0x11,0x89,0xcc,0x84,0xa4,0x88,0x06,0xaa,0xf6,0xcb,0x91,0x85,},{0x8f,0xd7,0xfa,0x40,0x0c,0x03,0x2f,0xcf,0xbc,0x40,0x29,0x42,0xfc,0x78,0x63,0x75,0x26,0xbe,0x97,0xab,0x82,0xf2,0x37,0xbb,0x39,0x3e,0xa3,0x9e,0x35,0x73,0x8c,0x67,0xd7,0x54,0x09,0x54,0x3a,0x8b,0x3c,0x05,0x5f,0x08,0xbf,0x69,0x19,0x9a,0xf6,0x3b,0x69,0x11,0xa4,0x82,0xfb,0x4f,0x65,0x80,0x80,0x2e,0xc9,0xd2,0xdc,0x3c,0x11,0x06,},"\x87\x0f\x4c\xd9\x7c\xfc\x0a\xaf\xad\xa4\x00\x72\x31\x2f\xb5\x4b\xcc\xc0\x76\x28\x71\x4e\x49\x62\xd4\xbe\xf4\xee\xb5\xde\x40\xa1\x9a\x24\x6b\x5b\x7d\x52\xd4\x87\xb7\xe5\x2d\x65\x6f\x2c\x64\x03\xb9\x16\xd0\x2e\x02\xa6\xd2\x91\xc1\xe1\x82\x8d\xd9\x45\xa5\x83\xb4\x38\x52\x8d\x1c\x39\x76\x5a\x57\x20\x31\xff\xa9\x16\xb6\x83\x21\xf3\x2e\x66\x46\xf0\xdc\xc1\xc6\x02\x35\xff\xaa\x32\x35\xf4\x84\xa5\xc4\x97\x8f\xa3\xe6\xbf\x14\x30\x1d\x53\xe1\x2f\x4c\xc5\x21\x18\xb1\xf6\xf0\x7f\x53\x36\xf5\xd0\xa9\x37\x89\xbb\x01\xd1\x62\xfb\x31\x26\xdc\xd7\x56\xe0\x64\x2e\x7e\x69\x89\x63\xc0\x34\x59\x11\xa5\xcf\x3c\x99\x53\xf7\x73\x19\x42\x6c\xea\x2c\xde\xda\x3e\xfe\x98\x9e\xcb\x63\xcb\x9e\xb8\xb9\x20\xde\x76\x6c\x4f\xcf\x63\x36\xe5\xbc\x43\x71\xa0\x68\x37\x1f\xed\x95\xc8\xc2\xb6\x1e\xe9\xb7\xc3\xe3\x83\x1c\x20\xbf\xfe\x87\x07\xc0\xc9\x8b\xe9\x61\x53\xc8\xa8\x73\xd7\xf2\x8a\xfc\xa1\xbf\x71\x08\x5c\xe0\xe3\x89\x9e\xef\x55\x91\xbd\xd6\x66\xdc\x2d\x07\x64\x17\x72\xd7\x45\xc5\x16\x44\xa2\x60\x81\x5b\x20\x8c\x4d\xd3\x05\xf0\x5f\xe4\x63\xd0\xd9\xd5\xa9\xee\xff\x97\x79\xf5\xb1\xd4\x4f\x26\x08\x30\x78\x56\x6d\x0e\x5f\xf5\x6b\x3a\xf0\xe6\x4c\xc3\x87\x08\xaf\x5a\x65\xf6\x54\x35\x2d\xf1\x04\x37\xf1\xdd\xf9\x45\xa0\xda\x1f\x4d\xef\x6a\x71\xa0\x60\xe0\xc4\xad\xec\xca\xac\xf8\x5e\x09\x0f\x70\x90\x37\x0a\xe2\x4e\x52\x38\xd7\x68\xa0\x8f\xe6\xb4\xbb\x5e\xc4\x97\xa6\x60\x31\x98\x60\x84\x15\xc7\xc6\x49\x00\x48\xaa\x36\x73\x7c\x08\x50\x30\x08\xae\xce\x0f\x49\x42\x19\xdd\xf8\x9b\x72\xea\x77\x17\x1c\x6d\x31\x17\x08\x9e\xb8\x89\x07\xe8\xc3\x3f\xb9\xe7\x0b\x0d\xc2\x81\xf6\x64\xb5\xf9\x65\xb5\xd2\xad\xb1\x25\x07\x10\xef\x23\x52\x02\x5f\xb2\x93\x39\x5a\xe1\xd2\x3e\xe3\xb5\x92\xb4\xc5\xf2\xd5\x55\x69\xa5\x45\x86\x54\xce\x3f\xc2\x5d\xd0\xe3\xf7\xe6\x75\x7a\xa7\xb3\x47\xc1\xff\xd3\xba\x4d\x4f\x2c\x4b\x6d\x36\xaf\xd5\x98\x63\xa3\x2a\x59\x4e\x74\x53\x7e\xce\x9b\x8b\x1e\xc2\x69\xbb\xc4\xcb\x54\xd7\x62\x38\x21\x1f\x62\xa9\x8a\x46\xa4\xaf\x66\x2f\xa8\x1e\xba\x6f\x30\xf5\x14\xb8\x66\xb7\x94\x2b\xc1\x73\xf7\x21\x1a\x6c\x01\x4d\xa1\x4e\x74\x13\x27\xa5\x68\x62\x3d\x14\xb8\xf8\x35\xef\x1d\x5d\x62\xb2\x52\x3c\xfe\x6a\x85\xbc\x69\xfa\x05\x20\x0d\xea\xc1\x56\x8b\x94\x6a\x81\x6b\x75\xc5\xd7\x60\x31\x74\xfd\x4e\x2f\x91\x01\xa7\x90\x63\x79\x1b\xc3\xd5\x92\x97\xcd\xc1\x0b\xda\xa6\x63\xab\xf3\xc1\xbe\x2f\xda\x17\xe4\xe5\xce\x39\x4e\x90\xbd\x76\xb1\xf9\xe0\x40\x5f\x56\x75\xb9\x9d\x63\x8a\xbc\x2c\x1b\x2d\x8b\x53\xa6\xfd\x3d\xc8\x37\x58\x55\xec\x54\xcc\xbd\xa2\x4e\x67\x25\x27\x72\x3b\x07\xbb\x59\x9d\xb5\x4e\x38\x79\x33\x91\xcf\x09\xef\x3b\x1f\xd7\x61\x49\x90\x06\x5b\xbd\x4a\x19\xe8\xd3\xd1\x04\x82\x53\xba\x4c\x97\x1c\x2f\x98\xd2\xb3\x59\xdf\x50\x90\x87\x32\x3a\xa6\x90\x50\x29\xf5\xcc\x5e\x1a\x0a\xaf\x2f\x7c\x01\x08\xdd\xb1\xa4\x0f\x56\x2b\xe6\x4e\x57\xe6\x95\xed\x21\xdc\x7d\xb1\x7d\x53\x36\x77\xef\x12\xfc\xbb\xe2\x9f\x3b\x23\x7b\xb6\x34\x4b\x11\x09\xb3\x2a\x94\x62\xab\xc3\xad\x3c\x07\x10\xb0\x4f\x38\xc6\xf5\x95\x2d\xb2\x75\xe7\x7e\x2f\x37\xe9\x5d\x55\x09\x6b\xba\xf3\xe3\x05\xd5\xd7\x43\xd3\x65\x95\xbf\x05\x67\x89\x2c\x21\x0a\xc7\xba\xe7\x37\x1d\x16\x45\x84\x78\x5d\xd8\x90\x17\x41\x59\xb3\x93\x0a\x9a\x6c\xe3\xa1\x66\xdd\xa2\x38\x3e\x6e\x2a\xf2\x8c\x1b\xf3\x19\x24\x47\xe9\x05\x11\xdc\xd8\x0e\xbd\xf9\xee\x2c\x9b\xde\xdd\xee\xb6\x10\x55\x86\x41\x53\x2d\x07\xcd\x13\xda\x61\x25\x41\x54\xcc\x0f\xd9\xd4\x81\xe3\xb0\xa2\x37\xaf\x2e\xc2\x62\x56\xd4\xab\x21\x9f\xaf\x15\xad\x2b\x7e\x8e\x57\xab\x72\x6f\xf2\x72\x32\x16\xa5\x74\x58\x5e\x2a\x63\x9d\x94\x8c\x2c\x4f\x69\xee\xaa\xd2\x83\xe3\xa4\x4f\xf2\x68\xea\xef\xd7\xe6\x6b\x73\xed\xe4\x73\xa8\x39\x7c\x76\xb4\x8d\x56\xcb\x3c\xcd\xab\xc9\x1a\x89\x29\xcf\x42\x99\x83\x50\xe0"}, -{{0x76,0x2f,0x06,0xca,0x01,0xe3,0x14,0x71,0x5f,0x92,0xc9,0x0b,0xbe,0x72,0xa2,0x5b,0xf2,0x62,0x12,0xc8,0x1e,0xb1,0xd1,0xa0,0xda,0xe2,0xc3,0x11,0x30,0xf7,0xcd,0xbb,},{0xf9,0x62,0x6f,0xfd,0x69,0x27,0x31,0x92,0x5e,0x5a,0xac,0xfa,0x1b,0xde,0xd0,0x1a,0xa8,0xf7,0x30,0xb7,0x72,0xd5,0xe4,0x6a,0xdb,0xc3,0x15,0x56,0x5b,0x9b,0xf2,0xc9,},{0xe8,0x42,0xb4,0x9e,0x53,0x3d,0xbc,0x92,0x99,0x8d,0xc0,0x78,0xe5,0x97,0x93,0xa2,0xc2,0xfa,0x63,0x6b,0xdf,0xaf,0xdb,0x48,0x93,0x4c,0x93,0xcf,0x34,0x79,0x71,0x02,0x93,0x8d,0x13,0x7a,0xb7,0xea,0xd1,0xa0,0xf7,0x0e,0x94,0xa6,0x7d,0x57,0xef,0x6a,0x02,0xc9,0xec,0x77,0xd7,0x1f,0x70,0xcc,0x57,0xf1,0x53,0x3b,0xec,0x87,0x73,0x0e,},"\x94\x97\x48\x3a\x4f\xba\x78\x43\x3b\x38\xe9\xde\xb8\x91\x5c\x75\x0b\x6d\xa0\xf7\x8a\xf4\xa6\x8b\x62\xf9\xfc\x03\x91\xe3\x38\x87\x3b\x1d\x64\xb1\xb7\xf0\x9f\x12\xf0\x56\xa3\xc9\x16\x53\x49\x8a\xd5\x6e\x06\x9b\x8b\x16\x08\x87\xe8\xe3\x78\xa7\x6d\x8b\x3c\x66\x70\x83\xc0\xa2\xb2\xd2\x31\x7d\x3b\x87\x48\x57\xe5\x78\x62\xef\x0c\xb7\x04\x36\xa9\x02\x8f\x01\x91\xcc\xc6\x16\xe9\xd7\xc9\xbd\x86\x98\x08\xcf\x09\x48\x35\xff\x51\x86\x77\xb3\xfb\x08\x9f\x4c\x9d\x07\x7c\xc7\x74\x24\x05\xb4\x86\x3a\xc7\xa5\x96\x45\xc9\xcf\x54\x0d\x57\x39\x9d\xa6\xae\x9d\x07\xfd\x19\xfc\xa9\x5b\xc8\xa8\x6d\x8b\x8e\x24\xe4\x87\x33\xf3\x21\x58\xfd\x19\xa8\xa1\x11\x1d\x1d\xa1\xf9\xb5\x80\xa3\x9c\x10\x48\x46\x16\xcf\x2b\xc0\xec\x29\xf6\x3f\x77\xc8\x53\x56\x15\x8e\x16\xda\x59\x4b\x5a\x89\x0e\x55\xd0\xb6\x45\x99\xb3\x02\x93\xe9\x00\xed\x92\xad\x26\x19\x69\xe7\xdf\x4c\x4b\x1d\x0b\x60\x24\xbd\xce\xb6\x90\x67\xef\x48\x6c\x20\xfd\xcd\x22\xa1\x0d\x5d\xa4\x5f\xbf\x90\x5b\xa1\xe9\x35\xc9\x6f\x50\xaf\xb6\x35\x71\xbc\xff\x31\x30\x68\x4e\xda\x0b\x56\xe6\x0b\x26\xcf\x4c\x0e\xf9\x93\x8a\x92\x76\x8f\xc8\x63\x1f\xe3\x08\x23\x6b\x01\x2f\x92\xaf\x24\xa8\xf6\xe6\xec\xbe\x76\x62\x9b\xba\xf8\xff\xe5\x4c\xdb\xe8\x67\x1d\xe2\xba\x62\x4a\x7c\x0f\x61\x93\xbb\xa4\x11\x04\x12\x90\x2b\xac\x29\x90\x92\x2a\x9e\x5a\x81\x05\x3c\xf8\x76\xa4\xc8\x05\xa0\x4c\x56\xa8\x13\x9d\x34\x19\xe4\x54\xa6\x22\xd0\x34\x2b\xf4\x26\xe9\x80\x2c\x3d\xc1\xb4\x08\x0c\x75\x49\x2a\xfe\x9d\x7b\x15\x45\xfe\x08\x6d\x96\x35\x41\x32\x4f\xf5\x2a\x48\xc6\xbf\xae\xa2\x66\x68\xb3\xe0\x1e\x52\x36\xfd\x45\xfe\x54\x59\x45\x35\xc0\xb2\x3e\x28\x7e\xbd\x14\x28\xc8\xbe\x0a\xd1\x41\x60\x0e\x91\xcb\x51\xe1\xea\x66\x27\x1a\x64\x21\xfb\x68\x9e\x88\xa0\x79\x0a\x65\x1d\xbd\x21\xee\x20\x89\xb2\x74\x66\x6f\x66\x0c\xa0\x9c\xe2\xd6\x0e\x39\xe2\xee\x5f\x03\xb6\xeb\x82\xd1\x99\x76\x96\x6e\x79\x90\x0a\x81\x0f\x6d\x5b\x5c\x1a\x54\x8e\x50\x64\xf5\xc3\xd8\xa9\xf2\xde\xf0\x17\x9d\xf9\x9d\x14\x3f\xde\x69\xb0\x71\x2c\x09\x1c\x29\xe9\xb2\x5f\x40\xca\xfd\x57\xa0\x24\x65\x8d\x77\x74\x03\x76\x10\x34\x2f\x38\x00\xfd\x51\xf4\x9e\x79\xa5\xb3\xde\xcc\x11\x2f\x58\xd0\x3e\x3d\x29\x58\x75\x85\x88\xbc\x4b\x1c\x6a\x6c\xda\x7b\xc5\xf5\xbe\x18\x3e\x41\x51\x3c\x1f\x23\x0f\x3c\xc3\x64\x30\x4b\xf8\x24\x84\xb7\xcf\x19\xa0\x02\xe1\x50\xf9\x8c\x5e\x97\xc6\x16\x6e\xa1\x5b\x86\x34\x0b\x8c\x5e\xbe\x5c\x1a\x18\x3e\x55\x88\xe6\x6f\x55\x90\x50\x86\x31\x3f\x37\xa4\x09\xe8\x9b\x47\xdb\x31\xae\x97\x45\x3e\xdf\x69\xfe\xd7\xbe\x08\x11\x30\x71\xf3\x74\xb2\x6e\xc6\x04\x3f\x2a\x0e\x9c\xf8\xba\xd8\x02\xab\xad\x69\xe6\x17\xe7\x62\x43\xb3\xcc\x03\x4b\x09\x9d\x87\x29\xee\x40\x7a\x53\xeb\x03\xbd\xc6\x41\x0a\x03\x95\x04\xb3\xb1\x2c\x81\x9b\x64\x54\x5d\x40\x5c\x6a\x4f\x08\x49\x21\x93\x5b\xdf\xf4\x13\x0a\xe6\x29\xd9\x09\x62\x6b\x06\x26\x76\xe5\x38\xea\xfd\xff\xb1\xd6\x22\x9c\x08\x89\xd3\xcd\xdd\x33\x65\xdc\x3d\x65\x36\xf7\x24\x8c\x49\x31\x7c\xb5\x0c\x56\xfb\x57\x85\x55\x41\xd6\xfe\xeb\xac\x81\x6c\x99\x28\xfa\x66\x2d\x0a\xe8\x0a\x0f\x39\xe5\x70\xbb\x7d\x22\x41\x6f\x98\xf3\x71\xb6\x42\x47\x96\x89\x51\xa8\xa2\x46\xf7\x4b\x30\x61\x74\x3c\x9a\xf7\x68\x4b\xbb\x96\x6a\xe0\xbd\x78\xa8\x10\x49\x3e\xa4\xcc\xd7\x11\x74\x87\x1c\x82\xbb\x65\x2b\x27\x48\xe5\xbc\xcb\x0a\xb6\x38\x8a\x50\xf0\x53\xa0\x48\x08\x7f\xd9\x7e\xb1\x5c\x1a\x21\xb1\xee\x18\x25\xe5\x4a\xa1\x30\xd6\x63\x18\xaa\xf6\x61\xbb\xb2\x47\x63\x57\x7e\xb3\x7d\x31\x0e\x21\x9b\x0a\x9b\xba\x03\x75\xeb\x9c\x9b\x4a\xf8\xc4\xb9\x9a\x36\x99\xe0\xd3\x26\x67\x33\xb6\xe4\xe9\xc5\x34\x49\x0a\x13\x41\xcb\x19\x90\xca\x5b\x1c\x84\x7b\xc8\x12\x60\x26\xfe\xa9\x03\xa1\xf5\x49\xd6\x5a\xf8\xfe\x02\xa9\x16\x3f\xf8\xea\x28\x1e\x72\x26\x24\x3e\x2a\x15\x3b\x92\x18\x51\xde\x10\xf7"}, -{{0xc5,0xcc,0x0b,0x95,0x81,0x8c,0x4b,0xf3,0x8d,0xa1,0xd6,0x5f,0x02,0x16,0x27,0xe9,0xe5,0x7d,0x26,0x2b,0x02,0xec,0x6d,0x91,0x7a,0x7d,0x46,0xb1,0x1c,0x7f,0xe4,0x8a,},{0x45,0x7d,0xa4,0xef,0x14,0x51,0x9d,0x54,0x1e,0xdf,0x92,0xca,0xbe,0xd9,0xb0,0x4d,0x8a,0x2f,0x2a,0xfd,0x15,0x10,0xa9,0x2f,0x00,0x9b,0xb4,0xe8,0x75,0x4f,0x1e,0xba,},{0x3b,0xa0,0xaf,0x8a,0xf1,0x27,0xc4,0x58,0x48,0x26,0x09,0x0e,0xcd,0xaf,0x48,0x5e,0xbd,0xf0,0x7b,0x82,0xbc,0x49,0x9c,0x9a,0x2b,0xef,0xca,0x28,0xd4,0x93,0x44,0x97,0x4a,0xdd,0xbc,0x8d,0x80,0xa5,0x25,0x60,0xe0,0xf3,0xd7,0x3f,0xf5,0xcc,0xcc,0x72,0xc7,0x4b,0x5b,0x47,0xad,0x2e,0x6d,0xe9,0x61,0x2d,0x1a,0x00,0xae,0xc9,0x27,0x01,},"\xd6\x60\x8b\xf5\xac\x00\x0e\xca\xf9\x5f\xc0\x9f\x9c\xb7\x49\x8c\x51\x8a\x6e\x02\x55\x58\x6e\x63\x37\x85\x3b\x1d\x7d\x9d\x7d\xe4\xdf\xe1\x24\x5d\x59\x03\x1a\x31\x7d\x4e\x2b\x6a\x73\xc4\xc3\xf9\x5b\x58\x2e\x72\xa6\x42\x02\x21\x58\x7b\xac\x12\x0f\xb8\xed\x73\x48\x07\x0f\x28\x60\xd8\x58\x66\xa0\x9f\xe7\x56\x74\x34\x97\xf2\x11\x9b\xc1\xbf\xdf\x57\x3b\xe3\x5d\x10\x91\xbe\x37\xf1\x8b\xcd\xa6\x74\x1c\x90\xd5\x66\xcc\x92\x4b\x72\x16\x4b\x74\x9a\xf9\xa6\xf4\x0f\x71\xd3\xea\x5d\x87\x64\xcd\xc8\x17\x14\xbd\x73\x95\xe5\xf6\x79\x97\x36\x36\xef\xf1\xdb\x1c\xf0\x01\x29\x83\xf7\x1a\x2f\x2b\x12\xd4\x5a\x29\x4e\x5a\x38\x9f\x4c\xd2\x48\x3e\xb3\x9d\xa0\xdf\x26\xb7\x36\xc7\xaf\x6e\x41\xdd\x35\xa7\x8e\x45\x29\x2c\x39\x4e\x34\x68\x95\x32\x88\x87\x21\xf8\x63\xc5\x6d\xb9\x7d\xa1\xcd\x10\xa6\x6a\x20\xa6\x70\xb2\x7f\xe8\xce\x55\x68\xa4\x2b\x89\x37\x79\x0c\x7b\xe1\xaa\x42\x0d\x20\x3d\x7a\x88\x5c\x17\x29\xcd\x6b\x8e\x19\x71\x89\xe4\x79\xd5\x42\xcb\xcb\x9b\x53\x65\x6f\x2b\x9f\x53\x9c\x32\x5c\x34\xaa\x59\x8f\xd9\x1e\x7d\xf7\x0f\x9a\x74\xab\xec\x46\x76\x54\xb1\xc9\xa3\xd1\x44\x38\xe7\xc0\x83\x60\x40\xb7\x93\x87\x1e\xcb\xe9\xe5\xf6\x68\x0c\xcc\xcd\x5d\x46\x96\xa8\x7e\x37\xe8\x9e\xab\x28\xb6\xbd\x67\x9e\x8f\xe1\x62\x7b\xdc\x9d\x37\x3b\x82\xf5\x2c\xd8\xc4\x9b\xe9\xba\xcd\xc6\x30\xa3\x2f\xd1\x28\x35\x25\x5a\x54\x2f\xb7\xb1\x23\x93\x77\x9d\x44\x98\xaa\x06\xa0\xe7\xe1\xa4\x97\x79\x39\x81\x7e\xb2\x08\x8a\xf1\xe1\x9b\xb0\xe5\xac\xa8\x54\xc1\x25\xdc\x60\x3d\x83\x57\x36\xa0\x3d\x93\x80\x51\x53\x0c\x9a\xb1\xaa\x3b\xc7\x79\xb3\xba\xe7\x45\x0e\xf5\x7d\x1b\x3f\xc0\x93\xa3\x7d\xbe\x9d\x1b\xd6\xd0\x40\xf2\xf8\xee\xba\x77\xf7\xfa\x88\xc1\x49\xf0\x65\xc7\xac\xe3\x32\x77\xaa\x99\x69\xc2\x66\xea\x6d\x85\xca\xd6\x2c\xfa\xf5\x50\x8e\x70\x32\x71\x6b\xe6\x84\xa2\x28\x56\x41\x3e\x0e\x65\xe4\x2b\x6e\x9e\x6d\x86\x5a\x87\x36\x3c\xbb\x62\xd5\xbb\xb6\xa3\x73\x1d\xdd\xa0\xfa\x6a\xd0\x29\x3a\xf9\x89\x3c\x09\xa9\xe7\x43\x09\x0f\x2c\xee\x2f\x44\x37\x73\x6d\xd4\x33\xe2\xac\x74\x28\xbd\xc8\xc7\x7c\xb9\x96\x43\x55\xfa\x44\x15\xcc\x38\x31\xd8\xc7\xca\x5a\xf9\x3d\x51\x75\x2e\x71\x8c\x60\x66\xec\xa1\x42\x6a\x87\xc2\x98\x08\x28\x1a\x85\xac\x7e\x0b\x40\x44\xff\x6e\x28\x0e\x28\x01\x4b\x93\x83\xd1\x9c\x9d\x38\x7d\x29\xdc\x14\xde\x43\x3d\xa2\x60\x78\x4a\x49\x44\xca\x76\xc2\xfe\x8a\x08\x0d\x09\x96\xd9\xa6\xc2\xa3\xd3\xa7\x07\x72\x80\xed\xce\xe0\x38\x9a\xa8\xe5\x36\x5d\x1d\x9b\x34\x6e\xca\x09\x47\xb0\xff\x52\x65\x94\x3c\xcf\x09\x93\x9a\x4b\x4a\x8f\x98\x5f\x6a\x5e\x72\x72\x3c\x79\x5d\xa0\xbc\x36\x0d\xce\x50\x1f\x67\x3a\xb6\xea\x84\x43\xf1\x29\x42\x79\x52\x45\x3e\xb7\x2b\x3a\x8d\x0d\x97\x6c\x27\x8c\x5b\xd1\xa9\x85\x3c\x91\x8e\x0c\x24\x0c\x3c\x73\x49\x32\x95\x3f\xdb\x50\x39\xfb\xb0\x46\x87\x93\x7c\x9f\xf0\xab\x74\xa1\x6e\xae\x21\x2b\xc6\xf2\x0e\x70\x0a\x77\xc0\x92\xd2\x3d\x2e\xfb\x58\x0e\x0c\x19\xd6\x5f\x30\x41\x29\xab\x8e\x6c\xc1\x2e\x58\x05\x22\x57\xba\x09\x44\x9f\x30\xd3\xd9\x74\x39\x1a\xff\xf5\x63\x3d\xef\x2f\x5c\x4e\xbd\x57\x3a\x9e\x44\x4b\xf3\xa3\xdd\xac\xed\xf0\x2c\x05\xf3\xcc\x2e\x75\x06\x64\xa8\x4a\x1d\x24\xc5\xd2\x8b\x49\x67\x0d\xe8\xa2\xf2\x09\x08\x39\x48\x3c\xa3\x89\x59\x99\x1a\x7d\x37\x27\xe2\x1a\x15\xe8\x20\x16\xc1\x5a\x09\xee\x71\xf4\xf4\x3c\x0a\x60\x8b\x48\x48\x5c\x99\x34\xa3\x86\x14\x79\x4d\x62\x91\xda\xa3\x9c\x01\xc4\x5d\x3d\xeb\xe5\x79\xb5\x82\x3b\xf3\x40\x64\x04\xb4\xc8\x0e\xe6\xff\x34\x2b\x46\xb3\x34\xb0\xb8\x83\xb4\x0b\xfd\x2f\x9a\x53\x59\x5a\xb6\x2f\xd1\x35\x1e\xbc\x88\x30\x83\x70\x49\x72\x18\xdf\xc9\x8c\xe0\x81\x40\x7d\xa8\x12\xa4\x6d\x64\x97\xd7\xaf\x9e\xc6\xd8\x3e\x1c\x60\xee\xb7\x12\xd8\x89\xdf\xbe\xd0\xc8\x05\xaa\x11\xcf\x81\x7d\xd8\xf0\x43\x96\xef\x87\x1a\x26\x11\x2d\xcb\x7c\x0e\x1d\x2e\x68"}, -{{0x61,0xfa,0x86,0x77,0xee,0xda,0xde,0xd6,0x9b,0x16,0x5c,0x8d,0x27,0x7c,0x97,0x82,0x49,0x66,0x30,0x28,0x30,0x1d,0xf6,0x16,0x3e,0x39,0xb0,0x6a,0xc2,0xf5,0x62,0x5f,},{0x87,0x33,0x9e,0xb5,0x72,0x38,0xdb,0x2e,0x4e,0x60,0xf3,0xc2,0x8a,0x3f,0xd5,0xfb,0x61,0x1c,0x65,0xfd,0xdc,0x81,0xee,0xd7,0xcf,0x77,0x71,0xdf,0x34,0xd9,0x22,0x67,},{0xc0,0x4e,0xbd,0x11,0xc3,0xeb,0x09,0x39,0x6f,0xe8,0xd6,0x82,0x79,0x51,0x0a,0x9e,0xfe,0xe3,0x91,0xab,0xee,0x40,0x81,0xf0,0xd2,0x75,0x67,0x4a,0x30,0x47,0x94,0x83,0x5a,0xad,0x7f,0x3e,0x34,0x5b,0xcf,0x0a,0xf8,0x02,0x7f,0x97,0x47,0x7e,0x79,0xe6,0x79,0x2b,0x8f,0x29,0x98,0x46,0xae,0x28,0xcb,0x13,0xbd,0x88,0x75,0x37,0x99,0x0d,},"\x02\xc5\x81\xde\xe0\x3f\x2c\x60\x39\x35\xaf\x5e\xce\xec\xfa\x67\x71\x34\xa3\xe0\xae\xa5\x4f\xec\xaf\x42\x71\xfb\x52\x95\x1a\x27\xb7\x68\x77\xcc\xd4\x9a\xb4\x86\xdf\xc2\x27\xcf\x31\xc9\xd9\x57\xcc\x97\x30\x65\x73\xfc\x7f\xe1\xd3\x1b\x6c\x7d\xf3\xd7\x80\xf3\xa0\x5c\xa6\x39\x56\x57\xa9\x42\x43\x42\xc9\xc6\xb7\x03\x12\x7e\x03\x8d\xf0\x79\x21\x54\xe3\x0a\x49\x47\x61\x12\xcb\x92\xd0\xd5\xa2\xd2\x2e\x89\x57\x52\xa8\x6e\xdd\xdd\x91\x2f\xdc\x81\xb1\xe6\x4a\x7b\xb7\x50\xf0\x99\x18\x21\x32\xee\x48\x23\xfd\xe8\x45\x80\x2a\x94\x45\x39\xd4\x12\xb2\xa8\x1a\x15\xb0\x00\x71\xa9\x50\x50\x4c\x5b\x55\xa7\x1b\xdb\x8c\x5a\x58\x26\x39\xe8\x55\xe8\xbe\x24\x1c\xda\x1b\xa6\xb3\xb4\xf6\x45\x54\xd1\x78\x24\x90\x4c\xb3\x0c\xd7\xef\xd9\xac\x04\x9e\x39\x0b\xb7\x9f\x53\x59\x8e\xf1\xe8\xfc\x27\xdd\x7b\xf5\x99\xc9\x02\x8c\x9e\xbf\x92\xfc\x3b\xe1\x1d\xf3\x29\x61\x2a\x22\x8e\x0f\x56\x84\x68\x7b\xf4\x1f\xf2\x03\xe9\x7a\x76\x86\x12\x6a\x39\x36\x6b\xdc\x26\xd5\x0b\xe0\x25\xd5\x18\x7c\x6b\xa0\x66\x6e\x37\x9b\xe4\xa8\x0a\x9e\x62\xef\xfc\xd9\x16\xd7\xf9\x8d\xe6\x51\xe0\x0b\x97\xad\xf5\xd2\xd5\x3d\xaa\x7f\x8d\x69\x5a\x29\x15\x60\x75\x5c\x74\x44\x82\x36\x4c\x4f\x1f\xa4\x7e\xc0\xb1\xda\x16\x1a\xa3\x88\xf9\x59\x79\x89\xa9\x77\x26\xd3\xed\x2c\xec\x82\xf1\xa1\xbb\xc4\xac\x0b\xe0\xa0\x0c\xb4\xa8\xdb\x1f\xb7\xc1\x4b\xa0\x5d\x89\x63\x48\xdc\x05\x59\xd2\xa9\x0b\xea\xc2\x04\x1d\xd7\x7f\x82\xd6\xb1\x2a\xeb\x22\x43\xca\x0f\x41\x9a\x57\xd3\xca\x9c\x7d\x25\xa3\x0f\xf0\xe8\xbb\x0d\x94\x51\x55\xd1\xb3\x6a\xd1\x07\xb5\x5b\xea\xa9\x5b\x7d\x5e\x32\x00\x34\x07\x62\x9f\x15\x15\xf8\xa7\x08\x9e\x24\x88\xd0\xd7\x54\x4c\x2f\x7c\xc7\xc7\xf0\x98\x5d\xa4\x28\x40\xd4\x36\x8f\xf4\xf0\xfa\x4f\xa2\x98\xe3\xb7\x22\x93\x03\xab\xa5\x14\xae\x94\xe7\x02\x65\x35\xa3\xf4\x26\xff\xbb\x4e\x00\x1c\xd5\x0e\xd1\x2f\x21\x4b\x3a\xbe\xf9\x6e\x30\x16\x35\xc9\x87\xb1\x33\xfc\x5e\x61\x84\xe7\xb7\x57\x2b\xc3\xd9\x9a\x45\x23\xcb\xd5\xaf\xe5\x93\xce\xdf\x4c\x9c\xd0\x2f\xf2\xe3\x62\x37\xe4\xee\x12\xef\x1a\x22\xd1\x6d\x7c\xf4\xc0\x72\xdc\xed\x91\xcd\xd2\x6e\xe1\x44\xcc\x2b\xef\x49\x50\x02\x63\x49\xe9\x44\x47\x84\x08\x1f\xe4\xe0\x49\x8b\xc7\x5f\x72\xe6\x81\x8f\x45\x9b\xba\x90\x49\xc5\x61\x31\x6c\x9f\x49\x8e\x7b\x1a\x99\x4b\x0e\x93\x05\x5f\xe7\x3e\x44\x4c\xbd\xf9\x6a\xc3\x5e\x9c\x4e\x92\xe6\xb4\x9e\x3b\xc0\xe9\x9d\xe1\x71\x6d\xf8\xea\xca\xeb\x8d\x2f\xd7\x48\x70\x04\x4c\xb3\x9c\x0e\x36\x7a\x1f\xe3\x2a\x9b\xb2\x97\x44\x16\x36\x4e\x73\x0d\x52\x48\xdf\xb1\xdf\x16\x4a\x8d\x58\xca\xa1\x00\x5f\xdc\x91\xba\xc2\xbc\x01\xcc\x77\xde\xcc\x14\x89\x3e\xf9\x46\xfb\x3c\x81\xbe\x08\x32\xc7\x2f\xba\x37\x20\x62\xf8\x36\x0f\x4d\x8e\x6d\x5b\x74\x1c\xf7\x03\x2d\x8d\x89\xde\x2e\xdf\x4c\x71\x4a\x29\xf7\x5a\xbd\x8f\x5f\xf4\x3e\xcd\xd4\xb7\xa0\x4d\x7d\xb0\x88\x2d\x16\xe7\x44\x73\xa0\xfb\x79\xdb\x44\x4a\x78\xea\x44\xaa\x26\x31\xb8\xc0\xd7\xb0\x30\x0d\x55\xcb\x6a\xc4\x85\xf2\x4c\x0a\xcc\x64\x77\x47\xc4\x3d\xb3\xb2\xa8\x67\x7b\xaf\x65\x6f\xa7\x35\xa5\x75\xf1\x81\x3f\x36\x68\xa2\xac\xa9\x17\x57\x11\xb5\x25\xeb\x49\x6e\x9e\xf9\x71\x1d\x75\xf5\x90\xc7\xd9\xef\x99\xe0\xf5\x9e\x84\x83\xcb\xf9\xf2\x84\xe3\xf5\xa3\x3e\xe7\x78\x1e\x62\xb8\xb0\x55\x51\x77\x7e\xfe\x0f\xbf\xd1\x9e\x54\xb6\xbb\xd1\x42\x94\x4b\xc2\x95\x9a\x82\xeb\xd2\x95\xd2\x3d\x34\x43\xb6\xce\x65\x8c\x2d\x57\x9a\x76\x37\xb5\x49\x52\x04\x91\x90\x8e\x34\x28\x2e\xc2\x71\x69\x72\xe6\xf0\x35\x39\x29\x54\x7e\xf1\x53\x7a\xec\xc9\x6b\x2d\xf6\x16\x14\x85\x99\xb0\x9d\x9b\x81\x39\x4a\x13\xfe\x7d\xb8\x67\x60\xb1\xe2\xa0\x60\xef\xd4\x84\xe8\x18\x99\x39\xeb\xdf\x6f\x21\x64\x0d\x89\xd8\xe7\x36\xde\xe0\x82\xad\x72\xa0\x18\x4a\xde\xdd\x8d\xf2\x14\x74\xc9\xf5\x26\xbc\xfd\xf7\xe8\x56\x58\x19\x4b\xb6\xd9\x42\xe7\xf3\xfe\x96\xc2\x3f"}, -{{0x70,0x48,0xc6,0x52,0x1a,0xef,0xaf,0xa4,0xea,0xc6,0xd6,0xc3,0xa7,0x02,0xb9,0x52,0x54,0x80,0xa6,0x64,0x82,0xe4,0x96,0x98,0x96,0x75,0x7f,0x2c,0xd1,0xac,0x7d,0x5b,},{0xed,0x93,0x11,0x3c,0x16,0x43,0xa5,0x3a,0xa0,0x64,0xca,0xa6,0x31,0xce,0xb6,0xe2,0x0f,0x6d,0x6e,0xc2,0xfc,0x6c,0x07,0x11,0xcb,0x8a,0x1f,0xe7,0x31,0x39,0xaf,0x93,},{0x7c,0x45,0x70,0x3e,0xd3,0x94,0x2e,0x44,0x04,0x1c,0x7f,0xa1,0x85,0x8a,0xa5,0xf1,0xdc,0x38,0x1f,0x49,0x3a,0x45,0x2d,0xfb,0x52,0x70,0x80,0x17,0x89,0x8f,0x71,0x0e,0x31,0x11,0x8e,0x33,0x1f,0x00,0xaa,0x64,0xcb,0x73,0x88,0x36,0x68,0x2b,0x7d,0x17,0x7e,0x97,0x95,0x5c,0x00,0x31,0x9a,0xbd,0x79,0xa4,0x9e,0x0f,0xcd,0x16,0xfe,0x00,},"\x53\xf7\x4c\x72\x4d\xb1\x57\x8a\x1a\x29\x6a\x7c\xca\xc9\x04\xa2\x50\x4d\xd9\x00\x53\x89\xb4\xf8\xd4\xea\x4b\x63\x07\x29\x8f\xc6\xdc\xce\x98\xa6\xbc\x07\x28\x0d\x20\x36\x4e\x40\x5a\x46\x7e\x73\x65\x78\x96\x52\x69\xc8\x14\x61\xd6\x1f\xc6\xb7\xe4\xba\xd6\x8d\x2b\x6d\xd0\x00\x58\x50\x10\x5f\x0a\x67\xbb\xc6\xee\x22\x3e\xc1\x75\x4a\xf4\xe3\xb9\xaf\xa5\x06\x2d\x1c\x18\x61\x04\x8f\x18\x5b\x12\x8f\x1a\x5c\x0f\xb2\x5c\x39\x19\xb4\x83\x3e\x29\xe2\x02\xbc\x94\x1a\x90\x5e\x63\xc2\xc0\x5b\x10\x14\x64\x7b\xd7\xed\xe5\xbe\x9f\x99\x66\x15\x18\x7a\x3d\x3b\xb2\xc7\xdc\x4c\x28\xf7\x05\x3d\xef\x9b\x28\xb2\x9e\x23\x31\xf1\x62\x96\xdc\xe8\xf1\xed\xe4\x84\xca\xec\x99\x67\x02\xbd\x99\x02\xe5\x26\x84\xc8\x12\xc8\x74\x40\xf6\x9b\xd1\x41\xc7\xe0\x0c\x69\x47\xd1\xfc\x7c\x3b\xdc\x0b\xc5\x50\x6b\x6e\xa4\x62\xe6\x5f\x9e\x74\x3b\x72\xc0\x07\xdd\xc7\xa3\x77\x49\x37\x77\xd4\xeb\x12\x62\x0c\xa6\xc0\x19\xc8\xbf\xc4\xc2\x9e\xc8\xaf\x38\x2f\xc3\xea\xc8\x41\x02\x1a\x74\xe4\x67\x4b\xa3\xe4\x3e\x5d\x7b\x41\xe3\xfe\xeb\x17\xda\x00\xa7\xce\x45\x5a\x1c\xec\x70\xb0\xbe\x6e\x56\xf8\x5f\xc3\x7f\x64\xcf\x07\x33\xb7\xe3\x12\x41\xde\x64\x1a\x8a\x8e\x5b\x91\x89\x7b\xc1\x58\xfe\x93\xd1\x02\xc0\x1d\x1f\x5e\x16\x6d\x40\x81\x65\xfe\x3f\xcb\x13\xd5\x30\x45\x90\xab\x8e\xf0\xdc\x8d\x5a\x8c\x1d\x8a\x93\xfc\xeb\x85\x4f\xc1\xfa\x36\xd0\xcc\x48\x0c\xf8\x51\x2d\x80\xbe\xe6\x9b\x06\x50\xa9\x57\xda\xed\x28\x3c\xd7\x63\x81\x55\xed\x77\x30\x86\xe8\x6a\x8f\xfb\x19\x8a\xcc\x74\x23\xb5\xd1\xa6\x09\xa1\x75\xa5\x6b\x94\xc9\x6b\x73\x18\x51\xb9\x3a\x94\x97\x71\x01\xe2\x55\xf1\xce\x92\xe2\x32\xa0\x5e\x2e\x33\x87\xfc\xb4\xdc\x13\xa3\x1b\xee\x6e\xe2\x55\x07\x32\x2c\x73\xc9\x88\x30\x80\xa7\x4c\x00\xf8\x03\xa9\x98\xdd\x53\x0a\x79\x12\x6b\xb1\x44\xed\x55\x74\xc4\xb2\x31\x80\xe3\x4e\x09\x92\x83\xb4\xbb\x1d\x28\x82\x2f\xce\x37\x17\x04\x6f\xf3\x2e\xf9\xe2\xcd\xf9\x67\xe3\x18\xea\x72\x6a\x2a\xee\xc5\x78\x06\x64\x3a\xd4\x80\x1d\x3e\x0d\xa5\x2a\x1d\x77\xbf\x04\x3f\x5a\xe9\xf3\xae\xa9\xe4\xbc\x4f\xa7\x95\xd0\x84\x01\x08\x5c\xa9\x4c\xfc\x4c\xe7\x19\xda\xbc\x7b\x23\x90\xd0\x3d\x29\x4a\x65\xb7\xaf\x9b\xc3\x90\x72\x28\x5b\x77\x7b\x2f\x13\x3d\xc1\x1a\x70\xc0\xa9\xf0\x60\xe1\x04\x41\xf4\x02\x16\xac\xb6\x41\x63\x7a\x2e\xad\xf1\xf7\xb8\xd2\x62\xfe\xc1\xb4\xd0\xf0\xf4\xfa\xa9\x3f\x3f\x73\x2c\xac\x38\x2d\x8a\xc4\x2e\x17\x8e\x22\x44\x99\x9d\x76\x4a\x9d\x0e\x98\x17\x14\x68\x6e\xb4\x92\x44\x97\xe5\x6b\x50\x15\x7e\x99\x39\x03\x2c\x9f\x88\xeb\x65\x7c\xfd\xe4\x4a\xd3\x47\x14\xaf\x4a\x51\x32\x4e\x5e\x77\xd0\xde\xea\x99\xc9\xf2\x44\xd2\xe0\x9e\xa4\x25\x82\x0a\x74\x6d\x88\x3a\x0c\xf4\xb7\x05\xc2\x9d\xf8\xc0\x37\x44\x81\x54\xdc\x08\xa4\xd4\x33\x74\x05\xfb\x87\x65\x82\x31\x14\x37\x0b\x37\xed\x86\x08\x6e\xc5\xf8\xbd\x6c\x72\xab\xf1\x3f\x51\x84\x30\x71\x0f\x59\x7b\x06\x10\x8f\x65\xb3\x0a\x48\x34\x96\xe2\xed\x81\xda\xb1\x0f\xee\x94\x7f\xe0\x4b\x54\x85\xf2\xe3\x07\x40\x49\xd2\x22\x84\x26\x66\x51\xad\x10\xdd\x08\x6a\xaa\x5d\x45\x2e\x0d\x1a\x61\x12\x9d\x1e\x77\xc6\x63\xc2\x6d\x08\x89\x62\xb5\x54\x56\x45\xb7\xa1\xa8\x71\x3d\x51\x32\x7a\x7a\x35\x9b\x12\xda\xad\xb8\x5a\x2c\xd4\xb5\x41\x0d\x5c\x20\x26\x7f\xa7\x66\xb8\xc4\x2a\x84\xdc\x42\x66\x45\x88\x87\x9b\x3e\xae\xfd\x4c\xc8\xdc\x69\x3f\x98\xac\x20\x56\x09\xe5\x70\x66\x5b\x01\xea\x46\x55\xe3\x94\x29\xa7\xa7\xe5\x42\xef\xb4\xf7\x89\x0d\xbf\x4e\x34\xc6\xcf\xf0\x7e\x4d\x35\xbd\x3e\xee\xdf\x5b\x46\x28\x0f\x4a\x0d\xa0\xc2\xe7\x3c\x94\xea\x81\xcf\xea\xe7\xf9\xbd\x04\xfe\x2d\x45\x97\x65\x00\xf7\xdc\xac\xb0\xdf\x2a\x5d\xc7\x36\xa8\x23\x67\x1d\xb6\x79\xbe\x66\xcb\x33\xc1\x62\xfd\x2c\x74\xae\x71\xfb\xf4\xd2\xb0\x5a\xf0\x42\xb3\xa9\x77\xf5\xb9\x44\xb9\xfd\xb6\xc3\x44\x24\x42\x1b\xcf\x4f\x62\x23\x76\x84\x28\xfa\x14\x0f\xd4"}, -{{0x3e,0x63,0x73,0xb2,0x65,0xb9,0x67,0x89,0x00,0x7a,0xd2,0xa1,0x0c,0x30,0x9a,0x56,0x76,0x38,0xf2,0x55,0x87,0xd7,0x7e,0x28,0xb0,0x82,0x3a,0x4f,0x17,0x9a,0xe4,0xfe,},{0xa3,0x23,0x4e,0x5d,0x13,0xb0,0x34,0x72,0x16,0x50,0x36,0x40,0x4f,0x6d,0xe8,0x0e,0x70,0x28,0x39,0x50,0x0f,0x13,0xd9,0xc9,0x85,0xa0,0x77,0xd4,0x5c,0x69,0xff,0x45,},{0xf5,0x1e,0x0f,0x87,0x8a,0x5a,0x70,0x96,0x47,0xe8,0x5f,0xea,0x83,0x9f,0xd5,0x66,0xe6,0xf3,0x5c,0x8a,0x61,0x85,0xd0,0xc9,0xeb,0x13,0xe0,0xd5,0xb9,0xe6,0xe8,0xaa,0x95,0xc3,0x33,0xa8,0xf5,0x06,0x32,0xa4,0xd6,0x65,0x7b,0x51,0x8c,0xe4,0xcf,0xde,0x40,0xb8,0xf5,0xa0,0x5b,0x2d,0x9f,0x84,0x41,0xfc,0xc9,0xd2,0xd6,0x92,0xd5,0x09,},"\xb9\xd0\x68\xbb\xca\xe7\x72\x2f\x82\x8b\x0f\x8c\x98\xa7\x38\xe3\x6a\x7d\xf4\xc9\x97\xc7\x24\xba\x27\x53\x1a\xf3\x4a\x2f\x10\x6c\x75\x13\xa4\x4a\x46\x1a\x9a\xa4\x30\x9b\xc1\x5c\x4e\x0d\x42\x75\x91\x93\xea\x1c\xde\xa9\x56\xbb\x81\x59\x85\xf5\x78\x67\x14\x5e\x9e\x2c\x75\x85\xfc\x8d\x61\x02\x7e\x47\xd2\xd7\x35\xe2\x44\x8a\xf3\x78\x29\x09\x40\x4e\xde\xaa\xc0\xfd\x73\xf6\x04\x5d\xcd\xb0\x4f\x03\x77\x75\x8f\x02\x20\x4a\xae\x3a\x72\x20\x31\x1c\x0f\x47\x23\x58\x27\x10\xcc\x44\x0c\x36\xc9\x58\x7b\x5c\x9e\xbc\x40\x63\xfe\xa8\xca\x3f\x43\x19\x58\x94\xf7\x9a\x36\x50\x87\x13\x72\x82\x30\x2d\xbf\x2e\x7a\x0d\x41\x1a\xb5\x8b\x70\x26\xcc\xde\x19\x88\x69\xaa\x73\x43\x34\xc0\x52\x38\xe2\x75\xe3\xc3\xab\x21\x70\x83\x49\x57\x69\xe2\xfa\xd3\x74\x05\x14\x52\xd7\xf5\xb1\xdb\x0e\x78\x58\x36\xd4\xbd\x5e\x29\x78\xa3\xe9\x91\xaf\x0f\xf7\x16\xf4\x38\x89\xa0\x7f\x5d\xf2\x99\x60\x36\x21\xc3\x9e\x2c\xde\xe0\x89\x98\x5d\x9e\x6b\xf7\xb2\xfb\xd0\x23\x73\xae\x1b\x5e\x9b\x88\xf5\xb5\x4a\x07\x6e\x67\x6d\x77\x90\xbf\xc8\xf5\x7d\xcc\x59\xef\x52\x85\x0c\xe9\x92\xa7\x3b\xa7\xbc\x99\x1d\xeb\x4d\xde\x5e\xb0\xb2\x16\x70\xb1\xb3\xd4\xb6\x4f\x36\xcc\xa8\xe3\x07\x09\x85\x68\x49\x7d\x89\x16\xf6\xb5\xd0\xe9\xe8\x9f\x99\xf8\x60\x06\xf3\x9b\xd3\xa8\x10\x76\x9c\x8f\x78\x01\x77\x3c\x96\x38\xab\xcf\x5e\x27\x11\xb1\x9d\x11\x67\x59\x3a\xcb\xe8\x5e\x41\x61\x42\x89\x97\xa2\x19\x4d\xc5\xe7\xb7\x64\x0f\x0d\x2c\x1e\xb2\x05\x55\x3b\xe9\x16\x7f\xfb\xc2\x2b\x7c\x2e\x76\x98\xf3\xaf\xa1\x07\x54\xcb\x44\xd4\xb1\xd4\x5b\x83\x73\x03\xb1\x66\x90\x73\x41\x5a\x22\x60\x6b\x50\xf2\x1f\x82\x65\xe1\x39\xf2\x30\x5a\xc0\xe0\x12\x7a\xe0\x56\xce\x8a\xbe\xab\xa2\x0e\x1d\x26\x9a\x2b\x2e\x89\x9c\x49\x54\x72\x68\xa0\x69\x6a\xe4\x50\xdc\x02\x67\xf7\xf6\x3a\x8e\xdf\x07\x4c\x47\xd3\xc2\xdb\x1d\xa3\x63\x93\x73\x73\x04\xe6\xdd\x4f\xac\xcd\xb6\xab\x55\xe5\xf8\x52\x0c\x3d\xff\x5f\x6b\xea\xc3\x0b\xa8\x5b\x86\x08\x23\x51\xe3\xde\xd8\x40\x0a\xa5\x7f\x65\x0c\x0c\x33\x03\x6d\x65\xb3\x9b\x7d\x2f\xb6\x11\x28\x63\xd5\x9b\x72\x55\x82\x42\xe8\xb0\x45\xad\xdd\x35\x7d\xe6\xfd\x37\xa8\xf6\x61\x17\x65\xc9\xb5\xff\x19\xcc\x4d\xb7\xe1\x17\xc6\x5a\x00\x45\x89\x08\xb0\x24\x5d\x04\xf7\x90\x8f\xc7\x3b\x16\x5d\xff\x6e\x4b\xe4\xb4\x20\x32\xd8\xcf\xd7\xd6\xf7\x77\x2c\x1b\xfe\x72\x1d\x4b\xcf\xe2\xfc\x52\x79\x98\xf3\x4f\xb4\x41\x8a\x1f\xae\x1e\x6c\x37\x67\xc4\xd0\x78\x06\x21\xf9\x23\xda\x1f\x0a\x0d\x3d\x21\x9c\x03\x6a\xcf\xd3\x70\x9d\xad\x4c\xf2\x4d\x90\xbc\x69\x1d\x70\x0e\x6a\x9c\x80\xcc\xfd\x10\xbd\xe8\xe7\x91\xc0\xfe\xa8\x28\x80\xc0\x7b\xaa\xaa\x31\x1e\xef\x79\x24\x07\x84\xf6\x28\xa7\xd2\xa0\x91\x84\xe0\x16\xf8\x10\x08\xe7\x74\x29\xa8\x65\x8b\x15\x3e\x44\xe7\x9a\x98\xad\x24\x8f\x7f\xda\x23\xb5\x90\xd6\x46\xd7\xc1\xd8\x41\xf4\x92\x7d\x6e\x8b\xc7\x32\x14\xd1\x0a\x7f\x3c\x29\xc8\xf8\x39\xa8\x90\x8d\x20\xa7\x4e\x82\x7a\xf4\x67\xac\x5a\xbf\x0f\x1d\x0e\xd3\x9c\xdd\xd9\x69\xdd\xe9\xee\xb4\xa4\xb7\x52\x7a\xb3\xe2\x47\x5a\x19\x5e\x24\x47\x4a\x4e\x36\xb0\x90\x52\xe2\xda\xd4\xa5\xeb\x46\x91\xe2\x63\xb8\xc6\x1b\xbd\xe8\x77\x72\x20\x7e\x01\x1c\x4c\x1e\x14\x23\x5f\xb2\x4e\x4d\xa4\x38\x87\x5d\x18\x53\x0f\xef\x90\x26\x19\xdd\x48\x5d\x77\xb5\x45\xab\xb5\x6b\x69\xc7\x55\xaf\xe7\x58\x60\x69\x71\xab\x97\xdd\x3a\xce\x1c\x1a\x34\xa3\x37\x94\xc8\x15\x6d\xa7\x99\xe8\x22\x4d\x88\x5e\x18\x68\xf9\xcb\x46\x6d\x80\x2c\x82\x7c\xc3\xe1\xec\xd0\xae\x6e\x0b\x01\xf8\xf7\x91\xb1\x22\x08\xfc\xc0\xfe\xd3\x85\xb7\x96\xeb\x2f\x29\x08\xb5\x8d\x30\xb3\x73\x3f\x14\x70\xf2\xe2\xef\x12\xad\x43\xfe\xb7\x2d\x08\x16\xde\x3c\x13\xa8\xb5\xa5\x23\xe1\x4c\xdf\x5f\xf3\x72\x0b\xf8\x77\x69\xcd\xe7\x49\x5d\x22\x6b\xf3\x82\x38\xa8\x25\xf7\x5a\x09\xf6\xbb\x9a\xfc\xe5\x16\xa7\xbc\x70\x11\x43\x70\xbb\xc4\x0f\x17\xc7\xbc"}, -{{0xf5,0xe8,0x59,0x7e,0xac,0x0e,0xbf,0xa9,0xd3,0x85,0xde,0x85,0xa1,0xfb,0xaa,0x35,0x14,0x63,0x95,0xb1,0x34,0x57,0xb5,0xb1,0x4d,0x36,0x70,0xda,0xca,0x69,0x05,0xe7,},{0xce,0x93,0xe6,0x42,0xc2,0xf1,0x50,0x84,0xbc,0x83,0xba,0xfd,0xaa,0x19,0x67,0x63,0xde,0x2a,0x3c,0x51,0x3b,0x0e,0x44,0xf6,0x8d,0xdb,0xde,0x37,0x85,0x14,0xc4,0x41,},{0x57,0x65,0x43,0xfc,0x21,0xab,0x0a,0x7c,0x5f,0x63,0xb1,0xcf,0xf0,0x1b,0xf8,0x45,0xdf,0x91,0x79,0x2e,0x7a,0x97,0x50,0xc5,0x50,0x8b,0x51,0x66,0x5e,0x7f,0x89,0xf1,0x7c,0x6e,0xc3,0x35,0x5a,0x0a,0xed,0x87,0xdb,0x8c,0x77,0xbd,0xb2,0x71,0xfb,0xed,0xc7,0x14,0xff,0xad,0xb7,0x8b,0x5e,0x0f,0x97,0x81,0x16,0x77,0x1b,0xa7,0xcf,0x0b,},"\x27\x33\x41\xf2\x19\xff\x5c\xf3\x81\xc7\x7b\x2d\xd2\x26\xc5\x8f\x8f\x33\xc4\x52\x70\x48\xcb\x00\x6a\xff\xef\x8c\xee\x15\x1e\x30\x0e\xfe\xf6\x29\xfe\xd2\x1b\x70\x45\x1f\x72\x92\x92\x62\x7d\x1f\x3f\x1b\x52\x57\x35\x9e\xe5\xa6\x71\xcf\x62\xae\x57\x32\x49\x40\xf2\xd0\xb1\x5a\xac\x76\xff\x39\x82\x20\xc0\x80\x24\xe2\x9a\x8c\xf3\x65\x04\xe1\x2a\x4e\x96\x43\x8f\x42\xc3\xda\x0c\x00\x05\x41\xbc\x11\xf0\x91\x38\x1b\x0b\x72\xb5\x8a\x92\x08\x3f\x44\x6e\xca\x19\x91\x99\x68\x78\xde\x35\x08\x1c\xc4\xab\x90\x95\x8c\x96\xcf\x5c\x99\x79\x6c\xba\x79\x51\xee\x18\x6f\x26\x52\x7a\xed\xe6\x9d\xb3\x04\xce\x29\x41\xba\x15\xcc\x00\xba\x2f\x14\x11\xf2\x08\xda\xd4\x5e\x87\xbc\xf6\x38\x79\x2d\xe0\xa6\x86\x24\xb6\x67\x29\x7c\x27\xa3\x43\xdb\x4b\xaf\x34\xa0\x22\x8e\xaf\x0d\x10\x22\x00\x9b\x5d\x06\x8b\x25\x34\xd9\x20\x30\x2e\x71\x31\x0f\xeb\xf0\xdf\x1b\xb0\x2c\x2e\xf0\xad\x1a\xe1\x49\xde\xad\xf8\xc1\x84\x37\x3c\x0f\x7e\xb6\xb2\x56\x95\xbe\x82\xd1\x2c\x71\xb6\xc8\x32\x67\xd9\xa2\x33\x66\x7e\x77\xbc\x20\x59\x83\xf8\xb8\xd8\x77\xd8\x5a\xea\xd3\xf6\x0e\x82\x0f\xfc\xb1\x7a\xdd\xdd\x92\xa7\x71\x2b\xbe\xb3\x4e\xe7\x19\x66\xda\xfd\x99\x07\xd1\x93\xdd\x9d\x72\x5a\x31\xa6\x13\xd2\x9e\x32\xbe\x72\x13\x28\x08\x92\x6d\x94\x37\x47\x7f\xee\x25\xed\xa6\x10\xae\xb1\xdc\xe1\x2e\xa3\x16\xc6\xae\xc6\x68\x9e\x50\x1c\x55\x19\x23\x82\x5a\x34\xb4\x2c\x4f\x06\x75\xb8\x6a\xb2\x6a\xde\xea\x2e\x60\xda\xe6\xc6\xd1\xcd\xd0\xcb\x3c\x34\x7b\x16\x38\x40\x39\xa8\xe3\xfd\x60\x87\x38\x13\x87\xcb\x4b\xc7\x2d\xdb\x5f\x25\xb3\x74\x85\x9b\x02\xe5\xbb\x1b\xa0\x6d\x3c\xc6\x9e\xc4\x4c\xec\x4b\x98\x5c\x84\x76\xe3\x50\x32\xe9\x9a\xbf\x00\x1a\x1d\x44\xdd\xc6\xe2\x88\x9c\x3c\x2c\x3e\xca\xce\xd6\x09\xb2\xb2\x68\x0e\x00\xb1\xef\xa7\xe9\xd2\x6d\x62\xf2\xb3\xab\x36\xf9\x21\x04\x47\x90\xab\xbd\x49\x36\x07\x56\xdc\xff\xcc\xf2\x30\xf6\x6d\xbb\x70\x1a\xa1\x64\xda\xd6\x06\x9a\xa2\xb8\xb3\x30\x9f\x2f\xe4\x4d\x5e\x0b\x25\xbd\x55\x64\x31\xf0\xdf\x4c\x2e\xa9\x7a\xe7\x9e\xd4\xa5\x75\x78\xd6\x6f\xc6\x93\x9c\x57\x62\x8a\x90\xca\xc9\x7a\xdf\xa8\x70\x2a\x4a\x1c\x89\x65\xba\x1a\x90\x26\x25\x67\x28\x66\x64\x00\x30\x03\x53\x3c\xc9\x31\x4c\xaf\x7d\x3b\x98\x2e\x0a\x43\x2f\xf5\xaa\x4e\xd5\x74\x19\x83\xd9\xb5\x43\x23\xac\x7e\x29\x9b\x2b\x49\x56\xc1\xa2\xc1\x91\x55\x7b\x27\xd8\x6b\xe7\x14\xb5\xb6\x8f\xcb\x1d\x41\xf7\x8c\xa5\xdd\xb6\xb5\x3b\x3d\xfc\x8e\x7d\x6b\x3c\x3d\xb0\x59\xaf\x9f\x2d\xd7\x65\xef\x04\xb6\xd1\x6e\x67\x37\xc7\x27\xaa\x11\xf3\xdf\x37\x74\xa3\xfc\x96\x18\x2e\x28\x2a\xcc\x3d\x23\x3e\xea\xbf\x8c\x72\xd3\xf2\x46\xae\x18\x45\x05\x28\x8f\xef\x39\xb3\x67\x66\xb1\x0d\xd1\xbf\xbf\xbf\xa7\x0f\x97\xb3\xc9\x01\x72\x6d\x1e\x0d\x0a\x83\x7d\x11\xf0\x12\x3a\x34\xab\xad\x1a\x79\xaa\xbe\x80\xb1\x25\xb1\x28\xee\x16\x0b\x51\x18\x48\xf7\xf0\x4c\x49\xc8\xd5\xc2\xf2\x04\x1d\xa7\xd9\x59\x9c\x29\xb1\xda\xc8\xc6\x80\x77\xef\xac\x3e\xca\x58\xbb\xc1\x63\x7a\xad\xce\x21\xc7\x74\xfe\xa4\x2d\x2b\xcf\x4a\x0b\x98\x92\x30\x7e\x36\xfa\x25\x0a\xce\xe7\x95\xad\x2b\xfe\xcf\xbf\x60\x31\x9b\x81\x66\x3e\x2a\x26\x57\x19\x46\xf7\x5a\x8d\x96\x9a\xf1\x6b\x3b\x57\xc3\xec\x3e\x66\x15\x8a\xaf\x42\xcc\xf5\xe5\x8b\x93\x7a\xae\xf6\x13\x31\x86\x06\x60\x33\x17\xe5\xaa\x31\x8b\xe7\x0f\x8d\xa3\xc0\xc1\x6b\xe6\xc2\x9e\x3e\xc9\xfe\xf4\xe4\x6e\x8c\xa2\x41\xd9\x41\xd5\x80\x49\xa0\x63\xd9\x0a\xfc\x95\x3c\xa3\x2e\x8a\x50\xa6\x47\x36\x32\x58\x8a\xc4\x1e\xae\x97\xf2\x0c\xe9\xb7\x41\xed\x41\xc9\xa4\xaa\x65\x51\xfd\x82\x3c\xe0\xc8\x11\xa5\xbb\x5a\x17\x1c\x1e\xa4\x23\x8a\x02\x46\x81\x1e\x46\x9c\xf4\x98\xb7\x96\x21\xc3\x23\xeb\xa7\x98\x53\x44\xfe\x11\xe6\x74\x99\xed\xf4\x96\x74\x91\xaa\x74\x9f\x8f\x3f\xe3\x99\x61\xd7\x68\x92\xc9\x3a\xac\x3b\x19\xfa\x4b\x4f\xc1\x74\xd7\xd4\xd4\xd8\xbd\x6e\xe4\x75\x47\x50\x08"}, -{{0xcd,0xad,0xc5,0xb8,0x9c,0xb2,0xb6,0x30,0x8a,0x00,0x6f,0x2f,0x4e,0x95,0x5a,0x91,0xaa,0xf3,0xba,0x70,0x16,0x5f,0x2d,0x44,0x4e,0xf1,0xff,0xeb,0xbd,0xaa,0xa2,0x21,},{0x05,0x41,0x41,0x5f,0xf5,0x46,0x7f,0x28,0xce,0xac,0x83,0x9b,0x13,0xa1,0x76,0x6e,0x72,0xc9,0x9e,0x65,0x45,0x20,0x7d,0x9d,0x5d,0x96,0x97,0x41,0x1e,0xb6,0xbc,0xa7,},{0xff,0xed,0xe7,0x01,0xeb,0x18,0x29,0xce,0x23,0x61,0xcd,0xa2,0xc8,0xbb,0x63,0x33,0x85,0x39,0xd8,0xad,0x2f,0x66,0x77,0x58,0x55,0x31,0xe7,0xbf,0x1d,0x39,0x22,0x38,0x26,0x79,0xa1,0xae,0x84,0xff,0xeb,0x75,0x3f,0xc9,0x75,0x4e,0x50,0xc0,0x18,0x52,0xf9,0x55,0xe3,0xfd,0x60,0x9f,0xf6,0x4b,0xf0,0x5b,0xbe,0x70,0x75,0xcd,0xbe,0x00,},"\x91\x17\x27\x03\x6d\xb3\x09\xd6\xe2\xe3\x36\x9e\x4f\x17\xd9\x8d\x99\xec\x07\x0c\x33\x28\x3b\xb1\x24\x4e\xfd\x62\xe7\x6b\xd7\x0a\x69\xb9\x72\x3b\xd2\xb5\x20\x47\x2b\x98\xaa\x06\x59\x24\x36\x6d\xe7\x80\x90\x0b\xcd\x8b\x77\xb5\x0f\x87\xc3\xc3\x61\x87\x02\x4b\xbc\x59\xcc\xf4\x48\x2c\x7b\x4a\xad\xb5\x6e\x2e\x5e\xcc\x00\x03\xd9\x89\xd6\xaf\xc6\x3e\xc1\x02\x42\xe5\x74\x82\xfe\x39\x21\x52\x61\xd5\xfc\x95\xa0\x18\x5f\x95\xe9\x54\x0c\x55\xf7\x4d\x69\x60\x48\xbc\xa7\xab\x11\x26\x81\xa5\x55\x8e\xa9\x3c\x3b\x1f\x1c\xd3\x64\x65\x9e\x94\x33\xce\xee\xbe\x05\x4e\xe7\x13\xc4\x77\x60\xd7\xad\x13\x2a\x7f\x3f\x8f\xe3\xd5\x04\x1b\x81\x1a\x26\xb6\x5e\xfb\x1f\x34\x0e\x18\x1a\x4e\xc7\x20\xea\x13\x6b\x3a\xf3\xd9\xe5\x46\x1d\xd2\x43\x70\x33\x6f\x10\xe6\x35\x4c\x8c\x17\xac\xf9\x99\x85\x44\xce\xc0\x87\x3e\xfa\x68\x7c\xb1\x32\xae\xcf\x70\xae\xbb\xc5\x67\xba\x03\xc5\x36\x49\x9e\xf9\x6c\xc8\x41\x2e\x7a\xaa\xd5\xbf\x96\x42\x2b\xe4\x7c\xb9\x41\x36\x45\xdf\x2c\x17\x03\x19\x23\x47\xdc\xbb\x12\x31\x27\x45\x59\x71\xae\x15\x7e\x9f\xa2\xdb\xff\x88\x74\x5a\x96\xc6\x58\xb8\x65\xe4\x1f\x55\xae\xbf\x98\x39\x50\x05\xdd\xcb\xd5\x98\x3e\x6a\xe0\x2c\x4f\xbb\x5e\x17\x91\x67\x96\x32\x5f\x76\xed\xf5\xb6\x4a\xfa\x4e\xc5\xa7\x41\x8a\xfe\xd2\x3a\x97\xef\xad\xe6\x8b\x6a\x5b\x31\x45\xf0\x8a\x5d\x3d\xb9\xc2\x98\xa5\x12\xfa\xbd\xac\x68\x56\x2b\x3f\x55\x37\x7f\xf4\x4b\x00\xc1\xc2\xf3\xef\xd1\x81\x32\xda\x71\xf9\x71\xa9\x53\xa9\x31\x8c\x57\x52\x33\x61\xa1\x60\xf9\xb7\xe3\xb5\x1c\x52\x4e\x95\xdd\x5e\xf4\x56\x8e\xf1\x8a\x80\x07\x75\xe9\xd2\x6e\x07\x13\x19\x42\xd2\xbe\x4e\xf2\x2c\x0c\xbc\x13\xdf\x01\xc6\x8b\x1b\xcd\x3b\xce\x9b\xd5\x1c\x4c\xed\x65\x2a\xdc\x40\x07\xbe\x43\xb3\x7c\x67\xa5\xc5\x5e\xd4\x02\x9e\x8a\xd1\x5d\xef\x83\x05\xc9\x68\x62\x1a\xed\x4c\xd4\xbf\xe0\x79\xa6\xf4\x88\x84\xd8\x56\x80\x39\x2c\xa9\x2b\xa6\xe1\x2f\xea\x6f\x4a\x05\x6f\x79\xd6\x7b\x19\xb0\x5f\x90\xd6\x84\xbe\x7d\x45\x72\x5f\x79\x67\xc6\xa4\x67\xaf\x43\xb8\x6a\x6b\x1b\x9d\x9e\xed\x3a\x42\x48\x97\x1c\x76\xa7\xac\x29\xc2\x92\xdf\xba\x4d\x75\xc5\xf7\xba\x70\x9a\x39\x05\x8e\x96\xad\xf6\xdb\xd7\x60\xd3\xce\xf4\x02\x4b\xf3\xed\xc4\x41\xef\xbf\x11\x47\xa2\xc1\x08\xbd\x6f\x9e\xb4\x39\xc1\xc5\xc4\xd3\xa6\xea\x4e\xc3\xd9\x2c\xef\x38\x13\x61\x88\xbe\xc9\xe0\xb6\xc0\x51\x8d\x8b\x79\xba\x59\xc5\xdc\xba\x39\x3a\xed\xfd\xff\xb0\xb7\x0d\x77\x9c\x2b\x97\x65\xce\x44\x52\xe7\xe3\xb0\x8c\x44\x02\xb1\xa6\x08\x32\x08\x40\xfb\xe9\x6d\x1e\xb8\x65\x6e\xb1\xc2\x0d\x95\x51\xdd\xf5\x33\xb9\xf1\x5e\x4e\xb5\x78\x37\x56\xc5\x3d\xdd\x3b\x14\xd8\x07\xf8\x38\xac\x96\x80\xf8\x9f\x1a\xdf\xb7\x8d\x68\xcc\xb0\x67\x31\xa9\x0b\xea\xc5\xf0\xd7\x09\xd5\xb8\x8c\x75\x43\x7a\x66\x3c\xb9\x62\xd3\x7f\x96\xb8\xe8\x92\x84\x77\xb5\x61\x12\x28\x01\x5d\x33\x7f\x04\x9e\x8b\x62\xe4\xdf\xf8\xd0\xbb\x6c\xda\x24\xa5\xdf\x90\x83\xe3\x48\xbe\xf1\x25\x85\xf5\xf4\xc4\xd3\xbb\x3c\x7e\x78\xd5\x50\x19\x4a\x45\x25\x1a\x08\x79\xa1\x62\x4b\xf9\xdd\x35\xeb\x65\x5c\x39\x39\xfe\xa8\x90\x9f\x6d\xf3\x95\xbe\xbd\x02\xb6\x8a\x17\xa8\x97\xc9\xaa\xdd\xd6\xe2\xe2\x04\x61\xe3\x03\xf5\x7c\xde\xb0\x0a\xe0\xf2\x3e\x60\xa9\x4c\x19\xc7\x71\xd8\xaa\x60\x53\x3b\x93\xce\xdc\x1b\x76\xd2\x29\x0a\x01\xbf\x43\xb2\x72\x5f\x12\x5b\xef\xa5\x75\x15\x4e\x98\x6c\x9c\x62\x05\xa1\x59\x6c\xba\xa2\xd1\x34\x70\xc2\x34\x22\xf2\xdf\x7b\xec\xe4\xe6\xeb\xd7\x52\xe9\x38\x9a\xe6\x08\x57\xb5\x29\x69\xd2\xdd\xef\xa9\xc0\x34\xf1\xbf\x35\xae\x33\x16\x30\x4e\x94\x9c\x89\x90\x82\x0e\x26\xe6\xcf\xfa\xe4\xb3\x88\xd1\x50\x5f\x92\x37\x06\x29\x7f\x8d\xb5\x56\x53\x79\x19\xeb\xbe\x30\x86\x02\x3f\x12\xf4\xde\xd3\xb1\x1a\xcf\x2a\x6d\x97\x3d\xdd\x8e\xb2\x7b\x07\xc5\x80\xbf\x44\x8c\xaa\x5a\x2e\xa1\x16\xc5\xea\xf3\x6f\x7a\x6b\x17\xa8\x5b\x39\x55\xdc\x8a\x44\xa6\x20\xd8"}, -{{0x2d,0xdd,0x79,0xe7,0x60,0x64,0xc2,0xe6,0xb3,0x22,0xaf,0xb0,0xc5,0xc6,0x85,0xcd,0xbe,0xc6,0x28,0x21,0xcd,0xfc,0x0c,0xb1,0x4d,0xb7,0xd0,0x1b,0xa3,0xbf,0x21,0xa5,},{0xf5,0x5b,0x4a,0xb6,0x4a,0x25,0x82,0x21,0x2b,0x96,0xcc,0xac,0x06,0x40,0xe2,0x71,0x94,0x4a,0x34,0xa2,0x86,0xd0,0x35,0x83,0x30,0x45,0x81,0x0e,0x34,0x18,0x24,0xbb,},{0xa4,0xc3,0x96,0xe1,0x9d,0xd4,0x2e,0x03,0x91,0x84,0xcd,0x25,0x11,0x88,0xff,0xa2,0x45,0xf0,0x36,0x7c,0x69,0xc0,0x2d,0x12,0x47,0x4e,0x5c,0xa9,0xe5,0xc7,0x68,0xa7,0xee,0x3a,0x3d,0x47,0xeb,0x22,0xd1,0xac,0x9e,0x04,0xb7,0x04,0xa7,0x4f,0x41,0x69,0x47,0xf3,0xf4,0x9a,0x32,0x42,0x59,0x4e,0x7b,0x63,0x90,0xe8,0x2b,0x60,0xd5,0x05,},"\xa5\x66\x74\xa1\xe1\xf0\x97\x95\x25\x1a\xbe\x54\xab\x43\xc2\x98\x20\x8f\xef\xc9\xbb\x91\x76\xfd\xb2\x3e\x1e\x9f\x60\xf0\x32\x64\x79\x15\x56\x7e\xbd\xcc\x2b\x86\x9e\xdb\x70\x55\xf4\xab\xa6\x7e\xcf\xe7\xfa\x19\xed\xa4\x5c\x06\x04\x7c\x7a\x51\x84\x8b\xe9\x97\x32\x51\xf8\x5f\xf7\x6f\x1c\x59\xe3\x65\x43\x82\x85\x8c\x9b\xe1\x23\xdb\x8a\x94\x90\xc6\xc9\xb3\x09\xb8\x2d\x1e\x2c\xa6\xf4\xa0\x7d\x00\x12\x02\x83\xc6\xc2\x95\x64\x49\x95\xa9\x66\x28\x61\x2b\x8d\x67\x91\x57\x35\x18\xe2\x55\x6a\x68\x8a\x09\xf1\x49\xbc\x84\x6a\x68\xbd\x0e\xf7\x92\x79\x03\x57\x10\x03\x1e\xf0\xa8\xfe\xd1\xdd\x0b\xf0\x26\x12\x5d\xc6\x64\x8f\x86\xf6\x43\x09\x94\x2e\x18\xf2\x3b\x12\xd1\xdc\x68\xc6\xf2\x77\x0c\xa8\xb5\x48\x5b\x36\x9b\x0c\x92\x00\x7a\x94\x61\xc1\x39\xfc\xbb\x41\x17\x5f\x31\x6d\x44\x67\x06\x0a\xb4\x3d\x12\x22\xf5\x80\x24\x04\xbf\x63\xc2\xdf\x7e\x00\x4b\xdc\x40\x0c\xa8\x0f\xe0\xd2\xcb\x68\xa2\x10\xfb\xc3\xfc\x0b\x90\x32\x09\xd5\x47\x6e\x7a\x56\xba\xef\xb8\xfa\xd7\xf3\x28\xb7\x2f\x32\x71\x13\xe1\x39\x41\x4b\xa6\xf3\x4e\x99\xc2\xec\xcd\xe0\x44\xe7\xa3\xac\x70\xc5\x80\xcd\x26\xc7\x45\x01\x92\xca\x4c\x82\x3c\x7a\xc5\xea\xe8\x76\xc0\xd1\xc8\xc7\x68\xc1\xcb\x0b\x7e\xa4\x1f\xc9\xb7\xd2\x94\x37\xbb\xad\xab\x18\xe0\xf5\xed\x1d\xef\xe0\xcf\x6c\x0e\xba\xa6\xb6\xd7\x77\xf4\xda\xd9\xab\xdd\xbf\xc0\xfd\x6a\xb5\xee\xea\x80\x3c\xfa\x01\xc0\xbd\x46\xf6\x5f\xef\xa4\x69\x01\xab\xbe\x0d\x89\x10\x4e\x3b\xc4\xae\xe1\xf0\x59\x9c\x69\xb6\x7b\xa5\x45\xab\x9b\x54\xf5\xde\xe3\x40\xac\x69\xd8\x82\x99\xe8\x68\x22\xac\xdd\xdd\xce\x60\x11\x22\x01\x2f\x99\x29\x97\x74\xaa\xf1\x7c\x96\x4e\xde\xcb\x95\xe1\x27\x7d\x46\x2d\xe6\x4e\x91\x15\xa6\x1a\xd9\x8a\xa3\xd2\x2e\x3b\xa6\xf8\xf1\xcd\x69\xb6\xb5\x2b\x83\x38\x28\x23\xf3\x0e\x96\x6b\xda\xd1\xff\x5f\xc1\x98\xae\x32\xe9\xb6\x80\x55\xd4\x39\x2b\xc7\xc3\xdf\x10\x15\xf1\x28\xae\xe1\xe4\xfa\x3d\x49\x99\xe3\x29\xf2\x2f\x0f\xf6\xaa\x77\x8b\xae\x02\x94\xa1\xdf\x74\x36\xcb\x16\xa2\xbf\xcd\x74\xb4\x63\xab\xe7\xcb\x4b\xac\x53\x62\xc8\x9c\x9d\x1a\x37\x8a\x2c\xb8\x85\xcc\x3b\x26\xab\x4b\xe8\x81\xef\x1a\xfc\x14\x43\x0e\x10\xd2\x65\x39\xca\x35\x8c\x36\x76\x28\x6a\xd8\x1c\xe1\xc9\xe7\x85\x92\xaf\x66\xf1\x82\xbb\x1f\x7f\x86\x2f\xe7\x55\xbf\xfb\x5b\xe5\xc5\xf2\xb7\x31\xc1\x32\xe2\x38\x8a\x76\xa1\xa7\xb1\xcd\xdf\x05\xae\xd2\xac\x9e\xc4\x08\x47\x52\x71\x94\x2c\xca\xdd\x32\xe4\x9d\x87\x91\xed\xf8\xb8\xde\x11\x75\x51\xce\x26\x4a\x60\xb8\x41\x05\xea\xe8\x7e\x66\xf6\xa4\x01\xd1\x32\x2b\xb2\x1a\x98\xe8\xac\xd2\x77\x49\x32\x54\xe5\x04\x00\x4f\x72\xc7\x6e\x79\x03\xd2\xfa\x38\xfa\xb7\x17\xe9\x4c\xe6\x27\x94\x7c\x4e\xa3\x26\xbd\x25\x75\xc3\x73\x10\xf3\xb4\xd8\x43\xb9\x0f\xa7\x7d\x32\xd9\x95\x21\x94\x15\x0b\x62\xf8\x50\x18\x7a\x4f\xdf\x38\x46\x6d\xfa\x06\x56\xc0\xa2\xe0\xb3\xf0\x74\x92\xac\x8e\x37\xe5\xd0\xdf\x95\xcc\x89\xdf\x30\x85\xa2\x69\x29\x1d\xc2\x51\x22\x10\xd3\xfe\x44\x24\x8d\x7a\xb9\x96\xbe\x09\x9a\xf6\x4c\x22\x75\x66\x66\xf8\xde\xa5\x6c\x00\xb9\x06\x77\xd1\x18\x25\x00\xdd\x27\x4f\xd0\x76\x92\x53\x82\x6d\x67\x7a\xb1\x6a\x55\x7b\x08\xb3\xc5\x22\x65\x49\x8d\x85\xc4\xcb\x2b\x60\x0e\xe0\x48\x1b\x7c\x1c\x47\x6a\x9d\xaa\x8b\x88\xc7\x1f\xc2\x1b\x6f\x89\xbf\xdf\xec\xe5\x8d\xa9\xe8\xd5\x65\x65\x2e\x43\x95\xbd\xf4\xc8\x11\xb4\xf4\xf2\x2d\x2b\x96\x13\x26\x1f\x88\xc6\x04\xc2\x97\x4d\x3e\x97\x7d\x14\x0d\x04\x6e\x1b\x66\x25\xb7\x07\x16\x40\xd3\x52\xcb\x7e\x7e\x65\xd4\x6c\x61\x34\x47\xbe\x8d\xc5\xa2\x00\xaa\x9a\xca\xb4\x6a\xfc\xcf\xeb\xb6\xb1\xc3\x19\x73\x24\x6c\x34\xfa\xaf\x8d\x26\xea\x5e\x83\xbe\x15\x71\x8f\x8f\xdb\x0c\xfc\x44\x4e\x2e\xb6\x0f\x36\x59\xb0\x20\x16\x1c\x22\x8e\x6b\x92\x40\xb7\xac\x39\x4c\xab\x81\x2d\xe1\x05\x15\x76\x6f\x22\x47\x3e\xcc\xa5\x35\x59\x4c\xe5\x28\xa5\x7c\xf5\xda\xb2\xeb\x32\xab\x84"}, -{{0x3a,0xbb,0xdb,0x0b,0xa1,0x1a,0xa1,0x06,0x3b,0xd2,0x6b,0x02,0xc1,0x16,0x03,0x78,0x62,0x28,0x5b,0xab,0xd2,0x15,0xd2,0x40,0xbc,0x9c,0x09,0x26,0xf4,0xec,0xea,0x81,},{0xb8,0xfc,0x59,0x43,0x8f,0x8c,0xe9,0xe3,0x78,0x5a,0x47,0x3b,0x22,0xc8,0x89,0x2c,0x51,0xea,0xc2,0x56,0x8c,0x68,0x1d,0xcc,0x77,0xb6,0xf0,0xe0,0x79,0x9c,0x4e,0x33,},{0x98,0x1f,0x20,0x05,0x5a,0x45,0x75,0x25,0xae,0xe5,0x61,0x62,0x64,0xe6,0xaf,0x42,0xe8,0xb3,0x87,0xcb,0x08,0xf8,0xb4,0xa7,0x3f,0x9b,0xe0,0xb3,0x66,0xf1,0x03,0x5b,0xb3,0x0a,0x1c,0x87,0x48,0x94,0xcb,0xec,0xe0,0xa8,0x46,0xd8,0x49,0xb7,0xec,0xc5,0x56,0x58,0x5d,0x0d,0x3d,0x39,0x56,0x45,0x80,0x7f,0xf2,0xa3,0xca,0x5a,0x59,0x0c,},"\xdc\xcd\x55\xf9\x22\xcd\x27\x4f\x69\x75\x00\x0a\xdc\x8d\x98\x63\x0c\x6d\x75\x2c\x12\x02\xa9\xdd\x12\x10\x48\xb9\x39\x45\xaf\x2b\x11\x10\x96\x77\x88\xf9\x9e\xc0\x28\xe3\xd3\xb4\xcf\x82\xfb\x07\x17\x3e\xa4\x40\x1e\x3b\xb4\xb0\x7b\x7b\x0b\x24\xb0\x59\xa7\x66\x33\x95\x32\xd9\xdf\x3e\x31\xb7\x2c\x95\x8c\x11\x9d\x8d\xfa\x15\xa5\x07\xaf\x6c\x5f\x7e\x78\xfe\x27\x0f\xa8\x1b\x9d\xf0\xf2\xe4\xaf\x24\xbd\x99\xfb\xeb\x14\xe0\x03\x30\x84\xd7\xfb\xf8\x4d\xde\xdf\xd5\xce\x56\x75\x1d\x15\x90\x84\x75\xdf\x8a\xf0\x13\xd0\x91\x17\x3c\x13\x86\xb9\x13\x94\x26\xcc\x60\x81\xea\x16\x5b\x8c\xe4\x81\x94\xb8\xe1\x8a\x9b\x91\xa4\x63\x13\x44\xfe\x29\xc8\xe7\x28\x18\xb7\x1f\xa1\x5c\x92\x92\xd1\x3f\xdf\x5f\x9d\x18\xe2\x9b\xd0\x29\x1b\x81\x38\xde\x73\x8f\xd3\xa3\x6c\x35\x23\x90\x22\x36\x8b\x45\x6f\x1f\xac\xba\x90\xa0\xd8\x0d\x6e\x31\x1c\x5f\x6c\x6f\x04\x67\x7e\x92\x37\x3a\x5f\xc4\x73\x88\x94\xdb\xed\x20\x6c\x30\xda\x34\x1b\x3b\x19\x6c\x94\x78\x58\xa6\xd2\xad\xc6\x8a\xac\x3f\x20\xcf\xdb\xe0\x49\x79\x61\xda\xe3\x34\x70\x26\x6d\x17\xec\x71\x9a\x59\xf0\x58\x6f\x82\xf9\x9f\x1c\x90\xed\x70\x05\xa2\x07\x21\x9a\x55\xed\xc7\x60\xf4\xeb\x8f\x24\x02\x64\x7f\x6f\x77\x97\x1f\xf7\xb6\x34\x35\x7b\x6b\x29\xbb\xd7\xea\x05\xe2\xe2\x58\x54\xe9\x9c\x62\x0f\x4b\x8b\x64\x73\x90\x22\xff\x0b\x33\x8a\xfe\xf3\x5f\xb6\xf4\x1a\x53\x62\x9a\x51\x8e\xb9\x3d\x66\x02\x0f\xb3\x53\xae\xf8\xdd\x07\x1e\x09\xc9\x16\xd4\x70\x4a\xcd\xf7\x76\xb3\x8c\xa9\xc5\x9f\x21\x1f\xf8\x8c\x43\x0a\x57\xe8\xf1\x71\x39\x23\xb3\xf3\x0c\xa8\x69\x70\xa1\x4a\x52\xdb\x4b\xcb\xe6\x0d\xf4\xbc\x3c\xfd\xf2\x54\xbf\x10\xf8\xaf\xae\x87\xbd\x61\xb3\x58\xf4\x3c\xc2\x96\xc0\x41\x29\x64\xc4\xe0\x0f\x71\x21\x33\x97\x46\x85\x17\xcb\x01\x37\x9c\xb7\x29\xc7\xb9\xe3\x5b\xd5\x0b\xdd\x98\xc3\xd3\xb7\x62\x97\xa1\x38\xb5\x7c\xeb\x6c\x77\x74\x2d\xf0\x88\x1d\x07\x66\x8c\x08\xa6\x30\xa4\x4e\x6e\xd7\xeb\x20\x6d\x6a\x56\x44\x07\x10\x43\x8a\x51\x11\x42\x4b\x61\xaa\xee\xce\x40\xe9\x00\xf5\xe3\xc4\x57\xe9\xd6\xe3\x1a\x79\xec\x5b\x4b\x42\xb6\x8e\x66\xe1\x99\x30\x92\x87\xca\xd6\x53\x36\xfc\x7f\xe4\x3f\x43\xcd\x8c\x77\x3d\x3c\x65\x80\xd7\x21\x7e\x2c\xab\xec\xd3\xea\xbc\x48\x5c\x4a\xcf\x47\x71\x8c\x39\xb0\x2c\x78\x58\xff\x34\x7c\xec\x75\x35\xed\xdc\xd4\xfc\x81\x5d\xf8\x14\x56\x9a\x88\xae\x70\xf2\x73\x3a\x65\x39\xf2\x08\xc7\x9c\xf4\xe7\xc4\xf9\xea\x24\x1a\x92\xe9\x51\x51\x71\x36\x14\x18\xa4\xc2\xe5\x3c\x07\x6a\xaa\xbc\x47\xe4\xc9\x71\xbd\x04\xb1\x00\xc2\x62\x82\x30\x88\x57\xe0\x6e\x7e\x5f\xbc\x43\x42\x56\x4f\xb3\xb1\xea\x4a\x17\xa9\x25\xe9\x1e\xe6\x91\x22\x32\x1d\x39\x2b\x24\x69\x65\xb8\x6b\x54\xfd\x5c\x83\xfa\x5c\x47\x41\x63\xf9\x8a\x9f\x44\x7d\x88\xcb\x59\xfe\x2c\xdf\x9f\x54\x12\xfc\xbe\xb3\xef\xfa\xc8\x97\x67\x91\xc6\xa4\x7b\x66\x9a\x2f\xc5\x5a\xbe\x8e\x09\xe7\x41\x57\xef\xcd\x1c\xa7\x8f\xc1\x0f\xa6\x87\x01\x0c\x68\x26\xc6\xe8\x96\xef\x5c\xd7\x1d\x0f\xe4\xd1\xbd\x07\xc1\x0d\xac\x3b\x03\x48\x5e\xdd\x25\x69\xa7\xee\xcf\xbc\x4e\x5d\x2e\xe2\x37\x98\x59\xe2\x65\x26\x7b\xed\xaa\xd6\x9d\x93\xb7\xc1\xbd\x18\xf2\x7e\xa4\x24\x83\xc7\xe4\x10\x0e\xe0\x5b\x28\x30\x39\xbf\xb9\x89\x1d\x37\xc4\x67\xed\x83\xb8\x8c\x79\x4e\xab\x6b\xab\x9d\xc6\x77\x89\x26\x50\xe2\xd8\x96\xfb\xfe\xc1\xb1\xcd\xb7\x21\xbe\x30\xb0\xb8\xe5\x35\x87\x09\xe1\x65\xcb\xe3\xa1\x82\xc9\x3b\xc0\xa0\xce\xa2\xf8\xcf\x3a\x62\x57\xad\xf7\x64\x53\x40\x41\x20\x22\x41\xa5\x27\x9b\x66\x8e\x40\x12\x5f\xc0\x94\x58\x5a\x3c\x58\x8a\xba\x82\xb6\x7c\xd9\x1d\x48\x3e\x54\x30\x04\x28\x42\x68\x63\xa4\x23\x64\x04\x9d\x7c\x45\xa1\x69\x38\x5a\xa8\x9b\xf3\x77\xf0\xd3\x2b\x07\x80\x9b\x58\x71\x39\x5e\xc0\x53\xa2\x57\xd9\x3e\x48\xbb\xf4\x07\xeb\x60\x91\x40\x1e\x25\x65\x46\xe3\x1f\x9f\xcd\x24\xd2\xc5\xb3\x33\xcf\x65\x78\x50\x02\xf0\x8d\x54\x8d\xb2\x6a\xd1\xf3"}, -{{0x8a,0x44,0xd6,0xaf,0xc6,0xc8,0xee,0xe1,0xbc,0x7d,0x5f,0x69,0xe4,0x95,0xb0,0xb1,0x8c,0xa7,0xae,0xe0,0x07,0xde,0xa7,0xcf,0x0d,0x17,0x14,0xd7,0x85,0xa9,0xf4,0xed,},{0xd4,0xf3,0x66,0xb3,0x37,0x7f,0xa3,0x9b,0x36,0xf9,0xae,0x14,0xda,0x40,0x4e,0x22,0x40,0x49,0x0d,0xbd,0x8d,0x79,0x6b,0x1a,0xb8,0x72,0xdf,0xcb,0x83,0xa5,0x95,0x40,},{0xe0,0x72,0x7e,0xb7,0x2e,0x84,0xd2,0xb8,0x2c,0xdb,0xd0,0xa6,0xbd,0x2f,0x49,0x49,0x63,0x16,0xaa,0xe8,0x35,0x1e,0x49,0x02,0xac,0xd5,0xe3,0xcc,0x57,0x34,0x6e,0x7e,0xba,0xfd,0xd9,0x2a,0x90,0xde,0xd7,0x6f,0xd0,0xc6,0x69,0x0d,0x68,0xbb,0x2f,0xed,0xd6,0x13,0xe4,0x4f,0xa2,0x22,0xbe,0x01,0x26,0xda,0x52,0x0a,0xcc,0x2c,0x41,0x05,},"\xde\x80\x32\x69\x66\x53\x6c\xe9\x49\x96\xaf\x2d\xe7\xa0\x76\x05\xcc\x4f\xcb\x9e\x75\xee\x0a\x67\xa1\xe2\x09\x32\x11\x1d\xe9\xb3\x56\xd5\xbe\xea\xe8\x6c\xc5\xf5\x64\xc1\x0d\x66\xe3\xde\x95\xa5\xb9\x9e\x84\x49\x28\xea\x8e\x77\x58\x6c\xf3\xc1\x0a\xd3\x63\x3d\xde\xeb\x1d\x9d\xcf\x3f\x94\xb7\x0b\xf1\xef\x63\xd2\x38\xdf\x20\x4d\x70\x5c\x0b\x17\x4f\x83\x28\x25\x45\xf5\xe4\x07\x5f\x8d\x69\xa4\x81\x79\xc2\x9e\xab\xf5\xc1\x74\x2e\xf3\x9e\x1a\xd9\x63\xbe\xbb\xb6\x6f\xce\x94\x91\xa9\x84\x65\x12\x15\xc2\xe7\x50\xe6\xee\x83\x65\x76\x64\x40\xa8\x44\x19\xe5\x2d\xcf\x67\x1f\x1c\x52\xea\xa2\xb9\x90\x2b\xcc\xa4\xb3\x7c\xff\xdb\xac\x8e\x7e\x7e\x6b\x0a\x5c\x87\x48\xef\xbf\x45\x2d\xf6\x16\x3f\x4c\xa0\x7b\x61\xf9\xa0\x5e\xc2\x0a\x2b\xd6\x33\x38\x9e\x67\x0b\xb5\x45\x4a\xcd\x6f\x3a\x06\x33\x5b\x5d\xa9\xec\x32\x62\x64\xe9\x62\xc7\xd9\xd0\x6c\xe7\xe9\xff\x04\xa0\xa5\xbb\xdf\xaa\x4c\x41\x08\x66\xa5\x72\x01\x16\x51\x43\x9f\x2d\xbc\xe5\xde\xe6\x67\x92\x4a\xc4\x93\x4d\x20\x54\x96\xbd\x1d\x4d\xf0\x8b\xd0\xcb\x3f\xd2\xde\x73\xa2\xef\x34\x2f\xf0\x09\x1e\x10\xe1\x5b\x3b\x76\x0a\x57\x5d\xf9\x3c\xf1\xc9\x7c\x01\xc5\xab\x11\xc0\x94\xbf\x34\x87\x82\x06\x71\x8f\x6b\x28\x5a\xa5\xcc\x51\x27\xbd\x7f\x98\x8b\x84\xa9\x04\x95\x30\x6f\xd9\xe9\x9d\x89\x55\xe6\x68\xd1\xa3\xff\x10\xf6\x5b\x7c\x47\x9f\xac\x24\x11\x9a\x3c\x10\x12\x2d\x4d\x18\xa8\x05\xb2\x47\xdf\x16\x8c\x0a\x51\x00\x16\x9b\x55\x72\xd1\x70\x12\xd7\x51\xa4\x2e\x83\x37\x61\x15\xe1\x15\x61\xc1\x60\xc1\x5e\xfa\xd7\x6d\x21\xf7\xab\xb4\x30\x36\x64\x75\x23\x86\x31\xf8\x4c\x88\xf8\x38\xb0\xac\x40\x4c\x91\x3d\x2f\xa1\x24\x50\x23\x84\x85\xc3\x02\xfc\x20\x1f\x44\x15\x1c\x19\xbc\xbd\xc1\x19\x0c\x12\xd1\x54\x08\x31\xfb\x19\x58\x1c\xb9\x31\x72\xb0\xd2\xff\x5c\x65\xf3\x1c\xaf\xf2\x0f\x81\x38\x81\xf8\x4e\x5e\xf9\xd5\xc1\x65\xe0\x96\xd2\x54\xca\xdf\x89\x52\x49\xaa\xb8\xd4\x49\x6c\x94\x0a\x40\xf9\x07\xbd\x40\x93\x5a\x94\xf5\xe5\x5b\x6d\xd0\x51\x15\x41\x00\xfe\x33\x17\x70\xef\xf2\xba\xd6\x54\x56\x19\xb8\xa3\x3e\xf6\x46\x2a\x50\xc0\xb2\xc4\xed\x2f\xba\x4e\x4e\x38\x3e\xbf\x29\x32\xe6\x19\x27\x66\xa4\xaa\xd1\xd6\xe2\xb6\x92\xd9\xf2\xbd\xc2\x33\x93\xe8\xaa\xcf\xba\x32\x3b\x53\x4f\x84\xed\xf2\xdc\xed\x7c\x94\xd5\x16\x87\xda\xa2\x71\x98\xa9\x14\x4b\x31\x2b\x71\x6f\xe1\x70\x14\xa7\xbe\xd0\xc1\x4a\x24\x38\x73\x3d\x55\x5c\x65\x64\xc8\xc1\xa3\xd9\x97\xeb\xae\x7b\x3d\xe8\x87\x7a\xf5\x3c\x1d\x1a\x50\x29\x15\x8a\x80\xaa\x0c\x87\x48\x9f\xef\x27\x0c\xdf\xfe\x10\xd3\x4b\x15\xc1\xa9\x69\x3a\xe0\x39\x02\x43\xe3\x14\xcf\xac\x06\xef\x6e\xef\xeb\xcc\xf4\x3d\x42\xea\xc2\x4c\xe9\x87\x94\x29\xd2\xfc\x72\x53\xb3\xed\x17\x58\x25\xbc\x4d\xa0\x76\x2b\x49\x33\xa9\x8a\xfd\xb9\x4b\x06\xf4\xfc\xd2\xad\x36\x11\xaa\x99\x9d\x7c\x1c\x8d\x85\x2d\x01\xdd\x9e\x52\x64\x84\x55\xa0\x4e\xb2\x33\x0a\x76\xfd\x94\x2c\x53\x1e\x51\x4b\x5e\xc0\x72\x8a\x89\xd3\x4c\xa5\x90\xea\x99\xc8\x8f\xaa\x20\xdf\xb7\xbb\xf6\x56\x54\xaa\x6c\x21\x2b\xeb\x8a\xd6\xbf\x7c\x77\x73\x91\xcd\x49\xc3\x9c\xf8\xab\x51\xb9\x5b\x41\x9e\x3d\xfc\x8d\x94\xa9\x3a\x1e\xf0\x22\x3c\x6d\xe9\x0b\xf9\x62\x18\xd8\x04\x5b\xd4\x95\x2a\x0d\x83\x72\xa5\x57\x8c\x6a\xaf\xa7\x4b\xa6\x62\xe3\x18\x8e\x6a\x6e\x56\x7e\x4d\x2f\xe8\x22\x7d\x07\x43\x98\x2a\x41\xeb\xfa\x0d\x31\x0f\xe7\x9f\xed\x27\x04\x17\x90\xef\xd5\xaf\xac\x22\x43\xe1\xd1\x50\xb1\x45\x01\x5d\x9d\xea\xb0\xed\xed\x63\x94\xac\x36\xfc\x5f\xb2\x01\xf5\x20\x4f\xbd\x42\x2a\x36\x04\x23\x30\x15\xbb\x0a\x48\xa9\x20\xe2\xe5\xe0\xd4\xde\xed\x67\x20\x25\xf2\x3c\xfb\xa9\x38\x89\x59\x7e\x50\x4c\x88\x87\xad\xd4\x6c\xfe\xf4\x02\x4a\xfb\x8a\x26\xee\xb7\xdc\xdd\xb2\x39\x7b\x44\xa1\x79\x63\x67\x34\x00\x42\x13\x70\x28\xc3\x30\x76\x26\x81\x6c\x29\x31\xe6\x1e\xbb\x6b\x69\xed\xcb\xcb\x61\x2c\x9b\x18\x1a\x28\x53\x01\xce\x46\xf8\x2f"}, -{{0x8a,0x97,0x2d,0xd0,0xf1,0x19,0x0c,0x2b,0x9d,0x54,0x8f,0x4b,0xa5,0x82,0x64,0xbb,0x04,0x82,0x67,0x75,0x50,0x2a,0x8d,0x5c,0x2b,0x20,0x9e,0xe8,0x8d,0xce,0xa5,0xfb,},{0x6d,0x80,0x37,0x5f,0x3c,0xf1,0xaa,0xb2,0x83,0x55,0x1d,0xf4,0x45,0xd1,0x7e,0x7d,0x3b,0xaf,0x9b,0xcb,0xec,0xbb,0xb2,0x67,0x05,0x2e,0x02,0xfd,0xb6,0x91,0x44,0xd3,},{0xbd,0x45,0xb3,0xc0,0x45,0x85,0x0e,0xbe,0xf7,0xb8,0x0d,0xd1,0xde,0xab,0x48,0x03,0x7b,0x13,0x46,0xc7,0x1d,0xea,0xf1,0xe5,0x8f,0x2a,0x7b,0x16,0x26,0x74,0xf9,0x4d,0x1e,0xf3,0xd4,0x23,0x90,0x37,0x33,0x0b,0xd6,0x33,0x5f,0xe4,0xf0,0x14,0x92,0x50,0x90,0x1f,0x00,0xa8,0xe4,0x6b,0xe5,0xfa,0x0a,0xae,0xc6,0x9d,0xe0,0x6d,0x73,0x04,},"\x30\xb2\x89\x48\x93\x9a\xa2\x63\x43\x7e\x45\xc5\xc0\x25\x4f\xb2\x0e\x61\x7e\xd0\xf3\xfa\x7d\xac\xe5\xa0\xa8\xe0\xfe\x3c\x1f\xc4\xad\xb2\x80\x9b\x61\xc5\xe8\xd9\x2c\xd2\xf3\xde\x93\xb1\x73\xbe\x70\x7b\xad\xa9\x42\x40\xc6\x26\x2c\x16\x0e\x8c\x78\x21\x65\xbe\xef\x99\xd0\xbe\x8e\xcd\xad\x63\x16\xdc\xd7\x34\xbb\xb9\x0a\x66\xcb\xd5\xb1\xcb\x4f\xd8\xf2\x22\x6c\xea\x94\x8e\x4d\xf7\x6b\xbe\x25\x1d\x47\x8f\x5c\x3f\xe0\xd6\xde\x4b\xe5\x4f\x67\xf5\x02\xb2\x80\x4f\x62\x8b\x79\xa5\x50\xfb\x1a\xc4\x83\xad\x2b\xa1\x66\x37\xc4\xbc\x9d\xa6\x7f\xb4\xf9\x86\x59\xc4\xc4\x39\x4d\x16\xb6\xd1\x4b\x3e\x0b\x0c\x1e\x62\x5d\x71\x0d\xcc\x1c\x11\xdf\x5d\x34\x14\x7b\x1e\xc5\xa4\x17\xb9\xe2\x1f\x90\x8c\xfc\x52\x3d\x43\xe3\xf1\x81\xc7\x20\x9c\xc5\x6b\xdb\x5a\x21\x62\x86\x95\xed\x32\x0f\x8d\x4c\x07\xfd\x6d\x84\xaa\x03\x42\x6f\x21\x64\x4a\xae\xfe\xee\xc3\x11\xc7\x4e\x94\x99\x93\x60\x47\x35\x0a\x9b\xf5\xb7\x03\x96\x2e\x77\xce\x55\x13\x36\x83\x5f\xc3\x2c\xcb\xd2\xc9\x0a\xe5\x2e\x24\xd4\x7d\x8d\xcb\x98\x7a\xbd\x12\x1d\x3f\x74\x6b\x5d\xe2\x30\xf2\x64\x69\x60\x3f\xb0\xc4\xa8\xf6\xcd\x79\x73\xd7\xda\x88\x2e\xd1\xd6\xe4\xd9\xc5\xa4\x6e\xc2\xc2\x19\x40\xad\x33\x89\xa1\x86\x01\x4e\xe9\x72\x78\xe5\x35\x09\x88\xb1\x5e\xcd\x9e\xa7\x45\x6b\x3c\xb5\x5e\x4d\x30\x93\xf1\x3a\x87\x5b\x50\xd6\x51\x63\x78\xec\xaf\x58\xd7\x52\xc6\x37\x4e\xd1\x56\x38\x40\x93\x11\xfc\xd3\x79\xd1\x22\xc8\xd8\xc5\x9b\x86\xf4\xe8\xdc\x46\xad\xb7\x30\xa9\x33\x84\x6e\x0b\xd2\x48\xd3\x60\x82\x52\xd9\x70\xb5\x04\xc8\x13\xc6\xde\xa9\xfc\x88\xa3\xde\x64\x19\x56\xdc\xa2\x91\x20\x4d\x39\x0b\x6b\x39\x98\x1f\x8c\x0a\x6b\xcf\xc3\x1c\xa0\x74\x44\x20\x66\x2a\x9b\x35\xeb\x3f\xc2\x11\xf8\x10\xa3\xe8\x06\x25\x00\xb1\xe4\x9b\xdf\x85\x76\x65\xff\x32\xa9\xba\x76\x19\x4b\xbb\x77\xfb\x9c\x15\x41\x29\x64\x24\x4b\x98\x65\xf7\x3d\xed\x9f\x25\xb4\x9b\x42\x5a\xa2\x53\xd8\x07\xd9\x81\x82\x92\x76\x3a\x51\x3e\xc8\x07\x47\x34\x4f\xba\x0a\xcf\xe5\x93\xcc\x26\xb1\x33\x0b\xb9\xad\xe6\x6c\x4e\x88\xcf\x1b\xae\xd6\xd6\xe7\xb7\x50\xe6\xc7\x23\x9d\x7b\xcb\xfa\x3f\xbe\x45\x40\x5a\x63\xb9\x6d\x50\x34\xcc\x0c\x07\xff\xc3\xb5\x08\x58\x08\x1d\x19\x55\xe2\xd2\xfe\x5b\xe5\xfd\xa7\xa8\x99\x69\x43\x76\x8b\x05\x51\x70\xb7\xfd\x52\xf0\xa3\x20\x97\xfe\x1b\x7a\x94\xf1\xbf\x87\x9a\x0c\xba\xbe\x10\xac\x9a\x7c\xc1\xf9\xf5\x50\x68\xc4\x8e\x3c\xcc\x06\x51\x36\x43\x10\x18\xd3\x8d\x20\x10\x9d\xc9\x5d\x99\xcc\x2b\xbe\x7c\x62\x7a\xb1\xa8\xaa\x5f\x43\x16\x13\xb7\x90\xc2\xe6\x52\x6c\xf0\x4f\xdc\x9e\x55\xf5\x1c\x05\x5f\x3c\x20\x45\xa6\x75\xe3\xa1\xe5\x4b\xa4\x09\xf7\xae\xfa\x7e\x4a\xa0\x7a\x2b\xbd\x5e\x4a\xb1\x63\x21\xa9\xf0\x99\x69\x43\x91\xfd\xa6\x8a\x74\x58\x1e\x2f\x1f\x11\xdd\x9a\x6d\x52\x4b\x1b\x83\x26\x0d\xb5\x7b\x72\xef\x29\xc2\x8c\x8d\xb5\xc3\x7f\xd1\x85\xb7\xc2\xd8\x45\x50\x90\x65\x3a\xf3\x32\xdb\xc8\x2b\xfb\x0d\xb5\xdc\xca\xbf\xb6\xb2\x8c\xaa\x35\x05\x25\xcb\x54\xcc\x84\xe5\x53\xe1\xcf\x39\x54\xb6\x12\x39\x3e\x79\x93\xff\x7e\x8b\xf5\xec\xe3\xf1\x45\x09\x4d\xd7\xa2\x7c\xb4\x7f\x22\x74\x76\xf2\x89\x23\x52\x51\xf7\x72\xb3\xba\x77\x6b\xb7\x73\xaf\x0c\xc5\xf7\x86\xa3\xfb\x9e\x93\x1a\x53\x0c\xfb\xd8\x91\xcb\x5a\x5d\xfe\x25\x16\x9e\xf9\x33\xcc\x82\xc9\x08\x0f\x32\x39\x61\xa1\x20\x15\x8e\x4b\xbd\x71\x13\x4e\xf1\xf9\x01\x08\xb8\x15\xc2\x89\xd4\xe9\xa9\x58\x9e\xc6\x4c\x05\xfb\xb4\x2a\x21\xb2\x3d\x16\xe2\xa6\x46\x78\xae\xcf\xab\x65\xcd\x9a\x80\x6c\x59\x81\x03\xd4\x1f\x70\x09\x77\x63\x17\x83\x1f\xed\xdd\x1c\x90\x02\xd4\xa9\x22\x04\xf9\x7b\xa9\x49\x0c\x61\x46\x98\x03\x07\x21\x02\x52\x4b\x9d\xf5\x19\x00\x5f\x98\xaf\x54\xd6\x0c\xa5\xba\x60\xb5\x5b\x09\x6a\x4a\xc2\xb1\x6e\xb9\xcc\x81\x97\x3c\x31\x35\xd3\xfb\x68\x73\xdd\x96\x53\x80\x0a\x22\xbb\x5d\x0d\x61\x17\xca\x5d\x91\x65\x53\xbe\x39\xc9\xa3\xb5\x11\xeb\x3d\xb7\x30"}, -{{0x12,0x38,0x0c,0x45,0xa7,0x9a,0xde,0x0f,0x48,0x3c,0x88,0x1a,0xaa,0x37,0x30,0x43,0x8b,0x08,0x35,0x90,0xf4,0x04,0xdc,0x9e,0x60,0x1f,0x76,0x15,0xf3,0x75,0xa6,0x28,},{0xd6,0x6f,0xc5,0x9a,0xe9,0x17,0xf7,0x6d,0x24,0xce,0x8a,0xb8,0xee,0x03,0xfb,0xcb,0x71,0x5d,0x5e,0xea,0x4b,0x08,0x39,0x2b,0x59,0x1e,0x64,0x85,0x91,0xc7,0x3c,0x89,},{0x02,0xb2,0x51,0x74,0xa3,0xdd,0x52,0x19,0xed,0x48,0xb2,0xc9,0x4c,0xa2,0x12,0xb6,0x3a,0x6a,0x3a,0x25,0x97,0x70,0x3c,0x07,0xb7,0xf0,0xc9,0x65,0xc3,0xc6,0xac,0x2e,0xb4,0x50,0xef,0xe3,0x87,0x16,0xa2,0xa2,0x8b,0x3f,0x89,0x84,0x6b,0x06,0xeb,0xdc,0xa4,0xbd,0x09,0xaa,0x58,0x1f,0x24,0xe8,0x4d,0x80,0xfc,0x10,0xac,0x1a,0x00,0x0a,},"\x68\x45\x23\xc2\xe7\xfa\x8b\x4b\xd7\x54\x8c\x4b\xac\xaa\x86\x78\xa3\x30\xdb\xbb\x96\x06\x32\x94\x01\x66\xb2\xcc\x9a\xfc\x15\x35\xc8\x0c\x11\x2c\x8d\xc4\xad\xa7\x62\x92\x33\xfe\x90\x90\x55\x23\x7d\x51\x3e\x29\x2a\xf1\x5a\xd7\x69\x2f\x11\x5a\xa0\x92\xda\x65\x75\x32\xf5\x18\x99\xc3\xf7\xf5\xd9\xd4\x07\xed\x5c\x16\x3e\xb3\x95\x04\x80\xa4\x12\x2a\x09\x92\x98\x1f\x07\x7b\xc8\x67\xf9\x06\x07\x54\x07\xba\x98\x49\xc4\xea\x04\x73\xce\x54\x0a\x79\x67\x44\xef\xa3\x86\x03\x78\xe1\xb8\x93\x43\xe5\x83\xd0\x80\x7e\x5a\x67\xc4\xd5\xbd\x7c\xe6\x41\x29\xfe\x90\x2b\x8c\xfa\xbd\x2c\x21\xfa\x3d\x2a\x10\xe9\xbf\x9e\xa5\xe5\x47\x3a\xe2\x50\xc9\x16\x05\x09\x97\x26\x78\xf9\xa7\x40\xe6\xca\xdb\x3b\x52\xf5\x02\xfa\x61\x6c\xff\xae\x1d\xef\x89\x3d\x54\xe4\x1e\x54\xd3\x26\x46\x4c\x9f\x43\x5c\x63\x50\x5f\xb1\x5e\x3e\xea\xf5\x02\x1c\x65\xdc\xd0\x10\xf8\x40\xaa\xb3\x17\xc8\x60\x5d\xfb\x1a\x0c\x8a\x3d\x55\x49\x86\x1b\x69\xaf\x2c\x93\xd8\x6c\x98\x1d\xf3\xa5\x1c\x5b\xf5\x78\x5c\x2f\x85\x26\x10\xe4\x4f\xa4\xff\x1c\x71\x61\x15\x2e\x56\x18\x38\x47\x44\xfe\x83\xba\xbf\x0b\xcb\x75\x61\x78\x9a\x02\x31\x25\xf6\x24\x2a\x18\x3c\xac\x95\x49\xc9\x32\x73\x3a\x86\x8a\xa1\x82\x65\x6e\x2b\xa0\xa8\xc0\xbe\x10\x69\x96\xa8\x5c\xeb\xf1\xbd\xad\x12\x3b\x98\x2b\x4e\x05\x55\x10\x87\x94\x82\x02\x1d\xae\xa9\xd8\xf2\x6c\x58\x8e\x6c\xd1\x01\x26\xcb\x31\x96\x88\x03\x56\xbe\xe8\xf2\x98\xbc\xa3\x06\xec\x56\x99\xc7\x57\x6b\x76\x50\x87\xc2\x53\xa6\x02\x14\x01\x0c\x6e\xd7\x0d\x87\x1c\xfc\x87\x38\x01\x8a\x0e\xdb\x57\xf1\x06\xb4\x21\x8d\x85\x5e\xab\x2c\x91\xf3\x9f\x85\x8b\x3f\x25\x90\x56\x31\xa0\xee\xe2\x98\x56\xfd\x34\xf7\xb8\xc9\xba\x51\xc1\xc4\xc6\xa7\x35\xd6\xc7\xa1\x3d\x22\x0d\x7a\x56\x6c\x3f\x50\x6c\x72\xbc\x74\x17\xab\x37\xf0\xd6\xd7\x96\xff\xc7\x1d\xf9\xdc\x7c\x6e\x13\x7d\xa5\x6b\x7a\x3e\x10\xcf\x0b\x1a\xbb\x3f\xfb\x70\xbc\x66\x29\x3b\x5d\x75\xb4\x05\xed\x8b\xec\x0d\x6f\xcd\x06\x92\x5c\x38\x11\x68\xac\x18\x8d\x0b\x8a\x1a\xf0\x83\x9f\x5b\xde\x84\x3b\x69\x91\xe5\xa5\xd6\xcd\x66\xfe\x6b\x0f\xde\x86\x7c\x08\x6e\xd4\x38\x76\x91\x9a\x1b\x72\x33\xd8\xd7\xe1\xd2\x74\x2f\x61\xc7\x7d\x8e\x59\x91\x68\x9c\x83\x28\x67\x66\x55\xb7\x6a\x37\x50\x56\x0e\x75\xd1\xc7\xe8\x5e\x3c\x00\x85\x05\x93\x31\x09\x4b\xba\x57\x10\x03\x2c\xf6\x79\xa5\x25\xc7\x8b\x31\x70\x0e\x6d\x91\xf7\x52\x94\xc4\x22\x48\x92\x97\xe1\x73\x59\x43\xe4\x17\xfc\xd3\x55\x80\x58\x2f\xdd\x02\x39\xb5\x11\x46\x53\x0c\xc0\x9d\x83\xb2\x8f\x0a\x1d\x64\x22\x20\xdf\xb9\x9b\xad\x62\xf3\x95\x41\x03\x50\x81\xd6\x5d\x77\x8d\xdf\x32\x39\xba\x0e\x6f\xa9\x91\x4b\x17\xb3\x97\xa5\x34\xcb\x8f\xd3\xb4\xff\x42\xa8\xd8\xc8\xee\x66\x15\x3f\xbb\x1f\xf0\xfa\x54\xf7\xbd\x03\x27\x85\x16\xe6\x34\x1a\xf8\x0f\xcd\x1f\xce\xe7\x0c\x35\x9d\x20\x53\x68\xac\x49\x0d\x75\xa3\x54\x51\x2d\xa4\x6b\xa7\x63\x4c\x15\xb2\x84\xb2\x44\x77\x80\x8f\x17\x63\x33\x60\xa4\xb4\x9f\xb3\xbc\xaa\x84\x18\x41\xcf\x92\x41\x7e\xb2\x4c\xe4\x82\xd5\xa2\x4b\xfd\x2d\xac\x37\x22\x31\xda\x53\x9a\x05\x42\x00\x02\xff\x7a\x20\xc4\x76\x09\x7d\xa0\x6f\x59\xf0\x33\x14\xe6\x05\x9f\xad\x88\xc5\x0c\x3b\xaa\xc0\x3c\xef\xa7\xcd\x82\x11\xd2\x46\x1b\x16\x60\xea\x6b\xcf\x47\x68\x38\xc9\x1a\x10\x07\x4e\xb4\xb4\x0e\x6e\x97\x4a\x94\x5a\x67\xf6\xee\x69\x04\x23\x1e\xf0\x41\x88\xf1\xea\xd5\xba\xf3\x56\x94\xef\xe3\x01\xed\xc7\xe8\x66\xda\x23\xb5\xa6\xc5\x8f\x01\xb2\xa5\x2c\xf3\xab\x80\x5e\xdc\x5c\x13\x68\x62\x6b\x95\xb9\x4e\xb4\x64\x5b\x69\x3e\xc8\x80\xf2\xb8\x11\x7a\x69\x3a\xfb\xdc\xd2\x48\x24\x31\x89\x0f\x41\x0b\xc5\x80\x53\x0f\xef\x37\x58\x79\xc2\xe4\x60\x49\xca\x89\x1a\x2c\x3e\xcd\x60\x43\xae\x80\xd8\xaf\x34\x66\x34\x67\x4c\x6d\xfe\x90\x59\x97\xde\x5d\x05\xd6\x20\x09\xee\xed\x27\x75\x02\xfb\x5a\x5a\x31\x55\xee\xee\xb6\x73\x48\xb6\x0d\x89\xa3\x4a\x78\x12\x63\x9f\x54\x1f\xfe"}, -{{0xd1,0xb3,0x43,0x0d,0x4e,0x63,0xaa,0xbf,0xa9,0xef,0x96,0xbc,0xba,0xf1,0xfa,0x6a,0x9e,0xb5,0x21,0x9d,0xd4,0x4d,0xf3,0xb1,0xa6,0x15,0x63,0xdf,0xfe,0x1c,0xcb,0x28,},{0xc2,0x8a,0x05,0x19,0x52,0x45,0x29,0x0e,0xcd,0x38,0x53,0x55,0x85,0xce,0x51,0xf3,0xc2,0x35,0xc5,0xd6,0x50,0xc8,0xc5,0x7c,0x2f,0x79,0xbb,0x0a,0xc0,0xe8,0x08,0x34,},{0x4c,0xb6,0xff,0x5d,0xd7,0x06,0xb1,0xae,0x81,0x6c,0xdb,0xaf,0x9e,0x9e,0x1e,0xdc,0x80,0xa6,0x62,0x84,0xf9,0x46,0x52,0xd5,0x0e,0xc1,0x4e,0x28,0x3b,0x2a,0xdc,0x59,0x2f,0xd0,0x84,0x33,0x71,0x44,0xff,0xa7,0x12,0xdc,0x34,0xce,0x8e,0x61,0x06,0x68,0xa6,0x5e,0x96,0x9f,0x05,0xce,0xb5,0x47,0x86,0x30,0x4d,0x0d,0x58,0xd3,0x1a,0x08,},"\x07\x6c\x0c\x87\x62\xe4\xbc\x00\x3c\x36\x0a\x12\xa1\x95\x98\x05\x05\x51\xd1\x6b\x4b\x8d\xa0\xfb\x9c\x4a\xfc\xc8\x1a\xdb\xe6\x19\x95\xf2\x5c\xbc\x28\xdc\xa4\x20\xbf\xa9\x46\x10\x54\xd3\xee\x00\xad\x78\x18\x3e\x7f\x26\xdf\x68\x98\xaf\x9a\x4d\x22\x5f\xca\xb6\x7c\x04\x2e\x9a\x13\x52\x5d\x1f\x75\xff\x0e\x3d\x8d\xa8\x08\x96\xb7\x28\xf3\xe2\xdb\x65\x94\x4a\xe0\x71\x7d\x77\x59\x90\xb5\x9e\x5b\x70\x43\x4b\xd4\xb3\xee\x45\x2f\x10\xac\x06\x10\x57\x0b\x38\x22\x08\x32\x96\x8f\x54\x4d\x3e\x4d\x11\x9b\x1d\x4b\x50\x15\xc6\xcd\xf4\xcf\x22\x0b\x56\xb5\xc0\xcc\xd8\xe3\x98\xd5\xe4\xa5\x8d\xa3\xb0\xe2\xb2\x70\xa5\xd3\x9b\x82\xab\xb7\xf9\xd2\x7a\x41\x90\x18\x55\x0b\x62\x00\xae\x51\xc8\x48\x82\xf0\x86\xae\x7e\xa5\x35\x16\x71\xb6\xdd\x96\x09\x23\xad\x6b\xef\xc1\x34\x09\x87\x9a\x8d\xf6\x19\xbd\xf6\xc8\x8a\x6f\xe1\xec\xc0\xf0\xf3\xaa\x21\x9f\xb6\x19\x02\xbe\x48\xa5\x3d\xf2\xbc\x66\xc5\x6f\x1c\x1d\x17\xf7\xe6\x16\x7d\x25\x51\x65\xf1\x74\xba\xa9\xca\xf5\x3c\x73\xcb\xbb\x7c\xc2\xc7\xc0\x87\xf4\x3a\xbe\x2a\xed\x5a\x21\xfe\x42\x90\xb8\xd6\x79\x60\xa8\xa9\xcb\xc2\xa5\x7a\xbe\x22\x65\x4d\xc1\x84\xcf\xf9\x16\x8b\xb6\x97\x27\x03\x75\xfe\x88\xd5\xc4\x9c\xf9\x5b\x06\xcf\x9d\x0d\xac\x81\xfb\xd9\xc0\xd7\xb8\x2d\x05\xed\x2c\x3f\xd4\x9c\xcc\x29\x40\x44\x41\x71\x25\x45\xf9\xa9\x91\xe4\xf0\xdd\xb6\x21\x90\x83\x82\x96\xf9\x67\x29\x9a\x38\x60\x72\x26\xd8\xa6\x81\xf0\xa8\xf3\xc4\x38\x4f\xd1\x8b\x30\x25\x7c\x46\x3c\x0a\xbd\x0f\x4f\x6f\x12\x25\xa5\x1b\x76\x2d\x6d\x0a\xc7\xd5\x9c\xd2\xef\xd6\x98\xb8\xd1\x3e\x23\xd7\x04\x09\xf6\xb0\x7d\x69\x5c\x16\x71\xcd\x6f\x59\x44\x3b\x1d\xb0\xab\x35\xb9\xdc\x06\x40\xe4\xc6\xd1\xac\x50\x47\x5d\x28\xef\x94\xf8\x17\x90\xe2\xe5\xb2\x54\x55\x14\xb2\xa4\x9c\x5c\x21\x53\x45\x9b\xe5\x40\x89\x0f\x53\xbc\x18\xe4\xa1\x6d\xcb\x5d\xcf\x50\xf3\x7a\x95\xc6\x06\xfd\xf4\x85\x98\xe5\x2a\xf3\x17\x9a\x20\x48\x61\x5d\x93\xd9\x7e\x05\x99\xb7\x08\x8c\x11\x74\xbb\x9f\x15\xe3\x70\x18\xf9\x9a\xcb\xce\x5b\x13\x02\xf8\xd8\xce\x2a\xb8\x54\x37\xfe\xeb\x0c\xaa\x77\x84\xdc\x83\xc9\xe7\xc3\x6f\xe0\x59\x90\x6b\x03\x0a\x86\xa3\xde\xd0\xab\x9d\x8b\x73\x52\x9d\x47\x5e\x66\x1a\x08\x08\xd6\xd3\xf0\x90\x7f\x85\x28\x87\x3f\x08\xd5\x74\x8b\xe1\xd6\x97\x12\xe8\x52\x62\xd7\x7b\xdf\x13\xbf\xd1\x8a\x5c\xde\x6f\x71\x46\x26\x73\xab\x29\xb1\x61\x73\x15\xa9\xa6\xe9\x36\xa8\xe8\x1a\x8e\x43\xbd\x0f\x66\x44\xa5\xc6\x9e\xaa\xac\x89\xbd\xaa\x99\xcc\xa8\x03\x83\x37\x05\xe5\xaf\xa6\x9b\x3b\xd1\xd0\x25\x2b\x85\x46\x50\xf2\x19\x97\x91\xe6\xac\xa7\xc7\x5a\x86\x12\x83\x21\x62\x33\xa2\x63\x3a\x6a\xef\xf9\xd3\x01\xee\x5c\xb4\xdd\x72\xc0\x8a\x45\xcd\xae\x8f\x54\x58\xc0\x95\xb2\x2e\x75\x9c\x43\xb4\x9b\x98\xe9\xf4\xcb\x33\xd5\xde\xa8\x79\x44\x9e\xae\x73\xcb\x87\x4c\x73\x59\x43\x25\xeb\xf6\x8c\x1e\xd4\x06\x4b\x6f\x61\xab\x2f\x01\x4a\x2f\x19\xf3\x2e\x12\xb3\x3c\x5e\xaa\x8a\x29\x20\x4d\x5e\xba\x58\xdc\x07\x50\x72\xfe\x39\x9b\xe7\xd1\xab\x18\x08\x20\x8f\xb4\x08\x12\x3b\xdc\x0b\x4a\xb3\x13\x0f\x9f\x70\x6d\xc3\xeb\x19\x4b\x60\x5e\x73\xa3\x2f\x12\x5a\xe4\x91\x28\x5c\xe6\x03\x9f\xb6\x23\xc3\x8b\x81\xd5\xab\xa0\xf5\x59\x9f\x6c\x86\xe8\x72\x48\x6b\x4e\x96\x49\xda\xff\xe3\xa3\xd0\x6c\xb0\x73\xdd\x3b\xc6\xf4\xe1\x0a\x18\x70\x0e\x45\x72\x2d\x78\xa6\xb0\x97\x2d\xc9\x4d\x5c\x7a\x7b\x66\x41\x75\x7b\x79\x60\x75\x71\x9d\x7b\x8e\xc3\x6a\x1e\x79\x6f\xb5\xf8\xfe\x6f\x1b\x79\xa0\x85\x9c\xb4\xd6\x7c\xec\x05\xed\x91\x4c\xfa\x32\xc1\xdd\xfe\x21\x8e\xf9\x63\x43\x6c\x3a\x11\x48\xac\x2c\xf9\x09\xdf\x73\x59\x89\x06\x57\x46\x3a\x4e\xa2\x5f\xed\x59\x61\x8a\x06\x81\xa1\x21\x7e\x22\xd6\x4e\xf9\xd9\xb4\x55\x9d\x0a\x0f\x6b\x3c\xe8\xd8\x47\x93\x0b\x23\x23\x01\xca\xf4\x4c\xdf\x7a\x3f\x18\xa2\xac\x13\x0b\x92\xcf\xd9\xc0\x33\x60\x55\x7b\x5f\x7c\x47\x75\x46\x2a\x10\x71\xf7\x03\x44\xc7\x18\x37\x4b"}, -{{0x03,0x3e,0x00,0x3d,0x7a,0xab,0x7b,0xc7,0xfc,0x8a,0xc2,0x04,0xc7,0x33,0x79,0x9a,0xe5,0x53,0xc3,0xfe,0xc5,0x3f,0x10,0xdb,0xf7,0x95,0xb5,0xf4,0xb8,0x7f,0x1c,0x95,},{0x68,0x2f,0x46,0xf5,0xc0,0x56,0xdd,0x45,0xba,0x0b,0x5a,0x78,0x20,0x31,0xf9,0x59,0x6a,0x73,0xaa,0x29,0x2c,0xa2,0x32,0x6b,0xed,0xa7,0x4a,0x52,0xfc,0x32,0xb7,0x16,},{0xed,0xb4,0xe0,0x20,0xd6,0x76,0xfa,0xc6,0xa8,0x45,0x53,0x48,0x80,0xbf,0x61,0x36,0x37,0x4a,0x8b,0x7f,0x2c,0x53,0x85,0xbb,0x9e,0xe2,0x25,0x38,0x1f,0x49,0x4e,0xfb,0x74,0xa5,0x5b,0x41,0x3a,0xe0,0xea,0x70,0xad,0xd6,0x1b,0xfd,0xfb,0x87,0xfb,0x42,0xd5,0xbc,0x0c,0x53,0x59,0xdd,0xdd,0x57,0x3d,0x53,0x8a,0xe9,0x3a,0x6b,0x36,0x09,},"\x59\x6a\xa2\xc4\x0b\x33\x18\x87\x89\x38\xeb\xc1\x38\xdb\x27\x4b\xb3\x8a\x52\x01\xeb\x7c\xaf\x87\x5e\x6c\x64\x57\x91\xda\xe0\x12\xbd\xef\xd4\x85\xe6\xbd\x9d\x84\x99\xc4\x2a\x2a\xe8\x6c\xf3\x2b\x18\x00\x2e\x76\xbb\x58\x2c\xca\x0d\xec\x48\x15\xde\xd8\xa1\x21\x1f\x8f\xc8\x85\x7f\xce\x1d\x57\xf6\x15\x1d\x88\x78\x7b\x97\x8f\xab\x56\xbf\x92\x6b\x15\x33\xe1\x94\x99\xe8\xbb\x99\x15\x8c\xdd\x6e\x98\x0f\x6b\xa5\x43\xae\x83\x1f\x9d\xd1\x34\xb0\xfe\x6d\x5c\x24\x88\x7d\xc7\xa8\xd4\x78\x1d\xd9\xb7\xfc\x5d\xc9\x46\x4b\x04\x5c\xbf\x9d\x1e\xf5\x03\x6b\x5b\xf2\x8b\x54\x9a\xc7\xaa\x8f\xaf\xb9\x1a\xdc\x9f\xec\xa7\xa1\x45\x54\xd1\x10\xe3\x10\xc7\x49\xe4\x85\x33\xf3\x59\xc7\x0f\x05\xfb\x7a\xed\xef\x13\x66\x36\xb8\xef\x72\x23\x88\x65\x39\x86\x4e\xe5\x2d\x34\x11\x8b\x4b\x8b\x74\xe0\x8f\xe6\xb6\x58\x96\xe4\xb1\x9b\x6d\x7c\x3f\x25\x28\x26\x55\x85\x48\x17\x10\xd2\xd7\x49\x48\xeb\x4b\x17\x08\xa5\x0f\xa7\x40\x21\xbd\xa4\xb3\x61\xbc\x68\xd2\xa5\xd2\x02\x10\x9f\x8d\x28\xd8\xaa\x67\xd7\x8c\x11\x36\xcd\x2e\x90\x3c\x8d\xfa\x17\x5a\xf7\xbd\x96\x3b\x73\xda\xe4\x95\x87\x3c\xcd\xae\x62\xbf\xef\x88\x56\x36\xdd\x83\x55\x0f\xf9\xc0\x5c\x37\xba\x33\x89\xd1\x54\x36\x85\xd8\x94\x83\xb0\xc1\x04\xe7\xef\xbb\x77\x02\xc5\xa0\x39\x8a\xc7\x20\x48\x4c\x50\x93\x68\x35\xee\x9d\xf2\x53\xf0\xef\x8c\xbe\xf3\xe0\x7d\xe9\x69\x51\x1c\xcb\xf8\x75\x57\x49\x3a\x0b\x97\x2e\xf0\xe8\xe6\x29\xcf\x38\x22\xdb\x21\x28\x6e\xd7\x27\x66\x1b\xd3\x17\x86\xfc\xa1\x42\x11\x06\xda\xcd\xee\x1c\xaa\xf4\x94\x54\xe8\x54\x79\x4f\x70\x4d\x22\xa9\x5a\x4c\x8e\x6b\x1c\x2f\xee\xa5\x7e\x56\x23\x8c\x20\x96\xf1\xcc\x57\x86\x47\xfe\xa5\x44\xd6\x76\x44\x82\xbd\xf5\x14\x88\x79\xa2\x5f\x94\x3d\xb1\x6f\x29\x02\x1b\x9e\xcf\xe3\xe0\x90\xb4\x25\xc8\x1c\x70\x09\x84\x2e\x1c\x7a\x02\xd9\x1c\xa6\x0c\x12\x01\xc3\xbd\xae\x9c\x53\x73\xaf\x03\xf2\xf4\xdb\xef\x40\xde\x8d\x9b\x21\xfe\xd6\x8d\xee\x51\x0d\xe0\x42\x72\x34\xca\xa1\xc2\x0a\x3a\xe5\x49\x95\x48\x34\xc9\x33\x73\xd9\x13\xb8\x75\x0f\x23\xa0\x37\x80\xd7\xa9\x45\x4e\xd6\xfe\x51\xfd\x2d\x27\x6b\x9d\x4a\xa3\x2d\xe0\x5e\x03\x81\x6e\x64\xe9\x46\x6f\x4f\x0e\x22\x46\x51\x42\x8d\x34\x2c\xbc\xc6\x97\x17\x0a\x47\xef\x99\x6b\xda\xcb\xce\x91\x11\x7c\xa1\xf8\x45\x5b\x25\xb2\xb0\x84\x43\xe9\x91\x4e\x3d\x90\xc4\x89\xee\xaa\x77\x31\xdd\xea\x21\x23\xd5\x5d\x67\xb1\x66\x83\xfb\x7c\x82\x36\xaa\xa5\xa1\xb0\xfc\xaf\x8d\x17\x00\x11\xdb\xe9\xaa\x28\x57\xbe\x61\x2c\xbb\x85\xef\x69\xe5\x68\x31\xb4\xda\xcf\xbc\x7a\x59\xb4\x65\xa6\x6d\xc7\x41\x2d\xdb\x3d\x6a\xf4\xeb\xfd\x70\x58\x64\xe7\xd4\xfb\x99\xa6\xcc\xb4\x8b\x11\x83\x68\xfe\xab\x02\xa3\x40\xc4\x32\x76\x8d\xe0\xe0\x67\x87\x1e\x9e\xa8\x08\xd6\xd9\x93\x81\x58\x29\xe7\x1f\x6c\x04\x2b\x66\x49\x95\x09\x8f\xee\x94\xd5\x43\xdf\x15\xe5\xb1\x69\x57\x03\x1b\xd2\x38\xbc\xad\xbb\xdc\xc5\x76\xaf\xfb\x64\x03\x03\xd6\x9c\x5b\x25\x0b\x3a\x53\x9a\xfd\x12\x7f\x7e\xe2\x60\x9e\x52\xe5\x15\x4f\xbd\xff\x3e\x45\xf9\xc4\x40\x66\x65\x6d\x56\x1e\x0f\x64\xdf\xf2\x80\x5d\xf8\x8e\x30\xa3\x80\x53\x08\x22\x41\x3a\x7a\xb7\x6a\x1b\x9a\x86\x53\x78\xd2\x47\x63\x06\x9a\x81\x40\x02\xa9\xa9\xd0\x37\x95\xca\x8d\x2b\x5b\xd1\x09\x03\x93\xe9\xe4\xb1\xff\x7d\x7f\x0e\xb8\x4e\x71\x2a\x01\x8f\x68\xc9\xe3\x84\xf0\xa0\xae\xf3\x96\x78\x79\x28\x4f\x40\x9e\x30\xd2\x36\x50\x86\xe6\x69\x52\x27\x8c\xa9\xb6\xf9\x0e\x8f\x69\xa4\x8d\x9b\x28\xbb\x4c\x4e\xd6\x32\xab\xca\x3a\xf4\x14\x4d\xa7\x42\x2b\xf5\x19\x92\xf7\x34\x73\x14\x53\xc7\xa3\x3e\x15\xe5\x9f\x53\x08\x12\x9d\x6a\x77\x4a\x94\x58\x6f\x72\x33\x11\x17\x91\x76\xc0\x94\x8f\xff\x4e\x30\xc1\xb9\x59\x81\x2c\xac\x97\x7c\xc7\x43\x47\xb0\x07\x94\x0f\x2f\xb9\x62\xa9\x0d\x66\x06\x6a\x6d\xe8\x80\x19\x84\xde\xe4\xa5\x32\xd4\xb0\xac\xd6\xdc\xaf\x06\x72\x7b\xab\x70\xb3\x86\x62\x32\x23\x4c\x91\x00\xbf\xdc\x66\x9f\x77\xca\x49"}, -{{0xee,0x55,0xfc,0xf7,0x0a,0x27,0x5c,0x72,0x6b,0xd4,0x85,0x66,0x83,0xb3,0x47,0xde,0xcf,0xd4,0x22,0xf1,0x82,0x6c,0x07,0xa9,0x32,0xcb,0x85,0xbe,0x9f,0xa4,0xef,0x3c,},{0xdf,0xcf,0xfb,0x5e,0x15,0x53,0x78,0x9d,0x56,0xa9,0xf3,0x91,0x4b,0xce,0x50,0x0d,0x07,0xc5,0xac,0x31,0x1f,0x92,0x78,0x54,0xb2,0xcf,0x1e,0x58,0x33,0xc0,0x32,0x37,},{0x9d,0x8c,0xb2,0xea,0xf3,0xff,0x3e,0x0c,0x2b,0xc6,0x72,0xe1,0xd2,0x55,0xc5,0xb8,0xe8,0x07,0x31,0xbf,0xf6,0xf6,0xab,0xa5,0x17,0xe1,0x33,0x54,0xe8,0x51,0x08,0x0f,0x4a,0x8b,0xb8,0x12,0x1b,0x26,0x24,0x24,0x4c,0x9e,0xe9,0x5c,0x8a,0x09,0x2f,0x10,0x37,0x03,0xfb,0xe6,0x6f,0x9c,0xba,0x10,0x0d,0x2e,0x91,0xed,0x77,0x4a,0xc9,0x07,},"\xb8\xc8\x45\xcf\x7c\x54\x85\xf0\x62\x2d\x1d\xdc\x17\xf7\xa0\xf6\xf0\xfd\x70\x74\xfe\x19\x4b\x0e\x0c\xd4\x26\x50\xcf\xc8\x17\xf5\x7f\x09\x5f\x8c\xdf\xad\x1e\xbe\x0d\xfb\xc1\xbd\x76\x17\xab\x4f\x20\x4e\x9d\x55\xd8\x1a\x7c\x8a\x43\x39\x40\xec\x6f\x17\xc8\xa8\xe3\xd5\x6c\x1a\xfb\x0a\xf3\x74\xbd\x32\xd5\x4e\xf7\x13\x2d\x26\xb8\x9c\x47\x0c\x2a\xb5\xbe\x16\xfa\xbb\x4c\x75\x19\x3d\x6d\xa5\x9b\xa2\xfd\x15\x7e\x9e\xa4\xe0\xc5\xc0\x8a\x52\x02\xf5\xed\xc6\xa6\x17\x01\xf0\x8b\xb3\x44\xca\x64\x55\xd7\x5d\x14\x5a\xdb\x24\x4c\x53\x4c\x8c\xfc\x62\x3f\x4d\x4b\x67\x67\x59\x4b\x39\xa7\x69\x0b\xee\xec\x4d\xf9\x74\x6a\x57\xff\xee\x05\x14\x54\xc4\x27\x8e\xa4\x3c\x81\x0f\xf1\x3c\xd7\x69\x61\x5f\x9d\x05\xd4\xfe\x4a\x51\x58\x3e\x80\xc0\x15\xdc\xfe\xd9\xaf\x05\xf9\x3d\x05\x4d\x34\xff\xd9\x39\xbd\xd8\xf0\x51\x8f\xa3\x03\x0a\x96\x4d\xc9\xd8\x0d\xf0\x0f\x16\x35\x82\x40\x72\xcd\xf2\x9b\xc8\x02\x59\x20\x9d\x50\xf5\x6f\xca\x9f\xbd\x6a\xe1\x51\x4a\x67\x19\x89\xce\xa4\xf6\x84\x6b\xc1\x91\x79\x09\x7c\xca\x40\xc6\x24\xd7\xed\xbf\x91\xfb\x5b\x25\x39\xeb\xbd\x50\x2d\x36\x46\x71\x14\x30\xba\xe4\x23\xfd\x11\x58\x48\x09\x33\x18\xb7\xd0\x87\xef\x1e\x3b\x89\x4b\xc3\xb9\xea\x27\xaf\x85\x3f\xca\x85\x95\xd3\x6f\xb7\x29\x99\x69\x16\x2f\x2e\xd6\xa2\xb5\x50\x75\xb2\xc6\x30\x80\x28\x57\x17\x6d\xec\x4c\xb5\xac\xf2\xb1\x3a\x35\xa9\x94\x9b\x91\x2b\xb5\x7d\x81\xeb\x0c\x8a\x8a\xdf\x3c\xf6\x4c\xb5\x71\xbf\x5f\x3d\x71\xf9\x87\xd6\x4d\x74\xe9\x19\xa0\x03\x36\xe5\x7d\x35\xee\x4e\xec\xfc\x65\x70\x00\xdd\x5b\x12\x99\x5e\xe1\xb1\x16\x59\x1c\xe5\x8e\x56\xde\x25\xb2\x9c\x94\x82\x9d\x1d\x68\x52\x1b\x95\x58\xe4\x72\x5e\xc7\x70\x39\x06\x9c\x0c\xd1\x7b\x2a\x00\x33\x59\xe9\xe1\xe1\x12\xc7\x59\x01\x76\xce\xbc\xe7\xf0\x01\xf1\xd1\x36\xe8\x18\xf4\x81\x8c\xfd\x94\x74\x5a\xfa\xab\x56\xf1\xa4\x06\xf9\x7d\xd9\xe6\x1b\x73\x52\x66\xd6\x82\xad\x7d\xf2\x6d\xd7\x0c\xde\x0b\x57\xfe\xa7\xdb\x2d\xf8\x32\xfa\x88\xa3\x5f\x53\x97\x94\x88\x4d\xdc\x41\x21\x84\x03\x01\x6c\xb6\xd5\x22\x1f\x3f\xeb\x5d\x3a\xee\x4a\x98\x40\xa9\x13\x07\x2d\x29\xf8\xd1\xa9\x36\x7b\xb0\xbb\xf5\x45\xf7\xda\xe7\xc0\x0a\x0d\x0c\x03\x42\x23\x1a\xe4\x62\xbb\x74\x2e\x14\x98\xee\x58\x4a\xe6\xc8\x3f\x2f\x1f\x2d\x04\x52\xbe\xad\x98\x22\x68\xcd\x3c\xfd\xe7\x8f\xf4\x22\xe2\x26\xbf\x7b\x2a\xf1\x13\x77\x57\x79\x7f\xb0\x2e\x52\x75\xc3\x48\x09\xd5\x4c\xa9\xee\x2a\x65\x27\x5e\x6e\x5c\xff\xdd\x20\xad\x1f\xa1\xee\x0b\xd8\xb2\x1e\x04\xce\x82\x9e\x02\xcd\xb6\x3c\x48\xbf\xcd\xd8\x6d\x3a\x08\xc5\x97\x89\xc9\xd7\x8e\x36\x18\x1d\xef\xeb\x72\x27\x10\x72\x75\xed\x6b\x5c\xcb\x12\x7c\xd7\x2b\x37\x4e\x17\xf5\xee\x0b\x5e\x47\xb4\xb3\xe1\x4a\x8e\xc6\xd8\x6b\xb7\x50\x71\x87\xf2\x8d\xb3\x2b\x3f\x3f\xa1\xca\x13\x44\x6f\xe5\x25\x3e\xe7\x83\x64\x5e\x79\x42\x72\x79\x9a\x86\x3b\x4f\xca\x99\xe4\x43\xcb\xaa\x05\xde\x3c\x50\xed\xf3\xd5\xcd\x7c\x10\x52\x9c\x6c\x09\xa0\xc1\x45\x34\x06\xac\x7e\xca\xfa\x9b\x3a\x1f\x36\x9d\x68\xf3\xc6\x18\xf5\x8e\xfc\x35\x9d\xf2\xf3\xfc\xd2\x47\x8b\x55\xa4\x1a\x11\xf2\x48\x7e\x7f\x70\xec\x29\x3b\x3e\xcc\xc7\x00\xef\x44\x4a\x33\xd1\xea\xe9\x84\x9c\x5b\x76\xd2\x9a\xfd\x5a\x23\x86\x1a\xef\x4f\x2a\x7b\xa3\xf6\x66\x30\x1f\xde\xb5\xd3\xd8\xf0\xdc\x9e\xe2\xe0\x14\xb2\x4c\x74\x65\xde\xe3\xc0\x96\x4e\xdd\x49\xed\x49\xed\xab\xb5\xca\x7a\xfb\x99\x57\x4d\x00\x1e\x58\x12\xa0\x85\x23\x1f\x24\x1b\x6b\x08\xc7\x3e\x80\xfb\x44\xbb\x2a\xdf\x55\x4f\x14\xfd\x6d\xce\x94\xa6\xf6\x36\x23\xd9\xc1\xde\xb4\x1a\xd1\x01\x65\x1a\x6b\x67\xae\x52\x34\xda\xae\x81\x97\x9f\xbd\x82\x33\x89\x64\x9a\x3b\x0a\x06\xc6\x8b\x80\x46\x8a\x99\x1d\x30\x07\x74\x87\x51\xfa\x69\x28\x1d\xb1\xb9\x4d\x6c\x16\x0a\x1c\xab\x50\x94\x3c\xdb\xb8\xde\xa5\x75\x09\x06\xb3\xc6\x59\x5b\xb5\x80\xde\xdb\xfa\xe5\x74\x64\xcc\x7a\x65\x1d\x4c\x51\xdb\xb5\xfa\x98\x05\x97\xd1\x76\x69"}, -{{0x49,0xc2,0x98,0xa2,0xdb,0x3d,0x25,0x89,0xc9,0xfe,0x16,0xa4,0xe5,0x71,0xe5,0xaa,0x23,0xcb,0xaa,0x77,0x7b,0x86,0x47,0x02,0x90,0xa3,0xed,0xa7,0xa5,0xd3,0xe9,0x6b,},{0xda,0xc5,0x23,0xd6,0x37,0x4c,0x8f,0xf1,0x5f,0xc4,0xdd,0xc7,0x13,0x71,0x5a,0xc3,0x5c,0xf5,0x54,0x7f,0xc1,0xb1,0xb2,0x64,0x6b,0x63,0xfb,0x41,0xa7,0xf2,0x16,0x21,},{0x2a,0x43,0x9c,0x73,0xc9,0x81,0x17,0xfb,0x29,0x52,0xe2,0xb1,0x61,0xf7,0xf3,0xb9,0x9e,0x7d,0x39,0xbc,0x69,0x7f,0x79,0x40,0x75,0xdb,0x7b,0x63,0x4d,0x29,0xf1,0xff,0x57,0x24,0xf6,0x77,0xf8,0x31,0x2a,0xd5,0x15,0xb0,0x97,0xcc,0xa9,0xdf,0xc3,0x0e,0x79,0xee,0x8a,0x7c,0x9d,0xd7,0x28,0xbd,0xd4,0x5d,0xf8,0x59,0xc7,0xbd,0xe3,0x0a,},"\x35\x82\xee\xb0\xd3\x71\xdf\x38\x5d\xe8\x8b\xaa\xd3\x80\xcb\x0c\xdb\x60\xea\xb2\xba\xeb\xb3\xc7\x98\x37\x75\x3d\x08\xe1\xcb\x78\xc0\xbd\x76\xdd\x11\x04\x45\x49\x56\xd5\x71\xce\xb7\xe6\xb5\x71\xa5\x23\x68\x35\xd7\x84\xb5\x0f\xf6\x60\x57\xb1\x35\x95\xe7\xd0\xc8\xf2\x5d\x08\xae\x8b\x54\xb6\x12\x3b\xa0\x81\x51\xac\x7d\xb0\xc5\x6a\x98\x0f\x7f\x0b\xb3\x9a\x54\xb4\x37\xf5\x48\x51\x97\x99\x86\xab\x13\x67\x83\x5e\x5c\x4f\x3a\x3b\x3d\x76\x0d\x38\x27\xe7\x6c\x56\x8a\xe7\xae\xbb\xb6\x12\xe7\x75\xbd\xde\xcc\xd3\x34\xac\x6b\xcd\x32\x53\xab\xc2\x9d\x4b\x7c\x3f\x10\x36\x26\x66\xf6\xae\x75\x08\x03\x70\xa3\x6c\xba\x55\xdb\x3a\x91\xcb\x57\x89\xe4\xd6\xf9\xef\xea\x4d\xf1\xdd\x77\x30\xa5\xe2\x79\x60\xd5\x3b\x51\x21\x94\x8c\xce\x5a\xf6\x53\xff\xf1\xd5\xb4\xe5\xb0\xa8\x8c\x71\x8c\x49\xb3\x1c\x79\x3d\x88\xc1\xcc\x45\xab\x8d\xa2\x9d\x05\xe9\x06\xcd\x05\x94\xb5\xf6\x63\x8c\x8e\xc3\xf1\x76\x0b\xa4\x23\xb5\xab\x1d\x08\xa5\x87\x70\xaf\xb0\xf1\x39\xab\xd3\x49\xc1\xbf\x16\x0d\x89\x02\x23\x9c\xe2\x4f\x19\xb4\xe1\xbe\x09\x5f\x7e\xd1\x65\xf3\x93\x1e\x3c\xbc\xc3\x07\xe9\xfc\x5c\x65\x80\x31\x22\x8e\x55\xcb\xbe\xec\x0d\x0b\xcf\x8f\x69\x51\x54\xa9\xee\xd1\xbe\xf3\x52\x28\x78\x9b\xfc\x0d\x23\x8b\x83\x72\xd3\x18\x32\x8c\x13\x39\xfe\xa0\x88\x14\xdb\x86\x21\xab\xca\x3a\xeb\x82\x09\x8b\x5a\xa8\x7b\xb9\x8f\x5e\x40\x52\x2a\x08\x88\x53\x2c\x17\x48\x45\x3d\xb2\xd2\xb3\x94\x3e\x4a\xbb\x31\x2d\xe3\x19\xae\xc4\x8c\xc1\xc9\x47\x75\x97\x29\x53\xfb\x64\x96\xb8\x16\x89\x37\x62\x35\x10\xcd\x48\xc8\xb2\x47\x95\x6d\x31\x68\x48\x6c\x17\x6a\xe7\xa4\xcb\x38\x4e\xac\xfd\xab\xfa\xdd\x9f\xba\x30\xa2\x3b\x81\x1b\xd7\x79\xf3\xcb\xa5\x43\x38\xc2\x8b\xb3\x38\x22\x38\xed\x3b\x8d\xd2\x1b\xea\xb2\xf5\xca\xde\x28\xc5\xe0\x9b\x31\xa4\x54\x80\x8a\x53\x48\x12\x2e\x3a\xe3\x81\x22\x96\xf7\x86\x9c\x38\x65\xc3\xc9\xd8\xfe\x18\xbd\x81\x2f\x2e\x60\xe9\x14\x97\x5c\xfe\x1b\xef\x8d\xbb\x80\x97\x00\x6f\x0d\x7c\xf3\xfc\x15\xeb\x95\xc2\x78\x54\xb1\x43\x12\xb8\x8d\x52\x80\x15\xaf\x69\xfb\x75\x05\xb8\xf3\x27\x03\xf6\x4e\xb1\xc9\x58\xf0\x46\xdd\x25\x12\x42\xf8\xbe\xa7\x46\x7f\xc7\x29\x1d\x09\x5e\x96\x96\xe1\x1a\xa4\x5a\xbe\x79\x24\xe8\x56\x35\x15\x35\xaa\x07\x73\xd3\xd9\xe6\x1c\xc9\xa2\xd8\x9b\x5b\x07\x74\xd7\x64\x5e\xe1\xaf\x7e\xb6\xfc\xd4\x40\xbc\x69\xd4\x3e\xde\xaa\xf9\x35\xfd\x2a\x52\x95\xac\x19\xa9\x7d\x70\xaf\x92\x98\x83\x0f\x81\xc0\xa5\x09\xf2\x42\xf4\x73\x37\x24\x78\xfa\x58\x79\xfb\x2c\xb8\x51\x10\x80\xfc\x2e\xcd\x82\x59\xb8\xc3\xce\x9e\x8b\x64\x07\x61\xdc\x79\x27\xc3\x2e\x7f\x5b\xae\x97\xa8\xb8\xac\x93\x56\x62\xe5\xf4\x5d\x14\xca\xd6\xd3\x4a\xff\xc9\xa1\x94\x14\xc4\x56\x6f\x45\xf9\x77\x39\x67\x10\x89\x4c\x53\x99\xed\x44\x80\xf1\x8e\x90\x95\x7f\xaa\x76\xcc\xb5\x12\xa2\xd0\x75\x73\x05\x8a\x95\xb4\x2f\xe1\x81\x02\x49\xd1\xc8\x5e\xc4\x31\xa0\x49\xd1\xae\xcb\x0f\x11\x83\x79\xbd\xc3\xf1\xee\x49\x0b\xc8\xa0\x54\xc3\x2c\x3d\xac\x76\x59\x96\x6c\xdb\x66\xf9\x95\xac\x40\x3d\x5e\x79\xeb\x6b\x25\xb3\xf3\xf6\x5a\x6c\xee\xc2\x20\xd6\x6c\x05\xf8\xa8\xa9\x8b\x80\x79\x9b\xa4\xf2\xc6\xdb\xbb\x4d\xfb\x58\x62\xc9\xa4\x6b\xca\x01\x3e\xbd\xfa\xba\x74\x94\xa3\x0c\xe1\x46\x06\xaf\xc0\xb0\xf9\x93\x14\x3f\xed\xee\x78\x96\xd9\xa6\xbb\x81\x49\x91\x66\xed\x02\xe9\x41\x86\xaa\xf3\x21\x87\xae\xb6\xe2\x82\x50\x1b\xca\x43\xb5\x7b\x7e\xfa\x09\x39\xc9\x34\xbc\x8f\xbb\xd2\x6c\x44\xb6\x18\x33\x5a\x35\xc6\x92\xff\x99\x6a\x5b\x95\xd3\x27\xdf\x9b\x2a\x66\x21\xb3\xb0\xf1\x90\xdb\x1f\x36\xd9\x11\xd1\xa6\x63\xa4\xeb\xf9\xa2\x85\x4b\xb4\xf4\x06\x10\x95\xb6\x98\x12\xc8\x2c\x2f\xfe\x3f\x92\xe9\xb4\x4d\x2e\xa6\x31\x69\x88\x1c\xae\x84\x53\xd6\xee\xf7\xcf\x69\xc2\x5a\x28\xb3\xf8\xdd\xc7\x01\x48\xef\x26\x72\x1a\x3c\x1f\x2e\x62\xd9\xd1\x0c\xea\x42\xfc\xa3\xfa\xcd\x74\x67\x3a\x4e\x7f\x33\x50\x73\x64\xaa\x28\x6c\x0f\x38\xd7"}, -{{0x82,0x3f,0x0c,0x29,0xfb,0xfd,0xd3,0xd1,0x82,0x8f,0x30,0x55,0xe9,0xec,0x01,0xff,0xd1,0xb5,0xa3,0x75,0x11,0x8d,0xdd,0x7e,0x4e,0x0c,0x43,0x71,0x9f,0x57,0x3f,0xf7,},{0x73,0x12,0x5f,0xc8,0x3a,0xbb,0x8b,0x7c,0x65,0x85,0x59,0xfc,0x12,0x73,0x93,0x23,0x1d,0x03,0xca,0x58,0x46,0xe0,0xc8,0x81,0x18,0xd1,0x3d,0x55,0xca,0x44,0x78,0x9d,},{0xfa,0x74,0x7b,0x6f,0xe3,0x38,0x1a,0xd6,0xbc,0x82,0xa9,0x56,0x43,0xc1,0xf4,0xa2,0x0b,0x76,0xba,0x73,0xbf,0xf0,0x0e,0x63,0x5d,0x64,0x20,0x2d,0x8b,0x0d,0xf0,0x3d,0xbc,0x56,0xb0,0x13,0x8b,0x3a,0x6d,0x41,0x98,0xff,0xaf,0x58,0xcc,0xd3,0xd3,0x88,0xed,0x25,0xeb,0xcf,0x77,0x04,0x43,0xe4,0x1e,0x9d,0x21,0x47,0x95,0x0a,0x30,0x0b,},"\x80\x2c\x39\xce\x7f\x2a\x50\xbd\x81\x62\x2a\xdd\x0d\xf4\xe0\xfe\x03\xec\x3d\x2d\x30\x5a\x45\xa6\x16\x52\x71\xed\x79\xad\xd2\x43\xb9\xa0\x0e\x52\x18\x31\x92\xfe\xb2\x4c\x4f\xdb\xd2\x2c\x80\x7a\xe1\x00\xef\xcf\x16\x5b\x9c\x99\x61\x94\xe0\x0f\xa8\x17\x76\x5e\xa9\x4a\x03\x07\x0e\x48\x66\x86\xb4\x45\xfc\xb2\x63\xcc\xfe\x1f\x58\x62\xf3\xb8\x4b\x10\xf3\x90\x08\x0b\xfc\xae\x44\x7a\xe0\x06\x97\x42\xb8\x61\x8f\xa9\x57\x5f\x7e\x63\x7a\xd5\x4e\x83\x4c\xaf\x03\x94\xd7\x45\x03\x2c\xe1\xe2\x55\xc0\x27\x32\x50\xf1\x50\x4b\x37\xa0\xad\xd9\x4a\xa2\x45\xc7\xde\x52\xc8\x0e\x05\xd6\xe0\xa9\x6a\x14\x41\x05\x43\x82\x6a\x49\xe9\xb9\x45\x62\x6d\x4e\x89\xf5\x50\x27\x16\x3d\x4b\xd6\xd0\xe9\xbd\x1a\x24\x77\xf6\x7d\x3d\x56\x68\xa4\x2e\x94\xd8\xb6\x11\x93\xd8\x21\xe0\xd1\xb2\x30\xfc\xad\xc5\x36\x13\xb7\x5b\x02\xcf\xb8\x15\x84\x56\x07\x7e\xbd\xf5\xa5\xf0\x0c\x3b\x5b\x18\x63\x70\xca\xfe\xc4\xa2\x1c\x69\xdc\xe1\xf0\x1e\xfe\xf2\x3c\x37\xab\x90\xf8\x58\x23\x8a\xef\xbe\x21\x2b\x55\x6d\x2f\x07\x34\x06\x55\x9f\x1a\x51\xd8\x4e\xff\xfd\xce\x07\xb0\x0d\x01\xbb\xf3\x37\x71\xcc\x12\xc9\x60\xac\x89\x36\x5a\x9c\x82\xc5\x23\x43\xf7\x60\x33\x81\xb8\x90\x23\xc1\xa6\xe7\x02\xa5\xb1\xe4\xbd\x19\x1e\xa6\x97\x0b\x5e\xa4\x51\xea\x05\xb5\x9b\xf8\x3e\x55\xf2\x9a\x1f\x80\x32\x12\xbb\x2e\x58\xf0\x61\x63\x33\xd9\x11\x47\x08\x52\x9e\x8b\x6c\x60\x81\xde\xeb\x7c\x29\x9a\x5a\x2a\x53\xcc\xd2\x4e\xd5\x8f\xfb\xfe\x50\x3d\x80\x61\x4a\xdb\x05\xca\x11\xcf\x29\xde\xd0\x09\x04\xea\x12\x39\xf8\x2b\xa4\x0c\x79\x3e\xbc\x33\x97\x75\xf8\xb0\xfe\x39\x01\xf5\x48\x2e\x31\x0c\x79\x3c\x6e\x2c\xf0\x1d\xc1\x57\x72\x7a\xf2\x38\xf4\x9c\x98\x62\x80\x4b\x04\x75\x51\xfd\x88\x6f\x4a\x48\x99\xe2\x2a\x6a\x65\x70\x11\x17\xa3\x85\x80\x55\xbb\xfe\x96\x6e\x37\x0e\x73\x3e\x17\xef\xad\xa2\x85\x9f\xd8\xff\xa9\xe0\x1f\xce\x56\x06\xa2\x55\x36\x76\x78\xf4\xbd\x4e\x21\xe5\xda\x0f\xef\x30\x75\x7f\x34\xe3\x89\xf7\x6b\x7d\x57\xc4\xe4\x10\xa0\x02\xe9\x00\xe4\x8f\xb2\x18\xc8\xf2\x77\x8f\x14\x8f\xee\x56\x96\x5f\x5b\x47\x3e\x25\x25\x6c\x23\xa7\xaf\x19\x83\x42\xcf\x3e\xf0\x2b\x84\xdf\x2c\xd5\x80\x0a\x46\x1c\x1b\x07\xbd\xa2\xf4\x26\x28\xa6\x8a\xd2\x9d\xbb\x82\xa4\x70\x96\x7d\x73\x02\xc9\x93\xb2\x34\x13\x6e\x5b\xf2\x55\xe6\x24\x8b\x10\x2c\x2b\xff\xb2\x01\x72\x37\x1f\x1c\xa3\xe1\x0b\x08\x10\xe8\x64\x95\x03\x54\x6d\x9a\x73\x1c\xf1\x9b\x08\x33\x57\xd4\xcf\xec\xc8\x9b\xed\xb5\x35\x06\xfe\x19\x9b\x67\x03\x91\xa6\x20\x06\x9a\x30\x81\xf2\x53\xb4\xd7\x90\x88\x0a\xa2\x3b\x53\xe9\x7c\x75\xdc\x0c\x36\x05\x40\xe5\xb0\xa3\xef\xb1\xac\xcf\xfd\x13\x74\x14\xff\x84\x23\xd5\x46\x46\xfc\x56\xba\x5f\x53\xbd\x84\xc7\x26\x7c\x2f\x7e\xe3\xe3\x76\x07\x54\x41\x54\x36\x5f\x9f\x85\x08\x1d\xd7\xd2\xee\x75\xd3\x02\x27\x5c\x79\x9e\xf2\x42\x7c\xa6\x49\x63\x55\xdc\xda\x1d\x44\xe0\xd9\x77\xbf\x68\xdb\x30\x06\x50\x0a\xe3\xf4\x00\xd6\xa8\xc7\xcf\x47\x05\x7d\x4f\xc8\x7e\xee\xcb\x02\x11\x6b\x73\xee\xd6\xce\x1f\xcc\xef\x6e\x8f\xb8\xae\xa3\x63\xb2\xf6\xf5\x32\x2a\x5f\x07\x53\xf4\x58\x99\x53\x76\x46\xd5\x86\x51\xbe\x90\x37\xbf\x91\x42\x3c\x29\x86\xf5\xcc\x2b\xcb\xce\x4f\xae\xc9\x03\x49\x8b\x40\xfc\x2d\xea\xb6\x60\x3d\x6e\xea\x58\x5d\x27\x20\xd2\x1b\xb2\x72\x2b\xc0\x5b\x35\xae\xd2\xbc\xc0\xe8\x04\xfe\x9d\x23\x9f\xaf\xda\x7d\xda\xfe\x1d\x78\x60\xab\xb0\xfb\x28\xf4\xbf\x2b\x1f\xbb\x62\xa7\x86\xe4\x55\xbe\x02\x4b\x19\x3b\x78\x30\xbe\x0d\x55\x8f\x02\xc9\xf3\xae\x31\xdc\x10\x7e\xe9\x42\x1d\xc5\xf0\xb0\xf8\x94\x02\xb7\x1a\x45\x81\x40\x15\x36\xbc\x47\x30\x85\x06\xd9\x69\x39\xa2\x06\x36\x27\x44\xe2\x7d\xde\x94\x4f\x40\x96\xa1\x2b\x5f\x63\xda\xb6\x4d\x04\x14\x84\xd3\xfd\x91\xa6\x2c\x2f\x0e\xf9\xae\x78\x74\x22\xeb\x27\xfe\xd0\x80\x2e\x25\xf9\xbc\x77\x5c\x49\x15\xa8\x37\xfe\x3e\xb7\xb9\xd5\x84\x3e\x4d\x82\x10\xc6\xb4\x94\xb6\x12\x81\x63\x7a\x6b\xe3\x20\x52"}, -{{0x65,0x67,0x66,0x33,0x37,0x42,0x14,0xc4,0xac,0x4b,0x7b,0xce,0xa9,0xf1,0xcc,0x84,0xb1,0xb7,0xe7,0x94,0x11,0xe3,0x10,0x52,0x5a,0xce,0x38,0x5f,0x45,0x66,0xc1,0xd5,},{0x0e,0x6e,0xc5,0x80,0x1d,0x8b,0xd6,0xb1,0xeb,0x42,0x14,0x21,0xa1,0x40,0x8f,0x13,0x4c,0xf7,0x12,0x33,0x8e,0x0f,0xfc,0x24,0xcd,0xcc,0xdc,0x4f,0x7f,0xa3,0x1d,0xbe,},{0xe0,0xb8,0x67,0xc9,0xdb,0xda,0x35,0x32,0x34,0x33,0xc0,0x46,0xe0,0x83,0x0c,0x25,0x1b,0x43,0x46,0xc5,0x39,0x59,0x72,0x28,0x6b,0x3a,0x72,0x31,0x0e,0xd4,0x52,0x6e,0x54,0x5d,0xc0,0x9d,0x39,0x18,0xf2,0xeb,0x99,0x20,0xbc,0x9b,0x24,0x1e,0x90,0x50,0xd8,0x48,0xd3,0x83,0x02,0x88,0x65,0x15,0x91,0xf9,0x36,0xd3,0xba,0xe4,0x53,0x01,},"\x9d\x62\x2c\x20\x67\x87\x69\x40\x93\xc6\xf2\x9f\x93\x61\x9f\x21\xbb\x64\xc0\x39\x41\x6d\x20\xdc\x70\x8a\x08\x4a\x9d\x2e\x49\x0c\xf5\x65\x8e\x13\xd6\x2c\xb0\xd2\x1e\xab\x00\xe4\x2d\x85\x1b\xc6\xec\x75\xda\xf4\x05\xd2\x37\x32\x46\xee\xa4\x15\xe8\x66\x29\x1b\xab\xf7\x64\x97\x68\x0a\xaf\x04\x42\x5a\x42\x55\x2b\x10\x7d\x58\xcd\x18\x56\x1c\x8c\x94\x83\xf7\x40\x74\x4c\xbf\xa6\x05\x4c\x1b\x12\x6f\x5a\x76\x65\x9a\xc1\x9d\xdd\xad\x4a\xb5\xa0\x91\x55\xd8\xc0\x50\xb5\x35\x4e\x06\xa4\xdd\x3e\xe3\xa6\xf9\xc9\x1e\x8b\x4c\x7a\xf2\x74\x96\x64\xe7\xab\xe9\x70\x61\x58\x9e\x15\x3c\x58\xe2\x7c\xf2\x99\xa2\x5f\x2b\x53\x0c\x06\x07\x31\xec\x0f\x43\x66\xbd\x1d\xeb\xeb\x4d\x4e\x91\x2e\x76\xe5\x08\x53\x4d\x43\x3e\xc4\x8f\x96\xb6\x2e\x15\x0d\xe9\x39\x63\xa1\xb3\xe6\xc8\x09\x1b\x49\x5a\x96\x51\x8c\xe3\xd3\xb9\xa8\xdb\xdc\x2a\x13\xfd\xd0\x77\xf2\x23\x1d\xe8\xd7\x6f\x56\xd9\xab\x1c\x2f\x9e\xfa\xbc\xe4\x63\x83\x64\xf8\xfb\x2a\x2c\x68\x3c\xa8\x19\xb7\x03\xab\x45\x3b\x11\xd3\x7a\x69\xfa\x4b\xcb\x80\x23\x98\x08\x34\xf7\xb9\x02\xad\x18\x19\xfc\x02\x92\x12\xfd\xea\x0a\xbf\x11\xde\xc8\x8c\x55\xd6\x8e\xf8\x7a\x26\xdb\xb1\x5d\xc3\xd3\xdf\xbc\xdd\xdd\x5e\xd7\x1b\xe8\x6f\x32\xc7\x6e\xe2\x22\x1d\x92\x43\x68\x3d\xf9\x51\x65\x64\xb2\x6b\xab\x5c\x84\x5d\x4d\xfe\x0a\xdc\xc7\xcb\x9f\xe1\xee\x2c\x05\x1a\xf5\x90\x8c\xe0\xcc\x3a\x90\x90\x4d\xbc\x0d\x36\x80\xed\x49\x92\xf4\x6c\xe2\x5c\x2e\xe8\x51\xc4\x14\xf0\x18\x7d\x89\x3e\x5c\x3b\x01\x89\xa7\xbb\x68\x93\xd6\x83\xf5\xe3\x39\x4c\xc0\x46\x29\x9a\x16\xa1\xc1\xb5\x69\x59\x33\xa8\x9b\xb1\x30\x30\x85\x5b\x81\xb3\xc7\x46\x85\xf7\x19\xde\x01\x60\x57\x5a\x0f\xf0\xa9\x1f\xd9\x43\x47\xb8\xbc\xbe\x12\x5d\x1d\x3f\x9c\xe7\x72\xa8\x12\x6e\x00\xf5\x63\xb3\x18\x96\x56\xd5\x52\x2c\x18\x7a\xb8\x31\xa7\xad\xe7\xac\x06\xfd\xca\xc7\xf1\xd4\x58\x82\xe5\x1f\x9b\xf5\xb4\x4a\x2d\xab\xa4\xa5\x3d\xbb\x31\x97\x0b\x4a\x0f\x12\x72\xfe\x14\x08\x7e\x0c\x3c\x7e\x45\x42\x31\x2f\xe7\x4d\x76\x7f\x21\xe7\xea\x48\x7d\x52\x84\x28\x4f\x46\xf2\x0f\x32\xc5\xb1\x6e\x1e\x0a\xc8\xd7\x96\xab\x2f\x80\xb3\x44\xe7\xa8\xd8\x4d\x5d\xe8\x23\xa5\x08\x97\x75\x2d\xc5\x49\xa4\x8f\xc1\x0b\xcd\x43\x6a\x7a\x93\xe9\x7c\xd0\x5d\x78\x30\x13\x8f\x32\x38\x79\x68\x0c\x34\x3c\x16\x46\x7d\x26\x4d\x74\x9b\xf4\x5e\x40\xf3\x9f\xbc\x3a\x00\xc4\x3b\x00\x69\x3b\x01\x56\x76\x8f\xf2\xe3\xf8\xad\x9e\xb6\x40\x50\x22\xf5\xca\xda\x66\x94\xe8\xa3\x3c\xdc\x59\xc6\x67\x3c\x44\x11\x72\x44\xeb\x03\xfd\x7f\xd6\x75\x93\x0c\x29\x4e\xdd\x29\x40\xf5\xf1\x80\x95\x3d\x91\x0c\x55\x48\x5b\x20\x57\xae\x0c\x93\x02\xf4\xa8\xe8\x31\xa5\x53\x0e\x3c\xbb\xf6\xf4\x72\x22\x40\x83\xa9\x52\xa8\x39\x0a\xb0\x0d\xc0\xf6\x9d\xfd\x88\x0e\xea\x2d\x73\x9d\x21\x8d\x6a\x66\xf2\x37\xf1\x0d\x44\x01\xaa\x75\x8f\xf8\x12\x0c\x0a\xe2\x76\x61\x27\x84\x90\x24\xf5\xa4\xcc\x57\x4a\x5b\x02\xb9\x35\x96\x68\x12\xcd\x1f\xb6\xd7\x9d\x0c\x4f\x59\xff\x80\xf0\x35\xa0\xb1\x09\xcc\xcb\x22\xfb\x08\x53\x5b\x87\x41\x49\xed\xf2\xa0\x97\x0c\x14\x88\x84\x27\xd0\x7d\x1e\xaf\xa6\x84\xa6\xd3\x45\x4e\x49\xb2\x25\x18\x4c\x6b\x99\x3e\xc8\xdd\xb8\xb5\xa3\x5e\xe4\x5f\x87\xf6\x92\x66\xd4\x90\x96\xa3\x17\xd8\x6a\xde\x27\xf4\x52\x9f\xe7\x23\x64\xd0\xb9\x58\x00\x72\x99\xd9\xde\x87\xd6\xff\x9f\xb0\x4d\x57\x3a\xea\x46\xba\xc8\xeb\x76\x47\x52\xeb\x46\x5c\xaa\xab\xa6\x89\xa6\x46\x0c\x11\x07\x30\xbd\xd0\x8b\x16\x89\xde\x7b\x05\xde\x59\xaf\x9f\xe2\x44\xac\x36\x3e\x95\xc9\x8b\x66\x93\x59\xaf\x90\x31\xa3\xa9\x3b\xa6\x31\xab\xf1\xf6\x1d\x20\xef\x7f\xc6\x88\x3b\x48\x40\xfc\x92\x67\x12\xe1\x3d\x87\x4b\x72\x2f\x6a\x79\xb1\x60\x70\xc0\x31\x13\x25\xe9\xa7\x0f\xcd\x86\x91\x6c\xfa\x1d\xa7\xf9\xd0\x56\x3a\x22\xfe\x9b\xfe\x85\x4b\x0c\x18\x6c\x86\x63\xb0\x61\xb6\x5b\xc0\x71\xe8\x39\x93\x8d\x8f\xdd\x7c\xf8\xf6\x95\x2a\x64\x67\xfa\xd8\xe5\x84\x90\xed\x2b\x26\x81\x33\x01"}, -{{0xd2,0xed,0xed,0xcd,0x85,0x32,0x06,0xcb,0xf5,0x9b,0xd7,0x4a,0x25,0xa3,0x03,0xfa,0x2d,0x6c,0x39,0x36,0xbb,0x48,0xeb,0x42,0xf6,0xd9,0x00,0xcb,0xe8,0x07,0x72,0xbe,},{0x22,0x44,0x11,0x1e,0x2e,0x76,0x9e,0xab,0x81,0x87,0x1e,0x06,0xc5,0x80,0x17,0x8c,0x23,0x5c,0x7b,0xf4,0xa5,0x2d,0x2e,0xcc,0xe1,0x18,0x87,0xa9,0xb4,0x6c,0x45,0xc8,},{0xbe,0x3c,0x2b,0x56,0x7f,0xe8,0xc2,0x08,0xc9,0x8e,0x71,0x97,0x11,0x7e,0xb0,0x1b,0x3c,0x19,0x7b,0xdf,0xc8,0x58,0x56,0x2d,0xc5,0xcd,0x90,0xf8,0xe2,0xc0,0x35,0x70,0x42,0x30,0x39,0x95,0xba,0xba,0x2f,0x40,0xb7,0x34,0x5c,0x56,0xdb,0x0b,0x46,0x25,0x58,0x0a,0xa8,0xdc,0xc4,0x8d,0xf6,0x01,0x9d,0x23,0xa8,0x38,0xea,0x71,0x72,0x02,},"\x80\x70\xbc\x0d\xb0\x89\xa5\x92\x54\x46\x01\x9b\x7e\x40\x3c\x74\xec\x78\x90\x3e\x4b\xd5\x4b\xc1\xd0\x8a\x54\xa6\xf0\xed\x75\xa8\x5b\x76\x3f\xf5\x4d\xc3\x3a\x26\x00\xcc\xb4\x57\xfd\xba\xea\xe5\x48\x47\x7f\x6d\x69\x47\xae\x26\xde\xb7\x1e\xac\xd1\xd2\xd6\x22\x82\xa0\x83\x84\x3b\xe4\xe5\x93\x1d\x91\xc9\x3b\x62\x82\xc5\x88\x07\xce\x8f\x0d\x88\x0b\x14\x38\xda\xd8\xfd\xcb\xa8\x61\x2d\xf7\x3b\x9f\xaf\xf3\xa9\xf7\xdb\x30\x05\x25\x05\x36\xaa\xbd\x98\xae\x02\x7a\x89\x5e\x10\xb5\xcb\x7b\x69\x87\x5c\x0f\x39\x93\xaf\x24\x51\x92\xf4\x39\x3e\x9c\x4d\x34\x05\x74\x6e\x31\x1d\x3a\x91\x44\x7f\xcd\xbd\x73\x06\xb6\x02\x0c\x93\x3b\xba\xb9\xe3\x9d\x13\x49\x16\x25\x03\x5c\x9c\x63\x6e\xfa\x17\x39\xc3\x58\x87\x10\xa8\x79\xd9\xe3\xce\x17\x64\x61\x6f\x10\x82\xe8\xdf\xf5\x75\x59\xc3\xf5\xa5\xd7\x6d\xd3\x01\x12\x4f\xa4\x89\xfb\x94\x9e\x9e\x03\x9d\xd4\x62\x1b\xda\x60\xf0\xb8\x6b\x31\x1e\x78\xed\x0a\xb3\xb5\x28\x96\x50\x44\xb2\x3d\x78\xee\x2f\x81\x06\x1f\x8e\xdb\xd6\x92\x99\x33\xd1\x8c\x02\x07\xde\xc4\xb5\xb6\xb2\xfa\x4a\xca\x27\x47\xcf\x5b\x11\x0d\xf0\x0b\x0c\x98\x27\xbd\xb3\xd9\xdb\x2c\x7b\x03\x28\xd4\x0d\x99\xe1\xf6\xb2\x28\xe4\x0d\xad\xae\x78\xae\xda\x02\x89\xb6\xa2\x3d\x4e\xb5\x83\x70\x88\xe5\xd8\x84\x13\x63\x2c\xcc\x22\xe2\x1a\x73\x76\x8c\x67\x32\x01\xe9\xa8\xd8\xdc\x6e\xb6\xf7\x39\x7f\xed\xbd\x39\x8d\x26\xf9\x69\x2c\xa7\x2f\x6d\x6c\xf0\x56\xaa\xac\x50\xac\x2f\x3b\x26\x6d\xbe\x5e\x7b\xe7\xa0\x24\x77\x45\x78\xea\xd5\x85\x24\x5d\xaa\xa7\x3e\x0a\xaf\x83\x3c\x07\x0b\xa4\xb2\x04\x4c\xcb\x5e\x5c\xd1\x6f\x9c\x0a\xd9\x2e\xa8\x44\x80\x55\xdd\x82\x8c\x79\x93\x5a\xa6\xc0\x74\x1f\x9e\x2b\x81\x03\x24\xfd\xc6\xe6\x1e\x84\x2f\x94\x57\x22\x68\xbf\x7d\x5a\xdf\xa7\xab\x35\xb0\x7f\xb1\x9e\x78\x15\xa8\xaa\x5d\x81\x13\x01\x30\xac\x5c\xda\x8a\x47\x51\xee\x76\x03\x8c\x0a\x6b\xc2\xfa\xba\x4c\x49\x7e\x62\xb9\xf1\xf1\x94\xb8\xa5\x99\xb0\x77\x01\x81\x4b\x6d\xfb\x7d\x84\xbc\xdd\x5b\x7b\x5b\xc2\x24\x9f\x1d\x38\x45\xef\xf9\xef\x8c\xc7\x32\x85\x35\xd7\x0d\x53\xc7\xaa\x0c\x73\x05\x90\x1d\xe7\xc4\xed\x2f\xe1\x83\x82\x65\xd4\xa4\x17\xb8\x76\xad\xbd\x88\xeb\x93\x3f\x27\xc9\xaa\x48\xc8\xc7\xe3\x4e\x48\x14\x7c\xcf\xfb\x2f\xb6\x1a\x34\x8f\xea\x13\xef\x67\xcd\xf2\xe0\x39\xe3\x3f\xd8\x9e\x2c\x1a\xd2\xa4\x25\x4e\x3b\xf7\x48\x45\x2a\xa8\x3e\xfe\xca\x46\xe7\x80\xed\xe1\xd1\x3f\xf4\xcc\x5e\x7d\x01\xed\x45\xeb\x8c\x74\x81\x8d\x48\x60\xaf\x47\x59\xa8\x3e\x14\x88\x96\xab\x68\x73\x43\x95\x76\x0e\x00\x14\x6b\x79\x3c\x3e\x72\x89\x8a\xa0\xb3\xc5\xe0\xc1\xd3\xfd\xf1\x21\x58\xd2\xe8\xff\x11\x23\xa3\xa0\xc6\x4c\xf6\x37\x4a\x7f\x44\xf1\x1a\x57\x5e\x48\xa3\x79\x18\x1b\x30\xa4\x86\x5c\xfd\x02\x2a\xa9\x83\x27\x56\x35\xce\x4f\x2c\xc4\x0b\xfe\x06\x60\x67\xec\x4f\xe2\x41\xfa\x04\x7b\x55\x27\x0a\x1a\xd0\x77\x6c\x5f\x96\x86\x10\x14\xcb\xf4\x0a\x04\x32\xc5\x59\xf2\x2d\x79\x34\x2b\x79\xf8\xe7\x04\x2d\xcc\xfb\x1c\xf5\x0f\x83\x08\x5f\x80\x63\xfb\x18\x87\xed\x2d\xfc\x9d\xb7\xef\xc9\x6d\xaa\x0f\xf2\xbc\x4f\x52\x33\x5b\x02\x11\x2d\x16\x39\x2e\x13\x4c\x02\x23\xde\x45\x8f\xc0\x72\xcc\x22\xbf\x9e\x7e\xab\xc0\x62\x08\x18\x0a\x57\xe7\xce\x48\x05\xee\x4e\x0f\xc0\x15\x84\x09\x98\xfd\x56\x86\x44\xa0\x38\x6b\x3d\x8e\x7d\xda\x52\xab\xf6\x4f\x7d\xd0\x08\x68\xfc\x84\xf0\x36\xca\x8a\x78\xe9\xba\x81\x71\xca\x90\x26\x7c\x74\xe6\x15\x9a\xca\xc7\xaf\x5b\xf2\x37\x59\xab\xc5\x3d\x82\xe7\x93\xdb\x87\xfd\xad\xe1\x36\x33\x54\xff\xdc\xb0\xbd\x4c\xc9\x21\x3f\x5c\x84\x54\x45\xfc\x64\x9b\x2a\x1f\x32\x9f\x9d\x41\xd8\xa0\x31\xab\x46\xb4\x72\x16\x0f\x03\x43\x4b\x4b\x6b\xc5\xa4\x01\x52\x4d\x61\x79\xad\x66\xf9\xe2\x21\xc9\x06\x7f\xc8\x7f\xe4\xa7\x7e\x21\xe8\x02\x3b\x61\x69\xeb\xf1\x09\x0c\xd5\x56\xa9\xbe\x50\xb9\x18\x7f\xe4\x60\x7c\x59\x25\xe6\x0b\x41\x4f\x6a\x5c\xbf\x8a\xfa\x15\xed\x0e\xb3\x4b\x67\xb4\xc9\xc5\xd5\x4a\xdb\xe6\x40"}, -{{0xb5,0x69,0xf7,0xc1,0xaa,0xdf,0x56,0xed,0x1b,0x5f,0xa1,0xb6,0xfa,0xd6,0x48,0xd0,0xdc,0x54,0x4f,0xf8,0xfc,0xd1,0x73,0x78,0x0d,0xe4,0x1a,0x7d,0x4d,0xe6,0x0c,0xb6,},{0x9e,0xff,0xa4,0xae,0xd9,0xc6,0x58,0xe4,0x34,0x60,0x71,0x43,0x44,0x68,0xa0,0xb8,0xa0,0x4e,0xcf,0x78,0x41,0x69,0x9d,0x63,0xe8,0x88,0x7c,0xe2,0x05,0x57,0x0c,0xea,},{0x2e,0x32,0xba,0x05,0x56,0xbd,0xe9,0x74,0xd7,0xa1,0x9b,0x3b,0x9a,0x1e,0x92,0xf1,0x83,0x92,0x4c,0x4b,0x74,0xc5,0xd7,0x51,0xb5,0xab,0x3d,0x00,0x79,0x67,0x01,0x6e,0xc0,0x3a,0xfe,0x91,0xd7,0x42,0xfb,0x22,0xb6,0x3e,0x5e,0x55,0xb2,0xfc,0xb6,0xc6,0x1a,0x46,0xe9,0xdc,0xe7,0xfe,0x9f,0xa3,0x0b,0xbf,0x66,0xae,0xf4,0xb8,0x5f,0x09,},"\x7c\x5a\xa4\xdc\x80\x78\xaa\x77\xe8\xb3\xb7\xfe\xe6\x10\x84\xcf\xad\x76\x47\x62\xf1\xef\x26\xd8\xde\xb7\xf2\xf3\xb1\x86\xdf\xc7\x72\x48\x75\x50\x19\x78\x45\xfb\xa2\xf4\xc2\x3c\x83\x5b\x9b\x58\xdd\x0b\x63\x5c\x64\x91\x35\x13\x7f\x24\x8f\x5e\xf7\x13\x56\x4d\xe3\xc9\x66\xef\xa5\xf6\xdb\x6b\xea\x9e\x30\x97\x07\x49\xf8\xe8\x72\xd8\xd7\xae\x45\x35\xb7\x5e\x17\x6e\xa0\x48\x9b\x91\x5f\x34\x71\xd8\x27\xeb\x5b\x44\x45\x86\x48\x8c\xfc\x3f\xa6\xa4\x50\x82\xda\xcb\x82\x64\x95\xe5\x0a\x3b\x5d\xc6\xbb\x93\x0a\x33\x1f\x30\xc3\x85\xbc\x3b\x24\xce\x70\xb8\x95\x96\xdb\x6b\xfb\x68\x7d\x99\xa5\x81\x98\x7c\xa8\x76\xea\x0e\x75\x76\x96\xb3\xfc\x03\x77\x9a\x65\x81\x30\xc4\x10\xb3\x44\xed\xac\xc4\x27\x7d\x44\x84\x54\x99\xd6\x78\xe1\x41\x4f\x15\xf3\x6e\x16\x63\x35\x18\x95\x69\xce\xf3\x56\x7a\xc2\xe3\xab\x82\x1c\x91\xc9\x32\x74\xf5\xc2\x8a\x5d\x1f\x7c\x1b\xf5\x09\x9b\x10\xf8\x4e\xcb\x13\xa4\xe4\x53\x8f\x66\x49\xbf\x74\xf7\x39\x4b\x70\x3e\xf5\x36\x49\xd8\x15\x16\xcb\x1d\xb5\x21\x41\x60\x65\xcf\x9f\x27\x6a\xb8\x0c\x93\x08\x89\x7a\x27\xdf\xe3\x7e\x5e\x14\x2f\x18\x19\xb8\xd3\x48\xdf\x50\xa0\x46\xa1\x28\x88\xe3\xb7\xf2\xdc\xc7\x0f\x52\x18\xd1\x5e\xbb\x9a\xa7\x29\x1a\x1a\x92\xac\x44\x5c\x51\xd3\xa5\x3d\xd6\x91\xef\xff\xcf\x5a\x01\xe8\x76\xa7\x2a\xa4\x81\xeb\x4f\x12\x1a\x07\x23\x97\xd8\xcc\x93\xbb\xc2\xc9\xa6\xc2\x8c\xc8\x9b\x11\xff\xc0\xe9\x10\xd8\x2d\x9d\x62\x98\xa3\x67\xa0\xe1\xe3\xe8\xc8\x65\xe4\x32\x6a\x31\x9b\x22\x66\x6e\x52\x9f\x19\x98\xf1\xb3\xc8\xef\xb5\xfc\x21\xcc\xe9\x70\x40\xfb\x62\x47\xda\xa0\x00\x0a\xc5\x55\x4d\x89\xe7\xb2\x71\x59\xdd\x0b\x18\x00\xb7\x60\xb7\x9c\x91\xef\x6e\x97\x0b\x1e\x6c\x5f\xf4\x24\x42\xb1\xb3\xae\x4d\x3c\x43\x9e\x08\xec\x2f\x6b\x94\x17\x73\x87\xca\x5c\x01\xdf\x6f\x07\xf8\xe3\x4d\x25\xed\xbd\x49\xd8\xb7\x4e\x31\xa5\xe6\x5d\xec\x1f\x87\x60\xfa\x22\xc0\x0e\x6f\xb1\xcd\x55\x5b\xe6\x8b\x0a\xb4\x35\x99\xf0\xb9\xf4\xa5\x4a\x7c\xcb\x06\x26\x83\x89\x5d\x5e\xf6\x6d\x24\xdf\xb1\x67\x8c\xb0\xd0\xe8\xc8\x01\xd8\xe5\xff\xe7\x9b\x91\x39\xfc\x96\xd1\x18\xeb\x39\xb9\xc8\xd4\x40\x44\x89\x32\x5d\x45\xb4\xa3\x20\x2b\xea\xdc\xa6\x6f\x83\x1c\x68\xef\xb8\x15\x94\x15\x81\x93\x0e\xad\x29\xfd\x5f\x21\x1b\x90\xe7\xa3\x9f\x0d\x4f\xf4\x8c\x62\xa5\x45\xe2\x8a\xc2\xce\x29\xbe\xdc\x35\x6d\x92\xfc\x00\x34\x71\x76\xd7\x76\x23\xe0\xe1\x80\x9e\xff\x3f\xe6\x2b\x75\xa7\xd9\xde\xb7\x27\xd8\x61\x72\xd1\x4e\xdb\xf2\x78\x9a\x57\x14\x3c\x69\x92\x5c\x91\x7d\x43\x3b\x46\x83\xb0\x69\x3b\x3c\xd9\xe7\xe3\x77\x99\x64\x10\x72\x7f\x5e\x6f\xb8\xf5\xcc\xd1\x86\x0a\x20\x29\x4e\xcf\x33\xfa\xf9\x7a\x1e\x0f\x85\xb7\x61\x44\x7d\x47\x61\xb9\x6e\x4d\xf1\xb3\x12\xbd\x41\x4c\xab\xcf\x49\x84\x97\xb0\xea\xd6\x7c\xd1\xe5\x90\x1b\xbf\x3a\x16\xa8\x89\x1c\xcc\xed\x8a\x90\x7d\xf8\x87\x26\x95\x2d\x4a\xb3\x70\xa6\xb7\xdf\x29\x42\xcf\x13\x61\x5a\x5b\xc1\x2b\x4e\x10\x6d\xc3\x01\x3c\x68\xb8\xfb\x90\x63\x99\xdf\x15\xf1\xaa\x90\xd5\x6a\xa9\x74\xb1\xd2\xb2\x8c\x1a\x84\x53\xb9\xbf\x07\x92\xa5\x1c\x97\xce\x8a\x12\xaf\xc9\x34\x1b\xb4\xc0\xc3\x7b\x12\xdc\xb1\x2c\x63\x94\x49\x77\x5d\x9a\xc5\xc2\xec\x49\x67\x3d\xa5\xaa\xf7\x49\x3e\xd5\xf1\xf2\x11\x6e\xae\xf7\x2b\xb7\xfb\x1e\x09\x3e\xde\x2c\x26\x31\x7f\x4f\x4b\x6a\xd5\x85\x34\x62\x05\xdf\x91\xa6\xe9\x6b\xc6\x6d\x30\x64\xbc\xe9\x52\x39\x8f\xfc\xe8\x80\x71\xed\x9f\xf2\x75\x0c\x65\xc0\xc3\x04\x12\x5a\xc2\xca\xdc\x4f\xef\x71\xa8\x18\x73\x24\x96\xa8\x4c\xa5\x74\xd4\x82\xd5\xa3\xbb\xa2\x0e\x16\xdd\x2f\xa2\x4d\x32\x70\xf6\xc6\x09\x92\xf7\xf6\x3e\x88\xf5\x2e\xff\x62\x22\x99\x8e\xb4\x41\x67\x27\x38\x43\x75\xf5\x9f\x00\xe4\x75\x12\xee\x46\x4c\x31\x84\xac\xea\xff\x3c\xcf\xb0\x6b\xd1\x5c\x18\x3c\x5e\x48\x59\x26\x28\x8b\x99\x7b\xfa\xaa\xec\xf6\xec\xbb\xf7\xd2\xab\xf4\x90\x6d\xf7\x6b\x12\x77\xc5\xf5\xa8\x7e\x68\x17\xb1\xc6\x36\xe9\x1e\xfd\x7e\xcc\xf6\x4f"}, -{{0x32,0x34,0x65,0xd0,0x31,0x3d,0x10,0x01,0xa2,0x61,0xab,0xfd,0x44,0xfe,0x65,0xc3,0x8c,0x9a,0x00,0xca,0x0f,0x20,0x33,0x5d,0x65,0x53,0xde,0x49,0x26,0x99,0xfc,0x46,},{0xe2,0x2f,0x16,0xbd,0x4c,0xc7,0xe9,0x4c,0x46,0xba,0x31,0x96,0x1a,0xf8,0xc5,0x83,0xf9,0xd2,0x71,0x8c,0x68,0xf7,0x3d,0x85,0x06,0x9f,0x60,0x8e,0x15,0xba,0x87,0x66,},{0xda,0x3a,0xad,0xb3,0x43,0x60,0xb2,0xda,0x0c,0x26,0x54,0x2e,0xa7,0x1d,0xef,0xa8,0xa0,0xbf,0x7f,0xbd,0xae,0x3e,0xe9,0xe1,0x1c,0x84,0x08,0x4a,0xd0,0x5c,0xce,0x7b,0xa7,0xd9,0x4d,0xe2,0x5d,0x85,0x63,0x98,0x26,0x16,0xbc,0xdb,0x5b,0xb6,0x39,0x5f,0xac,0x4a,0x7e,0x84,0xbc,0x77,0xe2,0x1e,0xd3,0x6d,0xf7,0x5d,0xec,0x99,0x0b,0x06,},"\xbb\x10\x82\xe1\xcf\xdc\xd2\x9b\xfc\xa2\x46\x4d\x5c\xe4\x46\xb5\xba\x65\x4b\xa5\x8c\x22\x53\x8d\xa9\x26\xb8\x30\x3c\xab\xfd\x28\x4a\x7b\xd5\x99\x4a\x78\x6f\xa6\x6a\xed\xf0\xe1\x5f\x20\xc3\x82\xcd\xac\xf3\xd1\x45\x57\xff\x7a\x82\x67\xfa\x04\x67\x2c\xac\xab\x76\x70\x08\x65\x0a\xa9\xb4\xa7\xc9\x07\x1c\x47\x99\xf1\xff\xa4\x5c\xa4\xd5\x86\xe0\x20\x47\x44\x4c\x14\x23\x19\x43\x46\x7a\x3a\xba\xef\xa5\x39\x59\xda\x22\x6e\xb0\xc1\x53\x92\x01\x97\x60\x15\x96\x97\x74\x82\x93\xc0\x25\x56\x87\x83\x58\x8a\x39\x10\xe7\x8e\x5e\xa4\x27\xc4\x40\x7a\x89\x01\x06\x1b\x8b\x99\x2b\x82\xa2\xdf\x58\xc0\x4a\x1b\x2c\x5f\xad\x11\xc6\xb3\x79\x85\x6c\x2e\x0f\xef\x8a\x95\x0d\xe7\xe0\xfc\x22\x31\x03\x09\xe0\x8b\x13\x2b\x0c\xce\x4f\xc1\xec\xbf\x94\x57\x4a\x38\x8d\x4a\xe3\x66\x75\xd3\x29\x9a\x95\x15\x54\xeb\xf1\x80\xeb\x38\x1e\x1b\x5d\xf9\x77\xd9\x38\x43\x38\x91\xbc\x47\x8d\x76\x81\x85\x0b\x9d\xc9\xc5\xc7\x69\xd4\x05\xf5\xd8\x83\x9f\xc9\x73\x61\xd6\xcb\x30\x6c\x20\x30\x26\xcf\x2e\x2b\x3d\x39\x84\x9e\x1f\x4b\x12\x25\xeb\x25\xef\x8a\xcd\x40\xb0\x06\xf2\x0c\x64\x4d\xb6\x50\xc7\x5d\x38\xc0\xfc\xdd\x48\xf5\x98\xc7\xb4\xa6\x01\x06\xe6\x9e\x19\xcd\x71\x25\x89\xce\xdc\xcf\x50\x86\x4e\xa5\xf9\xe9\x5e\x01\xf1\xdd\x85\xc7\x51\x4f\x2c\x94\xb2\x83\x59\xde\x41\x32\xb8\x8c\x3e\xe1\xd1\x0a\x80\xa9\xfa\xdf\xb6\x90\xe3\xd8\x86\x41\xb3\x16\x8f\x0b\x89\x6a\xf8\x99\x0a\xdb\xf0\xe4\xf8\xe9\xd3\xf9\xd4\xcd\x31\x4e\x12\xc3\xbc\xe0\xcc\x87\x38\xe0\xcf\xc1\x90\x5b\xe5\xef\xa0\x71\xf7\x10\xb3\x2f\x8e\x58\x98\xc6\x0e\xb1\xbb\x8f\xee\xb7\x40\x00\x56\x0f\x41\xcb\x2e\xbc\x32\xb2\x60\x0b\x69\x80\xa2\xa4\x06\x4d\xfa\xa3\x79\x7e\xc4\x4c\xfb\x72\xd3\x79\xf8\x09\x73\x79\xca\xd6\x7e\xcd\xc0\xc3\x24\x14\xfa\x41\xc7\x2b\x1b\x9e\x4e\xdf\x55\x18\xcb\x39\xfe\x90\x92\xb4\x39\xaf\x3a\x4e\xbd\x5a\xfe\x79\xbe\xdc\x0e\xa8\xbf\x17\x47\x9a\x28\x21\xf5\xe9\xbd\x91\xd7\xf4\xaa\x5e\x38\x46\x99\x52\x37\x19\xb6\x95\x7f\x82\x36\x7c\xd8\x5f\xea\x9d\xed\x62\x36\xa2\x07\xc9\x4c\xb3\x73\xe3\x39\x3c\xb4\xfe\x11\xf9\x0a\x1b\x87\x79\xe4\xab\x4c\x34\x66\x13\x6b\xf2\x1e\x2a\xab\x78\xf7\xd2\x72\x6d\xb6\x41\x4f\xa5\xc4\xa3\xf7\x31\x3a\xd2\x11\x6a\x6d\x7c\xe4\x0a\xaa\x10\x01\xc2\x70\x4d\x5b\x05\xae\x54\xc7\xcc\x6f\x56\x72\x17\xf1\xa4\x7b\xfd\x0e\xe7\x38\xea\xea\x5e\xad\xb5\x37\x10\x75\xbe\x07\x6c\x87\x50\xae\xce\xfc\x41\x7e\xa7\xbf\xda\xac\x3c\xc3\x8b\xf1\x6c\xc2\x6d\xf7\x60\x0e\x3c\x7e\x8e\x43\x1f\x26\x76\xfc\x2a\x8c\x43\xa6\xa1\x43\x68\xba\x62\xbb\x32\x43\x9a\x06\xbe\xac\x38\xa0\x47\xb3\x74\x5e\x26\xf4\x07\xad\x82\x3d\x6a\xd1\xc0\xb6\xa4\x43\x41\xe1\x5f\xc9\xb3\x31\x21\x4f\xfc\x89\x69\x82\x11\xb0\x51\x33\xd6\xd3\x43\x3b\x5d\x59\xf7\xab\x4d\x10\x9e\x54\xe4\xc5\xd6\xf3\x2f\xcf\x72\x30\xfa\x4e\x25\x28\xc8\x61\xbb\x21\xcc\xc9\xe3\x10\xe9\x49\x7e\x07\x7e\xa6\x75\x51\x0d\xa7\x12\xb1\xa5\xdf\x57\x5c\x5d\x1b\xf7\x36\x2d\x07\x11\x80\x03\x9a\xec\xfa\xa5\xc8\x57\x3c\x24\xc0\xf4\xeb\xe8\x1c\x2f\x88\x9a\xed\x3d\xe5\xa0\x00\xbe\x12\xfe\x3d\x0a\xf2\xdc\x2c\xd4\x24\x0e\x31\x4a\x17\x6c\x55\x3e\xfd\x5c\xba\x79\x8d\x9f\xf1\xe3\xd4\xbd\x9e\x90\xbb\x81\x13\xe3\x84\x9d\x73\x5a\xfa\x4a\xf6\x94\x5c\xc5\x7d\x4c\x37\x8d\xb8\x4f\x20\x6e\xf7\xea\xb1\x1c\x63\x7a\x7f\x72\x60\xf1\x22\xa9\x7d\xff\x67\x47\xe9\xb4\xc1\x74\xed\x0d\x64\xf9\xef\xd7\xfc\xcc\xf9\x81\x51\x9e\xc5\x80\xa8\x18\x25\x47\xd1\x79\x68\xc4\x01\x51\xfd\xf6\xd5\x4b\xc5\x7a\x91\x15\xf0\x40\xfa\xb5\xc1\x00\xde\xb0\x39\x12\x2b\x7d\x2b\xfd\x98\xb6\xad\xf3\x8f\x42\xb2\x96\xea\x3b\x37\x8a\x90\x42\x59\xb7\x5d\x60\x70\x3b\x48\x40\xb3\xf5\xda\x09\x62\x0a\x54\x77\x62\x80\xe9\xca\x9e\x8c\xd9\x24\xae\xd2\xb5\xdd\x2b\x49\x83\x4e\x58\x1c\xae\xd5\x27\x1c\xd7\x8c\xe0\x8e\x4b\xba\x49\xb5\x9c\xd7\x7c\x1b\x62\x76\x64\x91\x48\xab\x72\x47\xf9\x7f\xc0\x13\x16\x35\xde\x47\x4d\x3c\x23\x49\x3c\xa9\x8d"}, -{{0x60,0xff,0xdb,0xae,0x00,0x3f,0xa2,0x79,0x4f,0xca,0xbb,0xf8,0xf5,0xb4,0x16,0x44,0xfe,0x3a,0x7f,0x44,0xed,0x6c,0x83,0x41,0x93,0xda,0x07,0xa9,0xdc,0x5e,0x26,0x65,},{0x35,0xb5,0xeb,0x31,0xab,0x55,0x64,0x92,0x57,0x8b,0x3d,0xbd,0x6c,0xf1,0x68,0x7d,0x1f,0xdb,0x21,0x6a,0x72,0x58,0x18,0x07,0x96,0x63,0x48,0x2f,0x22,0x1c,0xe4,0x21,},{0xb8,0xf3,0xe1,0xf3,0x78,0x5a,0x2a,0x39,0xbb,0x08,0x6c,0xa4,0x65,0xc0,0xab,0xf0,0xa3,0xe8,0x74,0x43,0x22,0x5a,0xc6,0xe9,0x66,0xed,0x9b,0x45,0x31,0xc5,0x4a,0x89,0x4a,0x9a,0xbd,0x01,0xac,0x31,0xb8,0x57,0x57,0xfe,0x75,0x30,0x8c,0x95,0x94,0xff,0x65,0xf9,0x7c,0xdd,0x91,0xe8,0xd8,0xa9,0x3c,0xf1,0x2b,0x9e,0x6d,0xbe,0xe9,0x0b,},"\x3f\x8f\xf2\x0b\xb4\xf0\x08\x34\xc8\x0f\x2e\xe6\x89\x3d\x6f\x73\xbf\x7a\xce\x27\x29\x60\x1b\xb2\x6a\x0f\xb2\x72\xa4\xd0\xee\xa1\xfa\xe1\xd3\x06\xac\x2c\x5f\x32\xad\xd6\x01\x35\x85\x1d\xa2\x7e\x4f\x12\xe6\x4e\xa5\xe9\xe9\x96\x0b\x13\x83\xb0\x4c\xe0\x5a\x98\xb0\x41\x4d\xad\x97\x1e\xa9\x89\x44\x87\x1d\x41\x5c\xc2\xc4\x6d\xa4\x03\x97\x6d\x9f\x21\x93\x89\x58\xd4\xea\x8c\x79\x03\xb1\x4f\x2a\x44\x85\xfd\x69\xaf\xb2\x4a\xbe\x10\x2d\x8f\xec\x26\x6f\xb4\x68\xb4\x11\xeb\x20\xa3\x39\x67\x7d\x88\xeb\x31\xc9\x97\xb4\xdc\x88\x56\x13\xf0\xbe\x7c\x70\xda\xf8\x56\xa3\xdf\x92\xda\x96\x02\xfb\xa2\xe6\x74\x9d\x2f\x42\x6b\xee\xf6\x86\x62\xd5\xb0\xc2\xfd\x31\x32\x1b\x22\xb5\xec\x59\x7d\xa5\xd7\xe6\xa2\x88\xeb\xd9\x44\x3c\x5f\x39\xeb\x87\xdc\xf4\xa5\xad\x9d\x56\xc6\xba\xf6\x08\x09\x96\xa7\x79\x36\xbd\x87\xdc\x3c\xb4\x2e\xd4\xc4\xd4\x26\x88\xa9\xe1\x93\x82\x9b\x76\x1f\xf3\x20\xe2\xa6\x6c\xc6\x76\x48\xe7\x0e\xea\x3a\x1f\x2f\x9b\x9d\x5b\x42\x02\xfb\x5a\x39\xe9\xad\xc6\x09\x08\x6a\x9b\xe2\xa8\x32\x3a\xc6\x69\x31\xbd\xf6\xc5\x04\xd3\x33\x62\x11\xe4\x6f\xde\xfc\x48\x1f\xbf\x17\xf6\x13\xda\xb1\xfc\x5c\x09\x7c\x92\xdb\x06\x09\x90\x6d\x78\xb2\x5a\x45\x5a\x30\x45\x71\x8e\xfd\x3e\x3b\x14\xe2\x52\xb1\xae\x59\xc7\xc3\x89\x3e\x31\x91\x3b\x2c\x26\x4c\x0f\xfc\x3b\x60\x6c\xa1\xb0\x1d\xc4\x7e\xe8\x28\xa0\x8e\x46\xaf\x60\x4e\x59\x0d\xef\x44\xd2\x7a\xab\x93\xa4\x03\x25\x1f\xca\x07\x72\xe9\xdf\x0f\xab\x7a\xf0\xcb\xc5\x18\x1e\xfd\xa4\xda\x91\x3d\x8e\xb6\x45\x2f\x6c\xec\xbd\xa2\x04\xbc\x72\xd7\xc9\x90\xf6\x0c\xe0\xdd\x83\xc6\x34\xe9\x12\x23\x60\x91\xb0\xa6\x67\x3a\x7c\x89\xea\x59\x30\x8d\x55\xbd\x7e\x63\xa8\x52\x67\x74\xcb\xdd\x7a\x13\x39\xfa\xc2\x12\x4c\x90\x22\xab\xd6\xfe\xce\x7f\x2d\xae\xdf\xd8\x7f\xa6\x83\xdc\x0e\x3e\xf4\x08\x06\xa0\xab\x19\x87\x69\xd3\xa9\x9f\xe8\x1a\x99\xb6\x86\x00\x31\x90\x87\xaf\xa4\xea\x79\xd7\xee\x45\xda\x9c\xd4\x08\x09\xf4\xee\x8f\x4e\x25\xa0\x17\x75\x21\xee\x9d\xba\x8b\x56\x21\x2e\x88\x71\x9b\xb7\x36\x73\x36\xf4\xa7\xbc\x71\x22\xb4\x1a\x7d\xfa\xa2\x67\x2f\x92\xf2\x34\x03\xa1\x0c\x4f\xb2\x53\x88\xc6\xb2\x00\x81\x09\x3d\x49\xf3\xbe\x8a\x9e\x1c\x63\x4e\xf7\xba\x96\xb6\xd5\x23\xdd\x6f\xf6\x13\xc0\xa2\x3b\x60\x45\x70\x26\xcd\x48\x5b\xa8\xdb\x61\xd8\x0a\x0d\xc6\x59\xd9\xaf\x42\xa3\x8c\xae\x77\x7f\xec\x68\xe3\x9c\x52\x98\x6f\xf9\xfc\x20\x78\x9c\x10\x58\x51\x07\xc0\x40\x47\xb6\x6b\xa1\x4e\x93\xfb\x90\x4e\xa9\x0d\xf7\xac\x9f\x01\x54\xc9\x6f\x32\x36\xac\xf6\xdc\x8b\x44\xf5\x54\xc0\xcd\x51\x31\x93\xe5\xdf\xd8\x7e\x08\x5a\xd4\xb3\x8a\xa4\xc5\xe3\x6b\x24\x27\x72\x20\x88\x81\x6e\xcd\x2b\xc3\xa3\xdd\xa0\x1e\x4f\xb3\xff\x5e\xec\x7a\x64\x17\x32\x2b\xa6\xa2\x77\x73\xd2\x44\x95\xa8\x39\x19\x4a\x4a\x58\x2f\xe5\xab\xdb\x8b\x5d\x53\x3a\x24\x26\x25\x89\x24\x1f\xc8\x1f\xdf\x5e\x79\xfd\x26\x77\x64\x28\xf8\xe1\xce\x9e\x92\x6c\xf2\x72\x71\x6e\x75\x83\xab\xfc\x67\xa9\x4a\xae\x08\x16\xc1\x00\x0a\x19\x61\x70\xbb\xff\x1f\x45\xe5\xed\x9e\x26\x7a\xce\x1e\x4d\x91\x5d\xce\x72\x16\xc5\xf4\x04\xde\xf6\xfe\x2b\xd8\xb2\x8b\x2e\xcc\xf3\xe2\xae\xa0\xc0\xd6\x62\x63\x90\x27\x4e\x47\xe7\x45\xed\x3a\x23\xbc\xfd\x21\xd2\x84\xc3\x95\x37\x9d\xc0\x20\x80\xf0\x79\x36\xbc\x15\x4e\x7b\x99\xee\x73\xdb\x18\x8b\xd2\xa3\x94\xe0\x3a\x01\xff\xe2\xd1\xb3\x30\xce\xb7\x21\x58\xf9\x58\xc7\x16\xa8\x17\x11\xdb\xf6\x5a\xff\x8c\xd1\x2f\x5d\xfa\x53\xb3\x76\xeb\xb8\xb9\x8f\x86\x28\xf1\x7e\xf8\xb2\xab\x9c\x0b\xb6\x84\x12\xf4\xe3\x47\xa6\x33\xe2\xf8\xda\x1a\x55\x6d\x96\xf4\xaf\x72\x11\xc0\x78\x07\x9c\x10\x54\x1c\x07\xdc\x37\x22\xd1\x8d\xab\x8f\xa8\xbc\x49\x25\xab\xa5\xc9\x66\xf8\x05\x04\x03\x22\xdf\xbb\xbe\x87\xfb\xfe\xb1\x96\x1f\x5c\xcd\x40\xa9\x1b\x99\x7e\x54\x31\x5a\x7e\xef\xc3\xa4\x7b\xb0\xc8\x7d\xc2\x37\x55\xce\x72\x27\x57\x49\x96\xf4\xbe\x7a\xa3\x44\xfe\x0d\x17\xb9\x7b\xc5\x0c\x58\x38\xf9\x92\x92"}, -{{0x17,0x4e,0x99,0x3d,0x9b,0x81,0xf2,0xaf,0x67,0xe9,0xff,0xb8,0xeb,0xd5,0xda,0x41,0x79,0x66,0xa9,0xe7,0x7f,0x66,0xc6,0x5c,0x76,0x77,0x38,0xfe,0x83,0x57,0xd0,0x7c,},{0x3b,0xb7,0x38,0x6f,0x1b,0x1c,0xbf,0xae,0x55,0x37,0x03,0x83,0x3e,0xbc,0xbf,0xe2,0xdf,0xff,0x8c,0x89,0x9a,0x07,0x92,0xd7,0xce,0x23,0x22,0xb5,0xba,0x64,0x5a,0x5f,},{0xe6,0x07,0xbc,0x9a,0x53,0x60,0xb3,0x1d,0xa5,0x6b,0xe1,0xc5,0x44,0xc2,0x00,0x02,0x84,0x95,0x1d,0x86,0x89,0xf4,0xb7,0x22,0xbc,0x46,0x73,0xa0,0xc8,0x48,0x9b,0x84,0x48,0x3e,0xd8,0xe7,0x6e,0x29,0x7e,0xa0,0x46,0xe8,0x5b,0x37,0xba,0x56,0x30,0x58,0x5e,0x53,0x75,0x56,0x6a,0x18,0x7a,0xfb,0x56,0x96,0x66,0x1e,0x5b,0xfd,0xc1,0x0e,},"\xa4\x01\x75\x0a\xfc\x48\x37\xdf\xe3\xaa\xcc\x28\x4a\x59\x71\x45\xdf\xef\x02\x62\x9e\xf8\x7b\xd0\x93\x8d\x44\x39\x79\xdf\x76\xf2\x9f\xcd\x66\xa5\xb7\x1e\xa8\xab\x78\x72\x77\xe3\x05\x6f\x6e\xa1\x1b\x08\xbd\x23\x89\x79\xf9\xd3\xb0\x62\x53\x8c\x4d\x60\x40\xa8\x6b\x6e\x32\x04\x7a\xec\xc5\x9c\x23\x77\xad\x0e\xa4\xc4\x0c\x79\xff\x9f\xe9\x8c\x95\x8b\x2b\xf2\x5f\x2f\xd6\x34\x24\x32\x63\x6f\x5f\x7d\x5b\xb0\xd2\xec\xf1\x81\x83\x42\x6c\x73\x14\x79\x84\xd9\x5b\xbe\x16\x2e\x11\x97\x2d\xdb\x78\xa2\xa7\xc3\x45\xc5\xc0\xbb\xba\xba\x9c\xf3\x8a\x2d\x5d\xd5\x09\xa7\xdf\x8b\x84\x28\x74\xa9\x6e\x64\xb5\xd6\x4f\x5c\x41\xa2\x1d\x20\x8d\x14\xce\xa7\x06\x6c\xf2\x2d\xee\x0c\xa4\x1a\xa4\x6a\xb9\x21\xd4\xce\xec\x89\xec\x87\x3f\x77\x96\x0e\xda\x60\xd9\x67\x6c\xfd\x0d\xbf\xae\xc8\x72\xc2\xad\xe8\xfb\xa4\x28\x5a\xac\xd5\x27\x14\x3a\xe0\x34\x1d\x67\xd0\x07\x81\x19\x65\x3b\x5d\x23\xd4\x6e\x6e\xf7\x02\x64\xb1\xb0\x91\x38\x70\x87\x76\x23\x71\x6d\x0f\x1a\x59\x02\x1b\xe7\x4c\x91\x4b\x43\x24\x71\xa4\x3a\x29\xf2\xb6\xdb\xeb\x6a\x22\x3e\x2d\xba\xab\xb8\x20\xb4\xad\xbe\x33\x78\x29\xe1\xde\x0c\x18\x4d\xd0\xd0\x9f\x9d\x01\xd4\x25\x27\xe5\xd4\x0a\xbb\xda\xcc\x8a\xc0\xf1\xb2\xc5\xc1\xcb\x2f\x23\x87\x6d\x2d\x1b\x6b\x43\xdf\xe4\x82\xf9\xd4\x5a\x18\xf5\xc2\x2b\x15\xf1\xfe\x52\x1e\xf5\x7b\x08\xae\xc6\xa3\x03\x39\x25\xc7\x45\x4c\x93\xe6\x31\x9e\x77\x8a\xc4\x94\xfb\x14\x0a\xe5\xf1\xa3\x1c\xc8\x32\xca\x24\x88\x65\x10\x04\x06\x3b\xcf\xf8\xfd\x9a\xe9\x26\x6a\xf5\x27\xf2\xc3\x1f\x6a\xcb\x8f\x3d\xeb\xd9\x97\x8e\xf9\xdf\x01\x08\xe3\xd5\x0c\x49\x19\x90\xc9\x0d\xd8\xee\x9d\x64\xea\x4e\xbf\xd7\x11\xc9\x9d\x90\x44\xec\x11\x34\x2c\x53\x83\xca\x39\x23\x2e\xd9\x7a\x07\xe4\xdc\x51\xdb\x4c\x1f\xe9\x47\x34\x8d\xff\xe7\x0a\x95\xc9\x9d\xb1\x47\x51\x31\x48\x01\xf1\x3f\xa2\xbf\x42\xd8\x67\x37\x5a\x08\xee\x9b\x3b\x79\x9e\x0b\x15\x27\x8e\x95\xe9\x1a\x89\x68\x06\x4d\x6d\xfd\x8f\x51\x15\x43\x8c\xcb\x8b\x51\x6c\xa0\xc4\x1d\xbb\x19\x87\x3c\x6e\x10\xa2\x36\xec\xc2\xda\xd5\x22\xf8\x0f\x01\xc1\x4e\x2f\xa1\x4a\x0d\x79\x2b\x9f\xc4\x86\xc6\xfb\x0e\xfb\xdf\x21\x30\xf0\x2d\xf1\x49\x7d\xb5\xab\xa8\xbe\x61\xca\x70\xb2\x93\x88\xe4\xee\xc7\xe0\x69\x4a\x38\xc0\xd0\x3c\x59\xbb\x6a\x2d\xc3\xcc\xd6\xdd\xe1\xe2\x9e\xe2\xc1\xb3\x25\xac\x72\xaa\x8e\x6f\xab\x91\x38\xf8\xb6\xf5\xd3\x24\xd4\x6a\xf3\xa3\x54\x2c\x8b\xd8\x7c\xb0\x4f\xaf\xc5\x4b\x5d\xb8\x27\xde\x60\x67\x62\xa0\x97\xb6\x22\x79\x9c\xa8\x27\xbd\xa9\xc1\xc0\xbb\x26\x7e\xba\x82\x54\xa8\x1c\x6b\x85\x8a\x37\x5b\x94\xbd\x09\xf3\x9e\xeb\x88\xcb\x14\xb8\xd4\x6e\x47\x40\xdc\x1a\xb4\x2a\x89\x5f\x86\xd2\xc5\x7f\xc2\x8b\x07\xb7\xf6\x0f\xc4\xf8\x84\x7b\x8b\xc8\xad\x83\xa2\x48\x1a\x28\xf2\x9b\xca\x35\x10\xff\x8b\xf1\xdd\x75\x81\xe3\x35\x71\x64\xf4\xfe\x92\x0f\x9d\xe8\x39\x37\x6d\xe0\x64\x90\x0d\xc7\xf8\xbc\xf5\x11\xdc\x57\x2e\x0f\x0f\x6a\x75\xb9\x29\x79\x7d\xa4\x1c\x52\xea\xe6\xfe\x13\x75\x0c\xe3\x51\xe8\x76\x76\x30\xba\xdf\x6d\x7d\x4e\xab\x90\xcd\x19\x04\xc9\x6c\x04\x8a\x9a\xcb\x21\x3a\x9e\x5b\x86\x46\x15\x73\x8a\x84\xf2\x22\x98\x6a\xc2\x35\x54\xcf\x4c\xe5\x4e\x80\xab\x57\x33\xc0\x65\xb8\x04\x59\x92\x1d\xd3\xd8\x37\x2d\x0e\x85\x94\xd4\x36\x43\x51\xbf\x04\x1c\x14\x6f\xa8\xd2\x3a\x19\x3e\xb8\x07\xec\xe2\x3f\x24\xab\x65\x95\xe9\x32\xc9\xce\x1a\x75\x9b\xf7\x88\x91\x4d\xb0\x08\xe8\x70\x98\xdd\x81\x46\x5e\x26\x10\x64\x7a\xc3\x8e\x08\x86\x66\xf6\x0e\xc5\xd0\xe2\x17\x33\x20\xa4\x0c\xd9\x85\xf0\xe0\x0d\xbc\x2b\x45\x70\x72\x74\x83\xa8\xc2\x5f\x6f\xc1\xe0\x93\xbb\x57\xcc\xaf\xd1\xca\x20\x2f\x29\x86\xc7\xc5\x54\x0a\x7c\x3e\x10\xc4\xa6\xfc\x26\xd1\xd6\x2c\x2c\xa5\xaf\x83\x05\xce\xeb\xe4\x2f\xf9\x6e\x7d\xc5\x48\x21\x43\x75\xe8\xa7\xf9\xf7\x12\xba\x8b\xd8\x75\xe4\x3c\xa1\x0c\xf9\xb1\x83\xf0\xc8\x51\x95\x12\x92\x85\x38\xa4\x78\xcb\x98\x25\x9b\xd8\xb3\xe3\x34\xbc\xc4\x63\x55\x95\xca\xd3"}, -{{0xe5,0x37,0x15,0xfe,0xc9,0xd3,0xb2,0x0e,0x9c,0x29,0x91,0xe5,0x4b,0x5e,0xb0,0xa8,0xcc,0x81,0x87,0x55,0x69,0xc9,0x5e,0x22,0xa2,0x00,0x13,0x60,0x02,0x17,0x60,0x04,},{0x53,0x51,0x89,0x9b,0x69,0xb2,0x11,0x6b,0xc7,0xf8,0xa8,0x81,0x4d,0x1e,0x5b,0x9f,0xc7,0x85,0x69,0x8b,0xeb,0xd9,0xab,0x14,0x27,0x7c,0x3e,0xcc,0x01,0xef,0x8b,0x1d,},{0x3d,0x0a,0xdc,0xe7,0x7a,0x4e,0x04,0x6f,0xcb,0x9b,0x49,0xad,0x5e,0x6c,0x68,0x09,0xc8,0xac,0x33,0x6c,0x73,0x34,0x04,0xe5,0xd3,0xf0,0x15,0xc9,0x22,0x5c,0x3d,0xf4,0x6e,0xf2,0x1e,0xa3,0x4c,0xff,0xb3,0xaf,0x69,0x97,0x4f,0x8b,0x7e,0xab,0x2d,0x23,0xfc,0xd5,0xa1,0xe1,0x75,0x3a,0x40,0x23,0xde,0xb3,0x81,0x86,0x29,0xa9,0x8a,0x0b,},"\x84\x31\xcd\x16\xd5\xc0\x93\x77\x5e\x18\xc0\x82\x52\xc4\x3f\x95\xb1\x01\x7e\xb7\x11\xfc\xaf\x73\xe1\xe0\x0c\x0c\xd6\xf3\x44\x87\x44\xab\x9b\x0e\x64\x33\x55\x18\xc4\x83\xae\x94\xde\xb9\x76\x77\xf8\x18\xf0\xe8\x1a\x74\x90\x61\x5b\x71\x41\xb9\xc3\x5f\x80\x55\x6e\x69\x71\xce\xa2\x8e\x9a\x32\xc3\x28\xcc\x26\x69\xfc\xa5\xb1\x23\xcb\x66\x2d\xeb\xab\x2b\x98\x15\x77\x64\x66\x80\x70\xe1\x8e\xdf\x76\x1a\xe1\x96\xbd\x4b\x24\x4f\xea\x7b\x74\x98\x45\x16\xbe\x2c\x00\x73\x9e\x76\xe6\xc4\xb6\x21\xcb\x39\x83\x76\x5a\x20\xd8\x47\x78\xd5\xa4\x35\x0b\x16\x8f\x6a\x0f\x71\x2a\x98\x20\xa8\x5a\x63\x6f\xaf\x92\xc7\x89\xc4\x28\xcf\xd2\x96\x2e\xd2\x07\xc3\xac\x88\x99\xc2\x58\xca\xc1\xad\xb5\x15\x9f\x76\x4b\xa3\x72\x29\xc5\xcb\xf7\x83\xfc\x9a\xa4\xd1\xea\x46\xec\xc8\x5f\xe0\x96\x14\x85\xd4\xfc\x5c\xb2\x1d\xf0\x01\x2a\xc9\xb9\x55\x37\x3b\x14\x22\xe5\x1a\xfa\x1c\x55\x09\x88\x86\x2c\x86\x13\x3b\x76\x0a\xa6\x30\xfc\x0a\xce\xe8\x98\x91\x17\xd1\xdd\x96\xe3\xe6\x28\x7b\x69\x28\x7c\x59\x0b\xdc\xa9\xcb\xc8\xee\xce\xf2\x81\xee\x6d\x1c\x8d\x88\x82\x2b\xfe\xa5\xfa\x0f\x53\x0f\x23\x27\x80\x93\xc7\xc8\x5a\x0d\x44\xc3\xa7\x74\x04\xee\x79\xf1\xc8\x36\x8c\xd7\x32\x1b\xf1\x48\xfd\xa4\xdc\xf2\xeb\x07\xe4\x63\x0e\xa4\x22\x58\x75\x86\x37\x17\x80\x51\x45\x36\xb8\x94\xc5\x24\xe6\xb8\x3d\x5a\x76\xa1\x5c\x83\xe9\x5a\xb3\x14\xe0\x7b\x34\xb9\x8c\xd9\x9e\x07\x70\xb4\xeb\x9b\x3f\x3f\x50\x5b\xae\x8a\x06\xf7\xf9\x50\x25\x8d\x79\x07\x48\x10\x71\x95\xeb\x4f\x6b\x84\x84\x0f\x8c\x05\x90\x72\x73\x96\xed\x14\xe3\xf5\x32\x39\x47\x6c\x4d\x2a\x72\x69\xb2\xe1\xf9\x72\xfb\xff\x33\xe4\x72\x44\x26\x74\x5e\xc8\x86\xa3\x29\x16\x29\x5e\x70\xd4\x68\xd0\x6c\x7d\xbb\x5f\xf9\xa3\x54\xe1\xac\x90\x3b\xb4\x5c\xa5\x26\xf0\x8b\x49\xa6\x5e\x82\x29\x7d\x8d\xd3\xfb\x25\xaa\x42\x8f\x64\x34\x5b\xca\x97\x40\xd9\x07\x8d\xac\x9e\x11\x38\xc9\x21\xbd\xd7\x48\x81\x67\x3d\x49\xd0\xcd\x20\x06\x81\x17\x23\xde\x28\x7c\x6c\x95\x83\xe4\x56\xa0\x1a\xb1\xa3\x4d\xfa\x1e\xaa\x96\x3b\x71\xe8\xbc\x7f\xa8\xa9\x8c\xad\x4f\x94\x1e\x4b\x37\xb6\x0e\xef\x92\x3b\x32\x94\x88\x23\x50\xb3\x8e\xa4\xea\xc0\xe9\x23\x2e\x93\xc5\x32\xdb\x5d\x7e\xec\x8e\xcf\xae\x65\xe0\x80\x47\x30\x78\x77\x7d\xdf\xdd\x11\x50\x8a\x6e\x59\xf0\xeb\xaa\x3f\x60\x44\x1f\x82\xa7\x1a\x73\xc8\x4b\xca\x06\xa3\x71\xff\x5c\x9f\x77\x21\x3a\x2d\xb7\x95\xd4\xa8\x89\x78\x23\xd8\x8f\xd9\x2a\xe3\xe0\x57\xe8\xbb\xd8\x0c\x99\x0a\xf8\x38\x6b\xdf\x26\xf1\x2d\x97\x3c\x8c\x5f\xf9\xed\x6f\x7b\x2d\x8e\x61\x83\xcf\x6e\x68\xf3\xbb\x89\x8f\x59\xa9\x3e\xc4\xde\x3b\xea\x60\x5a\x5d\x8b\x15\xdf\xab\x71\x3f\x35\x85\xc4\x8d\xc9\xa5\x76\x82\x42\xb3\x31\x01\x43\x80\x30\xe7\x04\x48\x80\xd1\x7c\x2e\xe8\x4f\x89\xd2\x6a\x1f\x7b\x19\x86\x19\x3f\x96\x63\xc5\x87\xd5\x0c\xa9\xdd\xf6\x18\x6a\x51\x76\xaf\xef\x1a\xdb\x24\x81\xb7\x92\x54\xb7\x8d\x3b\x34\xc6\x97\x90\xeb\x28\xb9\x0b\x14\x61\x17\x0c\x3d\x73\x81\x83\x76\xcd\xf3\x71\xaf\x0a\x0f\xea\xf1\x4f\xdf\x70\x16\xed\x6e\x7f\x08\xc0\xc1\x4b\x52\x70\x5c\x86\xd4\xf0\x00\x3b\x5e\x45\xf9\x74\xc0\x64\x16\xcc\xb5\xca\x3e\x9d\x52\x9a\xa9\xd4\x15\xc2\x5a\x44\x6f\xa2\xd6\x9e\x82\xf4\x99\x4e\x57\xe9\x22\xc1\x7c\x1c\x34\x2d\xd7\x28\x1e\x41\x00\x52\xd9\xe4\xaa\x1b\x30\x9b\x7d\x47\x0d\x45\x8c\x66\x3e\x17\xff\x25\x00\xd0\xbb\x8e\x46\xa9\xc4\x36\x7e\x09\x1c\xaf\x87\xdd\xfc\x06\x2a\xae\x08\xa6\x5c\xb9\xe0\xea\xa7\x1c\x99\x45\x9c\x5e\x7c\xb1\x12\xa2\xee\x98\xa5\xe4\xcb\xee\x0d\xc5\x20\xf8\x7c\x30\x22\xda\x65\x49\xbe\x1e\xe7\x0a\x0a\x73\xad\x84\x99\xc9\x7d\xd0\x6a\xa1\x4c\x9f\xd8\x62\x8a\x92\xca\x6d\xb4\x87\x32\x2d\xb9\x59\x8a\xda\x1f\xce\x28\xf4\xb9\xfc\x1d\x3c\xc3\x9d\xcf\x2e\xd1\xdf\x3d\x86\x2d\x87\xf5\x5c\xc1\x01\x6f\xb9\xe7\x3e\x7c\xc8\x97\xb9\x70\xd5\xff\x35\xac\xfe\xb0\x5c\x1c\x89\x19\x28\x08\xae\xeb\xfb\x2c\xd1\x7c\xb1\xc9\x4f\xab\x05\x98\x98\xfe\xdc\x2f\xbd\x44\xcc\xef"}, -{{0xab,0xfd,0x69,0x7b,0xfb,0xc5,0xb6,0xff,0x2b,0xdf,0xf3,0xbc,0xe1,0xd7,0x77,0xe0,0x5f,0xbe,0x3e,0xc8,0xb9,0x5c,0xe6,0x93,0xd6,0x23,0x93,0x12,0x09,0x31,0x3d,0x4f,},{0xa7,0x09,0x32,0x1a,0x02,0x10,0xcb,0x80,0xab,0x58,0xbf,0x95,0x5e,0xcd,0xeb,0x8a,0xaf,0x9e,0xe4,0xc3,0x75,0xf9,0x59,0xc5,0x30,0x89,0xd4,0x37,0x48,0x8c,0x08,0x2d,},{0x8c,0x36,0xb5,0xa1,0x11,0xc5,0xa8,0x11,0x9f,0x2d,0x9d,0xb5,0x7e,0xbb,0x59,0x2d,0xae,0x86,0xad,0x4b,0xf6,0x78,0xc1,0x49,0x2e,0x26,0xf3,0xc1,0x0f,0xbe,0x03,0xf1,0x05,0xca,0xe0,0xdc,0x68,0xb5,0x52,0x59,0xb9,0xb5,0x98,0x92,0x89,0xdb,0x33,0xd9,0x5d,0x2e,0xe6,0xb7,0x56,0xc7,0x60,0xf9,0xd3,0xaa,0x0e,0x68,0xa1,0x89,0xde,0x02,},"\x89\x6b\x7a\xb8\x41\x3f\xfe\x43\x9a\x2f\x44\x87\xec\x49\xd6\x4e\x31\xc7\x4f\x50\xac\x83\xf5\x5d\xa6\x1a\x70\x03\xaa\x71\x6c\x2a\x9d\xf6\xb4\x38\xe6\x2f\x53\xd8\xf0\x19\x2f\x37\x36\x32\x47\x60\xd7\xe8\xc4\x4a\xc0\xba\xca\x3a\xe2\xa6\xfb\x93\xf1\x3d\x96\x88\x67\x99\xfd\x2c\x45\x51\xb0\xab\x36\xf1\x73\x08\x55\x55\x12\x65\xa5\xa3\xc3\xc2\x1d\x95\x16\xa2\x37\xf5\xdb\xc1\xc8\xe7\x29\x99\xb7\x82\xc5\xca\x41\xa4\xf6\xe9\x30\x8e\x64\xaf\xde\xe0\xbf\x47\x9e\x54\x6b\x89\xc5\x1b\xc5\xe4\xf7\x1e\x57\xfb\x24\xce\x43\x7a\x8b\x81\xb9\x1d\xc7\x98\xb5\xab\x36\xf2\x9a\xfd\x5b\x48\xe8\x1c\x17\x6a\xe5\xed\xf9\x53\x71\xba\x32\x46\xfb\x43\x94\x05\xbd\x10\xee\xd3\x67\x8e\x3e\xc6\x23\x07\xa3\xb3\xdc\x1b\xad\xba\x05\x1f\x16\x77\x4b\x85\x08\x81\x88\xc2\xa9\xe3\x20\xa1\x61\x8d\x5f\x26\xce\x94\xee\x2b\x93\x3c\x30\x5f\x6d\x95\x84\x95\x8e\xea\x31\x56\xc3\xd1\xe0\xef\x39\xa1\x86\x27\x5e\xe6\x2c\x40\xf3\xc1\xac\xd1\x5d\x8b\xe6\xe0\x74\x35\x1f\x53\x49\xce\x3d\xf6\x95\x17\x50\x5f\x45\xfa\x06\xa8\x15\xc6\x9c\xa1\x8f\x45\x0f\x42\xb5\xcf\x4e\xbd\x99\x26\x84\x45\xe0\xf6\x81\x04\xa7\xde\xeb\x0a\x11\x5b\x81\x7b\x99\xe1\xa7\x3e\x0f\xa9\xd8\x7d\xb7\x1f\x8e\xc9\x4f\x87\x08\xc9\xbc\x2e\x62\x2b\x96\x33\x65\xeb\xcf\xb9\x7c\xfe\x73\x32\x63\x00\x70\xe9\x65\x4e\xaa\x60\x36\x1a\x45\xd4\x02\xdc\x0a\xb2\x97\x66\x52\x42\x66\x7f\xbd\x99\x40\xf6\xcd\x33\x19\x52\x46\xa8\xc2\x86\x9a\xf7\x59\xa8\x62\xd4\xb6\x41\xdb\x14\x4d\x57\x32\x36\x6b\x20\x63\x6c\x40\x27\x78\x7f\x55\x80\x27\xd7\x6f\xcb\xf8\x43\x2e\xb9\x3e\x6d\x14\x56\x7d\xf8\xdb\xf2\x11\xda\xeb\x56\x55\xdb\x10\xac\xdd\xd0\x5e\xca\x06\xac\xce\xe9\xfd\xa8\xd3\xb7\x0c\xa1\xe6\xdc\x58\x7f\xa4\xb7\x8f\x63\xcd\x66\x3f\xf0\x24\x38\x70\x57\x0f\x4d\xcb\xaa\x3f\xb6\x26\xb4\xe1\x13\xbd\xe4\x7d\x5c\x9d\xb2\xb4\xba\x6e\xc6\xdb\xf9\x18\xac\x05\x69\x49\xef\x3c\xfc\xb1\x15\x56\x16\x15\x77\x1a\x03\x5a\x43\xd3\x3b\xa2\x65\x1d\xbe\xb4\x63\x48\x26\x1c\xe3\xc4\xc9\xf2\x46\xd2\x3f\x94\xdb\xc2\xd0\xc1\x9b\x92\x1e\x24\xc7\x7d\xa5\x99\x2f\x1b\x4b\xdf\x2e\xde\xa4\x99\xf5\x41\x11\x68\xac\x0c\x12\xe9\x6f\x3b\x15\xd2\xe1\x2a\xc8\xd7\xb3\xed\x8d\x1e\x07\xc4\x26\x7a\x25\xd3\xa3\xc3\x53\xa4\x20\x8b\x74\x06\x27\x8a\xab\x9e\x70\x0f\x7b\x20\x6f\x48\xe6\xea\x7c\xc9\x7e\x55\x4f\x15\xc9\xbe\x34\x9d\xd9\x15\x14\xdb\xe8\xd8\x89\xf2\xdc\xbb\xfa\x18\x2c\x9f\xaf\x58\x07\xa6\x9b\x2e\x97\xfa\x77\x1a\x6f\x23\x1a\x4c\x7b\x31\xd1\x17\xb8\xed\x0e\x63\x0c\xdf\x13\xe0\x82\xbb\x4f\x63\xc3\xf9\xac\xb3\x55\x32\x04\xcc\xd7\x6e\x18\x35\xc4\x6e\xec\x3d\x43\xc5\x61\xbb\xf1\x7c\x92\x21\x4a\x6d\xb1\x21\x2b\x60\x03\xcf\x2c\xc2\x6c\x7a\xe6\x75\xfc\xd0\x53\xb9\x47\xe7\x22\xf9\xe8\x57\x62\xce\x8a\x16\xe4\x65\x4e\xc6\x34\x2f\xc6\x46\xe5\xca\xb4\x72\x79\x7e\xab\xf6\x58\xba\x4a\xfd\x14\x2f\xc8\xfc\x4c\x8f\x98\xf2\x3c\x24\xdc\x99\x84\x7a\xe8\xce\xf0\x87\x9e\x1a\xb3\xbb\x80\x97\xe4\xc3\x52\x9a\xdd\x2d\x8e\x8e\x2c\x20\x69\x21\x0f\x50\xac\xe1\xae\x32\xa6\xc8\xe6\x38\x4a\x2b\xf7\xd7\x9c\x66\xc7\x46\x14\x9c\x84\xad\x75\xa3\xa1\x76\xe4\x5e\x13\x6d\x94\x69\x5a\xed\x4b\xfd\x08\xb4\x26\xea\x8c\x4b\x93\x79\xf3\x74\x25\x50\xe1\xcf\x5a\xc8\x4c\x18\x17\x4d\x68\x0e\x92\xaf\x2c\x18\x74\xac\x1c\x13\xd2\x82\x32\xde\x19\x37\x68\xe5\x61\x94\x7c\xbd\x6b\x79\xe9\xb9\x9d\xa6\x5c\xfb\x74\xff\xb3\x2f\x7d\x3d\x20\x25\xc6\x07\x63\xdc\x07\xf5\x55\x39\xb4\xd2\x53\xde\x1e\x6c\x25\x82\x3a\x62\x58\xc7\xa9\xce\xd1\x50\x1d\xce\x27\x86\x89\x8a\x3e\x05\xc9\xbf\xf8\xfc\x5b\x21\x25\xd0\xf4\x71\x08\x8a\x13\x4b\x48\x73\xc8\xd5\x5c\x04\x45\xf6\xca\x39\x6b\x3d\x7b\x4b\xc2\xbf\x5c\x4d\x22\x40\xda\x41\x82\x93\xaf\x6a\x3e\xd8\x53\xde\xdd\x3b\xf6\x68\xd9\x37\xb3\x5a\xa0\xc2\xac\xbf\x23\x76\x6f\x9f\x3e\x96\x82\x84\x75\xab\x08\x64\x96\x61\x7a\x6e\x81\xd6\x53\x58\x9b\x2f\xe5\x0b\x7b\xa8\xf0\xcf\x1e\x5a\x44\xd8\xd6\x2f\x08\x37\x7a\xbf\xc2\x62\x97"}, -{{0xdc,0xfa,0xd5,0x9f,0xc6,0xb6,0x97,0x10,0x9e,0x72,0x7f,0xf6,0x6a,0x5f,0xe9,0x3a,0x6a,0x22,0x6f,0x63,0x1a,0x64,0xe5,0x79,0x7a,0xd8,0xd8,0xc8,0xb6,0x35,0x87,0x34,},{0xe7,0x9f,0x4f,0x51,0x13,0x72,0xe3,0x55,0xe7,0xe9,0xe0,0xe8,0xb5,0x34,0x6f,0xdb,0xcd,0x2d,0xf1,0xfc,0x5c,0x3a,0x18,0x90,0xd2,0x7f,0xa1,0xfa,0x92,0x8d,0x27,0xa6,},{0x05,0x2f,0xf7,0x95,0x40,0x73,0x74,0x56,0xc6,0xa4,0x2c,0x41,0xc9,0x7d,0x6b,0xf5,0x17,0xb8,0xcf,0x28,0x9b,0xc7,0x8b,0x50,0x3d,0xee,0x6a,0x30,0xef,0x51,0x68,0xb3,0x8f,0x75,0xbe,0xac,0xa1,0xe1,0x4d,0x97,0x1f,0x87,0x73,0xe3,0x94,0x1b,0xd6,0xdf,0x5c,0xb9,0x77,0x8d,0xea,0x12,0x5a,0x4c,0x4f,0xe0,0x11,0x6b,0x70,0xee,0x84,0x0b,},"\x7d\x92\xdd\xd8\x13\x3c\x61\xc6\x10\xc1\x30\x8c\x23\xae\xaf\x99\x38\x84\xa4\xe6\x7f\x7b\x94\xbb\x88\x6d\xad\x50\x98\x69\xa9\x32\xec\x4a\x27\xd4\x10\xd2\xc2\x9c\xa7\xae\xae\x6f\x92\x80\xcf\x6c\x4b\x06\x7e\xc7\x51\xe5\xe8\xc3\x9f\xf4\x44\xd4\x22\xce\xab\xae\x14\x5d\x42\xf0\x47\x45\x3d\xd4\x02\xd1\x79\x74\x05\x03\x34\x09\xe7\x2c\xc1\x9f\x79\x3d\x5d\x26\x8f\xb3\xfd\x2c\x11\xea\x2c\xb0\xd7\x04\x36\xe1\x8f\x9e\x88\xa0\x15\x15\xdc\x86\x5f\x6a\x1e\xb2\x36\x90\x32\x8f\xd7\x5d\xe2\x63\x21\xa3\x8f\x12\x19\x7a\x97\x20\x1b\x1d\x84\x52\x94\x4f\xbc\x54\x1c\xb6\x8c\x77\xd4\x95\x15\xdb\x53\x26\xf2\xb1\xd0\x76\x3e\xda\x06\xd2\x50\xce\x2a\x5e\x0b\xbd\x7d\x16\x76\xd7\xd4\x1f\xb3\xab\xe8\x8b\xdb\xe3\x72\xf9\x6b\xf7\xbb\x52\x6d\x6b\x65\xa2\x51\x5e\x83\xa5\x77\x04\x5b\x54\x79\xb3\x8b\x85\x2f\xe4\xab\x01\x1c\xbf\x21\xc0\x85\xef\x5f\x0a\x7c\x1b\xed\x76\x57\x2b\x0f\x86\x02\x28\x06\x7a\x89\x9f\x89\x5a\xe7\xf6\x25\x6e\xb6\x51\x40\x87\xf9\xd6\xf5\xc3\x55\x96\xc1\xf4\x80\xc7\x31\x13\x54\x6c\xb9\xcc\x30\xf5\x6a\xb0\x74\xa9\xff\x28\xac\xab\x7e\x42\x65\x0a\x96\x1d\xa3\x25\xac\x5b\x65\x94\xb8\x1c\x93\x25\x0a\xe7\xd3\x92\x67\xa1\x9c\x97\x62\x54\x07\xed\xda\x04\x04\xcb\xe5\xa3\x6e\x95\x9f\xc8\x20\xb2\x7e\xf5\xca\xd7\x96\xc1\x1e\xaf\xf1\xc0\xe2\xf9\xd4\xb3\xc6\x49\x15\x02\x19\x5d\xe0\x36\x59\xb3\x64\xe4\xe8\x7b\x2b\x2d\x73\x3e\xc2\x5e\x6f\x9b\x63\xd5\xf6\x91\x79\xe0\xd2\x7b\xd4\xae\xcc\x8f\x12\xa5\x07\xa9\x1b\xaa\x48\xd9\x9b\x3a\x42\x6c\xec\xeb\xae\xf3\x7d\x73\x61\x10\x6a\x84\x90\x64\x43\x09\xf6\xeb\x4d\x25\x96\x44\x3b\x6b\x01\x18\xb9\x45\xac\xec\xc6\x44\x3e\xa6\x1f\xcd\x15\x5b\x54\x32\x5b\xc2\xc3\x1b\xe0\x25\x0f\x94\x82\xe1\x3f\xd8\xeb\x44\xe2\xae\xd7\x6b\xe8\x12\xaf\x54\x53\xcb\x7f\x86\x32\x45\x8f\xc8\xa0\x2a\x2f\x45\x48\x0d\x79\xb0\x6c\x7d\xda\x38\xb4\x69\x5d\x08\xb5\xa4\x30\x50\x4f\x1a\xe2\x27\x5b\x05\xc9\x1e\x79\x9d\x44\x70\xf3\x8a\xbe\x77\x73\x6d\xfa\x89\x5c\x19\x7e\xa4\xb6\x3c\x2d\xf1\x8e\xfe\xb1\x41\x84\x83\x7b\x8d\xdf\x48\x90\x95\x20\xd9\x10\x45\xb9\xd9\x65\x5c\x22\x5a\x83\x17\x39\x60\xb4\xd7\xcd\x0d\x8b\xae\x30\x23\x75\x57\xf8\x69\x70\x8b\xe1\x38\xad\x52\x46\xc8\x66\xc6\xc0\x59\xdc\x59\x7a\xbf\xd4\x94\x32\x37\x37\x68\x96\x73\x6b\x97\xb7\xe0\x28\x9e\xf9\xbb\xd2\x94\x77\x74\x5c\xb6\x0f\x46\x20\x2f\x1d\xe9\x84\xf5\x09\xb1\x80\x88\x33\xf5\x80\x18\xcd\xe8\xc2\x6b\xef\x4c\x00\x5b\xdc\xa3\x85\xb0\x57\x35\x11\x0c\xa0\x2e\x56\x2b\x50\xed\xdf\xf6\xfd\xe9\xfb\xb8\xd0\x30\xce\xdf\x70\x31\xbb\xeb\x32\xb1\x2b\x24\x2b\xe4\x9f\xde\x01\x60\xc1\xfb\xde\x99\xb0\x3c\x06\x2a\x1a\x47\x06\x23\x45\xc9\x2e\x0b\x60\x4d\x08\x0f\xac\xce\x92\x43\x48\x15\x29\xc7\x05\x97\xdf\xd6\x43\x82\xcb\x54\x06\x91\xb5\x9b\x71\xb0\x94\x33\x2b\xaf\x0b\xbb\x12\x5b\x63\xa4\x46\xbb\x97\x49\x1c\x04\x64\x32\x8c\xab\xd7\x62\x7c\x46\xf3\x92\xf3\xb1\x24\x82\x2f\x20\x13\xc6\xe1\x6d\x3c\xa8\x7c\xc5\xbe\xcf\x56\xb0\xfc\x6e\xb2\xbf\x99\x23\xb3\x01\x2b\xa2\xb6\x12\x50\xa6\x33\xa4\xd2\xee\x39\x12\x56\xc5\x20\x95\x73\x82\xaf\xf9\x70\xc5\xd2\x23\x85\xc3\x34\x4c\x6d\x4b\x45\x61\x57\x1c\x96\x32\x9b\xf7\x56\x15\x29\x75\x16\xb9\xf2\xce\xb9\xf9\x97\xa3\x95\x23\xaa\x0f\x58\xb4\x88\x77\x2d\x82\xfc\x0d\x78\xc5\xdd\x52\xec\xfa\x6b\xfa\xc6\x3a\x76\xe1\x48\x08\x8b\x36\xf2\x4a\x88\xe6\x83\x85\x49\x6d\xda\xdf\x30\x23\xf7\x2d\x87\xc2\xef\xa2\x6e\x87\x7d\x32\xf1\xda\x97\xcd\xb4\x2c\x8f\x15\x71\x89\x88\xe4\x28\xcd\x02\xf4\xd0\x95\x43\xbd\x0b\xd5\xb2\xf4\x09\x96\x3d\x0f\xa3\x73\x53\x1f\x78\xb5\x92\xbd\x13\x7e\xea\xea\x0b\x4e\x7f\x91\x82\x08\xe1\xd5\x90\x08\xa8\xaf\x50\x58\xf5\xd9\x23\xc4\xf3\x2d\xf1\x99\x90\xf1\x0d\xd3\xf0\xeb\x20\x62\x93\xb2\xb3\x44\x3f\x4a\x5d\x2d\xcc\x5f\x7d\x3b\xba\xf6\xaf\x43\xfe\x45\xf5\xdb\xbe\x53\xec\xf4\xbf\x1b\x4a\x13\xe2\xd4\x6e\xf8\x02\x98\xd4\xf0\x1c\x40\x2e\x21\x0f\xcb\x9f\xf2\x08\x4e\xc0\x3e\x42\x00\x8d"}, -{{0x69,0x6d,0xc4,0x81,0xf6,0x19,0xa9,0x49,0x85,0x63,0xc8,0x3d,0x0d,0x0e,0x55,0x56,0x5c,0x14,0xa0,0x78,0x45,0xfe,0x4a,0x66,0xab,0xa2,0x24,0x7b,0x11,0x3f,0xf8,0xef,},{0xc9,0xd7,0x37,0xab,0xc4,0xa9,0xe7,0x3c,0x14,0x9e,0xad,0xc1,0x95,0xa8,0x37,0x89,0x9f,0x2c,0xd5,0x01,0x93,0x73,0xc3,0x0e,0xca,0xf6,0x2e,0x5f,0x8e,0x14,0xb6,0x45,},{0xde,0xd5,0xd9,0x91,0x93,0x5c,0xd1,0xf9,0x39,0x0f,0x1e,0x85,0x92,0x9c,0xa1,0x6d,0xab,0xfc,0x83,0xe6,0x5e,0x43,0x27,0x2e,0xb1,0x75,0x16,0x71,0xaa,0x31,0x93,0x0c,0x72,0x85,0x55,0x34,0x14,0x30,0xce,0x7c,0x80,0x48,0x5d,0xe5,0x80,0x06,0x42,0x71,0x29,0xa4,0xd3,0x4f,0xd6,0x81,0xd5,0x2d,0x84,0x0a,0x16,0xba,0xfa,0x15,0x30,0x02,},"\x2d\x4b\x3a\xd0\xcc\x99\xf9\x83\xe4\x1f\x9b\x48\xc4\xa8\x18\xef\xf7\x5f\xcf\xb9\x3a\x12\x29\xec\x27\x40\xed\x19\xc1\x07\xd6\x21\xdf\x78\x05\x8d\xe7\xc2\xdd\x72\x51\xf5\xff\x45\x43\x40\x86\x5f\x6c\x86\xda\x65\x83\x1f\x66\x72\xdb\x23\x17\x26\xfd\xfe\x4b\x9e\xe3\x15\xd9\x3c\x72\x44\xa9\x20\xdf\x37\x05\x4c\x82\x44\x9d\x31\x0f\x89\x29\x32\xdd\xba\xd9\x4c\xc9\xbb\x39\xac\x89\x37\xcc\x76\xc9\x65\x21\xd3\xfd\xc0\x28\xba\x23\x41\x0b\x29\x02\x3e\x81\x38\xfd\x3f\x52\x43\x19\x88\x4e\xe5\xda\xd0\xd2\x34\xc8\xdf\x66\x1f\x88\x24\xbe\x47\x7e\x21\x69\x9f\x63\x69\xb1\x5f\xf3\xff\xef\xc1\x51\xaa\x55\x5b\x3c\x3d\x76\xad\xb4\x5f\x25\x67\x2d\x38\x0d\x47\x2b\x31\x48\xda\xbd\xef\x42\x45\xb6\x8e\x82\x85\x62\xf2\x5c\xc5\xb8\x1d\x9b\xbb\x24\x1b\xca\x9d\x19\x34\xea\x35\x3f\x95\xf7\xdb\xf3\x64\x64\x33\xe8\x1a\x35\x4e\x1e\x20\x56\xb8\x1c\x15\xaa\x1f\xa8\xed\x7a\x9d\x1a\xf9\x92\x38\xcd\x5a\x5a\xe9\xe8\x41\xc4\x8d\xc3\x48\xae\x1d\xe7\xc4\x1a\xca\x23\x32\x82\x36\xbc\x38\xb4\x7f\x47\xc7\x36\xb2\x57\xa3\x07\x8d\x57\xd5\x74\xb6\x47\xa7\xfc\x8c\x4d\x01\xbc\x50\x30\x21\x50\xd5\x03\x2b\xfa\xcb\x04\xbb\x0f\xd1\x55\xd9\x4d\x92\x06\x66\x77\x20\xe1\x80\xa6\x45\xaf\x46\x24\x59\xe3\x32\x6d\x46\x0d\xa3\xc4\x8e\x75\x72\x67\x8e\x19\x19\x26\x8d\x3e\x47\x40\xd6\x2a\x26\xf7\xc8\x55\x9c\x1c\x43\x9b\x4b\x0b\x0c\x59\x42\xa6\x20\xcf\xdb\x93\xcc\x68\xaa\x15\x52\x0f\xf2\x86\x42\x69\xd7\xa0\xc1\x55\x78\x0a\xdc\x6c\x18\x8e\x0b\x56\x5f\xb9\x59\x43\x19\xe6\xf5\x1d\x15\xca\xf6\xb2\x80\xe7\x15\x8f\x25\x79\x94\x07\xf3\xba\x0d\xd1\xce\xea\x64\xb9\x32\x6d\x2c\xfd\xef\x01\x7e\x1f\x17\x2f\x4d\xde\x0f\x7e\x46\x13\x50\x1a\xf0\x1e\xe0\xac\x30\x09\x5f\x48\xb5\x95\x90\x90\x2b\x1a\xec\xfe\x09\x34\x13\x91\x8d\x83\x5a\xdf\x96\x2e\xcf\x18\x58\x0d\x16\xf9\xfd\x4f\x6f\xa1\x09\x8a\xf1\xd8\xa2\xbc\x24\xdc\x86\xf7\x1d\x0a\x61\xff\x15\x00\x10\x86\x7d\x08\x69\x87\xb5\x1d\xd0\x30\xf5\x0a\xb6\xe3\x74\xb8\xe0\x11\x84\xb3\xe2\xb2\x14\xab\x1c\x7f\xdf\xae\xdb\xc5\x45\xe3\x8c\x3c\xd2\xf6\x98\x29\x79\x54\x1f\xe0\xff\x88\xbe\xd6\x75\x06\xda\x95\x72\x7a\xf1\xa2\x03\x8f\x32\x40\xae\x5b\xfd\x30\xee\x09\x21\x0e\x00\xfd\xcf\x2a\x06\x4d\x5d\xb4\x61\x49\x46\xbd\xa9\x72\xc6\x70\x08\x1a\x6e\xe6\xa1\x0b\x63\xf6\x73\xc8\x3c\x91\x5c\xa5\x57\x3e\x0e\xd6\x87\xb0\x06\x7c\x40\x07\x92\xa9\xbc\xc3\x34\x4e\x0e\x43\xf5\xdf\x63\xfe\xd5\xef\xa8\x5e\x9a\xaf\x85\xe4\xd7\xa2\xc5\x3a\x6c\x92\x82\x8e\x07\xfe\x63\xe2\xd2\x3f\x1b\xdf\x97\xd8\x4a\xdc\x36\xe9\xfc\x95\xfa\xad\xf0\x3e\x06\xd6\x5a\x19\xc5\xe2\x85\xef\xfd\x0e\xa0\xcf\xa8\x39\xd5\x5a\x0a\x0d\xbf\x6d\xa2\x87\x85\xc7\x7f\x5c\x04\xbf\xd5\x99\x74\xef\x37\x93\xcd\xc3\x98\xdf\x7a\x1b\xbc\x9c\xfc\xfc\x3a\x51\xff\xa9\xa2\x0d\x60\xc4\x7b\x24\x5d\xaf\xa3\xe4\x46\x23\xcd\x71\x1d\x77\x62\xc5\x0a\x67\xd6\x50\xc7\xe8\xc4\xfd\x3b\xeb\xc0\xc4\x98\xd2\x15\x2a\xb9\x82\x7c\x70\x0c\x7b\x28\x61\x56\x57\x49\xb5\x86\x4f\xec\x95\xb7\xf6\xb1\x99\x4e\x78\xd8\xf8\x5d\x06\x9c\xc1\x1f\x85\xbe\xd9\x71\x2f\x7a\x9f\x06\x0b\x0b\xf6\x75\x32\xe8\x8e\xb9\xdf\x3e\xb4\xa8\xd2\xfb\xba\xa8\x5e\xda\x92\x6d\x81\xc4\x9f\xb8\x6e\x73\x73\x1b\x7e\xd2\xa1\x90\x50\x78\x51\x3f\x7c\xa0\xfd\xcc\x3b\x1d\x57\x6e\x6a\x60\x12\x4c\x44\x61\x8d\xf1\x89\x0e\x16\x97\x94\x95\x6c\xb1\xec\x50\x1b\xa2\x04\x99\x70\xc8\xe7\x4c\xc1\x80\x06\x4c\x18\x44\x68\xbe\x4f\x08\x9a\x3a\xe2\x26\x3c\x85\x58\x63\xb6\x2c\x28\x31\x3d\xdf\x9c\xa8\x5b\xf6\x6b\x08\xa2\x64\x15\x5a\xd7\xc3\x28\x23\x8d\xfe\x61\x4a\x07\xed\xe9\x15\x5a\x09\xcc\xaf\xf9\x22\x92\x24\x93\x41\xba\xed\xcb\xe0\xe6\x46\x6e\x2c\x76\x04\x5e\x46\xda\xd2\xfc\x89\x9a\x17\x82\xe0\x09\x98\xe7\x9a\x83\xab\xfa\xe9\xb7\x06\xf7\x07\xf5\x8e\x73\x02\x03\xe1\xd2\xcc\xa0\x28\xc9\x22\xbe\xb6\xd1\x57\xfa\x7a\x98\x13\x2a\x92\x1a\x3d\xa2\x1f\x2f\x76\x9b\xb6\xc1\xf5\xf1\x9e\x9e\x85\xa1\x3b\x78\x1a\xf1\x41\x03\x9d\x51\x4e\xe1\x07"}, -{{0xf3,0xf8,0xd6,0x2f,0xee,0x3a,0xf3,0x75,0x66,0x96,0x30,0xcb,0xf0,0x63,0xbf,0xa9,0x30,0x18,0x9a,0xf1,0x36,0xcd,0x75,0x91,0xe2,0x4d,0x57,0x8d,0x73,0x66,0xbf,0x61,},{0x47,0x14,0xc6,0x04,0xaa,0x95,0xe1,0x82,0x8a,0x28,0x36,0x7b,0xa7,0x87,0x60,0xb5,0x89,0x64,0x31,0x68,0x3e,0xe9,0x96,0xcf,0xf9,0x68,0x71,0x77,0x32,0x91,0x95,0x3c,},{0x8d,0x6f,0x7c,0xee,0xb9,0x30,0x8b,0x4a,0x30,0x38,0x79,0xfc,0x6c,0xfa,0x5c,0xa8,0xe0,0x5d,0xfc,0x3d,0xef,0xc2,0xb2,0xcd,0x29,0x10,0xdd,0x4b,0x17,0xc9,0x4e,0xae,0xe8,0x45,0xab,0xe6,0x5f,0xd7,0x15,0xdf,0x05,0xb0,0x12,0x8e,0x43,0x16,0xe2,0x33,0x47,0x99,0xc6,0xe8,0xfa,0x74,0x7e,0xbc,0x8a,0x04,0x0c,0x74,0xf5,0xa1,0x48,0x0c,},"\xe1\xdd\x1f\xfd\x73\x7a\xc6\xdc\x24\xb3\xb9\xce\x3b\x79\xe8\x35\xbf\x69\x8e\x93\x13\x03\xd8\x09\xce\xa1\x78\x2d\xc3\xaf\x63\xa0\xd5\xe6\x73\x92\x82\x3d\x14\x39\xe7\xb6\xe3\x37\xb0\x1c\x8b\x21\x54\x34\xc2\x78\x2b\x3b\xe7\x44\x3c\xb5\xc8\x81\xe5\xfb\x6c\xf3\xbb\x24\x41\x28\xb4\xda\x6a\x6f\x42\xb2\xbb\x2c\xd7\x51\x29\xd5\x64\x18\x85\x43\x48\xc3\x39\xdc\xd9\x12\xb4\x55\x57\xa9\x15\xe9\xfd\x7f\x37\x91\x62\x36\x51\x0c\xb6\xc3\x31\xc1\x40\xb8\x7d\x22\x53\x11\x60\x0b\x8d\x13\x2a\xc4\x74\x73\x83\x9c\x72\x0f\x9f\xf0\xf9\xc1\xdc\xaa\x85\x81\x5a\x9d\x27\xb9\x75\x8c\xd9\x1d\xc5\xd3\xe5\x33\x26\xfc\xdf\xb2\x73\x0e\x52\xbe\x31\x03\x95\x7a\xc8\x91\x49\xa4\xc3\x00\x4c\xb6\x03\x8c\x0d\x80\xfa\x72\xac\x63\x0d\x33\x3b\xe5\xad\x4a\xdb\x58\x5a\xeb\x71\xae\xf1\xcd\xfd\x57\xb9\x15\xfa\xc4\xf1\xaf\x78\xe7\xa5\x97\xf8\xd1\xba\x06\x67\x2b\x19\xc0\xb6\x58\x08\xa8\xa0\x71\xff\x84\x09\x03\x43\x79\x58\x9f\x3d\x41\x30\x2d\x2d\x39\xb3\x31\x8e\x8c\x00\x90\xfa\x36\xcb\x95\x88\x57\xff\x5b\x21\x1c\x96\x66\xe2\x7b\xc8\x95\xab\x9d\x00\x6a\xba\xf5\x95\x0a\x03\xff\x17\xea\x98\x21\x78\xa4\x46\xdd\xa2\x46\x6f\x5a\x40\xb8\xf8\x95\x50\x9e\x4f\x4d\x4a\x6a\x27\x39\x99\x7f\xbd\x49\x68\xf8\x94\x36\xce\xe3\xd8\xed\xb8\xa6\xda\x9b\xd3\xd5\x5b\x06\x64\x90\xe8\x33\x9c\x78\x93\x5b\x77\x88\x3f\x95\xb9\x32\xfa\x5e\x6b\xb7\xdf\x30\x3b\xe3\x0f\xa5\x67\x24\x9f\xff\xb4\x73\xa1\xe4\x64\x32\x2d\x7c\x10\x3f\xe8\x22\x4c\x7e\xc5\x7b\xd3\x9b\xcd\x03\x0b\x96\x78\x7a\xeb\xcd\x20\xe9\xad\x65\x1c\xfa\x2b\xf0\x4b\xa7\x0a\x1c\xf6\x48\xe0\xa5\x44\x95\x67\x20\x2a\x93\x7a\x45\xbe\xcb\xb6\xfc\xde\xd3\x0c\xf9\xb5\xc7\x48\xf8\x82\xb5\xdc\x2a\x4d\x65\xbe\x69\xfd\x7d\x9c\x38\x1e\x83\xd0\xdc\x2a\x34\xb6\xde\xe9\x12\x20\xba\x90\x6e\x51\x2f\xcd\x63\x36\x8e\x2c\xe7\x33\xe4\x66\xb4\xb8\x2b\x84\xfb\x0c\x71\x7d\xc8\x94\x5c\xaf\x6d\x46\xac\x1c\x2f\x64\x18\xf7\x72\x9e\xf4\xc3\x5e\x40\x24\x22\xd6\x4b\x1c\x3e\xbd\x1b\x32\xa3\x0f\xc4\xc5\xee\xce\x7d\x44\x08\xff\x67\x9f\xf0\x1a\x1c\x7b\x03\xca\x51\x7b\xe5\x2e\x6a\xe7\x65\x0f\x7b\xad\x38\x90\x1e\x34\x8a\x55\x93\xbc\x99\x8f\x7c\xf2\xea\x97\x72\x9c\xb0\x04\xf5\x61\xb3\xb5\x8f\xe5\x98\x09\xa4\x1f\xd4\xb3\xb7\x66\x60\x90\x6a\xd9\xed\xa2\x3b\xf9\x25\x43\x7e\xf4\x52\xb1\x6f\x54\x0b\x3b\x80\xa3\x5a\x70\x93\xc2\x73\x4e\xef\xe6\xfa\x97\xd8\x81\xd7\x9e\xf5\xb7\x67\xd9\x88\x9f\x11\x84\x77\xb7\x3f\x58\xa4\xc0\xcb\x15\xe0\xac\x81\x01\x12\x05\x71\xca\x32\xce\x87\x1f\x30\x8a\xd9\x05\x7a\x80\xc8\x28\x15\x4f\xb1\xbc\x2b\x20\x1d\x0c\xd1\x00\x6e\x02\x2d\x44\x4d\xc9\x3f\x1b\xcf\x22\x4d\xb7\x4a\x5b\x37\x3e\x15\x3e\x85\x18\x54\x94\x8b\x6d\xa1\x47\xb7\x32\x87\xcf\x17\xd1\xfb\x72\xb4\x82\x76\x11\x10\x36\x09\xca\xb2\xa1\x77\x9e\x97\x93\xb9\xa7\x08\x20\xfc\x6f\x38\x28\xa6\x4c\x9e\xac\x35\xef\x7a\xa7\xb1\x76\x09\xd8\xef\xf8\xa9\xe5\x2e\x4e\xbc\xd8\x6b\x1e\x14\xfd\x14\x0b\xea\x47\xc6\xb8\xdd\xc4\x1e\x8c\xd2\x71\xeb\x92\x28\x7c\xbd\x06\x10\x51\x22\x42\xf7\x6a\x1e\xf3\xea\xc1\xe4\xbb\xbc\x1a\xda\xe5\x00\x34\xa7\xa2\x64\x7e\x08\xb2\xfd\x20\xaa\x93\xa9\x3c\xb2\xff\xde\xbf\x2e\x46\x1e\xcc\xef\xbb\xd1\xfe\x89\x4c\xe7\x0a\xdf\x79\x01\x73\xba\xe9\x6f\x5a\x55\xa1\x88\x7e\x9a\xe0\x9f\xce\xd1\xd4\x30\x6c\x29\x1c\x6b\x19\xec\xac\x47\x07\xe9\xef\x71\x3e\xa1\x8a\x75\x62\xc6\x67\x83\x26\x22\x89\x92\x07\x7a\x46\x69\x73\x49\x66\x10\x80\x00\xb4\x14\x4f\x45\xa0\xc3\xa2\x86\x3a\x4c\x6a\x3c\x07\x63\x2c\xb9\x3e\xb1\x97\xd2\x94\x88\x4d\x9c\xa3\xdd\x4b\x21\xf3\x9d\xb7\x07\xf6\x3a\x7f\x9a\x57\x0f\x7f\x0f\xeb\x99\xb2\xca\x7d\xa7\xdf\x92\xa1\x77\xab\xcf\xe8\x6e\xc6\x61\xd3\x0b\xcd\xcf\x15\x22\xbd\xb1\xfe\x11\x67\x32\x58\xdf\x7e\x46\xef\x4d\x32\x66\x65\x09\x31\x56\x55\x3f\x28\xb3\x56\x3f\xe7\x19\x2f\x72\xf5\xf9\xb3\x90\x3d\x79\xfe\xa0\x4e\x2c\x48\x8b\x46\x5b\x49\x78\xd6\x9f\x26\xe0\x5a\x59\xd5\xed\x4e\xf4\xca\xb2\x32\xac\xfd\x56\x4f\xc6"}, -{{0x86,0x5a,0x43,0x2e,0xcc,0xe7,0xe7,0x8c,0x42,0x70,0x9f,0xc1,0xe5,0x31,0xdf,0x5e,0x39,0x59,0x13,0x2b,0x2b,0x6f,0x31,0x8f,0xd1,0xc3,0x45,0x21,0xf9,0xa2,0x6e,0x3b,},{0xc7,0xa8,0xca,0xf8,0x93,0x0b,0x62,0x2a,0x50,0x13,0x37,0xf9,0x28,0x40,0xed,0x96,0x61,0x1a,0x32,0x20,0x80,0xfd,0xe5,0xe4,0x9f,0x0a,0x2f,0x6e,0x33,0xb8,0x82,0x83,},{0x32,0xbb,0x75,0x20,0xe2,0x63,0x9c,0x6c,0xca,0x19,0xa2,0xb9,0x83,0x6b,0x08,0xf8,0xb0,0x83,0xca,0x33,0x36,0x9d,0xdf,0x5f,0x9a,0x87,0x7d,0x4c,0x7a,0x9e,0xb0,0x5f,0x9c,0x3d,0xc3,0x4e,0xd4,0xcf,0xa4,0xb2,0x83,0xe5,0x19,0x22,0xb0,0x94,0x06,0x6c,0xe9,0xff,0xa4,0xd9,0xdf,0x62,0x19,0x10,0xca,0x37,0xb0,0xb3,0x7f,0xba,0xbb,0x0e,},"\xb2\x31\xb6\xd2\xec\xde\x49\xf5\x13\xb0\xdf\x25\xaa\xfc\x3e\x5d\xa4\x5b\x6a\x99\x58\xd6\x0f\x54\x64\xca\x59\x3c\x03\x00\x5e\xcf\x36\x1e\xf1\x69\x6b\xb6\xe5\x5d\x65\x38\xe3\x4b\x38\xf3\x24\xc2\x1c\xea\x5c\xc8\x1a\x00\x73\x27\x8b\xb9\x27\x27\xef\xf8\x1a\xf5\x61\x80\x2d\xce\xf3\x3b\xec\x10\xad\x65\x94\xe2\x2d\x9c\x44\x18\xaf\x39\x88\xa4\x3e\xd0\x87\xb9\x95\x4b\xf8\xd6\x28\x3e\x4b\xea\xe8\xc0\x96\xde\x66\x06\x75\x1c\xbe\xd6\x85\x84\x6c\x66\x30\xb9\x52\x8f\xf3\x64\xa7\xc4\x84\x64\x11\x34\x72\xc9\x86\x0b\x33\x71\x96\x3c\x91\x14\x95\xa9\xc6\x28\xa3\xe3\xe4\x7a\xb0\x99\x1f\x10\xdd\x1d\xd3\x31\x61\x52\x52\x62\xd6\x3b\xab\x64\x88\x19\xd5\x7d\x12\x69\xe1\x14\x82\x5c\x54\x34\xe6\xb2\x84\x5f\x42\x79\x5d\x4f\xb0\x83\xad\x79\x40\x1f\x2a\x07\x61\xc6\x34\xa5\x45\xae\xc7\xcd\xb1\x3b\x5b\xe4\x49\xf1\xd8\x29\x32\x63\x78\xed\x1f\x49\x3f\xe8\xc8\xe9\xb0\x68\xcc\x1d\xbc\xf1\x65\x55\x0b\x81\x32\xc3\x19\xda\xc4\x87\xb8\x7b\xb2\x2a\x54\xcd\xf6\x0a\xac\x71\x51\x61\x82\xa4\xe6\x9b\xa0\x83\xf6\xe8\x6d\x1a\x4f\x05\x08\x3a\x77\x61\x9e\xf2\x39\xf7\x02\x39\x6d\x7e\x46\x96\x8c\xc0\x4a\x3b\x34\xdf\x32\x65\xec\xf1\x61\x57\xab\xe1\x5c\x64\x2c\xd7\x42\x70\x96\xd8\xd4\x0d\xb0\x02\xd1\x96\xca\xb1\xbe\x30\x4b\xcf\x32\x2d\x9d\x1a\x24\x51\xb6\xc1\x1e\xea\xf3\xe8\xe3\xd9\x29\xf4\x80\xb6\xb7\x78\x04\xfe\x84\x49\x6c\xa7\x57\xe0\x43\x37\x91\x4c\xe9\x44\x75\xd7\x99\x0c\x74\x57\xc8\xe6\x06\xf8\xbc\x20\x7d\x2d\x48\x11\x9c\x80\xa6\xb4\xa9\xe0\x7b\x22\x92\x26\x57\x0d\xcd\x99\x49\x89\xfe\xcc\x69\x4c\x6c\x2f\xb5\x97\x5c\x9a\x6a\x9b\x74\xe8\x15\x9c\x27\xdd\x36\x77\xdf\xd5\xcb\x65\x1f\x1e\x32\xad\xfa\xfd\x81\x0b\x6e\x5d\x5e\xfb\xac\xe3\x1a\xe6\xd9\xb1\x21\x91\xe8\x93\x98\xda\x06\x3f\x13\x8b\x75\x84\xc5\x8e\x77\xe7\xf9\xfd\xd7\xfb\x9e\xf5\xd6\x8a\xe4\x9c\x6c\xca\xd2\x8d\x18\xbc\x60\x09\xd4\x18\x7e\xd1\x42\x02\x24\xa5\x65\x8a\xad\xf1\x35\xb5\xa9\x53\xf2\xdc\x3c\x8b\xfc\xaf\x66\x9e\xd5\xda\x38\xd0\x14\x4f\xd9\x66\x5e\x6f\x06\x77\xd3\xfc\x88\x04\xe2\x1c\xc2\x5f\xd5\xe0\x1a\x3f\x3f\xa8\x3e\x57\x1e\xb2\xf8\x82\xa7\x65\x9c\xe5\xd8\x64\xd8\xbb\x54\x07\x2b\x09\x86\xa8\x54\xf1\xa7\xf2\xd2\x72\x0d\xf8\x57\xe6\xd4\x21\x96\x30\x84\x1b\x1c\xcd\xcf\xc6\x72\x6b\x91\xbf\xc1\x7e\x18\xc3\xe3\x48\x0c\x23\xa2\xc0\x5e\x4b\xfe\xdd\xd4\xdb\x9e\xf4\x23\x88\xf2\x34\xfd\x3e\x4f\x3d\xad\x66\x60\x26\xe2\x78\x06\x12\x37\x41\x61\x31\x6a\xfc\x76\x65\xf9\x41\x1b\x6c\x5a\xa7\x89\x33\xb1\x80\x21\xc0\x12\xb0\x84\xf3\x24\x47\x60\xa4\xea\x1b\xcf\x31\xcc\x9f\x5c\x40\x44\xa9\xbc\xc7\x5a\x98\x67\x07\xf3\x8f\x45\xac\x1c\x7f\xa1\x39\xee\x95\xa6\xd8\xf1\x6c\x3c\x1e\x12\x76\x4c\x4b\x0b\x11\x94\xc0\xfc\x5f\x7e\xef\xf9\xa8\x48\xc4\x05\x0b\x0e\x65\x16\x84\x71\x9d\x43\x8a\xad\x56\x01\x91\x64\xfa\xe4\xf4\x88\x82\x20\x5e\xce\x0b\x99\x73\x67\x91\x08\x4a\x75\x3b\xa7\xd5\x6e\x88\xfc\xee\xa5\x33\x56\x6c\x3a\x2c\xa4\x8d\xd6\xef\xc4\x9b\x27\xdb\xf1\x4f\x26\x16\xce\xd6\x52\xe1\x38\x33\xab\x90\x28\xad\xa4\x54\x43\x1c\x89\xb3\xcb\x74\x41\xfd\xb8\xf2\x3e\x12\xb6\x0a\x1a\x10\x4a\x2a\x8c\xf4\xa6\x4e\x87\x8a\xa2\x6f\x54\xe8\x88\x1a\x4b\x15\x1a\x16\xa9\x6d\xe8\xb9\x80\x7e\x72\x93\x96\xeb\xe3\xe3\xd3\x94\xf8\x08\xbd\x74\xb7\x31\x2f\xe6\xb8\x4b\x13\x12\xaf\x8a\x1e\x41\x33\x59\x9d\x07\xbd\xf3\x3d\xb2\x1e\x01\x6b\x5c\x19\x6c\x1b\xa3\x11\x57\x08\xf5\x81\xbb\x82\xf4\xb5\x7a\x6c\xa1\xa5\x29\xe6\x4d\x19\x30\x42\xc1\xdc\x5f\xaa\x0a\x03\xab\xf5\x38\x49\xe1\xbd\xef\xba\xb6\x4b\x1c\xb6\x0f\xe1\x0a\x3f\xc1\x82\x3a\x23\x4c\x45\xf3\xb0\xdc\xe6\x6a\x46\x73\x9c\x01\xae\xad\x12\xde\x6f\x03\x13\xc7\xbe\x71\x40\x5f\x3f\xdc\x4a\x50\x7a\x9d\x84\xe8\x68\x6f\x6f\xc9\x26\x35\xdb\x0f\x78\x56\xc7\x37\x3a\x61\x8a\x72\x52\xc1\x29\xa7\x76\x0e\x20\x29\x54\x3d\x72\x62\x28\xc2\x1d\x00\xad\x4a\xc5\x2e\x5b\x1a\x6e\x31\x20\x09\x17\xf1\x5a\xf5\x15\x85\x9e\x08\xf2\xa7\x9a\xce\x67\x99\x1e\xd6\x90\x44"}, -{{0x2b,0xe1,0xf9,0x8c,0xe6,0x55,0x3c,0x91,0x5b,0x6a,0x09,0x33,0xec,0x0d,0xe3,0x47,0xb3,0x70,0xe2,0x9c,0xa2,0x94,0xe8,0x00,0x55,0x41,0x23,0x9f,0x63,0xb4,0x30,0xd0,},{0x7a,0x6f,0x44,0x69,0xc3,0x0a,0x63,0xf5,0x60,0xf9,0x87,0x34,0xfc,0x19,0x06,0xeb,0xd1,0x37,0x1e,0xd8,0x01,0x25,0xfa,0x3e,0x4c,0x86,0xb4,0x3f,0x26,0x2c,0xab,0xbc,},{0x8e,0x65,0x9a,0x3f,0x53,0x5a,0x58,0x9a,0x5f,0xd2,0xd2,0x17,0xcb,0xcb,0x8b,0x77,0x7e,0x5a,0xf2,0x0b,0x23,0x44,0x32,0xf7,0xda,0xc2,0x9f,0x81,0x0a,0x2b,0x47,0x37,0xc5,0xca,0xb1,0x0b,0x59,0xdf,0xd0,0x14,0x4f,0x30,0x90,0xf5,0xf9,0xe0,0xe6,0x67,0xf0,0xe2,0x1a,0x9f,0x57,0x3f,0xe1,0x3b,0x1c,0x28,0xec,0xcb,0xb5,0x31,0xa2,0x05,},"\x62\x68\x20\x1f\x93\x2a\x7c\xd3\xf8\x79\xae\x6a\xb8\x38\x55\xa2\xf5\x02\x91\xde\x78\x4d\x7d\x9e\x9a\xda\xa1\xb9\xaf\xed\x6f\x5a\xea\x20\x24\x0e\x59\xfe\x93\xe5\xa7\x08\x8c\x95\xec\x8e\x15\x74\x5f\xb8\xfd\xeb\x91\xdf\x01\x51\xc7\xb4\x60\x50\x67\x56\x1e\xa0\x8d\xbf\x00\xc4\xff\xe1\xfd\x0a\xcf\x10\x36\x56\xa7\xb5\x4f\xad\x0f\x25\xab\x16\xb4\xbd\xa3\x47\x17\x9e\xd1\xca\xdb\x7b\x98\xbe\x08\x95\xe0\x50\xdc\xbc\x37\x9d\x1f\xd5\x53\xe9\x97\x95\x92\x8b\x67\xa7\x52\xf8\xd2\xec\x1b\x9d\x66\xbf\x6a\xc9\x97\xe7\x44\xdc\x32\x7f\x24\x22\x30\xf9\x2e\x79\xae\x31\x27\x45\xa5\xab\x6d\xde\xc1\x99\x8f\xb6\x3d\xc4\xf6\xb0\x5f\x14\x72\x22\xd4\xb6\x5a\xce\x90\x17\xdc\x1b\xcd\x67\x5e\x49\x5f\x9e\xab\xb5\xf6\x02\x13\x3f\x6c\x72\xe0\x53\xe9\xf4\xae\x30\xd8\x72\xd7\x8b\xf7\x1f\xeb\xa3\x7a\xcc\x59\x50\x55\xc3\xbe\xa5\x3a\x05\xef\x0c\x7f\x21\x2d\xcf\x4e\x0a\xf8\x38\xea\x29\x28\xf4\xcd\xc9\xfd\xc8\x37\xda\x25\xf2\x69\x66\xb2\x45\x6a\xbe\xa6\x6a\x5d\xfb\x8f\xaa\x8f\xa0\x91\xf7\x33\x1d\x54\x36\xe9\x8a\x8d\x63\x23\xcc\x9e\x9a\x91\xd5\xa0\x2a\x49\x51\x17\x14\x84\x9b\x47\x45\x4b\xaf\x99\xc5\xf8\x50\xa0\x8d\x3d\x98\x41\x0e\x93\x9a\x9e\x89\xb1\x50\x53\x82\x5f\x3e\x9a\xee\x71\x44\x74\x16\x14\x07\x82\xe1\xbf\x3b\x0d\x8b\x4f\xf6\x2e\x77\xa4\xa0\x3f\x71\x0a\x8a\xb7\x6c\xf6\x35\x92\xc0\x5c\x44\x0c\x8f\x06\x47\x70\x09\x91\x63\xc1\x22\x70\xf3\xd5\xec\x9a\x6b\xc9\x71\x5b\xff\xfe\xc7\x69\x61\x1d\x21\xfa\x00\x3c\x3c\xc8\x35\x6c\x97\x5d\x37\xb6\x2b\x88\xaa\xbb\x85\x97\xda\xca\x19\x6c\x96\x48\xa3\x1d\x15\xbb\x0b\x86\xcf\x07\x0e\xe0\x1e\x51\x1e\xf3\x73\xb4\xa4\x4c\x6a\x00\x16\x0a\x79\x7f\x2e\x82\x0b\x71\x6f\x5c\xa6\x44\x64\xe4\x18\x9a\x00\xfe\xe9\x78\xd3\x5b\xf2\x04\xf7\x1d\xb1\xf5\x01\xf9\xb6\xe5\xdf\xc8\x21\xa8\xaf\x5d\xbf\xef\xd3\x53\xad\x36\x81\xf9\xbc\x3c\x22\xc6\x7c\xb2\x11\xb4\x30\xb6\xa5\x5f\x3e\x73\xda\x7c\x3a\x07\xce\xb7\xd2\xfe\x25\x4b\x10\xc2\x70\x3a\xb2\xe2\x29\x4d\xd0\xd3\x15\x2d\xc7\xb2\x1a\xab\x87\xb1\x50\xf7\x37\xa9\x47\x46\x3f\xb2\x04\x17\x5d\xe8\x54\x32\x36\xfb\xb0\xda\x5c\x7d\x48\xc5\x7f\x61\x74\x4d\xe6\xf9\x84\xaa\x8e\x61\xb9\x70\xc6\x2d\x0e\xeb\x84\x9d\xa7\xe8\x9a\x61\x22\x2d\x43\x20\x79\xcb\xcf\x5f\x8a\x2b\xa9\x30\x30\x16\x83\xc0\x78\x5c\x26\xfd\xf8\x5d\xa3\x02\x08\x74\x60\x45\x99\xac\x6c\x84\x7e\xc2\x60\x86\x58\xb5\x78\x8c\x7b\x8d\x3a\x37\x44\xfd\x54\x42\xe2\x4c\x8e\xec\xcd\x42\x07\x56\xbd\xd8\xb8\xa7\x7c\xfd\x80\x58\x96\x05\xdc\xed\x9a\xfd\xa2\xbd\xb6\x30\xa0\xcb\x61\x2f\x73\x9c\xe6\x17\xd5\x4e\xde\x6c\xcf\x36\xaa\x31\xe7\xe3\x73\xd8\xa0\xfb\x1b\x7c\x99\x06\xf7\x6b\x5f\x9d\xe8\xc2\x68\x91\xde\x00\x6e\xb7\x97\xea\xd4\xa8\x6f\x70\x16\xf3\x4b\xcd\xe9\x2f\x94\xac\x3e\x92\x0b\xa5\x8d\x6d\xff\x77\x20\x78\xd8\x02\xa9\x4f\x56\xcb\x26\xbf\x79\x4f\xd9\x0c\xa0\xad\x4f\x2e\x7a\xcd\xc5\x92\x9b\xc7\x36\x49\x97\xde\xd9\x8c\xa6\x9c\x57\x39\x91\xbb\x9a\xb8\x5f\x23\x5b\x63\xe7\x6f\x77\xe0\xab\x45\xe7\x89\x12\x38\x98\x69\xaf\x21\xe7\x4e\x66\xf7\xc4\x56\xb8\x27\xe6\x70\xbe\xb0\xf0\x72\x66\x88\xbb\x1f\x90\x36\xd3\x8d\xa0\x7d\x69\xea\x36\x66\xf7\x6b\xd6\x05\xd8\x2e\x2d\xd6\x38\x7e\xce\x6e\x82\x4a\x56\x97\x00\xf0\x1b\x19\x5d\x1a\x9b\xdc\xb0\xf9\x6a\xb5\xc5\x4e\x06\xc2\x11\x9b\x40\x6b\xc4\x88\x84\x80\x66\x04\x18\xbb\x42\x88\xea\x2f\xda\x96\x63\x1b\x0e\x1f\x60\xac\x86\x1d\x6c\xcc\x4c\x84\x4b\x64\x7a\x7d\x74\x03\xbc\x2d\x15\xba\xfe\x4a\xf6\x77\xe8\x56\xfe\x0d\x2b\x5f\x66\x3b\xe4\xe4\x80\xb3\x8f\x6b\x76\x6a\xdc\xd3\xd0\x52\x98\xef\x13\x98\xd0\x4d\x15\x23\xa6\x8b\x91\xdd\x31\xcf\x5d\xc4\xb7\x3d\xec\xbf\xd7\x21\x3f\x98\x1b\x20\x7e\x1f\x6e\xf2\x25\xd7\x94\x8a\x1a\xa1\x7d\x8d\x57\xa1\x12\xf1\xd4\x46\x8d\x2d\x28\xf7\xec\x2e\x54\xb7\x4a\x69\x2c\x59\x58\x02\x2e\x82\x03\x1a\x41\xb3\x15\x09\x0e\xd4\xd5\xbd\x7b\xd0\xb4\x51\x47\x63\x38\xf7\x39\xa7\xd7\x03\x1a\xf2\xd3\x6c\xaa\x09\xff\xdb\xb7\xc3\x96\x50\x7c\x75"}, -{{0x10,0xbb,0xe6,0xe7,0x61,0xa7,0x5c,0x93,0x5b,0x51,0x7f,0x09,0x36,0xfe,0xcb,0x9e,0xc6,0xfc,0x21,0x5e,0x58,0x13,0x08,0x00,0xea,0x18,0xd1,0xff,0x44,0x2a,0x4f,0x13,},{0x86,0x43,0xdd,0xf8,0xaa,0x8d,0x9c,0x8a,0x78,0xb6,0xeb,0x69,0x9f,0xd2,0x0a,0x57,0xf6,0xf1,0x86,0x36,0xb0,0x6c,0xe6,0x9d,0xac,0xdc,0xa1,0x26,0x7a,0xcb,0x39,0x54,},{0xf0,0xf3,0x57,0x41,0x03,0x73,0x31,0x3b,0x7c,0x62,0x52,0xd6,0xd9,0x66,0x00,0x36,0x0c,0x23,0x75,0x2d,0x43,0x1c,0xa8,0x07,0x5b,0xcf,0xb7,0x72,0xd4,0x9c,0xd6,0x09,0xb6,0x5c,0x9c,0xd8,0x38,0xd6,0x34,0xd8,0xd9,0xb9,0x5d,0x1e,0xe3,0x0e,0xde,0xcc,0x13,0xe3,0xca,0x99,0x7b,0x24,0x37,0x30,0x3f,0x8a,0x33,0xa1,0xff,0xc8,0x33,0x06,},"\xe8\x10\x8c\x6d\xe4\x13\x37\x33\xdc\x19\x9a\x73\x39\x2e\x22\x6f\x71\x2c\x36\xa2\x4f\xa9\x1d\x6f\xb0\x9f\x92\xdf\x21\x8d\xeb\x2d\x28\x30\xa6\x68\xfd\x69\x4b\x48\x09\xd0\x25\x35\x07\x23\x12\x47\xc7\xf2\x58\xb4\xd6\x5c\x56\xbb\x69\x34\x5e\xf6\xaa\x97\xe7\xc5\x9e\x81\x53\x77\x5a\x5a\x3c\xf1\x09\xc4\xbc\xa9\x81\x55\x69\xda\x69\x32\xe8\x21\x83\x42\x5b\x42\xd7\x48\x3c\x9d\xbf\xcb\xd8\xeb\x38\xc8\x47\x29\x57\x1e\x8e\xc9\x39\x82\xc3\x17\x71\x67\x59\x59\x8c\x4f\x6a\x1b\x7f\x8d\xa7\x30\x6a\x78\x15\x72\x1c\xaf\x02\xe7\x02\x46\x71\x23\x14\xf7\x66\xbe\x9c\xb1\x77\xcd\x2f\xa3\xbd\xa2\x2c\xd6\x76\xc5\xd2\xe8\x6e\x8d\x79\x8f\xd3\x4f\x54\x3c\x9b\xe3\x12\x96\x51\xf2\x73\xf4\x84\xf0\xb9\x46\x7b\x14\x09\x55\xcd\x29\x81\xff\x26\x03\xc0\xbd\xbb\x43\x6a\xc0\x95\x5a\x11\x6c\x5e\x5f\xc3\x04\x25\xe1\xfe\x78\xf6\x41\x0f\x6e\xf7\x57\xf6\x04\x66\x88\x54\xba\xe7\x9b\xfe\x22\xe1\xa8\x5c\xe5\xee\x5d\x64\x34\xb4\x61\x01\x20\xea\x7e\x5d\x3d\x13\x7c\xe2\x07\x51\x4f\x85\x34\xad\x9b\xf3\x92\xb7\xdc\x53\x55\x51\x4b\x59\xf8\x35\x46\x6c\x8e\xb5\x6f\x44\xed\xdc\x5b\xad\x20\xcf\x0b\x48\x0b\x2e\x82\x2a\x6f\x46\xfd\x95\xf3\x0f\x18\x3c\x7b\xb3\x14\x3e\x4e\x61\x00\xe2\xdb\xc9\xf2\xbf\x0d\x43\x07\x3e\x0f\xe6\x5f\x01\xbc\xce\x6a\x1a\xe4\x01\xc1\x25\x41\xbe\x3a\xe6\x8c\xde\xac\x2a\x4a\xc7\x1f\x16\x63\xb5\xfd\xfc\x2e\x50\xf0\xe0\x77\xfb\x3a\x0a\x8b\x8e\xee\xad\x62\x7c\x1c\x3e\x79\xdd\x73\x61\x04\x6f\x7e\x57\xc1\x74\x36\xc3\x2d\xc4\x43\x2f\x05\x00\x28\xcc\x7a\xa4\x40\x8c\x2d\x29\xd1\xd7\x99\x8f\xdc\xdd\xa3\x2b\xb3\x2f\x70\x4d\xc2\x63\xdb\x9b\x8e\x06\xc5\x76\x30\x87\x0f\x8b\xb6\xec\x66\x1f\xde\x1b\x7d\xa9\x4d\x53\xb0\x47\x70\x1a\x45\x88\x47\x8c\x1c\x66\x23\x46\x74\x1a\xea\xc4\xc2\x53\x38\x55\x6a\x3d\x84\x8d\xe5\xb2\xa2\x3e\xce\xa6\x1b\x77\x6b\xd0\xe8\x03\x7e\xfb\x85\x01\xef\xf2\x39\xc7\xfa\xcc\xa6\xc8\x36\x7e\xd7\xc8\xad\xce\x91\x9f\xef\x1a\x15\x5a\xe0\xd5\x47\x8a\x98\x00\x2c\x95\xa1\x6f\xbf\x4c\x0e\xd0\x16\xea\x5d\x38\x66\xfe\x1d\xe4\x54\x83\x2a\x4e\x95\x65\x97\x6b\x60\xb3\xdd\x2e\xaf\x7f\xee\x61\x2f\x2b\xc0\x40\xd9\x39\x75\x43\x5e\xeb\xd1\x2f\x06\xeb\x09\xec\xea\x2c\x66\x76\x83\x08\xf5\x8c\x77\xac\x51\xed\x7b\xd2\x16\x36\xfc\x9c\xc3\xfd\x14\x87\x0b\xd0\x6b\xdf\x12\x8a\x81\xb1\x47\x92\xe6\x08\xc4\x7e\xa2\xd5\x35\xca\x7a\xa2\x1e\xb8\xa8\xa5\x6d\x76\x99\x16\x63\xa8\x19\x0a\x95\x05\x7d\x33\x67\x1e\x73\xc7\xcb\xce\x5a\x98\xd3\x1e\xf0\xd7\x3b\xd0\xb1\x63\x78\x7b\x7f\xdc\xd2\xdd\xfc\x72\x96\x0f\x2b\xe3\x20\x84\x6d\x4b\x29\x08\x0d\x7a\xeb\x5b\x7e\xa6\x45\xa2\xad\x5a\x59\xc0\x12\xbf\x7b\x95\x15\xd8\x59\xe1\xc1\x47\x2e\xf8\xa4\xd3\xc9\x5e\x71\x1a\xf9\x7a\xe4\x61\x8e\xfb\xab\x3d\xff\xe8\x8c\x9f\x6a\xf4\xa0\x9b\x0e\x73\x38\x7e\x25\x1b\x77\xd7\xbf\xf5\x21\x4f\x79\x18\x62\xdb\x69\x88\x41\x1e\x2a\xe2\xc7\x5b\xf2\x8d\x28\x60\x2a\x63\x7c\x26\xf4\x9c\x18\xd3\x09\xd2\xfc\x58\xa1\x26\x66\x7a\xd3\xc2\xec\x16\x0c\x99\xba\x40\xfb\xda\xc1\x7e\x7e\x4c\x21\xa5\xd5\x07\x85\x97\x62\xeb\xa0\x9c\x41\x60\xdf\x66\xf5\xfe\xef\xe6\x71\x5a\x28\xc5\x29\x6c\xf4\x3e\x5e\x77\x1f\x31\xfc\xe5\x13\x3b\xe9\x7c\xab\x57\x30\x1b\x4c\x9d\xf9\xcd\x9a\x4a\xcf\x1c\x33\xfa\xc9\x46\xfa\x15\x96\xfa\x65\xc8\xf3\x65\x8b\xe4\x7a\x47\x3a\x62\xc5\x21\x81\xec\xa1\x83\xe4\x24\x6c\xd6\x24\xd8\x78\x3d\xcc\xe5\xfd\xcc\x1f\xea\x17\x3f\x80\x71\xf7\x07\x4f\x55\x89\x7d\xe9\xbf\xe8\x4a\x6c\x4f\xdf\x80\x2d\x50\x26\xb8\x14\x5e\x6c\x8c\x89\x50\xaf\xc5\xb4\x0f\xd0\x35\x6f\xc5\x5e\xe1\x7e\x1f\x85\x3a\x4c\x2f\xcc\x34\xa1\x36\x9b\x87\xd2\x8d\xc2\xfd\x20\x10\xf1\x99\x03\xaf\xf8\xe4\x6d\xe0\x49\x38\xf4\x94\x82\x45\xd5\xb4\x25\xd0\x74\xac\xdf\x2b\xd8\x0b\xfc\x37\x35\xcc\x34\xa2\x25\x90\xf1\x94\xaf\x93\x13\xee\xf4\xab\x5f\xde\x61\xf1\xf9\xb5\x85\x78\x63\x8f\xcb\x4f\x28\x50\xb2\xfc\xe6\xe0\x3d\xb4\xd0\xa8\x34\x84\x81\x63\xc4\xb2\x7e\x12\x9f\x5c\xc7\x4f\x67\xf0\x08\xa2\x71\x2d\x1d"}, -{{0x18,0x6d,0xcc,0x7e,0xfc,0x5e,0xd7,0xe6,0x1a,0xe5,0x3d,0xc4,0x20,0x93,0xba,0xe8,0xf1,0x5d,0xd9,0x9f,0x0f,0x03,0x33,0x26,0xc5,0x76,0xff,0x75,0x69,0x50,0xd0,0x6d,},{0xc8,0xd1,0x41,0xac,0xb6,0x42,0xaa,0x9b,0xfb,0xd5,0x43,0x27,0x7c,0x2d,0xca,0x8a,0xa9,0x88,0x8e,0xef,0xf0,0x45,0x43,0xb3,0x78,0x9b,0x21,0xf2,0x6a,0xeb,0x0f,0x71,},{0x89,0x45,0x06,0x97,0x87,0xc1,0xc6,0x76,0xa8,0x4a,0x70,0x3c,0xae,0x1e,0x0b,0xac,0xae,0xff,0xd3,0x3e,0x91,0xbe,0xc3,0x60,0x3e,0x1f,0x13,0xfb,0x17,0x0e,0x31,0xe6,0xd7,0x04,0x9e,0xda,0x2b,0xf6,0x27,0x18,0x0f,0x45,0x6c,0x3f,0x7a,0xab,0xfc,0xd3,0x6c,0x49,0xa8,0xc0,0x4f,0x8a,0xe6,0x92,0x9e,0xc5,0xad,0xa0,0x7b,0x65,0x72,0x08,},"\x97\x43\x64\xd6\xc8\x38\x84\x2c\xcc\x4e\x74\x9e\x6a\xfd\x53\x71\x70\xdc\xd8\xcc\x50\xd6\x66\x54\xd1\x05\x48\x23\x39\xca\xbd\xf7\x4e\x32\x93\x5e\xe2\x19\x27\x2e\xa1\x68\x4f\xb9\x3c\x1f\xab\x42\xb5\x63\x18\x39\x24\x35\x91\xbd\x07\xd3\xbe\x94\x9b\x0d\xd1\x5e\x31\x96\xdf\x19\x6b\xa7\x52\xad\x11\x21\xac\x71\x12\xd5\x66\x94\x4e\x15\x3a\x4e\x06\x19\xb3\xa2\x32\x24\x1f\x02\x0b\xe0\x71\x9f\x6b\xec\x91\x8b\x26\x82\x8e\xb1\x67\x0e\xcf\xc7\x3c\x66\x84\x4e\xa3\xe4\x04\xc6\xa2\xfc\x01\xbe\xb4\x03\xc9\xd6\xca\x55\x1a\xd8\xa6\xe7\x1f\x46\x64\x7f\xa6\x05\x3f\x03\x14\xf8\x12\x4d\x8d\x2b\xc1\x2c\xc8\xfa\x8d\xb9\x5f\x2b\x73\x53\x75\x20\x1b\x81\x6a\x9c\xf4\x0f\x83\xee\x4b\x86\x71\x61\x80\x32\xde\x22\x9c\xe7\x62\x71\xd0\x3d\x26\x72\xa1\xae\x4a\x28\x8c\x85\xdc\xd2\x7f\xb8\x45\x2a\x81\x32\xe9\xff\x29\xe1\xe8\x9b\xf1\x1b\x1c\x83\x51\x92\xc0\x4b\x13\xbe\x14\xf3\xcd\xe5\xd3\x7c\xe9\x6f\x1d\xc2\xa9\xcc\xda\x0c\x4d\x73\x7b\xca\x1f\xa2\x20\xd2\x1b\xf3\x60\xb9\x05\x15\xbb\xd2\x26\xbb\x2a\x6c\x8d\x5f\x2a\xb0\x18\xd4\x08\x4e\x24\xee\x33\x3c\xe4\xe3\x9b\xcb\x6b\x46\xe7\xae\xb4\xdb\x9b\x6c\x65\xb2\x44\xd9\x82\x82\x3a\x77\x0f\x9c\x62\xa0\xbd\xe2\xcb\xb7\xec\x36\x84\x0d\x45\x51\x87\xfa\xff\x4e\x48\x8a\x5c\x60\x8e\xbd\xb7\xdb\x84\xd8\x7d\xad\x38\x67\xe3\xb0\xd0\x4b\x64\x71\x5e\x16\x56\x0a\x62\xf1\xee\x03\xdf\x61\x83\xfd\x5e\x37\x55\x5d\xa1\x97\x2f\xca\x06\x2d\x12\xbb\x84\x20\xe0\x82\xda\xcb\x8d\xeb\xb9\xc1\x43\x85\x41\xd0\xda\x24\x64\xef\x7e\xc5\x22\x63\xfb\x9b\x9a\x4c\x46\x9c\x83\x32\x3e\x48\x19\xdf\xdf\x4f\xa0\xa7\x70\xc3\xa7\x09\x25\x4e\x05\x31\x48\x30\xe8\x7f\xbb\x67\x36\xc7\x2d\x9d\xab\xe0\x1a\x31\x0e\x91\xeb\xbf\xae\x76\x7a\x1f\xcb\x62\xf6\x4f\xa3\xba\x8d\x53\x40\x0d\x64\x69\xad\x1c\xcb\x81\x1f\xb9\xe1\x15\xf1\x41\x27\xb1\x3e\x83\x64\xaa\x2f\xe8\x0b\xbc\x88\x6a\x10\xdf\x1b\x9c\xc4\xae\x46\x01\xf5\x46\x1a\xf0\x91\xf5\x26\xd2\x72\xda\x9b\x20\x38\x57\xa4\x44\x7e\xab\xde\xf4\x39\x83\x04\x96\xa5\x75\x9c\x21\xde\x65\xba\x3a\x3c\x8b\x8e\x93\x9c\x46\x13\x32\xa9\x24\x85\x2c\x20\x5c\x77\x11\xf3\xa6\x8a\x23\x67\xa9\x45\xde\xf4\xfb\xe5\xf8\x1c\x60\xcb\xb7\xe3\x94\xa2\xa4\x9b\xe9\xec\x2a\xae\xb1\xf3\x30\x57\x59\x79\x44\x6a\xd9\xd0\xd5\x4a\xbd\x43\x6f\x28\x60\xf0\x42\x34\x26\xf4\xbb\xc2\x6b\x3b\x9f\x65\x0d\x69\xb1\x00\x72\xd7\x47\xa3\x9e\x47\x8f\x45\x5e\xaa\x12\xc7\xc6\xe1\x2b\xfc\x45\x36\xa3\x59\x43\x44\xbd\x02\xb6\x20\xe3\xe2\xb4\xe0\xd5\x34\x08\x9d\xd7\xb0\x4f\xa6\x34\x80\x45\x67\x58\x6c\x62\xbe\x03\x91\xc7\xbd\xb0\xa9\xfb\xc1\xef\x3b\x33\x21\x1e\xdb\xf8\xef\x58\xc2\xb7\xa4\x9d\x06\x66\x79\x59\xd7\xe5\xd4\x46\x71\xee\x73\x57\xa1\x0b\xa0\xcb\x1a\x44\x5a\xe5\xd7\x09\xce\x25\x5e\x92\xde\x71\x59\x75\xaf\x94\xb8\x9d\x4a\x29\xc7\x1f\x9d\x88\xc8\x5b\x6c\xd1\x1d\x8b\x33\x5b\xf8\xf2\xc6\x58\xe6\xdd\x7c\x3f\x6c\x80\xad\x4d\x0e\x5a\x6c\x87\xdb\xa7\xb5\xb8\xa8\xa4\x7e\x72\xf4\xd1\xd3\xc7\x43\x63\x1d\xf9\xad\xfc\xfa\x45\xce\xe0\x49\x8d\x5a\x44\xa9\xf7\x5c\x83\xb7\x5b\x2a\x3c\x23\x0f\xf0\x76\x7d\x38\x88\xf9\x41\xee\x1b\x66\x24\xdd\x0e\x12\xd0\x6e\xd1\xab\x8b\xb1\x35\xff\xd3\x79\xe9\xde\x37\x88\xbe\x54\x1a\xad\xb2\xd6\xa7\xcc\x60\x13\x16\xf2\x1e\xb9\xaa\xa9\x22\xf5\x6a\x8e\x35\x26\xc9\xbd\x11\x77\xfe\xfc\x2f\xbe\x3e\x43\x0b\x62\x8e\xeb\xd6\x66\x1e\x3b\xa2\xd6\x31\xc6\xa8\x42\x2c\x24\x1e\xcd\x96\x99\x72\x41\x2f\x74\xda\x6b\x12\x43\xbf\x0f\xbe\xe8\xa8\x4d\x52\xe4\x0a\xee\x3f\x1e\x4f\xc8\x31\x40\x2c\x62\xf3\x57\x6b\x22\xe8\xe3\xc3\xdc\x4e\x16\x0b\xc3\xb6\xb9\xd2\xce\x00\x58\x53\x81\x2e\xaf\xc0\xa4\xe2\x5b\xa7\x12\x27\x9b\x00\xba\x3f\x91\x30\xff\x36\xe3\xef\x19\x71\xdd\xe7\x50\x8b\x27\x92\xfe\x64\xd4\x75\x68\x8f\xc6\xf3\x31\x3a\xad\xb7\x85\x30\x2e\x6b\x7f\x9a\x84\xf2\xdb\xc2\xf3\xcf\x06\x0e\xe0\x8b\x46\x37\x36\xf8\x36\xdb\xb2\x62\xd3\x29\x68\x4c\x20\x84\x92\xd1\x7d\x81\x12\x21\xbe\x02\xb6\x5e\xe2\x8e\x11\xb5\x46\x92"}, -{{0x07,0x05,0xb3,0x36,0xc8,0x9c,0xa3,0x5f,0xfd,0xde,0x0a,0xf0,0xf9,0x06,0xea,0xcf,0x62,0x3c,0x56,0xc3,0xf7,0x67,0x38,0x16,0x8e,0x76,0xfc,0xd5,0x88,0x2d,0xf7,0x9e,},{0xea,0xaa,0xf2,0xa1,0x5f,0x44,0xb6,0x34,0xce,0xf1,0x5a,0x63,0x8b,0x80,0x20,0x7f,0x61,0x09,0x9a,0x07,0x96,0xf5,0xd4,0x3f,0x3e,0x9d,0x04,0x8e,0x6a,0xe7,0x96,0xc1,},{0xd4,0xa9,0xba,0xe8,0xec,0xc4,0x72,0xc3,0x76,0xba,0xb8,0x05,0xc2,0xce,0x0c,0x1c,0x2e,0xd5,0xfc,0x77,0x37,0x15,0x46,0x8c,0xb1,0xa4,0x93,0x45,0x64,0xda,0xce,0xcf,0x43,0x8b,0x1d,0xd2,0xac,0x1b,0x5c,0x5e,0x33,0x6a,0x1e,0x20,0x70,0x1d,0x5d,0xcf,0x3c,0x8e,0xe3,0xad,0x22,0x3b,0x13,0x9f,0xa9,0x0a,0x1b,0x55,0x2e,0x1b,0x77,0x07,},"\x61\x6f\xe1\x5f\xcc\xb3\x31\x0f\x9e\xc7\x45\x64\x47\xda\xda\xf8\xe0\xa5\xfb\x26\x9b\xe1\x69\xb0\xc3\xea\x2c\xfd\xaa\xa5\x5d\x37\x93\x7f\xe7\x5b\x78\x32\x4a\xc2\x78\xa6\x50\x47\xe0\xae\x4f\x32\x7e\x97\xef\xfc\xb7\xbe\xd9\x1d\x09\xda\x72\x0b\x0a\x10\x1b\xe9\xe9\x6d\x0b\xa8\x5b\x1f\xf4\x9d\x8d\x1d\xf3\x62\xd3\x45\x4f\x0d\xb6\x82\x55\x96\x10\x1c\x97\xe5\xda\xca\xd0\x7e\xc4\x92\xd3\x0f\x2d\x0c\xb7\xe7\xde\x4e\x74\x4b\xb6\xa6\x10\x0b\x75\x4d\xa8\x47\x41\x1d\x09\xaa\xce\x8d\x5d\x41\x07\x58\xb8\x30\x87\xdb\x4b\x5e\x62\x97\x97\x9a\x21\xfb\x65\xaf\x39\x09\x52\xc4\xf9\x36\x26\x0e\x72\xd7\xc7\x83\x27\xb9\x4a\xa6\xcd\x61\x72\x78\xb0\xce\x9e\x1b\xd3\xfb\xed\x93\xb6\x9b\xc6\x49\x85\xdd\xe0\xe2\xc4\x35\x7b\x50\x2f\x05\x5e\xe7\xb0\xa0\x38\x84\x74\xda\xe0\x2d\x6c\x1a\x73\x1f\x87\x78\x5d\x75\x3a\xeb\x0d\x9c\xfd\xf8\x50\x02\xdf\x56\x6f\xc2\x50\x7d\xe7\xba\x6f\xd0\x35\xbe\xe1\x7a\x2e\x80\x8b\x4a\x75\x88\xc5\x83\x37\x5c\x82\x40\x7a\x40\xae\x9e\xeb\xdf\x94\xdf\x2f\xb8\xca\xbf\x17\x60\x6c\x43\x9e\xa7\x04\x59\xb2\x12\xaa\xe4\xa3\xf5\x30\xec\xad\xc5\xe8\x8e\x25\x48\xfa\x64\x3c\x7d\xdf\x50\x63\xb2\xe1\x06\x73\xe5\x9d\x07\xfe\x90\x68\x92\xb6\x7e\xb5\x8f\x93\x88\xa5\x6b\x37\x04\x52\xe9\x97\x77\x55\xfc\x04\xdf\xbc\x77\xda\x6c\x05\xbe\xdd\xeb\xf0\x36\x52\x56\xb5\x2c\x9a\xef\x8a\x82\x17\x3b\x8c\x89\xfb\xd9\x8c\xea\x36\xa8\xb8\x96\xfe\x66\xd3\x7c\xa7\x9b\xec\x7f\xbf\xe9\x58\xfe\x89\xf6\x76\x50\x85\xb3\x35\xdc\x77\x03\x43\xe2\x30\xca\xdd\xfa\x28\x33\xda\xa6\x62\xfe\x82\x08\xdd\x88\x5a\x6f\xdf\x72\xe3\x6e\xcf\x22\xbb\xbb\xcb\xe7\x9d\x37\x06\x50\x23\x69\x40\xbc\x2e\x6d\x4a\xc7\x4f\xe4\xd5\x54\xc9\xbc\x23\x2f\x07\xd2\xaf\x62\x20\xd1\x57\xbd\x2d\xa6\xa6\x61\x2a\x08\x1b\x4c\x99\x04\xa2\x86\x9b\x13\x7e\xe3\xa0\x85\x6f\x12\xb2\xeb\x87\x62\xdb\x94\xed\x0b\xa1\x36\xf2\x3e\x7f\xb4\xbd\x1f\xcd\xee\x10\xdd\x84\xe2\xcd\x3b\x0a\x49\x14\x8a\xc7\x4d\xb4\x66\xdb\xee\xf8\x1e\x6a\x8c\xe0\x86\x11\x02\xde\x9b\x1a\x3e\x1d\xcf\x5c\x6b\x03\x08\xa8\x2e\x3a\xc7\xc2\x28\x3c\x7c\xc2\xf3\x4f\xfa\x14\x5b\x9f\x74\xb7\x99\x04\xb3\x2b\x79\xe9\x60\xb8\x14\xaa\xde\x63\xa0\xdf\x01\x67\xdc\xd2\x4e\xd9\x0a\x8d\xa7\xb9\x34\xc7\x72\x93\x2f\x5a\x47\x8f\xe2\xa7\x2f\x94\x5a\x13\x09\x6e\xc3\x7c\xe7\x64\xb5\x81\xeb\x89\xe5\xf6\xb2\xbd\x7e\xb8\x8b\x85\xa8\x95\x87\x77\x4d\x45\x8c\x58\xcd\x87\x94\x57\x97\x3d\x64\x8e\xf7\x71\xc5\xf1\xde\xb2\x7a\x0c\xc5\xb2\x92\x46\xac\x2f\xa1\x2d\x18\xdd\xc6\xb9\xf9\xac\x9c\xf1\x46\xc3\xf2\x2b\x1e\x44\x99\xad\xee\xfb\xcd\x22\x49\x74\x0e\x13\xa2\x24\xe7\xb6\xb3\xef\x15\x60\x5e\x7e\x74\xe6\x8d\x7b\x72\x64\x24\x09\xb9\x0c\x4e\xc1\x61\xeb\x24\xc9\xb4\x0f\xf9\xc7\xe6\xe5\xda\x98\x32\x2a\xca\x52\xc4\x6a\x8d\xdc\x19\x0f\x1c\xab\x15\x7c\x4c\x76\x19\x60\x1a\x6b\x33\xdf\x6a\x50\xda\x66\x1b\xc7\x53\x60\xdf\xf6\x97\x50\xd3\x45\x74\x09\xcc\x02\x41\xc3\xe8\xc4\xb3\xe5\x06\xd4\x26\xaf\x52\xb7\x02\x31\xcd\x6c\x91\x26\x0c\xc4\x31\xe4\xcc\xfd\x49\x6c\xa1\x4c\xea\xae\x1c\xda\x78\x72\x1e\x16\x33\x9d\x52\x68\x2b\x69\x51\xf9\x66\xc7\xda\x5c\x6e\x10\xd9\x19\xae\x66\xa9\xf5\x2d\xec\x10\x86\x75\x38\xd3\xdf\x6d\x59\x3a\x32\xdb\x69\x5a\x8d\x77\x45\x70\x35\x16\xea\x56\xf8\xc1\xc8\xf0\xef\x53\xbd\xeb\x7f\x53\xc2\xd9\x44\xf5\x11\x94\x0c\xcb\x90\x62\x49\x22\xac\x59\x9f\x46\x19\xc3\x04\x62\x07\xd6\x05\xf6\xff\x94\xde\x78\x8d\x25\x34\x22\x29\xdc\x8a\xf9\x2b\x5f\xdf\x0d\xd7\x1d\xf2\xb4\x46\xcd\xf1\xd9\xa2\x05\x24\x33\x9e\xe1\xc3\x18\x26\x28\x7e\xf7\x27\x81\xa7\xa3\x52\x89\xf8\x5a\x15\xba\x57\xc7\xfd\x5d\x88\x5b\xd0\x55\x3a\xb4\x08\x05\xf5\x17\xe8\xf1\xb1\xb3\xc4\xfc\x67\x71\xe6\xf2\x24\xbc\x03\x11\x24\xb9\xc9\xae\xb1\x9c\x5a\x96\xbf\x14\x88\xe1\xe6\x6c\x6e\x88\x80\x92\x30\xc8\x3a\x74\x15\x55\x54\xa2\x19\xec\x37\x9a\xe5\x4a\x9f\xe7\x9d\xbe\xde\x3d\x57\x60\x42\xa6\x35\xd1\x97\xf4\xd8\x18\xc7\x78\x75\x5b\x8b\x45\xe5\x13\xde\xac\x88\xf6\x04\x25"}, -{{0x95,0x17,0x4a,0x09,0x15,0x68,0x4c,0xdb,0xb6,0x19,0xb0,0x55,0x49,0x5b,0x00,0xf1,0x92,0x82,0xcf,0xfc,0x3b,0x05,0x01,0x9e,0x6a,0xb7,0x09,0xa4,0xa1,0x74,0x2b,0xab,},{0xaa,0x8c,0x87,0x2d,0x7e,0x10,0xb6,0x7f,0x7f,0xf2,0x41,0x72,0xc3,0x63,0x7e,0x80,0x82,0x5a,0x0a,0x71,0xee,0x0c,0x48,0x86,0x3a,0x2a,0xcd,0xcb,0xe8,0xda,0x45,0x9a,},{0x78,0x0f,0x40,0xc2,0x0f,0xea,0x3b,0x11,0xc9,0x42,0x2a,0x43,0xb9,0xa6,0xf7,0x96,0x11,0xe7,0xf1,0xf5,0x9d,0x14,0x88,0xc1,0x5a,0x5f,0xd2,0xd3,0x2c,0x07,0xda,0xdc,0x39,0x1c,0x38,0x95,0x3e,0xdf,0x0d,0xe4,0x8b,0xe5,0x2d,0xa2,0xaf,0x33,0x5c,0x47,0xb8,0xd2,0xe4,0x4a,0xb9,0xd3,0xdf,0xb7,0x6b,0xa5,0x38,0xb0,0x66,0x49,0x52,0x08,},"\x5e\x1a\x74\x00\x45\x6c\xad\x4f\x9b\xa8\x66\x43\xbc\x7c\xbf\x3b\x35\x68\xdc\xb5\x22\xb3\x70\x55\xe8\xc3\x9d\x3c\x80\xf2\x28\x42\x38\xe5\x72\x7f\xd7\x51\x3c\xc8\xb3\x1c\x57\xae\x7b\x40\x50\xaa\x81\x9f\xc2\x36\x09\x30\xeb\x0d\xd6\x77\xa5\xb2\xc7\x29\xfe\xb2\xda\x3a\xd7\x9a\xe7\xfc\xcd\xdd\xb6\xc0\x84\x46\x26\x1e\xc9\xbb\xe5\x9c\x64\xe9\x9a\xbb\xc8\x6d\x3c\x48\x35\xf0\x0f\xef\xe5\x27\x43\x3a\x50\x1a\x3b\x6d\x57\x2c\xf5\xe1\x2a\x88\x01\x0b\x46\xa4\x72\xb9\xbd\x86\x91\xa4\x07\xc3\x65\xf9\xf7\x16\x34\xb4\xd9\x7e\xdf\xdf\xf0\x63\x14\xc0\xc1\xb4\xeb\x93\xc7\x60\x7f\x1d\x6f\xa3\x54\x65\x93\x22\xc2\x84\x07\x3f\x42\x60\x25\x18\xc5\x4f\xdf\x26\xea\x2c\x27\xc8\x0a\x6d\xfa\x20\x56\x83\x91\xab\x35\x72\x82\xc0\x6b\x23\xbe\xdc\x1d\xf1\x26\x4b\x61\x1c\x1e\x9c\xf1\x8a\xeb\xe2\x49\xfd\x86\x17\xc6\xe3\xee\x98\xc5\x3c\x0f\x6f\x21\x75\xc5\x7e\xf8\xe2\x06\xbd\x3c\xf1\x05\x62\x7a\x98\x92\xeb\x68\x99\x20\x21\x3a\xae\xb6\x3d\x87\x66\x3d\xbf\xa5\x3f\x0f\xb2\x81\x62\x69\x48\x29\x6b\x2d\xbc\xdd\xe1\xc5\x1a\xf8\x62\xee\xcf\x1c\xfe\x8a\x46\xa2\xc4\xb2\x8c\xfe\x71\x30\x33\x0a\xd1\x73\xf8\x71\x27\xaa\xca\xff\x43\xc0\xbd\xde\xa4\x8b\x00\x38\x97\x6e\x66\x2c\x04\xb6\xb0\x4a\xd0\x3d\xe1\x24\x62\xc2\x76\x5d\xb5\x35\x04\x95\x20\xcc\x11\x4a\xfd\xb6\xc9\x25\x49\xb0\x54\x6a\x90\x27\xd4\x49\x75\x5b\xeb\x8d\x4c\x17\xe6\xa2\xa4\x75\xf9\x67\x6a\x33\x7b\x4e\x86\x6d\x96\x32\x5e\x38\x9a\x52\xc1\x6c\x51\xe1\x8e\x0d\x81\x03\x34\x0c\x84\x17\xb2\xc5\x7a\x55\xd0\x42\xff\x5e\x5f\xc6\x5d\xf4\x23\xe0\x09\x2b\x0e\xa8\x8b\x96\xa9\x07\xc9\x51\x21\xc5\x47\xa6\x80\x61\xf2\x7b\xcf\xb5\x8c\xe6\xc0\x77\x28\xd4\x84\x6b\xdc\xbf\x0c\x62\x54\x10\xed\xf8\xde\xa8\xcb\x4c\x9d\x0b\xbe\xef\xcd\xe1\x92\x73\x36\x5f\x48\xd7\x5a\xec\x07\xd1\xc2\x2c\xcd\x23\x06\x8a\x97\xc3\xfe\x75\x2e\x87\xa3\x01\x18\xfe\x2d\xfd\x52\x18\xb6\xb1\x25\x15\x4e\x0e\xa3\x86\xcf\x23\x9e\x31\x37\xf8\xca\x6d\x8b\x74\x6b\x6a\x67\xd5\x08\xcf\x8c\x1a\xb6\x3e\x57\x15\xe6\x72\x1e\xda\x5c\x2b\xc3\x93\xa4\x93\xdb\xd2\xf9\xa1\xfa\x92\x6b\x9a\x59\xe4\x5a\x18\x0a\xee\xb0\x25\x99\xa8\xcd\xd6\x86\xf8\x89\xb4\x85\x27\x23\xcb\x6d\xbf\xb5\x01\x4c\xab\x5f\x65\x8a\x30\x9a\x47\x22\x39\x36\x0e\xea\xf6\x4f\xc8\x20\x3a\x3c\x70\x89\x70\xe1\x5c\xbc\xf1\x36\x25\x5d\x96\x44\x6c\x39\xa9\x27\x03\x1d\x26\x7d\x69\xec\xd5\x1d\x7a\xf6\xe9\x1f\xb4\xae\xf9\xd7\x8c\x33\x35\xe9\x07\x11\x33\xcf\xb8\xe2\x12\x99\x90\xc6\x46\x37\xc7\xad\xf1\xda\xef\x2d\xc2\x6c\x11\x63\x39\x9f\x3f\xe1\xe7\x92\x33\x80\x92\xef\x6f\x8d\xfa\xf2\x57\x30\xdd\x2f\xe8\xd9\x78\xf6\xf7\x70\xf5\x2b\x68\x23\x81\x76\x56\x4c\xee\x5f\xbb\x98\x50\xb3\xb3\xa0\x4d\x94\x84\x60\x41\x78\x26\xeb\x2e\xb2\x4f\xcc\x5f\xe3\x53\x34\xbb\x95\x21\xe8\x7b\xc4\xdb\xde\x2a\xc9\xe1\xc9\x89\x49\xdc\x2d\x29\xad\x27\x9e\x38\x84\xb9\x05\x26\x8e\xbd\x08\x08\xbf\x41\x82\x57\xe7\x5e\x26\x2b\x4d\x01\xb0\x24\xa6\xe9\xaa\x7b\xd5\x01\xdb\xa9\x4f\xf5\x06\x39\x4b\x4b\x0a\xe6\x08\x1e\xa7\x30\x30\xc4\x3a\x6a\x91\x76\x6e\x80\xf9\xf4\x2c\x0b\x68\xb9\x84\x19\xad\x4e\xee\x4e\x9a\x72\x8a\xde\xfb\xd7\x9e\x83\x1f\x70\xf4\x1e\x62\xb4\x3f\x0b\xf4\x2b\x3b\x2c\xd5\x3b\x55\x89\x11\x76\x64\xbc\xeb\xc4\x09\xa7\x64\x5b\x1e\xed\xda\x48\x2f\x6b\x68\x95\xa6\x57\xba\x78\x9b\x89\xe5\x02\xd6\x99\x87\x51\xd6\x30\x3d\xed\x5f\xa1\x56\xee\x7c\x7e\xaf\xe5\x46\x26\xd1\x03\x2c\x4d\x7d\xff\x97\x7f\x1d\xcc\x86\xaf\x89\xb1\xe6\x46\xa4\xaf\xc2\x42\x7e\xd0\x2c\x0a\xf5\xd3\x28\x90\xf9\x5f\x13\xf9\x8c\x1a\x5b\x1d\x9f\xbb\x78\x1a\x9a\x89\xb2\xd7\x90\xc1\x46\x5c\x2d\x15\x20\x92\x6f\xdf\x28\xc1\x7d\x9b\xa1\x58\x7a\xd7\x61\xf0\x65\xd3\x39\xbd\xbe\x38\xf4\x13\x3f\x45\xbb\x59\x78\x74\x26\x42\xf9\x0c\x06\x5e\xe4\x89\x25\x73\xf6\x05\x9f\x8b\x4c\xe2\xc1\x3e\x73\xb8\x91\xcd\x05\xf2\x37\x31\xed\x9a\x07\xe2\xb8\xff\xdc\x96\x3b\x06\xa5\x10\x20\x9c\x32\x99\x80\x94\x9f\x40\xd8\x07\x3a\x01\x3e\xf8\x43\xdf\xcc\x4a\x33\x94"}, -{{0x5a,0x84,0xaf,0x28,0xa5,0xdf,0xbb,0x32,0x33,0xa1,0x2f,0x08,0x37,0xf6,0xe8,0x65,0x4e,0x7b,0x0d,0xe1,0x6b,0x02,0xab,0x3c,0xd1,0x78,0x64,0x43,0x1e,0x27,0x46,0x67,},{0x80,0xd4,0xba,0x78,0x9f,0x8a,0x4b,0x20,0x47,0xad,0xaf,0xa5,0xed,0x26,0xcd,0x8c,0x54,0x67,0x33,0x29,0x2e,0x8b,0xf6,0x93,0xcf,0xd1,0x7e,0x28,0x4e,0xfc,0x68,0x71,},{0xa0,0xb8,0x4c,0xa5,0xaf,0x76,0x46,0xe6,0xf6,0x2a,0x69,0x35,0x37,0x94,0x73,0xfa,0x6e,0x4c,0x27,0x69,0x58,0x51,0xfc,0xbd,0xae,0x29,0x17,0xb2,0xdc,0x68,0xd7,0x96,0xe2,0x78,0xd7,0x0c,0xd6,0x7f,0xce,0xdf,0x6c,0xa6,0x29,0xb8,0x81,0xf7,0xc4,0xf2,0xaa,0x25,0x59,0xb2,0x0d,0x67,0x06,0x11,0x76,0x6b,0xd6,0x5a,0xa4,0xfe,0xf2,0x04,},"\x8a\xac\xd1\xb8\xa3\x9b\xf0\x8f\xd5\xc9\x18\x44\x6b\xe5\x76\xe6\xa3\xf2\x7f\x36\x11\x16\x07\xf2\x7b\x56\xa9\x12\x14\xe7\x63\xf9\xa8\x7f\xb1\xd1\x84\x48\x98\x96\x17\x97\x64\x44\x60\xbf\xf5\x48\x8c\x10\x3a\xf6\x05\xe8\x74\x0e\x46\x58\x8f\xb9\x3e\x44\x3c\x3b\xb2\x3b\x92\xc0\x98\x70\xa5\x57\x65\x3a\x1f\x22\xc2\x18\xcc\xbc\x2f\x07\x3a\x27\x2d\x17\xa8\x42\x23\xef\x14\x3f\x4c\x7c\xa2\x58\x46\x0b\x79\x81\x69\x67\x3d\xa1\x07\xd7\x1d\x53\x56\xce\x9f\x75\x59\xa9\xb0\x38\x39\x99\x51\xf5\x75\xc7\x7e\x5b\x9d\x05\x29\x57\x8e\xca\xa2\xe2\x08\x92\x66\xfc\x52\x6c\x5d\x40\x9f\xbd\x46\xbb\x86\x84\x1c\xb5\x54\xf5\xbd\x3c\x99\x71\x3b\x04\x3e\x40\x46\x53\xa7\xd0\x13\x44\xd4\xdb\x83\x1a\x21\x72\x82\xc4\xb3\x36\x40\x56\x53\xb8\x5d\x27\xa4\x6b\x25\x9c\x85\x5c\xdd\x85\xad\x6f\x7a\xed\xd8\x35\xff\x55\x00\xcc\x8b\xaf\x0f\xb2\xf0\x18\x09\x10\xc6\x46\x72\xb8\xa8\xd4\x9d\x98\x4a\x78\x29\x3c\xf5\x77\x9c\x91\x0c\x3a\xcb\xbc\xa4\x55\xa8\x54\x66\xe5\x35\x04\x4f\x34\x80\x26\x2c\x09\x0f\xbf\x4e\x0b\x0d\xb4\xd1\xef\x87\x59\xda\xaf\xdd\x8d\x05\x90\x74\x82\x46\x1f\xf9\x10\xc4\x37\x19\x5d\x5c\x7f\xed\x9d\x82\xcb\x94\xe7\xe4\xec\x24\xda\x05\x3e\x47\xf6\x2b\x48\x8e\xb7\xb2\x44\x65\x5c\x7d\xbb\x20\xed\x60\x7e\xed\x45\x31\x44\x9e\x07\x80\xe6\x1c\xfd\x57\x40\x86\xff\xc5\xdc\x52\x42\x83\x77\x5c\x44\xf7\x54\x7c\xda\xb0\x4a\x51\xee\xe4\xe1\xb7\xb6\x5a\x57\x57\x3a\x92\x48\x4a\x35\x90\x0a\x90\x9f\x81\xe4\x15\x02\x9d\x22\xca\x93\x7a\x3a\xcd\x9e\x61\xf8\xc0\xe6\x86\xb2\xd2\xad\x03\x77\xaf\x8e\xe1\x66\xe4\xa2\x0a\x82\xaf\xf4\x51\xe1\x51\x10\x3e\x0a\x17\x67\xb2\x71\xfa\x9c\x2b\x1d\xd1\x20\xf8\x05\x85\x3b\x3b\x8a\x56\x0f\xc8\xb9\x37\x62\x83\xb5\x11\x24\x32\x4a\x28\x4a\x0e\x9a\xc4\x9d\xf6\x9f\x52\x4c\x8e\x04\x2d\xf8\x2e\xfb\xcd\x16\x88\x1e\xc1\x31\xa1\x52\x10\xdf\x73\xde\x02\x94\x34\x47\xf2\x2a\x2e\xa1\xdc\x8b\xf9\x68\x29\x8e\xe9\x7f\x3a\xd5\x46\xd7\x8b\xc6\x60\x89\x7e\x08\xd2\xa2\x8b\x2b\xa6\x8b\x54\xb9\x54\xf1\x47\x64\x51\xc6\x92\x07\xe5\xdd\x24\x8a\xe4\x7e\xf3\x56\x94\x99\x0e\x6f\x05\x8b\xc0\x01\x7b\x74\x95\x10\x5c\xc8\x73\x90\x66\xaf\xb1\x1e\x1f\x26\x60\x19\x42\x54\x6a\xe8\x49\xff\x2f\x56\x73\x0f\x13\x26\xbb\xee\xa6\x40\xee\x17\x8f\xa2\x47\xad\xff\xef\xc0\x46\x49\x4f\xc7\xff\xc0\x77\x7d\x5d\xbe\x8a\x55\xda\xee\x61\x40\x6f\xe3\xc7\x08\x8d\x43\xd9\xe1\x4d\xa2\x1c\xa5\x2f\xd8\xc1\x60\x09\x1c\x8f\x99\xa6\x7d\xad\x65\xc6\x4f\xea\x9d\x18\xb1\x53\x7d\x06\x1f\x5d\xce\x87\x9e\x0b\xc4\x26\x48\xd2\xea\xa0\x2d\x97\x21\x85\x75\x3c\xb2\xf6\x22\x5d\x8d\x03\xbb\x07\xf9\x44\xb1\x0c\xf4\xea\x22\x27\x5c\x3d\x70\x84\x80\x20\xf3\x0c\x82\x3b\x76\x14\x3a\xcf\x54\x59\x99\xa2\xcc\x4b\x58\x98\xd9\x4b\x4a\x25\xef\xbe\x5a\x60\x33\x1c\xc0\x09\xfe\xc0\xa2\x5b\xc9\x89\x47\xb1\xb7\x13\x9e\x22\xd2\x32\x80\xff\x88\x54\xa1\xec\x76\x22\x1b\x1b\xf3\xd1\x08\x32\x8c\x8a\xc4\x63\xc6\x52\x63\xa2\xd7\xca\x74\x33\x48\x29\x31\xa1\xd8\xfc\x14\x4b\xbe\x9b\xef\x67\x8c\x92\xe1\xc2\xd1\x09\x21\xb6\xad\x43\xa7\x5c\x53\xbc\x07\x58\x54\xed\x2d\x99\xd8\x25\xf3\x0a\x5e\x10\xd5\x17\x43\x8e\x4d\x4f\x71\x13\x42\x9f\x1e\xdb\x38\x7d\x6b\xd7\xaa\xd2\x92\x74\xf8\xd2\xdc\x88\x9b\x7e\xfb\xeb\x58\x68\x6f\x8d\x66\x9c\xea\xef\x92\xc7\x5e\xd5\x30\x7f\x0c\x03\xf5\x90\x01\x81\xce\x57\x3c\x8f\xa2\x86\x75\x20\x5f\xb1\x05\x7f\x62\x6a\xa2\x30\xd0\x3e\x2e\xaa\x8c\xff\xcd\xe2\x00\x81\x47\x5d\x80\xb2\x45\xa1\xca\x60\x45\xba\x20\x4a\xb0\x00\x69\x07\x9c\x63\x7f\xc3\xfb\x3e\x80\xca\x04\x62\xe7\xa4\xcd\xd9\x28\x3f\xf9\x00\x85\x30\x36\x48\x16\x79\x2f\xdf\x3b\x9a\x4e\x4d\xc8\x37\x92\x28\xed\xcb\xb1\x54\xbe\xf3\x87\xd3\x77\x60\xd7\x9a\xfb\xb7\x36\x26\x0a\x1d\xb1\x01\x38\x36\x1f\x24\xb8\x26\xdb\xcd\x5f\x0f\xc9\xe7\x83\x0d\x26\xd8\x0c\x52\xa7\x92\x18\x92\x76\xbc\xe3\x47\x60\xfb\x77\xbe\x13\x12\xac\x8c\xf9\x7d\x92\xcb\xf3\xd0\x77\x80\x28\xdb\x5e\x8e\xae\x89\xe0\xb9\xbc\x87\x78\xae\xb1\x27\x8f\x04\x71\xcb"}, -{{0x79,0x3a,0xc8,0x8d,0x7d,0x3b,0x6f,0xa7,0xf4,0x7d,0xee,0xc3,0x1f,0x68,0xdd,0xcc,0xb7,0x01,0x82,0x0f,0x1b,0x13,0xdd,0xc6,0x52,0xf7,0xc6,0xa8,0x5b,0x60,0x52,0xa5,},{0x91,0xb6,0x22,0x7a,0xcd,0xd1,0x83,0xda,0x62,0xc5,0x19,0x65,0xc6,0x35,0x35,0x8b,0x20,0x4d,0x68,0x3e,0xe0,0x64,0x43,0xcb,0xd4,0x0e,0x71,0xc1,0xf7,0x6a,0xd1,0x02,},{0xa8,0x4f,0x55,0x2b,0xf4,0x43,0x22,0xa6,0xdb,0x24,0x5c,0xa0,0x06,0xd1,0xcf,0x78,0x0c,0x61,0x68,0x0f,0xe7,0x42,0x9a,0x89,0x47,0xc3,0x5f,0x21,0xbc,0x4b,0x44,0x22,0x8b,0xa3,0x0a,0xea,0x0c,0x74,0x4b,0x86,0x64,0x59,0xd3,0xb8,0xac,0xad,0x45,0x3b,0x06,0xac,0xe2,0x47,0xba,0x69,0x52,0x8c,0x6b,0x3b,0xc4,0xb2,0x0e,0x75,0x63,0x0e,},"\xec\x50\xaf\xad\x8a\xde\x74\x05\xe2\xc6\xf5\xc6\x24\x7b\xbb\xcc\xfb\x2c\x17\x16\x6f\x78\x84\xfe\xae\x10\xd9\x0f\x5d\x83\xc4\xb6\xf0\xbf\x76\xde\x2f\x78\x97\xba\x11\x94\xd6\xd3\x44\x9d\xdb\x80\xae\x74\xeb\x8e\xd6\x8f\x04\x9b\x35\xc6\xf2\x19\x16\xdb\x4d\xfc\x27\x24\xdc\x3a\xf7\xad\x8d\xd5\xc4\x4f\x60\xd2\xf4\x9f\xad\xd7\x00\x4d\xa1\x59\x30\x93\x94\x2c\xae\x52\x08\xbf\x54\xcf\x90\x3b\xee\x64\x69\x05\xfc\xe2\xeb\x2e\x37\x0d\x0d\xca\x48\xd8\x20\xad\xea\xb1\x6a\x3b\x67\x5e\x5a\x4a\x8e\x26\x7e\x34\xff\x96\xf3\x12\x2b\x18\xde\x0c\xad\x92\x92\xab\x63\xd2\x6e\x5f\x31\x0f\xa2\x16\x8c\x29\x66\xbd\xb6\x3b\x0d\xe0\x86\x26\x76\x7b\x37\x9d\xe4\x63\x3b\x9f\x3e\xda\x79\x17\x28\x1d\xad\x66\x1e\x9f\x77\x2b\x84\x4a\x79\xe8\x00\xfd\x84\x27\x02\x44\x6e\x4a\xa7\x31\x75\x71\x07\xf3\xfd\x65\x47\xbf\x40\x75\x96\x3d\x5f\xd5\xf5\x8e\x80\x85\x3f\xc4\x27\x51\xdc\xa0\x78\xa9\xfa\x8d\x5b\xb3\xd9\xa3\x4a\xbc\xab\x02\x93\xd6\xce\xae\xc4\x89\x67\xa1\xe6\x22\x43\x98\xca\xd0\xf6\x05\xa3\xbe\x8e\x67\x58\xea\x8f\x29\x20\x9d\x8e\x4c\x4c\xa1\x89\x3b\xaa\xd9\x1e\x37\x9b\xa3\xb1\x73\x30\xc1\x2a\x5b\x6f\x21\x9b\x38\x4a\x8a\xb9\x78\xbf\x1b\x37\xc3\x73\x1a\x1b\x47\x4b\x24\xb5\xd6\x7d\x4c\xec\x28\xaa\xc6\x51\x0b\x11\xf2\xcf\x21\xbc\x16\x96\x3d\x51\xf5\x53\x87\x27\x71\x8f\xc4\xe2\xe5\x17\x2e\x3c\x0c\xda\xbc\x27\x7f\x0d\x70\x37\xc3\x4c\xa6\x8f\x73\x28\x88\x48\xb9\x26\xbd\xe0\xcf\x47\xab\xfa\x66\x60\x09\x16\x94\x6f\x07\x65\x1c\x28\x0a\x20\x86\xb1\x4d\x52\x57\x0c\xc8\xa4\xb7\x43\x58\xb5\x9c\x30\x2b\x9d\x00\xe1\xb4\x98\xf3\xbc\x33\xee\x4e\xcf\x2b\xce\x2c\x65\xed\x7e\x8b\xa7\x4d\x35\xb7\x51\xd3\xc9\x9f\x40\x86\x19\x68\xc2\xb7\xf3\xa5\xbe\x34\x8c\x57\xd9\x3b\x40\xff\xd0\x51\xed\xd7\xca\xca\x6e\xe6\xbc\xa7\x21\xdc\xba\x8d\xb8\xd0\x06\x4f\x54\xd3\x6e\xc5\xe8\xd6\x2a\x71\xfd\x1c\x90\xf1\x49\x24\xf4\x1c\x16\x3f\x00\x7a\xfc\x6f\xbb\xfe\x86\x45\xfa\x47\xc3\xc9\x80\x24\x6d\x1b\x92\x27\x43\x85\x95\x3c\x53\x41\xcd\x64\xc3\x4a\xe9\x71\x7c\xc2\xc3\x7f\x58\x35\x9c\x0a\x99\x91\xc2\x3f\xe6\x37\xde\x6c\xdf\x08\x62\xf7\xd0\x32\x9f\xe7\x58\xaa\x89\x2a\xd4\x58\x3b\x9d\xf2\xf3\x33\x7d\x5b\xe5\x70\xba\x65\x49\x98\xed\x29\x2f\x11\xf0\x17\x72\x38\x2a\x04\x34\x2f\xdd\x99\xe6\x9e\x0d\x97\xc4\x3f\x10\xac\x9b\x96\xf1\x40\xa6\xf8\x3c\x47\x29\xe7\xa9\x00\x47\x1f\x2b\x1d\xf2\x40\x1b\xc5\xc6\x80\x42\x2b\x13\xb0\xc8\x00\x7d\x63\x68\x1f\x66\xa0\x59\x5a\x1c\x5d\x3a\xcd\xe5\xb7\x79\x42\x6e\x73\x6b\xc1\x00\xc5\xe6\xf5\x26\x08\xdc\x39\x1e\x3e\xf9\xb1\xbb\x6a\xf1\x3d\x24\x9b\x7d\x32\xce\x06\x80\xc3\x68\xf5\x4d\x5f\xe0\x39\xcf\xe1\x01\x30\x25\x1e\x4d\xb1\x4c\x79\xc8\xd0\x44\x06\x04\x65\x82\x29\x90\xd8\x80\x93\xcd\x73\x65\x32\x85\x2e\x44\x78\x89\xdb\x89\xcc\x60\x05\x29\x96\xa3\x2a\x64\x36\x5c\x07\x26\x05\x1c\x11\x9e\xda\x90\x1d\xe5\x76\xb3\x34\xfc\x70\x49\x48\x23\x92\xe2\x62\x0b\x0a\x3a\x13\xfa\xb1\xd3\x6f\xc0\xa5\xf2\x3d\xb1\x47\xfd\x85\x7b\x26\xa6\x98\x04\x8f\x8b\x81\x1e\x23\xd7\x22\xe2\xe9\x02\x7e\xd4\x12\x4b\x48\xdc\x5e\x57\x8a\x7a\xeb\x19\xa1\xb4\xf9\x48\xee\x5b\x46\xf6\x5b\x97\x96\x46\xe2\xbe\x07\x47\x14\x11\x8b\xaa\x4b\xfc\x15\xb0\x89\xa0\xe0\x66\x27\xda\x46\xe4\xbb\x06\xaa\x3c\x7c\x5d\xd6\x48\xe0\x3c\x9c\x2d\xec\x3f\xac\xd9\x56\x26\x56\x2f\x30\x00\x88\x32\x30\xd2\xb0\xa1\xf8\xa7\x47\x8c\xb7\x7f\x93\x9a\x5f\x18\x8f\x45\x8d\x10\x37\xb9\x01\x76\x66\x4d\x86\xea\x85\x0b\x8a\xf5\x08\x7f\x86\x60\x5a\x77\xe0\x25\xef\x6c\x7e\x6a\x2a\x59\xf0\x06\xcb\xa1\x89\xfa\xd9\x33\xf4\x2c\x53\x27\x08\x10\x9b\xc1\xaf\x81\x48\x19\x59\x5f\xfc\xb9\x5f\xbf\x5b\x7e\x93\xa7\x11\x97\xe4\x77\xee\x7c\x04\xb8\x51\xc1\xc3\x66\x22\xcd\xd8\xe6\xc8\x60\xd9\xab\x2c\xac\x56\xd2\xdc\x98\xfa\x69\x12\x4f\x2b\xb2\xa6\x47\x1e\x1c\x73\xb6\x61\xf0\x71\xf5\xd8\x6d\xe7\xd1\xde\xaf\xa4\xed\xcd\xc7\xbf\x1f\x70\x5c\x56\x30\x0a\xff\xd0\x58\xb9\x69\x77\x91\x41\x9e\x5f\xb2\xa5\xb7\xf7\x8c\xe3\x40\x1f\xf5\x50"}, -{{0x89,0xde,0x74,0x42,0xd7,0x4b,0xa9,0x38,0x59,0x69,0xc9,0x65,0x1a,0x88,0xfe,0x28,0xe0,0x40,0xd5,0x93,0x90,0x7d,0xac,0x1a,0x39,0x87,0x41,0x8b,0xdf,0xdb,0xad,0x89,},{0xfd,0x3b,0xa9,0xfa,0xd3,0x20,0xeb,0xa4,0x5d,0x07,0xb8,0x4a,0x49,0x7b,0xe1,0x7d,0x3f,0xc7,0xdd,0x99,0x99,0xc9,0x68,0x88,0x3c,0xd6,0xac,0x13,0xb0,0x66,0x9b,0x17,},{0xba,0xb5,0x72,0x84,0xd2,0x0e,0xe5,0x4c,0xc7,0xf9,0x70,0x8d,0x71,0x77,0x06,0xd8,0xfa,0xf6,0xe4,0x63,0x32,0xb0,0x69,0x1d,0x6f,0x21,0x3a,0x8d,0xb8,0x01,0x15,0x5b,0x4e,0x33,0x8c,0x13,0x61,0xb5,0x92,0xbe,0x75,0x85,0x01,0xb1,0x82,0x17,0x93,0xae,0x52,0x27,0xcc,0x3b,0xa8,0xdf,0x8a,0xdf,0xc6,0xed,0x9a,0xca,0xb5,0x4c,0xc4,0x01,},"\x9d\x52\x72\xf0\xb7\x84\x88\x2b\x94\xc7\x6d\xfb\x9d\x46\x0c\xa4\x95\x02\x5e\x0a\xec\x5d\x52\xcc\xff\xfe\xce\x9f\x81\x73\xc1\x05\x58\x26\x6c\x49\x85\x25\x89\x1a\x97\xbf\x38\x78\xe3\x3c\x3d\xe2\xfc\x2e\x52\x55\x0b\x43\x15\x62\xcb\xe4\xa3\xd0\x11\xec\xc9\xe7\x7e\xc3\x6a\xd3\x83\x41\x35\x8c\x88\x32\x1c\x03\xd0\x8b\xb4\x26\xa7\xd5\x85\x41\x71\xc0\x27\xec\x48\xd5\x78\x19\xa9\x1a\xfd\x02\xa6\x18\xcc\xbc\x25\xe6\x8e\x53\x09\xd0\x47\xb1\x56\xe3\x57\x05\x37\x3a\xda\x2e\xb8\x31\x32\x1a\x20\x3e\x1b\xd8\xf0\xef\xec\xc0\x96\x18\x64\x7b\x41\xdf\xf2\x2b\x39\xd0\x22\x35\xf8\x71\x53\x2f\x60\x85\xe9\xcc\x52\xec\x00\x9b\x33\xee\xbc\xdc\x26\x7d\x77\x67\xc9\x0c\x92\x7e\x15\x4f\x72\xf3\xf4\x8a\x34\x95\x63\x19\xb2\x93\xc8\xa8\xb3\xe3\x4e\xfc\x5f\x62\xf2\xb4\xe8\x01\x9b\x50\xa0\x8f\x5c\xcf\x95\xbc\x83\x1b\xaf\x40\x81\x1d\x87\xe5\xed\xbd\x2f\xd5\x36\x5b\x26\xa4\x31\xae\x95\x80\x0f\xf3\x81\xcd\x62\xca\x40\xe1\x86\x6d\x95\x0d\xce\x14\xf0\x30\x91\x8a\xba\xc6\x8e\x79\x16\xdd\xb9\x5a\xdc\x19\x71\x28\x78\x74\xd0\x7e\xb0\xed\xef\x64\x29\x66\x52\xc4\x80\x44\xb0\xc5\x52\x1a\x8d\x27\x0d\x53\xd7\x4e\xc6\x3b\x89\x0f\x33\x63\xf9\x20\x7f\x66\x52\xae\x8e\x78\x35\xc3\x82\x0a\xd6\xd9\xe3\x63\x3f\x4b\xfd\x53\x79\xa4\x4f\x29\xd6\x5f\x36\x09\xfe\x35\x58\x17\xdc\xa5\x51\x8d\xfe\x3b\xd7\x69\x32\x0a\x03\x19\x02\xe9\xcf\x66\x69\xc2\x4f\x88\xb0\x1e\xb3\x69\x95\xbd\xb8\xdb\xed\x6e\xe0\xc9\xb7\xf3\x22\x95\xc6\x1b\xa8\x90\x5e\x55\x98\xf3\xc9\xe1\xc8\xbf\x72\x64\xf9\x82\x93\xfa\xea\x17\x74\x7f\x88\x44\x0c\x31\x81\x8c\x43\x3e\xa3\xd2\x3c\x01\xf4\xf7\xe9\xc3\xdd\x3d\x5f\x32\xec\x9e\xac\xd7\x1a\x09\xe3\xa9\x97\x38\x1f\x1c\xbf\xfd\xf4\xb5\xba\x49\x79\xde\xb7\xb0\x98\x41\xaf\xa3\xb0\x3d\x1c\x93\x11\x09\x7b\x86\x2c\xae\x11\x70\x7c\xbd\x3a\x4a\xe6\xc8\xa2\x6a\x30\x6a\x68\x7c\x41\x4a\x4e\xa1\xe8\x12\xf1\x15\xf6\x0f\x70\xbd\xa7\xf8\xfb\xe7\xbc\x2d\x50\xcc\x55\x0b\xba\x29\x1d\x5e\xc5\x23\x22\x9a\x08\xed\x56\x8b\x5c\xee\x18\xfe\x6f\x46\x78\x2c\x17\xcd\x82\x88\x01\x63\x92\x15\xbc\x5e\x9b\xe4\x55\x5c\x9a\x18\x00\x97\x67\xa6\xc5\xc7\x4a\x82\x29\xd2\xff\xaa\x39\x9d\x8e\x64\x32\x4e\x88\x42\x23\xd5\x07\x0f\x73\x5a\x75\xd8\x5f\xf6\xc9\x4a\x9f\xbc\x2b\x36\x51\x38\x6d\xe5\xa2\x3c\xce\x95\xc8\x78\x81\xc7\x93\x99\xae\x71\xf0\x90\x73\x7e\x21\x87\xfe\x90\x4a\xab\x1d\x92\xd6\x18\x67\x95\xc9\xb4\x6c\x62\xa5\x91\x4f\x36\x30\xfd\xcb\xac\x3b\xd4\xb0\xda\x4e\xc3\x13\x6a\x1f\xb2\xba\x40\x32\x2d\x7c\xc4\x08\x5e\x16\x70\x09\xcf\x74\x50\xfc\x6a\x28\x6c\x2f\x79\x51\xd5\x1a\xae\x23\xb8\xf3\x30\x20\xef\xb5\xe3\x24\x5b\xa6\xa3\x54\x3a\x2b\xde\xc4\x47\xd5\x1a\xe0\x0b\x5e\x16\x78\xb7\x60\x93\xcf\x21\x6b\x95\x07\xc9\x63\xeb\xfc\x02\x4c\xcd\x6e\xf6\xc7\x8c\x45\x72\x27\x3b\xea\xaf\x55\x07\x6d\xc4\x4a\x22\x4b\x58\x61\x57\x05\x79\x19\x65\x30\x7c\xef\xd4\x86\x72\xc0\x81\xbc\xcf\xbc\x1d\x15\xb0\x62\xb3\x8b\x4f\xba\x9b\x9b\xec\x95\x6c\xd1\x44\x44\xee\x43\x7e\x79\x60\xcc\x60\x1e\xdd\xc0\x2f\x1a\x76\xb6\x85\x74\xd5\xf8\x84\x31\x50\xc0\xb9\x00\x99\x34\xa2\xbf\xaf\x60\x57\x70\xc1\x36\xba\x29\xf3\xdc\x7e\x29\x59\x7a\x24\x80\xdb\x23\xe2\xb2\x67\x7e\xc6\xc5\x1b\xd3\x01\xf2\xb5\xa3\x9d\xfd\xa7\xb4\x77\xbe\xdd\x1c\xda\xed\x10\xe2\x9d\x29\x54\x62\x9b\x98\x76\xf8\xee\x54\xe4\x04\x73\x69\xd5\x34\xca\xb5\x4a\xea\x44\x1d\xc9\x47\xeb\x3f\x59\x38\x2b\x21\x83\x60\x57\x2f\x26\x59\x58\x31\x53\xc0\xe2\xb9\x12\xcf\x30\xc8\x15\xb2\x6f\x05\x85\x3d\xd3\x05\x51\xee\xcf\x64\xb8\x58\xa4\x41\xbb\x8c\x6d\xb8\xa9\xfd\xe7\x7a\x32\xa7\xb4\x6a\xf6\x6f\x8c\xb9\xf3\x5e\xe0\xfa\xfb\x0b\xd4\x2d\x9e\x65\xb2\xa9\x05\x82\x41\xa3\x1b\x8c\xa1\x11\x54\x34\x23\x76\x70\xaa\xb4\xef\xf3\x60\x10\xed\x03\x71\xf4\x65\x95\xda\x1b\xdd\x57\x9b\xbb\x67\xaa\xdb\x68\xe7\x7a\xd3\xa3\x8c\x8f\x26\xd2\xaf\x5a\x71\x03\xba\x5f\x22\xb4\x2c\xc1\x2a\x8c\x3c\xe5\xc9\x21\xc9\x1c\xfc\x0e\x63\xdf\x90\x27\xd2\x62\x29\xb1\x04\x7c\xbc\x18\xf6\xb0"}, -{{0x26,0x22,0xbd,0x9b,0xbe,0xf7,0xff,0x4a,0x87,0x62,0x9e,0xa0,0x15,0x3d,0xc4,0xd6,0x08,0xc3,0x1f,0xa5,0x84,0x79,0x88,0xff,0x50,0x0d,0x88,0x06,0x81,0xf1,0x13,0x72,},{0x19,0x97,0x58,0xa9,0xc3,0xd0,0xee,0x3e,0xeb,0xcb,0xbd,0xa3,0xe1,0xef,0x54,0x55,0xff,0x46,0xd7,0x36,0xbb,0x4e,0xf0,0xc0,0x6a,0x73,0x9f,0x9a,0xc5,0x84,0x83,0x95,},{0x43,0x78,0x96,0x6b,0x78,0x31,0xde,0xf4,0xae,0xcb,0x49,0x89,0xbc,0xaf,0x9c,0xae,0x99,0x46,0x1c,0xb9,0xb5,0x9d,0x19,0x51,0x8c,0xc1,0xec,0x7b,0x83,0x51,0xbc,0xd1,0xf7,0x23,0xaa,0xc5,0xf0,0x61,0xb3,0x83,0x63,0x57,0x4f,0xf9,0x6b,0xa1,0x0e,0x19,0x6b,0x1b,0x05,0x31,0xe1,0x18,0x30,0x36,0xa4,0x25,0xe6,0x9c,0x45,0x98,0x04,0x0c,},"\x89\x1e\x82\x12\x25\x47\xd6\x1e\x83\xb0\xab\xaf\x27\xc7\x30\x3f\x05\x22\xa2\xec\x4a\xf4\x4e\xf0\xac\x19\x6a\x99\x78\xb1\xc6\x23\xef\x1f\xa7\x2b\xaf\x70\x91\x0a\x5c\x51\xc4\xf7\x8e\x0f\xe9\xfe\x37\xe2\x43\x9c\x47\x95\x91\x6c\xfa\x22\xab\x47\x1a\x25\x57\xcc\x7b\xa6\xb6\x69\x56\x06\x3d\xde\xb3\x9c\x50\xf1\x4f\x06\x34\x8f\xa6\x6b\x60\x64\xdc\xff\xca\x50\x43\x96\x7f\x05\x25\x4d\x57\x7a\xbf\x22\xae\x8c\x90\x00\x0c\xe2\xe6\xa1\xa8\xb2\xe3\xa6\xb3\xab\xc5\x63\xeb\xff\xb2\x04\x45\xf0\x91\x1c\xc4\x2a\x98\x7f\x84\x56\xef\xba\x41\x30\xe6\x8f\x01\xfc\xdf\x7b\xf7\x71\xfc\x1d\x35\x37\x1a\x0d\x75\xdd\x5f\x90\x00\x2c\x90\xb6\xcb\xad\xe4\x0d\x5b\x23\xfd\xb4\x9a\xba\xcb\x72\x19\xae\x27\x56\x1a\xa2\xa8\x79\xda\x88\xdf\x34\xa8\xc5\x81\xf0\xc6\x71\x98\xff\xc6\x08\xfe\x91\x95\xb5\x55\x5c\x8a\xe9\x34\xc8\x30\xaa\xe2\x88\x5b\xea\x87\x48\x74\x48\xe1\x1b\x4f\x2f\x17\x2e\x4d\x5c\xfe\x4f\xd1\x13\xf9\xd2\x01\x6c\x24\xa7\x34\x51\x2b\xb9\x18\xf5\x75\xe7\x54\x13\x97\x18\xe3\xd2\x0e\x79\x0a\xbb\x94\x2c\xba\x3e\xc8\xb2\xdb\x59\x07\x96\xdc\x43\x5f\x13\x9f\xc6\x4d\xdc\x85\xa2\x24\x94\xef\x2b\xfa\x1f\x5c\x0f\x18\x75\xea\x58\xe8\x4e\xb3\x74\xec\xf8\xce\xc6\x46\x8b\x6b\x09\xd1\xe7\x4f\x15\x41\xed\x45\x4a\x28\x07\xd3\xf4\x05\x35\x66\xb0\xe4\xe2\xc6\xae\xce\xd1\x0d\xc0\x07\xe9\xdf\x41\x6f\x26\x7f\xcb\x3f\xe1\x7b\x8b\xac\xe0\x3f\x07\x43\xe0\xe6\xd4\xa4\x8c\xe7\x6e\xdf\xf6\x0c\x0e\x3a\x30\x84\x56\x99\x54\x13\xc1\x07\x6f\xf3\x7e\xcf\x23\x81\xa0\xd4\xe9\xe4\xa9\x13\xa2\x58\xd9\x83\xb9\x69\x6b\x5c\x45\xaf\x37\xc8\x68\x40\x70\xe4\x00\xb8\xf8\x65\xa5\x04\x04\x3f\x45\xd7\x8b\x97\x13\xf3\x35\xaa\x41\x6a\x46\x16\x64\x10\x73\x5f\xb5\xd8\x22\x10\x45\x8d\x5a\x08\xa1\x04\xd4\x00\x2a\xb6\x11\x88\xf9\xdf\x45\x7d\xd7\xed\x59\x37\xca\x50\x77\x60\x6b\x41\x8b\xbc\x86\x84\xa1\xd5\x25\xbf\xa5\x51\x08\x76\x40\xb1\xd1\x77\xca\x6d\x4f\x64\x71\xb3\x9b\x2c\xe4\x3a\xfb\xf8\x28\x5e\xcd\x68\x7e\x43\x8f\x44\x25\xdf\x56\x8a\xb8\x6f\xa2\x31\x63\x49\xa1\x10\x2b\x41\x43\xd7\x1e\xf4\xe2\x4f\x5c\x53\x0c\x77\xaf\xb0\x10\x07\x88\x63\x64\x40\xe7\x40\x67\x5a\x61\x74\xc5\xf0\x57\x10\xb2\x53\xa4\x11\x17\x3f\x9e\x82\xce\x6e\x22\xf4\x09\x5e\x77\x14\xb8\x73\x7e\x14\x7a\xa0\xf2\x31\x91\x57\x8f\xfd\x93\x82\x3c\xe4\xbf\x91\xc1\xd1\x10\x98\x2a\x5d\xa0\xe4\xb8\x1b\xd2\x5b\x9b\x9c\x21\x42\xa7\x67\x1e\xe9\x37\xc9\x0f\xd0\x71\x5e\xc9\xaf\xa4\x4d\x86\x04\x68\x98\xb4\x2f\x75\x35\x89\xd2\x26\x8d\x2a\xaa\xa9\x85\xcc\x90\xe0\xf9\xe8\x27\xa3\x92\x3e\x77\x16\x34\x6f\x4f\x89\x31\xc7\x28\x21\xb3\xeb\x64\x5d\xaa\x74\x52\xc8\xaf\xc8\x98\xd7\x97\x55\x45\xc1\x2d\xa1\xbd\xb2\x09\x04\x5c\xb0\x0f\x4b\xfd\x53\x83\xdf\x01\xf0\x03\x68\x0b\x97\x34\x40\xf1\xa3\x9c\x9d\x82\x09\x59\xef\x6f\x85\xbd\x33\x63\x90\x65\xae\xfd\xc8\xbc\xfe\xcb\xd9\xb9\x55\x40\x49\x73\x8a\xf2\x9f\x12\x94\x63\x9d\x39\x15\xd6\x32\x99\x5e\x8f\xaf\x71\x3e\xf2\xee\x3c\x29\x8b\x55\x96\xfa\x10\xc9\x9f\x94\x6d\xdb\x32\x34\x06\x95\xdf\x1c\x19\x45\x94\xea\xf3\x77\x8d\x73\xc8\xba\x60\x40\xc0\x4e\xb3\xa4\xff\x86\x77\x93\x6b\x88\xe0\xc5\xf0\x44\x14\x80\xd1\x07\xd7\xac\x22\x02\xb3\xb6\x94\xe5\x7c\xcc\xa6\xd8\x25\xe2\xa0\x7e\x81\x2e\xd2\x9b\x2c\x20\xd5\xc6\x05\x47\x15\x79\xe3\xed\xff\xc2\x23\xf2\x42\xc5\x93\x91\xdb\x41\xe9\x8d\x5f\x3d\x6c\x5b\x1e\x32\xac\x82\x37\xfc\xfd\x10\x20\x54\x3a\x40\x41\xe0\x3d\x92\xad\x3e\x2e\xc5\x52\x91\x47\x07\xc7\x7c\xd0\x1f\x3e\x48\x01\x14\x44\x28\x3f\x09\x68\xfa\x4d\xee\xee\x55\xc4\x56\xed\x1f\x87\x7a\xde\x04\xac\x8e\x8d\x2c\xb6\xc8\x58\x20\xb4\x92\x9b\x25\xbf\x31\xe9\x25\x43\x5d\x6b\xcc\x50\xd3\xe2\xe9\xb8\x51\x02\xe9\x70\xd7\x89\x5c\x25\xad\xe5\x21\x61\xa3\xb6\xbf\x50\x1a\xb0\x19\x61\xcb\x63\xed\x99\x0a\xeb\x93\xed\xa3\x82\x8b\xf0\x4c\xa5\x28\x53\xc7\xb6\xb8\xe9\xe4\x9e\x34\x9d\x69\xb5\x3b\xe0\x74\x85\xf5\x42\xb7\xcd\xd0\x6b\x52\x7d\x41\xdd\x11\x9c\x70\xb5\x64\xf1\xa9\x3a\xec\x62\xae\x74\xe6\xe8\xf8\x55"}, -{{0xae,0xb1,0x3c,0xcb,0x90,0xc8,0xcb,0xef,0x90,0xd5,0x53,0xda,0x3f,0x69,0x01,0xb3,0xd7,0x5c,0x13,0x01,0x1f,0x02,0x49,0x74,0xda,0xf7,0x9a,0x17,0x89,0xc8,0xc6,0x32,},{0x5f,0xaa,0xfe,0xb5,0x95,0xf1,0x6d,0x33,0x8f,0x1c,0x72,0xa9,0xf3,0xe4,0x98,0xf3,0x8b,0xab,0x69,0xa8,0x1b,0x37,0xd2,0xd0,0x92,0xb7,0xbf,0x7e,0x50,0x5d,0x82,0x0d,},{0x06,0x11,0xb1,0x9a,0x74,0x72,0xa4,0x43,0xe8,0x7e,0x54,0xd7,0xc6,0x64,0x7f,0xaa,0xb1,0xb7,0x9a,0x83,0xfd,0x43,0x71,0xc9,0x2b,0x97,0x54,0x00,0xfd,0x62,0x8a,0xcf,0xc3,0x25,0x77,0xcc,0xbb,0xaf,0x03,0xd8,0x8f,0x89,0x3c,0x88,0xf2,0xca,0xc7,0x84,0xc7,0x22,0xa0,0x8f,0x38,0x7a,0xbc,0x31,0x9a,0x70,0x2c,0x86,0x84,0x79,0x65,0x0b,},"\x86\x1a\x10\x18\xd6\xbd\xc4\x80\x5a\x5c\x4d\xf8\x7e\xfa\xa4\x62\xc6\x8b\x4b\xf4\x06\x5c\x68\x4c\x2a\xf1\x31\xc6\x37\x73\x88\xba\xee\x58\xc6\xc8\xf8\x84\x23\x62\xec\x6e\x3b\xce\x07\xc8\xaf\x55\x88\x5e\x82\xdb\x87\xa1\x52\x27\x80\x0d\xd3\x3a\xfc\x5e\x5f\xd1\x57\x01\xe9\x5f\x53\x50\x1b\x1a\x6f\xf8\x3c\x64\xe8\x51\x71\x49\xbf\x3f\xf0\x11\xb0\x94\xa0\x9c\x67\x3d\x0f\xc4\xa3\x9e\xe5\x5e\x69\xf0\x71\x17\x7b\x8a\xa3\x64\xe1\xe2\x56\x06\x4c\xf7\x02\x79\xcc\x76\x69\x5a\xe4\x9d\xaf\xcd\x80\xca\x0a\x14\xe1\x69\x1d\xb9\x46\x42\x2e\xc7\x5a\xb4\xf7\x86\x59\x15\xa6\x9b\xd4\x8d\x89\xb1\x2a\xdf\x48\x7d\x4d\xb9\xbe\x87\xcd\xdc\xa2\x11\xaa\x88\xe9\xbb\xe8\x49\xda\x21\x39\x89\xeb\x08\x44\x59\x2a\xd6\x3e\x28\x1b\x2e\x4a\xfe\x6a\x88\x36\x00\x66\x09\x92\x6c\x0f\x78\x7e\x84\xf2\xa9\x5b\x46\xb6\x6f\x0e\x45\x55\xc9\x48\x3c\xe2\x17\x6f\xc6\x3f\x7c\xc9\xf4\xf2\xa2\x2d\xb0\x55\xaa\xe2\xe6\x8b\x30\xa0\xda\x5f\xeb\x80\xc2\xa6\x0e\xa1\x0d\xbf\x67\xfb\xbc\xdb\xe0\xbe\x33\xf2\xe9\xc1\x3c\x46\x9e\x77\x68\xf2\xff\x59\x60\xa5\x5e\xb4\x82\xec\x11\xd4\x7e\x15\x4b\x7c\x42\xa5\xfb\x75\x6c\x8a\xd5\x39\xb3\x3d\x12\x5a\x4a\x65\x19\x2c\x6c\x9b\xd5\x76\x23\x8c\xa7\x2a\x73\xcd\x17\x9e\x8c\xf5\xcd\x04\x8e\xd3\x30\x21\x38\x23\xab\xba\xfc\x36\x82\xb2\xb7\xf6\x8c\x5b\xc4\x6f\xd0\x9a\x8c\xb2\xa3\xfd\x09\x95\x73\xee\x2e\x6f\x28\xc8\x2e\x27\x1b\xb5\xef\x93\x4b\x0b\x0c\x38\x1c\xfa\xae\xc6\x66\xd7\x17\x10\x6a\x87\x4a\xf3\x0a\xa7\x41\x25\xea\xe9\xac\xc2\xf1\xf2\x41\x18\xcb\x4e\x68\x3a\x73\x1e\x37\xe5\xe4\x64\xa1\xea\x3d\x2a\x53\xcc\x0d\xca\xd4\xc1\x7c\xea\x9a\x43\xe2\x36\x5f\x3a\xe3\xdd\x89\xeb\x39\x97\x74\x20\x04\x55\x50\x74\x5f\xc2\x67\xfc\x7d\xcc\x56\x02\xe9\x14\x97\x2a\x4d\xa6\xeb\xeb\x68\x7f\x68\xa0\xcd\x7d\x8b\x4f\xdd\x73\x72\x21\x06\xa8\xe4\x36\xb9\x3e\x5b\x58\xf5\x98\x2a\xce\xcd\xec\xfd\xb3\x82\xfe\x98\x53\x82\x61\x42\x6b\xa6\x40\x52\x55\x76\x43\xce\x9f\xec\x71\xea\x43\xcf\x5b\x6c\xba\xde\xb4\x95\x31\x93\xff\x3e\xd1\xa1\xf9\x22\xa9\xaf\x2e\xc6\xf3\x38\xe7\xfb\x0a\xff\xe3\xd1\x3c\x33\xe3\x95\x87\x3e\x4a\x7a\x7f\xb0\x44\x98\x1e\x05\xa6\x71\x97\xb9\x96\xb1\x99\xb4\x30\x11\x11\x93\x63\xe5\x61\xd5\xb8\xa5\x17\x84\xfd\xff\x58\xab\x80\xed\x4c\x49\xe9\x3f\x0c\xf4\x19\x24\xf9\x83\x5e\xfb\x09\xf6\x44\x63\xb6\x55\x17\xb6\x7b\x15\xdc\x3f\x28\xad\x9a\x9b\x2d\x29\x46\x8d\xe2\xc6\x3e\x62\x00\x4b\x6a\x3f\xd0\xc5\xc2\xe2\xaa\xa6\xcf\xa1\x5e\x4f\xaa\xfa\x1e\x2c\x71\x3e\x98\xd3\xfd\x25\xca\xb9\xe5\x17\x03\x59\xc8\x36\x51\x52\xb4\x74\x27\x6e\xd0\x03\x7c\xdf\x77\x18\x28\xe2\xfb\x7c\xce\xc4\x89\x5f\x21\xad\xcc\x5b\x68\x87\xc8\x6e\x51\xad\x05\xf2\x55\xf6\xe9\xda\xd2\xc4\x1f\x56\xb9\x8b\x7b\xbb\xf9\xfc\xb6\xba\x8c\xad\xfd\x38\xad\x8c\x62\xf9\x2d\xd8\x77\x40\xfa\x1e\x1b\xd1\x70\xc0\x0b\x20\x49\xc5\x13\x0f\xe7\x33\xf1\x6b\x1f\x2c\x7f\x00\xb2\xef\x97\xb3\xa9\x54\x58\xc5\x3f\x19\x9d\x46\x53\x36\xd5\xff\x59\x77\x80\x6e\x1a\xfd\xe3\xea\xa2\x46\xd8\x5c\xab\xf7\xe1\x23\x48\x1e\x23\x92\x99\x76\xed\x19\xc4\x0e\x29\xff\x33\xd8\x0e\x7d\xea\xb1\x92\x71\xde\xcd\x5e\xe0\x61\x72\xb0\xb0\xa1\x39\xbd\x62\xa2\xe7\xc8\x3a\x8a\x65\x60\x1d\x0a\x05\xd6\x1a\xf9\xc6\x03\x2d\xf5\x80\x01\xd4\x73\xe2\x0d\xd6\xc6\xaf\xd7\x8d\xdb\xd7\xcd\x17\x8e\x9c\x27\x1e\x05\x72\xf8\x59\x82\x82\x3c\xe6\xc4\x02\x93\x0c\xf8\x0f\x5e\x0c\x7c\xda\x85\x12\x2a\x76\xd1\xce\x02\x1b\x1e\x3d\xe2\x55\x6d\x1b\x45\xac\x7b\x01\xb5\x9c\xad\xa2\x52\x91\xd6\x38\xa5\x2a\x5e\x7d\xbc\xdd\xf9\x6b\xb1\x77\x4a\xb0\xb0\x77\xe4\xb3\xda\x5a\x95\x8f\xe1\x1d\xee\x4a\x02\xe6\x9b\x91\x8d\xdb\xfa\x1c\x5b\x3b\x7d\xca\x9f\x87\x84\xbb\x6b\x0b\x9d\x5a\x7f\xee\x74\xbb\x03\x74\x7f\x61\xc2\xb2\xf1\xb4\x92\x45\x2d\x3b\x56\x0b\x48\xd3\x9d\x87\x21\xe9\x83\x75\x25\x56\xd4\x4d\xa6\xb0\x28\xd9\xae\xf8\xbf\xf9\xaa\x37\x9c\x8e\x2b\x0a\x63\x6d\x74\x88\x60\xab\xd8\xe6\x4f\xc8\xe9\x65\x20\xa3\x4a\x27\xf7\x67\xaa\x97\xa8\xf7\x7b\x60\x95\x21\x8e\xad"}, -{{0x73,0x87,0x2b,0x14,0x76,0x2f,0x68,0xda,0xe4,0xfc,0x10,0xdf,0xd6,0xf4,0x2d,0x3f,0x96,0x22,0xbf,0x2a,0xfe,0x6b,0x34,0xa9,0x56,0x49,0xaa,0x38,0x74,0x24,0xee,0x6c,},{0xdf,0xab,0x2c,0xe1,0xab,0x99,0x81,0xaa,0x7c,0xbf,0x32,0x07,0x35,0x00,0x07,0xfa,0x6c,0xe6,0xca,0x60,0xa2,0xed,0x7b,0x59,0x0f,0x3c,0x2f,0x62,0x92,0x2d,0x8f,0x61,},{0x85,0x25,0xc3,0x46,0xca,0x3a,0x6a,0x6c,0x5f,0x65,0xc4,0x17,0x78,0x59,0x93,0x77,0x65,0x98,0x70,0xcb,0x6d,0xf9,0xa4,0xa0,0xe5,0x5b,0x40,0xc3,0x5b,0xeb,0xa5,0x5c,0x8e,0x00,0x9e,0x56,0x00,0xb6,0x44,0x7d,0xc7,0x40,0x2b,0xa2,0x77,0x49,0x29,0x7e,0x8f,0x95,0x28,0x69,0x18,0x56,0xf7,0x2d,0x2a,0xd7,0x61,0xed,0x1b,0xc1,0x53,0x09,},"\x43\x3d\x71\x78\x1c\xea\xb2\xb4\x7d\x82\x6e\x67\xd3\x9f\x9b\x80\xd2\xff\xd7\x25\xf8\xc5\xae\xb4\x0c\xbe\x4f\x9b\x5f\x48\xef\x93\x52\x1c\xce\xc6\x04\x36\x0b\x96\x47\x32\x31\x90\xbf\xef\x75\xac\x93\x15\x62\xd2\x7f\x4a\x4e\x31\xf4\x6e\x57\xbc\x99\xfa\x51\x58\xc8\x2e\x12\xb7\x37\xe4\x5c\x5d\xe9\xf7\xdd\x7c\x86\x22\xd4\xa7\xea\xad\xf7\x20\x2f\xb4\x9d\x81\x9c\x9a\xd2\x4f\x88\x07\x31\x3c\x5f\x37\xdc\x20\x45\x3b\xdf\x05\xc9\xbf\x1a\x3c\x21\x17\xc9\x3e\x7f\x3c\xc8\xa2\x54\x20\x98\xe8\xfc\x1c\x64\x2f\xa4\x7b\x05\x54\x36\x57\xb8\x5f\x48\x0b\xc8\x6e\xc4\x28\x00\xbb\x14\x22\x35\x9c\x7c\x3e\x8f\xf4\xbe\x59\x8b\xd5\x4f\x1d\xc5\x86\xac\xae\x45\xa4\x74\x06\x22\xb9\x62\x74\x2b\xc8\x6e\x17\xcf\xa6\x3e\x77\x53\x54\xe7\x70\x7e\x50\x79\x58\x9e\x8d\x10\x8b\x1f\x11\xda\xce\x05\x75\xcb\x9a\x6d\x26\xb5\x9f\xce\x98\x14\x65\xd9\xbc\x34\x4e\xa6\x94\x5a\x95\xb8\x62\x79\x63\x84\xfa\x81\x70\x56\x08\x57\x45\x7b\xef\xf9\x5a\x9b\x5a\xc3\xd6\xad\x28\x2d\x44\x92\x9a\x30\x30\x26\xb4\xbb\xed\xd6\x0e\x2e\xf0\x55\xa3\x1f\x52\xd7\xce\x8d\xf2\xca\x5d\x18\x51\xc5\xb1\x67\xdb\x08\x09\x25\x9b\xb8\x12\x56\x90\x74\x10\x5c\x73\x4c\x85\xd6\x23\x12\x73\x75\x5f\x3a\x8b\x56\xdc\x50\x8d\xb5\xc2\x3d\xac\xb7\xa0\x61\x67\xbd\xa5\x1b\xc0\x13\x50\xf0\x16\xcd\x41\xb2\x1e\x8c\xc5\xbc\x93\x34\x3a\x9b\xb6\xea\x47\x38\xc5\xc8\x4b\x78\xfa\x96\x3c\x41\x0e\x43\x3d\xc5\x98\x19\x6c\x22\xe5\xb7\x91\xe1\x2a\x4b\x34\x3f\x7c\xd4\x7b\xbb\x0e\xb0\x78\x2b\xdb\x1a\x4e\x46\x68\x46\xa0\x30\x52\x8e\xeb\x89\x05\x6f\x73\x25\x71\x93\xad\xaa\xbc\x1b\x22\x98\x62\x03\x48\x78\xc3\x25\x8a\x53\x25\x48\x76\x2e\x29\xec\xc0\x01\xab\xd9\x89\x64\x9d\xa5\xe1\x44\xcf\x35\xd4\x86\x99\xf2\x3b\xc4\x6c\x5b\x34\xe0\x4a\x53\xe7\x27\x24\xb2\xb0\xb8\x78\x98\x25\x75\xd6\x88\xe2\x3c\xbe\x3a\x34\x06\x7f\x49\x71\xe5\x55\x97\x2e\xc2\x90\x8a\xe5\xf0\x3e\x88\x31\xec\x67\x75\x5b\xe9\x56\x87\xce\x63\x72\x93\x9e\x1e\x2f\xb6\x95\x1e\xc9\xec\xf4\xbf\x7d\x15\x35\x43\x1e\x25\x9f\x29\xad\x43\x12\x22\xb5\x4b\x65\xaa\x7d\x07\xcf\xb5\xdf\x16\x2a\x87\xc4\xd0\x34\x81\xeb\x44\x1f\x22\x1d\x7f\x58\x62\x7a\x14\x16\x4e\x7f\x4c\x2e\x3a\x1d\x50\x7e\x89\x9d\x53\x58\xe0\x08\x29\xb0\x8c\xf3\xae\xcb\x8a\x75\xb2\xa3\x1c\x31\x85\xa5\x80\xe1\x2b\x13\xf0\x64\x28\x69\xff\xfb\x05\x67\x23\xe9\x61\xaa\xf6\xfe\xfe\x67\xb4\xa7\xc4\xc9\x3d\xb3\xfe\x1f\x61\xad\xcc\x76\x55\x69\xa9\x9c\x09\xa3\xc8\x24\xed\x4a\x98\xba\xbe\xae\x43\xef\xb1\xf3\x51\xba\x13\x0e\x22\xaa\x97\x81\x19\x86\xbe\x92\x3c\xc4\x18\x0a\x7c\x4b\x78\xbc\xc1\x40\xce\xc1\x55\x74\x65\x4a\xa6\xd6\x5a\x06\xb9\x7e\xcf\xa5\xf3\xa9\x35\x5f\x96\xe4\xee\xaa\x76\x89\x21\x7b\x66\x3f\xba\x4d\xab\x0d\x99\xb1\x9c\x8d\x8d\xbf\x47\xa1\x57\xe5\xd5\x96\x9a\x35\xef\x84\xdf\xf9\x56\x2e\xdd\x43\x4e\x73\xae\xe7\xd0\xd8\x92\xdd\xa7\x2a\x36\x2a\x22\xa7\xe9\xfa\x86\x34\xa5\x7e\xeb\xd1\xa9\x07\x48\x5c\xa8\x92\x1b\xdc\x19\xee\x9e\xe5\x88\xf3\x95\x68\x7d\x3f\xc8\xf8\xc2\x5f\x2e\x95\x76\xca\x60\x31\x3f\xbb\x2c\x26\x5a\x99\xf2\xcd\xd5\x57\x5b\x1d\xd5\x30\x60\x4e\x9a\xd6\x69\x5c\x9f\xb3\x59\x94\xa8\xb8\x7d\x5c\x85\x70\x54\x9a\x4d\x32\x9b\x9f\xe0\x87\x06\x9a\xb7\xeb\x0d\x71\x4a\x94\xe1\x92\x61\xf8\x6e\x44\x8f\x2d\xa9\xb1\xcb\x0c\x0d\xbe\x41\xd4\x4c\x3a\x82\x47\x83\xd1\xbd\xbd\x73\x26\x05\x1a\xeb\x10\xad\xab\x80\x5c\x5c\x59\xd0\xe8\x3b\x1c\x11\xa2\xfd\xd3\x5e\x44\x4a\x49\x9e\xd1\x5d\xaf\xd8\x38\x62\x77\x5f\x6c\xdf\xc6\x75\x95\x81\x84\x07\xbe\x55\xec\xbf\x7b\xf8\x6c\x73\x06\x9a\xac\xe5\x77\x62\x6a\x85\x63\x53\x6f\x60\x50\x42\xcf\x7c\xaa\xf6\xfc\x8e\x3b\x54\x5b\x77\x41\x4d\xf8\xd9\xf6\x49\xb9\x9e\xe4\x25\x41\xda\x38\xc3\xaa\xe6\x27\x20\x78\x45\xb8\xf4\x14\xa8\x07\x4d\x70\x86\x8a\x5c\x0b\x07\xb0\x70\xc3\xc6\x53\xbe\x04\x07\x6b\x83\xca\xd7\xb0\x30\x5d\x95\x00\xaa\x44\x45\x5c\xb8\x60\xdc\xc7\x64\x00\xaf\x93\xc3\xd2\xef\xb4\x2a\xe0\x56\xf1\x42\x8b\x65\xf1\x22\xe1\xc7\xb9\x58\x4d\x81\x4d\x50\xac\x72\xef\xdb"}, -{{0x67,0xcf,0x27,0x15,0x52,0x87,0xbe,0x6b,0xfa,0xb6,0x62,0x15,0xe0,0x17,0xc3,0x46,0x63,0x22,0xf2,0x1e,0x6e,0xb1,0x40,0xbe,0x4f,0x1b,0xde,0xcf,0x55,0xab,0xfd,0xc1,},{0xd0,0x70,0xaa,0xb2,0x95,0xa8,0xaf,0x93,0x57,0x27,0xc3,0xbe,0x44,0x2b,0x25,0x1d,0xb9,0xe7,0x74,0xd2,0xf4,0x4b,0x3c,0x24,0x24,0xc5,0x2f,0xc8,0x96,0x56,0xe1,0x69,},{0xc9,0x34,0xa3,0xa1,0xaa,0xab,0x78,0xd9,0x26,0x9d,0x1e,0x9d,0x13,0x39,0x2f,0x72,0xc6,0x37,0xbc,0x5d,0xe5,0x4f,0x04,0x69,0x1e,0xfc,0x29,0xd4,0x73,0xb4,0x75,0x02,0x5d,0x8d,0x8f,0xe3,0xc5,0x23,0xd2,0xd2,0x9c,0x41,0xc5,0xf3,0xde,0xc6,0xca,0x38,0xce,0x6d,0x68,0xd7,0xff,0x09,0xb6,0x13,0x5b,0xa2,0x4d,0x0d,0x32,0xcc,0x15,0x02,},"\x0f\xf0\x52\x97\x03\x1c\x89\x27\x74\xcb\x2c\x01\xe8\xca\x60\xdd\xd0\xce\xac\xc0\xb8\xd5\x91\xa8\x91\xe3\x3b\x19\xe1\xbe\x9e\x36\x3b\xc6\x42\x0d\x6f\x52\x9f\x04\x84\x0b\x3b\x08\x85\x3c\x83\x5a\x03\xe0\x36\x97\x8b\x04\xa4\xf9\xec\x6b\xe4\xae\xf3\x31\x95\x61\x90\x99\x6d\xea\x27\x26\x19\xf1\x68\x6d\x33\xbe\xf0\x3d\xbc\x08\x5a\x92\x3a\x0f\x11\x5b\x78\xf6\x53\xfe\xeb\x60\xbb\x9e\x45\xf3\x4f\xb8\xbe\x5a\x4c\xbb\x64\x8c\x7d\x29\x95\x6f\x0d\x0e\x96\xbd\xd3\xc8\xd0\x64\x97\x20\x62\x4c\xbc\x20\x79\xe8\x4f\xd6\xd0\x10\x24\x11\x24\x09\x84\x59\xf1\x2a\xf2\x99\x1d\x38\x28\x77\x0f\x50\xb1\x04\xea\x6e\x5f\x51\xfd\xad\x30\xa9\xb8\x07\x9d\x21\x59\xe4\x6d\x64\xaf\x91\xd0\x7c\x10\xed\x19\x81\x4d\xf2\xaf\xe6\x60\xd7\xd8\xf2\x40\x35\x34\xe9\x2c\x62\xe1\xea\x6d\x68\x82\x03\xbc\xa3\xd9\x7c\x2a\xfd\xa8\x3b\x25\x55\x20\xff\xe9\x2a\x33\x62\x57\x72\x51\x3b\x1f\xe3\x4f\xaf\xe3\x2b\x6a\x9b\x8c\xf9\x94\xdf\x7e\x63\x4e\x68\x65\x91\xe5\xf0\x07\x3a\xba\xbc\x64\xa8\x92\x10\xba\x53\xa4\x99\x1c\x11\x55\x7e\x03\x34\xe6\xc6\xa5\x03\x6c\x64\x2a\x31\x8f\x22\x95\x11\x71\x39\x08\x5f\xb3\x40\x75\x64\x70\x06\x75\x8e\x32\xbc\x00\xad\x10\x9f\xe8\x03\xf7\xee\x9f\x5e\xc2\xaf\x4d\x25\xc3\x07\x0a\xbc\x51\xcf\x4d\x78\xe1\x3a\x7c\xe2\x83\xd4\xfb\x4e\xb4\x1d\x3e\x8c\xe9\x02\x38\x50\x0a\xe0\xce\xda\x32\x0e\xc5\x92\x2e\xfa\x10\xb9\x03\x74\x8e\x1e\x85\x3a\x37\x29\xd2\x4c\x10\x54\x39\xdf\x2f\x70\x00\x12\x3d\xb9\xb2\xc0\x15\x33\xbb\xf0\xd0\x28\xeb\xb2\xfc\x00\xdc\xe3\x8a\xd0\x63\x28\xee\x9e\xcd\x84\x9a\x6e\xfc\x3a\xe8\x84\xef\x69\x33\xcf\xeb\xed\x05\x5b\xb2\x96\x8a\x0b\x06\x76\xb5\x72\x92\x16\x17\x8c\x75\x19\xef\x07\x88\x59\x3f\xc0\xdc\xff\x50\xd7\xe0\xb1\xeb\xb3\xcf\x49\xbb\xd1\xbf\xa5\xc3\x0e\xa7\xb8\x8c\x36\xe1\xa1\x59\x3a\xef\x0b\xb3\xf9\xe2\x09\x1c\x85\x89\xf7\x41\x4b\xee\xd8\xdf\x46\x6a\x2e\xd8\x7b\x2c\xb5\xf3\x5f\x1d\x31\x24\x6c\xeb\x96\x86\x09\x25\x36\x15\xd7\x80\x43\x51\x73\x79\xee\x69\x74\xa6\x69\xcb\x48\xda\x6a\xc2\xf9\x6d\x70\x0b\x7e\x44\xa4\x35\xcf\xef\xec\x40\x2a\x1e\x31\x10\xe7\x69\x81\x92\x4f\x26\x01\xc0\x1d\xc0\x35\x46\xfd\x4f\x51\x16\x49\x30\x2f\x06\x33\xdf\xbd\x25\x65\x1c\x5a\x59\x9c\x90\x95\x44\x89\xc7\x6a\x65\xec\x05\xa7\xe4\xcc\x74\x61\x6c\xe2\x56\x01\xcc\x37\xb8\x04\xe1\xf0\xbc\xc8\x65\x10\x23\xb1\x2e\x13\x56\x84\x41\xe8\xb8\xef\x4c\x30\x5f\xcd\xad\x3d\x2b\x13\xfa\x08\x03\x24\xb2\xfd\x6b\x61\x99\x8c\xf8\x64\xb6\x58\xbc\x7f\xef\xcc\x48\xa5\xa7\x68\x1d\x7c\x86\x6c\x34\x2c\x7f\x5d\x6c\xf1\x08\x81\x52\x2c\xc7\x10\x25\x7d\x25\xa4\xc1\xe3\x52\xd2\x70\xe9\x02\x08\x2a\xb9\x54\x1d\x59\x00\xce\xff\xa0\x91\x4b\x16\xb5\x5e\x0d\xd3\x78\x6e\x98\xd4\x17\x20\x87\x5a\x14\x8e\xb4\xab\xdb\x01\x53\x85\x66\x79\xfb\x98\xc0\xec\x48\x5e\x5f\x45\x8d\x63\x5b\x78\x61\xa2\xb3\xa8\xba\x5e\xc2\xc1\x44\x4d\x35\x39\x80\x20\x0e\x5e\x07\x18\x08\x85\x4a\x26\x8c\xc7\x6c\x60\x5c\x94\xf3\x73\x29\xc3\x61\x87\xa4\x1f\xdd\xf9\x2a\xab\xdb\x49\x96\xa0\xe1\x0b\x31\x55\x26\xaf\xea\xc8\x0e\xb2\xfa\x32\xaf\x78\x6a\x34\x31\x6b\x36\x11\x1e\xe9\x35\x21\x08\x14\x4d\x70\xf7\xd1\x72\x3b\x32\xf4\xdb\xaa\x82\x20\x13\x53\x41\x1d\x65\x77\x13\xe5\x5e\x35\xdf\x78\x58\x0b\x1b\xc0\x86\x80\xf0\x15\x9f\xa1\x16\xfa\xf4\x63\x56\x6a\xaf\xe8\xae\xa6\x98\x57\xe7\x2e\x44\xac\x80\x9a\xc4\x3f\x5c\x45\x93\x9d\x85\xa1\xa5\xf4\xa3\x70\xa1\x89\x96\xc8\x51\x4a\x46\xf3\x43\x71\xef\x9e\x5f\xb2\x04\x42\x2c\x93\x4a\x1d\x29\x3d\x10\x1b\x8c\x16\xf9\x9c\xc0\x73\xea\x36\x6a\x13\xa4\x5c\x43\x7d\x62\x0d\x13\x2b\x74\x40\x9c\xbf\x8b\x9c\x07\x5b\x41\x63\xf7\x26\xaa\x67\xe5\x09\xa2\x48\x74\xfc\x1b\x1f\xb6\xfb\x7c\x73\x55\x15\x9c\x02\xaa\x13\xe6\x4b\xad\xf1\x50\x35\x6b\x18\x41\xb3\x21\xf8\x04\x1e\x13\xed\x77\xe8\x46\x1c\xfb\xb8\xe8\x28\x48\x8b\xf5\x17\xa5\xd2\x9f\xf8\x2e\x73\x67\x48\x0a\x8e\xdd\xde\xb5\x35\x0e\x7a\x83\x42\x3b\xd0\xb1\xc5\x5f\x7b\xb4\x24\xca\x04\xc2\x05\x72\x3c\xd5\x40\x56\x71\xe7\x33\xf3\x91\x60\x0a"}, -{{0x18,0xc2,0x1c,0x0d,0x0d,0xe1,0x3d,0x4c,0x64,0x49,0x7e,0xf0,0x26,0x0d,0x66,0xcf,0xd3,0x42,0x16,0x98,0x1a,0x1b,0x49,0x39,0x1a,0xe5,0xcb,0x0e,0x41,0x43,0x6e,0x9f,},{0xf7,0xd4,0xdd,0x1e,0x05,0x9c,0x36,0xf6,0xd1,0x21,0xc0,0xaf,0xfe,0xb2,0x1f,0x0c,0x57,0x2b,0x45,0x99,0x2f,0x84,0x94,0x8b,0x09,0xaa,0xfb,0xcd,0x86,0xbb,0x53,0x5c,},{0xc9,0xc0,0x99,0xe2,0x1d,0x09,0x5a,0xfa,0xdd,0x4e,0x71,0xc9,0xab,0xf6,0xb7,0x08,0x33,0x24,0x77,0x62,0x25,0xb5,0x87,0xb6,0x0a,0x0e,0x60,0x92,0xec,0xb3,0xd3,0x3c,0xff,0x39,0xc6,0x7d,0x34,0x77,0x6a,0xe9,0x9d,0xda,0x75,0x4a,0x3c,0x2b,0x3f,0x78,0x11,0x35,0xa3,0x8c,0x78,0xed,0x64,0x55,0xaa,0xf0,0xae,0x0c,0x31,0x3b,0x62,0x05,},"\x68\xab\xca\x7c\x16\x6a\xfe\x06\x3e\x47\x7b\x80\xe3\x7d\xb2\x24\xe1\xa2\x35\xde\x8f\xcd\xeb\x7f\x42\x7a\xf6\x7e\x00\x12\x47\xcc\x5e\x05\x71\x82\xfd\x9b\x6d\xb8\xba\xba\xa6\x58\xcf\x3b\x3f\xe4\xb0\x76\x3b\xf8\x8d\x67\x31\x1b\x11\x90\xbe\x83\x40\x18\xcf\x57\xa3\x32\x92\x24\x13\x76\x46\x20\xac\xe0\x54\x45\xee\x01\x9a\x06\xdf\xf9\x8b\x23\x89\x79\xad\x6d\x30\x90\x1b\xef\xa3\xc6\x4f\x6b\xd8\xc6\xeb\x09\x2c\x2e\x62\x84\x13\x88\xfd\x8c\x4e\x84\x19\xe2\x77\x89\x84\x89\x67\x37\xed\x90\xa2\xcd\xb2\x19\x96\xae\xf7\xc2\x16\x38\xd6\xcb\xe6\x80\x32\x2d\x08\x99\x65\x97\xa9\xe3\x03\xf6\xf5\xf4\x79\x40\xf8\xc5\xba\x5f\x5f\x76\x38\x3e\x7e\x18\x06\x4a\x3d\x2d\xff\x5f\xdf\x95\xe9\x0c\x5e\xb3\x0f\x4d\x8d\x45\x9e\xe1\xd5\x06\xa8\xcd\x29\xcd\xc6\x9b\x67\x54\x96\x3b\x84\xd6\x74\x94\xb3\x53\x05\xd1\x0d\x12\xb9\x48\x74\x17\xb2\xce\x28\xad\xcb\x10\xb6\x5c\xc9\x31\xfb\x33\x81\xae\x02\xe7\xaf\x79\xa0\x2b\xf9\x9e\x25\x8a\x56\x36\x10\x90\xe0\xb7\x12\x22\xb3\xac\x60\xbf\x2f\xb7\xba\x83\x2d\x03\x4f\x5b\x6b\xc6\xfa\x66\x3a\xe7\x41\xf7\x6d\x97\xc1\xac\x32\xbc\xb7\x41\x15\x07\xd5\x18\xd2\xf6\x05\x4b\x57\x83\x28\xc5\xf6\x7f\x75\x8a\xc0\x1b\xfe\x6f\x4d\x35\x90\x0f\x50\xa5\xdc\xd3\x0d\x2f\x92\x61\xb6\xbb\xec\x4c\x1d\x1f\xc1\x8d\x2a\x7e\x70\xc4\xd3\x6c\x21\xfa\xf8\xcf\x94\xa5\x87\xc3\xa0\xd1\xa9\xcd\xe7\x83\x1a\xe6\x26\x77\x54\x68\xdd\xcd\x40\xa8\xba\x18\xf4\x2b\x34\x18\x8d\xe5\x74\x1e\x1b\xe8\x30\x7b\x10\x84\x58\x65\x15\xec\x01\x5e\x4e\x37\x1d\x29\x44\x3a\x40\xb0\xc0\x69\xc6\x41\xd8\xce\xe5\xe4\x61\x18\x62\x98\x7c\x3e\x35\x6b\x12\x93\xb0\x51\x8b\x4a\x4c\x8e\xa9\x7f\xc5\xa4\xdb\x1f\x01\x29\xab\xee\x72\xfb\x80\x92\xea\x35\xc2\xda\xb6\x75\x73\x85\x02\x07\xb8\xe8\x27\x18\x99\x9a\xd9\x9c\x4c\x83\x9e\xac\x14\x63\x6b\xd5\xe4\xd8\x43\x6a\x27\x0d\xd9\x0b\x8e\x32\x13\x02\xe5\x2a\x92\xd8\x91\xff\x18\x91\x54\x2a\xe2\xca\xa0\xd6\x6e\x0f\x66\x1e\xae\x37\xb2\x5b\x08\xbb\x2e\x0e\xee\xc4\x83\x80\x09\x77\x8c\xd5\x25\x98\x43\x80\x98\x3b\x2b\xaa\xdd\x71\x02\xa1\xe3\x56\x73\x4e\x41\xd7\x61\x83\x82\x9e\xa9\xab\x82\x44\xc3\x36\x59\x7c\xa2\xd6\x79\x88\xf2\x81\x43\x84\x67\xe4\x53\xf5\x62\xc6\x7b\x22\xd0\xa4\xdd\x9f\xcb\x46\xa5\xf8\x0d\x29\x9d\xb5\xf0\x1f\x59\x16\x0a\x19\xd7\x4c\x64\x4f\xa5\xa9\x40\xe3\x2c\x9d\x8d\x98\x3b\xab\x7e\xfb\x0d\x7c\x7d\xa4\xe3\xfd\xa1\xcd\x0d\x18\xa4\x55\x8e\xb9\xfe\x46\x40\x8a\xab\x50\x85\x91\x2b\xf2\xf4\x6a\xb6\x3a\x93\x54\xf9\x02\x7c\x93\x69\x12\x23\xff\xaa\xb8\x46\x3b\xac\x4c\x4b\xc3\xb1\x1a\xbc\x46\xba\x68\x71\x7c\x91\x78\x0d\x3f\x30\x47\x0d\xbd\xd8\x8b\x37\x80\xa1\x94\xc8\xa4\x0a\x2c\x0a\x81\xa4\xd5\x6d\xec\x2d\x89\x62\xc3\x4d\x2a\xb7\x33\x69\x02\x8e\x1b\xfe\xaa\x6b\xb5\x82\x41\xff\x4f\x89\x8f\x80\xad\x3b\xb1\xc6\x91\xb8\x64\x7f\x2c\x69\x83\x95\x4c\x1c\x77\x95\x74\x58\xee\xbf\x1c\x50\x55\xc3\x16\x93\xab\xce\xd0\x53\x84\x73\x5a\x4f\x74\x19\x68\xbd\x6a\xc3\x15\x65\xcf\xee\x71\xc8\x84\xc1\xe2\x9e\x9e\x7a\xe0\xf7\xec\xd0\x4d\x46\x3b\x1d\xc3\x89\xc3\x60\x37\xe8\x14\x58\xdc\xec\x61\xd0\x76\x40\x32\xdd\x58\x9b\x92\xaf\xda\x2f\xc9\x02\x8f\x41\xab\x53\xcc\xa2\xd0\x4e\xc6\xa9\x56\x59\x55\xcb\xcf\x1a\x34\x63\x98\x9c\x71\x39\xbb\x90\x2a\x59\x21\xe8\xb2\xc9\x9c\x48\xe1\x37\x11\xf0\xbc\xc3\x99\x25\x95\x16\xc8\x1a\xe9\x42\xa6\x79\xd4\xba\x33\x97\x9e\xb1\x2f\xcd\x28\x60\x60\x2e\x47\x24\xb1\x33\x0f\x1c\xd2\x57\xb5\xb2\x89\x1d\xae\xe8\xef\x4c\x92\xfc\x3b\xfd\xb3\x4e\x53\x2d\x58\x70\xf3\x80\x59\x86\xac\x97\xb5\x03\xfd\x85\x87\x35\x48\xe3\x09\x50\x00\x0f\x8a\x70\xbe\x51\xfa\x75\x76\x03\x50\x1f\x2d\x30\xe8\x52\xef\xea\xc4\x82\x68\x62\xae\xd7\xf6\xd2\x0c\x9a\x8c\x8d\xbe\x36\x2d\xfe\xe4\x18\x93\xf2\x7e\x6f\xd5\xe9\x1d\x0e\x7e\x3d\x4f\xd8\x15\x5f\x44\xfd\x8e\xf1\x7a\xf1\x4a\x84\x8d\x44\xa8\x76\x31\xae\xee\x75\x14\x62\xb2\xa5\x40\x87\x06\x8d\xae\xab\x3e\xa3\x28\x9e\xce\x62\x12\xb3\xb5\x2c\xe7\xa8\x88\x6d\xf2\xa7\x27\xb7\x2a\x57\x0c\x2f\xb9\xc5\x03\x41"}, -{{0xdb,0x9a,0xae,0xe1,0x98,0xcd,0x26,0xa5,0x2b,0x11,0x81,0xfa,0x3f,0xd9,0x2a,0xbe,0x42,0x5e,0x66,0x6d,0x89,0x0b,0xf9,0x69,0x46,0x7d,0xd2,0xce,0x28,0x0e,0xd4,0xa7,},{0x3c,0x89,0x7c,0xaf,0xe2,0xb4,0x99,0xec,0xb2,0xe1,0xdd,0x01,0xea,0x55,0xf3,0xfc,0x88,0xf6,0x8c,0x25,0xb6,0x4a,0x63,0x6b,0x31,0xa1,0xfd,0x1c,0x78,0xf3,0x7f,0x3f,},{0xb2,0xe3,0xd9,0xc5,0xd0,0xff,0x32,0x99,0x96,0xbc,0x89,0xd2,0x6f,0xb3,0xac,0x12,0x6b,0xde,0xd3,0x13,0xcb,0xf8,0xdf,0x86,0x71,0x86,0x38,0xc1,0x99,0xe0,0x57,0x27,0x3d,0x09,0xeb,0x16,0x3c,0x6c,0x18,0x1f,0xd8,0xbc,0xe5,0x1f,0x72,0xd4,0xd9,0xd2,0xe8,0x4a,0xbb,0xe0,0x83,0x30,0x77,0x3b,0x9f,0xcc,0x21,0x66,0xf1,0x40,0xd6,0x0e,},"\x47\xfb\x62\x15\x61\xf8\xb7\xee\xce\xc6\x03\x3f\x2b\xcb\x6f\x43\xac\x68\xc9\x58\xdf\xd2\x65\x6f\x52\xa0\xc2\x9b\x4a\xcd\x44\xf4\x30\x4c\x6b\xf7\x7e\xea\xa0\xc5\xf6\xd3\xb2\x2d\xb1\x96\x99\xc3\xdc\xde\xde\x69\x8a\xbd\xe6\x23\xec\x4b\x2b\x90\x91\x0c\x80\xac\x3a\xf3\x9c\x55\x0b\x6d\xd4\x09\xe6\x3d\x77\x70\x66\x55\xa9\x19\x9c\xb5\xc0\x25\x8f\x5b\xa3\x82\x85\xff\xdc\x64\xb8\xa8\xf3\x73\xd1\xfb\x29\xba\x87\xf8\x4d\xdf\x5f\x34\xd8\xf1\x40\xbb\xc1\x7b\x39\x61\x68\x2d\xf5\xd0\xa8\xf9\x10\x2e\x37\x9a\x99\x98\x13\x9d\xfe\x40\xab\x8c\xe7\x53\xbf\x56\x26\x10\x82\x37\x77\x1a\x7d\x8e\x10\x9e\x9e\x0a\xfe\x9b\x66\xd0\x42\x09\x42\xe1\x63\xa4\xf3\xc0\x3f\x71\x81\x3e\xe0\x78\xbd\x09\x0a\xc3\xd0\x77\x2e\x26\x22\xc2\x59\xe6\x82\x55\x2c\x75\xb0\x8d\xd0\x55\xa4\xa5\xeb\x5e\x60\x94\x40\xbc\xd3\xf3\xa6\xfe\xb8\x76\xfd\x16\x92\x15\x20\xc6\xcb\x68\x84\x71\x0d\x2e\x15\xcd\xad\x6d\xaa\xee\xd9\x59\x62\xdd\xa2\x1c\x67\x88\xf7\x84\x91\x79\x17\x98\x2e\x1c\xcb\xb5\xfd\xd9\xbd\xc1\x76\x9d\xb6\xb6\xdb\x57\xca\x35\x4e\x01\xa1\x33\x9d\x8e\x77\xe9\xdb\xbb\x58\x12\xfb\xab\x6a\x14\xc5\x40\x85\xc0\x65\x95\x99\xf1\x50\xe2\x24\x72\x47\x0f\x1e\x5e\x67\x2c\x42\x5f\x37\x5f\x9e\x0d\x6e\x8d\x52\xfa\x17\xb7\xa8\xd7\xa4\xd7\xca\x3e\x12\xf4\xdb\x53\x83\x6a\xed\x2b\xeb\xd7\x45\x89\xba\xca\x8c\xe9\x10\x02\x91\xbf\xb7\xe4\x56\xdb\x7f\x2f\x0a\x84\xdc\x0a\x74\x88\x85\x13\x66\xa9\xa5\xfe\xa0\xe3\xef\xc7\x4b\x9c\xdd\x4b\xd9\x7b\x65\xab\xf3\x61\x39\x3c\xe1\x70\x3d\x85\x71\x80\x5e\xe6\x8a\x13\xd3\x65\x4f\x03\xdc\xec\xfb\x77\xa5\x34\x30\xd0\x94\x96\xad\x73\xec\x01\x75\x99\x57\xe5\x10\x46\xaa\x73\x96\xf5\x92\x33\x86\x50\x11\x7a\xc7\xb4\xdd\x35\x73\xeb\x53\xd9\xc9\xf9\xdf\xa6\x2e\x23\x69\xc7\x7a\xf9\xc0\xd4\x2f\x61\xba\xe7\x4b\x28\x7d\xdf\xa2\x7b\x7f\x1c\x1b\xe9\x88\x3a\x04\x46\x91\xd5\x6d\xc1\x37\x34\xad\x4e\xe3\xa3\x2a\x9f\x40\xe3\x28\xc5\x00\xd0\xfe\xd8\xea\x05\x10\xe9\x38\xf2\x75\x80\x04\x02\x2b\xca\xa6\x90\x2b\xda\x10\x14\xb8\xae\x33\x65\x27\x28\x29\xed\x94\xfa\xba\x63\xcb\x14\xa3\x6c\xf8\x13\x90\xec\xa8\x3f\xc1\xc6\x27\x17\x20\x13\x26\x1b\x39\x93\x77\x9a\xa0\x76\xa5\xc5\xd8\x1d\x90\xd2\x70\x62\xe1\xa6\xd9\x0b\x5c\xf1\x00\x5c\x70\x19\x17\xb7\xad\xac\x18\x0c\xb7\x5b\xbc\xe0\xf2\x7f\x2f\x18\x0e\x2c\xb9\x01\x40\xc1\x4c\xc6\x00\x9d\x2d\x41\xaa\xb1\xdb\x94\x18\xf9\x1d\x4c\xf3\x94\x00\x2c\xd7\x0a\xc9\xdc\x11\xce\x86\x53\x47\xfa\x3f\x56\xf8\x7c\x14\x9e\x2b\x17\xd2\xc7\x2b\x66\x3a\x58\xe3\x18\x7b\xb1\x9b\x9b\xac\x2d\x11\x48\x3b\xa1\x2f\x77\x0a\xc0\x4d\xc4\x6d\x38\x85\x18\xfa\x54\xdc\x15\x2e\x9a\x9d\xfb\xff\x14\xf1\x4c\x61\xcb\x37\x58\x97\xe3\x0c\x53\xe6\xde\x42\xd5\xe1\x40\x1d\xae\x1b\x22\xba\xaa\x0e\x8a\x41\xc6\xaf\x9d\x0e\x0b\x13\xa9\x1a\x23\xd9\xb7\xd5\x55\x20\x47\x02\x9a\x35\x21\x94\x6c\x71\x20\xd3\xd2\x58\xb3\xae\xfc\xf7\x54\xd1\x95\x94\x87\xa1\xfe\x77\x43\xac\x7e\x1c\xc8\x9e\x36\x8b\x19\x78\x09\xc3\xa2\x73\x17\xe0\xec\x48\xd5\x46\xdb\x1e\x21\xeb\x62\x9a\x29\xbc\x62\x47\xcd\xd4\xa1\x37\x14\x37\x56\x3e\xdd\x12\xfa\xea\x2c\x5c\xb7\x7e\xed\xed\xbf\xc5\x80\x08\xfa\xd1\xf6\x5a\xf3\x58\x43\xfa\x27\x4c\x73\x4e\x3f\xbb\xaa\x9c\xc5\x0d\x68\x37\x48\xb7\x5a\x48\x5f\x94\xd6\x30\xb0\x32\xa5\xf1\x06\x7d\x1d\xeb\x30\xe9\xd2\x21\x8c\x93\x5c\x98\x1d\x01\xc0\xc5\x47\xfd\x68\x41\x31\x36\xed\xf4\xc0\xc7\x70\x28\x6e\x82\x34\x42\xe1\xc5\x13\x65\x19\x29\x21\x3c\x12\x1c\x1d\xe7\x00\x98\x91\x41\xab\x4a\xf3\xb3\xfe\x74\x04\xb4\xd2\xa3\x8c\x53\x0b\xaf\xb4\x98\xe6\x49\x53\xce\x1c\x0f\xb7\xd3\x40\xe2\x11\x35\xbf\x8a\xfd\xd8\xdd\x65\xb1\xb1\x8c\xf1\xc8\xfb\x9f\x40\x2b\x26\x70\x40\x0b\x86\xdd\xaf\xb1\x84\xcc\x51\xd5\xfd\xa2\x73\xb8\x0c\x26\x52\x1f\x91\x2f\x35\x83\xb4\xae\x30\x1d\xae\x15\x1c\xb5\x5c\x75\x70\x3a\xad\xef\x03\x24\x15\x22\x7d\x53\xe3\x95\xdb\x6c\x15\x0a\x1e\xe8\x39\xad\x26\xba\xe5\x52\xe1\xab\x73\x62\x14\xdc\x04\xb0\xf3\xc4\x1b\x7c\xfb\xd0\x49\x68\x1b\xc8\x4c\x3d\x16\x53\x07\x68"}, -{{0xa8,0x04,0xc3,0x3b,0x4d,0x38,0xcb,0x3c,0xe3,0x1c,0xf3,0xba,0xc1,0x04,0x9e,0x0d,0x4e,0xc6,0x3a,0x1a,0x0b,0x7b,0x59,0xfd,0x8a,0x36,0xee,0x37,0x54,0x16,0x56,0xaa,},{0x60,0x72,0x25,0x6d,0x65,0x74,0xa2,0x93,0xbd,0x7c,0x22,0x1c,0x55,0x1c,0x32,0xcf,0x2f,0x77,0x15,0xe1,0x9e,0x43,0x3a,0x49,0xd9,0xb8,0xb0,0x49,0x0e,0x56,0xef,0x62,},{0xb1,0xb4,0x4a,0x14,0x2a,0x7c,0x4c,0x3d,0x0b,0xf4,0x66,0x1e,0xda,0xc5,0xb7,0x67,0x00,0x57,0x26,0xc1,0x4a,0x27,0x69,0xb7,0xc2,0x14,0xfb,0x58,0x73,0x7e,0xc2,0xe4,0xbc,0x51,0xc3,0xa1,0x95,0xd2,0xba,0x1b,0x74,0xa5,0x4e,0xff,0x4c,0x33,0xa9,0x0f,0x41,0xcc,0xde,0xfa,0x9e,0x93,0x65,0xfd,0xe8,0xdd,0x85,0x9f,0xd3,0x97,0x8c,0x0a,},"\xdb\xfe\x30\x7f\x2a\xae\x9e\x07\xec\x7c\x4b\x68\x21\x06\xd2\xc9\x36\x7b\x0c\x4a\xaa\x58\xae\x80\x4e\x0a\x39\x04\x75\x4e\x6c\xf8\xfe\xe7\x3c\xf9\xe2\xd4\x5d\x02\x89\xe5\x07\x82\x93\xdf\xc4\x69\xd4\x6e\xa6\x70\x26\xc5\xaa\x69\x2d\x2f\x2c\x9f\xb4\xec\x57\xcd\xab\x4c\x04\x3f\xf9\xae\x61\x85\xf2\x7a\x70\x44\x54\xe5\xf5\x39\x50\xaa\xbd\x25\xc9\x91\x04\x74\xd4\x5a\xf8\x83\x68\x62\x72\x3e\x0e\x6a\x27\x82\x3d\x82\xbc\xbb\x68\xa9\x60\x52\x42\x2a\x18\x19\x51\x2e\x3b\x43\x40\x8c\xf4\x89\x57\xad\x6a\xe2\x35\xb7\x23\x3d\xf1\x82\x84\x74\x91\x53\xdf\xa5\x7d\xe3\x50\x74\xa3\x0e\xdf\xab\x8a\x56\xdf\x28\xab\x2e\x29\x40\x30\x6c\x22\x1a\xa5\x54\x90\xcc\x66\x4e\x14\x68\x3f\x30\xee\x61\x5e\x2d\x93\xfd\xf9\x71\xf5\x96\x66\x34\x65\x84\x3b\x3a\xdd\x63\x92\xba\x33\x90\x31\x1e\xf8\xdc\x59\xf2\x51\x44\x5d\x66\x9e\x10\xa0\x06\x19\x91\xe1\x13\x56\x19\x23\xaa\x21\x52\x44\x46\x3d\x82\x64\x19\x9a\xc5\x88\x92\x4e\x23\x1e\x84\x19\xd8\x68\x5f\x33\x8e\x59\x9b\x5f\x40\xbf\x9b\xd1\xae\xce\x77\x25\x35\xbb\xbc\xb8\xf6\x88\x1c\x2e\x80\x04\x91\xab\x3b\x57\xb4\x4b\x8a\xe4\x3a\xeb\x5c\x4a\xe5\xe7\xed\xeb\x22\x8f\xed\xc9\xf6\xb9\xca\xde\xa1\x76\xe1\x34\x93\x6d\xed\x60\xaf\x1c\x22\x87\x34\xfb\x00\x57\x0f\x23\x74\xbb\xbf\xa1\xbb\x17\x07\x85\x80\x5d\x6b\x6c\x70\x1e\x82\x09\x52\xea\xe4\x5b\x8c\x23\x66\x11\x3a\x1d\xfb\x2e\x35\x85\x2a\xf4\x19\xb7\x54\xf9\xcf\x7a\x08\x1c\x3d\xde\x6c\x80\x53\xbf\x1c\xe0\xc8\x53\x39\xd5\x69\x9c\x42\x24\x76\xfc\x21\xf2\x6c\xe7\x5d\x2a\x7f\xed\x09\xfc\x0f\x41\x75\x78\x98\x47\xd8\x76\xc5\x1a\xa4\xe0\xbf\x7c\xe8\x42\xb8\x30\x8d\xc7\xa2\x8c\x82\x39\x52\x07\x14\xdc\x23\x31\x36\xe0\x9f\x55\x7c\x7e\xf3\xe0\xf8\x3b\xad\x63\xcb\x28\xac\x61\x6d\x39\x28\xf3\x83\x7d\xce\x1d\xd5\x8a\xcb\x8d\xdb\xc7\x2e\x82\x2d\xee\xe4\x5f\x00\x77\x6a\xcc\x88\xe0\x0c\xd3\xa9\xdb\x48\x6d\x92\xd5\x35\xa5\x7a\x0f\xdc\x4f\x90\x3b\x62\xe5\x17\x22\x1c\x30\x8c\xba\x2e\x30\xff\xe7\xb9\x19\x37\xa9\x94\x17\x72\x1f\x56\xfe\x6d\xf4\x48\x40\xe9\xe4\x11\x36\x92\x9c\x0c\xa3\xdc\x28\xdd\xf2\x37\x9e\x4d\xcf\xde\x83\x72\x3e\x2d\x4c\x9e\x23\x29\x9c\x05\x6a\xfb\x31\xd3\xe7\x0d\x08\x5d\x0a\x31\x2c\x5c\xd5\x70\xb6\x99\xde\xa8\x71\x74\x58\x53\x13\x48\xc9\x6f\x6e\xb5\x2d\x7e\xe6\x1d\x56\x60\xf6\x5e\x90\x9a\x14\xce\x10\x33\xdc\x85\x3f\x2f\x25\xd0\x9c\xf4\xe4\x0d\x07\xef\xf7\x2e\x15\xa3\x90\x56\x4a\x2b\xe3\xc0\x42\xd8\x9a\x68\x66\x0a\x97\xff\xac\xec\x49\x67\xa4\xb6\x18\x71\x2d\x70\x60\x75\x65\x20\xc2\x9e\xe8\xd9\x22\x0a\xd8\x61\x5c\x4f\xcf\x39\x69\xbd\x3b\x2e\x09\x47\xe1\xf0\xbe\x7e\x2d\x80\xe0\xa6\x14\x80\xc3\x16\x6d\xb5\x58\x22\x18\xbb\x0a\x8b\xe9\x84\x8e\xfd\x41\xb6\xce\x0c\xd7\x95\xc4\x86\xab\xb6\x72\x10\xbe\xb6\x0c\xd0\x78\xb4\x6a\xeb\x7f\x4f\x48\x50\x31\x90\x2b\xcd\x71\x31\xe0\x0b\x70\x35\xaa\x2d\x43\xfe\xe0\x63\xf7\xf3\x0b\xd5\x70\xda\x1d\xbb\x65\xc0\xca\x92\xa4\x81\x26\x32\xe4\x32\x77\x85\x53\xe3\x5e\x85\x6c\xaa\x82\x18\x22\x1f\xd6\x31\x6a\xb0\x86\x91\x73\xb3\x84\x09\xbc\xef\xe6\xd2\xdb\x92\x10\xf9\x02\x41\x73\xb6\x6d\xbb\x92\x67\x7c\xbc\x71\xc8\xa1\xcd\x58\x3f\xa6\xf3\x54\xd3\xc9\x3f\xa8\xb1\x6c\x71\x37\x4f\x25\xa0\x0c\x33\x2f\x85\xa8\xbe\xfd\x54\x03\x88\xfb\x50\xdb\x9f\x5d\x96\xe4\xe4\xe6\x98\x83\x3c\xe3\xd6\x3c\x10\xb8\xee\xc7\x0a\x24\x3b\x90\x15\xdb\x45\x94\x31\xb6\x2f\x56\x68\xbb\xa6\x0f\x07\x04\xf6\xbd\xfe\x95\x46\xea\x47\x5c\xef\x2e\xbc\xcb\xa4\xb7\x68\x08\x48\xe8\x2b\xef\xf5\x85\x4e\x49\xf6\x5b\xb7\x73\xa4\x92\x2e\x90\xf9\xb8\xaf\xc7\xcf\x81\x87\x30\x58\x8e\xd5\xaa\x7b\x39\x98\x26\xaa\xdd\x54\x37\x2f\xcb\x76\x14\x58\xb6\x4d\xe6\x68\x57\xf4\xad\xac\xd4\xc3\x29\x00\xcb\x77\x13\x6a\x53\x5d\x7b\xbb\xb5\x54\x59\x7a\xec\xf3\x9f\xf6\x98\xb4\x5e\x6a\x21\x8d\xf1\xd2\xab\xe6\x15\xeb\x8d\x9e\x18\x24\xc0\xbe\xcc\xe9\x07\x67\x89\x9e\xbf\xd2\xc7\x30\x14\x4b\x32\xc7\x46\x04\xc0\xe5\x3e\x25\x05\xbb\x15\xd2\x80\x07\xa8\x7b\x99\x31\xd6\xee\xc0\xa6\xcb\x5b\x0f\x96\xd3\x19\x4b\x24\x23"}, -{{0xf8,0x20,0xe6,0xf2,0x4a,0x84,0x18,0xb6,0xac,0xda,0x16,0x5f,0x29,0xa3,0x60,0xf7,0x67,0xcd,0xed,0xde,0x8f,0x64,0xd7,0x68,0xb9,0x5f,0xc2,0xa5,0xf3,0xf4,0x04,0xe7,},{0x79,0xc4,0xb2,0x63,0xb2,0xe5,0x8f,0x67,0x86,0x28,0xd4,0xea,0x82,0xb1,0x75,0xac,0xa2,0x30,0xb9,0xa2,0x02,0x85,0xc8,0x28,0xf9,0x4e,0x1f,0xfd,0x63,0xd7,0x5b,0x23,},{0xf9,0xfd,0x72,0xf3,0x21,0xca,0x21,0x33,0xbf,0x85,0x85,0x90,0x8d,0x9c,0xa7,0xb8,0xe3,0x36,0x22,0x7e,0x3f,0xfb,0x37,0x49,0xa1,0xfb,0xe8,0xc9,0xb1,0xe5,0xd5,0x0e,0xf0,0x1f,0x9d,0xb5,0xf0,0xd2,0xa7,0xc7,0xc1,0x39,0x9b,0x97,0xc9,0x04,0x4e,0x1b,0xc1,0xad,0xc3,0x2b,0x8b,0xea,0x46,0xda,0xd7,0xb8,0x10,0x26,0x46,0x96,0x03,0x03,},"\xab\x6b\xd4\x5b\xb0\x6d\xfb\x90\x69\x11\x8f\xf9\x98\xf3\xbd\x39\x3e\xa8\xe9\x44\x97\x9e\x89\xe0\x49\xf2\x50\x5c\xd8\x93\x1b\x93\x08\x6b\x7e\x9d\x8e\xe7\x64\xe9\xb4\x47\xea\x4e\xa1\x21\x38\xbb\x45\x27\x5a\x21\xa1\x98\x43\xf7\x5d\xc5\x42\x1d\x61\xff\xd8\x61\x83\x8e\x58\x33\x82\x5d\x67\x16\x2f\x32\x59\xc2\x64\x47\xbe\x51\xdc\x18\x02\xef\x5a\x04\xba\x73\xb7\x83\x93\x57\x06\xab\xb4\x2c\x51\x3b\x65\xf2\xbb\xc4\x4f\x83\xda\x10\x61\x24\x2f\x2d\x5e\x51\x98\xf3\x8c\x10\x71\x7a\x86\xa3\xa1\x97\xe7\xcd\x90\x34\xf6\x36\x11\x44\x99\x03\x72\x77\xac\xb4\x72\x2c\x06\xa9\x1c\xb2\xf6\x5e\x21\xeb\x8d\x22\xd3\x6a\xd7\x3b\x42\x65\xf7\xa7\x94\x7e\x00\xe7\x22\xbd\xa6\x70\x43\xcd\x12\x81\xbc\xd8\x7e\x76\x3f\xc9\x7b\x54\xc8\xf8\x68\x36\xcd\xbf\x08\xc9\xa1\xf7\x00\xf4\xea\xed\x9e\xa5\x9a\x6f\xc1\xbc\x0d\xf8\xc9\xec\x1f\xc2\x97\x7c\xad\x60\xf9\x78\xab\xc0\xc8\x38\x1a\xa9\xfb\x06\x0e\x3f\x99\x37\x8a\x51\xb2\xd9\xaf\xbe\xf3\x58\xd5\x51\x62\xa3\x89\x22\xeb\xb8\x7d\x2a\x3e\x0f\x0f\x40\x00\xb1\xc3\x9b\x15\x02\xe9\x59\x45\xe8\xac\x9f\x4a\x3e\xa7\xc9\xdd\xb5\x81\xa5\xec\x06\xc0\x0b\xa8\x7a\x73\x70\x84\xb3\x84\xfa\xba\x09\xc8\x48\x71\xdd\xd6\x7d\xc1\xbe\xbb\x2f\x7f\xbd\x94\xa5\x59\x7d\x01\x9f\xe6\x29\xe5\xbf\x12\xbe\xa2\xe3\x3c\xa8\x4c\x68\x0d\xc5\xa3\x98\x9b\xbf\x3a\xf9\xee\xec\xe8\xab\x8f\xc8\x61\xe3\xb8\xbf\xc1\xe6\x7e\x2a\xee\x32\x6b\x37\xfb\x9b\x51\xcf\xa0\xb5\xf5\xfc\x16\x00\x69\xb4\x50\xb7\x04\xe0\xfa\xb7\xfb\x6c\x5a\xb3\xc4\x0b\x8f\x0b\x3d\x09\x30\xb9\x11\x2d\x64\xb9\xda\xca\xb4\xdd\x87\x5f\x29\xd8\xc5\x8c\x5d\x20\x53\xad\x91\x48\xff\xde\x22\xd9\x0b\xc0\xd5\x0f\x5d\xec\xa6\x8d\x3e\xa2\x5c\x5b\x4c\x76\x88\x87\x1c\x0c\x77\xdb\xce\xea\xcb\xd0\xa4\x22\x9f\x49\x70\xec\x87\xb3\x44\x99\xe2\x78\x30\x3c\x06\x69\x4c\x30\xac\x68\x52\x4d\x11\xb1\x72\x79\x4b\x48\x12\x73\xa5\xda\xc4\x61\x22\xd2\x47\x20\x95\xa5\x63\xa4\x35\xd1\x85\xd5\xe9\x1d\xa7\x26\xe7\x45\x92\x99\x9c\xda\xc6\x88\xa3\x3f\x38\xf7\xc0\x35\x58\x8f\x62\x5d\xc6\xac\x73\xd0\x04\x7a\xb3\xd6\xd1\x2f\x1a\xe3\x3d\x8b\x62\xd6\xd6\xc6\xca\xcf\xf0\xbd\xd8\x94\xb5\x7e\x31\x89\x12\xac\x0c\xf4\xa5\x34\x76\x2b\x2f\x6d\x26\x3c\x93\x58\x04\x42\x3e\xd8\x68\xcf\x8c\xfb\xb8\xbe\x8f\x6d\x8a\x71\x4a\x26\x8a\x39\x0e\xdc\x2d\xd5\x09\xd2\xdc\x96\x85\x1d\x1b\xd4\x32\x49\xbd\x0f\x69\xb0\xc4\xcb\x2f\xf4\x08\x0d\x1f\xd5\x62\x2b\xc2\x38\xdd\xa6\xe9\x30\x02\x5d\x8a\x2b\x12\xb9\x72\xf9\xeb\xa1\x74\x21\xd4\xce\xa6\x42\xf4\x0a\xd9\xea\x85\x47\xae\x59\x49\x8c\x3a\xd1\xb9\xa0\xc3\x4e\xd8\xc0\x1a\xae\x3b\xd2\x1a\xc1\x77\x43\xb5\x77\xf9\x51\x5c\xfb\xdd\xe2\x70\x4d\xc5\x7e\x80\xf1\x25\x32\x3d\x55\x10\x0b\x9f\x69\x79\x27\xd4\x31\xdf\xe7\x36\x31\xb5\x8e\x52\xaa\x6a\xeb\x04\x78\xbf\x45\x95\x52\x43\x86\x89\xfb\xeb\x9c\x60\xd8\x7a\xae\x09\x95\x43\x62\xcd\x02\xa2\xb0\xb4\x79\xef\xd3\x8f\x17\x82\x1a\xf3\x9b\x21\x92\x6e\xe0\x2f\x7d\x97\x2a\xd0\xf5\x4e\xa6\x57\x2c\xc3\xeb\xd0\x20\xb1\xee\x26\x88\x25\x33\xbd\x19\x11\x43\x23\x81\x5f\x67\x2e\xc8\xc9\x05\x68\x73\x0a\x58\xe4\xe1\xe3\x5f\x68\x21\x21\x9a\x32\xb8\xa6\xc5\x2c\xed\x6f\x95\x73\xd9\xf3\xbe\xb2\x85\x13\xba\x62\xfb\x20\x1f\x7f\xd4\x1b\xb1\x0c\xa3\x4b\xb1\xc7\x0f\x2f\xd7\xbb\x92\x99\xa7\xc5\xf7\xf2\xe0\xfa\x1d\x1a\xf0\xe9\xae\xf5\xed\xe7\xc1\x69\x50\xe8\x60\xec\xd6\x1f\x18\x42\xa1\xa2\x2c\x98\x31\xc0\xc0\xd4\xed\xa8\x40\xb0\x88\xa5\x45\x20\xc9\xb1\x8c\x76\xeb\xa9\xbe\xbc\xd5\x91\x38\x1c\x18\x0d\x7f\x86\xa0\xe5\x8a\xdd\x92\xb9\xb0\xc8\x07\x6a\x7c\xdc\xab\x60\xde\xa4\xc1\xaf\xb1\x8c\x8b\x94\xb1\xb3\x92\xcc\xfb\x4d\xae\x27\x11\xe7\xd1\x2d\x2b\xc7\xc7\x82\x5f\x63\x99\x2e\xc3\x24\x71\x63\xc2\x83\xb1\x07\x5e\x32\x24\x5f\x69\xcf\x47\x24\x0a\xef\x0d\xb4\x3e\xfa\xe8\x6f\xc1\xfd\x3b\xb9\x9c\xf5\xb7\x89\xf5\xbc\xba\x95\x04\x65\x7d\x9e\x62\x2a\x4a\xa1\x6f\x01\xd4\xd8\x44\x41\x31\x24\x44\x7d\x6d\x1a\x44\x23\xe7\xb5\x5d\xb7\xe6\xa3\x1a\x31\x9f\x4b\xac\xae\x43\x0a\x33\xa9\xbd\xd4\xef\x36\x80"}, -{{0x0a,0x05,0x6b,0xe0,0x39,0xfd,0x55,0xda,0xda,0x44,0x1d,0x03,0x73,0x61,0x27,0x3f,0x20,0x6e,0x00,0x0a,0x74,0xa0,0x5c,0x51,0xc0,0xcb,0xb6,0x27,0x43,0xf1,0xf3,0x40,},{0x73,0x14,0x02,0x17,0xa4,0x93,0xa1,0x78,0x66,0xff,0xf5,0x15,0x48,0x32,0x27,0x3d,0xf7,0x9d,0x58,0x11,0x54,0x3c,0x22,0x2a,0x39,0xd0,0x56,0xb8,0xc9,0x70,0xdb,0xfa,},{0xfa,0xb8,0xe5,0xd9,0x3d,0x7d,0x46,0xc6,0x5e,0xe1,0x17,0xc5,0x37,0x5e,0x73,0xc9,0x70,0x5f,0x87,0x54,0x17,0x7f,0xdd,0x46,0xef,0xed,0x47,0x37,0xc2,0x87,0x68,0xcc,0x4b,0x95,0xa9,0xc8,0x4c,0x52,0x9b,0x4b,0x91,0x6b,0x28,0xda,0xbd,0x87,0x41,0x18,0x31,0x44,0xbc,0xdb,0x48,0x3d,0xf9,0x8a,0xf8,0x9d,0x82,0x40,0xcf,0x09,0x46,0x04,},"\xa5\xab\x14\x76\x84\xe4\xd4\xa7\xbc\xb5\xa9\x6f\xb3\x98\x18\xe2\x3f\x56\xc2\xd8\xa7\x44\xe9\x12\x3d\x62\x08\x39\x30\xab\x1d\x0b\xb5\x32\xe6\x87\x14\xfc\xec\x7e\x6c\x41\x13\x4b\x6b\x19\xdd\xd8\x67\xfe\x63\x5c\x9e\xd6\x53\x93\xee\x39\xc5\xe8\xfa\xb4\x56\xcb\x5b\x32\x79\x78\x83\xf3\xcd\x9a\x09\x02\xb9\x79\x63\x48\xee\x66\xc6\x91\xfb\x4f\x2b\xb1\x47\x64\x41\x06\x57\xc7\x4a\xb3\x64\x56\x78\x79\xb6\xfa\x0a\x6f\x4d\xaf\xd9\x30\xd9\x23\x4c\xd7\x83\x4f\xb9\xd0\xee\xdf\xbb\x5a\x39\x4b\xf0\x84\x6e\xc6\x96\x9c\x2e\xf7\xce\x39\xe3\x85\x38\x95\xff\x5b\x4d\xa3\x1e\x54\x34\x1b\x42\x72\xe4\xa2\x60\x49\x18\x9f\xf2\x82\x41\xce\xef\xfb\x7d\x2e\x1f\xaf\x4f\x77\x9f\xa6\x5c\xac\x0f\x57\x83\xc6\x0a\xe7\x7d\xe3\x0a\xd4\x46\x5f\xdb\x39\x0d\x42\x57\x1e\xff\x4a\x63\x13\x63\x49\x93\x7d\x6c\xae\xef\xcd\xae\x22\x9e\x2f\x28\xce\xa8\xab\xf3\xff\xae\x3c\x3e\xcc\xd9\x06\x70\xa4\x21\x2a\x2b\xee\x1c\xa6\xa5\xb5\x4f\x09\x4f\xc3\x23\x10\x58\xf5\xcb\x9e\xce\xb9\x99\x3b\xe4\x70\x27\xd5\x1c\x18\xde\xca\x41\xcd\xda\xf4\xe8\xbc\x56\xa9\x9f\xd2\x70\x35\x5f\xf4\x59\x71\x95\x0e\x34\x37\xa1\x98\xcc\xc3\x25\x41\x68\xdf\xc1\x57\x40\x80\x80\x2e\xe1\x01\xa6\x17\xfb\x60\x4e\x86\x8f\x8f\xa8\xfb\x30\xda\xeb\x43\x07\x4d\xe1\x1f\x24\x83\xd9\x16\xde\x56\x43\xb7\xca\xc2\x3d\x93\x40\x50\x8a\x3f\xd6\x21\xec\xd2\x50\x04\x35\x6a\x53\x55\x4a\xd3\xad\x7d\x5d\x25\x81\x7a\xd7\xc9\xa6\x10\x00\x8c\x67\xac\x16\xba\x42\x11\xc4\x2f\x5d\xad\xf8\x6c\x2c\x3a\xed\x82\x5c\xf2\xa9\xb5\x23\xbf\xc0\x3d\xd7\xde\x40\x0c\x67\x80\x7e\x13\x9e\xa5\xdb\xce\x4e\xe1\xf7\xd3\x18\x88\x9b\x01\xa9\xf4\x48\x03\xc3\x22\xac\x3b\x61\xe2\x0e\x63\x12\xd0\xa0\x3b\xf9\x92\x7f\xa3\x3f\x04\xed\x7e\x20\x7b\x16\xf2\x65\x02\xc2\x98\x3a\x3a\x96\x1f\x22\x44\x61\xfe\x9b\x64\x92\x3b\x1d\x09\x18\x94\x76\xae\x8d\x00\x1d\x0e\xca\xae\x4d\xf6\x0d\xb3\x5f\x44\x8b\xb6\x12\xf9\x65\x5a\x5f\xb1\x44\xdf\x11\xd8\x3a\xa6\x93\x68\x86\xc3\x04\x94\x9e\x59\xaa\x46\xdf\x65\xc2\x2c\xe7\xbf\x28\x9b\x3c\x77\xc2\x5d\x89\x6b\xe6\xd5\x1d\xee\x10\x74\x82\x61\x68\x8c\x8b\x07\x1c\x85\x6f\x99\x62\xc6\x67\x75\xdd\xf1\x60\x83\xda\xe0\x65\x87\xe3\x2a\x63\x61\x19\x9d\x72\x09\x7e\x38\x3a\xd7\x43\x94\x91\xb5\xa5\x63\xa3\xe6\xd5\x8d\xa3\xd5\xab\xb1\xde\x84\x89\x0a\x36\xb4\x21\xce\x03\xd4\x84\xdf\xd6\x00\x39\x63\x8d\x46\xed\xfb\x60\x65\x9e\x3a\x25\xac\x6e\x9a\x93\x5a\xd6\xda\xd5\x0f\x92\x7b\xcc\x2f\xf9\x9f\x99\x24\xa5\xb7\x99\x5d\xc2\x3c\x8f\x30\x1c\xcc\x77\x69\xf7\x1c\x18\x26\x09\x04\xa3\xdc\xfb\x81\x7d\x2d\x80\x5c\xb1\xf1\x96\xbe\x8b\x6e\xcf\x35\x2b\xc2\x96\xbc\x3f\x76\xea\x91\x35\x3f\x8c\xf3\x5b\xcd\x2b\x57\xeb\x59\x42\x77\x3d\x68\x34\xac\x50\xee\xad\xc7\xe6\x64\x61\xd1\xda\x09\x8c\xce\xc7\x5f\xf7\x20\x52\x15\xf5\x24\x59\xd9\x76\x20\xf9\xf0\x28\x9e\x93\x91\x1d\xb3\x9b\x21\xdf\x81\x8f\xdf\x0b\xed\x45\x50\x92\x44\x63\x3d\xf0\x1c\xdd\xdb\x4b\x75\x97\x2f\xa7\xea\x6f\x73\x28\x1c\xbd\xbb\xd1\xbc\xb0\x0c\x3b\xc1\xb1\x72\x8e\xea\xe0\xbb\xa1\x72\xb1\x31\xf5\xd3\x08\x90\xa3\x41\xe6\xb7\x2f\x7e\x89\xdd\x4b\x6d\xb3\xe7\x9b\x69\x27\x58\x6c\xf2\xc8\xac\x38\xdd\x14\xf3\x74\xd7\xf5\xbb\xa9\xf4\x35\x3d\xef\x10\xdd\xc9\x4d\x3d\x11\x18\xc5\x69\x9e\x38\xb6\xb5\x04\x91\x8e\x58\x9e\xfe\x3f\x7e\x97\x3f\xb4\x0e\x2e\xbd\x05\x7d\xe1\x38\x5e\x39\xd6\x99\xa8\xf6\x83\xb9\x62\xfa\xe4\xf3\x90\x28\x81\xf1\xaf\xbe\xd7\xc7\x83\x82\x35\x58\xc3\x6d\x68\xc6\x87\x5d\x16\x6f\xa2\x43\xeb\x2a\xe1\x4f\x7e\x63\x15\xa6\xd2\xab\x4e\x79\xea\x8e\x16\xe6\x9d\x30\xed\xc7\x08\xf1\xe7\xaf\x7a\xda\xfe\xdc\xd3\x16\x88\x98\xb3\x31\x87\x81\x78\xc4\xba\x88\x33\xd2\x0b\x3c\xac\x9d\x32\xb8\x88\x8c\xc6\x78\x32\x06\x39\x74\x70\xa2\xe7\xcc\x4c\x98\x09\xff\x79\xce\xac\x9d\xc2\x4c\xa1\x43\x8c\x91\x9c\x8a\x41\x5e\x82\xf0\x90\x2b\x4d\x9c\xf4\xcc\xd5\x76\x96\x8d\x5b\xee\x81\xc5\xf1\x9c\x7d\x57\xb9\xba\xda\x8e\xab\x47\x56\xea\x27\x0d\xd2\x61\x29\xe6\x12\x2e\xe2\xd6\x15\x24\x2b\xc7\xfa\xbf\xf4\xf8\x31\x2e\x68\x6c\x8f"}, -{{0x22,0x05,0x24,0x86,0x0c,0xb8,0x9a,0xb2,0x95,0xbd,0x88,0x4f,0x98,0x8a,0x57,0x91,0x18,0x68,0x69,0x3d,0x6b,0x10,0x5a,0x80,0xb2,0x30,0xf2,0x1e,0x57,0x80,0x5a,0x7d,},{0x4a,0xb3,0x2b,0xc1,0x56,0x6a,0x76,0x77,0xe7,0x99,0x73,0x4d,0xc8,0x41,0x81,0xfb,0xb6,0x54,0xb8,0x13,0x37,0x91,0x80,0xf1,0xdd,0x35,0xae,0xf2,0xd3,0x24,0xc1,0x2c,},{0xdb,0x1c,0xc0,0xc5,0xdb,0x77,0x3e,0xc5,0x16,0x89,0xbe,0x28,0x84,0x2f,0xa6,0x79,0x1a,0x7d,0x75,0xe2,0x9c,0x22,0x8a,0xe9,0x59,0x3a,0x58,0x0e,0x08,0x75,0xb1,0x67,0x0f,0x09,0xb0,0x34,0x42,0x92,0x9a,0x18,0xf1,0xe9,0x41,0x4e,0xa3,0x43,0x15,0xff,0x09,0xd9,0x1d,0x92,0x2e,0xe4,0x7f,0x10,0xf7,0x1d,0xa4,0xab,0x13,0xb7,0xd9,0x01,},"\x02\x4a\x54\xac\x5e\x01\x63\xb3\xa4\xfd\xd0\x2f\x59\x36\x88\x8a\xe2\xf9\xb7\x4a\x64\x14\xb5\x3c\x63\x81\x17\x3b\x09\x5a\x4d\xda\xcf\xc3\xa6\x9f\x19\x16\x7d\x0f\x1a\xe0\xc1\x20\xbb\xa7\xe9\xfc\xb7\xcc\xfc\x79\x6d\x89\xea\x46\xef\x80\x58\x86\x6e\xf6\xda\x7d\x01\xa6\xa1\x42\xea\x69\xd7\x20\xc4\xf8\x05\xac\x54\x05\xa8\x01\x2c\x3c\x2a\x82\x63\xb5\x37\x2d\x59\xbf\x7f\x40\x99\x29\x90\x13\xd2\x62\x59\xdf\xd5\x19\x3e\xce\x56\x17\x97\x77\xbe\x51\xb8\x6b\xd1\xce\x5f\x1f\xc9\x15\x6f\x2b\x3a\x32\xc0\x9d\x86\xbc\x61\x32\xde\x57\x61\x02\xe2\xf0\x3c\x71\x6d\xb5\x36\x6c\xcb\xe7\x42\xae\xe3\x55\x2a\xc3\xb3\x9d\x0e\xc7\xd4\xe4\xe9\x62\x6b\xf8\xec\xe0\x31\xd6\x78\xd3\x48\x09\x05\xc0\xe3\x38\xfb\x7c\xc0\x26\xe3\xe7\x9c\xf2\xc2\x78\x1a\xc2\xa5\xa4\x0d\xf4\x28\x4e\x23\x5a\x03\x89\xe9\x28\xfc\x63\x55\x7d\xc6\xf1\x99\xfc\xec\x5f\x36\x1e\xa2\x47\x59\xfa\x7c\x5f\x71\x97\x8c\x0b\xa2\x45\xe4\xb0\x3a\xe4\x35\x94\x1c\x86\xc8\x1a\x51\x43\x0c\x2d\xc9\x92\x7e\x3b\x0f\x4e\xc4\xeb\xa7\xc2\x74\x5b\x49\x39\x87\x15\x4d\x7d\xa8\x5b\x67\xde\x21\xc5\x98\x40\x7f\xb2\xa7\x60\x80\x4a\xd0\x5b\xfd\xfa\x45\xa6\x13\x22\x4b\x22\xa0\x85\x88\xcc\xea\x3c\xbd\xf4\x7a\x19\x8b\xeb\xf8\xcf\xed\x86\x49\xd6\xd5\xf3\xfa\x50\x13\x76\xbd\xfb\xa4\x00\x3d\xac\x22\x37\xdc\xac\xe5\x31\x5b\x7f\xef\xb8\x79\xa8\x9a\x85\xbc\xe6\xda\x52\x6f\xc3\x60\xcb\xb4\xfd\x55\x4e\xf0\x13\xf3\x3b\x73\x84\xcd\x2b\x22\xa8\x85\x77\xf3\xa2\xd3\x66\x42\x2a\xae\x46\x41\x7b\xa9\x16\xe1\x64\x6e\x24\x40\x4a\x88\xb5\xd5\x3f\xf1\xae\xd2\xa4\x7b\xaf\x81\xfc\xb4\x28\x63\x97\x99\x13\x94\xb2\xec\xc3\x96\x67\xac\x46\xc2\xbd\xb6\xd0\x23\xb3\x3d\xb0\x13\x45\x7c\x40\x05\xd8\x39\x01\x5d\x88\x51\xf0\x28\xac\x33\x4f\xb2\x4b\xba\xd2\x90\x2a\x4d\x63\xae\x68\xe0\xec\xa7\xea\xea\x1e\x85\x65\x29\x64\x7b\xaf\x14\x12\x21\x37\x54\xed\x50\xaf\x3f\x43\x6e\x9b\xaf\xc1\x60\x16\x39\xb3\x9d\x3e\x52\xa9\x3a\x89\x8f\xb6\x01\x9f\xd5\xed\x6e\x7d\xfc\x05\x0e\x7c\xe5\xf3\xd3\x5c\xeb\x50\x67\x02\x1c\x0f\xbd\xc7\x08\xd3\xf2\x6b\xd6\x05\x68\xd1\xed\x2b\x61\x2b\x69\x62\x35\xd5\x33\x33\x18\xf9\xa6\xc9\x87\x23\x5a\x7a\x07\xf8\xc6\xa9\x35\x4f\xb8\xe7\x34\x76\x30\x65\xaf\xcd\x4d\x93\x77\x64\xa4\xf0\x37\xcc\x7e\x7e\x2b\x93\x21\x7f\x16\x41\x68\x4f\xa8\x1b\x7f\xf7\x98\x6a\x28\xb3\x8e\x95\xb3\x32\xe7\x46\x49\xe8\x3d\x0d\xed\x79\x5c\x57\xf2\x4c\xf2\x76\xe0\x14\x39\x01\xba\xfe\xf0\xf1\x69\x3f\xe7\xcf\x10\x90\x4f\xb0\xd8\x80\xd7\x2e\x44\x71\x6a\x70\x69\xda\xaa\xe7\x42\xcf\x0f\xf3\xed\x92\xf5\xf7\xd1\xe1\x0e\x04\x9d\x8d\xf0\x43\x63\x1e\xd0\xed\x4c\x4a\xc4\x02\x2d\x84\x03\xcb\x04\x21\xb4\x54\xcb\xfb\x6f\x48\xa3\x0e\x9e\xe1\x60\x9a\xd7\xb6\x82\x11\x97\x7a\xcb\x33\xb9\xc1\xa1\xbe\x73\x58\x14\xc5\x8f\x66\xdb\x5f\x0b\x8a\xc7\x73\xb1\xd5\x8d\x4e\x6b\xc4\x5d\xfd\x48\xa2\x94\xbb\xd2\x5e\x92\x67\x1f\x56\xf3\x02\xf2\x9b\x50\xd8\x04\x31\xc8\xf2\xea\x33\x99\x62\x57\xb2\x08\xe0\x57\xea\x76\x72\xcc\x2d\x1c\xd4\x20\x4b\x85\xb2\xab\x50\x90\x27\x13\x13\x59\xae\xb4\x2e\x3e\xcc\xdb\xae\xcf\xe2\xcd\x3e\x5a\x33\x13\x26\x6e\x76\x11\x94\xff\x69\xca\xe9\xe3\x7e\x51\xcc\x0a\x54\xf0\x86\xdd\xe1\x3c\xb3\x31\x18\xe3\x4f\xe3\x3c\x74\xd7\x35\x58\x27\x52\xd6\x8d\x21\xc7\x9e\x5c\x3a\xae\xa9\x4b\xa1\x07\xcb\x7e\xe8\xa7\x0a\x3f\x9a\x01\xe9\x80\x8c\x0a\xeb\xa6\x66\x53\x15\xb4\x56\x25\x84\x0a\x03\x3a\x6e\x2a\x87\x54\x95\x05\x79\x42\xed\x9b\xb2\xce\x6e\x4e\xe6\x0b\xed\x47\xcd\x9d\x58\x4b\xc2\x45\x24\x39\x7a\x10\x94\x98\xee\x2a\x97\x3a\xad\x6a\x29\xb7\x0a\x1c\xfb\xfe\x9a\xa5\xc7\xcb\x9f\x35\xf0\xfa\x00\x22\x7f\x43\x98\x8d\x07\x61\x9b\x6f\xb2\xf6\xd3\xbe\xe2\x8e\x10\xee\x70\x53\x47\x01\x5a\x92\x2e\x2e\x88\xd3\x4f\xb0\xce\x51\x5b\x08\xdf\x3a\x1b\x63\x4f\xf9\xec\x15\xd0\x59\x41\x82\xc8\x6e\xbb\x0d\xb7\x83\x61\x2a\x7d\x19\xe4\xb2\x2e\x82\x2d\x56\x62\x45\xae\xd7\x2e\x69\x4c\x3d\x10\x1b\xfa\x4c\xa8\x79\x86\x2e\x5f\x99\xc2\x3a\x5d\x66\x08\x3c\xe0\x6d\x87\xf3\x99\xaa\x78\x88\xab\x83\xb8\x66\x44\x72"}, -{{0x4e,0xf6,0x0f,0x06,0x91,0xd7,0x37,0xe6,0x4d,0x43,0x7b,0xfd,0x33,0x98,0x33,0x0e,0x55,0xe3,0xc0,0x94,0xcf,0x41,0xfc,0x55,0x7b,0x0f,0xe0,0xb6,0x43,0x90,0x9a,0xb8,},{0x30,0x6a,0xb1,0x46,0xe5,0xc8,0xcd,0x63,0x0f,0x9b,0x48,0xbf,0x8b,0x68,0x5d,0xb0,0xb6,0xb5,0x53,0xef,0x69,0x68,0x68,0x53,0xb6,0xb5,0x31,0x96,0x01,0x18,0x54,0x8c,},{0xcb,0xf7,0xcf,0x22,0x08,0x1c,0x5f,0x23,0x5d,0xba,0x35,0x63,0x0f,0xb3,0xf0,0x40,0x8f,0xce,0xcc,0xef,0xeb,0x28,0xb9,0x9d,0x74,0xdb,0xd9,0x8c,0x90,0x2c,0x7d,0x99,0xba,0x9c,0xa7,0xfa,0xb3,0x74,0x7c,0x50,0x4c,0xc2,0x19,0xf4,0xdd,0x10,0x10,0x81,0xf5,0x8c,0xe6,0x16,0xe2,0x92,0x80,0xe3,0x62,0x53,0x9f,0xe4,0x9f,0x34,0xd7,0x05,},"\x0a\x18\x8a\xc2\x6f\x3c\x5d\x89\xf3\xd5\x88\x37\x4f\xac\x5e\xcf\x9a\x46\x7e\x21\x65\xb3\x1d\x0b\x0f\x23\x50\x1b\xd2\x2e\x62\xbf\x35\x55\xff\xba\x94\x63\x1d\xe7\x4a\x6a\x3c\x3c\xf6\x3b\x03\xac\x1b\xbb\x37\xd2\x33\xec\xa5\x99\x3b\x09\x70\xa0\x22\x0d\xe8\xd6\xc4\x1a\x97\x03\x07\x30\x9a\x52\xda\x05\x76\xdc\x33\x4d\x80\x64\x47\xaa\x09\xd0\xb2\x45\xea\xcd\x0b\x42\xc4\xe1\x9f\xa3\xd6\xfb\xdc\x22\x94\x30\xeb\x3c\x75\x58\xaf\x53\x31\xc6\xe7\xfc\xc2\xe5\x52\xce\x35\xd5\x79\x07\x3b\x54\x8d\xc1\x15\xbb\xd2\x7e\x5a\x33\xce\x1c\x47\xfc\x84\x61\xe3\x91\xb6\xd7\x67\x95\x34\x87\xcc\x52\xee\x67\x3b\xc4\xbe\x96\x56\x9c\x85\x57\x36\x9e\xbb\x6e\x02\xf7\x92\x38\x10\x8c\x3b\x58\x56\xee\x38\x1a\x79\xff\x46\x4c\x8f\x60\x09\xfd\x47\xe6\x7b\x4c\x80\x20\x1e\x11\xe6\x1a\xb8\xf5\x9b\xa5\xd0\x7b\x15\xac\xe3\xfb\x37\x4c\x64\xb6\xb4\xc3\x45\xe2\xb0\x0e\x91\x51\xab\x8e\x1c\x5c\x98\x56\x8b\xc5\x8d\xd0\x81\x2a\xaa\x3b\xee\xe1\x65\xe7\xea\xe5\x8f\xbd\xe6\x30\x77\x20\x3c\x4f\xd6\xe1\x60\x68\xd7\x6e\x3d\x3a\x13\xf1\xcd\xd7\x32\x88\xbd\x5e\x4d\xa4\x4e\xb1\x19\xa0\x4c\x4d\x32\xef\xa2\xf1\x3e\x74\x26\xa2\xf4\x1c\x56\x23\xc9\xb0\x66\xb1\x30\x36\x39\xb8\xfc\xea\x0d\x87\x74\xcc\x08\x04\x5f\x7e\x34\x63\x65\xff\x31\xd3\xb1\xed\x99\xe9\x7b\xca\x5f\x25\xc9\x2b\x28\x43\xac\x58\x5d\x02\x19\x3a\x2f\xd3\x94\x66\xf7\x3a\xaa\x98\x9b\x1f\xa0\x5b\x9a\x15\x7f\xd0\x27\x7c\x5e\x74\x5d\x25\x8e\x02\x78\x03\xa5\x24\xad\x94\x30\x94\x25\xc3\xf4\xde\xc3\x1c\x0e\xfc\x54\x77\x52\xf4\xc7\x19\x4c\xbb\x27\x2f\x84\x9a\x52\x16\x9c\x6a\x07\x8d\x20\xed\xe1\x43\x20\x16\x52\x84\x77\xb5\x8c\x2b\xdf\x60\x63\xf9\x44\x7e\x33\x83\x7c\xcb\x43\x7d\x8d\x6b\x95\xcf\x4c\x44\xbe\x70\xc8\x19\x3a\xd9\x80\xa1\x05\xf3\xdb\x6f\x99\x30\xba\xb4\x67\x8c\x77\x63\x42\xfa\xf1\x70\xed\xf7\x42\x48\xd3\xb1\xca\x96\xf7\x31\xb9\xd0\x26\xd8\xf0\xf7\xc3\x4e\xd3\x72\xc1\xcd\xe1\x76\xf5\x5f\x55\x86\x75\xcc\x31\x80\xc2\x39\x02\xf4\xba\x95\x08\xd1\xc9\x1c\x3c\x9e\x68\x87\x30\x32\x7f\x3f\x7b\x63\x7a\x8f\xee\x54\x37\x37\x59\xfc\xb1\x7c\x92\x17\xea\x44\xce\x43\x69\x1a\x8f\x64\x63\x64\x0a\x4a\x5e\x15\x1e\x62\x54\xc4\xef\x12\x62\x3b\x49\x39\x4d\xa7\xcc\x79\x45\x26\x93\x81\x7d\x6b\xae\xa9\xa0\xa7\x58\x76\x94\x8b\x1f\x8d\x3b\x71\x7f\x9e\xc3\x67\x53\xf5\x32\x63\x71\x03\x83\xb9\x82\x62\xae\x63\x54\xff\x2a\x22\x83\x22\x0a\xd4\x2c\x5c\xb2\xcb\xbd\xf1\x2c\x87\x95\x13\x71\x0b\x16\xbe\x85\x6f\x3b\x13\x55\xb3\x6f\x4b\x80\xc0\x17\xc2\x1b\xe8\x5e\x96\x05\x3d\xa0\x50\xc4\x03\x12\x10\x0a\xbb\x64\x0b\x87\x3d\x88\xfb\x6e\xe0\xd1\x9e\x9e\x61\xb0\x4c\x97\x0b\xd1\xf0\x60\xdd\x31\x1b\xbb\x9a\x6e\x35\xb9\x85\xfd\xca\x17\xca\xee\x8c\xd5\xdb\x63\x7a\xcd\x90\xcb\x8e\x82\x32\x55\xc0\x56\x01\x8f\xef\x59\x20\xdb\x64\x0d\x22\x01\xc5\xed\xdb\xd8\xa9\xc9\x47\x4d\xa8\xde\xf7\xe1\x32\x5b\x3c\xc4\x36\xc7\x4f\x81\x5d\xb1\xe4\x2b\x42\x1f\xaa\xb6\x26\xa4\x37\x8c\x2d\x84\x26\x1b\xf6\x49\xa5\x3b\x32\x1f\x59\x8c\x44\xbb\xd3\x00\x2b\x06\xcf\x7f\x1f\xde\xf8\x4a\xb3\x5f\x73\xed\x7d\xc6\x50\x96\xcb\x1d\xc0\xcc\x0e\x34\xc5\x61\xc8\xa1\x5c\xf5\x27\x9a\xbb\xed\x9b\x16\xff\x24\xa9\x74\x4e\x3f\x5e\x64\x9c\xc9\xd8\x88\x4f\x89\x1c\x3f\xb7\x89\x02\x03\x1f\xfe\x0e\x01\x21\xc7\x20\x80\xad\x10\xc2\x47\xb7\xc9\x3a\x9e\xbb\x2d\x84\xd4\xf8\x77\x75\x0d\x7b\x34\x16\x39\x3d\x03\x04\x52\x26\xbb\x79\x94\xee\xa5\x8e\x27\x2d\xc1\x8c\x46\xb3\x82\xd1\xf9\x7b\x23\x76\x5f\xda\x7a\x8c\xe2\x1f\xc6\xb9\x8d\x72\x3f\xfc\xcd\x99\xac\x46\x55\xcc\x5d\x10\x10\x5a\x2a\x5b\x7c\x8c\xfb\xfb\x90\xe2\x7a\x9a\x80\x9e\x41\xae\x64\x00\x63\x28\x64\x05\xa9\xbe\x83\xac\x5d\x29\x07\xa4\x5f\x16\x3c\x77\x64\xb0\x9f\x99\xa5\x55\x93\x22\x0d\x69\x01\x29\x2b\x9b\x58\x03\xa0\xfe\x71\xb0\xe4\x44\x1c\xbf\xef\x84\x1c\x33\xce\xbc\x98\x36\x4d\x66\x6e\x5a\x9f\x5e\x7e\x69\xa1\x50\x8e\x43\x80\xed\x36\x13\x45\xb7\x24\x8a\x4c\x1c\x1c\xe0\x87\x69\xbc\x71\x52\xdd\xb3\x32\xfb\xa1\x76\x20\x0f\x5a\xbb\xae\x38\x12\xf4\x06\xda\x72\xdd\xe5\xdb"}, -{{0x19,0x7e,0x15,0xdc,0xe4,0xc4,0x7d,0x73,0x4d,0xbc,0xe4,0x68,0x8a,0x7a,0xd5,0xfe,0x41,0xeb,0xf2,0xaa,0x29,0xa2,0xbd,0xdb,0x2b,0xee,0x62,0x84,0x29,0xc1,0xbc,0x02,},{0x30,0xfa,0xc3,0x23,0x04,0x8b,0x0c,0x78,0x1a,0x9f,0x63,0xc1,0xee,0x69,0xf2,0xb9,0xe7,0x5a,0x27,0x06,0xd2,0x49,0x51,0x2a,0x27,0x39,0x60,0x7f,0x26,0xdb,0x13,0x8f,},{0x2c,0x3c,0x8c,0xd2,0x99,0xc9,0x06,0x0b,0x65,0x99,0x9b,0x03,0xa6,0x57,0x9b,0xc5,0x0e,0xf1,0xfe,0x0d,0x85,0x1f,0x23,0xbe,0x9c,0xb5,0x8f,0x8f,0xb8,0xc6,0x72,0xee,0x08,0x6a,0x53,0x9e,0xad,0x94,0x9e,0x08,0x7d,0xf0,0x91,0x12,0x2d,0x26,0xfa,0xaa,0xd2,0x06,0xa5,0xc5,0x2f,0xcd,0x58,0xb5,0x14,0xd7,0xa9,0x35,0xbe,0x01,0x79,0x08,},"\xfd\x97\x1d\x48\x94\x6b\x51\xff\xed\x7b\x62\xc5\xd0\x99\xc1\xe5\x6b\x13\x58\xb9\x22\x35\xe1\x01\x0e\x3f\x23\x84\x4d\xdb\x73\xbc\xee\x8d\x2e\x1c\x99\x77\x35\x3b\xc9\x6a\x22\x1c\x05\x60\x29\x31\xfa\x16\xcc\xc2\xab\x6d\x0f\x01\xc8\x46\xc2\x92\x0e\x99\xde\x02\x6d\xc2\x89\x7f\x3d\x5f\x3c\xee\x17\x4c\xe7\x51\xd4\xa8\x05\xee\x19\x59\xa3\xc6\x9c\xfd\x42\xd7\xc9\xaf\xd3\x1f\xa9\xb1\xcf\x05\x78\x6d\x8f\x90\x42\xa4\xf9\xf8\x1c\xf7\xac\x9c\x1c\x39\xb3\x6f\x1e\xe9\x5b\x98\xcf\x7e\xe3\xf4\x3e\x2c\x34\x37\x33\xd1\xd8\x2c\xc0\x8b\x2c\xde\xb7\x8d\x98\x20\x34\x08\x5f\xf4\xdc\x65\x36\xcd\x15\x4a\x79\x0c\x85\xc8\x61\x3e\xc4\xe5\xe1\xdc\x37\x7d\x38\xa7\x45\xd9\x38\xcf\xb1\x5c\x8b\x8a\xa8\x61\x21\x83\x5f\x2e\x25\xe9\xe6\xd0\xde\x68\x02\x5d\x81\x0c\x3d\xc9\xdf\x99\x1d\xad\xad\x39\xdc\x69\x81\xfd\xba\xc1\xff\x9b\x7a\x79\x1c\x39\x60\xd8\x56\x43\x66\xe5\xaa\x39\xa9\xe9\xc7\xcb\xf1\xd3\xf0\xf8\x20\xd1\xb9\x01\x08\x75\x1a\xc7\x64\xda\xbe\x05\xc5\x1c\x18\x52\x9d\xa1\xb0\x34\x96\x14\x66\x84\x24\xab\x4e\x93\x64\x40\xc4\xa2\x51\x3b\xe5\x28\x53\x93\x72\xee\xe7\x87\x54\x58\x9d\xbe\x79\x94\xfa\xa1\xf6\x22\x91\x24\xf8\x39\x95\x0e\xd0\x92\x3f\x43\x23\x31\x5a\xc9\x63\xbb\xe4\xc8\xe1\x77\xda\xc5\x16\xe7\x34\x22\x38\xf1\xcd\xf1\x40\xbe\xfc\x8a\xcd\xca\x3d\x00\x2b\x16\xc1\x39\x8d\x86\x86\x00\x30\x4c\x7e\x98\x53\xb2\x3a\x51\xb1\x7d\x9f\xd0\x61\x56\xe1\xd1\xd0\x8a\x28\x46\x09\x09\xfa\x20\x9c\xcc\xcc\x4c\xec\xbd\xb1\xa4\x63\x48\x08\x91\x15\x31\x86\x81\xa9\x5a\xe5\x80\xab\x67\x66\x04\x13\x84\x65\x1c\xc4\xe6\x14\x51\x03\x92\x3b\xdf\x4a\x32\xa9\x3d\x93\xee\xd3\x18\x79\x1f\x20\x80\x5f\x7e\xa8\x4b\x74\x3e\xe1\x1e\xad\x9e\x4c\xa0\x3d\xa7\x6d\xdd\x24\x9f\xd4\x47\x5f\xc1\xa3\x53\xc7\x0a\x83\x38\x9b\xfa\xc5\x20\x98\xdb\x06\x6d\x10\x29\xc4\xef\xfb\xed\x86\x4e\xbe\x7f\x10\x7e\x01\x03\xb3\xa8\xf3\xfd\x1d\x6a\xb4\x36\x0b\x99\xe8\xb1\x40\xc5\xea\x13\x3e\x92\x3c\x39\x2b\x8e\x40\x63\xaa\x6e\x52\x26\x38\xf6\x1d\x7a\x71\xc9\x22\x58\x97\xd9\xf8\xa1\xe1\x6c\xfc\xc8\x01\xe7\xd5\x41\x04\xeb\x10\xe6\x1a\x5a\xe6\x3c\x5c\x85\xa5\xb2\x93\x92\xab\x3a\xb8\xe5\xc0\x39\xf1\x00\xd0\xf4\x60\x0c\x61\x0e\x02\x09\x43\x6e\xf2\xec\xe4\xd0\xbd\xb0\xba\xb4\x37\xb2\xdb\x5f\x37\x08\xfd\xdf\x96\x66\x0f\x6f\xb1\xa9\x0d\x60\x48\xd3\x95\xaf\xaf\xa7\x60\xcc\xaf\x15\xde\xaa\x0e\xff\xeb\x26\xec\x17\x68\x1d\x17\x2c\x13\x30\xf7\x8e\x78\xa8\x73\x6b\x28\x5f\x61\x5f\x15\xd4\xf2\xc3\x13\xd2\x5f\x30\xae\xe9\xd1\xdb\x39\xf5\x35\xfc\xdd\x0e\xbc\x8e\x71\xb8\x9c\xe6\xb3\xfc\xb5\x67\xcd\x0f\xa2\x88\xf4\x8e\xd3\xa7\x59\xbb\x2e\xd2\x00\xfd\xc2\x30\x91\x50\x2f\xd9\xca\x65\x1c\xe5\xe3\x42\x2a\x98\x33\x5a\x81\xd7\x4a\x65\xcc\x15\x00\xe9\x07\x0a\xbb\x60\x9c\x1c\x1f\x68\xfc\x2c\xa9\x4c\xdd\x55\x0f\x99\xbc\xb2\xd0\x92\x41\x6b\x9b\xd3\x88\x41\x0b\x8f\xe7\x48\xfb\x8c\x9a\x5a\xb8\x61\x5f\x2e\xd9\x68\xf8\x5d\xcb\x27\x27\x72\x69\x84\xbe\xad\xa7\xa1\x8a\xfd\xb0\xc7\x2a\xa6\x5d\xe7\xab\xb7\xa8\x6f\x11\x16\x9a\x6e\xad\xf1\xc2\x1d\x61\x4e\x52\xc0\xc8\xf0\x19\x74\x7d\x34\x1a\x05\xd8\x5e\x37\xbf\x58\xd8\x32\x7e\x99\x39\xc2\x38\x7c\x27\x44\xed\xf8\x38\x56\x3c\xb3\x7f\x0b\x16\xe8\xa0\x6f\xc6\x28\xa9\x72\x30\x50\x6f\xa4\x18\x39\x54\xdc\x74\x81\x5f\x3b\xe2\xeb\x2a\xff\x4a\x13\xc0\x65\xf7\x43\xb7\xd8\x5d\xe8\x04\xeb\x28\xef\xe5\x70\xed\x5e\xcc\x71\xab\xa9\x7f\x97\x63\xb4\x36\x17\x32\x47\xf3\x8e\x0c\xf6\x29\x72\x09\xb6\x51\x28\x46\x5a\x38\x26\x64\xce\xd8\x01\x1f\xcc\x3d\x0e\x56\x3f\x15\x5b\xc6\x3c\x94\xdd\xe7\x3c\x7b\x17\x24\x7b\x8c\x3a\x4e\x80\x34\xeb\xd4\x36\x46\x35\x18\x5c\xe9\xc7\x08\x1d\xbd\xbe\x85\x45\xf7\x9d\x01\xaa\x53\x2a\x0d\xc5\x2c\xb7\x90\xa3\x1f\xc2\xff\x41\xac\xeb\xad\x27\xcc\xe9\x24\x45\x54\xdb\x65\x2f\xa2\x87\xba\xe7\xde\xcb\xcc\x8c\xe9\xe0\x1d\x1a\x88\xab\x41\x2b\x6c\x65\x78\x20\x3b\x42\xde\xc9\x82\xb7\xf3\xb8\x23\x14\xdb\x2c\xc7\xc5\xc3\xdc\x1d\x3d\x8b\x17\x14\x4d\xa7\xfe\x60\xe7\xa8\x72\x5f\xd0\xa9\x7c\x61\x06\x07\xcf\x41\x3c\x72"}, -{{0x08,0xb5,0xfd,0x4e,0x41,0x9d,0x23,0x70,0xc0,0xfc,0xd6,0xc3,0xb9,0x2f,0x8d,0xb3,0xaf,0xd4,0x22,0x68,0xf5,0x33,0x08,0x5d,0x9f,0xce,0x32,0xb5,0x22,0x82,0x4e,0x34,},{0xcd,0x0d,0xa6,0x99,0x37,0x9e,0x4f,0x94,0x25,0xe8,0x4b,0x97,0x57,0x30,0x0a,0x51,0xa1,0x63,0xf3,0x58,0x73,0x4c,0xc3,0x7a,0x91,0xff,0x0e,0xa4,0x88,0xd2,0x97,0x79,},{0x42,0xa1,0x37,0x56,0xb7,0x5c,0x67,0x22,0x48,0x5f,0xa3,0xf6,0x94,0x04,0x1b,0x39,0xb7,0xd7,0xc5,0xfd,0x40,0xeb,0xc0,0x6a,0x52,0xe0,0xff,0x34,0xce,0x14,0xd8,0xd4,0x0f,0xa8,0x2a,0x95,0x08,0xb5,0x68,0x53,0x7d,0x26,0xd0,0xdd,0x7c,0x0a,0x31,0xbe,0x71,0x0d,0xa8,0x0a,0xab,0x35,0x19,0x6a,0x03,0x9b,0x60,0x64,0x1d,0xb1,0xe1,0x01,},"\x3c\xee\xee\xa3\x0f\xa4\x01\x56\x3d\xf3\x6b\x19\x8b\x9b\x59\x69\x8c\x10\xe1\x00\xa2\xf3\x0e\x6f\x78\xfe\x62\xb9\x2e\xca\xc9\x89\xe8\xaa\x09\xec\x76\x0e\x89\xca\xc0\xa1\x6b\xde\x3c\xac\x73\x62\x2a\x86\x27\xef\xed\xfa\x4e\xc0\x9b\x87\x3f\x7e\x10\x00\xe7\x69\x82\x91\x0c\xa0\xaa\x4a\xfb\x1f\xf5\xa8\x44\x8b\x76\xf7\xb0\xd2\xa2\xd5\x2a\x7f\x40\xde\xde\xfc\x68\xd6\x0c\xe6\x62\x2c\xa0\x80\xd6\x69\x8e\xa6\xc3\xbd\x72\x10\xb3\xb6\x48\xf5\x32\x52\x29\x14\x94\xb3\x5a\x55\xff\x40\xfa\x1a\x63\x1a\x57\xc5\x10\x01\x1a\x46\xbf\xb9\xe2\x71\xba\xe1\xe7\x8c\xe6\xc6\xea\x60\xc5\x5b\xa0\xcc\xe3\x60\x59\xbf\xb0\x1e\x39\x45\x56\x98\x7f\x74\x4b\x72\xae\xbb\xdb\x4b\x1b\xdb\xb3\xbb\xaa\xee\x1b\x8b\x2f\x31\x74\x50\x6a\x79\x3f\x0a\x51\x1b\x2b\x56\x90\x49\xb3\x0a\x2e\x08\x41\x42\x41\x84\xa4\x8e\xca\x9e\x2d\x83\x78\x3a\xc5\xb6\x1e\xb9\x47\xcb\xd8\xba\xb7\xad\x38\xb0\xc6\x84\x27\xd8\xf9\x4a\xe2\x85\x19\x0d\xbb\x6e\x0c\x6d\x58\x0a\x25\x14\x23\x94\xbe\x94\x81\x58\xd8\xda\x83\xb4\xf3\x4a\x8d\x25\x8b\x97\x07\x56\x32\xb3\xc2\x8b\xfa\xe3\x10\x5e\xd1\x87\x2e\x35\x6e\x43\xae\xd5\x93\x97\xb9\x11\x0b\xbf\x9d\x8c\xa2\xa0\x44\xd5\x27\x1e\x6c\xc3\x61\xe1\x4e\x69\xa9\x32\x51\x76\x83\xec\x81\x81\x8f\x02\xcf\xa0\x29\x5e\x56\x61\xce\xa3\xe5\x86\xaf\xc0\xdb\x41\xba\x95\x55\x3e\xe7\x5b\x20\x0b\x0f\x97\x90\x11\x1d\x37\x57\xa7\x39\xe5\x63\x55\x7a\xff\x9b\x70\xca\x14\xe8\x7b\x79\x54\x37\xba\x91\xa9\x5d\xd0\x7e\xa6\x9a\x11\x35\x9f\x36\xca\x03\x29\x8e\x0b\xfa\x4f\x91\x2f\x64\xa2\x92\x4a\xd9\x01\x97\x5a\x2a\x96\x0b\xa1\xbe\x89\x92\x1b\x1f\x54\x85\x49\x6b\x7e\xa5\xda\x6d\x8a\x69\x37\xac\x10\x5b\xf3\x76\x0e\x48\x76\x99\x0a\x0f\x5c\x5a\x63\x4f\x74\xcb\x57\xdf\x7c\x17\x2c\x8a\x41\x53\x72\xe6\xd9\x03\x29\x87\x17\x49\x96\x16\xf8\x97\x1c\x68\xbb\xec\xe9\x2e\xa8\x78\xa1\x8e\x23\xf3\x27\xc3\x64\x9b\x6a\x85\x2e\xf2\x3b\x7b\x3e\x60\x3c\xdf\x80\x45\x2d\xbf\x1b\xe2\xfb\x77\xe8\x14\xd2\x52\x54\x96\xbb\x31\xfb\x6e\x4e\xd2\x53\x32\x48\xb3\x9d\x5f\xbe\x23\x90\xa9\xb6\xfc\xca\xba\x99\x7e\x8b\x49\xb5\x98\x36\xe3\xe0\x95\x29\xea\x5e\x41\x13\xee\xe4\x51\xc9\xc6\xbb\x26\x74\x1d\x0e\x4c\x58\x6f\x53\xd6\x04\xc6\xea\x0c\x0e\x60\xdb\x02\xe5\x10\x9f\x37\x34\xf5\x1c\xdd\x89\x85\xaf\xeb\x3e\xca\xff\x65\xe0\x59\xe3\x12\xcd\x50\xfa\x34\x9f\xf2\x8b\xdc\x9b\x70\xb7\xf5\x32\xdb\xab\x1d\xf4\x3b\x03\x16\x7c\x1d\x2e\x3f\xa6\xee\x8c\x9b\x17\x4a\x0b\x2c\xf8\xaa\x9f\xfa\x40\x6b\xf5\xbd\x72\x88\x78\x0c\x9c\x4a\x6b\x69\x79\x49\xb4\x86\x38\xd4\x20\x79\xc8\xc6\x6e\x14\xd9\xb5\x72\xa2\x10\xa0\x93\xea\xf1\xd2\xf7\xa7\x03\xb5\xcd\x20\xad\xc4\xf9\x92\x7a\x6e\xa8\xea\x78\xfa\xa6\x1b\xc6\x2b\x3c\x5c\xbd\x3a\x53\x25\x25\x66\xd0\x43\xba\x55\x65\x90\xd9\xa7\x63\xbe\x7f\xea\x4b\x20\xe1\xe9\xcf\xbe\xbf\xae\x15\x43\x9b\x33\x4d\xc5\x39\xb1\x7d\xad\xa2\xe4\x34\xe9\xc8\x32\x25\xb1\xe8\xf6\xbe\xb7\xd5\x56\xb4\x7d\x7f\x69\xf7\xeb\x7d\xf5\xed\xe2\xee\xbd\x84\xe2\x50\xb7\xc9\x46\x8c\x21\xfd\xc0\x17\x0e\xa8\xdf\x66\x2d\x61\x80\x58\x1f\x65\x7f\xe7\x6c\xef\x18\x58\xb6\xb0\x2f\x73\x25\xc7\x21\x96\x43\xfb\xa2\xf7\xe9\x96\x3a\x33\x32\x2d\x65\x04\xab\x91\xbf\x10\xa9\x78\xfa\x07\xb4\x7d\x5d\xb0\xbe\x00\x0d\xcd\x00\x2b\xdd\xaf\x67\x6b\x77\x25\x9c\x9f\x60\xad\x0b\x11\x67\x1c\xd5\x77\x7c\x1e\x80\xb1\x3f\x82\xeb\x0f\xb6\xa1\x80\xb5\x66\x62\x93\xa4\x32\x40\x86\x2f\xbf\xa3\x97\x8d\x95\x31\x19\x71\xaf\xab\x9e\x1c\xc8\xab\x14\xa8\x76\xb6\x57\x2a\xc8\xa4\xb7\xe0\xb4\x0a\xaf\x6b\x52\xa1\xcf\x4c\x1e\xbc\x6c\x1c\x48\x7d\xf5\xa3\xcb\xc4\x00\x5a\x0e\xe3\x29\xca\xbc\x28\x6d\xb1\x0f\x17\xd0\xf1\x78\x2e\x07\xd3\x32\x4f\x0c\x73\xef\xbd\x3c\x2f\xb5\x2b\x71\xf9\x8a\xd9\x5d\xb9\x50\x62\xd9\x14\x25\xe7\x34\x67\xbc\x1e\x4e\x9b\xf5\x52\xe8\xa2\x44\x29\xd9\x7d\xb1\xd6\x6d\xd4\xd9\x95\xe5\xf8\xd2\x4e\x9c\x91\x0b\x2e\xb1\x75\x8e\xf7\x55\x25\xc3\xd6\x5a\x3f\x43\x0a\x02\x73\x48\x82\x0c\xe3\x05\x3b\x6f\x3a\xf4\xec\x96\xd0\x49\x37\x31\xc8\x18\xc6\xb1\xa7\x0c\x25\x0a\xc6\x86\xa4\xfc"}, -{{0x1e,0x85,0xc9,0xe4,0x51,0xb7,0xac,0xf8,0x01,0xd1,0x6b,0xc8,0x26,0x8e,0xb4,0x2a,0xe8,0x5c,0x72,0xc6,0x8e,0x9f,0x90,0x92,0x7a,0xa0,0xf3,0xb5,0x0b,0xef,0xd2,0x29,},{0xa6,0x9d,0x05,0x7f,0x4b,0x74,0x38,0x11,0xe0,0x7a,0xc7,0x45,0x61,0xc2,0x25,0xbe,0x03,0x81,0xc7,0xd5,0x84,0x9e,0x60,0x18,0x79,0x37,0x01,0xa8,0xcb,0x6c,0x99,0xb5,},{0x6c,0x36,0xda,0x9a,0xd6,0xc4,0x56,0x34,0x3c,0xe6,0x42,0xac,0xa4,0x54,0x92,0x3a,0x52,0xa2,0x84,0x4c,0xe5,0xee,0x58,0x94,0x7c,0x8d,0xf7,0xba,0xb2,0xeb,0xe4,0x67,0x82,0x3c,0x56,0x33,0xe5,0x30,0xb1,0x67,0xd7,0x1c,0x47,0xad,0x95,0x49,0xdf,0x05,0x94,0x3f,0x99,0x42,0x1e,0x17,0x47,0x5c,0x4d,0x4f,0x08,0xde,0xdf,0x6f,0x32,0x05,},"\x18\x9e\xa9\xc8\xd9\xed\x14\xb0\xde\x82\xb4\x4c\xbd\xd5\x87\x57\xa2\x7c\x68\x38\x3f\xba\x59\x77\x61\xf9\xe8\x62\xe0\x8d\xe1\x5b\x1e\x44\xc3\xdb\x1b\xad\xbd\xe7\x69\x80\xee\x39\xe6\x99\x62\x9f\x6f\xcf\xef\x32\xd3\x6b\x33\x93\xda\x2c\xa5\xa8\x1f\x95\x9c\x8b\x0f\x1b\x80\x1b\x5f\xa4\xc4\x7c\xa3\x95\x91\xe6\x12\xa2\x43\x5c\x5b\xaf\xd7\x7a\x5c\x7a\xb7\x43\x59\x21\x09\x06\xf4\x75\x33\xb1\x87\x9e\x2a\x5a\xf5\x86\x4d\x96\x1c\x81\x46\xe2\x5d\xac\x77\x25\x55\xe0\x42\xa8\x87\x26\x14\x19\xab\x8c\x9f\x6f\x62\x56\x25\x48\x1d\xa5\xb9\x35\x26\xa1\x31\xf3\x7b\x53\x4a\x00\x50\xa8\xa4\x62\xb3\x3f\x20\xa7\xe9\x4b\x89\x15\x30\xb1\x9b\xf6\x54\xee\x95\x34\xc9\xa8\x36\x1d\x03\x63\x5d\x8d\x27\xd4\x6b\xe7\xbf\x84\x78\x1a\xd0\xd4\x2d\x1e\x7c\x48\x54\xa4\x9b\xa1\xba\x45\x82\x62\xfe\x5e\xa1\x90\x21\xb9\x35\xa6\x94\x94\x92\xd7\x0b\x60\x5e\x15\x19\x89\xef\x26\x41\xb2\xbf\x81\xec\x4b\x92\x02\x0f\xc7\x07\x4c\x2a\x63\x22\x9d\x51\xa9\x44\x18\x6a\x28\x89\x5e\x8e\xa9\x52\x92\xc2\xf8\x72\xbb\x21\xa3\x14\x93\x99\xe2\x3c\xcd\x8e\x2f\xc4\xf1\x7a\x46\xb5\x9c\x28\x2c\x51\xb5\x8d\x00\x26\x6a\x5c\x16\xb1\xce\x35\x0d\x54\x85\xe8\xd8\x01\x6d\xd0\xa5\x0a\x59\x84\xcc\x94\x81\x54\xcd\x5c\xe7\xcd\xa0\xee\x0a\xb1\xd7\x25\x1b\xdc\x70\xa1\x78\x5b\x8e\x91\x03\x91\x7f\x4b\x91\x7a\xb2\xb4\x94\xf3\x48\x33\x89\xa2\xf9\x23\x75\x41\x84\x9e\xd3\xbd\x56\x5c\xff\xac\x9e\x75\x6d\xb5\x6e\xf5\xe2\x34\x95\xbc\x77\x1e\x88\xbf\xfa\x87\x07\xce\xea\x5c\x09\xbe\xca\xdd\x05\x9a\xb8\x89\xd1\xdf\x7e\x88\x7b\x71\xa9\xe6\xc2\x38\x37\x8f\xbe\x0c\x36\x30\x38\x66\x16\x36\x3f\x20\x7b\x16\xc3\x27\x0d\x39\xac\xde\xd5\x11\x52\x99\x92\xf4\xe5\x98\x78\x91\x21\xd3\x16\x13\x58\x10\x63\x6b\xaa\xde\x8a\x28\xed\xc6\x6b\xbf\x5e\xde\x3f\x40\x4a\x70\xb4\x7d\x35\x98\x8b\xe7\x06\xb4\xea\xa0\x30\x23\xa3\x90\x93\xd5\x83\xcd\x4c\xd8\xbf\x4c\x74\x34\x1a\x02\x8c\x19\xd6\x0d\xa3\x1b\x6a\x7a\x03\x4c\x08\x1a\x2b\x03\x0f\xeb\x3c\xd2\xf0\x3d\x0f\xaa\xbf\xfb\x58\xe3\xfc\x36\xc0\x06\xcf\xb9\x29\x47\xa7\xde\x5b\xa8\x74\x76\xc1\xb0\x51\xe1\x82\x83\xc0\x3e\x9c\x6e\x5a\x5c\x3c\x27\x77\xd9\xa0\x75\x73\x72\x37\x96\x64\xe8\x2f\x84\x85\x82\x4f\xed\xb7\x0a\x4b\xc4\xe3\x56\xed\xd1\xb5\xce\x0f\xb6\xe4\x1d\xe0\x17\x16\x21\xb8\x4f\xaf\xa0\x01\x89\xaf\xa8\xa6\xa9\x00\xb1\x4c\x70\x75\x8f\x7a\xa4\xfb\x82\x40\x0e\x0d\x18\xab\x3c\xd7\xe4\x8a\xcf\xd4\x89\xca\xb0\xe7\x2e\x71\x9f\x79\xa0\x7d\x06\x6c\x53\x1a\x89\x1c\x55\x29\x1f\x22\x45\xdb\xbe\xe4\x4e\x52\xb1\xdf\xc8\x72\x7a\xae\x38\x7a\xb9\xe7\x19\x94\xa3\x85\x4e\x1a\xdd\x73\xd9\xa7\x96\x5c\x77\x55\x21\xc2\xf5\x40\x84\x22\x76\xdd\x30\x9e\x2f\x6a\x34\x1e\x7f\x0f\x37\xf2\x2b\xb6\x62\x7b\x6e\x9c\xb2\x5b\xa2\x4c\x6c\x4f\x4e\xb9\xf5\xe7\x62\x2d\x88\xda\x19\x84\xe2\x9c\x5d\xa0\x01\x03\x9c\x44\x04\x2b\x59\x35\x14\x06\xa4\x13\x36\xdd\x77\x2d\x49\x7d\x3f\xc8\xaa\xc4\x11\x72\xeb\x5a\xa6\x41\x7f\xe4\x22\xec\x7c\x15\x0b\x96\xb0\x45\x4e\xe3\x31\x24\x7c\xb1\x53\x8a\xef\xf3\xec\xa2\xd5\x0e\x53\xd6\xd1\x31\x70\xa7\x6a\x00\x49\xea\x0c\x05\x90\x4a\x63\x90\xed\x14\xce\x74\x91\xe9\x7f\x75\x4c\x52\x22\xda\xc4\xb6\x11\x8b\xa3\x81\xf5\x52\xe7\x3e\xa8\x49\x1e\x3b\x7a\xc9\x49\x56\x9b\x56\x9c\xf2\xd2\x9a\x80\x41\x0e\x06\x5b\x5c\xc4\xa4\x66\xbb\x04\xeb\x7a\x15\xf5\x96\x79\x2e\x84\x90\xba\x70\x02\xec\x36\x15\x71\xaf\x5d\x8f\x57\x67\x5c\x95\x64\x49\x47\x0a\x2f\x99\x55\x40\x73\x67\xe4\x09\xa2\x32\x89\x95\x53\x12\x0a\x27\x7d\xb8\x63\xe9\xa8\x2d\xda\xba\xe8\x7b\x78\x91\x45\xba\x89\x8d\xf3\xc2\x8b\x96\xfb\xe3\x01\x4c\xd0\x85\xc6\xe6\x0e\xe8\x83\x17\x01\x03\x6d\x99\xc5\x42\x5d\x58\xe8\xbc\xc9\xfd\x92\x71\xd4\x6a\xec\x1e\xb9\x55\x13\x01\x02\xea\xaa\xb4\x4e\x07\x70\xc3\x0b\x2b\x12\x7e\xfb\x0e\x5f\x8a\x3f\x7a\x0c\xa3\x4e\xc9\x98\x4a\x46\x01\x1b\xc2\x6b\xfd\xe0\xc0\x81\x9b\xb5\x47\x06\xb5\x65\x63\x8b\x75\x42\xdc\x4b\x8b\xf8\x09\x8d\xc0\x1f\x16\x1b\x3b\x12\x96\x18\xb5\x9a\xde\xd3\x3c\xb5\x9c\xe9\x18\x9a\x67\x62\xdb\xae\x5b\x0d\x34\xb7\x1c\x8d\xbf"}, -{{0x51,0xcf,0x86,0x8f,0x82,0x0e,0xed,0xa0,0xdb,0xd1,0x01,0x80,0xf7,0x77,0xe6,0x06,0x5c,0x93,0xa4,0x83,0xc5,0x8a,0x77,0x8b,0x67,0xe7,0xd8,0x42,0x30,0x2f,0xb7,0x67,},{0xab,0x08,0x8f,0x50,0x2f,0xbc,0xf2,0x15,0x0e,0x48,0x46,0xb3,0x4d,0x2c,0x80,0x97,0xff,0x01,0x3c,0x02,0xa8,0xb9,0x7c,0xfc,0xf2,0xb9,0x5a,0x1c,0x72,0xdf,0x3e,0x24,},{0xe1,0x53,0x42,0xa1,0x1c,0xaf,0x89,0x28,0x95,0xe4,0x66,0x22,0x88,0x63,0xd0,0x83,0xb0,0x69,0x2f,0x01,0x06,0x10,0x74,0x8c,0x23,0xdf,0x2f,0x11,0xd2,0x94,0x75,0xba,0xfc,0xe9,0x27,0xca,0xfe,0x7f,0x07,0xef,0xb8,0xc3,0x47,0xed,0x56,0x63,0xe7,0x3b,0xea,0x89,0x53,0x1c,0xed,0xc0,0xc3,0x48,0xe7,0x9b,0x6e,0x58,0xa7,0x57,0x49,0x07,},"\x7c\x2d\x8e\xe8\x2d\x9a\xbf\x8a\xa9\xc7\x24\xc7\x5b\x90\x99\x04\x73\xf1\x31\x76\x3f\xe9\x3b\x30\xcb\x04\x72\x35\x88\x62\x1d\xa2\xa3\x27\x92\x8b\x22\x64\x9f\xa0\x62\xcd\xea\xbd\x77\x76\x15\x38\xb2\x70\x9b\x8f\xb7\xa2\x00\x6e\x50\x35\x09\x13\x4c\x92\x9c\x30\x11\xe1\xd7\x28\xa5\x7a\x4e\x17\x51\x98\x07\x5e\x21\x42\x53\xf3\xf3\x0e\x01\xb6\xe0\x4e\xab\xd4\xde\x06\x78\x95\x58\xe6\x98\xb1\x86\xef\xe3\x4b\x32\x12\x95\x68\xb3\xe8\xd0\xd7\xea\x3f\xf0\x0b\x3f\x25\xa4\x22\x36\x89\x3a\xa8\xa4\x1b\x67\x4a\x0a\xb5\xf4\x1e\x7b\x28\xcf\x5a\x7c\xb7\x65\xe1\x8e\xad\x6d\xe6\xa3\x53\xa7\x82\x4a\x3c\x49\x78\x60\x38\xd6\xf4\x93\x7f\x32\x64\xd6\xcc\xf0\xc0\xa2\x46\x5b\xb6\x93\xe5\x2b\x3d\x1e\x6e\xb9\xae\x4c\xb6\x5d\x09\xcf\xf5\x48\x42\xe8\x53\x62\x85\x7a\x59\xf7\x19\x8a\x68\x8a\x3d\xf3\x85\x13\xcd\xd6\x1e\x21\xdf\xd8\x59\x14\x2c\x83\x44\xa3\xb8\xb2\xa7\xc7\xdb\x17\x0f\x39\xf8\x7c\xa3\xff\x8e\xd4\x27\x96\x2b\x2b\x1a\x14\xd1\x22\xfa\x2d\x5a\xea\x2a\x66\x40\x11\x7d\xd2\x58\xfa\x0f\xc5\x4a\xc6\xe9\x40\xbc\x16\xd2\x11\xec\x9a\xdf\x91\x4a\xb1\x65\x78\xf5\x21\xf6\x55\xd2\x12\x7e\x79\xe8\x71\xbf\x7f\xa7\x54\x47\x19\xd5\x8e\xd8\x47\x85\x0c\xb2\x7b\x99\xeb\x8f\x29\xb1\x6c\xdc\xc2\x8b\x15\xc1\x25\x9a\xb4\xd5\x89\x70\x5a\x40\x66\x88\xf6\x05\xa2\xeb\xf5\x80\x51\xc4\x3a\x77\xc4\xe0\x1f\xd6\xf7\x49\xd3\x2d\xb4\xe8\x9f\x26\x3c\x2c\x16\xde\x18\x1f\x0e\x6b\xdd\x0a\x6a\x64\xff\xe6\xf1\x82\x94\x44\x09\x6d\x9f\x3e\x2b\x67\xe4\xbb\x00\x66\x50\xb5\x92\x9d\x1f\x82\xeb\x11\xbb\xed\x24\xe8\xf1\x01\x8a\x73\x84\x60\x5a\x3c\xf2\x9a\xb5\x98\x33\x79\x39\xc7\x6a\x3b\xe8\x61\xe4\x83\xc5\x80\x5e\xc3\xce\xe4\x5e\x34\x24\x84\x7a\x08\x55\x8d\xcc\x99\x49\x9f\xb9\x38\x2a\xca\xe5\x6c\xdc\x87\xfb\xd5\xb2\x6f\xf9\x4c\x86\xf2\xe1\x08\x79\x43\x83\x50\x1c\x8b\x33\x36\x68\x50\xa7\x6a\x0d\xfc\x0a\x7c\xd7\x89\xa0\x3f\x01\xa3\xe9\xd9\xe9\xae\x39\xfd\x72\x45\xdc\x29\x29\x9d\x24\xf3\xb4\xb1\x67\xca\xcc\xd2\x23\xa9\x9b\x6b\x20\xa3\xb6\x73\xdc\x5f\x74\x66\xd0\xb2\xf8\x15\x09\x8a\x49\x7c\xca\xf8\x04\x20\x16\x8e\xdd\xbf\x4d\xa5\x7b\x86\x66\xe9\xd3\x3c\x48\xeb\x30\x4b\x4c\xfc\xf4\x57\xcd\x76\x59\x54\x3f\x6d\x1e\x66\x18\x90\xf5\x62\xb4\x3b\x8b\x6d\x1c\x4d\xcc\x07\x7b\x60\xbf\xa5\x33\xff\xab\x92\x8d\xbf\xd9\x55\xdc\x51\x16\xd7\x70\x95\x0b\x69\x0e\x21\x06\xad\x52\xd4\x2c\x31\xc2\x2b\x88\x48\x89\x43\x32\xb5\xc6\x99\xe5\xc3\x31\xfb\x38\x1e\x58\x12\xe7\x52\x6f\xdf\x4b\x8a\xa2\xda\xaa\x2c\xa2\xcf\xb9\xc9\x21\x11\xb6\x1c\xbc\x3d\x1e\xef\x6c\x8c\x67\x37\xf0\x55\x88\xf0\x44\x67\xdb\x83\x30\x84\x3a\xcc\x98\xdc\x1a\x16\xfb\xd9\xd9\xd9\x4b\xd8\xbf\xde\x26\xc3\xf7\x1d\xee\x72\xb5\x09\x10\xc3\x6b\x24\x0f\x80\x2a\x61\xca\x16\x37\x2f\x6f\xfa\xad\xb2\xbe\x4e\x85\x3c\x5e\xd6\x9a\x3d\x1f\x6c\x7b\x2d\xe5\x13\xc5\x3a\x3f\xdd\x0a\x67\x6f\x83\xd0\x9d\x5c\x51\x17\x60\x47\xd9\x20\x07\x16\xbf\x22\xba\xe4\x5f\xe0\x1b\x3e\x0c\x2c\x51\xc1\x6e\x46\xad\x06\x37\xf7\x9f\x9b\x4d\x83\x86\x77\x04\xfe\xda\x9f\x22\x78\x31\xde\xa2\x63\x39\x9c\xa2\x77\x1a\x4e\x78\xb4\xdf\x8a\xc0\xde\x6a\x94\x1e\xab\x37\x0b\x1f\xdb\x47\xda\xf6\x64\x2a\xae\xaa\x63\x17\x0f\xa9\xb3\xd1\xe1\x62\x8f\x7c\x4e\x7c\xf0\xea\x8b\x8a\x8e\x51\x8c\xba\xce\xf9\xad\xe8\x4d\xf0\x32\x48\x48\x47\xff\xb6\x1b\xbd\x07\xe8\x72\x7c\xc4\xc2\x5d\xa5\x77\xb2\x64\x51\x9b\x49\x99\xfa\x7c\x0b\xc3\x23\xd4\xf3\xf9\x73\x9f\x78\x0b\x9b\x2c\x23\xc7\x78\x55\xee\x5f\x6d\xcc\x40\x15\x44\xd6\xb6\x4b\x27\x70\x15\x8f\xdc\x6c\x12\xf4\xd8\x9b\xeb\x04\x4e\x0e\x85\xac\x7a\x68\xd4\x29\x17\xb1\x34\x51\x14\xb9\xa6\x72\xd1\x23\x1b\x2c\x6c\x0f\x96\x9f\x20\x35\x31\xe7\x1b\xbb\x40\x05\xb1\x03\xa7\xdc\x3a\x58\xb5\xb8\x24\xa7\xe0\x1b\x6e\xb9\xf4\x96\xdf\xa6\x4d\x64\xd8\xc6\x77\x7f\x53\xaa\x58\xd5\xda\x04\x6d\x72\x6f\x55\x45\x4c\x88\xb6\xd7\xd4\xab\x0d\x21\x98\xa8\x97\x09\xf1\x18\xa6\xb3\x24\x60\xb9\xeb\xce\xff\x3f\xdd\xc6\x05\xda\x77\xef\x3d\x1b\xa3\x0f\xec\xf0\x7b\xe2\xf5\x31\x3f\x4e\xe6\x35\xaf\x5e\x95\x61\xd8\x77\xe9\x9c"}, -{{0x54,0x3d,0x5f,0x1d,0x4a,0x6e,0x10,0x29,0xb1,0x91,0x41,0x38,0xfb,0x1f,0x46,0x59,0xe6,0x94,0x56,0x55,0x72,0x07,0x40,0x66,0x88,0xa2,0x03,0x5c,0xbb,0xb2,0xa6,0x8a,},{0x3c,0x83,0x79,0x0c,0x3b,0x45,0x53,0xde,0xae,0x4f,0x84,0x3b,0x50,0x1d,0x26,0xf6,0x16,0x70,0x93,0xee,0x54,0xe2,0x79,0x75,0x9f,0xfa,0xd8,0xcb,0xc0,0x61,0xe7,0x20,},{0x55,0x20,0x11,0x94,0x02,0x6f,0xd6,0x44,0x8b,0x1d,0x52,0xf8,0x3e,0xd2,0x0a,0xc2,0x84,0xe7,0xe7,0x7f,0xa9,0x2d,0x52,0x95,0xd3,0x38,0x25,0xce,0xa3,0xac,0xa4,0x7e,0xc7,0xaa,0xca,0x2f,0xc0,0x86,0x79,0xf9,0xac,0xfc,0xed,0xb3,0x76,0xfd,0xa4,0x61,0x9b,0xe3,0x27,0x2c,0x74,0x45,0xe8,0x70,0x5c,0x30,0x61,0x41,0xcd,0xe1,0x6c,0x0f,},"\xfe\x00\x57\xf0\x62\xfc\x87\x13\x24\xb8\xbd\x5d\x42\x7e\x9a\x52\x76\x23\x1b\xd3\x09\x90\x7e\x58\x81\xd7\xae\x53\xb1\xf3\x70\xc2\xa4\x33\x02\xa1\x65\x10\xb4\x60\x64\xa3\x07\x36\xba\xc9\x09\x51\xf1\xd9\x88\x1a\xf6\x2c\x70\x14\x83\xeb\xb9\x27\x2a\xd7\x72\x12\xee\xb5\xfc\xbc\x7e\xc2\x28\xd9\x69\xf8\x90\x27\x32\x11\x3b\x98\xe3\xbf\x82\xdf\xea\xdd\x0d\xe5\xe7\x65\xd2\x87\x0b\x12\xd1\xf9\xb5\xa2\x82\x97\xc9\xfd\xd1\x49\x5c\xf8\x77\x89\x19\x6a\x7d\x64\x4e\xec\xd9\x35\x87\xdb\xf2\x0c\x28\xeb\x09\xda\x28\x66\x03\xc5\x82\xd2\x12\x9a\x65\x7d\xb2\xd1\x7a\xdd\x35\x58\xdd\xe0\x29\xce\x27\xb8\x83\x52\xde\x3f\x95\xab\xa1\x7e\x1e\xd1\x91\x37\x22\xdb\x08\xa7\x95\xdf\xbb\x70\xd6\x2a\x88\x02\x72\x4c\xb0\xf5\x35\xf8\x48\xd0\x52\xaa\x3d\xde\x91\x66\x96\x3a\x80\x41\xfc\xcc\x4e\x60\xbf\xb1\x1d\xe2\xbf\x28\x6e\xb6\x02\xa4\xaf\x84\x2f\x4d\x1a\x34\x0d\x78\xbb\xbc\xb2\x85\x7f\x0c\x30\x8f\x44\xbb\x10\x1e\x7b\xc8\xb7\x41\xd5\x06\x09\x4e\x27\xbb\xaf\xa7\x24\x28\xef\x66\x6e\xa6\xea\x16\xf7\x99\xb4\xee\x58\x27\x8f\x04\x59\x74\xd8\x6d\xc7\x2c\xf5\x26\x0d\x96\xf9\xc0\x9b\x2f\x11\x81\xe1\xa4\x50\x0f\x92\x83\xdc\x67\x7f\x38\x4f\xf6\x4e\x51\xe8\x9f\x76\x58\x20\x20\x32\x6c\x38\x8c\x08\xa0\xfd\x00\xde\x73\xd5\xd4\x9c\x06\xc0\xc6\x84\x19\x1a\x26\x4f\xff\x72\x6d\x87\x2d\xc3\xae\x49\x6c\x7b\x47\x8c\xfc\x61\xb5\x17\x14\x19\x2f\x76\x46\x3e\x3d\x0a\xab\x41\x0e\xa1\x15\xe8\xbe\xfe\xdb\x99\x7d\xdd\x16\x99\x21\xb3\x20\x7e\xa6\x6c\x1f\x59\x45\x0b\x76\x23\x12\x9f\xd1\xe2\xdd\x3d\xa8\xf5\x20\x63\x91\x17\x13\x38\xea\x0e\xc8\xef\x3c\x59\xed\x8a\xfc\x69\xf3\x86\x5c\x29\xa0\x72\x3a\x9b\xbe\x95\xa7\x42\x68\x1e\xf9\x85\x7e\x81\xab\xc8\x0c\x92\xd2\xa7\x18\xa8\x04\xf5\x30\x4f\xef\x3c\x63\xd7\x99\xa6\xef\x87\x82\xa7\xdb\x46\x68\x1d\x0d\xe3\x50\x64\x46\x98\x22\x67\xb2\x15\x2b\x0c\x32\x18\x69\xe2\x3c\xce\x8c\x4e\xbe\xbe\xaf\x4a\xa1\xeb\xe9\x28\x3b\x69\x26\x05\x26\x0f\xf6\x21\xb0\x3c\x10\x82\x2a\xa5\xf6\xd0\x3b\xde\xf4\x9c\x46\x2a\x68\xd4\x71\xe8\x49\xe1\x64\xe3\x87\x4f\x6e\x9f\x6c\xb3\xb5\xf2\x93\xeb\x38\xae\x52\x45\xa1\x59\xec\x42\x61\xa9\xbf\x6b\x5f\x7b\x76\x15\xfd\x33\x9e\xa1\x27\x33\x11\x3c\xe7\x67\xf8\x83\xae\x66\x75\x41\x7f\xc7\x70\xb5\x0b\xd6\x0e\x6f\x20\xad\xdb\x29\xc1\xf7\x50\x62\x33\xe3\x2a\x7e\xbf\xad\xab\xff\x98\xcf\xd0\x9b\x2b\x3b\xbd\x3e\xae\x00\x69\x54\x8b\x9d\x89\x87\xaf\x46\xca\x98\xeb\x09\x5b\xac\xbd\x87\x47\x24\xba\x10\xf3\x63\x3a\xa0\x8a\xb6\xec\x26\x49\x4d\xdf\x68\x54\x30\x9b\x55\xd4\x3b\xdb\xd2\x9a\x75\x56\xf1\x2d\xfb\x23\xcd\x0d\xb4\xeb\x39\x37\xa6\x5c\x4a\xed\x96\xe8\x7b\x34\x65\x55\xf9\xfc\x68\x97\x94\x3a\x0f\xae\xe6\x5c\xcf\x39\x4b\xd8\x9b\x38\x1b\xee\xce\x25\xd1\xba\x68\xf8\xfe\x32\xc2\x3b\x33\x54\xf5\xbe\x7e\x3e\xa3\xc0\xde\xc0\xf7\xec\x2d\xd8\x3f\x92\xb7\x30\x58\x89\x2b\x63\x8d\x4c\x3b\x72\x42\xbb\x8f\x55\xbf\x08\x7b\xa4\x5a\x19\x0a\x69\x8b\xae\x67\x5e\x0c\xd5\xe8\x44\x6f\x2b\x21\xae\xb6\x3d\x2c\xae\xa0\xf6\x79\xa8\x37\xe7\x93\x57\x30\x8d\x9f\x0b\x8a\xf3\x1f\x9d\x08\x00\x8c\x39\xee\x8d\x34\x75\x28\x71\x3c\x88\x50\x01\x7a\x7f\x4a\xb9\x8a\x35\xc7\x53\x19\x40\xfa\x76\x21\xe6\x72\x03\xee\x78\x2d\xb3\xa2\xfa\xa3\x0f\x3a\xa8\x50\xa5\xff\x7a\xae\xd8\x4c\x00\xff\xd2\x14\xf2\xc9\x26\x17\x35\xfa\xc3\x25\x9d\x50\xe0\x3c\x26\x52\x50\x52\x79\xd9\x12\x51\x92\x7d\xe5\xe5\x6a\x8b\x90\x64\xcc\xf9\xf4\x5d\xcb\xef\x46\xe1\x18\x9c\xed\x2b\xc7\x9e\x6f\xf6\x52\xe6\x90\x97\xac\xe5\x56\x8b\xb2\xd5\xbe\xf3\xce\x21\xa2\x5b\x3f\x79\xee\x27\x5e\xa3\x4e\x62\x13\x80\x56\x6d\x70\x4c\xd9\x3f\x24\xdd\x90\x20\x93\x2c\xc0\x52\x18\xc2\x3b\x5b\x22\xff\xfa\x7e\x99\xee\x7f\xe4\x57\x87\x6a\x5e\x33\x64\xc9\xa8\xe8\xb0\x49\xcf\xa2\x09\x69\x77\x4f\x50\x6d\x19\x96\xcb\xe6\xef\x5a\x37\x79\x3e\xcd\xb0\x4c\xfd\xea\xed\x7d\xcf\x79\xab\x27\x84\x74\xdd\x77\x08\x22\xd4\xb3\x6f\xc6\x8e\x4b\x2d\xd6\x61\xef\x99\xde\x01\xde\x6e\xec\x57\xfa\x57\x3e\xde\x10\xfb\xbd\x5a\xc6\xfd\x6c\xd8\xbb\x4e\xee\x50\x9d\xbb\x46\x10\x37\x44\x01"}, -{{0xf8,0xd2,0x57,0xfd,0xfc,0xf9,0x97,0x96,0xf8,0xce,0x4d,0x8a,0xad,0xe3,0xb2,0x25,0xa5,0x3c,0x26,0xfe,0xec,0xef,0x39,0x5b,0x95,0x61,0xd9,0xd5,0x87,0xf5,0xa3,0x3c,},{0xf6,0x6b,0xd4,0x87,0x7d,0xf7,0x8a,0xec,0x04,0xca,0x7e,0x77,0x73,0x28,0x99,0xde,0x06,0x77,0x7e,0x69,0x86,0x29,0xf2,0x99,0x69,0xf8,0xfa,0x9c,0x2f,0x47,0xab,0x9e,},{0x92,0x35,0xd4,0x48,0x07,0x86,0x98,0x16,0xe2,0x8e,0x42,0xc8,0x1c,0x80,0x1f,0xfb,0x12,0x1d,0xe8,0x26,0xc0,0xd3,0x3d,0xcc,0x4a,0x4e,0x1c,0x93,0x2d,0x52,0x28,0xb6,0x39,0xbb,0x29,0x4e,0x16,0x09,0x0a,0x93,0xd1,0xf6,0x90,0x4a,0x70,0x04,0x22,0x2f,0xda,0x0a,0x55,0x44,0x6d,0x99,0x01,0xc7,0x23,0x40,0x00,0x7b,0xb4,0x5a,0xe1,0x03,},"\x23\x3e\x1e\xf9\x01\xab\xcb\x69\xfb\x48\x60\x85\xd8\xdb\x02\x33\xff\x78\xf3\x7b\x13\x6f\x0a\xfe\x24\xf7\xda\xc1\x94\x4c\x36\x78\xe7\x4f\xed\x58\xa1\xad\x54\x83\x5b\x7d\xbc\xb4\x6f\xff\x6c\x35\x24\x31\x22\x73\x30\x0b\x6d\x87\x8a\x93\xe0\x60\x8a\x4a\xba\xca\x4e\x31\x94\x72\x2b\xb9\xe2\x3d\x17\x19\x4d\x86\x67\xb8\x4f\x2d\xb0\x38\xc2\x4e\xfb\x8f\x53\x40\x9c\xf5\x59\x4f\xdd\xb8\xbc\xd6\x1f\x74\xcf\x07\x26\xb5\x1c\x65\x1c\xe0\x1e\xb6\x6a\x59\xb4\x55\xf7\xd8\xa7\xd6\x0d\x39\x27\xe0\xc6\xc5\x4b\x13\x8e\x01\x92\x53\x71\xd2\xd9\xd9\x62\xaa\x98\x2f\x5e\x60\x85\x28\x0c\xc0\x5f\x35\x69\x93\x91\x1f\xd2\x03\x9d\xfc\x34\x21\x17\x97\x02\x91\x38\x1d\x82\x02\x7d\xb3\x6c\x79\x91\x00\x05\x7d\x93\x52\xb2\xcd\x87\x9d\x9c\x82\xaf\x73\x4b\x7f\xa2\x97\xd2\x11\x49\xc9\x78\xaa\x5e\x12\x5b\x20\x37\x2a\x9b\x2e\x0e\xd3\x57\x33\x7e\xfa\xea\x13\x91\xf3\xb9\xef\x11\xe3\xe5\x13\x5b\xb7\x0b\xdb\xe3\x2a\x9b\xdb\x7c\x3c\x42\xd5\xd5\x7c\xc8\xda\xb6\x81\x16\x28\xa0\x10\x89\x49\x5c\xb8\xa4\xa7\x6a\x48\x29\x6c\xd8\xdf\xaf\xc0\x05\xad\x49\xd7\x0b\xb1\x9f\xac\xa2\x08\x4a\x1b\x6f\x5e\x48\xd2\x3c\x03\xfb\xcf\x6f\x10\x6d\xb7\x70\xf0\x7c\x33\xe8\xe7\xf4\x75\x7d\xa9\x04\xa4\x4d\xd0\xe7\x38\xf3\xd5\x73\x3a\x32\x93\x75\xce\xd7\x4f\x3c\x42\xbf\xcd\xbb\x91\x01\x00\x45\x5d\x6a\xa7\xd2\xe3\xe3\xaa\xa5\x8a\x82\x96\x30\xd3\x76\xb0\xb4\x66\xdc\x85\xaa\xc4\x8f\xe2\x69\x94\x6a\x7b\xc7\x2d\x91\xeb\x37\xde\xd2\xf4\xa7\x7c\x68\x4b\xe0\x10\x93\xfd\x12\xde\x9d\x9d\x83\x19\x9c\xcc\x50\x95\x9a\x48\xd6\xe9\xa4\x14\x27\x56\x60\x92\xf0\x4a\x0f\x95\xca\x52\x37\x2e\x07\x62\xb9\x66\xce\x62\x32\x05\x5a\x4f\xd7\x57\xc6\x1b\x8b\xad\x83\xba\xef\x91\xa3\xc2\x77\x2f\xb3\x2e\xad\x8f\x59\x1a\xc1\xe0\x2b\xbf\x90\xa7\xf6\xc3\x90\x79\xb8\x6f\xb8\x14\xcc\x24\x2e\x98\x0f\x0b\x8b\x1a\x2c\xec\xb8\xe6\xd4\xe8\xa5\x21\x1b\xf8\xba\xbf\x38\xe8\x29\xab\x98\x83\x60\x8b\xd6\xd5\x9e\xa5\xe8\x36\xa9\xb4\xa4\xfb\xed\xed\x1b\xea\x2f\xfe\x97\x7e\x8c\xf3\x61\x5c\xa4\xa5\x0f\xea\x1f\x05\xf1\xfe\x53\xc8\xea\xc5\x00\x32\x3e\x1f\x52\xa8\x06\x83\x15\x39\x95\x79\x88\xd7\x9a\xcc\x7b\x54\xf7\xd0\x2b\x48\x0c\x46\x9f\xd6\x95\x40\xfe\xa4\xbd\xd6\x8c\xbd\xc6\x8c\xf9\xc7\x87\x2f\xd7\x92\x59\x1b\x01\xe9\xd9\x90\x2d\x8a\x61\x4f\x4c\x21\x82\x3f\x23\x50\x8f\xfd\x49\xff\x21\x8b\xea\x92\x2e\xc1\x41\xef\xf6\x0d\xa1\x77\xcc\xad\x7d\x7b\x9d\x44\x4f\x3b\x03\x45\x81\x15\xf1\x16\xcc\x6e\x37\x62\x5c\x39\xcb\xad\xf0\x93\x62\xf3\x1d\x33\xf4\xc1\x3c\x33\xb6\x29\x20\x07\xf2\xca\xfd\x19\x4f\x62\xc6\x43\xe7\xa2\x55\x71\x56\x4f\xeb\xad\x7d\x33\xe3\x64\xb6\x33\xd0\x08\xb0\x90\xd7\xa0\x91\x35\x8b\xc6\x9c\x56\x7b\x95\x22\xb5\xc1\xcd\x01\x21\x8d\x38\x52\x9a\xeb\xb0\x3d\x9c\x2a\x5e\xb2\x28\x5a\x71\x76\xf9\x8c\x28\x03\x6f\x21\xe1\x9e\x92\xb4\x06\xe9\x48\x95\xfa\x28\x1b\x35\x22\x8f\xbf\x76\xe7\x3e\x17\x58\xaf\x1b\x43\x4a\x4d\xf9\x8e\x8c\xc5\x56\xb9\xd8\x3f\x6b\x0b\x7f\xf5\x2c\x68\x0f\x65\xef\xe4\xe0\x0c\x59\xb4\x6c\xe5\x93\xbf\x98\x89\x98\x05\xd0\x2b\x91\x65\xb7\x42\x98\x49\xe7\x39\x53\x77\x0a\xe3\x93\xe4\xf1\xf9\x7c\xb9\x0c\xd6\x15\x9c\xc9\x39\x52\xae\x8a\x4d\x3d\x56\xa9\xa9\x5d\xf7\xcf\xab\xac\xd4\xd0\x30\xd7\x36\xea\x45\x4d\xfa\x4b\x4a\xed\x1b\xcd\x88\x5d\x2f\xbe\xa5\xff\xa2\xcf\x29\x27\xc1\x37\xc8\x6b\xe4\xfe\x01\x64\x12\x62\x8f\xe7\xa0\xa0\xf0\x2b\x6b\x6a\x9a\x21\x68\x93\x2b\x94\x3f\xf8\xb2\x8d\xd5\x87\xe7\x72\x87\x79\x0a\xaa\xa6\x9a\x98\x50\x6c\x76\x4e\x6f\x5b\xa6\x33\x8c\x09\xf3\x82\xe1\xb9\x87\xd9\x9f\x14\xa3\xe1\x95\x8c\xb6\x2a\xe6\x70\x5a\x57\x7f\x9f\xfc\x67\x30\x64\x01\x12\x87\x41\xa8\xd0\xaf\x03\xc0\xaa\xaf\x6a\xf0\x6b\xd8\x8e\xe4\xb0\xaf\x67\x03\xe0\xea\x60\xb0\x40\x9a\xce\x24\x57\x2f\xb3\x86\xe0\x7e\x9c\x22\xc9\x68\x6b\xdc\x66\xd4\xfc\xf3\xc7\x46\x1d\x38\x33\xa4\xc3\x01\x32\x43\x60\x7d\x4d\x15\x82\x17\x18\x73\x26\xdf\x51\x72\x5a\x6b\xc5\x11\x6e\x99\x0b\xef\x8a\x5a\x95\x79\x60\x02\x07\x20\x6b\xfc\x3a\x6d\xcf\x07\x46\xef\x75\x6f\xd9\x39\xe1\x87\xf6\x68\x75\x07\x16\xc0"}, -{{0x8d,0xa9,0xf5,0x4d,0xa0,0xb6,0xa5,0xa3,0x89,0x85,0xb8,0x8b,0x71,0x33,0x9d,0xc7,0x38,0x4c,0xfd,0x5a,0x60,0xbe,0xe1,0x59,0xc3,0x94,0xc2,0x23,0x63,0xbc,0x7e,0xdd,},{0x1a,0xc1,0xa8,0xed,0xeb,0x21,0x7a,0xe9,0xb3,0xa3,0xde,0x53,0x0d,0x24,0xd8,0x3e,0x11,0xfb,0x65,0x38,0xcc,0x70,0x9b,0x52,0x99,0x4f,0xa9,0xc3,0xf1,0xfa,0xdd,0xc8,},{0xf6,0xdc,0xc2,0xd2,0x7b,0xaf,0x16,0xc4,0xf4,0x81,0x7f,0x87,0x49,0x91,0x57,0xd3,0xac,0x1f,0x84,0xed,0x39,0x8a,0x5e,0x8b,0x0d,0x50,0xf4,0x2e,0xdd,0x73,0x85,0xcf,0x06,0x33,0x7a,0x02,0x36,0x10,0x99,0x70,0xb7,0x9c,0xa0,0x9d,0x7c,0x98,0x31,0xc8,0x76,0xa8,0x02,0x79,0x94,0x21,0xc2,0xab,0xd0,0x75,0x87,0xf5,0xeb,0x66,0x16,0x0f,},"\xbd\x53\xba\xba\x66\x57\xd8\xdb\x8b\xec\xae\x6e\xab\xff\xa5\x2b\x01\x5a\x5a\x05\xfd\xd2\xe0\x70\x64\x7d\xe9\x6f\x9c\xa4\xdd\x21\x9f\xe0\xda\x60\x8f\xa0\x44\x7f\x46\xd1\x7c\x9a\x35\x82\x44\xcd\x54\x08\x59\x65\x82\xcc\xd3\xcd\xd0\x15\x1d\x6f\x09\x23\xe6\x3d\x16\x68\x37\x84\x5f\x27\x3f\xca\x7a\xf6\xc8\x9d\x8d\x52\x46\x17\x5c\x21\x67\xfb\xb9\xc2\xeb\xf6\xa7\x59\x54\x91\xf9\x7a\x97\x13\xb0\x2b\xdf\x41\x3e\x20\x9a\xb2\x2d\xb7\xdd\x2b\x37\xfc\x49\x43\x69\x18\xcc\xeb\xe5\x74\x6b\xc6\x4d\xdd\x6d\xce\x19\xec\x45\x58\xc4\x0e\x08\x96\xe2\x19\x09\x28\x0c\xba\x06\xd1\x6b\x72\xf3\x1d\x98\x76\x85\xd0\x71\xdb\x81\x55\xe9\x9e\xbc\xc6\xc8\x21\xd9\x26\x83\xfd\xce\xe0\x86\x68\xa5\xed\x58\xf8\x39\xd9\xed\xaf\xb9\xf1\x45\x9d\x48\xde\x8e\x1b\xb6\xf7\xce\x84\xda\x0b\xe4\x11\xc8\xf7\xbe\x1b\x9a\x24\xbc\x5d\x0f\xe3\xa9\x6b\x02\x35\x07\x50\xa5\xcb\x25\x0b\x49\x55\x5a\x48\x76\x72\xbd\xff\x3c\x3f\x78\x4e\x3f\xb6\x3c\x1c\x97\xba\x6a\xe4\x3a\x10\xe1\x96\xf1\x88\xdc\xc6\x35\xe2\x14\xe2\x9d\xf5\x09\xe5\x60\x8a\x53\x67\xaa\x28\x00\xc1\xa9\x6a\xd9\x36\xa9\xe2\xa5\x79\xb8\x59\x2e\xc1\x3a\x35\x93\x36\xa6\x27\x88\xc3\xec\x55\xc0\xff\xd6\xa7\xd4\x9e\xcb\x7c\x68\x2e\xfa\x30\x81\x99\xf7\x08\xd7\x9d\x0e\x88\x56\x36\x6d\x26\x9f\xab\x24\xeb\x1a\x07\x5c\x96\xc8\x81\xca\xb8\x97\x08\xce\xd2\x79\x23\x0d\x3f\x1f\x3e\xe1\x73\x67\x22\x83\xeb\x8d\x8a\x82\x40\x38\xf6\x48\xac\x43\x72\x75\xd7\x5a\x0e\x15\xf7\x1c\xe5\x6a\x8a\xeb\x77\x1f\x07\xa7\xf3\x2a\xfc\x9d\x61\x2a\x13\xbd\x83\xb7\xf9\x39\x90\xd3\x8f\xc3\xf4\xf4\xab\x8a\xa9\x43\x0c\x65\x73\x6e\xb6\x4b\x16\x80\x6e\x99\x5c\x1c\xe9\xdc\xf4\xc5\x54\x4e\x7b\x3d\x01\x54\x1c\x57\x21\xbb\x4b\xe4\xcf\x0a\xe3\x82\xa0\xc1\xb1\x69\xd8\xe4\x18\xde\xfd\x55\x94\x42\xac\xea\x14\xb0\x0d\x70\x5b\xcf\xa7\x8b\xe0\x75\x6a\x8f\x37\x7c\xbf\x18\x3b\xf2\x59\x06\x87\x41\x15\xd8\xce\x4c\x3b\xa8\x74\x10\x29\x38\xa4\xea\x16\x03\x6d\x91\xa4\x2c\x5f\x8f\x18\x86\x55\xca\xcb\x00\xc8\x8e\x3a\x68\x50\x88\x16\xe5\xe1\xc3\x1d\x27\x18\x0b\xbb\xa9\x51\x8a\x96\x30\x72\x6d\x7d\x04\x7d\xd8\xd2\xc0\x40\x12\x19\xe1\x4e\x6b\xad\xfc\x9b\x95\xb7\x7a\x6a\xce\x9b\xea\x71\xd1\xb4\x7c\x21\x89\x03\xa1\x15\xad\x02\x9e\x7f\x20\x39\xea\x23\xcf\xd1\xfa\x6a\x44\xd0\x89\xfc\xac\xb6\x78\x15\x3d\x67\x4c\x0e\x08\x17\x64\x99\x55\x95\xcb\x68\x94\x89\x5f\x08\xe2\x5b\x98\x4e\x3a\x69\x4c\x92\xfc\x7c\xbe\x0f\xfc\x46\x97\x23\x0b\xcb\x0c\xa4\x08\xc2\xd7\x08\x5c\x11\xba\xde\xb3\xe6\xc0\xe7\x5e\x6c\x49\x8d\xb1\xbe\xc1\xed\x2a\x3e\x24\x45\xc3\x2b\x19\x13\xa8\x95\x00\xf6\x9e\x7f\x23\xf4\x1d\x62\xe5\xc1\x89\xf3\x9a\x05\x6c\xb9\xfc\x68\xa4\x52\x02\x3a\x33\x3f\x75\x22\x0c\xb9\xb9\x44\x84\xac\xac\x6b\xbc\x67\x1f\x59\xff\xa0\x72\xb7\x1a\x18\x96\xa1\xb3\x06\xe9\xdc\x55\x8d\xa0\xec\x20\xf3\x73\xe4\xc3\x55\xe0\xc5\xec\xcb\xbf\x13\x50\xc8\xc0\x79\x14\x89\x2c\x45\x4d\xef\xce\xfb\x71\x7b\xe3\x4d\x08\x7a\xeb\x24\x4a\x86\xff\x49\xa6\xc4\x70\xaf\xb3\x6b\x40\xfe\x8b\x71\xc5\x05\xa4\xff\x7a\xf2\x98\x4c\x65\x28\x49\x38\xec\x0e\x40\x52\x31\x52\x1f\x48\x10\x14\x7d\xc4\xe3\x73\xfd\xab\x66\x47\xb8\x6f\x79\x82\x75\x02\xfd\x08\x7e\x27\xf3\x10\xd6\xb3\x12\x36\x31\x13\x84\x21\x55\xc5\x7a\x32\xba\x03\xb6\xcf\xf9\x65\x53\x0b\xd7\x95\xfc\x29\x2e\x24\x1c\x9b\x6c\xa0\x85\x14\x00\x32\xef\xe7\x46\xf3\x7d\x57\xe9\x58\x42\x11\x84\xb8\xa4\xc1\xa6\xa1\xe3\x7d\x45\xe0\x77\x31\x98\x33\x06\x8d\xdc\xb8\x9d\x38\xc7\x5b\xeb\xa1\xa6\xe8\xe4\x05\x28\x88\xec\x18\x16\x2d\xd6\xff\x0c\x59\xa2\xfd\x0b\x47\xf3\x11\x91\x95\x68\x0f\xfc\xcd\xdf\x5f\x76\xb3\x5f\x02\x2a\xa6\x6b\xd1\xac\x56\xf1\xae\x33\x3e\x9b\x9d\x04\x6f\x0b\x79\xa8\x92\xec\xc4\xf8\xd2\xf3\x1e\x17\x53\x6c\x4c\x62\xa9\xb5\xe0\x63\xdd\x2d\xce\x37\xd3\xd0\xac\xb4\x20\x23\xeb\x2f\x2e\xa3\x29\xd3\x87\x6c\x23\x86\xa0\x22\x76\xff\xf9\xd3\x08\xab\xba\xdb\x72\x74\x30\x1a\x69\x62\xec\xae\xeb\x20\xbe\xf5\xe3\x6a\xff\xfc\x38\x7c\xa8\xe1\x85\xe5\x62\xb8\x65\xb4\x92\x04\xc1\x7b\x2a\x70\x11\x9b\x06\x1c\x29\xc0\xfe\x90\x04"}, -{{0x7a,0x2e,0xfd,0x39,0x01,0x24,0xd3,0xfb,0xef,0xc5,0x4a,0x57,0x71,0x06,0xe7,0x4b,0x2d,0x1f,0x5d,0xd5,0x04,0xc0,0x50,0xd0,0xd3,0x59,0xe5,0x3c,0x0f,0x5c,0x87,0x2b,},{0xef,0xc3,0x03,0xd9,0x22,0xe8,0x8f,0x70,0xf3,0x8c,0x1a,0x2b,0x92,0x06,0x84,0xef,0x66,0x30,0x34,0xa1,0xb2,0x3a,0xb9,0xd6,0x9b,0x6c,0xe8,0xed,0x87,0x06,0xf7,0xf7,},{0xc2,0x8b,0x34,0x80,0x48,0x05,0xd8,0x1f,0x7a,0xef,0x78,0x49,0x70,0x67,0x0e,0xda,0xa4,0x17,0x23,0x2b,0xcc,0x67,0xda,0x9b,0x51,0xe9,0xc3,0xd7,0x4f,0xc4,0x99,0x1b,0xde,0x97,0xa0,0x6b,0xd5,0x3f,0xa0,0x0b,0xb4,0x40,0xfd,0x56,0x16,0xcd,0x0d,0xe6,0xe9,0xb0,0xd1,0x9f,0x2f,0x68,0xbf,0xaf,0x9d,0x4c,0x51,0x72,0xc4,0xe5,0x20,0x0a,},"\x23\x8f\xbe\x9f\xb3\x5c\x72\x5c\x6c\x1f\x32\x92\x48\x09\x4b\xc7\xda\x1b\x27\x3e\xdc\x76\x99\xa7\xe3\x45\x2b\x57\x88\xd8\x78\x67\xde\xfc\x40\xa0\x05\x90\xe8\x75\x80\xd2\xc0\x27\x5d\xf5\xab\xcc\xe0\xe1\xaa\xa1\x82\x90\xbf\x93\xb4\x4e\x5a\xd9\xd7\x60\xdd\x21\xf1\xaa\xca\x38\x31\x78\xf9\xff\xf9\x13\x0f\x73\x18\x7b\xa9\xd3\x1e\xa3\x60\x4a\x1c\xdf\x39\x11\xe1\x43\x77\xa0\xce\x8b\x44\x18\x9a\xda\xa7\xaa\xc2\x3b\x6c\xdc\x7a\x42\x5b\x7e\xa7\x45\x50\x84\x55\x70\x4f\x9a\xd7\xa8\x95\x27\x18\xc3\x98\xb4\x21\xb6\xe0\x9c\xb7\x8c\xb5\x2a\x18\x14\xee\x2e\x96\x39\xec\x68\xd3\x61\xf0\xa3\x20\x41\xd6\xe7\x42\x5b\x4b\xb3\x3c\x70\x19\x6e\x24\x00\xeb\x81\x2d\xb8\x50\x6c\x9f\x32\x45\xbd\x98\x8f\xbc\x89\x1b\xe2\x0c\xb0\x69\x15\x59\xfc\x91\x6b\x57\xff\x96\xc9\xb1\x44\x89\xe0\x99\x3c\xb7\x39\xa3\x9d\xa2\x46\xd0\x1a\x6e\xbd\x07\x58\x35\x81\xf2\x50\xbf\x48\x0b\xc4\x4b\x2c\x33\x91\x54\x2d\x59\x5e\x4d\x39\x94\x90\x19\x5f\x84\x45\xdf\x63\x8f\x34\x69\x8f\x1a\x96\xed\x27\xb3\x53\x3e\x3e\xb6\x7e\x8f\x86\x58\x65\xfa\x95\x55\xed\x34\xdf\x11\x15\x76\x41\xa0\x0e\x6d\x60\xcf\x62\x3f\xec\x1a\x92\xb8\x7a\x15\xd7\x65\x18\x5f\xd9\x05\x5a\xcb\x38\xd7\x5c\x99\xdb\x4f\xce\x7b\x0e\x39\xfd\xc3\xf8\x51\xda\xf6\x5c\x7a\x33\xf4\x64\x81\x69\x31\x83\x9f\xef\xe8\xe5\x8d\x9a\xb7\x42\xb8\x61\x87\x3f\xd2\x29\x18\x9e\x59\xcd\x4c\xe8\x23\x9f\xc9\x54\x3f\x53\x9d\x2d\x29\x61\x14\x26\x6e\xa8\xc6\xfd\x15\x2a\xc6\xb3\x42\xe5\xd1\xa5\x57\xab\x35\xca\xc5\x1e\x2d\x12\x12\xee\x31\x7c\x4d\x26\x71\x68\x29\xe2\x57\x46\xdf\x17\xd2\xa6\x22\xc2\x43\xf3\xec\xbb\x65\xf5\x7a\xb0\xf4\x27\x0e\x3d\x06\x68\xa9\x62\x50\x22\x45\xb9\x4c\x06\xdf\x0c\x5e\x39\xe3\x53\xaa\x84\x2e\xa0\x80\xcf\x50\x27\x08\xb1\xdd\xa2\xd0\x01\x82\x4d\xe4\x58\xd3\x77\x62\xaf\x2c\xdf\xd5\xa6\xd3\xf3\x5e\x08\xa1\x8e\x14\xaa\x7a\x64\x2c\x51\xe4\x04\x7e\x63\x75\x17\x84\x6d\xf6\x46\xd0\x73\x36\xfb\x17\x24\x34\xe0\x88\x3e\x2b\x77\xd8\xed\x1c\x52\xc9\xcc\x63\x6a\x56\xa1\x9e\x57\xa5\xf1\x61\xb9\x2d\x1d\xcb\xfa\x49\x6f\x34\x4a\xe6\xd4\xdf\xdc\x95\x69\xad\xe4\x57\xa4\x90\x91\x36\x2e\x5a\x0c\xdd\x81\xb3\x75\x32\x43\xfd\xac\x30\xa2\xd2\x7e\xa0\x26\xa5\xe6\x01\x44\x1e\xcd\x55\x37\xa7\x20\x1b\xdc\xb7\xfd\x58\xb2\x40\xd0\x22\x9f\xdd\x9b\xab\xf1\x12\xb5\x69\x48\x12\x25\x0e\x76\x8d\x7c\x0c\xe6\xca\x56\x5a\xd0\x6a\xb8\xf7\x8a\x5c\x99\x50\xee\xf5\x38\x72\x6f\x57\x6c\x4b\xd2\xe0\x75\x5c\x7f\x98\x39\x29\x37\x2a\x5f\xe1\x1c\x73\xf9\xe1\xfa\x45\x3a\xb5\x4b\x58\x17\xaa\xd3\x59\x67\x56\x12\x7d\x84\xe3\x11\x94\x53\xe8\x82\x5b\xb8\x46\x0d\x85\x1f\x1f\x7e\x4a\x28\x38\xa2\xbe\x78\x6b\x23\x35\x04\xa6\x91\xdb\x0f\xa2\x2a\x5f\x41\xfe\x3f\xd3\xc9\xb5\x38\xb0\x4f\x40\x9e\x09\x18\x09\x48\x6b\x28\xad\x0d\xed\xa7\xb3\x8a\x42\xce\xfc\x48\xde\x7d\x86\x79\xc0\x3b\xf8\x77\x23\x85\x11\x82\x0d\x07\x70\xcc\x8d\x7b\x41\x72\x37\x78\x23\xa0\xb9\x91\x49\xab\xb8\x91\x8b\xfb\x66\xd5\xab\xfc\xd1\x00\x60\xb0\x5c\xb4\xf2\x39\xdd\x42\x81\xd9\x34\x83\x50\x4b\x73\x1e\xaf\x5a\xdd\x51\x5f\x1f\x3c\x3b\x52\xb4\xe3\xbd\xaf\x97\x6a\x17\xb3\xc9\xec\x61\xbf\xc8\xe7\x71\x16\x71\x58\x04\x53\x2c\xf2\xdb\xf2\x0b\x7b\xa5\xea\xd8\x5a\xfb\x95\x2b\xee\xc2\xfc\xcf\xf8\x5f\xf5\x07\x2b\xa4\xed\x6b\x54\x38\xab\x15\x20\xc6\xef\x4b\x0b\x26\xf1\x2e\x84\xae\xdd\x65\xce\x5c\x7b\xbe\x6a\xcb\x67\x72\xf5\x93\xa6\xb4\xf8\x1d\xdd\x9d\x50\x27\x46\x50\x50\x47\xc8\x12\xa0\x06\x7a\xfc\xeb\x8d\xc9\xbf\xf3\x0d\x40\x87\xf8\xd5\xa3\x75\xec\xa6\x05\xa0\x62\x27\x84\xd8\xfe\xa2\x78\xcd\x1a\x52\x41\xad\x4b\x3f\x1b\x91\x4f\x74\xf7\x3b\xc3\x6e\xe7\xcc\x82\xd9\x6e\xfd\xa6\x3a\x3b\x67\x99\x73\x0f\x20\x65\x6c\x12\x35\x6c\x79\x06\x9b\x2b\xe6\xf9\xb7\x7b\xe1\x01\x98\x31\x18\x82\x3e\xa6\x6e\x7c\x20\x98\xfb\xc7\x2f\xc9\xc0\x39\xdf\xe3\x0f\x2d\xab\xa1\x3c\x3b\xde\xfb\x8a\x78\x0b\xeb\x5c\xb1\xb6\xc2\x86\xa6\xb3\xef\x48\xfd\x15\xc6\x6c\x04\x5b\xa2\x9f\x09\x70\x41\x3b\x98\x8d\x0e\xa0\x04\xab\x84\xc9\x39\x19\xf0\x4f\x9b\xf8\xca\xf5\x8c\x4e\xb4\x78\xf3\x58\xef\x8b\x68"}, -{{0xef,0x36,0x48,0xcb,0xe7,0x34,0x02,0xab,0x45,0x0c,0xd6,0xec,0x37,0xe5,0x45,0xd0,0xcd,0x2c,0x99,0x9e,0xcc,0x1f,0xa3,0x81,0xa4,0x5c,0x66,0x0e,0x18,0x53,0x30,0x32,},{0x52,0xa1,0xa4,0x52,0x73,0x87,0x26,0x76,0x58,0x2c,0xc7,0x67,0x33,0x99,0x26,0x41,0x4c,0xd5,0xd0,0x3d,0x98,0x0c,0xf6,0x29,0xdd,0xa2,0xd1,0xa2,0x05,0xe9,0x83,0x0a,},{0xf6,0x70,0x79,0x29,0x42,0xec,0x41,0x44,0x28,0x47,0x56,0x38,0x85,0x3c,0x42,0x72,0x8e,0x86,0xba,0x12,0xbb,0xe8,0x59,0x48,0xb3,0x91,0x34,0xcf,0x6e,0x2b,0xd1,0x28,0x13,0xe0,0xd8,0x3e,0x51,0xe6,0x57,0xc9,0x01,0x07,0xad,0x93,0xa4,0x78,0x8a,0xa3,0x83,0x13,0xfa,0x96,0x2f,0x67,0x67,0xa8,0xf7,0x80,0x5b,0xde,0x65,0xca,0x42,0x0d,},"\x6a\x93\x37\x8f\x88\x0c\xf0\xff\xdb\x8e\x07\xd6\x83\xcc\x35\x2e\x2a\x10\x33\xc4\x50\xba\xa0\xe8\xc4\xe1\x62\x05\xfd\x0c\x02\x74\x3b\x0e\xa0\x64\x97\x1d\x91\x1e\x49\x47\x13\xe6\xd9\x4a\x02\x17\x2e\xd0\x14\xd5\x06\x59\x2e\xc6\xc7\x0a\x9c\x97\x85\x52\x46\xbf\x3d\x26\xf3\xcf\x74\xf4\x93\xc1\xb6\x97\xa0\xc4\x14\x16\x0c\x34\x14\x12\x83\x09\x85\x43\x08\x06\xa0\xcb\x3c\x84\x75\xe7\xe5\xa9\x73\x68\x6c\x24\xd5\xef\x1b\xe7\xd0\x06\x50\x96\xfe\xb5\x2e\xab\x26\x0b\x5c\x48\x8a\xf0\x92\x70\xde\x6d\xec\xd3\x3f\xea\x85\x89\xdd\x10\x21\xba\xf4\x1e\x3f\x25\x5f\xb8\xfa\x19\x16\xeb\xd8\x53\x1e\xeb\x2f\x88\x6b\xb3\xb3\xb0\x4f\x9a\xf6\xb2\x76\xc3\x59\x23\xf1\x0d\x3a\x0a\xf1\xe3\xf5\x8b\x0d\x15\xae\xd1\x65\x04\x5f\x20\x6f\x3f\x43\x0a\xbd\xff\x09\x44\x90\x97\xe4\xb2\x6d\x00\xa8\xf9\xf1\xe8\xf7\xa1\x9f\x38\x58\x81\x24\xc3\x28\xec\x43\xa9\xcf\xb4\x3d\x3b\x2c\x6b\xdf\x6a\x3c\x1a\x10\x2e\x0e\x33\x3d\xe1\xac\x21\x4a\x6d\xf7\x6d\xab\x44\xba\x76\xbf\x03\x52\x73\xb7\xff\x62\x38\xec\x82\x48\x3b\x2d\x2d\x9d\x54\x29\x1a\x72\x27\x0f\x88\x93\x3b\x78\x6c\xac\x05\x1d\x99\x0b\x3c\xf7\x40\x84\x5f\xed\x3a\x67\x86\x7d\x7c\x7c\x05\x67\x4e\x7c\xb0\x2c\xa5\xb7\xac\xdf\xba\x38\x52\x80\x3a\x3d\x56\xc4\xd5\xc1\x3b\xb1\xd7\x72\x34\x67\x74\x1e\xac\x1f\x2a\x7a\xcd\x3a\x95\xf3\xa5\x16\x10\xa4\x86\xfc\x53\xa9\x85\x16\x28\xc5\x57\xd3\x6d\x8a\x4c\xd3\x7a\xae\x9c\x41\x74\xdb\xbd\xb6\xbd\x88\x5c\xf4\x0b\x38\x2b\x8d\xed\x24\xa4\x52\x2a\x27\x8f\xef\x76\xc4\x53\x19\x06\x7e\x55\x28\x6e\x7b\x08\xc6\x03\x48\x6e\x38\xa0\xac\xf4\x7e\xde\xf8\x48\xec\xbe\x94\x2e\xce\xad\xb8\x63\x6c\x83\x3f\xeb\x88\x2a\x51\xa4\x59\x5e\x24\xf6\x07\xca\x3c\x9d\xa1\xb2\x40\x4c\xe5\xc7\x47\xe0\x62\x64\x17\x4d\x64\x50\x43\x31\x70\x9b\xef\x30\x05\x5a\x5d\x69\x5e\x09\x53\x7c\x8f\x8c\x1e\x5a\x3a\x5d\xb0\x65\x99\xe3\x19\xdf\xdb\x28\x72\x96\x65\x27\x3b\xf8\x68\x95\x5e\xa5\x64\x27\xf0\x8b\xac\xd7\x77\xf1\x79\xb3\x02\xf3\xf6\x8d\x04\xf3\xf3\x88\x3d\x34\x49\x55\xb6\x55\xdd\xc6\xd5\x28\x2b\x6d\x4d\xf1\xd8\x36\x30\x21\x0e\x69\x91\x78\xe1\x1f\x72\x2e\x9e\x5c\xda\x67\x28\x92\xae\x9b\x23\xe8\x16\x9c\xbb\x54\x80\x93\xb8\x3e\x64\x3e\xb4\x99\xd9\x37\xd2\x8f\x38\x11\x59\x7b\x64\x84\x10\x2f\x0c\x8e\xb8\xc8\x88\x8c\xda\xc2\x29\xae\xbf\x89\x08\x6a\x64\x95\xac\x55\x1f\x3b\xbd\xf2\xd1\xc9\xa9\x3e\xd1\xd3\xa8\x61\xee\xcd\x9e\xb8\x39\x94\x9b\xfb\xe6\xa4\xf6\xe6\x48\x6e\xde\xda\xb5\x22\x9d\x53\x2b\x58\x97\x6d\x67\x51\x2f\x9f\x71\xae\x79\xb4\x14\x5c\xa2\xfa\x49\x7a\x16\x5f\x11\x07\x17\x66\x6c\xa3\x34\x0b\xbd\xa8\xdf\x1f\x82\xb8\xc0\x54\xcf\x76\x54\xc3\x56\x90\x16\x8f\x96\x27\x7d\x41\xc1\xc2\x36\xb6\x81\x98\x17\x3c\x6e\x2b\x0a\x20\x8e\xf8\x3c\x02\xa4\x3e\x47\x3d\x90\x68\x6a\xce\x75\xb5\xbd\x32\x1b\x3f\x54\x28\x13\x27\xa6\x73\xca\xd4\xd4\xad\x30\x40\xd4\x8c\xf4\x93\xea\x23\x1b\x3f\xec\x06\xf3\x99\x32\xd7\xf7\x0a\x38\x42\x8d\xf8\xfe\xe4\x37\x05\x32\xae\x5f\xb1\x12\x05\x9f\x0a\x1d\x4f\xbe\x11\xb5\xa2\x3b\xb8\x76\x35\x42\x9e\xd3\x3a\xd1\xf6\x14\x80\x14\xcb\xc1\x60\xd9\x3c\xa2\x59\x20\x53\xa6\xe9\x53\x78\xd6\xcd\x3f\x50\xdb\x52\xbe\x92\x8e\x40\x92\xfe\x5d\x2b\x70\x95\xa9\x56\x68\x64\xad\xfd\xa5\x9f\xd5\xf2\xfb\x62\x54\xbd\x59\x17\xb7\x0f\xa1\x46\x99\x66\x5a\x37\x29\x7c\x98\x3c\x1b\xb9\xef\xe1\xc6\x7b\x41\x3d\xd1\xa8\x53\x0c\xbf\x22\x72\x97\xa8\xbb\xf9\x3a\x8a\x02\x45\x4e\x8e\x46\x1a\xc2\x12\xb8\x46\xa7\x0d\x5d\x56\xd6\xc3\xa6\xe6\x5a\x03\xbe\x05\x80\x21\x9b\xdd\xec\x88\xd4\x03\x89\x11\xfd\x95\x74\x56\x3f\x33\xe0\xf9\xe6\x04\x46\x88\xd3\xdd\x48\xfa\xc7\x03\x86\x9a\xa0\x9d\x96\xef\xee\x7d\x6c\x68\x07\x1d\x99\x22\xd5\xe8\xed\x8d\xc4\x0f\x1b\x79\x8f\x1c\x58\x0f\x78\x59\xcb\x84\xf1\xe1\x4b\x5e\x74\xdd\xea\x16\xad\x5c\xbe\xea\x4c\x48\xfb\xcf\xfd\x29\x53\x1a\xcc\xc0\x63\x39\x38\xe3\xbc\xb2\x21\x26\x76\xb6\x1e\xf9\x01\xe9\xc8\x31\xa4\x17\x74\xd8\x31\x7e\xf3\x5a\xf7\x69\x90\xbd\x24\x93\x1f\xde\x6d\x40\x7e\x22\xe7\x63\xcf\x6a\x57\x90\xb2\x37\x61\x90\x8e\xee\x60\x96\x37\xa2\xc1\x10\x59"}, -{{0x2c,0x8e,0xe7,0xfa,0x9b,0xa2,0x8c,0xe7,0x04,0x96,0x76,0x08,0x7b,0x11,0x63,0xb2,0x41,0x11,0x8d,0x34,0xcd,0xf5,0x34,0xae,0xbe,0x8b,0xa5,0x92,0x82,0xa6,0x2a,0xc2,},{0x24,0x4c,0x24,0xf5,0xec,0xb2,0xdd,0x1d,0x14,0x63,0x51,0x22,0x21,0x32,0x5d,0x73,0xc8,0x1e,0xe4,0xd8,0xad,0xb8,0xe0,0x1e,0x23,0x34,0x5c,0xaf,0x9c,0xa5,0x35,0x3b,},{0xca,0x0b,0xb6,0xc1,0x23,0x56,0x55,0x5f,0x6e,0x1d,0x8f,0x5c,0x8a,0xa7,0xb5,0xe8,0x0c,0xd2,0x80,0xe8,0xb1,0xb9,0xba,0x2e,0xc9,0x55,0x0f,0x62,0x2f,0x48,0x2c,0x3a,0x9a,0xd3,0xbe,0x03,0xa4,0xc9,0xdf,0xc1,0x0d,0x01,0x12,0xb0,0x18,0x9d,0xe9,0x4b,0xff,0xaf,0xd7,0x03,0x41,0x14,0xe0,0xe0,0xd4,0x2c,0x23,0xf3,0x2d,0xc8,0x18,0x07,},"\x07\x66\x9a\x89\x64\xf0\x63\x80\xd2\xd4\x98\x2c\xb6\x34\x9d\xe5\x50\xb3\x8c\xbc\x35\xdb\x2c\xe5\x72\xde\x88\x7f\x66\x30\x55\x73\x6f\xaa\xc7\xec\x07\xc3\x2d\xf6\x0e\xe2\x59\x84\x22\xbf\x37\xe7\xcf\x31\x9a\xb3\xc9\x05\x56\x08\xca\x0c\x49\x75\x7d\x76\x88\xe2\x01\x3b\x82\x44\xf3\x54\x04\xf4\x5a\xc2\x19\x49\x7f\xe9\x24\xde\x93\xa5\x8d\x0f\x72\x1a\xed\x78\x25\xf6\x3b\x26\x67\x07\x7c\x16\x1e\xb4\xdd\x8b\xf7\xdd\xbd\xbb\xc1\x9a\x9e\xae\x59\x78\x97\x8d\x5a\xeb\x33\xa0\x6d\xde\x18\xe6\x12\xe0\x5b\xdb\xca\xe0\x16\x1a\xa2\x38\x90\x38\x02\x64\x29\x96\x0d\xda\x3a\xa1\x7e\x96\x7d\x10\x77\x3c\xa4\x97\x35\xd8\xec\xd7\x40\x9b\xe1\x65\xc0\x9b\xb0\xb5\x09\x69\x1d\x59\x1c\x18\x5c\x93\xcd\xee\xae\x95\x35\x23\x16\x54\x46\x80\x52\x38\x21\x45\x8c\xac\xcf\x52\x8a\xc0\x45\x4e\x4c\xdd\xc6\xdf\x0d\x1e\xa5\xf1\xf5\xcc\x1e\xee\xe0\x5e\x19\xa2\xad\x0b\x6a\x49\x73\x6e\xd8\x55\x23\x36\xfc\xfc\xad\xbd\x93\x1b\x0b\x8e\x96\x3b\xe0\x5c\x8e\x70\x37\x38\x85\x52\x51\x2b\x68\x23\x58\x3e\x4a\x14\x38\x4c\xef\x50\x29\x23\x2d\x3e\x0b\xaf\xe4\x66\x35\x1b\x4b\xb3\xf5\x67\x54\x5a\xb4\x1f\xa4\x6b\xff\xaf\xa8\x77\xa1\x2b\x38\xa2\x7a\xbd\x64\xf7\x7f\xbb\x4d\xb4\x66\xff\x7f\x70\x65\x04\x14\x1d\x3a\xdd\x0d\x73\x72\xf1\x6f\xe3\xd8\xc6\x9f\x62\x99\xd9\x39\x66\xd6\x24\xa3\x07\x0e\xad\xb8\xb4\x9f\x29\xfa\xb4\x84\x4c\x75\x28\xa2\xa4\x0b\x66\x98\x70\x60\x69\x5c\xaa\x66\xb8\x67\x18\xc5\x10\x49\xac\xf4\xcf\xad\x38\x53\xed\xb4\x92\xe3\x68\xcb\xd0\x73\x96\x8e\xca\xa4\xa1\xee\x60\x46\xb5\xe8\x26\xe9\x01\xf4\xa8\x08\xc0\x42\x7c\x02\x6f\xe2\xf7\xb2\xe1\x96\x86\x67\xb5\x3a\x7d\x36\xd7\x02\xf2\xff\x82\xc6\x42\xd3\x49\x19\xf8\xe9\xaa\xaf\xe4\x62\xa3\xd4\xf9\x26\x92\xde\xac\x75\x2b\xe3\x48\xf5\x4c\xf0\x89\xdd\x9c\xd0\x51\x84\x6b\x04\xb7\x19\x31\xe1\x9e\x89\xd1\x25\x86\x4b\xfa\x89\x48\xac\xe0\xef\xf3\x3c\x45\x11\x05\x69\xa0\xdf\x37\x53\xf4\xc5\x8d\x80\x02\xb5\xbc\x38\x10\x2e\xc2\xec\xf6\x95\xfa\xfa\x89\x16\xda\x90\x02\x38\x7e\x44\xf9\x6d\xab\xf8\xa9\x82\xc5\x3c\x9b\xad\xbc\x37\xbd\xe4\x37\xf1\x46\xf7\x7d\x8f\x7b\xaf\x12\x87\x31\x96\xb0\xc3\x61\x93\xaf\x55\xf5\x42\xd9\x96\x8a\xed\x80\x69\xab\x9f\xbc\xd6\x81\x4e\xc4\x72\x79\x9a\xd0\x9c\x73\x0d\x41\xed\xde\xca\x3b\x62\x69\xd3\x1a\xb5\x23\xb5\x95\x47\x07\x73\x76\x34\x5b\x05\xf2\xae\x69\xb4\xee\x72\x8c\x86\x3d\x1b\xc0\x4e\x9b\x7d\x3d\x0f\xcc\xeb\x35\x9c\xbd\x08\x58\x59\x7a\xf2\xd6\x06\x3e\x25\x3f\xae\x2c\x3f\x25\x03\x4c\x33\xed\x59\xed\xd2\x78\x28\x68\x29\x86\x81\xca\xf5\x64\xdb\x8d\x19\x36\x6f\x34\xea\xe8\x5b\xa7\x3c\x1e\x23\x89\xb0\xdd\x78\xa9\xd2\xca\xa0\xf2\x3c\x9a\xd5\xf6\xcd\x9f\x2c\x4a\xd5\xd5\x89\x46\xad\xb7\x18\xcb\x83\xda\x58\xe2\xfc\xbb\x60\x25\xbe\xf4\x66\x0a\x83\xe0\xaf\x55\xe2\x03\x08\x02\x93\x2f\x2a\x89\x6a\x09\x60\x79\xb7\x54\xc9\x9f\x7b\x64\x23\xb4\x5a\x86\x47\x2e\x67\x23\xef\x88\x96\xc4\x32\x4c\x73\xd3\x4a\xd5\x8a\x4c\x01\xb3\x8a\x97\xc7\x3b\xe5\xaa\x7f\x74\xa2\xfa\x4d\x07\x95\xaf\x6d\xbf\xcd\x6d\x4e\xb4\x42\xa7\xe2\x04\xdb\x4e\xcb\x1f\x8a\x22\x6b\xdf\xa2\x1b\x6e\xb1\x71\xc9\xe5\x9f\x1a\x19\x2e\x23\xa7\x6c\x35\x2b\x04\xd8\xa8\x02\x33\x98\x5b\x77\xa2\x9c\x02\x01\x19\xce\x65\x1c\x7f\x41\x83\xd0\xe9\xc1\x9f\xe1\x8a\xa1\x02\x0c\x25\xe4\x58\x9d\xee\x34\xb9\x01\xbd\xaf\x9f\xf9\x45\x0c\x91\xaf\x3c\x1d\xb6\x70\xb4\x77\xe0\xac\x21\x07\x69\x6c\x9e\xc0\xd3\x1d\x82\x64\x7b\x68\xea\x19\x49\x9f\xe3\x4a\x8e\x2e\x7b\x37\x8d\xc7\xe7\x54\x24\xe8\xc4\x56\x45\xb0\xc2\x81\x8e\x9f\x88\x5a\x1c\x58\x41\x5b\xba\x1c\x3f\x2a\x77\x54\x9b\xdc\x46\x80\xdb\xcd\x16\x50\xc7\x5d\x0f\x45\x2a\x6b\x20\x85\x91\xdf\x0f\xa6\xe1\x81\xda\x2a\xbf\xab\x44\x46\x21\xd5\xf7\x7c\x2c\xd7\x95\x56\x46\x72\x46\x44\x7a\x89\xf0\xaa\xac\xad\x66\x0c\x9a\x92\x5e\xba\xfb\xad\x43\xc4\x78\xa3\xc8\x50\xa2\x7e\x01\x01\x9d\x88\xa5\xb1\xdc\x81\xb5\xd2\xe9\xf7\x40\xa0\x28\xcc\xb7\x2c\x1a\xcf\x89\x7e\xa5\xad\x89\xe0\xf9\x44\x88\x88\xd5\xb1\x5c\xe6\xe4\x29\x77\xf7\xa7\x29\x15\x5a\x28\x4d\x11\x87\x58\xac\x65\xf3\xfb\xb9\x8d\xeb\x65"}, -{{0xdd,0xd8,0xe9,0xff,0x85,0x56,0x79,0x89,0x6a,0x13,0x97,0xb4,0x27,0xdb,0x85,0x43,0xab,0xe8,0xbb,0x5d,0xd1,0x22,0xe3,0xe3,0x02,0xcc,0xfc,0xe5,0xfd,0xc6,0x3e,0x12,},{0x5a,0x9a,0x31,0x2e,0x89,0x2a,0x10,0xb9,0x8d,0x0d,0xcd,0xd2,0x8d,0xb3,0x48,0x1c,0x3c,0x28,0xad,0xd5,0xad,0x0b,0x19,0x46,0x16,0xda,0x4a,0x3d,0xf7,0x66,0x01,0x09,},{0xdf,0x84,0x9b,0x7b,0xd2,0x97,0x45,0xf8,0xbe,0xcd,0xdd,0xf6,0xc9,0xba,0xf0,0x94,0xd7,0xa9,0x8c,0xc9,0x33,0x8c,0x34,0x4e,0xca,0x17,0xfd,0xe0,0x75,0xfd,0xa8,0xd1,0x54,0x32,0x99,0xf6,0x25,0x98,0x23,0x17,0xdb,0x7b,0x3c,0x77,0x3b,0x64,0xf7,0xd1,0xf2,0x86,0x92,0xac,0x45,0x3b,0x81,0xd7,0xec,0x7b,0x7e,0xc3,0x41,0x7a,0xce,0x04,},"\x5e\x8f\xee\xc5\x09\x35\x0d\x2e\xe7\x95\x5b\x6f\x3e\x27\x82\x78\xa4\xcb\x48\xae\x72\xb4\x65\x89\xe4\x78\xbe\x59\x74\x7d\xf5\x39\x4a\x16\x9f\x19\xe1\x0d\xb5\x32\x02\xa6\xa5\x23\x20\xb6\x3a\x9a\x2b\x72\x3f\xd3\x1a\xa2\xdb\x6d\x58\xc5\x73\x32\xda\x31\x78\xbc\xf9\x66\xc5\x3a\xbd\xa3\x5f\x12\xda\xef\x9e\xdc\xf3\x99\xe4\xa8\xc5\xf8\x3d\x36\xf4\x4a\x17\xd7\x98\x46\xbf\xc9\x6c\xe6\x90\x19\x4c\x21\x9a\x29\x89\x2f\x03\x67\xa7\xab\x38\x44\x83\x78\x79\xe3\x81\x8d\xb8\xd7\x0c\x4e\x3f\xba\x4d\x28\x07\x34\x64\xdf\x20\x85\x95\x10\x38\xfe\xa4\x32\x81\xb6\xb6\x06\xdc\x88\x46\xb3\x0b\x07\x63\xf2\xca\x82\xbd\x50\x21\xf9\x11\x70\x35\xa7\x7b\xcd\x10\x75\x47\x7c\x5f\x43\x21\x43\x34\xd4\xd4\xce\xdd\x18\xf7\x38\xd6\x76\xc7\xb5\x1a\x18\x5f\xfa\x8d\x04\x10\x11\x86\xa4\x95\x2b\xbd\x87\x22\xf5\x39\x90\xb6\x06\x37\x04\x1e\x11\x4a\xeb\x8c\xe7\x11\x11\x31\xd4\xdb\x3f\xb4\xd3\x5d\x99\x5a\xd8\xd6\x65\x0c\x0c\x4c\xcd\xce\x9d\xcc\x39\xdb\x18\x8a\x68\x78\x55\x62\x74\x06\x26\xb3\xae\x3e\x02\x3f\x40\x77\x2d\xed\x87\x6a\x45\xcb\xef\x74\xa0\x58\xfd\x78\xc1\xa1\xff\x2c\x24\x51\xe1\x11\xac\x1b\x4b\x7e\xe4\xc8\x1c\xd7\x63\x10\xd4\xd2\x98\xfb\x3c\x49\xf5\xe6\x40\x19\x08\xa6\x30\xfa\x85\xdb\x74\x71\x80\x4f\xe9\x90\x84\x7f\x0f\x75\x94\x72\xf5\x93\xdc\xf0\x2e\x11\x3e\x15\xe5\x64\xd3\x0d\x59\x84\x69\x2d\xa5\x5b\x0b\x7f\x22\x19\xc4\xac\x16\x26\x51\x1a\xcf\x19\x4d\xc7\x02\x6e\xb9\xd3\x67\xa4\xa2\xf1\xdf\xb5\x15\xcb\x2c\x08\xda\x4f\xe5\x95\xc8\x58\x11\x12\x0c\xba\x2a\xe7\xb6\x6e\x67\xc9\x1f\xb8\xfb\xcb\x9d\x99\xf1\x3e\x50\xfd\x67\x46\x4d\x90\xc8\xdc\xf6\x93\x55\x23\xcf\x6d\x13\xfd\xd1\x06\x35\xb9\x23\x2b\x7a\x61\xdc\xec\x9a\x2b\x92\x10\x61\x41\x0d\xf1\xde\x6a\x45\x16\x7f\xb9\xf6\xf1\x09\xdc\xc0\x88\x91\xf2\x03\xb2\x74\xa3\xb6\x82\x71\xb3\xf3\x5e\x74\xf9\x4b\xdc\xed\x0c\x5f\xf8\x63\x71\x73\xa1\x76\xe7\xda\xcc\x81\xf2\xcd\xc4\xfb\x0d\x52\xd1\xdf\xa7\xf2\x7b\x55\x2f\xd8\xd8\x7a\x1c\x55\xd6\x94\x7f\xd9\x2e\xd3\x25\x3f\x95\x94\xdb\x7d\xf1\x7a\x7f\xc6\xa7\x5e\xcf\x4f\xaa\x4d\x1e\x21\xb6\x76\xb3\x72\x7d\x77\xfb\xd4\x3f\xa7\xbe\x76\xbf\xb5\x8f\xc3\x09\xe5\x67\x5f\x0a\x85\x9c\xc4\x7f\x37\xb1\xbf\x45\x59\x32\xd8\x24\xe8\x63\x78\xde\x7a\x7e\x8c\x40\xce\xd2\x20\x90\x04\x4d\xbb\xf9\x1c\x70\xe5\x28\xea\xcd\xef\x37\x85\xba\x3c\x69\xa3\x73\x5a\xf6\x70\x9c\xd7\x6a\xab\x28\xa6\xac\xa6\xe8\x44\x97\x4b\x10\xb3\xfb\x7b\x09\x86\x00\x7a\x72\x7c\x2c\x8f\xc9\x5b\x25\xf3\x1f\x14\x6b\x36\xac\xd4\xc5\x37\x07\x49\x20\xaf\xf2\x47\xde\x0f\x17\x9c\x13\xca\x57\x79\x0a\x6a\x71\xd6\x2e\x23\x32\x1c\xcc\x75\xb7\xf3\xb0\xaf\xa0\xd0\x35\x27\xc9\x11\x4a\x7d\x4e\x30\xc1\xac\xe6\xd7\x71\x20\x13\xde\xe6\x66\x99\xaf\x9c\x56\x1c\x44\xae\x61\x98\xed\x39\x10\x4e\x60\x61\xae\x2c\x45\xa9\xa3\xc7\x4b\x5d\x0f\xbc\x4a\x33\xe8\xdf\xe2\xa8\xac\xc9\x51\x1e\xf7\xe6\x56\x71\x33\xf9\xfe\x35\x54\x28\x4a\x75\xa0\x59\xa6\x49\xdd\x24\xec\x04\xa5\x77\x30\xc6\xd2\xe9\xbf\x11\x4e\xa5\x8a\x89\x94\xab\xdb\x0c\x19\x43\x24\x15\x72\xc7\x9e\xad\x04\x3a\xd1\xc8\xca\xaf\x5c\x9d\xa5\x3d\xd0\x55\x22\xfe\xbc\x40\x33\x54\xd6\x2f\xe3\xff\x93\x88\x2d\xf7\x5f\xb2\x94\x58\xd2\x2e\x69\x96\xc3\x5b\x69\xfa\xae\xf2\xe0\xc4\x16\x38\x86\xcb\x3c\x3d\x0f\x60\xe1\x50\xd3\x63\xd6\xdb\x59\xfe\xfc\x62\x6b\x1b\xbb\x1e\x05\x2a\x62\x41\x4c\x4b\x78\x56\xd7\x20\x93\x43\x2b\x08\xf8\x21\xbc\x78\x4a\x5a\x6b\x0b\xc2\x64\x9c\x2d\xaa\x50\x86\x58\x98\x0d\x80\x22\x91\xe7\x34\xab\xaf\xf0\x6a\xfb\xf2\x79\x5e\x4e\x35\x4d\x52\x21\xdc\x4f\x52\xcc\x96\xd6\xb8\xcf\x18\x08\xb1\xa8\x20\x8d\xb7\xda\xa8\x0a\xb7\x10\xc5\x6a\x8b\x0e\x9c\xb8\x08\x1d\xee\x93\xf5\xf0\x15\xf0\x76\x64\x46\x3a\x3d\xcc\xff\x7c\x8a\xd1\x99\x23\xa9\x7e\x39\x04\x5b\xcc\x4d\xce\x0a\x73\xd4\x9c\x56\xd5\xe9\x37\xbd\x11\xe6\x18\x23\x40\x1c\x06\x62\x06\xe3\x13\xe6\x0b\x47\x53\x7e\x34\x70\x4d\x7d\x35\x15\x55\x9b\xb9\xd0\x53\x2d\x02\x8e\x28\xa5\x7a\x87\x9f\xd6\x17\xcc\x61\xf7\xf7\x76\xbd\x6a\x00\x8c\xd4\xf8\x12\x37\x8e\xd3\x7f\x39\x4b\xb9\x7e\x6e\x75\x6d\xa8\x19"}, -{{0xa8,0x86,0xf4,0xd3,0xf3,0x4e,0x32,0x0e,0xc6,0xd5,0xf4,0xca,0xa8,0x63,0xf8,0x14,0x77,0xdf,0x77,0x2e,0xff,0x97,0xe6,0x4a,0x37,0xa0,0x5f,0x42,0x11,0xd1,0x90,0xa8,},{0xe9,0xbc,0x96,0xc8,0x1e,0x87,0x81,0x10,0x26,0x8b,0x55,0xde,0xf7,0xea,0x40,0x07,0xa4,0xef,0x9f,0x54,0xd3,0x83,0xd5,0xfb,0x0f,0x6d,0x43,0x43,0xe1,0x01,0x0f,0x38,},{0xab,0xf2,0x83,0xdb,0x1f,0x80,0xc5,0x4c,0x58,0x3b,0x49,0x9d,0xbe,0x20,0xaa,0x04,0x24,0x8c,0x1d,0xce,0x12,0x1f,0x39,0x11,0x67,0x78,0x13,0xac,0x3e,0x01,0x1f,0xd1,0x59,0xad,0x0b,0xf7,0x6b,0x1a,0xa7,0xcc,0x7b,0x14,0xd7,0xb5,0x50,0x84,0x86,0x88,0x25,0x2a,0xcc,0x7f,0xec,0xe9,0x04,0x87,0x24,0x0c,0x3d,0x39,0x9d,0xd3,0x43,0x08,},"\x8b\x83\x1b\x87\x7b\xc3\xa9\x9f\x61\x3c\x89\xcd\xa6\x98\xb3\x75\x9d\x64\x38\x22\xb5\xa8\x8f\xaf\x38\x22\xec\xb2\xce\x98\xf6\x71\xd7\x55\x43\x21\xb2\x4b\x74\xb4\xe3\x0a\x66\x3f\x7a\x55\x70\xae\x91\x7f\x47\x9b\xda\x29\x89\x4b\x1a\x8c\x02\x8c\x9d\x19\x3e\x4e\x7a\xc1\x19\x16\xdd\x8e\x9c\x3f\x0e\xc0\xef\x80\xbd\x27\xfd\xfe\xee\x80\xc1\x70\xc7\x81\x40\xb2\x4c\x15\x27\x14\x15\xac\xf7\x5c\x26\x95\x6a\x4d\x4b\xf9\x9d\x40\xe8\x61\xe9\x07\x83\x20\xd0\x97\xe1\x25\x9e\x5e\xc1\x7b\x58\x3a\x95\xe5\x24\x30\xdd\x8c\x00\x8e\xd8\xc7\xdd\x1d\xe1\xbe\xcd\xd1\xe6\xbf\xec\x4b\xf3\x34\x7a\x22\xdd\x24\x9f\x3a\xc3\x07\xa2\x94\x5e\x91\x37\xfa\x4a\x8c\x26\xc8\x02\x10\x77\x23\x9c\xb3\x24\x81\x6a\x8d\xad\x32\xb0\x1e\xe3\x4a\x08\x90\x30\x98\xcb\x9c\x42\x45\x29\x1b\x90\x3c\x96\x27\x07\x40\x95\x24\x9e\x78\x28\x13\x47\x70\x32\xba\x32\xef\x04\x1a\x07\x48\x6e\xb4\x47\x8c\x57\xb9\xd5\x32\x26\x9a\x4a\x47\xcb\x5e\x97\x4d\xf7\xe0\x10\x96\xfb\xe4\xf1\xcc\xd4\xe6\x63\x66\x34\x87\x97\x4c\x62\xcd\xd9\x4d\x77\x71\x6c\x84\x79\xd7\x9f\x6b\x6a\x7d\x9c\x15\x59\x88\xcf\x39\x02\xfb\x69\x74\x24\x96\x3e\xc4\xec\x34\xff\x2a\x35\xd7\x42\xc4\x45\x5a\x59\x3b\xac\xff\xc4\xd9\x69\x9b\xa7\x62\x6c\x76\xcb\x1a\x61\x62\x53\x75\x18\x87\xf6\xff\xe2\xbe\x20\x8c\x71\x3d\xf1\xab\x63\x6d\x72\x2e\xa0\x6c\x1c\x03\xa5\x7f\x2c\xec\x08\x03\x86\x6c\xca\x33\x35\xc2\x8b\xf4\x1c\x7d\xef\x81\xac\xb3\x88\x58\xdc\x10\xe5\x94\x67\x20\x86\x24\x96\x7e\x2e\x22\xd9\xe5\x66\x1b\xb9\x45\xf9\xe0\x51\x76\x87\xdc\x80\xf9\xb8\xfd\xec\xc8\xa9\x76\x00\xb6\xc2\x19\xa3\xb2\x3a\x90\xb6\xd1\x8a\xaa\xce\x2c\x78\x40\x0f\xf3\x8c\x8c\x05\x96\x7f\x54\x4b\x6a\x60\x6c\x71\xac\x19\x9e\xaf\xd0\x7e\xb5\x84\x8d\xf1\x65\x7e\xfb\x23\x3f\xba\xba\xe6\x3a\x05\x63\x81\x91\xa0\xaf\x74\x84\xa1\xba\xe1\x58\x13\x75\x67\x2c\x57\x1e\x26\x4f\x60\x42\x25\x17\x3a\x54\xa3\x8d\xd6\x2a\xe7\x13\x0d\x05\xdd\x29\x1a\xd1\x23\x54\xde\x86\xa6\xe1\x13\xe8\x3f\x6d\x66\x85\x16\x15\x7b\x79\x67\x02\x0d\xc6\x51\x7d\x8c\xf4\x2d\xd7\xb1\xa8\x97\xfe\x1b\x4e\x04\x55\x3c\xe2\x6e\x29\x99\x80\xaa\x5f\x7c\xe0\x17\x9b\xf4\x95\x4f\x01\xc2\xa2\x36\x54\xe5\xe9\x73\x1e\x14\x47\x34\x7f\xa4\x3a\xa8\xb2\xcb\xd6\xd4\xb2\xdf\x93\xfa\x54\xaf\x71\xe5\x02\x8a\x6d\xa8\xc7\x1e\xf3\xc5\x0c\x0d\xe2\x4d\xca\xee\x78\x56\x78\xe9\x2a\xaf\xab\xeb\x23\x3b\x01\x1f\x45\xc1\x06\x49\x65\x08\x5d\x25\x47\x05\x0f\x21\xc6\x52\xaa\x53\x3a\xfe\x91\x8a\xa0\xf9\xbd\xaa\x26\x07\xb8\x73\xcc\xd3\xdb\xd1\xd3\xa8\xcc\x62\x17\x2c\xeb\x43\xb9\x21\xef\x6b\x25\xc0\x6b\x09\x92\xe4\xdf\x2b\x91\xe3\x71\xb0\xef\x2b\x39\x47\x38\x8d\xae\xc8\xec\x6f\x7e\x38\x67\xd1\xf6\x10\x72\xaf\x59\x01\x54\xfa\x61\x9a\x07\xf8\x7e\x02\xbd\xdc\x74\x06\x31\x42\x70\xaf\x1c\x15\xe8\xee\x88\xb3\x9c\x01\xbe\x60\x2e\x4f\x0b\x52\xd9\xa0\x72\x4e\x71\xed\xdd\x7f\xa9\x13\x41\x69\xc5\xfa\xab\x91\x59\x79\xee\xa9\x36\x2d\x0f\x1f\x91\x60\x26\x81\x62\xdd\x38\xdb\x02\xfc\xfb\x41\x35\x0a\xa0\x8e\x1e\x14\x09\xb2\x28\x8d\xb1\xfe\x4a\x0e\x58\x6b\x59\x10\xf4\xde\x89\x4b\xf9\x97\x4f\x6a\x49\x83\x01\x3a\x19\x0e\x7a\x73\x6d\x14\xec\x54\xc3\x64\x4a\x3e\xe9\x58\xa5\xbd\xfb\xcb\x62\x97\xab\xa4\x3a\xf6\xc7\x27\x46\xbb\x13\x54\x10\x50\x7d\x8f\xdd\xe7\x3a\x2a\x48\xb7\x46\xf9\x18\xbe\xf9\xed\x92\xc5\xbe\x62\xdd\x55\x23\xfe\x14\xb1\x6d\x63\x84\xca\x46\xef\x59\xb2\x18\x5f\xe9\x33\x38\x3a\x2c\x7a\x9b\xf0\x2d\xa9\xd0\xfd\x8b\x0c\x7d\x7b\xde\x6b\x43\x9f\x99\x60\x15\x5e\x34\x5d\x68\x5d\x4d\xc3\xc7\x14\x04\xd6\x56\x81\x19\x23\xaa\x3c\x47\xd4\xb0\x9a\x0b\xae\xf0\xa1\x2e\x75\xb6\x43\x9b\xa8\x13\x5d\xb1\x58\x65\x87\x42\x22\xcd\x7a\xa4\x28\xf5\xca\x5c\xe5\x14\x0e\x22\xff\x92\x69\x7f\x37\xfc\x70\xb5\xb4\xc9\x4d\x33\x14\xe6\xaa\x16\xb2\x14\x6b\xca\x4f\xc9\x41\x57\x95\x1f\xc4\x92\x45\xda\x53\xf6\xc4\x3d\x1b\xeb\xd8\x94\xe3\x1a\x13\x49\x88\x4d\x71\x1b\x55\xdb\xe7\x78\xff\xa7\x27\x16\x5c\xf7\xcb\x67\x64\x35\x86\x6c\x2d\x2c\xb8\x39\x74\x5c\xa4\x01\x66\xa2\xf7\xcf\xc7\x7a\x84\x24\x68\xb5\x1a\x8e\x76\x57\x5f\xc9\xdd\xfb\x5f"}, -{{0x49,0x7e,0x3e,0xbd,0x9e,0x4c,0xaa,0x81,0xc5,0xa8,0x97,0x3d,0x52,0xf1,0xd2,0x3f,0x60,0xc1,0x34,0xca,0x53,0xf6,0x2a,0x85,0x3a,0x0a,0xc0,0x43,0xe5,0x1c,0xb5,0x17,},{0x71,0xc0,0xca,0x7c,0xfa,0x05,0xca,0xfa,0xbb,0x14,0x3d,0x84,0xae,0x41,0xde,0x83,0x84,0x6f,0x42,0xc7,0x7c,0xaa,0x7a,0x91,0xa2,0xe3,0x48,0x39,0x7d,0x07,0xd5,0x2f,},{0x12,0x74,0x08,0x39,0xb3,0xc9,0xf1,0xba,0x87,0x98,0x96,0xdf,0xf6,0xd7,0x25,0xe8,0x4e,0x04,0x43,0xef,0x96,0xc3,0x49,0xef,0xf9,0x4d,0xc4,0x83,0x31,0x43,0xe5,0xb4,0x19,0x80,0x4d,0xa9,0xdb,0x11,0x8a,0x95,0x92,0xb1,0xb1,0xca,0x48,0xaf,0x18,0xf7,0x5b,0xef,0x1c,0xa4,0x68,0xa1,0xa5,0xc7,0x4c,0x7a,0xc8,0x13,0xbb,0x2c,0xf3,0x06,},"\xe1\x32\xf9\xd6\x7b\x17\x29\x38\x9b\x82\x8a\x9f\xae\x05\xa6\x7a\xa5\x7f\x0e\xf7\xe7\xd4\xd1\xba\x24\x4d\xec\x87\x04\xdb\x96\x95\x65\xd1\xca\xb8\x09\xe4\x8f\xc0\xab\xf9\x50\xbc\xd4\xa3\x7d\x97\xae\xac\xe6\xda\x54\x6d\x49\x14\xcb\x5b\x86\xd6\xab\x18\x1d\x83\x18\x70\xc3\x09\xbc\xa6\x16\x46\x8f\x2a\x34\xd3\xdf\xaf\xcd\xbb\x75\x80\xb0\xc5\xd9\xff\x98\xe2\xc5\x4e\xc8\x03\xbe\x0d\x3f\xda\x1d\x4b\x8c\x0d\x77\x09\xc8\x9e\x68\x0b\x00\x8b\xf9\xb8\xd9\x03\xb5\xe9\x34\xb0\x19\x70\x5f\xe0\xb0\xc8\xcf\xbc\x3c\x09\x67\x84\x3b\x0a\x1f\xa1\xb3\xf1\x62\x77\x6e\xbe\x96\xb7\x40\xed\xd6\x4a\xd7\xc3\x5b\x3f\xd1\xa0\x85\xc9\x9d\x16\xf5\x41\x67\x82\xde\x17\x35\x85\x87\x47\x0d\xd1\x3b\x51\x94\xf2\x0f\x23\x23\x2b\x2f\x70\x2f\x10\xaa\xfc\xaa\x59\xc7\x06\x6f\x24\xc4\xc4\x71\xe4\x2f\xa8\x6c\x6b\x9c\x5c\x3e\x1e\x8f\x83\x65\xf4\xdd\x75\xac\xb3\x2f\xff\xc0\x53\xc9\xaf\x41\xc6\xfd\x2e\xfa\xc3\x0e\xcf\x6a\x2d\xd0\x08\x5d\xe9\xb1\xd8\xcd\xc5\x0b\x16\x60\xa8\x66\xdf\x77\x67\x19\x8b\xd9\xc8\x73\x70\x61\x5d\x2b\xca\x99\xf7\x7b\x84\xd9\x8d\x7b\x24\xc9\xc2\x0f\xd7\x76\x8f\xd0\x38\x0d\x6b\x37\x36\x03\x40\xd1\x35\x98\x04\x78\x20\xdc\xed\x88\xa8\xd4\x2d\x57\x29\x37\xb6\xef\xa1\x69\x21\xa1\xb2\xb2\xd0\xeb\x93\x16\x73\x07\x08\x38\xe6\x11\xe6\xc0\x23\x29\x0d\x86\xfe\x90\x2f\x14\xac\x3a\xcd\x02\x9e\x33\x97\xfe\xb9\x7b\x17\x16\x62\x45\xab\x40\x7a\x76\x6d\x2e\x09\x04\x42\x4d\x33\xcd\x3d\x6e\x2e\x62\xa5\x2c\x65\xdf\x7c\xf0\x04\xd1\x41\x5c\x0b\x43\x0c\x11\x27\x62\x3d\xab\x27\x2a\x2c\x2e\x2b\x43\xe0\x2b\x48\x1b\xe9\x28\xe8\x99\x54\x27\x28\x32\xbe\x09\x8b\x50\x2b\x8b\x56\x43\xc6\x74\x82\xf5\xde\x44\x03\x03\x25\x81\xf0\x8a\xfb\x0a\xea\x48\x86\x85\x82\x60\x7b\xb3\x91\x98\xc1\xbf\x13\xa8\x69\xb6\x32\x58\xa7\x58\x90\xb6\x94\x45\xff\xd3\x45\x64\x02\x3e\x47\xf8\xb1\x88\x4a\x5e\x49\xb7\xd9\x42\x5f\x28\xd5\x15\x30\x13\xfe\x37\x55\xc6\xcb\x11\x4d\xb1\x80\xe6\x0b\x3d\xc4\xad\xb3\x6a\x21\x42\x81\x28\x00\x5a\x77\x2f\xb5\x71\x89\x34\x55\x65\xbb\xd1\x75\x98\x13\x52\x3b\xad\x62\x85\x5e\x79\x28\xee\xf5\x88\x0d\x3b\xff\xf1\xd0\xec\x65\xc2\x45\x92\x33\x5c\xda\x47\xcf\xcc\x5b\x5f\xa6\x52\xb4\x72\x63\x22\x52\x24\x84\x6a\x20\x9a\x3d\xd7\x76\x66\x61\xfc\xa4\xcc\xca\x59\xc4\x56\xfc\x9c\xc3\xe1\xcf\x80\x42\x55\xaa\x5f\x39\x7b\xab\x19\x98\x04\x33\x6b\xde\x29\xe5\x5c\x6c\x37\x7d\x58\x3f\x08\x2c\xe6\x47\x23\x73\x9e\x4f\x02\x46\x06\xf9\x06\xc1\x10\xd0\xa5\xb6\x10\xe5\xfe\xd9\x6d\xab\x5f\x08\xf4\xcb\x3c\xfc\x40\xa3\x55\x57\xe1\xa7\x40\xb8\xc7\xc0\x1f\x7d\x32\x79\xdd\x9c\x4e\x87\x64\xc9\x0b\xc1\x4f\x41\x61\xdb\x5a\x37\xf0\x98\x9b\x7b\xd8\x03\x5f\x8b\xea\x39\x4e\xa1\xd6\x00\x2c\xe9\xc3\x4f\x1e\x9c\x52\xc6\xa1\x5d\x15\xbc\x5b\x25\xc6\xc1\x5a\xb0\x0d\xfd\x6a\x5b\x1b\xc9\x17\xaf\x0b\x1b\x05\xfd\x10\xd0\x61\xb3\x68\x3d\x75\xb5\xf9\xef\xfb\x22\xae\x72\x08\x5b\xe4\xf6\x79\x7b\x58\xcb\x0c\xab\x56\x18\x44\x12\x1f\x98\xbf\xd9\x58\x3e\x0b\xcc\xb7\x0f\xad\x76\x98\x0a\x7a\x73\xb2\x3c\x70\xb3\xfd\x02\xf7\x75\x7c\x11\xa3\xc2\x1d\x19\xe0\x56\x50\xff\xb8\x2b\x9e\x0d\xf8\xa6\x73\x5d\x48\x01\x56\xf4\x79\x49\xd4\x45\x85\x1b\xae\xaa\x5e\xe2\x38\x14\xa4\x1b\x25\x23\x4f\xb9\x2c\xc0\xdf\x19\x80\xd0\x23\xd5\x1b\x5c\xf4\xc3\x11\x85\xc1\x18\xe3\xee\x3c\x0c\x0a\x46\xe0\xa2\xbe\x6f\x1d\x3a\xe4\x52\xcb\xb6\x6f\x0f\xd9\x19\x71\x34\x2d\xa7\xb1\xb9\x96\x58\x9d\x94\x09\x67\x81\x55\x21\x95\xc4\x33\xca\xf1\x9c\x37\xf9\xf1\x4f\xa0\xae\x15\xae\x0b\x02\xb9\x39\xe4\x02\x03\x4f\xf8\x18\x85\x93\x9d\x94\x4e\x60\x4f\x47\x4f\x21\x52\x43\x89\x39\x0f\xda\xda\x06\xe3\x0d\x69\x06\x8c\x88\x48\xcf\x0a\x95\x1e\xab\x25\xc4\x91\x25\x62\x94\x4f\x40\x24\x68\x18\x7a\x23\x23\x9d\x33\x63\x2f\x29\x12\x3d\x49\xb7\xde\x13\x08\x33\x98\xdb\xa9\x7d\xed\xe1\x2f\x79\x59\xb9\x52\x47\xa0\x8f\xc8\xe4\xb5\x39\x9d\x1c\x03\x5c\x08\x94\xcc\x75\xae\x98\x1c\x2d\xd4\x93\x54\x13\xbb\xeb\x68\x53\xfe\x04\x65\x5c\x77\xd1\x58\xc1\x23\x7b\x3e\x0d\xec\xa5\x63\x6d\x69\xe0\xdb\xc5\xac\xaf\x72\xb6\x0c\x10\xbb\x98\xcc\xdd\x60\x09\x8a\x03"}, -{{0x85,0xb4,0xd7,0x64,0x16,0x91,0x28,0x62,0x6f,0xd9,0xc7,0x82,0xad,0x61,0x16,0x22,0x9e,0xdd,0x77,0x63,0x1c,0x2b,0xc9,0xb8,0xee,0x54,0xb3,0x65,0x42,0xc1,0x49,0xeb,},{0x6a,0x09,0x89,0x7e,0x62,0x9b,0xb4,0x37,0x04,0xde,0xbb,0x67,0x15,0xc9,0xde,0xa5,0xd8,0x92,0xb6,0x34,0x30,0x64,0x40,0x99,0x7c,0x3c,0x9e,0x94,0xbe,0x8a,0xb5,0x47,},{0x4a,0x79,0xc4,0x42,0xa4,0xc3,0x9c,0x62,0x89,0x26,0x17,0xef,0x8e,0x80,0xb4,0x09,0x11,0xc4,0xb9,0xd3,0xff,0x0a,0x56,0x73,0xb5,0x7b,0xdb,0x84,0x54,0xad,0x73,0x67,0x69,0xdf,0x27,0xc7,0x8a,0x4b,0xf7,0xad,0x56,0x60,0x40,0xe7,0x47,0x27,0x8b,0x11,0xeb,0x65,0xcf,0x9e,0xc7,0xeb,0xa8,0x66,0x12,0x0a,0x36,0x54,0xf4,0x71,0x6e,0x00,},"\xb2\xa0\x49\x3d\x47\x1c\x33\x91\xf7\xad\xd1\xe2\xcf\x0b\xfb\x32\xab\x05\xdb\xcb\x14\xf6\xe4\xf5\xf3\x46\x3a\xa8\xd9\x95\x52\xf4\x33\x02\x20\x46\xd2\xf8\xeb\x76\x3c\x01\x71\xfc\xb1\xe7\x4a\x04\x9f\xfe\xb4\xb8\xf0\x10\x0b\x82\x10\xfc\xe8\x56\xb2\xe1\xa8\xe7\x39\xd2\xf9\x36\x73\xef\x8f\x8f\x40\x49\x8b\x30\x81\xfa\x1f\xd7\x85\x19\x8c\x6d\x37\x0e\x16\x2d\x41\xab\xe8\x31\x86\xf2\x32\x97\x83\x40\x8b\x9b\x88\x0d\x00\xf8\x1d\x53\x10\x0b\x42\xd2\x7a\x26\x1f\x20\xcd\xee\xd1\x9c\xc5\x8c\xb8\x63\x12\x81\xd8\x0d\xb1\x92\x53\x10\xe2\x35\xe4\x49\x66\x30\x9b\x87\x9b\xdf\xc2\x32\x22\x14\x33\xba\xe5\xca\xe4\x66\x90\xcb\x52\x7b\x67\x79\xe1\x1f\x1b\xd2\xa5\x6b\x59\xc5\x6e\xd4\xd9\x4f\xdf\x7a\xa8\x9d\xfa\x9b\xf2\x0d\xbf\xa6\xa4\x39\x8b\x98\x38\x45\x17\xe1\xdd\x5d\x2c\xd9\xce\x52\x4a\x47\x36\x2e\xf3\x2a\xc7\x92\x74\x2a\x12\x9c\x9e\x06\x13\x08\x76\xab\x5a\xd5\x51\x8e\xab\xc5\xe8\x0b\x02\x2d\x8f\xa1\x3e\x50\xd5\x5d\xed\x58\x95\x33\xe6\xea\x32\x24\x2c\x1b\x3f\xd7\xe6\x5f\x80\xde\xe7\x20\xb6\xd8\x7d\xcf\xf3\xe3\xdf\x04\xc8\x02\xd2\xe9\x14\xa8\x7a\x36\x29\xc9\x0b\xb6\x9e\x0a\x6f\x8b\xbb\x5e\xe5\x05\xf1\x43\xc9\x97\x73\x75\xad\xb0\x65\xc3\xe3\xd3\x91\xf9\x05\xfa\x3c\x33\x6c\x9d\xa4\x1e\x4a\x23\x20\xbc\xf4\x60\x97\x6f\xc7\xeb\x1f\xb6\xc6\xa3\xc3\x95\xdb\xd1\xd2\x8a\x1b\x09\xcd\xb9\xae\x9f\x9a\xae\xe4\xd9\xc5\x66\xa2\xac\x40\xad\xd8\x70\x47\x9f\xaf\x54\xad\x1b\x76\x97\x71\x0b\x4e\xb6\xf7\x32\x02\x44\xb5\x97\x57\xd1\xea\xc3\xd9\x22\xb7\xa7\x30\xb1\xac\xf0\xde\x9a\x45\xd4\xac\x87\x9d\x21\xfc\x61\x6e\xf3\x96\x5d\x74\x34\x5e\xd7\x07\x79\xeb\x68\x32\x80\xce\xe2\x5b\xf3\x73\x9b\xeb\x6b\x4c\xdf\xa2\x5d\x20\x2d\xa1\x3a\x4a\x67\x30\x40\xd9\x70\x48\x65\x8b\x92\x05\x47\x95\x05\xd0\xbe\xe4\x88\x0a\x73\x99\x7c\x70\x82\x5a\x6e\xc5\xfd\x9f\x95\x2e\x65\xfa\x02\x22\x54\x45\xfc\x3b\xdf\x4a\xde\xa3\xd4\xd2\x25\x51\xcb\xac\xeb\x38\x74\x79\x8d\x6a\x33\xa6\x66\x3f\xe3\x75\x70\x81\xd6\x24\x3d\xfd\x7c\xd2\xee\xbf\x60\xa3\x89\x9f\xa1\xf8\xf6\xc9\x56\xa3\xb1\x83\xf8\x9b\x9e\x7d\x2c\xa3\x64\x48\x58\x4d\x53\xaa\x8b\x44\xe6\x5a\xd3\xe5\x27\xf7\x87\x23\xfa\x6f\x59\x22\x42\x98\xdf\x31\xd5\xe8\xad\xa5\x67\xc8\xd1\xb1\x1f\x3b\x13\x14\x75\x53\x31\xc1\x73\x2d\xc5\x4a\x12\xa4\x35\x6e\xdd\xa4\x7e\x3c\x13\x0b\x32\x52\x82\xa3\x54\xbf\xe1\x5c\x30\x00\xd2\x07\x82\x29\x31\x79\x41\x87\xe0\x97\x3a\xb8\xef\x87\xbf\x89\xc3\x54\xa0\x35\xa8\x1f\x45\x91\x12\x23\x56\x3b\xfd\x99\xf9\x0a\x75\xe5\x3d\x01\x0d\x89\x29\xf4\xf8\x5a\x5a\x5a\x4f\x9f\xcc\x1c\x78\xf0\xa2\xfc\x46\x6f\x5f\x1c\x65\x22\xcf\x62\xa7\xbe\x37\x88\x07\x96\xe9\xb3\xca\x09\x11\xec\xca\x3f\x22\xc3\xb2\x4d\x5d\x9d\xaa\x68\x88\xf8\x9a\x8f\x71\xa1\x58\x59\x35\x9c\xea\x46\x8e\xf2\x38\xec\xf6\x46\x19\x27\x83\xa2\x57\xad\xda\xde\x90\x47\xe1\x3e\xdd\x8b\xcc\x1f\xd4\x17\x7c\xb2\x0f\x88\xd1\x19\x98\xd9\xc7\x26\x2d\x64\x8c\x2b\xf6\x6f\xb2\x27\xb9\xb3\xa9\xed\x46\x96\x2d\x22\x57\xa4\x20\xf6\x4b\xea\xd9\xe2\x86\x57\xb5\x21\xdb\x2e\x22\x16\x52\x87\x79\x1f\x3a\x1b\xec\x4c\x78\x22\xa6\xca\xbd\xe5\xec\x77\x01\x88\xcb\x74\x49\x8a\x4f\x08\xe5\xa3\xa7\x63\x9d\x24\x0a\xe3\xf4\xfd\x03\x53\xc0\xdd\xa8\xae\x41\x0b\x9f\xa7\xf4\x3f\xee\xd1\x3e\x9f\x13\xe6\xc9\x41\x0a\x1d\x24\xcd\xfc\x2c\x8e\x64\xa1\x5a\x12\xf7\x55\x45\xb0\xa5\x75\x71\x35\x23\xd4\xdf\xa1\xa4\x74\x27\xa8\x85\x1b\xa9\xac\xcc\xad\x78\xb4\xef\x6a\x18\x5f\x5c\x3b\x00\x11\x90\xdd\x8f\x37\x08\x8a\x00\x0a\xcc\xf4\x48\xbe\x8d\x49\x37\x1d\x9d\xa2\xe1\xcb\x5f\xfe\x07\xd4\x1a\x5c\x22\xe9\x46\x60\xac\x37\x13\x5a\xc8\x58\xcb\x17\x69\xcb\x66\xe8\x26\x9f\xd5\x33\x58\xec\xac\xf5\xdd\x92\xc7\xeb\x61\x86\xb4\xd4\xd6\x13\x0a\x73\x2d\xc1\x0b\xbb\x2b\xe3\x2f\x9b\x1d\x69\x51\x01\x4a\x63\x5c\x12\xd2\x2f\x0d\xc5\xbd\x5c\x2a\x3f\x96\xae\xc6\x2e\x77\x77\x94\x7e\xaa\x02\x28\x12\xca\xce\xd3\x3a\x5b\xef\x9f\xf8\x83\x5f\x88\x03\x67\xa3\x7b\x0b\x76\xd2\xdd\xe3\x96\xc6\x14\xe1\xa4\x72\x1e\x00\x0c\x00\xf1\x61\x93\x5b\x14\xa7\x38\xa1\xb7\x0f\x6e\xa5\x42\x55\xb7\x95\x18\x69\x64\x62\x12"}, -{{0x33,0xd4,0x77,0x60,0x2f,0x29,0x63,0x05,0xa6,0x71,0x9e,0xa6,0x94,0xc0,0x44,0xe9,0x0d,0x23,0x3c,0x2d,0xea,0x85,0xc4,0x6a,0xbe,0x19,0x20,0xe8,0x8c,0x31,0x78,0x49,},{0xff,0x6f,0xee,0xa0,0x28,0xec,0x34,0x6d,0xd4,0x91,0x07,0xbb,0x71,0x3f,0xdd,0xbb,0x28,0x2e,0xbc,0xd0,0x34,0xe2,0xea,0xfc,0x7c,0xdb,0x1c,0x5a,0xdf,0x92,0x63,0x90,},{0xca,0xa2,0x87,0x98,0x95,0xd4,0xf6,0x20,0xb9,0xeb,0x5f,0xed,0x22,0xb4,0x56,0x2e,0xeb,0x1a,0xd6,0x38,0x22,0x96,0x8f,0x76,0xad,0x91,0x07,0x6b,0x16,0x6c,0x05,0xee,0x20,0x86,0x4d,0x98,0xbb,0xbc,0x6e,0x79,0xdd,0x03,0x62,0xca,0xcf,0x7a,0x21,0xb4,0xcf,0xc2,0x30,0xd6,0x35,0x5d,0x43,0x12,0x0c,0xff,0xfb,0x94,0x8b,0x8f,0x6c,0x0e,},"\xcf\xea\x07\xa7\x79\xf1\x53\x7e\x49\x81\x23\xc6\x76\x29\x05\x73\xef\xcc\x5d\xb7\x02\x45\xd9\x3d\xea\x5c\x05\x72\x6f\x87\x13\xd0\x02\xae\x66\xc1\xc9\x69\x07\x47\xca\x92\x30\xb1\x62\x9d\x36\x62\xab\x73\xd6\x6b\x94\x98\x79\x16\x4b\x21\xa3\x5f\x40\xcf\x37\x99\x04\x19\x08\xed\x6f\x92\x29\xec\xb3\x90\xc5\xf2\x22\x34\xe1\xc5\xf2\x6b\x3a\xb5\xba\x59\xe7\x8c\x64\x96\x98\x71\xb4\x28\xb7\x85\x16\x77\x75\x55\xaf\x4e\x89\xc6\xfb\xc1\x93\xa9\x46\x95\x22\x6c\x6d\x32\x99\x91\xa1\x1b\xd5\x80\xd1\x89\x56\x08\x9b\x58\xa0\xe4\x2c\xa3\x5f\x6c\x6d\x26\x09\xad\xe0\xd0\xb6\x19\xd4\x89\x25\xc6\x8c\xd9\xd2\x25\x0d\xff\x27\xcf\x2f\x0d\x44\x44\x87\x09\xb6\x79\xf3\x5b\xbd\xce\x0f\x49\x6b\x0a\x16\xca\x67\xea\xce\xec\x25\x8b\x1a\xec\x91\x77\x5a\x3a\x2e\xe8\x01\xb1\xc9\xa2\x26\xa6\xb0\x01\x92\x6a\x05\x7a\x06\x30\x67\x27\xee\xda\xe8\xc5\x77\x53\x1d\xf0\x4a\xc0\x9b\x5b\x49\xbc\xde\xab\xde\xb8\xac\x4e\x8e\x82\xcf\x1e\x7a\xf8\x35\xfc\x61\x1c\xa7\xa6\x84\xb8\x35\x26\x04\x24\x15\xb1\xd6\x65\x2e\x86\x34\x31\x1e\x19\x46\x27\xea\xe7\x8d\x01\x1e\x6f\x40\xf6\x45\x79\x4e\x36\x89\x5a\x23\xe1\xbd\x84\x88\x3a\x39\x3e\xcf\xe5\xa2\x48\x02\x6a\xea\x86\x44\x70\x59\xf7\xa4\x29\x36\x8f\x21\xc8\x9e\x01\x45\x20\x79\x78\xb9\x13\xc8\x0a\x22\xd7\xca\xf2\x67\x3f\x7c\x76\xf6\xc2\x6c\xf8\x84\x41\x2e\x17\xd0\xc2\x55\x43\x0f\x50\x2b\xce\x74\xe3\xa3\x10\xd1\x7f\x6f\x4d\x48\x5d\xa2\x80\xed\x5b\x5e\xea\x6c\x49\xba\x74\x8d\x76\x48\x14\xb9\xe3\xda\xf6\xfc\xc2\x18\xc2\x74\x0c\xa7\x70\x18\xf7\x13\x44\x51\x9d\xa8\x2a\xda\x31\xe0\x01\x92\x4f\xc7\x76\x79\xe3\xe9\xff\x9f\xab\x67\xdd\x09\xa6\x19\x24\xc8\x21\xa1\xfd\x99\x9f\x74\xdf\xa3\xf8\x19\xad\xb3\x1d\x15\xe5\xed\x8a\xaa\x52\xc1\xbd\x7c\xca\x26\x67\x11\xa7\x4d\xd6\x21\x04\xef\x3c\x2b\xf7\x37\xfc\xe6\x94\x2b\x34\x8a\x33\xc3\xdf\xd6\xd9\x2a\x72\x4b\x6d\x58\x78\x42\x1a\xeb\x23\x0a\x53\x3f\xe2\x1c\x8b\x2f\xd3\xda\x59\x6a\x61\x80\xa4\x5c\x98\x6d\x7e\xce\x4c\xdc\x8a\xd6\x81\xea\xd6\x90\x64\xbb\xdd\xfc\x20\xf3\xc5\x21\x25\xf8\x33\x95\xbe\xd1\x55\x7f\x67\x18\x2b\x9f\xe9\x91\x38\xaf\x3c\x35\x6c\x5e\x65\x29\x78\xdd\x23\x8b\x76\x1c\x74\x2f\x81\x58\xe2\x31\x4b\x96\x42\x08\x33\x09\x78\xb0\x62\x0a\x13\xa1\x6d\x76\x1d\x52\xf0\x6e\x46\x6a\x40\x94\xb6\x5c\xd6\xf2\x68\x54\xae\xd6\xf9\xa8\xc2\xa8\x84\xa0\xd0\xbf\x4e\xe5\x87\xee\xb8\xb6\x02\x48\x72\x39\xa7\xe5\x81\x72\xc8\x09\x98\x3a\x8d\xb1\xc1\xfc\x7c\xe8\xc4\x8b\xc8\xa6\xfb\x81\x2d\x6a\xa9\xe8\x3a\x3a\xb4\xdd\xf7\xa8\xd4\x0d\x3f\xe0\x0e\xa1\x6e\x04\x06\x2b\x8a\xce\xb9\xc9\x9e\xef\xa4\x1f\x4f\x87\x44\x78\x28\x12\x6d\x0d\x9c\x9f\x86\x05\xe8\x46\x7c\x5e\x4d\x67\x1d\x5c\x6d\x9f\xa7\x0d\x74\x70\x98\xd9\x41\x21\x12\x23\xb9\xbc\xf2\x61\x93\x8d\x67\x04\xa3\x2d\x22\xc6\x1e\x30\xf3\x57\x0a\x1f\x5d\x09\x98\xb4\x79\x10\x80\x88\x2a\xa5\x62\x31\x67\xb6\x3a\x23\xf3\x40\xf0\xe7\xc6\xf9\xa8\x30\xa7\x5b\x74\x63\x1f\xa5\xb5\x7a\xfd\xb1\xe6\xbc\x22\x69\x9b\xb0\x31\x56\x67\x5d\x59\x83\x53\xa5\xd1\xb5\x58\x97\xe4\xc1\x10\x61\xdd\x14\x5f\x23\xe8\x53\x7c\x63\x2f\x75\xc1\x0d\xf0\x5b\x25\x54\x72\x38\x57\x40\x17\xfe\x7b\x64\xb8\xe9\x98\x69\x15\x7f\xee\x35\xf7\xad\x7e\x63\xe9\x95\x93\x30\x29\x29\x50\x3a\x96\x76\x80\x23\xb4\x12\x5a\xd7\x49\xdf\xf4\xb9\x92\xee\x5c\x2b\x4f\x3a\xda\x48\x89\xe4\xae\x62\xec\x15\xd2\xdb\x59\x69\xd7\x30\xdb\x30\x75\x47\xf6\x38\xc3\x18\x50\x32\xb1\x2f\x75\xfb\xb3\x17\xe4\x7d\xf7\xb9\x29\x2a\xe9\xe7\x6a\x2c\x0a\x06\xfc\xad\x10\x8c\xdd\x23\x5f\x6e\x38\xd9\x67\xb6\x37\x95\x11\xff\x69\x65\xc2\x2f\x2c\x66\x80\xa1\x2b\x03\x04\xeb\x2b\x29\x6c\x99\xa7\x6c\x27\x29\xd9\x8e\x0a\x78\x24\xb6\x7f\x3f\xe8\x42\xd6\xf6\xab\x27\x3e\x89\x48\x45\xb3\x2d\xc6\xdd\xfc\x7a\x22\x0f\x76\xbd\x96\x5c\x69\x85\x81\x83\xc8\xf3\x57\x39\x5f\xc5\x7d\xc8\x29\xde\xfa\xac\xb5\x60\x3a\x75\x78\x68\xd5\xe5\x62\xf9\x78\x1e\xe3\x9e\x0e\x94\x68\x8a\xd3\x54\x5b\x32\xdd\x73\x66\xb6\xb0\x47\xe8\xd1\xd3\xd5\x65\x99\x7b\x23\x6e\x7f\x75\x96\xc5\xf8\xd7\xc1\xc1\x1b\xcf\x4a\x24\x46\x20\xcb\xd2\x1d\x55\x9a\x7c\x9b\x3f"}, -{{0x70,0x74,0x56,0x86,0x11,0xa6,0x6d,0xfc,0xa8,0x30,0x7c,0xae,0x60,0x8b,0xb2,0x69,0x95,0x84,0x4d,0xf4,0x35,0xe5,0x30,0x0e,0x5b,0x4d,0x72,0x91,0xcc,0x22,0x90,0x7f,},{0xdd,0xab,0xdd,0xd1,0x5e,0xaf,0x83,0x11,0x5d,0xdd,0x06,0x5d,0x7e,0x22,0x0b,0x1e,0xfc,0x26,0x2a,0x61,0xc5,0x2e,0x91,0x43,0x47,0x44,0x2b,0xde,0x6d,0x00,0x25,0x06,},{0x7f,0x65,0x31,0x34,0xc0,0xb9,0x0f,0x44,0xa4,0x89,0xf0,0xb0,0x5f,0xc4,0x07,0x07,0xad,0x9f,0x13,0x98,0xf3,0x40,0xb4,0x47,0xa3,0xc9,0x86,0x1f,0x51,0x1c,0x9f,0x15,0x68,0x80,0x3b,0x76,0x84,0xa0,0x4a,0x89,0x8c,0x45,0x15,0x4d,0xd4,0x86,0xbd,0x50,0x75,0x89,0x98,0xe1,0x26,0x43,0x93,0x78,0xb3,0xf5,0x9f,0xf3,0x67,0x49,0x2a,0x0a,},"\x6c\x13\x74\x23\xea\xc7\x90\xb8\xe8\xe4\x18\xb2\x90\xe0\x57\x9c\x7b\x86\xb1\x4a\xed\x81\x8d\xe8\xce\x53\xce\xa3\xf3\x40\xa1\xa9\x53\x91\xf9\x84\x96\x8f\x2b\x42\x29\x28\x2a\x81\x61\xc0\x9a\xb1\x49\xcd\xac\xd6\x69\x70\xb4\x01\x3f\x52\xe5\xe6\x8e\xa8\xc9\xdb\x68\x5b\x2c\x53\x07\x35\x00\xe5\xb3\x5e\x29\xea\x0b\xa1\xf4\xd1\x59\xa5\x58\xd3\x61\xb0\x65\x16\x83\x6c\xf7\xb9\xea\x50\x1f\xa0\x50\x6b\x98\x5f\x03\x6a\x82\xd9\xe0\x84\x48\x9d\x3b\xfe\xd3\x40\x93\xe2\xd6\xd9\xed\xf5\x57\x85\xed\x35\xa9\x0c\xe5\x6c\x76\x16\x86\xcc\x3e\xa1\xa2\xc7\x6a\xda\x5e\xc8\xc1\x45\xd8\x18\xb0\x47\xcc\x51\x6e\xec\x5d\x2d\x6a\x93\xa5\x55\x92\xd8\x92\xe3\xd5\xcd\x10\xc2\x50\xc0\x4b\x04\x9b\x38\xfc\x7e\xc0\xf3\x9a\xba\x15\x82\x40\x07\x33\x6c\x2b\x0f\x7f\x81\xd6\x4d\x5c\xa3\xe2\x9d\x6f\xda\x4c\x23\xd9\xba\x65\xd9\xfe\x3c\xb4\xe0\x39\x13\x69\x72\x87\xb4\x6a\x0b\x1f\xcc\xd2\x62\x4e\x39\x7a\xe9\x5c\x52\x54\xbc\xd8\x8d\x2c\x7c\x8f\x70\xfd\xc8\x17\x3f\x64\xc1\xde\x32\x28\x1a\xb4\x18\x46\x93\xb4\x8a\x34\x9e\x67\x82\xbc\x89\x92\xb4\x3c\x7d\xe7\xcb\x9d\x33\x92\x9b\xf9\x53\x06\xc2\xaf\x7e\x93\x8d\x84\x86\xb3\x86\xf9\xfd\x3f\x0f\x71\x61\xe0\xe6\x86\x2d\x4f\x92\x81\x44\x68\x65\xa1\xc9\xbe\x24\x60\xef\xbc\x20\x15\x1b\x06\xe7\x9d\x01\x46\x17\xd0\x30\x0e\x67\x1d\x48\x76\x74\x58\x59\x66\x25\xb7\x6d\xff\xc5\x58\xaa\x9b\x40\x61\x21\x96\xec\x82\x7e\x1c\x6f\xff\x51\x8f\xb7\xad\x4b\xf8\xc4\x6f\xcb\x27\x88\x85\xaa\x49\x1b\x77\xa2\x89\x95\xcf\xb9\xd7\x96\x40\xaa\xd1\x74\xc6\xdf\x43\x93\x8e\x3f\x13\x85\x20\x5c\x54\x59\x5b\x33\xde\xde\x50\x14\x37\x46\xa1\x70\x5e\x7e\x0b\x69\xaf\x4a\x26\xc3\xb7\x65\x15\x05\x18\x92\xb1\x5c\xa6\xe4\x8c\x3d\x91\xfb\xc7\x5e\x8f\xe4\xa0\xfe\x8e\xd2\xc2\x6c\x10\x73\xbe\xb7\x0e\xa3\x8d\x09\x27\x02\x92\x78\x40\x67\x55\xae\x6e\x11\xda\x37\x86\x53\x64\x95\x15\xe0\x08\x5b\x5e\xa7\xdb\x32\x49\x20\x8e\x33\xa6\xc8\xb6\xae\x8c\xd8\x0c\x9b\xd6\xb9\x83\xe7\x3e\x9b\x91\xdb\xec\x09\x1f\xae\x99\x5f\x80\x32\x42\x7e\xde\xc0\x2c\xad\x90\x55\xeb\x8b\x7d\xbc\xfa\x80\xd4\xf6\x4f\x57\x27\xa1\x52\xf1\x1c\x47\xe5\x2d\x75\x3a\x57\xb6\xe5\xfd\xdf\x77\x4c\xea\x4d\xa9\x10\x02\x68\x19\xc4\x1e\x32\xb4\xf1\x99\x72\x7e\x23\xc5\x4a\xb5\xd7\x01\x42\xb8\x54\xa2\x7b\x04\xe6\x4c\xf4\x4a\xf2\xa8\x99\x5e\x12\x00\xbd\x11\x7c\x7a\x16\x74\xed\xef\x59\xbc\x53\xf7\x3a\xda\xf6\x38\xe0\x77\x3b\x85\xb5\x63\x34\xaf\xf6\xe1\x17\x43\xe3\xa3\xd3\x61\x4a\xa8\xa3\x75\xb3\x78\x1e\xc8\x14\xcc\x08\xe7\x1e\xfa\x78\x18\x51\x9c\xb2\x4a\xf8\x2c\x33\x1d\xfd\x6a\xc7\x8e\xc1\x7f\xd7\x17\x4b\x61\x02\x1e\x8c\xf9\x01\xa2\xaa\xa6\xad\xbc\x90\x2a\x91\x6b\x2a\x2f\x4f\x79\xe5\x51\x50\x1f\xbf\x01\xdf\x6b\x85\x18\x50\x4c\x1e\x94\x64\x69\x38\xbe\xd1\xa8\x50\x9c\x2a\x38\xfb\x6a\x79\x8a\x78\x58\xf4\x09\xb0\xf2\xfb\x9b\x3f\x48\x17\xe5\x68\xc5\x2d\x9a\xbf\xe2\x16\x8c\xc3\x65\x0f\xc4\x3e\x0f\x99\x75\xfe\x29\xe3\x3a\xed\x1a\x7b\xf3\x0d\x86\x31\x15\x07\x90\x65\x0a\x3c\xb7\x8c\x36\x8f\x1a\xea\x9a\xc6\x0c\x5e\xeb\x96\x9a\x45\xf8\x4a\xa3\x73\x66\xa8\x39\x77\x19\x0f\x41\xae\x42\x1e\x0c\x46\xfd\xa3\xfa\x01\xb9\x26\xfc\xef\x82\x24\xfd\xa3\x6d\xf4\xf8\xa8\x77\x01\xfe\x79\xfe\x06\x28\xef\x0c\xc0\x2d\xf2\xbd\x78\x32\x07\xc7\xdb\x87\x11\x9a\x03\x69\xfe\x16\xee\xb3\x8f\xdc\x9f\xb3\x5d\x9e\x19\x5f\xe1\x4f\x8c\x10\x38\x20\x8a\xb9\x77\x00\xaf\x79\xf2\xe2\xe0\x54\x96\x83\x02\x07\xc7\xda\x8d\xbe\x8e\x9b\xb7\x3b\xc4\x71\xa4\x3f\x1b\xe6\x50\xfa\x92\x81\x9a\xeb\x5d\xc7\xee\xd7\xee\xd8\x17\x12\x70\xd2\x19\x25\x7d\x19\x61\x0b\x89\xd2\xd6\x2d\x3f\x5b\x64\x8e\x13\x9e\xed\xf1\xff\x74\xbe\x01\xa5\xef\x1d\x95\xf8\x12\x92\x26\x01\xee\x92\x51\x51\x57\xc4\xec\xad\xfa\x3e\xef\x9f\x2a\x67\x7c\x00\x3c\xa4\xab\x9b\x2c\x45\x47\x2c\xe5\x5e\x18\xf4\x0a\x21\xfe\x1b\x0d\x45\xb5\x0b\x50\xc5\x2a\x0b\x1a\x5d\x7c\x37\xd8\xeb\xc1\x5e\x02\x05\x84\xd9\xed\xd7\xb5\x65\x05\xf8\x20\x78\xe0\xf8\x99\x38\x91\x35\x01\x4c\x86\xd1\xe2\xed\x49\xf9\xcd\x31\x90\x76\x94\x35\x53\xa3\x12\xae\x05\xab\x33\x35\x26\xe1\x36\x71\x4f\x09\xa4\x02\xb3\xc8"}, -{{0x7d,0x7c,0xa8,0xe8,0xd3,0xb8,0x43,0x44,0xa5,0xe4,0xde,0xa0,0x8b,0x33,0x8d,0x8f,0xaa,0x5f,0xfc,0x11,0x9c,0xe5,0x66,0xef,0x65,0x6f,0x0f,0x45,0x84,0x77,0x5b,0x21,},{0x0b,0xde,0x34,0xb7,0x46,0xd2,0xc5,0x49,0x08,0x53,0x06,0x4d,0x48,0xc6,0xb4,0xc1,0xcb,0xbc,0x3e,0xe7,0xbe,0xff,0x5e,0x8f,0x68,0x4c,0x12,0x0f,0x31,0x5d,0x7e,0x4e,},{0xd0,0xc3,0xe2,0x48,0xa8,0xcb,0x2d,0xdc,0x7e,0x9f,0x21,0xc9,0xc5,0xb0,0x09,0xf7,0x0e,0xa2,0x9d,0xa6,0x89,0x7c,0xd9,0x2c,0x26,0x0f,0x04,0x7e,0xd6,0x8a,0xa1,0xc8,0xb9,0x65,0x7f,0x9d,0x82,0x6e,0x88,0xf4,0xa5,0x12,0xc5,0x00,0x3b,0xe6,0x40,0x68,0x80,0x74,0x12,0x63,0xae,0x7c,0xe6,0x86,0x0e,0xfe,0x73,0xad,0x54,0xd4,0x82,0x04,},"\x0b\x72\x70\x75\x34\x5d\x61\x9f\x5c\xdc\x7f\xc4\xc4\x3c\xdc\x19\x10\x58\x11\xd9\x5d\x06\x9f\x81\xc0\xa6\x2f\xe1\xe1\x17\x8c\xf1\xc3\x5d\xb0\x5e\x2d\xe8\x7d\x11\xae\x1a\x6f\x53\xef\x38\xb3\x9b\xf4\xed\x8f\xbf\x56\xef\x01\x7a\x1d\x3c\x15\xb6\x4f\xe4\xb2\x61\x0b\xf6\x9b\xd1\x9a\xc7\xaf\xd4\x6a\x2b\x87\xb4\x88\xb6\xc7\x8a\xd4\x56\x81\x1c\x1d\xd6\xbd\x4a\x6b\x5d\xa6\x98\x73\x9f\xd1\xa1\x4c\xeb\x9f\x27\xf1\x24\xb6\x9f\x6b\xd1\x6d\xe5\x53\x7a\xad\x80\x68\x1c\x56\x33\x58\x03\x94\xda\x3b\x84\xe9\xb7\xa5\x5e\xba\xb8\x52\x2d\x2d\x6b\xf1\xaa\x4e\x7b\x15\x9c\xbf\x4e\x20\xb5\x0b\xfe\x9c\x71\x1a\xa0\x47\x11\x9f\x1d\xad\x87\x49\x26\x0b\x87\x63\x9e\x9c\x14\x1d\xef\x62\x02\x6a\x99\x03\x73\xdc\xfd\x99\xf7\x7b\x0f\x5e\xa6\xad\xfd\x8f\x59\x4b\x9c\xe4\x10\x64\xa5\xed\x30\x7b\xf2\xd8\xd1\x73\x70\x49\x8a\xd7\xf4\x5f\x9c\x4d\xd2\x6c\x42\x0f\x45\x0f\x53\x62\x3b\xb6\xd7\xf3\xf4\x6a\x14\x9d\x8f\x13\x5b\xc2\x91\x33\x10\xfb\x8f\x90\x43\xd0\x99\x27\x8b\xbe\xba\x39\x17\x9f\xa3\x67\xb0\x16\x73\xe1\xc9\x53\xef\xfd\x2c\xae\xa7\x31\x1c\x47\xc0\x37\x27\x44\x09\x5b\x1c\x8f\x90\xee\xf5\xf1\x92\x9d\xb1\x99\x6c\xd5\x84\xf6\x15\xd5\x6f\xae\x3a\xec\xac\x3e\xe8\x8b\xd0\xb2\x96\xf4\x49\xcc\x27\x13\xc5\x2d\xa6\x95\x24\x8f\xaa\x8e\x38\x9b\x05\xa0\xbc\xac\x69\xdc\xe9\x71\x97\x23\x19\x4f\x43\x3b\x02\x97\xeb\x08\x59\x01\x9f\x14\x1a\x20\x7c\xe8\xcc\xb5\x98\x82\xca\xa6\xe1\x8f\x0b\x43\xbd\xdd\xb9\x0a\x0a\x85\xff\xd5\x77\xd6\x39\x4a\x1d\x80\x48\x94\x10\xf9\x2a\xfb\x85\xba\x50\x6a\xa9\xf3\xf4\x27\x44\x5d\x21\x22\x4b\x9c\xb0\x46\xc0\x5f\x1b\xac\xd7\xb7\x49\xfb\x7b\x10\x24\xd0\x92\xe4\xee\x4b\x30\xa4\x6e\xdf\x71\x84\x70\xc9\x94\x91\xc6\x8f\x48\x79\xd6\x2b\xfc\xe7\x04\x6d\x81\x38\xcb\xb9\xe7\x21\x29\x99\xa4\x49\x8b\x45\x5f\xc9\x0a\xc2\x83\xe9\x35\xde\x04\xdf\x6f\xc9\x99\xe4\x43\x4b\xe1\x10\x63\xd6\xe4\xee\x9e\x09\x6a\x87\xbc\x71\x6d\x2c\x81\x99\x16\xc3\x7a\x4e\x62\x98\xc4\x99\x45\x36\x6e\xc3\xf5\x00\x72\x0b\x06\xdc\x99\xd3\xd8\xac\x30\x3e\x6c\x26\x4e\x28\xa7\xc2\xd4\x19\xec\x62\x2a\x97\xa7\x11\x54\x4f\xb1\xf4\x73\x5b\x11\xf8\xbb\x1d\x7e\x2c\x81\x6a\x15\x62\x87\xb4\xcc\x0c\x65\xaa\xa2\x80\xb8\x37\x73\x7f\x0a\x84\xe3\x6d\xe2\xdf\x2f\xc3\xa5\x0d\xf9\x80\x91\x8f\xb9\xe5\x83\x4b\x42\xac\x0e\x0c\x72\x78\xd7\xfe\x8d\xb4\xdb\xde\xca\x01\x41\xd5\xfe\xf5\xdc\x61\x51\xf8\x7b\x86\x34\xc2\x41\xa8\xfa\x0a\x82\x71\x78\x99\x77\x3a\xe8\x9f\x53\x78\x90\xb9\x15\x5a\x7a\x05\xbc\xe4\x78\x66\xec\x20\x28\xa4\x78\x98\xd4\x85\x82\x3a\x2e\x99\x23\x19\x68\x0e\xb6\x99\xb0\xdd\x53\x58\xf5\x46\xfc\x53\x7c\x73\xd3\xa4\xb2\x23\xa0\x94\x15\x18\xb6\xd1\xe6\x6b\x27\x67\x6c\x1b\x1f\xc7\x6a\x08\x32\x05\x24\xa7\x2e\x29\x7f\xce\x17\xaa\x80\xd8\xea\x7b\x38\x8a\x55\x16\x8e\x7d\xad\xb8\x36\xe9\xde\xe7\x07\xed\x25\xc0\xee\x4d\xb2\x5b\xee\x3c\x48\x5b\x39\x64\x92\x04\xef\xaf\x28\x20\xb2\x73\x63\x68\xfc\x77\x3c\xe0\x90\xc3\x85\x37\x80\x02\xc4\x71\xb0\x94\x79\x5c\xb2\x66\xd3\x9e\xb7\x58\x0d\x70\x1b\xe4\xc8\x91\x6f\x6b\x38\xbf\xe2\x5f\xdf\x36\xd6\xc4\xad\xaf\xa9\xae\x98\x64\xc5\x7b\xb7\x37\xb4\x95\x06\xed\x38\xd6\x2d\xe6\x0c\xc0\x59\x9e\xc6\xbb\x1a\xcf\x24\xb1\xd3\x7d\x60\xef\xde\xb7\xd9\x42\xc5\x36\x03\xa2\xf0\x47\x6e\x95\x12\xc9\x38\xb2\x8d\x49\x5a\x6f\x26\xa9\x07\xc3\x96\xb8\x41\xae\xdd\x8e\x14\xac\x44\x7b\x49\x5d\xf1\xf6\x76\xda\xcc\xd5\xa7\x40\xc0\x42\xf5\x77\x2b\x7d\xb1\x7f\x4f\x1a\x3a\x1c\x8e\x7c\x48\x83\x70\xe7\x36\xb5\x1e\x69\x0f\xd2\xdd\xcb\x5a\xa6\x19\x57\xa7\xc7\x97\x5a\xcb\x2d\xcb\x91\x5d\x07\x4d\x74\x42\x79\xea\x1c\x41\x69\xf8\x68\x87\x3a\xc5\xc2\x08\x90\x16\x2c\x1d\xf9\x65\x64\x19\x97\x5a\x43\xd3\x19\x8e\x18\xc3\x09\xa1\xeb\x7c\x1d\x87\x87\x3f\xb1\x5c\x6d\xa4\x7f\x54\x8a\x01\xf6\x9b\xda\xb9\xc3\x9e\xf0\x0d\x41\x8a\x6f\x61\x9d\xd7\x3d\x7d\xb4\x5c\xbb\x6a\xd2\x25\xa2\xde\x78\x7b\xa7\x77\xbc\x73\xd2\x8f\xc3\x04\xf1\x00\x09\xf4\x02\x2c\x2c\xf8\x4d\xe0\x08\xd7\x0f\xcd\xc8\xba\x7f\x10\x7c\x36\x98\x59\xe9\xc9\x0c\xa8\xa3\x93\xb5\x53\xf2\x66\x05\xff\xd7\x23\x0c\x92\x14\x90\x70\x0f"}, -{{0xd2,0x1f,0xdd,0x7b,0x10,0xe5,0x4a,0x8b,0x6b,0xe9,0x5a,0x02,0x24,0xad,0x70,0x66,0x4d,0xd9,0x21,0x12,0xe2,0x68,0x3a,0x4f,0xd2,0x79,0xc4,0x07,0xdb,0x38,0x71,0xbb,},{0xf8,0x9c,0x27,0x2e,0x7d,0x1c,0xc9,0x3d,0x69,0xf6,0x94,0xde,0xc9,0xcc,0xe0,0x5a,0xc2,0x47,0x73,0x45,0x04,0x82,0x9c,0x56,0x99,0x74,0x13,0xc8,0x95,0x8b,0x93,0x30,},{0x6d,0x69,0xe8,0x3b,0x3e,0x7e,0xd5,0x5a,0x85,0xf9,0xfc,0x9d,0x25,0x19,0xda,0x0b,0x0a,0x1e,0xb4,0xda,0xae,0xe9,0x91,0xa6,0x65,0x1f,0x5c,0x89,0x19,0x0c,0x0d,0xe7,0x23,0x73,0xcd,0x98,0x9d,0x46,0xbe,0x13,0x67,0xf9,0xda,0xf1,0xb9,0x2f,0xed,0x3b,0x52,0xbb,0xa5,0x4a,0x1e,0x4c,0xca,0x5b,0xc8,0x72,0x6e,0xd0,0x7f,0x30,0x25,0x01,},"\xb8\x64\x4a\xdb\xef\x9c\x7c\xab\x91\x20\xac\xed\xc8\xe7\x5c\x43\x3d\x03\x6f\xfa\xe0\xf9\x55\xbe\x6a\x48\x8f\x1f\x42\x7a\x68\xa8\x90\x2d\x02\x6e\x63\xdd\x6c\x9b\xf9\xd9\x7d\xe7\x86\xb3\x1d\xd4\xf4\xc9\xa4\xf8\xa6\x22\xf1\xff\xc8\x4d\xa6\x96\x7c\xa7\x74\x33\xc3\x98\xf4\xd3\xf1\xc4\x43\x49\x89\xb7\xac\x9d\x0f\x3b\x1b\xe0\xc8\xb3\x52\x82\x4f\x4e\x7a\x08\x3f\x34\x2e\xc1\xbe\x1d\xa8\xfb\x75\x52\x42\xa6\x54\x88\x0e\xf2\x98\xf0\x59\x79\xff\x02\x6d\xdc\xc0\x44\x86\x0e\x67\x57\xa2\x9c\xfa\xa2\x22\xa3\x59\x7e\x38\xf1\x77\x99\x62\xa4\x1a\x4c\x8c\xe6\xa6\x5b\x87\x81\x99\xb4\xd8\x0f\x4a\x03\x90\xca\xc1\x9c\x22\x6e\xea\x4b\x60\x36\xe5\x7a\xd8\x30\xec\xfc\x00\x69\x3e\x26\x13\xd3\xed\xf4\x65\xfc\x8c\x4f\xa2\x93\xfd\x8c\xfc\x36\xdc\x8e\x37\xbc\xeb\xab\xec\x03\x49\xeb\xd8\x84\xe1\xb2\x8b\xce\x82\x4e\x0d\x55\xb6\xd0\x15\x38\x38\x01\x66\x8b\x34\xf5\xba\x72\x3d\x2a\xc0\xa2\x64\xfa\xb2\xc7\x28\x60\x8f\x16\x2d\xe0\x11\x79\x25\x9b\xe2\xcc\xb0\x81\x50\x02\xfd\xed\x8e\x0d\x78\xb0\x28\x07\x31\x3e\x91\x0e\xb3\xa7\x33\x7c\x53\x4e\x84\x6f\x9e\xe1\x55\x42\x6e\x4a\xef\x64\x36\x61\xb0\xed\xb4\x45\x96\xfd\xdc\xd0\xb3\xe8\x14\xc1\x37\x81\x7a\x42\x2b\xaa\x40\xc9\x05\x3d\x03\x86\xc6\xec\xdb\x58\x90\x52\x59\x47\x42\x67\x7c\x48\xdc\xfc\x8c\xd4\xa9\x36\x67\xed\x4d\x87\x64\x60\x01\xed\xa0\x79\xe8\xb9\x9d\x52\xba\x21\xc5\xec\x56\x69\xfe\xdf\x6f\x40\x44\x7a\x7f\xf8\x90\x1d\xb0\xef\x18\x47\xd3\xca\xcf\x01\x98\xa2\xf3\xbd\x7b\xcf\x2d\xd8\x11\xa0\x97\xfc\x5e\x51\x88\xb0\x3f\xdf\x54\xe5\x17\x63\x7a\x14\x50\x10\x00\xd0\xd3\x55\x16\xca\xf0\x69\x94\x02\xb4\x8f\x8d\x8c\xc3\xaf\xb1\x7a\x56\x13\x2d\x08\x23\x70\x35\xa0\xc9\x54\x90\xbf\xe5\xd7\xb7\xfb\x40\x17\x8f\x28\x1e\x4d\x87\x2e\x47\xa0\xe9\x55\xce\x97\x36\xf3\xc3\x33\xa6\xad\xf5\x0a\xd3\x19\x94\xeb\x9f\x45\x32\x7f\xac\xc8\xc5\xd1\x13\xfa\xd4\x71\x3f\xe7\xf1\x98\x01\x0d\x42\x04\x6b\xbf\xe6\x8b\x0d\xaa\x79\xdc\xb8\x75\x59\x29\xbe\x92\xf9\xca\xa1\x50\xdf\xbd\xe3\xfc\x9e\x39\x2b\x2b\x70\x1c\x30\x21\xc2\x40\xe4\x67\x9d\xe4\x11\x24\xb1\x88\x8e\x5d\xb5\xa8\x3d\x05\xce\xaf\x49\xeb\x44\x0d\xc4\x50\x26\xd4\x50\xbc\x98\x4b\x8d\x6f\x02\x85\x0e\xcb\x57\x0e\xee\x0a\x38\x19\xb1\x2b\xc2\x63\x67\xb5\xb9\x8e\x1b\x14\x1c\x9b\x0a\x96\x90\xea\x4a\x37\x00\xda\xd1\x23\x95\xf9\x75\xd1\x1c\xd7\x7f\x96\x36\x88\x31\xf2\x1f\x4e\x96\x8c\xc5\xba\x9e\xf8\x24\x74\x03\x8b\xc7\xaa\x26\x12\x2d\x21\x8b\x74\x30\x41\x50\x6a\xeb\xbd\x1f\x98\x79\x59\xfd\x16\x0d\x6e\xb7\xd5\x8d\x4f\x57\x6f\x8c\x0c\xa8\xaf\x86\x8e\x39\xb5\xea\x87\x20\x39\x37\xe0\x30\x8a\xcb\xea\xe9\x1e\x10\x60\x7e\x44\xe8\xab\x49\x5b\xc0\x1d\xd5\x73\xfb\xad\xc9\x44\x79\xff\x92\x08\x2c\x7b\xb7\x51\x34\x79\xc7\x0f\x04\x07\x76\x90\x25\xd3\x4d\x72\x14\x0c\x25\xd8\x21\xf0\x34\xa3\x98\x51\xa9\x3c\x62\x3b\x71\xc9\x40\x0e\x94\x26\x39\xf2\x8b\xbd\x03\x2e\x1d\x8d\x3c\x05\x9f\x7c\x2c\xd3\x1d\x74\x76\x46\x2d\x27\x76\x03\x5d\x07\x88\x02\x02\xdb\xfe\x9e\x07\xd1\x54\x62\x2d\x7a\xc6\x17\x5a\x5a\xfa\x79\xfe\xd4\xdc\xc1\x37\x12\x62\x0c\x41\x99\x4e\x11\xd9\x24\x30\x8f\xb2\xff\x3a\x1e\xda\x44\xc7\x61\xbc\x73\x6f\x34\x51\x22\xf0\x2a\x40\xae\x6f\x7d\xbd\x03\xd9\xfe\x96\xee\x3d\x7a\x3b\x4a\x5e\xef\xbf\xcc\x56\xdc\x42\xef\x27\xbd\x80\x85\x17\x60\x38\xb9\xeb\xae\x63\xaa\x75\x03\x52\x75\xec\x34\xe4\x18\x57\x39\xd6\x36\x24\x67\x70\xac\xcc\xc6\xdc\x62\x0e\x2f\xc9\x15\x6f\xa9\x48\x3e\x0d\x9c\xae\x0e\x8c\x46\x39\x48\xa3\xd9\x7a\xe8\xdd\xa5\x96\x6c\x88\xf0\x70\x93\x29\x2c\xce\x22\xbb\xda\x06\x2b\xaa\xfa\x7f\xe8\x4d\x0b\xa2\xd2\xdd\x29\x5b\x23\x45\x8b\xca\xeb\x2e\xf7\x42\xa2\xed\x1c\x83\x44\x83\xcd\x70\x93\x85\xaf\xea\xdc\xbc\x0a\x9c\x6a\x4f\x38\x7b\xab\xf7\xe3\xdc\x36\xc8\x10\xdb\x20\x9b\xeb\x66\xc8\x66\x64\x04\xc6\x61\xdf\xe9\xd3\x2c\x4c\x08\xaf\xc6\xf3\xb1\x25\x7d\x64\x84\xa7\x55\xf5\xac\x70\x1e\xb1\x3f\x87\x76\x3f\xee\x33\x0f\xfa\x04\x22\xcd\x80\xa9\x20\x38\xc6\xf4\x52\x92\xbd\xee\x5f\x89\xe9\x4c\x7a\x65\x21\x97\xfc\x19\x06\xb4\x82\x58\x37\x24\x49\xb1\x08\x1c\x6b\x97\x13\x4c\x43\xc8\x9e\xe2"}, -{{0xd3,0x36,0xfd,0x84,0x08,0x19,0x6d,0x22,0xfb,0x69,0x8e,0xb2,0x5b,0x76,0x54,0xfd,0xa4,0x6f,0x5d,0xe4,0xc9,0xb4,0xd0,0x49,0x50,0xc3,0x98,0xb5,0x9a,0x44,0x29,0x0a,},{0xf3,0xcd,0x96,0x34,0x7c,0xea,0x63,0xe5,0x00,0xa4,0xc9,0x2c,0x3b,0xf2,0x15,0x66,0x2d,0xd0,0x40,0x07,0x84,0xdb,0xf8,0xb5,0x95,0xdd,0x3d,0x39,0x5f,0x90,0xcc,0x12,},{0xaf,0x7e,0x2d,0xf7,0x52,0x9f,0xd1,0x8d,0x1b,0x21,0xb8,0xfd,0x4c,0x06,0x81,0x50,0x59,0x18,0xe2,0x51,0x14,0x34,0xfe,0x4e,0x49,0x54,0xe7,0x43,0xc1,0xcf,0xa4,0x5e,0x41,0x09,0xd3,0x6c,0x3e,0xec,0xf2,0xe2,0x5d,0x20,0x9b,0x9b,0x5d,0x25,0xf7,0xcb,0xc3,0x80,0x29,0x6d,0x64,0x77,0x52,0xe3,0x0d,0x3b,0xea,0x3b,0x92,0x9b,0x09,0x03,},"\xfb\x49\xc1\x9b\xc4\x44\x4c\x28\xeb\x26\x25\xf3\x1d\x99\x6d\x5e\x36\xc5\x7f\xa6\xfd\xd7\x72\xe6\x7b\x71\x99\xce\xc6\x7e\xda\x54\x51\x71\x2d\xf7\xa6\x9d\xbb\xd5\x6e\x7c\x39\x87\x96\xb2\x00\x1d\xef\x65\x1c\x4b\x9c\x05\xee\x31\xd9\x56\x79\x53\x5c\x81\x2a\x37\xd3\x1d\xdb\x30\x73\x19\x9c\xd7\x04\xff\x7c\xa2\x98\x1f\x7b\x9c\x92\x7a\x7f\x7d\x77\x6f\xb6\xf6\x09\xf7\x27\xe6\xea\x70\x9c\xe7\xf4\x3a\x60\x79\x35\x04\x16\x9a\x89\x05\xd9\xb2\x31\x09\xf0\xd8\x67\x96\x6a\xa3\xe3\x00\xc7\xe1\x1d\xde\xdb\x9c\xc1\x17\xb9\x04\xf6\x29\x27\xe4\x8e\x4d\x73\xfe\x1a\x6c\xec\xcc\x4c\xeb\x08\xe6\x4a\xb5\x5f\x25\xc9\x82\x16\xce\xc9\x37\x60\x8a\xd7\x93\x14\x69\x98\xf1\x4c\x29\x85\xe6\xc2\x91\x0d\xf7\xb1\x38\x8f\x9d\xd8\x63\xf1\xe4\xd7\xd1\x62\x14\x79\xb8\x51\x2c\xdb\x34\xe6\x73\xeb\x02\xa4\x89\x34\xe3\x9c\x2d\x18\xd7\x0f\x96\x6d\x67\x6a\x2b\xd7\x5d\xb5\x43\xd2\x5c\x5d\xcd\xc3\xef\x3b\x8b\xc8\x20\x18\x48\xc3\x09\x61\xe9\x15\xd9\x68\xbd\xc3\x19\x46\xb0\xd1\x8e\xde\x7c\xb0\x16\x6d\xbe\x1f\xfe\xff\x94\x39\xc9\xc3\x40\x4a\xf6\x01\x6c\x73\xed\xeb\x25\x3d\x93\xf5\x62\xa1\xa6\xcd\xd5\x78\x98\xa9\xb3\x42\x25\x87\xd5\xf5\x6a\xf3\xd0\x6b\x3f\x6c\x25\x75\x1f\x44\x46\x0f\xb3\x29\x96\x56\xdc\x11\x22\x7e\xf4\x83\x7a\xab\xdd\xee\x40\x0f\xa5\x3f\x69\xe5\xce\xd0\x53\xc7\x6d\xce\xcd\xf0\xad\xc9\xef\x80\xf4\xb3\x30\x54\x2f\xf1\xfa\x2d\xf0\xb8\xd4\x3c\xd1\xc3\x11\xb1\xb9\x95\x5c\x63\x2c\x8e\x5f\x04\x91\x93\x1c\x04\xde\x43\x4d\xf8\xf7\xa3\x94\xe5\xfe\xf0\x16\xdb\x2e\xb7\xc8\x7b\x2a\xc7\xa4\xa7\x30\x43\xbd\x7f\x98\xad\x0a\x4d\x45\x3a\xbf\xb0\xbe\x8b\xe4\xcb\x14\x57\x42\xaa\x56\xaa\x5e\xf2\xdf\xf1\x22\x30\xa5\x10\xe3\xb7\xf8\x2f\x78\x47\x70\x0e\xee\xa5\x90\x5b\x02\x89\x69\x6c\x4c\x14\x2b\xf3\x4b\xcf\x81\xa9\x62\xd7\x5b\x8d\x09\x10\x55\x73\x37\x79\x33\x5b\x7f\xd4\x7a\x20\xd1\x7c\x94\x8a\xb7\x32\x94\x78\x32\x67\x43\x71\xe2\x2e\x71\x11\x34\xf5\xc9\x19\x79\x23\x57\xf7\x9b\xf7\x0c\x44\x70\x78\x75\x28\x43\x4f\xc0\xb4\xca\x09\x3e\xe9\x25\x43\x42\x0d\x1c\xa8\x11\x24\xf5\x58\x53\x17\xe2\x50\x82\x1a\x4f\x3d\x8c\xe0\xf9\x19\xde\x9f\xbf\x01\x27\x08\x7e\x67\x69\x03\xf6\xcb\x39\x02\x5b\xcc\x73\xa0\x76\x29\x54\xb7\x2e\x66\xa6\xbe\x9b\x96\xc9\x7b\x6f\x60\x30\xbf\x5c\xa0\xbc\x27\x27\xa9\xa1\x79\xcf\x9d\x94\x05\xf3\xfe\x18\xf3\x49\x23\x89\x07\x9a\x5b\x65\xbc\xb1\x3a\x0d\x5e\xf4\x1c\x2c\xd9\x7e\x70\x2c\xee\x4a\x2f\xeb\x1e\x67\x02\xbd\x4c\x63\xfe\x0a\x4a\xe9\x94\xc4\x28\x7a\x83\x7b\xc3\xf6\x4c\x2d\x89\x88\x57\xcd\xb3\x2a\xcd\x4b\xd1\x33\x67\x6e\x51\xf7\x7b\xc7\x11\x0e\x3c\xe5\x2d\x92\x04\xfd\x26\x91\xa6\xd3\x70\x78\xf6\x8e\x7b\xce\xf3\x0f\xc9\xc4\x83\x98\x58\x22\xb6\x61\x11\x92\x38\xe4\x0f\x9c\xfd\xca\xbe\xf2\xd7\xb1\x6b\x05\x9a\xb2\x4a\xdc\x05\x00\x37\x12\xbb\xb1\x28\x09\x6e\x37\xf9\x1b\xc4\xc5\xc8\x15\x08\xbe\x27\xfa\x0b\x84\x94\x0b\xe3\x6b\xce\xd2\xe6\x5c\xd3\x6b\x39\xfb\xdc\x5e\xa6\x86\x14\x15\x92\x28\xca\x65\xc5\xd8\x40\x7b\xaf\x66\x3b\x52\x8e\x7d\x87\x73\x4c\x7b\xc7\x7d\xc8\x43\x1a\x1d\xd6\x87\x3c\xfd\xdf\xc3\xe7\x57\xd9\xad\x1f\xed\xd3\xc7\x98\xf1\xfe\x60\xe7\x15\xee\x48\xa6\xbc\xbb\x13\xb6\x16\xa8\x9a\x38\xe3\x36\x48\x9d\x3d\x6c\xcb\x72\x69\x14\x11\x2a\x1b\xc5\xd9\x77\xc9\xb2\xa3\xfa\xc1\x07\xad\x09\x4b\x03\x8a\xb7\x54\x68\x26\x3c\x34\xbd\xa8\x17\xc0\x56\xe0\x7a\x6c\x56\x69\x7c\xb6\x4a\x0b\x1f\x96\x6f\x6d\xe0\xbb\x1c\x0a\x71\xc8\xa5\xfe\x13\x3b\xa2\x03\x6d\x24\xda\xcc\xad\x3f\xa0\x3b\x39\xcd\x27\xf8\x32\x75\x27\x51\x05\x5a\x81\x55\x91\x3d\x04\x0f\x51\xda\xe7\x8d\x71\x94\x6c\xa0\x4d\x83\xc7\xc8\x94\xc2\x80\xaa\xec\x28\x55\x43\xe5\xfd\x5e\x32\x7a\xcc\xca\x9a\xbe\xf1\x56\xa1\x3b\x95\x71\x44\x6b\xd8\x00\x7f\xf9\x2d\xbc\x0f\xba\xf2\x3a\x94\x41\xb5\x3c\x1c\xd7\x40\xc3\x4c\x28\x29\x29\x10\x1a\xd2\xea\x8b\x85\xd7\x00\x52\x99\x1b\x77\x4e\x92\xff\x75\xcc\x85\x11\x3e\x09\x00\xb5\x1b\x86\x3e\x1f\x2a\xda\xab\x2d\xbc\xf4\x6a\xf4\x79\xea\x24\x8e\xc2\x88\x9a\xfb\xfe\x73\x74\x08\x39\x3a\x2b\x1b\x33\x01\xf6\x5c\x1f\xac\x8b\x67\x67\x95\xab\x5b\xf4\x47\xf0\x5e\x0d\xaf\x67\x76"}, -{{0x65,0x73,0x22,0x78,0x41,0xf6,0xf9,0x28,0x31,0x14,0x6c,0x44,0xc0,0xe4,0x80,0xcd,0xf5,0x44,0xbb,0x87,0x65,0x52,0xcc,0x5f,0x9d,0x42,0xf1,0x5b,0xdc,0xc0,0x44,0xb8,},{0x19,0x22,0x57,0xa5,0x4c,0xe5,0xd0,0x4c,0x19,0x43,0x9f,0xdc,0x9e,0xde,0x18,0xec,0x85,0x6e,0x29,0x87,0x0e,0x24,0xd3,0x73,0x1f,0xe2,0x22,0x47,0x99,0x94,0x9b,0x7e,},{0x53,0x8e,0xac,0xe4,0x93,0xde,0x53,0x38,0x4b,0x1e,0x98,0x5b,0xb9,0x07,0xc0,0x94,0xf8,0x16,0x84,0x30,0xda,0xb1,0x4d,0x37,0x79,0x1b,0xe6,0xe7,0x8f,0xf3,0xf5,0xa3,0x06,0xec,0x70,0xdc,0xac,0x86,0xd9,0x93,0xa4,0xc1,0xf7,0x58,0x50,0x78,0x6d,0x79,0x5f,0x02,0x2b,0x79,0xbe,0x6a,0x54,0x77,0x69,0xe4,0x15,0x69,0xc5,0xa9,0xa3,0x0a,},"\x6e\x7c\x6b\x12\x2a\xb3\x6b\xd1\x35\xf6\x9e\x2b\x85\xe7\xfc\xce\xfb\x07\x2c\x12\xcf\x08\x8a\x32\x29\xd8\x76\xef\xf5\x32\x38\x9f\x05\x77\x11\x6f\x7a\xf2\x9f\x11\x95\xe3\x82\x88\x39\x38\x13\x80\x46\x71\x78\xb2\x29\xc5\xa1\x8d\x7c\x49\x43\xec\x97\x0d\xd1\x8b\xce\x72\x3b\xd0\xca\x91\xff\xa9\x55\x63\x54\x6a\x32\x4f\xe0\xb9\xbf\x6c\x04\x55\xd4\x27\x60\x39\xe8\xd2\x91\xfc\x72\x76\xaa\x55\xa1\xcd\x3e\xa0\x52\x82\x65\x4a\x7f\x97\x00\xad\xcb\xc7\x80\x77\xc5\xdd\x0f\xc8\x6e\xce\xd4\x8f\x4a\x60\xcc\xb7\x6b\xfb\x8b\x45\x62\xba\xc2\x2a\x02\xd1\x9e\x44\x89\x39\x4a\xb9\x71\x9f\xc1\x44\xf5\xdb\x2e\xf0\x39\xb3\x7f\x3b\x51\xd1\xd6\x57\xa0\xcf\x83\x5d\x71\xf1\xa4\xaf\x01\xeb\x9f\xd8\x85\xc6\x04\xa6\x24\xcb\xe9\x10\xbf\xde\x09\x3a\xd3\xf0\xcb\xfd\x9a\x48\x30\x73\x29\xd4\x42\x34\xbd\x01\x19\x1d\x56\xe5\x22\xd7\x2b\x54\xe1\xfe\x47\x33\xda\x3a\xec\x68\x27\xea\xb3\x55\x48\x98\xe0\x3e\x57\x7b\x4e\x7b\x9d\xd3\xf3\x08\xe6\x16\x80\x8d\x02\x94\x49\x9f\x28\x86\x29\x5e\x54\xc3\x60\x19\x9c\xa8\x3a\x83\xff\x46\x19\x5e\xa3\xc4\x84\xa6\x68\x38\xd5\x1a\xcb\xe9\x61\x1e\xee\x03\x6a\xe2\x81\xc6\x79\x3c\xbd\x45\x1f\x92\x71\xfb\x5d\x25\xea\x7c\x18\x99\xab\x5d\x43\xed\x8b\x9d\x06\x7b\xc5\x6d\x8d\x4a\x15\xf1\xda\xb8\xd8\xd9\x5d\x1b\x17\xaf\x64\xcb\x18\xc1\x14\x75\x51\x14\x7a\xdd\xcb\xdd\x53\xfb\xcc\xd9\x02\x6f\x85\x55\x47\x13\x1b\xee\x95\x07\x16\x39\xf6\x49\xf2\xd0\x35\xa2\x5a\x3e\x42\xe3\x8e\x22\xbb\xf0\x38\x10\x6c\xe8\xbc\x4a\xd6\x76\x8a\xb9\x2c\xd5\x7a\xfa\xcd\x04\xee\x55\xcf\x07\x14\xb7\x68\x95\x2d\xac\x24\x0b\x1e\x9b\x28\x35\xec\xf7\xb0\xd6\xc4\x07\xc8\x25\x24\xa9\x23\xb9\xf5\x4d\x1b\x8f\x12\x56\x4a\x87\x21\x44\xef\xad\x3f\x3a\x7d\x23\x97\xcd\x12\x17\xdc\x5a\x9c\x96\xe4\x3b\x29\x60\xa8\x42\x5e\x97\xe0\x7a\x02\xb0\xda\xc9\x0f\x34\x6b\x91\xa3\x46\xa2\x3e\xd2\xbb\x7f\xe6\x91\x9c\x22\xdf\xf0\x3f\x62\xda\x7d\xba\x17\x6e\x8d\xdb\x22\xf3\xf3\xa6\x68\x89\x1d\x3f\x4e\x69\x54\x8d\x0a\xc4\xe7\x1e\x6d\x28\xed\x5a\x67\xab\x5a\xc6\x11\xd4\x60\xb6\x7a\x20\x1f\x4f\x56\xa5\x00\x3c\xa7\xa7\xd1\xcd\x1d\xb6\xc1\x00\x75\xb0\x92\x27\xcb\x8c\x5d\xc1\x66\x6f\x8b\xe7\x10\xb4\xb7\xbc\x2b\x95\xae\x60\xda\x4f\x64\x17\x9a\x50\xd2\xf8\x87\x44\x36\x15\x91\x67\x1d\x36\xb7\x29\x63\x15\xf6\x99\x64\x39\xad\x79\x82\x1d\xa8\xe7\x72\xdf\xbf\x55\xa9\x0d\x5d\x52\xef\x7d\x76\xb3\x5f\xfe\xbd\x42\xe3\x52\x5f\x45\x30\xc5\x4a\x0f\x23\xb4\xd0\x7c\x5f\x59\x74\x47\x0e\x89\x40\x4d\x17\x6e\xef\xf9\xef\x23\x33\x61\x96\x91\xc5\x9b\x7a\xad\xd4\x2c\x29\x6b\x1d\x0d\x32\x8d\x9a\x3b\xd5\x9a\x54\xbb\xa9\x3a\x0c\x1f\x1d\x62\x41\x8c\x21\x90\xc3\x81\x74\xb6\xab\xea\x02\xdb\x66\xe8\x18\x32\x0e\xc4\xb8\xba\xc1\xc1\x2f\x18\xf3\x0d\xad\xe2\x7e\x63\xc5\x8f\x9e\x7c\xaf\x4b\xf6\x9b\x26\x5a\x2f\x9d\x91\x80\x08\x61\xac\xf4\x79\xe6\x5e\xc1\x7e\x68\x05\x77\xe0\x58\xcb\x16\xc1\x09\xbc\xf9\xb2\x90\x9f\xce\x33\x61\xa2\xc2\x68\x5c\x10\xbe\x85\x40\xa1\x22\x2d\xb5\xec\xf0\xcc\x4d\x53\xa4\x21\x4b\x7b\xf6\x24\x8a\xdc\x3a\x86\x1e\x34\x84\x1a\x37\x79\xc4\x60\x46\xc5\x36\x4f\x1e\xa9\x1a\x78\xc9\x70\x0d\x46\x2e\xcf\xaa\xe3\x6b\xa7\x60\xc1\xbd\x6a\x23\x7c\x96\x1e\xdf\x40\x22\xce\xde\xfe\x5e\x93\x7b\xbe\xd7\x05\x1a\xe6\x1b\x96\xd0\x8b\x04\x87\xce\x05\x68\xff\x0d\x32\x74\x0b\xbd\x49\xad\x0d\xb8\x6e\x09\x10\x2a\xb2\x1a\x91\x56\x16\xe9\xdf\xdd\xc8\x1e\xbf\xb3\x6c\x90\x3e\x07\xa4\x0c\xd2\xdd\x11\x9f\xf4\xa5\x0b\x93\xfc\x6f\xdf\xc0\xf3\x6e\x59\xe0\x14\x8f\xcf\xf3\xfe\x8e\x2c\xd6\xd3\x0a\x9e\x4b\x8f\x01\x55\x67\xd1\x18\xb6\x27\x4e\x1e\xd7\x5b\x22\xe4\x4c\xa9\xd9\xdb\xfc\x16\x07\x42\xcf\xac\x58\x1e\x1a\x0b\xf5\xff\x33\x26\xbc\x5f\x78\x96\xb9\xca\x05\xa8\x11\xd5\x5e\x97\xc8\x34\xd3\x7a\x64\x95\xcc\x26\xcf\x44\x2b\xd2\xd9\x01\x29\x89\x5e\x9c\xc0\xed\x01\xe2\x15\x52\x93\xf4\x7a\x07\xab\x58\x80\xc6\xca\x29\xed\x44\xd9\xcc\xbc\xaa\xda\x7f\x3e\xb6\x04\x02\x18\x14\x88\x65\x4e\x04\x91\x15\x78\xb1\xaa\x9c\xdd\x4b\x86\xb0\xdd\x24\x50\xdf\x3a\x43\x08\x1e\x41\x10\xab\x58\xde\x76\x39\x24\xd3\xc8\x91\x52\xe9\x92\x93\xe6\x38\xf9\xac\xd8\xd7"}, -{{0xa6,0x3c,0x1f,0x54,0xb2,0xca,0x05,0x8f,0xed,0x2e,0xe2,0x50,0x4b,0x98,0x3f,0xf3,0x3d,0x57,0x0a,0x9b,0xab,0xa5,0x83,0xc0,0x86,0xce,0xfe,0x19,0xf4,0x3e,0xc4,0x9d,},{0x32,0x9b,0x86,0x6b,0xca,0x41,0x94,0x29,0x7f,0xc1,0xad,0x5a,0x0e,0xba,0x0d,0xf9,0x56,0x69,0x9c,0x74,0xab,0x7d,0xa5,0xfa,0x54,0x62,0xbd,0x06,0x61,0x47,0x10,0x20,},{0x28,0x33,0x59,0xbe,0x41,0x29,0x0a,0x51,0xe6,0xa7,0xc5,0xd5,0x72,0x5c,0xa4,0xea,0x0a,0x68,0xf1,0x4a,0xca,0x14,0xb0,0xf0,0x25,0x66,0xde,0xe2,0x1f,0x49,0x0d,0xa3,0xc7,0xe9,0x5f,0x7a,0xb7,0x39,0xbc,0x35,0xa7,0xf4,0xf2,0x32,0xe9,0x71,0xaa,0x15,0x76,0x57,0xa6,0x33,0xeb,0xa0,0xe7,0x2d,0xc9,0x7a,0xf3,0x2c,0xdb,0x92,0x87,0x02,},"\x79\x1b\x86\xfd\x58\x77\x13\x47\x8f\x92\x34\xff\x30\xce\xfc\x12\x3c\xd7\xc3\xeb\x12\x5f\xa7\x4e\x4c\x6d\xb6\x4e\x78\x44\xf7\xc8\x5b\x16\x86\xe7\x1e\xd0\x8d\x1a\x6a\x04\xe0\xeb\xbd\xff\x4a\xb1\x60\xc9\x76\xc8\xab\x9b\x50\x5f\x6a\x7e\xb0\xa1\x84\x27\xe9\x99\xa8\x82\x8d\xf1\x06\x84\xf8\xc7\x5b\x6a\x6b\x0a\x64\xc0\xaf\xa4\xbb\x22\xbe\xd1\xcb\x93\x25\x35\x9c\xac\x3b\x8c\x50\x8d\x98\xbc\xb0\xeb\xcd\x74\x8d\xc1\x32\xf1\xd6\xa3\x60\xa4\x45\x0d\x12\x92\xa1\xfe\xfc\x4e\x57\xe4\x10\x7a\x22\x3f\x42\x1e\x7d\x14\xa3\x84\xb8\x5c\x18\x84\x4d\x0b\x9e\xed\x2e\xcb\x81\xbb\x74\xe8\xa1\x26\x52\xd9\x85\x05\x79\x5a\x01\x31\x16\xa7\x07\x6c\xcb\x54\x93\xd6\xa7\x11\xf7\x63\x7e\x97\xa7\x80\xe7\x4d\xa1\xb3\x9b\x15\xcc\x7b\xbd\xe2\xe6\xc4\xd0\xd3\xe8\x30\x05\x97\xc8\x36\xe8\x0b\xcb\x8d\x80\x81\xd9\x74\xe0\x24\x32\xea\xc8\x83\x68\x21\x1d\x3a\xaa\xe8\x9a\x14\x41\x71\x08\xe1\xff\x67\x37\x08\x38\x49\xc6\x25\xb4\x0d\x63\x1f\x6c\x83\x57\x22\x0c\x7f\x37\x38\x0b\x3b\x2c\xc5\xd0\xe2\xdf\x6b\x4d\x11\x96\x57\x9d\xbc\x57\xb6\xc9\xea\x0d\x41\xf4\xfa\x0e\x55\x6f\x94\x3c\x94\x48\xef\x42\xfc\x78\xdf\x59\x96\x64\x8c\xe2\xf3\xde\x04\xd8\xa6\x63\xf9\x67\xf3\xd9\x33\xd4\xf6\x53\x57\xab\x29\xba\x5b\x64\x05\xfb\x16\x29\x72\x57\x8d\xdb\xb2\x36\x7b\xed\x14\x3c\x85\x4c\x10\x88\xde\x92\x1d\x79\xf5\xa9\x2a\x85\x48\x37\xeb\x77\x02\xe1\xba\x92\x5c\x6e\xac\x23\xd1\x34\xba\x1b\xaf\xc5\xd4\x6d\xe2\xa1\x94\x2c\x7f\x36\x6f\x70\x1b\x0a\xfa\xbb\x75\xcb\x1d\x80\x8e\x1a\x1e\x4e\x3a\xe5\xde\x88\xe8\xe9\x98\x97\x57\x45\x8b\xdd\xd8\xa8\x06\xc1\x10\xcc\x3a\x73\x3d\x1d\x4a\xc5\x8a\x40\x5c\x4d\x81\x13\x4f\xbc\x24\xcc\xde\x7d\x5a\xfe\x42\x0f\x9f\x17\x85\xf0\xa5\x02\x0f\xaf\xbb\x22\x61\x22\x25\x08\xaa\x05\x28\xb7\xb4\x8b\x56\x72\x00\x95\x84\x25\xef\xcb\x42\x93\x4a\x88\x0b\x13\x34\x44\xbb\x10\x9f\x2a\x95\x4c\xfa\x35\xa2\xd1\x7c\xb0\x5e\xe3\xf1\x6d\x06\xb3\x21\xa1\x5f\x91\x33\x9a\xbe\xda\x24\x3a\xd6\xc0\x91\x9f\xac\x51\xe9\x07\xe0\x53\xfd\xee\xd1\xcf\x03\x00\x37\x34\x13\x77\x93\x94\x1b\x8a\xdf\x9a\xb6\xaf\x81\x9c\x24\x5d\x6d\x56\xf1\x69\x64\xc8\xa7\x5b\x07\x56\xa8\xcb\x0c\xa8\xc1\x2a\xc6\xe6\xb3\x94\x2e\xeb\xec\x2f\x86\x88\x35\xf8\x1b\x10\x9d\xb4\x98\xa4\xca\x2e\x02\x1f\xa7\x65\x60\x8d\x23\xd8\x03\xde\xdc\x9e\x51\x45\x3f\xc1\xd2\xa6\xa3\x8a\x4a\xab\x25\x7c\x0f\xe7\xd6\x7d\x32\xa5\x41\xe0\x14\xb6\x0e\x10\x13\xa9\x2c\x1b\x3a\xd9\xe6\xf1\x1b\xe2\x93\xb2\x46\xf9\xa0\xc6\x44\x0b\x0b\x54\xfe\xe7\x5f\xed\x2f\xb7\x5c\xc9\x1e\xcb\x32\x73\x8c\x49\x58\x31\x58\x6a\x11\x24\x2d\x87\xdc\xb4\x88\x3e\xdf\x67\x57\xa5\x0b\x18\x84\x37\x59\xb9\x8d\xd0\xce\xf4\xa3\xfe\x10\xd7\x63\x70\xec\xda\x8c\x83\xfa\xb8\x7e\xee\x26\x56\xc5\xf2\x61\xc3\x40\xea\x91\xa5\x60\xd0\xe2\xc6\x42\x89\x26\x7f\x00\x36\xba\x35\x94\x48\x00\xa5\xa0\xae\xf3\xf1\xdf\x83\x9a\x72\x4e\x18\x1d\x79\xb8\xa3\xc1\x6f\x65\xae\x27\x95\x3c\x4a\xae\x8c\xcd\x30\xff\x5a\xcc\x4b\x31\xe4\x76\x5c\x68\xfb\x38\x31\x9f\x10\xac\xf8\x92\x47\xb5\xa3\x9b\x3b\x08\xa1\x91\x75\x4a\x24\xac\xa9\x59\x6a\x1f\x8a\x70\xb6\xe4\xf0\x3a\x20\x04\xa9\x08\x6f\xf6\xed\x07\x65\x2a\x92\x6e\x1e\x2d\xf7\xbd\xcc\xd5\xbe\xc1\x6e\x5c\x4e\x96\x83\x64\xa0\x9a\xbf\x9d\xed\x93\xdf\x5f\xca\x0b\xcc\xa5\xc8\x12\x97\x6e\x5c\xfb\x3c\x34\x93\xfc\x17\x5d\x1d\x92\xee\x8d\x1c\x98\xfb\x33\x82\xb3\xab\x90\xc5\xc0\xe4\xbd\xf6\xa3\xac\x94\x76\x7b\x68\xd4\x7e\x6b\x9c\x24\x42\x65\xe3\xb1\xab\x06\x23\xa8\xf0\x10\x02\x73\xf2\xc6\x07\xde\x89\x61\x2c\x72\xd3\x9b\xe4\xc0\xb4\xd7\x7a\x3c\x61\x36\x8d\xf4\x0b\x36\x08\x65\x29\x89\xd1\xe1\x9c\x0a\xaf\x0e\x3c\x25\x3e\x56\x2c\x64\x09\xfe\x64\x48\x92\x9b\x33\x75\x3d\xe1\x62\xe6\xde\x5b\xd4\x66\xa5\x11\x4f\xc0\xe5\xf5\x71\x02\x75\x5e\x29\x54\x4f\x03\xb2\x8d\x4f\x78\xde\x9a\x02\x4d\xd4\xc4\xe8\xc3\xc2\xd4\x41\x15\xa7\xae\x15\xed\xb4\xf5\x58\xaa\x7d\xba\x64\x26\xe7\xe3\x72\xc5\x4f\x79\x40\xbd\x77\x14\x46\x7f\x8c\x3a\x1a\xdd\x3c\x64\x01\x89\xc3\x16\x60\xd8\xcc\x01\xd3\xc5\x38\x2e\x42\xab\xc1\x04\xc7\x23\xf9\x48\xa8\x04\xca\x85\x30\x47\xb6\xb8\x7b\x5b\x6e\xf4"}, -{{0x5b,0x67,0xa6,0xd7,0xc6,0x50,0xdd,0x92,0xdd,0xd0,0x36,0xce,0x7a,0x30,0x5b,0xc9,0x59,0xa4,0x97,0xc5,0xe5,0x15,0xa6,0x84,0x93,0x03,0x5c,0xb3,0x85,0x0e,0xe0,0x3d,},{0x4c,0x6f,0xc1,0x64,0x05,0x05,0xfb,0x46,0x66,0x9f,0x93,0x04,0x8f,0x8e,0xf5,0x57,0x09,0x9f,0x3f,0xd9,0x2a,0x53,0x06,0x4b,0x16,0x33,0x63,0xa3,0x1b,0x7f,0x00,0xaa,},{0x0f,0x07,0x3c,0x9a,0x58,0x6f,0x6f,0x5e,0x08,0x38,0x9a,0x2a,0x5e,0x18,0x08,0xe2,0x70,0xf0,0xed,0xb6,0xaf,0x10,0x44,0x96,0xf9,0x37,0x57,0x62,0x3f,0xea,0x53,0x13,0x3a,0x73,0x1c,0x44,0x5a,0xc2,0x35,0x78,0xcd,0x56,0xa3,0x88,0x3c,0x08,0x95,0x86,0x68,0x63,0x1f,0xed,0xf1,0x44,0x6c,0xe3,0x4f,0x85,0x7f,0x90,0x82,0x2b,0xa8,0x0a,},"\x62\xcc\xde\x31\x77\x2c\x57\xe4\x85\x3a\xaf\x2a\x81\x81\xfd\xb5\x3f\xb8\x27\x90\xea\x65\x01\xbf\xc8\xf5\xd4\xae\x8d\xbd\x52\xde\x42\xce\x2e\x89\x61\xac\x17\x31\xf4\xbc\x08\x5f\xb5\x61\xef\x09\xa2\x44\x29\x70\xb6\x29\x79\x01\xae\xaa\x2e\xe5\x55\xb7\xd5\xe3\x95\x1c\x7c\x35\x12\x39\xdd\xee\x95\xff\x54\xf9\x24\xda\x95\xca\xe7\xb1\x5b\xa6\xa9\xa1\x33\x7b\x8c\xe4\x92\x1e\xd9\x13\xcd\x79\x1c\x1c\x69\x41\x08\x0e\x54\x8f\x3c\x36\xe8\x45\xac\xbf\xd8\xd8\xce\x35\xe2\xfd\xc2\xa2\xad\x6c\x7e\x24\x61\xbf\xcb\xf1\xaa\xbc\x55\xcf\x0f\xae\x42\x88\x85\xbe\x5e\x86\x53\x33\x08\xc9\x75\x68\x05\x21\x9a\xbd\x7f\xfc\x16\x57\xb6\xf4\x63\x29\x20\xa0\xc1\x0e\x0e\x36\x33\x19\xd9\x00\xfc\xd6\x1e\x7d\xdb\xcd\x6e\x76\x2a\x7d\xb9\x24\x80\xc3\x63\xb2\xc0\x64\x0c\x6b\xf3\x2d\x69\x0d\xd8\x29\xd8\x40\x5f\xa6\x6e\x47\x83\xeb\xe1\xcb\xde\x95\x47\x95\x4a\x90\xba\xad\x9f\x77\x4e\x94\x54\x9a\xbb\xff\x2c\x1f\x5c\xae\xc2\xbf\xd2\x8e\x41\x5d\x36\x42\x9d\x58\x51\x8c\x3e\x17\xe8\x69\x9e\x19\x89\xd4\x7b\x8d\x62\x7e\xf9\xab\x4d\x1e\x7d\x12\x0b\x37\x2c\x21\x41\x30\x4f\x7f\xab\xd0\x26\x5b\x8b\xe4\x1f\x54\x67\xf4\xde\x9e\x65\xc1\x25\xee\x1f\x27\xa2\x89\xc4\xf7\xc9\xa1\xfb\xf2\x5b\xfc\x2f\x8d\x30\x8e\x7f\xf5\x21\x91\xcb\x76\x44\xc6\xaf\x20\x45\x22\xf2\xac\x87\xb5\xf4\x05\x25\xfd\x43\xd3\x08\xc8\xdb\xc6\xa8\x61\xd2\x5d\xb2\x3e\xe2\x76\x67\x8a\x1b\x6e\x8e\x91\x28\x3b\xe0\x24\x70\x48\x2e\xd6\xcc\x9f\x6e\x39\x63\x51\xd1\x1b\x1c\x7e\x22\x32\x9c\x09\x1f\xe7\xd3\x68\xf6\x06\x53\xf9\x3b\x0f\x6a\x3f\x71\x2c\x20\xf9\xd2\xd8\xa9\xa0\x81\x98\x72\xf0\xc7\x1d\x7b\x1c\x0b\xc1\x68\x3a\x15\x2b\x48\x4b\xc2\x1c\xf5\x56\x09\x3a\xb4\xc0\xac\x16\xd3\x22\xff\x0b\xf4\x52\xe5\x58\x1e\x1e\x72\x41\x67\x38\x84\x02\x3c\x7d\x6e\x17\xe2\xde\x80\x59\xf6\x0e\x4c\x18\xe1\x3b\xd5\x5f\xcf\xee\x62\x3f\xd0\x46\x9c\x0d\x09\x11\x61\x1d\x09\x9a\x25\x70\x20\xf2\xf3\x1b\xf5\x07\x8e\x6e\x65\xa1\x35\xd5\xbf\x40\x76\x20\x23\x6d\x6c\xc7\x59\x31\x0f\xa7\x28\xff\x8b\xb5\xec\x56\xab\xbe\x1a\x3c\xd1\x51\x53\xf8\x92\xd9\x58\xd3\x0d\x16\x2d\x01\xee\x66\x5f\x5b\x56\x27\x81\xd8\xdc\xf8\x42\x80\x59\xe5\xfd\x22\x5a\xd7\x8a\x99\xea\x76\x0f\xe5\xd9\xee\x82\x19\xc9\x5a\xcb\x18\xd0\x56\x22\xe1\x0a\x9b\x6c\x67\xf6\xd4\xf6\xed\x11\x63\x5c\x5e\x2e\x0f\x85\xdd\x5d\x3c\xbd\xa6\x5a\xa4\x23\xd5\x94\xa8\x0b\x40\x42\x7b\xc3\x21\xe0\xee\xf9\xaf\xd2\xbc\x87\x46\xab\x73\x99\xff\x6d\x0e\x12\x87\xb6\x61\xdd\xc4\x06\x2d\x07\x20\x18\xf4\xc1\x0e\x86\xcf\xae\xd7\x2d\x9e\x68\x6e\xd0\x9d\x52\x55\xd3\x60\xe3\xee\xa2\xc2\x9b\x9e\xae\xa0\x5f\xc7\x8c\x8c\xdb\x8c\x9d\x4a\xfc\x7a\xdc\x6d\x4a\xa0\x67\xb7\xab\xfb\x0a\x4e\x94\x0a\x77\x58\x0e\xc2\x06\x45\x6c\xb9\xe9\xf9\x5f\x6d\x56\x5d\x53\x6e\x53\x5a\x16\x7e\xde\x8e\x20\xec\x36\x08\x1e\x2f\xc5\x5a\xef\xaf\x24\xd2\x27\xff\xfe\x5e\x6c\xb0\x30\x93\xf4\x43\xb4\xc5\x16\x55\xd9\x1c\xa6\xf2\x75\x95\x9d\x1a\x80\x2a\xde\xab\x44\x70\x1b\x31\xe8\xb0\xfd\x02\x22\xc4\x99\x96\x6c\x72\xd1\x02\x0a\xd9\x37\x0e\x28\x02\xbe\x04\xc9\x93\x3f\x6b\x77\x4f\x6e\x8c\x69\xfc\x0b\xfd\x31\x59\x39\xa1\x27\xb4\xe0\x6d\x0f\x6f\x5e\xde\x67\x1c\xe1\x16\x12\x12\x6b\x51\x87\xb5\x33\x29\xb0\xa9\xcb\x7d\xa3\xb1\xcc\xd6\x7b\x8c\x07\xba\xb9\x9a\x66\x2d\xf8\xce\x85\x1f\x50\x2f\xc4\xe1\xed\x16\x32\xb6\xba\x55\x55\x44\x01\x8f\x75\x27\xe3\x62\xef\xc7\xe3\xb2\xba\x6f\x75\xa1\x25\x4f\x42\x8b\x3b\x7e\x0b\xea\x69\x54\x9e\x7f\x9c\x73\x62\x75\x55\x00\x80\xae\xe3\xaf\x59\x14\xe3\xa3\x4b\xe6\x56\xc7\x7f\x6b\x29\x42\x0e\x54\x33\xf3\xdf\xf3\x81\x1f\x35\x28\x20\x8e\x9d\x85\x0a\xa3\xc2\x9b\x0f\x77\x8a\x24\x27\xd5\xfd\xe3\x07\x32\xdf\xe5\x04\x43\xa9\xc1\xad\x55\xc7\x2a\x08\xab\x26\xff\xaf\x8e\xfb\x90\xbc\xaf\xd3\x72\x6b\x00\xc0\x05\xc8\xc0\xf0\xdb\xf2\xa1\x35\x30\x86\x72\x1e\x44\x65\x45\xb8\x13\x44\x11\x94\xa7\x55\xfd\x26\xb9\x63\xaf\xd9\x77\x27\x8d\x1b\x10\xf0\x90\x01\xc7\xed\x97\x54\x03\xc1\x5c\xbe\x7f\x99\x2a\xb0\x7b\x84\x70\xc9\x39\xf8\x66\xf4\x20\xf7\x7d\xb7\x79\xaf\x83\x97\x00\x32\x9e\x07\x77\xa6\x11\x63\x65\xd7\x6c\x36\xd0\x9d\x86\x04\x72\xa5"}, -{{0x26,0x31,0xc8,0xc3,0x4d,0x29,0x48,0xdd,0xd5,0x99,0x6b,0x41,0x49,0xce,0xfd,0x23,0x8e,0xa7,0x45,0x2e,0xc2,0x2e,0x24,0x61,0x24,0xdf,0xa2,0x79,0xcc,0xc2,0x7d,0xb8,},{0xc3,0x90,0x67,0x86,0xff,0xb8,0xa7,0xc2,0x7c,0x44,0xc2,0x44,0x7f,0x9d,0xde,0x7d,0x66,0x6d,0xfe,0x58,0x8c,0xfc,0x54,0xf2,0xd2,0x50,0x40,0x51,0x2a,0x37,0x1b,0xc1,},{0x0a,0xdc,0x6f,0xa4,0x0f,0xfb,0x81,0xf6,0xef,0x4e,0x41,0x87,0x55,0x49,0x17,0x77,0x5c,0xf4,0x65,0xe7,0xb5,0xe8,0x57,0xf2,0xe1,0xe7,0xf4,0x00,0x97,0x71,0x06,0xd2,0x37,0x7e,0xbc,0x76,0xab,0xb1,0xdb,0x92,0x4c,0x64,0x86,0x7e,0x3c,0x6f,0xe3,0x8c,0x0b,0x4f,0xcb,0x1d,0x0f,0x94,0x68,0xe8,0xfb,0x23,0x50,0x29,0xa8,0x1c,0xe6,0x04,},"\x6f\x9b\xdc\xe1\x44\x3f\x28\x56\xd4\xa2\xf2\x27\x82\x83\x50\x12\xb7\x81\x8a\x0e\x02\x0d\xbc\xc2\x2a\x82\x16\x58\x30\x5f\x13\x42\x34\xd1\x4c\xea\x63\x61\x00\xed\x89\x6c\x2a\x8f\xb0\xe8\x70\x48\xec\x6f\x8b\x31\x48\x4f\x78\xeb\x17\x10\x45\xad\xd7\x2c\x85\x71\x0e\xc9\xf9\xb5\xd4\x36\x23\x41\x7b\x56\x53\xbe\x86\xe7\xfb\xf8\xb4\xff\x91\x11\x0a\x80\x8c\xb4\x1a\xcf\x66\xd4\x36\xe8\x9a\x73\x7f\xae\xa4\xef\xf3\x54\x49\x60\xf1\x14\xb8\x33\xb0\xb4\xeb\xc2\xc1\x40\x70\xb0\xbf\xb7\xb0\x05\x7e\xeb\xb8\x42\xbd\x1c\x1e\xd4\x58\xad\x34\x28\xf8\xf7\x2a\x1d\x1d\xb3\xc4\xcb\x47\x97\xa3\x99\xd4\x7a\x1e\x6d\xb7\x4d\xcb\x2e\xe2\x4a\xe8\x15\x85\xcf\x66\xef\x6d\x9b\xd2\x23\xf0\xf5\x4b\xc8\xc1\xce\xc1\xbb\x44\x60\xbe\xf4\xff\xd3\x2e\xe8\x05\xc3\xca\x5e\xe9\x76\xff\x9c\x14\x55\x9f\x8d\x75\x66\x62\xa2\xbc\x19\xe4\xc5\x98\x54\x06\xa0\x73\x05\xc9\x95\x0d\x86\x6c\x9a\x79\xa3\xe5\xf6\xc5\x96\x97\x53\xa1\x70\xe0\xfc\x4c\xc0\x9c\x6d\x87\xa1\x2b\x44\xcd\xf3\xbe\x16\x23\x15\x9e\x90\xca\xb7\xa8\xa3\xe6\xf0\x1f\x26\x85\x95\xb0\x21\xb1\xef\x7d\x00\x76\x94\x77\x27\x0d\x55\x84\xc9\x12\xe2\x2a\x36\x74\x38\x27\x7f\x59\xdf\x20\xc5\x62\x0d\xd5\xbe\xaa\x9b\xb6\x0b\xee\x47\xf4\xaf\x52\x7d\x89\x29\x57\xb2\xd1\x2b\x67\x8b\x52\x79\xa3\xf8\x32\x64\x65\x4c\x0a\x0f\x8d\x21\xe7\x09\x66\x8f\x30\xfb\x6e\x68\xf0\x47\xd0\xd9\xa7\xc2\xae\x9a\x28\xf7\xcb\x9d\xbf\x18\xf6\x3f\xc1\x66\x1f\x07\xd3\x10\xe5\x40\xc7\x76\x31\xf5\xbd\xac\x58\x24\x68\x5d\x7c\x9a\xba\x0f\xe1\xd0\x94\x07\xa9\x66\x2e\xf1\x8e\xb3\xe2\x8f\xd1\xe8\xbc\x89\x26\x57\xbc\x38\x24\x3a\x2e\x64\x53\xbd\xae\xab\xb2\x79\x1f\xc5\x48\x95\x21\x29\x54\x57\xad\x04\x18\x0c\xa8\x71\xf6\x31\x87\x92\xbd\x15\xfd\x18\x00\xce\x59\xdd\x3e\xcc\x7e\x0b\x72\x97\x92\x67\xd8\x18\x3e\x80\x4f\xdd\x45\xda\xad\x84\xfc\x4c\xaf\xeb\x56\x1e\xa8\xd6\xa7\x4a\x7c\xde\x72\x2d\x96\x25\x3a\xb3\xe7\x5f\x0a\xdd\xe0\x2a\x61\xfd\x5e\x1f\x59\xcb\x1f\x5f\x1b\x2e\x05\x26\x43\x58\x9a\x9e\x4b\xe4\xdd\x6e\xe6\x45\x38\xcb\x0b\x10\x9a\x11\x3f\x30\xa5\x8b\x35\x65\x62\x40\x43\x66\x2a\xbe\x17\xf6\x0e\x31\xe8\x9c\x36\xc9\x95\xe0\x0a\xe0\x7f\x56\xa9\x11\x8a\x31\xae\xc2\x4a\xd5\x44\xbc\x96\x58\x11\x21\x8d\xf8\x27\xc1\x73\x0b\xb9\x04\xbb\x79\xb6\x86\x13\xf6\xc9\x94\x67\x9b\x69\x90\xd7\x75\xb5\xcb\x32\xdb\x97\x19\x4b\xd8\x10\x19\xbe\xa4\x1f\x3a\x7e\xef\x50\x1b\xf8\x49\x1b\x0e\xa8\x59\x38\x84\x52\xe3\xec\xbe\x16\xaa\x7d\x56\x91\x51\x0a\x66\x06\xc4\x93\xe4\xc2\x93\x96\x1b\xf4\x0b\x4c\xd3\x00\xd9\xd2\x2e\xa1\xa7\x72\x4c\x07\x8b\x8b\xab\x1f\xd1\x65\x04\xe9\x89\xb1\x36\xd9\x25\x1a\xc9\xf1\xed\x94\xa5\xe9\xac\xbd\x9c\x04\xf8\x05\x8a\xfe\x03\x04\x9a\xed\x8b\xa2\x9f\xa2\xe8\xfb\x44\xf8\xe8\xc0\x4e\x87\x27\xf3\x99\xe7\x35\xe6\xc1\x49\x6a\x91\xa9\xb2\xcd\x2a\xb0\x2d\x43\xb2\x85\xe9\xd7\x61\x02\x93\xb6\x74\x9d\xf1\x04\x4b\x30\xe2\xda\x99\xa5\x64\x42\x9a\x23\xe6\x8c\x96\xfc\xe9\x2b\x08\xa0\x0b\x7b\x74\x2b\xa9\x7a\x62\xee\x58\x77\x6d\x7d\xd5\x65\xa4\x90\x07\x1d\x4b\x19\xdc\x64\x8e\x03\x32\x9c\xc5\xc8\x25\xd3\x87\xeb\xa4\x9e\x2e\xff\x6c\x43\x41\x86\x5c\x46\x4f\x13\xf1\xbe\xb1\x82\x7a\x7f\x26\x8c\xc1\x5a\x98\x24\x80\xbf\x08\x4f\xe3\x65\x2c\x1b\x0e\x0b\x4a\xd2\x62\x55\x85\x9a\xbf\x1c\x8a\x7f\x9b\x3b\xef\x09\x8a\x94\x07\xfd\xea\x0a\x53\x9e\xb0\x08\xfd\xd7\x49\xfa\x01\x86\xcc\x01\x69\xd9\xd9\xe6\x8f\xe5\xe5\x4c\xac\x32\xce\x57\xb5\xc8\x4c\x2d\x80\x5e\xca\x39\xc2\xdb\xbd\xd2\xe0\x2f\x7d\x22\x88\x26\x71\x2f\xf4\xa6\x14\x11\xca\x0a\xeb\x6f\x01\xa1\xf8\x0e\xf2\x9e\xeb\x07\x1a\x43\x22\x2d\x94\x97\x18\x4b\xd8\x5d\x9e\x44\xb1\x66\xbe\x97\xcf\xd2\xa7\x32\xaf\x4a\x23\x34\x63\xd3\xab\x54\x3a\x7a\x3c\x7a\xec\x55\x56\x56\x56\x88\x40\xf4\xdf\xea\x21\x7f\x65\x53\xaa\x98\xaf\x32\x4c\x12\xb2\xc3\x21\x4e\xe7\x6e\xec\x70\x06\x70\xaf\x68\xc8\xc1\xf3\x69\x46\xef\xd7\xff\x09\x33\xe5\x45\x3f\x12\x8e\x97\x15\xfd\xb3\x34\x4a\xc1\x0c\x4b\xb7\xec\x8f\x10\xdd\xf5\xdb\x71\xf1\xcf\x0e\xfe\x40\xf7\x5e\x5b\x63\x34\xef\x8c\xf8\x42\x9b\x32\x91\xe6\xe4\xce\x37\x9c\x17\x8a\xff\xcb\xc6\x10\x30\xeb\x89\x6d\x74\x4d"}, -{{0x39,0x76,0x9a,0x66,0xf0,0xca,0x12,0x90,0xfd,0xa1,0x43,0x75,0xb3,0x5c,0x66,0x3f,0x6a,0x4b,0x2a,0xb3,0x60,0x71,0x79,0xab,0xd9,0x90,0x63,0xe2,0xef,0xa2,0xc6,0xa8,},{0xf9,0xfd,0x4c,0x19,0x1f,0x38,0xf1,0x21,0x90,0xd3,0x28,0x5e,0x20,0xc6,0xce,0xe5,0x4c,0xfd,0x6f,0xf3,0x15,0x30,0x0a,0x4e,0xfd,0xc8,0xa9,0x0e,0x80,0xaf,0x40,0x83,},{0x14,0x42,0xde,0xa2,0x80,0x7e,0x03,0x11,0x59,0xec,0x6a,0x41,0x2d,0x8e,0x07,0xbb,0x3e,0x29,0x93,0x08,0x09,0x0f,0x21,0x8f,0xa7,0xc1,0x0a,0x9c,0x50,0x68,0xef,0x9b,0x64,0xef,0x11,0xca,0x9f,0xb9,0x2b,0xe1,0xd0,0x21,0x6b,0x99,0x31,0x8f,0xf0,0xf0,0x3c,0xb8,0x71,0xcd,0x7d,0xd6,0x3a,0x38,0xae,0x17,0x02,0x31,0x3e,0x5b,0x25,0x0c,},"\xff\x4d\x89\x87\xe3\xfa\x36\x01\x2b\x75\x86\x73\x6b\x79\x3d\x65\x97\x54\x69\x8c\xd1\x2b\x65\xe5\xba\x9d\x75\x8c\xac\x16\x49\x28\x8d\x20\x22\x43\x77\x28\x3e\xa5\x42\x5d\xec\x10\xab\x99\x17\xd1\x8c\xd1\x3d\x1b\xdf\x4a\x76\x9f\x37\x04\x4c\x84\xfa\xa2\xa4\x49\xc6\x89\xe0\x04\xc1\x4e\x00\x5c\x49\xda\x41\x06\xff\x75\xce\x13\x03\x36\x1c\x6e\x3e\x34\xcc\xfe\xe7\x5e\xe9\xc3\x1c\xbd\x06\xa4\xbc\xdb\xb4\x2f\xd6\x49\xbe\x4d\xfc\xd6\x64\x00\x6d\x6a\x5f\x61\x07\x7c\x04\xa6\xa8\x1d\xb3\x6b\xe8\x6b\xa4\x2c\x29\x51\xf0\x51\xae\xda\x64\xac\xea\x49\x6c\xb9\x24\x98\x2b\x9f\x7d\x23\x4a\xc9\x72\x3f\xef\x98\xa8\xe1\x27\x55\xe3\x26\xa5\x2f\xbe\x35\x85\x1f\x41\x1e\xeb\x86\x76\x06\xd4\x5b\x51\x3f\x54\x52\x63\x91\xc5\x54\x63\x5c\x18\x0b\x8f\xd0\xee\x45\x1a\xfc\x96\xe4\xef\xd3\x60\xb6\x1e\x6b\xaf\x03\xdd\x6d\x19\xba\x51\x5c\x31\xec\x1c\xdd\x3a\xff\xff\xdb\x27\x35\x4e\x3e\x6b\x56\xe9\xe1\xa1\xa1\xb7\xd4\xb5\x7d\x9d\x76\x89\xbb\x2f\xea\x6c\x8d\x3f\x9c\xe0\xdf\x2d\x9e\xe9\x19\xc4\x23\x0a\x1f\x20\xb8\x5d\xfe\xfe\x1e\xa3\xd7\xf7\x7d\xb4\x70\xe4\x02\x24\x29\xef\x60\x9b\x0f\xf4\x49\x46\x44\x0a\xcb\x44\xcd\x13\x44\x5b\xcf\xa3\xf2\x05\x03\xc2\x6c\x2f\xb6\x63\xc8\x90\x65\xfb\x93\x34\xa6\x03\xeb\x9a\xb7\x15\x2e\x62\x62\x92\x33\xc4\x4c\xb0\x0e\x77\x71\x6d\x9b\x72\xc8\x4f\xd1\xb3\x40\x63\x4f\xf1\xce\xa3\x47\x50\x15\x76\x10\x0e\xcb\x0f\xd1\xbb\x76\xae\x0d\xff\x1c\x2b\x09\x48\xeb\x71\xee\x2c\xc3\x1e\x79\xd3\x01\x5d\x72\xdb\xee\x22\x4a\x98\x0e\x0f\x95\xa6\x9f\x79\x3d\xa8\x3a\x2d\xaa\x56\xef\xe5\x7b\x2f\x8c\xea\xac\x9e\x55\xf4\x43\xca\x9e\x73\x2b\x48\xc7\x5f\xac\x21\xc3\x6f\xa7\x72\x73\xc3\xf3\x48\x35\xff\xd8\x3c\x96\xf0\x0a\xc6\xe8\x6c\xff\xed\x08\x15\x36\x46\xc1\xce\xa2\x23\xda\x9c\xa3\x60\xca\xb9\x7e\x03\xb2\xb6\xc8\xfb\xa7\xc1\x95\xa3\x9a\xe5\x2e\xb2\xee\x86\x43\x00\xae\x56\xa1\x0f\x54\x7f\x99\xa3\x16\x98\x72\x24\x9f\x97\x77\x4b\x17\x98\x93\x55\x36\xf2\xf5\xf0\x11\xce\x57\x61\x3a\x94\xfc\xb7\xe7\x28\x6a\x6d\x49\xc1\x0f\xd9\x29\xd7\x67\x1c\xbb\x8c\xf1\x7d\xfc\xad\x4b\x24\x85\xc3\xd8\xfd\x79\x12\x87\x21\xe5\x5d\x84\x80\x87\x63\xc2\xaf\xa9\xc5\x5e\x3b\x0c\xd7\xbf\x2f\x0a\x66\xb5\xe4\x67\xbe\xc5\xee\x89\xad\x57\x0b\x60\xf1\x88\xb3\xf7\xb4\xa5\x11\xff\x85\x93\x12\xde\xd0\x78\xd8\xd0\x09\x11\x34\xfd\x49\xbc\x79\x2d\x2d\x7d\x60\xb3\x04\x94\x1c\x7f\x23\x20\x6f\x99\xe8\x63\xb1\xe2\xd8\xc9\xec\xff\xd2\xff\x0a\x3a\x3c\x75\x49\x85\x61\x5a\x9a\x92\xed\xce\xad\x00\xfe\x0e\x05\x49\x3b\x19\x8d\x1f\x7c\x90\x08\x84\x46\xbb\xa4\x60\x38\xa7\x1f\x32\x65\x3b\x59\x12\xb2\x4f\x43\x13\x77\x48\xb7\x5a\xec\x2c\x15\xfe\x4b\xf5\xa6\xf8\x6b\x8a\x6c\xdd\x9c\x74\x47\xf2\xeb\xb0\xf4\x3b\x01\xca\x15\x23\xe0\xd4\x96\x24\x00\x06\xad\x7f\xff\xfa\xfe\x0d\xf5\x75\x4b\x34\x2c\xaf\xf3\x55\x5d\x72\xa2\x7d\x0b\x92\xca\x16\x67\x66\x5c\xec\x43\xbf\xb5\x83\x07\x7a\x9c\x17\x41\xfa\x49\x2c\xe3\xdc\x2c\x75\x29\xcd\xed\x81\xb8\x28\x1a\x3f\x37\x59\x48\xb8\xa7\xce\xd0\x96\xb2\xfa\xcc\x25\xe3\x90\x29\xe2\x21\xb6\x6a\x53\xd3\x97\x9e\x1f\x40\x5f\xd8\x8a\xfc\x06\xec\x6e\x43\x09\xdc\x85\xe6\x9d\x6e\xf2\xb4\xb4\x92\x66\x16\x4a\x9d\x9d\x1c\x31\xee\x39\x21\x12\x7b\x13\x38\x1b\xfb\x74\x0d\xd3\x8d\xc1\xc7\x31\x59\x21\xf9\xc2\xfe\x58\xb6\x1b\x63\x1a\x7d\x9f\xde\x2d\xd8\xa4\xbe\x3d\xed\x04\x90\xae\x3b\x83\x76\x79\x19\x55\xc1\xc4\xb4\xfe\xd0\x0b\x9f\x4c\x38\xab\x73\x50\xfc\x2e\x37\xa3\x15\x0c\x18\x16\x2b\x1f\xaf\x03\x37\x89\x4b\xc2\x3e\x74\xf5\x95\xe4\xbe\x33\x46\x6d\xea\xb3\x54\x58\xbe\x97\xb4\xf7\x56\x58\x97\xf0\x68\x52\xf7\x1c\x60\xfe\xf9\x10\x1d\x72\x6b\x72\xe0\x10\x2a\x97\xb2\xca\x52\x11\xe3\x80\x68\x34\xb0\xac\x1a\x7d\xf8\x7c\x2a\x07\x8d\xf2\x63\xef\x8b\xa4\x57\xdc\x89\x1b\x7f\x2e\x62\x78\x11\xab\x62\x2b\x99\x46\xf8\xc6\xb7\x31\xf2\x40\x78\xd1\x7b\x06\xb2\x00\xc3\x44\x7f\x80\x32\xaa\x3e\x7a\x24\x3e\xe4\x22\xdd\xa2\xe6\x52\xfd\x75\x71\x3a\xfb\xce\x8a\x59\xef\x85\x36\x65\x3a\x48\xdc\xf4\x2a\x70\xe7\x62\x1f\x9b\x28\x02\x40\x9b\xe1\xc1\xa6\x1f\x32\xe3\x67\x89\xa5\xc5\x05\x5e\x1a\x82\x68\xe9\xdc\x43\x8c\x2e\x15\x27"}, -{{0x0c,0x80,0x8b,0x06,0x6f,0x0c,0x8e,0x8d,0xbb,0x1c,0x23,0xd6,0xc2,0xce,0xdd,0x0b,0xe8,0x66,0xd8,0x42,0x5f,0x24,0x1a,0x92,0x85,0x70,0x0e,0xa5,0x45,0x36,0xcf,0x6d,},{0x44,0xee,0x72,0x90,0x04,0x50,0xc5,0x6a,0xb2,0x1f,0x26,0x86,0xd2,0x95,0x25,0xd0,0x66,0x3e,0x0b,0xdd,0x87,0x72,0x5b,0xea,0xc5,0xd6,0x8b,0xac,0xeb,0x69,0xf1,0xd2,},{0x38,0xc6,0x82,0xce,0xde,0xfb,0x13,0xe4,0x6b,0x11,0xf7,0xb5,0xf8,0x00,0xcc,0x81,0x20,0xd4,0x5a,0x83,0xcd,0x8d,0x8d,0xec,0x10,0xc5,0x77,0xbb,0x01,0x53,0xd5,0x09,0xba,0x4f,0xdf,0x40,0x09,0x98,0x78,0x8b,0x70,0x60,0x07,0xce,0x16,0x2b,0x96,0x94,0x5c,0x71,0x40,0xbe,0xee,0x74,0xe1,0x9d,0x07,0x43,0xaf,0xa4,0xec,0xfd,0x25,0x0a,},"\xc9\x45\x71\x41\x00\x58\x1f\x4e\x24\xda\x11\xfc\x0f\x6c\x6d\x02\x10\x43\x3f\x97\x77\x52\x51\x24\xc5\x5e\xe0\x72\xd8\x5d\x79\x8b\x70\x5f\x9d\x31\xc8\xf9\x77\xdb\x6e\xdf\xb7\xa6\x5c\x78\xad\x2d\x7d\x31\xd6\xb7\xb5\xbe\x40\xff\x11\x78\xd3\x03\xb6\x83\x9b\xb0\xc6\x32\x10\xc1\xd3\x38\xc1\x03\xaf\xa0\xd4\x53\xec\xa1\xbc\xa2\x77\xd9\x30\x77\x8a\xd5\x08\x02\x27\x2f\x03\xdb\xe2\x18\x4f\xc3\x1e\xf8\xea\x6a\xbe\x21\x69\x97\x19\x9f\x7c\x1b\x33\x77\x37\x96\x89\x07\x27\x2a\xa5\x1b\xd4\x9c\x07\x38\x9c\x95\x46\x8c\xef\x4f\xd9\x9a\xe7\x8c\xa4\x54\x2a\x2b\xbc\x0e\x8a\xa9\x52\x14\xad\x1c\xff\xf9\xd5\x08\x5a\x43\x43\x94\x47\x3b\x84\xb7\x4b\xe9\xbf\x2f\x02\x02\xad\x1e\xe4\x61\x66\x04\xca\x1d\xd7\x5f\x4a\x19\x53\x42\xeb\xbf\x8f\xc5\x9f\x3f\x79\x61\x65\x54\xdc\x7b\xfd\xd5\x56\xbe\x43\x72\x21\xc1\x0b\xfa\xd3\x9e\x11\x9e\x06\x04\x5b\xe5\xfe\xd6\x83\xd3\x53\x4f\xb6\xcf\xed\x33\x89\x1c\x96\xf9\xc3\x30\xf2\x8b\x68\x4f\x8f\xba\xd4\x7c\x01\x41\x8e\xab\x6c\xee\xcc\x2e\xd7\x77\xf4\xc2\x18\xa2\x7a\xc2\x25\x82\x39\x23\x15\xc5\x3a\xa7\x30\x9e\xc5\x4c\x61\x75\x23\x6e\x44\x24\xdc\x97\x84\x65\xab\x62\x8d\x95\x44\xb0\xbe\x84\x10\x3e\xb5\x6f\x1b\xaf\xe5\xe5\xea\xed\x04\xc9\x8b\xfe\x2e\x8a\x24\x18\xc6\xc5\x2a\x61\xea\xce\x85\x23\x6b\x66\xc7\xb3\xb8\x70\x7e\xd5\x56\x41\xdd\x9d\x5d\xa9\x7c\x99\xc1\x1c\xbe\xb9\xaa\x2d\xb1\x47\x82\x0d\xc7\x24\x80\x0a\x9d\x80\xf5\x05\xfa\x5a\xf2\x09\x21\xca\xd2\x43\x56\x83\xbb\x4f\xc6\x0b\xdd\xd4\x75\xf8\x63\xe2\xf5\x95\x0d\x23\x63\x99\xd8\xd7\x5b\x40\x4b\x39\x4a\x54\x67\x37\xf9\x3a\x62\x40\x87\x00\xb3\xab\x3c\x1e\x92\x2b\x1a\x85\x9a\x29\x15\xc2\xd3\x53\x68\x81\x5c\xd4\x5b\x85\xb2\xac\x08\x31\x21\xff\x00\x0f\x05\x0d\xcd\xf4\x15\xe5\x27\x5a\x5c\x42\xda\xe3\xb1\x54\x00\xf3\xdd\xaf\x93\x39\xf2\x0a\x12\x61\xa8\x8c\xd9\x02\x05\x63\x97\x63\x21\x11\x52\xdf\x41\x4a\x9a\x6a\x62\x18\xf5\x6b\x35\xa2\xde\x9e\x84\x82\x44\x9f\x6d\xa7\x7c\x9e\x3d\x4a\xf0\x49\x30\x15\xa7\x26\x21\x7f\x82\xac\x58\x95\x4f\xe3\xe2\xe3\x44\x40\x35\x6b\x11\x2e\x06\xa6\xf6\x71\xfb\x5a\x6e\xf4\x61\x9a\x6e\xa7\xb4\xe0\x4d\xb3\x75\x7f\xb6\x64\xc3\x96\xb3\x41\xca\x89\x00\x1d\xc1\x60\x4b\x51\xfa\x91\x53\xf9\x13\x0c\x10\x20\xff\x88\x90\x92\x87\x82\x3a\xb3\x91\x5c\xcc\x85\xc4\xe3\x5d\xf6\xc2\xf8\xe6\xf9\x02\xbe\x82\xba\x21\x29\x7f\xd3\x83\x5a\xff\x5c\xe0\x2f\x3c\x07\xdc\x09\x3f\xcb\x1a\xba\x26\xe0\x6d\xfe\x6f\x02\xdf\x79\x29\x1a\xac\xa0\x69\xec\xab\x93\x81\x40\x4c\x9c\x3e\xa1\xad\x40\x9a\xdf\x29\x2a\x91\xe3\xa5\x82\xd5\xa7\xb6\x8f\xfb\xe1\x0a\x03\x05\x24\x8e\x09\x67\xe6\xdf\x37\x2f\x28\x1b\xd1\x92\xe1\x39\x97\x9c\x98\x66\xca\x8f\xe1\xe1\x0e\x06\x16\xdc\x2d\x4f\x85\xe1\x19\xe0\xcb\x4b\xfe\x8c\xc3\x1d\x9f\x5c\x01\x8b\x65\x40\x85\x24\x00\x0a\x30\x16\xa2\x3d\x99\x14\xd5\x7e\x95\x55\x76\xe2\x66\x0b\x0e\x0d\x96\xc8\x49\x5a\x12\xc3\xd7\x31\x22\xd2\x00\xb0\xf0\xe5\xeb\xd4\x46\x56\x2b\x08\xf4\x79\x34\xab\x49\x9a\x96\x99\x1d\xcf\x99\xc9\x6a\x62\x88\x07\x39\x84\x5d\x29\x82\x01\x50\x55\x3e\xae\x9b\xe0\xbb\x41\xd5\x3d\x3a\xf0\x1d\x98\x67\xbb\x47\x32\xc9\x0b\xf6\xe1\x37\x31\x6e\x3b\x1e\xdc\xc2\x09\xa8\xa0\x9f\xb0\x62\xa6\xef\x05\xf3\x7e\x57\xf2\xc5\xd1\xd0\xca\xba\xf0\x7a\x8e\xd7\xd4\x14\x55\x40\x7b\x09\x67\x54\x18\x0a\xa9\x6d\x3d\x96\x59\x19\x45\xdd\x7a\x10\x40\xa2\xde\x60\xd8\xe1\xc0\x54\xf7\x85\x46\x52\xb7\x32\xe7\xa8\xf5\xb6\x47\x4c\x3b\xaa\x18\x40\xfb\xe8\x1b\x1e\x6b\x54\xe2\x01\xef\x0b\xc8\xd0\xf2\x13\xd7\xce\xc1\xd8\x24\xd2\x22\x09\xac\x72\x52\x5a\x64\xb9\x03\xe7\x73\xb8\x3f\x1b\x68\xf6\x40\x27\x9f\x15\x05\x3d\x21\xec\x15\xce\x2f\xf7\x59\x22\x17\x6b\x75\x84\xa1\x6b\xf1\xa1\xf0\xd6\x36\xb7\x94\x2a\x3d\x61\x86\x2f\x6f\xd1\x30\x99\x72\xd3\x14\x1e\xb7\x69\x31\x4c\xa9\x75\xd0\x20\xbf\x02\xbf\xdd\xf1\x7d\x14\xb6\x0e\xb7\x86\xbf\x9f\x55\x98\x9f\xe4\x73\x32\x0d\x44\x29\x67\x7e\x30\x1c\x68\x26\x33\xf8\x13\xff\x26\xc0\xa3\xda\x92\xf6\xd0\x68\x06\x16\x10\x5b\x04\x25\xaf\x33\x8c\x2e\xa6\x15\x3b\xdd\x52\x16\xfa\xe2\xaf\xe4\x61\xe9\x24\x9c\x05\xe3\x2f\x76\xad\x7c\x42\x9d\x92\x53\x4b\x68\x6d\xd1"}, -{{0x04,0x9d,0xac,0x3c,0x97,0x7d,0x9d,0xf5,0x03,0x49,0x6b,0x43,0xd7,0x6e,0x55,0x40,0xe3,0x15,0x00,0x1a,0xd5,0x7f,0x15,0xea,0x9f,0x08,0x70,0xca,0xd2,0xd4,0xf9,0xe9,},{0xfc,0x6f,0x4b,0x7e,0xb3,0x9a,0x71,0x16,0x80,0xf9,0x66,0xd4,0x68,0xa6,0x1a,0xbb,0x13,0xa9,0xb6,0x44,0x9b,0xb9,0x9f,0xda,0x3d,0x12,0xce,0x1b,0x50,0x6d,0x1b,0x4b,},{0x75,0x32,0xd1,0xa6,0x1a,0x98,0x1f,0x30,0x3d,0x7c,0x24,0x54,0x35,0x4f,0x99,0x54,0x0c,0xd4,0x84,0xcd,0xe9,0xab,0x33,0x7d,0x6f,0x7b,0x51,0xf1,0x79,0x22,0x0f,0x7f,0xa2,0x07,0x34,0x76,0xb4,0x1c,0x71,0x52,0x9f,0x98,0x36,0xdb,0x6b,0x1d,0x0f,0x5a,0x48,0x2b,0xbb,0x4c,0x68,0x36,0x61,0x76,0xed,0x14,0xd4,0xd8,0xee,0xfa,0xde,0x0d,},"\x7f\x31\xe3\x46\xf6\x8d\xa7\x37\x16\xaa\xcb\x16\xee\xa1\x9b\xb2\x41\x42\xdc\x28\x3e\x72\x63\xff\xc3\xf7\x04\xa2\x2a\xe5\x27\x5a\x0e\xf9\x5f\x06\x69\xba\xe5\xa5\x4c\x7f\xeb\x84\xbc\x74\x87\x3c\xca\x0f\x33\x5d\x6c\xff\x3d\x8b\x4a\x20\x05\x6c\x64\xf5\xe8\x82\xcb\xbb\xd2\xac\x74\x20\x76\x76\x46\x7e\x54\x66\xdd\xd5\x6a\xed\xf5\x6e\x09\x7c\x7f\x59\xd9\x45\x91\x5e\xb0\xeb\xd0\xc3\xc8\x3d\x48\x88\x8d\x3e\x9e\xde\x51\xad\x2d\xd8\xa0\xee\x1e\xab\x4c\xf8\x7f\xfa\x78\x63\x5a\xfc\x4d\x6e\xf3\xe8\x7d\xda\x3b\x65\x56\x5c\x29\x85\xa4\xad\x0a\xcf\xdf\xb8\x1c\xb0\xe6\x1c\x67\x82\x6a\x6e\xa0\xbe\xd4\xc0\x8a\xa1\xa5\x41\xde\x60\x45\x87\x04\xac\x21\xca\x12\xf1\xc8\x11\x8b\xb3\x09\x2c\x35\xa4\x0c\x92\x1e\x68\x45\x64\x56\x2c\x2c\x10\x49\xdc\xdc\x2b\x8d\x6a\x97\xe3\x56\x7d\x35\x6b\xff\xb5\x69\x2a\x41\xd8\x9d\xdd\xa0\xec\x35\x52\x15\x2a\x27\x57\x7f\x1c\xce\x57\xd0\x09\x86\xdc\xa7\x7e\xdf\x5e\x25\x18\x15\x82\x00\xad\xf6\x90\xaf\xfb\x31\xaa\xf2\xb5\x74\x83\x68\x39\x44\x09\x99\xf1\x57\x91\xce\xa8\x53\x42\xac\x94\xa9\x6c\x7a\xf7\xa1\x9e\x49\x43\x10\xae\x26\x67\x5f\x43\xc3\x52\x58\xe8\x5b\x68\x40\xb9\x9c\x6b\x09\xcf\xa5\x8d\x19\xf1\xe4\x3a\x77\xe3\x97\xb0\x8c\x0d\xb1\x83\x0b\xca\x67\xb3\x9e\xcd\x87\x52\xda\x61\x1e\x08\x32\xc6\xca\xe7\xbb\x8c\xe7\x4a\x82\xe7\xe7\x33\x0b\xe5\x06\x2e\xd0\x5a\xa5\xc8\x44\x57\xb0\x07\xfb\x5c\xcd\xc2\x0a\x55\xd5\x4d\x8e\x04\x09\xc8\xbd\x83\x88\x3d\x2e\x02\x9d\xff\x26\xea\x5d\xb2\x75\xdc\xe0\x99\xe4\x18\x65\x9a\x04\x00\xf1\x3b\xe9\xff\xdc\x14\xe7\xd6\x45\xa9\x46\x77\xca\x84\x69\x70\xb7\xe6\xac\x52\x7f\xa0\x09\xa3\x59\x45\x4b\x3c\x49\x36\x49\x05\x18\x9f\xb4\x9c\x9b\xac\xb6\x50\xc0\x3c\xd8\x28\x75\x89\x4e\x35\x46\xba\x03\xc3\x2e\x33\x6f\xc6\x51\x6a\x87\x67\x6c\x50\xd5\xb8\x0b\x30\x54\x27\x3b\x15\x7c\x5d\x76\x75\x14\xe5\x45\x74\xb8\xa1\x01\x98\x5a\x8e\x96\x7e\x95\xda\x8f\x92\x98\x00\x26\x0e\x08\x14\x8b\xee\xe2\xd7\x78\x1e\x9e\x85\xd4\x63\xa9\x4f\xfe\xfd\xbb\x75\xc2\x8f\xa8\x89\x80\x15\x68\x09\x99\x42\x9c\xee\x79\x8b\x3f\xd2\xd9\x67\x37\x86\x8a\x26\x3f\xba\x9f\xb6\xf4\xaa\xd5\x6a\x15\xc6\x41\x2f\xf8\x5e\x7d\x37\x52\x10\x2d\xaa\xf2\x5e\x74\x5f\xa5\xf6\xf1\x74\xa2\x31\xfc\xce\x86\x24\xdd\x70\x85\x6f\x9b\xab\xcc\x20\x91\x44\xff\x68\x64\x64\x8d\xea\x0d\x68\x84\x56\x6a\x4c\x39\x14\x78\x05\xbe\x08\x4e\x47\x40\xbc\x50\x93\x09\xbc\xb1\x42\x96\x4b\xb0\xcf\xcf\x67\x26\xa0\xe0\x4b\xbf\x32\xae\x68\x34\x73\x2b\xda\x03\x84\xce\xa8\xf4\xa4\x84\x9b\xba\x0d\x18\x64\x6c\x1c\x34\x47\x18\x96\xb5\xbe\xf1\x49\xf8\xca\xb9\xec\x83\x72\x2b\x0f\xb2\x09\xef\xe8\xa0\x4c\x4a\x23\x5d\xc8\xdd\xb2\x0a\xcd\x92\x76\x5a\xfb\xf3\x05\x87\x40\xea\x70\xb9\xc1\x0d\x9c\x5a\xef\x86\x06\x29\x8f\xe4\x15\x15\x93\xb2\x1f\x79\x7d\x92\xae\x9f\x1e\x08\x81\xb0\xd2\x71\xb0\xd5\xb1\x0c\x6e\xd8\x3c\x34\x9e\xc2\x47\x3f\xbf\x2f\xf7\x80\xdc\xd0\x76\xd8\xcf\x0a\xea\xfa\x71\xfe\x2b\x8c\x51\x28\x01\x5f\x8f\xbb\xcf\xec\xd5\x28\x1c\xd5\xea\xcb\x6f\xe9\xac\x6e\xaa\x6e\x47\xd6\x67\xb9\xad\x4b\x7e\x41\x1e\x6c\xb7\x46\x3d\x56\x76\x07\xaf\xbf\xd0\x41\x8c\x4e\xb0\x6a\xfe\x84\x7f\x5e\x40\xb4\x99\x44\x38\x28\xd5\xa2\x73\xa4\xa8\x7e\x46\xde\xf2\x1a\x91\x9d\x73\x86\x3a\xf0\x05\x4a\x09\x9e\x3a\xdc\x54\x50\xb8\xe3\x2f\x51\xea\x52\xc5\x99\xa4\xa2\xa3\x53\x51\x78\x8a\xf7\xcb\x71\xe5\xc4\x4b\xcb\x8d\xf5\x4a\x60\x1e\x6e\xc2\xc1\x82\x8b\x48\xc4\xb1\xae\x44\x63\x10\x6f\x10\xef\xa5\xca\xf3\x09\x1a\xbf\x99\xaa\xba\x52\x52\xf4\x84\xd3\xbb\xc6\x2b\xfa\x6b\x2a\x80\x6d\x23\xc6\x33\x1a\x62\xfc\x46\xbc\x62\x76\x79\xe7\x3e\xc8\x2d\xcc\x08\xf7\x91\x43\xf4\xb7\x1e\xcf\x35\x7e\xa2\xf0\xd7\x4e\x6d\x30\x58\xe6\x06\x04\x3f\x6e\x8f\xed\x70\x42\x82\xc1\x6b\x1f\x98\x8f\xfa\x36\x5c\xfa\xe9\xa3\xcf\x79\x2e\x0c\x5b\xaa\xd7\x0c\xa7\xe2\x57\x76\x01\x8b\x5e\x7f\x0e\x95\x44\xe1\xd7\x3f\x3e\x5d\x1e\x41\x6a\x5e\x50\xfb\xed\x29\x6d\xc1\xbf\x4b\x29\xa3\xfb\xe3\x2e\xfb\xd7\xe9\x9c\x83\x01\x5d\x27\xf5\x35\xad\xec\xf1\x75\xfc\x36\xc1\xea\x4f\x44\x23\xb3\x6d\xcd\xc0\x54\xba\x99\x32\x78\xe8\x5a\xc3\x62\x2d\x43\x5f\x52\x37\xba\x61\xb4\x9a"}, -{{0xf0,0x7d,0x61,0xb5,0xca,0x1c,0x27,0x00,0xcb,0x50,0xf9,0x00,0xc2,0x6b,0x7c,0x28,0xf6,0xc6,0x94,0x08,0x08,0xc7,0xba,0xff,0xf7,0x4f,0xca,0x4b,0x11,0xf4,0x25,0xd4,},{0xeb,0x24,0x3d,0xfa,0xcc,0x2d,0xc6,0x43,0x57,0x76,0xd5,0x54,0xec,0xed,0x8b,0xf9,0x23,0x90,0x60,0x4b,0x35,0x55,0x7c,0xda,0x51,0xfd,0x20,0x3e,0xdd,0xb4,0x93,0xfa,},{0xc1,0x9b,0x53,0x2b,0x82,0x48,0x56,0x39,0x32,0x63,0x97,0x01,0xbf,0x15,0xbc,0x01,0x5f,0xae,0xbb,0x17,0xbb,0x98,0xd8,0x71,0x61,0x6e,0x10,0x48,0xd6,0x4c,0xa5,0xf9,0x55,0xf5,0x58,0xf6,0x3b,0x53,0x53,0xa1,0x57,0x6f,0xa1,0xac,0xae,0xf3,0x9b,0xcb,0xc9,0x02,0x17,0x56,0xdf,0x5d,0x1a,0xb3,0xbc,0x74,0x1a,0xcc,0xf9,0x05,0x9b,0x04,},"\xc1\xc6\x78\x43\xd6\x9a\x0e\x62\xe7\xbf\x71\xf9\x02\x06\xa3\xd5\x59\x5c\xa3\xc4\x82\xaa\xa7\x67\xe9\x31\xb0\xd6\xc2\xf4\x75\x2a\xb8\x69\x91\xf0\x35\x83\xbb\x13\x8e\x9f\x72\xfa\xb5\x8f\xd6\x02\xa4\xb6\xb2\x96\x02\xcf\x89\x14\x08\xaf\x5a\x1b\xfd\x33\x98\xc0\x17\x8c\x44\x14\x61\xe3\xf4\x9b\xc8\x1d\x64\xc0\xd9\x7f\x5d\xed\x69\x2c\x75\xd4\xd6\x4d\xac\x5d\x80\xd6\x3b\xd4\xdc\x52\x10\xc1\xd9\x35\x0b\x14\x2b\xa6\xe7\x68\xf1\x50\x80\x7a\xb8\xa8\x6c\xac\xdb\x59\xd8\x4d\xdf\x66\x0b\xe5\x62\x03\xc0\x14\xfb\xa1\xe0\xdc\x16\xfa\x6d\x32\x69\x4e\x14\xb1\x28\xed\xd1\xf6\xc6\xab\x44\x5a\x3a\xd3\x41\x74\xfa\x9e\x4b\x01\xf2\x5b\x1d\x5e\x6e\xb7\x69\x83\xb4\x29\x5c\xe4\x91\x4d\x3a\xe4\x8c\x70\x4a\x30\xe5\x54\xfc\x1f\x86\x8b\x62\x72\xef\xf0\x6d\xa2\x4b\xfe\x17\xe4\xe0\xf0\xfa\x46\xbb\x08\xff\xb9\x07\xcb\x61\xbe\xbe\x52\xdf\x31\x1a\x64\xcb\x57\x8b\x30\xfd\x62\x7d\xf1\x12\x21\xae\x40\x03\xa0\xb0\xc6\x8e\x3c\x6f\x95\xa2\x1c\x85\x00\xd4\x1b\x2c\x58\x9c\xc4\x6a\x13\x9c\xac\xff\x57\xdc\xf0\x07\x59\xf5\x2e\x9c\xa3\xda\xbd\xb1\x78\x8a\xb6\xb3\x8a\x50\x48\xf5\x8e\x08\xe0\x5c\x39\x4f\x9d\x3c\x72\x11\x3d\x45\x2b\x70\x84\xc5\x19\xf8\x6c\x16\x89\xff\xdb\xae\x50\x6e\xd8\x45\x05\x22\xcb\xe4\x3d\xe2\x7a\xa3\xbf\xdd\x92\xa9\x1b\x71\xe5\x2a\x3c\xbf\x77\xc1\xbd\x28\x93\xea\xbd\x40\x7a\x57\xfe\x5e\x14\x68\x73\xbf\xb2\x04\x3f\x4a\x61\x47\xdf\x08\x3e\x54\xa2\x20\x8d\x19\x25\x81\x3f\xa4\x04\xe4\xc4\x74\x06\xe7\x72\x86\x43\xeb\xfb\x0b\x10\x14\x2f\x90\x9e\xf8\x56\xfd\x3a\x91\x6b\xc0\x85\x15\x43\xb8\x2a\x55\xf8\xcd\x52\x9b\xd2\x1d\x9e\x29\x09\xd6\xd7\xe7\x7b\xdc\xea\x46\x73\xe5\x45\xff\x4a\x67\xfa\x37\xd6\x5f\x1f\x63\xf1\x1d\x5d\x0d\x55\x97\x4a\x30\xab\xe1\x88\x33\x5d\xb5\xdc\xbd\x35\x66\x58\xf9\xb7\x76\x82\xd9\x6d\xab\xb2\x58\xea\x95\x95\x1a\x05\x59\xae\xa4\x06\x4d\x5e\xa1\x68\x05\x01\xdc\xb4\x22\x8f\x2c\x95\x6f\x81\xd2\x10\x11\x44\xaf\x74\xc7\x16\xbc\x8b\xf4\x29\x6d\xc3\xb8\x31\x72\x5c\xc1\x7d\x3b\xfd\x90\x66\xa2\x99\x53\xb2\xec\xd7\x50\x59\x43\x5b\x49\xa2\x5a\xc5\x25\xb4\xfb\xab\x17\x79\x02\x2d\xfb\x6d\xe5\x25\x14\x9d\xcd\x90\x2a\xc8\xa7\xe2\x1f\x34\x4f\x5f\x01\x01\x48\x06\x92\xd6\x16\x08\x95\x2c\x71\x41\x3e\x30\x03\x79\x45\xe2\x06\xc5\xee\xad\xfc\x3e\xdc\x4b\xae\x0d\x79\x6c\xa0\xc5\xf5\x6d\x6f\xfb\x3f\x09\x69\xdf\x9d\xf8\xa7\x94\xf5\xdc\x83\xa3\xb2\xf5\xc3\xab\x36\xbb\x90\x1b\xcc\x31\x55\x1c\x55\x0c\x63\xfa\x41\xd6\xa8\xd5\x7b\xdb\x9b\x5c\x65\xbc\x61\x0c\x3a\x98\x97\x52\xab\x28\xa0\x15\xe7\xc2\xf6\xb2\xfb\xf1\x99\xa7\x6b\x97\x50\xc0\xd3\xd5\x92\x11\x9c\x8b\x40\x22\xfa\x45\xba\xde\x2f\xbb\x41\x43\x26\x79\xb5\x2a\xcb\x46\x08\xa9\x5c\x34\xaa\x40\xbf\xfe\xc1\x0b\xc9\x8f\x47\x29\xdf\xcc\xb6\x50\xb2\xa0\x52\xdf\xb0\x68\x95\x9e\x64\x8a\x92\xd5\xaa\x4d\xd2\xd1\x7d\xde\x67\xcd\xf2\xe6\x37\x7a\xf0\xd4\xae\x37\x96\x07\x38\x9d\x7e\x35\x96\x44\x1b\x9f\x42\x22\xcf\xf6\xaf\x73\xb3\x30\x02\x70\xce\x54\x80\x0b\xd9\x34\xa9\x10\x9a\x02\x56\x3a\xdc\x56\xae\x46\x58\x44\x51\xcd\xaf\x4a\x77\x53\x81\x57\xe5\x87\x0f\x4a\xe1\x2d\xbc\x81\x87\x0f\x5d\xb4\x1a\x2c\xb5\x5e\x00\xdb\x3d\x22\x31\x62\x8f\x17\x27\xc3\xac\xb9\x9e\xd3\xac\xd8\xb6\x71\x56\xa8\x00\x5a\x4c\xc8\xf3\xd3\x55\x5b\x79\xa0\x37\x73\xa9\x31\xf1\x4e\xeb\xce\x40\xb9\xfe\x46\xed\xe5\xda\x08\x81\xfb\x22\x07\x17\xe4\x18\xe8\xb5\xa0\xfe\x5e\x47\x7e\x72\x85\xc5\x54\xe8\x59\xe1\x64\x41\x67\x2b\x48\x99\x34\xa3\xa9\xee\xb8\x8d\x78\xfc\xc5\xc1\xdb\x2d\x1f\xbd\xde\x39\x27\x73\xf6\xc9\x39\x97\x2e\xe8\xfa\x31\x89\xf4\xe9\x87\x2b\x4a\xbd\xc8\x3b\x37\x9c\x0c\x10\xe8\x18\xdc\xff\x75\xc8\x3d\x68\x70\x72\x92\x84\xce\xd4\x1f\x2f\xf5\x5a\x87\xc9\x60\xe6\x3d\x12\x11\xf0\x80\x71\x29\x3f\x6a\xc6\x3f\x9b\xde\xf3\x8f\xd5\x91\x9c\xa9\x0b\x3f\x5e\x25\xa6\xc0\xc6\x64\xc4\xec\xf8\x31\xc6\x4e\x2d\x4c\x6e\x79\x8a\x98\xa3\xa0\xf7\xbe\x7a\x24\x63\xea\xda\xa6\xa2\xa3\x48\xf9\xa4\x94\x71\x71\x23\xcc\x0a\x28\xc0\xa5\xea\xe3\xf5\xb5\x85\xf2\xcb\x8c\xb2\x60\xc2\xc5\x03\xe4\x15\x78\x57\x3c\xd9\xb7\xcb\xa1\x40\x8d\xca\x9d\x86\x0a\xe4\xf8\xc3\xd3\xf3\x22\xa4\x5b\x58\xa2\xc4"}, -{{0x50,0x86,0x4a,0x75,0xaa,0x0c,0x69,0xb5,0x93,0x50,0x07,0x7c,0x20,0x4b,0x20,0x75,0x7f,0x2b,0x8b,0x68,0x55,0xc3,0x7e,0xd7,0x21,0xb4,0x9f,0x2a,0xc9,0x17,0xd6,0xb2,},{0xcf,0xf3,0xeb,0xd5,0xea,0x0c,0x8b,0x55,0x31,0xd9,0x21,0x1e,0x22,0x19,0xe4,0xcf,0xe5,0xde,0xd9,0x91,0xd8,0xec,0x42,0x4d,0xf5,0x4c,0xf5,0x3c,0x83,0x76,0xf9,0xbd,},{0x17,0x74,0x55,0xa7,0x16,0x94,0xf1,0x2b,0x76,0x2f,0xd1,0x7e,0x08,0xbd,0xf0,0x10,0xa7,0xfc,0x91,0xd1,0x91,0x41,0xd7,0xae,0x23,0x99,0xbd,0x24,0x1a,0x99,0x8a,0x6a,0x50,0xa9,0x72,0x2a,0xc1,0x23,0x2c,0x59,0xe4,0xe2,0xaa,0xa8,0x28,0x07,0x8b,0x2b,0x92,0xf4,0xa5,0x4c,0xdf,0x0e,0xfe,0xbb,0xa2,0xc1,0x6d,0xbe,0xaf,0x07,0x22,0x03,},"\xb3\x65\xf4\x76\xac\x92\xe7\x60\x12\xa7\xff\xd8\x78\x2a\xf1\x5a\x3f\x5e\xe1\x47\xf6\x03\xa3\x67\xad\xf2\xf9\x72\x46\x13\xe8\x76\x5b\x03\x7a\xc0\xeb\x1f\x67\x37\x36\xe1\x13\x63\xe3\x52\xed\x5a\xe9\xeb\x5a\x67\x12\x5e\xd8\x18\x90\x03\x42\xae\x93\x37\x1c\x43\x3b\x91\xf6\x02\x1d\x4b\xe2\xa0\x52\xb0\xda\x43\xb3\x68\x2e\x7f\x74\x0a\xe8\x01\xd0\x54\x10\x57\x85\x8e\xb0\xc9\xc2\x8d\x98\xf0\x3b\x45\xe1\x28\xaa\xa3\x42\xc6\xb6\x02\x77\x67\x92\xaa\x81\x24\x1c\xad\x06\xf1\x33\x8f\xa0\xc7\x17\x57\x18\x0f\x58\x8c\x83\x01\xd9\x1c\x27\x67\x9b\x50\x21\xcd\x75\xd7\xf6\x17\x1e\xe9\xf8\xd5\x6e\x43\x77\x67\x98\x12\xf6\xec\x5e\xd4\x65\x38\xca\xed\x50\x0c\x1d\x15\xf5\xfc\x86\xea\xf9\xed\x9c\xf9\xa0\x60\x6b\x22\x61\x4f\xaf\x67\x64\x62\x13\x4e\x3d\xb3\x58\x23\x32\xb4\x83\xdf\xa5\x4c\xa2\x9a\x5e\xb0\xd6\xba\xe3\x38\x0e\x19\xd0\x60\x11\x34\x53\xf3\x2b\xba\xb7\xe1\x18\x62\x7b\x40\xbc\xab\xf1\x71\x1b\xcf\xea\xb8\x95\x7d\xe3\x39\x43\x6c\x70\x88\xbb\x88\x31\x01\x53\x9a\x09\xd3\xbe\xf0\x88\xfc\x1f\x84\x07\x64\x03\x6f\xfb\xb3\x3d\xec\xd1\x2a\xac\x57\xfd\x26\xf8\x48\x23\xe1\x95\x53\xd4\xd6\x7e\x00\x0e\x94\x36\xca\x32\x3d\xe0\x99\xbc\x1c\xe7\x5e\xbf\x5d\xdc\xcb\x44\x8c\xd7\xa2\xe4\xbb\xd6\xb3\x2e\x3f\x20\x24\xf9\x6c\xc5\xc7\x15\x2b\x8b\xe8\xed\x0b\xd8\xe4\x36\xd3\x24\xd1\xce\x1d\xd3\xcf\xcc\x45\x2a\x28\xc7\x3a\x95\xaf\x84\x82\xaa\x77\x2a\xe5\x3d\x5b\xe1\x29\x2e\x39\xd1\x71\x6b\x43\x75\x8f\xe5\x63\xc8\xaa\x3b\x74\xbb\xa5\xc0\x2d\x04\x77\x8d\x91\xe3\xd4\x3d\xcc\x72\xbb\x7c\x7b\x04\x3c\x05\xc8\x74\x5b\x70\x5e\xe7\x5b\x5a\x4e\xc7\xb9\x5b\x65\x43\x59\xfb\x5e\x85\x33\x38\x21\x98\x51\xd4\x0a\x8a\xfb\xb4\xf9\x1e\xcb\xb4\x1e\xb8\x15\x34\x19\x6c\xc0\xcc\x9d\x3e\xb7\x14\x39\x6c\xaf\x04\x5b\x23\x17\x22\xd4\x48\x65\x03\x64\x04\x19\x98\x84\x80\xa7\x81\x58\x08\xbe\x97\x42\x87\x37\x2c\xfc\x48\x99\x65\xaa\xc5\xb8\x09\x5c\x63\x75\x81\xeb\x91\x0f\x90\x55\xcd\x1c\x0a\x0a\x3b\x0b\x33\xac\xa9\x0f\x7c\x5b\x8e\x6e\xf6\x83\xab\xf0\xce\x53\xae\xba\x51\xbe\xc4\xfc\x7b\x42\x7a\x23\x47\x36\x0f\xca\x86\x36\xd3\xf1\x46\x92\x84\xf2\x69\xa9\xab\xf0\xcb\x1a\x24\x4a\x15\xd6\xb4\x04\x65\xe7\x5c\xf8\x90\x92\x47\x4a\x8b\xed\xa0\x33\x39\x1d\xd3\x11\xc4\x99\x51\x9a\x08\xc4\xf0\x34\xe7\x19\x18\xd7\xca\xd4\x18\x45\x32\x7c\x89\xe7\xb1\xe9\x4a\xfb\x07\x23\x78\x2c\xe5\xc5\x53\xef\x36\x79\x1b\xba\x63\xde\x17\xd7\x46\x49\x18\x94\x01\x2c\xeb\xd8\x7b\x18\x37\xa8\x21\xef\x5c\x62\x4b\xbc\x84\xcc\x50\x35\xf5\xe7\x0c\xd9\xf2\x1b\x42\x21\x9a\x2d\xce\x30\xe0\xe6\x5c\x25\x0d\x0d\x19\x4d\x2b\x52\x48\x6b\x03\xee\x66\x33\x29\x81\xa5\x22\x51\x74\xdb\x17\xe5\xa8\xbb\x4a\x10\xed\x9c\x8a\x44\x5c\x41\x44\x2f\x3b\xcd\xb6\xb4\xf4\x9e\x4e\x1d\xc8\x76\x61\xa7\xb6\xe4\x1f\x35\xf5\x5d\xd6\x7b\xd4\xcb\xc6\xff\x58\xbf\xbf\xfa\xff\xd2\xc3\x82\xfc\xad\x0c\xae\x8f\x0d\xf9\xaf\x6a\xcf\x09\x40\x00\x76\x18\xa5\x4a\xee\x31\xd9\x32\xcb\xd8\xe8\xb4\x1c\xa0\x38\x21\xc4\x28\xa0\xef\x8e\x58\xd2\x43\x5e\xec\xd5\x03\xc5\x4d\xa9\xc1\x62\x8f\x3c\x74\x9b\x77\x05\x19\xf5\x3b\xf2\xd5\x7e\xd7\x12\xd0\x75\xd3\x73\x37\xb7\x7a\x2b\x10\xa7\x2d\x2d\x59\x0c\x20\xd5\xce\xc2\xca\xcc\x6c\x3a\x8d\xc1\x13\xe2\xd1\x6e\xf2\xd1\xb3\x90\xed\x96\xe4\x03\x6a\xcd\x30\x4e\x0c\x7c\xef\x9d\x43\x1f\x88\x21\x8a\xa1\xf8\x38\x28\xdd\xa6\x36\xb9\x4a\xa7\x61\xc7\x31\x7e\xcf\x11\x6c\xbf\xc6\x11\xe5\xba\x6d\x94\xc5\x0e\x99\x46\x93\x02\x3b\xdf\x2d\x24\x8e\xd6\x03\xf8\x5b\xe7\x3a\x00\x08\xb7\x5a\xde\xf9\x51\xdc\xcf\xa3\x0e\x42\xe9\xf5\xbb\x05\x02\x3a\xde\x79\x75\x06\xcb\xf9\x0b\xb6\xdc\xe4\x3c\xf3\xa1\xc3\x14\x1a\x5c\xc5\xfd\x9a\x4f\x3c\xc5\x57\xb9\x0e\x18\x04\x9b\x3c\x13\x0f\x46\x1e\x4f\x32\x29\x9f\xa1\xd1\xcf\x9c\x7f\x2e\xa2\x05\x35\x65\xe8\x16\x0a\x34\x1c\xdd\xf9\x9a\xcd\xdd\x49\x16\x97\xfa\x70\x51\x24\xab\xda\xb4\x2a\x5e\x8f\xcf\x04\x8d\xd9\xf1\x79\x38\x4e\xc9\x2a\x46\x9a\xeb\x11\xe8\xbc\x62\xb6\x9d\xbc\xfc\xec\x66\x81\x75\x47\x57\xe4\xc5\xd0\xfd\xd9\xb9\xcf\xda\x49\xaf\x09\xb8\x3a\x5a\x4a\x10\xae\xd9\xa4\xcf\x7d\xdf\xa2\x89\x20\x9d\x47\x5a\xb3\x31\x8c\xd4\xb9\x65\xe0\x07\xdc\xe1"}, -{{0xe5,0x5f,0x22,0x0f,0xff,0x80,0x79,0x14,0x8b,0x25,0x41,0x89,0xbb,0x29,0x41,0x74,0xf8,0xe2,0xc5,0x75,0xe5,0x7f,0x39,0xd4,0xba,0xc8,0x16,0x5c,0x5e,0x56,0xe7,0x69,},{0x7f,0xd5,0x07,0xd0,0x3f,0xe1,0xd6,0xe3,0xf9,0x11,0xf0,0x59,0x59,0x7b,0x0e,0x29,0x2e,0xa0,0x96,0xf5,0xbc,0x85,0x18,0x52,0x91,0x6b,0xf1,0x21,0x7c,0xaf,0xdc,0x6c,},{0xc1,0x02,0x3a,0x70,0x68,0x74,0x3e,0xc4,0x66,0x8f,0x49,0x5e,0xb7,0xbd,0x4d,0xb5,0x81,0x29,0xc1,0x1e,0x58,0x29,0x9e,0xa8,0x7d,0x6f,0xac,0xd3,0x02,0xbf,0x29,0x6a,0x98,0xe2,0x98,0xfd,0xb4,0x8e,0xdd,0xf9,0xc4,0x4e,0x79,0xae,0x86,0x41,0xf7,0x34,0x50,0x3b,0xb8,0x3d,0xc0,0xb3,0x1f,0x61,0x0d,0xf1,0xd1,0xe9,0xd6,0x19,0xa7,0x05,},"\x1e\x2c\xe8\xbf\x0e\xa7\x87\x5d\xf2\x85\xb1\xdb\xd3\x4b\xbe\x67\x30\x7f\x2e\x8a\xc8\xbc\x14\x2c\x3b\xa3\x14\xc1\x64\x2c\x65\xa2\xd6\x2e\xb2\xc7\x83\xf9\x16\x28\x3c\xa4\xec\x3e\x53\x6d\x3e\xeb\x65\xcf\xdc\xc0\x54\x9a\xc4\xf6\xa4\x5f\x53\x9a\xc5\xdf\x79\xa6\xd5\x76\x82\x19\x73\x9d\x0c\x9a\x0c\xdb\xb3\x12\x42\x29\x6c\x33\x12\xb7\xed\x56\x00\x43\xf5\x36\xcd\x1d\xe9\xa9\xc2\xb2\x89\x64\x1a\x1c\x2d\x84\xf9\xa6\x8b\x7c\x03\xb8\xb8\x56\x7e\x5d\xc7\x13\x8c\x2c\xb9\x67\xc6\x28\xaa\x25\xb2\xea\xb4\x34\xd4\x49\x0b\x23\x50\x74\x09\x71\x7c\xde\x94\xda\x59\xdc\x1d\xc2\x5c\x7b\xe4\x2a\x8a\xa0\x2e\xdc\xf4\xd9\x95\x36\x8e\x6b\xa0\xee\x1f\x95\x36\x00\xdb\x98\xd2\x2d\xe0\xf8\xd2\x57\x02\x0e\x0a\x40\x6e\xe1\x66\x9b\xd5\x27\xb9\xfe\x1c\x61\x1f\x9b\xe5\xa3\xd7\x52\x8e\x8b\x61\x51\x67\x0a\x86\x63\xd2\xed\x1a\x58\xd3\xe3\x69\xbb\x72\x2a\x63\x02\xd7\xc1\x72\xa1\x9b\xda\xf3\x57\xee\xdb\x02\x27\x91\x56\xe3\xb9\x03\x44\x31\xa7\xd6\x8a\x39\x52\x8e\xb4\x02\x35\x87\x57\x3e\xb8\x8f\x30\xf9\x4e\x83\x3e\x8a\x23\xb9\xd0\xac\x7b\x5c\xa8\x78\x24\x59\x6b\xbb\x0a\x3d\x0c\xa1\xb1\x6a\x68\x78\xfd\xf7\xe2\xce\xa3\x4a\x6f\xfb\x95\xa9\xff\x4e\x88\x8a\x97\x59\x37\x35\xb8\x68\xda\x75\xd8\x70\x7b\xbf\xdb\x1d\x93\xeb\x86\xa5\x1e\x2d\x21\x5f\x1d\xd9\xdc\xf7\x83\x88\x72\x9a\x3e\xb0\xf0\x66\xdd\xc9\x41\xe9\x50\xc9\x21\x27\x19\x8b\xce\x63\xa5\x48\x68\xd9\x97\x02\x95\x72\xff\xa6\xf6\xfe\xa1\xd3\xa6\x91\x64\xc9\x99\x69\x53\xdc\x8b\x6f\x9d\xad\x06\x35\xc9\xb0\x81\xf5\x5f\x98\x33\x40\xf0\x81\x4b\xf5\x47\x08\x03\x09\x0e\x79\x97\xf7\xab\x79\x6c\x2b\x15\xad\xaf\x40\x21\xd6\x7c\xff\xaf\x6e\x1e\xf6\x28\x67\x50\x39\x45\xc2\x1a\x32\x96\x64\xe0\x8a\x95\xa4\x15\x82\x30\x0d\xa9\xbe\xd2\x08\x44\x4c\xe6\xaa\x12\xb3\xf8\x67\x79\x5c\x6e\xe4\xc4\xc9\x25\x70\x18\x62\x73\x61\x29\x3b\xd5\x27\x82\x1a\x29\xa3\x39\xb4\x04\xa2\xda\x4b\xd9\x94\x4f\x87\x70\x40\x79\x8b\xb5\x4a\xbd\x2d\x76\xcb\xb1\x8d\xf4\x29\x7f\x4c\xe3\x33\x7f\x64\xd2\x05\x80\xaa\x64\xbd\xec\xac\x37\x6a\x6a\x4f\xf7\x4d\x01\x44\xb2\xfe\x74\xce\xf8\x2d\x50\xa5\xe6\xbd\xd7\x99\xe5\x5f\xf6\x96\x62\xba\xc5\x37\xad\xcb\x68\x81\x22\x8c\xb6\x37\x04\x50\x0c\x14\x3a\x4f\x4d\x1d\xb2\x8d\x45\x56\xbe\xe6\x04\xa3\x99\xff\xd2\x06\x54\x65\x97\xde\xe9\x22\x52\x54\x7f\x6c\x65\x7f\x36\x84\x1a\x87\xd5\x65\xf6\x55\x27\x16\xc2\x5a\x21\x15\x14\x77\xbe\xe9\xef\x96\x18\x55\xfb\x1a\xf2\xda\x80\x68\xf2\x8c\xe9\xff\x70\xd5\x25\x2c\x7a\x63\xa2\xe1\x4d\xed\x6b\x89\x77\xb1\xd7\x69\x1a\x77\xed\x2e\x57\xd2\x2f\xf2\xe1\xfc\x4c\xdb\xce\xb5\xe8\x05\x85\x8d\x90\x38\x96\xea\x67\x07\xe4\x8b\x34\x5f\x60\xe2\x81\x8b\x2f\xce\xc4\xdb\xa4\x8c\xae\xa9\xef\xa3\x82\x79\xfb\x83\xd5\xb0\xf4\x6a\x45\xe4\x2c\x41\x76\x5d\x01\x71\xba\xac\xd8\xd6\xdd\xa7\x99\x13\x14\xb3\x4e\x15\xfd\x36\x12\x7c\x46\x7d\x1d\xe0\x1c\x01\xa3\xa7\x8a\x8c\x1b\x10\x3b\xee\x17\xa7\xa0\xb7\xac\x55\x76\xfd\xc2\x26\xdd\x24\x59\x77\x31\x46\xcf\x38\x26\x14\x17\xca\x19\x13\x5d\xbd\xa9\xbd\xbe\x54\xcd\x17\xaa\x7d\xdd\x38\xfd\xca\xc2\xab\xa3\x96\xb3\x65\xce\xae\x98\x91\x9f\x6c\x51\x77\xfc\x58\x3f\x5b\xee\x3f\x48\x70\x49\x14\x30\x6a\xa1\x9e\xe9\x0e\x3f\xd0\xde\x55\x91\xc6\x69\xff\x35\xab\x16\xfe\xf3\x8d\xee\x18\x7b\xae\x1e\x5a\xaa\x56\x6d\xf1\x05\x44\xb7\xd6\xd4\xeb\x00\xda\x7e\xbe\xb4\xec\xdc\xc4\xd8\xe3\x2b\x49\xcb\xbd\xc6\xe6\x66\x40\xbd\xb0\xf7\x2e\x05\x91\x8a\x05\xc3\x5d\x9b\xff\x7e\x0e\x88\xf2\x41\xd7\xc6\xc8\xcb\x2f\xed\xcc\xdf\x65\x56\x0a\xf0\xe7\x83\x3e\xfe\x34\xaf\x79\x0d\xb6\x31\x89\x02\x2c\xfd\x71\xfc\x8a\xcf\x88\x86\x01\x27\xbd\x4f\xbf\x02\x6b\xcb\xe3\x60\xe3\x3a\x89\x95\xe6\x36\xd0\x3b\xb8\x6d\xfd\x01\x98\xad\xa9\x59\x34\x2d\x8e\x9c\x9e\xd9\x3e\x23\x29\x7d\xa9\x8d\x66\xa0\xd4\xfc\x96\x51\x62\x73\x3b\xc8\x65\x41\xb9\x5a\x6c\x90\x97\xcb\x55\xa9\x73\xc6\xfa\xc1\x94\xe8\xf8\xa1\x64\x27\x4c\x47\x9c\x51\x0e\x62\xd8\xa0\x35\xeb\x75\x11\x81\xb5\x02\xaf\xb6\x14\xd8\xc4\x46\x7b\x54\x45\xc2\x68\xdc\x3d\xd0\xab\xbd\x57\x70\x04\xc0\xbc\x47\xb1\x5f\xcb\x80\x1b\x79\x35\x97\x57\xb5\xea\x89\xcf\x8c\xf7\x7f\xc6\xd1\x60\xe6\xcd\x73\xc4"}, -{{0xd5,0xe3,0xa4,0x06,0x71,0xbd,0x45,0xf0,0x88,0x42,0xdd,0xc7,0x8a,0xbe,0x57,0xde,0x3b,0x9c,0xe5,0x64,0x6b,0x73,0x0d,0x2e,0x59,0xfe,0xcf,0x5a,0x7d,0xf8,0x0f,0x40,},{0x41,0x6c,0x37,0xae,0x1a,0xd1,0x5b,0x63,0x2b,0x0e,0xa4,0x39,0x32,0xc1,0x76,0x37,0x28,0x2c,0xd9,0x1d,0x59,0x79,0x55,0x2e,0x5e,0xeb,0xb9,0x9a,0x41,0x9d,0x5c,0x97,},{0x63,0xde,0x6a,0x98,0x11,0x42,0x36,0x5a,0x3e,0x59,0x26,0x31,0xc8,0x27,0x72,0x37,0x80,0x97,0x39,0xd1,0xc9,0x8f,0x5a,0x1c,0xb2,0xcc,0xcd,0x34,0x06,0x7d,0x1c,0xa5,0xdc,0x8f,0x2f,0xc6,0x3b,0x8a,0xe1,0xa6,0x89,0xdc,0xaa,0x29,0x1b,0xa6,0xb6,0x9b,0x1a,0x67,0x95,0xc5,0x79,0xa5,0xdb,0x6d,0xcc,0xee,0x73,0xf6,0xa4,0x20,0xac,0x0a,},"\x09\xfe\x6f\xfa\x8b\xf0\x94\x2a\x64\x92\x13\x57\x65\x9d\xbc\x6e\x4f\x8b\x63\xca\x3b\x9e\xa4\x75\xea\x39\xd7\x92\x52\x90\xa1\x48\xd8\x7b\xb1\x55\x74\x1d\xfa\x28\xae\x1b\xea\xdc\x1f\x3e\x1a\xb7\x67\x37\xeb\x5d\x5d\xda\xde\xd0\xbb\x38\x2d\x7e\x11\xea\x81\xa5\xe7\x80\x16\x12\x69\x62\x60\xba\x3b\xd0\x9c\x80\xb6\x23\xf6\x36\x38\x0a\xa0\x20\x8f\xee\x0a\xff\x70\x81\x2d\x53\x07\xb2\x71\x83\x83\x23\x43\xde\xba\xa3\x60\x5d\xda\xd1\x7d\xdd\x70\xd6\x11\x40\x0d\xdd\x10\xd6\x38\xaa\x3d\x6c\x68\xa2\x8c\xf0\xe9\x7c\x1d\xed\xf6\xcc\xd9\xc7\x31\xa8\x4f\xf0\x40\x5a\x3a\x22\xdc\xba\x00\xab\x44\xd5\xb2\x18\x44\xf1\x4d\x13\x74\xac\x0c\xb1\xe5\x8d\xf4\xa9\x0c\x41\x25\x63\xcf\xe6\x9d\x88\x2d\x35\x0f\x6a\xaf\xbf\xa6\x4f\xa2\xf9\xff\x82\x60\x32\x32\x67\x80\xae\xcf\x93\x05\xd8\x21\x7c\x17\x9d\xbb\x63\xc1\x51\x54\x12\x32\xeb\x65\x97\x92\x65\xd8\x76\xc4\xbc\x43\x05\xc0\x2f\x40\xbc\x1d\x05\xdb\xaf\x7d\xcf\x4f\x7d\xd9\x23\x2c\x17\xee\x0f\x7a\x05\x55\xf5\x04\xba\x37\x74\x54\x84\x88\x93\x3e\x75\x71\xeb\x3f\x71\xc4\xcb\xb2\x0c\xc4\xe4\xa7\x32\x2f\x35\xac\x0e\x79\xa5\x91\x55\x79\x8d\xd0\xf5\xb3\xc1\x13\x19\xb7\xd8\xf3\xea\x79\xee\x3a\xcc\x68\xbd\xb9\xf3\x7c\x7d\x4c\x8f\x9c\xab\xa1\xeb\xf8\xeb\x7f\x43\xb4\x62\xae\xfd\x38\xe8\xc0\xd4\xc6\x39\x79\xcf\x66\x31\xde\xc3\x1a\xb5\xce\xd3\x93\x7e\xf5\xb2\x36\x2c\xb0\x9c\x71\xdd\x09\x66\x57\x70\x0f\xd9\x6b\xda\x55\x5e\x22\x71\x2f\x71\xae\xc1\x1a\xe5\xe9\x1b\x24\xbd\x16\x49\x49\x8b\x8d\x9f\x86\x7f\xb6\xc4\x1e\x07\x60\x80\xf7\x40\xd0\x74\xc2\xa2\x55\x72\xd3\x4e\x66\x6b\x63\x67\xbf\x7c\xbb\x3d\xd4\x2a\x23\x82\xdc\x19\x73\x96\x12\x68\x60\x53\x96\x81\x0a\x45\x6a\xc0\x81\xbb\xfd\x3a\x54\xb4\x48\x81\xfc\xfc\x45\xb4\x24\x5e\xe7\x24\x65\xb4\x87\xd0\x7f\x2e\xf3\xf7\x4a\xdd\x71\xcd\xfd\xd1\x6e\x92\xfe\x25\x7d\x33\x46\x45\xb0\xa9\xbc\x7d\x07\x26\x13\xfb\x9c\x0c\xde\xa9\xdb\x4c\x72\xbc\x87\x10\x9e\x10\x2d\x7c\xba\xf3\x66\xec\xd6\x7f\xbe\x3d\xed\x32\x74\x73\x07\xa7\xae\xef\x61\x73\x5a\xd3\xaa\x5c\xe9\x5d\xee\xcc\x16\xa1\x6e\xb2\xa0\xbc\xc7\xad\xc0\xa1\x1d\x88\x80\x32\x26\x0e\x7c\x7e\xc9\xe5\x4f\x5a\x25\x31\x70\x2a\x7e\x5d\xfb\x87\xc3\x6c\xe3\x13\xa3\x14\x75\x88\xae\xf9\x62\xc7\x2f\xa9\x66\xd2\x41\x63\x7c\x38\x8b\x83\xdd\xec\x93\x43\xbb\x86\x34\x3e\x92\x0b\x12\xce\x1c\xc9\x15\xc8\x3b\x31\xe9\x98\x62\x69\x06\x74\xea\x49\x35\xa4\x88\x09\xd4\xd2\x79\x05\x41\x37\x54\x63\x92\xad\x9f\x08\xe7\xb8\xde\x61\xae\x73\xe8\x1e\x48\x3d\x3c\x63\xb5\xae\x73\x4e\x18\xe7\xa2\x2f\xee\xd1\x23\x3d\x0c\xa6\x33\x55\xf3\xa4\x8a\x33\x06\x7e\x1a\x0e\x19\x71\xf3\x6a\xa9\x29\xfe\x06\x13\xc2\x1c\x4a\xef\xf9\x41\x84\x29\xc3\xb0\x72\xa5\x98\x49\x59\x28\x7a\x5e\x5c\x40\xbe\x02\xbd\x22\xb9\xa7\x9c\x7f\x3f\x53\x59\xd2\xbb\xe4\x93\xf5\x56\xda\xcb\xb0\xcb\x4c\x29\x3c\x7d\x94\x12\x65\xe7\x77\x39\x2d\x14\x8d\x68\xc0\x7a\x13\xc8\xde\xc8\xe5\xd1\xe1\xc7\xf0\x41\xe8\x98\x3e\xdd\xda\xa4\x64\x9d\xac\x15\x72\xa3\x9a\xe4\xc6\x48\x0c\xa5\x50\xe2\xe4\x46\x2d\xcc\x84\x9c\x1b\xab\x78\x1d\x28\xa3\x55\x2b\x2d\x98\xe0\x2e\x15\x18\xe6\x55\x53\x40\xfb\x76\xd6\x8d\xb5\x89\x16\xd5\x56\xa7\xb8\x15\x63\xab\xa8\x1d\x9a\x57\xae\x50\xf0\x4c\xf5\x68\x60\x21\x84\x7d\x79\xb6\xbb\x3d\xa8\x01\x7a\x60\xb1\xc3\xbe\xef\xd4\x8d\x2b\x3c\xd3\x9c\x6f\x53\xc0\x8b\xcc\x96\x7d\x93\x06\x9f\x56\x2b\xb3\x6e\x0c\x4f\x4c\xa6\xbc\xcc\x5e\x57\xd3\x59\x03\xcd\x80\x0a\x61\x78\x5a\x93\x77\x0e\x37\x7f\x4f\xe8\xe9\xf4\xb6\x66\x80\x98\x49\x68\xf9\x64\x9e\x10\x5e\x7a\x11\x9d\x97\x63\x6f\x3a\x05\xca\xea\xb1\xd7\xea\x0b\xc8\x13\x34\xb4\x2d\x5c\xc0\x80\x83\x0e\xc2\x4d\x36\x9c\xf8\x67\x3a\x49\x0d\x59\xeb\x4c\xb0\x81\x81\xda\x39\xa4\x6d\x96\x6e\x23\xfe\xd8\xd3\x8a\x5f\xab\xc7\xe8\x43\xbc\xfb\x01\x5a\x44\x74\xbf\xd4\x6d\x4a\x43\xff\x4a\x51\xa9\x56\x76\x61\xe2\x69\x6d\xb8\x7c\x37\x58\xd3\xb5\x4c\xe7\x84\x6d\x13\x91\xd7\xf4\x65\x26\xef\x30\x84\x4d\x49\x32\x00\x18\xd7\x49\xb5\xd4\xdf\xd3\x0d\x38\x0c\x6e\x57\x3f\xc4\x14\xd8\xfe\xfc\x5d\x71\x04\x70\x75\x6b\xec\x00\xd8\x8a\xc4\xaf\xc9\x25\xd1\xed\xe3\x7e\xae\xe6\x00\x4a\x23\xea\x0e\xf8\xb6\x0e\x48"}, -{{0x4e,0xd7,0x04,0x8a,0xa1,0x28,0x4d,0xbb,0xcc,0x24,0x89,0x38,0xb4,0x0c,0x35,0x74,0x21,0x93,0x59,0x7a,0xdd,0xaf,0xdd,0xe0,0x64,0x13,0xb8,0xd4,0xcc,0xfb,0xe1,0x37,},{0xbf,0x84,0x1f,0xe4,0x44,0xad,0xd1,0xf7,0xc3,0xea,0xcd,0xfd,0x07,0x84,0xb4,0xe8,0x55,0xd2,0x40,0x5f,0x40,0x21,0xcd,0x9d,0x82,0x66,0x07,0x1c,0x32,0xc8,0xa2,0x73,},{0x10,0x6a,0x9d,0xeb,0x23,0x27,0xf3,0x38,0xcc,0xb7,0x1b,0xcc,0x94,0xe2,0xfe,0x3d,0x2e,0x97,0x3c,0xe6,0xdd,0x8f,0xa7,0xba,0xca,0x80,0x8b,0x41,0x11,0x81,0x3e,0x3b,0xc3,0xb4,0xd8,0x8e,0xfa,0x6a,0x00,0xc4,0x71,0x0b,0xbf,0xe5,0x31,0x96,0xf9,0xab,0x3a,0x15,0x0b,0x16,0x54,0xb9,0x08,0xfe,0xac,0xf9,0xc1,0x3d,0xf2,0xd6,0x38,0x02,},"\xdc\xff\x95\x87\xd6\x04\x6c\x11\x32\xbe\x07\xdf\x26\xdf\x63\x82\xff\x92\xcf\xc8\xeb\x53\x45\xc5\x1d\xd5\x0d\xd1\x88\xee\x76\x9f\x10\xa4\xde\x5e\x88\x83\xd1\x16\x96\x7b\xea\x97\xd3\xb3\x2b\xc8\xae\xbb\x9f\x01\x3d\x6d\xf9\x52\xf2\x51\xc1\xa3\x12\x34\x6e\x72\xce\xe1\x35\xa1\xbf\xd7\x6b\xf3\x08\x0a\x35\xc8\x38\xb4\x4d\x75\x5f\x26\x3d\x21\x03\x10\xfa\x8d\x28\xc4\xca\x52\xf0\x8c\xac\x5b\x83\xa8\xa3\xb1\xdf\xc4\x6d\x9b\x75\x2d\x9f\xc7\x36\x49\xd0\x0b\xb9\xee\x99\x26\x50\x63\x9c\x22\x5d\xea\xc1\xf3\x9b\x9e\x80\x36\x89\xd1\x9e\x6d\x9f\x8e\xf4\xf5\x1f\x1d\x11\x60\x1f\xac\xf4\x10\xdb\x64\x8b\xcc\x82\xbf\x64\x87\x69\xa7\xdd\x59\xc6\xe8\xa2\x37\xdb\x23\x9d\x3f\x66\x1d\x78\x52\xc4\x26\xd3\x94\xa9\x05\x09\x52\x6a\x85\x9b\x47\x64\x59\xde\xdb\xe6\xd8\x99\x36\xc0\xf3\x98\x99\x95\x51\x1d\x4a\x57\x6e\x54\x2c\xce\x5e\x0d\xd7\xee\xef\xeb\x03\x26\xd3\x3f\x25\xc2\x2a\xb6\xe7\x69\x06\x33\xf4\xc9\xed\x2a\xad\xf1\xd2\x4f\x94\x86\x21\x23\xa4\x64\x04\x2c\xea\x19\x3a\x2f\x04\x79\xd3\x9b\xcd\x1b\xbd\x1c\x7a\x0c\xa7\xe6\x25\x8e\xd3\x73\x23\x72\xf5\x4e\x0e\xd5\xe3\xf1\xe2\xe4\xd4\xa0\x4c\x51\x0b\xee\x08\xd1\xc6\xd5\x70\xcf\xd6\x3a\xbf\x14\xb4\xee\xf0\xb9\x6f\x39\xca\x29\xe4\x3c\x52\xf2\xca\x3d\xfd\x46\x0f\x66\xe3\x02\x35\xb1\x59\xaa\xef\x2c\xc1\x56\x01\x29\x69\xfd\x3d\x15\x99\x78\xd6\xca\xa0\xa9\x45\x22\x29\x1f\x79\x89\xd8\xaf\x10\x83\x19\x96\x13\x7b\x68\xd9\x7f\xc1\x7f\x6a\x9b\xc2\x84\x5e\xf3\xdd\x47\xcb\xc3\x86\xe8\x97\x7a\x86\x54\x36\x34\x12\xda\xc3\xac\x51\xc6\x38\x17\xb7\xc0\x51\x87\x8d\xcf\x45\x8a\xb3\x63\x0d\xd7\xae\xf6\x8d\x27\x0f\x8d\xa7\x88\x0a\x46\x7b\x33\x04\xf5\xba\xed\xfb\xa9\x17\x3e\x7e\xfd\x00\x7c\x41\x2d\x17\x20\x9c\x56\xd2\x39\x68\xe3\x40\xb8\xa0\xed\xb4\x1b\x7e\x2a\x40\x88\xbe\xc0\x1b\x53\x2d\xf8\x9b\x52\x15\x81\x31\x31\x10\x7b\x7b\x47\x4f\x03\xc2\xe4\x7d\x43\x17\xf1\x1c\x4f\x51\x60\x90\x43\x04\x99\x7e\x76\xa1\x21\xa9\x56\x02\x35\x20\x8d\x79\xb2\xda\xb4\xf7\xe1\x96\x79\x32\x02\xc0\x90\x2c\xe9\xc4\xbf\xc1\x0b\x8f\xe3\x97\xe3\x5c\xa0\x25\x64\x54\x66\x2a\xe8\x78\xef\xb0\xa0\xa6\x06\xfa\xc0\xa9\x52\xc9\xf6\xba\xae\xb2\xd4\x5b\x25\x8c\x61\x75\x59\xc0\xed\x25\x28\xa8\x8b\x49\xaa\x44\xee\x43\x03\x5b\x0d\x79\x3a\xad\x39\x53\xc1\xa5\xa3\x46\x38\x66\xbc\x81\x5b\x1f\xfc\xe2\xff\x2b\x65\xe0\xfd\x47\xdb\xc1\x5f\x4e\x7a\x06\xbf\xab\xc2\x90\xfc\x62\x09\x0b\xf7\xd9\x48\x53\xf7\x7c\x04\x44\xa9\xb9\x0e\xfe\x77\xd1\xce\xb4\xbd\x39\xe2\x03\xbc\x88\x40\x11\x62\x4e\x68\x46\xe2\xa3\x71\x05\x8d\xab\xa6\x3c\x23\xf8\x6c\x42\xc3\xe3\x1e\xaa\x4b\xd7\xd7\xa4\x2a\xf2\xd5\x24\x89\x6e\x31\xba\xa3\xe2\x07\x63\xf8\x5d\xcf\xd5\x27\x75\xf2\x80\x72\xd8\x9f\x0b\xd4\xfa\xe3\x0d\x0b\x13\x7e\xe3\x7a\xb0\x63\xba\x06\xfe\x9d\x4e\xc6\x2a\xbb\x2f\xea\x0f\x81\xb8\xcb\xee\xfc\x03\x00\x80\xb8\x02\x6a\x58\xfd\x18\x67\xf6\x6b\xe1\x15\x4e\x65\xbf\xea\x7d\xce\xc5\x5f\xe3\x2d\x51\xfb\x0b\x4a\x8a\x5a\x8a\x04\x42\x63\x94\x3d\x6a\xc8\x01\x1c\x6e\x67\x01\xbe\xec\x3a\x88\x65\x58\x40\xc4\x89\x2d\x45\x0d\x31\x2b\x76\x52\xd2\x51\x47\x69\xf2\x3b\xfd\x6e\x70\x46\x46\x7d\xf2\x9a\x28\x7f\xf3\xc4\xc9\xd0\xe6\x4e\x6d\x9e\x4e\xde\xe1\xb9\x35\xd0\x76\x81\xd4\x70\x04\x35\x28\x86\xe8\x47\xb0\xc6\xd5\x76\x2f\xd4\x5a\x81\xa5\x3c\xce\x94\x76\xc8\x87\x22\x1a\xea\x6c\x0c\x82\xbb\xf3\xb2\x97\x93\x2e\x5b\x11\xe5\x38\xa3\x24\x5d\x63\xd7\xb7\xb0\x91\xdf\xa1\xd7\xb9\xa0\xe2\xdb\x66\x98\xa4\xc5\xe9\xfe\x93\x16\x62\xd7\xc6\xec\x6d\x9d\x5b\x92\xbc\x7e\x04\x15\x55\xdf\x4d\xf0\xca\x11\xca\xbc\x48\x5f\x9c\x55\x61\x38\xa7\x17\x45\xf0\x3b\x97\x83\xbb\x20\x0b\x72\xd2\x33\x69\x7e\x8b\xcf\x6b\x41\x17\xee\x67\x63\xd7\x92\xd7\x42\x22\x64\x85\x2f\x4f\x30\xf8\xd1\x89\x0e\x2e\xa0\x80\x98\x04\x0f\x7f\x28\x8e\x4a\xbe\x90\xb6\x3c\xab\x2c\x14\x37\x30\x60\x84\x0e\xf8\x27\xec\xc8\x46\xcd\x56\x0e\x90\xa2\x0b\x83\x05\xf4\x63\xc3\x6e\xa0\x38\x84\xa5\xdf\x4c\x25\xf1\xba\x9e\xa1\x25\x95\x2d\xc0\x91\xb9\x75\x16\xde\x1d\x28\x7c\x0e\x2b\xf5\x29\x77\x5b\xa6\xd2\xf8\xed\xe0\x3c\xb4\x2c\x1e\x40\x0e\xc8\x04\xa9\xdf\x08\xe4\x6f\x44\xb5\x06\x63\x46\xe3\xf7\xc7\xa1\xa8"}, -{{0xc7,0xec,0xa8,0x3e,0x94,0x85,0x76,0xbd,0x9f,0x27,0x8f,0xd7,0xb8,0x28,0x00,0xa4,0x1d,0x92,0xda,0x9b,0x72,0xd5,0xa1,0xcc,0xdb,0xbc,0x65,0x58,0x10,0x52,0x56,0x8b,},{0x07,0x6b,0x83,0x52,0xdc,0xa8,0x03,0x1e,0x85,0x3c,0x8d,0x90,0x99,0xc2,0xef,0x57,0x93,0x37,0xcc,0x7b,0x2b,0x4c,0x75,0xd1,0xa0,0x63,0xea,0x3e,0xc7,0x25,0xb7,0xfd,},{0x86,0x99,0x6a,0x1b,0x8e,0x49,0x5d,0x42,0x52,0x77,0xe9,0x7c,0xc0,0x83,0x05,0x49,0x34,0x9b,0xc2,0xb6,0xf3,0xdc,0xda,0x60,0xf3,0xb7,0xd3,0x50,0x1b,0x8b,0x50,0xb5,0xb4,0x58,0xcd,0xa5,0x8b,0x43,0x6e,0x23,0xc0,0x2c,0xd4,0xa2,0x2b,0x23,0x48,0x13,0xaa,0x9b,0xcc,0x3c,0x61,0xf9,0x83,0xc0,0xb7,0xef,0xec,0xa0,0xf1,0xbe,0xc2,0x0d,},"\x8d\x8c\xef\xd6\x73\x85\x5c\xcd\x8e\xb8\x53\x4c\x31\x2d\x33\x80\x05\xbb\x05\xf5\xb9\x50\x7d\x58\x85\x9e\x1e\x95\x3b\x0a\x4d\x91\x3b\xe7\x59\xd8\xed\xfa\x92\x89\x8c\x6e\x70\xa5\x3f\x81\x95\x4f\xc3\x44\xb4\xad\x62\x46\xb0\x10\x94\x81\xba\x6f\x73\xae\x63\x31\xab\xf2\xdf\x10\x8e\xb2\xe8\x5c\xeb\x08\x7c\x1f\x6f\xcf\xc9\xde\x2c\x1f\x13\x9b\xa1\x77\x1b\x72\x68\x03\x02\xd8\x11\xcc\xd0\xcc\xd4\xe0\xc7\xfe\xb0\x13\x2e\xb2\x0b\x33\x4e\x5a\xab\xe5\xf6\x11\x9f\xd8\x94\x7d\x9e\x88\x52\xe1\xeb\x1b\x74\x10\x7e\x17\x41\x00\xe3\xe6\xdf\x0c\x3a\x68\x13\x0c\xa6\x30\x94\x02\x59\x4b\xb5\x0c\x1c\x8e\x27\x74\xf1\x32\x14\x49\x6a\x7b\x1f\x34\x83\x85\xea\xbf\xbc\xcb\xac\x16\x5a\x5a\x2e\x7d\x9d\xea\x5f\xfd\x58\xb0\xbd\x88\xb4\x9c\xb3\x31\xec\xb7\xf4\xe9\xd6\xba\xe9\x79\x1a\xd7\x88\xe6\xab\x89\x26\xc1\xcc\x16\x15\xde\xaf\x4c\xc4\x00\xc7\x7a\x31\x61\x97\xbc\xa1\x90\x49\x95\xe1\x36\x5d\x1b\x97\x02\x64\x83\x76\x11\x69\x30\xf6\xf9\x11\x66\xe6\x14\x86\x29\xe7\x5b\xe2\xd0\x68\x95\xf6\xa8\xd1\x5d\x5a\x94\xca\x69\xb7\x12\xf3\x3b\xcf\x95\xbe\x0c\x1b\xe6\x90\x2b\xb7\x8b\x8a\x23\x0d\x7a\x85\x60\xc4\xd8\x4e\x23\x89\x55\x2a\x81\x57\x1a\xa6\x65\xc1\x9c\x2e\x93\xb0\xd4\x3e\x8c\x2c\xbd\x9e\x88\x5d\x70\x52\x51\x8b\x77\xc4\x7e\x84\x1d\x11\x9d\xc2\x8b\x65\xa7\x50\x4f\x66\x42\x71\xf0\x6c\x7f\xf3\x93\xf8\x25\xb1\xe5\x93\x0d\x02\xb9\xc7\x00\x35\xe2\x92\x41\x1c\x4a\xed\xf6\x60\x47\x00\x69\x70\xe3\x49\xdf\xca\x7f\xb4\x1c\x10\xfd\x53\x7e\x35\x25\x2e\x10\x9e\x33\x36\xd7\xa8\x2a\x14\xde\x5d\x55\x40\xc6\xfc\x65\x71\xd5\x77\x4f\x39\xb7\xc4\x03\xe7\xb8\x87\x5e\xc2\x15\x87\x7e\xfc\x6c\xc8\xea\x48\xb1\x86\xb4\x68\x21\xea\x5e\xf2\xba\x8b\xac\xd4\x0d\x79\x7e\x6a\xdd\x06\x41\x32\x83\x14\x5b\x60\x46\x2b\x35\x03\xc5\xb8\x81\xd7\x9a\x59\x29\x55\xd1\x8a\xfa\x08\x96\x9e\x31\x45\x7f\x5b\x27\xda\xec\x01\x03\x38\xed\x86\x7f\x30\x08\x78\xfd\x87\xce\x32\x18\x80\xb8\x60\xa0\xc6\x42\x84\xca\x2d\xc1\x5f\x5e\x53\x10\xe1\x0e\x6a\x73\xa7\xea\x65\x0e\xa9\xd3\x73\x69\x4d\xa4\xdd\x42\x9a\xe7\x41\x2e\xf9\xb2\x9c\x83\xb3\xb0\x68\xc7\x47\x69\xf4\x31\xce\x06\x15\xf9\xff\x4f\x82\xba\xac\x47\xb4\xbc\xe9\x04\x49\xec\x41\xc2\xa2\xd5\x73\xd9\x2b\x92\xe0\x56\x31\x48\x61\x65\xbc\x71\x0e\xf5\x84\x0f\x80\xda\xe9\xf9\xdd\x5c\xff\xd4\xeb\xf5\xd1\x07\x46\x51\x0c\x5f\xcb\xfe\x62\xcb\x97\x03\xc0\xb1\x54\xc8\x6f\x10\x81\x66\x72\x49\x76\x70\xa3\xb0\x15\x0b\xb4\xe1\xb0\x3b\x3b\xd5\x44\xc1\x2a\x90\xc3\xed\xcc\xd7\x90\x0e\xbb\x5b\x31\xc9\x11\x17\xcc\x82\x81\xa3\xc4\xed\x04\x99\x8e\x99\xae\xd4\x1b\xb4\x1f\xce\x99\x90\xa4\x06\x48\x5b\x14\xdb\xe3\xbc\x1a\x5f\xcf\x77\x19\x50\x79\x90\xda\x3b\x0b\x3c\x68\xad\x40\xd8\x95\x0c\x0d\x49\xce\xd1\x01\x93\x19\xa3\xf3\x6a\xff\x6c\xaf\x75\xd7\xf9\xa0\x93\x3d\xd3\xab\xdd\x76\x92\xa1\x56\x2f\x06\x13\xfe\x4a\x27\x8d\x5c\xe4\xc8\xda\xfb\xb5\x5b\x2e\xc2\xaf\x2b\x24\xe8\x39\x6f\x58\x7b\x17\x0c\x9c\xa6\x54\x75\x08\xfa\xcd\xe7\x34\x90\xdf\xb0\x1e\xb6\x65\x7e\x3f\x4f\x27\x23\x04\xb7\x0b\xf0\x47\xa4\x3a\x2b\x58\xe5\x56\x8b\xc5\x2b\x2c\x8d\x4c\x03\x21\x9a\x5a\x8b\xd3\xdc\x06\x43\x18\x59\x13\xc0\xaf\x74\x11\xf8\x1b\x77\xbe\x2a\x9b\xfd\x5c\xb2\x69\x77\x11\x3d\x26\x58\xa9\x71\x92\xb4\x1c\xf6\xc7\x01\x1b\x0f\xf6\xa1\x1c\xbf\xf3\x50\x55\x46\x32\x2f\x0b\xef\x60\x97\xe4\x6b\x36\x49\x2b\x01\x6a\x45\x62\xe0\x92\xb6\x7c\x3f\xcc\xc7\x78\x0e\xa2\x74\xd9\x6d\x59\x58\x49\xf7\xe2\xa5\x6d\x79\xed\xcb\x32\xd7\x84\x04\x9f\xc1\x32\x4a\x5b\xee\xfc\x24\x19\x3a\x66\xe1\xca\xc4\xa1\x3a\x81\x1b\x90\x95\x83\xcc\x91\x0c\xf0\x8d\x4b\x10\x4d\xbd\xb8\xa6\xf2\xb2\x1f\xbc\x1d\xb1\x17\x5a\x1a\x23\x56\xa6\x3d\x3e\xea\x9d\xbb\x85\x37\xd2\xc6\x86\x27\x54\x3d\xf0\xd1\xf8\xfd\x8d\x57\xa1\x8b\x0d\xbd\x69\xb9\x20\xcb\x9b\x28\x6e\x3c\x07\xae\x44\xae\x2e\x1b\xee\xc0\x1c\xee\x6b\xa9\x88\xb5\xd1\xaf\xb9\x97\x90\xb1\xdd\x91\x06\x55\xc4\x3d\x7f\x2a\x3e\xd3\x75\x4b\xa4\x65\x16\xd2\x78\x70\x55\x59\xf5\x74\x16\x22\xa9\xab\xb5\xc8\xf2\x3f\xa9\x76\xa9\xd1\x46\x94\x8a\xde\x6b\xa6\x60\x8a\x35\xe4\xe0\xd3\x30\xe8\x2e\x96\xa2\xbe\x6c\x78\xad\x0c\xd4\xd8\x70\x4e\x57\xce\xa1\x46"}, -{{0x7b,0x46,0x9d,0xf9,0xc8,0xf7,0x84,0x89,0xab,0x47,0xcc,0x70,0xa8,0x85,0x03,0xf1,0xb8,0xf3,0xd9,0x29,0xc3,0x3f,0xea,0xb1,0xc5,0x03,0xf0,0x96,0x9a,0x3a,0xc3,0x7b,},{0xa8,0x14,0xc7,0xe3,0x73,0xd0,0x11,0x3b,0x90,0x62,0x4a,0x8a,0xb2,0xbc,0xa5,0xcf,0x53,0xbf,0x52,0x8e,0x39,0xfc,0x3d,0x36,0x7d,0xe1,0x54,0xb9,0x4b,0xb2,0x2f,0x1d,},{0x18,0xfa,0xf8,0x2d,0x08,0xe1,0x06,0x8e,0x9f,0x98,0x3d,0x81,0x2f,0x05,0xfd,0xb6,0x92,0x9d,0x27,0x23,0xdb,0x1f,0x77,0xc4,0x5a,0x74,0xbb,0x09,0xcf,0xf2,0x77,0x73,0xb5,0x4c,0xe8,0xf4,0x3b,0x30,0x15,0x41,0x91,0x12,0xe7,0x25,0xea,0x7a,0xcd,0xa4,0xb2,0x3b,0x81,0x20,0xe7,0xb0,0xcf,0x42,0x01,0x53,0xe5,0xb0,0x3d,0xd0,0x61,0x09,},"\x1c\x0f\xd7\x45\x0e\x29\x67\x5c\x93\x09\x16\x38\xc2\xac\x93\x3c\xa9\x97\x76\x6e\x38\x0e\xc3\x3a\x92\xb8\xa7\xe1\xa1\xed\x98\x21\xc7\x5f\xcc\xb5\xc5\xf3\x76\x0e\x76\xd0\xe8\x81\x03\x11\xdd\xc6\x24\xea\x87\x42\x13\x1c\x1c\x43\x08\xf4\x17\x8e\x04\xd0\x49\x60\x69\x3d\x84\x6c\x1f\x51\xd8\x77\x3b\x6d\xeb\x34\x43\xd8\x74\xb9\xe2\xde\x3b\x77\x78\x51\x85\x51\x8b\x2e\x9e\xe7\x36\xc6\x3a\x39\xc8\x21\x2c\xa8\x66\x9e\x16\x1d\x13\x1b\x1a\xb2\x26\x4f\xdd\x72\xdc\x56\x28\xb1\x1c\x06\xf2\xaf\x9f\x07\x89\x04\x7b\xdd\x4e\xbb\x5d\x55\x89\x9f\x74\xdc\x4e\x12\xe7\x97\x53\x63\xf6\x3a\x8d\xa7\x6b\x55\x85\xc1\x6b\xb6\xd5\x5b\x05\xfa\xde\x87\x13\xd1\x9c\xad\x1a\x21\x16\x40\x26\x26\x91\xaa\xc9\xb4\x37\xa9\xec\xf8\x9a\x92\x46\xec\xdb\xa1\xff\x0b\xea\x78\x49\x4c\xee\x15\x29\x62\x16\xea\x6b\xb8\x82\x47\x9d\x24\x37\xc9\x49\x4a\xc7\xfa\x4f\x30\x15\xd1\xd3\x14\x9d\x55\x64\xd7\xc1\x1a\x7e\x7b\x61\x4f\x7d\x3e\x9d\x45\x4f\x0a\x05\xb0\x40\xa1\xe0\x6f\xe7\x83\x7c\x2a\x9d\xa2\x79\x4d\x91\x8b\xff\xa9\xe6\x1a\x0c\x3f\x08\x9f\x6c\x9f\x7e\xea\xc5\x86\xe3\x4b\xf9\x44\x70\xd9\x13\xda\x41\x37\x1c\xac\xdf\xc7\xee\x8b\xd1\x13\x56\x55\x56\x69\x24\xea\xdf\x09\x6a\xc0\x30\xa6\x59\x02\xc1\x03\xb1\x72\xd1\x2e\x88\xf0\x53\xfc\x56\xee\x73\xf3\x18\x70\x81\x70\x83\xaf\xa8\x02\xf7\x66\x8b\x81\x5e\xe7\x90\xf7\xd4\x0b\x43\x7a\x2e\x6d\xb2\xf0\xfb\x26\x83\x6b\x4b\x23\x31\xeb\xa5\x55\x39\x61\x4c\x0f\xe1\x72\x40\x24\x2d\xd3\xaf\x73\x83\xbc\xff\x7d\x3f\x47\xd6\x54\x4b\x08\x72\x0c\x0a\x52\x44\x1f\x74\x11\x93\x5d\xd4\xa9\x52\xd3\x86\x51\xa8\x00\x05\xfa\x3e\xb0\xea\xec\xc7\x35\xd2\x90\xe8\xbd\x5e\x31\xb7\x40\x14\x0e\x13\x6b\x2c\x00\x25\x23\xd8\xeb\x2a\x0a\xb5\xbd\x68\x70\x02\xb3\xb9\x26\xf7\x5e\xb6\x90\xd1\xda\x73\xad\x23\x58\x92\xf3\xb2\x3a\x75\x6b\x60\x5a\x43\x7c\x00\xe0\x62\x13\x04\xe8\x10\xf9\x9e\x31\x4c\x4d\x63\xe3\x22\xd9\xb6\x98\x15\xf3\x82\xff\xa1\xec\x62\x80\xfc\x0e\x64\x1c\x8a\x6f\x6f\x7f\x61\x98\x5b\xd3\x56\x7e\x0f\x44\x0d\xe9\xf7\x62\x17\x15\xda\xcd\x07\x42\x8c\x00\x90\x15\x4d\x59\xce\x6d\xb4\x01\x69\xc6\x58\xac\x5b\xf4\x4b\x67\x67\x1f\xe1\x9e\x4b\x5b\x38\xaa\xd2\xd3\xd4\xe1\x90\xa5\x50\xaa\xd4\x18\x83\x52\xf7\x98\x1a\x6d\x88\x06\x25\x02\xdf\x86\x79\x13\x50\x39\x2d\x41\xce\xfa\xcb\x24\xe3\x7b\xc7\x00\xcb\x02\x91\x90\xc3\xb1\x82\x14\x77\xe1\x17\xd5\xa4\x62\xfb\x3e\x79\x13\x3b\x10\x73\x59\x89\x66\xf5\x2b\x63\x25\x6d\xbf\x32\x6a\xce\x14\xdb\x0c\x80\x05\x8c\xf0\x0d\x68\x9a\x0a\x58\x11\x1a\xf1\x69\x27\x44\xbf\x79\x1b\xcb\xb4\x27\xa3\x72\x24\x6e\x95\x01\xa8\x5c\xd5\x20\xc6\x1a\x1e\x59\xee\x18\x0e\x8c\x97\x19\x2f\x60\xfa\x5d\x3a\xb0\x5d\xf8\xd8\x55\x1c\x1a\xc6\xca\x0a\x9a\x01\x2f\xfe\xce\xb3\xc1\xf5\x21\x41\x1e\xdb\x65\x09\xbc\x27\x8a\x65\x1e\x12\x9e\x96\xb0\xad\xc7\xae\xd7\x07\x22\x1c\xae\xac\x22\x98\x84\x41\x3d\xaa\x10\x59\x5d\x22\xd1\xdb\x70\x82\x12\x5f\x4f\x96\x95\x00\xa1\xd4\x8d\xac\xda\xe8\x0f\x40\x29\xc1\x63\xdc\xd7\x9d\xdc\x64\x68\xfc\xda\x16\x37\xb8\x7d\xdc\xf2\xa3\xd9\xb4\xd2\x99\xa0\xe5\x39\x4d\xf9\x0e\xd0\x3b\x62\x13\x7b\xa6\x7b\x9f\xea\x8a\xe1\xf0\xd2\x2f\x91\xc6\x3a\x24\xb5\x93\x4f\x74\xc2\x65\xc4\x3f\x1b\x92\x3d\xb9\x80\xad\xfc\xee\x83\x13\xda\x52\x01\x76\x73\x0e\xf9\x73\x6b\x27\xe6\xba\x32\xd1\x7e\xa6\x9d\xca\xc6\xf4\xa0\x16\xed\xfe\x2d\xb5\xa5\xbb\x3b\x64\x93\x2f\x70\x11\xf1\xc4\x53\xbb\xe8\x8b\xba\xc8\xc7\x03\x5f\x93\xfe\x39\xb5\x81\xfc\xaa\x7a\xaf\x08\x2f\xbe\xd0\x04\xfd\x1f\xd5\xa4\xe2\xd9\xc1\x97\x16\x60\x4b\x19\xce\x19\x9e\x21\x69\xa7\xbe\x51\x8d\x5f\xad\xd2\xac\x31\xb9\x54\x78\x08\x2a\xc9\x13\x06\x00\x8d\xe4\xec\x0e\xf4\xc9\xf9\xd6\xf9\x6d\x2f\x66\xd6\x2f\xaf\xc2\x19\x40\x82\x80\x8a\xf0\xd6\x7b\x9f\xba\x0d\x18\x9b\x05\x5f\x06\x1c\xca\xc2\x4b\x27\x61\x0b\xfb\xd5\xa2\x23\x2d\xd6\xf3\xc8\x90\xa9\xb1\x26\x64\x71\xb3\x22\xe9\xe1\xbf\x97\x75\x7b\xef\x72\xab\xce\xe9\x3b\x05\x1f\xc9\x23\xcf\xd4\xe7\x23\xbe\x3e\x17\x14\x3f\x38\xee\xbb\x90\x0b\x5b\xbc\xf7\x30\x47\x32\xb9\xc0\xa1\xc5\xfc\x95\x09\xa6\x93\x58\x0a\xe7\x3a\x4c\xdf\xc5\xfb\xf2\x0c\xe8\x1e\xbc\x83\x5c\x6c\x90\x9d\x83\x11\x41\xb1\x94\xf6"}, -{{0xdf,0xec,0xde,0x7a,0x56,0xa1,0x8c,0x1f,0x19,0xd8,0x0a,0x19,0xa4,0xf1,0xda,0xdd,0xd0,0xbc,0xec,0xb0,0x1e,0xec,0xad,0x6d,0xfc,0xa0,0xf9,0x57,0xa9,0x14,0xed,0x7a,},{0xaf,0xba,0xa6,0xe7,0x3e,0x85,0xb0,0x2b,0x25,0xa4,0xb5,0x87,0xec,0xb8,0xc4,0xdf,0xb7,0x9a,0xa9,0x20,0x27,0x61,0xef,0xa8,0xd1,0xdf,0x2c,0xd0,0xaa,0x63,0x16,0xc4,},{0xb4,0xfd,0xe5,0x5b,0x91,0x6c,0xf6,0x00,0x68,0xf1,0x9b,0x25,0x35,0x1c,0x14,0x10,0xdc,0xf6,0x6b,0xfc,0x40,0xf9,0x6d,0x1b,0xa2,0x36,0x8b,0xc2,0xb9,0x11,0x5a,0xaa,0x5b,0x2d,0x1c,0xf0,0xe3,0xdf,0xca,0x02,0xac,0x90,0x2a,0x94,0x3e,0x24,0x89,0xa5,0x68,0x1b,0xba,0xfe,0xd3,0x9c,0x6e,0x33,0x21,0x1a,0x9c,0xb2,0xff,0x6e,0x54,0x09,},"\xae\x6e\x8f\xf6\x5c\xcd\xe6\xf2\x64\x84\x95\x08\x26\xb4\x36\x23\x05\x8a\x5e\xfe\x02\x0b\xb1\x9b\x7d\x8b\x4e\x25\x76\x8b\x69\x27\x34\xfe\x07\xc9\x13\xb9\xe8\x81\x26\xbe\xcb\xf1\x4a\x0f\xd0\x20\x5b\x39\xfc\xc2\xae\xc3\x73\xf8\xc1\x84\xc6\xa9\xbb\xbb\x84\x44\x9a\x7c\xa3\xb9\x20\xad\xa0\x88\x01\xdf\xc6\x6f\xf1\x9a\xeb\x92\xf2\x55\x53\x99\xa4\x30\x27\x7a\xe2\x2d\x23\x75\x4e\xaa\xce\x3c\x73\x84\x67\x97\x53\x6d\xd7\x1a\x56\xf4\xb5\x84\x2c\x0f\x41\x0d\x19\x89\xac\xac\x5d\x80\x5d\x26\x57\x2c\x0f\x3a\x64\xdd\x20\x71\x66\x22\x12\xd5\x2f\xe9\x9e\x59\xd9\x66\x04\x77\x77\xf9\x03\x0f\xa4\xfd\x2e\xe7\x4b\x7a\x7c\x9f\x7c\x34\xa6\xdc\x7e\x03\x59\x3a\x13\xd6\x4c\xe6\x24\x53\xee\x3c\xa3\x0d\x84\x67\x28\x39\xf1\x9f\x1c\x15\xd0\xc4\x5d\x27\x55\xbb\x39\x4a\xcf\x4d\xcb\x7f\x7f\x07\x11\xac\x40\xea\x46\x61\x2e\xa3\x7a\x76\x07\xad\x32\xe8\x18\x26\x5f\xab\x19\x33\xf5\x09\x4e\x2d\x03\xbc\xfa\xa5\xf6\x16\x67\xf3\xb3\x7f\x00\xc4\xc5\x8d\x9b\x41\xb9\xaf\x39\x00\x48\x2b\x0f\xfb\x4f\xa4\x37\x6a\xa0\x40\x00\x9d\xec\x2f\x45\x25\x79\x9c\xb0\x05\xf3\x9d\x74\xcb\x2d\x8d\xce\x8c\x20\xc2\xc3\xf5\x40\x97\x03\xaf\x15\x6c\xfb\xa2\x8a\x9d\x91\x64\x39\xcb\x29\xf8\x3d\x24\x29\xce\x62\x23\x51\x9e\x75\xe1\x5c\x7c\x7f\xa2\x15\x11\x9e\x07\x3f\xa7\x97\x4d\xb1\x4f\x7a\x01\x09\x3f\xaa\x94\xad\x52\xab\x1e\xad\xce\x1a\x89\x36\x6c\xa1\x3a\xdb\x89\x06\x64\x38\xa2\xbe\xb7\x30\x34\x17\x0a\xa4\x2d\x9c\x2d\xdb\x97\xc1\x4a\x17\xc3\x09\x43\x76\xd2\xa3\xff\xd8\x09\x5f\xc4\x05\x3d\x91\xd1\x6e\x06\xd2\x76\x93\xa1\x31\x0f\x01\xa7\x51\x11\xcf\xed\xa8\x92\xc3\x97\x2a\x13\x3a\x09\xad\xda\xa8\xf7\x41\x45\xf8\x86\x81\xb6\xd2\x77\x96\x4b\xfe\x38\x55\x1a\x2c\x61\x9f\xa3\xca\xe3\x94\xac\xb2\x9c\x94\x10\xb4\x5e\x10\x1b\x17\x40\xe8\xb2\xaa\x6f\xeb\xc3\xa4\x5d\xad\xb9\xd9\x58\x9d\x59\x7e\x57\xcd\x94\x7b\x68\x4c\xc3\x55\x24\x6c\xe6\xc3\x26\xdd\x98\xcf\x92\xb6\xee\xa3\xba\x5a\xb0\x37\x00\x62\x26\x36\x32\x4d\xc1\x22\x2c\xd7\x48\xfa\x07\xbf\xd3\x9a\x1e\x06\x98\x09\xe5\x67\x14\x1a\x61\x3e\x2e\x8b\xe9\xdd\x39\x8a\xb6\xbe\xaa\xfd\x85\xff\x36\x28\xee\x2a\xa3\x2d\x0a\x57\xbb\xac\xf9\x56\x19\x0b\x5c\x42\x42\xeb\x5b\x85\x87\xd2\xfd\xcb\x07\x41\xb9\x41\x6a\x05\xf5\xfe\xcb\x1f\xb2\xd6\x47\x88\xdc\xe7\x83\xc1\xf6\x3e\x60\x64\x1f\xce\x5e\x1d\x2b\x18\xa9\x50\x0c\xd6\xa1\xfd\x33\x5c\xc1\xdb\x46\xef\x04\x75\x2b\x2d\x22\x07\x2e\x6d\xfc\xfc\xfa\x56\x9b\xb2\x5e\x45\x7a\xfe\xb6\x3a\x4f\xbe\xdc\x29\x3a\xd9\xd1\xab\xa4\xe3\x94\xaa\x10\x97\xe1\x2b\x0f\xc9\x0c\x89\xf7\x6d\xf0\xd6\x44\x1f\xa9\x98\x08\xb6\x0b\xe0\x7d\xfc\xc7\xf9\x01\x0b\xbf\x90\x33\x55\x6d\x5e\xe2\xd4\x48\x93\x7b\x78\x34\x93\x92\x0f\x68\x1e\x4d\xa7\x08\x67\x10\x97\xe1\x99\x48\x1b\x8e\xf0\xe0\x15\x0d\x7c\x28\x51\xdf\x44\xc5\x45\x12\x2f\x9b\x0e\x5b\xa2\xee\xff\x2d\x98\x8d\x56\xd9\xbb\xb5\x5d\x98\x96\x11\x11\x51\xa4\x36\xaf\x06\x5e\x0c\xad\x17\x8a\x2c\x9f\xa8\xf6\x97\x4e\xcd\xf0\x9a\xdf\x01\x33\x00\xcf\xfe\xda\xf4\xb8\x79\x1b\x46\x7b\xa7\x93\x3a\xda\x5d\x63\x2d\xb4\x4e\xd6\xdc\xf2\xaa\x64\x89\x17\xbe\x63\x37\xd2\xe2\xd2\x06\x85\x6d\x08\xf9\xee\x7b\x5e\x2f\x14\xdd\xc6\xd3\xac\x42\x92\x15\xa8\x79\x23\xad\x32\xd5\xdc\xfe\xe3\x68\x63\x16\xdd\xd1\xb2\x7b\xb1\x93\xa5\xfc\x05\xc8\x93\xa9\x39\xa5\xb9\x89\x87\x36\x6c\x82\x9e\x39\x2f\x48\x5e\xa1\x5e\x22\xcd\x8f\x85\x7a\x13\x4a\xfa\x98\xf3\x72\x15\x57\x6d\xdc\x5a\xab\x4f\x2d\x10\xca\xaf\x05\x00\x59\xa3\x35\xf2\x4b\xcd\xcb\xac\x81\x9f\x66\xdb\x07\xaa\xbd\xfb\x76\x27\x1d\x17\xbc\xe2\x2c\xba\x46\x3a\x80\xaa\x89\x2d\x0d\x8e\x05\x5f\x94\x8d\xf7\xf6\xe6\xc3\x00\xda\xef\xfd\x3a\x23\x6d\xdd\xcf\x23\x8f\xe1\x06\x66\xa5\x7c\x6e\x3a\xe7\xe3\x67\x3d\x35\x57\x8f\x8b\x8e\xa6\x9d\x3c\x08\xe0\x14\x0a\xfd\x3e\xe0\x30\xb2\x2a\x37\x21\x60\xf9\x08\xa3\x78\xf8\x10\x1b\x5f\x59\x69\xfe\xa3\x10\xee\xd3\x7a\x00\xd9\x73\x02\xd5\xc2\xdb\xe8\xcc\x60\x00\x75\xdc\xcd\x33\xad\x63\xd2\x65\xaa\xf6\x0e\x24\x1c\xe3\x11\xbe\xd7\xdd\x5e\x27\x45\x24\x1a\xe0\x2a\xe5\x32\xd1\x5c\x18\x88\x6e\x81\x81\x38\x75\x1a\xfc\x51\x85\x0e\x50\x6c\x6d\x31\xa8\xee\xf4\x51\xad\xfd\x4b\x3d\x26\x6b\x41\x5a\x7e"}, -{{0x07,0x82,0x8c,0x58,0x0e,0xbf,0x9e,0x1d,0x82,0x5a,0x59,0xc3,0xbf,0x35,0xf0,0x72,0xae,0x12,0x33,0x55,0xbd,0xcc,0x24,0x9e,0xec,0x7f,0x2f,0xc5,0x75,0x5e,0x29,0xb5,},{0x58,0xe5,0xed,0x85,0x10,0x0b,0xbd,0x9b,0x22,0x21,0xaf,0xc9,0xc9,0x31,0x84,0x33,0x0a,0xd5,0x9e,0x13,0x85,0x60,0x62,0x44,0xbf,0x00,0x3b,0x8d,0x20,0x18,0x50,0x1b,},{0xbb,0x09,0x36,0x04,0x39,0xa8,0x2d,0xee,0x5c,0x7d,0x85,0x77,0x9e,0x54,0xc1,0x3f,0x88,0xe0,0x6d,0x38,0xf4,0xb9,0x49,0x60,0xfe,0x17,0xa1,0xeb,0xca,0xa3,0xee,0x2f,0x33,0x0c,0x64,0x91,0x54,0xbb,0xc8,0x75,0xa4,0x07,0x6c,0xf0,0xbb,0xf7,0xee,0xbf,0x7b,0x8d,0x08,0xd5,0xaa,0x4b,0xe7,0x41,0x38,0x81,0x24,0x5f,0xc2,0xd2,0xb6,0x01,},"\x0e\xda\xd5\xca\xe6\xed\x98\x43\xe9\x1c\x50\xd9\x34\xcf\x55\xdd\x65\x8f\x3d\x25\x20\x39\xcd\x6c\x75\xbe\x4f\x6b\x86\x6f\xb7\x5f\x35\xc8\xf9\x8f\x17\x21\xd7\xe6\xd9\xd9\x8a\x22\xe0\xb4\x93\x4d\xcc\x12\x92\x61\xbf\x67\x23\xb2\xfa\x7a\x99\x5e\x35\xc4\xbd\x79\xc5\x81\x6a\x32\x16\x07\xd9\xdc\xce\x39\xfe\xfa\x1d\x55\xde\x4e\x76\x17\x54\x8e\xc3\x85\xc3\xde\x01\xe3\x66\xbf\x50\xc4\x57\xa5\x55\xe9\x32\x07\x0e\x2a\x5a\x01\x97\xb7\x9e\xfb\xe7\x00\x6f\x0c\xec\x78\xb6\x0e\xbb\x8f\xa8\x78\x1d\x8e\xb7\x32\x6e\xdc\x30\xe6\x2d\x32\x97\xa1\xe0\xa1\x11\x71\x08\xc4\x6e\xe5\xdb\xef\xc6\x59\x42\x89\x33\x5e\x78\x0d\x55\xa0\x84\xf5\x52\xda\x3f\x36\xd3\xc4\xc6\x17\x8b\xa7\x4d\x4d\xec\xef\xc5\xa3\xb8\xc4\x7c\x16\xf5\x34\xbd\xb6\x08\x95\xd3\xd5\x4c\xd2\xbb\x26\x6b\x39\x9e\x4d\x4f\xb4\x8d\x7a\x8c\xde\x17\xf4\x24\x12\x56\x07\x37\xd3\xc0\x6e\x29\xdf\x52\x4d\x0c\xbd\x30\x93\xef\xca\x1c\x8f\xed\xca\xa1\x24\xab\xb2\x7a\xbd\xac\x6a\x29\xe0\xe8\x24\x6a\xbd\x6f\x5f\x53\x19\x50\x03\x7f\x76\x32\x3a\xa5\x6c\xc3\xfe\xfa\x60\x30\x41\xd5\x5f\x19\x29\xe2\x77\xe7\x2c\xda\x1f\x96\x54\x1d\x2a\xf3\xe9\x0c\x0f\x0e\x28\xbe\x19\x6d\x8f\x69\x21\xf3\xcd\x57\xa7\x92\x6b\x86\x0a\xa1\xbc\x40\x35\x76\x89\x2a\x96\xb9\x31\x90\xae\x38\x3f\x63\x1b\x72\x80\x26\x58\xb2\xe8\x45\x1d\x52\xa2\xf4\x5d\xb4\xf8\xbc\x3b\x0e\x4e\x50\xb6\xd6\x03\xa5\xbd\xd3\x0c\x23\x42\x00\xad\x7d\xeb\xb9\x63\xf5\x8a\x4f\xa2\x03\x30\xb3\x69\x64\x49\x44\x5a\xa3\x71\x82\x48\x42\xfb\xf3\x26\xd9\x01\xdf\xe3\xbe\x04\x54\x52\xa3\x74\x0d\xd1\x60\xe7\x27\x33\xf6\xe2\x73\x35\x25\xa2\x9a\x86\x5f\x6f\x50\xd5\x3b\xf7\x19\x1c\x59\x9c\x87\x6f\x5c\x9c\xa1\xe3\xfa\xd7\x96\x06\x48\xe0\xd4\x71\xf7\xd5\xc0\x1c\x67\x3f\x42\xd6\x59\xbc\x3d\x98\xdb\xf0\x7d\x8f\xeb\xfb\x99\x5d\x17\xf9\xa0\x2c\xd6\xc3\x9f\x2d\xdc\xd0\xf1\xd2\x22\xb9\xe1\x1f\x2d\xd7\xd3\xc7\x51\x82\x24\xbb\x6b\xfb\x8b\x7c\x58\xfe\x8a\xc1\x05\x40\x59\x03\xa1\xb9\xda\x75\x16\x71\x5b\x7a\xfc\x38\xa5\x55\xe6\xbb\xcd\xba\xd4\x6e\x34\xe5\x76\xfe\xa3\x4c\xe3\x57\x34\xed\x20\xaf\x5d\x88\xee\xb1\x04\x7a\x26\x60\x64\x8b\xbb\x11\x3a\xd9\xdb\x8c\x53\xed\xb6\xed\x98\x71\xa1\xe4\x4c\x9e\xd2\xdf\x56\x56\xfb\x2b\x28\x06\xec\xf0\x3b\x1e\xca\x9e\xab\x50\xa6\xea\xab\x55\xb9\x33\xb2\xdd\x1f\x21\xd4\x50\xde\x9d\x5c\xb2\x23\x2f\x07\xa3\x92\x08\x1b\x0b\x4b\x88\x5d\x54\x78\x9e\x2f\x75\xbf\x2c\x4c\xda\xd8\x78\x98\x9b\x1d\x6d\xab\xd9\xed\x23\xc7\xc5\xb0\x35\x6a\x7d\x9e\x73\x35\x29\x0d\x7c\x85\xb9\x66\xe8\x01\x84\xbd\x07\x99\x86\x02\x88\x6d\x70\x76\x19\x35\x65\xc8\x1c\xcc\xda\x4c\xc7\xd3\x3c\x85\xd9\x05\xb1\xbe\xb6\xe8\xe7\x41\x8e\x8a\xca\xed\xf0\xd9\xa3\x2a\x7d\x29\xd0\x7c\xf4\x4d\x31\x19\xd4\xe7\x89\x68\x20\xb7\x7d\xe6\x4b\x65\x5e\x4f\x14\x88\x00\x43\x4a\xf7\xbd\xb2\xa5\x6b\x25\xeb\x94\xea\x39\xf2\x16\x95\x96\xbb\x2b\x11\x76\x1f\x08\x2b\xae\xc0\x88\x85\xf4\xa0\xeb\x6c\x95\x76\x71\x35\xa7\xf7\xcd\x72\xe7\x43\xd2\xdf\xf1\x44\xdd\x8b\xaf\xb1\xb3\x18\x00\x6e\x58\x76\xf8\xe2\xcb\x44\xaa\x58\x8f\x90\x62\x66\xac\x67\x11\x9c\x17\xf5\xde\x11\x4e\x72\xe4\x2a\x1f\xb3\x99\x44\x32\x1a\x11\x1f\xa7\x95\xff\x70\x17\xf2\xfb\x8c\xaf\x48\x2f\x55\xd7\x7a\x80\x85\x54\x28\xde\xd7\xec\x20\xac\xec\xca\x83\xf8\xd1\xeb\x13\x7b\x58\x8c\xcb\x74\x5c\x10\x5f\x2b\x2c\xa4\x1c\x3a\x9f\x49\xd3\xc6\xe9\xd7\xc6\x48\xb0\x03\xb9\x70\x7c\x90\x64\x62\xed\xad\x61\x7a\x8c\xfb\xf9\xbc\xc6\xc5\xfb\x6f\xa9\x84\x32\x5d\x65\x82\xe2\x8f\x62\x00\x53\x83\xf3\x38\xdf\x5b\x38\xfa\x9d\x19\xc2\x2a\x2a\x7e\xa1\xd6\x8a\x92\xd1\xd9\x3b\x7f\xb0\xb8\xf3\x3b\xc8\x76\x0f\x28\xae\xb1\x43\x9a\x8b\x07\xf3\xda\x58\xdd\xb1\x55\xb4\x98\xcb\x09\xc7\x5a\x55\x96\x83\x8a\x65\x01\x3e\x24\xd5\x64\x0d\x08\x42\xa7\x69\x93\x22\xcf\x3f\xfc\xb5\x70\x3f\x41\x4f\xfd\x16\x88\x60\xba\xd3\xe3\x08\xb2\xb5\xbf\x3c\xdf\x7f\x36\x3b\xf9\xaa\xf4\xb3\xbc\x42\x4c\x14\x6c\x6f\x54\x21\x43\x0f\x9f\x47\x6a\xa3\x4a\x0c\x6e\xe8\x01\x31\xfc\x4d\x4d\x97\x07\x23\xa2\x18\x6a\xe3\x62\x5e\x28\x6d\x17\xdd\xdc\x43\x5c\xcb\x00\x83\x16\x78\xab\xa5\x84\xa6\x2d\xbf\xf0\x02\xbe\xad\x6e\x11\xe2\x3c\x54\xd3\x3c\xf3\xa4\xb2\x31\xa9\x08"}, -{{0xf0,0x8e,0xe8,0xda,0xa7,0x3e,0x1f,0xeb,0x61,0xa8,0x8e,0x06,0x2d,0xfb,0x10,0x03,0xc8,0x57,0x8a,0x0d,0x53,0xbd,0x3b,0xc9,0xe5,0x89,0xef,0xb9,0x2f,0x68,0xbe,0x14,},{0x76,0x69,0x2c,0xe8,0xd1,0x16,0xec,0xcb,0x89,0x70,0x77,0xed,0xca,0xaf,0xdd,0x3e,0xb4,0x4e,0xa1,0xa4,0x86,0xb9,0x0e,0x49,0xe9,0x7f,0x96,0x69,0x01,0x01,0x55,0x02,},{0x66,0xdf,0xa4,0xc1,0x57,0x5b,0xef,0xf2,0xf5,0xa2,0x30,0xb2,0x8c,0x58,0xc3,0xee,0xa0,0x73,0x6d,0xf3,0x79,0xd7,0x55,0x59,0xbc,0x9d,0x37,0xa9,0x57,0x9d,0x12,0x1c,0x05,0xc3,0x73,0xe8,0x48,0x4c,0x97,0x47,0xef,0x44,0x77,0xe8,0x0c,0x4b,0x2c,0xb4,0xdd,0xf1,0x6a,0xe9,0xfd,0xfa,0x08,0xa0,0x75,0x47,0xd1,0x07,0xdc,0xea,0x12,0x03,},"\x64\xde\x90\x04\x4d\x0e\x76\xbc\x02\xfc\xff\xcb\x75\x26\x36\x67\xb3\xbd\x73\x3b\x40\xbf\xb2\x6c\x6c\x52\xfd\xb4\xb0\x78\x22\x78\xca\xba\xe4\x1e\x21\x29\xea\x40\x17\xe9\x4d\xe8\x60\x87\x96\x4f\x66\xd8\x62\x07\x98\x74\x67\xa1\x68\x8f\x9f\xab\x3f\xfb\x2f\x1d\x00\x63\xbf\x62\x6c\x94\x13\x67\xc1\x2e\x31\x9a\xb7\xca\x30\x20\xc9\xb3\xa7\x21\x5a\x19\x30\x3e\x2d\x0e\x89\x88\x79\x1d\xe0\xd8\xe1\x63\x2d\xaa\x38\xc7\xf3\xe7\xf6\xe4\x8c\xe1\x22\x14\x3d\x1e\x2c\xb6\x61\xba\x77\xc6\x9e\x6a\x71\x09\x11\x64\x4b\xc1\x10\xff\x58\xbb\x00\xb5\x29\x08\x20\xce\x30\x97\x0e\x7f\xde\x18\x9e\x14\x0e\x5c\x70\xc7\x83\xee\xd5\x3f\x0e\x2a\xc7\xec\xae\x4f\x27\xdb\x81\xd1\x5b\x86\x46\xfa\xa9\xc5\xa3\xae\x2b\x7f\x47\xcd\x58\x0d\x77\x07\xb0\x02\x49\x9b\x4c\xfe\xb8\xc5\x91\xaf\xdf\x1c\xc6\x2a\xf2\x59\x5c\x18\x4a\xbc\xf0\xb2\x62\x3a\x1b\xae\x60\xaf\x70\x26\xb2\x8d\x05\x40\xb4\x15\x26\xe3\x02\x0f\x81\xb8\x94\xeb\x3f\xe3\x1b\x72\xb2\x1a\x32\x60\xda\xe3\x21\x0c\x4c\xe4\xfd\x69\xe2\xe5\xea\x0c\x86\x32\xa5\x83\x26\x2a\x12\xb3\xa8\xb1\x6c\x9c\x12\x06\xad\x73\x02\x30\x37\xcf\x30\x65\x3c\xb8\x0a\xa7\xdf\x83\x14\xb0\xf5\xbc\x6e\x9d\x5f\xa0\x0b\x00\x9d\x55\x52\xd8\x3b\x79\x70\xb5\xbc\x4b\x99\x84\xf6\x9d\x1c\xca\x9c\xe4\xcb\x74\xdd\xd2\xd8\x79\xd3\x73\x12\xa0\xe1\x59\xd7\xa6\xaf\xb7\x7a\xc5\x85\xe6\xb4\x59\xc5\x51\x30\x4e\x1e\xeb\xfb\xca\xb4\x3a\x10\xb5\x05\x92\x4e\x03\xea\x33\x2f\x5d\x02\x0a\x55\xc7\xaa\x68\x3c\x54\x1d\xcf\x77\x90\xa2\x40\xaf\x07\x9b\xab\xa9\x40\x96\xb4\x60\x60\xfd\x7a\xfe\x90\x56\xca\x99\xe6\x88\xdf\x28\x0a\x9b\xe8\xc8\xc7\x3e\x6e\x6f\xb0\x52\xa3\x3e\xb3\x32\x8a\x7f\x60\x25\x42\xfe\x28\x0c\x89\x0e\x3c\xca\xf2\x2c\x7f\x34\xf8\x7b\x5e\x5b\xa7\x84\xb4\x72\xb1\xe1\xa9\x93\x47\xa9\xe0\xd2\x40\x85\x8d\x12\x77\xa5\xc6\xb3\x49\x38\x3f\xe4\xfd\x55\xcf\x92\xe6\x9f\xaa\xd3\x26\xb8\xd6\xdb\x46\x23\x30\x26\x22\x1e\xe6\xd0\xa1\xc4\x24\x65\x33\xc4\xa0\xe5\xbd\x17\x2e\xb8\x93\x6a\x9c\x0d\x30\x06\x65\x38\xe3\xeb\x4a\xd5\xcb\x98\x77\xfd\x86\x1b\x48\x2b\x30\x15\x0a\x06\x10\x41\x61\x64\x7e\x01\xd0\x04\xd9\x97\x40\x3e\xe0\x67\x26\xcb\x97\xe2\xe2\x5f\x18\xc6\x68\xee\xe4\xc5\xbf\x72\x52\x98\x03\x18\x9e\xe6\xa7\xae\xc2\x38\xd5\x90\x6e\xa5\xae\x10\x72\x2c\x9a\x61\xa7\x8a\xea\x52\xaf\x33\xea\xac\x75\x40\x6b\x1a\x60\xbe\xfb\xaa\xd4\x84\x76\xd9\xff\x88\x7f\xd2\x83\xeb\x16\x55\xbc\xc0\x7c\xf7\x53\x33\x14\x36\xdb\x5b\x3b\x13\x03\x2f\xf9\xc3\xd6\x96\x38\x0e\x9f\x5a\xbf\x50\xd3\x55\x6f\xda\x0d\xf0\xb5\x38\x97\xa7\x37\xac\x7a\x3b\x87\xc2\xa8\x32\xb0\xc7\x27\x3e\xa9\xfc\x54\xa7\x67\xf1\xa8\x12\xbf\x01\x64\xbf\x75\x21\x63\x0b\x81\xb9\xdd\x93\x0d\x92\xee\x2c\xa2\x8e\x32\x03\xb7\x7b\xc0\x82\xce\xb3\x7d\x55\xed\xbc\xb7\x1d\xf0\xb7\x92\x36\x78\x9a\x25\xd4\x18\xcb\xb9\x55\x44\xe2\xce\xf3\x3b\xbd\xeb\x27\xa3\xf7\x90\x9c\x1f\x49\x8f\x47\x13\x5a\xe9\x03\x3a\xdf\x25\x0a\xd4\xf6\x57\x53\x61\xe4\xcf\xcc\x9b\xcf\x4b\x90\xc3\xad\x47\xa3\x44\x22\x97\xa2\x23\xcc\xa8\x43\xd7\x20\x5e\xd0\x8a\x9b\x87\x16\x0a\x6d\x01\xb4\x6a\x7d\x1c\x84\x4e\x8d\x1f\x18\xf6\x18\x68\x2b\xfb\x22\x95\x5f\x39\x5b\x2a\x57\x90\xa5\x1a\x69\x64\x99\xd9\xe7\x1a\x50\x1f\x3f\xa5\x46\xde\x9b\x10\xae\x47\xbc\xee\x42\xba\x7f\x86\x9f\xb9\xce\x4e\xd7\xc6\x45\x33\x26\xc0\x34\xcf\x05\xd9\xf1\xe3\xc2\x00\x70\x1b\xa7\x52\xda\xbb\xd8\x68\x52\x1c\x3d\x8f\x80\x67\x2d\x42\xf6\xcf\x45\x64\xf0\x8c\xd7\xb3\x90\xe6\xd4\x9d\xd9\x00\x90\xaf\xdb\x84\x48\x6f\xfc\xaa\x4e\x84\xd8\x86\x82\x74\x4d\xc0\xa8\x78\xfa\xa7\xcd\x44\x0a\x8b\x27\x67\x10\x90\x20\x81\xf4\xdc\x84\x17\x46\x19\xa6\x6e\xa3\xa3\x71\xf9\x55\x05\x40\x0d\x99\xfa\x99\x90\x17\x71\x0c\x8e\x27\x14\xbe\x60\x94\x9d\x46\x13\x10\xf7\xd4\x3a\x0d\xc1\x23\x51\x6d\x77\xd3\x62\x21\x3f\x9f\x75\xa5\xa1\xc3\x93\xaf\xfc\x49\xea\x15\x1d\x46\xa8\x1f\xfa\xd2\x39\xf2\x8c\x07\xf6\x5f\x59\xea\x07\x7d\x9a\x4d\x9c\x75\x2d\xe4\x9b\x9e\xf3\x6b\xe6\x0d\x11\x2d\x79\x5f\x58\x8b\x00\xef\x6e\x77\x30\xde\xa6\x5e\x10\x16\xda\x0d\xd4\x62\x37\x0e\x0b\xa5\xc6\x60\x00\x1e\x45\x7c\x08\xb4\x36\xda\x29\x03\xb6\x29\x06\x93\x20\x84\x72\x8c\x81\x67\x1c\xbf\xb0\x79\xbb\x29"}, -{{0x27,0x2d,0x64,0xde,0x50,0xb1,0x31,0x2b,0xee,0x23,0xd7,0xf4,0xce,0xa5,0x08,0xa8,0xfc,0xcf,0x3e,0x9b,0x32,0x4e,0x97,0xb1,0xc8,0xe7,0x25,0x02,0xf6,0x1f,0xbf,0x45,},{0x33,0x49,0x8c,0x3b,0x71,0x2a,0xb9,0xc0,0x1e,0xc7,0x6b,0x2e,0xfe,0x2b,0x83,0xad,0xd1,0xe1,0xf2,0xb5,0xeb,0x78,0xf2,0x16,0x92,0x32,0x34,0x51,0x82,0x0c,0xbe,0x10,},{0x33,0x81,0x4c,0x6e,0xf3,0x75,0xab,0x96,0x37,0x69,0xb2,0xde,0x4a,0x25,0xe7,0x02,0x0f,0xcd,0x97,0xf7,0x8f,0x8f,0xc9,0x34,0x55,0xc4,0xb1,0xc2,0xbd,0x45,0xd4,0xb0,0x1e,0x19,0x29,0x00,0xe3,0x12,0x22,0x65,0xfc,0x55,0x2c,0xd5,0xc5,0xf0,0x0e,0x93,0x1e,0x3a,0x18,0x3c,0xca,0x5b,0xa0,0x80,0x2d,0xaf,0xde,0xbb,0x79,0xeb,0xeb,0x03,},"\xd6\x26\x0d\x7e\xec\x5d\x43\x62\x08\xe7\xe7\x37\x65\x5e\x09\x71\x81\x42\x70\x19\x44\x05\xe3\x6e\x39\xf8\xf1\x7b\x64\x9f\xbc\x16\xc0\xf3\xd7\xf2\xbe\xf5\xeb\xc0\x2b\xb1\xc4\xdf\x48\xe8\x47\x0a\x3e\xae\x8a\x3c\xca\xf6\x40\xab\xcc\x09\x4a\xa9\x11\x50\xff\x1a\x8c\xf1\x16\x96\x93\xeb\xf5\xac\x00\x34\xb9\xb9\x19\xec\xf1\x7d\xb7\x91\xdf\xe5\xfe\xdc\x90\x91\x8b\x23\xe5\x4e\x90\x04\xa1\xae\x77\x1c\x21\x3e\xd7\xed\x73\x34\x43\x4e\x5b\xc0\x2c\x0d\xda\x2b\xd1\xa8\x76\xfb\x82\x4a\x19\x7b\xc9\x96\x13\xb1\x40\x9e\x70\x52\x31\x0b\x08\x20\xda\x71\x44\x69\x29\xae\x7c\xfd\x3a\xfb\xa0\x42\xde\x54\x57\x8a\x5b\xfd\x94\xc1\x54\x43\x91\xa3\xd9\xac\xbd\x56\x63\xef\x65\xc6\x92\x0d\x78\x51\x6d\xec\x1c\xd5\x5f\x6e\xb7\x29\x0b\xa0\xaa\xf9\xa1\x71\x65\x82\x00\xb2\x4a\x47\xa0\x71\xb9\x6f\xea\x03\xc6\xca\x7e\xd0\xd6\xfe\x67\x5d\xd6\x37\x61\x83\x3d\x75\xbc\x5e\x58\xa9\x58\x58\x2d\xb0\x2a\x60\xc6\xce\x0a\x63\xf4\x2b\xa8\x37\xae\x77\xc1\x7a\x32\x70\x5f\xd9\xca\xfa\x58\x7b\x55\x5d\xd4\x61\x98\x51\x07\x97\x94\xe2\x4e\xb4\x46\x08\x83\x5a\x6f\x48\x24\x92\x0d\x57\x7a\x27\x03\x96\xc9\x57\x3b\xc7\xd8\x2f\xe2\xaa\x04\x65\x95\x66\x13\xa2\xc5\x08\xcf\x24\x32\x33\x7a\x36\x5e\x6c\x98\x4c\xba\x91\x7f\x0c\xf8\x42\xaf\x12\x2d\xc8\x9d\xea\x95\x8d\x41\x8c\xae\x44\xa6\xe4\xed\x26\x3a\x41\x5f\xf9\x94\xa5\xff\xb2\xff\x13\x91\x3d\xf2\x14\xbb\xfe\x90\xa3\x4b\x24\x7e\x71\xab\x73\xf7\xff\x00\x4c\x23\xac\xfd\x90\xc7\x67\x61\x1a\xa5\x58\x14\xc6\x69\x64\x16\x8e\x56\x8b\xa7\x5b\xf3\x49\x03\x59\x7c\xdc\xac\x78\xc2\x4b\xb9\xf1\x4f\x5c\x86\xa5\x1f\x36\x4f\x9a\xb4\x1e\x46\x4a\xee\x64\xfa\x50\xa1\xc1\x59\xcb\xd8\x50\x83\x2c\x50\x4a\xb4\x2a\x58\x4a\x96\xd5\xae\xe0\x82\xd8\x2c\x1e\xdd\xa1\x93\x38\x16\x0b\x8d\xcf\xa3\x41\x9b\x3a\xf6\x4d\x9c\xfb\x10\x4f\x98\xf9\xd3\x5e\x53\x94\xe2\x32\x28\xe2\x75\xc8\x7d\xb5\x0c\xa8\x67\x54\x0b\x88\x0c\x7a\xf2\x9f\xbf\x53\x42\x94\x58\x1c\x22\x24\x0b\xcd\x4d\x7d\x2c\x20\xff\xc3\x67\x33\xad\xa2\x76\x53\xd3\xae\x1a\x8c\x22\x03\xea\xc6\x26\xe2\xe9\xbb\x4b\x52\xce\x52\x3e\x5a\xdb\x3b\x2c\x10\xdc\xf7\x8c\x2a\x1e\x62\x6a\x16\xeb\xfa\x1b\xdb\x8c\x16\x14\x93\xa5\xaa\xa2\xd8\x4b\xfa\xa0\xf2\x02\x7f\xfe\x4e\x9e\xae\xb3\x32\xeb\xda\x7c\xbb\xb6\x77\x76\x9d\x78\x51\x7a\xdf\x72\xf8\x23\xa7\xf8\x44\x16\x5a\x07\x98\x78\xd2\x58\xfd\x95\x22\x5c\x21\x17\x78\x37\xe6\x9c\x19\x68\x5a\x05\x1c\xa9\x2b\x12\x0b\x7d\x86\xd7\x85\x95\x47\x1f\xfc\x42\xa5\xe6\xe6\x43\x1b\xe7\xb6\x4f\x80\x76\x45\x8b\xac\xd6\xc7\x29\x03\xcc\x34\xfc\x63\xa4\x0c\xf3\xdf\x00\xef\xf9\xd6\xee\x9a\x8f\x39\xd2\x5e\xad\x81\xa8\x12\x88\x88\xb0\xa1\xac\x0e\x5e\x3a\xd9\x27\x71\x2c\x14\x14\x6a\xdf\x82\x87\x70\xff\x95\x87\x09\xeb\x19\x28\x8e\x77\xbb\x70\x73\x48\x81\xe9\xe0\x16\xcd\x29\xe7\xd0\x89\x93\x41\xff\x6b\x29\x7a\xc7\x96\xbb\xde\x48\x6e\xc3\x59\x49\xf6\xa3\x2b\x2c\xa6\x47\x38\x59\x15\xec\xba\x3b\x9f\x02\x25\x08\x71\x45\xc1\x8d\x65\x59\xd3\xa3\x1d\x6f\x22\xfc\x49\xf8\xa6\x31\x5f\x1d\x32\xab\xee\xb7\xcf\x2c\x2c\x77\x6e\xa7\x35\x0f\xd5\xeb\xc0\xe0\xf2\x65\xba\xcc\xc2\x69\x7a\x7c\x8c\xa4\x0c\x13\x5f\x6c\xfc\xb0\xb5\x8a\x61\x43\x19\x60\xff\xa9\x06\x57\x09\xa9\x61\xa6\x33\xd5\x70\xb7\x3f\xb4\x49\x1d\xe5\x2a\xd0\xd7\xb2\x04\xb6\xe9\x97\xb0\x37\xed\xe3\xf7\xec\xa8\x20\xa7\xcd\xb2\xc6\x9a\xc2\x91\x48\xbe\x35\x23\x50\x8a\xe7\xe4\xc3\xd1\xa7\x17\xf5\x5a\x82\x1d\x14\xc3\xb6\x4f\x08\xca\x9a\xe4\x96\x13\xb1\x15\x77\x3e\xf6\x18\xd3\x21\xc9\x08\xbd\x21\x56\x71\x7a\x43\x4e\x50\x89\xa5\x94\x8c\x04\x5c\x8d\xa8\xa4\xbd\x86\xed\x5f\xab\xc6\xb1\x34\x66\xe6\xde\xda\x58\x32\x07\xd2\xad\xa2\xb2\xab\x9c\xb1\x54\x3d\xf7\xa3\x73\x4d\xfb\xc6\xfc\x42\x81\x06\xd4\x84\x47\x24\xa1\x3d\xf4\x2f\xaa\xb1\x8c\xa8\x9d\xb2\x0a\xc9\xbc\x27\xb8\x53\x94\x66\x7c\x5a\x27\x79\xca\x63\xed\x7a\xc2\xb7\xc0\xd4\x12\x23\x91\xee\x46\x02\xd6\x1e\xa0\x38\x17\x64\xfb\x72\xdc\xc2\x24\xe6\x5e\xae\x2b\xc4\x50\x6b\x0f\x09\xe2\x32\x05\xd0\xbb\x21\xc7\x7d\x82\x87\xc1\x65\xe0\xb4\x2c\x55\x15\x79\x77\x8a\xcb\x72\x58\xa2\x47\x9d\x7c\xf2\x5b\x90\x2e\x8d\x0d\xa4\x29\xbd\xe3\x6b\x45\x90\xda\xe9\x6f\x52\x54\x81\xac\x83\x78"}, -{{0x0c,0x9f,0xe5,0x59,0xad,0x1e,0xd3,0xba,0x16,0x4d,0xac,0xea,0xcb,0x02,0x35,0x67,0xb2,0x43,0x03,0x20,0xb6,0x71,0x5d,0xe7,0x32,0xa0,0x3c,0x59,0xc7,0x30,0x31,0x30,},{0xe7,0x0f,0xc4,0x66,0xfb,0x2a,0xcd,0x74,0xe0,0x99,0xc3,0x6e,0x2c,0x22,0xfa,0x51,0x29,0x0b,0xdd,0xe9,0x6d,0xf9,0xc3,0x1b,0x6d,0xfb,0xfd,0xc2,0xe2,0xc1,0x4a,0x40,},{0x6c,0xd8,0xae,0xd9,0x7d,0x9c,0x62,0xd5,0xfd,0xae,0x59,0x7d,0x06,0x1c,0x0c,0x2b,0xc3,0x7e,0x42,0xdf,0x06,0xb8,0x32,0x7a,0x46,0x8f,0x92,0xb3,0xf4,0x38,0xa1,0xe6,0xb6,0xb1,0xef,0x2b,0xe7,0x85,0x49,0xa2,0x89,0xfd,0x3f,0xc1,0xa6,0x29,0x9e,0x5a,0x33,0xd5,0x39,0x6c,0xb4,0xfa,0xc1,0xe8,0xe9,0x98,0x2f,0x0c,0xb3,0xd2,0x0d,0x07,},"\x26\xeb\xc6\x48\xcf\x8c\x79\x65\xec\x6e\xbe\x96\x5d\x9c\x79\x2b\xed\x90\x65\x5a\xd4\x40\x18\x3c\x6d\x70\xea\x64\x67\xbb\x8e\x6f\x04\xec\x84\x3f\x33\x31\x56\x91\x7b\xf4\xc5\x1d\x0e\xd0\xf2\x8b\x7c\xd3\x1b\xc1\x2c\xf8\x40\x68\x6b\x82\xb0\xc2\xc3\x50\xbb\xda\xc8\x05\x33\x37\x25\xd6\xb6\x9c\x2a\xb7\xf3\x4e\xe5\x93\xfa\x1c\xcc\xed\xf3\xf0\x64\x2a\x68\x8f\xcc\x1c\xd9\x8b\x09\x87\xd0\x1f\x71\x3a\x2f\xa6\x41\x6c\x96\x19\x21\xde\x0c\xc2\xc9\xec\x7a\x55\x58\x55\xe7\xfc\xd4\xc7\xdd\xaa\x14\xfd\x91\xec\xb0\x42\x24\xe1\x76\x1b\x7d\x6b\x35\xf4\xaa\x56\x18\xa5\x00\xca\x00\xd1\xca\x24\x51\xb5\xd3\x68\xaf\xde\x3a\x40\x7e\x78\x31\x35\xf3\x90\x19\xa5\xb9\x84\xe8\x2a\xc2\x79\xc0\x5e\x48\xc2\x95\xeb\xd1\x56\x38\x21\xa0\x74\x3c\x52\x24\x6b\x5d\x2b\x20\x34\xe3\xae\xb6\xce\x7c\x5c\xf9\x19\xe7\x4a\x9c\x7b\xbc\x9e\x25\xda\x30\x43\x0e\xb1\x6e\xcf\x38\x37\xeb\x38\xa0\xf5\x59\x79\x2a\x72\x98\x90\xba\x83\x10\x26\x0f\x8a\xeb\x9b\x5a\xf0\x0e\xb6\x33\xc1\x2d\xee\x02\x26\x28\xba\x41\x8d\x75\xcf\x18\xde\x2f\x2e\x65\xe4\x9b\x1a\x69\x68\x4d\x61\x27\xef\x48\x1c\xa8\x61\xec\xbc\xe3\xbe\x86\x49\x7e\x65\xdf\x4c\x5f\xcd\x08\x17\xc9\x71\x6b\x59\xf2\xa2\x63\xd5\xe9\xeb\x60\x68\x39\xf8\x5c\x5a\x36\x58\x37\xb0\xfb\xe2\xc4\x27\x4d\x66\xcb\x2c\x65\xed\x36\x5f\xab\xf5\x8f\x15\xbe\x52\xb5\x1c\xb6\x01\x18\xca\x4f\x73\x0d\x44\x73\x59\xf7\xef\x34\x6b\x75\x02\x17\xd4\x7b\x2e\x79\xc8\x6c\x0c\x62\x81\x6a\x0c\x7c\x18\xa2\xce\x2b\x68\x8e\x0c\xce\x0d\x75\x23\x21\xe7\x9b\x42\x38\x57\xda\xc5\x9f\x8f\xbe\xb0\x94\x11\xe7\x16\x69\xef\x9a\x26\x43\xf2\xe9\x9f\x38\x7a\xc1\x83\xe0\xb0\xac\x72\xc5\x9a\x0c\x3c\x18\xc0\xde\x8b\x01\x08\x78\x07\x4a\xcc\x1a\x2b\x39\xf9\xdf\x99\xd9\xf8\xf8\xb5\x2f\xef\xe4\x94\x3c\x52\x5f\xd4\xd0\x6a\xd8\x78\xe4\x66\x08\xab\xf2\x7a\x54\xbc\x50\x06\xf6\x47\xdb\x72\x48\x51\xdb\x7c\x45\x78\xae\x66\x58\x3d\xc4\xbb\x51\x8e\xf0\x28\x89\x03\x47\xe8\xfc\xe0\x92\x7d\x7d\x9a\xf3\xab\x5d\x0d\x2d\x20\x2a\x40\x26\xaa\x2e\xa7\x48\x79\x62\x67\x6a\x60\x32\x98\xe7\xd2\xe7\xb9\x09\x21\xee\x1b\x52\x80\x6d\x71\xa7\x64\xe0\x3e\x25\xdd\xd6\x84\x8f\x61\xd4\x6f\xad\x3d\x00\x8e\x10\xee\x5c\xd5\xa3\x39\x0f\x9d\x15\x8a\x44\x37\xef\x61\x5f\xc9\x0a\xc5\xbf\x3a\x9d\x68\x2e\x12\xc3\x39\x8a\xc7\x76\x80\xd2\x2c\xd1\xa6\xa5\x6e\xc3\xb2\x5c\xed\xe8\x67\xed\xd3\x83\x15\x9c\x61\x64\xd6\x3e\x9c\xd1\xc9\x56\xac\x72\x35\xff\xfa\xe9\x36\x16\x6c\xcd\x35\x89\x8e\x29\xc9\xb4\xca\x4e\x29\x25\xda\x32\x3b\x6f\xbf\x67\xcf\xd5\x96\xc8\x8a\x1a\x35\xa8\x35\x98\x51\xdd\xcb\xa8\xf6\x13\x4a\x9f\xaa\x24\x4d\xcb\x47\xe6\x91\x27\x6e\xe6\x25\xcc\x20\xad\xce\xc2\x1c\xbe\x77\xa3\xac\xb9\xba\x72\xf0\xc9\xd3\xda\x7e\x9c\xd5\xbe\x3b\x95\x99\x0b\xa5\x4a\x9f\x31\xaf\x17\x1f\x95\xae\xea\xd3\x33\x1c\xb1\x88\xa5\xb2\xc6\xf5\x39\xac\xb4\x8b\x98\xb3\xf7\x34\x1f\x60\x25\x1c\xb6\x04\x29\xcc\xd9\xcf\x32\xf0\x09\x20\x5f\x27\x53\xfb\xbb\x26\xaa\x53\x17\x43\x42\xad\x18\x4d\xab\x68\x70\xc0\xfb\x52\x93\x01\x19\xd9\xf9\x7d\x84\x89\xa6\x00\x76\xaa\xdb\x2e\x96\x05\x4a\xc7\xcb\x7f\x84\xe1\x3c\x75\xbb\xf9\xe4\xd9\x24\xd2\x27\x2a\xfe\xf0\x87\x19\x15\xe2\x43\xce\x66\xfc\x2a\x88\x88\x51\x35\x35\xb1\x0b\xb4\x07\x9c\x80\x6b\xd9\x49\x28\x1e\x28\x28\x35\x23\xd0\xd2\x10\xb3\x1e\xf6\x2a\x95\xdc\xae\x0c\xd2\x52\x90\xc7\xed\xf2\xc2\x4b\x43\x28\x22\xde\xbe\x34\x7f\x1c\xae\x94\x5f\x57\x28\xc7\x1b\x54\x03\xef\x14\xe7\x2c\x3d\x83\x42\xe1\x98\xb3\x62\xee\x20\xf8\x09\xe4\x6a\xca\x01\x5f\x35\x47\x7f\xf8\x9a\xc4\xb3\x7e\x66\x15\x85\x6f\x7e\xa2\x51\xfb\xfe\x13\xf9\x06\x52\x59\xb0\x94\x6a\xae\xf2\x49\x43\x27\x0a\x85\x4d\xe8\x89\x78\x00\x33\xd6\x3d\xda\x54\x47\x99\x8a\x3e\xd7\xe5\x06\xae\xb5\x1e\xa3\x7b\x68\x1a\xc3\x07\x67\x97\xac\xdb\xfc\xc2\x78\x83\x63\x0a\xdb\x72\x26\x0a\x46\xaf\x0a\x60\xd5\x3f\x66\x54\x56\x6e\x20\xd6\x08\x8c\xd4\x8e\x23\xb2\x8d\x81\xf0\xee\xd2\x05\xb9\x2a\xaf\xd9\x61\x64\xd6\xd3\xca\x3f\xc8\xb1\x71\x80\x4e\xe9\xfc\xe7\xab\xae\xd2\xea\x4d\xdf\x9c\xb2\xb3\xae\x73\xa7\x0e\xd6\x3d\xe4\x5e\x14\x10\x14\x28\xd0\xa7\xa2\x26\xdb\x39\xab\x6c\xd0\x43\x74\x08\x0e\x69\x83\xf0\x18\xce\x93\xda\x4c\x89\xac"}, -{{0x15,0xd7,0x5a,0xd8,0xe4,0xaf,0xb1,0x26,0x34,0xcc,0x8e,0x60,0x0f,0x1a,0x42,0x67,0xef,0x95,0x84,0xf4,0xc4,0xac,0x44,0xff,0xfe,0x4b,0x9f,0xcb,0x88,0x5c,0x9d,0x2a,},{0x09,0xd1,0x26,0xf0,0x17,0xe0,0x16,0x97,0x74,0xe8,0xc3,0x7a,0xb3,0x79,0x26,0x3a,0x80,0x75,0x74,0x61,0x27,0xc2,0xd1,0x1e,0xcb,0x0e,0x4c,0xb4,0x54,0x70,0x9f,0xf1,},{0xa8,0xf2,0xf4,0xb9,0xe2,0x07,0x2c,0xa9,0xfa,0xde,0x37,0xfd,0xd6,0x2d,0x8d,0x02,0x42,0xfd,0x4d,0xaa,0x09,0xfd,0x85,0x6e,0x75,0xf4,0xe3,0x43,0xc7,0x26,0x0e,0xa6,0x77,0xf7,0x53,0xa6,0x27,0xae,0xd0,0x8c,0xb9,0x6c,0x44,0x4e,0x29,0xbd,0xb5,0xb5,0x38,0x5d,0x43,0x84,0x3b,0xbe,0x79,0xa3,0xdd,0xa3,0x6e,0x1e,0x11,0x01,0xc5,0x0f,},"\xd1\xce\xa2\xb7\xe9\xaf\xc1\xf0\xfa\xb8\x90\xd2\x70\x0a\x5a\xe4\x1e\x15\xe7\xd3\x4d\x3b\xf1\x9d\x0f\x34\xd9\xf9\xf0\xab\x98\x12\xdc\x7c\x2a\x8d\xc4\x4c\x8e\xe7\xf3\x78\x87\x61\xec\xd9\x88\xee\x72\xc7\x36\xb6\x2a\x7c\xac\x3c\xc9\xb7\x38\xe9\x38\xdf\x77\x87\x37\x7e\xb9\xff\xd1\x20\xd4\xff\x58\xcf\x1c\x06\x75\x63\x3f\x7e\x83\xc4\xb1\x15\x54\x8f\x14\xd2\xf7\x0c\x6d\x48\x22\x11\x44\x3a\x84\x99\x59\x95\x58\xc1\x42\x77\x98\x0f\xa4\x2a\x78\x42\x79\x07\xf7\x3a\x41\xf5\xf6\x69\x3b\x2f\x75\xfe\x5e\x7a\x6f\xf0\xa6\xc3\xa4\xe2\xed\x1d\x0d\x96\x8d\x5c\xc9\xd6\xf1\x3d\x41\xc3\xd2\x91\x39\x6a\xe7\xe4\x34\xe6\x64\xb2\xff\x24\x3e\x7f\x6d\x88\x01\x02\x10\x07\x8c\x39\xb5\xa5\x76\xca\xf4\x09\xbb\x47\x11\xb3\xee\xfc\x48\x6b\x67\xb7\xff\xea\xe0\xcb\xac\x6a\x0f\xbd\xf5\x34\x3f\xb2\xae\x4e\x05\x7e\xdc\x8c\x9d\x2e\xd3\x1e\xae\x9e\xc8\x3d\x2b\xed\xd2\x19\xeb\x98\x9b\x2d\x44\x19\x61\x8c\x2d\x3c\xe4\x49\x0e\x35\xfb\xca\xd4\x32\xb0\x12\x47\x95\xf9\xc5\xcb\xdc\x1e\xb0\xc3\x07\x2b\x4a\xa8\x01\xd2\x6f\xbc\xc7\xb0\x7b\x82\x57\xf5\xfe\x47\xac\xd9\xbc\x58\x7b\x56\x57\xcf\x07\xca\x54\x5b\xb5\x68\xc9\xe4\xe7\x3c\xdd\xf6\x25\x4e\x22\xf7\x8a\xb2\xf8\x06\x45\x19\xf8\xab\xfd\x16\xfc\xfa\x90\xf8\x76\x87\xdb\x0c\x42\x09\xbe\x2c\x6c\x79\xa5\x52\x1f\x44\x18\x96\x78\xd9\x32\xc5\x45\x85\x70\x0a\x24\x37\x70\x2e\x56\xaa\xb5\x88\xa1\x7c\xb2\xcc\x94\xc0\x0e\x87\x57\x0e\xf3\xac\x51\x33\xd7\x53\x03\x8a\xa4\x65\x10\xa2\x60\xc1\xfe\x80\x47\x9b\xc0\x2e\xed\x9a\x8d\x1d\xe9\x93\x54\xac\x26\x48\xb4\x8b\x96\xab\x1b\x80\xcc\xa6\xca\xe1\x87\x7f\x37\xd7\x04\x28\xbb\x50\x85\x0e\x03\x08\xdb\x0b\x42\x30\x87\xbf\x7d\xde\x27\x9e\x09\x67\x66\xf2\xab\x3a\xb2\x38\x5b\x04\x64\xa5\xbe\xd7\xbb\xd8\xd4\x57\xe9\x35\xe2\x00\xaa\xaa\x8d\x95\x15\x70\xe0\x53\x07\x6d\xb1\x8a\x6a\x62\xf7\x2b\x31\x95\x79\x88\x4a\x08\x26\xba\x2b\x43\x63\x71\xdd\x21\x8b\x01\xa0\xc5\xe5\x8d\x0c\xd5\xff\x98\x25\xe4\x46\x6f\xe9\x66\xdf\x05\xcc\x31\xc8\x03\xe5\x21\x21\x83\xdd\xf2\x9c\xef\x7f\xb9\x16\x48\xa4\xf8\xee\x19\xfd\x5f\x8d\xbd\x8a\x56\xbe\x7a\xbf\x33\x65\x9a\x92\x24\xa1\xe2\x7a\x10\x24\xef\xfd\xfb\x88\xe8\x80\x61\x48\xd0\xd1\x78\x09\x06\xaf\x1e\xbe\x3e\x5f\x14\x36\x31\x90\xd8\x8c\xc6\xe5\x08\x94\x44\xf1\x25\xd0\x63\x15\x5d\xcf\x86\xca\x92\x63\xf2\xf5\xf1\x83\xc2\x69\x74\xfe\x00\x0b\x93\x42\xd2\x4c\x78\x1e\x20\x58\x28\x7c\xb6\xf3\xf1\xe3\x27\x0c\x22\xb7\x70\x7b\x83\x23\xa5\xcc\x8d\xb8\x1a\xa9\x06\xbb\x59\xd6\x96\xcb\x97\xcc\x74\xe3\x59\x59\x5f\xfb\x83\x73\xca\xd3\x71\x0e\xa0\x9e\xa9\x74\x4c\x20\xe9\xa1\x2e\x05\xbe\x5a\x95\xf0\x85\xac\x56\x16\x78\xd7\xda\x43\x2e\x4c\x7c\xb5\x3e\x12\x71\xdf\x5c\xd5\xa3\x39\xd2\xd7\x52\x0f\x1c\x18\x48\xd1\x50\x71\xd8\xc6\x98\x46\xb2\x3c\x5d\x24\x32\xc7\x38\x90\xf2\xed\xed\x37\xc3\xd2\x96\x4a\x4b\x5b\x55\x22\x58\x88\xe8\x92\xf5\x26\xd1\xca\xc3\x1e\xac\x35\x6f\x36\x1c\x2b\xf3\x36\xc4\x62\xd6\x0c\x82\xe8\x2b\x61\x6f\x2a\x51\x9c\x2f\x67\xbf\x01\x29\x03\x69\xbe\x9b\x55\xe9\xf5\xc8\xce\xc4\xf2\xe1\xb2\xab\x30\x25\x06\xc9\x03\xdc\x3e\x7b\x9c\x97\x81\x41\xdc\x90\x4b\x01\xb1\xc2\x3d\x25\x00\x43\x99\xbf\x8b\x73\xd6\x9c\xd5\x39\xc7\x9a\xf5\xe9\xa0\xa5\x11\xec\xa2\x21\x07\x8a\x1f\xf7\xb0\xf6\x04\xae\xa8\x42\x46\xc3\xcb\x32\xdb\x93\x81\xbe\x12\x17\x67\xe0\x97\xbe\xa5\x17\xbf\xcd\x82\xdf\xe9\x21\x37\x98\x40\xef\xb4\xb6\xf0\x2a\x48\xec\xda\xf1\x2d\x2c\xd3\x89\x30\xd4\x47\x3a\xdf\x97\xcd\x71\xdc\x4e\xa1\x03\x82\xf4\xf5\xd1\xdd\x75\x62\xcd\x4b\xf5\x11\x59\x32\xf6\xc4\x70\x0a\xa8\xfe\x8d\xec\xa9\xd5\xe7\x27\x79\x02\xb8\xf8\x86\x52\x97\x65\xdb\x24\x86\x07\x4b\x23\xa1\x9f\xd4\xb0\x43\x56\xbf\xa6\x22\x6c\x82\xba\xf6\x9a\x08\x7d\x9c\xa1\x88\x23\xf8\xe3\xe6\x83\x08\xe1\x6b\x80\x4c\x36\x3d\xf5\xb6\x30\x7e\x76\x24\x0d\xb1\xed\x84\x1b\x61\x2d\x65\x54\x8d\xdf\xbe\x83\x67\xda\x60\x77\x2c\x6a\xff\x55\x4d\xc8\x5d\x04\x19\x48\x34\x5e\x56\x7d\xa9\x33\x31\x51\x85\x8f\xdf\x69\x93\x27\x39\x25\xbf\xdc\x71\x81\xb5\xf6\x46\xd0\x63\xa8\xc8\xf3\x10\x56\x9b\x0e\xd0\x93\xbd\x9d\xff\x04\xfe\xbf\x0b\x41\xc6\xdc\x55\x16\x9a\x14\xa3\xc8\x62\xe5\x41\x6f\x1e\x58\x2f\xde\xe8\xfe\x87\xdc"}, -{{0xbf,0x3c,0x0c,0xbb,0xbe,0x20,0xbe,0x2a,0xcf,0xaf,0xb2,0x7a,0x36,0x11,0xb4,0x89,0x21,0xa7,0x28,0xab,0x17,0x33,0x4b,0x8a,0xfd,0xee,0x83,0x05,0x17,0x8f,0x61,0x3b,},{0x45,0x00,0xa0,0x3c,0x3a,0x3f,0xc7,0x8a,0xc7,0x9d,0x0c,0x6e,0x03,0xdf,0xc2,0x7c,0xfc,0x36,0x16,0xa4,0x2e,0xd2,0xc8,0xc1,0x87,0x88,0x6d,0x4e,0x6e,0x0c,0x27,0xfd,},{0x8f,0x87,0x03,0xbc,0xf4,0xc0,0x32,0x94,0x17,0x33,0x9e,0xb0,0x26,0xf2,0xb7,0x2d,0x31,0x4d,0x92,0x2e,0x9a,0xcc,0xb5,0xd8,0xbb,0x7e,0xec,0x87,0xe0,0x7e,0x61,0x38,0x55,0x16,0x72,0xa6,0x13,0x2c,0xb4,0xf8,0x75,0x50,0x8e,0xd3,0x29,0x95,0x67,0xb4,0xa7,0x41,0x34,0xd2,0xbd,0xf0,0xd8,0x57,0xf9,0x80,0x86,0x1d,0x18,0xbe,0x7e,0x01,},"\x8f\x30\xba\x2f\x79\x2e\x9a\x97\xf6\xea\xfe\x29\xf9\x76\xa4\x80\x28\xcb\x88\x57\xb5\xc7\x98\xbc\x2b\x61\x68\xc4\x64\x44\xc0\xce\x69\x60\x70\x37\x4c\x5e\x6a\x40\xc3\xd1\x8a\x5d\xc7\x66\x9f\xc4\x1d\xb9\xa8\x1c\xff\x75\x9b\x8c\xa0\x15\x98\x71\xc3\x44\x2e\x8c\x75\x12\x69\x8f\xa4\x47\xb5\x78\x3e\xe0\x1d\x1b\x61\x14\x49\xab\xad\x23\x71\x62\x92\x2b\x02\xd1\xae\xc5\xde\x1d\x66\x6f\x17\xda\x16\x13\x10\x63\x01\xd3\x05\x86\xd1\x16\xe2\xac\x09\x00\x7d\xd7\x1e\x81\x23\xed\xe4\xc5\xa6\xa9\xac\x07\x7f\xe3\xd9\x39\x09\xda\x62\x8e\x86\x58\x70\xa4\xe2\x5c\xb3\x55\x91\x67\x5a\x06\x90\xbe\xc4\xaf\x02\x81\x71\x4f\xe6\x66\x1b\xd5\xc0\x0a\x27\xd7\x9f\x95\x9f\xb4\xd4\xfb\x16\x36\xa6\xa3\x57\x5f\x4f\x01\x47\x06\x63\x89\x9d\x73\x74\x72\xb0\x96\xbe\x4d\xb7\x23\x71\x53\x67\xa4\x1a\x3a\x4c\x13\xf7\x42\xd9\x08\xf4\xd9\x21\xcf\xdd\x15\x6e\x75\x86\x82\x61\xba\x9c\x10\xd8\x58\x74\xca\x2d\x6c\x0c\x9e\x72\x95\xe5\x66\x2b\xd9\x16\xa3\x63\xc7\xa7\x96\xea\xd6\x17\xc4\x25\x1e\x67\x94\xda\x06\xc3\xd0\x8f\x2f\xdc\x38\x86\x94\x4a\x75\x09\xe6\x40\x9c\x90\x6b\x59\x31\x13\xb4\xb1\xf9\x85\x01\x32\x96\x0d\x9f\x3a\x4e\xeb\x73\x86\xfa\x59\x2f\x61\x93\xbe\xab\x8e\x0f\xf0\xf2\x89\x08\xa0\xd5\x48\xdb\x87\xba\xe9\x78\xb0\x5a\xbb\xca\x9b\x3e\x96\xd8\x79\x5b\x88\x07\x7f\x62\x0f\x21\x24\xe3\x15\x90\xeb\x09\x9e\x94\xe0\xe6\xe3\xcd\x62\x0a\xe6\x29\x0f\x3e\x2d\x01\x46\x7e\x5b\xef\x4f\xab\xde\xf7\x9d\x9a\xb9\x23\x9e\x75\x3e\xc4\xfa\x0b\xb1\x10\xff\x1d\x39\x3f\xca\x02\x24\x35\x02\xd7\xe9\x87\x99\x1e\xb7\x6d\x08\xf8\xbe\x7e\xb2\xb1\xee\x00\xc3\xb6\x8b\xbf\x72\xa6\x23\xba\xa1\x5b\xe8\x96\xb3\x21\x5e\xbe\x8a\x82\x31\x31\x09\xfc\x62\x9b\x0c\xce\x64\x91\xf8\x13\xc2\x49\x70\xe4\xff\xe6\x86\x9e\x40\xb4\x6b\x4e\xd2\x29\x86\xd0\x04\x21\x55\x27\x6c\x23\x0d\xe4\xc0\x5d\x67\x85\x52\xf2\xe8\x51\xca\xcf\x5a\x47\x21\x57\xdb\xb1\xa9\x9a\x2b\x42\xff\x40\x37\xf0\xdc\x63\x80\x67\x29\x21\xc9\x09\x20\x6e\x80\x05\x0e\x61\xa6\xb3\x05\x6b\x17\xe3\xae\x83\x50\x09\xb2\x04\x19\xa3\xb9\x84\x6d\x37\x48\x92\xe7\x19\xf1\xb3\x5b\xc1\x25\x7d\xa9\x3c\xcc\x6d\x8f\x8f\xca\xa8\xe6\x09\xa8\xd2\x04\xdf\x10\x8b\xe7\x19\x34\x67\xe7\xf1\x05\x93\x52\x82\xc3\xfe\x66\x70\xa5\x32\x94\x42\xea\x3e\xdd\xa2\x37\x6a\x03\xa1\xcf\xe8\x72\x3a\x90\x9c\x06\x4d\x30\xfe\x9b\xb0\x21\x2c\x33\xaf\xe2\xbe\xa3\x0c\x91\x43\xc0\x01\xda\x01\xc7\xed\x50\x45\x59\xb9\x7f\xe2\xce\xa0\x9b\xeb\x9d\xb5\x19\x00\xdc\x13\x67\x05\x92\x1e\x20\x29\x78\x45\xba\x72\xa9\x7a\xa7\xc9\x53\x81\x45\x71\xbe\x3f\x08\xce\xf9\x68\x04\x5a\x5a\xc3\x40\x04\xf6\x7f\xbf\xa5\x4e\x99\x6b\x31\x1b\xd8\xdc\x52\x7d\x89\xe1\xd4\xf5\x34\x53\xa6\x71\x37\x20\x10\x1c\x45\xa6\x0e\xe3\xa0\x5c\x2e\xe6\x6f\x13\x4b\x5a\xf4\x0e\x4b\x70\xef\x37\xba\x3f\x0a\xfd\xef\xc0\x39\xf3\x42\xc2\x8a\xf9\x19\x82\x51\x38\x1a\x10\x79\xa5\xdd\x03\x5a\x8c\x28\x97\x6c\x6b\x7f\x4d\xb0\x9e\xa3\x83\xa3\xa8\x7f\x0f\x85\x1f\xd3\x31\xae\xa7\xfa\x4b\xfc\xd9\x56\x31\xd6\x52\xfa\x2f\x50\xf1\xc2\x3f\xf2\xbc\x13\x7a\x06\x04\xe3\xd9\xf3\x9c\xcb\x96\x51\x45\xbc\xa4\x8b\x06\xdc\x8a\x81\x75\x47\xb6\x25\xef\xfa\x79\x6d\x00\x0c\x37\x74\xba\xd1\x98\xdb\x12\x41\xbe\x7a\x2c\x0d\xc4\xa4\x64\x1b\x9a\x8c\xb9\xcb\x8c\x8c\x38\x87\x57\x6f\x52\x72\xc3\x3a\xaf\xfe\x45\x61\x5f\x51\xa9\x6f\xae\x76\xcf\x51\x25\xbc\x69\xad\x0a\x40\x38\x79\x07\x99\xb5\xc2\x62\x44\x21\xa6\x43\x3d\xba\xb3\x9c\xcc\xb0\xb1\x78\x7b\x5b\xce\x28\x95\x94\x48\x9d\x17\xed\xb5\xf9\x31\x03\x74\x80\x7d\x36\xc6\xe6\x73\x47\x26\xbb\x33\x00\x4e\xca\xe8\xbb\x69\x1d\xcd\x38\x76\x01\xf4\xea\x91\x1b\x4b\x90\xeb\xff\x75\x6d\x7d\x8d\x9e\xb4\x22\xcb\xb9\xaa\xf7\xf4\x77\x2e\x0a\x54\x36\x43\x06\x85\xe5\x7b\x69\x74\x54\xe8\x2e\xea\xdc\xe4\xab\xa0\x62\xb7\x76\x82\xcf\x21\x9b\xe1\xfd\x9b\x00\xf1\xcb\x11\x35\xa1\x02\x13\x49\x53\x9a\x4b\x93\xae\x21\x3f\x19\x3d\x29\x32\x73\x8e\xf7\x29\x20\x49\x9b\x7b\xe2\xa8\x1c\x9b\xaa\xed\x17\xc5\x46\x41\xa5\x97\x4d\x27\x22\x32\x41\xe3\xc6\xa0\x95\x22\x6b\xd2\x37\xe0\x59\x1e\x00\x2b\x3a\xf0\x56\x5d\xf3\xe9\x76\x42\x0f\x97\x64\xa0\x9a\xe8\xbf\xa2\x79\x5f\x8f\xad\x7f\xc6\x87\xbd\x2d\xe2\x3d\x14\x88\xf4\x49\xd8"}, -{{0x28,0x7f,0xaf,0xd2,0x13,0x74,0x57,0x2f,0x57,0x81,0x00,0x47,0xd0,0xd9,0x8c,0xb1,0xff,0x3d,0x01,0x20,0xfa,0xa4,0x88,0x61,0x32,0x24,0x57,0x32,0xc1,0xa6,0xab,0x78,},{0xe8,0x25,0x20,0x63,0xf5,0xad,0x7e,0x95,0xbd,0x05,0xc5,0x02,0xa8,0xbc,0x4a,0x17,0x55,0x63,0x60,0x86,0x9b,0x9d,0xe0,0xa3,0xb8,0x58,0x93,0x8e,0x11,0x11,0x76,0x19,},{0x62,0x01,0xe3,0x05,0x91,0xd3,0x6b,0x7b,0x22,0x6e,0x36,0xfd,0xf5,0x64,0x34,0xc4,0x7c,0xd3,0x05,0x18,0x37,0xaf,0x31,0x31,0x3a,0x99,0x17,0xfd,0x02,0xdd,0xed,0x2b,0x5b,0xbb,0x4b,0xbc,0x36,0x8b,0x3b,0xd1,0x5d,0x06,0x20,0x45,0xf1,0x05,0xb6,0xe7,0x34,0x1b,0x15,0x15,0x0d,0x36,0xf9,0x00,0x87,0x59,0x1d,0x83,0x99,0x01,0xb8,0x01,},"\xb3\xc4\x43\xe4\xe5\x89\x9c\x16\xd3\x9e\x81\xb4\xf8\x07\x40\x42\xa9\x04\xa7\x35\x07\x4b\x27\x95\xd9\xac\x06\xb1\x37\x9e\xf7\x61\x8d\x2a\x53\x4b\x6b\xef\x81\x56\x9e\x60\x71\x92\x67\xbf\x29\xcd\x9d\x16\xac\xc9\xa1\x74\xd8\x02\x6b\x14\xb1\x27\xd0\xd2\xd8\xb4\x58\x39\x98\x89\x5a\xd7\xef\x72\xfe\xdc\x53\xb8\xf0\x8a\x22\x50\x10\x0e\x1f\x1f\x0a\xab\x48\xbc\x70\x74\x64\x34\x88\xe6\xb6\x70\xe1\xb0\x72\x7c\x38\x5a\x34\xff\x65\xa0\xd7\xe8\x3b\xa8\x60\x83\xb8\x73\xdf\xf0\x55\x92\x09\xb1\x4b\x2a\xc4\x2b\xf7\xc5\x72\xd0\xc5\x91\x7a\xc4\x2e\x4a\xe4\xda\xe1\xdd\x42\x35\x79\x52\x76\xa0\x76\x13\x2c\xfe\x3e\x0c\x35\x0b\x26\x58\x0f\xbb\x3a\xf8\x17\x77\xb9\x3a\xd9\x5c\xb7\xff\x17\xc2\xd9\x80\xce\x0d\x49\x2f\x6d\x40\xfa\x90\xba\x3f\xca\xa2\x1b\xb6\x87\x35\xee\x1e\xf2\x08\x49\x5e\xbf\x7b\x02\x27\x6f\xfa\x1e\xfc\x08\x16\x58\xbb\x44\xcd\x27\x61\xef\x5e\x3e\x1c\xa6\x0e\xc8\xb5\xd8\x16\xd4\xab\xac\xd0\xbc\xc8\x02\x68\xd8\xf4\xdf\x8b\x3a\x52\x04\x9d\xb0\x15\x7e\x2b\x6e\x81\xac\xd6\xf3\xf2\x89\x47\xc0\x76\x27\x95\x5c\xda\xc9\xea\xa1\xde\x17\xd4\xb9\xda\xa3\x61\xfb\x49\x78\x26\x64\xd7\xd6\xd2\xca\x5c\xec\x6d\x14\x89\x3c\x3e\x80\xb6\xd1\x6d\xaa\xcf\xfc\xc0\xb7\x59\x37\xe8\xbe\xf6\xf9\xe1\x12\xa8\x7f\x4b\x03\x5f\x90\x36\x07\x0a\x2c\xcc\x55\xc2\xaa\xd9\x39\xdf\x67\x4f\x7e\x4e\x12\x68\x5e\x01\x6e\xa0\xe4\x90\x2a\xaa\xaf\xaf\xfe\x38\xdd\xb2\xf9\x0d\x9c\xf7\x85\x37\xf6\x13\x91\x69\x6f\xf0\x33\x0a\xe8\xf7\x9a\x1c\x1e\xd5\xd5\x2b\x4e\xe2\xa6\x2d\x90\xfb\x82\xd9\xa4\x83\x93\xfa\x33\x81\x0b\x40\xd0\x45\x59\x02\xd5\x74\xff\x05\x20\x03\xe0\x16\x0c\x0f\x47\xb5\xe5\x80\xa0\x78\xbc\xee\xf0\x60\x73\xdd\xa8\xb2\xd1\xf1\x04\xa5\x95\xe9\x0b\xb6\xa4\x8e\xdd\xd8\x65\xf1\xca\xe4\xf1\x78\xfe\x22\xe7\x5f\x2f\x61\x24\xa9\xda\x06\x82\x44\x71\x12\xb3\xdb\x5b\xe8\xc4\x24\x72\xb2\x41\xe9\x44\xfd\x23\x70\xc2\xdc\x27\x15\xc0\x5a\x41\xbd\xbc\x89\x0c\x41\xc6\x5f\xb0\x8c\x2f\x59\x31\x74\x39\x1a\xc8\x80\xf3\xcb\x67\xd1\xb7\x4f\xf8\x02\xef\x96\x2a\xfe\xf7\xb9\xf3\xea\x32\x6f\x95\x27\xe7\xfb\xa6\x98\x18\x79\x24\xb6\x4c\xcd\xd0\x86\x62\x48\xc7\x6e\xe6\x4c\x79\x06\x9b\xe0\xa0\x57\xb1\x0a\xe1\x90\xf3\x8f\xf5\xab\xa8\x44\xe3\x93\x31\xcf\x1d\xb1\x3c\x90\x09\x06\xbe\xe0\xd7\xe7\x54\x6e\xf5\x23\x24\xe3\x7c\x59\x06\x75\xf1\x39\xf5\x8f\x57\x3a\x49\x4f\x4a\xe8\x2c\x4e\xc8\x10\x66\xa6\x8e\x2d\x92\x90\x01\x91\xc4\x7d\x30\x62\xf0\xf9\xaa\xed\x19\x11\x37\xcd\xa9\xb8\x3c\xd1\x30\xe8\x26\x29\x60\xe6\x24\x4f\x8f\x6e\xf3\x9f\x15\xa4\xfe\xd1\x3c\xb6\x69\xed\xc1\x9f\x5c\xe1\x62\xce\xb8\xd2\x42\xb9\xad\xdb\xfb\xa8\x77\x2c\xe7\x49\x85\xa5\xf3\x72\x0d\x59\x0a\x92\x0e\x1d\xca\x75\xa8\x79\xb1\xaa\x45\x9f\x74\x62\xff\xf2\xe9\x50\x72\x76\x1b\x20\x92\x54\xfe\x38\xc5\x4d\x83\x3a\x8e\x2c\xb8\xfc\x40\xc5\x98\xf3\xc7\xf7\xd6\xc5\x70\x57\x15\xd0\x30\x8d\xc3\x0e\xaa\x84\x67\x6d\x20\x9d\x7b\x7b\x31\x34\x47\x56\xe6\x9a\x9a\x4c\xb4\xe4\xa2\x51\x81\x7a\x37\x86\xfe\xa6\x72\x8d\xd6\x08\x22\x33\x6b\x45\xae\x5d\x47\xc7\x04\xb4\x5c\x4c\xad\x38\xc1\xe0\x1a\xb9\x3d\x14\x16\x92\xd5\x5d\x12\xfd\xb9\x74\x0f\x1d\x18\x15\x82\xf1\xc4\x8c\xe5\x43\x48\x60\xd9\x30\xf0\xe7\xe7\x0e\xdc\xff\xb8\x55\x60\xa5\x3d\xba\x95\xd5\x7b\x31\xe8\x92\x41\x37\xbc\x2c\x19\xe3\x4b\xb9\xc9\x86\x68\x77\x17\x42\x80\xe8\x0c\x23\x97\x8d\x57\x79\x58\x64\xa7\x37\x4a\xef\x38\x3f\x3b\xf6\x37\x53\x59\xbf\x63\x56\x47\x40\x09\x84\x61\xa6\xc7\x6e\x8f\x23\x89\x13\x28\x87\x69\xa1\xcb\x1c\x95\xb2\x2c\x32\xa9\xeb\xb3\xec\xeb\x04\x8e\xe3\x24\xcf\x0d\x7e\x85\xa3\x89\xb0\x4d\xed\xbb\xcb\xee\xf2\x98\xd0\x52\x78\x16\x08\x5c\x0c\x83\xef\xaa\x29\x85\x46\xe8\x39\x0b\xd1\xbf\xe4\x65\xec\x1b\xaf\xae\x69\xee\x52\x18\xe7\x2c\xae\xdb\x9b\x64\x9c\xf7\x3e\xec\x45\x4a\x2b\x48\x49\x65\x17\x96\x72\xde\xbc\xf9\x44\x13\x63\x99\x5a\x8a\x90\x7d\xe1\x7d\xc0\x68\x4f\x2a\xea\x57\x9a\x2f\xb4\x48\x41\x95\xdb\x41\x15\xca\x32\xe9\x70\x52\x6d\xc0\x0a\x5c\xac\xaf\x58\x87\x11\xdb\xd4\x69\xce\x80\xbd\x29\x7c\x4f\x41\xd6\xfa\x28\xa5\x97\xc6\x37\x2c\x0d\x21\x49\x60\xb5\x45\x98\xcd\x8b\xc8\x49\xeb\xdc\xa3\x6d\x62\x25\xb2\x0d\xec\x0d\x03\x11\x69\xce\xbb\x36\xea\xdc\x3a"}, -{{0x9a,0xd0,0x49,0x10,0x08,0x51,0xd0,0xf7,0x9b,0x71,0x12,0x25,0xc9,0x88,0x47,0x79,0x5a,0xcf,0xc3,0x60,0x1c,0x14,0xb8,0xa9,0x77,0x8d,0x62,0x70,0xcd,0x4c,0x05,0xed,},{0xe7,0xca,0xcf,0x4f,0x37,0x14,0x54,0x3c,0x27,0xa3,0xe9,0xed,0x83,0x3b,0xaf,0x3b,0xde,0x4c,0x09,0x56,0x3b,0xef,0x59,0xe7,0x63,0xfa,0xb7,0x1f,0xb5,0xe4,0xff,0x56,},{0xfe,0xc0,0xaf,0x34,0xcb,0xc5,0xcf,0xfc,0x56,0xe9,0x6d,0xd5,0xed,0x59,0x68,0xe5,0x2c,0xbd,0x42,0x69,0x84,0x4f,0xc3,0x0e,0x3a,0xb0,0xd3,0x47,0x2b,0x5d,0x18,0x0c,0x8d,0x1b,0x76,0x90,0x51,0x8f,0x41,0xf1,0x44,0x38,0xe7,0xf3,0xa8,0x3d,0x5e,0x89,0x76,0xcb,0x9a,0x26,0x15,0x1f,0xc4,0x14,0x9a,0x32,0x98,0xd7,0xe4,0x2c,0x05,0x03,},"\xc2\x84\xbd\xd8\xf8\x27\x5b\x49\xac\x80\x8c\x39\x04\x5e\x50\xe1\xed\x50\xc8\xa1\xaf\xd0\x11\xaf\xe5\xdb\x3d\xda\x62\x0b\xe8\xae\xc3\x7f\x45\x60\x57\x62\xe2\x25\xd0\x41\x11\xf2\x1b\x49\xfc\xef\xca\x3f\x3d\x5f\x81\x3b\x20\x20\xa5\x2c\x49\xf9\x5c\x4a\xd6\x1c\xa2\x14\x61\x8a\xde\x7e\xed\x6c\xd8\xd3\x14\xdc\x4c\x63\x55\x95\x52\x77\xd4\x57\x46\x2f\x03\xb9\xfb\xa2\xe2\x25\xb1\xb5\x37\xcd\x4b\x52\x37\x50\x5c\x90\xd4\x32\x05\xe1\x71\x5c\x39\x63\xcc\xfb\xec\x37\x9e\x6c\x17\x05\xe0\x80\x34\xa3\x1a\xfc\xe6\x46\x72\x7e\x78\xa2\x0e\xed\x88\xae\xb0\xdc\xda\xbc\x5c\x86\xe8\x69\x79\xe6\x3a\x5c\x26\xc3\xe2\x17\x79\x73\xb6\x98\x3c\xeb\xfe\xda\x9f\x31\x47\x93\x61\xb6\x61\x76\x3a\xa7\x26\x1c\x09\x39\xca\xd4\x8b\x71\x90\x8e\xa9\x07\x68\xbb\x6c\x95\x83\xd8\xea\xeb\x9e\x03\x38\x51\x5a\xca\x12\x42\x62\x6d\xc6\xbe\x04\xec\xc4\x42\x9e\x4c\xbb\x4f\xf3\x36\x09\x61\x92\xf7\x50\x1e\xc4\x71\xb5\x96\xa9\x9d\x4c\x02\x75\x82\xcc\x69\xe2\x04\xb6\xfb\xcd\xdf\x59\xf5\xbf\x74\x62\xdd\xcd\x59\x89\x12\x1f\xd1\x0f\x11\xa0\x67\x5b\x6c\x4e\x4f\x65\x20\xd2\x7d\x7c\x61\x43\x1b\xa7\xd1\x74\xf5\x73\x95\xa0\xbf\x72\xd3\x8c\x11\x42\x73\x6d\xed\x6b\x91\xe4\x81\x1c\x0e\x85\x41\xa6\xc0\xd9\x96\xc5\xa1\x7d\xc9\x7d\xb3\x88\xf7\x21\xd2\x35\x7d\x3c\x6a\xf5\xc8\x6b\x1d\x5e\x47\x6e\xa0\xac\x0b\x1c\x11\xd4\x38\x7f\x76\x90\x39\xbd\xf5\x38\xa0\x21\x6e\xdd\x00\x45\xee\x6d\xd8\x9e\xef\x82\xa4\x25\xa8\x3f\xaa\x1b\x12\x80\x70\x38\xca\x19\xeb\xec\x00\x2e\x8b\x3c\x15\x34\x4c\x61\xcf\xd1\xe5\xf0\xe3\xb0\x27\x3d\xeb\x37\x27\x8c\xf1\x97\xd8\xa8\x3b\x13\xd9\x92\x30\x8a\x51\x37\x3e\xb3\x81\x14\xc9\xe4\x5b\x43\x87\x80\x27\x7d\x1e\x32\xf3\x97\x29\x62\xa3\xe1\x4a\x8d\x08\xdb\x9f\x09\xae\xc3\xdd\x32\xa5\xb9\x94\x23\xe6\x1f\x5e\x79\x94\x4a\xb5\x7a\x36\xf6\xec\x07\xcc\x32\x04\xf9\x16\x5e\xe0\x21\xad\xa9\x3e\x6f\xec\xb7\xec\x45\x6a\xa0\x28\x8c\x37\x8a\x75\xaf\xd6\xe9\xda\xd6\xc6\xf8\x8e\x95\x9a\x2c\xf2\x8b\xfe\x56\xd2\xe6\x1b\x2a\xda\xec\xf0\xd8\x6d\xd8\x92\x8b\xce\xda\x26\xb0\x54\x02\x46\xb7\x33\x7f\x5c\xdc\xec\x11\xfb\x0c\x1a\x59\xd6\x31\xfc\xca\x19\x40\x8f\x95\x22\xb6\x8a\x39\xf8\x6e\xf9\x70\xb8\x83\xa0\xf0\xbd\x6b\x7b\x14\x15\xec\x9a\xa0\x43\xb5\x2e\x19\xba\xc1\x76\xd6\x7b\x79\xe2\xa5\xdc\xa8\xbf\xd2\x91\x02\xac\x60\x8e\x47\x3e\x9f\x98\x2c\x3e\xc8\x93\x2d\x8a\xa8\xcd\x56\x52\x84\x49\x1d\xe5\x2f\x51\x6b\x9e\xbf\xb7\xdb\xe1\x29\x95\x11\xae\x73\x2c\x2a\xd1\xee\x49\x92\xb0\x77\xfa\xff\xc6\x5f\x48\x8f\x1b\xa2\x15\xda\x69\x79\x60\x09\x71\x19\x6d\x0f\xf3\xa0\x8a\xd9\xf0\x0e\x82\x9c\x1d\xe1\xaf\xca\x10\xca\x47\x6b\xe6\x64\xaa\xd2\x61\x88\x9b\x0e\xb7\xae\xb6\xed\x86\x37\x61\x89\x00\xac\xf4\x81\xe2\xd2\x24\xec\x64\xa6\xe6\xcf\x4f\xa4\xdf\x73\x1b\x7a\x4f\xee\xff\x25\x80\xc9\x9b\x6d\x75\xb4\xdc\xd0\x97\x69\x65\xcb\x2b\x0b\x56\x35\x22\x78\x42\xd0\x8a\x7d\x90\x7a\xae\xbc\x2f\xde\xd8\x00\x98\x11\xdc\xdd\x73\x35\x49\x21\x75\x3b\xc5\xde\xc0\x17\x68\x93\x35\xf5\x6d\x0f\xb7\xae\x21\x3b\x41\x79\x2b\x1f\x4e\xb1\x4a\x24\x53\x59\x77\xa3\x05\xb1\x9e\xb9\x83\x8d\xc6\xb5\x15\x28\xb9\x8a\x39\xbd\xa0\x60\x10\x71\x7a\x20\x8c\x34\x7a\xa1\x58\xee\xcd\xfd\x9a\x04\x72\xd3\xb8\xd9\x20\xf9\x69\xe1\x2b\x65\x91\x9b\xda\x38\xb4\x61\x94\x98\x50\xcc\x9c\xc1\x8d\x8e\x3b\xaa\x8c\x88\x6d\x93\xcd\x09\x6a\x20\x9d\x54\x3c\xa3\x37\x5f\xc4\xe7\xd6\x51\x03\xcb\x64\x24\xbe\xab\x44\xe8\xbc\x4a\x5b\x62\xc2\x9a\x01\xbc\xf4\x4d\xcc\x61\xe7\x67\x5c\x02\x5d\xec\x07\x24\x20\x01\x94\xbd\xe7\x4d\x72\xc0\x2e\x94\xa9\x46\xa7\x52\xf3\x60\x84\x57\xfd\x91\xf2\x92\x71\x57\x71\x48\x7d\x26\xca\xd4\xe5\xcf\x6e\xf7\xc6\xf7\x16\x27\xa4\xda\xf8\xa4\xc9\xb8\x91\xc1\xee\x8f\x04\xae\xaa\x99\xfe\x0c\x8b\x4e\x83\x3b\x76\x09\x06\x6b\x61\x32\xa9\x68\x89\x0e\x26\x95\xda\x22\xb2\xd8\x57\xc8\xc0\xad\x91\x87\xc9\x60\x69\xe4\x76\xe2\x7e\x46\x32\xc4\x47\xee\x76\x71\x4a\x31\xd1\xe5\x14\x9e\xcb\x33\x7e\xe1\x32\xf3\x55\x2d\xa3\x3a\xb2\xd6\xfa\x9d\x7e\x93\xf6\x8a\x77\xcb\xf1\x91\xcb\x06\xbc\x22\xf3\x47\x0a\xf6\xd7\x58\x1e\x3a\xcc\xbe\xca\x0b\x6f\xeb\x08\xa1\x4b\x9a\x80\xc1\xef\x59\x37\x4c\xcd\xc0\x52\x3c\x36\x84\x50\x4c\x01\x04\xbb\xa2\x2c\x10"}, -{{0xde,0x54,0xe1,0x3f,0x9e,0x2c,0xc7,0x54,0x54,0x6c,0x99,0xb3,0x3b,0x3d,0x72,0xf4,0xd1,0xf7,0x71,0x50,0x38,0xa9,0x65,0x9f,0x33,0x63,0x65,0x77,0xbb,0x52,0x6a,0xdb,},{0x36,0x33,0x8d,0xb3,0x32,0x6b,0x00,0x5e,0x5c,0x61,0xff,0x78,0x2b,0xe2,0xea,0xb1,0x66,0xd4,0xeb,0x72,0x34,0xa9,0x8e,0xa1,0xcd,0x85,0x5e,0x1a,0xd5,0x35,0xe9,0x4c,},{0x37,0xac,0xa8,0xf2,0x48,0x39,0x4a,0x9e,0x04,0xd0,0x6a,0x7d,0xa8,0x4a,0x7d,0xef,0xa3,0x9d,0xe4,0xda,0x2b,0xcb,0x18,0xd5,0xf6,0x4c,0xc3,0x4d,0xb0,0x86,0x51,0xaf,0x4a,0xbb,0x19,0xfa,0x2a,0x92,0xa7,0xdd,0xa5,0x6e,0xc9,0x93,0x0b,0x81,0xae,0xbd,0x23,0x99,0x05,0x11,0xf6,0x84,0xc6,0xd1,0x5b,0xa5,0x95,0xf7,0xd4,0xa2,0x74,0x0e,},"\xdc\x40\x41\xad\x61\x42\x3a\x12\xa0\x41\x13\x18\xa6\xe6\x2a\x5e\xf6\x4a\x19\xab\xe2\xd9\x85\x22\x97\xbe\x2d\x4a\x35\xeb\x86\x70\xca\x36\xc5\x21\x53\x1b\x30\x38\xac\xda\xee\xa2\xea\x01\xa0\xb6\x18\x78\x62\xa4\xe1\xa8\x9d\x4b\x81\xc5\x31\x8e\xd4\xd6\x71\x31\xbc\x38\xf8\x41\xa1\x42\xa2\xf6\xf3\x16\xdf\xf0\x76\x93\x9d\xc0\xeb\x81\xb2\x30\xfe\xa9\x88\x1f\x8f\x0f\xf7\xed\x0b\x29\x3f\x69\xb2\x89\xfe\x77\x08\x81\xfb\x37\x10\x80\x8e\x8e\x59\xe6\x4e\x19\x0c\x1e\x37\x9b\x9d\xd3\x48\xb0\x2c\x23\x47\xd7\xe2\x06\x96\x79\x0b\x62\x77\x6a\x2e\x82\x5b\xed\x69\x17\x03\x7c\xb6\x35\xc9\x2f\xbc\x76\xb4\xc5\x85\x10\x27\xe7\xf1\x38\x52\xee\x7e\x7c\x52\x57\x3a\x90\x30\xb7\x9f\x22\xb6\x0d\x58\x69\xef\xe6\x80\xc0\x16\x64\x92\x9f\xe9\xa0\x6f\xa3\x33\x05\x2b\xe1\xd6\xaf\x3a\x0b\x48\x2c\x33\x2e\x18\x05\x1e\x78\xb3\x33\x83\x9d\x6c\xb9\x3d\x93\xeb\xfb\x27\x7e\x42\x68\xfb\xee\xee\xba\x1e\x8f\x96\xa5\xc9\xe3\x28\xc4\x26\x72\x12\xca\xc2\x51\x21\x5b\xfa\xa7\x8f\xd8\x8a\x87\x41\x7a\x80\x60\x2d\xcd\x88\x28\xe8\x04\x00\xda\x30\x4e\x98\x98\x62\xd1\x32\x01\x08\x2d\xe3\x53\x09\x25\xe0\xed\xc2\xc1\x30\xa9\xa4\x19\x07\x1b\x31\x08\x8d\xa6\xf6\xff\x40\x56\x30\x1c\x12\x9f\xc2\x13\x52\x33\x62\x8d\x16\xd8\xbf\x16\x0f\x6c\xe8\x6d\x83\xcd\x4e\x29\xae\x0c\x73\x84\x3d\x70\xb5\x30\x56\xc5\xaf\x3f\x3d\xc5\x61\x27\x1c\xb5\xaf\xf3\x93\xf0\x80\x3a\xde\x07\x2d\x9c\xeb\x74\x5b\x61\x87\xb2\x8d\x24\x69\x67\x67\xd5\xc2\x1f\x4d\x4a\xc5\x8d\x5b\xb6\x6c\x5c\xad\xfe\xfb\x16\x26\xef\x93\xf7\x14\xc7\x82\xb6\xef\x3c\xcf\x4b\x44\xee\x75\xf0\xbb\x75\x7a\x25\xd9\xb4\x6a\x9d\x93\x1a\x03\x72\x7d\x49\x6a\x22\x81\x0c\x63\x4f\x5c\x1a\xe6\x0c\xbd\xf2\xf1\xea\x29\xb5\x46\x07\xcf\xf5\x0d\x9f\x8e\x03\xa0\xa4\x51\x3c\xf6\x8d\xfb\x61\x97\x73\x41\x1b\x61\x80\x95\x9a\x8a\xac\x30\xb2\xee\xe4\xad\x32\x79\x15\xf6\x0a\xe5\x2b\x90\xe0\x4a\x9b\xce\xf8\xdc\x67\xe7\x1e\xa1\x0a\xca\x55\x3d\xb9\x89\x5c\xd8\x00\x84\x57\xd7\x6f\x02\xce\xb5\x35\x00\x21\x11\x09\xe8\x96\x03\xf3\x04\xd8\x80\xaa\xf0\x28\x61\xfe\x37\xc9\x53\x4a\x9d\x67\x2d\x83\x71\x3c\xd3\x26\xc9\xab\x81\xc3\x53\x76\x4c\xa5\xad\x5a\xc0\xe7\xf1\xff\x88\x0f\xb4\x8a\xcd\x9c\xbb\x94\x90\x64\xe2\x11\x83\xbc\x38\xfb\x1d\x90\xcf\xe6\x19\xa8\xb8\xfb\xf5\x32\x18\x89\xbb\x15\xc0\x2a\x53\xe4\xd3\x67\xfc\x66\x88\x77\xb6\x62\x28\x1c\x4a\x2a\xf6\x78\xf8\x6e\x69\x1d\xaa\x8a\xfd\xca\xc1\xb8\x20\x18\x9f\xe5\xc2\x50\x8c\xe3\x6e\xdd\x9c\x6f\x8f\x51\x57\x50\x71\x83\x94\x39\xa0\x03\x35\x2c\x15\x73\xe1\x27\x68\xdd\x6d\xeb\xdf\x1e\xd4\xf9\x4a\xc7\x9d\xf1\xab\x6a\x0b\xc2\x50\x79\xc0\x93\x54\x77\xd9\x14\x99\x88\xec\x3b\x87\x93\xef\xcd\xa8\x59\xac\xc3\x92\xab\x3f\xa9\x94\x93\xd7\xae\x0a\x65\x75\xb6\x95\xa1\xce\x07\x65\x32\x86\x02\x87\xdd\x49\x89\x67\xc4\x6f\x7a\xdd\x49\x49\x4c\x02\xe7\x44\xc4\x02\x80\x19\x57\x82\xe2\x42\x44\x76\x16\x5e\x72\xce\xe2\x36\x42\xe5\x1c\xec\x43\x21\x91\x11\x6a\xec\x59\xb5\x9f\xcf\x0a\x36\x83\xb9\x5f\x76\x07\x60\xa2\x0b\xd6\x74\x54\xd8\xde\x64\x7c\x0f\x9f\xfc\x4f\x90\xf6\xe4\x5a\xc9\x3d\x80\x2f\x33\x82\x99\xef\x28\x0d\x3b\xb7\xa4\xa8\x9d\xb8\xc5\x9a\x12\x52\x6f\x27\x83\x02\x4c\x8a\xde\x90\x02\xf0\x0e\x3d\x52\x9b\x78\xdc\xdd\x49\x03\xda\xf5\x76\x7a\x2b\xed\x75\x14\x53\x96\xef\xb6\x97\x90\x71\x2d\xe6\xa5\x90\x1e\x6d\x8c\x15\x28\x01\x82\x38\x82\x85\x02\x1d\x0e\x70\x92\x92\x15\xd9\xf2\xb7\x99\xbb\x92\xf2\xca\x56\xf4\x8e\x8c\xbb\xa2\xf1\x9b\x08\x58\x45\x12\x65\x67\xcf\xaf\xa6\x03\xc2\x94\x6e\xa1\xe7\xd2\x74\x55\x4a\x38\xbf\x7d\x86\x51\x1f\x3e\x47\x4f\x9f\xa5\xcb\x11\x10\x5f\xb5\x2f\xc6\x81\x77\xf3\x38\x5f\xe1\x39\x7b\xe5\x84\xa7\x00\x89\xdc\x74\x1b\x4b\x00\x95\xbf\x7e\xb2\x99\x3b\x41\x8d\xf8\x7b\x14\xa1\xf9\x79\x26\xe8\x68\xdf\x6e\x56\x8b\xec\xa2\x21\x5f\x2d\xd7\xce\x8a\x3c\x9e\xe8\x49\xcb\x41\x34\x6c\x68\x4f\x7f\xfe\xf0\xa7\x92\xed\xf4\x33\xca\x99\xef\x34\xc7\x3f\x92\x72\xa7\xeb\x97\x58\x7c\x8f\xce\x4a\x51\x36\x44\x47\x37\x13\x8d\x53\xea\xdf\x3a\x84\xf5\x01\xbb\x10\x45\x6e\x8e\x4a\x40\x47\x08\x2c\x9e\x14\x35\xf5\x76\x52\x6c\x21\x64\x71\x4d\x70\xb3\xd0\xa6\xe9\xc0\x8a\x53\xe3\x23\x84\x0f\x4d\xcf\xe8\xf2\xd1\x9f\x0b\xe2\xc8\x8e"}, -{{0x85,0x04,0xfb,0xca,0xab,0xa6,0x76,0x83,0xf8,0x15,0x49,0x92,0x82,0xb6,0xeb,0xd4,0x97,0xa8,0x1a,0x91,0x56,0xf5,0x3e,0x02,0x5c,0x2d,0x3e,0xce,0xe0,0xdb,0x65,0x59,},{0xe6,0x2d,0xa8,0x64,0x93,0xa0,0xca,0xf5,0x29,0x21,0xd5,0x60,0x2f,0xbd,0xc3,0xdd,0x3a,0x84,0x36,0x94,0x1f,0x6b,0xe2,0x40,0xb3,0x15,0x09,0x68,0x12,0x38,0x74,0x6d,},{0xc0,0xea,0x07,0x4b,0xf9,0xad,0xde,0xe2,0xe3,0x35,0x0a,0x96,0x9e,0x7c,0x56,0x9e,0x3a,0xea,0x1a,0x41,0x88,0xee,0x5a,0xf3,0x4c,0xb7,0x3f,0x38,0x82,0x98,0x65,0x3d,0x29,0x9b,0x5d,0xbd,0x94,0x16,0x3f,0xba,0x20,0x9e,0x8f,0x7d,0xc2,0xe2,0x63,0x4d,0x3a,0x52,0xa0,0x28,0x10,0xa8,0x8c,0x61,0x52,0x94,0x5b,0xc1,0x6b,0xbd,0xfb,0x0c,},"\x6c\x63\xed\xbd\x40\xa0\x38\x74\xec\xae\xf8\x16\x02\xcd\x68\x50\xc0\x9f\x49\x15\xb7\xaa\xf4\x18\x25\x8c\x56\x83\x64\x53\x8e\x83\x92\xa8\xc3\x79\x83\x8b\x0c\x95\x34\x5b\xf6\x4c\x3d\xbc\x17\x58\x53\xfb\x64\x1f\x35\x0f\x0b\x53\xa0\x5a\x8e\xc2\x90\x28\x8c\x03\x26\xd4\x35\xff\x77\x6f\x86\x83\xa2\x73\x33\x3f\x9b\xb2\x80\x21\x84\xec\xc5\x3b\x06\xb2\x8c\x2c\x40\x2a\x54\xbf\x13\x4c\x1a\x23\x29\x97\x49\xa6\xce\x2b\x51\xa7\xba\x22\x23\x21\x48\x79\x7e\x99\x3f\xf2\x58\x28\x6e\x94\x77\x78\xa8\x74\x2d\x3f\x36\xcc\x78\x42\x97\x60\x43\xfc\x23\xda\x8a\x97\xec\xb9\x71\x5f\xc0\x5f\xb0\xf2\x3f\xa7\x32\x1d\xdc\x19\x32\x86\x16\x31\x60\x4e\xba\x2e\xf2\x5d\x8b\x75\x6c\xe4\x73\x36\x56\xbf\xd1\xe1\x47\x08\x92\x3a\xc7\xc6\x0a\x79\x84\x61\x36\xd7\x41\x97\x3b\xa5\x51\x41\x89\x72\x0b\xc0\xf7\x77\x4b\x7b\xd3\x57\x45\x95\xbd\xe2\x51\x50\x31\xb2\x5b\x62\x65\x4b\x16\x10\x35\x77\x80\x70\xac\xe1\x49\x71\xdf\x1f\xe0\xbe\x4e\xa1\xef\x55\xcf\x87\x47\xd3\x71\x6c\x1c\xe7\x07\xb1\xa7\xc8\x52\x0e\x6d\xeb\x33\x4e\xb1\x86\x33\x8f\xc9\x30\x00\x76\x8e\xb2\xbe\x40\xc6\xe0\xdc\x3f\x5d\xf8\x31\xb3\x2c\x3a\x2c\x33\xe2\x88\x98\xd6\x76\x2a\x15\x22\xd3\xd4\x8d\xae\xe5\x6a\x02\x69\xbd\xdf\x6c\xfc\x9d\x73\xf8\xd1\x78\xae\xcc\xbf\xfe\xf7\xce\x16\x4f\x98\xaf\xea\x22\x4a\x9b\x60\xed\xe4\x6a\x95\xfa\xdc\x9f\xc5\xd9\x4d\x20\x9c\x16\x6d\x9b\x8d\xe2\x53\x38\x1e\xa2\x24\x88\x62\x94\x6b\x9c\xf5\x34\x94\x74\x55\xc2\x44\x58\xcf\x56\x68\x3a\x0e\xc4\x7a\x2c\x65\x07\x5c\x69\x4c\x7c\x3d\x6a\xdf\x9a\xe5\xe8\xad\x31\xac\x76\x9f\x83\xaa\x26\xe3\x12\xc5\xb0\x1a\x9a\x09\x40\x4b\x15\xb8\x14\xba\xa7\x66\x6b\x3e\x03\xf0\x6a\x8d\x63\x48\xab\x8c\xcb\x9b\x60\xa4\xa4\xfa\xf8\x6f\x71\x35\xdf\x03\x9d\x95\x5c\x07\xbd\x92\xe7\xb8\xe3\x27\xee\x6c\x1b\x40\x19\x6a\x28\xb4\x44\x6a\xa5\xa9\xb2\xb9\x77\x3a\xb7\x6e\x3c\xe2\x11\x80\xf0\x9d\x6c\x08\xd2\x77\xc6\x77\x1d\x67\xe2\x2d\x84\x54\x0f\xa4\x3b\x38\xf6\x34\xcf\xc4\x6e\x5b\x8c\x33\xf1\x5a\x56\x8a\x77\xe4\x91\x4a\xad\x9a\xb8\xc9\xf7\xfe\xa4\x7f\x76\x77\xc0\x18\x80\xb3\xe8\x5d\x2d\x0e\x3f\xbd\x6d\xc6\xe9\x9e\x43\x7d\xdc\x73\x6f\x92\xb5\xa2\xff\x29\x27\xe0\xb4\x42\x14\x2f\x08\x97\xd0\xb8\xa1\x9a\xc2\x03\x63\x3d\xf4\x13\xfe\xaf\x8e\xf5\x0a\x5f\x76\x7b\xed\xaf\x20\xf1\xc1\x3f\x3b\x89\xd1\xe8\xb7\xbd\x18\xd5\x91\xf9\xde\x11\x6e\xe3\x4f\x98\x24\xe4\xea\xd1\xae\x9d\xa2\xe8\xca\xae\xf8\x8b\x29\x51\x6a\xa9\x42\xde\x77\xa7\x46\x7b\x6f\xb2\x6a\x66\x6f\x30\x64\x8c\x71\x5a\x2e\xe9\xf9\x46\x74\x3b\x54\x3a\x44\x28\xe0\xdf\xd0\x61\x78\xe7\xe9\x3e\xc6\xf2\x6e\x00\x3e\x05\x8b\xec\x14\xa4\xaa\x2e\x3b\x8d\xe1\x12\x95\xa7\x64\xca\xb3\x0b\x31\x3f\xcc\x57\x43\xb2\xfb\x89\x96\x2d\xdc\x5c\xdc\x6a\xa0\xd2\xe4\xa3\x06\xe7\x7a\xf7\x6a\x05\xa5\x98\x92\x3f\x62\x8a\x85\xdf\x1c\xc7\x3a\xd3\xbc\x01\xc4\xb9\x79\xbd\x7c\xb2\x96\x59\x0a\x88\xb0\xa4\x1b\x44\x5d\x50\xa0\x84\x23\xe4\xed\x80\xf1\x76\x3c\x71\x6b\x6c\x45\x7d\x84\x5d\xfa\xa6\x8d\x12\xb0\xd0\x3c\x55\xfd\xe8\xae\x6b\x2b\x92\xbc\x63\x22\x94\x3d\xbe\x54\xc7\x06\xbc\x8e\x5f\xce\xe7\x06\x54\xb2\x6f\x3b\xfd\x87\x7f\x5f\x53\x39\xac\x18\x2d\x54\x17\xbd\x4c\x07\x35\xd8\x25\xbf\x70\xe8\x5e\xab\x82\x16\xed\xda\x63\x2a\xe7\xe2\x2b\x3e\x53\xd0\x78\xa8\xb2\x0b\x5a\x7e\x23\x85\x33\x7c\xf9\x2b\x3c\x16\xb0\x23\x56\x3e\x11\xcb\x50\x43\xb7\x04\xd3\x7e\xb5\xed\x9e\x85\xfc\xdc\x95\xcf\x7a\x6e\xad\xe4\x08\x03\x17\x5a\x00\x8e\xf6\x53\xac\x61\x36\xf1\x61\x29\xab\xae\x11\x37\xc5\x82\x34\x00\x74\x8a\x81\x25\x62\x54\xd3\x17\xcf\xc9\x39\xe2\x6e\xa0\xce\xf9\xf6\x54\x8d\xb4\x28\x90\xc4\x8b\xeb\x04\x79\x10\x3b\xa0\x89\xe5\x14\x11\x80\x38\xb1\xb9\x09\x43\xd7\x16\xf7\xa8\xd4\xcd\xa5\x98\x3a\x67\x4b\x83\xa0\x02\xd8\xac\x9c\x65\x73\x4a\x28\xb7\x7b\x76\x0c\x8e\x38\x03\xf8\x78\x1e\xa9\x19\x9f\x79\x7c\xe7\x29\xe0\x6b\xff\xfe\x8c\x29\xb2\x0b\xc8\x52\x27\xc0\x9c\xc0\x52\x19\xff\x2b\xa3\x8e\x18\x05\x10\x83\x73\x2f\x83\xcb\xfc\xcc\x31\x07\x56\x45\x0b\x26\x1d\x5b\xe1\x83\xd9\xfb\x44\xec\x18\x52\x9f\x2c\xc9\x84\x8c\x40\x11\x9c\x60\x76\x76\xbc\x4d\x90\x15\xfd\x4b\xd2\xfc\x91\x8d\xc8\x03\x1e\xc1\x9a\x05\xff\x36\x2c\x18\x40\x43\xbe\x7f\xe0\x66\x01\x9a\xc5"}, -{{0xea,0xc0,0xf0,0x6c,0x2c,0x14,0xf3,0x7d,0x43,0x4b,0xc9,0x98,0x97,0x22,0x5d,0xd2,0xe3,0xf1,0xed,0x74,0xaa,0x74,0x42,0xc5,0x50,0x33,0x9d,0xf7,0x7d,0x0b,0x7b,0x32,},{0x43,0xe6,0x20,0x55,0xdb,0x6e,0x13,0x49,0xc9,0x4d,0x89,0x02,0x91,0x87,0x88,0x20,0x20,0xcb,0xcf,0x9d,0x75,0xe0,0x3e,0xb6,0x56,0xfa,0x0a,0x15,0xb1,0x90,0x02,0xd7,},{0x45,0xf2,0x80,0x3a,0xfe,0xb0,0xfc,0x44,0xd3,0xaa,0x96,0x5b,0x12,0x65,0x9b,0xf5,0x02,0xe4,0x72,0x95,0x70,0x61,0x84,0xb2,0xa1,0xc6,0xf1,0x6d,0x05,0x06,0x13,0xf5,0x96,0xa2,0x00,0x13,0x94,0xe0,0x0e,0x2a,0x44,0xc4,0x6c,0xf6,0x50,0x5d,0x5c,0xf5,0xb8,0xab,0x84,0x12,0xf0,0x7e,0xda,0x95,0x1a,0x15,0x00,0x5e,0x33,0x8f,0x3c,0x0e,},"\x27\xb7\xfd\x0e\x71\xad\xf1\x94\xcf\x54\x07\xb6\x77\x17\x93\x06\x0d\xe0\xfc\xa7\xca\x0a\xe6\x48\x35\xc4\x31\x87\x40\x8a\x70\x4f\x53\x3d\x5e\xa0\xc8\x3a\x65\x43\x87\xba\x7d\xb1\x6e\xd5\x8e\xc8\x37\x22\x6d\xf5\x7c\x1f\xe6\x38\x2c\x59\x19\xe9\x22\x13\xf6\xf1\x8c\xbb\x57\x35\xd1\x78\xa4\x76\xaf\x35\xd3\x90\xb7\xcd\x25\x56\x21\x7c\x53\x0f\x3a\x1f\x8a\xb2\x33\x9c\x1a\x5e\x8d\x96\x93\x87\xef\xd3\x94\x14\xb5\x6b\xb7\x84\xdf\xd5\xeb\x89\xb8\x59\xe1\xf4\x03\xa2\x38\xec\xa2\xa9\x41\xe6\xdb\x56\xac\x45\x6b\x73\x45\x06\x98\xd1\x45\x5e\xc1\xe9\xb3\x9a\x1e\x90\x7d\x6b\xc7\xe6\xcf\xf4\x24\xa2\x8e\xed\x57\x9a\xf1\x63\x10\x11\x5b\x67\xf5\xfc\xf7\xf8\x34\x6b\x3f\xa0\x26\x0c\x6d\xa2\xe2\x77\x55\xac\xa5\x70\xba\xbb\x3d\x30\x3c\xc8\x32\x46\x0c\x96\x3b\xfd\xd5\xc1\xff\xb2\xfc\x19\x92\x19\x29\xdd\xa2\xa7\x17\xfb\xcb\xeb\x2b\x85\x25\x76\x1b\xd6\x60\xce\x4a\x0f\x76\x85\x28\x5d\x7f\xad\x61\x15\xab\x09\xf8\xe6\x3f\x5f\x77\x39\x14\x49\x4e\x20\xbe\x1b\x51\x2d\x11\x14\xcc\xe3\xf0\xf6\x8c\x7d\x94\xf5\x48\x57\x69\x4f\x22\xaf\x4c\x69\x8d\x78\x2c\xe8\x37\xb0\xc1\x72\x2b\xb7\x31\x3b\xb2\xc4\x1f\x6d\x3d\xd1\xa0\x28\x77\xfb\x42\x96\xd8\x66\x2a\x9e\x86\x25\x98\x4d\xc1\xfd\x1a\x95\x10\xeb\xa9\xd6\x43\xac\x58\xa8\x86\xa0\x45\xcd\x0e\x53\xc0\x56\xa8\x33\xf9\x68\xb3\x5d\x01\x32\x0e\x9c\xc0\xb4\x35\xd3\xf6\xbf\xad\x26\xf9\xeb\x57\x54\xd3\x8d\xdf\x6d\x5c\x4b\xf6\x15\xa7\x64\x4a\x23\xf9\x82\x6b\xcc\x97\x60\x92\xd8\x2d\x81\xd5\x47\x00\x0d\xe0\x08\x1b\x7a\x40\xa9\x3f\xbd\xda\xc1\x3f\x7d\x99\x70\x8c\xcd\xee\xb9\x40\x5c\xd6\x34\xca\x07\x48\xca\xd2\xc1\xd8\xf1\x64\xf5\xd7\x7a\x4f\x36\x4a\xe4\x88\xbe\xdc\xf1\xf2\x0e\xb9\x54\xbc\x8a\x27\x8a\xf8\x14\x32\x41\x78\x56\xa9\x00\xf8\xf1\x52\x92\x1a\xfb\xe1\x79\x14\x22\x9a\x51\x3b\xd7\x1a\xb7\xe6\x61\xcd\xe1\x29\xaf\x93\xe2\x50\x94\xc5\x61\x18\xed\x1f\x22\xdb\x64\x44\x28\xb4\x74\x65\x1f\xe3\x6b\xe8\x2f\xa3\x69\x5c\x41\xfc\x86\x99\x66\x7e\x05\x37\x43\xb0\xa4\x11\x55\xc3\x1f\x1e\x26\x79\xc6\xe8\xcb\x9c\x9d\x1f\x5f\x4b\x40\xa3\x20\xa9\xfd\x9f\x47\xda\x9b\x94\x21\x1b\xa6\x01\xb2\x2a\x11\x52\x10\xd9\xf5\x59\xc4\x49\x6f\x01\x73\x24\x58\xf4\x9a\xc3\x4e\xb3\x86\x63\x6c\x8b\x6c\x68\xc7\xbb\xc0\x07\x8a\xb6\xf3\x98\xa6\x24\xb8\xba\xfb\x1c\x62\x29\x58\x56\x2d\x23\x1d\xff\xd4\xdb\x09\x61\x96\xbb\x87\x47\x9e\x42\xea\x22\xac\xbd\xcd\xe8\xde\xb1\x0e\x31\x16\x32\xf0\x2f\xca\x14\x78\x7f\xd3\x14\x05\x69\xb9\x42\x89\x91\x54\x3e\xc6\xe8\x34\xe1\x0b\x14\x9f\x23\xc7\x4b\xb9\x9a\xc7\xb3\x79\x9a\x20\x96\xd2\x2e\x38\x7a\x71\x2b\x6f\x90\x11\xea\x34\xc5\xbe\x4c\x46\x85\x81\xac\x62\xce\x66\x20\x63\x25\x2e\x06\x6a\x9a\x3b\x15\xc9\x57\x0d\x06\x5d\xc1\x61\x99\x29\xf0\x6b\xc7\x5a\x31\x79\x46\x8b\xc8\xa1\x6e\x3d\xdc\x4f\xe1\x85\xce\xba\x0a\x92\xa5\x46\xb8\x67\x5f\xc1\xad\xe5\x63\x07\x15\x0c\x7e\x4c\x84\x4f\x6a\xa5\xf1\xed\xbf\xb5\x4a\xc6\x32\xca\x2b\x25\x9c\x32\xa3\x3e\xe2\x86\x78\x56\xc3\x39\x0a\x67\x40\x36\x4c\xb0\xdf\xb9\x76\xe5\x3d\x0c\xc6\xc4\x2a\x10\x6a\x1c\x26\x91\x8c\x8a\x6a\x03\x3b\x2a\xa3\xc7\xf2\xe4\x39\x2e\x79\xf8\xec\xa5\xb3\x36\xba\xc5\x06\x1d\x76\x98\xa3\xbf\xe7\xc2\xc2\x92\x89\x25\x54\x03\x0d\xe6\xce\x7c\x0d\x06\xee\xfc\x54\x90\x6f\x81\xe0\x09\x7f\xcf\xf2\x7d\x14\xb9\xb7\x99\x4a\x79\x70\xe1\xa5\xf5\xc6\xb6\x40\x5d\xca\x22\x03\x3d\xff\x0e\xae\x13\x8a\xd8\x99\xf6\xee\x68\x12\x0b\x8f\x22\x74\x4b\x02\x69\xa9\xa8\x98\x9b\x6f\x7e\x08\xaf\xfa\xe7\x7b\xca\x21\x68\xad\xe2\x40\x58\xae\x68\xa7\xf8\x00\xe0\x2e\x7c\x38\x39\x1b\xaf\x56\x5d\xd4\x0b\x55\xfa\x3a\xb3\xc2\x47\xb9\xce\xb4\xd9\x67\x47\x17\x75\xe6\x63\xd6\xa1\xc6\xc7\xe1\x73\x50\xbb\xd6\xb9\xa3\xeb\x1e\x48\x4a\xc2\xe7\xa7\xa5\xc8\x4f\x50\x83\xe5\xac\xe8\x73\x0d\xe8\x9c\x47\xe8\xdc\xf8\x34\x1e\x40\xba\x34\x5d\xbd\x66\xba\xe0\xf7\xf0\x76\xa7\x05\xb1\xbb\x7f\x47\x0e\x3e\xdf\xb2\xb7\x8e\x4d\x63\x59\x41\x3d\x18\xd3\x32\x80\xb4\x54\xa0\xdb\xb8\x81\xd8\x60\x67\x26\xfa\x9b\xea\x27\x24\x75\xe7\x9f\xea\x6a\x54\xcb\x4c\x06\x19\x54\x1b\x4e\x77\xc1\x70\xc8\x61\x68\x74\xb9\x54\xbe\xb8\xd1\x05\xb8\x6b\xd1\x91\x7e\x25\xcf\xba\x92\x67\x18\x7e\xe2\x03\x8b\x3f\x00\x78\xf4\xc3\x18\xb5\x87\xcf\x44"}, -{{0xe6,0x08,0xd5,0xde,0x97,0x97,0x90,0x7d,0xb6,0xd9,0x8e,0x03,0x45,0xd5,0xca,0xf2,0xad,0x33,0xe0,0xed,0xde,0xbf,0x18,0xb8,0x1d,0x61,0xe8,0x37,0x3e,0xcf,0xb4,0x99,},{0x60,0xe0,0xc1,0x6a,0xda,0x58,0x6e,0x36,0x46,0x91,0x2a,0x5f,0x2b,0xb3,0x18,0xfb,0xc3,0xd5,0x0b,0x57,0xd3,0x6f,0xab,0xb6,0x37,0x69,0x6f,0x9d,0x8d,0x4d,0xc7,0x61,},{0x0d,0x8f,0x09,0x5e,0x42,0xa2,0x73,0x0a,0x3c,0x7b,0xed,0xf4,0x2d,0x5c,0x83,0x39,0x8b,0x5c,0x0e,0xe9,0xc7,0x7c,0x5a,0x61,0xd9,0x82,0x29,0x13,0x96,0xa9,0x18,0x2a,0x08,0x02,0xa3,0x7f,0x32,0x4b,0xc4,0xfb,0x5d,0x4a,0xa4,0xed,0x60,0x44,0x4b,0x66,0x14,0x4b,0xac,0xbc,0x86,0x51,0x05,0xd7,0x69,0x0f,0x14,0x06,0x50,0x69,0x1d,0x03,},"\xe6\x10\xfa\x7d\x83\x85\xc0\x9c\x78\x98\x9e\xd5\xef\x7a\x23\x05\x47\xf0\x13\xcb\x7e\x8d\xdf\x31\x74\x9f\xfc\x31\xce\xe1\x0a\xb3\xef\xac\xa3\xf1\x4e\xa1\x94\x51\x0f\x09\x85\xa8\x18\xef\x8b\x04\x0e\x10\xc3\xa5\x11\x4d\xe1\xac\x08\x0f\x14\xc3\xd6\x5d\x3c\x24\x4f\x92\x42\xf7\x54\x92\xca\xba\xe8\x00\xfc\xfc\x9b\xc2\x75\xea\x1f\x27\x72\x8c\x92\x0c\x25\x8f\xe7\xaa\x73\x94\x80\x60\x29\x9c\xb8\x78\x35\x79\x2e\xdc\xc0\x72\x15\x0b\x73\xce\xfe\xb0\xd5\x15\x62\xe5\x3b\x46\x81\x0e\x27\xa4\xd7\xf6\xab\xd3\x2e\x95\x9f\x7d\x73\x1d\xde\x01\xd9\x4b\xc4\x1e\xd8\x35\xef\xcd\x42\xc9\x22\x43\x70\x37\xa8\x7d\xd3\x66\xff\xad\x2e\xec\xab\x6a\xba\xeb\x4f\xcf\x07\x39\x2b\x3a\xb4\x0c\xfa\xef\xea\xa4\x26\x6b\xc5\x37\x67\x16\x93\xc9\x09\x3d\xab\xe8\xa0\x53\x8c\xaf\xd1\x2c\x63\x9a\x04\xbd\x2b\xa8\x0c\xe0\xf2\x9a\xdb\xfc\x66\xbd\x46\x37\xca\x05\x43\xa5\x3b\x0e\x37\x1d\x0e\x2e\x47\x0d\x31\xba\x36\x06\x42\xa4\x5a\xb4\xcf\xe3\xe7\x90\xf5\x87\xf6\xc5\xa5\x58\x3f\xd1\x5b\x18\x99\x78\x38\xa2\x00\x92\x1c\x1c\x39\x9c\x0b\x16\x27\x8b\x7d\xd6\xd3\xaa\xab\x6f\x32\x5b\x16\xaf\xdf\x76\x1a\x1b\xbf\x86\x7d\xe2\xbd\xd4\x86\x15\xf1\x5b\x52\x67\x70\xed\x20\xd7\x9f\x0f\x30\x71\x4b\xee\xed\xa5\x8f\x52\xa3\xcc\x0c\x5a\x61\x83\x15\xe5\x22\xb9\xeb\xe7\xcd\x99\xb6\x5e\xd5\x32\xa6\x2e\x0f\x0d\xf7\x27\x64\xd6\xec\x6d\x6d\x1b\xa4\x0e\xf4\x0e\x05\x42\x63\x60\x79\x5d\x6d\xd8\x5b\xb3\x9f\x73\x21\xd3\xfb\x06\x27\x5d\xe0\x96\xaa\xe4\xa2\xfa\x22\x93\xf3\x1b\x33\xf4\xad\x4d\x7c\x25\x1a\xc1\x3e\x8e\x15\xc2\xbf\xb1\xf9\x8f\x49\x62\xc5\x4b\x6c\xe0\x33\xb0\x8a\xa6\x26\xf2\x90\x5d\x46\x3f\x55\xb7\x1c\xbd\xad\xec\xdb\x3e\x0b\x36\x5d\xae\x07\xb1\x70\x30\x19\x83\xae\xb8\x3b\x1e\x9f\x2f\x28\xcf\x65\x41\x9f\xd6\xb0\xa1\xa9\xc2\x6c\xb5\x4b\x59\x49\xf4\xbc\x01\xa9\x86\x81\x84\x4b\x43\x03\x4c\x37\x2a\x45\x3d\x38\xf0\x47\x3d\x0d\xdc\x70\x9d\x9f\x49\xc8\x75\x3a\x75\xb8\x56\xc7\xe9\x77\x55\x17\xdf\x57\x4a\x09\xa3\x95\x3b\xde\x5d\xae\xdf\x8e\x4a\x8d\xa9\xd7\x73\xa2\x15\x12\x0e\x26\x9f\xa1\x86\x11\x33\xcd\x4c\xea\xeb\x91\xd5\xcc\xa2\x60\x63\x25\x45\x8e\x50\xcb\x96\x6d\x14\x05\x5b\x22\x44\x7e\xb6\x5d\xc1\x01\x18\xda\x08\x31\xdf\x28\xc3\xb4\xee\x8b\x11\xf0\x73\x2f\x15\x21\xbb\x94\x82\xb1\x1f\x5a\x86\xb2\x2f\x18\xe8\x3d\xd1\xd9\x67\xd3\x94\x42\x85\xe5\xd6\x3a\x5a\x98\x98\x17\xab\x24\x18\xbc\x7e\xd8\x91\xa3\x73\x84\x67\x47\xa1\x2b\x52\x7c\x2f\x44\xee\x01\x97\xb9\x46\xc6\x7e\x67\xfa\x4a\xa1\xc2\x9f\x33\x79\xd4\x6f\xe0\x7d\x3a\xab\x83\xda\x17\xf9\xd7\x6b\xed\xd3\x84\x36\xa0\x55\xe3\x4c\xa1\xd3\xaf\x5a\x87\x54\xd3\x8c\x17\xb9\xba\x4e\x64\x19\xcb\xab\x51\x5f\x43\x1a\x25\x95\x95\x4e\x42\x8c\x26\x70\xfa\xe3\xbe\xd6\x2b\x45\x96\x17\x9c\xb5\x9e\x21\x10\x87\x08\xd0\x71\xbc\xf9\xc6\x21\xc6\xdf\xf0\x3d\x3c\xdc\x92\x02\x02\x94\x54\x01\x3b\x9d\x13\x38\x47\xf2\x65\x44\x81\x1c\x01\x69\x77\x0f\xdc\x6f\xe5\x63\x8b\xfd\x7a\x72\x0d\x8b\x38\xf7\xe3\x0a\x7e\x68\x79\x06\x0b\x5f\x28\xc8\xab\x17\xb0\x02\x00\x71\x32\x07\xe8\x63\x7b\xff\x48\x44\xd8\x42\xd9\xca\x78\x83\x91\x34\x01\x98\xa3\xfe\x01\x72\xdf\xa7\x4d\xe1\xe5\x5a\xde\xfb\xc2\xe9\xbc\x7e\x88\x54\x76\xd1\xb9\xc0\x55\x81\x34\x08\xa4\x75\x28\x43\x43\x55\xbf\x03\xfd\xd4\xe2\x7d\x8b\x34\x61\xb0\xfb\x66\xab\x3e\x15\xa8\x79\xa1\x84\x45\x7e\x9e\xd9\xea\x6c\x51\xb6\x63\xb3\x1e\xdc\x8c\x4a\x3c\xd4\x54\xf6\x9d\x9c\xe5\x18\xd1\xb8\x78\x88\xee\x3d\x9d\xd5\x41\x6e\x43\xe1\x14\xac\x05\x72\x13\x52\xdf\xfc\x2c\xa8\x85\x97\x37\x7b\xbc\x41\x40\x09\xb0\xc2\xfd\x36\x9b\xe5\xba\x35\xa6\xdc\xe3\x47\x8b\x6c\x11\xb3\x3c\x0a\x33\x91\x8b\x6e\xe5\xac\x4c\xd4\xc2\xf1\xca\x6b\xd1\x90\xa0\x00\xa8\x38\xda\x38\xf5\x30\x77\x56\x03\x35\x59\x6d\x13\x58\x93\x77\x93\x96\x38\x10\xa7\x9a\x21\xb8\xd4\x61\x40\xe7\x68\x89\x8d\xcd\xa8\x8a\x0f\xaf\x8d\xdd\x0d\x63\x38\x47\xaa\xea\x0e\x03\x0b\xe6\x45\x5b\x41\xe3\xed\xe1\xe2\x87\x37\x30\xeb\x84\x81\xac\xaa\x7a\x51\x9c\xf9\x19\x58\x47\xa8\x6a\xfa\x57\xf9\x07\x1d\x44\xf4\xaf\x4c\xa0\xd3\x43\xc9\x0c\x0d\x22\xd9\x46\x14\x65\x85\xf0\x0e\xf3\xae\xf5\x7f\x0f\x9e\x55\xe8\x18\xc0\x12\x8a\xe2\x55\xdb\xc3\x11\x6c\xf0\xfe\x02\x16\x6d\x54\x85\x9d\xec\xbf\xdc\xcc"}, -{{0x0e,0x86,0x87,0x2c,0x78,0x62,0x0f,0x10,0xcb,0x6d,0xfc,0x46,0x3d,0x2c,0x28,0x72,0xc4,0xda,0x66,0x07,0x48,0xc9,0xcd,0xa0,0x1a,0xb1,0x45,0x69,0x58,0xaf,0xba,0x7f,},{0xde,0x49,0x89,0x98,0x92,0x69,0xca,0xbd,0x8f,0x4f,0x40,0x9c,0xf1,0xa4,0xd9,0x74,0x03,0x8b,0x27,0x55,0x02,0x27,0x35,0x57,0xf3,0x12,0xd5,0x55,0x3f,0xab,0x93,0xc3,},{0x20,0x37,0xe9,0x77,0x41,0xc3,0xe6,0x40,0x9c,0x66,0xfc,0x67,0x82,0xaa,0xb3,0x89,0xc5,0xd7,0x78,0x09,0x7a,0xc7,0x78,0x99,0x9e,0x85,0x76,0xe4,0x9e,0xf4,0xf6,0xa0,0xc7,0x73,0x0b,0xd9,0xe0,0x93,0xdd,0x3c,0x0a,0xe7,0xec,0x76,0x20,0x33,0x80,0xda,0x65,0x71,0x47,0xd3,0x3a,0x8d,0x9d,0xd6,0x5e,0xd0,0x0c,0xf7,0x62,0x24,0xd6,0x01,},"\xa9\x00\xf3\xe9\xc6\x43\xa5\x64\x9b\x07\x6f\xb6\x9c\x3b\x2a\xc0\x84\xd5\x2c\xcb\xaf\xcd\xca\x5a\x9d\xb1\xda\xa7\x05\x00\xde\x99\x33\xd2\x3d\x15\x3f\x74\x95\x4e\x1b\xd5\xf5\x7b\x89\x9f\xe8\xa4\xb1\x34\xc1\x95\x41\x2b\x49\x83\x3b\x6e\x50\x95\xa6\x55\x4e\xaa\x6d\x84\x4b\x11\xf1\x58\x4c\x85\x05\x5b\x87\xf4\x1c\x99\x96\x69\x04\x6c\x71\xae\xb5\xc0\x45\x3f\xd6\xa3\xc4\x37\xf8\x15\xf0\x68\x98\x7c\x38\x68\xcc\x07\xaa\x2a\xf6\x58\x19\x04\x6c\x30\x7b\xaf\xb7\x53\x0d\xe8\x4f\x71\x30\xae\xa7\x8e\xf0\x05\xd5\xff\xf5\x2f\x8d\xea\xf1\xd5\xe9\xc3\x26\xd3\x21\x7f\xc5\x5b\x94\xf6\x28\xaa\x10\x4f\x6a\x24\xa3\x95\xe6\x2d\x1b\x62\xbd\x9c\x0d\x82\x43\x63\x19\xc5\xd7\x3e\x57\x65\x43\x5f\x3b\xa8\x56\xa4\x73\x4f\xd6\x0a\xe6\x17\xf7\xf0\xc3\xba\x57\x22\xa7\x33\x66\xc8\x8a\x6d\xfe\xca\x85\xc4\x44\x63\x9f\x44\x1f\x2c\x55\xfd\xc4\x64\xec\xb2\x99\xee\xe3\x6d\x8e\xae\x06\x3b\xb9\x4b\xb2\x43\x9d\xa0\x4f\xa5\xeb\xc5\x09\x23\x38\xa5\x03\x5e\x48\x0f\x08\x34\xae\xee\x8d\x71\x1f\x28\xc4\x6d\xc9\x60\xde\x1b\xe9\xdf\x30\x7c\x18\xc5\xc1\x78\xb2\x62\x96\xdc\x56\x7f\x15\xbf\x60\x86\x3a\x36\x71\x08\x67\xe9\x2f\xd5\x10\x48\x86\x56\x74\xc2\xaf\x0c\x53\xb2\xe7\xa2\x48\xae\x5b\xd0\x9a\x49\xaa\x03\x06\x18\x49\x5f\x82\x48\x0c\x42\x0a\xe1\x06\x88\x9b\xec\x00\x62\x78\xb9\x22\x72\x07\x57\x09\xfe\xc9\x54\x87\xcf\xb1\x00\x61\xe6\x72\x2b\x93\xee\xbf\xc0\xbc\x58\x7b\xf7\xba\x5f\x66\x92\xb0\x74\xf5\x5a\x98\xd5\xc3\x02\x76\x0b\x1b\xf1\xd0\x9f\x7e\x86\x68\x47\x9c\xa6\xf0\x1e\xed\xa2\xfd\xaf\x58\x4a\xc2\x05\x8f\xbf\x7c\xf3\x10\x0d\x06\xb8\x09\x1b\xfe\xab\x51\xc0\xc0\xb1\xd4\xee\x3a\x82\x57\xf6\x9b\x16\x17\x60\x4f\xce\x95\x3b\xb5\xf7\xf2\x71\xc6\xa1\x88\x0e\xa1\xb3\xf6\x62\x67\xe2\x43\x9f\x34\x58\x06\x28\x91\x78\x77\xc6\x6e\xc0\xfe\xd7\x6e\x44\xe8\xbb\x2b\x91\xa8\x80\x6d\xf4\xba\xca\x6c\xc9\x28\x89\xb8\x80\x50\x70\xc9\xa6\x17\xf8\x07\x15\x75\x30\x75\x1c\xc1\x7c\x47\xb0\x9e\xeb\xa9\x4d\x22\xb4\xe5\x47\xc3\x70\xce\x7a\x49\x6f\xca\xa3\x41\x2a\xff\xff\xb8\xc9\xb4\xde\x89\xb9\xf1\x21\xaa\xec\x5f\x54\x4b\x0c\x72\x5e\xc5\xee\x9d\x4b\x34\x76\xad\xc9\xd0\x50\xed\xb0\xfd\xba\xf0\x2c\xa9\xe3\x8a\xf1\x5f\x51\x50\x15\xa2\x67\x29\x2e\xc9\xaa\x54\x44\xed\x1d\xec\xd9\xcd\x9e\x1e\xad\x64\x87\xa0\xcc\xef\x99\x5b\x1c\x60\x0a\x03\x69\x35\x83\x86\x60\xac\xab\x27\x6d\x8b\x0e\x5b\x07\xd9\xf3\x63\x53\x21\x4b\xf8\x0f\x94\x1a\xc8\x8c\xf4\x0a\x08\xaf\x91\x79\x26\x23\x41\x12\xec\xcd\xaa\x16\x2d\xc9\x9d\xe3\xe2\x5b\xaf\xf6\x5b\xb0\x1e\x49\x89\x89\x86\x33\x2b\xdc\x2d\x70\x5d\x5a\xea\x40\xf9\xbc\x4f\xbb\x28\x06\x89\x44\x96\x03\x8d\xa2\x36\xe9\xdc\x29\x60\x0c\x9c\xed\xea\xc3\xb6\x16\xcc\x56\xd8\x9e\xc2\xfa\x67\x38\x96\x66\xc6\xc4\xfe\x23\x3b\x63\x91\x05\x02\x3e\x10\x1b\x87\x4a\x63\x30\xfe\x57\x3f\x80\xac\xe5\x5d\x03\x7c\xc6\x12\xe6\xdf\xd5\xa6\xe6\x86\xf9\xa8\x30\x54\xfc\x46\xe1\x5b\xb6\xda\x45\x3d\x81\x0c\xf1\x38\xa1\x78\xbf\x03\x9d\x1e\x18\x16\x14\xff\x40\xcb\xe6\xbb\x3b\x47\x36\x63\x75\x2e\xa8\x02\x5f\xf7\xf7\x39\xee\x4b\x67\x11\x0f\x96\x80\x89\xb2\x47\x3c\xd0\x44\xd4\x8b\x00\x9d\x06\x77\xf7\x91\xf5\x4e\x2d\xf6\xaf\xdc\x3a\xcb\x9e\x99\xdd\x69\x58\xa4\x50\xc0\xe1\xb6\xdd\x5e\x97\xa2\xcc\x46\x29\x8b\x4f\x48\xac\x6a\xda\xf0\x13\xd7\x5b\x2c\x42\x07\x2d\x2e\xe1\x3f\x73\x36\x87\xee\x83\xc3\xf7\x0c\x4f\xdd\x97\x20\xfd\x17\x98\xc6\x62\xfe\xf3\xba\x01\x2b\xed\xd4\x45\xc4\x72\x9f\x21\x30\x48\x4f\xe7\x7a\xc1\xb4\xc4\xdd\xeb\x81\xfa\xf6\x0f\x76\xe3\xbd\x7d\x21\xa9\xa6\xc5\x7a\x69\xa9\xcd\x9c\xc2\x03\xfc\x63\xb5\x9e\xe8\x4b\x89\x15\xb3\xc1\x8a\x59\x54\xe2\x27\xc8\x6e\xbb\xb7\xd4\xc4\xc1\xa0\x8d\x0c\x5e\x46\x7c\x68\xa0\x69\x70\x75\x1e\xf5\x84\xbd\xd6\x11\xe1\xdd\x1b\x48\x90\x0a\xb3\x54\xb9\x9c\xec\x6e\x1d\xf3\xbd\x41\x46\xea\x07\x55\x35\x0d\xc1\x1c\x3a\x3f\x60\x0d\x47\x0a\x74\xf4\x75\xe4\xfe\xed\xaf\x08\x65\x27\x6f\xa8\xa9\x77\x13\x47\x1d\x0c\xa9\x95\x5c\x71\x35\x88\x33\x9d\xee\x79\x65\x6e\x56\x7e\x6a\xb1\xdb\xf9\x83\x07\x03\x81\x7a\xe6\x20\x92\x9a\x06\x84\xa5\xca\xf2\x0f\xef\x81\xa8\xee\x89\x7b\xe7\xe5\x05\xad\xe6\x49\x6b\x9a\xef\x02\x72\xbd\x8f\x35\x08\x60\x23\x3b\x33\x8c\x2e\x36\xd3\x13\x8d\xb6\x95\x38"}, -{{0x52,0x03,0x54,0xd8,0x5a,0x87,0xd7,0xc2,0x2c,0xa6,0xf7,0x84,0x71,0x44,0x10,0xec,0x98,0xbf,0x6a,0x65,0xf8,0x03,0xef,0x93,0x79,0xbd,0xc8,0x04,0x35,0x9b,0x23,0x49,},{0xd8,0x51,0x1c,0xea,0xc2,0xfd,0x66,0x1a,0xcb,0xff,0xb0,0x1b,0xa2,0x74,0x1c,0xad,0x88,0x99,0x34,0xde,0x63,0x92,0x96,0x1b,0xde,0xc6,0xfa,0x46,0x12,0x3b,0x7f,0x0f,},{0x75,0x4e,0x60,0xd3,0xf6,0xf4,0xab,0x4f,0x5d,0x0d,0xdb,0xb0,0x01,0x53,0x20,0x09,0x16,0x63,0x88,0x48,0x7f,0x78,0x0b,0x76,0xf6,0x0b,0xd0,0xbc,0x9f,0xef,0xab,0xfa,0xab,0x6b,0xe2,0xae,0x78,0x69,0x57,0x3a,0x64,0x79,0x6e,0xf2,0x84,0x6e,0x85,0xe5,0xcd,0xae,0x52,0xdb,0x10,0x44,0xfe,0xfa,0x79,0x6b,0xac,0xf4,0x8b,0x96,0x8b,0x0d,},"\xa1\xd4\xad\x48\x6e\xbb\x7c\x1a\x0a\xcb\x8f\x11\x70\x13\xe8\xe4\x74\x67\x89\xc6\x24\x4a\x56\xc9\xed\xfb\xf1\xef\x37\xac\x13\x09\xaa\xf5\x1c\x93\x75\xfc\x12\xca\xcd\x68\x97\xa4\x47\x95\x45\xf2\xbf\x39\x0a\xb7\xc0\xc0\xe5\xc5\x92\xf5\x50\x6e\x99\x38\x37\x8a\x11\xb6\x36\xbf\x85\x70\x29\xb9\x68\x54\x7a\xa5\x06\xc4\xa0\x82\x9a\x15\xfd\x39\x95\xfe\xad\x4f\x86\x0f\xd7\xc6\x23\xc6\x3e\x86\x95\x43\x6e\xae\x55\x81\x64\x14\x77\x83\x47\x09\x2f\x5f\x4d\x42\x2b\xb1\xb5\xe5\xa0\x69\x66\x24\x1e\xfe\xc1\x4f\x1e\x4f\xca\x06\x63\x91\x14\x71\x8c\x30\xeb\xca\xdd\x4c\x6d\x8a\xbe\x7f\xe9\x3b\x25\xd1\x71\x73\x53\x39\x54\x18\x8b\x1a\xb0\x3f\xcb\x77\x92\xcb\x63\x5c\xe3\x6e\x9b\xdb\xdd\xe7\xa5\x61\xc5\xf6\x69\x20\xd9\x10\xcb\x26\x9c\x8c\x1c\x3f\x59\x32\x65\x09\x00\x72\xc4\x89\x32\xe6\x92\xa9\xc7\x38\xc7\x04\x89\x74\x89\xa7\x15\xc2\xb3\x94\xd5\xa8\x6f\x70\x36\xa4\xca\xc5\xdc\xb5\xb8\x5c\xfa\x16\x21\x56\xe0\xbc\x6b\xfe\x02\xfb\x4c\x38\x60\x8c\xfb\x23\xc9\x2b\x8b\x6a\x3c\xb4\x6e\x48\x7d\x60\xe0\xdc\x97\xaa\x2e\x33\xe3\xda\xda\x92\x5e\x4e\x66\x12\xcc\x5a\xf1\x25\xe5\xac\xa4\x58\x17\xa2\xfd\x6c\x3f\xf1\x0b\x18\x93\x8b\x44\xbd\x4d\xd2\x0d\x7f\xcc\xf7\xf2\x6b\x40\xa6\x6f\x48\xaa\xff\xc9\xa5\x41\xe6\xd3\x71\x38\xfc\x55\x46\x98\x68\xe2\xd1\x03\x65\xef\xf3\x7f\xac\x36\x0f\xab\x3d\xc5\x54\x37\xac\x2d\x8f\xea\x74\x74\x40\x5f\xb3\x63\x0f\x79\x63\xd2\xd4\x59\x58\xf9\x09\xd1\x48\x30\x28\x6f\xf1\x52\xaa\x75\x2f\x51\x0c\xe9\x80\xbd\x57\x54\xe3\xfa\x32\xc6\x99\x24\xdd\x95\xd5\xc1\x52\xa7\x37\xa8\xfa\xdc\xfd\x0a\x45\x60\xe0\xb1\x14\xf8\xe8\xaa\xa6\x18\xd4\x38\xb9\x87\x71\x11\xda\x17\x40\xef\x81\x7c\x44\x19\x39\xec\xec\x79\x9b\xa1\x6b\x1b\x17\x1c\xa9\xb6\x49\xb7\xd7\x8f\xa0\x52\xd1\x49\x7a\x50\x76\x88\xbe\xde\x49\x00\xab\xc5\x3a\x96\x48\xda\x59\x17\x03\x5c\xef\xfe\x0d\xa2\x1c\x25\xc0\x9b\x06\xd6\x18\x5b\xdd\xa2\xd7\x78\xf7\xed\xe6\x15\x3e\x3e\xaf\xf4\x95\xc9\x79\x6d\x4d\x16\x6d\x2d\x2e\xa4\x18\xe4\xa4\xaa\x6e\x67\x8f\xaf\x06\x96\xe7\x52\xa0\x9e\x02\xea\xad\xe7\x63\x07\x0e\x08\x8e\x99\x64\x91\x9f\xf4\xaa\x4c\x82\xf8\x62\x9a\x3d\x5c\x79\x7c\x2a\x64\x59\x4d\x20\x68\x35\xda\x0b\xfa\x43\xcc\xd9\xdd\xfc\xdb\x6a\xac\x4d\x48\x6e\x03\xc8\x41\x22\x37\x59\x39\xa5\x27\x0b\xc1\x51\x9e\x07\x07\xe5\x1c\x3f\x46\xf1\xe5\xc5\x66\xb3\x3a\x24\x5f\xa0\xc2\x02\x83\x84\x72\x36\x3d\xe9\xf0\xed\xde\x2e\x79\x1d\x82\x29\x30\x95\xf7\x50\xbf\xf5\x45\xe6\xc3\x47\x39\xdc\xc5\x4d\xb0\xa3\x6a\xe2\xe2\xaa\x39\xb0\x7c\xb4\xf6\xa9\x64\x62\x40\xd2\xd3\x14\x88\xf6\x78\x15\xb2\x95\x45\xd2\x20\xbe\x92\x9e\x33\x39\xf8\x28\x1a\x93\x7e\x05\xa8\xc5\xc3\x88\x7e\x06\x04\x8e\xa7\xb1\x8a\x48\xf8\xd9\x1b\x1e\x3a\xf5\xca\xb5\xce\xda\x0e\xbd\x71\xbf\x54\xed\xec\x20\x3d\x37\x16\x5e\x4c\x9f\x9f\x80\x46\x1c\xd2\x9f\xcd\x99\xdd\xea\x43\x96\x93\x94\x1b\x5d\x53\xff\x94\x37\x9c\xf6\x42\x57\x1d\xd5\x59\xa1\x1f\x8f\x38\x3d\x94\x3f\x22\x55\xcf\x71\x58\x00\xaf\x77\x6b\x10\x45\xbf\x19\xa9\xc9\xbb\x09\x51\x55\xdf\xb6\x46\xb6\x5f\x4a\x28\x0f\x2a\x97\xef\x92\x7d\xda\xbe\x24\xa2\xf9\x71\xa8\x17\x0d\xd4\x2a\x08\x92\x76\x82\x5c\xb9\x14\x8c\x01\x5a\xae\x1e\x9d\xad\xf2\x2c\x10\xe7\x54\x8c\x59\xbf\x6b\x86\x8b\x20\xe8\x6c\x83\xa9\xe7\x34\x3a\xec\x27\x54\xee\x62\x25\xf9\xfd\xce\xaf\x8e\x51\xc4\x0e\x95\x5b\xda\x49\xc3\x5d\xed\x38\xfa\x8b\xcc\x1e\x6c\x8f\xc9\xc2\x41\x2e\x91\x04\xc5\xc2\x36\x8b\x1f\x99\x23\xe0\x10\xfa\x2e\xde\x91\x1d\x42\xb1\x39\xf4\x00\x7e\x34\x26\x92\x2f\xfb\x61\x58\xec\xa9\x7b\x47\xcf\xc9\x97\x85\x35\x12\xbb\x9d\x4c\xa2\xf0\x17\xc2\xc2\x63\xdc\x19\x9f\x3b\xf1\xeb\x4f\x15\x08\xef\x82\x8b\x0e\x00\xdb\x21\x00\x27\x36\xa7\xf2\x2e\xc9\x12\x98\x19\x45\x83\x13\x9a\xd7\x5f\x58\xe2\x1b\x51\x8d\xaa\x49\xa4\x07\x6c\x63\x75\xfa\xa6\x08\x91\xa6\x9e\x52\xa6\x56\x69\x9d\x80\x34\xa7\xab\x7f\xcb\xe4\x21\x75\x49\x14\x41\xfe\x61\xb1\x78\x3e\x83\x78\x57\x52\x22\x15\xa5\xfa\xc5\x59\x0b\xed\x2e\x9d\x20\x66\x06\x09\x6d\x3b\xe8\xee\x92\x87\x3b\xfc\x30\xca\xb1\x5c\xe9\xf9\x91\x0d\x01\xa1\x17\xf8\x99\x26\xcc\x3a\xfa\x8d\x10\x4f\x79\x9f\xf3\x80\x98\xde\x28\xb8\xff\x0f\x03\x87\x25\xc2\x90\x3b\x24\xc1\x42\x9c\xea\x49\x25\x24\x9d\x87\x81"}, -{{0x06,0x1b,0xcf,0x1a,0xa6,0xfd,0x98,0x98,0x97,0xb3,0x22,0xe5,0x91,0xcc,0xef,0x54,0x54,0xef,0x4a,0x5a,0xdb,0x1a,0x48,0x00,0xf3,0x26,0x11,0xcf,0xf2,0xb5,0xbc,0x78,},{0x73,0xc8,0x0b,0x73,0x4b,0xfc,0x94,0x17,0xd5,0x76,0x89,0x0c,0x20,0x16,0x6d,0xa5,0xc7,0xfa,0xbd,0x61,0x3f,0x75,0x47,0x4f,0x76,0x49,0x73,0x2e,0x00,0x29,0x5b,0xe2,},{0x5a,0xda,0xa9,0x43,0x30,0xa0,0x35,0x37,0x12,0xa3,0x4d,0xbe,0x97,0x3b,0x75,0x18,0xf9,0xa2,0xc7,0x13,0xf8,0xaa,0xd1,0x00,0x25,0x1b,0x08,0x6a,0xe8,0xde,0x26,0xf6,0xd2,0xb6,0xcc,0xf0,0x52,0x8c,0xc5,0xde,0xdc,0xa3,0x18,0xdf,0x19,0xcc,0x7e,0x45,0xde,0xae,0x28,0x1e,0x13,0x24,0xb9,0x6e,0x32,0xfe,0xf4,0x5a,0xaf,0x60,0xb1,0x0c,},"\xd6\x3b\xb9\x20\x8c\x1f\x4c\x7d\x43\x32\x6c\xf3\x5f\xa5\xd8\x39\x33\x15\x18\x04\xab\x89\x1d\x49\xb0\xbd\xaf\x42\x9e\x4c\x39\xa3\x21\x42\x8e\x0d\x90\xaa\x00\x31\x8b\x97\xe0\x8c\x70\x24\xc9\x12\xcf\x38\x88\x79\xf3\xcf\x97\x4b\xb2\x53\xa1\xe7\xa4\xc8\xee\xc1\x93\xbf\x4c\x14\xaf\x6f\xb9\x79\x4d\xf0\xd4\x97\x85\x0e\xdb\x04\xd5\x74\xc9\x7e\xd7\x6c\x70\x21\x39\x96\x84\x01\xb4\x0e\xb5\x43\x94\xef\x4c\xfa\xa7\xe5\xd3\xcd\x94\x3a\xf1\x21\x92\x53\x8d\xde\xe5\x93\xc2\xa2\x4a\x26\x7a\xfa\x13\x71\xfd\x77\xfe\xee\x20\x71\xf4\x36\x9f\xbe\xf8\x79\x76\xe7\xeb\xd8\x1d\x1e\x5b\x31\xd6\xe0\x9e\x02\xd8\x30\x35\x7d\x36\xbf\xf8\x59\x67\x03\xe4\x14\x6d\x08\x27\xbe\xc9\xc0\xf8\x7b\x26\xf3\x11\x95\xc9\x6c\x93\xb6\xd8\xc4\x67\x67\xec\x1b\xc6\xde\x39\xf0\x00\x8a\x41\xff\x87\x5d\xa0\x50\xa3\xf8\x65\xab\x92\xcb\xf2\x9c\x38\xa2\x80\xf3\xbf\x69\xf6\x8e\x92\xb5\xf4\x30\xcd\xee\x35\x01\x98\x1d\x0b\x3d\x18\x90\x96\xe0\xae\xac\xd6\x4c\x33\x10\x24\x21\x34\x88\x12\x15\x8b\xb6\x1e\x51\xae\x93\x65\x92\xb2\xf8\xf1\xb9\x10\x94\x9e\xf3\x72\x32\x58\xa9\xb4\x4e\x4e\x1b\xda\xdf\x1a\xe2\xcf\xc1\x8e\x37\xd2\xed\x0d\xd1\x73\x44\x04\xb8\xba\xa5\xf3\x93\xcd\x56\x06\x9e\xce\xbf\x7e\xdd\x7c\x06\xcf\x6c\x8a\xa3\xe8\xe1\x2f\xbf\x94\x6d\x7b\x32\xd8\x45\x3b\x6f\xbb\x65\x35\x52\x6c\x8f\xb8\xfc\x1d\x58\x15\x56\x0b\xb3\x1b\x99\x5d\xf2\xad\xbd\x83\x6a\xdd\x92\x9a\x56\xfd\xd9\x3a\x17\x47\xd9\x3a\x40\xc0\x5e\x12\x9e\xb6\xf8\x58\x3c\x29\x21\xcc\x9d\xbd\xda\x42\x25\xe1\x76\xdb\x38\x6a\x02\xec\x40\xaf\x10\x32\xc9\xb6\x2e\x95\x14\x70\x25\xf4\xac\x8d\xd5\x84\x33\xb6\x4a\xc0\x73\x15\x0c\x69\xb9\xc4\x15\x4d\xcb\xb0\x03\x44\xf3\x08\x11\x3c\xd9\x19\x9c\xcf\xb5\x07\x58\x01\xc7\x05\xb8\xfc\x43\xb7\xc8\xbc\x16\x73\x65\xe4\x62\x93\xd0\x6c\x4f\x48\x35\xc6\x4e\xe5\xd5\x38\x3f\x68\x90\xca\x35\xa8\x0a\xf9\x17\x74\x81\x62\xdf\x25\x18\xab\x14\x68\xf1\x53\x62\x98\x99\x40\x6c\xde\x66\xce\x07\xfa\x7d\x29\x93\xda\xbe\x0c\x60\x08\x9c\x91\x89\x24\x88\xf3\xbc\xaa\xec\x40\x8a\x0c\xd0\x8c\x9a\xa9\x8e\x09\x37\xe0\x2c\x41\xad\x52\xd2\x41\xa9\x98\x33\xe3\xb8\x3f\x7d\x3f\x1b\x07\x8c\x31\xd4\x5c\x34\xfa\x01\x75\xab\xbd\x0f\x32\x2b\x8f\xd2\xdc\x83\x49\x1d\xa2\x92\xad\x00\x76\x2e\x3e\x57\x7b\x9e\xee\x0a\xae\x08\x72\x90\x70\xac\x25\xe3\x3b\xc9\x45\x25\xbc\x0d\x2a\xb5\x97\x04\xef\xec\x5c\x01\x48\x42\x1a\x47\x92\x8d\x34\xb1\xe4\x5c\xe7\x21\xee\x64\x47\xfb\x08\x2a\xc4\x00\xb3\xe6\x84\x6d\x20\x4f\x7f\x9d\xb6\xf0\xa3\x2b\x2a\x69\x73\x8b\x3e\xe9\xdd\xbb\x0d\xbd\x7e\x0f\x04\x1d\x7e\xa5\x3a\x5d\x64\x7f\xb5\x0b\x39\xae\x24\xd7\x8c\x8b\x07\xcf\xc4\xe0\x52\x71\x1f\x0d\x46\x39\xe7\x21\xd5\xc3\x6f\x31\xb5\x88\x86\x67\x12\xb7\x57\x10\x8a\x40\xcc\x7a\xbb\xb9\x91\x30\x83\x30\x3a\xae\x05\xa0\xf1\xaf\x0e\xc6\x87\x84\x41\xa2\x5c\xf8\x72\x9a\xba\x42\xa3\xa9\x4c\xe9\xb7\x38\x88\xa0\xf5\xc9\xe4\x0c\x9f\xc4\x54\x10\xf0\x68\x1f\xa7\xf9\x08\x98\x56\x2c\xcb\x4b\xbc\x55\xf0\xab\x1f\xe9\xc7\x0e\xa6\x60\x26\xdd\xa8\xd7\x09\x0f\x7b\x38\xed\xb5\xae\xc1\x55\x7b\x11\x66\x98\x7c\xd4\x1a\x70\x59\xcd\xee\x60\x9b\x74\xd8\xfe\x06\xb7\x05\x9b\x77\x24\xbf\xf5\x30\x07\xf7\xe1\x10\x46\x2f\x06\xad\x14\xd0\x7e\xe1\xb4\xd6\x9a\xc8\x23\xbc\xf5\x76\xd2\xfa\x9e\x2e\x8e\xd7\xf3\x19\x80\x40\xd4\x71\x29\x60\x63\x13\x7c\x98\x1a\xdb\xf3\x64\xcb\x20\xf0\xa1\xad\x20\x54\x47\x2f\x7c\xee\x25\x27\xf9\x98\x09\x61\x5d\x2e\x4b\x73\x4b\x06\xf3\x5d\xee\xcb\xd6\x26\x19\x66\x3d\xde\x81\xd6\xe2\x35\x28\xb0\xc9\x71\x32\xaf\x0a\x23\xba\xd6\x3d\x9c\x08\x14\x2a\x26\xe2\x74\x3f\x86\x18\xec\xfe\x72\x3b\x19\xff\xdd\x0b\x19\xab\xd9\xa3\xf4\xfe\x21\x0b\x1e\x71\xac\xdf\xe3\x8a\xbe\xbe\x23\xf7\xfd\xef\x66\x38\x1c\xbc\x75\xf3\x07\xe5\x57\x72\x35\xb0\x2e\x4c\xd9\xcf\xaa\x15\x03\x08\x68\xed\x14\x53\xda\x58\xf7\x83\xb7\x35\x2b\x04\x65\x68\x44\xc0\x42\x44\x1e\xfe\x6a\x3b\x4f\x8f\xec\x8f\x7d\xe8\x07\x44\x54\x0c\x4f\xc7\xa1\x07\xf4\xe1\xbf\xcb\xd9\x9d\xa2\x5b\x97\x46\x09\x5d\xdf\x01\x25\xd5\x6d\xa7\xe7\xf8\x60\x3f\x04\xd3\x59\xa0\x88\xb4\xc0\x44\xf9\x36\xcc\xb7\xd8\xf8\x9e\xd5\x3c\xc9\x91\xa3\x49\x7c\xa9\x52\x09\x4f\xf3\xc3\x30\x46\xf2\x60\x9d\x07\xb2\x9b\x63\x39\x81\x36\x9c\xb2\xf0\xee\xcd"}, -{{0x2e,0x19,0xcd,0x44,0x2f,0x22,0xa4,0xa9,0x9d,0xff,0xc5,0x5e,0x7b,0xf6,0x25,0xf8,0x9d,0x13,0x44,0xb5,0x63,0xf6,0x78,0x53,0x13,0xa7,0xee,0xe9,0x73,0xb4,0xaa,0x36,},{0xee,0x3d,0xa7,0x6a,0x8f,0xcf,0x40,0x3a,0x29,0x58,0xd4,0x55,0x1d,0xa0,0xa7,0x2b,0x2e,0x73,0x85,0x22,0xb2,0xe6,0xb2,0x0f,0xba,0x6a,0xa2,0x6b,0x32,0x30,0x73,0x57,},{0x28,0x32,0x6b,0x5b,0x97,0x8e,0x0d,0xbd,0xab,0x5d,0xde,0x70,0x37,0x85,0xa6,0x67,0xa7,0xef,0x43,0x9d,0x81,0xea,0x47,0xe0,0x66,0xb0,0x89,0xd1,0x16,0xc2,0x5a,0x34,0xbb,0x63,0x3f,0x26,0x0d,0x55,0xf4,0x5b,0xdf,0x6b,0xcd,0xa7,0x48,0x03,0xd7,0x62,0x4b,0x19,0x27,0xce,0xc1,0x8e,0xb1,0x99,0x22,0x60,0xbe,0xef,0xc3,0x99,0xd9,0x0e,},"\x1b\xfc\x5c\x6a\xa6\xa5\x35\x4f\xbb\x86\x14\x69\x79\x63\x48\xac\x63\x19\x12\x4d\xa3\xf1\x0d\x20\xd5\x0b\xbd\xc7\x15\x9d\x41\xb5\xab\xb1\x36\xc7\x99\x6a\x77\x37\x97\x12\x2b\x52\x5e\x8e\x2d\xca\x19\x54\xf6\x39\x17\x07\x30\x1d\x90\xf2\x10\x1b\x46\xc7\xb0\x86\xef\xa1\x58\x77\xca\xdc\xd0\x58\x12\xdb\x34\xb9\x96\xcb\x4f\x53\x1a\xbc\xd1\xe9\x8d\xb0\x8a\x5c\xf1\x36\x8e\x8f\x4b\x11\x09\x14\x2e\x95\x62\xbd\x00\x85\xff\xae\x5e\x66\x0f\x59\xc9\x30\x79\x3e\xbd\xb6\xe8\x0b\x0a\x2f\x4f\x3f\x59\xbf\x9d\x39\x5c\x48\xd2\x6e\x0a\x72\xa6\x0f\x9d\x1f\xf8\x7f\xd2\xd7\xa3\xf5\x38\x3a\xa9\x02\xad\xed\xed\xeb\xc6\xcd\x1b\xef\xd0\x38\x33\x61\x62\x74\x9d\x91\xa9\x57\xca\x2e\x3d\xd4\x70\x91\xc5\x59\x31\x13\xda\x87\xc3\xd6\x6a\x02\xc8\x0a\x6e\xdd\xb5\x35\xc4\x8c\xa1\xf3\x4a\x97\xfd\x1c\x95\xeb\xc2\xe5\x70\xfc\x8f\xaf\xe6\xe5\xd6\x54\x6d\x1f\x3a\x9b\xa8\xda\xac\x33\x4c\xf4\x7b\xf1\x17\xe1\x28\x0d\x0e\xbd\xf1\x4b\x0f\xcd\xbb\x43\xb8\xd2\x48\xcc\x6b\x61\x32\x0f\xdb\x04\x49\xed\x5f\x5d\xe8\xba\xb1\x21\xaf\x0d\x85\x54\x95\x6e\x6a\x12\x01\x6b\x42\x67\x7b\x44\x36\x78\x92\xc3\xb2\x0a\xfc\xc2\xcb\x9c\xfb\x5b\x10\x0a\x95\xb5\x1e\x8b\x07\xda\x9f\x51\x41\x5f\x4c\xd7\x78\x1a\x31\x37\x65\xe2\x0d\xb2\x7f\x23\x43\xe0\xf7\x19\xec\xea\x9a\xf0\x26\x95\x6f\x33\x87\xe9\xea\x7e\xd0\xa2\x93\x75\x9b\x4a\x26\x22\x02\x80\x7b\x41\x30\x9f\xb8\x0f\x50\x18\x5d\xb6\xa5\xf8\xbd\xca\x17\x88\x41\xbe\xc0\x6a\xdd\xc7\x61\x0d\xf7\x60\x17\xb5\x14\xbc\x41\x42\xf2\x6a\x36\xbf\x5b\xac\xec\xb0\x12\xfa\x41\x71\x0d\xd8\x49\xbe\xf7\xa7\xe4\x51\x43\x28\x36\xfe\x9b\x32\x65\xfd\x5b\x59\xee\x40\xb0\x4d\xad\x85\xcf\x48\xf8\x91\x46\x5a\x84\x2c\xd4\x50\x0a\x10\x24\xee\xfd\xf0\xf5\x54\xf0\xca\x17\xec\x9f\x7b\x71\x52\x56\xa9\xb9\xdb\xe2\x79\x66\x38\x6d\x8a\xc3\x7d\x3c\x51\x58\x96\xde\x0f\x7c\xdf\x7c\xf5\xb3\x20\xff\x7a\x8e\xf6\xb3\x4b\xa8\x20\xab\xa9\x06\x6d\xd2\x53\xc5\xb7\x76\x37\x77\xf9\x4b\x2d\x6a\xd8\xc7\x10\x22\x1e\x11\x37\x53\x5d\xff\x8a\x1b\x75\x65\xec\x81\xbd\x8d\xde\xb5\x02\xe3\xd5\x8f\xf8\xf1\xfe\x6e\x86\xb8\xdc\x15\xa3\xaa\xec\x68\x8b\xbb\xec\xd4\x68\x82\x81\xdb\x0f\x81\x8d\xe0\xf7\x26\x1b\xa9\xcc\x58\xc8\xbc\x0d\x02\xe0\x66\x32\xef\xe7\x28\x7a\xd7\xa8\x43\x31\xa8\x24\xd9\x28\x73\x44\xef\xaa\xa7\x4f\x1f\xc5\x76\xd0\x26\x94\x30\xf8\x56\xa8\x56\x52\x65\xb9\xd6\xef\x71\xfe\x13\x4d\x25\x10\xab\x06\xb6\x0b\xf3\xc1\x53\xb5\x7e\xcf\xd2\xe6\x34\x24\x03\xfe\x67\x8b\x58\x86\xb6\xb7\x34\xb7\xd3\x69\x06\x62\xb6\xc8\xc6\xf6\xe2\x50\xe5\xaf\x6a\x81\x83\x16\x6d\xdc\xd0\xa1\x7f\x0c\xdd\xc8\x63\x6e\xf1\xa6\x84\x98\xbe\x50\xb6\x59\x95\x39\xd4\x6b\x4c\xea\x97\x13\x0e\x08\xf9\x4c\xa5\x3e\x88\x46\x44\xed\xa7\x5d\x23\xcd\x2c\x03\x8a\x5f\x17\xb5\x91\xe2\x13\x69\x37\x8c\xd3\xfb\x57\x62\xd1\xa7\xc3\xe6\x6a\x11\xae\x6e\x91\xcb\xae\x61\x6a\xd0\x55\xe3\x9d\xc4\x1e\x15\x4f\x4f\xce\xd7\xb2\x69\x6d\x9d\xc6\x73\x80\xbb\x8e\xef\x47\x4e\x9a\xa8\x3c\xec\x47\xfa\xfa\xfb\x94\x1d\x62\x65\x64\xb2\x07\x5b\xcc\x08\x56\xda\x8d\x6e\x1b\x0b\x8f\x18\xba\xf7\x51\x3b\xbd\x14\xe4\x91\xed\x51\x79\x68\xc4\xf7\x24\x1a\xf2\x50\x98\xee\x8d\xf1\x30\xb7\xa3\x4d\x59\x73\x6d\x78\x36\xd3\x23\xfe\x3f\x43\xf5\x08\xcd\xcb\x75\x58\x95\xf5\x9a\x00\xc8\x04\xed\x16\x4c\xc3\x39\x92\xf3\xae\xe9\x62\xae\x9e\x99\x0b\x74\x27\x2e\xb9\x87\xb1\x2d\x90\xb2\x73\x14\xd5\x74\x00\xe7\x37\xd1\x34\x3e\x97\x09\x85\xc4\x27\x10\x60\x87\x6a\xbc\xd7\x04\x9e\x7c\x9f\xe2\x44\xff\x3e\xf9\x85\x60\x99\x5b\x74\x82\xd3\x1b\xc7\xc0\x9d\x99\x69\xf7\xcd\x41\xf4\xe4\xe2\x52\x75\x0d\xc1\x6c\xcd\xb2\x9b\x98\x53\x14\xa0\xb6\xe7\x49\xc9\x5f\x9b\xd2\x83\x8d\x5a\xc4\x9e\xe0\x31\xfd\x07\x9b\xec\x30\x28\xdd\x9d\xd0\x7d\xb6\xfa\x62\x2a\xd6\x21\xb3\xb1\xe1\x27\xe8\xfc\xa3\x7b\xd1\x46\xe3\xcf\x70\x3e\x91\x17\x01\xb7\xa1\x6c\x2d\x30\x36\x9c\x94\x64\x8e\xcc\x03\xdf\x10\xd7\xdd\x5c\x05\x58\xfa\x95\x93\x42\x5d\x94\x87\x27\xd6\x86\x0c\x3a\x14\xf8\x11\x24\x51\x06\x61\x6d\x2a\x5f\xa9\x81\xc6\xb7\xf4\x7e\xc9\xde\xf6\x54\x12\xd1\x32\xac\xc6\x91\x9d\xa4\xe8\x85\x97\xaa\x91\x90\xca\x61\x4b\x21\x80\x66\xa0\xf7\xb1\x69\x97\xee\x74\x7c\x5a\x09\x78\x5e\x50\xd0\xa8\x91\xd9\x59\x37\x86\x3d\x61\x3c\xef\xf7"}, -{{0x82,0x10,0x90,0x99,0xd1,0xea,0xfe,0xed,0x5a,0x85,0x20,0x60,0x46,0x49,0x1b,0x34,0xd0,0x6d,0xcd,0xe3,0x3f,0x08,0x09,0x60,0x28,0x7b,0x10,0xfb,0x23,0xff,0x9f,0x78,},{0x08,0x1c,0xfd,0xf2,0xd7,0x58,0x65,0x4c,0x41,0xc4,0x47,0xe1,0xe6,0x27,0x38,0x10,0xf8,0xa7,0x38,0xa7,0x33,0xaf,0xc4,0x22,0x94,0xa2,0xb1,0xbb,0xb7,0x69,0xef,0xce,},{0xb3,0x98,0x7f,0x32,0x4b,0xc7,0xe7,0x76,0xc0,0xf2,0x87,0xfa,0x13,0xad,0x28,0x74,0x16,0x95,0xe2,0xe7,0xbc,0xe8,0xd1,0x43,0xe2,0x9f,0xad,0x5d,0x00,0x99,0x47,0x58,0xe2,0x25,0xfb,0x80,0x21,0x00,0xd2,0x3f,0xd6,0xcc,0xaf,0xee,0x8e,0x0a,0x95,0xbc,0x47,0x9b,0xe8,0xc2,0x3a,0x11,0x31,0x97,0x45,0x76,0x5b,0x7c,0xd4,0x7e,0x70,0x06,},"\x84\xf4\x7d\xd7\x94\x97\x7a\x6c\x15\x05\xac\x8c\x05\x68\x0c\x56\x15\xa2\xd5\xb0\x57\xe3\x9b\x04\xf8\x5e\x3f\x9f\xf0\x49\x60\xe0\xe0\x16\x68\x5a\x86\xee\xbc\xec\xf6\xfb\xce\x5f\xdd\xcd\xac\x1a\x47\x4c\x8a\x0d\x50\x2c\x40\xe1\x0f\x94\x86\x46\xfd\xac\x6c\x81\xf1\xff\xbb\x17\x7a\x2a\x49\x63\xb6\x78\x25\x90\x3c\xde\x65\xb5\xdb\xe0\xd8\x94\x1d\x54\x6c\xff\xa2\xbf\x8a\x8c\xa8\xd6\xc6\x40\x85\x30\xa6\x29\x0f\x5d\x08\x82\xf1\xa1\x67\x2d\xbf\x97\x8e\x10\xc5\xc8\xaf\x5e\x0a\x62\x39\xf0\x65\x5e\xe7\xfd\x9e\x66\x96\x30\x77\xa0\xe8\x47\x13\x73\x97\xd1\xf0\x69\x99\xdc\x6f\x8a\x94\x5c\x60\x03\xea\x4e\xa7\xfd\x58\x37\x8a\xcb\x44\xed\x57\x80\xea\xa3\x67\x79\x6b\xee\xa3\x7d\xdc\x23\x69\x99\xd0\x12\xd6\xa7\x16\xd7\x91\x56\x49\xcc\x28\xe5\x88\x75\x64\x7e\x9f\x5a\xc0\x55\x3c\x0f\x54\x4d\xf5\x64\x69\xc6\x70\x81\xd5\xe3\x03\x95\xf3\xe9\x60\xe6\xa5\x2f\x08\x33\x19\x2c\x54\x8c\xd5\x7c\x92\x6b\x82\xdb\x48\xc3\x61\xbd\xe7\x03\x33\xa3\x70\x08\x3e\xaa\xa0\x68\xdc\x2a\xe4\x52\xd2\x1e\xf1\x33\x1a\xed\x19\x0b\xd3\xe1\x28\x9a\x10\x4c\xf6\x67\x83\x43\x77\xcf\x7b\x5a\x29\x77\x48\x07\xc3\xf1\xea\x9e\x7b\x28\x83\x1d\x0f\x6c\x42\x94\x78\x58\x67\xb1\x37\xb6\x50\x28\xc1\x4f\x93\x2a\x1b\xa8\xe6\xf9\xf5\x96\x24\xfe\x0c\x39\x68\x43\xea\x19\xe4\x6f\xba\x09\x14\x2c\xf9\xd4\x24\x97\x31\x2f\x36\x02\x44\x03\x2f\x1e\x00\xf3\x8d\xd0\xde\x29\xf9\x63\xb5\xcc\xc1\xef\x12\xb2\xcc\x62\x04\xb9\x94\xaf\x1f\x3b\xaf\x19\x6d\x9e\x21\xe8\xfa\x4f\x09\x73\x20\xc6\x44\x04\xd0\xb7\xd5\xab\x38\x56\x0c\xa0\x65\x53\x64\xb0\xb0\x9c\xd6\xdc\x0f\x0e\x05\xb8\xc9\x11\x03\x64\xf1\x42\x4a\x96\x72\xb7\xef\xdf\x7e\x1f\x37\x8e\x23\x45\x50\x56\x6d\xbe\x13\xb0\x15\x78\xb0\x41\x53\xe9\xc3\x7b\x55\x3e\x32\xa4\x44\x1b\xc9\x7e\x29\x53\xbe\xc2\xe4\x14\x55\x51\x0f\x98\x02\xef\x94\x8d\xcb\xf1\x3f\xad\xdd\x72\x2e\xde\x57\x36\x27\xb2\x58\xd5\x5e\x83\xc0\x89\x5b\x22\x91\x9e\x4b\xe5\xce\x8d\x81\x9c\xe6\xad\x84\x3b\x2d\xd0\x9d\xf6\x40\x04\xc8\x26\xc1\xdd\xe7\xce\x64\x80\xa2\x71\xa8\x58\xa1\xdb\x16\x9e\x14\x94\xd4\x46\x90\x32\xbc\xc1\xcc\xd8\x96\x53\x19\x8b\x7c\x07\x3f\x76\xa2\x6a\x29\x99\xb5\x64\x8c\xba\xdc\x15\x74\xc7\x8e\xad\x8e\xec\xe8\x3b\x91\xe1\x29\xc4\x37\xf9\xee\xec\x04\xc8\x07\x45\x90\x02\xe6\x6d\xcc\xa9\xbf\xc2\xca\xed\x9e\x6c\x0b\xa2\x3d\x23\x55\xde\xf7\x56\x65\x74\x94\x30\xee\x92\xc5\x32\xa6\x95\x47\x9f\xec\x92\x91\x74\xf4\x40\xec\xb6\x1a\x5a\xe8\xb2\xb7\xe9\x58\x92\x05\x58\x26\x89\x78\xf7\xfb\x4d\xa1\xb3\x8b\x12\x01\x4f\x5d\x61\xb0\xfd\xd7\xf6\x13\x6b\xa4\x28\x1b\x41\xa3\xa3\xcd\x18\x80\x52\xb6\x98\x76\x5b\x6f\x05\xe4\x1e\x78\x37\x3e\xa8\x30\x46\x97\x87\xa3\x75\x10\x99\x3d\x12\xf9\x3e\x96\xc7\x2d\x72\xf4\x46\x19\x84\xf6\x91\xa4\x1c\x7d\x33\x97\xdd\xd5\xa1\xb3\x92\x37\xd1\x30\x88\x64\xd4\x15\xfc\x6c\x22\xb6\x3f\x37\x6c\xed\xde\x37\xf5\x25\x2b\x51\xec\x72\xe5\x15\x5f\x3b\xdb\x4f\xcd\x54\x12\x49\x8b\xd2\xe0\xc1\xf9\x85\x0b\x3a\x85\xd1\xdf\xd2\x51\x67\xa3\xcd\x77\x1e\x8e\x4c\x9d\x86\x8c\x95\xa7\x17\x5e\x37\x75\xf6\xce\xf1\x7e\x4e\x36\x49\x7c\xe9\xe4\x55\x32\xbd\x7f\x44\xb2\x77\x6e\x40\xf9\x1a\x07\xca\x4f\xa1\xb9\x5d\xbe\x81\xcf\x8f\x49\xe4\x6b\x6c\x82\xa6\xee\x43\x47\x91\x8a\x76\x43\xb0\xd9\xa3\x88\x57\x21\x2c\x69\x3e\xad\xac\xfd\x37\xa5\xf1\xd9\x15\x58\xf5\x45\x4d\xcd\xd0\x59\x35\xf2\x90\xe6\x2d\x7e\x65\x00\x6c\xd5\x49\xf6\x55\x3c\xe7\x41\xdf\x44\xd3\x96\x44\x00\x1e\xb4\x79\xca\x69\x56\x8a\xd1\xf2\x3b\xba\x09\x9a\x41\xa4\x72\x94\xdb\x93\x87\x31\xc5\x30\xaf\x1c\xeb\x92\x17\xd2\x9b\xc2\x70\x56\x13\xc1\xa1\xfe\x9c\x20\x8d\x0b\x01\xba\x6f\x4d\x9b\x4c\x7b\xa8\xf0\x21\xdf\x91\xea\x2d\x57\x8c\xe0\x83\x12\x3e\x83\xba\x4b\x9c\x50\x40\x7f\x66\x66\xfb\xe6\x11\x58\xb0\xd1\xb9\x57\x77\x72\xe3\xea\xff\x8f\xb4\x29\xd0\xf6\xd2\xe3\x84\x12\x61\x30\xf2\x1b\x44\x9f\xb1\xdc\x17\x0d\xb4\x5a\xf5\x05\xbd\x31\x82\x67\x8a\x9b\x5f\x9f\xdf\xf6\x5f\x04\x13\xb6\x72\xc4\x78\x63\x40\xfc\xf2\x52\x2e\xa7\xf3\xd8\xad\xe8\xa0\x59\x52\x96\x49\xdb\xda\x9c\xe5\x1f\xf0\x5a\x2a\x2a\x3d\x66\xd2\x16\x6b\xf2\xc9\xc6\x77\x2b\xa0\xef\x41\x05\xe6\x8c\x05\x5e\x02\x13\xd4\x2c\x1e\xe1\x23\xb3\xc1\x21\x78\x43\xe6\xec\x57\x5d\x75\x4d\xf3\xc9\x0a\x75"}, -{{0x65,0xfc,0xbd,0x62,0x6d,0x00,0x21,0x11,0x33,0x4b,0xaa,0xd4,0xe6,0xa8,0x00,0x6e,0x47,0xa1,0xf9,0x13,0x97,0xbe,0xe6,0xdd,0x6c,0xd7,0xda,0x5a,0x0e,0x02,0x48,0xa4,},{0x20,0x40,0x9a,0x14,0x6b,0x42,0xc9,0x6b,0xea,0xb0,0xb4,0x2e,0xa7,0xf2,0xc2,0x51,0x93,0x11,0x9d,0x0d,0xf4,0x4d,0xc2,0xbf,0x14,0xd1,0x1a,0x32,0xfd,0x73,0x36,0x15,},{0xbc,0x78,0xe1,0x6b,0xa6,0x74,0xe0,0xa7,0xdb,0xa5,0x7a,0x19,0x09,0x4f,0x97,0x33,0xc5,0x5d,0x74,0xb9,0xd1,0x5f,0x8a,0x44,0xd1,0xbb,0xc0,0xa0,0x23,0xf7,0x01,0x55,0xde,0x29,0x77,0x11,0x1a,0x41,0x7e,0xef,0xa8,0xcb,0x30,0xec,0x12,0xab,0xc8,0x38,0x42,0x28,0x16,0x7c,0x70,0x98,0x2a,0x82,0x06,0xb1,0xff,0xb7,0x21,0x74,0xaf,0x01,},"\xe4\xc0\x94\x7f\xc8\xca\x78\xfa\x88\x63\xf4\xd0\x44\x49\x9d\x03\x6e\x2e\x7e\xf8\xc1\x7e\x83\x8f\x2f\xac\x02\x67\x5b\x7b\x53\x81\xe5\xf9\xab\xce\xaf\xd0\xd8\x88\x6a\x92\x9d\x9d\x9b\x49\xfc\xb7\x38\x61\xb2\x9d\x15\x18\xac\x5f\x83\xf7\xf8\xfc\x26\xbd\x1c\xeb\xc2\x2d\x87\x3a\x9a\x08\x23\x14\x06\xfb\x03\x2e\x48\x66\xe5\xf5\x5c\x7c\x04\x41\xc5\x19\x04\x1b\xb2\xcc\x73\xf9\x22\x6d\xd5\xd0\x7e\xce\xb6\x60\xd6\xc9\x67\xdb\x23\x36\x55\x74\xbe\xe8\xfc\x10\x22\x29\x28\x76\x77\x13\x57\x1a\x71\xc9\x3a\x85\x27\x8d\x42\x29\x9a\x70\x59\x9c\xa9\x93\x26\xcc\x86\xf6\xd9\x8d\xaa\xc0\x00\xfd\xfa\x71\x05\x62\xf4\x81\xfa\xa0\x20\xc7\x2a\x76\xe2\x06\x7d\x15\x4c\x23\x5a\x7a\x4f\x29\x70\x8c\xc5\x44\x53\x3b\xd7\x99\xed\x63\x63\xeb\x3b\x56\xaa\x4a\x6d\x0e\x37\x9b\xbf\x07\x60\x05\x95\xc2\x3a\xb1\xf3\xf9\xf1\x70\x8e\x00\x70\x26\x1b\xbb\xf4\xbf\xea\xf6\xd6\xce\xd4\xd7\xff\x72\x2c\x9c\xc5\x2d\x91\x33\xea\x68\xd4\x95\xdc\x94\x89\xc3\xed\xf6\x83\x02\x31\x35\x1f\x65\xcb\x52\x72\xf5\x39\x6e\x2c\x4a\x1a\x5c\x88\x66\x1a\x10\x18\x92\x24\x9e\x23\xd6\xce\x9f\xdb\x6a\x9a\xbf\x74\x27\x2c\x2f\x59\xc3\xd8\xfd\x87\x43\xcc\xe4\x61\x12\x6c\xa0\xa8\xb8\x32\xb4\xb2\x18\x33\x6b\x1a\xe1\x4d\xa6\x77\xba\x7f\x1b\x2c\xc5\xca\x3c\x71\x58\xf7\x27\xa9\xe1\xb8\xfd\xd9\xed\xf5\xc2\x18\x7f\xcb\x83\xdb\x86\x2a\xd0\xc6\xb3\x92\x16\xde\x31\x16\x91\x95\x56\x46\x51\x00\xad\xe0\xa4\x2b\xd6\xba\x10\xd9\x54\x18\xb6\x9a\x3e\x00\x5e\x9f\x10\x45\x89\xea\x59\x48\xb2\xb5\x1b\xc7\xb1\xa9\xa0\x74\x9d\xa8\xf0\x13\x78\x1b\xc0\x5c\x80\x5b\xb5\x1e\x18\x77\x61\xac\x24\xc7\x64\x14\xf6\x68\xeb\x45\xfb\x0a\x50\x24\xdf\xe5\xa5\xca\x06\xf0\x40\x3a\x02\xe3\xb2\xfe\xf7\xa2\xc4\xbc\xfb\x1d\x07\x5d\x31\x0d\x51\x97\xe6\x59\xcd\x14\x02\x3f\xae\xc2\x0e\x04\x5c\xab\xcb\x86\xb2\x21\xa1\xd4\x82\x71\x13\xff\x32\x67\xa6\x4d\xeb\xe9\x93\x90\x04\xca\xba\xc8\x5e\x5c\x74\x61\xe7\xe8\x2a\x97\x5a\xcf\xae\x0b\x6c\x51\x6a\x1c\x60\x53\x74\xcf\xea\x7d\x81\x90\x44\xef\xd6\xd7\x46\x54\x42\x4f\xd5\xc9\x0f\xf2\x57\x4f\xcd\x8e\x00\x77\x40\xd9\x75\x86\x1d\x0d\xf5\x25\x9f\xe4\x3e\x43\x63\x9e\x36\xe5\x28\x95\x43\x9b\xa2\xc2\x7c\x1e\x88\x9c\x93\x09\x41\x04\xfe\x91\x49\x21\xbd\x6f\x25\xd3\x98\x5a\xb1\xf2\x2c\xa5\x57\xb0\xe4\x9a\xfc\x73\x75\x24\x3c\x52\x1c\x6d\x5f\xaf\xe0\x38\x1c\xce\xa8\x28\xe8\x8e\x64\x7f\xd9\x09\x76\xb3\xfb\xec\x19\xfe\x9a\xdb\x11\x3c\x64\x04\xbd\x35\x2b\xfc\x00\x04\x46\xd2\x10\x05\xb5\xf9\x50\xae\x07\xe5\x1c\x76\x8c\xa3\xff\x61\x77\xb2\xea\xc5\x0f\x10\xdd\x2e\x64\x61\x0f\xa8\xab\x57\x88\xfa\xee\xe2\x9d\x12\x90\x09\xd7\xfe\x46\xaa\x3d\xa6\xb9\xd8\x6c\x73\x06\x5e\xb5\x16\x1f\xbd\xbd\xfa\xc5\x77\x7c\x4e\x75\x45\x2e\x6e\x16\xae\x9f\xd6\x6b\xb7\xd9\xaa\xa4\x26\xbc\xb7\xa6\x91\x5f\x0f\xf4\x4a\x1f\x8e\xc7\x13\x94\xe9\x35\x2f\xdf\x20\xe0\x2f\xaf\xe1\xe0\xce\xfe\x50\x74\x4c\x31\x94\x95\x6f\x92\x8f\x82\x53\x37\x55\x37\x38\x38\xdc\xc1\x29\x6a\x89\x1a\xdf\x64\x1c\x73\x82\xd6\x9b\x4f\x5a\x43\xd4\xaf\x77\x72\xa4\xa1\xee\x87\x92\x92\xd7\xa4\xf3\x2a\xc3\x5e\xe1\x21\xc6\xc3\x4c\xa5\xf9\x84\x87\xa9\x41\xfc\xb1\xe6\x5b\x44\xd4\x45\x61\x27\xee\xdb\x2f\xcc\x1c\x3f\x48\xef\xf9\x30\x09\x81\xe5\x2a\xc3\x8b\x49\x6a\xb8\xbb\xce\x14\x4a\x85\xeb\x9c\x07\x63\x8b\x31\xfd\xaa\x78\x17\x44\xbc\xe1\x7e\x8d\x93\xdc\xdc\x60\xaf\xed\xa4\x88\x80\x76\x17\xf8\x8d\x6a\xa5\x44\x22\xfd\x34\x7d\xda\xdd\xef\xf3\x7a\x56\x3d\xbf\x19\x97\x4b\x2a\x23\xbe\x30\x0f\xbf\xa6\xc7\xfc\x41\xf8\x4c\x69\x05\x41\x52\x69\xf1\x95\x99\x0b\x5b\x4d\xe1\x26\x68\xc7\x1c\x87\xb5\x04\xf4\x11\x24\xbf\x94\x43\x6f\x33\x30\x45\x63\x15\x18\x15\x2c\x51\x62\xa2\x47\x5c\x40\xef\xb6\xcb\xda\xaf\x9a\xf4\x28\xfe\xd3\x25\xb3\xa7\xd9\x4c\x17\x52\x0f\xd8\x9e\x00\xdd\xf0\x8b\x22\xad\xf6\x61\xf0\xac\xd7\x23\xb3\x96\x9d\xc6\x43\x4e\xa6\xf9\x2e\xf5\x8e\x8d\xfa\xe5\xb0\xcc\x28\x85\xba\x98\x7e\xa1\xd1\x6c\x39\xb3\x4e\xf6\x50\x23\x00\x9d\x63\x45\xe4\x8e\x36\x91\xa4\x1f\x02\xa7\x7b\x7f\xe1\x33\xea\x9d\xe7\x56\x5f\x15\x7a\x20\x78\xae\x98\x8b\xbb\x26\x6d\x22\xd5\xfa\x91\xa7\xb2\x63\xe9\x8a\xd2\xdc\x07\x31\xfe\x5a\x29\x02\x5a\x0c\xb4\x36\x86\x4a\x5a\x60\xdb\x25\x7f\x1e\x76\xb5\xc6\x08\xf2\x5c\xde\xcc\x87\xea\xe6"}, -{{0xb5,0x00,0x76,0x8a,0x28,0x23,0x91,0x5c,0x4a,0x68,0x48,0xd3,0x5f,0x64,0x87,0xd4,0x3b,0xd7,0x66,0xd2,0xce,0x09,0x45,0xf8,0xa3,0xcc,0xdb,0x8d,0x82,0xa3,0x89,0x2b,},{0xb8,0xce,0xa2,0x15,0xa0,0x12,0x4e,0xed,0x27,0x00,0x57,0x25,0xd8,0x97,0x78,0x1e,0xa0,0x64,0xdc,0xef,0xb2,0x14,0x22,0xc8,0xbd,0x24,0x02,0xc5,0x6a,0x10,0x57,0x1c,},{0xe3,0xdb,0x47,0xa1,0x1e,0x10,0xe7,0x88,0x92,0x5d,0x14,0xb1,0xe2,0x8b,0x54,0xc9,0xfc,0xf9,0xb6,0xac,0xc1,0xdf,0x8c,0x14,0xf6,0x83,0xa5,0x67,0x2f,0xd5,0x04,0xdd,0x4a,0x47,0x5a,0x33,0x93,0xb3,0xef,0x8b,0xce,0xac,0x23,0x61,0xdb,0xba,0x35,0x30,0xaf,0x25,0xc2,0x46,0xc3,0xec,0x4c,0x05,0x89,0x9b,0x51,0x7f,0x6c,0xd3,0x4f,0x0a,},"\x0a\x9f\xda\x8b\x8c\xfc\xa7\xa5\xb0\x5d\x78\x11\x6f\xce\xe1\x9a\xb8\x03\xc1\xc6\x01\x0c\xe1\x1d\xaa\x8e\x93\xa6\x6d\x12\xc1\x2e\x47\x4e\xb9\x1c\x26\x40\xd9\x7a\x81\x3d\x9a\x83\x0d\x26\x88\x68\xeb\x2e\x37\x70\x42\x5f\x10\xc7\x58\x40\x46\x8e\x66\x9d\xc7\xf6\x1d\x3b\xe2\xde\x88\xae\x0e\x54\x2b\xc8\x09\x67\x91\x13\x95\x7a\x14\xda\x4e\xaf\xf5\x49\xbf\xde\x63\x7d\x7c\xaf\xdc\x6a\xa8\x39\x94\x83\x73\x97\xf8\x6e\x4f\xde\x86\xd4\x02\xfa\x9a\xef\x7f\x65\x54\x9a\x21\x43\x73\xe5\x60\xe6\xd7\xa1\xc2\x76\x9e\x0c\x7d\x5a\x01\x71\xe7\xcc\x00\xdf\xf3\x6e\x04\x29\x79\x8b\x53\xaa\x62\x16\x24\xbd\xa7\x4d\x6d\xf0\xbf\xff\xfb\xd8\xfd\x7b\xef\x1a\x64\xf3\x6c\x00\x07\x82\xf6\xed\x03\x1a\xf5\xc2\xa7\x4a\x18\x96\x35\x98\xc9\xba\x06\x23\x92\xde\x96\x02\x03\x67\x94\xb7\xb5\xe6\x8c\x25\xc9\x3f\xe7\xcf\xad\x47\xa7\xc5\xb9\x79\xd4\x76\xcd\x51\x3a\x12\xbf\x03\x07\xcb\x16\x31\x74\x00\x42\xa9\xfb\xf3\xeb\x0b\xe5\x17\x06\x20\xda\xfd\x5f\x16\xed\x89\x34\x2c\x26\x25\xd7\x83\xe7\x4e\xe0\xd7\x84\xbf\x05\x19\x43\x74\x0c\x88\xb0\xbe\xf7\xbc\x85\xe1\xa6\xa4\xa5\x17\xd4\x92\xfb\x73\x7e\x77\x66\x99\x59\x0c\x93\x22\x4c\xd4\xd9\x24\x5d\x4e\x93\x71\xa3\x67\xc0\x71\x2f\x87\x49\x0f\x92\x47\xc4\x9a\xdd\x93\x13\xf2\x77\xa4\xd9\xf2\x6b\x75\xaa\xe4\xde\xd6\xa3\xde\xf8\x5f\x83\xfc\x99\x59\x10\x40\x55\x48\xaf\x67\x0e\xd8\xaa\xa3\x05\x24\xab\x82\x9c\xcb\x56\xa5\x00\x5b\x58\xbc\xe8\x68\xc9\xe8\x07\x4f\x07\xdd\x7f\x38\x18\xf2\x99\xe4\xe0\x86\xbe\xd9\xea\xb9\x02\xcf\x11\xb3\x98\xd5\x31\xb8\x63\x2e\x7d\x52\x3a\x8f\x87\x76\x95\xf4\x6c\xcf\x9c\xe2\x4e\x62\xca\xb2\xc7\xcd\x0a\xae\xe1\x7d\xb5\x26\x76\xa4\xb5\x05\x8e\x9c\x1d\x7c\x47\xbf\xfc\xb6\x41\xb0\xea\x2b\x09\x44\xf3\x9a\x75\x66\x5a\x7e\xf2\x9b\x7f\x02\xa8\x78\xdb\x82\x38\x83\xbd\xac\xfb\x0f\xbe\x5d\xfe\x5a\x9b\xed\x9f\xda\xc7\xe4\x14\x2e\x3e\xb5\x0d\x5e\x84\x0b\xd0\xac\x0b\xec\xf4\xfa\x97\xe1\xfc\x48\x27\xc3\x97\xa5\x24\x65\xd9\x16\x88\x99\x54\xb3\x70\x1b\x0f\xac\x61\x15\x9b\x23\x09\x2f\x46\x85\xf4\x78\x8b\xad\x35\xd0\x0d\xa2\x67\x9e\xcc\x54\x92\x1f\x1a\x86\x47\x10\x16\x57\xab\x49\x47\x74\x20\x56\x7a\xed\x67\xc8\x60\x59\x30\x44\x4b\x5d\x07\x92\x7c\x17\xef\xf1\xf8\x57\x0c\xf2\xaf\x29\xe7\x19\xf8\x5c\xa7\x84\x9b\x89\x55\x49\xf1\x3d\xfe\xca\x68\xbb\xef\x71\xe3\xce\x8b\x6c\xed\xd2\xff\x68\xd3\x2b\x02\xca\xf5\x95\x1a\x0b\x3e\x6b\x0b\xae\x6a\x96\xc0\x20\x58\x19\x1f\x30\x5e\x09\x07\x11\xc4\x6d\xad\xdc\xd5\xae\xee\x76\x9c\x3a\x10\x5e\x9a\x82\x7b\xbd\x19\x5d\x32\x92\x31\xc2\x62\x38\x47\x9a\x9b\xb0\x07\x1a\xfb\x16\x0e\xf9\x55\xe8\x74\xd7\xa4\x20\xc5\x67\x85\xf4\x4a\xe0\xa1\x8c\x52\xd8\x28\x0c\x59\x98\xcf\x38\x88\xfe\xaf\x89\x89\x81\x34\xbc\x8d\x41\x1f\xc9\xf6\xc5\x76\x8e\xa7\xa2\x49\x72\x94\x13\x73\x9e\x53\x2b\x64\x39\x37\x15\x2c\xdf\xb8\xd2\xff\x87\xfd\x48\x08\x4d\xd8\xae\xeb\xea\xf0\xf7\xb1\x0d\x87\xb6\xe4\x42\x32\x28\xc9\xfc\x8d\xc5\xe3\x85\x2a\xa8\xb8\xac\xc5\x45\xd1\x8f\x25\xc5\x5d\x73\xda\x1b\xb8\x2e\x3e\xb3\x76\xf9\xef\x05\xb2\x74\xd7\xec\xb1\x84\x5d\x65\xca\x0c\xd2\x62\x9f\x03\x8a\x2d\x66\x4d\x7a\x69\x78\x1c\x84\xe9\x8d\xe2\xc2\x09\xc4\x6e\xfc\x51\x16\x21\x72\x85\x66\x49\x46\x9e\x67\x33\x08\xdc\xc1\x45\xea\xf7\x83\xf5\xcb\x5b\x4b\xe7\xd9\xfd\x58\xee\x09\x74\xc9\x81\xa3\x8f\xea\x8e\x31\x26\x7a\xbf\xa4\x10\xe6\x9e\x46\x48\x2f\x51\x34\xf3\xda\x1f\xfe\x38\x1b\xd6\x9d\x8d\x0b\x78\xea\x90\x9b\x4a\xf9\x39\x6d\xca\xff\x89\x96\x0a\x04\x9e\xda\x69\x46\x61\x6f\xc2\x7c\xcf\x9a\x9e\x5b\xa1\xa0\x13\x57\x64\xf3\x77\x19\xda\x4d\x28\x07\x81\x85\xd0\x4d\x72\x41\x9c\x2c\x70\xf2\x90\xd9\x7e\x1f\x82\xb8\x79\xf7\x1b\x9e\x19\xd5\x04\xd3\x64\xcd\x3b\xa2\x2c\xf9\x05\x25\x0f\xd3\x7d\x58\xe5\xfe\x40\x20\x9f\x60\x72\xa0\x6d\x8b\x5b\xa7\x01\x96\x23\x05\x77\x87\x7e\xc4\x61\x53\x16\x7a\x7c\x7a\xea\x27\x0f\xa1\x09\x8a\xba\x9e\x3a\x74\xac\xb3\x6a\x11\xb0\x9b\xd0\x7a\x3b\x88\xea\x65\x4e\x26\x83\x65\x62\x5b\x58\x9b\x22\x06\xc7\x10\xd9\x60\xf4\x2e\xa4\x19\xb7\xe4\xe3\xda\x47\x59\xfc\xbc\xa5\x0e\x4b\xf4\xcc\x55\xcf\x88\xf7\x0b\x31\x80\xc8\x05\xa7\x04\x50\x86\xaf\xa0\x4c\x6b\xe2\x32\x23\xec\xae\x5f\x82\xc1\x46\xd5\x43\x11\xd1\x80\x7c\x2e\x4a\x53\xf9\xe0\xa4\x48\x2b\x4e\x1e"}, -{{0x9e,0xb5,0xc9,0xef,0x13,0x53,0x5f,0x80,0x81,0x09,0xf4,0xa4,0x3c,0xfa,0xd5,0x68,0x4f,0x80,0xda,0xf0,0x2e,0xed,0x54,0x10,0xac,0x0b,0x0a,0x09,0xa6,0x08,0x2d,0x69,},{0x36,0x7e,0xea,0x1e,0xcb,0x4e,0x5e,0xec,0xdf,0x7e,0x47,0x1b,0x90,0xbb,0x34,0xf9,0xb7,0x98,0x2c,0x8c,0xd6,0x6d,0x42,0x55,0x5c,0x24,0x0b,0x41,0xcd,0x87,0x39,0xdb,},{0x42,0x9c,0xe1,0xfe,0x84,0x6d,0x25,0x08,0x49,0xec,0xa7,0xd4,0x56,0xf8,0xc5,0x9f,0x86,0x75,0xb1,0xf4,0xc1,0x3f,0x2b,0xe4,0x16,0x88,0xdf,0xb8,0xca,0x2a,0x3b,0x24,0xae,0x29,0xd5,0xb6,0xbf,0x47,0x11,0x57,0xbc,0xb6,0xe2,0xec,0x9d,0x4a,0x26,0xb0,0x38,0xe6,0xec,0x28,0x58,0x4c,0xc2,0x3f,0x2a,0x03,0x55,0x6d,0xbb,0x37,0xe9,0x00,},"\x2d\x7c\xb0\x5e\x61\xdb\xae\x26\x25\x8e\x38\x61\xc6\x39\xef\x0e\x1d\x17\xfc\x71\x1a\x00\xf3\x35\xba\x3c\x02\x71\x37\xe0\x07\x08\xd7\x08\xc1\xff\x45\x7f\xf2\xc6\x51\x12\xf7\xdc\xd7\xd0\x2f\x24\xd5\x6f\x07\x21\x58\xea\x1c\x71\x83\x25\x50\xa5\x83\x66\xfd\x91\x97\x29\x6b\xbe\x61\xaa\x4d\x00\xde\x18\xa4\x53\xef\x91\x74\xfa\x81\x96\x83\x05\xc4\x1c\x34\x55\xf4\x2d\x44\x7a\x92\x34\xf0\x6e\x13\xbf\x8b\xca\xa1\xba\xbb\x11\x69\x5f\xaf\xdc\x08\xf7\xa5\x84\xb2\xea\x1f\x61\xe9\x38\x92\x60\xce\x73\x35\xa0\x7d\xe7\x2c\x89\x11\xa5\x8a\x31\x3f\x10\x88\xdc\xdf\x5c\x8d\x4c\x45\x6c\xba\x2d\xcb\x4f\x2d\x15\x6b\x49\x43\xb9\x5b\xd4\x93\xea\x4f\xe1\xa8\x2d\x4e\x3e\xa0\x2a\xa0\x29\x72\x40\x0b\x5e\xe1\x78\x42\x83\x2d\x59\x97\x9f\xc1\x79\xf8\x43\xc4\x4b\x03\xeb\x3c\x30\x24\x16\xd0\xcd\xaf\x11\xc4\xca\x8a\x66\xcc\xbb\x69\x97\x39\x5e\xdf\x6f\xca\x2e\xa0\x04\xcf\x34\x86\x97\x10\x04\xa4\x20\x42\xaf\x8e\xce\x00\x5b\x94\x46\x1d\x86\xdc\xde\x21\x2a\x2e\xb1\xbe\x3b\x91\x4c\x78\x3e\x48\xac\x1a\xd4\x6c\xac\xd7\x3e\x1e\xb4\x48\x36\x83\x22\xd2\x67\x8e\xfc\xb2\xab\xff\x52\x09\x3d\xb0\xf2\x59\xdc\xe5\xc1\xe1\x9a\x51\x28\x20\xf2\x35\xd6\xae\xaf\x0e\x1a\x72\x3c\x2c\x65\x0c\xff\x1e\xe3\xb6\xb4\xf4\xcc\x98\x9c\x0b\x7d\x6d\xe3\xcd\x7e\x6d\xaa\x39\xbb\x69\x07\x10\xdf\x00\xa7\x19\x4c\x17\x20\x1f\x0e\x81\xbe\x64\xb6\x73\x9e\x1c\x1e\x81\x76\xb7\xe1\x2a\x35\x34\x27\xc0\x67\xc1\x93\x14\xdb\x64\x2e\x5c\x76\x26\x6b\x64\x0e\xb1\xcc\x0c\x73\xf8\x4f\xc0\x22\x7e\x5a\x96\x06\x0d\x81\x40\x71\xcd\xe2\xfe\xd9\x44\x76\x7b\x74\x66\xf9\x00\x1d\xfc\x22\x36\x85\x42\x9b\xc4\xe5\xe4\x8f\x5c\x13\xa6\x3a\x4e\x0d\x82\x61\x33\xad\x92\x0d\x11\x77\x21\x45\xad\x6e\x13\xc9\x38\x97\x39\x8a\x8a\x40\x1f\x93\xdb\xd1\x03\x00\x5c\x7d\xae\x44\x38\x7f\x3e\x80\xb7\x93\x60\x7d\x05\xd2\xd8\xbc\x0d\x03\x51\xa3\xa4\x52\xb8\xce\x75\x9c\x1a\xd4\x8d\xf7\xb9\xba\x9e\x4a\x17\xdf\x61\xfd\xab\xb9\xb5\x77\xb5\xce\xc3\xe9\x46\x1f\xbb\x5e\x12\x81\x55\xa3\xc9\xc8\x9f\x8f\x6b\xeb\xb7\x32\x2a\x16\x67\x8e\x8e\xcb\x98\x95\x3d\x95\x83\x10\xdb\x1b\x06\x34\x48\xc3\x49\xf3\x6e\x16\x8f\xac\x48\x4c\xb3\xc0\xd4\xcb\x2c\x25\x1b\xd9\x2e\xf8\xe9\x26\x2b\x44\x09\x3d\x7e\x65\x0a\x7d\x3b\xed\x37\x91\xfa\x88\x10\x0f\xee\x6e\xf0\xd5\xe2\x3d\x1e\x9a\x80\x99\xcc\x03\x35\x20\x2a\x4f\x10\x6c\x24\x77\x7e\x98\xf8\x1d\x26\xef\xba\x15\xc9\xad\x15\x41\xe0\xad\xbf\x1d\x1d\x76\x07\x6b\x0d\xfd\x7b\x7d\x6c\x8b\x82\xf9\xc0\x93\x46\x8c\xd1\x96\x67\x2d\xc5\x47\x8e\x91\xce\x70\x1c\xdd\x7b\x68\xb3\x53\xc9\x71\x11\xf0\x42\x97\x60\x63\x57\x62\xf8\x68\x3a\xe9\x70\x56\x4b\xce\xba\x91\x20\x51\x76\x42\xe8\xb3\xa2\xba\xaa\x85\xc2\x5b\x54\xa9\x43\x76\x61\x84\x90\x4c\x72\xd9\x29\x63\x4e\xc5\xf0\xc2\x84\x73\x41\x5f\x12\x53\x89\x06\xc6\x78\xfc\xa4\xe6\x82\xdb\x48\x79\x75\x84\x92\x53\x7e\x78\x50\xb9\xbf\xef\x3e\xb9\x05\x3b\x43\x92\x0d\x81\x0e\x55\xbe\x96\x6a\xec\x68\xc9\xdd\x3b\x62\xcc\xf5\x7e\x81\x78\xcb\x5e\xf6\xd1\x6d\x17\x2a\x56\xdd\x92\x4f\x00\xf2\xd3\xb5\xe9\x3a\xaa\x92\xb2\x9f\xb8\x33\x6d\x73\xe2\x9e\x59\xd1\xc4\x7e\xa6\x23\x0c\xda\x1d\x5b\x03\xbb\xa5\xdf\xdb\x33\x1f\xeb\x19\x44\x3f\x12\x3d\x2a\x03\xff\x4f\x10\xec\xa1\x66\xc2\x99\x85\x88\xf1\xe5\x84\xed\x19\x4d\xd6\xf7\x3c\x8a\xca\x84\x66\x31\x90\x4d\x9f\xe4\xa9\x8b\x36\x78\x23\xe4\x6e\xdb\xa2\x88\x51\x29\x87\x9e\x92\x77\xe1\x50\xf0\x29\xb8\xfa\x7b\xd1\x1e\xab\x9c\xe1\x33\x67\x77\xc8\x0b\x56\xb3\xa1\xf0\x81\x1a\xdb\xca\x0f\x5b\x40\x25\xa5\x50\x3c\x81\x96\x66\x1a\xee\x90\x00\x6e\x9c\x85\xbb\xfa\x4c\x5a\x0e\x90\x28\x85\xc8\xce\x51\x21\x2e\xe6\x7f\x0f\xe0\xb6\xaf\xbc\x8b\xad\x45\x37\x27\x54\x3b\x3c\x68\xb8\x90\xdd\xab\xa2\x69\xd2\x5f\xc1\x64\x3f\x54\x83\x51\x36\xa1\xa2\x5b\xa1\x8d\x91\x6c\xed\xd6\xa4\x7f\xc0\x7a\xdf\x6f\xc6\x9f\xa5\x08\x94\x9d\xc1\x0d\x9d\xc5\xe0\x26\x1b\x52\xf3\x65\x71\x70\x38\x4e\xcc\xd9\xc8\x05\x41\x35\x4b\x1c\xe0\xf6\xfb\x5e\xd3\xe8\xd5\x4a\xf0\xb5\xbf\x0a\x92\x83\x51\x25\xc7\xd9\xbc\x4f\x09\x2f\xf3\x80\xe5\xe8\x96\xfb\xf3\x02\x55\x2b\x14\xd5\xb6\x1a\x22\x4d\x86\xe3\x01\xc7\xa6\x6a\x66\xe4\xe4\x32\x9a\xac\x0a\x66\xb1\x56\x77\x23\x74\xdc\x1c\x71\x68\xd5\xb5\x61\x65\x2f\x8f\x43\x87\xe4\xf2\x89\xb6\x36\x6a"}, -{{0xef,0x09,0x48,0xe1,0x32,0x81,0xf3,0xcf,0x35,0x2c,0xbf,0xaf,0x8d,0x89,0xd1,0x17,0x76,0x85,0x52,0xd5,0xa1,0x54,0x8e,0xcb,0xaf,0x37,0x41,0x2e,0x97,0x67,0x0f,0xac,},{0x58,0xc2,0x45,0x7f,0x5a,0x5e,0x3c,0xfb,0xf4,0x71,0x19,0xa8,0x7f,0x2a,0xff,0x19,0x18,0xf1,0xe6,0x7a,0xe6,0xfa,0x91,0x71,0xd3,0xf4,0x1e,0xee,0x07,0xa8,0x68,0x72,},{0xcc,0x12,0xf6,0x9d,0xb6,0x3a,0x67,0x8e,0xc4,0x77,0xa6,0x05,0xa5,0x05,0xc5,0x7d,0xc2,0xb8,0x10,0xef,0x85,0xe3,0xe3,0x45,0x19,0xcb,0x25,0xc5,0x10,0x63,0xaa,0x66,0x35,0x5d,0x3f,0x1e,0x29,0x74,0x69,0x58,0x66,0xed,0xf6,0xf1,0x71,0x71,0xce,0x37,0x84,0x2f,0xba,0xb5,0x07,0x5f,0xc8,0x95,0xd1,0x8e,0xd7,0x43,0xc5,0x46,0x08,0x0c,},"\x7e\xc4\x7f\x2f\x1f\xe3\xb7\x0a\x6d\x1d\x82\xc7\xcd\x92\x4b\x4b\xf9\xb2\x02\x9f\xc1\x2c\x52\xa6\xe1\xcc\x06\xcf\x5a\xbf\xc0\xa4\x42\xe7\xcf\x14\x5c\x15\x42\xb9\xb1\x35\x04\x96\x65\x71\x10\x35\xe3\xc2\x9a\x91\xd4\xfd\xae\xd6\x12\x70\x57\xa8\x12\xc2\x2c\xd7\x5a\xd1\x87\x9b\xe1\xd2\xc6\x11\x0e\x79\xe9\x87\x52\x4e\x4e\x8f\x27\xf1\x6e\xda\x90\xcb\xd4\x73\x3f\x11\x18\x25\xb5\x16\xd1\x06\x7f\x81\xec\xa5\xe6\x94\x85\x76\xd5\xbf\xed\xb3\x27\x7c\x1a\xbc\x1e\x60\xf3\x74\xd0\x70\x1b\x32\xcc\xfd\x6a\x5e\x9c\x8d\x16\x59\xaa\xf3\xd0\x81\x86\x13\x61\x3b\x7e\x28\x8d\x84\x5e\x9a\xaa\xba\x2e\x3e\x9b\x41\x1d\x50\x1d\xff\xe8\x56\xfd\x31\x3e\x9f\xcc\x9e\x74\x30\xb9\x98\x3f\x20\xab\x4e\xbf\x4e\xb6\x16\xbd\x63\xe2\xc5\x77\x43\x65\x89\x95\xed\x0a\x14\x9a\xe6\x20\xa3\x95\x61\x37\x19\xb3\xed\x7c\xed\x45\x88\xd5\x91\x5d\x70\xa2\xf0\xc6\x87\x68\x0e\xc3\x4f\xe3\xe9\xf7\x23\x92\xe1\x89\xe1\x3a\x47\x49\xd5\xca\x9f\xac\x65\x1b\x92\xc0\x84\xc4\x06\x6f\xdf\x98\xa8\x69\x22\x3e\x4e\x0c\x9b\xec\x58\x12\xb5\xc1\x90\x0e\x6e\x60\xd3\xa1\x88\xd4\x8a\x74\xdf\xd4\x15\xb5\xca\xd2\xe9\x1f\xf7\x6d\xf7\x50\x89\xd2\x0a\x75\x5f\x26\x07\x56\xc8\xf1\x38\x2a\x29\xf7\xb9\x37\x26\xe7\x31\x07\x1c\xd4\x77\x45\x8c\x6f\x20\x22\xdf\xad\x7d\x4f\xc7\xab\x23\x80\x54\x18\x64\xf6\xb5\x87\x74\xf9\xae\x8e\x5f\x07\x7c\x1a\x8d\xa0\x73\xc3\x98\x53\xeb\x2f\xd4\x77\x22\x0b\x45\xa3\xd9\x22\x63\xdc\x7e\x14\xd3\xbb\x2b\x36\xfc\xa4\x66\xc7\xef\x8a\x24\x75\x38\x72\x5f\x2f\xce\x5c\x72\x21\xbc\x75\x1c\xde\x13\x94\x60\x4f\x59\x31\xd7\x33\x36\x0c\xcd\x47\xce\x08\x77\x12\x95\x81\x80\xad\x84\xfa\xe7\x13\xb5\x43\xf0\x5e\xef\x6a\xbc\x06\x61\x43\x31\x21\xed\x3b\x45\x06\xa1\x46\x50\x25\x31\x6f\xb8\xf9\xd6\x45\x35\xcc\x45\x38\xac\xd4\x06\x4d\xd5\x76\xb0\x74\x0e\x1b\xeb\x13\xbc\xea\xf1\x55\x54\x3d\xc8\x90\x97\xca\x5c\xa1\xcf\xfa\x0a\xd6\x5a\x10\xbc\xb7\x59\x35\x4e\xab\x8a\x42\xde\x73\x4a\xf9\x09\xc2\xfe\xba\x38\x0d\x66\x40\x9f\x32\x5d\x5f\x17\xaf\x9c\xa7\xf8\xcb\x41\x34\xfd\x6a\x2b\x6a\x52\x8d\x9e\x60\xd9\x61\x2b\x8e\x8b\x40\x62\xf8\xe0\xfa\xd1\xe7\xee\xb9\xcb\xfe\xf6\xe9\x73\x8e\xc7\x97\x3e\x1c\xb2\xba\x23\x27\xde\xca\x4e\xa4\x65\x68\xf3\x1e\x12\xf7\x30\xe2\x47\xc1\xd0\x70\x29\xfd\x44\x22\xb2\x98\xff\x23\x98\x02\x3b\x41\x20\xa3\xa4\x25\xff\xb6\x52\x88\x0c\x19\xea\x69\xf3\x63\x9e\x0f\x6d\xf4\xf0\x08\x76\xcc\x45\x28\xe2\x67\xe8\x1d\x59\x43\x19\x9d\x0f\xeb\x6c\xb4\xe1\xba\xf4\x04\xbb\x6f\x8b\x39\xb1\x2d\xbc\xe9\xfd\xc3\x5d\xc1\x58\x06\x6e\x99\x75\xae\x5b\xd3\xb5\x5f\x2a\x41\xa7\x91\xba\xf3\xe8\x35\x1e\xc6\x04\x94\x47\x90\xa2\x2c\x93\x3c\x80\xb1\x59\x0b\xa1\x97\xa4\x70\x6f\x7f\x51\x28\x68\x2e\xdc\xd7\x4d\xd7\x8d\x43\x5e\x78\x7c\x2b\x76\xa5\x7b\x3f\x4e\x7d\x7b\xe2\xef\xd2\x6d\xa5\xf9\xa8\x29\x11\x9b\x01\x50\x8b\x70\x72\xc7\x69\x9c\xe5\x2b\xb5\x78\xcc\x5b\x1b\x93\x66\x1b\x51\x72\xfb\x84\xda\xf1\xba\x36\x4d\x2c\xbd\x80\xe2\xc9\x9b\xca\x9c\xae\xa8\x73\xcc\x0a\x16\x29\xea\xc3\x84\xe9\xb2\x06\x84\x2a\x6e\x61\x83\x38\x75\x91\xb4\xaa\x34\xa9\x5f\xd8\x9b\x49\xd8\xd1\x5d\x91\xe2\x19\x40\xe1\x7d\xca\xf1\xef\xf8\xa0\xa4\x7a\x0d\x7a\x95\xda\xea\xd8\x2a\xa3\xdf\x82\x04\xa0\xcd\x20\x69\x24\xae\x51\x0f\xec\x8a\x9c\x4e\x8d\x85\xd4\x66\xfd\xb4\xdd\x36\x5d\xc9\x93\x36\xb2\x2c\xe0\xb9\x56\xb5\xee\x00\x17\xf2\x9d\x25\xee\x66\xfb\xdc\xec\xb0\xd9\x96\xff\xb9\x7c\x8d\xef\xde\x40\xa9\xff\x99\x93\x19\x3c\xa8\xf1\x68\x50\x67\xc1\x9c\x52\x6e\x0e\xfe\xd2\x36\xf8\xed\xb8\xde\xf6\xc2\xa0\x3e\x21\x95\x2c\x86\x12\xd6\x24\xe6\x88\x6a\x31\x1f\xfb\x9e\x2f\x15\xda\x44\xab\xe1\x80\xd2\x6a\x14\xb1\x5f\x63\x56\x1e\x09\x7a\x73\x0e\xca\xbb\x79\x2c\x7c\x23\x5f\xdd\x36\x0f\x57\x1f\x27\xef\x68\x67\x7a\x7d\x63\xbe\xb4\x97\x59\x82\xcb\x19\x9a\x56\x0f\x81\x6e\xe1\x29\x89\x44\x5f\x7f\x75\xb8\x3e\xb2\x78\xd6\x28\x25\x94\x7d\x84\x09\x9a\xf2\xa6\xff\x2e\xad\xbb\xf5\x89\xb5\xeb\x2f\x72\xed\x11\x4c\x73\x15\x11\x53\xae\x00\x22\xbc\x95\x64\xd1\x5c\x2d\x5c\xdb\xba\xab\xbe\xf6\x38\xf0\x30\x95\xf5\x3e\xeb\xac\x96\x83\x40\x9a\xd3\x06\x0c\xfb\x7c\x70\x37\xb9\xb0\xbe\xfe\x06\x9c\x92\xa0\x2b\xe9\x53\x38\x8e\x9e\xa4\x5d\x36\xdd\xf4\xf5\xa8\x38\x94\x32\xcc\xf5\x04\xc5\x08\x08\xb0\x7f\x69"}, -{{0x90,0x3f,0x3b,0x53,0x99,0x89,0x2e,0x29,0xcc,0xfa,0xfb,0xaf,0xbd,0x7c,0xc4,0x53,0x3c,0x15,0x4a,0x62,0x56,0x82,0x40,0x6c,0x89,0xbf,0x89,0x4c,0x88,0x9e,0x43,0xf4,},{0x8f,0xa5,0xff,0x5b,0x6b,0x26,0xbd,0x67,0xdf,0x86,0x40,0x46,0x42,0x9d,0xf1,0x24,0xb5,0x23,0x00,0x5d,0xd8,0x94,0x44,0x27,0x5c,0x8a,0xb7,0xeb,0xdd,0xb6,0xf4,0xdb,},{0x49,0x5a,0x8f,0x99,0x19,0x41,0xc6,0x29,0xbd,0x64,0x1a,0x67,0x47,0x1a,0xb8,0x60,0xbf,0xd3,0x9b,0x72,0xf2,0x33,0x55,0xf7,0x27,0x09,0x09,0xd5,0x30,0x7c,0x77,0xb1,0xb9,0x4b,0xae,0x3e,0xd1,0x94,0x50,0x78,0x0e,0x90,0x85,0x30,0x5f,0x31,0xb1,0xe1,0x68,0x3f,0xac,0xf0,0xd1,0xfc,0x88,0x40,0xae,0xc7,0x7d,0xf6,0x7a,0xea,0xb3,0x02,},"\xa2\xc1\x1b\x5f\xb8\x84\xa8\x22\xfa\xe6\x4d\xa8\xdc\xb4\x45\x2c\xfd\x7a\x04\xca\x6d\x7a\x5a\xbc\x8d\x82\x71\xe9\x3f\x93\x44\x9e\x1f\xeb\x8e\x02\x97\x5f\x49\x6b\x90\x34\x40\x0d\x35\x99\xab\x97\xaa\x39\x97\xda\xd1\xc9\xff\xab\x5b\x9f\x8d\xf4\xaa\xa5\xb8\x40\xd9\x0d\x86\x2f\xff\x7f\xf0\xcf\x73\xa6\x0c\x66\x15\x00\x09\xe0\x1c\x93\x7b\xd1\xaf\x68\x07\xb5\xba\x2e\xf6\x12\xee\x13\xd6\xde\xf4\x0b\xb0\x9c\x46\x81\x1a\x2d\x4e\x46\x8e\x03\x8b\x32\x30\x55\xf9\xdf\xbd\x01\x82\x9a\xe2\xf1\xa5\x35\xef\x02\x95\xca\x1e\xd1\x76\xe4\x6d\xe9\x96\xcc\x87\xba\xce\x45\x35\x62\x33\x21\x18\x35\xb6\xf4\x75\x7c\x99\xbd\x52\x7e\x76\x6a\x5f\x0b\x12\x7c\x8c\xff\x8e\x6d\x66\xf8\xba\xb8\x6d\x00\x00\x45\x2c\xd7\xf6\x7b\xe5\x57\x78\x85\x13\xec\x07\x09\xb5\x37\xb0\x07\xb4\x20\x16\xe7\xa8\x96\x83\x46\x9b\xd8\xff\x8d\x21\xeb\x10\xc1\x49\x17\xd4\x7f\x2d\xc4\xf8\x26\x32\x4f\x7c\x01\xb2\x4f\x8d\xcf\xf0\x4a\xa6\xd8\x50\x95\xd9\xab\x15\x4b\xa5\xc3\xbd\x91\x9c\x9d\x72\x8d\xbd\xc9\x90\xd1\x9c\xeb\x23\x7b\x45\x29\x07\xbd\xbe\x21\xf9\xf0\x8c\xdd\xae\x5b\xe4\x79\x27\x67\x09\xb8\xae\x73\xf8\x97\x4c\x4b\x11\x38\x41\xad\x53\x5d\x6f\xf6\x22\x3e\xea\x47\xd1\x85\xc8\xe8\xa6\x5f\xde\xe2\xc2\xd4\x58\x00\xc1\x7c\xb5\x56\xea\xfd\x67\x66\x47\xd9\x96\x8e\x55\xca\x9c\x59\x23\x2b\x97\x70\xad\x10\xf9\x55\xfc\xb5\x85\x8e\xdf\x0b\x74\x83\xad\xc1\x81\x7c\x0f\x8d\x02\x24\x04\x82\xca\xa7\x6f\x43\xc6\xd2\xe9\x6a\x4f\xf9\x59\x1c\xd7\xb8\x78\xea\x61\x9e\xa5\x6d\x1b\x58\x86\x31\xe7\x63\x3c\x5e\xcb\x2b\xa6\x99\x83\x98\xcb\x06\xe3\xcf\x75\xae\xb3\xe0\x8d\xab\x19\x63\x2d\x45\x4f\xf7\xdc\x0e\x2a\x41\xf0\x97\x37\xe8\xee\x82\x3d\x1b\x9e\x24\xdd\xa8\x4a\x2c\xe0\x31\x3c\xb9\xfc\xe3\x1c\xb6\x63\xc5\x5c\x05\x64\x5e\x63\x40\x17\x56\xe8\xad\x38\xf5\x17\x4c\x02\xa6\x63\xd8\x15\xad\x64\x42\x2f\xf7\x72\x7d\x4f\xda\x16\xe4\x8d\x4b\xf8\xf6\x60\x2e\x72\x60\xda\x62\x33\x0e\x68\x78\xc3\x47\x64\xe1\x29\xaf\xbd\x55\x22\x08\xf6\xbe\xd4\xf7\xce\xe9\xb6\x71\xf4\x88\x38\x88\x15\xd7\x4b\x49\x51\xb8\x68\x2c\xe7\x6c\xfe\x31\xe9\x38\xc4\x70\xb8\xf7\xa4\x5f\xd6\x3a\x96\x91\xf4\x26\xa7\x5c\x58\xed\x3d\xbc\xe3\xae\x8f\xd9\xd1\x0a\x83\x52\xe4\x7c\xc1\xb1\x2c\x91\x92\xac\x86\x26\xd1\xb3\x84\xb7\x7a\x18\xb9\x86\xe7\x1a\x99\x86\x46\xc1\x37\x99\x2b\x67\xc4\x81\x7e\x34\x63\x45\xfa\xf5\x0a\x26\x59\xfd\xc5\xca\xd5\xc7\x19\x64\x8e\xfe\xe3\x84\x7c\x0f\xf6\xbd\x70\x95\xc2\x8b\x4c\x51\x95\x96\x7c\x90\xcf\x84\xe1\xef\x68\xa1\xad\xa0\x1f\x62\x74\xed\xe3\x63\xfb\x82\xe0\xb5\x49\xa8\x70\x24\x5d\x60\x8c\xae\x82\x34\xf6\xd8\x4a\xbe\xb6\x1b\x71\x84\x66\x09\x36\x20\xd8\x5c\x58\x4a\xb0\x1e\xed\xa0\x91\xee\x8a\xff\x1c\xf6\x7a\x46\x75\x67\x9a\x1f\x40\x03\xe6\x6a\xaf\x43\x87\x1b\x88\xec\xda\x6a\x16\xdc\x5a\xcb\x05\x39\x5f\x2d\xa9\xdf\x70\xd3\xbd\xb6\x14\x38\xe1\xc3\xd4\x09\x81\xe0\x34\x62\x7d\x02\x6e\xe1\xd2\xe7\x9f\x65\xcb\xb8\x18\x9f\xcb\xb3\xcc\x8b\x5c\x2e\x7e\x79\x6b\x5d\x28\x89\x41\x1d\x56\x41\xfb\x86\x9c\x7b\x0a\x58\x9c\x43\x25\x4f\x8c\x54\x38\xaa\xf5\xac\x42\x38\x32\xf0\x18\xd7\x9a\x51\xb9\x6f\x24\x2e\x2d\xe0\xc8\x51\xcc\x5f\xc2\xb2\x06\xbc\xa4\xb5\xbe\x83\x61\x25\xac\xa1\x44\xbb\xc3\x8c\x8c\x63\x8b\xe0\xd3\xbb\xe0\x25\xa1\xbe\x8b\x3d\x03\xd5\x92\x9b\xaa\x64\x9c\x35\x44\xa3\x2a\x91\x5e\x92\x6a\x38\x79\x1b\x13\x4a\x97\x1b\xc5\x2d\x1b\x6c\xa6\x25\xef\xb7\xc2\xf3\xbb\x47\xab\x51\xd4\x3c\x8e\x37\x4d\x16\xcd\xa8\x82\x20\x4b\x71\xca\xfe\x90\x93\xcb\x60\x78\xef\x2b\xdf\xad\x59\xed\xea\xf3\x6d\x0c\x1a\x4d\xc4\x25\xb9\xe7\x18\xc4\x51\x85\x22\x5a\x9c\x30\x84\xb7\x82\xbf\xe1\x63\x49\x2f\x8e\x84\x82\xec\x9a\xa0\x73\xf6\x90\x1f\xf3\xd1\x11\x7c\xe9\x17\xe1\x91\x22\xfa\x67\x65\x0d\x85\x8f\x8f\x82\xb3\x76\x69\x72\x3c\x22\x6d\x72\x16\x97\xe7\xae\x33\x59\xf5\xa6\xb0\x24\x24\xee\x87\x94\xcb\xea\xa6\x41\xed\xbb\xf7\x53\xb1\x03\xa5\xfe\x15\x8b\xe0\xba\x60\xd8\xa2\x12\xd4\x2f\x8c\x5c\x2a\xf2\x54\xbf\x1b\x9c\x80\xdf\x6f\x1c\xf0\x9d\x70\x79\x3c\xae\x1a\xbb\x46\x27\xb1\x78\x0f\x1b\xce\x7f\x61\x7e\xe5\x0f\x6b\xd4\xb0\x83\xb2\xfc\x7c\xd8\x44\xaf\xb7\x23\x80\xd5\xcb\x6b\x25\x5b\xf4\x7e\xa7\x1c\xad\x6c\x6c\x4d\xf0\x21\xf8\x1b\x54\x8f\x43\x2c\x18\xac\x36\x6c\x6a\xec\xd0\x3b\x6c\x8c\xe2"}, -{{0xee,0x81,0xe0,0xfb,0x05,0x2e,0x23,0xad,0x75,0x9d,0xe6,0xaa,0x98,0x38,0xde,0x98,0xe3,0x6d,0x48,0x20,0xdc,0x0e,0x1b,0x7b,0x3e,0xf1,0x14,0x1a,0xb9,0xde,0x33,0x40,},{0x98,0xf3,0xc9,0x88,0x07,0x94,0xde,0x64,0xfa,0x26,0x9b,0xdf,0x33,0x60,0x95,0xe0,0xe0,0x1b,0x1a,0x3b,0x37,0x5f,0x96,0x5b,0x93,0x70,0x0b,0xbd,0xf4,0xb9,0x68,0x69,},{0xf0,0xd8,0x73,0xbe,0x15,0xcf,0x45,0x4c,0x74,0x34,0xde,0xab,0x71,0xde,0x25,0xcf,0xe9,0x9e,0x81,0xa4,0x8d,0x2d,0xce,0x6a,0x35,0xd1,0x63,0x37,0x14,0xdf,0x0f,0x8b,0x40,0x29,0xe0,0x58,0x25,0x11,0xef,0xc4,0xd0,0x68,0x92,0xf6,0x72,0x85,0x02,0x46,0xbc,0xf0,0x70,0xc4,0x6f,0xad,0xc2,0xfa,0xab,0x44,0xdc,0x43,0x50,0x45,0xde,0x00,},"\x28\xd9\x9e\x95\x18\xb8\x82\x83\xc2\x20\xe7\x6d\xe2\x05\xd7\xb6\x16\x23\x59\xb1\xdf\xec\x1f\xba\xab\x98\xec\x0e\xf1\xdf\x8d\xa4\x0b\x6b\x7a\x77\x5e\x97\x28\x45\x0a\xeb\x23\x51\xfe\x5c\x16\xaf\xda\x3a\xec\x0d\x71\x04\x9d\xa4\xcb\x7d\x4c\x63\x71\x3a\x24\x10\xab\xb0\x22\xf8\x16\x11\xcc\x06\x45\x87\xc8\x04\x7d\x43\x83\xc0\x0c\x3c\x56\x2e\x9c\xee\xa3\x57\x75\x09\x53\x91\xb5\xf3\xdd\xa0\xe3\x73\xc4\xa7\x7f\xf6\x18\xa2\x8e\xf6\x87\x87\xeb\xfc\x3e\xbc\xcc\xc5\xd1\xce\x32\xdd\xf4\x3b\xfc\xe5\x72\x03\xda\x76\xa8\x66\x4b\x3c\x61\x6a\x88\x69\x28\x2d\xb0\xb7\x28\x11\xb5\xfd\x5a\x2a\x03\xa4\xff\x66\x72\x4b\x04\x89\xea\x2e\x10\x73\xd7\x81\xc3\xf1\x89\x11\x5d\x79\xba\x20\xa4\x6d\x1d\xfa\xf5\xb1\xa5\x84\x7b\x2a\x2e\x31\xb2\x80\x87\x37\x56\x9e\x60\xb5\x72\x31\xe6\xa9\x9a\xf2\x6f\x58\xaf\xeb\x15\x77\x08\x10\x47\x48\x12\xfe\x4a\xfa\xcf\x88\x45\x06\xb8\xc3\x14\xbc\x67\x51\xbb\x42\xb4\xbd\x6e\x87\xd2\xe5\xde\x70\xfe\xc5\xf0\x01\x4c\x42\x57\xb1\x34\x72\xa3\xb0\x11\x1a\x7a\x8c\xf8\x3b\x1d\xc0\xcf\x96\x20\x22\xcd\x44\x46\x8a\x3a\xb1\xf0\x01\x6b\x70\xca\xfb\x1d\x02\x46\xac\xd7\x05\x39\x37\xc9\xac\x40\x20\x7c\xf1\x3b\x50\xdd\x15\xe2\xa2\xe1\x5f\x50\xa0\x5b\xca\x2f\x28\xe7\x70\x26\x23\x71\xda\xce\xe0\x2e\x25\xb2\xa5\x96\x58\xed\x90\xc0\x60\x0f\xa2\x65\xb7\xde\x3d\x44\xf8\xef\x07\x21\xbf\x39\xec\x4d\x4e\xca\x58\x88\x52\x7b\x77\x80\x67\xb1\xd6\x59\xc0\x05\x14\xc8\xd7\x05\x62\x73\xa2\x94\xcb\xaf\xe4\x50\x90\xd0\x69\xbb\xd0\x9f\x92\xf4\x61\xe6\x48\xf3\xe6\x82\x88\x2c\x71\x57\x6e\x97\x4d\xeb\xb0\xcb\x7e\x0e\x83\x16\x40\x66\x60\x15\x0d\xab\xb5\x8e\x76\x24\x66\x14\xa2\x91\xc1\x2c\xe9\xe0\x34\x6c\x02\x77\x4d\x4d\x09\xce\xcc\x23\x69\x67\x12\xfe\xe2\x50\xc0\xbb\x5d\xf7\xa2\xa4\xc4\x3a\x55\x63\x33\x1b\xcb\xbf\x84\xbe\x3f\x2e\xeb\x06\x54\x53\x2e\x85\xec\x59\x7b\x53\xb3\x2f\x39\x54\xcc\xaf\x0c\xd4\x26\xde\xf9\x1e\xc4\xb2\x08\x41\x69\x48\xaf\x27\xde\x04\xd8\x32\x70\x58\x97\xa0\x4c\x5e\x24\xa2\xe8\x8b\x20\x04\x0f\xd4\xec\xa3\x08\x9f\xdb\x91\x8a\x92\xe3\x5c\x4d\x31\xda\x26\x85\x0b\x9d\xd3\x41\x18\xc7\x44\x49\xa8\x55\xff\x4b\xc9\xff\xf0\xd1\x44\x78\x39\x65\x4b\x00\x41\x79\x99\xfa\x4e\xb8\x91\x02\x13\x3c\xd3\x20\x40\x91\x53\x58\x49\x57\xc1\x04\x89\xdb\x4b\x72\x44\xc9\x59\x07\x98\x8e\x83\xdc\x82\x12\x71\xdc\x1a\xb6\x43\xd6\x99\x2d\x0f\xd8\x20\x49\x2a\xe6\x42\xe2\x4d\x19\xa1\x79\xfa\x75\xd9\x36\x3b\x32\x16\x62\x60\x6f\xd9\x4a\x47\xfd\xb2\xe6\x8d\x3f\x30\xc0\x46\x73\xf8\x09\xde\x01\x44\x94\x5e\xa4\xd4\x18\x3d\x48\xf1\x75\x07\x9e\xed\x50\x32\x3c\x6b\x19\x2e\x02\x0e\x16\x2a\x35\x03\xaa\x58\x2f\xb0\x8b\x40\x36\x24\xa2\x3e\x35\x7e\xed\xa0\x8d\x90\x43\x86\xf3\x58\xc3\x6c\x64\xd3\x14\xc7\x7c\xd9\xd4\xd2\x3d\x58\x1e\xe5\x3d\x81\xff\x97\xad\xa0\x19\xcf\xcf\x04\xeb\x9d\xcc\x1d\xe9\xb7\x4c\x3d\xb6\xb8\x11\x57\x8b\xd4\xf2\x19\xc5\xca\x48\xef\x4c\x82\x6b\x09\xe6\xc9\x6d\x03\x1f\x65\xdd\x48\xb6\xe7\x3d\x0c\x10\x05\x86\xb2\x1d\xf0\x29\x3a\x03\xd2\xed\x7e\x50\x09\xad\x02\x53\x40\xc2\x1d\x09\x06\x06\x91\xf5\xcd\x8a\xf2\xab\x12\xf9\xb8\x60\xee\x87\x81\x5e\x1a\x9f\x40\x0c\x2a\x6f\x63\x4e\xa8\xf9\xb3\x42\x5a\x08\xd1\x0b\x3c\x81\x53\x67\x38\x8f\x4d\x1b\xe3\x56\x31\x8e\xcf\x90\x35\xd0\xee\x97\x5a\xff\xa8\x59\xca\xac\x28\xeb\xcc\xd0\x59\x9b\xb2\xf6\xf3\x52\x36\x61\xbd\x17\x8f\xc9\xe4\xca\xc3\x78\xbb\x9d\xd4\x71\x6b\xb0\x69\x23\xfd\x2b\xbd\x56\xc9\x59\xc4\x2b\x95\xd5\x01\x93\xf8\xbf\x29\x9f\xcc\xa3\xb2\xee\xa9\x4e\xc5\xf9\x85\x83\x92\x4c\x08\x04\x16\xe2\x8b\x54\xfe\x57\x65\x84\x58\xb0\x55\xce\x4d\xe8\xa7\x5f\xc8\x27\x15\xca\xe9\x1d\x37\x5c\xf6\x92\x81\x37\x80\x51\xbb\x61\xfd\xd7\xbb\x00\x68\xf6\x3e\xfa\x6d\x6e\x83\xd8\xfd\x42\x57\xaf\x80\x97\x0f\x4a\x9e\x69\x24\xb2\xde\x0a\xd9\x66\xdf\xfe\x6f\xa4\xa1\x13\xb0\xe7\x72\xf1\x76\x87\x85\xb3\xb4\x20\x49\xf7\x6c\x48\xad\x80\xf2\xc6\x7f\xb0\xf9\x1a\x5f\xc4\x10\x79\x12\x52\x0d\x8d\x68\x3c\x06\x2c\x3a\x22\x2b\xcd\xa7\xe7\x10\xba\xcd\x47\x8e\xe8\x83\x67\xb6\xa0\x59\xa4\x52\xfd\x26\xf1\x14\xa5\xac\xbd\x69\x79\xba\x01\x9f\x7d\xa6\x8a\xc0\x4a\x19\x30\x26\xbc\x1c\x27\xe4\x83\x7b\x1d\xe2\x9c\xce\x09\x0e\x33\x80\xd5\x05\x1a\x58\x64\x09\xe6\x28\xe3\x14\x56\x65\xbb\x1d\x84\xec\xd8"}, -{{0x69,0xd0,0x1d,0x82,0x91,0x13,0x08,0x1c,0xbf,0x5d,0x0c,0x6e,0xf7,0x7b,0x21,0x77,0x5c,0x8d,0x9b,0x68,0x00,0x00,0x05,0x6f,0x03,0xc7,0x5a,0x7d,0x0a,0x05,0x87,0xd2,},{0xee,0x84,0x69,0xdd,0x61,0xcf,0x5d,0xe4,0x00,0xda,0x7d,0x7a,0x47,0x9a,0x44,0x18,0xe6,0x77,0x2e,0x69,0xff,0x53,0x30,0xce,0x5c,0xa7,0x78,0x59,0xfe,0x27,0x17,0x55,},{0x40,0x8c,0xef,0xcf,0x01,0x41,0x7e,0x2d,0xc6,0xa8,0xa1,0x82,0x84,0xe4,0x11,0x65,0x7f,0x03,0x92,0x50,0xc3,0x12,0x78,0xdb,0x28,0x19,0xf9,0xea,0xea,0x42,0x93,0xfb,0xf6,0x83,0x1a,0x28,0x01,0xfc,0x1e,0xa6,0x87,0x16,0x57,0xb8,0x41,0xe1,0x73,0xf4,0x51,0xb0,0xd5,0x75,0xa9,0x37,0x9e,0x35,0x85,0x7e,0x8c,0x72,0x97,0xfa,0x14,0x04,},"\x0b\x9e\x11\x0f\x29\xd1\x98\x16\xa1\x7b\x2c\x75\x47\x8f\x13\xce\xe9\x53\x81\x1a\x19\x83\x01\x4c\xb7\xeb\x0f\x75\x52\x69\x12\x04\x4c\x3e\xa6\x82\x97\x80\xe6\x57\xf8\x17\xc5\x59\x7d\x46\x61\x08\x0d\x90\x34\xc9\x77\x87\x22\x41\x8f\x2c\x3a\xee\xca\xef\x6b\x69\x0c\x5b\xd3\xb5\x93\x70\x10\x86\x98\x8e\x43\x40\xae\xc3\x4e\x01\x72\x75\x8e\xb2\x40\x87\xd0\x3a\x8f\x76\xe7\xcb\xca\x53\xaa\xaf\xc4\xd2\x15\x5c\x75\x32\xab\x54\xbe\x48\x87\x26\x53\x06\x6f\xa1\xfd\xd5\x4a\xcf\xe9\xda\xae\xca\x35\x6c\x29\x0e\x6b\xe6\x33\x55\xb6\xd9\xfc\x52\xeb\x5e\x4f\xcc\xbb\xc6\x08\x35\x07\x13\x2d\xe4\x85\xbf\xae\x9f\x42\xe1\x97\x12\x23\x2b\x71\x64\x02\xc2\x3f\xea\x74\xef\xa6\x9d\x73\xc8\xc2\xe3\xa8\x66\x2b\x8b\x65\xb0\xfd\x00\x77\x41\x01\x3e\x1f\x6e\x3c\xfe\x43\x45\xd5\xc8\x30\x68\x2f\xe6\x00\x21\xd7\x08\xe1\x0a\x9e\x9f\x40\x52\xff\x7a\x6a\xbf\x28\xac\xb1\xd6\xb5\xfb\x03\x8e\xed\x3f\x72\x51\x3c\x35\x5b\xbf\xd5\xc2\x27\x4f\xa8\x5f\xc4\xf4\x46\x97\x4b\x2d\x1b\xc0\x36\x50\x7a\x1e\xb5\xfc\xf5\x5d\xbd\x44\x21\x0e\x53\x82\x74\xde\x80\x8b\x90\x0b\xf1\xc0\xfc\xc0\x24\x12\x70\xdb\x8d\xbd\xcd\x88\x34\x9d\x67\x22\x4f\x08\x7e\x5f\x07\xf6\x99\xb0\xba\xe6\x8b\x2e\xbc\x9a\x4e\x27\xc7\x0d\x3a\xc7\xd9\x96\xfa\x7d\x4d\xab\xd5\x68\x37\x8e\x3f\x93\x90\x5b\x1c\x89\xc6\x52\xd3\x84\xc1\x6c\x2b\xcb\x1c\x98\x44\xc3\x8f\x71\xbb\x13\xe0\xc6\xa2\xea\x95\xb6\x12\xe3\x90\xc5\xf8\x6d\x24\x8e\xa5\x31\xf2\xec\x6f\x63\x9a\x40\x2d\xfa\xcc\xf3\x72\x17\x00\x53\x44\x03\x07\x45\xd1\xf1\xe5\x20\xcc\x19\x5d\xaf\xdd\x7f\x29\x5f\x37\x7b\x8d\x61\x47\x16\x70\x38\x36\x21\x9b\xb7\xb0\x9f\xea\x7a\xae\x9a\xc3\x3e\x42\xdc\xab\x65\xcc\x61\x42\xfc\xd8\xce\x15\xe9\x77\x17\xfd\xb3\x3e\x95\x38\xc4\x4f\x6c\xd9\xc1\xc6\x5d\xb6\x27\x51\xf5\x52\xf8\x70\xf1\x01\x42\xc9\x6f\x9d\xf1\x85\x5a\xbb\x39\xe4\x27\x06\xa5\x63\xab\x15\x45\x11\xfd\xce\x68\x7c\x95\x76\xf9\xed\xc3\xb4\xba\x55\x34\x6c\xe6\x68\x02\xff\xfe\xf4\xb1\xb5\xe1\x20\x15\xce\x8b\x57\xde\x54\x58\xca\xa0\xda\xf3\x41\x96\x81\x28\x58\x42\x88\xc2\xf2\x7c\xbf\xb7\x6e\xab\x28\x6b\xac\x5f\x66\xaa\xd0\x04\x9e\x0c\xa6\x0a\x90\x14\xe1\x79\x01\xc4\x13\x0e\x83\xce\xae\xb4\xc2\x71\x3e\x97\x1a\x23\x5e\xff\x99\x5a\x81\x3a\xe4\xea\x64\xa5\x83\xff\xde\xfd\xac\x82\xac\x76\xea\xf4\xd4\x7c\x4a\xc8\x25\x0f\xcb\xaf\xd6\xb8\x8f\xae\xb4\x80\x15\xf5\xb4\x2b\x53\x34\xa5\x0b\x31\xd4\x50\x2e\xa4\x91\xda\x90\xdc\xe9\x3c\x08\xfd\x56\xf5\xc5\x8e\xed\xb3\x79\x16\x6a\x23\x76\x2b\xe5\xe4\xad\xea\xa6\xf4\xae\x1c\x24\xe0\xca\xc4\xdd\xca\x03\x83\x45\x85\x60\xcd\xc4\x8b\x8c\xd1\xf4\x2a\x3b\xa2\xf6\xff\xb6\x07\x79\x09\xfc\xb2\x94\xad\x1e\xf4\xa4\x4c\x22\xec\x4b\x39\x87\xdd\xbe\xef\x32\x5b\x98\xce\xd5\x68\x15\xea\x7d\x5f\xcc\xf5\xaf\xdf\xe9\x8e\x0e\x6d\x92\x0f\x7a\xda\x2e\xb5\xc9\x16\x24\xc7\x6c\xbb\xa2\x99\x3a\x9c\x7a\x55\x02\x1d\x12\x7a\x66\x7b\x39\xe2\x35\xdf\x4f\x81\xde\xe7\xdd\x14\x28\x98\x77\x8d\xbd\x92\x13\x5b\x70\xb3\xac\xf5\x9f\x6c\x29\xa2\xc9\xd4\xa7\x00\x6e\xf1\x1a\x91\x8b\x3a\x29\x06\x26\x4a\x15\xd6\xb5\x29\x30\x8c\xbc\x89\xf8\x56\x01\xfc\x1e\xa1\x31\x4d\x67\xf7\x56\x6c\xf1\x09\x16\x5c\x7f\x92\xde\x1a\x18\xd7\x0d\xeb\xe0\x24\x34\x9d\xb3\x56\x0a\x6e\x52\x7e\x2a\xc3\xe0\x67\x89\x46\x87\x04\xe6\xb8\xf1\x87\x1f\x16\xba\xe9\x82\x73\x92\xb4\x18\xf1\x08\x6c\xc4\x97\x08\x6c\xed\x14\xb1\x24\x9d\x6d\x87\x94\xf2\x3b\xb8\x77\x9d\x41\x86\x48\xf2\x15\x56\x56\xa6\xfd\xa7\x44\x0c\x56\x28\x4d\x9b\x21\x88\xfa\x7d\x17\x36\xbc\xcc\x9c\xff\x0b\xe5\xb1\xe1\xf5\x51\xff\x81\x37\xff\x59\x66\xed\x9d\x0f\x7f\x01\xc3\xdf\xf2\x98\xe9\x10\x2f\xfb\xd3\x24\xbf\xca\x5f\xfe\x09\x68\xe6\x6f\x9d\x82\xf4\x87\xd3\x03\x93\x4f\x27\xf7\x8b\x28\x37\x8e\xb7\x2c\x38\x27\x29\x62\xa5\xf7\x35\xd7\x39\x2e\x5d\x33\x3f\xd8\x6d\xe1\x67\x26\x9c\x17\xa1\x65\xb9\x2d\x31\xa4\x88\x0a\x41\xe1\x36\xf7\x18\x96\x0a\x91\x9b\x3d\x7c\x4e\x74\xcb\xd7\x3c\x73\xf9\x21\xbe\x51\x3f\x73\x9a\xff\xb2\xe4\x1f\x80\x42\x6b\xb8\xcf\xb4\x56\x4b\x98\xfc\x4d\xe5\x32\x55\xce\x3f\x98\xb4\xd2\x2a\xe6\xfc\xe9\x19\x0b\x55\xbf\x2c\x93\x86\x1c\x1d\xca\xc1\x01\xb5\xe1\x6c\xf0\x99\x91\xc5\xde\xfa\x33\xf8\xd5\x10\x56\xd9\x34\xbb\x4b\x47\x7b\x65\x20\xd4\xc7\xae\x22\xea\x7f\xb3\x10\x9d\xe7\xf4"}, -{{0x4b,0x8e,0xd2,0x97,0x31,0xf1,0x04,0x79,0x5e,0x97,0xde,0xe7,0xc8,0xb4,0x01,0xa0,0x2a,0xfa,0xa9,0xa7,0x95,0xe6,0x13,0x35,0x3d,0x2b,0x95,0x00,0x17,0x65,0x02,0x7a,},{0xf2,0x22,0x98,0x21,0x0b,0x09,0xfd,0x61,0x7f,0xc8,0xb3,0x50,0x74,0xca,0x18,0x01,0xe6,0x07,0x5d,0xc9,0x2a,0x8f,0x50,0x34,0x4b,0x80,0xe8,0x54,0x05,0xa0,0x38,0xf5,},{0x23,0x45,0x88,0x66,0x86,0xeb,0x39,0xb5,0x19,0x9c,0xaa,0xa9,0x61,0x5b,0xc6,0xb4,0x89,0x6f,0x07,0x6e,0x8b,0xd7,0x36,0xc0,0x03,0x8a,0x65,0x17,0xf9,0xc2,0xb1,0x67,0xe7,0x59,0xf3,0x73,0x72,0x26,0x8a,0x69,0x7e,0x9b,0x78,0x60,0x5f,0x2e,0xd9,0x47,0x25,0xf6,0x90,0x5a,0x79,0x00,0x15,0x3f,0xc9,0xe8,0xbe,0xed,0x31,0xff,0xae,0x05,},"\xcb\xb5\xf1\x3a\x0e\xf2\x83\x7b\x80\x5d\x3b\x78\x51\x09\xf9\xf2\xe0\xd0\xa0\x17\xbf\xe7\x69\x2d\x91\xec\x23\xdd\xab\x78\x17\x33\x0b\xef\x24\x7f\xd9\x1a\xb2\xc7\x7d\xd4\x41\x25\x19\xcb\xd3\x84\x75\xce\x0c\xb3\x9b\x14\x80\x09\x2b\xc7\x38\xd4\x15\x2b\x8a\x6d\x55\x24\x8e\x3b\x9f\x32\xcd\xcd\x15\xec\x5d\x05\x9e\xc3\xc8\x84\x75\x54\xee\x47\x00\x53\x94\x97\x4d\x8e\xb2\x35\x92\xd1\x7f\x5a\x39\x6e\x3c\x19\xf8\xe8\x98\x37\x06\x79\xfe\xf5\x31\x8c\x4d\xd2\x99\xc6\x21\x7d\x6a\xbc\xc9\xb6\x1a\x5b\x2d\x0c\xfe\xf6\x95\xd1\x70\xca\x20\xa8\x3d\x6f\xd3\xc6\x66\xc8\xfd\x1c\x10\xad\x97\x0e\x2f\xa6\xaf\x10\xff\x0e\xd0\xcb\xfe\x75\x22\x46\xd0\x3f\x3a\x3c\x60\x32\xdb\xb3\x19\xbc\xfd\xac\x4d\xaf\xc5\x0b\xc3\xe6\xbf\x59\x5f\x49\x1d\xec\x38\x8b\x34\x41\xb8\xce\xe0\xdf\x91\xf5\x5c\xc7\x80\x7d\x07\xf8\xf5\x41\xed\x73\x22\xff\xc3\x9d\x18\xf8\x95\x60\xe4\x12\x3a\xec\x1d\x77\x96\x9c\xf1\x87\x77\x86\xf4\xcf\x94\xb1\x77\x0b\x10\x90\x65\x5e\x8c\x72\xee\xce\xa4\x57\x2e\x46\xf5\x80\xf9\x63\x96\x6d\xb2\xa1\x08\x5e\xea\xbc\x57\xbf\x4a\x84\x72\x4b\x9c\x85\x99\xa4\x33\xab\xf5\x8b\xca\x80\x40\x91\xd3\xd5\xe6\xe5\x04\x8e\xc2\x7b\xf8\x12\x9b\x67\x0c\xc2\xc8\x8d\x9c\xac\x47\x18\x59\xf4\x69\xb9\x18\xf3\xf6\xd7\x0f\x7d\x66\x63\x50\x1f\xfb\xef\xef\x02\x6d\x79\xea\x70\x92\x7c\xcf\x60\x75\xee\x51\x05\x42\x33\x21\xe1\x1a\xee\x9a\xd1\x6f\x98\x7e\xfb\xdd\x00\xb6\x2a\xff\x69\x8e\x52\x1a\xdf\x92\x03\xb1\x5e\x9f\x0f\x3a\xd0\x7d\xca\xd9\xdd\xcc\xaa\xe9\xb4\x90\x24\x7f\x12\xc3\x11\xde\xe6\xb7\x3b\x8f\x91\x24\xfd\xce\x12\x99\xb4\x7f\xb1\x91\x4c\xee\x7e\x3a\x07\x81\x4e\x31\x2c\x3c\xe5\x69\x27\x67\x2c\x51\xb3\x18\x59\x80\xcd\xe5\x7f\x3a\x75\x9b\x50\xbc\xfc\x4c\xb0\x75\x3b\x95\x4d\x97\x13\x5d\xeb\x2a\x05\x32\xe9\x8b\x66\xf3\x9a\x7c\x08\xcf\x4d\x54\x85\x39\xe2\xeb\x9f\x42\x2f\x66\x49\x65\x88\x93\xa7\xc3\xc2\x5a\x4f\xc9\x01\xf8\xc3\x98\xb8\xc7\x27\x33\x91\x1a\x00\x72\xed\x6b\xd2\xf4\x18\x93\x89\xae\x10\xa8\x14\xf6\x48\xd7\x1f\x69\xc3\x7e\x82\x95\x78\x44\x28\x18\x3b\x93\xc8\x01\x3b\x96\x4a\x9f\xef\x86\xb4\x8f\x48\x93\x16\xbc\x22\x2e\x96\xb3\xbd\x15\xff\x14\x9b\x96\x82\x03\x29\x55\x1c\x15\xe0\xd0\x95\xd1\x56\x9b\x1e\x21\x31\xc7\x87\x51\x56\x5c\x30\x41\xf2\x97\x85\x39\x5b\x97\x15\x13\x17\xf6\x2e\x35\x82\xe4\x07\xb1\x64\x9e\x60\xd0\x3a\x85\x99\x12\x0a\x30\x2a\x46\x95\xfa\x86\x2b\x41\x20\xf9\x4d\x22\xec\xae\x72\x39\x8d\x20\x94\xd1\x08\xad\x2d\xbc\x1b\x95\x97\x35\x90\x21\x42\xaa\x5f\xe6\xe7\x99\x65\x59\xf6\xf6\x01\x44\x8a\xea\x02\xf3\x56\xf8\xdc\xdd\x14\x43\x40\xeb\x36\x19\xf9\x86\x5b\xf7\x67\x2a\xea\x32\x6c\x4e\x93\xc9\x9f\x0e\xd1\xf9\xed\x86\x6b\xe1\x5d\x3a\xf2\x67\x5f\x6d\xd6\xe2\x96\x60\x2c\xa3\x73\xa8\x15\xb0\xbe\x46\xbc\x2a\x3f\xbb\xa0\x6b\x88\x05\xc7\x31\xfe\x08\x00\x7d\xaa\x06\x05\x09\x61\xb2\x4d\x14\x69\x3a\x72\x89\x8c\xcf\xb8\xb8\xfe\xdc\x60\xa4\xee\xf8\xff\x79\xb6\xdd\x75\x92\x59\x18\x33\xb5\x76\xef\x48\x29\x4e\x5e\x04\x85\x94\x2e\x57\xc1\x19\x60\x2e\xdd\xf8\x8b\x1f\xae\xa5\x17\xf2\xfc\x2e\x3d\x14\xd2\x46\xa5\x2c\xbd\x71\xa1\x08\xc6\x6b\x6c\xc4\xf2\xd4\x58\x04\xa2\x82\xec\xed\xb1\xb0\xad\x3d\xc3\xb4\x88\x0a\xb2\xff\x78\xb8\xdd\xde\x48\xf7\x46\x6c\x14\xfe\xd3\x49\xe9\x5b\x50\x53\xab\xf1\xbf\x09\x91\x12\x60\x31\xd9\x75\x47\xd1\x43\xc2\xae\x16\x49\x28\xb6\x1c\x07\x08\xaf\x8c\xa3\xe4\xf5\x51\x54\xd1\x3d\x75\xe9\x7d\xb4\xba\x3e\x69\xd3\x6e\x9b\x37\x08\x23\x68\xc2\xf7\x21\xbd\x3f\x95\x12\x6a\x1e\x00\x4e\xb2\xa1\xbf\x26\x83\x43\xae\x21\xd2\x99\x50\x44\xa2\xca\xdd\x67\xff\xac\x9e\x15\x38\x17\x5b\x3c\xc4\x4d\xb5\xd2\x6f\x1d\x5c\xc8\x9c\xa0\xe1\xc1\xee\x85\x37\xa8\xa9\x1d\x32\x4c\x2e\x02\xe1\x8b\x9f\xb9\x73\x0d\x6d\xda\x55\xf7\x2d\x84\x33\x89\x69\x3e\xbf\xcb\xa7\xfb\xe1\xa0\xbc\xff\xb9\xaa\x28\x4f\x4a\xe6\x6f\x44\xa8\xb8\x93\x02\x98\x3b\x22\x73\x6d\x0c\x72\xd6\xa0\x44\xe4\x29\x16\x24\x24\x3a\x4e\x0c\xe6\x5d\x5e\x53\x46\xd6\x7f\xed\x37\x60\xdd\xb0\xc5\x10\xb5\x0f\xf3\xee\xf0\xa1\x8a\x26\x7d\xe7\x30\x47\x6d\xd8\x2d\xff\x70\x72\xcb\xa0\x98\x48\x25\xa0\x04\xdd\x4b\xcd\x8c\x37\xfd\xaf\x1f\x68\x3d\x1d\x93\x80\xe1\x35\xa9\x5d\x24\xb8\x9f\xad\x0b\xe9\x41\xc5\x48\x25\x1b\xec\x90\xcc\xae\x01\x5b\xc0\x56\x7d\xa8\x4b\x37\x1e\x50"}, -{{0x08,0x0d,0x7f,0x76,0x18,0x2e,0xe6,0xbc,0xea,0x89,0x4b,0x1e,0x00,0x60,0x55,0x8b,0x3b,0x12,0x5a,0x34,0x99,0xdf,0x39,0x73,0xb8,0xdd,0x66,0x93,0x40,0x8e,0xe4,0x69,},{0x41,0x24,0x71,0x3d,0x7c,0x2d,0xf5,0x0f,0x93,0x05,0x57,0x30,0xd1,0xb2,0x81,0xda,0xec,0x30,0x28,0xcf,0x2c,0x1e,0x48,0x58,0xd1,0x28,0x70,0x7a,0x23,0xd6,0xde,0xb0,},{0x18,0x5f,0xb1,0xb6,0xd8,0x6d,0xc4,0x44,0x48,0x10,0xcf,0x5e,0xc6,0xfe,0xf0,0xab,0xda,0xfa,0x2a,0x6f,0xcc,0xb4,0x5d,0x11,0xcf,0xb5,0x4b,0xa1,0x6a,0x68,0x43,0xf2,0x80,0xd3,0x80,0x47,0x10,0x02,0xae,0x0d,0x71,0x50,0x85,0x56,0xc7,0x8e,0xd5,0x41,0x5e,0x42,0x33,0x8c,0x16,0x1f,0x2b,0x62,0x1e,0x74,0xcb,0xa4,0xf6,0xa1,0xd4,0x02,},"\xab\x0a\x6d\xe2\x35\x1b\x9a\x84\x98\xf6\x82\x72\xd9\xa0\xa7\xa0\x57\x36\x5d\x34\xef\xa0\xfd\x34\xcc\x3b\xf8\x62\xe4\x9c\xdc\x30\x2b\x2b\xd5\xa3\x0d\x60\x1a\x13\x0e\xc4\x03\x2f\x54\x1a\xe6\xcb\x7b\xa9\x7f\x84\x18\x3d\x2d\x25\x81\x28\x7c\xa7\x01\xd7\xd7\xa9\xab\xa1\x10\xce\x58\xb9\x46\xac\x08\x24\x30\x5d\xf7\x92\x9f\x3d\xd7\xfc\x9c\x87\x32\x23\x86\x37\xe2\xb1\x81\xd6\xe1\x16\xc7\xf6\x6e\x32\x26\xaa\xe3\xce\xd1\x61\x02\x62\xda\x1a\x0a\x4a\xa5\x0a\x1b\x94\x43\xec\x82\x83\x29\xe4\x73\x4d\x28\xfc\x25\xab\x9c\x1d\xe9\xb8\x98\x7e\x5d\xc0\xc8\x13\x19\x16\xc5\xf1\x89\x28\x70\x4a\x71\xe8\x06\x22\xb1\x49\x2b\xf2\xfe\xc5\xd4\xb6\xdb\xe4\x15\xc8\xaf\x2c\xe3\xef\x10\x9b\x34\xdd\x5e\x64\xd5\x68\x46\xf0\x85\x93\x5a\x4a\x5d\x10\x73\x49\x7f\xb3\xfb\x8f\xb7\x7e\x8f\x5d\x5e\x3f\xd0\x0c\x30\x65\x2e\x3c\x5c\xde\x40\xa3\x35\xd1\x4e\x54\x25\xff\xba\x94\x28\x85\xed\x17\xbd\x36\xdf\x50\x69\x24\x23\x7e\x75\xbe\x84\xda\x82\x19\x50\xb9\x14\x24\xfd\x9f\x16\xc1\xb2\xc7\x83\xe9\x0f\x8c\xc2\xcc\xc7\x98\x0c\xe9\x15\xc7\x69\x6b\x06\xa5\x86\x73\x02\x59\xe6\xd1\x45\x88\x58\x2b\xab\x9d\x2a\x39\xf6\x9e\x98\xe7\xf2\xae\x9b\xc0\xc2\x61\x0d\x7e\x04\x57\xf2\x6a\x5d\x66\x54\x3b\xe1\xd6\x5b\x79\xc4\xb7\xc0\xd8\xee\x73\xd0\xc2\xb6\x7b\xf5\x0d\x80\x82\xf0\x06\xf9\x6d\x11\x95\x05\x87\x31\x93\xdf\xdb\xd4\x32\xbb\x1c\x9e\xe0\xd0\x3e\xe5\x4c\xf9\x5d\x20\xe9\x1f\x7f\x3a\x06\x9b\x62\x56\xf4\x21\x59\xcd\xc1\xe6\x00\xa9\xa1\xc2\xf5\xa8\xe4\x67\xd5\xc2\xa9\xdf\xf8\x73\x0e\x6b\xe8\x26\xfb\x2a\x1e\x64\x48\xbf\xc4\xfc\xaa\xaa\xcd\xaa\x76\x62\x35\x1f\xaa\xdc\x91\xf7\xca\xa7\x73\x7d\xc8\x2e\xc3\xd4\xb2\x19\x36\xbc\xa1\xbd\x7c\xe3\x73\xad\x66\x26\x4a\xf1\x32\x41\x16\x75\x49\x31\x8c\xdd\x78\xe5\x63\x82\x7f\x85\xea\xb2\x0e\x0b\x42\xbc\x55\x4a\x71\x2c\x00\x51\xa5\x01\x0d\xc2\xf2\xc7\xdb\x85\xac\xf6\x54\x9f\x9d\x10\x2c\x90\x3c\x1b\xe5\xa0\x52\x92\xc3\x0f\x21\xab\x1b\x2b\x8a\xbc\xbb\xf1\x04\x72\x3c\x63\xf0\xeb\xc5\x54\xfb\xee\x42\x02\x0c\xcb\x14\xf4\x43\x47\x8d\xf7\x7c\x6a\xa4\x4d\xb9\xa5\x7f\x8f\xd4\x4d\x97\xea\x09\x9e\x47\x74\x82\x3e\xbe\x12\x3f\xcf\x50\x16\xa6\x6e\x83\x7b\x2f\x65\xc1\x84\x5e\x68\x1e\xe2\xa7\x05\x9f\xb1\x29\x0c\xd0\xa9\x33\x12\x98\x55\xcc\x83\xc8\x7e\x0b\x3b\xb6\x1e\x44\x13\x4a\xdd\xd3\x63\x78\x50\x24\x6c\xdc\xda\xa2\x9f\x15\xc4\x1a\x3d\x4d\xd2\xc1\xd7\x60\x06\x21\x24\x33\x31\x24\xcf\x09\x14\x35\xfd\xce\x71\x1f\x52\x31\x63\x68\x99\x9b\xef\xa4\xc8\x0a\x39\xb3\x75\x0e\x4e\x38\x62\x89\xe4\xe2\x85\x5e\x97\xb6\x19\xb0\xa2\x57\x99\x91\x24\x08\xb7\xd5\x8a\x4d\xd9\x81\x95\x71\xe9\x01\x43\x0f\x6d\x55\x55\x29\xdd\x63\x0a\x18\x67\x45\x9b\x80\x22\xd0\xe0\xad\xd6\xab\x4f\x12\xf6\x0b\xaa\xc7\x59\x79\xbb\xff\x7f\x62\x58\xd2\x8d\x67\x60\xb1\xff\x24\x3c\x39\xe4\xbb\xd6\xcf\x9b\xea\x57\x2a\x9c\x08\x2d\x05\xad\xcf\xd4\xcc\xf9\xfa\x02\x6f\x2c\x90\x4b\x6e\x78\x2e\xd7\x09\xdf\x77\x48\xa3\x07\xcd\x2d\xc3\xa0\xfc\x41\x23\xdf\x58\x0c\xbf\x49\xe0\x5c\xee\xab\xc9\xf3\x9e\x57\xb7\xf3\x00\x90\x5d\x8b\x31\x00\x91\xfb\x95\x3f\x3d\xef\x36\xde\xb3\xe8\xbf\x37\x2f\x59\x16\xb5\x15\x97\xdf\x02\x4c\xe8\x5c\xc4\xc3\x6e\xab\xdc\x58\x0b\x5c\xf1\x52\x99\x46\x48\xf1\xd7\xf3\x5f\xed\x5c\xd1\x0f\x6e\x29\x49\x16\x1a\x33\x59\xb3\x03\x4d\x45\x0e\xa6\xf6\x1c\xdf\x1d\x5a\xf7\x6d\x40\x10\x2b\x60\x29\x4f\x4e\x49\x07\x82\x49\x02\x6d\x62\xfe\x35\xfd\xf2\x24\x92\x8b\x0c\x49\xba\x2b\x53\x39\xeb\xb1\x92\xc5\xab\x7f\x05\xcd\xb9\x46\xe3\x7d\x67\x1a\x4a\x5e\xf2\xa5\x82\x72\x20\xb4\x43\x8c\xbd\xa0\x57\x36\x29\x28\x06\x64\x8f\x5b\xdd\x52\x42\x0f\xa7\x6b\x84\xa6\xad\xdb\x12\x63\xeb\x0c\x50\x0e\x81\x56\x6d\x71\x8d\x50\x66\x02\x6d\xa0\x97\x05\x4a\x86\x63\x10\x16\xdd\xfb\x70\x6a\x56\x77\xd5\x02\xef\x84\xaa\x73\xb5\x86\x3b\xc4\x0f\xdc\x42\xcb\x73\x21\xac\x5f\x00\xe2\x92\x8f\xed\x7b\x04\x18\x59\x6d\xb4\xb6\x15\x1d\xd6\xbc\x6e\x81\x8f\x02\x53\x55\x2b\xf1\x37\x41\xe6\x96\x80\xe9\x66\xc9\x2c\x29\x3e\x13\xc9\x0f\x7c\x99\x99\xbd\x1e\xc6\xaf\xe3\xb4\xaf\xfb\x47\x34\x0c\x89\x85\x98\x29\xfe\xb5\x99\xdb\x3a\x8c\x3d\x33\xfc\x8d\x45\xfa\x53\x81\x07\x8a\xe9\xf7\x5d\x85\xc1\x49\x6f\x5f\xb5\xad\xdf\x4e\x40\x09\xb7\x64\xbc\xc9\x11\x8e\x92\x75\xdc\x72\x19\xf2\x81\xd0\xd1\xef\x71\x58"}, -{{0x49,0x84,0x6a,0xda,0x7a,0xe6,0x84,0x97,0x1d,0xd9,0x17,0x10,0x79,0x90,0x90,0xb3,0x7f,0xe5,0xad,0x56,0x1d,0x72,0xa3,0x5f,0x2e,0xfb,0x40,0x5f,0x19,0x6a,0xb0,0xec,},{0x4d,0x37,0x0a,0x81,0x94,0xa3,0x04,0x5b,0x09,0xb3,0xbd,0xaf,0xa2,0x7f,0xb9,0xac,0xd5,0x99,0x43,0xa5,0x4a,0xe1,0x4c,0xba,0xaa,0x22,0x00,0xeb,0x0f,0x3d,0xa7,0x1b,},{0xa5,0xc8,0x09,0xd1,0xca,0x4c,0xfb,0xb3,0xdc,0x70,0xa2,0xa3,0xa1,0xf2,0x67,0xc2,0x73,0x30,0x42,0x07,0x19,0xe3,0x60,0x62,0x18,0xa1,0x47,0x1c,0xac,0x57,0xcb,0x67,0x4b,0x9b,0x42,0x82,0x7c,0x5e,0x9a,0x7b,0x25,0xc8,0x13,0x9c,0x13,0xdf,0xf6,0x0b,0xde,0x6c,0x2d,0xba,0xd3,0xa8,0x36,0x11,0x97,0xc1,0xfb,0x19,0xd2,0xcd,0x52,0x0b,},"\xab\x39\x8d\x94\xf9\x28\xb1\xd4\x21\x02\xa3\xe5\x13\xcc\xd1\xcb\x10\x89\x90\x11\x03\x94\x10\xa8\x88\x8b\xba\x26\xdf\x1a\x03\x72\xbd\xba\x0c\xe8\xd8\x54\xaf\x51\xe9\x33\x0a\x8d\xaa\x93\xc1\x05\x80\x90\x6a\x8a\xc7\x2d\x29\x4a\xeb\x95\x66\xfe\x1c\x78\xba\x84\x71\xc0\x6c\x4a\x8a\x75\x11\x3b\x34\x89\x3f\x62\x76\xed\x81\x32\x92\x05\x3b\x95\x6a\x46\x5d\x84\x7d\x2e\xce\x86\xe2\xda\x8a\x9f\x0f\xe3\xdb\x52\xa5\xaa\xc7\x46\xef\x96\x48\x5e\xf8\x1f\x13\x62\xb5\xa4\x2e\xaa\xee\x1f\xbb\x06\x46\x70\x44\x71\xa2\x1b\xf7\x63\x67\xbe\xaa\x07\x81\x2b\x3d\x32\xad\xcd\xed\xde\xd7\x53\x9e\x3a\x50\x1b\x83\xc0\x5b\x19\xa4\x9b\x52\x0e\xde\xdc\x9a\x78\xa5\xfc\x2d\x50\x12\xf1\xd4\xe3\x81\x84\x4e\x79\x2e\xd9\x0b\x0f\x57\xbc\xe3\x75\xc7\x5a\x65\x8b\x2c\x78\xc6\xff\x7d\x9e\xfc\xd4\xbf\xa3\x5c\x47\x68\xcb\xb1\x95\xe4\x82\x3d\x9b\xbd\x83\x5a\x37\x4f\xa0\x4c\xa1\xea\xae\x9c\x56\x6d\x8f\xd5\xaa\x7c\xa5\xef\xe0\xdf\xc3\x17\xff\xfa\x40\x9e\xf1\x02\x2f\x1c\x3b\x37\x6a\x93\x5a\xf5\x57\x08\x3e\x95\x28\x7b\x07\xa9\x8a\xc6\xc1\xb7\xbd\x8b\xb2\x6b\x60\xfa\x7c\x4b\xc9\x19\x73\xb2\x01\xb2\x99\x22\xb4\xb9\xd0\x3d\xd6\x88\x2a\x0b\xd3\xb7\xd9\xe5\xb8\x1e\xe7\x4c\x36\xbe\xc6\x65\xe4\x34\x3c\x8c\x9a\xd3\x36\xda\x38\x50\xc9\xb2\x69\x7f\xe1\xcc\xe2\x9c\x37\x86\x22\xa3\x3c\x24\x8f\x44\x8c\x88\xf4\x8d\xf0\x26\x01\x43\xb2\xa3\x42\xf1\xdd\xee\x74\xd3\xb9\x7c\xa3\xe1\x16\x6b\x15\x69\x93\xda\xd3\x0c\x49\xd8\x10\xd7\x40\x48\xbc\x6d\x46\x76\x52\x00\x4d\x7e\xdb\x65\xc6\xda\xc3\xa2\xc5\xd3\x00\xb9\x7e\xe3\xa1\x0a\x9e\x14\xb6\x9f\x3c\xad\x67\x59\x72\x96\x2e\x1f\x8e\xd9\x75\x47\xad\xed\xc4\x7d\x1c\xf3\x47\x1e\xf3\xb2\x2f\xdb\xf7\x8e\x34\xf3\x1a\x3b\xb7\x66\x9c\x41\xbd\x92\x92\xc3\x80\xbc\xe9\xa4\x2d\x84\xbc\x27\xac\x92\x8b\x8b\xfc\x3c\x63\xd2\x0c\xcd\xb4\x78\xdf\x7d\xdf\x42\x1f\xb1\xcd\x90\x5f\xfc\x4c\x04\x78\x6f\xd9\xae\xf0\x6b\x89\x38\xab\x8e\xf5\x22\x21\x7b\x2c\x04\x51\x5f\x61\xa1\xc3\x12\xea\x83\x25\x3f\x84\x58\xc0\x91\x8f\xcf\xe8\x74\xe6\xe7\xfb\x11\x27\x5d\xb2\xa2\xec\x79\xa2\xd8\x68\x30\x32\x33\xc1\xb6\x97\x95\x2a\x3b\xfd\x3a\xd0\xa6\xf6\xcd\xd5\xe7\x2c\xc9\x40\x9f\x74\x10\xa4\x0d\x5b\x45\x36\xdd\x46\xeb\x16\x11\xae\x86\x70\x36\x71\xb3\xa0\x51\x5a\x03\x77\xbe\xa1\x56\x54\xba\x0a\x0d\x1e\x4e\x96\x02\x63\x28\x42\xf2\xac\xd4\xef\x99\x32\x36\xe9\x93\xf2\x65\x0d\x59\x92\x3f\x24\xe2\xcd\x30\x93\x2d\x8b\xf8\xae\xec\x64\x44\x72\xba\x46\xa0\x78\x81\x49\x6c\x92\xa0\x13\x5c\x67\x5a\xeb\x0c\xe6\x18\x10\x88\xdb\x8f\x15\x6c\xfe\x74\x35\xca\xc6\xc9\x7d\xa6\x37\xdb\x4a\x89\xf5\x13\x31\xda\x13\x73\x1e\x74\x1f\xcc\xc0\x35\x55\x42\xce\x11\xef\xa6\x9d\x05\x38\xd3\xef\x12\x7a\xa6\x87\x45\xed\x30\x85\xd2\x9d\xa9\x0d\xc5\x83\x70\x1b\x6b\x3a\x70\xa3\xef\x3e\x16\xa9\x24\xb3\x32\x03\xb9\x23\x96\xc4\xb9\x45\xf1\x27\xa7\x88\x8f\xa0\x50\x15\xc0\x60\x30\x07\x56\x67\x29\x23\x7c\xc0\x78\x2b\x30\xc0\x20\xd9\x95\x95\x47\xfe\xec\x9f\x4d\x67\x64\x60\xbf\xe0\xc5\xc1\x9c\xea\xba\xee\x06\x82\xdb\x8b\xe6\x91\x35\x18\x1e\xc0\xfd\xd9\xf7\xa6\x6d\x50\xbd\xc3\x79\xe4\xa2\xc5\x98\x17\x8f\x95\x93\x94\x6a\xca\x64\x05\xb1\x77\xfc\xad\xe0\xf8\x64\x21\x58\x3e\xd6\x7e\xba\x18\x72\x22\xa1\xe4\x44\x95\xb3\xae\x54\x4f\xdc\xa2\x8e\x2c\x14\x48\x5e\xab\x04\x71\xaa\xa8\x03\xc2\x9a\x9d\x8a\x48\x92\x67\x64\xfc\xa1\xdf\x51\x40\x7a\xd3\x3e\xc1\x7e\x94\x1e\x6e\x26\x17\x23\x7a\x84\x30\x98\x73\xdc\x71\x36\x55\x87\xbd\xe4\x27\x4b\x5d\xc3\x27\xcc\xb1\xe1\xe9\xc8\x57\xe0\x42\xcc\xca\x8d\x85\x52\xba\x28\x8c\x97\x8c\xfa\x0a\xf9\x9d\x67\xcd\x03\x40\x60\x62\x8e\x23\x52\x5d\xbc\xa2\x07\x67\x9c\xe2\x96\x90\x87\x84\x48\x55\x3c\xd3\x86\x75\xbc\xe0\x7b\xf9\x7b\x93\x17\xdc\x44\x46\x8b\x76\x8b\x15\x8b\x0c\x11\x1d\x63\xa5\x72\x23\x56\x55\xc4\x0e\x16\x59\x7c\xa0\x59\xf4\x0c\x3d\x8a\xc5\xbd\x61\xa4\x87\xc1\x53\x13\x84\x6a\x70\x4a\x78\x11\xb8\xbc\x0c\xee\x61\xe3\x47\x62\xb6\xc1\xb7\xce\xa1\xc4\x6e\x60\x87\xe9\xa3\x6f\x89\x91\x8a\x25\x8b\x3f\xa7\x76\x20\xbe\x10\xc1\x84\xc3\xfc\x39\x73\x90\x24\xe9\x82\x78\xfd\x65\xb8\x2c\xad\x83\x69\x9f\x3a\xd8\xc6\xec\xcb\xec\x8b\x7b\x1b\xd7\x91\x4d\x3f\x6c\x3d\x02\xbf\x40\x28\x3b\x1c\x1f\x1e\x98\xe3\x08\xbe\xae\xbb\xf8\x94\xb8\xf5\xe9\x1b\xbb\xc6\x25\x35\xf9\x23"}, -{{0x83,0x34,0x3e,0x37,0xad,0x09,0x1a,0x85,0xee,0xc3,0x70,0x70,0x1b,0x81,0xa5,0x8f,0x93,0x70,0xa4,0xb0,0x42,0x3a,0x07,0x0d,0x60,0xf9,0x2d,0x8d,0x18,0x09,0x84,0x4e,},{0x50,0xb6,0x8b,0xf7,0x26,0xea,0xbc,0xa5,0x3a,0xc6,0xc9,0x0d,0x4e,0xac,0x55,0x47,0x03,0x71,0x2d,0x22,0x10,0x55,0x54,0xf0,0x5b,0xf7,0x9f,0x9d,0x08,0xfc,0xc4,0x93,},{0x9c,0x69,0x89,0xcb,0xe1,0x7e,0x16,0xca,0xa2,0x53,0xff,0xb1,0xa6,0x4a,0x10,0x6f,0xb0,0x17,0x82,0xc9,0x9b,0x17,0x22,0xba,0xf1,0xac,0xaa,0x42,0xae,0x5b,0x36,0xb7,0x9b,0x2a,0x2c,0xd8,0xfc,0x91,0xf5,0xad,0x89,0x23,0x81,0x70,0x25,0xa7,0x78,0x25,0xa0,0x5d,0xf8,0xc4,0x17,0xec,0x53,0xc4,0xa3,0xaa,0x1c,0x0e,0xfd,0x5b,0xbe,0x0f,},"\xc7\xda\xdc\xac\x5d\x87\x95\xe1\x74\xb6\x91\x38\x91\x2e\x70\xff\x41\xe7\xa7\x25\xfa\xf3\x85\xb7\x73\xed\x15\x09\x89\x72\xb3\x0d\x9b\x73\x93\x72\xd9\x75\xb4\x80\xcc\xfd\xfc\x58\x0e\x2e\x2d\xdf\x5e\x3c\x27\xee\x79\x12\x79\xab\x95\xe4\x38\x2b\x14\x59\xdd\x8d\x41\xae\x36\x0d\x4a\x87\x88\x46\x69\x29\x24\xfe\xef\x39\x0c\x0d\xbb\xfa\x35\xe4\xb8\x2d\x7c\xbc\x33\xee\x15\x81\xc5\x2b\xd9\x49\x38\x5b\x2e\xe4\x02\x63\xa5\x7d\xa1\x17\x4b\xb4\xac\xad\x37\xcd\x8a\xe2\xa6\xb4\x5f\x7a\x6d\x6b\xbe\xf5\xa7\x98\xce\x85\xb9\xe0\x5e\x76\x47\xe3\x34\xec\xfc\x77\x63\x78\xde\x17\x4c\x49\x7c\x0f\x40\x75\xe6\x25\xaf\x7a\xed\x50\x2c\xd1\xcf\x7f\x58\x8d\x0d\x80\x7f\x02\xe3\x2f\x43\x00\xf2\x28\xa5\x0a\x66\x7b\x5a\xd1\xfb\xbc\x17\xe0\xb3\xc5\x70\x51\xdd\xc6\x02\xf5\x76\x07\x9f\x6f\xc5\x88\x9b\x7f\x29\x00\x71\x13\x34\x42\x0f\xc6\x66\xf6\x6d\xba\xff\x41\x26\x33\x6c\x35\x3f\x1e\x5b\x56\x4a\x66\x45\x37\xf8\x37\x86\xda\x5c\x56\x27\x74\x54\x06\xd7\xb2\xfe\x32\x33\xbf\xd5\x8e\xf4\x64\xa0\x6c\x95\xcf\xd0\xb9\x88\xa7\x6d\x05\x3a\x64\x4b\xcc\x15\x9c\xad\x53\xa7\xc5\xdb\xb4\x0e\xef\x5c\xd0\x47\x05\x6a\x3f\x09\x26\x5b\x13\x25\x69\x9c\x7d\x15\x9d\x5c\x90\x24\x40\x17\x33\x57\xff\xab\x8f\x7a\x5e\x38\x9f\x46\x8c\x33\x3b\x78\x2f\x80\x17\x0a\xe9\x09\x83\xaf\x15\x3f\x2e\x73\xbd\x2b\xef\x12\x5e\x3d\x38\x68\xc2\xab\x9e\xcf\x03\xaf\xf7\x6e\xcb\xeb\x18\x16\x7c\xa2\xf7\x11\xcd\x56\x58\x51\xd7\xf0\x4e\xe9\xd9\xb0\x1b\x6d\x83\xa7\x60\x57\x22\x62\x0d\x28\xc8\x4d\x6c\x1a\xf4\x2f\x6a\x76\x92\x58\xf5\x3c\x1f\x66\xda\x36\x66\x6d\xa5\xca\xa9\xbd\x9e\x8f\xbc\x16\x92\x11\xb1\xae\xd9\xc2\x55\x8f\x6a\xaf\x5b\x14\x5a\xbc\x72\x1a\xbb\x00\x72\x01\x94\xe0\x27\x03\x54\x68\xbd\xe3\xfe\x0b\x88\x88\x4f\x4e\x9b\x26\xe7\x71\xe6\xc7\xa0\xa5\x5e\xa3\x6f\xc5\x0d\xec\x8c\xef\x16\x2f\x9b\xba\x5b\x4b\x16\x10\x5a\xfd\x6e\x37\x4e\x03\x8d\x5c\x85\x87\xcf\xd7\xdd\x88\x29\x0b\x2c\x9c\xab\x45\xa2\x64\xd6\x54\x0e\xa1\x41\x6e\x6e\x4e\x74\xa1\x2f\x45\xa2\xef\x13\xcc\x8a\x36\xe7\xb0\xa2\x6b\x90\x2c\x3d\x96\xe2\xe2\x22\x92\x02\xe2\x57\x65\x69\x4b\x94\x33\x73\xd1\x6e\x60\x0b\xd7\x86\xd9\x55\xa4\xb3\xf1\x02\x16\x40\xc3\x9a\x0b\x6c\x69\x15\x00\x28\x1a\xe0\xd0\x98\xcc\x7f\x38\x5e\x18\xa0\x7e\x62\xfa\x4a\x10\x1e\xf5\xb7\x85\x51\xfa\x29\xbd\x15\xee\x03\x53\xa1\xa5\xef\x9b\x21\x6e\x8b\x0f\xa5\x07\x50\xa3\x41\x62\xb6\x35\xa0\xbc\x5e\x5d\x72\x30\xaa\x19\xaf\xa1\x28\xab\xa6\x42\x2d\x38\xeb\x77\xa3\xf0\xbb\x9d\xd8\xe4\x65\x2f\x12\x07\x0a\x37\x36\x1c\x37\x25\x50\x3c\x9d\x22\xe2\xfa\xce\x2e\xa7\x4a\x70\x02\x40\x62\x47\xdd\x86\x97\x5f\x07\x57\x5c\x9e\x7c\x6f\x41\xb5\x3b\x26\xd5\xcf\x52\xc5\xac\xc2\xc5\xd9\x82\x71\x43\x4e\x9f\xa5\x09\xc6\xdf\xbd\x72\x43\x72\xaa\x5c\x13\x45\x1a\xae\x39\x3d\xe0\xa1\x86\x46\x4f\x5d\x33\x7e\x9f\x62\x7b\x4f\x1c\x29\x09\x46\x70\x65\xe8\x9a\x42\x2e\xc4\x0e\xe1\xd8\x0a\x13\x39\x00\xa6\x2f\x4e\x4f\x7e\x94\xeb\x72\x61\x5e\x7e\xc2\x99\x6c\x6c\x24\x30\xc3\xe9\x57\xce\xae\x21\x05\xa1\xe9\x0e\xae\xac\x0d\x31\xaf\xfa\x9f\x57\x92\x6d\x71\xd9\x72\xa9\xa2\xde\x11\x25\x8c\xc1\xe7\x28\x59\x9c\x9f\xb3\x87\x24\x91\x84\x7e\x10\xc6\x7e\xfa\xef\x6b\x69\x6a\x03\x0f\xf0\x53\x3a\x58\x3b\xea\x1d\x04\xdf\x25\xf7\xee\xf3\xa1\x3b\x8e\x31\xaa\xd1\x33\x85\x7d\xf1\xb4\xe5\xff\xbd\xee\x37\xf4\x0f\x38\xd2\x24\xc7\x0a\xe0\x4e\xf3\x3b\x41\xb0\x2e\x71\x91\xa8\x66\x56\xb0\xd7\x2b\x2c\xbb\x53\xc4\x90\x8c\xa2\x06\xf7\x57\x34\xb2\x77\x08\x15\x4f\xcd\x8a\x97\x42\x9c\xfd\x1f\x2d\xa2\x42\x97\x78\x43\x80\x03\xf5\xb5\xb9\xc2\x1d\x9e\xd2\x3b\x8a\xd8\xa2\x28\xeb\x4f\x65\xc2\x4c\x1c\x59\x69\x9a\x5c\x90\xaf\xf7\x73\xe5\xc6\x76\xdb\x36\x2a\x19\x30\xba\x16\xab\xa7\x6e\xf8\xda\xa4\x2b\x3e\xb2\xcc\xc4\x5c\x93\x4d\x23\xd4\x92\x9a\x7a\xd9\xe3\xef\x46\x8b\x06\xa4\x99\x5c\x80\xdd\x23\x6a\x7b\xcf\x38\x79\xd8\xb7\x94\x67\xf7\x2b\x33\x84\xc1\x60\xcc\x18\x17\x14\xe9\x2f\x20\x35\xe7\xb9\x72\xa2\xcc\x52\x42\xd9\x32\x52\x5e\xae\x7c\x50\xbd\x26\x3b\x0f\xa0\x9c\xbd\x9d\x6f\x98\x4b\x9c\xf6\x15\x2d\x9a\x13\x3c\x27\x84\x32\x02\xd1\xe8\x7f\xa5\xa6\xe1\x23\x5d\x9c\x75\x6b\xb8\xe6\x8b\x05\xb9\x8d\xa5\x41\x95\x22\x3f\xdf\x02\x10\x25\x32\x50\x63\x3c\x11\xc5\xf6\x0b\x5e\x67\xd7\xee\xfc\xaa\x6c\x2d\xaa\x52\x31\x37"}, -{{0xda,0x01,0x32,0x21,0xb2,0xf5,0x88,0xaf,0x40,0xe2,0x11,0xa0,0xf9,0x75,0xd4,0x4f,0x9d,0x65,0x02,0x81,0x60,0x51,0x4c,0x39,0x61,0x89,0xf2,0x7c,0x7b,0x06,0x66,0xea,},{0x07,0x11,0x7c,0x6b,0x0d,0xb5,0xb6,0xfd,0xa1,0xed,0xc4,0x39,0x6c,0x47,0xc2,0x2b,0x54,0xee,0x0c,0xe5,0x37,0x5c,0x3e,0xc6,0x33,0xc8,0x3a,0xfc,0x53,0xad,0x6c,0xe4,},{0x10,0xcb,0x52,0xd6,0x10,0xe4,0xa8,0x1d,0x32,0x86,0x9b,0xff,0xce,0x38,0x07,0xe6,0x39,0x1f,0x78,0x2f,0xcd,0x53,0x8b,0x55,0x4d,0x09,0x03,0x7f,0xda,0x72,0x28,0x5b,0x96,0x62,0xb1,0xb1,0x10,0x7c,0x40,0x81,0x78,0xac,0x00,0x9f,0x05,0x25,0x96,0x73,0x88,0xa7,0xd8,0x5f,0xa1,0x23,0x59,0xd3,0xce,0x38,0x75,0x03,0x7d,0xcf,0x6a,0x04,},"\xbc\x93\xee\x1e\xc4\x72\x8a\xc6\x36\xa6\x24\x8f\xcc\x45\x51\xc9\xd1\x59\x80\xdb\x8e\x5f\x54\xb0\xef\x07\x5a\x71\x97\x0e\x17\x6a\x3c\xb9\x18\x2e\x32\xda\x7a\x8c\x2a\xc0\xcd\x7e\x59\x57\x74\x57\x5f\x9c\x83\x50\x6a\x60\x6f\xac\xe8\x95\x12\x13\x5d\x03\x2a\xb0\x5e\x39\xff\xf9\xc8\xca\x6c\x25\xcd\x5d\x78\xec\xc3\xac\x32\x32\x90\xc9\xc8\x16\x26\x73\x5e\x19\x0e\xb5\xae\x34\x5c\xa7\xa9\x58\x40\x9f\x77\x43\xb0\xb1\x61\x49\x16\x83\x22\x17\xc5\x7e\xee\x1b\x4f\x8e\x62\x2a\xc0\x52\xa9\x3d\xd5\xb3\x9d\x07\x61\xe4\x0e\x9f\xbd\x83\x96\xf6\x0a\x3b\xf6\x66\x0c\x5f\xa9\x9c\xd8\x13\x9f\x68\xcb\xe0\x89\x4e\x5c\x67\xe1\x68\xcc\x74\xb2\x72\x4e\x9d\x91\xd6\x00\x0a\x0c\xec\x58\x7a\x11\x46\x3f\x72\xee\x6e\xd2\x55\xbd\x87\xeb\x30\xfd\x45\x75\x96\xf6\x88\xca\x0e\xa7\x3f\x30\x49\x72\x38\xde\x21\xc9\x3f\xbb\x12\x94\xdb\x61\xe4\xa5\x60\x89\x10\x6d\x1c\xf7\xce\x5a\x65\xec\x3d\x12\x17\x0c\xe7\x84\x0f\x08\x8a\x8d\x0e\x3a\xef\x17\xe5\x31\xde\x47\x80\x03\x57\x02\x58\xe9\x27\xf1\x56\xe7\x96\x10\x65\xaf\xa6\x66\xaf\x38\x58\x2b\x35\x3c\xc4\x77\xba\x77\x5c\xae\x45\x94\x6d\x08\xdb\x75\x21\x59\x14\xda\x32\x61\xb6\x22\x94\xe9\x2a\xfb\x38\x14\x59\xc2\x1d\xda\x4e\xa6\xed\x79\x5f\x79\x25\x7c\x09\x4d\xd6\x08\xdc\x8e\x1b\x7c\x40\xcd\x29\xfe\xa2\x22\x08\x8f\x65\x69\x7e\xa8\x88\x95\xd1\x0a\xce\xa8\x79\x73\x60\xdc\xba\xce\xe2\x69\xc6\x06\x60\x0a\xdf\xfd\xcf\x9c\x7c\x38\x1d\x0a\xd6\x69\x69\x67\xd9\xff\x03\xe6\x1a\x24\x90\x65\x02\xb2\x95\xe7\x6f\x4d\x08\x75\x65\x5b\x01\xe6\xff\xca\xcc\x8e\xf0\x11\x29\xc7\x2a\x58\x46\xb6\x0e\xc8\x00\x17\x37\x4e\x75\xd3\x06\x40\x3d\x9e\xcc\xf2\x64\x95\xd2\x98\x12\x0a\x06\x33\x83\x5c\x5d\x1e\xff\x17\xc9\xc6\x24\x76\xf7\x52\xc8\x97\x10\xad\xfa\x4d\x51\x61\x7b\x59\x18\x17\x3c\xba\x72\x25\x40\xe3\x88\xff\xbf\xfb\x96\x68\x74\xdb\x00\x40\x4d\x06\xb0\xce\x11\x39\xba\x74\x14\x3c\x76\xb8\xf4\xd3\x3b\x21\x16\xe1\xcc\xe1\x75\x17\x3a\x96\xfc\x15\x1e\xa2\x39\xbf\xc2\x0d\x66\xfb\xb6\xf5\x2a\x66\x6c\x0e\x81\xcc\x2b\x80\x20\x91\x06\xe2\x48\x0e\x41\x11\xc7\x0e\x7b\xe4\xaa\xbb\x68\x42\x2f\x0b\x8c\x6b\xa1\x5c\x14\x2f\x82\xe6\xc7\xf3\x78\xd7\x80\x0a\x09\xea\xa4\xda\x25\x3c\x2f\xd9\x1e\x12\x63\xc6\xb6\x55\xbf\x70\x25\x5d\x7e\x3b\xb4\x77\x55\x23\xa0\xa9\xe7\xff\x03\x79\x7e\xe3\xff\xca\x8a\x50\xd1\x0f\x20\xd5\xe5\xa8\x89\xec\x5e\x33\x4e\xf2\x6c\xf7\x99\x8b\x08\x36\xf6\x56\x45\x68\x88\xe1\x37\xf3\x9d\x3e\x43\xe2\xce\x3c\x6e\xf5\x40\xd9\x5d\x9a\x20\xc4\x2c\xb8\xae\x2d\x9d\x0f\x25\xa8\x91\xc3\x63\xea\xd9\xcc\x42\x3f\x9a\x32\x3f\xe2\x32\x28\x1f\xb6\x7f\x5b\xe1\xc0\x78\x43\x61\x46\x04\x68\xa8\x7e\x95\xdf\xa3\x5d\x7f\x0f\xfa\x22\x11\xbe\x6b\x5f\xb3\x2d\x42\xba\x65\x18\xab\x6e\xa9\x37\x80\xf4\x31\xd3\x00\x67\x31\xbe\x44\x40\xe7\x12\x97\x4f\x74\xba\xea\x41\x9f\x40\x22\xfa\x25\x02\xe1\xb2\x39\x8e\x93\x86\x16\x7d\x93\xec\xa9\x2c\xa6\x0d\xd7\xd9\x1f\xe8\x23\x24\xf6\x82\xd9\x4a\xa7\xa8\x6a\xb0\x34\xf8\xa9\xe9\x52\xe8\xfc\x95\xbf\xf4\xdf\xed\x6a\x43\x31\x3a\xbb\x92\x40\x1b\x30\xc3\x3c\x79\xa7\xba\x3e\xfd\xbe\x16\x28\x04\x0f\xba\xf4\x43\xf3\xf9\x80\x84\x6f\xdb\x28\x3d\xcc\xd9\x3f\xab\x09\x70\x8b\x7d\x54\x86\x1d\x74\xb1\xfe\x8f\x10\x70\x1f\x21\x1b\xa3\xd3\x90\xe8\xa6\xae\x40\x77\x39\x64\x6a\x79\xa5\x83\x37\xa7\x17\xa8\x72\x00\x9c\x2d\xf6\x76\x1c\x24\x25\xa3\x2a\x00\x18\xaa\xf9\x64\x64\x70\xcb\xc8\x7c\x3a\x65\xc0\xe0\xef\xfb\xaa\x52\x8f\xe4\x78\x3c\x77\x2a\xb2\x66\xb8\xf2\x82\x68\xcf\x14\xaf\x23\x4b\x15\x81\x6d\x1a\x3a\x49\x1a\xf5\xf2\x97\xe3\x3d\x57\x29\x71\x5d\x51\x2c\x37\x3f\xef\x5e\xcc\x3f\x39\x54\xa6\x0a\x2a\x0f\x64\xd8\x29\x47\x41\x19\xca\x1a\x18\xf1\x05\x78\xd0\x4d\x63\x8d\x5e\xea\xfc\x37\x1a\x94\x6f\x6c\xe7\xef\xbd\x2a\xcc\xe3\x4e\x20\x44\x1c\xde\x9a\x37\xd5\xa8\x7d\xc6\x19\xb0\xa7\x27\x59\x6c\xd1\x2e\x15\xcd\x97\x84\xbb\x91\xf1\x39\x9a\x59\xfc\x0a\x7a\x4a\xf6\x8b\x0d\x57\x5d\x93\x38\x71\x72\x97\x33\x75\xc4\x65\xdf\x5d\x2d\x5e\x06\x1a\x2a\x9b\x23\xb4\x91\x5a\x0a\x8b\x8c\x1f\x09\x42\x09\x4a\xf7\x28\xc8\xc3\x11\x45\xfa\x7a\xaf\x74\xa2\x1a\x3b\x03\x2b\xb0\x9c\x39\x22\x05\xbf\x09\x5b\xda\x98\x6e\x5d\xd6\x62\x7c\x1e\x41\x7f\x65\x03\x26\xdf\xe3\xa9\xc9\x99\x4c\x6e\x0e\x01\x27\x6f\x91\xf2\x98\x7d\x2b\x85\xde\xda\x96\x54\x91"}, -{{0x5a,0x86,0x8f,0xb7,0x5e,0xa0,0x72,0x1f,0x7e,0x86,0xc7,0xbc,0x10,0x6d,0x74,0x13,0xc8,0xcf,0x4d,0x03,0x3c,0xe1,0x40,0x05,0xdf,0x23,0xce,0x4c,0x15,0x5b,0xbd,0x27,},{0x6d,0x1e,0x29,0xf3,0x9d,0xed,0xa2,0xbb,0xfb,0xb5,0x7c,0xb0,0x1c,0xb3,0x9e,0x58,0x80,0x82,0x78,0xe5,0x19,0x6a,0xda,0x1c,0x02,0x76,0x46,0xf2,0x04,0x87,0xd2,0x52,},{0x38,0xc4,0x8d,0xba,0x99,0xa6,0x52,0x4a,0x18,0x8d,0x5c,0xd7,0x8a,0x98,0xe6,0x77,0xdd,0x26,0x3e,0xf6,0xb4,0xdf,0x44,0x6b,0x31,0x0b,0x3d,0xd8,0x9c,0xaf,0xdd,0xb9,0xb1,0x7a,0x65,0xbb,0xa8,0xe1,0x39,0x68,0xbd,0xc2,0x5b,0x1d,0x84,0xb6,0xe2,0x43,0x6e,0xdf,0x31,0xaa,0x75,0x6e,0x3a,0x48,0x72,0x6d,0x6f,0x91,0xc8,0x08,0xee,0x0e,},"\xd5\xaa\x11\x82\x5b\x99\x44\x8c\x80\x63\x06\x23\xd8\xc7\x46\x01\x7c\xfe\x3d\xe6\xfa\x8a\x0c\x6e\xd6\x62\x71\x27\xcf\xc1\xf8\x4d\x4e\x0a\x54\xe6\xa7\xd9\x08\xd3\x71\x9f\x14\x21\xd1\xd4\xc7\x8b\x3c\xdd\x94\x76\x9a\xb6\x03\x3b\xce\x97\x9d\xd9\x0e\x10\x68\x02\xeb\xa9\xa0\x32\x95\xd4\x8f\x9b\x9a\x95\xd5\x7e\xe7\x74\x54\x02\xa4\x80\x23\xbf\x3b\xdd\xd5\xc6\xb9\x1c\x77\x3e\x49\x19\x13\xa3\x8a\xc3\x46\x26\x05\xcf\x28\x2d\xea\xc7\x57\x42\xfb\xd2\x75\x29\x27\x6e\x81\xdc\xce\x8d\xff\x96\x05\x03\x5e\x8c\xf0\x5d\xf6\xa4\x3d\xb1\x51\xf0\x41\x57\x65\xbc\xbd\x1f\x1b\xb6\x68\xad\x62\x73\xb8\x91\xc0\xdc\x4f\x3d\xba\x59\x0e\xa8\x2f\x83\x63\x76\x9b\x9c\x77\x51\x19\x47\x11\x73\x75\xdc\x49\x04\xd4\x8b\x88\xb6\x8a\x25\x5b\x28\x01\x1b\x11\x04\x81\x94\x09\x3e\x98\x20\x7a\xb1\xcf\x75\x6a\xb8\x33\x1f\x8d\x6f\x9d\x5b\xe2\xe1\x19\x05\x73\xe9\x5e\x71\x0f\x2a\x35\x01\xb5\x3a\xa0\x82\x5d\x6c\x12\xdc\xfb\x94\xac\x80\xdc\x10\x82\xcb\x4a\xd2\x62\xe6\xd4\x93\xad\xce\xb6\xbc\x19\x14\x5f\xbf\x73\x8d\xf7\x6f\x21\x34\xfa\x04\xcb\xbe\x44\xff\xc5\x5f\xfe\x5f\x9d\x3e\x9b\xeb\xd1\x59\xa0\x01\xaa\x9b\xf7\x88\x92\xa1\x65\x38\xa5\x20\x82\x3c\xde\x5d\x61\xe2\x9a\x56\xa7\x7a\xb9\x6e\x49\xe3\x00\xd9\x86\x59\x62\xc7\xe7\xfb\x8b\xcf\x5d\xe0\xb9\x38\x29\x7c\x3f\x4d\x6f\x60\x21\xe2\x4d\xfd\xad\x98\x61\x65\x2f\x34\x0f\x42\x1e\x7a\xf2\xc7\x1e\xd9\xa7\x15\x87\xfc\x75\x3b\x11\x55\x49\xb2\xf7\xf7\xcb\x29\x69\x0e\xa2\xb1\x58\xa9\x4c\xd2\xbc\x42\xe7\x06\x3d\x61\x9b\x93\x9d\x52\x3e\x3c\x23\x7e\xb1\xf4\x08\x10\xde\x0b\x44\xaa\x69\x37\x86\x3d\x62\x9e\xdd\x55\x75\xe6\xc0\x47\x52\x61\xb6\x27\x47\x30\x92\x77\x5c\x84\x36\x00\x11\xd5\x7c\x57\x20\x9c\x2e\x87\x5a\x3f\x89\x63\xe8\xb2\x41\xa7\xaa\x75\xef\x30\xc4\xa7\x18\xac\x4d\xd4\x66\xdc\x7a\x3e\x40\xe5\x87\x4f\x15\x7a\x84\x9e\xd3\xa3\xa9\xd4\xae\xb7\xd9\x4d\xf0\x9b\xb5\x5a\x0b\x2b\xc9\xf8\xb6\x95\xc3\x71\x79\x30\x23\x67\x60\x63\x67\xc5\xf3\x24\x82\x8c\xe7\x5a\x94\x4f\x50\x70\x3a\x47\x90\x6a\x80\x88\xf3\xa1\x1c\xfe\x4a\x85\x4e\x01\xf1\x74\x12\x52\xc4\x86\x33\x7d\x06\xb1\xcc\x6c\x6b\x9b\x12\x95\x43\x1e\xe0\x73\x59\x35\x7b\x3a\x78\xef\x50\x75\xb6\x5d\x7f\xed\x5e\xb7\x42\xe5\x10\x15\x98\x44\x4b\x46\x62\x3f\x89\xa3\x03\xac\xc1\x0c\x73\x24\x49\x51\x3b\x70\xdc\x45\x6a\x79\xd3\x7c\x48\xe5\xe7\x26\xc2\xf5\x58\xda\x0a\x1c\x46\xef\xbd\x2d\x92\x03\x26\xa6\x78\xb8\xa2\x2f\x09\x44\xbe\x4a\xf5\x5b\x6c\x71\xf4\x53\xfb\xae\x40\x0e\x6a\xcc\x04\xe0\xe9\x5c\xa2\x00\x16\x7e\x96\xee\x98\xea\x83\x93\x16\xda\x93\xa1\x2c\x2d\x76\xf1\x1a\xee\xbe\xb7\x8e\x65\xea\x48\xf7\xfe\xeb\xbb\x13\x7b\x2a\xc6\x7e\xae\xf0\x2a\x2d\x9e\x64\x71\xdd\x63\x4a\x03\x7d\x4f\x5d\x35\xa2\xf7\x8a\xf4\x1a\x8e\xa5\xaf\x5b\xc8\x15\x0a\x99\xed\x68\xa6\xa0\xcc\xff\x2b\x1d\x79\x65\xd8\xbc\x3e\xf9\x28\x5b\xa6\x42\x1d\x87\xc3\x3a\xad\x81\x03\xa5\x87\xbe\x01\x92\x68\x45\xbf\xbd\xdb\xaf\xc6\x9c\x4b\x92\x52\x88\x67\x20\xd4\x18\x50\x9f\x40\xf3\xdc\xf5\x57\x65\xdc\xcc\x3d\xee\xd8\x27\x72\x15\xe6\x9f\x05\x6b\xa3\x1b\x8a\x30\xb5\x00\x94\xea\x8f\x14\x47\x20\x76\x0c\x8f\x8c\x05\x5c\xf1\xa8\x69\x64\xff\xcb\xb8\xee\x1b\xb2\x18\x12\x76\xea\x99\xa7\xb8\xe7\x10\x67\xfa\x31\x0b\xa4\x47\x1e\x84\x27\x90\x37\xbc\x49\x2a\x55\xde\x20\x55\x48\xe7\x7b\x01\x45\x04\xee\x66\x64\xc4\x98\x8c\xbb\x9e\xd9\x1f\xf3\x2e\x22\x59\xed\x4c\xfd\x61\xa1\x97\xd0\xdb\xc3\x2c\x68\xf6\x54\x9c\x0d\x29\xfc\x45\xf3\x6a\xcb\x26\xb1\x64\xde\x97\xcc\xdc\x37\x90\x0d\x93\xcd\xbc\xf9\x68\x7e\xf5\x3f\x1f\x4d\xa1\xb1\xae\x42\x25\xb8\x84\x20\x9e\x81\xba\x43\x11\x52\x04\x77\xed\x42\x11\xb0\x92\x40\xbd\x7b\x82\x5e\x54\x73\x9f\xe2\x5d\x86\x24\xaf\x04\xb8\x6f\x6d\x11\x06\xd1\x81\x70\xe5\x06\x4d\x1a\x73\xc1\xfb\x1a\x27\xb2\x89\xa9\x48\xd7\x71\xa2\xf6\xb8\xb0\x9a\x63\x5d\xb9\x6c\x62\x51\xc3\x5a\x18\x76\xd3\x69\x62\x66\x99\x41\x6c\x0e\x40\x29\x8a\x68\x1f\xda\xf5\x25\x5f\x58\xc2\x55\x77\x59\xd8\xf5\xdf\x14\x8d\xec\x9d\xbe\x1c\xe6\xdf\x04\x1c\x36\xf8\x3e\x69\xcc\xfb\x4a\xac\xa5\xcb\x48\xfa\x6a\x85\xc8\xff\x66\x06\x15\x24\xd8\xb1\x1b\xd7\xff\xae\xd9\x9d\x0c\xd4\x5c\x42\x01\x0f\x21\xd3\x6c\xc3\x16\xca\x86\x09\x55\x63\x5b\xff\xaa\x7d\x9a\xac\x57\x2d\xcc\xf3\x15\x3d\x42\xee\x8a\x2b\x12\xba\xa5\x7c\x16\x0b\xd0\xad"}, -{{0xc5,0x4b,0xd3,0x43,0x1f,0x26,0x59,0x28,0x1d,0x31,0xe9,0x3b,0x30,0x78,0x76,0x68,0xbc,0xba,0x6e,0x5e,0xe4,0x7d,0xb4,0x6e,0x50,0xde,0xab,0xe3,0xf4,0x8c,0x9e,0xd8,},{0x1e,0xba,0x6e,0xb3,0xf7,0xf2,0x4c,0xdf,0x80,0xab,0xf8,0xa1,0x9d,0x30,0x8c,0x24,0xf1,0xe2,0x5b,0xa1,0x59,0x70,0xed,0xa7,0x11,0x67,0x07,0xb0,0xf1,0x2c,0xf9,0x32,},{0xdf,0x45,0x41,0xdf,0xf1,0xa9,0x79,0x7f,0xeb,0x61,0x7f,0x98,0xe4,0xb5,0x7a,0xa7,0x71,0x41,0x31,0xee,0x8f,0xf5,0x45,0xed,0x50,0x82,0xe3,0x56,0x8e,0xfd,0x1c,0x39,0x9c,0xdc,0x56,0xf5,0x58,0x29,0x91,0xeb,0x87,0x85,0xfb,0x33,0x86,0x4e,0xef,0x7f,0x55,0x3f,0x3e,0x24,0x82,0x62,0xed,0x54,0x8a,0x1a,0x68,0x88,0xf9,0x2e,0x92,0x0e,},"\x6f\x8c\xdd\x75\xe1\xb8\x56\xbb\xbe\x9c\xdc\x25\x53\x7f\xdf\x7e\x82\x36\xcb\x02\x9a\xcd\x39\x84\x49\x21\x10\xd0\xc3\x04\x41\xd4\x21\x84\xb5\xfb\x18\x3d\xa9\xf3\x14\x03\x78\xdf\xa7\xd7\x4c\xcc\x9e\xf5\x00\x19\x3c\xc9\x57\x9f\xff\xa6\x0b\xd2\xa8\xab\x9e\x09\x58\x15\x00\xcf\x06\xcd\x35\xab\xc1\x71\xd9\xd1\x2c\x65\x80\xd9\x68\x2f\x9f\x49\xfe\x36\xd0\xa3\x17\x72\x38\xfa\x50\xe7\xeb\x4c\x27\xe4\x60\xf5\xe4\x58\x0a\x56\x56\x8a\x19\xe0\x3d\x95\xb0\xff\x4f\x4a\x23\x18\x24\xcd\x2f\x34\x42\xe0\xba\x40\x0b\xc1\x1b\x7a\x98\x9d\x50\x1f\x5d\xf3\x5e\x43\x01\x50\x8f\x72\xa8\x52\x01\x4b\xfb\xf4\x00\x1e\x28\x09\x54\x73\xd9\x65\x9e\xed\x60\x67\xba\xf6\x8f\x92\xbe\xf3\x12\xc0\x9b\x19\xaa\xf7\xc4\xfb\xa3\xd9\x02\xb9\xf6\xcf\x95\x2e\xb9\xb9\xa5\x3c\xa8\xbc\xbd\x04\x2d\x84\x2e\x98\x53\xb6\x72\xa1\xd0\x09\xd8\x23\x83\x8b\xeb\xe5\x63\x7c\x4c\x07\xed\x1b\x19\x48\x55\x4b\x23\xb3\x2d\xe1\xd6\xc1\x16\xf9\x33\xb3\x54\xf2\x8b\xbb\x77\x9f\xa6\x54\x8c\x48\x29\x2b\x61\x2c\x7f\x55\x1a\x75\xfb\xc4\x6c\x02\x73\x6b\xf9\x9e\x9c\x8e\xad\x56\xf0\x5a\xb0\x42\x7a\x6e\xc6\x16\xe3\xdc\xc7\x75\x7e\xfd\xb7\x62\x8d\x4e\x96\x32\x5f\xe0\xae\x25\x4c\xef\x5c\xb7\xa7\x04\xb3\x5a\x92\x0c\xb3\xfa\x2a\x03\xe9\x61\xda\xf3\x71\x82\x1b\xe0\xb3\x0f\x19\xae\x49\x52\x44\x1e\x08\xa7\xd2\x2f\x54\x31\x39\x0a\x5b\xe8\x09\x7f\xd5\x79\x7a\x1a\x62\x97\x66\x4d\xa4\x2c\x20\x08\xd0\x32\x10\x60\xeb\xe3\x18\x1e\xb7\x95\xa7\x28\x92\x58\x08\xda\x78\x67\x29\x3b\x72\x08\xf3\x77\xd3\xa7\x71\x18\x5e\x6d\x2c\x1c\x8c\xe1\x83\x76\xfe\x3c\x0c\x14\x58\xc7\xf5\xbe\x34\xf4\x28\xa0\xd5\x75\x93\x10\x74\xc9\x7c\xbf\xce\x8a\xd8\x13\x13\xec\xca\x73\xa9\xf3\xdb\x43\x4f\xba\xd4\xbb\xbf\xf5\x02\xbf\x72\x97\xe1\x7a\x97\xa8\x86\x42\x11\xe6\x78\x9b\xa1\x92\x03\x6e\xa5\x9a\x34\xd8\x4f\xf2\xa1\x11\x07\x4c\x3f\x23\x73\xb1\x01\x11\xb5\xda\xa7\x89\x56\x0c\xb3\x54\x90\x95\x4c\x88\xea\x00\xc4\x10\xdf\x85\x0a\xd0\x0c\xae\x2f\x28\xe7\x19\xfb\x06\x71\x69\x88\xa9\xbb\x0b\xfc\x6c\x98\x9d\x58\x7e\x56\x85\xae\x88\x3c\x2c\x2e\x74\xdd\xbf\x91\x5c\x98\x56\xaa\xe8\xf3\x28\x8f\xc6\x25\xbf\xb2\xfe\x26\x8d\x74\xf5\x9f\x8b\x7d\x83\x63\x74\x97\x69\x16\x90\x07\xd5\xe6\x7b\x7d\x0b\x8c\x8f\x5a\x9d\x9f\x9c\x7b\x74\x5c\x0a\x42\x94\x76\x2c\xbe\xca\x42\xd5\x38\x49\x61\xe9\x21\xa7\xef\xb6\x5d\xa8\xd1\xe0\x3b\x67\x45\xcd\xf3\x08\x09\x7f\xb1\x3d\x64\xfd\x2f\x8c\x10\xfa\x95\x09\xeb\x2d\x91\x38\x7f\x00\x64\x5c\xa7\xd0\x48\x3b\x2c\xd1\x4c\x20\x6b\x8d\x7a\xe0\xa3\xfb\x7c\x09\xbc\x68\x43\xd1\x02\xad\xcd\xa1\x9f\x8b\xbd\x85\x1e\xb6\x83\xc4\x43\x5c\xeb\x4b\x3d\x23\xd3\x8f\x56\xd4\xd1\x11\x4e\xef\x0f\xc6\xf2\x4d\xf5\x27\x70\xd8\xf1\xf3\xf8\x2f\x47\x20\xe8\x92\xb3\x15\x24\x4e\xf5\x6c\x36\xb2\x3f\xcd\x40\x79\x78\x52\x41\x40\x38\x2e\x11\x74\x0f\xd4\x6f\xe4\x29\x99\x23\xf5\x2b\x88\xb4\xa9\xcf\xf4\xb2\xb4\xb2\x3a\x2e\x76\x0a\xd8\x1c\x78\xba\x87\x69\x31\xd9\xaa\xa4\xbe\xed\x40\xfb\x10\xa7\x99\xeb\x30\xd3\x7f\x75\x47\x78\xba\xc8\x5b\xf0\x63\x1d\x85\x2b\xe7\xd7\x4a\x64\x31\xf3\x84\xa4\x02\x5c\x10\x91\x42\x1d\x67\xa4\xe9\xc9\x4c\x1b\xe3\x69\x0c\x6b\xf8\x1d\x06\xbd\xaf\x32\xfe\xab\xba\xf1\xdc\x26\x3f\x27\x3a\x0b\x9e\xd6\x54\x60\xba\xef\xce\xfc\xf6\xac\xcc\xda\x0e\xdd\x23\xdf\x9e\x05\x12\x8e\x29\xd6\x61\xc4\xb4\x4b\xd9\x2d\x64\x0f\xaa\x85\x3a\xfd\x83\x70\xe5\x63\xb4\x0a\xe0\x14\x9a\x14\x28\xe0\x6e\x3d\xd8\xe6\x6b\x79\xda\x21\xcc\x75\x3d\xdc\x47\x6e\x3d\x76\xe2\xf3\x6f\x2b\x6c\x6b\xc1\xb6\x50\x87\xd5\xf8\x6c\x8a\xc3\x54\x71\x1a\x8c\x08\xf3\x48\x6e\x47\x9d\x6a\xe9\x43\xf8\x84\x63\x32\xd4\xe5\xb4\xbb\x2e\x82\x57\xe3\x08\x3d\xf4\xf8\x1d\xd4\xf0\xc1\xee\x1d\x97\x18\x21\x66\x16\x1a\x18\x59\x7e\xe0\xb9\x59\xde\x1c\x45\x59\x1a\xbf\x7c\x51\x03\x3d\x7c\x66\x35\x2d\xee\xb6\x82\xe7\x77\xae\xae\x2f\xa8\xd3\xa7\x7f\x47\x0d\xb7\x8d\xdc\x1b\x1f\xc8\x28\x40\xc4\x06\x57\x76\xd9\xbf\xca\x9d\x39\x2d\x92\x88\xee\x91\x32\xaa\x3e\x4f\x2d\x19\xd0\xd9\x3e\x01\xb6\x66\xf3\x64\x7a\xba\xf2\x25\xc2\x92\x41\x9c\x8a\x82\xeb\xa3\xe1\x1a\xb1\x03\x84\x6f\xcd\x49\x35\xf4\x12\x41\x47\x7c\x0f\x15\x2b\x79\x65\xad\x54\xbb\x72\xbc\x3d\xe2\xe0\xb7\x9d\x62\x25\xe8\xfa\x7a\x62\x86\xb5\xfc\xcb\xb3\x58\x22\xe8\x0c\x8b\xfe\xa7\x4c\xb4\x8a\x22\xd2\x41\x38\x53\x95\xc2"}, -{{0xea,0x60,0xda,0x01,0x79,0xbc,0xaf,0x6b,0x21,0x81,0x42,0xb1,0x11,0x90,0x46,0xff,0xe6,0xd8,0x5a,0x74,0x1b,0x0d,0x16,0x62,0x30,0xbc,0x6d,0xe3,0x30,0x4f,0x67,0x73,},{0x50,0x6b,0x2e,0xbb,0x49,0xbd,0x9b,0x9f,0xf6,0x6e,0x6b,0x7b,0x1f,0xab,0x96,0x68,0xcb,0x18,0x1b,0x4f,0xb5,0xe4,0x34,0x3d,0xdd,0xd3,0xf8,0xa9,0xd7,0x02,0x03,0x1c,},{0x27,0xfb,0x6b,0x5f,0x06,0x52,0x8a,0x64,0x19,0x8a,0x3e,0x7d,0x67,0xc7,0x38,0x84,0x0a,0x8c,0xff,0x4b,0x48,0x2b,0x4d,0x52,0x4b,0x12,0x2d,0x17,0xd2,0xae,0xbc,0xc0,0x38,0x9b,0xe2,0xc6,0xe2,0x8e,0x2c,0xdf,0xc4,0x84,0xc1,0x8d,0xe4,0x25,0xdb,0x56,0xcd,0xfa,0x56,0x1c,0x50,0x7c,0xd9,0x70,0x60,0x2d,0x3a,0x38,0x5d,0x3a,0xea,0x0f,},"\x61\x2d\x6e\xf6\xe4\x34\x9f\xfa\xe5\x16\xe9\x83\xe8\xfa\x7b\x52\xd9\xfd\x13\x42\x82\x24\x0d\x95\x14\x38\x24\xbd\x4a\xae\x03\x23\x4b\x76\xa8\xcd\x6d\x40\x68\xcf\x00\x9e\x48\x1c\x26\x85\x36\x1c\x75\x50\x42\xc4\xe6\xab\x87\x03\xec\xbf\x8f\x02\x0c\xf5\x73\x9a\x4c\x2a\x03\xc3\x73\x1e\x9c\xf7\x5a\xee\x25\x96\x61\x53\xb9\x71\x15\x15\xc6\xc3\x9a\xfa\x95\xf2\x21\xac\x33\x95\xb0\x89\xc9\x7a\xc9\xb5\x14\xe1\x7d\x55\xf7\x96\xa3\xec\xc1\x35\xfa\xaa\xee\x90\x7a\xab\x10\x29\x64\x7b\x48\xac\x81\x74\x9b\xab\x26\x62\x7c\xf7\x09\x5d\x74\xc2\xfc\xee\x35\x67\x1c\x8b\xb4\x60\x53\xf5\x15\x1b\x0c\x2e\x5d\xab\xe0\xf2\xd6\xaa\x20\x41\x33\x05\x02\x0b\x2a\xfd\x9e\xe3\x38\x7b\x2c\x9e\xd0\xbc\x3f\xe2\x90\x2a\xf4\x10\x0c\xec\x23\x32\x7b\x0f\x1e\x4c\xa3\x9e\xf6\xea\xf6\xfd\xf5\xd5\xac\xf9\x3f\xc8\x68\x53\x6d\x8c\xba\x40\x17\x69\x32\x9f\xbe\x93\xef\xfc\x7e\xe6\xbf\x93\xa6\xe5\x88\xbd\x55\x1e\xaa\x51\x28\x53\x95\x2c\x81\xb2\x45\xe5\xd2\x29\xd2\x94\xe4\x13\x70\xb8\x67\x80\x86\x67\x88\x7a\x6f\x9e\xba\x2a\x8d\x56\xa7\xa7\x04\xe6\x6b\x1c\x02\xf9\x6e\x73\x89\x5f\x48\x3e\x44\xa5\xc5\x66\xcb\x1a\xf2\x65\x73\xbf\xe2\xaf\xce\x06\xb1\xfb\x58\x77\xe5\x1e\xf3\x12\x6a\x3f\x21\x0f\xbf\x21\x3e\xd6\x5d\x5c\xa4\x6c\x46\xce\x4a\xa9\x45\xbd\x8c\xa6\x11\xe3\x83\x62\x50\xf5\x64\xf7\xea\x35\x42\x39\x82\xf9\x70\x5f\xcd\x6b\xef\x46\xae\x16\xcb\x0f\x6b\xc9\x12\xc3\xf2\x86\x42\xb8\xd8\x77\x75\xb8\x18\xe4\xe4\xe8\x06\x11\x67\x89\x9b\xd2\x7a\x7e\x2f\xb8\x18\x7e\xe9\x91\x7d\x2d\x58\x6b\xf9\xd4\x99\xe8\xfa\xbc\xa8\x3d\xdf\x58\xc7\x43\x7e\xaa\xce\xc4\xf4\x44\xfb\x2b\xf7\x45\xdc\xcd\x8c\xae\x38\x94\x45\x71\xde\xde\x20\x37\xdc\x41\xf0\x81\x8a\x3d\x91\xe3\x02\x0a\x72\x74\xc6\x67\x42\x47\x87\x60\x83\xd0\xe3\x97\x46\xc9\x68\x40\x61\xbf\x74\xad\x58\x84\x36\xce\x1b\x76\x3d\xbf\x4b\xfc\xf8\xde\x6e\x35\xc5\xa7\x62\x66\x75\xc1\x27\x29\x2b\x21\xdf\x3c\x16\xf8\x10\x63\x32\x2a\x75\xf3\x43\x88\x86\xf1\xf0\xce\xbf\xc1\xa9\x6f\x41\x38\x4c\xbd\xd8\x61\xb0\x4f\x51\x9f\xf6\xa9\x34\x4d\x94\xf3\xd3\xa0\xab\xa8\x40\x9d\xfc\xf1\x8d\x01\xf2\xb5\xb4\x55\x17\x16\x39\xee\xa7\x7d\xee\x70\x6e\xa8\x3d\xcd\x2b\x8b\x1f\xc5\xec\x0d\x74\x07\x61\xa5\xf0\x5f\x7e\xc8\xd8\x7a\xd1\xf2\x92\xa5\x0c\x8b\xae\x0a\xd3\x2b\x03\x41\x9a\x95\x0d\x9f\xe3\xb3\xec\xc4\xd8\xd3\xaa\x95\xe0\x2b\x51\xb1\x83\x1d\x83\xea\xde\xaa\x44\x23\x86\x35\xf9\xc6\x5e\xfe\x2f\x67\x44\xa7\x0b\x9a\xe4\x1e\xf1\x5d\x97\x90\x8c\x05\x33\x93\x44\x12\xf7\x95\x83\xd0\xe9\xb3\xd7\x06\xa1\x28\xe8\x8f\xb5\x1e\xed\xb6\x5e\x46\xd8\xa2\xb3\x8b\xbd\xd6\x45\x55\x54\x96\x7a\x8d\xc0\xc6\x8b\xdd\xfe\xae\x0f\x8f\x72\xf0\xb8\x86\xc3\xc7\x41\xfa\xc4\xf9\x1e\x5c\x49\x1d\xba\xe9\xda\x45\x94\x83\x6c\xf1\xd9\xfb\x6e\xe1\x30\x02\x50\x89\xae\xd3\x50\xef\x24\x7b\xc9\x88\x7a\x20\x50\x15\x9d\xde\xd1\x42\x8f\xfd\x9b\x07\xb9\xec\x2e\x3d\x4b\xbd\xc2\xdd\xb5\x4e\x87\x3b\x63\xf2\x47\x52\x33\xe1\x91\x33\xa1\x4b\x66\x58\x50\x94\x57\x00\x81\x86\xd6\x22\x59\x95\xa9\x67\x26\xb5\x29\xf4\x42\x81\xaa\x24\xfe\xfd\x1c\xff\x8f\x81\x5d\x93\xa5\x98\x69\x31\x66\x22\x90\xb3\xee\x16\x83\x3c\x60\xf0\xaf\xce\xf2\xcb\xc0\x00\x62\x3f\x39\x31\x90\x9c\xa9\x76\xa0\x94\xe2\xb0\xfd\xb7\xdc\xf7\xc4\x85\xe1\x49\x88\xa3\x6f\x19\xb6\x64\x25\x38\x5f\x56\x32\xce\xf6\x5d\x1d\x34\x14\x62\x3a\xe3\xee\x81\x6e\x76\x3a\x5f\x60\x64\x66\x62\x2b\xe6\x60\x21\x14\x50\x29\x51\xcf\x0c\x09\x7c\x16\x48\xa7\x2e\x2c\x43\xd9\xaf\xa9\x68\x9f\x2c\x3c\xfe\x02\x6c\xdc\xe3\xbd\x1b\xf9\xeb\xf7\x77\x56\x2e\xcd\x8f\xf1\xb0\xd7\x75\x30\x6d\x90\x04\x43\xf3\x0a\x84\x33\x10\xb8\xde\x6a\x38\xff\x10\x8b\x72\x39\x13\xd7\x89\x9b\x9f\xbe\x7c\x3d\x76\x6e\xf8\xbd\xfb\x6d\x8b\x0b\x52\x95\x6c\xb1\xce\xc9\x93\x6d\x70\xb4\x87\xc0\x14\x40\xa8\x42\xb2\xfa\xbe\x38\xe7\xb8\x85\x1a\x38\x7d\x35\x8b\xe7\xef\x12\xa7\xe4\xf2\xb5\x27\xe8\x30\x90\xd6\x7e\xb0\x13\xc9\xc2\xcf\xd3\xde\x5a\x1a\x3f\x99\x74\x8a\x41\xf4\x81\x9d\x90\x36\xe5\x00\xc5\x04\xc9\x88\xbf\xd2\x4f\x61\x7d\x6e\xbd\xca\xb2\xdd\xea\xa6\x15\x79\x41\x4f\x36\x0b\x46\x9a\x33\xa6\xde\xd9\x6b\xa1\xd8\xc1\x40\xc4\xff\xc9\x49\x90\xd8\xad\xf7\x8c\xd3\x87\x80\xbd\x68\x66\x3d\x1a\x0e\xe3\x3f\x53\x7c\xdf\x89\x2d\x56\x2e\x82\xdc\xd1\xd9\x12\xca\xd3\x8d\x65\x56\x7d\x29\x14\x06"}, -{{0xb6,0x2c,0x24,0x18,0x78,0x27,0x35,0x13,0xe0,0xbf,0x6f,0x33,0xd2,0x10,0x43,0x65,0xb2,0xce,0x9c,0x5a,0x1b,0x78,0x60,0x58,0xe9,0xc5,0xb4,0xd1,0xd1,0x92,0xf8,0x7f,},{0xbb,0xf6,0xfc,0x51,0x98,0xf3,0xfb,0xa5,0xab,0x00,0x7f,0x8a,0x63,0x2d,0x28,0xd1,0xaf,0x86,0x5d,0x29,0x0f,0xa0,0xa9,0x0f,0xaa,0x9a,0x9b,0x5b,0x9c,0x13,0xf3,0xfb,},{0xc5,0x90,0x39,0x58,0x7b,0x38,0xdc,0x14,0x1e,0x05,0x5a,0x93,0x85,0x01,0x04,0xd6,0x29,0xe3,0x80,0x70,0x5b,0x8f,0xc9,0x18,0x84,0x7c,0x5e,0x2a,0x35,0x2d,0xa3,0xa0,0x2f,0xce,0x7f,0x71,0x99,0xf4,0xae,0x2b,0x1e,0x2a,0x59,0x48,0x34,0x18,0x93,0x2e,0x18,0x5f,0x7e,0x45,0xb5,0x05,0x0c,0x64,0x2c,0xec,0xc7,0xe7,0x81,0x99,0x85,0x07,},"\x26\xa3\xc2\x6a\x5a\x18\x9c\xad\x40\x7c\xba\xa3\xa6\x86\x7a\xc0\xa2\x60\x88\xc7\x5f\x9d\x0f\xa1\x9b\xd5\x02\x74\xce\xc5\x75\x5a\x49\x71\x09\xa4\x73\x28\x4d\x6f\xc8\x1a\xd4\xb9\xec\x29\xfa\x7e\xc9\x76\x4f\xd3\x09\x9f\x06\x0e\x36\x83\x65\x52\xff\x24\x13\xe3\xd5\x09\x5f\xe0\xb1\xa8\xbf\xcf\x67\xee\x06\xaa\x90\x32\xe7\xbb\x32\x49\x69\x80\x47\x71\x4d\x28\x14\x15\x27\x3c\x98\x34\xad\x9e\xb6\x65\xa7\xd9\x72\x20\xe7\x2d\x9c\xa7\x3f\x31\xaf\xa7\x73\x86\x75\xba\x31\x62\xef\xef\xe7\x47\x9a\x5b\xc4\xbc\xe2\xe8\xb7\xaf\x47\x41\xd7\x03\xdc\x9b\xbd\x60\xb4\xcf\x4b\x90\x87\xf6\xcf\x86\xcf\x53\xae\xd0\x2b\xf4\xca\x6a\x18\xf6\x07\xcb\x52\xa3\x03\xd7\x8e\x85\xad\x88\xfd\xfc\x86\xdc\xb7\x18\x77\x27\xb0\x3b\xe2\x27\x74\x5b\xea\x74\x4f\xd0\x06\x52\x5b\xc5\x9a\x4d\xdd\xab\x91\x5c\xef\x40\xa8\xf3\x08\x02\x91\x3b\x79\x13\xea\xf9\x74\x33\x65\x52\xe2\xf1\x45\x6a\xd8\x03\xdc\x58\xc9\xb4\xb1\x8e\xfa\xf7\xf7\xe3\x57\xe2\xcd\x77\xd1\x38\xd9\x00\x80\xe2\x96\xd1\x36\x4a\x2f\x32\x4d\x3e\x0d\x6e\xdc\x20\xb8\xbd\xaa\x9d\x2e\x87\x1f\x5e\x7b\x05\x1f\xb6\xfc\xdb\x55\x95\xf2\x1d\x3f\x8d\xe2\x9f\xb7\x86\x78\xfa\x47\x9e\xaa\x32\x57\x9c\x78\x4d\x51\x3a\xc5\xf8\x36\xd9\x54\xd0\xd3\xfc\x0e\x5f\xc8\xa6\xee\xab\x90\x20\x2b\x4c\x4a\x2b\xec\x24\xcf\x63\xea\x67\xc4\x70\x09\x62\x18\xcd\x43\x1e\x88\x31\x05\xfc\x9c\x27\xf9\xea\x77\xc1\x8e\xda\x69\xbc\x00\xa2\x24\x2b\xd4\x20\xf0\x95\xc9\xb9\xa9\x2d\x95\x6c\xcc\x5a\x85\x72\xb0\x57\xa7\xfe\x17\x3e\xeb\x2a\x31\x66\xcb\x20\x89\xd1\x13\xa8\x16\x46\x2b\x25\x80\x5b\x8a\xba\xff\x5b\x0b\x22\x87\xc5\x08\xec\x2b\x8c\x34\xb2\x19\x5c\x33\x28\x70\xd3\xcc\x39\x60\x17\xa1\x6b\x9e\x0d\xa6\x18\x2d\x07\x1d\x3b\xf3\x63\xd3\xf1\xe7\xb7\xda\x11\xd7\x11\x25\x0a\x58\xaf\xd7\x4e\xd3\xe3\x15\x8d\x47\x18\xba\xd4\xd2\x74\xbb\x34\x44\xcf\xc3\x18\x07\x4b\x53\xbe\xba\x44\xa2\xa3\x4f\xf8\xeb\x72\x6e\x4a\x1d\xaa\x91\x10\x51\x62\x16\x51\x89\x8b\x88\x71\x69\xf6\x2b\x9c\x0f\x40\x20\x48\x3e\xf5\x44\xf8\xf5\x72\xfa\x6a\x66\x40\xa4\xcf\xfc\xe9\x76\xcb\x70\x24\xf8\x47\xbd\xc9\x5d\x1d\x7c\xe6\x53\x50\x5d\xeb\xfc\x69\x88\xed\x28\x9d\xd4\x7a\x9e\xb2\x61\x25\x9e\x3e\x65\xe4\x5f\xc9\xd7\x14\x94\x69\x35\xcd\x8e\xa1\x3b\xc6\xdb\x5e\xaa\xb9\xe8\xb1\x0d\xae\x0f\xdd\x69\x79\xc2\x03\x5c\xfb\x80\x98\x25\x2f\x22\x05\x44\x3b\x80\x88\x16\xbf\x77\x87\xb7\xf1\xe7\x8b\xc9\x8a\x72\x85\xe7\x33\xd4\x5f\xc4\x61\x0c\x20\x97\x7c\xa3\x22\x98\x89\xbb\x8c\xd2\xb6\x94\xce\x9e\x3f\xe7\x83\x03\xaf\x83\xe1\x06\x42\x25\x42\xfb\x79\x61\xd3\x2e\xb1\xd2\xc5\xfb\xe6\x07\x51\x67\x4b\x07\x47\x73\xee\x06\x16\xe0\x29\x73\xf6\xa7\x4a\x3a\xe4\x66\x4a\x26\x50\x91\x5a\x3e\x10\x49\x3b\x9e\x66\xa3\x9f\xa5\xc8\x9c\x61\xd4\x47\x35\xf1\x07\xd3\x37\x57\xae\x67\x9b\x43\xa8\xd4\x3a\x01\x75\x7a\xe1\xf3\x27\x9e\x86\x24\x42\xe1\x50\x71\x55\x50\xee\x82\xe4\x9c\x0d\x49\x43\xfa\xf1\x3f\x22\x79\x1f\x0e\x66\xf2\x4a\xc5\x0a\xb3\xc0\x03\x85\x2b\x21\xe1\x5b\x2f\x00\x6e\xdc\x2c\xd6\xa8\x79\xc4\x76\xab\x5b\x35\x2e\xb1\x09\x9d\xad\x4c\x50\x37\x24\x00\xfa\xa5\x49\x8d\x78\xc6\xb8\x57\x03\x4c\x25\xca\xf7\xb9\x33\xfa\xf6\xbd\x7c\x59\xfa\x3d\xa5\x73\x97\xb6\x03\xde\x9c\xb9\xd8\x0e\x51\xf7\x99\x7b\xaa\x46\x2a\xcd\x53\x7e\x2c\x41\x94\xc7\x6c\x7e\x0b\xe6\x51\x2b\xce\x4d\x63\x66\x0b\x36\xc7\xcc\x46\x63\x1f\xb9\x67\x1a\xd8\xc5\xd2\x8e\x2f\x2e\xe2\xed\xce\x81\x95\x44\x21\xb8\xa3\xd9\xff\x6f\x66\x69\x9f\x4b\xce\x88\xbc\xb8\xef\x19\x2c\x26\x2a\x74\xab\x7e\x19\x1e\xee\x91\x01\xa2\x8d\x4b\x66\x28\x2b\x51\x22\x09\x3d\x14\x1c\x64\x96\xc7\xab\xa4\xd3\x52\xe4\x72\xee\x74\x40\xe0\x5a\xf6\x0d\xa0\xcf\xc9\x3e\x30\x36\x42\xba\x8f\xb8\xe5\xc5\x68\x68\x7a\xbd\x63\xaf\xb3\xed\x6a\x32\xb6\xda\xe5\x6a\x7e\x5d\x73\xde\xba\xf4\x1d\x35\xca\x36\xad\xb9\x7a\x22\xc0\xad\xbe\x71\x8b\xec\x1f\xa5\x19\x98\xde\x9b\x4b\x96\xa7\x9c\x5b\x96\x55\xb0\x16\x5d\x5e\x1b\x9a\x8c\xc5\x52\xe8\xc9\x32\x9e\xde\x58\xdf\x74\xc6\x7b\x2b\xa1\xa8\x42\xfd\x3e\x81\x58\xc1\xfe\xa3\xa9\x9b\x56\xa2\xc2\xa9\x62\x07\x85\x3d\x26\x02\x2c\xec\x17\x0d\x7e\x79\x94\x4d\x2f\x56\xaa\xb1\xf1\x91\xbf\xd4\x8d\x72\x54\x90\xca\x82\xb8\xd9\x06\xf0\x68\x0e\x69\xee\xb9\x57\x57\x74\xfb\x9d\x60\x45\x13\xfb\xc2\x6f\x5d\x30\x3b\x68\x85\xca\xc0\xbf\x8e\xfe\xe0\x53\x8f\x92"}, -{{0x0f,0x77,0xf7,0x7a,0x1c,0x7e,0x04,0xbd,0xa8,0xe5,0x34,0xf4,0xe3,0xef,0xf9,0xa2,0x38,0xcc,0x14,0x87,0x6b,0x7e,0x3e,0xca,0x8b,0xed,0xe1,0x92,0x3a,0x33,0x64,0x06,},{0x10,0x45,0xea,0x9f,0xe2,0x14,0x58,0x3a,0x0c,0xdb,0xc4,0x94,0x93,0x2b,0xc4,0x4a,0xfe,0xeb,0x08,0x0b,0xec,0x48,0x5c,0xc2,0x34,0xfd,0xdc,0xff,0x13,0x9c,0xce,0x00,},{0xb2,0x0b,0x9c,0x42,0x46,0xf0,0xd2,0x97,0x01,0x38,0xaf,0x7d,0xc9,0xaf,0x62,0x9b,0x68,0xfb,0xc3,0x7d,0xf8,0x7a,0xfd,0xca,0xdc,0xb5,0x45,0xc1,0x76,0x83,0x76,0xa0,0x9c,0x3b,0xab,0xc3,0xeb,0x1a,0xf3,0xb7,0x51,0x98,0x52,0xf7,0x5f,0xab,0x1c,0x9c,0x11,0x9c,0x66,0x2c,0x58,0x77,0xfb,0x2f,0x72,0x99,0xca,0xb5,0x7f,0xad,0x3d,0x0e,},"\x0e\xcb\x74\x6d\xbd\xb0\x16\x14\x21\xaf\xeb\x7a\xde\xa7\xa3\x7c\x2e\xa4\x40\x8a\x59\x2c\x9d\x78\x1e\xd6\xac\x6f\x4e\xe5\xcc\x65\xd5\x27\x0e\x4c\xf2\x76\x32\xf7\xc5\xc1\x33\xd4\x39\xb7\x8d\x1f\x71\xaa\x6d\xd8\x07\x13\xd9\x0b\x15\x1e\x19\x12\x1b\xfa\x87\x71\x0e\x84\xa4\x85\x0a\x3b\x5b\x02\x65\xba\x26\x03\xd0\x71\x6e\x9b\x7e\x11\x22\x10\x9c\x39\xc6\xf1\x02\x7f\xce\x18\x79\x8c\xbb\x4f\x6b\xc5\xe4\xd7\xac\xa4\x70\x46\x90\xf5\xc9\x81\x51\x08\x71\xc3\x13\x59\x57\x98\x33\x86\x81\x10\x7f\x2b\x57\x94\xd4\x6f\x6e\x0b\xde\x2c\xd0\x64\xb3\xb1\xfc\x00\xca\x47\x18\x8b\xbb\xc1\xf4\xa0\xce\x30\x5c\xc6\xd8\xa8\x96\x92\x0e\xb9\xeb\xae\x57\x9f\xd3\x38\x5f\x8f\x1f\x35\x97\x62\x88\xf4\xc5\x8f\xfc\x47\x60\xf3\x59\xb0\x03\xc8\x72\xe9\xa2\x40\x55\x35\x5e\xa9\x58\x5e\x95\x10\x69\xdc\xa2\x5f\xd0\xcc\x0b\x9d\xb5\x2a\xae\xaf\x19\xd4\x3f\x2e\xab\x4f\x83\x56\x03\xad\x12\xd2\xdc\x49\xb3\x10\x25\x6b\x94\xbe\xd5\x48\x96\xa1\x6b\x69\xb0\x9c\xb4\xc8\xff\x5c\x23\xcc\xe5\x59\x3d\x87\xad\xe2\xa8\x2a\xda\x50\x85\x9e\x15\x44\xc1\x86\x18\xa6\x5c\x00\x7e\xf4\x24\xc9\x85\x4a\x17\x5b\x6e\x6c\x0e\x64\xb2\xc8\xeb\x8a\xd4\xd2\x8b\x97\x7d\x68\xe7\x81\x69\x91\x51\x98\x97\x53\x94\xd3\xb9\xb2\x69\xca\xb0\xd3\x26\x1b\x2b\x56\xcd\x2c\xc4\xbd\xdb\xd4\xf1\x43\x9e\x0d\xbe\x2c\x9b\x3f\x3f\x75\x14\xed\xac\x5e\xbb\x46\x22\xb9\x2a\x69\xa8\x40\xa9\x02\x85\x50\xb2\x21\xdb\x59\xdd\xfb\x00\x13\x96\xf8\x63\x92\xa1\x7f\x08\xcc\xb1\x94\xcd\x9e\x1a\x00\x81\xd7\xdd\x9c\xca\x23\x57\xfe\xb8\xb7\x95\xe5\x17\x02\x9f\x79\xc8\x2a\x3b\xe6\xf9\xa0\x31\xdd\x1a\xf1\xe7\x9e\x49\x82\xbf\x8e\x76\xb3\x10\xf9\xd3\x55\xef\xcd\x5b\x1e\xfa\x9f\x35\x9c\x17\xcf\x3b\x51\x0d\x51\x3e\x8c\xd5\x78\x6a\x0d\x34\x45\xdc\x59\xa8\x43\x3a\x46\x48\x86\x87\xb0\xf5\x8b\x1b\xd6\x56\x7c\x2a\xf4\x87\x3b\x51\xfc\x84\x5e\x76\x7e\x24\x30\x05\x19\x2f\x8f\x06\x74\xf2\x81\x26\x5a\x55\xd7\x6c\xea\x32\x22\x60\xc9\x32\xce\xa6\x71\x7a\xdb\x98\xa2\xdd\xa8\xc6\x98\xe2\xe8\x92\x55\xfe\xb7\x7d\xa7\x64\x81\x67\xbc\x1e\x58\x87\x7f\xeb\x72\xd1\xd1\x4b\x0c\x30\x4f\x07\x37\x2d\x95\x56\x75\x23\x7c\x49\xf7\xa6\xdb\xc9\x15\xe6\x81\x4a\xba\xe6\xcc\xe4\xca\xf9\xf4\x80\x87\xe9\xdf\xb2\x82\xd8\xf3\x40\x37\x7c\x1e\x29\xc6\x73\x1c\xcc\x26\x67\xda\x66\x95\xb7\x12\xbe\x03\x12\xd8\x65\x11\x19\x34\xf1\x68\xd5\x54\x43\x65\xdd\xae\x27\xab\xc6\x4a\xef\xbc\xb3\x22\xdb\x7d\x97\xd9\x0d\x95\x7a\x63\x7b\xd8\x26\xc2\x27\xe9\xeb\x18\x0b\x45\xa4\x31\x62\x6a\x6f\xd8\x90\xc0\xe5\xf4\xed\x7e\x85\x64\x74\x75\x2f\x80\xb5\xae\xf6\xe7\x3e\xfd\xaa\x6c\x2c\x45\x1b\xd7\x4c\x1e\xf4\x66\xca\x3a\xaa\x25\x73\xbb\x52\xcb\x2b\x1c\xa9\x6a\x1b\x57\x44\x03\xce\xae\x1c\xf0\x5f\xfc\x53\x43\x0e\x1e\x4c\xd5\x59\x3b\xd1\xef\x84\xbc\xbf\xe2\x19\xf0\x81\x60\xd1\x66\xf2\x73\x1d\x99\xb8\xd7\xa3\x2b\x12\x99\x1f\x77\x77\x5a\x26\x7e\xc0\x82\x97\xec\x51\x2d\x7b\x72\x43\x56\x32\x52\x5c\x04\x00\x0f\xb0\x0a\x79\x3f\x8b\x5f\x8f\x37\x47\xb5\x53\x59\xdf\x21\xb7\xe2\xc4\x9f\x2b\x0b\x9a\xe0\x82\xaf\xc7\x0a\x14\x68\x71\x37\x0b\x8d\x50\x08\x6d\xe0\x0f\x94\x48\xbe\x89\x02\x17\x4b\xa2\xcc\x85\x1f\xa3\x79\xdd\x70\x31\xca\x45\x7a\x88\x69\xaf\x4b\x6c\x27\x29\xda\xc5\x19\x55\x6b\x8b\xb4\xab\x51\x9e\xf1\xbb\x02\x4e\xa8\xb7\xf0\x17\x71\xc9\xaa\xb7\x48\xe5\x73\x81\xa0\x19\x2a\x6e\x39\x8c\xbe\x6d\xd9\xf3\x67\xcc\x7b\x33\x54\xf8\x3b\x79\xbc\xda\x46\xb7\x93\xa4\xad\xa8\x55\x49\xc8\xd6\xbd\xd6\x16\x81\x24\x36\x2f\xf9\x08\xaa\x1a\x0c\xb7\x8a\xa3\x30\xc4\x2d\x5a\x5d\x48\x12\x35\xac\xac\x3a\x91\x9b\x96\x9c\x50\x98\x72\x66\xd4\x04\xd1\x5d\x0e\x70\x6f\xd9\x00\x76\x34\xf6\x9e\x13\xc5\x6e\xc4\x71\x33\x88\x4f\xca\xdd\xc1\x6b\xee\xee\xd1\x9e\x0c\xd9\x17\xaa\x49\x63\x67\x86\x7d\xfc\xea\x27\x4e\x1a\x47\xda\x77\x4f\x3c\x93\x63\x02\x1e\x7c\x8d\x6b\xf8\xf0\x00\x53\xfa\xcc\x11\xcb\x68\xa9\xd6\xe1\xfc\x2d\x6d\x19\x17\x5d\x63\x24\xff\x7c\xa6\xc2\x30\x58\xb8\xb6\x93\xd8\xfd\x4e\x0b\x51\xdc\xbb\x11\x35\x43\xf2\xfc\xc0\x45\x2e\xb9\xd9\x67\xac\x0f\xa9\xb2\x3e\x9e\x0b\x1d\xa8\xd8\x3a\x3c\x1f\xc9\xe9\xec\x97\x1f\x0f\x67\xfc\x74\x5b\xb1\x73\x76\xbc\x46\x24\x5f\x52\x8c\xb6\xe5\xfe\xe1\x1b\xcd\xda\x86\x7b\x7f\x79\x01\x9c\xf9\xdb\x59\x18\x58\x23\x0a\xec\xb4\xd1\xe9\x3d\x16\x7c\xd8\x6b\x42\xdd\x87\x9a\x13\xfa\x0e"}, -{{0xc5,0xa5,0x05,0x34,0x77,0xae,0x31,0x15,0x8e,0x74,0x69,0xdd,0x15,0x04,0x86,0x76,0x50,0xd4,0x6f,0x15,0x89,0x06,0x7f,0x5c,0xd8,0x81,0xca,0xf2,0x5c,0x26,0xcb,0x21,},{0x70,0xf8,0x5d,0xb9,0x80,0x7b,0x26,0xfc,0xf3,0xe6,0x69,0x0b,0x91,0x72,0x4f,0x7a,0xe3,0xd2,0x0e,0xc3,0x60,0x4a,0xb7,0xd6,0x30,0x8d,0x90,0x94,0x30,0x8b,0x2d,0x59,},{0xf5,0x19,0x1b,0x44,0xbd,0x6c,0xc3,0xea,0x28,0x17,0x71,0xdf,0x12,0x54,0x9b,0xa2,0xbe,0x22,0x8b,0x51,0xeb,0x79,0x1b,0x9e,0x5e,0xd2,0x81,0x5f,0x86,0x2a,0xa6,0x30,0xb5,0x69,0x67,0xcd,0xef,0x8b,0x6a,0xf0,0xb9,0xd2,0x1a,0xb8,0xc9,0x7a,0x6d,0xff,0x68,0x1c,0xce,0xd9,0xf5,0x01,0x97,0x13,0xd4,0x35,0x7c,0xb3,0xe5,0x4c,0x0d,0x08,},"\x85\x71\xff\x39\x03\x48\x6a\x43\xa6\x12\x6c\x32\x3e\x7b\x3a\x74\x14\x1d\x13\x85\xd4\xbd\x70\x3f\x19\xe2\xd1\xb6\x4b\x50\x28\x1d\x27\x16\x8a\xe3\xe7\x69\xc6\xdd\x9d\xf7\xd9\x78\x64\xfb\x37\x82\x2f\x00\x21\x85\x2e\x31\x68\xab\x7d\x84\x5a\x65\x45\xed\x0c\x37\x7d\x9f\x7c\x04\x8a\x2b\x96\xe8\xdc\xf4\x45\x77\x96\x84\xa0\x58\xc2\xb9\xc2\x1a\xc6\x8a\x0c\x34\x1d\x1d\x6c\x09\x81\x45\x64\x57\x45\x8e\xb7\xce\xbf\x66\x67\x87\x40\x77\x7e\xca\x26\xe0\x1e\x1c\x8f\x53\xb5\xd4\x75\x6c\xc5\xf0\xb9\x0f\x0c\x5d\xb0\x53\x93\xcd\x4b\x8e\x44\xf6\x81\x0c\xaa\x5a\x11\x6a\x33\x57\x77\x24\x39\x5d\x41\x3a\xf6\x19\x63\x2a\x6f\xed\x14\xe2\x15\xc2\xf1\x9d\x10\x5c\xe2\xbf\x14\x98\xe6\xd2\xab\x4f\x65\x0f\x61\xba\x5c\xf6\xd0\xc7\x3b\xbb\xde\x98\xe3\x04\x29\x91\x0a\x4e\x67\xdf\xbc\x71\x7c\xb0\x91\x18\x2d\x59\x70\x58\xb5\xd7\x65\xd0\x97\xe6\x87\x58\x31\xb5\x88\xaa\xeb\x3e\x73\x27\xe8\x56\xb4\x2f\xa9\x83\xfd\x25\x4e\xf1\xf9\x18\xb0\x43\xd1\xdd\x3d\x7b\x7e\x30\xb3\x15\x38\x6e\xec\x91\xe7\xf9\x4d\x59\x8f\x4b\xeb\x3b\x27\xb4\x2f\x4e\xe1\xfb\xf7\xaf\xb4\x86\xbd\xcc\x60\x81\xcc\xb8\x67\xf0\x41\x11\x04\x4f\x4b\xbb\xe3\xc8\x12\x2e\xde\xad\xef\xa9\xd6\x93\x90\x6e\x0d\x6e\x13\x3b\xf6\xf2\xda\x61\x58\xfe\xed\xbd\xa0\x24\x41\x0f\x12\x08\x6e\x7a\xcc\xf1\xc6\x8e\x15\x57\xf0\x0c\x14\xe9\xc7\xea\x76\xa5\xed\x13\x37\xa0\x54\xac\x2c\x94\x9c\x05\x97\x7e\x03\x02\x74\xf6\xa4\xf2\xa6\xb3\x0a\x15\xc5\x70\xec\x94\x33\xf7\x4f\x47\x52\x80\x87\xc9\xce\x9a\x62\x92\x95\x1c\x54\x35\x49\x96\xfb\x28\x3c\x0d\xc4\xcf\x33\xc0\x01\xbc\x96\x87\x5e\xa6\xe1\xf4\x6f\x83\x7f\xf1\x8d\xd9\x54\x5f\xb9\x93\x46\x55\x34\x2b\x12\xc2\x99\x0b\x9f\x1c\x6f\xf4\xd6\x64\x89\xd6\xae\xdc\xe7\x5c\x7c\xb0\x3a\xc1\x34\xbf\xd3\x9b\x18\x1d\xfb\x7f\x9a\x97\xce\x73\x7f\xe5\x70\xad\x5f\x81\x34\x59\x39\xa6\xde\x5a\x40\xa3\x3a\x0e\x44\xbf\x95\x75\x03\xd5\xca\x02\x83\x51\x2e\x57\xfb\xa8\xa3\xa6\xf2\xc3\x90\x68\x7b\x1b\x77\x08\x67\x6e\x0f\xd0\x3b\x7c\x18\x8d\x45\x61\xc1\x87\x91\x63\xea\xf2\xb5\x96\xdd\xd5\xf3\xc1\xf4\xda\xdb\xc1\x39\xc2\x16\x48\x92\x82\x0b\x2f\xe0\x9c\xbc\x3d\x19\x08\x80\x76\x36\x45\x10\x25\x4f\x2b\x6d\x41\x03\x29\xe7\x0f\x2e\x5a\x94\x5b\xba\xcd\x2c\xa8\x9b\xd4\xb6\xe1\xf5\xe2\xe1\xd4\xf4\xed\x2f\xe0\x11\x3b\xcf\x32\x96\x2f\x00\xd5\xc3\x3b\x1d\xf9\x88\x40\x2b\xa0\xdc\x88\x04\xc1\xaf\x66\xcc\xae\x26\x70\xef\xa3\x13\x4c\x67\xfc\x90\xfe\xed\x8d\x8d\xee\xdc\xcf\x6a\x46\xf2\x29\x40\x45\x4a\xf2\xbb\x67\x54\xcf\x23\x5d\xdb\xb0\x00\x1c\x6c\x74\x1b\xf8\x74\xbc\xd8\xd4\x1d\x9d\xba\x81\x62\x58\x1c\x37\x46\xd7\xf3\x0e\x73\xde\xf6\x94\x15\xaf\x51\x81\xc1\x49\x91\x42\x95\x12\x2d\x45\x98\x2f\x94\x94\x3e\x20\xb0\xff\xc7\xfe\x6d\xdf\x19\xa0\x22\xe8\x7a\x52\x13\x33\x57\xa1\xe8\x0f\x37\xf2\x8a\x4c\x4a\x8a\x61\xc1\x48\xdd\x87\x5c\x1e\x8e\xcd\xcd\x84\x0d\xd8\x63\xe4\x4d\x9b\xcb\x16\xb6\xe5\xaf\x01\x47\xb3\x4a\x7a\x90\x52\xc8\xd3\xf4\x52\x01\x3d\x2d\x35\x4f\x68\x03\xf9\xea\xf6\x05\x6f\x3b\x01\x3c\x61\x6e\x47\xf3\x98\x81\x91\x46\x32\x0a\x5e\x3d\xbd\xf1\x68\x43\xea\x29\xde\xf2\x62\xcc\x9a\x34\x36\x72\xcf\x96\xbc\xcc\x6e\x87\xe6\xa6\xba\xf0\x71\x2e\x6e\xe8\x9a\xa6\x04\x89\xf1\x7c\xb7\x2d\xdc\x44\xba\xd1\x61\x58\x7d\x87\xf5\x4d\x67\xcc\x0a\x27\x78\x49\x7d\x83\x10\x88\x31\x5f\xfe\xee\x3d\x26\x8c\x59\xbe\xfe\x88\x4c\x3a\xa0\xe0\xae\x22\x96\xbb\xb6\x0e\xac\x90\x97\xcd\xf8\xdc\x09\x87\xce\xb1\x74\x2b\x05\x86\xdf\xce\x79\xec\x10\x42\x5b\x28\xf4\xe6\x45\x20\xd7\x12\xe3\xf4\x6e\xa8\x3b\xe2\xde\x6a\x15\x74\x07\x3b\xc5\xc7\x55\x7b\x8e\x25\xb6\x41\x11\x84\xea\x28\x3d\x88\x00\x23\x2c\x79\x06\x94\x21\x81\x1f\x88\x3c\x29\x94\xe7\xb7\xe2\xad\x9f\x8d\xc4\x89\xc9\x34\x77\x24\x39\x46\x09\xc9\x89\x09\xa6\xc2\x60\x17\xb5\x0f\x20\xd5\x0c\xca\xcb\xde\x36\xb7\x6b\xa6\x46\xa7\x6d\xc6\xa5\xb0\xf5\x06\x49\xc5\x65\x8b\xbd\xfd\xd3\xb5\xca\xfc\x54\x79\xa2\xf4\x8e\xe5\x15\x42\xf2\x3e\x9f\xc9\x21\x32\x06\x0f\xd6\x35\xef\xf4\x52\x11\x1c\xda\xf3\xef\xbd\xb7\xdb\x9e\x7d\x47\x16\xd0\xd6\x01\x1c\x29\x11\x8a\x55\xd4\xc1\xa4\x36\xab\xe2\x4e\x3c\xbf\x40\x23\x5b\x76\xdd\x19\x23\x50\x3c\x5f\x35\x98\x12\x4e\x2d\xf5\x5a\x2d\x1f\x24\x6e\x90\xde\x4b\x71\x64\x5d\x51\x75\xb6\x1b\x01\x74\xe7\xe5\x7d\xf1\x28\x5c\xcf\x8c\x86\xb8\x38\x2c\x25\x80\x79"}, -{{0x05,0xc7,0x19,0xca,0xe0,0x6e,0x2b,0xb7,0xd8,0x78,0x63,0xab,0x31,0x50,0x27,0x2c,0xb2,0xf8,0xc3,0xaa,0x24,0x21,0x91,0x2d,0x87,0xf9,0x8e,0x75,0x89,0x63,0x8c,0xe9,},{0x90,0x21,0x17,0x96,0xfe,0xd3,0xd5,0x3b,0x81,0xf8,0xfe,0xeb,0x1b,0xad,0x1f,0xfc,0x93,0x3e,0x5f,0x10,0xd3,0xbc,0x1b,0x36,0xdd,0xf2,0x10,0xa4,0x79,0x23,0xdf,0x03,},{0xba,0x6e,0xb7,0x51,0x37,0x1d,0xf7,0x21,0xb7,0x70,0x7a,0x5b,0x33,0x39,0xed,0xb5,0x5f,0x13,0x86,0x40,0xb9,0x7b,0xe6,0x33,0x4d,0x6c,0xda,0x51,0x91,0xa3,0xff,0x63,0x67,0x91,0x17,0x61,0x88,0x2a,0x4a,0x00,0x7f,0x16,0x1b,0x74,0x8c,0xec,0x95,0xb1,0x9e,0x99,0x5f,0x28,0x58,0xc2,0x57,0xcd,0x61,0x69,0x25,0x66,0x62,0x30,0x11,0x02,},"\xec\x24\x19\x18\x41\x8e\x60\x52\x20\x42\xe6\x73\x39\xe6\x64\x94\x99\xf3\x1a\x6c\x7c\xf8\x92\x5f\x1f\x61\xdd\xe8\x94\x60\x36\x02\xae\x8b\xb5\xf5\x88\x09\x82\x1f\x83\x34\x4f\x23\xcd\x31\xe6\x4e\xc9\xff\xe7\x9a\x98\x6b\x7e\x29\xe4\x31\x9a\x63\x41\x43\x16\xbd\x6e\xe2\x0e\x02\xa5\x0d\xa4\x40\x12\xbd\x2d\x6f\x9f\x67\x9e\x88\xed\x0c\x8b\xb1\xe2\xca\xd5\x5e\x56\x57\x89\x88\x33\x45\xb7\x54\x6f\x3d\x54\xb1\xb3\x62\xb1\xc6\x50\x50\x2c\x01\x9d\x73\x13\xaf\xbc\x82\x68\x9b\x23\xa3\xa5\x2d\x8f\x1a\xf9\xf8\x1e\x18\x8d\xbd\xf2\x03\xfb\x53\x00\xb4\x22\x5b\xfb\x67\x73\x33\x7b\xe6\x75\x0b\x3d\xb8\x8c\xe0\x97\x34\x3f\x62\xee\x2c\x11\x85\x74\xef\x15\x0c\xbd\x4c\x62\x76\x0c\x3e\x43\xdc\xbc\x39\x21\x8b\xd6\xd9\x85\x65\xfa\x38\x98\x11\xb1\xa6\x74\xf6\x17\xfd\x75\x67\x33\xdc\xb5\x67\xa9\x2d\xbf\x38\x55\xb5\x7b\x1f\x4a\x46\xd5\xb8\x97\x4b\x39\xac\x0d\x0e\x24\xd9\x9d\x20\x37\xc0\x4f\x60\xd9\x14\x0f\x64\xb0\x7a\x77\xd7\xea\xa1\xce\x8a\x78\xe8\x44\xb1\xdc\xf0\xe3\x74\x24\xf3\xf9\xd2\x53\xa5\x48\x56\x1a\x03\x75\xa8\xd4\x34\x12\x97\xbf\xed\xb7\x04\x8c\x79\x35\xe1\x48\x14\x18\xf9\xbb\xa9\x27\x1f\x9f\xd6\x02\x62\x24\xe7\x8e\x05\x5d\x8a\x09\x39\xfa\x2f\xe1\xdb\xc0\xfc\x7b\x58\x3e\x4c\xff\x34\x90\xe1\xd0\xf6\x10\xb2\x52\xe3\x0d\x84\x97\xd0\x0e\x4a\xac\xb3\x75\xf1\x9a\x47\x19\xf7\x9c\xa1\xea\x58\x3a\x2f\x8b\x14\x06\xa4\xaa\x5c\xb5\x5c\x08\xb6\x59\x3b\x67\x6e\xb5\xc3\x4a\xbe\x89\x39\x2d\x62\xd2\x33\x08\xa3\x34\x8b\x57\xaf\xfb\xba\x77\x39\xcd\xe8\xe1\x90\x9d\x34\x25\xee\xb2\x09\x26\xa9\x77\xd3\xa9\x4a\x86\xe0\xba\x10\xb3\x86\x92\x66\x98\x82\x7e\x86\xb4\xfd\x6c\x61\x80\x04\x7c\x87\xec\x3b\x31\x61\x9d\x05\xa9\xdf\x34\xef\xd3\xd7\x6a\x83\x69\x62\xb2\xef\x60\x4d\x07\xaf\x09\x75\xeb\x8f\x3d\xd2\x25\x94\x32\x38\x02\x56\x4c\x92\x9b\x3f\x65\xda\xcb\x57\x2b\x32\x55\x3d\x69\xb3\x1a\x19\x76\x90\xa9\xbb\x86\x0b\x08\x0a\x77\xcf\xbb\x3c\x17\x5a\xaf\xce\x01\x46\xa8\x2a\x4d\x06\xe8\xc7\x50\x52\x1b\x72\x6e\xf1\xcb\x29\xd0\x21\xe5\x91\x5e\x5e\x84\x62\xed\xe5\x39\x54\x45\x24\x5c\x9a\xe8\x82\xee\xc4\xb1\x74\x5e\x11\x79\x1f\x76\x21\xd3\xfe\x70\x2c\xac\x15\x25\xe1\xf7\xb4\x6e\x11\x05\xcd\xd0\x6d\xa2\xaf\xde\x26\x47\x5d\xc1\xf7\x8d\xf8\xe2\xd7\x2b\x0e\xc3\xef\x7d\xd9\x56\x19\x3c\x99\x68\x42\xa4\x32\x69\x65\x38\xcf\x12\x3d\x76\x87\x21\x1f\xfc\xd0\x90\xb9\x38\x1e\xab\xec\x87\x9f\x76\x9a\xac\x0d\x35\x64\xe1\x6d\xf7\x94\xfa\x24\x72\x8d\x71\x72\xfd\x07\x73\x2e\xab\x07\x7e\xd8\x1c\x22\x08\x4f\x6f\x78\x1b\x62\x6d\xac\x67\x42\x8a\x9d\xdf\x3b\x0d\xb0\x46\x52\x51\x22\x0d\x18\xb8\xbf\x62\x04\x64\xc5\x1a\x57\x8d\xec\xcc\xbb\xab\xa5\x45\xed\x44\x2c\xf1\x2c\x4c\x66\xf6\xcb\x6e\x69\x01\xea\x54\xae\xda\x23\x6e\xc4\x5e\xef\x88\x6a\x7d\xdd\x2c\x04\x1c\xab\xa3\xa6\xce\xe3\x39\x71\x5b\x6c\xe9\x7e\x76\x5e\xc3\x47\x9f\x3d\x52\x82\x4a\x81\x94\xbe\xc2\xa8\x96\x47\xe8\xc6\x3f\xf7\x64\x5f\xf6\xd0\x53\x67\xc7\x67\xbc\x48\xcc\x96\xba\xf0\x5d\x6a\x41\x5b\x2a\x5a\xff\x9b\xfb\x21\x79\x48\xfa\xd3\x57\xb9\x8f\x47\xdf\xed\x62\xff\x12\x85\xeb\x9f\x46\x8f\x0f\x29\xed\xd7\x5a\xdc\x0c\x8c\x2f\xf6\xa5\x65\xed\xb8\xed\xfb\x48\xbe\xa0\x3b\x70\xc4\x47\x36\x9c\x52\xd8\x81\xee\xa0\xee\xdb\x08\xc3\x15\xcd\xf0\xbf\xeb\x97\x9c\x1c\x02\x50\x94\x6b\xb1\x00\xc2\x86\x6b\x41\x69\xb8\xcb\xd4\x4d\x65\x8f\x02\x36\xe1\xe9\xf3\xaa\x13\xbb\x8e\x80\x22\xa3\x8c\xe9\x97\xc9\x4b\x5b\xaf\x97\xe0\xba\x62\x1f\x7e\x09\x67\x1c\xe6\x38\xc2\xa3\x9e\xe6\xc6\xe2\x5a\x68\x80\x19\xdd\x16\x76\x75\xce\xae\xc2\x1c\x6b\x42\xa7\xc8\xc4\x76\xd1\x29\xdc\xc6\x93\xc3\x92\xa0\x2b\xe9\x1b\x87\x43\x7a\x08\xa0\xeb\xf1\xa7\xbd\x97\x6b\xa2\x37\x74\x76\x68\x38\xb8\xd6\x02\x4f\x5b\xb9\xb0\x7f\x3c\x6b\x71\x9b\x4d\xe1\x5b\x72\x44\x80\x48\xab\x70\xdb\x3d\x4b\xea\x77\xba\x35\x9b\x51\xb1\xec\x17\xdb\xe8\x01\x0a\xef\x02\x44\xa8\x07\x9c\xa8\xb9\xa2\xa7\x97\xf3\xb1\xfe\x04\x7c\x8d\xd5\xca\xb7\xfb\x48\x68\x29\x23\x9c\x4e\xf6\xd9\xa3\x83\x70\xd4\x88\xc4\x7b\x7c\x03\x0e\x49\xa5\x50\x0c\x9a\xbb\x39\xa9\xa5\xab\xfe\x72\xe9\x18\xb7\x63\x84\xec\xaa\xfe\x16\x27\x26\x6c\xd1\x4e\x69\x6c\x09\xd2\x51\x2e\x31\x25\x82\xa8\xa9\x11\xe7\xb7\xbf\xa0\x4c\x21\x81\x9a\xf6\x87\xf0\x4c\x5e\x0c\xbe\x9a\x2c\xe2\x4d\x4d\x3f\xd1\x21\x90\xb2\x53\xda\xbc\x12\xc6\x3c\xab\xfa\x94"}, -{{0x53,0x11,0xf3,0xc9,0x61,0x01,0xcb,0x8b,0x7a,0xbc,0x62,0x2b,0xb9,0x32,0x6b,0x8f,0x51,0x3c,0x2b,0x16,0xd2,0x94,0xdf,0x79,0x7f,0x56,0xdf,0xd8,0x20,0x3d,0xda,0x27,},{0x23,0x0b,0x70,0x02,0xf5,0x7c,0x79,0xae,0x2e,0x6b,0xfd,0xb8,0xdf,0x30,0xdb,0x3e,0x90,0x07,0x56,0xb5,0x4a,0xf3,0x96,0x8c,0x67,0x0e,0xe2,0xf3,0x2b,0xb1,0x1e,0x0a,},{0x3c,0xbb,0xb2,0x60,0x88,0x70,0xde,0xa1,0xef,0xee,0xbb,0x3f,0xbf,0x68,0x1e,0x27,0x70,0x5c,0x35,0xe4,0xdd,0xee,0xa8,0x6c,0x1b,0x34,0x2a,0x77,0xdc,0x29,0x6b,0x49,0x84,0x19,0x80,0x8e,0xac,0xbc,0x78,0x85,0x56,0x11,0xff,0xbc,0x92,0x65,0xa7,0x47,0x98,0xe5,0x18,0x27,0xe6,0xe5,0xd8,0x11,0x81,0x6d,0x3c,0xa2,0x1e,0x8b,0x9c,0x06,},"\x61\xb1\x5b\xe3\x7c\x4e\xb3\x97\xd9\xe7\x7e\x00\x15\x1a\x28\xed\x3e\x86\xd5\x0a\x95\x52\xbb\x48\x50\xb6\x21\x76\x3f\x01\x2e\x7e\x77\xbb\x5d\xb8\xf3\xdf\x7d\xcf\x76\x9f\x2d\x1d\x46\xd8\xd6\x0b\xae\x40\xc8\xca\x6e\x25\xc6\x41\x0b\x60\x07\x8a\x93\xfd\x05\x90\x21\x14\xbd\x91\x04\x5c\x06\x19\x2c\x70\xc4\x2c\x9f\x41\xf8\x16\x1c\xa4\x65\x64\xeb\xc2\x1a\x4b\xdd\x81\x90\xeb\xa2\xae\xb3\x09\x82\x30\x72\xec\x2c\x02\x00\xce\x64\x98\xf9\xd7\x2b\x37\xb3\xfb\x46\x67\x74\x32\x6d\xf3\x7a\xd8\x80\xd8\xed\xdb\x32\xaf\x67\x3e\x45\xd8\x8e\xec\x49\xb1\x57\x7b\x43\xb8\x63\x91\x11\xc2\xe0\xb9\x41\x87\xd2\xd4\xe0\x17\x3c\x00\x0f\x4c\x37\xbe\x84\x5d\x68\x81\x0b\x78\x89\xff\x2a\x04\x9f\x3f\x9f\x24\x5e\xc7\x0f\x21\xde\xf9\x77\x80\xb6\x11\x40\x0a\x83\xc3\x1a\x79\xd9\x3a\x8e\x98\xb6\x08\xfd\xcf\x24\x88\xb0\x68\xfe\x1a\xe4\x21\x72\x93\xa9\x36\x7b\xb7\x34\xb5\xbc\x7b\xd8\x81\x9b\x37\x7f\x09\x0b\x4f\x8f\xdb\xff\x50\x79\x9c\x76\x88\x0d\x19\x13\x35\x80\xe1\xdd\xfc\x2b\x9b\xaa\xdd\xba\xb3\x4f\xc6\xfd\xc0\x78\x01\x4b\xd1\xff\x73\x9d\xaa\xfe\x54\x76\xf3\xf7\x9d\x4d\xbe\xc2\x16\xfa\x76\x80\xee\x8e\x84\x00\x2d\xcb\x9d\xdb\xc7\xfc\x1e\x1c\x8e\xf4\xf1\xb2\xa2\x08\x1b\x92\x82\x24\x3d\xa6\x15\x3c\x1f\xce\x09\x05\xcf\x35\xf8\x3a\x68\x4c\x01\xb0\x45\x57\xec\x84\xf7\xe9\xa9\x4f\xc2\x88\x2e\x2f\xf1\x9f\xea\x21\xd2\xce\x61\x67\x86\x1c\xe0\x1d\xf8\xb8\xd3\xc3\xe8\xd2\x55\x61\x0b\x7a\xf2\x59\x6c\xd5\xcf\x00\x16\x73\x49\x42\xcc\x71\x4c\x27\x2c\x05\xfd\xa9\xd3\x47\x23\x62\x66\x46\xa4\x61\x30\x18\x2c\xeb\xcf\x17\x9e\xc0\x0a\x6a\x17\x3b\xd8\x57\x7f\xa8\x45\xc4\x4d\x19\xc6\x99\x79\x44\x75\x5f\x2b\x4e\x46\x85\x63\xa7\x5e\x90\x16\x52\x3b\x87\xdd\xac\x3e\xee\x21\xbc\xbc\xa0\x8f\xcc\x29\x54\x6a\x43\xcb\xe0\xd8\xd1\x0a\x0e\x8d\xdc\xba\x17\x2d\x1d\xed\x15\x03\x78\xe1\x8b\x36\x8c\x77\x63\x91\x3e\x4b\x40\x70\x12\xfd\x76\xa8\x72\xd2\xcb\x04\x93\x0b\x8e\x22\xb3\x08\x24\x3d\x4c\xc2\x78\xfd\xf2\xe1\xf9\x40\xae\x89\xac\x89\x1b\x9e\x06\x61\xae\xe5\x53\x93\x7b\xf3\x50\xb4\x07\x07\x0a\x1b\xdf\xc4\xf7\xa3\x78\x7e\xf3\x99\xd2\xca\xf4\xec\x74\x43\x9c\x58\x73\x76\xc7\x7b\xe0\xc3\xde\x53\x9d\x3a\xc2\x60\x89\x76\x5b\x9b\xe1\x0b\x90\x38\x69\x46\x36\xe2\x62\xd7\xba\xa0\xb3\xa8\x94\x1a\x20\x15\x96\x76\x39\xf6\x04\x4c\x67\xe5\x9b\xc8\x1c\xf2\xfb\xa7\x04\xac\x0d\xf4\x8d\xa6\x03\x74\x05\xa8\xe8\xb8\xa7\xce\x3c\x58\xef\x38\xa8\x83\x53\x8b\x24\x7f\xfe\x18\x09\x7a\xf0\x95\x24\x2b\x05\x8b\xdd\x1e\x3e\x24\x5e\xec\xe0\xa7\x1b\x75\xb9\x7d\x52\xf2\x0d\x6d\x51\xbb\x97\x66\xb0\xda\x0f\xc0\x9c\x8a\xc2\xa3\x0f\xb6\xe7\xb3\x2e\xe0\x6d\xad\xf4\x6d\x73\x59\xcc\x06\x6a\xa9\x47\x85\xd8\xa8\x82\xff\x09\x7d\x78\xa8\x6b\xe2\xd4\x56\x00\xdd\x3d\x30\x60\x12\x5f\x01\xc0\x63\xe4\x88\xd5\xc3\xef\xee\x1b\xca\x1e\x58\x51\x64\x55\xff\xca\xec\x1b\x81\xef\x43\x38\x76\xbf\x09\xff\xa5\x1d\x6f\x50\x18\x58\x52\x24\x57\x9c\xb6\x7b\x56\xce\x1c\x21\x6e\xc0\xa8\x83\xe0\x6c\x8e\x15\x63\x42\x1e\xa7\x2b\x0c\x10\xd4\xbb\x31\xe4\x91\xc2\xae\x2f\xe8\x13\x9f\x24\x9e\xc9\x27\xd8\x06\xba\x08\xdb\x52\xb1\xb5\x06\x66\x90\x47\xf0\xc1\x16\xff\x37\xac\x5b\xa6\xcd\xb1\xea\xaf\x33\xfd\xad\xb0\x70\x5c\x79\x9d\x35\xac\x6d\x9c\x80\xda\x90\xc1\x43\x8b\x58\x5f\xfd\x59\x35\x0a\x26\x86\xb1\xec\x35\x16\x6c\xb9\xb6\x9a\xd0\xf5\x65\x86\xaa\x03\x27\x4d\x78\x2e\x3f\x85\x8d\xb6\x4a\xdf\xbf\x04\xd5\x22\x8a\x7b\x1c\x4a\x20\x48\xbb\xcd\xb9\x41\x15\x3a\x43\x6d\x74\x2c\x38\xb5\x8b\x4d\x7d\x13\xc9\xf1\xd6\x0e\x15\x2a\xa2\x79\x23\x49\xa3\xd9\x4e\x7e\x6b\x11\x04\xaa\x1b\x87\x09\x98\xc1\x8d\xd7\x06\x56\x54\xa8\x52\x81\xbb\x6f\x02\x7f\xaa\xd5\x56\xb1\xf5\x32\xe7\xa1\xe2\x2d\x56\x40\x69\x28\x95\x87\xa0\xef\xc9\xc1\x58\x5d\x13\x5f\x31\x23\x3c\x41\xf4\x40\x46\x6e\x71\xfe\x90\x12\xe5\xf9\xa0\xd7\x4a\x72\x82\xee\x39\x2f\xb0\x16\x5d\xb7\x9f\xf1\xd3\x17\x6e\xd0\x8a\xfe\x1d\xaa\x66\xcf\xbf\x43\x05\xae\x16\xac\x17\x92\x33\x43\x99\xf7\x1b\x19\x17\xdd\xec\x27\x0a\xcf\xf6\x65\xea\x05\xd1\x84\xc2\xc5\xcd\x2c\xcd\x90\x2b\x22\xf9\xb7\x19\x5e\x66\xa6\x55\x56\xca\x88\x4b\xa6\xf5\xda\x04\xdc\xd4\x61\x7f\x33\xdc\x2b\x44\xa0\xea\x74\x2a\xeb\x2b\x93\xf3\xa4\x1d\xf7\x95\x7a\x02\x67\x97\xa5\x85\xce\xee\x81\x4b\x19\x75\xf5\x23\xd2\xdb\x5d\xbb\x9b\xe0\xca\x64\x9d\x1d\x45\xdc\xfd"}, -{{0xd2,0x90,0xff,0xd9,0x33,0x95,0xbd,0x5f,0xc5,0x87,0xd1,0xab,0x51,0x18,0x66,0xe7,0x2b,0x37,0x1a,0x17,0x35,0x73,0x2d,0x9d,0x5c,0x6a,0x18,0xdd,0x46,0x5e,0x93,0x63,},{0xfd,0x4a,0xad,0x73,0xb0,0x32,0x46,0x1c,0xa0,0xaa,0xe8,0x71,0xca,0x70,0x16,0x38,0x3b,0x2b,0xe0,0x16,0x90,0x53,0xfd,0xbf,0x6c,0x59,0x14,0xfd,0xd6,0xdd,0x6f,0x92,},{0x21,0x70,0x4d,0x5e,0x62,0x6d,0xcf,0x6a,0x9d,0xcd,0xef,0x93,0x54,0x29,0xeb,0x7f,0xb5,0xb2,0x57,0xee,0xcd,0x7b,0xf7,0x4a,0xcb,0x0c,0xd3,0x0e,0xcf,0xcf,0x60,0x8d,0x0c,0x5b,0x63,0x3a,0x4a,0x8a,0x9b,0xa2,0xcc,0x82,0xa2,0x1e,0x03,0x35,0x5e,0x01,0xd8,0x5d,0xae,0x7e,0xca,0xc8,0x89,0x6d,0xc1,0x5d,0xae,0x04,0x85,0x70,0x71,0x04,},"\xeb\xd9\x00\xbc\x91\x0c\x5e\xcc\x4d\x97\xda\xf7\xcb\x5e\xbb\x54\x91\x50\x0b\x7a\xd1\x16\xe3\x06\x60\x95\x07\x09\xd8\x08\x4b\xb6\x43\x4c\x5b\xea\x4a\x8c\xcc\x1e\xd5\xa8\x01\xbe\xbb\x1a\x11\x78\x78\xc0\x37\x47\x00\x3e\x14\x8e\xd9\x14\x34\x83\x2e\x89\x66\x24\x1a\x7f\xff\x22\xfe\x1d\x6d\x8c\x3c\x3d\xdd\x72\x15\xa1\xef\xaf\x4b\x07\xaf\xee\x1b\x25\x67\x3a\x14\x39\xea\xac\x32\x4e\x89\x5d\x4b\xe8\x39\xe9\x76\xc0\x3a\xc0\x01\x25\x48\x76\x88\x8c\xca\xaf\x39\x12\x72\x7a\x60\x10\x6a\x87\xbe\x69\x24\x7c\x9e\x43\x8c\x31\xfc\xa8\xd9\xc6\x1b\xae\x36\x8c\x83\xe4\x09\x01\xa9\x97\x00\xdf\xf8\x39\xb5\x13\xba\x8d\xc4\x2d\x93\xce\x09\x87\xa2\x33\x34\x70\xa9\xf9\x83\x31\x3f\x91\x98\x86\x59\xda\x54\x03\x9e\x49\x9c\xd1\xaf\x2b\x8f\xa0\xeb\xe7\x50\xe2\x4d\x55\xc2\xa5\xbd\x1a\xde\x3f\x68\x00\x92\x54\x2b\xd1\xbe\x0b\x97\x35\xba\x39\x3a\xd5\x69\x7d\x24\x1e\x8e\x8b\x28\x64\x6d\xb2\x7d\x2f\xb5\xa9\x40\xe8\xfa\xea\xf0\xb6\xc9\xef\xda\x88\x61\x5d\xec\x89\x1c\xe7\x32\x93\x08\x13\xbf\xbb\xd0\xbc\x5f\x82\x10\xab\xe8\x43\xbe\xb5\xe4\xf0\x28\xf4\x9b\xea\x34\xf1\xe5\xb0\x9e\xac\x4c\x66\x62\xc7\x4f\xba\x39\xde\x4a\x96\x02\xa9\x69\x4a\x85\xc7\xc1\x37\x5f\xda\xdf\xda\x6a\x19\x57\xfc\x5b\x59\x87\xa6\x87\xb0\x39\x95\xe5\x16\x97\xa1\xab\x5b\xb6\xcb\x11\xb6\x63\xc1\x37\x2f\xad\xe4\xc0\xac\xa8\xfb\xeb\xb4\xeb\x54\xce\x7c\xe3\x6c\x69\x04\xea\xf6\xea\xb2\xf3\x4f\xac\xd8\xc7\x68\xc8\xd3\x6d\xa2\x39\x7b\x1a\x02\x73\x5a\xea\x72\xcf\xaa\xd0\x39\x34\x10\xdb\x52\x7a\x8a\xb2\x36\xd4\xcd\xab\xdc\x88\x8f\xac\x6f\x18\x21\x48\xb1\x32\x61\x44\x25\xd3\x90\xff\x03\x6e\x54\x85\x5e\x42\x03\xc5\x12\x03\xc1\xf4\x3e\x37\xbb\xf6\xb9\xbf\x27\xf5\xb7\xe7\xc6\x65\x15\x14\x65\x40\x1a\xc3\x2c\xbe\x9e\x33\x50\x53\x5e\xdf\x48\xa7\xbc\x36\x03\xe2\x23\x2e\x93\x8f\x9a\x81\x5a\xc4\xd1\xde\xec\x99\x1e\xf9\x62\x09\x48\x44\x1f\x7a\x2f\x4a\x46\xe2\xc4\x00\xab\x91\x4c\x4b\xe5\x1d\xca\xad\x8e\xd8\x23\x9c\xbb\xe9\x77\xa9\xf0\x9c\x02\x69\x83\x19\xd9\xfe\x2a\x8c\x6e\xb6\x0b\x79\x9f\x29\xae\x76\x59\x97\x0d\x2e\xbd\xff\x3c\x6c\xf7\x09\xbb\xf6\xf4\xbb\x55\xb9\xdf\x4f\x61\xa2\x41\xde\xc1\x44\xb5\x99\x3f\x08\x7e\x78\x4b\x97\xbe\x1e\x53\x60\x8c\x2e\x81\x7c\xe3\xd9\xaa\xf9\x14\xe6\xb7\x23\xf5\xb4\xaf\xff\xd2\xa6\xb9\xfe\x9d\x2d\x73\x91\x5c\x7a\xd1\xff\xb1\x3e\xfc\xb7\x3c\x56\x23\x81\x95\x64\x52\x03\x98\x4c\x99\xaa\xfd\x02\x35\xf7\x3b\x3f\x88\x2e\x07\x39\x39\xbf\x78\x66\x57\x28\x01\x38\xdb\x05\xb8\x6f\xcc\x94\x60\xb3\x85\xef\x45\x59\x20\x4e\xcd\x81\xe2\xf1\x2f\x5f\x06\x2a\xa4\x48\xdc\xcc\x82\xea\x8d\x89\x46\x6d\xd1\xbe\x46\xf8\x2c\x4f\x87\xbf\x0d\xb2\xb8\x78\xac\xbb\x0d\x91\x12\xc8\xdb\x6f\x51\xd3\x5f\x6d\x42\xf7\x49\x85\x6b\x99\xe5\x50\xb6\xc4\x54\xe9\xe8\xbe\x4d\xa1\x75\xf0\xb5\xe8\x6b\xe6\x6c\x97\x9f\xd8\x78\x23\x7e\x57\xf6\x91\xf0\xd2\xac\xd0\x28\xfb\xff\xa5\xb0\x66\x87\x75\x03\x4d\xb1\xf2\x1d\xdb\xe7\x11\x4e\xe3\xdc\x0b\x44\xda\xca\x64\xc5\xa0\x3a\x2f\xee\xae\xab\xeb\x70\x63\xbf\xcc\xcc\x55\x9b\xaf\x27\xf1\xcc\xb2\x20\x2f\xa4\xd1\xb2\xbf\x44\xc0\x4b\x2c\x2f\x81\xf9\x4e\x28\x1b\x1a\x5a\xdc\x85\x0d\xa1\xb9\x47\x9f\xca\xbd\xda\xde\xa5\x6a\x11\x5b\xb5\xf0\x6c\xc0\x16\xf1\x41\xc0\xfc\xb5\xe8\x3a\xb2\x48\xea\xec\x90\x15\x8d\x8b\xe6\x47\xaf\xf1\x2e\x7e\xeb\x5e\x57\xdb\xcc\x29\x3c\xb3\xb6\xaa\xcb\x55\x23\x6d\x4a\x83\x9a\x06\x20\xf4\x76\x23\x87\xdd\x17\x14\xdf\x5c\x13\x5e\x3d\x9d\x68\x24\xf9\x3b\x7c\x90\xd3\xae\x38\xc5\x18\xd6\x07\x12\x0c\x83\x95\x70\x41\x3b\x46\xb8\xcc\xd7\x37\x04\x92\xd8\xae\x5c\x60\x9e\x00\xcf\x82\x51\xe2\xe7\xdf\x81\xe5\xb4\xf9\xc1\x6a\x5a\x53\x9f\x0a\xfc\xce\x41\xbb\x43\x62\xe5\xea\xa5\xf9\x40\xa1\x70\x6f\x4a\xfb\x6b\x14\x43\x2c\x81\xd4\xba\x1a\x33\xd3\x22\xdb\xf1\x06\x45\xab\x63\x73\x7e\xad\xc8\x6f\xe6\xe0\x97\x6f\x76\x33\x97\xfb\x89\x86\x37\x59\x5d\xfd\x36\x93\x47\x92\xd7\x79\xe2\x4c\x2a\x3f\x0b\xac\xf5\x3e\x04\x73\xc5\xfd\xa9\xc6\x12\x84\xe4\x41\x9b\xdc\x0e\xef\x5d\x22\xf4\xd9\xbf\x42\xe8\xc0\x49\x33\xbb\x93\xb5\x3c\x29\x5d\x7a\xc9\x39\x5a\xbb\x6d\xcb\xd7\x42\xb1\xe1\xbc\x3b\x0e\xa4\x43\x4e\xa2\x1b\x8e\xca\x9a\xe6\x82\xd3\x31\x5a\x41\xe9\xc3\xc3\x37\x18\x40\x76\x1d\xc5\x9c\xac\x45\xda\x7e\x38\x13\xe2\x87\x88\xdc\x89\xde\x35\x5b\x5a\xee\x08\x80\x90\xa3\x8d\xd3\x9d\x83\xe5\xe4"}, -{{0xd7,0xfd,0x73,0xd1,0xd2,0x29,0xa6,0x58,0x94,0x42,0x0e,0x4b,0xa7,0x34,0x27,0x0d,0x5a,0x20,0x75,0x83,0x64,0xde,0x89,0x7d,0x85,0x55,0xe2,0x41,0x97,0x45,0x3c,0x19,},{0x3c,0x22,0x77,0x2a,0xec,0x0a,0x0c,0x15,0x59,0x07,0x7f,0x2c,0xfd,0x1f,0x24,0x65,0xd4,0xb4,0x84,0x95,0xc5,0xd0,0x5f,0x1f,0x83,0x7c,0x31,0x84,0x5f,0x34,0xca,0xd1,},{0x40,0x0c,0x35,0x05,0xf1,0xdf,0xa8,0x0d,0xf4,0xb2,0x6d,0xb2,0x4c,0x02,0x7e,0xb8,0x19,0x77,0xf0,0xfb,0x9b,0x5a,0xca,0x52,0x4a,0xd5,0x12,0x00,0xf4,0xbf,0xb1,0x33,0xdb,0x83,0x48,0x23,0x31,0x41,0x95,0xf4,0xed,0xc2,0x92,0xd5,0xf5,0x30,0xd0,0x85,0x56,0xe7,0x80,0x9c,0xaf,0x23,0x39,0x76,0x8a,0xa3,0x80,0x29,0xfd,0xbc,0x28,0x0f,},"\xc9\x22\x58\x59\xd5\x55\xbc\x42\x01\x1a\xf1\xb4\xf1\x49\x98\xe6\xe9\xb0\xa6\x5e\x21\x72\x71\x3e\x96\x83\x80\xfb\x6c\xee\xdd\xa2\x2e\x02\x2c\x51\x30\x30\x31\xd9\x93\x1c\xce\xf2\xf7\xbc\x70\x5c\x9e\x21\x5c\x1d\x08\x9d\x48\x8d\xad\xda\xee\x15\x5c\x93\x9b\x62\x02\xca\x53\xbf\xc7\xf6\xe8\x8e\x15\x29\xd8\x2f\xb4\x5e\x02\xb5\xd0\x5a\x82\xbb\xb9\xdb\x5f\x41\x5c\x58\xba\x8b\xd5\x6c\xff\xd9\x22\x70\xb2\x47\x49\xe5\x6d\x12\xc9\x9a\xe9\x0c\x78\x00\xf5\x4f\x55\x25\x4e\xa4\x2d\xa5\xdc\xfb\xe0\xe1\xd9\x89\xcd\x2f\x68\x97\xe2\x32\xdf\x04\x70\x7b\x34\xaf\x75\xfa\x7f\xec\x33\xe5\x5e\xd5\x6a\xee\x39\xc2\x2b\x04\x5b\xed\xd1\x61\x08\x3b\xc5\x51\x4c\x1f\x81\xca\x90\x7b\x7c\x76\x03\x17\xa7\xfd\x5a\x5a\x02\xa5\xd4\x0e\x2e\x82\x3e\x24\xad\x96\xae\xf6\xda\x8e\xa9\x82\xb5\x16\x1c\xc3\x9d\x84\xaa\x2f\xfd\x95\x44\xc1\x1b\x63\x40\x37\xab\x0a\x1c\x8e\x36\xac\x63\x01\x9d\xa1\xb2\xd9\x95\xcb\x7b\xd3\xd6\x2f\xe5\x74\xde\xab\xcc\xbd\x0d\x3a\xe7\xa5\x6e\x5b\xec\x91\xe4\xba\x3f\x3d\xb8\xbf\xea\x88\xe6\x7d\xa6\x2e\x88\x27\x8a\x6e\x3b\x41\x8d\xce\xea\x05\x89\xf2\x5f\x7d\xd8\xad\x19\xdd\x84\x50\x89\x41\x9b\x47\x2e\xfc\xcc\x87\x9c\x17\x2b\x32\xee\x4a\x4d\xbc\x2e\x6c\x2e\x86\x5b\xb3\xb8\xca\x0a\xdc\xb7\x1f\xdf\x89\xe1\x97\x39\x10\xef\x24\x29\x15\xf3\x3e\x23\x6d\x2f\x7c\x8e\x9f\x1e\xe5\xb0\x7c\x6e\x3c\x25\x36\x0f\x8c\xb1\x46\x0b\xe8\x7d\xb3\x1a\x29\x1d\x4d\xee\x34\x95\x3e\x75\xc6\x75\xbf\x18\x1b\xb7\xa0\xb7\xb5\xc1\xbe\xfd\xc8\x6a\xda\x07\x2a\x48\xf6\xac\x75\x5d\x49\x9b\xd6\x8d\x62\x5d\x85\x14\x52\x5c\xc3\xab\x8f\x54\xce\x15\xa8\x71\x29\x17\x78\xde\x13\x05\xd2\x21\x93\x61\xaa\x30\xe3\x32\xa2\xe0\x69\x07\x7c\x5c\x53\x45\x75\x20\x37\x9d\x8b\x90\xd2\x4b\xd8\xa3\xa7\x70\x0f\xf7\x66\x23\x1c\xb5\x69\x7f\x9a\xce\x52\x1a\x99\xe8\x96\xda\x54\xc4\x07\x93\xbc\x7c\x1f\xb1\x58\x4b\xb1\xc8\x61\x94\xd2\xfb\x7a\x4b\x80\x2f\x30\x88\x5e\x0e\xe8\xaf\x88\xd6\x88\x6e\x3a\x3a\x4d\x4c\x85\x46\x49\xcc\x01\xab\xdf\x35\x31\x9a\x08\x56\xcc\x65\xd0\x92\xa3\x86\xf8\x86\x96\x25\xcd\x0a\xca\xc0\x87\xe9\x35\x17\x90\xcc\xb4\xa8\x65\xf6\x51\xa8\x81\xc3\xeb\xf1\x09\x07\x27\x74\xf9\x40\xf5\xaa\x98\xa2\xa2\xaa\x3d\xd3\x66\x47\xd0\xde\x83\x00\x1a\xa7\xcd\xc0\x31\xcc\x4a\x4d\x75\xdc\x11\xce\x55\x16\x76\xa2\xad\x43\xa3\xf6\xa1\x6a\x4b\xc5\xae\xe8\x0e\x53\x64\x20\x60\x87\x36\x4e\xb8\xb2\xb1\x5f\xb7\x05\x38\x0a\x07\x2d\x7c\x8b\x51\x99\x59\x43\xaa\x76\x2e\x8d\xeb\x4c\x56\x8c\xda\xa1\x41\x1a\xb6\x8f\x28\x48\x9e\x13\x23\xbb\x61\x56\xce\x25\x00\xb0\x6e\x77\x93\xc5\x10\xa3\xde\x29\x15\x08\x40\xbf\xdb\x0b\x2b\x7b\x21\xc2\xbb\x8a\x77\x46\x16\x7c\x92\x9d\xd0\xad\xad\x44\xfe\xd8\xf3\x6e\x83\x81\xb3\x42\x08\x0b\x2a\x7d\x82\xa3\xf8\x1f\xf7\x26\x30\xcb\x78\xdf\x91\xf7\xb6\x5a\x44\xef\xf6\xed\x64\xd4\x8a\xfe\xd1\x09\xdd\x7a\x69\x3a\x1b\xa8\xc3\x7e\x00\x8f\xcb\x15\x7e\x37\x29\x7d\x32\xeb\xa7\x65\xa6\xc7\x19\x3e\x73\xbd\x97\x64\x79\x85\xb1\x60\x38\xc7\x4a\x08\x4a\x8f\x25\x65\x4c\xd8\xcd\x2c\xdd\x27\xff\x17\x33\x4e\x06\xad\xaa\x05\x82\x64\x01\x7a\x3b\x2d\xa7\x8e\x57\x38\xa2\x7e\x35\x0d\x88\x2f\x5f\xae\x19\x92\x78\xd4\xe5\x0b\x8b\xad\xf5\x7c\x21\x41\xdf\xdc\x3c\xff\x99\xdf\x5d\xe8\x6f\xec\x29\x3c\x76\xcb\x94\xb6\xb1\x9b\xa3\x03\x4e\x46\x0f\x84\xc2\x80\xa2\xe6\x41\x2f\xab\x56\x98\xce\x89\x02\x07\xca\xba\xbc\xa0\xa9\x5b\x5a\xd5\x33\xce\x11\x4b\xf7\x1a\x40\x4a\x87\x59\x0d\x35\xfa\x7c\xed\xba\x43\x13\x1c\x4e\xe9\x23\x44\x83\x9f\x25\xcb\xfa\xeb\x12\xae\xeb\xc8\x04\x08\x93\x95\x1a\x34\x6b\xd2\x8f\xdd\x16\x7b\xd2\x0f\x71\xa1\xe5\x9f\xb6\x0d\x55\xe1\xc5\x67\xf4\x78\xf0\x27\xcf\x67\x9a\x37\xd1\xd9\xdb\x86\x7e\x17\xbf\xdd\x60\xb3\x47\xd8\x9d\x32\x26\x39\xd3\x15\xbb\x7a\x2c\x91\x34\xf0\x0e\xa0\x3a\x36\x7f\x30\x5e\xa4\xd6\x0d\xc9\xd5\x67\xcf\x92\x48\x51\xe4\x69\xea\x95\x4e\xd3\xea\x63\xea\x86\x06\xf7\x9f\x07\x73\x39\xbf\xa2\xb5\x1a\xe4\x9b\xaa\x0f\xb2\x53\x77\x82\x1d\x7c\x11\xef\x9a\xd4\xbb\x4c\x0f\xe4\x89\xac\xba\xb0\xef\x00\x0d\x61\x8c\x7a\xf5\xef\xd2\x05\xd6\x85\x99\xfc\xbd\xd9\x5e\x28\xf8\x36\xe0\x91\x6f\x9f\xf5\x48\xd0\xba\x17\xda\x62\x53\x6e\x74\x64\x68\x01\xee\xb6\x12\x2b\xa3\x2c\x41\x07\x3a\xe0\x4e\x42\xc6\xc1\xd5\xd8\xd2\x29\x76\xa5\x62\x26\xdd\xf4\xb6\xac\x95\x45\x5f\xb5\x30\x99\xf2\x02\x15\xb2\xeb\xc9\x07"}, -{{0xfd,0xa7,0xcb,0x08,0x40,0x16,0xba,0x51,0x3c,0x7c,0x4f,0x8f,0x71,0x80,0x48,0x0b,0xb1,0x81,0xe9,0x56,0x95,0xea,0x68,0x73,0x7f,0xa3,0x4a,0x40,0xec,0xbd,0xf3,0xef,},{0xa2,0xde,0x3a,0x0e,0xf9,0x72,0x98,0xfd,0x71,0x61,0x06,0xe2,0xf3,0xf5,0x45,0x13,0x05,0x7a,0x40,0x07,0x2d,0x23,0x4c,0x35,0x18,0x15,0x4c,0x1b,0xd1,0x2d,0xe0,0x37,},{0x33,0x61,0x4b,0x7a,0x94,0xf7,0x5e,0x03,0x65,0x34,0xd7,0x6e,0x30,0x14,0x7e,0xcc,0xdd,0x2a,0x04,0xe0,0x0c,0xd4,0x70,0x4a,0xb6,0xe8,0x07,0xd6,0xa2,0xac,0xc1,0xe1,0xd9,0x63,0xb8,0xee,0xe0,0x81,0x0d,0x41,0x2d,0x9d,0x56,0xe5,0x45,0x56,0x30,0x2b,0x10,0x73,0x0c,0x15,0xab,0xf8,0x9c,0x29,0xa0,0x27,0x30,0x3e,0xa8,0x8a,0xe7,0x01,},"\xc2\x1b\xb3\xf8\xe3\x7b\xef\xa3\x67\xc9\x13\x67\x31\x01\xba\x30\xd3\xb5\xc7\x4b\xd8\xbd\xb0\x9c\xd2\x86\x40\x01\x2d\xb4\x11\x20\xc2\xbc\xc4\x08\x5d\xe2\xa0\xf9\x5c\x92\x15\xdd\xef\x8c\xb5\xfc\x8d\x8b\x12\x51\xb4\x15\x27\xc6\x7d\xfa\xa3\xf9\x5b\xa3\x57\x83\x91\xea\x5a\x66\x29\xa7\x33\x09\x5f\xd0\xa4\x3f\xdb\xa4\x0f\xfe\x26\x0f\xff\x82\xac\xee\x2e\xbe\x98\x0e\x9e\xce\xcc\xfe\x7e\x10\xb2\xed\x8c\x2e\x6b\x41\x0d\x54\x7a\x12\x86\x57\x1d\xf3\xd7\x01\x17\x4e\x57\x9f\xcf\x19\xd3\xbd\x80\x86\xc0\x42\x3f\x37\x11\x77\x89\xf3\x05\xd9\x67\x0a\xd2\x8c\x99\x67\x4f\x52\xcf\x64\x21\x1a\x08\x1d\x0c\x6c\x30\x96\xda\x2c\x71\xbf\x5f\x57\x99\xa7\x91\x0e\x6f\x38\x10\x4a\x37\xa6\x55\x7c\x2d\xae\xf3\x40\x81\x4a\x1f\x83\x0d\x59\x37\x73\xc6\xcf\x48\xd8\x3e\xa0\x72\x94\xb9\x4e\xb0\x80\xb8\x5d\x69\x70\xe2\x8f\x40\x51\xd5\x06\x6d\xb1\x0e\x96\x19\x73\xa6\x26\xa8\x26\xae\xaf\x8a\x06\xec\x0d\x56\x6b\x7e\x0c\x4e\xf6\x0f\x0c\x56\x78\xfc\xbb\x5b\x2a\xc6\x3f\x7b\xed\x06\x44\x8a\x24\x7b\x3d\x42\x7b\x87\x08\x6d\x33\x57\x3f\xb2\xd7\x22\x8c\x5c\x34\xea\x66\x40\xee\xfa\x95\x64\x48\x5a\x79\x63\x8e\x9c\x97\xc0\xaf\x84\xcf\xee\x7c\xe4\xa7\x39\x22\x0c\x84\x29\xe0\x67\x14\x39\x53\xd5\x50\x66\x8d\xad\xc8\x4e\x7b\xed\x9a\xb0\x70\xa5\x94\x33\x90\xc6\x11\xd7\x5b\x1c\xb1\x28\x73\xa3\x7d\x98\x50\x66\x1a\x00\x77\xbf\xa9\xca\x9b\x8b\x26\x37\x66\xc1\x49\xff\x0e\xe4\xb4\xad\xba\x25\xea\xf7\xd7\xf5\x01\xf3\x62\x45\x42\x56\xbc\x12\x69\x37\x8e\xf3\x35\x9a\x8e\xd6\xb9\x60\xb8\x66\x21\xfa\x3b\x61\x3e\xb1\x32\x12\x2f\x49\xf2\xeb\x2c\xeb\x68\x32\xa3\x99\x1e\x96\x1c\xb0\xe7\x8b\x74\x2e\xf4\xd6\x5e\x8d\xe3\x46\x96\x66\xfe\xc7\xc5\xb8\x74\x78\x95\x71\xc5\xc9\x9a\x2c\x02\xa0\x53\xff\x7d\x2f\xc9\x00\x76\xba\xfe\x1f\x26\x7f\xa8\x1a\x39\x90\xf2\x7f\xf1\x4f\x03\x00\x0a\xf0\x0c\x59\x28\x6c\xb9\xbb\x98\xe2\x04\xe9\x01\x90\xae\x2a\x50\xed\xef\x04\x9e\xa9\x2a\x1f\x78\x50\x88\xf9\x4a\xdf\x65\x88\xfb\x43\xbb\x40\xfb\xe2\x32\x42\x35\xcc\x7e\x16\x8b\x80\x26\x4b\x06\x9f\x94\x4f\x50\x36\x92\xc9\x49\x23\x4d\x5b\x76\xbc\xff\xab\xe2\x9f\xf9\x06\x4b\xd7\xcb\xed\x9e\x00\xe5\xb7\xfd\xda\x43\x12\xeb\x80\x14\x65\xf1\x27\xd0\xca\x68\x83\x2a\x7f\x4e\xd0\xea\xed\x8f\x55\x9c\x16\x31\xcd\x4d\x34\xf0\xdc\x41\x4d\x9f\xcf\xe8\x49\xa9\x1e\x25\xf3\xe0\xff\x01\x3a\x8c\xff\xa8\x06\xed\x8e\x93\xd0\x8a\x1e\x5a\x75\x76\x82\xca\x3d\x26\xab\xc8\x69\xc7\x6f\x1c\x79\x00\x7d\x55\x9d\xfe\x67\xe7\x8d\x8a\xf0\x19\x58\x08\xb0\xe7\x71\xc7\x1e\x64\xb5\x71\x6f\xb3\x63\x09\xc2\x50\x25\xfa\xe6\x41\x4c\x28\xbb\xdb\xd4\xde\x59\x7a\x74\x99\x6c\x9d\xa9\x74\x92\x0d\x59\xe6\xf4\xc2\xed\xfe\x11\x0f\xf8\x17\xfd\x48\x0a\x50\x80\x97\x80\x48\x86\x57\x12\x05\x8c\x5f\xe7\xb5\x60\xb1\x2b\x67\xf7\x37\xea\x6e\x2a\xf9\x24\x2c\xf0\x7a\xd0\xa8\xa6\x79\xf2\x64\x30\x04\x6a\xdc\x3e\x70\x66\x4c\xc9\xc0\xee\x5a\xbc\xef\x6d\x72\x6b\x4e\x04\x17\x60\x48\xb7\x95\xbe\x12\x85\x1b\xdb\x74\x00\x3a\x13\x20\x41\x19\xb8\x68\x64\xd6\x53\x5b\xa0\x95\x04\x0a\x85\xd9\x78\x1c\xf4\xf3\x48\x0a\x30\x4e\x22\x7f\x78\x7a\xd5\x38\xe6\x8f\x4b\xab\x01\x41\x79\xe3\x0d\x3f\xde\xf9\xef\xf1\x1b\xcf\x47\x1f\xa3\xa0\xbc\x74\xb5\x57\x6f\x30\x2d\x3a\x6b\x49\x9f\x11\xf2\xef\x32\x6a\xc0\x26\xc9\x8d\xb1\x0e\x27\x41\x41\x3f\x32\x22\x28\xb3\xcf\xf0\xf3\x37\xba\x2f\x29\x4c\x78\xef\x73\xf0\xe8\x77\x87\x8f\x8f\xc7\xff\x6d\x10\xbc\xe6\x6a\xd6\x28\x43\x79\xb8\x0c\xa8\x93\x27\xd4\xdb\x0b\xf1\x4e\x6d\x8f\x01\xb2\x2a\xb2\x02\xb7\x16\xcc\x07\xe3\xc8\x86\x6d\x16\x8a\x50\x94\xba\xc5\xa4\x95\xe7\x38\x68\xee\xdc\x27\x22\x2e\x64\x44\xf8\x3b\xcf\x65\xac\xdc\x3e\xc8\x91\x20\xbb\x50\xe8\xab\xfc\x28\xb7\x8e\x6d\x98\x0c\x77\x5f\x48\x49\xa0\xe8\xca\xda\x80\x24\x0b\xca\x24\x5e\x39\x96\x6e\x89\xa0\x34\x4d\xf8\x36\x3a\x7d\xcc\x81\xb2\x01\xce\x9c\x75\x3a\xd5\x44\xe1\x12\x4e\x21\x02\x0d\x4c\x62\xde\xda\x9e\xd9\xb9\xd1\xf2\xfb\x7c\x54\xca\x7a\xb0\x9f\x38\x3b\xef\x48\xcf\xc6\x84\x8c\x27\x13\x02\xa1\x0f\xa6\x87\xf5\x6e\x00\xe0\xa7\xd0\x93\xc9\x27\xb4\xfd\xd8\xf1\xbe\xdf\x62\x88\xa0\xe3\x02\x84\x8a\x80\x12\xf1\x27\xa7\x9d\x2d\x30\xa0\x6c\xe1\x7d\x94\xaa\x6f\x7f\x8a\x1e\x6e\xb9\xd0\x68\x1c\x37\x74\xf6\x14\xcc\x6d\xbc\xb2\xa8\x13\xf9\x25\xc6\x30\x6a\x63\x05\x72\xa8\x3e\xc1\x09\xd5\xf5\x33\xc0\x58\x4c\xb4\x21\xd9\x19"}, -{{0xa1,0xac,0x48,0xaa,0x5f,0xfa,0x3d,0x80,0x08,0x19,0xd0,0x3b,0x7f,0x62,0xba,0xbf,0x29,0x1f,0x20,0x90,0x4c,0x11,0xa6,0x40,0x0e,0x4f,0x45,0x20,0x5f,0x10,0x3e,0x38,},{0x08,0x54,0xe0,0x34,0x0f,0x81,0x49,0x85,0xfb,0x12,0x2b,0x78,0x72,0x94,0x79,0xe3,0xfd,0xe8,0x55,0xc2,0x11,0xca,0xde,0xae,0x56,0xf0,0xd4,0xdc,0x08,0x28,0xd5,0xfa,},{0xc5,0x7e,0x3c,0x09,0x1e,0xd2,0x4e,0x5e,0x84,0x66,0x5b,0xd9,0xbb,0x10,0x2d,0xb4,0x97,0x97,0xdf,0x90,0x08,0xf0,0x55,0x57,0xfa,0x0d,0x5a,0xd7,0xa2,0x95,0xe5,0xe4,0xd2,0xa4,0x71,0x6b,0x17,0xf8,0xc9,0x1c,0xb1,0x2f,0x5a,0xbf,0xb1,0xaf,0x02,0x7f,0xb0,0x41,0x11,0x99,0xac,0xc5,0xd2,0x85,0xd8,0x42,0xa4,0xb6,0x5b,0xde,0x49,0x02,},"\xd6\xf1\x24\xed\x75\x20\x21\xc1\x09\x26\x97\x2a\x0c\x26\xf3\xb1\x83\x8b\x3c\x7a\xf2\x47\xc1\x80\x09\xa2\x31\xec\xce\x96\x4b\xf6\x69\x86\x37\x83\x3f\x60\x7d\xca\x83\x6f\x8a\x60\x6c\x72\xae\x3c\xb1\x70\x17\x44\x47\xa2\xcc\xe5\x83\xf6\xe2\x44\xdb\xc1\x63\xe2\x15\xb9\x82\x0d\xe7\x49\x6f\xfc\x5b\x70\x50\xc4\x8f\x28\x30\x24\x66\x78\xcb\xa4\xdc\x5c\xaa\x07\xc1\x45\x85\x63\xaa\x2d\x10\xdc\xb7\x77\x0e\xf8\xfe\xde\x02\x7d\xd7\xf2\x0d\xdc\x8c\xc7\x8c\x3a\x2e\x2e\x95\x8b\xd1\x8c\x00\x06\xcf\x8f\xb8\x2d\x44\xe5\x3e\x1d\xa7\xaa\x80\xfd\x10\x06\xf3\xb2\x30\x0c\x9b\x07\x9d\x8a\x66\xf1\xe4\xa3\xf4\x70\x61\xf9\xe2\xf4\x5d\xae\x35\xdc\x29\x52\x04\xb1\x94\x60\xca\x57\x07\xab\x57\xce\x21\x5a\x24\xc1\x0f\xaa\xb3\xfa\x20\xbc\xcd\x10\x1e\x7a\x7d\x70\x07\x75\x99\xf3\xd6\x72\x57\x07\x55\x21\x29\xca\xd7\x57\xd6\x51\x4c\x1b\x28\x99\x7e\x47\x1f\x94\xb0\xfd\xed\x8f\xbb\xd0\x65\xde\xad\x19\x6d\x2c\x07\xd3\xdf\xa7\xb9\xfb\x3b\xae\x76\x80\xf7\x66\x21\x20\x0d\x09\x9e\xeb\xeb\xbe\xa0\xe8\x95\x7d\xf5\xb5\xe2\x04\xca\x3e\x9e\x29\x52\xb8\xa3\x0f\x0a\x13\x1a\x68\x67\xb1\x38\x1e\x39\x4b\x1b\x44\x43\x10\xf0\x76\x32\x66\x56\xcf\x93\x41\x67\x80\x08\xe9\x52\x51\x47\xd8\xd6\x1c\xe9\x3d\x3b\xf5\x39\x00\xca\xb9\x12\x66\x37\x17\xe0\x98\x72\x93\x83\x3d\x19\x02\xd7\xfb\x04\x7b\x99\x7b\x86\x02\x6c\x46\x7d\x7b\xb1\x7c\xf4\x57\x96\x73\x8f\x7a\x77\x4a\xc1\x26\x76\x4e\xd4\xeb\x45\x12\x43\x09\xf4\x58\x62\x60\x17\x6b\xa4\x65\x91\x8d\x48\x33\x0a\x9c\xc1\x8c\x4e\xce\xa0\xdd\xaf\x38\x94\x6a\xcc\x0e\x36\x1d\xd4\x0a\x7e\x91\x33\xce\xb5\x0e\x1c\x31\x7e\xa4\x2b\xd0\x98\x0a\x72\xb8\xba\x3d\x8a\x6c\x76\x93\xdd\x56\x02\xf3\x74\xf2\x66\x4d\xf4\xba\x56\xdf\x01\xe8\x82\xfc\xa4\x2c\xb4\xdb\x62\x1f\x47\x6c\x76\xe1\xea\x9f\xd1\x05\x91\x1a\x74\xb7\x79\x52\xd9\x91\x4a\x5a\xc0\xf9\x8a\x90\x0c\x1b\x2e\x1a\x56\xc4\xea\x85\x18\xa9\xee\x47\xc4\xed\x14\xd0\xbd\x35\xec\xa5\x60\x31\x9c\x8e\xa2\x47\x55\xd7\x1a\x4e\x03\x08\x50\xbc\x4d\xc6\x03\x89\xf3\x25\x80\x40\x21\x20\x4c\xce\xbc\x25\xfe\xdb\xd3\x2e\xdd\x8d\x84\x46\xaa\x23\xce\x56\xa8\x5f\x77\x9e\x85\x8d\x36\xaf\x7c\x07\x3c\x11\x5e\x34\x1f\x41\x2c\x66\x0f\xab\x80\x0f\xe7\x4c\x50\xe7\x14\xee\x08\x6e\x2f\xbc\x8d\x7a\xbb\xf3\xe9\x8f\xb4\x0c\xa2\x7f\x1f\x01\xa9\xaa\xdd\x8c\xc2\x27\x5c\x2d\xd3\xf7\x6e\x4c\x1d\x81\xc4\xb7\x92\xda\xec\xc9\xfe\x66\x04\x49\x41\xb8\xb2\x91\x84\x86\xdd\x4a\xcb\x56\x2a\x7b\x58\xad\x8c\x60\xc2\x1b\x83\xcf\x48\xae\xfa\x72\x56\xa1\xed\x80\x9e\x66\x98\x11\xf4\x84\x36\x49\x70\xbc\x56\x95\x08\x99\x19\xbc\x32\xd2\x8e\xa7\x52\xe8\xe3\x18\xce\xff\x46\x7f\x77\xae\x19\x77\xc5\xff\xd7\x9c\x17\xc2\xda\x8b\xc7\xf8\x23\xdd\x94\x39\x86\x83\x18\x99\x45\xf8\xb7\x92\x38\xa4\xe8\x15\xb1\x42\xb8\x66\xac\xbd\xbc\xb7\xae\xa7\xf1\x43\xff\xfb\x7c\xc2\xb4\xb5\x4b\xbf\x36\x1a\xfd\xa9\x13\xad\x6d\xf1\xe4\x9d\xfd\x6b\x53\x26\x42\xe6\x3f\x55\xd8\x93\xa4\x70\xd4\x03\x70\x66\x5c\xfb\x74\xef\xd3\xf5\x9c\xb0\xff\x60\x06\x17\x4c\xa3\x5f\x53\xb9\x7c\x54\x3e\x08\xaf\x4b\xf5\xbb\x75\xff\x90\x31\x61\x06\x52\xa3\xf6\xf2\xa0\xcf\xe9\x7e\x7a\x52\x1f\x3d\x2a\x28\x91\x14\xde\xd3\x47\x72\xb0\xe4\x98\x17\xbd\xe1\xcb\x92\x4f\xf5\x14\xe2\x86\x6a\x09\xe3\xed\xe0\x78\x2d\x2c\x0c\x98\xe6\x81\x4b\x8c\x1e\x77\x8c\xf8\x30\x63\x48\xc9\x33\xad\xb2\xe4\x72\xdb\xa0\x9d\xb9\x54\xff\x49\x64\x83\x73\x39\x5a\x2f\x01\x81\x95\x8f\xeb\x1e\xa2\x83\x4c\x99\x53\x28\x73\xdb\x5c\x88\xeb\x52\x89\xc7\x7e\x90\x01\x52\x03\xef\x50\x2a\xc8\xe1\xc4\x8f\xa1\xa0\x6d\xaf\xa6\x51\x9d\x52\xda\xe3\xc5\x56\x75\x70\xdd\x24\x34\xe6\x71\x92\x7c\x66\x36\x3f\x78\x31\x56\x89\x3f\x13\x8a\x84\xc7\x56\x64\xb3\x0a\xe4\x27\x51\x12\x73\x6d\x53\xd4\xf3\x99\xdd\xda\x3d\x23\x06\x7c\x07\x3f\x52\x1a\xfb\xa1\xf7\xbe\x58\x55\x13\xc2\xce\xc9\xc8\xf0\x8d\x2a\x22\xc3\xc8\x53\x92\xcd\x2a\xe5\x0f\x39\x28\x25\x1f\x86\xb3\x10\xc6\x9a\x0f\x8c\x4e\x85\x3a\xb3\xf3\xe8\x12\x9b\x05\x66\xef\x4b\xbb\xe8\x0b\x8c\x02\xc8\x92\x8a\x4d\xe5\x6c\x0d\x11\x9a\x45\xbb\xf5\xaf\x18\x08\xd4\x88\x85\x2d\x8a\x45\xbe\xb0\xd6\x83\x24\x8a\x4d\x65\xde\x15\x26\xb3\xd1\xd2\xff\xc1\xf2\x22\x15\xb6\x08\x46\x8c\xbc\x3b\xd3\x95\x14\xb3\x97\xfc\x0d\xb0\xf1\x13\xdb\xe6\xfc\xe4\x65\x2e\x82\xff\x89\x5b\x2b\x43\x87\xe0\x41\xd7\xe4\xe7\xbd\xe4\x69\x47\x69\x66\x5e\x81"}, -{{0xf5,0xe5,0x76,0x7c,0xf1,0x53,0x31,0x95,0x17,0x63,0x0f,0x22,0x68,0x76,0xb8,0x6c,0x81,0x60,0xcc,0x58,0x3b,0xc0,0x13,0x74,0x4c,0x6b,0xf2,0x55,0xf5,0xcc,0x0e,0xe5,},{0x27,0x81,0x17,0xfc,0x14,0x4c,0x72,0x34,0x0f,0x67,0xd0,0xf2,0x31,0x6e,0x83,0x86,0xce,0xff,0xbf,0x2b,0x24,0x28,0xc9,0xc5,0x1f,0xef,0x7c,0x59,0x7f,0x1d,0x42,0x6e,},{0x0a,0xab,0x4c,0x90,0x05,0x01,0xb3,0xe2,0x4d,0x7c,0xdf,0x46,0x63,0x32,0x6a,0x3a,0x87,0xdf,0x5e,0x48,0x43,0xb2,0xcb,0xdb,0x67,0xcb,0xf6,0xe4,0x60,0xfe,0xc3,0x50,0xaa,0x53,0x71,0xb1,0x50,0x8f,0x9f,0x45,0x28,0xec,0xea,0x23,0xc4,0x36,0xd9,0x4b,0x5e,0x8f,0xcd,0x4f,0x68,0x1e,0x30,0xa6,0xac,0x00,0xa9,0x70,0x4a,0x18,0x8a,0x03,},"\x08\xb8\xb2\xb7\x33\x42\x42\x43\x76\x0f\xe4\x26\xa4\xb5\x49\x08\x63\x21\x10\xa6\x6c\x2f\x65\x91\xea\xbd\x33\x45\xe3\xe4\xeb\x98\xfa\x6e\x26\x4b\xf0\x9e\xfe\x12\xee\x50\xf8\xf5\x4e\x9f\x77\xb1\xe3\x55\xf6\xc5\x05\x44\xe2\x3f\xb1\x43\x3d\xdf\x73\xbe\x84\xd8\x79\xde\x7c\x00\x46\xdc\x49\x96\xd9\xe7\x73\xf4\xbc\x9e\xfe\x57\x38\x82\x9a\xdb\x26\xc8\x1b\x37\xc9\x3a\x1b\x27\x0b\x20\x32\x9d\x65\x86\x75\xfc\x6e\xa5\x34\xe0\x81\x0a\x44\x32\x82\x6b\xf5\x8c\x94\x1e\xfb\x65\xd5\x7a\x33\x8b\xbd\x2e\x26\x64\x0f\x89\xff\xbc\x1a\x85\x8e\xfc\xb8\x55\x0e\xe3\xa5\xe1\x99\x8b\xd1\x77\xe9\x3a\x73\x63\xc3\x44\xfe\x6b\x19\x9e\xe5\xd0\x2e\x82\xd5\x22\xc4\xfe\xba\x15\x45\x2f\x80\x28\x8a\x82\x1a\x57\x91\x16\xec\x6d\xad\x2b\x3b\x31\x0d\xa9\x03\x40\x1a\xa6\x21\x00\xab\x5d\x1a\x36\x55\x3e\x06\x20\x3b\x33\x89\x0c\xc9\xb8\x32\xf7\x9e\xf8\x05\x60\xcc\xb9\xa3\x9c\xe7\x67\x96\x7e\xd6\x28\xc6\xad\x57\x3c\xb1\x16\xdb\xef\xef\xd7\x54\x99\xda\x96\xbd\x68\xa8\xa9\x7b\x92\x8a\x8b\xbc\x10\x3b\x66\x21\xfc\xde\x2b\xec\xa1\x23\x1d\x20\x6b\xe6\xcd\x9e\xc7\xaf\xf6\xf6\xc9\x4f\xcd\x72\x04\xed\x34\x55\xc6\x8c\x83\xf4\xa4\x1d\xa4\xaf\x2b\x74\xef\x5c\x53\xf1\xd8\xac\x70\xbd\xcb\x7e\xd1\x85\xce\x81\xbd\x84\x35\x9d\x44\x25\x4d\x95\x62\x9e\x98\x55\xa9\x4a\x7c\x19\x58\xd1\xf8\xad\xa5\xd0\x53\x2e\xd8\xa5\xaa\x3f\xb2\xd1\x7b\xa7\x0e\xb6\x24\x8e\x59\x4e\x1a\x22\x97\xac\xbb\xb3\x9d\x50\x2f\x1a\x8c\x6e\xb6\xf1\xce\x22\xb3\xde\x1a\x1f\x40\xcc\x24\x55\x41\x19\xa8\x31\xa9\xaa\xd6\x07\x9c\xad\x88\x42\x5d\xe6\xbd\xe1\xa9\x18\x7e\xbb\x60\x92\xcf\x67\xbf\x2b\x13\xfd\x65\xf2\x70\x88\xd7\x8b\x7e\x88\x3c\x87\x59\xd2\xc4\xf5\xc6\x5a\xdb\x75\x53\x87\x8a\xd5\x75\xf9\xfa\xd8\x78\xe8\x0a\x0c\x9b\xa6\x3b\xcb\xcc\x27\x32\xe6\x94\x85\xbb\xc9\xc9\x0b\xfb\xd6\x24\x81\xd9\x08\x9b\xec\xcf\x80\xcf\xe2\xdf\x16\xa2\xcf\x65\xbd\x92\xdd\x59\x7b\x07\x07\xe0\x91\x7a\xf4\x8b\xbb\x75\xfe\xd4\x13\xd2\x38\xf5\x55\x5a\x7a\x56\x9d\x80\xc3\x41\x4a\x8d\x08\x59\xdc\x65\xa4\x61\x28\xba\xb2\x7a\xf8\x7a\x71\x31\x4f\x31\x8c\x78\x2b\x23\xeb\xfe\x80\x8b\x82\xb0\xce\x26\x40\x1d\x2e\x22\xf0\x4d\x83\xd1\x25\x5d\xc5\x1a\xdd\xd3\xb7\x5a\x2b\x1a\xe0\x78\x45\x04\xdf\x54\x3a\xf8\x96\x9b\xe3\xea\x70\x82\xff\x7f\xc9\x88\x8c\x14\x4d\xa2\xaf\x58\x42\x9e\xc9\x60\x31\xdb\xca\xd3\xda\xd9\xaf\x0d\xcb\xaa\xaf\x26\x8c\xb8\xfc\xff\xea\xd9\x4f\x3c\x7c\xa4\x95\xe0\x56\xa9\xb4\x7a\xcd\xb7\x51\xfb\x73\xe6\x66\xc6\xc6\x55\xad\xe8\x29\x72\x97\xd0\x7a\xd1\xba\x5e\x43\xf1\xbc\xa3\x23\x01\x65\x13\x39\xe2\x29\x04\xcc\x8c\x42\xf5\x8c\x30\xc0\x4a\xaf\xdb\x03\x8d\xda\x08\x47\xdd\x98\x8d\xcd\xa6\xf3\xbf\xd1\x5c\x4b\x4c\x45\x25\x00\x4a\xa0\x6e\xef\xf8\xca\x61\x78\x3a\xac\xec\x57\xfb\x3d\x1f\x92\xb0\xfe\x2f\xd1\xa8\x5f\x67\x24\x51\x7b\x65\xe6\x14\xad\x68\x08\xd6\xf6\xee\x34\xdf\xf7\x31\x0f\xdc\x82\xae\xbf\xd9\x04\xb0\x1e\x1d\xc5\x4b\x29\x27\x09\x4b\x2d\xb6\x8d\x6f\x90\x3b\x68\x40\x1a\xde\xbf\x5a\x7e\x08\xd7\x8f\xf4\xef\x5d\x63\x65\x3a\x65\x04\x0c\xf9\xbf\xd4\xac\xa7\x98\x4a\x74\xd3\x71\x45\x98\x67\x80\xfc\x0b\x16\xac\x45\x16\x49\xde\x61\x88\xa7\xdb\xdf\x19\x1f\x64\xb5\xfc\x5e\x2a\xb4\x7b\x57\xf7\xf7\x27\x6c\xd4\x19\xc1\x7a\x3c\xa8\xe1\xb9\x39\xae\x49\xe4\x88\xac\xba\x6b\x96\x56\x10\xb5\x48\x01\x09\xc8\xb1\x7b\x80\xe1\xb7\xb7\x50\xdf\xc7\x59\x8d\x5d\x50\x11\xfd\x2d\xcc\x56\x00\xa3\x2e\xf5\xb5\x2a\x1e\xcc\x82\x0e\x30\x8a\xa3\x42\x72\x1a\xac\x09\x43\xbf\x66\x86\xb6\x4b\x25\x79\x37\x65\x04\xcc\xc4\x93\xd9\x7e\x6a\xed\x3f\xb0\xf9\xcd\x71\xa4\x3d\xd4\x97\xf0\x1f\x17\xc0\xe2\xcb\x37\x97\xaa\x2a\x2f\x25\x66\x56\x16\x8e\x6c\x49\x6a\xfc\x5f\xb9\x32\x46\xf6\xb1\x11\x63\x98\xa3\x46\xf1\xa6\x41\xf3\xb0\x41\xe9\x89\xf7\x91\x4f\x90\xcc\x2c\x7f\xff\x35\x78\x76\xe5\x06\xb5\x0d\x33\x4b\xa7\x7c\x22\x5b\xc3\x07\xba\x53\x71\x52\xf3\xf1\x61\x0e\x4e\xaf\xe5\x95\xf6\xd9\xd9\x0d\x11\xfa\xa9\x33\xa1\x5e\xf1\x36\x95\x46\x86\x8a\x7f\x3a\x45\xa9\x67\x68\xd4\x0f\xd9\xd0\x34\x12\xc0\x91\xc6\x31\x5c\xf4\xfd\xe7\xcb\x68\x60\x69\x37\x38\x0d\xb2\xea\xaa\x70\x7b\x4c\x41\x85\xc3\x2e\xdd\xcd\xd3\x06\x70\x5e\x4d\xc1\xff\xc8\x72\xee\xee\x47\x5a\x64\xdf\xac\x86\xab\xa4\x1c\x06\x18\x98\x3f\x87\x41\xc5\xef\x68\xd3\xa1\x01\xe8\xa3\xb8\xca\xc6\x0c\x90\x5c\x15\xfc\x91\x08\x40\xb9\x4c\x00\xa0\xb9\xd0"}, diff --git a/external/ed25519-donna/test-internals.c b/external/ed25519-donna/test-internals.c deleted file mode 100644 index 3c67df516e..0000000000 --- a/external/ed25519-donna/test-internals.c +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include "ed25519-donna.h" - -static int -test_adds() { -#if defined(HAVE_UINT128) && !defined(ED25519_SSE2) - /* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */ - static const bignum25519 max_bignum = { - 0x7ffffffffffff,0x8000000001230,0x7ffffffffffff,0x7ffffffffffff,0x7ffffffffffff - }; - - /* what max_bignum should fully reduce to */ - static const unsigned char max_bignum_raw[32] = { - 0x12,0x00,0x00,0x00,0x00,0x00,0x88,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - - /* (max_bignum + max_bignum)^2 */ - static const unsigned char max_bignum2_squared_raw[32] = { - 0x10,0x05,0x00,0x00,0x00,0x00,0x80,0xdc,0x51,0x00,0x00,0x00,0x00,0x61,0xed,0x4a, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - /* ((max_bignum + max_bignum) + max_bignum)^2 */ - static const unsigned char max_bignum3_squared_raw[32] = { - 0x64,0x0b,0x00,0x00,0x00,0x00,0x20,0x30,0xb8,0x00,0x00,0x00,0x40,0x1a,0x96,0xe8, - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; -#else - /* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */ - static const bignum25519 ALIGN(16) max_bignum = { - 0x3ffffff,0x2000300,0x3ffffff,0x1ffffff,0x3ffffff, - 0x1ffffff,0x3ffffff,0x1ffffff,0x3ffffff,0x1ffffff - }; - - /* what max_bignum should fully reduce to */ - static const unsigned char max_bignum2_squared_raw[32] = { - 0x10,0x05,0x00,0x40,0xc2,0x06,0x40,0x80,0x41,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - /* (max_bignum * max_bignum) */ - static const unsigned char max_bignum3_squared_raw[32] = { - 0x64,0x0b,0x00,0x10,0x35,0x0f,0x90,0x60,0x13,0x05,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; -#endif - unsigned char result[32]; - static const bignum25519 ALIGN(16) zero = {0}; - bignum25519 ALIGN(16) a, b, c; - size_t i; - - /* a = (max_bignum + max_bignum) */ - curve25519_add(a, max_bignum, max_bignum); - - /* b = ((max_bignum + max_bignum) * (max_bignum + max_bignum)) */ - curve25519_mul(b, a, a); - curve25519_contract(result, b); - if (memcmp(result, max_bignum2_squared_raw, 32) != 0) - return -1; - curve25519_square(b, a); - curve25519_contract(result, b); - if (memcmp(result, max_bignum2_squared_raw, 32) != 0) - return -1; - - /* b = (max_bignum + max_bignum + max_bignum) */ - curve25519_add_after_basic(b, a, max_bignum); - - /* a = ((max_bignum + max_bignum + max_bignum) * (max_bignum + max_bignum + max_bignum)) */ - curve25519_mul(a, b, b); - curve25519_contract(result, a); - if (memcmp(result, max_bignum3_squared_raw, 32) != 0) - return -1; - curve25519_square(a, b); - curve25519_contract(result, a); - if (memcmp(result, max_bignum3_squared_raw, 32) != 0) - return -1; - - return 0; -} - -static int -test_subs() { -#if defined(HAVE_UINT128) && !defined(ED25519_SSE2) - /* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */ - static const bignum25519 max_bignum = { - 0x7ffffffffffff,0x8000000001230,0x7ffffffffffff,0x7ffffffffffff,0x7ffffffffffff - }; - - /* what max_bignum should fully reduce to */ - static const unsigned char max_bignum_raw[32] = { - 0x12,0x00,0x00,0x00,0x00,0x00,0x88,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - - /* (max_bignum * max_bignum) */ - static const unsigned char max_bignum_squared_raw[32] = { - 0x44,0x01,0x00,0x00,0x00,0x00,0x20,0x77,0x14,0x00,0x00,0x00,0x40,0x58,0xbb,0x52, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; -#else - /* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */ - static const bignum25519 ALIGN(16) max_bignum = { - 0x3ffffff,0x2000300,0x3ffffff,0x1ffffff,0x3ffffff, - 0x1ffffff,0x3ffffff,0x1ffffff,0x3ffffff,0x1ffffff - }; - - /* what max_bignum should fully reduce to */ - static const unsigned char max_bignum_raw[32] = { - 0x12,0x00,0x00,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - /* (max_bignum * max_bignum) */ - static const unsigned char max_bignum_squared_raw[32] = { - 0x44,0x01,0x00,0x90,0xb0,0x01,0x10,0x60,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; -#endif - unsigned char result[32]; - static const bignum25519 ALIGN(16) zero = {0}; - bignum25519 ALIGN(16) a, b, c; - size_t i; - - /* a = max_bignum - 0, which expands to 2p + max_bignum - 0 */ - curve25519_sub(a, max_bignum, zero); - curve25519_contract(result, a); - if (memcmp(result, max_bignum_raw, 32) != 0) - return -1; - - /* b = (max_bignum * max_bignum) */ - curve25519_mul(b, a, a); - curve25519_contract(result, b); - if (memcmp(result, max_bignum_squared_raw, 32) != 0) - return -1; - curve25519_square(b, a); - curve25519_contract(result, b); - if (memcmp(result, max_bignum_squared_raw, 32) != 0) - return -1; - - /* b = ((a - 0) - 0) */ - curve25519_sub_after_basic(b, a, zero); - curve25519_contract(result, b); - if (memcmp(result, max_bignum_raw, 32) != 0) - return -1; - - /* a = (max_bignum * max_bignum) */ - curve25519_mul(a, b, b); - curve25519_contract(result, a); - if (memcmp(result, max_bignum_squared_raw, 32) != 0) - return -1; - curve25519_square(a, b); - curve25519_contract(result, a); - if (memcmp(result, max_bignum_squared_raw, 32) != 0) - return -1; - - - return 0; -} - - -int -main() { - int ret = 0; - int single; - single = test_adds(); - if (single) printf("test_adds: FAILED\n"); - ret |= single; - single = test_subs(); - if (single) printf("test_subs: FAILED\n"); - ret |= single; - if (!ret) printf("success\n"); - return ret; -} - - diff --git a/external/ed25519-donna/test-ticks.h b/external/ed25519-donna/test-ticks.h deleted file mode 100644 index 0103e03dde..0000000000 --- a/external/ed25519-donna/test-ticks.h +++ /dev/null @@ -1,50 +0,0 @@ -#include "ed25519-donna-portable-identify.h" - -/* ticks - not tested on anything other than x86 */ -static uint64_t -get_ticks(void) { -#if defined(CPU_X86) || defined(CPU_X86_64) - #if defined(COMPILER_INTEL) - return _rdtsc(); - #elif defined(COMPILER_MSVC) - return __rdtsc(); - #elif defined(COMPILER_GCC) - uint32_t lo, hi; - __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); - return ((uint64_t)lo | ((uint64_t)hi << 32)); - #else - need rdtsc for this compiler - #endif -#elif defined(OS_SOLARIS) - return (uint64_t)gethrtime(); -#elif defined(CPU_SPARC) && !defined(OS_OPENBSD) - uint64_t t; - __asm__ __volatile__("rd %%tick, %0" : "=r" (t)); - return t; -#elif defined(CPU_PPC) - uint32_t lo = 0, hi = 0; - __asm__ __volatile__("mftbu %0; mftb %1" : "=r" (hi), "=r" (lo)); - return ((uint64_t)lo | ((uint64_t)hi << 32)); -#elif defined(CPU_IA64) - uint64_t t; - __asm__ __volatile__("mov %0=ar.itc" : "=r" (t)); - return t; -#elif defined(OS_NIX) - timeval t2; - gettimeofday(&t2, NULL); - t = ((uint64_t)t2.tv_usec << 32) | (uint64_t)t2.tv_sec; - return t; -#else - need ticks for this platform -#endif -} - -#define timeit(x,minvar) \ - ticks = get_ticks(); \ - x; \ - ticks = get_ticks() - ticks; \ - if (ticks < minvar) \ - minvar = ticks; - -#define maxticks 0xffffffffffffffffull - diff --git a/external/ed25519-donna/test.c b/external/ed25519-donna/test.c deleted file mode 100644 index 6154492503..0000000000 --- a/external/ed25519-donna/test.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - Validate ed25519 implementation against the official test vectors from - http://ed25519.cr.yp.to/software.html -*/ - -#include -#include -#include "ed25519.h" - -#include "test-ticks.h" - -static void -edassert(int check, int round, const char *failreason) { - if (check) - return; - printf("round %d, %s\n", round, failreason); - exit(1); -} - -static void -edassert_die(const unsigned char *a, const unsigned char *b, size_t len, int round, const char *failreason) { - size_t i; - if (round > 0) - printf("round %d, %s\n", round, failreason); - else - printf("%s\n", failreason); - printf("want: "); for (i = 0; i < len; i++) printf("%02x,", a[i]); printf("\n"); - printf("got : "); for (i = 0; i < len; i++) printf("%02x,", b[i]); printf("\n"); - printf("diff: "); for (i = 0; i < len; i++) if (a[i] ^ b[i]) printf("%02x,", a[i] ^ b[i]); else printf(" ,"); printf("\n\n"); - exit(1); -} - -static void -edassert_equal(const unsigned char *a, const unsigned char *b, size_t len, const char *failreason) { - if (memcmp(a, b, len) == 0) - return; - edassert_die(a, b, len, -1, failreason); -} - -static void -edassert_equal_round(const unsigned char *a, const unsigned char *b, size_t len, int round, const char *failreason) { - if (memcmp(a, b, len) == 0) - return; - edassert_die(a, b, len, round, failreason); -} - - -/* test data */ -typedef struct test_data_t { - unsigned char sk[32], pk[32], sig[64]; - const char *m; -} test_data; - - -test_data dataset[] = { -#include "regression.h" -}; - -/* result of the curve25519 scalarmult ((|255| * basepoint) * basepoint)... 1024 times */ -const curved25519_key curved25519_expected = { - 0xac,0xce,0x24,0xb1,0xd4,0xa2,0x36,0x21, - 0x15,0xe2,0x3e,0x84,0x3c,0x23,0x2b,0x5f, - 0x95,0x6c,0xc0,0x7b,0x95,0x82,0xd7,0x93, - 0xd5,0x19,0xb6,0xf1,0xfb,0x96,0xd6,0x04 -}; - - -/* from ed25519-donna-batchverify.h */ -extern unsigned char batch_point_buffer[3][32]; - -/* y coordinate of the final point from 'amd64-51-30k' with the same random generator */ -static const unsigned char batch_verify_y[32] = { - 0x51,0xe7,0x68,0xe0,0xf7,0xa1,0x88,0x45, - 0xde,0xa1,0xcb,0xd9,0x37,0xd4,0x78,0x53, - 0x1b,0x95,0xdb,0xbe,0x66,0x59,0x29,0x3b, - 0x94,0x51,0x2f,0xbc,0x0d,0x66,0xba,0x3f -}; - -/* -static const unsigned char batch_verify_y[32] = { - 0x5c,0x63,0x96,0x26,0xca,0xfe,0xfd,0xc4, - 0x2d,0x11,0xa8,0xe4,0xc4,0x46,0x42,0x97, - 0x97,0x92,0xbe,0xe0,0x3c,0xef,0x96,0x01, - 0x50,0xa1,0xcc,0x8f,0x50,0x85,0x76,0x7d -}; - -Introducing the 128 bit r scalars to the heap _before_ the largest scalar -fits in to 128 bits alters the heap shape and produces a different, -yet still neutral/valid y/z value. - -This was the value of introducing the r scalars when the largest scalar fit -in to 135-256 bits. You can produce it with amd64-64-24k / amd64-51-32k -with the random sequence used in the first pass by changing - - unsigned long long hlen=((npoints+1)/2)|1; - -to - - unsigned long long hlen=npoints; - -in ge25519_multi_scalarmult.c - -ed25519-donna-batchverify.h has been modified to match the -default amd64-64-24k / amd64-51-32k behaviour -*/ - - - -/* batch test */ -#define test_batch_count 64 -#define test_batch_rounds 96 - -typedef enum batch_test_t { - batch_no_errors = 0, - batch_wrong_message = 1, - batch_wrong_pk = 2, - batch_wrong_sig = 3 -} batch_test; - -static int -test_batch_instance(batch_test type, uint64_t *ticks) { - ed25519_secret_key sks[test_batch_count]; - ed25519_public_key pks[test_batch_count]; - ed25519_signature sigs[test_batch_count]; - unsigned char messages[test_batch_count][128]; - size_t message_lengths[test_batch_count]; - const unsigned char *message_pointers[test_batch_count]; - const unsigned char *pk_pointers[test_batch_count]; - const unsigned char *sig_pointers[test_batch_count]; - int valid[test_batch_count], ret, validret; - size_t i; - uint64_t t; - - /* generate keys */ - for (i = 0; i < test_batch_count; i++) { - ed25519_randombytes_unsafe(sks[i], sizeof(sks[i])); - ed25519_publickey(sks[i], pks[i]); - pk_pointers[i] = pks[i]; - } - - /* generate messages */ - ed25519_randombytes_unsafe(messages, sizeof(messages)); - for (i = 0; i < test_batch_count; i++) { - message_pointers[i] = messages[i]; - message_lengths[i] = (i & 127) + 1; - } - - /* sign messages */ - for (i = 0; i < test_batch_count; i++) { - ed25519_sign(message_pointers[i], message_lengths[i], sks[i], pks[i], sigs[i]); - sig_pointers[i] = sigs[i]; - } - - validret = 0; - if (type == batch_wrong_message) { - message_pointers[0] = message_pointers[1]; - validret = 1|2; - } else if (type == batch_wrong_pk) { - pk_pointers[0] = pk_pointers[1]; - validret = 1|2; - } else if (type == batch_wrong_sig) { - sig_pointers[0] = sig_pointers[1]; - validret = 1|2; - } - - /* batch verify */ - t = get_ticks(); - ret = ed25519_sign_open_batch(message_pointers, message_lengths, pk_pointers, sig_pointers, test_batch_count, valid); - *ticks = get_ticks() - t; - edassert_equal((unsigned char *)&validret, (unsigned char *)&ret, sizeof(int), "batch return code"); - for (i = 0; i < test_batch_count; i++) { - validret = ((type == batch_no_errors) || (i != 0)) ? 1 : 0; - edassert_equal((unsigned char *)&validret, (unsigned char *)&valid[i], sizeof(int), "individual batch return code"); - } - return ret; -} - -static void -test_batch(void) { - uint64_t dummy_ticks, ticks[test_batch_rounds], best = maxticks, sum; - size_t i, count; - - /* check the first pass for the expected result */ - test_batch_instance(batch_no_errors, &dummy_ticks); - edassert_equal(batch_verify_y, batch_point_buffer[1], 32, "failed to generate expected result"); - - /* make sure ge25519_multi_scalarmult_vartime throws an error on the entire batch with wrong data */ - for (i = 0; i < 4; i++) { - test_batch_instance(batch_wrong_message, &dummy_ticks); - test_batch_instance(batch_wrong_pk, &dummy_ticks); - test_batch_instance(batch_wrong_sig, &dummy_ticks); - } - - /* speed test */ - for (i = 0; i < test_batch_rounds; i++) { - test_batch_instance(batch_no_errors, &ticks[i]); - if (ticks[i] < best) - best = ticks[i]; - } - - /* take anything within 1% of the best time */ - for (i = 0, sum = 0, count = 0; i < test_batch_rounds; i++) { - if (ticks[i] < (best * 1.01)) { - sum += ticks[i]; - count++; - } - } - printf("%.0f ticks/verification\n", (double)sum / (count * test_batch_count)); -} - -static void -test_main(void) { - int i, res; - ed25519_public_key pk; - ed25519_signature sig; - unsigned char forge[1024] = {'x'}; - curved25519_key csk[2] = {{255}}; - uint64_t ticks, pkticks = maxticks, signticks = maxticks, openticks = maxticks, curvedticks = maxticks; - - for (i = 0; i < 1024; i++) { - ed25519_publickey(dataset[i].sk, pk); - edassert_equal_round(dataset[i].pk, pk, sizeof(pk), i, "public key didn't match"); - ed25519_sign((unsigned char *)dataset[i].m, i, dataset[i].sk, pk, sig); - edassert_equal_round(dataset[i].sig, sig, sizeof(sig), i, "signature didn't match"); - edassert(!ed25519_sign_open((unsigned char *)dataset[i].m, i, pk, sig), i, "failed to open message"); - - memcpy(forge, dataset[i].m, i); - if (i) - forge[i - 1] += 1; - - edassert(ed25519_sign_open(forge, (i) ? i : 1, pk, sig), i, "opened forged message"); - } - - for (i = 0; i < 1024; i++) - curved25519_scalarmult_basepoint(csk[(i & 1) ^ 1], csk[i & 1]); - edassert_equal(curved25519_expected, csk[0], sizeof(curved25519_key), "curve25519 failed to generate correct value"); - - for (i = 0; i < 2048; i++) { - timeit(ed25519_publickey(dataset[0].sk, pk), pkticks) - edassert_equal_round(dataset[0].pk, pk, sizeof(pk), i, "public key didn't match"); - timeit(ed25519_sign((unsigned char *)dataset[0].m, 0, dataset[0].sk, pk, sig), signticks) - edassert_equal_round(dataset[0].sig, sig, sizeof(sig), i, "signature didn't match"); - timeit(res = ed25519_sign_open((unsigned char *)dataset[0].m, 0, pk, sig), openticks) - edassert(!res, 0, "failed to open message"); - timeit(curved25519_scalarmult_basepoint(csk[1], csk[0]), curvedticks); - } - - printf("%.0f ticks/public key generation\n", (double)pkticks); - printf("%.0f ticks/signature\n", (double)signticks); - printf("%.0f ticks/signature verification\n", (double)openticks); - printf("%.0f ticks/curve25519 basepoint scalarmult\n", (double)curvedticks); -} - -int -main(void) { - test_main(); - test_batch(); - return 0; -} - diff --git a/external/secp256k1/.cirrus.yml b/external/secp256k1/.cirrus.yml deleted file mode 100644 index 81a4f04328..0000000000 --- a/external/secp256k1/.cirrus.yml +++ /dev/null @@ -1,101 +0,0 @@ -env: - ### cirrus config - CIRRUS_CLONE_DEPTH: 1 - ### compiler options - HOST: - WRAPPER_CMD: - # Specific warnings can be disabled with -Wno-error=foo. - # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. - WERROR_CFLAGS: -Werror -pedantic-errors - MAKEFLAGS: -j4 - BUILD: check - ### secp256k1 config - ECMULTWINDOW: 15 - ECMULTGENKB: 22 - ASM: no - WIDEMUL: auto - WITH_VALGRIND: yes - EXTRAFLAGS: - ### secp256k1 modules - EXPERIMENTAL: no - ECDH: no - RECOVERY: no - EXTRAKEYS: no - SCHNORRSIG: no - MUSIG: no - ELLSWIFT: no - ### test options - SECP256K1_TEST_ITERS: 64 - BENCH: yes - SECP256K1_BENCH_ITERS: 2 - CTIMETESTS: yes - # Compile and run the tests - EXAMPLES: yes - -cat_logs_snippet: &CAT_LOGS - always: - cat_tests_log_script: - - cat tests.log || true - cat_noverify_tests_log_script: - - cat noverify_tests.log || true - cat_exhaustive_tests_log_script: - - cat exhaustive_tests.log || true - cat_ctime_tests_log_script: - - cat ctime_tests.log || true - cat_bench_log_script: - - cat bench.log || true - cat_config_log_script: - - cat config.log || true - cat_test_env_script: - - cat test_env.log || true - cat_ci_env_script: - - env - -linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER - env_script: - - env | tee /tmp/env - build_script: - - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" - - docker image prune --force # Cleanup stale layers - test_script: - - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh" - -task: - name: "ARM64: Linux (Debian stable)" - persistent_worker: - labels: - type: arm64 - env: - ECDH: yes - RECOVERY: yes - EXTRAKEYS: yes - SCHNORRSIG: yes - MUSIG: yes - ELLSWIFT: yes - matrix: - # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU - - env: { CC: 'gcc-snapshot' } - << : *LINUX_ARM64_CONTAINER - << : *CAT_LOGS - -task: - name: "ARM64: Linux (Debian stable), Valgrind" - persistent_worker: - labels: - type: arm64 - env: - ECDH: yes - RECOVERY: yes - EXTRAKEYS: yes - SCHNORRSIG: yes - MUSIG: yes - ELLSWIFT: yes - WRAPPER_CMD: 'valgrind --error-exitcode=42' - SECP256K1_TEST_ITERS: 2 - matrix: - - env: { CC: 'gcc' } - - env: { CC: 'clang' } - - env: { CC: 'gcc-snapshot' } - - env: { CC: 'clang-snapshot' } - << : *LINUX_ARM64_CONTAINER - << : *CAT_LOGS diff --git a/external/secp256k1/.gitattributes b/external/secp256k1/.gitattributes deleted file mode 100644 index 30efb2244f..0000000000 --- a/external/secp256k1/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -src/precomputed_ecmult.c linguist-generated -src/precomputed_ecmult_gen.c linguist-generated diff --git a/external/secp256k1/.gitignore b/external/secp256k1/.gitignore deleted file mode 100644 index bffba8cb2c..0000000000 --- a/external/secp256k1/.gitignore +++ /dev/null @@ -1,67 +0,0 @@ -bench -bench_ecmult -bench_internal -noverify_tests -tests -exhaustive_tests -precompute_ecmult_gen -precompute_ecmult -ctime_tests -ecdh_example -ecdsa_example -schnorr_example -ellswift_example -musig_example -*.exe -*.so -*.a -*.csv -*.log -*.trs -*.sage.py - -Makefile -configure -.libs/ -Makefile.in -aclocal.m4 -autom4te.cache/ -config.log -config.status -conftest* -*.tar.gz -*.la -libtool -.deps/ -.dirstamp -*.lo -*.o -*~ - -coverage/ -coverage.html -coverage.*.html -*.gcda -*.gcno -*.gcov - -build-aux/ar-lib -build-aux/config.guess -build-aux/config.sub -build-aux/depcomp -build-aux/install-sh -build-aux/ltmain.sh -build-aux/m4/libtool.m4 -build-aux/m4/lt~obsolete.m4 -build-aux/m4/ltoptions.m4 -build-aux/m4/ltsugar.m4 -build-aux/m4/ltversion.m4 -build-aux/missing -build-aux/compile -build-aux/test-driver -libsecp256k1.pc - -### CMake -/CMakeUserPresets.json -# Default CMake build directory. -/build diff --git a/external/secp256k1/CHANGELOG.md b/external/secp256k1/CHANGELOG.md deleted file mode 100644 index ee447c0c1c..0000000000 --- a/external/secp256k1/CHANGELOG.md +++ /dev/null @@ -1,174 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.6.0] - 2024-11-04 - -#### Added - - New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See: - - Header file `include/secp256k1_musig.h` which defines the new API. - - Document `doc/musig.md` for further notes on API usage. - - Usage example `examples/musig.c`. - - New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. - -#### Changed - - API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal. - - Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++). - - Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility. - -#### Removed - - Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API. - -#### ABI Compatibility -The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed. -Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x. - -## [0.5.1] - 2024-08-01 - -#### Added - - Added usage example for an ElligatorSwift key exchange. - -#### Changed - - The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). - - "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly. - -#### Fixed - - Fixed compilation when the extrakeys module is disabled. - -#### ABI Compatibility -The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. - -## [0.5.0] - 2024-05-06 - -#### Added - - New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order. - -#### Changed - - The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations. - - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). - - This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB). - -#### ABI Compatibility -The ABI is backward compatible with versions 0.4.x and 0.3.x. - -## [0.4.1] - 2023-12-21 - -#### Changed - - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one. - - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`. - -#### ABI Compatibility -The ABI is backward compatible with versions 0.4.0 and 0.3.x. - -## [0.4.0] - 2023-09-04 - -#### Added - - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. - ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See: - - Header file `include/secp256k1_ellswift.h` which defines the new API. - - Document `doc/ellswift.md` which explains the mathematical background of the scheme. - - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. - - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). - -#### Fixed - - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. - -#### Changed - - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. - -#### ABI Compatibility -This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. - -## [0.3.2] - 2023-05-13 -We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. - -#### Security - - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. - -#### Fixed - - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. - -#### Changed - - Various improvements and changes to CMake builds. CMake builds remain experimental. - - Made API versioning consistent with GNU Autotools builds. - - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. - - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. - - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). - -#### ABI Compatibility -The ABI is compatible with versions 0.3.0 and 0.3.1. - -## [0.3.1] - 2023-04-10 -We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. - -#### Security - - Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14. - -#### Added - - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases. - -#### Changed - - Increased minimum required CMake version to 3.13. CMake builds remain experimental. - -#### ABI Compatibility -The ABI is compatible with version 0.3.0. - -## [0.3.0] - 2023-03-08 - -#### Added - - Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported. - - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory. - - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target. - -#### Fixed - - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning. - -#### Changed - - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) - - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. - -#### Removed - - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags). - -#### ABI Compatibility -Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions. - -## [0.2.0] - 2022-12-12 - -#### Added - - Added usage examples for common use cases in a new `examples/` directory. - - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. - - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. - -#### Changed - - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`. - - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API. - -#### Deprecated - - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. - - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. - - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. - -#### ABI Compatibility -Since this is the first release, we do not compare application binary interfaces. -However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. - -## [0.1.0] - 2013-03-05 to 2021-12-25 - -This version was in fact never released. -The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). -Therefore, this version number does not uniquely identify a set of source files. - -[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0 -[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 -[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0 -[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 -[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 -[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 -[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 -[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 -[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0 -[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93 diff --git a/external/secp256k1/CMakeLists.txt b/external/secp256k1/CMakeLists.txt deleted file mode 100644 index 041bfa3dca..0000000000 --- a/external/secp256k1/CMakeLists.txt +++ /dev/null @@ -1,405 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -#============================= -# Project / Package metadata -#============================= -project(libsecp256k1 - # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of - # the API. All changes in experimental modules are treated as - # backwards-compatible and therefore at most increase the minor version. - VERSION 0.6.0 - DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." - HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" - LANGUAGES C -) -enable_testing() -list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) - -if(CMAKE_VERSION VERSION_LESS 3.21) - # Emulates CMake 3.21+ behavior. - if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(PROJECT_IS_TOP_LEVEL ON) - set(${PROJECT_NAME}_IS_TOP_LEVEL ON) - else() - set(PROJECT_IS_TOP_LEVEL OFF) - set(${PROJECT_NAME}_IS_TOP_LEVEL OFF) - endif() -endif() - -# The library version is based on libtool versioning of the ABI. The set of -# rules for updating the version can be found here: -# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -# All changes in experimental modules are treated as if they don't affect the -# interface and therefore only increase the revision. -set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 0) -set(${PROJECT_NAME}_LIB_VERSION_AGE 0) - -#============================= -# Language setup -#============================= -set(CMAKE_C_STANDARD 90) -set(CMAKE_C_EXTENSIONS OFF) - -#============================= -# Configurable options -#============================= -option(BUILD_SHARED_LIBS "Build shared libraries." ON) -option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) -if(SECP256K1_DISABLE_SHARED) - set(BUILD_SHARED_LIBS OFF) -endif() - -option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) - -## Modules - -# We declare all options before processing them, to make sure we can express -# dependendencies while processing. -option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) -option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) -option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) -option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) -option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON) -option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) - -# Processing must be done in a topological sorting of the dependency graph -# (dependent module first). -if(SECP256K1_ENABLE_MODULE_ELLSWIFT) - add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) -endif() - -if(SECP256K1_ENABLE_MODULE_MUSIG) - if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG) - message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.") - endif() - set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) - add_compile_definitions(ENABLE_MODULE_MUSIG=1) -endif() - -if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) - message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.") - endif() - set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) - add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) -endif() - -if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) - add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) -endif() - -if(SECP256K1_ENABLE_MODULE_RECOVERY) - add_compile_definitions(ENABLE_MODULE_RECOVERY=1) -endif() - -if(SECP256K1_ENABLE_MODULE_ECDH) - add_compile_definitions(ENABLE_MODULE_ECDH=1) -endif() - -option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) -if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) - add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) -endif() - -set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]") -set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) -include(CheckStringOptionValue) -check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) -add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) - -set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]") -set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86) -check_string_option_value(SECP256K1_ECMULT_GEN_KB) -if(SECP256K1_ECMULT_GEN_KB EQUAL 2) - add_compile_definitions(COMB_BLOCKS=2) - add_compile_definitions(COMB_TEETH=5) -elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22) - add_compile_definitions(COMB_BLOCKS=11) - add_compile_definitions(COMB_TEETH=6) -elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86) - add_compile_definitions(COMB_BLOCKS=43) - add_compile_definitions(COMB_TEETH=6) -endif() - -set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") -set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") -check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) -if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) - string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) - add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1) -endif() -mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) - -set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") -set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") -check_string_option_value(SECP256K1_ASM) -if(SECP256K1_ASM STREQUAL "arm32") - enable_language(ASM) - include(CheckArm32Assembly) - check_arm32_assembly() - if(HAVE_ARM32_ASM) - add_compile_definitions(USE_EXTERNAL_ASM=1) - else() - message(FATAL_ERROR "ARM32 assembly requested but not available.") - endif() -elseif(SECP256K1_ASM) - include(CheckX86_64Assembly) - check_x86_64_assembly() - if(HAVE_X86_64_ASM) - set(SECP256K1_ASM "x86_64") - add_compile_definitions(USE_ASM_X86_64=1) - elseif(SECP256K1_ASM STREQUAL "AUTO") - set(SECP256K1_ASM "OFF") - else() - message(FATAL_ERROR "x86_64 assembly requested but not available.") - endif() -endif() - -option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) -if(NOT SECP256K1_EXPERIMENTAL) - if(SECP256K1_ASM STREQUAL "arm32") - message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") - endif() -endif() - -set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]") -set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON") -check_string_option_value(SECP256K1_VALGRIND) -if(SECP256K1_VALGRIND) - find_package(Valgrind MODULE) - if(Valgrind_FOUND) - set(SECP256K1_VALGRIND ON) - include_directories(${Valgrind_INCLUDE_DIR}) - add_compile_definitions(VALGRIND) - elseif(SECP256K1_VALGRIND STREQUAL "AUTO") - set(SECP256K1_VALGRIND OFF) - else() - message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.") - endif() -endif() - -option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) -option(SECP256K1_BUILD_TESTS "Build tests." ON) -option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) -option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) -option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) - -# Redefine configuration flags. -# We leave assertions on, because they are only used in the examples, and we want them always on there. -if(MSVC) - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") -else() - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") - # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) - string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") -endif() - -# Define custom "Coverage" build type. -set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING - "Flags used by the C compiler during \"Coverage\" builds." - FORCE -) -set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING - "Flags used for linking binaries during \"Coverage\" builds." - FORCE -) -set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING - "Flags used by the shared libraries linker during \"Coverage\" builds." - FORCE -) -mark_as_advanced( - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE -) - -if(PROJECT_IS_TOP_LEVEL) - get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - set(default_build_type "RelWithDebInfo") - if(is_multi_config) - set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING - "Supported configuration types." - FORCE - ) - else() - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY - STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" - ) - if(NOT CMAKE_BUILD_TYPE) - message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING - "Choose the type of build." - FORCE - ) - endif() - endif() -endif() - -include(TryAppendCFlags) -if(MSVC) - # Keep the following commands ordered lexicographically. - try_append_c_flags(/W3) # Production quality warning level. - try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". - try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". - try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". - # Eliminate deprecation warnings for the older, less secure functions. - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) -else() - # Keep the following commands ordered lexicographically. - try_append_c_flags(-pedantic) - try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. - try_append_c_flags(-Wcast-align) # GCC >= 2.95. - try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. - try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. - try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. - try_append_c_flags(-Wnested-externs) - try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. - try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. - try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall. - try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. - try_append_c_flags(-Wshadow) - try_append_c_flags(-Wstrict-prototypes) - try_append_c_flags(-Wundef) -endif() - -set(CMAKE_C_VISIBILITY_PRESET hidden) - -set(print_msan_notice) -if(SECP256K1_BUILD_CTIME_TESTS) - include(CheckMemorySanitizer) - check_memory_sanitizer(msan_enabled) - if(msan_enabled) - try_append_c_flags(-fno-sanitize-memory-param-retval) - set(print_msan_notice YES) - endif() - unset(msan_enabled) -endif() - -set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") -if(SECP256K1_APPEND_CFLAGS) - # Appending to this low-level rule variable is the only way to - # guarantee that the flags appear at the end of the command line. - string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}") -endif() - -set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") -if(SECP256K1_APPEND_LDFLAGS) - # Appending to this low-level rule variable is the only way to - # guarantee that the flags appear at the end of the command line. - string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}") - string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") -endif() - -if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) -endif() -if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) -endif() -if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) -endif() -add_subdirectory(src) -if(SECP256K1_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() - -message("\n") -message("secp256k1 configure summary") -message("===========================") -message("Build artifacts:") -if(BUILD_SHARED_LIBS) - set(library_type "Shared") -else() - set(library_type "Static") -endif() - -message(" library type ........................ ${library_type}") -message("Optional modules:") -message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") -message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") -message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") -message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") -message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") -message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") -message("Parameters:") -message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") -message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB") -message("Optional features:") -message(" assembly ............................ ${SECP256K1_ASM}") -message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") -if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) - message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") -endif() -message("Optional binaries:") -message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") -message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") -set(tests_status "${SECP256K1_BUILD_TESTS}") -if(CMAKE_BUILD_TYPE STREQUAL "Coverage") - set(tests_status OFF) -endif() -message(" tests ............................... ${tests_status}") -message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}") -message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}") -message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}") -message("") -if(CMAKE_CROSSCOMPILING) - set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") -else() - set(cross_status "FALSE") -endif() -message("Cross compiling ....................... ${cross_status}") -message("Valgrind .............................. ${SECP256K1_VALGRIND}") -get_directory_property(definitions COMPILE_DEFINITIONS) -string(REPLACE ";" " " definitions "${definitions}") -message("Preprocessor defined macros ........... ${definitions}") -message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") -message("CFLAGS ................................ ${CMAKE_C_FLAGS}") -get_directory_property(compile_options COMPILE_OPTIONS) -string(REPLACE ";" " " compile_options "${compile_options}") -message("Compile options ....................... " ${compile_options}) -if(NOT is_multi_config) - message("Build type:") - message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") - string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") -else() - message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") - message("RelWithDebInfo configuration:") - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") - message("Debug configuration:") - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") -endif() -if(SECP256K1_APPEND_CFLAGS) - message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}") -endif() -if(SECP256K1_APPEND_LDFLAGS) - message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}") -endif() -message("") -if(print_msan_notice) - message( - "Note:\n" - " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" - " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" - ) -endif() -if(SECP256K1_EXPERIMENTAL) - message( - " ******\n" - " WARNING: experimental build\n" - " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n" - " ******\n" - ) -endif() diff --git a/external/secp256k1/CMakePresets.json b/external/secp256k1/CMakePresets.json deleted file mode 100644 index b35cd80579..0000000000 --- a/external/secp256k1/CMakePresets.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, - "version": 3, - "configurePresets": [ - { - "name": "dev-mode", - "displayName": "Development mode (intended only for developers of the library)", - "cacheVariables": { - "SECP256K1_EXPERIMENTAL": "ON", - "SECP256K1_ENABLE_MODULE_RECOVERY": "ON", - "SECP256K1_BUILD_EXAMPLES": "ON" - }, - "warnings": { - "dev": true, - "uninitialized": true - } - } - ] -} diff --git a/external/secp256k1/CONTRIBUTING.md b/external/secp256k1/CONTRIBUTING.md deleted file mode 100644 index a366d38b0e..0000000000 --- a/external/secp256k1/CONTRIBUTING.md +++ /dev/null @@ -1,108 +0,0 @@ -# Contributing to libsecp256k1 - -## Scope - -libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library. -The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem. - -## Adding new functionality or modules - -The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope. - -It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable. -Contributors are recommended to provide the following in addition to the new code: - -* **Specification:** - A specification can help significantly in reviewing the new code as it provides documentation and context. - It may justify various design decisions, give a motivation and outline security goals. - If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. -* **Security Arguments:** - In addition to a defining the security goals, it should be argued that the new functionality meets these goals. - Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security. -* **Relevance Arguments:** - The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. - -These are not the only factors taken into account when considering to add new functionality. -The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design. - -We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality. - -## Communication channels - -Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board. - -Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic). -The channel is `#secp256k1` on Libera Chat. -The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1). -Chat history logs can be found at https://gnusha.org/secp256k1/. - -## Contributor workflow & peer review - -The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md). - -### Coding conventions - -In addition, libsecp256k1 tries to maintain the following coding conventions: - -* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations. -* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)). -* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). -* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. -* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). -* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)). - -#### Style conventions - -* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures. -* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting. -* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block: - ```C - void secp256k_foo(void) { - unsigned int x; /* declaration */ - int y = 2*x; /* declaration */ - x = 17; /* statement */ - { - int a, b; /* declaration */ - a = x + y; /* statement */ - secp256k_bar(x, &b); /* statement */ - } - } - ``` -* Use `unsigned int` instead of just `unsigned`. -* Use `void *ptr` instead of `void* ptr`. -* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h). -* User-facing comment lines in headers should be limited to 80 chars if possible. -* All identifiers in file scope should start with `secp256k1_`. -* Avoid trailing whitespace. - -### Tests - -#### Coverage - -This library aims to have full coverage of reachable lines and branches. - -To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): - - $ ./configure --enable-coverage - -Run the tests: - - $ make check - -To create a report, `gcovr` is recommended, as it includes branch coverage reporting: - - $ gcovr --exclude 'src/bench*' --print-summary - -To create a HTML report with coloured and annotated source code: - - $ mkdir -p coverage - $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html - -#### Exhaustive tests - -There are tests of several functions in which a small group replaces secp256k1. -These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)). - -### Benchmarks - -See `src/bench*.c` for examples of benchmarks. diff --git a/external/secp256k1/COPYING b/external/secp256k1/COPYING deleted file mode 100644 index 4522a5990e..0000000000 --- a/external/secp256k1/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Pieter Wuille - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/external/secp256k1/Makefile.am b/external/secp256k1/Makefile.am deleted file mode 100644 index a95b4809d4..0000000000 --- a/external/secp256k1/Makefile.am +++ /dev/null @@ -1,302 +0,0 @@ -ACLOCAL_AMFLAGS = -I build-aux/m4 - -# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo -# which does not have an explicit foo_CFLAGS variable set. -AM_CFLAGS = $(SECP_CFLAGS) - -lib_LTLIBRARIES = libsecp256k1.la -include_HEADERS = include/secp256k1.h -include_HEADERS += include/secp256k1_preallocated.h -noinst_HEADERS = -noinst_HEADERS += src/scalar.h -noinst_HEADERS += src/scalar_4x64.h -noinst_HEADERS += src/scalar_8x32.h -noinst_HEADERS += src/scalar_low.h -noinst_HEADERS += src/scalar_impl.h -noinst_HEADERS += src/scalar_4x64_impl.h -noinst_HEADERS += src/scalar_8x32_impl.h -noinst_HEADERS += src/scalar_low_impl.h -noinst_HEADERS += src/group.h -noinst_HEADERS += src/group_impl.h -noinst_HEADERS += src/ecdsa.h -noinst_HEADERS += src/ecdsa_impl.h -noinst_HEADERS += src/eckey.h -noinst_HEADERS += src/eckey_impl.h -noinst_HEADERS += src/ecmult.h -noinst_HEADERS += src/ecmult_impl.h -noinst_HEADERS += src/ecmult_compute_table.h -noinst_HEADERS += src/ecmult_compute_table_impl.h -noinst_HEADERS += src/ecmult_const.h -noinst_HEADERS += src/ecmult_const_impl.h -noinst_HEADERS += src/ecmult_gen.h -noinst_HEADERS += src/ecmult_gen_impl.h -noinst_HEADERS += src/ecmult_gen_compute_table.h -noinst_HEADERS += src/ecmult_gen_compute_table_impl.h -noinst_HEADERS += src/field_10x26.h -noinst_HEADERS += src/field_10x26_impl.h -noinst_HEADERS += src/field_5x52.h -noinst_HEADERS += src/field_5x52_impl.h -noinst_HEADERS += src/field_5x52_int128_impl.h -noinst_HEADERS += src/modinv32.h -noinst_HEADERS += src/modinv32_impl.h -noinst_HEADERS += src/modinv64.h -noinst_HEADERS += src/modinv64_impl.h -noinst_HEADERS += src/precomputed_ecmult.h -noinst_HEADERS += src/precomputed_ecmult_gen.h -noinst_HEADERS += src/assumptions.h -noinst_HEADERS += src/checkmem.h -noinst_HEADERS += src/testutil.h -noinst_HEADERS += src/util.h -noinst_HEADERS += src/int128.h -noinst_HEADERS += src/int128_impl.h -noinst_HEADERS += src/int128_native.h -noinst_HEADERS += src/int128_native_impl.h -noinst_HEADERS += src/int128_struct.h -noinst_HEADERS += src/int128_struct_impl.h -noinst_HEADERS += src/scratch.h -noinst_HEADERS += src/scratch_impl.h -noinst_HEADERS += src/selftest.h -noinst_HEADERS += src/testrand.h -noinst_HEADERS += src/testrand_impl.h -noinst_HEADERS += src/hash.h -noinst_HEADERS += src/hash_impl.h -noinst_HEADERS += src/field.h -noinst_HEADERS += src/field_impl.h -noinst_HEADERS += src/bench.h -noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h -noinst_HEADERS += src/hsort.h -noinst_HEADERS += src/hsort_impl.h -noinst_HEADERS += contrib/lax_der_parsing.h -noinst_HEADERS += contrib/lax_der_parsing.c -noinst_HEADERS += contrib/lax_der_privatekey_parsing.h -noinst_HEADERS += contrib/lax_der_privatekey_parsing.c -noinst_HEADERS += examples/examples_util.h - -PRECOMPUTED_LIB = libsecp256k1_precomputed.la -noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) -libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c -# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree. -# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). -libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES) - -if USE_EXTERNAL_ASM -COMMON_LIB = libsecp256k1_common.la -else -COMMON_LIB = -endif -noinst_LTLIBRARIES += $(COMMON_LIB) - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libsecp256k1.pc - -if USE_EXTERNAL_ASM -if USE_ASM_ARM -libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s -endif -endif - -libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES) -libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) -libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) - -noinst_PROGRAMS = -if USE_BENCHMARK -noinst_PROGRAMS += bench bench_internal bench_ecmult -bench_SOURCES = src/bench.c -bench_LDADD = libsecp256k1.la -bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) -bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES) -bench_ecmult_SOURCES = src/bench_ecmult.c -bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -endif - -TESTS = -if USE_TESTS -TESTS += noverify_tests -noinst_PROGRAMS += noverify_tests -noverify_tests_SOURCES = src/tests.c -noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) -noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) -noverify_tests_LDFLAGS = -static -if !ENABLE_COVERAGE -TESTS += tests -noinst_PROGRAMS += tests -tests_SOURCES = $(noverify_tests_SOURCES) -tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY -tests_LDADD = $(noverify_tests_LDADD) -tests_LDFLAGS = $(noverify_tests_LDFLAGS) -endif -endif - -if USE_CTIME_TESTS -noinst_PROGRAMS += ctime_tests -ctime_tests_SOURCES = src/ctime_tests.c -ctime_tests_LDADD = libsecp256k1.la -ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) -endif - -if USE_EXHAUSTIVE_TESTS -noinst_PROGRAMS += exhaustive_tests -exhaustive_tests_SOURCES = src/tests_exhaustive.c -exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) -if !ENABLE_COVERAGE -exhaustive_tests_CPPFLAGS += -DVERIFY -endif -# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). -exhaustive_tests_LDADD = $(COMMON_LIB) -exhaustive_tests_LDFLAGS = -static -TESTS += exhaustive_tests -endif - -if USE_EXAMPLES -noinst_PROGRAMS += ecdsa_example -ecdsa_example_SOURCES = examples/ecdsa.c -ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC -ecdsa_example_LDADD = libsecp256k1.la -ecdsa_example_LDFLAGS = -static -if BUILD_WINDOWS -ecdsa_example_LDFLAGS += -lbcrypt -endif -TESTS += ecdsa_example -if ENABLE_MODULE_ECDH -noinst_PROGRAMS += ecdh_example -ecdh_example_SOURCES = examples/ecdh.c -ecdh_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC -ecdh_example_LDADD = libsecp256k1.la -ecdh_example_LDFLAGS = -static -if BUILD_WINDOWS -ecdh_example_LDFLAGS += -lbcrypt -endif -TESTS += ecdh_example -endif -if ENABLE_MODULE_SCHNORRSIG -noinst_PROGRAMS += schnorr_example -schnorr_example_SOURCES = examples/schnorr.c -schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC -schnorr_example_LDADD = libsecp256k1.la -schnorr_example_LDFLAGS = -static -if BUILD_WINDOWS -schnorr_example_LDFLAGS += -lbcrypt -endif -TESTS += schnorr_example -endif -if ENABLE_MODULE_ELLSWIFT -noinst_PROGRAMS += ellswift_example -ellswift_example_SOURCES = examples/ellswift.c -ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC -ellswift_example_LDADD = libsecp256k1.la -ellswift_example_LDFLAGS = -static -if BUILD_WINDOWS -ellswift_example_LDFLAGS += -lbcrypt -endif -TESTS += ellswift_example -endif -if ENABLE_MODULE_MUSIG -noinst_PROGRAMS += musig_example -musig_example_SOURCES = examples/musig.c -musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC -musig_example_LDADD = libsecp256k1.la -musig_example_LDFLAGS = -static -if BUILD_WINDOWS -musig_example_LDFLAGS += -lbcrypt -endif -TESTS += musig_example -endif -endif - -### Precomputed tables -EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen -CLEANFILES = $(EXTRA_PROGRAMS) - -precompute_ecmult_SOURCES = src/precompute_ecmult.c -precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY -precompute_ecmult_LDADD = $(COMMON_LIB) - -precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c -precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY -precompute_ecmult_gen_LDADD = $(COMMON_LIB) - -# See Automake manual, Section "Errors with distclean". -# We don't list any dependencies for the prebuilt files here because -# otherwise make's decision whether to rebuild them (even in the first -# build by a normal user) depends on mtimes, and thus is very fragile. -# This means that rebuilds of the prebuilt files always need to be -# forced by deleting them. -src/precomputed_ecmult.c: - $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT) - ./precompute_ecmult$(EXEEXT) -src/precomputed_ecmult_gen.c: - $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult_gen$(EXEEXT) - ./precompute_ecmult_gen$(EXEEXT) - -PRECOMP = src/precomputed_ecmult_gen.c src/precomputed_ecmult.c -precomp: $(PRECOMP) - -# Ensure the prebuilt files will be build first (only if they don't exist, -# e.g., after `make maintainer-clean`). -BUILT_SOURCES = $(PRECOMP) - -.PHONY: clean-precomp -clean-precomp: - rm -f $(PRECOMP) -maintainer-clean-local: clean-precomp - -### Pregenerated test vectors -### (see the comments in the previous section for detailed rationale) -TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h - -src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: - mkdir -p $(@D) - python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ - -testvectors: $(TESTVECTORS) - -BUILT_SOURCES += $(TESTVECTORS) - -.PHONY: clean-testvectors -clean-testvectors: - rm -f $(TESTVECTORS) -maintainer-clean-local: clean-testvectors - -### Additional files to distribute -EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md -EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md -EXTRA_DIST += doc/ellswift.md doc/musig.md -EXTRA_DIST += examples/EXAMPLES_COPYING -EXTRA_DIST += sage/gen_exhaustive_groups.sage -EXTRA_DIST += sage/gen_split_lambda_constants.sage -EXTRA_DIST += sage/group_prover.sage -EXTRA_DIST += sage/prove_group_implementations.sage -EXTRA_DIST += sage/secp256k1_params.sage -EXTRA_DIST += sage/weierstrass_prover.sage -EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING -EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json -EXTRA_DIST += tools/tests_wycheproof_generate.py - -if ENABLE_MODULE_ECDH -include src/modules/ecdh/Makefile.am.include -endif - -if ENABLE_MODULE_RECOVERY -include src/modules/recovery/Makefile.am.include -endif - -if ENABLE_MODULE_EXTRAKEYS -include src/modules/extrakeys/Makefile.am.include -endif - -if ENABLE_MODULE_SCHNORRSIG -include src/modules/schnorrsig/Makefile.am.include -endif - -if ENABLE_MODULE_MUSIG -include src/modules/musig/Makefile.am.include -endif - -if ENABLE_MODULE_ELLSWIFT -include src/modules/ellswift/Makefile.am.include -endif diff --git a/external/secp256k1/README.md b/external/secp256k1/README.md deleted file mode 100644 index 222e5fb768..0000000000 --- a/external/secp256k1/README.md +++ /dev/null @@ -1,142 +0,0 @@ -libsecp256k1 -============ - -![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) -[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1) - -High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve. - -This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose. - -Features: -* secp256k1 ECDSA signing/verification and key generation. -* Additive and multiplicative tweaking of secret/public keys. -* Serialization/parsing of secret keys, public keys, signatures. -* Constant time, constant memory access signing and public key generation. -* Derandomized ECDSA (via RFC6979 or with a caller provided function.) -* Very efficient implementation. -* Suitable for embedded systems. -* No runtime dependencies. -* Optional module for public key recovery. -* Optional module for ECDH key exchange. -* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). -* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki). -* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). - -Implementation details ----------------------- - -* General - * No runtime heap allocation. - * Extensive testing infrastructure. - * Structured to facilitate review and analysis. - * Intended to be portable to any system with a C89 compiler and uint64_t support. - * No use of floating types. - * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") -* Field operations - * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). - * Using 5 52-bit limbs - * Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan). - * This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community. -* Scalar operations - * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. - * Using 4 64-bit limbs (relying on __int128 support in the compiler). - * Using 8 32-bit limbs. -* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman). -* Group operations - * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). - * Use addition between points in Jacobian and affine coordinates where possible. - * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. - * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. -* Point multiplication for verification (a*P + b*G). - * Use wNAF notation for point multiplicands. - * Use a much larger window for multiples of G, using precomputed multiples. - * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. - * Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. -* Point multiplication for signing - * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. - * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) - * Access the table with branch-free conditional moves so memory access is uniform. - * No data-dependent branches - * Optional runtime blinding which attempts to frustrate differential power analysis. - * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. - -Building with Autotools ------------------------ - - $ ./autogen.sh - $ ./configure - $ make - $ make check # run the test suite - $ sudo make install # optional - -To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. - -Building with CMake (experimental) ----------------------------------- - -To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. - -### Building on POSIX systems - - $ mkdir build && cd build - $ cmake .. - $ cmake --build . - $ ctest # run the test suite - $ sudo cmake --install . # optional - -To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags. - -### Cross compiling - -To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. -For example, to cross compile for Windows: - - $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake - -To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): - - $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 - -### Building on Windows - -To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. - -The following example assumes using of Visual Studio 2022 and CMake v3.21+. - -In "Developer Command Prompt for VS 2022": - - >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build - >cmake --build build --config RelWithDebInfo - -Usage examples ------------ -Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. - * [ECDSA example](examples/ecdsa.c) - * [Schnorr signatures example](examples/schnorr.c) - * [Deriving a shared secret (ECDH) example](examples/ecdh.c) - * [ElligatorSwift key exchange example](examples/ellswift.c) - -To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. - -Benchmark ------------- -If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build. - -To print the benchmark result to the command line: - - $ ./bench_name - -To create a CSV file for the benchmark result : - - $ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv - -Reporting a vulnerability ------------- - -See [SECURITY.md](SECURITY.md) - -Contributing to libsecp256k1 ------------- - -See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/external/secp256k1/SECURITY.md b/external/secp256k1/SECURITY.md deleted file mode 100644 index b515cc1c8e..0000000000 --- a/external/secp256k1/SECURITY.md +++ /dev/null @@ -1,15 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -To report security issues send an email to secp256k1-security@bitcoincore.org (not for support). - -The following keys may be used to communicate sensitive information to developers: - -| Name | Fingerprint | -|------|-------------| -| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | -| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | -| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 | - -You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/external/secp256k1/autogen.sh b/external/secp256k1/autogen.sh deleted file mode 100755 index 65286b9353..0000000000 --- a/external/secp256k1/autogen.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -autoreconf -if --warnings=all diff --git a/external/secp256k1/build-aux/m4/bitcoin_secp.m4 b/external/secp256k1/build-aux/m4/bitcoin_secp.m4 deleted file mode 100644 index 048267fa6e..0000000000 --- a/external/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ /dev/null @@ -1,91 +0,0 @@ -dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. -AC_DEFUN([SECP_X86_64_ASM_CHECK],[ -AC_MSG_CHECKING(for x86_64 assembly availability) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include ]],[[ - uint64_t a = 11, tmp; - __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); - ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no]) -AC_MSG_RESULT([$has_x86_64_asm]) -]) - -AC_DEFUN([SECP_ARM32_ASM_CHECK], [ - AC_MSG_CHECKING(for ARM32 assembly availability) - SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS" - CFLAGS="-x assembler" - AC_LINK_IFELSE([AC_LANG_SOURCE([[ - .syntax unified - .eabi_attribute 24, 1 - .eabi_attribute 25, 1 - .text - .global main - main: - ldr r0, =0x002A - mov r7, #1 - swi 0 - ]])], [has_arm32_asm=yes], [has_arm32_asm=no]) - AC_MSG_RESULT([$has_arm32_asm]) - CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS" -]) - -AC_DEFUN([SECP_VALGRIND_CHECK],[ -AC_MSG_CHECKING([for valgrind support]) -if test x"$has_valgrind" != x"yes"; then - CPPFLAGS_TEMP="$CPPFLAGS" - CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include - ]], [[ - #if defined(NVALGRIND) - # error "Valgrind does not support this platform." - #endif - ]])], [has_valgrind=yes]) - CPPFLAGS="$CPPFLAGS_TEMP" -fi -AC_MSG_RESULT($has_valgrind) -]) - -AC_DEFUN([SECP_MSAN_CHECK], [ -AC_MSG_CHECKING(whether MemorySanitizer is enabled) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ - #if defined(__has_feature) - # if __has_feature(memory_sanitizer) - /* MemorySanitizer is enabled. */ - # elif - # error "MemorySanitizer is disabled." - # endif - #else - # error "__has_feature is not defined." - #endif - ]])], [msan_enabled=yes], [msan_enabled=no]) -AC_MSG_RESULT([$msan_enabled]) -]) - -dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) -dnl Append flags to VAR if CC accepts them. -AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [ - AC_MSG_CHECKING([if ${CC} supports $1]) - SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS" - CFLAGS="$1 $CFLAGS" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no]) - AC_MSG_RESULT($flag_works) - CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS" - if test x"$flag_works" = x"yes"; then - $2="$$2 $1" - fi - unset flag_works - AC_SUBST($2) -]) - -dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode) -dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled -AC_DEFUN([SECP_SET_DEFAULT], [ - if test "${enable_dev_mode+set}" != set; then - AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]]) - fi - if test x"$enable_dev_mode" = x"yes"; then - $1="$3" - else - $1="$2" - fi -]) diff --git a/external/secp256k1/ci/ci.sh b/external/secp256k1/ci/ci.sh deleted file mode 100755 index 3636deafa1..0000000000 --- a/external/secp256k1/ci/ci.sh +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/sh - -set -eux - -export LC_ALL=C - -# Print commit and relevant CI environment to allow reproducing the job outside of CI. -git show --no-patch -print_environment() { - # Turn off -x because it messes up the output - set +x - # There are many ways to print variable names and their content. This one - # does not rely on bash. - for var in WERROR_CFLAGS MAKEFLAGS BUILD \ - ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ - EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \ - SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ - EXAMPLES \ - HOST WRAPPER_CMD \ - CC CFLAGS CPPFLAGS AR NM \ - UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS - do - eval "isset=\${$var+x}" - if [ -n "$isset" ]; then - eval "val=\${$var}" - # shellcheck disable=SC2154 - printf '%s="%s" ' "$var" "$val" - fi - done - echo "$0" - set -x -} -print_environment - -env >> test_env.log - -# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang). -case "${CC:-undefined}" in - *gcc*) - $CC -v 2>&1 | grep -q "gcc version" || exit 1; - ;; -esac - -if [ -n "${CC+x}" ]; then - # The MSVC compiler "cl" doesn't understand "-v" - $CC -v || true -fi -if [ "$WITH_VALGRIND" = "yes" ]; then - valgrind --version -fi -if [ -n "$WRAPPER_CMD" ]; then - $WRAPPER_CMD --version -fi - -# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0). -case "${CC:-undefined}" in - clang*) - if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ] - then - export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" - else - case "$WRAPPER_CMD" in - valgrind*) - export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" - ;; - esac - fi - ;; -esac - -./autogen.sh - -./configure \ - --enable-experimental="$EXPERIMENTAL" \ - --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ - --with-ecmult-window="$ECMULTWINDOW" \ - --with-ecmult-gen-kb="$ECMULTGENKB" \ - --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ - --enable-module-ellswift="$ELLSWIFT" \ - --enable-module-extrakeys="$EXTRAKEYS" \ - --enable-module-schnorrsig="$SCHNORRSIG" \ - --enable-module-musig="$MUSIG" \ - --enable-examples="$EXAMPLES" \ - --enable-ctime-tests="$CTIMETESTS" \ - --with-valgrind="$WITH_VALGRIND" \ - --host="$HOST" $EXTRAFLAGS - -# We have set "-j" in MAKEFLAGS. -build_exit_code=0 -make > make.log 2>&1 || build_exit_code=$? -cat make.log -if [ $build_exit_code -ne 0 ]; then - case "${CC:-undefined}" in - *snapshot*) - # Ignore internal compiler errors in gcc-snapshot and clang-snapshot - grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log - return $?; - ;; - *) - return 1; - ;; - esac -fi - -# Print information about binaries so that we can see that the architecture is correct -file *tests* || true -file bench* || true -file .libs/* || true - -# This tells `make check` to wrap test invocations. -export LOG_COMPILER="$WRAPPER_CMD" - -make "$BUILD" - -# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool -EXEC='./libtool --mode=execute' -if [ -n "$WRAPPER_CMD" ] -then - EXEC="$EXEC $WRAPPER_CMD" -fi - -if [ "$BENCH" = "yes" ] -then - { - $EXEC ./bench_ecmult - $EXEC ./bench_internal - $EXEC ./bench - } >> bench.log 2>&1 -fi - -if [ "$CTIMETESTS" = "yes" ] -then - if [ "$WITH_VALGRIND" = "yes" ]; then - ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 - else - $EXEC ./ctime_tests > ctime_tests.log 2>&1 - fi -fi - -# Rebuild precomputed files (if not cross-compiling). -if [ -z "$HOST" ] -then - make clean-precomp clean-testvectors - make precomp testvectors -fi - -# Check that no repo files have been modified by the build. -# (This fails for example if the precomp files need to be updated in the repo.) -git diff --exit-code diff --git a/external/secp256k1/ci/linux-debian.Dockerfile b/external/secp256k1/ci/linux-debian.Dockerfile deleted file mode 100644 index 241bfa9719..0000000000 --- a/external/secp256k1/ci/linux-debian.Dockerfile +++ /dev/null @@ -1,79 +0,0 @@ -FROM debian:stable-slim - -SHELL ["/bin/bash", "-c"] - -WORKDIR /root - -# A too high maximum number of file descriptors (with the default value -# inherited from the docker host) can cause issues with some of our tools: -# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662 -# - valgrind crashing: https://stackoverflow.com/a/75293014 -# This is not be a problem on our CI hosts, but developers who run the image -# on their machines may run into this (e.g., on Arch Linux), so warn them. -# (Note that .bashrc is only executed in interactive bash shells.) -RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc - -RUN dpkg --add-architecture i386 && \ - dpkg --add-architecture s390x && \ - dpkg --add-architecture armhf && \ - dpkg --add-architecture arm64 && \ - dpkg --add-architecture ppc64el - -# dkpg-dev: to make pkg-config work in cross-builds -# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces -RUN apt-get update && apt-get install --no-install-recommends -y \ - git ca-certificates \ - make automake libtool pkg-config dpkg-dev valgrind qemu-user \ - gcc clang llvm libclang-rt-dev libc6-dbg \ - g++ \ - gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \ - gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ - gcc-mingw-w64-x86-64-win32 wine64 wine \ - gcc-mingw-w64-i686-win32 wine32 \ - python3 && \ - if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ - apt-get install --no-install-recommends -y \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ - fi && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# Build and install gcc snapshot -ARG GCC_SNAPSHOT_MAJOR=15 -RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ - mkdir gcc && cd gcc && \ - wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ - wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \ - sha512sum --check --ignore-missing sha512.sum && \ - # We should have downloaded exactly one tar.xz file - ls && \ - [ $(ls *.tar.xz | wc -l) -eq "1" ] && \ - tar xf *.tar.xz && \ - mkdir gcc-build && cd gcc-build && \ - ../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \ - make -j $(nproc) && \ - make install && \ - cd ../.. && rm -rf gcc && \ - ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \ - apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# Install clang snapshot, see https://apt.llvm.org/ -RUN \ - # Setup GPG keys of LLVM repository - apt-get update && apt-get install --no-install-recommends -y wget && \ - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ - # Add repository for this Debian release - . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ - apt-get update && \ - # Determine the version number of the LLVM development branch - LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ - # Install - apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \ - # Create symlink - ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \ - # Clean up - apt-get autoremove -y wget && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - diff --git a/external/secp256k1/cmake/CheckArm32Assembly.cmake b/external/secp256k1/cmake/CheckArm32Assembly.cmake deleted file mode 100644 index baeeff0292..0000000000 --- a/external/secp256k1/cmake/CheckArm32Assembly.cmake +++ /dev/null @@ -1,6 +0,0 @@ -function(check_arm32_assembly) - try_compile(HAVE_ARM32_ASM - ${PROJECT_BINARY_DIR}/check_arm32_assembly - SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s - ) -endfunction() diff --git a/external/secp256k1/cmake/CheckMemorySanitizer.cmake b/external/secp256k1/cmake/CheckMemorySanitizer.cmake deleted file mode 100644 index d9ef681e65..0000000000 --- a/external/secp256k1/cmake/CheckMemorySanitizer.cmake +++ /dev/null @@ -1,18 +0,0 @@ -include_guard(GLOBAL) -include(CheckCSourceCompiles) - -function(check_memory_sanitizer output) - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - check_c_source_compiles(" - #if defined(__has_feature) - # if __has_feature(memory_sanitizer) - /* MemorySanitizer is enabled. */ - # elif - # error \"MemorySanitizer is disabled.\" - # endif - #else - # error \"__has_feature is not defined.\" - #endif - " HAVE_MSAN) - set(${output} ${HAVE_MSAN} PARENT_SCOPE) -endfunction() diff --git a/external/secp256k1/cmake/CheckStringOptionValue.cmake b/external/secp256k1/cmake/CheckStringOptionValue.cmake deleted file mode 100644 index 5a4d939b9e..0000000000 --- a/external/secp256k1/cmake/CheckStringOptionValue.cmake +++ /dev/null @@ -1,10 +0,0 @@ -function(check_string_option_value option) - get_property(expected_values CACHE ${option} PROPERTY STRINGS) - if(expected_values) - if(${option} IN_LIST expected_values) - return() - endif() - message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") - endif() - message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") -endfunction() diff --git a/external/secp256k1/cmake/CheckX86_64Assembly.cmake b/external/secp256k1/cmake/CheckX86_64Assembly.cmake deleted file mode 100644 index ae82cd476e..0000000000 --- a/external/secp256k1/cmake/CheckX86_64Assembly.cmake +++ /dev/null @@ -1,14 +0,0 @@ -include(CheckCSourceCompiles) - -function(check_x86_64_assembly) - check_c_source_compiles(" - #include - - int main() - { - uint64_t a = 11, tmp; - __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); - } - " HAVE_X86_64_ASM) - set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE) -endfunction() diff --git a/external/secp256k1/cmake/FindValgrind.cmake b/external/secp256k1/cmake/FindValgrind.cmake deleted file mode 100644 index 3af5e691e4..0000000000 --- a/external/secp256k1/cmake/FindValgrind.cmake +++ /dev/null @@ -1,41 +0,0 @@ -if(CMAKE_HOST_APPLE) - find_program(BREW_COMMAND brew) - execute_process( - COMMAND ${BREW_COMMAND} --prefix valgrind - OUTPUT_VARIABLE valgrind_brew_prefix - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif() - -set(hints_paths) -if(valgrind_brew_prefix) - set(hints_paths ${valgrind_brew_prefix}/include) -endif() - -find_path(Valgrind_INCLUDE_DIR - NAMES valgrind/memcheck.h - HINTS ${hints_paths} -) - -if(Valgrind_INCLUDE_DIR) - include(CheckCSourceCompiles) - set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR}) - check_c_source_compiles(" - #include - #if defined(NVALGRIND) - # error \"Valgrind does not support this platform.\" - #endif - - int main() {} - " Valgrind_WORKS) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Valgrind - REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS -) - -mark_as_advanced( - Valgrind_INCLUDE_DIR -) diff --git a/external/secp256k1/cmake/GeneratePkgConfigFile.cmake b/external/secp256k1/cmake/GeneratePkgConfigFile.cmake deleted file mode 100644 index 9c1d7f1ddd..0000000000 --- a/external/secp256k1/cmake/GeneratePkgConfigFile.cmake +++ /dev/null @@ -1,8 +0,0 @@ -function(generate_pkg_config_file in_file) - set(prefix ${CMAKE_INSTALL_PREFIX}) - set(exec_prefix \${prefix}) - set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) - set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) - set(PACKAGE_VERSION ${PROJECT_VERSION}) - configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY) -endfunction() diff --git a/external/secp256k1/cmake/TryAppendCFlags.cmake b/external/secp256k1/cmake/TryAppendCFlags.cmake deleted file mode 100644 index 1d81a9317a..0000000000 --- a/external/secp256k1/cmake/TryAppendCFlags.cmake +++ /dev/null @@ -1,24 +0,0 @@ -include(CheckCCompilerFlag) - -function(secp256k1_check_c_flags_internal flags output) - string(MAKE_C_IDENTIFIER "${flags}" result) - string(TOUPPER "${result}" result) - set(result "C_SUPPORTS_${result}") - if(NOT MSVC) - set(CMAKE_REQUIRED_FLAGS "-Werror") - endif() - - # This avoids running a linker. - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - check_c_compiler_flag("${flags}" ${result}) - - set(${output} ${${result}} PARENT_SCOPE) -endfunction() - -# Append flags to the COMPILE_OPTIONS directory property if CC accepts them. -macro(try_append_c_flags) - secp256k1_check_c_flags_internal("${ARGV}" result) - if(result) - add_compile_options(${ARGV}) - endif() -endmacro() diff --git a/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake b/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake deleted file mode 100644 index 0d91912b6d..0000000000 --- a/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR arm) -set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) diff --git a/external/secp256k1/cmake/config.cmake.in b/external/secp256k1/cmake/config.cmake.in deleted file mode 100644 index 46b180ab19..0000000000 --- a/external/secp256k1/cmake/config.cmake.in +++ /dev/null @@ -1,5 +0,0 @@ -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") - -check_required_components(@PROJECT_NAME@) diff --git a/external/secp256k1/cmake/source_arm32.s b/external/secp256k1/cmake/source_arm32.s deleted file mode 100644 index d3d9347057..0000000000 --- a/external/secp256k1/cmake/source_arm32.s +++ /dev/null @@ -1,9 +0,0 @@ -.syntax unified -.eabi_attribute 24, 1 -.eabi_attribute 25, 1 -.text -.global main -main: - ldr r0, =0x002A - mov r7, #1 - swi 0 diff --git a/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake b/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake deleted file mode 100644 index 96119b72d1..0000000000 --- a/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Windows) -set(CMAKE_SYSTEM_PROCESSOR x86_64) -set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) diff --git a/external/secp256k1/configure.ac b/external/secp256k1/configure.ac deleted file mode 100644 index f880a3578d..0000000000 --- a/external/secp256k1/configure.ac +++ /dev/null @@ -1,517 +0,0 @@ -AC_PREREQ([2.60]) - -# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of -# the API. All changes in experimental modules are treated as -# backwards-compatible and therefore at most increase the minor version. -define(_PKG_VERSION_MAJOR, 0) -define(_PKG_VERSION_MINOR, 6) -define(_PKG_VERSION_PATCH, 0) -define(_PKG_VERSION_IS_RELEASE, true) - -# The library version is based on libtool versioning of the ABI. The set of -# rules for updating the version can be found here: -# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -# All changes in experimental modules are treated as if they don't affect the -# interface and therefore only increase the revision. -define(_LIB_VERSION_CURRENT, 5) -define(_LIB_VERSION_REVISION, 0) -define(_LIB_VERSION_AGE, 0) - -AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) - -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) -AC_CANONICAL_HOST - -# Require Automake 1.11.2 for AM_PROG_AR -AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) - -# Make the compilation flags quiet unless V=1 is used. -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -if test "${CFLAGS+set}" = "set"; then - CFLAGS_overridden=yes -else - CFLAGS_overridden=no -fi -AC_PROG_CC -AM_PROG_AS -AM_PROG_AR - -# Clear some cache variables as a workaround for a bug that appears due to a bad -# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe. -# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421 -AS_UNSET(ac_cv_prog_AR) -AS_UNSET(ac_cv_prog_ac_ct_AR) -LT_INIT([win32-dll]) - -build_windows=no - -case $host_os in - *darwin*) - if test x$cross_compiling != xyes; then - AC_CHECK_PROG([BREW], brew, brew) - if test x$BREW = xbrew; then - # These Homebrew packages may be keg-only, meaning that they won't be found - # in expected paths because they may conflict with system files. Ask - # Homebrew where each one is located, then adjust paths accordingly. - if $BREW list --versions valgrind >/dev/null; then - valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null) - VALGRIND_CPPFLAGS="-I$valgrind_prefix/include" - fi - else - AC_CHECK_PROG([PORT], port, port) - # If homebrew isn't installed and macports is, add the macports default paths - # as a last resort. - if test x$PORT = xport; then - CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" - LDFLAGS="$LDFLAGS -L/opt/local/lib" - fi - fi - fi - ;; - cygwin*|mingw*) - build_windows=yes - ;; -esac - -# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS. -# -# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as -# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user -# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS -# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag). -# -# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by -# libtool for compiling helper executables. For example, when compiling for Windows, libtool will -# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure -# proper operation of uninstalled programs linked by libtool against the uninstalled shared library. -# These executables are compiled from C source file for which our flags may not be appropriate, -# e.g., -std=c89 flag has lead to undesirable warnings in the past. -# -# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. -AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ - # GCC and compatible (incl. clang) - if test "x$GCC" = "xyes"; then - # Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported - # flags will succeed. - # Note that failure to append -Werror does not necessarily mean that -Werror is not - # supported. The compiler may already be warning about something unrelated, for example - # about some path issue. If that is the case, -Werror cannot be used because all - # of those warnings would be turned into errors. - SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" - SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS) - - SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers - SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. - SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. - SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 - SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 - SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only - SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only - SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 - - CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" - fi - - # MSVC - # Assume MSVC if we're building for Windows but not with GCC or compatible; - # libtool makes the same assumption internally. - # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. - if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then - SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level. - SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". - SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". - SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". - # Eliminate deprecation warnings for the older, less secure functions. - CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS" - fi -]) -SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) - -### -### Define config arguments -### - -# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. -# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. -AC_ARG_ENABLE(dev_mode, [], [], - [enable_dev_mode=no]) - -AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [], - [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) - -AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], - [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) - -AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], - [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) - -AC_ARG_ENABLE(ctime_tests, - AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [], - [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])]) - -AC_ARG_ENABLE(experimental, - AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], - [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) - -AC_ARG_ENABLE(exhaustive_tests, - AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [], - [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])]) - -AC_ARG_ENABLE(examples, - AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], - [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) - -AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) - -AC_ARG_ENABLE(module_recovery, - AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) - -AC_ARG_ENABLE(module_extrakeys, - AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) - -AC_ARG_ENABLE(module_schnorrsig, - AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) - -AC_ARG_ENABLE(module_musig, - AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])]) - -AC_ARG_ENABLE(module_ellswift, - AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) - -AC_ARG_ENABLE(external_default_callbacks, - AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], - [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) - -# Test-only override of the (autodetected by the C code) "widemul" setting. -# Legal values are: -# * int64 (for [u]int64_t), -# * int128 (for [unsigned] __int128), -# * int128_struct (for int128 implemented as a structure), -# * and auto (the default). -AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) - -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], -[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) - -AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], -[window size for ecmult precomputation for verification, specified as integer in range [2..24].] -[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] -[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] -[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] -[For very large window sizes, use "make -j 1" to reduce memory use during compilation.] -[The default value is a reasonable setting for desktop machines (currently 15). [default=15]] -)], -[set_ecmult_window=$withval], [set_ecmult_window=15]) - -AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86], -[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).] -[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.] -[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] -)], -[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86]) - -AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], -[Build with extra checks for running inside Valgrind [default=auto]] -)], -[req_valgrind=$withval], [req_valgrind=auto]) - -### -### Handle config options (except for modules) -### - -if test x"$req_valgrind" = x"no"; then - enable_valgrind=no -else - SECP_VALGRIND_CHECK - if test x"$has_valgrind" != x"yes"; then - if test x"$req_valgrind" = x"yes"; then - AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) - fi - enable_valgrind=no - else - enable_valgrind=yes - fi -fi - -if test x"$enable_ctime_tests" = x"auto"; then - enable_ctime_tests=$enable_valgrind -fi - -print_msan_notice=no -if test x"$enable_ctime_tests" = x"yes"; then - SECP_MSAN_CHECK - # MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if - # the uninitalized variable is never actually "used". This is called "eager" checking, and it's - # sounds like good idea for normal use of MSan. However, it yields many false positives in the - # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and - # we're only interested in detecting branches (which count as "uses") on secret data. - if test x"$msan_enabled" = x"yes"; then - SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS) - print_msan_notice=yes - fi -fi - -if test x"$enable_coverage" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" - SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" - # If coverage is enabled, and the user has not overridden CFLAGS, - # override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up - # with "-O0 --coverage -g -O2". - if test "$CFLAGS_overridden" = "no"; then - CFLAGS="-g" - fi - LDFLAGS="--coverage $LDFLAGS" -else - # Most likely the CFLAGS already contain -O2 because that is autoconf's default. - # We still add it here because passing it twice is not an issue, and handling - # this case would just add unnecessary complexity (see #896). - SECP_CFLAGS="-O2 $SECP_CFLAGS" -fi - -if test x"$req_asm" = x"auto"; then - SECP_X86_64_ASM_CHECK - if test x"$has_x86_64_asm" = x"yes"; then - set_asm=x86_64 - fi - if test x"$set_asm" = x; then - set_asm=no - fi -else - set_asm=$req_asm - case $set_asm in - x86_64) - SECP_X86_64_ASM_CHECK - if test x"$has_x86_64_asm" != x"yes"; then - AC_MSG_ERROR([x86_64 assembly requested but not available]) - fi - ;; - arm32) - SECP_ARM32_ASM_CHECK - if test x"$has_arm32_asm" != x"yes"; then - AC_MSG_ERROR([ARM32 assembly requested but not available]) - fi - ;; - no) - ;; - *) - AC_MSG_ERROR([invalid assembly selection]) - ;; - esac -fi - -# Select assembly -enable_external_asm=no - -case $set_asm in -x86_64) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1" - ;; -arm32) - enable_external_asm=yes - ;; -no) - ;; -*) - AC_MSG_ERROR([invalid assembly selection]) - ;; -esac - -if test x"$enable_external_asm" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1" -fi - - -# Select wide multiplication implementation -case $set_widemul in -int128_struct) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1" - ;; -int128) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1" - ;; -int64) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1" - ;; -auto) - ;; -*) - AC_MSG_ERROR([invalid wide multiplication implementation]) - ;; -esac - -error_window_size=['window size for ecmult precomputation not an integer in range [2..24]'] -case $set_ecmult_window in -''|*[[!0-9]]*) - # no valid integer - AC_MSG_ERROR($error_window_size) - ;; -*) - if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then - # not in range - AC_MSG_ERROR($error_window_size) - fi - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window" - ;; -esac - -case $set_ecmult_gen_kb in -2) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5" - ;; -22) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6" - ;; -86) - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6" - ;; -*) - AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86']) - ;; -esac - -if test x"$enable_valgrind" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND" -fi - -# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). -# We don't want to set the user variable CFLAGS in CI because this would disable -# autoconf's logic for setting default CFLAGS, which we would like to test in CI. -SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" - -### -### Handle module options -### - -# Processing must be done in a reverse topological sorting of the dependency graph -# (dependent module first). -if test x"$enable_module_ellswift" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" -fi - -if test x"$enable_module_musig" = x"yes"; then - if test x"$enable_module_schnorrsig" = x"no"; then - AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.]) - fi - enable_module_schnorrsig=yes - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1" -fi - -if test x"$enable_module_schnorrsig" = x"yes"; then - if test x"$enable_module_extrakeys" = x"no"; then - AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.]) - fi - enable_module_extrakeys=yes - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" -fi - -if test x"$enable_module_extrakeys" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1" -fi - -if test x"$enable_module_recovery" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" -fi - -if test x"$enable_module_ecdh" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" -fi - -if test x"$enable_external_default_callbacks" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" -fi - -### -### Check for --enable-experimental if necessary -### - -if test x"$enable_experimental" = x"no"; then - if test x"$set_asm" = x"arm32"; then - AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) - fi -fi - -### -### Generate output -### - -AC_CONFIG_FILES([Makefile libsecp256k1.pc]) -AC_SUBST(SECP_CFLAGS) -AC_SUBST(SECP_CONFIG_DEFINES) -AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) -AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) -AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) -AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) -AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) -AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) -AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) -AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) -AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) -AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) -AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) - -AC_OUTPUT - -echo -echo "Build Options:" -echo " with external callbacks = $enable_external_default_callbacks" -echo " with benchmarks = $enable_benchmark" -echo " with tests = $enable_tests" -echo " with ctime tests = $enable_ctime_tests" -echo " with coverage = $enable_coverage" -echo " with examples = $enable_examples" -echo " module ecdh = $enable_module_ecdh" -echo " module recovery = $enable_module_recovery" -echo " module extrakeys = $enable_module_extrakeys" -echo " module schnorrsig = $enable_module_schnorrsig" -echo " module musig = $enable_module_musig" -echo " module ellswift = $enable_module_ellswift" -echo -echo " asm = $set_asm" -echo " ecmult window size = $set_ecmult_window" -echo " ecmult gen table size = $set_ecmult_gen_kb KiB" -# Hide test-only options unless they're used. -if test x"$set_widemul" != xauto; then -echo " wide multiplication = $set_widemul" -fi -echo -echo " valgrind = $enable_valgrind" -echo " CC = $CC" -echo " CPPFLAGS = $CPPFLAGS" -echo " SECP_CFLAGS = $SECP_CFLAGS" -echo " CFLAGS = $CFLAGS" -echo " LDFLAGS = $LDFLAGS" - -if test x"$print_msan_notice" = x"yes"; then - echo - echo "Note:" - echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS" - echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this." -fi - -if test x"$enable_experimental" = x"yes"; then - echo - echo "WARNING: Experimental build" - echo " Experimental features do not have stable APIs or properties, and may not be safe for" - echo " production use." -fi diff --git a/external/secp256k1/contrib/lax_der_parsing.c b/external/secp256k1/contrib/lax_der_parsing.c deleted file mode 100644 index bf562303ed..0000000000 --- a/external/secp256k1/contrib/lax_der_parsing.c +++ /dev/null @@ -1,148 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include - -#include "lax_der_parsing.h" - -int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { - size_t rpos, rlen, spos, slen; - size_t pos = 0; - size_t lenbyte; - unsigned char tmpsig[64] = {0}; - int overflow = 0; - - /* Hack to initialize sig with a correctly-parsed but invalid signature. */ - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - - /* Sequence tag byte */ - if (pos == inputlen || input[pos] != 0x30) { - return 0; - } - pos++; - - /* Sequence length bytes */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (lenbyte > inputlen - pos) { - return 0; - } - pos += lenbyte; - } - - /* Integer tag byte for R */ - if (pos == inputlen || input[pos] != 0x02) { - return 0; - } - pos++; - - /* Integer length for R */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (lenbyte > inputlen - pos) { - return 0; - } - while (lenbyte > 0 && input[pos] == 0) { - pos++; - lenbyte--; - } - if (lenbyte >= sizeof(size_t)) { - return 0; - } - rlen = 0; - while (lenbyte > 0) { - rlen = (rlen << 8) + input[pos]; - pos++; - lenbyte--; - } - } else { - rlen = lenbyte; - } - if (rlen > inputlen - pos) { - return 0; - } - rpos = pos; - pos += rlen; - - /* Integer tag byte for S */ - if (pos == inputlen || input[pos] != 0x02) { - return 0; - } - pos++; - - /* Integer length for S */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (lenbyte > inputlen - pos) { - return 0; - } - while (lenbyte > 0 && input[pos] == 0) { - pos++; - lenbyte--; - } - if (lenbyte >= sizeof(size_t)) { - return 0; - } - slen = 0; - while (lenbyte > 0) { - slen = (slen << 8) + input[pos]; - pos++; - lenbyte--; - } - } else { - slen = lenbyte; - } - if (slen > inputlen - pos) { - return 0; - } - spos = pos; - - /* Ignore leading zeroes in R */ - while (rlen > 0 && input[rpos] == 0) { - rlen--; - rpos++; - } - /* Copy R value */ - if (rlen > 32) { - overflow = 1; - } else if (rlen) { - memcpy(tmpsig + 32 - rlen, input + rpos, rlen); - } - - /* Ignore leading zeroes in S */ - while (slen > 0 && input[spos] == 0) { - slen--; - spos++; - } - /* Copy S value */ - if (slen > 32) { - overflow = 1; - } else if (slen) { - memcpy(tmpsig + 64 - slen, input + spos, slen); - } - - if (!overflow) { - overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - } - if (overflow) { - memset(tmpsig, 0, 64); - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - } - return 1; -} - diff --git a/external/secp256k1/contrib/lax_der_parsing.h b/external/secp256k1/contrib/lax_der_parsing.h deleted file mode 100644 index 37c8c691f2..0000000000 --- a/external/secp256k1/contrib/lax_der_parsing.h +++ /dev/null @@ -1,97 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/**** - * Please do not link this file directly. It is not part of the libsecp256k1 - * project and does not promise any stability in its API, functionality or - * presence. Projects which use this code should instead copy this header - * and its accompanying .c file directly into their codebase. - ****/ - -/* This file defines a function that parses DER with various errors and - * violations. This is not a part of the library itself, because the allowed - * violations are chosen arbitrarily and do not follow or establish any - * standard. - * - * In many places it matters that different implementations do not only accept - * the same set of valid signatures, but also reject the same set of signatures. - * The only means to accomplish that is by strictly obeying a standard, and not - * accepting anything else. - * - * Nonetheless, sometimes there is a need for compatibility with systems that - * use signatures which do not strictly obey DER. The snippet below shows how - * certain violations are easily supported. You may need to adapt it. - * - * Do not use this for new systems. Use well-defined DER or compact signatures - * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and - * secp256k1_ecdsa_signature_parse_compact). - * - * The supported violations are: - * - All numbers are parsed as nonnegative integers, even though X.609-0207 - * section 8.3.3 specifies that integers are always encoded as two's - * complement. - * - Integers can have length 0, even though section 8.3.1 says they can't. - * - Integers with overly long padding are accepted, violation section - * 8.3.2. - * - 127-byte long length descriptors are accepted, even though section - * 8.1.3.5.c says that they are not. - * - Trailing garbage data inside or after the signature is ignored. - * - The length descriptor of the sequence is ignored. - * - * Compared to for example OpenSSL, many violations are NOT supported: - * - Using overly long tag descriptors for the sequence or integers inside, - * violating section 8.1.2.2. - * - Encoding primitive integers as constructed values, violating section - * 8.3.1. - */ - -#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H -#define SECP256K1_CONTRIB_LAX_DER_PARSING_H - -/* #include secp256k1.h only when it hasn't been included yet. - This enables this file to be #included directly in other project - files (such as tests.c) without the need to set an explicit -I flag, - which would be necessary to locate secp256k1.h. */ -#ifndef SECP256K1_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** Parse a signature in "lax DER" format - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: pointer to a signature object - * In: input: pointer to the signature to be parsed - * inputlen: the length of the array pointed to be input - * - * This function will accept any valid DER encoded signature, even if the - * encoded numbers are out of range. In addition, it will accept signatures - * which violate the DER spec in various ways. Its purpose is to allow - * validation of the Bitcoin blockchain, which includes non-DER signatures - * from before the network rules were updated to enforce DER. Note that - * the set of supported violations is a strict subset of what OpenSSL will - * accept. - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is - * guaranteed to fail for every message and public key. - */ -int ecdsa_signature_parse_der_lax( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/external/secp256k1/contrib/lax_der_privatekey_parsing.c b/external/secp256k1/contrib/lax_der_privatekey_parsing.c deleted file mode 100644 index a1b8200079..0000000000 --- a/external/secp256k1/contrib/lax_der_privatekey_parsing.c +++ /dev/null @@ -1,112 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include - -#include "lax_der_privatekey_parsing.h" - -int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - memset(out32, 0, 32); - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) { - return 0; - } - privkey++; - /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) { - return 0; - } - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) { - return 0; - } - if (end < privkey+lenb) { - return 0; - } - /* sequence length */ - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) { - return 0; - } - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { - return 0; - } - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { - return 0; - } - if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); - if (!secp256k1_ec_seckey_verify(ctx, out32)) { - memset(out32, 0, 32); - return 0; - } - return 1; -} - -int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { - secp256k1_pubkey pubkey; - size_t pubkeylen = 0; - if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { - *privkeylen = 0; - return 0; - } - if (compressed) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - memcpy(ptr, key32, 32); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = 33; - secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - memcpy(ptr, key32, 32); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = 65; - secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} diff --git a/external/secp256k1/contrib/lax_der_privatekey_parsing.h b/external/secp256k1/contrib/lax_der_privatekey_parsing.h deleted file mode 100644 index 3749e418fe..0000000000 --- a/external/secp256k1/contrib/lax_der_privatekey_parsing.h +++ /dev/null @@ -1,95 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/**** - * Please do not link this file directly. It is not part of the libsecp256k1 - * project and does not promise any stability in its API, functionality or - * presence. Projects which use this code should instead copy this header - * and its accompanying .c file directly into their codebase. - ****/ - -/* This file contains code snippets that parse DER private keys with - * various errors and violations. This is not a part of the library - * itself, because the allowed violations are chosen arbitrarily and - * do not follow or establish any standard. - * - * It also contains code to serialize private keys in a compatible - * manner. - * - * These functions are meant for compatibility with applications - * that require BER encoded keys. When working with secp256k1-specific - * code, the simple 32-byte private keys normally used by the - * library are sufficient. - */ - -#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H -#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H - -/* #include secp256k1.h only when it hasn't been included yet. - This enables this file to be #included directly in other project - files (such as tests.c) without the need to set an explicit -I flag, - which would be necessary to locate secp256k1.h. */ -#ifndef SECP256K1_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** Export a private key in DER format. - * - * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: privkey: pointer to an array for storing the private key in BER. - * Should have space for 279 bytes, and cannot be NULL. - * privkeylen: Pointer to an int where the length of the private key in - * privkey will be stored. - * In: seckey: pointer to a 32-byte secret key to export. - * compressed: 1 if the key should be exported in - * compressed format, 0 otherwise - * - * This function is purely meant for compatibility with applications that - * require BER encoded keys. When working with secp256k1-specific code, the - * simple 32-byte private keys are sufficient. - * - * Note that this function does not guarantee correct DER output. It is - * guaranteed to be parsable by secp256k1_ec_privkey_import_der - */ -SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( - const secp256k1_context* ctx, - unsigned char *privkey, - size_t *privkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Import a private key in DER format. - * Returns: 1 if a private key was extracted. - * Args: ctx: pointer to a context object (cannot be NULL). - * Out: seckey: pointer to a 32-byte array for storing the private key. - * (cannot be NULL). - * In: privkey: pointer to a private key in DER format (cannot be NULL). - * privkeylen: length of the DER private key pointed to be privkey. - * - * This function will accept more than just strict DER, and even allow some BER - * violations. The public key stored inside the DER-encoded private key is not - * verified for correctness, nor are the curve parameters. Use this function - * only if you know in advance it is supposed to contain a secp256k1 private - * key. - */ -SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( - const secp256k1_context* ctx, - unsigned char *seckey, - const unsigned char *privkey, - size_t privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/external/secp256k1/doc/ellswift.md b/external/secp256k1/doc/ellswift.md deleted file mode 100644 index 9d60e6be0b..0000000000 --- a/external/secp256k1/doc/ellswift.md +++ /dev/null @@ -1,483 +0,0 @@ -# ElligatorSwift for secp256k1 explained - -In this document we explain how the `ellswift` module implementation is related to the -construction in the -["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759) -paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi. - -* [1. Introduction](#1-introduction) -* [2. The decoding function](#2-the-decoding-function) - + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) -* [3. The encoding function](#3-the-encoding-function) - + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates) - + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses) - + [3.3 Finding the inverse](#33-finding-the-inverse) - + [3.4 Dealing with special cases](#34-dealing-with-special-cases) - + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1) -* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates) - + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) - -## 1. Introduction - -The `ellswift` module effectively introduces a new 64-byte public key format, with the property -that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally -indistinguishable from uniform byte arrays. The module provides functions to convert public keys -from and to this format, as well as convenience functions for key generation and ECDH that operate -directly on ellswift-encoded keys. - -The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$ -and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on -the curve. - -**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$ -are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid -x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function). - -**Encoding** a given $x$ coordinate is conceptually done as follows: -* Loop: - * Pick a uniformly random field element $u.$ - * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements. - * With probability $1 - \dfrac{\\#L}{8}$, restart the loop. - * Select a uniformly random $t \in L$ and return $(u, t).$ - -This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full -$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates). -The algorithm finds a uniformly random $(u, t)$ among (almost all) those -for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for -almost all x-coordinates on the curve (all but at most 39) is close to two times the field size -(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field). - -## 2. The decoding function - -First some definitions: -* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$ - * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement. -* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$ - public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square. - This implies that the order of $E$ is either odd, or a multiple of *4*. - If $a=0$, this condition is always fulfilled. - * For `secp256k1`, $a=0$ and $b=7.$ -* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$ -* Let the function $h(x) = 3x^3 + 4a.$ -* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$ -* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$ -* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below. -* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. - -**Note**: In the paper: -* $F_u$ corresponds to $F_{0,u}$ there. -* $P_u(t)$ is called $P$ there. -* All $S_u$ sets together correspond to $S$ there. -* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there. - -Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right -hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$, -out of the three right-hand side factors an even number must be non-squares. -This implies that exactly *1* or exactly *3* out of -$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$, -at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception -to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate. - -**Define** the decoding function $F_u(t)$ as: -* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$ -* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square). - -$P_u(t) = (X(u, t), Y(u, t))$, where: - -$$ -\begin{array}{lcl} -X(u, t) & = & \left\\{\begin{array}{ll} - \dfrac{g(u) - t^2}{2t} & a = 0 \\ - \dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0 -\end{array}\right. \\ -Y(u, t) & = & \left\\{\begin{array}{ll} - \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\ - Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0 -\end{array}\right. -\end{array} -$$ - -$P_u(t)$ is defined: -* For $a=0$, unless: - * $u = 0$ or $t = 0$ (division by zero) - * $g(u) = -t^2$ (would give $Y=0$). -* For $a \neq 0$, unless: - * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero) - * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$). - -The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$ - -The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where: - -$$ -\begin{array}{lcl} - x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\ - x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\ - x_3 & = & u + 4Y^2 && \\ - z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3} -\end{array} -$$ - -### 2.1 Decoding for `secp256k1` - -Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is: - -**Define** $F_u(t)$ as: -* Let $X = \dfrac{u^3 + b - t^2}{2t}.$ -* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$ -* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square. - -To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case -$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$): - -**Define** $F_u(t)$ as: -* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$). -* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$). -* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). -* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ -* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ -* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square. - -The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice, -but the approach here is simple enough and gives fairly uniform output even in these cases. - -**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there. -We wish to avoid the need for callers to deal with this special case. - -This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and -in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate). - -## 3. The encoding function - -To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process: -* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$ -* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$ -* For each of the found $t$ values, verify that $F_u(t) = x.$ -* Return the remaining $t$ values. - -The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$ - -$$ -P_u^{-1}(X, Y) = \left\\{\begin{array}{ll} -Yu\sqrt{-3} - X & a = 0 \\ -\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\ -\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u) -\end{array}\right. -$$ - -The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions, -it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the -$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected. - -Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$, -the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid. -This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of -$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out. - -Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as -$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square, -and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined -before those values are computed. - -It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would -take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take -precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$ -values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder; -any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder. - -### 3.1 Switching to *v, w* coordinates - -Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and -$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$ -* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$ -* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$ -* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where - -$$ -\begin{array}{lcl} - x_1 & = & v \\ - x_2 & = & -u - v \\ - x_3 & = & u + w^2 \\ - z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3} -\end{array} -$$ - -We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$ -expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable: -* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). -* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). -* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions). - -### 3.2 Avoiding computing all inverses - -The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the -set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary. - -Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a -uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8, -picking a uniformly random element from that, restarting whenever $\bot$ is picked: - -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Compute the set $L = F_u^{-1}(x).$ - * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ - * Select a uniformly random $t \in T.$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. - -Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly -random element in it, so we do not need to have all $\bot$ values at the end. -As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account), -we can associate every index in $T$ with exactly one of those formulas, making sure that: -* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$ -* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check). -* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those. - -The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting -to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases) -for an analysis of all the negligible cases. - -If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas, -the loop can be simplified to only compute one of the inverses instead of all of them: - -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Pick a uniformly random integer $c$ in $[0,8).$ - * Let $t = G_{c,u}(x).$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. - -This is implemented in `secp256k1_ellswift_xelligatorswift_var`. - -### 3.3 Finding the inverse - -To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula. -Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression). -Ignoring the negligible cases, we get: - -**Define** $G_{c,u}(x)$ as: -* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas): - * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence). - * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) - * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). -* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ - * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. -* Let $w = \sqrt{s}.$ -* Depending on $c:$ - * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$ - * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$ - -Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly -50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen -with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$ -implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered -and $\bot$ would have been returned already. - -**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4). -The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to -have the $G_{c,u}$ be deterministic, and capture all choices in $c.$ - -Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$ -transformation. Furthermore, that transformation has no effect on $s$ in the first branch -as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down: - -**Define** $G_{c,u}(x)$ as: -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a).$ - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}.$ -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ - * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$ - * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$ - * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$ - -This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input. -There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values. - -### 3.4 Dealing with special cases - -As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs. -For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness -we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that -do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same -$t$ value for multiple $c$ inputs (thereby biasing that encoding): - -* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$): - * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves. - Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve - fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square). - This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$), - the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the - encoder anyway as there will generally be more than 8. - * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence - as it can deal with $g(u)=0$. - This is again only possible on even-ordered curves. -* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): - * When $s=0$, a division by zero would occur. - * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases. - It is equivalent to checking whether $r=0$. - This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition. - A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first - it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero. -* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder: - * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve. - * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$. - -**Define** a version of $G_{c,u}(x)$ which deals with all these cases: -* If $a=0$ and $u=0$, return $\bot.$ -* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). - * If $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. - * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ - * If $s = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ -* Depending on $c:$ - * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ - * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ - * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ - * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ -* If $a=0$ and $t=0$, return $\bot$ (even curves only). -* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$ -* Return $t.$ - -Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once, -for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached: -* All cases where $P_u(t)$ is not defined: - * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$ - * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$ -* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch. - -These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves. - -### 3.5 Encoding for `secp256k1` - -Specialized for odd-ordered $a=0$ curves: - -**Define** $G_{c,u}(x)$ as: -* If $u=0$, return $\bot.$ -* If $c \in \\{0, 1, 4, 5\\}:$ - * If $(-u-x)^3 + b$ is square, return $\bot$ - * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. - * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ - * If $s = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$ - * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$ - * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$ - * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$ - -This is implemented in `secp256k1_ellswift_xswiftec_inv_var`. - -And the x-only ElligatorSwift encoding algorithm is still: - -**Define** *ElligatorSwift(x)* as: -* Loop: - * Pick a uniformly random field element $u.$ - * Pick a uniformly random integer $c$ in $[0,8).$ - * Let $t = G_{c,u}(x).$ - * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. - -Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them. -While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$ -combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity. - -## 4. Encoding and decoding full *(x, y)* coordinates - -So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding -for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information -in $t$ as well. - -Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are -mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$ -being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order -of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead. - -Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode -the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the -four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$ - -**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit. - -To encode the sign of $y$ in the sign of $Y:$ - -**Define** *Decode(u, t)* for full $(x, y)$ as: -* Let $(X, Y) = P_u(t).$ -* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square. -* Let $y = \sqrt{g(x)}.$ -* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$ - -And encoding would be done using a $G_{c,u}(x, y)$ function defined as: - -**Define** $G_{c,u}(x, y)$ as: -* If $c \in \\{0, 1\\}:$ - * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). - * If $g(-u-x)$ is square, return $\bot.$ - * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). - * Let $v = x.$ -* Otherwise, when $c \in \\{2, 3\\}:$ - * Let $s = x-u.$ - * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. - * If $c = 3$ and $r = 0$, return $\bot.$ - * Let $v = (r/s - u)/2.$ -* Let $w = \sqrt{s}$; return $\bot$ if not square. -* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. -* Depending on $c:$ - * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$ - * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$ - -Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$ -This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$. - -In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation -of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where -$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$. - -### 4.1 Full *(x, y)* coordinates for `secp256k1` - -For $a=0$ curves, there is another option. Note that for those, -the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to -encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get -as decoder: - -**Define** *Decode(u, t)* as: -* Let $u'=u$ if $u \neq 0$; $1$ otherwise. -* Let $t'=t$ if $t \neq 0$; $1$ otherwise. -* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. -* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ -* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ -* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square. -* Let $y = \sqrt{g(x)}.$ -* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise. - -This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$ - -The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$ - -This is implemented in `secp256k1_ellswift_elligatorswift_var`. - -Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points -where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in -[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift -in the first place. diff --git a/external/secp256k1/doc/musig.md b/external/secp256k1/doc/musig.md deleted file mode 100644 index ae21f9b131..0000000000 --- a/external/secp256k1/doc/musig.md +++ /dev/null @@ -1,54 +0,0 @@ -Notes on the musig module API -=========================== - -The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`). -A usage example can be found in `examples/musig.c`. - -## API misuse - -The musig API is designed with a focus on misuse resistance. -However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation. -While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes. - -Therefore, users of the musig module must take great care to make sure of the following: - -1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`. - See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that. -2. The `secp256k1_musig_secnonce` structure is never copied or serialized. - See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`. -3. Opaque data structures are never written to or read from directly. - Instead, only the provided accessor functions are used. - -## Key Aggregation and (Taproot) Tweaking - -Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`. -A plain tweak can be added to the resulting public key with `secp256k1_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `secp256k1_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341. -Both types of tweaking can be combined and invoked multiple times if the specific application requires it. - -## Signing - -This is covered by `examples/musig.c`. -Essentially, the protocol proceeds in the following steps: - -1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`. -2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants. -3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`. -4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers. -5. Someone (not necessarily the signer) aggregates the public nonces with `secp256k1_musig_nonce_agg` and sends it to the signers. -6. Process the aggregate nonce with `secp256k1_musig_nonce_process`. -7. Create a partial signature with `secp256k1_musig_partial_sign`. -8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`. -9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`. - -The aggregate signature can be verified with `secp256k1_schnorrsig_verify`. - -Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed. -Whenever possible, it is recommended to generate the nonces only after the message is known. -This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios. -However, it does require two rounds of communication during the signing process. -The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing. -Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5). - -## Verification - -A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. diff --git a/external/secp256k1/doc/release-process.md b/external/secp256k1/doc/release-process.md deleted file mode 100644 index a64bae0f0d..0000000000 --- a/external/secp256k1/doc/release-process.md +++ /dev/null @@ -1,94 +0,0 @@ -# Release process - -This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. - -We distinguish between two types of releases: *regular* and *maintenance* releases. -Regular releases are releases of a new major or minor version as well as patches of the most recent release. -Maintenance releases, on the other hand, are required for patches of older releases. - -You should coordinate with the other maintainers on the release date, if possible. -This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release). -It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3. - -This process also assumes that there will be no minor releases for old major releases. - -We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core. - -## Sanity checks -Perform these checks when reviewing the release PR (see below): - -1. Ensure `make distcheck` doesn't fail. - ```shell - ./autogen.sh && ./configure --enable-dev-mode && make distcheck - ``` -2. Check installation with autotools: - ```shell - dir=$(mktemp -d) - ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir - gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa - ``` -3. Check installation with CMake: - ```shell - dir=$(mktemp -d) - build=$(mktemp -d) - cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir - gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa - ``` -4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. - ```shell - tools/check-abi.sh - ``` - -## Regular release - -1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that - * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by - * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), - * removing the `[Unreleased]` section header, - * ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and - * including an entry for `### ABI Compatibility` if it doesn't exist, - * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, - * if this is not a patch release, - * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and - * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. -2. Perform the [sanity checks](#sanity-checks) on the PR branch. -3. After the PR is merged, tag the commit, and push the tag: - ``` - RELEASE_COMMIT= - git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT - git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH - ``` -4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that - * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, - * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and - * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). - - If other maintainers are not present to approve the PR, it can be merged without ACKs. -5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). -6. Send an announcement email to the bitcoin-dev mailing list. - -## Maintenance release - -Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists. - -1. If there's no maintenance branch `$MAJOR.$MINOR`, create one: - ``` - git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1)) - git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR - ``` -2. Open a pull request to the `$MAJOR.$MINOR` branch that - * includes the bug fixes, - * finalizes the release notes similar to a regular release, - * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` - and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt` - (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). -3. Perform the [sanity checks](#sanity-checks) on the PR branch. -4. After the PRs are merged, update the release branch, tag the commit, and push the tag: - ``` - git checkout $MAJOR.$MINOR && git pull - git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" - git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH - ``` -6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). -7. Send an announcement email to the bitcoin-dev mailing list. -8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/external/secp256k1/doc/safegcd_implementation.md b/external/secp256k1/doc/safegcd_implementation.md deleted file mode 100644 index 5dbbb7bbd2..0000000000 --- a/external/secp256k1/doc/safegcd_implementation.md +++ /dev/null @@ -1,819 +0,0 @@ -# The safegcd implementation in libsecp256k1 explained - -This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. -It is based on the paper -["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) -by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. - -The actual implementation is in C of course, but for demonstration purposes Python3 is used here. -Most implementation aspects and optimizations are explained, except those that depend on the specific -number representation used in the C code. - -## 1. Computing the Greatest Common Divisor (GCD) using divsteps - -The algorithm from the paper (section 11), at a very high level, is this: - -```python -def gcd(f, g): - """Compute the GCD of an odd integer f and another integer g.""" - assert f & 1 # require f to be odd - delta = 1 # additional state variable - while g != 0: - assert f & 1 # f will be odd in every iteration - if delta > 0 and g & 1: - delta, f, g = 1 - delta, g, (g - f) // 2 - elif g & 1: - delta, f, g = 1 + delta, f, (g + f) // 2 - else: - delta, f, g = 1 + delta, f, (g ) // 2 - return abs(f) -``` - -It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop -keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until -*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a -"division step" (referred to as divstep in what follows). - -For example, *gcd(21, 14)* would be computed as: -- Start with *δ=1 f=21 g=14* -- Take the third branch: *δ=2 f=21 g=7* -- Take the first branch: *δ=-1 f=7 g=-7* -- Take the second branch: *δ=0 f=7 g=0* -- The answer *|f| = 7*. - -Why it works: -- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper): - - (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*. - - (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even). -- Neither of those two operations change the GCD: - - For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a* - and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has - common factor *c*. Reasoning in the other direction shows that no common factor can be added by - doing so either. - - For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove - it from *g*. -- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3). -- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the - gcd of *f'* and *0* is *|f'|* by definition, that is our answer. - -Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at -the low-order bits of the variables to decide the next steps, and being easy to make -constant-time (in more low-level languages than Python). The *δ* parameter is necessary to -guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look -at high order bits. - -Properties that will become important later: -- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*. -- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we - do not need to worry about rounding. -- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N* - bits of *f* and *g*, and on *δ*. - - -## 2. From GCDs to modular inverses - -We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=1 -mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is -prime and *0 < x < M*. In what follows, assume that the modular inverse exists. -It turns out this inverse can be computed as a side effect of computing the GCD by keeping track -of how the internal variables can be written as linear combinations of the inputs at every step -(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)). -Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*. -Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x -mod M*. - -A similar approach can be used to calculate modular inverses using the divsteps-based GCD -algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping -track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*. -*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M* -and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M -= 1*). - -```python -def div2(M, x): - """Helper routine to compute x/2 mod M (where M is odd).""" - assert M & 1 - if x & 1: # If x is odd, make it even by adding M. - x += M - # x must be even now, so a clean division by 2 is possible. - return x // 2 - -def modinv(M, x): - """Compute the inverse of x mod M (given that it exists, and M is odd).""" - assert M & 1 - delta, f, g, d, e = 1, M, x, 0, 1 - while g != 0: - # Note that while division by two for f and g is only ever done on even inputs, this is - # not true for d and e, so we need the div2 helper function. - if delta > 0 and g & 1: - delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d) - elif g & 1: - delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d) - else: - delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e ) - # Verify that the invariants d=f/x mod M, e=g/x mod M are maintained. - assert f % M == (d * x) % M - assert g % M == (e * x) % M - assert f == 1 or f == -1 # |f| is the GCD, it must be 1 - # Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f. - return (d * f) % M -``` - -Also note that this approach to track *d* and *e* throughout the computation to determine the inverse -is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the -entire computation is determined (see section 3 below) and the inverse is computed from that. -The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to -be faster at the level of optimization we're able to do in C. - - -## 3. Batching multiple divsteps - -Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)* -to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper): - -``` - t = [ u, v ] - [ q, r ] - - [ out_f ] = (1/2 * t) * [ in_f ] - [ out_g ] = [ in_g ] - - [ out_d ] = (1/2 * t) * [ in_d ] (mod M) - [ out_e ] [ in_e ] -``` - -where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is -taken. As above, the resulting *f* and *g* are always integers. - -Performing multiple divsteps corresponds to a multiplication with the product of all the -individual divsteps' transition matrices. As each transition matrix consists of integers -divided by *2*, the product of these matrices will consist of integers divided by *2N* (see also -theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay -them: we compute the integer coefficients of the combined transition matrix scaled by *2N*, and -do one division by *2N* as a final step: - -```python -def divsteps_n_matrix(delta, f, g): - """Compute delta and transition matrix t after N divsteps (multiplied by 2^N).""" - u, v, q, r = 1, 0, 0, 1 # start with identity matrix - for _ in range(N): - if delta > 0 and g & 1: - delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v - elif g & 1: - delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v - else: - delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r - return delta, (u, v, q, r) -``` - -As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this -function to compute the transition matrix only needs to see those bottom bits. Furthermore all -intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*, -*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit -integers could set *N=62* and compute the full transition matrix for 62 steps at once without any -big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs -to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps. - -We still need functions to compute: - -``` - [ out_f ] = (1/2^N * [ u, v ]) * [ in_f ] - [ out_g ] ( [ q, r ]) [ in_g ] - - [ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M) - [ out_e ] ( [ q, r ]) [ in_e ] -``` - -Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f* -and *g* will be multiple of *2N*, and division by *2N* is simply shifting them down: - -```python -def update_fg(f, g, t): - """Multiply matrix t/2^N with [f, g].""" - u, v, q, r = t - cf, cg = u*f + v*g, q*f + r*g - # (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero - # bottom bits. - assert cf % 2**N == 0 - assert cg % 2**N == 0 - return cf >> N, cg >> N -``` - -The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2N mod M*. -This is easy if we have precomputed *1/M mod 2N* (which always exists for odd *M*): - -```python -def div2n(M, Mi, x): - """Compute x/2^N mod M, given Mi = 1/M mod 2^N.""" - assert (M * Mi) % 2**N == 1 - # Find a factor m such that m*M has the same bottom N bits as x. We want: - # (m * M) mod 2^N = x mod 2^N - # <=> m mod 2^N = (x / M) mod 2^N - # <=> m mod 2^N = (x * Mi) mod 2^N - m = (Mi * x) % 2**N - # Subtract that multiple from x, cancelling its bottom N bits. - x -= m * M - # Now a clean division by 2^N is possible. - assert x % 2**N == 0 - return (x >> N) % M - -def update_de(d, e, t, M, Mi): - """Multiply matrix t/2^N with [d, e], modulo M.""" - u, v, q, r = t - cd, ce = u*d + v*e, q*d + r*e - return div2n(M, Mi, cd), div2n(M, Mi, ce) -``` - -With all of those, we can write a version of `modinv` that performs *N* divsteps at once: - -```python3 -def modinv(M, Mi, x): - """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" - assert M & 1 - delta, f, g, d, e = 1, M, x, 0, 1 - while g != 0: - # Compute the delta and transition matrix t for the next N divsteps (this only needs - # (N+1)-bit signed integer arithmetic). - delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N) - # Apply the transition matrix t to [f, g]: - f, g = update_fg(f, g, t) - # Apply the transition matrix t to [d, e]: - d, e = update_de(d, e, t, M, Mi) - return (d * f) % M -``` - -This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem -because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps -increasing). For variable time code such excess iterations will be mostly optimized away in later -sections. - - -## 4. Avoiding modulus operations - -So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of -`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the -sign of *f*. These are relatively expensive operations when done generically. - -To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range -*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus -operation at the end: - -```python -def update_de(d, e, t, M, Mi): - """Multiply matrix t/2^N with [d, e] mod M, given Mi=1/M mod 2^N.""" - u, v, q, r = t - cd, ce = u*d + v*e, q*d + r*e - # Cancel out bottom N bits of cd and ce. - md = -((Mi * cd) % 2**N) - me = -((Mi * ce) % 2**N) - cd += md * M - ce += me * M - # And cleanly divide by 2**N. - return cd >> N, ce >> N -``` - -Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|* -never exceed *2N* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have -outputs whose absolute values are at most *2N* times the maximum absolute input value. In case the -inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming -*M > 1*, the multiplication results in numbers in range *(-2NM,2NM)*. Subtracting less than *2N* -times *M* to cancel out *N* bits brings that up to *(-2N+1M,2NM)*, and -dividing by *2N* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that -to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be -counteracted by incrementing *d* and *e* by *M* whenever they're negative: - -```python - ... - if d < 0: - d += M - if e < 0: - e += M - cd, ce = u*d + v*e, q*d + r*e - # Cancel out bottom N bits of cd and ce. - ... -``` - -With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the -output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de` -invocations there are. In what follows, we will try to make this more efficient. - -Note that increasing *d* by *M* is equal to incrementing *cd* by *u M* and *ce* by *q M*. Similarly, -increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write: - -```python - ... - cd, ce = u*d + v*e, q*d + r*e - # Perform the equivalent of incrementing d, e by M when they're negative. - if d < 0: - cd += u*M - ce += q*M - if e < 0: - cd += v*M - ce += r*M - # Cancel out bottom N bits of cd and ce. - md = -((Mi * cd) % 2**N) - me = -((Mi * ce) % 2**N) - cd += md * M - ce += me * M - ... -``` - -Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this -increment, and the decrement that cancels out bottom bits. The second one depends on the first -one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce* -at first, and using that to compute the final *md*, *me* values: - -```python -def update_de(d, e, t, M, Mi): - """Multiply matrix t/2^N with [d, e], modulo M.""" - u, v, q, r = t - md, me = 0, 0 - # Compute what multiples of M to add to cd and ce. - if d < 0: - md += u - me += q - if e < 0: - md += v - me += r - # Compute bottom N bits of t*[d,e] + M*[md,me]. - cd, ce = (u*d + v*e + md*M) % 2**N, (q*d + r*e + me*M) % 2**N - # Correct md and me such that the bottom N bits of t*[d,e] + M*[md,me] are zero. - md -= (Mi * cd) % 2**N - me -= (Mi * ce) % 2**N - # Do the full computation. - cd, ce = u*d + v*e + md*M, q*d + r*e + me*M - # And cleanly divide by 2**N. - return cd >> N, ce >> N -``` - -One last optimization: we can avoid the *md M* and *me M* multiplications in the bottom bits of *cd* -and *ce* by moving them to the *md* and *me* correction: - -```python - ... - # Compute bottom N bits of t*[d,e]. - cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N - # Correct md and me such that the bottom N bits of t*[d,e]+M*[md,me] are zero. - # Note that this is not the same as {md = (-Mi * cd) % 2**N} etc. That would also result in N - # zero bottom bits, but isn't guaranteed to be a reduction of [0,2^N) compared to the - # previous md and me values, and thus would violate our bounds analysis. - md -= (Mi*cd + md) % 2**N - me -= (Mi*ce + me) % 2**N - ... -``` - -The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same -range. That also means that the *d* value at the end of `modinv` will be in that range, while we want -a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the -conditional negation of *d* (based on the sign of *f*) into it as well: - -```python -def normalize(sign, v, M): - """Compute sign*v mod M, where v is in range (-2*M,M); output in [0,M).""" - assert sign == 1 or sign == -1 - # v in (-2*M,M) - if v < 0: - v += M - # v in (-M,M). Now multiply v with sign (which can only be 1 or -1). - if sign == -1: - v = -v - # v in (-M,M) - if v < 0: - v += M - # v in [0,M) - return v -``` - -And calling it in `modinv` is simply: - -```python - ... - return normalize(f, d, M) -``` - - -## 5. Constant-time operation - -The primary selling point of the algorithm is fast constant-time operation. What code flow still -depends on the input data so far? - -- the number of iterations of the while *g ≠ 0* loop in `modinv` -- the branches inside `divsteps_n_matrix` -- the sign checks in `update_de` -- the sign checks in `normalize` - -To make the while loop in `modinv` constant time it can be replaced with a constant number of -iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit -inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is -sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of -*⌈724/N⌉* times. - -To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise -operations (and hope the C compiler isn't smart enough to turn them back into branches; see -`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a -divstep can be written instead as (compare to the inner loop of `gcd` in section 1). - -```python - x = -f if delta > 0 else f # set x equal to (input) -f or f - if g & 1: - g += x # set g to (input) g-f or g+f - if delta > 0: - delta = -delta - f += g # set f to (input) g (note that g was set to g-f before) - delta += 1 - g >>= 1 -``` - -To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the -definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As -*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows -that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then -*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*. - -Using this we can write: - -```python - x = -f if delta > 0 else f -``` - -in constant-time form as: - -```python - c1 = (-delta) >> 63 - # Conditionally negate f based on c1: - x = (f ^ c1) - c1 -``` - -To use that trick, we need a helper mask variable *c1* that resolves the condition *δ>0* to *-1* -(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by -the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see -`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all -numbers in range *[-263,0)* to *-1*, and numbers in range *[0,263)* to *0*. - -Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write: - -```python - if g & 1: - g += x -``` - -as: - -```python - # Compute c2=0 if g is even and c2=-1 if g is odd. - c2 = -(g & 1) - # This masks out x if g is even, and leaves x be if g is odd. - g += x & c2 -``` - -Using the conditional negation trick again we can write: - -```python - if g & 1: - if delta > 0: - delta = -delta -``` - -as: - -```python - # Compute c3=-1 if g is odd and delta>0, and 0 otherwise. - c3 = c1 & c2 - # Conditionally negate delta based on c3: - delta = (delta ^ c3) - c3 -``` - -Finally: - -```python - if g & 1: - if delta > 0: - f += g -``` - -becomes: - -```python - f += g & c3 -``` - -It turns out that this can be implemented more efficiently by applying the substitution -*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing -*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1* -computation: - -```python - # Compute a mask c1 for eta < 0, and compute the conditional negation x of f: - c1 = eta >> 63 - x = (f ^ c1) - c1 - # Compute a mask c2 for odd g, and conditionally add x to g: - c2 = -(g & 1) - g += x & c2 - # Compute a mask c for (eta < 0) and odd (input) g, and use it to conditionally negate eta, - # and add g to f: - c3 = c1 & c2 - eta = (eta ^ c3) - c3 - f += g & c3 - # Incrementing delta corresponds to decrementing eta. - eta -= 1 - g >>= 1 -``` - -A variant of divsteps with better worst-case performance can be used instead: starting *δ* at -*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs -(which can be shown using convex hull analysis). In this case, the substitution *ζ=-(δ+1/2)* -is used instead to keep the variable integral. Incrementing *δ* by *1* still translates to -decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or -*~ζ*. Doing that conditionally based on *c3* is simply: - -```python - ... - c3 = c1 & c2 - zeta ^= c3 - ... -``` - -By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to -also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of -`divsteps_n_matrix` is obtained. The full code will be in section 7. - -These bit fiddling tricks can also be used to make the conditional negations and additions in -`update_de` and `normalize` constant-time. - - -## 6. Variable-time optimizations - -In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time. -Constant time operations are only necessary when computing modular inverses of secret data. In -other cases, it slows down calculations unnecessarily. In this section, we will construct a -faster non-constant time `divsteps_n_matrix` function. - -To do so, first consider yet another way of writing the inner loop of divstep operations in -`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use -the original version with initial *δ=1* and *η=-δ* here. - -```python -for _ in range(N): - if g & 1 and eta < 0: - eta, f, g = -eta, g, -f - if g & 1: - g += f - eta -= 1 - g >>= 1 -``` - -Whenever *g* is even, the loop only shifts *g* down and decreases *η*. When *g* ends in multiple zero -bits, these iterations can be consolidated into one step. This requires counting the bottom zero -bits efficiently, which is possible on most platforms; it is abstracted here as the function -`count_trailing_zeros`. - -```python -def count_trailing_zeros(v): - """ - When v is zero, consider all N zero bits as "trailing". - For a non-zero value v, find z such that v=(d<>= zeros - i -= zeros - if i == 0: - break - # We know g is odd now - if eta < 0: - eta, f, g = -eta, g, -f - g += f - # g is even now, and the eta decrement and g shift will happen in the next loop. -``` - -We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever -there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as -well. - -Observe that as long as *η ≥ 0*, the loop does not modify *f*. Instead, it cancels out bottom -bits of *g* and shifts them out, and decreases *η* and *i* accordingly - interrupting only when *η* -becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to -*g* to cancel out multiple bottom bits, and then shifting them out. - -It is easy to find what that multiple is: we want a number *w* such that *g+w f* has a few bottom -zero bits. If that number of bits is *L*, we want *g+w f mod 2L = 0*, or *w = -g/f mod 2L*. Since *f* -is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before -doing more) or more than *η+1* steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but -apart from that, we're only limited by the complexity of computing *w*. - -This code demonstrates how to cancel up to 4 bits per step: - -```python -NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n -i = N -while True: - zeros = min(i, count_trailing_zeros(g)) - eta -= zeros - g >>= zeros - i -= zeros - if i == 0: - break - # We know g is odd now - if eta < 0: - eta, f, g = -eta, g, -f - # Compute limit on number of bits to cancel - limit = min(min(eta + 1, i), 4) - # Compute w = -g/f mod 2**limit, using the table value for -1/f mod 2**4. Note that f is - # always odd, so its inverse modulo a power of two always exists. - w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) - # As w = -g/f mod (2**limit), g+w*f mod 2**limit = 0 mod 2**limit. - g += w * f - assert g % (2**limit) == 0 - # The next iteration will now shift out at least limit bottom zero bits from g. -``` - -By using a bigger table more bits can be cancelled at once. The table can also be implemented -as a formula. Several formulas are known for computing modular inverses modulo powers of two; -some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pages 245-247. -Here we need the negated modular inverse, which is a simple transformation of those: - -- Instead of a 3-bit table: - - *-f* or *f ^ 6* -- Instead of a 4-bit table: - - *1 - f(f + 1)* - - *-(f + (((f + 1) & 4) << 1))* -- For larger tables the following technique can be used: if *w=-1/f mod 2L*, then *w(w f+2)* is - *-1/f mod 22L*. This allows extending the previous formulas (or tables). In particular we - have this 6-bit function (based on the 3-bit function above): - - *f(f2 - 2)* - -This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in -`divsteps_n_matrix`, gives a significantly faster, but non-constant time version. - - -## 7. Final Python version - -All together we need the following functions: - -- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function - from section 2, but with its loop replaced by a variant of the constant-time divstep from - section 5, extended to handle *u*, *v*, *q*, *r*: - -```python -def divsteps_n_matrix(zeta, f, g): - """Compute zeta and transition matrix t after N divsteps (multiplied by 2^N).""" - u, v, q, r = 1, 0, 0, 1 # start with identity matrix - for _ in range(N): - c1 = zeta >> 63 - # Compute x, y, z as conditionally-negated versions of f, u, v. - x, y, z = (f ^ c1) - c1, (u ^ c1) - c1, (v ^ c1) - c1 - c2 = -(g & 1) - # Conditionally add x, y, z to g, q, r. - g, q, r = g + (x & c2), q + (y & c2), r + (z & c2) - c1 &= c2 # reusing c1 here for the earlier c3 variable - zeta = (zeta ^ c1) - 1 # inlining the unconditional zeta decrement here - # Conditionally add g, q, r to f, u, v. - f, u, v = f + (g & c1), u + (q & c1), v + (r & c1) - # When shifting g down, don't shift q, r, as we construct a transition matrix multiplied - # by 2^N. Instead, shift f's coefficients u and v up. - g, u, v = g >> 1, u << 1, v << 1 - return zeta, (u, v, q, r) -``` - -- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time - changes to `update_de` from section 5: - -```python -def update_fg(f, g, t): - """Multiply matrix t/2^N with [f, g].""" - u, v, q, r = t - cf, cg = u*f + v*g, q*f + r*g - return cf >> N, cg >> N - -def update_de(d, e, t, M, Mi): - """Multiply matrix t/2^N with [d, e], modulo M.""" - u, v, q, r = t - d_sign, e_sign = d >> 257, e >> 257 - md, me = (u & d_sign) + (v & e_sign), (q & d_sign) + (r & e_sign) - cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N - md -= (Mi*cd + md) % 2**N - me -= (Mi*ce + me) % 2**N - cd, ce = u*d + v*e + M*md, q*d + r*e + M*me - return cd >> N, ce >> N -``` - -- The `normalize` function from section 4, made constant time as well: - -```python -def normalize(sign, v, M): - """Compute sign*v mod M, where v in (-2*M,M); output in [0,M).""" - v_sign = v >> 257 - # Conditionally add M to v. - v += M & v_sign - c = (sign - 1) >> 1 - # Conditionally negate v. - v = (v ^ c) - c - v_sign = v >> 257 - # Conditionally add M to v again. - v += M & v_sign - return v -``` - -- And finally the `modinv` function too, adapted to use *ζ* instead of *δ*, and using the fixed - iteration count from section 5: - -```python -def modinv(M, Mi, x): - """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" - zeta, f, g, d, e = -1, M, x, 0, 1 - for _ in range((590 + N - 1) // N): - zeta, t = divsteps_n_matrix(zeta, f % 2**N, g % 2**N) - f, g = update_fg(f, g, t) - d, e = update_de(d, e, t, M, Mi) - return normalize(f, d, M) -``` - -- To get a variable time version, replace the `divsteps_n_matrix` function with one that uses the - divsteps loop from section 5, and a `modinv` version that calls it without the fixed iteration - count: - -```python -NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n -def divsteps_n_matrix_var(eta, f, g): - """Compute eta and transition matrix t after N divsteps (multiplied by 2^N).""" - u, v, q, r = 1, 0, 0, 1 - i = N - while True: - zeros = min(i, count_trailing_zeros(g)) - eta, i = eta - zeros, i - zeros - g, u, v = g >> zeros, u << zeros, v << zeros - if i == 0: - break - if eta < 0: - eta, f, u, v, g, q, r = -eta, g, q, r, -f, -u, -v - limit = min(min(eta + 1, i), 4) - w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) - g, q, r = g + w*f, q + w*u, r + w*v - return eta, (u, v, q, r) - -def modinv_var(M, Mi, x): - """Compute the modular inverse of x mod M, given Mi = 1/M mod 2^N.""" - eta, f, g, d, e = -1, M, x, 0, 1 - while g != 0: - eta, t = divsteps_n_matrix_var(eta, f % 2**N, g % 2**N) - f, g = update_fg(f, g, t) - d, e = update_de(d, e, t, M, Mi) - return normalize(f, d, Mi) -``` - -## 8. From GCDs to Jacobi symbol - -We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an -extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we -make corresponding updates to *j* using -[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): -* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). -* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). - -These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied -very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this -calculation is slightly simpler than the one for the modular inverse because we no longer need to -keep track of *d* and *e*. - -However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for -positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative -values. We resolve this by using the following modified steps: - -```python - # Before - if delta > 0 and g & 1: - delta, f, g = 1 - delta, g, (g - f) // 2 - - # After - if delta > 0 and g & 1: - delta, f, g = 1 - delta, g, (g + f) // 2 -``` - -The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 -and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm -will converge. The justification for posdivsteps is completely empirical: in practice, it appears -that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a -number of steps proportional to their logarithm. - -Note that: -- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. -- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. -- We need to update the termination condition from *g=0* to *f=1*. - -We account for the possibility of nonconvergence by only performing a bounded number of -posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not -yet been found. - -The optimizations in sections 3-7 above are described in the context of the original divsteps, but -in the C implementation we also adapt most of them (not including "avoiding modulus operations", -since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate -Jacobi symbols for secret data) to the posdivsteps version. diff --git a/external/secp256k1/examples/CMakeLists.txt b/external/secp256k1/examples/CMakeLists.txt deleted file mode 100644 index c9da9de6be..0000000000 --- a/external/secp256k1/examples/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -function(add_example name) - set(target_name ${name}_example) - add_executable(${target_name} ${name}.c) - target_include_directories(${target_name} PRIVATE - ${PROJECT_SOURCE_DIR}/include - ) - target_link_libraries(${target_name} - secp256k1 - $<$:bcrypt> - ) - set(test_name ${name}_example) - add_test(NAME secp256k1_${test_name} COMMAND ${target_name}) -endfunction() - -add_example(ecdsa) - -if(SECP256K1_ENABLE_MODULE_ECDH) - add_example(ecdh) -endif() - -if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - add_example(schnorr) -endif() - -if(SECP256K1_ENABLE_MODULE_ELLSWIFT) - add_example(ellswift) -endif() - -if(SECP256K1_ENABLE_MODULE_MUSIG) - add_example(musig) -endif() diff --git a/external/secp256k1/examples/EXAMPLES_COPYING b/external/secp256k1/examples/EXAMPLES_COPYING deleted file mode 100644 index 0e259d42c9..0000000000 --- a/external/secp256k1/examples/EXAMPLES_COPYING +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/external/secp256k1/examples/ecdh.c b/external/secp256k1/examples/ecdh.c deleted file mode 100644 index 13aa760b2d..0000000000 --- a/external/secp256k1/examples/ecdh.c +++ /dev/null @@ -1,120 +0,0 @@ -/************************************************************************* - * Written in 2020-2022 by Elichai Turkel * - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -#include -#include -#include - -#include -#include - -#include "examples_util.h" - -int main(void) { - unsigned char seckey1[32]; - unsigned char seckey2[32]; - unsigned char compressed_pubkey1[33]; - unsigned char compressed_pubkey2[33]; - unsigned char shared_secret1[32]; - unsigned char shared_secret2[32]; - unsigned char randomize[32]; - int return_val; - size_t len; - secp256k1_pubkey pubkey1; - secp256k1_pubkey pubkey2; - - /* Before we can call actual API functions, we need to create a "context". */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - if (!fill_random(randomize, sizeof(randomize))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Randomizing the context is recommended to protect against side-channel - * leakage See `secp256k1_context_randomize` in secp256k1.h for more - * information about it. This should never fail. */ - return_val = secp256k1_context_randomize(ctx, randomize); - assert(return_val); - - /*** Key Generation ***/ - if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we fail. Note that the probability of this occurring is negligible - * with a properly functioning random number generator. */ - if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { - printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); - return 1; - } - - /* Public key creation using a valid context with a verified secret key should never fail */ - return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1); - assert(return_val); - return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2); - assert(return_val); - - /* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */ - len = sizeof(compressed_pubkey1); - return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED); - assert(return_val); - /* Should be the same size as the size of the output, because we passed a 33 byte array. */ - assert(len == sizeof(compressed_pubkey1)); - - /* Serialize pubkey2 in a compressed form (33 bytes) */ - len = sizeof(compressed_pubkey2); - return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED); - assert(return_val); - /* Should be the same size as the size of the output, because we passed a 33 byte array. */ - assert(len == sizeof(compressed_pubkey2)); - - /*** Creating the shared secret ***/ - - /* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified - * seckey and valid pubkey */ - return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL); - assert(return_val); - - /* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified - * seckey and valid pubkey */ - return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL); - assert(return_val); - - /* Both parties should end up with the same shared secret */ - return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); - assert(return_val == 0); - - printf("Secret Key1: "); - print_hex(seckey1, sizeof(seckey1)); - printf("Compressed Pubkey1: "); - print_hex(compressed_pubkey1, sizeof(compressed_pubkey1)); - printf("\nSecret Key2: "); - print_hex(seckey2, sizeof(seckey2)); - printf("Compressed Pubkey2: "); - print_hex(compressed_pubkey2, sizeof(compressed_pubkey2)); - printf("\nShared Secret: "); - print_hex(shared_secret1, sizeof(shared_secret1)); - - /* This will clear everything from the context and free the memory */ - secp256k1_context_destroy(ctx); - - /* It's best practice to try to clear secrets from memory after using them. - * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), or the OS - * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. - * - * Here we are preventing these writes from being optimized out, as any good compiler - * will remove any writes that aren't used. */ - secure_erase(seckey1, sizeof(seckey1)); - secure_erase(seckey2, sizeof(seckey2)); - secure_erase(shared_secret1, sizeof(shared_secret1)); - secure_erase(shared_secret2, sizeof(shared_secret2)); - - return 0; -} diff --git a/external/secp256k1/examples/ecdsa.c b/external/secp256k1/examples/ecdsa.c deleted file mode 100644 index 80ae9d46c5..0000000000 --- a/external/secp256k1/examples/ecdsa.c +++ /dev/null @@ -1,137 +0,0 @@ -/************************************************************************* - * Written in 2020-2022 by Elichai Turkel * - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -#include -#include -#include - -#include - -#include "examples_util.h" - -int main(void) { - /* Instead of signing the message directly, we must sign a 32-byte hash. - * Here the message is "Hello, world!" and the hash function was SHA-256. - * An actual implementation should just call SHA-256, but this example - * hardcodes the output to avoid depending on an additional library. - * See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */ - unsigned char msg_hash[32] = { - 0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4, - 0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64, - 0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34, - 0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3, - }; - unsigned char seckey[32]; - unsigned char randomize[32]; - unsigned char compressed_pubkey[33]; - unsigned char serialized_signature[64]; - size_t len; - int is_signature_valid, is_signature_valid2; - int return_val; - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - /* Before we can call actual API functions, we need to create a "context". */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - if (!fill_random(randomize, sizeof(randomize))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Randomizing the context is recommended to protect against side-channel - * leakage See `secp256k1_context_randomize` in secp256k1.h for more - * information about it. This should never fail. */ - return_val = secp256k1_context_randomize(ctx, randomize); - assert(return_val); - - /*** Key Generation ***/ - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we fail. Note that the probability of this occurring is negligible - * with a properly functioning random number generator. */ - if (!secp256k1_ec_seckey_verify(ctx, seckey)) { - printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); - return 1; - } - - /* Public key creation using a valid context with a verified secret key should never fail */ - return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey); - assert(return_val); - - /* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */ - len = sizeof(compressed_pubkey); - return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED); - assert(return_val); - /* Should be the same size as the size of the output, because we passed a 33 byte array. */ - assert(len == sizeof(compressed_pubkey)); - - /*** Signing ***/ - - /* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a - * custom nonce function, passing `NULL` will use the RFC-6979 safe default. - * Signing with a valid context, verified secret key - * and the default nonce function should never fail. */ - return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL); - assert(return_val); - - /* Serialize the signature in a compact form. Should always return 1 - * according to the documentation in secp256k1.h. */ - return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig); - assert(return_val); - - - /*** Verification ***/ - - /* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */ - if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) { - printf("Failed parsing the signature\n"); - return 1; - } - - /* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ - if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) { - printf("Failed parsing the public key\n"); - return 1; - } - - /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ - is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey); - - printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); - printf("Secret Key: "); - print_hex(seckey, sizeof(seckey)); - printf("Public Key: "); - print_hex(compressed_pubkey, sizeof(compressed_pubkey)); - printf("Signature: "); - print_hex(serialized_signature, sizeof(serialized_signature)); - - /* This will clear everything from the context and free the memory */ - secp256k1_context_destroy(ctx); - - /* Bonus example: if all we need is signature verification (and no key - generation or signing), we don't need to use a context created via - secp256k1_context_create(). We can simply use the static (i.e., global) - context secp256k1_context_static. See its description in - include/secp256k1.h for details. */ - is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static, - &sig, msg_hash, &pubkey); - assert(is_signature_valid2 == is_signature_valid); - - /* It's best practice to try to clear secrets from memory after using them. - * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), or the OS - * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. - * - * Here we are preventing these writes from being optimized out, as any good compiler - * will remove any writes that aren't used. */ - secure_erase(seckey, sizeof(seckey)); - - return 0; -} diff --git a/external/secp256k1/examples/ellswift.c b/external/secp256k1/examples/ellswift.c deleted file mode 100644 index afb2fee40b..0000000000 --- a/external/secp256k1/examples/ellswift.c +++ /dev/null @@ -1,121 +0,0 @@ -/************************************************************************* - * Written in 2024 by Sebastian Falbesoner * - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -/** This file demonstrates how to use the ElligatorSwift module to perform - * a key exchange according to BIP 324. Additionally, see the documentation - * in include/secp256k1_ellswift.h and doc/ellswift.md. - */ - -#include -#include -#include - -#include -#include - -#include "examples_util.h" - -int main(void) { - secp256k1_context* ctx; - unsigned char randomize[32]; - unsigned char auxrand1[32]; - unsigned char auxrand2[32]; - unsigned char seckey1[32]; - unsigned char seckey2[32]; - unsigned char ellswift_pubkey1[64]; - unsigned char ellswift_pubkey2[64]; - unsigned char shared_secret1[32]; - unsigned char shared_secret2[32]; - int return_val; - - /* Create a secp256k1 context */ - ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - if (!fill_random(randomize, sizeof(randomize))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Randomizing the context is recommended to protect against side-channel - * leakage. See `secp256k1_context_randomize` in secp256k1.h for more - * information about it. This should never fail. */ - return_val = secp256k1_context_randomize(ctx, randomize); - assert(return_val); - - /*** Generate secret keys ***/ - if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we fail. Note that the probability of this occurring is negligible - * with a properly functioning random number generator. */ - if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { - printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); - return 1; - } - - /* Generate ElligatorSwift public keys. This should never fail with valid context and - verified secret keys. Note that providing additional randomness (fourth parameter) is - optional, but recommended. */ - if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) { - printf("Failed to generate randomness\n"); - return 1; - } - return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1); - assert(return_val); - return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2); - assert(return_val); - - /*** Create the shared secret on each side ***/ - - /* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail - * with a verified seckey and valid pubkey. Note that both parties pass both - * EllSwift pubkeys in the same order; the pubkey of the calling party is - * determined by the "party" boolean (sixth parameter). */ - return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2, - seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL); - assert(return_val); - - /* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail - * with a verified seckey and valid pubkey. */ - return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2, - seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, NULL); - assert(return_val); - - /* Both parties should end up with the same shared secret */ - return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); - assert(return_val == 0); - - printf( " Secret Key1: "); - print_hex(seckey1, sizeof(seckey1)); - printf( "EllSwift Pubkey1: "); - print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1)); - printf("\n Secret Key2: "); - print_hex(seckey2, sizeof(seckey2)); - printf( "EllSwift Pubkey2: "); - print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2)); - printf("\n Shared Secret: "); - print_hex(shared_secret1, sizeof(shared_secret1)); - - /* This will clear everything from the context and free the memory */ - secp256k1_context_destroy(ctx); - - /* It's best practice to try to clear secrets from memory after using them. - * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), or the OS - * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. - * - * Here we are preventing these writes from being optimized out, as any good compiler - * will remove any writes that aren't used. */ - secure_erase(seckey1, sizeof(seckey1)); - secure_erase(seckey2, sizeof(seckey2)); - secure_erase(shared_secret1, sizeof(shared_secret1)); - secure_erase(shared_secret2, sizeof(shared_secret2)); - - return 0; -} diff --git a/external/secp256k1/examples/examples_util.h b/external/secp256k1/examples/examples_util.h deleted file mode 100644 index 3293b64032..0000000000 --- a/external/secp256k1/examples/examples_util.h +++ /dev/null @@ -1,108 +0,0 @@ -/************************************************************************* - * Copyright (c) 2020-2021 Elichai Turkel * - * Distributed under the CC0 software license, see the accompanying file * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -/* - * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems. - * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below. - * - * Platform randomness sources: - * Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom - * macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html - * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 - * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom - * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom - */ - -#if defined(_WIN32) -/* - * The defined WIN32_NO_STATUS macro disables return code definitions in - * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. - */ -#define WIN32_NO_STATUS -#include -#undef WIN32_NO_STATUS -#include -#include -#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) -#include -#elif defined(__OpenBSD__) -#include -#else -#error "Couldn't identify the OS" -#endif - -#include -#include -#include - - -/* Returns 1 on success, and 0 on failure. */ -static int fill_random(unsigned char* data, size_t size) { -#if defined(_WIN32) - NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); - if (res != STATUS_SUCCESS || size > ULONG_MAX) { - return 0; - } else { - return 1; - } -#elif defined(__linux__) || defined(__FreeBSD__) - /* If `getrandom(2)` is not available you should fallback to /dev/urandom */ - ssize_t res = getrandom(data, size, 0); - if (res < 0 || (size_t)res != size ) { - return 0; - } else { - return 1; - } -#elif defined(__APPLE__) || defined(__OpenBSD__) - /* If `getentropy(2)` is not available you should fallback to either - * `SecRandomCopyBytes` or /dev/urandom */ - int res = getentropy(data, size); - if (res == 0) { - return 1; - } else { - return 0; - } -#endif - return 0; -} - -static void print_hex(unsigned char* data, size_t size) { - size_t i; - printf("0x"); - for (i = 0; i < size; i++) { - printf("%02x", data[i]); - } - printf("\n"); -} - -#if defined(_MSC_VER) -// For SecureZeroMemory -#include -#endif -/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ -static void secure_erase(void *ptr, size_t len) { -#if defined(_MSC_VER) - /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ - SecureZeroMemory(ptr, len); -#elif defined(__GNUC__) - /* We use a memory barrier that scares the compiler away from optimizing out the memset. - * - * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f - * in BoringSSL (ISC License): - * As best as we can tell, this is sufficient to break any optimisations that - * might try to eliminate "superfluous" memsets. - * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is - * pretty efficient, because the compiler can still implement the memset() efficiently, - * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by - * Yang et al. (USENIX Security 2017) for more background. - */ - memset(ptr, 0, len); - __asm__ __volatile__("" : : "r"(ptr) : "memory"); -#else - void *(*volatile const volatile_memset)(void *, int, size_t) = memset; - volatile_memset(ptr, 0, len); -#endif -} diff --git a/external/secp256k1/examples/musig.c b/external/secp256k1/examples/musig.c deleted file mode 100644 index 0352dc40f3..0000000000 --- a/external/secp256k1/examples/musig.c +++ /dev/null @@ -1,260 +0,0 @@ -/************************************************************************* - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -/** This file demonstrates how to use the MuSig module to create a - * 3-of-3 multisignature. Additionally, see the documentation in - * include/secp256k1_musig.h and doc/musig.md. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "examples_util.h" - -struct signer_secrets { - secp256k1_keypair keypair; - secp256k1_musig_secnonce secnonce; -}; - -struct signer { - secp256k1_pubkey pubkey; - secp256k1_musig_pubnonce pubnonce; - secp256k1_musig_partial_sig partial_sig; -}; - - /* Number of public keys involved in creating the aggregate signature */ -#define N_SIGNERS 3 -/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ -static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { - unsigned char seckey[32]; - - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 0; - } - /* Try to create a keypair with a valid context. This only fails if the - * secret key is zero or out of range (greater than secp256k1's order). Note - * that the probability of this occurring is negligible with a properly - * functioning random number generator. */ - if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { - return 0; - } - if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { - return 0; - } - - secure_erase(seckey, sizeof(seckey)); - return 1; -} - -/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache - * and return the tweaked aggregate pk. */ -static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) { - secp256k1_pubkey output_pk; - /* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP - * 32. */ - unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; - /* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as - * defined in BIP 341 */ - unsigned char xonly_tweak[32] = "this could be a Taproot tweak.."; - - - /* Plain tweaking which, for example, allows deriving multiple child - * public keys from a single aggregate key using BIP32 */ - if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { - return 0; - } - /* Note that we did not provide an output_pk argument, because the - * resulting pk is also saved in the cache and so if one is just interested - * in signing, the output_pk argument is unnecessary. On the other hand, if - * one is not interested in signing, the same output_pk can be obtained by - * calling `secp256k1_musig_pubkey_get` right after key aggregation to get - * the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */ - - /* Xonly tweaking which, for example, allows creating Taproot commitments */ - if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) { - return 0; - } - /* Note that if we wouldn't care about signing, we can arrive at the same - * output_pk by providing the untweaked public key to - * `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey - * if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */ - - /* Now we convert the output_pk to an xonly pubkey to allow to later verify - * the Schnorr signature against it. For this purpose we can ignore the - * `pk_parity` output argument; we would need it if we would have to open - * the Taproot commitment. */ - if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { - return 0; - } - return 1; -} - -/* Sign a message hash with the given key pairs and store the result in sig */ -static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) { - int i; - const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS]; - const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS]; - /* The same for all signers */ - secp256k1_musig_session session; - secp256k1_musig_aggnonce agg_pubnonce; - - for (i = 0; i < N_SIGNERS; i++) { - unsigned char seckey[32]; - unsigned char session_secrand[32]; - /* Create random session ID. It is absolutely necessary that the session ID - * is unique for every call of secp256k1_musig_nonce_gen. Otherwise - * it's trivial for an attacker to extract the secret key! */ - if (!fill_random(session_secrand, sizeof(session_secrand))) { - return 0; - } - if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { - return 0; - } - /* Initialize session and create secret nonce for signing and public - * nonce to send to the other signers. */ - if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { - return 0; - } - pubnonces[i] = &signer[i].pubnonce; - - secure_erase(seckey, sizeof(seckey)); - } - - /* Communication round 1: Every signer sends their pubnonce to the - * coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends - * agg_pubnonce to each signer */ - if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { - return 0; - } - - /* Every signer creates a partial signature */ - for (i = 0; i < N_SIGNERS; i++) { - /* Initialize the signing session by processing the aggregate nonce */ - if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) { - return 0; - } - /* partial_sign will clear the secnonce by setting it to 0. That's because - * you must _never_ reuse the secnonce (or use the same session_secrand to - * create a secnonce). If you do, you effectively reuse the nonce and - * leak the secret key. */ - if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { - return 0; - } - partial_sigs[i] = &signer[i].partial_sig; - } - /* Communication round 2: Every signer sends their partial signature to the - * coordinator, who verifies the partial signatures and aggregates them. */ - for (i = 0; i < N_SIGNERS; i++) { - /* To check whether signing was successful, it suffices to either verify - * the aggregate signature with the aggregate public key using - * secp256k1_schnorrsig_verify, or verify all partial signatures of all - * signers individually. Verifying the aggregate signature is cheaper but - * verifying the individual partial signatures has the advantage that it - * can be used to determine which of the partial signatures are invalid - * (if any), i.e., which of the partial signatures cause the aggregate - * signature to be invalid and thus the protocol run to fail. It's also - * fine to first verify the aggregate sig, and only verify the individual - * sigs if it does not work. - */ - if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) { - return 0; - } - } - return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); -} - -int main(void) { - secp256k1_context* ctx; - int i; - struct signer_secrets signer_secrets[N_SIGNERS]; - struct signer signers[N_SIGNERS]; - const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS]; - secp256k1_xonly_pubkey agg_pk; - secp256k1_musig_keyagg_cache cache; - unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; - unsigned char sig[64]; - - /* Create a secp256k1 context */ - ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - printf("Creating key pairs......"); - fflush(stdout); - for (i = 0; i < N_SIGNERS; i++) { - if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { - printf("FAILED\n"); - return 1; - } - pubkeys_ptr[i] = &signers[i].pubkey; - } - printf("ok\n"); - - /* The aggregate public key produced by secp256k1_musig_pubkey_agg depends - * on the order of the provided public keys. If there is no canonical order - * of the signers, the individual public keys can optionally be sorted with - * secp256k1_ec_pubkey_sort to ensure that the aggregate public key is - * independent of the order of signers. */ - printf("Sorting public keys....."); - fflush(stdout); - if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - - printf("Combining public keys..."); - fflush(stdout); - /* If you just want to aggregate and not sign, you can call - * secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL - * while providing a non-NULL agg_pk argument. */ - if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Tweaking................"); - fflush(stdout); - /* Optionally tweak the aggregate key */ - if (!tweak(ctx, &agg_pk, &cache)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Signing message........."); - fflush(stdout); - if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Verifying signature....."); - fflush(stdout); - if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - - /* It's best practice to try to clear secrets from memory after using them. - * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), or the OS - * swapping them to disk. Hence, we overwrite secret key material with zeros. - * - * Here we are preventing these writes from being optimized out, as any good compiler - * will remove any writes that aren't used. */ - for (i = 0; i < N_SIGNERS; i++) { - secure_erase(&signer_secrets[i], sizeof(signer_secrets[i])); - } - secp256k1_context_destroy(ctx); - return 0; -} diff --git a/external/secp256k1/examples/schnorr.c b/external/secp256k1/examples/schnorr.c deleted file mode 100644 index 909fcaa1f3..0000000000 --- a/external/secp256k1/examples/schnorr.c +++ /dev/null @@ -1,153 +0,0 @@ -/************************************************************************* - * Written in 2020-2022 by Elichai Turkel * - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -#include -#include -#include - -#include -#include -#include - -#include "examples_util.h" - -int main(void) { - unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; - unsigned char msg_hash[32]; - unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'}; - unsigned char seckey[32]; - unsigned char randomize[32]; - unsigned char auxiliary_rand[32]; - unsigned char serialized_pubkey[32]; - unsigned char signature[64]; - int is_signature_valid, is_signature_valid2; - int return_val; - secp256k1_xonly_pubkey pubkey; - secp256k1_keypair keypair; - /* Before we can call actual API functions, we need to create a "context". */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - if (!fill_random(randomize, sizeof(randomize))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Randomizing the context is recommended to protect against side-channel - * leakage See `secp256k1_context_randomize` in secp256k1.h for more - * information about it. This should never fail. */ - return_val = secp256k1_context_randomize(ctx, randomize); - assert(return_val); - - /*** Key Generation ***/ - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Try to create a keypair with a valid context. This only fails if the - * secret key is zero or out of range (greater than secp256k1's order). Note - * that the probability of this occurring is negligible with a properly - * functioning random number generator. */ - if (!secp256k1_keypair_create(ctx, &keypair, seckey)) { - printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); - return 1; - } - - /* Extract the X-only public key from the keypair. We pass NULL for - * `pk_parity` as the parity isn't needed for signing or verification. - * `secp256k1_keypair_xonly_pub` supports returning the parity for - * other use cases such as tests or verifying Taproot tweaks. - * This should never fail with a valid context and public key. */ - return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair); - assert(return_val); - - /* Serialize the public key. Should always return 1 for a valid public key. */ - return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey); - assert(return_val); - - /*** Signing ***/ - - /* Instead of signing (possibly very long) messages directly, we sign a - * 32-byte hash of the message in this example. - * - * We use secp256k1_tagged_sha256 to create this hash. This function expects - * a context-specific "tag", which restricts the context in which the signed - * messages should be considered valid. For example, if protocol A mandates - * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag - * "my_boring_protocol", then signed messages from protocol A will never be - * valid in protocol B (and vice versa), even if keys are reused across - * protocols. This implements "domain separation", which is considered good - * practice. It avoids attacks in which users are tricked into signing a - * message that has intended consequences in the intended context (e.g., - * protocol A) but would have unintended consequences if it were valid in - * some other context (e.g., protocol B). */ - return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); - assert(return_val); - - /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */ - if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) { - printf("Failed to generate randomness\n"); - return 1; - } - - /* Generate a Schnorr signature. - * - * We use the secp256k1_schnorrsig_sign32 function that provides a simple - * interface for signing 32-byte messages (which in our case is a hash of - * the actual message). BIP-340 recommends passing 32 bytes of randomness - * to the signing function to improve security against side-channel attacks. - * Signing with a valid context, a 32-byte message, a verified keypair, and - * any 32 bytes of auxiliary random data should never fail. */ - return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand); - assert(return_val); - - /*** Verification ***/ - - /* Deserialize the public key. This will return 0 if the public key can't - * be parsed correctly */ - if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) { - printf("Failed parsing the public key\n"); - return 1; - } - - /* Compute the tagged hash on the received messages using the same tag as the signer. */ - return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); - assert(return_val); - - /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ - is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey); - - - printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); - printf("Secret Key: "); - print_hex(seckey, sizeof(seckey)); - printf("Public Key: "); - print_hex(serialized_pubkey, sizeof(serialized_pubkey)); - printf("Signature: "); - print_hex(signature, sizeof(signature)); - - /* This will clear everything from the context and free the memory */ - secp256k1_context_destroy(ctx); - - /* Bonus example: if all we need is signature verification (and no key - generation or signing), we don't need to use a context created via - secp256k1_context_create(). We can simply use the static (i.e., global) - context secp256k1_context_static. See its description in - include/secp256k1.h for details. */ - is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static, - signature, msg_hash, 32, &pubkey); - assert(is_signature_valid2 == is_signature_valid); - - /* It's best practice to try to clear secrets from memory after using them. - * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), or the OS - * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. - * - * Here we are preventing these writes from being optimized out, as any good compiler - * will remove any writes that aren't used. */ - secure_erase(seckey, sizeof(seckey)); - return 0; -} diff --git a/external/secp256k1/include/secp256k1.h b/external/secp256k1/include/secp256k1.h deleted file mode 100644 index c6e9417f05..0000000000 --- a/external/secp256k1/include/secp256k1.h +++ /dev/null @@ -1,899 +0,0 @@ -#ifndef SECP256K1_H -#define SECP256K1_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** Unless explicitly stated all pointer arguments must not be NULL. - * - * The following rules specify the order of arguments in API calls: - * - * 1. Context pointers go first, followed by output arguments, combined - * output/input arguments, and finally input-only arguments. - * 2. Array lengths always immediately follow the argument whose length - * they describe, even if this violates rule 1. - * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated - * later go first. This means: signatures, public nonces, secret nonces, - * messages, public keys, secret keys, tweaks. - * 4. Arguments that are not data pointers go last, from more complex to less - * complex: function pointers, algorithm names, messages, void pointers, - * counts, flags, booleans. - * 5. Opaque data pointers follow the function pointer they are to be passed to. - */ - -/** Opaque data structure that holds context information - * - * The primary purpose of context objects is to store randomization data for - * enhanced protection against side-channel leakage. This protection is only - * effective if the context is randomized after its creation. See - * secp256k1_context_create for creation of contexts and - * secp256k1_context_randomize for randomization. - * - * A secondary purpose of context objects is to store pointers to callback - * functions that the library will call when certain error states arise. See - * secp256k1_context_set_error_callback as well as - * secp256k1_context_set_illegal_callback for details. Future library versions - * may use context objects for additional purposes. - * - * A constructed context can safely be used from multiple threads - * simultaneously, but API calls that take a non-const pointer to a context - * need exclusive access to it. In particular this is the case for - * secp256k1_context_destroy, secp256k1_context_preallocated_destroy, - * and secp256k1_context_randomize. - * - * Regarding randomization, either do it once at creation time (in which case - * you do not need any locking for the other calls), or use a read-write lock. - */ -typedef struct secp256k1_context_struct secp256k1_context; - -/** Opaque data structure that holds a parsed and valid public key. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, - * use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To - * compare keys, use secp256k1_ec_pubkey_cmp. - */ -typedef struct secp256k1_pubkey { - unsigned char data[64]; -} secp256k1_pubkey; - -/** Opaque data structure that holds a parsed ECDSA signature. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_parse_* functions. - */ -typedef struct secp256k1_ecdsa_signature { - unsigned char data[64]; -} secp256k1_ecdsa_signature; - -/** A pointer to a function to deterministically generate a nonce. - * - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. - * Out: nonce32: pointer to a 32-byte array to be filled by the function. - * In: msg32: the 32-byte message hash being verified (will not be NULL) - * key32: pointer to a 32-byte secret key (will not be NULL) - * algo16: pointer to a 16-byte array describing the signature - * algorithm (will be NULL for ECDSA for compatibility). - * data: Arbitrary data pointer that is passed through. - * attempt: how many iterations we have tried to find a nonce. - * This will almost always be 0, but different attempt values - * are required to result in a different nonce. - * - * Except for test cases, this function should compute some cryptographic hash of - * the message, the algorithm, the key and the attempt. - */ -typedef int (*secp256k1_nonce_function)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - const unsigned char *algo16, - void *data, - unsigned int attempt -); - -# if !defined(SECP256K1_GNUC_PREREQ) -# if defined(__GNUC__)&&defined(__GNUC_MINOR__) -# define SECP256K1_GNUC_PREREQ(_maj,_min) \ - ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) -# else -# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 -# endif -# endif - -/* When this header is used at build-time the SECP256K1_BUILD define needs to be set - * to correctly setup export attributes and nullness checks. This is normally done - * by secp256k1.c but to guard against this header being included before secp256k1.c - * has had a chance to set the define (e.g. via test harnesses that just includes - * secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the - * BUILD define so this condition can be caught. - */ -#ifndef SECP256K1_BUILD -# define SECP256K1_NO_BUILD -#endif - -/* Symbol visibility. */ -#if defined(_WIN32) - /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax - * for MSVC compatibility. A __declspec declaration implies (but is not - * exactly equivalent to) __attribute__ ((visibility("default"))), and so we - * actually want __declspec even on GCC, see "Microsoft Windows Function - * Attributes" in the GCC manual and the recommendations in - * https://gcc.gnu.org/wiki/Visibility. */ -# if defined(SECP256K1_BUILD) -# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) - /* Building libsecp256k1 as a DLL. - * 1. If using Libtool, it defines DLL_EXPORT automatically. - * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ -# define SECP256K1_API extern __declspec (dllexport) -# else - /* Building libsecp256k1 as a static library on Windows. - * No declspec is needed, and so we would want the non-Windows-specific - * logic below take care of this case. However, this may result in setting - * __attribute__ ((visibility("default"))), which is supposed to be a noop - * on Windows but may trigger warnings when compiling with -flto due to a - * bug in GCC, see - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ -# define SECP256K1_API extern -# endif - /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static - * library on Windows. */ -# elif !defined(SECP256K1_STATIC) - /* Consuming libsecp256k1 as a DLL. */ -# define SECP256K1_API extern __declspec (dllimport) -# endif -#endif -#ifndef SECP256K1_API -/* All cases not captured by the Windows-specific logic. */ -# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) - /* Building libsecp256k1 using GCC or compatible. */ -# define SECP256K1_API extern __attribute__ ((visibility ("default"))) -# else - /* Fall back to standard C's extern. */ -# define SECP256K1_API extern -# endif -#endif - -/* Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ -# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) -# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) -# else -# define SECP256K1_WARN_UNUSED_RESULT -# endif -# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) -# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) -# else -# define SECP256K1_ARG_NONNULL(_x) -# endif - -/* Attribute for marking functions, types, and variables as deprecated */ -#if !defined(SECP256K1_BUILD) && defined(__has_attribute) -# if __has_attribute(__deprecated__) -# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) -# else -# define SECP256K1_DEPRECATED(_msg) -# endif -#else -# define SECP256K1_DEPRECATED(_msg) -#endif - -/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ -#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) -#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) -#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/* The higher bits contain the actual data. Do not use directly. */ -#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) -#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) -#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) -#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) - -/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and - * secp256k1_context_preallocated_create. */ -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) - -/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ -#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) -#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) - -/* Testing flag. Do not use. */ -#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) - -/** Flag to pass to secp256k1_ec_pubkey_serialize. */ -#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) -#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) - -/** Prefix byte used to tag various encoded curvepoints for specific purposes */ -#define SECP256K1_TAG_PUBKEY_EVEN 0x02 -#define SECP256K1_TAG_PUBKEY_ODD 0x03 -#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 -#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 -#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 - -/** A built-in constant secp256k1 context object with static storage duration, to be - * used in conjunction with secp256k1_selftest. - * - * This context object offers *only limited functionality* , i.e., it cannot be used - * for API functions that perform computations involving secret keys, e.g., signing - * and public key generation. If this restriction applies to a specific API function, - * it is mentioned in its documentation. See secp256k1_context_create if you need a - * full context object that supports all functionality offered by the library. - * - * It is highly recommended to call secp256k1_selftest before using this context. - */ -SECP256K1_API const secp256k1_context *secp256k1_context_static; - -/** Deprecated alias for secp256k1_context_static. */ -SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp -SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); - -/** Perform basic self tests (to be used in conjunction with secp256k1_context_static) - * - * This function performs self tests that detect some serious usage errors and - * similar conditions, e.g., when the library is compiled for the wrong endianness. - * This is a last resort measure to be used in production. The performed tests are - * very rudimentary and are not intended as a replacement for running the test - * binaries. - * - * It is highly recommended to call this before using secp256k1_context_static. - * It is not necessary to call this function before using a context created with - * secp256k1_context_create (or secp256k1_context_preallocated_create), which will - * take care of performing the self tests. - * - * If the tests fail, this function will call the default error handler to abort the - * program (see secp256k1_context_set_error_callback). - */ -SECP256K1_API void secp256k1_selftest(void); - - -/** Create a secp256k1 context object (in dynamically allocated memory). - * - * This function uses malloc to allocate memory. It is guaranteed that malloc is - * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see secp256k1_context_static and the functions in - * secp256k1_preallocated.h. - * - * Returns: pointer to a newly created context object. - * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). - * - * The only valid non-deprecated flag in recent library versions is - * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality - * offered by the library. All other (deprecated) flags will be treated as equivalent - * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for - * historical reasons, future versions of the library may introduce new flags. - * - * If the context is intended to be used for API functions that perform computations - * involving secret keys, e.g., signing and public key generation, then it is highly - * recommended to call secp256k1_context_randomize on the context before calling - * those API functions. This will provide enhanced protection against side-channel - * leakage, see secp256k1_context_randomize for details. - * - * Do not create a new context object for each operation, as construction and - * randomization can take non-negligible time. - */ -SECP256K1_API secp256k1_context *secp256k1_context_create( - unsigned int flags -) SECP256K1_WARN_UNUSED_RESULT; - -/** Copy a secp256k1 context object (into dynamically allocated memory). - * - * This function uses malloc to allocate memory. It is guaranteed that malloc is - * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in secp256k1_preallocated.h. - * - * Cloning secp256k1_context_static is not possible, and should not be emulated by - * the caller (e.g., using memcpy). Create a new context instead. - * - * Returns: pointer to a newly created context object. - * Args: ctx: pointer to a context to copy (not secp256k1_context_static). - */ -SECP256K1_API secp256k1_context *secp256k1_context_clone( - const secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; - -/** Destroy a secp256k1 context object (created in dynamically allocated memory). - * - * The context pointer may not be used afterwards. - * - * The context to destroy must have been created using secp256k1_context_create - * or secp256k1_context_clone. If the context has instead been created using - * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the - * behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must - * be used instead. - * - * Args: ctx: pointer to a context to destroy, constructed using - * secp256k1_context_create or secp256k1_context_clone - * (i.e., not secp256k1_context_static). - */ -SECP256K1_API void secp256k1_context_destroy( - secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1); - -/** Set a callback function to be called when an illegal argument is passed to - * an API call. It will only trigger for violations that are mentioned - * explicitly in the header. - * - * The philosophy is that these shouldn't be dealt with through a - * specific return value, as calling code should not have branches to deal with - * the case that this code itself is broken. - * - * On the other hand, during debug stage, one would want to be informed about - * such mistakes, and the default (crashing) may be inadvisable. - * When this callback is triggered, the API function called is guaranteed not - * to cause a crash, though its return value and output arguments are - * undefined. - * - * When this function has not been called (or called with fn==NULL), then the - * default handler will be used. The library provides a default handler which - * writes the message to stderr and calls abort. This default handler can be - * replaced at link time if the preprocessor macro - * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build - * has been configured with --enable-external-default-callbacks. Then the - * following two symbols must be provided to link against: - * - void secp256k1_default_illegal_callback_fn(const char *message, void *data); - * - void secp256k1_default_error_callback_fn(const char *message, void *data); - * The library can call these default handlers even before a proper callback data - * pointer could have been set using secp256k1_context_set_illegal_callback or - * secp256k1_context_set_error_callback, e.g., when the creation of a context - * fails. In this case, the corresponding default handler will be called with - * the data pointer argument set to NULL. - * - * Args: ctx: pointer to a context object. - * In: fun: pointer to a function to call when an illegal argument is - * passed to the API, taking a message and an opaque pointer. - * (NULL restores the default handler.) - * data: the opaque pointer to pass to fun above, must be NULL for the default handler. - * - * See also secp256k1_context_set_error_callback. - */ -SECP256K1_API void secp256k1_context_set_illegal_callback( - secp256k1_context *ctx, - void (*fun)(const char *message, void *data), - const void *data -) SECP256K1_ARG_NONNULL(1); - -/** Set a callback function to be called when an internal consistency check - * fails. - * - * The default callback writes an error message to stderr and calls abort - * to abort the program. - * - * This can only trigger in case of a hardware failure, miscompilation, - * memory corruption, serious bug in the library, or other error would can - * otherwise result in undefined behaviour. It will not trigger due to mere - * incorrect usage of the API (see secp256k1_context_set_illegal_callback - * for that). After this callback returns, anything may happen, including - * crashing. - * - * Args: ctx: pointer to a context object. - * In: fun: pointer to a function to call when an internal error occurs, - * taking a message and an opaque pointer (NULL restores the - * default handler, see secp256k1_context_set_illegal_callback - * for details). - * data: the opaque pointer to pass to fun above, must be NULL for the default handler. - * - * See also secp256k1_context_set_illegal_callback. - */ -SECP256K1_API void secp256k1_context_set_error_callback( - secp256k1_context *ctx, - void (*fun)(const char *message, void *data), - const void *data -) SECP256K1_ARG_NONNULL(1); - -/** Parse a variable-length public key into the pubkey object. - * - * Returns: 1 if the public key was fully valid. - * 0 if the public key could not be parsed or is invalid. - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a - * parsed version of input. If not, its value is undefined. - * In: input: pointer to a serialized public key - * inputlen: length of the array pointed to by input - * - * This function supports parsing compressed (33 bytes, header byte 0x02 or - * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header - * byte 0x06 or 0x07) format public keys. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a pubkey object into a serialized byte sequence. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object. - * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if - * compressed==1) byte array to place the serialized key - * in. - * In/Out: outputlen: pointer to an integer which is initially set to the - * size of output, and is overwritten with the written - * size. - * In: pubkey: pointer to a secp256k1_pubkey containing an - * initialized public key. - * flags: SECP256K1_EC_COMPRESSED if serialization should be in - * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. - */ -SECP256K1_API int secp256k1_ec_pubkey_serialize( - const secp256k1_context *ctx, - unsigned char *output, - size_t *outputlen, - const secp256k1_pubkey *pubkey, - unsigned int flags -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Compare two public keys using lexicographic (of compressed serialization) order - * - * Returns: <0 if the first public key is less than the second - * >0 if the first public key is greater than the second - * 0 if the two public keys are equal - * Args: ctx: pointer to a context object - * In: pubkey1: first public key to compare - * pubkey2: second public key to compare - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp( - const secp256k1_context *ctx, - const secp256k1_pubkey *pubkey1, - const secp256k1_pubkey *pubkey2 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Sort public keys using lexicographic (of compressed serialization) order - * - * Returns: 0 if the arguments are invalid. 1 otherwise. - * - * Args: ctx: pointer to a context object - * In: pubkeys: array of pointers to pubkeys to sort - * n_pubkeys: number of elements in the pubkeys array - */ -SECP256K1_API int secp256k1_ec_pubkey_sort( - const secp256k1_context *ctx, - const secp256k1_pubkey **pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Parse an ECDSA signature in compact (64 bytes) format. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: pointer to a context object - * Out: sig: pointer to a signature object - * In: input64: pointer to the 64-byte array to parse - * - * The signature must consist of a 32-byte big endian R value, followed by a - * 32-byte big endian S value. If R or S fall outside of [0..order-1], the - * encoding is invalid. R and S with value 0 are allowed in the encoding. - * - * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail verification for - * any message and public key. - */ -SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( - const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sig, - const unsigned char *input64 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse a DER ECDSA signature. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: pointer to a context object - * Out: sig: pointer to a signature object - * In: input: pointer to the signature to be parsed - * inputlen: the length of the array pointed to be input - * - * This function will accept any valid DER encoded signature, even if the - * encoded numbers are out of range. - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature verification with it is - * guaranteed to fail for every message and public key. - */ -SECP256K1_API int secp256k1_ecdsa_signature_parse_der( - const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sig, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an ECDSA signature in DER format. - * - * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: pointer to a context object - * Out: output: pointer to an array to store the DER serialization - * In/Out: outputlen: pointer to a length integer. Initially, this integer - * should be set to the length of output. After the call - * it will be set to the length of the serialization (even - * if 0 was returned). - * In: sig: pointer to an initialized signature object - */ -SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( - const secp256k1_context *ctx, - unsigned char *output, - size_t *outputlen, - const secp256k1_ecdsa_signature *sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Serialize an ECDSA signature in compact (64 byte) format. - * - * Returns: 1 - * Args: ctx: pointer to a context object - * Out: output64: pointer to a 64-byte array to store the compact serialization - * In: sig: pointer to an initialized signature object - * - * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. - */ -SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( - const secp256k1_context *ctx, - unsigned char *output64, - const secp256k1_ecdsa_signature *sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Verify an ECDSA signature. - * - * Returns: 1: correct signature - * 0: incorrect or unparseable signature - * Args: ctx: pointer to a context object - * In: sig: the signature being verified. - * msghash32: the 32-byte message hash being verified. - * The verifier must make sure to apply a cryptographic - * hash function to the message by itself and not accept an - * msghash32 value directly. Otherwise, it would be easy to - * create a "valid" signature without knowledge of the - * secret key. See also - * https://bitcoin.stackexchange.com/a/81116/35586 for more - * background on this topic. - * pubkey: pointer to an initialized public key to verify with. - * - * To avoid accepting malleable signatures, only ECDSA signatures in lower-S - * form are accepted. - * - * If you need to accept ECDSA signatures from sources that do not obey this - * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to - * verification, but be aware that doing so results in malleable signatures. - * - * For details, see the comments for that function. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context *ctx, - const secp256k1_ecdsa_signature *sig, - const unsigned char *msghash32, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Convert a signature to a normalized lower-S form. - * - * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: pointer to a context object - * Out: sigout: pointer to a signature to fill with the normalized form, - * or copy if the input was already normalized. (can be NULL if - * you're only interested in whether the input was already - * normalized). - * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) - * - * With ECDSA a third-party can forge a second distinct signature of the same - * message, given a single initial signature, but without knowing the key. This - * is done by negating the S value modulo the order of the curve, 'flipping' - * the sign of the random point R which is not included in the signature. - * - * Forgery of the same message isn't universally problematic, but in systems - * where message malleability or uniqueness of signatures is important this can - * cause issues. This forgery can be blocked by all verifiers forcing signers - * to use a normalized form. - * - * The lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to verify, - * making it a good choice. Security of always using lower-S is assured because - * anyone can trivially modify a signature after the fact to enforce this - * property anyway. - * - * The lower S value is always between 0x1 and - * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive. - * - * No other forms of ECDSA malleability are known and none seem likely, but - * there is no formal proof that ECDSA, even with this additional restriction, - * is free of other malleability. Commonly used serialization schemes will also - * accept various non-unique encodings, so care should be taken when this - * property is required for an application. - * - * The secp256k1_ecdsa_sign function will by default create signatures in the - * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case - * signatures come from a system that cannot enforce this property, - * secp256k1_ecdsa_signature_normalize must be called before verification. - */ -SECP256K1_API int secp256k1_ecdsa_signature_normalize( - const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sigout, - const secp256k1_ecdsa_signature *sigin -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); - -/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. - * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of - * extra entropy. - */ -SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; - -/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; - -/** Create an ECDSA signature. - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. - * In: msghash32: the 32-byte message hash being signed. - * seckey: pointer to a 32-byte secret key. - * noncefp: pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used. - * ndata: pointer to arbitrary data used by the nonce generation function - * (can be NULL). If it is non-NULL and - * secp256k1_nonce_function_default is used, then ndata must be a - * pointer to 32-bytes of additional data. - * - * The created signature is always in lower-S form. See - * secp256k1_ecdsa_signature_normalize for more details. - */ -SECP256K1_API int secp256k1_ecdsa_sign( - const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sig, - const unsigned char *msghash32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Verify an elliptic curve secret key. - * - * A secret key is valid if it is not 0 and less than the secp256k1 curve order - * when interpreted as an integer (most significant byte first). The - * probability of choosing a 32-byte string uniformly at random which is an - * invalid secret key is negligible. However, if it does happen it should - * be assumed that the randomness source is severely broken and there should - * be no retry. - * - * Returns: 1: secret key is valid - * 0: secret key is invalid - * Args: ctx: pointer to a context object. - * In: seckey: pointer to a 32-byte secret key. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( - const secp256k1_context *ctx, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Compute the public key for a secret key. - * - * Returns: 1: secret was valid, public key stores. - * 0: secret was invalid, try again. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: pubkey: pointer to the created public key. - * In: seckey: pointer to a 32-byte secret key. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Negates a secret key in place. - * - * Returns: 0 if the given secret key is invalid according to - * secp256k1_ec_seckey_verify. 1 otherwise - * Args: ctx: pointer to a context object - * In/Out: seckey: pointer to the 32-byte secret key to be negated. If the - * secret key is invalid according to - * secp256k1_ec_seckey_verify, this function returns 0 and - * seckey will be set to some unspecified value. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( - const secp256k1_context *ctx, - unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( - const secp256k1_context *ctx, - unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead"); - -/** Negates a public key in place. - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * In/Out: pubkey: pointer to the public key to be negated. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Tweak a secret key by adding tweak to it. - * - * Returns: 0 if the arguments are invalid or the resulting secret key would be - * invalid (only when the tweak is the negation of the secret key). 1 - * otherwise. - * Args: ctx: pointer to a context object. - * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to secp256k1_ec_seckey_verify, this - * function returns 0. seckey will be set to some unspecified - * value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak, which must be valid according to - * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly - * random 32-byte tweaks, the chance of being invalid is - * negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead"); - -/** Tweak a public key by adding tweak times the generator to it. - * - * Returns: 0 if the arguments are invalid or the resulting public key would be - * invalid (only when the tweak is the negation of the corresponding - * secret key). 1 otherwise. - * Args: ctx: pointer to a context object. - * In/Out: pubkey: pointer to a public key object. pubkey will be set to an - * invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak, which must be valid according to - * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly - * random 32-byte tweaks, the chance of being invalid is - * negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Tweak a secret key by multiplying it by a tweak. - * - * Returns: 0 if the arguments are invalid. 1 otherwise. - * Args: ctx: pointer to a context object. - * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to secp256k1_ec_seckey_verify, this - * function returns 0. seckey will be set to some unspecified - * value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * secp256k1_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead"); - -/** Tweak a public key by multiplying it by a tweak value. - * - * Returns: 0 if the arguments are invalid. 1 otherwise. - * Args: ctx: pointer to a context object. - * In/Out: pubkey: pointer to a public key object. pubkey will be set to an - * invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * secp256k1_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Randomizes the context to provide enhanced protection against side-channel leakage. - * - * Returns: 1: randomization successful - * 0: error - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). - * - * While secp256k1 code is written and tested to be constant-time no matter what - * secret values are, it is possible that a compiler may output code which is not, - * and also that the CPU may not emit the same radio frequencies or draw the same - * amount of power for all values. Randomization of the context shields against - * side-channel observations which aim to exploit secret-dependent behaviour in - * certain computations which involve secret keys. - * - * It is highly recommended to call this function on contexts returned from - * secp256k1_context_create or secp256k1_context_clone (or from the corresponding - * functions in secp256k1_preallocated.h) before using these contexts to call API - * functions that perform computations involving secret keys, e.g., signing and - * public key generation. It is possible to call this function more than once on - * the same context, and doing so before every few computations involving secret - * keys is recommended as a defense-in-depth measure. Randomization of the static - * context secp256k1_context_static is not supported. - * - * Currently, the random seed is mainly used for blinding multiplications of a - * secret scalar with the elliptic curve base point. Multiplications of this - * kind are performed by exactly those API functions which are documented to - * require a context that is not secp256k1_context_static. As a rule of thumb, - * these are all functions which take a secret key (or a keypair) as an input. - * A notable exception to that rule is the ECDH module, which relies on a different - * kind of elliptic curve point multiplication and thus does not benefit from - * enhanced protection against side-channel leakage currently. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context *ctx, - const unsigned char *seed32 -) SECP256K1_ARG_NONNULL(1); - -/** Add a number of public keys together. - * - * Returns: 1: the sum of the public keys is valid. - * 0: the sum of the public keys is not valid. - * Args: ctx: pointer to a context object. - * Out: out: pointer to a public key object for placing the resulting public key. - * In: ins: pointer to array of pointers to public keys. - * n: the number of public keys to add together (must be at least 1). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( - const secp256k1_context *ctx, - secp256k1_pubkey *out, - const secp256k1_pubkey * const *ins, - size_t n -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Compute a tagged hash as defined in BIP-340. - * - * This is useful for creating a message hash and achieving domain separation - * through an application-specific tag. This function returns - * SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash - * implementations optimized for a specific tag can precompute the SHA256 state - * after hashing the tag hashes. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object - * Out: hash32: pointer to a 32-byte array to store the resulting hash - * In: tag: pointer to an array containing the tag - * taglen: length of the tag array - * msg: pointer to an array containing the message - * msglen: length of the message array - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256( - const secp256k1_context *ctx, - unsigned char *hash32, - const unsigned char *tag, - size_t taglen, - const unsigned char *msg, - size_t msglen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_H */ diff --git a/external/secp256k1/include/secp256k1_ecdh.h b/external/secp256k1/include/secp256k1_ecdh.h deleted file mode 100644 index 4d9da3461d..0000000000 --- a/external/secp256k1/include/secp256k1_ecdh.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef SECP256K1_ECDH_H -#define SECP256K1_ECDH_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** A pointer to a function that hashes an EC point to obtain an ECDH secret - * - * Returns: 1 if the point was successfully hashed. - * 0 will cause secp256k1_ecdh to fail and return 0. - * Other return values are not allowed, and the behaviour of - * secp256k1_ecdh is undefined for other return values. - * Out: output: pointer to an array to be filled by the function - * In: x32: pointer to a 32-byte x coordinate - * y32: pointer to a 32-byte y coordinate - * data: arbitrary data pointer that is passed through - */ -typedef int (*secp256k1_ecdh_hash_function)( - unsigned char *output, - const unsigned char *x32, - const unsigned char *y32, - void *data -); - -/** An implementation of SHA256 hash function that applies to compressed public key. - * Populates the output parameter with 32 bytes. */ -SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; - -/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256). - * Populates the output parameter with 32 bytes. */ -SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; - -/** Compute an EC Diffie-Hellman secret in constant time - * - * Returns: 1: exponentiation was successful - * 0: scalar was invalid (zero or overflow) or hashfp returned 0 - * Args: ctx: pointer to a context object. - * Out: output: pointer to an array to be filled by hashfp. - * In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key. - * seckey: a 32-byte scalar with which to multiply the point. - * hashfp: pointer to a hash function. If NULL, - * secp256k1_ecdh_hash_function_sha256 is used - * (in which case, 32 bytes will be written to output). - * data: arbitrary data pointer that is passed through to hashfp - * (can be NULL for secp256k1_ecdh_hash_function_sha256). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( - const secp256k1_context *ctx, - unsigned char *output, - const secp256k1_pubkey *pubkey, - const unsigned char *seckey, - secp256k1_ecdh_hash_function hashfp, - void *data -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_ECDH_H */ diff --git a/external/secp256k1/include/secp256k1_ellswift.h b/external/secp256k1/include/secp256k1_ellswift.h deleted file mode 100644 index 0d1293e94f..0000000000 --- a/external/secp256k1/include/secp256k1_ellswift.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef SECP256K1_ELLSWIFT_H -#define SECP256K1_ELLSWIFT_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* This module provides an implementation of ElligatorSwift as well as a - * version of x-only ECDH using it (including compatibility with BIP324). - * - * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by - * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding - * uniformly chosen public keys as 64-byte arrays which are indistinguishable - * from uniformly random arrays. - * - * Let f be the function from pairs of field elements to point X coordinates, - * defined as follows (all operations modulo p = 2^256 - 2^32 - 977) - * f(u,t): - * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, - * a square root of -3. - * - If u=0, set u=1 instead. - * - If t=0, set t=1 instead. - * - If u^3 + t^2 + 7 = 0, multiply t by 2. - * - Let X = (u^3 + 7 - t^2) / (2 * t) - * - Let Y = (X + t) / (C * u) - * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an - * X coordinate on the curve (at least one of them is, for any u and t). - * - * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian - * encodings of field elements u and t concatenated, where f(u,t) = x. - * The encoding algorithm is described in the paper, and effectively picks a - * uniformly random pair (u,t) among those which encode x. - * - * If the Y coordinate is relevant, it is given the same parity as t. - * - * Changes w.r.t. the paper: - * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point - * at infinity in the paper. Here they are remapped to finite points. - * - The paper uses an additional encoding bit for the parity of y. Here the - * parity of t is used (negating t does not affect the decoded x coordinate, - * so this is possible). - * - * For mathematical background about the scheme, see the doc/ellswift.md file. - */ - -/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X - * coordinate along with the encoded public keys to a uniform shared secret. - * - * Returns: 1 if a shared secret was successfully computed. - * 0 will cause secp256k1_ellswift_xdh to fail and return 0. - * Other return values are not allowed, and the behaviour of - * secp256k1_ellswift_xdh is undefined for other return values. - * Out: output: pointer to an array to be filled by the function - * In: x32: pointer to the 32-byte serialized X coordinate - * of the resulting shared point (will not be NULL) - * ell_a64: pointer to the 64-byte encoded public key of party A - * (will not be NULL) - * ell_b64: pointer to the 64-byte encoded public key of party B - * (will not be NULL) - * data: arbitrary data pointer that is passed through - */ -typedef int (*secp256k1_ellswift_xdh_hash_function)( - unsigned char *output, - const unsigned char *x32, - const unsigned char *ell_a64, - const unsigned char *ell_b64, - void *data -); - -/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses - * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte - * array pointed to by data. */ -SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix; - -/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with - * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the - * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent - * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to - * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh"). - * The data argument is ignored. */ -SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324; - -/** Construct a 64-byte ElligatorSwift encoding of a given pubkey. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object - * Out: ell64: pointer to a 64-byte array to be filled - * In: pubkey: pointer to a secp256k1_pubkey containing an - * initialized public key - * rnd32: pointer to 32 bytes of randomness - * - * It is recommended that rnd32 consists of 32 uniformly random bytes, not - * known to any adversary trying to detect whether public keys are being - * encoded, though 16 bytes of randomness (padded to an array of 32 bytes, - * e.g., with zeros) suffice to make the result indistinguishable from - * uniform. The randomness in rnd32 must not be a deterministic function of - * the pubkey (it can be derived from the private key, though). - * - * It is not guaranteed that the computed encoding is stable across versions - * of the library, even if all arguments to this function (including rnd32) - * are the same. - * - * This function runs in variable time. - */ -SECP256K1_API int secp256k1_ellswift_encode( - const secp256k1_context *ctx, - unsigned char *ell64, - const secp256k1_pubkey *pubkey, - const unsigned char *rnd32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decode a 64-bytes ElligatorSwift encoded public key. - * - * Returns: always 1 - * Args: ctx: pointer to a context object - * Out: pubkey: pointer to a secp256k1_pubkey that will be filled - * In: ell64: pointer to a 64-byte array to decode - * - * This function runs in variable time. - */ -SECP256K1_API int secp256k1_ellswift_decode( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const unsigned char *ell64 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Compute an ElligatorSwift public key for a secret key. - * - * Returns: 1: secret was valid, public key was stored. - * 0: secret was invalid, try again. - * Args: ctx: pointer to a context object - * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift - * public key - * In: seckey32: pointer to a 32-byte secret key - * auxrnd32: (optional) pointer to 32 bytes of randomness - * - * Constant time in seckey and auxrnd32, but not in the resulting public key. - * - * It is recommended that auxrnd32 contains 32 uniformly random bytes, though - * it is optional (and does result in encodings that are indistinguishable from - * uniform even without any auxrnd32). It differs from the (mandatory) rnd32 - * argument to secp256k1_ellswift_encode in this regard. - * - * This function can be used instead of calling secp256k1_ec_pubkey_create - * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret - * key as entropy for the encoding (supplemented with auxrnd32, if provided). - * - * Like secp256k1_ellswift_encode, this function does not guarantee that the - * computed encoding is stable across versions of the library, even if all - * arguments (including auxrnd32) are the same. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create( - const secp256k1_context *ctx, - unsigned char *ell64, - const unsigned char *seckey32, - const unsigned char *auxrnd32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Given a private key, and ElligatorSwift public keys sent in both directions, - * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH). - * - * Returns: 1: shared secret was successfully computed - * 0: secret was invalid or hashfp returned 0 - * Args: ctx: pointer to a context object. - * Out: output: pointer to an array to be filled by hashfp. - * In: ell_a64: pointer to the 64-byte encoded public key of party A - * (will not be NULL) - * ell_b64: pointer to the 64-byte encoded public key of party B - * (will not be NULL) - * seckey32: pointer to our 32-byte secret key - * party: boolean indicating which party we are: zero if we are - * party A, non-zero if we are party B. seckey32 must be - * the private key corresponding to that party's ell_?64. - * This correspondence is not checked. - * hashfp: pointer to a hash function. - * data: arbitrary data pointer passed through to hashfp. - * - * Constant time in seckey32. - * - * This function is more efficient than decoding the public keys, and performing - * ECDH on them. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh( - const secp256k1_context *ctx, - unsigned char *output, - const unsigned char *ell_a64, - const unsigned char *ell_b64, - const unsigned char *seckey32, - int party, - secp256k1_ellswift_xdh_hash_function hashfp, - void *data -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_ELLSWIFT_H */ diff --git a/external/secp256k1/include/secp256k1_extrakeys.h b/external/secp256k1/include/secp256k1_extrakeys.h deleted file mode 100644 index 48c98693cf..0000000000 --- a/external/secp256k1/include/secp256k1_extrakeys.h +++ /dev/null @@ -1,250 +0,0 @@ -#ifndef SECP256K1_EXTRAKEYS_H -#define SECP256K1_EXTRAKEYS_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Opaque data structure that holds a parsed and valid "x-only" public key. - * An x-only pubkey encodes a point whose Y coordinate is even. It is - * serialized using only its X coordinate (32 bytes). See BIP-340 for more - * information about x-only pubkeys. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, use - * use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To - * compare keys, use secp256k1_xonly_pubkey_cmp. - */ -typedef struct secp256k1_xonly_pubkey { - unsigned char data[64]; -} secp256k1_xonly_pubkey; - -/** Opaque data structure that holds a keypair consisting of a secret and a - * public key. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 96 bytes in size, and can be safely copied/moved. - */ -typedef struct secp256k1_keypair { - unsigned char data[96]; -} secp256k1_keypair; - -/** Parse a 32-byte sequence into a xonly_pubkey object. - * - * Returns: 1 if the public key was fully valid. - * 0 if the public key could not be parsed or is invalid. - * - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a - * parsed version of input. If not, it's set to an invalid value. - * In: input32: pointer to a serialized xonly_pubkey. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( - const secp256k1_context *ctx, - secp256k1_xonly_pubkey *pubkey, - const unsigned char *input32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an xonly_pubkey object into a 32-byte sequence. - * - * Returns: 1 always. - * - * Args: ctx: pointer to a context object. - * Out: output32: pointer to a 32-byte array to place the serialized key in. - * In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key. - */ -SECP256K1_API int secp256k1_xonly_pubkey_serialize( - const secp256k1_context *ctx, - unsigned char *output32, - const secp256k1_xonly_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Compare two x-only public keys using lexicographic order - * - * Returns: <0 if the first public key is less than the second - * >0 if the first public key is greater than the second - * 0 if the two public keys are equal - * Args: ctx: pointer to a context object. - * In: pubkey1: first public key to compare - * pubkey2: second public key to compare - */ -SECP256K1_API int secp256k1_xonly_pubkey_cmp( - const secp256k1_context *ctx, - const secp256k1_xonly_pubkey *pk1, - const secp256k1_xonly_pubkey *pk2 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. - * - * Returns: 1 always. - * - * Args: ctx: pointer to a context object. - * Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key. - * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that - * will be set to 1 if the point encoded by xonly_pubkey is - * the negation of the pubkey and set to 0 otherwise. - * In: pubkey: pointer to a public key that is converted. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( - const secp256k1_context *ctx, - secp256k1_xonly_pubkey *xonly_pubkey, - int *pk_parity, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Tweak an x-only public key by adding the generator multiplied with tweak32 - * to it. - * - * Note that the resulting point can not in general be represented by an x-only - * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey - * is a normal secp256k1_pubkey. - * - * Returns: 0 if the arguments are invalid or the resulting public key would be - * invalid (only when the tweak is the negation of the corresponding - * secret key). 1 otherwise. - * - * Args: ctx: pointer to a context object. - * Out: output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. - * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. - * tweak32: pointer to a 32-byte tweak, which must be valid - * according to secp256k1_ec_seckey_verify or 32 zero - * bytes. For uniformly random 32-byte tweaks, the chance of - * being invalid is negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( - const secp256k1_context *ctx, - secp256k1_pubkey *output_pubkey, - const secp256k1_xonly_pubkey *internal_pubkey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Checks that a tweaked pubkey is the result of calling - * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. - * - * The tweaked pubkey is represented by its 32-byte x-only serialization and - * its pk_parity, which can both be obtained by converting the result of - * tweak_add to a secp256k1_xonly_pubkey. - * - * Note that this alone does _not_ verify that the tweaked pubkey is a - * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey - * can easily be the result of a different internal_pubkey and tweak. - * - * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the - * result of tweaking the internal_pubkey with tweak32. 1 otherwise. - * Args: ctx: pointer to a context object. - * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey. - * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization - * is passed in as tweaked_pubkey32). This must match the - * pk_parity value that is returned when calling - * secp256k1_xonly_pubkey with the tweaked pubkey, or - * this function will fail. - * internal_pubkey: pointer to an x-only public key object to apply the tweak to. - * tweak32: pointer to a 32-byte tweak. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check( - const secp256k1_context *ctx, - const unsigned char *tweaked_pubkey32, - int tweaked_pk_parity, - const secp256k1_xonly_pubkey *internal_pubkey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Compute the keypair for a valid secret key. - * - * See the documentation of `secp256k1_ec_seckey_verify` for more information - * about the validity of secret keys. - * - * Returns: 1: secret key is valid - * 0: secret key is invalid - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: keypair: pointer to the created keypair. - * In: seckey: pointer to a 32-byte secret key. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( - const secp256k1_context *ctx, - secp256k1_keypair *keypair, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Get the secret key from a keypair. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object. - * Out: seckey: pointer to a 32-byte buffer for the secret key. - * In: keypair: pointer to a keypair. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( - const secp256k1_context *ctx, - unsigned char *seckey, - const secp256k1_keypair *keypair -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Get the public key from a keypair. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to a pubkey object, set to the keypair public key. - * In: keypair: pointer to a keypair. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const secp256k1_keypair *keypair -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Get the x-only public key from a keypair. - * - * This is the same as calling secp256k1_keypair_pub and then - * secp256k1_xonly_pubkey_from_pubkey. - * - * Returns: 1 always. - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair - * public key after converting it to an xonly_pubkey. - * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the - * pk_parity argument of secp256k1_xonly_pubkey_from_pubkey. - * In: keypair: pointer to a keypair. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( - const secp256k1_context *ctx, - secp256k1_xonly_pubkey *pubkey, - int *pk_parity, - const secp256k1_keypair *keypair -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Tweak a keypair by adding tweak32 to the secret key and updating the public - * key accordingly. - * - * Calling this function and then secp256k1_keypair_pub results in the same - * public key as calling secp256k1_keypair_xonly_pub and then - * secp256k1_xonly_pubkey_tweak_add. - * - * Returns: 0 if the arguments are invalid or the resulting keypair would be - * invalid (only when the tweak is the negation of the keypair's - * secret key). 1 otherwise. - * - * Args: ctx: pointer to a context object. - * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to - * an invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak, which must be valid according to - * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly - * random 32-byte tweaks, the chance of being invalid is - * negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add( - const secp256k1_context *ctx, - secp256k1_keypair *keypair, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_EXTRAKEYS_H */ diff --git a/external/secp256k1/include/secp256k1_musig.h b/external/secp256k1/include/secp256k1_musig.h deleted file mode 100644 index 11b8f08c88..0000000000 --- a/external/secp256k1/include/secp256k1_musig.h +++ /dev/null @@ -1,588 +0,0 @@ -#ifndef SECP256K1_MUSIG_H -#define SECP256K1_MUSIG_H - -#include "secp256k1_extrakeys.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** This module implements BIP 327 "MuSig2 for BIP340-compatible - * Multi-Signatures" - * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki) - * v1.0.0. You can find an example demonstrating the musig module in - * examples/musig.c. - * - * The module also supports BIP 341 ("Taproot") public key tweaking. - * - * It is recommended to read the documentation in this include file carefully. - * Further notes on API usage can be found in doc/musig.md - * - * Since the first version of MuSig is essentially replaced by MuSig2, we use - * MuSig, musig and MuSig2 synonymously unless noted otherwise. - */ - -/** Opaque data structures - * - * The exact representation of data inside the opaque data structures is - * implementation defined and not guaranteed to be portable between different - * platforms or versions. With the exception of `secp256k1_musig_secnonce`, the - * data structures can be safely copied/moved. If you need to convert to a - * format suitable for storage, transmission, or comparison, use the - * corresponding serialization and parsing functions. - */ - -/** Opaque data structure that caches information about public key aggregation. - * - * Guaranteed to be 197 bytes in size. No serialization and parsing functions - * (yet). - */ -typedef struct secp256k1_musig_keyagg_cache { - unsigned char data[197]; -} secp256k1_musig_keyagg_cache; - -/** Opaque data structure that holds a signer's _secret_ nonce. - * - * Guaranteed to be 132 bytes in size. - * - * WARNING: This structure MUST NOT be copied or read or written to directly. A - * signer who is online throughout the whole process and can keep this - * structure in memory can use the provided API functions for a safe standard - * workflow. - * - * Copying this data structure can result in nonce reuse which will leak the - * secret signing key. - */ -typedef struct secp256k1_musig_secnonce { - unsigned char data[132]; -} secp256k1_musig_secnonce; - -/** Opaque data structure that holds a signer's public nonce. - * - * Guaranteed to be 132 bytes in size. Serialized and parsed with - * `musig_pubnonce_serialize` and `musig_pubnonce_parse`. - */ -typedef struct secp256k1_musig_pubnonce { - unsigned char data[132]; -} secp256k1_musig_pubnonce; - -/** Opaque data structure that holds an aggregate public nonce. - * - * Guaranteed to be 132 bytes in size. Serialized and parsed with - * `musig_aggnonce_serialize` and `musig_aggnonce_parse`. - */ -typedef struct secp256k1_musig_aggnonce { - unsigned char data[132]; -} secp256k1_musig_aggnonce; - -/** Opaque data structure that holds a MuSig session. - * - * This structure is not required to be kept secret for the signing protocol to - * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing - * functions (yet). - */ -typedef struct secp256k1_musig_session { - unsigned char data[133]; -} secp256k1_musig_session; - -/** Opaque data structure that holds a partial MuSig signature. - * - * Guaranteed to be 36 bytes in size. Serialized and parsed with - * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. - */ -typedef struct secp256k1_musig_partial_sig { - unsigned char data[36]; -} secp256k1_musig_partial_sig; - -/** Parse a signer's public nonce. - * - * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: pointer to a context object - * Out: nonce: pointer to a nonce object - * In: in66: pointer to the 66-byte nonce to be parsed - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse( - const secp256k1_context *ctx, - secp256k1_musig_pubnonce *nonce, - const unsigned char *in66 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a signer's public nonce - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * Out: out66: pointer to a 66-byte array to store the serialized nonce - * In: nonce: pointer to the nonce - */ -SECP256K1_API int secp256k1_musig_pubnonce_serialize( - const secp256k1_context *ctx, - unsigned char *out66, - const secp256k1_musig_pubnonce *nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse an aggregate public nonce. - * - * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: pointer to a context object - * Out: nonce: pointer to a nonce object - * In: in66: pointer to the 66-byte nonce to be parsed - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse( - const secp256k1_context *ctx, - secp256k1_musig_aggnonce *nonce, - const unsigned char *in66 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an aggregate public nonce - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * Out: out66: pointer to a 66-byte array to store the serialized nonce - * In: nonce: pointer to the nonce - */ -SECP256K1_API int secp256k1_musig_aggnonce_serialize( - const secp256k1_context *ctx, - unsigned char *out66, - const secp256k1_musig_aggnonce *nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse a MuSig partial signature. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: pointer to a context object - * Out: sig: pointer to a signature object - * In: in32: pointer to the 32-byte signature to be parsed - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse( - const secp256k1_context *ctx, - secp256k1_musig_partial_sig *sig, - const unsigned char *in32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a MuSig partial signature - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * Out: out32: pointer to a 32-byte array to store the serialized signature - * In: sig: pointer to the signature - */ -SECP256K1_API int secp256k1_musig_partial_sig_serialize( - const secp256k1_context *ctx, - unsigned char *out32, - const secp256k1_musig_partial_sig *sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Computes an aggregate public key and uses it to initialize a keyagg_cache - * - * Different orders of `pubkeys` result in different `agg_pk`s. - * - * Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort` - * which ensures the same `agg_pk` result for the same multiset of pubkeys. - * This is useful to do before `pubkey_agg`, such that the order of pubkeys - * does not affect the aggregate public key. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, - * this arg can be NULL. - * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that - * is required for signing (or observing the signing session - * and verifying partial signatures). - * In: pubkeys: input array of pointers to public keys to aggregate. The order - * is important; a different order will result in a different - * aggregate public key. - * n_pubkeys: length of pubkeys array. Must be greater than 0. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg( - const secp256k1_context *ctx, - secp256k1_xonly_pubkey *agg_pk, - secp256k1_musig_keyagg_cache *keyagg_cache, - const secp256k1_pubkey * const *pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4); - -/** Obtain the aggregate public key from a keyagg_cache. - * - * This is only useful if you need the non-xonly public key, in particular for - * plain (non-xonly) tweaking or batch-verifying multiple key aggregations - * (not implemented). - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: agg_pk: the MuSig-aggregated public key. - * In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( - const secp256k1_context *ctx, - secp256k1_pubkey *agg_pk, - const secp256k1_musig_keyagg_cache *keyagg_cache -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding - * the generator multiplied with `tweak32` to it. This is useful for deriving - * child keys from an aggregate public key via BIP 32 where `tweak32` is set to - * a hash as defined in BIP 32. - * - * Callers are responsible for deriving `tweak32` in a way that does not reduce - * the security of MuSig (for example, by following BIP 32). - * - * The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after - * the following pseudocode buf and buf2 have identical contents (absent - * earlier failures). - * - * secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...) - * secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache) - * secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache) - * secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...) - * secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32) - * secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...) - * - * This function is required if you want to _sign_ for a tweaked aggregate key. - * If you are only computing a public key but not intending to create a - * signature for it, use `secp256k1_ec_pubkey_tweak_add` instead. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. If you - * do not need it, this arg can be NULL. - * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes - * `secp256k1_ec_seckey_verify` and is not equal to the - * secret key corresponding to the public key represented - * by keyagg_cache or its negation. For uniformly random - * 32-byte arrays the chance of being invalid is - * negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add( - const secp256k1_context *ctx, - secp256k1_pubkey *output_pubkey, - secp256k1_musig_keyagg_cache *keyagg_cache, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the - * generator multiplied with `tweak32` to it. This is useful for creating - * Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP - * 341. - * - * Callers are responsible for deriving `tweak32` in a way that does not reduce - * the security of MuSig (for example, by following Taproot BIP 341). - * - * The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in - * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier - * failures) returns 1. - * - * secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) - * secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32) - * secp256k1_xonly_pubkey_serialize(..., buf, output_pk) - * secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) - * - * This function is required if you want to _sign_ for a tweaked aggregate key. - * If you are only computing a public key but not intending to create a - * signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. If you - * do not need it, this arg can be NULL. - * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes - * `secp256k1_ec_seckey_verify` and is not equal to the - * secret key corresponding to the public key represented - * by keyagg_cache or its negation. For uniformly random - * 32-byte arrays the chance of being invalid is - * negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add( - const secp256k1_context *ctx, - secp256k1_pubkey *output_pubkey, - secp256k1_musig_keyagg_cache *keyagg_cache, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Starts a signing session by generating a nonce - * - * This function outputs a secret nonce that will be required for signing and a - * corresponding public nonce that is intended to be sent to other signers. - * - * MuSig differs from regular Schnorr signing in that implementers _must_ take - * special care to not reuse a nonce. This can be ensured by following these rules: - * - * 1. Each call to this function must have a UNIQUE session_secrand32 that must - * NOT BE REUSED in subsequent calls to this function and must be KEPT - * SECRET (even from other signers). - * 2. If you already know the seckey, message or aggregate public key - * cache, they can be optionally provided to derive the nonce and increase - * misuse-resistance. The extra_input32 argument can be used to provide - * additional data that does not repeat in normal scenarios, such as the - * current time. - * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility - * that it is used more than once for signing. - * - * If you don't have access to good randomness for session_secrand32, but you - * have access to a non-repeating counter, then see - * secp256k1_musig_nonce_gen_counter. - * - * Remember that nonce reuse will leak the secret key! - * Note that using the same seckey for multiple MuSig sessions is fine. - * - * Returns: 0 if the arguments are invalid and 1 otherwise - * Args: ctx: pointer to a context object (not secp256k1_context_static) - * Out: secnonce: pointer to a structure to store the secret nonce - * pubnonce: pointer to a structure to store the public nonce - * In/Out: - * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this - * call to secp256k1_musig_nonce_gen and must be uniformly - * random. If the function call is successful, the - * session_secrand32 buffer is invalidated to prevent reuse. - * In: - * seckey: the 32-byte secret key that will later be used for signing, if - * already known (can be NULL) - * pubkey: public key of the signer creating the nonce. The secnonce - * output of this function cannot be used to sign for any - * other public key. While the public key should correspond - * to the provided seckey, a mismatch will not cause the - * function to return 0. - * msg32: the 32-byte message that will later be signed, if already known - * (can be NULL) - * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate - * (and potentially tweaked) public key if already known - * (can be NULL) - * extra_input32: an optional 32-byte array that is input to the nonce - * derivation function (can be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen( - const secp256k1_context *ctx, - secp256k1_musig_secnonce *secnonce, - secp256k1_musig_pubnonce *pubnonce, - unsigned char *session_secrand32, - const unsigned char *seckey, - const secp256k1_pubkey *pubkey, - const unsigned char *msg32, - const secp256k1_musig_keyagg_cache *keyagg_cache, - const unsigned char *extra_input32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); - - -/** Alternative way to generate a nonce and start a signing session - * - * This function outputs a secret nonce that will be required for signing and a - * corresponding public nonce that is intended to be sent to other signers. - * - * This function differs from `secp256k1_musig_nonce_gen` by accepting a - * non-repeating counter value instead of a secret random value. This requires - * that a secret key is provided to `secp256k1_musig_nonce_gen_counter` - * (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen` - * where the seckey argument is optional. - * - * MuSig differs from regular Schnorr signing in that implementers _must_ take - * special care to not reuse a nonce. This can be ensured by following these rules: - * - * 1. The nonrepeating_cnt argument must be a counter value that never repeats, - * i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with - * the same keypair and nonrepeating_cnt value. For example, this implies - * that if the same keypair is used with `secp256k1_musig_nonce_gen_counter` - * on multiple devices, none of the devices should have the same counter - * value as any other device. - * 2. If the seckey, message or aggregate public key cache is already available - * at this stage, any of these can be optionally provided, in which case - * they will be used in the derivation of the nonce and increase - * misuse-resistance. The extra_input32 argument can be used to provide - * additional data that does not repeat in normal scenarios, such as the - * current time. - * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility - * that it is used more than once for signing. - * - * Remember that nonce reuse will leak the secret key! - * Note that using the same keypair for multiple MuSig sessions is fine. - * - * Returns: 0 if the arguments are invalid and 1 otherwise - * Args: ctx: pointer to a context object (not secp256k1_context_static) - * Out: secnonce: pointer to a structure to store the secret nonce - * pubnonce: pointer to a structure to store the public nonce - * In: - * nonrepeating_cnt: the value of a counter as explained above. Must be - * unique to this call to secp256k1_musig_nonce_gen. - * keypair: keypair of the signer creating the nonce. The secnonce - * output of this function cannot be used to sign for any - * other keypair. - * msg32: the 32-byte message that will later be signed, if already known - * (can be NULL) - * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate - * (and potentially tweaked) public key if already known - * (can be NULL) - * extra_input32: an optional 32-byte array that is input to the nonce - * derivation function (can be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter( - const secp256k1_context *ctx, - secp256k1_musig_secnonce *secnonce, - secp256k1_musig_pubnonce *pubnonce, - uint64_t nonrepeating_cnt, - const secp256k1_keypair *keypair, - const unsigned char *msg32, - const secp256k1_musig_keyagg_cache *keyagg_cache, - const unsigned char *extra_input32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); - -/** Aggregates the nonces of all signers into a single nonce - * - * This can be done by an untrusted party to reduce the communication - * between signers. Instead of everyone sending nonces to everyone else, there - * can be one party receiving all nonces, aggregating the nonces with this - * function and then sending only the aggregate nonce back to the signers. - * - * If the aggregator does not compute the aggregate nonce correctly, the final - * signature will be invalid. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: aggnonce: pointer to an aggregate public nonce object for - * musig_nonce_process - * In: pubnonces: array of pointers to public nonces sent by the - * signers - * n_pubnonces: number of elements in the pubnonces array. Must be - * greater than 0. - */ -SECP256K1_API int secp256k1_musig_nonce_agg( - const secp256k1_context *ctx, - secp256k1_musig_aggnonce *aggnonce, - const secp256k1_musig_pubnonce * const *pubnonces, - size_t n_pubnonces -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Takes the aggregate nonce and creates a session that is required for signing - * and verification of partial signatures. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: session: pointer to a struct to store the session - * In: aggnonce: pointer to an aggregate public nonce object that is the - * output of musig_nonce_agg - * msg32: the 32-byte message to sign - * keyagg_cache: pointer to the keyagg_cache that was used to create the - * aggregate (and potentially tweaked) pubkey - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process( - const secp256k1_context *ctx, - secp256k1_musig_session *session, - const secp256k1_musig_aggnonce *aggnonce, - const unsigned char *msg32, - const secp256k1_musig_keyagg_cache *keyagg_cache -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Produces a partial signature - * - * This function overwrites the given secnonce with zeros and will abort if given a - * secnonce that is all zeros. This is a best effort attempt to protect against nonce - * reuse. However, this is of course easily defeated if the secnonce has been - * copied (or serialized). Remember that nonce reuse will leak the secret key! - * - * For signing to succeed, the secnonce provided to this function must have - * been generated for the provided keypair. This means that when signing for a - * keypair consisting of a seckey and pubkey, the secnonce must have been - * created by calling musig_nonce_gen with that pubkey. Otherwise, the - * illegal_callback is called. - * - * This function does not verify the output partial signature, deviating from - * the BIP 327 specification. It is recommended to verify the output partial - * signature with `secp256k1_musig_partial_sig_verify` to prevent random or - * adversarially provoked computation errors. - * - * Returns: 0 if the arguments are invalid or the provided secnonce has already - * been used for signing, 1 otherwise - * Args: ctx: pointer to a context object - * Out: partial_sig: pointer to struct to store the partial signature - * In/Out: secnonce: pointer to the secnonce struct created in - * musig_nonce_gen that has been never used in a - * partial_sign call before and has been created for the - * keypair - * In: keypair: pointer to keypair to sign the message with - * keyagg_cache: pointer to the keyagg_cache that was output when the - * aggregate public key for this session - * session: pointer to the session that was created with - * musig_nonce_process - */ -SECP256K1_API int secp256k1_musig_partial_sign( - const secp256k1_context *ctx, - secp256k1_musig_partial_sig *partial_sig, - secp256k1_musig_secnonce *secnonce, - const secp256k1_keypair *keypair, - const secp256k1_musig_keyagg_cache *keyagg_cache, - const secp256k1_musig_session *session -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Verifies an individual signer's partial signature - * - * The signature is verified for a specific signing session. In order to avoid - * accidentally verifying a signature from a different or non-existing signing - * session, you must ensure the following: - * 1. The `keyagg_cache` argument is identical to the one used to create the - * `session` with `musig_nonce_process`. - * 2. The `pubkey` argument must be identical to the one sent by the signer - * before aggregating it with `musig_pubkey_agg` to create the - * `keyagg_cache`. - * 3. The `pubnonce` argument must be identical to the one sent by the signer - * before aggregating it with `musig_nonce_agg` and using the result to - * create the `session` with `musig_nonce_process`. - * - * It is not required to call this function in regular MuSig sessions, because - * if any partial signature does not verify, the final signature will not - * verify either, so the problem will be caught. However, this function - * provides the ability to identify which specific partial signature fails - * verification. - * - * Returns: 0 if the arguments are invalid or the partial signature does not - * verify, 1 otherwise - * Args ctx: pointer to a context object - * In: partial_sig: pointer to partial signature to verify, sent by - * the signer associated with `pubnonce` and `pubkey` - * pubnonce: public nonce of the signer in the signing session - * pubkey: public key of the signer in the signing session - * keyagg_cache: pointer to the keyagg_cache that was output when the - * aggregate public key for this signing session - * session: pointer to the session that was created with - * `musig_nonce_process` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( - const secp256k1_context *ctx, - const secp256k1_musig_partial_sig *partial_sig, - const secp256k1_musig_pubnonce *pubnonce, - const secp256k1_pubkey *pubkey, - const secp256k1_musig_keyagg_cache *keyagg_cache, - const secp256k1_musig_session *session -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Aggregates partial signatures - * - * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean - * the resulting signature verifies). - * Args: ctx: pointer to a context object - * Out: sig64: complete (but possibly invalid) Schnorr signature - * In: session: pointer to the session that was created with - * musig_nonce_process - * partial_sigs: array of pointers to partial signatures to aggregate - * n_sigs: number of elements in the partial_sigs array. Must be - * greater than 0. - */ -SECP256K1_API int secp256k1_musig_partial_sig_agg( - const secp256k1_context *ctx, - unsigned char *sig64, - const secp256k1_musig_session *session, - const secp256k1_musig_partial_sig * const *partial_sigs, - size_t n_sigs -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/secp256k1/include/secp256k1_preallocated.h b/external/secp256k1/include/secp256k1_preallocated.h deleted file mode 100644 index f2d95c245e..0000000000 --- a/external/secp256k1/include/secp256k1_preallocated.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef SECP256K1_PREALLOCATED_H -#define SECP256K1_PREALLOCATED_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* The module provided by this header file is intended for settings in which it - * is not possible or desirable to rely on dynamic memory allocation. It provides - * functions for creating, cloning, and destroying secp256k1 context objects in a - * contiguous fixed-size block of memory provided by the caller. - * - * Context objects created by functions in this module can be used like contexts - * objects created by functions in secp256k1.h, i.e., they can be passed to any - * API function that expects a context object (see secp256k1.h for details). The - * only exception is that context objects created by functions in this module - * must be destroyed using secp256k1_context_preallocated_destroy (in this - * module) instead of secp256k1_context_destroy (in secp256k1.h). - * - * It is guaranteed that functions in this module will not call malloc or its - * friends realloc, calloc, and free. - */ - -/** Determine the memory size of a secp256k1 context object to be created in - * caller-provided memory. - * - * The purpose of this function is to determine how much memory must be provided - * to secp256k1_context_preallocated_create. - * - * Returns: the required size of the caller-provided memory block - * In: flags: which parts of the context to initialize. - */ -SECP256K1_API size_t secp256k1_context_preallocated_size( - unsigned int flags -) SECP256K1_WARN_UNUSED_RESULT; - -/** Create a secp256k1 context object in caller-provided memory. - * - * The caller must provide a pointer to a rewritable contiguous block of memory - * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably - * aligned to hold an object of any type. - * - * The block of memory is exclusively owned by the created context object during - * the lifetime of this context object, which begins with the call to this - * function and ends when a call to secp256k1_context_preallocated_destroy - * (which destroys the context object again) returns. During the lifetime of the - * context object, the caller is obligated not to access this block of memory, - * i.e., the caller may not read or write the memory, e.g., by copying the memory - * contents to a different location or trying to create a second context object - * in the memory. In simpler words, the prealloc pointer (or any pointer derived - * from it) should not be used during the lifetime of the context object. - * - * Returns: pointer to newly created context object. - * In: prealloc: pointer to a rewritable contiguous block of memory of - * size at least secp256k1_context_preallocated_size(flags) - * bytes, as detailed above. - * flags: which parts of the context to initialize. - * - * See secp256k1_context_create (in secp256k1.h) for further details. - * - * See also secp256k1_context_randomize (in secp256k1.h) - * and secp256k1_context_preallocated_destroy. - */ -SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create( - void *prealloc, - unsigned int flags -) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; - -/** Determine the memory size of a secp256k1 context object to be copied into - * caller-provided memory. - * - * Returns: the required size of the caller-provided memory block. - * In: ctx: pointer to a context to copy. - */ -SECP256K1_API size_t secp256k1_context_preallocated_clone_size( - const secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; - -/** Copy a secp256k1 context object into caller-provided memory. - * - * The caller must provide a pointer to a rewritable contiguous block of memory - * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably - * aligned to hold an object of any type. - * - * The block of memory is exclusively owned by the created context object during - * the lifetime of this context object, see the description of - * secp256k1_context_preallocated_create for details. - * - * Cloning secp256k1_context_static is not possible, and should not be emulated by - * the caller (e.g., using memcpy). Create a new context instead. - * - * Returns: pointer to a newly created context object. - * Args: ctx: pointer to a context to copy (not secp256k1_context_static). - * In: prealloc: pointer to a rewritable contiguous block of memory of - * size at least secp256k1_context_preallocated_size(flags) - * bytes, as detailed above. - */ -SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone( - const secp256k1_context *ctx, - void *prealloc -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; - -/** Destroy a secp256k1 context object that has been created in - * caller-provided memory. - * - * The context pointer may not be used afterwards. - * - * The context to destroy must have been created using - * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone. - * If the context has instead been created using secp256k1_context_create or - * secp256k1_context_clone, the behaviour is undefined. In that case, - * secp256k1_context_destroy must be used instead. - * - * If required, it is the responsibility of the caller to deallocate the block - * of memory properly after this function returns, e.g., by calling free on the - * preallocated pointer given to secp256k1_context_preallocated_create or - * secp256k1_context_preallocated_clone. - * - * Args: ctx: pointer to a context to destroy, constructed using - * secp256k1_context_preallocated_create or - * secp256k1_context_preallocated_clone - * (i.e., not secp256k1_context_static). - */ -SECP256K1_API void secp256k1_context_preallocated_destroy( - secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_PREALLOCATED_H */ diff --git a/external/secp256k1/include/secp256k1_recovery.h b/external/secp256k1/include/secp256k1_recovery.h deleted file mode 100644 index 93a2e4ccbd..0000000000 --- a/external/secp256k1/include/secp256k1_recovery.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef SECP256K1_RECOVERY_H -#define SECP256K1_RECOVERY_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Opaque data structure that holds a parsed ECDSA signature, - * supporting pubkey recovery. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 65 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_parse_* functions. - * - * Furthermore, it is guaranteed that identical signatures (including their - * recoverability) will have identical representation, so they can be - * memcmp'ed. - */ -typedef struct secp256k1_ecdsa_recoverable_signature { - unsigned char data[65]; -} secp256k1_ecdsa_recoverable_signature; - -/** Parse a compact ECDSA signature (64 bytes + recovery id). - * - * Returns: 1 when the signature could be parsed, 0 otherwise - * Args: ctx: pointer to a context object - * Out: sig: pointer to a signature object - * In: input64: pointer to a 64-byte compact signature - * recid: the recovery id (0, 1, 2 or 3) - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( - const secp256k1_context *ctx, - secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *input64, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Convert a recoverable signature into a normal signature. - * - * Returns: 1 - * Args: ctx: pointer to a context object. - * Out: sig: pointer to a normal signature. - * In: sigin: pointer to a recoverable signature. - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( - const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sig, - const secp256k1_ecdsa_recoverable_signature *sigin -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). - * - * Returns: 1 - * Args: ctx: pointer to a context object. - * Out: output64: pointer to a 64-byte array of the compact signature. - * recid: pointer to an integer to hold the recovery id. - * In: sig: pointer to an initialized signature object. - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( - const secp256k1_context *ctx, - unsigned char *output64, - int *recid, - const secp256k1_ecdsa_recoverable_signature *sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Create a recoverable ECDSA signature. - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. - * In: msghash32: the 32-byte message hash being signed. - * seckey: pointer to a 32-byte secret key. - * noncefp: pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used. - * ndata: pointer to arbitrary data used by the nonce generation function - * (can be NULL for secp256k1_nonce_function_default). - */ -SECP256K1_API int secp256k1_ecdsa_sign_recoverable( - const secp256k1_context *ctx, - secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msghash32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Recover an ECDSA public key from a signature. - * - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to the recovered public key. - * In: sig: pointer to initialized signature that supports pubkey recovery. - * msghash32: the 32-byte message hash assumed to be signed. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( - const secp256k1_context *ctx, - secp256k1_pubkey *pubkey, - const secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msghash32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_RECOVERY_H */ diff --git a/external/secp256k1/include/secp256k1_schnorrsig.h b/external/secp256k1/include/secp256k1_schnorrsig.h deleted file mode 100644 index 013d4ee73d..0000000000 --- a/external/secp256k1/include/secp256k1_schnorrsig.h +++ /dev/null @@ -1,190 +0,0 @@ -#ifndef SECP256K1_SCHNORRSIG_H -#define SECP256K1_SCHNORRSIG_H - -#include "secp256k1.h" -#include "secp256k1_extrakeys.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** This module implements a variant of Schnorr signatures compliant with - * Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1" - * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). - */ - -/** A pointer to a function to deterministically generate a nonce. - * - * Same as secp256k1_nonce function with the exception of accepting an - * additional pubkey argument and not requiring an attempt argument. The pubkey - * argument can protect signature schemes with key-prefixed challenge hash - * inputs against reusing the nonce when signing with the wrong precomputed - * pubkey. - * - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to - * return an error. - * Out: nonce32: pointer to a 32-byte array to be filled by the function - * In: msg: the message being verified. Is NULL if and only if msglen - * is 0. - * msglen: the length of the message - * key32: pointer to a 32-byte secret key (will not be NULL) - * xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32 - * (will not be NULL) - * algo: pointer to an array describing the signature - * algorithm (will not be NULL) - * algolen: the length of the algo array - * data: arbitrary data pointer that is passed through - * - * Except for test cases, this function should compute some cryptographic hash of - * the message, the key, the pubkey, the algorithm description, and data. - */ -typedef int (*secp256k1_nonce_function_hardened)( - unsigned char *nonce32, - const unsigned char *msg, - size_t msglen, - const unsigned char *key32, - const unsigned char *xonly_pk32, - const unsigned char *algo, - size_t algolen, - void *data -); - -/** An implementation of the nonce generation function as defined in Bitcoin - * Improvement Proposal 340 "Schnorr Signatures for secp256k1" - * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). - * - * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of - * auxiliary random data as defined in BIP-340. If the data pointer is NULL, - * the nonce derivation procedure follows BIP-340 by setting the auxiliary - * random data to zero. The algo argument must be non-NULL, otherwise the - * function will fail and return 0. The hash will be tagged with algo. - * Therefore, to create BIP-340 compliant signatures, algo must be set to - * "BIP0340/nonce" and algolen to 13. - */ -SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; - -/** Data structure that contains additional arguments for schnorrsig_sign_custom. - * - * A schnorrsig_extraparams structure object can be initialized correctly by - * setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT. - * - * Members: - * magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization - * and has no other function than making sure the object is - * initialized. - * noncefp: pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_bip340 is used - * ndata: pointer to arbitrary data used by the nonce generation function - * (can be NULL). If it is non-NULL and - * secp256k1_nonce_function_bip340 is used, then ndata must be a - * pointer to 32-byte auxiliary randomness as per BIP-340. - */ -typedef struct secp256k1_schnorrsig_extraparams { - unsigned char magic[4]; - secp256k1_nonce_function_hardened noncefp; - void *ndata; -} secp256k1_schnorrsig_extraparams; - -#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c } -#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\ - SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\ - NULL,\ - NULL\ -} - -/** Create a Schnorr signature. - * - * Does _not_ strictly follow BIP-340 because it does not verify the resulting - * signature. Instead, you can manually use secp256k1_schnorrsig_verify and - * abort if it fails. - * - * This function only signs 32-byte messages. If you have messages of a - * different size (or the same size but without a context-specific tag - * prefix), it is recommended to create a 32-byte message hash with - * secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows - * providing an context-specific tag for domain separation. This prevents - * signatures from being valid in multiple contexts by accident. - * - * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig64: pointer to a 64-byte array to store the serialized signature. - * In: msg32: the 32-byte message being signed. - * keypair: pointer to an initialized keypair. - * aux_rand32: 32 bytes of fresh randomness. While recommended to provide - * this, it is only supplemental to security and can be NULL. A - * NULL argument is treated the same as an all-zero one. See - * BIP-340 "Default Signing" for a full explanation of this - * argument and for guidance if randomness is expensive. - */ -SECP256K1_API int secp256k1_schnorrsig_sign32( - const secp256k1_context *ctx, - unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_keypair *keypair, - const unsigned char *aux_rand32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API int secp256k1_schnorrsig_sign( - const secp256k1_context *ctx, - unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_keypair *keypair, - const unsigned char *aux_rand32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) - SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead"); - -/** Create a Schnorr signature with a more flexible API. - * - * Same arguments as secp256k1_schnorrsig_sign except that it allows signing - * variable length messages and accepts a pointer to an extraparams object that - * allows customizing signing by passing additional arguments. - * - * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32 - * and extraparams is initialized as follows: - * ``` - * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - * extraparams.ndata = (unsigned char*)aux_rand32; - * ``` - * - * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig64: pointer to a 64-byte array to store the serialized signature. - * In: msg: the message being signed. Can only be NULL if msglen is 0. - * msglen: length of the message. - * keypair: pointer to an initialized keypair. - * extraparams: pointer to an extraparams object (can be NULL). - */ -SECP256K1_API int secp256k1_schnorrsig_sign_custom( - const secp256k1_context *ctx, - unsigned char *sig64, - const unsigned char *msg, - size_t msglen, - const secp256k1_keypair *keypair, - secp256k1_schnorrsig_extraparams *extraparams -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); - -/** Verify a Schnorr signature. - * - * Returns: 1: correct signature - * 0: incorrect signature - * Args: ctx: pointer to a context object. - * In: sig64: pointer to the 64-byte signature to verify. - * msg: the message being verified. Can only be NULL if msglen is 0. - * msglen: length of the message - * pubkey: pointer to an x-only public key to verify with - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( - const secp256k1_context *ctx, - const unsigned char *sig64, - const unsigned char *msg, - size_t msglen, - const secp256k1_xonly_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_SCHNORRSIG_H */ diff --git a/external/secp256k1/libsecp256k1.pc.in b/external/secp256k1/libsecp256k1.pc.in deleted file mode 100644 index 0fb6f48a6c..0000000000 --- a/external/secp256k1/libsecp256k1.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libsecp256k1 -Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin-core/secp256k1 -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lsecp256k1 - diff --git a/external/secp256k1/sage/gen_exhaustive_groups.sage b/external/secp256k1/sage/gen_exhaustive_groups.sage deleted file mode 100644 index 070bc1285f..0000000000 --- a/external/secp256k1/sage/gen_exhaustive_groups.sage +++ /dev/null @@ -1,156 +0,0 @@ -load("secp256k1_params.sage") - -MAX_ORDER = 1000 - -# Set of (curve) orders we have encountered so far. -orders_done = set() - -# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups. -solutions = {} - -# Iterate over curves of the form y^2 = x^3 + B. -for b in range(1, P): - # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all. - if len(orders_done) == 6: - break - - E = EllipticCurve(F, [0, b]) - print("Analyzing curve y^2 = x^3 + %i" % b) - n = E.order() - - # Skip curves with an order we've already tried - if n in orders_done: - print("- Isomorphic to earlier curve") - print() - continue - orders_done.add(n) - - # Skip curves isomorphic to the real secp256k1 - if n.is_pseudoprime(): - assert E.is_isomorphic(C) - print("- Isomorphic to secp256k1") - print() - continue - - print("- Finding prime subgroups") - - # Map from group_order to a set of independent generators for that order. - curve_gens = {} - - for g in E.gens(): - # Find what prime subgroups of group generated by g exist. - g_order = g.order() - for f, _ in g.order().factor(): - # Skip subgroups that have bad size. - if f < 4: - print(f" - Subgroup of size {f}: too small") - continue - if f > MAX_ORDER: - print(f" - Subgroup of size {f}: too large") - continue - - # Construct a generator for that subgroup. - gen = g * (g_order // f) - assert(gen.order() == f) - - # Add to set the minimal multiple of gen. - curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)])) - print(f" - Subgroup of size {f}: ok") - - for f in sorted(curve_gens.keys()): - print(f"- Constructing group of order {f}") - cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1]) - gens = list(curve_gens[f]) - sol_count = 0 - no_endo_count = 0 - - # Consider all non-zero linear combinations of the independent generators. - for j in range(1, f**len(gens)): - gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens))) - assert not gen.is_zero() - assert (f*gen).is_zero() - - # Find lambda for endomorphism. Skip if none can be found. - lam = None - for l in cbrts: - if l*gen == E(BETA*gen[0], gen[1]): - lam = l - break - - if lam is None: - no_endo_count += 1 - else: - sol_count += 1 - solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam)) - - print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)") - - print() - -def output_generator(g, name): - print(f"#define {name} SECP256K1_GE_CONST(\\") - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(")") - -def output_b(b): - print(f"#define SECP256K1_B {int(b)}") - -print() -print("To be put in src/group_impl.h:") -print() -print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") -for f in sorted(solutions.keys()): - # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers). - b, _, _, HALF_G, lam = min(solutions[f]) - output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}") -print("/** Generator for secp256k1, value 'g' defined in") -print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.") -print(" */") -output_generator(G, "SECP256K1_G") -print("/* These exhaustive group test orders and generators are chosen such that:") -print(" * - The field size is equal to that of secp256k1, so field code is the same.") -print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.") -print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.") -print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.") -print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).") -print(" */") -print("#if defined(EXHAUSTIVE_TEST_ORDER)") -first = True -for f in sorted(solutions.keys()): - b, _, _, _, lam = min(solutions[f]) - print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}") - first = False - print() - print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};") - output_b(b) - print() -print("# else") -print("# error No known generator for the specified exhaustive test group order.") -print("# endif") -print("#else") -print() -print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;") -output_b(7) -print() -print("#endif") -print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") - - -print() -print() -print("To be put in src/scalar_impl.h:") -print() -print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") -first = True -for f in sorted(solutions.keys()): - _, _, _, _, lam = min(solutions[f]) - print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) - first = False - print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) -print("# else") -print("# error No known lambda for the specified exhaustive test group order.") -print("# endif") -print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") diff --git a/external/secp256k1/sage/gen_split_lambda_constants.sage b/external/secp256k1/sage/gen_split_lambda_constants.sage deleted file mode 100644 index 7d4359e0f6..0000000000 --- a/external/secp256k1/sage/gen_split_lambda_constants.sage +++ /dev/null @@ -1,114 +0,0 @@ -""" Generates the constants used in secp256k1_scalar_split_lambda. - -See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations. -""" - -load("secp256k1_params.sage") - -def inf_norm(v): - """Returns the infinity norm of a vector.""" - return max(map(abs, v)) - -def gauss_reduction(i1, i2): - v1, v2 = i1.copy(), i2.copy() - while True: - if inf_norm(v2) < inf_norm(v1): - v1, v2 = v2, v1 - # This is essentially - # m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2)) - # (rounding to the nearest integer) without relying on floating point arithmetic. - m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2) - if m == 0: - return v1, v2 - v2[0] -= m*v1[0] - v2[1] -= m*v1[1] - -def find_split_constants_gauss(): - """Find constants for secp256k1_scalar_split_lamdba using gauss reduction.""" - (v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)]) - - # We use related vectors in secp256k1_scalar_split_lambda. - A1, B1 = -v21, -v11 - A2, B2 = v22, -v21 - - return A1, B1, A2, B2 - -def find_split_constants_explicit_tof(): - """Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius. - - See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on - elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2 - """ - assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10]. - assert C.j_invariant() == 0 - - t = C.trace_of_frobenius() - - c = Integer(sqrt((4*P - t**2)/3)) - A1 = Integer((t - c)/2 - 1) - B1 = c - - A2 = Integer((t + c)/2 - 1) - B2 = Integer(1 - (t - c)/2) - - # We use a negated b values in secp256k1_scalar_split_lambda. - B1, B2 = -B1, -B2 - - return A1, B1, A2, B2 - -A1, B1, A2, B2 = find_split_constants_explicit_tof() - -# For extra fun, use an independent method to recompute the constants. -assert (A1, B1, A2, B2) == find_split_constants_gauss() - -# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. -def PHI(a,b): - return Z(a + LAMBDA*b) - -# Check that (A1, B1) and (A2, B2) are in the kernel of PHI. -assert PHI(A1, B1) == Z(0) -assert PHI(A2, B2) == Z(0) - -# Check that the parallelogram generated by (A1, A2) and (B1, B2) -# is a fundamental domain by containing exactly N points. -# Since the LHS is the determinant and N != 0, this also checks that -# (A1, A2) and (B1, B2) are linearly independent. By the previous -# assertions, (A1, A2) and (B1, B2) are a basis of the kernel. -assert A1*B2 - B1*A2 == N - -# Check that their components are short enough. -assert (A1 + A2)/2 < sqrt(N) -assert B1 < sqrt(N) -assert B2 < sqrt(N) - -G1 = round((2**384)*B2/N) -G2 = round((2**384)*(-B1)/N) - -def rnddiv2(v): - if v & 1: - v += 1 - return v >> 1 - -def scalar_lambda_split(k): - """Equivalent to secp256k1_scalar_lambda_split().""" - c1 = rnddiv2((k * G1) >> 383) - c2 = rnddiv2((k * G2) >> 383) - c1 = (c1 * -B1) % N - c2 = (c2 * -B2) % N - r2 = (c1 + c2) % N - r1 = (k + r2 * -LAMBDA) % N - return (r1, r2) - -# The result of scalar_lambda_split can depend on the representation of k (mod n). -SPECIAL = (2**383) // G2 + 1 -assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N) - -print(' A1 =', hex(A1)) -print(' -B1 =', hex(-B1)) -print(' A2 =', hex(A2)) -print(' -B2 =', hex(-B2)) -print(' =', hex(Z(-B2))) -print(' -LAMBDA =', hex(-LAMBDA)) - -print(' G1 =', hex(G1)) -print(' G2 =', hex(G2)) diff --git a/external/secp256k1/sage/group_prover.sage b/external/secp256k1/sage/group_prover.sage deleted file mode 100644 index bb09295369..0000000000 --- a/external/secp256k1/sage/group_prover.sage +++ /dev/null @@ -1,353 +0,0 @@ -# This code supports verifying group implementations which have branches -# or conditional statements (like cmovs), by allowing each execution path -# to independently set assumptions on input or intermediary variables. -# -# The general approach is: -# * A constraint is a tuple of two sets of symbolic expressions: -# the first of which are required to evaluate to zero, the second of which -# are required to evaluate to nonzero. -# - A constraint is said to be conflicting if any of its nonzero expressions -# is in the ideal with basis the zero expressions (in other words: when the -# zero expressions imply that one of the nonzero expressions are zero). -# * There is a list of laws that describe the intended behaviour, including -# laws for addition and doubling. Each law is called with the symbolic point -# coordinates as arguments, and returns: -# - A constraint describing the assumptions under which it is applicable, -# called "assumeLaw" -# - A constraint describing the requirements of the law, called "require" -# * Implementations are transliterated into functions that operate as well on -# algebraic input points, and are called once per combination of branches -# executed. Each execution returns: -# - A constraint describing the assumptions this implementation requires -# (such as Z1=1), called "assumeFormula" -# - A constraint describing the assumptions this specific branch requires, -# but which is by construction guaranteed to cover the entire space by -# merging the results from all branches, called "assumeBranch" -# - The result of the computation -# * All combinations of laws with implementation branches are tried, and: -# - If the combination of assumeLaw, assumeFormula, and assumeBranch results -# in a conflict, it means this law does not apply to this branch, and it is -# skipped. -# - For others, we try to prove the require constraints hold, assuming the -# information in assumeLaw + assumeFormula + assumeBranch, and if this does -# not succeed, we fail. -# + To prove an expression is zero, we check whether it belongs to the -# ideal with the assumed zero expressions as basis. This test is exact. -# + To prove an expression is nonzero, we check whether each of its -# factors is contained in the set of nonzero assumptions' factors. -# This test is not exact, so various combinations of original and -# reduced expressions' factors are tried. -# - If we succeed, we print out the assumptions from assumeFormula that -# weren't implied by assumeLaw already. Those from assumeBranch are skipped, -# as we assume that all constraints in it are complementary with each other. -# -# Based on the sage verification scripts used in the Explicit-Formulas Database -# by Tanja Lange and others, see https://hyperelliptic.org/EFD - -class fastfrac: - """Fractions over rings.""" - - def __init__(self,R,top,bot=1): - """Construct a fractional, given a ring, a numerator, and denominator.""" - self.R = R - if parent(top) == ZZ or parent(top) == R: - self.top = R(top) - self.bot = R(bot) - elif top.__class__ == fastfrac: - self.top = top.top - self.bot = top.bot * bot - else: - self.top = R(numerator(top)) - self.bot = R(denominator(top)) * bot - - def iszero(self,I): - """Return whether this fraction is zero given an ideal.""" - return self.top in I and self.bot not in I - - def reduce(self,assumeZero): - zero = self.R.ideal(list(map(numerator, assumeZero))) - return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) - - def __add__(self,other): - """Add two fractions.""" - if parent(other) == ZZ: - return fastfrac(self.R,self.top + self.bot * other,self.bot) - if other.__class__ == fastfrac: - return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) - return NotImplemented - - def __sub__(self,other): - """Subtract two fractions.""" - if parent(other) == ZZ: - return fastfrac(self.R,self.top - self.bot * other,self.bot) - if other.__class__ == fastfrac: - return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) - return NotImplemented - - def __neg__(self): - """Return the negation of a fraction.""" - return fastfrac(self.R,-self.top,self.bot) - - def __mul__(self,other): - """Multiply two fractions.""" - if parent(other) == ZZ: - return fastfrac(self.R,self.top * other,self.bot) - if other.__class__ == fastfrac: - return fastfrac(self.R,self.top * other.top,self.bot * other.bot) - return NotImplemented - - def __rmul__(self,other): - """Multiply something else with a fraction.""" - return self.__mul__(other) - - def __truediv__(self,other): - """Divide two fractions.""" - if parent(other) == ZZ: - return fastfrac(self.R,self.top,self.bot * other) - if other.__class__ == fastfrac: - return fastfrac(self.R,self.top * other.bot,self.bot * other.top) - return NotImplemented - - # Compatibility wrapper for Sage versions based on Python 2 - def __div__(self,other): - """Divide two fractions.""" - return self.__truediv__(other) - - def __pow__(self,other): - """Compute a power of a fraction.""" - if parent(other) == ZZ: - if other < 0: - # Negative powers require flipping top and bottom - return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) - else: - return fastfrac(self.R,self.top ^ other,self.bot ^ other) - return NotImplemented - - def __str__(self): - return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" - def __repr__(self): - return "%s" % self - - def numerator(self): - return self.top - -class constraints: - """A set of constraints, consisting of zero and nonzero expressions. - - Constraints can either be used to express knowledge or a requirement. - - Both the fields zero and nonzero are maps from expressions to description - strings. The expressions that are the keys in zero are required to be zero, - and the expressions that are the keys in nonzero are required to be nonzero. - - Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in - nonzero could be multiplied into a single key. This is often much less - efficient to work with though, so we keep them separate inside the - constraints. This allows higher-level code to do fast checks on the individual - nonzero elements, or combine them if needed for stronger checks. - - We can't multiply the different zero elements, as it would suffice for one of - the factors to be zero, instead of all of them. Instead, the zero elements are - typically combined into an ideal first. - """ - - def __init__(self, **kwargs): - if 'zero' in kwargs: - self.zero = dict(kwargs['zero']) - else: - self.zero = dict() - if 'nonzero' in kwargs: - self.nonzero = dict(kwargs['nonzero']) - else: - self.nonzero = dict() - - def negate(self): - return constraints(zero=self.nonzero, nonzero=self.zero) - - def map(self, fun): - return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()}) - - def __add__(self, other): - zero = self.zero.copy() - zero.update(other.zero) - nonzero = self.nonzero.copy() - nonzero.update(other.nonzero) - return constraints(zero=zero, nonzero=nonzero) - - def __str__(self): - return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) - - def __repr__(self): - return "%s" % self - -def normalize_factor(p): - """Normalizes the sign of primitive polynomials (as returned by factor()) - - This function ensures that the polynomial has a positive leading coefficient. - - This is necessary because recent sage versions (starting with v9.3 or v9.4, - we don't know) are inconsistent about the placement of the minus sign in - polynomial factorizations: - ``` - sage: R. = PolynomialRing(QQ,8,order='invlex') - sage: R((-2 * (bx - ax)) ^ 1).factor() - (-2) * (bx - ax) - sage: R((-2 * (bx - ax)) ^ 2).factor() - (4) * (-bx + ax)^2 - sage: R((-2 * (bx - ax)) ^ 3).factor() - (8) * (-bx + ax)^3 - ``` - """ - # Assert p is not 0 and that its non-zero coefficients are coprime. - # (We could just work with the primitive part p/p.content() but we want to be - # aware if factor() does not return a primitive part in future sage versions.) - assert p.content() == 1 - # Ensure that the first non-zero coefficient is positive. - return p if p.lc() > 0 else -p - -def conflicts(R, con): - """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" - zero = R.ideal(list(map(numerator, con.zero))) - if 1 in zero: - return True - # First a cheap check whether any of the individual nonzero terms conflict on - # their own. - for nonzero in con.nonzero: - if nonzero.iszero(zero): - return True - # It can be the case that entries in the nonzero set do not individually - # conflict with the zero set, but their combination does. For example, knowing - # that either x or y is zero is equivalent to having x*y in the zero set. - # Having x or y individually in the nonzero set is not a conflict, but both - # simultaneously is, so that is the right thing to check for. - if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): - return True - return False - - -def get_nonzero_set(R, assume): - """Calculate a simple set of nonzero expressions""" - zero = R.ideal(list(map(numerator, assume.zero))) - nonzero = set() - for nz in map(numerator, assume.nonzero): - for (f,n) in nz.factor(): - nonzero.add(normalize_factor(f)) - rnz = zero.reduce(nz) - for (f,n) in rnz.factor(): - nonzero.add(normalize_factor(f)) - return nonzero - - -def prove_nonzero(R, exprs, assume): - """Check whether an expression is provably nonzero, given assumptions""" - zero = R.ideal(list(map(numerator, assume.zero))) - nonzero = get_nonzero_set(R, assume) - expl = set() - ok = True - for expr in exprs: - if numerator(expr) in zero: - return (False, [exprs[expr]]) - allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) - for (f, n) in allexprs.factor(): - if normalize_factor(f) not in nonzero: - ok = False - if ok: - return (True, None) - ok = True - for (f, n) in zero.reduce(allexprs).factor(): - if normalize_factor(f) not in nonzero: - ok = False - if ok: - return (True, None) - ok = True - for expr in exprs: - for (f,n) in numerator(expr).factor(): - if normalize_factor(f) not in nonzero: - ok = False - if ok: - return (True, None) - ok = True - for expr in exprs: - for (f,n) in zero.reduce(numerator(expr)).factor(): - if normalize_factor(f) not in nonzero: - expl.add(exprs[expr]) - if expl: - return (False, list(expl)) - else: - return (True, None) - - -def prove_zero(R, exprs, assume): - """Check whether all of the passed expressions are provably zero, given assumptions""" - r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) - if not r: - return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e))) - zero = R.ideal(list(map(numerator, assume.zero))) - nonzero = prod(x for x in assume.nonzero) - expl = [] - for expr in exprs: - if not expr.iszero(zero): - expl.append(exprs[expr]) - if not expl: - return (True, None) - return (False, expl) - - -def describe_extra(R, assume, assumeExtra): - """Describe what assumptions are added, given existing assumptions""" - zerox = assume.zero.copy() - zerox.update(assumeExtra.zero) - zero = R.ideal(list(map(numerator, assume.zero))) - zeroextra = R.ideal(list(map(numerator, zerox))) - nonzero = get_nonzero_set(R, assume) - ret = set() - # Iterate over the extra zero expressions - for base in assumeExtra.zero: - if base not in zero: - add = [] - for (f, n) in numerator(base).factor(): - if normalize_factor(f) not in nonzero: - add += ["%s" % normalize_factor(f)] - if add: - ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) - # Iterate over the extra nonzero expressions - for nz in assumeExtra.nonzero: - nzr = zeroextra.reduce(numerator(nz)) - if nzr not in zeroextra: - for (f,n) in nzr.factor(): - if normalize_factor(zeroextra.reduce(f)) not in nonzero: - ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f))) - return ", ".join(x for x in ret) - - -def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): - """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" - assume = assumeLaw + assumeAssert + assumeBranch - - if conflicts(R, assume): - # This formula does not apply - return (True, None) - - describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) - if describe != "": - describe = " (assuming " + describe + ")" - - ok, msg = prove_zero(R, require.zero, assume) - if not ok: - return (False, "FAIL, %s fails%s" % (str(msg), describe)) - - res, expl = prove_nonzero(R, require.nonzero, assume) - if not res: - return (False, "FAIL, %s fails%s" % (str(expl), describe)) - - return (True, "OK%s" % describe) - - -def concrete_verify(c): - for k in c.zero: - if k != 0: - return (False, c.zero[k]) - for k in c.nonzero: - if k == 0: - return (False, c.nonzero[k]) - return (True, None) diff --git a/external/secp256k1/sage/prove_group_implementations.sage b/external/secp256k1/sage/prove_group_implementations.sage deleted file mode 100644 index 23799be52b..0000000000 --- a/external/secp256k1/sage/prove_group_implementations.sage +++ /dev/null @@ -1,285 +0,0 @@ -# Test libsecp256k1' group operation implementations using prover.sage - -import sys - -load("group_prover.sage") -load("weierstrass_prover.sage") - -def formula_secp256k1_gej_double_var(a): - """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" - rz = a.Z * a.Y - s = a.Y^2 - l = a.X^2 - l = l * 3 - l = l / 2 - t = -s - t = t * a.X - rx = l^2 - rx = rx + t - rx = rx + t - s = s^2 - t = t + rx - ry = t * l - ry = ry + s - ry = -ry - return jacobianpoint(rx, ry, rz) - -def formula_secp256k1_gej_add_var(branch, a, b): - """libsecp256k1's secp256k1_gej_add_var""" - if branch == 0: - return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) - if branch == 1: - return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) - z22 = b.Z^2 - z12 = a.Z^2 - u1 = a.X * z22 - u2 = b.X * z12 - s1 = a.Y * z22 - s1 = s1 * b.Z - s2 = b.Y * z12 - s2 = s2 * a.Z - h = -u1 - h = h + u2 - i = -s2 - i = i + s1 - if branch == 2: - r = formula_secp256k1_gej_double_var(a) - return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) - if branch == 3: - return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) - t = h * b.Z - rz = a.Z * t - h2 = h^2 - h2 = -h2 - h3 = h2 * h - t = u1 * h2 - rx = i^2 - rx = rx + h3 - rx = rx + t - rx = rx + t - t = t + rx - ry = t * i - h3 = h3 * s1 - ry = ry + h3 - return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) - -def formula_secp256k1_gej_add_ge_var(branch, a, b): - """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" - if branch == 0: - return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) - if branch == 1: - return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) - z12 = a.Z^2 - u1 = a.X - u2 = b.X * z12 - s1 = a.Y - s2 = b.Y * z12 - s2 = s2 * a.Z - h = -u1 - h = h + u2 - i = -s2 - i = i + s1 - if (branch == 2): - r = formula_secp256k1_gej_double_var(a) - return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) - if (branch == 3): - return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - rz = a.Z * h - h2 = h^2 - h2 = -h2 - h3 = h2 * h - t = u1 * h2 - rx = i^2 - rx = rx + h3 - rx = rx + t - rx = rx + t - t = t + rx - ry = t * i - h3 = h3 * s1 - ry = ry + h3 - return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) - -def formula_secp256k1_gej_add_zinv_var(branch, a, b): - """libsecp256k1's secp256k1_gej_add_zinv_var""" - bzinv = b.Z^(-1) - if branch == 0: - rinf = b.Infinity - bzinv2 = bzinv^2 - bzinv3 = bzinv2 * bzinv - rx = b.X * bzinv2 - ry = b.Y * bzinv3 - rz = 1 - return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz, rinf)) - if branch == 1: - return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) - azz = a.Z * bzinv - z12 = azz^2 - u1 = a.X - u2 = b.X * z12 - s1 = a.Y - s2 = b.Y * z12 - s2 = s2 * azz - h = -u1 - h = h + u2 - i = -s2 - i = i + s1 - if branch == 2: - r = formula_secp256k1_gej_double_var(a) - return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) - if branch == 3: - return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - rz = a.Z * h - h2 = h^2 - h2 = -h2 - h3 = h2 * h - t = u1 * h2 - rx = i^2 - rx = rx + h3 - rx = rx + t - rx = rx + t - t = t + rx - ry = t * i - h3 = h3 * s1 - ry = ry + h3 - return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) - -def formula_secp256k1_gej_add_ge(branch, a, b): - """libsecp256k1's secp256k1_gej_add_ge""" - zeroes = {} - nonzeroes = {} - a_infinity = False - if (branch & 2) != 0: - nonzeroes.update({a.Infinity : 'a_infinite'}) - a_infinity = True - else: - zeroes.update({a.Infinity : 'a_finite'}) - zz = a.Z^2 - u1 = a.X - u2 = b.X * zz - s1 = a.Y - s2 = b.Y * zz - s2 = s2 * a.Z - t = u1 - t = t + u2 - m = s1 - m = m + s2 - rr = t^2 - m_alt = -u2 - tt = u1 * m_alt - rr = rr + tt - degenerate = (branch & 1) != 0 - if degenerate: - zeroes.update({m : 'm_zero'}) - else: - nonzeroes.update({m : 'm_nonzero'}) - rr_alt = s1 - rr_alt = rr_alt * 2 - m_alt = m_alt + u1 - if not degenerate: - rr_alt = rr - m_alt = m - n = m_alt^2 - q = -t - q = q * n - n = n^2 - if degenerate: - n = m - t = rr_alt^2 - rz = a.Z * m_alt - t = t + q - rx = t - t = t * 2 - t = t + q - t = t * rr_alt - t = t + n - ry = -t - ry = ry / 2 - if a_infinity: - rx = b.X - ry = b.Y - rz = 1 - if (branch & 4) != 0: - zeroes.update({rz : 'r.z = 0'}) - return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) - else: - nonzeroes.update({rz : 'r.z != 0'}) - return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) - -def formula_secp256k1_gej_add_ge_old(branch, a, b): - """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" - a_infinity = (branch & 1) != 0 - zero = {} - nonzero = {} - if a_infinity: - nonzero.update({a.Infinity : 'a_infinite'}) - else: - zero.update({a.Infinity : 'a_finite'}) - zz = a.Z^2 - u1 = a.X - u2 = b.X * zz - s1 = a.Y - s2 = b.Y * zz - s2 = s2 * a.Z - z = a.Z - t = u1 - t = t + u2 - m = s1 - m = m + s2 - n = m^2 - q = n * t - n = n^2 - rr = t^2 - t = u1 * u2 - t = -t - rr = rr + t - t = rr^2 - rz = m * z - infinity = False - if (branch & 2) != 0: - if not a_infinity: - infinity = True - else: - return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) - zero.update({rz : 'r.z=0'}) - else: - nonzero.update({rz : 'r.z!=0'}) - rz = rz * (0 if a_infinity else 2) - rx = t - q = -q - rx = rx + q - q = q * 3 - t = t * 2 - t = t + q - t = t * rr - t = t + n - ry = -t - rx = rx * (0 if a_infinity else 4) - ry = ry * (0 if a_infinity else 4) - t = b.X - t = t * (1 if a_infinity else 0) - rx = rx + t - t = b.Y - t = t * (1 if a_infinity else 0) - ry = ry + t - t = (1 if a_infinity else 0) - rz = rz + t - if infinity: - return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) - return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) - -if __name__ == "__main__": - success = True - success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) - success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) - success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) - success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge) - success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)) - - if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": - success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43) - success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)) - - sys.exit(int(not success)) diff --git a/external/secp256k1/sage/secp256k1_params.sage b/external/secp256k1/sage/secp256k1_params.sage deleted file mode 100644 index 68f95adec4..0000000000 --- a/external/secp256k1/sage/secp256k1_params.sage +++ /dev/null @@ -1,39 +0,0 @@ -"""Prime order of finite field underlying secp256k1 (2^256 - 2^32 - 977)""" -P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - -"""Finite field underlying secp256k1""" -F = FiniteField(P) - -"""Elliptic curve secp256k1: y^2 = x^3 + 7""" -C = EllipticCurve([F(0), F(7)]) - -"""Base point of secp256k1""" -G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) -if int(G[1]) & 1: - # G.y is even - G = -G - -"""Prime order of secp256k1""" -N = C.order() - -"""Finite field of scalars of secp256k1""" -Z = FiniteField(N) - -""" Beta value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" -BETA = F(2)^((P-1)/3) - -""" Lambda value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" -LAMBDA = Z(3)^((N-1)/3) - -assert is_prime(P) -assert is_prime(N) - -assert BETA != F(1) -assert BETA^3 == F(1) -assert BETA^2 + BETA + 1 == 0 - -assert LAMBDA != Z(1) -assert LAMBDA^3 == Z(1) -assert LAMBDA^2 + LAMBDA + 1 == 0 - -assert Integer(LAMBDA)*G == C(BETA*G[0], G[1]) diff --git a/external/secp256k1/sage/weierstrass_prover.sage b/external/secp256k1/sage/weierstrass_prover.sage deleted file mode 100644 index be9cfd4c76..0000000000 --- a/external/secp256k1/sage/weierstrass_prover.sage +++ /dev/null @@ -1,275 +0,0 @@ -# Prover implementation for Weierstrass curves of the form -# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws -# operating on affine and Jacobian coordinates, including the point at infinity -# represented by a 4th variable in coordinates. - -load("group_prover.sage") - - -class affinepoint: - def __init__(self, x, y, infinity=0): - self.x = x - self.y = y - self.infinity = infinity - def __str__(self): - return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) - - -class jacobianpoint: - def __init__(self, x, y, z, infinity=0): - self.X = x - self.Y = y - self.Z = z - self.Infinity = infinity - def __str__(self): - return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) - - -def point_at_infinity(): - return jacobianpoint(1, 1, 1, 1) - - -def negate(p): - if p.__class__ == affinepoint: - return affinepoint(p.x, -p.y) - if p.__class__ == jacobianpoint: - return jacobianpoint(p.X, -p.Y, p.Z) - assert(False) - - -def on_weierstrass_curve(A, B, p): - """Return a set of zero-expressions for an affine point to be on the curve""" - return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) - - -def tangential_to_weierstrass_curve(A, B, p12, p3): - """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" - return constraints(zero={ - (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' - }) - - -def colinear(p1, p2, p3): - """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" - return constraints(zero={ - (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', - (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', - (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' - }) - - -def good_affine_point(p): - return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) - - -def good_jacobian_point(p): - return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) - - -def good_point(p): - return constraints(nonzero={p.Z^6 : 'nonzero_X'}) - - -def finite(p, *affine_fns): - con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) - if p.Z != 0: - return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) - else: - return con - -def infinite(p): - return constraints(nonzero={p.Infinity : 'infinite_point'}) - - -def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): - """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - on_weierstrass_curve(A, B, pa) + - on_weierstrass_curve(A, B, pb) + - finite(pA) + - finite(pB) + - constraints(nonzero={pa.x - pb.x : 'different_x'})) - require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + - colinear(pa, pb, negate(pc)))) - return (assumeLaw, require) - - -def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): - """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - on_weierstrass_curve(A, B, pa) + - on_weierstrass_curve(A, B, pb) + - finite(pA) + - finite(pB) + - constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) - require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + - tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) - return (assumeLaw, require) - - -def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - on_weierstrass_curve(A, B, pa) + - on_weierstrass_curve(A, B, pb) + - finite(pA) + - finite(pB) + - constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) - require = infinite(pC) - return (assumeLaw, require) - - -def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - on_weierstrass_curve(A, B, pb) + - infinite(pA) + - finite(pB)) - require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) - return (assumeLaw, require) - - -def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - on_weierstrass_curve(A, B, pa) + - infinite(pB) + - finite(pA)) - require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) - return (assumeLaw, require) - - -def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): - assumeLaw = (good_affine_point(pa) + - good_affine_point(pb) + - good_jacobian_point(pA) + - good_jacobian_point(pB) + - infinite(pA) + - infinite(pB)) - require = infinite(pC) - return (assumeLaw, require) - - -laws_jacobian_weierstrass = { - 'add': law_jacobian_weierstrass_add, - 'double': law_jacobian_weierstrass_double, - 'add_opposite': law_jacobian_weierstrass_add_opposites, - 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, - 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, - 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab -} - - -def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): - """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" - F = Integers(p) - print("Formula %s on Z%i:" % (name, p)) - points = [] - for x in range(0, p): - for y in range(0, p): - point = affinepoint(F(x), F(y)) - r, e = concrete_verify(on_weierstrass_curve(A, B, point)) - if r: - points.append(point) - - ret = True - for za in range(1, p): - for zb in range(1, p): - for pa in points: - for pb in points: - for ia in range(2): - for ib in range(2): - pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) - pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) - for branch in range(0, branches): - assumeAssert, assumeBranch, pC = formula(branch, pA, pB) - pC.X = F(pC.X) - pC.Y = F(pC.Y) - pC.Z = F(pC.Z) - pC.Infinity = F(pC.Infinity) - r, e = concrete_verify(assumeAssert + assumeBranch) - if r: - match = False - for key in laws_jacobian_weierstrass: - assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) - r, e = concrete_verify(assumeLaw) - if r: - if match: - print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)) - else: - match = True - r, e = concrete_verify(require) - if not r: - ret = False - print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)) - - print() - return ret - - -def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): - assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) - return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) - -def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): - """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" - R. = PolynomialRing(QQ,8,order='invlex') - lift = lambda x: fastfrac(R,x) - ax = lift(ax) - ay = lift(ay) - Az = lift(Az) - bx = lift(bx) - by = lift(by) - Bz = lift(Bz) - Ai = lift(Ai) - Bi = lift(Bi) - - pa = affinepoint(ax, ay, Ai) - pb = affinepoint(bx, by, Bi) - pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) - pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) - - res = {} - - for key in laws_jacobian_weierstrass: - res[key] = [] - - print("Formula " + name + ":") - count = 0 - ret = True - for branch in range(branches): - assumeFormula, assumeBranch, pC = formula(branch, pA, pB) - assumeBranch = assumeBranch.map(lift) - assumeFormula = assumeFormula.map(lift) - pC.X = lift(pC.X) - pC.Y = lift(pC.Y) - pC.Z = lift(pC.Z) - pC.Infinity = lift(pC.Infinity) - - for key in laws_jacobian_weierstrass: - success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC) - if not success: - ret = False - res[key].append((msg, branch)) - - for key in res: - print(" %s:" % key) - val = res[key] - for x in val: - if x[0] is not None: - print(" branch %i: %s" % (x[1], x[0])) - - print() - return ret diff --git a/external/secp256k1/src/CMakeLists.txt b/external/secp256k1/src/CMakeLists.txt deleted file mode 100644 index f31b8c8f55..0000000000 --- a/external/secp256k1/src/CMakeLists.txt +++ /dev/null @@ -1,176 +0,0 @@ -# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. -include(GNUInstallDirs) - -add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL - precomputed_ecmult.c - precomputed_ecmult_gen.c -) - -# Add objects explicitly rather than linking to the object libs to keep them -# from being exported. -add_library(secp256k1 secp256k1.c $) - -add_library(secp256k1_asm INTERFACE) -if(SECP256K1_ASM STREQUAL "arm32") - add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) - target_sources(secp256k1_asm_arm PUBLIC - asm/field_10x26_arm.s - ) - target_sources(secp256k1 PRIVATE $) - target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm) -endif() - -if(WIN32) - # Define our export symbol only for shared libs. - set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT) - target_compile_definitions(secp256k1 INTERFACE $<$>:SECP256K1_STATIC>) -endif() - -# Object libs don't know if they're being built for a shared or static lib. -# Grab the PIC property from secp256k1 which knows. -get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) -set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) - -target_include_directories(secp256k1 INTERFACE - # Add the include path for parent projects so that they don't have to manually add it. - $>:${PROJECT_SOURCE_DIR}/include>> - $ -) - -# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, -# see below "Calculate the version variables" in build-aux/ltmain.sh. -math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") -set_target_properties(secp256k1 PROPERTIES - SOVERSION ${${PROJECT_NAME}_soversion} -) -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set_target_properties(secp256k1 PROPERTIES - VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) -elseif(APPLE) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) - math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") - set_target_properties(secp256k1 PROPERTIES - MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} - MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) - unset(${PROJECT_NAME}_compatibility_version) - elseif(BUILD_SHARED_LIBS) - message(WARNING - "The 'compatibility version' and 'current version' values of the DYLIB " - "will diverge from the values set by the GNU Libtool. To ensure " - "compatibility, it is recommended to upgrade CMake to at least version 3.17." - ) - endif() -elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(${PROJECT_NAME}_windows "secp256k1") - if(MSVC) - set(${PROJECT_NAME}_windows "${PROJECT_NAME}") - endif() - set_target_properties(secp256k1 PROPERTIES - ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" - RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" - ) - unset(${PROJECT_NAME}_windows) -endif() -unset(${PROJECT_NAME}_soversion) - -if(SECP256K1_BUILD_BENCHMARK) - add_executable(bench bench.c) - target_link_libraries(bench secp256k1) - add_executable(bench_internal bench_internal.c) - target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm) - add_executable(bench_ecmult bench_ecmult.c) - target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm) -endif() - -if(SECP256K1_BUILD_TESTS) - add_executable(noverify_tests tests.c) - target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) - add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests) - if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") - add_executable(tests tests.c) - target_compile_definitions(tests PRIVATE VERIFY) - target_link_libraries(tests secp256k1_precomputed secp256k1_asm) - add_test(NAME secp256k1_tests COMMAND tests) - endif() -endif() - -if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) - # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables). - add_executable(exhaustive_tests tests_exhaustive.c) - target_link_libraries(exhaustive_tests secp256k1_asm) - target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) - add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests) -endif() - -if(SECP256K1_BUILD_CTIME_TESTS) - add_executable(ctime_tests ctime_tests.c) - target_link_libraries(ctime_tests secp256k1) -endif() - -if(SECP256K1_INSTALL) - install(TARGETS secp256k1 - EXPORT ${PROJECT_NAME}-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) - set(${PROJECT_NAME}_headers - "${PROJECT_SOURCE_DIR}/include/secp256k1.h" - "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" - ) - if(SECP256K1_ENABLE_MODULE_ECDH) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") - endif() - if(SECP256K1_ENABLE_MODULE_RECOVERY) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") - endif() - if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") - endif() - if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") - endif() - if(SECP256K1_ENABLE_MODULE_MUSIG) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h") - endif() - if(SECP256K1_ENABLE_MODULE_ELLSWIFT) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h") - endif() - install(FILES ${${PROJECT_NAME}_headers} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ) - - install(EXPORT ${PROJECT_NAME}-targets - FILE ${PROJECT_NAME}-targets.cmake - NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - ) - - include(CMakePackageConfigHelpers) - configure_package_config_file( - ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in - ${PROJECT_NAME}-config.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - NO_SET_AND_CHECK_MACRO - ) - write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake - COMPATIBILITY SameMinorVersion - ) - - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - ) - - include(GeneratePkgConfigFile) - generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig - ) -endif() diff --git a/external/secp256k1/src/asm/field_10x26_arm.s b/external/secp256k1/src/asm/field_10x26_arm.s deleted file mode 100644 index 664b921400..0000000000 --- a/external/secp256k1/src/asm/field_10x26_arm.s +++ /dev/null @@ -1,916 +0,0 @@ -@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: -/*********************************************************************** - * Copyright (c) 2014 Wladimir J. van der Laan * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ -/* -ARM implementation of field_10x26 inner loops. - -Note: - -- To avoid unnecessary loads and make use of available registers, two - 'passes' have every time been interleaved, with the odd passes accumulating c' and d' - which will be added to c and d respectively in the even passes - -*/ - - .syntax unified - @ eabi attributes - see readelf -A - .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte - .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .text - - @ Field constants - .set field_R0, 0x3d10 - .set field_R1, 0x400 - .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff - - .align 2 - .global secp256k1_fe_mul_inner - .type secp256k1_fe_mul_inner, %function - .hidden secp256k1_fe_mul_inner - @ Arguments: - @ r0 r Restrict: can overlap with a, not with b - @ r1 a - @ r2 b - @ Stack (total 4+10*4 = 44) - @ sp + #0 saved 'r' pointer - @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 -secp256k1_fe_mul_inner: - stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} - sub sp, sp, #48 @ frame=44 + alignment - str r0, [sp, #0] @ save result address, we need it only at the end - - /****************************************** - * Main computation code. - ****************************************** - - Allocation: - r0,r14,r7,r8 scratch - r1 a (pointer) - r2 b (pointer) - r3:r4 c - r5:r6 d - r11:r12 c' - r9:r10 d' - - Note: do not write to r[] here, it may overlap with a[] - */ - - /* A - interleaved with B */ - ldr r7, [r1, #0*4] @ a[0] - ldr r8, [r2, #9*4] @ b[9] - ldr r0, [r1, #1*4] @ a[1] - umull r5, r6, r7, r8 @ d = a[0] * b[9] - ldr r14, [r2, #8*4] @ b[8] - umull r9, r10, r0, r8 @ d' = a[1] * b[9] - ldr r7, [r1, #2*4] @ a[2] - umlal r5, r6, r0, r14 @ d += a[1] * b[8] - ldr r8, [r2, #7*4] @ b[7] - umlal r9, r10, r7, r14 @ d' += a[2] * b[8] - ldr r0, [r1, #3*4] @ a[3] - umlal r5, r6, r7, r8 @ d += a[2] * b[7] - ldr r14, [r2, #6*4] @ b[6] - umlal r9, r10, r0, r8 @ d' += a[3] * b[7] - ldr r7, [r1, #4*4] @ a[4] - umlal r5, r6, r0, r14 @ d += a[3] * b[6] - ldr r8, [r2, #5*4] @ b[5] - umlal r9, r10, r7, r14 @ d' += a[4] * b[6] - ldr r0, [r1, #5*4] @ a[5] - umlal r5, r6, r7, r8 @ d += a[4] * b[5] - ldr r14, [r2, #4*4] @ b[4] - umlal r9, r10, r0, r8 @ d' += a[5] * b[5] - ldr r7, [r1, #6*4] @ a[6] - umlal r5, r6, r0, r14 @ d += a[5] * b[4] - ldr r8, [r2, #3*4] @ b[3] - umlal r9, r10, r7, r14 @ d' += a[6] * b[4] - ldr r0, [r1, #7*4] @ a[7] - umlal r5, r6, r7, r8 @ d += a[6] * b[3] - ldr r14, [r2, #2*4] @ b[2] - umlal r9, r10, r0, r8 @ d' += a[7] * b[3] - ldr r7, [r1, #8*4] @ a[8] - umlal r5, r6, r0, r14 @ d += a[7] * b[2] - ldr r8, [r2, #1*4] @ b[1] - umlal r9, r10, r7, r14 @ d' += a[8] * b[2] - ldr r0, [r1, #9*4] @ a[9] - umlal r5, r6, r7, r8 @ d += a[8] * b[1] - ldr r14, [r2, #0*4] @ b[0] - umlal r9, r10, r0, r8 @ d' += a[9] * b[1] - ldr r7, [r1, #0*4] @ a[0] - umlal r5, r6, r0, r14 @ d += a[9] * b[0] - @ r7,r14 used in B - - bic r0, r5, field_not_M @ t9 = d & M - str r0, [sp, #4 + 4*9] - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - - /* B */ - umull r3, r4, r7, r14 @ c = a[0] * b[0] - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u0 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u0 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t0 = c & M - str r14, [sp, #4 + 0*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u0 * R1 - umlal r3, r4, r0, r14 - - /* C - interleaved with D */ - ldr r7, [r1, #0*4] @ a[0] - ldr r8, [r2, #2*4] @ b[2] - ldr r14, [r2, #1*4] @ b[1] - umull r11, r12, r7, r8 @ c' = a[0] * b[2] - ldr r0, [r1, #1*4] @ a[1] - umlal r3, r4, r7, r14 @ c += a[0] * b[1] - ldr r8, [r2, #0*4] @ b[0] - umlal r11, r12, r0, r14 @ c' += a[1] * b[1] - ldr r7, [r1, #2*4] @ a[2] - umlal r3, r4, r0, r8 @ c += a[1] * b[0] - ldr r14, [r2, #9*4] @ b[9] - umlal r11, r12, r7, r8 @ c' += a[2] * b[0] - ldr r0, [r1, #3*4] @ a[3] - umlal r5, r6, r7, r14 @ d += a[2] * b[9] - ldr r8, [r2, #8*4] @ b[8] - umull r9, r10, r0, r14 @ d' = a[3] * b[9] - ldr r7, [r1, #4*4] @ a[4] - umlal r5, r6, r0, r8 @ d += a[3] * b[8] - ldr r14, [r2, #7*4] @ b[7] - umlal r9, r10, r7, r8 @ d' += a[4] * b[8] - ldr r0, [r1, #5*4] @ a[5] - umlal r5, r6, r7, r14 @ d += a[4] * b[7] - ldr r8, [r2, #6*4] @ b[6] - umlal r9, r10, r0, r14 @ d' += a[5] * b[7] - ldr r7, [r1, #6*4] @ a[6] - umlal r5, r6, r0, r8 @ d += a[5] * b[6] - ldr r14, [r2, #5*4] @ b[5] - umlal r9, r10, r7, r8 @ d' += a[6] * b[6] - ldr r0, [r1, #7*4] @ a[7] - umlal r5, r6, r7, r14 @ d += a[6] * b[5] - ldr r8, [r2, #4*4] @ b[4] - umlal r9, r10, r0, r14 @ d' += a[7] * b[5] - ldr r7, [r1, #8*4] @ a[8] - umlal r5, r6, r0, r8 @ d += a[7] * b[4] - ldr r14, [r2, #3*4] @ b[3] - umlal r9, r10, r7, r8 @ d' += a[8] * b[4] - ldr r0, [r1, #9*4] @ a[9] - umlal r5, r6, r7, r14 @ d += a[8] * b[3] - ldr r8, [r2, #2*4] @ b[2] - umlal r9, r10, r0, r14 @ d' += a[9] * b[3] - umlal r5, r6, r0, r8 @ d += a[9] * b[2] - - bic r0, r5, field_not_M @ u1 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u1 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t1 = c & M - str r14, [sp, #4 + 1*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u1 * R1 - umlal r3, r4, r0, r14 - - /* D */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u2 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u2 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t2 = c & M - str r14, [sp, #4 + 2*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u2 * R1 - umlal r3, r4, r0, r14 - - /* E - interleaved with F */ - ldr r7, [r1, #0*4] @ a[0] - ldr r8, [r2, #4*4] @ b[4] - umull r11, r12, r7, r8 @ c' = a[0] * b[4] - ldr r8, [r2, #3*4] @ b[3] - umlal r3, r4, r7, r8 @ c += a[0] * b[3] - ldr r7, [r1, #1*4] @ a[1] - umlal r11, r12, r7, r8 @ c' += a[1] * b[3] - ldr r8, [r2, #2*4] @ b[2] - umlal r3, r4, r7, r8 @ c += a[1] * b[2] - ldr r7, [r1, #2*4] @ a[2] - umlal r11, r12, r7, r8 @ c' += a[2] * b[2] - ldr r8, [r2, #1*4] @ b[1] - umlal r3, r4, r7, r8 @ c += a[2] * b[1] - ldr r7, [r1, #3*4] @ a[3] - umlal r11, r12, r7, r8 @ c' += a[3] * b[1] - ldr r8, [r2, #0*4] @ b[0] - umlal r3, r4, r7, r8 @ c += a[3] * b[0] - ldr r7, [r1, #4*4] @ a[4] - umlal r11, r12, r7, r8 @ c' += a[4] * b[0] - ldr r8, [r2, #9*4] @ b[9] - umlal r5, r6, r7, r8 @ d += a[4] * b[9] - ldr r7, [r1, #5*4] @ a[5] - umull r9, r10, r7, r8 @ d' = a[5] * b[9] - ldr r8, [r2, #8*4] @ b[8] - umlal r5, r6, r7, r8 @ d += a[5] * b[8] - ldr r7, [r1, #6*4] @ a[6] - umlal r9, r10, r7, r8 @ d' += a[6] * b[8] - ldr r8, [r2, #7*4] @ b[7] - umlal r5, r6, r7, r8 @ d += a[6] * b[7] - ldr r7, [r1, #7*4] @ a[7] - umlal r9, r10, r7, r8 @ d' += a[7] * b[7] - ldr r8, [r2, #6*4] @ b[6] - umlal r5, r6, r7, r8 @ d += a[7] * b[6] - ldr r7, [r1, #8*4] @ a[8] - umlal r9, r10, r7, r8 @ d' += a[8] * b[6] - ldr r8, [r2, #5*4] @ b[5] - umlal r5, r6, r7, r8 @ d += a[8] * b[5] - ldr r7, [r1, #9*4] @ a[9] - umlal r9, r10, r7, r8 @ d' += a[9] * b[5] - ldr r8, [r2, #4*4] @ b[4] - umlal r5, r6, r7, r8 @ d += a[9] * b[4] - - bic r0, r5, field_not_M @ u3 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u3 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t3 = c & M - str r14, [sp, #4 + 3*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u3 * R1 - umlal r3, r4, r0, r14 - - /* F */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u4 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u4 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t4 = c & M - str r14, [sp, #4 + 4*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u4 * R1 - umlal r3, r4, r0, r14 - - /* G - interleaved with H */ - ldr r7, [r1, #0*4] @ a[0] - ldr r8, [r2, #6*4] @ b[6] - ldr r14, [r2, #5*4] @ b[5] - umull r11, r12, r7, r8 @ c' = a[0] * b[6] - ldr r0, [r1, #1*4] @ a[1] - umlal r3, r4, r7, r14 @ c += a[0] * b[5] - ldr r8, [r2, #4*4] @ b[4] - umlal r11, r12, r0, r14 @ c' += a[1] * b[5] - ldr r7, [r1, #2*4] @ a[2] - umlal r3, r4, r0, r8 @ c += a[1] * b[4] - ldr r14, [r2, #3*4] @ b[3] - umlal r11, r12, r7, r8 @ c' += a[2] * b[4] - ldr r0, [r1, #3*4] @ a[3] - umlal r3, r4, r7, r14 @ c += a[2] * b[3] - ldr r8, [r2, #2*4] @ b[2] - umlal r11, r12, r0, r14 @ c' += a[3] * b[3] - ldr r7, [r1, #4*4] @ a[4] - umlal r3, r4, r0, r8 @ c += a[3] * b[2] - ldr r14, [r2, #1*4] @ b[1] - umlal r11, r12, r7, r8 @ c' += a[4] * b[2] - ldr r0, [r1, #5*4] @ a[5] - umlal r3, r4, r7, r14 @ c += a[4] * b[1] - ldr r8, [r2, #0*4] @ b[0] - umlal r11, r12, r0, r14 @ c' += a[5] * b[1] - ldr r7, [r1, #6*4] @ a[6] - umlal r3, r4, r0, r8 @ c += a[5] * b[0] - ldr r14, [r2, #9*4] @ b[9] - umlal r11, r12, r7, r8 @ c' += a[6] * b[0] - ldr r0, [r1, #7*4] @ a[7] - umlal r5, r6, r7, r14 @ d += a[6] * b[9] - ldr r8, [r2, #8*4] @ b[8] - umull r9, r10, r0, r14 @ d' = a[7] * b[9] - ldr r7, [r1, #8*4] @ a[8] - umlal r5, r6, r0, r8 @ d += a[7] * b[8] - ldr r14, [r2, #7*4] @ b[7] - umlal r9, r10, r7, r8 @ d' += a[8] * b[8] - ldr r0, [r1, #9*4] @ a[9] - umlal r5, r6, r7, r14 @ d += a[8] * b[7] - ldr r8, [r2, #6*4] @ b[6] - umlal r9, r10, r0, r14 @ d' += a[9] * b[7] - umlal r5, r6, r0, r8 @ d += a[9] * b[6] - - bic r0, r5, field_not_M @ u5 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u5 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t5 = c & M - str r14, [sp, #4 + 5*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u5 * R1 - umlal r3, r4, r0, r14 - - /* H */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u6 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u6 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t6 = c & M - str r14, [sp, #4 + 6*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u6 * R1 - umlal r3, r4, r0, r14 - - /* I - interleaved with J */ - ldr r8, [r2, #8*4] @ b[8] - ldr r7, [r1, #0*4] @ a[0] - ldr r14, [r2, #7*4] @ b[7] - umull r11, r12, r7, r8 @ c' = a[0] * b[8] - ldr r0, [r1, #1*4] @ a[1] - umlal r3, r4, r7, r14 @ c += a[0] * b[7] - ldr r8, [r2, #6*4] @ b[6] - umlal r11, r12, r0, r14 @ c' += a[1] * b[7] - ldr r7, [r1, #2*4] @ a[2] - umlal r3, r4, r0, r8 @ c += a[1] * b[6] - ldr r14, [r2, #5*4] @ b[5] - umlal r11, r12, r7, r8 @ c' += a[2] * b[6] - ldr r0, [r1, #3*4] @ a[3] - umlal r3, r4, r7, r14 @ c += a[2] * b[5] - ldr r8, [r2, #4*4] @ b[4] - umlal r11, r12, r0, r14 @ c' += a[3] * b[5] - ldr r7, [r1, #4*4] @ a[4] - umlal r3, r4, r0, r8 @ c += a[3] * b[4] - ldr r14, [r2, #3*4] @ b[3] - umlal r11, r12, r7, r8 @ c' += a[4] * b[4] - ldr r0, [r1, #5*4] @ a[5] - umlal r3, r4, r7, r14 @ c += a[4] * b[3] - ldr r8, [r2, #2*4] @ b[2] - umlal r11, r12, r0, r14 @ c' += a[5] * b[3] - ldr r7, [r1, #6*4] @ a[6] - umlal r3, r4, r0, r8 @ c += a[5] * b[2] - ldr r14, [r2, #1*4] @ b[1] - umlal r11, r12, r7, r8 @ c' += a[6] * b[2] - ldr r0, [r1, #7*4] @ a[7] - umlal r3, r4, r7, r14 @ c += a[6] * b[1] - ldr r8, [r2, #0*4] @ b[0] - umlal r11, r12, r0, r14 @ c' += a[7] * b[1] - ldr r7, [r1, #8*4] @ a[8] - umlal r3, r4, r0, r8 @ c += a[7] * b[0] - ldr r14, [r2, #9*4] @ b[9] - umlal r11, r12, r7, r8 @ c' += a[8] * b[0] - ldr r0, [r1, #9*4] @ a[9] - umlal r5, r6, r7, r14 @ d += a[8] * b[9] - ldr r8, [r2, #8*4] @ b[8] - umull r9, r10, r0, r14 @ d' = a[9] * b[9] - umlal r5, r6, r0, r8 @ d += a[9] * b[8] - - bic r0, r5, field_not_M @ u7 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u7 * R0 - umlal r3, r4, r0, r14 - - bic r14, r3, field_not_M @ t7 = c & M - str r14, [sp, #4 + 7*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u7 * R1 - umlal r3, r4, r0, r14 - - /* J */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u8 = d & M - str r0, [sp, #4 + 8*4] - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u8 * R0 - umlal r3, r4, r0, r14 - - /****************************************** - * compute and write back result - ****************************************** - Allocation: - r0 r - r3:r4 c - r5:r6 d - r7 t0 - r8 t1 - r9 t2 - r11 u8 - r12 t9 - r1,r2,r10,r14 scratch - - Note: do not read from a[] after here, it may overlap with r[] - */ - ldr r0, [sp, #0] - add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 - ldmia r1, {r2,r7,r8,r9,r10,r11,r12} - add r1, r0, #3*4 - stmia r1, {r2,r7,r8,r9,r10} - - bic r2, r3, field_not_M @ r[8] = c & M - str r2, [r0, #8*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u8 * R1 - umlal r3, r4, r11, r14 - movw r14, field_R0 @ c += d * R0 - umlal r3, r4, r5, r14 - adds r3, r3, r12 @ c += t9 - adc r4, r4, #0 - - add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 - ldmia r1, {r7,r8,r9} - - ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) - str r2, [r0, #9*4] - mov r3, r3, lsr #22 @ c >>= 22 - orr r3, r3, r4, asl #10 - mov r4, r4, lsr #22 - movw r14, field_R1 << 4 @ c += d * (R1 << 4) - umlal r3, r4, r5, r14 - - movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) - umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) - adds r5, r5, r7 @ d.lo += t0 - mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) - adc r6, r6, 0 @ d.hi += carry - - bic r2, r5, field_not_M @ r[0] = d & M - str r2, [r0, #0*4] - - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - - movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) - umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) - adds r5, r5, r8 @ d.lo += t1 - adc r6, r6, #0 @ d.hi += carry - adds r5, r5, r1 @ d.lo += tmp.lo - mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) - adc r6, r6, r2 @ d.hi += carry + tmp.hi - - bic r2, r5, field_not_M @ r[1] = d & M - str r2, [r0, #1*4] - mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) - orr r5, r5, r6, asl #6 - - add r5, r5, r9 @ d += t2 - str r5, [r0, #2*4] @ r[2] = d - - add sp, sp, #48 - ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} - .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner - - .align 2 - .global secp256k1_fe_sqr_inner - .type secp256k1_fe_sqr_inner, %function - .hidden secp256k1_fe_sqr_inner - @ Arguments: - @ r0 r Can overlap with a - @ r1 a - @ Stack (total 4+10*4 = 44) - @ sp + #0 saved 'r' pointer - @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 -secp256k1_fe_sqr_inner: - stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} - sub sp, sp, #48 @ frame=44 + alignment - str r0, [sp, #0] @ save result address, we need it only at the end - /****************************************** - * Main computation code. - ****************************************** - - Allocation: - r0,r14,r2,r7,r8 scratch - r1 a (pointer) - r3:r4 c - r5:r6 d - r11:r12 c' - r9:r10 d' - - Note: do not write to r[] here, it may overlap with a[] - */ - /* A interleaved with B */ - ldr r0, [r1, #1*4] @ a[1]*2 - ldr r7, [r1, #0*4] @ a[0] - mov r0, r0, asl #1 - ldr r14, [r1, #9*4] @ a[9] - umull r3, r4, r7, r7 @ c = a[0] * a[0] - ldr r8, [r1, #8*4] @ a[8] - mov r7, r7, asl #1 - umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] - ldr r7, [r1, #2*4] @ a[2]*2 - umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] - ldr r14, [r1, #7*4] @ a[7] - umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] - mov r7, r7, asl #1 - ldr r0, [r1, #3*4] @ a[3]*2 - umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] - ldr r8, [r1, #6*4] @ a[6] - umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] - mov r0, r0, asl #1 - ldr r7, [r1, #4*4] @ a[4]*2 - umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] - ldr r14, [r1, #5*4] @ a[5] - mov r7, r7, asl #1 - umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] - umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] - umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] - umlal r9, r10, r14, r14 @ d' += a[5] * a[5] - - bic r0, r5, field_not_M @ t9 = d & M - str r0, [sp, #4 + 9*4] - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - - /* B */ - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u0 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u0 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t0 = c & M - str r14, [sp, #4 + 0*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u0 * R1 - umlal r3, r4, r0, r14 - - /* C interleaved with D */ - ldr r0, [r1, #0*4] @ a[0]*2 - ldr r14, [r1, #1*4] @ a[1] - mov r0, r0, asl #1 - ldr r8, [r1, #2*4] @ a[2] - umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] - mov r7, r8, asl #1 @ a[2]*2 - umull r11, r12, r14, r14 @ c' = a[1] * a[1] - ldr r14, [r1, #9*4] @ a[9] - umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] - ldr r0, [r1, #3*4] @ a[3]*2 - ldr r8, [r1, #8*4] @ a[8] - umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] - mov r0, r0, asl #1 - ldr r7, [r1, #4*4] @ a[4]*2 - umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] - ldr r14, [r1, #7*4] @ a[7] - umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] - mov r7, r7, asl #1 - ldr r0, [r1, #5*4] @ a[5]*2 - umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] - ldr r8, [r1, #6*4] @ a[6] - mov r0, r0, asl #1 - umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] - umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] - umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] - umlal r9, r10, r8, r8 @ d' += a[6] * a[6] - - bic r0, r5, field_not_M @ u1 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u1 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t1 = c & M - str r14, [sp, #4 + 1*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u1 * R1 - umlal r3, r4, r0, r14 - - /* D */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u2 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u2 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t2 = c & M - str r14, [sp, #4 + 2*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u2 * R1 - umlal r3, r4, r0, r14 - - /* E interleaved with F */ - ldr r7, [r1, #0*4] @ a[0]*2 - ldr r0, [r1, #1*4] @ a[1]*2 - ldr r14, [r1, #2*4] @ a[2] - mov r7, r7, asl #1 - ldr r8, [r1, #3*4] @ a[3] - ldr r2, [r1, #4*4] - umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] - mov r0, r0, asl #1 - umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] - mov r2, r2, asl #1 @ a[4]*2 - umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] - ldr r8, [r1, #9*4] @ a[9] - umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] - ldr r0, [r1, #5*4] @ a[5]*2 - umlal r11, r12, r14, r14 @ c' += a[2] * a[2] - ldr r14, [r1, #8*4] @ a[8] - mov r0, r0, asl #1 - umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] - ldr r7, [r1, #6*4] @ a[6]*2 - umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] - mov r7, r7, asl #1 - ldr r8, [r1, #7*4] @ a[7] - umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] - umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] - umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] - umlal r9, r10, r8, r8 @ d' += a[7] * a[7] - - bic r0, r5, field_not_M @ u3 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u3 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t3 = c & M - str r14, [sp, #4 + 3*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u3 * R1 - umlal r3, r4, r0, r14 - - /* F */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u4 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u4 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t4 = c & M - str r14, [sp, #4 + 4*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u4 * R1 - umlal r3, r4, r0, r14 - - /* G interleaved with H */ - ldr r7, [r1, #0*4] @ a[0]*2 - ldr r0, [r1, #1*4] @ a[1]*2 - mov r7, r7, asl #1 - ldr r8, [r1, #5*4] @ a[5] - ldr r2, [r1, #6*4] @ a[6] - umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] - ldr r14, [r1, #4*4] @ a[4] - mov r0, r0, asl #1 - umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] - ldr r7, [r1, #2*4] @ a[2]*2 - umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] - mov r7, r7, asl #1 - ldr r8, [r1, #3*4] @ a[3] - umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] - mov r0, r2, asl #1 @ a[6]*2 - umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] - ldr r14, [r1, #9*4] @ a[9] - umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] - ldr r7, [r1, #7*4] @ a[7]*2 - umlal r11, r12, r8, r8 @ c' += a[3] * a[3] - mov r7, r7, asl #1 - ldr r8, [r1, #8*4] @ a[8] - umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] - umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] - umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] - umlal r9, r10, r8, r8 @ d' += a[8] * a[8] - - bic r0, r5, field_not_M @ u5 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u5 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t5 = c & M - str r14, [sp, #4 + 5*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u5 * R1 - umlal r3, r4, r0, r14 - - /* H */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - adds r5, r5, r9 @ d += d' - adc r6, r6, r10 - - bic r0, r5, field_not_M @ u6 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u6 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t6 = c & M - str r14, [sp, #4 + 6*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u6 * R1 - umlal r3, r4, r0, r14 - - /* I interleaved with J */ - ldr r7, [r1, #0*4] @ a[0]*2 - ldr r0, [r1, #1*4] @ a[1]*2 - mov r7, r7, asl #1 - ldr r8, [r1, #7*4] @ a[7] - ldr r2, [r1, #8*4] @ a[8] - umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] - ldr r14, [r1, #6*4] @ a[6] - mov r0, r0, asl #1 - umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] - ldr r7, [r1, #2*4] @ a[2]*2 - umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] - ldr r8, [r1, #5*4] @ a[5] - umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] - ldr r0, [r1, #3*4] @ a[3]*2 - mov r7, r7, asl #1 - umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] - ldr r14, [r1, #4*4] @ a[4] - mov r0, r0, asl #1 - umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] - mov r2, r2, asl #1 @ a[8]*2 - umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] - umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] - umlal r11, r12, r14, r14 @ c' += a[4] * a[4] - ldr r8, [r1, #9*4] @ a[9] - umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] - @ r8 will be used in J - - bic r0, r5, field_not_M @ u7 = d & M - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u7 * R0 - umlal r3, r4, r0, r14 - bic r14, r3, field_not_M @ t7 = c & M - str r14, [sp, #4 + 7*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u7 * R1 - umlal r3, r4, r0, r14 - - /* J */ - adds r3, r3, r11 @ c += c' - adc r4, r4, r12 - umlal r5, r6, r8, r8 @ d += a[9] * a[9] - - bic r0, r5, field_not_M @ u8 = d & M - str r0, [sp, #4 + 8*4] - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - movw r14, field_R0 @ c += u8 * R0 - umlal r3, r4, r0, r14 - - /****************************************** - * compute and write back result - ****************************************** - Allocation: - r0 r - r3:r4 c - r5:r6 d - r7 t0 - r8 t1 - r9 t2 - r11 u8 - r12 t9 - r1,r2,r10,r14 scratch - - Note: do not read from a[] after here, it may overlap with r[] - */ - ldr r0, [sp, #0] - add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 - ldmia r1, {r2,r7,r8,r9,r10,r11,r12} - add r1, r0, #3*4 - stmia r1, {r2,r7,r8,r9,r10} - - bic r2, r3, field_not_M @ r[8] = c & M - str r2, [r0, #8*4] - mov r3, r3, lsr #26 @ c >>= 26 - orr r3, r3, r4, asl #6 - mov r4, r4, lsr #26 - mov r14, field_R1 @ c += u8 * R1 - umlal r3, r4, r11, r14 - movw r14, field_R0 @ c += d * R0 - umlal r3, r4, r5, r14 - adds r3, r3, r12 @ c += t9 - adc r4, r4, #0 - - add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 - ldmia r1, {r7,r8,r9} - - ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) - str r2, [r0, #9*4] - mov r3, r3, lsr #22 @ c >>= 22 - orr r3, r3, r4, asl #10 - mov r4, r4, lsr #22 - movw r14, field_R1 << 4 @ c += d * (R1 << 4) - umlal r3, r4, r5, r14 - - movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) - umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) - adds r5, r5, r7 @ d.lo += t0 - mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) - adc r6, r6, 0 @ d.hi += carry - - bic r2, r5, field_not_M @ r[0] = d & M - str r2, [r0, #0*4] - - mov r5, r5, lsr #26 @ d >>= 26 - orr r5, r5, r6, asl #6 - mov r6, r6, lsr #26 - - movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) - umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) - adds r5, r5, r8 @ d.lo += t1 - adc r6, r6, #0 @ d.hi += carry - adds r5, r5, r1 @ d.lo += tmp.lo - mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) - adc r6, r6, r2 @ d.hi += carry + tmp.hi - - bic r2, r5, field_not_M @ r[1] = d & M - str r2, [r0, #1*4] - mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) - orr r5, r5, r6, asl #6 - - add r5, r5, r9 @ d += t2 - str r5, [r0, #2*4] @ r[2] = d - - add sp, sp, #48 - ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} - .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner - - .section .note.GNU-stack,"",%progbits diff --git a/external/secp256k1/src/assumptions.h b/external/secp256k1/src/assumptions.h deleted file mode 100644 index 7961005350..0000000000 --- a/external/secp256k1/src/assumptions.h +++ /dev/null @@ -1,87 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ASSUMPTIONS_H -#define SECP256K1_ASSUMPTIONS_H - -#include - -#include "util.h" -#if defined(SECP256K1_INT128_NATIVE) -#include "int128_native.h" -#endif - -/* This library, like most software, relies on a number of compiler implementation defined (but not undefined) - behaviours. Although the behaviours we require are essentially universal we test them specifically here to - reduce the odds of experiencing an unwelcome surprise. -*/ - -#if defined(__has_attribute) -# if __has_attribute(__unavailable__) -__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function."))) -# endif -#endif -static void secp256k1_assumption_checker(void) { - /* Bytes are 8 bits. */ - STATIC_ASSERT(CHAR_BIT == 8); - - /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 - without signed overflow, which would be undefined behaviour. */ - STATIC_ASSERT(UINT_MAX <= UINT32_MAX); - - /* Conversions from unsigned to signed outside of the bounds of the signed type are - implementation-defined. Verify that they function as reinterpreting the lower - bits of the input in two's complement notation. Do this for conversions: - - from uint(N)_t to int(N)_t with negative result - - from uint(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with positive result */ - - /* To int8_t. */ - STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55)); - STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33); - STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF); - STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34); - - /* To int16_t. */ - STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322); - STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C); - STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4); - STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678); - - /* To int32_t. */ - STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B); - STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE); - STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8); - STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789); - - /* To int64_t. */ - STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL); -#if defined(SECP256K1_INT128_NATIVE) - STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL); - STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL); - STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL); - - /* To int128_t. */ - STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)); -#endif - - /* Right shift on negative signed values is implementation defined. Verify that it - acts as a right shift in two's complement with sign extension (i.e duplicating - the top bit into newly added bits). */ - STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA); - STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A); - STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48); - STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL); -#if defined(SECP256K1_INT128_NATIVE) - STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)); -#endif - - /* This function is not supposed to be called. */ - VERIFY_CHECK(0); -} - -#endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/external/secp256k1/src/bench.c b/external/secp256k1/src/bench.c deleted file mode 100644 index 1127df67ae..0000000000 --- a/external/secp256k1/src/bench.c +++ /dev/null @@ -1,279 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include -#include - -#include "../include/secp256k1.h" -#include "util.h" -#include "bench.h" - -static void help(int default_iters) { - printf("Benchmarks the following algorithms:\n"); - printf(" - ECDSA signing/verification\n"); - -#ifdef ENABLE_MODULE_ECDH - printf(" - ECDH key exchange (optional module)\n"); -#endif - -#ifdef ENABLE_MODULE_RECOVERY - printf(" - Public key recovery (optional module)\n"); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - printf(" - Schnorr signatures (optional module)\n"); -#endif - - printf("\n"); - printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); - printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); - printf("\n"); - printf("Usage: ./bench [args]\n"); - printf("By default, all benchmarks will be run.\n"); - printf("args:\n"); - printf(" help : display this help and exit\n"); - printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n"); - printf(" ecdsa_sign : ECDSA siging algorithm\n"); - printf(" ecdsa_verify : ECDSA verification algorithm\n"); - printf(" ec : all EC public key algorithms (keygen)\n"); - printf(" ec_keygen : EC public key generation\n"); - -#ifdef ENABLE_MODULE_RECOVERY - printf(" ecdsa_recover : ECDSA public key recovery algorithm\n"); -#endif - -#ifdef ENABLE_MODULE_ECDH - printf(" ecdh : ECDH key exchange algorithm\n"); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - printf(" schnorrsig : all Schnorr signature algorithms (sign, verify)\n"); - printf(" schnorrsig_sign : Schnorr sigining algorithm\n"); - printf(" schnorrsig_verify : Schnorr verification algorithm\n"); -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT - printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n"); - printf(" ellswift_encode : ElligatorSwift encoding\n"); - printf(" ellswift_decode : ElligatorSwift decoding\n"); - printf(" ellswift_keygen : ElligatorSwift key generation\n"); - printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n"); -#endif - - printf("\n"); -} - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - unsigned char key[32]; - unsigned char sig[72]; - size_t siglen; - unsigned char pubkey[33]; - size_t pubkeylen; -} bench_data; - -static void bench_verify(void* arg, int iters) { - int i; - bench_data* data = (bench_data*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); - CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - } -} - -static void bench_sign_setup(void* arg) { - int i; - bench_data *data = (bench_data*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = i + 1; - } - for (i = 0; i < 32; i++) { - data->key[i] = i + 65; - } -} - -static void bench_sign_run(void* arg, int iters) { - int i; - bench_data *data = (bench_data*)arg; - - unsigned char sig[74]; - for (i = 0; i < iters; i++) { - size_t siglen = 74; - int j; - secp256k1_ecdsa_signature signature; - CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); - for (j = 0; j < 32; j++) { - data->msg[j] = sig[j]; - data->key[j] = sig[j + 32]; - } - } -} - -static void bench_keygen_setup(void* arg) { - int i; - bench_data *data = (bench_data*)arg; - - for (i = 0; i < 32; i++) { - data->key[i] = i + 65; - } -} - -static void bench_keygen_run(void *arg, int iters) { - int i; - bench_data *data = (bench_data*)arg; - - for (i = 0; i < iters; i++) { - unsigned char pub33[33]; - size_t len = 33; - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key)); - CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED)); - memcpy(data->key, pub33 + 1, 32); - } -} - - -#ifdef ENABLE_MODULE_ECDH -# include "modules/ecdh/bench_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "modules/recovery/bench_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -# include "modules/schnorrsig/bench_impl.h" -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT -# include "modules/ellswift/bench_impl.h" -#endif - -int main(int argc, char** argv) { - int i; - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - bench_data data; - - int d = argc == 1; - int default_iters = 20000; - int iters = get_iters(default_iters); - - /* Check for invalid user arguments */ - char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover", - "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec", - "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode", - "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"}; - size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); - int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size); - - if (argc > 1) { - if (have_flag(argc, argv, "-h") - || have_flag(argc, argv, "--help") - || have_flag(argc, argv, "help")) { - help(default_iters); - return 0; - } else if (invalid_args) { - fprintf(stderr, "./bench: unrecognized argument.\n\n"); - help(default_iters); - return 1; - } - } - -/* Check if the user tries to benchmark optional module without building it */ -#ifndef ENABLE_MODULE_ECDH - if (have_flag(argc, argv, "ecdh")) { - fprintf(stderr, "./bench: ECDH module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); - return 1; - } -#endif - -#ifndef ENABLE_MODULE_RECOVERY - if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { - fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); - return 1; - } -#endif - -#ifndef ENABLE_MODULE_SCHNORRSIG - if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { - fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); - return 1; - } -#endif - -#ifndef ENABLE_MODULE_ELLSWIFT - if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") || - have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") || - have_flag(argc, argv, "ellswift_ecdh")) { - fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n"); - return 1; - } -#endif - - /* ECDSA benchmark */ - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - - for (i = 0; i < 32; i++) { - data.msg[i] = 1 + i; - } - for (i = 0; i < 32; i++) { - data.key[i] = 33 + i; - } - data.siglen = 72; - CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); - CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); - data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - - print_output_table_header_row(); - if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters); - - secp256k1_context_destroy(data.ctx); - -#ifdef ENABLE_MODULE_ECDH - /* ECDH benchmarks */ - run_ecdh_bench(iters, argc, argv); -#endif - -#ifdef ENABLE_MODULE_RECOVERY - /* ECDSA recovery benchmarks */ - run_recovery_bench(iters, argc, argv); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - /* Schnorr signature benchmarks */ - run_schnorrsig_bench(iters, argc, argv); -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT - /* ElligatorSwift benchmarks */ - run_ellswift_bench(iters, argc, argv); -#endif - - return 0; -} diff --git a/external/secp256k1/src/bench.h b/external/secp256k1/src/bench.h deleted file mode 100644 index 1564b1a176..0000000000 --- a/external/secp256k1/src/bench.h +++ /dev/null @@ -1,188 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_BENCH_H -#define SECP256K1_BENCH_H - -#include -#include -#include -#include - -#if (defined(_MSC_VER) && _MSC_VER >= 1900) -# include -#else -# include -#endif - -static int64_t gettime_i64(void) { -#if (defined(_MSC_VER) && _MSC_VER >= 1900) - /* C11 way to get wallclock time */ - struct timespec tv; - if (!timespec_get(&tv, TIME_UTC)) { - fputs("timespec_get failed!", stderr); - exit(1); - } - return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; -#endif -} - -#define FP_EXP (6) -#define FP_MULT (1000000LL) - -/* Format fixed point number. */ -static void print_number(const int64_t x) { - int64_t x_abs, y; - int c, i, rounding, g; /* g = integer part size, c = fractional part size */ - size_t ptr; - char buffer[30]; - - if (x == INT64_MIN) { - /* Prevent UB. */ - printf("ERR"); - return; - } - x_abs = x < 0 ? -x : x; - - /* Determine how many decimals we want to show (more than FP_EXP makes no - * sense). */ - y = x_abs; - c = 0; - while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) { - y *= 10LL; - c++; - } - - /* Round to 'c' decimals. */ - y = x_abs; - rounding = 0; - for (i = c; i < FP_EXP; ++i) { - rounding = (y % 10) >= 5; - y /= 10; - } - y += rounding; - - /* Format and print the number. */ - ptr = sizeof(buffer) - 1; - buffer[ptr] = 0; - g = 0; - if (c != 0) { /* non zero fractional part */ - for (i = 0; i < c; ++i) { - buffer[--ptr] = '0' + (y % 10); - y /= 10; - } - } else if (c == 0) { /* fractional part is 0 */ - buffer[--ptr] = '0'; - } - buffer[--ptr] = '.'; - do { - buffer[--ptr] = '0' + (y % 10); - y /= 10; - g++; - } while (y != 0); - if (x < 0) { - buffer[--ptr] = '-'; - g++; - } - printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */ - printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ -} - -static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { - int i; - int64_t min = INT64_MAX; - int64_t sum = 0; - int64_t max = 0; - for (i = 0; i < count; i++) { - int64_t begin, total; - if (setup != NULL) { - setup(data); - } - begin = gettime_i64(); - benchmark(data, iter); - total = gettime_i64() - begin; - if (teardown != NULL) { - teardown(data, iter); - } - if (total < min) { - min = total; - } - if (total > max) { - max = total; - } - sum += total; - } - /* ',' is used as a column delimiter */ - printf("%-30s, ", name); - print_number(min * FP_MULT / iter); - printf(" , "); - print_number(((sum * FP_MULT) / count) / iter); - printf(" , "); - print_number(max * FP_MULT / iter); - printf("\n"); -} - -static int have_flag(int argc, char** argv, char *flag) { - char** argm = argv + argc; - argv++; - while (argv != argm) { - if (strcmp(*argv, flag) == 0) { - return 1; - } - argv++; - } - return 0; -} - -/* takes an array containing the arguments that the user is allowed to enter on the command-line - returns: - - 1 if the user entered an invalid argument - - 0 if all the user entered arguments are valid */ -static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { - size_t i; - int found_valid; - char** argm = argv + argc; - argv++; - - while (argv != argm) { - found_valid = 0; - for (i = 0; i < n; i++) { - if (strcmp(*argv, valid_args[i]) == 0) { - found_valid = 1; /* user entered a valid arg from the list */ - break; - } - } - if (found_valid == 0) { - return 1; /* invalid arg found */ - } - argv++; - } - return 0; -} - -static int get_iters(int default_iters) { - char* env = getenv("SECP256K1_BENCH_ITERS"); - if (env) { - return strtol(env, NULL, 0); - } else { - return default_iters; - } -} - -static void print_output_table_header_row(void) { - char* bench_str = "Benchmark"; /* left justified */ - char* min_str = " Min(us) "; /* center alignment */ - char* avg_str = " Avg(us) "; - char* max_str = " Max(us) "; - printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str); - printf("\n"); -} - -#endif /* SECP256K1_BENCH_H */ diff --git a/external/secp256k1/src/bench_ecmult.c b/external/secp256k1/src/bench_ecmult.c deleted file mode 100644 index 3974af75f4..0000000000 --- a/external/secp256k1/src/bench_ecmult.c +++ /dev/null @@ -1,367 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2017 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ -#include - -#include "secp256k1.c" -#include "../include/secp256k1.h" - -#include "util.h" -#include "hash_impl.h" -#include "field_impl.h" -#include "group_impl.h" -#include "scalar_impl.h" -#include "ecmult_impl.h" -#include "bench.h" - -#define POINTS 32768 - -static void help(char **argv) { - printf("Benchmark EC multiplication algorithms\n"); - printf("\n"); - printf("Usage: %s \n", argv[0]); - printf("The output shows the number of multiplied and summed points right after the\n"); - printf("function name. The letter 'g' indicates that one of the points is the generator.\n"); - printf("The benchmarks are divided by the number of points.\n"); - printf("\n"); - printf("default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n"); - printf(" batch size\n"); - printf("pippenger_wnaf: for all batch sizes\n"); - printf("strauss_wnaf: for all batch sizes\n"); - printf("simple: multiply and sum each point individually\n"); -} - -typedef struct { - /* Setup once in advance */ - secp256k1_context* ctx; - secp256k1_scratch_space* scratch; - secp256k1_scalar* scalars; - secp256k1_ge* pubkeys; - secp256k1_gej* pubkeys_gej; - secp256k1_scalar* seckeys; - secp256k1_gej* expected_output; - secp256k1_ecmult_multi_func ecmult_multi; - - /* Changes per benchmark */ - size_t count; - int includes_g; - - /* Changes per benchmark iteration, used to pick different scalars and pubkeys - * in each run. */ - size_t offset1; - size_t offset2; - - /* Benchmark output. */ - secp256k1_gej* output; -} bench_data; - -/* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */ -static void hash_into_offset(bench_data* data, size_t x) { - data->offset1 = (x * 0x537b7f6f + 0x8f66a481) % POINTS; - data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) % POINTS; -} - -/* Check correctness of the benchmark by computing - * sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */ -static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset, size_t* scalar_offset, size_t* scalar_gen_offset, int iters) { - int i; - secp256k1_gej sum_output, tmp; - secp256k1_scalar sum_scalars; - - secp256k1_gej_set_infinity(&sum_output); - secp256k1_scalar_set_int(&sum_scalars, 0); - for (i = 0; i < iters; ++i) { - secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL); - if (scalar_gen_offset != NULL) { - secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]); - } - if (seckey_offset != NULL) { - secp256k1_scalar s = data->seckeys[(*seckey_offset+i) % POINTS]; - secp256k1_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]); - secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s); - } - } - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); - CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); -} - -static void bench_ecmult_setup(void* arg) { - bench_data* data = (bench_data*)arg; - /* Re-randomize offset to ensure that we're using different scalars and - * group elements in each run. */ - hash_into_offset(data, data->offset1); -} - -static void bench_ecmult_gen(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - - for (i = 0; i < iters; ++i) { - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); - } -} - -static void bench_ecmult_gen_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); -} - -static void bench_ecmult_const(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - - for (i = 0; i < iters; ++i) { - secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]); - } -} - -static void bench_ecmult_const_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); -} - -static void bench_ecmult_1p(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - - for (i = 0; i < iters; ++i) { - secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL); - } -} - -static void bench_ecmult_1p_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); -} - -static void bench_ecmult_0p_g(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - - for (i = 0; i < iters; ++i) { - secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]); - } -} - -static void bench_ecmult_0p_g_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); -} - -static void bench_ecmult_1p_g(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - - for (i = 0; i < iters/2; ++i) { - secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]); - } -} - -static void bench_ecmult_1p_g_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, &data->offset1, iters/2); -} - -static void run_ecmult_bench(bench_data* data, int iters) { - char str[32]; - sprintf(str, "ecmult_gen"); - run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters); - sprintf(str, "ecmult_const"); - run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters); - /* ecmult with non generator point */ - sprintf(str, "ecmult_1p"); - run_benchmark(str, bench_ecmult_1p, bench_ecmult_setup, bench_ecmult_1p_teardown, data, 10, iters); - /* ecmult with generator point */ - sprintf(str, "ecmult_0p_g"); - run_benchmark(str, bench_ecmult_0p_g, bench_ecmult_setup, bench_ecmult_0p_g_teardown, data, 10, iters); - /* ecmult with generator and non-generator point. The reported time is per point. */ - sprintf(str, "ecmult_1p_g"); - run_benchmark(str, bench_ecmult_1p_g, bench_ecmult_setup, bench_ecmult_1p_g_teardown, data, 10, 2*iters); -} - -static int bench_ecmult_multi_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) { - bench_data* data = (bench_data*)arg; - if (data->includes_g) ++idx; - if (idx == 0) { - *sc = data->scalars[data->offset1]; - *ge = secp256k1_ge_const_g; - } else { - *sc = data->scalars[(data->offset1 + idx) % POINTS]; - *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; - } - return 1; -} - -static void bench_ecmult_multi(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - - int includes_g = data->includes_g; - int iter; - int count = data->count; - iters = iters / data->count; - - for (iter = 0; iter < iters; ++iter) { - data->ecmult_multi(&data->ctx->error_callback, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_ecmult_multi_callback, arg, count - includes_g); - data->offset1 = (data->offset1 + count) % POINTS; - data->offset2 = (data->offset2 + count - 1) % POINTS; - } -} - -static void bench_ecmult_multi_setup(void* arg) { - bench_data* data = (bench_data*)arg; - hash_into_offset(data, data->count); -} - -static void bench_ecmult_multi_teardown(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int iter; - iters = iters / data->count; - /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ - for (iter = 0; iter < iters; ++iter) { - secp256k1_gej tmp; - secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); - CHECK(secp256k1_gej_is_infinity(&tmp)); - } -} - -static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { - secp256k1_sha256 sha256; - unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; - unsigned char buf[32]; - int overflow = 0; - c[6] = num; - c[7] = num >> 8; - c[8] = num >> 16; - c[9] = num >> 24; - secp256k1_sha256_initialize(&sha256); - secp256k1_sha256_write(&sha256, c, sizeof(c)); - secp256k1_sha256_finalize(&sha256, buf); - secp256k1_scalar_set_b32(scalar, buf, &overflow); - CHECK(!overflow); -} - -static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { - char str[32]; - size_t iters = 1 + num_iters / count; - size_t iter; - - data->count = count; - data->includes_g = includes_g; - - /* Compute (the negation of) the expected results directly. */ - hash_into_offset(data, data->count); - for (iter = 0; iter < iters; ++iter) { - secp256k1_scalar tmp; - secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS]; - size_t i = 0; - for (i = 0; i + 1 < count; ++i) { - secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); - secp256k1_scalar_add(&total, &total, &tmp); - } - secp256k1_scalar_negate(&total, &total); - secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total); - } - - /* Run the benchmark. */ - if (includes_g) { - sprintf(str, "ecmult_multi_%ip_g", (int)count - 1); - } else { - sprintf(str, "ecmult_multi_%ip", (int)count); - } - run_benchmark(str, bench_ecmult_multi, bench_ecmult_multi_setup, bench_ecmult_multi_teardown, data, 10, count * iters); -} - -int main(int argc, char **argv) { - bench_data data; - int i, p; - size_t scratch_size; - - int iters = get_iters(10000); - - data.ecmult_multi = secp256k1_ecmult_multi_var; - - if (argc > 1) { - if(have_flag(argc, argv, "-h") - || have_flag(argc, argv, "--help") - || have_flag(argc, argv, "help")) { - help(argv); - return 0; - } else if(have_flag(argc, argv, "pippenger_wnaf")) { - printf("Using pippenger_wnaf:\n"); - data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single; - } else if(have_flag(argc, argv, "strauss_wnaf")) { - printf("Using strauss_wnaf:\n"); - data.ecmult_multi = secp256k1_ecmult_strauss_batch_single; - } else if(have_flag(argc, argv, "simple")) { - printf("Using simple algorithm:\n"); - } else { - fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]); - help(argv); - return 1; - } - } - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; - if (!have_flag(argc, argv, "simple")) { - data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); - } else { - data.scratch = NULL; - } - - /* Allocate stuff */ - data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS); - data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS); - data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS); - data.pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS); - data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1)); - data.output = malloc(sizeof(secp256k1_gej) * (iters + 1)); - - /* Generate a set of scalars, and private/public keypairs. */ - secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g); - secp256k1_scalar_set_int(&data.seckeys[0], 1); - for (i = 0; i < POINTS; ++i) { - generate_scalar(i, &data.scalars[i]); - if (i) { - secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); - secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); - } - } - secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS); - - - print_output_table_header_row(); - /* Initialize offset1 and offset2 */ - hash_into_offset(&data, 0); - run_ecmult_bench(&data, iters); - - for (i = 1; i <= 8; ++i) { - run_ecmult_multi_bench(&data, i, 1, iters); - } - - /* This is disabled with low count of iterations because the loop runs 77 times even with iters=1 - * and the higher it goes the longer the computation takes(more points) - * So we don't run this benchmark with low iterations to prevent slow down */ - if (iters > 2) { - for (p = 0; p <= 11; ++p) { - for (i = 9; i <= 16; ++i) { - run_ecmult_multi_bench(&data, i << p, 1, iters); - } - } - } - - if (data.scratch != NULL) { - secp256k1_scratch_space_destroy(data.ctx, data.scratch); - } - secp256k1_context_destroy(data.ctx); - free(data.scalars); - free(data.pubkeys); - free(data.pubkeys_gej); - free(data.seckeys); - free(data.output); - free(data.expected_output); - - return(0); -} diff --git a/external/secp256k1/src/bench_internal.c b/external/secp256k1/src/bench_internal.c deleted file mode 100644 index a700684922..0000000000 --- a/external/secp256k1/src/bench_internal.c +++ /dev/null @@ -1,436 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ -#include - -#include "secp256k1.c" -#include "../include/secp256k1.h" - -#include "assumptions.h" -#include "util.h" -#include "hash_impl.h" -#include "field_impl.h" -#include "group_impl.h" -#include "scalar_impl.h" -#include "ecmult_impl.h" -#include "bench.h" - -static void help(int default_iters) { - printf("Benchmarks various internal routines.\n"); - printf("\n"); - printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); - printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); - printf("\n"); - printf("Usage: ./bench_internal [args]\n"); - printf("By default, all benchmarks will be run.\n"); - printf("args:\n"); - printf(" help : display this help and exit\n"); - printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n"); - printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n"); - printf(" group : all group operations (add, double, to_affine)\n"); - printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n"); - printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n"); - printf(" context : all context object operations (context_create)\n"); - printf("\n"); -} - -typedef struct { - secp256k1_scalar scalar[2]; - secp256k1_fe fe[4]; - secp256k1_ge ge[2]; - secp256k1_gej gej[2]; - unsigned char data[64]; - int wnaf[256]; -} bench_inv; - -static void bench_setup(void* arg) { - bench_inv *data = (bench_inv*)arg; - - static const unsigned char init[4][32] = { - /* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0], - and the (implied affine) X coordinate of gej[0]. */ - { - 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, - 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, - 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, - 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 - }, - /* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1], - and the (implied affine) X coordinate of gej[1]. */ - { - 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, - 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, - 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, - 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 - }, - /* Initializer for fe[2] and the Z coordinate of gej[0]. */ - { - 0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d, - 0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44, - 0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38, - 0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7 - }, - /* Initializer for fe[3] and the Z coordinate of gej[1]. */ - { - 0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e, - 0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68, - 0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3, - 0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5 - } - }; - - secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); - secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); - secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); - secp256k1_fe_set_b32_limit(&data->fe[1], init[1]); - secp256k1_fe_set_b32_limit(&data->fe[2], init[2]); - secp256k1_fe_set_b32_limit(&data->fe[3], init[3]); - CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); - CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); - secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]); - secp256k1_gej_rescale(&data->gej[0], &data->fe[2]); - secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]); - secp256k1_gej_rescale(&data->gej[1], &data->fe[3]); - memcpy(data->data, init[0], 32); - memcpy(data->data + 32, init[1], 32); -} - -static void bench_scalar_add(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } - CHECK(j <= iters); -} - -static void bench_scalar_negate(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]); - } -} - -static void bench_scalar_half(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - secp256k1_scalar s = data->scalar[0]; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_half(&s, &s); - } - - data->scalar[0] = s; -} - -static void bench_scalar_mul(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } -} - -static void bench_scalar_split(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - secp256k1_scalar tmp; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]); - j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]); - } - CHECK(j <= iters); -} - -static void bench_scalar_inverse(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]); - j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } - CHECK(j <= iters); -} - -static void bench_scalar_inverse_var(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]); - j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } - CHECK(j <= iters); -} - -static void bench_field_half(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_half(&data->fe[0]); - } -} - -static void bench_field_normalize(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_normalize(&data->fe[0]); - } -} - -static void bench_field_normalize_weak(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_normalize_weak(&data->fe[0]); - } -} - -static void bench_field_mul(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]); - } -} - -static void bench_field_sqr(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_sqr(&data->fe[0], &data->fe[0]); - } -} - -static void bench_field_inverse(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_inv(&data->fe[0], &data->fe[0]); - secp256k1_fe_add(&data->fe[0], &data->fe[1]); - } -} - -static void bench_field_inverse_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]); - secp256k1_fe_add(&data->fe[0], &data->fe[1]); - } -} - -static void bench_field_sqrt(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - secp256k1_fe t; - - for (i = 0; i < iters; i++) { - t = data->fe[0]; - j += secp256k1_fe_sqrt(&data->fe[0], &t); - secp256k1_fe_add(&data->fe[0], &data->fe[1]); - } - CHECK(j <= iters); -} - -static void bench_field_is_square_var(void* arg, int iters) { - int i, j = 0; - bench_inv *data = (bench_inv*)arg; - secp256k1_fe t = data->fe[0]; - - for (i = 0; i < iters; i++) { - j += secp256k1_fe_is_square_var(&t); - secp256k1_fe_add(&t, &data->fe[1]); - secp256k1_fe_normalize_var(&t); - } - CHECK(j <= iters); -} - -static void bench_group_double_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL); - } -} - -static void bench_group_add_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL); - } -} - -static void bench_group_add_affine(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]); - } -} - -static void bench_group_add_affine_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL); - } -} - -static void bench_group_add_zinv_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - secp256k1_gej_add_zinv_var(&data->gej[0], &data->gej[0], &data->ge[1], &data->gej[0].y); - } -} - -static void bench_group_to_affine_var(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; ++i) { - secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]); - /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates. - Note that the resulting coordinates will generally not correspond to a point - on the curve, but this is not a problem for the code being benchmarked here. - Adding and normalizing have less overhead than EC operations (which could - guarantee the point remains on the curve). */ - secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y); - secp256k1_fe_add(&data->gej[0].y, &data->fe[2]); - secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x); - secp256k1_fe_normalize_var(&data->gej[0].x); - secp256k1_fe_normalize_var(&data->gej[0].y); - secp256k1_fe_normalize_var(&data->gej[0].z); - } -} - -static void bench_ecmult_wnaf(void* arg, int iters) { - int i, bits = 0, overflow = 0; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A); - overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } - CHECK(overflow >= 0); - CHECK(bits <= 256*iters); -} - -static void bench_sha256(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - secp256k1_sha256 sha; - - for (i = 0; i < iters; i++) { - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, data->data, 32); - secp256k1_sha256_finalize(&sha, data->data); - } -} - -static void bench_hmac_sha256(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - secp256k1_hmac_sha256 hmac; - - for (i = 0; i < iters; i++) { - secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); - secp256k1_hmac_sha256_write(&hmac, data->data, 32); - secp256k1_hmac_sha256_finalize(&hmac, data->data); - } -} - -static void bench_rfc6979_hmac_sha256(void* arg, int iters) { - int i; - bench_inv *data = (bench_inv*)arg; - secp256k1_rfc6979_hmac_sha256 rng; - - for (i = 0; i < iters; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); - secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); - } -} - -static void bench_context(void* arg, int iters) { - int i; - (void)arg; - for (i = 0; i < iters; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE)); - } -} - -int main(int argc, char **argv) { - bench_inv data; - int default_iters = 20000; - int iters = get_iters(default_iters); - int d = argc == 1; /* default */ - - if (argc > 1) { - if (have_flag(argc, argv, "-h") - || have_flag(argc, argv, "--help") - || have_flag(argc, argv, "help")) { - help(default_iters); - return 0; - } - } - - print_output_table_header_row(); - - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters); - - if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters); - - return 0; -} diff --git a/external/secp256k1/src/checkmem.h b/external/secp256k1/src/checkmem.h deleted file mode 100644 index 7e333ce5f3..0000000000 --- a/external/secp256k1/src/checkmem.h +++ /dev/null @@ -1,102 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2022 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/* The code here is inspired by Kris Kwiatkowski's approach in - * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h - * to provide a general interface for memory-checking mechanisms, primarily - * for constant-time checking. - */ - -/* These macros are defined by this header file: - * - * - SECP256K1_CHECKMEM_ENABLED: - * - 1 if memory-checking integration is available, 0 otherwise. - * This is just a compile-time macro. Use the next macro to check it is actually - * available at runtime. - * - SECP256K1_CHECKMEM_RUNNING(): - * - Acts like a function call, returning 1 if memory checking is available - * at runtime. - * - SECP256K1_CHECKMEM_CHECK(p, len): - * - Assert or otherwise fail in case the len-byte memory block pointed to by p is - * not considered entirely defined. - * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len): - * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode. - * - SECP256K1_CHECKMEM_UNDEFINE(p, len): - * - marks the len-byte memory block pointed to by p as undefined data (secret data, - * in the context of constant-time checking). - * - SECP256K1_CHECKMEM_DEFINE(p, len): - * - marks the len-byte memory pointed to by p as defined data (public data, in the - * context of constant-time checking). - * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len): - * - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer. - * - */ - -#ifndef SECP256K1_CHECKMEM_H -#define SECP256K1_CHECKMEM_H - -/* Define a statement-like macro that ignores the arguments. */ -#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) - -/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan. - * Choose this preferentially, even when VALGRIND is defined, as msan-compiled - * binaries can't be run under valgrind anyway. */ -#if defined(__has_feature) -# if __has_feature(memory_sanitizer) -# include -# define SECP256K1_CHECKMEM_ENABLED 1 -# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len)) -# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len)) -# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len)) -# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len)) -# define SECP256K1_CHECKMEM_RUNNING() (1) -# endif -#endif - -#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE -# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) -#endif - -/* If valgrind integration is desired (through the VALGRIND define), implement the - * SECP256K1_CHECKMEM_* macros using valgrind. */ -#if !defined SECP256K1_CHECKMEM_ENABLED -# if defined VALGRIND -# include -# if defined(__clang__) && defined(__APPLE__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wreserved-identifier" -# endif -# include -# if defined(__clang__) && defined(__APPLE__) -# pragma clang diagnostic pop -# endif -# define SECP256K1_CHECKMEM_ENABLED 1 -# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) -# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) -# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len)) - /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck. - * This is more precise than the RUNNING_ON_VALGRIND macro, which - * checks for valgrind in general instead of memcheck specifically. */ -# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0) -# endif -#endif - -/* As a fall-back, map these macros to dummy statements. */ -#if !defined SECP256K1_CHECKMEM_ENABLED -# define SECP256K1_CHECKMEM_ENABLED 0 -# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) -# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) -# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) -# define SECP256K1_CHECKMEM_RUNNING() (0) -#endif - -#if defined VERIFY -#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len)) -#else -#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) -#endif - -#endif /* SECP256K1_CHECKMEM_H */ diff --git a/external/secp256k1/src/ctime_tests.c b/external/secp256k1/src/ctime_tests.c deleted file mode 100644 index bbde863d96..0000000000 --- a/external/secp256k1/src/ctime_tests.c +++ /dev/null @@ -1,266 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include -#include - -#include "../include/secp256k1.h" -#include "assumptions.h" -#include "checkmem.h" - -#if !SECP256K1_CHECKMEM_ENABLED -# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" -#endif - -#ifdef ENABLE_MODULE_ECDH -# include "../include/secp256k1_ecdh.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "../include/secp256k1_recovery.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -# include "../include/secp256k1_extrakeys.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "../include/secp256k1_schnorrsig.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -#include "../include/secp256k1_musig.h" -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT -#include "../include/secp256k1_ellswift.h" -#endif - -static void run_tests(secp256k1_context *ctx, unsigned char *key); - -int main(void) { - secp256k1_context* ctx; - unsigned char key[32]; - int ret, i; - - if (!SECP256K1_CHECKMEM_RUNNING()) { - fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); - fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); - return 1; - } - ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); - /** In theory, testing with a single secret input should be sufficient: - * If control flow depended on secrets the tool would generate an error. - */ - for (i = 0; i < 32; i++) { - key[i] = i + 65; - } - - run_tests(ctx, key); - - /* Test context randomisation. Do this last because it leaves the context - * tainted. */ - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_context_randomize(ctx, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret); - - secp256k1_context_destroy(ctx); - return 0; -} - -static void run_tests(secp256k1_context *ctx, unsigned char *key) { - secp256k1_ecdsa_signature signature; - secp256k1_pubkey pubkey; - size_t siglen = 74; - size_t outputlen = 33; - int i; - int ret; - unsigned char msg[32]; - unsigned char sig[74]; - unsigned char spubkey[33]; -#ifdef ENABLE_MODULE_RECOVERY - secp256k1_ecdsa_recoverable_signature recoverable_signature; - int recid; -#endif -#ifdef ENABLE_MODULE_EXTRAKEYS - secp256k1_keypair keypair; -#endif -#ifdef ENABLE_MODULE_ELLSWIFT - unsigned char ellswift[64]; - static const unsigned char prefix[64] = {'t', 'e', 's', 't'}; -#endif - - for (i = 0; i < 32; i++) { - msg[i] = i + 1; - } - - /* Test keygen. */ - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); - SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret); - CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - - /* Test signing. */ - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); - SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature)); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); - -#ifdef ENABLE_MODULE_ECDH - /* Test ECDH. */ - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_RECOVERY - /* Test signing a recoverable signature. */ - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); - SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); - CHECK(recid >= 0 && recid <= 3); -#endif - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ec_seckey_verify(ctx, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ec_seckey_negate(ctx, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_UNDEFINE(msg, 32); - ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_UNDEFINE(msg, 32); - ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - /* Test keypair_create and keypair_xonly_tweak_add. */ -#ifdef ENABLE_MODULE_EXTRAKEYS - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_keypair_create(ctx, &keypair, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - /* The tweak is not treated as a secret in keypair_tweak_add */ - SECP256K1_CHECKMEM_DEFINE(msg, 32); - ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); - ret = secp256k1_keypair_sec(ctx, key, &keypair); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_keypair_create(ctx, &keypair, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_MUSIG - { - secp256k1_pubkey pk; - const secp256k1_pubkey *pk_ptr[1]; - secp256k1_xonly_pubkey agg_pk; - unsigned char session_secrand[32]; - uint64_t nonrepeating_cnt = 0; - secp256k1_musig_secnonce secnonce; - secp256k1_musig_pubnonce pubnonce; - const secp256k1_musig_pubnonce *pubnonce_ptr[1]; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_keyagg_cache cache; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig; - unsigned char extra_input[32]; - - pk_ptr[0] = &pk; - pubnonce_ptr[0] = &pubnonce; - SECP256K1_CHECKMEM_DEFINE(key, 32); - memcpy(session_secrand, key, sizeof(session_secrand)); - session_secrand[0] = session_secrand[0] + 1; - memcpy(extra_input, key, sizeof(extra_input)); - extra_input[0] = extra_input[0] + 2; - - CHECK(secp256k1_keypair_create(ctx, &keypair, key)); - CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair)); - CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); - SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); - ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); - /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ - SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); - CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1); - - ret = secp256k1_keypair_create(ctx, &keypair, key); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - } -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - for (i = 0; i < 2; i++) { - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); - ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - - SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); - ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix); - SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); - CHECK(ret == 1); - } - -#endif -} diff --git a/external/secp256k1/src/ecdsa.h b/external/secp256k1/src/ecdsa.h deleted file mode 100644 index 4441b08398..0000000000 --- a/external/secp256k1/src/ecdsa.h +++ /dev/null @@ -1,21 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECDSA_H -#define SECP256K1_ECDSA_H - -#include - -#include "scalar.h" -#include "group.h" -#include "ecmult.h" - -static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); -static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); - -#endif /* SECP256K1_ECDSA_H */ diff --git a/external/secp256k1/src/ecdsa_impl.h b/external/secp256k1/src/ecdsa_impl.h deleted file mode 100644 index ce36e85e6a..0000000000 --- a/external/secp256k1/src/ecdsa_impl.h +++ /dev/null @@ -1,304 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - - -#ifndef SECP256K1_ECDSA_IMPL_H -#define SECP256K1_ECDSA_IMPL_H - -#include "scalar.h" -#include "field.h" -#include "group.h" -#include "ecmult.h" -#include "ecmult_gen.h" -#include "ecdsa.h" - -/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 - * $ sage -c 'load("secp256k1_params.sage"); print(hex(N))' - * 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - */ -static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, - 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL -); - -/** Difference between field and order, values 'p' and 'n' values defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - * $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))' - * 0x14551231950b75fc4402da1722fc9baee - */ -static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( - 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL -); - -static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { - size_t lenleft; - unsigned char b1; - VERIFY_CHECK(len != NULL); - *len = 0; - if (*sigp >= sigend) { - return 0; - } - b1 = *((*sigp)++); - if (b1 == 0xFF) { - /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ - return 0; - } - if ((b1 & 0x80) == 0) { - /* X.690-0207 8.1.3.4 short form length octets */ - *len = b1; - return 1; - } - if (b1 == 0x80) { - /* Indefinite length is not allowed in DER. */ - return 0; - } - /* X.690-207 8.1.3.5 long form length octets */ - lenleft = b1 & 0x7F; /* lenleft is at least 1 */ - if (lenleft > (size_t)(sigend - *sigp)) { - return 0; - } - if (**sigp == 0) { - /* Not the shortest possible length encoding. */ - return 0; - } - if (lenleft > sizeof(size_t)) { - /* The resulting length would exceed the range of a size_t, so - * it is certainly longer than the passed array size. */ - return 0; - } - while (lenleft > 0) { - *len = (*len << 8) | **sigp; - (*sigp)++; - lenleft--; - } - if (*len > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. - (Checking this is the responsibility of the caller but it - can't hurt do it here, too.) */ - return 0; - } - if (*len < 128) { - /* Not the shortest possible length encoding. */ - return 0; - } - return 1; -} - -static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { - int overflow = 0; - unsigned char ra[32] = {0}; - size_t rlen; - - if (*sig == sigend || **sig != 0x02) { - /* Not a primitive integer (X.690-0207 8.3.1). */ - return 0; - } - (*sig)++; - if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) { - return 0; - } - if (rlen == 0 || rlen > (size_t)(sigend - *sig)) { - /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ - return 0; - } - if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { - /* Excessive 0x00 padding. */ - return 0; - } - if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { - /* Excessive 0xFF padding. */ - return 0; - } - if ((**sig & 0x80) == 0x80) { - /* Negative. */ - overflow = 1; - } - /* There is at most one leading zero byte: - * if there were two leading zero bytes, we would have failed and returned 0 - * because of excessive 0x00 padding already. */ - if (rlen > 0 && **sig == 0) { - /* Skip leading zero byte */ - rlen--; - (*sig)++; - } - if (rlen > 32) { - overflow = 1; - } - if (!overflow) { - if (rlen) memcpy(ra + 32 - rlen, *sig, rlen); - secp256k1_scalar_set_b32(r, ra, &overflow); - } - if (overflow) { - secp256k1_scalar_set_int(r, 0); - } - (*sig) += rlen; - return 1; -} - -static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { - const unsigned char *sigend = sig + size; - size_t rlen; - if (sig == sigend || *(sig++) != 0x30) { - /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ - return 0; - } - if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) { - return 0; - } - if (rlen != (size_t)(sigend - sig)) { - /* Tuple exceeds bounds or garage after tuple. */ - return 0; - } - - if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { - return 0; - } - if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { - return 0; - } - - if (sig != sigend) { - /* Trailing garbage inside tuple. */ - return 0; - } - - return 1; -} - -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { - unsigned char r[33] = {0}, s[33] = {0}; - unsigned char *rp = r, *sp = s; - size_t lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], ar); - secp256k1_scalar_get_b32(&s[1], as); - while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } - while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } - if (*size < 6+lenS+lenR) { - *size = 6 + lenS + lenR; - return 0; - } - *size = 6 + lenS + lenR; - sig[0] = 0x30; - sig[1] = 4 + lenS + lenR; - sig[2] = 0x02; - sig[3] = lenR; - memcpy(sig+4, rp, lenR); - sig[4+lenR] = 0x02; - sig[5+lenR] = lenS; - memcpy(sig+lenR+6, sp, lenS); - return 1; -} - -static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { - unsigned char c[32]; - secp256k1_scalar sn, u1, u2; -#if !defined(EXHAUSTIVE_TEST_ORDER) - secp256k1_fe xr; -#endif - secp256k1_gej pubkeyj; - secp256k1_gej pr; - - if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { - return 0; - } - - secp256k1_scalar_inverse_var(&sn, sigs); - secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, sigr); - secp256k1_gej_set_ge(&pubkeyj, pubkey); - secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); - if (secp256k1_gej_is_infinity(&pr)) { - return 0; - } - -#if defined(EXHAUSTIVE_TEST_ORDER) -{ - secp256k1_scalar computed_r; - secp256k1_ge pr_ge; - secp256k1_ge_set_gej(&pr_ge, &pr); - secp256k1_fe_normalize(&pr_ge.x); - - secp256k1_fe_get_b32(c, &pr_ge.x); - secp256k1_scalar_set_b32(&computed_r, c, NULL); - return secp256k1_scalar_eq(sigr, &computed_r); -} -#else - secp256k1_scalar_get_b32(c, sigr); - /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */ - (void)secp256k1_fe_set_b32_limit(&xr, c); - - /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) - * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), - * compute the remainder modulo n, and compare it to xr. However: - * - * xr == X(pr) mod n - * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) - * [Since 2 * n > p, h can only be 0 or 1] - * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) - * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] - * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) - * [Multiplying both sides of the equations by pr.z^2 mod p] - * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) - * - * Thus, we can avoid the inversion, but we have to check both cases separately. - * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. - */ - if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ - return 1; - } - if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - /* xr + n >= p, so we can skip testing the second case. */ - return 0; - } - secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); - if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ - return 1; - } - return 0; -#endif -} - -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { - unsigned char b[32]; - secp256k1_gej rp; - secp256k1_ge r; - secp256k1_scalar n; - int overflow = 0; - int high; - - secp256k1_ecmult_gen(ctx, &rp, nonce); - secp256k1_ge_set_gej(&r, &rp); - secp256k1_fe_normalize(&r.x); - secp256k1_fe_normalize(&r.y); - secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(sigr, b, &overflow); - if (recid) { - /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log - * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. - */ - *recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y); - } - secp256k1_scalar_mul(&n, sigr, seckey); - secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(sigs, nonce); - secp256k1_scalar_mul(sigs, sigs, &n); - secp256k1_scalar_clear(&n); - secp256k1_gej_clear(&rp); - secp256k1_ge_clear(&r); - high = secp256k1_scalar_is_high(sigs); - secp256k1_scalar_cond_negate(sigs, high); - if (recid) { - *recid ^= high; - } - /* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature. - * This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. - */ - return (int)(!secp256k1_scalar_is_zero(sigr)) & (int)(!secp256k1_scalar_is_zero(sigs)); -} - -#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/external/secp256k1/src/eckey.h b/external/secp256k1/src/eckey.h deleted file mode 100644 index d54d44c997..0000000000 --- a/external/secp256k1/src/eckey.h +++ /dev/null @@ -1,25 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECKEY_H -#define SECP256K1_ECKEY_H - -#include - -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak); - -#endif /* SECP256K1_ECKEY_H */ diff --git a/external/secp256k1/src/eckey_impl.h b/external/secp256k1/src/eckey_impl.h deleted file mode 100644 index 121966f8b5..0000000000 --- a/external/secp256k1/src/eckey_impl.h +++ /dev/null @@ -1,92 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECKEY_IMPL_H -#define SECP256K1_ECKEY_IMPL_H - -#include "eckey.h" - -#include "scalar.h" -#include "field.h" -#include "group.h" -#include "ecmult_gen.h" - -static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { - if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { - secp256k1_fe x; - return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); - } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { - secp256k1_fe x, y; - if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) { - return 0; - } - secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && - secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { - return 0; - } - return secp256k1_ge_is_valid_var(elem); - } else { - return 0; - } -} - -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { - if (secp256k1_ge_is_infinity(elem)) { - return 0; - } - secp256k1_fe_normalize_var(&elem->x); - secp256k1_fe_normalize_var(&elem->y); - secp256k1_fe_get_b32(&pub[1], &elem->x); - if (compressed) { - *size = 33; - pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; - } else { - *size = 65; - pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; - secp256k1_fe_get_b32(&pub[33], &elem->y); - } - return 1; -} - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { - secp256k1_scalar_add(key, key, tweak); - return !secp256k1_scalar_is_zero(key); -} - -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) { - secp256k1_gej pt; - secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak); - - if (secp256k1_gej_is_infinity(&pt)) { - return 0; - } - secp256k1_ge_set_gej(key, &pt); - return 1; -} - -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { - int ret; - ret = !secp256k1_scalar_is_zero(tweak); - - secp256k1_scalar_mul(key, key, tweak); - return ret; -} - -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) { - secp256k1_gej pt; - if (secp256k1_scalar_is_zero(tweak)) { - return 0; - } - - secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero); - secp256k1_ge_set_gej(key, &pt); - return 1; -} - -#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/external/secp256k1/src/ecmult.h b/external/secp256k1/src/ecmult.h deleted file mode 100644 index 326a5eeb43..0000000000 --- a/external/secp256k1/src/ecmult.h +++ /dev/null @@ -1,61 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_H -#define SECP256K1_ECMULT_H - -#include "group.h" -#include "scalar.h" -#include "scratch.h" - -#ifndef ECMULT_WINDOW_SIZE -# define ECMULT_WINDOW_SIZE 15 -# ifdef DEBUG_CONFIG -# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value") -# endif -#endif - -#ifdef DEBUG_CONFIG -# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE) -#endif - -/* No one will ever need more than a window size of 24. The code might - * be correct for larger values of ECMULT_WINDOW_SIZE but this is not - * tested. - * - * The following limitations are known, and there are probably more: - * If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect - * because the size of the memory object that we allocate (in bytes) - * will not fit in a size_t. - * If WINDOW_G > 31 and int has 32 bits, then the code is incorrect - * because certain expressions will overflow. - */ -#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24 -# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24]. -#endif - -/** The number of entries a table with precomputed multiples needs to have. */ -#define ECMULT_TABLE_SIZE(w) (1L << ((w)-2)) - -/** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); - -typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data); - -/** - * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. - * Chooses the right algorithm for a given number of points and scratch space - * size. Resets and overwrites the given scratch space. If the points do not - * fit in the scratch space the algorithm is repeatedly run with batches of - * points. If no scratch space is given then a simple algorithm is used that - * simply multiplies the points with the corresponding scalars and adds them up. - * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) - * 0 if there is not enough scratch space for a single point or - * callback returns 0 - */ -static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); - -#endif /* SECP256K1_ECMULT_H */ diff --git a/external/secp256k1/src/ecmult_compute_table.h b/external/secp256k1/src/ecmult_compute_table.h deleted file mode 100644 index 665f87ff3d..0000000000 --- a/external/secp256k1/src/ecmult_compute_table.h +++ /dev/null @@ -1,16 +0,0 @@ -/***************************************************************************************************** - * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *****************************************************************************************************/ - -#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_H -#define SECP256K1_ECMULT_COMPUTE_TABLE_H - -/* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */ -static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen); - -/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ -static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen); - -#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */ diff --git a/external/secp256k1/src/ecmult_compute_table_impl.h b/external/secp256k1/src/ecmult_compute_table_impl.h deleted file mode 100644 index 69d59ce595..0000000000 --- a/external/secp256k1/src/ecmult_compute_table_impl.h +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************************************** - * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *****************************************************************************************************/ - -#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H -#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H - -#include "ecmult_compute_table.h" -#include "group_impl.h" -#include "field_impl.h" -#include "ecmult.h" -#include "util.h" - -static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) { - secp256k1_gej gj; - secp256k1_ge ge, dgen; - int j; - - gj = *gen; - secp256k1_ge_set_gej_var(&ge, &gj); - secp256k1_ge_to_storage(&table[0], &ge); - - secp256k1_gej_double_var(&gj, gen, NULL); - secp256k1_ge_set_gej_var(&dgen, &gj); - - for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) { - secp256k1_gej_set_ge(&gj, &ge); - secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL); - secp256k1_ge_set_gej_var(&ge, &gj); - secp256k1_ge_to_storage(&table[j], &ge); - } -} - -/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ -static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen) { - secp256k1_gej gj; - int i; - - secp256k1_gej_set_ge(&gj, gen); - secp256k1_ecmult_compute_table(table, window_g, &gj); - for (i = 0; i < 128; ++i) { - secp256k1_gej_double_var(&gj, &gj, NULL); - } - secp256k1_ecmult_compute_table(table_128, window_g, &gj); -} - -#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_const.h b/external/secp256k1/src/ecmult_const.h deleted file mode 100644 index 080e04bc88..0000000000 --- a/external/secp256k1/src/ecmult_const.h +++ /dev/null @@ -1,38 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_H -#define SECP256K1_ECMULT_CONST_H - -#include "scalar.h" -#include "group.h" - -/** - * Multiply: R = q*A (in constant-time for q) - */ -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); - -/** - * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point - * only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is - * returned. - * - * If known_on_curve is 0, a verification is performed that n/d is a valid X - * coordinate, and 0 is returned if not. Otherwise, 1 is returned. - * - * d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero. - * - * Constant time in the value of q, but not any other inputs. - */ -static int secp256k1_ecmult_const_xonly( - secp256k1_fe *r, - const secp256k1_fe *n, - const secp256k1_fe *d, - const secp256k1_scalar *q, - int known_on_curve -); - -#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/external/secp256k1/src/ecmult_const_impl.h b/external/secp256k1/src/ecmult_const_impl.h deleted file mode 100644 index 0d78f7c3ce..0000000000 --- a/external/secp256k1/src/ecmult_const_impl.h +++ /dev/null @@ -1,399 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_IMPL_H -#define SECP256K1_ECMULT_CONST_IMPL_H - -#include "scalar.h" -#include "group.h" -#include "ecmult_const.h" -#include "ecmult_impl.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because - * the tables cannot have infinities in them (this breaks the effective-affine technique's - * z-ratio tracking) */ -# if EXHAUSTIVE_TEST_ORDER == 199 -# define ECMULT_CONST_GROUP_SIZE 4 -# elif EXHAUSTIVE_TEST_ORDER == 13 -# define ECMULT_CONST_GROUP_SIZE 3 -# elif EXHAUSTIVE_TEST_ORDER == 7 -# define ECMULT_CONST_GROUP_SIZE 2 -# else -# error "Unknown EXHAUSTIVE_TEST_ORDER" -# endif -#else -/* Group size 4 or 5 appears optimal. */ -# define ECMULT_CONST_GROUP_SIZE 5 -#endif - -#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1)) -#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE) -#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE) - -/** Fill a table 'pre' with precomputed odd multiples of a. - * - * The resulting point set is brought to a single constant Z denominator, stores the X and Y - * coordinates as ge points in pre, and stores the global Z in globalz. - * - * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE. - */ -static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { - secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE]; - - secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a); - secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr); -} - -/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point. - * - * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries: - * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its - * bits are interpreted as signs of powers of two to look up. - * - * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is - * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15], - * which means we just need to look up one of the precomputed values, and optionally negate it. - */ -#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \ - unsigned int m = 0; \ - /* If the top bit of n is 0, we want the negation. */ \ - volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \ - /* Let n[i] be the i-th bit of n, then the index is - * sum(cnot(n[i]) * 2^i, i=0..l-2) - * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise. - * For example, if n = 4, in binary 0100, the index is 3, in binary 011. - * - * Proof: - * Let - * x = sum((2*n[i] - 1)*2^i, i=0..l-1) - * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1 - * be the value represented by n. - * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise. - * Case x > 0: - * n[l-1] = 1 - * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1) - * = sum(n[i] * 2^i, i=0..l-2) - * Case x <= 0: - * n[l-1] = 0 - * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2 - * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1) - * = sum((1 - n[i]) * 2^i, i=0..l-2) - */ \ - unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \ - secp256k1_fe neg_y; \ - VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ - VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ - /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one - * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ - (r)->x = (pre)[m].x; \ - (r)->y = (pre)[m].y; \ - for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ - /* This loop is used to avoid secret data in array indices. See - * the comment in ecmult_gen_impl.h for rationale. */ \ - secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ - secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ - } \ - (r)->infinity = 0; \ - secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ - secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \ -} while(0) - -/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed - * formulas/constants. - * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */ -#ifdef EXHAUSTIVE_TEST_ORDER -static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER; -/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */ -#elif ECMULT_CONST_BITS == 129 -/* For GROUP_SIZE = 1,3. */ -static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul); -#elif ECMULT_CONST_BITS == 130 -/* For GROUP_SIZE = 2,5. */ -static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul); -#elif ECMULT_CONST_BITS == 132 -/* For GROUP_SIZE = 4,6 */ -static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul); -#else -# error "Unknown ECMULT_CONST_BITS" -#endif - -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) { - /* The approach below combines the signed-digit logic from Mike Hamburg's - * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309) - * Section 3.3, with the GLV endomorphism. - * - * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a - * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n), - * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define: - * - * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) - * - * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) - * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A - * = (2*v + 1 - 2^l) * A - * - * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the - * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table. - * - * It is appealing to try to combine this with the GLV optimization: the idea that a scalar - * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that - * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the - * secp256k1_scalar_split_lambda function which performs such a split with the resulting s1 - * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting: - * - * To compute q*A: - * - Let s1, s2 = split_lambda(q) - * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A) - * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A) - * - Return R1 + R2 - * - * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n) - * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting. - * - * To make it work, we want to modify the input scalar q first, before splitting, and then only - * add a 2^128 offset of the split results (so that they end up in the single 129-bit range - * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick - * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to - * compute it from q: - * - * To compute q*A: - * - Compute s = f(q) - * - Let s1, s2 = split_lambda(s) - * - Let v1 = s1 + 2^128 (mod n) - * - Let v2 = s2 + 2^128 (mod n) - * - Let R1 = C_l(v1, A) - * - Let R2 = C_l(v2, lambda*A) - * - Return R1 + R2 - * - * l will thus need to be at least 129, but we may overshoot by a few bits (see - * further), so keep it as a variable. - * - * To solve for s, we reason: - * q*A = R1 + R2 - * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A) - * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A - * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A - * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) - * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) - * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n) - * <=> f(q) = (q + K) / 2 (mod n) - * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n) - * - * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of - * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE - * that is not less than 129; this equals ECMULT_CONST_BITS. - */ - - /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */ - static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0); - secp256k1_scalar s, v1, v2; - secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE]; - secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE]; - secp256k1_fe global_z; - int group, i; - - /* We're allowed to be non-constant time in the point, and the code below (in particular, - * secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a - * constant-time manner anyway. */ - if (secp256k1_ge_is_infinity(a)) { - secp256k1_gej_set_infinity(r); - return; - } - - /* Compute v1 and v2. */ - secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K); - secp256k1_scalar_half(&s, &s); - secp256k1_scalar_split_lambda(&v1, &v2, &s); - secp256k1_scalar_add(&v1, &v1, &S_OFFSET); - secp256k1_scalar_add(&v2, &v2, &S_OFFSET); - -#ifdef VERIFY - /* Verify that v1 and v2 are in range [0, 2^129-1]. */ - for (i = 129; i < 256; ++i) { - VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0); - VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0); - } -#endif - - /* Calculate odd multiples of A and A*lambda. - * All multiples are brought to the same Z 'denominator', which is stored - * in global_z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - */ - secp256k1_gej_set_ge(r, a); - secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r); - for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); - } - - /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A). - * - * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits - * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2). - * - * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal - * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2. - * This means that all we need to do is add these looked up values together, multiplied - * by 2^(ECMULT_GROUP_SIZE * group). - */ - for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) { - /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */ - unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); - unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); - secp256k1_ge t; - int j; - - ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1); - if (group == ECMULT_CONST_GROUPS - 1) { - /* Directly set r in the first iteration. */ - secp256k1_gej_set_ge(r, &t); - } else { - /* Shift the result so far up. */ - for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) { - secp256k1_gej_double(r, r); - } - secp256k1_gej_add_ge(r, r, &t); - } - ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2); - secp256k1_gej_add_ge(r, r, &t); - } - - /* Map the result back to the secp256k1 curve from the isomorphic curve. */ - secp256k1_fe_mul(&r->z, &r->z, &global_z); -} - -static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) { - - /* This algorithm is a generalization of Peter Dettman's technique for - * avoiding the square root in a random-basepoint x-only multiplication - * on a Weierstrass curve: - * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/ - * - * - * === Background: the effective affine technique === - * - * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to - * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as - * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as - * the curve b=7 coefficient does not appear in those formulas (or at least does not appear in - * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2 - * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf. - * - * This means any linear combination of secp256k1 points can be computed by applying phi_u - * (with non-zero u) on all input points (including the generator, if used), computing the - * linear combination on the isomorphic curve (using the same group laws), and then applying - * phi_u^{-1} to get back to secp256k1. - * - * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply - * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z - * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic - * curve where the affine addition formula can be used instead. - * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is - * (X3, Y3, Z3*Z). - * - * This is the effective affine technique: if we have a linear combination of group elements - * to compute, and all those group elements have the same Z coordinate, we can simply pretend - * that all those Z coordinates are 1, perform the computation that way, and then multiply the - * original Z coordinate back in. - * - * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to - * other curves too, but there the isomorphic curves will have different 'a' coefficients, - * which typically does affect the group laws. - * - * - * === Avoiding the square root for x-only point multiplication === - * - * In this function, we want to compute the X coordinate of q*(n/d, y), for - * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention - * we pick whatever sqrt returns (which we assume to be a deterministic function). - * - * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3). - * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2. - * - * The input point (n/d, y) also has Jacobian coordinates: - * - * (n/d, y, 1) - * = (n/d * v^2, y * v^3, v) - * = (n/d * d*g, y * sqrt(d^3*g^3), v) - * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v) - * = (n*g, sqrt(g/d^3 * d^3*g^3), v) - * = (n*g, sqrt(g^4), v) - * = (n*g, g^2, v) - * - * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X - * coordinate n/d, and this holds even when the square root function doesn't have a - * deterministic sign. We choose the (n*g, g^2, v) version. - * - * Now switch to the effective affine curve using phi_v, where the input point has coordinates - * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there. - * - * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X - * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve - * a square root, but as long as we only care about the resulting X coordinate, no square root - * is needed anywhere in this computation. - */ - - secp256k1_fe g, i; - secp256k1_ge p; - secp256k1_gej rj; - - /* Compute g = (n^3 + B*d^3). */ - secp256k1_fe_sqr(&g, n); - secp256k1_fe_mul(&g, &g, n); - if (d) { - secp256k1_fe b; - VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d)); - secp256k1_fe_sqr(&b, d); - VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */ - secp256k1_fe_mul_int(&b, SECP256K1_B); - secp256k1_fe_mul(&b, &b, d); - secp256k1_fe_add(&g, &b); - if (!known_on_curve) { - /* We need to determine whether (n/d)^3 + 7 is square. - * - * is_square((n/d)^3 + 7) - * <=> is_square(((n/d)^3 + 7) * d^4) - * <=> is_square((n^3 + 7*d^3) * d) - * <=> is_square(g * d) - */ - secp256k1_fe c; - secp256k1_fe_mul(&c, &g, d); - if (!secp256k1_fe_is_square_var(&c)) return 0; - } - } else { - secp256k1_fe_add_int(&g, SECP256K1_B); - if (!known_on_curve) { - /* g at this point equals x^3 + 7. Test if it is square. */ - if (!secp256k1_fe_is_square_var(&g)) return 0; - } - } - - /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has - * corresponding affine X coordinate n/d. */ - secp256k1_fe_mul(&p.x, &g, n); - secp256k1_fe_sqr(&p.y, &g); - p.infinity = 0; - - /* Perform x-only EC multiplication of P with q. */ - VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); - secp256k1_ecmult_const(&rj, &p, q); - VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj)); - - /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to - * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate - * (X / (Z^2*d*g)). */ - secp256k1_fe_sqr(&i, &rj.z); - secp256k1_fe_mul(&i, &i, &g); - if (d) secp256k1_fe_mul(&i, &i, d); - secp256k1_fe_inv(&i, &i); - secp256k1_fe_mul(r, &rj.x, &i); - - return 1; -} - -#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_gen.h b/external/secp256k1/src/ecmult_gen.h deleted file mode 100644 index 43dd10c38d..0000000000 --- a/external/secp256k1/src/ecmult_gen.h +++ /dev/null @@ -1,143 +0,0 @@ -/*********************************************************************** - * Copyright (c) Pieter Wuille, Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_H -#define SECP256K1_ECMULT_GEN_H - -#include "scalar.h" -#include "group.h" - - -/* Configuration parameters for the signed-digit multi-comb algorithm: - * - * - COMB_BLOCKS is the number of blocks the input is split into. Each - * has a corresponding table. - * - COMB_TEETH is the number of bits simultaneously covered by one table. - * - COMB_RANGE is the number of bits in supported scalars. For production - * purposes, only 256 is reasonable, but smaller numbers are supported for - * exhaustive test mode. - * - * The comb's spacing (COMB_SPACING), or the distance between the teeth, - * is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers - * COMB_SPACING * COMB_TEETH consecutive bits in the input. - * - * The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1)) - * secp256k1_ge_storages. - * - * The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point - * addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a - * conditional negation. - * - * The number of point doublings is COMB_SPACING - 1. */ - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* We need to control these values for exhaustive tests because - * the table cannot have infinities in them (secp256k1_ge_storage - * doesn't support infinities) */ -# undef COMB_BLOCKS -# undef COMB_TEETH -# if EXHAUSTIVE_TEST_ORDER == 7 -# define COMB_RANGE 3 -# define COMB_BLOCKS 1 -# define COMB_TEETH 2 -# elif EXHAUSTIVE_TEST_ORDER == 13 -# define COMB_RANGE 4 -# define COMB_BLOCKS 1 -# define COMB_TEETH 2 -# elif EXHAUSTIVE_TEST_ORDER == 199 -# define COMB_RANGE 8 -# define COMB_BLOCKS 2 -# define COMB_TEETH 3 -# else -# error "Unknown exhaustive test order" -# endif -# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1) -# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))" -# endif -#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ -# define COMB_RANGE 256 -#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ - -/* Use (11, 6) as default configuration, which results in a 22 kB table. */ -#ifndef COMB_BLOCKS -# define COMB_BLOCKS 11 -# ifdef DEBUG_CONFIG -# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value") -# endif -#endif -#ifndef COMB_TEETH -# define COMB_TEETH 6 -# ifdef DEBUG_CONFIG -# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value") -# endif -#endif -/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */ -#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH) - -/* Range checks on the parameters. */ - -/* The remaining COMB_* parameters are derived values, don't modify these. */ -/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */ -#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING) -/* - The number of entries per table. */ -#define COMB_POINTS (1 << (COMB_TEETH - 1)) - -/* Sanity checks. */ -#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256) -# error "COMB_BLOCKS must be in the range [1, 256]" -#endif -#if !(1 <= COMB_TEETH && COMB_TEETH <= 8) -# error "COMB_TEETH must be in the range [1, 8]" -#endif -#if COMB_BITS < COMB_RANGE -# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low" -#endif - -/* These last 2 checks are not strictly required, but prevent gratuitously inefficient - * configurations. Note that they compare with 256 rather than COMB_RANGE, so they do - * permit somewhat excessive values for the exhaustive test case, where testing with - * suboptimal parameters may be desirable. */ -#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256 -# error "COMB_BLOCKS can be reduced" -#endif -#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256 -# error "COMB_TEETH can be reduced" -#endif - -#ifdef DEBUG_CONFIG -# pragma message DEBUG_CONFIG_DEF(COMB_RANGE) -# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS) -# pragma message DEBUG_CONFIG_DEF(COMB_TEETH) -# pragma message DEBUG_CONFIG_DEF(COMB_SPACING) -#endif - -typedef struct { - /* Whether the context has been built. */ - int built; - - /* Values chosen such that - * - * n*G == comb(n + scalar_offset, G/2) + ge_offset. - * - * This expression lets us use scalar blinding and optimize the comb precomputation. See - * ecmult_gen_impl.h for more details. */ - secp256k1_scalar scalar_offset; - secp256k1_ge ge_offset; - - /* Factor used for projective blinding. This value is used to rescale the Z - * coordinate of the first table lookup. */ - secp256k1_fe proj_blind; -} secp256k1_ecmult_gen_context; - -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx); -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); - -/** Multiply with the generator: R = a*G */ -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); - -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); - -#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/external/secp256k1/src/ecmult_gen_compute_table.h b/external/secp256k1/src/ecmult_gen_compute_table.h deleted file mode 100644 index bd41803a87..0000000000 --- a/external/secp256k1/src/ecmult_gen_compute_table.h +++ /dev/null @@ -1,14 +0,0 @@ -/*********************************************************************** - * Copyright (c) Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H -#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H - -#include "ecmult_gen.h" - -static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing); - -#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */ diff --git a/external/secp256k1/src/ecmult_gen_compute_table_impl.h b/external/secp256k1/src/ecmult_gen_compute_table_impl.h deleted file mode 100644 index 6aa8d84082..0000000000 --- a/external/secp256k1/src/ecmult_gen_compute_table_impl.h +++ /dev/null @@ -1,108 +0,0 @@ -/*********************************************************************** - * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H -#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H - -#include "ecmult_gen_compute_table.h" -#include "group_impl.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "ecmult_gen.h" -#include "util.h" - -static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) { - size_t points = ((size_t)1) << (teeth - 1); - size_t points_total = points * blocks; - secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec)); - secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds)); - secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs)); - secp256k1_gej u; - size_t vs_pos = 0; - secp256k1_scalar half; - int block, i; - - VERIFY_CHECK(points_total > 0); - - /* u is the running power of two times gen we're working with, initially gen/2. */ - secp256k1_scalar_half(&half, &secp256k1_scalar_one); - secp256k1_gej_set_infinity(&u); - for (i = 255; i >= 0; --i) { - /* Use a very simple multiplication ladder to avoid dependency on ecmult. */ - secp256k1_gej_double_var(&u, &u, NULL); - if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) { - secp256k1_gej_add_ge_var(&u, &u, gen, NULL); - } - } -#ifdef VERIFY - { - /* Verify that u*2 = gen. */ - secp256k1_gej double_u; - secp256k1_gej_double_var(&double_u, &u, NULL); - VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen)); - } -#endif - - for (block = 0; block < blocks; ++block) { - int tooth; - /* Here u = 2^(block*teeth*spacing) * gen/2. */ - secp256k1_gej sum; - secp256k1_gej_set_infinity(&sum); - for (tooth = 0; tooth < teeth; ++tooth) { - /* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */ - /* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */ - secp256k1_gej_add_var(&sum, &sum, &u, NULL); - /* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ - secp256k1_gej_double_var(&u, &u, NULL); - /* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ - ds[tooth] = u; - /* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */ - if (block + tooth != blocks + teeth - 2) { - int bit_off; - for (bit_off = 1; bit_off < spacing; ++bit_off) { - secp256k1_gej_double_var(&u, &u, NULL); - } - } - } - /* Now u = 2^((block*teeth + teeth)*spacing) * gen/2 - * = 2^((block+1)*teeth*spacing) * gen/2 */ - - /* Next, compute the table entries for block number block in Jacobian coordinates. - * The entries will occupy vs[block*points + i] for i=0..points-1. - * We start by computing the first (i=0) value corresponding to all summed - * powers of two times G being negative. */ - secp256k1_gej_neg(&vs[vs_pos++], &sum); - /* And then teeth-1 times "double" the range of i values for which the table - * is computed: in each iteration, double the table by taking an existing - * table entry and adding ds[tooth]. */ - for (tooth = 0; tooth < teeth - 1; ++tooth) { - size_t stride = ((size_t)1) << tooth; - size_t index; - for (index = 0; index < stride; ++index, ++vs_pos) { - secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL); - } - } - } - VERIFY_CHECK(vs_pos == points_total); - - /* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */ - secp256k1_ge_set_all_gej_var(prec, vs, points_total); - /* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */ - for (block = 0; block < blocks; ++block) { - size_t index; - for (index = 0; index < points; ++index) { - VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index])); - secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]); - } - } - - /* Free memory. */ - free(vs); - free(ds); - free(prec); -} - -#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_gen_impl.h b/external/secp256k1/src/ecmult_gen_impl.h deleted file mode 100644 index 070a121308..0000000000 --- a/external/secp256k1/src/ecmult_gen_impl.h +++ /dev/null @@ -1,341 +0,0 @@ -/*********************************************************************** - * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_IMPL_H -#define SECP256K1_ECMULT_GEN_IMPL_H - -#include "util.h" -#include "scalar.h" -#include "group.h" -#include "ecmult_gen.h" -#include "hash_impl.h" -#include "precomputed_ecmult_gen.h" - -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) { - secp256k1_ecmult_gen_blind(ctx, NULL); - ctx->built = 1; -} - -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { - return ctx->built; -} - -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { - ctx->built = 0; - secp256k1_scalar_clear(&ctx->scalar_offset); - secp256k1_ge_clear(&ctx->ge_offset); - secp256k1_fe_clear(&ctx->proj_blind); -} - -/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to - * secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn - * from (before applying blinding). */ -static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) { - int i; - - /* Compute scalar -1/2. */ - secp256k1_scalar neghalf; - secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one); - secp256k1_scalar_negate(&neghalf, &neghalf); - - /* Compute offset = 2^(COMB_BITS - 1). */ - *diff = secp256k1_scalar_one; - for (i = 0; i < COMB_BITS - 1; ++i) { - secp256k1_scalar_add(diff, diff, diff); - } - - /* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */ - secp256k1_scalar_add(diff, diff, &neghalf); -} - -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { - uint32_t comb_off; - secp256k1_ge add; - secp256k1_fe neg; - secp256k1_ge_storage adds; - secp256k1_scalar d; - /* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom - * 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256 - * avoids the need to deal with out-of-bounds reads from a scalar. */ - uint32_t recoded[(COMB_BITS + 31) >> 5] = {0}; - int first = 1, i; - - memset(&adds, 0, sizeof(adds)); - - /* We want to compute R = gn*G. - * - * To blind the scalar used in the computation, we rewrite this to be - * R = (gn - b)*G + b*G, with a blinding value b determined by the context. - * - * The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section - * 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg, - * https://eprint.iacr.org/2012/309). - * - * Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of - * the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0) - * or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are - * covered. By manipulating: - * - * comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1) - * <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P - * <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P - * <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P - * - * If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that - * - * (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G - * <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order) - * - * We use an alternative here that avoids the modular division by two: instead we compute - * (gn-b)*G as comb(d, G/2). For that to hold it must be the case that - * - * (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2) - * <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order) - * - * Adding precomputation, our final equations become: - * - * ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order) - * ctx->ge_offset = b*G - * d = gn + ctx->scalar_offset (mod order) - * R = comb(d, G/2) + ctx->ge_offset - * - * comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1, - * depending on the value of the bits d[i] of the binary representation of scalar d. - */ - - /* Compute the scalar d = (gn + ctx->scalar_offset). */ - secp256k1_scalar_add(&d, &ctx->scalar_offset, gn); - /* Convert to recoded array. */ - for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) { - recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32); - } - secp256k1_scalar_clear(&d); - - /* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the - * (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions. - * We rewrite our equation in terms of these table entries. - * - * Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1), - * with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11, - * COMB_TEETH=6, COMB_SPACING=4, we would have: - * mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20, - * mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44, - * mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68, - * ... - * mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260 - * - * We will split up the bits d[i] using these masks. Specifically, each mask is - * used COMB_SPACING times, with different shifts: - * - * d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) + - * (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) + - * ... - * (d & mask(0)<<(COMB_SPACING-1)) + ... - * - * Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for - * b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on - * 2^COMB_TEETH distinct values). - * - * If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i - * iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68) - * would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2. - * - * With that, we can rewrite comb(d, G/2) as: - * - * 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1))) - * + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1))) - * + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1))) - * + ... - * + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...) - * - * Or more generically as - * - * sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1) - * - * This is implemented using an outer loop that runs in reverse order over the lines of this - * equation, which in each iteration runs an inner loop that adds the terms of that line and - * then doubles the result before proceeding to the next line. - * - * In pseudocode: - * c = infinity - * for comb_off in range(COMB_SPACING - 1, -1, -1): - * for block in range(COMB_BLOCKS): - * c += table(block, (d >> comb_off) & mask(block)) - * if comb_off > 0: - * c = 2*c - * return c - * - * This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would - * be possible to apply an initial offset instead of a final offset (moving ge_offset to take - * the place of infinity above), but the chosen approach allows using (in a future improvement) - * an incomplete addition formula for most of the multiplication. - * - * The last question is how to implement the table(b, m) function. For any value of b, - * m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have - * fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables - * which contain a value for each such m value. - * - * Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating - * the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) = - * (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m). - * Because of this it suffices to only store the first half of the m values for every b. If an - * entry from the second half is needed, we look up its bit-flipped version instead, and negate - * it. - * - * secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index - * is the relevant mask(b) bits of m packed together without gaps. */ - - /* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */ - comb_off = COMB_SPACING - 1; - while (1) { - uint32_t block; - uint32_t bit_pos = comb_off; - /* Inner loop: for each block, add table entries to the result. */ - for (block = 0; block < COMB_BLOCKS; ++block) { - /* Gather the mask(block)-selected bits of d into bits. They're packed: - * bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */ - uint32_t bits = 0, sign, abs, index, tooth; - /* Instead of reading individual bits here to construct the bits variable, - * build up the result by xoring rotated reads together. In every iteration, - * one additional bit is made correct, starting at the bottom. The bits - * above that contain junk. This reduces leakage by avoiding computations - * on variables that can have only a low number of possible values (e.g., - * just two values when reading a single bit into a variable.) See: - * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf - */ - for (tooth = 0; tooth < COMB_TEETH; ++tooth) { - /* Construct bitdata s.t. the bottom bit is the bit we'd like to read. - * - * We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f) - * but this would simply discard the bits that fall off at the bottom, - * and thus, for example, bitdata could still have only two values if we - * happen to shift by exactly 31 positions. We use a rotation instead, - * which ensures that bitdata doesn't loose entropy. This relies on the - * rotation being atomic, i.e., the compiler emitting an actual rot - * instruction. */ - uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f); - - /* Clear the bit at position tooth, but sssh, don't tell clang. */ - uint32_t volatile vmask = ~(1 << tooth); - bits &= vmask; - - /* Write the bit into position tooth (and junk into higher bits). */ - bits ^= bitdata << tooth; - bit_pos += COMB_SPACING; - } - - /* If the top bit of bits is 1, flip them all (corresponding to looking up - * the negated table value), and remember to negate the result in sign. */ - sign = (bits >> (COMB_TEETH - 1)) & 1; - abs = (bits ^ -sign) & (COMB_POINTS - 1); - VERIFY_CHECK(sign == 0 || sign == 1); - VERIFY_CHECK(abs < COMB_POINTS); - - /** This uses a conditional move to avoid any secret data in array indexes. - * _Any_ use of secret indexes has been demonstrated to result in timing - * sidechannels, even when the cache-line access patterns are uniform. - * See also: - * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe - * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and - * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, - * by Dag Arne Osvik, Adi Shamir, and Eran Tromer - * (https://www.tau.ac.il/~tromer/papers/cache.pdf) - */ - for (index = 0; index < COMB_POINTS; ++index) { - secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs); - } - - /* Set add=adds or add=-adds, in constant time, based on sign. */ - secp256k1_ge_from_storage(&add, &adds); - secp256k1_fe_negate(&neg, &add.y, 1); - secp256k1_fe_cmov(&add.y, &neg, sign); - - /* Add the looked up and conditionally negated value to r. */ - if (EXPECT(first, 0)) { - /* If this is the first table lookup, we can skip addition. */ - secp256k1_gej_set_ge(r, &add); - /* Give the entry a random Z coordinate to blind intermediary results. */ - secp256k1_gej_rescale(r, &ctx->proj_blind); - first = 0; - } else { - secp256k1_gej_add_ge(r, r, &add); - } - } - - /* Double the result, except in the last iteration. */ - if (comb_off-- == 0) break; - secp256k1_gej_double(r, r); - } - - /* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was - * subtracted from the input scalar gn). */ - secp256k1_gej_add_ge(r, r, &ctx->ge_offset); - - /* Cleanup. */ - secp256k1_fe_clear(&neg); - secp256k1_ge_clear(&add); - secp256k1_memclear(&adds, sizeof(adds)); - secp256k1_memclear(&recoded, sizeof(recoded)); -} - -/* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { - secp256k1_scalar b; - secp256k1_scalar diff; - secp256k1_gej gb; - secp256k1_fe f; - unsigned char nonce32[32]; - secp256k1_rfc6979_hmac_sha256 rng; - unsigned char keydata[64]; - - /* Compute the (2^COMB_BITS - 1)/2 term once. */ - secp256k1_ecmult_gen_scalar_diff(&diff); - - if (seed32 == NULL) { - /* When seed is NULL, reset the final point and blinding value. */ - secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g); - secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff); - ctx->proj_blind = secp256k1_fe_one; - return; - } - /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ - secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset); - /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, - * and guards against weak or adversarial seeds. This is a simpler and safer interface than - * asking the caller for blinding values directly and expecting them to retry on failure. - */ - VERIFY_CHECK(seed32 != NULL); - memcpy(keydata + 32, seed32, 32); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); - secp256k1_memclear(keydata, sizeof(keydata)); - - /* Compute projective blinding factor (cannot be 0). */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - secp256k1_fe_set_b32_mod(&f, nonce32); - secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f)); - ctx->proj_blind = f; - - /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - secp256k1_scalar_set_b32(&b, nonce32, NULL); - /* The blinding value cannot be zero, as that would mean ge_offset = infinity, - * which secp256k1_gej_add_ge cannot handle. */ - secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_ecmult_gen(ctx, &gb, &b); - secp256k1_scalar_negate(&b, &b); - secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff); - secp256k1_ge_set_gej(&ctx->ge_offset, &gb); - - /* Clean up. */ - secp256k1_memclear(nonce32, sizeof(nonce32)); - secp256k1_scalar_clear(&b); - secp256k1_gej_clear(&gb); - secp256k1_fe_clear(&f); - secp256k1_rfc6979_hmac_sha256_clear(&rng); -} - -#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_impl.h b/external/secp256k1/src/ecmult_impl.h deleted file mode 100644 index 0b53b3fcb9..0000000000 --- a/external/secp256k1/src/ecmult_impl.h +++ /dev/null @@ -1,853 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - ******************************************************************************/ - -#ifndef SECP256K1_ECMULT_IMPL_H -#define SECP256K1_ECMULT_IMPL_H - -#include -#include - -#include "util.h" -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "precomputed_ecmult.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* We need to lower these values for exhaustive tests because - * the tables cannot have infinities in them (this breaks the - * affine-isomorphism stuff which tracks z-ratios) */ -# if EXHAUSTIVE_TEST_ORDER > 128 -# define WINDOW_A 5 -# elif EXHAUSTIVE_TEST_ORDER > 8 -# define WINDOW_A 4 -# else -# define WINDOW_A 2 -# endif -#else -/* optimal for 128-bit and 256-bit exponents. */ -# define WINDOW_A 5 -/** Larger values for ECMULT_WINDOW_SIZE result in possibly better - * performance at the cost of an exponentially larger precomputed - * table. The exact table size is - * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes, - * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can - * be larger due to platform-specific padding and alignment. - * Two tables of this size are used (due to the endomorphism - * optimization). - */ -#endif - -#define WNAF_BITS 128 -#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w) -#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) - -/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ -#define PIPPENGER_SCRATCH_OBJECTS 6 -#define STRAUSS_SCRATCH_OBJECTS 5 - -#define PIPPENGER_MAX_BUCKET_WINDOW 12 - -/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ -#define ECMULT_PIPPENGER_THRESHOLD 88 - -#define ECMULT_MAX_POINTS_PER_BATCH 5000000 - -/** Fill a table 'pre_a' with precomputed odd multiples of a. - * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements. - * zr needs space for n field elements. - * - * Although pre_a is an array of _ge rather than _gej, it actually represents elements - * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates - * can be recovered using z and zr. Using the notation z(b) to represent the omitted - * z coordinate of b: - * - z(pre_a[n-1]) = 'z' - * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0 - * - * Lastly the zr[0] value, which isn't used above, is set so that: - * - a.z = z(pre_a[0]) / zr[0] - */ -static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) { - secp256k1_gej d, ai; - secp256k1_ge d_ge; - int i; - - VERIFY_CHECK(!a->infinity); - - secp256k1_gej_double_var(&d, a, NULL); - - /* - * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z. - * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve. - * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C). - * - * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C) - * d_ge := phi(d) = (d.x, d.y, 1) - * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z) - * - * The group addition functions work correctly on these isomorphic curves. - * In particular phi(d) is easy to represent in affine coordinates under this isomorphism. - * This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise. - */ - secp256k1_ge_set_xy(&d_ge, &d.x, &d.y); - secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z); - secp256k1_gej_set_ge(&ai, &pre_a[0]); - ai.z = a->z; - - /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a. - * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z. - */ - zr[0] = d.z; - - for (i = 1; i < n; i++) { - secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]); - secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y); - } - - /* Multiply the last z-coordinate by C to undo the isomorphism. - * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios, - * undoing the isomorphism here undoes the isomorphism for all pre_a values. - */ - secp256k1_fe_mul(z, &ai.z, &d.z); -} - -SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) { - (void)n; - (void)w; - VERIFY_CHECK(((n) & 1) == 1); - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); -} - -SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) { - secp256k1_ecmult_table_verify(n,w); - if (n > 0) { - *r = pre[(n-1)/2]; - } else { - *r = pre[(-n-1)/2]; - secp256k1_fe_negate(&(r->y), &(r->y), 1); - } -} - -SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) { - secp256k1_ecmult_table_verify(n,w); - if (n > 0) { - secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y); - } else { - secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y); - secp256k1_fe_negate(&(r->y), &(r->y), 1); - } -} - -SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) { - secp256k1_ecmult_table_verify(n,w); - if (n > 0) { - secp256k1_ge_from_storage(r, &pre[(n-1)/2]); - } else { - secp256k1_ge_from_storage(r, &pre[(-n-1)/2]); - secp256k1_fe_negate(&(r->y), &(r->y), 1); - } -} - -/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), - * with the following guarantees: - * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) - * - two non-zero entries in wnaf are separated by at least w-1 zeroes. - * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * than the number of bits in the (absolute value) of the input. - */ -static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { - secp256k1_scalar s; - int last_set_bit = -1; - int bit = 0; - int sign = 1; - int carry = 0; - - VERIFY_CHECK(wnaf != NULL); - VERIFY_CHECK(0 <= len && len <= 256); - VERIFY_CHECK(a != NULL); - VERIFY_CHECK(2 <= w && w <= 31); - - for (bit = 0; bit < len; bit++) { - wnaf[bit] = 0; - } - - s = *a; - if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) { - secp256k1_scalar_negate(&s, &s); - sign = -1; - } - - bit = 0; - while (bit < len) { - int now; - int word; - if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) { - bit++; - continue; - } - - now = w; - if (now > len - bit) { - now = len - bit; - } - - word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; - - carry = (word >> (w-1)) & 1; - word -= carry << w; - - wnaf[bit] = sign * word; - last_set_bit = bit; - - bit += now; - } -#ifdef VERIFY - { - int verify_bit = bit; - - VERIFY_CHECK(carry == 0); - - while (verify_bit < 256) { - VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0); - verify_bit++; - } - } -#endif - return last_set_bit + 1; -} - -struct secp256k1_strauss_point_state { - int wnaf_na_1[129]; - int wnaf_na_lam[129]; - int bits_na_1; - int bits_na_lam; -}; - -struct secp256k1_strauss_state { - /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */ - secp256k1_fe* aux; - secp256k1_ge* pre_a; - struct secp256k1_strauss_point_state* ps; -}; - -static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *state, secp256k1_gej *r, size_t num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { - secp256k1_ge tmpa; - secp256k1_fe Z; - /* Split G factors. */ - secp256k1_scalar ng_1, ng_128; - int wnaf_ng_1[129]; - int bits_ng_1 = 0; - int wnaf_ng_128[129]; - int bits_ng_128 = 0; - int i; - int bits = 0; - size_t np; - size_t no = 0; - - secp256k1_fe_set_int(&Z, 1); - for (np = 0; np < num; ++np) { - secp256k1_gej tmp; - secp256k1_scalar na_1, na_lam; - if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) { - continue; - } - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]); - - /* build wnaf representation for na_1 and na_lam. */ - state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); - state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); - VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); - VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); - if (state->ps[no].bits_na_1 > bits) { - bits = state->ps[no].bits_na_1; - } - if (state->ps[no].bits_na_lam > bits) { - bits = state->ps[no].bits_na_lam; - } - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - * The exception is the precomputed G table points, which are actually - * affine. Compared to the base used for other points, they have a Z ratio - * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same - * isomorphism to efficiently add with a known Z inverse. - */ - tmp = a[np]; - if (no) { - secp256k1_gej_rescale(&tmp, &Z); - } - secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); - if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z)); - - ++no; - } - - /* Bring them to the same Z denominator. */ - if (no) { - secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux); - } - - for (np = 0; np < no; ++np) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta); - } - } - - if (ng) { - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - secp256k1_scalar_split_128(&ng_1, &ng_128, ng); - - /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) { - bits = bits_ng_1; - } - if (bits_ng_128 > bits) { - bits = bits_ng_128; - } - } - - secp256k1_gej_set_infinity(r); - - for (i = bits - 1; i >= 0; i--) { - int n; - secp256k1_gej_double_var(r, r, NULL); - for (np = 0; np < no; ++np) { - if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { - secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { - secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - } - if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } - if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } - } - - if (!r->infinity) { - secp256k1_fe_mul(&r->z, &r->z, &Z); - } -} - -static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { - secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - struct secp256k1_strauss_point_state ps[1]; - struct secp256k1_strauss_state state; - - state.aux = aux; - state.pre_a = pre_a; - state.ps = ps; - secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng); -} - -static size_t secp256k1_strauss_scratch_size(size_t n_points) { - static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); - return n_points*point_size; -} - -static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { - secp256k1_gej* points; - secp256k1_scalar* scalars; - struct secp256k1_strauss_state state; - size_t i; - const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); - - secp256k1_gej_set_infinity(r); - if (inp_g_sc == NULL && n_points == 0) { - return 1; - } - - /* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these - * allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS - * constant and strauss_scratch_size accordingly. */ - points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej)); - scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); - state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); - state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); - state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); - - if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) { - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - - for (i = 0; i < n_points; i++) { - secp256k1_ge point; - if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - secp256k1_gej_set_ge(&points[i], &point); - } - secp256k1_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc); - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 1; -} - -/* Wrapper for secp256k1_ecmult_multi_func interface */ -static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { - return secp256k1_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); -} - -static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { - return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); -} - -/** Convert a number to WNAF notation. - * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. - * It has the following guarantees: - * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) - * - the number of words set is always WNAF_SIZE(w) - * - the returned skew is 0 or 1 - */ -static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) { - int skew = 0; - int pos; - int max_pos; - int last_w; - const secp256k1_scalar *work = s; - - if (secp256k1_scalar_is_zero(s)) { - for (pos = 0; pos < WNAF_SIZE(w); pos++) { - wnaf[pos] = 0; - } - return 0; - } - - if (secp256k1_scalar_is_even(s)) { - skew = 1; - } - - wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew; - /* Compute last window size. Relevant when window size doesn't divide the - * number of bits in the scalar */ - last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; - - /* Store the position of the first nonzero word in max_pos to allow - * skipping leading zeros when calculating the wnaf. */ - for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { - int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); - if(val != 0) { - break; - } - wnaf[pos] = 0; - } - max_pos = pos; - pos = 1; - - while (pos <= max_pos) { - int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); - if ((val & 1) == 0) { - wnaf[pos - 1] -= (1 << w); - wnaf[pos] = (val + 1); - } else { - wnaf[pos] = val; - } - /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit - * is strictly negative or strictly positive respectively. Only change - * coefficients at previous positions because above code assumes that - * wnaf[pos - 1] is odd. - */ - if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { - if (wnaf[pos - 1] == 1) { - wnaf[pos - 2] += 1 << w; - } else { - wnaf[pos - 2] -= 1 << w; - } - wnaf[pos - 1] = 0; - } - ++pos; - } - - return skew; -} - -struct secp256k1_pippenger_point_state { - int skew_na; - size_t input_pos; -}; - -struct secp256k1_pippenger_state { - int *wnaf_na; - struct secp256k1_pippenger_point_state* ps; -}; - -/* - * pippenger_wnaf computes the result of a multi-point multiplication as - * follows: The scalars are brought into wnaf with n_wnaf elements each. Then - * for every i < n_wnaf, first each point is added to a "bucket" corresponding - * to the point's wnaf[i]. Second, the buckets are added together such that - * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... - */ -static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) { - size_t n_wnaf = WNAF_SIZE(bucket_window+1); - size_t np; - size_t no = 0; - int i; - int j; - - for (np = 0; np < num; ++np) { - if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) { - continue; - } - state->ps[no].input_pos = np; - state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); - no++; - } - secp256k1_gej_set_infinity(r); - - if (no == 0) { - return 1; - } - - for (i = n_wnaf - 1; i >= 0; i--) { - secp256k1_gej running_sum; - - for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { - secp256k1_gej_set_infinity(&buckets[j]); - } - - for (np = 0; np < no; ++np) { - int n = state->wnaf_na[np*n_wnaf + i]; - struct secp256k1_pippenger_point_state point_state = state->ps[np]; - secp256k1_ge tmp; - int idx; - - if (i == 0) { - /* correct for wnaf skew */ - int skew = point_state.skew_na; - if (skew) { - secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); - secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); - } - } - if (n > 0) { - idx = (n - 1)/2; - secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); - } else if (n < 0) { - idx = -(n + 1)/2; - secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); - secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); - } - } - - for(j = 0; j < bucket_window; j++) { - secp256k1_gej_double_var(r, r, NULL); - } - - secp256k1_gej_set_infinity(&running_sum); - /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... - * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... - * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) - * using an intermediate running sum: - * running_sum = bucket[0] + bucket[1] + bucket[2] + ... - * - * The doubling is done implicitly by deferring the final window doubling (of 'r'). - */ - for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { - secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); - secp256k1_gej_add_var(r, r, &running_sum, NULL); - } - - secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); - secp256k1_gej_double_var(r, r, NULL); - secp256k1_gej_add_var(r, r, &running_sum, NULL); - } - return 1; -} - -/** - * Returns optimal bucket_window (number of bits of a scalar represented by a - * set of buckets) for a given number of points. - */ -static int secp256k1_pippenger_bucket_window(size_t n) { - if (n <= 1) { - return 1; - } else if (n <= 4) { - return 2; - } else if (n <= 20) { - return 3; - } else if (n <= 57) { - return 4; - } else if (n <= 136) { - return 5; - } else if (n <= 235) { - return 6; - } else if (n <= 1260) { - return 7; - } else if (n <= 4420) { - return 9; - } else if (n <= 7880) { - return 10; - } else if (n <= 16050) { - return 11; - } else { - return PIPPENGER_MAX_BUCKET_WINDOW; - } -} - -/** - * Returns the maximum optimal number of points for a bucket_window. - */ -static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { - switch(bucket_window) { - case 1: return 1; - case 2: return 4; - case 3: return 20; - case 4: return 57; - case 5: return 136; - case 6: return 235; - case 7: return 1260; - case 8: return 1260; - case 9: return 4420; - case 10: return 7880; - case 11: return 16050; - case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; - } - return 0; -} - - -SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) { - secp256k1_scalar tmp = *s1; - secp256k1_scalar_split_lambda(s1, s2, &tmp); - secp256k1_ge_mul_lambda(p2, p1); - - if (secp256k1_scalar_is_high(s1)) { - secp256k1_scalar_negate(s1, s1); - secp256k1_ge_neg(p1, p1); - } - if (secp256k1_scalar_is_high(s2)) { - secp256k1_scalar_negate(s2, s2); - secp256k1_ge_neg(p2, p2); - } -} - -/** - * Returns the scratch size required for a given number of points (excluding - * base point G) without considering alignment. - */ -static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) { - size_t entries = 2*n_points + 2; - size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); - return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; -} - -static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { - const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); - /* Use 2(n+1) with the endomorphism, when calculating batch - * sizes. The reason for +1 is that we add the G scalar to the list of - * other scalars. */ - size_t entries = 2*n_points + 2; - secp256k1_ge *points; - secp256k1_scalar *scalars; - secp256k1_gej *buckets; - struct secp256k1_pippenger_state *state_space; - size_t idx = 0; - size_t point_idx = 0; - int bucket_window; - - secp256k1_gej_set_infinity(r); - if (inp_g_sc == NULL && n_points == 0) { - return 1; - } - bucket_window = secp256k1_pippenger_bucket_window(n_points); - - /* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If - * these allocations change, make sure to update the - * PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size - * accordingly. */ - points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); - scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); - state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space)); - if (points == NULL || scalars == NULL || state_space == NULL) { - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); - state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); - buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets)); - if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - - if (inp_g_sc != NULL) { - scalars[0] = *inp_g_sc; - points[0] = secp256k1_ge_const_g; - idx++; - secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); - idx++; - } - - while (point_idx < n_points) { - if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - idx++; - secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); - idx++; - point_idx++; - } - - secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); - secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 1; -} - -/* Wrapper for secp256k1_ecmult_multi_func interface */ -static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { - return secp256k1_ecmult_pippenger_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); -} - -/** - * Returns the maximum number of points in addition to G that can be used with - * a given scratch space. The function ensures that fewer points may also be - * used. - */ -static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { - size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS); - int bucket_window; - size_t res = 0; - - for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { - size_t n_points; - size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window); - size_t space_for_points; - size_t space_overhead; - size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); - - entry_size = 2*entry_size; - space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state); - if (space_overhead > max_alloc) { - break; - } - space_for_points = max_alloc - space_overhead; - - n_points = space_for_points/entry_size; - n_points = n_points > max_points ? max_points : n_points; - if (n_points > res) { - res = n_points; - } - if (n_points < max_points) { - /* A larger bucket_window may support even more points. But if we - * would choose that then the caller couldn't safely use any number - * smaller than what this function returns */ - break; - } - } - return res; -} - -/* Computes ecmult_multi by simply multiplying and adding each point. Does not - * require a scratch space */ -static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) { - size_t point_idx; - secp256k1_gej tmpj; - - secp256k1_gej_set_infinity(r); - secp256k1_gej_set_infinity(&tmpj); - /* r = inp_g_sc*G */ - secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc); - for (point_idx = 0; point_idx < n_points; point_idx++) { - secp256k1_ge point; - secp256k1_gej pointj; - secp256k1_scalar scalar; - if (!cb(&scalar, &point, point_idx, cbdata)) { - return 0; - } - /* r += scalar*point */ - secp256k1_gej_set_ge(&pointj, &point); - secp256k1_ecmult(&tmpj, &pointj, &scalar, NULL); - secp256k1_gej_add_var(r, r, &tmpj, NULL); - } - return 1; -} - -/* Compute the number of batches and the batch size given the maximum batch size and the - * total number of points */ -static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) { - if (max_n_batch_points == 0) { - return 0; - } - if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) { - max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; - } - if (n == 0) { - *n_batches = 0; - *n_batch_points = 0; - return 1; - } - /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ - *n_batches = CEIL_DIV(n, max_n_batch_points); - *n_batch_points = CEIL_DIV(n, *n_batches); - return 1; -} - -typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t); -static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { - size_t i; - - int (*f)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t); - size_t n_batches; - size_t n_batch_points; - - secp256k1_gej_set_infinity(r); - if (inp_g_sc == NULL && n == 0) { - return 1; - } else if (n == 0) { - secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc); - return 1; - } - if (scratch == NULL) { - return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - - /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than - * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. - * As a first step check if there's enough space for Pippenger's algo (which requires less space - * than Strauss' algo) and if not, use the simple algorithm. */ - if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(error_callback, scratch), n)) { - return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { - f = secp256k1_ecmult_pippenger_batch; - } else { - if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) { - return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - f = secp256k1_ecmult_strauss_batch; - } - for(i = 0; i < n_batches; i++) { - size_t nbp = n < n_batch_points ? n : n_batch_points; - size_t offset = n_batch_points*i; - secp256k1_gej tmp; - if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { - return 0; - } - secp256k1_gej_add_var(r, r, &tmp, NULL); - n -= nbp; - } - return 1; -} - -#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/external/secp256k1/src/field.h b/external/secp256k1/src/field.h deleted file mode 100644 index 1f6ba7460f..0000000000 --- a/external/secp256k1/src/field.h +++ /dev/null @@ -1,350 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_H -#define SECP256K1_FIELD_H - -#include "util.h" - -/* This file defines the generic interface for working with secp256k1_fe - * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). - * - * The actual definition of the secp256k1_fe type depends on the chosen field - * implementation; see the field_5x52.h and field_10x26.h files for details. - * - * All secp256k1_fe objects have implicit properties that determine what - * operations are permitted on it. These are purely a function of what - * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at - * compile time, and do not depend on the chosen field implementation. Despite - * that, what these properties actually entail for the field representation - * values depends on the chosen field implementation. These properties are: - * - magnitude: an integer in [0,32] - * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. - * - * In VERIFY mode, they are materialized explicitly as fields in the struct, - * allowing run-time verification of these properties. In that case, the field - * implementation also provides a secp256k1_fe_verify routine to verify that - * these fields match the run-time value and perform internal consistency - * checks. */ -#ifdef VERIFY -# define SECP256K1_FE_VERIFY_FIELDS \ - int magnitude; \ - int normalized; -#else -# define SECP256K1_FE_VERIFY_FIELDS -#endif - -#if defined(SECP256K1_WIDEMUL_INT128) -#include "field_5x52.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "field_10x26.h" -#else -#error "Please select wide multiplication implementation" -#endif - -#ifdef VERIFY -/* Magnitude and normalized value for constants. */ -#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ - /* Magnitude is 0 for constant 0; 1 otherwise. */ \ - , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ - /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ - , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) -#else -#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) -#endif - -/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p. - * - * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. - * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. - * - * SECP256K1_FE_CONST_INNER is provided by the implementation. - */ -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } - -static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); -static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( - 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, - 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul -); - -#ifndef VERIFY -/* In non-VERIFY mode, we #define the fe operations to be identical to their - * internal field implementation, to avoid the potential overhead of a - * function call (even though presumably inlinable). */ -# define secp256k1_fe_normalize secp256k1_fe_impl_normalize -# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak -# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var -# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero -# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var -# define secp256k1_fe_set_int secp256k1_fe_impl_set_int -# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero -# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd -# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var -# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod -# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit -# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 -# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked -# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked -# define secp256k1_fe_add secp256k1_fe_impl_add -# define secp256k1_fe_mul secp256k1_fe_impl_mul -# define secp256k1_fe_sqr secp256k1_fe_impl_sqr -# define secp256k1_fe_cmov secp256k1_fe_impl_cmov -# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage -# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage -# define secp256k1_fe_inv secp256k1_fe_impl_inv -# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var -# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds -# define secp256k1_fe_half secp256k1_fe_impl_half -# define secp256k1_fe_add_int secp256k1_fe_impl_add_int -# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var -#endif /* !defined(VERIFY) */ - -/** Normalize a field element. - * - * On input, r must be a valid field element. - * On output, r represents the same value but has normalized=1 and magnitude=1. - */ -static void secp256k1_fe_normalize(secp256k1_fe *r); - -/** Give a field element magnitude 1. - * - * On input, r must be a valid field element. - * On output, r represents the same value but has magnitude=1. Normalized is unchanged. - */ -static void secp256k1_fe_normalize_weak(secp256k1_fe *r); - -/** Normalize a field element, without constant-time guarantee. - * - * Identical in behavior to secp256k1_fe_normalize, but not constant time in r. - */ -static void secp256k1_fe_normalize_var(secp256k1_fe *r); - -/** Determine whether r represents field element 0. - * - * On input, r must be a valid field element. - * Returns whether r = 0 (mod p). - */ -static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); - -/** Determine whether r represents field element 0, without constant-time guarantee. - * - * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r. - */ -static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); - -/** Set a field element to an integer in range [0,0x7FFF]. - * - * On input, r does not need to be initialized, a must be in [0,0x7FFF]. - * On output, r represents value a, is normalized and has magnitude (a!=0). - */ -static void secp256k1_fe_set_int(secp256k1_fe *r, int a); - -/** Clear a field element to prevent leaking sensitive information. */ -static void secp256k1_fe_clear(secp256k1_fe *a); - -/** Determine whether a represents field element 0. - * - * On input, a must be a valid normalized field element. - * Returns whether a = 0 (mod p). - * - * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires - * normalized input (and is much faster). - */ -static int secp256k1_fe_is_zero(const secp256k1_fe *a); - -/** Determine whether a (mod p) is odd. - * - * On input, a must be a valid normalized field element. - * Returns (int(a) mod p) & 1. - */ -static int secp256k1_fe_is_odd(const secp256k1_fe *a); - -/** Determine whether two field elements are equal. - * - * On input, a and b must be valid field elements with magnitudes not exceeding - * 1 and 31, respectively. - * Returns a = b (mod p). - */ -static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); - -/** Compare the values represented by 2 field elements, without constant-time guarantee. - * - * On input, a and b must be valid normalized field elements. - * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers - * in range 0..p-1). - */ -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); - -/** Set a field element equal to the element represented by a provided 32-byte big endian value - * interpreted modulo p. - * - * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. - * On output, r = a (mod p). It will have magnitude 1, and not be normalized. - */ -static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a); - -/** Set a field element equal to a provided 32-byte big endian value, checking for overflow. - * - * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. - * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned. - * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting). - */ -static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a); - -/** Convert a field element to 32-byte big endian byte array. - * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. - * On output, r = a (mod p). - */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); - -/** Negate a field element. - * - * On input, r does not need to be initialized. a must be a valid field element with - * magnitude not exceeding m. m must be an integer constant expression in [0,31]. - * Performs {r = -a}. - * On output, r will not be normalized, and will have magnitude m+1. - */ -#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m)) - -/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression. - * - * Should not be called directly outside of tests. - */ -static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); - -/** Add a small integer to a field element. - * - * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. - * a must be in range [0,0x7FFF]. - */ -static void secp256k1_fe_add_int(secp256k1_fe *r, int a); - -/** Multiply a field element with a small integer. - * - * On input, r must be a valid field element. a must be an integer constant expression in [0,32]. - * The magnitude of r times a must not exceed 32. - * Performs {r *= a}. - * On output, r's magnitude is multiplied by a, and r will not be normalized. - */ -#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a)) - -/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression. - * - * Should not be called directly outside of tests. - */ -static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a); - -/** Increment a field element by another. - * - * On input, r and a must be valid field elements, not necessarily normalized. - * The sum of their magnitudes must not exceed 32. - * Performs {r += a}. - * On output, r will not be normalized, and will have magnitude incremented by a's. - */ -static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); - -/** Multiply two field elements. - * - * On input, a and b must be valid field elements; r does not need to be initialized. - * r and a may point to the same object, but neither may point to the object pointed - * to by b. The magnitudes of a and b must not exceed 8. - * Performs {r = a * b} - * On output, r will have magnitude 1, but won't be normalized. - */ -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); - -/** Square a field element. - * - * On input, a must be a valid field element; r does not need to be initialized. The magnitude - * of a must not exceed 8. - * Performs {r = a**2} - * On output, r will have magnitude 1, but won't be normalized. - */ -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); - -/** Compute a square root of a field element. - * - * On input, a must be a valid field element with magnitude<=8; r need not be initialized. - * If sqrt(a) exists, performs {r = sqrt(a)} and returns 1. - * Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0. - * The resulting value represented by r will be a square itself. - * Variables r and a must not point to the same object. - * On output, r will have magnitude 1 but will not be normalized. - */ -static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); - -/** Compute the modular inverse of a field element. - * - * On input, a must be a valid field element; r need not be initialized. - * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its - * inverse). - * On output, r will have magnitude (a.magnitude != 0) and be normalized. - */ -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); - -/** Compute the modular inverse of a field element, without constant-time guarantee. - * - * Behaves identically to secp256k1_fe_inv, but is not constant-time in a. - */ -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); - -/** Convert a field element to secp256k1_fe_storage. - * - * On input, a must be a valid normalized field element. - * Performs {r = a}. - */ -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); - -/** Convert a field element back from secp256k1_fe_storage. - * - * On input, r need not be initialized. - * Performs {r = a}. - * On output, r will be normalized and will have magnitude 1. - */ -static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); - -/** Conditionally move a field element in constant time. - * - * On input, both r and a must be valid field elements. Flag must be 0 or 1. - * Performs {r = flag ? a : r}. - * - * On output, r's magnitude will be the maximum of both input magnitudes. - * It will be normalized if and only if both inputs were normalized. - */ -static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); - -/** Halve the value of a field element modulo the field prime in constant-time. - * - * On input, r must be a valid field element. - * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is - * the magnitude of r on input. - */ -static void secp256k1_fe_half(secp256k1_fe *r); - -/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. - * The value is chosen so that it is likely to trigger edge cases related to - * internal overflows. */ -static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); - -/** Determine whether a is a square (modulo p). - * - * On input, a must be a valid field element. - */ -static int secp256k1_fe_is_square_var(const secp256k1_fe *a); - -/** Check invariants on a field element (no-op unless VERIFY is enabled). */ -static void secp256k1_fe_verify(const secp256k1_fe *a); -#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a) - -/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */ -static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m); -#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m) - -#endif /* SECP256K1_FIELD_H */ diff --git a/external/secp256k1/src/field_10x26.h b/external/secp256k1/src/field_10x26.h deleted file mode 100644 index 203c10167c..0000000000 --- a/external/secp256k1/src/field_10x26.h +++ /dev/null @@ -1,57 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_H -#define SECP256K1_FIELD_REPR_H - -#include - -/** This field implementation represents the value as 10 uint32_t limbs in base - * 2^26. */ -typedef struct { - /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, - * where p is the field modulus, 2^256 - 2^32 - 977. - * - * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly - * corresponds to how much excess is allowed. The value - * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is - * normalized. */ - uint32_t n[10]; - /* - * Magnitude m requires: - * n[i] <= 2 * m * (2^26 - 1) for i=0..8 - * n[9] <= 2 * m * (2^22 - 1) - * - * Normalized requires: - * n[i] <= (2^26 - 1) for i=0..8 - * sum(i=0..9, n[i] << (i*26)) < p - * (together these imply n[9] <= 2^22 - 1) - */ - SECP256K1_FE_VERIFY_FIELDS -} secp256k1_fe; - -/* Unpacks a constant into a overlapping multi-limbed FE element. */ -#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) & 0x3FFFFFFUL, \ - (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ - (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ - (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ - (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ - (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ - (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ - (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ - (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ - (((uint32_t)d7) >> 10) \ -} - -typedef struct { - uint32_t n[8]; -} secp256k1_fe_storage; - -#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} -#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] - -#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/external/secp256k1/src/field_10x26_impl.h b/external/secp256k1/src/field_10x26_impl.h deleted file mode 100644 index ea14c27318..0000000000 --- a/external/secp256k1/src/field_10x26_impl.h +++ /dev/null @@ -1,1232 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_IMPL_H -#define SECP256K1_FIELD_REPR_IMPL_H - -#include "checkmem.h" -#include "util.h" -#include "field.h" -#include "modinv32_impl.h" - -#ifdef VERIFY -static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { - const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude; - VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); - VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); - if (a->normalized) { - if (d[9] == 0x03FFFFFUL) { - uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; - if (mid == 0x3FFFFFFUL) { - VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); - } - } - } -} -#endif - -static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { - r->n[0] = 0x3FFFFFFUL * 2 * m; - r->n[1] = 0x3FFFFFFUL * 2 * m; - r->n[2] = 0x3FFFFFFUL * 2 * m; - r->n[3] = 0x3FFFFFFUL * 2 * m; - r->n[4] = 0x3FFFFFFUL * 2 * m; - r->n[5] = 0x3FFFFFFUL * 2 * m; - r->n[6] = 0x3FFFFFFUL * 2 * m; - r->n[7] = 0x3FFFFFFUL * 2 * m; - r->n[8] = 0x3FFFFFFUL * 2 * m; - r->n[9] = 0x03FFFFFUL * 2 * m; -} - -static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t m; - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) - & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); - - /* Apply the final reduction (for constant-time behaviour, we do it always) */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ - VERIFY_CHECK(t9 >> 22 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t9 &= 0x03FFFFFUL; - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; -} - -static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; -} - -static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t m; - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) - & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); - - if (x) { - t0 += 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ - VERIFY_CHECK(t9 >> 22 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t9 &= 0x03FFFFFUL; - } - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; -} - -static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - uint32_t z0, z1; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; - z0 |= t9; z1 &= t9 ^ 0x3C00000UL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - return (z0 == 0) | (z1 == 0x3FFFFFFUL); -} - -static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { - uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; - uint32_t z0, z1; - uint32_t x; - - t0 = r->n[0]; - t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - x = t9 >> 22; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - z0 = t0 & 0x3FFFFFFUL; - z1 = z0 ^ 0x3D0UL; - - /* Fast return path should catch the majority of cases */ - if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { - return 0; - } - - t1 = r->n[1]; - t2 = r->n[2]; - t3 = r->n[3]; - t4 = r->n[4]; - t5 = r->n[5]; - t6 = r->n[6]; - t7 = r->n[7]; - t8 = r->n[8]; - - t9 &= 0x03FFFFFUL; - t1 += (x << 6); - - t1 += (t0 >> 26); - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; - z0 |= t9; z1 &= t9 ^ 0x3C00000UL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - return (z0 == 0) | (z1 == 0x3FFFFFFUL); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { - r->n[0] = a; - r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -} - -SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { - const uint32_t *t = a->n; - return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; -} - -SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { - return a->n[0] & 1; -} - -static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - int i; - for (i = 9; i >= 0; i--) { - if (a->n[i] > b->n[i]) { - return 1; - } - if (a->n[i] < b->n[i]) { - return -1; - } - } - return 0; -} - -static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { - r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); - r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); - r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); - r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); - r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); - r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); - r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); - r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); - r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); - r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); -} - -static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { - secp256k1_fe_impl_set_b32_mod(r, a); - return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { - r[0] = (a->n[9] >> 14) & 0xff; - r[1] = (a->n[9] >> 6) & 0xff; - r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); - r[3] = (a->n[8] >> 16) & 0xff; - r[4] = (a->n[8] >> 8) & 0xff; - r[5] = a->n[8] & 0xff; - r[6] = (a->n[7] >> 18) & 0xff; - r[7] = (a->n[7] >> 10) & 0xff; - r[8] = (a->n[7] >> 2) & 0xff; - r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); - r[10] = (a->n[6] >> 12) & 0xff; - r[11] = (a->n[6] >> 4) & 0xff; - r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); - r[13] = (a->n[5] >> 14) & 0xff; - r[14] = (a->n[5] >> 6) & 0xff; - r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); - r[16] = (a->n[4] >> 16) & 0xff; - r[17] = (a->n[4] >> 8) & 0xff; - r[18] = a->n[4] & 0xff; - r[19] = (a->n[3] >> 18) & 0xff; - r[20] = (a->n[3] >> 10) & 0xff; - r[21] = (a->n[3] >> 2) & 0xff; - r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); - r[23] = (a->n[2] >> 12) & 0xff; - r[24] = (a->n[2] >> 4) & 0xff; - r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); - r[26] = (a->n[1] >> 14) & 0xff; - r[27] = (a->n[1] >> 6) & 0xff; - r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); - r[29] = (a->n[0] >> 16) & 0xff; - r[30] = (a->n[0] >> 8) & 0xff; - r[31] = a->n[0] & 0xff; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { - /* For all legal values of m (0..31), the following properties hold: */ - VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); - VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); - VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); - VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); - - /* Due to the properties above, the left hand in the subtractions below is never less than - * the right hand. */ - r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; - r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; - r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; - r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3]; - r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4]; - r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5]; - r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6]; - r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; - r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; - r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { - r->n[0] *= a; - r->n[1] *= a; - r->n[2] *= a; - r->n[3] *= a; - r->n[4] *= a; - r->n[5] *= a; - r->n[6] *= a; - r->n[7] *= a; - r->n[8] *= a; - r->n[9] *= a; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { - r->n[0] += a->n[0]; - r->n[1] += a->n[1]; - r->n[2] += a->n[2]; - r->n[3] += a->n[3]; - r->n[4] += a->n[4]; - r->n[5] += a->n[5]; - r->n[6] += a->n[6]; - r->n[7] += a->n[7]; - r->n[8] += a->n[8]; - r->n[9] += a->n[9]; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { - r->n[0] += a; -} - -#if defined(USE_EXTERNAL_ASM) - -/* External assembler implementation */ -void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); -void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); - -#else - -#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { - uint64_t c, d; - uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; - uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; - - VERIFY_BITS(a[0], 30); - VERIFY_BITS(a[1], 30); - VERIFY_BITS(a[2], 30); - VERIFY_BITS(a[3], 30); - VERIFY_BITS(a[4], 30); - VERIFY_BITS(a[5], 30); - VERIFY_BITS(a[6], 30); - VERIFY_BITS(a[7], 30); - VERIFY_BITS(a[8], 30); - VERIFY_BITS(a[9], 26); - VERIFY_BITS(b[0], 30); - VERIFY_BITS(b[1], 30); - VERIFY_BITS(b[2], 30); - VERIFY_BITS(b[3], 30); - VERIFY_BITS(b[4], 30); - VERIFY_BITS(b[5], 30); - VERIFY_BITS(b[6], 30); - VERIFY_BITS(b[7], 30); - VERIFY_BITS(b[8], 30); - VERIFY_BITS(b[9], 26); - - /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x). - * for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9) - * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. - */ - - d = (uint64_t)a[0] * b[9] - + (uint64_t)a[1] * b[8] - + (uint64_t)a[2] * b[7] - + (uint64_t)a[3] * b[6] - + (uint64_t)a[4] * b[5] - + (uint64_t)a[5] * b[4] - + (uint64_t)a[6] * b[3] - + (uint64_t)a[7] * b[2] - + (uint64_t)a[8] * b[1] - + (uint64_t)a[9] * b[0]; - /* VERIFY_BITS(d, 64); */ - /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - t9 = d & M; d >>= 26; - VERIFY_BITS(t9, 26); - VERIFY_BITS(d, 38); - /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - - c = (uint64_t)a[0] * b[0]; - VERIFY_BITS(c, 60); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ - d += (uint64_t)a[1] * b[9] - + (uint64_t)a[2] * b[8] - + (uint64_t)a[3] * b[7] - + (uint64_t)a[4] * b[6] - + (uint64_t)a[5] * b[5] - + (uint64_t)a[6] * b[4] - + (uint64_t)a[7] * b[3] - + (uint64_t)a[8] * b[2] - + (uint64_t)a[9] * b[1]; - VERIFY_BITS(d, 63); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - u0 = d & M; d >>= 26; c += u0 * R0; - VERIFY_BITS(u0, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 61); - /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - t0 = c & M; c >>= 26; c += u0 * R1; - VERIFY_BITS(t0, 26); - VERIFY_BITS(c, 37); - /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - - c += (uint64_t)a[0] * b[1] - + (uint64_t)a[1] * b[0]; - VERIFY_BITS(c, 62); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ - d += (uint64_t)a[2] * b[9] - + (uint64_t)a[3] * b[8] - + (uint64_t)a[4] * b[7] - + (uint64_t)a[5] * b[6] - + (uint64_t)a[6] * b[5] - + (uint64_t)a[7] * b[4] - + (uint64_t)a[8] * b[3] - + (uint64_t)a[9] * b[2]; - VERIFY_BITS(d, 63); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - u1 = d & M; d >>= 26; c += u1 * R0; - VERIFY_BITS(u1, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - t1 = c & M; c >>= 26; c += u1 * R1; - VERIFY_BITS(t1, 26); - VERIFY_BITS(c, 38); - /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - - c += (uint64_t)a[0] * b[2] - + (uint64_t)a[1] * b[1] - + (uint64_t)a[2] * b[0]; - VERIFY_BITS(c, 62); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - d += (uint64_t)a[3] * b[9] - + (uint64_t)a[4] * b[8] - + (uint64_t)a[5] * b[7] - + (uint64_t)a[6] * b[6] - + (uint64_t)a[7] * b[5] - + (uint64_t)a[8] * b[4] - + (uint64_t)a[9] * b[3]; - VERIFY_BITS(d, 63); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - u2 = d & M; d >>= 26; c += u2 * R0; - VERIFY_BITS(u2, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - t2 = c & M; c >>= 26; c += u2 * R1; - VERIFY_BITS(t2, 26); - VERIFY_BITS(c, 38); - /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[3] - + (uint64_t)a[1] * b[2] - + (uint64_t)a[2] * b[1] - + (uint64_t)a[3] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - d += (uint64_t)a[4] * b[9] - + (uint64_t)a[5] * b[8] - + (uint64_t)a[6] * b[7] - + (uint64_t)a[7] * b[6] - + (uint64_t)a[8] * b[5] - + (uint64_t)a[9] * b[4]; - VERIFY_BITS(d, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - u3 = d & M; d >>= 26; c += u3 * R0; - VERIFY_BITS(u3, 26); - VERIFY_BITS(d, 37); - /* VERIFY_BITS(c, 64); */ - /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - t3 = c & M; c >>= 26; c += u3 * R1; - VERIFY_BITS(t3, 26); - VERIFY_BITS(c, 39); - /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[4] - + (uint64_t)a[1] * b[3] - + (uint64_t)a[2] * b[2] - + (uint64_t)a[3] * b[1] - + (uint64_t)a[4] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[5] * b[9] - + (uint64_t)a[6] * b[8] - + (uint64_t)a[7] * b[7] - + (uint64_t)a[8] * b[6] - + (uint64_t)a[9] * b[5]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - u4 = d & M; d >>= 26; c += u4 * R0; - VERIFY_BITS(u4, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - t4 = c & M; c >>= 26; c += u4 * R1; - VERIFY_BITS(t4, 26); - VERIFY_BITS(c, 39); - /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[5] - + (uint64_t)a[1] * b[4] - + (uint64_t)a[2] * b[3] - + (uint64_t)a[3] * b[2] - + (uint64_t)a[4] * b[1] - + (uint64_t)a[5] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[6] * b[9] - + (uint64_t)a[7] * b[8] - + (uint64_t)a[8] * b[7] - + (uint64_t)a[9] * b[6]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - u5 = d & M; d >>= 26; c += u5 * R0; - VERIFY_BITS(u5, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - t5 = c & M; c >>= 26; c += u5 * R1; - VERIFY_BITS(t5, 26); - VERIFY_BITS(c, 39); - /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[6] - + (uint64_t)a[1] * b[5] - + (uint64_t)a[2] * b[4] - + (uint64_t)a[3] * b[3] - + (uint64_t)a[4] * b[2] - + (uint64_t)a[5] * b[1] - + (uint64_t)a[6] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[7] * b[9] - + (uint64_t)a[8] * b[8] - + (uint64_t)a[9] * b[7]; - VERIFY_BITS(d, 61); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - u6 = d & M; d >>= 26; c += u6 * R0; - VERIFY_BITS(u6, 26); - VERIFY_BITS(d, 35); - /* VERIFY_BITS(c, 64); */ - /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - t6 = c & M; c >>= 26; c += u6 * R1; - VERIFY_BITS(t6, 26); - VERIFY_BITS(c, 39); - /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[7] - + (uint64_t)a[1] * b[6] - + (uint64_t)a[2] * b[5] - + (uint64_t)a[3] * b[4] - + (uint64_t)a[4] * b[3] - + (uint64_t)a[5] * b[2] - + (uint64_t)a[6] * b[1] - + (uint64_t)a[7] * b[0]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x8000007C00000007ULL); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[8] * b[9] - + (uint64_t)a[9] * b[8]; - VERIFY_BITS(d, 58); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - u7 = d & M; d >>= 26; c += u7 * R0; - VERIFY_BITS(u7, 26); - VERIFY_BITS(d, 32); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); - /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - t7 = c & M; c >>= 26; c += u7 * R1; - VERIFY_BITS(t7, 26); - VERIFY_BITS(c, 38); - /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[8] - + (uint64_t)a[1] * b[7] - + (uint64_t)a[2] * b[6] - + (uint64_t)a[3] * b[5] - + (uint64_t)a[4] * b[4] - + (uint64_t)a[5] * b[3] - + (uint64_t)a[6] * b[2] - + (uint64_t)a[7] * b[1] - + (uint64_t)a[8] * b[0]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000007B80000008ULL); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[9] * b[9]; - VERIFY_BITS(d, 57); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - u8 = d & M; d >>= 26; c += u8 * R0; - VERIFY_BITS(u8, 26); - VERIFY_BITS(d, 31); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[3] = t3; - VERIFY_BITS(r[3], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = t4; - VERIFY_BITS(r[4], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[5] = t5; - VERIFY_BITS(r[5], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[6] = t6; - VERIFY_BITS(r[6], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[7] = t7; - VERIFY_BITS(r[7], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[8] = c & M; c >>= 26; c += u8 * R1; - VERIFY_BITS(r[8], 26); - VERIFY_BITS(c, 39); - /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R0 + t9; - VERIFY_BITS(c, 45); - /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); - VERIFY_BITS(r[9], 22); - VERIFY_BITS(c, 46); - /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - d = c * (R0 >> 4) + t0; - VERIFY_BITS(d, 56); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[0] = d & M; d >>= 26; - VERIFY_BITS(r[0], 26); - VERIFY_BITS(d, 30); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += c * (R1 >> 4) + t1; - VERIFY_BITS(d, 53); - VERIFY_CHECK(d <= 0x10000003FFFFBFULL); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[1] = d & M; d >>= 26; - VERIFY_BITS(r[1], 26); - VERIFY_BITS(d, 27); - VERIFY_CHECK(d <= 0x4000000ULL); - /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += t2; - VERIFY_BITS(d, 27); - /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = d; - VERIFY_BITS(r[2], 27); - /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) { - uint64_t c, d; - uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; - uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; - - VERIFY_BITS(a[0], 30); - VERIFY_BITS(a[1], 30); - VERIFY_BITS(a[2], 30); - VERIFY_BITS(a[3], 30); - VERIFY_BITS(a[4], 30); - VERIFY_BITS(a[5], 30); - VERIFY_BITS(a[6], 30); - VERIFY_BITS(a[7], 30); - VERIFY_BITS(a[8], 30); - VERIFY_BITS(a[9], 26); - - /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * px is a shorthand for sum(a[i]*a[x-i], i=0..x). - * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. - */ - - d = (uint64_t)(a[0]*2) * a[9] - + (uint64_t)(a[1]*2) * a[8] - + (uint64_t)(a[2]*2) * a[7] - + (uint64_t)(a[3]*2) * a[6] - + (uint64_t)(a[4]*2) * a[5]; - /* VERIFY_BITS(d, 64); */ - /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - t9 = d & M; d >>= 26; - VERIFY_BITS(t9, 26); - VERIFY_BITS(d, 38); - /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - - c = (uint64_t)a[0] * a[0]; - VERIFY_BITS(c, 60); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ - d += (uint64_t)(a[1]*2) * a[9] - + (uint64_t)(a[2]*2) * a[8] - + (uint64_t)(a[3]*2) * a[7] - + (uint64_t)(a[4]*2) * a[6] - + (uint64_t)a[5] * a[5]; - VERIFY_BITS(d, 63); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - u0 = d & M; d >>= 26; c += u0 * R0; - VERIFY_BITS(u0, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 61); - /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - t0 = c & M; c >>= 26; c += u0 * R1; - VERIFY_BITS(t0, 26); - VERIFY_BITS(c, 37); - /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - - c += (uint64_t)(a[0]*2) * a[1]; - VERIFY_BITS(c, 62); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ - d += (uint64_t)(a[2]*2) * a[9] - + (uint64_t)(a[3]*2) * a[8] - + (uint64_t)(a[4]*2) * a[7] - + (uint64_t)(a[5]*2) * a[6]; - VERIFY_BITS(d, 63); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - u1 = d & M; d >>= 26; c += u1 * R0; - VERIFY_BITS(u1, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - t1 = c & M; c >>= 26; c += u1 * R1; - VERIFY_BITS(t1, 26); - VERIFY_BITS(c, 38); - /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[2] - + (uint64_t)a[1] * a[1]; - VERIFY_BITS(c, 62); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - d += (uint64_t)(a[3]*2) * a[9] - + (uint64_t)(a[4]*2) * a[8] - + (uint64_t)(a[5]*2) * a[7] - + (uint64_t)a[6] * a[6]; - VERIFY_BITS(d, 63); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - u2 = d & M; d >>= 26; c += u2 * R0; - VERIFY_BITS(u2, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - t2 = c & M; c >>= 26; c += u2 * R1; - VERIFY_BITS(t2, 26); - VERIFY_BITS(c, 38); - /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[3] - + (uint64_t)(a[1]*2) * a[2]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - d += (uint64_t)(a[4]*2) * a[9] - + (uint64_t)(a[5]*2) * a[8] - + (uint64_t)(a[6]*2) * a[7]; - VERIFY_BITS(d, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - u3 = d & M; d >>= 26; c += u3 * R0; - VERIFY_BITS(u3, 26); - VERIFY_BITS(d, 37); - /* VERIFY_BITS(c, 64); */ - /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - t3 = c & M; c >>= 26; c += u3 * R1; - VERIFY_BITS(t3, 26); - VERIFY_BITS(c, 39); - /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[4] - + (uint64_t)(a[1]*2) * a[3] - + (uint64_t)a[2] * a[2]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[5]*2) * a[9] - + (uint64_t)(a[6]*2) * a[8] - + (uint64_t)a[7] * a[7]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - u4 = d & M; d >>= 26; c += u4 * R0; - VERIFY_BITS(u4, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - t4 = c & M; c >>= 26; c += u4 * R1; - VERIFY_BITS(t4, 26); - VERIFY_BITS(c, 39); - /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[5] - + (uint64_t)(a[1]*2) * a[4] - + (uint64_t)(a[2]*2) * a[3]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[6]*2) * a[9] - + (uint64_t)(a[7]*2) * a[8]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - u5 = d & M; d >>= 26; c += u5 * R0; - VERIFY_BITS(u5, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - t5 = c & M; c >>= 26; c += u5 * R1; - VERIFY_BITS(t5, 26); - VERIFY_BITS(c, 39); - /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[6] - + (uint64_t)(a[1]*2) * a[5] - + (uint64_t)(a[2]*2) * a[4] - + (uint64_t)a[3] * a[3]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[7]*2) * a[9] - + (uint64_t)a[8] * a[8]; - VERIFY_BITS(d, 61); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - u6 = d & M; d >>= 26; c += u6 * R0; - VERIFY_BITS(u6, 26); - VERIFY_BITS(d, 35); - /* VERIFY_BITS(c, 64); */ - /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - t6 = c & M; c >>= 26; c += u6 * R1; - VERIFY_BITS(t6, 26); - VERIFY_BITS(c, 39); - /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[7] - + (uint64_t)(a[1]*2) * a[6] - + (uint64_t)(a[2]*2) * a[5] - + (uint64_t)(a[3]*2) * a[4]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x8000007C00000007ULL); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[8]*2) * a[9]; - VERIFY_BITS(d, 58); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - u7 = d & M; d >>= 26; c += u7 * R0; - VERIFY_BITS(u7, 26); - VERIFY_BITS(d, 32); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); - /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - t7 = c & M; c >>= 26; c += u7 * R1; - VERIFY_BITS(t7, 26); - VERIFY_BITS(c, 38); - /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[8] - + (uint64_t)(a[1]*2) * a[7] - + (uint64_t)(a[2]*2) * a[6] - + (uint64_t)(a[3]*2) * a[5] - + (uint64_t)a[4] * a[4]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000007B80000008ULL); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[9] * a[9]; - VERIFY_BITS(d, 57); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - u8 = d & M; d >>= 26; c += u8 * R0; - VERIFY_BITS(u8, 26); - VERIFY_BITS(d, 31); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[3] = t3; - VERIFY_BITS(r[3], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = t4; - VERIFY_BITS(r[4], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[5] = t5; - VERIFY_BITS(r[5], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[6] = t6; - VERIFY_BITS(r[6], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[7] = t7; - VERIFY_BITS(r[7], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[8] = c & M; c >>= 26; c += u8 * R1; - VERIFY_BITS(r[8], 26); - VERIFY_BITS(c, 39); - /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R0 + t9; - VERIFY_BITS(c, 45); - /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); - VERIFY_BITS(r[9], 22); - VERIFY_BITS(c, 46); - /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - d = c * (R0 >> 4) + t0; - VERIFY_BITS(d, 56); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[0] = d & M; d >>= 26; - VERIFY_BITS(r[0], 26); - VERIFY_BITS(d, 30); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += c * (R1 >> 4) + t1; - VERIFY_BITS(d, 53); - VERIFY_CHECK(d <= 0x10000003FFFFBFULL); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[1] = d & M; d >>= 26; - VERIFY_BITS(r[1], 26); - VERIFY_BITS(d, 27); - VERIFY_CHECK(d <= 0x4000000ULL); - /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += t2; - VERIFY_BITS(d, 27); - /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = d; - VERIFY_BITS(r[2], 27); - /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} -#endif - -SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { - secp256k1_fe_mul_inner(r->n, a->n, b->n); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_sqr_inner(r->n, a->n); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { - uint32_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = vflag + ~((uint32_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); - r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); - r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); - r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); - r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); - r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -} - -static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - uint32_t one = (uint32_t)1; - uint32_t mask = -(t0 & one) >> 6; - - /* Bounds analysis (over the rationals). - * - * Let m = r->magnitude - * C = 0x3FFFFFFUL * 2 - * D = 0x03FFFFFUL * 2 - * - * Initial bounds: t0..t8 <= C * m - * t9 <= D * m - */ - - t0 += 0x3FFFC2FUL & mask; - t1 += 0x3FFFFBFUL & mask; - t2 += mask; - t3 += mask; - t4 += mask; - t5 += mask; - t6 += mask; - t7 += mask; - t8 += mask; - t9 += mask >> 4; - - VERIFY_CHECK((t0 & one) == 0); - - /* t0..t8: added <= C/2 - * t9: added <= D/2 - * - * Current bounds: t0..t8 <= C * (m + 1/2) - * t9 <= D * (m + 1/2) - */ - - r->n[0] = (t0 >> 1) + ((t1 & one) << 25); - r->n[1] = (t1 >> 1) + ((t2 & one) << 25); - r->n[2] = (t2 >> 1) + ((t3 & one) << 25); - r->n[3] = (t3 >> 1) + ((t4 & one) << 25); - r->n[4] = (t4 >> 1) + ((t5 & one) << 25); - r->n[5] = (t5 >> 1) + ((t6 & one) << 25); - r->n[6] = (t6 >> 1) + ((t7 & one) << 25); - r->n[7] = (t7 >> 1) + ((t8 & one) << 25); - r->n[8] = (t8 >> 1) + ((t9 & one) << 25); - r->n[9] = (t9 >> 1); - - /* t0..t8: shifted right and added <= C/4 + 1/2 - * t9: shifted right - * - * Current bounds: t0..t8 <= C * (m/2 + 1/2) - * t9 <= D * (m/2 + 1/4) - * - * Therefore the output magnitude (M) has to be set such that: - * t0..t8: C * M >= C * (m/2 + 1/2) - * t9: D * M >= D * (m/2 + 1/4) - * - * It suffices for all limbs that, for any input magnitude m: - * M >= m/2 + 1/2 - * - * and since we want the smallest such integer value for M: - * M == floor(m/2) + 1 - */ -} - -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { - uint32_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = vflag + ~((uint32_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); - r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); - r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); - r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); -} - -static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { - r->n[0] = a->n[0] | a->n[1] << 26; - r->n[1] = a->n[1] >> 6 | a->n[2] << 20; - r->n[2] = a->n[2] >> 12 | a->n[3] << 14; - r->n[3] = a->n[3] >> 18 | a->n[4] << 8; - r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; - r->n[5] = a->n[6] >> 4 | a->n[7] << 22; - r->n[6] = a->n[7] >> 10 | a->n[8] << 16; - r->n[7] = a->n[8] >> 16 | a->n[9] << 10; -} - -static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { - r->n[0] = a->n[0] & 0x3FFFFFFUL; - r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); - r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); - r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); - r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); - r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; - r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); - r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); - r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); - r->n[9] = a->n[7] >> 10; -} - -static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) { - const uint32_t M26 = UINT32_MAX >> 6; - const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], - a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; - - /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and - * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). - */ - VERIFY_CHECK(a0 >> 30 == 0); - VERIFY_CHECK(a1 >> 30 == 0); - VERIFY_CHECK(a2 >> 30 == 0); - VERIFY_CHECK(a3 >> 30 == 0); - VERIFY_CHECK(a4 >> 30 == 0); - VERIFY_CHECK(a5 >> 30 == 0); - VERIFY_CHECK(a6 >> 30 == 0); - VERIFY_CHECK(a7 >> 30 == 0); - VERIFY_CHECK(a8 >> 16 == 0); - - r->n[0] = a0 & M26; - r->n[1] = (a0 >> 26 | a1 << 4) & M26; - r->n[2] = (a1 >> 22 | a2 << 8) & M26; - r->n[3] = (a2 >> 18 | a3 << 12) & M26; - r->n[4] = (a3 >> 14 | a4 << 16) & M26; - r->n[5] = (a4 >> 10 | a5 << 20) & M26; - r->n[6] = (a5 >> 6 | a6 << 24) & M26; - r->n[7] = (a6 >> 2 ) & M26; - r->n[8] = (a6 >> 28 | a7 << 2) & M26; - r->n[9] = (a7 >> 24 | a8 << 6); -} - -static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) { - const uint32_t M30 = UINT32_MAX >> 2; - const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], - a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; - - r->v[0] = (a0 | a1 << 26) & M30; - r->v[1] = (a1 >> 4 | a2 << 22) & M30; - r->v[2] = (a2 >> 8 | a3 << 18) & M30; - r->v[3] = (a3 >> 12 | a4 << 14) & M30; - r->v[4] = (a4 >> 16 | a5 << 10) & M30; - r->v[5] = (a5 >> 20 | a6 << 6) & M30; - r->v[6] = (a6 >> 24 | a7 << 2 - | a8 << 28) & M30; - r->v[7] = (a8 >> 2 | a9 << 24) & M30; - r->v[8] = a9 >> 6; -} - -static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = { - {{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}}, - 0x2DDACACFL -}; - -static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp = *x; - secp256k1_modinv32_signed30 s; - - secp256k1_fe_normalize(&tmp); - secp256k1_fe_to_signed30(&s, &tmp); - secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe); - secp256k1_fe_from_signed30(r, &s); -} - -static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp = *x; - secp256k1_modinv32_signed30 s; - - secp256k1_fe_normalize_var(&tmp); - secp256k1_fe_to_signed30(&s, &tmp); - secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe); - secp256k1_fe_from_signed30(r, &s); -} - -static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { - secp256k1_fe tmp; - secp256k1_modinv32_signed30 s; - int jac, ret; - - tmp = *x; - secp256k1_fe_normalize_var(&tmp); - /* secp256k1_jacobi32_maybe_var cannot deal with input 0. */ - if (secp256k1_fe_is_zero(&tmp)) return 1; - secp256k1_fe_to_signed30(&s, &tmp); - jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe); - if (jac == 0) { - /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back - * to computing a square root. This should be extremely rare with random - * input (except in VERIFY mode, where a lower iteration count is used). */ - secp256k1_fe dummy; - ret = secp256k1_fe_sqrt(&dummy, &tmp); - } else { - ret = jac >= 0; - } - return ret; -} - -#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/external/secp256k1/src/field_5x52.h b/external/secp256k1/src/field_5x52.h deleted file mode 100644 index f20c246fdd..0000000000 --- a/external/secp256k1/src/field_5x52.h +++ /dev/null @@ -1,62 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_H -#define SECP256K1_FIELD_REPR_H - -#include - -/** This field implementation represents the value as 5 uint64_t limbs in base - * 2^52. */ -typedef struct { - /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, - * where p is the field modulus, 2^256 - 2^32 - 977. - * - * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly - * corresponds to how much excess is allowed. The value - * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is - * normalized. */ - uint64_t n[5]; - /* - * Magnitude m requires: - * n[i] <= 2 * m * (2^52 - 1) for i=0..3 - * n[4] <= 2 * m * (2^48 - 1) - * - * Normalized requires: - * n[i] <= (2^52 - 1) for i=0..3 - * sum(i=0..4, n[i] << (i*52)) < p - * (together these imply n[4] <= 2^48 - 1) - */ - SECP256K1_FE_VERIFY_FIELDS -} secp256k1_fe; - -/* Unpacks a constant into a overlapping multi-limbed FE element. */ -#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ - ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ - ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ - ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ - ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ -} - -typedef struct { - uint64_t n[4]; -} secp256k1_fe_storage; - -#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ - (d0) | (((uint64_t)(d1)) << 32), \ - (d2) | (((uint64_t)(d3)) << 32), \ - (d4) | (((uint64_t)(d5)) << 32), \ - (d6) | (((uint64_t)(d7)) << 32) \ -}} - -#define SECP256K1_FE_STORAGE_CONST_GET(d) \ - (uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \ - (uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \ - (uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \ - (uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0] - -#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/external/secp256k1/src/field_5x52_impl.h b/external/secp256k1/src/field_5x52_impl.h deleted file mode 100644 index 46dca6b981..0000000000 --- a/external/secp256k1/src/field_5x52_impl.h +++ /dev/null @@ -1,522 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_IMPL_H -#define SECP256K1_FIELD_REPR_IMPL_H - -#include "checkmem.h" -#include "util.h" -#include "field.h" -#include "modinv64_impl.h" - -#include "field_5x52_int128_impl.h" - -#ifdef VERIFY -static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { - const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude; - /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); - VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); - VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); - VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); - VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); - if (a->normalized) { - if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); - } - } -} -#endif - -static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { - r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; - r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; - r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; - r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; - r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; -} - -static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t m; - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) - & (t0 >= 0xFFFFEFFFFFC2FULL)); - - /* Apply the final reduction (for constant-time behaviour, we do it always) */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ - VERIFY_CHECK(t4 >> 48 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t4 &= 0x0FFFFFFFFFFFFULL; - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; -} - -static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; -} - -static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t m; - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) - & (t0 >= 0xFFFFEFFFFFC2FULL)); - - if (x) { - t0 += 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ - VERIFY_CHECK(t4 >> 48 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t4 &= 0x0FFFFFFFFFFFFULL; - } - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; -} - -static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - uint64_t z0, z1; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; - z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); -} - -static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { - uint64_t t0, t1, t2, t3, t4; - uint64_t z0, z1; - uint64_t x; - - t0 = r->n[0]; - t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - x = t4 >> 48; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - z0 = t0 & 0xFFFFFFFFFFFFFULL; - z1 = z0 ^ 0x1000003D0ULL; - - /* Fast return path should catch the majority of cases */ - if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { - return 0; - } - - t1 = r->n[1]; - t2 = r->n[2]; - t3 = r->n[3]; - - t4 &= 0x0FFFFFFFFFFFFULL; - - t1 += (t0 >> 52); - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; - z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { - r->n[0] = a; - r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -} - -SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { - const uint64_t *t = a->n; - return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; -} - -SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { - return a->n[0] & 1; -} - -static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - int i; - for (i = 4; i >= 0; i--) { - if (a->n[i] > b->n[i]) { - return 1; - } - if (a->n[i] < b->n[i]) { - return -1; - } - } - return 0; -} - -static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { - r->n[0] = (uint64_t)a[31] - | ((uint64_t)a[30] << 8) - | ((uint64_t)a[29] << 16) - | ((uint64_t)a[28] << 24) - | ((uint64_t)a[27] << 32) - | ((uint64_t)a[26] << 40) - | ((uint64_t)(a[25] & 0xF) << 48); - r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) - | ((uint64_t)a[24] << 4) - | ((uint64_t)a[23] << 12) - | ((uint64_t)a[22] << 20) - | ((uint64_t)a[21] << 28) - | ((uint64_t)a[20] << 36) - | ((uint64_t)a[19] << 44); - r->n[2] = (uint64_t)a[18] - | ((uint64_t)a[17] << 8) - | ((uint64_t)a[16] << 16) - | ((uint64_t)a[15] << 24) - | ((uint64_t)a[14] << 32) - | ((uint64_t)a[13] << 40) - | ((uint64_t)(a[12] & 0xF) << 48); - r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) - | ((uint64_t)a[11] << 4) - | ((uint64_t)a[10] << 12) - | ((uint64_t)a[9] << 20) - | ((uint64_t)a[8] << 28) - | ((uint64_t)a[7] << 36) - | ((uint64_t)a[6] << 44); - r->n[4] = (uint64_t)a[5] - | ((uint64_t)a[4] << 8) - | ((uint64_t)a[3] << 16) - | ((uint64_t)a[2] << 24) - | ((uint64_t)a[1] << 32) - | ((uint64_t)a[0] << 40); -} - -static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { - secp256k1_fe_impl_set_b32_mod(r, a); - return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { - r[0] = (a->n[4] >> 40) & 0xFF; - r[1] = (a->n[4] >> 32) & 0xFF; - r[2] = (a->n[4] >> 24) & 0xFF; - r[3] = (a->n[4] >> 16) & 0xFF; - r[4] = (a->n[4] >> 8) & 0xFF; - r[5] = a->n[4] & 0xFF; - r[6] = (a->n[3] >> 44) & 0xFF; - r[7] = (a->n[3] >> 36) & 0xFF; - r[8] = (a->n[3] >> 28) & 0xFF; - r[9] = (a->n[3] >> 20) & 0xFF; - r[10] = (a->n[3] >> 12) & 0xFF; - r[11] = (a->n[3] >> 4) & 0xFF; - r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); - r[13] = (a->n[2] >> 40) & 0xFF; - r[14] = (a->n[2] >> 32) & 0xFF; - r[15] = (a->n[2] >> 24) & 0xFF; - r[16] = (a->n[2] >> 16) & 0xFF; - r[17] = (a->n[2] >> 8) & 0xFF; - r[18] = a->n[2] & 0xFF; - r[19] = (a->n[1] >> 44) & 0xFF; - r[20] = (a->n[1] >> 36) & 0xFF; - r[21] = (a->n[1] >> 28) & 0xFF; - r[22] = (a->n[1] >> 20) & 0xFF; - r[23] = (a->n[1] >> 12) & 0xFF; - r[24] = (a->n[1] >> 4) & 0xFF; - r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); - r[26] = (a->n[0] >> 40) & 0xFF; - r[27] = (a->n[0] >> 32) & 0xFF; - r[28] = (a->n[0] >> 24) & 0xFF; - r[29] = (a->n[0] >> 16) & 0xFF; - r[30] = (a->n[0] >> 8) & 0xFF; - r[31] = a->n[0] & 0xFF; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { - /* For all legal values of m (0..31), the following properties hold: */ - VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); - VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); - VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); - - /* Due to the properties above, the left hand in the subtractions below is never less than - * the right hand. */ - r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; - r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; - r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; - r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; - r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { - r->n[0] *= a; - r->n[1] *= a; - r->n[2] *= a; - r->n[3] *= a; - r->n[4] *= a; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { - r->n[0] += a; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { - r->n[0] += a->n[0]; - r->n[1] += a->n[1]; - r->n[2] += a->n[2]; - r->n[3] += a->n[3]; - r->n[4] += a->n[4]; -} - -SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { - secp256k1_fe_mul_inner(r->n, a->n, b->n); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_sqr_inner(r->n, a->n); -} - -SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { - uint64_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = vflag + ~((uint64_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -} - -static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - uint64_t one = (uint64_t)1; - uint64_t mask = -(t0 & one) >> 12; - - /* Bounds analysis (over the rationals). - * - * Let m = r->magnitude - * C = 0xFFFFFFFFFFFFFULL * 2 - * D = 0x0FFFFFFFFFFFFULL * 2 - * - * Initial bounds: t0..t3 <= C * m - * t4 <= D * m - */ - - t0 += 0xFFFFEFFFFFC2FULL & mask; - t1 += mask; - t2 += mask; - t3 += mask; - t4 += mask >> 4; - - VERIFY_CHECK((t0 & one) == 0); - - /* t0..t3: added <= C/2 - * t4: added <= D/2 - * - * Current bounds: t0..t3 <= C * (m + 1/2) - * t4 <= D * (m + 1/2) - */ - - r->n[0] = (t0 >> 1) + ((t1 & one) << 51); - r->n[1] = (t1 >> 1) + ((t2 & one) << 51); - r->n[2] = (t2 >> 1) + ((t3 & one) << 51); - r->n[3] = (t3 >> 1) + ((t4 & one) << 51); - r->n[4] = (t4 >> 1); - - /* t0..t3: shifted right and added <= C/4 + 1/2 - * t4: shifted right - * - * Current bounds: t0..t3 <= C * (m/2 + 1/2) - * t4 <= D * (m/2 + 1/4) - * - * Therefore the output magnitude (M) has to be set such that: - * t0..t3: C * M >= C * (m/2 + 1/2) - * t4: D * M >= D * (m/2 + 1/4) - * - * It suffices for all limbs that, for any input magnitude m: - * M >= m/2 + 1/2 - * - * and since we want the smallest such integer value for M: - * M == floor(m/2) + 1 - */ -} - -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { - uint64_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = vflag + ~((uint64_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); -} - -static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { - r->n[0] = a->n[0] | a->n[1] << 52; - r->n[1] = a->n[1] >> 12 | a->n[2] << 40; - r->n[2] = a->n[2] >> 24 | a->n[3] << 28; - r->n[3] = a->n[3] >> 36 | a->n[4] << 16; -} - -static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { - r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; - r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); - r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); - r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); - r->n[4] = a->n[3] >> 16; -} - -static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) { - const uint64_t M52 = UINT64_MAX >> 12; - const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; - - /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and - * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). - */ - VERIFY_CHECK(a0 >> 62 == 0); - VERIFY_CHECK(a1 >> 62 == 0); - VERIFY_CHECK(a2 >> 62 == 0); - VERIFY_CHECK(a3 >> 62 == 0); - VERIFY_CHECK(a4 >> 8 == 0); - - r->n[0] = a0 & M52; - r->n[1] = (a0 >> 52 | a1 << 10) & M52; - r->n[2] = (a1 >> 42 | a2 << 20) & M52; - r->n[3] = (a2 >> 32 | a3 << 30) & M52; - r->n[4] = (a3 >> 22 | a4 << 40); -} - -static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) { - const uint64_t M62 = UINT64_MAX >> 2; - const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; - - r->v[0] = (a0 | a1 << 52) & M62; - r->v[1] = (a1 >> 10 | a2 << 42) & M62; - r->v[2] = (a2 >> 20 | a3 << 32) & M62; - r->v[3] = (a3 >> 30 | a4 << 22) & M62; - r->v[4] = a4 >> 40; -} - -static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = { - {{-0x1000003D1LL, 0, 0, 0, 256}}, - 0x27C7F6E22DDACACFLL -}; - -static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp = *x; - secp256k1_modinv64_signed62 s; - - secp256k1_fe_normalize(&tmp); - secp256k1_fe_to_signed62(&s, &tmp); - secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe); - secp256k1_fe_from_signed62(r, &s); -} - -static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp = *x; - secp256k1_modinv64_signed62 s; - - secp256k1_fe_normalize_var(&tmp); - secp256k1_fe_to_signed62(&s, &tmp); - secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe); - secp256k1_fe_from_signed62(r, &s); -} - -static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { - secp256k1_fe tmp; - secp256k1_modinv64_signed62 s; - int jac, ret; - - tmp = *x; - secp256k1_fe_normalize_var(&tmp); - /* secp256k1_jacobi64_maybe_var cannot deal with input 0. */ - if (secp256k1_fe_is_zero(&tmp)) return 1; - secp256k1_fe_to_signed62(&s, &tmp); - jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe); - if (jac == 0) { - /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back - * to computing a square root. This should be extremely rare with random - * input (except in VERIFY mode, where a lower iteration count is used). */ - secp256k1_fe dummy; - ret = secp256k1_fe_sqrt(&dummy, &tmp); - } else { - ret = jac >= 0; - } - return ret; -} - -#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/external/secp256k1/src/field_5x52_int128_impl.h b/external/secp256k1/src/field_5x52_int128_impl.h deleted file mode 100644 index f23f8ee1c4..0000000000 --- a/external/secp256k1/src/field_5x52_int128_impl.h +++ /dev/null @@ -1,274 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -#include - -#include "int128.h" -#include "util.h" - -#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { - secp256k1_uint128 c, d; - uint64_t t3, t4, tx, u0; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - VERIFY_BITS(b[0], 56); - VERIFY_BITS(b[1], 56); - VERIFY_BITS(b[2], 56); - VERIFY_BITS(b[3], 56); - VERIFY_BITS(b[4], 52); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); - - /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). - * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - secp256k1_u128_mul(&d, a0, b[3]); - secp256k1_u128_accum_mul(&d, a1, b[2]); - secp256k1_u128_accum_mul(&d, a2, b[1]); - secp256k1_u128_accum_mul(&d, a3, b[0]); - VERIFY_BITS_128(&d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - secp256k1_u128_mul(&c, a4, b[4]); - VERIFY_BITS_128(&c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); - VERIFY_BITS_128(&d, 115); - VERIFY_BITS_128(&c, 48); - /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(t3, 52); - VERIFY_BITS_128(&d, 63); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - secp256k1_u128_accum_mul(&d, a0, b[4]); - secp256k1_u128_accum_mul(&d, a1, b[3]); - secp256k1_u128_accum_mul(&d, a2, b[2]); - secp256k1_u128_accum_mul(&d, a3, b[1]); - secp256k1_u128_accum_mul(&d, a4, b[0]); - VERIFY_BITS_128(&d, 115); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); - VERIFY_BITS_128(&d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(t4, 52); - VERIFY_BITS_128(&d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - secp256k1_u128_mul(&c, a0, b[0]); - VERIFY_BITS_128(&c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - secp256k1_u128_accum_mul(&d, a1, b[4]); - secp256k1_u128_accum_mul(&d, a2, b[3]); - secp256k1_u128_accum_mul(&d, a3, b[2]); - secp256k1_u128_accum_mul(&d, a4, b[1]); - VERIFY_BITS_128(&d, 114); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(u0, 52); - VERIFY_BITS_128(&d, 62); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - secp256k1_u128_accum_mul(&c, u0, R >> 4); - VERIFY_BITS_128(&c, 113); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[0], 52); - VERIFY_BITS_128(&c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - secp256k1_u128_accum_mul(&c, a0, b[1]); - secp256k1_u128_accum_mul(&c, a1, b[0]); - VERIFY_BITS_128(&c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - secp256k1_u128_accum_mul(&d, a2, b[4]); - secp256k1_u128_accum_mul(&d, a3, b[3]); - secp256k1_u128_accum_mul(&d, a4, b[2]); - VERIFY_BITS_128(&d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); - VERIFY_BITS_128(&c, 115); - VERIFY_BITS_128(&d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[1], 52); - VERIFY_BITS_128(&c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - secp256k1_u128_accum_mul(&c, a0, b[2]); - secp256k1_u128_accum_mul(&c, a1, b[1]); - secp256k1_u128_accum_mul(&c, a2, b[0]); - VERIFY_BITS_128(&c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - secp256k1_u128_accum_mul(&d, a3, b[4]); - secp256k1_u128_accum_mul(&d, a4, b[3]); - VERIFY_BITS_128(&d, 114); - /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); - VERIFY_BITS_128(&c, 115); - VERIFY_BITS_128(&d, 50); - /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[2], 52); - VERIFY_BITS_128(&c, 63); - /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); - secp256k1_u128_accum_u64(&c, t3); - VERIFY_BITS_128(&c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[3], 52); - VERIFY_BITS_128(&c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = secp256k1_u128_to_u64(&c) + t4; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { - secp256k1_uint128 c, d; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - uint64_t t3, t4, tx, u0; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - - /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * px is a shorthand for sum(a[i]*a[x-i], i=0..x). - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - secp256k1_u128_mul(&d, a0*2, a3); - secp256k1_u128_accum_mul(&d, a1*2, a2); - VERIFY_BITS_128(&d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - secp256k1_u128_mul(&c, a4, a4); - VERIFY_BITS_128(&c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); - VERIFY_BITS_128(&d, 115); - VERIFY_BITS_128(&c, 48); - /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(t3, 52); - VERIFY_BITS_128(&d, 63); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - a4 *= 2; - secp256k1_u128_accum_mul(&d, a0, a4); - secp256k1_u128_accum_mul(&d, a1*2, a3); - secp256k1_u128_accum_mul(&d, a2, a2); - VERIFY_BITS_128(&d, 115); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); - VERIFY_BITS_128(&d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(t4, 52); - VERIFY_BITS_128(&d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - secp256k1_u128_mul(&c, a0, a0); - VERIFY_BITS_128(&c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - secp256k1_u128_accum_mul(&d, a1, a4); - secp256k1_u128_accum_mul(&d, a2*2, a3); - VERIFY_BITS_128(&d, 114); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); - VERIFY_BITS(u0, 52); - VERIFY_BITS_128(&d, 62); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - secp256k1_u128_accum_mul(&c, u0, R >> 4); - VERIFY_BITS_128(&c, 113); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[0], 52); - VERIFY_BITS_128(&c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - a0 *= 2; - secp256k1_u128_accum_mul(&c, a0, a1); - VERIFY_BITS_128(&c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - secp256k1_u128_accum_mul(&d, a2, a4); - secp256k1_u128_accum_mul(&d, a3, a3); - VERIFY_BITS_128(&d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); - VERIFY_BITS_128(&c, 115); - VERIFY_BITS_128(&d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[1], 52); - VERIFY_BITS_128(&c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - secp256k1_u128_accum_mul(&c, a0, a2); - secp256k1_u128_accum_mul(&c, a1, a1); - VERIFY_BITS_128(&c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - secp256k1_u128_accum_mul(&d, a3, a4); - VERIFY_BITS_128(&d, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); - VERIFY_BITS_128(&c, 115); - VERIFY_BITS_128(&d, 50); - /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[2], 52); - VERIFY_BITS_128(&c, 63); - /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); - secp256k1_u128_accum_u64(&c, t3); - VERIFY_BITS_128(&c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); - VERIFY_BITS(r[3], 52); - VERIFY_BITS_128(&c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = secp256k1_u128_to_u64(&c) + t4; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/external/secp256k1/src/field_impl.h b/external/secp256k1/src/field_impl.h deleted file mode 100644 index 896507a3a4..0000000000 --- a/external/secp256k1/src/field_impl.h +++ /dev/null @@ -1,457 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_IMPL_H -#define SECP256K1_FIELD_IMPL_H - -#include "field.h" -#include "util.h" - -#if defined(SECP256K1_WIDEMUL_INT128) -#include "field_5x52_impl.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "field_10x26_impl.h" -#else -#error "Please select wide multiplication implementation" -#endif - -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { - secp256k1_memclear(a, sizeof(secp256k1_fe)); -} - -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe na; - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY(b); - SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); - SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); - - secp256k1_fe_negate(&na, a, 1); - secp256k1_fe_add(&na, b); - return secp256k1_fe_normalizes_to_zero(&na); -} - -static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) { - /** Given that p is congruent to 3 mod 4, we can compute the square root of - * a mod p as the (p+1)/4'th power of a. - * - * As (p+1)/4 is an even number, it will have the same result for a and for - * (-a). Only one of these two numbers actually has a square root however, - * so we test at the end by squaring and comparing to the input. - * Also because (p+1)/4 is an even number, the computed square root is - * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). - */ - secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j, ret; - - VERIFY_CHECK(r != a); - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); - - /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in - * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - */ - - secp256k1_fe_sqr(&x2, a); - secp256k1_fe_mul(&x2, &x2, a); - - secp256k1_fe_sqr(&x3, &x2); - secp256k1_fe_mul(&x3, &x3, a); - - x6 = x3; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x6, &x6); - } - secp256k1_fe_mul(&x6, &x6, &x3); - - x9 = x6; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x9, &x9); - } - secp256k1_fe_mul(&x9, &x9, &x3); - - x11 = x9; - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&x11, &x11); - } - secp256k1_fe_mul(&x11, &x11, &x2); - - x22 = x11; - for (j=0; j<11; j++) { - secp256k1_fe_sqr(&x22, &x22); - } - secp256k1_fe_mul(&x22, &x22, &x11); - - x44 = x22; - for (j=0; j<22; j++) { - secp256k1_fe_sqr(&x44, &x44); - } - secp256k1_fe_mul(&x44, &x44, &x22); - - x88 = x44; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x88, &x88); - } - secp256k1_fe_mul(&x88, &x88, &x44); - - x176 = x88; - for (j=0; j<88; j++) { - secp256k1_fe_sqr(&x176, &x176); - } - secp256k1_fe_mul(&x176, &x176, &x88); - - x220 = x176; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x220, &x220); - } - secp256k1_fe_mul(&x220, &x220, &x44); - - x223 = x220; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x223, &x223); - } - secp256k1_fe_mul(&x223, &x223, &x3); - - /* The final result is then assembled using a sliding window over the blocks. */ - - t1 = x223; - for (j=0; j<23; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<6; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x2); - secp256k1_fe_sqr(&t1, &t1); - secp256k1_fe_sqr(r, &t1); - - /* Check that a square root was actually calculated */ - - secp256k1_fe_sqr(&t1, r); - ret = secp256k1_fe_equal(&t1, a); - -#ifdef VERIFY - if (!ret) { - secp256k1_fe_negate(&t1, &t1, 1); - secp256k1_fe_normalize_var(&t1); - VERIFY_CHECK(secp256k1_fe_equal(&t1, a)); - } -#endif - return ret; -} - -#ifndef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } -static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; } -#else -static void secp256k1_fe_impl_verify(const secp256k1_fe *a); -static void secp256k1_fe_verify(const secp256k1_fe *a) { - /* Magnitude between 0 and 32. */ - SECP256K1_FE_VERIFY_MAGNITUDE(a, 32); - /* Normalized is 0 or 1. */ - VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); - /* If normalized, magnitude must be 0 or 1. */ - if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); - /* Invoke implementation-specific checks. */ - secp256k1_fe_impl_verify(a); -} - -static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 32); - VERIFY_CHECK(a->magnitude <= m); -} - -static void secp256k1_fe_impl_normalize(secp256k1_fe *r); -SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - - secp256k1_fe_impl_normalize(r); - r->magnitude = 1; - r->normalized = 1; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); -SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - - secp256k1_fe_impl_normalize_weak(r); - r->magnitude = 1; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); -SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - - secp256k1_fe_impl_normalize_var(r); - r->magnitude = 1; - r->normalized = 1; - - SECP256K1_FE_VERIFY(r); -} - -static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); -SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - - return secp256k1_fe_impl_normalizes_to_zero(r); -} - -static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); -SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - - return secp256k1_fe_impl_normalizes_to_zero_var(r); -} - -static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); - - secp256k1_fe_impl_set_int(r, a); - r->magnitude = (a != 0); - r->normalized = 1; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); -SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); - SECP256K1_FE_VERIFY(r); - - secp256k1_fe_impl_add_int(r, a); - r->magnitude += 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(a->normalized); - - return secp256k1_fe_impl_is_zero(a); -} - -static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(a->normalized); - - return secp256k1_fe_impl_is_odd(a); -} - -static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY(b); - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - - return secp256k1_fe_impl_cmp_var(a, b); -} - -static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a); -SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { - secp256k1_fe_impl_set_b32_mod(r, a); - r->magnitude = 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a); -SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { - if (secp256k1_fe_impl_set_b32_limit(r, a)) { - r->magnitude = 1; - r->normalized = 1; - SECP256K1_FE_VERIFY(r); - return 1; - } else { - /* Mark the output field element as invalid. */ - r->magnitude = -1; - return 0; - } -} - -static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); -SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(a->normalized); - - secp256k1_fe_impl_get_b32(r, a); -} - -static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); -SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(m >= 0 && m <= 31); - SECP256K1_FE_VERIFY_MAGNITUDE(a, m); - - secp256k1_fe_impl_negate_unchecked(r, a, m); - r->magnitude = m + 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a); -SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) { - SECP256K1_FE_VERIFY(r); - - VERIFY_CHECK(a >= 0 && a <= 32); - VERIFY_CHECK(a*r->magnitude <= 32); - secp256k1_fe_impl_mul_int_unchecked(r, a); - r->magnitude *= a; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(r); - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(r->magnitude + a->magnitude <= 32); - - secp256k1_fe_impl_add(r, a); - r->magnitude += a->magnitude; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); -SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY(b); - SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); - SECP256K1_FE_VERIFY_MAGNITUDE(b, 8); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); - - secp256k1_fe_impl_mul(r, a, b); - r->magnitude = 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); -SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); - - secp256k1_fe_impl_sqr(r, a); - r->magnitude = 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { - VERIFY_CHECK(flag == 0 || flag == 1); - SECP256K1_FE_VERIFY(a); - SECP256K1_FE_VERIFY(r); - - secp256k1_fe_impl_cmov(r, a, flag); - if (a->magnitude > r->magnitude) r->magnitude = a->magnitude; - if (!a->normalized) r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); -SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { - SECP256K1_FE_VERIFY(a); - VERIFY_CHECK(a->normalized); - - secp256k1_fe_impl_to_storage(r, a); -} - -static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); -SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { - secp256k1_fe_impl_from_storage(r, a); - r->magnitude = 1; - r->normalized = 1; - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); -SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { - int input_is_zero = secp256k1_fe_normalizes_to_zero(x); - SECP256K1_FE_VERIFY(x); - - secp256k1_fe_impl_inv(r, x); - r->magnitude = x->magnitude > 0; - r->normalized = 1; - - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); -SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - int input_is_zero = secp256k1_fe_normalizes_to_zero(x); - SECP256K1_FE_VERIFY(x); - - secp256k1_fe_impl_inv_var(r, x); - r->magnitude = x->magnitude > 0; - r->normalized = 1; - - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); - SECP256K1_FE_VERIFY(r); -} - -static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); -SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { - int ret; - secp256k1_fe tmp = *x, sqrt; - SECP256K1_FE_VERIFY(x); - - ret = secp256k1_fe_impl_is_square_var(x); - secp256k1_fe_normalize_weak(&tmp); - VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); - return ret; -} - -static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); -SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 32); - - secp256k1_fe_impl_get_bounds(r, m); - r->magnitude = m; - r->normalized = (m == 0); - - SECP256K1_FE_VERIFY(r); -} - -static void secp256k1_fe_impl_half(secp256k1_fe *r); -SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { - SECP256K1_FE_VERIFY(r); - SECP256K1_FE_VERIFY_MAGNITUDE(r, 31); - - secp256k1_fe_impl_half(r); - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - - SECP256K1_FE_VERIFY(r); -} - -#endif /* defined(VERIFY) */ - -#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/external/secp256k1/src/group.h b/external/secp256k1/src/group.h deleted file mode 100644 index 992ff5c98c..0000000000 --- a/external/secp256k1/src/group.h +++ /dev/null @@ -1,212 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_GROUP_H -#define SECP256K1_GROUP_H - -#include "field.h" - -/** A group element in affine coordinates on the secp256k1 curve, - * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6. - * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve. - */ -typedef struct { - secp256k1_fe x; - secp256k1_fe y; - int infinity; /* whether this represents the point at infinity */ -} secp256k1_ge; - -#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} -#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -/** A group element of the secp256k1 curve, in jacobian coordinates. - * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve. - */ -typedef struct { - secp256k1_fe x; /* actual X: x/z^2 */ - secp256k1_fe y; /* actual Y: y/z^3 */ - secp256k1_fe z; - int infinity; /* whether this represents the point at infinity */ -} secp256k1_gej; - -#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} -#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -typedef struct { - secp256k1_fe_storage x; - secp256k1_fe_storage y; -} secp256k1_ge_storage; - -#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} - -#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) - -/** Maximum allowed magnitudes for group element coordinates - * in affine (x, y) and jacobian (x, y, z) representation. */ -#define SECP256K1_GE_X_MAGNITUDE_MAX 4 -#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 -#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 -#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 -#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 - -/** Set a group element equal to the point with given X and Y coordinates */ -static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); - -/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness - * for Y. Return value indicates whether the result is valid. */ -static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); - -/** Determine whether x is a valid X coordinate on the curve. */ -static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x); - -/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */ -static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd); - -/** Check whether a group element is the point at infinity. */ -static int secp256k1_ge_is_infinity(const secp256k1_ge *a); - -/** Check whether a group element is valid (i.e., on the curve). */ -static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); - -/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); - -/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */ -static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); - -/** Set a group element equal to another which is given in jacobian coordinates. */ -static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a); - -/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len); - -/** Bring a batch of inputs to the same global z "denominator", based on ratios between - * (omitted) z coordinates of adjacent elements. - * - * Although the elements a[i] are _ge rather than _gej, they actually represent elements - * in Jacobian coordinates with their z coordinates omitted. - * - * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of - * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len. - * The zr[0] value is unused. - * - * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]). - * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the - * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is - * implicit. - * - * The coordinates of the final element a[len-1] are not changed. - */ -static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr); - -/** Check two group elements (affine) for equality in variable time. */ -static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b); - -/** Set a group element (affine) equal to the point at infinity. */ -static void secp256k1_ge_set_infinity(secp256k1_ge *r); - -/** Set a group element (jacobian) equal to the point at infinity. */ -static void secp256k1_gej_set_infinity(secp256k1_gej *r); - -/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); - -/** Check two group elements (jacobian) for equality in variable time. */ -static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b); - -/** Check two group elements (jacobian and affine) for equality in variable time. */ -static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b); - -/** Compare the X coordinate of a group element (jacobian). - * The magnitude of the group element's X coordinate must not exceed 31. */ -static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); - -/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); - -/** Check whether a group element is the point at infinity. */ -static int secp256k1_gej_is_infinity(const secp256k1_gej *a); - -/** Set r equal to the double of a. Constant time. */ -static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a); - -/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */ -static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ -static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); - -/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient - than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ -static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ -static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); - -/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); - -/** Clear a secp256k1_gej to prevent leaking sensitive information. */ -static void secp256k1_gej_clear(secp256k1_gej *r); - -/** Clear a secp256k1_ge to prevent leaking sensitive information. */ -static void secp256k1_ge_clear(secp256k1_ge *r); - -/** Convert a group element to the storage type. */ -static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); - -/** Convert a group element back from the storage type. */ -static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); - -/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ -static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); - -/** Convert a group element that is not infinity to a 64-byte array. The output - * array is platform-dependent. */ -static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a); - -/** Convert a 64-byte array into group element. This function assumes that the - * provided buffer correctly encodes a group element. */ -static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); - -/** Convert a group element (that is allowed to be infinity) to a 64-byte - * array. The output array is platform-dependent. */ -static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge); - -/** Convert a 64-byte array into a group element. This function assumes that the - * provided buffer is the output of secp256k1_ge_to_bytes_ext. */ -static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data); - -/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. - * - * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the - * group, and this function returns always true. - * - * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a - * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this - * function checks whether a point that is on the curve is in fact also in that subgroup. - */ -static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); - -/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ -static void secp256k1_ge_verify(const secp256k1_ge *a); -#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a) - -/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ -static void secp256k1_gej_verify(const secp256k1_gej *a); -#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a) - -#endif /* SECP256K1_GROUP_H */ diff --git a/external/secp256k1/src/group_impl.h b/external/secp256k1/src/group_impl.h deleted file mode 100644 index c668fb2401..0000000000 --- a/external/secp256k1/src/group_impl.h +++ /dev/null @@ -1,974 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_GROUP_IMPL_H -#define SECP256K1_GROUP_IMPL_H - -#include - -#include "field.h" -#include "group.h" -#include "util.h" - -/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ -#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ - 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\ - 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\ - 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\ - 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\ -) -#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ - 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\ - 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\ - 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\ - 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\ -) -#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ - 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\ - 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\ - 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\ - 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\ -) -/** Generator for secp256k1, value 'g' defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - */ -#define SECP256K1_G SECP256K1_GE_CONST(\ - 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\ - 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\ - 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\ - 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\ -) -/* These exhaustive group test orders and generators are chosen such that: - * - The field size is equal to that of secp256k1, so field code is the same. - * - The curve equation is of the form y^2=x^3+B for some small constant B. - * - The subgroup has a generator 2*P, where P.x is as small as possible. - * - The subgroup has size less than 1000 to permit exhaustive testing. - * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). - */ -#if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 7 - -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7; -#define SECP256K1_B 6 - -# elif EXHAUSTIVE_TEST_ORDER == 13 - -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; -#define SECP256K1_B 2 - -# elif EXHAUSTIVE_TEST_ORDER == 199 - -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199; -#define SECP256K1_B 4 - -# else -# error No known generator for the specified exhaustive test group order. -# endif -#else - -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; -#define SECP256K1_B 7 - -#endif -/* End of section generated by sage/gen_exhaustive_groups.sage. */ - -static void secp256k1_ge_verify(const secp256k1_ge *a) { - SECP256K1_FE_VERIFY(&a->x); - SECP256K1_FE_VERIFY(&a->y); - SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX); - SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - (void)a; -} - -static void secp256k1_gej_verify(const secp256k1_gej *a) { - SECP256K1_FE_VERIFY(&a->x); - SECP256K1_FE_VERIFY(&a->y); - SECP256K1_FE_VERIFY(&a->z); - SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); - SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); - SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - (void)a; -} - -/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ -static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { - secp256k1_fe zi2; - secp256k1_fe zi3; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_FE_VERIFY(zi); - VERIFY_CHECK(!a->infinity); - - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r->x, &a->x, &zi2); - secp256k1_fe_mul(&r->y, &a->y, &zi3); - r->infinity = a->infinity; - - SECP256K1_GE_VERIFY(r); -} - -/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ -static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) { - secp256k1_fe zi2; - secp256k1_fe zi3; - SECP256K1_GE_VERIFY(a); - SECP256K1_FE_VERIFY(zi); - VERIFY_CHECK(!a->infinity); - - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r->x, &a->x, &zi2); - secp256k1_fe_mul(&r->y, &a->y, &zi3); - r->infinity = a->infinity; - - SECP256K1_GE_VERIFY(r); -} - -static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { - SECP256K1_FE_VERIFY(x); - SECP256K1_FE_VERIFY(y); - - r->infinity = 0; - r->x = *x; - r->y = *y; - - SECP256K1_GE_VERIFY(r); -} - -static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { - SECP256K1_GE_VERIFY(a); - - return a->infinity; -} - -static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { - SECP256K1_GE_VERIFY(a); - - *r = *a; - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_negate(&r->y, &r->y, 1); - - SECP256K1_GE_VERIFY(r); -} - -static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { - secp256k1_fe z2, z3; - SECP256K1_GEJ_VERIFY(a); - - r->infinity = a->infinity; - secp256k1_fe_inv(&a->z, &a->z); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_mul(&z3, &a->z, &z2); - secp256k1_fe_mul(&a->x, &a->x, &z2); - secp256k1_fe_mul(&a->y, &a->y, &z3); - secp256k1_fe_set_int(&a->z, 1); - r->x = a->x; - r->y = a->y; - - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(r); -} - -static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { - secp256k1_fe z2, z3; - SECP256K1_GEJ_VERIFY(a); - - if (secp256k1_gej_is_infinity(a)) { - secp256k1_ge_set_infinity(r); - return; - } - r->infinity = 0; - secp256k1_fe_inv_var(&a->z, &a->z); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_mul(&z3, &a->z, &z2); - secp256k1_fe_mul(&a->x, &a->x, &z2); - secp256k1_fe_mul(&a->y, &a->y, &z3); - secp256k1_fe_set_int(&a->z, 1); - secp256k1_ge_set_xy(r, &a->x, &a->y); - - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(r); -} - -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { - secp256k1_fe u; - size_t i; - size_t last_i = SIZE_MAX; -#ifdef VERIFY - for (i = 0; i < len; i++) { - SECP256K1_GEJ_VERIFY(&a[i]); - } -#endif - - for (i = 0; i < len; i++) { - if (a[i].infinity) { - secp256k1_ge_set_infinity(&r[i]); - } else { - /* Use destination's x coordinates as scratch space */ - if (last_i == SIZE_MAX) { - r[i].x = a[i].z; - } else { - secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); - } - last_i = i; - } - } - if (last_i == SIZE_MAX) { - return; - } - secp256k1_fe_inv_var(&u, &r[last_i].x); - - i = last_i; - while (i > 0) { - i--; - if (!a[i].infinity) { - secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u); - secp256k1_fe_mul(&u, &u, &a[last_i].z); - last_i = i; - } - } - VERIFY_CHECK(!a[last_i].infinity); - r[last_i].x = u; - - for (i = 0; i < len; i++) { - if (!a[i].infinity) { - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); - } - } - -#ifdef VERIFY - for (i = 0; i < len; i++) { - SECP256K1_GE_VERIFY(&r[i]); - } -#endif -} - -static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) { - size_t i; - secp256k1_fe zs; -#ifdef VERIFY - for (i = 0; i < len; i++) { - SECP256K1_GE_VERIFY(&a[i]); - SECP256K1_FE_VERIFY(&zr[i]); - } -#endif - - if (len > 0) { - i = len - 1; - /* Ensure all y values are in weak normal form for fast negation of points */ - secp256k1_fe_normalize_weak(&a[i].y); - zs = zr[i]; - - /* Work our way backwards, using the z-ratios to scale the x/y values. */ - while (i > 0) { - if (i != len - 1) { - secp256k1_fe_mul(&zs, &zs, &zr[i]); - } - i--; - secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs); - } - } - -#ifdef VERIFY - for (i = 0; i < len; i++) { - SECP256K1_GE_VERIFY(&a[i]); - } -#endif -} - -static void secp256k1_gej_set_infinity(secp256k1_gej *r) { - r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - secp256k1_fe_set_int(&r->z, 0); - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_ge_set_infinity(secp256k1_ge *r) { - r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - - SECP256K1_GE_VERIFY(r); -} - -static void secp256k1_gej_clear(secp256k1_gej *r) { - secp256k1_memclear(r, sizeof(secp256k1_gej)); -} - -static void secp256k1_ge_clear(secp256k1_ge *r) { - secp256k1_memclear(r, sizeof(secp256k1_ge)); -} - -static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { - secp256k1_fe x2, x3; - int ret; - SECP256K1_FE_VERIFY(x); - - r->x = *x; - secp256k1_fe_sqr(&x2, x); - secp256k1_fe_mul(&x3, x, &x2); - r->infinity = 0; - secp256k1_fe_add_int(&x3, SECP256K1_B); - ret = secp256k1_fe_sqrt(&r->y, &x3); - secp256k1_fe_normalize_var(&r->y); - if (secp256k1_fe_is_odd(&r->y) != odd) { - secp256k1_fe_negate(&r->y, &r->y, 1); - } - - SECP256K1_GE_VERIFY(r); - return ret; -} - -static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { - SECP256K1_GE_VERIFY(a); - - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - secp256k1_fe_set_int(&r->z, 1); - - SECP256K1_GEJ_VERIFY(r); -} - -static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { - secp256k1_gej tmp; - SECP256K1_GEJ_VERIFY(b); - SECP256K1_GEJ_VERIFY(a); - - secp256k1_gej_neg(&tmp, a); - secp256k1_gej_add_var(&tmp, &tmp, b, NULL); - return secp256k1_gej_is_infinity(&tmp); -} - -static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) { - secp256k1_gej tmp; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(b); - - secp256k1_gej_neg(&tmp, a); - secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL); - return secp256k1_gej_is_infinity(&tmp); -} - -static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) { - secp256k1_fe tmp; - SECP256K1_GE_VERIFY(a); - SECP256K1_GE_VERIFY(b); - - if (a->infinity != b->infinity) return 0; - if (a->infinity) return 1; - - tmp = a->x; - secp256k1_fe_normalize_weak(&tmp); - if (!secp256k1_fe_equal(&tmp, &b->x)) return 0; - - tmp = a->y; - secp256k1_fe_normalize_weak(&tmp); - if (!secp256k1_fe_equal(&tmp, &b->y)) return 0; - - return 1; -} - -static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { - secp256k1_fe r; - SECP256K1_FE_VERIFY(x); - SECP256K1_GEJ_VERIFY(a); - VERIFY_CHECK(!a->infinity); - - secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); - return secp256k1_fe_equal(&r, &a->x); -} - -static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { - SECP256K1_GEJ_VERIFY(a); - - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - r->z = a->z; - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_negate(&r->y, &r->y, 1); - - SECP256K1_GEJ_VERIFY(r); -} - -static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { - SECP256K1_GEJ_VERIFY(a); - - return a->infinity; -} - -static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { - secp256k1_fe y2, x3; - SECP256K1_GE_VERIFY(a); - - if (a->infinity) { - return 0; - } - /* y^2 = x^3 + 7 */ - secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_add_int(&x3, SECP256K1_B); - return secp256k1_fe_equal(&y2, &x3); -} - -static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) { - /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ - secp256k1_fe l, s, t; - SECP256K1_GEJ_VERIFY(a); - - r->infinity = a->infinity; - - /* Formula used: - * L = (3/2) * X1^2 - * S = Y1^2 - * T = -X1*S - * X3 = L^2 + 2*T - * Y3 = -(L*(X3 + T) + S^2) - * Z3 = Y1*Z1 - */ - - secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */ - secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */ - secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */ - secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */ - secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */ - secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */ - secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */ - secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */ - secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */ - secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */ - secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */ - secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */ - secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ - secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ - secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - SECP256K1_GEJ_VERIFY(a); - - /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, - * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have - * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. - * - * Having said this, if this function receives a point on a sextic twist, e.g. by - * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, - * since -6 does have a cube root mod p. For this point, this function will not set - * the infinity flag even though the point doubles to infinity, and the result - * point will be gibberish (z = 0 but infinity = 0). - */ - if (a->infinity) { - secp256k1_gej_set_infinity(r); - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - return; - } - - if (rzr != NULL) { - *rzr = a->y; - secp256k1_fe_normalize_weak(rzr); - } - - secp256k1_gej_double(r, a); - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { - /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ - secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GEJ_VERIFY(b); - - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - *r = *b; - return; - } - if (b->infinity) { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - - secp256k1_fe_sqr(&z22, &b->z); - secp256k1_fe_sqr(&z12, &a->z); - secp256k1_fe_mul(&u1, &a->x, &z22); - secp256k1_fe_mul(&u2, &b->x, &z12); - secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 0); - } - secp256k1_gej_set_infinity(r); - } - return; - } - - r->infinity = 0; - secp256k1_fe_mul(&t, &h, &b->z); - if (rzr != NULL) { - *rzr = t; - } - secp256k1_fe_mul(&r->z, &a->z, &t); - - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_negate(&h2, &h2, 1); - secp256k1_fe_mul(&h3, &h2, &h); - secp256k1_fe_mul(&t, &u1, &h2); - - secp256k1_fe_sqr(&r->x, &i); - secp256k1_fe_add(&r->x, &h3); - secp256k1_fe_add(&r->x, &t); - secp256k1_fe_add(&r->x, &t); - - secp256k1_fe_add(&t, &r->x); - secp256k1_fe_mul(&r->y, &t, &i); - secp256k1_fe_mul(&h3, &h3, &s1); - secp256k1_fe_add(&r->y, &h3); - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { - /* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ - secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(b); - - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - secp256k1_gej_set_ge(r, b); - return; - } - if (b->infinity) { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - - secp256k1_fe_sqr(&z12, &a->z); - u1 = a->x; - secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 0); - } - secp256k1_gej_set_infinity(r); - } - return; - } - - r->infinity = 0; - if (rzr != NULL) { - *rzr = h; - } - secp256k1_fe_mul(&r->z, &a->z, &h); - - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_negate(&h2, &h2, 1); - secp256k1_fe_mul(&h3, &h2, &h); - secp256k1_fe_mul(&t, &u1, &h2); - - secp256k1_fe_sqr(&r->x, &i); - secp256k1_fe_add(&r->x, &h3); - secp256k1_fe_add(&r->x, &t); - secp256k1_fe_add(&r->x, &t); - - secp256k1_fe_add(&t, &r->x); - secp256k1_fe_mul(&r->y, &t, &i); - secp256k1_fe_mul(&h3, &h3, &s1); - secp256k1_fe_add(&r->y, &h3); - - SECP256K1_GEJ_VERIFY(r); - if (rzr != NULL) SECP256K1_FE_VERIFY(rzr); -} - -static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { - /* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ - secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(b); - SECP256K1_FE_VERIFY(bzinv); - - if (a->infinity) { - secp256k1_fe bzinv2, bzinv3; - r->infinity = b->infinity; - secp256k1_fe_sqr(&bzinv2, bzinv); - secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); - secp256k1_fe_mul(&r->x, &b->x, &bzinv2); - secp256k1_fe_mul(&r->y, &b->y, &bzinv3); - secp256k1_fe_set_int(&r->z, 1); - SECP256K1_GEJ_VERIFY(r); - return; - } - if (b->infinity) { - *r = *a; - return; - } - - /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to - * secp256k1's isomorphism we can multiply the Z coordinates on both sides - * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). - * This means that (rx,ry,rz) can be calculated as - * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. - * The variable az below holds the modified Z coordinate for a, which is used - * for the computation of rx and ry, but not for rz. - */ - secp256k1_fe_mul(&az, &a->z, bzinv); - - secp256k1_fe_sqr(&z12, &az); - u1 = a->x; - secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); - secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, NULL); - } else { - secp256k1_gej_set_infinity(r); - } - return; - } - - r->infinity = 0; - secp256k1_fe_mul(&r->z, &a->z, &h); - - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_negate(&h2, &h2, 1); - secp256k1_fe_mul(&h3, &h2, &h); - secp256k1_fe_mul(&t, &u1, &h2); - - secp256k1_fe_sqr(&r->x, &i); - secp256k1_fe_add(&r->x, &h3); - secp256k1_fe_add(&r->x, &t); - secp256k1_fe_add(&r->x, &t); - - secp256k1_fe_add(&t, &r->x); - secp256k1_fe_mul(&r->y, &t, &i); - secp256k1_fe_mul(&h3, &h3, &s1); - secp256k1_fe_add(&r->y, &h3); - - SECP256K1_GEJ_VERIFY(r); -} - - -static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { - /* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */ - secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; - secp256k1_fe m_alt, rr_alt; - int degenerate; - SECP256K1_GEJ_VERIFY(a); - SECP256K1_GE_VERIFY(b); - VERIFY_CHECK(!b->infinity); - - /* In: - * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. - * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. - * we find as solution for a unified addition/doubling formula: - * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. - * x3 = lambda^2 - (x1 + x2) - * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). - * - * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: - * U1 = X1*Z2^2, U2 = X2*Z1^2 - * S1 = Y1*Z2^3, S2 = Y2*Z1^3 - * Z = Z1*Z2 - * T = U1+U2 - * M = S1+S2 - * Q = -T*M^2 - * R = T^2-U1*U2 - * X3 = R^2+Q - * Y3 = -(R*(2*X3+Q)+M^4)/2 - * Z3 = M*Z - * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) - * - * This formula has the benefit of being the same for both addition - * of distinct points and doubling. However, it breaks down in the - * case that either point is infinity, or that y1 = -y2. We handle - * these cases in the following ways: - * - * - If b is infinity we simply bail by means of a VERIFY_CHECK. - * - * - If a is infinity, we detect this, and at the end of the - * computation replace the result (which will be meaningless, - * but we compute to be constant-time) with b.x : b.y : 1. - * - * - If a = -b, we have y1 = -y2, which is a degenerate case. - * But here the answer is infinity, so we simply set the - * infinity flag of the result, overriding the computed values - * without even needing to cmov. - * - * - If y1 = -y2 but x1 != x2, which does occur thanks to certain - * properties of our curve (specifically, 1 has nontrivial cube - * roots in our field, and the curve equation has no x coefficient) - * then the answer is not infinity but also not given by the above - * equation. In this case, we cmov in place an alternate expression - * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these - * expressions for lambda are defined, they are equal, and can be - * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) - * then substitution of x^3 + 7 for y^2 (using the curve equation). - * For all pairs of nonzero points (a, b) at least one is defined, - * so this covers everything. - */ - - secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */ - secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */ - secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ - secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */ - m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */ - secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */ - secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */ - secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */ - /* If lambda = R/M = R/0 we have a problem (except in the "trivial" - * case that Z = z1z2 = 0, and this is special-cased later on). */ - degenerate = secp256k1_fe_normalizes_to_zero(&m); - /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. - * This means either x1 == beta*x2 or beta*x1 == x2, where beta is - * a nontrivial cube root of one. In either case, an alternate - * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), - * so we set R/M equal to this. */ - rr_alt = s1; - secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */ - secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */ - - secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */ - secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */ - /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. - * From here on out Ralt and Malt represent the numerator - * and denominator of lambda; R and M represent the explicit - * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ - secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ - secp256k1_fe_negate(&q, &t, - SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */ - secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ - /* These two lines use the observation that either M == Malt or M == 0, - * so M^3 * Malt is either Malt^4 (which is computed by squaring), or - * zero (which is "computed" by cmov). So the cost is one squaring - * versus two multiplications. */ - secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */ - secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */ - secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ - secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ - secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ - r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ - secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ - secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */ - secp256k1_fe_negate(&r->y, &t, - SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */ - secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */ - - /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ - secp256k1_fe_cmov(&r->x, &b->x, a->infinity); - secp256k1_fe_cmov(&r->y, &b->y, a->infinity); - secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity); - - /* Set r->infinity if r->z is 0. - * - * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false, - * which is correct because the function assumes that b is not infinity. - * - * Now assume !a->infinity. This implies Z = Z1 != 0. - * - * Case y1 = -y2: - * In this case we could have a = -b, namely if x1 = x2. - * We have degenerate = true, r->z = (x1 - x2) * Z. - * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b). - * - * Case y1 != -y2: - * In this case, we can't have a = -b. - * We have degenerate = false, r->z = (y1 + y2) * Z. - * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ - r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { - /* Operations: 4 mul, 1 sqr */ - secp256k1_fe zz; - SECP256K1_GEJ_VERIFY(r); - SECP256K1_FE_VERIFY(s); - VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s)); - - secp256k1_fe_sqr(&zz, s); - secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ - secp256k1_fe_mul(&r->y, &r->y, &zz); - secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ - secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ - - SECP256K1_GEJ_VERIFY(r); -} - -static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { - secp256k1_fe x, y; - SECP256K1_GE_VERIFY(a); - VERIFY_CHECK(!a->infinity); - - x = a->x; - secp256k1_fe_normalize(&x); - y = a->y; - secp256k1_fe_normalize(&y); - secp256k1_fe_to_storage(&r->x, &x); - secp256k1_fe_to_storage(&r->y, &y); -} - -static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { - secp256k1_fe_from_storage(&r->x, &a->x); - secp256k1_fe_from_storage(&r->y, &a->y); - r->infinity = 0; - - SECP256K1_GE_VERIFY(r); -} - -static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { - SECP256K1_GEJ_VERIFY(r); - SECP256K1_GEJ_VERIFY(a); - - secp256k1_fe_cmov(&r->x, &a->x, flag); - secp256k1_fe_cmov(&r->y, &a->y, flag); - secp256k1_fe_cmov(&r->z, &a->z, flag); - r->infinity ^= (r->infinity ^ a->infinity) & flag; - - SECP256K1_GEJ_VERIFY(r); -} - -static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { - secp256k1_fe_storage_cmov(&r->x, &a->x, flag); - secp256k1_fe_storage_cmov(&r->y, &a->y, flag); -} - -static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { - SECP256K1_GE_VERIFY(a); - - *r = *a; - secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); - - SECP256K1_GE_VERIFY(r); -} - -static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { -#ifdef EXHAUSTIVE_TEST_ORDER - secp256k1_gej out; - int i; - SECP256K1_GE_VERIFY(ge); - - /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ - secp256k1_gej_set_infinity(&out); - for (i = 0; i < 32; ++i) { - secp256k1_gej_double_var(&out, &out, NULL); - if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { - secp256k1_gej_add_ge_var(&out, &out, ge, NULL); - } - } - return secp256k1_gej_is_infinity(&out); -#else - SECP256K1_GE_VERIFY(ge); - - (void)ge; - /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ - return 1; -#endif -} - -static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) { - secp256k1_fe c; - secp256k1_fe_sqr(&c, x); - secp256k1_fe_mul(&c, &c, x); - secp256k1_fe_add_int(&c, SECP256K1_B); - return secp256k1_fe_is_square_var(&c); -} - -static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) { - /* We want to determine whether (xn/xd) is on the curve. - * - * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square). - */ - secp256k1_fe r, t; - VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd)); - - secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */ - secp256k1_fe_sqr(&t, xn); /* t = xn^2 */ - secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */ - secp256k1_fe_sqr(&t, xd); /* t = xd^2 */ - secp256k1_fe_sqr(&t, &t); /* t = xd^4 */ - VERIFY_CHECK(SECP256K1_B <= 31); - secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */ - secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */ - return secp256k1_fe_is_square_var(&r); -} - -static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) { - secp256k1_ge_storage s; - - /* We require that the secp256k1_ge_storage type is exactly 64 bytes. - * This is formally not guaranteed by the C standard, but should hold on any - * sane compiler in the real world. */ - STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); - VERIFY_CHECK(!secp256k1_ge_is_infinity(a)); - secp256k1_ge_to_storage(&s, a); - memcpy(buf, &s, 64); -} - -static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { - secp256k1_ge_storage s; - - STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); - memcpy(&s, buf, 64); - secp256k1_ge_from_storage(r, &s); -} - -static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) { - if (secp256k1_ge_is_infinity(ge)) { - memset(data, 0, 64); - } else { - secp256k1_ge_to_bytes(data, ge); - } -} - -static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) { - static const unsigned char zeros[64] = { 0 }; - if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { - secp256k1_ge_set_infinity(ge); - } else { - secp256k1_ge_from_bytes(ge, data); - } -} - -#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/external/secp256k1/src/hash.h b/external/secp256k1/src/hash.h deleted file mode 100644 index 6d903ca7e0..0000000000 --- a/external/secp256k1/src/hash.h +++ /dev/null @@ -1,44 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HASH_H -#define SECP256K1_HASH_H - -#include -#include - -typedef struct { - uint32_t s[8]; - unsigned char buf[64]; - uint64_t bytes; -} secp256k1_sha256; - -static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); -static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); -static void secp256k1_sha256_clear(secp256k1_sha256 *hash); - -typedef struct { - secp256k1_sha256 inner, outer; -} secp256k1_hmac_sha256; - -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); -static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash); - -typedef struct { - unsigned char v[32]; - unsigned char k[32]; - int retry; -} secp256k1_rfc6979_hmac_sha256; - -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); -static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng); - -#endif /* SECP256K1_HASH_H */ diff --git a/external/secp256k1/src/hash_impl.h b/external/secp256k1/src/hash_impl.h deleted file mode 100644 index 956e0ea48b..0000000000 --- a/external/secp256k1/src/hash_impl.h +++ /dev/null @@ -1,299 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HASH_IMPL_H -#define SECP256K1_HASH_IMPL_H - -#include "hash.h" -#include "util.h" - -#include -#include -#include - -#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) -#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) -#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) -#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) - -#define Round(a,b,c,d,e,f,g,h,k,w) do { \ - uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ - uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ - (d) += t1; \ - (h) = t1 + t2; \ -} while(0) - -static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { - hash->s[0] = 0x6a09e667ul; - hash->s[1] = 0xbb67ae85ul; - hash->s[2] = 0x3c6ef372ul; - hash->s[3] = 0xa54ff53aul; - hash->s[4] = 0x510e527ful; - hash->s[5] = 0x9b05688cul; - hash->s[6] = 0x1f83d9abul; - hash->s[7] = 0x5be0cd19ul; - hash->bytes = 0; -} - -/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { - uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; - uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0])); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4])); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8])); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12])); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16])); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20])); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24])); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28])); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32])); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36])); - Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40])); - Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44])); - Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48])); - Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52])); - Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56])); - Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60])); - - Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); - - s[0] += a; - s[1] += b; - s[2] += c; - s[3] += d; - s[4] += e; - s[5] += f; - s[6] += g; - s[7] += h; -} - -static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { - size_t bufsize = hash->bytes & 0x3F; - hash->bytes += len; - VERIFY_CHECK(hash->bytes >= len); - while (len >= 64 - bufsize) { - /* Fill the buffer, and process it. */ - size_t chunk_len = 64 - bufsize; - memcpy(hash->buf + bufsize, data, chunk_len); - data += chunk_len; - len -= chunk_len; - secp256k1_sha256_transform(hash->s, hash->buf); - bufsize = 0; - } - if (len) { - /* Fill the buffer with what remains. */ - memcpy(hash->buf + bufsize, data, len); - } -} - -static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { - static const unsigned char pad[64] = {0x80}; - unsigned char sizedesc[8]; - int i; - /* The maximum message size of SHA256 is 2^64-1 bits. */ - VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61)); - secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29); - secp256k1_write_be32(&sizedesc[4], hash->bytes << 3); - secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); - secp256k1_sha256_write(hash, sizedesc, 8); - for (i = 0; i < 8; i++) { - secp256k1_write_be32(&out32[4*i], hash->s[i]); - hash->s[i] = 0; - } -} - -/* Initializes a sha256 struct and writes the 64 byte string - * SHA256(tag)||SHA256(tag) into it. */ -static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { - unsigned char buf[32]; - secp256k1_sha256_initialize(hash); - secp256k1_sha256_write(hash, tag, taglen); - secp256k1_sha256_finalize(hash, buf); - - secp256k1_sha256_initialize(hash); - secp256k1_sha256_write(hash, buf, 32); - secp256k1_sha256_write(hash, buf, 32); -} - -static void secp256k1_sha256_clear(secp256k1_sha256 *hash) { - secp256k1_memclear(hash, sizeof(*hash)); -} - -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { - size_t n; - unsigned char rkey[64]; - if (keylen <= sizeof(rkey)) { - memcpy(rkey, key, keylen); - memset(rkey + keylen, 0, sizeof(rkey) - keylen); - } else { - secp256k1_sha256 sha256; - secp256k1_sha256_initialize(&sha256); - secp256k1_sha256_write(&sha256, key, keylen); - secp256k1_sha256_finalize(&sha256, rkey); - memset(rkey + 32, 0, 32); - } - - secp256k1_sha256_initialize(&hash->outer); - for (n = 0; n < sizeof(rkey); n++) { - rkey[n] ^= 0x5c; - } - secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); - - secp256k1_sha256_initialize(&hash->inner); - for (n = 0; n < sizeof(rkey); n++) { - rkey[n] ^= 0x5c ^ 0x36; - } - secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey)); - secp256k1_memclear(rkey, sizeof(rkey)); -} - -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { - secp256k1_sha256_write(&hash->inner, data, size); -} - -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { - unsigned char temp[32]; - secp256k1_sha256_finalize(&hash->inner, temp); - secp256k1_sha256_write(&hash->outer, temp, 32); - secp256k1_memclear(temp, sizeof(temp)); - secp256k1_sha256_finalize(&hash->outer, out32); -} - -static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) { - secp256k1_memclear(hash, sizeof(*hash)); -} - -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { - secp256k1_hmac_sha256 hmac; - static const unsigned char zero[1] = {0x00}; - static const unsigned char one[1] = {0x01}; - - memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ - memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ - - /* RFC6979 3.2.d. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, zero, 1); - secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - - /* RFC6979 3.2.f. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, one, 1); - secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - rng->retry = 0; -} - -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { - /* RFC6979 3.2.h. */ - static const unsigned char zero[1] = {0x00}; - if (rng->retry) { - secp256k1_hmac_sha256 hmac; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, zero, 1); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - } - - while (outlen > 0) { - secp256k1_hmac_sha256 hmac; - int now = outlen; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - if (now > 32) { - now = 32; - } - memcpy(out, rng->v, now); - out += now; - outlen -= now; - } - - rng->retry = 1; -} - -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { - (void) rng; -} - -static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) { - secp256k1_memclear(rng, sizeof(*rng)); -} - -#undef Round -#undef sigma1 -#undef sigma0 -#undef Sigma1 -#undef Sigma0 -#undef Maj -#undef Ch - -#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/external/secp256k1/src/hsort.h b/external/secp256k1/src/hsort.h deleted file mode 100644 index d54995caad..0000000000 --- a/external/secp256k1/src/hsort.h +++ /dev/null @@ -1,33 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Russell O'Connor, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HSORT_H -#define SECP256K1_HSORT_H - -#include -#include - -/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This - * is preferred over standard library implementations because they generally - * make no guarantee about being fast for malicious inputs. - * Remember that heapsort is unstable. - * - * In/Out: ptr: pointer to the array to sort. The contents of the array are - * sorted in ascending order according to the comparison function. - * In: count: number of elements in the array. - * size: size in bytes of each element. - * cmp: pointer to a comparison function that is called with two - * arguments that point to the objects being compared. The cmp_data - * argument of secp256k1_hsort is passed as third argument. The - * function must return an integer less than, equal to, or greater - * than zero if the first argument is considered to be respectively - * less than, equal to, or greater than the second. - * cmp_data: pointer passed as third argument to cmp. - */ -static void secp256k1_hsort(void *ptr, size_t count, size_t size, - int (*cmp)(const void *, const void *, void *), - void *cmp_data); -#endif diff --git a/external/secp256k1/src/hsort_impl.h b/external/secp256k1/src/hsort_impl.h deleted file mode 100644 index 1c674ff1c4..0000000000 --- a/external/secp256k1/src/hsort_impl.h +++ /dev/null @@ -1,125 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Russell O'Connor, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HSORT_IMPL_H -#define SECP256K1_HSORT_IMPL_H - -#include "hsort.h" - -/* An array is a heap when, for all non-zero indexes i, the element at index i - * compares as less than or equal to the element at index parent(i) = (i-1)/2. - */ - -static SECP256K1_INLINE size_t secp256k1_heap_child1(size_t i) { - VERIFY_CHECK(i <= (SIZE_MAX - 1)/2); - return 2*i + 1; -} - -static SECP256K1_INLINE size_t secp256k1_heap_child2(size_t i) { - VERIFY_CHECK(i <= SIZE_MAX/2 - 1); - return secp256k1_heap_child1(i)+1; -} - -static SECP256K1_INLINE void secp256k1_heap_swap64(unsigned char *a, unsigned char *b, size_t len) { - unsigned char tmp[64]; - VERIFY_CHECK(len <= 64); - memcpy(tmp, a, len); - memmove(a, b, len); - memcpy(b, tmp, len); -} - -static SECP256K1_INLINE void secp256k1_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) { - unsigned char *a = arr + i*stride; - unsigned char *b = arr + j*stride; - size_t len = stride; - while (64 < len) { - secp256k1_heap_swap64(a + (len - 64), b + (len - 64), 64); - len -= 64; - } - secp256k1_heap_swap64(a, b, len); -} - -/* This function accepts an array arr containing heap_size elements, each of - * size stride. The elements in the array at indices >i satisfy the max-heap - * property, i.e., for any element at index j (where j > i), all of its children - * are smaller than the element itself. The purpose of the function is to update - * the array so that all elements at indices >=i satisfy the max-heap - * property. */ -static SECP256K1_INLINE void secp256k1_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride, - int (*cmp)(const void *, const void *, void *), void *cmp_data) { - while (i < heap_size/2) { - VERIFY_CHECK(i <= SIZE_MAX/2 - 1); - /* Proof: - * i < heap_size/2 - * i + 1 <= heap_size/2 - * 2*i + 2 <= heap_size <= SIZE_MAX - * 2*i <= SIZE_MAX - 2 - */ - - VERIFY_CHECK(secp256k1_heap_child1(i) < heap_size); - /* Proof: - * i < heap_size/2 - * i + 1 <= heap_size/2 - * 2*i + 2 <= heap_size - * 2*i + 1 < heap_size - * child1(i) < heap_size - */ - - /* Let [x] be notation for the contents at arr[x*stride]. - * - * If [child1(i)] > [i] and [child2(i)] > [i], - * swap [i] with the larger child to ensure the new parent is larger - * than both children. When [child1(i)] == [child2(i)], swap [i] with - * [child2(i)]. - * Else if [child1(i)] > [i], swap [i] with [child1(i)]. - * Else if [child2(i)] > [i], swap [i] with [child2(i)]. - */ - if (secp256k1_heap_child2(i) < heap_size - && 0 <= cmp(arr + secp256k1_heap_child2(i)*stride, arr + secp256k1_heap_child1(i)*stride, cmp_data)) { - if (0 < cmp(arr + secp256k1_heap_child2(i)*stride, arr + i*stride, cmp_data)) { - secp256k1_heap_swap(arr, i, secp256k1_heap_child2(i), stride); - i = secp256k1_heap_child2(i); - } else { - /* At this point we have [child2(i)] >= [child1(i)] and we have - * [child2(i)] <= [i], and thus [child1(i)] <= [i] which means - * that the next comparison can be skipped. */ - return; - } - } else if (0 < cmp(arr + secp256k1_heap_child1(i)*stride, arr + i*stride, cmp_data)) { - secp256k1_heap_swap(arr, i, secp256k1_heap_child1(i), stride); - i = secp256k1_heap_child1(i); - } else { - return; - } - } - /* heap_size/2 <= i - * heap_size/2 < i + 1 - * heap_size < 2*i + 2 - * heap_size <= 2*i + 1 - * heap_size <= child1(i) - * Thus child1(i) and child2(i) are now out of bounds and we are at a leaf. - */ -} - -/* In-place heap sort. */ -static void secp256k1_hsort(void *ptr, size_t count, size_t size, - int (*cmp)(const void *, const void *, void *), - void *cmp_data) { - size_t i; - - for (i = count/2; 0 < i; --i) { - secp256k1_heap_down(ptr, i-1, count, size, cmp, cmp_data); - } - for (i = count; 1 < i; --i) { - /* Extract the largest value from the heap */ - secp256k1_heap_swap(ptr, 0, i-1, size); - - /* Repair the heap condition */ - secp256k1_heap_down(ptr, 0, i-1, size, cmp, cmp_data); - } -} - -#endif diff --git a/external/secp256k1/src/int128.h b/external/secp256k1/src/int128.h deleted file mode 100644 index 5355fbfae0..0000000000 --- a/external/secp256k1/src/int128.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef SECP256K1_INT128_H -#define SECP256K1_INT128_H - -#include "util.h" - -#if defined(SECP256K1_WIDEMUL_INT128) -# if defined(SECP256K1_INT128_NATIVE) -# include "int128_native.h" -# elif defined(SECP256K1_INT128_STRUCT) -# include "int128_struct.h" -# else -# error "Please select int128 implementation" -# endif - -/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */ -static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo); - -/* Multiply two unsigned 64-bit values a and b and write the result to r. */ -static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); - -/* Multiply two unsigned 64-bit values a and b and add the result to r. - * The final result is taken modulo 2^128. - */ -static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); - -/* Add an unsigned 64-bit value a to r. - * The final result is taken modulo 2^128. - */ -static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a); - -/* Unsigned (logical) right shift. - * Non-constant time in n. - */ -static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n); - -/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */ -static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a); - -/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */ -static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a); - -/* Write an unsigned 64-bit value to r. */ -static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a); - -/* Tests if r is strictly less than to 2^n. - * n must be strictly less than 128. - */ -static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n); - -/* Construct an signed 128-bit value from a high and a low 64-bit value. */ -static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo); - -/* Multiply two signed 64-bit values a and b and write the result to r. */ -static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b); - -/* Multiply two signed 64-bit values a and b and add the result to r. - * Overflow or underflow from the addition is undefined behaviour. - */ -static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b); - -/* Compute a*d - b*c from signed 64-bit values and write the result to r. */ -static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d); - -/* Signed (arithmetic) right shift. - * Non-constant time in b. - */ -static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b); - -/* Return the input value modulo 2^64. */ -static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a); - -/* Return the value as a signed 64-bit value. - * Requires the input to be between INT64_MIN and INT64_MAX. - */ -static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a); - -/* Write a signed 64-bit value to r. */ -static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a); - -/* Compare two 128-bit values for equality. */ -static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); - -/* Tests if r is equal to sign*2^n (sign must be 1 or -1). - * n must be strictly less than 127. - */ -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign); - -#endif - -#endif diff --git a/external/secp256k1/src/int128_impl.h b/external/secp256k1/src/int128_impl.h deleted file mode 100644 index cfc573408a..0000000000 --- a/external/secp256k1/src/int128_impl.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SECP256K1_INT128_IMPL_H -#define SECP256K1_INT128_IMPL_H - -#include "util.h" - -#include "int128.h" - -#if defined(SECP256K1_WIDEMUL_INT128) -# if defined(SECP256K1_INT128_NATIVE) -# include "int128_native_impl.h" -# elif defined(SECP256K1_INT128_STRUCT) -# include "int128_struct_impl.h" -# else -# error "Please select int128 implementation" -# endif -#endif - -#endif diff --git a/external/secp256k1/src/int128_native.h b/external/secp256k1/src/int128_native.h deleted file mode 100644 index 7c97aafc74..0000000000 --- a/external/secp256k1/src/int128_native.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SECP256K1_INT128_NATIVE_H -#define SECP256K1_INT128_NATIVE_H - -#include -#include "util.h" - -#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; -SECP256K1_GNUC_EXT typedef __int128 int128_t; -# define UINT128_MAX ((uint128_t)(-1)) -# define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) -# define INT128_MIN (-INT128_MAX - 1) -/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ -#endif - -typedef uint128_t secp256k1_uint128; -typedef int128_t secp256k1_int128; - -#endif diff --git a/external/secp256k1/src/int128_native_impl.h b/external/secp256k1/src/int128_native_impl.h deleted file mode 100644 index 7f02e1590b..0000000000 --- a/external/secp256k1/src/int128_native_impl.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef SECP256K1_INT128_NATIVE_IMPL_H -#define SECP256K1_INT128_NATIVE_IMPL_H - -#include "int128.h" -#include "util.h" - -static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { - *r = (((uint128_t)hi) << 64) + lo; -} - -static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { - *r = (uint128_t)a * b; -} - -static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { - *r += (uint128_t)a * b; -} - -static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { - *r += a; -} - -static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - *r >>= n; -} - -static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { - return (uint64_t)(*a); -} - -static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { - return (uint64_t)(*a >> 64); -} - -static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { - *r = a; -} - -static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - return (*r >> n == 0); -} - -static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { - *r = (((uint128_t)(uint64_t)hi) << 64) + lo; -} - -static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { - *r = (int128_t)a * b; -} - -static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { - int128_t ab = (int128_t)a * b; - VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r); - *r += ab; -} - -static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { - int128_t ad = (int128_t)a * d; - int128_t bc = (int128_t)b * c; - VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc); - *r = ad - bc; -} - -static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - *r >>= n; -} - -static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { - return (uint64_t)*a; -} - -static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { - VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX); - return *a; -} - -static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { - *r = a; -} - -static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { - return *a == *b; -} - -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { - VERIFY_CHECK(n < 127); - VERIFY_CHECK(sign == 1 || sign == -1); - return (*r == (int128_t)((uint128_t)sign << n)); -} - -#endif diff --git a/external/secp256k1/src/int128_struct.h b/external/secp256k1/src/int128_struct.h deleted file mode 100644 index 6156f82cc2..0000000000 --- a/external/secp256k1/src/int128_struct.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef SECP256K1_INT128_STRUCT_H -#define SECP256K1_INT128_STRUCT_H - -#include -#include "util.h" - -typedef struct { - uint64_t lo; - uint64_t hi; -} secp256k1_uint128; - -typedef secp256k1_uint128 secp256k1_int128; - -#endif diff --git a/external/secp256k1/src/int128_struct_impl.h b/external/secp256k1/src/int128_struct_impl.h deleted file mode 100644 index 962a71d13b..0000000000 --- a/external/secp256k1/src/int128_struct_impl.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef SECP256K1_INT128_STRUCT_IMPL_H -#define SECP256K1_INT128_STRUCT_IMPL_H - -#include "int128.h" -#include "util.h" - -#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ -# include -# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) -/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. - (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64, - which supports both __(u)mulh and _umul128.) */ -# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) -# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.") -# endif -static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { - *hi = __umulh(a, b); - return a * b; -} - -static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { - *hi = __mulh(a, b); - return (uint64_t)a * (uint64_t)b; -} -# else -/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */ -# define secp256k1_umul128 _umul128 -# define secp256k1_mul128 _mul128 -# endif -#else -/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */ -static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { - uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; - uint64_t lh = (uint32_t)a * (b >> 32); - uint64_t hl = (a >> 32) * (uint32_t)b; - uint64_t hh = (a >> 32) * (b >> 32); - uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; - *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); - return (mid34 << 32) + (uint32_t)ll; -} - -static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { - uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; - int64_t lh = (uint32_t)a * (b >> 32); - int64_t hl = (a >> 32) * (uint32_t)b; - int64_t hh = (a >> 32) * (b >> 32); - uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; - *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); - return (mid34 << 32) + (uint32_t)ll; -} -#endif - -static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { - r->hi = hi; - r->lo = lo; -} - -static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { - r->lo = secp256k1_umul128(a, b, &r->hi); -} - -static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { - uint64_t lo, hi; - lo = secp256k1_umul128(a, b, &hi); - r->lo += lo; - r->hi += hi + (r->lo < lo); -} - -static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { - r->lo += a; - r->hi += r->lo < a; -} - -/* Unsigned (logical) right shift. - * Non-constant time in n. - */ -static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - if (n >= 64) { - r->lo = r->hi >> (n-64); - r->hi = 0; - } else if (n > 0) { -#if defined(_MSC_VER) && defined(_M_X64) - VERIFY_CHECK(n < 64); - r->lo = __shiftright128(r->lo, r->hi, n); -#else - r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; -#endif - r->hi >>= n; - } -} - -static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { - return a->lo; -} - -static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { - return a->hi; -} - -static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { - r->hi = 0; - r->lo = a; -} - -static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - return n >= 64 ? r->hi >> (n - 64) == 0 - : r->hi == 0 && r->lo >> n == 0; -} - -static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { - r->hi = hi; - r->lo = lo; -} - -static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { - int64_t hi; - r->lo = (uint64_t)secp256k1_mul128(a, b, &hi); - r->hi = (uint64_t)hi; -} - -static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { - int64_t hi; - uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); - r->lo += lo; - hi += r->lo < lo; - /* Verify no overflow. - * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set), - * then we require that the resulting value also be positive (the sign bit is not set). - * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1). - */ - VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu)); - /* Verify no underflow. - * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set), - * then we require that the resulting value also be negative (the sign bit is set). - */ - VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu)); - r->hi += hi; -} - -static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) { - int64_t hi; - uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); - hi += r->lo < lo; - /* Verify no overflow. - * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set), - * then we require that the resulting value also be positive (the sign bit is not set). - */ - VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu)); - /* Verify no underflow. - * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set), - * then we require that the resulting value also be negative (the sign bit is set). - */ - VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu)); - r->hi -= hi; - r->lo -= lo; -} - -static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { - secp256k1_i128_mul(r, a, d); - secp256k1_i128_dissip_mul(r, b, c); -} - -/* Signed (arithmetic) right shift. - * Non-constant time in n. - */ -static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { - VERIFY_CHECK(n < 128); - if (n >= 64) { - r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64)); - r->hi = (uint64_t)((int64_t)(r->hi) >> 63); - } else if (n > 0) { - r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; - r->hi = (uint64_t)((int64_t)(r->hi) >> n); - } -} - -static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { - return a->lo; -} - -static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { - /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */ - VERIFY_CHECK(a->hi == -(a->lo >> 63)); - return (int64_t)secp256k1_i128_to_u64(a); -} - -static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { - r->hi = (uint64_t)(a >> 63); - r->lo = (uint64_t)a; -} - -static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { - return a->hi == b->hi && a->lo == b->lo; -} - -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { - VERIFY_CHECK(n < 127); - VERIFY_CHECK(sign == 1 || sign == -1); - return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 - : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n; -} - -#endif diff --git a/external/secp256k1/src/modinv32.h b/external/secp256k1/src/modinv32.h deleted file mode 100644 index 846c642f8c..0000000000 --- a/external/secp256k1/src/modinv32.h +++ /dev/null @@ -1,43 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODINV32_H -#define SECP256K1_MODINV32_H - -#include "util.h" - -/* A signed 30-bit limb representation of integers. - * - * Its value is sum(v[i] * 2^(30*i), i=0..8). */ -typedef struct { - int32_t v[9]; -} secp256k1_modinv32_signed30; - -typedef struct { - /* The modulus in signed30 notation, must be odd and in [3, 2^256]. */ - secp256k1_modinv32_signed30 modulus; - - /* modulus^{-1} mod 2^30 */ - uint32_t modulus_inv30; -} secp256k1_modinv32_modinfo; - -/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). - * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of - * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. - * - * On output, all of x's limbs will be in [0, 2^30). - */ -static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); - -/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */ -static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); - -/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus - * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result - * cannot be computed. */ -static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); - -#endif /* SECP256K1_MODINV32_H */ diff --git a/external/secp256k1/src/modinv32_impl.h b/external/secp256k1/src/modinv32_impl.h deleted file mode 100644 index 981d2abc6d..0000000000 --- a/external/secp256k1/src/modinv32_impl.h +++ /dev/null @@ -1,725 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODINV32_IMPL_H -#define SECP256K1_MODINV32_IMPL_H - -#include "modinv32.h" - -#include "util.h" - -#include - -/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and - * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. - * - * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an - * implementation for N=30, using 30-bit signed limbs represented as int32_t. - */ - -#ifdef VERIFY -static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; - -/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */ -static void secp256k1_modinv32_mul_30(secp256k1_modinv32_signed30 *r, const secp256k1_modinv32_signed30 *a, int alen, int32_t factor) { - const int32_t M30 = (int32_t)(UINT32_MAX >> 2); - int64_t c = 0; - int i; - for (i = 0; i < 8; ++i) { - if (i < alen) c += (int64_t)a->v[i] * factor; - r->v[i] = (int32_t)c & M30; c >>= 30; - } - if (8 < alen) c += (int64_t)a->v[8] * factor; - VERIFY_CHECK(c == (int32_t)c); - r->v[8] = (int32_t)c; -} - -/* Return -1 for ab*factor. A consists of alen limbs; b has 9. */ -static int secp256k1_modinv32_mul_cmp_30(const secp256k1_modinv32_signed30 *a, int alen, const secp256k1_modinv32_signed30 *b, int32_t factor) { - int i; - secp256k1_modinv32_signed30 am, bm; - secp256k1_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */ - secp256k1_modinv32_mul_30(&bm, b, 9, factor); - for (i = 0; i < 8; ++i) { - /* Verify that all but the top limb of a and b are normalized. */ - VERIFY_CHECK(am.v[i] >> 30 == 0); - VERIFY_CHECK(bm.v[i] >> 30 == 0); - } - for (i = 8; i >= 0; --i) { - if (am.v[i] < bm.v[i]) return -1; - if (am.v[i] > bm.v[i]) return 1; - } - return 0; -} -#endif - -/* Take as input a signed30 number in range (-2*modulus,modulus), and add a multiple of the modulus - * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the - * process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range - * [0,2^30). */ -static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int32_t sign, const secp256k1_modinv32_modinfo *modinfo) { - const int32_t M30 = (int32_t)(UINT32_MAX >> 2); - int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4], - r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8]; - volatile int32_t cond_add, cond_negate; - -#ifdef VERIFY - /* Verify that all limbs are in range (-2^30,2^30). */ - int i; - for (i = 0; i < 9; ++i) { - VERIFY_CHECK(r->v[i] >= -M30); - VERIFY_CHECK(r->v[i] <= M30); - } - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif - - /* In a first step, add the modulus if the input is negative, and then negate if requested. - * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input - * limbs are in range (-2^30,2^30), this cannot overflow an int32_t. Note that the right - * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is - * indeed the behavior of the right shift operator). */ - cond_add = r8 >> 31; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - r5 += modinfo->modulus.v[5] & cond_add; - r6 += modinfo->modulus.v[6] & cond_add; - r7 += modinfo->modulus.v[7] & cond_add; - r8 += modinfo->modulus.v[8] & cond_add; - cond_negate = sign >> 31; - r0 = (r0 ^ cond_negate) - cond_negate; - r1 = (r1 ^ cond_negate) - cond_negate; - r2 = (r2 ^ cond_negate) - cond_negate; - r3 = (r3 ^ cond_negate) - cond_negate; - r4 = (r4 ^ cond_negate) - cond_negate; - r5 = (r5 ^ cond_negate) - cond_negate; - r6 = (r6 ^ cond_negate) - cond_negate; - r7 = (r7 ^ cond_negate) - cond_negate; - r8 = (r8 ^ cond_negate) - cond_negate; - /* Propagate the top bits, to bring limbs back to range (-2^30,2^30). */ - r1 += r0 >> 30; r0 &= M30; - r2 += r1 >> 30; r1 &= M30; - r3 += r2 >> 30; r2 &= M30; - r4 += r3 >> 30; r3 &= M30; - r5 += r4 >> 30; r4 &= M30; - r6 += r5 >> 30; r5 &= M30; - r7 += r6 >> 30; r6 &= M30; - r8 += r7 >> 30; r7 &= M30; - - /* In a second step add the modulus again if the result is still negative, bringing r to range - * [0,modulus). */ - cond_add = r8 >> 31; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - r5 += modinfo->modulus.v[5] & cond_add; - r6 += modinfo->modulus.v[6] & cond_add; - r7 += modinfo->modulus.v[7] & cond_add; - r8 += modinfo->modulus.v[8] & cond_add; - /* And propagate again. */ - r1 += r0 >> 30; r0 &= M30; - r2 += r1 >> 30; r1 &= M30; - r3 += r2 >> 30; r2 &= M30; - r4 += r3 >> 30; r3 &= M30; - r5 += r4 >> 30; r4 &= M30; - r6 += r5 >> 30; r5 &= M30; - r7 += r6 >> 30; r6 &= M30; - r8 += r7 >> 30; r7 &= M30; - - r->v[0] = r0; - r->v[1] = r1; - r->v[2] = r2; - r->v[3] = r3; - r->v[4] = r4; - r->v[5] = r5; - r->v[6] = r6; - r->v[7] = r7; - r->v[8] = r8; - - VERIFY_CHECK(r0 >> 30 == 0); - VERIFY_CHECK(r1 >> 30 == 0); - VERIFY_CHECK(r2 >> 30 == 0); - VERIFY_CHECK(r3 >> 30 == 0); - VERIFY_CHECK(r4 >> 30 == 0); - VERIFY_CHECK(r5 >> 30 == 0); - VERIFY_CHECK(r6 >> 30 == 0); - VERIFY_CHECK(r7 >> 30 == 0); - VERIFY_CHECK(r8 >> 30 == 0); - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ -} - -/* Data type for transition matrices (see section 3 of explanation). - * - * t = [ u v ] - * [ q r ] - */ -typedef struct { - int32_t u, v, q, r; -} secp256k1_modinv32_trans2x2; - -/* Compute the transition matrix and zeta for 30 divsteps. - * - * Input: zeta: initial zeta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final zeta - * - * Implements the divsteps_n_matrix function from the explanation. - */ -static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { - /* u,v,q,r are the elements of the transformation matrix being built up, - * starting with the identity matrix. Semantically they are signed integers - * in range [-2^30,2^30], but here represented as unsigned mod 2^32. This - * permits left shifting (which is UB for negative numbers). The range - * being inside [-2^31,2^31) means that casting to signed works correctly. - */ - uint32_t u = 1, v = 0, q = 0, r = 1; - volatile uint32_t c1, c2; - uint32_t mask1, mask2, f = f0, g = g0, x, y, z; - int i; - - for (i = 0; i < 30; ++i) { - VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ - VERIFY_CHECK((u * f0 + v * g0) == f << i); - VERIFY_CHECK((q * f0 + r * g0) == g << i); - /* Compute conditional masks for (zeta < 0) and for (g & 1). */ - c1 = zeta >> 31; - mask1 = c1; - c2 = g & 1; - mask2 = -c2; - /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ mask1) - mask1; - y = (u ^ mask1) - mask1; - z = (v ^ mask1) - mask1; - /* Conditionally add x,y,z to g,q,r. */ - g += x & mask2; - q += y & mask2; - r += z & mask2; - /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */ - mask1 &= mask2; - /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ mask1) - 1; - /* Conditionally add g,q,r to f,u,v. */ - f += g & mask1; - u += q & mask1; - v += r & mask1; - /* Shifts */ - g >>= 1; - u <<= 1; - v <<= 1; - /* Bounds on zeta that follow from the bounds on iteration count (max 20*30 divsteps). */ - VERIFY_CHECK(zeta >= -601 && zeta <= 601); - } - /* Return data in t and return value. */ - t->u = (int32_t)u; - t->v = (int32_t)v; - t->q = (int32_t)q; - t->r = (int32_t)r; - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 30 of them will have determinant 2^30. */ - VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); - return zeta; -} - -/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */ -static const uint8_t secp256k1_modinv32_inv256[128] = { - 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, - 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, - 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, - 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, - 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, - 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, - 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, - 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, - 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, - 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, - 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 -}; - -/* Compute the transition matrix and eta for 30 divsteps (variable time). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final eta - * - * Implements the divsteps_n_matrix_var function from the explanation. - */ -static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { - /* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */ - uint32_t u = 1, v = 0, q = 0, r = 1; - uint32_t f = f0, g = g0, m; - uint16_t w; - int i = 30, limit, zeros; - - for (;;) { - /* Use a sentinel bit to count zeros only up to i. */ - zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ - g >>= zeros; - u <<= zeros; - v <<= zeros; - eta -= zeros; - i -= zeros; - /* We're done once we've done 30 divsteps. */ - if (i == 0) break; - VERIFY_CHECK((f & 1) == 1); - VERIFY_CHECK((g & 1) == 1); - VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); - VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); - /* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */ - VERIFY_CHECK(eta >= -751 && eta <= 751); - /* If eta is negative, negate it and replace f,g with g,-f. */ - if (eta < 0) { - uint32_t tmp; - eta = -eta; - tmp = f; f = g; g = -tmp; - tmp = u; u = q; q = -tmp; - tmp = v; v = r; r = -tmp; - } - /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more - * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 - * can be done as its sign will flip once that happens. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ - VERIFY_CHECK(limit > 0 && limit <= 30); - m = (UINT32_MAX >> (32 - limit)) & 255U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; - /* Do so. */ - g += f * w; - q += u * w; - r += v * w; - VERIFY_CHECK((g & m) == 0); - } - /* Return data in t and return value. */ - t->u = (int32_t)u; - t->v = (int32_t)v; - t->q = (int32_t)q; - t->r = (int32_t)r; - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 30 of them will have determinant 2^30. */ - VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); - return eta; -} - -/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track - * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because - * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign - * by applying the returned transformation matrix to it. The other bits of *jacp may - * change, but are meaningless. - * Return: final eta - */ -static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) { - /* Transformation matrix. */ - uint32_t u = 1, v = 0, q = 0, r = 1; - uint32_t f = f0, g = g0, m; - uint16_t w; - int i = 30, limit, zeros; - int jac = *jacp; - - for (;;) { - /* Use a sentinel bit to count zeros only up to i. */ - zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ - g >>= zeros; - u <<= zeros; - v <<= zeros; - eta -= zeros; - i -= zeros; - /* Update the bottom bit of jac: when dividing g by an odd power of 2, - * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ - jac ^= (zeros & ((f >> 1) ^ (f >> 2))); - /* We're done once we've done 30 posdivsteps. */ - if (i == 0) break; - VERIFY_CHECK((f & 1) == 1); - VERIFY_CHECK((g & 1) == 1); - VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); - VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); - /* If eta is negative, negate it and replace f,g with g,f. */ - if (eta < 0) { - uint32_t tmp; - eta = -eta; - /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign - * if both f and g are 3 mod 4. */ - jac ^= ((f & g) >> 1); - tmp = f; f = g; g = tmp; - tmp = u; u = q; q = tmp; - tmp = v; v = r; r = tmp; - } - /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more - * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 - * can be done as its sign will flip once that happens. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ - VERIFY_CHECK(limit > 0 && limit <= 30); - m = (UINT32_MAX >> (32 - limit)) & 255U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; - /* Do so. */ - g += f * w; - q += u * w; - r += v * w; - VERIFY_CHECK((g & m) == 0); - } - /* Return data in t and return value. */ - t->u = (int32_t)u; - t->v = (int32_t)v; - t->q = (int32_t)q; - t->r = (int32_t)r; - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, - * the aggregate of 30 of them will have determinant 2^30 or -2^30. */ - VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 || - (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30)); - *jacp = jac; - return eta; -} - -/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. - * - * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range - * (-2^30,2^30). - * - * This implements the update_de function from the explanation. - */ -static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp256k1_modinv32_signed30 *e, const secp256k1_modinv32_trans2x2 *t, const secp256k1_modinv32_modinfo* modinfo) { - const int32_t M30 = (int32_t)(UINT32_MAX >> 2); - const int32_t u = t->u, v = t->v, q = t->q, r = t->r; - int32_t di, ei, md, me, sd, se; - int64_t cd, ce; - int i; - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ - VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ - - /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ - sd = d->v[8] >> 31; - se = e->v[8] >> 31; - md = (u & sd) + (v & se); - me = (q & sd) + (r & se); - /* Begin computing t*[d,e]. */ - di = d->v[0]; - ei = e->v[0]; - cd = (int64_t)u * di + (int64_t)v * ei; - ce = (int64_t)q * di + (int64_t)r * ei; - /* Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. */ - md -= (modinfo->modulus_inv30 * (uint32_t)cd + md) & M30; - me -= (modinfo->modulus_inv30 * (uint32_t)ce + me) & M30; - /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ - cd += (int64_t)modinfo->modulus.v[0] * md; - ce += (int64_t)modinfo->modulus.v[0] * me; - /* Verify that the low 30 bits of the computation are indeed zero, and then throw them away. */ - VERIFY_CHECK(((int32_t)cd & M30) == 0); cd >>= 30; - VERIFY_CHECK(((int32_t)ce & M30) == 0); ce >>= 30; - /* Now iteratively compute limb i=1..8 of t*[d,e]+modulus*[md,me], and store them in output - * limb i-1 (shifting down by 30 bits). */ - for (i = 1; i < 9; ++i) { - di = d->v[i]; - ei = e->v[i]; - cd += (int64_t)u * di + (int64_t)v * ei; - ce += (int64_t)q * di + (int64_t)r * ei; - cd += (int64_t)modinfo->modulus.v[i] * md; - ce += (int64_t)modinfo->modulus.v[i] * me; - d->v[i - 1] = (int32_t)cd & M30; cd >>= 30; - e->v[i - 1] = (int32_t)ce & M30; ce >>= 30; - } - /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ - d->v[8] = (int32_t)cd; - e->v[8] = (int32_t)ce; - - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ -} - -/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. - * - * This implements the update_fg function from the explanation. - */ -static void secp256k1_modinv32_update_fg_30(secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { - const int32_t M30 = (int32_t)(UINT32_MAX >> 2); - const int32_t u = t->u, v = t->v, q = t->q, r = t->r; - int32_t fi, gi; - int64_t cf, cg; - int i; - /* Start computing t*[f,g]. */ - fi = f->v[0]; - gi = g->v[0]; - cf = (int64_t)u * fi + (int64_t)v * gi; - cg = (int64_t)q * fi + (int64_t)r * gi; - /* Verify that the bottom 30 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; - VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; - /* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting - * down by 30 bits). */ - for (i = 1; i < 9; ++i) { - fi = f->v[i]; - gi = g->v[i]; - cf += (int64_t)u * fi + (int64_t)v * gi; - cg += (int64_t)q * fi + (int64_t)r * gi; - f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; - g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; - } - /* What remains is limb 9 of t*[f,g]; store it as output limb 8. */ - f->v[8] = (int32_t)cf; - g->v[8] = (int32_t)cg; -} - -/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. - * - * Version that operates on a variable number of limbs in f and g. - * - * This implements the update_fg function from the explanation in modinv64_impl.h. - */ -static void secp256k1_modinv32_update_fg_30_var(int len, secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { - const int32_t M30 = (int32_t)(UINT32_MAX >> 2); - const int32_t u = t->u, v = t->v, q = t->q, r = t->r; - int32_t fi, gi; - int64_t cf, cg; - int i; - VERIFY_CHECK(len > 0); - /* Start computing t*[f,g]. */ - fi = f->v[0]; - gi = g->v[0]; - cf = (int64_t)u * fi + (int64_t)v * gi; - cg = (int64_t)q * fi + (int64_t)r * gi; - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; - VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; - /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting - * down by 30 bits). */ - for (i = 1; i < len; ++i) { - fi = f->v[i]; - gi = g->v[i]; - cf += (int64_t)u * fi + (int64_t)v * gi; - cg += (int64_t)q * fi + (int64_t)r * gi; - f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; - g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; - } - /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ - f->v[len - 1] = (int32_t)cf; - g->v[len - 1] = (int32_t)cg; -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ -static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ - secp256k1_modinv32_signed30 d = {{0}}; - secp256k1_modinv32_signed30 e = {{1}}; - secp256k1_modinv32_signed30 f = modinfo->modulus; - secp256k1_modinv32_signed30 g = *x; - int i; - int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */ - - /* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */ - for (i = 0; i < 20; ++i) { - /* Compute transition matrix and new zeta after 30 divsteps. */ - secp256k1_modinv32_trans2x2 t; - zeta = secp256k1_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv32_update_fg_30(&f, &g, &t); - - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* At this point sufficient iterations have been performed that g must have reached 0 - * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g - * values i.e. +/- 1, and d now contains +/- the modular inverse. */ - - /* g == 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || - secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || - (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0)); - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo); - *x = d; -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ -static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ - secp256k1_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}}; - secp256k1_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}}; - secp256k1_modinv32_signed30 f = modinfo->modulus; - secp256k1_modinv32_signed30 g = *x; -#ifdef VERIFY - int i = 0; -#endif - int j, len = 9; - int32_t eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */ - int32_t cond, fn, gn; - - /* Do iterations of 30 divsteps each until g=0. */ - while (1) { - /* Compute transition matrix and new eta after 30 divsteps. */ - secp256k1_modinv32_trans2x2 t; - eta = secp256k1_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ - - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); - /* If the bottom limb of g is 0, there is a chance g=0. */ - if (g.v[0] == 0) { - cond = 0; - /* Check if all other limbs are also 0. */ - for (j = 1; j < len; ++j) { - cond |= g.v[j]; - } - /* If so, we're done. */ - if (cond == 0) break; - } - - /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ - fn = f.v[len - 1]; - gn = g.v[len - 1]; - cond = ((int32_t)len - 2) >> 31; - cond |= fn ^ (fn >> 31); - cond |= gn ^ (gn >> 31); - /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ - if (cond == 0) { - f.v[len - 2] |= (uint32_t)fn << 30; - g.v[len - 2] |= (uint32_t)gn << 30; - --len; - } - - VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of - * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ - - /* g == 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || - secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || - (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0)); - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo); - *x = d; -} - -/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1. - * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */ -#ifdef VERIFY -#define JACOBI32_ITERATIONS 25 -#else -#define JACOBI32_ITERATIONS 50 -#endif - -/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ -static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { - /* Start with f=modulus, g=x, eta=-1. */ - secp256k1_modinv32_signed30 f = modinfo->modulus; - secp256k1_modinv32_signed30 g = *x; - int j, len = 9; - int32_t eta = -1; /* eta = -delta; delta is initially 1 */ - int32_t cond, fn, gn; - int jac = 0; - int count; - - /* The input limbs must all be non-negative. */ - VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0); - - /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we - * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or - * time out). */ - VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0); - - for (count = 0; count < JACOBI32_ITERATIONS; ++count) { - /* Compute transition matrix and new eta after 30 posdivsteps. */ - secp256k1_modinv32_trans2x2 t; - eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); - /* Update f,g using that transition matrix. */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); - /* If the bottom limb of f is 1, there is a chance that f=1. */ - if (f.v[0] == 1) { - cond = 0; - /* Check if the other limbs are also 0. */ - for (j = 1; j < len; ++j) { - cond |= f.v[j]; - } - /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */ - if (cond == 0) return 1 - 2*(jac & 1); - } - - /* Determine if len>1 and limb (len-1) of both f and g is 0. */ - fn = f.v[len - 1]; - gn = g.v[len - 1]; - cond = ((int32_t)len - 2) >> 31; - cond |= fn; - cond |= gn; - /* If so, reduce length. */ - if (cond == 0) --len; - - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ - VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ - return 0; -} - -#endif /* SECP256K1_MODINV32_IMPL_H */ diff --git a/external/secp256k1/src/modinv64.h b/external/secp256k1/src/modinv64.h deleted file mode 100644 index f4208e6c23..0000000000 --- a/external/secp256k1/src/modinv64.h +++ /dev/null @@ -1,47 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODINV64_H -#define SECP256K1_MODINV64_H - -#include "util.h" - -#ifndef SECP256K1_WIDEMUL_INT128 -#error "modinv64 requires 128-bit wide multiplication support" -#endif - -/* A signed 62-bit limb representation of integers. - * - * Its value is sum(v[i] * 2^(62*i), i=0..4). */ -typedef struct { - int64_t v[5]; -} secp256k1_modinv64_signed62; - -typedef struct { - /* The modulus in signed62 notation, must be odd and in [3, 2^256]. */ - secp256k1_modinv64_signed62 modulus; - - /* modulus^{-1} mod 2^62 */ - uint64_t modulus_inv62; -} secp256k1_modinv64_modinfo; - -/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). - * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of - * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. - * - * On output, all of x's limbs will be in [0, 2^62). - */ -static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); - -/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */ -static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); - -/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus - * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result - * cannot be computed. */ -static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); - -#endif /* SECP256K1_MODINV64_H */ diff --git a/external/secp256k1/src/modinv64_impl.h b/external/secp256k1/src/modinv64_impl.h deleted file mode 100644 index 548787bedf..0000000000 --- a/external/secp256k1/src/modinv64_impl.h +++ /dev/null @@ -1,780 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODINV64_IMPL_H -#define SECP256K1_MODINV64_IMPL_H - -#include "int128.h" -#include "modinv64.h" - -/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and - * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. - * - * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an - * implementation for N=62, using 62-bit signed limbs represented as int64_t. - */ - -/* Data type for transition matrices (see section 3 of explanation). - * - * t = [ u v ] - * [ q r ] - */ -typedef struct { - int64_t u, v, q, r; -} secp256k1_modinv64_trans2x2; - -#ifdef VERIFY -/* Helper function to compute the absolute value of an int64_t. - * (we don't use abs/labs/llabs as it depends on the int sizes). */ -static int64_t secp256k1_modinv64_abs(int64_t v) { - VERIFY_CHECK(v > INT64_MIN); - if (v < 0) return -v; - return v; -} - -static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; - -/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ -static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) { - const uint64_t M62 = UINT64_MAX >> 2; - secp256k1_int128 c, d; - int i; - secp256k1_i128_from_i64(&c, 0); - for (i = 0; i < 4; ++i) { - if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor); - r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62); - } - if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor); - secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c)); - VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d)); - r->v[4] = secp256k1_i128_to_i64(&c); -} - -/* Return -1 for ab*factor. A has alen limbs; b has 5. */ -static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, int alen, const secp256k1_modinv64_signed62 *b, int64_t factor) { - int i; - secp256k1_modinv64_signed62 am, bm; - secp256k1_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */ - secp256k1_modinv64_mul_62(&bm, b, 5, factor); - for (i = 0; i < 4; ++i) { - /* Verify that all but the top limb of a and b are normalized. */ - VERIFY_CHECK(am.v[i] >> 62 == 0); - VERIFY_CHECK(bm.v[i] >> 62 == 0); - } - for (i = 4; i >= 0; --i) { - if (am.v[i] < bm.v[i]) return -1; - if (am.v[i] > bm.v[i]) return 1; - } - return 0; -} - -/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */ -static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) { - secp256k1_int128 a; - secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); - if (secp256k1_i128_check_pow2(&a, n, 1)) return 1; - if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1; - return 0; -} -#endif - -/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus - * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the - * process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range - * [0,2^62). */ -static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; - volatile int64_t cond_add, cond_negate; - -#ifdef VERIFY - /* Verify that all limbs are in range (-2^62,2^62). */ - int i; - for (i = 0; i < 5; ++i) { - VERIFY_CHECK(r->v[i] >= -M62); - VERIFY_CHECK(r->v[i] <= M62); - } - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif - - /* In a first step, add the modulus if the input is negative, and then negate if requested. - * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input - * limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right - * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is - * indeed the behavior of the right shift operator). */ - cond_add = r4 >> 63; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - cond_negate = sign >> 63; - r0 = (r0 ^ cond_negate) - cond_negate; - r1 = (r1 ^ cond_negate) - cond_negate; - r2 = (r2 ^ cond_negate) - cond_negate; - r3 = (r3 ^ cond_negate) - cond_negate; - r4 = (r4 ^ cond_negate) - cond_negate; - /* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */ - r1 += r0 >> 62; r0 &= M62; - r2 += r1 >> 62; r1 &= M62; - r3 += r2 >> 62; r2 &= M62; - r4 += r3 >> 62; r3 &= M62; - - /* In a second step add the modulus again if the result is still negative, bringing - * r to range [0,modulus). */ - cond_add = r4 >> 63; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - /* And propagate again. */ - r1 += r0 >> 62; r0 &= M62; - r2 += r1 >> 62; r1 &= M62; - r3 += r2 >> 62; r2 &= M62; - r4 += r3 >> 62; r3 &= M62; - - r->v[0] = r0; - r->v[1] = r1; - r->v[2] = r2; - r->v[3] = r3; - r->v[4] = r4; - - VERIFY_CHECK(r0 >> 62 == 0); - VERIFY_CHECK(r1 >> 62 == 0); - VERIFY_CHECK(r2 >> 62 == 0); - VERIFY_CHECK(r3 >> 62 == 0); - VERIFY_CHECK(r4 >> 62 == 0); - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ -} - -/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). - * Note that the transformation matrix is scaled by 2^62 and not 2^59. - * - * Input: zeta: initial zeta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final zeta - * - * Implements the divsteps_n_matrix function from the explanation. - */ -static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { - /* u,v,q,r are the elements of the transformation matrix being built up, - * starting with the identity matrix times 8 (because the caller expects - * a result scaled by 2^62). Semantically they are signed integers - * in range [-2^62,2^62], but here represented as unsigned mod 2^64. This - * permits left shifting (which is UB for negative numbers). The range - * being inside [-2^63,2^63) means that casting to signed works correctly. - */ - uint64_t u = 8, v = 0, q = 0, r = 8; - volatile uint64_t c1, c2; - uint64_t mask1, mask2, f = f0, g = g0, x, y, z; - int i; - - for (i = 3; i < 62; ++i) { - VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ - VERIFY_CHECK((u * f0 + v * g0) == f << i); - VERIFY_CHECK((q * f0 + r * g0) == g << i); - /* Compute conditional masks for (zeta < 0) and for (g & 1). */ - c1 = zeta >> 63; - mask1 = c1; - c2 = g & 1; - mask2 = -c2; - /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ mask1) - mask1; - y = (u ^ mask1) - mask1; - z = (v ^ mask1) - mask1; - /* Conditionally add x,y,z to g,q,r. */ - g += x & mask2; - q += y & mask2; - r += z & mask2; - /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ - mask1 &= mask2; - /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ mask1) - 1; - /* Conditionally add g,q,r to f,u,v. */ - f += g & mask1; - u += q & mask1; - v += r & mask1; - /* Shifts */ - g >>= 1; - u <<= 1; - v <<= 1; - /* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */ - VERIFY_CHECK(zeta >= -591 && zeta <= 591); - } - /* Return data in t and return value. */ - t->u = (int64_t)u; - t->v = (int64_t)v; - t->q = (int64_t)q; - t->r = (int64_t)r; - - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial - * 8*identity (which has determinant 2^6) means the overall outputs has determinant - * 2^65. */ - VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0)); - - return zeta; -} - -/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final eta - * - * Implements the divsteps_n_matrix_var function from the explanation. - */ -static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { - /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ - uint64_t u = 1, v = 0, q = 0, r = 1; - uint64_t f = f0, g = g0, m; - uint32_t w; - int i = 62, limit, zeros; - - for (;;) { - /* Use a sentinel bit to count zeros only up to i. */ - zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ - g >>= zeros; - u <<= zeros; - v <<= zeros; - eta -= zeros; - i -= zeros; - /* We're done once we've done 62 divsteps. */ - if (i == 0) break; - VERIFY_CHECK((f & 1) == 1); - VERIFY_CHECK((g & 1) == 1); - VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); - VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); - /* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */ - VERIFY_CHECK(eta >= -745 && eta <= 745); - /* If eta is negative, negate it and replace f,g with g,-f. */ - if (eta < 0) { - uint64_t tmp; - eta = -eta; - tmp = f; f = g; g = -tmp; - tmp = u; u = q; q = -tmp; - tmp = v; v = r; r = -tmp; - /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled - * out (as we'd be done before that point), and no more than eta+1 can be done as its - * sign will flip again once that happens. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 6) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 63U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) - * bits. */ - w = (f * g * (f * f - 2)) & m; - } else { - /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as - * eta tends to be smaller here. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 4) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 15U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) - * bits. */ - w = f + (((f + 1) & 4) << 1); - w = (-w * g) & m; - } - g += f * w; - q += u * w; - r += v * w; - VERIFY_CHECK((g & m) == 0); - } - /* Return data in t and return value. */ - t->u = (int64_t)u; - t->v = (int64_t)v; - t->q = (int64_t)q; - t->r = (int64_t)r; - - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 62 of them will have determinant 2^62. */ - VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0)); - - return eta; -} - -/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track - * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because - * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign - * by applying the returned transformation matrix to it. The other bits of *jacp may - * change, but are meaningless. - * Return: final eta - */ -static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) { - /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ - uint64_t u = 1, v = 0, q = 0, r = 1; - uint64_t f = f0, g = g0, m; - uint32_t w; - int i = 62, limit, zeros; - int jac = *jacp; - - for (;;) { - /* Use a sentinel bit to count zeros only up to i. */ - zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ - g >>= zeros; - u <<= zeros; - v <<= zeros; - eta -= zeros; - i -= zeros; - /* Update the bottom bit of jac: when dividing g by an odd power of 2, - * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ - jac ^= (zeros & ((f >> 1) ^ (f >> 2))); - /* We're done once we've done 62 posdivsteps. */ - if (i == 0) break; - VERIFY_CHECK((f & 1) == 1); - VERIFY_CHECK((g & 1) == 1); - VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); - VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); - /* If eta is negative, negate it and replace f,g with g,f. */ - if (eta < 0) { - uint64_t tmp; - eta = -eta; - tmp = f; f = g; g = tmp; - tmp = u; u = q; q = tmp; - tmp = v; v = r; r = tmp; - /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign - * if both f and g are 3 mod 4. */ - jac ^= ((f & g) >> 1); - /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled - * out (as we'd be done before that point), and no more than eta+1 can be done as its - * sign will flip again once that happens. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 6) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 63U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) - * bits. */ - w = (f * g * (f * f - 2)) & m; - } else { - /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as - * eta tends to be smaller here. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 4) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 15U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) - * bits. */ - w = f + (((f + 1) & 4) << 1); - w = (-w * g) & m; - } - g += f * w; - q += u * w; - r += v * w; - VERIFY_CHECK((g & m) == 0); - } - /* Return data in t and return value. */ - t->u = (int64_t)u; - t->v = (int64_t)v; - t->q = (int64_t)q; - t->r = (int64_t)r; - - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, - * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ - VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1)); - - *jacp = jac; - return eta; -} - -/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. - * - * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range - * (-2^62,2^62). - * - * This implements the update_de function from the explanation. - */ -static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) { - const uint64_t M62 = UINT64_MAX >> 2; - const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; - const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int64_t md, me, sd, se; - secp256k1_int128 cd, ce; - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ - VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ - - /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ - sd = d4 >> 63; - se = e4 >> 63; - md = (u & sd) + (v & se); - me = (q & sd) + (r & se); - /* Begin computing t*[d,e]. */ - secp256k1_i128_mul(&cd, u, d0); - secp256k1_i128_accum_mul(&cd, v, e0); - secp256k1_i128_mul(&ce, q, d0); - secp256k1_i128_accum_mul(&ce, r, e0); - /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ - md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62; - me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62; - /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ - secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md); - secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me); - /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ - VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62); - VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62); - /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ - secp256k1_i128_accum_mul(&cd, u, d1); - secp256k1_i128_accum_mul(&cd, v, e1); - secp256k1_i128_accum_mul(&ce, q, d1); - secp256k1_i128_accum_mul(&ce, r, e1); - if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ - secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md); - secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me); - } - d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); - e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); - /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ - secp256k1_i128_accum_mul(&cd, u, d2); - secp256k1_i128_accum_mul(&cd, v, e2); - secp256k1_i128_accum_mul(&ce, q, d2); - secp256k1_i128_accum_mul(&ce, r, e2); - if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ - secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md); - secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me); - } - d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); - e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); - /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ - secp256k1_i128_accum_mul(&cd, u, d3); - secp256k1_i128_accum_mul(&cd, v, e3); - secp256k1_i128_accum_mul(&ce, q, d3); - secp256k1_i128_accum_mul(&ce, r, e3); - if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ - secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md); - secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me); - } - d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); - e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); - /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ - secp256k1_i128_accum_mul(&cd, u, d4); - secp256k1_i128_accum_mul(&cd, v, e4); - secp256k1_i128_accum_mul(&ce, q, d4); - secp256k1_i128_accum_mul(&ce, r, e4); - secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md); - secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me); - d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); - e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); - /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ - d->v[4] = secp256k1_i128_to_i64(&cd); - e->v[4] = secp256k1_i128_to_i64(&ce); - - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ -} - -/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. - * - * This implements the update_fg function from the explanation. - */ -static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { - const uint64_t M62 = UINT64_MAX >> 2; - const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; - const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - secp256k1_int128 cf, cg; - /* Start computing t*[f,g]. */ - secp256k1_i128_mul(&cf, u, f0); - secp256k1_i128_accum_mul(&cf, v, g0); - secp256k1_i128_mul(&cg, q, f0); - secp256k1_i128_accum_mul(&cg, r, g0); - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); - VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); - /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ - secp256k1_i128_accum_mul(&cf, u, f1); - secp256k1_i128_accum_mul(&cf, v, g1); - secp256k1_i128_accum_mul(&cg, q, f1); - secp256k1_i128_accum_mul(&cg, r, g1); - f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); - g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); - /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ - secp256k1_i128_accum_mul(&cf, u, f2); - secp256k1_i128_accum_mul(&cf, v, g2); - secp256k1_i128_accum_mul(&cg, q, f2); - secp256k1_i128_accum_mul(&cg, r, g2); - f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); - g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); - /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ - secp256k1_i128_accum_mul(&cf, u, f3); - secp256k1_i128_accum_mul(&cf, v, g3); - secp256k1_i128_accum_mul(&cg, q, f3); - secp256k1_i128_accum_mul(&cg, r, g3); - f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); - g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); - /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ - secp256k1_i128_accum_mul(&cf, u, f4); - secp256k1_i128_accum_mul(&cf, v, g4); - secp256k1_i128_accum_mul(&cg, q, f4); - secp256k1_i128_accum_mul(&cg, r, g4); - f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); - g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); - /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ - f->v[4] = secp256k1_i128_to_i64(&cf); - g->v[4] = secp256k1_i128_to_i64(&cg); -} - -/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. - * - * Version that operates on a variable number of limbs in f and g. - * - * This implements the update_fg function from the explanation. - */ -static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { - const uint64_t M62 = UINT64_MAX >> 2; - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int64_t fi, gi; - secp256k1_int128 cf, cg; - int i; - VERIFY_CHECK(len > 0); - /* Start computing t*[f,g]. */ - fi = f->v[0]; - gi = g->v[0]; - secp256k1_i128_mul(&cf, u, fi); - secp256k1_i128_accum_mul(&cf, v, gi); - secp256k1_i128_mul(&cg, q, fi); - secp256k1_i128_accum_mul(&cg, r, gi); - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); - VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); - /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting - * down by 62 bits). */ - for (i = 1; i < len; ++i) { - fi = f->v[i]; - gi = g->v[i]; - secp256k1_i128_accum_mul(&cf, u, fi); - secp256k1_i128_accum_mul(&cf, v, gi); - secp256k1_i128_accum_mul(&cg, q, fi); - secp256k1_i128_accum_mul(&cg, r, gi); - f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); - g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); - } - /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ - f->v[len - 1] = secp256k1_i128_to_i64(&cf); - g->v[len - 1] = secp256k1_i128_to_i64(&cg); -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ -static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ - secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; - secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; - secp256k1_modinv64_signed62 f = modinfo->modulus; - secp256k1_modinv64_signed62 g = *x; - int i; - int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */ - - /* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */ - for (i = 0; i < 10; ++i) { - /* Compute transition matrix and new zeta after 59 divsteps. */ - secp256k1_modinv64_trans2x2 t; - zeta = secp256k1_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv64_update_fg_62(&f, &g, &t); - - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* At this point sufficient iterations have been performed that g must have reached 0 - * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g - * values i.e. +/- 1, and d now contains +/- the modular inverse. */ - - /* g == 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || - secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || - (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0)); - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo); - *x = d; -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ -static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ - secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; - secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; - secp256k1_modinv64_signed62 f = modinfo->modulus; - secp256k1_modinv64_signed62 g = *x; -#ifdef VERIFY - int i = 0; -#endif - int j, len = 5; - int64_t eta = -1; /* eta = -delta; delta is initially 1 */ - int64_t cond, fn, gn; - - /* Do iterations of 62 divsteps each until g=0. */ - while (1) { - /* Compute transition matrix and new eta after 62 divsteps. */ - secp256k1_modinv64_trans2x2 t; - eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); - /* If the bottom limb of g is zero, there is a chance that g=0. */ - if (g.v[0] == 0) { - cond = 0; - /* Check if the other limbs are also 0. */ - for (j = 1; j < len; ++j) { - cond |= g.v[j]; - } - /* If so, we're done. */ - if (cond == 0) break; - } - - /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ - fn = f.v[len - 1]; - gn = g.v[len - 1]; - cond = ((int64_t)len - 2) >> 63; - cond |= fn ^ (fn >> 63); - cond |= gn ^ (gn >> 63); - /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ - if (cond == 0) { - f.v[len - 2] |= (uint64_t)fn << 62; - g.v[len - 2] |= (uint64_t)gn << 62; - --len; - } - - VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of - * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ - - /* g == 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || - secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || - (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0)); - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo); - *x = d; -} - -/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1. - * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */ -#ifdef VERIFY -#define JACOBI64_ITERATIONS 12 -#else -#define JACOBI64_ITERATIONS 25 -#endif - -/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ -static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { - /* Start with f=modulus, g=x, eta=-1. */ - secp256k1_modinv64_signed62 f = modinfo->modulus; - secp256k1_modinv64_signed62 g = *x; - int j, len = 5; - int64_t eta = -1; /* eta = -delta; delta is initially 1 */ - int64_t cond, fn, gn; - int jac = 0; - int count; - - /* The input limbs must all be non-negative. */ - VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0); - - /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we - * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or - * time out). */ - VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0); - - for (count = 0; count < JACOBI64_ITERATIONS; ++count) { - /* Compute transition matrix and new eta after 62 posdivsteps. */ - secp256k1_modinv64_trans2x2 t; - eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); - /* Update f,g using that transition matrix. */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - - secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); - /* If the bottom limb of f is 1, there is a chance that f=1. */ - if (f.v[0] == 1) { - cond = 0; - /* Check if the other limbs are also 0. */ - for (j = 1; j < len; ++j) { - cond |= f.v[j]; - } - /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */ - if (cond == 0) return 1 - 2*(jac & 1); - } - - /* Determine if len>1 and limb (len-1) of both f and g is 0. */ - fn = f.v[len - 1]; - gn = g.v[len - 1]; - cond = ((int64_t)len - 2) >> 63; - cond |= fn; - cond |= gn; - /* If so, reduce length. */ - if (cond == 0) --len; - - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ - VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ - } - - /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ - return 0; -} - -#endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/external/secp256k1/src/modules/ecdh/Makefile.am.include b/external/secp256k1/src/modules/ecdh/Makefile.am.include deleted file mode 100644 index 7f7f95f1fd..0000000000 --- a/external/secp256k1/src/modules/ecdh/Makefile.am.include +++ /dev/null @@ -1,4 +0,0 @@ -include_HEADERS += include/secp256k1_ecdh.h -noinst_HEADERS += src/modules/ecdh/main_impl.h -noinst_HEADERS += src/modules/ecdh/tests_impl.h -noinst_HEADERS += src/modules/ecdh/bench_impl.h diff --git a/external/secp256k1/src/modules/ecdh/bench_impl.h b/external/secp256k1/src/modules/ecdh/bench_impl.h deleted file mode 100644 index c23aaa94d1..0000000000 --- a/external/secp256k1/src/modules/ecdh/bench_impl.h +++ /dev/null @@ -1,57 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_BENCH_H -#define SECP256K1_MODULE_ECDH_BENCH_H - -#include "../../../include/secp256k1_ecdh.h" - -typedef struct { - secp256k1_context *ctx; - secp256k1_pubkey point; - unsigned char scalar[32]; -} bench_ecdh_data; - -static void bench_ecdh_setup(void* arg) { - int i; - bench_ecdh_data *data = (bench_ecdh_data*)arg; - const unsigned char point[] = { - 0x03, - 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, - 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, - 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, - 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f - }; - - for (i = 0; i < 32; i++) { - data->scalar[i] = i + 1; - } - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); -} - -static void bench_ecdh(void* arg, int iters) { - int i; - unsigned char res[32]; - bench_ecdh_data *data = (bench_ecdh_data*)arg; - - for (i = 0; i < iters; i++) { - CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); - } -} - -static void run_ecdh_bench(int iters, int argc, char** argv) { - bench_ecdh_data data; - int d = argc == 1; - - /* create a context with no capabilities */ - data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); - - if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters); - - secp256k1_context_destroy(data.ctx); -} - -#endif /* SECP256K1_MODULE_ECDH_BENCH_H */ diff --git a/external/secp256k1/src/modules/ecdh/main_impl.h b/external/secp256k1/src/modules/ecdh/main_impl.h deleted file mode 100644 index 842b5359e3..0000000000 --- a/external/secp256k1/src/modules/ecdh/main_impl.h +++ /dev/null @@ -1,74 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_MAIN_H -#define SECP256K1_MODULE_ECDH_MAIN_H - -#include "../../../include/secp256k1_ecdh.h" -#include "../../ecmult_const_impl.h" - -static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { - unsigned char version = (y32[31] & 0x01) | 0x02; - secp256k1_sha256 sha; - (void)data; - - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, &version, 1); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); - secp256k1_sha256_clear(&sha); - - return 1; -} - -const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; -const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; - -int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) { - int ret = 0; - int overflow = 0; - secp256k1_gej res; - secp256k1_ge pt; - secp256k1_scalar s; - unsigned char x[32]; - unsigned char y[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(point != NULL); - ARG_CHECK(scalar != NULL); - - if (hashfp == NULL) { - hashfp = secp256k1_ecdh_hash_function_default; - } - - secp256k1_pubkey_load(ctx, &pt, point); - secp256k1_scalar_set_b32(&s, scalar, &overflow); - - overflow |= secp256k1_scalar_is_zero(&s); - secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); - - secp256k1_ecmult_const(&res, &pt, &s); - secp256k1_ge_set_gej(&pt, &res); - - /* Compute a hash of the point */ - secp256k1_fe_normalize(&pt.x); - secp256k1_fe_normalize(&pt.y); - secp256k1_fe_get_b32(x, &pt.x); - secp256k1_fe_get_b32(y, &pt.y); - - ret = hashfp(output, x, y, data); - - secp256k1_memclear(x, sizeof(x)); - secp256k1_memclear(y, sizeof(y)); - secp256k1_scalar_clear(&s); - secp256k1_ge_clear(&pt); - secp256k1_gej_clear(&res); - - return !!ret & !overflow; -} - -#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/external/secp256k1/src/modules/ecdh/tests_impl.h b/external/secp256k1/src/modules/ecdh/tests_impl.h deleted file mode 100644 index 3c3acdaf8c..0000000000 --- a/external/secp256k1/src/modules/ecdh/tests_impl.h +++ /dev/null @@ -1,152 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_TESTS_H -#define SECP256K1_MODULE_ECDH_TESTS_H - -static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { - (void)output; - (void)x; - (void)y; - (void)data; - return 0; -} - -static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { - (void)data; - /* Save x and y as uncompressed public key */ - output[0] = 0x04; - memcpy(output + 1, x, 32); - memcpy(output + 33, y, 32); - return 1; -} - -static void test_ecdh_api(void) { - secp256k1_pubkey point; - unsigned char res[32]; - unsigned char s_one[32] = { 0 }; - s_one[31] = 1; - - CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); - - /* Check all NULLs are detected */ - CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL)); - CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); -} - -static void test_ecdh_generator_basepoint(void) { - unsigned char s_one[32] = { 0 }; - secp256k1_pubkey point[2]; - int i; - - s_one[31] = 1; - /* Check against pubkey creation when the basepoint is the generator */ - for (i = 0; i < 2 * COUNT; ++i) { - secp256k1_sha256 sha; - unsigned char s_b32[32]; - unsigned char output_ecdh[65]; - unsigned char output_ser[32]; - unsigned char point_ser[65]; - size_t point_ser_len = sizeof(point_ser); - secp256k1_scalar s; - - testutil_random_scalar_order(&s); - secp256k1_scalar_get_b32(s_b32, &s); - - CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1); - - /* compute using ECDH function with custom hash function */ - CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); - /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); - /* compare */ - CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); - - /* compute using ECDH function with default hash function */ - CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); - /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, point_ser, point_ser_len); - secp256k1_sha256_finalize(&sha, output_ser); - /* compare */ - CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0); - } -} - -static void test_bad_scalar(void) { - unsigned char s_zero[32] = { 0 }; - unsigned char s_overflow[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 - }; - unsigned char s_rand[32] = { 0 }; - unsigned char output[32]; - secp256k1_scalar rand; - secp256k1_pubkey point; - - /* Create random point */ - testutil_random_scalar_order(&rand); - secp256k1_scalar_get_b32(s_rand, &rand); - CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1); - - /* Try to multiply it by bad values */ - CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0); - CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0); - /* ...and a good one */ - s_overflow[31] -= 1; - CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1); - - /* Hash function failure results in ecdh failure */ - CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); -} - -/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ -static void test_result_basepoint(void) { - secp256k1_pubkey point; - secp256k1_scalar rand; - unsigned char s[32]; - unsigned char s_inv[32]; - unsigned char out[32]; - unsigned char out_inv[32]; - unsigned char out_base[32]; - int i; - - unsigned char s_one[32] = { 0 }; - s_one[31] = 1; - CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); - CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1); - - for (i = 0; i < 2 * COUNT; i++) { - testutil_random_scalar_order(&rand); - secp256k1_scalar_get_b32(s, &rand); - secp256k1_scalar_inverse(&rand, &rand); - secp256k1_scalar_get_b32(s_inv, &rand); - - CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1); - CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1); - CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0); - - CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1); - CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1); - CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0); - } -} - -static void run_ecdh_tests(void) { - test_ecdh_api(); - test_ecdh_generator_basepoint(); - test_bad_scalar(); - test_result_basepoint(); -} - -#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/external/secp256k1/src/modules/ellswift/Makefile.am.include b/external/secp256k1/src/modules/ellswift/Makefile.am.include deleted file mode 100644 index 8251231ea3..0000000000 --- a/external/secp256k1/src/modules/ellswift/Makefile.am.include +++ /dev/null @@ -1,5 +0,0 @@ -include_HEADERS += include/secp256k1_ellswift.h -noinst_HEADERS += src/modules/ellswift/bench_impl.h -noinst_HEADERS += src/modules/ellswift/main_impl.h -noinst_HEADERS += src/modules/ellswift/tests_impl.h -noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h diff --git a/external/secp256k1/src/modules/ellswift/bench_impl.h b/external/secp256k1/src/modules/ellswift/bench_impl.h deleted file mode 100644 index b16a3a3687..0000000000 --- a/external/secp256k1/src/modules/ellswift/bench_impl.h +++ /dev/null @@ -1,106 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H -#define SECP256K1_MODULE_ELLSWIFT_BENCH_H - -#include "../../../include/secp256k1_ellswift.h" - -typedef struct { - secp256k1_context *ctx; - secp256k1_pubkey point[256]; - unsigned char rnd64[64]; -} bench_ellswift_data; - -static void bench_ellswift_setup(void *arg) { - int i; - bench_ellswift_data *data = (bench_ellswift_data*)arg; - static const unsigned char init[64] = { - 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68, - 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e, - 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79, - 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21, - 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f, - 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30, - 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85, - 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc - }; - memcpy(data->rnd64, init, 64); - for (i = 0; i < 256; ++i) { - int j; - CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64)); - for (j = 0; j < 64; ++j) { - data->rnd64[j] += 1; - } - } - CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16)); -} - -static void bench_ellswift_encode(void *arg, int iters) { - int i; - bench_ellswift_data *data = (bench_ellswift_data*)arg; - - for (i = 0; i < iters; i++) { - CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16)); - } -} - -static void bench_ellswift_create(void *arg, int iters) { - int i; - bench_ellswift_data *data = (bench_ellswift_data*)arg; - - for (i = 0; i < iters; i++) { - unsigned char buf[64]; - CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32)); - memcpy(data->rnd64, buf, 64); - } -} - -static void bench_ellswift_decode(void *arg, int iters) { - int i; - secp256k1_pubkey out; - size_t len; - bench_ellswift_data *data = (bench_ellswift_data*)arg; - - for (i = 0; i < iters; i++) { - CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1); - len = 33; - CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED)); - } -} - -static void bench_ellswift_xdh(void *arg, int iters) { - int i; - bench_ellswift_data *data = (bench_ellswift_data*)arg; - - for (i = 0; i < iters; i++) { - int party = i & 1; - CHECK(secp256k1_ellswift_xdh(data->ctx, - data->rnd64 + (i % 33), - data->rnd64, - data->rnd64, - data->rnd64 + ((i + 16) % 33), - party, - secp256k1_ellswift_xdh_hash_function_bip324, - NULL) == 1); - } -} - -void run_ellswift_bench(int iters, int argc, char **argv) { - bench_ellswift_data data; - int d = argc == 1; - - /* create a context with signing capabilities */ - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - - if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters); - - secp256k1_context_destroy(data.ctx); -} - -#endif diff --git a/external/secp256k1/src/modules/ellswift/main_impl.h b/external/secp256k1/src/modules/ellswift/main_impl.h deleted file mode 100644 index 745a969139..0000000000 --- a/external/secp256k1/src/modules/ellswift/main_impl.h +++ /dev/null @@ -1,592 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H -#define SECP256K1_MODULE_ELLSWIFT_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_ellswift.h" -#include "../../eckey.h" -#include "../../hash.h" - -/** c1 = (sqrt(-3)-1)/2 */ -static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); -/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */ -static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee); -/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */ -static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef); -/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */ -static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41); - -/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */ -static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) { - /* The implemented algorithm is the following (all operations in GF(p)): - * - * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852. - * - If u = 0, set u = 1. - * - If t = 0, set t = 1. - * - If u^3+7+t^2 = 0, set t = 2*t. - * - Let X = (u^3+7-t^2)/(2*t). - * - Let Y = (X+t)/(c0*u). - * - If x3 = u+4*Y^2 is a valid x coordinate, return it. - * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. - * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate). - * - * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get: - * - * - Let c0 = ... - * - If u = 0, set u = 1. - * - If t = 0, set t = 1. - * - Let s = t^2 - * - Let g = u^3+7 - * - If g+s = 0, set t = 2*t, s = 4*s - * - Let X = (g-s)/(2*t). - * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u). - * - If x3 = u+4*Y^2 is a valid x coordinate, return it. - * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. - * - Return x1 = -(x2+u). - * - * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This - * means X and Y do not need to be evaluated explicitly anymore. - * - * - ... - * - If g+s = 0, set s = 4*s. - * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it. - * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it. - * - Return x1 = -(x2+u). - * - * Simplifying x2 using 2 additional constants: - * - * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. - * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. - * - ... - * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. - * - ... - * - * Writing x3 as a fraction: - * - * - ... - * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ... - * - ... - - * Overall, we get: - * - * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. - * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. - * - If u = 0, set u = 1. - * - If t = 0, set s = 1, else set s = t^2. - * - Let g = u^3+7. - * - If g+s = 0, set s = 4*s. - * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it. - * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. - * - Return x1 = -(x2+u). - */ - secp256k1_fe u1, s, g, p, d, n, l; - u1 = *u; - if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one; - secp256k1_fe_sqr(&s, t); - if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one; - secp256k1_fe_sqr(&l, &u1); /* l = u^2 */ - secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */ - secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */ - p = g; /* p = g */ - secp256k1_fe_add(&p, &s); /* p = g+s */ - if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) { - secp256k1_fe_mul_int(&s, 4); - /* Recompute p = g+s */ - p = g; /* p = g */ - secp256k1_fe_add(&p, &s); /* p = g+s */ - } - secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */ - secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */ - secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */ - secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */ - secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */ - secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */ - if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) { - /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */ - *xn = n; - *xd = d; - return; - } - *xd = p; - secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */ - secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */ - secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */ - secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */ - /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed, - * which we already have computed above. This could be deduplicated. */ - if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) { - /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */ - *xn = n; - return; - } - secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */ - secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */ - secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */ - - VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p)); - /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */ -} - -/** Decode ElligatorSwift encoding (u, t) to X coordinate. */ -static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) { - secp256k1_fe xn, xd; - secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t); - secp256k1_fe_inv_var(&xd, &xd); - secp256k1_fe_mul(x, &xn, &xd); -} - -/** Decode ElligatorSwift encoding (u, t) to point P. */ -static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) { - secp256k1_fe x; - secp256k1_ellswift_xswiftec_var(&x, u, t); - secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t)); -} - -/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x. - * - * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also - * fewer, or none at all. Each such partial inverse can be accessed individually using a - * distinct input argument c (in range 0-7), and some or all of these may return failure. - * The following guarantees exist: - * - Given (x, u), no two distinct c values give the same successful result t. - * - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var. - * - Given (x, u), all t values that map back to x can be reached by combining the - * successful results from this function over all c values, with the exception of: - * - this function cannot be called with u=0 - * - no result with t=0 will be returned - * - no result for which u^3 + t^2 + 7 = 0 will be returned. - * - * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then - * using the low and high bits to pick signs of square roots) is to match the paper's - * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through - * c=7 are copies of those with an additional negation of sqrt(w). - */ -static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) { - /* The implemented algorithm is this (all arithmetic, except involving c, is mod p): - * - * - If (c & 2) = 0: - * - If (-x-u) is a valid X coordinate, fail. - * - Let s=-(u^3+7)/(u^2+u*x+x^2). - * - If s is not square, fail. - * - Let v=x. - * - If (c & 2) = 2: - * - Let s=x-u. - * - If s is not square, fail. - * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. - * - If (c & 1) = 1 and r = 0, fail. - * - If s=0, fail. - * - Let v=(r/s-u)/2. - * - Let w=sqrt(s). - * - If (c & 5) = 0: return -w*(c3*u + v). - * - If (c & 5) = 1: return w*(c4*u + v). - * - If (c & 5) = 4: return w*(c3*u + v). - * - If (c & 5) = 5: return -w*(c4*u + v). - */ - secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q; - int ret; - - secp256k1_fe_normalize_weak(&x); - secp256k1_fe_normalize_weak(&u); - - VERIFY_CHECK(c >= 0 && c < 8); - VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x)); - - if (!(c & 2)) { - /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or - * c=4) formula, or x2 (if c=1 or c=5) formula. */ - - /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips - * back under the x3 formula instead (which has priority over x1 and x2, so the decoding - * would not match x). */ - m = x; /* m = x */ - secp256k1_fe_add(&m, &u); /* m = u+x */ - secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */ - /* Test if (-u-x) is a valid X coordinate. If so, fail. */ - if (secp256k1_ge_x_on_curve_var(&m)) return 0; - - /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */ - secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */ - secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */ - secp256k1_fe_mul(&m, &u, &x); /* m = u*x */ - secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */ - - /* Note that at this point, s = 0 is impossible. If it were the case: - * s = -(u^2 + u*x + x^2) = 0 - * => u^2 + u*x + x^2 = 0 - * => (u + 2*x) * (u^2 + u*x + x^2) = 0 - * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0 - * => (x + u)^3 + x^3 = 0 - * => x^3 = -(x + u)^3 - * => x^3 + B = (-u - x)^3 + B - * - * However, we know x^3 + B is square (because x is on the curve) and - * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m) - * test above would have failed). This is a contradiction, and thus the - * assumption s=0 is false. */ - VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s)); - - /* If s is not square, fail. We have not fully computed s yet, but s is square iff - * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is - * nonzero). */ - secp256k1_fe_sqr(&g, &u); /* g = u^2 */ - secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ - secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */ - secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */ - if (!secp256k1_fe_is_square_var(&m)) return 0; - - /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */ - secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */ - secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */ - - /* Let v = x. */ - v = x; - } else { - /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */ - - /* Let s = x-u. */ - secp256k1_fe_negate(&m, &u, 1); /* m = -u */ - s = m; /* s = -u */ - secp256k1_fe_add(&s, &x); /* s = x-u */ - - /* If s is not square, fail. */ - if (!secp256k1_fe_is_square_var(&s)) return 0; - - /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */ - secp256k1_fe_sqr(&g, &u); /* g = u^2 */ - secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */ - secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */ - secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ - secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */ - secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */ - secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */ - secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */ - if (!secp256k1_fe_is_square_var(&q)) return 0; - ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */ -#ifdef VERIFY - VERIFY_CHECK(ret); -#else - (void)ret; -#endif - - /* If (c & 1) = 1 and r = 0, fail. */ - if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0; - - /* If s = 0, fail. */ - if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0; - - /* Let v = (r/s-u)/2. */ - secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */ - secp256k1_fe_mul(&v, &v, &r); /* v = r/s */ - secp256k1_fe_add(&v, &m); /* v = r/s-u */ - secp256k1_fe_half(&v); /* v = (r/s-u)/2 */ - } - - /* Let w = sqrt(s). */ - ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */ - VERIFY_CHECK(ret); - - /* Return logic. */ - if ((c & 5) == 0 || (c & 5) == 5) { - secp256k1_fe_negate(&m, &m, 1); /* m = -w */ - } - /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */ - secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3); - /* u = {c4 if c&1=1; c3 otherwise}*u */ - secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */ - secp256k1_fe_mul(t, &m, &u); - return 1; -} - -/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt). - * - * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness. - * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a - * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */ -static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) { - secp256k1_sha256 hash = *hasher; - unsigned char buf4[4]; -#ifdef VERIFY - size_t blocks = hash.bytes >> 6; -#endif - buf4[0] = cnt; - buf4[1] = cnt >> 8; - buf4[2] = cnt >> 16; - buf4[3] = cnt >> 24; - secp256k1_sha256_write(&hash, buf4, 4); - secp256k1_sha256_finalize(&hash, out32); - - /* Writing and finalizing together should trigger exactly one SHA256 compression. */ - VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); -} - -/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate. - * - * u32 is the 32-byte big endian encoding of u; t is the output field element t that still - * needs encoding. - * - * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */ -static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) { - /* Pool of 3-bit branch values. */ - unsigned char branch_hash[32]; - /* Number of 3-bit values in branch_hash left. */ - int branches_left = 0; - /* Field elements u and branch values are extracted from RNG based on hasher for consecutive - * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64 - * cnt values that follow are used to generate field elements u. cnt==65 (and multiples - * thereof) are used to repopulate the pool and start over, if that were ever necessary. - * On average, 4 iterations are needed. */ - uint32_t cnt = 0; - while (1) { - int branch; - secp256k1_fe u; - /* If the pool of branch values is empty, populate it. */ - if (branches_left == 0) { - secp256k1_ellswift_prng(branch_hash, hasher, cnt++); - branches_left = 64; - } - /* Take a 3-bit branch value from the branch pool (top bit is discarded). */ - --branches_left; - branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7; - /* Compute a new u value by hashing. */ - secp256k1_ellswift_prng(u32, hasher, cnt++); - /* overflow is not a problem (we prefer uniform u32 over uniform u). */ - secp256k1_fe_set_b32_mod(&u, u32); - /* Since u is the output of a hash, it should practically never be 0. We could apply the - * u=0 to u=1 correction here too to deal with that case still, but it's such a low - * probability event that we do not bother. */ - VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u)); - - /* Find a remainder t, and return it if found. */ - if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break; - } -} - -/** Find an ElligatorSwift encoding (u, t) for point P. - * - * This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p - * as input, and returns an encoding that matches the provided Y coordinate rather than a random - * one. - */ -static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) { - secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher); - secp256k1_fe_normalize_var(t); - if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) { - secp256k1_fe_negate(t, t, 1); - secp256k1_fe_normalize_var(t); - } -} - -/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */ -static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); - hash->s[0] = 0xd1a6524bul; - hash->s[1] = 0x028594b3ul; - hash->s[2] = 0x96e42f4eul; - hash->s[3] = 0x1037a177ul; - hash->s[4] = 0x1b8fcb8bul; - hash->s[5] = 0x56023885ul; - hash->s[6] = 0x2560ede1ul; - hash->s[7] = 0xd626b715ul; - - hash->bytes = 64; -} - -int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) { - secp256k1_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(ell64 != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(rnd32 != NULL); - - if (secp256k1_pubkey_load(ctx, &p, pubkey)) { - secp256k1_fe t; - unsigned char p64[64] = {0}; - size_t ser_size; - int ser_ret; - secp256k1_sha256 hash; - - /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using - * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ - secp256k1_ellswift_sha256_init_encode(&hash); - ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1); -#ifdef VERIFY - VERIFY_CHECK(ser_ret && ser_size == 33); -#else - (void)ser_ret; -#endif - secp256k1_sha256_write(&hash, p64, sizeof(p64)); - secp256k1_sha256_write(&hash, rnd32, 32); - - /* Compute ElligatorSwift encoding and construct output. */ - secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ - secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ - return 1; - } - /* Only reached in case the provided pubkey is invalid. */ - memset(ell64, 0, 64); - return 0; -} - -/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */ -static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); - hash->s[0] = 0xd29e1bf5ul; - hash->s[1] = 0xf7025f42ul; - hash->s[2] = 0x9b024773ul; - hash->s[3] = 0x094cb7d5ul; - hash->s[4] = 0xe59ed789ul; - hash->s[5] = 0x03bc9786ul; - hash->s[6] = 0x68335b35ul; - hash->s[7] = 0x4e363b53ul; - - hash->bytes = 64; -} - -int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) { - secp256k1_ge p; - secp256k1_fe t; - secp256k1_sha256 hash; - secp256k1_scalar seckey_scalar; - int ret; - static const unsigned char zero32[32] = {0}; - - /* Sanity check inputs. */ - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(ell64 != NULL); - memset(ell64, 0, 64); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey32 != NULL); - - /* Compute (affine) public key */ - ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32); - secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */ - secp256k1_fe_normalize_var(&p.x); - secp256k1_fe_normalize_var(&p.y); - - /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), - * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */ - secp256k1_ellswift_sha256_init_create(&hash); - secp256k1_sha256_write(&hash, seckey32, 32); - secp256k1_sha256_write(&hash, zero32, sizeof(zero32)); - secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ - if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32); - - /* Compute ElligatorSwift encoding and construct output. */ - secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ - secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ - - secp256k1_memczero(ell64, 64, !ret); - secp256k1_scalar_clear(&seckey_scalar); - - return ret; -} - -int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) { - secp256k1_fe u, t; - secp256k1_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(ell64 != NULL); - - secp256k1_fe_set_b32_mod(&u, ell64); - secp256k1_fe_set_b32_mod(&t, ell64 + 32); - secp256k1_fe_normalize_var(&t); - secp256k1_ellswift_swiftec_var(&p, &u, &t); - secp256k1_pubkey_save(pubkey, &p); - return 1; -} - -static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { - secp256k1_sha256 sha; - - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, data, 64); - secp256k1_sha256_write(&sha, ell_a64, 64); - secp256k1_sha256_write(&sha, ell_b64, 64); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); - secp256k1_sha256_clear(&sha); - - return 1; -} - -/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ -static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); - hash->s[0] = 0x8c12d730ul; - hash->s[1] = 0x827bd392ul; - hash->s[2] = 0x9e4fb2eeul; - hash->s[3] = 0x207b373eul; - hash->s[4] = 0x2292bd7aul; - hash->s[5] = 0xaa5441bcul; - hash->s[6] = 0x15c3779ful; - hash->s[7] = 0xcfb52549ul; - - hash->bytes = 64; -} - -static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { - secp256k1_sha256 sha; - - (void)data; - - secp256k1_ellswift_sha256_init_bip324(&sha); - secp256k1_sha256_write(&sha, ell_a64, 64); - secp256k1_sha256_write(&sha, ell_b64, 64); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); - secp256k1_sha256_clear(&sha); - - return 1; -} - -const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; -const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; - -int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) { - int ret = 0; - int overflow; - secp256k1_scalar s; - secp256k1_fe xn, xd, px, u, t; - unsigned char sx[32]; - const unsigned char* theirs64; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(ell_a64 != NULL); - ARG_CHECK(ell_b64 != NULL); - ARG_CHECK(seckey32 != NULL); - ARG_CHECK(hashfp != NULL); - - /* Load remote public key (as fraction). */ - theirs64 = party ? ell_a64 : ell_b64; - secp256k1_fe_set_b32_mod(&u, theirs64); - secp256k1_fe_set_b32_mod(&t, theirs64 + 32); - secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t); - - /* Load private key (using one if invalid). */ - secp256k1_scalar_set_b32(&s, seckey32, &overflow); - overflow = secp256k1_scalar_is_zero(&s); - secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); - - /* Compute shared X coordinate. */ - secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1); - secp256k1_fe_normalize(&px); - secp256k1_fe_get_b32(sx, &px); - - /* Invoke hasher */ - ret = hashfp(output, sx, ell_a64, ell_b64, data); - - secp256k1_memclear(sx, sizeof(sx)); - secp256k1_fe_clear(&px); - secp256k1_scalar_clear(&s); - - return !!ret & !overflow; -} - -#endif diff --git a/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h b/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h deleted file mode 100644 index 839c24aee4..0000000000 --- a/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h +++ /dev/null @@ -1,39 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H -#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H - -#include "../../../include/secp256k1_ellswift.h" -#include "main_impl.h" - -static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256k1_ge *group) { - int i; - - /* Note that SwiftEC/ElligatorSwift are inherently curve operations, not - * group operations, and this test only checks the curve points which are in - * a tiny subgroup. In that sense it can't be really seen as exhaustive as - * it doesn't (and for computational reasons obviously cannot) test the - * entire domain ellswift operates under. */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_scalar scalar_i; - unsigned char sec32[32]; - unsigned char ell64[64]; - secp256k1_pubkey pub_decoded; - secp256k1_ge ge_decoded; - - /* Construct ellswift pubkey from exhaustive loop scalar i. */ - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_scalar_get_b32(sec32, &scalar_i); - CHECK(secp256k1_ellswift_create(ctx, ell64, sec32, NULL)); - - /* Decode ellswift pubkey and check that it matches the precomputed group element. */ - secp256k1_ellswift_decode(ctx, &pub_decoded, ell64); - secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded); - CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i])); - } -} - -#endif diff --git a/external/secp256k1/src/modules/ellswift/tests_impl.h b/external/secp256k1/src/modules/ellswift/tests_impl.h deleted file mode 100644 index 3c314c9b50..0000000000 --- a/external/secp256k1/src/modules/ellswift/tests_impl.h +++ /dev/null @@ -1,436 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H -#define SECP256K1_MODULE_ELLSWIFT_TESTS_H - -#include "../../../include/secp256k1_ellswift.h" - -struct ellswift_xswiftec_inv_test { - int enc_bitmap; - secp256k1_fe u; - secp256k1_fe x; - secp256k1_fe encs[8]; -}; - -struct ellswift_decode_test { - unsigned char enc[64]; - secp256k1_fe x; - int odd_y; -}; - -struct ellswift_xdh_test { - unsigned char priv_ours[32]; - unsigned char ellswift_ours[64]; - unsigned char ellswift_theirs[64]; - int initiating; - unsigned char shared_secret[32]; -}; - -/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324 - * test vectors. Created using an independent implementation, and tested decoding against paper - * authors' code. */ -static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = { - {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}}, - {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}}, - {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}}, - {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}}, - {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}}, - {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}}, - {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}}, - {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}}, - {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}}, - {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, - {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}}, - {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}}, - {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, -}; - -/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324 - * test vectors. Created using an independent implementation, and tested decoding against the paper - * authors' code. */ -static const struct ellswift_decode_test ellswift_decode_tests[] = { - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, - {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, - {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, - {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0}, - {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1}, - {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0}, - {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0}, - {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1}, - {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, - {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, - {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0}, - {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0}, - {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0}, - {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0}, - {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1}, - {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, - {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, - {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1}, - {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, - {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, - {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0}, - {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0}, - {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0}, - {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0}, - {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1}, - {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0}, - {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1}, - {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0}, - {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1}, - {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, - {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, - {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1}, - {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0}, -}; - -/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating, - * taken from the BIP324 test vectors. Created using an independent implementation, and tested - * against the paper authors' decoding code. */ -static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = { - {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}}, - {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}}, - {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}}, - {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}}, - {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}}, - {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}}, - {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}}, -}; - -/** This is a hasher for ellswift_xdh which just returns the shared X coordinate. - * - * This is generally a bad idea as it means changes to the encoding of the - * exchanged public keys do not affect the shared secret. However, it's used here - * in tests to be able to verify the X coordinate through other means. - */ -static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { - (void)ell_a64; - (void)ell_b64; - (void)data; - memcpy(output, x32, 32); - return 1; -} - -void run_ellswift_tests(void) { - int i = 0; - /* Test vectors. */ - for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) { - const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i]; - int c; - for (c = 0; c < 8; ++c) { - secp256k1_fe t; - int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c); - CHECK(ret == ((testcase->enc_bitmap >> c) & 1)); - if (ret) { - secp256k1_fe x2; - CHECK(fe_equal(&t, &testcase->encs[c])); - secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]); - CHECK(fe_equal(&testcase->x, &x2)); - } - } - } - for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) { - const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i]; - secp256k1_pubkey pubkey; - secp256k1_ge ge; - int ret; - ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc); - CHECK(ret); - ret = secp256k1_pubkey_load(CTX, &ge, &pubkey); - CHECK(ret); - CHECK(fe_equal(&testcase->x, &ge.x)); - CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y); - } - for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) { - const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i]; - unsigned char shared_secret[32]; - int ret; - int party = !test->initiating; - const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours; - const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs; - ret = secp256k1_ellswift_xdh(CTX, shared_secret, - ell_a64, ell_b64, - test->priv_ours, - party, - secp256k1_ellswift_xdh_hash_function_bip324, - NULL); - CHECK(ret); - CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0); - } - /* Verify that secp256k1_ellswift_encode + decode roundtrips. */ - for (i = 0; i < 1000 * COUNT; i++) { - unsigned char rnd32[32]; - unsigned char ell64[64]; - secp256k1_ge g, g2; - secp256k1_pubkey pubkey, pubkey2; - /* Generate random public key and random randomizer. */ - testutil_random_ge_test(&g); - secp256k1_pubkey_save(&pubkey, &g); - testrand256(rnd32); - /* Convert the public key to ElligatorSwift and back. */ - secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32); - secp256k1_ellswift_decode(CTX, &pubkey2, ell64); - secp256k1_pubkey_load(CTX, &g2, &pubkey2); - /* Compare with original. */ - CHECK(secp256k1_ge_eq_var(&g, &g2)); - } - /* Verify the behavior of secp256k1_ellswift_create */ - for (i = 0; i < 400 * COUNT; i++) { - unsigned char auxrnd32[32], sec32[32]; - secp256k1_scalar sec; - secp256k1_gej res; - secp256k1_ge dec; - secp256k1_pubkey pub; - unsigned char ell64[64]; - int ret; - /* Generate random secret key and random randomizer. */ - if (i & 1) testrand256_test(auxrnd32); - testutil_random_scalar_order_test(&sec); - secp256k1_scalar_get_b32(sec32, &sec); - /* Construct ElligatorSwift-encoded public keys for that key. */ - ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL); - CHECK(ret); - /* Decode it, and compare with traditionally-computed public key. */ - secp256k1_ellswift_decode(CTX, &pub, ell64); - secp256k1_pubkey_load(CTX, &dec, &pub); - secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec); - CHECK(secp256k1_gej_eq_ge_var(&res, &dec)); - } - /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */ - for (i = 0; i < 800 * COUNT; i++) { - unsigned char ell64[64], sec32[32], share32[32]; - secp256k1_scalar sec; - secp256k1_ge dec, res; - secp256k1_fe share_x; - secp256k1_gej decj, resj; - secp256k1_pubkey pub; - int ret; - /* Generate random secret key. */ - testutil_random_scalar_order_test(&sec); - secp256k1_scalar_get_b32(sec32, &sec); - /* Generate random ElligatorSwift encoding for the remote key and decode it. */ - testrand256_test(ell64); - testrand256_test(ell64 + 32); - secp256k1_ellswift_decode(CTX, &pub, ell64); - secp256k1_pubkey_load(CTX, &dec, &pub); - secp256k1_gej_set_ge(&decj, &dec); - /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we - * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works - * because the "hasher" function we use here ignores the ell64 arguments. */ - ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL); - CHECK(ret); - (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */ - SECP256K1_FE_VERIFY(&share_x); - /* Compute seckey*pubkey directly. */ - secp256k1_ecmult(&resj, &decj, &sec, NULL); - secp256k1_ge_set_gej(&res, &resj); - /* Compare. */ - CHECK(fe_equal(&res.x, &share_x)); - } - /* Verify the joint behavior of secp256k1_ellswift_xdh */ - for (i = 0; i < 200 * COUNT; i++) { - unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; - unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32]; - secp256k1_scalar seca, secb; - unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64]; - unsigned char share32a[32], share32b[32], share32_bad[32]; - unsigned char prefix64[64]; - secp256k1_ellswift_xdh_hash_function hash_function; - void* data; - int ret; - - /* Pick hasher to use. */ - if ((i % 3) == 0) { - hash_function = ellswift_xdh_hash_x32; - data = NULL; - } else if ((i % 3) == 1) { - hash_function = secp256k1_ellswift_xdh_hash_function_bip324; - data = NULL; - } else { - hash_function = secp256k1_ellswift_xdh_hash_function_prefix; - testrand256_test(prefix64); - testrand256_test(prefix64 + 32); - data = prefix64; - } - - /* Generate random secret keys and random randomizers. */ - testrand256_test(auxrnd32a); - testrand256_test(auxrnd32b); - testutil_random_scalar_order_test(&seca); - /* Draw secb uniformly at random to make sure that the secret keys - * differ */ - testutil_random_scalar_order(&secb); - secp256k1_scalar_get_b32(sec32a, &seca); - secp256k1_scalar_get_b32(sec32b, &secb); - - /* Construct ElligatorSwift-encoded public keys for those keys. */ - /* For A: */ - ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a); - CHECK(ret); - /* For B: */ - ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b); - CHECK(ret); - - /* Compute the shared secret both ways and compare with each other. */ - /* For A: */ - ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); - CHECK(ret); - /* For B: */ - ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); - CHECK(ret); - /* And compare: */ - CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0); - - /* Verify that the shared secret doesn't match if other side's public key is incorrect. */ - /* For A (using a bad public key for B): */ - memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); - testrand_flip(ell64b_bad, sizeof(ell64b_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); - CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */ - CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); - /* For B (using a bad public key for A): */ - memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); - testrand_flip(ell64a_bad, sizeof(ell64a_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); - CHECK(ret); - CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); - - /* Verify that the shared secret doesn't match if the private key is incorrect. */ - /* For A: */ - memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); - testrand_flip(sec32a_bad, sizeof(sec32a_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); - CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); - /* For B: */ - memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); - testrand_flip(sec32b_bad, sizeof(sec32b_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); - CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); - - if (hash_function != ellswift_xdh_hash_x32) { - /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */ - /* For A (changing B's public key): */ - memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); - testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); - ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); - CHECK(ret); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); - CHECK(ret); - CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); - /* For B (changing A's public key): */ - memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); - testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); - ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); - CHECK(ret); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); - CHECK(ret); - CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); - - /* Verify that swapping sides changes the shared secret. */ - /* For A (claiming to be B): */ - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); - CHECK(ret); - CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); - /* For B (claiming to be A): */ - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); - CHECK(ret); - CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); - } - } - - /* Test hash initializers. */ - { - secp256k1_sha256 sha, sha_optimized; - static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; - static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; - static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; - - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_encode has the expected - * state. */ - secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag)); - secp256k1_ellswift_sha256_init_encode(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); - - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_create has the expected - * state. */ - secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag)); - secp256k1_ellswift_sha256_init_create(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); - - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_bip324 has the expected - * state. */ - secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag)); - secp256k1_ellswift_sha256_init_bip324(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); - } -} - -#endif diff --git a/external/secp256k1/src/modules/extrakeys/Makefile.am.include b/external/secp256k1/src/modules/extrakeys/Makefile.am.include deleted file mode 100644 index 0d901ec1f4..0000000000 --- a/external/secp256k1/src/modules/extrakeys/Makefile.am.include +++ /dev/null @@ -1,4 +0,0 @@ -include_HEADERS += include/secp256k1_extrakeys.h -noinst_HEADERS += src/modules/extrakeys/tests_impl.h -noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h -noinst_HEADERS += src/modules/extrakeys/main_impl.h diff --git a/external/secp256k1/src/modules/extrakeys/main_impl.h b/external/secp256k1/src/modules/extrakeys/main_impl.h deleted file mode 100644 index 0c7e266777..0000000000 --- a/external/secp256k1/src/modules/extrakeys/main_impl.h +++ /dev/null @@ -1,285 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H -#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "../../util.h" - -static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) { - return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey); -} - -static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) { - secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge); -} - -int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) { - secp256k1_ge pk; - secp256k1_fe x; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input32 != NULL); - - if (!secp256k1_fe_set_b32_limit(&x, input32)) { - return 0; - } - if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { - return 0; - } - if (!secp256k1_ge_is_in_correct_subgroup(&pk)) { - return 0; - } - secp256k1_xonly_pubkey_save(pubkey, &pk); - return 1; -} - -int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) { - secp256k1_ge pk; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output32 != NULL); - memset(output32, 0, 32); - ARG_CHECK(pubkey != NULL); - - if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - secp256k1_fe_get_b32(output32, &pk.x); - return 1; -} - -int secp256k1_xonly_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_xonly_pubkey* pk0, const secp256k1_xonly_pubkey* pk1) { - unsigned char out[2][32]; - const secp256k1_xonly_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pk0; pk[1] = pk1; - for (i = 0; i < 2; i++) { - /* If the public key is NULL or invalid, xonly_pubkey_serialize will - * call the illegal_callback and return 0. In that case we will - * serialize the key as all zeros which is less than any valid public - * key. This results in consistent comparisons even if NULL or invalid - * pubkeys are involved and prevents edge cases such as sorting - * algorithms that use this function and do not terminate as a - * result. */ - if (!secp256k1_xonly_pubkey_serialize(ctx, out[i], pk[i])) { - /* Note that xonly_pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1])); -} - -/** Keeps a group element as is if it has an even Y and otherwise negates it. - * y_parity is set to 0 in the former case and to 1 in the latter case. - * Requires that the coordinates of r are normalized. */ -static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) { - int y_parity = 0; - VERIFY_CHECK(!secp256k1_ge_is_infinity(r)); - - if (secp256k1_fe_is_odd(&r->y)) { - secp256k1_fe_negate(&r->y, &r->y, 1); - y_parity = 1; - } - return y_parity; -} - -int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) { - secp256k1_ge pk; - int tmp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(xonly_pubkey != NULL); - ARG_CHECK(pubkey != NULL); - - if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - tmp = secp256k1_extrakeys_ge_even_y(&pk); - if (pk_parity != NULL) { - *pk_parity = tmp; - } - secp256k1_xonly_pubkey_save(xonly_pubkey, &pk); - return 1; -} - -int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { - secp256k1_ge pk; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output_pubkey != NULL); - memset(output_pubkey, 0, sizeof(*output_pubkey)); - ARG_CHECK(internal_pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) - || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { - return 0; - } - secp256k1_pubkey_save(output_pubkey, &pk); - return 1; -} - -int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { - secp256k1_ge pk; - unsigned char pk_expected32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(internal_pubkey != NULL); - ARG_CHECK(tweaked_pubkey32 != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) - || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { - return 0; - } - secp256k1_fe_normalize_var(&pk.x); - secp256k1_fe_normalize_var(&pk.y); - secp256k1_fe_get_b32(pk_expected32, &pk.x); - - return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 - && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; -} - -static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) { - secp256k1_scalar_get_b32(&keypair->data[0], sk); - secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk); -} - - -static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) { - int ret; - - ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]); - /* We can declassify ret here because sk is only zero if a keypair function - * failed (which zeroes the keypair) and its return value is ignored. */ - secp256k1_declassify(ctx, &ret, sizeof(ret)); - ARG_CHECK(ret); - return ret; -} - -/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk - * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and - * pk with dummy values. */ -static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) { - int ret; - const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32]; - - /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's - * invalid. */ - secp256k1_declassify(ctx, pubkey, sizeof(*pubkey)); - ret = secp256k1_pubkey_load(ctx, pk, pubkey); - if (sk != NULL) { - ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair); - } - if (!ret) { - *pk = secp256k1_ge_const_g; - if (sk != NULL) { - *sk = secp256k1_scalar_one; - } - } - return ret; -} - -int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) { - secp256k1_scalar sk; - secp256k1_ge pk; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(keypair != NULL); - memset(keypair, 0, sizeof(*keypair)); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey32 != NULL); - - ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); - secp256k1_keypair_save(keypair, &sk, &pk); - secp256k1_memczero(keypair, sizeof(*keypair), !ret); - - secp256k1_scalar_clear(&sk); - return ret; -} - -int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - memset(seckey, 0, 32); - ARG_CHECK(keypair != NULL); - - memcpy(seckey, &keypair->data[0], 32); - return 1; -} - -int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(keypair != NULL); - - memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); - return 1; -} - -int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) { - secp256k1_ge pk; - int tmp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(keypair != NULL); - - if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) { - return 0; - } - tmp = secp256k1_extrakeys_ge_even_y(&pk); - if (pk_parity != NULL) { - *pk_parity = tmp; - } - secp256k1_xonly_pubkey_save(pubkey, &pk); - - return 1; -} - -int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) { - secp256k1_ge pk; - secp256k1_scalar sk; - int y_parity; - int ret; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(keypair != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair); - memset(keypair, 0, sizeof(*keypair)); - - y_parity = secp256k1_extrakeys_ge_even_y(&pk); - if (y_parity == 1) { - secp256k1_scalar_negate(&sk, &sk); - } - - ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32); - ret &= secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32); - - secp256k1_declassify(ctx, &ret, sizeof(ret)); - if (ret) { - secp256k1_keypair_save(keypair, &sk, &pk); - } - - secp256k1_scalar_clear(&sk); - return ret; -} - -#endif diff --git a/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h deleted file mode 100644 index 645bae2d47..0000000000 --- a/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h +++ /dev/null @@ -1,68 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H -#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H - -#include "../../../include/secp256k1_extrakeys.h" -#include "main_impl.h" - -static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { - secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; - secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; - secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; - int parities[EXHAUSTIVE_TEST_ORDER - 1]; - unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; - int i; - - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_fe fe; - secp256k1_scalar scalar_i; - unsigned char buf[33]; - int parity; - - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_scalar_get_b32(buf, &scalar_i); - - /* Construct pubkey and keypair. */ - CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); - - /* Construct serialized xonly_pubkey from keypair. */ - CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); - - /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ - CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); - CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); - - /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); - CHECK(parity == parities[i - 1]); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); - CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); - - /* Compare the xonly_pubkey bytes against the precomputed group. */ - secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); - CHECK(secp256k1_fe_equal(&fe, &group[i].x)); - - /* Check the parity against the precomputed group. */ - fe = group[i].y; - secp256k1_fe_normalize_var(&fe); - CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]); - - /* Verify that the higher half is identical to the lower half mirrored. */ - if (i > EXHAUSTIVE_TEST_ORDER / 2) { - CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); - CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); - } - } - - /* TODO: keypair/xonly_pubkey tweak tests */ -} - -#endif diff --git a/external/secp256k1/src/modules/extrakeys/tests_impl.h b/external/secp256k1/src/modules/extrakeys/tests_impl.h deleted file mode 100644 index ab4ef4a74b..0000000000 --- a/external/secp256k1/src/modules/extrakeys/tests_impl.h +++ /dev/null @@ -1,483 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H -#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H - -#include "../../../include/secp256k1_extrakeys.h" - -static void test_xonly_pubkey(void) { - secp256k1_pubkey pk; - secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; - secp256k1_ge pk1; - secp256k1_ge pk2; - secp256k1_fe y; - unsigned char sk[32]; - unsigned char xy_sk[32]; - unsigned char buf32[32]; - unsigned char ones32[32]; - unsigned char zeros64[64] = { 0 }; - int pk_parity; - int i; - - testrand256(sk); - memset(ones32, 0xFF, 32); - testrand256(xy_sk); - CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - - /* Test xonly_pubkey_from_pubkey */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk)); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL)); - memset(&pk, 0, sizeof(pk)); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk)); - - /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ - memset(sk, 0, sizeof(sk)); - sk[0] = 1; - CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); - CHECK(pk_parity == 0); - - /* Choose a secret key such that pubkey and xonly_pubkey are each others - * negation. */ - sk[0] = 2; - CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); - CHECK(pk_parity == 1); - secp256k1_pubkey_load(CTX, &pk1, &pk); - secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk); - CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); - secp256k1_fe_negate(&y, &pk2.y, 1); - CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); - - /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk)); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL)); - CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); - { - /* A pubkey filled with 0s will fail to serialize due to pubkey_load - * special casing. */ - secp256k1_xonly_pubkey pk_tmp; - memset(&pk_tmp, 0, sizeof(pk_tmp)); - /* pubkey_load calls illegal callback */ - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp)); - } - - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32)); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL)); - - /* Serialization and parse roundtrip */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1); - CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); - - /* Test parsing invalid field elements */ - memset(&xonly_pk, 1, sizeof(xonly_pk)); - /* Overflowing field element */ - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0); - CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - memset(&xonly_pk, 1, sizeof(xonly_pk)); - /* There's no point with x-coordinate 0 on secp256k1 */ - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0); - CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - /* If a random 32-byte string can not be parsed with ec_pubkey_parse - * (because interpreted as X coordinate it does not correspond to a point on - * the curve) then xonly_pubkey_parse should fail as well. */ - for (i = 0; i < COUNT; i++) { - unsigned char rand33[33]; - testrand256(&rand33[1]); - rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; - if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) { - memset(&xonly_pk, 1, sizeof(xonly_pk)); - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0); - CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - } else { - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1); - } - } -} - -static void test_xonly_pubkey_comparison(void) { - unsigned char pk1_ser[32] = { - 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, - 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 - }; - const unsigned char pk2_ser[32] = { - 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, - 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c - }; - secp256k1_xonly_pubkey pk1; - secp256k1_xonly_pubkey pk2; - - CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1); - CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1); - - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0)); - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0)); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0); - memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0)); - { - int32_t ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(ecount == 2); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - } - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0)); -} - -static void test_xonly_pubkey_tweak(void) { - unsigned char zeros64[64] = { 0 }; - unsigned char overflows[32]; - unsigned char sk[32]; - secp256k1_pubkey internal_pk; - secp256k1_xonly_pubkey internal_xonly_pk; - secp256k1_pubkey output_pk; - int pk_parity; - unsigned char tweak[32]; - int i; - - memset(overflows, 0xff, sizeof(overflows)); - testrand256(tweak); - testrand256(sk); - CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak)); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak)); - /* NULL internal_xonly_pk zeroes the output_pk */ - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL)); - /* NULL tweak zeroes the output_pk */ - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - /* Invalid tweak zeroes the output_pk */ - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - /* A zero tweak is fine */ - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1); - - /* Fails if the resulting key was infinity */ - for (i = 0; i < COUNT; i++) { - secp256k1_scalar scalar_tweak; - /* Because sk may be negated before adding, we need to try with tweak = - * sk as well as tweak = -sk. */ - secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); - secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); - secp256k1_scalar_get_b32(tweak, &scalar_tweak); - CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0) - || (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0)); - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - } - - /* Invalid pk with a valid tweak */ - memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); - testrand256(tweak); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); -} - -static void test_xonly_pubkey_tweak_check(void) { - unsigned char zeros64[64] = { 0 }; - unsigned char overflows[32]; - unsigned char sk[32]; - secp256k1_pubkey internal_pk; - secp256k1_xonly_pubkey internal_xonly_pk; - secp256k1_pubkey output_pk; - secp256k1_xonly_pubkey output_xonly_pk; - unsigned char output_pk32[32]; - unsigned char buf32[32]; - int pk_parity; - unsigned char tweak[32]; - - memset(overflows, 0xff, sizeof(overflows)); - testrand256(tweak); - testrand256(sk); - CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak)); - /* invalid pk_parity value */ - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak)); - CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL)); - - memset(tweak, 1, sizeof(tweak)); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); - - /* Wrong pk_parity */ - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); - /* Wrong public key */ - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); - - /* Overflowing tweak not allowed */ - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); -} - -/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 - * additional pubkeys by calling tweak_add. Then verifies every tweak starting - * from the last pubkey. */ -#define N_PUBKEYS 32 -static void test_xonly_pubkey_tweak_recursive(void) { - unsigned char sk[32]; - secp256k1_pubkey pk[N_PUBKEYS]; - unsigned char pk_serialized[32]; - unsigned char tweak[N_PUBKEYS - 1][32]; - int i; - - testrand256(sk); - CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1); - /* Add tweaks */ - for (i = 0; i < N_PUBKEYS - 1; i++) { - secp256k1_xonly_pubkey xonly_pk; - memset(tweak[i], i + 1, sizeof(tweak[i])); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1); - } - - /* Verify tweaks */ - for (i = N_PUBKEYS - 1; i > 0; i--) { - secp256k1_xonly_pubkey xonly_pk; - int pk_parity; - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); - } -} -#undef N_PUBKEYS - -static void test_keypair(void) { - unsigned char sk[32]; - unsigned char sk_tmp[32]; - unsigned char zeros96[96] = { 0 }; - unsigned char overflows[32]; - secp256k1_keypair keypair; - secp256k1_pubkey pk, pk_tmp; - secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; - int pk_parity, pk_parity_tmp; - - CHECK(sizeof(zeros96) == sizeof(keypair)); - memset(overflows, 0xFF, sizeof(overflows)); - - /* Test keypair_create */ - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk)); - CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL)); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk)); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - - /* Invalid secret key */ - CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0); - CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - - /* Test keypair_pub */ - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); - CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair)); - CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL)); - CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); - - /* Using an invalid keypair is fine for keypair_pub */ - memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); - CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); - - /* keypair holds the same pubkey as pubkey_create */ - CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1); - CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); - - /** Test keypair_xonly_pub **/ - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL)); - CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); - /* Using an invalid keypair will set the xonly_pk to 0 (first reset - * xonly_pk). */ - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); - memset(&keypair, 0, sizeof(keypair)); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair)); - CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); - - /** keypair holds the same xonly pubkey as pubkey_create **/ - CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); - CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); - CHECK(pk_parity == pk_parity_tmp); - - /* Test keypair_seckey */ - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); - CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair)); - CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL)); - CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); - - /* keypair returns the same seckey it got */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); - CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); - - - /* Using an invalid keypair is fine for keypair_seckey */ - memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); - CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); -} - -static void test_keypair_add(void) { - unsigned char sk[32]; - secp256k1_keypair keypair; - unsigned char overflows[32]; - unsigned char zeros96[96] = { 0 }; - unsigned char tweak[32]; - int i; - - CHECK(sizeof(zeros96) == sizeof(keypair)); - testrand256(sk); - testrand256(tweak); - memset(overflows, 0xFF, 32); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak)); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL)); - /* This does not set the keypair to zeroes */ - CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); - - /* Invalid tweak zeroes the keypair */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0); - CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); - - /* A zero tweak is fine */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1); - - /* Fails if the resulting keypair was (sk=0, pk=infinity) */ - for (i = 0; i < COUNT; i++) { - secp256k1_scalar scalar_tweak; - secp256k1_keypair keypair_tmp; - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - memcpy(&keypair_tmp, &keypair, sizeof(keypair)); - /* Because sk may be negated before adding, we need to try with tweak = - * sk as well as tweak = -sk. */ - secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); - secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); - secp256k1_scalar_get_b32(tweak, &scalar_tweak); - CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0) - || (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0)); - CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 - || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); - } - - /* Invalid keypair with a valid tweak */ - memset(&keypair, 0, sizeof(keypair)); - testrand256(tweak); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); - CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); - /* Only seckey part of keypair invalid */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - memset(&keypair, 0, 32); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); - /* Only pubkey part of keypair invalid */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - memset(&keypair.data[32], 0, 64); - CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); - - /* Check that the keypair_tweak_add implementation is correct */ - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - for (i = 0; i < COUNT; i++) { - secp256k1_xonly_pubkey internal_pk; - secp256k1_xonly_pubkey output_pk; - secp256k1_pubkey output_pk_xy; - secp256k1_pubkey output_pk_expected; - unsigned char pk32[32]; - unsigned char sk32[32]; - int pk_parity; - - testrand256(tweak); - CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); - - /* Check that it passes xonly_pubkey_tweak_add_check */ - CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1); - - /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ - CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1); - CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); - - /* Check that the secret key in the keypair is tweaked correctly */ - CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1); - CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); - } -} - -static void run_extrakeys_tests(void) { - /* xonly key test cases */ - test_xonly_pubkey(); - test_xonly_pubkey_tweak(); - test_xonly_pubkey_tweak_check(); - test_xonly_pubkey_tweak_recursive(); - test_xonly_pubkey_comparison(); - - /* keypair tests */ - test_keypair(); - test_keypair_add(); -} - -#endif diff --git a/external/secp256k1/src/modules/musig/Makefile.am.include b/external/secp256k1/src/modules/musig/Makefile.am.include deleted file mode 100644 index 796443c93b..0000000000 --- a/external/secp256k1/src/modules/musig/Makefile.am.include +++ /dev/null @@ -1,8 +0,0 @@ -include_HEADERS += include/secp256k1_musig.h -noinst_HEADERS += src/modules/musig/main_impl.h -noinst_HEADERS += src/modules/musig/keyagg.h -noinst_HEADERS += src/modules/musig/keyagg_impl.h -noinst_HEADERS += src/modules/musig/session.h -noinst_HEADERS += src/modules/musig/session_impl.h -noinst_HEADERS += src/modules/musig/tests_impl.h -noinst_HEADERS += src/modules/musig/vectors.h diff --git a/external/secp256k1/src/modules/musig/keyagg.h b/external/secp256k1/src/modules/musig/keyagg.h deleted file mode 100644 index a0b37252f8..0000000000 --- a/external/secp256k1/src/modules/musig/keyagg.h +++ /dev/null @@ -1,32 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H -#define SECP256K1_MODULE_MUSIG_KEYAGG_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_musig.h" - -#include "../../group.h" -#include "../../scalar.h" - -typedef struct { - secp256k1_ge pk; - /* If there is no "second" public key, second_pk is set to the point at - * infinity */ - secp256k1_ge second_pk; - unsigned char pks_hash[32]; - /* tweak is identical to value tacc[v] in the specification. */ - secp256k1_scalar tweak; - /* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is - * -1, parity_acc is 1. Otherwise, parity_acc is 0. */ - int parity_acc; -} secp256k1_keyagg_cache_internal; - -static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); - -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); - -#endif diff --git a/external/secp256k1/src/modules/musig/keyagg_impl.h b/external/secp256k1/src/modules/musig/keyagg_impl.h deleted file mode 100644 index 0db4fce859..0000000000 --- a/external/secp256k1/src/modules/musig/keyagg_impl.h +++ /dev/null @@ -1,291 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H -#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H - -#include - -#include "keyagg.h" -#include "../../eckey.h" -#include "../../ecmult.h" -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../util.h" - -static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; - -/* A keyagg cache consists of - * - 4 byte magic set during initialization to allow detecting an uninitialized - * object. - * - 64 byte aggregate (and potentially tweaked) public key - * - 64 byte "second" public key (set to the point at infinity if not present) - * - 32 byte hash of all public keys - * - 1 byte the parity of the internal key (if tweaked, otherwise 0) - * - 32 byte tweak - */ -/* Requires that cache_i->pk is not infinity. */ -static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, const secp256k1_keyagg_cache_internal *cache_i) { - unsigned char *ptr = cache->data; - memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4); - ptr += 4; - secp256k1_ge_to_bytes(ptr, &cache_i->pk); - ptr += 64; - secp256k1_ge_to_bytes_ext(ptr, &cache_i->second_pk); - ptr += 64; - memcpy(ptr, cache_i->pks_hash, 32); - ptr += 32; - *ptr = cache_i->parity_acc; - ptr += 1; - secp256k1_scalar_get_b32(ptr, &cache_i->tweak); -} - -static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) { - const unsigned char *ptr = cache->data; - ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0); - ptr += 4; - secp256k1_ge_from_bytes(&cache_i->pk, ptr); - ptr += 64; - secp256k1_ge_from_bytes_ext(&cache_i->second_pk, ptr); - ptr += 64; - memcpy(cache_i->pks_hash, ptr, 32); - ptr += 32; - cache_i->parity_acc = *ptr & 1; - ptr += 1; - secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ -static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - - sha->s[0] = 0xb399d5e0ul; - sha->s[1] = 0xc8fff302ul; - sha->s[2] = 0x6badac71ul; - sha->s[3] = 0x07c5b7f1ul; - sha->s[4] = 0x9701e2eful; - sha->s[5] = 0x2a72ecf8ul; - sha->s[6] = 0x201a4c7bul; - sha->s[7] = 0xab148a38ul; - sha->bytes = 64; -} - -/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */ -static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsigned char *pks_hash, const secp256k1_pubkey * const* pks, size_t np) { - secp256k1_sha256 sha; - size_t i; - - secp256k1_musig_keyagglist_sha256(&sha); - for (i = 0; i < np; i++) { - unsigned char ser[33]; - size_t ser_len = sizeof(ser); - if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) { - return 0; - } - VERIFY_CHECK(ser_len == sizeof(ser)); - secp256k1_sha256_write(&sha, ser, sizeof(ser)); - } - secp256k1_sha256_finalize(&sha, pks_hash); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ -static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - - sha->s[0] = 0x6ef02c5aul; - sha->s[1] = 0x06a480deul; - sha->s[2] = 0x1f298665ul; - sha->s[3] = 0x1d1134f2ul; - sha->s[4] = 0x56a0b063ul; - sha->s[5] = 0x52da4147ul; - sha->s[6] = 0xf280d9d4ul; - sha->s[7] = 0x4484be15ul; - sha->bytes = 64; -} - -/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and - * otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys. - * second_pk is the point at infinity in case there is no second_pk. Assumes - * that pk is not the point at infinity and that the Y-coordinates of pk and - * second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { - VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); - - if (!secp256k1_ge_is_infinity(second_pk) - && secp256k1_ge_eq_var(pk, second_pk)) { - secp256k1_scalar_set_int(r, 1); - } else { - secp256k1_sha256 sha; - unsigned char buf[33]; - size_t buflen = sizeof(buf); - int ret; - secp256k1_musig_keyaggcoef_sha256(&sha); - secp256k1_sha256_write(&sha, pks_hash, 32); - ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); -#ifdef VERIFY - /* Serialization does not fail since the pk is not the point at infinity - * (according to this function's precondition). */ - VERIFY_CHECK(ret && buflen == sizeof(buf)); -#else - (void) ret; -#endif - secp256k1_sha256_write(&sha, buf, sizeof(buf)); - secp256k1_sha256_finalize(&sha, buf); - secp256k1_scalar_set_b32(r, buf, NULL); - } -} - -/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk - * and cache_i->second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { - secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); -} - -typedef struct { - const secp256k1_context *ctx; - /* pks_hash is the hash of the public keys */ - unsigned char pks_hash[32]; - const secp256k1_pubkey * const* pks; - secp256k1_ge second_pk; -} secp256k1_musig_pubkey_agg_ecmult_data; - -/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ -static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { - secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data; - int ret; - ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); -#ifdef VERIFY - /* pubkey_load can't fail because the same pks have already been loaded in - * `musig_compute_pks_hash` (and we test this). */ - VERIFY_CHECK(ret); -#else - (void) ret; -#endif - secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); - return 1; -} - -int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) { - secp256k1_musig_pubkey_agg_ecmult_data ecmult_data; - secp256k1_gej pkj; - secp256k1_ge pkp; - size_t i; - - VERIFY_CHECK(ctx != NULL); - if (agg_pk != NULL) { - memset(agg_pk, 0, sizeof(*agg_pk)); - } - ARG_CHECK(pubkeys != NULL); - ARG_CHECK(n_pubkeys > 0); - - ecmult_data.ctx = ctx; - ecmult_data.pks = pubkeys; - - secp256k1_ge_set_infinity(&ecmult_data.second_pk); - for (i = 1; i < n_pubkeys; i++) { - if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { - secp256k1_ge pk; - if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) { - return 0; - } - ecmult_data.second_pk = pk; - break; - } - } - - if (!secp256k1_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) { - return 0; - } - /* TODO: actually use optimized ecmult_multi algorithms by providing a - * scratch space */ - if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { - /* In order to reach this line with the current implementation of - * ecmult_multi_var one would need to provide a callback that can - * fail. */ - return 0; - } - secp256k1_ge_set_gej(&pkp, &pkj); - secp256k1_fe_normalize_var(&pkp.y); - /* The resulting public key is infinity with negligible probability */ - VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp)); - if (keyagg_cache != NULL) { - secp256k1_keyagg_cache_internal cache_i = { 0 }; - cache_i.pk = pkp; - cache_i.second_pk = ecmult_data.second_pk; - memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash)); - secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); - } - - if (agg_pk != NULL) { - secp256k1_extrakeys_ge_even_y(&pkp); - secp256k1_xonly_pubkey_save(agg_pk, &pkp); - } - return 1; -} - -int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) { - secp256k1_keyagg_cache_internal cache_i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(agg_pk != NULL); - memset(agg_pk, 0, sizeof(*agg_pk)); - ARG_CHECK(keyagg_cache != NULL); - - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - secp256k1_pubkey_save(agg_pk, &cache_i.pk); - return 1; -} - -static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) { - secp256k1_keyagg_cache_internal cache_i; - int overflow = 0; - secp256k1_scalar tweak; - - VERIFY_CHECK(ctx != NULL); - if (output_pubkey != NULL) { - memset(output_pubkey, 0, sizeof(*output_pubkey)); - } - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - secp256k1_scalar_set_b32(&tweak, tweak32, &overflow); - if (overflow) { - return 0; - } - if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) { - cache_i.parity_acc ^= 1; - secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak); - } - secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); - if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { - return 0; - } - /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ - VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk)); - secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); - if (output_pubkey != NULL) { - secp256k1_pubkey_save(output_pubkey, &cache_i.pk); - } - return 1; -} - -int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { - return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0); -} - -int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { - return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1); -} - -#endif diff --git a/external/secp256k1/src/modules/musig/main_impl.h b/external/secp256k1/src/modules/musig/main_impl.h deleted file mode 100644 index a1311e4191..0000000000 --- a/external/secp256k1/src/modules/musig/main_impl.h +++ /dev/null @@ -1,12 +0,0 @@ -/********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_MAIN_H -#define SECP256K1_MODULE_MUSIG_MAIN_H - -#include "keyagg_impl.h" -#include "session_impl.h" - -#endif diff --git a/external/secp256k1/src/modules/musig/session.h b/external/secp256k1/src/modules/musig/session.h deleted file mode 100644 index d6d76bc6c1..0000000000 --- a/external/secp256k1/src/modules/musig/session.h +++ /dev/null @@ -1,24 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_SESSION_H -#define SECP256K1_MODULE_MUSIG_SESSION_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_musig.h" - -#include "../../scalar.h" - -typedef struct { - int fin_nonce_parity; - unsigned char fin_nonce[32]; - secp256k1_scalar noncecoef; - secp256k1_scalar challenge; - secp256k1_scalar s_part; -} secp256k1_musig_session_internal; - -static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session); - -#endif diff --git a/external/secp256k1/src/modules/musig/session_impl.h b/external/secp256k1/src/modules/musig/session_impl.h deleted file mode 100644 index dde3808582..0000000000 --- a/external/secp256k1/src/modules/musig/session_impl.h +++ /dev/null @@ -1,816 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H -#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H - -#include - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "../../../include/secp256k1_musig.h" - -#include "keyagg.h" -#include "session.h" -#include "../../eckey.h" -#include "../../hash.h" -#include "../../scalar.h" -#include "../../util.h" - -/* Outputs 33 zero bytes if the given group element is the point at infinity and - * otherwise outputs the compressed serialization */ -static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { - if (secp256k1_ge_is_infinity(ge)) { - memset(out33, 0, 33); - } else { - int ret; - size_t size = 33; - ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); -#ifdef VERIFY - /* Serialize must succeed because the point is not at infinity */ - VERIFY_CHECK(ret && size == 33); -#else - (void) ret; -#endif - } -} - -/* Outputs the point at infinity if the given byte array is all zero, otherwise - * attempts to parse compressed point serialization. */ -static int secp256k1_musig_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { - unsigned char zeros[33] = { 0 }; - - if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) { - secp256k1_ge_set_infinity(ge); - return 1; - } - if (!secp256k1_eckey_pubkey_parse(ge, in33, 33)) { - return 0; - } - return secp256k1_ge_is_in_correct_subgroup(ge); -} - -static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; - -static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, const secp256k1_ge *pk) { - memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4); - secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]); - secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]); - secp256k1_ge_to_bytes(&secnonce->data[68], pk); -} - -static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, const secp256k1_musig_secnonce *secnonce) { - int is_zero; - ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0); - /* We make very sure that the nonce isn't invalidated by checking the values - * in addition to the magic. */ - is_zero = secp256k1_is_zero_array(&secnonce->data[4], 2 * 32); - secp256k1_declassify(ctx, &is_zero, sizeof(is_zero)); - ARG_CHECK(!is_zero); - - secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL); - secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL); - secp256k1_ge_from_bytes(pk, &secnonce->data[68]); - return 1; -} - -/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ -static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) { - secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag); - /* The flag argument is usually classified. So, the line above makes the - * magic and public key classified. However, we need both to be - * declassified. Note that we don't declassify the entire object, because if - * flag is 0, then k[0] and k[1] have not been zeroed. */ - secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic)); - secp256k1_declassify(ctx, &secnonce->data[68], 64); -} - -static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; - -/* Saves two group elements into a pubnonce. Requires that none of the provided - * group elements is infinity. */ -static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, const secp256k1_ge* ges) { - int i; - memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); - for (i = 0; i < 2; i++) { - secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ges[i]); - } -} - -/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't - * properly initialized */ -static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_pubnonce* nonce) { - int i; - - ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0); - for (i = 0; i < 2; i++) { - secp256k1_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i); - } - return 1; -} - -static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; - -static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, const secp256k1_ge* ges) { - int i; - memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4); - for (i = 0; i < 2; i++) { - secp256k1_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]); - } -} - -static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_aggnonce* nonce) { - int i; - - ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0); - for (i = 0; i < 2; i++) { - secp256k1_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]); - } - return 1; -} - -static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; - -/* A session consists of - * - 4 byte session cache magic - * - 1 byte the parity of the final nonce - * - 32 byte serialized x-only final nonce - * - 32 byte nonce coefficient b - * - 32 byte signature challenge hash e - * - 32 byte scalar s that is added to the partial signatures of the signers - */ -static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) { - unsigned char *ptr = session->data; - - memcpy(ptr, secp256k1_musig_session_cache_magic, 4); - ptr += 4; - *ptr = session_i->fin_nonce_parity; - ptr += 1; - memcpy(ptr, session_i->fin_nonce, 32); - ptr += 32; - secp256k1_scalar_get_b32(ptr, &session_i->noncecoef); - ptr += 32; - secp256k1_scalar_get_b32(ptr, &session_i->challenge); - ptr += 32; - secp256k1_scalar_get_b32(ptr, &session_i->s_part); -} - -static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) { - const unsigned char *ptr = session->data; - - ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0); - ptr += 4; - session_i->fin_nonce_parity = *ptr; - ptr += 1; - memcpy(session_i->fin_nonce, ptr, 32); - ptr += 32; - secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL); - ptr += 32; - secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL); - ptr += 32; - secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL); - return 1; -} - -static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; - -static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) { - memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4); - secp256k1_scalar_get_b32(&sig->data[4], s); -} - -static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) { - int overflow; - - ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); - secp256k1_scalar_set_b32(s, &sig->data[4], &overflow); - /* Parsed signatures can not overflow */ - VERIFY_CHECK(!overflow); - return 1; -} - -int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) { - secp256k1_ge ges[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(in66 != NULL); - - for (i = 0; i < 2; i++) { - if (!secp256k1_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) { - return 0; - } - if (!secp256k1_ge_is_in_correct_subgroup(&ges[i])) { - return 0; - } - } - secp256k1_musig_pubnonce_save(nonce, ges); - return 1; -} - -int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) { - secp256k1_ge ges[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out66 != NULL); - memset(out66, 0, 66); - ARG_CHECK(nonce != NULL); - - if (!secp256k1_musig_pubnonce_load(ctx, ges, nonce)) { - return 0; - } - for (i = 0; i < 2; i++) { - int ret; - size_t size = 33; - ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1); -#ifdef VERIFY - /* serialize must succeed because the point was just loaded */ - VERIFY_CHECK(ret && size == 33); -#else - (void) ret; -#endif - } - return 1; -} - -int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) { - secp256k1_ge ges[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(in66 != NULL); - - for (i = 0; i < 2; i++) { - if (!secp256k1_musig_ge_parse_ext(&ges[i], &in66[33*i])) { - return 0; - } - } - secp256k1_musig_aggnonce_save(nonce, ges); - return 1; -} - -int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) { - secp256k1_ge ges[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out66 != NULL); - memset(out66, 0, 66); - ARG_CHECK(nonce != NULL); - - if (!secp256k1_musig_aggnonce_load(ctx, ges, nonce)) { - return 0; - } - for (i = 0; i < 2; i++) { - secp256k1_musig_ge_serialize_ext(&out66[33*i], &ges[i]); - } - return 1; -} - -int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) { - secp256k1_scalar tmp; - int overflow; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(in32 != NULL); - - /* Ensure that using the signature will fail if parsing fails (and the user - * doesn't check the return value). */ - memset(sig, 0, sizeof(*sig)); - - secp256k1_scalar_set_b32(&tmp, in32, &overflow); - if (overflow) { - return 0; - } - secp256k1_musig_partial_sig_save(sig, &tmp); - return 1; -} - -int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); - - memcpy(out32, &sig->data[4], 32); - return 1; -} - -/* Write optional inputs into the hash */ -static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { - unsigned char zero[7] = { 0 }; - /* The spec requires length prefixes to be between 1 and 8 bytes - * (inclusive) */ - VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8); - /* Since the length of all input data fits in a byte, we can always pad the - * length prefix with prefix_size - 1 zero bytes. */ - secp256k1_sha256_write(sha, zero, prefix_size - 1); - if (data != NULL) { - secp256k1_sha256_write(sha, &len, 1); - secp256k1_sha256_write(sha, data, len); - } else { - len = 0; - secp256k1_sha256_write(sha, &len, 1); - } -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */ -static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0xa19e884bul; - sha->s[1] = 0xf463fe7eul; - sha->s[2] = 0x2f18f9a2ul; - sha->s[3] = 0xbeb0f9fful; - sha->s[4] = 0x0f37e8b0ul; - sha->s[5] = 0x06ebd26ful; - sha->s[6] = 0xe3b243d2ul; - sha->s[7] = 0x522fb150ul; - sha->bytes = 64; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */ -static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0x07101b64ul; - sha->s[1] = 0x18003414ul; - sha->s[2] = 0x0391bc43ul; - sha->s[3] = 0x0e6258eeul; - sha->s[4] = 0x29d26b72ul; - sha->s[5] = 0x8343937eul; - sha->s[6] = 0xb7a0a4fbul; - sha->s[7] = 0xff568a30ul; - sha->bytes = 64; -} - -static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { - secp256k1_sha256 sha; - unsigned char rand[32]; - unsigned char i; - unsigned char msg_present; - - if (seckey32 != NULL) { - secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - secp256k1_sha256_write(&sha, session_secrand, 32); - secp256k1_sha256_finalize(&sha, rand); - for (i = 0; i < 32; i++) { - rand[i] ^= seckey32[i]; - } - } else { - memcpy(rand, session_secrand, sizeof(rand)); - } - - secp256k1_nonce_function_musig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, rand, sizeof(rand)); - secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); - secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); - msg_present = msg32 != NULL; - secp256k1_sha256_write(&sha, &msg_present, 1); - if (msg_present) { - secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32); - } - secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32); - - for (i = 0; i < 2; i++) { - unsigned char buf[32]; - secp256k1_sha256 sha_tmp = sha; - secp256k1_sha256_write(&sha_tmp, &i, 1); - secp256k1_sha256_finalize(&sha_tmp, buf); - secp256k1_scalar_set_b32(&k[i], buf, NULL); - - /* Attempt to erase secret data */ - secp256k1_memclear(buf, sizeof(buf)); - secp256k1_sha256_clear(&sha_tmp); - } - secp256k1_memclear(rand, sizeof(rand)); - secp256k1_sha256_clear(&sha); -} - -static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { - secp256k1_scalar k[2]; - secp256k1_ge nonce_pts[2]; - int i; - unsigned char pk_ser[33]; - size_t pk_ser_len = sizeof(pk_ser); - unsigned char aggpk_ser[32]; - unsigned char *aggpk_ser_ptr = NULL; - secp256k1_ge pk; - int pk_serialize_success; - int ret = 1; - - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - - /* Check that the seckey is valid to be able to sign for it later. */ - if (seckey != NULL) { - secp256k1_scalar sk; - ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey); - secp256k1_scalar_clear(&sk); - } - - if (keyagg_cache != NULL) { - secp256k1_keyagg_cache_internal cache_i; - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - /* The loaded point cache_i.pk can not be the point at infinity. */ - secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x); - aggpk_ser_ptr = aggpk_ser; - } - if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1); - -#ifdef VERIFY - /* A pubkey cannot be the point at infinity */ - VERIFY_CHECK(pk_serialize_success); - VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); -#else - (void) pk_serialize_success; -#endif - - secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); - VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); - VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); - secp256k1_musig_secnonce_save(secnonce, k, &pk); - secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); - - for (i = 0; i < 2; i++) { - secp256k1_gej nonce_ptj; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); - secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj); - secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); - secp256k1_scalar_clear(&k[i]); - secp256k1_gej_clear(&nonce_ptj); - } - /* None of the nonce_pts will be infinity because k != 0 with overwhelming - * probability */ - secp256k1_musig_pubnonce_save(pubnonce, nonce_pts); - return ret; -} - -int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secnonce != NULL); - memset(secnonce, 0, sizeof(*secnonce)); - ARG_CHECK(session_secrand32 != NULL); - - /* Check in constant time that the session_secrand32 is not 0 as a - * defense-in-depth measure that may protect against a faulty RNG. */ - ret &= !secp256k1_is_zero_array(session_secrand32, 32); - - /* We can declassify because branching on ret is only relevant when this - * function called with an invalid session_secrand32 argument */ - secp256k1_declassify(ctx, &ret, sizeof(ret)); - if (ret == 0) { - secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1); - return 0; - } - - ret &= secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32); - - /* Set the session_secrand32 buffer to zero to prevent the caller from using - * nonce_gen multiple times with the same buffer. */ - secp256k1_memczero(session_secrand32, 32, ret); - return ret; -} - -int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const secp256k1_keypair *keypair, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { - unsigned char buf[32] = { 0 }; - unsigned char seckey[32]; - secp256k1_pubkey pubkey; - int ret; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secnonce != NULL); - memset(secnonce, 0, sizeof(*secnonce)); - ARG_CHECK(keypair != NULL); - - secp256k1_write_be64(buf, nonrepeating_cnt); - /* keypair_sec and keypair_pub do not fail if the arguments are not NULL */ - ret = secp256k1_keypair_sec(ctx, seckey, keypair); - VERIFY_CHECK(ret); - ret = secp256k1_keypair_pub(ctx, &pubkey, keypair); - VERIFY_CHECK(ret); -#ifndef VERIFY - (void) ret; -#endif - - if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) { - return 0; - } - secp256k1_memclear(seckey, sizeof(seckey)); - return 1; -} - -static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { - size_t i; - int j; - - secp256k1_gej_set_infinity(&summed_pubnonces[0]); - secp256k1_gej_set_infinity(&summed_pubnonces[1]); - - for (i = 0; i < n_pubnonces; i++) { - secp256k1_ge nonce_pts[2]; - if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) { - return 0; - } - for (j = 0; j < 2; j++) { - secp256k1_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL); - } - } - return 1; -} - -int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { - secp256k1_gej aggnonce_ptsj[2]; - secp256k1_ge aggnonce_pts[2]; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(aggnonce != NULL); - ARG_CHECK(pubnonces != NULL); - ARG_CHECK(n_pubnonces > 0); - - if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) { - return 0; - } - secp256k1_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2); - secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pts); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */ -static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0x2c7d5a45ul; - sha->s[1] = 0x06bf7e53ul; - sha->s[2] = 0x89be68a6ul; - sha->s[3] = 0x971254c0ul; - sha->s[4] = 0x60ac12d2ul; - sha->s[5] = 0x72846dcdul; - sha->s[6] = 0x6c81212ful; - sha->s[7] = 0xde7a2500ul; - sha->bytes = 64; -} - -/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ -static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { - unsigned char buf[33]; - secp256k1_sha256 sha; - int i; - - secp256k1_musig_compute_noncehash_sha256_tagged(&sha); - for (i = 0; i < 2; i++) { - secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]); - secp256k1_sha256_write(&sha, buf, sizeof(buf)); - } - secp256k1_sha256_write(&sha, agg_pk32, 32); - secp256k1_sha256_write(&sha, msg, 32); - secp256k1_sha256_finalize(&sha, noncehash); -} - -/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */ -static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ge *nonce_pts, const secp256k1_scalar *b) { - secp256k1_gej tmp; - - secp256k1_gej_set_ge(&tmp, &nonce_pts[1]); - secp256k1_ecmult(out_nonce, &tmp, b, NULL); - secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); -} - -static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { - unsigned char noncehash[32]; - secp256k1_ge fin_nonce_pt; - secp256k1_gej fin_nonce_ptj; - - secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); - secp256k1_scalar_set_b32(b, noncehash, NULL); - /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ - secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); - secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); - if (secp256k1_ge_is_infinity(&fin_nonce_pt)) { - fin_nonce_pt = secp256k1_ge_const_g; - } - /* fin_nonce_pt is not the point at infinity */ - secp256k1_fe_normalize_var(&fin_nonce_pt.x); - secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x); - secp256k1_fe_normalize_var(&fin_nonce_pt.y); - *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); -} - -int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) { - secp256k1_keyagg_cache_internal cache_i; - secp256k1_ge aggnonce_pts[2]; - unsigned char fin_nonce[32]; - secp256k1_musig_session_internal session_i; - unsigned char agg_pk32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(aggnonce != NULL); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(keyagg_cache != NULL); - - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x); - - if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) { - return 0; - } - - secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); - secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); - - /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ - secp256k1_scalar_set_int(&session_i.s_part, 0); - if (!secp256k1_scalar_is_zero(&cache_i.tweak)) { - secp256k1_scalar e_tmp; - secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); - if (secp256k1_fe_is_odd(&cache_i.pk.y)) { - secp256k1_scalar_negate(&e_tmp, &e_tmp); - } - session_i.s_part = e_tmp; - } - memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); - secp256k1_musig_session_save(session, &session_i); - return 1; -} - -static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) { - secp256k1_scalar_clear(sk); - secp256k1_scalar_clear(&k[0]); - secp256k1_scalar_clear(&k[1]); -} - -int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { - secp256k1_scalar sk; - secp256k1_ge pk, keypair_pk; - secp256k1_scalar k[2]; - secp256k1_scalar mu, s; - secp256k1_keyagg_cache_internal cache_i; - secp256k1_musig_session_internal session_i; - int ret; - - VERIFY_CHECK(ctx != NULL); - - ARG_CHECK(secnonce != NULL); - /* Fails if the magic doesn't match */ - ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce); - /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls - * of this function to fail */ - memset(secnonce, 0, sizeof(*secnonce)); - if (!ret) { - secp256k1_musig_partial_sign_clear(&sk, k); - return 0; - } - - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(keypair != NULL); - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(session != NULL); - - if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) { - secp256k1_musig_partial_sign_clear(&sk, k); - return 0; - } - ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x) - && secp256k1_fe_equal(&pk.y, &keypair_pk.y)); - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - secp256k1_musig_partial_sign_clear(&sk, k); - return 0; - } - - /* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. - * This corresponds to the line "Let d = gâ‹…gaccâ‹…d' mod n" in the - * specification. */ - if ((secp256k1_fe_is_odd(&cache_i.pk.y) - != cache_i.parity_acc)) { - secp256k1_scalar_negate(&sk, &sk); - } - - /* Multiply KeyAgg coefficient */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk); - secp256k1_scalar_mul(&sk, &sk, &mu); - - if (!secp256k1_musig_session_load(ctx, &session_i, session)) { - secp256k1_musig_partial_sign_clear(&sk, k); - return 0; - } - - if (session_i.fin_nonce_parity) { - secp256k1_scalar_negate(&k[0], &k[0]); - secp256k1_scalar_negate(&k[1], &k[1]); - } - - /* Sign */ - secp256k1_scalar_mul(&s, &session_i.challenge, &sk); - secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); - secp256k1_scalar_add(&k[0], &k[0], &k[1]); - secp256k1_scalar_add(&s, &s, &k[0]); - secp256k1_musig_partial_sig_save(partial_sig, &s); - secp256k1_musig_partial_sign_clear(&sk, k); - return 1; -} - -int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { - secp256k1_keyagg_cache_internal cache_i; - secp256k1_musig_session_internal session_i; - secp256k1_scalar mu, e, s; - secp256k1_gej pkj; - secp256k1_ge nonce_pts[2]; - secp256k1_gej rj; - secp256k1_gej tmp; - secp256k1_ge pkp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(pubnonce != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(session != NULL); - - if (!secp256k1_musig_session_load(ctx, &session_i, session)) { - return 0; - } - - if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) { - return 0; - } - /* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */ - /* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */ - secp256k1_effective_nonce(&rj, nonce_pts, &session_i.noncecoef); - - if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) { - return 0; - } - if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - /* Multiplying the challenge by the KeyAgg coefficient is equivalent - * to multiplying the signer's public key by the coefficient, except - * much easier to do. */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp); - secp256k1_scalar_mul(&e, &session_i.challenge, &mu); - - /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. - * This corresponds to the line "Let g' = gâ‹…gacc mod n" and the multiplication "g'â‹…e" - * in the specification. */ - if (secp256k1_fe_is_odd(&cache_i.pk.y) - != cache_i.parity_acc) { - secp256k1_scalar_negate(&e, &e); - } - - if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) { - return 0; - } - /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ - secp256k1_scalar_negate(&s, &s); - secp256k1_gej_set_ge(&pkj, &pkp); - secp256k1_ecmult(&tmp, &pkj, &e, &s); - if (session_i.fin_nonce_parity) { - secp256k1_gej_neg(&rj, &rj); - } - secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL); - - return secp256k1_gej_is_infinity(&tmp); -} - -int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) { - size_t i; - secp256k1_musig_session_internal session_i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(partial_sigs != NULL); - ARG_CHECK(n_sigs > 0); - - if (!secp256k1_musig_session_load(ctx, &session_i, session)) { - return 0; - } - for (i = 0; i < n_sigs; i++) { - secp256k1_scalar term; - if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { - return 0; - } - secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term); - } - secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part); - memcpy(&sig64[0], session_i.fin_nonce, 32); - return 1; -} - -#endif diff --git a/external/secp256k1/src/modules/musig/tests_impl.h b/external/secp256k1/src/modules/musig/tests_impl.h deleted file mode 100644 index ce6ae1784d..0000000000 --- a/external/secp256k1/src/modules/musig/tests_impl.h +++ /dev/null @@ -1,1143 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H -#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H - -#include -#include - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "../../../include/secp256k1_musig.h" - -#include "session.h" -#include "keyagg.h" -#include "../../scalar.h" -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../util.h" - -#include "vectors.h" - -static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) { - int ret; - secp256k1_keypair keypair_tmp; - ret = secp256k1_keypair_create(CTX, &keypair_tmp, sk); - ret &= secp256k1_keypair_pub(CTX, pk, &keypair_tmp); - if (keypair != NULL) { - *keypair = keypair_tmp; - } - return ret; -} - -/* Just a simple (non-tweaked) 2-of-2 MuSig aggregate, sign, verify - * test. */ -static void musig_simple_test(void) { - unsigned char sk[2][32]; - secp256k1_keypair keypair[2]; - secp256k1_musig_pubnonce pubnonce[2]; - const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - secp256k1_musig_aggnonce aggnonce; - unsigned char msg[32]; - secp256k1_xonly_pubkey agg_pk; - secp256k1_musig_keyagg_cache keyagg_cache; - unsigned char session_secrand[2][32]; - secp256k1_musig_secnonce secnonce[2]; - secp256k1_pubkey pk[2]; - const secp256k1_pubkey *pk_ptr[2]; - secp256k1_musig_partial_sig partial_sig[2]; - const secp256k1_musig_partial_sig *partial_sig_ptr[2]; - unsigned char final_sig[64]; - secp256k1_musig_session session; - int i; - - testrand256(msg); - for (i = 0; i < 2; i++) { - testrand256(sk[i]); - pk_ptr[i] = &pk[i]; - pubnonce_ptr[i] = &pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - - CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); - if (i == 0) { - testrand256(session_secrand[i]); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_secrand[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); - } else { - uint64_t nonrepeating_cnt = 0; - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[i], &pubnonce[i], nonrepeating_cnt, &keypair[i], NULL, NULL, NULL) == 1); - } - } - - CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); - - for (i = 0; i < 2; i++) { - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 1); - } - - CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1); -} - -/* Generate two pubnonces such that both group elements of their sum (calculated - * with secp256k1_musig_sum_pubnonces) are infinity. */ -static void pubnonce_summing_to_inf(secp256k1_musig_pubnonce *pubnonce) { - secp256k1_ge ge[2]; - int i; - secp256k1_gej summed_pubnonces[2]; - const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - - testutil_random_ge_test(&ge[0]); - testutil_random_ge_test(&ge[1]); - - for (i = 0; i < 2; i++) { - secp256k1_musig_pubnonce_save(&pubnonce[i], ge); - pubnonce_ptr[i] = &pubnonce[i]; - secp256k1_ge_neg(&ge[0], &ge[0]); - secp256k1_ge_neg(&ge[1], &ge[1]); - } - - secp256k1_musig_sum_pubnonces(CTX, summed_pubnonces, pubnonce_ptr, 2); - CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[0])); - CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[1])); -} - -int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { - int ret; - size_t i; - ret = secp256k1_memcmp_var(value, expected, len); - for (i = 0; i < len; i++) { - value[i] = testrand_bits(8); - } - return ret; -} - -static void musig_api_tests(void) { - secp256k1_musig_partial_sig partial_sig[2]; - const secp256k1_musig_partial_sig *partial_sig_ptr[2]; - secp256k1_musig_partial_sig invalid_partial_sig; - const secp256k1_musig_partial_sig *invalid_partial_sig_ptr[2]; - unsigned char pre_sig[64]; - unsigned char buf[32]; - unsigned char sk[2][32]; - secp256k1_keypair keypair[2]; - secp256k1_keypair invalid_keypair; - unsigned char max64[64]; - unsigned char zeros132[132] = { 0 }; - unsigned char session_secrand[2][32]; - unsigned char nonrepeating_cnt = 0; - secp256k1_musig_secnonce secnonce[2]; - secp256k1_musig_secnonce secnonce_tmp; - secp256k1_musig_secnonce invalid_secnonce; - secp256k1_musig_pubnonce pubnonce[2]; - const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - unsigned char pubnonce_ser[66]; - secp256k1_musig_pubnonce inf_pubnonce[2]; - const secp256k1_musig_pubnonce *inf_pubnonce_ptr[2]; - secp256k1_musig_pubnonce invalid_pubnonce; - const secp256k1_musig_pubnonce *invalid_pubnonce_ptr[1]; - secp256k1_musig_aggnonce aggnonce; - unsigned char aggnonce_ser[66]; - unsigned char msg[32]; - secp256k1_xonly_pubkey agg_pk; - secp256k1_pubkey full_agg_pk; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_musig_keyagg_cache invalid_keyagg_cache; - secp256k1_musig_session session; - secp256k1_musig_session invalid_session; - secp256k1_pubkey pk[2]; - const secp256k1_pubkey *pk_ptr[2]; - secp256k1_pubkey invalid_pk; - const secp256k1_pubkey *invalid_pk_ptr2[2]; - const secp256k1_pubkey *invalid_pk_ptr3[3]; - unsigned char tweak[32]; - int i; - - /** setup **/ - memset(max64, 0xff, sizeof(max64)); - memset(&invalid_keypair, 0, sizeof(invalid_keypair)); - memset(&invalid_pk, 0, sizeof(invalid_pk)); - memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); - memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); - pubnonce_summing_to_inf(inf_pubnonce); - /* Simulate structs being uninitialized by setting it to 0s. We don't want - * to produce undefined behavior by actually providing uninitialized - * structs. */ - memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); - memset(&invalid_pk, 0, sizeof(invalid_pk)); - memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); - memset(&invalid_session, 0, sizeof(invalid_session)); - - testrand256(msg); - testrand256(tweak); - for (i = 0; i < 2; i++) { - pk_ptr[i] = &pk[i]; - invalid_pk_ptr2[i] = &invalid_pk; - invalid_pk_ptr3[i] = &pk[i]; - pubnonce_ptr[i] = &pubnonce[i]; - inf_pubnonce_ptr[i] = &inf_pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - invalid_partial_sig_ptr[i] = &partial_sig[i]; - testrand256(session_secrand[i]); - testrand256(sk[i]); - CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); - } - invalid_pubnonce_ptr[0] = &invalid_pubnonce; - invalid_partial_sig_ptr[0] = &invalid_partial_sig; - /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test - * musig_pubkey_agg */ - invalid_pk_ptr3[2] = &invalid_pk; - - /** main test body **/ - - /** Key aggregation **/ - CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2)); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3)); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 0)); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 0)); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - - CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - - /* pubkey_get */ - CHECK(secp256k1_musig_pubkey_get(CTX, &full_agg_pk, &keyagg_cache) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, NULL, &keyagg_cache)); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, &full_agg_pk, NULL)); - CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); - - /** Tweaking **/ - { - int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32); - tweak_func[0] = secp256k1_musig_pubkey_ec_tweak_add; - tweak_func[1] = secp256k1_musig_pubkey_xonly_tweak_add; - for (i = 0; i < 2; i++) { - secp256k1_pubkey tmp_output_pk; - secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); - /* Reset keyagg_cache */ - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(CTX, NULL, &tmp_keyagg_cache, tweak) == 1); - tmp_keyagg_cache = keyagg_cache; - CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak)); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL)); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - /* Uninitialized keyagg_cache */ - CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak)); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - } - } - - /** Session creation with nonce_gen **/ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - /* nonce_gen, if successful, sets session_secrand to the zero array, which - * makes subsequent nonce_gen calls with the same session_secrand fail. So - * check that session_secrand is indeed the zero array and fill it with - * random values again. */ - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - - CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - /* session_secrand = 0 is disallowed because it indicates a faulty RNG */ - memcpy(&session_secrand[0], zeros132, sizeof(session_secrand[0])); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - - /* invalid seckey */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], NULL, msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, NULL, max64) == 1); - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); - CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); - - /* Every in-argument except session_secrand and pubkey can be NULL */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], NULL, NULL, NULL) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); - - /** Session creation with nonce_gen_counter **/ - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64) == 1); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen_counter(STATIC_CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, NULL, &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], NULL, nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* using nonce_gen_counter requires keypair */ - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, NULL, msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* invalid keypair */ - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &invalid_keypair, msg, &keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, &keyagg_cache, max64) == 1); - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, NULL, max64) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &invalid_keyagg_cache, max64)); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt,&keypair[0], msg, &keyagg_cache, NULL) == 1); - - /* Every in-argument except nonrepeating_cnt and keypair can be NULL */ - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, NULL, NULL) == 1); - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[1], &pubnonce[1], nonrepeating_cnt, &keypair[1], NULL, NULL, NULL) == 1); - - - /** Serialize and parse public nonces **/ - CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL)); - CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce)); - CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); - - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, NULL, pubnonce_ser)); - CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], NULL)); - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], zeros132) == 0); - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); - - { - /* Check that serialize and parse results in the same value */ - secp256k1_musig_pubnonce tmp; - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); - CHECK(secp256k1_musig_pubnonce_parse(CTX, &tmp, pubnonce_ser) == 1); - CHECK(secp256k1_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0); - } - - /** Receive nonces and aggregate **/ - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1)); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, inf_pubnonce_ptr, 2) == 1); - { - /* Check that the aggnonce encodes two points at infinity */ - secp256k1_ge aggnonce_pt[2]; - secp256k1_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); - for (i = 0; i < 2; i++) { - secp256k1_ge_is_infinity(&aggnonce_pt[i]); - } - } - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); - - /** Serialize and parse aggregate nonces **/ - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, NULL, &aggnonce)); - CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL)); - CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce)); - CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); - - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, NULL, aggnonce_ser)); - CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, &aggnonce, NULL)); - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, zeros132) == 1); - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); - - { - /* Check that serialize and parse results in the same value */ - secp256k1_musig_aggnonce tmp; - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); - CHECK(secp256k1_musig_aggnonce_parse(CTX, &tmp, aggnonce_ser) == 1); - CHECK(secp256k1_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0); - } - - /** Process nonces **/ - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache)); - - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); - - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); - /* The secnonce is set to 0 and subsequent signing attempts fail */ - CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - { - unsigned char sk_tmp[32]; - secp256k1_keypair keypair_tmp; - testrand256(sk_tmp); - CHECK(secp256k1_keypair_create(CTX, &keypair_tmp, sk_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - } - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session)); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); - - CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0])); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, &invalid_partial_sig)); - CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], buf) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, NULL, buf)); - { - /* Check that parsing failure results in an invalid sig */ - secp256k1_musig_partial_sig tmp; - CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, max64) == 0); - CHECK(secp256k1_memcmp_var(&tmp, zeros132, sizeof(partial_sig[0])) == 0); - } - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], NULL)); - - { - /* Check that serialize and parse results in the same value */ - secp256k1_musig_partial_sig tmp; - CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); - CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, buf) == 1); - CHECK(secp256k1_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0); - } - - /** Partial signature verification */ - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session)); - - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); - - /** Signature aggregation and verification */ - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2)); - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0)); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 1) == 1); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); -} - -static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { - secp256k1_scalar k1[2], k2[2]; - - secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); - testrand_flip(args[n_flip], n_bytes); - secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); - CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); - CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); -} - -static void musig_nonce_test(void) { - unsigned char *args[6]; - unsigned char session_secrand[32]; - unsigned char sk[32]; - unsigned char pk[33]; - unsigned char msg[32]; - unsigned char agg_pk[32]; - unsigned char extra_input[32]; - int i, j; - secp256k1_scalar k[6][2]; - - testrand_bytes_test(session_secrand, sizeof(session_secrand)); - testrand_bytes_test(sk, sizeof(sk)); - testrand_bytes_test(pk, sizeof(pk)); - testrand_bytes_test(msg, sizeof(msg)); - testrand_bytes_test(agg_pk, sizeof(agg_pk)); - testrand_bytes_test(extra_input, sizeof(extra_input)); - - /* Check that a bitflip in an argument results in different nonces. */ - args[0] = session_secrand; - args[1] = msg; - args[2] = sk; - args[3] = pk; - args[4] = agg_pk; - args[5] = extra_input; - for (i = 0; i < COUNT; i++) { - musig_nonce_bitflip(args, 0, sizeof(session_secrand)); - musig_nonce_bitflip(args, 1, sizeof(msg)); - musig_nonce_bitflip(args, 2, sizeof(sk)); - musig_nonce_bitflip(args, 3, sizeof(pk)); - musig_nonce_bitflip(args, 4, sizeof(agg_pk)); - musig_nonce_bitflip(args, 5, sizeof(extra_input)); - } - /* Check that if any argument is NULL, a different nonce is produced than if - * any other argument is NULL. */ - memcpy(msg, session_secrand, sizeof(msg)); - memcpy(sk, session_secrand, sizeof(sk)); - memcpy(pk, session_secrand, sizeof(session_secrand)); - memcpy(agg_pk, session_secrand, sizeof(agg_pk)); - memcpy(extra_input, session_secrand, sizeof(extra_input)); - secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); - secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); - secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); - for (i = 0; i < 6; i++) { - CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); - for (j = i+1; j < 6; j++) { - CHECK(!secp256k1_scalar_eq(&k[i][0], &k[j][0])); - CHECK(!secp256k1_scalar_eq(&k[i][1], &k[j][1])); - } - } -} - -static void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { - secp256k1_sha256 sha; - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); - test_sha256_eq(&sha, sha_tagged); -} - -/* Checks that the initialized tagged hashes have the expected - * state. */ -static void sha256_tag_test(void) { - secp256k1_sha256 sha; - { - char tag[] = "KeyAgg list"; - secp256k1_musig_keyagglist_sha256(&sha); - sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); - } - { - char tag[] = "KeyAgg coefficient"; - secp256k1_musig_keyaggcoef_sha256(&sha); - sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); - } - { - unsigned char tag[] = "MuSig/aux"; - secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); - } - { - unsigned char tag[] = "MuSig/nonce"; - secp256k1_nonce_function_musig_sha256_tagged(&sha); - sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); - } - { - unsigned char tag[] = "MuSig/noncecoef"; - secp256k1_musig_compute_noncehash_sha256_tagged(&sha); - sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); - } -} - -/* Attempts to create a signature for the aggregate public key using given secret - * keys and keyagg_cache. */ -static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) { - secp256k1_pubkey pk[2]; - unsigned char session_secrand[2][32]; - unsigned char msg[32]; - secp256k1_musig_secnonce secnonce[2]; - secp256k1_musig_pubnonce pubnonce[2]; - const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - secp256k1_musig_aggnonce aggnonce; - secp256k1_keypair keypair[2]; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig[2]; - const secp256k1_musig_partial_sig *partial_sig_ptr[2]; - unsigned char final_sig[64]; - int i; - - for (i = 0; i < 2; i++) { - pubnonce_ptr[i] = &pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - - testrand256(session_secrand[i]); - } - CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); - CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); - testrand256(msg); - - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk0, &pk[0], NULL, NULL, NULL) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk1, &pk[1], NULL, NULL, NULL) == 1); - - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, keyagg_cache) == 1); - - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); - - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); - - CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), agg_pk) == 1); -} - -/* Create aggregate public key P[0], tweak multiple times (using xonly and - * plain tweaking) and test signing. */ -static void musig_tweak_test(void) { - unsigned char sk[2][32]; - secp256k1_pubkey pk[2]; - const secp256k1_pubkey *pk_ptr[2]; - secp256k1_musig_keyagg_cache keyagg_cache; - enum { N_TWEAKS = 8 }; - secp256k1_pubkey P[N_TWEAKS + 1]; - secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1]; - int i; - - /* Key Setup */ - for (i = 0; i < 2; i++) { - pk_ptr[i] = &pk[i]; - testrand256(sk[i]); - CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); - } - /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ - CHECK(secp256k1_musig_pubkey_agg(CTX, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); - musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); - CHECK(secp256k1_musig_pubkey_get(CTX, &P[0], &keyagg_cache)); - - /* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for - * that key. If xonly is set to true, the function f normalizes the input - * point to have an even X-coordinate ("xonly-tweaking"). - * Otherwise, the function f is the identity function. */ - for (i = 1; i <= N_TWEAKS; i++) { - unsigned char tweak[32]; - int P_parity; - int xonly = testrand_bits(1); - - testrand256(tweak); - if (xonly) { - CHECK(secp256k1_musig_pubkey_xonly_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); - } else { - CHECK(secp256k1_musig_pubkey_ec_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); - } - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &P_xonly[i], &P_parity, &P[i])); - /* Check that musig_pubkey_tweak_add produces same result as - * xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */ - if (xonly) { - unsigned char P_serialized[32]; - CHECK(secp256k1_xonly_pubkey_serialize(CTX, P_serialized, &P_xonly[i])); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); - } else { - secp256k1_pubkey tmp_key = P[i-1]; - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &tmp_key, tweak)); - CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0); - } - /* Test signing for P[i] */ - musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); - } -} - -int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, - secp256k1_musig_keyagg_cache *keyagg_cache, - unsigned char *agg_pk_ser, - const unsigned char pubkeys33[][33], - const unsigned char tweaks32[][32], - size_t key_indices_len, - const size_t *key_indices, - size_t tweak_indices_len, - const size_t *tweak_indices, - const int *is_xonly) { - secp256k1_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; - const secp256k1_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; - int i; - secp256k1_pubkey agg_pk; - secp256k1_xonly_pubkey agg_pk_xonly; - - for (i = 0; i < (int)key_indices_len; i++) { - if (!secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { - *error = MUSIG_PUBKEY; - return 0; - } - pk_ptr[i] = &pubkeys[i]; - } - if (!secp256k1_musig_pubkey_agg(CTX, NULL, keyagg_cache, pk_ptr, key_indices_len)) { - *error = MUSIG_OTHER; - return 0; - } - - for (i = 0; i < (int)tweak_indices_len; i++) { - if (is_xonly[i]) { - if (!secp256k1_musig_pubkey_xonly_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { - *error = MUSIG_TWEAK; - return 0; - } - } else { - if (!secp256k1_musig_pubkey_ec_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { - *error = MUSIG_TWEAK; - return 0; - } - } - } - if (!secp256k1_musig_pubkey_get(CTX, &agg_pk, keyagg_cache)) { - *error = MUSIG_OTHER; - return 0; - } - - if (!secp256k1_xonly_pubkey_from_pubkey(CTX, &agg_pk_xonly, NULL, &agg_pk)) { - *error = MUSIG_OTHER; - return 0; - } - - if (agg_pk_ser != NULL) { - if (!secp256k1_xonly_pubkey_serialize(CTX, agg_pk_ser, &agg_pk_xonly)) { - *error = MUSIG_OTHER; - return 0; - } - } - - return 1; -} - -static void musig_test_vectors_keyagg(void) { - size_t i; - const struct musig_key_agg_vector *vector = &musig_key_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - unsigned char agg_pk[32]; - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); - } - - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - - CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(c->error == error); - } -} - -static void musig_test_vectors_noncegen(void) { - size_t i; - const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; - - for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { - const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL; - unsigned char session_secrand32[32]; - secp256k1_musig_secnonce secnonce; - secp256k1_musig_pubnonce pubnonce; - const unsigned char *sk = NULL; - const unsigned char *msg = NULL; - const unsigned char *extra_in = NULL; - secp256k1_pubkey pk; - unsigned char pubnonce66[66]; - - memcpy(session_secrand32, c->rand_, 32); - if (c->has_sk) { - sk = c->sk; - } - if (c->has_aggpk) { - /* Create keyagg_cache from aggpk */ - secp256k1_keyagg_cache_internal cache_i; - secp256k1_xonly_pubkey aggpk; - memset(&cache_i, 0, sizeof(cache_i)); - CHECK(secp256k1_xonly_pubkey_parse(CTX, &aggpk, c->aggpk)); - CHECK(secp256k1_xonly_pubkey_load(CTX, &cache_i.pk, &aggpk)); - secp256k1_keyagg_cache_save(&keyagg_cache, &cache_i); - keyagg_cache_ptr = &keyagg_cache; - } - if (c->has_msg) { - msg = c->msg; - } - if (c->has_extra_in) { - extra_in = c->extra_in; - } - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk, c->pk, sizeof(c->pk))); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce, &pubnonce, session_secrand32, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); - CHECK(secp256k1_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0); - /* The last element of the secnonce is the public key (uncompressed in - * secp256k1_musig_secnonce, compressed in the test vector secnonce). */ - CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); - CHECK(secp256k1_memcmp_var(&c->expected_secnonce[2*32], c->pk, sizeof(c->pk)) == 0); - - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); - CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66)); - CHECK(secp256k1_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0); - } -} - - -static void musig_test_vectors_nonceagg(void) { - size_t i; - int j; - const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; - secp256k1_musig_pubnonce pubnonce[2]; - const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - secp256k1_musig_aggnonce aggnonce; - unsigned char aggnonce66[66]; - - for (j = 0; j < 2; j++) { - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); - pubnonce_ptr[j] = &pubnonce[j]; - } - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce)); - CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; - secp256k1_musig_pubnonce pubnonce[2]; - for (j = 0; j < 2; j++) { - int expected = c->invalid_nonce_idx != j; - CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); - } - } -} - -static void musig_test_set_secnonce(secp256k1_musig_secnonce *secnonce, const unsigned char *secnonce64, const secp256k1_pubkey *pubkey) { - secp256k1_ge pk; - secp256k1_scalar k[2]; - - secp256k1_scalar_set_b32(&k[0], &secnonce64[0], NULL); - secp256k1_scalar_set_b32(&k[1], &secnonce64[32], NULL); - CHECK(secp256k1_pubkey_load(CTX, &pk, pubkey)); - secp256k1_musig_secnonce_save(secnonce, k, &pk); -} - -static void musig_test_vectors_signverify(void) { - size_t i; - const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_valid_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_pubkey pubkey; - secp256k1_musig_pubnonce pubnonce; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig; - secp256k1_musig_secnonce secnonce; - secp256k1_keypair keypair; - unsigned char partial_sig32[32]; - - CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); - CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); - - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[0])); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { - const struct musig_sign_error_case *c = &vector->sign_error_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_pubkey pubkey; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig; - secp256k1_musig_secnonce secnonce; - secp256k1_keypair keypair; - int expected; - - if (i == 0) { - /* Skip this vector since the implementation does not error out when - * the signing key does not belong to any pubkey. */ - continue; - } - expected = c->error != MUSIG_PUBKEY; - CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(expected || c->error == error); - if (!expected) { - continue; - } - - expected = c->error != MUSIG_AGGNONCE; - CHECK(expected == secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); - if (!expected) { - continue; - } - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); - expected = c->error != MUSIG_SECNONCE; - if (expected) { - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - } else { - CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - } - } - for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { - const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig; - enum { NUM_PUBNONCES = 3 }; - secp256k1_musig_pubnonce pubnonce[NUM_PUBNONCES]; - const secp256k1_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; - secp256k1_pubkey pubkey; - int expected; - size_t j; - - CHECK(NUM_PUBNONCES <= c->nonce_indices_len); - for (j = 0; j < c->nonce_indices_len; j++) { - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); - pubnonce_ptr[j] = &pubnonce[j]; - } - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); - - expected = c->error != MUSIG_SIG; - CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig, c->sig)); - if (!expected) { - continue; - } - expected = c->error != MUSIG_SIG_VERIFY; - CHECK(expected == secp256k1_musig_partial_sig_verify(CTX, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { - const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_musig_pubnonce pubnonce; - int expected; - - expected = c->error != MUSIG_PUBKEY; - CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(expected || c->error == error); - if (!expected) { - continue; - } - expected = c->error != MUSIG_PUBNONCE; - CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); - } -} - -static void musig_test_vectors_tweak(void) { - size_t i; - const struct musig_tweak_vector *vector = &musig_tweak_vector; - secp256k1_pubkey pubkey; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_secnonce secnonce; - - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonce)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_tweak_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - secp256k1_musig_pubnonce pubnonce; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig; - secp256k1_keypair keypair; - unsigned char partial_sig32[32]; - - musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey); - - CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); - - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); - CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); - - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_tweak_case *c = &vector->error_case[i]; - enum MUSIG_ERROR error; - secp256k1_musig_keyagg_cache keyagg_cache; - CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(error == MUSIG_TWEAK); - } -} - -static void musig_test_vectors_sigagg(void) { - size_t i, j; - const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_sig_agg_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - unsigned char final_sig[64]; - secp256k1_musig_keyagg_cache keyagg_cache; - unsigned char agg_pk32[32]; - secp256k1_xonly_pubkey agg_pk; - secp256k1_musig_aggnonce aggnonce; - secp256k1_musig_session session; - secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, c->aggnonce)); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); - for (j = 0; j < c->psig_indices_len; j++) { - CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); - partial_sig_ptr[j] = &partial_sig[j]; - } - - CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); - CHECK(secp256k1_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); - - CHECK(secp256k1_xonly_pubkey_parse(CTX, &agg_pk, agg_pk32)); - CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_sig_agg_case *c = &vector->error_case[i]; - secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - for (j = 0; j < c->psig_indices_len; j++) { - int expected = c->invalid_sig_idx != (int)j; - CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); - } - } -} - -/* Since the BIP doesn't provide static test vectors for nonce_gen_counter, we - * define a static test here */ -static void musig_test_static_nonce_gen_counter(void) { - secp256k1_musig_secnonce secnonce; - secp256k1_musig_pubnonce pubnonce; - unsigned char pubnonce66[66]; - secp256k1_pubkey pk; - secp256k1_keypair keypair; - uint64_t nonrepeating_cnt = 0; - unsigned char sk[32] = { - 0xEE, 0xC1, 0xCB, 0x7D, 0x1B, 0x72, 0x54, 0xC5, - 0xCA, 0xB0, 0xD9, 0xC6, 0x1A, 0xB0, 0x2E, 0x64, - 0x3D, 0x46, 0x4A, 0x59, 0xFE, 0x6C, 0x96, 0xA7, - 0xEF, 0xE8, 0x71, 0xF0, 0x7C, 0x5A, 0xEF, 0x54, - }; - unsigned char expected_secnonce[64] = { - 0x84, 0x2F, 0x13, 0x80, 0xCD, 0x17, 0xA1, 0x98, - 0xFC, 0x3D, 0xAD, 0x3B, 0x7D, 0xA7, 0x49, 0x29, - 0x41, 0xF4, 0x69, 0x76, 0xF2, 0x70, 0x2F, 0xF7, - 0xC6, 0x6F, 0x24, 0xF4, 0x72, 0x03, 0x6A, 0xF1, - 0xDA, 0x3F, 0x95, 0x2D, 0xDE, 0x4A, 0x2D, 0xA6, - 0xB6, 0x32, 0x57, 0x07, 0xCE, 0x87, 0xA4, 0xE3, - 0x61, 0x6D, 0x06, 0xFC, 0x5F, 0x81, 0xA9, 0xC9, - 0x93, 0x86, 0xD2, 0x0A, 0x99, 0xCE, 0xCF, 0x99, - }; - unsigned char expected_pubnonce[66] = { - 0x03, 0xA5, 0xB9, 0xB6, 0x90, 0x79, 0x42, 0xEA, - 0xCD, 0xDA, 0x49, 0xA3, 0x66, 0x01, 0x6E, 0xC2, - 0xE6, 0x24, 0x04, 0xA1, 0xBF, 0x4A, 0xB6, 0xD4, - 0xDB, 0x82, 0x06, 0x7B, 0xC3, 0xAD, 0xF0, 0x86, - 0xD7, 0x03, 0x32, 0x05, 0xDB, 0x9E, 0xB3, 0x4D, - 0x5C, 0x7C, 0xE0, 0x28, 0x48, 0xCA, 0xC6, 0x8A, - 0x83, 0xED, 0x73, 0xE3, 0x88, 0x34, 0x77, 0xF5, - 0x63, 0xF2, 0x3C, 0xE9, 0xA1, 0x1A, 0x77, 0x21, - 0xEC, 0x64, - }; - - CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair)); - CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, NULL, NULL, NULL) == 1); - - CHECK(secp256k1_memcmp_var(&secnonce.data[4], expected_secnonce, 2*32) == 0); - CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); - - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); - CHECK(secp256k1_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0); -} - -static void run_musig_tests(void) { - int i; - - for (i = 0; i < COUNT; i++) { - musig_simple_test(); - } - musig_api_tests(); - musig_nonce_test(); - for (i = 0; i < COUNT; i++) { - /* Run multiple times to ensure that pk and nonce have different y - * parities */ - musig_tweak_test(); - } - sha256_tag_test(); - musig_test_vectors_keyagg(); - musig_test_vectors_noncegen(); - musig_test_vectors_nonceagg(); - musig_test_vectors_signverify(); - musig_test_vectors_tweak(); - musig_test_vectors_sigagg(); - - musig_test_static_nonce_gen_counter(); -} - -#endif diff --git a/external/secp256k1/src/modules/musig/vectors.h b/external/secp256k1/src/modules/musig/vectors.h deleted file mode 100644 index 8407c2a69a..0000000000 --- a/external/secp256k1/src/modules/musig/vectors.h +++ /dev/null @@ -1,346 +0,0 @@ -/** - * Automatically generated by ./tools/test_vectors_musig2_generate.py. - * - * The test vectors for the KeySort function are included in this file. They can - * be found in src/modules/extrakeys/tests_impl.h. */ - -enum MUSIG_ERROR { - MUSIG_PUBKEY, - MUSIG_TWEAK, - MUSIG_PUBNONCE, - MUSIG_AGGNONCE, - MUSIG_SECNONCE, - MUSIG_SIG, - MUSIG_SIG_VERIFY, - MUSIG_OTHER -}; - -struct musig_key_agg_valid_test_case { - size_t key_indices_len; - size_t key_indices[4]; - unsigned char expected[32]; -}; - -struct musig_key_agg_error_test_case { - size_t key_indices_len; - size_t key_indices[4]; - size_t tweak_indices_len; - size_t tweak_indices[1]; - int is_xonly[1]; - enum MUSIG_ERROR error; -}; - -struct musig_key_agg_vector { - unsigned char pubkeys[7][33]; - unsigned char tweaks[2][32]; - struct musig_key_agg_valid_test_case valid_case[4]; - struct musig_key_agg_error_test_case error_case[5]; -}; - -static const struct musig_key_agg_vector musig_key_agg_vector = { - { - { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, - { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, - { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 }, - { 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }, - { 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } - }, - { - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, - { 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B } - }, - { - { 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }}, - { 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }}, - { 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }}, - { 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }}, - }, - { - { 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, - { 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, - { 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, - { 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK }, - { 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK }, - }, -}; - -struct musig_nonce_gen_test_case { - unsigned char rand_[32]; - int has_sk; - unsigned char sk[32]; - unsigned char pk[33]; - int has_aggpk; - unsigned char aggpk[32]; - int has_msg; - unsigned char msg[32]; - int has_extra_in; - unsigned char extra_in[32]; - unsigned char expected_secnonce[97]; - unsigned char expected_pubnonce[66]; -}; - -struct musig_nonce_gen_vector { - struct musig_nonce_gen_test_case test_case[2]; -}; - -static const struct musig_nonce_gen_vector musig_nonce_gen_vector = { - { - { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } }, - { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } }, - }, -}; - -struct musig_nonce_agg_test_case { - size_t pnonce_indices[2]; - /* if valid case */ - unsigned char expected[66]; - /* if error case */ - int invalid_nonce_idx; -}; - -struct musig_nonce_agg_vector { - unsigned char pnonces[7][66]; - struct musig_nonce_agg_test_case valid_case[2]; - struct musig_nonce_agg_test_case error_case[3]; -}; - -static const struct musig_nonce_agg_vector musig_nonce_agg_vector = { - { - { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 }, - { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, - { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, - { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, - { 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, - { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 }, - { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } - }, - { - { { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 }, - { { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 }, - }, - { - { { 0, 4 }, { 0 }, 1 }, - { { 5, 1 }, { 0 }, 0 }, - { { 6, 1 }, { 0 }, 0 }, - }, -}; - -/* Omit pubnonces in the test vectors because our partial signature verification - * implementation is able to accept the aggnonce directly. */ -struct musig_valid_case { - size_t key_indices_len; - size_t key_indices[3]; - size_t aggnonce_index; - size_t msg_index; - size_t signer_index; - unsigned char expected[32]; -}; - -struct musig_sign_error_case { - size_t key_indices_len; - size_t key_indices[3]; - size_t aggnonce_index; - size_t msg_index; - size_t secnonce_index; - enum MUSIG_ERROR error; -}; - -struct musig_verify_fail_error_case { - unsigned char sig[32]; - size_t key_indices_len; - size_t key_indices[3]; - size_t nonce_indices_len; - size_t nonce_indices[3]; - size_t msg_index; - size_t signer_index; - enum MUSIG_ERROR error; -}; - -struct musig_sign_verify_vector { - unsigned char sk[32]; - unsigned char pubkeys[4][33]; - unsigned char secnonces[2][194]; - unsigned char pubnonces[5][194]; - unsigned char aggnonces[5][66]; - unsigned char msgs[1][32]; - struct musig_valid_case valid_case[4]; - struct musig_sign_error_case sign_error_case[6]; - struct musig_verify_fail_error_case verify_fail_case[3]; - struct musig_verify_fail_error_case verify_error_case[2]; -}; - -static const struct musig_sign_verify_vector musig_sign_verify_vector = { - { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, - { - { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, - { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 }, - { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } - }, - { - { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } - }, - { - { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, - { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, - { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }, - { 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, - { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 } - }, - { - { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, - { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }, - { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } - }, - { - { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF } - }, - { - { 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }}, - { 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }}, - { 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }}, - { 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }}, - }, - { - { 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY }, - { 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY }, - { 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE }, - { 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE }, - { 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE }, - { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE }, - }, - { - { { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, - { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, - { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG }, - }, - { - { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, - { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, - }, -}; - -struct musig_tweak_case { - size_t key_indices_len; - size_t key_indices[3]; - size_t nonce_indices_len; - size_t nonce_indices[3]; - size_t tweak_indices_len; - size_t tweak_indices[4]; - int is_xonly[4]; - size_t signer_index; - unsigned char expected[32]; -}; - -struct musig_tweak_vector { - unsigned char sk[32]; - unsigned char secnonce[97]; - unsigned char aggnonce[66]; - unsigned char msg[32]; - unsigned char pubkeys[3][33]; - unsigned char pubnonces[3][194]; - unsigned char tweaks[5][32]; - struct musig_tweak_case valid_case[5]; - struct musig_tweak_case error_case[1]; -}; - -static const struct musig_tweak_vector musig_tweak_vector = { - { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, - { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, - { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, - { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }, - { - { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, - { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 } - }, - { - { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, - { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, - { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 } - }, - { - { 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB }, - { 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 }, - { 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 }, - { 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } - }, - { - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }}, - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }}, - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }}, - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }}, - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }}, - }, - { - { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }}, - }, -}; - -/* Omit pubnonces in the test vectors because they're only needed for - * implementations that do not directly accept an aggnonce. */ -struct musig_sig_agg_case { - size_t key_indices_len; - size_t key_indices[2]; - size_t tweak_indices_len; - size_t tweak_indices[3]; - int is_xonly[3]; - unsigned char aggnonce[66]; - size_t psig_indices_len; - size_t psig_indices[2]; - /* if valid case */ - unsigned char expected[64]; - /* if error case */ - int invalid_sig_idx; -}; - -struct musig_sig_agg_vector { - unsigned char pubkeys[4][33]; - unsigned char tweaks[3][32]; - unsigned char psigs[9][32]; - unsigned char msg[32]; - struct musig_sig_agg_case valid_case[4]; - struct musig_sig_agg_case error_case[1]; -}; - -static const struct musig_sig_agg_vector musig_sig_agg_vector = { - { - { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, - { 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 }, - { 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C }, - { 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 } - }, - { - { 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C }, - { 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC }, - { 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 } - }, - { - { 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB }, - { 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 }, - { 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 }, - { 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 }, - { 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE }, - { 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 }, - { 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC }, - { 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } - }, - { 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 }, - { - { 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 }, - { 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 }, - { 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 }, - { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 }, - }, - { - { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 }, - }, -}; -enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 }; diff --git a/external/secp256k1/src/modules/recovery/Makefile.am.include b/external/secp256k1/src/modules/recovery/Makefile.am.include deleted file mode 100644 index 156ea690fa..0000000000 --- a/external/secp256k1/src/modules/recovery/Makefile.am.include +++ /dev/null @@ -1,5 +0,0 @@ -include_HEADERS += include/secp256k1_recovery.h -noinst_HEADERS += src/modules/recovery/main_impl.h -noinst_HEADERS += src/modules/recovery/tests_impl.h -noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h -noinst_HEADERS += src/modules/recovery/bench_impl.h diff --git a/external/secp256k1/src/modules/recovery/bench_impl.h b/external/secp256k1/src/modules/recovery/bench_impl.h deleted file mode 100644 index 57108d4524..0000000000 --- a/external/secp256k1/src/modules/recovery/bench_impl.h +++ /dev/null @@ -1,62 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H -#define SECP256K1_MODULE_RECOVERY_BENCH_H - -#include "../../../include/secp256k1_recovery.h" - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - unsigned char sig[64]; -} bench_recover_data; - -static void bench_recover(void* arg, int iters) { - int i; - bench_recover_data *data = (bench_recover_data*)arg; - secp256k1_pubkey pubkey; - unsigned char pubkeyc[33]; - - for (i = 0; i < iters; i++) { - int j; - size_t pubkeylen = 33; - secp256k1_ecdsa_recoverable_signature sig; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); - CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); - CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); - for (j = 0; j < 32; j++) { - data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ - data->msg[j] = data->sig[j]; /* Move former R to message. */ - data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ - } - } -} - -static void bench_recover_setup(void* arg) { - int i; - bench_recover_data *data = (bench_recover_data*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = 1 + i; - } - for (i = 0; i < 64; i++) { - data->sig[i] = 65 + i; - } -} - -static void run_recovery_bench(int iters, int argc, char** argv) { - bench_recover_data data; - int d = argc == 1; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - - if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters); - - secp256k1_context_destroy(data.ctx); -} - -#endif /* SECP256K1_MODULE_RECOVERY_BENCH_H */ diff --git a/external/secp256k1/src/modules/recovery/main_impl.h b/external/secp256k1/src/modules/recovery/main_impl.h deleted file mode 100644 index 76a005e017..0000000000 --- a/external/secp256k1/src/modules/recovery/main_impl.h +++ /dev/null @@ -1,159 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H -#define SECP256K1_MODULE_RECOVERY_MAIN_H - -#include "../../../include/secp256k1_recovery.h" - -static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { - (void)ctx; - if (sizeof(secp256k1_scalar) == 32) { - /* When the secp256k1_scalar type is exactly 32 byte, use its - * representation inside secp256k1_ecdsa_signature, as conversion is very fast. - * Note that secp256k1_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - secp256k1_scalar_set_b32(r, &sig->data[0], NULL); - secp256k1_scalar_set_b32(s, &sig->data[32], NULL); - } - *recid = sig->data[64]; -} - -static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { - if (sizeof(secp256k1_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - secp256k1_scalar_get_b32(&sig->data[0], r); - secp256k1_scalar_get_b32(&sig->data[32], s); - } - sig->data[64] = recid; -} - -int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { - secp256k1_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - ARG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - secp256k1_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { - secp256k1_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(recid != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); - secp256k1_scalar_get_b32(&output64[0], &r); - secp256k1_scalar_get_b32(&output64[32], &s); - return 1; -} - -int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { - secp256k1_scalar r, s; - int recid; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(sigin != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); - secp256k1_ecdsa_signature_save(sig, &r, &s); - return 1; -} - -static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { - unsigned char brx[32]; - secp256k1_fe fx; - secp256k1_ge x; - secp256k1_gej xj; - secp256k1_scalar rn, u1, u2; - secp256k1_gej qj; - int r; - - if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, sigr); - r = secp256k1_fe_set_b32_limit(&fx, brx); - (void)r; - VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); - } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, sigr); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, sigs); - secp256k1_ecmult(&qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); -} - -int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar r, s; - int ret, recid; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - - ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata); - secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); - return ret; -} - -int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) { - secp256k1_ge q; - secp256k1_scalar r, s; - secp256k1_scalar m; - int recid; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); - VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ - secp256k1_scalar_set_b32(&m, msghash32, NULL); - if (secp256k1_ecdsa_sig_recover(&r, &s, &q, &m, recid)) { - secp256k1_pubkey_save(pubkey, &q); - return 1; - } else { - memset(pubkey, 0, sizeof(*pubkey)); - return 0; - } -} - -#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h deleted file mode 100644 index 6bbc02b9a8..0000000000 --- a/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h +++ /dev/null @@ -1,148 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H -#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H - -#include "main_impl.h" -#include "../../../include/secp256k1_recovery.h" - -static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { - int i, j, k; - uint64_t iter = 0; - - /* Loop */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ - for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ - if (skip_section(&iter)) continue; - for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ - const int starting_k = k; - secp256k1_fe r_dot_y_normalized; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - int expected_recid; - int recid; - int overflow; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); - - secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); - - /* Check directly */ - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); - r_from_k(&expected_r, group, k, &overflow); - CHECK(r == expected_r); - CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); - /* The recid's second bit is for conveying overflow (R.x value >= group order). - * In the actual secp256k1 this is an astronomically unlikely event, but in the - * small group used here, it will almost certainly be the case for all points. - * Note that this isn't actually useful; full recovery would need to convey - * floor(R.x / group_order), but only one bit is used as that is sufficient - * in the real group. */ - expected_recid = overflow ? 2 : 0; - r_dot_y_normalized = group[k].y; - secp256k1_fe_normalize(&r_dot_y_normalized); - /* Also the recovery id is flipped depending if we hit the low-s branch */ - if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) { - expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized); - } else { - expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized); - } - CHECK(recid == expected_recid); - - /* Convert to a standard sig then check */ - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k, NULL); - CHECK(r == expected_r); - CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); - - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } - } - } -} - -static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { - /* This is essentially a copy of test_exhaustive_verify, with recovery added */ - int s, r, msg, key; - uint64_t iter = 0; - for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { - for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { - for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { - for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int recid = 0; - int k, should_verify; - unsigned char msg32[32]; - - if (skip_section(&iter)) continue; - - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - secp256k1_scalar_get_b32(msg32, &msg_s); - - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k, NULL); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); - - /* We would like to try recovering the pubkey and checking that it matches, - * but pubkey recovery is impossible in the exhaustive tests (the reason - * being that there are 12 nonzero r values, 12 nonzero points, and no - * overlap between the sets, so there are no valid signatures). */ - - /* Verify by converting to a standard signature and calling verify */ - secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } - } - } - } -} - -static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) { - test_exhaustive_recovery_sign(ctx, group); - test_exhaustive_recovery_verify(ctx, group); -} - -#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */ diff --git a/external/secp256k1/src/modules/recovery/tests_impl.h b/external/secp256k1/src/modules/recovery/tests_impl.h deleted file mode 100644 index 7a28a3ce65..0000000000 --- a/external/secp256k1/src/modules/recovery/tests_impl.h +++ /dev/null @@ -1,338 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H -#define SECP256K1_MODULE_RECOVERY_TESTS_H - -static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - (void) msg32; - (void) key32; - (void) algo16; - (void) data; - - /* On the first run, return 0 to force a second run */ - if (counter == 0) { - memset(nonce32, 0, 32); - return 1; - } - /* On the second run, return an overflow to force a third run */ - if (counter == 1) { - memset(nonce32, 0xff, 32); - return 1; - } - /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ - memset(nonce32, 1, 32); - return testrand_bits(1); -} - -static void test_ecdsa_recovery_api(void) { - /* Setup contexts that just count errors */ - secp256k1_pubkey pubkey; - secp256k1_pubkey recpubkey; - secp256k1_ecdsa_signature normal_sig; - secp256k1_ecdsa_recoverable_signature recsig; - unsigned char privkey[32] = { 1 }; - unsigned char message[32] = { 2 }; - int recid = 0; - unsigned char sig[74]; - unsigned char zero_privkey[32] = { 0 }; - unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); - - /* Check bad contexts and NULLs for signing */ - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL)); - /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ - secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL); - /* These will all fail, but not in ARG_CHECK way */ - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0); - /* This one will succeed. */ - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - - /* Check signing with a goofy nonce function */ - - /* Check bad contexts and NULLs for recovery */ - CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL)); - - /* Check NULLs for conversion */ - CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL)); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1); - - /* Check NULLs for de/serialization */ - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL)); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1); - - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5)); - /* overflow in signature will not result in calling illegal_callback */ - memcpy(sig, over_privkey, 32); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0); -} - -static void test_ecdsa_recovery_end_to_end(void) { - unsigned char extra[32] = {0x00}; - unsigned char privkey[32]; - unsigned char message[32]; - secp256k1_ecdsa_signature signature[5]; - secp256k1_ecdsa_recoverable_signature rsignature[5]; - unsigned char sig[74]; - secp256k1_pubkey pubkey; - secp256k1_pubkey recpubkey; - int recid = 0; - - /* Generate a random key and message. */ - { - secp256k1_scalar msg, key; - testutil_random_scalar_order_test(&msg); - testutil_random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_scalar_get_b32(message, &msg); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); - - /* Serialize/parse compact and verify/recover. */ - extra[0] = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1); - extra[31] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1); - extra[31] = 0; - extra[0] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); - memset(&rsignature[4], 0, sizeof(rsignature[4])); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); - /* Parse compact (with recovery id) and recover. */ - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); - /* Serialize/destroy/parse signature and verify again. */ - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); - sig[testrand_bits(6)] += 1 + testrand_int(255); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0); - /* Recover again */ - CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 || - secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); -} - -/* Tests several edge cases. */ -static void test_ecdsa_recovery_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' - }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 1. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - secp256k1_pubkey pubkey; - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - secp256k1_pubkey pubkeyb; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - int recid; - - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0)); - CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1)); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2)); - CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3)); - CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); - - for (recid = 0; recid < 4; recid++) { - int i; - int recid2; - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; - unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; - unsigned char sigbderalt1[39] = { - 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt2[39] = { - 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, - 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, - 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - secp256k1_pubkey pubkey2b; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); - } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); - /* Leading zeros. */ - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); - sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); - sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); - sigbder[7]--; - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0); - for(i = 0; i < 8; i++) { - int c; - unsigned char orig = sigbder[i]; - /*Try every single-byte change.*/ - for (c = 0; c < 256; c++) { - if (c == orig ) { - continue; - } - sigbder[i] = c; - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); - } - sigbder[i] = orig; - } - } - - /* Test r/s equal to zero */ - { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - secp256k1_pubkey pubkeyc; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); - } -} - -static void run_recovery_tests(void) { - int i; - for (i = 0; i < COUNT; i++) { - test_ecdsa_recovery_api(); - } - for (i = 0; i < 64*COUNT; i++) { - test_ecdsa_recovery_end_to_end(); - } - test_ecdsa_recovery_edge_cases(); -} - -#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/external/secp256k1/src/modules/schnorrsig/Makefile.am.include b/external/secp256k1/src/modules/schnorrsig/Makefile.am.include deleted file mode 100644 index 654fa2e5ae..0000000000 --- a/external/secp256k1/src/modules/schnorrsig/Makefile.am.include +++ /dev/null @@ -1,5 +0,0 @@ -include_HEADERS += include/secp256k1_schnorrsig.h -noinst_HEADERS += src/modules/schnorrsig/main_impl.h -noinst_HEADERS += src/modules/schnorrsig/tests_impl.h -noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h -noinst_HEADERS += src/modules/schnorrsig/bench_impl.h diff --git a/external/secp256k1/src/modules/schnorrsig/bench_impl.h b/external/secp256k1/src/modules/schnorrsig/bench_impl.h deleted file mode 100644 index 93a878ede3..0000000000 --- a/external/secp256k1/src/modules/schnorrsig/bench_impl.h +++ /dev/null @@ -1,104 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORRSIG_BENCH_H -#define SECP256K1_MODULE_SCHNORRSIG_BENCH_H - -#include "../../../include/secp256k1_schnorrsig.h" - -#define MSGLEN 32 - -typedef struct { - secp256k1_context *ctx; - int n; - - const secp256k1_keypair **keypairs; - const unsigned char **pk; - const unsigned char **sigs; - const unsigned char **msgs; -} bench_schnorrsig_data; - -static void bench_schnorrsig_sign(void* arg, int iters) { - bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; - int i; - unsigned char msg[MSGLEN] = {0}; - unsigned char sig[64]; - - for (i = 0; i < iters; i++) { - msg[0] = i; - msg[1] = i >> 8; - CHECK(secp256k1_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL)); - } -} - -static void bench_schnorrsig_verify(void* arg, int iters) { - bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; - int i; - - for (i = 0; i < iters; i++) { - secp256k1_xonly_pubkey pk; - CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); - CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk)); - } -} - -static void run_schnorrsig_bench(int iters, int argc, char** argv) { - int i; - bench_schnorrsig_data data; - int d = argc == 1; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *)); - data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); - data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); - data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); - - CHECK(MSGLEN >= 4); - for (i = 0; i < iters; i++) { - unsigned char sk[32]; - unsigned char *msg = (unsigned char *)malloc(MSGLEN); - unsigned char *sig = (unsigned char *)malloc(64); - secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair)); - unsigned char *pk_char = (unsigned char *)malloc(32); - secp256k1_xonly_pubkey pk; - msg[0] = sk[0] = i; - msg[1] = sk[1] = i >> 8; - msg[2] = sk[2] = i >> 16; - msg[3] = sk[3] = i >> 24; - memset(&msg[4], 'm', MSGLEN - 4); - memset(&sk[4], 's', 28); - - data.keypairs[i] = keypair; - data.pk[i] = pk_char; - data.msgs[i] = msg; - data.sigs[i] = sig; - - CHECK(secp256k1_keypair_create(data.ctx, keypair, sk)); - CHECK(secp256k1_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL)); - CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair)); - CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); - } - - if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters); - if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "schnorrsig_verify")) run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters); - - for (i = 0; i < iters; i++) { - free((void *)data.keypairs[i]); - free((void *)data.pk[i]); - free((void *)data.msgs[i]); - free((void *)data.sigs[i]); - } - - /* Casting to (void *) avoids a stupid warning in MSVC. */ - free((void *)data.keypairs); - free((void *)data.pk); - free((void *)data.msgs); - free((void *)data.sigs); - - secp256k1_context_destroy(data.ctx); -} - -#endif diff --git a/external/secp256k1/src/modules/schnorrsig/main_impl.h b/external/secp256k1/src/modules/schnorrsig/main_impl.h deleted file mode 100644 index 82bba2f597..0000000000 --- a/external/secp256k1/src/modules/schnorrsig/main_impl.h +++ /dev/null @@ -1,269 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H -#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_schnorrsig.h" -#include "../../hash.h" - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ -static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0x46615b35ul; - sha->s[1] = 0xf4bfbff7ul; - sha->s[2] = 0x9f8dc671ul; - sha->s[3] = 0x83627ab3ul; - sha->s[4] = 0x60217180ul; - sha->s[5] = 0x57358661ul; - sha->s[6] = 0x21a29e54ul; - sha->s[7] = 0x68b07b4cul; - - sha->bytes = 64; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ -static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0x24dd3219ul; - sha->s[1] = 0x4eba7e70ul; - sha->s[2] = 0xca0fabb9ul; - sha->s[3] = 0x0fa3166dul; - sha->s[4] = 0x3afbe4b1ul; - sha->s[5] = 0x4c44df97ul; - sha->s[6] = 0x4aac2739ul; - sha->s[7] = 0x249e850aul; - - sha->bytes = 64; -} - -/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 - * by using the correct tagged hash function. */ -static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; - -static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; - -static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { - secp256k1_sha256 sha; - unsigned char masked_key[32]; - int i; - - if (algo == NULL) { - return 0; - } - - if (data != NULL) { - secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha); - secp256k1_sha256_write(&sha, data, 32); - secp256k1_sha256_finalize(&sha, masked_key); - for (i = 0; i < 32; i++) { - masked_key[i] ^= key32[i]; - } - } else { - /* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */ - static const unsigned char ZERO_MASK[32] = { - 84, 241, 105, 207, 201, 226, 229, 114, - 116, 128, 68, 31, 144, 186, 37, 196, - 136, 244, 97, 199, 11, 94, 165, 220, - 170, 247, 175, 105, 39, 10, 165, 20 - }; - for (i = 0; i < 32; i++) { - masked_key[i] = key32[i] ^ ZERO_MASK[i]; - } - } - - /* Tag the hash with algo which is important to avoid nonce reuse across - * algorithms. If this nonce function is used in BIP-340 signing as defined - * in the spec, an optimized tagging implementation is used. */ - if (algolen == sizeof(bip340_algo) - && secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) { - secp256k1_nonce_function_bip340_sha256_tagged(&sha); - } else { - secp256k1_sha256_initialize_tagged(&sha, algo, algolen); - } - - /* Hash masked-key||pk||msg using the tagged hash as per the spec */ - secp256k1_sha256_write(&sha, masked_key, 32); - secp256k1_sha256_write(&sha, xonly_pk32, 32); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, nonce32); - secp256k1_sha256_clear(&sha); - return 1; -} - -const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340; - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ -static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - sha->s[0] = 0x9cecba11ul; - sha->s[1] = 0x23925381ul; - sha->s[2] = 0x11679112ul; - sha->s[3] = 0xd1627e0ful; - sha->s[4] = 0x97c87550ul; - sha->s[5] = 0x003cc765ul; - sha->s[6] = 0x90f61164ul; - sha->s[7] = 0x33e9b66aul; - sha->bytes = 64; -} - -static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) -{ - unsigned char buf[32]; - secp256k1_sha256 sha; - - /* tagged hash(r.x, pk.x, msg) */ - secp256k1_schnorrsig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, r32, 32); - secp256k1_sha256_write(&sha, pubkey32, 32); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, buf); - /* Set scalar e to the challenge hash modulo the curve order as per - * BIP340. */ - secp256k1_scalar_set_b32(e, buf, NULL); -} - -static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) { - secp256k1_scalar sk; - secp256k1_scalar e; - secp256k1_scalar k; - secp256k1_gej rj; - secp256k1_ge pk; - secp256k1_ge r; - unsigned char buf[32] = { 0 }; - unsigned char pk_buf[32]; - unsigned char seckey[32]; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(msg != NULL || msglen == 0); - ARG_CHECK(keypair != NULL); - - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_bip340; - } - - ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair); - /* Because we are signing for a x-only pubkey, the secret key is negated - * before signing if the point corresponding to the secret key does not - * have an even Y. */ - if (secp256k1_fe_is_odd(&pk.y)) { - secp256k1_scalar_negate(&sk, &sk); - } - - secp256k1_scalar_get_b32(seckey, &sk); - secp256k1_fe_get_b32(pk_buf, &pk.x); - ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); - secp256k1_scalar_set_b32(&k, buf, NULL); - ret &= !secp256k1_scalar_is_zero(&k); - secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); - - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - secp256k1_ge_set_gej(&r, &rj); - - /* We declassify r to allow using it as a branch point. This is fine - * because r is not a secret. */ - secp256k1_declassify(ctx, &r, sizeof(r)); - secp256k1_fe_normalize_var(&r.y); - if (secp256k1_fe_is_odd(&r.y)) { - secp256k1_scalar_negate(&k, &k); - } - secp256k1_fe_normalize_var(&r.x); - secp256k1_fe_get_b32(&sig64[0], &r.x); - - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); - secp256k1_scalar_mul(&e, &e, &sk); - secp256k1_scalar_add(&e, &e, &k); - secp256k1_scalar_get_b32(&sig64[32], &e); - - secp256k1_memczero(sig64, 64, !ret); - secp256k1_scalar_clear(&k); - secp256k1_scalar_clear(&sk); - secp256k1_memclear(seckey, sizeof(seckey)); - secp256k1_gej_clear(&rj); - - return ret; -} - -int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { - /* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */ - return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32); -} - -int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { - return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32); -} - -int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) { - secp256k1_nonce_function_hardened noncefp = NULL; - void *ndata = NULL; - VERIFY_CHECK(ctx != NULL); - - if (extraparams != NULL) { - ARG_CHECK(secp256k1_memcmp_var(extraparams->magic, - schnorrsig_extraparams_magic, - sizeof(extraparams->magic)) == 0); - noncefp = extraparams->noncefp; - ndata = extraparams->ndata; - } - return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata); -} - -int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) { - secp256k1_scalar s; - secp256k1_scalar e; - secp256k1_gej rj; - secp256k1_ge pk; - secp256k1_gej pkj; - secp256k1_fe rx; - secp256k1_ge r; - unsigned char buf[32]; - int overflow; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(msg != NULL || msglen == 0); - ARG_CHECK(pubkey != NULL); - - if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) { - return 0; - } - - secp256k1_scalar_set_b32(&s, &sig64[32], &overflow); - if (overflow) { - return 0; - } - - if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - - /* Compute e. */ - secp256k1_fe_get_b32(buf, &pk.x); - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); - - /* Compute rj = s*G + (-e)*pkj */ - secp256k1_scalar_negate(&e, &e); - secp256k1_gej_set_ge(&pkj, &pk); - secp256k1_ecmult(&rj, &pkj, &e, &s); - - secp256k1_ge_set_gej_var(&r, &rj); - if (secp256k1_ge_is_infinity(&r)) { - return 0; - } - - secp256k1_fe_normalize_var(&r.y); - return !secp256k1_fe_is_odd(&r.y) && - secp256k1_fe_equal(&rx, &r.x); -} - -#endif diff --git a/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h deleted file mode 100644 index 601b54975d..0000000000 --- a/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +++ /dev/null @@ -1,214 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H -#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H - -#include "../../../include/secp256k1_schnorrsig.h" -#include "main_impl.h" - -static const unsigned char invalid_pubkey_bytes[][32] = { - /* 0 */ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - /* 2 */ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 - }, - /* order */ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF, - ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF, - ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF, - (EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF - }, - /* order + 1 */ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF, - ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF, - ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF, - (EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF - }, - /* field size */ - { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F - }, - /* field size + 1 (note that 1 is legal) */ - { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 - }, - /* 2^256 - 1 */ - { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - } -}; - -#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0])) - -static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, - size_t msglen, - const unsigned char *key32, const unsigned char *xonly_pk32, - const unsigned char *algo, size_t algolen, - void* data) { - secp256k1_scalar s; - int *idata = data; - (void)msg; - (void)msglen; - (void)key32; - (void)xonly_pk32; - (void)algo; - (void)algolen; - secp256k1_scalar_set_int(&s, *idata); - secp256k1_scalar_get_b32(nonce32, &s); - return 1; -} - -static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { - int d; - uint64_t iter = 0; - /* Iterate over the possible public keys to verify against (through their corresponding DL d). */ - for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) { - int actual_d; - unsigned k; - unsigned char pk32[32]; - memcpy(pk32, xonly_pubkey_bytes[d - 1], 32); - actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d; - /* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k. - Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */ - for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) { - unsigned char sig64[64]; - int actual_k = -1; - int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; - int e_count_done = 0; - if (skip_section(&iter)) continue; - if (k <= EXHAUSTIVE_TEST_ORDER / 2) { - memcpy(sig64, xonly_pubkey_bytes[k - 1], 32); - actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k; - } else { - memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32); - } - /* Randomly generate messages until all challenges have been hit. */ - while (e_count_done < EXHAUSTIVE_TEST_ORDER) { - secp256k1_scalar e; - unsigned char msg32[32]; - testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); - /* Only do work if we hit a challenge we haven't tried before. */ - if (!e_done[e]) { - /* Iterate over the possible valid last 32 bytes in the signature. - 0..order=that s value; order+1=random bytes */ - int count_valid = 0; - unsigned int s; - for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { - int expect_valid, valid; - if (s <= EXHAUSTIVE_TEST_ORDER) { - memset(sig64 + 32, 0, 32); - secp256k1_write_be32(sig64 + 60, s); - expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && - (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); - } else { - testrand256(sig64 + 32); - expect_valid = 0; - } - valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); - CHECK(valid == expect_valid); - count_valid += valid; - } - /* Exactly one s value must verify, unless R is illegal. */ - CHECK(count_valid == (actual_k != -1)); - /* Don't retry other messages that result in the same challenge. */ - e_done[e] = 1; - ++e_count_done; - } - } - } - } -} - -static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) { - int d, k; - uint64_t iter = 0; - secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - - /* Loop over keys. */ - for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) { - int actual_d = d; - if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d; - /* Loop over nonces. */ - for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) { - int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; - int e_count_done = 0; - unsigned char msg32[32]; - unsigned char sig64[64]; - int actual_k = k; - if (skip_section(&iter)) continue; - extraparams.noncefp = secp256k1_hardened_nonce_function_smallint; - extraparams.ndata = &k; - if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k; - /* Generate random messages until all challenges have been tried. */ - while (e_count_done < EXHAUSTIVE_TEST_ORDER) { - secp256k1_scalar e; - testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); - /* Only do work if we hit a challenge we haven't tried before. */ - if (!e_done[e]) { - secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; - unsigned char expected_s_bytes[32]; - secp256k1_scalar_get_b32(expected_s_bytes, &expected_s); - /* Invoke the real function to construct a signature. */ - CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams)); - /* The first 32 bytes must match the xonly pubkey for the specified k. */ - CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); - /* The last 32 bytes must match the expected s value. */ - CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); - /* Don't retry other messages that result in the same challenge. */ - e_done[e] = 1; - ++e_count_done; - } - } - } - } -} - -static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) { - secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; - secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; - int parity[EXHAUSTIVE_TEST_ORDER - 1]; - unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; - unsigned i; - - /* Verify that all invalid_pubkey_bytes are actually invalid. */ - for (i = 0; i < NUM_INVALID_KEYS; ++i) { - secp256k1_xonly_pubkey pk; - CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); - } - - /* Construct keypairs and xonly-pubkeys for the entire group. */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) { - secp256k1_scalar scalar_i; - unsigned char buf[32]; - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_scalar_get_b32(buf, &scalar_i); - CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); - CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); - } - - test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity); - test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity); -} - -#endif diff --git a/external/secp256k1/src/modules/schnorrsig/tests_impl.h b/external/secp256k1/src/modules/schnorrsig/tests_impl.h deleted file mode 100644 index 2d716a01f8..0000000000 --- a/external/secp256k1/src/modules/schnorrsig/tests_impl.h +++ /dev/null @@ -1,982 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_H -#define SECP256K1_MODULE_SCHNORRSIG_TESTS_H - -#include "../../../include/secp256k1_schnorrsig.h" - -/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many - * bytes) changes the hash function - */ -static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { - unsigned char nonces[2][32]; - CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); - testrand_flip(args[n_flip], n_bytes); - CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); - CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); -} - -static void run_nonce_function_bip340_tests(void) { - unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; - unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'}; - unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; - size_t algolen = sizeof(algo); - secp256k1_sha256 sha; - secp256k1_sha256 sha_optimized; - unsigned char nonce[32], nonce_z[32]; - unsigned char msg[32]; - size_t msglen = sizeof(msg); - unsigned char key[32]; - unsigned char pk[32]; - unsigned char aux_rand[32]; - unsigned char *args[5]; - int i; - - /* Check that hash initialized by - * secp256k1_nonce_function_bip340_sha256_tagged has the expected - * state. */ - secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag)); - secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); - - /* Check that hash initialized by - * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected - * state. */ - secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); - secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); - - testrand256(msg); - testrand256(key); - testrand256(pk); - testrand256(aux_rand); - - /* Check that a bitflip in an argument results in different nonces. */ - args[0] = msg; - args[1] = key; - args[2] = pk; - args[3] = algo; - args[4] = aux_rand; - for (i = 0; i < COUNT; i++) { - nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen); - nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen); - nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen); - /* Flip algo special case "BIP0340/nonce" */ - nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); - /* Flip algo again */ - nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); - nonce_function_bip340_bitflip(args, 4, 32, msglen, algolen); - } - - /* NULL algo is disallowed */ - CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0); - CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); - /* Other algo is fine */ - testrand_bytes_test(algo, algolen); - CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); - - for (i = 0; i < COUNT; i++) { - unsigned char nonce2[32]; - uint32_t offset = testrand_int(msglen - 1); - size_t msglen_tmp = (msglen + offset) % msglen; - size_t algolen_tmp; - - /* Different msglen gives different nonce */ - CHECK(nonce_function_bip340(nonce2, msg, msglen_tmp, key, pk, algo, algolen, NULL) == 1); - CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); - - /* Different algolen gives different nonce */ - offset = testrand_int(algolen - 1); - algolen_tmp = (algolen + offset) % algolen; - CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1); - CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); - } - - /* NULL aux_rand argument is allowed, and identical to passing all zero aux_rand. */ - memset(aux_rand, 0, 32); - CHECK(nonce_function_bip340(nonce_z, msg, msglen, key, pk, algo, algolen, &aux_rand) == 1); - CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); - CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0); -} - -static void test_schnorrsig_api(void) { - unsigned char sk1[32]; - unsigned char sk2[32]; - unsigned char sk3[32]; - unsigned char msg[32]; - secp256k1_keypair keypairs[3]; - secp256k1_keypair invalid_keypair = {{ 0 }}; - secp256k1_xonly_pubkey pk[3]; - secp256k1_xonly_pubkey zero_pk; - unsigned char sig[64]; - secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; - - testrand256(sk1); - testrand256(sk2); - testrand256(sk3); - testrand256(msg); - CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1); - CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1); - CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1); - memset(&zero_pk, 0, sizeof(zero_pk)); - - /** main test body **/ - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL)); - - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams)); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams)); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams)); - - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0])); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0])); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL)); - CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk)); -} - -/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the - * expected state. */ -static void test_schnorrsig_sha256_tagged(void) { - unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; - secp256k1_sha256 sha; - secp256k1_sha256 sha_optimized; - - secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); - secp256k1_schnorrsig_sha256_tagged(&sha_optimized); - test_sha256_eq(&sha, &sha_optimized); -} - -/* Helper function for schnorrsig_bip_vectors - * Signs the message and checks that it's the same as expected_sig. */ -static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) { - unsigned char sig[64]; - secp256k1_keypair keypair; - secp256k1_xonly_pubkey pk, pk_expected; - - secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - extraparams.ndata = (unsigned char*)aux_rand; - - CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams)); - CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); - if (msglen == 32) { - memset(sig, 0, 64); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand)); - CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); - } - - CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); - CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); -} - -/* Helper function for schnorrsig_bip_vectors - * Checks that both verify and verify_batch (TODO) return the same value as expected. */ -static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) { - secp256k1_xonly_pubkey pk; - - CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized)); - CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); -} - -/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See - * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ -static void test_schnorrsig_bip_vectors(void) { - { - /* Test vector 0 */ - const unsigned char sk[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 - }; - const unsigned char pk[32] = { - 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, - 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, - 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, - 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - const unsigned char msg[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - const unsigned char sig[64] = { - 0xE9, 0x07, 0x83, 0x1F, 0x80, 0x84, 0x8D, 0x10, - 0x69, 0xA5, 0x37, 0x1B, 0x40, 0x24, 0x10, 0x36, - 0x4B, 0xDF, 0x1C, 0x5F, 0x83, 0x07, 0xB0, 0x08, - 0x4C, 0x55, 0xF1, 0xCE, 0x2D, 0xCA, 0x82, 0x15, - 0x25, 0xF6, 0x6A, 0x4A, 0x85, 0xEA, 0x8B, 0x71, - 0xE4, 0x82, 0xA7, 0x4F, 0x38, 0x2D, 0x2C, 0xE5, - 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47, - 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0 - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 1 */ - const unsigned char sk[32] = { - 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, - 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, - 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, - 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF - }; - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x68, 0x96, 0xBD, 0x60, 0xEE, 0xAE, 0x29, 0x6D, - 0xB4, 0x8A, 0x22, 0x9F, 0xF7, 0x1D, 0xFE, 0x07, - 0x1B, 0xDE, 0x41, 0x3E, 0x6D, 0x43, 0xF9, 0x17, - 0xDC, 0x8D, 0xCF, 0x8C, 0x78, 0xDE, 0x33, 0x41, - 0x89, 0x06, 0xD1, 0x1A, 0xC9, 0x76, 0xAB, 0xCC, - 0xB2, 0x0B, 0x09, 0x12, 0x92, 0xBF, 0xF4, 0xEA, - 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C, - 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 2 */ - const unsigned char sk[32] = { - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9 - }; - const unsigned char pk[32] = { - 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, - 0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, - 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, - 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 - }; - const unsigned char aux_rand[32] = { - 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE, - 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC, - 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C, - 0x4B, 0x0B, 0x62, 0xD7, 0x98, 0xE6, 0xD9, 0x06 - }; - const unsigned char msg[32] = { - 0x7E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, - 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, - 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, - 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C - }; - const unsigned char sig[64] = { - 0x58, 0x31, 0xAA, 0xEE, 0xD7, 0xB4, 0x4B, 0xB7, - 0x4E, 0x5E, 0xAB, 0x94, 0xBA, 0x9D, 0x42, 0x94, - 0xC4, 0x9B, 0xCF, 0x2A, 0x60, 0x72, 0x8D, 0x8B, - 0x4C, 0x20, 0x0F, 0x50, 0xDD, 0x31, 0x3C, 0x1B, - 0xAB, 0x74, 0x58, 0x79, 0xA5, 0xAD, 0x95, 0x4A, - 0x72, 0xC4, 0x5A, 0x91, 0xC3, 0xA5, 0x1D, 0x3C, - 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E, - 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7 - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 3 */ - const unsigned char sk[32] = { - 0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81, - 0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0, - 0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54, - 0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10 - }; - const unsigned char pk[32] = { - 0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25, - 0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD, - 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, - 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 - }; - const unsigned char aux_rand[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - const unsigned char msg[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - const unsigned char sig[64] = { - 0x7E, 0xB0, 0x50, 0x97, 0x57, 0xE2, 0x46, 0xF1, - 0x94, 0x49, 0x88, 0x56, 0x51, 0x61, 0x1C, 0xB9, - 0x65, 0xEC, 0xC1, 0xA1, 0x87, 0xDD, 0x51, 0xB6, - 0x4F, 0xDA, 0x1E, 0xDC, 0x96, 0x37, 0xD5, 0xEC, - 0x97, 0x58, 0x2B, 0x9C, 0xB1, 0x3D, 0xB3, 0x93, - 0x37, 0x05, 0xB3, 0x2B, 0xA9, 0x82, 0xAF, 0x5A, - 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27, - 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3 - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 4 */ - const unsigned char pk[32] = { - 0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12, - 0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83, - 0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA, - 0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9 - }; - const unsigned char msg[32] = { - 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, - 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, - 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, - 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 - }; - const unsigned char sig[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, - 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, - 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, - 0x76, 0xAF, 0xB1, 0x54, 0x8A, 0xF6, 0x03, 0xB3, - 0xEB, 0x45, 0xC9, 0xF8, 0x20, 0x7D, 0xEE, 0x10, - 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93, - 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 5 */ - const unsigned char pk[32] = { - 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50, - 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21, - 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, - 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 - }; - secp256k1_xonly_pubkey pk_parsed; - /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); - } - { - /* Test vector 6 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0xFF, 0xF9, 0x7B, 0xD5, 0x75, 0x5E, 0xEE, 0xA4, - 0x20, 0x45, 0x3A, 0x14, 0x35, 0x52, 0x35, 0xD3, - 0x82, 0xF6, 0x47, 0x2F, 0x85, 0x68, 0xA1, 0x8B, - 0x2F, 0x05, 0x7A, 0x14, 0x60, 0x29, 0x75, 0x56, - 0x3C, 0xC2, 0x79, 0x44, 0x64, 0x0A, 0xC6, 0x07, - 0xCD, 0x10, 0x7A, 0xE1, 0x09, 0x23, 0xD9, 0xEF, - 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E, - 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 7 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x1F, 0xA6, 0x2E, 0x33, 0x1E, 0xDB, 0xC2, 0x1C, - 0x39, 0x47, 0x92, 0xD2, 0xAB, 0x11, 0x00, 0xA7, - 0xB4, 0x32, 0xB0, 0x13, 0xDF, 0x3F, 0x6F, 0xF4, - 0xF9, 0x9F, 0xCB, 0x33, 0xE0, 0xE1, 0x51, 0x5F, - 0x28, 0x89, 0x0B, 0x3E, 0xDB, 0x6E, 0x71, 0x89, - 0xB6, 0x30, 0x44, 0x8B, 0x51, 0x5C, 0xE4, 0xF8, - 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35, - 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 8 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, - 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, - 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, - 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, - 0x96, 0x17, 0x64, 0xB3, 0xAA, 0x9B, 0x2F, 0xFC, - 0xB6, 0xEF, 0x94, 0x7B, 0x68, 0x87, 0xA2, 0x26, - 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C, - 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 9 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x12, 0x3D, 0xDA, 0x83, 0x28, 0xAF, 0x9C, 0x23, - 0xA9, 0x4C, 0x1F, 0xEE, 0xCF, 0xD1, 0x23, 0xBA, - 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC, - 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 10 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x76, 0x15, 0xFB, 0xAF, 0x5A, 0xE2, 0x88, 0x64, - 0x01, 0x3C, 0x09, 0x97, 0x42, 0xDE, 0xAD, 0xB4, - 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9, - 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 11 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, - 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, - 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, - 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 12 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, - 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, - 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, - 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, - 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 13 */ - const unsigned char pk[32] = { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, - 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, - 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, - 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, - 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 - }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); - } - { - /* Test vector 14 */ - const unsigned char pk[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 - }; - secp256k1_xonly_pubkey pk_parsed; - /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); - } - { - /* Test vector 15 */ - const unsigned char sk[32] = { - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - }; - const unsigned char pk[32] = { - 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, - 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, - 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, - 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - /* const unsigned char msg[0] = {}; */ - const unsigned char sig[64] = { - 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB, - 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18, - 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC, - 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF, - 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62, - 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64, - 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27, - 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63, - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig); - test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1); - } - { - /* Test vector 16 */ - const unsigned char sk[32] = { - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - }; - const unsigned char pk[32] = { - 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, - 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, - 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, - 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - const unsigned char msg[] = { 0x11 }; - const unsigned char sig[64] = { - 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24, - 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A, - 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35, - 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03, - 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD, - 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96, - 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33, - 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF, - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 17 */ - const unsigned char sk[32] = { - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - }; - const unsigned char pk[32] = { - 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, - 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, - 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, - 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - const unsigned char msg[] = { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, - }; - const unsigned char sig[64] = { - 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B, - 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B, - 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52, - 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70, - 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8, - 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC, - 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51, - 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5, - }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } - { - /* Test vector 18 */ - const unsigned char sk[32] = { - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, - }; - const unsigned char pk[32] = { - 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, - 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, - 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, - 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, - }; - const unsigned char aux_rand[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - const unsigned char sig[64] = { - 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34, - 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63, - 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F, - 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8, - 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7, - 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23, - 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0, - 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67, - }; - unsigned char msg[100]; - memset(msg, 0x99, sizeof(msg)); - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); - } -} - -/* Nonce function that returns constant 0 */ -static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { - (void) msg; - (void) msglen; - (void) key32; - (void) xonly_pk32; - (void) algo; - (void) algolen; - (void) data; - (void) nonce32; - return 0; -} - -/* Nonce function that sets nonce to 0 */ -static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { - (void) msg; - (void) msglen; - (void) key32; - (void) xonly_pk32; - (void) algo; - (void) algolen; - (void) data; - - memset(nonce32, 0, 32); - return 1; -} - -/* Nonce function that sets nonce to 0xFF...0xFF */ -static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { - (void) msg; - (void) msglen; - (void) key32; - (void) xonly_pk32; - (void) algo; - (void) algolen; - (void) data; - - memset(nonce32, 0xFF, 32); - return 1; -} - -static void test_schnorrsig_sign(void) { - unsigned char sk[32]; - secp256k1_xonly_pubkey pk; - secp256k1_keypair keypair; - const unsigned char msg[] = {'t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'm', 's', 'g', ' ', 'f', 'o', 'r', ' ', 'a', ' ', 's', 'c', 'h', 'n', 'o', 'r', 'r', 's', 'i', 'g', '.', '.'}; - unsigned char sig[64]; - unsigned char sig2[64]; - unsigned char zeros64[64] = { 0 }; - secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - unsigned char aux_rand[32]; - - testrand256(sk); - testrand256(aux_rand); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); - /* Check that deprecated alias gives the same result */ - CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1); - CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); - - /* Test different nonce functions */ - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); - memset(sig, 1, sizeof(sig)); - extraparams.noncefp = nonce_function_failing; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); - CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); - memset(&sig, 1, sizeof(sig)); - extraparams.noncefp = nonce_function_0; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); - CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); - memset(&sig, 1, sizeof(sig)); - extraparams.noncefp = nonce_function_overflowing; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); - - /* When using the default nonce function, schnorrsig_sign_custom produces - * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ - extraparams.noncefp = NULL; - extraparams.ndata = aux_rand; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1); - CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); -} - -#define N_SIGS 3 -/* Creates N_SIGS valid signatures and verifies them with verify and - * verify_batch (TODO). Then flips some bits and checks that verification now - * fails. */ -static void test_schnorrsig_sign_verify(void) { - unsigned char sk[32]; - unsigned char msg[N_SIGS][32]; - unsigned char sig[N_SIGS][64]; - size_t i; - secp256k1_keypair keypair; - secp256k1_xonly_pubkey pk; - secp256k1_scalar s; - - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); - - for (i = 0; i < N_SIGS; i++) { - testrand256(msg[i]); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL)); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk)); - } - - { - /* Flip a few bits in the signature and in the message and check that - * verify and verify_batch (TODO) fail */ - size_t sig_idx = testrand_int(N_SIGS); - size_t byte_idx = testrand_bits(5); - unsigned char xorbyte = testrand_int(254)+1; - sig[sig_idx][byte_idx] ^= xorbyte; - CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); - sig[sig_idx][byte_idx] ^= xorbyte; - - byte_idx = testrand_bits(5); - sig[sig_idx][32+byte_idx] ^= xorbyte; - CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); - sig[sig_idx][32+byte_idx] ^= xorbyte; - - byte_idx = testrand_bits(5); - msg[sig_idx][byte_idx] ^= xorbyte; - CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); - msg[sig_idx][byte_idx] ^= xorbyte; - - /* Check that above bitflips have been reversed correctly */ - CHECK(secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); - } - - /* Test overflowing s */ - CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); - memset(&sig[0][32], 0xFF, 32); - CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); - - /* Test negative s */ - CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); - secp256k1_scalar_set_b32(&s, &sig[0][32], NULL); - secp256k1_scalar_negate(&s, &s); - secp256k1_scalar_get_b32(&sig[0][32], &s); - CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); - - /* The empty message can be signed & verified */ - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1); - - { - /* Test varying message lengths */ - unsigned char msg_large[32 * 8]; - uint32_t msglen = testrand_int(sizeof(msg_large)); - for (i = 0; i < sizeof(msg_large); i += 32) { - testrand256(&msg_large[i]); - } - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1); - /* Verification for a random wrong message length fails */ - msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large); - CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0); - } -} -#undef N_SIGS - -static void test_schnorrsig_taproot(void) { - unsigned char sk[32]; - secp256k1_keypair keypair; - secp256k1_xonly_pubkey internal_pk; - unsigned char internal_pk_bytes[32]; - secp256k1_xonly_pubkey output_pk; - unsigned char output_pk_bytes[32]; - unsigned char tweak[32]; - int pk_parity; - unsigned char msg[32]; - unsigned char sig[64]; - - /* Create output key */ - testrand256(sk); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); - /* In actual taproot the tweak would be hash of internal_pk */ - CHECK(secp256k1_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1); - - /* Key spend */ - testrand256(msg); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); - /* Verify key spend */ - CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1); - - /* Script spend */ - CHECK(secp256k1_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1); - /* Verify script spend */ - CHECK(secp256k1_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); -} - -static void run_schnorrsig_tests(void) { - int i; - run_nonce_function_bip340_tests(); - - test_schnorrsig_api(); - test_schnorrsig_sha256_tagged(); - test_schnorrsig_bip_vectors(); - for (i = 0; i < COUNT; i++) { - test_schnorrsig_sign(); - test_schnorrsig_sign_verify(); - } - test_schnorrsig_taproot(); -} - -#endif diff --git a/external/secp256k1/src/precompute_ecmult.c b/external/secp256k1/src/precompute_ecmult.c deleted file mode 100644 index 5ef198a770..0000000000 --- a/external/secp256k1/src/precompute_ecmult.c +++ /dev/null @@ -1,90 +0,0 @@ -/***************************************************************************************************** - * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *****************************************************************************************************/ - -#include -#include - -#include "../include/secp256k1.h" - -#include "assumptions.h" -#include "util.h" - -#include "field_impl.h" -#include "group_impl.h" -#include "int128_impl.h" -#include "ecmult.h" -#include "ecmult_compute_table_impl.h" - -static void print_table(FILE *fp, const char *name, int window_g, const secp256k1_ge_storage* table) { - int j; - int i; - - fprintf(fp, "const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); - fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 - ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", - SECP256K1_GE_STORAGE_CONST_GET(table[0])); - - j = 1; - for(i = 3; i <= window_g; ++i) { - fprintf(fp, "#if WINDOW_G > %d\n", i-1); - for(;j < ECMULT_TABLE_SIZE(i); ++j) { - fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 - ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", - SECP256K1_GE_STORAGE_CONST_GET(table[j])); - } - fprintf(fp, "#endif\n"); - } - fprintf(fp, "};\n"); -} - -static void print_two_tables(FILE *fp, int window_g) { - secp256k1_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); - secp256k1_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); - - secp256k1_ecmult_compute_two_tables(table, table_128, window_g, &secp256k1_ge_const_g); - - print_table(fp, "secp256k1_pre_g", window_g, table); - print_table(fp, "secp256k1_pre_g_128", window_g, table_128); - - free(table); - free(table_128); -} - -int main(void) { - /* Always compute all tables for window sizes up to 15. */ - int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE; - const char outfile[] = "src/precomputed_ecmult.c"; - FILE* fp; - - fp = fopen(outfile, "w"); - if (fp == NULL) { - fprintf(stderr, "Could not open %s for writing!\n", outfile); - return -1; - } - - fprintf(fp, "/* This file was automatically generated by precompute_ecmult. */\n"); - fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n"); - fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); - fprintf(fp, " */\n"); - fprintf(fp, "#include \"group.h\"\n"); - fprintf(fp, "#include \"ecmult.h\"\n"); - fprintf(fp, "#include \"precomputed_ecmult.h\"\n"); - fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); - fprintf(fp, "#if ECMULT_WINDOW_SIZE > %d\n", window_g); - fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build.\n"); - fprintf(fp, "#endif\n"); - fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); - fprintf(fp, "# error Cannot compile precomputed_ecmult.c in exhaustive test mode\n"); - fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); - fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n"); - - print_two_tables(fp, window_g); - - fprintf(fp, "#undef S\n"); - fclose(fp); - - return 0; -} diff --git a/external/secp256k1/src/precompute_ecmult_gen.c b/external/secp256k1/src/precompute_ecmult_gen.c deleted file mode 100644 index 4d153a6574..0000000000 --- a/external/secp256k1/src/precompute_ecmult_gen.c +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************************* - * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *********************************************************************************/ - -#include -#include - -#include "../include/secp256k1.h" - -#include "assumptions.h" -#include "util.h" - -#include "group.h" -#include "int128_impl.h" -#include "ecmult_gen.h" -#include "ecmult_gen_compute_table_impl.h" - -static const int CONFIGS[][2] = { - {2, 5}, - {11, 6}, - {43, 6} -}; - -static void print_table(FILE* fp, int blocks, int teeth) { - int spacing = CEIL_DIV(256, blocks * teeth); - size_t points = ((size_t)1) << (teeth - 1); - int outer; - size_t inner; - - secp256k1_ge_storage* table = checked_malloc(&default_error_callback, blocks * points * sizeof(secp256k1_ge_storage)); - secp256k1_ecmult_gen_compute_table(table, &secp256k1_ge_const_g, blocks, teeth, spacing); - - fprintf(fp, "#elif (COMB_BLOCKS == %d) && (COMB_TEETH == %d) && (COMB_SPACING == %d)\n", blocks, teeth, spacing); - for (outer = 0; outer != blocks; outer++) { - fprintf(fp,"{"); - for (inner = 0; inner != points; inner++) { - fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 - ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")", - SECP256K1_GE_STORAGE_CONST_GET(table[outer * points + inner])); - if (inner != points - 1) { - fprintf(fp,",\n"); - } - } - if (outer != blocks - 1) { - fprintf(fp,"},\n"); - } else { - fprintf(fp,"}\n"); - } - } - free(table); -} - -int main(int argc, char **argv) { - const char outfile[] = "src/precomputed_ecmult_gen.c"; - FILE* fp; - size_t config; - int did_current_config = 0; - - (void)argc; - (void)argv; - - fp = fopen(outfile, "w"); - if (fp == NULL) { - fprintf(stderr, "Could not open %s for writing!\n", outfile); - return -1; - } - - fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); - fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); - fprintf(fp, "#include \"group.h\"\n"); - fprintf(fp, "#include \"ecmult_gen.h\"\n"); - fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n"); - fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); - fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n"); - fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); - fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); - - fprintf(fp, "const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = {\n"); - fprintf(fp, "#if 0\n"); - for (config = 0; config < sizeof(CONFIGS) / sizeof(*CONFIGS); ++config) { - print_table(fp, CONFIGS[config][0], CONFIGS[config][1]); - if (CONFIGS[config][0] == COMB_BLOCKS && CONFIGS[config][1] == COMB_TEETH) { - did_current_config = 1; - } - } - if (!did_current_config) { - print_table(fp, COMB_BLOCKS, COMB_TEETH); - } - fprintf(fp, "#else\n"); - fprintf(fp, "# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build.\n"); - fprintf(fp, "#endif\n"); - - fprintf(fp, "};\n"); - fprintf(fp, "#undef S\n"); - fclose(fp); - - return 0; -} diff --git a/external/secp256k1/src/precomputed_ecmult.c b/external/secp256k1/src/precomputed_ecmult.c deleted file mode 100644 index cbd030ce50..0000000000 --- a/external/secp256k1/src/precomputed_ecmult.c +++ /dev/null @@ -1,16456 +0,0 @@ -/* This file was automatically generated by precompute_ecmult. */ -/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and - * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. - */ -#include "group.h" -#include "ecmult.h" -#include "precomputed_ecmult.h" -#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) -#if ECMULT_WINDOW_SIZE > 15 - #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build. -#endif -#ifdef EXHAUSTIVE_TEST_ORDER -# error Cannot compile precomputed_ecmult.c in exhaustive test mode -#endif /* EXHAUSTIVE_TEST_ORDER */ -#define WINDOW_G ECMULT_WINDOW_SIZE -const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = { - S(79be667e,f9dcbbac,55a06295,ce870b07,29bfcdb,2dce28d9,59f2815b,16f81798,483ada77,26a3c465,5da4fbfc,e1108a8,fd17b448,a6855419,9c47d08f,fb10d4b8) -#if WINDOW_G > 2 -,S(f9308a01,9258c310,49344f85,f89d5229,b531c845,836f99b0,8601f113,bce036f9,388f7b0f,632de814,fe337e6,2a37f356,6500a999,34c2231b,6cb9fd75,84b8e672) -#endif -#if WINDOW_G > 3 -,S(2f8bde4d,1a072093,55b4a725,a5c5128,e88b84bd,dc619ab7,cba8d569,b240efe4,d8ac2226,36e5e3d6,d4dba9dd,a6c9c426,f788271b,ab0d6840,dca87d3a,a6ac62d6) -,S(5cbdf064,6e5db4ea,a398f365,f2ea7a0e,3d419b7e,330e39c,e92bdded,cac4f9bc,6aebca40,ba255960,a3178d6d,861a54db,a813d0b8,13fde7b5,a5082628,87264da) -#endif -#if WINDOW_G > 4 -,S(acd484e2,f0c7f653,9ad178a,9f559abd,e0979697,4c57e714,c35f110d,fc27ccbe,cc338921,b0a7d9fd,64380971,763b61e9,add888a4,375f8e0f,5cc262a,c64f9c37) -,S(774ae7f8,58a9411e,5ef4246b,70c65aac,5649980b,e5c17891,bbec1789,5da008cb,d984a032,eb6b5e19,243dd56,d7b7b365,372db1e2,dff9d6a8,301d74c9,c953c61b) -,S(f28773c2,d975288b,c7d1d205,c3748651,b075fbc6,610e58cd,deeddf8f,19405aa8,ab0902e,8d880a89,758212eb,65cdaf47,3a1a06da,521fa91f,29b5cb52,db03ed81) -,S(d7924d4f,7d43ea96,5a465ae3,95ff411,31e5946f,3c85f79e,44adbcf8,e27e080e,581e2872,a86c72a6,83842ec2,28cc6def,ea40af2b,d896d3a5,c504dc9f,f6a26b58) -#endif -#if WINDOW_G > 5 -,S(defdea4c,db677750,a420fee8,7eacf21,eb9898ae,79b97687,66e4faa0,4a2d4a34,4211ab06,94635168,e997b0ea,d2a93dae,ced1f4a0,4a95c0f6,cfb199f6,9e56eb77) -,S(2b4ea0a7,97a443d2,93ef5cff,444f4979,f06acfeb,d7e86d27,74756561,38385b6c,85e89bc0,37945d93,b343083b,5a1c8613,1a01f60c,50269763,b570c854,e5c09b7a) -,S(352bbf4a,4cdd1256,4f93fa33,2ce33330,1d9ad402,71f81071,81340aef,25be59d5,321eb407,5348f534,d59c1825,9dda3e1f,4a1b3b2e,71b1039c,67bd3d8b,cf81998c) -,S(2fa2104d,6b38d11b,2300105,59879124,e42ab8df,eff5ff29,dc9cdadd,4ecacc3f,2de1068,295dd865,b6456933,5bd5dd80,181d70ec,fc882648,423ba76b,532b7d67) -,S(9248279b,9b4d68d,ab21a9b0,66edda83,263c3d84,e09572e2,69ca0cd7,f5453714,73016f7b,f234aade,5d1aa71b,dea2b1ff,3fc0de2a,887912ff,e54a32ce,97cb3402) -,S(daed4f2b,e3a8bf27,8e70132f,b0beb752,2f570e14,4bf615c0,7e996d44,3dee8729,a69dce4a,7d6c98e8,d4a1aca8,7ef8d700,3f83c230,f3afa726,ab40e522,90be1c55) -,S(c44d12c7,65d812e,8acf28d7,cbb19f90,11ecd9e9,fdf281b0,e6a3b5e8,7d22e7db,2119a460,ce326cdc,76c45926,c982fdac,e106e86,1edf61c5,a039063f,e0e6482) -,S(6a245bf6,dc698504,c89a20cf,ded60853,152b6953,36c28063,b61c65cb,d269e6b4,e022cf42,c2bd4a70,8b3f5126,f16a24ad,8b33ba48,d0423b6e,fd5e6348,100d8a82) -#endif -#if WINDOW_G > 6 -,S(1697ffa6,fd9de627,c077e3d2,fe541084,ce13300b,bec1146,f95ae57f,d0bd6a5,b9c398f1,86806f5d,27561506,e4557433,a2cf1500,9e498ae7,adee9d63,d01b2396) -,S(605bdb01,9981718b,986d0f07,e834cb0d,9deb8360,ffb7f61d,f982345e,f27a7479,2972d2d,e4f8d206,81a78d93,ec96fe23,c26bfae8,4fb14db4,3b01e1e9,56b8c49) -,S(62d14dab,4150bf49,7402fdc4,5a215e10,dcb01c35,4959b10c,fe31c7e9,d87ff33d,80fc06bd,8cc5b010,98088a19,50eed0db,1aa1329,67ab4722,35f56424,83b25eaf) -,S(80c60ad0,40f27da,de5b4b06,c408e56b,2c50e9f5,6b9b8b42,5e555c2f,86308b6f,1c38303f,1cc5c30f,26e66bad,7fe72f70,a65eed4c,be7024eb,1aa01f56,430bd57a) -,S(7a9375ad,6167ad54,aa74c634,8cc54d34,4cc5dc94,87d84704,9d5eabb0,fa03c8fb,d0e3fa9,eca87269,9559e0d,79269046,bdc59ea1,c70ce2b,2d499ec,224dc7f7) -,S(d528ecd9,b696b54c,907a9ed0,45447a79,bb408ec3,9b68df50,4bb51f45,9bc3ffc9,eecf4125,3136e5f9,9966f218,81fd656e,bc434540,5c520dbc,63465b5,21409933) -,S(49370a4,b5f43412,ea25f514,e8ecdad0,5266115e,4a7ecb13,87231808,f8b45963,758f3f41,afd6ed42,8b3081b0,512fd62a,54c3f3af,bb5b6764,b653052a,12949c9a) -,S(77f23093,6ee88cbb,d73df930,d64702ef,881d811e,e1498e2,f1c13eb1,fc345d74,958ef42a,7886b640,a08266e,9ba1b378,96c95330,d97077cb,be8eb3c7,671c60d6) -,S(f2dac991,cc4ce4b9,ea44887e,5c7c0bce,58c80074,ab9d4dba,eb28531b,7739f530,e0dedc9b,3b2f8dad,4da1f32d,ec2531df,9eb5fbeb,598e4fd,1a117dba,703a3c37) -,S(463b3d9f,662621fb,1b4be8fb,be252012,5a216cdf,c9dae3de,bcba4850,c690d45b,5ed430d7,8c296c35,43114306,dd8622d7,c622e27c,970a1de3,1cb377b0,1af7307e) -,S(f16f8042,44e46e2a,9232d4a,ff3b5997,6b98fac1,4328a2d1,a32496b4,9998f247,cedabd9b,82203f7e,13d206fc,df4e33d9,2a6c53c2,6e5cce26,d6579962,c4e31df6) -,S(caf75427,2dc84563,b0352b7a,14311af5,5d245315,ace27c65,369e15f7,151d41d1,cb474660,ef35f5f2,a41b643f,a5e46057,5f4fa9b7,962232a5,c32f9083,18a04476) -,S(2600ca4b,282cb986,f85d0f17,9979d8b,44a09c07,cb86d7c1,24497bc8,6f082120,4119b887,53c15bd6,a693b03f,cddbb45d,5ac6be74,ab5f0ef4,4b0be947,5a7e4b40) -,S(7635ca72,d7e8432c,338ec53c,d12220bc,1c48685,e24f7dc8,c602a774,6998e435,91b6496,9489d61,3d1d5e59,f78e6d7,4ecfc061,d57048ba,d9e76f30,2c5b9c61) -,S(754e3239,f325570c,dbbf4a87,deee8a66,b7f2b334,79d468fb,c1a50743,bf56cc18,673fb86,e5bda30f,b3cd0ed3,4ea49a0,23ee33d0,197a695d,c5d9809,3c536683) -,S(e3e6bd10,71a1e96a,ff57859c,82d570f0,33080066,1d1c952f,9fe26946,91d9b9e8,59c9e0bb,a394e76f,40c0aa58,379a3cb6,a5a22839,93e90c41,67002af4,920e37f5) -#endif -#if WINDOW_G > 7 -,S(186b483d,56a0338,26ae73d8,8f732985,c4ccb1f3,2ba35f4b,4cc47fdc,f04aa6eb,3b952d32,c67cf77e,2e17446e,204180ab,21fb8090,895138b4,a4a797f8,6e80888b) -,S(df9d70a6,b9876ce5,44c98561,f4be4f72,5442e6d2,b737d9c9,1a832172,4ce0963f,55eb2daf,d84d6ccd,5f862b78,5dc39d4a,b1572227,20ef9da2,17b8c45c,f2ba2417) -,S(5edd5cc2,3c51e87a,497ca815,d5dce0f8,ab52554f,849ed899,5de64c5f,34ce7143,efae9c8d,bc141306,61e8cec0,30c89ad0,c13c66c0,d17a2905,cdc706ab,7399a868) -,S(290798c2,b6476830,da12fe02,287e9e77,7aa3fba1,c355b17a,722d362f,84614fba,e38da76d,cd440621,988d00bc,f79af25d,5b29c094,db2a2314,6d003afd,41943e7a) -,S(af3c423a,95d9f5b3,54754ef,a150ac39,cd29552f,e3602573,62dfdece,f4053b45,f98a3fd8,31eb2b74,9a93b0e6,f35cfb40,c8cd5aa6,67a15581,bc2feded,498fd9c6) -,S(766dbb24,d134e745,cccaa28c,99bf2749,6bb66b2,6dcf98df,8d2fed50,d884249a,744b1152,eacbe5e3,8dcc8879,80da38b8,97584a65,fa06cedd,2c924f97,cbac5996) -,S(59dbf46f,8c94759b,a21277c3,3784f416,45f7b44f,6c596a58,ce92e666,191abe3e,c534ad44,175fbc30,f4ea6ce,648309a0,42ce739a,7919798c,d85e216c,4a307f6e) -,S(f13ada95,103c4537,305e691e,74e9a4a8,dd647e71,1a95e73c,b62dc601,8cfd87b8,e13817b4,4ee14de6,63bf4bc8,8341f32,6949e21a,6a75c257,778419b,daf5733d) -,S(7754b4fa,e8aced0,6d4167a2,c59cca4c,da1869c0,6ebadfb6,48855001,5a88522c,30e93e86,4e669d82,224b967c,3020b8fa,8d1e4e35,b6cbcc5,37a48b57,841163a2) -,S(948dcadf,5990e048,aa3874d4,6abef9d7,1858f95,de8041d2,a6828c99,e2262519,e491a425,37f6e597,d5d28a32,24b1bc25,df9154ef,bd2ef1d2,cbba2cae,5347d57e) -,S(79624144,50c76c16,89c7b48f,8202ec37,fb224cf5,ac0bfa15,70328a8a,3d7c77ab,100b610e,c4ffb476,d5c1fc1,33ef6f6b,12507a05,1f04ac57,60afa5b2,9db83437) -,S(35140878,34964b54,b15b1606,44d91548,5a169772,25b8847b,b0dd0851,37ec47ca,ef0afbb2,5620544,8e1652c4,8e8127fc,6039e77c,15c2378b,7e7d15a0,de293311) -,S(d3cc30ad,6b483e4b,c79ce2c9,dd8bc549,93e947eb,8df787b4,42943d3f,7b527eaf,8b378a22,d827278d,89c5e9be,8f9508ae,3c2ad462,90358630,afb34db0,4eede0a4) -,S(1624d847,80732860,ce1c78fc,bfefe08b,2b29823d,b913f649,3975ba0f,f4847610,68651cf9,b6da903e,914448c,6cd9d4ca,896878f5,282be4c8,cc06e2a4,4078575) -,S(733ce80d,a955a8a2,6902c956,33e62a98,5192474b,5af207da,6df7b4fd,5fc61cd4,f5435a2b,d2badf7d,485a4d8b,8db9fcce,3e1ef8e0,201e4578,c54673bc,1dc5ea1d) -,S(15d94412,54945064,cf1a1c33,bbd3b49f,8966c509,2171e699,ef258dfa,b81c045c,d56eb30b,69463e72,34f5137b,73b84177,434800ba,cebfc685,fc37bbe9,efe4070d) -,S(a1d0fcf2,ec9de675,b612136e,5ce70d27,1c21417c,9d2b8aaa,ac138599,d0717940,edd77f50,bcb5a3ca,b2e90737,309667f2,641462a5,4070f3d5,19212d39,c197a629) -,S(e22fbe15,c0af8ccc,5780c073,5f84dbe9,a790bade,e8245c06,c7ca3733,1cb36980,a855bab,ad5cd60c,88b430a6,9f53a1a7,a3828915,4964799b,e43d06d7,7d31da06) -,S(311091dd,9860e8e2,ee13473,c1155f5f,69635e39,4704eaa7,40094522,46cfa9b3,66db656f,87d1f04f,ffd1f047,88c06830,871ec5a6,4feee685,bd80f0b1,286d8374) -,S(34c1fd04,d301be89,b31c0442,d3e6ac24,883928b4,5a934078,1867d423,2ec2dbdf,9414685,e97b1b59,54bd46f7,30174136,d57f1cee,b487443d,c5321857,ba73abee) -,S(f219ea5d,6b54701c,1c14de5b,557eb42a,8d13f3ab,bcd08aff,cc2a5e6b,49b8d63,4cb95957,e83d40b0,f73af454,4cccf6b1,f4b08d3c,7b27fb8,d8c2962a,400766d1) -,S(d7b8740f,74a8fbaa,b1f683db,8f45de26,543a5490,bca62708,72369124,69a0b448,fa779681,28d9c92e,e1010f33,7ad4717e,ff15db5e,d3c049b3,411e0315,eaa4593b) -,S(32d31c22,2f8f6f0e,f86f7c98,d3a3335e,ad5bcd32,abdd9428,9fe4d309,1aa824bf,5f3032f5,892156e3,9ccd3d79,15b9e1da,2e6dac9e,6f26e961,118d14b8,462e1661) -,S(7461f371,914ab326,71045a15,5d9831ea,8793d77c,d59592c4,340f86cb,c18347b5,8ec0ba23,8b96bec0,cbdddcae,aa44254,2eee1ff5,c986ea6,b39847b3,cc092ff6) -,S(ee079adb,1df18600,74356a25,aa38206a,6d716b2c,3e67453d,287698ba,d7b2b2d6,8dc2412a,afe3be5c,4c5f37e0,ecc5f9f6,a446989a,f04c4e25,ebaac479,ec1c8c1e) -,S(16ec93e4,47ec83f0,467b1830,2ee620f7,e65de331,874c9dc7,2bfd8616,ba9da6b5,5e463115,e62fb40,d0e8c2a7,ca5804a3,9d58186a,50e49713,9626778e,25b0674d) -,S(eaa5f980,c245f6f0,38978290,afa70b6b,d8855897,f98b6aa4,85b96065,d537bd99,f65f5d3e,292c2e08,19a52839,1c994624,d784869d,7e6ea67f,b1804102,4edc07dc) -,S(78c9407,544ac132,692ee191,a024399,58ae0487,7151342e,a96c4b6b,35a49f51,f3e03191,69eb9b85,d5404795,539a5e68,fa1fbd58,3c064d24,62b675f1,94a3ddb4) -,S(494f4be2,19a1a770,16dcd838,431aea00,1cdc8ae,7a6fc688,726578d9,702857a5,42242a96,9283a5f3,39ba7f07,5e36ba2a,f925ce30,d767ed6e,55f4b031,880d562c) -,S(a598a803,da6d86c,6bc7f2f5,144ea549,d28211ea,58faa70e,bf4c1e66,5c1fe9b5,204b5d6f,84822c30,7e4b4a71,40737aec,23fc63b6,5b35f86a,10026dbd,2d864e6b) -,S(c4191636,5abb2b5d,9192f5f,2dbeafec,208f020f,12570a18,4dbadc3e,58595997,4f14351,d0087efa,49d245b3,28984989,d5caf945,f34bfc0,ed16e96b,58fa9913) -,S(841d6063,a586fa47,5a724604,da03bc5b,92a2e0d2,e0a36acf,e4c73a55,14742881,73867f5,9c0659e8,1904f9a1,c7543698,e62562d6,744c169c,e7a36de0,1a8d6154) -#endif -#if WINDOW_G > 8 -,S(5e95bb39,9a6971d3,76026947,f89bde2f,282b3381,928be4d,ed112ac4,d70e20d5,39f23f36,6809085b,eebfc711,81313775,a99c9aed,7d8ba38b,161384c7,46012865) -,S(36e4641a,53948fd4,76c39f8a,99fd974e,5ec07564,b5315d8b,f99471bc,a0ef2f66,d2424b1b,1abe4eb8,164227b0,85c9aa94,56ea1349,3fd563e0,6fd51cf5,694c78fc) -,S(336581e,a7bfbbb2,90c191a2,f507a41c,f5643842,170e914f,aeab27c2,c579f726,ead12168,595fe1be,99252129,b6e56b33,91f7ab14,10cd1e0e,f3dcdcab,d2fda224) -,S(8ab89816,dadfd6b6,a1f2634f,cf00ec84,3781025,ed6890c4,84974270,6bd43ede,6fdcef09,f2f6d0a0,44e654ae,f624136f,503d459c,3e898458,58a47a91,29cdd24e) -,S(1e33f1a7,46c9c577,8133344d,9299fcaa,20b0938e,8acff254,4bb40284,b8c5fb94,6066025,7dd11b3a,a9c8ed61,8d24edff,2306d320,f1d03010,e33a7d20,57f3b3b6) -,S(85b7c1dc,b3cec1b7,ee7f30de,d79dd20a,ed1f4cc,18cbcfcf,a410361f,d8f08f31,3d98a9cd,d026dd43,f39048f2,5a8847f4,fcafad18,95d7a633,c6fed3c3,5e999511) -,S(29df9fbd,8d9e4650,9275f4b1,25d6d45d,7fbe9a3b,878a7af8,72a28006,61ac5f51,b4c4fe9,9c775a60,6e2d8862,179139ff,da61dc86,1c019e55,cd2876eb,2a27d84b) -,S(a0b1cae0,6b0a847a,3fea6e67,1aaf8adf,dfe58ca2,f768105c,8082b2e4,49fce252,ae434102,edde0958,ec4b19d9,17a6a28e,6b72da18,34aff0e6,50f04950,3a296cf2) -,S(4e8ceaf,b9b3e9a1,36dc7ff6,7e840295,b499dfb3,b2133e4b,a113f2e4,c0e121e5,cf217411,8c8b6d7a,4b48f6d5,34ce5c79,422c086a,63460502,b827ce62,a326683c) -,S(d24a44e0,47e19b6f,5afb81c7,ca2f6908,a507668,9a010919,f42725c2,b789a33b,6fb8d559,1b466f8f,c63db50f,1c0f1c69,13f9968,87b8244d,2cdec417,afea8fa3) -,S(ea01606a,7a6c9cdd,249fdfcf,acb99584,1edd28,abbab77b,5104e98e,8e3b35d4,322af490,8c7312b0,cfbfe369,f7a7b3cd,b7d4494b,c2823700,cfd65218,8a3ea98d) -,S(af8addbf,2b661c8a,6c632865,5eb96651,252007d8,c5ea31be,4ad196de,8ce2131f,6749e67c,29b85f5,2a034eaf,d096836b,25208186,80e26ac8,f3dfbcdb,71749700) -,S(e3ae19,74566ca0,6cc516d4,7e0fb165,a674a3da,bcfca15e,722f0e34,50f45889,2aeabe7e,45315101,16217f07,bf4d0730,de97e48,74f81f53,3420a72e,eb0bd6a4) -,S(591ee355,313d9972,1cf6993f,fed1e3e3,1993ff3,ed258802,75ea8ce,d397e246,b0ea558a,113c30be,a60fc477,5460c790,1ff0b053,d25ca2bd,eee98f1a,4be5d196) -,S(11396d55,fda54c49,f19aa973,18d8da61,fa8584e4,7b084945,77cf032,55b52984,998c74a8,cd45ac01,289d5833,a7beb474,4ff536b0,1b257be4,c5767bea,93ea57a4) -,S(3c5d2a1b,a39c5a17,90000738,c9e0c40b,8dcdfd54,68754b64,5540157,e017aa7a,b2284279,995a34e2,f9d4de73,96fc18b8,f9b8b9f,dd270f66,61f79ca4,c81bd257) -,S(cc8704b8,a60a0def,a3a99a72,99f2e9c3,fbc395af,b04ac078,425ef8a1,793cc030,bdd46039,feed1788,1d1e0862,db347f8c,f395b74f,c4bcdc4e,940b74e3,ac1f1b13) -,S(c533e4f7,ea8555aa,cd9777ac,5cad29b9,7dd4defc,cc53ee7e,a204119b,2889b197,6f0a256b,c5efdf42,9a2fb624,2f1a43a2,d9b925bb,4a4b3a26,bb8e0f45,eb596096) -,S(c14f8f2,ccb27d6f,109f6d08,d03cc96a,69ba8c34,eec07bbc,f566d48e,33da6593,c359d692,3bb398f7,fd4473e1,6fe1c284,75b740dd,98075e6,c0e86491,13dc3a38) -,S(a6cbc304,6bc6a450,bac24789,fa17115a,4c9739ed,75f8f21c,e441f72e,b90e6ef,21ae7f4,680e889b,b130619e,2c0f95a3,60ceb573,c7060313,9862afd6,17fa9b9f) -,S(347d6d9a,2c48927,ebfb86c1,359b1caf,130a3c02,67d11ce6,344b39f9,9d43cc38,60ea7f61,a353524d,1c987f6e,cec92f08,6d565ab6,87870cb1,2689ff1e,31c74448) -,S(da6545d2,181db8d9,83f7dcb3,75ef5866,d47c67b1,bf31c8cf,855ef743,7b72656a,49b96715,ab6878a7,9e78f07c,e5680c5d,6673051b,4935bd89,7fea824b,77dc208a) -,S(c40747cc,9d012cb1,a13b8148,309c6de7,ec25d694,5d657146,b9d5994b,8feb1111,5ca56075,3be2a12f,c6de6caf,2cb48956,5db93615,6b9514e1,bb5e8303,7e0fa2d4) -,S(4e42c8ec,82c99798,ccf3a610,be870e78,338c7f71,3348bd34,c8203ef4,37f3502,7571d74e,e5e0fb92,a7a8b33a,7783341,a5492144,cc54bcc4,a944736,93606437) -,S(3775ab70,89bc6af8,23aba2e1,af70b236,d251cadb,c867432,87522a1b,3b0dedea,be52d107,bcfa09d8,bcb9736a,828cfa7f,ac8db17b,f7a76a2c,42ad9614,9018cf7) -,S(cee31cbf,7e34ec37,9d94fb81,4d3d775a,d954595d,1314ba88,46959e3e,82f74e26,8fd64a14,c06b589c,26b947ae,2bcf6bfa,149ef0b,e14ed4d8,f448a01,c43b1c6d) -,S(b4f9eaea,9b69176,19f6ea6a,4eb5464e,fddb58fd,45b1ebef,cdc1a01d,8b47986,39e5c992,5b5a54b0,7433a4f1,8c61726f,8bb131c0,12ca542e,b24a8ac0,7200682a) -,S(d4263dfc,3d2df923,a0179a48,966d30ce,84e2515a,fc3dccc1,b7790779,2ebcc60e,62dfaf07,a0f78feb,30e30d62,95853ce1,89e12776,ad6cf7f,ae164e12,2a208d54) -,S(48457524,820fa65a,4f8d35eb,6930857c,32acc0,a4a2de42,2233eeda,897612c4,25a748ab,367979d9,8733c38a,1fa1c2e7,dc6cc07d,b2d60a9a,e7a76aaa,49bd0f77) -,S(dfeeef18,81101f2c,b11644f3,a2afdfc2,45e1991,9152923f,367a1767,c11cceda,ecfb7056,cf1de042,f9420bab,396793c0,c390bde7,4b4bbdff,16a83ae0,9a9a7517) -,S(6d7ef6b1,7543f837,3c573f44,e1f38983,5d89bcbc,6062ced3,6c82df83,b8fae859,cd450ec3,35438986,dfefa10c,57fea9bc,c521a095,9b2d80bb,f74b190d,ca712d10) -,S(e75605d5,9102a5a2,684500d3,b991f2e3,f3c88b93,22554703,5af25af6,6e04541f,f5c54754,a8f71ee5,40b9b487,28473e31,4f729ac5,308b0693,8360990e,2bfad125) -,S(eb98660f,4c4dfaa0,6a2be453,d5020bc9,9a0c2e60,abe38845,7dd43fef,b1ed620c,6cb9a887,6d9cb852,609af3a,dd26cd20,a0a7cd8a,9411131c,e85f4410,99223e) -,S(13e87b02,7d8514d3,5939f2e6,892b1992,21545969,41888336,dc3563e3,b8dba942,fef5a3c6,8059a6de,c5d62411,4bf1e91a,ac2b9da5,68d6abeb,2570d556,46b8adf1) -,S(ee163026,e9fd6fe0,17c38f06,a5be6fc1,25424b37,1ce2708e,7bf44916,91e5764a,1acb250f,255dd61c,43d94ccc,670d0f58,f49ae3fa,15b96623,e5430da0,ad6c62b2) -,S(b268f5ef,9ad51e4d,78de3a75,c2dc89b,1e626d43,50586799,9932e5db,33af3d80,5f310d4b,3c99b9eb,b19f77d4,1c1dee01,8cf0d34f,d4191614,3e945a,1216e423) -,S(ff07f311,8a9df035,e9fad85e,b6c7bfe4,2b02f01c,a99ceea3,bf7ffdba,93c4750d,438136d6,3e858a3,a5c440c3,8eccbadd,c1d29421,14e2eddd,4740d098,ced1f0d8) -,S(8d8b9855,c7c052a3,4146fd20,ffb658be,a4b9f69e,d825ebe,c16e8c3c,e2b526a1,cdb559ee,dc2d79f9,26baf44f,b84ea4d4,4bcf50fe,e51d7ceb,30e2e7f4,63036758) -,S(52db0b53,84dfbf05,bfa9d472,d7ae26df,e4b851ce,ca91b1eb,a5426318,da32b63,c3b997d,50ee5d4,23ebaf66,a6db9f57,b3180c90,2875679d,e924b69d,84a7b375) -,S(e62f9490,d3d51da6,395efd24,e80919cc,7d0f29c3,f3fa48c6,fff543be,cbd43352,6d89ad7b,a4876b0b,22c2ca28,c682862,f342c859,1f1daf51,70e07bfd,9ccafa7d) -,S(7f30ea24,76b399b4,957509c8,8f77d019,1afa2ff5,cb7b14fd,6d8e7d65,aaab1193,ca5ef7d4,b231c94c,3b15389a,5f6311e9,daff7bb6,7b103e98,80ef4bff,637acaec) -,S(5098ff1e,1d9f14fb,46a210fa,da6c903f,ef0fb7b4,a1dd1d9a,c60a0361,800b7a00,9731141,d81fc8f8,84d37c6,e7542006,b3ee1b40,d60dfe53,62a5b132,fd17ddc0) -,S(32b78c7d,e9ee512a,72895be6,b9cbefa6,e2f3c4cc,ce445c96,b9f2c81e,2778ad58,ee1849f5,13df71e3,2efc3896,ee28260c,73bb8054,7ae2275b,a4972377,94c8753c) -,S(e2cb74fd,dc8e9fbc,d076eef2,a7c72b0c,e37d50f0,8269dfc0,74b58155,547a4f7,d3aa2ed7,1c9dd224,7a62df06,2736eb0b,addea9e3,6122d2be,8641abcb,5cc4a4) -,S(84384475,66d4d7be,dadc2994,96ab3574,26009a35,f235cb14,1be0d99c,d10ae3a8,c4e10209,16980a4d,a5d01ac5,e6ad3307,34ef0d79,6631c4f,2390426b,2edd791f) -,S(4162d488,b8940203,9b584c6f,c6c30887,587d9c4,6f660b87,8ab65c82,c711d67e,67163e90,3236289f,776f22c2,5fb8a3af,c1732f2b,84b4e95d,bda47ae5,a0852649) -,S(3fad3fa8,4caf0f34,f0f89bfd,2dcf54fc,175d767a,ec3e5068,4f3ba4a4,bf5f683d,cd1bc7c,b6cc407b,b2f0ca64,7c718a73,cf71872,e7d0d2a5,3fa20efc,dfe61826) -,S(674f2600,a3007a00,568c1a7c,e05d0816,c1fb84bf,1370798f,1c69532f,aeb1a86b,299d21f9,413f33b3,edf43b25,7004580b,70db57da,b182259,e09eecc6,9e0d38a5) -,S(d32f4da5,4ade74ab,b81b815a,d1fb3b26,3d82d6c6,92714bcf,f87d29bd,5ee9f08f,f9429e73,8b8e53b9,68e99016,c0597077,82e14f45,35359d58,2fc41691,b3eea87) -,S(30e4e670,43538555,6e593657,135845d3,6fbb6931,f72b08cb,1ed954f1,e3ce3ff6,462f9bce,61989863,84993501,13bbc9b1,a878d35,da70740d,c695a559,eb88db7b) -,S(be206200,3c51cc30,4682904,330e4dee,7f3dcd10,b01e580b,f1971b04,d4cad297,62188bc4,9d61e542,8573d48a,74e1c655,b1c61090,905682a0,d5558ed7,2dccb9bc) -,S(93144423,ace3451e,d29e0fb9,ac2af211,cb6e84a6,1df5993,c419859f,ff5df04a,7c10dfb1,64c3425f,5c71a3f9,d7992038,f1065224,f72bb9d1,d902a6d1,3037b47c) -,S(b015f804,4f5fcbdc,f21ca26d,6c34fb81,97829205,c7b7d2a7,cb66418c,157b112c,ab8c1e08,6d04e813,744a655b,2df8d5f8,3b3cdc6f,aa3088c1,d3aea145,4e3a1d5f) -,S(d5e9e1da,649d97d8,9e486811,7a465a3a,4f8a18de,57a140d3,6b3f2af3,41a21b52,4cb04437,f391ed73,111a13cc,1d4dd0db,1693465c,2240480d,8955e859,2f27447a) -,S(d3ae4104,7dd7ca06,5dbf8ed7,7b992439,983005cd,72e16d6f,996a5316,d36966bb,bd1aeb21,ad22ebb2,2a10f030,3417c6d9,64f8cdd7,df0aca61,4b10dc14,d125ac46) -,S(463e2763,d885f958,fc66cdd2,2800f0a4,87197d0a,82e377b4,9f80af87,c897b065,bfefacdb,e5d0fd7,df3a311a,94de062b,26b80c61,fbc97508,b7999267,1ef7ca7f) -,S(7985fdfd,127c0567,c6f53ec1,bb63ec31,58e597c4,bfe747c,83cddfc9,10641917,603c12da,f3d9862e,f2b25fe1,de289aed,24ed291e,ec67087,3a5bd56,7f32ed03) -,S(74a1ad6b,5f76e39d,b2dd2494,10eac7f9,9e74c59c,b83d2d0e,d5ff1543,da7703e9,cc6157ef,18c9c63c,d6193d83,631bbea0,93e0968,942e8c33,d5737fd7,90e0db08) -,S(30682a50,703375f6,2d41666,4ba19b7f,c9bab42c,72747463,a71d0896,b22f6da3,553e04f6,b018b4fa,6c8f39e7,f311d317,6290d0e0,f19ca73f,17714d99,77a22ff8) -,S(9e2158f0,d7c0d5f2,6c3791ef,efa79597,654e7a2b,2464f52b,1ee6c134,7769ef57,712fcdd,1b9053f0,9003a348,1fa7762e,9ffd7c8e,f35a3850,9e2fbf26,29008373) -,S(176e2698,9a43c9cf,eba4029c,202538c2,8172e566,e3c4fce7,322857f3,be327d66,ed8cc9d0,4b29eb87,7d270b48,78dc43c1,9aefd31f,4eee09ee,7b47834c,1fa4b1c3) -,S(75d46efe,a3771e6e,68abb89a,13ad747e,cf189239,3dfc4f1b,7004788c,50374da8,9852390a,99507679,fd0b86fd,2b39a868,d7efc221,51346e1a,3ca47265,86a6bed8) -,S(809a20c6,7d64900f,fb698c4c,825f6d5f,2310fb04,51c86934,5b7319f6,45605721,9e994980,d9917e22,b76b0619,27fa0414,3d096ccc,54963e6a,5ebfa5f3,f8e286c1) -,S(1b38903a,43f7f114,ed4500b4,eac7083f,defece1c,f29c6352,8d563446,f972c180,4036edc9,31a60ae8,89353f77,fd53de4a,2708b26b,6f5da72a,d3394119,daf408f9) -#endif -#if WINDOW_G > 9 -,S(90a80db6,eb294b9e,ab0b4e8d,dfa3efe7,263458ce,2d07566d,f4e6c588,68feef23,753c8b9f,9754f18d,87f21145,d9e2936b,5ee050b2,7bbd9681,442c76e9,2fcf91e6) -,S(c2c80f84,4b705998,12d62546,f60340e,3e6f3605,4a14546e,6dc25d47,376bea9b,86ca160d,68f4d4e7,18b495b8,91d3b1b5,73b871a7,2b4cf61,23abd448,3aa79c64) -,S(9cf60674,4cf4b5f3,fdf989d3,f19fb265,2d00cfe1,d5fcd692,a323ce11,a28e7553,8147cbf7,b973fcc1,5b57b6a3,cfad6863,edd0f30e,3c45b85d,c300c513,c247759d) -,S(57488fa2,8742c6b2,5a493fd6,60d936e,a6280b0c,742005ab,ce98f585,5ad82208,31b3ca45,5073bea5,58adbe56,c27b470b,af949ae6,50213921,dc287844,f1a29574) -,S(f1133cbe,6be8bbc8,dc8df2b8,d75963c2,d40ed616,c758cdc8,4edbc5eb,4899447d,57fc2447,2225b23f,5714626d,8d67d561,10bd3a60,dd7a1687,cbbb893,f652f50f) -,S(95083e75,3301bd78,7f8989c7,9065bb81,3f3d69bf,f3e42505,f4e0417,5bbe89c0,844adb5c,e7d10de9,4617c73c,a77040e4,ee4e92e0,156b3c70,cc593fa4,94b33482) -,S(1a908355,cbb75675,5e576ed2,9c99af63,8668c7b3,63c8d973,62100443,bc5c75c6,d765466c,6e556e35,2f778722,25627d80,a7353807,4b44ff27,57ad22e,2f2454a2) -,S(c5922f74,bd343d5,aa867308,fad97f9f,8a2d1f63,c5f31db4,f04df3be,f349b648,77b1f068,7cfcdbe8,812605e5,d8b752c,da811844,236a4c43,77f53c94,6e7bd648) -,S(64e1b196,9f910297,7691a404,31b0b672,55dcf31,163897d9,96434420,e6c95dc9,c16f60c7,c11fc3c9,eb27fa26,a9035b66,9bfb77d2,1cef371d,dce94e32,9222550c) -,S(33b2e76,687744ed,6c521bad,3333dd37,c602f8a7,549e9ce7,808fb7ea,7ce08de,e1bcfe7f,c8ed8ae9,5cf6c243,7fdd94bf,d742e8ca,a6de7811,4c25112a,86988efd) -,S(20f18f4c,866d8a1c,c2a31033,17b4ac31,89fbf30f,f294a75c,951473be,45e4f294,8d6857c9,d08ef7b4,fd888336,3d37bee7,fe8529f,7173f589,43fcae81,d2d0ea0e) -,S(4d1623c9,44c9c716,a0eb4c68,5e2a8b9d,2df34653,54643bef,d1444176,d7b69a8b,ddf1b9fe,8744ad03,f996bf6b,96ec3496,2b601bd5,ed952f78,54f58388,8917be80) -,S(a901b0db,e8ab292d,280d6b36,85894785,4faad0a4,dd0da7e2,d4ad0ff5,3db079e0,3f27e7e1,834f1a61,af6f04dc,61e7ae64,716bc5e0,a6b063b3,1d0e60e,47298a9d) -,S(7e0af071,30218ffd,50bd66f4,484645b1,2f42a24f,7c80889b,3031c9a6,ebfc9a70,50bc23f3,926cd0c4,9f53fbb2,35eb1e89,d579517,f5bdc3ab,2416db78,5aaedb3f) -,S(7ba8187e,1a7b25a2,c185d335,440a9038,b47f0528,546e9da4,ef82aab0,5aebf20d,6e6aee6c,9625370a,f866c25c,7ca5dd78,527efbc,e7d8b3a3,9ab24930,9a185187) -,S(8c050fc3,4d83b279,b6000816,e18fca38,9767b796,e926772,55b84a39,d93a6807,986314ef,75b68fb2,827c2965,4198139,5d699fcd,81cf23ce,7019bc41,35174870) -,S(53b7849a,78e4df86,25860583,a5249948,9d7201a2,cbf50620,2a7b8b1b,c99c2ec9,4e31ea12,ac607d07,5de4b22d,e1be2c52,e0a44d25,4728d2c5,44d2ddf9,e3e469c0) -,S(9bdf9e67,a5d0c995,6a075a01,fe762be,b6335004,31dee78e,febc527e,53313b33,94264621,a5960e0e,e24c2792,6f16cad2,907f2636,762e8d5a,17e94afd,8e9d2bb0) -,S(7caa72b3,7a8ab3bd,bac031a,47606f89,17d9f42c,6ec2d2fb,429fd990,4a381f34,5b5853ab,7ee5de8d,34e3d6be,b201094f,ff8fbd1e,682f7f1,ef87ddd6,5d7303c9) -,S(2ef29b9f,9827975,79c0295f,c3f48db7,925d62c7,5532493d,de16b97e,3993d81a,496c944d,d9875ba6,a537ef9,6bf4c714,a0afff24,387d95e8,9b42337a,33110753) -,S(df157cad,95b07875,573c1860,ae5d02c6,4029e952,ec354e6a,9e5c34be,97317ff8,f2eccac7,75922b50,899c979a,2b3cc30,b629e62e,85693ba4,70f6ee38,1284c162) -,S(dd55c150,a29ca526,b6182e64,3b9eb544,e651d236,b71920e7,b15a9870,16454b1d,44c757a5,42f4ea2e,b39605d4,268c2510,ac685aab,d77a8f5c,4d95e23f,4c2e9368) -,S(16886cf4,6ed42c79,19147763,63d3256,c4d5d393,87f01723,25b9e4b8,98227f27,7421a220,7ee73299,d46192fc,93ca03de,c824ed8d,e2f48367,ec538317,a17fffb) -,S(6ff180fc,daa30618,8e8b306,d6f0acff,27968c22,484ff45e,56aeaa7b,2b60732f,7d16d654,f0c2aff0,fc254dad,63761a2,6c8d4022,ea85b8cc,22f3ea1e,f69961a9) -,S(3ea4511,a00dc2a0,3eb4f51f,40ee677c,aa912b55,39f685c4,f8bcc8ea,dc395e36,6c9ed1f1,528b0215,93a39839,340ddb53,a2f2e36,5290c498,24b035c6,73c9259d) -,S(b82cd70,dc3de9ea,b38742d8,f32dfb8d,53e4150a,835e54b6,3c7cca20,f253081d,e8bcbfe,1f7f6e75,d32e2049,9329765f,2effc56,a922f268,60d4bc0a,add0e24d) -,S(fe2fc3e0,748745,84ee23bf,105a69a6,6d056f0,17327d49,b7b38b57,a196c77f,3e18941c,c3c6d297,cc9a32f6,95807b1c,7da8561d,e4fde71d,4f9bbdb6,e9bf3916) -,S(4b90176,cdaa3693,47e8778b,12db9d6e,e8b00114,46ea35ec,845dbf57,4bb7858b,f60547ab,6e9c5fd3,eca6e349,b85880c6,1fdad0fc,2f7ab155,295caaec,b973c154) -,S(35f38251,1d34600b,4b8c86a9,f0dbc9ed,defc4272,f59528a0,cd3ec10a,5944c6d2,29a835f6,ef7fa1e5,f6f37a80,cf96ca98,43762bb1,b12a0dae,ae83234b,d0b5ccd5) -,S(1d74b297,311b7ff,a1027e26,587d3f5b,e1d0e9ac,3f0111cd,f3cc2371,722cb94a,5c7bcf8b,57f114e0,b73bcfb8,10f5c60d,35dc99ae,9dc7f0e2,606cc1f7,28c2071e) -,S(50a094f3,9c6f956,b020737,b9ec722e,4f75d1b7,c41593e6,f934a68a,98450428,a286e222,dfe10cfd,9689eaba,6a81f044,89c86db6,869aa1b5,54a90f1e,83778eee) -,S(9b65bb81,2129157c,dfecf12e,275ec38c,282dbcd9,14b48105,99b0a6d6,27c63db7,c582db1a,3f0f2242,1913b2e9,51e98a78,660b4c40,ad08fd65,528593bc,18223188) -,S(8b4544fc,1fdfa06e,456c1115,a1dc831c,85e7f1c5,e620eca5,1c20802d,36a4bc6b,e3e77c41,288f2602,e722af7f,4b70e64d,e4116fb9,955b03b0,6ea8b19f,7a20350d) -,S(6c709880,b959eb7c,5179b29c,c5578fdc,6cb2ae13,ddcede29,d5f81d95,de0ab4aa,c9e33fae,bd8eba42,6736c0c7,6f3deaba,ee2b59c5,953fb43,c2dcc513,9e7c4bdc) -,S(77760b51,37ba6a71,95d891f7,94a087a0,76fc9d67,802b81e7,85b5677,3d537806,f5202cf5,aaeea58b,f4f58c7e,df4417be,1b87ffde,e68e77f0,d7e81abe,158e3a25) -,S(1a8bd783,6a0b0c82,e9a904a8,a8c91a67,e23cd4f8,efd625d0,df4c426e,7e163102,61fe64ca,b0952cae,3c574f28,2f74a87d,c2a96316,b7009f2e,4e9c5fcc,12285844) -,S(fe217db6,59079913,fb1e453e,d24d91d6,a3fb3099,e69471d7,53db5390,864abc30,5dcf9abb,a9625ed6,80b0f20f,b1f047d5,93a0c61c,53969253,8cdf6b03,4d730b58) -,S(2504d637,54afd5eb,c38f58b6,5ead696d,7e3abd7,48cb6c5f,212aed49,f5b33b91,79a6bf43,75f1469c,4f5321c6,c72fbbf4,ba7cec10,5675f437,b5e013ad,7b5d75d4) -,S(b06f702,f47b22d7,89a9bd3f,687105c3,6160abbf,5cc8976b,7fbddcaf,db197b5c,7669bbd4,19a4d491,f592a35b,6aa3dfe4,5bd2fe7f,d179c778,1cd5f918,d732f63d) -,S(803b203b,b31f9cf9,4034eeb9,31b54480,a6f3f99e,bd23d0ac,bc2128a6,d044e23,308abc8d,f271f759,59b20c5c,7fa62baf,bfc9ccbf,49b946a9,54e5381c,1728d1c7) -,S(266a9cb4,c5f5cead,bb50e5bd,a03a7312,e52de1de,8e95a8dc,d57289fe,302749a,9eea970b,a856b2fa,a3e82877,cc84ed4f,3dc0efba,1e7c3baa,8b386ffc,46e0ae7e) -,S(fd8a9d95,d80c7ad5,2599a7ab,98163df3,64c4c141,e9abea35,5d7360bc,f84eba94,a9fb1702,100953b3,59b2e268,8ae7fd33,a30377da,47bfda71,3e2d7d73,dfb1030c) -,S(a7322df3,9f28f23,59fc339a,8b2c80be,6e84acc5,b7b0b8f8,f2cb6f26,f9db0a7d,22f6fe9d,21749501,7fdb7f5b,2f12fa57,95f40e1,31714885,c12a2ea1,6edb6be6) -,S(82a8c10f,336a6649,63a104dd,bf7f0f18,bd4c461a,ea569ffc,82c3c7e4,cb052d36,737ceca2,c0ef7227,8b90501c,cb71b671,5e5c31d4,cd0478c1,18fe1287,95f1dd0c) -,S(9b50d1b6,8e3bf795,7cd12f,5a60c26,6c4ef2b7,5ba5c516,c54784a9,4f15d6df,2afc8d09,b79176d8,d003fd2a,4f18d526,403fff27,2d47e778,7376feb7,cbddd8fd) -,S(3f9083dd,c8b423fe,7de3a822,81d3056a,b8dcb9d7,ee82cb80,6718595f,bae08d32,cb13c152,fd511d91,a9e0ed90,afa021a0,81f77f6d,20cc1376,e2195ffc,f28fa758) -,S(c75c85c1,ee17c1a2,56eff6bd,592666cb,c9231706,59d50bfa,dbd1074e,f2167faf,1ab4eabe,5e09409d,75cca892,2647f48d,bd698a16,d4f7cc85,96daf169,40023a52) -,S(c5341fea,f8a0f5d3,b4d0cf0d,2f7aad7c,60ea8e2b,3d4b7fb9,5c68d576,98656045,95f9f4e9,7e5b9f,a48fa422,a26ab982,dc48a4d5,4d712398,6e6d3ab9,74e88915) -,S(83acda3e,2a8997e0,d52bd4c6,8705dd22,220852b7,752d67fd,8967a032,60c2d89b,dce1bae1,d655ba51,7f5b5580,99711757,a77cd3b,dd4b8e8e,330e9779,1bc31df0) -,S(5b819146,8b299074,5b9c4164,e29d594c,f1c0d571,6c5d3962,5bd279b3,25237b,cc3636a0,3fddddfa,bed88daa,b081f359,1c48d2ca,71ba34fc,f6989f4a,f7625d8e) -,S(64778122,214e38ef,f8041796,166104e7,32f5f664,d38d7721,9b89045e,2c3b0e6c,329cf049,7e15eec7,b8eafc4a,b8a7d1c,d8b63203,8d4aef81,974cf984,4611a32d) -,S(ed4d826a,fe5762f4,79509909,9aee8664,2b475a9d,6da1017c,43d0cb9f,1af12323,8c6f81be,3fafa5ee,c8296f92,8ac7919d,c4d88c9a,59442274,d0531b7b,f7e48e78) -,S(38b42924,419aecc3,acd6f551,346fd61a,4d82ac2b,55f7afe9,7a06eb40,cd109c4a,7f42c096,2feb2f73,b2b0965a,1f359a6a,de49d768,a2ce6b07,b5acb92b,73e05583) -,S(c3cad4a8,d8bb94a7,b434cf70,183e8615,bb2a8f62,24f216e3,446ac2e9,82138911,f649be27,8cad9764,20742ce3,82dce3a1,420e372e,f1b25b27,59a8ed38,7282765e) -,S(2d408ff4,d3d236fd,54fae40d,ce3ea9ec,d9212e57,36591a9e,55588e4a,54bd6538,d596adf0,e8692a06,bc6284bf,299bef6,85e2a171,585aa132,4b9a05b5,ce815b7) -,S(ee7adf6d,247f25fb,76e90cf8,13f888eb,d67423a3,a3c6fdae,bafb7eaa,7a33c854,e077184b,4ae8f705,6c10dd9e,f541689d,143f6871,789e1801,deaefc1d,527a8fb4) -,S(2f9457c8,a9ffaca1,3d91151d,c4c5e89d,dd5d37a3,7c9a864b,7c811f3e,1144b34,eb4c9848,9093d573,a295407e,1d6fc48a,787120ce,b3d3dcfb,b40634e0,e75e221d) -,S(d3f332b8,a0f11582,1ce3478c,efe18de3,60120483,ef531c27,7b30c46e,b7fec294,ea75b9b2,5d717861,d1af1c01,9c372941,c8968b90,ef134f9f,323215e1,bb0b2155) -,S(183408d3,38b05aad,3521fcd8,6ef36dd7,5f3ddb86,66b52f7e,9a4cdf1f,8e152b91,66998520,6edf4ac6,f39be21f,20c98824,210e204c,e4499809,5de35537,1641218c) -,S(283fec5d,b1145e53,ba8f1f0f,f9cf89a7,21faffd6,c2534686,3d395609,5f40374e,70b01237,74af550e,68e68e5f,65ca6e98,8846e03,cf39af77,8511be82,bc32fefe) -,S(ce7570a,4f943cfa,413bd249,d8e7dbfc,ebc73579,770fd6da,f54a0dfb,dd52fa62,e115b14b,ef4695cf,fb85bdf9,8ba3985c,bd5e5b89,83e05390,7c36f9ce,8b75d41d) -,S(7e9c4f19,c8f4ec3f,1269f648,cd919525,df790315,74cbeb15,37794a4c,838fd470,e9d9dbfe,8cf5f5cc,a855d6cc,bd11f480,60fafa8d,ad6bd3e9,c86df5ce,b0fa5270) -,S(e2a9bbe6,d5d5bfe,a7c7f919,df2309f9,ba04f4c,722a3ec2,3bf451b4,64cb001b,e4177ce1,c3cd6ac7,78925bd6,7e72cb77,d1925b91,d06a7f16,98411a47,86393fb0) -,S(504512a4,3e17ef50,e43bf37d,42a94990,f55e641b,1558c265,e7099002,75271012,954a5fd8,57ba3acf,2d4b1f41,e8e1f2cd,1f21c4b9,6899781b,742a49d2,e61ed18b) -,S(81d1f013,a6bb325f,4b2d1d51,ba72c721,859945d8,a17b3411,cd5cbe87,285f850d,2d5d2fb1,f0c30855,3b1fe249,298b2059,259d3d49,d4d7071a,dce4bcc5,dc937193) -,S(5b66c2df,c1d28266,18a87276,7e66c33d,d90dd514,14a3b87c,a733383d,1d895022,9bd0178e,38189569,2217267b,7407e987,27fcaeda,12d8cf54,49eb5472,d554e0ff) -,S(aeb5f70e,98ec5e38,dbd2d544,bdbff8ab,99b583d9,af58c597,afaf8688,20381186,618bd6b0,d25ca70d,f08b7692,9336e421,691b0973,f2f5a05,2e7adc17,3584427b) -,S(b289eff,e841943b,84761e3c,67a9c02a,557679ca,76ad753a,707a9821,2505052e,7a981f0,c21862a8,53b4f895,dc62482c,530ed738,5e5d1e33,cfb9d0f,e879992c) -,S(abae3945,8b12199e,6b0c8360,cfd28288,3f585917,e44e1200,f81bd356,f619291c,adb23bcd,b3d069c5,e83be30b,2469b068,b2a81b7,b667e934,233b75ef,b5753f28) -,S(4a9583a6,485b5a5a,81ac224a,518eb29d,1e0f658c,8d91b013,9419c809,55fbacaa,d8003c9e,e3c842f5,ede375a8,a7768db4,803ecf11,9b7b37de,cea15631,b4e8dbca) -,S(d52f630e,dba6f7cb,65fcf465,44ab0d9e,ea236ac1,460f17ae,3a210102,10ebc169,21155748,9fa93b88,3e5bea50,da005c53,68e21a0c,41bc83d9,145c13e1,370d26d0) -,S(bdc5237,82c75858,f5c50fc0,52e4c1e9,c74a2a63,35bca9bf,8d10e120,9add6a4d,abb1d9f8,74637668,e214efba,fbf529d3,12ff023b,c1d5723e,58540436,6834f189) -,S(44770a33,8bf0aab8,3bb64e47,6eb6167a,88156d16,8f13ce86,26ee0912,e59ad087,5b5930f1,2e9c40bc,b3393a89,5c2d6457,6a3abd23,b7291b99,c965c33d,ef60a55c) -,S(b15e7b32,2e404aee,319ac203,23e36672,6503108d,8ee8e1c8,3e32d924,515e1679,5246a819,bbfb291,5f82ed56,50796f50,5ced5c25,87347d57,a873ceaf,3d997e7a) -,S(a1ed7557,5225cd0,f2c50f75,8a1c1df9,665ae108,d5e04190,27bbd9ae,ddb00f22,3c83145d,ad9f8748,7b97e746,4850ed02,d71dbd04,93281a1,3d212776,6a791ee2) -,S(e8aaf361,6a1bc60f,d9bfc43c,2c60580f,479e9ec9,c23a37a2,3cf8afb3,1d918af5,6ce693b6,4a37c672,7e141041,ab9a0d58,9ab9c303,a5ac3d3e,c89b6f27,9e79827c) -,S(5dc6f8cd,2c855e63,52a4a4ef,6187a6d6,759c043,38a3db76,c5a3aa37,54c20a3,f602c342,8593a9a8,d671d1bc,7c1d8834,fe9f5f5,2e6a7f0f,bb870146,4e6f4838) -,S(63327311,67bed8af,68a063ef,22aa489c,f6563620,461af26a,5f1a07cb,6b42f3a6,b8f7c3b2,20701320,f20ca036,761d3e56,bf94a700,9a919f1a,3ea0cb81,b74424a6) -,S(8a40d925,9a393b38,2305c201,7e8654db,ad66e50a,d798a0d3,535230f9,48080263,afb6a74d,9849454e,dd7f703a,5c6616d1,43f9cbcc,9a9a5d6f,6a7b5d1f,9d9fcaff) -,S(e7147107,27c7420a,f517fd3f,9a05b7de,a6a02c8b,cc20b17d,cdfdeaf8,2078645a,da7d67cb,c1ede9d4,fedd5dcd,c96b04f9,a3561ba0,2581b055,eaa144eb,4217daca) -,S(6131291c,d95fb878,1e42a68,553952c2,9922bce8,91c026c0,cae1f69c,9661c82d,160e1c1c,13342fd4,59d4f989,8ae632b8,42b89479,13733b89,384fc104,2d30bf01) -,S(4bc4f845,b6764692,d0a9bfa8,1788809e,fc5e2aa9,da5003bf,b782bcf1,d1ca4951,87092dcb,b9c3d254,e3b055ff,3a76ec05,64c4a7c5,7fb1783c,efdc40fc,10b751f0) -,S(45a880a2,7bbee9df,29f9bff5,c985f364,52865b5d,582a201f,698e6eca,a2be67df,fe49a6a8,b5e46bf1,ef679714,dabd590e,a831d46b,8ee94eb6,13132ba3,7855fabb) -,S(6a826a38,317c0c86,64d6847a,220145d1,877e5495,b21500d3,f21f1a0d,4af4f2a4,4521954e,fcc98263,df2f14e0,e6e6b47a,f6b83f0b,bc20722c,15445f87,e05f4513) -,S(15356506,f255f7e9,6cc8aa1b,9dce572,8bd860de,7c6cc75f,613e8a34,366a23a9,cd15abbc,d744d485,d5e401f,1f89a5df,122f37b4,e362b4ce,e3e53b1c,110bf3) -,S(f3bc12ae,f53d9f5f,6b865178,2dac2ec,cacff3a5,cca6443a,2b5e1ca0,f2b89b91,cfd4d36b,eb2e11f2,41fd0f36,7a0737ad,303e915f,f247f131,368ca509,18e00957) -,S(7e3c8c6d,fa04a536,f7a26ef1,8b387649,22320bef,58453373,6f728297,335c0fd4,72ea16b5,32a7336d,3332400b,303c0236,b6a1294d,88ce7fe9,15571284,d1f7c189) -,S(198cbfcf,a0575fc2,c161c696,d85155fe,6943ab9b,d6e17223,d8844608,ad0369d8,d5e6268b,30952422,be59fe0e,fe7ba2e7,3215994,827a46c2,f2972b26,153cf7ae) -,S(1e056e89,b68cf35a,22183c08,9089b90d,5a147caa,780b1fd6,3aeb1350,afb0e5e8,b8241453,abc44c57,ddad6ff3,86d416f4,3e258a39,c6f8837,9f80472b,943f32b9) -,S(dc7ff974,8d827e7e,a6173b2f,1a646d47,d8108144,ce7f98fb,3fac729e,72faaa21,c1fdac5a,ef4c6f0f,fcb8e1c5,c4417c71,3e3d5f07,146daa1a,aaf2e7fe,e70c4914) -,S(71b95efc,c4981e07,5354bc1,1cdfbc48,36b2eff0,bf8f8ec2,9a99da1b,2fd28e79,fd5a3197,6fad6aee,c304752c,c3ebbc51,1f3695b0,9a737fa3,af42cc6,efd684cc) -,S(43854caf,29dc2bd6,c9f3e8ff,a25bba83,f6b96121,897044ae,6876883a,de542b3a,56365176,897632f,8dde3167,7a24f558,34c5c9a5,5c1cbf36,fd8b4480,3c9c6c81) -,S(2adfe17,90e9f9c,708c9b73,d5fd084,b6eff990,fb877961,45c2ecf2,d427b222,b5ce3160,5d6dd9c6,22cae425,ccd28912,c4439820,c06950cd,4c86d9b4,53abd7ed) -,S(a123452c,2b7eaf31,15b3a534,3b3ff31a,9f70c54,ae33c620,471e3e82,27a9d6f9,933d3483,78a71f44,3788194a,afc545e7,f53e37a6,f779f96e,8fa14ccd,ede3b4eb) -,S(9b89a3c2,ca995a81,86c15217,61348737,aab166ae,7decca60,3d06e32c,cec0a6ab,2a7d3701,a8724b12,bd7c4830,224ac083,cbea83d0,543b5414,80ba8c8a,e7731232) -,S(64dd7457,e7d9d739,8e2b9a0,dc45272b,384b0433,9ed8b2ed,c9079646,11e9e9b2,ea90f8aa,e214ee16,ed608a72,36699899,4e311dc7,780ef885,b29290c3,823c470e) -,S(59227431,be607c6b,d327fd71,4eb71c87,20abba42,1c7f550a,6b35767d,6fa2176c,cb7571c4,71c5527,65bd289e,a3cf3f38,796da2b1,2c953d0b,8705125c,4861d598) -,S(53d765cd,adb26e9e,1c80ddf1,99374363,843b7d08,a7237bdc,8c5106ef,795fe2c2,7bbbb198,eb39973b,76d87f81,94d45150,a66d4f3b,128a40be,c989a405,ad7c287b) -,S(e507de9e,c16b3bf3,523a989c,f5ff6c1,452ee90,9b66ffc1,6d7b519a,57bb66af,a2f2f02a,8272de6e,3dc8b395,8959ad2,51b6d3d0,4c81952,59a501e2,8ff7892a) -,S(16f48c6,eb84fb2,81903b8c,b9f60b7a,65601d76,e2a57983,5569c983,39b4a6f2,8613bb84,8398681d,66f1e75d,5b6ef44f,d827b629,f4956a4,41d8f503,dd32b289) -,S(650471ae,774265e3,270b5132,33d12d85,bb98e38,2a3b3af9,cab6339,e1446056,838e7793,34aa6fe6,cae90a62,d359c339,187b4032,15d97cda,4e62724a,a5a50306) -,S(15dea416,fa34584f,cc90e19d,69825fae,348d1ba1,fd7ac821,559aac2a,bc21dda8,1fcabf2,1e19ce68,ee12a3d2,84bd1304,10fa5f5,d45f9c15,d4070243,a8433047) -,S(b42b2495,4f1f70ed,3db90087,8357ba46,ee9d6a07,b4f7c751,dc5cba07,b05b46e2,e15723eb,e0bdbe6,d6f28d6d,a0443c63,4851f5b4,c551bec6,9f9196a0,969ed71) -,S(8e9e4f5,c6aeac31,1dab1125,dec9b460,6ab10b7e,8e250960,a17fc57f,c0230f83,ffb0e211,c79fbb79,78bd4e53,a05a267f,f1e32c34,d6287dee,64576d31,ab959ab2) -,S(87be7323,73bd4b73,8627fb63,bd4d50bf,d6f2bb81,f804b528,29549fe9,3fe1ac2e,f6a9186f,f147b9b5,ffc844b2,ec0e255a,1ae5537d,75624288,ce8421f8,7e94e1a4) -,S(43601d61,c8363874,85e9514a,b5c8924d,d2cfd466,af34ac95,2727e1,659d60f7,8791c000,7c09c94d,b328034b,88c5bbbc,11333536,6679eb09,9a5e75b5,83bc2c2a) -,S(341b1580,f83071c5,365f0bcb,ba66af96,6902e394,2a2560ac,a0daafa3,2ab49d0d,4b985b13,c5499026,7ff564d2,d4649c6f,7e8fdbe1,ba101d94,1c034e14,64877b20) -,S(175e7cb3,ce4a3a43,7c7181e2,c79fb154,33ac1aa8,e56492eb,57627171,f14dad95,31ce61a8,7834f52e,fcf8703f,93696f42,58130155,63ca5d9c,e92d8fc2,81135b0d) -,S(5ad430cc,64e61c61,e3b3c848,2ca3ecac,89c1e495,4c80ba98,249e45c1,307165ad,bea2a060,505c13bc,317ca083,c5a8b85c,9ead5f6e,1ac23fbe,ac7cecea,9251c791) -,S(41dce0d9,6dace318,988602df,7fa84c1,80f0ce3,dd7d09f2,8aefefa6,db8b837,74962c3f,ed9a6e9c,896635ea,855323b6,8850091,f84dee33,3cdff8d0,d2827928) -,S(a5ef4498,87104dda,103c1dc2,52067643,9aed2d5e,432fe5b,a23cc142,39961bcc,1cbcf83e,a363e0d9,3e6ecc32,8653ba7a,a165c526,765b09f0,696b0d61,f122db3a) -,S(4da26ece,9ad46003,38bdf68b,852a2cbe,18225f2e,2d6d5e62,6db57235,fb3a9d45,d10b5a63,7ab546bf,cc610e2d,1c3d61f4,61b0a806,e7ba29c7,3d3de909,e9fae659) -,S(6e621e6f,53d2408e,488d8eb1,6a19a4f7,e9d95585,11e69111,29dedc69,f98f4763,7b148ef2,73e1b131,341ad477,9342c7bc,7b945a2c,b52c448e,4bb5fd50,3cea1a19) -,S(ebaf5764,5bed7469,9b57ea75,8a395a90,66bae20a,8f082ab6,da4554d5,278be83b,5847f4e0,6c653033,5e29ea94,389ee3e6,d916314a,60126028,650ab9e0,bfcfbba7) -,S(c0f88a71,711b632d,24b55dbf,52b15d2,faa38ca1,1438c17a,6a6ff635,3310182f,2cbfad4d,16c07021,86611eec,408082fb,fb2e9898,141a5248,1c59e44e,cd0676ff) -,S(5d9b6c18,84b79498,c6244fbf,262922c6,dc1cddb7,3cf70ae0,1b5287b0,5b5c6350,328e831d,2f2b162c,4abe1644,bb54cc85,18db178c,5b6ae97e,5e85110c,7d7fdf1d) -,S(d1d1360f,37ed6e69,d4f214c6,323a53b7,e57d7595,55904016,654c49f0,4e02e21c,627eea93,c6c9b53f,94559414,40a8b100,6eba68d4,6c922b6a,1521f394,6dd15e4e) -,S(efc987cb,f1023af5,58acfa18,97b1b2b2,ace29a83,65674703,e4969ccb,ee411731,195a6a65,d3790bec,71642986,3bcef432,e38242fc,9f565dbb,e159bc42,f5740c69) -,S(f3026b97,163df3bd,61b88b78,73864480,968d1d7b,83ef6b01,31090faa,18284ff0,177c3a61,682363ab,bf281615,d59f06ff,5f87644c,84d670e9,a6c56ac1,b611509b) -,S(5d34ff5f,123b5b69,92ac92c6,8c9cff46,deeecf9,68ff830b,5622090d,682c5873,2d1a0b9c,8eaba065,43204df1,48eb1618,25443efa,80f8aff3,d49b6626,c5955ac8) -,S(cbf9ba17,94a95247,c39da065,84308cc8,e0ee591d,31a9b0bb,dac67280,468447f4,549b18c3,10feaea1,225fade,934112d3,4058101d,74f00538,1b82796a,d0461736) -,S(920975ba,9e2261b,bf5982a6,b57a7344,8e7747b8,368d7a53,79acacd4,c7dcd31f,e95e0508,81af550d,9221f5a,e9541031,6367d24b,d545bdcb,434e7638,acb46dbd) -,S(815b2ae4,6fdcb55d,926cdce8,2b4f25d0,39132312,3bc180ff,33fcf132,7eeca64,62f637c6,7d886374,8f1e2e26,865118b9,99285b87,55f25512,c968b4fe,49b8c971) -,S(1bb9a6c2,8e28d4ba,30ea8639,7a4d387e,27ca8025,da231926,de3c454,f7e0b16e,a0cbc016,5e32171c,8184265e,ac7e0147,206349d5,41035a94,f56efc49,dcd7ab93) -,S(6f0153fe,dffd83ea,b099d29d,dde278f1,9c05a4ba,78eb4c3d,34d337c6,da68bc22,a532d00d,35013f85,9f4041d3,aa231f2b,9fc49967,e0e2f82,4d5051f9,e7f0c626) -,S(3454f73b,3bee77a4,d00d384,71bf555a,ed23e5e6,c6dae855,2e9cb7a9,1b20258a,92c20846,cfdf1e8f,3fe5bcaa,6bdedc3,9926833a,3f40d28f,23a8f952,d8d18dde) -,S(367807c9,a3606b4e,1b8c2616,ad528030,1dfcf686,40eddf02,fc59317c,230e9a86,1f023f2f,a2bbece7,3dba14c,124095cb,fdc4f92f,281a14,8304a412,c16ecae6) -,S(8ec4fdc3,9891f6af,1374e06f,c44b815,1b82541,75fc4909,acba5941,201af62b,2dc6cae5,cac2d887,83dca0e5,3c798f8,fe067bcf,5fc29751,13756cf7,ef4e5f1b) -#endif -#if WINDOW_G > 10 -,S(5cc24a6d,4c5b24f9,14542f91,e5fa937f,ffa08551,51b8b842,8729b06a,9178a263,b1da8635,81531a1f,bfb38a4e,419fa1fe,ca8d55a8,3ddbcb98,da19d5cf,fb7da472) -,S(83905926,c03905c3,a9644a6c,da810dd2,92602a50,50c52a21,9134fc4d,e3599e9f,4293260f,e8af6792,a20b115e,aa837638,9094298b,21d9de16,cf20e0c5,7a46089a) -,S(944b097e,4721e9dd,f8204ac3,d3878fa,e8fa6c14,34ae4822,481b2985,6589b6c7,5fc47565,30e9b095,f8b79643,1e745b99,1525bd4c,4764e8e,e8af4b96,9bd6ddf6) -,S(ab0b4a3f,cfb7c134,e1caaf04,a63a7331,17327a1e,5fa90301,7b5ebbf,3423b73d,e1e79263,a5bbba8a,cd78c92c,faeccd3a,b84944d3,785c0781,3763bf1a,ce96c9da) -,S(57a344b5,220f2b0e,f7bf7fbf,5a2e4e7,1aa2c3d8,7bf090bc,f803dfee,fe8b85f,f82b7d0e,8ef9620,e48c9f13,53a72a95,a9e11a3c,1678cf10,576e639b,b1a7d04e) -,S(6e053e1a,800b7c4c,51f8c4c9,5cf0f4ff,3608e396,ec46188d,a1a9263f,c8d81ac5,86389e98,e3c823c9,e1b5384f,fce428c3,62e36579,7202fdba,dc3d8c49,395e7473) -,S(62d76406,1804717f,b30d4a7c,7567b545,48a289ec,7f083f1c,59deae25,ce485cb7,f1d6314b,661d1f8d,8531d57b,9470fb53,d1509b2d,a626a0fc,4cafc941,b668be84) -,S(e5db28f2,219fb2aa,830cf108,bd2449a,5c4d0800,82d34658,9e347f31,dd29250f,c296e646,32f97dd5,ba3b7012,ead44b6f,324fcfd2,f35f8b24,8e58fe68,888bd453) -,S(4725b3e9,a3d00de4,8a53177c,9fff831f,733ec89b,c2994ab2,3fe815f1,9b32729,ac3b7747,de38c00f,145fdb74,1482bb52,324127cd,2979ee12,d4a9e689,b9f8e778) -,S(d0d3afb6,492c72e7,394ed918,7013e347,b036b65e,a76e0569,bbe9e346,41d72b3e,2dd3a45b,94aafe07,53061caa,a28560,bd952b0b,2f63f13,96f42fb7,8e02fef3) -,S(7853e735,d717c857,97b85654,a24acff3,104143ed,cf4b4b4c,7869068f,c304632c,a873d9,e70fd14a,c2777a8f,b5a02922,bae3a31a,14938e69,cb535355,de1efadd) -,S(6db26b3,7d4fdc59,13a1a01a,14c92356,ee44e2c9,7f9d72ca,7789de33,8ee904a4,14fe2225,bf2ba0cc,28c1c409,e9849c4a,d8adf792,63869b68,54a28ae9,631941fb) -,S(b52f0869,bb98af3c,b2f7f5c,669fa43e,538e400f,63a9cce6,99aa2ef8,eb2848df,24566b24,55bc454a,e7b378cc,a0e57b6a,8b821c8c,a76fb858,bb616e17,8907be5a) -,S(8614dde1,1ee6af03,eb34a9e9,970fa7c3,234152c0,1384f7e4,c1e1f93a,197b448,2a1125a2,ac996870,2ba22b5a,d230c40e,4e5c7e55,d8ba6ba1,5e54d3cc,7b72f3cc) -,S(982a37ae,625f6e5b,78e71c18,f20bdd0,8b3308eb,59d0cab2,dbc20937,938c1cfa,671fe16f,a65128,591249e2,b5070bf,2a689e2b,dd6c57dc,18e5309a,b6a40d0c) -,S(6bea9305,26b4829c,ec99742f,c9231c00,627a09af,22ca9d9b,4081a2fd,4c3e703a,aec5402a,54517b4c,1f344d14,b1943e69,d7541f10,c45bd483,2b02b059,499a6cc1) -,S(b5724781,8694487e,7cc188b3,36d116b0,54016a99,20731920,ba7bd29,96583edb,5cbbd186,1f80a4bd,3d58262d,ebc58ffd,1d278fb3,b4d7fec6,208f6286,77845cdc) -,S(de1ade62,7ba00e91,786f4f53,18ac5392,4df5a534,704edbb6,2e0e9e2d,997c5412,7ef486c5,bf23bfb,fc6dc15a,41c0673f,a9d003e6,e1d09a8e,4bffee9d,ae2021e0) -,S(3738a57c,b1721c41,9f9e465d,fb80e1d7,33720398,bc01166d,d476d36f,3398c0a0,e1f25bb2,1662b16d,6d28a629,ad84385a,43df566c,52924bfd,11854a78,b70c22f5) -,S(4cae21c1,6b2a1239,a85575f1,2ddf6daa,1955feb8,b7502e37,6940006e,7a81885d,2affe855,388660d8,27671e89,c82832b2,25fa2c9b,29d559e2,37af565c,b4dc99c3) -,S(4c511a1f,ba8a0be3,6e37cf55,85bcc3a7,97bfa7ee,1baa6039,5732faf8,dcc2bd7b,ea69f794,5c6babff,23400fd4,a95d6833,abb27269,887c372d,8a6a45ca,b25651af) -,S(d811d8c4,323b4370,2607c25a,de936c0a,c2e4a44b,2ba51f83,20c5179e,745a7e29,6ff970a2,17bf47f8,da0aeab,cb490e3b,46c6df3f,69f9e93c,3c4dd94a,e7c05345) -,S(101eb5d3,b5e5aaff,e39bbafd,f13b5ffa,33db68ae,1fb09b0b,1cae25e6,16c43eee,9d6a5514,9867725a,607a1c96,eb03120c,a4970939,34e0cf4a,1631a63a,bac5ddb3) -,S(89eb1152,b8dde45f,e141f21f,62fead1,ecdc7f70,eff8f968,de21cf8b,72480519,f8a337c4,3181e3d5,69ec99d7,f2bc4770,cb6703a8,63fbd95b,41fdb07c,b697b447) -,S(53d633f3,f48ea44d,273d8f1e,455019a9,49d95eeb,68de70cd,bd1e964d,9ad0dc16,1b26ed76,964dcf1b,3f7fe6f3,2e6db7e6,8e8ff4ee,48fe63af,48ffd33b,cd1645fe) -,S(de106910,49891106,59a94d26,b9cedb64,6ce3db4b,8398ad1a,92f8f95f,d8d9be6a,87640b41,dbd99d16,578a3d06,d23d4088,8768a4e6,dcf83e7b,5b9d9133,5eb43d32) -,S(40ed1e6f,b9ee245,ac189a9a,7809da10,cc6daa7b,41a163ca,f761773c,6af5bea2,ffed1501,7298fb9a,78eb7bdf,1430ac04,82bae82e,a7197adb,50bcc1e1,fc217b2e) -,S(55faaaee,59a20b9a,3784d171,9ea529cc,1b7ab3a3,29f26dfa,a3b11bd6,67ba15c1,a9f8939b,52ac53e3,5ed4771d,8e47065c,d7f2805,a7e5475c,37353ddf,182f4a65) -,S(b51de64e,21cf88af,2180ca17,24956d10,a95ac607,f034fccb,a53bd02b,fa8af3fb,175d9b70,1c652ebf,46b99f1f,6e66c4a6,9b840019,a48b1ac4,878b386c,3b7f81e) -,S(5156b0dc,bcd91e82,4bb235be,9367cf40,7b8927e8,cd874171,556f997b,7b07b143,1d457c0f,a29d4c3f,e65ded19,1127016d,d40ada90,cbb0d8de,c2af4bf8,20cc91dc) -,S(3bf51d72,60b4973,161fac55,88e441a7,f1993c06,791b6bcd,e11d8e,96dd63d,7bc6b470,90a7afdb,fc63905d,df698499,73e1e4e2,af74f126,63eae8a4,f4722d49) -,S(d2971091,20088102,1154f4d3,ba6f2da1,22fa74c6,4faae05a,d76db7b0,9ad61fe5,7350ebaa,f2ccf3c8,f940cc14,151c23c2,bc33cb73,65528156,92648f6b,628e3fc8) -,S(c2ee47ca,8e17112f,a255a520,21ffd30b,6d7a3b7e,2341526c,559b60a9,c768013d,2e6e8b6b,d83b7f5b,1dc8e83b,edb3b23a,80d9ff08,2029831a,45305016,2bece448) -,S(559998d6,9ddcce0d,9e0da39e,96cc4c00,c5ef444b,561dbaaa,e475adbd,3e70b6cf,c49c2a00,95aeee5b,8deb5e8c,db4d21e4,cf0f3173,1af2fac5,25c534c2,34ffb328) -,S(4b4b02c3,e4c8badd,e45305c3,9721a98d,7c1955dd,90dcb2f9,e9d54901,6bbaf363,a0b67b7e,be8f59b3,c25d546e,3dc304d,d22a6a64,615bcfb9,25b685e3,18d43468) -,S(fbafe7fd,7836b427,51cf897c,5d42897c,7650ade8,ee1ed01f,e0d7dd2c,aac549c5,2f511943,52d07e51,7b7841f5,8eda5225,229a7e28,9a453aeb,5e70110e,12668436) -,S(ccd306f9,c65b8a0,7884e620,b73ac4e6,81b21bd0,2a4b219f,954de1b6,7076c06c,823fa47f,a7b0b50c,907056dc,73e04574,3f68a7,5a4c8566,8ab5f5b1,5657510b) -,S(bafbd838,995a691d,3b5a870a,7847452d,9124155d,d89a9980,820b8d56,18195a3b,8df4c9fa,c94829ee,fb0e7f52,1020b5b0,4f05f4d5,839c8687,4e893e7d,8ad92a3) -,S(d125cc3a,8073156e,a166af8,ff940a64,713d8f37,b86919fb,157cc380,224f458f,a030e8b6,ac4e37a7,df01054a,ea23a78e,1bb7a22e,f26052a3,a034ecbc,bc35abde) -,S(7d491f28,1b5ddaba,ef2c6433,be22e42d,f2d1bbfd,8a7e8866,8cbf278e,cb8187c2,ca18161d,70360966,ca381ea3,f760b2fe,28b040c7,ebc82af9,bea27ba6,f4dfe8ed) -,S(31ccda33,9f29123a,86c2995c,6a9f4979,6d70a595,5079b961,6015f07b,cdf8c39e,aeb27d0b,edf61fac,99528a9f,f060d1f2,376626b0,bc807a19,561c2e4f,e8b49f65) -,S(79e64c7,f45f9189,6c92073e,71b76fb1,e5ec912f,de11ba7,d7439f4a,297807ba,57d93436,b354963c,5891abe3,825d89b4,d17685bc,c9632e7e,fe85ded7,5823c921) -,S(d6232edf,fccb3868,71ef057b,60bda43f,69f422d2,debce06c,78a31f6a,8c42274e,13daefa0,b2e2e09d,36f472f2,29b5f7d1,58a18f63,ac3dc4d6,d62cc7d7,ec0ef826) -,S(21c0f298,b2d6e3a5,3738fc00,c8289458,722d78d2,48a33ea6,a7ebb667,446e368e,867553ec,17d2fd95,b895eede,15da569e,cbb3f25a,e5f334a2,b20660df,df062383) -,S(1d1a3d01,dcbf799,d551621c,54f74720,eaa2311c,3fd9b1d0,f4f2caee,4c3196c8,d5a7a115,9900f90c,879b1a30,13945d8c,5453bf1c,7e5e33d,6f8faeae,439734eb) -,S(57488680,8fa99ede,ca97d1,8582a151,62e26d5c,7753a561,4f4bb1dc,28e76735,debda859,7117ede0,dcc0ecc5,4ec1a494,b3bbee34,95db2b1e,ebaa1db9,2fc17c6f) -,S(b6dd34d3,4ce1dffa,4e1e820c,4c8bde9f,607194d3,1c1ce07c,9f6fadc8,9791715a,8bf48868,e405d533,2adc0ec9,49bc7cf,1487e554,3a043200,71786521,8a39cc9d) -,S(90f9ded5,69088772,ca2bc887,1522df9b,5821df6c,9e20b160,f3504bd,4a91d0de,d17e64a,dd534a6e,fdd0af26,b4494339,f76b3c1b,126397f9,a2beba76,eaf902ac) -,S(c55f34e8,58d19353,9106e4a0,c3002873,db07b239,9b10299d,260acc65,6b2cfa59,7d9f38d4,74b5a22e,72949f7f,e2cefb34,9a8fe1fb,c16b8dda,11f162de,30e50f5b) -,S(6ae44192,d38981c5,9b3f8452,c4a2b627,f39c16d2,b6f52575,c5f1722,56b8ecad,9bbba8dd,7c49204a,9edc4b91,e38e4973,fa61de1c,eda6ad61,603d9715,7f0b099d) -,S(33a7d639,423e1b36,6a93ad99,eab6444c,bd0c251f,6cd8b79a,e0344eef,6fdcffbc,c26112cc,6dca2a,fa52684f,c9ed22d3,2f067891,d5bac2c0,2bb86e3b,9411c61e) -,S(48471331,eac48670,28fa6642,a76ca6c5,3380c1d9,f52a4b2,ea640d47,f159af0a,b4ea8546,93fde01c,fb903a31,18bb61f5,c5047b94,705a714d,5b586d47,a0142704) -,S(565ac39,9ae731c0,4cffaab7,43d24b71,72defd79,beb8ce86,d46012a5,c2587917,deb56aa5,d45031ea,fc411fec,e09a9646,14664989,fd4f40d7,79c02981,98bbab48) -,S(964838b5,3b6c2b7d,6a8d017d,c5a32fc,99549094,6dcbf773,eaa7085c,98314c0b,2daf9f3c,ec44034f,c8a71ee0,ee76bd77,ac6fdc9e,fa042a2f,6caf9c5e,fd130b97) -,S(bc00da90,7b8d078b,9d83522d,ae548b14,6f9bff0d,2ef887c,4aae2f1e,c4eb88d5,6bd0fd11,f9e2db73,65f21dd1,34cb29f6,fef4d7f,b419abef,eafe15a4,20ddb152) -,S(1a59f855,f89f0c,f13dd8ae,9f5e550c,a2082bb3,27fb111d,75455ab,dba7bea4,7ea2fb40,d460adff,c9e25c53,a65c508,e77e6e76,e2e435c2,150c870a,7600c823) -,S(7a3b611b,d3bffc6a,d4508162,45695024,452706a3,279a6fda,d88598a5,4eccc764,16e09589,68066e52,c873d6ef,e549d3aa,83d30bd6,a1d730d3,68aa1ad2,32233145) -,S(2fed5577,9cbe0a5a,786fa95b,5c56e27a,a0a1cc28,51112bef,4cd5e1b7,15d6d91,7eeacc27,b2297fb5,63d691fa,36dc650a,f66fd3e6,6fe5e637,9959d46e,2d4bddfa) -,S(267ad217,952edf65,673efaea,6bebb44b,18326dd,f1b36d02,f0154a0d,774a9558,77593cc0,7e9d5e5e,688a7b33,bf54a01,703cc9b7,a0485e6d,907515bb,11a13fef) -,S(eb6ed62c,239b99c8,6978ccec,a5f32145,e0d341b,ca7eab10,6fa05ee1,7f6687e8,ad899e22,50f6a8e8,ce29b225,83ad8755,2a6e6ab8,9061d33b,6629fbfc,52c0a241) -,S(ca5cf17c,e03d214f,b4ef33c,41686c4f,5087a59b,f88ca7b1,891094d,430a9e5b,17e44eeb,473f75ba,cffae683,c8ea0299,e1935180,7257803e,f9963ad3,d0989ce9) -,S(4c7bc29c,acf0642e,63f035ec,a93e6b6c,c82f21cf,46623a2f,e4c7215e,51e82f7c,7c55e76e,8756796c,143f64e7,e40a402b,eb537be4,f1f5322,e59d2be2,82776875) -,S(57cab8e9,b42289f0,503e5013,acf4dd7,79783184,2389fd20,80b61bc3,671058e3,78225318,6671273d,a7b0b884,e72e9bee,2b048c45,9430d2ca,7c398aaa,9fd9e2bc) -,S(3c2bf23d,f1120c34,de813a82,a56843f5,abf3d272,ed2e6c27,53ff6310,9bc4823e,1759db63,88aed233,ce0c5b47,ec9dcb88,76740928,e12fe9d0,d08eb759,2d3f1990) -,S(c010a9ac,83e0742a,d3348dc,3dcfddd2,34170aa2,28d36856,d8581b1a,eab38d2,634c97ed,644a68f,e1f1da1f,190cf920,2b2dc810,446b78ea,9cd27684,3c76aafd) -,S(a4abd9ee,548ba468,e4cb632,b3d9c8a9,4f1b773f,ba3a9660,5504593a,92071994,3a14266a,ba263297,fc6ab00a,8403565d,c9390b48,ebffcb61,11b5e8ef,c8f87182) -,S(dc02c852,efc115f1,c5c08540,deceffe5,d68b82e5,99b78711,5a7a333d,e8dda172,e4e6593a,8e1ae842,ca7f4eae,d8cccaa2,8a35f8dc,cb8549ba,2367faf5,5f6c29c6) -,S(ee4769e8,223822ff,c28a5a4b,5f29fd7c,a54fc81,72175cac,1b6db5a2,91ec57c8,fca2c6bc,4076c8eb,a0978b9a,2b0158c4,33890514,28094619,38413fe6,c020385f) -,S(f3006c1d,34910c0f,d435a6de,cf088c38,2cf990cf,3124f2ab,b11d2727,d93ef066,7629f5,aa367f51,a29ebaf1,235cf267,f8016a6c,88dfcd9b,82d36904,c949eae2) -,S(7cfb203d,7bf5669,129f0a3e,325c3fd6,b1b9c804,4932f0f3,794b9357,1e7313b7,4f76b9fd,24339c38,c88c4217,387b016d,e4ae08fe,67182d39,82a45bb4,e82bc60f) -,S(cca3ce0,36e00993,9d30be8,e70455ad,efeabe71,83aeb206,a324d0eb,32312c0a,9674ae58,fe947c6d,34c63725,2058c88c,91b437dd,98da58b2,efd7e8d,1615b9e5) -,S(9fb64148,81cd5c27,82da071c,1f98d71,d9815fd2,2389d212,c66ace66,ab0d9c8,4c25454,1a513742,5f75e515,c04f1c73,d11d5047,9c76b09b,ce23c13e,d1813251) -,S(1dbbebf,3e3d459,10d39de2,32560b4d,eb5d2ad8,6aa1542,c2c070b6,51558b25,ec68e71c,2e94e490,4194753f,d7484ca1,940eae51,69831876,877b9ce7,2d0b9db1) -,S(7751d219,92f47421,7742856b,4c84d41,5a890ee9,24185e21,5a210a3f,a46bb5f7,2915a9c5,b770c86c,edd32749,3f698c17,6371f6a1,4cac5a22,73a3c648,1b237fef) -,S(39a849a0,5b189c3e,20782983,ecf664b1,e7b89c96,4e11d737,70797fca,ecf36a2d,d3e6f8f1,6191db06,be2274d1,56685895,48e69253,54f41114,f43b5ed1,13690c5) -,S(67e56125,b29ced20,f9f95522,d412d67c,80e3d628,b8bfddea,768117cb,e79b25bb,608dfc15,7e3c23f4,4aa0fd88,3d02d293,3c83edcf,66ea57f,9167b712,8d03da21) -,S(a51aeda,2f7d59d,d31eec20,e95839f6,ecdd01ef,529327bb,5cb229b7,b78f1525,704967df,93fb862b,3d38b18f,4c6818ab,6621c7d0,80d92cdd,1f0092c0,d7847903) -,S(c980693e,73a1cb46,f5eb71b7,73b00389,f8bcb36f,fb489e7a,aae64c23,6ac1745d,bf3b808e,fe6b7efb,771853e5,6fbba6e8,b3b21fef,706bd4,274cc058,b6fae474) -,S(c78df930,bcf54c1c,28e27aab,2975e9f3,94167bd2,948d4713,6b17a374,a1391a9,9a424f36,6d3a79be,55bb5e9a,283be1e0,163bfe22,1bc65e5e,318f0de,304d9ae7) -,S(9a75f7bc,c6d2f3a9,e6168ebc,8f7f1e50,a998b1e4,e67316e5,fb242fc4,6d284089,cb478e6,dff8b9aa,3ad06c6e,8fc7e35a,39bf6ec3,787977bf,d40f3159,bf169e01) -,S(76b2131a,db0bb3e7,db48277d,95ce73e4,7eba1e7c,b6f801c0,d20b71a3,8b6e6224,32e3cda,ef60e55b,a9e36e6,cd287737,196c5af8,120c47b2,f79d2492,9979263a) -,S(21898361,4ec5971d,f55f96c9,3da89483,cdcc4c46,deb8de68,f32a42b3,5c1384e1,2c396c50,44a4953a,b22a2d22,47769741,c5eda54a,d9c9ac97,d6486b5f,126dac3e) -,S(ac0b0a49,4e9d180d,101dbe1c,a528fecb,a08449a6,cf5d82a9,aa14f875,e3db8adc,26d1d412,25a1b583,2dd53b9c,56a6a8e8,371dd19f,31462dd9,b2aefe3e,70412554) -,S(f869b58c,851a65f,bd6d3329,75f596a2,9d1a78cd,bbf04a1b,6dca6c27,30e04625,40dee344,fc6f5c72,c18b1603,e149949c,a0cfb31b,b8b91b09,c3cbabb0,c6a5bff0) -,S(f74f02db,2406250f,8984a5f2,273c63ed,a640a43a,8e7d72aa,ecf78d6e,b9544c3a,882e3a6d,cacc1e92,8a3c1a61,85f2bcf1,5e364f7a,1eeeaaea,1c0af593,cf86185b) -,S(c0613eb6,1d6755eb,2ebc9284,a0aa69d2,88c39050,4b7e869f,f3d943aa,67ea65d,72f61ae5,27b5c82e,4afa8966,55d9289d,29931c1b,f0d36c09,fe4213c5,27848cba) -,S(eb66ff98,60ba08a6,3c0fd8c4,7117aeb0,ae0dbf63,524307a7,eb739f08,f31285db,c3142ca,54bcf2ae,8b05dfb9,4e40f4ba,7d3662f3,774e616,55c7515a,87ddc5d5) -,S(3a7108e6,a1256061,fc25d58b,ca534602,e41c6b15,156c15b8,71a516f0,ec4a861d,daae2d02,41cabb2,191b5be,c17e7e88,957bfcd7,66df1226,a183064e,3c4393a6) -,S(d17e3a58,c83169d1,33ee7371,7b205f2c,ea1a2ff3,4e744958,949e9403,b8f89d5f,98c35f7d,69e5d98b,920ffafa,6d15d349,2d75fcb9,81ca5022,5ac7ff32,618b1a20) -,S(d6e32892,cefbb8ed,14350cbf,2618e2fe,98caf6d4,f7679385,fff36bab,bf6541c,7175462e,be0f5ec0,7872b55,356f2498,976196bc,edbe021e,8081ebd,b2636298) -,S(318d49ff,60e900ae,6e8e2182,f38ec006,82ddc8ae,93aa6291,86d5ddf8,affef75,6e97ec27,dd7d614d,c1ed4fd8,fdf6aa70,8dcc3eb,be288831,a9888166,66333b2) -,S(fd6f9e30,1772db8b,a68ea5ae,b585abbd,c075e72b,68d6f67c,5a2f8144,98cf6346,dadd16e7,64775bd5,ca5c5f51,35843556,d7608230,aaff4125,4d4eab38,1d28d2c0) -,S(8fe25b38,a2c74761,a90ed08d,4bce768c,f074282a,e9560d31,566ae43a,182ddd36,6ee1e84a,77c6ab78,a2cda1b3,2fbdfe2e,51d66843,271d15c7,3f8e1a82,1e4c23a2) -,S(37cf0ed2,88ed8fef,4ae17bcf,f6bfb815,3e12bab2,a46d7e5d,2e6feb99,9793bef8,92e7a57,18eb0751,c99254f4,ddb5c278,e17a417b,21793339,119a146d,bbe3e0d3) -,S(688c2061,6b9d0c8,76deb812,b60000e8,eca0e04f,531ed1e0,9158442,7bf403c,bab4b2ba,41ba4d53,df512e76,32200bdc,11d8583,f2ceb5bd,a8b7eb14,5ccc01fe) -,S(4b4caaaa,f5399535,d822371d,63965216,d1b53584,d89a84e9,d868395a,70b3d804,3ddd27af,cd18049a,3b01d043,7761e4ea,652fbd91,115c470a,e4c7bd40,51ee73d2) -,S(6f5acbc4,4135da60,758ed9a5,18b39b5f,47cca398,24e20e56,1444dd52,e2fa1d2e,5dc9d46,e5f6d94d,48af2efc,2f197a2,f729f1d7,335fa569,524d37c,4acd58c4) -,S(79d2d449,3dffcb91,6fda527b,f8b6b622,661d6f23,738288c6,ce94313d,c267fc42,b2683bf1,3fa8f7fc,be302823,dfbc9153,8d902791,d5d6dde1,d2805f37,a0c08db) -,S(33a8e87e,246b7b9c,9c77a6b0,7cc67d41,f3915dbc,2180118,c0800b33,f9f95524,baa8244c,584fd05f,2655e36b,e2e5c459,207d30ef,dcdb2294,70b34333,9d16ff8f) -,S(9a169132,f3887df8,20561a7a,e4bd5461,3235ddb2,fba7a19,3f4daaba,79868e95,686fc317,995446c4,42945216,1a96595a,a233b100,e5f8bbc0,71990229,44630bcd) -,S(790b74f4,8405ce3f,9abdc7e9,439f2f5,c859989e,2ca5e6fc,29046104,8783ac42,8961c913,562385ca,990593a3,77111a5d,1dc6762b,b1a928a6,6ebb304b,8a24a701) -,S(e2a3d0cf,ae1fc2d9,87caaeb6,9f32fcd6,95471785,f524e438,b5487aa3,72f9e49c,9cc24205,ecf2708c,357edb54,308ce452,11f7dc03,98fb48db,4982d337,14c93046) -,S(cb30c43,5992c195,76d372b1,96f2ae68,cfd2653e,63e3ba7a,2b3c21ec,960bcbea,f65735b9,708338c9,acc9cba1,4b491b8a,fb683058,266a483d,4987cdd3,89ccd0b4) -,S(1faedc95,d6310bee,6298ffb1,6fb3e6a3,296ca66b,7c995d2d,fe924381,10e8b46a,35039e3f,8201e904,e5378d03,2bd8b766,26d9f0ce,4425d2ce,e7bbd24f,b8725089) -,S(a646cf5a,2be8c1d1,3f05410c,ed51b3f5,8e93ea53,1e28bf31,8f6c750b,52b3e8f9,58c58ecb,7727a920,b47a7e78,e1e51d11,e427d7e4,465429bd,a01f4650,a4c102bb) -,S(32734727,18537d38,e9b8c397,a5cc322d,1c77c0c6,15eded39,dcebc020,debe2205,c2debc89,58c3f60b,d4c7b072,d475a7d5,c1ea784b,c3e532bb,72c02490,9a42d65) -,S(16a1a718,855a212,c068c095,d930a270,9906dd22,e7db3f4d,4ce2f393,d572827e,d389d64b,b30ba9eb,6ce80335,cbe8f7dd,b1ef3016,a8b74660,2196b724,d115605c) -,S(b4bf4d14,5de25571,33694b86,76166e90,eeb1ebf8,4a7402e9,a61af4cf,23687596,49db20a4,d82397e5,6318640a,6b605e96,37d38961,a58ae3db,fac2fc11,bbd11242) -,S(d4ed67a9,ccf4665e,418a0de0,8d9380cb,fc311413,e90a964b,bf367b9b,b892630,8ff7e57c,e79a0883,1fe8a972,92493764,7472b77,61b055fa,37105d18,b51df131) -,S(8ad256f1,9f413ef2,eae906f,c1c2ca4,44d5dfdc,f916d366,b32f1f47,f54fe70d,bdeeeb41,8d2c4dc5,82547f65,91c97219,34778f5e,d25eff4,94e243ed,a6d34da7) -,S(8dd3e2fa,fe55b5f1,f13723e0,1a5587b9,c67d22ee,21f1f62f,7f62a15,31f17f8e,aa23d2a4,7d6b717e,55d7c6b6,5d9c46c6,8f2db41c,ba66960b,4b4bf93f,5fc88cb0) -,S(44fd9e28,2a8e30af,ac34db01,a7b0e939,3c13917,554d9a67,8e577a5d,4b3d0f6,cb079061,353319b3,a1669d59,295bdbe2,18927d06,ccb1290e,4840cc16,911a61d0) -,S(5d249a02,4464ed65,831d2aa9,c9645f46,2db7c9f4,e5a46477,746b1a71,88b7aa42,2bff7386,527d6b5c,2c595f80,e08b4d20,23bb8dfb,f294da12,b54f8b14,77281d0) -,S(d98eb458,1edcd51d,465e123c,d891c481,ddd18b54,b9408ca,85ac47c8,e10fb23,15bfd3be,d3756ac6,f2f1f9e6,f254c9b,2b153717,1b265081,6a2cc21b,78b4dcf2) -,S(2f12c369,19a2aeb6,2132134d,2e85150f,6edb486e,9d672eb5,876804d6,44db6082,c0111edd,3b4d28c4,edd264b8,dc2bd0e3,20834dc7,bda82dd0,827133c5,7f8cf73b) -,S(4d949684,7099c9f8,421d35df,ebce57aa,71326034,8f07e3e6,f03017c3,144b4624,9afb5a57,d71369c7,28db308f,b8b07da0,b91f954d,b182eadb,126b1fff,ddb673da) -,S(cf1db910,5e95f1c8,e360b39a,752ab17e,fca8f24,d9ddc8b2,a9768700,e2af2466,e7c99f66,c49c8674,a6c1b94b,4b964019,5e645ca7,b3d2e004,ad8dc73,f647ca5f) -,S(e71eb425,7d2ffa8a,b79d63a2,42c67585,d4b1747f,5b27f22,a9ee4284,6aa62b85,a906aeec,f901a376,7d721f45,da53e342,3bc0a779,870e33c3,d10f6426,6a2c8865) -,S(bcd987d3,b2575f4,3bc5c3e1,b4a299bf,21c58b6c,a27ebb21,8f9882ab,30559887,403804c9,4339ae27,2bafd894,e63a4eb4,690c1b4c,9289db00,761e9b3a,1d483f65) -,S(b74d5cf7,48af7162,395d2d5e,8a69f740,7a2bebba,69564042,ea9c7e34,b1f8cab0,b5c5fddb,332bfb59,835e9a23,4afa4543,5728dfaa,7dcfca3e,a3c57deb,e849b336) -,S(46f3def5,9835c9ae,1a7b3b13,a920bea9,e9bc12ee,633b3edc,57251b72,3560837d,587b2e1f,2e8eb9cb,37aa6977,870214ec,818fb71c,1035eeca,91d53e68,150ce67b) -,S(8d3418fd,eb3f0968,de51f4d7,cbb60299,a50ceba4,1915d8b6,5774cfb7,7667d572,cee79910,16a28462,aa9da7c0,f67b4c7,e8b3dd38,f4b2203,9d05115a,ac661db8) -,S(98cb0f09,4510695d,78a0a672,eb67253a,30f4327b,7864fbcf,529cf212,ad6f7c10,25952dac,4e1b5035,9b47e9b5,52852d1f,300fde75,a6bd532f,9fd56af,2a0ab333) -,S(96045e4c,ca075fc,4a5383f3,f03de105,a34c7c4c,b030ceff,b58b98e1,2b39a3cf,f527b8fd,92234151,ba11f24f,7bd5dfed,6ebd03e3,a5048c6e,8f2d5231,7201bafe) -,S(f262e891,42addef8,cba26a9c,ad779761,c3f4b3e5,5990a93e,703bf56a,99cc6030,275cc764,86c86a90,f597dd6,7092ecff,5382c7b7,33939ca1,d1f3218d,6f0b594b) -,S(cd79c02,ee175336,5f9f7900,be51bb2b,ad75ef81,3c6c5634,7cc717db,156d17fe,b5ebe8ff,b30de5bd,a5326044,16abbae1,4ff9198e,b491794a,c4500031,947a985d) -,S(28b4bf22,5b1d40dd,e0122e03,e630830a,d9ba4629,cc51c9d2,80a225f9,48f858f4,24756189,98bb414d,4a534c6b,e300297b,aadf4ffc,b10e6795,4ea36e25,2cf3cac0) -,S(f018f206,7dd55df3,9c53344b,c6128a5f,cc765c36,c7b0bea0,16c8465c,c6ed2ff7,d9fc5ab2,cd619d4a,c66c1cd2,251504cc,cda34a76,86c5661a,960a00f8,e4aa7e66) -,S(496968cf,8086d02,9a5dd5c7,4f47cbda,7f661ef1,488b3942,18ed886c,424a7a13,d7d8df98,442060e0,f17a363,579c6600,360b5124,2774e2df,c8d4b787,1e1874e7) -,S(242d4c59,e9113b77,68e48574,93600da7,b984355c,a1d07949,8921016b,22efedab,470dcfd7,b0c8c2ed,63a28074,a505573b,42f50920,6b0ae577,27a8b796,7a0f42b1) -,S(b6b804cc,1a1a59d3,84c4afac,c5e5050f,466280bc,d5ab1586,1d20f4dd,1385e8c7,2f789346,2a636a9,9ba2a1d2,32829f41,39b57967,bb26d0c,898798bb,6521d439) -,S(dc30a3d0,7ecc5fdd,38b8048a,f281024b,46904b2d,2a4c51ca,d1b49b7,1d918a4e,326409b0,70550e97,58f53698,7936a54a,b701f7b6,78a7d10f,ebb511a6,c18cc917) -,S(e1fe434d,345bf330,83abb628,f4f44ac,5fb22934,977813c2,c015f2b,43d3fab8,1b251ca5,2af897ac,4c08df48,ce3d1607,d3b31b2c,2dcd7f7a,59a95b07,774c4d83) -,S(a8ed88da,e08ac5e2,afbe4a40,ee775645,82c2f513,cfd72060,bd1fd5d1,76fb8d08,f4fb60b0,74419630,fbaf5b53,717b2a6f,5cc2d98f,1d29481b,77b1f9f3,84175729) -,S(b52cf828,de1e9cd7,c95c083e,ec50d228,8e770713,a0e2543f,76fa5790,2c7c6481,635a3953,46fbbf,903dc729,d3e3b52b,43eebdc5,3748ed83,3c95eaf7,1b75790f) -,S(702079ae,f76d9bfd,ccb957a9,4aad93fc,b1297c54,d634978e,4dc78292,161d5e83,4983c08b,f2d81c52,d3b3a202,e0c6ddb9,32a43a45,c4b95f82,c8c10642,5a783b52) -,S(4638d4d1,8e9de1ce,ef4fe8cb,db4378e2,3ed3dcb9,513cc9a0,dd73ee2e,be57bbf5,561ee032,45cc3066,968853f7,51fa36be,cb50740,a5951e87,cf77ef20,cb27e110) -,S(eeb34eb7,5facadde,d561dc5e,e3d0a039,d98e4880,910439cb,ecfb22d9,3b386bfc,f2b23cff,5ebdc8c,558db8c,1c311a94,e9d8f63a,d1cf4af4,c21c2349,a6e57c4c) -,S(7f2c6e5,becf3213,c1d07df0,cfbe8e39,f70a8c64,3df7575e,5c56859e,c52c45ca,950499c0,19719dae,fda0424,8d851e52,cf9d66ee,b211d89a,77be40de,22b6c89d) -,S(6ec76722,1ec5d27c,f7e11064,d4f8b016,3cea090f,6a950f81,85623303,23e53647,9b03c757,9704e839,c8eec7d0,f063c4fd,d0aa7ba0,5ad75254,984b1703,ae69a3d6) -,S(98f6f69d,320d5eca,1f184b0,378f67cd,b44a707a,c5b2af54,99e9f8a4,524dea7e,26ef6b3d,7b037663,979333fe,56bc33a,ca54a3dd,78c9244d,79ef5426,f2b69a02) -,S(cf1ef445,58b82c76,5d77ac99,8c0170c9,2d308668,2d9ed7af,2961cf05,5b47e390,8bcc1d05,fb880ec7,8762d8f3,f5afefe8,f4345bd8,36397d23,befdf446,498511c3) -,S(10e01651,efa26f2e,f88cc5c1,594f378,9ab62b82,5a0875aa,37c280a1,8c6f07e8,2e6a15e1,1f776335,30fb2cdb,788aaa98,83105da3,7e28c0a,8fad503e,b9779df2) -,S(b94e2fe0,41ce209b,6efd77d7,44983130,af90945,120b9a58,5427966,e93eee4a,8f7abf1,103e92f5,5dcb1dde,746df10d,a86bfb8d,2776a0f0,1d07142d,c9bca443) -,S(cf9e7d02,c671a9ea,145d233e,244d8af6,6d71cc34,e17f2ccc,1225d2b3,16d41154,82eeb8a1,f0b966f,bbc3858a,3878f969,a853e2bb,e1b60c4e,e13eff85,d2d2ca7) -,S(da3a3c29,94ad3b91,319d18eb,dcf4b934,df8e4f2b,e052f436,6d539aff,4bd48bb2,28f9d653,c4042478,831ccfe7,bec86663,5e0d32ed,f6db4f54,25669a91,d1dc0193) -,S(ab812818,2b80378b,d914c9fc,d2831f30,a0a095c9,d0e52450,d4ba27b0,f1eec101,5abc582,274876d6,3dce366a,fbb1d80a,2286dc2a,dc0c078f,1424d45e,26666b3) -,S(ea5b82a2,bf02caa5,d5d64391,c0965c53,f0edd967,f8df94ab,831408f7,e5c4977a,81fe8299,f320837,acddd504,7b888e6,2518d53e,897dacac,5d28bce8,ff3d9339) -,S(50605c0b,ab201d7d,3dd618b,e3da2d29,318aeac1,7df58d2c,a95b8fbc,fbe70fa2,e50b1e,7b5693,c4ecc160,d928cd6e,d4c978fc,6c2a68af,c03f397d,72a60383) -,S(f76c50b6,6d7dcace,f45409d8,854f79b6,51356661,108b7168,31b58b25,ea1191dd,7d055b74,b0195140,bc0e2e93,a97f07b3,a3040148,7720df86,d3bd1810,6df3cc72) -,S(de5053ba,d716047c,cc2367db,272e4e11,41312690,2bd79b32,f6d3d959,93260e7d,1c54a2d3,9c34b0db,deb61b5,b5f46033,b1e4c581,5113bf3,d3f38de1,c97cc7e2) -,S(ad3e719f,180e946b,1b98a332,bde18e54,437f1a24,949d712,1aff7c8d,fa06499d,b458d7f1,390fa4d7,d2473863,abedc063,ef310adf,7ca2f2c8,82bcad3e,2f1b554) -,S(270a0234,5560af6b,6310c867,332f8b79,839a3ae7,6e2666ec,b46c840c,c36bae4b,8daab84b,92157d16,ca0f160,99877a1,ef7ef072,1bdb5bc6,89d16a19,4ebedeaf) -,S(eb5ed17e,3027c9c4,c87ffdb2,94a84ff7,25ba2b5b,2bf72d30,f98334ee,68624621,39fffcb3,8f74d471,9be8d1a2,14c61ad3,df4a91bf,d599c3ae,3b54b4ec,860a942) -,S(b9c11df2,8a0b98cc,623f4e80,75acd469,fb1f6621,a7572d6a,7bac135c,2ce0a5dd,5bfa8a78,d42b95ef,327eb0c3,692b3ba9,5eb506a2,4e2fca1e,391ec545,40a76278) -,S(eed17043,80abe259,fe661106,6eda0408,f60f1399,3c49a21c,a8a6310c,ebe74b5c,6dcb6276,cbe37b91,162a243f,57afcd9a,8cc2c661,652c324a,567d5db7,22a0d750) -,S(8e4b0f6f,5f5b9cf4,68e5524a,4adf62b6,8c68e310,5ee374c2,5265000c,53aa97a7,d1f880ae,c18d0191,b74578c1,6d0418f6,c7e59f2d,157c0d56,e25137ec,c1b7f74a) -,S(77ae21bd,fc6596b9,ae85ce9c,93112b1d,a7f393da,1238d76e,90cf59c8,caa5ebbe,f4484581,1e3266cd,f4625390,e729154f,51694717,3206ef9b,9106c547,ff4a21d1) -,S(1d379ca8,71c02ef4,59a8bd35,f5066265,92922533,f0503999,e16d6b07,dbd2346f,c0550b9a,72899a7b,42197cfe,d195c704,a6333d5e,178d91c1,d50b772,4140cad0) -,S(625017f3,28fc16ae,99367199,5f02772a,5c7ea721,7d47c296,cbad670c,3fef1ccc,1b44e253,af3b214f,edbeb4ac,50110df6,d7056d06,617c2bf3,6189a74d,64450603) -,S(c7a4fe49,6bdc3509,3ae3f508,d43877e8,d1019d16,740a5eb7,8eaa72b8,638412d,1b5b12a8,95fb7130,e8792406,74b8f735,6730938b,675996fb,a30a9744,960febef) -,S(cff9f83c,e8f9c4ef,3e80102c,bc48c409,b65c6166,b74f052f,a5628348,b2441d3f,4cc418f8,2180207e,fc846a41,ed6973f2,814ceb07,a8bd252e,338e32cd,e352ee6f) -,S(84027710,45b8c295,c938ae98,a9ea11dc,2fd23ae5,7ade6ef8,2c604721,66700541,72946592,d3c11404,881b972c,eba81d4f,f3f80dcd,40b15da5,f56e0723,841e4f99) -,S(f7ab1330,e00cb9ec,61a346b,d8f5522d,5e304a4e,a94f84af,b5c70614,d2e0d2c,5d4ac851,89350a54,af58def4,6f3f3d69,2ef0f6a3,9dd4ef86,6bb1101b,df5e6144) -,S(a7c84e19,2303b778,8c1a4d5b,786c9829,d0da4ddc,c13f692c,7851884c,6fd4e618,56e32e5b,8fc2db2f,21d64bad,35e3f115,65928533,a829d744,939ba456,bb1774fe) -,S(b8b0c884,a680dac0,363bc55a,fa677a72,c65f4139,7f5cdcc,f199d80d,ac98c43a,43e4188a,c92606c1,cd6bec5b,a4edb045,6569f87a,625db932,d0f8e71e,516b8127) -,S(816ec443,d0576135,5a3bc33c,1db4a179,c5bef98e,943af8dd,ac250482,a65e0df6,89a7b2c9,e9f3588d,990f6fa1,96e366b6,54f9a30,1218a2a9,c9b87c48,55f0b360) -,S(8ded2103,823d07d5,33fba24f,7fccc47c,b101960f,3b717fd2,af39d49a,a91e28a0,3f03ed1f,be1a661e,f43ef9f7,d753eaad,e3e1a391,2a682ad4,fb19526c,c0011728) -,S(b1c4b39c,e874d478,bfbdf9e3,ce8c3165,ff4f7c4,bee20c87,4849aeaa,d0d6260b,38af8b61,30701881,fbbfe724,5396adc9,32c25b84,dfbc4dbd,a54bd236,c04b4fde) -,S(7d5bce3b,e5953eb3,a17f657c,fabc8209,f011bcf2,7e10b90d,e75dad9,fab2c971,7380d686,5f5fd782,b0708b3b,62c39e49,864b2ba7,4066167c,bbcede2a,b0f84787) -,S(2af5111a,422af2cd,14e7717f,bc7171c4,96af178,8b229497,a54d2b87,4c00f285,4468bf1b,ee43f100,7e800b68,b7b3b243,2f3445c5,c8aca59f,7534beae,bb771f41) -,S(b46e29c0,6dc8ddef,f8bdfb65,f4043b61,fe010dae,a2d0955d,c81a7b49,637af766,62777495,ae16314f,d7d0cef8,24a27a9f,748c5c9b,9c51645,9c1ec9dd,9d7b59f5) -,S(105786d3,f44ea40f,71eb3bd5,339cd514,aef6d8fa,5923b4a5,89b219c,fba6b1ea,2a4ea7da,c87522cb,7d92c450,8e86d0b9,39fad024,9fc2cf15,1ba005cd,b743d0bc) -,S(1f3c0c81,be856e30,18934573,892ceb22,d2d2d8ef,f08b7857,5c624f48,16adb23f,7321690,de24499c,f52f4840,89c4d7b4,11158d52,d32731c9,faaea567,8bf6072b) -,S(16dcbae3,a95a95fa,912484f,f833ba0e,e437876b,f16f9c9f,5abf46aa,468bd2b3,56727c07,247b12d6,c1ade473,3c691700,30e5582a,cde14034,3449f241,59ffa44d) -,S(114be56c,d6723c8f,924ff3c0,f5edabc6,e42314a6,49edbfff,1c794438,dae70726,984dd72,855cdeae,7c580046,b32cfa7a,45b61b75,944735e1,d5fd9065,268ac521) -,S(8d0cb2e6,1f98472,e169dbac,7f5babff,51766b3a,8d74e17d,747b7eac,d903fdaf,d1593bf5,b9e793f7,25cea368,2ceabb11,f06b36ab,899e160a,f1f736a,80bc9b92) -,S(5b420754,188c82e4,db72f3a2,c8049691,34e3b43e,484b45ca,ab4727f5,31714db3,4a89307d,27d7f360,7acd1643,719be148,1c7eed5c,77598883,8bf6cc13,a4723d9f) -,S(91e3761d,95761d96,8d856a72,800fe0b5,9f01c62e,1cc446ed,18c1b58f,88cbf74b,b5ab61e3,96f88376,28f3389e,9999ef55,b73a58c0,d33debc7,25812530,2b96c772) -,S(31380b83,dc77e5f2,9c2f5548,abe052a,16e0f1f,2d8aad3,5b05d29c,5c1a4655,23ccafae,cc84ea72,3c434342,b839cd0a,b42173bc,1aa1db20,1073fe26,6593403d) -,S(ae40198c,bcd54264,904b44c7,c9019553,8f3f3727,a0c9639a,764cda80,b21edd27,3a57f08,ffecccfc,cd9a0e7c,827d98a2,ffceea9a,6c39d200,5cfae623,34eeba8f) -,S(f4729787,abeac0f1,249b1d3a,c19bb025,5764a854,727b415f,73e24c88,a8a981c8,e31161a5,68d81328,c7f9783f,de146d07,b51aae15,bfe719d,ab4e9e,ae65d172) -,S(f92f02b8,34148934,f7059b61,7e84d0a6,f52d3b8c,a7d7b69,ce4c8175,7ed5884a,faed7ef8,82733020,888eb530,5c6dea4b,cacd208f,fbb66b7,6f3cf41,a8864080) -,S(a2bed8aa,e93bd682,be8cc4d,d1f84fc2,9efe4022,b2b0dec4,9ed3ce17,7cc93363,287ab9c9,62126fb7,e0340f29,9edeb89e,7bf235b3,b3f08213,d630c9df,198ada1d) -,S(5a42cfcd,3d1811d1,99b09dc8,9308134,cf6219e2,e029598e,899418f9,b7af4724,95ce721c,39929d76,b0ea83b1,80bf25c2,e301413d,60fb8717,2e0ee8f0,593f8423) -,S(1d27ab05,67e8bf19,323f1eca,44175085,2e768a6b,a1436789,40ba2b94,5b0e530f,18439939,496d29a1,58a532be,76b04932,a23e3ddd,d51a1b07,c6c33e6a,11e1afa8) -,S(592bf859,22c05bf4,4b42fcf6,e4cdf3fd,bbbf8088,b7263d31,9bc74914,6eab4326,84cbd8c3,8dccf0ef,de3946f3,ba2eac25,3aaab976,8f7f601e,7d95bc74,4c7f65) -,S(66730a70,5ae3dab8,bfc01f4a,deeadc41,d4df156,d03c4fcf,1dd9e16f,9359d5,c04c7cc4,4ea1d8b2,273b9170,19b9efb3,6e8f422c,4863f718,582f57a0,778273ee) -,S(3d002600,532420ac,9fb246d,84e48560,1ce6897b,979491ae,7c5914e,dbb7fe83,5bd73264,2f16d4e7,7bcc4855,72494523,c221fa1d,321c552a,53241dd7,94c7d98e) -,S(d42ae36,2b5dd22f,d2089d37,d22e2c2a,750395ad,710aa1c0,61ed4275,43a24487,84439e00,1571e1ea,53bcc24b,a11b6f7c,ded0a649,b2a12fc9,c2a618fe,cb39ada7) -,S(37c761ca,486fabfd,b306d,c18e9074,409e101e,5bdd1670,edef1253,aa253743,e53840e3,1110db1,89ec241a,e7b2cb89,29669da9,5c07f3d0,6277f667,b90cad12) -,S(4e672ef8,bbafbc8e,eb819f37,15ac0d6c,2afa9781,a197345b,2889ed0a,f3b0e788,9c10f0db,bb16d807,4680133f,e62e0eab,130cb0b9,51937852,4afcf4c,38814061) -,S(c1f2943b,23c07929,e9c635ae,66f62949,8e1df12,f35aba68,ed8791d6,8fd51fec,3376b6c8,93ad5ec5,991f7ef9,6a6b1105,2f2262c6,680045fd,fc4d4bfe,ea64ae75) -,S(3df2461e,739cd984,72cf10cd,f663e651,351e826d,7afdcffc,e17602ae,c0370be6,5e48fcb3,3ed9c0ec,3594eeb0,81adaaa,bd5ec5a5,7eeaf01f,c9f00d02,c692cb06) -,S(d4d3d528,f98b92d5,f4c4ecfb,ab60fd85,50f12327,5b63b3fd,5518c1f3,d62a82b7,64496d50,85435de6,991a838e,d984bc09,2554053b,54b05a2e,490d2ce,da7d5b76) -,S(ecd8399b,4aa3368f,1a7a4113,63ff03a7,ad644847,e225108,b3ee7d02,1209236b,2e1209fb,a7921c29,e351e61,73c02cb5,c629d88f,4ca51af,30f37123,75355213) -,S(d5990be5,7e6a0da9,333354a,fb344d59,416d1a70,785cdae3,8c332e09,cdf78722,b2a2cd8b,73f76f3d,1079198d,34441008,278f73c8,93979ece,eefc5911,7ba17814) -,S(7598ab65,1d8ced00,af3d5978,661d801e,b57e9089,287bd74f,85ef042a,90374b1b,589fc426,9466b1ff,b9c0cbd4,b022e9ee,7edaae87,8f4cc240,b60db60d,6c28f04f) -,S(fd071417,b12d2d31,852048b7,61c5301b,be088cfd,98ebce7d,7e0922cf,41f694e7,2d9c53f1,ee63b93,2adf679d,96b548d8,d47d8f74,58ef8b45,9664da23,be32c363) -,S(5a5b4990,e290868a,d1d571ac,8e9347f2,b1e513bf,cbc2b8d1,5e56ce01,2b72ca0e,c76852f5,7159524,541569f6,3c4c9c7d,424285e7,e83145d5,e5161998,efebf968) -,S(93deec24,3cd4f146,42f5a415,f6ea6f36,25c90081,5f3d20f5,9728c056,fde7f2bd,88f919be,b9993a16,61f78145,f54149f4,6abfa859,1907736d,d5e85f25,bf2dc7cb) -,S(9224d17b,a65ad967,969104c9,3068d439,9c9bec7e,7613a602,f5c9917e,46df82b6,346c98e3,2bc2a4e8,c7689e54,eeb1064c,1b5691fb,cf5a4710,55cefbcf,18a32f65) -,S(851acc91,24ddff9c,14cf054b,87347a71,cfc91637,6e559189,f055143,3b79c38e,d959bdf0,58d21cc3,430527e8,cc49dc56,2dd20bf1,30f0e13a,55cc69cc,1e116f35) -,S(ff6c1303,b7c111c5,87e01ef,44829510,eff0a612,931f9212,2b71075f,2cea4d96,24f09bbf,7bcf50aa,ca239be,b925505e,7e99d0ff,5a959574,5370eea1,7b4841f6) -,S(f23bd9f0,55e7bd1d,433fb51e,c8b6ecb6,fd5014f,4f4ca9d0,6a4bc636,435fdac0,9652b458,9d269ad9,68ee7012,aee47447,25ba917d,f120bda6,9d2194ee,a56d7b60) -,S(9d622c56,ea6d5d19,7b823e60,1bbd4af0,1fe070f9,391bb564,2a05527a,49f46ff7,8061bb94,d6485fe,d9fbd557,66db3dca,c648c7c4,2e025494,e6c3a91c,fd5c609e) -,S(9494efe4,cff5d5e7,6394b67c,407b9961,2915afde,56933b80,370d0adf,2f020c13,ab0c7e38,c85ee1cc,27964b2,de42372f,fd86ecb8,fd3f0a81,84f5af38,58a7e4ea) -,S(a8e4d7ba,ffbc52fc,a8cb6c,2938a01c,e028c259,97403268,dbe1600a,952e1a86,8d5b83d,dc3022c,4f79723,c6f16722,cc7eeeb9,c964496f,c9f67c29,351a0bed) -,S(83841f64,938e460f,eff191ad,4d72d7a5,203c01af,1519cdf1,f17c3bb5,e4927ac5,f5868f2,c2e87249,21373397,40415c4a,ecb1f30d,b204fe41,80e01d79,eb536800) -,S(ee8974d9,5ef03f8a,860dcba6,7b597fb2,af2a2df6,950aeacb,d623c883,20612f6,5cf10d74,3085dd7,cc695145,3f9f763d,6596abfa,eb7cf216,34ee07f8,a4f141ac) -,S(68e88d8c,23616ca3,b136e5fa,3427628d,a92dde6b,2691d857,b2d01a60,b6579606,5a9090,3766d6eb,c58c5d60,9b6a5675,e5ec7b73,86a17c41,2574d179,a0fd5450) -,S(fe34dd8a,c62ec8b6,20dbea79,44ccca40,cfe6ab5a,ce3b2e7c,50ac589a,9522345b,88cf0055,adf1e122,535611d7,bd3e00a7,30c9edd5,898d25bf,f0abb9bf,6bd6c8c0) -,S(423a7a9c,c0f81489,aaa62479,c1317368,9989366,fd18bff7,f6a5f235,8251bc1f,c926b3dd,519241d,2e776ea,16112e41,259ce896,472ce71f,de4261bd,29c678ee) -,S(7fa60bf9,7cbf54ff,e61bb840,b2e08d91,ffb0eb4,727c0e73,ed4f157,ad0b98f4,d5b1aadf,84d387b8,fddc7b26,a7f736a6,7e296fed,7978e81f,6e7b3b09,e94d733) -,S(9e53cb0e,f1eddebc,77edf8a6,6917f915,8294815d,eef898c,f1e77433,60153a66,5358daf2,60fea2a1,b9a4c6f1,b8bebe09,4983499c,fe5577a2,ed8f817f,46b41ccf) -,S(adf93641,c616c677,99b44ad5,354332c0,1404718e,8ec91e96,31e69552,3ad6f119,da3c66af,e4cfb3df,f55f6761,5c6ac42a,8dc17241,5ad38619,dfe2a13b,7e42ff9e) -,S(701e3ec,485db367,b0687ddb,2be15f4b,5b6242c4,396f6f0c,9726ecb6,474e4ca8,1098fa76,13dce1c5,29f7fea,30740377,691aa3cf,3d13cf94,6f2d8191,2d3b9e83) -,S(d8fc5ba5,d3ecaa05,9e9a7e04,2c52500a,d513645e,6149e84,aac0d910,f8ccfefc,72724b4d,eec94da,7494b4d9,83a2df06,df96ee83,e578d920,c2597089,7b4b3d8a) -,S(7bc88f9a,8279ffb7,658a186,faaa5f0c,c900cb9d,4a33b8dc,c9eea83e,ff71398e,cdcd21df,e5ed8151,1a2d8c77,e08b76f7,4939d39f,1f5581b0,aa956066,fa14a7c) -,S(8578d531,bc79e1f,6e219bc7,7f2172a3,e5fb92a5,efbf9919,f46ea11,6f5ef0e5,fcd1b2ac,39c262c6,94eef5e0,52338f9c,cac2d04d,ed17c290,768759cd,13b7d550) -,S(98bc22d7,3ea2661b,545eb5f4,37e1cc0a,d4124020,44bb9093,5cdde758,a8020a62,143c7dde,d33ba5b,c2ac8d83,cc462f94,2607bff2,a1aa32d9,f32e14c2,82232226) -,S(7fcf821e,95d2176d,d088106c,a5bf0855,9980f265,ea3c401a,aca44b0a,d5e8ee10,27c341ae,87e7afee,f8af4598,e8e27cab,c127b054,1b389cfb,266ec9d2,fe400284) -,S(898a39b9,d440ef05,f87e195b,6a334f93,67acd67a,1fc76ca8,316292ea,216a5f1,eb642fbb,fe3274e5,2fd1cae9,744fabfa,c0db80e6,2bd4f7c3,fc2ca43b,18ce52ef) -,S(3ee974a2,8918c216,a962480,1f18bf9a,87d6a627,83323e3c,bf138bf4,3f2192a4,f5b386df,ac71eb35,499d5b2a,960fd20e,fde39fc,10dd5c63,dc50b55b,cd660d9c) -,S(bdd10d2f,de76df34,9ab753ee,d06c1251,9766bbf4,2fb610a5,7ddc3f36,4047c14a,504532ed,34f97eb9,b8b27664,ab440032,2b8b47f6,9c403bbd,6bc74330,16923dec) -,S(2c179437,39784124,4ff9a4a0,eb9ff292,477a5148,c4176b23,c000a1ce,3bedd63d,a367b584,4f9b7b2b,a82fccca,b9a12a8c,2c1ca5f7,3e630173,e37e600f,f2fcfb6) -,S(282ef30e,f2d61d13,6f71e6df,6ee97ebd,a83036a3,2d3cd841,36289798,b3e71580,90b0cd33,c350ea2e,54c25264,7a3fc91f,5b4f9dc3,1f58e86f,c47825dc,e3d0f43a) -,S(a42b4d55,42acfa7c,b54ab3d5,ee0bebd,85bf6ea,db138ef7,1ea38c73,899eff23,17e38880,f10b9927,764c4997,326b0b9f,63d0e03a,fd2f0bd,b1ff3cca,1f566bb7) -,S(b23acc64,c5b00c8f,4b580d47,49589559,a06fcea5,75f3d38b,1a02251e,ff7ef00e,66bb180a,7eaa64d8,4bfe6a17,d457f5e7,73964ac,ff908729,3bc540aa,1cb6464f) -,S(942dce6,96aeb063,4681ce7a,407516e9,89df029c,ecc77023,411a628f,75885ea7,e208be8a,88be7b3f,6b6b06ce,a3aafb45,c439f0ba,d517a784,ba13f80b,707caf14) -,S(b8a6a2b9,52194ec0,8238e4db,e71eb948,23e64a94,e10ea0e1,610465ab,88392d16,f8029f31,b8e5ee3f,77a758ae,343be258,34c7bef4,c1b555c7,4cb63d51,cba5fec1) -,S(a36d3369,a1ee05f7,b1fdb083,ea614cb6,f15feac4,17a416d9,cc83fc2,868fc20,e4abd7f9,fe40f27d,5b7b7651,6a9fd714,aacd2ae0,5f0a1f10,e94327e3,76f0af52) -,S(4ea30108,3d711ae6,ffccc89b,9d6fd4d5,6f03bd68,f4508cc0,ebef5e43,88dda1d,81e9997a,8b1c5949,6554bcf,154166d3,40f9ea5f,ce55ec83,eed793d5,5ca3e513) -,S(20228716,1c1c89c7,64742e62,e427b712,fee118f,406a175e,ce2f424e,2affdc55,7837965e,cf26a7f3,428d2864,41e1d09a,91eaff0c,5ecd2c28,bc817766,67fa35b1) -,S(d3c072fc,8e4bf160,5790d429,61206123,95be9092,f166784c,f5adb7e8,6070d20c,72688262,594c75bb,bb55c0fa,af7991c8,f412e0eb,afd1c0c,f5bcab82,d8daf31a) -,S(294dac7c,e307fa7c,cf0e8f34,28a354d2,94003dbd,ca763dad,3e6df60e,530ec82,479fc222,a7bcaa62,aee807c4,ba6309e6,cfbcc783,afd49ecc,fb9b45f,cf84673d) -,S(3956ca5c,c09fe8d9,e4042a8d,67b276fe,225de609,ea24575c,7075d9ac,4e732fae,1c965fe7,a8219052,9d25ee0c,e1fd62f3,7196431d,7bd78302,e287a26a,2eeaa23e) -,S(24d2e396,da144b48,e736eb06,84940175,4f4109d6,6d87a9e6,97ee82bf,91fb3def,bb79e772,24b02fcf,dd1e3c9c,edbad212,ea875c75,1fe7c81e,76d7d0d9,a372236e) -,S(638d4042,f16e5c07,fcbf9619,dd9c2f91,18852889,3e12cd3a,b49e2b9b,99a2aa5e,d0d97842,4f0010a4,df9eb8b,8e5d8147,f618da43,74b8a4db,222e4ab2,b32b3d92) -,S(f91ad5b,a99972ba,bb323a1f,d3032e1d,94202d88,63680c5c,d7d67828,8f0d866c,60b66d45,a693175a,3a38bb4f,efb32dac,1cb558e1,b0d13571,e24a14d5,9452bdc0) -,S(3154137d,779c25f1,4ff1fb88,a6d0370b,9e6af48d,88e7fc39,c6417272,eaa69b7c,eb3bd91e,9c09178a,398e112a,9264484e,c1980c19,b1993b13,560d39fb,92295f7a) -,S(f8821e1f,dfdf9fc8,1e3acb3c,1d1d7a65,f710be2d,94a19355,721cb93,61549597,bb507868,c1e05282,51b635b9,dcf28e5a,c5770c05,c7afc2a3,f4b4c45b,7d8993ec) -,S(8409463a,521404a5,a2d8aa90,50e3ad8,ec5d6faf,870333b0,6dd4f63e,8354a655,cc99452b,85092ca5,39cc1b66,83b7ab37,1b8a6525,269a1ecf,91b857be,e1db3bd4) -,S(96802411,12d370b5,6da22eb5,35745d9e,314380e5,68229e09,f7241066,3bc471,ddac2d37,7f03c201,ffa0419d,6596d103,27d6c703,13bb492f,f495f946,285d8f38) -,S(9d1abaec,9f5715a1,5c762824,4170951e,f85e87f,68ca5393,d3f9fc3f,a23a69c8,f21ee700,50dbb61c,238c89e6,29423538,71b010e7,98867bdd,149ad28b,3f28cadf) -,S(1fb96691,8db3af46,c37234b6,a4b04371,9886d6a0,5859ba32,f72742d6,141f7ae6,8bc13ecc,207efd91,f7f4c442,6e9a425a,a17b5578,20404eca,b09d5582,d41f7379) -,S(22d9e364,b9274dab,98bcb23,e0428e8a,416d54f0,5a781281,ee221db6,9e1ec7b8,5dc23258,f93d7db5,e5799195,b74e9519,4c300a91,28f924c1,c1e4865e,2d8407d) -,S(625fa450,aed083fb,30166766,d5874131,adb168c0,247cbff8,3987297b,f873e45d,720a8104,473dc904,65585ed2,1a0244f0,fbb5a286,5b8e5117,5a21f644,8776bb7b) -,S(24acb1c1,9b6dfc25,defb01c2,e2681ae8,2deacc0f,f21ae8ff,1f82f37,a6a2147f,f729d335,210e8061,8a8abdcd,b71aabe1,93f50ada,dfaf7d52,783991dd,d3ca5d4b) -,S(d2856803,a99d30d4,f3a328e3,bbf7db3b,6c6d1896,ba5b339f,33c1302c,f75ab555,9649994d,64705b87,62c98bbf,1b41b725,2b814a89,3e780fdf,5689c9da,692d6ff) -,S(80529e65,9d196884,b15e95ef,871e5fd8,8fb5298f,3bc7831b,50a0bc98,4cb5fe0a,868b3e4f,9ae4bea8,efde50bf,c5a5b268,b74b4a8,74e86de6,e9ae476f,10b3b778) -,S(7f9199aa,3b8201ed,5d288e49,49c43277,e0bb316,953f1dde,d0674d7e,8728e183,1aba673,d0372029,546c174a,3a72268c,ee9d7e41,dd97de2f,fcbe1f9f,1a5288b9) -,S(7d32c885,8e959f6,48c4674c,dcccb191,29b4566d,644d2fb7,6d0c8966,2c29ecbc,d90e94ec,b50bfee8,c951afb8,e65c7386,875ea99e,31f553e8,66e00342,6d39698) -,S(f2b961c0,9291ecc8,576ce67e,bbd1bf01,1f1727ff,ad9eb74c,bf8819e3,2d1abfbf,ebfe5849,5a1e6a36,46c38220,8656f638,ed0aec0a,d40c0524,1707102,3126f795) -,S(d9a0c689,95283291,972d6a72,897181b2,6b4ae317,4e98a676,f75bbfbf,81be876e,d36ae886,a0acbc9a,d1564d97,4d3f0309,e9039b93,bb350d92,2b7f8c7a,c6bfa042) -,S(c7a36324,6aeb7c8c,991b2aa7,10abdf5c,fff29912,30b3a69f,be2dd481,7c7c3e0a,1298fdd7,e448d2d,79986302,6b4b2d49,2b32148,d6d1e5f8,15f5b0c0,5c9e21f) -#endif -#if WINDOW_G > 11 -,S(635cd7a0,5064d3bc,66535a0,4dbf563a,640d2464,c7fe0ac4,8304214f,e4985a86,e40265,913e77f6,46735cfc,af9e2f30,e8d5f047,f3281a4c,e0453e27,e9e3ae1f) -,S(5da624f,38edea25,37f5b632,695b481a,eca54bb7,2169cadc,c5b91e10,989ee5f5,d3ea6dba,a1080300,fffaeeb2,43a5256e,48c28822,37b16505,a220d771,ca721779) -,S(aa4f64a2,b19775ec,92c1f687,1fe4b6d5,ce05278c,2976c80e,fe19284f,e87d4d5e,f39f117e,95fce0fb,6976e949,9583a66c,224ea028,8396518e,293793dc,3ed4f240) -,S(9b6518ea,99ff1b42,22a93f26,62e05551,d60969ec,ebe378c1,477b5c36,427e0641,2e9f1655,8650fb3b,43aea9dd,30532ff9,bebdf7c5,1d421656,27b7487d,8f93165a) -,S(6c9b9aa2,b5972e0f,a1e01138,1ddcbeb8,6547f47f,fb101159,4b193d00,ae97b562,af09d91c,8d4c71d2,be523d0f,9d205bda,a6e78eb2,67476d3b,1624a038,6275e27d) -,S(a2a1c880,3cdc95c5,5e636541,c7112a0,cf80aec6,a37e5f71,f5366612,db467cbe,c4cf570f,3638f040,ffe5410d,50d4b175,802e2e1a,c422fc2,73eb9b2d,4e23fc09) -,S(63d3750,c961ccd6,34a5af10,48897366,13102bae,20f2c8a9,ca8437e5,ab650427,87415332,74b39a76,72de90dc,698742a1,f21125f0,71393fa0,6d670045,8e339248) -,S(8d070e66,e4428255,a53e8fb,5845d14c,bcc97dbf,19b6930e,1f5160b2,52bdd04a,4bc98c82,4f2b4f04,c9884099,f173cd22,48cdef90,ceef4bb2,497da8dd,99487ecd) -,S(f1fe56a7,2e5f008b,b5014395,cc1658f,e3f3d4df,7b361456,175bfd2b,4a91c8bd,be5ffebe,e57a7da5,d01e302a,d3688567,a19caa5f,fe8a57b2,be2c866e,f5f275f2) -,S(802c9adb,d2eb969e,9ba71a95,675bcc7,b412399d,5aecd635,7476a1fe,73554b21,42132026,f547ce69,66e6527d,370f9c0e,cc3344c9,be1047ef,b7422e13,6772bc5e) -,S(95b1b6c0,9d6ced22,f0a5cd,abc7a594,9d24cda4,f178a745,c718204b,1493db56,bc143681,53033d16,ac8ce5e9,a6cf240d,27b2331d,36cb23dd,f69009d4,b6adb01d) -,S(eaed529,1f94eae,183b2aa4,e17022f1,7b79a06e,d76b169d,2d6483a6,a6ede35d,53d5b276,91c5899c,ddac1efa,3ad6baf0,bc6e377c,99ac7f8f,9cb27fb9,5dd559b3) -,S(77c44fe5,9f6f448c,72eb485b,6ef3f7f3,906d690e,367beabe,ac7b7359,9c27d770,bcd75022,6c440f80,2ccf0360,4e3d6b38,e6629c9f,facc49d3,83322eeb,fb1102fd) -,S(e863b2e2,f00f0a46,b6752002,cd936a88,11b6279,5411944e,fadae5fb,e40a0306,b5c79ba3,6da29f17,5b9caff,631e8ead,c2ed937d,66008358,b36fe044,67243a5f) -,S(226f5bef,93df71d0,b2feedda,4ada3098,3883adb4,f3dcedec,2721e72e,eef8f191,a09204b5,2bcebc14,8a0a08fb,e8458618,f966078b,d75ccfbc,c13233ce,741707c3) -,S(aa222fb0,8c1e7c53,9f3a82b3,9c6f08de,c33beda4,aff7c46e,3a4e9036,83467184,41105cf,21cafd39,821a7c3a,a6dff931,c1653d29,906b5d4a,c5dd6431,7c1c3765) -,S(1879c2cd,26ef4ed3,dc5220bb,397b1501,f94482cc,1236da82,239754f1,e1fec96a,912d5f35,75eade14,91fb1609,21d63042,4fc68951,cb73d351,464725b7,71f0d67d) -,S(be39e4a4,e7eed88b,f4a4cfc5,970d4b7e,6df6211e,bdc2bb76,7657ecb1,ac9902e0,d8b1e4f1,13fca7b7,6306d9a2,b4cf5a49,32ae54a4,5615c899,f94cc476,7e27cb4e) -,S(1ea72fce,33378c3d,d0302836,86c3f8a8,1c2912e4,7cf44631,d3fbdc2f,752d5786,e20f4558,fe1cdd14,ccff261a,fe506b78,cb6e2b0,807fc7c9,aed0b888,3748906e) -,S(56e33dd,67bff57d,e8c638e6,f32bc396,2d0ca011,b74db242,3ac662fa,da036806,4039c0cc,165e7130,9317d4e,41de57bf,50d78ecf,3e14ee2e,fbb3b93f,c393f461) -,S(51981691,a5f1d8df,1cafb95a,738b9e3e,d036ce54,f10a7447,c470cc2,e80f37ad,9fb9047,67cf2a99,766e3c2,6e97f045,d03fabdc,471ef664,d31aa662,c5972261) -,S(ef3a5685,77a59783,6b0be7f9,5f927996,b90db9b9,bcd57f30,16ec5979,98869dbd,51cfe457,ff22749e,949782c6,ae1f4783,fabe1136,4bb524d3,72ac3d8c,1b7c5e07) -,S(efc652a1,8c3a85ba,7ee9e0b1,6e3c6433,79a66882,5304a22,523c060d,af196415,8a656c14,cef91af3,1db2498,f5987083,8fcee71c,98c09d49,737447b3,54f7b2a5) -,S(cdda1fef,f4d5ce2c,d9802198,389880f1,8adc7962,c04a95de,f07370a1,884bbf82,8bc26ffc,b0c9dc05,d799174b,4a478162,4417f9ab,8536235a,e55c9b0,49e31d6c) -,S(6f3f3985,3454aa13,134b76d7,77dedd40,d46bb6ac,dc3a3a3f,93886847,b96cf0d4,a8ba499c,4f7ca1b5,ae7e5192,ea408344,b6e32491,e5649637,e4eec5c9,2cadba81) -,S(e52d11af,91abfb83,ea842065,ed8d804f,a2a3627d,85149ee8,61cd5df,e54b13e4,59f3106d,619e5672,cb21f6ed,4e73285d,2e132a3d,e3ed069,46838e12,a9cfff97) -,S(89fec736,f0de1cb6,45654d13,b32b3cab,8fb91869,c30e2ac0,66c0cfa3,9e7256ff,f9417ae8,4d3e1a6d,b6ab938d,9dfde62d,73e708db,b58f5ded,46b455ae,7e44274) -,S(5140f56,91b10553,ce86ce73,3028749f,52261520,a8903f75,31bdac09,22b70b29,91a1962b,9e02c23d,61f4ce,21c0ce90,ad0acf0b,fa250afd,dd67d72,aa2dc024) -,S(3c16130,93109917,1075e199,ed32f94b,579d0eb,85520d09,c0f90fc8,7d267b5c,d50d04df,e4040db9,3aa0010,7693ac01,e9f156ca,5e800e51,a5f7d36b,78ac64c3) -,S(fd87690e,63a50237,258b8a58,f0240552,a2d0b952,911d1fa8,be13eeb8,9be8bac9,406dc1ac,ccb968f5,6fa3ee35,247fc66b,b40f04e3,ac512474,58e4fea4,8a1b9225) -,S(8e4d1de,17e78f3,2ce8ad59,973b328e,99005ce0,6a8d9347,ebc7434b,d5a12a81,c6348f3e,744ca65d,744c843b,4bbf0d8a,992bafa8,8c31b6da,42919401,b1a2a8ae) -,S(382c7bcf,ea62c678,173b6eeb,ba58caaa,f4988104,1677bff6,ea739a0c,6c7743c2,190a5da,77e64243,53df7f27,e01c0f6a,67e9addc,afcd3523,7cf5539a,69c5eb7d) -,S(f56a8b4e,74b84807,539fa471,bea50795,25b0dac9,53bf5d29,e87d90d5,f914ed0f,5456d908,da57e612,3ab881c6,56a6ea24,8f9f201c,13915a48,c50151fb,c096db8b) -,S(908e9ffb,6a5e557a,1fef8ea2,b16b80c4,3af3652c,55f12a04,4ecfdb06,17965b80,beae28c9,d1b14cf0,f8182ca0,7ebc3137,b9c01094,ed6b6043,562de75a,878bc2ce) -,S(a6c30718,433381fd,16b22533,52934eb,3fad254b,99d41e78,7ef2e6e9,bec86ef4,47a9a286,a60d5102,4d129e4,e0309c72,9e266f82,5ee26f4,4bf90057,623fb818) -,S(948bad86,6c3e2c26,2d46163,52be20ae,30a652e3,4a299361,4766eb7,98b3e903,30d30622,ad478a2b,99c43b0f,915de0c,4321da4a,76a18d33,95b4c484,d9c35164) -,S(d6c92b9d,cb8a17ae,77788125,18782d36,9d536edc,f96d2c9f,c9e84d2,1cf6a3f2,dd9367a0,93518377,97b0ae88,1aec5d4b,ed68624,8ec2207b,9e0104af,2ade09b9) -,S(f9ff3d7b,7d8b13d6,46c641ca,64df802f,7b082209,a75ae328,54cef0fd,65566abd,ac58619e,1f192095,f7223022,43d811d1,b9269d28,a18711c8,c84e5960,32deec98) -,S(3dae1dba,3a70e0f7,209a920,42837ed5,7f4e767f,834d14e1,c3528f6e,92c8d5e0,7ae2468d,6ea1f2cf,e1fcdfad,3ffe87c9,5c7816d9,ea99332e,8b4d055,280f797f) -,S(27045105,6fcc937c,9cbffe13,f2aaeb0,8ffd227e,dbbc7ca,d0b4b01d,19b49937,11766a54,6c24fdfe,220d3724,661d6c75,bbd801f5,c4286ad4,d08a698f,1ffa4397) -,S(f9d95ff9,6c3260ee,cd434075,262fba81,2024c556,649c4865,bb90d65e,20defd22,37cbf7fd,8f741411,80a632ba,8304730b,a89d54a,1a5b1dda,24b026bc,17a13c2d) -,S(4e8df18,f90f67e9,fed8c6d5,b66cfbe6,ff0a86bb,db990214,48ab57c5,c5a7021f,7e69f8c5,ccf56413,453a2b1b,3b34843c,e9badfd,3a83729e,a2293fda,f2a621f5) -,S(8c2a4d2a,710a7fb2,1ba78383,63c66458,ab3d32bd,3be35821,c8a5b779,d2ffef9f,d532447d,27e42583,46171515,71bd6577,f82d8f91,ff39d205,caa5aac6,365511d6) -,S(28b7f3a0,19749cce,6fc677af,a8fae72e,c10e811e,d4b04e19,63143cef,87654b75,30471eb,3245ab39,1597c881,e71f4a1d,e241ba31,a678fe39,2ced5a63,845ec782) -,S(cb474d0f,fcb8e72c,257b5acb,999ec8e,d89f6494,cf4b008,8f6d7db,59be416b,ff7cd0ce,fc293cbb,8ab9a950,8759f856,9a0e59b3,effc00c7,e3a3051a,a16622fd) -,S(c33e6982,5dbebc40,265567fb,ede2a4a5,1a180034,2e9963f5,bd57b35f,4055b36c,22ff3ff5,7ce265ce,253b5061,599ab066,82c0cb5,91a51e0d,b798ec2c,c546be18) -,S(84bfc106,44d37123,71a441a8,4444a9ab,257e0745,b3d0ca0e,ee341838,19bd2237,7cbe56d5,7b7af706,c33d13ff,b3e4197b,afd7f421,1ece235a,e1c2187b,289ef6f1) -,S(9c312ec,d53b244e,fd40f003,f7e0835f,6063028a,5b0488dc,73599653,f97b713a,11bcbd0f,58fc77ef,854d0b16,188b4e8,59698ba5,fee41fe6,165449b1,4eb76d14) -,S(5c06af59,a22d6f2d,cd83bf4,e3bbcf21,d474f61a,e01d0433,2d0a82dc,af15cefc,476b4be9,f1c265fd,a8c6d70d,6c669aaf,41fbefb1,425e2be2,9048165a,4322aae8) -,S(777259c6,81a3ed43,b4c0eb54,7af39ebb,f44f0d71,c84602bf,2d6d45b3,f1b6bdcf,8a9d3753,5481858a,eec44851,4c834667,d6742b9c,f563ebba,22fde187,fb3bf754) -,S(b370601e,ae1fc1d3,14e4328b,4d0244de,174b8c4,766283c,e3820c50,41266842,8ef05079,2174c3b0,752a9abc,8d980ee3,eda7b5aa,4042a932,3e136834,bc125ac0) -,S(5af94ac0,7f8d6492,a472ad40,67097206,78086856,b01528bf,8248ac8e,dafe6584,8a54c7ce,57eade51,1d5f32ef,cef5f56c,b40dffd7,8cfe5655,2a9c3966,e62daf1a) -,S(8fe3c19c,e2e87055,385d4f23,c5832f37,4f84b41f,3f945945,81acb8e7,5b0586c6,f923099f,d16f44c3,a4314d49,1af193c9,2f5e2017,156f860,674f5ac,91728c28) -,S(d580961d,2642bd1e,5f9211b3,9b65eb5,e531d17f,a37bafc3,b5f288fc,13ac9a71,500c0554,337e8b43,36e50a6e,b12fa86,d9678cdc,5b38f650,e4f897e9,1b4185cb) -,S(255dced,529fa623,49e46033,86790c32,234e7967,5a9c5405,256cfbf1,4295e82b,7eeda9c4,7f3e1c7b,fc3253d3,faa46317,5dfba7cd,94f6cb10,c8f4b4a,7d799815) -,S(4b7ebfa7,9240451f,ab8476a4,ae48e55f,1a27c338,a8dd8458,bdbe422,ec891557,dfb260e9,f89135f6,fca23cf,ad7ed812,c12622d7,e4285284,8c63d83e,85b59085) -,S(919d0780,9e6092a9,a3b5819e,c67719d,3119569d,3bd14c7d,8f47f555,1f2fbf28,ca0b6af8,76d70f2c,ecbb2fa5,98d6118,c204d3d4,a30e24fd,cbcaf283,843d8094) -,S(466867a9,de89a944,5bed73bd,5ae342a4,9b8c896b,59eebf42,393dd536,8c70ee78,2a5d9707,b3e15823,79bd6ca,e8b7ed09,9cbb9f93,4ee96029,385d5678,aae042e1) -,S(71274d08,c8784517,8921526f,cf71258d,fc740d5b,be655f3c,d985cba2,c1db3f7b,e0af0130,a5be1434,f8d652bc,4406177b,3cdd2ca6,6abe7f56,d848def,fb4b25e0) -,S(a46e9048,2d25241d,13c693c1,f4e6068f,b6e8256d,1fb3111f,a0ae0e37,7ebe2bcd,7567700c,f22aab69,8126e7ac,961726ad,fdd708bf,d5ae5111,40f921be,94474eda) -,S(f7590b91,f2431126,85873b0f,77be6851,10ea918b,a26d3b5b,aec02bfa,a5e84abd,481848f8,594c94d0,c9b5d6cc,858dcbc8,2d25128d,5ea28e2e,ded935a4,62708999) -,S(2d7aa8e5,1282e1da,dad39d64,398f0790,4f966edf,aff5e3bc,9a22edde,428c2edf,12b2133c,42032099,eb33ea24,f1755f9d,a30b4da1,708cdfb5,7635b61a,335d9d79) -,S(91313f40,3302c47f,d9f113a5,581f135c,82280927,5f658607,99550fa9,7236d0e3,f8b6ec07,5e7804bf,461daee9,1f21285b,aa9e96c2,2e0cff27,c323f627,90838a77) -,S(da248119,9d385a7,8468e86e,1b146fbd,e0be031c,3a19d0de,2f44a1d5,6c6743cb,c07c897b,5f76f6ee,f2c62511,19b37c47,5d418b6,1d2cda66,6d39ef67,40348cbf) -,S(95e36a24,b1bc2e3,fb5e6082,de9ed432,760ec3f9,6f01dbd6,2e820268,dde82220,be6990d7,3abc4a3a,8f03b209,dcb4202b,52a74a87,1e1e3d01,7665e9d1,1ce1cb63) -,S(8b05b060,3abd75b0,c57489e4,51f811e1,afe54a87,15045cdf,4888333f,3ebc6e8b,1d10f881,45db40fb,889e2ddc,e81bda7c,27f5b615,acd6179d,bb30f4fe,7f40fb39) -,S(ffabca3b,764a327a,750bbb2b,a1cb8329,d43ec0b7,dcd8f728,55a9d30c,f3020f54,93970a65,c90ba260,5b2fb393,a4e994b4,c791965c,b60a1302,cf585443,6dd0f05a) -,S(b3a85aef,ef35e4a9,8f0f05fa,9752998a,d3514868,b133e7c0,a18fb053,b866c72,30115ee1,c21e5b9e,3d6b36c,54e700e8,9ee78c7,e88a2752,38f46d1f,5b6005e2) -,S(a4f1fd5f,4c233cf2,b9c5659,f666d51,5b78fc32,ebcb52d5,d155250c,c95b7ab5,91d19f85,726a1258,444419fe,c5219c7,33754325,89d92d52,c363d61c,81faa0da) -,S(97b84b4b,7baecf13,94bf3923,2b58b5ed,9eb14637,d29b3c98,bec3e624,15bbb0a,497db4af,be8e7b3a,13493d73,ca92b4b6,5eac7f30,d86dbbf4,8b86f495,2d162435) -,S(2ceba0d9,203e3666,75e78e96,51b5b57b,a9de5f82,3cc8569a,1c274d19,946312b3,d4c2fe86,f042cfde,41f0a88a,6d77c188,b7805db6,c6ab440a,488a75c3,8ed2b437) -,S(ab8b1930,6cddaca2,8be57b78,b4836998,912391cb,c6a41e10,e91b86a2,3f2b7009,fdbbabdc,79fba1ae,9d8472a1,7a648206,7abed651,36892a03,35128650,374172cf) -,S(2763029,1ff140b1,57eac2b5,9938f26b,c149705d,aa2dacd,6bb0d305,1a15b394,c2b6b32a,38dcb9e2,f4640838,c52f5ca0,55359479,86ecd875,a91504ac,49374ee6) -,S(22d1edbd,1cc1514c,7f91d793,3e9dd124,9e703fd0,8c65ed8e,6cc79eb5,cafc78c5,7453e7ee,a53ae741,13024fca,208a3816,a93942c1,2378ff7a,5e65678,c0a85efe) -,S(70d869c0,c5729e94,270fa559,bdb3fb8,b6146527,5ecedb7c,c8e7c9bd,acffe222,4bfcad32,8ce78fb4,617baec8,48c2c3a8,f8d41474,9c131657,115dcbb8,f6ec30c5) -,S(a25b45de,da8d5782,64f60dcc,da97bd28,ed9039c0,6bb7c97d,d4a24eb8,791b1647,8fd84983,fd2ad956,32376555,4c43a664,f306f11e,2f030c7d,fe1c68d8,aa43db8f) -,S(823fcd6c,9b237c0d,5aa38336,6737066f,3e77fa14,b975a5cf,39ca8a74,3b1024b8,e691a44d,29a4f2dd,e99c2ba3,bb6d4345,d1433e4b,d1c65d72,198f16b5,4424dde0) -,S(39a5a63,8244aef6,432b1247,d394d305,ee594bd2,6ed2433a,3a96c4ce,5a158d0c,147ced39,dd8b8494,d57ff37e,a24cb108,ee4b9f43,50c556cd,32df8b27,626a8023) -,S(8f9febb5,b85bb2dc,74aaf7b,81b27796,2a18f6bb,4879f5f8,de94aa56,b3206487,48daebd6,d4175a00,e37dbde,c2b57b3d,dc7474f2,ab6a093c,32a86acb,f610c2a2) -,S(fc16fb14,2f500856,4509158a,5f6b4e35,6a08db53,36e9d3f8,4f7a03d,9143f60c,8e9326f2,7e02b73a,10f4ada5,9db85fe7,4027584e,6b32aeaf,58bcf804,dc1f7a36) -,S(7db09ea7,17446f6e,9115d8f0,987eba83,eaecae01,f4201d78,8e292486,85c5a281,b4469cee,426d455d,f736b2ad,c12fd17e,79fd2167,c5a6f864,2733e327,c215742b) -,S(d45d1bf5,28baef1c,3ea56fda,b1f8d3c6,3df7caf5,c7ecb0b8,564fbc94,a4d9a57e,91e26984,64830e89,1cd21d3d,81ad7000,ad0c84d1,3c05a191,c1a172e1,16aeccc1) -,S(3faf0b75,1b6f85d8,550a9ffa,a7a26bb1,6a4d9c99,ae97678a,d43a1a91,75f03901,8a5d062a,a4e43cf6,5caaa39f,6386311c,be775d14,3b8d9368,b555c436,1844328f) -,S(54608cbe,8e08a472,79cc5e39,c65e1ec0,1eefdba3,3b127107,4926b06c,76efd121,a7695bc,40def81e,48ec5f91,cc98fc2b,9bdc2776,71d05afd,cb789e20,c540f038) -,S(559a0d89,50dfcd4,364e6955,23b56972,e8a201da,4e196d46,64dd580d,909823ec,7bf8e1ad,d6528b90,cedb8d5c,87f5953,5641e32b,6a6a7b4,c46e8052,e8dc71c3) -,S(166e8858,b5e2b9f2,b1648c34,41e5fc28,bb305ea9,b0679c3,1a996b94,acf467a8,9c9b306d,ff82fb42,acd8a6b9,108f9994,dc1b7c37,dd0c9d2a,f64205a3,92e5bdb2) -,S(40e29e8c,e66e83ba,a94ec5fc,3ae438ee,e5284f94,c5efe5a8,d41da738,38fe1941,7c71f71c,c01e7868,1cf154e2,73a23d0b,84ae684f,b0e709c3,9551884d,39acb2dc) -,S(6829c8f9,eb659ce6,7f87fc76,4661b400,6aeb8b3d,bf674408,1a844380,72d4ee7e,1d35530a,8332dc05,54e82522,5e9ff30b,6647fcb3,304fd908,ea506945,ca22913b) -,S(4a3fe05a,322e9fd3,93393b13,6e2af237,e25a2540,42d10e7a,dbb35d41,13658196,859a41f8,d4527641,a93c40d9,ef0ab175,78dbdc45,7edeaea1,f147018c,7901574c) -,S(de5817c9,a675eb2e,c1567ad5,a6467cc2,9e9ddec2,177f382,25a5e101,9aa44f94,4050ebd0,5413311c,df17e625,6d4bf102,71b45e17,4c8fcaf5,ec36567a,ccf723a4) -,S(fde29245,4f07f411,abdf1a2,6f3d8f38,daa7b9b3,1b51fe7a,155da5eb,5662a108,f2a4e6d3,7b39e929,ccf347a3,ac6c719f,f09d1756,e407371e,d98dfdc8,b727808a) -,S(f28d3cfb,6eb98ba1,76fc536d,6a772861,b0917415,d08c22e8,a43a90ed,eff42436,4508be2b,b328250d,e043dc82,d8894aa4,1971fe8c,42e6cb61,e9d02735,1279d1bf) -,S(c7655c30,4d1cb5b7,d0992afb,119a6df7,7bb65496,420f78c7,117b951,7f16e3ee,898162c2,cdb730dc,4b986b1c,b0de79c1,a348b0be,51b9070d,2e427e2d,e71dfdfd) -,S(e57d97c7,2fa3ee66,71d67936,eb62f4d8,53ffba74,f2158d0d,7ae3eca0,7b4b147,b1e3012c,a3d92975,91ab80b9,a668ca13,1ed42660,47c34958,c07c720f,e1fecd64) -,S(eada8642,155025bf,c0644f92,fe014ccb,6cd3d37b,76686a44,bccdf8c1,e22b0c01,89035d7d,71d71bb0,117c37c5,540f82a5,7152aac,af79fe91,6aed7d2,9dfeeed) -,S(3e76267e,3f172198,9f9d7e8e,11fa3ff,62dbf8f9,77503e27,5567ec84,e60d0e25,a1835790,9631c6db,a453001e,c7e3973a,416f8bc7,e2fe0871,82d8a236,6e1160b6) -,S(a11d97d8,9c262f35,2279e69,2d66be7e,5de7235,18e6750c,6972d250,91a3df70,d18df8a3,dd6fb016,df2e48fe,ab889165,44768d77,e9488b71,fd31c6db,d52a69dd) -,S(b16e3f75,cefec06e,edd54bf8,dae7cc29,a5ab5208,fd58d787,922f4221,f5f20651,57fbfeb4,5a6e32ed,74fc1989,16909891,233ae90,c539b81d,a758761a,a6d0eb2d) -,S(37de800a,3f73ea6e,9eb564c2,faf147a4,837339b3,44a33d9f,beb25784,c74628b2,59339259,9da55803,196b7e5,3596aad7,e33fc96c,fa2ae0a0,2f41ec13,e6254050) -,S(6f68412d,65b3abaf,6fcb781d,8b6e6baa,4ae57fb0,9325a1f1,9beec438,cbd68055,884fd59d,406171bc,b31042,21abb5d,27dc1433,ef49af08,ec031543,2f8d3bcc) -,S(91479a9e,6bc5e261,24cf0ce2,b52f070f,980f1f9a,f60bca79,572902d6,cb6e4366,2304f70a,22de4435,99f6025d,4b13be27,47932524,112f64a,ef935d1a,9c2f5288) -,S(8ba6b0df,36ac8708,8c1e7c1e,4177dcc9,4cceabc7,4a6c7701,8358c194,4d19bd8a,e96b720e,e9d515e2,922abe8a,177ac755,989dff1b,789a85ba,ad17f859,62ab9ed4) -,S(ab152195,871f3fcc,58f59a8c,a35514f0,f11b8a69,54e4ec9e,f4aacb7b,29d567cc,c1ddad48,623ebda1,42899ad1,75f88ff1,965ec1ca,651b419c,3c8ea037,f267fb4) -,S(7eb23f48,5eb92bd0,1c0e6448,e19adc22,6ca45c46,d4d5c756,e552ce7d,551600c5,953e9b12,4278b939,7b3de07,63e30c55,a300ef97,a8587328,b3dc27b1,a7c57ac5) -,S(b23f4c2b,a4b2700d,c7520a92,25890491,e0212fb7,eeb1f0a,2f624905,4e21ee17,a38b6772,9e95b3af,2cc7d5a5,c10386c2,8a2c287e,6349f811,457ae0dd,8b598530) -,S(85d2e723,387e55b6,a2c1a02b,96cfad64,67a6c12e,b75424a9,a10ab77,2769c2a4,727abdac,223898af,1b077fb,7d481434,ded380cf,21a131d0,db845150,c8e4d303) -,S(27c1715e,8dba4cc,41383d59,e669f66a,54ae6901,88a794be,9fd8da6c,9b09273d,2767ca54,306e6ca2,3517d884,1e7f30f3,e16e22c5,cf2bbf9d,998d5cd4,b5b1a266) -,S(e70b8cd3,7f9a5e8e,9e0c4fb5,6f85a6ab,42cf4042,4080350f,4465cf8b,95eed89,2e3d8c58,94788d1b,9734e93c,7508cad,faacdf06,319854fe,5ec4b0fe,6b0cb31a) -,S(e23dd455,24058396,98c81a39,f3f076ae,93932c61,d0e7f65e,e2c2013c,dde956b9,6c53cbd0,cd8ab8,bf5cef85,a8aa0b64,52b57e79,cb53315b,1dcdb68b,78cf77c9) -,S(5e923f81,ccc49813,11a09f2c,47677cbb,9aaf0832,10c683b7,d7a07399,4d919c9f,604d7112,e64cad06,fe0e64a8,af7054fe,7059667c,fb5159f7,738b97f4,38306873) -,S(23d9f253,1a9fa278,e02b71d7,113fde6b,1380e543,633286a5,60037ab7,70142507,55dc8247,b6eb6119,a6ef49f6,bb4e85e3,a9fd201,4f696564,42d3372b,fe44a9ac) -,S(eeb23095,ad2551ef,15dbb281,5ef6d252,886c79ef,12c7318a,50f5d89,d73b8f24,d1a71b94,b9810ce8,eb0c3896,3e7cfb90,56a80f82,9d384eac,67d9859b,11ba1ddb) -,S(64a6de7b,57bdf7e2,54beee53,6efeea9b,899a8436,e421e3c0,e7a2682b,54b7c21b,6427936e,2e344fca,c402e2d,2902fc6f,181ad190,e3f0d537,cf40c96f,27b4755b) -,S(9e4676ce,d76daf3f,1c1aad5e,51e700b8,8207fd45,3cec846d,779f02c2,cc270073,5685c781,1d7610ad,4655019,5d8a844b,6ffc4acc,eb458c38,d9d74f4b,cbdc9e42) -,S(95ee1228,80616ba1,76e0ee23,14428c7b,1d83c635,6ec843e5,d134b359,8d645473,7be34c64,41914c07,58081278,9b254c71,49a60d13,c6ee3a3,7d12e29e,a3bf4054) -,S(e53ffeef,d92081a2,f91df506,6453cbdf,d0b1089a,c598da9,94fe4c03,fc6516ad,560f02c1,4a600d02,a2e70b28,5164618f,5dcd1b67,ac071929,ecc1d891,e4c59c2f) -,S(9c332744,7c75488c,5a14f1ad,fa3d9974,90d4eb10,63afba83,fafcc3ea,62a7b68,9cc759fb,9a7fc3b,4d0ff7d2,24d0cc54,cacfb78f,5590eb8a,d689b6ee,19791c63) -,S(e826d500,2f4315ff,77eb22b0,c8b74142,f1d1037e,81e3c58e,4ea39430,973d3c45,3a466e58,82f971f4,3ab9316d,fc7d53a4,e8ab16e0,2ae75045,5d8d1999,bc8b65de) -,S(ced4df0e,af93b5c4,8dcf196c,6e9b16bc,dd38a87b,3fd67512,d387b388,115e13c7,fe08a63b,dd149dca,b4f2c930,99cd11e1,8c754271,cedd597e,910462c6,d68b74cc) -,S(b056ed27,88ea50df,2b220182,df38f54f,8065e36d,e0218b27,ee8c5416,db7eb33d,97338375,cef457f9,ebe43aa8,28e9a1e9,8d514d9f,fc300a6b,a1a83db,dacf6409) -,S(35dec74,2fef94a,7fe60b66,7341f6a3,eba030c0,4061d156,1c9ee288,5b7830df,2599121,39c810fd,e7f02fe6,eb6e9221,3eb8be6e,4d8f045c,aba1f058,789b933e) -,S(3f23cc8,7733213f,d2e15cb9,942af44f,d7981e97,37c5af1f,81addfb,324e020b,24e8ccc0,d43ccde3,4e392455,dcdec100,7ffc0c61,3b5f865a,c8afc051,756e8f83) -,S(9ba96c76,c0805cea,d7ecfa43,dba0d86f,c8471dcc,8bce9bc1,e06537ef,2bbabbdb,c1a3c433,1c2ae04d,be2f8e3a,8f4f07b1,622d9820,607ee3ae,e93bc37,f943def3) -,S(83c1479a,31475395,8d510396,5decc9ce,1d414f41,610e2ac5,c2e887d7,d16a3815,84d4d018,1354cd46,e5f39bbf,f9fffbba,c123d470,d07c292c,7f085740,289b5b7a) -,S(bacf627a,2db11d88,76e6714a,2857db8,a8d7010d,7b349ab1,fcb5ebc7,efe0a32d,a287dc0d,a44c448e,68b777b7,36ace20a,14b3e586,bab7ef5e,d57ae303,e8c83129) -,S(73063c55,30129f79,10bfd2d3,a0147167,4ca888d1,d64d24d4,619c5cff,2776ebd7,d57941d9,44ccf8c8,2fab0362,b14986c5,9d71906c,d28584ea,368c4bb2,2c159489) -,S(4ee8632,df55ad15,12ba4ce3,4ddb403e,a3f51a12,d445a011,4d08a00b,3b5d6637,c29f7199,dc30275a,39ff01a3,19723d19,91687901,9616fd81,88ae6c45,92b14820) -,S(fc46e66d,68bbd41f,98b18a16,a23efaca,8f5345ef,b567786c,cd42afe7,d7e7ef28,8b42a2df,abf8849d,53daf38a,4a4c28b9,a0238231,ec8f69d5,d702715,a643c18a) -,S(a71ad1b0,158d7978,7eece5e,2a3907b1,3f9b6b98,aefc7963,8a9de618,b3a7dc13,6fd7e86d,a956c464,e538a864,41b9b7d2,ccfc5c44,e80a66ea,4375e6a1,ef08bf90) -,S(602185f3,6075a67f,d7bb9957,60c6af59,61a7c553,d51d828d,ed37768,f1860a3a,90d312db,706b835e,647a027c,e7a89d39,2265cd4,dd52e802,165c32bd,4d10b2e7) -,S(db0fca83,76729191,b9d9976d,37dc62c3,36b4437f,943706b5,98e7b7df,607a77ca,23dedd6e,8eba7ebf,e0c9f0b3,2a1802fa,78699a68,99507dd9,c4f4841d,82efc29d) -,S(6919b861,598d4f09,2a159909,fff8de82,237d0aec,339d884,7618f257,a4a54939,ab9f82fe,1fa53aa3,b85c0784,59a4e191,27a1a214,392c3ff2,f3e1cbdb,6f34b90c) -,S(f4a7d2e9,f1f51ba7,c3cf0a5d,5d53a00e,877ec118,f7e39e39,299efb2e,8074bd59,9f050900,6aa6ace2,da4e6380,cbce7983,c9bea9d,99741be0,ef17e190,2c5bd257) -,S(8a5d7210,d4f1de13,1091ae23,2fffbd96,3927317e,54197656,366b2e35,cd453da3,9aff8a1b,5b71da0e,a6558a05,a9306adb,4cae1004,e532aa98,abcd1644,b0580a54) -,S(99eb23dc,e40d7159,b0a0406b,ea04b87a,2c9195c2,2afd79f3,f938018e,b8e86f16,2ef21938,a66efdec,7ff6cdda,a79fcabf,b1f17fde,9e80db37,82b47d41,64ecff66) -,S(3bf16e84,1a874418,ac7f0d0b,9abbe781,611ad0e4,7acbe904,a99ba65a,b4d37472,1d3cb9f4,e1948cb2,fc88c0f1,9277437c,7d1138b2,8aef4355,1fb35121,a3e714ad) -,S(a3ef83ff,19eb394e,b87c133,36388a86,561811ce,5449895a,f459fe4f,e7f01f3e,1955dd39,8bdcaccb,cdc7ddb4,711d08e1,9d687ccd,d335a4a1,45d13a4,8178cbab) -,S(26816f51,da9b4e81,3edc024c,223dd6b4,5a344d11,f5ade552,63ef17e,70b1af90,46278e1d,1d6b67a3,57280967,6604e897,65611b7f,bbccfd30,22007a60,294aabd6) -,S(5e1653c0,d640f148,ecbb14f6,97940b0f,1d47dcc9,48e7525a,909e8444,afdea823,9b8b81ed,e7cb8350,ecfaef22,92bdc528,8e499cc9,6feedc86,cd45cccf,4cb092c7) -,S(1bd88e45,b0d3694,56348c23,125b12b6,b7725d6f,addc08f2,47fe9dbd,e828de9e,182939e3,2d8bddda,577dae7c,a1d40164,9f6faf68,69808fe2,98dba2f,b8a95db0) -,S(4b03fe06,3adc4e40,315e754f,bebb7802,b80ab716,d4201fbd,31b12c5f,d9b73c02,a864d0a8,e2c5e519,ced537,e03f98e3,a5623c31,ea4a430e,73e8cf54,1c80fb06) -,S(e20a515,7818f33,1ed927f1,3c46f3b5,2146860f,d085e68c,5884f1e8,45d35f61,a1c12002,1a79d6c5,89e466c4,3fd48f66,a924e9a0,a3d20db0,484875e6,96bcf328) -,S(e3d11a4e,74a1e1cd,8be24d87,4885e1eb,4aaecea1,c802ba73,2db925c7,f81e37be,8f1ec01e,a1ef01f,63806787,b8831d4b,22b0a9c,7b44bc7f,73d2a3b6,861645f5) -,S(8a233215,57fe0dbe,e8e92b58,4729b163,da71fa32,f400617,d1e2a081,3e37f6e5,af5e471a,bb8c7505,aea1ed74,bd7798cb,267dbd29,61c35f5e,93889056,aecce950) -,S(3bbc0a2c,b43f4683,151070e0,7015cd6,997e8dfa,99685cbe,99f9a76d,6851d20d,9a1dfb8e,a5f14c40,b9968e88,b6083111,fd140843,96fa8278,bb0e351b,7cb4f97d) -,S(8c04d781,82d83ab,e8c59dac,9407b4b9,65380f38,39431184,811e133c,911d1deb,4d74e493,fdb22316,fcf21340,88039534,c0a3e098,7198ceab,4a65260b,4c0a3db4) -,S(467d4d0e,72312cde,df0aa7c4,62e03644,1ed9f915,c9e7e8c8,5770a4d6,d6a0291f,83db40a9,d7c2954a,30c624dd,f11d565a,f117e240,183a81fc,d4dda1d,70a1ce32) -,S(b62f60cd,8e55a101,ab060186,941cbd52,ce73ae2d,e19ac195,d55f498c,45a3dc8c,59da48b0,7c6d2562,eeb0ed09,158cd20b,4a5108b8,fbf6fcef,428cc301,b314ef41) -,S(6b5d6210,f98aee61,df36d7f1,9546efe9,166e88cc,6492183,379dd1b5,cb9e681f,dbfb1748,59c88a6b,72c8afca,830045c2,7c6de87a,c47228e7,7f246e6f,698a0d76) -,S(88744d04,e8c7842b,68d2cc9e,f58977cc,548768db,48d3c286,49ecd0a,22300c97,84573aa5,1ea3c51e,5a0b0e42,5c7c90b6,149d2993,91085bc0,393f58a2,8fb9c38c) -,S(fdf2c824,40f2ac58,19b06571,216ad938,d0218ba5,be4d3d4b,ada80e32,c32e37c8,c2abc4b5,9e961ffb,e48c6f20,58602dfd,9172031a,740668b5,5876d5aa,5d538f74) -,S(4d2fdf64,1f5a883b,322273bd,24755405,15178ce0,9b4ce8a9,36648957,ef777559,22ba1d01,210bf31c,6421b89b,9b3217ae,b2837f01,c344a9fa,bed0b385,4aa41b11) -,S(ec7cbca1,e743bfdf,81af3fae,a5c64a8f,5a54dccc,2afca269,9c461592,34ddc633,9f193da9,ea76a050,7b528c05,e5a10107,dc5263e4,98fcee29,5f57816e,4eab0917) -,S(ff2fa113,771998b8,b801e779,3cb804c,da9cd6df,9d371943,c7fabbc0,44b44fdf,962127f2,1ac57670,c79d966d,b8cd6f0a,2aec6824,22cac54,23746bcb,2df6093c) -,S(6d1b406b,2dfb02d2,34ec21be,c436d6af,4fd418c9,29f175ee,6475e77a,8a57580,b8945668,9dba8e2f,8f0693d6,d3e7b602,f157efe5,38b9ef07,b2dea23d,bce895eb) -,S(4abb9dfb,449e00ce,46476727,dc6b96,317bff7,74c21df5,87bef539,644d7963,6086f2b7,c016c69b,2ad80786,89af1c98,4d6dbba8,7545d8e4,9c2c58bd,f86e6407) -,S(db0c51cc,634a4096,374b0b89,5584a3ca,2fb3bea4,fd0ee236,1f8db63a,650fcee6,7ec0bd2b,aea1ae18,4bd16fd3,97b0e64d,5d28257f,85836486,367fe33c,c5b6e6a0) -,S(ae6f6dbc,d0664919,a65e02ed,646de704,6996a382,21aa8e74,4954d22c,37fdb287,abe70eae,f8ae7404,11931379,19f9102e,c5bbb2f5,f5fefd1b,b76fb6a1,c3f2f201) -,S(aea3eb97,cb321f30,bd0771a9,17fc9770,f4079a62,fac51fda,63dd3ac8,d35f6227,b6a53416,398515c5,e9133704,a287dfdf,878145a1,4416b525,6f1ae46,6abf39b6) -,S(90c9f8cf,711d50de,81f7234e,f6c13af8,39355c06,3e891ded,51bca1c,852233be,8d95778,18f19649,f2d3d452,81358783,17d2c32e,aa01551e,d7fe21c8,3421bff5) -,S(5ad7ece5,ab1d0344,5528dcde,34b48efe,fd954aab,920260e2,1495ed8c,86d976e0,2df2163b,2c3c63ab,bef274e9,3c46b6e0,62ac9444,b17843d8,70014b03,f78569b0) -,S(b6ba2e2c,8e942ef0,16e6d3ee,13ab0cac,1d80ae7d,588a831c,b7844e8e,3bd28d9a,41180a35,f923dfdf,501b6b06,7d241160,a2ebf453,d00b501d,855ddb7,1bef7fb4) -,S(7e409bc9,bba26c7d,fabdd450,bc84589c,799555a9,c6809cc4,13a4c674,7ff5f37d,c518961,9cc5afe2,e41c4260,481d8fdf,6066b034,19fe030c,e423dee7,79c9e6b1) -,S(9486cd14,70b2f2ee,28d01060,6c7c4c22,2c72636a,a50b64e0,3008516e,de4f602c,886ccb8c,fc5b006f,df931785,f732367e,c062e9a3,49f452ce,aacfb74b,deb467af) -,S(e7c11d7b,c8b07205,1e1af6d8,745ba05e,94b1ee9c,5482d83b,1af9ed8b,21338d2a,fdc4d293,828cab1e,fc9062aa,192f35a9,6ad4683d,797fcf79,c74852de,d75c8e50) -,S(dfe627b,ff315cb0,1b1b67b2,776ded35,19b1a85d,8e802217,c98000f0,93d50bcd,993c55eb,bb65087b,6fdd2480,c9d68e6b,ea0f69d1,b95efc28,5f32a8ee,55f9e773) -,S(a0f0cc17,fd00a2cb,5fc7c981,860f02f3,eb31c26d,54841dde,189eac65,a446f516,bfae884c,31d58a3b,f11077a7,d3edd37e,14bbe4ea,bd30fa74,ff5c295e,4b3b8969) -,S(c1dbb6bc,bc14286e,d6eef926,c946b52b,d37e7f53,91fe1dd9,dd7b72ba,a3e37338,67b02d87,bd336882,f4b6fdc8,1a3a88d7,aa5e2735,139e1bd0,e793e6a6,12df7bf0) -,S(20b9065b,c7d495c4,c92cb1f0,6eedf5ef,7025511,10343eeb,e82505bc,bb4bebb2,a6987316,5c231d92,bd21a4f9,60242d9,4fec71a7,4b24fbd,55d51246,10756835) -,S(7bedfdd0,c4d8c38,dda9544d,38fc8786,55ab9a66,4f8dbf2e,3c54810,eda69190,9994f0b0,d4f52de,6ead0049,172fee05,365556e5,3c9d4591,690715a6,f8af77a1) -,S(26762eaf,997983f6,ac63815b,720e97cb,5adcadd2,419d368,df4d385e,6b5918e0,81f5448c,e11b4dbc,24be2e9,be5620fd,25f0c0d6,76aae549,2792188d,5a27e6be) -,S(7148cae7,ee18e152,c3354ff5,dda86e13,ea14f175,92d0d3d9,a944f4cd,f387bb79,bdb35fa,f6f86e90,41465efe,dac6bc0e,ffd42a0b,eee83365,93dcb4de,2310b18d) -,S(27e45dd9,33ae2c33,a69ae00b,156845b5,bb4d8f06,593c2723,5038ce17,87bdbc90,a2bce33f,a93579a3,f8d9c75c,9271a2b1,7dfe36a0,590f2db1,f7cabfd6,51801ac9) -,S(af0c7215,5b28ae8c,2a2d79c7,d81e603c,d0539c11,fed2aa98,fa2bf2b2,d7d6b7d7,ae6bdfcf,a25109c0,b80bfc,71cfac3e,3b5b26e1,e4f2c856,40d2c69a,a7ac41f9) -,S(7b63c408,d4f8d34f,314e609b,21e8e372,de0f5a19,1accabec,7ecfe02a,63cbabf4,aa08009a,78fa96bd,8ceb6f65,e88859b6,236925d0,bccba7c,e0db29be,94f16327) -,S(ab768853,14f3e88b,d63cffb6,8f4f3232,4f4b4801,41aeff93,94d58f9b,85c6890c,1a71c833,d6d96bc1,c33610e,d7ff1481,c9ff9841,157c59e0,5d3a036f,cf7f192c) -,S(641437f0,7ad75112,f8375487,cc0ed859,ccd308da,4b25e5a9,953e351c,9e3bd32e,3c58f7e6,b255346a,f50f1ba8,3f008662,7d2ec950,84c326b0,ccc3a388,81a9b131) -,S(f532fd2d,600ed478,c1dcceaf,fd01ae87,60f7ecc8,7739580b,9b4a7649,67a082cb,7393514c,71117d7f,7cdbb4d6,c803c9f3,221847ad,697c945e,440bcfa1,1285fa96) -,S(33679959,2c4bab44,d89e6f60,8f882938,db73dbd4,75f0dc3e,e1fbd075,b1c7631,4c1f8004,6fe89cf3,6d078251,5ff57cde,17125d62,5cf675aa,1fd70163,49694fbc) -,S(e184c16d,2a34ca57,b06b5396,28cac285,6f18b7e0,32970a5b,e2221a07,be56c9cb,7dffc17b,51ef9c4d,f16ab068,8c66df57,d646cd34,46b509c7,7f85e03d,e2c5bf73) -,S(f8a97d16,2fb49d55,bb8de990,9a20c1e3,4f6ce6d6,efb8c68f,e26c884,6415d419,3cd3cc53,4dbfca01,9492e161,61f2e86c,5f20a83a,866874a7,ded4c2e4,42061146) -,S(9eb6aa2f,6c6ad821,d46dd612,38d3dc53,28cfc406,ad71964e,b32de0ea,12475781,14501a83,79d32e09,3664ce34,1a419b28,53dfe3e8,fbc204af,cb33e347,6c45c299) -,S(ebc2566a,68e68955,e1e42740,323fd401,7c40315f,ceba7642,5f887a3c,3602668a,75e8109,96ff56e2,655f9f85,ae9ec9a5,fab3bdc1,42ef063a,a06931e4,d4c7ea39) -,S(55646438,a966ce5c,2fa5b29d,ba4840cb,ab9c5e4b,4074a9fd,674b7eb2,f52bc392,34631a86,76034a89,cfc3f68a,45cd52e6,2987d80c,e9a8e28f,a37020f,981c8d66) -,S(b87f8309,befb81f3,313257b8,c7dd914c,82eff5d,6729f2e7,eceb0337,7b16575e,bea66832,59e4002d,6fbdf03f,b80bec1b,eda5e1c2,cc55c630,deedb7fd,a96ea298) -,S(45957585,b440d63e,acf598b2,16e435e,24b6cf15,2892c8d7,953471df,70a0a93e,f4cb6260,776a4f4f,23ac366a,565067fb,b29739fc,233493a0,b3eaaea,c4b71427) -,S(2c90f64c,8d9c42bb,1824c821,8f9cc057,3fe8d648,b960ee11,1487bbe4,9648ca87,829bcd57,ac643cb6,9f000a9,f22fcf57,69bebf7d,6b1d8ab4,da21be41,d3c25a8a) -,S(eb327ac7,779c9abd,9546a3fc,c7731729,2e753912,2ba9f7be,36db0548,144b5efe,21ac2c85,8d2fcd38,8c32c594,d6e74803,2cbbf365,238565a0,8c439190,518c9435) -,S(95ec7e2,272ccca7,aa2b07fd,d37d0f08,daa35418,1ae30e6a,dba0cb1d,2c6d007d,733786ef,59df6050,552ac913,c10b8890,2d589e7e,4f740f33,75f78fc5,2ba12b5f) -,S(4b7a6698,8b4fa080,f27c845d,7ff17371,91104a29,2c6195f5,fc367c69,fc0cbbd1,8b043bd0,a3605612,87b38fd4,d99b29e4,8e52494d,8241207c,9284581b,63a85b8f) -,S(89b2c58b,6df581df,352ab28a,619027c0,a9233792,fc6525e7,47dabd31,a342e6b2,300b1b34,d459e65b,e265edea,203b74bc,9b053feb,888e81f4,10045a10,d7f53a2b) -,S(41099b5d,9f6a28d0,e4a7ff0d,b75ec487,1c926327,89f0c800,7ada8114,9bc43cf1,2a0aba96,2e2b92b6,e949253b,e06588d1,3e07919a,3594b26,995c15b7,7a62cae5) -,S(bcb0fc64,9ec508c3,507396b2,9a663555,8825ea9c,1389c817,af7fd616,7229be4,168c7992,cf3bf5ab,6c3a12ae,922e647,13664db9,2d7bfe5c,2c746933,3a07d606) -,S(7a3fc958,5a6256af,9e314ca7,55a8096,9cd3b3d6,f70349a5,ec719cd,ed8b762e,fe8b280c,29cd0716,35288526,b7179d90,dadecd78,39128f22,17d445cb,d3df1346) -,S(377093e1,b968a35e,e0f229e1,e656da9a,7583c1e6,d06fe1,c89e3f06,61a8176a,e7c0860d,f6c9f461,7e6a4dd0,b8c0d800,6aba8e88,20aeb82,e6e0f8a0,c2c601d9) -,S(c5eff3da,f4a5cccc,f1f27a93,361301a1,919b1dd2,5a98ea37,5ba63f14,4aafecd8,34e11634,26f983dc,18c8a02c,2222c2fd,a94129f,4e3f1d67,f424964c,dcb97a1c) -,S(fc7919,eb560d33,44230f72,8368afcb,3c0fa6f1,52ec54e9,84ea9ccb,e63ffb27,1c7d3782,af766ff9,bc1cb838,8e4a7dd0,a04bc4ce,adad3fa9,4132842a,9859a6b3) -,S(2783d7fb,49386d72,54434cd6,edc6f46f,b3118322,43d381c6,287d8b24,861ca5bd,a3aaf271,b806ac0,e3c45026,28f89c79,e4c68574,81710111,a9316e38,c7fa5c70) -,S(7407a478,68d4e0d0,f77f8949,5e5bbf95,88f54a6f,fd35d229,8ad4b30f,2d8a02f3,1250d562,96e18cb0,aa5b393e,a933297e,debf3d94,59ac1ce,24cc11b5,87fdec9c) -,S(c2d2cce3,2940ecda,77ac108e,71544079,c5899fa4,f8461df6,cc54dd21,a861a321,f0beb1fa,40bb8071,928b05e3,ecc8545b,a919eaa,e830db72,9e6de85b,f05a1909) -,S(8cf6b189,c5051956,6a94e1f5,ab5e9530,d459a935,4cb13eb,349fac3e,ade8a56f,bf6a9d70,32e52886,ce6d06d3,b22d47a8,327aa788,1621338c,1606054b,cfcf9c96) -,S(d6b07586,ed9f8471,f96ac5f,53277d1e,2deeaa2b,7fd09d51,ece6766d,29a94968,dab4d4b4,ce5655cf,4aef0d0d,5e3fa292,2f79041e,d2e23c9c,75be83f5,f09c5326) -,S(a720b733,60a03edf,f33a0921,90795834,9e661d33,44da800f,b857227b,ef4d647,1f213c6a,721c2d82,6037e3a5,a0f4867f,13d79dff,bd44f5b1,1bb5c0b5,4884ea63) -,S(558a5698,3b03c6c6,717db862,e59dd075,b39f9ba2,ca01b0ac,95a69cec,1f3a5ff7,7e07c752,db21b68b,21738458,a045fc60,fe3ae869,887fd557,92ecc6c7,d4ffb1a4) -,S(b927dfc3,278668a8,c5329941,f11d0e0a,a7c2d9d7,f8d6c263,9cab5550,10e14ca4,3ce83725,9954227b,b420e35f,77705225,72f4d854,999af552,4b8795c2,b723388c) -,S(2b70d499,1085aff5,88e23ed5,ab55a374,3c35f71c,651c0165,13f98ecc,4f0e6da8,df413b4d,aa1e5c9c,a2398469,7d82762f,a701413,1cae25cd,1a94f02a,506a8b06) -,S(b8836cdc,f72f6e00,99a9181d,94ba77e9,e1368e54,a62e1144,1421f2ef,2daefe56,9ad452f,e31f26d,cad7014b,68ceaeb6,1beecaa,5394c359,afa52209,e50427ce) -,S(252b297b,65f0e23a,9788b48,f33809a,ec66b445,cd90db00,4dcb6a80,c4af93a7,8cc4e0c4,3c346211,736a3bcf,c24a58bf,9f77c7d0,c53350e8,6cb0de2,60916838) -,S(9f3d30ca,1c15cc66,8efd5fa0,3d6b7bdb,d34f2704,cd729892,aad9171c,debe6330,448b6434,f95ee7a,bc056974,f1476171,353d9b98,4e22057b,38662327,b23211b0) -,S(8225e16e,5bc9add9,ff8a771b,5bc7bce1,653b545e,4e54b9e6,6e2d2985,2fd35e49,6254c5e3,aaefa2c1,6ca4e1de,87f09d94,df836b9d,d100612c,7174aa75,7d0570fa) -,S(a7dcee48,4d6e99b1,b72a80b7,4de255b1,74f4767,4d3c5799,4669ca6,aad02ebe,1d6f0cfa,76a2901f,4861f541,bef7a948,78586178,8c7c42a4,2db583ba,1c170a7) -,S(a91445a8,5d4ce90e,98d3372f,d2c664b8,9a6baa2b,a396fd1e,210e315e,809976b4,adc4c68b,99b072b1,b51d1512,cd94007c,72deacf9,4e7c5449,f1d83876,78b1d100) -,S(7462c9ce,907c9655,75c41096,3510e00f,6f6ea6ad,886cdc79,ed685ee2,2a7ce1f1,4ffa41c5,f02c2299,c42df5ac,79cc4140,47a854e8,332f8f2a,e67ffa20,bb71c7df) -,S(d42895f3,dea495bd,af8e36bb,6a79f234,dfd85544,965a8506,5d38ca86,28cd4f40,2fedeb18,13a11c42,e7869b20,7bb8486c,9821710f,a80d9bbd,59c92ae0,b50d9cf5) -,S(ef9b6b62,ce85588a,f13434b2,7ef53d12,e8291e6d,76a65669,c29d99a1,4d388adc,159f5fcf,9af0c962,ed907955,e91407ca,80261255,45b6938a,db18aee0,9bbf912f) -,S(4003f1a0,bc659daf,df5fb7bd,bc96afff,92877c7e,2a693f39,2afb06c8,fdbc9f32,ebffcaa1,7458f0b0,28ff1dcb,74be865d,7faeafa6,c2707cc9,ea685eb5,7961fef9) -,S(4390488b,6b03d851,648786f0,7486f5cd,aa9ae1d9,4867de,bed7036a,6ac09a8b,78329de5,a10db56b,1c35b88a,21ddf393,452001c1,29a0bd6e,5dd76a63,8682f07a) -,S(ae6da0d2,9ea3fb66,b6006c56,5dff8b41,6074ee16,f9ff86b9,60574067,abfadea1,74caaa63,dd012a63,e76f0916,f370614e,29e3f01e,b88b49c0,5ca33234,c11cdac7) -,S(78f879df,98614721,b7c65652,4e806f6,35942e0,950514fb,2fad8a86,bbcfc72a,4194e58c,478ae80b,fab661b7,ffb85cc7,2318aad3,88d61c68,a755296d,38281ac6) -,S(80684365,4f41b0c6,d6cd51cc,838355dc,352e028,7b1c1d1d,edd2f96e,5fc97e01,8b0c223f,13c61b4e,1e141a0d,35f29a7,7546bc7e,3b1e5c45,262033eb,92b62461) -,S(29509d9f,4fd975f4,6efd1169,1d97d0aa,f83b5934,9c797010,5cb3908,4b87466c,1477eb75,69a0af96,c9cfccbe,135e3c86,a33de585,2ead38da,8a0eba6a,6d0da81) -,S(191d1443,3d9c722f,c1532fe,33c63a9c,4e3d5741,6ebf799c,2d8ffeae,df1dfa4a,5bd00409,b6b571ad,745ecf83,91884eed,a5e3c7b6,65ec9706,eae4b4dd,703a2cd8) -,S(2843d42e,d2738168,5eed65af,eea82bf2,a50f0e1e,3db201e1,ebf8b159,1b0155a8,807cea66,c0fa9f53,b47e6e2c,232cb225,77edafb8,99a6f98,ff87d091,bbc63ee8) -,S(5568b7b0,9656d36f,5347514b,8e8212f8,e96ed02d,4516c018,4d653bd1,2bc8f644,5b44eba6,54836dc4,3fbda30d,7ea36406,4960459b,a4128911,8b2d8638,50e60d87) -,S(5b84e0e0,809e44a6,9e8d81ab,595b32f8,4a7dd421,c073fd6e,5f38ec5e,b145e803,1a65a2d0,fa791ced,72fa1522,ae431155,7e6109c0,fe934243,cb43d3ef,ad13d398) -,S(ef42c56b,dd241071,47e1519a,18d32910,675ba842,92cc8ede,900a64ea,bedfa672,70151747,33359977,611e0c25,4addbf6b,26a618a2,31474e3c,c9e7bcd3,8bff75ac) -,S(48dff2dc,b50d4a56,4be6ed00,3b1415b4,adc653ec,87eae94c,92b7c129,5656eb63,a9be97fb,53afecf6,f0bc59e9,8bfad542,fa29e63d,f701f6b5,f0f66081,8d643928) -,S(672e90f5,246ad174,10c9a2df,c22b098c,d1923bd4,19fdc337,f881e4fb,4ae938d4,73fd3380,1fda6db6,883e678b,31e5f09e,f331b624,5617ec9e,97aa28b9,a1781f19) -,S(59cdb9b1,71fb819c,909e094a,95dc15de,dbfe5521,4a7cb723,ee7cb761,4b315cde,55ac212,670b4a63,ecf3f8e7,3082009d,7f2d38d9,e490ca18,7a6db01b,e88351a2) -,S(5ce38d0a,357a58ab,134db879,b99994c4,6b827f82,8e1ce8f0,43108de,ad2ddb18,5e816202,d9c1d86e,c2f84b33,ddbcc51b,94748c67,1089c9c1,745a14d9,3b97f716) -,S(c982196a,7466fbbb,b0e27a94,b6af926,c1a74d5a,d07128c8,2824a11b,5398afda,7a91f9ea,e64438af,b9ce6448,a1c133db,2d8fb925,4e4546b6,f001637d,50901f55) -,S(383cb084,79e61bec,dca81d29,7796d00f,60bfbcc2,83c83d31,725f5329,839ec818,26e26fa2,49008933,8bde0498,15f34d9,bbc3426,ad8644ff,db1a190f,79dec91e) -,S(e6945731,2ad4f14a,71917b52,448011df,28b88c9b,6ac84550,248ca4fd,102f612b,30ed2082,51fc701e,5ebeddda,c9eb0b44,c81cc86f,9706889c,1b1c3386,4d76f53d) -,S(2d0071ba,8f799352,212168d2,1262a729,250809f2,24fa58a7,f283c4c6,bb9976f7,cdca6901,4e4873f1,16945544,800079d,ccc118f1,a5709b03,c872b017,5f1dfd8b) -,S(c82b9457,65b74fbf,91cf35f0,679877b9,da35c2b0,8437d789,8d748f22,1e927e,2e504dd1,bb06bfc,7e057dae,9aac8f07,b57a0f2a,39b1533d,9313d9f2,45fd6a2) -,S(9c1a4c2e,7eac21a9,fed135ed,e737dd19,2654eda2,fb3a4227,63cb6328,75bbf0a6,f3134b6c,12f71c58,226c9128,9b7b5a06,80eb6646,e9da2e60,20008efe,10e9197f) -,S(971d3d9b,bc693222,ed8bd645,e80b7cf9,9b170a36,2d57753b,6a2ac27e,8d6c9b28,d63d49a,e296dc2c,6c4a73af,7fc5e86d,e2039433,f3858980,80a36f7f,91d22e2e) -,S(f5493a73,86bc1151,23f29f2a,e0619e05,660a317a,bf5ac23f,a67802fa,8b917d2b,e6adbccb,8b780530,2b305157,b427b8b5,38455e02,80133e23,9642306e,65e0f1d7) -,S(831f123e,500e0a0a,e497a321,5ebde2ad,763244fd,40b386da,dde05537,99b6e014,35616862,2ff588ac,552fa508,ceef5ef9,ac04af0a,9db6b950,f44719c8,cb221d6c) -,S(9b8ce06d,18474c,3394c334,2ef385d6,7a338c22,98e92975,f1728c87,897cfb35,76940220,b8dc3e04,7cda50c4,c1f53747,7ce8757,a4a3731d,712cea05,42a40d72) -,S(f70a916b,a98d2bc9,60172410,42bf3e14,14f06cad,dffa7cb,1e8137a7,3fc5b855,f1b8c1f4,70d7896f,f39a3fbe,997a88f3,b5426d84,43c4023f,ff98fffb,280275a2) -,S(2d2ab7bb,c44e7fe4,ab283661,2f621d05,a64d6909,fd94e599,92d52afa,c0763d56,53450e00,2a6991c8,68fe044e,8b61c2d3,c5fec8af,3605728a,e57d32cc,c55328e8) -,S(8178deb8,c516978c,ea25423f,3a913157,321ff7c5,5d8058f3,dc9b9d46,f4d10005,16a71b2b,46c9d303,f4ae6a28,235249bd,f9c00146,a26b6bfb,5983bfb6,8d6ff4bc) -,S(b470bb76,d012ba7e,67ef9c32,add59940,1f700ca,16003011,26e6a692,36b56a64,f7d093e0,7d179861,871f36f1,58d26987,1775f082,a2fbfa69,27cc2272,614fd95c) -,S(164f2aba,837cac12,19b48eb3,30f02141,d3a89921,1cdb3f78,fe17133f,e2de29ce,3bc05608,95f7d034,4a9ec79e,b821c06,c2837c50,66925197,2c076374,871d28dc) -,S(c77a3a04,2a86d2e,f512268b,35cbb89d,e6a210ea,883e2283,ec59fec5,12e725f4,2ebcd56b,edf1a07f,e587e592,8ed602b3,6d1db4e2,5b49e914,8dc9eedc,131cfba2) -,S(e2defa1,f714cf71,557a3f1d,71c6abe8,11df5504,da38e9f,60ad335,3b11349,5ed64303,7a53bbc7,2f41912e,a657d944,c5107da,3b9ab54b,d88b545a,e045f229) -,S(ee2d12cb,b4cd9e4c,163fca1e,5a4330af,35280ce9,cc1d57b2,d2112443,b6313e3c,e28b1dc1,a4377c65,838ecafa,bfffb696,4057fb6f,dd4baf08,49f9223a,ee153262) -,S(4392c96,73e6deca,f3c39c34,f5be7c3d,a2109b45,2271467c,78f256d6,7d9e28bd,7fe4c183,ae352533,b049edd5,343a6bb4,747d63d7,d0f406fd,5902a886,110c50) -,S(5972e2ee,167374ad,93a655f1,6008f49a,f5586b2,f81197a6,712ff31c,a0d6960,6d70fc55,d0a57c74,8a2e485a,d903bd72,779343fc,7c090847,bc3dec1a,6f7c71d6) -,S(a85d800a,fc2c0315,889f1faa,29e5766a,a180f31a,400e3c19,85589af0,302c78aa,7429d7f4,903c76a0,a4437b41,92865b7a,ff5aca7a,52dd32a5,8f8b00d,b97ec85e) -,S(c9836b0f,d594fcc,9a89e85d,7d506386,ccee3f38,72759cdc,9548569f,a5f1c245,9f0b1926,93b7fed6,2f1a7d06,fd716727,bed1c2c5,9bb431ed,943b7082,d094fac0) -,S(ca2184fd,b2b84654,d0348e5f,6d963193,75f2c441,ae64622b,588cae7f,d202bd3b,d1222820,3d657aac,493dbb2,fe9729b9,e2563cc8,1f671626,83c4f0fd,726a4de9) -,S(9e0515c6,3c9b9664,8762704,80605d56,b5dea0cc,c7a4c66b,44a2e605,36941fd8,29de3224,a2eb2d86,afef789e,2dba061e,95f0b762,117ede50,6d4b21c9,54be831a) -,S(42042c25,33203a7f,c22cf7a,fa5f3d79,8a3447da,51d66f60,53a8f000,af5dc1cc,f075a67a,6d6c3872,315420d5,bc13d13,c54f3c1d,61f73d9d,ff688da7,f5e6c05a) -,S(6645a1bd,4eab02be,45884ffd,288955fe,3f5a68ca,9ae431bc,cd3967c7,12295b96,231f79f9,1d264ed4,28ed4b30,f0e92c4c,bf902865,24050b67,30cccd12,bb84cfad) -,S(4e281e6d,2c316e88,231482ab,1587de37,6898f3a8,870f475f,30bd1ee8,d4b32f9f,f48cadc8,1c119edd,e5f78062,cddc3416,c3f708d5,f37e4910,11ef7581,c065602c) -,S(77236414,96e41e9f,f13c7ffb,c7a66203,4fbaf7d3,e432ce02,fcd54ef0,4aaf5136,222e0174,d6cc01e,fb4b4bf2,9000f697,98bec7a0,657f328c,80083074,242dd218) -,S(3f2b704c,8d467859,ada6070c,b1221840,18ab009f,f7b5ebdd,af31d977,dd45860,a47167a5,146aeb5e,8c38dd21,5d61a2df,e2b6ab8b,fd05ea9f,b59faea8,3b4dd88a) -,S(794ec130,d243d811,2ebb70f0,35f983db,84b3acd0,ae4c5b51,640b9e92,ecad4146,49edecbe,95c25c7c,eeca537f,937aef5c,658f2dd5,d8c0de71,c80777aa,d07be84d) -,S(750ff9ec,e363e12b,79b04cf4,a7b1c0b1,49c554cd,6e9fe3ba,808c9614,95a96aa3,5a28269d,d1c5a3ed,f4e70f14,9a060b42,2d4474bf,1e4c6dfb,2de1502f,7a1d59a9) -,S(d65c05d7,df6668ec,b96c9ec1,fd129462,263b082c,9b7f4169,6335fb2a,b66272cf,d7728c5,1c10d42d,242cc5b7,fc77fdad,7e48be06,6b2f7c37,891ba4f0,de188839) -,S(d3804cb6,8cb2e9e9,b5b9d270,db9a172,aecffe39,72a3d2f6,1225bef5,595190c3,11fb350c,9568648b,30af4131,46053428,2879023e,6ff0d613,482c2471,b5e30d5e) -,S(f762de26,35c6349f,6cc95c61,9ecf8d37,6a938241,1106db3d,b34e9e84,70351bf6,dc67f9e0,c8a50f9e,e753352d,a99112e4,ccfe22d,3e88410b,1cadc0ba,bc9fd814) -,S(ab18b4bf,a827ff4b,17ee163e,d17e3927,d7dcecee,ba87ce7d,ac5e5767,53b87a71,6db83bd5,73e40926,c882bc09,c4d07f72,29706d1c,d2b1ded5,b57ea9b9,2b0da919) -,S(f754c248,fec21ae8,da343a87,459622a,b12478ad,8f63ad8b,f5c66695,198c95e,2cfb76a2,5f9c8776,b848d8e6,7f544774,e056ca7a,32bbae52,93b27992,6052b1bd) -,S(f8d9473e,3c3f0798,f893ecdb,716bca16,103516c3,1341c8e2,c2462d4f,9a46c51c,55f0065f,a422fe3a,26b314da,c7547835,5c53bd3b,e11b4686,9e05be92,d7924e02) -,S(8639942,d294cbc8,9a75fa22,5b29fda9,2f7c5ab4,bfbc4395,352d050d,754eb741,3913ea2a,445de35a,36d79abd,db3ed7cf,741da883,4cb81c29,6779d8a9,e7d11e4d) -,S(2a588c6c,706a388b,f1719230,b5a71b4a,6857282,83aec61,794d1a78,bb95d5c2,af25ed77,1a56f6d9,6407f07e,a7e11f97,61f458ae,bfbb1b00,96842c4b,6cc47592) -,S(137bd1ee,8931b9a8,b26dba4a,d9a5edb0,a5459717,22e1fe3,37ee8d54,20a0cb6,cde9fb7b,8197c77d,273e9f0e,e87d76a1,eaea105e,21154b7f,f5848a30,17ceea62) -,S(46580345,c686313c,97152371,13af2c2a,f9b5fea,a1e0bb48,d21bbe32,d2de2bbf,75bc5d7b,b6329ffb,2bfbc79d,b66f4c2a,7edade8e,a16bb051,a3a8ee9,ec92ef64) -,S(4a149252,afaf5acd,982fc491,c26af545,2ef93d6,1b282a85,56d5ef64,391bd233,fbc100bc,10b55b60,96656ea3,863f5d4b,bb9e83fc,5a25e59a,3b53d78f,60cfe285) -,S(894ebda6,fc0bcf8f,e025131,3475d64b,95bdf089,7d9753fa,ad0f92f2,15a01f18,b25f3150,155772cf,c69d0251,97d37ae0,1e4ede02,e2994377,9fae26cf,5f5ec056) -,S(e70d8a93,a91b891,30def1b2,bfd720ac,2deedca6,f9e5a85a,3c2a6eae,45eb032e,bd3aee53,a3b0ff6b,45fb96ea,4911cb02,fe102681,878a1b0a,693fdf11,4cd9f9cc) -,S(7cb1fdc3,e5ccb1dd,4a16765b,f9546b6a,1189883f,135d447e,eb245fbb,4eb36852,90ee0d6,becf5ff7,b80edbe1,75dbf258,d1889008,a8fed4e0,1968e2ca,8fca582d) -,S(51278ad8,331da17,8fc90a21,432b9058,b39f57d0,31210685,bf9bfbc2,87b9bfc1,5aaf547,f39ce678,8c3ad759,b25db3e5,7bc1f9e1,f75bc040,536ddce9,d3a66b6f) -,S(f0eeaa1f,c52b3068,48b56308,22fcf0f3,fee5008,54e276ce,e9fe9904,54f59cdd,90ff89b,944d70bd,eb5e5e01,6afbeb30,d51cf7fa,81182e63,ab3bb2c9,f2124f02) -,S(36fc9bf2,8bf90fd2,613670c2,27b51c00,df5b4caf,252b5df6,648ddb6b,3aeea71,887c3876,f1ac6c28,606c8161,4ddbbbe7,d975ecc6,9fd9075e,13d0e3a3,e7836683) -,S(6e31e26b,cf9436c,e14d2d04,1c29f62e,135c549d,5e65bacd,ba4df2a8,9b91b68b,2389684,9e63bdaa,b5f7d9f7,7a778b31,94c1af87,d09a9a85,85896188,acd0e7ae) -,S(c5044649,a4b1c2bf,ac6a8a1c,ead33aa0,3da9fad8,4f742eac,35792672,1d98e864,6d2602d2,83e696bb,717d1327,cc1143b,45fdc84d,b8d400af,537b201d,a7a1027b) -,S(a933e71,f13c44d5,bda8e963,b5a007bb,b9b2e84c,c45211e6,eca804ec,6a99ca28,931bf3bc,ec45e2f6,e6571207,31d42fdc,c3ce0279,542114f5,c1c0f659,f6200faa) -,S(9003f61d,840c2d62,1ba98884,e117038b,b8559d0,b132a1aa,83adf65d,f8e4a58b,50c75124,f72b3952,9feb7ece,cba26854,1388a1ac,73631532,b67f56dc,e8d30895) -,S(fc807c18,3cb370cc,8638abdf,c17281a6,914e21a9,e9f3e2c5,33fb7c37,caa0a886,3ac79d3e,75ac1d5b,a9af7263,9d564256,1ccf6fd0,6b8d2cde,e9d24a1b,e8af00ba) -,S(3d072ae4,aca4ac23,b43b608f,150bcd4b,cd780dae,7e4073c1,86293cce,dfee9cbd,6d9e443,f721c9f8,a98fc563,8d7627,f9c60414,67da3857,92fd55d2,7e65d9b6) -,S(d0cb8594,7061b4a7,d2bc5eed,522faf8b,ba6e26bc,7acb1d3d,106aabd9,a7f80dc0,fbfd0f26,e9d0dcc1,a0107b82,d1a9876b,8d7562f1,41f0892c,9b739e47,7b012e0a) -,S(e4edc0ab,6416c644,1e59f46c,c7221cc0,267aadac,242cee32,41a6d25b,635bc9fd,f41c3ae9,cea7b4c4,4834482,980807d1,c496fd4e,bb06964,b84c1fc3,4fcdc71e) -,S(6233b50b,2d3d9101,8f5a83c8,84be0f5e,ffb80641,1b0b5271,557d32ab,dd7eb4b2,8dfaad24,ffdd2ac2,5770f21e,328588b1,34a3a2b,dda40399,7911ef19,855dbcc5) -,S(6ca00162,e27265e2,27b4e544,7e981f6b,c427e65e,bde295df,9434b7dc,52a19ab5,d33f5f63,a8f227e0,a43fe297,babb3a07,223e8916,e153a5c,e0f57e65,1154cce1) -,S(c01205aa,5d2a8d5d,c0d328ae,7ce7cb16,d6c9d992,8b6105b3,cd68666e,36fefcfc,b65e5f99,c4f48095,e1bd6f6f,6af8ba7e,cf2988ab,ffa9bb45,3ad01859,e831d3e) -,S(e3965393,e6268cb,61d6fb19,58050f39,7b8a597,4a6c4abb,4e0b78d2,dae0e155,1f78ad46,2ed6e1d9,18004892,85383b2c,3f971fa5,cda0c828,a2f289bf,80731737) -,S(27bfd0f3,702a9d43,50c1a6,9fd990fd,3dc03af8,50bd84f8,1248222,6cb099ce,22e16b60,e8caaebd,19b0c0bc,e40be7c0,c49fd3f0,d9094f39,fec1b1c,bc643de8) -,S(8210fbc0,23319565,9eec1777,12997a89,2a37172c,6f75e3c6,cbf080a0,6f96a2f0,1ddd7792,101166cb,bb11d552,85e1eeb3,bfacbb25,6d1a5097,16dea91e,46afee8d) -,S(15cc66b6,5fcbbd80,df15298a,25e2ff80,ae4d5065,f8befab0,89cd21a7,4e347b5e,944b47e9,35748296,deb324c9,f5616d28,7b225b34,488fb34b,6ddacd32,7937c97) -,S(eb7b7aa2,45960169,1ea1a482,a9e6c35e,c7bb08fc,726c2c4b,ff801ae0,94c97976,4d2e9570,cc187791,fcbd20e9,3f0656a,f5596f4e,104c3f2,27c23f82,2ed1b1f6) -,S(4598fafc,ed29e844,c22436e0,996a8469,18e7c106,b40a5ea1,5fb0e7df,5e9ba12c,e73d96b6,d292ea2c,39779dfe,7f716609,978a8555,e5b09629,7dce228f,f35e6093) -,S(49835a86,3612e594,572a2591,76f90e18,e57d4dfc,1910c705,8e37eeb3,1a8600f7,3b7613a,fbd2cc1,cc23b147,e0e80d36,464c08a2,e488d7b9,8250ed37,dfcfa531) -,S(3a6d6fed,1fcc8067,32a3177b,4dbdc33,3cbfe0b7,d19305b9,965916f7,ce335351,cc3f3d8a,314d617f,148a6706,d7f10641,11eb2b56,1bd1dd0d,f2986925,5a6624ea) -,S(21208586,6860fe30,ce92d2ef,b2035b74,f672a024,ee7baa78,fb0d6c7b,3ad7a9f5,aaf145be,51b1ec,3fee8be1,1f6e9d73,96ff0ce3,41f25d7c,e1074a09,78bebbb7) -,S(f819132a,c9bb2f09,663d609c,51cb11b9,833ac082,6ceffcc8,67cda04d,266e4e06,b1fde638,ec6a305c,aaffd1a0,6404aeec,c52f48ef,7646abb3,7e227239,4c891de5) -,S(536c05d8,8786640c,43734d72,aed62d9,168385a1,213c4428,423a9437,c2ec009d,7f4be100,d827de18,68bc2b43,c83a08c5,fd84ddee,1fa9ef13,4b489325,db6df0d5) -,S(4328123e,c4c6db76,37ee3ed3,42c8a859,9de2fb1,a39a24bd,650b73ba,a1df722b,81c002ea,1277753,e6a22fa7,1b4f86f5,4ee11f10,f5d5b15,94c9d7e9,63a40857) -,S(f3e156fe,f8529951,86a9e536,f985c1,6a85fc32,d50e9a08,1550da68,112a5f17,91ffd66b,56ff0e6f,65d67e83,c362b853,a2f441ce,7418d091,5d5dd09a,b48892d2) -,S(32ba7359,84e13f42,d2e8a716,a54c40ac,6645a1af,eaf030e6,8242a8d8,8b456cc9,67ffcf1e,1c32b150,a82ab317,8ef24c93,f055765c,9e7e6200,f868b183,bcb4c6f5) -,S(cb9c2b3a,43d105e,518674cf,64d8b4aa,9c868b93,18abbddd,ccabc0ac,59829311,1fc67ef2,233f076b,ded3ac47,99c859d1,834bea5f,bd2bd5db,242607ee,842b691f) -,S(e14f2858,b7bf7070,32349695,e09bcd3b,5effa957,abc19e85,6efa31bd,2e9234f0,3e04e49d,d3f3fd39,883cbc25,80d5ff06,cf8cbf0d,4a895761,f3cd15e4,dce08bdb) -,S(156beb7b,1c27b8e3,cc78113,c97ff026,74810dec,58409e01,d7b7388,87550d82,c711730a,80216ec8,352adf2f,d5939991,3a8e92c6,c16c17b,16e27a91,90bc5371) -,S(de5ea7e6,b9b46864,4b80e495,9a2ddaa1,a24a3399,f8039355,7b798b5b,2c55d600,8901a027,e6a823d2,dc0a9d24,e182cd52,b9b1de67,22b7f7d5,3a03c615,8cd48ee8) -,S(8eddd368,8bfaed46,25b7312e,7b2bf0ec,aea07414,a1281ade,b79b9e3f,ec17c3c7,2db43af9,26171d34,d5ca48a8,9223e57b,59b885b1,5c4f7231,6d8edb6c,7955da7b) -,S(5c971b6a,665ad1de,8fa489ae,22237ed9,87872e0f,ef95eb85,fb2ad3d7,f0b1d4e3,4d71f598,37c2af6f,af32ff7,42ba01d9,aa8d4d7b,302d39a6,c4fc693a,5f8b1f66) -,S(edfb253c,28212b6a,d5b66589,a2a8f1cd,bd3586ef,34254768,85cfb70a,46b9e228,3e5b6608,b7e81f69,b8cb26b8,4f306292,594e42e0,25134c1d,7f7b2a24,b2616c00) -,S(4395f24a,e127772c,db163dd4,e22574bb,d2373cc6,b2c67384,737c56b7,dd525c13,bac6e725,4c800c2c,64896913,df739574,676581dc,1b4447a,819be64c,10103526) -,S(81100ad5,73a766b7,f8913b64,b5f5a87f,8c782353,5f62a3eb,182f0ff1,946866f5,52cac16e,325b0899,9d068f7d,51dd9d5,c6afb8ba,9870a9c9,d28b4170,e9a00c73) -,S(fd3a0551,41168146,6ae358c3,aa14216d,dee3a05e,e5ddee40,7f72347b,eb95120f,2af2f30d,45ceb12a,b89b7b88,b7e04b20,11a3c607,58ce7250,e4c7bcd3,da8ee5b7) -,S(17a55b58,a7eceefa,3ff05b6d,fa17d6c2,76d1a032,abd198fa,4e3fc3ef,e6435ff9,d7273958,a3ad67c1,fdcee72,e71f0536,418f35a4,57e06240,bc99bf71,b9574d4f) -,S(870cb7b8,e2ca5ea0,8c5c73ae,e15e8b22,793fd005,5ed7003b,c49b4089,3b789b6d,c33c8b40,7b701caf,26d7a9bc,e22644a9,4badbec,ad509cc6,a7b0ee04,1be67aa3) -,S(f951c5fc,dc46ef00,adc53c89,a50ca0a7,ffbf7c36,d80e4897,5452cc1b,4e71f8a7,6ae2f821,7849cc24,30864d7d,24df9e59,c1705b92,5792e648,75120738,c792c95f) -,S(aeb8077f,3b92c676,ae11bb06,a18ada3f,6cbd832a,1637ed61,31e4902c,96a0caf1,29f41d1d,f5d4a430,94e75fb9,8bf317ff,6c8a6d7d,b37ccfd,e0232e1e,afcc1e35) -,S(d46f4d97,5d2f2e58,6d18a7e,5d8587c3,8482b78b,595de60c,b9d2035f,313b78f9,95d781aa,3bdc1176,396154ef,31fee42,f704e199,4316e33c,1053491a,e86392f0) -,S(6afb44,4b4bd89f,2e21b54a,c49b9ec3,af810b97,73c76eaf,4f3a5f1c,7a29b201,3502901f,d7d3b4ce,134ed90d,1388ab37,64db460d,bed334e,af061822,6ebf932f) -,S(5f02e582,a38b1703,a7bf6086,9587af5d,e6634954,cfaf8394,932f7ed,ebd86976,a0487cde,92f3a796,b24b06bf,740b8fe2,ccfa5d0c,a2b68a7d,ef46a005,2d7afec2) -,S(26427482,60432ced,5a07b885,f354667f,ad70eb75,9c556e33,c6652d3a,a0599fe,119238fe,2560382f,d76ea737,9340453b,a63867cf,6e044c62,949f858e,b828ce85) -,S(6b2a3e5a,d327adda,52b19a7d,d5e837ed,4f03a5a7,e1e5b7ff,2cd66660,469f91dc,2f9f4526,6b482fa,f336560,1da9e945,354ed265,e8d7e57a,22f04bce,8a54c6d9) -,S(2588b88b,7e214fba,ab10934d,def13e8a,e5fbaf77,d7497dc4,fcc0345c,435daa79,3e5cf90b,d3ba6d4c,8d7f142c,ef1a51da,61ca644f,acba35e1,51ebc114,c5435bbf) -,S(d9484146,92852eef,fa8178b4,a01404a,e4e3d846,c20c3fcb,cff5cff9,de551a93,d5b0fd7f,e628c427,434a1219,6ad99862,13ea0abd,969864cc,dbb8258b,96a6d5a4) -,S(5cf81fdc,3a2f2087,cb64b1c,9b6f4754,5ccc1e78,67cee5eb,9fe9c4ea,3b0de2ff,e0b0ab1c,f6bb8e5d,f7ddc700,5ec73471,e7ff3125,daf113,1b78fb8c,15bc0d7d) -,S(41b4ef7e,b719fdb5,704b3f17,4132c694,f8ed2471,1677a320,3b866660,dbe879a7,a6fe65b1,cbae2235,cda8b459,eeac19a4,9f44c2aa,1c8a881a,e12093b8,3621c85f) -,S(43ed572c,41f691e2,a8dd1691,86404ec8,7a4c0a3f,406f3bdc,5c2709a9,bb117af7,b7b9e1b8,90b40334,6bacbbab,7be4d477,90a2b093,dafbac3,fd4d2073,fa481da3) -,S(4e010a19,223086a6,314bb526,2f1955e,81722b41,e85fae42,1c338e46,1b397de3,f0d3f11c,3475ed8,44876e7b,3bd0bb8c,283b44e3,70c46ec4,a6159a27,eba65fa2) -,S(b3609cbb,7fc86bcc,4dbc385e,81edcd84,45e15d2a,7d355e22,41dd442f,ee11f36b,8607e5ac,a3df34ff,804017dc,977bba88,c308911a,aa1698e2,e6190c8,dc9c5f68) -,S(445e60b2,543fbd3,7bd68cdf,6db1125e,d1bdd6b6,b27249d1,df96e43e,df965b4e,a5fa458a,8c4ab47a,bebfdc7c,f922e713,c65f8b52,287a65b0,b5dcf0b,c7715fd1) -,S(709f8227,9264c99f,86b59a7b,ef14c189,be875b49,e00cb64c,f9dbb643,10f50fc9,168027f0,cd28d2be,8a69064b,468e4de5,3d4903ff,faaaf628,83f15031,58960d10) -,S(62aa200d,cbd1240b,a252e725,a333f21c,8a2e9d5e,fbf18cdb,e1567ff9,29fb4ba3,19aafd6c,7017bdbc,4b906b46,843e41ac,1ec3282b,12dee1b7,b18e3f28,9e0a1347) -,S(2ba73958,8ed54646,fa9f2389,802e2ab9,e123987f,c881ae11,f38f10ac,b882c09e,f37daa1c,9c0a98ae,f86cc45d,34801353,d8f8a193,77518423,721f3e12,375a25a6) -,S(8672b9cc,e8fbb69a,ae5c0f54,9b59dfe1,e266e9e0,3592a397,7314e6f,79005de8,20d8476a,efb61c79,adcaac68,fbf9eae,c411e875,a66b5aa3,99a97a86,9b05af65) -,S(334cb002,84202999,79fdbac1,5ee5c17,1f32bee6,133300ed,a26571e8,bdab6ab5,8827d99f,3da7878f,46b45bfd,579c5cb8,e4e972b6,49d6438d,96e5a188,5aa574d4) -,S(32b30e07,d260ec07,354cad6a,2f64f81c,e9f25f4e,47bf1afe,602f229a,35ac6d4d,71ffcf0d,64ee9078,6f290418,1126c44e,5c5e3688,f3063941,85660874,3c3c0427) -,S(e5099658,7a4b4e63,43e401ff,299e9bfb,3b5ce402,5c38fa05,761e600,a39a8451,7b0382a8,65429a86,94eacccf,5c6b3380,683a3916,70fc7241,f132c465,b3bb2ece) -,S(b3872c4c,2bf539bc,e0aea035,3b3d786d,ca684121,29db66ab,d316e930,e5d6477d,7ce04af,e4c8c86f,3b37ed1f,a9dd4161,59391c71,22d0f4f9,2424d090,901e285) -,S(d2b56fdf,9156e3ab,2e414d96,49f4c418,6095e74,a2df8908,f3b406de,9935d07b,443c2c1b,67668c56,a84b4925,946a8e5f,b06a33af,371552aa,adc3b500,efe3b23f) -,S(f69867e,1074c765,923f32e1,ec9f41b3,4e8288fd,62b0a081,15db15a9,f37fbacb,fd6c6e25,2a11a516,9ce04c6e,d719c22b,68709be7,6fdd0e58,cd0505c6,413fca16) -,S(bc1830b4,a9ab11c1,ad8778c8,688fccec,cae23898,555b6579,62670d8a,b9e64988,b6244089,f3c46133,1979a0fa,f3d0c8f2,8e95cdcb,12db9ea5,b6d95ac4,c22e3c81) -,S(fabaae21,dc729fda,98c4bbe8,3cd5fb92,126cfa1e,a21f43b7,445e4b47,f38dbafc,1b569775,64465832,c73513b3,ed6aed9f,177ce1ba,b2c09fbc,c4c33600,582d8cdc) -,S(93386101,4d5d4c3d,f912497e,a248d8e3,bcd3fc03,216dd57b,5473d96d,791f8bd4,3d8fc96a,c141163c,4ff3add5,44a6ad71,9e57f22b,8e806d95,1d630fa3,6c936725) -,S(c5312d5f,85c42820,59546b8e,ec6b186e,da0a4324,d30147f2,94a83fe,a6fd07f8,f8ae6e2a,79ba0756,523be12c,8d544734,332898e8,b35b651b,edaf806c,45d2992f) -,S(a08f2496,52c52f40,6db75c4d,da022f41,b73b1128,11aa7388,558480b5,f203b057,a396c7de,9ab5e1d9,5e9aa925,1ecfe3ca,191d7a25,37c4cccc,845dc745,2f3eb2e5) -,S(93d5330f,e8df6fa6,a74b34f,a251a6,a036e0b5,89b8a05b,c525e4bd,40f634df,ca15faea,10f424e5,5d6774f7,7c87da28,c4df567,7d153a08,f5ac560b,71838756) -,S(4622bcc,dfcab72b,e850a994,1f652110,5c35b813,f05a4f6,17055f92,aab51fa2,d960702d,31eeb256,d25cd245,695b53c8,e883d2a4,60965a8c,d29b41e9,d7ca2d4f) -,S(a326036c,7dd885d9,94ba5872,8138c30d,fb6c83e,d17c8d88,7aee086,e0ef9fe5,b465ce69,3719a155,31caafcd,e7689a17,456a6ce1,c75e5a53,4893cd67,32cb9bf7) -,S(2354417e,19637e79,71b0c887,bfa5c553,f3d5e7a9,84a6c946,b1d20b5a,7eef77a5,815a9721,b6ead3cb,b254fbf9,9f34f409,ea740053,3cf4ed4d,2169f48b,29f4bd4b) -,S(9d346d6d,fc53174f,5cda746b,23810d7,3a407819,ddd5df9f,2b07cc8b,b7ce6fca,9b6cc06b,64293e5c,a55a8ff9,f1e90551,4a199b03,df08e9b9,8512b357,9776c806) -,S(73c82b8e,c643a7b7,f95f000a,debe210f,bba638b4,5508564,bb5a3330,fd48dd01,fff15699,a0885c61,fe35f61b,84cb2bda,7d2acf5c,df0d6f07,5fff1369,805b614) -,S(902469d5,a0b2d5d1,cf931672,88506b95,f2d29bf,6ca291af,c9b39cbf,fc798ac8,356d011,d71c769d,342378bf,fcafe4ff,cd78addb,abe8b0d4,fa63de89,1fc3ade4) -,S(e670a0fb,3a0c86f0,53523afb,819b8944,dc4013e9,fd500371,b1efe23e,1f110637,869136b,cd13dcb2,157db5a3,d07e59ef,272557e0,9dcb250a,9bf659df,260b31b8) -,S(f3fef06d,526581e6,b0f68e27,cfb9cc9,b57f11e5,849545fc,b9ad3d5b,8a05c395,32b2e997,144420ec,c4c45176,efa5fbbd,570752d1,4b092f4,ff375544,19b8f553) -,S(72a37663,3958d844,560fc28a,8cc19d88,f942c09c,471d2cac,70ca5d39,396a05bd,de9b1b0e,6e121070,f684b3b8,402e8d8d,729ce846,d2f7ba8,503f4548,735ee1ad) -,S(38b78ad9,c43b7def,4119c3a8,190cde68,4172894f,a84cdae2,2b637bd8,805300b0,a181567,6c4f5f51,87204f17,5bff32e9,de7cc69,dc851c84,23de74a8,b3d01e6f) -,S(db968ac8,1d2e7c53,6c66fac9,e194fb23,540e2e89,8cbd3af,68e158ff,2b34752e,4d5c57ab,79d9972b,ac6b4af0,a6347271,4179e8e,fd14c769,a24e5a73,aab48a0a) -,S(2ace1679,2d3a4d83,71114f28,c1ed35b2,505dd4f9,97c72435,a145d367,a8aad318,5314312a,246874e4,cec63b87,f685f6d1,405b0ef,a1ae3539,cc88e73f,3626f625) -,S(32d80e69,c390ded,db8a4600,862727c4,bb1fda18,2563277e,852f93af,3dbae108,3c7d96f,ea89d06a,6d3cb3f8,181f7cdb,bc1c3e12,3d9f1d08,cbd557a9,60dc7c07) -,S(3ef49e8a,e7fe6b40,628e61a2,945db3cb,f1bf050d,e525d521,d8e8a408,76ee3908,4381c75c,62f45fb2,4d431b54,d63115af,3ff72d27,58c3c92b,d3d1de08,1a123f2) -,S(853808d5,cdb82cd0,39b517d4,1c88d7b0,e280ee6,59e5c640,5aa27542,3c9722da,c1677c44,9b2a9626,698a652f,81722242,3ed18d03,92d4200f,b4dc229f,5f7e8f5e) -,S(572fd483,490c05fe,857520bd,8861fccb,306ee4f3,29adef49,58c1db78,1fc8584f,82acc906,10392302,cf0107c0,6b3b6194,d38e9155,b31ebca0,be300036,3413f4a5) -,S(b1cbabb2,9aa8ca31,75aa9a2d,d4d956e4,fa771344,d4592481,38c93583,376e1386,888cc0f1,7f9afdf0,6ba1de03,41409c1,265cb2f6,c015fc,bc58d2dd,66292ec9) -,S(f856cb92,42393134,7580a65a,149a6e81,2c5c960d,670701a1,6ddbbb98,2f6bab20,c33511ba,192c00e9,991f580f,65c111df,77d9d6c2,d5d63869,c5595011,48536674) -,S(e1601cd4,773e129e,2c042887,b56bbb3b,9eed92fb,6c128e23,fffc3a7,ee73920e,180748c8,a38c7796,ee247c71,49ba1fcc,a78648c,a0508ec9,6f4a016f,301054ca) -,S(98ee20d4,5ffb6177,5ca206a5,b0cbf1d8,e8b37cab,97489534,a98928e3,367c7e72,2df4ace1,ea42db51,68ab5e6e,88fc405d,854b70e0,4521bc30,6978e465,6273c610) -,S(4796ca57,acde905a,31dcfe95,bedd1e13,5417bc41,f5acc246,ec0ad4ee,ddfe179f,7413f522,395a3802,b37637e5,9564c239,5bc565a3,463f815f,8ff962a1,f0a367a8) -,S(b367c864,38adb0b8,d5b627fd,56c7df9f,cfd55536,9abbdd40,6c68bdd,1a341200,c0364744,b99e816,7982f365,72268702,b4986cf5,c9c5749d,fd22499e,2e8fba51) -,S(db36884b,723ddecf,7e2244c0,20de844,e740760a,4f27d386,a747f4a7,88914d29,8ae487cc,2a743a3c,2a1e0750,7def0f2b,fef90e24,fda0e3b4,e5f3333,7d79e023) -,S(65971818,f71c212b,a8e45821,31eef4f9,76b4732e,6c6c3123,ccf5c6a0,99a316c4,415f6791,353350d3,3b087f39,13761119,526a2831,c70375db,4cd07754,e13604db) -,S(f2f4eb3a,13a8f4b2,42182a63,97eb6cd9,9053903f,961a1338,fcbccac7,60ebd65a,a575d67b,667e94d7,20adc8b7,4eab8ebc,18811b3f,3a3bcb6e,7950cafe,8ef9ca8) -,S(a24e7a0d,a058f0c6,3328fa51,fd3c927f,884b3f77,cc068a47,e8c6b4d3,1d113a49,be8db830,79aca569,9eb2fe3f,829719d5,bcee615,645e4c81,a9a7212f,450ef78b) -,S(e59a3ccb,77e11797,7db6cc32,5ebd5981,42212da7,48f0a4b8,981db72,41efad5a,a8e07545,fdda2668,cc0a10a2,2389a2d8,d6903416,a4a05299,9d4c2d4e,4a800d9) -,S(3191b263,a3c70be5,bec721f9,3dabe9c9,fc6c1a75,aaa94e9f,daf6060,fe4b8f32,339192cc,1c7a9bc7,2a9a87c4,ea3cbab0,c7af7b27,53e74491,717b1f99,5df38a96) -,S(63dd5fc6,4f9ddb0,8fd47e27,5e839b20,12f408e5,3c139463,8b97874f,9187023a,1af048b4,2e8b7e6,d456cccf,d12ef7ef,67e0910,4162239b,84f35cbc,8504bd9a) -,S(a92e457,cd8312ec,cb87229b,7f751c4b,2e1d8640,c2b8e5c1,2d3dbf4b,671bcf13,d7aedb56,5447eb5d,18449241,3a07d672,be46ab4f,3d5b4b3f,551f292e,5ffba768) -,S(1ee6b970,b9e09d22,2b20f02,14f00bb4,4789f55e,585f35ba,6c0dd6f8,39b10495,7c910fec,eff9eef5,d1a3c8a0,46252885,9dcf73bb,d4a0b2be,3f8d10e0,dc9e9462) -,S(b19c23b9,c2ac1957,5328d7c,43d04870,1abe9e97,30285ceb,e4fd1659,8f06a76a,79a811be,c07c8b70,6f380f8c,fe369e45,c605607c,d08c8a49,2745b283,37a38398) -,S(3c20db9f,9ed35fc2,7c0888f5,e266a455,4f3fbf98,b8b2a016,b1e9aef3,14f49a5,bb3ac294,3f29e63a,f610815a,4a1e5a12,9327c1b5,ccf489ea,7d8950e3,5bfbc4d5) -,S(fd1ccdba,b4746e9e,44eb5904,d338244,efa29ffc,8ce8014,f6b922c5,2eea4389,e1065546,52146f90,fa52439f,c43ce4eb,73961a52,10f6c040,97a82032,9a8df06e) -,S(e30fd18e,abdeb8a6,ef252dc7,3c2b0d75,83641a29,8db37ab5,1e2da099,9b64020c,49663672,1824f481,962bcab8,6716eb41,8e195d29,6afe9704,cfbc24c1,28dce88b) -,S(4bc1f789,26ddf930,e1aea784,83a9dc09,5cd72300,5540548,e6e217e7,515bda37,966b32b6,95dc1b00,8dcbfa2e,734bd9ab,36d8a26c,2a52c471,63a4cfcd,d200ca69) -,S(23d3e27b,9c864b8b,40f0f7d2,6ece9bc4,9004f98e,d46b539a,affffea1,54f036d4,be4617eb,f680a27c,cc4143d6,ac150d51,b3dfefbb,2892a6c7,1b36c794,8ac0b05d) -,S(28adcbd0,14cd3b70,f46e0a89,477b5cc0,4a513091,cb6c1aab,56de4894,3e6009c0,7c49a838,75204cca,38f250b4,608cfe4c,25040dc7,3ded4fda,f4a92cce,fce31601) -,S(776084b8,a86f0823,a5044ab8,70d84f60,ea52ec7b,a545ea0c,c86f219f,1ca29d08,60bbbecb,1048d250,b410bc38,49e567db,def17272,58570b2c,d0834532,581c60db) -,S(45df2e0f,fd32ef48,95d9667b,c6044951,e3db94b9,ed6af5fb,d4fe1e7d,228f2350,a732464b,1a8cfe06,69e4076e,d4164b98,4de155cb,68bb3994,73fd7918,63eaf095) -,S(6904976b,46a5fd1f,a74bff80,c493a2fc,8ae9bbe8,783cfebe,7f69f0e1,be7dd7ea,19d071b8,df9d1436,6241a22,1a00b340,30f1df45,5e66fcfd,5ad621ae,ca2c3e64) -,S(849d8728,f977d075,a8de805c,8e80980f,e01def35,1ee80f0b,ef528e85,29aef659,d84955c4,6c886283,b9d7adad,bc069d0d,8042dd9a,ec7246ff,edf31594,ae5bf428) -,S(e3d64b4c,234506e6,e7facec,8d7534ac,54588dc7,ea685281,e27c6746,472d58eb,4a32ad3c,cf822a84,74447baf,68aea598,11a9c839,4c9970ef,bc61f363,ae5a36eb) -,S(f41c7928,57d15a31,19b6f132,3b67639a,889877aa,e9213ece,c787d53,5463bbaa,73cfcd0e,c84c55,4d007594,152d9ddc,630c458e,7ea456d0,7cc60503,794d9328) -,S(e1d21747,47ab84c,e47a4a02,caed939f,e0cba1c,41e7b21d,67f52fd7,79186079,17b0b628,aa4bc0a3,ed9728a3,e24a8101,fb26da66,9ac92f63,af81aafe,7db2b668) -,S(a8a0018a,f8f86795,3189da2d,d52b4db0,5d7ddb4b,8d290c80,95a8e7dc,d86ef1d8,8bb9606c,84b88a1e,df980c7e,9360823e,25b927d7,9cab4c17,fc8aba7d,6826518b) -,S(7383c671,6ee05e44,daba57c0,50ebda60,e4e0c0e1,3df338f4,cd8d627f,736fffed,3bdcb946,5f164a74,638cb973,fc77daaf,38eafd48,9521cba0,4ad896c,8e89f0e0) -,S(61fa7e1c,8bc8ac97,96be6431,20858063,1ca36af4,520cc1e,858f90b,ad372dfd,3f0d6768,36c3e694,32287909,c8841de0,a5f646b0,94b0c207,8d634486,c3eba33d) -,S(86029e2b,ca0ac601,99092def,cf4882a8,b4f14349,43bf116d,3cb310a3,b2c4a740,b8be906e,cd9056f0,f3261cff,d12216c8,ef5f1553,dd708480,15463b7d,241c2f7c) -,S(e172f7e5,912aa487,589d6c4c,d0d6b9ab,48c4a6b0,5fc5f90e,2f6474c0,4fad95cc,edbd23c1,2b0a0ed3,b899920c,e8b64d7d,d7bfd79,5009c290,ea0673dc,8acc401) -,S(7986ba8d,322efc24,8b7b22ab,f838de93,2d931c78,cd6a8616,d1f37dbe,32873494,693eab22,4c750592,319b7544,d29fe0c,2420a5d3,d3b7e01e,e6ebc968,12a13634) -,S(ba594138,4a727673,7600a6d8,8d36b133,400bb5d3,6a8a9d46,3e8c65c,e1e00383,746f4e28,bc1b812b,227fc953,531058bf,d9c68545,2f6219bd,86799dbf,3c2ce557) -,S(45ff41c9,92d6b117,c86eeb77,bb17789f,6bf96cd7,2cf0c6b9,802af869,20476c8f,9324f5bf,6422e3ae,2010c9e1,27167d8,4f522e86,87fc95cb,ec3d6972,2002b59f) -,S(bad79e35,487a4da0,7171c282,e8666ed4,d00bada4,d9576a7d,9a93ecc3,c16ed68f,19397a2e,efb184a4,31a02e12,91db0cd4,5b153517,9038a920,7a6d50dc,787b57d2) -,S(ddfe2107,2d8875ec,60c4d583,59755bfc,22cf890d,d3665b79,cfa403bc,9e3c8a41,c62bd917,491d0a8a,9215674c,28c28872,8dbe0d3f,87c10d90,ce22b608,473f62e7) -,S(925f6a53,c07f923f,968ccadf,bef9d95c,d7594269,a3d9fa64,b1180edb,667eb299,1080e8ff,1f918e6,6f08b26b,7f9cee48,58f00038,b8ca50b7,b2939960,b1e7809c) -,S(c28e49dd,a75f0283,38e5d2c7,d1f03af0,12768bd0,6b0e0d0d,87878ba8,2720dd80,670f8989,c941a49b,cc512c5b,4987e167,ec5ae6b4,d7f68a98,331845ab,5d0db12b) -,S(7a9053e,95035be8,8188c196,d5e8e05a,b21dae48,d59406f3,7b9f86ca,2c837cbb,40ee088e,8e7694b7,994774e7,9d097d76,6de026f6,f7fbe352,e7f2bd0f,443a7e1c) -,S(33af78ea,bfbb00c5,4d88ef81,e9661b16,e0b32c85,a1b61b95,6c6a79fd,e036aa2,713e7aaf,537a796,c4d79644,c855d0b,15331988,5ef4629,d8048c69,d3cfd3c0) -,S(c588d014,5a3f3d33,29695573,96d674c3,1326dfa4,797d63d,f9a0c720,49583bd0,b5c0cfd1,6c67cdad,ababaa8f,cfd2cd76,7f747024,8caf60d7,37531c66,ac53cdfa) -,S(96b3d5ed,b93742c6,7c48ef12,c649341b,97223f22,1f0edd5a,2f2ab523,8038d29e,db475caa,38a3a05d,3719a2e6,4ce7b4ed,bf25fe57,4b28d6aa,9961ec0c,b0e44c4e) -,S(412f4b6e,3d894ee6,fb0cb00b,14662a9c,1eea3a42,5a286782,a62da77f,5644f0c7,a84ef636,ab9bc805,bffde813,93874429,a8503e89,8c03f1d6,f139af86,f6a676fe) -,S(25f0a785,c7b43028,52f1421d,a32c418d,32fdfdc4,89c39049,3794e1fa,e4563252,efeb090d,457190b5,89c953a3,aebef406,da716af5,1dc6e334,a0226883,6004e4bc) -,S(50fd4ab7,f367faf4,acb4403a,49ea3e7f,f02fed58,4327acfd,e0bd58a4,ed741c6f,78abc1a7,3c9dcd48,6520cb52,adb1c3a,2d08abcf,a079607e,a56307c6,3d46dd5f) -,S(157583d4,cfaf7f79,33b8fa66,430f107e,c357621f,4b94f313,bbcfbed1,46a477a,9aa6b235,ce8cd1fe,60cd4355,c46d4859,fe35ed8d,659d2aaf,fc09cdea,297e8db5) -,S(3c44bb62,5d262603,e44affc1,65b35976,f2edcedf,8be6b494,f4b3bc4a,5b3300be,88b1c561,67973ab8,5ecd4594,90598152,1ef0e8c7,1ff707b9,79ec2bf,3cbc2535) -,S(31d4264d,e1606b97,f2f71d19,33f23cc4,8fc5d9c6,e087dd93,5ee25b8f,ba298958,460609c0,a3aa1d26,2865180c,98555b98,c8e41db6,2e62b2c4,4ae01190,718251cb) -,S(1f551f0a,8ff14724,60ab206d,3dc1834b,352d1d1d,80a8fb78,a87247ae,5d03ad2f,24253c06,a4c8b148,db944f81,802bee34,fcb97ab6,50957b32,eccea33e,c116a6e3) -,S(de2c4e1d,27f08407,31334311,9ff5a8c4,206a1f73,2aaec3a8,7aab6bb5,c1cf333e,dc813ba1,40fecd3a,31ff4a8e,41fa498d,9226ca2a,cb2d5a71,c5a5cfe2,8195170d) -,S(6fdc5db2,adf54ac8,132c4a22,c382c2f0,c1f54bd1,8aed5620,a54bc4c1,18a95612,db3fa4e5,f318e94d,c0c11053,61d21643,cf60b0ca,a6dc4d26,944e8915,970e221e) -,S(c7eb76c6,ea0e1c51,a3aea6f4,dd7eba10,bb76650d,85df0fc,7fd77b73,53680603,5ae1c1d7,b788092a,3c41c3d,7bc32ef2,a4f4a39,a82b53e0,e6f47712,df5bf655) -,S(c81505a2,b7e78b5b,64ce048e,6312bfba,1a52c7b7,8219d857,b4813a98,c8aa89ed,46db2842,6d6ce211,5e1e49be,459f033d,c222be7f,96b247fa,87d5dfc0,df096806) -,S(cad75255,15f9c3d5,8705ff0d,83ac3508,f7dec312,bdc71c9,a17eb9e,78503bf8,32b36a02,76cfdb97,ecd2ddc7,638e4d61,6231be5,25b6b4c5,2d19c12c,6e6bd719) -,S(94d22144,e22b7e30,56eca8a4,7d6b15d8,f17f3c65,82533fab,c70e900d,be4cdd25,12c0760d,5fef2f85,d89dfbbd,bd0124cb,828bf72d,79b4ae5f,6121a84d,47d93bf9) -,S(325c5c23,ef00601f,ddf52040,7721bde2,13cba19f,c0f2e225,3b112b8b,916731a3,59d3cb98,c09c1643,993f3dd3,64c7d29,5cb38cb2,45d8f70e,9628e5ee,d62498e0) -,S(9c907089,544b8316,4a251516,81bdfda6,7d187438,3e7f4a7c,da96d861,91ee2318,f639dee7,e7010630,364539eb,5c225059,547117de,9fbe4911,d9718e6f,8372d20d) -,S(34f14807,ede9c06c,4cb2a1d8,97a4fb81,ec5544dc,eac1bfc0,f32f9835,302b7a82,78437a8c,ec6aa228,f5f18813,a68bde68,3c54c367,5d6be482,8d01f2a4,96d9c57) -,S(9498d30b,3f080828,e03d459a,fcb81fdd,490b47ff,c344d75,3887b600,1639788b,7a5c8305,b97abe3e,b241627d,c5187a9c,677865b3,567cfd2e,ce136852,e42522f7) -,S(eba08f6f,efd36e37,aa53ec32,d3cef88e,5d4f36ff,ebb978c8,76d452f5,7754f226,fe0e66b5,43aa54ca,7afeade9,b38cbe0b,39e17178,4d029470,608c7e38,bd2015c1) -,S(555d4bc2,bd21729,f6119b77,ae8c9bce,c8ef49bd,992cde50,4c794484,7240091b,cccebdb8,69521e33,2ca86941,593eb4a7,6c9052ff,a54f8315,d30119cc,7f437b54) -,S(33729b9c,19da3474,42f33833,d1723d45,3f3060ec,c692d823,679f087b,ffe8872,a94b6a4f,283af604,eb885405,6bfb8044,fac2f007,d7ebc800,b4abd64c,5c34fc30) -,S(2a1a889f,afe64678,647b060a,73ab92cf,78124ee0,d44c7c32,d8ae15e0,df1dc11,626f963d,3bf11f8e,686ba46b,e6dbbf0e,75aba0d0,7ef91218,98605ff3,fc8b75d8) -,S(4702854c,a303e6fc,ffc62f70,258bb2f5,639148b3,4e3927ff,f2dbcb0b,7c197d6f,7da261b2,8513257c,d1475c2d,e059372e,2da76eb3,f3b2c51,95c44447,d71e1156) -,S(7002edc5,a0cc23a0,65015cae,6e49e7b,51d90cfd,7da04e03,4857c596,cd319c5b,6f2845bd,6b7aa58,7ad2d2ae,19fd6115,78c47b56,84fc6975,db63e230,c3db73bb) -,S(273294d4,483d610d,b2169f05,71d5450f,f4cc5bc8,725d8ae6,7c1adf0b,6f48d485,99b241a2,ffec9e0,a039a003,18239aa2,a71e3cc1,1cfbb6d3,7268874b,67d942b1) -,S(1beccf82,3055b440,fad26a53,5a852a5d,710c72a,c4d28e83,b0335e8f,e98c9a69,f3ab566,ac0eee20,7c8ce0a4,d471eac,2c5db716,5e24b489,e2fde03f,7b8aecfc) -,S(dbe4eecf,4f033d53,5d949cae,c8fe672c,a1902323,77892197,fae8e192,53128160,b3f50bc7,927f0e5b,56241c72,24960fc5,896fc806,1c0a8a1f,5fd3d47c,d5aa566f) -,S(6643fc75,bed80c69,4591887a,5dc573ff,caf7f484,b0ae2631,133ecf4a,39bd1e20,4701285,f7ac7c93,bac1875f,dc4a26e3,8ec1e69c,293c3b7a,1f8b5c5f,878d58e5) -,S(99f90bde,cf1dcd5e,7158280,53f820e7,ef19d936,bca63f14,516342fe,5422a21,a04dfd30,6dfc615b,5390a86,8bebead6,5cfd7719,33f91e2a,180d2d79,b99cd4fd) -,S(54e7ce48,3184b7fe,45fb4e35,192b5678,bcf71f7e,49c033e,aad1dd32,86e33433,cac2833b,65ba9cb7,83a8b85c,b7f4e4e2,4d4f8546,3c6a2c3c,4decec88,14c0e8ef) -,S(cf864a4f,fb60993e,444f4e7b,8f4a9973,4705aa16,295627d3,1f7686b8,4bf02e08,7a98d20f,b736eb4d,465db874,ce98bdf1,6b8a1951,7744aa51,af276c7c,db6f1bde) -,S(6ff160d6,516fff91,5ae2cd45,7a98afe2,a2569345,60a7f26,c9e07212,6d59d1ae,5d1f1355,bf1410ac,e4f8b415,350f9c75,7db5d5ed,1f34de,aff5c197,b4eedc4a) -,S(9adba62,aefd2690,1d77f2a2,c6287da9,a56fe35b,3702da46,f231fe4c,9f5dfcc9,ba58ec45,cb4a359b,7126af,fd2c4bdd,2e708d43,41d96e7e,4825f153,abb04161) -,S(204ea41e,bbdcdc48,cd4ea945,72c10dfe,b5d90060,e9dcf5d6,52c0e2aa,14a2402d,7b2889ac,a1952f3c,b2c5db8a,9924a6fa,fb0b9e32,3ec09809,789f780b,ac36ae38) -,S(f7d6c669,364d3114,225a6826,c20d26ba,a4b4f190,e842696a,82aace97,5fc8ba22,15abb177,b42538c5,67d160,cb3c761b,1ff47cf4,4b0cbd16,36f67a5c,879d3470) -,S(7bc4d30a,87dd28c7,8b066e00,c02bd221,e50a7e64,45b57f0d,cb466f27,7d352587,f4ed4854,2e7e0164,da66e0c9,fcb04a1e,6efbc9c1,206b552e,c68cab96,d0c294d4) -,S(55442584,b046bee6,c245dfb9,59f20629,c200eb21,b42509d7,8564943b,1e316ef1,2e2aa971,c8111ed9,6666353a,103f2e4e,a29c4162,d19da280,905031a9,48580d82) -,S(8e7df8c0,de88903e,71224c97,3a8ca65a,923f872,841f2dcc,bcd69e64,b1dce1eb,e4153083,9ae86d51,e7147873,f1fba8db,c31205e2,34c94662,52ae43c1,25d2a0cc) -,S(672321dc,69d8aa18,25569d06,65fae079,b84a9bc9,35bda491,5d546f51,c651de8f,8ad6430b,8708897d,be809ab1,803a6eee,f977b1f1,6b34c188,d333d6f6,e7ef005f) -,S(f4e2bbc1,43e99b00,52032718,285d7698,1b8beb9a,f693dbfc,2d20f472,89ac3abc,e54990f5,dc330eab,2e722b7f,70cd426f,6d80e93e,205eba89,7eabf0b1,5d651a2a) -,S(5aa3aa5f,c6d2258c,907c7275,805c160a,72694f46,6b5fdad8,9134f1,d39ffff,22d72170,617eafa5,b843e82b,5f670cc2,3146aa98,cb07644a,7f4c0600,48ea9531) -,S(34752ff9,d2bf499a,c6b3acbd,1b78633c,9e9a31ea,45c34383,be3eb008,7be2e7ef,b53ea374,2cf3d886,51f7d076,3f67c8bb,39d73ca9,8306bedd,91a6db47,2c1104f8) -,S(d6502624,2ea44f7,d9b4c9b,5069e1c5,88977062,db2bad6b,51735366,27047327,52f5c99a,f2f2a8be,c034db3f,b573757e,d8014321,86db2c28,8c7151fc,4ab16f2d) -,S(52b3aec6,553d025f,d164a0e0,b1f39abd,915d4a9,ed5db2ac,b4593c30,11f4cc9,51547402,1c17b2bb,9d401683,931b25d7,77af18bc,e0e7bba2,432a7717,f4e2f8c9) -,S(8cbb677e,f7979224,12728418,68b79c12,eaa0ec6e,ba4f9b17,4d99547e,827ef9ca,a32809b8,b07e1312,b6a40ec6,411b60be,92974f98,bfedce19,ae590f98,40183f2) -,S(d8f55de0,e2eef17d,e94b1564,d74734b9,3f89f2d6,c317a248,7f1724e3,d531d47b,e9fd46f5,da576370,e0416f71,f271e64c,fa7dc64c,5e086930,523e92c,9ab7d770) -,S(fa6fc9bb,faa2b31f,f9d57301,4777169f,a4ddb8ed,ed4bab79,d0f4cf62,356b6fdb,b6ff57cd,dfdd790c,7aefd1e4,d4b111d8,43a2adcf,9f781b33,1b4420e0,f57d494) -,S(239f028c,e748edd9,69f752d9,abad0498,f9359017,653e6ae6,bb93f09d,61b58e9a,17dffeb7,8831f6ba,7ba463b7,bb7b142d,d55c8aa2,91bdaf7c,644e8ec,14f8b516) -,S(2ef6cbfb,728d976f,99c71db0,5389bba4,ecad3c14,8f2597bd,99af8f74,965e4f3b,19a27ba7,a382078c,3f1ebe8c,1d93a37b,deeef542,cf174273,b411b60f,79b0fd00) -,S(972d732b,9af8315e,88f042f1,3377871e,1a429247,d8537436,98b975d9,33064a0e,308153ba,ba4c3b87,40a380fe,e4bcbba2,a5c2ae3f,25fde1d4,f40af4db,aa4fd28b) -,S(3d378b34,ba4998f1,833aa295,185414be,e788bced,af422ed3,3c4f2747,6e062a4c,46a4559c,9217f919,80887b50,29f75c01,3c3d5238,d3758170,93eda1a8,f2c4c8a3) -,S(fbb2003b,1fc1b3aa,fd32b289,abe3b362,b13d70f2,7d6451e3,76bf882d,395c3087,97c866a5,c462362a,4ceb96bb,9c17db03,f28e5b1d,4e418a81,653a315c,4dfdabd) -,S(28fa94e,8eeab1fa,bd27a9,258e26c4,295efdb7,afb5a47e,6e14de8f,877a0471,f7619d0a,f2eee8f3,c0c7b5e2,8ce9d0f,62221919,4d1762a5,5145a909,9d23276) -,S(4708a285,7eb9c115,71627ede,6fa8fe29,4be27233,8798f25,c12cca0e,f9308ae9,f35f9964,2e773990,b2e0ab60,1a92cf56,85403466,87a8c35,50e36b91,ca4fa449) -,S(93408097,6ff4b874,d88903dc,b3ceed6e,a82427cb,36b62c6a,6364f2f8,9848a62f,e25a6962,d4e26764,9ab2d4fe,a0babf7,daf64d48,98bc60ae,ff3cfb63,e95f3c6f) -,S(f4a42ba0,818201ca,e3195da9,3a566623,9e0d24dd,256cbcac,3959dbc,720ddf9a,8fd26fcc,be3eff0,75d194af,e7391285,10bd4c8e,7230f96a,60fd27e0,a000f86) -,S(c5ada616,e65bcd40,cf39ef6,197e0a97,791cacef,b41b0991,9c51b166,e3a6240c,e4c65d68,fe41c62d,c85b0b32,39106ae9,cc26787a,60d351a0,4a7008a7,f96eb8c3) -,S(7c193ec3,d3f1d91b,cbd7c62e,5061a5a5,e8b1fa48,561102ba,ca2ae100,80c640e7,cc7cf895,511408f3,e400ff31,8a53685,3b8e068,1d4b333a,26b59cad,97873ccd) -,S(77542543,8e7cf128,32165629,3e6a1c19,22b76355,1ec716f1,d96002b0,ad1bd3c3,3747169d,212c37be,1906eec2,8860af9,edf7d932,c187c4,debbf800,8bd2137f) -,S(92dd5399,fa75e786,fa5c0f7f,90abd1a8,bb48ff43,e54dac5a,3b9990f6,27d90992,5cb1be8e,f93783e0,c2e5c824,ac6c5348,ee493231,9932e9a4,6e54921,3f11b7ba) -,S(c1770828,468eeb90,10b55053,2a532fe0,4f66e7a7,b7a1cb37,6eb6ddef,d693157d,da5643d,a0147d47,fd29e262,f61ae4a2,70e5e9a,77a76bc2,d2e7d24a,819a2e11) -,S(1372e116,e90ae522,4649a534,111392fd,a8baabe5,be8a8ad5,33cfddcc,af6378c8,5efbd4a2,695775bb,dc38c2aa,f8da6f45,1d0a1cf3,2bc584d6,e9b2b6e5,c8346af9) -,S(2bbdf21e,9fa1a2b2,bcd52009,7f30929d,5e2b7fa,e1038c00,8f32d86a,65dda936,51b78998,6008bddc,616c0dcd,2a883361,1806ebcc,5843b64c,b0ba02c9,339d45ec) -,S(36694ca4,d0495ed7,78230d49,e6f21217,9b63cc7c,26ee3f7f,6a7438bd,753005e1,2e49e3f3,bbdcb133,3ff1e17d,b18d5267,a87f48b6,95b5f907,5f5aa0d1,70bc0af8) -,S(243d84b1,dc9ce143,a6913bf8,d13c4aaf,6fbc1373,6bb8a7e8,5e648958,32013b8,39317ad,b6bec71d,ffe3c2dc,6dec5e10,21a3dd83,2dffeb91,108abd5b,6e7f28bf) -,S(1d888387,5255f3f6,838eab82,1a12a8fe,ba6dfde,f190585d,e039542b,2d91ec92,a9d38be2,e919f815,5d633538,d2f0aef3,9ccabdad,dbd912bc,46c2037f,3324b489) -,S(39a21f75,4c0d3376,f7560e2a,a743751d,5512d628,7a480955,6456f9ac,b1be3765,3cf324a5,2a7fd79e,3bc188c4,d55bb449,ef4950b1,3a4531bd,e0b2ea9d,4035e005) -,S(a10ff60c,d8e25df2,a1d394a9,52c67f6d,18ab0a1f,a56569e9,48d9278e,b42e21c8,b45f2d63,3ce82ef8,1dc0c0bd,4f891473,89fd2b35,f02cb237,bfd4f502,df9e991) -,S(bc269792,d5042f7,1051f7a6,46b971f9,bb801acd,dc24a2b2,5bbc459e,b7bcbcb1,b70445fc,1c032061,61b01530,c9205d7e,c7fab6de,1d83f1f4,78b35bd7,71235665) -,S(3d7279fe,fd5a3682,a82a7f95,d1db4442,5f0ef448,f6bccda9,9a61c240,9037cb95,df5226ca,e6365b7e,22b42cca,2ba2494d,9a2ea193,cd92162,2de6602f,70159740) -,S(e0c56d30,ef92af00,b936c2bd,951b3d51,bc439ad0,e4216e2f,d552c2d5,e8dbe588,c2bd177d,2a75c44,40dbd186,27669a0f,f35189c7,a4873e0f,6484b3b,68555fee) -,S(9bf960e5,2b7bbf52,fd839830,634baf1c,f0d6e332,4272bc15,d9999ae2,7873315b,b28719d,20e01dcc,b0016cb1,6a453739,551862f7,d9cc81c9,6662387,1d8d0405) -,S(20df196b,e60ba71a,e617a6b1,44757e0e,87fffb45,d447d9dc,d5480a0,34351198,9c722d43,c0d071b,a07d4953,9ad0abaa,f12ba358,42fee0ae,9960ce1f,26eb07d8) -,S(843c136,208b40b,9459693d,8154980,455a5f71,23b5f633,a26661d,ca9bac17,d5b5bd8d,9095fc40,d2d1820d,31dba542,d0c74f23,86770ede,c9b4df46,f2f12078) -,S(9109b4df,702c1ea0,dea4ee0c,ab46d6ef,708a3fcb,72f9dc03,e05bc722,408d11a0,75baa2c1,8be5801c,b5315195,4c2c3024,7348e9c7,913bb242,cf4ecc8b,96dc507a) -,S(f10cd1f5,c960a9bb,12adff03,c203c59d,8e51552e,3727edb2,329eef3c,5991113c,a84ac8e1,6f65daa6,16574689,8fee662c,9d2e03c6,4796151b,8f3f0bf1,5e8c465a) -,S(9f07713c,ffd3602f,ad077b69,a8a5f539,ae0d6d0,df58ba07,1eafe6ad,10e747a8,adfcc873,42b59083,cdc3d735,782f8ec1,cbb4ea3a,57970afe,58cd5e5c,8fee867b) -,S(6d1d9d0e,32905734,13b2b870,fff8978c,5ce9ec6c,b120d9f3,64063342,cd95801a,650be4a8,95d3b602,4d745f7c,23bbdce3,25a3f597,922e50ef,ba154f8c,6831018f) -,S(497185a5,6b3acc94,7a27791c,7e1fb149,5c649f99,dc767fa7,12820cc6,6cdcbd82,7d511b7c,11dae1b1,7e4078b2,fe7565a0,f33ce5bf,74181c3d,f5b6a951,fe6568c) -,S(fff738f9,848eeb9c,4ddb8bc7,52cd87c1,9a35f7be,14a470a2,c3154ff3,100a743f,106b8a55,cd913c97,76837cdc,f45c58a0,211b979a,17085df5,7bdff373,2f2c38ec) -,S(320391a4,8d3546cb,4466876a,37d60015,41899ef4,5dfc8e38,ccb9021b,981b4830,46f63030,b4559411,e742f303,25707b4b,23fa2d7d,e633800f,9c71205,6651b102) -,S(be44ce40,a925e88d,26937f7f,b7631f18,55879106,122813f9,adf16e00,5d85fe9e,1755ade7,d22e6dc6,7e6806d4,bf44b6e2,ca6948ca,9a418893,24db0266,2b6e1dc4) -,S(8d3f06b1,58ddd609,f83b0531,466fc2a3,da6aa80b,433a92dd,eeb20435,cf33ddae,2d554a99,efde513b,b8b6e5f4,dbd2e942,f1d0a641,98c3df2c,4c74705d,4b37af63) -,S(f814a79c,f258f553,255c1cb3,a054fcc0,d0c71d74,742b6627,210ea846,91596729,119fc95,be48b4b2,23c80c42,fd1f3d45,271ce8a,edeb82dc,31813f75,a32d867d) -,S(95e8fd46,1c37f1db,5da62bfb,ee2ad305,d77e57fb,ef917ec8,109e6425,e942fb60,ddc28b1e,dfdbcda1,aa5ace31,60b458b9,d3d5b1fe,306b4d09,a030302a,8e2db93) -,S(c06543fc,47e18816,bc720604,cfc20826,6f4e5cc0,f436e149,e2dab0e8,a7981e77,22070465,f3a4a7c2,1134819a,c194cc9d,28185431,17ec634e,e6634831,97021441) -,S(4983d95b,3716aefa,4a14d116,bded84e1,fd5b050,bd6001ca,a2b97086,b4d5c68e,1373426d,a2efcd14,333d47bc,ebd3befc,f5e609a6,6fac1b02,80cdae2c,7f0a279) -,S(a2bd5cc6,92e84b97,3ba2cd09,25e0850f,ad8054ed,e6b73ef6,1fdcc958,3eafe6ab,cca6e78a,f9141b1e,6159011b,99f8024d,33d8d797,9795aa4e,4f0b2767,e6a5ce2b) -,S(61c99231,a18f4e73,95076281,b367d084,b8f85226,3117ab60,bf698d4f,6b6d741a,82314b97,9e7f1d30,64861609,a08c019,af886db0,67d49929,9d340814,6e6cbfe5) -,S(4a5acfef,32c55299,3a7114fc,7913321a,d4072a2f,6c6bcdb7,3ed60bfd,6ab34304,7295a29,c06859b2,69bf9f29,64b26dbf,1323e89,4affa4da,9f61b056,9a0c03c9) -,S(e0467755,866f494c,2b36dcb6,c65ecac6,604e5013,4216ad48,7d4f5b68,bb7f4023,dead03c5,974dfa1b,f532f955,826189ad,ae945975,28ece029,d9e5a42c,30b336b3) -,S(686fdf05,c9265fdf,5b54ca74,b5b1e231,c4e8be60,20844596,40dc0d2b,bb215ea7,f4d43e1c,edf9b974,aef950e,bff3677b,c93723f2,c5901710,b6561e53,d57ea7da) -,S(12476985,f9b20c,ea62b7d7,b0d96d2f,e2bcd924,d1f15cb9,fce5ecbb,8bd21253,d3437cb3,9e904fc6,43a7b356,b4389c0b,3f1950f2,43dd7842,e32de16d,2b522004) -,S(656bdcec,9a87c9b2,e5b32291,9f657b,b5eb1e1e,d2fa724e,45388026,2ad17b1b,c7748d0c,47b6e4f7,f63f704b,3fdc08ff,cdfc830,d17c1d11,6aa3dce2,f92fa64d) -,S(5b7f710e,f721612,ca79b24,483ced12,7a3d403e,60ebc04c,3aebeb96,b483e4b5,1b5157a7,f0688aee,634196e8,de5a9eec,11db4b72,bd96b86b,698f7284,bfb08080) -,S(bfca66d0,552ba6f5,5795bf18,40f90d85,2545213d,81d2cdea,bc8d3d04,a1e6b4da,4910b0cc,290d4257,c04c4638,30cb3a10,223043a0,bddd8690,84b6dd1a,f1754e75) -,S(663fa68f,b79dcbbe,4798f8ef,2057bd14,1447c11b,cec70924,7f566032,88496f16,3ace2efa,1f3bbd23,d885598a,91d1f420,a42597a2,ab30f951,f2b27aa6,83c41786) -,S(27cce333,8a3db8f2,1fef2f86,ede68a25,7c1675ae,80cf004,6085f1de,495c4321,7156bd8c,8babe472,eb144a00,263d4fdf,7aefa69f,da2a9c29,4b16a82b,24d373ae) -,S(d49c06c4,52ec5c09,be27940e,13c575ef,b727be4b,1c0e8ce3,5aa5bc4d,64bd9560,2c653518,b298100a,72a66469,f9a03635,5d7ad789,546df3c2,f5175238,e78d18b0) -,S(6960807e,bd028026,d3cecd25,140d3bd6,3d7bf4fd,10afd129,cfa017f7,544ad08a,a785044f,28befae7,2b7cb546,5bda6bdf,6f9a6383,aa9abf4c,f7baeac0,920e7c7c) -,S(8382bf36,54b63a71,a3b75abe,ba57dbae,fc9263c5,5a54faa1,edeb5325,3df8faa1,e05eb9dc,c319cb53,4461da26,9627661e,dc9bef3d,945766dc,b6d0fcf1,849b011) -,S(803b9379,30ec876e,78c8cca9,fa932f22,b7e7059a,f605379a,cc45a3d1,4ab0bffb,7db2341c,5202d1c2,c6fec7d0,b7869471,cb90d1dd,17cd1152,b52af046,55e5790f) -,S(cb4db129,ab6ae9f,11165ff4,f73fab02,cb78fb0e,89647e08,f998ba11,d2c5292c,ccaef9a,1776384b,b5a80ad6,5bb366fe,745c2408,d754ee9e,f6154188,d7d1c9c2) -,S(fab28757,50e9f672,3838be8a,fc070fc7,8fd6af7b,84c9579a,a8152acd,ecd115a2,d59fe028,89cd562d,5397d3b8,3ae85303,764ee931,d9c6e495,6c311490,c0b3f065) -,S(dd879eba,f870ee3d,f6e3f03,60833e12,fbdf844c,d6a5b76c,19802485,6649bbc1,e7bb04c3,a99a5c11,dd7a324c,1d5696c8,b041a12a,c6a538f7,3094716c,9943c55a) -,S(7aa4afbe,29b06a1e,da9319d5,72572b13,1df68f74,1b5f8d8e,d00ccc04,80f8016e,15f79a9f,b77b8587,7f02e3c1,3202b972,423fd00d,937c0d2d,c9d94b17,53fe7130) -#endif -#if WINDOW_G > 12 -,S(9145f3f5,876a3265,5d7fee64,f2d6e660,c34354e9,1571d68b,a19e4cc5,8c39f890,45e0a95d,cf369fd0,5bc9ba7f,da108d6f,37650c1d,5766b6c9,98ecda28,b285d8ff) -,S(5450b752,36fb010d,1ef37afa,2077f3dc,a5a7f6c8,91a21317,13df740f,4511ac9e,a7c7ed57,62bef86d,4de1084d,3ded2d7b,13ff563a,67109ef0,8b6f0180,fe6ba175) -,S(ba6c0d72,5e48de2c,cb8256d6,7417d075,bbf2766f,d13501b8,4c32cf88,c0666a0f,cd2a9132,7137299f,50eda669,3a599032,bdecd64b,91bcc640,5ed186f3,e525e442) -,S(b94821ff,1feeebb4,6fd1006b,798fbdf5,d25a649d,aad58b05,53adb7b3,9605c921,21589ba0,79bb92a2,c7c3d950,c574afcd,f45ccfae,eec4365a,72dc58ab,f9077c05) -,S(46436446,497f7c76,b70e0d7a,5a963cc8,432f14de,93d61f81,98f8879f,da0681d,29344a4e,90c4d810,10da8aab,5ea25e5f,48c367e5,b3ec9239,8a3e608d,49c83a5f) -,S(bd8e5ac6,a2e210be,4959185b,7bcb0cf1,bd3be917,5baa0d08,2bb0b38,e4c1ae1d,6b381be4,6dcc9755,da7773a5,eec888a6,69c6f71a,7c3ec0a9,4edf08aa,2db1fa19) -,S(c27c1e1a,c428a7a5,f4c3405,58ace76d,7fb64593,b3942319,74cd18ff,99f22493,fc95d661,c12f7b3a,1cb1884c,fa9f5994,25108af3,c05e04a4,9544f919,c59cf57c) -,S(a1765561,837e4ca5,5268168e,ed90466c,44c17c01,4040fc02,9e53af22,77eb30d5,8a2dede2,b8d488bf,cd655d0b,30e6e2f7,3032c775,d0fa15ae,cfc8b66c,b6c28eb5) -,S(2bf6930d,35cacc91,87e9279f,678ba368,e9eea737,8300ef93,b03e98c1,81ddbea9,8a2d4d43,3aaa8bb0,3ffee538,38ca8e16,d0f3f930,c35d0db4,6e2fa069,e625209d) -,S(766a7725,9cc5aefd,90f005f4,d6755924,a36d085a,3a5856a,6a066a70,6877c8d7,db3fac97,4fd9e2e7,f05bfad1,5e938ef0,90b46d04,bf40bdc4,171c1e33,48049190) -,S(d25a60cd,953f21d4,5fcc333c,97329da,134196e3,9a913242,88792ff9,18461268,89bf2be8,bd04835f,dbb874e7,12352980,a07ad598,9035270f,397f24ce,790c7863) -,S(c7b28e9e,8b7125b2,6721f467,b665eafd,9bf56986,8ca180b3,60dfe429,cad95d68,ac28d58,b3a7b61a,71f947ed,8bca4768,9ec7bf34,7646a167,b37c3aa7,9e95c398) -,S(e2a5208a,c61f8c29,ada2d7a7,4cfce985,20c29160,f1f7a97,ce8b34dd,7c59bc24,de8ba14,49708a04,ccb4483b,4e90e383,a152ce27,777fce4a,880d9f5b,3dc70830) -,S(e1e8e4cd,2e8df95,d3b2b152,a540967d,6976e001,88287ca5,3e844adf,12e205b1,a5dbc6f9,cdc7547b,cb3f0091,8233723e,d34aa97,f546a491,a77d8cef,43bfc9e2) -,S(b20f0a51,4a684e55,2b228480,3f3b1c2a,3c3143b3,b895f75b,ea454bf0,9d2b6512,bc3db380,676d0d14,9c0b0c3,1941a07c,f7c95585,cd44ec31,e0edda96,e80d02c9) -,S(b71a6923,b1adbf77,94cd9d8d,407ac96f,9582cbc9,b9748949,9cfa696a,c29d3ec,75182389,9d59558f,b93113c8,d38c72d2,7b6d75ee,7679fb1c,89bfce1a,64b4f151) -,S(ca47adac,68ba38d1,8ccef76c,7565788,a82f415f,d9dda65,2004d5c6,a7d3bb3f,bd598ab,1b783382,44035385,e165fd5a,ccd8454c,3969d378,42fad050,4a8701df) -,S(5fade148,aceee9ee,9fb4eeec,edd5e4c9,4fb989c4,d99f65ee,a45f99d0,2d40e441,ba6fca3a,e82e5581,ac5104ca,c8dd2c00,15afd1cb,3943f1cb,5e61dd4c,d73831f0) -,S(767dc9d2,14fccf00,900ba01,a1cf30fa,e834c851,e633849e,8adada63,fe5f84e9,8c650911,aca30e56,2d6b97a5,2fd7cbfd,1a5bcd1,9ae197d6,9ee3215e,64404639) -,S(27f8f961,445e2a20,5daa7648,fc3c06d9,523544d7,477e686b,91d7178b,7e4f06d9,39110b27,82cd7be9,75596bce,6b79e5de,37933242,21be8172,427cdfd,82a73a60) -,S(8de0485b,343b5e4b,ada4070b,f79dde48,8a1b2889,839735bc,6a403165,3f3de668,90305767,6f43e0f7,d7d1c1a4,4c59124a,12fbba72,8302e143,1c2cfae2,ed5729d) -,S(5e43db6c,8770e8ae,8ab8d318,8e700c28,5b6af8a1,eec95fe1,b68e5cc5,952df0ff,6882628d,d85fbcfe,3a2a1091,15e59c78,9aeebb3d,37075f90,ae02a439,506c7aa6) -,S(7db2baab,4bf4300d,e7caf4e3,52df1423,6102863c,edfeb7a0,89311f42,59a4ed54,387561a2,fbbb44be,303fbbcd,685909cd,e553a84c,a3d4c0cb,d33026fe,178e8a84) -,S(96da8525,39106887,d1fdf9e8,232db3e4,cdbefdcc,abb90bbe,fc04d10d,b996c6f1,65271a31,49127341,9fb5d651,3dc33287,45948c92,b7fcc509,4023d300,9bf9edcc) -,S(84eff1cb,14eb1284,f5ba51fa,838b485e,64cd4c0f,acb97b00,81ba7848,add50613,926c9c8,a6540a8d,7b1e602b,6ce818c7,609f4511,32f284fc,7f578c52,a6febd9e) -,S(1eb96371,8e2a2a0f,f5ee6000,7bf94a00,416e6a92,25d59705,7fe19941,e2adfbbe,4870aad8,9635ddfa,dc3d4011,500639aa,d3cf0523,cff0dbb0,9c9f6a1,3005b855) -,S(2994a36a,6ea3f307,1bda8696,baf193df,c75fd4a1,f7683fd8,d454dcb8,77bdc098,e465e8ee,a7273d4c,d786bd0b,e96fd3e8,9969bf03,1b76aeb3,fc82c4c4,bf856766) -,S(25e7fb70,f3d357a2,c29b115b,5e2d97d9,d2b68fcb,b7f2fc00,237758d5,9d26c414,4959a370,a3bb895e,bf530fa0,13a86ab8,206b7330,efaca631,fed26773,f356c4f2) -,S(fc387f98,80bf6bbe,19f0481a,2d66bc5b,c3945c52,588860ea,dfd5893,347c0623,89d7b80e,83caf032,9c9d07af,734604aa,7ba33274,c1081ff,16e663eb,b49d67c4) -,S(c50af368,c25fc9fe,10220fa8,2f177720,ef5c00b4,85fa99,e2f03294,fe01e1d4,c3777b26,41983094,912b80d,9e94af7b,27d9f10f,978c931b,a4294cb6,b97579fb) -,S(a0f9d109,d524d9ba,a2e00362,941a5f20,d7015c48,554f5bea,7c97617e,10041f94,28c51c02,daa5e108,3e77ff2,c64560e1,2eae923a,3a699f1,daf3c62a,710e9ad0) -,S(41d12627,58b708,58727138,908004b3,2138bc23,cbcdfa28,5da862a3,48316de1,6277029,153bcec9,5c95f451,3d515d90,341d90a4,90eb2999,d29df4f0,7c1b9673) -,S(944c58ce,fe6cf543,d93afb77,e33adb3a,5774448c,d61d621c,fb80f856,6e99ca87,c071ec1c,9b7fc717,ca91c557,66bcb222,3294958a,b7d7b056,e7473170,284d66b5) -,S(3307ab12,e06d71ce,9c029bf1,88eebb58,9a27be59,17290635,f2babebf,be437145,889c3cb9,28cf9091,4748dd9b,f89e9809,4a6966d0,97d854c3,c6b6a949,c861d213) -,S(42baf011,1eb2224e,4ca03abd,24307b6,72b74572,2db6a8ac,dee1b7f3,45cb9ae6,bf32e128,d608dea2,4b564bec,38d22c5e,879515d2,7379cb11,25695faa,2e12ee06) -,S(856baabb,be7b4bd0,49fbe898,110d1175,166c69c0,a2bc86bf,e734c854,c402c621,24a323c9,b6d31fd3,cd424161,be229e89,1f825197,9ed4721b,943d7418,4912ac0c) -,S(38dbc18e,d998143d,874c224e,de83834d,95aeeadc,805cac1c,3216d830,d24a9cd4,273ec126,f7e85778,ea38e2ea,a90ab5c5,271c6eee,7f934a03,570891e5,167eae4a) -,S(359dc85b,ffcd2329,3166bb20,c8374af1,5e24c065,a5f48d92,c981eb81,4988dc59,de5dedf7,deef588b,90237d06,e437bdfe,c4a05703,f77b584a,e58162fa,bfbf39c6) -,S(e1068065,e2e91c88,3de2f73a,6a5f3da7,1d872a74,9d7f283b,b1ca35b7,c63666ea,810c3a52,b5df0851,87928afa,a7685035,a7e155fa,c8dd4523,c5ed1f01,73752cd9) -,S(50767f71,37e7c9a6,6e317183,cddfdfc,b564956d,cbd5f3c7,fd8506d,dbb19d83,e1c2dd5f,5e9d5fed,807d24dd,3f2e0ae2,393b6167,563db9fa,5e338664,a0d4fff8) -,S(44cecbf0,cdf88355,f1216d0d,efcea137,5e01275f,f53d8a72,5a0b5980,e6e65864,469568e,5094e9b9,ee290550,e67bc636,e8e3f022,f15c8d2e,25c3ad6,f51cd40e) -,S(1830c8ea,43cbb07e,fa2fe597,6afca2bb,87ed8a92,602e05e8,86ce3447,96aa18b3,df551328,e064aee7,67f56203,7fa31c11,3c8ce2fa,b5445d65,8bf1dd84,2f1da49d) -,S(58d54b7a,473a7ab2,51c33417,a41f4ee4,708245ea,c4f8eb79,9bf90aa4,bd9326c6,a191f338,15e2e07c,ca4c331b,fb1cb2ca,a1692093,faf5e789,1ce45a2e,c49b2a85) -,S(f0dce604,9507812e,603af104,42fc9861,70a18b6e,44e81af7,ba192b55,12c6792c,c221a221,b5e86ed6,23e48df5,5cf0f560,4cc60eb4,c54d95ce,3ada7b09,bbb966e4) -,S(42fb09e5,72c0302b,286aaa04,644b26ae,e4b958cf,ae5293d4,d7ba505,59dd2ab5,79c10573,a00e6888,fbc7ec76,983e7d17,f46e1ba8,27494099,43781bd5,19f2299f) -,S(7adf1551,ddae0c9a,8628db25,e0dad10c,935465bc,88b005de,ea2d0412,f3502ecb,657c0ba2,143cea92,c9ef5c3,69d110a1,2e031e67,9d945a9b,b3c5886f,29acfd20) -,S(dd5a48b9,56fdf6a6,d6271310,afc2f5bd,3a7bfdc9,28125345,4dffd91c,282c7a5a,7390d037,2e067f36,fab52107,29590464,2ac6b0cd,91a161e3,85df7cc1,7ca52657) -,S(631850b5,15374594,be1c783b,104d2ce0,13ac763b,1d36301d,2936c2d8,8a1466fe,2490ce1e,a9b67e44,a9241416,c5729ace,2016d202,b77efa85,78bf3228,c590882e) -,S(332e39e4,d6732229,aed85cd5,83a3ccc4,24466869,bdc6a8e0,741b0e06,f3a0bca5,90840f03,60db52ae,a58b1b4,74ad65c,b66ac30d,f4d465aa,60244d48,5d7578e7) -,S(de019556,f0c7e1c1,6567224e,826532f1,d72c0eb2,91e70980,de7513a4,362f0c97,39a3d79d,1cc98840,4162227a,66382529,d75fa5bd,64977e47,9af0aed8,68411ea3) -,S(4c44c0c8,e675da80,c6ffbf2,61b82e46,4f81b76c,a3f902a6,8094a2cb,24ed859f,59e1ee88,1ecc45de,d8ff2800,243ab8ac,c5497897,1a3a2246,63b2b593,e45ac34) -,S(e60339b8,481e19e,5c1f4d1a,85ddcec6,a4e0dcbe,113e7d28,2793654f,309286a2,9a1eeacc,a607941f,b51c7998,ed2a5a98,bc58e3f9,4737f72d,1b08a706,a49d9d59) -,S(10f42ee3,e7292f3,9f4bc472,708ffec5,c6ad955,c5285be0,d44d02c3,d8a25e66,6f365f0,53ebe28f,db9d5f2b,c967cf14,183e130d,f01a5106,34a975c,ec916a25) -,S(7e0931ca,d1286687,7d2fb0f3,1c58d74b,703af3ae,593a9548,b6d53d86,6729c445,5e4b9fc,75eab41d,663caf7e,8056f4c8,a9c34af9,22773ffb,f5a12174,1f6b0b0b) -,S(36313f7e,f9613c6c,ff14cd1a,78362f7d,b7f1acc0,db278f1c,6a011435,57963f22,1e6946ab,2a94231,4ac6627f,5494205c,33960a91,ba663a69,8641bab4,43d7edc2) -,S(223eeed8,8eedc265,b2e18a63,ceaa2e9e,83f9ba59,2fc8f3bb,55cec574,2869fe01,72122173,4ae29bfc,f3632cc8,92d72d10,5593f7b8,d687e5ff,eff21095,c1bbd71c) -,S(b6bd5ec9,33302c5e,3fb9b32,18795a11,60dbb2bc,f9a9b5fc,31b7a5a6,28b3ec20,fb9f87f2,98a8e5fe,b15f051d,63b48bac,34f373f3,9b42a42c,d0f1d2d9,c99dd495) -,S(a365a760,3b1c24fb,157f69ce,8fd57ae,5a802dbf,3b8f92c9,8f0a8b01,4ce24668,73e6422b,7746abda,2a38cc7,298180e6,578005b4,1b0d3760,6f2bec3f,5c0a89f9) -,S(e86f8fac,43e436f6,f4adba30,9d446a07,e24bac1e,d379e13a,a235ca1e,d7cebe6e,1e7bb4ef,aa75a9bd,713a592c,42a01134,930b7402,77cc1cd4,a913d6db,f4a166af) -,S(f5a57dfa,d2b25571,dad09304,cfde1da2,5cab3e2,e85895cc,9933e868,eb9bd5ac,d265de5e,8fc90e41,d518dad2,68997a24,8eb90906,becba9b0,c768c5e9,877c1ff6) -,S(e1dcd17a,7259374,7e6fd8ca,b2464a9d,6656607c,a2bf10f1,45c45947,75f76c7b,efa2c310,23f86d2,6489feb6,1232bd44,dff819ce,6b95678a,130de640,4af9a20e) -,S(83f8abdd,84996ad,1be74b80,a05da9ab,cb3774fd,cca40c3b,afd386cd,cfa801ff,267ebd64,329fb10e,56ee792d,966868d8,1c85ff37,6aa24287,3d37c63a,4bc3f63d) -,S(54cc9d79,6ca85a90,27487c71,6511485b,ca324b1a,f34fe454,ea9ba54b,4f259fae,18c39071,ef0b861d,7d016e9e,deb6e83a,3c6ce8c1,517ce0f2,e201da0b,fab2da2a) -,S(9d12a52a,e0091654,e2875ac1,b11f8744,1c3f65ac,940e6a51,6351c219,31402ba4,5ffbb334,276219af,418d17f3,9f5fad63,c6d7e42d,d53f6e52,bbee2f01,38e81d2e) -,S(659bfdb7,66821a91,cd030917,ff21aea4,488007f0,b7ef3824,4f23b665,e6496998,2ad708bc,4506e85a,341ef96b,78bc247f,d7321a8e,bc21f9db,8444e7ca,254784e0) -,S(e2cc4e33,d4a08374,4866a253,81549a6a,76ba1b4f,57312413,d601296e,5eb4670b,528b2b25,347e7f34,7b79780e,a64c3718,80497f0b,a3b28e18,79714089,a4672476) -,S(529c0b9c,9e21c36c,9b2164c0,fa505601,e8dbbac4,cfcac131,e248e103,e6edec68,7fa44821,72a0ca01,33669e6a,bd2e0386,6cb74f5f,9cbb7e4,96770129,567125f4) -,S(289d6baf,be6a7d1c,154d6532,a80fb65b,3d89e57b,eb2f1dda,654d3553,683b63a1,801f4863,d3ce8d61,60e2c62c,55267877,db149ff0,c3cdbb53,38893168,7d005400) -,S(d16a84c9,e3b36660,7c005bb3,425ab432,2eab9b58,58d1899e,51f2ecf0,790f14a1,2c6f5dab,10715328,f9ffc5ea,4ad6e0f1,46ec79cf,19cb2313,79bb5198,5156dd07) -,S(d03cac39,4fdabfbf,440a6893,e410dab2,a7062df3,ecbe1aff,d30703b1,6b6348f1,152313ce,f530b317,70d85c08,7de95b1b,5dc4a86d,38e4040a,e5d1ba34,449d19f9) -,S(b66b3c6c,a673c4a9,77ca7d85,1f969858,d4c4b604,bc497101,c89207b5,a863379b,54ba2563,771c6aac,482c63cb,7156961c,4b00faff,187f0560,9a470b06,31624da4) -,S(be684644,11c47cd7,dfd3127f,4e7d7308,2a43fb68,79c5e86,236e4516,a98c8c45,79290f83,c61d368c,2e395aae,b9cc50e9,7d78ddc2,fdee9f19,a15fae85,826733da) -,S(478ac3a0,9f34f463,4d61de70,9ee01878,4ca421f,91d20e0c,5c62bfb7,afcbde9b,f752f3b2,ccbc1096,1ae7526f,5574b5f6,e4bc7d4b,f77edc34,f6e37655,7b0988bf) -,S(745f355a,f2ed71a9,9d4d7de9,c9bd4a13,7271a2a0,c077c796,e7064179,8f3dcfc8,18ea61f4,6b0c87f0,9ed05816,c31e1992,d4fe8826,630c5f6e,67242063,86e288b9) -,S(54e7bd6f,9878a8b0,909aede5,9286427c,a3157a8e,38ab94b2,18db520e,86760ce0,d7b7d80d,c1eab448,d1f3c638,675dc0b4,e04bdba5,340d3f2d,dc1d24f3,dfb8e49) -,S(ff56afb6,55eb431e,f3c6f5c7,fcc6febf,99b018ae,3dc95208,27e4a01f,a07d510e,9bfabdb8,42d7b1c7,9f4388b4,49a28d6,ec723210,ea27509,655e9b44,2591e371) -,S(c2bcc099,ed298fc8,679d0250,6d8ea790,ea511b41,5ff3ebe3,82d39d21,fe9cda72,6c7bf2c4,35ecf773,5b6c31a5,82fd38c4,825de4f0,58efb070,aa1ecb58,530f971f) -,S(2383f144,9811331e,6c54b9a1,19c681fe,c8549e36,890b80f5,99a80187,8e2ec4e,13ab411f,d846b6b5,938a999a,704470f0,d8fff03e,9dd35cb1,44860a0e,3533a1f9) -,S(2f2271c0,d4fa1d8b,f8a44584,ba4f5266,9953f72,89de16b8,17d6bf0c,6e096048,646ef05d,b40e50e8,b6f32c22,63ef553f,a957173d,a6f14ab5,7cd60b60,2fb42fc4) -,S(b7b49b1b,f067a27,eedbe55c,bb011eeb,809e7ada,ada5d08,9bf1f26a,25e951c7,fec760ac,a8160525,ad6ec95c,7cb0329,4a9b7f20,45907331,5b2dee2c,7f7c33ed) -,S(36c8e1ca,d9933e5c,971866eb,12daf81e,7765d4cb,9f0af557,94181aa5,e5409223,895eb6d0,a0252282,d71cc730,9116ea95,22f2e35f,52498853,e291932a,dc8b8fdf) -,S(3cbe9127,63283592,13173e01,8cc2b0e0,fa5b8a11,5684cd6a,6ee7bde3,bc1ed523,7b2d3dc9,22f96c9b,9970aa9d,c75f1e15,c5149ab3,d0993055,e4df30cf,ce44dc81) -,S(76e94d41,c4639419,23448d38,8b239e6,fe0aec99,314ed16,4e67e97b,6247213c,8ee4a6c3,2f010749,103460bf,d75fa38f,f9efe4e4,bf283cb5,a3bc186b,21fa1278) -,S(493925cb,12c0e7e7,a15749e0,7fe9dba,5b265d27,8eec0c08,506f3433,4b1851ec,70900c6b,3960a465,6cab318f,9f730a66,e4a2400e,d819da9a,1f5b16bc,4c62b193) -,S(b37fdaba,d1a1393d,79820eb4,a4823d38,3873306a,a9f5e6b7,51173aed,c43cdcbf,8506f0de,57fad139,e20df67b,e30a75a7,dfd325f2,9e35652f,28fec608,f27030a) -,S(4451960c,48e95c49,32b0c90e,9f90724,8f2b7023,9c6c703,3c29f4a5,b0a5e8c1,83553a18,d9ce9f66,961c9e1a,47766a4e,28bc404f,bef524de,53b1b687,d4d7490c) -,S(9b0ac1a8,697c69b9,80cab20e,b3f98718,7857721b,c869c704,caf63b80,dfea3449,210e4c53,bf1bbf3f,71e32a58,22809853,61b61723,72e845d,65b5661d,fa7e60e9) -,S(e6697355,ccae4f7e,122d62de,1c00dcc5,32eca4fa,7dbd1ceb,e92684b4,781e0851,1f122cff,dbe5ef3c,944353f7,18806a82,9d3ded91,427bdda1,736ba236,e9bdc3cb) -,S(ffa890f1,1a1aa4ca,1f26f86,1288bac7,ad480a4e,1cc47f2a,fe39f260,f167201e,1688dfc4,1716fc3d,473c4149,77d0ee8c,ac569cda,b01ab5d,69d449ca,85439cb4) -,S(9088d4f2,6ce238cf,63eb09b1,5c04a04c,c41fcc57,946c6c14,cd3b1b4f,54b6bf47,9e380417,bc61004e,3d5c9943,b3d359db,2ae4ec81,2b70e909,bfe265d5,e4d2c2b9) -,S(a3395dda,c1e760e0,fe7f7e5f,e3296bc2,99949ca2,2c034707,67c08ffc,d9576a91,4f8a879a,54036d17,16f07016,23dfcfba,3141850c,de003870,6ee940e7,452393d3) -,S(11e54d64,54aac1e0,58cef234,51f686a9,1a77300d,75330ecb,d208678b,2b8ad651,749b2960,5a8419f9,c5521dfe,f552a24d,aaa53f45,908d2679,6e08b396,c9c020f2) -,S(c8f13cdf,7b41e822,ab6d5a70,7c701d29,98f5f0da,8e4c9746,75e808fc,64327f30,489a69df,17c09c1c,dec329d6,a1f34f60,445d7aad,d609d94d,44168947,c3199404) -,S(9175e6dc,cf674838,a94c628c,3e1a9dc2,9487f394,8a25e50c,d463cf6e,92d84442,8705713f,ed377125,51e37e51,78ca7a7,c13e193b,1b83c729,8cb08186,8fde1c22) -,S(8eed492f,b6d5f0e9,ee78f6b8,953ac0a0,5df8b9ec,db17a09d,22863bf4,3620099b,23a45742,17672e98,d9cf8b94,62439ec8,82e1acfd,40db9d9,9ece889d,1e0ff1bf) -,S(cb95ce23,dbac06ef,79793f54,3105f5d7,5cde90bc,651b7756,bebfa367,d5c2dd9,9612a6ba,c023b0c0,73b5ed99,271ddeb4,57d22d74,f7ecea4f,c618be5e,164a9a48) -,S(667218c8,bbd3ff37,d42a8ebf,8b5a7791,d8fdd493,9ce447c9,15dac906,67a3c980,dd401179,9e19afdd,46b44aab,1055b554,452a21e7,6750f2a,ce98083c,8cec26c0) -,S(884799c6,ded4851,ce53e855,dc429698,c7627b5,a0ed3852,19b59af8,32f76e5f,238d75ed,84e6408c,79cd2d37,152cde78,22e34377,fccf05ac,3afda662,c21c4a6b) -,S(8d98f36b,5fc0082c,597a05ba,e24ea6d2,2cc8bb90,3a6bf96a,256eeead,6911d143,26e8ad1a,fc902a6d,505b2fcf,80168177,de7df931,b1dc1516,f2ad7b38,e0ab3cd3) -,S(ba9062ca,c0ddc6d3,27f2cbc2,8d2efb1f,d1db2388,c86741ae,7403f4b8,3fd70ad2,473b335b,3036e754,d9d71ccd,53814455,674539fd,7b73d9f7,8f24bb0a,668b38c2) -,S(4a2d36d7,3bf0e609,7a69be67,55621051,7453ca53,11e288f0,1ff1dc03,acdca29,ff691e7,a90331cd,44e83ac6,c298f5fa,9d694a81,48db01d8,595a4386,b2ca8f83) -,S(e868f28f,d99c4b16,b64fb0d9,32c325c8,6b365136,e0055c4f,cd362e1d,cf37d0c4,ad3346c1,83401034,8e8e0440,e889109a,40e5fa11,37d94bca,2742adec,4cd4a9eb) -,S(6c5e8689,830a6ca5,12d77e56,62239833,ea77e696,da40feea,99da3519,2babbf3b,c29e05f1,5fd00b60,7bdc333d,d753647f,56b9830d,46a597c1,2bee9465,ad779540) -,S(b3a172a5,6ebf2dff,aeb91cc8,6b9d5a91,c317adc6,250ae210,e1a25bec,1c046344,28f6dd79,9ae40d6d,bd31fff9,9a4c2fa,f06401c0,de7a5d11,9fc5faf8,3b4ac3d5) -,S(198f05d2,e2f9d779,a50aed67,39468a8c,ac4a22ec,71a3ab80,91a94e2,100d8f47,cc6a183f,c9813173,caee3baa,f3fcb223,39708968,360c02b3,cbf899e0,b7cd0414) -,S(78b2178f,a943a791,4bc7703a,e850b07b,41ae77db,79fc39d8,9f0f50aa,b077f48e,85fd3e34,f2cbb092,8bb89004,e1801be1,d78fceec,c29eabeb,11b9cb15,625274e7) -,S(6f70df00,1d4c5175,f997a795,170e28a4,23828ef9,d5f72dcc,cec43fb8,d9943f3e,26315213,b77183e4,5979c34b,e730e2a6,956a66c2,a8dfbee5,f0f1eedc,ce8315ce) -,S(ab813144,3c946d29,d05509e3,b45b5926,e3964b2d,1cd0fbd0,9cfc359d,b5a9dccc,aebdf315,c1273af,a0c5e587,6c6c6132,16b7710b,3f505062,6336ca9,4f5c5ac) -,S(e72b3791,dd751127,23723e62,77e5e6ed,6b94569e,ba3321a2,a3e883e,5473ad3,131b3074,2dbcaaa0,fd3109ab,5e3a2847,9c2091ac,8830b19f,d4df4c82,9b28a3d8) -,S(ca5a3296,ecdd5e50,38fdf77a,fcc507da,bb525d7c,56b50c74,61928432,ce3ded63,8bdb6794,b7e177ba,9027258e,42b365bc,5a14209d,2bdce54b,3f865fc6,ffc4ab9e) -,S(eaa3be9f,26ae8cff,cedbe59d,cc03b202,e7d2e815,a7269819,c881a700,e31a9222,1b5a2cd7,a367d34c,60ef8026,51df2d3b,36ac2816,7cd7eacc,735e45c1,9524ec1c) -,S(ebba882d,3ab4ff6a,e162076d,56791554,35a011e6,74872206,582b03de,e8e97728,94222a05,3d8dd2cd,cdaf2ac7,69ed8c65,8a004c58,7bdfd0ed,355be474,65be16ac) -,S(ca0d97ea,537a5dd1,147cb784,eda20601,ba88e0d1,68e8df44,6d8923c8,353aba86,874ac858,89eb86f1,88ebb979,a4490e65,96c97892,874b5b68,167ca99,f68fba1f) -,S(51de2965,34807454,7e798f98,c5fc19c5,84a90a0b,e1dda24,7718cfb3,ebb797e1,81374e3a,ad04e6b9,55c1952b,fcdf9a7,ace0ee4b,99e487bf,87ceff58,3f7c54d) -,S(69d611f,3136be2,cce39bd,a1d48fb6,87b52135,365b8df5,151c6ec8,c1387509,75e2d820,563b64ca,c4d127e1,a5c29720,fb84c0aa,6b271fa7,e9da2c22,3195bde0) -,S(31163083,558660f,23220456,1dcde218,6fa4a4c0,de450a9c,b2f57de1,3a8aa135,25d6d496,b1341688,3008c636,ae1d8b76,29e14207,e5fbb817,539ddbf6,ff46eae2) -,S(84e342aa,efa9cd4d,4d82e5b4,4d0ad9a9,11f4623d,8684c274,cc3cd561,2c7ac334,fb90dbff,260f9997,c84f0a32,4fe5d2f6,f552affb,50aed654,fb8f660,2a92a70e) -,S(95efc402,969db115,22446814,3d4e3aa0,fa812aac,8867a5bc,64d66692,67bf6562,315bcc31,6149252c,56f3f00d,445255fa,e4567d9f,d77ab4b3,e82c1359,9f371883) -,S(5223623c,f87e9da0,bd289993,a55bb9be,55b40149,bb501507,e3d5c9e8,d78d07fe,6bfd0a21,dd2df437,9b1c16,b0076f88,832e921,db3cbdef,fa5808fc,ac613b56) -,S(f212d199,a6b707e,61d87ab3,109e1178,ea180f19,66b0a55d,f5f4cb97,c0cb0a4f,3280446c,7edbb64e,e47c3142,7c0ea113,7f511422,19ec3824,12f6b069,a0f7c84b) -,S(6b55063f,f25d76f8,2154431b,20058f96,e1e19ce2,210e1b50,835cf58c,31cfe8c9,5427dd62,36450762,46e99707,6f60ffed,558a82a3,dd7e31c6,492088da,9069f8bf) -,S(2539e5cf,a09690c0,12ae0c12,9e6f8b27,c9388d41,a82e1e96,47219d57,9b23045,94cb83f6,1e26a4dc,d1b93000,e5113347,31d804b4,a259e24a,77c457ad,d9021ac3) -,S(aa9b6ad3,4aaf1c30,71aed31e,8f28c3f7,9106421e,f0e53fb6,297fae54,a47d51d,dc0958e4,9fe4ae00,98b4e7db,10ab4d99,58cbd87e,ca443d3e,d1c9de77,83544c47) -,S(a850a313,aad224fb,f5ed6e63,5a3f6b0f,e08964e5,e9ca262f,780532f6,13487ad,7e476ad5,4cbc55c2,3b9708ca,eef3479,d9a5e570,26f15a4c,43b83363,ed4ccbe7) -,S(314fec33,f4fd0c96,d04889fa,b18e29d2,5da44132,6477b28c,7418d4ae,5fa09c1a,a2c9513,a98ffb7,9b5dd4f5,49534fdc,d9b4b8d3,1aa6a4a9,76b7b94f,ebd25f42) -,S(6e7dc3c8,9ec57e79,ae1581ae,1afbdcef,183998b8,cf52dc85,329afa35,4f3d0963,6b636805,6d5a8e9f,9651e3a8,2598ab1b,8f057830,fccac964,a83515f8,9d9f87d8) -,S(596df693,fc4ba2d5,20497a50,7d1841c4,38b6cfc0,58c274ad,9557d400,573337c5,6609ede9,1c97b09b,3a171723,e9ec5cfe,74b75c33,d5ccb3c6,bd03fd04,b37f4ff5) -,S(235f8dd4,10de7800,58550e8e,77bd42d4,ee3ba259,97bcb4ee,13cf0a12,14e8afb7,bf6e0ccd,b8e8e136,800f8d59,510a4455,53b72c33,824b71bd,189e158b,6cfa6712) -,S(a9d8ba97,b259e91f,125fbb28,c80e81f0,3f03906a,ef692279,4c9cc23,13db8b47,e668b954,19b580f2,67472afe,221f5895,5e6ce6f6,45ba737b,f14754ac,ec048656) -,S(53b44dc6,4f74c170,142bc629,51349b88,c4e2cc35,b7d9a7f4,827b07e8,4a288e5c,4aff13e1,404562c4,d8f006ea,dfee7b5a,32216187,d8c96c7e,5896e157,97075d4) -,S(76e6e038,a6baf9f7,1acb56ca,1494486a,a9187279,486f62f,947b5a02,580af1a0,51a5d110,66884076,44c18348,be045910,3b57e0d7,2266ffd4,465e6b4d,e1f0f0fa) -,S(7761ff19,2fc70129,10eda284,dde864bc,1c45b4c7,1bec7870,2bcf53bf,9bc1e6b5,80980f70,a82f7196,61f7e1fd,fc3e7d37,e0bb75cb,b1ab47c1,d947dac4,296e11b2) -,S(8199c9d6,1224f51f,e6dcdc33,3869d860,95c0bd8e,210d2d7f,8fed2804,a89aadf9,be89724f,5cbd2384,ae9bbd73,f030dc74,a158ee7d,2a9d292d,daae3057,4b1ec89b) -,S(15c279fc,760a2556,bbd62680,3bd779d8,8bd4dcb,e508b3b7,99d27405,91c55c0e,fd5038bf,ed80c963,4915d352,bca040fd,ea0b9b0,67215dee,3373e4d3,53390c39) -,S(fb3f8d06,b2804047,6f7b46a3,ecc2e7ed,9724ace4,14831a8,3c111615,f8a39b46,f9250cb6,ff851b61,3b3fd70c,63c1bd72,3177ed50,ac991185,4fbfb3cf,6bd2154e) -,S(39b2b547,3c964125,da2723e3,97c3fde,f9faf415,db0b389b,5eac9a6e,ba012edb,8ac1c2a5,a586f413,bd68aedf,1f65f231,6bce7bae,ddf9564,2882f2,1bfb7547) -,S(42d5dffa,e476151a,1d3f6d0b,bb24e8cd,bf72d73e,ac87e848,20cff44a,47f1552b,631d9645,d941c001,627ebe3a,f403bcf6,663f6e46,17d86ee2,922fadb4,b8847ee4) -,S(84dc96c6,24ecabf0,a5edd071,1e922d9a,630a0bd2,6d9c6158,e311fb7a,e6e0bd8f,40af318a,16b7324d,2acff10a,8bd2fc25,c795cc71,c0aa5a8,2cc8eae3,ef8703c6) -,S(636e760a,797bceee,11b812af,37bf7cbb,4663ba02,c36d93bf,1873983,4bbf505e,ed5c5e4b,6cc8cf76,436dab98,104b9458,69924f40,57d92ff,d74f703a,65f724d2) -,S(137fd025,4bb5ee78,669ca6f4,ae278064,7d32bc0f,f6175090,d4ff7580,98d06ae4,282d6aa2,25eaaaa0,e9b186a3,36e92e7,e07ec23d,e9ce4bc8,8fb7f09,328d0fd4) -,S(218ab848,39e49256,b55bc7a5,cb250fc0,df781f60,17abcb61,1b6734d2,12459e92,7eb14f56,b53fb0dc,430c49c8,d32f39f0,1a7212fc,701ca444,c994b3ce,4d0e1599) -,S(6b3f7ba0,106f22f8,df69e3a7,8f137605,1b2f0a99,ebb4f4fb,61915495,5f8eda65,c5788c4,4c946bef,86d9a4ab,481e8873,6c831000,5d36d3b7,aaafb7b7,2330d299) -,S(9b414ecb,a2de1195,196fdf19,62eb5b86,131ad1ca,f7fefd08,c5de31fd,d9e8ceca,38e6f31f,9550df40,80db0626,9da9f4e6,51e94e85,95e74797,639225e,a725a637) -,S(436b07a1,857425e1,86933af0,d1d444d6,156a4a8e,f3f2df8e,cbaf661b,26940653,94a52f35,f124ebde,ca642713,724fcc63,c6822dd1,bce4c53a,ce155b31,443f2d44) -,S(cc0a9338,9b25f82,33419bd1,87b5e290,b8d76f28,2099b4d1,fff32cd5,128fbc6b,cc7e86d,ec7ac7a9,448cb627,875500e0,e713ad7a,430ee9ec,220bfe87,6e3f458e) -,S(5a1b316e,aaf877af,cc7b1907,eaf8dcab,7ea684ea,72fbf888,8f21fe83,c3a19858,4af0339a,da08846a,6b6b3466,da69412e,74411094,22dbc450,cf7424ce,cd81e7e1) -,S(faf89165,74444bb2,1fe1e411,40398b25,ac4a5725,2f9ff274,e7d409,6d6c53ee,cfa7795f,af75547f,5dcb6426,3b16c9c5,d87984ac,81083cb3,99714f6c,99a43100) -,S(39e5fd8a,ca141623,1840c68c,6c6cb028,c94cd22d,49619e33,aa9e4dea,d174f248,f8121f65,7083da65,74013e78,88f66276,a8d3686,528aa105,61d10a6f,8c3c1ff1) -,S(20a135ec,147d0cf2,ccd3cddf,6fbe1356,a64b8ed4,219bc0e9,25743098,325cbc1,b17514ab,ea1a3725,4c101fd2,675d30a9,fa1d170a,811f06a7,15622ae6,ee82c013) -,S(a181a1b8,af48f73f,a13d69e2,ac75b13b,9903ca11,8a8851fa,b461c2b4,2c72320a,c96c8467,3f487e62,3d72c432,ad5887a0,a66fbd3a,c43aa5a,219c84b2,97a6df20) -,S(395fc031,720a5da2,faf5d76a,9516de8d,eb462695,5eb87fc2,752462c7,7db3ee4f,4aebc86b,53783895,ab4e14e7,c3ec449c,962ac869,9b340523,1288bf41,c759ad6a) -,S(a36de9ec,f6df2b96,87d632a6,1bb6337d,3fffce5,71b9fd17,4246b33d,1b64fa6f,784e4c4f,a133d140,1b212e14,77deb40d,620fe29f,d0f05ea9,cdbdc862,651999f4) -,S(8cb5a899,ecee4430,f7381820,4535f57,e55a3ab8,3dbdc359,d04746e2,9840ba8c,12a7282a,e9c3a3c1,2c1df0ec,c3d28b4d,731dedb1,ef02cb2c,b92da5de,17ff59a) -,S(de441e1,4d9c9ba1,90e37201,22fd1fbc,4cee72d8,b26b1f29,9c450b66,60b60985,add1a30e,d12ddd33,d4f740d4,427fbeb6,2927b3c6,75032110,508e2114,271b63e) -,S(88e38b56,b5e5544a,f2f3c1b,7128d118,520646c3,97295067,4078207a,9b9fbab7,8833208e,d44e9656,e5bac529,cbdaf184,dc8ea020,a2d8f4b7,8101d8e6,1000e5e3) -,S(a4f0f992,f5616420,b9ffa3d1,58d2d729,3ee217c9,60f5266c,6c5f3374,f4640a7,da6741a8,437a86bc,40ec9188,a1af42fd,b131a8e,81289e71,3d80e201,f82e6ddb) -,S(5f00a8cf,f2d1aaae,604a40be,e451d8d2,86899fbf,37f96ad7,efe52407,1c5c945b,135fc8b6,9ea76d6e,39d1549f,b4692d5b,b48ead3,ae6c662a,424b63d2,b59deb12) -,S(59351a0e,bfd6fca2,ee04c799,838ddb8f,9d168967,a9e6cda0,b416ce31,88f99218,6e01a267,3184f4a8,28e27b6d,4291e7c8,fc4159d,73a465b6,4fe3d4e9,d50fdb34) -,S(175ee35,f5c533b3,de87387a,5f263d0c,6705ef73,e77f39f7,2c796f91,2cb1aecf,a3792715,4540e426,1e0d40fc,4c5fbd60,5fca3b63,3cd7b506,a80d0280,b9d9513f) -,S(75189b41,597b18ac,9ab6362f,a7905ad4,5655951d,fad033b0,2047dfbb,f347b8fe,f536fd21,ffa10ea,57c023de,256a59ed,aa246842,845afed5,b0177b77,21b2527e) -,S(91af9ec3,2522d65c,70bd2a31,57efd23a,43885573,6b5a1c72,49a414,a19bd4ae,312007c3,8462b858,6b44898e,d0b4419b,31c9cc19,a2ca6d6e,6436bb08,741a32de) -,S(ddb2fc8d,41fad5d0,5d109443,2f283c5c,732273a4,1a14db04,712a1d84,a4565c27,4f7e30c5,2cec6f4,201673a0,9893d092,8f6ac9b6,d7f2da38,d63ba2fa,d69c1d0a) -,S(9ce65d22,d7240dc3,50144936,ea412539,ad40a907,f2b04f96,f7ddc1df,f63641a6,af93e587,7f25bc64,2460b425,76062f54,c3037e43,80542340,cf927609,79d97c8c) -,S(7dc0d0d4,1fedec58,91c3932e,b0bf492d,5489f1b0,1e7f95f5,4936d76f,776e9a2b,d55a279e,760c3c13,bfa1c7a4,93831a14,1e9bbcf5,a535934f,a5269995,b107c47a) -,S(d01215c,b6b4d728,9dd8d351,f3e4aa7e,f190d40f,3281c8c1,63d03a95,4c0e5ead,ef98344b,ccbd7eee,723ce7fe,641854d,c68be6c6,99eea25,48b2c881,b0fdc662) -,S(d4d1c31,a9faef8f,5991b0d2,9bdff3d4,bb6498c6,2933eaf3,e1d06767,8d7cb92f,98f3a848,ac6b91fa,85bccd42,f2185e46,715faedb,a4f6590a,4df5f862,ae6a4831) -,S(cc659ecf,42abf24c,3da2d83c,84b1e32,3d718f0c,41a1b5a4,9fad2f24,c6080839,7bbdfd55,4d843399,b6edf249,ae795758,c7aef094,3f84ccbb,f0f2761a,c81f963c) -,S(19ba1567,d5cff385,9d074e94,478bef34,f0eb4775,6708d04e,594d1641,71ea4b04,34ea281b,d536b02e,da858311,4e59c110,30555c91,c8b90ed5,d4f53485,4a820f9a) -,S(3f0f02e3,1a6e5907,631960e5,fd52d2da,e825d8e7,529586a5,437798f5,d7bbc30f,b93e27c3,3aecd4da,59079ddc,be2cd6a5,62a3bf29,7b40519a,3509061,e3e63c3b) -,S(9884c48f,35f63fd9,5a9dd895,b0f382b4,8d0fb096,e5fab23e,df07924,149ab12,5688c266,7070437c,3d5e321f,58b6f41b,e011545e,989feaa0,13f241fb,4180eb44) -,S(940f2a93,79bc9c55,3082e85a,c2f83e5a,bb4a6fe0,2b23cb47,4489bb7c,c46c7b4d,b4b82380,77ba9d8f,51e7c735,cbc6a784,2aa7429d,2cae2284,700c0e2c,7f21fd9d) -,S(a9a7699c,e5353d9f,41afeccb,b5343ea4,5f4beb03,42f9001c,e0742eb,58b782f0,3c759eaa,b3e18cf1,a4341f77,8a601ac9,b0536fbc,5fb498b4,c7ca9597,9587c994) -,S(a21e348a,9cdb00,56e36cc2,82d0112a,93f4da1d,23f274af,b1522263,b218913,141543fa,652f9506,6ecb8e28,a701e663,c70b1873,b1e778da,588c1f4c,7ebe89ed) -,S(d6d54d95,1121e118,52b298d6,18ce738,e8142906,306a5ca4,1f048fb3,5a5fd383,897dccb8,de891fe2,304fe9d0,38d8eed2,8f76c8f3,535a2912,41253445,828a7a83) -,S(7e0a635d,c937eafb,488c7f7b,5efb12fa,6232b464,a3a47ebe,21cc0f1d,c31e6cda,d2d1d4a,75525e1d,2ce5b34e,3adcbf36,74489c86,ced61e82,2d63ac63,8de921e2) -,S(4ce2080f,66a21c68,428870e8,36b3fae9,55bafa14,fac200d3,afea00b8,d451a659,29e1fa26,565b02fd,318d0f3e,f0df93ae,f0ca1b92,73e31b1d,891f055f,6c7da4c4) -,S(dab86b87,b633bf65,59cd5caf,1b89e815,e6d4b7b4,d8f58f7f,c091f542,712bad2e,8e49b109,d79a55f3,8d8159d7,f55bd930,4506a634,7e57bbdf,8fd15eb3,53c85b5e) -,S(c6a14ac2,90fa32e4,e8b5386e,a7672d39,ba16224a,152897a5,6ae29001,b365aca9,42aadcd6,dcc588fe,2421967a,42ff615e,45cd5f2d,fa258164,b2c0eac7,735dbc67) -,S(2599fa40,880b108f,28f24400,4f3458f6,63510bac,c8a1041d,e694e214,ea450a27,54792ad,4ae1cdf4,6a7a973a,1a02bfd2,a424c46e,548c13e6,951d94c8,7ba57a01) -,S(f6ab0cb4,a6afa8f7,aaed8fe9,e79ec43d,31265533,6fa4553b,bf3d7476,8ed9f9ff,4ea12589,c4ba0090,48c1a476,1907fcd6,82e913bc,57af13f9,73fd9746,845026ef) -,S(f51bd48b,ab8f020e,2d97ecdb,d3ff4da7,72738ff2,bc71dbeb,dfdd48b2,707f1dfc,6b168ba0,947f47fa,8a7fe7bc,e7ef90f9,b361c752,248bde43,8c93f3f,4a697c40) -,S(b601f114,6c9ca90c,af798f2b,1d0bf7d2,a50b286,53521362,5c898f0a,4a2a3443,a6ca3041,36b6b675,5f317a11,59f0f110,6877fed0,fcc167ed,f0cf2391,c61f87dd) -,S(792dd67a,e5957c04,76f0511f,c5b7191,5be6a158,f2871ccb,37e90651,f85f974b,9b7f5cb9,bec59f69,3a44774d,d2f463e1,1a4c1c5c,84ac3bcb,94175809,4b1dd44b) -,S(7d884669,33b6f4ad,b3700eb4,f02514ac,4c29c420,33c34377,93101302,8bb093f9,2fc8c35e,674500db,5287ead3,5e46c306,2ebeb5f8,a5134885,a2f9461f,b5e2cb3b) -,S(9c76eb91,6d0f860b,21b82038,77089435,ead4bc41,df82c249,10edb80,692a5351,72badbf3,38800156,1e235a6d,a8c7769f,e51d1e0,d6de06b0,d9998290,f5c88b62) -,S(a49b5638,3d8a93e1,55e52a2a,a1e47c33,8fef18d8,2dafc24e,cf5bb0f3,1fd807f9,1bc271b3,9bf34c4c,ee4b0760,bc934646,9dc392e6,1fce976d,bee58e8d,901d3ae0) -,S(4d3135a,675bb0b0,ca9d5cc9,68f1c72e,a704c9fe,77aea9e0,a4d6247c,dc634460,ae5d7cbe,72f5f4bc,f2f1ffea,cf02b13a,cb74bcef,68cced38,395a76ee,280cfc4e) -,S(59572fbe,17dd6e38,fc0421b9,b42f192c,eff95583,a9204e37,11f33089,9e53f588,57134640,a8cb3f9e,6a1ab805,1d60a047,a01c8f2f,9b72782a,39c45421,de1c7c24) -,S(73cccc6d,49b4780e,caaa1c61,228d2e9a,a5fff08,f5605a5,cb5ea1e6,712d9511,463a8d74,f986c8f1,1c12ea8b,59b158d3,6a52c06d,6a85b08e,dbb2cd4f,e3752cf4) -,S(b6c8ebfd,db620aa9,476f7280,e8fdcf6e,ae3885f1,87683d1e,e503c2a3,8c4c1e46,9a6faed9,f0210048,be575c2a,c8194a5e,76a25d55,f3215dde,b4091060,e7d39802) -,S(b4162e0f,92de5493,da996c53,93067de3,b9cc4a8d,4c21df7e,b507fc9c,4c5e392e,ccce10d0,c9211d36,46397873,3060d982,eecf2217,7b8ed120,a4052561,6a3b385b) -,S(46bf2566,ca4235d7,abe91955,2a0b8d40,a581008d,6544d9b7,a2a469d7,8d2b33a2,6f66fd6b,b8278841,92d82e39,cd0bc9d5,285b5cf0,2171ef1,b77c87f,c6785040) -,S(78446da4,e869a9cf,8badfcd1,b89c135d,b5422a68,2a9ef6b7,419a914e,3d59ab2f,4215b131,db7e46c1,9e03c051,f33bebde,3f5f31bf,2d428983,27d2b586,5a8c9ce3) -,S(86886a05,511080cd,42bdc762,95eb8edb,fa2b01ca,5cbd1d1f,4bebf001,5605f3b7,c71b69f3,5579c0dc,7078854a,83add404,f9b753ed,597a77d7,67507e77,f7914466) -,S(a02e675e,37f8fc43,fd38675a,744406e0,36d5fafc,b28a7371,e16d94bc,83713388,d6f9a541,835c80d4,eae16251,277e9eac,4ee66bd5,a1899c36,de3173de,fc41239e) -,S(a16b6aa8,432c6ced,cd110096,697bc04c,9b299777,ee287f14,ea4cc889,8492bf26,5c11a70,ef9e42ac,d0ed644,6ea7e14e,1e734da1,89ef1ace,d2fd7241,4e0db298) -,S(66a3f2fe,775fe5e5,d0ba1205,f7b81fca,12d7fc2b,f8685c5c,97114b98,e0f45b5a,5059bd14,a49ad49d,550daad0,30b4eb21,e626e2,95ed01c8,c1823050,5e5e3eaf) -,S(9a47a3ce,bf9a04c6,755c6321,61150ba,a1f09460,ea855785,96213784,5314b3a1,22da5ece,8f387e6a,f37c7045,b9296927,efd3a3f2,2b95eacb,c6cefc0e,ec40a80a) -,S(1c014014,9027b9a1,e3ce3c28,8f18fa87,12b25a53,49f9ac6f,97af6273,5b6628c5,672190fc,d048d3d6,b78bc34f,f160f978,87b49934,5753bd35,3a456c96,e448a4f) -,S(c2d9670a,1de5e876,5ac965cd,497e0765,8d137400,9e4ea31d,57effe5,2e8d84cc,ff818647,a6ddfbb1,3ab56b58,52956d08,b97a2e8c,f852379,cc7a7271,f13ccdf1) -,S(1a9fec47,16fd6a69,70ce094c,4141d68f,d21339e5,5396a691,e01b1e5,c996ec1d,e38eb2eb,6c8373fe,94f7639b,595de291,d29b8738,11f5d40c,24006d8b,93f8557e) -,S(b7df52ed,15e91a6d,40e9e500,6b1ab26c,53a51466,98d63bae,77856afb,1d8c464,ea60f1bf,d915fd8f,99d0706f,ff180d51,705c360d,a5fdac1,162ec530,b6e21254) -,S(2f95cca,bd092e2f,bdc86a53,40353350,918ba7f8,8488b9d1,295f9959,d7db6b5f,31456814,fe6ced86,59ea9c3d,f09bf38d,d5b0f893,8db1ea7b,5234648d,a1693ad2) -,S(763926c8,64dfe4db,6a1a432c,a37e4022,3b6ae1a3,7def3fea,883a6612,bd8a7c1c,f34d5b72,4378d10e,bb4b3e63,d80f1f98,a3e741e5,b9e4fa41,bd3f0a5,c361bd1f) -,S(2e43be7a,12916cf6,f312a513,fcb6c98b,708ce2dd,18dc4ebf,72a807c9,c8a31b0d,db919224,ce1b7e57,16e57b6c,ed514cd0,a3a9dc09,8cb59c5,971e99d0,dc24acfa) -,S(7d65e48f,1a867d28,76731984,afc6873c,2d1acdfb,13a5adf9,a56960c1,cd4a5561,9c73b955,f0957ad2,ff0e2d4b,caf795d8,bc992436,be7e69da,7b97ccbe,d983ebfc) -,S(1c6becc0,3131b772,cae166f0,4d715390,6b132c87,c5c76b7c,10b94a71,7819d725,2c3c64ff,94998533,97dd26c,dafdf608,41b84a22,cfb4906e,318c4d24,b23280ad) -,S(f5042a5d,5d118102,32ac83c7,d7edf079,aff339b0,7e9d20f8,198b2a64,13347675,19c10fbc,e644fc6d,2f238802,a045052,b2723f57,5a8bdd20,b597dffd,79a3e4c8) -,S(7c387866,c2c0353e,6e00c887,240e084f,e0ee9f0,2de12539,b4833588,bd4be300,ccc66f94,587fc58d,42fc49c6,d074800f,56f08855,6caf4ab4,c37b43,ef2b8f79) -,S(ece8ad23,d33adc2b,6ce38194,58ba2ede,104b35d1,1691f4e0,b7b206e4,eab3c140,eec976c0,7fa1d3f5,f3c245a1,2c9b728f,1c7e672f,53665e7c,5c6a408f,7c0c0a88) -,S(822b0926,a274dc38,c9eefecc,7d021774,b951cf19,3e2cbc56,a1baf58f,19d12b9d,48bcb10a,f9cac375,8314d2c4,9fcf0512,3638f008,510fe63f,1be0c2de,44118313) -,S(d26a3a03,6ef5f428,fa058d25,7ce62fe3,401dfe47,80c468a8,5cd2e77b,f85b8c3,98c39762,3a644329,7d5c6759,a308c2db,62f1bbcf,9bae4ba0,10fb1175,126a6fa7) -,S(7febb81d,8aa0cbbd,3002ab6,ca247d1d,24c8fcdf,bb1664be,b5b3c346,93019090,ee625bcb,12ca6da7,544ca6c0,2a84b9bf,966dc923,d8b23b44,6cfa4604,a6c3ec26) -,S(839e44e7,2d43b6bb,e6f63a75,cc3644ba,b7aa002a,6de2c087,33df2b0e,51d3473c,8368f635,26f41422,a563806,d775bf68,2d876d98,542b3da4,3e591e31,340fb9a9) -,S(52e947da,1c96e07c,9e2c84f3,23f2eed9,7e049b97,86d21135,ea958eac,db0d7afe,6bcfdec9,e0c70d3d,39de19a9,9fa72ba,bdbbe50e,dc44897d,9fa670e6,d473a831) -,S(72ec5426,5e4a743,1d7f6dd7,1c8e9e4c,c8b22074,cfcb00ce,db18c6b4,c67f3603,ddb9360b,7f9def94,f5ea6d71,51eed4ba,49455cf8,15bc9023,6156d4fa,786b5ee5) -,S(370a3f15,59a55689,16bf9ba,f2863d11,2ac051e9,d6a90f36,af39add3,1406c849,854cbda6,8517cee6,95ab5d3,20b1067b,ee80d993,235d1dda,ba3a0ec6,1f005840) -,S(12e57888,60d2fbdb,cb3af527,577ef6a1,41d1cf0c,f719ac6a,714f9a39,9bef5dc2,f5af7aca,5dd8126f,7dbb79ea,d5a4b475,a094969c,64adc821,ab46c5c1,86bd9ea2) -,S(b494abcd,b2fa5de,17b1abad,757bf9d2,8b7905c8,aca0a5bd,fe2ad8c3,30a2b722,c397ffd6,dad8619d,9ff8d8ae,e401a4f8,cbacf710,c6409adf,bf991d72,9294cb87) -,S(2957692d,900d0b94,b208245c,f71bdcb,118ea6e4,499dea83,1064605e,8ab9d89c,a3c55447,9284afea,37e94,fc24d50,f129342b,7ebbaa91,857d655a,40444a7b) -,S(61101879,f325e072,bca13642,dc14a5e7,1969aed3,2e49ccda,39cbf723,a1bd20eb,4e199c82,4816e4bb,d5b67269,e9d8eb0b,e5c2483e,d66757a9,c1d59847,e443b3) -,S(9eea48b2,99f3474f,8aa8c648,c2721fbe,c65f6ad4,990ab4e4,29a9c41a,ba55ab18,13954697,35ced1bc,7e857049,7f2b5a1f,b6802892,fbee0654,c1d7d89c,1f234443) -,S(dbb054d7,8ba7b707,ca475982,6a36808d,3fff42b6,31f1bc5c,c9df403b,518bd97a,396ef6c0,96343a55,dd404885,427e781f,a55a1f8,1ab95d4a,89d87975,611b923a) -,S(dba95bd5,7fdd2ef4,9dbcc0ea,35c14dc9,b2f62541,5b08e75c,d70f3caa,b61bbcf1,2af0965e,b7a17e46,18b6dba8,415159ba,b8f76ac,ae9384cc,64a90e32,d20a3d) -,S(6c312c9,7979bb0f,e72d8feb,c3c755db,bf1a132,722f6ef5,297beafb,8ad0e5be,36366388,db74739d,df78d5ea,3d8fab54,6c435961,71f78643,8be00718,8202c6ea) -,S(65eb7057,a494bc8f,549b8638,e18cd717,ad987030,aa3161e5,b9fe31b6,dc8825cd,458202a1,67f285e0,9196b4ac,f87068e2,160b7b42,2095bc92,7656694c,2fa80312) -,S(a0696917,b0e868da,ed5db7cb,d2aebd1e,c1117426,d842c0d6,b567e2b9,4effa7f6,c874d20d,a1bb4dc8,f01cb828,be8bda8b,c797ec3e,37feb0f5,ba55675c,41ecba78) -,S(4191bb82,19372a13,2dd37830,1086b64d,10874479,1d3b7879,3b27c65,782cced2,c74907c9,8ce4d218,d1ee52bf,82e130bc,49335279,2497b4a,34892fca,67dc3f2c) -,S(75f37d33,721293ee,5923b9b2,b95c958f,945e3f2,909c38f,3c3e7f5c,79b218c3,ac041f8e,c6b222a7,a2f28e18,1cf11aa2,a7d2fda1,1f402a33,9afdeace,a5928be7) -,S(cbc3173a,b58b2f29,20b3bef,6f18a84a,6004d1f7,1dd6c65,78571afb,96fb154e,c413a0b7,6f264414,2d3c166d,e9577ee1,b8f36ec9,618e8892,26de4de0,f9fd5c37) -,S(64e56b09,a139fa59,69688832,419cd1bd,64f212f4,5bf4cdd9,2a5e4370,dae226cc,a9194eee,f2429016,4b41eb3d,b429415,d10915a8,62a02fa7,671bc19e,50fbbbe) -,S(e33795c5,e2886cf2,9a22c2fb,8e02f913,34e13350,9cfc14f,73bcfb49,355285a6,7890fd21,f33d48c7,24e580cb,7b4bb065,f7c575d0,c6cdf5e1,5c2d6423,1afb304) -,S(7975e6b,7a73d0a0,d1543d2c,76c79233,6e6a0994,35eb7699,8f25ce75,a6b0b6dc,10b160ae,c68993ed,d5e48d5f,7562bc24,8f16eb10,a27f7115,121ce2f,f63eb06f) -,S(6d0d13cb,f9c13967,92e093d0,801f441b,c1ca4484,92ce3ce0,2ad71cdd,d1580f6f,17ae4238,84caf022,bbddcfe3,37a44309,4bdb25d4,71da56f1,bae4bf2c,ebb45746) -,S(2195f14a,23af2b59,c9fd3f90,42608037,60d39867,3fbd0856,a974a20,1bdf0154,fc05b38c,9a44ef01,f4db3a10,b500a372,5ff1aa58,86ff6111,da53ee14,f8136a8d) -,S(47679c73,60acf8b9,d1b54e16,7d1dd1a2,1f558288,3844fc4d,ac2a7fdf,8b713628,82a02225,f3b8e81d,e4d4bbde,94f7cd97,7ca0180a,ff3a4751,a93f6ca,17803ea7) -,S(b0bd02f5,1636a69b,23ffe514,cc2166bf,8cb4ff2e,2f7c8655,ac9aa7c9,de30831a,73fad62,48bacbc5,2a7ffc51,fbeba3d8,f4843b3f,ba6c8814,48add0d0,8fd5f518) -,S(dfaeffd6,bfe9f81f,ed3f81af,adbec5b8,aab5f15,23cb7452,c689b01,a3660158,3f54d105,c3ef4814,e6ca4bf9,ccb5b54f,30c4bf80,10d7b24d,f3b5f3da,c9240583) -,S(eb016abb,da661e49,8f53d2e7,96fd6be4,80dffae3,eb7e4ba7,46ae06b,f40d42ed,310d6dbb,aa7659a9,6cd4d50a,dc2e5e85,10f005ed,6d29d1f5,18bf83a2,7af895be) -,S(989e1bc4,3c0880b3,6d35b5eb,137f8e61,7263784c,d2f35173,e517afb0,c99fb2ed,4c4ceb5f,110cccc5,3a35963d,11df77d8,999b3bb4,c2cd92fe,b53b7476,9dfaa1d8) -,S(beb0170,be4a7bbf,1f65bd40,776d5efc,dd801d6f,909250bb,fbee1198,c2033811,1356b98a,1d329a38,57a99820,26d3ce6c,f52349d,fcc59644,ff4dcc13,8486461f) -,S(2d90bc1,986f9a4d,6f75e596,96c4296a,ea9bc55d,5b60d12e,337cb42a,ffc0b145,7d57cf64,734d1997,bf84b721,e67eafb6,b377ccbe,d2ef3b5b,48dc9f06,f71a0c4c) -,S(6b7a6a54,c9608062,de196848,dc3673bd,59fd53f3,fee72481,e829ca77,789f51bf,6a9ee208,157b8a69,f0879f30,c58afbe3,dd4dc42b,43cbf21a,5795224e,6c09af23) -,S(c99244c7,32cbdfe7,68df8fa8,7b7e7eeb,16faf0e8,8870fa8b,f4abcb68,368e8393,20ad1b55,53ba2ad2,40563453,b2dae2e8,58cc9b8c,c6a49951,bc0c0fc2,875620ae) -,S(553fc07b,402a8dc5,5f1cf4fc,609a01fd,350fef26,9c1f93f6,d2871f94,70f01b6b,3b518c75,39616def,fa7cd0dc,7d7d53ab,9b310217,7e470290,9c199137,34e5a824) -,S(c5930378,6ed8a7c,b3cdfc80,a34c85bb,721fa927,9492e369,a4e4bec0,c0fe2f69,3699e469,8a3e9129,3796dea6,213fd702,d7580e67,9f446300,1e1c7a53,3717c149) -,S(cb6f1118,f4d59964,b8f4613d,8c349d74,8cda0e7f,f1d11c6a,79dbecc8,911e7eb5,62b0ae88,98b0d5cf,723cc88f,48257c47,ca0fe3d,7de676f4,cf4835c8,fdde20ee) -,S(da2cab8f,8c26668d,d9722ae6,1decb99c,78b5d48c,966889a9,46fc522a,31a26db9,6a03377e,234f949,4a614cb7,c93b131,1808496b,12485ad8,fc21e1a7,6d0c7e98) -,S(fc6a4d42,3f9be3c7,fe337411,f03eef,fa595b83,9a6eca82,b228d5e6,b43b7d86,6c089544,eb8fbe1a,3dc78fdd,ac253fa8,27dfbd6e,269196f5,bb476865,a298beff) -,S(73c9a91a,b9c6e0d0,773258e8,3ca9460c,3d09fb49,9426fe09,db73756d,e3dee882,8b314327,efc0508a,d5a90259,c9ed876b,52040a10,45d06224,78cd635f,e571d2b3) -,S(a69f061,45b8cd1c,343e6127,14b80996,2bc02848,ae976762,933744ca,3b4516d3,87518d90,b4503741,ec16caf0,18615e27,96b6d91b,47f649ae,a86da209,d70ebe3d) -,S(1cbe4a25,70df40b7,1cddfb2a,c15ba441,376a430f,446a2572,fc95235f,28ed9691,12554ecc,f262e1aa,cf2a2d10,ab3953ee,c8ac69f3,99c5380b,6ef5d202,5613de85) -,S(8dea49c7,406dccfb,4305ac85,ba08b191,4ee2f11a,8827852f,d13c837d,b788e27d,c73d61a8,3b517c3e,bab8b15a,b7a0506c,2b6071e5,697b4056,d902957b,cfe9d9b0) -,S(de926377,b175cc3b,1ecab5af,81d38d6a,5e4b717d,55bc94f,6e4c43a4,86d0ade5,29d5f3e7,9169d974,d4289115,d8d4b8b1,6be387ac,e60d1cb9,73c387d5,17d0e11f) -,S(6e76eaa7,aeb37ab4,ab455a2f,3d525140,f6e8a9cc,5eb18fa3,8a9a25b0,d3b41497,7e3cc5a,78909d15,bbffb936,a47aabd9,44c40a3c,d690908a,89f193e4,95e066fa) -,S(37131ecf,22d57f0d,a662b03f,c9891f99,4678539d,37f5ff8f,9eed0f8,bc607574,c03b2d21,69d42968,f611d596,e173d4b9,281323aa,6abae6ac,c177a1c9,1249f3b3) -,S(72088814,82c89957,28e76633,bcdf0ebb,65155c8f,4979a4e7,66713f37,4a5d8152,6783c59f,8c0adc8b,da8e26f8,1990a00c,588a7974,b48aee92,d2a762e5,c974eedc) -,S(1b8263df,baca44b2,a7fa7a7a,dbf9d3ce,d4567fcd,144d9e8a,db712365,d3241864,1fc7e3e,24f01143,1944b98d,b2dac036,edf36680,80196785,783a41be,d788606d) -,S(7a372de,27ca7f2b,8199714d,bd583edf,ea41bae0,5a1313df,f1a8c260,cef5fd43,a0e3216b,b32c5785,b5c60f22,f5e4ed5,a5d3ab64,ba0eb2e2,916f1b9,b6281142) -,S(71815daa,55254491,c8bb9432,755ac1f0,c30f22fd,79d4232a,72bec0ea,8cd02300,8b341392,8de15c16,5fafcc68,84ebe3c0,3ade0918,4c463804,876f1600,c76471b4) -,S(1a54b7a,d3cfcc64,b62d866a,9f2056e,5535d4c,12c89c78,5d1c5c53,ff654d2b,b7c77ae3,9f4b87bd,22c77395,a91ec307,e9f5aef9,dd2892e8,41d8390b,47a12f19) -,S(85cb4457,1fc973e5,dcb0b695,3d75a2ec,22cd2820,74039987,7262b7ed,999c44a6,efdd1df3,bd13fe66,c0d4ef02,8e142093,58037a7a,bd06ed53,280d3318,9d0f6aa5) -,S(98e8649c,64a010c9,424b305a,2407a36a,cd72df8e,138df962,c35bdf75,fcfd4e4e,a804c569,34395d7c,549f7770,4c3faed1,624a8cf6,fcce08ef,cd3aa486,d5a6c60b) -,S(1eac47e6,a297e5a8,8f433895,874fac8b,5019a164,69c6a881,7e500b94,74a5a72b,8b7daa6b,784ddeae,f380bb1f,fe64b9ed,43a10a2,95c30325,f519e4ae,da11105) -,S(f079ac65,91f27363,17e9e0ab,6a723e25,e29950c7,a02a66bc,96c4ae68,44f42f5,ea87d1bf,c99f4374,4acc3ca0,214a1ef7,490186d0,3d924562,24981469,c432dfc5) -,S(d6d09d79,bf1f30e0,f011c3ad,a077b1d8,fa0d94e8,8683186e,ba471caa,32539643,8770bc64,fac8f541,f730494d,cdad2d48,ef510037,466bc049,876f5cc9,7caa8adf) -,S(376e4bd9,f8963368,7059565,68313f89,d6416ca6,b1e4e91e,3aff3ba0,b8351f65,ba436de5,67248f1d,5e99e8b9,6447cb28,497deea,47fae95b,78a5378d,e65f13f1) -,S(270f3a18,4b42c799,a2193dae,c96f834c,b17cb53,bba1610c,6578c741,b9f20d7,ccceb12b,9ab98bbb,a0fb0d0,1673377e,3a7054a9,f4a3b000,21b67328,57e7e5bc) -,S(ae271b64,1a1e5348,29e47a8a,93b496d0,b055d2b7,fa98ade2,f505a5d,ec1a599,14e9552f,39b481f2,522a9a23,f87afa9d,5847908a,53c1581e,45dfb244,7fc2bdd3) -,S(569eacfb,177d8a74,a9288ad6,4ee5390e,db36a93a,943fd6a2,5ec869b5,a7f28c8c,1cf62c32,9127642b,99a7508a,a6f4f136,bfda9af5,45f52844,cb9c71b,5f732f7c) -,S(77c7f27f,fdc4e7ba,a326a246,89790f8c,41bfb5ed,6d365e46,f277cf81,5f15b558,4d3440dc,138be5d9,566a6828,852c2ec0,e0f970eb,4501a43,25af933b,821c3007) -,S(d66292db,f1730306,a87f67e9,b044fef9,7d46761e,7b8301ed,132ed7d8,94adbb25,ceef7755,8ceca4ed,92145f23,8bfcb32b,3d36db14,6fc50209,cb0e58f6,2c8b83c5) -,S(1c42832e,12ea6f44,b77927ef,7ebb1f3,8769e3bb,f5507a49,25e8565e,a77ed0d6,8b9383a4,b31b4f5d,a717917d,9e1e41da,786a62a3,327be11e,280e538a,9c29d5ee) -,S(63e57eff,942262a8,cc362911,fb98cf30,60832435,3cd394cc,5d6abf77,b21f7968,9e3c1e2d,fb9083f2,4c344e7d,322ea530,146062e2,a25fb6b0,4502ea35,59b009be) -,S(be233fa1,86f38a5c,72c88e59,19094ea8,cf3ed3a9,b4ea3f9b,2a51489,97b83c90,402eb2b3,362fadb2,6e389ef9,edc537bd,40bd48ea,6296956f,efd19d0d,eddba564) -,S(636ddb80,4e7c74fa,9c5f4d06,5a730fce,f2cc6956,4a24b579,aaa0c3f1,61844b78,6a4a3569,583212c6,22feb59,897eac8a,6aa31ffb,916262e7,deef47eb,e6a2496c) -,S(d251c1d1,7250d87f,f7b5af1e,ee2f2566,215ae7c2,b6e69e60,5bdd6c2c,dee1c5e7,245accf5,7df52fa8,cab5c986,2b96658c,5de60d06,c84584cb,f554b518,7fb4ae78) -,S(405d4cb8,c62f133b,7051cbe0,54b06f42,9055f917,3ba8248c,c3bdc744,198ed407,8463df10,a8963cb4,298e8031,bd2bc3ed,523553fc,60746720,1a9abba7,305deb54) -,S(97f05aee,9ab33a07,e14a0314,4fda5be4,ab329394,1ce8f003,546ed8e3,9be983b8,59e62a26,7fd9138b,c4c70b15,533782cb,d321f120,1e3d1a7c,3be4ad5b,eb849261) -,S(3388161,18e125c0,6a9060f2,6b9ad691,c99fdf8d,4309553d,ea160749,eb91ac8,583e918b,5b8e1a68,c053af0d,245a9902,a571788f,dbdc0c88,7281767d,9404384b) -,S(ddd20c46,6bbe6a25,9f706b1a,ddc3b607,8cf65366,3369fc31,dc8f7fd3,3d17a9f9,b2df7b29,b4ea9868,bbaadcf4,6621ccf1,7833e159,acb43daa,7cf78e89,c1de5a99) -,S(923c6d2f,71ae0ee5,596c26bc,31389cbc,eecd0712,e8df91cf,dfe00172,3bdfc9f7,6fdb28ad,27c41243,6a41ae96,99a03d40,5ff2ed87,3207f082,414a4370,34be948) -,S(6d42a6bd,28d57e87,66a12461,b8a7d111,a448876c,149071a7,fde9df18,dca09e65,4df07ab8,1dbe97c,3585554d,f0226234,dcdd2826,747f2775,640bed6b,95fd28bf) -,S(7fd42961,59f9f259,d3c3610d,8539ece1,70efe104,31c9a3f0,4b9630ec,21d761ae,fd695441,b8ce2bf5,1037d00c,4d50e640,e85b6001,6d5d26dc,787f1df1,25d7e280) -,S(48c1050b,128d97df,e7900a01,70559990,944045dd,f408d8a7,5b59bb25,ea6770b5,8f7ceda0,4b6e319c,1cc61b31,53538a09,d450e49f,8863061e,f9b017c1,6cf66559) -,S(54462d9d,a12d62dc,96abaa1b,4883c67c,b3214c40,de5a4a09,689658f7,dee2a686,7673ad6f,916011d7,fd33bb5,eee819e,6a3f0016,d51ae37,bcfec2e,59ccd957) -,S(698534c4,e4e11d89,82a5a46e,44b771f0,95c5fe47,54d7a261,44373982,1e6435e8,36d602ac,b2720c71,8d619a8a,5e7d6873,9faba099,f71c1137,6a8f41d4,e1cbba18) -,S(4493f759,51c681c3,bb376b0d,7c88ecd9,d0bc2a21,26fd341a,d8c4832a,be77ecc,e553e21d,d4d99aad,97f15857,4bfd54be,df7143f4,e829c12a,39109892,c120351e) -,S(b054daa9,330080e1,89784cf5,f917c024,6c06325e,687e6ec8,cf8be248,ccf8313b,51f04715,5c9ce55a,c755f2a4,602420d,4ed52a5a,1dee9a83,b0688b1d,b767d866) -,S(4b4272a4,fa996b1f,9ffe6796,e6519db2,c1f8cfc9,606fbc57,1fe03713,c029583e,9526f2d0,dce7c53d,5cb36f8c,fcbc517b,cecde833,4384d10c,f5fc80a6,ff0edb83) -,S(d61eb681,c69de82e,caed8e64,7d1a3948,6cf63f83,f1f04bff,46a04aa3,63e29604,9b5a92fb,156d7b8f,37c6d9a4,30ae28eb,f62fdf5d,5bf441df,aa386259,721f08b8) -,S(bf8f002,57f979c0,9f973c8f,3dc15eb8,8349e340,efd8d57d,5763e4e0,c2bf507f,561d862f,1041e670,fdc265a8,36d363a3,43346739,f4f177d9,f66414a0,820614fe) -,S(63b254e2,a7a6fad6,4d9ca03f,7293a86f,b471fd45,51ec72d5,eb03e289,774cb498,f4145111,3a4ce922,dc7b3819,a2de49cd,f5be7d53,6befd880,837bbe7,51948c8b) -,S(bae6facd,e1da6ed8,63491f33,c4c9efe7,50fdd908,6b93c09a,e0418a29,d3968725,7c7dc955,e483176,f6bdf74c,6654e6a2,e4ca46c5,2526349b,b4d66090,6ea30533) -,S(f56285f8,ea15aa08,f3ed8139,59c660b0,d30a6317,5380429b,59584623,aceb34af,110033c1,a202194a,40703c9d,ea2dcb9a,d9a0f6da,7b99b8ee,31eb1ce9,55a9eb9) -,S(876c7c95,3de3d451,edb9191c,60e8e36a,eafbad2,198ec6a5,40d72633,8151d87a,95efff74,72ce0c6c,4010d17,7e52a859,cf55011d,1005bd27,df54e25e,972279b8) -,S(e956c7ed,77c7bd5,68096902,4ab1c758,a024d86d,ba3f30e3,fbfd83ac,940a6d30,1b5dfca6,f0d19ab7,7a57a9da,259a564a,5aa5759,ce6826b,45c71771,7aad9da) -,S(f53fde61,abdb4543,1456e9c0,65048cd7,ab743b5a,81a468bd,8fe2ffaa,99dd3f16,1d28b539,47ea22b5,178e86b,ab3561bd,a65ac78e,e0e2a6bc,1a26b64e,d790222f) -,S(b91a8681,52eb435d,475b9103,936a7c62,5e49b0b4,f7bcc3b5,f5d36449,c8043ad9,c758d17,56939bc0,61696f3d,11dd1bd5,722dc90d,1e8be88b,b3430062,a13aaa75) -,S(5a87bc70,23e32927,db4c55d0,abc97536,61f5adcb,b24c2897,b16f08cf,8d8f8cc7,9ceaae4b,aa6a0d5c,46d2120,fbff74b4,9d1ac32d,88a89b2c,3d2aa6e0,6f731e54) -,S(ac0b1b43,e54eb354,3bca80b9,efc5cdb1,215622a8,66b66e80,de979f79,71ceb034,a891575e,5731e152,17bc2b87,197da9b5,439477fb,d2bf07f6,9bd13f3,f4638d8d) -,S(d3c41ebc,2017cd82,76f4d6f3,f6ba2370,e84f1949,df3abdc1,45073467,e85ca915,52ab1d52,8be55945,1f6b1e91,610fcf35,bc1e9576,3ba3ece6,9da5e4d,8cdcf7b7) -,S(68cffc57,f4c82cc6,f7900d00,fe1b0f36,ab842e4f,49ee9063,4d1ebe95,47923b02,729955bf,aac10741,c3fda281,c18a306b,367ba904,baed26b2,6fe6a485,9ab1d8e2) -,S(7e0f58e1,246299ee,e08566b3,35324a66,579dc765,343f874c,d30f2553,8c177d9c,39652583,587293f0,809af7b,5d366740,86b9015,6a05928d,cd340196,8821447c) -,S(c72abbdb,d1816498,eb53d4bf,1b325fd6,5dc45086,73257bbb,97a15eb8,e4c9b542,3c8fafa5,5df5f3d2,88441ed3,e46cd318,841a068c,b681b782,88e77afb,2b25a7b9) -,S(74747f5d,3eb09144,1f64d76c,ef690378,943654ca,73fe15a1,b720abb5,d2363d0d,12c6724,bc7e8f7,321f993a,5caf0547,bf54c1a6,41f959b9,746fad7c,1c443649) -,S(f2a702d1,ab1de7c4,34cb5d71,dad689a9,29db862c,d1fb06e1,212ffc8f,91b67067,5b91e2c,c730ac9a,cb7452bc,7fb4dcfb,1d5ec11a,bd146429,62c7bd16,37afd854) -,S(a92d4f08,14e76b46,5fda87b6,201c46e8,c2535b3d,4be91e1b,530b5634,d00d9340,4d829a8f,3c02fb40,569fd9bf,e754dad8,38d96dbc,2350f0be,6f4ba065,5cd0277) -,S(79e30cb1,ac06c3b3,f90ea320,60a80fba,df5ea142,84a15746,2aaf917a,26f205a1,ad220a0a,81459495,5ac8a79e,d0cba974,7f17364a,9f6168d5,3521f276,c8d5c82f) -,S(6d55dc53,d412577f,463252b,e240fa32,88c8d6a3,babd6ff3,20231b6,8c9401d1,83a41c96,aa3b32c0,59155345,2679f056,c98e17c8,a0a5e154,d732fd3,7b006eb3) -,S(cf9c9f1f,604eb909,b37ea5eb,4cb8a0c2,11ef14e2,d3e2f48,7c83b56a,49b3f20a,2b90b9f6,4e649988,77260b5b,ecb441de,da24eaf9,df56ff93,dd3d1c8b,a247dff8) -,S(60d4299f,29ed994a,b3367780,9ef6fcac,e30f435b,ba9a8346,a2fd925e,186b35dd,df69b88,b8aab4c5,8ff86ddd,2d8e424b,40d51a4,9d189437,37b23695,4760331e) -,S(d93a6edd,1b674a60,6b6bbb85,4114a3bf,7de3be59,82cd2122,887c5376,d9493540,87da37d7,dc79197b,c0159006,4f921ae7,acfdb08c,447ed230,423c51bf,f9e5f7ff) -,S(cf8c3d37,7e108d98,b72bb6b3,1cb7b5f5,fd5869da,1a06fc60,25d9191a,bd652962,6f5cd02,bb96ad02,db42b034,321b3cae,fc54271a,879edc93,afc9c8b1,34128fbb) -,S(6ca99247,4637ecf9,827ab65a,c7b9ca0c,715b9048,f24c42a6,90847e68,8cdf29eb,51378da5,fefa454e,d96a446e,dab57c3e,8bb6160d,d015c1f6,d93983e4,feb55439) -,S(6f7d2c04,3cb813d5,dea67758,cacf2e3f,3cc3064d,7b9f08c5,58ed686d,28d17afd,4794e278,13ecec48,33f9106c,17c5e161,b590a5f2,ac293c8,c65a6cc6,5233bc6f) -,S(f8aee0d0,bc9883f,ab6a82b0,184e9199,e818d01a,7d99f475,d2ca8a24,e924f3e1,acf9cb2b,69135df0,9426bfa,c6b1b3de,44f1055e,5cd21b8a,b526f34a,839442b5) -,S(8b00fcbf,c1a203f4,4bf123fc,7f4c91c1,a85c8ea,e9187f9d,22242b46,ce781c,61e9e58a,3e81e690,ec026428,ee5442a,a8de699,dadfbcac,478985cc,89d35bc9) -,S(fbacbb07,8e84a2b2,c201ebbc,1cc3212c,a7278523,e984bc1a,b0eb7fa1,39d6dd4d,2c6c9dd6,f5eb0899,797df675,ccbbaa25,4e557d5f,d16c6083,3aa84a7e,4c3a0f52) -,S(1556875c,2f32f053,8d28f993,53ba2804,5ba601bb,3df8a175,bfa33dac,ac5c0611,53623050,c3da9464,8e9fb540,5888e387,d2eb783a,10e45cf8,ebaafe84,a4e240b7) -,S(b602b095,7f5b5e98,ce3e690e,c683f803,49a8ced0,5985f79e,2e972bb0,2d93d77,78868390,ddd6b821,e30046ac,b1bb7b31,ff358838,af5b89d9,60d39b4e,85435227) -,S(2a110165,23a5244e,89d66f8,a06f0553,7a846216,75fe4377,24f51501,da2dd17a,24d3b525,e1ca62e9,b02de498,30737f3a,b881d078,7d2c2bff,938c53a1,b8825159) -,S(7314759,1148f9a9,ce326a8e,4f43d2d9,a13edb92,56fc9d38,35a35da6,457efce0,b195cc94,80d0aa04,d3ac7cfa,45766472,1ad5adf0,3060b790,c7fb0ff7,77b2d8b3) -,S(a36e4fe4,c7e23d7,16362979,c5a9d8e0,525d864,37d96e3d,b2f45edd,b36206fc,56ace785,a428db4,a8a70de8,708339a4,346699f,697a6707,c745635e,66844751) -,S(97864be7,a2c54118,5d61b61d,5a2494f4,85b877d7,e8864402,3444d778,f43cac9a,43332a78,a85b8391,551dcd90,e93e71c,3a6c5428,71b980ab,138eda2,b9f2ff69) -,S(34a52dbf,2449eea6,da2c92c8,45dcd47f,daa7ca41,5ff02458,b74eb996,8519893e,add41829,900f26c9,f7ba8d55,21f3bb23,b3545a35,699d41b9,4270547f,e303ece4) -,S(e250aba9,94eea617,5fb7b2b4,8631f5bb,d8bdbbb,799f6fcf,5afde8a6,2ff3d629,803f34f5,9db0fa86,bcb6fae,689530fa,2e92c4ec,bff1757,409bd836,8143b0ea) -,S(18356a6d,b5946e2,1149347a,4558e116,7953042e,e3b2a372,869ae29,b871ae00,56ef0971,6b176f81,e1f98ec8,dca127c4,ba6de23,ba8c1f08,f19e9abb,995385cb) -,S(35a8ebf5,e5306084,365ef3f,30c29e56,ca5932d6,f73d688e,ed3cf2a9,10205533,9eae5d95,42954de,23d41032,5ada759e,20d30fd5,c2d058c4,53a18520,7f259958) -,S(37e06f5,25ea8fe9,ea862b92,53a965f,7b3dbe90,9ca487bd,a705041f,e6a4e1b9,83919fd3,5e489bea,23f13b60,41a19940,3f2f6568,fdcf60d7,3f57fb6,1fceb97c) -,S(abbbe697,ac6c002f,11062947,6e4a6ffd,48316646,718d8713,1a4dec19,5e131c27,b2c926cb,9d5122ff,7f8d8a24,a20eaf4e,fd704944,9aa48300,92971572,b12f9dcb) -,S(4df36acb,1484dcc3,f7c29c8b,78915315,5a1a3636,aeaca043,68a585a4,69b05878,fe16fe6f,c08af026,3fc417fb,19564534,aa059f4b,b7fced09,d4fc20de,6a41c41d) -,S(5ff14ee3,10256a0a,889570e5,ebdaf6af,c8f49c60,dc7c4731,23a7d29b,e799d0d7,96ff1538,55eb2fac,8f2a923e,ead9851a,95382d6c,56cfd0d8,9891d2bc,f7e65d7b) -,S(16a12c52,c1d422f4,791281a1,b7ab7186,a24dbac8,36af6810,4f62dea2,855d119a,7a6ef272,f67356de,46996cb3,8bbaaba9,d36a4bf4,60e3b2a,b3a81723,24c17478) -,S(8f4c9c33,83688920,a48b3d15,4fd567e4,5fcdbac,bea44eda,60600ffa,a1489ef5,2bb5bc4d,e06444c7,b2bc0082,d629e2e5,a4b0abd4,8cbb9b4e,37d564ca,db885717) -,S(498bf39b,7547010,854ca399,e50399ca,19236d2f,d05f5777,6abd6d2a,aab83310,8e2debff,cb58e36,bcc7beb5,8a45d4ba,b5edcd46,2c355d0c,4dde51a6,6afd691c) -,S(78147e0a,2978d396,b22247d1,74958336,2ba51d90,11e89c11,71e6e136,eefb5996,a66b7b0c,a73b661b,e71bf0fb,2eb4410c,4c75bff5,b8b05fd4,1d830d27,ff85989) -,S(351298d9,fb236c7e,5477aea1,d2df0048,47e112a2,e16adf66,3f4d77dd,828d4927,6c9c91af,8b6f23a9,d15c3884,e618ae51,241094d4,5878ff20,67f2ac81,dcfe00f9) -,S(fb5ffc0c,88fb609c,24cffc14,848549ad,c1814668,9e5f8a67,a342bcbe,16399d10,a995e13f,9ced94cb,90feff32,8e92e978,88cf5791,c885ca09,46f46e5f,b8229ab3) -,S(8352b7c4,4cc09c5d,717bd197,40dcaaa0,89565e94,77cd76b3,6c7a4fa0,4832097b,9507c998,fa25d9,758ca78,6774ae68,f91c8fab,694c5e23,6f8af6c7,7d0fe6bc) -,S(1be65c0f,273a2746,d6d014d7,6bb1c595,5d5ed1db,62ad940b,d8204115,85919f4a,dac98f30,2a38f839,a3d470a8,3ef83ae8,f044e93c,80b23552,da3da359,5c09a3f2) -,S(7107f3a5,2f4be227,eeb65037,ae800f64,8de14d89,ebf743a7,ed65f98c,b58418e,bfcf1c09,bd1af327,d14e429d,18eeae45,927b2df2,aa15ce60,69f6a74a,69fca7a4) -,S(117284b,e8edae5b,1ce54a13,3b1f9d98,983389cc,a4ccff,9dd04973,97312e3e,91e48c1e,724fed49,8bf51999,4c84d0b8,84e3af77,86e61539,638b45c3,8212b03d) -,S(a08d86de,b1ff9ab4,651f1cd0,d89b6714,41c243b6,c7e655de,d31b44a7,b00de54e,4d0fe7f6,344d39d1,57764fee,f74cc949,a72ed8d4,c2dbc12c,ec2629c,830f0d2f) -,S(9c44c1ce,df67418a,eef2cbf3,68d48a08,98cfc633,de711550,3f78ecb5,a4e8c25f,3cda2020,86d3f096,31da959b,9f9870c3,de3d3c6d,e4c1b35f,81f64dbe,31e743fa) -,S(d933e475,5215c065,bab118da,6f24d714,f8597949,a52ae319,250338b2,2339f149,5fb0f28e,313af04d,de3abfa6,4981287,e277e39,d2f19dcb,547d6fc,88baec45) -,S(7fe1f197,ddd0532c,a2010528,9f243bc6,4c2f9e53,65aad5ff,63c0f1d3,188a42cb,813b133f,a1869218,ee361828,6561e75d,a9ec6bac,6ba2ac7c,d3f5678f,fe472af7) -,S(e3568521,89612102,7ad0789c,72dc6d57,7ba412ae,b3d7551a,96aab952,c507f79c,7645c505,8e2ca8ac,ae5fe225,eddf4d45,7d820114,cd5e69a8,4966465a,423e3a30) -,S(c56afd46,8a5644a2,abebcefc,3b6a9da0,c667a183,b822780d,146ecf82,b6ebece4,9e41c655,a80e2844,89fc587c,b686549a,2915ba14,1c691e75,cc635f9,54f1a8d4) -,S(b242eb39,60e6a8f0,73b6042e,1095f0e1,440f9f8f,d1abed56,ad1f26,a1589345,944da76d,f063f0a0,3602decb,696f2a34,378579ad,e8469ca4,bb5041e5,876dfde0) -,S(3a52fd66,6d2e2e2e,888a43f2,fce68703,78f835a6,b5c3bd42,af57b107,323bb827,12e51177,a7b37a46,2755cea0,18f4f29e,96c7d6,d0e434cc,4874da99,a7af91c7) -,S(b77d5615,c8831ad1,147072d2,598a8c6b,4a71c0fe,967a6cf,70877aea,24d28f53,25d5b7cf,a068a665,deadf83d,5f793605,f5cff2c3,36a8d176,d18c634,9ebf3132) -,S(e4420c3b,61e435a8,53784728,8426aa27,f23d224f,4ff7a14d,79898369,c08530dc,422b04b4,857984b9,9bebd74e,1588ad96,9b3c67a9,89b119a7,f7cd2c84,ecca8572) -,S(888bfdbf,c6ab299e,3ba0fadd,a614fb01,236e3c44,98ad07ce,cae08105,630aaaea,86e7253d,58cfe580,628fb94a,a1a8f40b,7ada97c9,d8713453,f06f4773,3770eb3c) -,S(f74d258b,f7d78b30,ddbde398,a1398164,d850f2d,48616cce,8ef4c436,10ef419c,d13d49af,1e6dadfc,94332213,cbb12d32,5d60eb6,d48cec9d,fcaa7ff2,53029204) -,S(a8b33e90,98d60483,a7009786,11b92257,65cea0d4,b7ac0ae0,67914110,5cda6df0,58cc238c,c08d957b,1172598e,96ff4762,1182b6c0,652c9ddc,650f3b51,3521c553) -,S(5af8b154,7477fad9,8e5dbbe3,d4a1a15e,7a4a6cb6,5ae13cb8,9699470a,1a3ef1ff,525ed201,d0c61832,36c8fac1,366e8173,3c0a8c15,b6ef7672,cc84b1a3,7d6f25bf) -,S(155c454,6d4c5c4a,21d14383,3df8662a,fa71e665,ab7ff0bc,8119f29e,3bec21c,20e99f67,2f641185,cdceaefe,8fd7247f,63842282,edeff6d0,378966bf,50411aae) -,S(53918586,ee182d66,e7c22aea,5a663770,c8fd7f0c,6738d473,1010660c,7425a56e,c7fea092,3052ec1d,7e2564a1,e70b8924,cdbf727a,7212052f,abc58d9d,1856152e) -,S(f7964dd9,a0fab716,74804abb,a7740f4d,cc52d7f2,8d5acd4f,67998bba,3bad6414,6a989f64,aba0f60c,e7bdc5c2,aec11de6,d469a122,f1bbfccb,31cac834,89f62c59) -,S(741c8c8a,f514f2de,7880a909,b327c6ee,ffd72ee2,b5b1658e,72059edb,cd663183,f35d276d,e5de1460,dc53532d,48afe736,e40b6b31,fb6fdb49,1224544,a487b2ae) -,S(de8c69bf,6cc2a28a,fc6ea9f1,26ef4f22,606e55f1,312177e9,b2ef8835,8b47945a,8de62853,6900d614,780e2fec,b4ff7066,70d84742,3b1c852c,8b85ca4b,40a48a02) -,S(81e16f39,619bb41c,d8a523b2,d3dd0135,d6a8d5fd,9a8446af,cd058ea3,6f57c537,6786fc73,7cd2ecca,d146de9b,951deec4,375c434d,7dbac32f,2395c265,bbf4b31e) -,S(459e9589,d079b22e,8c5625b8,a725b30a,e70f7f04,8ab21a20,f0123aae,7a6f988d,a56ede93,5b71a292,c4ad26ac,cc3506cc,915de21a,4557512e,e767e8c4,33f38e08) -,S(b079d755,4faba7ff,20818806,a70b4ead,f2e5bb51,d1abb758,2284f385,868ebddd,495ddc2d,552f174b,210f6577,3e434fa9,20b6c0c4,574601dc,fcf5b701,fe74dffe) -,S(75391bbb,5983fb21,41580de1,dd5b10b4,bb30af17,3f05c100,569abd2c,674f288b,57c7a6ba,c9154ab9,eb66032f,2135a52a,b319f534,d1f1c80d,b58a4af7,de958d67) -,S(71436957,f2848f75,fc461069,e4fc691f,5bda94f7,32fcbe7d,5a89e136,41524db4,1287f852,ef4fadd5,65a2813c,51b93c81,95658a5a,5cef224f,e92511db,df3f0007) -,S(b9038b33,fa75d097,dcc74c9,e25970ec,94ad076b,7279f785,3b7c98f1,41543f9c,a28c3169,69295ed0,3fbc1bf4,8e39c8d6,af59cef3,d6f66660,73470ab0,dbcf838e) -,S(b2c63c28,a9fbd900,fbc664e6,36dbe0cb,f259bdb9,d67c34b0,83b8af17,a5f86196,a8f050fc,69c63c4,67308421,89510ca5,b7920723,6f5c12b0,ee7103ee,cd49ebdd) -,S(cdd2a5be,a32b2195,f4a7edfa,dfb7c785,d06bf346,f38e928a,5c92cc7a,2417f39c,ab66e78,ac421c36,3203ee7,22b380ae,2133864c,83829f04,d2daddd6,b7fa621b) -,S(825d0864,b079a737,acef03a8,28838ec5,a27d740c,724f9c39,780cfa61,9f3db80f,bf3ee8b7,749e44a6,7f27e427,fe05eba5,c2154fad,bc2e2b43,a877219b,461071d3) -,S(37b79e3c,bf6bf402,c96930a8,79f4ce3d,d0c36477,f0b0e218,608b890f,bf5e24c7,d97142c7,cec5630b,a090ff4c,9213c2f0,c32a5bb2,f7b0ee29,2045ad03,10f66f1d) -,S(fba64ad0,678ea75d,409105bf,5b452ebf,89560b0e,fbb079d8,aed22c33,552b6135,e665362d,e4e637a8,a85dd844,1a806ad7,5c628f19,7d6dbe3b,df63c0b2,d1f938c) -,S(76787b8e,77ed36f,9d84897d,e84c476f,d3bd490d,184327a8,59ea3f97,ecd9cf72,cf79f14,1a3f38c3,cc126011,d1d78dfc,e3ba228b,33d64158,210cd942,3980a9b3) -,S(26babdd0,ffb3a334,85e6ba1c,5661a551,f16a129e,42f9fe8a,3691a50d,157b31,1b3a4ae2,b1cf1a46,fb666e33,a20370b2,e66a6c71,27edc8ee,e4c4072d,8c2c530d) -,S(15aedbb7,7a2fa1e9,7a6aa864,7729f28,7ca4d3f2,36046008,c1b031d6,9f76307a,3342a142,bf8b2360,6a574643,9c05f36b,f9408878,5354c788,a6dcfd96,ff073649) -,S(98ece0a3,9bb7cd4f,df4d5767,c6ef4cc1,c2b072a0,dfde5fb3,de100f57,466fe467,c4e924a8,218c93e7,eb829d0f,839556c6,1e679d29,6a0a6bba,6f4f463e,ab227e28) -,S(7d867505,fc213eed,4cdffafa,b067bb71,8a48cda2,fb323304,1989b6a8,3ff373a9,5df51ff0,3c212078,197c417e,f4a4014c,96e167f8,8cea0c1b,9199ef75,7c97d47c) -,S(f24f19d7,43578e1f,be3ece8b,7b00d5e2,bf269a48,9d76d17f,410b73a2,95b3001f,644a43ff,55448b66,7b048bbb,b34f4c79,16d2b547,5148020d,53e53627,623631f) -,S(93853304,5c22296e,1e911281,ed4bea22,1fd1061d,2039a27b,923dd3bc,800efd59,22988cf6,cd2d15,f799bbf,e4cc905e,2607da21,e9fad162,8c2fe699,8beb7040) -,S(f090c705,39834f16,253b14ee,8e4d2685,b91ff4ec,9897df0d,af1531c9,46319743,c1171885,1d30271d,a8a08391,f53a02b6,28c59c8c,9af3ad2a,bf158341,280bd522) -,S(e8fc8ec,ab5bf3b7,4a0234ae,b2a8eafc,df9bb08,a90078e6,7fb6cd3e,fea78c6e,b08165,34ce9bb7,46efcd71,362e0a75,a8397c0b,490e75c2,9b007b28,26ddabe5) -,S(46258cd1,87cb43e7,3003cef6,94af37e3,c7426dba,c8033aa0,9b0a0d71,9f126785,846141a7,5f060822,764dd82e,2c369821,75576ebf,7082c6d4,601ad237,55ad4fc4) -,S(e7f38b3b,db3887ef,529d27c3,f433410b,94109bf3,45f9b7a1,e65bee6a,cca3e430,f52440f1,5eaec702,90adec0c,b07e8ac,ab1fafb7,adbc8f81,9fac349,2acd589f) -,S(2d29e833,1472798d,75fd5b75,1f569da,fa9a0167,f73fc62e,da5b03a5,2f537aec,52d3dd1a,b117b9fa,a17c58cf,c0593603,d9e2f55f,5a230001,d18976e9,792d2be6) -,S(a3b2ec9c,abf7a7b7,77fb44c9,c7552dd8,f47609a4,6f943c7c,8ac97d1c,3891ffb6,6ce38c70,f091381f,53093385,22a5ad66,4d528061,5b01b417,d559cbbf,3cfc19de) -,S(afcb3c1e,7582a56c,e6504dd,ab3d1a8e,6cefe762,58543015,a21f65d3,3100f473,6baf1f9d,fbeb8499,8a6afc61,8e193103,67edbd87,57b2c4a3,8e5a76c6,8b171af8) -,S(88b2f212,dc899567,bf62bbea,9466a8c2,6650f74a,490b86ec,cdd35625,d90e2ac8,73fd757b,def6153f,d7f6d4f5,da1723e2,6ecd6c42,d994a08e,7e458a64,d18c30a5) -,S(bfdea9f,4ca32916,651c971d,7da6a2a7,395c5945,5c4940d4,93d991be,1dadef3c,82747044,7ef3f684,4200adea,5b8077cc,4166bc65,1f6d4a17,578b64d8,21bc20d8) -,S(5d45cb81,aa765d69,ca52e386,9491ecf0,e8fdf6a6,3d64e65b,5213647e,e4973ae5,a4a4a32b,51a76d77,773517e7,c103a7dc,fdab36fe,3cafa2bd,b17f82b1,2fd019db) -,S(f3a503ce,e14e9994,aa34fa53,1c43e5db,6d6fe092,45d2f3ae,87d06753,7ae7109d,2b1714c0,a24d50b4,20722daa,d1951b63,568aa5ba,7325785,ac555e55,f3ec49e8) -,S(94c3a76d,6f812ed2,454c225e,ab8e6b8a,4261953,37d1d2d9,b666ade3,88cbeeb5,bb89cee6,aa406746,dd4893b9,5bf1818a,3d1351fa,d66e104c,bc8d63a1,efa953e3) -,S(23dbfe81,5232403,39d5a662,51fda5bd,b9a2d3d1,181dea3c,c0c908c8,f0f4c050,caef3a71,229f10ef,488f8385,c79ed0e4,b5c16899,d40ab679,4e45b84b,4deae6b2) -,S(3907e3d1,20ef8619,c11dc69d,c57935f5,d2dcbeca,1b4bbb88,e4629ec6,acbbf1d2,438f96b7,d74e2b9d,cc17b0a6,c936844,e6aad1bc,58a20055,ba298446,1415e853) -,S(c140b19,3eeb04fd,80aa6a37,3407f591,651c944b,33788b71,e6f05e1,672b7d9c,949bfd15,59e24543,9d5fef6b,70763b63,899450ef,430d2e64,1f7077b9,29e44072) -,S(977cf05b,c96a39c8,1dd2fe26,930f75e4,2563c3b6,b06e28d1,740a547e,f2ea56c,3802e3a,8508164c,36e95e23,46ca468b,7e15878,36a9edc0,e70c0e6b,9aa10d52) -,S(1069c0d6,3995e0d4,cad51e5a,9e4e57f6,795a7bb3,9ee3c376,1e827b20,d8a034e3,e1aa1487,9c0e4c65,581d89c4,7abb5e48,47963aac,788fe804,1d2c194c,5a7fe33b) -,S(ff78c680,c3414181,ff3ab10c,74e2a755,42419af5,3527a45b,ba3825b3,c93e3682,eeb70adb,f05390f3,76b2382e,20b2dbed,86c8c574,df2f256e,1fc4a376,24d3615e) -,S(5ec9eb03,3acd3d6a,9c04c3ff,5838a6a0,2b0cb26b,d5c37d05,9056afd9,86bcddc7,92a287f6,eed0df0,17c0bed1,ed9445c3,e39d92b4,8c3a9c8b,9ae26749,732aff03) -,S(eaa206ba,792dd34b,7ee67e14,d8dbc7e8,bef0a54d,a7dc7ee9,339d8ec8,471b37d1,5577e65e,be719ca0,7fef2530,c40c1617,55e00d21,1d78e5e2,695107c6,8d1ee92e) -,S(26d062f5,6034012a,3d76789d,455cefa2,689ef08e,d3d87f54,af952afd,ceb3ed7,5eff1dac,ef6f5877,99c340c5,f0d1f6dd,dbe6faa2,5ace9109,4e7b5836,d1323424) -,S(800d415a,e50db62a,4f49e449,d11eda8e,1a2413f9,c341bbd1,492f2271,1e602d48,569cad6d,5d19b5d,2299ec5c,fd12d9f3,d5c8cb0e,756036fb,dc5957f5,7c02eb50) -,S(6c01a352,bc16dc19,973aaca5,f1a21676,e1531fbe,f8586bb,9853c627,9c9a1c90,833dd742,c9596a0f,2767226a,b2548139,a39a17d2,d64d6765,4c073b18,f8cc04e7) -,S(3accc922,f1b3ff0c,504e7c4d,4738d1ad,f0b914b8,d08ef8e8,a54e431,37742c26,aa9cd483,27d60b34,304dee26,c52b2979,52a2d118,82e10b17,86a09acb,3cb0ad7) -,S(a0df5c72,828b73f2,a380f75,3f8e6352,f8d978c1,ee6ebedf,2ec70ff1,d0f8ec72,b230adbe,f1e0bd13,1e622689,379e7232,b1327db6,eb0ee306,80d7a89f,a4ac6670) -,S(9d5f0d94,9776ec98,607a8dbb,d54865c6,d4bbc970,d3ff85a4,49d57b97,33b52c73,ff08efba,f4893add,54b8a056,ff60d345,ad7faf15,7d11acf2,2cea0f2,afc1a8) -,S(def5d92d,9ea1822e,dea5b293,58a51ec8,228f54b5,a6738917,fb7f2108,6dd3d84e,b6c740d,b94aebc3,138d3ad0,202bff37,9d5bc20a,d7c0307a,479599ee,8b3129) -,S(fa90b105,cdc8d74e,3f87136c,f4d075f,643fb0f1,ba6eb832,73642e65,84df33de,3e6b28c3,73f58eba,49e9e852,f0f0e244,3a180d92,52624c27,3c079dea,50bba36d) -,S(8212e821,ff2f7b90,c01c8461,3d4d9df9,ce077cb2,9706a349,575b8cd1,a3d0eb52,d59c05db,2fa3e756,fda56e8f,33540639,d24bb5ed,2c8aeb5b,8f8e43ff,703185f0) -,S(ee340cc8,1d1f71d7,4b1a641e,101d15e5,24f155b7,2afb4e49,f9cd8b20,ec61220d,915d833f,25355fd7,f1efa796,4a8e8b04,86f8141e,f5811438,f0083382,ae286f37) -,S(2c535525,dd2e3d83,740b257f,bb7223e2,302b5009,7f8366b5,aa26f65,442afee1,1cd4514e,f945b668,4f38f966,2f3b5402,92d43a79,7f73f947,67272713,b61cf765) -,S(df7763cf,8b57a288,cf4a9083,a2a5f977,404b9e1d,6e814f2b,aae9ad45,fa67d94d,4f7dc336,31fdb48c,612276bd,d388ee9d,bf05295c,1a92709c,b4fc33ac,b1580ce2) -,S(3514c240,d6d0f218,11374b92,8cd6d063,8ff99b8f,4d5e4da1,8fd126a0,ecdcee60,2a0d1f4a,1a1baf80,3c98421c,7777ed1a,ac17abb2,720975ce,e530a5c6,4197fca2) -,S(3de75d9,e58bcb81,94dde551,ab541d54,237a1b58,d935f60a,b54bd3c,6ae40a27,9ada14db,be2db058,c6bad8c4,86f25037,3ec422da,fdd5bddc,455b2b8d,25d97c75) -,S(a728ce0b,1804355b,c5c144f8,1d5eb1c2,90ad3d52,f502c5dd,ae28a08a,6de0420f,4387cca8,f72b51a0,cfb4893f,a85491fd,42cce3b9,ec3344f7,ac93d001,47ddad3d) -,S(ec3c9a8a,5b844c0,947b22e0,2503a815,1d8234ab,aa94032e,16c1d874,5551c39b,7b08bcef,45f0fa93,660845ca,44edfae8,c8ac51ce,e836b043,3825e410,8ebd7fa6) -,S(b0173d56,24945acb,3bab7e6c,617532cf,e619e7cc,e9872e93,26a8ec55,a24761db,78d27b5f,3e9a0761,d0feff12,198dcb11,72a81df3,1320f10d,44591ae3,5f1b381) -,S(d9eb3bf3,cd43dc8b,977c3890,ed3a4b8f,4e04bd11,f95963a7,970d9600,40cd73f6,98196b5c,c42e808a,3f1db718,98c50048,510b9e4,c9b69c41,e7f5b2fd,63b23044) -,S(fbda51af,8a40230a,c7602606,21f92b38,29bbf1b0,1c027f10,7ca54c08,65a84e74,64833994,aa453bd5,4c8729e4,e9010fcb,8fd427ba,3bbe7c71,e812513b,fcd6ccf5) -,S(ae4b9a7,51be1966,f564661,61262faf,472b14c5,f0532cf8,8af872f,ba583f9d,8b2c248b,aa9d7e5a,6f0c6eed,9ad3ab5f,e2bd4078,da4fa281,f4b672e4,9695ee5e) -,S(58040152,6088026,1668c6a2,e462845c,f29764e0,31edf6dd,a40b6e0c,4ccf6ff5,d2f96ae6,4a83c04d,a072f9a4,e39976d8,a2e5f88f,fed070cd,5fb1a701,db329485) -,S(4c28d686,57380f81,639abbd9,fafcf47f,cf477e26,1c46a03b,57ca7326,4c7e029e,694b8a9c,4fa75e14,56a67e8,acfac16,3122a941,150da022,59fb024e,ced8a70) -,S(de205ab3,9e005587,f23b51a7,3d806f81,6984fc77,7179a6b9,465a92c,ff25c9a4,ed84325e,12efc1c2,db42cf1f,eacc12c,48f68e42,9aec9135,5af5c327,c5273d83) -,S(5ea82868,c2cb0a7,4b658dd5,721e6571,b968f589,6d22a5f1,b3ec6b69,594273f4,88d10eb0,8db264f8,13adecce,636f6c58,e1828539,1e538ad,6e2237d2,384a9499) -,S(189cf7c8,64497416,420bd98a,3e3db4e7,c3b0dd46,d7b9bc9c,37f2d036,324998ba,bb3409ce,d46dff28,36601b1c,f7dd606d,7422118d,723f7da2,4d25802,1edaa083) -,S(70a17187,38f50d43,8868026,58100245,3c3c41d7,8ee5e14d,3cf536f9,bc82789f,15c95120,e112537e,41f33870,18f09d1e,101dc445,a9f36296,2b9462d7,bc27c1d6) -,S(578ac0ff,622adb6e,8c20eed,f3011085,8e4271aa,46833865,cff46b9b,fb3a368,f711a1dd,f5f3172d,2b9b2f7d,9d50818a,6b0ceaf5,1d67e15f,1f01ca5b,bbd7f851) -,S(dc9fbc03,476aa747,d64738ba,ddce8a5b,5887f177,fa6cdaea,3e3b05e2,8d840071,c0f6752c,8087dd25,f8d94a19,d294e550,8bd26774,cf4e7ab9,515f0a4e,89eee1b4) -,S(9749acff,a348cd5f,2e84dec0,b3d73151,4bb817dc,4596d78f,e0295215,47b0294d,df667dea,35e54810,daeec20b,e0e7d203,d89856c9,94501167,23de84e0,5781a1c6) -,S(e39fbdcf,2fd2730d,c3359f21,fa815478,ae8e7a98,d6b132e8,e92d343e,32657d85,bafe9881,70a78596,76a6ae3e,364885a2,62441578,8c31c283,20a06b0b,e5b5e01c) -,S(6009014e,27f13712,c00bda4,dc913516,e04b692a,ea32b89,e0fab8bf,91402c09,34910894,f6bd1cd2,cb796f58,8ddba661,eb4006a8,6cec32e5,7086099d,42359f6b) -,S(bf04f247,d02e46d8,2fb9bec4,f76b3eef,b644c92d,43622162,d419488e,87f2f773,d646f4e8,bb3c2e4c,f19ab00,4674e354,302e125b,c1ed684d,32b1cebc,7c2172f6) -,S(9609f7ec,b122b353,85871efd,915c6d99,3e5468ab,c30e9acf,f5b4dfaa,31e5e3c3,106bc52e,b933f0b8,71578ac7,74e2ad89,ebb4d9f9,eeb95592,5d6b50dd,988f9a27) -,S(b690cc3a,e1ebe25,a07440fb,5cbdf56f,f5ae581d,4dec7366,8da2ad62,bab9abe,83cd0023,fd3a3ddb,2cda9603,2b6c1657,35e5f9f6,249a535f,b9666a97,e049dbd1) -,S(72da508c,ed507744,1aa2bc11,4a9098d8,2c947948,395bf38d,6cd00977,91d326d4,165baa93,3433ea2b,e978036,4fec922e,e5d743db,b8117e09,5eafb467,3f668457) -,S(e0fd116e,540a3009,2954322f,5125a72d,1133201b,985d1017,29b1c9b7,a9851c37,c6bc7276,48aa707e,549e899d,630d3155,a516a06b,777997ac,8509045e,e5b88a92) -,S(9d4b8bea,85d4e412,ee0d6389,e883f9db,297f01c,d0695c13,abe2b682,94c10af1,5e2280d7,3f7c0832,d9ae62fd,6a884973,5bb66ebb,e68a38d3,8a95258a,97556181) -,S(eef84395,aa4b6e04,ddc56123,cd5eb31d,69f1255,1c216d25,5057a2d4,388e08ff,45098aa4,34e14364,40d8b26c,73179c48,87797e6d,59963928,b1d6b61,d62d2376) -,S(66fe5c7d,56e38e48,6134371e,76ef427,b4652daf,6e60cde7,39aa1165,c90d7654,2d72926b,b6edc93b,7e40ad43,3cbb6c4d,96d4c384,966ca582,a108a84d,c11a2fba) -,S(5135f9cc,1818caec,cc55a304,aa983c98,82f9e1c2,939f27af,dc2c6df2,c08ea2ed,5a526dd2,7dfe1750,4f8baf4e,115ae1b4,2619b5e1,47986954,27ca3621,e03f22d6) -,S(1a37c089,af7f4a9c,2ffa2bc,c22a3e29,82e3318a,ce1ae29c,3fdf9b62,3e6487ca,d389c033,8522230b,a96b33d2,373672cf,509b0312,35d2ec18,3c955ff0,3d2464a5) -,S(49f7a5ff,15daaf40,913c68df,c9016f95,ed1edb22,22fb1576,e4a11848,47a248a0,f9b55b01,3d637bc9,e9794246,fa6bbef4,d5ebec82,1a5d7f61,1a18c7a7,b9abd8fd) -,S(8247845e,5d9ef839,207f0f1e,26eb0470,3b87f835,ac3af130,253aaf88,1e641ed7,577d790c,1a23984e,7f1b1947,4cb42ad7,b4409c8f,23f391de,3e2440a9,e53c5f1e) -,S(8295984e,cd160241,ace92ef6,10853e8e,57b7823e,25eea4fb,8f118593,d90e0749,635321a6,6798d5f7,39a450e7,67b1c38a,2c5dac96,780c83c1,4c38dbc8,c0ac8353) -,S(d4c32bf6,d8fcf5ff,be0ba34e,770c68b5,fb5db412,b1341537,7b2e9c80,3dd75461,b3c73602,e23845b3,2c44272b,4eda70b9,a1a71e51,66d13353,74153f66,4485f93d) -,S(1a08e32d,4a968e6,a44703af,6b526a32,3babe7ca,6882cd84,9fd3f769,6cc897ff,46ed98bd,b77bed4a,25c2e19b,e2b14a8d,3fdc8209,70344b39,9a6b2a8e,afad4141) -,S(8559be0e,96723f04,4b05965,da8c9777,6b40e1ee,ce49de82,e7cfdc34,354f4af7,63e24b88,854e20d1,2c3f049b,2dd0906a,ba4db6de,aba42dc0,5af03dd4,91333ef6) -,S(e0e0b223,fc7a478a,849c0ee3,f2ef2a6,edd0f08d,e8ccc8c5,5e28bdc6,5e211e8,ca38832c,3aaffac1,206d38e1,25b8847a,6609a5e,d1288d1a,511d6037,9fca60fc) -,S(a237be98,2d8ed250,75801eaa,5917582c,265c3424,5679b4e2,34539ce,68e40a19,f4cd227,976a3780,454d5de4,7026d668,dc1bfc32,9003c87c,f48982a5,5a231318) -,S(28a84882,1eb08d07,f03fe770,5a16f2bc,5edbd0d6,b4367ef2,474f9b60,1205ccf2,9067d3e9,e7d77628,ba0526b1,71d23da9,162551bd,f00fa301,eecb5fc3,f856a17c) -,S(142fe8d5,42bd6b5d,325b8fdc,3820de5b,cc83e2ee,13d59d16,f4c69adc,98c1d5e8,2973f278,32533b9,559d1421,38d7fa60,1b66d106,1bf9c453,9c8310a1,dc75b150) -,S(5b3b611c,5d20649d,19bb00a,11b4b928,8f3d5ffb,700fb6b9,9c97b012,98ad87d2,849059c8,cde0e12,cdfa7621,9ed70bb4,192ead87,5a22c58f,8ebcb58a,f2519182) -,S(248a2249,5d4905a3,f61f74c3,5f35f6f5,2edbdc63,9454cf6b,192c7ce,50beb8af,b5a6f3ff,b707c108,1cd97b24,38867a1d,61eaf73e,9b89b5c3,b1136ac7,bbfd4c83) -,S(8a474a2a,292b50e9,d4d1fa99,a229023e,31ea2093,2d3a5d2,875384d3,dbff075c,7745285c,7d5341b1,e5c39289,16cf8fd2,45b5f045,d30d5dc8,721d6b65,ef804dd9) -,S(3fa01255,7fc042ea,67cbe4ea,86637313,826d10d2,48d5bb22,8ca8d113,5015ffec,10b9d325,f59b4b8e,ecbdca5a,58c48e18,162d436c,a3228b25,e3f75f27,26a937b3) -,S(b77b5c0e,7b94f1a4,dd88f007,1af049b3,6b778d5f,c8a828c0,46ac2195,9fd65648,31246bc0,6722bbea,8c9d5722,26edd609,e2b65d2e,9df6c21a,d54cb157,faaeccc5) -,S(2635f482,67e82b97,6c2ccad7,89bd4bb4,5671846e,d5d1d8e0,8f2c41ff,8535b44a,7edc804e,956091fb,667f9e4d,47b7353d,d2ce39c,b53234d,afb6d5a7,a72b8def) -,S(2306b52d,ae0952c9,c6b6f39b,6d1ea36b,ed0012da,18d77238,4a4e0866,361b474d,438250b8,8d7b8f6b,9a63688b,b2cefcf4,bd767472,bcd21221,582b56cf,325486c0) -,S(caa866b8,dde8284,8f586f9e,ed5a1d1f,aa5604ee,a8c0016e,248d897b,a9f74b4c,2818f140,349f78c4,572834ce,b805a424,e33746a7,d58fb8f2,9954a55f,dc09c341) -,S(818def5a,a0793d50,5f5e9cc4,29c01ed3,fb5e577b,b25277cb,b74c70fe,88bb1641,da9eee80,f7621031,80e2d54d,796367d1,f48ea2b4,93a1445f,bddb3ee2,ee4f276d) -,S(2c62cdfa,568d412f,cd764ed0,1bcac5bb,c36e11c3,5a295bf0,8b12df92,447bf736,e8b8e025,58117062,705ef985,9aba6418,ee73eabf,195325a8,f82c051a,3ec31979) -,S(28ab54d9,9db06e8c,d4a2f7cd,517d049,4e477f1a,b6eb3416,59bce807,e1f04adb,993b5319,a5cb9602,be656276,bf3e7d84,4fb00304,1ecbfb08,72aa29e6,7494541c) -,S(493e7c16,2254a40c,54b4eca4,223a8241,d6c2abf5,f15ebbb6,3ea4814c,512b6061,56387f7b,588d9d4c,fee36b59,7ae8f21e,5fcf817b,f097ec89,7def80ba,3ceed628) -,S(672e11be,e7439165,4fe118dd,a2c5d389,8922a68e,222c9bce,902d2062,b9c51d4f,3555134a,2382a9d,b4bcfbca,45e9d62b,db6bbfa,bfce7c5f,c5102dc3,23dc36e1) -,S(8f8d0f6e,e3b86889,8de86c06,b59f8e5c,27524b2c,2959e701,38b2c3,8eda550a,e7def281,9e27abc5,9940fed6,687bcb3b,f364296c,26bf1fd4,5d417103,49212f34) -,S(da8c5783,4a11f0a5,797cf4c7,9179f30b,118f2802,1205d495,e8213fb5,78b293e3,6ecfe35c,6f663975,86bb1c3,ab5dc518,7c7a0ce1,b6338d28,a2c01df3,89c35f91) -,S(4953e0f5,3b1965ff,3efec2d6,fa99ba0c,fbce09b3,83e20ef4,2657faa1,49681955,c210c78d,9d1635b2,3e468324,7980766,3c28fa97,18d0ca39,fc09b541,975541c6) -,S(5491fdaf,48a0e1e1,be21f7fd,be910bd6,5cd3e0c8,16da38db,6c742042,3775f293,65273688,5d1c5338,a3be9b29,9b51f4f3,9c82de96,318643e,3d34ecd2,fc7ffae7) -,S(b9c4afa8,42363b9,fb583885,8f17d1b6,b0a8529,43c907f0,af3ec9b5,abc168d1,ebd3106b,1b75ebed,5d013aa1,eca7d8d5,e24d511b,6d4178e,514fe156,4b550d9a) -,S(918da36c,444847a1,b5f9826d,eab809d5,d6802e73,3abca386,24237683,92d2bd62,6e6237af,d7cc87e6,15e14113,ab38989e,889d5e6e,6166eeca,abf1ddc,8a53e218) -,S(777d2994,da1f514a,800240e,59b743cc,748eb42f,4572ac93,a2e42e37,1d3392a,6193d7,e9eb3195,2cab96f4,14e1d24f,9d92505a,9d21f864,5e6dd3a3,8a9680c6) -,S(108e6ea0,9a08c5c5,e27b8b3e,af24ef55,3988c650,34ef954c,4d17f232,5723bf3d,1a8b974b,86db6bb4,7c314ebf,f811937a,b8a0dd76,e824dbe2,88fde1bf,fc13b2eb) -,S(36d9dadb,65a54d49,1198a486,8deae1fd,3c2dcef4,4a682839,b5dac54a,456bf185,25e84356,d93b5d86,25eec306,565bef19,1edd9bf8,347dcd8d,785024b,2147bbf7) -,S(3e0ebab1,43ece776,729d8a9e,302726ce,aab89654,23292fe3,ab2e71d3,66531fa7,6e7b2608,556d6236,8948f32b,2fb04b34,8e38eae1,3d9abd5c,691383d9,958d41cd) -,S(923dc76a,f315f31a,a1de9521,a13ee9ab,ab08ab42,157f483,2babdb5c,18fa3728,7a8f17b6,7439857b,3141bfca,6d89e649,7facf685,6331003e,f6bee07c,ed3ae47) -,S(f87fff32,2dfeae3,4ce9cb81,51ce2e17,6bee02a9,37baac6d,e85c4ea0,3d6a6618,74e49037,aa726e0a,357ace25,603cdbfe,7c14a4cc,2e1e4e13,c7176121,585a03e0) -,S(1388065d,dd7f69a0,11dec106,b539f7e9,e00b5aff,7568820,e33f9c1,18881ed,acab1d8f,140661dd,422f72a5,5ab4242c,65d1a932,23fe732c,92b32317,4d13408e) -,S(e5476b1e,a99b6a08,83731542,7a3751b8,3d685b34,acc5201e,59e9b623,ac4b6941,57d5b2f1,c4dd795a,323c794c,aa8fa754,bc86dd67,3cc8577b,b418b2e9,5f3b4e21) -,S(f938ff60,f1e8ebea,4c229d89,4c98418e,90c14981,4ed7909c,3dd47cb0,15cd1f15,d7172212,1a0cc646,a0576e29,372bfbd6,37fe2c5,b6ed6821,4da50318,eebb13e1) -,S(b31bd410,7c4a5108,1795544d,5854f9bd,180b494f,a08878ad,8ad5a3bd,98a30aa3,94261097,6bd58962,5e941aff,a007eab3,d33828f0,e12b31c1,8fb6f5c0,50519e82) -,S(b3ed87ba,83210d01,1a2df141,b9a6c6d3,33abd692,55da3af7,b4447d03,f4c1cb2f,949dd379,29c757e1,a970273c,b6341e66,b90be71b,347e747a,be0914aa,4dd632b3) -,S(60e6c240,1ea790d8,4bb95e78,731bca08,89a57c0e,38b87f46,668ee16d,31221e17,f247bf35,c722098f,2a5c800a,571eaf0,36738704,4050d98c,c03bd146,ca9465c2) -,S(2ae806b0,4cc8d047,e7dd8d37,713cd71,eaf3e16a,f74c3b87,994afaf1,c3750a80,a8d978ac,b29771b5,1a87fafe,605ca0ee,6facf6a2,41aa135a,e38de4eb,b2e2e954) -,S(9af178a4,bbba2d29,e7a0bb15,51f6f3a9,d2384386,3779f439,58a424c2,29bb5c47,c1031fba,a0238857,a487ac85,72fbb3d1,4052a4ba,adcdf259,78101a21,ae79abd3) -,S(9dd6a721,e9cb27af,2e7da097,c9e8a250,fd78a531,330ecb2c,3a116d99,6008f523,e6837b7d,647309c9,4712adb1,4bc65787,fc4e975d,f4e82173,57dc9d3f,e7f36080) -,S(cf5f16be,d7a1a1e5,3b3e3f1d,e44efbb7,fcb717b6,9a28bf0f,e31a1da,a5e91c52,9549ebd5,4d87207b,c63912c9,99920cf4,b0c80a0d,8a69d4b1,4852834a,c4487497) -,S(c6794890,810954d0,782466a3,c52a0149,de577cfb,3a2001af,d45e905e,dfa64722,4a4fdf51,deb64031,bfca5fbd,5c827829,8621b625,1be69187,fcc2460d,f75ca468) -,S(a25fffcb,bee9e0ff,1659c1ea,41406aa,b03b4920,fe1a63e4,442d5241,30599713,176b9e06,5a821189,ac3fc28a,fb72a1ba,40fab791,4de987e2,1236f244,bf41486a) -,S(6079a722,fd5d923b,16acfafc,7248e329,128cab6a,cae9e5ec,dca49774,e0c5bf71,c09972de,99ca5a45,c4f6f1d9,10337efe,23f5292,bd5ecc45,df0f7aeb,d18c4bcc) -,S(188cb43d,9d4078e7,18fffc42,8b16723e,f64b950f,cab7582c,8139dcb9,2b66b403,a038fa37,ec9ea240,9a2879,9556916d,fcc8c2f3,358ab14c,140f7f1a,23af5404) -,S(e310fc40,cb575c68,f5792506,65567ec8,c445ca34,68cfd02c,d781b27e,f819bb30,31328a65,5ba312ee,5e901def,66e7b946,e0c18336,a0f1784d,df66b89e,2abe625e) -,S(dd86485d,1c8245dd,d940bdeb,1f462cc8,f15693df,246c3c8e,52b574bf,77dea4ac,cd6bb7c2,56c9a270,4c690175,ba298a09,8963a8b4,7e743b48,33fc09c6,9966ce2) -,S(1b7ed20c,f81567b8,6f7dc67c,ab69e197,dba77399,9b36097b,de85d02a,7019aef,f814e92a,d1cb4386,550d89b5,9a4bc378,df428d54,d314d531,be6fc35e,f0e3d1bb) -,S(a15587b,2d528338,ed146a03,670b3f1d,9b41cd0c,a0645897,a0f719a7,b5ded284,2aefe34b,5aba1a4e,e30d225c,c4023ee7,12fc1522,ad6b452b,fe6ea727,122e925d) -,S(57bb9f9,c99da691,98cfcf20,9a0940ce,8d19463,9e4d1054,484953e,936a5484,63d0fba8,d90226e8,2c7be5e4,1d77bf0f,700dc57b,d8d3079e,9a6a47c8,331660e4) -,S(224295b3,7fa1b4a0,d7d7f7a1,2113b21,291f84fb,8fa4b746,bab925d5,93bd262c,d60ac40,b1e4b0da,7563eb74,c222660a,46ed388e,c4517ddc,ea2962b9,38195796) -,S(2434eae6,a34ec53e,7c031b2,9e74354e,d6101ca0,f228055e,53b39a6b,5453b0e3,2ff5ed61,d57a04bb,138f3956,33a20e60,8b04f775,6476d0ed,6ce7a382,743ce23d) -,S(448de592,907c1113,bdb04c64,9fb22b05,ef2e6ab6,36d0a03b,700a5871,89885ce9,d7aacffd,6ab35068,debe6dea,25b02930,63af8b10,d4592880,3d0421cc,a879eabc) -,S(8405cf73,5aef7674,7feb92e7,1aa3ba0,defc0a1c,c1da698f,7c2a3718,6393dd76,5795d006,49cd10a0,4a661c78,3f4a8711,89c9ef2f,ba86853f,c7955258,e6c407f2) -,S(698974c1,e5c1487d,fe9349aa,371eb86,9318accd,72c66d5,581211cd,6e08efc9,37c2238c,dc8f4bf5,1f76536c,2ab9af61,bcec872a,bb84ce15,90bc1c0f,ef84509c) -,S(8a37857a,be3cabc6,7197781d,f315f78b,e6548c61,1b846d8d,ce2e5732,643fee05,29882f68,9154cd0,7e455e4d,9e3866d4,5e28e99b,21dde0b7,8b87698b,4cf674ed) -,S(a871b34f,5cdd39fe,13104c96,87a8a717,25ec8cdf,fa60846,793bce03,2397eaef,84f96417,9de103c0,9f7e2dc6,86c9213c,642312de,8de6cc5d,f3ffd7a2,c387cb28) -,S(49bcafb8,9f78a7f5,a8857905,e99e74ac,9ec66ec7,aeab8fb4,fd964ce6,8286f44a,e7db8ccb,5641ab74,a791d2ca,7bd193ea,71124a61,2716d94f,4eae407c,ed9eff6f) -,S(d5c7d92f,2f05c9e5,8f586289,dffe8499,40d9b84b,79feb686,c3f71300,f68b6df6,a68b2a5c,219ea38e,a04b272c,e1cf42bb,6fcb2b2b,fce36043,4f1802af,1d51c08e) -,S(2ac2fe3c,fea4cd7b,9c74a249,cb0c8ed0,6a825cbe,2826c56c,fe4a8db5,3b286696,7d90a659,b008a51e,ca2f6031,c6ca6078,505bb46c,f00a3834,a67e7804,b60f43f) -,S(7c09acbc,62827ecf,4f63a85f,5a0eda7a,5b0069ef,b03b51d9,2f61c5aa,10a39234,e07d2539,c29128c5,685f8641,45fdc318,854b56f2,962b001,5a96c688,69624836) -,S(e886dd56,7e1b42e7,69941ae7,13b2fad3,3bb4ff02,34a27a7f,2c496bbf,6ffbf9f0,d4b2277b,abeef80f,371c097f,df4e5de,5a4666f3,c630b010,81d1172d,c667a877) -,S(edf65cc8,e83983,c5a178f0,ff60bb1b,8ca8a6e5,85344464,73a199d,59c2dc,a2426713,f0c5309f,84a4710a,2de1cdfb,118a4db,1070d23a,92c76244,89ab2d5e) -,S(29c12f04,b78a6ebb,9356dbbe,5b152323,435ad7bb,a3d2d036,a746af6e,d26d17f8,8399275,bf6211aa,78ea211f,39ec451a,b3336d27,fa059935,8b7fcece,216eae4a) -,S(d5db8b8c,280e9914,f0a034ac,3e0f9fcf,169f2046,4a618789,994f8a79,6663c3e2,41163c3a,85a0039,f5e5635a,819941f7,98f27078,aa65ecbb,eb60d577,c263412b) -,S(990a4fa5,630eb00d,958e57ac,8bb4f7fe,10e1055a,c547d165,7000a17c,d9135f8d,f25ee025,491fa289,446a0364,68c71217,eb252414,f8fcf291,2ecb23d7,4bc9653b) -,S(d784ecf0,1c7849dc,ec901c3b,3315cf53,4e3049ec,c68d71b7,41637b57,9e9c0935,5de98d22,cc382aed,d8c82a84,1ec6fd46,30672008,8567dde,6b2d64fb,6b4205ce) -,S(6576cd0,58850cbb,aaf53b67,bdf3c19d,9b4d38e5,19c99338,3204cd35,6ce38193,a329993e,92d1e56e,31c1fbeb,27648fe3,d984960e,30bf3420,658f74c6,5710eaca) -,S(957788e5,f675c0c6,4649a808,1c4549ff,20ccb177,3d26e4d8,bb94844e,bc35efce,7ea4431c,dc4bee37,d95c3948,615e17cf,1d32906,9bc10a8c,515aa0e,521d9b5b) -,S(8af7ca80,5053b537,ec501abd,78c13ff0,da5549f3,b045096b,1452c05,e39e4a2e,25e86225,aac042e4,cfb235e6,da40543,6a436206,e9d67fb8,e1b5836a,2d7e8402) -,S(49bf0393,e16e634e,202ff642,ad79c179,e6eb7456,637b2ba2,623937d0,e215236c,8590613f,401de0d4,1cc0ce1e,e9a13441,41e5f80c,179ac722,d603e697,a431a85d) -,S(c82e2a25,2572863,527b6858,18c9b6dd,df3653ed,a264b5af,dc5ebd19,d4192063,3b86f800,cd87c1bd,3d70af04,47f9e939,c2717ff7,376f91c7,b2675e3e,39a6de8c) -,S(9ce43920,2b9a8f7c,3aefc9c3,fe4d227d,42ec1355,158b2041,a3712dfd,d8eedbf3,dbbb5b05,859aedd3,faef15d5,9a939ff9,53a54bb3,dc2ee6e2,6d5a20c9,ff5b52f6) -,S(e07009e,49de05ca,52d20221,3ecab4b8,baa707ad,96ef24a,168bdb6b,16fe6227,6a35b0bf,e752ba26,81b865b0,ade8d4eb,2583833c,a1523b2e,4178f9ce,6cbc33c9) -,S(eb4dcdb4,7e09af61,e4694814,79612715,d588615f,f4c23fab,65015bd,821da888,63e38168,584602fa,1e06536a,d4c8115c,86305c,41040083,4a55d153,e9661b8f) -,S(be5f8681,2bf20113,1d257015,dd29dacf,a2c65907,26078f7b,f864f339,10e49db6,d0f420e4,56174aff,5995a92d,a73fa511,43c4f1b8,c40e9f30,8f04011d,956d9da7) -,S(3b32dc39,10e75f9d,98fa1318,edd7e8ef,db214a5c,b31d5ed7,4a61f881,355b99a8,1a12de86,19c2e9e5,9fddf756,e752e54b,6e4e0aac,572fbc42,18baf1a2,a3a18bc5) -,S(95ac5dce,5c06e885,65d2922e,a3f386b7,dde10735,169729d0,a3c3e7a4,86e04db1,1a22cd87,ab1b1821,e3c49e85,616b7b49,680edb77,251969fd,e77b5b27,3ef39838) -,S(6e4ed0fb,a4b0f13e,335d1b74,a5ed295e,7dad591e,a8dc5cc,d301836d,7ce708eb,9056166a,c61c4e09,ed988e6e,59cd9ab0,16a2ef99,e99c1a54,ac37f152,a34b931) -,S(8b7c3394,208e0ee1,374925e1,7827d849,ea8d9a79,91d2d859,898eba2c,23a42e10,b6ab9237,96720bcc,910e6440,75ef3ff,2c8bebf6,2f21ad0d,3abeb2,7043d193) -,S(fda7b47,f6690d73,884965b9,8b6f5dca,dd48ab4d,8f96edcc,8e20584b,b0f871c6,9b402435,a272cc6d,28b487e8,b54b473c,30929222,55e47560,e18b8e6b,ca926c5d) -,S(f15da0f5,395a5a1a,ef8beb53,4c0e9aa3,6e63018b,cc91a55d,ad6106a3,3dbcb217,28cf69ea,bb3b0151,917571ac,48609723,80be252f,bcf98f6d,db6ebf76,578a8f1c) -,S(c6e266dd,2c7817e0,c92378e6,38709a97,d9a208b8,7fa832f4,abfd881b,bcaf9253,2af100c1,fa9bb3a3,c8e95e3,5d0bef58,5ffa7adc,93232082,84291ee7,cb769626) -,S(4bf8aa02,fdd201e,488c21a8,33925687,7f5a727a,4fdab13f,d133d08,b6e28753,58812658,ad9c4d59,a15c6bd7,9e6c622,d8fe5f05,95cbdd88,f39be9d3,cd5fc8b8) -,S(aa985f28,6dd485a,5589fc39,da77fb95,5cda673,db61e48b,972fc129,7cd0a6d3,abb0f897,2f1163b3,29a5a92d,a1ff02e0,7c277710,10e24a04,e1e5f60d,1e4b75b2) -,S(8174d101,ec13a1cf,4eb9f88d,88c14121,6c2fa04b,ced197c,8e1732ec,61c41c9d,c6765dc2,31b02e7f,eaf7a662,5a639b00,c6e5d94b,1a791bbb,46f6a758,8fd79aa7) -,S(f9f64ea9,d6039297,b728fe09,85a9a3a2,92573aac,fdbe6cbb,8702f04f,6df3d876,4146c7c1,406067d0,160950f2,1172e879,188069fb,d87eef9b,1a67d2c9,9a4ca01a) -,S(3e643a70,5a6885eb,3d34454a,2a5de925,f8067cbc,1ca92951,d8865ecc,a8f1b3b4,2deca704,5525534e,de9d54d1,d777a996,8b5e5882,7162ef11,b0fe08b7,e2fb0355) -,S(444df411,fcc3ac07,7e95d200,d6f76d03,caae45d2,b87a882e,4c0966f3,376c63c5,b4566598,643d964a,a7cd1a4d,f2decf3d,ec520c93,ac6e32bc,64350aa5,5416cc23) -,S(12a2f61f,58be35fe,314a7beb,1a6810a4,19cdaa6a,8424d465,bbb7a87a,646946a0,9a7bdf44,94c2cc8f,f1953946,1a69fbca,48410b31,95d79069,8dfd535d,290ba47d) -,S(bdd72692,462573c7,3d48af94,b687bd22,511b2b7a,93f48793,3d52b2b7,e264cb9f,56e6c4e,b794fab0,bd5ac992,3f7469aa,858e6df7,dc40f4ed,955c0df7,a2123874) -,S(e1bd5558,77c3f55d,12b4f156,ea4da9ef,c974bd29,d7d043d6,ec7fe56,a4066bdd,8dcd9b99,fbe7436a,2382bea5,6c5a32f7,789cbf1b,1c44433f,f5a95075,c3233170) -,S(a7c68de4,781c8294,bea46609,f4a1f550,fc064eb8,b071985d,804351d2,60132ad9,a08278b6,3d9efeb5,1062b240,d45989ba,6f6bbf9b,ebfa0766,8428862b,adb42c32) -,S(4f3a8769,b4c6e369,cbdeb90f,5137d07a,5fa0d66,3d8ca79a,56b3c70d,2a9aa855,f6c051c,5f701e15,348ed9f2,c4707584,b9d6db2c,b62bf93e,35b6486e,ea6ea169) -,S(deaabc1c,8089ebfd,841cac66,d8a6bb58,36fd047f,cb435a8d,74463dde,f444f232,fb7cc4ba,49c26e7a,a826e654,7c8a6d64,ccd14a49,62a6d4f9,f50c293,c228e8a1) -,S(c411af61,547b1b38,12551e1f,4ef2b32e,fd7f33ab,7cfce378,8b5b8f93,319c0695,d2bee7d7,3d50f82a,e9266d21,2fcfbb76,294ace4e,f6222ab4,797bbf88,558cb66b) -,S(d0ff6a94,485bdda8,d0c28494,5b9dddc4,4a35f101,d0a89637,8210bdea,909ec5e7,ab3f60fd,2923a8f2,d02b7e83,d8f953c4,cb1910ff,83a92a65,e2121f22,364f620f) -,S(a0d05cc,9555ed92,2851baea,35ad6cb1,6f2744,b3fe424,98235aa7,1f08c0f1,843b1105,237158a7,bd7e67c,a20b2705,50afe2ad,318077dc,4714c7c9,d6339948) -,S(bea08445,eb295fba,5c83ef6,7d909978,7d599642,893fb9d0,568e5920,1e3f5d32,2a81a7ff,b3f7f453,d78bb2bb,41d12ed1,e26594d6,bd4f5cc7,908f322a,6cce10e3) -,S(e8ebcc4c,431be689,9eb5aea6,f6ab9700,551c3098,c5acece3,e822c7de,e6f0d5f0,ef99a461,760ae4f5,8fbd511f,59a2ae79,6d65db64,eaa0d61e,97d0a3b,31fa902e) -,S(4948606c,dd73dc44,ecf1db77,c796d8b6,806bab5,85877cd1,d9630bce,966e8fd2,3c67333f,786c8c67,841630aa,639446a8,cb8c13ed,f3db9123,bc64b925,beb95f80) -,S(4f259b32,40d9efba,4e3e40cc,a66cd494,fb5a19a6,5b5c8a16,5c18792e,9ea778c2,fdd88087,78c26999,c4a00605,49f4ea2c,b1590f7f,4748cefb,1b68eaae,4d17446d) -,S(f303a493,e14d7f52,f276e2b4,3e118eeb,1e7e918d,e7aa7f33,7e350fa4,7adfcc29,c49fa46d,befe53f,5f5bc49d,aa6ad265,453f7977,c5fe4163,cfa1bd4b,69141b57) -,S(e00c4b17,f4c0800e,c1b11859,c40a560d,58b9fdfc,29df5a41,ea4b2f53,c1df595d,62441a66,c3ec4d29,d18d0d95,7b4ccd18,a72a1003,d34832fb,8c81fb75,9763b99d) -,S(484b8486,1af6af52,a47603bd,2b754be7,ca16bef2,21581171,4cfb2301,db72ce70,36f84ff5,a0ac79a3,fe696865,2a0a6759,cf72e5c5,8c76359,d477e72c,4d32fbc7) -,S(88be58ea,d8b51f44,a1be6a8a,7cbc149b,ca07fece,11a7adab,210467b8,4cd93f14,94c10caf,7037fbc1,71cd6cd6,a0697b19,8ebbebf4,9f00c67d,4d46ebca,92687fdc) -,S(abf6ceaf,9fddd7ef,44a75e11,b10119b7,7372a3d4,7c163b77,384de944,47da781b,5cadb30c,6320c67a,e9dfe2f3,b9bb4ef5,41718392,81c4a59a,7960eccc,6795d290) -,S(e8c26522,9ef665b2,67fcf10a,17c6c3cd,4e221e0d,95663deb,74f8384e,b89d173a,9a69fbad,f9b050ef,d231965b,30d91646,bec7ba26,9fcd0934,35ae11f,ca2aeeb3) -,S(66652bd8,bf72ecb9,5e670a24,e8683155,e031f3ea,91fff58d,f60fa4ff,d9c6c23e,4844ec08,3f182b73,22c2fbb6,6f6630a6,5fa6901,52dcfb3b,4b65a3a9,30be994e) -,S(207880c2,d8421040,dc8202c4,45bf6d58,75cac841,532aaf0b,adf252dd,4c2c0964,2b1819d7,3eb24de1,ae4ef316,7c92a7b1,a562d93,80fdc54,e916d1f0,c1860cfd) -,S(46b9bde4,53d0692e,ec933485,ed0dff68,7e8f262c,7d9270cc,763fd959,2013f581,58af9be6,3ae599c0,f499b0d6,3085b7d5,394cc786,9f2fe225,6ecabd2c,a14f9bf7) -,S(5d9b2574,dbebe5d0,9756e2f,29af3aa,a2fa2555,d629a78b,82b1d679,75ea3e11,ed9f40ac,aa6ac68f,cee3dd50,7629758f,f3a64190,1658f0f0,2b87b645,ee59263) -,S(ecb5ad82,8b986425,9a76a649,1774338b,dc598fd7,77cfec52,d086c172,6e590e4f,2b78936,73c6d87e,a954b5bf,52f8212f,65d33ea7,ccc4b4e3,1d98df2,c9887886) -,S(b32b64c1,5e711b8a,1d174725,de55c,ddd62e99,fc90e96e,8f3ca532,3924ea67,af5d61d3,6dceadf2,34a7a94d,e7e4be1a,4d81b84d,e0fe16a5,403b0c24,a6ac2083) -,S(5137f71b,71582334,a6d57aa1,5cf6ab3c,8b7f6842,a800b4ab,1c308fc5,820cd364,f7ea5fec,c9b17dab,c6a248d,49757711,e4a3b38,95658381,efa652a4,4df1eab4) -,S(b9bb0e1a,390b5889,3e113a89,801c3f5c,25f94e65,63161539,e7c56297,ce9ea866,d8db3c90,3c3d35fb,ae4e14ec,e81e4e31,247f60a8,2539880e,6b66951f,8324a11) -,S(3f091967,6da40ec2,4691c21,1c42f47b,88cc1192,ec1827d3,17beb468,924fe9af,f1b44826,3e882c1f,18ae6a81,238d0724,ba4c04bd,d3fcd395,8775df5c,16bb8de9) -,S(b5fa25f1,dad4600e,8d55e7af,c70a1b2c,3767da47,d625ced8,d55ac88,d893b4fe,7575f661,f2ba296c,7ed3a190,8a49d099,83e49503,ba17a70e,1d6939b2,8ad22347) -,S(a0371ce2,dc6a025b,78db797e,90373069,e4ca06ea,6b1cc018,3d4c6f7d,680d17b0,92b5a8a8,9a5005ce,e851c521,4599b774,24f0ff74,5c4af6bc,6937c432,e859919d) -,S(5aae6e90,a49107,78863967,d7d42020,cd0a9828,da25ac8c,7b19942a,1ee2f210,ed9cc20,82a54f3f,fd7218f7,b79ec399,7e82fdc4,cd783957,5760e4f7,b7ee8fd7) -,S(54e7daec,f4a9b6f4,b100f964,850deb65,64efddb2,e6ce7b05,3fed2a28,1a0841a0,d9ada32a,54773a81,d5a857ad,8b34d96,70d46785,70943dae,cc83deca,97c9c63d) -,S(e9b29910,d8bcef46,b48d8be0,c7649b84,383ed752,391ecd7a,bdb454c8,8fbf44e8,eb268094,f669e91f,a5173965,50e4c40b,d7a26792,9a8df3de,b84c703c,261d6b69) -,S(43f95222,f254a513,1977c589,577d1d9d,3f537a1c,9fe14ef6,384e1779,da546a97,d7d3c653,43345c47,f245b305,b662a2df,eef80b3,97b3f5e1,4b0eceb5,71cb18cc) -,S(9fb45fd5,3999fb92,830bc090,216ae485,6723385c,7224b1d,cc91294b,a6c3b103,5b47081b,dbfd82d3,90d7bf7f,39a494bb,6731b506,b827213a,277f7ac9,febdf451) -,S(dd92282b,835529cd,3295919b,2eb466f5,9ca840e,20ad87f2,3cbc824b,b71dcce9,ec45f6e7,bc59d668,b1ef4a29,d1e23bcd,f3796268,3b58fb7a,d58a9e1c,5f726371) -,S(7482f012,9fbdd7,bf99def4,f3de23c5,fe29036f,c1ad5c38,686c05da,dc16348d,a43c4a0d,5497f6f0,bf2b2a20,b65bad11,73fc0dba,c24e65f8,db1663a6,b840abd1) -,S(fa4cfd95,97fd6278,1dd2f587,a5b03195,537fca30,f7a9a377,a69a6869,70ebd9a5,4568b6c9,9ddbf778,bd31d269,be18a8fd,e2a35031,a30505c,1b8ebe1d,c7ae823a) -,S(51e0d3da,e7763e8e,81905e1b,4f1ffebe,2f1078d3,27944c53,d9b7d110,3fa60b9e,118da0c4,ab572fac,cf9f20b9,2108ed0,1da673a5,2395f3f7,bfa2ff2a,36da6740) -,S(7d8e567c,c0552335,38c3b857,289e96f4,502fc674,f40ebf86,c482a668,dbc9530,76c3fc46,c6446a,4b9fe552,ba8b2614,7484581c,585c8ad7,600c2ea6,8eb37571) -,S(d924c6d3,b400196f,dd1f216f,dfa18c79,1c316d67,9ef4c0ed,8d12b94a,cd1dfb1f,ec33cee,881c04b8,b11eb3f2,88dd9b92,90b9d119,26c692e5,9d82aa80,4febcea8) -,S(8dcb330b,6f629c8,d18d28b9,7a99d82b,3965cb1a,bf953b8f,33074457,5e93c0db,3d8a2d19,8323902d,1b129b57,313f81a8,b58b7340,f6f7c97a,b6d74f37,a46857a3) -,S(dd1c4a3b,94b06378,8cf86797,ddaeb671,57910f1d,35a32e80,d3f749f6,bea5d2b5,efbec0c7,5a69583d,643e5be9,ab78cb78,3d2afebc,73d7c64c,869bede,b3230777) -,S(2b03de34,1dfad7f7,395f6ec4,84d292c1,ec0275f2,bc762dab,7658a885,37f5e772,3235e8fb,3818582c,55bd48bb,49f78e5e,803d7d1,ae49bbdf,97166a76,c3c0d0e3) -,S(3a795b0f,ba145bc9,7e7a80ef,a6b77132,677f06bd,4c3e7f39,47978c83,1428dde2,f4125b9d,df038a26,37cbc9e1,eed40aec,81af644e,a3f1352b,526df579,44914691) -,S(ecf813b,a133d6cb,9c46c081,b0a851db,121f5c21,788d1e59,ef8c0588,684fcbbf,69e0daf2,a7b7b473,7f2becd0,789529c2,597e3915,ebe12093,ecd7738,13e53560) -,S(637c4982,c14163e4,1037191d,d4e09d3f,74383245,5368cc33,57669186,d6217d5a,da5a2ab8,fd83d2e3,25baaa5c,a378318,f6fb3747,5ac64b77,a74da573,deecb410) -,S(19fe73a2,d8875b57,dcff5fac,20530da0,54255658,1251f7c6,b198b3e3,71b90e87,3b03ac18,2ccc2518,c367a77a,1fe5e8b9,a3264681,28fc1ad3,5a39f7a0,d8151ca0) -,S(16ea62a,d4cdc00,9d151b3,b6680b0,c68b4cbd,f144c234,71d55b7f,3bb7ebb2,8cac4a1c,53672e59,338612a8,995980c1,35f02060,2e3b9f6a,8fffce9d,e53fa629) -,S(6b9d68b5,454c6d21,678e5413,279f9a28,e1eed485,fbf512e8,49f35394,22a40970,b63f5044,98ebe37d,af9e6969,da888eb7,907f8565,4b05d472,fa4b1b27,ae365482) -,S(1fa20c8c,8f0812c,2e7dc948,afb7ec92,32c3c27d,23165d05,868dd127,b5ed3e6,c5257f4d,82133642,7df68606,2c229fea,6cd16857,280a60cf,ed84deb6,29838076) -,S(73a83c92,7daeb4de,1cf1df6b,31d8f536,af15bb38,be506263,e8e8a6a1,bf6acc86,a08acbe4,cd6c30b,82b4e24d,e8c9b891,26a21dab,e4df40ab,2fb7ad6a,82eb8adc) -,S(3a995664,924e2dee,ca278cf9,3ce265e2,85ba90ce,fd2a55a4,8e1761ee,7588bdbe,f3221adc,99eb33d3,52465d93,91caf18e,d011a1bd,3b7cf39,dd48d45c,44cbbb0e) -,S(7c65ee19,b032f5cc,1d45cd9b,9c160e86,5ca516fa,b4f88596,5e07f269,3d429c26,47c7faf9,e3df277,d31076ae,4be2224d,8cc54a5e,3743e287,ff9572a4,23704c5) -,S(c010694c,6750dbbd,bd953118,dccb8d03,2f05e6d9,65db8fb0,3dc00b22,e4d397dc,3b4914c6,dd6c5441,59dfde10,a196f132,5a5e6101,52d41be2,39583b80,6c8e730c) -,S(e255848e,d28d8b6d,6f95a12b,92136131,a33dcb2c,a723fae7,5e317cf6,62519d57,62f7d5aa,1757dad7,98207dcd,18183b24,377c9ac0,1e106fe4,d36d9264,3fcfb7b6) -,S(f31418e5,73232992,3a878dfb,f1de30d1,a9669da7,76effc45,bd1a56d0,2c236ed9,e62ab884,dce0d946,55e34c8a,630b5aef,16a1eff6,1f889552,af7234b8,ae56b84c) -,S(9adb945,b876313b,ac9c290d,47c1e6aa,1f3f3c9a,e8c67770,61512c2b,bd703181,b21fc142,b4632616,4820b82b,edddf2b2,51531d0e,df0f0f86,50f74d1e,9f0908fd) -,S(c4682b2b,9d4a63a1,855132e9,b35b390b,ca04b846,b83bf36,1726c3c5,808da322,f25a906a,7100ba32,1b659762,23e36f04,14e9075a,835ce5a2,6eeb5d03,d35f6972) -,S(ebb0fd6d,60f49c47,8167c405,597c765e,559159f3,ae04003d,a99a1066,ea80d63a,eb37d160,667ac862,1da2ffcf,28b431c8,c4202f67,706f4350,afdc868e,6aa0b0f7) -,S(78f12d20,70d8bcb4,267cbb,bff637f1,65ffb098,95f5734e,3551bcbc,9a5597a,42976ab3,36621756,1bb574d2,c87d99cb,7419a3e3,39973740,7de17090,2bbb78f8) -,S(3dffc4a,f6214b63,9839fbc2,b949621a,35ae41bb,e7679eee,5798afbe,85919f69,58174b6b,1b4021ae,22dd15a4,29d97502,a13480fe,902860e9,36fead8,57f2c456) -,S(410c9393,a4ed42ca,2115198f,4db76eb8,bd16bf0d,324528bf,55d5d745,b55a15cc,404ff4b1,df71b89b,c14c2cf9,bca25176,83c2981a,731fc3d7,59faa0a,5ed58306) -,S(6b4d5156,87d6b079,3df36632,6fe6977c,b93e6569,66797196,6c16c495,be4e3649,647a4894,bbac207f,5d2a0315,2db1760c,1a25560a,95511c81,5d6c11a5,e969f4e3) -,S(58ffad7a,e87d5986,f0bccfd8,5005d9c1,6f0d8724,6be4dfd9,4a771c5b,a5f34247,ad8b7ad8,f9ab15fa,f50d6f93,ec8629c3,b33fba6b,ee36ace5,e505cf00,f0069817) -,S(e6d3e41d,1835fade,af27738,23e883b4,adb95669,72892c72,b310eacf,a6a757fd,a136c88c,b580ece7,cef03e42,5dbdb8ef,d6395cab,b427ae61,45a0ef0,21359c15) -,S(fc47c62b,43aaa030,ac104479,21bc1026,3b561b42,a2d32a5,573ae947,d953b35,5d318d1d,65fc7806,732b5810,40a1f511,62723626,b393b29,50230600,246224f0) -,S(ceae2867,cbcb37bb,8e78da9,3553866,d0a1b8a2,933cb1ca,36bacb7c,6fdb251b,48bf2c7e,c163aa95,79417b37,343727b7,956cc629,3a188c16,d4c2d1dd,abb3dfd) -,S(abb12378,c84735b5,c23408d8,2516d887,9195fb74,c8972d78,daa8243e,1befeab0,5a0bf64b,da5a465,d9d0be91,3c8a56d9,ce901c36,67041a02,abb591b3,3f66698e) -,S(d7781e39,8330c7c9,2185302b,e116316,1a576ce9,43a4824f,274ea700,3159eeaf,6341a432,4e07c5c7,3ee7398d,d1be3d7d,261aed99,96f6f310,fbb464af,d06651a) -,S(a6918dcd,46ec2045,72d71646,d2a21df1,6f3ad133,dfd41a6d,be5b7684,7e4c760c,c0e51aba,378d498d,9a70e4b5,3521397c,1d6c7cfb,2f6634e5,1f056e7d,932fa9c) -,S(413a4ee4,fbb5de60,392b340a,65fd9706,7785e2e0,248d2770,6ef044ca,83d1a204,a0362506,c18a8f34,3bebc668,d1b08fd1,6595a674,51db27c3,43af172f,8a3dd197) -,S(e1a7bc24,de8b0920,f6c4aa08,2fbd1126,87fd8766,237311a8,9681581c,5e04001c,3e3ba9fd,d0a2873d,149aeea2,61a55c65,3a3d90b1,efa8e49b,29bab100,1a6bed16) -,S(ff9292a0,a147ccc4,b5ae077f,8a337e05,ab1dde9b,1795942d,8a9a0fc3,dd333a75,e50f027c,5f7a3463,7654b412,25ad5dfe,b555ea2b,8305c7a4,3b6f5b78,7a23a166) -,S(eae56623,437c9dd3,9dc7a36b,45c2d3,afe849c6,1980140d,900039d4,4ccb9c0c,f1b8c9e9,92847436,dcab5a9b,22fe7e78,55e62e40,372d77be,39f68974,dd32e043) -,S(7dd20cbe,3467a3df,e1eda0f3,48c39e5,7f9c6004,bcc89227,3d002cb5,54bd5282,ec4d2f23,f035d2d5,4cf4c3f8,31772a46,ee922582,8ddfd4c6,4eb6a689,7c1485d0) -,S(359811cc,5acf1291,547b8870,33bda3c3,e4e245eb,db0dbfc7,3a02da3f,12a877eb,ed2f5087,8b97a3de,6ff916f,511c3a27,7702d1be,2b683a59,bb6acd98,e908a792) -,S(fb33e89c,f2bcca4e,4ead57ea,1a24d1b,5a6c76ca,bc605a2,c031102e,49a71c24,c75e02f5,ca602705,7ab5b958,42a9272f,d7fca940,c26e980e,192861d,2f1c9f45) -,S(a1cd33e,5eed74a0,1534f836,b05a5129,b7b2970e,f293b606,9d1ebb56,e5f687aa,f90d1ab9,ccfc345,3b2b60cc,1e4380e9,bdefc37a,896a1abc,c9978d08,1ec4a6b0) -,S(461696b9,3643b7a,bfb383cf,ced8ac92,5d9f169e,1db30999,b8553504,c4213614,674f5c77,5f300fa0,c8f40a85,9aebffd3,ee91c4ce,695998d6,de0d59a,3033bc72) -,S(6c6aaa22,1b589f6b,ccc885ae,93f7e8aa,1fd5cdf2,27471727,f390d5bd,e14ab025,a77c5e03,40e1b90d,1ad64483,fb50fa76,aeb84417,88ca415c,9f8d2cbb,aa077538) -,S(c918d391,927f3310,d032c7ee,6e729e6d,792eff1a,72acc268,3874fcd7,4e61c38b,58fd746c,346048f8,eda1bed0,e5b6cb58,fce24a72,6e27f965,74243c80,780dfb5b) -,S(48679e16,1ca0a3f5,e4ac2654,213c494d,9240c3f0,33fbe2c2,142ec589,6dea5918,556f93fe,300cafe3,e93a2966,767840e3,b2a19fe7,9cf204a9,a30d1f1e,3e1d1a41) -,S(c68c05a9,e46b6440,a72d6eed,eaac085a,5e945659,ac46a584,69968a30,c6e7b858,b8b4b5dc,35d4ff80,be3d64a1,d036a117,c768746a,4d2bf2b6,1b126460,15de450d) -,S(d133ef10,6358489f,8f976dc4,b6c54699,21e3dfe3,6f326dc9,f0538757,9d444e6a,2c66abc4,db690d2c,272b0f57,afd66a6e,327ec3eb,e32b45be,cbf3c502,baf968cb) -,S(53544f59,8d759dea,b10766dc,48a7e2da,61ca0a60,a201d193,92dad05b,3df976ae,449a205e,61cb7aef,204e3f0,3a199ad7,993d711,537e17e8,79a42bfe,2869cd47) -,S(3108a074,fda5133,39e26385,14b6b7c0,9254c65d,ee374a62,2fe34acb,83b8b331,42edc90d,54263fea,8b1a473d,ac2f2244,d6fc05d1,f59e115b,5d930132,268b6243) -,S(1666c40d,52c1c04,d9e95099,aeb55861,2ee58ac0,6b22f962,154cd8ca,7cb4b23c,5065bb41,ae046638,aab55923,e0752954,abafc247,d201e84f,b6c444b1,93a82fb9) -,S(c96d07eb,d3eee6a8,f001290d,f76b2d82,ed80fa90,bbd5ead5,3a572457,ee47722e,d3d69c04,447fb7e9,a3416af1,798b749d,13ba06e4,78a432c8,d00dc2cc,7e20baf3) -,S(a9ffc39,b11b5b05,78769a9e,8ce7542c,647fa7bd,7b2c3479,fce84d91,1d81b49d,bec21248,82e928f7,e98894dc,25840712,80a64449,38e53747,375d2122,68bcbee7) -,S(52ca128c,cd4c9380,8e55d3f5,29320fd3,e825787f,1a600f27,37fc5fbb,f7af0632,846e8a80,95a98cb7,b4ebab01,4d9dbfb9,37ffa493,83676ec3,70f42cde,3135f7c4) -,S(ff92aac1,77fd9927,7b8abc41,e49f7c94,698525,2329b9ae,8e0fa34e,a9407c20,af0d8cdd,5aaf5273,ebbbf2a9,b7230373,dafd9a93,42a47331,a3379f45,8ffdcfb5) -,S(a692a73e,d3c10a3c,38163c97,314d02fa,5fb653b1,d729ff09,a541d01b,27991e0c,722f55a,3e5bd3e8,d863d00,6b82415a,aa05c949,9a537809,cff9be69,e468b905) -,S(d9e59c3f,7a629a93,e32fc4cd,2c98d480,6b813ba6,315ce4e2,e2fc7fed,4120aefd,24ce2594,23073119,4f5bf658,909a47fd,3234be39,13aa8d30,eb08e14f,af0214bb) -,S(74e5270f,7771b109,64991ef7,9abcf05b,4dde8d5a,605ab587,14b8e534,4a0f6ff,2ad861a3,a4a83f09,687a285f,1356b1e3,71ced066,69154887,14bb0461,b3b1670f) -,S(b9169230,1c43f7e7,61a85615,7957c3a2,744668a4,8587ff58,7a201f59,31d4420c,bd36065b,c1268280,4cd818e0,c6515a5b,659ea423,f5b23e5b,ebe1f74e,5819536f) -,S(37faf253,864568da,972d7211,505b7fb2,cd01fdc9,5953bcd8,79239d90,364d51ee,b69ae2ce,749db3e7,e6aea736,a3bc961,d8c12523,6f7be823,65749ead,3bc15f85) -,S(e194114c,4a1c138b,34882477,f0dcd065,1c379f98,c198614b,43b087bb,a20cf8d2,7a3afb4b,b90ae22e,3b182cf0,6514a998,889f2ad3,d71d4d67,89e3758a,e898a93b) -,S(2ce2db01,d3fb451,7388e4b3,c81588d1,1c8b13ef,917333c,ca054379,fa17ddaa,9232da9d,af0e76a9,85e1529a,ed1a5568,74285cb3,8010c922,e2c30d77,367bbbc0) -,S(c292ec48,4bdb7045,3dce2e82,1fea7688,bd66c6e,59635f49,98618f9f,3d6f051f,210a74f0,6b81e69c,4d0af49b,fd153247,12b77736,126f4887,2b119ec8,97b57d6d) -,S(15bcc9c0,97618aef,697b423c,cd83ad3e,933db83,d77b42ad,3e132036,a5acfeee,e9fc7ef1,1bb996fd,bfb3c490,14912ca1,a1bb98a9,e9611c,1a83a806,b88a7a33) -,S(46119caf,50f13bd7,97be45fe,55f2d298,848639c6,99d5b113,fd24cb24,6e1e7785,6a203f91,f4c56eb9,7762cf8f,9ef932b4,ba301501,5aeb1215,b1327a93,842ea3b) -,S(f3a17794,3e4df182,a9549a3d,2da1f9fd,cf141094,5e6b3a64,9d9df885,b6f9ecf4,b34eb7cc,5e82ad39,fc2b6619,859f8328,444a1dff,c82ee115,c80cec10,6ecf7e8f) -,S(cef90a74,84a7f468,db9cbd45,f5b9a0c5,fa98bdfa,50297d67,536075c6,b7913fe4,d090eead,2a43fbc2,86702946,52507875,fb79a555,e5c55737,30fa40a2,6a301815) -,S(21d8a214,987aa938,ec4b88b2,4bfa5661,26c528b6,b9060b06,833c6ed2,a35702ce,c354340d,5b65a23b,c628167c,8a2830,f736dfe9,a501fc8e,94b66f26,d84579e4) -,S(6b18ff27,9049be4a,62a04f6c,f82dbd24,e19196fa,46e0761d,5d139518,3a1ca53e,ef806f0c,52c01367,8f81e9b2,6698fa32,6343f0d7,2522f8d8,6cacfdb2,c5ffa3b7) -,S(7d8ef4f2,452cc04,d5332afb,ea3e673c,bab07c36,c081a0ee,850ae31d,cb466e6f,32461667,55a2ceef,273367d0,df10f6c9,d224da47,f19117bc,137a6244,2cfa0c0d) -,S(c7de1821,55d15649,f5bb6327,65ac74a2,3413560,b1d31afd,6994b488,20d12cab,d9965856,c5fb2c0f,c93b8659,5c3240d8,7fbe0136,11d7e844,48252ce7,96eaa23a) -,S(4cecb33a,915e2c3b,189eb6ee,45fa4eb3,eddeff09,729945c6,f893bd,4381b294,cf17f112,b5e61cb8,44625035,7b700cd7,3534d6e1,3310b6ff,d1bbbd8e,1ea3aeb1) -,S(826cf464,bfce606b,b4c3ab5d,4cf00fe4,1c9bc72b,285c8c10,204aa658,66255749,6ba3b431,527d285b,5156fabf,b150aa2f,6d7ca564,b18011cb,b878e235,7b6849c4) -,S(c812dac6,f497d245,5192ba92,2d6fc10d,de51d608,d82e828e,b2187e7,648f8f62,d02e8c7,73630680,8126ee1a,efaf53fc,2be94dd8,7773e8f6,1ba6b4ab,b08b317e) -,S(5269550e,bd967f47,e45eaa8b,c9f14ebb,aa45926b,6e38cd1e,3c6d5d3f,e0ff8851,a1597d20,26e3eced,443422ff,cd1b3fd1,b45963d0,3086a95a,38b8661f,99a7455b) -,S(7fcfcb29,80e652cf,bc42721f,cdc40ba8,c7c2ae6d,54a51e9b,af1afee7,e84d7676,abf72d90,4a408e34,ec6bcbaa,ac8f19d6,a4d044f5,66a9cce9,f95debf8,882cfcdd) -,S(85f01aa0,4597e104,848e18a2,132a6a07,3d5f25eb,8baa857c,79dc4b6,64a9f451,f7463ceb,8a058187,7bbb71ab,35bcf456,5398cec1,cb4e0132,4b4ec47,e5f081af) -,S(95b4a1a,7dcd860f,ac3fee1d,10febeec,dc1a5fbc,224035fd,a01f8dff,92885628,2a0cdf9c,5bd94467,efa9dfa6,94c6ee3e,1f80bced,23738d97,f70406ec,bef7f772) -,S(4f624a6,24dddd0b,b254b38c,e37753d8,8cd95cac,ec4709f0,49b90ecd,7f6c51c5,874a9a83,2efecd9,2a20dcd,8ccfd454,668de4eb,1b976bd0,70ce584b,c77a4fa5) -,S(39e06912,e18b537b,ce440f58,545e9c6e,a2914d85,698d4043,437dd66d,7506b48d,eff20e0a,16e93096,abc80153,c128aa12,f06c6d,4695bef1,8db7a167,6f352e0) -,S(52edc132,66d67831,74ff4f59,cadb979,4c1d41b6,5efb9310,7a717b46,78f1ace9,e569e202,c6781e3f,e32c0bf4,9684d7d3,cb07cf55,8f46927c,3af6bbc1,c4d402d1) -,S(e3764b48,964b8107,3e287f07,c915fc8d,e4e9458d,6f2a8d3a,1dfa43f3,4328465f,bde2a64b,fb13e0ba,351b460f,6d0d7574,5b7261aa,53a79b6c,3ad5c8f3,4cfdb023) -,S(80efe507,7c77698e,3ec38768,ef81732b,e1c81aad,9c42cebe,75627eff,bcf513e6,690c671b,c54391e9,695e6059,953d3d9e,a9df2e17,5aed4bc3,483f104a,388b709) -,S(484ac7d5,ebcc497,a2f2bcac,87cd23ef,19b0bf7e,93f8e728,5173f70f,c908b641,1d9570e6,f3b17236,9f2b8551,653f3271,5bc8c995,14c2aeb6,1b44ea5e,90ef371e) -,S(9c989e3f,bf1fbdd8,4dfca53e,4415cdfa,adf26c26,3801ff65,36b8fb5f,77e3d124,a34ae61f,5755163b,964b3b80,28fee3ac,2993c442,d7f16dd4,c79aab0c,88212a38) -,S(8b8fb0f,601afe7f,6456570f,19e37f80,32846dd2,97b0d8e0,9308c57d,75a5066b,7858afe,ffc4e6c9,b2e32f10,fd67a1,d6166c72,26f03b3c,240b29e0,e848c9e7) -,S(e37d0e74,ee1d79a,981baa79,e0a5d807,bce0953a,211c00ef,451d9d60,7ee78177,d28a1285,2ad25f4,df1b5625,bfe59875,a07d0593,aab4ee6f,4bd23ebf,b09f8f9c) -,S(80c8577e,9a003683,ad658e75,47657b1f,281052d5,54cd0e19,4b2a9e70,1325c147,b3fd0cd,7ca3a2ea,ec7ba8a0,d7297347,fe2baf99,bcfbbfe4,32a6346f,564d945c) -,S(e7045d6d,34121e5,536f7902,67ae01a9,50f6ba8d,2d05349a,ddeb3833,3ea8c6a1,7306a8db,326994df,e15571d9,c2a5dd24,60b37c2f,e97559e4,e7d88ab8,8a181fba) -,S(55d2da4b,850a47fb,6b3af0b1,3c03889a,d87554f7,cb346980,4f2978c8,652e0d71,6ac0f982,c861d0f6,cd20b7b4,f22eee5d,189a56d,5cc46780,72361e79,dfe16e7c) -,S(ce562e09,55a22f7f,c83a5ff2,11500c03,a1e86d1c,404019f5,5bd1cdb0,b1a38d2f,91de004d,b4aac47b,c6b0a165,edc5f82e,47407032,6f1ced31,4bd6d96b,521bb865) -,S(74e00e1f,596af05,7f91bd64,53107f1d,cd0eb8,6b93b6fe,cc7592e3,7854773b,11ca88a3,38e52a53,eb311867,b10a146d,6fa9f015,11791374,e13fb749,d8e1d217) -,S(ae8f0b6b,c194f6c9,1d83e400,ac92ed97,68214d39,95868530,a2e99f9e,2104eb48,e973fc42,dc0a930,36127de9,eb57cbf8,d4aa8f73,14646362,c855ceec,d7ce4cf2) -,S(40a8c06c,8df83675,e108e0c0,565f33d3,7854e722,6f76b674,1582fdcd,ef891ae7,16ba7850,b5116afd,3d29e0b0,40faabed,b8ff9c09,83af624e,a100555d,887bf7ed) -,S(61ea9e54,5c57f6fa,a2ab410f,861f1fff,926795b0,4d240e48,7f6df1bc,6df83b33,c69ec12a,e0b217c3,72e1791f,7d4529f2,b9063e67,38a8c03c,49071581,da79ed15) -,S(1c889cd4,440caaa4,fcdf55f7,2145fc17,d73e25ec,264831cc,30a0cb5e,c1d37632,41b5246,131fa67c,7314a223,7db5e4b0,574f5b86,11560166,ee55bc94,22d72fdf) -,S(ff295890,791d87e7,982a99d3,ab50bfa5,c58e0d06,25392abb,4ab166a1,8e49525d,a09664de,19951364,19649baf,88806fbe,c370879f,efbe4a58,e619a01a,19454570) -,S(5eb2eabf,cfca1fd0,7c939e5,b8f890cd,74e399ae,d9bdf785,7bca8767,84e95f99,4c42e970,1c9a783c,201aff12,16265d8,1f46f25,fe110f63,31fb8fb,f72c9871) -,S(43e5508c,dbccc93b,5b3f8ce1,7a071c1b,3b17bf4d,8153f61f,cfc7b6b4,f6cbaf91,b5ed8f78,438ba71e,509ec388,d09a5307,c853bb73,db240638,15a07343,9bdfdcfc) -,S(f5d16930,23cb20df,c8607261,cafe533c,eb513f87,7f6e2c99,5b0c0f75,fdb56f53,e539b168,1528332,f7fc4bf8,73e2965c,2557dd40,6eb2c8f4,92ce0dc2,126ece68) -,S(db9d66d1,5dc5a918,46180a62,d662a2eb,72313c6f,ba511eb6,c7fe0c0f,78aba2a1,c96de8a3,61f0dc5a,9e2762d9,2257857c,3cfb46b5,81c3f0b1,f89a20f2,a1517227) -,S(e760d3d8,46fd63bc,4f565bfe,7bf5133b,56ffce08,27b99ab6,833a64b8,868ecdf2,60ee6685,8be2eb4,1821cc82,54062e01,2c1c1e12,285c8381,e60e5d4,12f102ce) -,S(2bdb2299,caca7ab,d22533e7,12e37004,e3a956b0,31da4d99,1351d790,5c33e026,64675cdf,c2738105,dac3e877,e27d00e7,80193286,24cbbf82,a784713f,b6e44731) -,S(1cce0bfd,5992134,b7813773,9fd6c844,7be48d20,e001bbbf,c3c87b9a,8166bee4,2d4a8ee5,1ed7fe30,c3a1253c,4cd9e83e,b5eeb73e,c166f4cc,42788bbd,cad37057) -,S(6d6be3c3,7f5dae7b,ff5b5bd8,ec6b8c65,ec8405c5,bb6575bd,6ebf89a5,77641075,4fd3cc1f,5c6fd3bc,6011507f,7c4eaf4b,24d1938d,35159b80,39246ccf,ac9c2c7f) -,S(d82c180,d96e781d,783fb1ca,8758fa1d,b3c67f2f,143e836c,c6007d8b,bdb22351,3802f669,952aada8,93b3e9a9,74a43218,37415af6,7964b1e1,51a7b8e2,7ad0c7d9) -,S(4ec61edd,7e03fd34,f91dfed1,b546f1b8,fbf9fcee,8c73e343,b228ce18,3db3cd71,e1199709,b5b2e2ec,8af90340,de9ec3c6,db7d948f,aa941cff,b1984856,b03ba9a9) -,S(31aad469,73aea11b,a54744d7,bead13ee,a8df7a8f,8e735643,add781e9,e17a034b,64676f41,3e49f606,3f68bdf5,7ced7486,a94680f8,e60e2913,f13b674f,84b37adb) -,S(a9842189,2fccdb8e,f6515903,b589ea62,1f946bd,97e2931a,5eb1ce4d,4d173e02,50be76ac,3b2dd7a3,a3370e13,3cd6fb37,7ea266d,a566049,abe488a4,89a3908b) -,S(822b54f3,3ec00433,7a6cfa09,277540ce,fee79b08,a50695e3,f8fe0ece,b7bef099,393623c6,20d3f604,7343ddce,d8805bf0,7405d336,fda8c712,8d044851,236bf7f6) -,S(100f6b55,fe3d7000,c5f8de14,ebfc5d7e,15793d10,e99dea3d,33adf25c,15065e0b,d1bb44f7,58c4dde2,7c928267,6d6c1114,a352ffd0,dcec8e51,9b2cd74a,4eecb4c2) -,S(ca5d8318,6a09c227,481aa6ec,d195d094,6a54257c,5adb71bb,2d4e8836,d6142f7f,d890847f,b9747a0a,f3ba0c38,84ae057f,878d8d31,fc73933d,e014f4d9,2677b42d) -,S(e91c25f4,2234d20e,2931a352,f98ff610,e8ffe53f,101b56ca,fa5da12e,24bfbf14,b1ec15e5,441ec52b,c71740f6,d60e99a7,7a26bcf5,143ceb41,872b4a22,964dbb86) -,S(57a8c8dc,310902d8,8569b290,22e99ae7,acb54547,2ccf7065,9e9d42c,1ae34445,85224541,442e09d,f4e92db5,64866aee,50e7cc3f,b8c20acc,b9c6161e,30ab1fb7) -,S(232b8c67,2502d16d,badd0d41,28c02b6f,55a8531d,a6fe87d9,581045b0,7104500f,38110a0e,9e7d8587,227c476f,6549492f,4f5255d9,e618cf39,9a7a40f5,85f93fb9) -,S(7d0be68a,d71f69b3,4f5d4876,319f7e7a,750d5c7,e3dc876,187627fe,77004fec,3e72a050,7d0af3e6,1d6f5402,8a5b971e,a12b1d18,2ca45e67,ca09efcd,45124633) -,S(4dd85f0b,77c2a271,c95fa436,90c43485,b70b02c4,9a46cd83,6ba7a2d2,7af93292,843642e5,c9554d98,48ab6ff8,5dada7a0,f139e64d,2081978e,8c9e3bf5,1c11d597) -,S(537a93f5,88f02004,70b531a1,74ba9a7a,3eb2e5c1,eb767214,9e264e2f,712e52f8,b0d9b3a0,dc009266,8e25f06,71895af3,94efa1f9,78257ebb,3f839b61,340e161f) -,S(13faf471,325b1e57,98ce60a4,6f82bfd1,ab346590,82588ae8,b972b331,9ee48684,a6720384,e84eb529,e22f2585,79b2201a,dce7ba18,845b8bfa,49a21ade,7634f743) -,S(691e24ed,5861b344,e015dbea,809dede7,ca17c482,22d9e06b,e1be4405,cfe8acb8,e3564adc,c197b0f,cc520d90,9d9c6347,5ad00294,3d0f3f96,6f49b76b,91c529ab) -,S(36543b91,aaaea850,15aa394f,fb334923,b754b3f8,9047f73f,423c15dc,7d3d7ea2,73b4693,b79b800e,8e48c838,9218094b,9dff44fe,5a1fafd5,2d68a2f1,bbbe5799) -,S(ff25abe0,394180cb,1e045045,5320ea80,e007bb0,fe3bc8a2,24f20b07,8433f05b,a512b109,26dfe650,e6dbd678,ad9db412,938f69e0,8aee6c2,f903631e,530b7e51) -,S(1dec07b,5faafdaf,51051f57,cd0247ac,cc607bc1,70c53222,72d389a1,7d87e443,7e77e937,382b2bc0,5a2207a9,2598dad4,d870ce67,d0e138d3,bb35094b,9fa9a325) -,S(2f10f776,f62f8632,ea20147e,d14e0919,485ab78d,fc636236,29c2994,9f413c32,3b2c5fc6,e760462e,b9d8c8b,5aa6b1f6,35c23668,33e7ef5a,d25269ec,68d2184a) -,S(7974f394,e61c2cdb,acf09681,4bcafb4a,ade31943,cc180188,31160022,dabd73ca,e1b34da0,3bc1aa66,87df854e,813ba451,2be4cde8,310e4056,73c83600,89e98309) -,S(54c5f39,3c5cc416,56577469,84aa3695,32af1ede,3a51b14,436748cf,1701c332,3dc67b49,49769cc5,22b0626a,eeab6ba,ddbde8ac,ef78a0cd,800c1b6a,5043e4e) -,S(199aa296,f047c7eb,1d8a972a,318585ae,8092e905,e555915d,81c1a3b,425f3783,f5823679,64d17a96,b4ca7946,dfd3a266,585154e1,cee02e2,b87e8fc7,eb46c262) -,S(d15d39d6,fb616dfa,6c292a3b,a1fc58e7,cbcdf0be,7976be87,9a7f088a,9bb7f299,4c8ae97c,4e37f837,bdbd4912,f43bfc79,679dd418,b57d061,f705ba60,2bd7a900) -,S(76d65134,880e7dfc,81a332c6,a04b82bd,bff26eca,9a5aedf5,a6f6683f,364ef58b,b71ae708,bbd22d83,a1ec9048,6975b9a2,7b4aa5bc,5bf1246a,6464406b,401507e7) -,S(1eb4d2a5,d4dffe36,30ae9ead,792ffa9b,452ef0e1,94c06a02,a0308143,dcae51b7,88d978c1,e6ab8e79,9a286af4,58cb3eda,7cc94b67,589b144c,9a55cdbd,6ff47b0b) -,S(dee03251,35708790,361c3451,6710623d,e474bdd2,4513562f,95512f0c,dddf571d,d22dbcfd,cbf6d809,2c68a28d,c118ffec,496d9623,b20667c3,7fc487a,1690f565) -,S(2eb0272d,c98ac6bd,ff68f0d5,5f13f509,bf1dbd9d,f36385ae,ef02356e,56d4760a,f80d4355,4aaf4eba,27aa1832,90573687,5c69ad44,7211f746,111ca02b,26a04277) -,S(eaf62e69,7509672d,8ff6ff7f,c7788822,b75853ea,27636b5,c39b0321,ab0eabf3,442e56aa,1c8fe22d,71b88b96,90733f1c,8614e160,35070095,6effdedb,2e0a3b7c) -,S(2059070a,13d96fd9,6bdc442c,236ef463,cbc70185,b8799d3b,15ef72ae,4592858,bc9042e8,3f259ae8,f6221d7f,46ae56d8,f426fbfe,901b94a2,80da34bd,14961ec8) -,S(ff2ef7fd,9e7f3e7e,6f7b4cee,a44ec281,4b8b4a44,208c462a,f925d27,ad2f52fe,6ace74fb,fa6f72b4,8156cb52,a67f5137,956a447,6b69fe3b,233ce4f3,df0a5e24) -,S(e3e5cef6,fc4553fb,d337a7b0,4357ff1d,d8fd0de6,4df17bf6,20f7f9d8,9d14d83,acddfda1,baa7b60f,d0d1863f,769a475f,e667b6fe,8a047365,1b84f44d,238f0460) -,S(97a8726a,41c02880,e9942341,a66b9c21,a0c64577,bde3c54e,c11119cd,bf57a6c3,b5f37cae,27023d07,78cc5c7,26d845e1,fe160aff,3459d164,681cc38d,8b67b4e8) -,S(ab01e6e9,4862f943,8639484a,119eadb4,12fd9002,1d7781c4,1b020450,9dcc81e6,6ae50c32,101b5c3a,51fab05,2ed79e5,48853cf4,15a30043,6b11ee05,7483b14b) -,S(c464410,da2dcf6b,2e6ba5a,c8d8479e,58ed9a4c,a8c2b0d,5a2ea15f,7673668f,3698c590,62392c7d,e597f333,cd3ce45b,eadee944,5209d361,adbbc386,b499945) -,S(17eacc68,5f721f3e,2013b0e6,76c10795,ee49d524,26edbd86,48f098f4,17867534,cc3116e9,cb19f49,bbf7214b,b3ab76fb,fec0f856,e994a01b,d6b63ece,189ef300) -,S(c040dd40,2908ef17,539b77bd,5befd53d,3ed2e8bc,d7d3608f,2b114dea,d4c00d73,7a6384ae,55ec2580,4d1403d8,45113dce,b2053ecb,6ce0d3d7,427835b4,15279c00) -,S(a5963498,3658f70c,2ec25fed,6659a290,41bf2ba2,ba92db93,41b03e39,2ebddb42,dc114caf,260ec4a7,a8e8bf4,1695785d,1ce7c2d2,82359600,a950ade4,d79f4872) -,S(44fe22d4,51dcf63f,c7e33d09,533836c7,66382372,339de279,9897cea1,1b29aa0d,1718c4e7,3d4bd434,929e9ffa,e2496f79,4f3bf80f,ae805a9e,53b577cc,4c4279b3) -,S(8bd718aa,1358c15e,fa3b246d,e244bfd8,4fc6b5f3,ed5ec91c,ff466a11,2c71647b,172f1a88,ba6c11f0,1b7deb8d,e4002793,65a0a3c8,443b2fa5,f406dfe8,4bd737fa) -,S(8ebdcc25,bbe6aa23,809aa53c,3ff3a7a5,d7ad4cd5,5dcf3cfc,d9ff8ce1,738680d1,5c563b26,af86adfa,c3728c,f886d83c,5be64766,78ac5872,cd798875,45e5641a) -,S(5cf54e1f,688faabc,99742fb8,be896cfa,b469e5d2,feb72f4e,9dbc67e0,e91713d2,d82d6590,d06330d8,2f86393e,190155b3,4920e8a8,86324b18,5694786b,e4fd09c5) -,S(6c0d96e4,3f01a1a7,2ec16ff4,e04571ed,387185c1,4c8a2f8c,db4c187a,85845f1a,f399a14b,763ec2ec,f3415c1b,b9bb6f70,abcf013a,3117ddd6,e55a96a6,b0798c08) -,S(eae928fe,fb6a2fdc,d05f1515,5726a133,9a15ef0b,ea716ad6,90d32dc3,92b74046,bdf87ad9,f086339d,cbfda797,8d6ed40e,f6fd4626,60d6db09,84ecc577,14c76bc) -,S(e5e5e30c,bbe72fde,d9f0dbbd,e08dda,b61d5cb3,1aa688f0,d572008e,447b3a21,9fb4adb8,f80b6e67,47c6ec03,d5171ce8,5de65682,a105435c,5610065a,85b248ae) -,S(711212ac,c9e26bb7,c5ace176,26b300bc,78df6b0c,a79a0b79,7dbcca,138223ee,dc68858,4ef44ddd,9e6b343b,c4c73fe3,6b873239,18e11cbb,dc3aa72a,ef027757) -,S(3b52ebb3,531aa4f6,ddbb9ea3,fb5e5784,c4cf11b2,a4c67d50,6b6340f0,21c5e22c,3da3eebd,dc0046a1,3facf02e,46818640,b698c8a6,3c5fb9de,55a9996b,b190938a) -,S(30f28481,110345e2,7dee7292,fe1c7a56,45294a17,e96cadf9,1eb76bdc,cf56b78b,70c610fc,26ece34b,f047864d,25116fac,3c149164,a1deb08,8e6d702b,77abb049) -,S(4a844a8,12c55b6,4e4d37b6,1ca4a1f1,5cfef527,699d5ab5,edf1564d,e930ff58,49874548,508de6e4,dbbe6bd3,8d0a9ff6,5826f9c0,63274cd3,f3189d59,683dfa3c) -,S(a5ca561e,a7c8484a,642e0fd9,a999e14c,5ce2b5d,edc51026,4519e6c6,7868b06f,cc917942,a5e2eeea,ac09b00e,affa7f6b,7abe386a,241de5a4,7a7c43a3,85afa7ed) -,S(f61b7ed3,1e16c456,c3851a68,e10f614a,1fa547c6,456e57ef,3c1f8ee4,dfd6e72c,cb26d0b7,fc401865,91f5fbdb,4d17bfa6,a0c5a811,4d099a54,734a3280,5f622f2b) -,S(f8e4d462,889700c4,b52859f9,e766fbe6,55976866,a22207fc,aee56185,15f678b2,30bb039f,c1b16fb0,aa09c271,bfbb76b1,6791e95,9dd51ae,6f01aa4e,bac77554) -,S(89cafc1a,5d25915,b2f6f71,71814a2f,d5d97a06,a717a91c,a392909d,332ab653,1a24a0ab,b4e4858,d29c0055,714f34e1,5eac02da,60e87ce1,6fe2f144,257ab76e) -,S(d285370b,d04f5dcf,caa01dca,7a2ad510,33c5b555,6aea60bb,4a48d97d,477c4f20,d4b427b7,32e885d0,13a2adf8,ec705145,c61386b2,c6981b41,6c44d202,4693b9d4) -,S(3c532f2,d9bdbfb3,219dc90d,17aba269,fd335066,e1fd4974,9026f66a,4df217c0,86fd5e7c,a6c97fd0,2c33c7b4,28413977,2791a6f9,f8c80576,75b3e306,66ac5d59) -,S(24d1950b,fc35706a,21b17a16,53037226,2984453e,37e26924,b730314c,cc8ac1ee,4d22a45d,6a31a90,bb247c68,59ae9a75,b05bb9e0,8b57ded8,4b9c1ea9,c9f918ac) -,S(cc6ab0f3,6227b1ab,149f8ace,ea036fc2,d8505341,ab67d44,59582b36,4e7615a9,f9ad93cc,40b1258,67c806b1,20fa6f21,bac918af,54a0f7d7,107680a3,83761cb8) -,S(de24a954,f36e94b6,ca816bcf,f730b99d,6320f20d,9b141cde,f08ff71b,25318cf,3e34b1d9,1ac24a49,b982d235,44afd62f,8475c35e,a48394d9,67904a41,db899933) -,S(77ab04c3,4900aba9,d83a12c,7953cfbd,5f8243db,48fab618,f83ff252,5a1ffec7,6265ac27,3bcd77ff,496265af,75a8db31,231c871a,30a32bd,ae873efe,bcac2f00) -,S(a47af706,5f4699e5,e0079885,d19580a2,51ff8dee,1dab741e,ce84ad51,16e78209,393cbbfd,f1b1f78b,a563f7cb,3465ab97,5b786088,3daffabf,bb8f34b9,7a257440) -,S(a9f5f9fd,c55c7b7,4dd170fb,d0322026,93d709e1,d52a37ea,8a545e9e,9cd7016d,98717925,4badf22e,8fd847b2,e9e80ab2,54f0d327,f6b6162b,8734b105,f1d5e0e1) -,S(d57e9ebc,96b938a2,8fa200c4,e586e7e1,ba866864,a947b71,6cc7cd63,4e18ec38,9aa0d2ef,68239110,5b4c8b7c,b412df87,25de16ea,f28596a3,62a6aac,d1b6bd36) -,S(7463a8d8,fb4dc14d,5618e66c,aa85d73a,e27ccc1c,ab820611,9f506829,faa58e9,82fd6ab2,275af504,aa0645a2,8438db86,ae7990c4,b4c389f,569aad0,68d4829f) -,S(2e7a708a,29c44831,9a02d03e,4eb331b1,3927ae64,534db2fc,a3c6e7cf,d53bf412,84f3f199,73500cdc,aeae0073,f39b3b2b,ebdf6824,ec018160,fd2e3b3d,4b1e11d1) -,S(8707b0bf,540bc058,faf2f3c2,e8ba304e,180d094b,b7fa8dda,414d30c4,d9dd5e03,70b61175,fb791033,50c6bd25,aa0594d7,18db5ee9,9667c25d,fbb49c20,f100b915) -,S(3fdb370c,3ce6cd02,886070a7,28e66749,22f67dce,1b6c08b9,613aa2d6,53ca842d,163518f2,474a0344,a5c4c5ec,10b1efef,5d3a5ef9,94010063,17a486b0,c8e0dafc) -,S(c37da302,412cd549,a01411e7,6f58d4b,33077960,94b31af,2a283d89,48472f62,aa08f287,16c642f4,8702d1da,aa0a82bd,ca849000,b8ad1d26,801c6fe1,3a21f92a) -,S(3eba0550,381ab0f9,251f923b,5c7a339,60ade9ec,2b0b47cf,25726fc7,a5e08a1c,1427b0eb,b681dd3a,88639652,5afc4e00,492a1ad9,a0c5a396,55741a5f,cf0fa7d9) -,S(96723ea1,8ce5d5d4,bf64628f,7754fa0e,e43f20a7,85356e01,94eaf8e6,bb50cee8,5ad09fbb,b9bbbf10,e86eef51,2d448aed,6cf51b5b,b28c8e8a,713066a5,81f49bdd) -,S(d7645211,7ecfb6cd,3a09d346,55d5c58,ab822892,67910f13,29f8d604,a3663748,ab7cc104,d20fde08,2c889dbe,2baaa9cf,bf2c9b10,c225da46,eebb8031,c28540f7) -,S(1f6b23dc,7e0ab136,20d907af,ad4bc944,8c866065,b4ac7e43,4dca8906,d0ada5e6,8c37b25d,6bc639da,ad092040,5daa9eb1,56041440,e48f6602,398ec256,763e247c) -,S(46ff04bb,aa06a168,79479e64,bc0e8ed7,6abb5a12,8afd1f9d,9bd80d50,75459945,b1104ec2,6af2ba0e,39133bb9,e47a61ab,e7e9d229,41d71764,91ef9da4,f51bcd4a) -,S(ca1b3c25,38888069,3b076e54,58bb0451,3bcdffb3,d824af86,f3f4a883,2a597ce2,f02916fb,dd1b6dc4,76109d11,bd9e81ed,dfc9d6f5,79847622,51bfe2,a1e0285a) -,S(c961e9a,adb69ec4,8efec7fe,dcdbdfb0,5fad1277,2b801763,ee747a10,99ece6b4,469a6c33,e0b253e5,270bb70a,d16c4b70,56bb9b3c,35f0a2a9,84e2f269,9d8fb6e4) -,S(3a2ea279,1418cc94,d3f81708,9d44e777,7b3132f5,b9b67393,ea4f28bf,939d99dc,15805143,c035d921,be217dc7,18d13e2e,b981bf8e,6525f88,31a96c65,6bf164be) -,S(416dcdf,b3a1f0be,1a3fd6ad,52fb1c03,4e24d48c,cf34d189,e7dedea6,b65a7a4a,76909ec2,bbc93359,ac177781,2132db31,47e90a0a,3c6ca35b,ebadd113,60c204c3) -,S(b397c245,9aefc175,8ba5177,2d4b3ed3,2ed9d1c4,85d2a2b1,7318545b,93c63eb3,a106a360,30763676,ab418ffc,692043ee,22813574,e3117a7e,4471ccb6,f5e71748) -,S(75c5589b,efd61646,329dbb75,5e809b2a,c1bdb8c0,d29a3065,32ef3909,d40637df,26f3e1e5,1492105c,90ea19dd,81fce6bb,95e60295,a1fe347d,cba27adf,a3e6f631) -,S(2eeecd12,a3517432,17d5158c,439a9046,e4b0dc80,119e58b6,620e6f08,969135a5,e1deebd0,48c58ed3,1b53d753,9c4c5791,13606467,14147707,806f491d,2daaba4c) -,S(a981f091,5d39d650,66b1d52e,5addda67,8cab860a,c75ac124,aa100593,9cbe65d1,4cb09fcb,7ab60293,2d98b23c,96e5109,88d4f149,4f334e7b,66c60040,7d3ed069) -,S(1a19fae3,a7e81d02,a1260c9,a759e79e,545cd869,2666b31a,9aa4c0a0,9bd4ef62,2807d657,8af25c69,e29bf7bf,d877dc7b,79714df0,68ae0707,89c5b72a,b0937902) -,S(cff8696c,1ee7d196,d76f139,2662e776,9b0f4314,99d30567,1952813d,2420c61a,8497e013,8a399690,25c04b1a,136bb816,3581f122,b62b70c1,47fc52c5,e6d16df8) -,S(6817a420,4a8b3479,caaa9582,4d48eb04,9669115a,9e5a5cd6,6cc905e2,1e27ce8c,9585468b,c3377a5c,98725465,35c8385e,8182a0c2,763226fd,95e72937,7b3052ad) -,S(9ceffc84,6e0ecc26,af13eb99,579478f3,7d114b19,59253233,bcd33d6c,8dd9d58e,e01aca1a,5cf8fa1b,67c4d4a,fef1c7ec,51060234,3ea64426,856d0aa8,fa5d2582) -,S(6a6e1dc6,f203f7fd,d9796589,2301e5fb,995a3731,8c410543,835f0edc,d3456c49,2a072b98,98b93e9e,b05f9ad8,6a97546d,83b579bf,6efd3482,f93baca1,3784496b) -,S(7e7bae1a,588d761b,5158b4f0,fb9186e8,8ba3a521,89ac36d2,4dd31d7c,d2a9129b,5198f63b,37995cc7,289e60e5,7d0f8738,17e6bbbc,d40d29d,cc4856fa,ab3dbdd6) -,S(13fc3a8,63deab2b,ed54966f,fa85e553,ffa15863,ee12f9f8,5dc5b35,6bd253,e31c3245,91275056,ffca59e7,6e76a957,a8b77c82,702e5d58,b3b5b577,73821459) -,S(ffe28deb,3f39d917,f6b6dbed,ae89ea4b,e5650326,d148ccb,becbc6d1,16e9c167,8d8a52b3,b878444d,e5385760,4e02b3fd,383c4be1,128c5b2c,262aaed6,9dbb988a) -,S(28ed423,9bf26de7,d0379a88,30fa0ecc,481c4354,1dcbc3cd,44483b0f,5cc57be,192122e2,ea018e67,4520d860,b4b8d859,2d560872,19bd0ac3,7bc0405b,10ce126e) -,S(7bf3827c,7be8c484,52acc00,eee769da,5aa4ca38,2f806d72,76c72c8b,bf8a708,925f3eee,e505529b,45c601fa,1d71d706,24a75d07,1ad29172,6bb243e8,a559eebe) -,S(cf1a7e99,21a01c3,f8ede862,71f7b6bd,2acb5aab,330a17a4,a7be1380,6fce7000,21365a83,7b3ba611,16a3e740,33a3463,5f1e70a3,f38a878a,7c3a155d,59d3d673) -,S(e779ea37,d1517cc4,e36c812,1bd0a986,af3bdd67,52626944,afcbcae9,11bb29c7,32c635ac,4b19775a,a04e2c6c,29c6f42,6472bb6d,45c1bf81,e8ac8015,d78a8a2f) -,S(10309d2b,76b54210,1599785d,6c381d52,f9697728,8e0182a1,638b7f68,f26c2a92,21edf83,4c859870,efb9b37,7f931316,f3abceac,c19b6a1a,438d020,658265a9) -,S(79927b09,701e46d4,2eb2240d,e9132036,f2b6b311,a7140701,813e721a,533a27f9,fb7c6513,a81886c1,a4c75640,36136104,8a0f47ee,b8d2b905,3b3d84ed,3b58920f) -,S(743b4e33,77da3429,9f593e68,3ce24e3f,85b1de0,4a3dd37e,fdd8c73,1528849e,37900069,b5ee63ec,7b3f178c,aae73281,fbba7de6,849e14f1,8164d6b6,742f3216) -,S(d73cd2e1,ce1bb7f,1aacd9b4,9951fe6a,e46064fb,a73acbf,49868605,c4f04da,e6a762e4,4cc6e71f,f5887fcd,6a33ff1c,cae7f84e,2f22a096,14b7f4ad,b253dde8) -,S(3e1c00d3,f563246b,3ff318a1,77b3ebf1,ba632481,47c073e8,ed32d697,95f6fa68,df2b60cf,87d5c129,1036aecb,80e381d,18ce2e00,c23fcef6,b4a72f0d,2d0776d3) -,S(96e07f90,92da1653,e5cf10e6,87526db4,ed90c2e4,c629b221,a32fdc6c,d968053c,d65c1c3b,b8a2ea6b,9ee20ea5,bfad3b9a,1f8517fe,2e5e3616,4ab20787,4dc2bd66) -,S(6d230440,26b1ee02,531cc124,b2e0796a,d27a7652,33862854,d8e177aa,afe1debb,f3a8f995,faa14689,50fbde47,1e4ec008,e3dc6228,a8cfd2c2,5983bc09,ed79bbd3) -,S(8dda9f5c,1f949dc0,314e43c4,9e716138,ad7d4511,a4b06d9d,c76fcef1,e5707781,d0563faa,7585b0a5,12b674f5,db737435,ad9d9bef,ae5ba77,5c78a582,6801310d) -,S(5070613f,98667363,f5eda369,fffda417,b4bf17fa,b4c276c4,e5aa357b,bbde97cd,b20eff,4fe77ea3,4185751f,9b16db86,eb40e47e,486a4817,8a0cf09b,dc34ebc2) -,S(3a4a70f0,bfab1456,b9b8838e,ac1aa188,4986d74,6a9b3a8e,fc792eb0,af16bce7,e4524a93,19168eda,a1832980,c04e8423,843b3e89,82381e24,8bdf5a3c,adc4f3e5) -,S(2cdcf892,183159a9,da9a82f5,4630773e,db5fba99,3bcdda38,b5291230,aab33532,c88ea6ea,c9113f32,85e299e7,42abce8d,fd95692,32292044,e0a35870,757677b9) -,S(1a85928d,f8f15f61,12e0cd6,f33199ea,2b7fed02,98c203d,781a2dde,28955c99,1b3986b2,821c76a3,fe13a6b0,30725c29,534a124,51ebe945,5682ce39,74db4299) -,S(86d14da1,d6b03065,a1520663,41b9f010,dde01966,3e622c1a,6b66b84f,1da1d388,679514ec,764f5cc9,e884a6f9,f38042cd,cfe5683e,1f6e5055,fd1380c2,8399b2de) -,S(e41f754f,bdfc879,43334341,5a5078e3,30045999,7c245441,565d0357,16201cc2,dd059641,c21d191e,dfef119f,492ee9b4,743f5e0,bb3cee47,dcbb0fdd,790e8e8e) -,S(b7ec9268,45b5bec4,79668d8f,4e444643,2946e17a,8338e2fc,756996d3,4475cae4,ab4a18b,b7539e90,10e210f5,779476b4,d945e350,978ec2cb,7cc62e71,4fdda53b) -,S(240fd9dc,f1eade19,1662554a,a25850b,bf3ecfbc,83249d4,56b769d4,b7518912,af03fa5e,e0ba3908,853a3a62,eaa6a804,5318a897,31352207,76a06b08,d104515b) -,S(353c4ec,ee7d3114,979e39d2,88cc3faa,2b88aadf,8f1cc129,a5c57237,875bb769,9fa7ec40,90af4e12,e940118b,ad70ab8e,28e607b8,5ae33cf0,2a0da4fc,d12d147e) -,S(f4eed58a,a8556688,11606ae1,1628fd1b,89340988,cbe0482d,39e80376,2bd933de,4278cf64,fe74e070,d071969c,a8ceb40d,18b40bfa,52d7feb9,1606f0f8,df3b3d44) -,S(698ffae2,e2d02660,434c17d5,b5552d4,b284f0a,736bc0fa,1a1290e,266ef1ce,1966cc8d,7845b74,1da7e53a,496fc12f,8bd50cff,b0bd143f,ab608198,e1ffc970) -,S(b53b596d,5c88c140,d6e0587d,417c8945,22d884a0,4fb596b,5957121a,65314098,ddff60b9,9befe76,c87de485,76c32eec,25deeb70,4cc19a56,77197ae8,8f2c745a) -,S(97604b21,d4393bf9,d6e4cba6,7e9f2768,79151865,9f626d65,52712fb7,1a13066a,e7aef384,e1cf7f7c,65c5b0d1,7357f266,7d871c54,fa027616,36062623,4a8d17f8) -,S(7a35c9ba,6edaee60,312b234c,1062f7bd,3b38760e,da1d47ed,b63484e9,51bb8623,33897a7b,a4546761,6ae92b58,6ef704a0,769f3a57,86ef8245,7ebd6a42,4d84a5b1) -,S(86d40c75,f989115d,ca26e0cc,9263010e,c9638b17,86707e01,b6a20d95,d1e2804,759bd762,4ffd8c1e,e71dcc8,a846b5c9,dddf2842,c4170410,c0f38742,ec315ca3) -,S(603bff47,9a4bb79f,663ddea4,93b90e5d,fc77f6e9,b2a401ce,3e8deb31,609badb7,62879fc,65281aaa,6aeeefff,cd33a02f,358c86dd,dc03720e,e1e23998,9da4f4b4) -,S(5c8b8f3,c7dc7a7d,721e0bbf,8a75a36c,fa13ebdc,14987d7b,5dee68b1,32203ed,6b601f38,2bc4c6bd,7d9d304d,88fcd6e5,3faa43ca,141bd90c,e7749340,ce08e7d3) -,S(313c1ec5,a91694c2,41e7a55f,f83b7378,25a6f27e,90090505,a7963ce8,7544fb05,9c3153ff,9a4365fa,fb644699,bc4462c5,1ed858e,24752e59,82566037,103c6384) -,S(51aca51,4616aefb,30268cb2,968e0fa0,150b4bd5,a79746bf,98b01543,a9d923bd,7c51f9b4,73a7747,bfd63ca4,f4e2b361,a0a66ec4,31df41cc,203457a7,4ee028b4) -,S(4ae8d399,27ea0648,4936d3f9,2bbe97a9,353071d6,7743ca12,2ab7b6c3,2619677d,f9dc519b,c251bce8,38ea332b,9110538,f350f5e,4352e7c9,19e677d4,3c8a47a3) -,S(6bd1c95d,3f9cb5a0,8c1a054a,884d4bbf,b100c289,c4af257b,aa0784de,a256dcca,7936283b,de39b12f,6f71fc40,1b07de78,80192357,a8887e71,39654ef8,6b803b5b) -,S(e2278a29,4642caad,ae370a62,e07fbbcb,5737f700,9ef9e8ce,19bdd283,aa49480e,43122fcd,f3943ce7,35b570b7,ed82f61d,87bc8b5,83d64f77,b36f143b,4837dd01) -,S(68537cd5,9f9469fd,d104bb01,93335830,8d24fb2c,b22471f,feef4ac4,fe96c644,765360ef,41107a51,dbf99ff3,26e3b19c,4003ab45,979de4a7,32063c81,8400050e) -,S(5ec9ffc6,69c99f9f,8f8a0735,fc088824,70be08ef,3f81bb54,b1290a07,765af330,abb54008,e76f8716,78c3229,56b47c0,1f4f1cdc,dd1cbb38,1a421397,1163b222) -,S(4e00188e,5d4930fb,a9471aba,465154a1,1a330f6,15cae31d,b2399874,704dfae9,7e76f30,282436aa,73f656dd,35b40209,5ed3fe29,d2086bba,57fbb81d,4d317868) -,S(4ae347a4,d480152e,ffd39ede,b4c2f3fb,a2659ce4,bd3b6e3c,8aaddfd5,f15ed984,383e2f46,d44cfdf,4fab8ba7,ba72c635,65bb6ac1,f35c7307,ca2c5c3,62d4e523) -,S(32cade24,a8d3ac0e,f96d90fc,86509a5e,35fd09c4,d8f7719c,603ce1b8,9c6665ef,87273873,5c63b137,5b63c5aa,6ca89f9a,266939f2,e0c936af,55c10d0a,fb8bea36) -,S(8e4ef195,60147576,6ace6891,f87c22f,20c703c3,d4f7204f,5f422444,51cfcbee,2fa72e3,89d97c1b,79eda0af,c00fbcfe,cd5b9d0c,c949c666,459706e,6ed47af) -,S(35fd575c,4adc03f6,c4d54991,18607a01,559d7316,9efc2509,aae7e7ff,a4a2c30a,f9a5779d,274881e7,cb700926,dcd10ac7,dbf3eecd,9c948aa1,3474add1,ca48e000) -,S(932e4c50,7fd02595,148929a5,2c4126c7,efc12f5f,5f5db287,3c635fed,c90a9cf6,ce6bca21,bbaca19c,29f6b1b2,4d1982c0,9e84effb,cdbf1f28,75f61ef9,ba8ba783) -,S(cad8de44,22a051c1,be36a37f,2f459707,55d3e2ad,35debfb2,11a45d73,49fbea11,48b0df1d,4f6669f2,80a41c90,34f86f11,308eebd7,8a9fd3e0,53323a66,f01c347a) -,S(9fc7d304,c847fae7,d016aa64,6cb36383,1919ffc8,fceb757b,462fbe90,6c9594d6,dd17c0e1,3bc6a187,cda9dd38,a7afdca4,1963676c,e4d4bc9e,516e3a45,d9860ff) -,S(41ba6cdf,10d4a05d,c6865453,894debb8,8300e4f7,4c17c0b4,c8935761,988b5849,7eb62b15,8c3f0965,e571e278,b2833321,ece57e84,cf153ac5,9309841f,e47ad4c5) -,S(1ff9fe5a,aef36ae6,a2d74248,cefb8693,d5bbf30d,f057e884,b227ba44,11c7377b,6ba24b6c,585c0038,49c9cf41,fcb55f09,50690850,5be64692,16520575,f1e74278) -,S(299d7c44,d706d29,e6d9d070,4856c272,6d134814,1f8f7ebd,893f38c6,cbf5d660,e4a74f3,4d0374e0,ca9b4887,76de9acc,62f7d1ff,9b494040,fc85eea,2d03ff32) -,S(a0333ed9,ec1c987,6e318ceb,83d6e93a,b607c2d,cea512d6,9f7b2bfd,72e3a67d,da7dd365,5f51769d,35b37393,21fe7b50,19f83e3b,b6b8941e,d685919,fba0539e) -,S(5a4412a2,2e52a330,534093d0,ba96865f,2821cf01,564ea0d2,e75b84fa,404251e0,6a4788e0,7e6c570e,8390bc0a,b06d293b,3675ab27,54eb700c,7cd4078d,8f0e4313) -,S(d772ec4c,3b141dc6,e534ea6,a69f9b65,783351d,c2fe7cdc,3e823cf6,32b7b0b5,bd93400d,1036487e,7090979d,ddab3821,c9ccd92f,db89bcfd,da929be6,689ac0df) -,S(949782d2,c7694c3b,ffb3e1cd,6e40f807,d4452fa4,eca1321c,d04a2367,6df89336,e7c5e67f,b8ba22b5,4372e5db,bcd63c55,9f4e2c14,c97bc930,b68d459c,bad436dc) -,S(7ee7d5f5,75e6f59f,3e0a9e4d,4c49c71f,6d9ca0c8,6177470e,2334f616,a457e6de,4462da9c,76123e66,c9074add,76fa310a,9cbbbe02,d6a07d01,97e732ee,d7d9f3ee) -,S(7a4b630a,e08d47b5,b785ba7c,15417951,8a554847,bb8320b,50faebb7,b13f843e,ca24e44f,b86801e9,7163a524,db4980de,69a3b219,7f9e5dc,6b5d7076,9d937c00) -,S(d2d90a42,428ac40a,40aa5503,2bb623c1,3a18eef3,2994f793,9c31c6cb,1aa82b96,75852e33,2367d59f,30039e06,40b1e0e1,394a3b6e,582dfb66,7464d5a3,f234972a) -,S(d92499ab,6206dfb3,da1b5606,62ed4f2f,a4809b5c,48349b91,340e0b16,e95d13e0,423544ed,26a4fe1a,8f940074,993aba60,fa4dfc64,be002941,11f29b2a,b271be38) -,S(ec0c1ec2,58875e66,d24e2d31,5b7ff87a,bba6f2be,6c6bf4dc,8d5830f5,c5d09a23,e526a7f1,648abd18,1c49a237,e608bf79,8b798c98,75804d7a,ee8ba416,28591421) -,S(69380968,835b5989,885b4805,290ea050,3a6ae508,17798c2e,f30e1009,6bba8863,71bea39d,80f0ba63,45297137,a14d07c7,7522df75,8192f345,a6170f5e,2f11e5f4) -,S(d66b1da1,9fd1637e,44cfe8d2,e1ff2fed,15a40a5d,f596c62b,ebbadc8d,fca9ab23,68cf64eb,bd2b4bb7,1ca17c4e,607b3315,5cc5d91d,26583b68,78a69476,586b9946) -,S(9dd98ca2,c6fa62cb,92750d70,c9931641,5036475c,a6b59695,a510dc88,3298c95f,55a88bb8,53b99cd6,f8d278b7,e63b31db,40750905,d98ffc81,87a0e07d,acfbe821) -,S(1b66bc2c,842cf1bb,ea4ecccd,c1e2d71,4efd848c,db7a9b92,5b9a9ade,d141bfa2,fe0b4701,55fe82b8,af43d88b,68423cb6,402b3501,8831ca89,ddb9a70,83673bea) -,S(b280dc4,8a9231de,d396a61c,2922e003,c7d2d5c9,f0e8312,c1c075ca,c8eb688a,81b745a6,a2f8be66,b32cb3ad,62babaf0,498c8261,531cfff7,da9ce306,d2738a74) -,S(7bc5951c,9eb3ba1c,828125ad,510e2e92,413e906c,f015680f,8cf1cdc5,f18a6b5d,41b905d8,480ba8bd,b8a6fc7f,49adc6d4,fbda2f0,ee229a1c,d43af5a6,98352a07) -,S(69ff74d1,2318548d,76a53095,25ca8695,11647908,dc4f2ea3,4ed2c53b,f6eabfc1,f3a3e628,8eb99f78,12eaca1e,b3adf5fd,1d617397,dcc95bde,d4be775,afde2419) -,S(5fe6dd3f,1f6d3a5,9fa8f8cd,de7f689a,ffa46098,aa0f03b9,2c552e1a,c84af209,9eeae901,acb8d022,4ed197a9,15510eaf,f356cc16,274a1aac,d6dbc74f,60dbfb55) -,S(469e9122,cb0475db,7469fafe,9c53f911,d3b52bc7,8cce23b1,21d22e59,c505f5f0,fe7487a8,38b2ba6b,f5a5825f,a4d22c26,80d8a580,9db637e,cb84e2fc,1058d812) -,S(1f4a3ebf,6b62923,b2df816e,8b30f8e4,72a5e718,70c1cc1c,6d63b4d,9160e6ab,98da1295,7602ae19,89938bd4,298a67d,1ebeebde,88706d39,b77c6a61,4dc89e2f) -,S(d8ea95fe,1c12ff0c,cec226ac,26f510a0,4117222d,d0fa4773,c2f78ebd,53b86b0f,155bef9e,dde6f293,b88bebb3,ce92c249,f154b59b,a01d7f5b,25fef472,8c6288d9) -,S(1ad8a3c7,97b38071,2214b2cf,87045300,2bb36f5d,dc7f2527,1797bd4f,1227cac6,680a77aa,3755237f,15418957,6fcf51ed,58398c5d,4d56a1c,cfa3c05f,4857814c) -,S(ffea7104,5d1d26e,d942646,9f0b0f88,355540b2,c32aa92a,3fdec318,24fa7d66,eca244e2,2d8da06c,44ec8db7,5702edd4,81f67af,2ca64ed4,cb5d04c2,2434eac8) -,S(4ac55ba3,f7fc8898,54a141c8,cfd6f675,d3abe9ba,55d90f3f,c1764ac8,b959d8ab,9c7b2b91,f135fb7b,fd252d14,118b104b,714821b4,1bd879ce,15bbc93b,f8be2bd2) -,S(5f814467,7aa9a4ce,f29de0eb,865b8a02,bc7061a9,ca525536,fe27af50,bb718ac4,bda965dc,4062b26f,e6434071,6301fb02,2b8cb894,73e39b36,69acf101,90d9c042) -,S(f372cb04,37917498,4b29f213,5981f32,da5f96a4,d1acb903,88beb154,75dd88bb,82d68f5c,1e62d500,1a0a0ea0,7694194c,7ceda2ec,e32c4efc,b2a0ab46,1a367d89) -,S(fb12bc5,45760478,36313375,3fbfa4b2,878ec6f2,243e2692,7a3c5320,bb59b128,3f820118,67dae1b5,bb5ac0cb,a24ca681,96193077,fd7bfe17,a926be5c,4953aef5) -,S(3d9759ac,918a4a34,f4307560,17a9747f,4adafea1,b0a92447,316ff819,60c0ea07,cd9dbcf,6d6a330a,b671d5dd,aa96497c,caa317a6,77bebecc,6fca559a,56018aaa) -,S(eae0aab3,699c521c,3fb49be4,669bc7dd,9f476fdf,58e42909,84455c82,fe3e00ce,badce8dd,450ee7c2,99b77b56,25e808a3,62c7ef1e,11e30bdd,9777fae1,4f17259e) -,S(fed252ee,c2c0ceaa,57625d0e,925ee5d3,43718a7d,24ca3384,55e0abed,451eb851,66bbb6ae,56ceefcc,21d66b27,70756f64,dd07211c,5cf0bb4c,457a5a8a,e82c648f) -,S(da639ebd,22ac3c1,417fb04d,3bab0b22,2362af2f,9d3013c9,bc08793a,2d7f9dbd,83f27620,55f1e9f2,fa74ed0d,536bbe54,3627aaea,3e7a031c,10aa7b4e,822466d5) -,S(524d24de,d77345af,4d4d3ac6,7c71df91,32ced2a6,acae682c,e097cfc2,7eab90dd,e4cf5cf7,c6927c5c,31b6f55c,90fe7cff,2d010a00,887b3b01,b2f7a074,fab7f5c2) -,S(7dac2ed5,fb52b60c,35c7cde0,c28617b4,28672da4,5fbc21c4,b24c5268,54ae4f94,cc6acc7a,e9168866,70b5c4a2,bd2466c2,f6cc11b6,d282b09e,a578ee0f,e7794038) -,S(5f46b64d,da61f59f,6b99d10d,e9291a,887e5d9c,a3893ea6,f7c51cbe,e56083ae,6043d055,da252655,506dcfb9,c5572929,9bfa6ba,7e1b582e,5ee1f3d9,e283a8ae) -,S(8863ec33,b6a25f21,6e641ec2,b8c5df0f,48ef0fc2,38a7f635,175961a1,7de14aa3,9d6618f3,1e52581c,2f829277,7490655b,45b2a583,da0ff7a1,17dcb12b,eb42541) -,S(85403446,3ac459ce,6d8184c7,ef26f91f,b377f3f7,3e92ea03,a1bd6a68,33a2f9f4,2d1f1296,8ac56499,b252a5b1,8313fe35,8f7719f2,3b0c9430,438f7278,c5b399cb) -,S(bf6b3f6,217e412b,fe651dbc,362266b4,6a325d27,5eb7f201,379cadd6,5e223c7f,a1160954,c14aa455,fb041e7d,ceee3ded,ebfad90d,6af1beaf,a9b1aef,97ba748b) -,S(4b20202d,3c186135,4aa079ea,409aa4cf,860ca219,8ba1bffc,77124e5a,bed9e59d,9f684503,c107c0b0,ba5d858f,2f11d904,7703eb45,510602ba,b555e8a9,f5b8873) -,S(4087f880,6d679a4b,3a24f533,127b5931,99c050f2,627cbe28,2686a5aa,6421dd2,4838ad84,b3d9d488,33c8c883,698f5a59,69880041,589f921b,5a5707d2,bd88e8b9) -,S(15a79287,cb2e7406,a2db91e0,5a4fc34,53877504,c790eac7,66d9131a,fe97b79c,9f4ef322,76572e3,d3fce497,c2c6160f,1bd597cf,b96a83fa,df2a41a6,b94a238a) -,S(1c4fa063,c0524bc4,ff233d61,bcb3d40a,404fb10a,7e222812,2739b343,e3bcecbe,2a8561ec,a2d82eeb,97209e9e,bd730b2b,d39c90b2,bf4d0353,3aa8c73d,62d48bd6) -,S(a0708ba7,43c1b2c5,267936c1,85312f2a,bb50b8a6,d4886c26,56d163b5,adf2a636,958f45f1,916988cc,6c9b8155,12e1d2c,7dc66a62,359a4324,5845e94d,371a20ea) -,S(d7960b4d,f01a42e6,e109d71f,2e33ffd,9b79754,b129a858,c213793c,e8acad7d,8caf19aa,5a841d2b,61c3d0e1,dc65730a,33566193,63118707,d81c1e19,dbdeb920) -,S(7a03dc6b,f8ba70d5,96e25ba3,8fca1b32,a7c4506e,6e8a3789,daac3240,bf8ba611,70f19e22,292d6856,5a63e378,b773e170,48a3681,d096b881,fcb84a4f,7f7d9028) -,S(53a9a662,a8fa3411,c3989850,c6c83aa5,da516ca0,726fddba,c2f38f25,c7443b97,5deac250,6179c31b,f313279e,844d1e5e,2adcfdc5,b803036e,140ff59e,3945e25) -,S(86b946b6,3dbb0d86,ffe69af6,3c1bbaa9,b7ee99b2,876836f2,a450d9c,feb2cdf7,44407783,d3d0e2a6,cb18ea1b,a1e4f133,7cbc39c0,19997a62,ed74b598,f74b1fa) -,S(ce81cf5,cb884b46,f6956726,20d2423f,6b28c8ff,ba71d9ba,bef152e6,ef752d8e,75afd973,8120644c,349bf924,c04c1aaa,979177ff,2890c926,2d0b5404,5ea9248c) -,S(41106e41,3a464d2d,9f86cb9e,47d57d47,7b791d43,133a2b8f,bc6ce92d,e1172ed9,e2ca44c2,30e920b8,5601a2,773a0f88,2ce4e42a,7379b374,d2ec6fa1,f76741c6) -,S(e9c1f2a0,4e830a12,e546541e,c7ac6f6b,bca3f1ca,2052c152,4e141b4a,20b49777,51df3843,8dd12c2,29973fcd,516712c8,5ca73721,f5d50308,86b91f9b,32a58124) -,S(8bb9e12d,c5e8ff3e,4ba25775,f1552e3b,9be21f27,4250d511,fce5cf15,e73bbf2c,8a822b7a,273c3730,1c24fcf5,c19c4de,b4d0968a,bc23962f,91ef11a8,d00d1152) -,S(b0058ef1,da227791,e4694c3e,ef66e031,697f3f3e,297d139,9ad597a7,acb6bd0f,7f5bab4a,5793814,d8c0bee6,8ffe8025,e5deb644,7d2ba978,c805b2f0,be205a2a) -,S(1dedd42d,8df5fdd6,52e02b78,4dfcab0,6dfc3557,4b8725c8,db95368c,ac2522a5,3055a449,23730d25,18ff4a8f,983b61b8,24b918de,f357654f,5b46559e,b6bca540) -,S(761a5248,c6794ba9,3f45b0b5,12bc39db,e471813d,9d5c5f7d,a46f2ef4,380ea544,185ded30,c4f5ceac,5e18d0a3,95ba8ed6,9f703408,5fad1fc5,c60d10b0,832c1292) -,S(f1d5b60,e515d0cc,8dc20982,a13c1b5b,a1749687,501a4f2f,fefab898,e3aa5caf,55fd766c,395fd8c2,173a9e4,8eb63f07,ee6f9ab7,54994708,e42ed9cf,78a0d91d) -,S(569cb44c,9b7900aa,576ba0bf,61c4455a,fb09ff4b,c30242d7,fba993fd,bb37425f,dfdeb8d2,ff1ae3d4,1e78f646,ac7dda3d,c1131de8,e2566d0,d3340272,cc350b1) -,S(3e59b69a,d99839e8,51947a78,7d8f850b,9c2dda11,7dcd0776,d22c787c,ba1851eb,732cd2a4,8bfeb030,6bdd9358,37ec4f27,7050745e,b2c9f6d4,34cd8834,592e20b3) -,S(a46d6621,7b45682,98250240,3fc0886d,81acec57,32c3087b,e6ea4c4,95296967,140cccf4,29a5b062,24097a73,f9a8208d,46147884,e6127464,51acef,b9763d33) -,S(b920e59c,f25c53ba,7c00c427,d1575c9c,4ad70efe,daeb7927,74d16c46,5079ab1c,606160f1,d4ba888d,1d5435a6,1656b937,9201ec5f,37f585c9,d43197c1,f045b67f) -,S(12cf1ae1,e7d837b9,eafda1ef,db270db6,3b88b6d9,8d05c713,896e06b7,f8bfa8c5,e0d66613,181b934b,9f23d7b,e9cfd8b3,c4c1d66d,485075d9,1e8cca69,39c99c0f) -,S(6aad27ae,a4eaca2,e60620e5,a328154e,eb93a900,be13a302,87ff39d3,8dc0ec1f,932155c5,caa21539,e27e8cd2,dc57fd7a,d4681474,342c0811,2fe626bb,94a1f46a) -,S(134cd94e,7cb166be,82b48916,6c06c1b8,8d168bf9,21f75c36,ce9343ec,acf870a0,42a673c5,e956fd45,e82a51cf,ff09a399,2f7c8fe7,e73d14c0,fab88c3b,9453236) -,S(d5dcd58c,7b7cc786,8c42971f,a1c85cee,429b1d18,dca68e2c,56d9f5b5,5a3989ee,e0ca4130,ef1bcae4,ecda0529,7a338bc7,45bedd0a,f0bb75c5,e316624e,21208100) -,S(951d6534,c344908b,905fa4cd,b691f33b,3e3567bd,1538a861,f66ac9d0,e0d8c8e,eef35922,eb847928,6681a990,345255f6,95a5f691,9a7d79f9,d575f306,ed7046f1) -,S(cedba44b,25f7964d,76d84c9c,9b521156,690af0ba,966ede27,b33665cf,c1cdd0fc,806a9049,cb8e9af1,d187b6b6,493316b6,187e7124,91a8f7d9,4c21b79a,87c79e7e) -,S(4ff03660,d1306bee,29abd39d,32beca15,d1c7d2d1,14492a20,49c6f4aa,d8a10b54,c2c75e69,8fd89951,e36e8bc8,be71f689,4990f25d,d2ff1893,d99e2773,6d1e574) -,S(c08bd508,8dbd6465,e87b7702,dfb7200,c78061a2,683b9824,389042ce,ce2e0ca7,562019d6,1343497a,b1640884,23a9f171,1db329b6,8c63e78,41793255,f88d7307) -,S(48dfdcaa,6fd2ceb2,3b85cdd2,28bac318,955bdda8,274a1e3a,7afd5db,4bf9857d,2a46622e,896167ba,5154e76f,ce429554,af60f4b5,1431d171,d55ffa2,ea0287ce) -,S(40420900,d81af883,cbf76b47,17025382,802c1479,a33a3cee,bbfacff3,16a1f236,866044e0,dbbcb53b,308f50fa,2b54255c,7831e96e,f19e1b4b,e4168d1b,7b85e3f7) -,S(96a3747b,23b667c7,70ec2018,4e99208e,ec1e3142,3b1156f,8b12f37e,322bdc42,67b0b3c8,df8c4647,3310b04b,ad325d6f,dc7545f4,a4a07af7,98c7cd86,3cf22ab2) -,S(cf07017d,e4037969,24361f0c,b151484b,f1db3e91,a8d16784,5039132b,c8460182,b7a1b107,62f29e30,d0f6e762,f6940638,e2eb60c9,e65ad067,99b1bb39,3797939d) -,S(12b5b8b2,5b0bb6f7,ad1b90de,d75fdd5b,93507aa3,dd7276dc,805cf5a,218beb15,5d3d4767,8cefa19b,80ed6368,d40ca199,5a5bc165,b3609ae,e89b56ed,b78933da) -,S(879b449c,e866e6d9,3998b9ac,e18b6f19,77ecd299,bd9b727d,cd99c37a,13a46765,b0c480eb,758cfb12,acf50c4e,91a8d9e5,f0c45215,f03e6bae,c6c13a83,63781c63) -,S(2ec48783,e9d3a01d,d1fa401d,d3fef249,e502280c,cb36d21d,d2b7b90a,cc7dead,fb029124,78f9e2ca,1a5e6150,5eb469a2,83fd8f81,6798703,ca2f0c7e,85a67fce) -,S(79cca258,27bedb07,39fe8fcd,2145956a,5b7878fb,bd873a83,aee22093,437c3ce7,ff488a93,d82e8750,14cb7c48,3eb74b30,bee990b2,2c1915a8,d3381cea,9cac467e) -,S(c444a4ca,3d2b8b7a,826b9eed,40616aa6,8e146a80,d49a9cd9,3e93cdd5,5adbd207,4d1368a9,63d504c2,541ae338,1ded0684,ac00ad0f,b8fc3231,9d1fc273,92d0f18) -,S(3ee47c50,cc0e44b2,5864e205,835e8d6,dbed328a,60493c26,7ee5529b,cff3e7a8,fa555339,56ea87b,c3249640,145e243c,b6229a30,3d1b91f,84e1ca9e,90a5f095) -,S(e963c987,3036bb7f,422251a2,9f9b0f47,8e69e2d9,2d1920a8,1c012d7d,c809980c,ff95bb0,779bbf2f,1242bfa4,880b173e,140f92d6,c7f8e5e6,18027a3c,55c52fd6) -,S(aaf6075b,b6a1b8b9,afe4b747,a46fa394,23738e50,e686c8bd,3f711cc6,548fc07d,4cdb0aec,6d11ca1c,1e85bd16,2eb411ea,53ab326e,bbdf898b,1bbd5219,aaf2b0cb) -,S(691e4817,d8e9756d,8e174a18,d5d708aa,842b44d5,ea921298,6e4c7585,4157ac0f,9eaeba0b,3bfa7ad7,80d0eb15,72f92873,4bb9a8df,29f508c2,d1ff4076,a0c0c222) -,S(c3e6fdbb,45af4a48,941c9d4c,583dad8c,c77dbfb3,1caf3fd8,1d9e087f,e744996a,ca998d1e,65ab29b8,fee07bfd,1ac4e979,b869474,b5498a73,e642bc9,608366f2) -,S(edbd6320,a55d25cf,21f2630b,e7c5c996,923eadf8,333d386,8cec00b3,940701f,d65192e7,afcef5e4,c88cd12b,fe28f94a,5e3d3d50,f6b2c3e3,f7a14243,4de4889e) -,S(c959ed83,a80ae0b8,ac2fd249,43c37412,b29684ed,9d4d85da,d7cb4c34,ea95d336,80c1dabb,8dccf252,ad8b0e97,25970c1,4de5f58e,12f7e5f,8b59a2e1,a72b168b) -,S(778cc574,471004e9,d88c9022,4d2d5cfa,2c5bc6ed,da64a312,74e3df83,3eed9237,eea23d31,6b2a1c02,7b92e502,db921d9d,675720fe,51cc3609,46b2dc93,92916c17) -,S(a1f87438,8c3656af,43f299f8,1d98d2c0,173e7e46,d3fbed9a,5c2afc96,63b42055,10bc8443,820d6c5,b3150e79,b9936785,5d874afe,dc72a84e,abb987a7,d56f4afc) -,S(c8ad7f0b,2d5f8b8a,cd9a1839,c3d043ee,8f7fa583,7540f6a3,d002091f,68224a5d,3018b580,eebe5b9a,2d1507cf,18a7fe4a,2a1cd4b5,1157dec3,8e65f191,c7aebf8b) -,S(c25d5264,b93fd7b,b7e4e426,1ae767f7,1ecf3840,a2a7ad20,bea810db,4820055f,fa15c8c7,6e3f2b0f,a29fffbc,eb48ed32,bf331aec,3a147524,c349e8e2,465ad684) -,S(d0b972eb,7e4cbfad,baf224dc,cb2d873b,28316877,88b5f2f2,ccc62bf5,e978f92b,ef5d3ca1,606a5852,aafbcb4c,f23e787a,75610b31,8420bf56,e94e420d,f7ab8e3b) -,S(f8b44c83,58564479,6448791a,b98132b6,d393e851,bbc294ab,56c8042b,1b0a2d07,c28242bf,42040be,e9851362,fc8e764e,2dbe0c01,d5bb0ed0,b8e1edfe,e870a27c) -,S(e7cb8901,6f72aade,39410adc,12fd1234,5d942419,51a6d36,8acb7c83,da5666b7,de367522,46b6d9d7,efd4ee6c,53a1656f,f0c87e80,cb0f8f63,95341c35,d6b21697) -,S(8b2128f,14e3f4aa,92e89478,64c5eaf5,f40f93e4,95cce167,fb2c7424,c279d87f,e7ed384a,f469b4b1,1812068,a830303e,699926d5,b8304c11,cbeb0e49,cf5d246) -,S(f34db5db,3cbcd586,38b6a5f3,ab5b31f4,1f3f631d,785e8317,658408f5,93b4afb,dfce7372,bb2c8466,fa31a1c7,4ffc1ac4,5bf11263,4c98ef2d,56e30fd5,c3dd3d9) -,S(c3689e09,a445d685,daca48ea,bca533b9,10b4fee4,dd251c86,a965d5c2,ecaabdb8,7804d05a,6a263fbb,c33efbe4,f4075d1f,d62e187e,3a5917a1,55c1f22f,1679e3f4) -,S(7ff995ec,f776a10d,7a66d62,6095892f,f1e47d4a,2b47ca78,d708a0cb,3f005cbc,edcdc774,5f17e430,cdca4d11,56d08288,e3911d0,e92999f5,cd5c5eac,ca6ea90d) -,S(3662a262,62234bf9,69b18351,2423ebb5,db78bd6,1cfca8e4,1c0253ec,427d4d27,88a62042,f07e69c,f40f671,ccaca36b,d550ef9b,79b4999f,c41cabac,1c2e1b09) -,S(2c127c2e,6d9c42e,970e66ee,24a07388,b6b4ebe9,1614b951,1763b414,3f54e8d1,a4773eb8,dacbadfa,afa26c8f,f4adae30,856be023,6022d93a,aae59c9d,fdd6629) -,S(c420ffa6,116f161f,fd94863a,9fe30b7e,b7dfcb0b,8cf9acb3,7f6d6515,4ac17802,e6cc469c,25c68f6c,8499e9cf,95eda8c1,7fd76d97,2ee8fbc0,79b143b,e50a028c) -,S(77896743,220343dd,58c2f06f,d3217468,34d386a7,e7fc969b,50c77847,eae3de0d,4350d59e,4408dcd9,710bcd7d,629e92a8,cd906759,627921f8,57054a4d,21fd9369) -,S(cf7ea42c,1a14dcb4,3334f9b,636ff0f7,7147688f,19133c83,dc127139,349f5827,b9c02c80,166bf9dd,139c2846,895e4aa6,ad1a689,66460a29,f8e951dd,d99e6d9d) -,S(d1793439,ab1fabdd,ada8ab1b,33c9f96e,417b1c84,7f753630,9d815fa5,a673a91f,ac13d659,3b5941b2,3b19f6f7,f9a67d0f,b429add2,5a40d05f,9bc0d1cf,ced3b3e0) -,S(bb1568d6,727dde70,c52f5863,133dc9e,54722577,4a74026b,e9864f02,9e92b420,b5654756,268d74c6,cc6adf80,ceee29c0,9e137d2b,e15aafe7,b170c95,22af3992) -,S(732912d7,83e8a5a3,a7468177,231ba93f,ce07c42d,778dc205,35cdea7a,db877dcc,d34b8388,1b128d23,e68ffd7c,29c7a945,1664f5d3,fed3dbab,6f78c8e,77df80a2) -,S(c74f0f71,fb8532e8,2c3e1865,1684d3b7,4927b6dd,22504afa,9084688c,7297074c,9da5ea61,c0bd178e,8bfe5a92,dd040c6e,35984bd4,1102806a,53a9f1a7,bd006ac1) -,S(bd4fa939,8bda5a0c,5a4e9e49,43060d9b,1785a613,3c970aac,91fcbc68,9e3283b0,631d4fed,b6614b49,459be1ca,ccbac0d6,e79cfdbb,f14de95c,5d2a5cda,30e433a) -,S(9fa65462,733f13d3,2483e0c8,15cb6bd3,e9bc2d79,7b89ba72,f2465c64,a341cc8f,7051fc5b,afc5b18d,748ada32,c4a27151,443505fc,2f14f130,10fa02e2,6a12db04) -,S(eaea6f7d,ab3dbf1e,816434a9,ddbe53bf,715168fe,2c1ebd4a,6cd40744,c35e31aa,b96962c2,4f202b96,c2080619,ff4ba905,a594b9b0,1f709e6a,76a1a7ab,9784d61d) -,S(b3df7ab6,3b947504,f33e6d5b,7b8e2553,9a117c8a,497f8751,6b97bfc5,3b17a2fc,72df7500,a35ae6ce,d6fa6265,1a759dd,f11f00ea,9152a5b5,ec51bbc4,9d758b9b) -,S(ef875ecc,46da48ae,45619be9,950e294f,4341df09,726417fa,3a8d1ac6,c3281bbf,7ab9e204,af4c05b6,d6d0eb6e,8306c987,51ced2c2,b9e8dbc2,8a642bb3,7f1c72f5) -,S(74c3c446,576a8a3a,5082f234,afca508b,3d748757,4cbf14e7,fc26f36c,70024fdc,73d57916,4ddb6fa8,72dd2afb,f9d8a307,b6ccac9c,94a4eae8,8c4fe8e1,dc136506) -,S(959c4b2c,409f2e3e,6c020493,33ba2f18,c06b7182,5a664e1a,cf33846d,cf39274,17cab35c,7401629f,b73cd398,dc5bedd,d319919f,1a3995d9,45f42f68,2c9aad47) -,S(404f0dd6,94195313,1953b53c,67fdfab7,f67c24bc,92fb4d69,a9479a9b,6c9175fb,857c75e7,f40a48d3,ab156085,1d42b037,7e7d3e79,86efd570,147917bd,f24d87b3) -,S(3e040511,233b0f5a,53df4d5a,b0854137,2db4ecef,170b566,807c4923,6ce82075,f9337271,dd443843,77a35ebf,56753b22,1fda08e0,1b790e02,b9603827,600df3d3) -,S(942ea853,10dfdc3e,1f7993e7,47bdac04,ecc8692b,94847bd3,e044cdf2,2cd77e6e,bbf2f7c8,e688b6e9,b4510bbe,58c41b1d,f33e9afa,5428ce51,e02e624b,9ea155e5) -,S(1e577a74,9883a5fb,85593809,7d0180a1,dce21791,e10b2c0a,3fe6cea1,cd03b532,a147662f,856f5e15,dba53000,7278e878,7b575612,d5dcd790,19417ec3,ac41c003) -,S(ebc9d95a,8a237b64,212e9dfa,607fe4a3,7a05fbfe,7c5594c8,ae472c4f,6ffeaa5a,39406dc0,e311a47c,cf15fb45,8f8b48d3,8fec2fd8,6b4afc05,b1747957,e7f1162a) -,S(c78eaf60,1afdfc20,2123d228,8496189,b9081637,1fb2c475,2773faf0,63cac063,95325b1,e0c22dc5,df6e84c5,16d396f9,bacb42cf,6c1fe9c7,6df83b3f,3eb42de7) -,S(b5918719,a1d504d2,b44a3d0e,117c2798,4f2e536a,3571db8,752685cf,df6d34a0,9b01e8cb,585cb7c8,fa29828a,ac899050,16beacb2,5e62ea35,6d54e9a6,18184abe) -,S(8706a73e,b59fc9d1,92907dfd,cc6f75b6,454f1045,4a5e9584,bdac978e,8e0042cd,8b1b5f56,6f1f78d6,f528405a,2b6a87e8,4265e2dd,1e34c1ce,7109286d,5bdc3a49) -,S(93e9256e,4ddb4bfb,6f4a9289,6e2ad04,793e5642,3a22230a,e645529d,712d6ca,83b242db,d9b3dfec,3640ea62,f0e3989b,d874f247,90a75cd6,9756a8ed,6eafdcea) -,S(2dad49af,8702f39b,cb353956,a1d5601b,a24fffbf,58ab527f,e9ac6ff9,ea2ac295,b5af68b8,e6040762,55c0704e,2cace8c0,ed403611,40dc02fe,2773a625,27e4675b) -,S(5ffc1899,4da42fa4,54962719,5ebe332c,86a2c364,f43b14f7,59710c54,4f6950a0,22eac0a8,79815faa,220e6141,9db053cd,4542ad2f,9ba9f63f,4331ad5,c2c9bb88) -,S(71be09bb,1832a799,c4e21bb8,a2bb5ad0,324c639c,e6e62b6e,69fa60bf,d41c51ba,c5227fc5,719a5b8f,28c40767,b54eb249,950588dc,c15e1656,e4ff238d,54dda472) -,S(4f94305,f92799f0,a64a3cb3,7df2bac4,56d661d6,44568277,bac0ed6,6a587212,4c48691f,bd8683d6,b94ddc7c,ad8d1d7e,6baf796d,6d00f344,511fc13,13c054ab) -,S(55ef868b,6fc2923e,e624fc09,65f61852,b3aeb38c,e2c6b3bc,54b86b3a,60f0ab81,ec198aea,ab16b4cc,5354d0ad,c66051fb,76cff6df,22dc1a0e,72ce6e79,1622efab) -,S(26ad5590,46e19dbf,e60953e,d40a3958,a357f6bc,23642279,cbcc355,74fdab68,af6fc5ef,906721c0,553c6a74,60bc6894,e5bb77e7,4dbc25e2,184fb3f0,fa795508) -,S(739fb43a,b1b07155,39c0b0ae,43901bf2,bc051a69,8ee8d503,84fcc1f0,ec37312a,c1223704,3c882226,2d4abe33,1de6ab4d,ff90d6b8,4c0b59e7,a193e763,6c6b7e28) -,S(2144649d,508cf5da,a7b422f8,22e9125f,d5a10965,a9d32c6c,c299bad4,6616771d,1153178c,e33c445,f03ef96b,35067ceb,76ddeaca,d9ddba1a,74acd229,d01ca76e) -,S(62cc463c,16ee8e8f,16ea8517,5508278d,4d5577e3,556d3580,ec8d90e3,bbb97072,cd294843,e299c500,846a6c91,c913395b,56b48efa,2f9ab3fc,b81863fe,8a6a891e) -,S(1196301,33edf190,d14fdb00,640f74cc,4317e1dd,b9dff1c9,707eac33,53ef9c21,f16ab4e5,e3a3ee6d,74385187,6da07034,caa4f519,6106a0c8,3136d21,5420494c) -,S(b250bf86,3fdaf93f,28f15bae,d9555287,777d4e34,2673c16,2b4a6319,2289adcd,295c05be,de343d28,87d3543f,6b40d5f9,da1e06ef,39fad6f8,28ad5ac1,39b3d2c1) -,S(93a40bbc,ae584739,9f10945a,72c199b1,27ef008,14e87e69,6f4f46f6,483e7c6c,81ed70c0,29809674,f5f289a4,5926864b,f088e2e0,af66173,89fe8cbc,aa858a09) -,S(b9e6761b,4e909d75,b17e76b3,4e9825e0,19ff7ddd,4faa9f90,eff8c0c0,f60978cc,640c1503,5fb91270,8881b70f,bf2c8575,65c75e3b,c98d211b,76279090,7b5aa117) -,S(4dc22812,fe3d9ba4,687e260c,f5b2dc08,ae454751,b022b9be,ebf4360d,10cfec24,9c35ef4a,56858135,552e986d,a4d68056,27f0822e,43031c43,5b2df5f,7f9a90d1) -,S(431276b3,1127f9c2,406b94ba,683d2d3b,e198e225,23663540,9348286c,4c9deadf,2265ed84,c7f1df86,4b46280d,ddc8cbee,c26d39c8,ddd5b743,13938c4a,e01efb3e) -,S(75c5b6c3,c99058f4,2b4b81d7,6cfaa917,328f1736,b8788360,aa810acb,3683632a,549f009f,def17b7f,70a309ef,49a890f1,4a5aaa1b,a80f0464,affdb5c5,a8f719d) -,S(3c900027,205af742,976b1a37,7a4801df,26d4d4e9,12ea757c,815ef99d,cea827d7,e28cff3,37eca7de,2387fa7c,339dab2,7a2446,fe7184c,83c578b1,8649cc0) -,S(5660f31a,3676b95f,9fa8ab0,d5c23f30,c89637bd,3a8ea97f,3a87aeab,3310d9ff,d6069cd6,6bc4ca0a,7d892ff3,e4d9aff3,955bb76c,2ba3f839,efbd786c,b11c568b) -,S(2b8b68a4,1b45dc86,7f7979ce,5b71d778,e6733cd4,79af6f61,8cd786ff,5f3babe9,7c831244,d5441b33,c20923f6,3ad9a093,840f89c4,6c1421ab,40ac52c5,8de4097a) -,S(8635004d,b817bcdc,4b357886,96b3fca0,1d369d4b,303e9290,44229cea,89c18610,2472da40,2bd46e6b,e2f84cc0,5158da1c,7e9f3512,1fc4b00c,4c3ec329,6eb909e2) -,S(6c991a6b,6eeb4f97,9b7afbde,46e1eccd,b0d39d03,dc64fb69,3a56a234,88cb28d0,1e5df74f,c2cd6350,50277188,d3eb4473,e0b753e,4cd41372,2bc119ef,65c95620) -,S(acdac19d,4283cc91,b9698ed7,e92288b8,554569a4,962ffa0c,a52a197e,9f41570c,fa536d87,523c8541,f530c6bf,e71742ba,451d41a6,f97d9afe,ea03a520,c6d7b66e) -,S(b1496ba3,f696cbb9,548b107c,3d28a7cb,85bba7f0,aeb50abb,a3e2a596,465fc6c0,77fb6cd5,727a4a6e,e0fc8f8e,ae807827,487740bb,ff5cc57a,8572ef3d,c86318ad) -,S(3fd97db5,6098e9ca,fccab31,d6d128e6,c2c9f878,adb07ec9,4d854034,d9b09126,1bd77c36,1494e374,fc45127,38b246f7,24e37d4b,27e14a2,2c0401f3,222b4578) -,S(5e8df855,f2a468ed,5476d5c4,409c7cfa,eb174cff,ad793338,8982ae2e,c2aefce9,52e73a82,3bb8ca88,a0977184,38701841,d50da8ec,c46f357a,17eb8cb1,36a6845f) -,S(99f106eb,1417cb69,e95e6fb0,a0fb932c,62021a1d,b940c661,3f814086,c64672bd,9e7fb038,e1e70011,6a926e6,a1c27fe5,e484d843,d184d533,7e9825ff,f7a6501d) -,S(686fc498,5526d87f,fd11d686,4ff0e208,68bb14fd,4a5c71f7,ac43063a,7e51ef8c,1d28f532,d793af85,bc96dd6b,2e0f23fe,4137dc5f,5b3d6244,22f60919,44588e5b) -,S(cfa5df56,cc450bca,914f3a85,b370f864,e4c83600,560bfb20,93df96bc,bff6b83d,cefb9a46,bab7ffc9,1b1d96c7,48f81706,61cf56f0,264e203f,78b05f3b,8d37604b) -,S(991b6b4c,3fbb9693,f7641eed,534e7cbe,8937606a,962a83e8,b39089e4,713e404e,3ffeba6b,be556688,d3b8a0a2,f4b92b8a,98dab79,d5847c71,13bb60ee,be3f8d3e) -,S(d104c5d3,b9b0121c,58a1fa14,f226c513,2955c4e3,56938bcd,6891bb92,13c8c0d7,8c8399a,814d7cfd,32cea21,85c77738,91ddb00,a091196a,3d90d056,b0caa6e9) -,S(76192853,a45c3648,749c9a40,719424eb,415a06f7,c74b31bc,ad93194b,e355dfce,31139287,3cbb5012,d7ebc934,52613c62,b5517b37,91475ecf,84ef3745,324ad2fc) -,S(173304a8,509c1f4,c05b1de5,c51093b2,10c7f9b9,81a7d6c8,8059fb1a,e5070725,43bfbd98,c8e08394,543db2e9,c692297a,800cdc8b,398c13d5,f9e21f89,341d353e) -,S(aca057e1,d28c5514,107f5b6a,9e46fc95,9eaccaa8,b14d4c4,6b7ae515,bda104a,e17f1717,70bd76ff,18095be9,a4b72b8c,cb00e6cd,23f6d702,4dcba433,e6bf6ce8) -,S(fb202550,e0098fb1,c30a7385,900a7dc3,85b2945f,60e6eb04,b7e8489d,3476dbaa,1aaf8420,3f72c68d,bd3bc98c,77f473cf,cedda922,dfc3c996,45e4f565,ef9a0f28) -,S(e95b710c,a0227ab8,e5b66c66,c2958be3,af1aa298,422c501c,8f879bc,e11ae7ac,e645f4e1,ab5cf4b7,da909022,cedd01f8,c745a968,d9ca30a2,c5525d50,9f97cf19) -,S(6db4525c,3589bff9,605cf203,cced45ff,ab136c6c,ce77ea15,14766f3d,e844770a,e6b7f403,f5f7584b,2331d295,82c0698b,799cd7bb,3c59c903,eb5d6848,72658c81) -,S(8893aa9e,49daeae7,15fc2959,e4db9c45,1690438a,6964a2c8,fbe73133,35085eb3,70fbd83e,ae803f3b,6377a4b0,265f62c9,bd15cec5,baec8c10,d01c7094,e5987cdd) -,S(be57f6cf,ac6e8cda,871e3ece,8aa78bc9,2cd9e2c4,8f3adfd5,6e39414d,8e0207a0,78170872,99abf89c,fdcd141d,899aa7ba,8893eedd,36bb3aa1,58120f2b,ee93d5f2) -,S(77fa6d2,85a01129,c5e05ddd,8d02b5d4,a2f69bf4,5a9e7562,6718cb54,20b34925,315bb23c,13a3d218,ce886288,ec0edfeb,37a2da99,e017b97,ce04db45,326455cc) -,S(2fed7bfe,8414dc33,62c834ca,767ffb0e,61094ad,978ddd00,b2ea09b8,d1f4dc03,14e5e8f7,aa0b3d31,565e434f,11c61b,63332a60,b6c4cff2,a6de2c5,98117e01) -,S(9f4c2cd0,5a871ba1,fcb43df2,bf03ee3f,7f8af242,ce8ee6a1,1aeac89,b4d66c6,eb421f52,f2427887,8ff8a2ab,dc384e23,d0fd7df5,fc341acf,83bc5940,be922920) -,S(53c0e0b6,824a04cc,b7203ef6,e37383f0,15f0a48b,bbc1d3ce,7c8fa7ca,5dbea647,6a9b598d,9246ca1a,539729f9,be809397,13c59d5e,105a8e91,836fd3a1,4d618cf9) -,S(dbc0cc82,d7906b84,b6b7bba5,433d68eb,bb20fdbf,7b4eefd5,c0a3ad8a,ad17d714,5ebc1f86,23ff2c3a,6f81b090,4e5e6338,8aee42e2,85306e37,a4fc7676,2dcd7211) -,S(7862af32,a3c08e04,7b1a8cbb,8131d55e,ca93a478,40c52165,af20aa6d,248f5f0b,bb5f6607,6b10353c,8a367a64,587b3bf9,7e8c272e,8da92684,f1efdc33,8bfc15d8) -,S(d3571fc,800158b7,6ed2bad8,15c93b1,f8238fc9,b8753752,4e44c0ca,931049ee,162dc9e8,3e6630aa,9d0872fa,915af449,70a9e6f9,526bf15f,4d26bc74,82a44bc3) -,S(a851c894,cebbc758,642b98e5,5df3584f,b9f531da,88faea26,e908b0b7,88589d9b,74702d5c,adfac1ef,71df3898,3ae433ad,1e1af1f9,b5fae0e1,151258e3,b375b422) -,S(a92e43f4,12effaa,e0978a08,cdb2e885,2d9af1f9,1f0931e,972016ce,da58012d,d8f5a09d,5560170e,b35d7bd1,28252096,535c687b,23bc13c6,bb903b95,d02fb668) -,S(75cafe44,8b4369c8,42e658c6,4760ecda,bb29e129,d283c24c,9007fb5,f3cff6bb,ca0e12e2,43c73553,1e2affab,51d4738a,db1ea5a2,fba215f5,3c9477b1,b55dc39) -,S(ab0066,4db959ec,2f17a233,78023b5a,c48c4177,7b6e6b56,a2148453,8c41d006,8cf9e2fc,35545169,f46762fb,940758ad,e3d3387d,eb72e9b7,b5d37175,9f5d8b31) -,S(27510ef8,2e4b2134,180855bf,469d1f0,f89b9afd,573f2781,4a1bea50,9db7ecb7,20fe00e8,86b54c06,1fe07355,5be99fd3,b0a1b20c,dec68aeb,90055c34,acfb87e1) -,S(773ff5a8,d388277b,7921405c,99c9c207,f4a6c2ee,3b59ac1d,7452c8ca,4db16d3a,cf45e631,f51cc65b,afc806bd,87318e3a,f75caf,3e734284,8d7435be,f8a52f8e) -,S(2f8f2c98,e69ebfc3,b7277e35,9da1a8ef,4293fc37,2e24386f,e14cc455,1ef45746,f85d23ec,c4dcaba0,23c3e406,604aaae8,8150a6c8,feea2c36,42ccad40,9968ec06) -,S(1878acda,ab8dd0e2,a0884952,26356ce5,74575678,64da41c0,61a83de9,6277f67f,412c868d,64e092c,ade96f05,bfa48af3,ecbcc128,e6d09bb,9684565a,d5477020) -,S(8cf281a,eac4e4e2,7ec4f3cd,d1373f62,c5a17b0f,49cf69c4,cad8c4bc,4f5618c1,2f17f995,29c9ea27,cda3911e,de33029a,7dbf09db,64ffa625,cd9fd86f,29ed5973) -,S(3a597c9f,f165369e,5d90d191,3dc2aefe,a0957936,717f1ec3,9ea20698,d08939f9,8c2203b2,90c9a2de,5b464b0,988e07,a7b48c86,f5891926,da462b4e,b00a14d4) -,S(cbe3205,96f10ff,5de9c861,55290393,b9ceec90,bbac68ac,5054facb,950ca15e,446cb06a,b76aba12,c32b4855,716001cb,9bf7c72c,ade16bd0,5472b947,4fee27f4) -,S(4313c9cf,8224e70,18413b09,e6544731,1cde7100,5ee60bd5,3a8db041,56fed594,dfaf359d,d3045a8c,b181021f,9a025208,e80bbd4,abc4a331,7ab9d735,1b329a96) -,S(cead2b51,f8d8adec,2d89651b,2da5ffa5,1f5cbfab,19fb7688,2bdf0faa,bf73c60e,ab2a2480,6992f0e8,c73e7932,2bf144ae,6dd3bda7,ed2d221b,f8451ca4,56a25897) -,S(9ce75c8d,848762f,645164b8,45ee6eee,98e34dad,9f8be0e5,2d8f27ae,4a7b79a0,e0556d4f,e11ba906,6b97c04c,8b742a26,9f627559,b9163571,d0a29dbc,9aa30a05) -,S(6024489c,621de255,f92106bf,8c23847b,10214b83,1d653a9,6ba00889,326741d7,950eb24,80a90200,ec932621,6b82e5e,abf63e08,6626faa9,b1fd8e2e,104ea858) -,S(d3c746f0,108f6bcd,406c2638,c07255fd,1f55e1a3,c6845e11,546d22ed,5f08e51d,d124dbe5,d349c739,e641a776,c57ef3db,35ed4e1a,6ffc165e,25d0bcce,438dfab6) -,S(a1eb5f5c,d85dc222,f97b9e11,e08594dd,a69c69f9,bcfa4c63,52cf2717,136514b8,46ed3d35,a393e017,76247ddd,7dda3ba0,ff5e3f76,30253b68,750a7c,f8a15fff) -,S(2b24a357,fa3ac2cb,faa5f1c6,1c14147c,e4406556,b82c7639,721f7561,485a8736,d67219bd,707aad55,1a8fd7ae,d5721d45,ad192a5f,5d0b643c,18330cd,1bd73ade) -,S(9901a1ab,9dc60159,63cc9cfb,42ecb41a,ab6a623e,62e9f306,126a4f6c,fd87b2ec,8f766594,17cd7f2,fff7a3df,6cb414e7,eb5950c1,ee265730,633ccd8f,f0339317) -,S(311e8445,5890e2f1,e1d8e600,37d58c83,28a2a4e1,b21c3763,4aeb9965,8477e8da,cf593f67,6cc75762,a1b0dd00,f6703bc1,e017e927,1e61c829,a0459056,ecce030c) -,S(905f72e3,97140f6e,298ad8b8,c8faf66f,122d27e4,6fee88b3,67a8ecc7,9e83bb77,c03f155d,bde9c265,d90b94fc,1b5b253a,2d98528a,a12e19b4,698714a6,f1b65257) -,S(61df77a5,d5940001,2fcc2f02,199cbb4c,39eafd33,27dc85e,4a3f55b,a339350c,27c88b7d,de9b3f,73b0603f,2d6e40f5,f3664020,8d6dc05f,684626a2,d9049161) -,S(e1f8e199,886d4b1d,5dd6af90,6eec06c7,de36dd4,ef026129,5bc42bac,5df18c28,502c12e9,b956eaf1,2865bc4b,ae7e6348,56a98db5,4c65a5e2,9ecf8ab7,51ca45a8) -,S(ade2f5b8,3804a21c,7dfe6a7,7044cf96,9180e154,79a4aac1,9b686076,fbb8565a,d0d65e1d,7c8168c,308985d6,f5d267e5,98a9e6f6,45715eee,3751bc26,ef066aca) -,S(c55820bb,154f972,ac345dd5,c62880b8,9f7f6b85,a1755b88,ea5821de,6f268187,911b0fea,1e6ca659,263b698c,8a17488d,4dc35f5a,d817e7a2,1241e56b,cc613086) -,S(ea20966e,321020f4,53964352,b8ccc2d2,1285888c,152ddd08,9f7039c6,6c7778b5,c942f591,cdc81e52,6abdc9bd,643429c1,66f5476c,dde18d39,59e29f26,9f4fc18c) -,S(3c57552d,9c2dfe5a,67301bbd,3e1ef84a,220c908a,8e80c707,9f9f4df4,607e2bf5,d49fa0ff,bc4a6397,3e71a0a1,7265ff65,6fd34754,ed508522,b9f0200b,e71f39e3) -,S(f188ccc6,e1043ec0,59e8e133,94ada165,a3fd5c0b,cf7f071f,eb5a0951,9bd4e1c3,5f1f371f,e53e79d0,2d6fb190,8207649b,db045c41,a2fe1cf,94486053,7bfdbe4) -,S(a0145fd2,7e72232e,8055a146,aa7bfb49,447112a2,d1ca53ca,d4835e42,c11c8c6a,7bc018a0,e5e70ccc,c4bb675,f0709cb0,ceb874bf,22c7ecc5,243e49c,3de679cc) -,S(53400de8,c221153,1fb85706,b558185,c17b7bd8,b17416bd,9c93df80,f16ff48e,e1228e47,3ba565f1,e50840b6,a36ea970,2df87320,8a66a44c,89cd33da,41a6cc6f) -,S(82115d2d,9d37e3,50ce3482,1d59af85,cc8960b4,52b99904,8c6c6674,ce64b1ac,98deaa09,659a0c24,4aadab0,3b9d1881,bffc1b3d,e9226f05,e75fb9ef,b61eb048) -,S(273d8c18,53d86f1c,c49e6e9d,450dce26,8669cb7c,3083968,1fc17894,59fe7c3c,6c5531aa,8ad026c8,174c25a2,51efbadb,14974e1f,7f7f88af,2e16d101,c2ea00) -,S(616e16,a7e38191,70e33f4f,bf428fcc,41e68ccb,5b059bfe,4036751b,ba5ee319,7dbcad21,182a3efd,b99173f5,cca99374,7c7dc3c7,3e8af2ea,ba84b0e4,f506748a) -,S(6761896a,76a39812,1f773402,d033f210,dc566610,275f6774,52c37c01,60b82812,7fdd01cf,1b40939f,8091184c,8e2c8ce5,11848df1,a23607eb,e760782e,67302c9b) -,S(77f7abaa,e97605da,12535bd9,e177b6b0,bd6eb020,92345fe6,dd4a6d4f,89e508b9,fb04996c,cc7b830d,fcf5fd19,bb7c9332,dbf20fa,10d61231,889e4b65,cc7f0b9e) -,S(c12f6717,3a2e2bba,3da97378,501f9cf1,bc4b4a8a,67b0c5a4,a0d8caa3,98bce311,de930986,44d31401,510012aa,3b6cb541,97cd133,6e583853,a330319f,779a47a8) -,S(6553a2de,19c7552c,8db9d268,ddf3a034,4afe8ffa,a76bb304,ee77ef95,c18e66aa,91a72010,7c180bb7,2af4dbb7,752d374d,69f95bce,c9bbb7f5,37377060,70edb93c) -,S(f54b4be,353f4185,22e2e936,3400caa9,bba98023,e6a3d3ee,c1fc5046,b7b834e3,96be786c,bdd5f1f0,a835afde,219745ab,ab6f78b4,577d3a5,1246437c,8e96f17e) -,S(c2d317c2,a0fa6522,bbc806e,45b4dc8b,f86be37c,4b677c64,c0d5b4b4,eadbb2a,c5710969,bd68cabb,718cb16d,fc9994a7,100f078d,4a3aeaf5,8e8eb35e,d313ab6a) -,S(52a567c6,a5b8a64f,dc74b9c9,57f5d472,cc43e143,4136fcce,fe1ff313,1b89f384,332631bf,a314298a,dd45f7d6,b8192956,d7de27e9,7d835d48,5c16f7a2,9c9e8f53) -,S(f7dc086c,891a4412,88543527,831247bd,3530f0f1,99b4c5e9,8d24a207,1dba4e20,734ed712,452e59ae,b0ef5f75,10485860,da055003,ff1067e7,b82de345,b74444aa) -,S(954f9fa9,7bb6dbc0,cbed8d8c,de6f8f75,b3f2ae51,e512cd3e,90520d8b,22ec06c6,b65b43bb,8bd9660f,4bdb3017,bb4f8214,5426f614,8f04378b,f65c39db,185dd9bb) -,S(20e69b98,41416588,20b66947,f775cd96,6def2dbe,416b545e,8188db14,2604e87e,e6514659,bd12b9b,35ae45a3,d43f6023,dcce04d,87df1f51,caa67f89,28632539) -,S(5cde5b82,2dc42f04,44187fb5,33029577,71bed484,2ab39dc3,709e7c57,c72ed1c,a0f7bad8,64e405b5,94416e7,53fd6137,cea3dcbe,7625fe41,b4929299,a9a0ea9f) -,S(b586cb4c,6ba6b0dc,2aafd03f,49d4d6e8,45b20460,5de71c34,6e73b131,fb26421f,ced613e7,c26ea3b2,a31de623,506afb86,6767b469,98bb116d,2b4ac9ab,58948744) -,S(7d3f6170,35803a82,c8e13dbf,a8d601c5,4e192a54,377e4a8b,2a2a5de6,90ba6ede,138e810e,62f413c2,fb56477,80c0bcbd,77eaf84b,e78e900f,1969f4d5,2ec6cb15) -,S(e7a314be,fc4af863,e7fe6713,5304ab81,c9fa32dd,80fa9b41,d8577ec2,8f7eb925,cd978600,f0e04acf,fa99b6d0,7da970c1,13ec94ce,c50808fb,91a44f4,80f3eb1f) -,S(179c3be4,9f41902e,e21cd8e8,10f0dfc8,ba5fc0ad,9e454231,ec090263,d3c6a577,75f9f60e,fb9b9aa0,29eb03f5,a50b7e4e,64021689,a4e889dc,5b9ff0cb,4c9cf184) -,S(10a55871,464bc182,b957808e,25754fa5,8d76269,5cf8c6f,e50610b0,91e6401f,d36493b9,6d2bda2c,e305c679,f906ba9e,99a787f2,aa8cb8b3,29516a3,41b56ff4) -,S(4a903722,5e858c84,15508d45,b31ec7f6,585827a2,f3a9c99f,96af3e9a,e88e555e,da4d45a7,fb9e44d0,cc52463f,20fcde14,31c9a477,d02c464c,70c7d132,3247d145) -,S(6d109d8c,2505808f,7b4052d6,b170ec80,c68373bb,e02f2b62,1cd29773,a96acb3e,c8dea0de,511f6e40,5141088e,cb023bff,200c870b,9cb952ad,c5038b28,eadc9a57) -,S(9c219898,6d202467,c055c734,73557505,6105b3e,2874dbf2,8f7f0c39,66e1af88,8637496c,8eddff12,f9dd4146,36565e0f,efddf5cd,52d48455,ec9fb2d,8dd0914a) -#endif -#if WINDOW_G > 13 -,S(22ca5039,e660f60,1036dd75,2bb973b,dcd104b5,dcb8f2e7,4de8edc6,c292b03a,86fd4471,1ef6b81e,4416449a,708fa0c9,cb6731ba,c403e58e,da5e915f,646b11e8) -,S(cfc18f02,cc004640,f2116fdd,1f6ca202,2e39be25,df75e27c,80bde842,e6b6f938,d62b58df,4f79d0e5,97ba2923,f708cbe5,c09236a4,d9d01398,6451d684,6290df7d) -,S(3388bcc2,3425458e,991f46ca,6235c50a,57490556,becbaf25,9d3c14f9,9a80a087,7d4aa2f8,6f65783,1c22316,6958fbf3,6c3dca5,d4ac413b,3102e13e,a645c016) -,S(d26bd013,1b8c12de,3dd8fefc,136d9f95,44ac963d,4cbcbaa8,2ba941e,f0b46a19,66f89ea3,31b6795c,6b694872,4cab492a,d045a7d,a6780653,cb10ac25,b68d3a99) -,S(dcd3370c,db67e8f2,163960ed,fef5f66b,465a03d4,d447f5ca,1d99d29e,57d1fdb9,8b93747a,320abf87,2cf8d448,393bf732,8a9eb4bd,9b64ded9,922616a7,347084ef) -,S(74074d05,e602ad56,337105af,59c63819,21d449bb,3fe0806f,80589f3f,4f8d8e7a,1a4d4bd4,adee80ad,44fd515,a1dd5236,bf0dd8f6,c44782cf,e19b8414,b03d574d) -,S(a89cc81,f3a23ebb,6a8df438,a78092a9,97120394,d6bb4dd,732373a8,2f05c174,4b6f83dd,676df063,4e5ddc9f,db979dec,326a9ce7,5707fd77,873a9644,a3c4fda4) -,S(8f1a10ba,fa913f0e,1902ae36,b07f964a,6443c540,b60ace03,7dda380f,6616424c,1028d644,45c177c3,24416ad4,e740f31d,14e3a462,d5a0326e,86998555,5de5525f) -,S(ad8fda79,14f9a236,a7957268,ada499ad,9154a2f8,478fa6d6,f4c74048,89e27b51,9ca1d2ab,1f7da6c6,f76deffc,5c3c933,703b74f0,26063834,6174e4be,320e82ae) -,S(6c6e990a,797b2970,4408cc24,6f238e2f,2192700f,e4fb3c87,4d15e32c,fd67fbe7,1ffc1798,f355659,9fa5b32c,c040da31,39811b87,93d4d9e1,be83061a,3f91dac1) -,S(202b13ea,31ad2abd,9635351d,e09f237b,9f86f75c,a340a47c,edc1f9a3,25118969,c52fb505,a14e37f4,d5111184,ebc81873,868a4521,700004c0,fe3cc535,181bcba0) -,S(5355f0a1,25142fa,b0dc7c7c,f9855953,34053c6,12326f5f,d2284291,d7b748a5,75bbe36a,553501f6,c1c8ff9d,e60ee3ef,9cddd36a,781c518f,4b1ccf17,7e281949) -,S(b8852d78,eacbdec9,d1cf1664,4a83aec2,79a39ab1,34706235,f913aeac,c29829d7,763bab50,52b3c61f,ae42735d,2e89ec3b,8d51eed0,f729e0fa,eb431613,df183156) -,S(cab2e44b,294df78e,1c17d4d6,a09ecd0d,696d18e8,b0f188b,eecced5b,7057ae2,f351b09a,501a499a,ced49607,c55b506e,de28bfad,5b20ed5,4059a068,19ff2f43) -,S(1400b9c9,9c6d555a,2bd2355e,b54b756b,b16f9f36,b9b86658,9d46853c,57056b31,8b290816,62f41167,a0a6993b,3d4211df,5709b91f,96f24436,e569c32a,dfa077a8) -,S(52ae372e,973e9c1c,687ae7a9,a111446b,b3d31b19,5588d8a5,fbec6e6,bfd9141e,f982b40d,e6d0e42d,b9638721,a4590db4,1f87cfcc,d8ece56b,71ebfe0d,82351ccb) -,S(3d14ffbd,40824625,be241e14,850dc030,1139b708,b937f2e0,fe5f65db,61899c24,b10a64fa,477ee047,4d9cf16b,8d2213a2,799882ef,d3766872,981fc761,88a1dfb7) -,S(c6f52adf,54e0c197,a8bbc270,d4c987b,e7ab3fd1,a95fe46e,82415ecd,baa48930,7524c06f,b53873b4,9050281c,99fa44b,b9ef9193,2adeba8f,77e5afd9,3856811d) -,S(90089264,bdc47cb6,7a3c838a,4c79c1c0,5f2d1dd8,6d18f55,9fe60a3e,c944c1aa,18963846,d70b3226,6a9d582c,c430e4b6,ca140bcb,91de7064,eea0fb39,d2ee04de) -,S(e27c24ea,478b37c1,6275b2d4,ce8212a5,2db74166,96f3c6eb,c1bf7091,efda0662,27ec5279,c3a267cb,fad532bb,5031791b,bb99f4da,fc3b7b7d,8537cf09,12783de3) -,S(ca5daa12,9cf1d6eb,70025d85,7955d3bf,2549b8ee,6064092b,917eff84,c40a3eb2,682d4905,500f6f7d,33e7c7c2,7d420b4b,7c4aa5f2,77b89e9e,f6a84259,de7a9811) -,S(9069ec0f,2b2ac688,46623fb5,c89d1424,6c98ac5b,4250c170,4871699e,fc877f55,cc500ec4,eff83712,16c0617e,e2407dfe,a6c3c3a8,c8b80266,975d3a56,e71fb05e) -,S(5fe1feeb,bd5ee1b,6ba742d3,c5e8aba0,536393c,592650f,b8cb1391,c3bda16c,db11b327,1ac64ed,3425ba06,8072f76f,ea02ae6a,4375daf5,3bf942b7,9865a34b) -,S(a4a91a5,f168f883,49035b6c,f90e4e0a,6bf2602a,85e0ccb8,31866c4a,ac1b2c34,5bfeea8,fe36ed1d,18af2ff8,e2b898aa,ff7265a9,c08f4857,ce082030,7f837596) -,S(f4135f36,f0c35b52,4a870505,4eaabe4d,43f5366e,d3c7d9e3,5f06f746,fa884849,1c6707f1,b8b6c078,b4d9d0ea,43075d75,ba1a5d30,c3a9c52d,d55fc4b2,650c526b) -,S(d5a8998a,9363fbae,d2b44992,883e84b8,14a504d,92b41e0f,dcc3a9f3,94380203,96016b03,6fddc805,8bb8ae7c,6d46cd7f,2f20c5af,a62abd4b,bf9b3da,ea60e9fb) -,S(8804ca34,4b30dbd,a07fb62,210c1938,d50297e7,9910dfa8,cc38b9be,4bf3d176,5b64bee5,79927c63,7788c55f,f3871631,eb65db50,b11cac91,24caede7,57d37b0d) -,S(8691c1fc,440c21b6,bc48e78e,78bda5a5,c947c74,7d098e74,ac5dbf6,2b811021,fd8ec1c5,35f51181,556c330a,f02a7110,682f4539,f66c1c09,3d48bca,d7b1787e) -,S(445fc1f6,343be2e1,fdebfe3f,894e9293,c3ee5fab,b0ed01eb,58a40637,ef093229,857f17fe,6737f853,d04aa1b7,3eded13b,c3c087f3,48da90af,32907bdb,7d85b605) -,S(5c397fde,a657d1b0,b2e3aaf9,5b88c4d6,af1a5555,a1dcf966,7d1c5001,a76493b4,9ce74820,7b6f3c75,2d736aee,6a9fc54f,ce5cb52c,f487fd32,de79a06f,df0aff0a) -,S(9b5565cb,28d7e028,361d2bc5,bdfe1912,d9f53584,372d30c1,d7e36fa4,c7fc1b7e,7d5cfa8d,2de2a832,58a57f05,4e3f6c6d,a23af075,d98b062d,82799b11,63879eea) -,S(afbdec63,1bbf870d,3971b165,71bb195a,a5229a9f,1012bb4b,89654da3,c9194f1d,cfcba749,b9492525,f9874ad1,bbb0a267,83fe5714,1f54316a,773c2453,8f27e296) -,S(7712abcb,ca3a5347,5cbc6160,5e9e9ec7,a7cc11c6,2c4b3f4d,e01d688,acad916b,7b91c9bc,eb12555,ad2b43af,8c3bd332,b57cbbfd,1ffefead,c68f0a2,6a4b82fb) -,S(3c452346,f2935e41,2e5fe506,fdf5066b,11b43a11,66e75c9f,7a2d38b,1ca2b7e2,fd3f6de1,27f96829,3af532f8,d4811fd9,e02038a,352b6696,2c608c7f,f59cd800) -,S(bd8582f,b4dbda3f,c7da53d6,70c994b8,e04eda44,ddf0b054,7d182db0,aa48b7be,799e2769,c18268bb,8c16b282,ee7d0828,ef0dc4b7,9767033a,d6de8c63,45285c68) -,S(c41010a7,8dd9dd40,62bfb71c,1691338f,befe03ea,d99eb719,74dce6cf,b2c84112,5008c39d,e71ebc22,3b1c5dbc,f824a63c,f270f807,3143e08d,29b162da,42a2ff83) -,S(e89e807e,6cf4ba27,6586a6,a509bc8f,f786bc5d,dedb5f4a,1b6253cc,2521d311,aadecb79,7c4948de,9379fcfc,4c040029,2228f9c1,c099117a,ad6d9949,f2fea2cc) -,S(363df1b3,be2dbf90,64137919,51218c34,84091f73,866f3fdb,dca1b90f,dcb08577,aefd04e,5634e36c,49621493,f7e76f20,f9ea5b64,6309a605,7e3bdf0f,75848bae) -,S(5c8d1638,83d2824e,48121322,85cc44bb,ca8fe33a,34d5c3be,cd4a3c8b,c78ea16e,f66f91d9,c7ce66c0,89500591,49f7525a,355347df,8f31a685,872aebae,1ac0456f) -,S(10ac6676,83583ed,d837789e,ed9254da,4181dd58,be75dff4,8085e87,eacbe126,6d3eaade,23f3e7bb,7465acb,c6b25af,72e0dba0,1815ea1a,1f57ebe,bb17d22d) -,S(1e79a1ea,7bb65540,44567796,2208ea3e,974c4c0f,9b61f7da,8dba697a,8c153048,b63e3d79,20a34888,68987406,4a8008eb,e07d35be,33a055dd,394ef2a5,f0787fc4) -,S(db0d1c73,97b0a23f,508df2ab,b00ff13e,11699118,11d6476a,7bebcd09,53fa9a5b,1c9d0877,3ca74f1e,d1972431,2b5c8eef,2f85fd41,6629cdc9,d0b9e328,4900dfe8) -,S(e1fdd7b3,481ece8d,266bdc22,92e775bf,96904223,e620f622,3a03ed,cb385f27,3cfab39f,28953ff7,d6dee65,83fdc6a7,d9b31f93,e2103e6d,9e4066a,970a4c77) -,S(96797134,2b69bb8f,3d6701c9,22130c8f,9ed85fe5,bf189880,3b2df11a,a223ffd3,2d43343f,630b6f9f,7c4b6d93,cd29a3e6,632c0dc6,c095794e,5997e47,e631d31) -,S(dfb40218,6e27d494,c69d2a0f,399dd480,ec0a776d,9a99fba8,cba81417,d9c33efc,332d91dc,e9f93273,15e45bcb,79603050,9bd8501c,17820f48,61f7b12b,5d37796e) -,S(6b65c5eb,ed13dca4,51608da7,b5c1a331,171de004,7fbe35e5,189b8468,c27681ec,afd0ee8,e0aebc0b,2f246b51,f6fd4f85,3e71fc4d,f5bb9f43,e2679c8e,89a34f62) -,S(bc1c3da1,60b03965,e26396aa,5d426df3,21e5c22,fdfcd004,80a390f5,28c4b619,fd657174,65e4fea9,ad7862c,422c11b,86ad94cd,35acbbc8,76ed464,aca31640) -,S(589b1d17,96d6ca35,53f8a6a8,cbc587e1,9026406,c2c6f8e2,de613dfa,8c05913a,e655d5ec,ac254f46,e279365d,e3bba2a4,3c7b6469,da45ec87,9742cbae,503fb3e0) -,S(9e726385,6d1e6c2a,94dc2ef5,c92d94bd,6ada63cf,cea75677,6125bf98,78ae4ed5,8c238df5,1e5b38f8,b628a48e,dc7aa2b,a83bc40,43c91896,69f5341,60e304dd) -,S(12269d78,14e0f74f,ba40c551,b2080e00,4f9bd3af,255218d5,7eab5dbd,c6764263,f0f70bd,6584975c,106febcd,bbd16920,daee58c7,c22dda70,4a95f864,e385b3d6) -,S(d3212f2f,cc509014,e0c48cdd,6273effc,5c73fdbf,1676faa3,15e9173b,573088a6,39af39f1,673f51f,362618c8,49c6934c,ff59b6ea,853fafc0,9db64084,4832df82) -,S(c535f72b,9bcc0bad,44014e72,4f649623,4ef288fd,9f42adcc,dae45a20,84250052,3f79985b,6fb7631b,62814a17,f7ce829a,88447302,293000a7,4655c7ee,4a271022) -,S(4f5b7126,9b169fa5,8602bb18,60ed0df7,271e3912,ec0d7c12,1c80fad3,93399605,b60fc104,7f2a58ea,9102c6cd,b97c932a,576f63f2,6204fb5,dbe41363,cdcfd0a7) -,S(cb459b3b,244c38b1,af2c2863,e0029c14,ec70e7d,737a7851,de9c8f1b,b7d5d065,7b67b15d,3c0376c8,2f646241,1e890b3a,a888bd15,692c90ea,53a74a4f,1957fbd0) -,S(787d61c7,ebde0c5,18f121bb,7f434196,d389f563,d1a46597,ea72a1fa,4e19054e,5baf56f2,5fcf8cb8,c271cf39,6b3d150b,f42e9ebb,d72b54ba,4b93bcbe,ae72a658) -,S(c38afc2a,31d0b0c9,4b77d97c,bd639082,3373538a,602352ba,cc93b6eb,c5f6115c,b925dfca,b138fcc2,4b9a26a4,c645f8d5,875e098b,d2e58469,d842688,43ee529f) -,S(37661e3b,8e606e95,b9dc6ad5,e5b9b25f,39a5dd0b,8ab7a82a,d6ec879a,ff406d0a,ab735e5d,430d8fce,1317e07b,d6cf9441,60d8bc39,132382a4,df1b1638,a7e9b977) -,S(e5127851,b8c22b47,c3d8e934,8dc0c677,88ea5ad9,f64e6062,abd68a16,51e256ba,5847f77e,349eb7,90b4b7dc,5537ffa,5b1e7d4d,b87044b3,f947f387,270405c6) -,S(f3c7f45d,a6b8a8a1,3713e7cb,7380fe06,127a3698,520bb41,955647b9,ad7382e9,2acf9a11,eb1b9d31,f71decd0,90093677,4b469301,719d4a51,ddfe5fbd,f63e7c87) -,S(86de4047,e8d5b252,523733a1,848a990a,79125f95,3bb0e4de,ff4b2f0,84d745ba,71e6a472,dac005d,2b284cf7,d5de92d3,56921105,1a9ee007,4279a746,71bc969a) -,S(c6115c30,72259d66,d960cd96,3f3aa16a,3029d9ca,c0c5ec63,5e2875c2,f3f57504,18d690d0,b33fdd78,d797f56c,23c821a1,ced02401,3443c770,50d12850,9f7a712f) -,S(cb545099,8b43473b,91838cbd,76929b05,8bfae0f1,e2bfbc6a,c61d3674,42f53c5b,4119d74d,79e34f08,cd7684b4,f9b9df55,c00ba8ba,7bfb4ddf,de38db78,91572bbf) -,S(d0dce704,b9362bb4,fb1771e2,660a98a2,a333b73,c6d09372,5a752f28,52922d2a,f92c3b70,7947ce0d,f1f3891a,259cc2ee,124d3f54,a4c518ff,de5a3915,96e37e47) -,S(db93e238,e5aa5986,38eab857,655cc53,d4270259,e7d73a96,249a19bf,216b20a4,8d19dc8b,670e8eb6,50b4f60c,d26ef657,3ab17895,c62fc94c,815d7eb5,fbbcc7c5) -,S(c387c37f,d8cebef8,29e07e54,b0796129,4d6c6cfc,bbf11835,ba85d4ef,68c3f486,852580d9,ae7eb300,6ca0f7d7,f12d7fe7,c8e3ae0d,b6258897,994fe78e,11ddeda9) -,S(ebb58d34,f04de551,37c01b5b,192bb4b6,4d3b22dd,23ad9092,f943749c,7606c232,1b979d05,9c99f9d4,db1d3e82,905abc9b,d92ae72c,509c912b,c59488fc,ddd1ae16) -,S(7891cc66,acfda29b,765810b1,730cad13,2f13178a,fbf238d8,2525ce42,96e38e6b,22193729,20188c6c,462987ad,7ecaec3,a21ff6e7,db00adb9,72facf65,367caaf1) -,S(c0b02542,e4bc1e8d,2c2578a5,3793fd8c,acec800,c0a311f4,72c50de3,5814d081,24bdc71,f5917c0,1ae6bb5,71c09197,76b1a884,ebffd673,13698bc1,b57f8371) -,S(ea15d574,b8704507,f12fd9a3,e40ea603,c2000cf4,4eb3d4b2,f07a36b5,c426d2dd,b6596d4f,4d8ca39f,4e0faf58,ab7e3894,c5cdc16c,589a524b,6ca25a51,8a30944e) -,S(77d387df,c35a6af7,b88d5726,a249d34e,70877698,1358c672,6e51b779,cf9604de,e5daeecd,2d70a962,d2d3c235,14fa2b1d,45916506,de017249,93fcd9a4,f08b4a87) -,S(a92742cb,7d1a24fb,c1a4dc2f,9d6fefbb,1064f9d4,c3152db8,3296a9dc,9dccd7ec,665a9cf9,8cdaf0a4,ec346df6,823f3c6,66d4f163,b3e7225a,d9d18e42,31679f76) -,S(253e54f7,9f0c393d,5d34053d,37b55304,f62de9da,29e0eb6f,36cb105f,a6316a46,54e168cd,ed78ec0c,32a9417a,c5b27ef0,67c8577f,8fe0bfd7,b2ae33eb,ce7155e0) -,S(d13048e0,e9c38720,6179586f,9e38029a,55fc01c7,b33d8443,4ee45cc0,3fbf2,7c4466db,94502477,85490689,7b251c39,af257840,b9bc61e3,64075080,84743f37) -,S(e9234110,387c2122,2887d079,7bdbc9aa,a632b237,2a5632c8,8e604653,70a284a2,2b98b08c,4ca3521b,4ffb3afe,66f98ed9,839a2651,f740f63a,e80b0cfb,6f6523c4) -,S(302e03a7,ab6978ef,73891a5a,7bb25764,7428341c,94f8a713,32ba9dad,83a29be5,4abe0adb,210c35be,b2ee850d,2e56bb3f,e8430db,644082ee,a98a2f83,5710120b) -,S(53701389,44400f30,dca0571e,eb0f8c7a,4fea8bdc,31d68859,8d7cd156,11665368,ca345664,39c1f221,a5731bbe,5a9a36e1,a712e2db,f16a6d19,71b1a74f,eaa97cbe) -,S(8c0e8186,645d7cb8,fad2b6f7,a5a2d399,656aaadd,5423cff4,9579529a,f28383cd,2ef275ea,14c44981,9307319d,18fbb482,63c6d24e,c94e18ff,cdcd7757,4c48d27f) -,S(64a70831,26baa3c9,a11615c4,5ff8ca99,adddc512,c697901d,afc43d7a,5fad8af5,ba43c48b,59a65f6a,c3a45c35,4bb17968,148efe4a,288f742c,43253e70,aafe29d5) -,S(fdbd066e,82ff8e24,b2f785e2,e166245f,63559acf,b4f56680,51db47aa,5d438e06,60dadcf,a19ed8c2,376a5d38,28b9499e,875731d5,b2417def,144e2a84,12973d63) -,S(b287ccb8,1ff90731,19ddba01,d9461512,82cf15cf,2dcb3e0a,f1b26f41,eead174f,6ff15339,7a9a0bee,4b38a463,5db66ed2,36d1beab,c0039bd1,acfbdc09,fb74e090) -,S(18047a48,b65234a4,fa5f2188,8b3032fb,3b3f8457,1bdec3c,962d5cd7,fd068116,13627669,18198832,306c5444,6cea5681,80134209,101a117b,1f34e15a,624574b) -,S(f1d3b54f,be4e2ce5,88a2dd32,8a41e136,6b74ffe9,5bd4aaae,ce7e7a8,235f914,37c25d41,300e817e,b4ae1471,e8486232,c0c21165,97efe33b,e86d6277,a8a3981a) -,S(9b0da9e9,5046dfab,7ff509a6,10ad56d,9770da36,c5e22a83,9ce3a36d,853bec4a,27d60345,30c25a36,e80bbc3f,f43829cf,df757c19,1a2924d9,6da77503,38135faa) -,S(d0833bd9,5155d18b,be55d40,3717568e,2d3e4d24,f2eb65f9,f13d8d65,d899c5cc,e509aec3,b5044ab5,11fb1e4c,56db7146,ffeefb82,ec4e9de1,3c473bc9,964741e8) -,S(8c41627c,185f17e4,28a01b40,27980e6b,ed62ad62,17c9f8a6,26c329e2,2fc37117,75ca226c,3316a552,37e8a1e7,483f73ee,a36da441,c732dca7,7d95b7b9,3a3662f7) -,S(371f0105,e43aaa30,5cc7099e,9a13b97c,2d75c26e,5b50b11e,7cc6283b,27728d27,c969dbe7,d0976d68,8cc64312,4538ead,b1194426,cedf149b,293b80c,6ab3ce99) -,S(5102f59a,4238a358,f8b4d3a1,85d864c2,d94aeb83,7a8f3e03,541ffbdc,2ccb1710,9e14c4f9,adb63c3f,4cd30606,cd41cabd,bbffdc3,89e996ce,91522093,85ef1445) -,S(ca21b6c,fd40403c,78353c7,836162f0,a7f57eaf,bd4a8cc2,6df2baa7,1ff08beb,108a3c46,47eba55b,3fd9f2ef,751edb0f,d6b68482,1424bffe,e6ae3e58,1f7f12f9) -,S(d9cd44b3,ff40d19c,e8368bc8,200e3dc9,7ec3642c,acc40769,7c94e68a,31d775d9,b6b6fb6c,683ef701,d4cf7101,79de4af,fd7c4a1b,5babf3cb,85c95eb,485f0901) -,S(9a1354b2,cbcb6888,bb564426,71bd4904,510da508,3fcc61e1,4fbdf44,15a10360,3f5f5291,707c48b4,4da3a2a8,93e24037,bc4927f3,81dd9b9b,710e8b82,874f953a) -,S(c5e55e0f,271a81c4,ae7deb0b,ceb0fdbe,20fc60c5,38692941,bd50ab9d,ad0fdf79,138a0f35,eab49301,7a53e7c,c62ae93a,85ed9e7d,708a00ae,cb10776f,fdc83a63) -,S(5ebc2f64,7f66bd3d,2290e4dc,6cc5f662,7c67ea72,599d2c6,9a004aed,9060f919,68f7dbce,df2085e2,27cf7920,65369637,3ec1e860,b10c8f1e,56e996d6,854659c) -,S(4f28eb9c,7d060dd0,5051a5a7,9a79c960,161d7081,d3a58b2d,a421075c,cf966e03,ec378861,5434741,bb2aeb8e,4a2afe78,44849f3d,2cf12a6c,2eff3e05,d267fafc) -,S(f50e20d1,ce113e09,850c7a9a,10b347c9,9fa039ee,57ec85c0,efe15b4a,1a83fe8f,4db7c231,90df41a2,8218595f,61407f20,cee46478,27d54aa9,4db9bfc3,fae975be) -,S(cce6b2d0,1adeab95,dd78cdf2,b55882bc,79de945c,d4249e76,ab2841a3,abeff5ef,1d690674,1312140a,fdf764bb,560b1bd5,bab1dbaf,9fa26bd5,604427e5,34626e52) -,S(55a65174,fb10557d,2ecc7312,15afcec1,e4830be5,2d34bbbf,bc80ed6e,9f2d8475,c69795f1,de1e537a,970dd412,65493806,3f0623d4,e7353eec,611c8917,278012c0) -,S(78221cfa,7b4db3dc,7e22779e,97ac8d46,d0c1d819,76594ab0,267ed28a,6127f290,8ddcd5ed,fd8e8c62,4883a158,2eab5652,ace0660c,2e358b66,3ad53e90,cbc46a54) -,S(9b985039,441ee434,ed4da39d,6010782c,9006cce2,8f92ff96,2b2d6fa,986ed178,e1cf85c8,7b537b2b,78bf67d2,2d9388c2,8a50dae1,73f003bb,85fe5f9c,12c6cfa4) -,S(9aa2ffb1,4a9e48de,57db9d78,d9b6757a,6c27e7b0,291dc4f3,8ae9f204,f7edf20,771c7be3,78e0f794,fe0066ef,8592952d,8f80d7d5,2772ca11,5ff8b7f6,377d1040) -,S(d1059083,66a0b463,17c510cb,40922a0c,949de251,6d80ec02,1e359a89,c6937e1f,84053a25,c9ea4414,a897155c,c45e0da,e5e6f2f,aec780ac,99c41545,fac8630e) -,S(1f3ecacf,7456984a,fedc2d81,2a81f7f,1ac58ad9,c70ba7c2,3e7a2ff1,f9c5d066,c6add8fa,2bfd24f1,73f4539e,f21681f8,15f1f362,e0f98d94,cd435d80,71a23e54) -,S(a312c709,a16d0cad,25551ece,86c8f947,5e504d06,eb3524fe,569cdca0,da2c4371,865ecc2a,ea04c5da,2089ea2c,66b5bb84,8c1fc29,ac7bf969,c778039,b3ae7b03) -,S(f21c4675,e829ba78,fbcf6410,9c2eed38,8c3493db,1017d69d,953f32f6,744197af,fd2c673e,43377caf,5db0ee06,1a37b03d,43d9373,482d3ef2,b37f74ad,98b2f57) -,S(116174ea,2a029a02,fbcb2eb6,1851ab31,f4836933,a73bd426,8feed7c0,18865692,2123d027,e1cead9d,b5fca2a2,d6f5d1d5,25cf3855,44b64352,ee772d4d,d70aaefd) -,S(358e77d0,919e4c6c,f64a2117,357e72d6,2334fcd0,f5e7e60a,962335fa,73f9d663,7ef8d620,6f99f403,10781985,988ac7cf,dcf5cdaf,a086a0cb,8b5b6eb6,7837bc08) -,S(509f7e0d,9e81f146,39157e20,3165faac,8056deb3,a813460d,b86c6daa,baa33fa9,55148e1a,340eb6c4,e6a8645f,93f1ad3b,fd12165f,c3bff090,a095b8d2,a0db6ea9) -,S(358e325c,185f0e26,1e9e30c4,9346f21c,a15c95bd,438020b9,ad9c7e6a,d2a4ed09,5fcc074,c97715b2,812ef690,3b3d6185,54aa11bd,34789b3d,97f9b65f,2d18c4b8) -,S(1e1c712d,bc00af2d,37f37e4e,a2589e02,e314c310,47890d26,8d36be3,dda2fc4c,4898f9a,e3136bbe,36798cf5,ad30b38b,974e7e75,42d4c14,5bfb1f6a,490655dc) -,S(a6516f9a,aa3f79b0,ff3b794d,c80a9590,64e31720,7361b918,bd797b57,23ffcd1d,c5934c6b,59f3b830,53f77b07,47c7c312,812373dc,ebdbcf9b,ed550300,3a54f5d4) -,S(e46b48d8,8b1e1b84,b9fab824,3044469,50cb5633,da599b79,295011b8,b1098155,43e9ba24,4a339976,e342e551,25974350,3e7c8a80,cd950a80,a5d79365,b0c94f51) -,S(ca7a5099,97a9c2e0,625105b,1df9e714,e1cc2d40,1227400,e583370d,3f65aa0b,dd8ca4e4,d2eecd1a,20d994fc,ef7cb0ef,19c61844,cd2ce039,b7a1eafe,66e1f071) -,S(326b5ec0,d29b576f,111352d4,b7786c40,8486599e,ec01ed0d,a390d586,96313f08,f4a3f171,a4ac654b,e7aa6063,3d5b2a0d,c2d5d3a0,3da4d264,95e828a8,1011d384) -,S(b762982,54f5c75a,a557038d,bfe9bad9,7c5bf8ee,e512fe2b,39293228,e70d306d,8b808f9f,b36e3e86,2c75bb2d,d7de8be,cc85c75,398496fb,f92db3db,143606c5) -,S(8bd624e1,2b1d36ff,dde50a09,6f1a811b,ae66f1a5,790654f5,ef79a21b,872286ca,6687ea2e,f4538961,b6731c74,744234af,8bf6a2a2,170544d0,fe9b8057,ad1f02df) -,S(ed25eac7,2a9f9290,bd414cc,cf846c65,509d1c33,d5573da4,2d78d25d,5de48a9,556fa9ed,2710fd03,b6d1583c,682cd7bd,8705a9d0,1f73a8b9,8f3a1eb5,d89eaa) -,S(f1943b6c,9ed76a84,9c67bc94,c755fb30,e8facc1,de280060,df4b9e7,8bc02bf,98c7ba08,85dc4e0f,6acbb646,42cb876f,a3156232,df1f84b0,4818ca56,882a40a7) -,S(c5b60b14,2de3ab8f,b0c24276,dcedae7b,83422821,6ac8ef39,1d351832,a5e9e5d3,ce86e4da,1174e609,f55e10d9,14d4a5e,33259578,e07c1260,e912acdf,9eb5cd69) -,S(b06638e,706cfe63,3359647b,253f99e1,c7778200,c168d4f5,92e2c409,493755ab,e6401fab,1b4d5229,136e2493,39f95357,e16dd37b,87e7f69d,3e88a383,cb44bbd5) -,S(cef8c1b5,486dacfd,29650ea5,432fa563,f0ec5fe4,6814bcd8,9f539b7d,264b14cf,80cc2c1,8d0b0be3,939ea,761d7281,5ed4fd2a,b252d66c,9316aac1,1a5a2fcf) -,S(f616904d,f868f2a1,5fcdccac,4198b1c1,62defb40,269754f3,8e546da2,4b85d7ce,fb971012,344024c9,f0bb93e0,b73b31cf,de8b4d37,aaeae3e4,7f62633a,7b8255b3) -,S(97386144,bc7e4a7b,33a51697,902fef4d,1613d8e5,ed80a599,a59f62c3,f98632e3,bd12d584,58429939,2dd834a9,5431af27,8e56065,ba79bb6a,5a806d36,cfc16b4) -,S(946f130c,7a70fa00,f403a56f,6656b279,1eb08ddc,561311b,551ce437,bb0200c8,acd698f6,a5037e60,7f5a923f,3af05784,186d9794,a7bf7105,7a66949,e1945b8d) -,S(ee0cf184,72c453b0,c38c064,fc0d2589,d5f1afc3,3423687d,91740bdc,c3929230,d817775a,7fecd397,e954db12,fca24990,8c773c28,b36e991f,79c78264,9fff8dc8) -,S(f335f7fe,9542a587,9d48b4f,4ab1287f,ef007289,4d93bc21,23463a77,7d535d7b,336e49a3,2465d29,35389c06,d8eafb4d,7639dae9,a6b19bf7,45518502,e3350283) -,S(55bf8179,4fb37f8d,dcc200d7,b76a9040,b1326d6c,559d7f06,f0eb0e0f,c97e7739,ca33cf00,79155cc1,e902ade6,f7d703ed,3053f6a4,f49d0866,32e930a2,afe69bfc) -,S(dffccf81,6143da46,5ee2195f,abb6d943,1033b901,2fe0c623,49b7d6f6,29de29b0,9bfdf3f6,e1dc4ae7,dc29fc06,f85e1588,c04bc39d,5fded90b,bfe75b9c,74f0aff7) -,S(b9748c94,25fc6fa2,fe5c1395,b556bb12,c435bc11,2e8f577f,3c5e7d82,3539dec3,f5238bb2,b995d23b,5e96b233,6d5141ec,f76d31bc,63aa96e3,dfaca8a8,c94007a2) -,S(92c43c54,e951b157,38f29e33,5f52ad9a,2c5349e5,fa6a39a3,fb615878,ae97f7ca,7c7a6b73,dedd1bca,308924fc,6364b62a,bdc4ae79,d68a62bf,71bb0195,612b4a17) -,S(b1937ea,25995e55,ee1ef139,d7a58923,5677afe9,f4726d96,40b66b0,d21eb272,d0f95a57,544ac7cf,e6c3e0ca,5e44494c,5585c503,a8ea9919,5a993180,cf043dd6) -,S(2c1cd64d,bd7ee24b,2bc5a6b7,2009b788,e2a5047a,8d10dfc9,4a46d807,c133f457,fe8a63df,ce7d7a4b,e7c31a1f,5e68826,7a9449fa,9e9ce30c,fd8684b7,660aabe3) -,S(4ff10a78,be6ea8a2,b6830649,b0a403d6,6d544368,6cc854ed,447f53fc,45004834,b3cb30c3,56d50596,2e81cf5b,f4e2db0d,e43384d7,28f5d8bd,b362d287,e58765d8) -,S(33f55b66,6c90665a,b60a7c2a,c714591,f877e8c8,517344d,9da03558,f43d28de,399848ab,6aa95ed5,8ae0ea80,c93931a2,af146754,385edce0,8c2a4f64,2d5163f6) -,S(b9712359,5a7237eb,18b7cc15,ff2d6be,408da66d,5885a636,20887ab,340d3e04,a283a3bd,643ac5a4,1b3f0ab8,fc693146,dd125f88,fa87cead,817788b3,be72363a) -,S(d20f9067,6efa9435,f602c1e9,fff7338f,5a4204a5,4d984dcc,f0ba5fc1,60a1035b,ac3a3c7a,452003f8,7244406c,ea315175,ca1af26f,6645486f,3faae77b,8f404139) -,S(322d6ea3,157c9f0d,444b2d0b,d072e192,81d8b3e0,3ee2ef5,4e294b53,fef41f2d,838147f1,9dc12dde,676a9e67,6a638c42,6e096df6,ea62ba97,ec359b4d,f92936b3) -,S(95925c08,68341b6,b7564ea7,bae00b0d,1d2bfacb,94aae4cf,8f29ed9e,fa0c26d5,c63edb9,13152232,c255557b,2207c2ec,edf14cfc,bdd246d0,2b46f7f8,76b92130) -,S(7592aab5,d43618dd,a13fba71,e3993cd7,517a712d,3da49664,c06ee1bd,3d1f70af,554ee877,af74284d,5ac0aef1,ccfa8ab2,7a9222ae,977a1b45,7d79d386,16eaa410) -,S(ed9d298b,e13eb71f,8631ad31,1b391680,8062574a,6053f503,671d9a59,1209e0eb,97a9abc0,dab8886d,9a07caa3,f40d87d,7b479efc,d500eb6f,e54ba1b8,9d85c3cb) -,S(cdfef636,a5900bc3,bd28daf3,308d469b,78ae69a2,ffc39fcb,9f8e4942,fa355fad,f8338fcc,54c0ef4e,a46a1c25,591607aa,f4f6c7c5,378f2d51,79f80e46,520db6d7) -,S(f638cf22,ca3bd6a,ca7a8fc4,26d9f5db,dbc0943d,6a587584,8ca52e6a,7949db49,56a267dd,8309eab7,90b49003,9d595141,653a7926,9fd1f732,f3691e0a,41675295) -,S(4340fef2,9b1e43f5,3c76cab,163920b3,7a66163a,bc942e1e,6387a2b1,8f14bd1c,2d5a782d,6889d353,c6c908f0,b6f7a9dd,59ff2f15,8bbb9eb6,ad62bc2b,832210a0) -,S(78af8680,5e3db13,cd2c01f,beeb826c,1aa83296,c6ed1a30,bf2822f1,a9b80991,19c7ca36,37a6ce91,2680d95b,6b94f835,ec458cdd,86206a2a,49d41af6,248c3725) -,S(d87e590f,e6a4bef7,54a831c0,13b3d561,72064279,38b96d49,58a2ae11,c9c41ef4,3928a93a,c9b43489,f1fff97f,f8ed4ebf,53b97aa1,b50896b3,e30b40b9,be1d1dc6) -,S(b59d19f3,69c547e9,4155cfd0,a0b9076e,85ea8569,195b8a7f,630a8446,ddc54c32,b8f5588a,ffe7abe0,e2b83d55,28162c5f,2d50827e,c44a4357,f81ff085,da661865) -,S(34f643da,7cd59b00,3aa64cd,81c143ab,662726bd,5eaf543a,6d83d30c,60f3ee78,41574cf2,91a7f573,5a0bd29b,3ee5a36,91906c1e,3fa47b22,d5204446,f4501ee8) -,S(56ef37d0,583e9de4,33f78757,dc31c968,fd007bf5,6b05db4e,cac395d6,233dbbf3,a140e01a,b5c898f9,10ae2807,53ba14ea,ba8cb5df,b9e9629a,92c14b9a,df5c9286) -,S(1e43f34,815b568b,1139ca5c,b3a5dd42,fc54dd76,78454fc8,7e3dd00a,edc957d7,5cc38274,ac96ee20,78a82d9e,64dc2bdc,8e947afa,d043302c,85d724f7,7e334cc8) -,S(ce79e49,35d2db7c,d9a9046d,3d81b7dd,f8b06c82,98f78eab,ad93062f,c339a952,fc2f6eee,1b90626a,5ad8c494,3bc3cf5b,8765c8f5,fdc05dc7,fffa08a1,b84f9686) -,S(b4144804,ca862c26,70cc3365,e1a00cf8,f6766cc3,4b3dce2c,76c40c31,86fe4fd9,e4368a1f,ca9b6e00,a3f752f0,3a00fd4,29cbdaab,5e2a04b8,7175b9ad,51b2219c) -,S(eaa29724,7406f824,8e79cf65,ced49d39,5416341e,c1bc46a7,b71d422,1f4fd39f,68e7f81b,e3b75cc3,de4d9932,85e21842,d0d4b6cf,38a1d46,248dd28b,a97c14a6) -,S(4e2d10ff,1f7288bc,3b8c6caa,3dcbfc72,eb7371c9,f42c6999,e7a2ec50,30f5b6a5,68da3c5c,df2a4fb0,a93515ca,3e417d00,6ba793f5,eb678f82,be88200f,a5a8774) -,S(834f21e1,114dec96,2a8a4b45,c67c2894,7d073b94,457c1adc,e009dda2,230659f1,e9fa61b6,edb5a0a0,2f7acb27,d04a67c3,39263adb,6320ca6e,f78ac7fb,25adc89c) -,S(a84b44ac,a0a64455,a97268d7,cd3d68fd,c43caed9,f9bdc381,ece7139e,30c7d0c7,2f903f3b,74e702bb,d2fbde43,f919af7b,d1267879,3882cd6d,a05af259,bbf6b74) -,S(21219e06,98bcb977,47b1df66,f9e0fa6e,600cbe7c,bb432cbd,d413481f,241d6789,7a4388d3,c8961874,a897d968,8b5d3266,2e6970be,324bb736,aefd1892,70954055) -,S(fa514e1f,93bfccf6,88b4bbdb,e4f49879,7b946549,82a27562,6867b22f,9baeafd4,ccd48215,52572b4a,9e087b51,8c930e09,2c2f6156,c26a730a,478f257d,a4f91b74) -,S(b60afbf1,643099f0,c0533a4a,99bd8c2d,2204d4f5,3f2fdffa,4cafa02c,79451ffb,fed8f90,1a029926,cd4b3bd2,76bda6e9,d321e006,3eef3f43,886eef8b,4b21294b) -,S(f29cf9a3,196ce34a,86efcca6,554694e8,17c2b765,39c6cdef,c74850e8,a7ed76cd,5130863a,f7c333cf,b37f1bf6,2db5bacc,994b2977,9951e8f6,2471129f,88c9c5f7) -,S(9cd9e23a,cb00bfc5,1a3af34b,3e23f1d,d8fe314a,322254ed,563b9275,c5084e4d,ecf0235c,c66ea710,151d6c1a,17b31705,4f31bd4c,f8d2a77d,4d36fc4e,1298e1d5) -,S(56f889b0,2cfa048a,f96d99a6,be56a282,18ed6691,ab2b25bf,f3d3b6f5,f6e5d65c,352b20ea,4a2372af,f674f824,8dc8fca1,bb8ecc29,ea0c8d92,1b7ea07b,241fe4bc) -,S(de32beb7,f8fad8fc,16d69a7d,d3def556,8e2366e5,246bfdea,16c936ab,5dff2a08,d731f11c,93a71c22,46c2bd06,fe265fab,eaa216cc,b0de1acb,a7c004d4,249e145f) -,S(85ec7dc1,dc1729d8,c03dfa58,fefaacdb,7d12dc3a,f984a693,968895e,2a6ba256,523038af,8e9aabcb,f98c73b5,afba31dd,89e4b9f2,ba1a841b,194b0b45,9a4a747c) -,S(f7948995,60528ec1,ed7f5efe,42db8bf6,e223280e,2b26d4ab,e23a5caf,41e2e141,9f7594e2,96ed1f98,86837e9f,da8d6d9e,58871e56,16cdd2fc,dd6fcb7b,80c6ff98) -,S(588d6fd3,b4208825,3d76e8ee,f01a93be,866bd53a,e228c137,62199ce0,f3454f10,a5fc9653,3e41208b,ba3f29ad,e31b7e32,6320b81,ad0ded2c,6d922a4b,b42af573) -,S(186fe08d,bbe5c8a7,56f87d4e,8976777b,b01db294,e834659c,bf423de,1ccc7443,d99ded39,a46f7820,3437a93a,435fd0ca,29f12e26,a6449bdc,a256f99e,9bdfbdc0) -,S(e549cb08,3055abf3,3b7eac38,cee13336,2af22e98,2f576bb,5a06d5de,59bd3d25,cdf37f20,e7b51483,6641c7f7,afc35ae5,5ababde4,34a945fd,4fe0325c,7d332381) -,S(a4e42afb,fd7f5158,5c86108f,cfe84b58,b930df79,f53a86e1,8ac93389,224422b,e9f8e1b,3963102,b58d6177,f915d7ac,541e551c,bbea3e2f,1ea47960,ce1e30) -,S(5f7ed844,42022f42,6b09e9cf,b7750fa4,4755fba9,7199fd4e,d09efdca,d803dadb,91d5ded,d06a8eb0,9c9592fc,c9096f1c,e852d9c3,9bfcdadd,ccbe1bdd,2b76ffad) -,S(3fac4743,32f064e1,b33fa22,3f67bd15,91dcf7f9,afa38f1,868e180e,c2938d66,45744e67,6b203799,3386d10a,b11730bb,eebf270f,9ea65920,6f93da61,e2aabe5c) -,S(5fb983ff,f058d214,2e4d13df,97d8e784,d4b10e0f,6a18c6b1,90e64bdf,fb7a7aa9,33394601,8dc540cd,eb73f73,a9733d74,ec581181,8a6d58e8,3460f1a6,8ddabd6f) -,S(baf35c3,fa939a2,db15eec1,ab083664,9c6e941e,19d3e0e0,43e0f5e6,df41f88a,42583cd3,e53fa1bc,4eebdc3f,e3b8b069,9de41445,54fed966,214108d2,f68e9201) -,S(97641f5a,a51e7ff0,f1d86183,a3fb3d60,4266c4d9,acdb9f9a,c704a05,809a8602,134ffa32,aa9fbdbe,d8d82fc9,1cfa78f,1ab169fd,459da39b,5b0d3287,ad9517dd) -,S(96a3711e,acdaf6dc,5adaa8fb,4be05c37,f59febca,1a876a5e,e23c6b55,2727292e,8fb0cfb9,681ebb7b,5e1fce0e,67ad5d81,34be9123,56100e96,b82ecd3f,a5da4392) -,S(ae64428b,8e540c6d,28d38892,6136320a,9f9f16b0,3e9d5e2a,14faadef,4f154b0a,db202e5e,b9bf73cd,b9ed5193,b0ff59e7,cc68aded,6fe6c2e4,d5b79493,fc118aeb) -,S(2c5932df,65c0c2c1,14b532cf,15b48433,e16424ff,ba87438d,42229075,6cc984fb,161ef8c4,b908a056,d395deec,38b9ff4d,1c643628,2ceb1e47,f59a2c24,c7d29130) -,S(76e21c78,6937ba69,18252d56,3ebfcbfe,2415389d,bc692071,f9c48f55,7aecca3e,de7786fe,9db47d61,e3b61d0d,49309fe9,ca634d28,8d71aa77,a3fa4efd,4533c8e6) -,S(7170dcef,ca8a138d,1d20b346,6afc6a46,99df363,fc964a36,eaa70805,b267900f,196bfd39,476f1455,98f89f7b,f870f8f8,440562e4,623fb203,3b36d5d,d8c0bb8d) -,S(98eddeb0,75bdd245,aa1fb466,ed1e89f7,61a95662,e35836f2,e6907c5b,691b6ccd,af3fb5f6,b59124b8,c9c2ddc2,108a3a2c,bdbcdc99,ab296814,731a841f,570c91be) -,S(bf42f806,59ae606f,a5e36fc5,c58379c1,8dd1c34e,fa98e67,68bf6da8,ba8e8849,d343fb70,6e4adb94,46f49578,26bae8c4,ca74a0d1,21cee98f,26be68f8,7555b8af) -,S(40c1c4a5,891e8dc6,29075c36,56249fc2,c42fd65c,8c338a0,d82df955,4662e1cd,667223d0,e68ef6c3,7195d819,2bcc12b3,f2025327,3a05703a,e5aa10e9,cc689ec3) -,S(162dd310,c8e3fe4,8384cf1b,1a0a2d6f,bfd3ef3c,5492fc92,b921133e,8f883dc1,1f2311d5,c82f02b9,f7197685,cf490e1c,3d0ebf4e,86ea0e21,a653c8e0,db5cff0) -,S(ff0f8146,89eaae3c,f3f302e5,1089ec58,5d63c4fd,5157bb3d,bdfc7e40,cc6331cb,4dc1fdb9,4eb529e3,bae54973,778d1daa,f8814cdf,5a3b0c2d,ac2b5647,551bf2e) -,S(143ae674,b011b557,2f472b22,44c6d9ab,14b3e641,54f4a033,c3ea3917,4607b78e,1528d582,faefba2,6018820c,a03dfd7,ca20298a,e199c99f,db9cb421,3601c35c) -,S(f3adce28,8fffd45f,96fa0efd,32974d98,4115a80e,cd6b86f3,5e17b017,8d9009a3,20202f00,96329bb0,69a0915e,494a586b,805580a4,eabd4ba7,2d20665b,4916a20e) -,S(d2270829,e2730d0e,2c8e6bc6,fa4c2247,4904ad22,f44fb2f8,5ad07558,c4d8cccf,d5a6b4ac,9d5bf669,5989741d,f262e412,27c66c7a,ae067a93,c6302f5e,8879a3bc) -,S(26d17eb6,7d9bf2a8,45c57a94,82bb2f3d,8347538a,65c9f567,56ecadf4,352964a6,954af3d4,7d67c345,bcfc4a52,a49aa70,b8703d1a,fcd21c6b,7f7719c1,e2068fb2) -,S(e4437f8b,e104c899,5cd1618c,e5ee7d10,36a52d99,31346476,bf68f21,e7fac74b,d6c156d5,b8256e6c,1a820dbe,3b56fc8c,f9b015bd,b81c756e,27b70db8,d995cb81) -,S(8932e04e,96db6079,662b63ed,29b5a39d,ac5bb51c,d1ec70,851474ef,a2d3c1d4,5437e77f,e030225d,53f5166,8c3551c9,fc912a0d,a3bd336e,c0587544,77e58541) -,S(fe776976,465b86c0,5b2003c7,36c8141c,933ed0e4,5c6dfd0,c7c82517,16617b26,b279dc5f,d576d506,d302b0af,359ddd50,94364d3e,255102aa,472e6d9c,c52aac39) -,S(6c60a4ff,b2a29224,5c84ecbe,1633817d,f69eb73c,a6b9f72c,b86fc91c,535b45f1,278dee6f,814bcc1c,70301a51,f9c7853,6489af2b,d23d6223,1b55cd29,2a2a0a2c) -,S(3132e58f,625f902a,98d556c5,ec9e8617,a955beb4,6e9c2a81,e121e473,9c9af04d,a5880964,a2443c5e,14db9220,446904c5,cf0a957c,945c5006,9438d869,45a9e461) -,S(b05cee36,361a9bf6,eb9003fd,c8d38587,640e180a,9de822dc,57e5012e,34903f6f,fb473886,29519a28,b745ce16,d625d85d,26fe21a2,30d798c5,305d8e82,545c9a5a) -,S(e202120f,5659e580,7a14e68d,e3aad7cc,23cd2f6c,abd86739,3a05f16,12005e83,49928b05,b66af992,d937cb4d,c05fbaf2,a70e8fac,7c081544,849d55e,fada136) -,S(57a91d89,2e5409e0,b07e68f0,450614cb,9a9bf0cd,8c5b3459,2f198633,c7a796b,47905cce,59018fa8,baa612c3,124b1192,1dbf7706,c5d8d16b,bd5c1e9f,8498e7fc) -,S(e092c40a,3ba465c2,d59e7c5,8265ddde,91c0468d,67428ee1,dd153b64,a5a7e8da,83f4e2b4,bdfc4248,2d4ab1d3,13b097f7,baa51411,134eb042,feb26f71,5bffd39b) -,S(73a3306e,7baa4fc4,a081a9c2,c335d3df,7c1ee84f,f5a46554,f78a6009,1de0ab38,1f68c8f9,2022c326,e37a7043,9552191a,3d93f684,3af0a235,bce893d,eda1f938) -,S(7c7a79f8,6e904961,73552caf,4a1401db,e99883c5,a39e493a,6a6eabbe,5f3a4434,85ceb252,e4883931,96c8ce8a,c0b596cc,a2670981,2c293554,15e17f8e,26e869bb) -,S(6a9df561,ce4ff772,b37054fa,e513657f,19f03086,eda93918,623a1c47,84a37788,bcf0274a,d9b3bf58,331ba398,a6611fed,fe719867,106eadb4,2b25b623,fdb65280) -,S(fe7bb24d,47b3adff,1c545d2d,ad2c6aff,81934cb5,bf2299ee,f3f8c53b,ff91c950,7fe65f86,9d2623c,930c27d6,f0a292cf,a881738b,4af0c5b,efde5c40,8a574e7f) -,S(26d1d2f2,7944b77c,290ba60e,17d05347,82ce2b64,ae815453,1da42907,30407d3d,ec3c5024,3106000b,d0b2372,53581384,51b768d1,d5aa206f,4d1055b4,b4f0f495) -,S(f00e51f9,38f91573,4ac563ff,8ea44de3,fb85cf4d,8f034806,e6c096d,8e73e2b8,7b7bffed,3a39a491,d3ab6a13,6fd88e0a,5854081d,21380c70,3c596771,a22c727b) -,S(73e15472,f42f8750,93abe811,a4d4bca8,8bd179d1,4e3e3b30,9e011e27,37cfc4d8,392ef4ae,58321768,1106426c,9b00b4a9,c53c826b,84bcda34,b5d0609,f85b9231) -,S(ed4667a9,aff30464,c851d86e,479df8e4,d29d2348,edaf8333,a7faf560,a9568092,77367875,6892d42d,469a9ab5,ff577e0,6d9f4fda,679882e4,3dadc7e6,3d49bb0c) -,S(d6ec16ab,10811cbd,dcc346a2,64dbfe0f,51066f2c,79034d74,af5b0ef2,541dde26,981f1cab,7ac7be22,9a91b733,6c0b89bf,4763b01e,4a1b715e,f4857e9e,4ad0527e) -,S(284ef47e,691931ac,8241d92d,2ee5b717,3f762ef2,bd1f48e6,8dca4b53,ab4c593f,ab739ee1,e6a7be47,83e1288,7ffe1b6b,b53a4d2e,3bfad3e1,c7ac5415,1bcf5e82) -,S(530f9e7,5a267d0a,fc3ba53a,c49018ef,44b490bc,835774f6,c6cc3f87,8d505c3,630c481e,44e5e9cb,cf6d7fba,8f7fded4,bee9fa70,4b88a8d3,6e2b3bc3,4e85e3f1) -,S(66a9b4fd,81d0165b,6737a4b3,8025d2da,ef9c4d20,3c49a2bc,1ba4d59c,eaa905f8,2770c44e,6a4dead9,7dd7311c,195d3051,12c86bca,257955f1,21b7b1cd,4e525e8c) -,S(25812e7e,dca47b64,9b18d739,7474de25,39bb7898,96ddb94f,60192135,23a289be,4bba3d83,72aa76e,6ba76f7f,18cb8644,788d3ab8,b58d0e5c,795c6213,6f17e2da) -,S(3c81be70,af162448,170f88b5,8fbf587e,df1a0e8a,3576cfd7,24acba77,dfb29608,ab16e48e,da59f480,7a0b5250,7102e9ba,ed9dc9fa,e0de8700,27bd5ff4,2aee13d4) -,S(ab626dcd,a5142933,ece82c8d,125aada8,39626e90,85c57525,2fb24f76,e0d6e39d,8add774b,34fa4b1b,d571f2a3,4d8ebfc2,bb7be73d,dab73cf,e7eedc01,764abff6) -,S(47f25106,120720ff,8cad6532,1a3e2873,aaaaed57,98e3933d,e1ccfe0b,f36bd85d,f6d472e,729512e4,ecb74ea3,f96583ac,cb44e013,ecd0bc60,c38b16f9,20585b60) -,S(6fd30299,f7398f1b,3c538d59,71b8bb0,e1640926,752d0842,36148b9f,23c26b1b,3b8d6166,a79ce235,1a2e9c4d,c5c89ff5,7810bef0,277f3d33,372e05bb,ba6799da) -,S(dd5b07c,784e1cd6,58c51ab7,45c4a09d,49db1287,dd7871e3,f449bd66,4a02e040,b26dad8a,62a491b8,dcced2a7,c0feed9b,6a04597c,d8a0f857,a4731078,d68d8659) -,S(3cf5836,104b4227,aa275e5f,16b84bca,15b61a8a,700b56b7,dff2adf2,167fcdad,1cc6f65a,2cb579fd,f6812340,88018dc9,445af726,2db43b5c,e9e49e4a,ce00c9fb) -,S(683b5455,8b9421c,c3aea163,d74c043d,d4cd804d,23857f41,3e01d28d,4919bb58,1bbe4576,2cd5c056,8add6943,8111cfed,691e2369,55022da,17cfddbe,79a11f0a) -,S(d78661b7,897a40dc,5f42f7ec,4202ae53,e83ff0e0,d73ce7d2,19503279,e43b724c,465299b0,e3f478ec,fc3db82a,61d5f290,aeead2fe,d0ec4a02,6652b29d,cad20b21) -,S(1258c664,fc15e794,e64dbb87,b4eebf1b,32e89e7d,50ec114a,1afa5506,19e15a21,327c4a92,81a73880,70d1a7de,c2a0e5c7,28c5997,bbc21571,94b0521a,141be0b1) -,S(f2d04fb5,1cffe2bd,c6e43cdf,ae7314c5,387f4dd2,4bf7fbb1,a6ccd627,86e8be00,89af3f8d,435f2152,8d32ee47,a86a2ae1,78d3a7da,c27ceb37,93250a8c,27061c9e) -,S(b67bbec1,4ab23ad8,e52cc402,def0083b,d21551a1,92a9df6b,b335481e,3f0dfb08,d6ca6bd1,93838993,5284528,56587554,3757cc13,fee01fe6,698b30f8,10a64a23) -,S(1baef1b9,fa401fd6,a053ce90,f2d661b8,8a466584,83a8489d,90d48312,2b79235e,28a19a14,a2f7817d,922b3872,cba558ad,bc1a69c6,c0b65ee8,3352494,a31699d7) -,S(6c0f066b,23623a48,b2b6a746,801baa85,f58de56c,e5287c79,c3c10ff1,b851aa8e,ec837256,84cb0f8,e528bd94,e1c86327,2347a479,2059f357,4ccdbb93,15ff0868) -,S(fbd5bb09,65bb9d22,bea6d6cb,7aebcf28,a0c815d6,18b79c0d,94913dd9,f63619d7,3303574d,5e605e5b,fe298f77,e20f3f6c,60ccc063,37a29c7e,6612dfca,3f00b924) -,S(2246042a,c4b22334,af6c81ac,8106bd1a,f8bd5f2,8dad88fe,7e568fa0,b35b1739,1da0d8eb,9c10116f,ce29bd9,61f92e36,9e538282,345a4f79,7cdabc70,5aff6e7c) -,S(470a914f,2fff2d37,835b3caf,542cf50b,9606cf6d,fd294c51,5632d9f3,4182bc4a,6b3805a8,d2c74856,a5be3cc9,e9c6a8eb,4398c606,81ce12db,b3a58660,1d426e) -,S(4e03f50b,ffb6d933,4282153b,a3f909d0,44bb7a11,50300c1e,cc8027b0,321b4be0,596c58ae,963e71ec,f1fe8f9c,b4de8cbc,9149b125,31e83e0,95f6e5a,b08c504c) -,S(5a6c4fea,b806bb76,191567e9,139dde28,188a26b4,a1803b7,d999278,fc57455e,6e81d07c,6505366b,c28ea476,a718e5f7,353d73c4,2f551459,d59a7d7,82e6ce49) -,S(ed73c9b2,9adf52e2,1280bb1b,ef63dd4d,74f4e09d,1be56c3,a246dc37,9b29bd5f,e9917b6,19ebe0ac,c7d1fa5b,7c4b7c52,e272ad9f,2df62161,59dc87b3,f913828b) -,S(68c6145b,38cbf9ed,4af10608,503ca13f,710dd34c,2386fa99,bdf93b69,c01c04bd,c963585e,607d9eac,5016f884,df535a9e,e7cb74d2,2e0c1e9d,e928d7ca,3fedc73a) -,S(1b651863,927317bc,1dc6094c,3f5c91cc,92269a12,59879b6,a8439a77,b0454126,31c6125f,8ac3d09b,d8c1fe92,c31bf13,c42b1915,e7147cf9,1371dc01,e8f5009f) -,S(45593ccc,dadbde3d,456b74f7,a3b705de,7229ff20,90a0df0d,38166d4e,6a09c52c,13d6657d,89fd0205,3c2b9a31,1ee964cd,e14634dd,20d85866,a43a4ea9,bc0bd737) -,S(1409c06e,d6f2fa2f,cd532983,d28c2109,e4dd7c1a,4ce77960,566d3eb4,37927da5,dc05f98d,4206fdba,e3b69836,e694b71e,fbeda304,537bc623,90edcad1,460984e4) -,S(d9e08c6b,c307b056,d4323921,5426febe,5d6e5cc8,4eb73707,4e2f00dc,e85f4580,a23c1647,c6b47a43,a3ab52ad,da32605d,172f4de4,201834f9,15d5a4b6,292c632d) -,S(7df319f3,d3c2b6b7,3533a916,64d5fa26,5ac0f18b,bbd5e8ee,1aa15dba,bd62fb32,9120f6af,e023bb98,1d6d8d96,31de0814,a9bd169b,a91af0b7,9c3db58d,2bc9f8c0) -,S(1a94e587,38b9fd1f,93146232,e2165798,11d74244,9bad3711,a373445,6986d7a5,332a27b3,17eee7ae,fb4604b,197f2db2,fc32549,ad86765a,74820428,abe4352e) -,S(dfa2cb4d,6db266db,2a82ef8d,fc0cf871,4aefff41,895ff691,fa0781f9,1b619a47,c5e5dbab,3a28a6c1,8cf20fef,4cba62f9,d2a1a0f7,6ea7056e,45acfe4c,49ad8b19) -,S(c2201007,be6bf76b,5e82c135,2a6e053b,acf4e2eb,c10a417b,f35e4c79,3a876730,92408aec,b9ae4d74,3af97c15,9c387343,9a735de8,90d1abe7,c8d14dd,fbefa581) -,S(d45632d2,ab087f0f,9d0d4d85,26730742,2f25c794,efa3815e,33e8285a,1bd7edc3,b7ce3697,c4994fa8,2479e99f,9c9e4b1d,814e7258,da7ba569,5543d6ef,8d5ff44f) -,S(8cef362b,cdc292b4,885f34ca,923a171a,df6c25b8,f6b7cded,c9003b71,cf5df93f,b3910f34,ed8b7fa2,bfa4f1c1,9d41d99a,d702e13b,5dab6bdf,2608186d,d09aaf5e) -,S(247f7be1,874c2831,17d60431,8184878d,3a415ae5,59595bfc,7f17583b,3cbf9838,90e235e6,a779b4fc,f9521da,65f65091,efd513e8,df338464,2f8a7cc8,f1f30eb8) -,S(b8c0cef1,c8703adf,411dd0b0,acaa2b82,f2609348,e36aac56,b0148ad8,981cf568,a0419411,47019aa1,4b8e74a8,1d49a97b,45e7aaa4,54c0f916,a33472ae,1275f14) -,S(8e55776e,6e1c791,2aa6b43a,4dd1bd17,a35ab0d,aad792c0,ab51bd86,8208cf09,dfe4ccc3,a025abbf,c2d12bc,6d462e6a,cec7307f,6daa9c01,2c8a7ad8,70822d56) -,S(f1cf6d3,fc9d9824,4e122790,de390241,db813b70,c48b667c,5f05846a,c3ad1ad,4925c6ab,3952d1b2,35ef1ec7,7ae7a84d,75006993,b173a6f6,c8b969af,c3984799) -,S(b49dbf88,dce5ee49,2b4495ab,9db762c3,81164147,cacbc00a,9e56670a,edb9ea31,c0f92f17,ab5797c7,758d703e,fd288a46,8971f7c2,de8923fe,b8b7acfa,ffa9ef2a) -,S(d6afe2ad,257b57ed,15573c50,a25f7dcc,399e2643,9e64acab,9a8c9f75,d8ca362,5df236b8,6919b56b,17140249,16282b11,38d355a3,561c5b42,b47ac6f3,8d35749d) -,S(bb0284c5,f23365fa,5972a439,fcee4b4b,45b48a9e,6844a44b,53e12004,1ae8e89f,684bcc0d,e09e5932,79018fb2,aed55329,53221dca,6f14f493,6ae76099,ba265300) -,S(57e95714,8a409697,1b8be621,98a04177,c4779627,ab5a77e4,6e82d847,e64467ec,714bd1b1,14ce2580,7c6d3a8,f12a5375,fd8e7cd2,5e854c12,6bb519f2,cd443f13) -,S(b0c82f60,b33c3b47,523ef2a3,de804521,a1e14478,eb637757,d17526d9,1e713094,cfc8d1b9,d763f52e,6522f70a,c93f7fd9,23d163d6,5a82b2ee,ac1af994,a2cea63c) -,S(2ba76170,404785bd,5932c185,c6d98ed0,667d8324,ff7f85a3,5c24a4bd,553e1ee3,1810790,74262af5,607167d6,b55164d1,e56aef19,f3e2f307,205d5603,eeea35b9) -,S(5bd54e13,d508b920,fb1d15c8,27e0ca59,3eb1c85,a7228895,b5c9235c,6ed3e88c,d65d35fd,5607e193,ea70ab1e,4ac7d822,878017ac,ef3bd6fc,2b1933af,660cf0c9) -,S(b0bbc2d2,753bd89a,b2bf1664,e6cf212c,a590d65f,5664e694,7ccdf977,3ea8d09a,9057b6c1,a1078bab,a1419065,4cc67052,7225741,1f34d47e,47f09bdc,8f993c23) -,S(c1701203,3cca38ac,ddc0fe41,95452129,b38b4630,20e8c459,224e9dc6,cd3133a8,c495d87b,1cfb6f67,46c07188,86c08616,624f78b5,ebf4fb14,fb6b636a,f5557e9a) -,S(1e0bd20e,5f1e49ff,32287961,7fbc28c4,7c9fa4dd,d93532ea,74930a24,5fa21bda,2d407400,e98f15d,e5da681b,2472fa11,b2a5869c,66be1cd5,7038e160,43dd6177) -,S(5cfc223f,ec4c6618,ff12a974,8533a70,f39defa3,bc05f88b,3a1b158,317ec15f,7d928bd4,89e3719e,6386ec22,6c738b09,eb4468f7,b6718cf9,3da33544,aff21411) -,S(f506560a,bebd668e,57e514e,bad47a84,5da345ce,50ac0e88,1cccc2c,81efa67d,e2ff0bf7,c9c2a99a,bc3580ad,17f64a26,63111fd8,15bdcd63,9d9a7d3a,ca0fc7e9) -,S(8448fe98,ec887485,45a46e4c,449d0168,1d00dcae,5bf96ef8,306e7bd8,26c54f45,d0f07229,17500322,2dda8271,33481376,85b20045,f69d656a,66aeedab,ea6f0407) -,S(c9a6857f,db037c2e,36d5ca71,32942f34,2480cf28,a98644f5,6bc455ba,97cffc55,a69e08b9,8f678e61,6c0b8326,ced6f97d,f742d974,b68cd1c6,b798e367,8faa149f) -,S(b5d13f5,c611eb3b,c82f7db2,d89ab19f,b8fc286d,8e4699d5,3dc664d,bac4011d,27eb1650,7cdc0fdf,5b92493f,f2487d0a,ef2692d8,9c702bb6,259808b1,324b7adc) -,S(bf9ec5f3,2e0ed4ac,c001b887,18c29c6e,90218471,d7f1afad,75abb34e,da35ce44,13846488,892b4065,b79224ed,368c47a4,a1734f68,7386546b,dd837a80,467ef2d1) -,S(2c3812be,4d3b1c13,aed1f6bd,1ca6f5b8,893c5a87,ad6a8f2e,d6d92ac1,3a526e19,366b82f1,45d551e0,b7bcf877,db340bcb,1b11edad,1466baf3,24a94cef,3433aece) -,S(77bdef28,dc8ef6c8,7fcd0a13,c08a26e5,9fd17253,8d8bd3a6,f21c5c86,ca33f572,da66b0c7,bf3bd49b,ec1fec,aa580a51,6977ba8a,83f957ef,8167f69,ea3c3a1b) -,S(bc4a799d,3185877b,cd86503e,3f34c606,8693bac0,654eeb15,4effd116,8b71afe5,53fcd7f8,99a8190e,a7159c99,e261525b,f59abf6b,d331be66,4f7f7757,7255569e) -,S(301fd884,733dce05,6190e4c7,d0375078,6fccdb6f,2e13f9dc,e275c188,2efcd040,79e4f9d5,185b9f51,fd835cef,64be607c,312c910c,e25cb73,5de2c88a,51e25cb6) -,S(241b4a9b,be5e7e54,214d0bda,13719c42,133f8377,e50db2f3,87b6018a,814adb70,c66edc08,fa4fd22e,1f76bca2,7fcc00cb,a8ce2100,248b3959,3c164847,b410bdb0) -,S(be6f1639,68191289,3c5c1351,d633d51d,dcd28c16,f3294981,56ea1602,d8c79585,6f674a7e,1a65539e,a7f8a966,8f5fe5e6,1ade5da0,a543335a,5f7a71e5,fbafff21) -,S(c8b5008f,79c69e2a,7e209ef6,a2d14b9,b3f7bfba,b7fcb285,e237cb31,3dd3a283,1dc79348,6c3cf7e0,bc36dd7,46efcb36,3cea15ca,a63008f5,2d83ec0a,6bb54bb9) -,S(5014af9e,aad5ed62,4e997ec3,a796ad1e,b038edac,77cf27d4,eeda7ff4,c06c0998,e01d786f,b8faa1c5,2d44a77a,987b4b6d,91143953,34977151,1a488602,3189dd7d) -,S(6ffefde6,2c40643e,da2d4f28,4f28fcdd,b0845ec0,8d882d2b,45dadd8c,a7bb989a,8e2b183c,782d3a9e,2229e4bd,9a2becbd,ff0a5480,6a6f4471,7fb6fe5c,8411cc0e) -,S(ac762bbf,190e1374,d32a7e5d,b4c0c36,ad0140f,c1e92290,4aaff1f1,487d463f,ccd79f18,31016b40,a381bfec,5db6b12f,bc34d850,ed81aa7e,435a513e,5f3adefe) -,S(973496d6,3ec05c75,93244e7,b737b1db,d791a5cd,e828f342,7968eae0,e811cb24,4b2c9bc0,44e3351,f637ff52,5c3f34f3,d7420b65,2f57bb7a,bf573e67,25647533) -,S(a9d89166,5f77bc30,74357753,9ea39e36,c39ce300,6fa03429,1a799b34,84a15d32,d09c3a17,fdedb8fc,f4f9ce98,20635a50,56dd884f,ccfaa96b,8d0813b8,4b80e213) -,S(108a8ffd,aa2b544d,8b8a7419,f2421bae,cbab636f,60d6ef76,9eca9a20,a0c5710b,ad3e9fc,ab04ad58,a265776a,75f0e389,cebbb273,9df328d7,b125665c,d4e0249d) -,S(ef969d7b,c8843c57,bfc0ac6d,f5e4495f,9543878d,95120a36,de8c5bed,727c5fb5,5ab81bb2,26738036,b145d81a,1deaada5,d1d4d653,7b80b02a,fc1cf85c,361f16fb) -,S(ab825bc2,4d505453,f12dafb2,8f70b245,d74200f2,410f5162,b0ba3096,43c39b62,789e7df2,23774415,da7e31da,277a81c9,708098b8,d455594c,6f9cb065,b1281a1d) -,S(4984a4e5,2c173c02,ec79198c,f8496972,eeed4e39,9933bac0,59856bb0,48bf2622,4596b67b,79be2e61,a0887a9c,2cc3ccf6,f199e924,3991f434,8e7cf897,acc5df3f) -,S(285c6ff4,93c1be13,f4f60d0d,8aa7cb24,4bf0f76a,23f3efbc,cfa4a132,625f7272,39dfe9a5,cf9cef28,d5cfd998,49db9b23,c4caace5,e8a27c12,12d7b3d9,d3ed49d3) -,S(1e14b1d1,7e721971,e9266717,13100aa9,9bc6e506,c278ac7b,348b708f,843db340,63a239d,d705f627,347fe464,c4d4143c,394d7dfc,5f79ea11,64d05f04,4ce41cee) -,S(b8f73b9,ed71cd1e,f61dcf30,9cd48587,3b1394c0,4cf318fc,10140bb5,be17c8aa,8af5dae0,bd66ec85,2ff4823a,a1be65ed,745676a,5ac42ec5,827107e6,776f665c) -,S(7e0c7297,e878fcf6,cb636776,d15afd0,49c995d3,1cd49d15,e624bf6e,8714540a,df5795f7,4c512043,f48b7568,bb271a00,ffd59530,a0280e5,8aaaf0fd,aeddd658) -,S(9f0ed1d,465bed9f,a2b51133,fcddfe48,10999011,b754acba,de5fd027,6b798545,7005ec9c,73bb0e00,64badde0,12aa99d9,d85b6c38,e63256e9,21799990,14a8459f) -,S(2d556f5e,b5c5af0,160608d,80e23cef,cc8e4000,b1e35b12,5a0a51aa,9c8e12bf,7600144,25bc3baf,1dc7f6fc,1fd86f41,d24d4488,f80ab8a9,4e4422ca,15f12000) -,S(2617667d,7637e02c,b479524,d9c7dcc1,2cc14ce5,4149928e,e8d81bcc,835ed3f2,521573ba,2cd809eb,8f5496be,478ca639,7a2c4e16,1b299ba,bc6ae419,4780884b) -,S(6247916c,5b519a64,7b76e10f,8810a3f3,4cae40cf,ed05a492,ba1b061f,d9aac10,ffd02570,535ba978,906a193c,500da1d4,602b0969,c3e9f4ca,f2d33026,eee7f098) -,S(c40b27e0,8ed50a88,60017e78,ececfb9,ea14c64a,95137db4,fa55d4cf,9a3c52af,2415cb8c,7d025b84,fd9d1e97,7105aa54,c4149fb8,30ea801b,a86f1acd,e07b6493) -,S(ba5aec8a,54a3a56f,cd1bf17b,ceba9c4f,ad7103ab,f0666974,8b66578d,3e0de12,348dab11,abecc4bf,3c7474d2,8ea5ba60,a705de60,39f9b70d,c49d58b0,6d57ffbd) -,S(ba14e658,f8dd294e,1331262c,ffb3f31a,c1e9e504,e55c7f67,5c002248,94076268,ced74905,fc43e55e,c70cb36c,66dd9a10,c221b0e3,a326e365,9b96de4a,c81aa1dd) -,S(3375af69,8880c7fa,29e718cb,4139ab30,f9c1d00e,a1c22d4,cfbdfa16,a7f4aff4,cfa8b491,a83be5b1,b66fa0b8,5e26c68e,8d27db79,ce55d726,ddde67ee,ce295a27) -,S(68d2614b,306cfdfa,e9fa109a,2c4b276f,5b9a8ee2,f7d502d5,efc94aa4,bd9f01fe,148c36bc,f04365ed,7ddf54e8,4d40fb59,ef9e1d48,8408c8f3,661386c8,5f48550e) -,S(93facea5,597703b0,ad2990d7,1d63387b,900ece6b,6c3677b,7fc47b7f,1c533edd,3c801bfa,8fa114e8,b5c19985,39a1f6c1,c20bbe44,d8ee7179,7454797c,942ad5f4) -,S(f11dd4a6,72f73118,95775ae1,76c90b2a,5a0a61f1,6ca205d6,eef6c275,75054277,bc06a16d,2ef2ac0f,7ea2083c,ac18d0d0,6c307d45,51e0a0e8,3f59b568,b9556ef6) -,S(42ebcc5d,710ba454,fd29a94e,f83c8004,b71fe85,9725c010,f10ca39c,864204f7,f8aa84eb,643101ed,4c7d5cdb,271d067c,e633c17c,dc698e40,279064d2,d65f223b) -,S(d40877dc,d96d5a94,87b6fbc,e89d19a0,549e96da,13f1fb2e,67e9e3e1,85c80e52,be9bb9b3,85f20fcb,8e57b59a,ffc01442,c0be8306,f5d9087c,837e234c,5e789444) -,S(c18b2c98,cd2110ab,888ec934,239240a7,aa40c1bb,ab8d7e39,8fa74358,2562931f,d9621034,9147d74c,75df18cd,1066c40b,b83f189c,937c01cb,24c2ce97,155773f8) -,S(154d6b22,1a44f841,1cf4fa0c,4bb4debf,6fe94658,c648f9e4,d14f88e3,e05c0bd1,df0bc307,c705332f,328bbb6a,dd94e63f,7c1074f3,ebc55976,de552a59,5875559a) -,S(a38259e5,629f93b1,a397d228,59842dbc,24485d59,c3ab86e0,a9326a35,e1a26f15,69b5accc,2fe52a63,b3874932,e8a79b8c,1713274f,f435d892,367bb9ea,91f783fb) -,S(9d729eee,e91e3493,9925a7d5,2eeded18,14827029,6f822013,d4db2a3c,763fcd19,6d832154,3cc8621,166f731f,2d874fb0,9cadc09e,4e330339,657aa2f0,e3e89a1f) -,S(2674f008,86307c7e,576cede7,944a9f9b,46398c93,8a0f8b39,b25701b3,67751e3a,3e9eb42,6ac9d1ef,837638d0,7b0f1f4e,e31bdec7,a9d22fa2,12a666b8,193f83cf) -,S(b2a06d5e,adb1b856,dd28e9fd,bb626c0f,b7c1642c,6f70c2c2,743f3451,4e237f41,5d4caf8b,8673b268,227baed4,481ad60b,de579a98,4d005f5f,f3bcead6,3bf664d3) -,S(20b27d64,d61debdc,ec3e4ec9,2040f05d,2b278c0f,1415ba60,f0bf23e1,222d713d,481d85e7,ff5c2df3,5cd26488,6056750e,c8c5c809,bb3afffb,41e447b7,a4e516a3) -,S(4f4a610c,450eaa25,f60d7c15,20c551f7,5270930f,45a7c51b,fc7cd5c5,3ce3f2e5,df1e8e11,db416228,672d8d8e,f9d68ed,e824234e,fd7de39c,2b32fd90,3a47f328) -,S(9b375ed8,504358,25570b4b,e359bc07,bc06c989,14659e9e,776fba36,a8aceaa9,3d056593,385c0069,915de5b1,f59c3483,22683440,86dcdf26,d1e6ae22,35e90927) -,S(43640804,5d432c87,31f865e7,2390b7ff,c13aff87,37fcfba4,60c0192,2ec9d1be,e2338eaf,6fc73fe1,e3df2aac,54bb4fbe,5aff2a92,5b8b16eb,2346b220,6070cbeb) -,S(a6e59c4f,24461172,4161f35c,fbe88d4e,59287f2e,f2b9ea39,4c476127,f41e0b66,75c70747,f5dd75f9,41cfa470,c4cf718a,57a8ae2b,2e7ab277,5f5ec5fe,7d9f334d) -,S(ff639617,ae7351fd,977bf1e8,46a6d33a,5293a959,74b296ed,7c9a007b,25322d51,e6123dab,fa2355f7,653f81ff,ee798353,e21dca71,ef40639f,79d73116,53dac457) -,S(77914840,1710d8e6,8a37cbc,5ad5e284,c254dfee,1c8b043,5f8ddbe9,4ef4faf3,d97f44e9,9ef3d4c7,4075dc3,894d2a6a,623be446,32c98eca,a54b8ed8,e0611414) -,S(f68910aa,29254aa,10551c00,adc135c4,947cf1fc,6dd8ee5,d42579fb,79484aad,40bdfbdb,33a56d63,ad587ea,fc9784de,69f9f5c4,3f5c7c94,1b9b59e4,c052c1fc) -,S(15be8f81,473d4cef,719c7501,1d560d84,f2d4d8d2,def1d696,29f62464,1b6e0fd3,7e66f926,fc991b41,c451ead0,6d93267,64b85ea8,849047bb,1d28eeee,70fd9a2a) -,S(e113d5a,2e22302e,f4327297,7c41c8b,d0c5c26f,9a0bd9db,9091abdd,8a84e9ca,2e4862d8,34c6dc45,17a6b70b,2f1b2c5b,b54941d1,cb803530,26a257ca,f5574dc0) -,S(96b10770,485bba67,7f620d9d,ec0d1be2,2c94dab0,57d6d595,aa78dfe7,47bea688,e060aaae,222726a,c1a1bd58,fc779d9a,ff854ac2,4a4996a5,2259e9f1,bbdbf30b) -,S(81742f00,5555954e,17e5e899,d2cfd8c,57f6f7c7,5a38e183,de878934,2405545d,a1763fc2,e5f705f2,e6f2fbb0,73578fb0,a8d742c6,8f92236e,df1ee03d,2ed2fc0e) -,S(17c19f13,96988f62,77cb72ea,f90d37bb,86bc7a0b,e16c1c17,fcc481ff,bb78a480,cb1290d5,210164eb,621c2642,ae3e51b9,3f430e60,718f9fd9,c5ec3bb6,53c78833) -,S(7b0f06,e8746ec9,c6648b2b,bb861548,bfeee507,63c01c3f,40319beb,a2497a3c,c6949378,84297d8e,308b318f,1caa0c7b,1634b758,9d6e8c6a,2fdb778e,d6a70020) -,S(715c2b06,2414183f,9a67d8c2,8a89b754,55a80517,cb1b8134,5f56e91,12c5e8b3,f89b89c8,9a795dc7,1e2d4cca,7f84b4d5,23167f03,97787b33,9205773f,2520370b) -,S(e0d0ce00,f974fc78,76777662,efe5dbf5,57aed09,dd89a4c7,8f1f40dc,8f74d3b6,acc5be65,ed704847,94bc7f05,c4c5511f,c253befe,7cb3c0d3,e85704e2,e3e3eb56) -,S(37553289,76fbb8b7,9a5aaf75,ecd9d2a1,bdba9a87,5bad6222,e770ab1f,d26432a2,6dbbe233,1b7e064b,d80bc7d0,12b2a088,1087e7c,2c5c1d77,eb016108,c2ced92d) -,S(2e95c3ef,51ea9036,8683f6b0,8b2afb04,f46ca651,2abdc699,446ab3a0,6fe3d3ff,905ea87,b1d8dfe0,48463b94,c61dbc62,1556c66,b2b498,39cb40c3,299b554a) -,S(25310e1e,721f3245,7f35c67f,b73553f6,6467580d,b5916cf4,fe7d75a,c4ff8eb5,9c5e52f9,be42eeb5,425a359b,87dcab1d,46ecd662,c17eb041,16b5430,786b4ace) -,S(25932b1b,2b24fc2d,d7877911,7d7cb506,27a23b7d,7faf53b0,cf707f51,b7830b7b,7e8e23b4,acdb26b0,1d7969a6,ddf3a2ae,2215e206,109cf3e,4e32d91,df536765) -,S(7d232af6,251f7667,ba69ba44,397f5b8a,892e135e,b09b684e,22b16a44,73c5ed3e,a3e8f638,c8a589b5,8cfdea61,d9824f1c,131b9045,9509b92c,1cd26571,a6d8356e) -,S(4d56caa0,1b65ea87,ba3e05b0,a4495606,6afc8645,4847633,cb9e9755,c8c720f9,14c34678,36e65197,ca3f1ada,936f0348,7c1eaee1,977ae08f,50f41771,77537330) -,S(71abd165,ca6ff8bb,775c81f4,2c722ed7,2615b503,3727dc2c,122efbd9,c500a88b,79ba2467,7284f86,2fb1c46a,e11ac4b9,a5969352,64224eb9,c39ab884,492620f1) -,S(8462fccc,c3810519,cc449634,5c5d9e56,30215e74,c41179f4,2002e906,56a48965,535a966,cd7fb998,bc548a7e,29fc4640,f0eb75a7,5c3c05cb,64d09048,a7787d4b) -,S(f68eac93,fed751d0,b578b5c,665684a8,b9c2b104,6fe45ae3,286e9351,36c09826,98e0c32b,98b0a8a2,8f119ff2,fa50e54b,66f7d8d5,732a1831,7334fc45,fd48bff5) -,S(61447250,9a8d935,9c0e4014,f6ff569a,43467dc7,e4940b16,15f442b2,d9f72041,fb7177f,c7f57ee7,deea7108,dfbea888,fa58f209,2aeb2d2e,b2f33141,7ac8f807) -,S(ea69ee11,4ffa1bd2,e2259a26,e2d88cf1,c9846ac9,379a1497,fc28ecc5,4b15614f,589b81b5,1dd6d750,91014108,3dd6cf3d,63183d1b,809b62c9,b17b768c,5ce4e2de) -,S(34727b24,3404de96,641a1ce0,d7ff150b,38e6aa15,c51fab78,1464c660,4e5d5263,9198326b,cf56ca77,35b9baad,dc0069d3,1920bff2,d5bbf804,435289d4,d827d4f2) -,S(952452ae,613778dc,29e2d275,6e98b4f0,eeebf4d9,526cead9,52f8d0d9,9e217461,c08b3a28,c195fb5a,f9a50eb1,1b1411b,c17f6582,dc14b5ff,797175b,2ad486a8) -,S(fbca3f18,dc4a8bc7,7e9afeba,66610306,401b8342,bde2dbfd,2d4a156a,e78e49ff,2b829d6d,6027b2de,eda0db7b,c76b924f,4cf75573,bb9329b6,c7b7e443,f94129c9) -,S(c7ddf11d,7ddc643a,957dff64,a08a4a70,5302bfff,b940882b,57bc4c15,5bd8c141,e9ca11f1,ac93b018,3fe8146,839be79b,b3711ee1,8a3daa88,89d55669,6e708e20) -,S(71043a30,86e3063e,b831f7e4,4e682181,1b3f2353,9cb6efa2,cd0ee4a6,70ce31b8,4db3f338,ef9fd273,4aa9cc92,55e2984d,9334c164,5320b411,ebcb7cb4,89322c9d) -,S(6de4ea40,15347cbb,d9349d36,80fa375c,5d70f044,799134c3,dbb6a776,48602585,3b76588,65ab52db,eea8d839,47025cf2,458a3243,38c73d70,f1d77df2,7f960418) -,S(29faa79f,467cecb7,ea17e23b,6f7ba03d,db9a0cc0,e1fa6215,bc425696,ba4fecbe,e5aa691f,c42fbc29,c1f027d0,46bdf106,64a2245e,d2ff1154,e50ffa1b,48f34838) -,S(ff880bfc,25ae5b22,78e5f15a,2bf8f5b,d750f8b8,74910f79,c8c42f93,16aafc99,9535f70a,728f79,37825bd8,1bb502db,60e7a166,bc8a0b10,5eeeee82,3a5747df) -,S(b781b6a0,3837f6f5,8520c566,352e8c09,60eff0b2,42524eee,f6a6bd2f,a4a2a378,acd7b7d4,6c683dd9,43722ee7,3c12b69d,cbf8389e,62755e4f,c44fffbf,4cdbbb62) -,S(6d976593,e8bac5d0,da732c64,82e4ac2b,b3f19062,59045990,ee540a3b,467406db,30c353e4,af6d8161,6c0bb9c0,f2a4aaed,6cbc1825,9a8b9658,3bd7e9c1,2f2a8b6b) -,S(18ed676a,4dd3e0db,46212112,9fad1e13,683ec782,2a6d9401,5d0866bd,6cdc3032,c86b06e1,5dbfa82a,5f7b9762,65e03670,6f9a6e7,7ee319bb,8ef26b16,a51bd5) -,S(3138e38,e9440ffc,c2cbce4d,aefd4b8d,d1e859d3,b951d18c,eb3540ca,db5ce2a1,df8ab1b2,a11a8667,dd660a13,490c6e6f,fef4bc40,94efa9a3,430e28c9,6895c241) -,S(757df4ac,2025c9aa,b8ab1e76,149a9762,163ce608,f4903c3a,91571cf,e8b00c95,ff0af5fe,ab36c5d8,47d15ab7,65000765,c56bd7cb,4d0fd8c4,a37d4ecc,dfa03430) -,S(8a697a52,7156589b,d13319a0,81e3b2f2,ce09de8,450b95cc,9aa70409,884c27e1,9eeb93c,b6029e9e,37f2815a,d332d5d9,5a5edde6,bbf03ca1,3df09f86,ad51f39d) -,S(b0bb6987,36f9e0b1,6cfc2198,e37a84d5,d35eb89b,d4f4c0b1,650d60e3,e58c721b,33d5b200,ce25b501,6f09808f,b38e82d,b855615,2f48c1eb,b3b6363b,ed6e00dc) -,S(1ca0edde,5dde4634,2637882a,d2f8ff7,ef6d6f5e,906ae2d8,d9f1b545,c837efed,19efb5ae,4cff683d,a7d5d4c0,f5eb9f3e,4c4d3a4f,ac58ee41,acb9ebda,a82863bc) -,S(780e5b0e,b9a4e57d,66a84931,1e1b765,d59ad11a,de4e921e,d90fc422,4d474aa7,5ebd9ccc,58cc5f21,2da579f4,c79aa3a4,1d8f34ff,418516a3,d339320c,133ab811) -,S(f7e92ce9,39808505,2d2af620,cdf210a7,30ec079a,54bf1468,edf686da,34eb4c9d,2c559dcf,e113a961,58fd54c0,32f14ada,57c23496,7a88b585,7b1f7ab9,78f93666) -,S(3c3afa20,75bb20a7,8f9ff809,20d80d61,3a5688a4,269336f5,4bc7da5c,4a89f938,7ef38308,1dd235d6,e563a9f5,46435f22,3bd836d9,3f1d132b,978f3f9c,7b888c8d) -,S(71d6f01d,ee60f9b5,75dec59e,7e56123,89fb9edc,3019115,af4fb155,f22097ee,e1ccc245,4a31a35c,52854091,fb414321,38da4fd2,eaf1680,2ef0470e,1c80bfee) -,S(9726660f,5705ec80,908a77b2,8e6257de,b107fc31,c58ab6ea,1f5f75b9,38c4fa2d,94cc07ae,3102d1e9,6118c213,b6db0c65,d3636fe7,8ea40c6,90c86949,b48cd4c1) -,S(ace5d0c7,54b2a1af,691a1a2,97e8b632,297fad12,ec1fc4b8,7fd02ac2,b2802719,924f9f24,8d3e725c,eba491f0,5f188d6a,7fc843ca,d24d0858,1f4c9485,8b9f85eb) -,S(fa51306b,34800ff0,ccd778f2,838a4a2a,8200eafd,622e98b8,8fa566b3,85943f64,b60ee616,6b144873,a1cee030,fc92b50d,4b67757,ad34d5c8,5f05c871,4296e293) -,S(85df9018,329d25a6,79c097ee,458eafcc,b716a59,611730f1,7c19d584,2dbea60a,c555d5b6,46d211c,e99ad7c0,9e787774,b7bc64c6,f2f6980a,e62e8911,897ab0fa) -,S(2f77c00d,c2024467,ab461b52,ae634a99,337ff5f4,780637f3,efb989ce,24af5e3a,c7f4a678,ebcbfabd,870c52b0,be7efba6,c5d28e7,aef2b253,3f0e7fa,905e3e39) -,S(52d8a23a,720050d6,ff6a499,7b802bf5,1f238df5,b0ef6001,58fc48c2,228bb34e,98ae81a7,861b8e1a,162d29b5,1c30c786,cebb1812,c91780f2,ccd302db,803d9136) -,S(a7f3e479,eaca0049,22fb8320,47555b5c,701daf22,407462fd,37b0edb1,7212b211,80f6190c,8c4ca7c1,7ba68498,d1bac039,3e33767c,c476fae8,e926500b,9fbdaada) -,S(31ef3150,e67bd326,61bbf4d7,942382af,73db5799,8f4880,ea04607c,a2356103,7db8f5d6,655d28d1,93b50bb5,14b16ed5,bc03c46a,e3d2c954,631834b1,a8a9a8ee) -,S(ee82f155,469c0299,39ad1ee3,52edea30,599b0cd3,868131fc,eabee245,3b8b058d,fd0c0d4e,2d77c2c4,2add9ed6,cadb898c,32de9398,f0394400,eed2ff30,5092b10c) -,S(dec7c7a,bfcedd6f,a9f7d45,8a071575,27354990,b456873e,206d1f7e,556b4586,af841ab4,cad597f4,186f0912,b79fe320,2c7626c7,b85cb276,73c18010,747200c4) -,S(c28e3370,48cd6fe9,7591ba40,5519bd80,2bf34f12,ee48762e,526b34d1,f4d2369d,e00abdd,da456731,7f486dba,6976ba13,b8640f52,39325a64,7d50eb17,f0636e8b) -,S(47157ca9,2c275f65,c29e9d,b0f23531,37027731,1cf05a93,7145123,df222195,648b17fa,c911fd25,af87e9ed,441cc874,9fefeb72,b34f8dc4,f430e0ce,89cbef6e) -,S(84d11702,745c53ce,d81b5503,79ff1947,9a0a9253,a7ab3868,f5471a64,6ca73241,4f16b6a2,c3c087a,4efb1353,644e64cd,fc593ec1,d8d656b6,2c0e0bc2,25f858c5) -,S(3bba3022,196060b8,6b2b2f28,ea8811c7,c74e8128,8e91adcc,b7fbe2d7,97d63fc9,7f34054a,f0945373,a77c5aa1,2ea4f54c,879d3f98,b6e7ef3a,9d73d2a2,a734e286) -,S(85637f4,7a2c6143,2437485a,b3d40e70,b9f74606,aa8538f4,425e8a06,98651c6b,bc6a95d5,6fb42b1e,67b07576,83a5036,f76e8531,a30d0096,c3500ad9,93396054) -,S(25302e98,5e75019a,21ed1605,dd3c543e,e8021a42,a40a967d,8ea6ed31,4dbbd123,849ccbe0,23097591,d46f9b4b,a13713f9,c0220639,11fdd0f3,267a4d8e,66797a83) -,S(e59a30bf,88e393e3,c08d73da,ba720ae3,485fde0f,b6b85f8e,4117f5e4,f43bea40,6fd7824f,e222cb37,1a0fa6bd,33e4bf83,83ebbb64,87872fb4,42284498,6197dfd5) -,S(c5902df6,97981a60,589e9bc3,b935de2e,de05331d,2c1365bd,a83f8183,f6247e4e,c67eb14f,5af551ef,1ab5ecb5,8feb7ce1,21d0736e,b93dac91,f865ac7d,2d75fe3c) -,S(df8bdac7,fe27127e,c679a9b4,74e3c809,b8b6409c,2e6c4c1b,277ab4e6,d5e66ad,3ff26fe4,9f0b3896,54d802ed,72eb4708,2738256f,c0266dc7,645b1027,717d43e1) -,S(1d55404e,9c7cb8ca,c39c7c02,b810d5f0,9eff9125,9166cf3,f1e8cf76,2c65a82c,c1787023,f6a1c8a3,5c499f64,a2fc4d23,e5a760ea,9a04707,c24bb9bd,b2a7632f) -,S(35f390c9,b035fdfb,68506073,d585e450,2d040e96,67a1b4ef,804ee088,df43b44,6a85cd88,86aad8b7,7dc36fec,50eb9754,4c3cad2a,da43d038,3c55da38,bff512a2) -,S(fbb0840d,ee888fa6,f26d7005,b2449cfd,1d22786e,d43d06d5,88f744c4,c5e059b0,6460514f,d89a70f2,3a4ffa21,9f651bae,203b05f4,bd3d45a6,508d2b25,cdb8d3bf) -,S(24056cf0,1c2275dc,44608ac4,66931e91,61fa0ae1,3353cac9,ce481271,a34d78d7,43ebd3c6,7e7381d1,bf03088f,434a5275,965a3fa0,d86a51bf,7dda1b63,cbc7751f) -,S(3b1043df,e8447c78,8e07c938,cd72f6b3,54f9f745,d7e71297,e7791972,70f9cd78,28e028c4,abf0d511,126c29d4,b2b185c7,b67ba361,e16c50c,34af129a,5e40d6fc) -,S(aef909d1,41793638,80d75b23,6635805c,8088b08f,5c577a81,a5bedd20,69a040e6,cbb4c6f,de26b6c,5d0c2b43,df40a3fa,93350cc0,1c497382,d8a1bb7c,8600dc51) -,S(c8d494f7,386331cb,6ff59aef,5f229bc7,913367b8,10f407ac,2c9f9d3,ca833f28,cb2c76f9,4b6285d4,d39afdac,bd3ef114,c7b85027,8d62da67,e70aa74b,b10de4d2) -,S(25afcff7,af14ca32,3dc74443,71de7b5f,c1b52e17,6fe5f3f5,f4f39139,34f75b28,d867a4a4,7f9d7e97,6cb1f57f,8d505a66,5010cdfb,4af4b781,75271722,6942b789) -,S(2436c86,f773930d,872c220d,c8bd72e5,d407682d,7708e2f8,19ad9632,3d32e2c7,6e396dea,92af663c,c44de690,24e1407f,20a95887,37f01662,bc89cdea,88ab67a5) -,S(61ceebd5,9e5733c7,910bcb86,e19159ee,57638bb8,7f3cc56b,d0f4d25,147f349d,2a850545,e9b0ed08,fb63082e,741a30ea,7d85218f,86282aef,3e74b15c,f2fadb9e) -,S(5a1133b5,d45d0071,42b91a73,79e2a46f,dcbfee6,e102d16d,d77e817e,b4b6c187,2ffd96ae,afd6d9c4,3c9c0517,133a4b7d,34c1c2e8,f398f81f,f6f0305,28d492e1) -,S(b74a3849,8b701b41,29eb5abe,8dcb13b9,fff0f191,314dd293,9c38d0f,4563c8ac,9d844e57,e50a20fd,864d6f7c,5a677855,689be528,f8431186,ffa96679,9cb9014f) -,S(c35c9cd0,4afb20b4,3fd1c337,5a952ad4,8e9a806c,a64aa4b7,52fcb204,5f89d26c,b041c6aa,4a83efcb,dee79d84,19e195b2,48c765c3,f069d5a4,b7e87792,79a9c65a) -,S(9a85aa58,753868b3,f04b2af4,479141d7,11703dde,e5b6e5e8,fea8ad37,d0b82b96,465c70ab,aa16f03b,d24b8075,233ec626,4e062041,3bf485f2,551d9952,7bd75d27) -,S(3ec71bcc,e051f3e5,12d83c14,cbd23f49,b3e825a3,cfa4c61b,d12eb057,5c86fe14,f198c21d,e2daa56a,55294c5a,b033f1aa,45caba3a,9a950007,db35f05e,e9915bdc) -,S(ee1cbe22,939e1ede,9010e23,535bf33f,6b09e579,3737db45,aea48f00,b359ae63,bf604026,d4444df6,27f7d297,1dab6a91,acecb6d9,de53228d,47178017,921b90a5) -,S(ebcbf3e1,71de3a62,ef47677d,1ff4d027,5a8cd92b,bc889ee7,8dcf0c99,6746073e,878d63c7,bc9c7224,914a3f3,2dadeb9,95c6d890,a3823f98,5c3f574,9ef6ebe8) -,S(e4e92ee4,ce72ef15,b87c57d5,259520d9,b6066430,c090dae5,6e81b2fd,ab9db797,3faac465,4a03a753,559f47db,f5877452,6d21838c,9c1f8217,ebef6965,655f944c) -,S(fc1ce758,8e292b03,7b4ef743,12eb1f67,cf275fc6,7c1e3d63,5bc42dd0,deac1cc1,176b79bf,44f7d9af,7f7c791e,8cafcb7a,495bc392,c23899b4,2fe7963d,e65186d7) -,S(f1f5bfff,179e6a6c,692a86b2,1c95ef85,49482b3a,b97a491f,9e9c7056,ba94fc56,389257a8,a2cd3bc3,fb4f0620,5c2aae70,67041512,10c62093,13a2584f,8a39e143) -,S(980e7414,61c3e001,ba6bfef8,d175a141,2c7aaa2e,748c3323,ac744fd6,ab793eb9,6e37ddae,29e05e83,b3cdde28,d4286005,34cbb33a,636c4259,c7fa7625,1b31826c) -,S(f519cff7,686a5257,71986dc,7e6c1955,adb7faa6,a6f7a07f,66a257ed,a1b1c179,3e803eb0,8c765c98,7941d008,a93b8503,174ed4ed,1c31e97f,9eeb8f2,a55a807) -,S(2dd8d9ea,3851fea9,1ba9bafd,bcc5cc0,9011d939,10edceee,144e2755,ba8f8061,6147f1af,d4224689,37cd058b,4ef52618,7adfdea9,ce970dc1,365fe04d,1da52ae3) -,S(860c4262,9483537,47ac0c41,5aa00f63,2854f88c,d7d09b35,edefd780,1454a4ae,a2a7a22a,7d826d25,8e7dfc56,1eef0d85,d15378a2,80535cef,95ce6e2e,d73392f4) -,S(e76b20ec,17d82c3d,987d4ea,20535209,e0697f90,2c964b28,ae97ad0b,aed732a6,c97844b6,85f6613b,fdb7cec9,cc47f701,32bc1137,d997f8f4,ad182492,67f54bf0) -,S(26731d0d,12fba582,636862b1,62a417b7,718ec9cd,e3d047a6,50455efd,910ab88,3c10efb3,b464a61,6e2023b,b0736d6e,8d298609,47ba5714,3b1a71fc,9b542192) -,S(50cb4878,52db811a,87fe46f5,ed014db0,3fc4570e,8b2d8ea8,9865df9d,a224dcde,bb8488a8,7937ae89,88f572a0,c100e450,c69db48d,303d06f9,5d54bd83,8b39621d) -,S(fb69453b,1d67ffdb,670f9fb9,2b3fae5f,64b0c4d,cb28ba0e,7ebeeb21,ffb02a60,b0fdef36,92d881b6,3ebb1387,984120f8,d1ba17af,477364ca,41e303ee,a4fd2c39) -,S(a8f1280b,4b720226,19faec4f,ea3f784d,3f4061a,56dbbb99,38c7706d,8bb249b4,ebb3b571,ac505913,4572e501,4be7be33,a97e12b9,bc1fd9d4,484703f4,6e39b8cc) -,S(4292ce09,df305790,f17cb3be,30996016,420f83c1,bc19abb8,78b49027,6eacaa98,1b14d94c,bf2b1d1d,82cf1873,3461b76c,f32c8d5b,6746e2f9,aa2aa248,1c745d36) -,S(ac241177,f16f747f,b796750,49c83f8f,8e1a062c,9796b05b,8c5a5587,a4c9464f,dd057503,8261d044,ec84eb03,73065687,266b695c,ef5cb41d,1cba3b5d,9176cf58) -,S(692eca73,26bf2da5,7fd9d640,acf7f846,78e75c9b,86b18e7d,d7fd2545,751823d3,17d6d462,548ea78a,18557320,289d61da,14c3850,4ff03347,8f17fdd3,71c8e97f) -,S(d01b1a44,55ef5011,e4ecf946,ec02e6f5,d0e129d4,d2f59889,e823cc5b,6f10e216,84a4d89e,55e33edd,d54f38f2,1649f5fd,807879e3,388df988,34556ae6,57f91a0f) -,S(1eba61f2,96a788d8,9273a67,18f2a0cf,fb0798c2,393330f1,2f890bc7,9bfc1e9b,89f298cb,e8471046,2df0a6a6,b6c4b6af,505da2c0,9ee13266,bc47cd5d,2ddc9661) -,S(26dff8da,94603121,4649fe1f,721edcc1,a2300ca,b1a6d548,9c9b68d7,415980ea,d8264a21,55e1bbdf,c3b65862,efb9548f,3c4a0a5f,97f5b713,9d3da15c,90004e60) -,S(4e642b51,425e1822,1275f64f,283e9eb1,a3116adc,a6e25047,cee3bc0f,323fe676,f28b7d65,9125468c,4951db0a,bc35d4dd,65b9c5a0,ed27d742,47a68a23,89eafbb2) -,S(354aff5c,ee9a27db,37e7c97b,4cea476b,b4f3700c,e9c26b21,e94d2e1a,78f448a2,8d6907d1,624b79e5,6392d008,2f6a794e,99b4c4d1,6ca78dd5,97709c86,2930fcdb) -,S(5286d074,949369fe,8f69f020,c0b65f75,e76995ee,5f49b9dc,d570b956,8ffbdc3d,255ef2e5,3dd2c40c,1e462a45,27e6ee00,e0a23d3e,b16b05e2,2781de6,879703ab) -,S(b84a8346,c86e2299,9acc8ff9,1a893592,6bddeeb8,6fde121c,266d5f60,3268add7,31179a8c,79f40238,e1b80c87,81e46597,29f5c8d3,d8bea0a3,f65b403b,ef20789f) -,S(1e7bd5e6,63fc9a50,2258b9f1,14fc51c3,1b9dfc27,9022c67e,fde7872,dd12bb94,6287a9b4,555b146,7d250f11,e77ee8b5,7accefe,6d91cb6b,927611f2,c2c1b84) -,S(7ee68a21,37289ebe,7a5cfde6,be672ca6,9d28acc4,54d6b8da,9c96b2ad,37d2bc81,3ec34064,a6c3ca,f2a8aeee,9b24e023,3d7dcbe,b7acddcc,8a53db84,c570c83e) -,S(29d4b10c,f4be3bfa,a9d07fdd,da6ba7ae,f3adef75,67c3c33f,8d4d914c,f8ce570e,b6a74385,96a4f40a,40d03c25,2c7070da,2ec79e08,dbef71f2,422392ce,1058bf4c) -,S(7907c5d9,5c5cd647,e312a43b,42c3f053,50218f10,da6279c9,895516d7,328c359e,6c65a9e1,ec062a1b,f2abca52,fdeeac18,26888378,58f985d4,c8f1c987,64d6a625) -,S(cc436eae,ce11bbc3,36014fe7,bc68fcfa,e5bc2c55,c53430ad,fc994b8d,959d31b1,16160de7,d6ffbf64,d644e608,96052985,6b2bd539,66d7edb3,a50c924b,fa9706a2) -,S(cf023d5d,278d4201,ae659d55,6239dfa2,1b5fb30b,14adbea,7351b620,150ec1f0,d6007395,ffcec07a,6e71c26e,7575cdb4,34c473b7,57d4574,9e5154e4,d4990741) -,S(1a2a093,f718c59b,d4d35b73,2c547b61,12b6a257,e807a38d,71b04125,e7746a21,2674b542,652fa39a,1a2cadcc,3924796e,16c0f8b0,5d83f919,f8b93547,98fd4c95) -,S(534ed420,4b8ac51,7518fdff,224ffae,f712e4c7,6a84215,fac925b7,eeb799d7,35e5852,3ea6199f,b9fe497f,576dfae8,fa30782f,d24cd439,c0708118,dbd82155) -,S(8d31e4ad,9e6f30ae,6c78ff18,8f4b0457,e9ba646b,3a26138c,f11d84c1,4a00d08e,f0dbefc1,909396c1,3a1e36a4,844b2a87,e4b0b1cd,4b30e996,47839bcd,4dd5feb2) -,S(81748452,267405a,bf664379,16ff7f73,c418439f,86b73159,54c15fd2,2d2b3412,13d1209b,435b50b,1409389,9961f5ae,9f6f95fd,280beba7,cb3f3f5d,a0f19bbc) -,S(bca87f72,e604e885,64552b,edf380ca,45842270,57efe12a,6cc23847,658aaa3,ee508af5,28b77125,72c123c6,276ba23f,af26538d,5752d84b,54ee82ba,df9e3d0e) -,S(de2baa9,a19652f6,c0c0365c,d6e78cb9,d527e546,1240fc52,e8c59183,7fcd3fb2,aeb418ef,466c32fd,4cb5f2be,571672dd,86573941,a9cf9bd,73377aca,1ed38905) -,S(7b8ce1e9,14df7919,b54a0591,c077135e,556f6cab,c7665e5a,c0004390,22acca9e,a60a3ff3,9cd8ad49,c100b72,4338a54,d06a96a9,f3fdc7c2,fb8ae598,c0b40628) -,S(cd71c179,13fe7443,19bc80f8,205d7617,4d6d44fd,a6ac3d1b,402279b,eca50e75,9f1e73bf,cf3438d0,1f01d1a9,3f633929,ae385812,528ad211,967bf38c,71419064) -,S(42cad02e,32dc8dc3,4ba36161,d0816af1,619b70e,117da444,f4f1e454,73ca8fe4,97cb2134,5a259cff,8870823d,fe11031a,79e59d7e,dd2593c6,65128a8c,36e75568) -,S(98a89130,4f0652c6,2986644a,62a1dfab,48331756,c8b9e1f6,d473c03c,b98ff8c7,c130f2ce,cc506903,9ca49b3e,534ad484,b277e0ad,7b2a8733,98864000,e9a824e8) -,S(23c45c76,84762aa,7bfd39ff,284403b0,d7a4a128,6bd7b455,22c09d2e,df8a4328,f4ab7317,95c46f47,c3d46dc7,cb0d43de,d57cb274,ff0c350a,f0d79548,bb303cde) -,S(8b700037,d584c4f2,f65416f2,dbd37c35,9e6a7b83,108dad34,3a6c4d0c,6a21d856,8371ec03,9ed0066d,4e8e7d86,69169f9a,5a172cf6,c324c2b,ecdfc76a,c365ca35) -,S(da6164a8,d0fb4111,ca1d78f2,83e8180,4f4ae8,50ae8596,cdb97d9a,a30f8a7b,f9a8463,717e4f17,a77caf4e,10c11101,1cc0b5a1,c788307f,c7aba482,2a9a342d) -,S(49f37d65,a9d1a54d,1929b9c2,6db7d7e,c45924e2,9e6010fa,2202d47d,eb5fd6b7,f9b9b785,28f62629,7bd0dbba,9340c142,1e64895,b1befa94,ca677de7,686aa51e) -,S(8755f088,e26859a0,1a56b78,ba1898ab,12d80837,308677cc,b38e9c53,e36efa10,5d67013d,1eec7a88,215b4768,f55f83f6,434906a9,f2f6a9a9,de5df75f,6ef7e478) -,S(35321796,b7aba6dd,873550fc,5a35e081,a4e6d134,a127c534,69ff777,c609045c,47ff0f43,efa93f4e,f197a680,4f1e1133,c5c8301c,b49de8ba,6fe10167,f0a1e832) -,S(3abedd2b,644bd2bb,e77ab5ea,2823b42,83479fec,df2b3421,56fe9ace,612559b3,4269b08e,6c13b818,131824ba,11e3369a,87bbccfa,330e408f,17985b21,e5e32b06) -,S(e30112a2,2c23462a,a803dc53,e3277d7,c14b62cc,92787f77,5be98ffc,7c956de8,d0c7e3d0,dbb10e8b,7a9f4e0f,f93e7581,99d90f6d,d869368a,8d2ad369,4898da40) -,S(6250858,439c4b4f,30d47f6c,b9259103,bcdf497b,f09d3762,f1073f5b,973cd06b,3437f5e4,84ce4258,5584407a,fb0e4383,87e4c930,2fcc902e,cd26b721,5075328e) -,S(77ad4485,b8c94cfa,4e904bc3,90e93e3f,66838d50,fb16e09b,dcb39ad6,88f826ea,4dbc505a,9798879e,137c8444,750ec3c3,34c2ecb5,485bab73,6b0b9bbf,806001d4) -,S(5dcd3e92,e413601d,b9dce337,7a8e67e4,3852b8cf,ac41066c,ad579199,3ac0b7db,acccd081,35efb43a,306760ed,ec278f7f,36996ed0,d6367f85,417754cb,a4e997c9) -,S(3a26663b,adce051f,c41d2e6b,9b931851,e65ca385,15f59737,fc8c27f5,caff788d,2d647eab,af01d846,70110e,7272cb4,9b9db0b8,88a8113,bab5f89b,90abc2bb) -,S(f57cceb9,51dc98fc,712fe9c2,c024031f,4e3b0f02,5067ac4,b8bb0096,e4b1aec0,696093eb,7a8aebed,a751455,782f99fb,ddb2c66d,438a7bca,9c4df301,b7a1ea25) -,S(a89a4778,bca06e14,bdbd46c,948ccd36,df47c83a,2dbba9b0,93589406,be9b4a0c,f4224dd6,9d08262d,22b98e2e,4e781e6e,939d69ed,d59f30d1,d23f9ea1,6ef366cf) -,S(64738381,84fe8247,2b463f4c,7ff04a6f,6a3be92f,ba295d72,adf065b8,10b962a9,bcd100c0,d09f6e93,4fe9d58d,d58004d0,9ba164fa,324010bb,c973709a,2ce32de) -,S(4a683a38,21261e28,2e0196ba,d9f8727a,f7bcaa4c,afd5e686,6c7cffaa,3adc7774,b5aba4d0,ec3d9aa4,39b37f0b,15f40fed,913af371,b1b94f20,2cc93378,954ff3b0) -,S(1025e16e,fdaeccd4,436cfd9e,b8ee1614,53fee046,e420296f,53cc2e5a,bb5cb3c7,f806b96b,67ce92a3,e159b807,58f38f73,704e4d8,3bd611c2,25314400,f0c48f3b) -,S(6149d809,675a5353,6fe2217b,7f6777c7,60039cb3,5a0840e4,552e2ac6,db6650d2,e4ae636c,9a9808aa,4f49b03f,bd12f786,c72f07f2,9e397a11,68154505,b1a96ca9) -,S(ba24112,43888342,54ee8327,4bb03dd3,2fff3edb,4d607047,d8c141d4,c3fec47f,8a6bf123,29c3fcdd,38e6a18d,ed28c8a1,3717e997,9d0c366d,aa640dd,bad5c35e) -,S(c20df096,3c7cac7e,9dbaa259,538af550,35c00550,94ad4993,2190688e,7856a961,491e995d,16cf7ae9,85b8dd8d,6a5890b8,fb4f2c42,aea7c33b,ad84835f,b245d40a) -,S(6f53d8ca,4dbb4d72,d9ef3dcb,93dd2ec1,aac9f38b,1b4cb2a5,c76449d,4faf0c50,6784a02d,f449beb7,24156de2,486753c0,77bbecc3,27caee12,f7888687,4e7ae24a) -,S(e57e78bd,71a08f60,51c8a046,184757eb,6364ae0f,8eca86b3,51317712,737bdda3,a0623c7e,8a535f66,57116c82,da77554e,31a1d263,28ec0e8f,116976d0,f4385342) -,S(f52f6f29,aad496ab,9e0abd0e,a7cb53a7,7853e8e1,a6e5ffff,285e97c4,f7ab099a,3df7c1fc,6d5c5e81,8b5de4b7,66f2995d,c361511c,198a68e0,b7196204,559d55a3) -,S(da74f5fb,5c0a6d09,6fb26268,b33d9c86,ec5cf08d,8bd65fe2,59f836a7,3efb0dc3,7e50e989,de5e2847,7e31c816,42a51edd,8d0ea031,35423f3e,ffea07a9,48a62c47) -,S(2a2c9aa8,7bd45217,f341d35,9a9d2de8,35d14414,cfd3eed8,a2337a64,e051f4ff,bf9efdeb,99335f68,a01fd7e5,d8aec9f9,49688221,59d18bf8,a466c6ef,9648a1ce) -,S(2a3440b1,91dc5314,c6d0da7d,b07e2cf3,7d13bcef,1ebfd23b,492ad632,92022266,bdec24f5,c993a020,2f2fda24,e8707947,e4c1e9f2,2c34efc6,dd1e62d3,e2ae2b40) -,S(a3a9bd74,3d1d36ad,fad36e8b,d5544500,e0accea,d53d081c,28740109,e10942a2,cc33decf,f8cae7d8,dedab1fc,ea1b4c16,2cb71104,ff75c16b,66db334f,ec794ca0) -,S(5b83d48f,70a2f212,93dc724,77f4d87f,80db7eac,2b08d70d,308953d1,88804950,f78c0488,a10c66c2,e11368d7,690fcc4d,982ecdb4,7ed539c3,30d4b14,4248b545) -,S(dd5b46a5,6e3e4a22,39e210,a871db8e,d901ab96,3c6fec29,4140d77b,be9736a,d9b76eba,ebdd45ac,35c52268,ccd35df8,9e7136ef,879848ce,ae647c13,d421d46b) -,S(2f74db5a,25486127,6236bc5b,22214097,d1ff781f,3798f64,62cc6dcb,3f61a6d3,b6d635ed,256f6d2f,a91b868e,a3014db3,64647147,ac89248e,ca983c09,53149c1c) -,S(32adc0c4,1f7c939a,58640b8b,fde1c8ba,119bff26,dfe4b0be,c5058ddf,23ab2e09,cf317248,7f0bb297,d7d7772d,2a01d917,40beed83,3a35a293,66bbb0dd,3946ae3f) -,S(4fe53ca7,172da8,272a152e,d74c07ed,4e336cb5,85cb2ae9,36f9f301,87c6cdce,81f6d1c4,bd711c16,21cc2986,916578c6,baf42870,58b84843,27e46e98,81e3a8ce) -,S(601934f5,577fa2a6,702f316e,b4dfed9a,3b08dc06,5d3e58ae,63f8548d,9fb2569f,6df7d882,4360fd7f,b5f96f68,93b1f1de,55e19690,f6acf954,362074d0,30f714cc) -,S(79da708,8ff4806c,64492ee5,2e9dda2f,e1bec3c6,79fa3129,8173c0f7,aa79d321,2b1eca29,76f2884a,35167e8a,bd2055af,44be734b,b0e0847f,f90abe8b,17f9a47) -,S(602b8209,c39f299c,bc208b51,ca8bf691,5b8d4fc8,d8399186,7e589dce,79262974,f8b6cda,5d7ca83,6aac43f9,4791a5d8,a5ed1f05,af90f5f2,267cd9da,567f5555) -,S(57a4f368,868a8a6d,572991e4,84e66481,ff14c05,c0fa0232,75251151,fe0e53d1,d6cc87c,5bc29b83,368e1786,9e964f2f,53d52ea3,aa3e5a9e,fa1fa578,123a0c6d) -,S(4f9b48f0,ae9df110,70c4c5ae,2b012cd6,4599063e,5bd32b54,43548b78,6a06db2a,d5a7a0fe,3cafc78f,66f563eb,f6fe42ae,980cd621,bf18aa15,7bdeded7,dd5ea016) -,S(e46a5308,4b11349f,44661589,38bb663d,e1910aad,35de0708,5a053b5f,6c5e7375,da46da88,9583632d,fbf923be,9f07ace2,cb8c3d2b,fa6bfc47,9e1a7d32,e1183ce9) -,S(3643d766,b94b161e,323e64de,3c925040,d62f2ad6,2b60a674,15c8b962,1c071ea,faf69af1,1f2b9e05,db29dcff,a020f6d4,80835d4f,83d35a96,7aff1b5b,9f16fa98) -,S(96769694,c026152,1bbe1b48,544e05dc,e6bea57b,7fa31478,f6ff1b1b,bf497dca,4eb5a6fd,7d0dae14,9673b033,bd97c08f,8210fd12,c759293c,40782702,b3e30b03) -,S(2e41def,2c479931,89be0ff4,b4110e28,7f80fda6,f4134ef6,5c867e66,59a24d07,26a14d7b,b8388b12,a3ba1f50,e56ffb3a,69bde3c1,17441f52,158531d,c874c313) -,S(f39d941a,f6eafe0e,9a44fbf7,71eb63e4,db94cbf0,854a837d,b7f284c5,ac03c29b,1ffed770,dac4d12,2241f8b5,507e04b0,72cd5934,c03b0183,d8b62e73,8cbd7b73) -,S(90900d34,4576beea,911f8dc,c2d90625,1cdac045,28017d1c,59576449,50136419,60d38bbb,2a338102,da044498,a2b2c5c,1457cee6,eb34d666,b0c0956a,48161ad6) -,S(3a5e4627,1007f4a6,2e744226,f1d2b782,44a523e3,97b6509e,e3e1a513,d8ac2e06,50f01fc1,74cfc3f,256dee2,fa415f35,bcdfcfe,57b79d90,f75226ba,e8202449) -,S(f66ea256,f6d711e4,1ea5492e,f6f6e46a,b13ac258,a8f0eb87,a06b6c3f,13e24355,fb8a1c47,980ea6c,87ec2401,4c0f6d2a,8f32a2a0,6f3fd0b5,7fa00307,26243841) -,S(cada0520,19a16ccc,fbb6d4ed,6c7436d0,c946a485,ab3362a8,5c62580b,d3038fa0,e249940a,34804324,ac706963,91ae7393,421de971,af0f203,2b5f2d21,7d32ae6) -,S(d16f5b5e,820b7295,96bd5192,9dd830b2,ce208413,5c2db712,2c4e75fa,cb759cf1,70edb084,cfbebcd7,ddd36380,75e05147,6ecdd585,e228749c,e61e3784,6a448ed8) -,S(bbccce8d,dc6bae0d,cb6e5149,8c666f31,3dc31ac9,d4d949a4,84751134,d5f71535,4da772fc,63ff92be,5271b479,68e7bbf5,c8941f68,989fa6e,a23ce5ad,23f91eed) -,S(515f28f5,cd8b75c4,325e940d,6821eba,e7d5d2f8,e836b291,5f606152,ed4243fe,a13143cc,f5d2b8fe,14a09f46,68229258,e1855a82,6f7db2a2,4ba2f1c4,63668b47) -,S(bd2f46ae,a78c462d,8691ed6f,9d381278,68d356b5,b8fd7f79,df6ed845,21233837,8f645ed3,f3cc803f,7eb32f70,ed7d6fe2,84ddd9ae,62ab8324,b92bd7c8,79c4af11) -,S(8576f13c,c3d32122,69e10b51,2011a450,4f8d7d3,92e0f133,47d7d65d,f9e37dfa,fbbf2048,3fa0e131,2309eb8c,19eede8b,86ff9028,45b66195,8d19d903,f68b1a4f) -,S(70be1e91,8fdf4e47,d73f262a,bf2361fd,763a83f2,d31cf41a,23b8c9f3,8309db4a,82f80575,e4246ef4,c13fa48,8892943b,a1897ac9,dc3ef188,29f3f708,428bc573) -,S(bb8a093d,1d586b53,9bf54a46,1a353af9,173529a,12312361,c8064e91,4b41180f,460e0ed7,8456a251,cd68d66b,ccf5de7e,28707540,d221d65e,72334d85,af478269) -,S(7817ae4f,34d9194c,f4b30628,7071fa1e,7b976a84,754c1860,6dc4a124,bc5c2e69,25f4ec56,c4e3b1b5,bc6ed346,e4f8b340,6afe1c0c,f84ad7b,481be5dd,2cd55cbc) -,S(85c760dc,411f59fa,6feed8e2,a0e5bb5f,e72af5f1,2734c9a5,bccfed11,bf66abcc,92583db0,b57c9c71,bf0f1248,23a67e5b,89a8910e,6500e8ad,10666b26,cbcb8cc4) -,S(20d80d35,4d9d762f,f2c739e3,b1e7377b,d9ee7123,47ea979a,d4c81abc,5d5086c3,6e191d7b,8017a675,e8123b7f,1f1351b5,ef6ed6b,1b225cf7,48941df7,62f0efe5) -,S(3306922d,43f2c4b0,65f6d9c8,d1289804,ec26cefc,97090fde,86dc3e0,fdba5657,98a8cc9f,c93dd7ac,7079f76e,fa1c4065,86f0e941,9f87cd88,1b865c30,13c7efc4) -,S(b35c7597,54d37f12,440f7703,39223681,8a1b9aac,b085fc1,8acde6c7,3b2fb001,484b90,69b08485,95c58ffb,df5968e,2ea789b4,6f93d660,a7af6b75,13cd649d) -,S(9bd41b53,7f8bc303,6cc9d010,45922b1a,5c647f8,e90fd587,86ef0975,474e1f33,590afbf6,55ece125,da486bfe,1ff389a5,8b866776,8d2013ae,c25d03bc,bf0274ac) -,S(2a3a672c,a9b3aef0,bce89703,a38e0dcb,6950d93a,7359420e,5278f160,541ded42,4c3a94b6,13f3383d,b908ebef,6b62bab2,c95f850c,f88aea5f,c6af3b89,c2693d8e) -,S(31ba6af2,a2d94f8,d4df3800,353806dc,c8db945f,16dc5bf6,93794382,58f74d3d,ad19dd02,b290eb1c,ba5d915e,f60344c5,fc1e6a82,c5427f4a,236238cc,2329df5a) -,S(fa2199bd,74b014f0,5df0f9b8,ebf44a98,587c0251,e9c49bb0,5bb12952,bc869720,4328917d,6efdf5f4,b0f5c483,860e1e9b,41ab6ee,b1f5631a,66d2d213,b163f45e) -,S(417b9046,c7f53c0f,5ccf2847,692ab63d,8aaac02,e3bfd99f,30a469a9,8be22d52,78c15e65,5f309788,dff6eae6,91706e00,7aede9a8,3bdb08e0,d495d6a4,863b82c0) -,S(56ac91f2,47d51fd8,8a0e6eca,67a69ffa,6158f498,1714964,f33e43d5,6f18bc2a,351b7d5c,9e1b1a4b,717c518b,37b81c64,429beeae,26e7a740,c54b1a66,dd0680c7) -,S(aeba32f8,83307ef3,152d835a,a0babec9,e164ae70,10c90250,68507d65,37215f8a,8d747d39,35cf5f2e,6ff16557,7ccef843,7ce7e3c6,a41cc40f,dcde2ae8,582c4e21) -,S(42c7b219,9af00c97,693d6bcc,256ed047,79ee10eb,e4dbe63,d47d681d,21db5813,a15fb708,1fb1c7cb,2ce44a4d,f8958432,a5fd875d,1fcf7c75,c3c4865b,b219378f) -,S(4337b297,ecf365a8,88bfe19d,1bcd5fe,25e0dba2,9c39e2c,36ca116d,a24e5d98,49c723ab,c6541edb,cbc83348,5e06db73,28d1ef8b,c9cd9722,915415bb,2242b7ad) -,S(18998c76,1481932c,e968af0c,eb84b250,aeefbf25,27e4ef84,a2519a1d,b7f857bf,455ebc85,64518443,5cac9ae7,7f3289d0,91133054,d0bf9ba3,9b7c8128,26c97fa2) -,S(64c76320,fa24572a,590516f,1bfd8b4f,87767b64,1e65588e,69cb895b,6a49b2b,a39a2a5,c4795095,a03ae76f,86825ec1,78366c8a,8799d395,d39fe8cf,74b9603f) -,S(41657405,e35eb87c,a5ba5f2d,3c6f12a6,dea917a3,3b3b44e1,ebbd3bf4,812b0ad7,8e2169ae,36f1452b,4577fe78,7adccb53,4d0ed75c,2096b491,6b68dd6f,95ff815d) -,S(aa200fa3,768a4b89,16e110c8,f4a6315,7bfd4a11,2c10cb6,8b76e30d,c0391f6e,567bd959,28b21555,dfec898b,d7d198a8,c49b79d4,6905afde,7fb3534e,a584695b) -,S(7aa78328,841d2f54,b843ba48,c8c9c623,eb529bd6,9e584966,555f9bba,77131599,6b4a2715,e4b8478b,24da7e7a,64e2f6f1,32711246,29a583ba,1bb44af3,69f698ed) -,S(94b1a7bd,6a2767ff,459234f,c78fbbbe,48446b4f,64bbdfdf,dae34475,396969a1,8f3065ef,2273a871,dd29320a,8b9aa41e,e77e2178,e8b8854f,df1e88cf,991cc33d) -,S(6b957ba7,1bfeebf5,294c8cb2,7681e0c0,5407df71,37a34710,35fd98ce,d526573a,67e4808d,3fc1853c,5e5cd4ff,6efb5092,35c6df0e,c0a5f7f4,583fdb88,7a2724a0) -,S(8b274330,ea34100,3be93892,ab1fcb2b,f9a6dfb6,80bd9cb2,b8aa6916,43717f7f,54fa2abb,77855883,e627f828,49c71389,4ed141aa,9c9cda3,c99afaf1,7998db90) -,S(d3f64f9b,67362339,491274de,77ac665f,3b686372,499a12e7,5d145e26,7b58db05,c06116c8,52bd15f4,145284f4,3899faa8,9bea5850,4018310e,5c82a050,c9a52449) -,S(198926f8,ce0e4329,1bb9280,390f795e,870d071e,801b4d4b,c4aeb555,f237ba79,76125bd9,5b8d07e7,5e27658f,a0dcf10f,5d6c10d0,4548dd76,a833f206,d2b3d34e) -,S(1bbd4d,595152f8,39746cfb,6ddc2584,ee4358fc,6f878309,9adca58b,cf01a13f,18f534de,cceac5ea,7083cdfe,3de5ebdf,ebdc70fc,4f0856e0,b587e9fc,df8d7733) -,S(88737f45,b2639272,37cb551f,52022693,52457f,21db398c,1312e275,f5a3132a,79a5672c,2895e1e8,4b1a7b22,21ba0c5e,e3e61cfe,c95aa029,b2a179d,e0c496ed) -,S(cbf3e18b,1f277773,34cca35e,8fe1cfa9,2d68497e,46e7a252,4e14bf,cccb1e83,db00c395,65bd456c,3c9d242a,5f24748c,7b91f770,926ba9a4,1ff5c94,86bc3f99) -,S(8070ef0c,f186efae,5f9c8846,72a93a98,8ab65b20,2720893c,40b1a641,c7022f70,da9805b0,46946a05,46824cf5,a87fd838,cc85c853,a745d8ca,a249d881,127bd9e5) -,S(acaf984b,8fa45dbb,e84c5064,8b6fe23,5c57dcb6,21243e21,90286980,c3f71eab,46f4ec16,8259fa2e,f144dfb0,bbae2907,801b8c1d,f17dd0b5,d1db3bd1,2ceb278e) -,S(2893a05,91f9ecea,735e8a32,a57e3d25,e8916252,52a44099,4eeda971,fbfdc965,6ea29941,91e4b123,12b5186,efb7d255,372aa6c2,aaf12a1,8c3b15a0,7bcfbb6a) -,S(64974631,68f0cb60,9c926e28,5ed12df0,cfccab0a,58f11b39,dc05b644,c2be951d,ea74181b,2fa885e2,4344bb21,9f2509c7,d432b5a9,c178b406,160489a,31eafb7c) -,S(b938443e,513394c8,b2d4f7c2,9811039,918621c,5d3a86e2,d1bf0e88,ba1faeef,af47f2a8,c7d98642,50784f38,45ff9414,c52473c8,9b669be0,96387daf,c353fc85) -,S(bd1ee245,ad10f50e,9f8fd4a7,876346b9,24f4758c,cf69bb8d,42f6dac5,9d2a5320,776e2e3e,69d88d5,c26477ac,74ffe92c,134ce443,64b39518,af787348,e0039605) -,S(cb7ec68,805e855f,17e7dc05,4279d8fb,6d8e1320,67a486a9,7d49df43,c660650f,f50790b2,84c04103,11f302eb,71525fd,b12d7339,6d259b5a,91ce4fd8,229e903c) -,S(ef07cf7e,affbb5a,29e22a1c,7c84cda7,1968c615,fbde2a15,e1c1211b,ab30cf83,98f4a6c9,422630d4,103fc2fe,e4c80f2c,2ca5565e,25859979,815c425c,70ef574f) -,S(4ffc1948,4d7fcc59,ccce4ca0,d11400f1,13dc5064,8626781,4eec26ad,3e7b8fc6,be9ebe07,98ff3d83,cb5ac107,5dc87f12,d94b65e3,937ee669,61b4e587,7fb75aa9) -,S(cbdd5373,339ed493,b8cdf0ef,ac6371b0,fad1ad6b,2da4db63,b4ed68bc,61d18396,527de487,c3212d47,1f538b6f,f709c130,3784a7d7,c803e5fa,c77bfa1a,d6bdb13f) -,S(ea035b2b,d8a1d7e9,db7f6b06,5e003f99,4e650aa0,e3035fed,65e7bf5b,c67cb5d2,aecb4370,2219f488,86772e91,afe81c6b,2cd57e96,2a3b0edd,dbc64608,8c3761c4) -,S(de1a4fd6,c1d6240a,d6e9dda6,b2d43fda,911648f6,901ed0cd,99ba8ef5,99f8db89,effc94d1,61c0ff41,d1ca6085,371e2e62,f85f90b1,542d2cd,3a4223ea,884da03e) -,S(2e644141,e8d87ed6,e1215787,8bcffebc,d75e118a,f00fb7f0,e58cf5b7,e6a076ed,4aa858dd,f2ba62d8,6b8a7011,26d22c2,b45c240d,f65f85b7,320e80ff,cb34b8d2) -,S(3844386a,90d6b878,90fb78ad,8f2d28e,47ff8879,2d275c3e,956883b3,71b73a33,f7f5df12,1a8149c0,75f6bde1,2ca8ee89,ff284557,f17cd57c,714fd474,b365cd18) -,S(e1fe9b32,1b91d362,2b618cd8,9ae8203d,bde185e0,bab2fae8,ff7e96f0,74358e42,c590fe90,1797132e,a25eff10,f2bf2a76,cef4f064,acaba1d5,f8537b4a,ddf3e1c4) -,S(560a00da,2f57d821,b6a0144d,45898af0,aefbbded,a1e08a49,9cc727c4,b27a3c0b,64874e4e,39db1377,3bcb79ff,983b152e,5db86d63,4dbbeeaa,a8b0112a,e795e208) -,S(9f33fba7,7ec8de2a,c1b16424,856e2814,1afe9b1d,bd0cd1dc,e5cbb2f2,f379094d,97cb8cd8,1838e2a7,26034f19,b5decd61,d972abd9,bffe3848,92fb0a9c,26fe94b0) -,S(98822fa8,24057512,48f9da04,2a0cfb15,e46ee253,e06a1226,da75047e,72d7a1b9,3e9eea35,7bc54ac,da547561,1f9590f3,db975d4c,ce7c4cc2,a553df14,feb19285) -,S(b814d1ac,4b757268,6ad88327,32f0f84b,bc72875e,7e21707c,c4086a06,ac1dbd88,b6364488,3749a122,401b8ab3,c4a7b8a8,c03462ff,18d69c36,cf145299,f18a98) -,S(246484c4,1e42113c,cd39f7b7,eed9dfcf,b39cf842,85c28cd8,6233c1a2,bd043e97,f35025b0,2e31bdd8,41d36f7,9d0b75e6,80f431eb,44a50502,3877f5d0,eb9552d3) -,S(9f330365,7b41b2ec,d87fff0e,4284e4c3,bbe8c524,91d358e,847afb98,ff51db91,4b9a7bcb,221c8870,de176a43,d4f7cce5,adf519c1,75613dad,317f4337,72d5e70d) -,S(c2e78e9b,3c75433c,5f5623a,8f5a4dc2,b0e71951,4b16161c,225b9bca,9d529d25,1e75c8f1,938376ca,c6387b20,9b24a2e3,e794362a,d62441b9,50588a3c,ab9079bb) -,S(89340ec4,b6e81b7c,855c9636,b548aeae,2125c40d,2907f86,7ce5e6ba,a7695391,f739a94e,263e796d,df1cc2c1,3e2bc10,2b2a9c9d,55248671,575c3ea3,792c72c6) -,S(9204ff15,f1443cc2,78facd4,8d38a6c3,5d66a93d,8fd8e2da,a7e2bbe2,d6629d22,2b9de875,456b50e9,6205020e,c293ff3c,13120555,82727253,be10263a,7559c019) -,S(f156da10,41122fd7,ce6b518d,c325f5de,61fad9e4,a7bd684d,7abc495e,ebff04d6,c73294ab,f4f2adfe,dcbaa78d,2031a5d9,7f2c404d,739f5703,76e46a0e,1b631d4) -,S(771a2d78,37d6413a,13099861,6050c362,2c379a55,26506265,9fa7da02,3280fa75,8b6bc39f,5cfe1f5b,82bef0b0,f6c8dd1b,e4270304,d5bc70f6,6b600b26,5d4c9aca) -,S(14cd58e0,36bb2c59,f63b52b1,f40e51cd,aec29f0e,b1cc0401,8e512366,85a18f69,79c254fd,ed354641,744c7262,39ea4e8f,ea15b19e,746b372e,f270c8d9,9c5e2006) -,S(e5f54077,1060072,5800bff1,390a67de,cd539cc9,52b6b43c,22bff27b,1a8633f1,d6e1c6c3,9baa86c7,5838e691,f9af8a06,80274da9,b0f54b5f,4c3b2028,8d666367) -,S(b0eaaf42,9c072037,fbfd14ba,79693d93,6791344b,3d37c3d7,5b8eaf8a,e7429197,d72661e,4a171b65,4f124d9b,d0201710,bc237382,6a2f0341,51051716,9b7af26d) -,S(e022d70b,44edaed,35957383,284e4ea0,5380f92e,cf62ce88,3c2e11e6,604d67c2,423c55d4,3ba0ed0d,1455228a,3153e9c2,7aed89b,2c3ddc71,52d2b11c,91ab4143) -,S(92a2d73e,b2eaaaf2,65a70f07,b949511b,af1a3eda,9e5d8651,349a665a,4bc5ab5f,4492d419,4794d254,9a089fff,53a32631,5f1703c,5ac34049,92d68121,e00fa973) -,S(43409686,de50a9c,cf35ac44,47a9ceeb,b12f102e,3ee6003e,c96235a9,8db9cb30,2f781040,952e1017,8e4e38ad,bd9c6c8b,c8e1e898,7f316cb0,37d2cddc,4e10bba9) -,S(d349dd1b,643f8d4,1b83aa5a,d735dc4e,94542643,3888a4e1,aaaa0ade,2394cd12,67f2f057,1da2b6ac,295c71c9,ea00efe9,cf082257,ece35bc6,72adece,433249a5) -,S(9a909a95,7fb87ebb,35f6834d,272d8ce7,babad39d,8f8323d9,c6813781,66dd10e6,ce3ead1a,32771a28,7f624835,2a2f6001,c12f16d9,f7093cec,86386572,a2ddbca1) -,S(f38b1e18,df2a2a64,9a3be25d,3686b5fb,1d77f971,1214d452,a67bccf0,ac07fa0b,5c9e9a,7f71b201,ba11ced5,9c0a4623,419a20d8,c488f9d4,591671ef,71e65ea6) -,S(42360fca,26b8d095,df52738b,c2762ed2,7b909784,c12b79a6,a86e06c8,31535a67,6b6f4ce5,e43ec003,be88bc43,2bddc453,db93aec1,657f6f66,5dec1912,468345e4) -,S(e3d7198d,a7c5e3b9,997993ea,a32377b1,b87325c0,5a002a94,53404c36,303f4a1e,72437218,ece6148c,df742be8,35fabfe4,a05f19cf,3205e65f,5c813781,2053ef4d) -,S(39412945,a8301110,6b54f625,8191529e,2f93db5,bd68db48,d6bc6d9,687cb59b,b8db822c,60f5c319,18b05784,40a958b4,e08b0a80,a1015d9f,d2826506,f250f08d) -,S(4d275f7,7e0ee98e,76b857c7,ed9368ce,d93dc914,d54ad4f4,21d2c097,cd241fc2,ecb803d4,9b502911,f619d361,f952ab13,935448e8,90cc2f05,277e48ab,a39d7473) -,S(29364876,c1db9cbd,a3efcd5b,6599ed59,160b145,3c8a9e03,c013f807,869556ce,2bdb4af4,cc44950c,84f56237,95941f7e,43ffb56a,77df186c,2dc31910,f23f6ede) -,S(7531f4a9,63dccdf7,ab83ef10,d3ba1333,6febcf41,f4b21e55,d380ee6d,e4878034,4753da9f,91d56bc2,1e9628ca,2d6269b1,e1dcb1bb,87c55e,9c44034a,1ba36ae8) -,S(8266d626,3d12feca,440dce7a,4bdf8ac1,6050ca28,5bc16777,a3d9450c,5c286e08,2500f2bf,fb8a4eb6,6a5e7e36,399f633c,96d908e2,5cda4877,5455df2c,afe2328b) -,S(66480001,4f339f15,8c39b26e,84389f87,6d5e62aa,59cb63d6,9eaa86d1,4bc589e9,a0699b3f,e3eb5a37,9f078526,375ac319,f145ffc1,da8a42f5,96c7016c,4ad92e2a) -,S(f8efcc85,8b9c0fba,605921b5,e6c89343,f641e2b8,e1f45134,86b77ab6,4cc70d49,ba97202f,7086f0d9,af5a0ae3,35d9a3c,5f4de2e2,79278834,f8b1d875,50a9d607) -,S(a5c1227d,254324a3,b1ec627c,93abfb3d,6f2485b0,1d8e2e73,6c542e09,9c992540,c9189db4,8a163bb5,6d99bed7,f38a7f7a,64cfef45,cf977da5,a1d16dbc,86ecc7cc) -,S(271b2619,a5b253df,fbb655d,7702dec5,6c85bb00,9260d893,8e050606,b8bbaf3,58ccf3fc,22cb8f27,dcdbd174,6abe5591,72bca7e5,d5af3bd8,d86c9a49,3ecd2ce5) -,S(c9e1382b,20c79741,d81800c,e721d4f2,1202ba30,92cac36a,d90c1dfd,570ae16,7eb1fcab,2a47cea0,3a92f707,d799749,6f7a0dfb,f9a43f6,90d213b8,1231e5b2) -,S(574b25,65232a04,1d58cb75,12b48945,45897e6a,8bd47dec,b1e0941e,309f2,bbfb86a9,567d74bf,93fbf2cc,6a9c9dd3,474db8fa,c2b5fb72,38b3af8,fe4615a9) -,S(9efe86ac,a6305eda,4b520e00,4dff6c56,1135e7ec,6953d2b4,a988d508,63046c38,4f92a291,32cb0818,af7cbe67,ec3b4d8a,7afa4f79,91a9ae42,551ad831,aae9af70) -,S(82ea48a0,ff76fa17,374bf4c3,d0918e6a,df26cafa,33d87284,13aa2dcb,d813f254,6a029539,9bb555aa,39de1ca1,417a8950,49b4c2d6,26ddf8e4,a7086b1d,bf2ac9f2) -,S(c289483e,817bb06c,31352a24,ba60adfb,e3af2feb,de329f4f,5fbde755,bdd2baaa,3b7ee90d,8b4aecef,62b6854a,1feb595f,9c49945e,c19685c0,4b13a1ce,1c780a53) -,S(6bde46cb,b5580d58,ea68deb3,1b0587b6,1698660,d78a8300,1c740b4,96e12cc4,3188a6a7,c1cd166a,4894ce75,c79d076,a41cc5c,d142ed91,e096eb32,e9293292) -,S(d1d2a3ae,2844615e,57f0a11d,66fd7571,176738f,a066cbdf,4519ac1f,65827cf4,7c0cfff7,c01c196,8b7697d7,c51562eb,8271f936,5c7daee7,f963122,67f603db) -,S(b74c0c87,4d195557,3b551c85,2abf9a5c,e276b088,cfaa0be8,f6515ed7,ba27370a,f0cb0e,380c571e,fe5e307b,ec4ed8c2,6f0c325e,114d71b5,51e0f1f7,45a662ab) -,S(a9a71b9a,9f126c3f,a17c3041,2317e118,84950077,baee298f,47d42609,f9015874,c05f3ffd,b31bf0cb,7fa4be1d,f634cecf,f1b1137f,551220f0,8f34c2a6,a42e0586) -,S(d6de1153,a161f27,ddb51416,2b3f823b,2b1b99fa,3fa21c25,9b02274a,80dbc68c,6c620863,659785a5,eec15d25,9acbdefc,714fab61,4e766215,348c80bd,bc59764a) -,S(dcaa1dbc,3acdca5c,51f8c22f,359487fa,73a7dc36,2a796df,11292a74,776b73f1,dc4131fc,c22c607b,4833719b,1715179,b4b4d49a,958c7514,7c8c4a8f,cc85159) -,S(135537a0,c4be13,1c3aa93c,677094d5,5f3a1300,95499d21,2206a244,5ab6c,7ef69f1f,d2d3df67,335f0d1d,dd52370b,8f3ebcf,e3483330,48c2f045,64fb0f69) -,S(28f1d817,c23262e6,4cd572bb,e3fd99ae,751dd6e5,5e9e804a,fb3fe9d8,39de93ac,24f5861,987e3da4,2dae0e89,67c835ac,8f5dfe8b,d41e5cb0,97029b48,39e2cb7e) -,S(f7c4ef83,6e8fb7fb,8eb31155,c08102df,e0779b87,9ad641e2,5f8ce135,44294289,7f9a781,db339621,d6150f09,16eb9682,16470d23,6957a0d1,3629964f,1f6bce2c) -,S(f1f5ae5e,1ddc9b35,18b66f7e,25a735d4,ddc8d018,5112faed,a8da8f66,1a28b3e6,9dbff12c,97924d80,50a4a8df,24fe7a8f,5c5c3486,3edb7cb4,1c6d9ddf,b9ad4288) -,S(95f83173,d170ce9c,1ca0dbc7,4578b639,257c10a1,eb65827d,c2afbd73,8b654f,63a83ebc,8294a88,413c3c91,c6918a31,7d5ab83b,7bee35b8,b75d1cbc,3412487) -,S(f4ada65c,9f095e11,eb88c8e3,77d60553,96474935,91be3a7d,f8c83c09,6a3ff750,e7683f28,a38545b2,e6cbc87c,3dbcc4a5,2ede1676,1b0dd78d,3ac51a5c,ad861ed3) -,S(41afac96,f714db3b,1b7bcd59,1dc7bc24,40b82756,d9394fd0,3afe7ae4,299e5fd2,9c2e9c6a,3292ff12,426e98ae,ac654a44,61c52d00,5da7af20,474e9a47,499fedc) -,S(37f30b1b,2cb81c9b,61941fe9,cca35f0d,e1b8dffd,c42f3ffd,ccaa16e,e8487405,92bf7a85,e3401d51,d9fdd08e,1086b649,8086bb3c,a4c9a2bb,61b1d54d,8cb88a0f) -,S(2f577166,646e7eaa,21531202,2ce0c8eb,605a2199,454c205b,9d760716,584fb3ce,f0d7326f,e43dcead,5ae0dc68,4d04b969,af32e8da,ed624ee0,98567dff,3d5f446) -,S(8abbc780,92c5512b,5eba0af9,4affdbf8,3c2e24ff,bf9fe7d,fd57e5ba,64b5150a,58f5998f,c2ec19a,a495b974,ffeccf6d,bb87dec,49152327,91a167d7,f6896b75) -,S(e41ace8f,a01376b3,27c73fe4,7e57cfc,f6da7cf5,c2810aed,219dd065,c147571c,b590aada,3c2a714c,322d0459,272f98e5,715d4545,196127a3,7d8a94bf,776844a2) -,S(300c9877,8b6355ee,ddd80f7f,4124789d,7c0c84fc,9d9ebb5a,be714cd9,890f1d88,dac2ba62,c5718731,c8f5c7a,4e1a7b80,68c5076c,834dd385,20f5e93b,e39c9002) -,S(69e339d2,19d40f84,25a072c1,f7876c3f,dcdb6623,26ca1b5c,87681707,12e24c61,8d439150,59a44700,2157e849,9b535921,4cd47280,937405a1,bad0b86d,38babc50) -,S(e56493df,8e47a99f,8ab3ccf6,41fab7b4,cddd779f,51fc746d,a2fdd484,cbbdb909,68dba20a,559e14fe,d0806036,d41c18b5,9745319d,758c1145,b6e49ca3,e3f5ee59) -,S(37a91c57,8998511c,d39c11e5,86e00eb0,f76532de,574d9c61,1a34d38d,e7f50587,e3a188af,d2d8a24,735975dc,9da895,feac2710,ab9d381e,e5d1dc43,b3145f18) -,S(c5f059fb,5cc262e1,12c629c7,194d783a,6224016f,65e4d24a,86c52742,dee88c1f,1c85bf52,1a96a95a,5177792d,590b46d5,8c090705,1efa0623,ab15578f,b38c890a) -,S(566edecc,d605ceb1,a298c59d,78401acf,c6323c63,f2845827,62678924,9b8716a1,ee0d1373,5adf6f20,789f85b9,32d332ff,8c40b3af,c02010a1,5ad062d4,5a44cc90) -,S(327e7033,c6ef4f87,52e33d,bccb4642,3e6cf4e2,c3ebb4c8,db69ccde,db2c7c7b,fc49092b,2be0f29b,4aa3e266,709aeb1c,12266239,f7bd9263,4aae16e9,53e8db36) -,S(989a7f69,3ac0ac86,55f29704,ea6caff6,84ef5ae2,8c5f5e1a,1eae7009,97778024,573d127b,3396458e,74bb5bd4,4acfea64,e8eb1fd7,3b0b292b,d1b7b642,80dadfd0) -,S(9ca7672f,14f27f54,ed1cec4b,74f49a57,7ce313fa,4a665976,9c22cc61,b30fc94,f920c4d7,31d52a4a,30803f81,82df8d30,6ab14104,eeec11dc,d2d6ca0f,3904e4a1) -,S(db100645,654fe8e1,95831687,17e2721a,6097850,ed2ef0cd,e1d5555e,7847f5f5,2b2c3ece,a9c90ecf,34fcdf89,5f76c8b6,619287ce,e745014c,96281928,31056567) -,S(4e2a0c9e,82743b42,5e6110a8,f3bff14e,418a34fa,65269c07,bb94d00c,d53295a9,512ac2e3,e00bb04b,6b4b9059,a3ac69c,8a34e5ec,8dfa14b3,d98b2c4e,3cccca7a) -,S(c12b3f70,24ea8acb,5136f98,185fb1cc,60c71a77,2943b68d,7334352f,66ac77f6,b799f99b,6f4b76f0,1f09f5a7,bfbe2526,d67a195,83327323,9c07bddf,2544803) -,S(64e5a2e,daf34e1d,ebd7c0cf,616413ff,d6c09b82,bfa783fe,aa755464,8ffd7e58,e020e09,66f032e2,e905d611,adf0926e,7509a2a4,b51844ff,72651f34,3c2f4a50) -,S(2b0b8b55,fa734380,f6ad1857,e03f02dd,3d66ec57,2cfb3b9f,ef040895,3f0a838a,ac897251,a9146597,8e0b45ba,e1c880a4,147ce01c,3408e476,5bd9013d,9e73a61a) -,S(ae0e3d30,a2026133,d3a54529,965a9679,6523e8b4,1efd4c5b,d6778930,2a88525e,fb6918ff,85632d24,250be67b,339ab260,c80c087d,da1efee9,7ec5dfb5,38f80552) -,S(2ff9c711,4dfea166,ffae46cb,1f44c3,3bfa1530,edf23454,a83de862,8fe00dd9,53f667a,4441817,a3e38351,78195c5d,acb0d707,bd20e759,9b5e82c4,6f318783) -,S(cc027014,88b959c6,c043f60c,c42b1449,9e2614e4,c19f5726,3edb116a,4e7bf695,eab3f590,9b22f677,666ce655,149a5f07,7b5325c,2036dfe2,e572e64a,5bb6007a) -,S(1801efd1,3c8035a6,5efe3b47,68495d27,f9dbf45a,f019d455,84d68be8,28a945d5,dff2d19e,fcb5968e,f4ef49d5,9a82f8b,f44a5abc,e0b68568,1acbda1b,fa59c4fe) -,S(6da2a9d5,7b60962,357c09de,4c7ababd,5b698fe3,6e747f8b,e6ab78fc,3cdd7cbf,1e274e70,4aeb8ae2,295ac9f9,b37c0af1,71310b82,99acc378,d505bdcc,e275060c) -,S(7e8fc96f,6a9215dd,3bf9e8a6,ea944ff0,c7dfe23a,1a99f44c,832a11ad,bafc82e4,e9a4fbe1,e0c26ca7,f739ed00,c63f3886,57d09503,a808ed51,ddc872e3,b1342bff) -,S(a6362f3a,77d6d6f7,fe266ab3,78707641,9f53e133,718ccf27,559bb448,7e0caf64,c01622da,3fc2385c,60a5cd86,66f751b,e29d8539,f473cd70,8784d61,d2cc787e) -,S(51865222,28b47493,a3da19b4,7076c1a9,8582bd55,37c25557,44970075,9b37d2b3,f0f0b979,68638d9d,93fca65b,f40cb8ce,826558b8,52451ad1,7d0afbd0,44287be1) -,S(a2a0909b,a9f1b9c3,8c714ff4,f71995ab,4d80212,9e8ee8e6,7e8bc3d1,81d472ce,4123900b,d45ec7bf,71bfdf98,ec453392,8b364d1e,cd925a6a,1e8f5c5e,ec40068d) -,S(da518122,454e7f36,a63f5ac2,a1bf979e,f1357bea,f9f0c921,2b031f87,b83aef2d,bf877efd,d415e80,c828c5e,1b9dd8b9,6cb7f3f8,b9a0cb32,b6bd8f37,686da722) -,S(41c40c54,1a983125,e59aa572,910c5aa4,8a698306,d483f82e,6cbd7506,3947a87d,76dabb65,6b89910a,bba9f129,ffbdf5e7,ef840033,c30f4c81,4e86f101,a3bfc57f) -,S(c49fde83,87f2e464,6847c980,acc50d88,28745e4c,88a41318,709099cc,9aaddbfd,a65bc512,dfd07bd3,79cbaf9e,628be7f8,c7ddb4ee,6611fa94,bbb48c7e,ae7227e1) -,S(85b17d61,b6ee743d,4df21940,6d7b7426,3a6c6b88,e8c51071,7a1f0183,e0fceae,22b9e8a2,74c71feb,5046ce02,2f4bffbb,ebddc53e,704f6be8,92d3092e,55868fef) -,S(c8e1d37f,e6d677f1,3e752189,505639ee,3914afc2,c8d4e43e,883f5c54,f117964f,b0cacd18,d08f5a91,af46ba55,91f99497,ee4a7ab4,36ab48e4,f88ad5ab,39bfc21e) -,S(dfec0030,7d25888c,5a7d6f83,33112995,1a30baa0,b97add9,866078a7,e483836b,4e5a8a06,bf2e9447,ef466416,82af8e44,f407ca0b,6fb97809,56e13a90,bafaa00d) -,S(eac6c438,7c18d8c6,eed7618d,c9d3076e,c842ff6e,5f4d4b20,92594d7f,7f0be9d6,19d69bbf,fc0c1b82,ba71802a,c0feebbd,77a86a67,d734a163,4e823a6b,2265b8d1) -,S(9ff38c4e,4dcddec,a4824db7,97f6ac80,69432c15,9cbc99b7,4d642011,b3424cde,f72fa660,b7c1bbfe,df45b0c9,3cc84b81,266bd041,b94f54f9,1d26221b,51619ebc) -,S(5e78593f,3a5a3293,5f9e4f8c,4fe28555,9153f69d,d44b2c1c,146fc644,a5313f36,9d9d5844,dc63bdd1,b2d95b70,5d63c97,58cbc5a6,1b2d114b,89da9b9a,8afd9c47) -,S(a107c7a4,89284b6f,b01ba38b,3e221c2,ad31a48,77af9b32,d22c8544,71009ae4,66072d4,6be46591,ee386cd5,bc0f9f2b,653b580b,c515d4c4,a0fc369a,27d9f6b5) -,S(241f1d0,308d9845,fe2445ba,67929976,ff98e88e,cc23a8f4,190ce5fa,41b02af1,886697ec,d413a88d,fa15723a,daf91d32,9c881ee,c5ac9c74,366b7ea8,a7e194a9) -,S(319ee8d2,627f906e,83d5c6d2,6eac3b42,34186016,8b9a9283,c8790c6b,e48a72fa,59e496ed,a67816e0,3409f849,1cb458c5,76034453,65fb281,9d0cc427,3e9eaa57) -,S(1866811a,fdf9bd,937f4f7e,96985759,e0100866,192878e1,a2614625,bfca4822,215e0465,e85f9c88,2783a131,6b65fa7c,585f0319,1a642501,72e51269,d5b7ae19) -,S(7effbed7,b949000,5db429fb,8cf64099,3989675a,f7394ce6,9ff2f769,53992f26,6efbb5ba,28f26d4b,5256affa,cbf2dc0b,616d8b6a,c6cd2aa7,a1d09ac8,40c7c749) -,S(d8c72bd0,e59315f2,1fee45c1,937952b2,665c8d66,70f14bf0,957a4d25,2b168867,64c02d62,fdd40a6f,d11e2cc3,a73fc60a,8a2da31b,2c99ae6e,5a946c61,be56fbcd) -,S(710ec622,ce64f381,43b96bbc,b0b0d691,87bbfd51,fab4d47a,bcf18308,18d0db4b,edfd1086,526c3af0,c2e9b961,890f531d,3d275c36,beabb0c5,4963314e,4534d994) -,S(9427964b,9aeaedd4,9c168e76,38086ddb,70574f27,9e4c3348,68e4c595,30d51ca6,110b41cf,2a6b0067,eb3b312e,928583d9,e0026bea,684c57af,7300a611,5c4e2dd8) -,S(aef79435,a8b3ed9c,9eb515c0,6db62165,c5a2e816,5eaa4a5c,46a59b39,8f55565f,6616e8f2,1274c425,c50cb93d,8942aab3,3653511,3c3552a0,118b17a4,5584b91d) -,S(3ebdd832,3546063a,68f40193,59d72f26,f49f0ce,4a5af994,a4ac67f3,3074b5a3,12367d4,b29549ee,d0eba318,f395d712,db7962f2,c8e2d9be,ed895006,78460238) -,S(a38d9e5e,c52b0871,d0bc6bc3,b673c848,19af86e2,534d60dd,729b405e,426aeff2,ebe46771,d9ae6c5d,13895538,3c8de4d5,f6d13428,8ac36a1c,b01c75e9,f32cad02) -,S(e7d29f82,619cbb19,90c407f7,b452cb8e,334369a1,16901b0f,9f4ec342,48a7d624,7595ced4,618b5160,6b8ce230,45d7616f,15b6ce14,aa8eee07,42bec5b5,9fc4e614) -,S(ec869eb0,279227b9,4ae333e2,6018f00c,7523de5c,e3e8c4ed,f81cefcf,4043ceae,a421aa55,2c89c841,a48bdd26,4e67d82b,ca3fe577,64101556,ec6ba7dc,711ac92b) -,S(4549d908,e44a8c8b,6fc5c057,144a352a,6f07523c,e026fae7,c070ff35,c6ec5e71,71d8e320,7707e04,10208c19,e2c8dc79,64b48600,1a6d640f,44c1138b,7ab5dd7a) -,S(51bb6e9e,fef7b8c9,b0a4f381,3e1406b3,2cc7a53d,165b385f,f98144b0,a5b070b2,65282be9,dd794fd0,8a31de11,d46df7cd,5268eedc,aadf3bef,de5956b5,a467044e) -,S(7cdc3297,4c7caa82,44203afc,d48e625e,aa2027d4,d91613e4,5a83eba0,696d001f,b92b9943,3b1a55b3,b78027a7,a289e5a2,6060a411,6c2cca36,19253490,83519565) -,S(3ca9c6be,b8e989b6,a67722f6,d817a6be,aa478fba,10146fc9,3099575,609c9314,5502ed7f,f4b81bc3,8386bba3,4124ca30,74c6e0da,bd148e4d,6bb7f096,ceca2c0f) -,S(aa2abe6c,45edcada,f01bc1c8,38ed5e63,90e1a229,cc920436,864111e8,ad354d0c,1b8229c6,6f91304a,24c61251,f1ba2b26,95bb3da8,87154d47,c44dc9f2,f824f6cd) -,S(b52cae3d,f28c9d59,319f226d,ef73b60f,75466aad,fbe6f75a,2ab6936d,8e3bc7ee,ebee735e,22c091d,cc873848,8a7c958a,421e0759,2e17fa3a,4462db88,8bcfe220) -,S(c1085703,62a6dcb6,13da6283,23496169,635469c3,47b65661,838d9053,3821ef54,fe6442c8,c1e6a8eb,2dc2cac1,40ad4c7c,44511cdd,82b79cde,c38cf9b3,4ceaf517) -,S(f09e9d1c,fcaf127f,59d45476,56422907,83477fcd,2fa6c768,d5a3965d,af08c11d,f01a722,1f44fb15,bf428fc9,c5d7efd9,a5b2e663,cfecc9a2,7e8f964e,8bc15d10) -,S(602462ef,1e473ebe,d88b3b17,9d71b597,fd3e805f,e03d341a,36c277f,495c4527,f91db461,71411dce,aaad9f23,53f2159e,fed2a9b1,eb9d2ce2,844e1f6d,63a079c3) -,S(273a881e,8e0d99fa,104ae355,8126a20d,6b828d13,96bbc70,720197fe,9bb582d,5bb26c58,14a7b914,cd3b2f72,7f76b6c0,d1b40775,79a2c3da,29534a1a,684b0d5d) -,S(7c1df346,616cb72,b42f4172,36fc98f9,e8cd0504,1da47d9f,566c8df2,e80cd54d,ad3e7e0d,d602b9be,45ba8d45,6bc12558,73153c2e,c16773b9,390ad630,4fc41dd7) -,S(796e2634,657ff114,7394551f,3ce800b7,9ad644b0,539786d3,c62c6551,3d942f94,b65bbe38,ed587111,c480eb9,c30081a4,1e8ec66a,8400db11,bb1cc7c2,a14f1c60) -,S(5e2761fa,9985f68a,a469953a,2a6642c8,62b0565b,602fc206,193bded6,1a302bd1,5ba09b70,9db24f5d,2f47c07,51367d0,3715c9da,b7d430b4,713dbac5,7253e274) -,S(46458c92,fd341a0f,eb1ab038,5a246b40,5c004c22,98db90e6,164126c5,4fabe794,859d68b,345341b8,58afc324,263f1ca6,9d018fae,eecf33ea,f02a3dd8,d7446725) -,S(fc481830,bf817c1c,ffc9ddc3,d6f4e624,a410e134,cbfb952c,5c7379a5,81153265,a188b228,bd3d7da1,44a48e89,fd9db4ab,8dfe385f,ace8e169,a43a2787,59322551) -,S(42d9767d,9771a550,3c702742,ce2aedbf,3a780466,804ad901,7792610d,5eed03e6,df69432e,9764f337,3a2c782b,e02d2433,d2e0f568,d0dd83ec,e89ea1c2,5ad50417) -,S(37122c49,993ab297,72e60222,615ed912,462deefd,d28e04dc,dc72f4e1,b9477148,627ff4f0,924cfbc3,aa0422cc,36402b8e,410b3ede,a552408e,f1d3820c,5996e39d) -,S(9c548182,94bafcbe,743e52cc,a76e1ead,3619a557,a5cb8bb7,3140ea1a,5c6896c3,5fcc472e,b88e8528,ec71dafb,f70504c2,ec0478b3,209494c5,b53bf05,b38f7fcc) -,S(7b9d7ad7,aa5b1f69,75c4e025,17123608,a59277f,d63f2a07,7ae69b80,f65a2db9,6cde1ee8,714aa229,d01c14d6,f514ecae,c4a7f15c,a756812f,abfd61fd,d7d1bf8) -,S(af5ddaf2,c985560a,d656d948,e41e082e,6990e950,6c77d53e,171cdea,58a9a102,e348451b,72896ff3,c4839ff7,6ce16b59,1f685348,eff943f5,fd4581f9,eca5b505) -,S(42667f18,e957bd19,5fab366,2e0d1565,d26394b4,14e2a9a3,95becb69,2111293d,288dd2b2,69e9bb63,4e7fb16c,1fe25797,3c0076b1,aecaa2a2,e57020d5,66bbc7a5) -,S(5e9c7a1d,50ab8326,74c2a5a6,f32665ce,9be97161,5e59b618,587541b7,40b276d7,92283461,1f39af42,34292c61,2c70744a,ec466418,ee08b5b1,a298456d,5fa11f17) -,S(98c60ffa,f486b582,2b4d9ac9,7b320b97,8b52b506,8b46bc48,9a2a4f28,dfed8b2a,a1c26113,c2534955,812f42fa,306edbe5,70416d84,aedc132b,5807b29b,745280f9) -,S(92bfa982,1ed52cd9,3c286e71,f350e5a7,f309481f,d866516c,f0a7599d,c385babc,a3fc9796,c71ab4b1,b7a54e73,8dfe24f7,6f527692,9516bcb8,2fae9ed,b2c1ddb4) -,S(9be27408,bd8eb59f,ace413e8,402b0c37,7b7798b9,3bb18c4,ec197382,fa5b865f,11085580,19646a39,68eed2c8,1bb92dde,def3ec29,5024c027,f54e8bfd,a67a2f61) -,S(27cd6a6c,b7bab059,6b791ce3,8c0918bf,7751bc59,db9e5827,5b1b9c46,976350bc,890d5167,8fce2ac5,f13761df,68651e7,2f41d04d,4feb4011,a16f80ee,83faeda8) -,S(e896e14d,aaf96139,4c8f6597,a0c66463,5f22be3c,96f30e1f,5d8881ce,f468f2eb,beb004b0,512c1ab1,dc4d971a,fd88baca,efea7e84,dadd2726,bb9f2b3,b196030b) -,S(24e2d269,ac485401,634b3779,efab2c0f,a9dd2389,850bb3da,54ec0d67,e53f8ec0,de702ec2,642bd4c2,3bca2ca,663a05a3,f5beda5b,e41fa460,8929aa58,219e525) -,S(97a627c9,48c1c9e4,5d50159b,4b121a50,9b5c4d01,de0a7db9,5a9d9c09,681d1676,19bd095b,55399c29,fcad4303,7f5d5c21,8d5f3cf9,a7c90b9f,fef7ee92,6f3203d9) -,S(a70d8251,e604ec5f,777234c7,f9d3c850,33ed6760,1fa0814b,40bd5370,7195b08f,df28d907,74e23de3,f152c016,ac710d43,85325a89,6a859f4e,e126d50,acbccc4f) -,S(2d676c43,4b276472,ce01a007,13d78b17,27743a97,36f3412e,a7c8c15a,fa42f42b,be28cde4,6ef5d32,403b8f94,1082b684,52fa703c,339498ea,24c08ff,c9fa7312) -,S(f66c25e1,75167275,5db857cf,cf27c036,46c89d29,b4a0d729,28fd42b4,b29cf5,3ee23ad4,22c4a884,4c049150,cd9c18ca,8d2a0231,bad69b6e,5926de9,c7193201) -,S(dba47c4b,9d39d87e,ef44f81d,24e8e005,ce6e77ad,8e4fdc6c,29393d7d,2427060,2d5c6492,e53d000f,977eedd,4dc3b5c5,5240f28b,9fcfb597,338edbbb,3d8d7622) -,S(a17601d9,4f627dc5,5895aeda,e91da3b6,94788f65,f083b01b,bfdf8815,27e10f0f,74089fc8,cfea1b15,afb025bd,99905b3a,baded5b,45e30890,fa3d8403,360a1183) -,S(dd70309f,b84afe90,7e261a12,5fb7ac8d,1c24c6c3,54eb83d5,188f3a13,4d80e141,32014ac0,ac93a77f,9d35b786,2c88ddde,4bdfd566,f6555868,2a836535,44bed563) -,S(79fd503d,e746baf9,701253f0,4c6a2f3,cadefb93,920c83f7,83b57768,87037afd,3c5cb658,63180931,3fa20c26,647a523e,86a4e600,8e8b17f,1e0d690d,eca61b93) -,S(d1aaf37d,77c7d63b,1f4eb896,16a29a4a,1e72658a,93560956,6b92c122,ba0ff6a0,e535b7ae,5cfbba07,2bdf0e0b,bf435bdc,c7cac39d,9d9ae32e,cfd13945,3ca93bec) -,S(68ff1b82,b351d94b,9b6b74fc,2cda4345,fe525d58,d6599644,5c752757,aad93c4f,abbb0ef1,c422ac08,d06194aa,c5d93bdd,9186e374,8518192b,79818f3a,b465a13c) -,S(22785c97,18063e5d,5db73bc,f4ca6487,14393ea2,62ece24a,5c41c059,9610552d,9c08026a,d7a7a80c,24c5e75c,8a75cd6e,1933e64a,25cb98c4,157181aa,ae1d8774) -,S(626cb5e7,563fb757,5f066258,3fc21762,e2678063,a77d8580,8891f244,4f5ffebf,8369ff6,72c3c3f2,43516184,5a9851c1,953a6da2,5662e11c,ce170cbc,668498b4) -,S(a99f0ef4,d6f46105,80ffa430,b88a4f28,61c8c4e4,b6fadac5,5e668f5a,80d12d2a,972adf29,39db0083,77802c40,6ae2aef6,4e2f064a,f8304d3e,28fff33e,b1053d06) -,S(b243ce27,2ff0b2db,cb80a3fb,dfbe94ab,784afe3c,cab3fe61,1931de9,c7f02645,db2ead19,fbb8c820,c7233df8,fea51836,3e85b858,4622be9f,41a0448e,360b7559) -,S(c74e3c9d,685cb62c,6a71b21a,a1dff5,43efb264,543222f3,f8bdf570,4363deb3,987d8261,fbf23d05,a38358ef,c4efb61a,5cd550b6,1e833ed4,38734486,edc4b2ec) -,S(ff2f64a7,fc984d4b,d1c885f3,4c096e9d,d34710c2,43dc3047,8886ef0d,ddf71c47,14c06258,fd5e2fdf,1eec9125,7690c0d7,9eac60d,785f2497,65e1a85a,a06e906d) -,S(7d92c4e1,3f4cab24,d36e8a8b,140f743a,6819b514,f6a19bad,ec162141,bb712085,606b5762,2ec7d7d2,a9b19330,9da686b8,3e0dc920,e6be33d1,b726f416,81b698c8) -,S(3a43d4d,9ef45289,89c9487c,77951602,4ce0cc20,ffbcd518,a0bd2546,fe13b6c,5f24d325,5768905e,6ba28d61,e6b126a8,eedad2a1,53499912,dfba3fc0,d9deb36e) -,S(8e72f02,80105e4d,15cc67e7,371d0c5e,6e59fd05,b3c66308,67342a6c,eea25f8f,94ddc51,58fdb86d,f09870da,47b79b03,1eada5ad,9bbdd509,9ea1d9de,96b368e) -,S(b89cfc23,6dc02762,ca77f9d1,8343f12e,ab8789b0,e5872d6b,fd9d013c,ccef54dd,9c9a7285,45a5996b,4a6ce6f9,df860d11,c3ad135c,f1f7437d,2ba7b904,411141cd) -,S(e85ee008,979868b4,bb190b53,5624b3b5,6744a43e,2c473ebb,c64e4910,41ccb59b,d3afe70f,9edec50c,227e3b3d,7eddd1d,e1c9a8b,f842d723,a8075a52,12cbd6a2) -,S(d8dd6bf2,774d6d15,93cc8e16,d5134066,f7f90651,39915b3b,fb0d5d93,b6cb97b5,5a203094,5f734f3f,11431862,b85e9f8b,25f7e6d1,91512b2c,6d256f4a,535e26f4) -,S(77e081c5,328fbdeb,45fbd554,5d133d84,33968ef,98d36aec,3e6385a2,76aa94e8,2ce853f7,ca25f2f8,45a6291a,3e080504,ba597fb7,91a21669,c0cb6be1,14c2959a) -,S(510786ea,e8a49682,6820b82f,549f07a2,b5b9203d,b1ad18c4,fb9c479f,67c904ab,dc130385,4e4dc69f,f63e21ae,71dc8674,b39382c1,eab1d8a8,fbd96867,af9cd96b) -,S(2fbafeb3,fbdad5b6,4c121056,e080d0c2,1169e433,3abc0dda,bb642789,a242639d,a85d82f,d9e6a14d,e599ef0a,11d3eb39,5ff199c9,5ea5f1c9,2f3f8a7c,14405cd3) -,S(200dbfeb,6e6e463c,1f3fbbc2,6b5f00c6,aec80809,1e28eae6,73b2b5e4,7b12ae0a,4852a219,bdaa3d97,83e1f071,15491827,83212776,fcd1b44a,c59dc01c,bba95ecf) -,S(27b140f6,259f7dc,93d46b6,e52cdb85,3ec22572,54218ab4,1acff2be,24b8a3d9,3ceed09f,70cbadba,d40054c4,f130e312,28bb5d63,71a74f7b,c85aa7ff,c0583387) -,S(fe4941ee,535c5311,8222ec35,14c2b02c,e175cca,d728ca0f,cd1d64ab,e95b7e71,e9cdc9ae,286d651b,d89cb442,2a64ada3,748e0ade,585cb70e,d357004e,e51f56f6) -,S(317d209b,4cae94bd,36f443d7,65be2f17,ce47ced,59935d88,5a03925e,75ff1cdf,c191495,68fe571c,ff945af,4b6a801e,c942a5df,78a62864,5434a5eb,8a262d72) -,S(f951a777,764e30e4,7705f8ab,150e9ab,df32e80b,593cecea,d9f9a143,cc93f9ea,efb951d6,25f2223e,e6ccc6b8,b12cddde,6ac2613b,11ae3052,65570f15,23afd925) -,S(71adf0eb,f5fd8e8b,f0f229a9,ffe496aa,4f251af6,6e5a284d,3091f344,3389c8ef,13f47463,293a5536,674dfdf7,2dc73add,98ed5672,e7676425,39ce655f,6b6969f4) -,S(2ea0406,58c0e80d,499cff39,ad463412,c3fbab1e,81f6eea5,911c45,236be75,be52c74,6073721,f09743d2,9a0a4e3,d82c08ed,feee2234,29163bc8,954f923f) -,S(42352390,4b3e80c2,750c4222,33f0b1f3,a373442d,96278935,d9b7e51,b6182aea,7f582349,b27b5166,30c8e48b,a9603224,fe09e8f,814fa966,395fed67,d9221d91) -,S(524d3c82,a92b285b,96064bf8,e9abe0b5,7702a29e,dc08ce53,771fab9e,fa7dda91,a47a0217,fdc6b2dc,d4b68e05,331bfd5c,366a8477,d3ed894,ec747240,f0f29c3a) -,S(f6ee1e08,5ce04de6,6aaeb5f5,f232329c,fc83caf,d16bcc48,776bae16,c056f7e8,3328b26a,7e2bd49a,aa193977,4947d7b4,ccbc955d,18b27c75,c2f6ac6d,bccea4d9) -,S(9c2f7d2b,b88f1417,722b5d11,95077d20,2ea84e6f,9bd93dae,3134d16b,17273978,1089f003,66c8b435,ce73c592,7c5e56bd,d338a4ca,ee5307da,a571be3c,2dab2a3a) -,S(593a1eb6,730fb6e5,1fd24f15,253ae1e7,5897b7b,48efe28f,9b9813c6,ca99cc3c,fcfb7820,fbd22d91,bc03a630,f74e519,9e35c1a,a3b1cace,40433001,7744f079) -,S(62ba10c3,83a7bacc,bcc4bc60,37f87a5e,8ec0eaff,de5a39f4,ef352b1,51f957e3,c267a1b0,dc84a161,a565fa19,aa0a2501,9fd01e0e,d7a660be,c2a7e9fc,cc7bdd45) -,S(1de2ac10,deae62a1,63f641fe,3a4a9da,39e12390,14a77c6a,6d73c619,5f731f64,60f43c95,b6d7969d,427b5ad,782214fc,a512b75f,a6f50006,d7141a89,dbc8d2b2) -,S(f11a5552,709083c8,83d08612,31772f18,c48e9271,6acbaa6d,a43416c2,fd4e1d3,a6d0ad64,7cf48c41,b6ce397b,38d5b3b0,2be51554,da2f3f4c,df593514,a2d742f4) -,S(f4454640,d75697e5,21d5cc01,fca5c7f5,3dbad43f,116c243d,2aeae96d,7cdc33fc,42972cef,46fe7704,5d6d7053,1a74ec87,6b25996b,c4cf66cf,b3784f79,66549102) -,S(2bfaf073,97be067c,1b7c20fa,3b319fad,10905b8d,8ecdad4,cad2ec8d,a1b8780a,ed526499,ea97c967,3d28bdee,9970f4fb,9077deb1,5f823cd5,775cc526,4e590285) -,S(fc1abc81,2b5fed90,bde3ca16,3422f73a,6df6e058,8ed69222,cfec54f7,4cf5f73b,db1c6edb,471cfcbe,468481dc,4b1cd1c4,7ac68f6f,4fe9dd8f,af0d1136,972b975f) -,S(d838c2ac,82e02f9b,a376f92d,293c02ad,b717d65f,be31cc76,12476e6f,4c506a8d,d87a3067,388f8e0,3c176f6c,a7eab123,532dd1cb,3e0f6ae2,51d7b31a,35189377) -,S(4b3a82ff,7295749,a259d54c,a9a5e539,32c53ff1,33a1c4b9,2f697e06,b13ee38c,44372b41,a788456d,3f66a0c4,6c815210,bf60734b,e570a290,32db3075,ba8d6265) -,S(d77cbbf3,6731ad4e,325eaf6a,9bd52f70,8e79d290,e379c2f2,b8d6ad3,fce411aa,ee466d25,f07813c7,91a81237,748bda9a,51f4266,4a385b50,5259bf84,ff8372f0) -,S(3867f6b2,58920b82,6eca75dc,953ac307,bed1872c,c0f1c6ec,84efc6d2,eeea1483,cc6a6adc,e6078097,a013ff18,dca9c5c9,254d70f4,68ac1cf4,b8267135,af88aee3) -,S(7b008875,e85fc84f,618ea7df,f20f7f17,2123fe98,c07b5279,930b52ef,cc1b0a9a,3f3b30bb,8dbc9169,a5c55a1c,4150772e,331f7834,b50bb904,a8c56600,bf075f90) -,S(ba5b44d9,16304a49,87579560,4d4b796,907e9b7a,4da49a5,ba7a1d77,8e34ef3a,16b49baa,48219e3b,9bae124f,dcd4de,4d47ea76,3ed39e13,f874c75b,cf333661) -,S(691eafe2,7fe4120d,852b3a23,b5bfa646,910fe521,355a3594,342d629c,e2b8d9df,43a06097,42184dca,7c294fd6,a5227dbd,bd71ea1d,c4bca878,1887f9f8,b6c71d85) -,S(13a6cbb,c9f5a86f,35173e38,a45dca65,551377d7,c37542d8,44006e48,54a54123,ecf3809c,9a964d9e,ffdcc2e6,2e8faf9e,8a43d38f,3023c4b8,84d18948,8488620) -,S(33fd2af3,fb595cd2,93d731e9,1b4f0e5a,da665420,2dcc36ce,b712e8d5,e6f10e45,e26a307a,a8bdda4,4b981bf9,808cfa3a,80ca5331,b3a94c31,f6331e60,98ed2cf) -,S(75954033,59e47f78,76b3ba57,5a758493,b0033298,22f4e44c,15cbe58b,34b774f6,7ee9a040,70b8568d,b0a99855,3442c000,b6e6651c,a7ad1253,f8e703de,5e0458a9) -,S(79199fb0,c3b17e68,4e815e7e,8414bef4,b3dd3665,10d032f3,6505da59,6f5b9480,95bca973,f358c9cf,ef3aacba,54a055b8,abaab383,4191a1b5,54ac3ee,53d9a0ab) -,S(9705f4e7,962ece0b,2e7ed64e,a33fd40,6edd0bc1,ac8997b5,d6d70000,a51aa352,4d4ce757,ad4547a8,a126193d,8921d6d8,58f40855,f71ab99d,b2bdd728,499ff347) -,S(881af067,b841ab5f,30560b98,3376674d,cadeeb75,b8b16e12,df7da3ce,312fd777,ccc13fd4,512ef05d,7c10f62d,8b144b1d,7588be3d,1a3a3701,9accdec9,3483b84f) -,S(fe8f7a44,33c2c9d8,f42e14cd,97ad0794,41bfc3b7,2fd412fb,1f6d5f5c,10e99621,e5b576ee,cf34374,96dc4ee3,a846c79b,4c8babf3,cc46a657,2a93fdd4,b6b3b2a9) -,S(ff43c8da,18e08b38,3f92f832,3c34e83,84f40064,9e0506cb,91893abc,5c4d798f,a575a059,23a9da02,c0c9dde1,981dbd86,f5a75433,a4bb2fd5,2427db01,7ddf2e7f) -,S(4715056,b97f4e21,13485242,74bb1b33,d8f9d841,73678a42,ed3c6fd5,28db276b,b4c0d146,3521f1d9,fe8cd71e,fb98aa28,73a18bee,66fae12f,cabfa201,854302b2) -,S(85c9d808,c5f51d5a,c2a51394,cb83e7ee,acd85eeb,31a88814,9744871c,271fff51,2a7c3bf,23829b88,66991454,d6ec7f5e,185050d,1982deb8,b4992bbe,5b666a7d) -,S(c02b94ef,8b1e368e,3cb4b25,903445cf,f46b60c7,6d6d2f24,529997f9,7d70dac9,bbb97d29,bcff81e4,8d417825,ade1d28b,10fadba2,acf961d6,80a343c1,e725f3a0) -,S(4b1593bd,28e26f7e,431ac439,3d353a1e,fcb8b63,fee7adb3,e29472a8,38241df6,8a67a728,f4966855,26225b11,3ac9d858,3f184f8b,3ccc8ef0,d6e4e34e,f2fdcc56) -,S(f640755b,ba51dee3,ad650555,9d52869b,7a8e7f6e,4b9dcdd2,31d1cd4f,26a64dd4,7387f800,a53e290b,d4c29f6e,ec24ac07,91e0e3c8,55d14882,a48d0539,6e87e1c8) -,S(949346a9,436836c6,3df6f42c,d708cef8,16d0a522,914a606e,2276979,7789515b,a903932d,952a0201,ef65c847,b8754174,31dd41d3,ede5c073,31383b9,a8e2b356) -,S(1824099e,c769edfc,2390b1f6,698c22f2,cdcc9783,c5cbe45c,de46008a,67f91a60,f8405fa,81e04dd5,6ce051f3,bfa088e2,804a8780,37892ae0,adf42767,311bd1e2) -,S(e6b46fd8,e4633d92,8805f34c,ce95f3dc,683aa792,139c62f9,2ec8acd1,d601d341,533db813,f3fea63a,528faf4a,7cbf58d8,d6c0bea4,c28391d1,6391d300,cc1d824a) -,S(63799b30,dc19b18d,d48d150d,3d4139d3,a04c6252,f176015d,60a436cf,ff992b93,26205112,5ebf4dee,d00e72f5,ff064178,7f485cb,2ba35507,3c3cdb0d,16dcc41b) -,S(8cd02f5a,b1d5a02d,e85b88d3,ae370b0f,7fac5324,9f1fd676,670a29f1,2ead7338,358b42ac,ceb689d6,612cb70f,bc9bba7,511d56ee,c4390627,8e2f0961,bcc0d8e4) -,S(d5e167e6,d48bd1dd,e95aba41,bf33b065,f7612766,4a0a8991,d3ea1a9e,ddf82fab,6cc23982,d653cdf4,fc4ec9cb,3cd86ae2,aaf45f62,38257d70,849c2686,ae71d1f7) -,S(c4073500,6987f2df,1334f09d,97f00c19,d72b1942,5864b0cf,4ff19dcf,7c9bfdba,f6566846,6b461326,a9b366bf,30378f82,b760ff0a,ca568ca8,2bf0c9d3,ff7ff262) -,S(9df1e71,9c501bfb,8a21db2,a838318e,29a7c2c0,fb2deb91,1840c7aa,f0c4fde2,cd628cae,6d0e0c02,b0315ae5,4901e703,e977c75b,43defea5,80a5325c,fad00fc0) -,S(95176429,df73c309,23108ee,6922c597,1c91c249,ad7165b,7d08b84d,2a4c696c,3ecffc49,3b62dbcc,82208470,375c929,1994fbb7,240740cb,dd8086cb,e9c0fbe4) -,S(708c48e8,692b0d35,e13a7e0e,94be8fb6,f57fe187,34f5556d,a318f600,c5628c6e,9534e302,deee1d1f,27e0432e,9f6a2f00,5af7e601,3f7da9bf,e1cde320,a105a664) -,S(2775e17a,b82dc739,b5d62079,4b26be15,46275ec0,9d32622b,2991cca1,4e5b4c09,3aa6ee7c,80e8359f,deeb52c2,8da1328f,338ab228,8744d52e,8a9b7908,1b1ccddc) -,S(47c1aac2,39c4f31,cf334959,b8fb48a0,44da6b34,3c383270,be19229c,30192da,5dad651c,5ba6c21d,845cd402,59a051c4,e5813f5a,21228355,1fde158b,600d7cc0) -,S(f80f445a,4b864c96,1bb2bf5,9cfa25f1,eef459d4,fa28ac70,d77daa1b,b8bad15e,a383de04,6b8c6996,6d0b9da6,ce9f88e5,83cd57f4,a5f12c88,63f7ff70,b374ff16) -,S(2924e7b9,1ad33619,a8df436d,578b7172,b2208125,9f2d5bf6,f9cb903e,bd4d2f66,b8642169,e2319f54,348e4f3f,e15d1f06,afa41255,ad62ceff,a768bdb8,48841875) -,S(37d6087b,91a64ed2,8341854e,3a2b9ac4,4310785e,77e32e2a,f13405f3,76dc4d83,35a23917,e068bccb,a823092f,32e6fcdd,a3ac9f09,2c251b1f,9bdb9971,3df25003) -,S(d748a96d,c79f1be0,6b43691c,bcf84b4f,e000d2ce,8294cfd8,391dcb92,10f4fab2,75b4ade0,65da902e,ce57e5c0,4b817228,975c0927,aafb76c8,223c4da6,f05bf51c) -,S(d05d2a25,eb5084ff,262361ea,33b6fb97,9492414e,c255fa8f,a0233d06,e42cc30c,14bbbeee,cecdc8f3,85b51429,8aa03d9,ba57a198,5ba98f4e,75efab60,69a6f2d2) -,S(69ba995b,d137edbe,5aff3906,764eca9c,b4684bf5,e8a8c302,78c89d97,483ff793,2b1cf451,b6226596,9833e864,91c5db95,a79ad96c,701580b2,46de1936,5bb63e32) -,S(7f01e9a1,5d0ecf28,fde0342f,f506104b,3a50aff2,f1ec997d,9a82ff71,54419461,1c3c9594,a6b8d375,361e25d1,fedcab63,d2704065,a83470e5,e03dcc43,ad12dc68) -,S(719232fd,193b9041,fd201bc4,7184e4cc,f2413d03,f0f8619d,813a409e,56e48cc6,161fc718,7dccb053,5337ff60,9eae05ab,12fb55a0,65f82d1e,68b19d3c,ae29a953) -,S(15b84120,155f7310,3386009a,57bd28bf,9a63bcfa,46c8bd08,2f53dc86,76e78c27,47dd637e,c9017e2f,e9804e0c,840aca4f,188171a0,ea9fb605,1402c503,31737816) -,S(ff429d97,bd380047,7db52ed4,eba69914,4a95ce2,7414da2c,74c074,bbfec567,7b3a6fbd,6e635bab,34973f62,4df77c03,6708c00a,cbcb8f25,69a5aa01,d57b3048) -,S(ccd705b,16be74c,cf1f476d,12c77e81,37917404,b2611ed8,858b1e55,d50a6ee3,8741ade7,5cc7b252,4dd55e17,897f78d6,946cb4c,31ad9f1f,737affc3,40e87c01) -,S(65b61a5e,24b3c57f,91678e81,8300ecaa,94e4b406,8d499534,d54c37d5,bb65b27,90d75e28,aab97b82,f1b86fda,2ae0851e,f65ac4c7,a5c664fd,79c16a76,75ed0c40) -,S(671529df,8f4073d9,43f82bdd,758fb8e5,4ffe0487,c1a38cf1,73c1419f,7ba06ef0,c46d9f2d,1f23349a,dd1121e1,d51ebe4,454fd141,c7076950,4d854cfd,14fede59) -,S(2af8a76,e7a1697,7af8e70,30bbd2c0,73da3fdd,4c6735b6,8e823cff,901b0440,55565be7,9ada7153,c7165976,91ee33cd,7c34f5ad,d65f543f,72ffd026,26c3c1cb) -,S(acd81d6f,c5ffbb87,4fcb3b1f,b7cc730a,4def3fd5,ef59fc4,2fb9472a,6f575707,8e319a8e,c8b8ea9e,11ef47eb,5071b696,b87c0ec9,63e851cc,e0929646,1d181a3) -,S(ab77e7d5,3ab9e8bc,2052d0bb,360aa7f2,ae062ca9,9b91441b,d60ce8db,80ffb912,5f92b6d9,cb0ab95b,9eb992e5,e1d70412,aca90998,b5d6ed8f,dfa4c752,2df96b5a) -,S(798b8195,1a6a8c7e,f8beda09,b06a2303,1d7efaf3,7b663265,e0188ab3,78124046,9592da1b,baea430,3644a7e5,4e67476f,d91382b5,f1181de7,a1bf9d44,e02b1bf6) -,S(f2486aae,c3be77d,8dddea22,488aeb4c,9dbff93a,24ff6f29,ed6d528b,9777b096,8e2b2d50,fe75c847,7c50327f,e36afb0b,d8409b62,8d83a8cc,41325aa8,4829126b) -,S(222e3d09,3b8aea8b,e0f64ee3,3aeeee72,d16ca088,264f4333,f9397488,146d2d54,eff500f,bfe6bbc4,1c2dd16e,8a0ebd79,37ba1f78,ccb098a4,351b539d,cacdcaa9) -,S(6768d3fe,7ca93476,245a18ee,ab53e002,4f99241d,9c321bd0,165b7d04,c121c1c9,402c9d73,c9b99722,2319ff1d,9e1c778,c4dc825,d030a43,823aee8b,90272877) -,S(6eb6740f,b2f0880c,eff25697,bfd7815d,b0b62884,cf8c8ef2,5137f098,f22dda79,cf7e8531,c12f5713,c302061c,1f42e6ac,79c4b695,e458db68,5209f03f,1485c86f) -,S(7101f348,4eb05a7e,aa0f385f,367b6a7e,5ede8959,71729ac2,950006aa,965fe51b,8d1fb913,a040fb75,778fff9f,c71afc2c,2605595a,1e44944b,e264f893,10d5c3f3) -,S(75a9e45c,acc6a25e,3fe4b25f,12030362,a0de03ea,cefba87a,11c8e6d3,e886579,52a85995,e91986d9,26a02cf3,1001fd82,854c49f9,55683f7a,dbe7c02b,cff69c6e) -,S(31194d92,bad76572,98bffc54,27f99ade,ceac14f7,830ac1b2,954d6730,3737dcbc,99e81c45,f5318eee,9d2449fa,33cc5bc6,8c556ebc,dac2ef19,a2d1ff3f,5fdd2832) -,S(904fa3fe,76fd6f43,86ac6138,70b4cce3,c1d743c3,8457d23c,522958ac,bd505af,94273262,1adf4633,79e929e4,54c70595,8dae9bfb,3957a304,5c8aae41,a7c1763b) -,S(1d1861f3,1a828b32,3699aede,f3fa265b,40de142,78a7df26,b5fa93ff,a4a8e0fd,b9657781,f13ffeb2,8e1306e3,b84bb965,3ffc30c2,63a65f61,1995f44d,d899f7dc) -,S(3bd33def,6de1a5d5,e5ef0289,e8565dce,aac95922,8443c09b,73ce545e,6819ad64,993f0109,eb560bd4,97436627,9a70e9bf,8bc9851d,f52441c2,97535ed5,d4f9c810) -,S(ca1b7d45,2a39aed2,a7f27b24,8e5a07c7,e4c257eb,7150e61c,7bec7f6c,58958634,ab11fe1b,c0357c37,b7da9804,39fb5481,179c0f7,442af2c7,298facda,3c4afcff) -,S(273a95ca,dee8386b,53ff29a3,6ce7d9ac,df145f7d,5f928f61,da6d57d1,8671aa58,88a6359d,bb06537d,1a6c6d83,24065284,315a031c,73c53ac2,adb14f95,1a5bbe2b) -,S(7ea4c0fc,a139bbac,553ad79c,d3921c01,c06923f5,29446279,d0f910f9,ac5561e6,bd049d47,45830e2,f31e7982,2639f198,2eb71c37,71aed93a,54dfa0bb,296dec96) -,S(71f1801c,a2babe5,d4793240,15ccc684,d3823f68,fcd12ce8,bc49607,9607d336,41ed07d0,8384e54,209b7de3,7e8fe7a6,14430c0e,439dca6c,f5ae6ddb,1ff1b4b1) -,S(b2838873,652ba1ee,ae8aec51,55541a3d,7000ffd9,6279cf2a,1c90582d,21cd8828,47ff155,73f5e3a5,245faf65,86afcc31,ee4d19f2,a1efc79d,2a0b4811,d27dce5e) -,S(34ca8da7,22634bc1,6873fbdc,c089224b,d9f8164a,6bf0acb5,b68d898e,b55a3e21,d8afb760,36a9c91c,7769055,d85a3ff7,1f041a90,5192df4b,73f9100c,e5c5d986) -,S(212cb397,d97341af,ca0cf5b2,ef6d796b,4b76eb87,89c3915a,a0e72337,4b19cc8f,f06e2cec,5f29f06f,97685f50,1126c50d,ff17e273,2f78de64,875c35d6,42f170a1) -,S(bc0367f6,43bd13dc,32582dfd,e7893f69,d5f29d2f,ce4b42e9,ffa8091c,6ca6228a,9bec6c89,d1251f06,4aff3e44,ab59ac32,c1764179,7b96f73f,527ff429,74556e78) -,S(8fcb1423,5d8e8894,5ab169bb,4d198e4a,5e489e33,cdeb69d8,dec100f1,a9bd5672,fa1cb396,bab390b2,60302a46,b4408427,c45ae320,5b1d1f5f,e52db790,e7fc057c) -,S(70ad8505,6675ec20,cbc43e80,11df60f4,d4917e84,cca25044,e15c2fa,e51e64ae,f4a51356,af9fa7c9,a5e62475,df5b713a,b63d68e0,cbef44e8,c004fa61,1d5a800d) -,S(ada7af47,48074168,86e6df81,f9718c06,bcf6e6d9,846fa880,3ede1f6c,b9695842,f66d51f,50f427d4,dc748bbe,771d952,98369c91,c41dd,575b76db,988a582f) -,S(f1b87d8d,7323ebb1,1bb8108f,9d34f8e9,bf1e977b,a527c52c,7f045d8b,1102eeee,bd95703,51ebe7a0,9ede5842,47b755b3,7e2aa0e7,7e380b7,9bddf768,b4346556) -,S(93659d5a,d55264ea,c900c301,cfed7b83,1fbf7c51,766cc833,cc591356,492a0553,b69389e9,646d0165,afa137df,1c1d02a3,519ff65d,8856c89c,cf46de05,c0154beb) -,S(e9d2bc49,2a9b4ffd,c482f54a,415beeec,409a62e5,d1781f48,b1738f7d,8ed4ffe2,893e4652,2dccbf80,ddde313,f4f25383,8d639208,36150631,60830408,44305df5) -,S(1424160a,7bf1ad91,18103eea,372da6a5,825e0bc1,a8760744,229e2af7,906cb210,c94da226,96a75d71,1e6f1d0e,10b23e96,4f1519e9,1f63743f,209ef8a1,3996af23) -,S(7f902712,402e4bd4,aabe434a,eb5fa7e9,8686d058,e6f26300,c458cee8,9c9efd87,bc00460b,2aefb418,b16cdcdd,c88446a7,1b8b018c,15261602,669188ac,62f95fb5) -,S(d327ce7c,66cb0f53,e86e5f16,c8dc2936,2a133f6a,38147c01,255c61f5,6f72745c,4dc1498a,c3cb39c1,6908b85,b8c52dca,618cc6d4,1c6f95f8,353758a3,86bea436) -,S(f044eb19,c9d81106,13803b,e8bbfc31,137dffce,547bfd1a,d5396ad,e32db3b3,5ad4428d,9c4c3e66,7f8551ce,ab282cfe,8128a8de,ffccfaf7,c102b9df,7e526f2a) -,S(7a6c5237,b95d19be,af46a81e,bdd54403,d135bbb7,f3c03d55,f67c5cbc,e18daf4,62a2e8b8,47fceb5c,484fc6e7,4ff68fed,bd492c66,8a70c1d7,cce2922,a204385b) -,S(59c7fcdc,b069c0b7,bb772afa,f5c20846,ffae949b,47589bb5,80495bc1,b59f82f0,82ec588c,6657566b,71ba4d79,ac8e2c7a,c09b3652,f24d46ec,3358eeba,126c38ad) -,S(f8cf3c21,1ed4558c,c40d3dc6,dbb85e54,81d99fdb,cdf27ae0,ea01bd4,6b6543d7,bd8049d0,1c3df630,8951f5db,dcce3043,5506a5c3,e0a8bb20,54de9dc,87a9778b) -,S(3855d764,b2389d4f,1ff47189,33aca82a,4d2dd23f,cfd13764,2782ce71,524504bc,82c4ea25,4af2abd0,2724ec34,6aae3aa3,b14a71ee,df13df95,9446c0bc,759ef72d) -,S(77644b31,1de4f0d8,d30b1d73,35553dab,6d3e0e6d,af7e6ffa,48cddd1a,52de5431,645e17ce,c0a0735,737730f9,92bb7431,7581c930,695829b4,cdbf5214,f45916b4) -,S(a4d4af43,afd6afbc,b2a511da,a6537abd,56bfc0cf,76659d34,56530663,d9ca138d,be6c9fd0,dd2df31b,b907f073,7d63df34,88b5db5f,3d5ff747,a25a2beb,73bb09dd) -,S(417ffa3f,e673a081,f72c3d64,5e64bc61,2da352ca,fb66d1aa,aa8fc060,74a75be5,9ab8be2f,90849474,809472af,d5a7490e,cfd9ca4a,7f738be1,de093e0,68c50151) -,S(78175154,93115041,6cbd772c,c74212c4,4f19eb04,95e88622,f75ee838,caef73cd,37d4d5c8,ffec3650,26381b91,d7cb18de,fdaf2cb0,a5d94ac2,dd7bf7fd,34d0d3e6) -,S(365c560c,3acc28ea,f560c66c,7e76625a,3c2ee7a4,8f62ef0f,736253fa,b1b5121,25cbc6fa,96c0f15e,38b03f88,338f8dd1,6990aa15,dcec58d6,4517d37c,5b74868f) -,S(c945ad25,1010023e,9126b6cb,3a19a925,6c6757fd,d88cf808,a94fa182,8f5bac7c,c9a8e90c,b4ac43bc,ef08ae3d,fc66f6db,99df4abb,2679de5b,174df92a,d654e2bb) -,S(4aad85ac,45e6d57d,73822387,632863de,ac8c3fb7,b7d3beec,629c0e1e,2c2e0213,38eee8e1,9e81bf64,9641c192,de53a071,29c03689,376f6595,2130b63c,fd6a2708) -,S(2bc10248,b0f6596,adcf9f66,3f624461,907e37ea,7d35367f,24b9f69a,26a291df,e0ac3ed3,3016b37a,91a780f6,b90b7743,24ad0c30,50812b2f,4f35426f,4311c79) -,S(cdc05991,abd28f93,e81a2c0,9a04e1fa,eca89400,81fcfcff,eb91c8d3,93ddfde2,dfda4ac4,4458e2b0,3feb9852,d1a8822f,8bf90a4e,bc79ab32,afc9a1b7,580193a5) -,S(5a24eff0,af2dc429,ff4ea857,f8aab10,31d285ae,9c8beb7d,793bf9d,db46a047,179db914,59739160,897f40dd,b7af0b8,a98b6f61,6aef7327,b53b6005,9c4c8f9a) -,S(16c1e53f,51603ca9,374aae6b,57d15fdb,e7c1d2b0,b0545467,636fe2ac,7838183a,bf858ef0,56e09bbf,5d8af50c,7e0fdc90,8d1f6c1a,570594b,a5368976,63a183e3) -,S(792f1eea,71b92f9a,d893a116,ac177801,a2f2405b,1c6846eb,c3a6559,eb01ccf4,bc062f0c,c610ef39,311ecf87,a7866b9c,52c0df0b,be1e0129,3ccd0b7a,2832a79d) -,S(1b399c40,f057719c,f544dc51,51137fe3,917dabac,f0804dd7,335ba65d,a57378e1,4d6794d3,b6e8a085,41de872c,1dd333a2,bfdd0712,aa846f6d,380a775c,600b425f) -,S(138b313e,b9c45ced,e0cd8219,b888c51f,9f8cd278,abe16ede,c210bffa,ba238e4f,a199a357,cbc8042f,4b6d4951,2f0acd26,13f0f76d,cd6dbf7f,d9e8723c,e6ac56d6) -,S(3e06c311,9c765664,d0068b24,cf4ae1a4,8f401811,17c93122,84ffc24d,eb542338,63a65596,e5607f1b,6a9c4596,39a90d06,93b08ab3,2807b696,498e7557,673624f) -,S(3f32f9b,49c88932,574e5455,c179e9de,80f0f6de,ed1ed25f,8a3de8b4,bbf8bd2e,a2d2bb1a,5fc96f89,ef490257,bf42a9dc,91f49ce,e2b86472,8551fa6b,6a589f17) -,S(89adc417,ffccc50f,a129602b,f5b1b82a,2c4f5efb,e3382b04,1fe77299,46414ec5,4ce7e75c,291b751d,155c291,5aa619ef,6c3daa28,25da8bc8,e2c7ef54,8c253215) -,S(f33fbd62,6bec8c9f,6597d486,2f54f65,e9f208fa,7c1d619,a13feaae,5ce4e9b5,c8f0602b,ebb9f152,87fe2eda,3050b032,a6f43c8b,7726825e,df02b424,51593774) -,S(eccc8ab,7b90e2f7,e45f7703,a0e97406,117fa04f,4512071d,568e3e64,a4a7d6b8,8456f705,a9c4a0d8,f2f3c233,3c8bb367,fcc8a645,f1fc560,48e1699a,58a1b6f4) -,S(f6962b33,a7ad862e,58181c75,42743ed0,e6e31d5,4df1fdfc,a4e3e95a,157de915,af3d47fb,48515ceb,f9f7e8ad,2a0159aa,55c155a,83359cf2,9ee3202,ea9e6605) -,S(3f1f3c6,7996fb10,65ed5df0,2095926a,5c45d2f2,38ff59e8,42b9d234,daace24d,d585c9e4,f0a29f0a,28e3c30b,22228dab,73750706,5690811f,1104bd4a,6d0ea28e) -,S(fcae019,36290e43,d8bf93c1,6ad2cd5e,dc33592d,4081b0e3,4aedd451,6e6e589c,8e98579e,cc42a444,2dc710d8,8cd09996,c8acb958,b9702c24,3a207ba1,471165cc) -,S(548f27ba,355229d,23b7922b,5fc8efad,abc4247d,baa312c6,d89570ab,151f522c,e5597d8,bbb47cd7,c8cba774,ff37c81e,b7b63c63,39b9600a,cb77f1b8,86ab6fa9) -,S(e2f64914,e8bf347e,d465cf1e,f086b7be,49797db8,611803ab,6e439bbd,5c146fa0,8e69e76f,7c641e4f,15248257,77aef9b,88b27a94,72d565d1,d2ed7463,fc6ae76e) -,S(8c532a0,2d970c0f,1d8f9762,2298b40d,c7d362c8,f38cd122,2cdbeaba,2c13db1d,90f8a2e9,428d66d,9e8ffc9f,bcb7606f,568251b6,2dec2768,1b6ffa8,7062bd0e) -,S(64646efe,e3c51972,f6af7e0c,8052aec4,6fc0ed97,af566f6d,3c323218,62291a23,9e29e150,f6ca370b,36a76ee7,171f2ddb,a10eb88a,986ffc50,d6c8f4f7,287a69fe) -,S(6e8ba4da,1df8dff7,cbff69a,6ef65c9,329199bf,9a67d1b5,1eb1e1f3,473be659,ae7562c8,959441a7,35ff2188,3e537bd7,eb5a34a2,7e144a06,f674679,815d852a) -,S(8c21abc8,f7812c0f,6de0d7e1,cadbf1f6,c94c871c,d5b8e9ca,e76c1f33,2b6bcaef,5a7c9cc3,13be03e2,5410ed03,7e0cefe9,5a36d6fe,68ff46b2,663a0ca9,747ed53e) -,S(ce0e383a,7c487e14,26636ff7,657a28f0,10ce5102,1eb89fea,3426b269,2f9f6353,3f95a465,d43f7804,2804e9da,4c73c8ec,97fcb9f6,fdace280,532c0c0d,6232e03a) -,S(7e33097f,51477c4f,f4459848,34673fc2,8078b6c7,c01cb700,80a37ee,1d698eb8,c1275bc0,7317c679,d881d274,e49065a2,e282b7e6,970065ad,141c1ca5,ca2d75a7) -,S(ef4d9cd6,b1487e61,fb31cf42,9eff2731,d686eb66,cfb3f867,9317b0e4,116837a6,c4f6beb4,280ddd5a,24f6461a,6ea1eba2,3bd2ff58,7ff612ec,d118b76a,3d63be1f) -,S(f3edc145,2ee49324,f7890bcb,9a5f8ba3,ce53f4a2,df0c94b9,92c573b2,f3716290,995446ab,fbc9b27a,8db301f0,87c2ae93,5c390565,491c0dbf,552a9820,d3fb2f2d) -,S(c1f62251,7398e914,d6134160,318d20c6,87d17427,2bc62c92,bd170ca8,2bcaa975,1c85ae27,36735b76,d5328d59,3292f718,f6d6da52,1c75cab,fcb06720,87769e99) -,S(a7e81df9,605f0881,d4856153,3e310715,b206c601,9a55b889,7141321e,463dea8e,3ae220fd,1f361be0,f0b70dbb,a7df796a,eb23deb,5c5440ad,aa16fef9,7cae8a4f) -,S(1b69bf29,8f5df296,7a3ac028,87d4ae5e,f46af5ac,5a8cf326,2fe7282b,e46a536b,c9c624aa,2d99a71,ea375c68,419b38a2,d7e9d7fd,8880dc60,28c24f2e,a846a91f) -,S(cddfef74,31763b9,8df15cb9,6b3b3127,b31c9987,fd17251d,b56122ed,dbbb44bb,972fef4,2e935aa3,4c679ce2,6a32a38c,225f0867,8f780b65,854459e7,f24869f5) -,S(32fe1cef,2c8a5163,66b47d30,9ef01e20,ee07f235,e7c0129c,fcb70fff,60e957ff,9e861731,bd376124,8b33babe,c354ea,3d13b2c7,c45b436f,e754edf2,4fb4588e) -,S(a382fbe9,f4914119,d31d0ccf,6afb61fe,4a759657,26556908,505225b8,79c24b0d,aa300360,39a1bfdc,273e0287,c7c222fe,cdde6318,c9838a55,5136cda8,d2111857) -,S(b53b5439,9ae330ea,e13e2467,7c0344d,59e305a7,96a228bc,6d6914ec,1a80ef88,99809053,8dfc6c5d,748f43cc,8ba8a8e2,969d8d1c,47551a36,8f30ee30,d5fadc7a) -,S(621b5253,f11cfec3,fb4bbfed,98b0ad9c,710fe2af,6aedb8d,f521d0da,fb64169a,2a234dc4,8b716af6,22dd025b,63e05c5f,3b93005c,13614bb3,abe0dbe9,260378aa) -,S(83332b6c,cc9c3c7f,3163f442,80f5758c,1e5979fa,b9a500be,d5b315e0,f9435b04,85360612,258c1f1c,bda41025,c402dd84,60c77df6,8762d2d4,16aa16af,dcd30ea0) -,S(27c8d8e3,91202622,2f72d926,da01b10e,fd54e21a,7a4746b6,68aa868f,dbf6538a,88768e3f,b8f2484d,56c9fe83,fde0fff7,4d0c0a81,213ac090,e90d2b42,22d6eb91) -,S(f349c70b,bcd82005,2fd2e05a,c42556ef,6ee768d4,f08b7a91,55d1ebfe,60067e5,6d595c19,4011d050,c7c3c4e9,e7aea90a,93fdc5b0,71d6c9fb,9f621a4e,750c6604) -,S(4966567a,b2029966,62b1368b,ac3f89e1,a0183b20,173a7156,edb827a7,13b24f90,6ef89436,c2bb3bb0,94910ee7,6c083e35,a097b859,16658947,1f59c33,37e21ab) -,S(4909501b,491da13f,78645b84,9bc63fea,75611b76,5ff6eb6,9a7414bf,913e0886,2c20c6b6,f2ee070d,c1dd4c95,6822ac5c,38b1acf7,5e093f17,c54b65aa,81014df8) -,S(1ed2e667,f5a2d140,18cd3ee4,f4163f7,bd5f898e,ee3dda72,bf84e356,10cddb76,bb4970c5,64fa4cea,e204babd,d869e36e,934810ef,68a22794,f9919e3,26db8e7d) -,S(c47bab41,a0bc37f,addf9c8c,7de86d68,c15d1a0d,85257d57,2a1d60d,4612f17b,e52acb1,36f47de1,1128091a,1a3cc3e0,e84ce767,cf8395cb,b09eea81,a2db09e3) -,S(e21068c1,4993cfc4,35490b52,5ece7657,f70825f3,dd2138c1,8f5ec6a0,c67a7394,cd610137,d48f8d9b,2bf99755,35fab6fb,65360fc,9db04a12,43027083,c732da) -,S(635f547d,47a72f5e,b069e144,6508a46,bd6a6f,11eefb87,da07e4f4,3ffaf917,8ea0a9f2,3da273b4,f324c8ed,81cb0bf0,21fecb57,54eaa642,21736923,2be64128) -,S(24632c0a,8648b4b1,fff2f79a,b3f8e64d,3837b6ae,9329eaa8,48565f02,45bdb47b,9c6d0788,c9e155d3,3c260360,862ab236,177ff875,a3823179,8146e442,f66e0426) -,S(43748dc3,cfb229d4,8549cc56,ecbcb01b,146541e1,5d2c3b5e,d59fbf7a,6b7bf503,9975a1ed,23a09906,3b87ea7f,2ccd88fc,b20607e,1aded9a9,265f34c1,45fb9c5c) -,S(8f848323,b8c41d68,31603b40,69be1dda,bb8750d0,11527a58,4bffdca,c3ae3ac0,77a8ac87,128260c2,86f5805a,b17e5a45,be81f83a,2a575c6e,2c88288a,c2d1b37f) -,S(29ebc368,b54d846d,bb5e8be4,81c19c80,2d8907db,c54412cc,6e2952ba,2948422c,e6b793a2,81d59d90,53aeb2d6,f79cbd1a,426f79a1,6860310a,ec72fe26,37c7e845) -,S(9414cbc4,ccf4012c,8c0cbe21,eb714953,d84bc602,9f8e4810,5ba79967,23ed345,ad1eeb92,89e4a109,2d132790,ece35cbd,da45bb64,bb6ae72b,39b9eb80,d57fdeee) -,S(1bd8565b,769d0024,613ab814,90f214c8,bea90a5,db1e75d4,11ec3dc7,288f756e,c050a46c,fc781e91,b79cfcb0,2abdae50,b69c2cd7,dcc56b13,1df2175d,c1d375d8) -,S(4f7584c,35ad66be,3d409154,eb8ded67,14ed0ae3,288593f2,76cec90b,629cb01,f4be9248,232a120e,11ccf1b3,e9c5a17e,1520fee1,8f1da048,fb01eb3c,17712bb0) -,S(5b0009de,7e85b317,ab127401,fd2f3ced,cffd1684,c4772b35,2b9c783e,1dd9f13b,f4585704,f531c34e,3377cb7c,e672c78d,cb8839be,ecfe048d,bb412328,b973ba64) -,S(c66f31c3,79396f01,2ea5fdbc,4222df38,37f85353,3f3ed9c3,ad13bcac,63b32815,7d7b808,4ae5e9cb,c123ca86,1b505242,4113ee84,bbac5ca3,ea1cd3da,6eb22668) -,S(33097f5d,c8b09934,26ba51b3,ee99e696,3d7ba455,e91a7af1,a57c85e6,5e63abd6,fbd26b3b,200c189d,c8b9e120,61869766,987401ed,66e4ed80,63835922,c270d7c4) -,S(1ace5245,a3b7ec60,b9a922d5,ffbbe43d,aa71cf0b,84e395f8,c37dd2a9,c85ffff4,72c0ed67,94708f9b,f29c51cb,b6cbb69c,6ad3f4d,10d62987,1c444da1,bb25084f) -,S(bc197b9e,4cce4c2c,bfb22524,93f9202c,6ed54e32,cd52f512,692a5af3,6b0c4471,d5137663,5182065d,a4d6be56,cec50889,3cad9b95,4d5d17df,adb084fb,dd673f70) -,S(66997931,334bdbed,174cfa73,3ecad896,13c6f500,b79a7fab,76ad0bc8,dcc7df70,fdbd3301,948e198e,ee3e7d3a,504ac560,ab00afdf,26940331,d49bd2c,6599435a) -,S(3ba86cdf,b38d82f9,7c20b962,103f79a,5637422f,370b08b3,89083cc3,1a6eb4bf,acec9811,76debb13,9bd7f981,9b476e1b,5377e32a,bdecafee,33dd6ad2,3258dfc8) -,S(f62432f,9db971d8,4c3acdbd,c2d915d6,6395199f,76e81243,fed930db,ef1603cd,ee89cf3d,177b4cc6,e5856acd,5de8757e,82269f4e,eb11a444,c2e0c797,4a7b5f28) -,S(84b41bdc,6a6dea46,ad6e650,5b280a1,b6d81250,794e0b1d,688aeea9,c067bbaf,9f78703c,b535b4bb,2b88cdf7,b5f0f0cb,e452fe6e,5cd0f2b2,ab8c2439,9fc00e7c) -,S(8e2dfea9,3ea64a14,e28f4883,98b8d455,48c52ac,a5399f88,28a42c1a,c89d4c67,fec01549,cda53605,335df10d,d8ed04eb,e09d7474,f69deff7,5935a499,f2781271) -,S(c3bc6dae,5401ac1d,3fd75e36,4cbc2fa1,dbd2f6a2,40e912f1,18b27759,9b105e0b,170fdcf5,5b739326,fd234506,303700b1,9c5dba48,b6f0cc34,a650c3f,3b63d6b4) -,S(33093e93,1b1e52e7,ac5a289e,27ff810,c2defced,e935795d,a10ecc89,a3c14691,7fbba584,5bd55ebd,a67dc842,1ae10fb9,2114f0b,d68bc47a,7ee87a7f,70deec38) -,S(21b35438,b6d1a3ce,6c765e,dc78dd89,3f121132,ecbcc208,a36fe734,d8141ef9,f6115a5,ed237dc8,f61a82b3,66fb508d,e2d516be,3b166a7f,2566bf06,eae300d0) -,S(ced66583,aa1bed17,30248edf,28e9e4fb,ade70821,1c2e48de,3782fc6,d3892df3,4f43ad36,f29da03b,f0fe634e,3c441c42,c3a81835,2407f1b6,cb38e738,18fdec96) -,S(c5a74420,f541a8ae,b0673122,29fbccaf,37f6eb7c,ccf2bec0,23a8573b,ee6f71f8,ae634c02,44263d36,c00a6e25,d25fa592,1612a535,4934d709,6c864865,60adb259) -,S(304a048b,f30f6b4b,2a725521,15b15ea4,8311c51f,c4cd212e,f0a4bac1,48b9de9e,8f935900,3d6ebf0d,129cb5dc,8a953fab,11ceeb85,b2123fec,154b065e,63bb3cd) -,S(ff96b5ae,7eba0af5,ac9875e,97811e91,6ecb66f1,3bb06519,72ebfbcd,5b9c2048,24af2186,bca71cea,e58a0b1d,b56aed1b,3de89cc8,70fd4e3c,31919e2f,6352a887) -,S(5909ce1c,df732eed,4147243,76fdb3ce,8b6d38b9,4a0b35d0,50bdce27,b1b701a3,2e44944,665e761,825cf223,90383a3f,7d3731bb,bf7792b0,37fc05e0,b224dfdf) -,S(ff6b771f,86d66610,6fa032b7,92844548,8ef9974,caf05ad7,cfb6b30e,abd1d527,6abd2a9c,9393e91c,ff77e055,7e9f6a86,9fcd0bae,3544bf50,b25f0427,908ba4b3) -,S(943ccf04,94dd1fad,1efda48a,12d9ace7,be919685,7e7fc5f4,befd7d23,3a1aa8d9,4f08b4cc,2dd93f8b,3751a23f,ca7e4f10,6014e01c,58791c52,3d01134c,1a0a7bd6) -,S(a79a7a7,a89e1cdc,908e0968,bf26c341,47a4638b,1d9cb5b3,ee6c49f7,405f172c,cb53d967,14b5be3a,e5497f34,ec0325b3,ebadcb76,b9838cd1,b3cee90f,f3bb8ceb) -,S(28ff2efc,71176efa,a861667c,d173f78a,4f548b36,aa33db2f,a50c0515,1c7b89dd,475b3707,db4ba15f,1485e165,68d7dbdf,8e67cdb3,37d79988,dc6e2249,d6fe4941) -,S(85b2c332,16a86885,c0704fa2,55b4ca00,223e897a,f0ae7557,f8687eb3,b1012968,a1f58d45,ba664056,efbcbe7a,f0ef479e,1f2bcbe7,98d055c5,7045d735,d657ea11) -,S(e9fc2d09,eefb32de,4068e2ad,d7bd3692,7a02b3e0,d354dd47,c2a70c9a,5cbb8778,ee009aa5,1216d068,3ee219b,bf53ccf4,f249d7ec,bd8c9cdf,80d0ec5a,5b65c312) -,S(da2dcb50,afd510d3,26e38af9,5a22850a,a1cc88d0,620fed65,763042f9,a0005d9e,1eef47b1,c3700963,5e16af23,f1308de9,ae0eab9a,b16c9443,6d501ebe,133eaeab) -,S(20daa29c,c6b166eb,ce717402,70873566,327891d3,ff7b6f08,b9b7da3c,1eb352e0,2ff6982c,ecd6fa4d,ec1d6692,92c3a326,a30cb526,4dc27a4,299dd3f7,7ae8a3fb) -,S(e16b08dd,2ae5be13,67547a53,496f9f4e,3aab8440,6cc34bdd,71b2ebf7,53674d9b,b70f724b,d9522b1c,8e43d60d,6357b5ba,48a1afc8,b7136c1d,9317a1d9,1ba06846) -,S(888a2daf,2d69db34,ff9485e,b06d44,c59670ec,3c68475,80753567,e56b93d3,ddbe4fa7,792e0b82,ac4753f0,5b271aba,8e804384,b7949a9e,9ba79fb6,31d4e3f5) -,S(747768e2,9090fdd5,2c22e308,131f97b2,ee6d8e0c,bf43d704,d50d60c7,616abd12,eaa75f40,8d1ce0b4,bb52879e,5ee7ff36,27b26645,c8ce3840,99dbac60,9cb61058) -,S(8569f2ac,1c7d131a,8d337cc8,87c00c1f,80897a58,f9131143,5a17d79c,fd8d6eda,504f0b44,252d06e8,2f8e700a,746a3393,85e43baa,a4e5da8e,dda7ed6d,83eacf71) -,S(4f15f3f9,a67221dc,4fca1d68,429b874,c4418df8,be480591,e57d6841,e11860c9,982c0d56,1783a9c1,a16bda10,87d29061,3f1154bc,4cc62a82,b795c54,a496b7ed) -,S(21e51a20,1f226e1e,3ebd56ce,6f7258d6,4e4f9db,aa425943,9e1bf7c0,144a92ce,4c47a801,b6a5a4ad,25c1486f,ec9bd0aa,428f3167,45136359,18d47079,75aac869) -,S(fac7e42e,8865ec0c,d0b4c4f9,dff6bf8b,e0f28336,395bdf2e,d5e2a118,9c0211a0,36812d9c,8337199e,fb1fece1,1997307a,ce656fb7,3bad65c6,41e6bba2,c4dd695e) -,S(a147839e,c91bc77e,cc568671,442d29ee,57f0f42d,7b9cb469,91064549,1a26d225,f404350e,bf7267f1,86120257,fa29fc1a,fc0d064e,2f14eeda,b730770a,c85bc5a4) -,S(d1212cf9,e5086804,44883c1f,4158f3e3,44a7900f,716ade2b,df19e41c,18636b8c,720b851,7b91665,128183a0,f3235c6a,2f9c21c8,e8c6ec0,5553acb0,27fc0964) -,S(13d5f334,a7ab2578,977c125,1a07d7a,2e4852ca,8927ce7,2dd9fe90,8b948975,973869e2,d1d0abb5,1ce31db1,ae8c3816,ff998753,479fe82a,7d87b6eb,798773ca) -,S(1f066961,6dae9e8e,76a9bec3,26bc2136,5ec754a5,34c787e6,b9abdfb0,e463507d,da48070e,b4ea111f,881f9fc1,2993a9bf,c6f99974,b3353ce,b5bd1cd1,c75b262d) -,S(729e187,38681dc3,c4ad9a49,59f975f5,907b15d0,114e029,8d4aad5f,69150269,dbf2ed8e,c60ea01b,6de0022c,8b035a7e,c1901c82,9e8d83f2,4560659f,8d455442) -,S(e92fcbe9,61353477,4d42435f,de190c26,8e3692ee,c2042fa0,2ee21687,1dfda12a,a75b5c0e,3f5280d6,41e36957,5e6ec5cf,585b1451,1f01da84,fb852cc8,2d64f2ff) -,S(85c2e61a,c69f8d39,e9c4dfbf,93f6b904,1ad35bcd,7f2b5c1c,789812d4,c8da36df,ca6d9187,694429e1,a5ca50b3,332ab11a,575264db,bf297752,f38fabb3,c0b53f45) -,S(10d17632,c33cc6b4,f5c2791,b5ae4f00,3adf9958,879c24f,10f147e1,bd1bc05c,e15ee734,f1ddec6f,45dbae00,88e4c5c0,be8464f,31205718,a8b2c929,939a687d) -,S(a6942345,25938972,f39820bd,27ea0bbc,92511dd6,827476f0,28fec86b,e25d609a,e06b3616,870f73f4,93f6d1b6,6256cb48,af49ee6c,b5296bd,ea73083,4f11d6e9) -,S(b4a7d8ed,2b3dae3f,43eba052,45b6c4c7,c401a675,6bb0d906,4f66d88,df94d8ac,ffc81c63,1a2cdb5a,fd7def11,9d07af35,74dcb04,e10a5ecf,d2b0a46d,90963456) -,S(5aebe21d,aebd3c57,285cb660,d9aa55d3,f84fb2ff,584f1266,3031e2ab,dda6fd17,22ea513,6a51b532,d178c40,cd5c8453,8f5994ef,7b35cff6,d9dcd999,daf1abe8) -,S(ac684664,194388d5,b796d64c,b4563aa6,69388d0d,83861c51,278316e7,2c8c7f87,cb9426d8,2dc90b01,97bf114,3f693e93,4d710988,26586e5f,f8913ab3,9ef41ac1) -,S(6f94bd49,f89e621,874c58c2,f27ce8a9,76ad2764,1627e835,6b82157c,24955250,d24330ce,4a54dc7c,5c7d9cf6,8f8622f5,e3633a85,8ec0d2ec,d8df3f9,bc7c5614) -,S(3f96c8c,e149947a,6d9ec5c,9ac5ff44,775e068a,785a2fa9,d0940905,a008f137,a91dcfaf,7111a506,3cf613d4,e360c9fc,9b7d9e40,30e00ce2,b120eacc,805f3f40) -,S(d805b05c,dfd675d3,b862a4c1,74909974,405a5b61,9b2a73c8,f3470959,779c707d,a68b544c,c7279f2d,e3a2abdb,fbb7fcb1,84366ef1,3cc3a66,b6d8cec8,3c3b6865) -,S(d2293c0b,d4189cb6,6be0efa7,874abe9b,59142233,6f2f71d4,808be34e,79df0e4,5fbc3248,87c54960,b9bfe70a,5cea3871,7f24f79a,3fe0d313,18cc068f,212682b1) -,S(931f090b,e22623fe,7ad49d26,e76b3c5d,e3f107fb,556f9657,facad9c,5b209d5f,cc255e79,d2a89899,865daf74,81aea395,848f57c0,1850c144,d5ad1a17,4b1cc087) -,S(118a6283,6707ff6b,c8ea72f6,285403a4,6e4e690a,db340987,a0359732,39e5ddc9,91f00fe5,e65a9058,36f9d447,d96af84,b6f5a18d,85c127ad,72221980,f7ff818b) -,S(81096ceb,5b6cb49a,d014ba42,d1d49e1,b811ca2d,2e6614be,1891c6a4,1f6a985a,da051c5,f8f9f3e5,78050a3c,1354b674,3f494860,6b04b8f5,b4dfe970,b7607e5d) -,S(9a80a438,5ff45ed6,2dd3559e,783eb47c,351b7e43,6ddc468b,9f410989,300cae06,845d1f99,21b69c5b,4628aee8,b0c55398,bee65659,e3e41cad,30e57bf8,b804b6d0) -,S(6a3168f3,b89955b9,7fac1d59,61e95fea,2143954d,fbbb6090,81c2408f,46747906,5b5f1f88,6778f108,3ae44a3f,82c901b6,12c741e,811d5403,c483c572,8cccc005) -,S(9a03ab11,78d165ba,23bd4298,58bc8ed7,797710fe,f4f8d8a7,3db0a90f,e1214af8,70888ce7,e61e4bf4,91512f2b,fa556f51,59a5550a,1d50a65c,a652b5bc,89e85665) -,S(8c90c18d,78b8d9e1,59a61575,48c14971,296c8c41,991dce25,e7878ef6,f4ea2f5d,2a5428cf,de628e51,a1644a5e,5dbb7227,2b97c0f9,b6909a68,2814882,cb1ca074) -,S(2e9bab7f,3062024d,84f7a5da,a02c9ed0,93327923,339fdd43,b68d6dd3,508a8957,c9af80b7,3f3803c9,f21e21f1,9523b2df,ea7e4f8c,9a376aca,4a147530,d2a43345) -,S(2734bf2e,718ecfef,64a95e7c,1fbe6a37,e2129898,343af84d,b5c17671,9a466322,f530098a,9f115f0c,e36a0ce3,4697312c,7d0a1e4b,df8a3ca8,f0a63631,e684216e) -,S(ab9ecaf9,500e4a4e,6e81b997,579b5214,4af3257b,8c8f40d5,e21c2a51,d56aab58,f7d38746,8e081844,9bd5e9d1,938a8859,d0aaede7,5743dbc3,ff30d51c,3de0f047) -,S(ae25f546,a4c09ef2,e5a9cd3e,85baa880,292b4d4d,4e8440c0,1696435a,cb1af368,46a2b3b3,7373840f,b739a9f2,2953c6c4,80bd59f2,11013d59,e051055e,f7f3da84) -,S(54285da6,4ef21cda,f597efaa,884fc00f,4e35abb2,bec04ace,54a83dc1,c12e6142,483beb2,144d7b5b,a47c2dc2,9225dd5c,b962a849,d46ff6e,5220b6c3,20cdbc3d) -,S(bece8434,4bc231f,60ad542e,d6a7857c,35a627ee,a2914874,c8deb661,37dca65e,a229fb80,2f9e72f,8e477fb8,de081254,fe1c93ad,a4d3b4f8,e9c2f4eb,3e2f6a95) -,S(3d55747,b148b857,472fe5af,1e820bbf,89994a2d,ae6c326b,26fd9cb4,fb5e81d1,dedeca5a,e86728a4,f635bc4f,1b2b162f,c9ea7dfb,efd5852d,b90001cf,bde465df) -,S(13c68219,d1633c73,59f6361a,88bf6a72,1846b520,33475715,fbc97dcf,75cde5d4,ce8a3cc2,39fc7f20,96abfe7c,52d79e9f,bddf0ce2,ab2b6e55,935413f9,37f83af4) -,S(e9e40ae1,a8041a47,274c481a,dab52f18,36690a29,be837433,43650126,d5b0a6ac,c19958b7,9c9839b8,1371f314,749147cd,9a22fa22,a55da9a9,577646f2,38c6bb7f) -,S(2e3b4553,7460a1a5,f7353a53,78db61c9,13af4371,9a268eea,6321b4c8,a1493068,f7ba5e56,104966c8,4959d3e2,290e5501,5ccf5cf2,b6fb5bb6,e0452c5d,cba54dcf) -,S(9855bc82,b9214b00,67eaa40e,bf670dce,6a59f3dc,4cca491e,db1f0f48,b4c62b8,a7d93f6e,3be6c73c,e9e37d6b,5b071603,87184e21,38478009,8d4c1c80,ccfcf435) -,S(37f820a9,b9342913,6d44bee2,69cf27df,67486bc5,233b8866,982f8476,15253979,fdcaea9d,aa629d37,7f345a5a,37c566a5,50dd893b,9d7ba88b,2a568a28,7870ca15) -,S(e82d2c98,a92a3b0c,690f6ba2,8070c59e,3e0cd0a2,a384d3b0,3cba9d1f,ded41a98,31e73a32,32d85b36,14833d34,4c7d502d,d09d7ecd,614b060,95c86be0,c8501460) -,S(bd492fc3,6dd4c906,6a071182,7eaece3b,ad46901e,b400bf3a,24b93799,9a923419,caada3c5,1e1fd5a4,6676dbd0,a7fd4049,8b93da93,bcd25af5,fdc6a0c9,1dd7798) -,S(6c8b46da,42d1ec4f,3ca2c4dc,15a69c80,cd8f0d99,7bdf3964,1cded32b,8629577a,d3ad4f62,729e42e0,f72ef596,5bcbc239,cbeb988e,e62b30a9,7f124004,c718c956) -,S(78b1e9e6,799bd3dd,854a25d3,4d356b4f,effee71a,ad0c8f05,ea9ebcc0,f8f5dd62,31503ed6,a26788dc,c07d7005,7a300665,d726ce2b,702e65c1,dd25f892,3931145d) -,S(f2ed02a6,63c5523e,3c68cda6,bfa4ab6b,cb53fa5c,15f0375,c8974eea,5aebdccf,3bde5c3,afdc0320,e3b92241,3220ad32,937720a8,d1477b67,773e725a,3cf36382) -,S(7e43f643,a45800bf,7e54d83,5ff6ba20,f67ab101,5d1aaa60,cde0967d,42caffd3,1f456eda,f473399,b57fbb37,807b5269,58600d12,b556879a,76e21459,5798d68a) -,S(df15e177,5eb73697,aa4c0a62,4b4d2ce9,7ccde2ca,66555d07,6430b656,61319be8,496cdc,f1543818,c2173dfb,8a60ee2d,8397cca,b16e4e53,b35079cf,b27311ad) -,S(edf1d706,295bb20,12dc1648,7940e84b,6707a3fb,91a14fce,ef37f669,c782e2ae,e3a0f2f6,fcd76c97,b20b2dd6,8e888eaf,9ed8f598,f08e4d7d,239a8964,fe019a2e) -,S(c15022b2,6b15821f,3be3c313,73d0464d,fd92cecd,6ba87c2d,9b18fb5c,16f8f6c0,78cd2370,d94e2842,e07961e6,92e9fa04,65d57f25,a80feda9,327581bd,ce136c2e) -,S(bd4df6b,b6ae15e0,109886a2,8a8f8c90,c6cc2bcb,b52dd105,e277da7e,c76001d9,499659b2,b0b4cb96,5b8e5029,96ced2e3,a6f6fadc,da01b875,72f8727d,8ef1446f) -,S(dfcec232,873894ce,525f9b4f,162f180e,1e2d6eb4,c846bed4,b2109700,8fbc0b76,afbc761b,f4c88e71,9c318f05,9a10ab3c,5a477ec5,33243b95,3f8ef006,69b4f92e) -,S(b0076c4d,e3c94fae,23659b00,5b8b41fc,b8473935,764e48e1,a9eb1fef,f5c94e54,e1eb3255,3c55a687,6f42ee5e,44830a09,fe17fda1,b84e8551,f3ea2308,f9c7d4f) -,S(9a1fe9c,17c4255c,c11e9fe3,3d66787a,fe9ebb0,99be88be,94b4c3f0,da2d0c11,e6aef709,99a8e739,6e23e1aa,c7ad1cab,25f6fd6e,62df02b0,96af568d,e88e8379) -,S(1d89a934,126bbc15,d9b99b88,b6c65106,e1d8b16e,799630f2,2576e9e4,15212899,b7e32256,92db0722,e9a79ef,7d95c509,37d64644,ed36cfd7,56780d59,a6f8f4eb) -,S(c60f5c68,b67b3796,3c462d4f,7530edfa,34546956,21bc80a6,ac2be433,700c7fa4,88f8b071,97fff0e3,a19b5a67,60dc92d3,b5507b53,5cec02c6,53f75a60,bf8a7e08) -,S(52cd2b6f,d9b2699,1b76499a,d301be43,6205761c,f768eec9,e6b7d6c2,52d9d949,d127cc66,1fa33508,a0d11a3e,ac782b26,26356382,f547e4aa,13802138,30ec835) -,S(1e44499e,a639835f,f384f107,fd16bb19,c21fbea5,cf4e3be9,20a34024,6d05dda9,41c6a8e9,a9042f9,950d12db,74fd0f21,8f8adf23,e961488d,27412c2,f2d1f53) -,S(139144f0,a56394ba,d1e53bae,360136eb,984ecc56,56a05cb1,c6727543,fc6861de,70394737,ff37e9b2,1bf174ab,6c042bb8,964f3d01,6ea1edc1,25ed3b4,2ed0742a) -,S(934ca02a,2454df18,61fcb954,6634e685,34fe75c8,b6db6eb7,5a2a74f8,654a2280,779e9784,266cfca0,b83caee,74fd24f1,6865ce3a,6be78be4,375fa15c,db195761) -,S(a64f047d,9e1c2459,77da8c32,9d35ecd4,af913baa,2d4b679a,7acd326d,886a3be6,e11e830f,f3b4ed6d,102145e3,b24759de,3210f309,8ec57581,e6014818,79112b2b) -,S(e1c688bd,cd629088,8d8820cc,df15fe8f,cfcf45c4,b8bd434e,2a15428e,818757e1,bc10c6e1,71e7c8e0,13b8e00,e77bb745,a34e7d1a,15267600,d130f6f2,18c77f7d) -,S(b1a30c95,123170f2,d9456de6,827afcc9,ba2bded,d955354,c6deeaac,68137358,9c76a0ab,c16c1caf,d3844346,9040373e,a678797e,dfa1b298,5a17d410,b04071f5) -,S(24cc27b5,fbb0291c,3468ba23,58f5e253,4c7cf99f,699af4d0,d6892bea,e6166e85,eaf369af,2516ba42,673c52e3,ff0768fe,d51aabce,2312b8dd,d7aa1ed8,cf9f71d5) -,S(8bb4017a,6166d1e2,f7fe8921,cbd31cee,bacab577,84da8a92,217aab2d,948f6a57,c899740e,6c476986,356e34fc,7182996d,a09cad72,93d78c8a,5c30d56b,88dc331) -,S(55d8b7dd,d82fdd96,e0ec17dc,20b303fd,e6dafef5,a527368b,ec99a33,60497f6f,fd624511,78bd66f,4361709e,44e72e9f,f4f29230,d1fff657,bbf84762,b7b8beca) -,S(82aa2def,5a5531af,519cbfe6,105dbde3,109d4626,ec47a845,5dbe2852,34c94df3,61160bea,9f83a2e5,8c2df91,925fbb25,8d1e60fa,6a147c4,ebc0ee38,cd811511) -,S(36c1277c,c6df7ff8,47c2cfbf,3cfa9198,804b03b0,c28e1636,ad3438cf,2cf6f7f4,2304fba2,74f81c74,5455d821,ea58e047,a7bb3b60,e32f020,aee5a2a5,16fe4833) -,S(f376fdcc,5b44cad7,e16c9e86,c00b366,d57b8925,fa49b18c,eb8856a,e0cd9119,2d6acd32,e4dee81f,489e3ef,11acfc8d,c3d0e7ac,bdf5c6ac,74fe7aa0,50a028cb) -,S(ea4e10dc,5372e9f5,d96e8ecb,907d3a89,97150b6c,39ecfd1c,c7aaacca,5dc5030b,b0896ea3,93b626bf,c2f486d2,9fdeb897,36d6be60,144fc3f9,5206666c,36d96ff5) -,S(74f392b4,b2664a17,9d3f0a2c,71b144b8,a376ea19,f1a9d91a,d181ca3,a6fdeb08,9bd4db21,428d588f,64ecef67,99b46735,c9523036,406d2636,c6eee083,e09e1fc0) -,S(3a36c842,59ba7774,a41a17da,f0e4c821,11c13a6b,58b82774,ca6962ef,cd4855eb,6ddad1ad,9ede928c,d65720c7,15ef39e5,f35e46ba,45d8ff48,2f095d2b,e0fa5e3c) -,S(9d77b2ad,5636a44f,16e73981,46b17ea9,7635ef18,8f32764d,eae50d2a,5c98c019,532dd027,a775861a,b9392b8a,cb2db097,eb5936cd,9d2f7234,f30c371a,22ee3eef) -,S(2e7402e9,450e2f80,e05168a0,f0c5f1bc,deb6117,ee46ac1b,39aae7e7,bea3c4ab,41e8f36b,5606fe2b,8ed6b3fe,f8821013,cf85721c,f242eb60,34b82afa,cd82fc3b) -,S(aeb2cb25,4ed0b5bd,81b33d35,e8f00a5c,6a6806f1,5314b320,de0c376e,533ebe6f,6b8116f5,2d7bfa2c,b3028249,fc83f317,5d761c0f,76833d0b,142c4d6a,29b9d59c) -,S(c86224bd,55d62c97,a00adabe,3a797929,4cca663a,ba3a3655,fbbcc3f4,5cca7895,a319a3b7,104f7935,36693adf,a6009db4,1d857353,fa950c21,844323bb,cd1cc214) -,S(1d1164cc,2c576a0d,d7b5a28b,cfdce6f4,d53ddde0,534b3a66,aaccfbba,3eefe561,b85890de,aa25d897,fccba694,7c470e45,ec600989,243ea91c,4670a,b44995a7) -,S(2b54fab4,13b915b5,ce76620a,5c493ccf,5e7f0f41,8bcd793b,92f26118,a440e3c8,8aff8d25,56fead8d,7e9bdfef,bddddf37,7a61ce4b,2effcdb,30ad0016,4f9bf5d1) -,S(1f1f2a24,a4e72a1f,609428ac,853e46d7,a9718c25,f2df9887,9a3aa60,5729b340,450dca4,f4920bba,bcf94f39,26871032,b631120,4b217170,991df216,2c421cbd) -,S(412f658e,e6777e4d,24e5682c,5007e057,83fbc559,f22f3200,f185ee52,c8ebd4e5,c2e0b64a,9d9394fe,b930b3d7,afa64cb1,c8399e3,27690e32,887b789b,6571c8f4) -,S(8495dcb5,567791de,976fec9a,367e250d,95102ef9,f92c11fb,f561f854,4cf4912b,65f809c5,7d3d824e,f5e63f19,153bda4f,542e511f,464e11c5,e2a9c32a,2a152443) -,S(f8e7bdc0,d841c95e,3a945b8b,c85ca4c7,b4a18a9,7a5646ee,1bb4ff08,5956cfde,cd0ac83,f93a3679,37c9d28c,24b9fc08,6d6660d6,15df5011,1b4edd5d,f0ed6d42) -,S(8324625a,4e4c1071,24876751,7df28ad4,8c8c5648,76e4a131,64f2f730,62854c94,761b1960,49922825,609c7ec3,70626025,de65e2cb,240b8356,1f5cc230,1f9bfaeb) -,S(8b1c49ff,99f87e22,af4b6bef,d353df1e,16a8e160,3023f2cf,213ed859,13ca04d4,cd4513d1,e178865,2d1cff72,822de250,6abbf975,7e2774c0,2ca1bde3,23ad6c23) -,S(e2ad61a1,20d24d80,8c830e89,d630b466,59deacf2,87aeb790,bcaacb82,96f4f138,51cd19dc,fc1c4867,daad2940,5acdc7ca,91849769,6003321a,bf5dbc6f,b2186291) -,S(e8dcd7e,a9a9a6f3,16a6aa91,53105601,e10356ce,7f4793ba,9eae3ad0,34c197a4,c835bad7,91f3aaf5,d32e2a99,e71c4add,95f69892,6a68695c,2e61ca85,38ea6b5e) -,S(f0b748e3,5875b8ef,361bba69,cfb05c4,d8643f95,9b207556,e46908e9,bcf81233,6a264e51,5d163a7b,678765f6,c29ca61,c1c0aeab,a9ff423e,91e9401b,2dd6e908) -,S(900de96f,9975a16,766dd305,bffe2423,e6eef8ae,93ebd796,2ce97d53,39af3a87,894ab2ec,d9c058a3,a331bf65,dbe69a49,f33f8e9b,12121439,650aa700,4d164478) -,S(8cbe7930,d2ea2342,730e306,7e9ecf95,ce7fbda1,e6d34645,a6e214a0,ed88aa53,867b156b,f875a67d,ae27f2c8,e232c934,85092c70,ec071ac9,919ddd85,70186b83) -,S(a0cbb1c9,5b35d243,945a65c0,fc5706d4,e79237df,c13583e6,9a292fec,9a25e68d,b6d7e9d1,3cd61a45,f81c8a55,40dc06e1,3c6d7024,5e850a40,55ba4eb1,82047e4f) -,S(148aac72,a3fa8cb5,aa6d3bbe,5e987fc,d8050c3d,63b47f4c,832a4488,262463cf,7f29de49,a6e24485,5aa45f6d,36f2e2bb,72749f91,8258c0b2,92a33322,677e4a61) -,S(3b9fed07,3a1afd6d,e6ecaf7e,fa20e2e6,c28616fa,25a218ce,fb07cf33,66f3977f,f0a85b3c,5084c964,a1f0c936,e96ad3e3,4fa9e7a1,348ed0fe,ac7003c,12c65fc9) -,S(7de45ced,5228bfd9,557b443c,30fa431a,7c9cbcea,dfbfe0fe,cc565ac7,ce3537aa,515ddd37,69107033,bcb794f3,ac55062d,78e0118a,60c98fc1,1999cdde,fa2686f0) -,S(9cc1a35a,534f562,98010274,74f3a857,c17cf99c,eba1d5aa,251e61b2,55913dd2,c092cda8,f30fa4f9,96115da3,7bf8e12f,c653e243,af2bc7cc,c691684c,3e433ae5) -,S(d82f1968,759b3b9c,c76ad729,828a7283,10fc71fb,22258562,920b690,7ab52ec6,54cd0a05,26983b0c,73808f8c,ae1c9d81,1b372082,dcac3306,c470af50,8818c607) -,S(16e6a947,3d95a95,c31bffc,c291b60d,1f9c548,85e5a498,24195ead,b87b7586,19e29938,581b6b8c,2e50d365,5a957c04,80ff4c8e,4ed73276,f882c558,dbd8aafd) -,S(d07e7af3,ee4f24,e46b4670,477c3463,ad57a74e,57a17197,ff098e52,3b5cd237,fff34e0f,43c91656,69b1019b,ef618888,d4d175de,b6f20b1b,c696f24c,135d0e20) -,S(2bf644e5,6dc027fc,63a118a3,43faa4e9,8ffe42b9,c983014,50a1f4d9,e5665380,bef5c175,77be1fc5,f8f66fb7,a06b55f7,eb84ca5f,66ea4477,c924f925,5a262ec5) -,S(518f0d37,db1db93,48c80101,442597c6,7a88107e,5e25fa3a,b97ed524,fc5cb045,dca8750e,a4e9ed01,66f113a1,44974250,6eb9f3f4,df8ab741,8dba0397,694d7294) -,S(bd48eb6,c50774a1,2be9893f,8c21f624,57bf54ba,8799928e,9a9c725d,6f0554c7,200a6da8,cd8f0300,6774bad9,769f738,dd58f350,632742d2,e2cfa787,f570f6e1) -,S(ccc8d93a,871169e3,69336622,b64fa1c0,800c5b45,e3c0b130,2aa99e34,db1517e2,40ee7e4,d45e6478,efa11f1b,c4548668,88837309,4809f056,11efd6c3,6d01d845) -,S(86f6392c,75877992,311d2e9a,27be9ea7,27e8d01c,fc27dab,8f4527f1,dbf6bd1a,7ee29611,b647aa2a,3d2b1304,c49ee690,57150518,fd46add3,e7caf34d,10f7922) -,S(e034f4e5,927b0fa6,c3794105,338751f9,9bb5a381,6da1dc1b,bfc41d83,b7d7fdfd,dc9f02cb,838242e4,13282b05,cbedcab9,e902567b,b279fb6f,f2248e75,41a5f89d) -,S(8fc36a16,a9dbf00,5ee3a66a,b825510,75eadfef,b86e1062,837b49cc,6ab51045,c7ee2c40,9605981d,217d9957,a004a4be,66a88527,9ec9f74a,70594999,23d200a6) -,S(d7bb40bc,54077d96,d6489b71,e65dcfe3,997130de,b517d12d,9c10adc8,e73278e0,e2096366,2f64bae4,5aa0706b,d96b5cb6,5897c0be,3a8a9b46,8ce9074a,a68b0a4b) -,S(d7357685,8054c714,1147d2d6,c265ce40,3c882681,157b07e0,b8be0a88,63bd2ac5,94f8754b,2fc94239,c254099e,9cd5804d,d2ce03a5,380c59c2,4f42ebe5,85a9932b) -,S(5b6f8aae,d9353ffa,71da7e99,bd3fe165,3e720ffd,657dc2b6,669ae0da,858f8392,4eeafd05,369c6eed,fa6f85ec,34e245f3,e4966840,30253c10,6e74f473,418f9089) -,S(39444d12,67cc29e4,384b4f4,9c4f4886,ab4076a0,19a0fb39,f7b72c4e,42222000,65c2502a,af90ee2d,8de48adf,35388eb9,329f3057,1b77d0ba,50ea01a1,ca83d771) -,S(53de00db,f1efb0a3,c159c4a7,dbc9888e,16ebad95,cec2d003,a18488b,1b0752c7,328ecbd9,99475dfa,752d6228,5e7bc51a,87dc6166,4d14a6d3,3a556322,5e2fbda) -,S(48a3baf,9b4f7213,e280eef0,d5fb6033,194d1bce,eb48d9e3,d4814a4c,bd5ead39,3b4ac9c9,e04a3852,bbc6f7fb,cc94b20f,7e749eed,44a9a9ce,7099a8bb,28334186) -,S(f00d7630,503c1ced,3c418237,27e22d7,acccf406,fa16eb6e,b524707e,5b3ac541,9a1ddd3f,ec177626,b1254605,df8ed593,c9e2bcff,db7d0404,f47571b7,31ca95b5) -,S(e1ff1994,3ce7eb59,e570858,2e8c21a0,c4f8eec8,40815ee8,9a482658,8941eaac,528e5572,746e72e6,ce61b53d,78aa57e9,dbf27e3e,bc36c3dd,3b4972,d7353b7e) -,S(e4f13c20,c48e750e,e15a665,275c27be,23b3aa04,5915ac55,2562bef0,7459bd49,bebc7ece,c6e51f99,a2e6b9d6,a7b1bbb3,63901053,362a9ebc,a2d21cc7,6e87ca30) -,S(e36e8cf3,824b66e8,7083d371,60cf2719,598c6c04,ac693ea4,d2dd5c83,886f5f20,4ea0e193,8afe57df,3db74910,481a54dc,f5be9fe8,64f249f6,c88d0cbd,a086c60b) -,S(51e1f319,3286d2fb,29cb4a06,84d7c547,797ff5dc,fde9572a,63dd1e0d,2646365f,ac470e3c,6f30ecc6,31a90d7e,6c4c3d43,b8640ced,b9465cb2,ace2cc87,52370e3a) -,S(8e82daa9,c40d4e72,605dadd6,45bc26dc,22277f41,56d2a248,29bcf79c,d5a5fae0,7f8155fd,be9057b2,2b191dd7,233e291b,b01b961e,32a124d7,33ad99b8,167c53ee) -,S(79e56744,273c7aa4,34ffd5e9,525fa788,38bea674,64e2a595,9881b359,3e2c41e3,625089a3,c50defb9,f00ec764,b47122d7,eb786a20,f278bc33,e806e7cb,f385ecab) -,S(a97e00e2,d19c1957,51deb891,84e24a22,af7fe156,f2f1e068,79ded3f6,62743f79,881d7ebd,8bcb2c49,354726bb,c44ff91e,f3f5835d,ea73b282,944a5097,cd8284a0) -,S(3bf10546,7bbf5c3,14e1c3fb,40542378,9bc52fbe,8fb38aa8,f4a70727,b338542,e789586c,fad5b7ff,6dc68e5f,ef840e05,9a87ba51,e58462b6,39042c64,24f6367) -,S(80296c77,58791dff,39b4ee87,ecf3406a,49cce0cf,8437fb2e,1f4880b,55d9cc5d,3b06be11,3c7f781f,ce28753b,708bc514,902e4834,bdb09284,846c4ddb,90152dcb) -,S(48e2cb7a,a3eedbfd,f6a9cc12,359c4ff1,b7b0fe4e,87e57023,59896506,20ba52fe,dc78417a,fa909bbc,594411ba,87f72ee0,a0a45631,3cff4aac,7ad564b0,9ee8ed1b) -,S(dc91351f,cb775488,286b482a,a187d79c,31a3db2e,99730b6b,7b4805a9,73403d46,ed720e0d,2d13192e,8c180ecd,5e09fa5f,fc52e35c,4e509b2f,fa93ff96,f7adb1a3) -,S(5d37c139,48ceb4fa,9cd05b15,1fb344e9,3a2b2653,5b052b9f,1797319,e990a670,f790933c,2590ba48,7a832ad,6b940634,b62e16d2,7c9e748a,1856d53a,1974cb01) -,S(98bcbab0,f8d69b22,6fd7eece,a848ff4,15c8e325,ad9e8157,708eca17,77070aa2,7671e3b3,db715487,e6affd61,5218a7ef,a08aa949,9bb10206,e2de58d,ea150212) -,S(60e2c1cb,3de9486e,fa594384,d5903340,12ce308d,2247a18,8fa5c112,3f35b1c5,6de7031b,9767c66f,5c3c11a3,853bf722,4d58d086,b68e08fa,63942f2f,9369d1bb) -,S(814716c5,aa8256b7,50bf2f70,2e2f9bcd,aaf513bb,329eb467,d873ea72,304885c7,eca644ee,8fa96189,13fba31e,23533de9,eb7efac9,a0fcb58,6300a42d,c7d297ee) -,S(25789f3f,1db412ef,af60f7b,636686d5,9fb71586,200e8e3b,e6d934fb,72f8de77,e5222798,99d1e21b,5734a6f7,7881a686,863bc03b,8c58cce9,633c8302,2c7de0ac) -,S(5382f40c,98bff8e5,646a87fd,f3fcb6a6,27f2a91e,780a1527,ef18cdf2,a0f1bdcd,231d01de,e41ca3a1,da068ce1,39d97a16,39c027d8,38c7879d,9a1e85c6,4a32b502) -,S(448cfd20,9db2fadf,fcaab14d,8f57dd01,67d9ecb3,f18e9dc6,e573238b,a11d1f2b,bad8e2e5,5a4f56c2,435e8d18,14d2824b,2ba1bb67,9520587,5a11c315,9166fea6) -,S(d917ca4b,fe6335f,5012b69d,5444bbf9,f6c4893d,eb612ab5,667afbe8,2e5653d,3fde9a4b,e6a49756,27950f1f,f17ce5f0,aeabc055,3102c33a,4bb85bae,f32bad17) -,S(c7ee9f5,17a883ad,733de053,be3ef583,1dd974e6,a4e8570,db35f24e,91ba8f72,8db7738d,26d367bf,657d2a31,c6a08ce2,e06a7e4d,2df39f3a,2bffd062,79bba44) -,S(83f0a19d,983ed6de,7a2b173,77c843bc,819a77b8,a32acaed,b7085e0,94d9a30b,d2ab3e96,67be4473,d8748b63,6113be60,880acd47,6d574e00,c37f4875,2cafe6a7) -,S(f3f8aa6a,61687c40,98fb56bd,e74d83dd,59674079,7c52f2e,2b299277,2313989d,3a690c9d,98503a3,2d201ff9,a896365c,caa1b54c,36857a21,ad63994f,41a109fb) -,S(4c1a11ca,a30bd6c7,d95d6e8b,3ebcb4e7,914fdd40,4384716a,283ee1ff,5032249e,e7e718c9,4653ef40,d214c604,e65339d0,6598f17c,37f82880,9b7e5215,b9424da0) -,S(2941b952,3419a018,53f3bdb0,420f3182,529ebbc8,5a1c8f6c,1d922c19,3ee5477d,377f226c,29ca66a0,aaa05baa,7f6c1ede,80482b51,8982763,864392dd,3e628413) -,S(9d04d07,aad49af8,65bb3eb1,8c7078ac,4b5f25ef,e18572c3,3842161d,8591a6a1,f572968d,ec2ca89f,b45ae02d,119644b6,779eb0ca,1d48f724,f8512ba2,2c83cd34) -,S(4401f767,c3c3a101,b99a983c,9a622824,d660c50,177bfef4,a2646b06,43d26e20,7952faf7,8e1b114e,16429309,1d0669e6,999f8bde,ee980c0b,b7d669de,86d4e342) -,S(94b6f427,fc4017d3,b328665b,acc863a8,ab8a1c4,7b283fa6,8d7b7f0c,1bbba31f,1336067d,35f0d2d4,6ec8199e,99dd07a9,9cbe7725,a9981868,e09a0217,df40d85a) -,S(41621ba2,92c79bbd,463b87cd,de75574b,f2fba59f,92025445,7389b4a2,4de7288f,355337d5,b6f30b78,81389951,fe67b943,3bc70a07,b294d11b,717ca2e1,a2cd3188) -,S(b0838415,6256c1d3,55900dde,6126818b,8a9b27ba,ab14d73f,c33c399e,fda3594e,2aaf9190,55b162e2,91cc5371,b6a4285f,843ef8d1,5069ec7d,c5d68475,c5a954a5) -,S(cc99a14f,ef418fea,5de9f437,7ccc1426,7d910f13,e8448fb,8ba92746,6c0dc9bd,2e30b64,7c01c12d,d42f164b,ac0c9bf2,22f7b3d9,2cffd7f5,c77aebb7,18536f28) -,S(8d2bb24a,dbec1858,d565d59c,1d805d8e,7b21d6b5,b967dd50,a2f420dd,5764e37,cdc6d730,e78daeba,712537c7,8a09322,fc371d0d,6a5645ef,e7014bf8,999f712f) -,S(63cee6de,f18cf4a,e6ca1871,7750e328,dbb94c6f,27422192,3b233a3,e50f7c9b,81230dad,ad2d233a,1b631b8f,7a885828,ce005031,e1365436,7ca34173,1efdfeb8) -,S(62084e9c,1dc6dd03,9a68d5cb,fba19dda,b2e4d07f,b8f46114,926a59e6,92755a0c,6dbeb4f4,62fb1af0,dc273a,aa827e0a,cc9c7f1a,fbcdf02c,c4bd98b7,5061a26) -,S(110c0eba,f65b6280,14e368ec,17072acc,3f34a937,7df79238,c2773625,5d8dd827,1a4ba716,6f236258,961d5865,b020b83b,c3c3e74,2dafaba9,649ff85b,2ae75c6d) -,S(d848a51e,50fb234b,a807306c,fab97405,baa50a5d,23cd12b6,8927c9e6,f1c87e00,9db9be62,88fb00c8,4cae4b1c,c99449ed,51fdb49f,3cb7aadc,16a72b6f,a96a4fd8) -,S(42311893,a2706ab4,52547f3b,3901b9ee,a8cf2660,581b0023,96bc9a7c,e14c2b5a,750f86db,9ba6222c,199c2a9f,77609a47,d6129a1c,e9ef4d70,daad3d2c,ae4165bc) -,S(4439c4ee,471adc41,32f45496,77ca1e32,6b252f1e,5f17f741,9fdaec0e,3834d37f,bd75c32c,22c5c3de,62f16ab6,6f86f93b,617c9565,b3859195,81a00ee5,75897e87) -,S(4dfce3da,b19231da,648b0bbd,8c52fdb6,e02e9e79,9806fbbf,36bacafe,c113b053,de8c5f1f,4b727fba,440a1c3e,147cc1a2,9d647c59,42feb42f,69d45a2a,13042c3a) -,S(3bba2b2e,e8e72736,f54f9158,281f6c14,9d0ba6f3,ec6d89ef,cddeff9b,8117dc9d,ff087274,77897e56,e5e93f94,7af6ca0f,6f9a2186,a6a60d2b,af690a30,da16ab24) -,S(a2fede43,37bc6b2,482d92ff,f55ab0c,e239a00f,4fbb0595,27f7d67d,8317deae,2a791508,43beffd7,ef08e195,d0ce022c,f780116,2f1852da,98c3638d,45869ed4) -,S(221c4e2f,f503eb4c,4a1aa8e6,77370085,b3d64d09,8430a185,2cb1cc3e,304bc0a3,c3c37b1b,f954e79,c124fd70,ad3f8765,a70a7929,4a262de1,99e11dd1,95b7ae41) -,S(a0c32f80,f7e4ba05,caf945b,49b91306,f909c8bd,559e4bfc,a58ef3c5,14740ed0,d3eb8f01,46ab4700,41de4cfb,dced45c9,966aa1c6,38a42c90,41ba1891,36f9562a) -,S(762e7a18,b4fe627f,1e1ca7,57740811,bf33395,cc962aa1,dff79be4,18da85c6,a0df0f46,50461c0f,4f8a743c,3455b842,5875f795,4af56b93,dce93234,c4f51ec5) -,S(2f02d935,cd95caf3,d56cfbe4,4337b1f,78389f34,1146f561,b8d632c4,b93a29f0,173470d8,23f190b4,f8008872,b23f1a32,9c45441,c12fe87b,e74e927,18f44569) -,S(c9f877d7,2eb816df,1c5adbd5,9fc98a39,c5877d6e,24ef1612,314e6392,e7eab212,14ce9917,88cf7eec,5a5a52b5,8fcaa9f5,88bb0052,754b3ad1,b0858e4,6a067c4c) -,S(cc4dff69,18a05cb7,a6f296df,6cbf5d0e,d6dd1c23,ae76c5df,239d2179,a0baa172,1cd438b1,b8471750,261b0650,663b4a56,e4dda0ba,b5390cd5,b7869448,654a4dc6) -,S(faaac74b,3ed2713a,29c10219,a78acd51,ca015a8a,65646a5b,cccec828,efcbfaa1,adcad43b,dcc2ec0d,bd65c46b,7fe79549,b2e74cc9,13fbcecb,f8bf661a,7d30d934) -,S(171356c9,30fa9bd0,da1444b7,35be6c0e,8a0025f2,3d1a2480,dd0aefc4,44fdbf46,770e9edc,991efb9d,ab44361e,d2398e54,62e2464d,2ee2a14e,b2e149bb,9c9bce3f) -,S(933f56a,e0473763,d2d491af,55f9fb19,c055017a,7a81b43,b641007b,e5680214,66059c47,481cdb63,481ea647,f494e541,ad1d70ff,93b1eba9,f85a9cab,a0ea76ad) -,S(a300f22,b182ad37,d7e44691,bc9c9c9,8a397f76,1ec1acf6,64ac1fe0,5bbb6b34,bd6f2ffc,a90974b9,460de269,4722f215,684abe44,6228b500,7b42bab4,5433593d) -,S(fc5e57ed,6e901355,f97c1d62,dee4d630,878b79b5,528e3fd6,85d6e3ec,af8fe1ea,1122127a,6c21cbb9,e598b1b5,68507bee,bc7c8549,345c9d49,8c4a9b2b,2f5bab01) -,S(5a2f40e2,7a64811f,bd4721c1,99019523,899e956,ea340bff,f3f452fb,5231ef3d,6b2bf95d,12578c79,74a06d26,39d71c31,d8c4a53a,6279886c,20a122d3,2093d547) -,S(59783333,df0b99c5,be76610d,67d7ef62,fb15757d,8dd1f310,6f9179b5,64f2084f,f2a9ea80,dd3d170c,813f4623,ba7583eb,7d309d97,c34f4c4f,a7676694,7e5b7f5a) -,S(cf61124,6b513fc8,73f72bb3,87a29c2d,a1c8bed7,4ca7ca08,1546db1f,37672d95,d23c3c76,697f0443,9ed1d1a5,661fb0fe,1e182cf4,2e07c787,3eff7abc,2f8c70ee) -,S(edd14f05,133a1480,e26eb7eb,8063f8eb,1cb871c9,606957ba,ac14b173,2ffe7d52,d682f280,d295d528,4c1b3aa8,445c274e,ee603308,ca4792a,61b5f8d6,34b1b70a) -,S(f9b0fce9,cdc8af3,8b26e790,2c95926c,33cb8d30,a5de80d1,75fd95c7,fc1a1713,ec7e8df6,f3d163d7,181083cd,c8cf4a89,df958b8b,d6fce2b5,d4752240,f2a3e6ac) -,S(ae906599,54187f57,89306981,7417c566,d9ea4315,f07094e4,e46bfd24,1746a3b7,2241bdad,c09d3313,e9d006ff,2a04709d,17335573,5be5b10,6775457f,231a129b) -,S(55f0f800,76492f7b,f5e134cd,e581ae3b,f68fe9f3,44107540,c54b350e,47d956e9,22a0891d,e68488a1,dfbb4b8a,35fe9835,e258dcb5,c70ccb98,2c8a48cb,c33956ff) -,S(90c8ab06,86fb40e2,31923bb1,df86647c,6cb7e3c4,c451d0c1,b871994c,19663bbb,dc748cd9,570eeb2d,c6fbb2c5,c417979,cb30d718,94c8e463,e3b7be3f,fcc80ab4) -,S(cbf47c2d,6b21ebb9,fb268e73,56ea849d,3e476d6b,ac09eb60,4bb2e27c,84a4c694,f0288fe6,8042894a,39abf8bb,e5962421,416ed9df,dab081cf,16e86fba,7abb2873) -,S(7c30885f,c18b68b2,8fff758,2148d738,d8f1bfb2,46543b16,37e9fce9,7d11fe80,3e2d1cb9,31a11c15,b26c6d37,8c886e10,52c06718,a63e621c,7ea51c76,3c013f2f) -,S(ad614919,d1bcba0,dd2a9da9,de9207db,e137c772,37f333e6,4f11433b,f66d7753,fcaea18b,3512a188,9d604619,2ba759b4,190b72d7,ec53d0b,aad9e01e,d239753d) -,S(8df7041b,af8c9c15,70ab50a8,1ed335b4,a7bc4171,a3939715,a295ca7c,4e5e29a2,e892e43,82677bdd,f3566b24,c7ddc6dc,e12eabc3,84a19a13,99b64ba4,bdce02e7) -,S(9f4c1e57,61c8520e,9a751891,ac1bb5f6,217f4e77,7dd88fbf,2a127804,2cfdadd6,fda210ad,c6cee889,c35831e,b3e12c7a,ed4b6963,9f3d4860,9d9b960f,4e7d0f50) -,S(a436f4dd,23ac70a2,c093bacf,91de3093,174de618,7525947c,2ee8ccab,a515acbf,c0e9d9d9,2a615b9a,9439a450,927bc128,5879e8b3,7d460ec,9fe57eff,7e19afb9) -,S(a38eed16,699743d9,16d8627c,5039695c,37497c67,c59547d5,67bdfa20,b86f1930,6e3e3ed6,effc3b5a,c9b5b5fe,3f26c91d,3be89bb1,48414c18,bb0e5454,49d9d7fd) -,S(5f4590d2,d4043a1,faf659e3,36b0f24c,b6f1de5,88e92586,83361eba,e2fbf3d6,250c0a73,42ceec0,3ec1af11,764e7ff6,ccc833b7,240466,15890be0,55197db) -,S(7565860d,c6ebb900,68ed16ff,8f7282a3,d52beac7,73cebc55,1be51f44,34cf56c0,4b56ecbe,526ed458,5428ad7d,e9d7f3eb,9b84687f,e01e1346,c32461f0,bae24c26) -,S(3e7c7fce,3a56ef01,cabad50f,2003a5a,77292742,be80b5de,c537b50f,95a9320c,98cd94b7,926e7111,f3778904,599fa9d9,d5dc342c,c495b914,a32d2722,93dbfaf1) -,S(131eb457,14cecf84,abf1aaf5,ec4c62ab,2ac91a0f,6af57552,2eb07274,b7cda208,a93aed4f,f0512604,46c61393,faec55aa,9b017a13,60d13031,27bfd897,e320839e) -,S(371bc601,e46963d7,388bff6,9c4b5f42,a98e68e0,2db3e6f1,637dd24e,a2a11ec8,e2fbeef1,932fa241,a9785238,c1b89269,21bbc7f1,3aa6bdd3,7b39d94a,49f84622) -,S(4770db04,92ca73e8,a0136bc2,2c45185,b4d45934,e4430237,1bcf5045,cae47d6d,e1af748c,25b1d906,ab77e080,d21df4bf,99a92f7b,4b1d790a,f1aeef36,2d41ec22) -,S(b31a8643,5af5db57,759dbae1,67ce3af5,e8e2ae34,20786fe0,da82812c,9594bfff,3793425e,860dc99a,a96a85a2,585b06a4,f5aaabd0,551fe0cf,3c743be3,c09aa4a2) -,S(e05eec52,84a2501,fddfe6dd,1619c374,a94121bd,7d1c99bf,9b2e665,bd3631f4,c0115f17,2122f806,99a24ea4,bd742425,4d883d77,6d269ed4,f6cc5626,ffb8e622) -,S(e55ddc84,ee407d3,45b84305,d97d3f57,e57810ef,bff3b35c,e4d8a325,2973d5c8,71f77bb5,b0fa6141,7e43e425,78ebb13c,abb87a6a,fa0cd1a1,26e8936,427ee677) -,S(ed7b6ab1,a5c8a9aa,284bf3ea,5501d33e,1aabbe76,f26a9f0e,d46dd23e,decd788f,2280bb54,19d1a620,18454a4b,cdfd82fb,824027d8,c51770d3,77233e01,1d0db63e) -,S(d4e331fc,3da4d8ae,e13a3329,acd4ee69,ce5cb71e,224f2001,f9606714,8090e79a,895141aa,2f63cd30,9f4a6b42,d6a88112,77821e51,6d08c52,1ae8e158,655e10d6) -,S(4f0ada0e,a8ec1ffe,6682545a,bd8152c7,2654718e,120d3d54,d648b487,896d4417,a603b9ac,6026ab46,47f5acf5,5a9fbaf7,20aaff54,56c88cd4,dc5ec7f5,935aa591) -,S(a2d13541,b08eeee2,4f086a9d,20df7528,a884cc05,4106b1b7,543eae3e,fdca84,5ac0b166,294d6b91,527a5249,7fd605ca,4bb67c35,85e002d1,74503b7f,5c803a45) -,S(4c1d520,14a0459,2b8887fd,afa945ff,cbfc4722,2ce008f,64fe8123,b5b6c8a4,243c4280,17b7918e,57d06597,f348efd4,ebcebff4,3950a608,3bb3e334,50ed738d) -,S(5f9e5a6,7d13e9b4,cc35b8e6,b2305cb0,fc2f5b7d,ff32ac55,1a5970a9,2bc54390,74808637,96965f7d,bc45833c,e8bedf00,85eb0cb7,26f3276b,30d9543b,7395ff6f) -,S(d76c6f80,95381b17,80ad28a8,80e29ab4,4447c297,34a4d286,98534bca,8954575,44b6c3f8,6b30e01a,61205178,90e429de,aa8273f1,277bc498,59c87300,a561b27b) -,S(7577729f,f78775af,703a9eae,b5864a18,6ad19f1d,dac658,e7a8a05b,d9df3344,6b519916,cceaaa53,92d2f822,98e7ecf3,3fa7c5b1,2e705345,32ec3f99,2f0afec9) -,S(50378f2b,457f04ba,d0b19425,86ada992,78700c8b,36bba67,fca916c5,8edc17db,cbd1451c,26bdcd49,1adbf40b,ac5338cf,26957364,f82fcad0,5fea3c2f,76273fc1) -,S(3748dc68,64365160,26384ba0,ec078ff2,7606eb44,e3d62b50,b9138be8,cc9ba86c,6c04e414,f624ae9c,ddd005a0,4e01828d,6e7bfb81,d350d271,96583c99,6611d709) -,S(b23a59be,8ea8d561,fbdeaea4,49eac729,3402f342,d05fd404,7f9c5d1c,57eea53b,bea47c68,f2d35b82,ce3c359c,83f5fa1a,95d40eff,702ed9c4,2fef0e84,406dfb9b) -,S(e4b451e8,7b42a5be,5c5f443,5701d2bb,9538fc06,925ccb49,ebfd71c1,16a64770,2af84669,9a790749,48efa86b,2b79b985,4cb261a6,8a9081e9,e1467b77,2f156da4) -,S(864ac6ec,65b8b086,346e671e,8651ddf9,de74a215,64f3da12,42ff7548,96dff165,f35738a7,7ab48555,91ca5103,c8d2bebd,b2cbf902,dfa93188,d68eb600,271a8730) -,S(b7d04a3d,a6a863d9,b7809022,56643864,fd36c5d7,9a056ac4,ecb27257,f02ecab0,cc40634c,6ba5dc23,e59e4e3b,fe6a07c0,1519abbe,7530f1a1,5ec7ef70,6f83b0c1) -,S(ddfc1af9,b51eddd8,2020de0c,4a8377cf,bd6e2531,ebc844c,7ca8fca2,714c1a0e,cf77c8c,1742c4e8,b22d9f54,a25daab9,c30f23f4,da3e1ad9,57b9660e,3ffe3951) -,S(78fcfe69,d5bb91e3,a13de26a,614d8479,e00c828f,8868fc30,ea75b47c,d51fcbe3,9ec67963,6b7053ba,b0cb231a,ac28143a,98021b48,4340f060,66da6e72,47f2d47d) -,S(dcd918de,16961d71,8222b4f8,19e76ecb,138c9884,7833a8fc,d4204dda,1115863f,abc3d8ba,c8d808cf,ca12318d,d13c2932,3ff7fb0d,813a5ed2,f5e52aba,cb23bb04) -,S(39ce2ef0,5de08106,93294eef,537bc212,e6f64fa2,96ccd2b2,94a0806c,c6c3177e,25eaf4cb,b7697a3,97a0ca92,6f3a266a,bbb5dda,78943492,39fd29db,78730556) -,S(495e4db6,43d4e89e,df50e937,e97ac4ba,1464514f,d3a46b5a,bae6a53d,3157a04,7d327e18,b2960d69,ebe4251c,f8c416b4,f84bb81b,a20ce6d4,6e6b1c57,e6ec1701) -,S(91c17e8c,b6357c0c,1c36dde5,29f9e6f7,a6cb6e97,f5b67dbe,fcaf5b96,637c33c1,2fe52097,fedb8ac2,efde2692,20f586af,f07b76e0,f685ce85,c965ec1b,a54c39ba) -,S(e3c4f480,3dffed44,6291f11e,cc5c9590,1c28749b,d6ae18d4,c0371221,d5ecfdbc,5a2e7102,571e27ce,974ad71d,acef8b28,4e7fb827,5453e40c,65b2be92,cbdc62d8) -,S(b3ee17f5,a0e81e7b,48814377,af9dcbb8,59ae7bea,5680f33a,cc15d8ed,75c25073,135a3c0c,9a6d2825,a6035afe,139ede23,b46332d5,5739ecb,6d092e7d,6cbfe86d) -,S(e4cca844,2bc91bed,342628e1,f6492335,7ca6e8d9,5e5b5732,29866066,eae76b75,dd55a555,39b5670f,f70b42b0,f319ac72,409f74e2,31d9cec,ecc8d90e,516f76b9) -,S(ab39cfc1,81c96089,998c02a4,64eae7ae,e517e4ea,962b6359,b5ebfbf7,da223b2c,def6dc57,b4dcbbe2,e6dcfec1,8281a189,72ba3b50,f996096,a22e4ea9,77d2fc4) -,S(22a32663,9e6e0469,fe4cad40,964f081a,677572d1,94b3ae01,f8e45c84,dfab402a,1c9c9d95,bd4e0ef0,5acf6148,44c98fcc,db44cf50,5d42af26,1b855f98,40d2b437) -,S(2bc788cc,eff94bf0,307c5ead,4fbc4dea,db269da1,7790a903,7c2fcc24,21f9cae9,172f3461,648c5520,44081c43,a8c78c3c,ccecb248,9d60d384,aa703e4e,24bc4b41) -,S(b930dbd2,a6720601,35a75bb8,8bbe69e8,3872c636,9fbcfe4,c622a300,2052729,9983f03,a872e8b8,2830e7f9,a7438b39,ff3f6836,3334debd,83940ff5,ae06f366) -,S(b435738a,2aa9ea40,702db448,da6f186f,29bcd03e,872a3466,f33b2e39,7514e3d3,5828d246,2d3c671f,85617e55,bcc34905,1678cb8e,f61c74e,92c54473,9098636b) -,S(c91f2e81,3acc9baf,2c52df27,d4180dd6,ee1fe67f,9db6223b,532dffb9,3072bd25,1c9c57d6,96c12f13,13afa0c2,b377e1e2,b027350f,bd24f455,69c15f07,85b73c0c) -,S(bb0946c2,8099ba93,8f28068f,416d9003,bad0d06,f8c7d31d,2b995f00,5c8d36c8,8e3878d9,3b575fe9,78fe1a62,1e978f28,1560421f,7782c164,8673906b,ed76da4a) -,S(485e3aa1,2e823374,cd506521,a707f367,5298dbf7,cb44f398,c31a06a4,8f085c8d,a12c8af5,7079b2b1,5a339d4c,302fc262,af0153e0,dfb4f878,a4b60017,86ca9a61) -,S(850f9448,d3282256,940da03f,e8a96eaa,f21d02a,78867db3,e8a9fb9a,713e844d,4551e4fe,3201ba2c,a74df3a,f58a820d,3a67836,a5a8d82,59ab2442,3bfccb7b) -,S(a74816b3,f66c1fe4,9f8e51b1,8eaf51d9,449cd4c0,54b6dc43,682c853b,be39884,4e7d5fb2,47ed7ea1,45af0cfd,c4cc1059,396626e4,80ec804f,15ecef7e,b372f7fc) -,S(2af5c56f,c71da217,79abcc1,73412016,e1eb702d,6b98af77,85ead6b7,7b20136d,7f3110a2,c6a82623,b2c49e95,a31a6b8e,783911d9,b532932,1b651541,86b706bd) -,S(9291ec91,a61adf1e,90d63135,fae60edb,1a313714,97260903,9684fee4,339b5834,d530506b,e8b0dbb3,fc09649f,1832de93,feef42bc,ade2de09,bac1dd17,bdd03884) -,S(160ad3c3,659a7816,4e9cb47,4e18ff6b,a8581fd1,823ce8e1,14444292,cc605b54,1618464d,5f28d719,a61f939e,b1eb91d9,a59f2c1,818dbb58,b6e1f426,a4d141fe) -,S(352599bb,8640920c,2d85a5d7,673dad8d,ea4280f8,6358a572,b4071934,60ba9d58,a78a591b,e8064f2b,22d7707a,d3c95cac,aa2ac3d8,638d564a,50f7d1c2,8b538d0c) -,S(ec20efbd,9a8c634d,92f7a728,1e9e15d5,adb37ce1,2236bf33,4d12c4fb,7b6ba527,acdb29bc,2a5a3115,3919315e,27af9d8a,e8c54792,fd5421e2,a9a57b3b,d51b70d) -,S(40d1e4da,8bdac6ec,55ee847d,c59781e9,bbd38785,1863c64c,5cfad460,e2dbebc3,c630581c,b7c92e68,a67c7d5b,dba3ec18,4e3755ff,27fb53ac,d3a2655a,316e9ab0) -,S(fbe12740,2faadf2e,2b1ac1c3,98b66df4,81674c2d,f0ffb512,7dbba444,e7d08c7,d00edcd7,f97914d0,3ac87182,14491698,f3dfee34,e6e8587c,52f2f7b8,b7f412d6) -,S(d781b5a7,47d191fb,8850fbd8,fb1e123,4070d9d6,2643008b,b0cd930d,c191eb03,a4aa95a2,5c74ab55,f95f2924,519b2911,9762ef30,248db792,d906b18f,346afa11) -,S(6472fc42,d926bc7c,115045d0,395b5e9,22790c39,ee520529,44a446f0,9ccf02cd,512014,a92593de,e2264e37,633c842b,45d1ab5,e2ad068,63db7894,4605a99d) -,S(eee180c2,e09601e8,6a517a93,54607a2c,5fa6cf26,4c80ffd2,c5715ed6,395e0c21,c8cba798,221d6fc5,b4fdaff7,f785ca3,49490af1,ae655711,e0649669,7483e7ea) -,S(900b262d,a172ad41,15bec071,c5763077,9103bed4,db500ab4,fad4b750,45ada2d6,316457f2,bbadfe91,3f418e7f,b3fa34d4,82c4c1d8,516755aa,371423e0,51e2cbaf) -,S(7e93db87,4e1e5070,772d3371,b9ef29d1,5d5e03b1,e66bce20,420801a2,13a34c9e,cdeaa624,750032a6,f5faa0fe,e00cdc10,63f3ec47,b5bfb56a,bc2c2339,e38465a8) -,S(461fb424,65f3a55d,e66761b8,44abfe3a,d172877a,3edb1f5,da98c82f,89a379ca,768261fd,ba032718,f5501dad,c05e41c1,1f584aa6,6b8e732b,7f15285b,18e815d9) -,S(1d9f581a,f0f61a0f,e5d0f0cc,91ba4f93,6de28aa6,5f35059e,997de778,9419e09f,7fe9c98c,7d59dc56,160302e1,89676f54,3f02db1d,622251f8,adf369b4,891bf6cd) -,S(8cd70b52,904b2aa7,240f7a70,e4efe379,66386dff,3ccdf62b,e2343821,767542c6,b3c3d03f,4c7e0b1f,f08bb2,f72bc6ba,e9e293d,886541f1,ff86bec9,b5ddc2f2) -,S(a0b547ea,9c08865b,99a5b8b3,800daefd,99097b23,4e442a2e,819aa628,eb4a5261,607ef115,e585100d,c003cb4e,1a27eb60,fd9d1e18,f2d23a22,80cddd89,f2ca2952) -,S(ea8a60f6,547038e3,683a649c,27e81ab4,192406f5,5fdbd775,78dd6360,4344d289,98afcac0,b05ad5ea,8fcb9f3e,3bc22f16,881b5fcf,5060c691,ac10f746,79822fb0) -,S(e6051a9d,882f9ef,77d488fe,55bb7829,48bce506,91350755,1a8cd4a,14b0a711,1c9cdabe,9d9eb555,cb9257b8,a60af75c,c1ec0c82,4d933498,ffaa14f6,2e920fce) -,S(600876c9,c50fd337,6ce5efb,c07e0e5b,165338c5,4f8eaa4b,39a525e9,88765674,401a671e,f52b21f3,83df5da0,aa0b215b,b044202e,606a746a,213796e4,dbea4189) -,S(3b045b9c,5ef6fdd0,9b3efe12,169e0414,3c0eca56,5b7e0185,274f1e97,f6b2ff40,aa5773ac,b21107c4,2a8085d0,5d6914c3,a135a47b,cb136dfa,d20e6813,62780a28) -,S(dce98d32,ee0b55e0,4d67807f,ded9cef5,f9504b1d,e552a2dc,643ee7f4,b1f0f1b6,d03ac27c,9e992497,cbb746d6,7acf5427,aba058e2,801df1b8,d435a1de,1f3fb086) -,S(365b1148,6e8a60fe,8a91c07a,93686787,dd5aea7f,22fa1449,58be984c,e378fd76,2c7f5217,319e5d50,4c5ecbbc,bdbb8ec1,b36e2767,54f405c3,f852b761,ef01c9c0) -,S(2e37935a,4dc465ed,ee8dc3ca,d4ede356,3c3720e8,57c986cb,b9c73b2e,ab6b5806,bd0873f1,5278f46d,802dc7f9,d7f81a4a,839cb690,10c6d522,c0e3945d,4bce346b) -,S(49b68e1,93745ad7,b60ddf92,70d71958,81cd8585,6e47b0bb,fbae94,f1647568,ca1d4bf0,13e43ef,53bcb2d0,5f4b85be,1dc82d31,f4a7795,755693c0,72819dc1) -,S(6df53d6c,c79c5a88,2c2b6f66,e9ede075,6c8cc6ba,3e60620c,b8130fcc,fa744564,48c3d6ed,3b2b7c59,2472f291,41a61495,4597f77c,afb576e1,729804d1,26431344) -,S(d99f8f06,9104e3b9,26163672,767145a2,2f9467c1,c8e32b8b,d28e170d,bf4865a1,ccfc46b0,55aa5d93,64e67c4e,2c06cb18,c2b43333,e4111479,fd1bfe50,52543d7f) -,S(77727c17,ebbf8338,ba807572,8558a059,e23af7fd,c68c342a,538ead93,e59930d1,a037dc7e,2cde1802,fe3bc65,75f50ca4,ede75194,133e7083,66de0338,40c629ea) -,S(1d40ead8,563a4ff7,c14c84cf,ad1339ac,36ae3789,99ec2663,77e0ca2f,6be22604,8497b443,b093917f,ee65a5ac,1c4dfb87,3a6b0c2d,a968d713,a711ec12,20d1face) -,S(2a39f41,adf5ab33,71a27c20,51840d37,e3226999,17a3d0ef,40590710,406bfae0,cdaf7a8,58e99fb8,23a36b04,8e844c18,8dd1a49e,c70488ed,155f2ac6,905c27c5) -,S(aaae4b1,d8b08cc4,8971cc92,fd974a21,66f5ea92,b6ce215e,28137088,19c684e0,9237995,c10a348a,84fd5cd5,5151e33,c63739d1,3a425bde,a34d78e9,e3cd8f0c) -,S(a5b0c042,591a53b6,334939d2,9ac2c9e2,11315a54,831ef440,965fdafc,e6477d40,ac3e7cfd,5d1f0248,b362b206,b3c7dd60,bc9904c8,d2a416d7,e117a5cc,4a62ca6) -,S(c1b7164,e6166a96,a8f643b4,7f094be4,3c16e3b5,3ebf5a1,2782e41f,27c63f0b,8469161a,4ffaf1ff,5b50ba81,1de3ac79,e34810bf,73ed1207,fcc0f01e,75663a98) -,S(98fd825,4b7963f0,4d8e0f2c,8eb26dd0,342e605d,8fdf28b4,57b98e14,adca63bc,e297a80d,213f6664,77f9dba6,5cbcb99d,2dc14325,be12098f,22061115,b1a192d6) -,S(f1f08649,71b6ed49,2d34127d,8c2e6f19,48c464cd,816acdc1,63eb3aad,594c3281,26ae2a0,f9e04fa9,13b8954d,85602e6f,506a0de5,2fdec31a,346338ab,f31f5c) -,S(ff470cd,c324d2ac,a63441ea,c0506fb5,b63af83a,61a23a91,17240e23,930dd197,e601f66b,b18e77e8,4607a772,a1efa73b,30734b4b,8fd31eba,5a5260d2,5627788f) -,S(90eabc6d,968aa196,b5808127,baabbaa8,ad0f82b9,332ed6dc,d04442df,bc6c63a6,d6df0f67,ffb23cd7,2dffc4be,44476b2b,2faed3e3,dcdc30f9,4c1fa4ee,bb5038f1) -,S(e217b126,acc507a1,b41e0826,b300363e,bc0a43b6,feaf3866,ecd4b8bb,cc7e11af,7eb28def,83db33d5,8b8eb733,2b27a386,921e3a5f,b0321ecd,a8d1fc6e,49e98f30) -,S(2a196fd5,82b85d5e,1772bc21,84d8aad2,b5d008ee,c795628d,20de68a9,fce1d184,994b4657,ee9ee3d4,fdf8dc8c,cad2ff1f,68526c67,89d82230,c3399f6,62201303) -,S(bc9e3bc8,3a6eca7e,8a9897c8,1118f7be,ca770cbd,7e66c2e6,1321d026,7ade4342,9d7ef7e2,d544a561,ab899291,75f35d24,e2b07661,2f84b0a3,f346542d,714f3f4b) -,S(ff2813f3,842a9f84,fea9e367,6f12f209,7e76b8ed,e691ccdf,6f6512aa,b2f198b3,206e3bd6,66d0c161,ac6de438,809f485,b8b6682a,f402bf76,18a484a2,c3fe1949) -,S(6e7599df,2d38d63e,be142321,769d7ca,34a50bbe,4e0adbaf,6c7479b8,d1af05f7,233dcf1d,4b0e4d88,4a9ed56e,b6b4946b,25614345,ecd182cd,5556faa5,e3654c8d) -,S(1edd9cd5,6c82eb28,14d844d1,a9e5c167,8397662e,b576f9f9,ba250719,33666146,a00f4a85,b2ee83e,949b5cb0,4d16820e,39d48ddc,95dd965f,e24251be,3df43f4c) -,S(2723de06,1f794cd7,76a4a090,738a81ea,818a2f73,92d7ab07,18d79fb6,407324af,35c7a9be,f9810c50,3c53429e,344ab888,38daad72,77cd0e78,3db1c1fe,c6bbf41f) -,S(4c4fb244,4cb54def,6d9659ee,b43c13c2,3874ec2b,a7c6b53a,f469ca26,ab9a213d,bbd2eafe,56447a9f,feb9ad15,349b338f,d4a1aed8,5a356472,82751e5,5b8efa3d) -,S(736359f7,347995a8,8e306977,1fb3fbcd,12847ed2,8e4e612f,25095720,667593e3,23bb37ed,4bce0512,35a215ca,6b8f9868,e303fda4,80d655f9,72c95bf9,12bd3741) -,S(15cb9594,ee936bd1,4b981394,60879bee,6f33b0f7,c0ccb293,825794d9,85f595be,aaad772a,2ec81ab6,13775e9,edb274ef,e2e133e6,5e58949a,c7f25429,fb1bb152) -,S(3b5489ab,97e5cf1e,84a90eb8,20b8772a,df574777,a61f0a9b,41e6c567,6be78fa4,145d13c8,e9674a17,ccecad63,f113d64a,d59a1eb,bbb10cf9,e7134cf6,562219be) -,S(78d1b99a,a6f9d385,b09bec7b,b59ce26b,23323e4c,3a259c56,68417597,a29dd2f5,1c8d11f8,e883b210,cf54369c,e9f6a280,a6b890ce,15b4a0ef,3cd8837b,7e16a122) -,S(385e4e8c,5ceffbbd,3a813e3f,938912e,d2fd2d18,2be81210,70cd15fb,39661e85,f4a1c414,9f5cfbc5,213ceb21,c1cc08ca,c9b168e2,58cdec70,36e2dacb,ab68069c) -,S(310f8c70,d8e46c6e,48930df3,c53e9292,a7c87230,292d6b1f,c28d9711,951aec6a,6fe319d3,c92c07b2,56715154,d5d7046f,59d92d5f,6dcedefd,b0386f5c,3417146f) -,S(764f3c30,23d1d50a,e170b80d,48d58923,c1f91a96,42210912,94066585,d7c70bbb,bd92fb1a,becdb4a0,ed941146,878c99cf,c3ee9eb8,c8f2b8e4,b547cb40,e3dca724) -,S(3d5d23ba,b357a37f,1bd3c86f,84010b8a,b37a8075,3c47b1ab,36f7ef72,a3e68126,2bbd1841,bdcf0265,838893c5,f5f9c0dd,7ccbb461,93068e0,8211595d,6b34255b) -,S(a70431ad,cdfc7b8b,febd2aff,d6759e94,6d4ddd7d,50f50dc0,87e256b8,2a7f8a1e,3ca4362b,9362b2ea,c33d77e8,befeccb8,23163921,86ff5f20,384247f5,9147f593) -,S(2a388212,2c1b2ecf,3c800432,7c5dd403,2263e9da,245dc697,bf7d63e6,300e8a7d,ac96d188,53b87bf0,3dc5f2fa,fa9b73a9,a339c0d9,a7245175,fd72c822,12f6ff78) -,S(e99c59a4,ae3022e,b50bc545,f57e3013,56b49bff,33069a9a,b4d17c0a,424b5451,29b24b79,fe55fab7,6c3737b5,61505916,b4fe1a98,20837349,baf445d6,2e9bada0) -,S(a0a42ed1,bd5ac5ed,f63f1a3c,3c3fe2d3,c0be26d6,b0da384b,f19c034e,83306d4,c39ff3d2,d4442374,7a293e28,8c320ee8,8aad0879,672679e4,e5bcf611,5ca0bbc3) -,S(b952e5d6,9ba9f063,f1d1670e,1419730f,5cc17e87,b6f0b01,c0b86ebb,c09e0053,c1e8099f,a230b8da,6e71c9b5,bbf250ae,273a4f9a,f53cd0ca,fe8f0c7,2dc46ae0) -,S(3aee273a,130f5f4e,463892b4,512621c9,be83c18c,655d5a2e,620f83fe,95a4e904,edf475c6,921fb6dc,f2c3c6a0,b93f9470,9237b035,9e8c9131,eb7eeb0f,bf0af7e7) -,S(96ddcdc,dc65af06,acb10d91,b87827fc,aa2f9e65,d28d0449,65ce255d,ba66ceac,2e6d0368,17fd4024,c830d4fe,310bbc23,9e2bf37e,60203584,215f852e,d100ab39) -,S(fd50f406,c757ec9d,b10e111c,32941fa1,e0d07ae7,9e3584d5,af45fae4,d30334a3,71b77494,d49c068f,c7db1d36,4f8db288,ed9ccb0e,c6137348,324f4bcf,d53fde6f) -,S(6f2d8268,11954523,614915c,9568ab9b,bd061112,bca3ba77,d3c64f91,6ba097d1,abe41199,849ca7c4,d317fe72,2a5647a2,97261d68,d025f5af,e880ef78,34787a87) -,S(d88c0db7,6dffb62a,27683d2c,e832a312,9c5099db,e2623c9d,3f064247,21cc1400,5134f15a,df6d7e92,5d81726d,f08732b6,ba5aa289,431bb4ea,542e6352,8dcec51f) -,S(a8de9ae4,ddde3f28,ead01363,2202fe4c,b6c0fd4a,a71d5562,d95f557e,747105fe,179e946b,5a71b614,90bc39a5,17dc752a,53682043,6efa907e,383e3da,a3be8803) -,S(626c6827,f7dc3d40,9daa4811,80e65b0d,799c94ef,e48077ae,6eb250aa,8fcd45ac,3d659db,87cf7b28,32e4a2db,8db88e5e,b30b7ea1,7819c00,fcec5d63,31bf2f32) -,S(28a3a2c,f00efa47,db4b2ef6,9f56cf02,1666ebef,b5220495,5b5484f4,2ca77d02,8dd00ed,fc9870ed,99ce90fb,927086c7,fc16837,9794db01,f7799b16,8393c82b) -,S(df0b029f,27c46405,245d0dc2,f178a48e,c3b67275,7fb92bd5,dbb29370,c1545786,f133ed05,c7e159a8,810a5ad4,e1019f15,757b474b,fea1679c,6ccd18a4,2a1099a) -,S(dc6f57af,9c1e0be5,2d2162a4,e8a6b63a,c549783,4c7c2c8b,421bbc5f,dc1a49ef,6f586aaf,e610fe5c,962ee20d,9b389bab,66fca44a,1c19379e,9e97e104,10f1a0c4) -,S(db796ea2,e0d2c690,19adcc0f,a81c1d93,8162472e,a0e3eac4,bf13b398,b255cd15,2e60c6a7,32e1fb44,641e0766,2191e28e,79375420,43bdb3e2,9474313c,7d05ac88) -,S(569b669e,72ea98fd,a5ba3efc,e74f88ce,881fe269,30b063ca,59fe369,35633a2d,badd8eaf,2551f872,5db3f740,6eb5e376,220b6a6f,ff4f8ca2,f76b7755,f8ca0c8c) -,S(36132420,1f9a33bb,d4b6b6f0,e2d175c6,ec795111,85fd2451,421ac333,78468ae4,f47b56ce,f7bc7366,6eeba135,14756486,62a58e17,d955dee,2821618f,fb3c4314) -,S(cdeb2037,1e4d2014,918fa243,182db0ff,855a0783,c92fd5b1,b604ed33,494a469c,7d3c7718,6829381d,2fd0098b,c84ee506,970a7ed5,5518b393,a83c6f79,d8dfa7d8) -,S(6035cfa9,d750c5ec,d3b721,ade88fff,ff6c4d74,f8db7755,c8717cfc,171598ef,fe1798da,160b2436,412dcde6,5482d202,9bb129d7,d58c9cb7,49f9fdb6,7dd675a) -,S(b1f52e97,e49998e4,e0e75b0c,47178f4,bb250b5d,97d92ac1,8dc9e41a,3b79c0f7,d83f3d65,4e4cfd8c,5f24370c,a2651c5f,de484cf8,1024f33d,8087a50a,d3df795f) -,S(aa799b53,4c73da0,9f011395,dd5f709b,f1a5e056,42536477,d7862b21,6df1b641,3a327047,b5e95b64,593f6887,9f38aa86,dd592007,cbbe7338,a003d2d3,33248646) -,S(da4a1964,45bdf4fc,479e56b6,6d339a45,262d629b,dd8c63c1,8d35e9bb,a445aa03,7b3a5eda,25cc63a4,66cff29,634d5eca,353376e7,26c2c6d5,63f3f92c,b69cb70d) -,S(c300b4ad,c2346d0d,433eba80,f0eef071,7e620d46,a07b384c,231e733f,a1b8d656,32083bb9,48d27ac7,f36aa439,a100b95a,f73448da,454de356,6f4a8771,e3cdba42) -,S(c559a528,67937244,d639bf7b,90df2b2,ed64a907,e20cebe7,6a358b2b,94359f04,9fcac1aa,5c08c983,20d671b5,63f4434a,806d78da,15964474,d2470cd,49bf5977) -,S(39b10147,a46dbf4,f074bca9,a83c10b1,b0911ceb,d3e795fa,9b96333b,dfe83540,ad35dcc8,c3b22743,4daaa313,cd6334e0,168da417,d162855e,64294196,2d308278) -,S(39c9cab7,d2dec601,7f840597,19994c9,4129ab2e,a2779d6b,34774a04,2f7d6d42,c73ebd6b,835a8a13,354cdd45,37ddfb3e,72ca72b4,c8049362,3afdce9e,43781845) -,S(1a625998,8a30b462,adec6097,2e218ec3,f8f81c4d,44131466,fc7b5eee,eec679ed,739beabb,1a97c9b,bf6776e6,2e213bd7,3651a39d,ba042037,bf5f8cdd,334114ab) -,S(396ed910,cd35c308,d412761e,bf283a98,85f33ecc,3ef643bf,3f422dfa,ea4c4308,721cdda6,a08a614a,4dc48cf8,442a46b1,3945e158,83671b7f,556d19e1,144dfe57) -,S(a50e06e8,a2e8ccfd,94aee96a,b0bd831c,83e15340,25e3abec,af7b7af3,9b299a47,593205b2,59a18063,fe5a4575,e8e085e1,4521fc1a,3ab5e14f,3fcd64fe,2bbeba52) -,S(4a9f8023,17b0d1c0,e62c8bcf,7393fa34,dbe15cd6,46e8f4a3,dc3f26b7,11c3e1de,40eff6d,915fff,cdb30c24,434e8928,239867c3,962655ac,2894bea9,f7c6bb71) -,S(8ce5e20d,9decb7e6,10b18562,e2ffbb88,7f323262,55ed9f05,5d2da2fc,8d608b73,eb69b6c,f363e164,e92371,b592727a,63f024b2,aa7011b5,4f1f698e,1ac720de) -,S(f32695d7,9b53e9e5,1f2525e2,8a5540ed,84143ed6,3700be0a,36726f9b,b483f24b,e8d36488,eea2055f,6592ca1f,6fe23493,1d81bd16,1c61523e,f1ee1907,c08471c8) -,S(3826fd86,3bf6592e,5b51ad14,6e02089,d9274881,25d25959,4856de1d,d6c34d07,ea86f1e6,a29035c7,43e82058,a7ff9f82,20da001,a8901e97,26583b1c,ffe4cc83) -,S(7b1afcd3,2e32b0f5,1ba09868,4ec72762,ae8611a8,98e87ddd,dc6410a,40ccd551,deba6ef7,79e10931,8036ee3,9bb6d0a8,a3ce0eb0,bc5620ef,c70828d3,d2e37884) -,S(3eb1fdfe,d2c27587,540d39b1,b66a36d1,8dedddcc,7f7f7b63,348460c1,35a91bd4,b8aeaaca,536ae794,619506cc,a812a67a,642c5345,8cfcf7b9,eb898f96,d26b36cb) -,S(9d61dac8,aae9fc5f,532290cb,683eea2e,b71b4d9e,901b7c45,c214beb5,9b56da8f,2e7caca4,2ea1b22e,7024fc3e,e267ce99,280a8f1e,78a2a271,7938762b,3a446036) -,S(2db372dc,3167faa8,e8e1e37a,85ed5546,e91a43ef,fddba39b,e38d0eae,3e11c7d8,16ab6f61,bc1abd6a,16e79697,fb59f0e8,84f00534,b7196380,9b06e10b,59707ffe) -,S(98f7cef9,f7a2b538,538e83cc,9ad3132a,5b03dd67,f7fc4030,2ff023d2,8805dc80,3b40f823,2813e6c6,bd56df89,1e96a175,468bedd3,f9518dd8,d658105f,aeb98943) -,S(eeab2e6c,c8ab0d24,d5df5852,8a89db42,c48f0861,4d488c7a,363cd195,edb62548,607c41ed,65d3328d,72be2503,f5edf14,523a7f74,402822cc,1709927,c82649da) -,S(955feeff,b2161c70,3469a9d6,c5fb31b7,b7cb5ed1,ada6b537,6d935705,b3db942a,a9195a48,a561c342,779c984,6a710059,283fcd0a,682cb5a3,fdf48ee4,15c0864b) -,S(219a4d2d,70d2ee9e,d3c8f541,1cdac36f,4db23bdd,a981a5c9,d44ce5ac,dccd85a7,67441968,43008ec1,71284aef,2c64f7dd,3dbfdda9,5c6c8e4,70a564f5,c4ef53b4) -,S(4976290d,7794b161,2e2f5cbd,282c1036,d594571,722e28a5,ed542972,f91ddb23,4cfd95f1,60fc5655,2fc8354b,446dc510,23571c24,56f57aec,79004616,ce17ebc4) -,S(472d53e0,268ead1d,bbbb99ed,599f5676,1866e0b3,c14d4a4b,5c44d722,b072b1c1,e9b9c009,6115d4d4,a8ed42e3,1d967b89,e4dfe82b,ec642db8,e31693ec,c2831232) -,S(2a6f5b7e,7a4db95c,af875d61,75a6e1b0,3f3462fb,c0dd5d50,da3327b4,70ab18ef,91b247a3,92aadc19,7d9f5b78,f0b013ce,c9f3724e,a2f37347,9ade7e03,8659d506) -,S(dc1815a3,bf48d81b,b5e5e654,fe0c8c3c,7431a62b,9d1065ba,17df9c45,23146c19,fe20729a,311550f0,e47e2af7,4747effa,d837c5f7,b08c8f36,d0fbdf2f,d594be8f) -,S(8e7953ec,ad8feeb8,97a95db4,f03ffb98,a8b47ecf,3e68bc4f,1df0b6e6,98397776,5dadf2ef,81b21cc4,26c40a39,51f31462,12f7c6fc,dabb5157,893b1637,c141ac5d) -,S(a4d91e6b,49d5724b,9e899fe1,c6686c89,faf96a05,6e666a74,72ee44cc,119b41a5,abd68615,e296498,f5abb820,cbdcfc26,fef10b2a,ba72e474,14ae9de1,960a4893) -,S(b97081a4,f3e426b9,d3a66dd6,8e0e442,754c4922,acae141d,d0294843,6b00eee9,558f6c83,99214bb4,baa9cb64,11550b12,2c8c2f77,8e28a4f1,ea61ed6c,b8f153da) -,S(6882b6ed,82279bce,70a73c6e,f6412c54,b873a5a6,b634a25e,a8c34210,fb825848,c6fdeee9,c8233e39,2ea79c61,6689e8a3,1e3a3b09,21f2b5ae,d6b9e14b,9ff21b3b) -,S(9c542731,1c715709,cabbf11f,a4fdeb3d,1a0dba80,ad50d1a4,62c7ee1a,44717fe8,aa041b10,78163458,c446bd40,ca77f760,ef4b6471,c4f2058d,7ea42975,d1f2b045) -,S(73a14da6,776b5c12,e838779d,e3be58de,4a5ed917,3b195d9,3577330c,780cd32c,c4068ffd,e98ec4d5,a7467bb7,e8bf2c89,ceb58574,cccb3a78,b0ce4a70,7ad2c49c) -,S(6488a286,27d26c4d,bade9d26,1e6ddb7e,8748d835,d9def8eb,fdc6c576,b6af91b5,27f8b1f0,b0501191,8af0916a,945bb07f,3c7f0695,5ada697,b5c601bd,3d6d8ff3) -,S(96546e7a,5b544c98,db9ee2ef,47dcfbce,cca1d38e,1978f71b,d8c9d4d0,5151046c,d04fe32f,8fe9ecff,220f07d2,2095c982,3b10f772,b261189e,84160ca7,5f4309d) -,S(ba046f56,4598b143,a02cdb90,972022ed,e769986c,82d28066,761463ed,8cfecdf8,fc6e23ab,d42457c1,5407d37c,d3d9daa,3e57bc0d,778dd68,53603232,3e27250f) -,S(39554751,e633ca7d,df6d82ed,86a8204,5e76557f,b13ca7df,310b80af,5ad0e4ec,a456ba84,f040f20e,977df5e9,5faa3f67,cdb2ba3c,2fb9bb4f,89486b02,a06d3b1c) -,S(c5f550e7,5fef9fd7,d96c924,11046c3d,ba56b8d7,e1b17c,d46a68a4,989c22aa,548582e0,3aeab617,556a987a,cee7d0fb,8d65ea42,dc8f2cc2,173c3636,27ac3fa9) -,S(2ccc1610,a48d8db3,9a80b2a0,ee063a43,26d4ba75,79b2727e,b999aacd,6e5fa050,de6dd7db,2114002c,8dcb17b,179e5843,fa205d69,4928eb70,a073f97f,f8348c84) -,S(93b07ce7,3e941c84,1e4089ff,2d8e6464,3ae59cf8,fe6e92c5,add89e10,f7084b3f,a6c0476,c5a7267e,54ec362d,3629a1ae,533efcfe,e18d3634,cb5a80e4,4018fa63) -,S(453c01f0,55c14679,5e3aeec8,26859b16,b0ec2707,61cbba3e,438c0566,5a91e7e9,f28eaec9,b9d3c8a2,2ef73843,6088425b,e14ac99,e52e73d9,8745bc49,a56766b2) -,S(3c6df1fd,ac078c28,a0a148fa,d15595b8,c1d09a4c,4a96794,6f8d6465,e80f12f1,4619a84d,4eaa134b,a06a6821,2e7ed292,d443db5c,150b54f,6dfcf267,82a5b58d) -,S(1b7f6968,39959785,30542989,59020dbf,f12054f9,2705efd6,dcc583,11b98630,279dc63e,e3e8fa8c,fbd731c9,b88ec6f0,67ee9e15,d0c14a37,372d9c20,c645c25) -,S(e1b7b953,9d49d0b9,9b90a642,74d2276c,6256f2f6,9cd03006,97ad842f,bffccc19,2b23b96f,51dc6569,8504628b,19e81534,f2acfedb,27f93316,fd0dd8d0,d5f9500f) -,S(404cf0c5,6fbf4233,4bd5f79b,ba97464f,9ce5525f,a56212bf,4bc817c8,af54f911,b5920609,88300588,5c61a6e0,75e3657a,23c04b5,79897c0f,2e22ca64,1f1ef662) -,S(43f1d986,da626bd8,efee817f,a09a3440,e7819aec,17ea971f,43fe2ec9,caae0c1,c5fa5ace,ce891aa,d2811f51,8175179f,3e93f438,2b3ab583,e51a200b,2a74f9ad) -,S(a18845c6,b3209951,16a183b8,1b762112,7bbcaae8,b67ee8fc,d23ecaf6,c5b9c1f,980ed5d9,d7e07e6b,2cfc5350,e818671b,8f54e7f1,5cebbb02,dfcc2951,bbef1f44) -,S(4d9c7eb,af99824,605cc17b,e03c929c,254c38ad,c026d5aa,2a304920,e7ac01ed,c64c5b35,bb0dce53,2273cf00,f3360f74,97065bb9,9fa9b1c9,70d41c19,53e781d3) -,S(e18d22f2,fbc3db09,bcd31783,3e8aa605,55953ef7,4c64814,edaeadc8,97e7c25d,cc258a81,71152072,24f7989d,fcaa8700,f15b8b2,85700b59,53ef2a22,efc7e07e) -,S(160575f9,f220904f,8d2ec9a6,c1417e8,35083aa7,9bc37d5a,3c8bdbe5,2a47879d,1e56b4a6,127e978d,41191c60,ad439fed,2c38704b,309d34ce,d655f93,5279a5e5) -,S(3b651bc7,57b1d626,4d6b7ebd,d3c5355b,4c3c9f6a,a1437e53,f9aa0372,5192d514,977a8774,95990312,ff1d8ec,5dc8a49e,5feb285a,8a1e2e4,19e56186,80231c3f) -,S(9085bdef,56facc02,76025015,498ab286,a9660e96,1fd6bb0c,d9579a8f,16ba532a,fd05d108,a557559c,5e7f791d,90e80e7b,68364c16,8f6b93b8,c55510f1,7ae9fe89) -,S(4224306d,f64a3862,fd33aab8,c1f0ace8,67cf1b25,76e1cc21,fef45448,e40569ec,8740b667,5279bc1d,ce887c2d,c59e42e4,63e72395,ff967249,8bd13d58,f60661bc) -,S(b7376697,4a512e31,a6f806b3,5bc55ee6,e0e2b2c0,ff5a0918,2f83ca35,dc22935c,d350c820,2676fade,ee4152a2,48fd5cbd,890b3e03,9d688462,51c2a082,85420103) -,S(73ba4f8e,d3b5d4d0,a7c505ab,1c1a7486,bb82e068,cba81574,557424da,4d0eb97a,93af3914,552dc360,549b4a2d,863d3f9,3a58ba9b,72541215,adca4bfe,26188271) -,S(285a014e,174724d9,8f0576c4,5694b052,ae93540,6bce1bef,524be03,6fd3d8ea,6fdad1d8,d2ce7757,e6ff5213,f91d4db7,9d406765,968ce8ca,b393e7c8,6a9af7dc) -,S(b0934dd7,27bfb54b,a2a5cea7,c6f8c0ab,84c2fd78,eca0d180,963869de,c28e768f,dcaf0d11,56029f31,4bebbb26,edb09913,484c94f7,d14d71bf,2bc709d8,f0b982c6) -,S(3b627add,8b69a9dc,b751c8bc,cef15d0a,ffcb49cf,357bb65e,c45c8c0f,5b681561,bda1980,9e380b7,2da13364,9d27cff7,693cd2bb,a77215e1,536296fc,dc46d19d) -,S(7e48fdec,1f2289df,a052e3f9,a4766daa,e4593876,5c8aa7c9,a62a369,52cb5ac2,e87af87a,ac116885,66e1e10c,5bedb49d,68449b8e,612939ac,61e384b9,bd8cb5f2) -,S(4031f08a,5de33bba,b6a2c267,feec2e40,d094d890,caa1008b,181ce43e,263ffd9d,cfdc4fd9,9737a5f0,9a789beb,91dfef45,a8f23be3,11b946b5,8a79b7f0,51b0be07) -,S(ba652b7c,61dddbb5,bf6e656f,4d441cc0,ec00a22c,7b900b1d,d5407ebf,931ed764,87fcb392,d1228156,a330b5d8,d3c67e00,1d207095,9a590088,a3b44d07,29556) -,S(fb936572,d1017653,ac7dd95d,2d8c30f3,62c967b9,ba0d3b1b,ffdc1ed0,6590e72d,adfa37af,db6b6a31,a779965,9958be2e,94038246,6b4a4587,b0879882,4836d8ed) -,S(294473cb,5e7c0852,f7c6fdb7,8861129d,b97ff328,19685148,99198870,b03bae7b,bd905536,f991867a,78a09f95,1bd5b4a0,78463e5a,6c767617,246eec38,7d90c86a) -,S(2fc0f44f,73a633fd,91737ced,1683b74c,7687dc8c,6d3a4c09,44a6c873,c5bc574e,29917cee,ffa063f9,4e949991,2ae373eb,ac572f50,9a451184,15e07354,1d22ad1f) -,S(811fb251,882c5a7e,f59d34f2,c8ed8a31,8da210dc,83bb8c40,b9ac0251,116d569e,74df6547,2cb55afa,4ee04ad3,f940de6a,d480e407,5c3cc00,ad291918,d8a0c55d) -,S(45a9e17c,c1d6cf09,1f451894,ad4e7e53,c47996c5,82fdc57b,a9e7e614,b7fc5d07,5169dc4f,2661f5,fb2d1920,89832b7,4e19196d,c37fdbbb,16d1caad,7b069be1) -,S(d577f7fc,45cda7ad,4743d96a,ab5c7bd4,abd06538,b78c0102,645d09ae,b5588e67,55172b71,7ea257df,ced1db61,88c78cea,765e2c2c,30bfd25e,52107128,303be07a) -,S(a6429a95,8098aa6e,39b71e08,d4b0cefe,4fb22d8b,777a59c0,650e11b1,9b06e44f,af494e62,5587055d,cac440f5,786240ab,36ab1825,f2c3a7dc,f6aa64b1,947dd2ed) -,S(f77c304,b89314b4,258b1c80,cf478ee8,50bca37a,63e20679,7396967,a39a743d,c487a176,29d914be,60845213,60f40f19,1c32f414,558e2c72,7e78637f,8dc1c7ee) -,S(41c6f2f6,15981247,71ff0a82,e1ededea,cd76ea2f,fb2f9f5d,ef766165,96d1c988,58a0f544,146c1a07,5ff9ed4f,f9b687c6,3642770e,45dbf1d3,407b52a9,5accb68) -,S(c8724ec8,c13d37af,9eaaacb,35765e3f,7ac2d2d7,1fdb5916,cdf66ed3,2eb968d0,70ecf721,42103e6d,e7d4bbf2,42bd9a6e,6ade66ed,a7862989,5ecd255e,44d81221) -,S(e2888c46,dd58e36,be2204a2,b75fab66,3b139e4a,e070c650,653ba9f3,ff1fbbf2,715910da,e1393b8a,b7d88879,720bd601,bc158498,9522108c,3312b353,2342509e) -,S(f1f4c384,d72d80b8,6b5999c9,aaa66f99,f56cf736,11ea9ec1,c14ac36f,66d834dd,b5543bc2,480142c8,ebb8527a,3c9aa786,2198388a,696b3c44,835e7375,24cc7e3f) -,S(487477f5,832fb7db,768d412,6edd7f5a,17aec3a6,3419de73,f61812b4,31940a5b,90322dde,4203fa98,bc44e3dc,32a6d56a,284f556,36db7c54,c5f78d5e,1b2608a7) -,S(a726963a,583167e2,4b8f957e,b3ee9f5,c55df02,9fe1229b,ff8af037,14ca75af,8fd7a984,d68929c0,81154d15,6b6541ff,4a636925,53a5a32d,99f6516d,c08f7449) -,S(d4c20db4,cf80eb1c,9d93a231,e699a68c,baa763c2,e2013033,8762ac5b,8b99e97c,ba1c77ba,2555a50c,84aa2071,39190a35,f5abc50e,589287a,426c6f9f,6ceca01f) -,S(7cf9c53,89ae702b,bedb5a55,ad8d0f36,5159ba1d,ac56fafa,fa59efe2,3a748168,ece3b324,338c7bbc,a2cec347,c31348ef,489bee0a,6ea4296f,6ec38502,b72336b8) -,S(920108e3,c1ebd4af,3979f9c3,326806f,eec92833,b4dbaf49,6992541b,44b73e55,3e22b133,d8adc483,4f03f348,eba48e65,6cf8f478,524f5395,ba92e200,95f466fc) -,S(1566af8a,98c48762,9b361337,2ad32a53,fc760538,49566a8a,4feb69c4,26479e90,2848c566,4bd72be4,c797db98,62fe1c7b,da5d3ba,eb3f7926,daba8516,da997796) -,S(a4db5e71,2eb8ceb,c7d7a704,12b0a8b1,d2f6d9be,271ef044,c0f76abc,af61723c,663e16e0,75a73ddd,f604bc0a,27a9407b,272f5f2a,f2b9f6a5,6958c8ca,c42e8ca4) -,S(d0c9cf53,8bbdb8f9,625d110,6c79cf1b,33d90e77,60778c13,8493bca7,8d53e5fb,b6ecce0e,8b9fd407,cc0a2125,b8bd30c,9975ad88,7dc1bd9,68379063,8a1d9a60) -,S(765fba92,480f57bd,70596d67,bcf3a389,4a58d514,54e3a04c,e657ce78,ffd8391f,5cb1dbba,1035350e,5a3b552e,3f41ab4c,50879bbd,5f3ae3db,af6ec902,1e18302f) -,S(9f9da9e8,e846702b,4aaa7b9b,68b652f8,9bd3f88e,5af4a503,2c51ee6f,8bfb4a5e,5dbd499d,7ecf17b0,eb17320c,a0688aca,1d8da08d,d2c0684d,edfa2d7f,5696a0f6) -,S(af86c83b,db95894b,72fb1a16,61aef5f0,ad949c9c,b465a5bf,b1192022,13fdd3f4,ec06827d,55410119,603d2b25,cc41c26f,4a7bb9,b1b88e55,123f3c12,d799e117) -,S(fbb48993,2fccbc8d,772b3fc,c80be33b,64c8e3b2,2ccbb09c,d94fa350,fd587e77,f9cdd24,279333da,b3451abd,634075a6,58598ad4,257bbe04,81111b6c,d8c0b858) -,S(40ecb1a3,ad97c2af,62b15eca,e2adc9c0,621f36f8,90a9269b,ae6edc1e,7ed60684,ff9ec194,fa3a617d,920e3e2b,32301fb9,9a41f4b3,ed9845f2,88daa005,3558b32e) -,S(31f892f1,c762b42,fcbd9014,bfe0238f,39873c30,c7d3b691,9736009c,18878f52,d9bd5005,f31f7345,53131066,ef6b92c1,5cd610b8,f7d4fff7,be536734,95718c95) -,S(ba122529,e9f6051e,2d94d150,c5d7739f,921f8193,8cab68f3,1c696fc8,24886c5c,c33c071f,7e9bd539,1b0577d3,37ac9c20,7c02859c,c396bc20,d9c7249a,856b1ed1) -,S(35316412,9a26d311,c993ecbc,5b9a0263,ef45d993,d58158c5,30c215f,2924cf03,86a620d9,521623bb,9ce3e2d9,c5b6385b,f92ef06f,91834e3f,6a9c6d35,7a3a9742) -,S(3024770b,e4134aa6,35ece92c,a4ec7f9c,4a4aa7ac,7851b3eb,f9718a21,52c8e462,1fcfafbd,72147afe,16dc1579,ce7384e4,ab3f8faa,f818d225,bbceb050,ffc8c8ee) -,S(f5ba313d,a40ee86c,5b6dbf16,9941d8e2,533c1ba6,4dd0871a,672d01c8,6bda6564,10a910d,b9697907,c96e95ec,15557649,8f965282,437f58c7,2944bbad,b800647d) -,S(685e17e2,972ccd05,34f7f426,b18c9518,e485a23e,132c18eb,b33b59c5,7264e2f1,96545b38,be84aac1,a77a3f47,51156daf,470fd42d,dea0fa0c,b930144e,b9f291c6) -,S(e01285fd,facc9822,a59e1bca,7e91c07d,fdd481dc,61d268e0,504f65d1,9bf119eb,ae82153a,2479daba,ef83615b,a7202b99,40bf5b5e,41c65063,f77d6e5,9dc39909) -,S(c61e4586,327710ec,784d6720,93201e4,93798a93,7635f220,b5421cb0,55839601,e461fbf5,aa5b64e7,a1e3e016,3ba555ca,5d42fcf1,7433c26d,cdeb8cb2,746c04ea) -,S(1c427acb,4e5890b6,e24d8ca2,513b61d9,3106fc34,90029af3,be87d65f,1fd192d4,1d96e025,1518528b,9bb04fa6,ec3430a1,84935ad5,ee8ae3e9,c9cec0c4,36cf29d0) -,S(5e577bfd,6d51897b,4b6ddb3b,a7d470b8,5a932619,b5982f54,431df6f1,f12fd8e7,c1a17292,9734c19d,3a836e90,8a5a7fd0,123cb044,c7ad1ff9,203d4d79,211c6eb4) -,S(cc78b333,1f968a40,bafaefc8,dfbcadf2,adc6ae76,6d3ea8a6,8173b40a,28237b30,5b7691b2,a5bc068,ff1ef04b,41238cb4,dfc2ce7c,9436f8aa,14eb0a40,45857d42) -,S(3855c437,487b44f2,9e5dc288,faf3ecea,c445372a,95adc16a,b1830a4,ec919fb6,df2e1e9a,48cbfa28,54fbcd5b,308bdbd5,ed1949f5,e1a39519,11c287c8,289359d2) -,S(c05233b4,a83356f,c5ffcf6b,97db3d6c,dc62cb21,b7de7c92,8f158466,b9d16b19,b1bda39,ce78847,3fa0eac6,51e8de54,956616f5,16233275,25ee3bf7,9e54f500) -,S(6c064d3c,f34226a7,d9a00024,5901f355,b736c1e,6561810b,455e7dec,99dfffb,160d9442,d25ec1a1,f80f8fd2,a1c5c42e,aa544477,28d242e9,925824cd,609eb9a7) -,S(9658eb89,70bb1aa5,1b61a93a,de6a7d,b3e20772,4789d009,bf37ba9d,8b714cf2,cd4ba4af,f7da8f8b,7821a903,f40d89e0,96be8949,997d5ff7,a58301ea,92c51cc2) -,S(6e023910,a5546f70,91f2b0c4,c3f996f7,5cf1f969,a71c31b8,7a3e7ea6,4bb4f0c8,f6ed65d7,90ec734d,d9ed8cfc,7d8921b8,7faa9b36,651c3589,99b9addb,34c459c5) -,S(3a35ac98,e9700499,f903528e,330537f,9262901b,d60c7a14,1e68f899,54c7ff6e,913d9516,da631c30,5394ac0c,9eda3824,1f247ff8,a7644eb6,c4d38da1,972069ed) -,S(d089fa51,15dfaa45,a8b6def3,b1948be,2317c66f,249763db,7350e57,76af212,4e6ae973,f326fac4,77a5120c,f3ffa113,a18e5dac,4a190f6a,b12fdc83,18a6da9c) -,S(e733c52f,2aa62ab4,748ea0f2,33d9531c,5b9cd9d5,f790b6ab,45bb2c2,d8cf2ef,701155c9,3c677293,acb23ab2,8d7ff753,36ac4885,70c52d89,fb80ddf1,d582a291) -,S(4b6f7b7d,c006684f,e64aa6f2,42babf86,1eb4770b,b8195b9b,e8caf763,e7f14c7a,6c58b780,ac757b33,c1805d8,a53a04c9,7bfaea05,d8f21d5a,2b0645eb,2194e00d) -,S(1b520402,cd1fac0a,c4d7aeb,8c552e73,44ff51c2,3b4778b4,81126e5f,e267f79d,8ee0d00,56649304,a0c4ee94,39add4d8,30b252f1,93d93c1,9e8ec375,37db1a39) -,S(8936e6d5,d7f1ed85,fc2da4c6,38a885e6,3400cc3f,43d864f5,bf9af2be,b97139b1,29812a20,b4b932a3,770cdc8a,6fd32625,8879f217,a5bd7c47,78d2b041,829b402b) -,S(6808ae7f,4813554d,aa36c043,a55d9171,aebd396f,5ba1a1ee,c4f11045,c96b518f,6afcae6e,88728ddc,578e85fd,5f41575c,f581b983,7c749c22,31b993a5,9c425810) -,S(586c6694,44c73f66,1211bba7,601d8009,93e23293,55a9b10f,2367924a,35a2cd1c,74b0901f,f6eba3cb,408f5507,d37cb7c7,873537dd,ef0671c8,862012ac,fe5416c7) -,S(789c825d,deadf1e0,4c788453,e918541e,b183aa5,99ccc66b,7897be8,1ff89e11,8106aa6f,641bb13c,6be7480b,89f98a9b,e40cc357,ffe9903c,b8f78938,e46cb5ab) -,S(d7ab80bb,fd26faa6,620d0ddf,97f64bca,e520426e,e1d8e076,acd7cfbe,a9419797,26af9f72,a6d1b103,aef4a85f,5139d14e,6e50a58b,9f32eefb,c7184537,90c5a823) -,S(18f712d4,4daf1ab8,4612b311,b1ebc418,bddf0f33,ca02b315,4c256d2f,36f67f7f,c40b1950,f92fd4ce,edb3c3f4,34ff7bf8,6b06d8d3,215d3ee9,f2d9bda6,77d25bc) -,S(8873276d,9f6d188f,78e2a7cb,f998bcc6,fc399d32,21de85b3,eb9e6ea6,c7e5a06e,297e8137,8ee9b9e8,ee820a3a,7e566178,dac97743,c04b6b4e,54a7081,e7c9e1a6) -,S(101b8101,5bd217eb,c08f57cd,fdf431cc,30fadd66,4df79157,1452ca66,c688e0ad,fa6c1b2f,ad203831,185816d4,a8f8dc9,4c7542b4,6c94dab3,39b73718,5d179e6a) -,S(77b3c157,76c31460,11e520a8,cb2071fb,abe3b3ca,2984bb6c,d81d4c53,7f42dd57,8d0bceb1,dab601b7,1c084c9b,443ef5ac,40cce5d,14f0c244,92589905,fc4a645a) -,S(151f2d52,56ac60b6,ff7aca33,8ba66f12,fbe2c189,33c805d3,ecf6a6a0,fddaec7a,d2aacd77,10cd4bf9,917038d6,49e94235,c4833c88,9cd57ea6,74ece9f0,764f62d6) -,S(dd75cf27,f41e417b,46338dbe,24b46df8,9508811c,111bd1a2,29a3809,171d32c7,e328b855,a3389b80,4ab03c33,cc91d86c,ee22170c,d8fb53dd,46c32224,19b67be5) -,S(faa1feb,bdd1d9c4,9de366ab,3f661b1e,6a3f6b76,335b428a,494d7eee,791d7a83,df361d4f,8fce02ab,8c248ee5,61e46555,948bb29d,81a569c4,13b5713d,b825d572) -,S(3cc10dbe,5bc2bb31,fddee65b,66789594,a4cadadf,8c6a7545,671dafed,4d8f8be5,802d45ef,8c66ad6f,e692a3a,9d42c974,7101120a,ea42510d,bc08e657,7039c2df) -,S(9544e725,325dec1c,914dee7f,752802e1,856cc485,35e3a1e,af576bec,a7b93ba2,cec7dba6,81513c04,ebf39b03,717338cc,aaf137dd,e5087686,aad83115,deeeeb49) -,S(94a0fbdc,d5d06236,7b17ff8b,4dcdf6c1,54eec66e,2779deac,38be37c,9f83a964,f25f34fd,5ef06c81,b7223e16,9a42e2e3,fea74213,5a2a30e5,76f29ef4,cfefe82a) -,S(989e29b2,c3fc7e2f,695fbd4b,f217ba43,14f67c3b,9f77633,100e84b3,c6b579c7,608a6d28,cd00297,2b4f3e9,917daaf9,ed003a43,1c22771,17250efd,b621c888) -,S(c38c5fc4,4295a59d,3b0e979b,5934ac2,49b4bd5c,e94097f1,c81064bf,73494a5,16240bf6,d354b36a,648e471a,e0ebc167,1d1dbc71,7cbeeecb,7600462d,61d1e2fb) -,S(de9cf667,35c4046c,58b41d8c,5c658efa,7dc656b,7ad877e1,546c138f,fa7a63b,2fc2824f,ba9162e3,e2372927,5448010b,ecc19de7,d9b94cb7,57586de3,506639ac) -,S(24cfd37,e56708b5,79d84b3,88c33c9f,f1dd9e08,4675a3c4,c8c440c0,f6c06522,1cbcc8ea,9820157,b4b4d289,55ac8672,1aee676a,cdb7df00,7383ac79,c42af897) -,S(9d6e3108,6ad8b9b6,2f4414a9,5e091e9d,2b275d8f,62641ed7,26421639,e87cc121,b924700a,6792a67d,4dab59ad,5a743cf0,43c46ab4,de751bca,757979b6,ead3abe0) -,S(52a89ae,28b28395,739c21e5,38ed38df,74aea22d,d2765d38,673be080,8609354d,c183ed57,9b65830b,d37cccd2,76b2f61,469b06d5,987b5708,89c5b1e,d8334e51) -,S(2ffd3272,491d1807,243f5d31,d727caf5,cda3bf8c,2c172550,46bd3420,da27571d,812e8fbd,6f38b334,a31e48be,6deaef58,599934b5,d3419d52,131cc9a6,535b6ad5) -,S(5d60c609,4269a43a,35e51b66,db193b16,65df689c,270662f2,eba959c5,9c973fca,f591324f,d1afd619,2b31bb7e,3f40cd40,6d3b9285,969c448a,3aff1f48,850efadc) -,S(23e0c40a,bfe53353,f4426340,e1c1b560,4c86daf9,85784d0a,e6da6b4b,3d12ff75,e90844b5,fc86092a,91baf68,280ca144,f19d5a79,9bacf827,f9921511,28191d9d) -,S(945818ab,5d4a1c12,ca6f20d7,7f37da80,50e67d79,30bd2bb1,155885ce,7c6094f6,b5f2c1d0,e2f9ae6d,aa669c96,9ededb60,32ca8163,fafcbb6f,9a11cd56,4a695e03) -,S(d1f4db7d,2586bf6a,187a469c,a0cd7bcd,5043be5d,6206d24b,c41ecd8f,d8724c8c,64054f82,77c4774b,bd480ce9,b2929c66,b1525eab,1c6f365,a1ca5ace,12206839) -,S(4f5c4d4f,24586e9c,1a85f2d5,b42a3d11,158b4f2a,5cf75e18,60f7f4ec,ec14a18d,57576e71,6d547960,6953be2b,e7ffbec2,1e48bb9e,970fb350,986b4a31,b0efdbe5) -,S(c13b605b,dcb31443,d8a3cf5c,5e4f903d,3f8edfc5,1e9a118,c3840cb9,4998150a,8dce2eaf,99f1fbf5,2e62a8ea,948b01c0,6c368e49,f41922b5,2f603cb2,16cb8435) -,S(1937b32a,b66f254e,4964a5b5,a1ceeb5b,a3df2466,e2669753,39174cd0,2429cbb6,9712b0a0,6f1b075c,bbceabb0,53fffb1b,181e079,813e022b,b5701738,ef2e385) -,S(e4a5333f,2f1772f3,84ef386,c3be1f58,d757bbdb,7ad2c4d7,47e61b07,419ba2e4,e84f7da7,2ec2e4b9,389b717,8bc15642,132571cc,9bc14c7c,5af14a7a,cb6b6f56) -,S(2f8a38b0,a3f42a8c,5080a0cf,5cc1085d,d57a8341,ae154dcf,fc7fdb4b,5606cca6,8764c6a5,2c301db6,56408d9c,4eed6294,2fa2a72e,1b1264f1,134f38c6,8e4681c1) -,S(3d2bdc2,c51c2d77,b6c585b6,3ceab5fe,acd14599,b841870b,8735712a,81a55ff7,33f749ad,bbe263df,a99a808f,f0476e44,92246036,a3e8b5e9,496b8dcd,b6d3e9e0) -,S(fc87f808,d6764ce3,376b9acf,62bfa3e2,1ecec215,22dbdb3e,6e5f3cc1,efab7d3a,ce75eb03,c1f4f937,70815dd8,750a4ac1,c0343024,ce1bc581,717cb971,2835176a) -,S(7f81b85c,62dee11e,be8885dc,cc98485,32354952,1c7e6cb4,374270bf,5b1e68d5,b7adef7d,6a84db61,c15ba062,d96cf739,1750aa4a,ed5c97f3,ad70d2a7,6a9c4558) -,S(d618d43f,7afd3ae5,e8dd8f47,f62ef91e,33cc8f89,3c21688c,8268b903,e1fd5557,6180817b,c8ab9b0,82b21267,9900c7e4,42ce9e8d,fc8c3fb4,fc5bcaa6,e0cd34b8) -,S(ba5a4c4f,f2379b06,daff540f,c8383b9b,694430bc,df76c931,ccf94cb,896e4940,3a221d1a,b138e6f,4ed309b2,4f2e9333,25299de5,534a528d,b91075a8,fd07b1f2) -,S(c69189b6,bee3746,88359141,5b35bac3,80136395,c83098ab,cec29fa3,18cfdf56,a185dbc2,b862da3a,cdc232fa,7e3407b1,9795e61e,29b7a79c,5828bd49,d739268c) -,S(51f67d44,32fb401,ab863423,b99d403a,70dffd86,87e5ad71,bcd3732c,1cefae12,88b17485,a2c404a3,2bcae68a,3cbf2166,403e23f,8a64df5c,a8eb2d94,61e10e59) -,S(cdacfe09,e5585f8d,4346fb69,a94b8b65,6001e117,ed3cca36,fa8bee6d,eb7c4bd5,ddf1bc5a,993131d0,15812176,206699d7,af5fc403,59455ece,fdb84492,6e028542) -,S(8129e771,e1fce476,9c701d70,cce90888,481eaaa1,d1661be3,19f33c93,8bf0e769,3eb5713d,a864bc56,39ed8b6f,974966af,8a4db189,b5446d70,d40a816,f045c6e2) -,S(b97062ef,6d415bc0,f302fc0f,8aa730d4,f39c14aa,f82889ad,a68132bf,5abce3ab,8ad70688,cd76c93c,fd8dfdd3,8522247c,6644c9e5,51116829,490f313,d53db3a6) -,S(19c3c98b,4e811b5f,ea5d6af8,c4e86be6,50de67ec,5154bca4,22a6a14f,4f0bd913,bc523f96,48bdc993,30e1b5c7,385097cb,c18b9d5e,924767bd,d5d746fa,a190a109) -,S(b9ef34c7,3616ee74,b1ebe43f,889118e2,ad7697b,efe63559,67a9b3c2,b5b42b9c,12f1cddd,d55b1ac1,b89be271,5e623952,e8dc05aa,3570e254,3b70ea68,5b661bea) -,S(7718e34f,58e2cdb5,80f9c39a,96d84dc7,59dd2a3e,bdebaca8,6e8edb97,f503c34a,a6d105fb,dc0841b8,12dcd8f9,6c4bd17d,cf5e3728,8e0e3093,13567b10,3e96df7) -,S(dab3884b,8e6de737,63bba89b,8d35a369,e259c1b1,8afb6ed6,21fcc871,c77e8dba,f44b6f29,c59a2d42,2babd4b5,edb4a009,c9316e09,2aef953e,e503a278,14a11577) -,S(cb3d0e10,1139782d,e5e6a897,8b5be6df,a6736751,e847ca18,76aedab1,e67f4366,27fe888d,d227943e,67969b33,be48f1d9,572aff67,69c150cf,189f9709,bd57d3ea) -,S(eb1b1ff8,55619d41,8d193db,bf62b4b7,656ea564,6ea2e79f,cca7fb3b,e8c3c6a0,c27fa0c7,5b73d5c1,d7113741,40384565,d36ae93a,49b327a5,cedd03c9,62282ea4) -,S(5d5079e6,bc40f11,f75a1117,3ab6bdc,bee8f9f3,d2e57aeb,58709786,1c39c5dd,14ae112b,a40db9d5,dd65829b,4be7bdf9,4d8435de,1872bab,80581221,446e46d0) -,S(1060ef7,6beb6af0,6d28acd2,6b214bb1,b708098d,e0300502,384fcc0a,a1a7b38e,ce40f39f,f6c6c642,9585464d,aa2183d7,34252c05,5207e2e2,75d0ec48,c3bdf9a3) -,S(9651c463,c001f731,8947c271,ac274529,e7bcc894,70d63e1a,fd723873,aa170695,4e362e7f,e8ff06da,73d6d17f,e8b63c99,3b16ba7a,5a9b154d,21837fb0,e654eaf7) -,S(5c422b76,592821b4,2f6822cd,cb428b19,895cda4c,d224400e,e0928f27,1f363dcc,2fdb4f4f,9e4c77ca,3448258f,f6c07f5,4cb6b4d8,15281484,44e5fcf6,492b9400) -,S(db147d2b,5d98250d,73a3ce51,9452cc4a,ab3868a6,cd4f43d2,b7224d93,a9faba2c,73254380,ad3c6acd,fa343227,a7299684,9fdebffe,64c4925,8a391a7a,50ed0de) -,S(9a6763a0,f97abfd1,65223767,8881e899,e1beca26,ed84d384,a41d16cb,e5454b4c,bb51407d,b6aa5817,32f1a3d5,51082908,e7952f75,92c8bcb2,737a01d3,3890306a) -,S(36fe7933,e9108af4,f4e5c889,ef94f584,7b45a9e,8c520000,7db6a00,e5daea8,d024a5ba,ecdd5a21,c8c3a0f4,a71e15c3,1943c7bb,66b459e2,7fc85bb4,25227ee5) -,S(40dae663,f04f7e68,ce782fb,87529681,44c749ea,5b7386af,c445568a,3bc784e7,49a463fd,ac6bcdd0,2458c85,423cf252,cea2ab47,44b16bb9,47811176,5755050b) -,S(ba1616d,c8fff3b0,8e8c6d10,b15afd9d,da55faba,79fa8a75,42c5c9cb,adc5b8d1,ef096c42,a6233c66,1965a3ac,eca095b2,7710455e,5f0e1019,7641ab25,b0a786ff) -,S(30486f67,23a54952,4d68c948,dbc71273,d69b4a05,5fb9e7d,a702d027,619c4a66,38ca4d4d,279ec9c0,85ea6369,5470a4b9,fd6acc6d,9a049ab6,5743ecba,c2444c76) -,S(1b83ee94,95ead1d5,80f67174,dec2a026,d6accd93,9a89d970,90f25bc8,d9e6932a,196d448,fb5e4851,e1b73d6d,a2e7d0eb,3d263034,9c2b3e0e,34584bc1,d6e20196) -,S(4ea9dc2e,edfa5a11,2fa76671,5c1579d9,328b6132,14ee64f,2e30f10c,b7517396,7414efc9,6ef83e29,5883f0b1,4019b41c,d4a192d9,d06cac9c,21e8f0f5,b06e50c2) -,S(4166c19d,bee9ad08,83b217aa,3b657436,87677792,d5cb9b31,1a097fcd,2eb033da,62c5065c,5fae6aa6,932b4d29,ab375ac6,b80e113f,d38d81f8,abc236eb,7eed541c) -,S(b17567eb,b112f54a,69c511a8,7d3d2f96,bbbc6686,af8e3f31,a2bbe0a,85a74899,f6676341,3788be54,ae3fc693,4b8936df,a6936721,c671cbb1,bdbfd72d,4c9f52c2) -,S(cd2b6515,2ab97f34,89d81fd,f3513131,a6df0685,5022102,12c2b8a9,be8095a5,cfe7952f,9ca41935,15ee40c7,2d44d023,22afff84,b8700bb4,5f492e31,e78f6a53) -,S(375603c4,9f33140a,3241a72,907ac0c7,2086c979,3aeaf74a,44732097,3618229f,7bb740f6,6322a773,e11ddb46,300975db,de08ba13,84480699,6681637b,eb85e837) -,S(102067d4,390a3dd9,6d83c176,f341dde9,7e10955d,2e001632,978f202e,efbb7432,7cf6cfd5,4d28ccc3,a7019f11,b6ba9df6,1d8b7eef,7e70722d,afa81a2f,839ba83e) -,S(47617e73,e3fbc53b,a703042c,f8b48fad,374ef42f,e8c2dd54,4fb7625c,de63081d,1fa4f423,c92a95b,b2c40f07,f43caaff,50cbae67,87c3e2a0,e4782f39,c1d439e8) -,S(2c431baf,57f75062,9f57aac0,8e28a060,46b814bd,318d74ca,82e1174e,f880f84,ddb9e7bc,68574b32,c1004108,9853f41e,62755a52,ac58badb,b8ee58c6,f209de50) -,S(91963643,8143b6e4,19b86b1f,79b708ab,3f4df44b,d774b41,338570dd,8343d599,9034ee17,7171a0d2,9fb91d68,26b87bbc,21be334,90f44049,69622a8b,76312f0d) -,S(bf28c201,af656c7b,838d42db,95683b06,2871859,2b016ddd,a4a4f7f7,c4b7754e,bbd4f04,dda510d2,a8a66c2f,46ab0681,ce6ffb5a,ac320e20,c50b6df3,a345d109) -,S(fcac7386,21825f4,4e1d531b,f598e40b,1aa4262c,a5aeb5a1,babb4f35,9518b137,3b196b7a,957bbea1,f3f2d1e4,1ba37eef,7dcca7fe,87e7c593,6ffff685,52e67b64) -,S(9cfea1df,caaee192,141f0278,e467f809,8ad89cc9,b47ed982,3029c1dd,726e9331,72d81e4e,7f30ee05,8fd0b646,95086e30,96a071c1,5b75df47,b10146b,18db211d) -,S(548d3f42,123553c7,965c7f21,f2802c30,455c5151,99b98e20,1e966f34,6a1334da,612ea25,cebb03d2,89538eeb,15b94686,8c0afb1,311278a,42694a0e,956418ae) -,S(e5be619a,ccf84c26,9b5c545,e8c4990e,ebd46756,c628de22,a6c8bdd6,74295bc0,640864a5,7d841af7,ad83aa74,fa858b91,89e246cf,9b361837,a742e2a0,71b08bf3) -,S(b560933e,3400ed4a,eea8f733,d2368c8f,a260460d,f734e209,e194e9ae,a1ac668f,5438f93d,31337853,9feab182,6cf17bbc,ac0975f4,de29a886,1b1c0c02,2c5f9da3) -,S(21dd9a97,baca3e79,77ecf7d,d74433fd,dedf2d96,8c3153c0,2c652aa2,1ccf60b1,de6e60e0,e048b0b7,b699bbd7,cda0c0c9,b851c4cd,34f4b8d9,17c07cd0,2684797e) -,S(5cfa560c,6d39439b,4c9b0a52,f9bda301,2f147874,48c9ff37,bcaf2900,fd934bbd,c7927a63,cc1959b,f3556998,ce936f29,29d5a5d3,3f0dda32,35affab9,a5b11b06) -,S(4a3b95bb,5adcd41,5036204b,394fcc95,6377afe7,b4902f49,461c4b6,866d4fc6,d59e3ee2,f1bd1e4c,c089179a,4db9387d,8d6be47b,df708023,2a0d00af,a8e84f2f) -,S(cc49a313,b4c69c9,13c06b7b,add06f17,404edb0a,dcdb3d4a,81c4b765,35f4671f,4bd722ec,c35e525e,af36c194,3d375592,ba483715,2c7a91b2,4dd57a89,687bc278) -,S(9d75085a,7426a69d,9ccf4f90,d8b4ee0,e07fdac0,18df3d37,40b264cc,d4146d98,5991253,de04b32d,4772f44,de49467d,ce174ae9,3f941ae6,a4f6e3c2,2cc4b0a9) -,S(dfd064df,737bdadd,2eb12cf5,d9f1e192,caa87c0e,fad20d18,b95b0d06,83210fb8,519f883d,a5bf8d33,50b1d2b,89012fd5,9f317299,3eae1226,13d81b92,9103805a) -,S(2b50a35c,d2356c35,d609013e,a66318bc,1cf20582,685c12e3,bf618102,807eaf9a,7d0b51d,303aeefe,b81f5a77,d9b5829e,fdf4241e,435380f6,ce74abab,1dc76335) -,S(e26e8f4b,2cf175e7,c76e2a59,459cd45e,f3202f3,3027f0c3,70481fa8,685abbc7,4c82e7ba,aa0d5161,53076702,997c34dd,716e5fe2,460eac0f,194f72fc,3ac2013a) -,S(5903db7d,54f4d857,6a584057,ce78dc07,1fd90e51,f825c959,b46d3483,5d0f87fb,c55e2fd3,e9ce119e,47c00332,9d18d6f7,febf9440,a18de0f3,81608011,1e9e99c8) -,S(4bbb0ecd,342a82d,c8b881e9,635241b6,1040e6ee,28b98204,fde953d4,4d25e9c1,12eb090,f3445b7,52abee8d,604e8784,82e97e9,b44d2335,8211a8c8,2cb0ef04) -,S(4a2455a,ae87bf97,c6e6eb38,fd3279e2,7029967d,41b9575b,647550f9,4bc4e8d2,5a340ac4,ffe3bee6,2d52bea1,e276178f,9af3422,f9c61c47,4a595550,73936074) -,S(f086d68d,c8ca19aa,54c329c4,c07b530f,94470abd,dce244ad,1decaf87,53477623,911c49d3,84a16af1,65be4161,cc4869ab,4d9e8ba2,808afd80,20d30971,b4bdbd08) -,S(4f1b177e,83b76c4e,24a53f91,2095f1b5,d4b7cdf7,29788cb4,c989f921,b7ba856c,a5568c4e,b060909a,fc3dc2ff,5bb9534b,99debb69,dc0b811,e1044705,7d80eaf2) -,S(eba87899,29a7e45a,23d2fcbc,884778d,c4fb5ae7,fa67954c,76534303,97db5823,e6f8c729,b3570917,9fc46b4,7f03af9e,801b26a6,1724aafe,e730217a,2dcbf68f) -,S(df117b13,34c9a5a7,92d58084,4444559f,130ee539,89cc6e7d,87723b63,a82282c2,dd87ca57,8eea3c51,2aec5492,ea55111c,1a2fc55d,4e2335a8,c9be5641,516f7120) -,S(d775543b,3e68ab88,36eaa1b,df5f6a06,1f5768e4,baa01a68,621321c6,e6ee82c5,70221b05,47c97398,3cee7a26,c4197f9c,27a2bf46,10506e18,493a9ee,1881436e) -,S(a7f10dd5,5a231ae5,abc5c611,68cd58ca,5e006f7f,fdf064c7,1482febf,4578515d,492a33a7,b66b9694,e225eb38,d1d99399,b2c24af2,d69c31e,b4797a9e,703c13b0) -,S(c79545ef,3119abd9,11336c86,c6b74846,801c6b3,812da05b,5d36e9c,620120ec,24c8fcdb,95b6eae4,51473f8e,f7dea06c,738a33c4,f1214382,bd7204dd,d3c28718) -,S(98bab5e,744f888f,5f843ba2,9e2104a3,afa14dd6,6a2206ec,8e783e0c,52c2cb11,83b5699f,e5e87ed8,c51d929b,8146bcd6,a7abaed4,636afcbe,b2c30d2,bcb94df6) -,S(6dce2828,7b6fa44a,c8213053,d39dfff5,60d84a84,ac264110,547752ef,dcac586e,1e1eb62a,b9d60cc4,5ab2fa8d,d065d1a4,c79be399,53578a5c,adcfc629,e237ed66) -,S(e386a59,287a73c9,306b091b,5b24ad8f,db06a9dd,8f6f0c1,b7fb0ace,623dfa83,4a7e73da,663b64a5,e624ce89,9e16fcd5,c0d3b221,42284ed6,852960a9,d05b34e6) -,S(8fdff782,e62fbe31,98c283fc,9b9543ac,cea0a318,2626d180,4beaa27,ea4fe4d5,fef8f471,9fe0d95b,673ed650,8107e887,a4f5301f,4317c708,c5222d2a,ac086675) -,S(4c9093ae,7842b148,1bbb8b8,4ea564e9,36ed1cc4,35c89089,a10e0442,292eaa37,2d683334,93d245fa,e5ac0903,fe9356f7,8642362b,f85a7426,ea2950a0,a65298dd) -,S(cc0634c5,5c5c52a9,d92b80f9,be072a35,56318c6,fd76cf2f,e866d5ba,33103a1b,750b7d41,b13cb69e,6d236eb0,87fc8600,4004aa77,1b699e88,7e8f0b08,d07f0b32) -,S(9749a673,41fa7ac5,8bd33f5f,9cca4ad9,1d53c7ec,cff76656,9a56f71e,3b918255,b685f1c1,9dc7d6,7692a2aa,fe37d9da,5e68fd69,cfa58d87,ec6ced8,68916068) -,S(b04abcef,b57862f2,5a57fdc,b7da0b1b,a25bd253,72bd91bc,9e0377b4,697d8e75,50479a64,66ad4be3,489b5869,d8b9bbe,62dcb8af,da8e7d42,78b5014a,19e168f6) -,S(d11f7de8,5481fbed,f1a3b395,785f00d6,295059b7,c8049768,22624e85,45c78902,1d163368,be0c1290,1a7369d8,11266982,b48928cb,448039c3,17333658,6f5c3416) -,S(a21c65f4,65c4c7a4,93225af,73b63cb2,fd615160,b29b2b90,970b880b,5756fd4b,69a26b89,394de60e,7dde3476,7048a295,57f1e3e2,5f7a586c,7666aa30,9345ecfe) -,S(53c626fb,b080360e,9243d399,9a58ced0,36ccda8b,186c76a4,fdeefee1,6a497a1f,ad926008,62a7ff1e,519106fb,933616a8,8264d7a,c40476bb,eda7e1b7,742ac9b7) -,S(cf67b587,1b2a3ad8,d0364fcc,8741f10a,11d96933,11b72870,60116c4e,74e6ff0e,2c963b7c,10ccd74e,f68ac068,cce1e30a,7be6537f,259abcae,6d36d29d,22b68422) -,S(50216d8,8cc8700,29da89a4,b34cde0d,36428829,de9f58d7,31ecd6a6,c90b4bc7,920c1df0,96bc4891,8defce32,2a512d5a,36f65d7e,65525e0c,123d9fa7,49e38b21) -,S(1d845594,f4686fbb,7b0cc62d,af790aff,3d6000bd,e26ec1a2,67766c3d,93d1aef3,eae11ba6,bd9dda02,ef134035,1847dc6c,92450b36,cd6a9734,25c09f9f,3134d260) -,S(11ad4f50,b6c5b97d,767d590,859e2ab5,2e7750a5,6f7e70c3,d5c52bb7,9e4785e1,2c2bba36,8725d9c5,2152496,f14cfa71,1826e846,fbf7e7ac,4e263db5,a8023b94) -,S(3568d27c,d72373e1,29a4a519,86082a1f,f76ee425,969d6e3d,12b242b0,bd49388c,e36dfa9,6d094047,16e35668,10a8e57,8eff108d,839cf3da,f04c76d5,8754fdb3) -,S(3772ab35,45e09d0c,5d2abb91,97007742,46310f72,bdc0b8ab,afaa2c17,f17801d7,25229a8c,eae0c746,2d7a50cd,a8b012e0,775693af,8edb7260,5340042,a78884e) -,S(8151b24f,72c4701a,e4624779,c8b93ad2,44f3b299,d1ee131f,a13054e5,c29274f2,58938307,25ffd619,de73fca0,50c28d77,73420724,4d2e4c99,86ed5512,b8bb6429) -,S(46a4855a,d4101f8c,60c59705,e537080,1b57a81d,9227f4c8,69234946,5d539c9a,8fa66dcf,21117195,e2c117ae,e2f20bb,9517ad24,5fea8864,beed3e68,89e36b59) -,S(b81bd54,3e654f3d,eec15001,c38bd2a4,efa7c45f,4ece2d4f,fd893c6,15803d16,15c3f7aa,31299a76,34431622,8f93b6a3,2b3947fe,5a894c4a,75d2ba01,4e9d3e75) -,S(3e169a1c,f2a0324d,2478c054,94d58801,423f10f2,4cfc9fab,a5cd5cad,12e7706,20405bdd,d814ac7c,53469075,a700b4bf,4d454b,fca920f9,86923562,19389135) -,S(74283e4a,b161b33f,f67a1b8,cde619bf,557f39b8,5443efdf,534bdd2d,4da65956,22296be2,89785c04,6773ad2b,c881744d,380c1717,1c77b159,bfee3689,d0b3df3a) -,S(62715786,cb76bc9f,b65da0a2,3b7954e6,1a617fb4,de828092,bde3da39,ea6b756e,3c27bbe3,8829a150,3b563337,bf995110,eec54d58,21e1f17d,34a5fd90,52c2db32) -,S(96200105,db23b893,84336bc9,d5596740,2c93aee2,ca35df73,9c55a000,6f7c8aae,3192968d,400a2604,c80307c5,d9865f49,ea41cdd8,e3fd3b19,a2bdfa17,84a6ba26) -,S(bd477798,bd2691b0,8cc52fb5,cbf8b2c5,31787535,541b5c31,3aad9696,b71d13fb,be2b51c9,a4ab0033,c21dae50,c4e7b2b,51978b39,4a66d50b,6be7e140,abddfc3b) -,S(fa149388,e46ff849,bb5490e8,3aac6788,70da101a,f52dab05,9039c305,475289e7,8455577f,a8d85674,3b32080a,dcd26a1e,c75af3d1,c184d5e3,7f22030b,8867b2a7) -,S(4228db83,af1ffb1,d4bbfae7,3781a70a,8ab50d3c,47200e86,ff436ae0,3391ba90,45db1d0a,b0e6f0a1,801560b6,419bd2e3,2413ddc9,4b4ad637,d4071d8c,b7a270a7) -,S(a97ab279,fe0df5a0,3d494c02,eb69c686,1dc3a39a,fca2bd49,f4161ff3,817c85c,5006c8bf,f128de17,3d72f99f,7cd6deec,5d4b7441,6b1ca290,e535c8d,c59bec7d) -,S(c0d46c57,6bdcc661,4e1a3a1c,c19fba37,9f27dc45,5135eb63,f8d44666,904c668f,396b60a3,b28b250,2c97d7cc,f93c7609,3d19172f,47fffa71,f190936d,cb215f58) -,S(73c5d7e0,4599fa7d,e09b8c2c,25c5bca2,b7ae4c6,e1b88e63,6de3363f,b1a8dbbd,1d9ed08d,558bd642,9e986b0,c431d67,9229adf,6fa8dea3,faf17da2,747bc617) -,S(370481d,a2ef4843,8d897c6e,f1a01750,b4788c65,62ad3ab7,bbf3c89e,e24827a7,a88b3876,c2051901,1d84acc3,3000f0f1,ccf794b4,5385aaaa,190e435c,760fa7b1) -,S(2dcbe303,3006f0a4,99dbb7d8,d34790be,f2b68cbf,649b9d54,eda8819d,637807ec,b82b46e3,c7ab329e,b915de2d,f3fa28d6,92cf43d,584f9bda,5d6f58f7,1a90c1e1) -,S(f45f3ca9,16db45c5,de35d957,c24f7a59,44052b64,f8f423c9,8a442f6,17bb4b7,79ddf02f,b3154d6c,da1d6a79,5c64de61,5b4a0ff7,810bbfc1,dad68e60,229b5a96) -,S(500caa8b,cad0567a,465c99bc,c4802553,ee17346b,e3a9ae93,4fe7e95d,e787605e,40847ed0,75dfc8d6,ae19dccf,73ddd256,4e1beea4,7f822a58,f0570c62,f238370a) -,S(30562986,a23962c5,5b746191,e23b893b,7bcd8b87,6fa85557,c525eec4,d64c3aff,2d5abe,41c45383,1b60c034,7bb55464,e19d8d98,8a5d5fe9,37337507,80577a53) -,S(f687d51a,32526b72,9ed3f690,be1e6205,ec72382b,6a30478f,63a18e0e,b48e422e,efce1b35,19c94f7a,fc54da2e,d36b15bc,f197e2ce,a0c2d680,211e12ab,7d515704) -,S(104a63f0,d385351c,c9ce207e,500ae7eb,22199ea7,dea65018,472884cf,a1ca505d,69c21887,50b20b3c,5af1600a,a2a2edc,a6de0be9,33d2e67c,e05ac4a8,30239cc5) -,S(50966099,4b7b8ca1,abf963e2,ff4d295a,eb3d59bd,43029c03,5e6ac9a3,ea80fc6e,d48589cd,40d019b1,81211674,854aea3e,56be56a7,bc8ae519,72963adf,327287b1) -,S(3106d6e7,94e5e135,1d788e85,eb0f2c7c,7ac22e9f,d1c86a0d,d22cf88f,54513c95,c05e593c,4568cc2,992849d8,4006ae18,4ad2888c,82ce8dfa,dbf984bd,2fa2bca0) -,S(4c967d1c,9977bdce,84f76ac7,13b9e5cf,d1081b43,de681235,e7914f6e,2059fdce,866470b2,a3e99b74,15c2cb09,83a5c7dc,fcc10d02,a28e90ee,206be515,e88968cd) -,S(96319099,ae8d7741,1d8bbb7f,bf58f62d,b4027b02,ff5e32b2,e4aff910,3a781a52,6c110074,daf2849,a3b148f8,dbba2f0b,d776eb4d,b787ced4,22edc5f5,67947389) -,S(7c93bb23,87a36cea,9dd7406d,95af56f2,b972242b,759728b3,bdf30fa3,58247ee7,21e4de98,33487c86,6da01e16,895a0e24,17cb34f6,e3d64e01,8f7c4d99,9e989942) -,S(c65e4a03,88de1618,6d9db143,387a3229,c764dabb,7c6ddcdd,c3ba9195,7f1e074,d586d143,8005b28,cea25a45,7c45c1fa,2137bc2,fd78417b,daa499bb,cfca658b) -,S(d895a924,90c28692,bcda380c,71d8d1b8,381b1fb1,a8108f35,4d9a17d8,64d674d5,d30bda25,a63013f,79ef5728,dbbcd259,c7cf2ba2,b00af73d,9804f758,7fde17f5) -,S(90467c3a,5b36b9bb,faffa164,63d1f70,c892e23a,3c7f1132,27bff1e1,5fdef988,4ec70191,40247d9b,3cfccb41,ba22ad76,20522577,1e33d568,946c8081,ea9b15a7) -,S(5cd03d63,d0e025a,7af268f7,8f53efc7,b4d38e5d,58da5981,abcad74,3e294c7e,c3729f6e,5517d41c,ab1510cf,ee4e0e48,f168e043,34dd8781,1a10b70f,b42dfb3e) -,S(5130c49c,652bc5ce,a3dd7629,bf362294,8bf69c02,f9806988,fc700a25,c7e964b,7e46e219,4bc9dbd3,99f98c7,b7a44313,a027ef23,1abe336b,7381c215,6f2cf563) -,S(95899c2a,33b8d4e9,13947306,6b924812,261a3155,e5a7ddbc,c5447796,8edd34da,8967be99,84240292,9ea7277b,5be0d045,bac79fb4,93a08a41,d4dc5991,da6b7cb3) -,S(3928013,8cb3e93f,7c4650c8,8184dfcf,6e55d238,2e75e604,9dd6e40e,f489745f,70b25e98,b897f3a1,c89bd6d4,72f2555a,56bdf04,6fb43799,58709471,f8006a52) -,S(a47e1331,b5fdbedc,e490497c,bff1088d,ba72070d,3cfc7997,fa388fc3,2f80b451,ca54b8be,fff00465,4086c75b,da3ccb9c,6244746,522124ec,ec22666e,a9576b19) -,S(cc1a608e,16c57528,3cbbb134,4083cfd3,f1b325cb,b48df6c8,2d50bed1,e0cfb96a,5b8aca44,67d9b224,413b0c98,78e09213,591b8f87,b024bab5,55120a83,38cc6734) -,S(d8354bc7,591ebaeb,7ae4d1df,2db3bde3,b7438d1d,69b5991a,5d70f6c2,c3fc3cea,efc89693,6765f03f,29422703,97591bed,7d95afc7,29807a31,fe266f08,9eab5ad3) -,S(6ac1c963,ceb2740b,212ef42e,6da07647,481ee21c,4e3fdd6f,f2ae3da2,8ddef8aa,4fc8817,1b6d5ae2,45453c94,f5f2031c,c52140d7,a110d9f,b1bbf3e8,e5164281) -,S(be130f59,b52e4148,f9c47469,778fb36e,74d4da3d,a00f5c4,dddd2e47,6f18b42d,16dcd9e2,f739a58a,22a7d76,1c1cdf61,c5b9f8b9,46449516,9398dc1,fbc47069) -,S(685db8cc,39864a55,68b56e59,96265bb1,24ee71f9,1f9f4f3f,fc3c79e6,c063bd2f,730a7141,8e5b2f7c,2d333b8e,5be3021,22b396bf,9a75f493,37bae5c,86b50f29) -,S(39f41ff3,89f74c1a,e25e564,b9bc189b,f31f9af,cf0ee4ea,aad66ee6,55d743ae,fbea0f6d,e25d4fee,53f0aad0,9338f739,26fdaeb2,edf9d8d8,8e1e520d,d66c8622) -,S(d7a69574,41bc9639,994737b3,d483bc0f,c29b1b62,cbf59f28,b12b208c,4c20ed1f,ce44e2da,cdf8158e,9c07ca25,1b9a3d06,91eea29f,41f824ce,ef2d631b,65ba8cb) -,S(85bad160,9139cbb7,2be86793,42b37884,22f5981c,5fdf30ba,4914395e,c1eaec9a,99fcd461,29e576b2,b25c57e8,8e3fe3ea,362055c7,843838db,4196a485,cf14dfec) -,S(2380bac4,d428a159,23c2ffbe,8f17da09,74d986fe,4210b72d,51a1eb80,23ea49e5,f4af7313,fde4c7f5,e45e38bf,c4d44bbb,3ca1015b,d209065e,5a6ab074,5ed6f54b) -,S(c0561359,b7d61dd0,e359108d,f221202b,97c1acfb,894f4e9e,46fc29fd,364f9cf2,3c377d80,1c72a9f6,2cfea5ff,350ceb32,75b16103,cecf492e,2901327,d27d83dd) -,S(72c499c1,b8f4f2a,eb9181d3,9bba5b2,76481c04,a588fc6,4ed438c4,920c2a06,6c994c8e,60825314,2a34867b,1f82bc1a,f05ff8ff,b3045e7a,72d01243,b2b1ce53) -,S(8de84cbe,2b66209,f8f8e2f3,f06feb45,66e02c9c,b5df26f8,84e20454,ffcf477d,c7f2f680,c4d07d88,69348e98,6a3b7ac2,ac9e8542,a019f379,6410b993,742a34a6) -,S(dbfec9d8,6581d762,e5ac8048,886b9d2e,9a2d02ee,63c5f442,7d02d12e,401710f2,6e611ff9,827bb1ac,a885acb5,906648d9,b46496a8,98a13c90,48868d,c0daafea) -,S(9dd651f8,6099edd1,b3d0ade7,82aae6b3,9588dc2a,291577f9,f2456f23,d1d0453d,4f6db617,f0d7860e,18be81a,dfb6d773,cd3f905f,98611845,5f5a0b05,ee715ebd) -,S(2fd8161a,c869de35,e777a885,ee608f96,356445f2,fa2f33d1,926260bf,9bd66a15,1d2c21e9,674c2d92,b64163eb,12de6347,98c6e7a2,9787daa,7c6b4c80,fd307f25) -,S(3f25bf89,24f505b2,3f1538ce,4940edf4,8b6d8765,f88778a8,495e8a84,a29dc391,70253583,e7e0782,18ab0252,52c613b8,34438254,9dc57c30,afd47297,2c8164f2) -,S(3c0f0359,d5f72344,f8f3d2fe,28458f30,467dc770,b55eab47,ff2e1ee2,6c773f0b,49583a39,459f19c4,5ac50d78,74626524,b9c25030,e45f2c7b,12729ca8,1edb33c7) -,S(56380666,ec1b5df2,36045855,fa0dd93c,87e38d70,fb170dd7,3be5c308,36b73a15,700690f0,b210ac6a,9aa91252,c8af8f60,b5cbbf93,8291fb11,7bce1f0a,759921a7) -,S(71ca710b,b9a5f7f,ec6b228a,af3fc47e,25f90201,fbe3c673,8bc6d2fa,9c9298bd,7dd2528d,c0750899,b1891287,170159ae,c759bca3,51e243f8,fcc9efe3,2f9abc89) -,S(78ddec3c,c938850e,7c2ec20f,98e1be3c,6ed87fae,827c9102,5112d0b3,5d264575,19072951,766a4050,c8585048,d6f19e60,22b9c163,f1799ddf,d486dedb,3d680321) -,S(9aaebafd,8852857e,8c670950,93dac29a,5813249,ed03e67f,3226ab3c,7b4ed70b,8c6a2acc,b541bd51,65e13bc,a3c4d2f3,2457bdcc,406ba71c,7b9cecd3,4705fffb) -,S(586eca74,941180fd,da16c7b2,8b9bf139,a3096a6a,20ab9bcc,6d12be5b,db2f79e2,b3b1d12,361609e5,afc5a7f8,26a21ea,ac4bfde,56016ad5,bfde6f93,a3488d71) -,S(1857bc3e,dbe4de2c,86fed7d4,cc3ee63,c0e0b6b1,36acf97e,e3638183,8d50ddf8,ea5e807b,e7a588cd,ec759c67,3584675a,8a7fbdb7,cc5a1835,119a4f64,8c275363) -,S(aa4cc744,7572c62,22a6cd,bcb8813b,64206796,27f5f7ba,863d8566,78e5b01a,ba969ac9,d259244a,9a3b7f9b,b3821a61,a4a97b8d,af7e08bf,f39f099f,8fa2f836) -,S(4588ec09,59174367,6885fad0,a43d85cf,d6f736b,cb276179,e794da35,204f36aa,fb835e7e,cdc681c6,ee1c89d1,dcbae3b,a9511692,a54c9c37,2f86f4b,cc7c62e) -,S(867acd03,7a3e5f86,99e33f22,72f7b1fc,25ce6622,5020a4e,ca3b3111,e880653c,e9112ac7,57d3f905,3249ba3c,ff64640e,639cd94e,5d6cf946,d8d7f3ad,25764646) -,S(5e0a4169,e4f81dc2,28ae4663,9ae3bd4,b527814f,4616fc13,318fd5db,26df370b,5bd335a8,fc23934e,bee2e32c,3bacad4c,c38cd624,8cb34ca9,e58f8add,3140d001) -,S(90053469,39df2418,1b5b2e57,82a82f15,542a55a3,adfe8263,663b4fff,b101c0f6,4ff0d589,973985f6,858f3837,89c3a5e1,74460778,3a1b1476,e3f1ea51,37e3d991) -,S(a99439a5,53df33ba,6a32f33,d90b1500,4e2db077,22a73561,8f4c3b0d,63cec63f,198e0929,f11fc777,ea9cd8a2,e4e6987e,6f9c1fc5,f703ce7e,7e6423db,39656cd4) -,S(51f2a136,1381ba14,c8fab71d,f82aa2e7,1c7789b1,b78c355,a0e2fdf1,5f085282,fd5f129f,ca15fea4,d6f23bbe,43197a3e,6e2b7b26,84934ea5,a97197cf,eb2d16a2) -,S(3a91f81c,8b064b2c,99509777,864c5b4f,bed208b8,f541f68e,82053158,2ea91d3a,9d59003a,d4ae39e1,95077329,e585a8e8,a542b594,b6010404,8573a01,23a513c9) -,S(71e99d50,aa22fa17,3f026dee,e728c114,5e491e84,e140b462,1056af19,9736c5c8,ff3e4f77,68588846,7c662729,1d947e77,699806e3,9bb0bb26,53f67ec4,176a4995) -,S(ad149e93,3a0344f7,3fb53286,ace2f3cc,46f7450e,e859980e,6d392001,7c8aaa39,7dbf4798,85a4f354,b4f14060,39a83789,65a5ab3f,f1157e3f,2a4f6fae,909e81bd) -,S(44f0a37f,5ad78f6c,4a40ca20,7969105e,86e79ed7,7ebbcc32,1a247f91,751ccb01,f404d867,911eb3fb,efb1e559,66b5128,70836d9a,12891905,af649555,c353044a) -,S(4f77dcc3,de8de08c,4c0a4a8b,29717868,50f5c0e3,b271ec1d,c0d38a61,b30ad5d,73c7424f,8ae80ee9,2118aa5a,b0aa65b3,58dc7300,806ef2fa,55836a39,4df57c69) -,S(794a108b,102a0923,6366efd3,8ef658c1,6d6d5c24,e5e2dc0d,38d71371,e6005555,871965ef,efd79050,69acf0fd,c1f84798,7c9e304b,5fdcbf75,1a6f6737,ce46ba2c) -,S(f1988561,234b863a,df5bd49f,5a0b1252,a72e297c,ea3083a8,22da48d7,14e8e594,7adba507,d0ab51a1,8c036612,dfda3f8f,abd2f573,d31aa03f,ca6eb361,a83fc418) -,S(48bed556,c07c99e0,71249b8f,7790aaee,f3fd27db,f82d1c75,491a18bd,cc3f4a80,9dae5280,21be418d,1b4dd08c,be5dbca8,46cf0122,d4943543,8561e555,66316e94) -,S(bbfef3fb,e53779d3,8f376fef,974bac74,ec8449bf,c2dc8a1f,3bfcb33f,943ab9c1,bea5b772,ee798aff,c610e849,5be0ea8c,ed462563,848030b0,8006c6cd,e312551b) -,S(42af3415,27b3cd52,3806b04b,ecc175c4,156839af,eebc212e,b74bd6,95b7f06,686e5fe5,ebf16ff6,2376d096,188de980,f91a5518,25bfa137,e7b46df,59dcef4f) -,S(3c56d78b,74ae87c4,6efea376,d58b7d5e,30749726,40c24d69,38ade127,71ce10e6,ce97decc,f9d1e215,d363b36b,6ca2bc6c,39fed00b,511bf883,50732752,48d54a41) -,S(4b122599,1944ef0a,ae6404a9,e48f69ce,67b52a1c,da4f291d,33afdb09,b789b61a,5c8be350,27a3f992,5377932c,b6d92bc0,62b1bc80,78e4611b,f3ebbe66,b6089571) -,S(9e42867,c02c9314,a3658f18,14d8c59d,71674955,2b00be9a,cd37350d,18d49db5,5d26d035,1ff90d73,d783155d,afe20cf0,39f65b1e,6d8d5d0d,831977c7,17a8c761) -,S(9643390c,5a95345,2a027d0d,47bf6fa8,306ab31e,5dbd8b94,402db973,275359ae,b354d7f7,1019e9c1,d23560d0,50fbd4bb,abbf492d,f595c0ce,a699721a,b27a3933) -,S(8b4916fb,86f77deb,505374f9,1f15782,1b6f7884,feae9f77,bacf5620,7e126b69,9a83c0,6d86db13,55c3d59,cbc87fae,ce6d2af3,64f9c213,816cb326,28be1fd4) -,S(d29df4b,109782c4,1f5ee9ab,b8488f7c,11de8efe,9552eff3,7ba3cf0c,d0054b9f,1bf06237,ea242c4f,bbe08f6,a79b6808,d1a5a444,1989fd1c,98a60981,40ca07a8) -,S(2aaf397b,a5405044,539167d0,55113acb,d4a20265,206ddede,203b8ea7,21dbd41d,374e32c7,1132bbac,91e4b4a8,aa32f308,13a81c2,4f7b3c66,63d8821e,9ef73081) -,S(2239b3d2,23eace6b,8ebd287c,8b6a398c,1ca58a94,5d8b7b81,7b1133f9,cf57ef48,fda880b7,4b54a8b2,8af4b26,78e03f28,f01d70fb,3e4ebbda,94ccbd43,e2b4cd46) -,S(8b3287bc,f47e72df,7edc9178,51edb145,b88ee233,9f254f62,e86ec624,a7c7e365,54a06bc0,9f60d54e,5f900868,c0c3d37c,db6d9969,1eb605be,321f0f20,9fecabb) -,S(d9accea3,3e3cfee9,10d7e1ff,3e87539d,ace742c7,24d6d36d,d8d981ca,984f7993,6adc974a,a901e5d2,d8cf5a05,a20bd02d,62947f81,5425e690,565638a8,427dc88b) -,S(d7fc57f8,34c348bd,e6692b50,474ee038,4af245da,40b8f6b3,8df2ae5,a8b3206d,b253e4b,41fd9fea,9b28e04b,a6db0324,231edb1,1f9af406,e38d2b30,244e2d19) -,S(25808fe0,ec4a1409,36b34e16,595021e2,b815f660,7a23d505,9ad5b5c3,14d9588a,d0664ad5,b1d46ef8,8c8a1eef,bb9df1ff,a75bc16c,e8bbcec6,6f4798f7,c58e7b96) -,S(e4474780,113955d6,72152fa5,70da35a7,59e67a76,29a39ecc,3226ea13,99927914,493cc170,aa2f0486,da6834d3,3566c78e,ad4eb3d2,837ef5ea,c1adf3f9,43793bee) -,S(c5040dbe,2af9d706,76ddd900,d00f1046,44e2b985,82d46f11,47602b91,126311ad,840aab11,a2316171,cc9b6466,778a9ce5,a7cabc1b,1077586b,91a8d280,324ddb15) -,S(23391baa,316d33eb,3a7ca123,6c47d4e4,8116cd4f,93bda3a8,12a228eb,437d9f14,1d81341d,9e6d76fc,1ca69af,f6d8d119,bc97c79,c7cb8b7f,1ebb54f5,cb7efd4d) -,S(13211756,3de3ba72,2fc6682c,beb39494,8aeb8fd8,c0b95eb9,45eab34f,bc39ac38,9b772721,8a4b0823,7c961431,e26cbfb9,aa527905,41b753df,89eb9ad8,8d74f006) -,S(3b8bb898,b27a2fc7,a1cf896b,bb5cd7e1,708b943b,afee896d,2ff77a95,ba789708,d81e541c,668003e5,5a1e13e9,6a1635de,7fdcbf79,c34068c9,248100c8,9d36c1cb) -,S(e1d70a2c,9af5c4ba,c505e4f5,5c0040ff,d94f162c,815a2e21,c7ce899f,e0217b4d,b25630d6,d20e0e4b,3686d66d,e2b1e53d,eb063b99,e79c212c,2fd3cfec,97a4532e) -,S(1b1e3823,a51778fa,d38f0c56,e2b36dff,a7e681c8,30fb41b5,ff1aaa7b,d912de1c,f2e99a90,a951201d,ce725855,6bf7fd27,bebe1626,8328116c,d593ff32,2584d4c1) -,S(1e31d838,94f56191,2c134817,55e467e1,8745a91c,d903102,e48f7282,21bda7a1,11dcef88,35dae18f,3c02c6d9,7f80896e,477a7b27,41203aee,5048c94c,7cd610ce) -,S(cb9ac34,795cbc99,bf67a7ff,2bc3b497,311f687a,51b5028c,422b0301,8ab7100e,5e5f0621,c804b35c,e01e95e9,a8dc13f7,e5ff32dd,8a44f320,74e44836,3cd0db1d) -,S(afc34ac4,67dad38,a0e326fa,1a656c48,24dcb884,f00a20ce,56c73835,b4e11c1b,c8b1c404,3f6d647a,382ef031,a02c10cb,77a033ae,bfc6dde1,d7508136,28bdcb96) -,S(3a6fc160,ca85aba1,619430bc,ba14e12,3330f636,7a78273e,603f85fb,e270aa81,594a2b72,86dbb390,945a7a48,3707bc32,cb72cfc9,19c241bb,61774dba,222bc0a) -,S(a840f695,657c9c3a,3f64f56e,af18debd,bdc1e4a8,e3eaee43,46b19601,433ce7d4,8a8a7ac0,ca41e2df,461eae96,bc00131b,1a77b824,7273269d,7a41f49f,ea126fbc) -,S(c044e01,70ec6914,c39d08c3,4a293268,65cd7762,d6e0f3e5,5f69d80a,e80a39d6,7bd63082,7ae51516,25ee0b5e,c2f97b37,6dd5fd7b,9205852a,92dbf922,3a0b4657) -,S(cb90135b,352b969b,45eb5c6,7cfdd288,2bf9271a,41da4b2a,a89dde94,eaa00b3a,14cbeca0,762d9b11,fe4b6d26,7277a8f7,b4dac82c,52634b49,2a84b616,2d79be93) -,S(fa7bc437,a24dab0f,21c7c063,3aa4a8ff,c8216676,75ea6963,c58c84d0,b182a0e,e24267c6,d7300c6b,6dd09326,c49359e0,fdf72114,401f244b,383eee54,d1a5aa35) -,S(e6354cdd,3f503d25,37b2bef9,91533ad8,35e95657,3bc8afcd,d0c1c05e,57b3299a,d6c17b70,6291c8a1,989955b9,ae9ef9c7,cdc2b6f3,f5cada0a,3c4d0b86,859ead7f) -,S(9da36530,7e815e3,df0dce9d,50d7d812,132ec23d,2bf0453b,483af1f,bb45cce8,bb374566,98a28ace,a86a1b10,2909ae91,3bbc4b23,22f4d09e,bd298e51,d067a8dc) -,S(dc457a1e,1a19cdc7,6ed1c3b,a416a886,13b25788,22d691ba,76319b8a,38c9d4db,39f93f66,de5a650d,d49919fa,294638a7,85e25bd8,f8285776,dfce813f,bbdc3b58) -,S(b2377b1f,1b1a0e98,5ff57bc6,64ca456f,ec216c6e,b7b389a9,62b9d82a,ccf0374d,383a5580,d723509c,bf114e74,b3eb9746,7a040fc0,6232adb5,dac199ac,77578c1a) -,S(8b1a6446,755d3a85,3851fabe,b95c24d8,2a5a86ce,5e5df65,78051124,acfc7e50,42b885d4,cb632a67,51a88aef,192a5bfd,ed1cd461,438cb623,1caf3346,9655cf75) -,S(9408819c,bacf1a0c,9e5f1416,23a907a7,c3a7efa2,30a15b3e,7d5a6ff2,5103f5b1,a9758ec9,d6f84f73,fd107451,f0ab79a2,1df08c30,cbb2456b,d6c68cb,c506f98) -,S(8bfef047,7b3f8cb,99d7c933,a884da4e,9ce6d473,c243d3ee,9c319870,b06ce25c,8bbcbd87,d06af17,550d17ee,83017c58,627f1d84,e8a07e37,ca73c12c,f7e5c498) -,S(2a857f0,c12202e1,1dcb84b8,adf582f9,8eff647f,c3803cc0,dc1d294b,414bdb61,9bac456d,a7fd9318,244af8c6,48ea23aa,62c8ae1d,af7fa9af,e430efec,46db6548) -,S(937b8c5a,90485ed3,d06b224,2ff53e6b,b94b1ee6,a493c835,25e3acb6,5d5cb5ec,d37b136f,f9fb374a,50f5a311,ae366ca6,c9c3d867,e9b7e788,da3b2766,a7ccd808) -,S(5f544d53,e2bfd6be,d9150ff3,6a1e5c5,22b24933,489201a0,65a0e0a0,3a43c77a,ba9c20e2,8c47cd98,1752c413,70ced32,8f4c847e,20165562,c3137e0b,12990f51) -,S(67b63388,90bf8baf,a5b64fa7,eb9fa4c9,e3249cfa,81a55cbd,9c297e7a,a7c807b9,dc185675,2d94b811,42b54577,edf808a5,d871ec1,6c8ba567,62061dbe,ae7625e6) -,S(587a9dd5,99cb448f,9f92ffa3,d6328032,b76604d8,386a2e2f,bd324628,98439442,496998e9,a893faa7,a49e73ca,2dbbf533,488aa687,51ffbdee,6b6d6dcd,dbae9870) -,S(36fb7b1e,c576ff9f,81077312,35d18612,18dfe51a,58642a56,8f80294a,63c29b38,34a45ac9,b82cb1bf,2c96fc1a,67de8a63,5c1a1589,61baf8e8,a2f01572,1566c4aa) -,S(87b71c8c,a0afecd2,dd8f49c5,109ff434,ab8a273d,4e4efcae,f775624c,71f4ba95,8519151f,51122588,76527c56,e1e6d9c8,5b3626a1,bd6ad0b8,1bc382cc,525676f9) -,S(acf65cf2,805c370b,a3bed962,c3ba3b0c,56c98,b81a696c,f433a0e7,a463e040,f093929b,f45be16a,f962762b,52f57ef2,dc7b0e23,cd68e3d6,63b3b402,15692d5b) -,S(e092bfed,8b010c85,b91f1674,1cdfb1d,e3e045ba,81297f44,8990475f,2147acf1,e0bb9842,ecc8683d,e4016072,86070da9,8c4d18af,8bdda91b,65770a98,77902c37) -,S(9bdfd7b9,8260bcbf,17812735,c70501db,ba386b7f,28ece691,97c871ca,610a52ae,9bc65398,3f8c4cce,731e01ba,a5f509f4,887d9a78,40620d9a,ffbcfdeb,5e371eeb) -,S(3db22321,d9311589,5c85587a,9095421c,afc8a80d,86a4240e,9a4a2f82,8643545f,42af30b8,2c57868d,e0f23c9a,fb19947e,fdd6bb45,4efc68bf,ddbf7349,8fb78eae) -,S(e9d3f14,a6a77ffc,f86decbd,c5e43fa3,c3757a64,22d37da6,25627961,622b3e5f,83ac0bed,1e2a714c,c6ed0764,da92cc17,fd18ee84,36d667f0,2f90f818,30e67de7) -,S(412486e4,f29b4887,e1448af,ad59599,b31b9085,8682580f,891d51e,9842f2a4,c31c5931,8c0d6790,c2fbbb03,9c2e761c,bc5577b,53161a8f,80d397f,de7ee3d) -,S(e9deec71,41ed506f,e2dafbe0,c9ab75f9,609f8422,a4b2da26,7c529d92,36b4ddaa,8728544,d8463bc2,d846029e,5d2a0a40,8dfb767f,9adb79eb,2209478f,6d94a21d) -,S(5a0a2292,553c46a0,823a1761,2b8925e1,bbf01c2c,5bcb7173,5f0fd6ff,b264218a,3097cdf0,adda0f10,a261f897,6447ff9c,12de696,8f05009c,e90d1575,e55dbae2) -,S(49cb2a37,8b681ad1,ba1dc23d,8d12f186,563a40f9,ce0ffd00,5bade11a,4928d1f,f235e2af,c0f65fa0,ff15a938,ad804a3c,fbecc5b6,e276bbd6,32a06959,3d6732d6) -,S(d4d71cb6,36881177,b05ad510,a621cd44,3dd1afd4,84d177cc,f99abdb9,1615feb3,3ad65378,de3eb9b1,606f385f,a950d533,5316c363,fb076c02,ac7f12f0,7562645b) -,S(591b2e1,4bdd6e00,64f798c3,14e86cc5,529c99b8,3f47d148,b7e3e642,35bfab2f,4f686266,fd2a4c66,4d6bbaf1,2a368d59,12a51789,5d783aec,a986a568,a8fa59b0) -,S(ee503c85,c984bc49,3d7b63c2,92eac9de,be253400,f4988086,970be236,47356876,bd828abb,6f9e89cc,741704e9,614d6711,39449bb3,a7ebdccb,976c573c,4bdaa47e) -,S(2f9b4fa7,2e5a1fc,ca36a3f9,8987c3af,756e78c9,77fd5697,758c95b3,14b3f89e,9668615b,3d5b3c74,4ea2e1ce,e909d9c3,956657f2,1a65fcf3,3f0ea150,1ca4a15d) -,S(18b6d06a,a34124f8,5f92b204,e2a010aa,a1f4aebc,6e13a62,34eb1c92,7afd46c3,66cc31b9,bdf600b0,7e624bf,a3e079f3,258b0ba5,5437264f,b460481d,1f4bef4e) -,S(3bc07963,bf758dd8,fff37d0f,30db6eb,67662a4d,65395688,1cc30340,ddb44ba0,60e11ef2,68209a1c,2df9a3c2,276db6f8,8e6dc1ec,b74548a3,57d770c1,ad057e5d) -,S(bf585d6,5b325423,afd49af3,c9fa68a,91498b5a,f0ee9e3d,d089b288,53a46a8,2f8944e9,ea484b9a,51256e2c,fa9e5396,4c000c1,3451cc05,94bcf6ad,e38e66a6) -,S(887c0a2e,be7a0257,5d5b59a9,11f40ef8,f0cf1438,d7f05a7f,64e9c133,cfb69294,45f334c8,4f9bc66f,50fde594,94175491,9c37c30d,d20f6a58,40271e71,60aec5c9) -,S(9dad7af9,a73325c,59a17700,fc3dc6bc,3718e79f,804a2116,1bf9a36,622f7d4f,2b7c225e,99c6a94,c7e326ec,b89eb8dd,40644bad,1893136,6442985a,e6159525) -,S(847e4f95,72bd29f7,4f3e9a2e,d73cdfcf,63bcb61c,9caf8694,7cb84594,a7dd551b,ba6ed282,e0a92c62,fa86286d,370cb344,f6f1182,a101c4b8,1ea89a15,b393ee16) -,S(25213205,df1c3600,4673c4b4,49256c70,b5d8c62c,cdd3d580,2684af47,f047a593,36dc81de,5af4709,fae2a47a,8a205647,95aabfec,42a79f3c,54763d67,ef096837) -,S(75228cd8,4866df7a,4713a25e,f2fb29fc,95ebfd70,5d73229a,b170cbce,1058e87a,fba4879b,cc02d3f4,fd25f056,c0854415,68a47355,929bb812,a7dbb30b,c012fe6d) -,S(74945539,22867c08,6d02fb07,c0424890,981a1337,42c63fe4,b6adadbb,59b68568,7d774917,8df8b19c,8af0bf0b,5247e751,3e3b8d04,46465180,341ebb54,1d1af3e2) -,S(69db7f53,2899e39c,fa0cbadf,c29946f2,71d28ce3,57f47f7a,609e0fcb,ffc9b04f,cb0243bb,103255da,ad423ffe,e1d50f9f,26da7cdd,764a11f0,a6694b63,199feabc) -,S(727ecdc1,fb4a0dbe,fd2fc37,8902f922,ec4aedf5,53dae225,1d173c29,2929f8c7,ae5bb2ed,13778d60,66446ee5,e5754db2,bfc4f7c1,64bc035c,224d495e,651f453b) -,S(903ced8f,ec2544b,e207f5c9,e2c7f2bd,91213873,5eebc382,b129e334,7ef25b72,2117ca29,ee13d31,5e89bf33,afa8b7db,ff75c795,6be40c8b,b2e41cd5,943190a6) -,S(c4d467ef,5149e117,3638a5ad,6fd36373,1c8906f0,80336ca3,3a6bbb99,1a03f33b,ea5b5b24,4c536bcf,ce3d437e,abf2fcec,431ad80c,ff975b63,bf398163,629b5c7) -,S(16b577a6,5f6d09f7,b23b2b7a,dd80a2f1,cff7a8a6,c36bfcf9,d325e37c,ea37326f,66ba8e2,14674e5e,228a6576,a52a791,84d98be1,db1a2dcb,e9073934,d09f15c1) -,S(ad4bcaf2,e480adfc,e1e45384,6bd7ddf7,67fceedb,d2bf1f5a,6768531d,9b63412f,51fa0360,47810f59,11b1b3a4,525ee72c,c4c891b7,56737f4a,a61a380,e9e741ac) -,S(b249eb38,52d2e787,4a52d776,d1bcb399,51ca65de,dd9e9dd5,87d73362,c33b571a,3e260824,14e4ece8,83cd84e,b177096c,62dd7706,a79c31d9,b1103232,53a66258) -,S(634192c7,696a01ae,81310d3a,59d2c53b,74dd0560,7e3be9db,ccfd1ec4,bde14a65,455b4850,e366e077,d86dcd70,9c787b18,4fd4cce4,4b92954a,dcbe5222,57b0e00f) -,S(ffbecbf5,d433f80,49e159cc,c14b198a,acc3c5ed,fbb1ace6,fd295dcc,4a2f5099,422e7aba,1ec66cf4,36489acf,9c03ba33,dd68d368,8a48685c,aaa1de52,440be3c0) -,S(65b4c4dc,1067e823,9cf4f1a9,d0632da,b6a8c83b,509a75ad,8c133dd1,5c1868af,f7cf5d9d,d7654618,5183f8ae,7f42a03,20c67817,9d5226d8,40dac1e5,f94d260e) -,S(d380ecce,9d603502,d518dbed,405b8d0c,8de48dbb,35d5b559,24c1a560,9bf9c67e,1ae84480,fd18ab10,9eb0ac15,265c609f,8b241b4d,a80b13ae,50c35f8f,db64c128) -,S(17189d28,b5ce1bbe,d78a1d96,15dd1a50,3fce43f7,19d042df,63484ff4,ce44511c,fbca28f4,7c7b3e39,4121b948,ba561289,85c53298,8db2fbb5,7596a473,a782350d) -,S(fbe332c2,e2a8b07d,a85ae4e6,1925bf3d,be685e4,fafcdee7,3f558382,80c2e84d,aa917342,5e187da0,e3f8c6d7,79b42cbe,b11c43e0,6b594eb3,e1a5797,ea4e29ca) -,S(8b9e8a87,8b5e725f,8b4bd518,22e9cd21,2100d1f5,cdaaf210,2d7963b,a0bc834f,331fb31c,c28f56bd,5ff1d6ad,80b65702,b2e873dc,4552c563,bed77a08,cc3ed659) -,S(97e92411,a3c0bcad,17a798ac,eca61ac2,34e1a68a,b668aa3b,d730cc8e,8de111ca,b0f170a4,bac15e17,2e75fb75,93c21a41,4794976,bafc7eb,7cdc4bf1,6947f48f) -,S(20358813,33a13c6e,cc8c76f8,2c279577,49aa3c1f,d4d51691,9cd23b25,d044eea8,480afaa4,8c86af0a,ece2f951,7df0f344,259fc4f1,4d9a5c0,ee73c891,780c7f29) -,S(caa1eccb,1575740a,90155103,9849befe,617579e6,22b7c343,a665beb7,a67dbcff,aa695bf9,f1c972ff,b6fd3451,1bf042d9,1aee5113,9c1ea577,e0bd52e0,a4e0a20b) -,S(8e7c2ba2,36f7a8e,fdaa212a,7fd6b883,f331049e,6e8f2bbd,138a3adb,c2620719,bd03702f,1434fb3f,5846c4e2,e779f8c0,d9b6e031,1feced02,20a618f8,2eec105c) -,S(e07dc033,6dcd04c1,fcfebf09,40c07783,88fbad11,8e4eb3b2,4dd637c7,baace975,b13bd0a0,e5eecb0,762ccf31,1bd53156,ef6f9268,50044195,10d6616a,b32a2c2c) -,S(6606c825,2679af01,9d8a904,4db0b28c,95aba791,d1c33072,97afa2df,bb8ce0cb,7505e59c,a9807993,5710de77,747868fb,10fe6c57,36ba2054,6477cac8,8e1d3cc) -,S(9fbf4cdc,ec48226c,b45450f,b0de5dae,2b31f935,2b99e0b5,22ab9935,1de6f061,f2e4d0a2,3da020e8,60a0d58a,2362b7dc,e9c5b646,7034ec91,a7dfa601,1ef850dd) -,S(e06d697,5195ffc2,988b0403,e977d32c,b7cc8167,e800db1b,976f6186,286916bc,8015370a,27d3d221,7af80e04,a49003ea,68302bb,c1a5c83,63244c0b,c30bb8bb) -,S(adcd67ab,21d2aac,65112fd4,e6e16cd7,ff792577,e9785a6b,cf4a3f0a,9293a6e2,6527b620,29062aaa,5058608,f5cc3bad,8e4f40d4,9b5be93d,faa5c2b,57fd7fb8) -,S(1d9069ea,b43a64cb,1187e963,d96809b3,5a447317,68910e13,3e0bf7a2,e1f2bd38,ab03dede,854b8fe9,4ad2f9a6,8ef5415c,fc78c28f,a4ec33bb,f15df31a,91e29108) -,S(f1f6b776,b8ec892f,148168ae,8ce83f4b,603206f7,2a38140e,3a422e67,a20a768,892ba036,3413da21,17d9b11a,7bb25cd9,e7136a7d,82a7f45d,14abfcb2,b9bff25a) -,S(a884f94a,ce79f4cd,f3a8d1b,f8a2dc3b,c21d1c23,433a7fb0,401c5df,1efab379,5f53356c,6e45248c,ec282fbe,ef03ddf7,c611affa,5d0d3082,dd630f80,dea05c96) -,S(b1988430,197a8800,e1016564,b48d4f7,1fb2be08,35e9efe9,81a80f10,e61da9ff,d5c7864d,ea7d12d2,5be7ace5,86e141a0,e515a41,5ec70bdf,44a68d8e,4dd849b9) -,S(15b73aa7,529d5b84,bd5c1db8,2b6c93aa,46985aae,942f6d4d,1094434e,d27fedb,297e32a2,bc8ad13c,42011259,b1ca3d40,632ac6de,f2fca262,75dabc8,ee721f89) -,S(339a76e0,443c1fb1,65992630,116e523f,8e35cc7a,16cd0f3f,57f7782c,7d97d40f,8990652e,fecd784c,33e75620,13b52e6f,914f0f6b,c413aa22,9e5bd773,cdfe9659) -,S(bef26cff,fb80ddab,9458312e,9b09044b,b1c535e1,84f4e51b,f64b5183,b67adfef,3818929a,ef076a83,58f20518,c5b310f5,2c6943f2,1675bbb5,ba1bde45,9d37490b) -,S(cdc56c81,8dafc273,4f4dae10,84f91b08,3dd40d86,23125894,c71d9243,8b2427e,f4b309d,e9c828b5,44542569,45579f91,b4376935,3f586c71,f07107f0,1f503cca) -,S(3ddefe81,b1f38479,ec9be80a,1961c5fb,a09312a6,2a775911,cd65200e,7d75bc6d,75d83edd,1eb9b479,4effae4e,ba8007d2,7c7e2d51,a9e95d3,a1e58358,56df055d) -,S(da7c6776,99032cbc,4c2bae12,59212cf2,a18879d2,63aaf99e,76339041,10576826,2e7a6d88,360ac45b,9871f779,9e80698e,4314cc3c,3f1cb1d0,c07ae9f3,38553f08) -,S(2611b435,e0bc20c5,88cfaa80,17f4555a,b8aba4c4,ae1c0385,9dfaa911,aa80d927,eb58f81a,e51dc504,465ff8c1,c0529fac,e47549d2,429e5b41,7ce0cad3,7d4508d4) -,S(b0fbe548,36f07c4a,a715aa08,806b71d6,b8f4c09,6945a7bc,3defec7b,67962961,cc60a224,66e7744d,c58668f,ede30ca2,1c1749b0,45ee50de,2a881a53,83e5abe0) -,S(1a03336f,dc51ee75,facb7688,b4603c86,77d371eb,5ededa9e,b50bb49e,c9020581,3fcf1b03,9c0edf8,99855fc3,6acfdbc7,bd507145,9be7e18c,e9f715e4,98daa7d7) -,S(763a1215,c8349155,aa849b20,f2f68a36,cf72892,49e4d3c3,810ee72f,78c159ed,37826a1c,cf30e1ed,a1795fba,d1f2f227,7b68d5c6,9ffd390b,d7dde5e6,58482684) -,S(7fc7b4c2,30183e37,dce0a586,a6f0188c,f7e664d8,5fa05eff,63f2c27d,cada4edd,fd7a780e,6ea89a06,f0649343,abe7bcf,6338d2fa,fe457f50,ac415c91,2bed6a8f) -,S(222807c9,b0686f55,d9eb7d7,412588f,dc543bfc,f016c8d7,74726135,dc65ddd8,b9670902,456c22ef,cb36d155,319393da,9a34b2b4,301c898b,43d957b0,a56cc2ab) -,S(79d8eb36,98d8d06e,6ca33f69,ca04d3c6,db636346,abfd603,ed0189f0,fc5fda77,bffc97e1,1b0234a9,8dd1d460,e19db522,931fd49e,26d7ab28,f1326517,23d955f1) -,S(a2366618,8e72e1b6,d5ab7713,decf6e3,1f801a6a,ac88ddc5,d464d127,ebadd34b,ef23da36,f3e71913,2774cd1c,d150ffb0,70e99ac8,5193faeb,b1736abe,77d60ed1) -,S(b6bad04d,dde6816d,9123e8e7,43fa46a5,b1fcbdb3,fa1f13be,480fc1bb,49dd9612,585fae09,a290b273,a68b7f34,645b80b1,850c6507,d959b546,7f1b0100,b6a4e511) -,S(2bf21c25,3353e715,283113db,8bb5018d,33fcbd58,f3d6face,b491e1d2,f4c3dfbd,e3a033a7,4e8a4d5b,c8c49121,43a47b07,b9fec4d8,a0d5b3ef,569c44c9,cf8d896e) -,S(64c27a41,e978e35d,63f3a90,e71091f4,41e9ad26,6a05edda,358dddd2,5d842744,fcbb625e,8fda695,988aac9e,cfe67c16,bed76802,3b527d27,521c1339,3dae32d1) -,S(620a1ef6,fdfe5b5e,9a4ef435,63cd7c8,af62acad,a02fb399,b7542d2b,6481a58d,b0b79e3c,550393a6,fa07f105,c547e203,a45fa7c5,ec825ae5,7bec305a,ddb8054f) -,S(1523f131,7cef7154,347ef68b,424ee0c6,15e71251,a06bf8a1,ecd74675,307b95cd,c72554cc,1d8ad664,dc1fe67a,3f11e5b4,a55806c5,53dc2612,bf5516ff,f0743b1d) -,S(d765303c,a9c8794,c00d4d8c,2cd73fcd,b43f763c,b753700,f66d7294,4eea0cfd,bafcaca5,204dd77a,a3a17b73,da3064dc,35b4cd22,ae01a623,781603d2,57bc267b) -,S(a75eb61a,fafce965,65198759,c25cbc41,ffbbf87b,61839a8e,a17f04ad,64c468b6,99802893,240f48aa,53c49b18,1a6d50e7,a8eba321,64d587b8,41497d9,65869873) -,S(7fa41b4c,d0bb91b6,c25813c7,1241e691,e7053f7d,beb0bcfa,4084e06b,bce59f2a,a0941779,755a695f,8317e7e2,f6a2c57,9431e22c,4aa09f,7e583b1c,e184aec7) -,S(816c0db7,2240f12a,d8deb440,8ae2276f,3bfa1bfb,d820bd6f,cc5ccff6,16e4dbf5,2a52c93d,d91ee658,9449dd4b,bf70255e,e57acbd0,a981ac9f,67c16604,3f7e52d0) -,S(33f635f1,317f1425,51390ac7,346905e0,ddbb3d87,b0c1780f,bb7dc950,c23414f8,7435a155,84eb1988,b974d570,bbc2b2c1,15123580,2bf93bd,b626a543,e54bfbcb) -,S(d2943ad7,4b0bb03,35307185,fbc438a7,bdfe11e,7b5e0eb3,e94bec46,a251999c,2dca8fcf,19aaa314,ebde41de,fff6e9fc,b6097d6b,3bfec06f,19aa4941,676d577e) -,S(26aa1fbf,c54375a6,fec54390,b5e44a0c,fb524b65,c10d1516,b0112525,9dfb1da6,49eceaa6,4c575ce,337d0b6,ee7e8198,83973c6f,abfa2f,d4b24e03,99a91b02) -,S(780aec1a,f866a030,5ca6d7da,1948f2f6,ab18717d,e82300cd,65eb58cf,a7d28d20,da650041,e45a0e1e,a9075b6d,107b6f7a,414b3a02,18aaf929,92cf2978,bc08b91a) -,S(1dcff259,8e59dd4a,3e515853,b3cc41e5,ef98113f,29ff7b3d,5eed6d50,2cb88b67,d7978630,7c6871e4,5654307a,e3836e07,aed86cbe,a9ab92f2,8c680172,1ab77271) -,S(b19af4a2,77321937,93e367eb,5ece1c63,8f336f3a,9cdb4b01,e2488ee4,373ff70d,a3ea8839,a5105a2d,4277f27a,26a8ee73,b9e73fcd,d54f641d,c214d5f7,9c821dec) -,S(1c8c1f29,548a9df6,f28b6126,b9324972,35f24e2d,a488e066,acf782f6,b4f6755e,1a79ab52,6a1e1aec,5ccc7e2a,3196a07e,78108b23,a86630c9,1795ef96,11ff432d) -,S(b6ff8dda,1ad6c3c2,3c8a10b7,b4313968,e4d70075,12c421d4,f0b1153e,bd5716ce,4d3869c6,b7b74167,ca0d21e4,edb3e01c,af8dbec2,aa87a32d,7c9306f9,a5ce61b8) -,S(dceff4ac,f61ba84a,81821932,9fa0ad60,ec08cf9d,830e6ccb,375488ce,d0f47b5c,949aece1,92bc61b4,883d5508,aa4a4aa8,fb1b8db0,385613b1,736a6eb5,c137d6f9) -,S(5561e7a7,b709689c,97c4aa18,9a3ce841,843ccf98,be851c8b,131eeb37,dca5ebef,4b108c17,f298be36,430e6b7f,26b414a2,33b924a6,e65dd5a7,9a1f15b,a99a14da) -,S(4d989577,89b01595,8e5d5bb,2e064e9d,9c56a254,5b3c8802,7ca0c997,a395a257,aaebaf33,ac950756,c5b200c9,f5b009c4,506964ce,5b706675,7951f221,40b6e0d0) -,S(82b58e6e,6373c4b,30ad55a9,d66cc804,e9da512f,bf4af668,1246a12f,e33bfc8e,8378122d,98dc1e37,2c33b5c2,1ff4c429,d6d7577d,2ff353d3,87cc0478,1a5ffb38) -,S(f49fa88a,a773784b,fe57d880,9efac44f,714c3d75,3669463a,d1199be8,2c6cdf3,41aff6c0,2164a411,c8be7281,493483be,aa9855b0,49820772,b96aa39f,9a18b3f4) -,S(67d485db,ac8445a1,8c1b97a7,8c1852a5,ce910f0,d78b073,969c58ce,c0efd78c,71dda92a,24ff2b31,5fcaa5a8,28bf07d9,596f49b9,cf19f4be,44e6f320,84981e97) -,S(9145f6f2,c19038c3,cff99883,b5a71760,30a46f7e,8b5d350a,db2a9610,4704d4cd,9d9179e7,852ac5fe,1d4664d5,4d778b3b,6c8e422b,b6e78add,56700dbe,6a22b0bc) -,S(492d5247,efc2f5f1,1cf3848c,e0719abd,53674089,808de4b3,5503e23f,46b2631b,374b0762,7812c898,7ed68877,c995a4d4,9f021d0b,29270863,d50b8c40,808fd750) -,S(5b8ddfb8,bb811678,9298d231,72bdb9c5,25c6610b,46187549,a381ca6,17dd1dec,b47d3764,fce3218d,17d0dee0,133d4f3b,c7ae170c,3e8831ce,a92a3531,7b1f7568) -,S(88db73ba,25a61641,af5e603c,cd54c6d4,63c6feb,da11ec5c,6a35d30f,e406c65,39b06f7b,1c1dd7b7,884c67a,e295f8c0,9b8b5be1,c14456b,4027bf1b,4800a753) -,S(3495cc9a,a23c1eb4,2cd85070,bb095563,2a7037bd,e330f721,fb38091a,9c382451,7feabb21,6f3982df,74429957,3c7557bf,b82ff4f,462fc64d,d9b3e10f,b69799ef) -,S(e8a5cea6,970e10c7,93f75666,9d2309b1,a4f7b52,c19db4f1,cd69a652,c445d7a2,daacdabf,bd5259bb,96d2dbf3,668e8c16,fab47624,294d9982,b961f0ea,32402b96) -,S(6e8c78a,e81a7ade,3989c483,7d9efe50,51af33f2,b2b2ee32,b5700b43,67931f9a,e5664504,751b41a1,45b5412c,be10a782,7d1d5193,30dd69ca,47be2975,2c291d35) -,S(b8f520a3,10c5b2f,8291722b,1e3a92ec,b9551db7,744dd208,ab4d1709,310a539e,65901c3a,b6712ded,8f66451e,1915113f,a96d3d1e,d9074790,9e291d00,970f3d75) -,S(a0538458,64459815,888bd917,3a2c16fc,ae0deaa7,cb804adf,e49dec0b,b2d8005a,27882f00,23dcc9fb,890dab73,f98925d3,e712608b,3d6069c8,ca58ca6d,de0d7a67) -,S(41280416,aa7f0924,1ed8b631,fc2959be,2117cf03,9c12f600,1faf8a05,15222144,c2fef80d,fd8e8433,ee55c363,c43f7e06,613f354e,32aef8e1,808817b1,af7f58e4) -,S(c4b8ff36,cbf83d10,51d130b7,e3d613b2,8b536f0e,b050a41a,7dd8f8aa,18c7a1ee,87d3c44c,8867337b,466ba76b,47512399,f6cf6c14,ad4977fc,276d67ec,5e7b4d47) -,S(40eb693a,7cb938e3,a6b85010,6b7cd257,1de630b9,86da02a9,3b7a7f5a,a0a51ac1,27b875e0,14d3417d,cbc3b770,c4cb8805,c7ede7a4,efa9f89f,a51e36c3,af6d8d18) -,S(f7491902,54e30180,75365d67,5f2ddf24,ac0c9d84,df371fb8,6e94a9bd,7f81dad4,6a271b36,c549080f,dc9bf1b5,ad275d62,68af0cc7,2ec68c7c,17ac24cd,5c5a6e46) -,S(cf13261d,e4ce19da,14e6996c,97a23f8e,f16388ac,c364f2e3,6a053254,849f287e,5568858d,be1a7447,f7e4ab51,bb872a78,8218c483,c771ab7c,4a0a968,73adac10) -,S(9c6bda62,9dd087df,d5516606,62226847,94cfd517,72c72a81,7263c761,ad3e8cb3,2c77dc7b,9c7fca7e,bb35628e,d62ffc79,9e5fbcc5,e25bb0be,5b1b67a,10c0eb3) -,S(d8d1035f,64439dec,20ecc9a5,5b314959,c1526d7b,d15b1922,bb7ab7e5,b9d26bf3,ab7e34d6,ccfdfea3,f607f697,b941bbf7,b922a436,b9cb4314,3eb1b948,ccdbbe30) -,S(c6f40a23,b8227a60,de32e104,7080f087,7d53aea5,b00a22a9,39cbc228,d1c1d424,e16bc58f,cf4b8c5c,9106f1f4,b8b2374a,63a3136b,e5a8c64d,7fe6bd0b,c1d80345) -,S(3a69da22,9477d3a5,7147c2de,cce22de1,d1e007cd,61d22509,49400b8f,63a43536,c79c4fd5,c4ba6062,c7cc95e1,c9b79cfa,46b98cd7,389cbc39,25cc2fbe,49a0e284) -,S(1b5fb8e5,492fc48a,46b7f6fc,a658f218,814c3d82,90aa339b,7bc7b794,325fc9d,a6290b12,4c9e0819,2b6f49f4,c4935b01,d2ca4235,8efea982,1646fbe7,dc7fff39) -,S(fdba0f02,b004b4ea,dc9e1c37,d1a7fa7e,8a755922,31f054c7,47bbe8ec,349a3845,42da61c9,e96471c2,6fedefd7,e30c43c9,6c3c09d,d72d662a,e2b82022,391646fe) -,S(c39391bf,cb7b9662,be7279f7,6338988,7c166343,2faf1760,f38f0cb3,a35140df,ea14e034,53dc82cc,484b8b3f,ff79d81b,449f9f81,d7a52d66,4c5b563c,9af556e1) -,S(254ff13d,c716cb2a,1ac0e36c,c6cb20c4,19aedd0a,2219321,675e1744,859cbcb,2644cf3,916d26af,9e36bfe3,247f5be8,896e02cf,83eb3701,c400ad2b,92e35921) -,S(24e4aa60,e9b464ad,a2c8974e,98568026,1769d35d,aa7c8c5b,71c9f57,28930474,9df7c2d1,82a94fe0,80a2244b,ccc9406f,6ed37c38,d9cbaaf7,8d973538,e8479f8e) -,S(7ad9bbad,f906685c,3efd81b3,8599fc02,fb19a4c1,8bff1ef8,702c4f6,d17543a6,9878b970,9c4018a4,f713ac8f,d8a533dc,da45e243,44926df0,133aad64,c5246f95) -,S(97d8fcd9,383a8717,e0c9eb2d,f7dfbaa8,c6e08339,be5fa2b5,1d12565,62d8ae53,1879ca4c,f5784f86,7f8363e1,5d85afa7,b1f114ca,7f8f474c,4a2c028f,7c6a777) -,S(3e0fc785,5a08c32e,1e14d1a9,2c56ffac,2af1acef,505ed72c,b8771ddd,8afe7572,6d79b7fc,fd1e8894,f0844fc9,da30b555,bb1768f3,df15a0b5,884e5b09,6e149390) -,S(d9da17db,b132d864,1da3a9b5,389d6f5e,fda483e7,fc7577ec,55b7ecfb,65602562,80e471e4,5feb0d70,2ee7f9e6,3f8f23b0,33a4f35e,8a0841a7,b67f8c63,c623b70b) -,S(1848f766,afcd1e34,82935daa,7b71212b,f38e2853,9d6fb9ec,a3d9809b,6fca18f3,ca9a7882,645d54f2,49d35df6,3748ed94,5f9196f4,a93d4b7d,ee70f44d,b6f5884) -,S(ed3744ae,9a7dac76,5ad65b2d,4fc2d15f,1a9d0047,f72c6be0,a849ca04,497a9f2f,3cf76d2e,d4e5c6f7,e4b23d03,23c477ef,2fdc5248,7066ef36,b763444f,6ab5fb5b) -,S(c4607b73,edf3545a,b10a3a65,e0312707,91212acc,a86226b7,b1ccfefe,5f3676d7,31ad465b,8595f783,d5c0cd03,6230e3dd,2628ac9c,45dc6d77,28c42093,3d7eb3ec) -,S(1c0962ed,2aaf69d7,8b20af04,93a3fa50,bfb9ad1b,64eb0699,641e4b0a,bc0e96f0,49f11af6,e088e3a2,a429c5b0,a87a7f6a,591b5a60,a397c123,2d56a4a,adaede44) -,S(6a0476c,9a41959e,98dc6ca,fb7b4381,82250e1a,ae62445b,1f09a098,ddc19454,56842c97,8ae3c4c9,2c266cd3,7c8e3514,ab4288b9,ccc7e33f,be552ec6,f511c7e1) -,S(24da0f6,53a30aa0,a6b14999,329f03c6,cdb59a80,e9ca68f6,b9367830,a0191f1c,83e79080,aa78bcf5,b810683a,f061c614,cdbd3b69,9e200b53,d1a2c757,2c138235) -,S(6c3483,22479d07,f5871901,3264402,a078728f,227c75f,6f33743f,9a1a7764,a377af74,4a125408,6bf128d8,45bda458,be779210,f0d85bff,eb192c0b,a0dcc4c6) -,S(212aabbb,4d14cb26,b26cf249,882b36e1,1cdc26f4,a1494905,15478f99,d5c43baf,e9140a0a,81d1582b,98eed57d,7ba8e584,11c22ea3,fc265148,ca1d6050,3847e281) -,S(a27478f1,2afca20a,8d46824e,5b0ba272,f26ee0c4,24a951ed,f371425a,b343b10e,51e74b86,a7fc97aa,5a3bdecb,67818d7a,70ad0ba3,7c7cd759,8ec80a4b,bc4036a3) -,S(e1c1269a,7171f9eb,a2e2fa7e,8f55e0e2,b9b8a507,e8cdbfe5,716f711a,572e293,41cfa170,8953242,f98d8e24,2e827684,5562c4a7,6d034848,e639335c,32afba46) -,S(204d544c,19418e19,bb328e1,ecc0fbd8,62f0f78b,24208780,4d5827c0,f5e09efb,c66098e3,1f5d1587,10a3799c,b4f980c0,18cf4ed4,534e49f0,6d057059,93d52fb7) -,S(16eddf0a,11a6f2f2,df230de2,f78b4cf0,980138b2,3ab196ee,361486c5,7a5172ad,e3db358f,ed8ab3c1,9204a792,6102c420,1327bdb4,fb81718b,b39a0ce2,b5992684) -,S(7c9f7831,2298d96b,65e6b7c1,2315379,3df7001a,79cb080e,af6829d3,2b8995f1,2037cc3c,90e3a0f1,b242018f,c53cb32e,b2481dd1,bbb700e4,a6019546,edf51e5c) -,S(129c2d46,1dbeb8f6,c1b913a5,b2d69602,63aee7e9,530c6dee,21168b16,6198fb1c,29ffeeb9,61c027f9,a2a14b72,a287d566,7bbd80bf,7cea0dc1,747ac25f,55137964) -,S(8be2e565,30d4932e,f6d1f9da,a3225b52,de204927,e0633b12,570a049c,1f6175aa,364b4e87,1a130cd1,40007056,e3c0951f,fabfe4bd,6a687404,23cc1800,505510c8) -,S(40b43f08,42ae9c67,ab0ceb62,453b4c41,42a6e12e,5f880c5e,27c90997,6252fa6c,6d1ac6c5,de1b2e5b,b225e46f,2c5a2d2c,248f11fe,d123ecca,4432a04b,cea2068f) -,S(47e2238a,2f34df3,cf1caa55,93c49db5,4c2cba9b,e3724f17,87473a0,5ac669df,4d04cfa2,3ee255f,eca104a3,60a52f7c,acfc6127,608dd908,9399be82,9cf31f3a) -,S(17286c55,3a45c6da,b4843323,84c565d7,b3de474b,5df8ed60,7c7a5c9e,e1cfc35a,6172d347,75a45151,60b104b2,79543107,5b194d24,793340cf,6d8723c9,6320007f) -,S(3451af9d,3c1492ca,d090bd34,45632ac5,a3e96c9,4d9ed258,b7fb2042,8dd7bb31,dd493383,21236e06,e7284fd7,84c1a3b0,7687c513,927cc79a,cc5f8b41,b14974d6) -,S(b00aa481,eccc5e7f,cb5bee2d,a6e0ac44,ed9afa3a,5b2a9619,d23d0252,14e5ce2,687b486,1f0032ce,f42ceb7,441f81fa,10d732a9,e7e76242,4a2ca8fb,e88866a1) -,S(53ec8e9c,c75bc91f,f248a239,34d735b2,ef706d4,c0761e2f,a8a55c7e,a0b23311,1b11dfc0,63c4b1ed,1b5104e0,15d5c5a8,c352f54b,9fd82768,8b5104f6,45d45919) -,S(1ecde1b3,9c072c9a,3b3eddd8,d71e3383,2fc80d78,7abb70a4,cdc9186c,a5efab66,4f5aec7,5a799762,b70cecb1,82049cd0,239f0c30,948a25f3,daae0bc,ae6dd626) -,S(1fe2fc3,702b558c,7ab9b479,fa08efa5,1e90239d,677052e6,5afc8754,9bb1394e,f6b586ae,3a395d3a,c216df2b,66d48fe6,11a64c0c,8a7db26d,30fbd720,c6845c2c) -,S(b53d0b2f,b8ac2ad5,582ba0c2,f031c7b,76e64cc5,28a5b9ba,872718b1,e06d5dec,8984e589,51ab87aa,64bb034c,17d23252,4101577,9476887b,351f034e,92e3a289) -,S(54e516,3bc2366,673fe5d8,1f335d81,a06ca310,a2116ea7,bc0ade12,8f37cf95,f471c826,9deb2c2b,f1b7206d,6e817355,9236607a,4b9930b4,c5b3a781,7312bd4a) -,S(e7efb772,a1d423a2,d39e2224,4c8bab91,3b8087ac,65d51f59,8c4db283,67b29a7b,f2dfb586,31d08b0,bf2b47f4,17f6a18f,704a39a0,a152e3bd,587e45c7,93a9b6e7) -,S(5ec59daa,e8a263a8,2afb4309,79ef0321,b163f2a,dc083e67,3446b98,d0b519fe,2eab4cc3,6a3deae5,30dc6aab,94e5584f,a8a5316f,5c05b04e,84215ea8,79ef82b9) -,S(427b5cd9,20589dfb,dae975c8,efc1f098,1119f69,c40d1216,58ccb903,d4bb62f5,d055e6e3,b8794842,4162803c,35fca878,6500b5a3,6871b18,d9846866,56d1213d) -,S(54954b15,fc594f3d,8f422c7,9dd42cb8,2cc30dd8,c0d10736,554844ef,9d05bcad,86a7cc65,73569c20,2aff8e04,21a00e4a,9c6b88f5,ebcc3975,64b4734c,f735373a) -,S(ff6f8f8d,23670fbf,2a1aa7b3,39568653,573eb480,67a2a1f0,1b55a1e6,b1f32559,7a53f1a6,c7cabc57,d731552f,9fd9447,36cd33f4,3f8f57cd,2d4ac1dc,1ac7e218) -,S(74d725e9,9021c210,e82d852f,41e0cb8a,3bba8efb,8a01552b,8420c265,958a2381,4ee69646,aa9f70bb,883d6ca4,e1016dd9,92f18de6,26ca27c,aeb5854,f5bb2bb0) -,S(e9439f7e,fc0342c9,c2d68fbb,c58d85d9,feca0570,d77448d7,6d3c3251,e49c845b,27da0d98,1b7e257a,eee90b45,9d0d7065,566667e7,a9287592,2031be02,3e233916) -,S(9684a48d,81a60856,6dd26622,b3ffd133,5facb32,9f2c4f1e,2c055cb0,a5c0b911,92038ad2,50adfbaa,5d587c31,f5e7b4e7,294bbd25,e7af1816,1be3532b,f24e68b2) -,S(1d003af9,469e26e,c7f0f121,4dc58728,9e4cf837,5f9d19b4,16277c97,1a0e7609,99c7c3a5,30822c72,b31dad8,146d2604,ed795f1a,7c37e139,c84afe9e,f71e5123) -,S(f96468f8,73cfaab7,76c32fa5,89f72c09,d680abf,c601642d,1c649ca,e197a149,1ffb4bc4,8495d31,b24a7ff3,353857e3,b6708186,c18936e9,9793e4d4,fa083b1d) -,S(b6ad4106,e30294d2,bcac86a2,131150bf,d93c14f6,51ec65f5,32904412,b3f89d32,19a366a6,74279641,d055201c,c4c42b43,4fa40792,90c1c3ee,5db2a4e6,38d228ce) -,S(875472f7,190bf305,9120fec3,ebb69fb2,2d47828,6cb1c108,a977e7cf,e45b9b9a,1adeffc5,f5dc59ad,e15d163a,95f8049f,a172d8e,30544562,50a7898,55a97c21) -,S(5445a9fa,f4245414,e64f7ae2,a1cb1b1f,54bb6fd5,af4a7407,4d9eeb05,9a27a670,496c5207,7da2e082,3e48978c,a3fb7a1d,3bdf07ea,61fde94c,e87741c4,e9418018) -,S(dae18625,704bac88,51f35026,7856830f,74d3a8f9,7c1f662b,f4c4cc3d,7814d138,abc059fd,7ba90619,83988ee6,35ec835f,c20f62fb,c68e2bff,373bda91,3be6f87) -,S(8a088f12,e8523de5,c7ce659c,107e1929,3d009b81,1fe94d02,deeca893,9d9845c9,4251212a,fb8ebb76,5d2d703c,bc18b208,41f8df47,fc5e44ba,ef7b0f76,7e29114a) -,S(d78f46a8,8f3b08d1,334ed25c,78f57910,716755cf,2bceaf6e,c25b52e4,d7af6d01,eb1855f2,29cb2010,f20b3f01,9cbf1b2d,929046d3,242446ee,5c9526ef,5b06f44d) -,S(1e0b4312,78ae0e27,5e55c4ca,cfefcdd6,f589809c,6faaefa8,3ec0d5c5,f99b034b,f38c53c5,544d3ab4,2ebd74ed,b8348503,fb523fae,9d73657,8bba2881,904918a7) -,S(f03155b2,9edb119c,f411f14,4a588f34,ab02d7f7,c415638,cd534465,ed7cbbd1,72d153e3,ff4fff14,b41d07cd,31960565,31736749,7f9c6495,599d3f06,b8e85813) -,S(f61fd68,3edc7fb4,d14c84fe,3416654b,8df66578,6d0bab41,53a96e39,e5de4c8e,952db567,cf0913b1,885d6884,d260fe4e,e11fc139,f58da12f,d38472e3,d42e5f92) -,S(78310e7a,29e437b2,5cb00e3b,13a4d86e,1ede6d8,4b1f344d,7ee9c7f7,e017dd77,26ff358a,4d5629e0,4c20f700,97c202d4,7030bd3f,43134a51,a7d101b6,e182f2d2) -,S(63ae8c4d,6b7329cb,a61509c2,d0b61ebf,4e6ac94b,c8a096b9,7a4027e1,1f781a3a,a8e954cf,bf407857,d19629cb,338a93a1,af16c929,ef8b96ce,2e483e95,dcd14f88) -,S(948d592a,594b354e,e2d03961,6338574c,ae662f26,ff79afa9,16579725,7cca739,37ff98e2,5ea0396e,89d3992f,773bd6d5,ce02758a,4ee25557,edc867b,2f1876c) -,S(653cf16f,a3140368,50b04de1,8bfee880,660a4161,4dc67a55,398e2d34,46100f45,acaaaede,5ff1e552,6766741a,ee43105b,ea4d3419,3e615c36,49c1db35,125a9202) -,S(46fb6882,8a5edc8b,f24fd1ee,e6a7789,141e1888,64508d2a,f3c511ff,8e8cc782,9d4ae53f,d52ce9bd,6ac9ff4a,e82c2e36,f4d26698,47ec90cf,ef383e01,37fd8887) -,S(5f11a0c7,23ea2a71,7c1face2,b4b0f28a,4ca44208,7a2ae0ea,e24c2005,7138c0ed,5ecaec84,ad97612f,ba7925dd,f126e4e6,3906eacf,6f991d5,bb273316,b80c8452) -,S(b9f49e1c,929bef7a,6d6b6b3b,deb10890,dbf2ba3b,3eba62c0,320bdc84,c2a9039f,98729e76,7e4f8b7b,bd0ecc1c,534aa030,6e1b684c,6f42d15c,2bf6820c,b501e558) -,S(ec8a102,e7d2905f,f273eea7,6c9a4608,965dc2b0,3631d2dc,63c38e72,15ade2c3,d8c899e7,242d96cb,49383686,8f671612,706ffe5c,368ccb6d,be5a3edc,f74371c0) -,S(107f02b3,c351805a,6c92a3c7,742a5259,582c5b0,39cf6daf,cdace604,2be236c6,517236bf,1ab47601,57d74685,8dc724a7,c5c2d55e,82c4a3e,685f389c,a99bfb9f) -,S(f0fb14a1,a5c1c016,d7b8c1fe,a8317872,b10d637a,daf6f6cf,b9860653,56298971,e1d9ed14,d33e65d,4258e87c,7280001c,c40b89ff,b3164337,92fbc547,964540d1) -,S(a5371adb,ea784ede,f6cce83c,ebde068,78a1c80a,ff83b47a,333f9b35,44489459,f5780572,127f5d74,773acbe7,b2a22cbc,7e3d09bc,ccd13edd,48ece3f2,c8129224) -,S(3c031e5e,1b0ba576,13c10971,5fa7d92e,2bbbb817,9603d3b9,99e4fadf,be17300d,d275a3fb,392036dd,474e65a2,cd7b6cc4,79cb40d7,1c363e6b,bf9c272e,ae9c83f3) -,S(87b5899e,685db530,a0969a68,9392080d,f8a1b9ae,523ce18b,2171c69c,5a5318f,6ae3204,e3f0afa5,a2d40b01,a42e84d1,1b1166fa,f99cec08,1f5af48f,fda775d4) -,S(d9f077dd,c002c16d,f9d8eedb,56b7e7b1,ea00d04e,3fe838dd,2ae40501,9b8bf74,6518d51e,503118e2,53cfc486,f70cb9ee,11c27302,ee5512f2,78f21265,af3ffeaf) -,S(9c09ab63,8d15acc9,609ce305,32277f63,7558a492,aefb98e,c9bc721c,f8921af7,b2cac58d,535abc10,8bed6ab3,165225f1,bf2f84a,9fbdf3d9,1caa4b79,e0f6fc) -,S(6ed1ef8b,4c2d9232,5cf8948a,5c369a24,52ab250d,ed0e48ae,1676dc73,9a8a7fc0,c1b7a08c,2cfe5154,fca74136,863da75a,5c6423bc,1c904585,f54ac87e,f6742008) -,S(882e8d70,154b7f6c,279f71c1,e2ba6087,cfc458a9,3079d8f1,3fbd3be2,506928d1,8949b22e,97c41872,9094ac62,e67ac1f2,8b31565,edbb3d1d,9b23a73a,6fe64131) -,S(708472a0,24c86ea0,7119d0af,b2509814,516840e9,fc23246a,a6da139f,b37aba52,9809b7a5,1d551532,a5b378d6,594a3665,3a8b057b,80cd530d,b7a53fbb,128fe5ac) -,S(3a44fad5,9a8b708,4ada1250,d8d08353,769d573d,71a225eb,d87a8cc3,af9fac3e,f29f4551,1250d0d0,a1974bf8,46124813,f9186e45,2d3c5c85,cb0c69fb,4b7f20cd) -,S(a3519dd8,e09e1bd4,160564c0,41c23362,36ba4c84,5899f90a,fcc370b3,cdfb9f30,64cff159,7c910711,d0199faa,6c74d08e,7150088e,34fce674,72dd3ec6,1b881d7e) -,S(5af16ce3,765f5c96,4eb3513f,19d99ff2,bea1affa,d68f829,1c4f0767,5cfcf1dc,864eb5,3bd711ed,4a842db6,b0164a78,511ff7b8,a87aa3dc,1f2402eb,a3815daa) -,S(1ff9a522,19cae5c2,5de1ec08,2641040,18848bd1,37a5949b,4021c2d0,563d54a8,546d634c,122276e1,b5cfb919,a5374309,8f85d7dc,149b14d4,791c83b0,1718e031) -,S(d7a6dcad,72a51ed8,f84926eb,cfab368c,7f02fcdc,aa66482a,c6b6dd6f,43d3e938,9a273cd6,3ea6ac86,5a68f378,e4466ae9,8598a058,6c97278,bde63b22,14e41c96) -,S(154f63e5,5bdccc7d,a696dfb5,2b6cd4c6,3c874b93,1f221282,3f4a8d19,1f32d797,e98f9722,17bca1c8,ea7269b0,d2aa6bc6,f0f29d7d,b340c67a,2df59135,77f76fae) -,S(f6ade08b,8513615c,ccd29095,c21bbdea,dbdbb7da,87ce9991,c27ec758,4c399bf1,98c81be0,19fccaba,131af074,b28a6311,3fc1c5ca,1318e96a,f037ad33,8f234ad1) -,S(9661cec0,3b2715f6,c6d29048,65fec2bc,b786b3f6,943a883a,3e51cb2c,c747637e,eaa1f7d9,9b34104b,74a8056a,9ec739f,cb9c3735,95f0b254,7fe75620,4f5358bf) -,S(e0a5323a,27d608c7,34c03465,f03705c3,480520cc,f5ac777f,53d498b4,655d19a1,1f727d78,a8b8c562,ebc60679,8462975f,63d88eb5,8e7cbaee,836bd629,260cc606) -,S(bab82efd,4646f2,f281980d,5250c6af,8206e95,dece4118,c24ce31d,282f6409,2a60b1dc,26a20126,8df8375a,5656c55f,cafbdbbb,46b7977d,137cd584,8d1fb82a) -,S(389e1399,ebbe958b,1806e9b3,ee51baef,2d7edd20,79e6a2c2,21e814ad,e1eb2631,6c158633,1f3cfe45,9e71fb4d,112a624c,e48adabd,435e6fd5,2c9459f6,ce9ae2be) -,S(b78179ca,c0dc553d,19f08174,7fa4511d,87d8961,1ba44045,8c307727,729d4515,7020be98,c496a50,6e4caa5a,94577d71,ce0a80c9,bb974c97,a6892351,e83e0de2) -,S(867ecd3d,d170f9a7,123d13fc,fd90058e,baa6a6f4,12ecadc9,f1e14d55,ff104306,3c0db3e1,bb91ee23,8fb27689,79f2b543,d698c5e2,fde48dc9,e2535e4a,946759bb) -,S(be71654c,26a1025d,41fd4d08,384b2ccb,db25bb2b,c15704e5,697be2f6,d4eecd38,316ed20f,c37a2dc7,a0af8d18,e4da0efd,2dcdaee4,44b2c1df,cdfaf6af,49406afa) -,S(5a8e1cb0,24d62685,e755b9a2,ad1e0165,41690544,7963dfda,6b6deba9,76e9079c,4c793173,743330de,7a8f4351,68dde95e,3889db2a,91de0a27,d088a222,f11ebba7) -,S(3bfad00b,2347bd0c,f13a761a,d0630453,bb884d0f,ae3d31f8,57216412,b82e6131,ef33c560,94157fec,3f7fe8e6,36d48183,71e3cbab,6f5b0518,96ebdb42,aa545f61) -,S(2447ede,684dce09,c896c2d2,b5c68cb7,60e02635,3b4f2dc7,428191ef,5d2c1961,ad38a82f,e80f860b,62b39e55,44438242,5ad6cb54,d6e7f377,62427f30,1ef7bfcb) -,S(a5eae321,eeb4b9f8,e8807e49,ba8de764,e7685f07,417c5239,9d857d4,8bcf985d,2acf8aa9,f5c1b7d3,2ad5f523,39e65595,17881d,48a7696e,ed3b1023,ab4def1d) -,S(97de995c,5337d938,3cca5b97,3ab05e8f,dc035e11,5c435251,7e575a,e890b13c,4fb2d969,2e308a29,34c3fb4d,c4dcef50,9202505b,cd891f79,e8f91210,e069e6dd) -,S(b8caf25f,a864918a,f803dad8,d0abdf95,25b70f44,546b1f3c,c6b1726c,4438f479,7c51b5fa,c0f56eb3,6ffa8c5a,76c074a,c30e2f36,b069ed79,23663da,c9c05c9) -,S(b5bc868c,1b96e2a1,b24f3001,af140107,b2cade8a,5b1f3443,44521764,ad07b2e6,8d6cfe29,4e929f33,d5aaa456,f545c33b,672a8c07,b214a6f2,38bba367,4938d639) -,S(5f51587c,242a3b22,10db666b,f2414c28,32ea2662,1f13f6e9,784a8a1,373ff602,2c3b260f,ebf20a4e,b853950f,99ccbb9f,1b39418a,66adb427,f5886944,8b46c858) -,S(1d0be0f9,5009a2b5,12a52e17,e044f3f7,4f08e695,60d0dfeb,822b4674,7a2bcfde,c3a82bc3,dbd81877,3783181c,f7b81ddb,a742c3b2,4f866538,9335ce4d,8f3a159b) -,S(3ef0ec28,b8003331,a6621bcd,6ce30ed2,9e0e62d5,b492592c,cecaf4bc,8d22fb8a,fe2c84ad,77d40e86,c92a03da,e43cc7f7,512fd363,98db0133,7d929ba7,a144b16d) -,S(84c29a24,a4ec04da,c76bef42,732a3648,f62f12b0,e7f0ead3,2ef9649,b7555fc5,e7620ebb,283a54a7,10eb454c,f22e49fb,929ec453,38e457ec,b18a7f0a,794f970e) -,S(6bba6634,e75d5fe9,21f40f4e,5f1c177b,a309cd73,107f1e9,28331573,eacf43a8,33ffe08c,42168243,1f086b44,12209c56,5b47fdea,54671a97,9d86be36,fb421582) -,S(13b67af0,51b0c01b,c49a6046,d9e5b6ea,488f6298,9559dbfa,47cf1674,6def0150,d0e8914b,1c1bf0b,5337cc35,d84acacb,a54add59,2321509e,e29f1d93,a0237608) -,S(161221bf,b5dcb62a,ebeabc94,6ccc4a26,fdf779cb,63640720,2c5cf13e,93af9300,d3fde2c5,dd9d6df8,70a66bd3,2b5213c,d1a212db,61aec7b7,2a49b7e9,2cf83b2c) -,S(30c5360c,c62f5846,3af60277,2b52201,7eda1fbf,866dc3d3,9a590bf8,e2eb508b,c8e91af5,9b9a2b,8837dbe8,edeac615,6c30e8c0,1b7679f0,1aab4a81,cac44efe) -,S(c0659a7f,dd9151f5,ea67f38b,7249727e,640364f0,87371007,a38b800b,ec3576,a6f648cb,6fa131c3,5458b5a7,77440361,8c57faae,1ca33ded,648f1601,a5cf47e3) -,S(3215224d,b795a892,446472a,8e1ab1cb,7d50fe95,a6844be,43e2787f,2679386,25750662,97f28d86,690c7eb5,92cffc5f,faba831b,efc3e38c,c5e501f9,358a9bf0) -,S(257654e2,a87a7048,3bd15445,da5c554f,fe776264,998975b3,b19a68a1,a1871145,fcb9319d,c67f14f,9d7fc4ee,fca05b18,9efe2430,96691043,9c28c88d,32636ec5) -,S(a4786a01,e504f154,f3d7926e,6e6908a8,17c8a66d,6db33e80,ce98b17,82f1b49,576e4d42,fc2e4f9f,e81a2967,8b7cfa7a,7f86e8e2,662afbfd,b028612,d323a2fc) -,S(5140f7a9,260c9856,4493ae62,a8af369c,90b484f7,e82e1e38,3c5a59a6,62db1e71,4e5172c2,b0879dfb,63a6aa92,cebf9153,94ddcdc0,985261fe,2f64714d,350bae86) -,S(f559d60c,f0f50b7,9c7d6d90,18a579d7,b781fe13,5210d342,31e6cf32,4ca66dfc,12d9ceae,8e5852a5,ca95fb56,abda8e42,5f1f05dc,ca29e08e,2052bab0,8d4eed15) -,S(88907ff5,fa2d01b,c970e0be,53a05354,a4fb73df,9a337857,cc869a1,b0547e7c,f5853b56,cc1211b6,427145f2,6fca6aaa,5b26401b,c00db73d,ab9157b9,7fa3d2f5) -,S(cc1e4bf6,4541506d,8e91fba3,1e1d8ffb,c8ac82f2,4def27ec,fe4b3ea6,e58c45ca,7617497d,a875183c,684585a6,306956d,1efcf1db,2753fb77,5902a63f,38d27592) -,S(7ee2c437,ef744210,5b6a6f9e,f1edde01,6c39557c,93454dd4,eca10daa,cbca99d5,21754734,5eeff5d9,f30503f6,9515da57,3e6d7b70,dbdee5b1,8274968f,6f3772d6) -,S(72feea2,39f9b4a9,a3f3af3e,f6bf420c,3605ba4b,b42da90f,6539e05e,33e2465c,a036ff,df7adedd,c8c2ad9a,d029428c,85482cd1,6b0cd20a,36d2aed9,e9f553cc) -,S(363da33e,94a0dd00,669b627c,4d7a3a6f,c8a0cbae,2641707c,938c8f5e,99914a,9bda9a77,ef1307a4,e236099,c1506f47,a2f936dc,d478b59c,3d0e98c0,7af58bd9) -,S(76540864,c8394290,9af4a48b,bbe05fdf,93af0f8d,1ec9b6e1,a7e91860,f2c133fe,f06923d7,738ceb02,2213a236,daf3d6f1,b3cc98f5,a5ed4845,83ce5c3e,54a3ecc2) -,S(573f0821,7a318a9f,8bd945c1,62e9a4a2,51e38189,34709606,c94cb401,f2b239c4,7e78e4f2,7de69e4b,948b105f,ec3ebd14,496cc128,d7c73fbe,7ca1d53a,b746bef5) -,S(8537981,89234b93,b5009656,f57e5ed6,f90d2184,819a5467,213a934e,22b01f5f,c94a79e8,cc990998,e1c69bbe,89ccefa2,9281fc0e,c99fa820,ed26f01f,62e475f8) -,S(53388512,29890336,3b1ccd4c,1cf0ed85,6f00a30c,78004512,57f6132c,edeb6041,d56e2a52,f856d1b9,a4f8feac,dbc9a844,dd22f55,469bf722,fd78b44b,6983334e) -,S(41ede48a,750ef7b6,5c49f913,afb98961,c5cb478c,39c4c85,2f33aaae,b0e4796d,d74c7bf9,4b6c4680,18892ea7,f04b53c9,4bdfe9c,d1a4c65b,8de2409c,32559de4) -,S(97e931f3,6596f736,992eece4,eed6a9df,fe762139,3acffeef,b6dd3b53,e5f08148,3da89933,53b9c52a,9e76ce7,7404fba4,39a24614,b62d42c0,9b660e2a,14dd5f1b) -,S(4caf4eea,3ca8b104,39847633,5252b37b,5c55b664,cc4979a5,4db00937,b222579d,c266732,a93bdc0,7cf88580,771d58a3,45a19100,4c0d1464,62171cd6,291607bb) -,S(857c1e90,5b3483c3,3ab24ee4,e51e3839,b52960f8,21a8706b,b7ea7c84,9e7b1ca4,8d6e9d0c,7a578771,b358380c,4a2e6bc5,1c6b09fd,e9b40c01,be5915ba,fe69dd80) -,S(410ef70b,e0dbf7ad,a68fc124,8dcba3cb,10ec39a4,9686b22c,1e7ed2c1,bcb5a182,d26e9ea3,331a56f5,cef074ae,e0b4a5c0,e6925d79,808ffdb3,b7cb9423,247f9e94) -,S(8caf87a8,c831eb10,817e5ec3,7aa431a,89dff6f9,a7e63f7a,30710419,5751029f,3f0bd6e1,c8dda6c3,c8e65ba0,7c3a4649,13aad207,3c5da058,bfe90872,67c8890a) -,S(eedee2cf,e92d2483,54a6a8a3,9d314fb1,b35ca18b,ffb9b779,8c16d5fa,fef10e8e,cb515ab0,21f0befe,4b31181f,3f9ce1dc,9fcd12c9,6793d624,c1eb35aa,e514c4c3) -,S(8cbf7ac7,1e77b7f7,7bad6a4e,9116db52,48bb2a75,744d4312,f02eecaf,2aebcee1,765c4b31,f67b26b5,3d17f97c,30d09636,b6f6697f,db6b799,169a2c05,779b7320) -,S(70cd45b4,cd449aaf,34ff0627,f0e01122,715dc6cb,98642dfc,c19fc672,54995db2,82e59456,761497b1,84320eac,3ada16c6,ee184ad9,10b60c41,20f0c538,2f535c8e) -,S(cfe217f9,783fcfd9,1e79d558,e37bec3f,50e5146,e0f442ea,702fdfb,6c7c45d5,537cbd0e,86453fbf,c57d70d8,78c7c3ac,da225186,17bb4dfc,7b6f7079,95c419d5) -,S(9826c0df,6486bb8e,2bf3d4f7,4cfafa71,ccabd2cb,12bf317e,651790f,48579d52,3dbf3586,f86d6253,d3749c05,2fc36d16,ae3bb457,8d4eeda7,34f172dd,b9c57342) -,S(ea18fcef,381b4bc2,c6b3fa3e,3744e9c4,a13e13df,576c8e74,d0f4f596,e28a02c4,c3e6bf9d,2bc445d7,87103c7f,e595a30a,41c9aa4,c41d1874,d7ffe69f,ee09f397) -,S(6de2c465,c09d5a54,61c618be,c9c16ffa,21b82e5d,673033a0,e88cf90c,fe6d8f4a,367acbd2,8950882b,428a8199,d3b21f5b,e1c4ccb0,3280bf5d,28b65cf2,bc4ee2ba) -,S(d6286e13,ee10c7d4,5ae50f80,3d1a5417,cecc9c68,9efd2847,6ffa73f,1a183f4e,7ab92bb7,55204e89,c7e3ca41,1c829e41,e965ab93,57db88ad,37f13e93,6aa56f56) -,S(7526e6fa,ea67460a,25525962,fdb6f209,73f0c861,ef3c364d,fce83df7,23c3bf58,2c76a8e0,d5a8611b,d3274411,cb323751,25a21fac,12e35ae8,f008f48c,18e3a674) -,S(fccaaada,56d64a3d,6d1d5d89,719f51f6,e737c803,893e8b2a,b785070f,8879308d,8262c566,3facf792,efd750ef,a969fab9,a2ee95d3,fe6e7d7d,8685c6a8,479362d1) -,S(b60d13b8,eb8a5f43,cc448379,7a397847,bd6d91a8,b3a6888a,fef4b115,59b57fe3,abf73ebe,5d2b8585,76104acb,ec885f1f,8405b053,3755b8ae,94ecf838,60ebaa54) -,S(332d4b0f,4a0dd872,ffd6d2c1,4379f925,4250fd66,dfaa2d90,127e6ce8,c377f8be,37f3143,47c2350b,f4333d7d,9e0b17eb,110dfacd,d87ce354,b7887cf3,1bc6232b) -,S(e99b2ee6,2ce6d633,1e0e880,37bd138e,5d021620,b555b94e,52def87b,4cc5788f,c9ea06fe,dabcca9f,6df1df26,8bb3e550,e2858dc2,b91a7c6d,2c048416,4e5546bc) -,S(89ead438,2a977aee,7fe692a1,d7199bdc,5af24191,e80573b1,dfb056dc,49c54353,b572ddce,db2d776c,2a967f70,6b7010ad,7fec43b,ebe5f19c,2de0f9af,d9994ece) -,S(cdad98e,529b413f,b46f6fa,98c74058,4777baff,b090d488,59587b4e,d598268f,d405a95e,543e639,470f10db,821f8786,ceabc281,788b0cac,3efee830,bfed034e) -,S(5096ef41,1cc1332b,e67f69ad,3cc3140a,c269849d,5e0f4f5b,e41290e4,86ee2cc3,7f33869f,ccd4b06b,ed61f312,30a7b3f1,49ef34a6,f2d46bb4,18c45343,73f8268a) -,S(bc0bea70,a0966734,8607253a,2c8be987,8c4d59ed,638ecdbb,8b9f60e2,a4a5be61,e19111ac,3c2b4e0b,4a86129,e6c4c275,54d1ff0,29ddf320,873e20cd,16873b78) -,S(2d166569,ac8f5a08,e0674d3,8aa7d747,b024bb8a,5c8407a7,dc451403,87223ec1,48af1b38,62216a5f,12a7d92d,4eec4e59,445c1587,e22238f7,3dd1bd77,e19a597a) -,S(b8cbcfae,bb8b1150,ddce37b3,26ec77b5,2947cddf,e3cf1d40,f27e8b7f,8145ba30,d5234cab,8b2ad2dc,8630ec02,2868a1e8,ffc2c3fb,cd5f5a05,62b6fddb,34823ca4) -,S(fb396092,563f12f4,ddddb9c0,f1ac19d9,fb2e3ebe,608eea22,7a9aaec6,dc960ee7,65e565df,fda1a394,3d27f661,c2eb01e9,646e88bb,6943953,58c9e62e,c9823c45) -,S(1c6e9d76,b8dcdfa,90625150,db2274b2,f8da06ee,21000225,80affa54,a414b297,706b450d,9ab0b0,5466edcb,bbed8b10,85679fb9,78d74057,607bc2ef,a5666255) -,S(2e043dc1,46ecff0e,6e566b13,d985cecb,77f55a0d,555e0277,dc660351,b9fca1c3,1c4f1ca,f75ceaf0,a051103b,90a7abf,665da500,2aac4e14,28a71e45,726d8398) -,S(5ae17b0c,a1bf8e90,e663ee12,d97d7855,9549f9ee,2d89592c,b4b0bc9a,585f482f,bb0df734,931700bc,73c6966c,1e8e5a77,a71806ad,88d731c7,16f236bc,b4fc8111) -,S(fa8bf342,6a24c3e5,d3c11c46,e75eda94,fca910df,c906a71c,1b08f468,a7caafc4,ca69817c,db07fbd9,e35e6c84,65b3cf05,4e2884f9,e57c0043,5dcada4c,2f5954e2) -,S(2cdff1c1,846dd7f7,b9df67ae,a3f4394d,1e1031b5,de7083cb,f905afb,991a88a4,4bbd724f,3827e42b,7d0530fe,de304711,6ea0d88f,8e564d3b,507ff3e2,ef76f39e) -,S(6fadbc00,55ca49ec,afdf82b2,96504f89,c5bb8291,ca942df9,5f5b3322,9d3b6905,f7671184,33a8326,a56f9472,8c411917,911a3053,f593e868,c06f57ef,54b7df62) -,S(c514695a,2f26aa40,dceb15f5,5d5ea8d2,6f4a1e06,12591fca,2f5a00e4,b8dd0841,5056ba08,2e78b06a,90937567,73fc4ef1,652905b1,16d8fa6e,8005283a,b113266c) -,S(83dcb8d4,93474f85,54c368dd,3e188c11,aad758ee,fdd1f064,66c11e16,cb7ff933,104e5b3d,4e57192,7c67a029,e119e79f,d6ed6fb,e61e288,e9f8bd84,630a53c7) -,S(bc65cf8a,cf9a0b26,43b69089,565f9a9,5f9ae882,2e2b1127,a8bcabb1,fcc8a93f,fdf9716b,a31ddd06,a080ac90,f6699b78,23ff28c1,155a79c3,ae9c292a,14fb2143) -,S(48778fa9,520b12a4,12d74b47,65ad37a2,695e37d6,4070d53c,1e09cbd2,4c9f140b,cdc64805,bec15940,387b4c02,bc51b469,446dd3c5,b2e35b39,fbeca21d,769c373e) -,S(9db2c42c,6a735886,8edc8831,2ed6873f,28077bb5,32d186e8,41f67ddf,a301dc25,e01cb235,ec9db45e,e1193e06,46a325b0,aa0ac5d4,786d0ac8,56990262,bfb3a0dc) -,S(cbcff58f,62bf025a,43a1ef44,256b27ff,37c6c8f,2496d2ae,fb280734,9cf8da6b,4fd99ed5,2da32753,3a9251f,e1e136bd,28f5331b,c1101da2,818de6e5,3bb1896d) -,S(9d520b97,87e68c45,817a12a2,93b1df96,70cbcf3,91788270,93367253,6f4f3639,615e115d,2b539895,d91885ca,a325625,41fec07,9d8fb6bb,22d9ecef,b6bc0f14) -,S(c648ddc4,57c2bc,bc23d182,8cc6d6e,4b0bfd3d,f83b2e7b,3ef6a341,9225dbbd,ac9a863,38dd1966,9bb47e99,e67a3d9d,ec16fe61,dc17ecaf,209a7fbc,518ab3d8) -,S(ae11f835,ea96f767,afde3f1e,79221dee,b80ead29,7b45e29a,7e596461,e82137dc,20453bec,b65a62f2,8996e1b5,f1953acb,4c5dfee5,4e5f9a15,c2a2178e,4c452596) -,S(a35549ad,56f8a64d,d23b9293,d8ef5128,699f6fe,365c0fec,29280d0,a364d46f,c84041cb,a38c9981,3015ffce,17ffece0,8f55a292,3c64868,f11cd6e1,bfbbe75) -,S(75877029,af5575e1,8dbfaef,37dac89a,2aad8308,d473a64,9c347097,e35f8077,843b0497,d19851bb,ed243762,177cc69,603cd674,216cd65b,2e5a85cf,5fc2b8b6) -,S(44ee3168,ca7ffd50,c467b1f6,83e532c1,ae00b9e9,f2eb1ca,917607fb,32d4ea99,10a20ea8,120b5a13,beda9f9a,9110eef,22564e3,9b96c141,1e73eb7f,c92c3270) -,S(9a013c89,8dafaf0b,90678f92,f3bb98c9,461e4595,42cb07d6,477b6f66,7a5337d4,11f8485a,c96623a4,e6c9b773,f5cd9fcb,fec396f1,ff53205e,8774ba1f,da3c2a73) -,S(b45e28a1,44d54182,20819a61,5f50b349,3fa12d17,2b8b5bea,83e73d69,b6b47d5c,d987db83,ccdacd21,dfff1dec,43997253,fb1c2092,95bcae4,5b76c306,92c29f4b) -,S(9e7d6a53,49845888,a8865d07,310192f8,9a659205,1d2a603,cdc03d35,a641a0c9,ca1774ed,ace29fa7,f57e5690,b4d1c0b2,ce5f1fbc,b21fb323,3c001498,54f462d9) -,S(113a1429,be1b613c,567b306d,5805c163,e433a940,8ef14b01,b9afea43,54991f47,225ee5fa,6d26cbb8,49191ec1,a51e385c,321e801,9152a3c7,50014567,7b928697) -,S(32ec8dd1,2cf85df,931e2597,f6b005e9,6d6eb0a6,d0dd7964,77655d71,418d9181,fd718dd0,78b3e4a5,9bef7f4d,9c430764,3423bc05,e1aa22ab,dd7bbb,aff9d8b9) -,S(ada43267,f2cedae4,5e1a5f1,46151f89,b145db70,ef477865,b1218e91,72e9246e,d148bee0,4d1f4d29,f9f15c57,8b047469,16e39686,c2b2ca54,1f3e0d4b,247cf82c) -,S(818a0abe,debd74a6,91fe662b,edba1a52,65f5ca07,2017c6bb,bf7b9847,95bf0cbe,e7b2d06a,1872c73,6988da9b,ce273b7b,ac0f03b,90903bc8,da719ce3,89c0a53) -,S(2f49eb55,ef77da10,804c1a1b,f596f09e,ae76026d,f2d12f14,d80be810,7d0b3c94,6a225810,2f1118,eb689aa1,e6d4ced1,1a79036b,802caffa,5694e383,3e038b83) -,S(7fe54d70,54cb025f,6bef8029,bedbd15e,bf66d5c7,986c678b,a5cc5353,7afaf74a,fdc617ec,72ac6632,6d16afb6,69188554,a47a82fd,db757695,2296c10,b4ad89b0) -,S(84f59366,2b8284a0,c9db8675,db9c55d7,411ec9ba,deec1319,56aa3f75,8eed2689,836e65d9,6bef6ed7,825119c4,c4511c89,48042592,f41eddfe,4de98e83,acd0d88) -,S(c90aa830,1a84820d,e06eb6b7,1ccc9bfc,a46b1612,5e2b5f52,da0a6fb5,4185ee1b,ea86d7c0,b285d82,9331e05c,d99c58a1,cc213449,d9226efb,16135237,f90dc8df) -,S(ffb4d576,abae49be,69f047ef,636142a9,8669b2ad,9cfdcadd,c057d96e,192ef100,3740cd14,b2d5e018,33a700e4,c80f6a8d,3d95966d,a5238120,80a9101b,b7ec6c7a) -,S(408a8d89,67ad6bcc,eb7ebb61,89afefff,12c24b5d,2c33ca3c,8b78fca,cd403de0,3b761fa6,378cc42e,a28fb66f,f1d8171d,4acd3557,fd6313a2,cdcbce47,e1caecf3) -,S(580a33f6,153109db,fdde27e3,f1b0ab04,6c80c04f,18326712,3e3482e8,7c53b787,bb8073c3,fddc81e0,e99ac5ae,69702ff6,f70a33a3,5639add8,1d353c0,e428431a) -,S(2d310a94,7054ccca,c46b1100,88349ad1,4c7860db,38c698c2,505e789f,8344130f,1ea2069c,3c6ec90e,9c11be0a,913d90e,2df1875a,2e26aa9a,5d28dc81,3e3db697) -,S(2874282b,e7b11cad,3f22f2e3,ab835aed,5d82b424,24697b32,985231f8,6a7aa450,286332d,b2e1b922,222e3860,e41d90ba,cf39ce03,21f26b74,cfa23171,f0415c42) -,S(af9e779f,f77bf3a0,10af5e41,82b77981,6940f85b,9530eea4,8b36e401,eb6231cf,9d3d4350,dbaf15c9,269d958b,86d6b88f,4deb7083,ab1ff389,c13f7541,98e84c67) -,S(445edb8d,515ca735,26fd2757,73b2778c,bc93ad8c,a661b35,4471d035,688c1ef3,94917a3c,fde762f8,3b774361,1f36a13e,e94b759a,455382f5,55d64f25,7090dc49) -,S(e010c20a,370d5306,f89993c,f7ec34d1,3e76feba,2b6612aa,dc75012,701811b4,cb45172d,280d9be0,52d57a21,4cb3cc47,798a6426,f215e3ce,e3af64ff,106fd8af) -,S(d34277ca,4625c7e5,b1134080,cfb44cd2,ef548b3b,67bb73f9,eed42352,ae5af8f9,a35f5779,7a628f7e,bb37bd60,9e3f44ee,c391909a,ce27ab44,1ece58c8,d7e4a4df) -,S(be0b9399,3bd54241,b684977f,ea4733e3,d96182c3,c9fb1c5d,d665eeca,cb1d628d,37904353,744ed26a,df76272,8ec41898,13218b0f,5fb09da,dbf5be84,fb7fdb8) -,S(308295f1,ed4a21e9,1ed9f48f,d6b42829,edd9bd34,e812f09d,c3b2c319,fd8f3980,6835c34d,5c360e1a,49a14c31,4ee4cca3,797d434,897c4181,a8ba5d7e,aeac0230) -,S(66cfeb51,61aa879d,fd791604,e10f5fa5,c2e07a5e,66a37b41,2b88db32,dc495b1a,a0e07a9b,f8a2fc01,3e229602,b483bc26,5ffba9c5,fb6ebfe3,f9ff9c9b,3252a1e1) -,S(f42b8fb,849cea70,4cfb3d9d,334a4a11,bf7b3aef,9b55f648,ec885a2d,6fe39ba4,b60621e2,a36d4aff,9f75db65,dd381ae1,f5b0fb4a,bc9f19a7,36d160a,61e8b22f) -,S(429c1785,22906323,2ecfdc46,2666f8f4,c57b7fda,608cc8e3,85a31254,bfab034f,e190ba59,1a868f57,40bbfcb0,481aa04e,50b3969e,abc941f1,8e69816b,2962af35) -,S(c8939d7c,94789a0c,b95e4237,fb378ee4,9895b985,6fc67d7d,fafdf7b8,debf611,143aff62,6e94617,c36d05e2,3062d2d4,47feb77e,9b15e2b0,4370f81f,1cad3682) -,S(5e4155bf,56303243,24e15ae4,142ad81e,2b82aeb7,8dc3ccfb,1d36f3cc,4398ef94,6801f527,2325a3b9,a9f3807f,216d7425,b9083364,203f3b75,ed6f4ff5,eb5da55a) -,S(1196b198,53f093be,7bbfa851,a7114e23,eb01c530,6078965b,5e9dbd3f,8d1b573,794cf0,54bfee20,d80dea44,d183db44,fe79dced,fef0a97e,5c557fd2,bc628795) -,S(d818d920,74bb737b,7db8fcd0,168030e3,39803e5f,6b76ba1d,ea836ed2,c73a6094,6ac7dbb5,1f63118a,80cd2aac,fb5f086e,ff15d51b,fb4ccafe,9d96f179,176e504) -,S(c0276b4b,f5ccabe9,ed9a433e,eae5c989,7039042d,b273ed88,51db464f,b06c6204,489270ae,6349ac81,d481a582,a8581520,972593d4,9b3facc5,fd52efca,24f4756b) -,S(94b2a1c,ca23cd30,eb9b300b,43d0b24a,b898906,1c4d8a7a,d3343d7,cdd83307,47c5ed56,b709bdca,5b960801,58338b9e,e6e74683,99a50640,6075302f,9e481df1) -,S(f2aee379,df2bf54e,e4a1c385,c28fb64,9f157d2b,d345995a,66868876,ae7d5108,ae766bae,9c90a1f9,c9079d35,1676eefb,19a7bf8f,bd56a311,13f2dd56,35c8ef08) -,S(fc8fe44f,3dbdc4b2,afa9cd04,3601c6a9,e81e4da0,456ce222,8306bb85,ba9833ad,6a321b78,a98f52d7,64330a52,ea5082b9,2b07655e,ce8c5094,ce307538,6d56fe15) -,S(d38cdd79,19a4f3cb,fbdaa3eb,e2ddc10d,7444d04b,5830eb7c,5b8b464e,4c255c14,6a0f1ef1,823a2fdb,94a311fe,cdaebe7,e1904095,1ddaae6f,1a565551,2c8c15fa) -,S(ac02e6f6,13d8690,d0c71943,a26b5e9f,916ea119,d7773f4c,14247538,9a4b41f,eadc499e,436b4eab,bed9c5e7,68fd2f67,72659819,437708f3,99531ba6,c05ea2b1) -,S(3948b1a,c36bd462,ac7b5cd0,7076f9ce,dc6d1a75,1ff65177,d7d9b701,d06419c8,ca91fceb,a01c03c7,ab141ea7,1cceb61f,72d5d18e,77964bd2,732bb95d,191765ba) -,S(4c7dbc8d,21d600da,6dd4c0c2,cffd8842,ea9e73d0,5dbcb554,35e31971,7e706e9a,86a77f44,b87b7abd,29c2f412,97f7e859,6db46ebd,8cdb442d,35dc17f5,278230fe) -,S(75228daa,b3825e2d,9f8c2f7,a0743b0d,b7dec731,d9df5e06,98ee11e4,8244f623,963c2987,e122f107,dba37bdf,ed282ea4,75e33665,260a5aa4,51021a88,780a1676) -,S(aa3a86b3,2ed2161f,8f6ea92c,71b7a47a,b584a73f,102c0147,632d2c2b,e80a579,b8fe249d,2b4ec64f,dd345d3,210244d7,f7e517ff,7722c2ab,bc4601ad,ae4e6cb7) -,S(702b912d,9828039d,a58b992f,7d6f3af9,4c03227d,3d3c368a,bcfd3164,193f22f7,25892c49,3a32cd78,130a4e14,c714cc7e,b576ccba,396ad36f,71de5c42,c6bac387) -,S(4ca10c88,6d44bfa6,2a221dfc,10c57011,269f703b,8f6f3567,829d3b5c,9c90ba75,3323eab2,9282e358,d4de6f27,72d77db3,95b04a22,7f0374b9,dac3ecfb,4ffde3e7) -,S(1619ea36,30da6972,2caa436,2c174efc,f3601c35,2e946d34,2da56738,92b9c325,22ad140e,13b8679e,a6d88dd6,148ded7b,a1c12697,91c7ede4,b98a72f9,f0e881e) -,S(21dfdc38,18debfb4,9cd409a8,a302f8ac,64d589ba,b65074c6,365bd398,d34d3032,bbbe7ec2,e835204,a786ddcd,bb6026e6,106d193e,21725c45,79eb17ce,784099a9) -,S(60fbe5dd,802f1ab2,cbae99aa,12cce0ef,36a472e,bbb1bd1,c0ddbd40,85069fe1,ea83b59,2dd304d6,82fd07a6,85408f0b,99feb1b2,b78b1316,7f9be524,a7349dc3) -,S(c804b465,fdcdc5bb,a848ee97,559405d3,dd7c2479,4dc4866a,e29676cc,1e147f96,aa4a2eb7,1fd82b70,ebebf43a,9b828e4f,fb10cca2,cf9bb522,3a7eeef2,5badc5a2) -,S(77a6e3e5,51373b55,dc51b338,3c32f6c0,5c74cfbb,3192fb7b,d96d9d3d,d50336d9,21d2326e,86efac71,48e075c1,ffcd573,5de35d6e,3856f2b6,7d358b6b,c6f047f) -,S(86ddc187,4a72eed2,666706ff,26a4ec65,a89d82cf,64e3d8c9,4731d62d,d5f7a5a,51f7cc40,ce45a123,a9217816,ba3e6dcb,40507b5e,4cde95c,443ce5ab,4f0cc29c) -,S(cf49d0f8,db8eeac4,6c108675,a155e327,8c80d5ef,84ea28ce,4a596f3f,c7d3beca,6ffdc741,ebae75c3,ed82dcd6,a6191d68,7cdd64a5,c3146d41,235b96df,420086fc) -,S(1d75ef89,57eb6722,2d60e872,1e126cec,c9f5c851,5fe18381,518cb54,b75875f4,82c5dfdd,9288561d,dbe4ae2f,5fa1d429,c2076625,7765b3e3,7b99dc66,b78dbdb4) -,S(bea4b735,f62e6122,9d8d9466,69503348,5bb5b7e3,c6ddb6dc,a292ca89,e7ad0689,90e3278a,8ea9e10,e7d9a451,7b7c01f2,7cda5836,f52a011c,d8e20ad3,7a08901) -,S(e85b0ade,a90e5170,18d0aaa2,75d5989e,577f5cf0,b3acb728,1af396a9,6169f2bb,d42970cd,3ca175c6,3916fec5,757b7f5a,30ef1269,d4083358,667f599,e650aaa8) -,S(d97592dd,24050526,e41ed550,fcf7cc2c,82ca5584,c0228f5e,3ffe42d8,a3928934,eac6c169,6bf01c3b,759a3852,a0236f4e,4de0db45,26f2d26a,2174dc4e,fe2d102e) -,S(e023ea4,50b620e2,378e60a9,a8c65778,fd772575,5aeb53eb,edd35ee1,666e00e7,4e4ed850,6dbdcf89,b060f0e7,8915f506,6bdd544c,e37e1e30,6a966353,6894797e) -,S(615b5c95,5cd4fd6e,a581b9f7,e6a857be,a7c0ec2d,c302dc9c,c8304ec2,d935e5a,c221c766,2602325b,bcd845bf,f5d754d9,46fc8074,f36a78d3,6e421b14,fd5f4d46) -,S(b1dfa434,2e12021,b9ce34d6,1391bdb,fa2a0d85,a004985b,c2cc7358,96ec13a7,fa3d115a,8162f828,1dbb7e9b,6f818b4,13c2a5cc,58993ead,d103ef59,9748438e) -,S(b64b601f,afbe47fd,ac675b83,5e4ecdc8,68c7e1ab,32598974,36ba3c9c,bbeada7c,af78c039,d2315746,feb60662,462dbc9a,652ae90d,573487d8,5ea52374,e9dbe68d) -,S(5429d346,fda1d9c8,6c5027d4,e94d7565,b0981f23,52715336,4a0f3264,6bb579cf,5b8ce197,dfecd92e,390754dd,2d74636e,162d6659,51464f37,ac696a32,995b1880) -,S(890694f2,56d6718,b040bb78,1041749c,20e21669,f3787f94,ff954b16,2a6f005b,d966934a,890dbbfc,bb90d7b2,26afd0f8,7bf505b7,31b94df3,5df1c141,2d753341) -,S(3ae75292,cd0526b7,fa6987a0,5fe060c8,269b5d1e,44a2867c,cb92c2b6,743cc117,10959cc1,5a74a82d,8f7d5416,a33256bc,f004eee9,87b82871,d22a2dd5,f2416a94) -,S(9d745a9b,ff717d55,5a353fd5,f1b9fa1d,347bbade,8a4abce9,3bb5dc7f,299b0707,cef338ae,d513c60c,7304f615,ae734de6,10461cff,ade0f69b,bac28e6,7ede8134) -,S(699e9c2c,8130c939,105ce7f4,f922c060,abf1b896,648509f0,aaab9519,d144f166,882b490e,1fb9f944,95d14583,83809d69,bfb7da29,97d244a4,38da39ed,7c3a19cd) -,S(e3a01cc1,dc520509,a91ea704,bcbfe298,ae79b4a5,4f433550,3884a1a7,85591f87,f3c641f3,68d19d57,fca87e54,6ddaf495,2480a891,37490b96,6617fd4,1edcc64e) -,S(5d150dc3,d9df375d,46dd2362,34498514,cc7ccee6,fd8ff5f1,ee5ee38d,6ac433d1,2c091250,d2e2ea0e,7d80263f,18401092,399a83fe,bfadc061,a32316eb,52ab0316) -,S(49fb9761,bb12ba3f,644aea5b,5e011f80,ec477880,58a6eb16,c100c5c2,e0996a66,7134220f,b7208914,58499caf,21654c5c,d9086b1b,92978370,89cfd06,d655e23c) -,S(34c55eb3,a4512dfb,de799021,1adcddc0,bdea055a,1f4f7b13,d530c945,2a44738e,258cc688,beff401f,9a910e26,d0c979e5,fdbb695,323321f2,ba39a4c5,4f98fd16) -,S(7068fcf0,7c3efe00,4ff7b82c,2af0c9cb,9b1c39f2,30dc602a,b2508d42,30a3a98c,e48730d8,844578c5,2e7657bf,202b5df5,2fe50679,7e2e1d77,aaab197a,e37ef1fc) -,S(e1d8910,a987aaa1,12ba1f95,ae8e346e,f49e5254,a2b01909,f73b874f,6b355a1e,8ad0311b,cc4947d8,999c2c14,9fd5c59d,d4a56a20,a0b90235,d7bab907,fe3cdb8) -,S(92509b88,ba8631b,16c6b2d,c60df45c,6bdf06d8,ed4dbd57,c10ac3cb,72d2caf2,3ea47a31,633b6299,a9f95651,b95f1411,ee6f0f33,35ddb8c3,3978af58,746a3ccf) -,S(90fd402a,e8d505e9,96aec994,db7d29a5,6446471e,34dc7512,6a356ac,1a66a519,68c0ff7,bcdc36e0,ada31816,ec4f0e67,9a6dc658,46aaaa62,e1958ba5,bada3b6b) -,S(b380ecb,7d9bca8e,1e35b0dd,d412b128,4cbc77f,c66c5f5,eb390d9f,a9400704,fd2a2092,77d9b783,9df69a7,229d55cd,18fa71db,e1f5f8a7,d78f450c,846a01a4) -,S(40e2e041,aecbb6cf,6f866140,b6149257,f3d029ef,ccf2a752,d3ef7b0,32b83f0c,122710a5,3c83888f,54e26679,417f2329,e1eda641,8e525326,704744c6,bc2291f0) -,S(8e609fc4,3f4e30c9,3893a38e,9aeacceb,7d254eb9,f77b49c8,c99c20a8,aaa03583,947c4c6e,9a821504,7f259a86,b1d70378,837fb57b,e0d696d,66a3dc3,7ac1a3e8) -,S(b871c5b2,2bfe9fd1,6898d00,1af89a8f,8d9c9324,52fce0bb,2ecc0835,f435f5ce,e302e5a3,ecbd0ee9,9f87226b,6f038003,507fe8ee,60b64,cd656f26,8f1d3078) -,S(526daa7e,39e891a,bb524170,96fff4d5,c6f80f57,cce87f83,2ac07cd5,50841682,69f04499,4fb7130e,758fd397,5ad40f68,c477bc9c,cc5c5f43,c5f5a554,b3d210df) -,S(c15c244a,514e3057,ce67cc07,3fb66fa1,5c031f51,8add9ba2,edc12f94,861ad25a,db1021ac,ecc3c897,8de34780,bbc9a8fc,16449ddf,5cb05b90,1ba39598,72846c50) -,S(37e20b19,466a038d,b3b63873,50dd3dc5,d3494876,cdb7f344,3e234173,eac1d388,b80a24,546541e2,ecabcfa2,7db57aba,5ea5bb79,f69ecf25,2d68ef63,fc3b89f0) -,S(6d091f28,feae0142,b311cd81,f57958a5,6a0da5c9,7ff5eab,c598e4fb,564ea528,48bc97f0,4d7ea6c1,38189719,6c85dd22,6e9d9f7c,5a8ba74c,27c29063,fdd07906) -,S(3bdbd416,a76efb56,ed01664f,b819dbfe,d3e545cd,3edd48d3,5ca635e0,bb54fd71,a6954d72,3ed7253f,ef301621,91fbad8f,9a63a893,82b98d26,a6bf36f5,2ceb0639) -,S(cd4e36a9,f111b55f,8c05d41a,4bc33ef0,c4109540,d9871237,4018b2e4,7e9d61ce,478dfa16,52632e69,6ef95ec,452df807,abded9bc,264e6dda,df0c6215,454e3e57) -,S(f23cc4a,9c59c0e,3bf21413,170ac67e,24845771,2e77f1c6,272a9f11,2df24efd,e933bc72,99b6effd,5cf58fc0,72f7a466,dc71cdce,74a3d3da,9ed5e7dc,577fa4b2) -,S(d98c6585,8c97eb35,b6846840,cb6db623,d7a349,435d4989,31a695ad,ed3c33e0,443fea24,ffe8825d,eb6c953c,70627395,ba13781a,164f2eb2,a85b862d,e3114990) -,S(2269daa6,c055dae1,b6d2b9d1,6c74a9bd,65325ddc,a249085f,a946e66b,6c744225,159d01f9,a61f0456,b08f0fe6,a42efdcd,30e14ff3,bb47fdee,2352dc9b,f5bfb3dd) -,S(335044fd,8eea8792,8de3880a,546b01ad,eb4d75b4,23ae7ba4,87740c03,167c48d5,69e503f5,26266bbc,63b0f2bb,757b3be8,cfe1d9c,e63d8226,8187a309,ceda1cc1) -,S(ee7a263d,86f9a83e,54cee87b,7bcae75,a601da9b,637aba50,46bc5f9a,3ff6c512,9fdd3192,203268e9,2388ac1c,840e7635,22271483,161f8f60,42d82909,41373d56) -,S(529b33b3,36f1631b,6c7b6111,ef44a888,bf95f344,766a2d97,6c5e5d5a,53f44245,12856106,93da6f4a,2fabc1a0,3280249f,6f29f9ee,9ccd7000,4cf0a857,ea061099) -,S(f2b3346d,a6cee9f5,1a933718,2d655a88,6a251353,8ebd243d,d3e3cd65,abdf1849,d41df628,be7703fe,9e866526,2f6278d3,55aaefcb,324df2e1,f483b0f7,77b77da3) -,S(535e9dbc,f03d98c6,70d03d04,5d638c7d,1db7a12a,22f3837b,3f559b70,4582befa,2c233228,bad897c5,bd4fa98d,67f8384a,62ea4761,4f64e4e7,40bc1f65,9e358392) -,S(c131688b,70da6ac6,5ee3172d,dff34624,b019bf78,85033970,8253b4a0,b299a7f1,fef187b6,e0e748d9,69a11d82,e9f996f8,d6e1aff,8b84d20,7dd78519,dce5f3cc) -,S(75dc84d3,f7ab7985,10ceddf3,da6bf832,a984d00c,98726a64,5dc71b21,754d3ba9,f5d9edf3,5e110491,2cc5e4d2,82eeaa53,84f62deb,1dc2a183,af5b232a,e3841c50) -,S(591dc7bc,9136c38e,ae727310,25c5fd52,82c6dad7,6f98c648,78847ed4,f32a36c5,fccfa4c4,f81cd382,e003aabb,4cb6c5e8,8d4875b7,21d44233,95397268,d7a421a0) -,S(83a59c89,2a8392ba,e7548fad,b87acf7a,d2c78db6,4c588f0f,b14753ce,12712596,7d00ac1a,33b12065,d67c598,8822ff3c,46f090e3,15cf919b,e3e5030c,e7c5873b) -,S(e9b0dfa5,8c52b2f4,a9c1b8c3,76391eff,6608f968,ec45bfc7,6ca93e2c,ba6f6f83,6449b28d,5846de0d,27489124,feb3f3fb,5c1f0839,a7809be2,e5cb5def,2e0a7c8d) -,S(16cd2f9,67b090c3,d151c002,d3a3d25c,c76adf50,d55a6f81,b1b9a650,b72bc03b,c592601e,2fe77090,39ccc091,bd78458b,a23db74f,848ee06f,50ffe4c6,8ad63a7b) -,S(f347d3fd,1bcde363,69e3d9e2,44d6e5f5,d80b8dba,7b1866b6,f584a38a,3aff1cbe,1c435ab9,ae38a13,98dcfc6d,64125e8,c7349f81,1584fa97,66dc4d24,7e87977a) -,S(5b190d87,d644854c,90c49f11,34921545,f349edd2,b4e9926d,534374cf,da428b1b,8a4eacc3,63efd6bb,5c93ab25,65d2c157,9c1d3176,b2713ea8,56bc97be,fa5401f3) -,S(a7786cb2,d7314ce8,f21e9665,bccacad,c49e78f3,7772c3ab,105f67d6,1c30834f,4fc7acd4,18982e3f,2fb1f911,cb70bfc0,6c4ea71b,a05f6371,46e96bd4,a9441953) -,S(d3654f53,e9071a18,8c5faedd,c0ef3616,abf74d26,f073ddcf,545a01fb,2fbf33cb,a56f20c7,213c0394,5978502f,c4a716f3,77c7a3d9,26c3cde1,880f103b,432f4383) -,S(e1138a87,400acbda,69d8ac3,bb6db4cd,27d03176,ee88994,2039a93,7822399c,f29a8fbf,dd3f6d46,5c640de6,b6853e40,1803cd95,f5e012c,9ce967d5,13a162c1) -,S(d29eb63c,91c0f4e5,b3c49c6,9c9ca952,5714730e,76bb87e7,374ac995,86317708,4ad93702,4e9180a5,9d22ab4a,c856de6a,d9d38c9f,1cb3fdd9,d73aff61,fea5f1a1) -,S(a9d403ba,a6717fd7,6577da1,d8b8ecb3,d2124b30,d18df147,ca48b482,26ee49f8,1eedfe7a,8c5ee1ee,50937bca,d9591144,56f1e49e,db74133f,f45176b7,26d5323b) -,S(ff7b58e8,dbb6055a,eeac6bfd,112d89c9,8d8f3763,98e41e39,ca076bd0,9ef57528,4e4e39d1,ad7a51e7,d6cb57c,836c0685,8e39f1f5,bd41aee6,cf5d250a,fc381121) -,S(43c50a9d,f7839f61,e1b6db23,4e2f146e,1672ea1d,566f5613,1e7bafd1,bd362979,f20fda98,81541a8b,a83e908f,69e05218,1e215885,f60cfbd6,1ada74ea,83f449ae) -,S(f608a9b7,1c91298,75662ae1,6be6d043,5803a9d5,29d3be53,9843f227,174ac30c,5ef364fa,e919dd42,1bad3243,413bb565,d788d266,d7b508f2,83c486a,327ad5bf) -,S(c913e029,dd1ef043,f9bc48d0,c267657,3cc11722,5cdad56,8d013327,445a117e,97573f0b,9c31cbb3,7bdcf07c,13526a04,32a38f18,43e26d8b,ace85a50,19a83049) -,S(aae0c49d,b17e7bc1,66c0c58a,cca847f,61318bb1,3482f63c,ce7dc55c,82a7d728,41170bf3,f68c3dac,22051aae,658cdc0e,810396ff,9d5d9251,6a7e6377,5c6be0b8) -,S(f2805f1f,45a0b622,59b9b15e,3de4a05d,e306c8b5,ebc5ac96,d35aa388,ebc846c8,f5d72739,6ba37244,57725cdd,912fa38,b36e201c,26409dc9,9789d087,6b8d1267) -,S(6969e4e6,e150d12e,4a230e59,37d865a0,f7d2323a,781270d8,7b0a7a90,fa4f39,c71c33d6,d323ed0c,3e77ebe0,8595dc9f,e030a0db,aae16f88,8dab7187,5e14de3a) -,S(aec2bf0,7a0e257a,be4fbdb8,e872dfbe,2aa0643a,411943e3,e4cef039,8d988f3e,d8e9f557,e686c380,c84bc528,fff0a830,bcc3b6a2,724d9df6,ef21d545,c8c931d0) -,S(9c6ff99a,13dfc35c,a502890b,69d91dd5,198f561c,790bf322,6bb243bd,4926f710,2aef920c,84a4f5ad,9d88f541,1ff46839,2f7f4e63,3422b11e,9b683403,f7ef849d) -,S(fa43745b,37a5e238,df0246d6,7eede652,ade75aec,b5dd8aef,afb8e6e0,96d7f1c2,df9d5aa4,2a3c6540,3793c8f3,fef939ee,48aba7f8,59fe9ead,dc44e82d,a98689b1) -,S(694a3288,6c4e26c7,eb3b84d0,9e777f96,ce3b74e,58658741,27643dda,a78d46b9,a54d6c6d,7645e5,6e8909be,922cc5a,a700d932,cb1318b0,1446a9e1,8bdfe67a) -,S(65499597,5be06b28,b4c339a2,b126210d,930fe920,7cc72be4,3d4ad17a,c08f38a0,bdee23bb,467fdce3,2d2cd92c,e81e3f5b,d29fe8b0,8b35abe1,c684443f,72f7900c) -,S(3791c8f6,75bb14e4,b7d4f084,483aec44,ea38eb2,9b108137,400099b0,799f0bd,2dc8f74a,da5e5eb6,f3b96ddb,cbee5ee5,8b2a3f45,c31cb16d,15a4e918,eef7bc76) -,S(d5e41065,eaf890e9,e9046936,acf6a43,59795c7a,1939d8ed,42941a8c,6ef31364,191ec4c8,a559fd4e,7abbb6b8,f2e4c32c,bd2f30cb,d06ff6d,21f156cb,f65bbcad) -,S(16ce2280,fa0b404d,28a29acb,62058b99,e504e6f2,eaaa3ae8,b77ad650,2c970dec,3d4683f4,486addb9,e54bc252,74e590c,b6eaec5e,7f96e9b8,8174b81d,56efb09b) -,S(a6b0ab30,6cdfb1f3,90e5b447,816841b7,e08f997e,d7d47016,bf3b501,c6107d07,2a62842f,b67e2794,92ed337f,d72abc9b,94e96e4,a10f658d,9cb9a4b6,a80abf7a) -,S(d7ca6d38,760b320b,21cb779c,d709f376,52b9d08a,8ff6ad90,21e00628,56033583,d6c05f72,866d59b9,6b91b6cb,b1401619,5e2d1cfa,9982db04,6d672fff,849e7bb5) -,S(78ab0563,2d3f707e,738cb134,7121c73f,e162405d,61a0bef3,75f6cb45,f5609d33,fe1a390c,10c7cb4f,297a4b42,4baa5c50,350eba49,55fb74f2,1094ec5f,ee75a6b0) -,S(c053553a,5b9fe803,65fc5a9,60e48fd9,218e2128,28935879,bd1072c5,180d6f04,e02da774,214dab04,e11c45cf,57be2802,7d0d28dc,51cc08a4,7528869a,3e719192) -,S(bf85d713,e2a995c3,ef98d403,30fc1fb3,5faf8e95,81385b4e,b65d5ebd,23f02d03,a5d45947,58d7b0e1,a8542a6f,21ddd207,dcb68e96,88284bbd,6b940748,b3e59b18) -,S(fb73b6c9,2be578b8,fe2ee0d,eb0aeec0,13816905,9e55031d,69a4d0f1,1bd280a,72ce7893,9bf5a55f,d4430bd2,55bde818,e15bbc98,37e3dcf3,e31d22c5,9614cd16) -,S(56496e5a,ed338dc9,201b04f7,8f4b6c2c,d9928135,83360dfc,1e2f370c,1628aa79,81dbf48a,824fca70,12315d3f,a56d5150,92ffa54,d1300725,86c8a476,be8c2db1) -,S(d698e395,9e81f098,485edcc6,2f2a421a,aecc0a79,58c9f6df,7905c931,b7a2130c,5903debc,e61eaa39,dac01a8e,3e970a39,79408bbe,1d0ffba4,5ce78c9c,79563d27) -,S(84b32e40,86709450,b32ade00,d3404b34,7fad8d7b,9387d931,780764e4,c566ff80,4c80d078,56cc4296,2b7941e3,195c5350,9bb5b0e4,325c24,4aa3a581,bb1cfdc8) -,S(7129c799,2a3689b4,c1873a45,f1ed3327,6528e243,28f30cf0,5ac38a61,8db2ed6,362b4fe8,482125a5,d4d15456,79009aa8,44f86619,cf3fca68,ce38995a,660810e4) -,S(93164c87,fa48b6ea,6b6cac08,8c991c34,5f8cad7e,f68c5b98,78139d28,d180d824,a3ac0d5c,c91cf0f9,cb97771,d16396ab,bd183221,c8d36a87,2785e847,b5d9e26b) -,S(4f90e8e2,37c4937c,a384c7b1,f929f329,94744d5e,8b89ad94,808ed9b0,9f305a68,cde776e0,2b6b484b,83f417c,fceed07a,ce725e00,343c4e70,14748f08,992430b8) -,S(4d9603bc,9f40716a,e6913fae,253eccd3,4442f6a1,3c058ed6,a10f91b6,75f716a1,92b679fc,278ce355,97165827,aa6fb450,9c52a412,284aa493,c6654ee4,3924add6) -,S(8b6f651f,91c54143,12c94f3b,c1632e13,f90cd718,67f906a5,aed13c4c,4ab17203,88c159a4,b80f2556,bb4e2b78,c126c40d,9ded995,bac6ac13,bf83655,210c7066) -,S(6f58b852,cab98347,e86448f0,78d49916,1909e1eb,60556ee9,8cdc20bd,b25ec256,3a4c05f,233d9305,e6abd30d,da0cebea,1681dab2,ad805cd3,2fa7023c,98239885) -,S(6be7f6a8,4021411c,acb710da,3ffafa32,8bb6ca91,59a91008,6cb98071,100c44bd,bf64a6f9,d461dfb4,581c8d59,b5fc1191,86f339ff,320e968b,b5810145,4836bee9) -,S(b2fcd0b,b8ea9e66,f2cfdbe1,3ecff9aa,99661f0f,2ac1844a,b3983d2c,ae102d39,a046989,bb3b8fa3,eb2cbba,d3a7e810,27c38cb0,ea33ec74,1444e8ce,7182bb86) -,S(a1d6ed0e,ab559b29,edf7770b,50cc5913,3916826b,6d99ef12,91bf744a,79a6fd96,bb91657e,c9255ae,173bf93b,51848094,2f17df30,ac6b391,df2237b4,c04ab69b) -,S(28f6570d,ed7130d7,35366201,e9ab639d,440da5e7,e1c9701b,d08a811e,912a9575,39191f60,119c59b2,3e91a7c7,fbf4c2c,e2216e5e,955db62e,dece6adc,f2d2884a) -,S(14c8ced,dbb83de4,218b089d,101d7b6c,31cfce22,49637853,b9c804f,90271fa3,48052d2,a5d02e71,135cba3d,24c7894b,de1293d,44a2f84d,7a8fece4,ea9a41fc) -,S(eaff9f05,fec737d3,d2a28fa1,bc8450a7,a75f563b,9221bca9,eda2f8fa,e12d489b,d6d4419b,5c9873d,7d3349fa,520f463a,2ad9f348,1a111c3d,d3fb70a9,23b8c139) -,S(e8ee4c6e,b42a3712,85b52457,52e7fc3c,ce0757e0,96932a43,d92bed15,14b35e95,d86bd4c,27ef1831,f107ff4e,6246cb7c,ee55abfc,cbc5de2d,5f230a2b,6a3b748a) -,S(98c61909,8213b06,6b70759,1c88a51a,d5e90922,6778386,a0776e6a,ee41e7e4,eb3d2e2c,f98bb904,42e90e2d,38ce4c53,fd72da8,1a37fefb,fc241aef,f65d4c8c) -,S(d4f66b81,f5d62986,c57a0dbb,c38bcb5d,89319806,4e28e17d,946cf7f3,f946dd29,c1930f8d,eedf1a00,cb7c5579,d814b5b8,2a12298e,530bb32,867821fb,7b7a5fc2) -,S(14d73ce7,5f8919b,55d54369,69866f0d,a13dd4c2,ad447c4e,b9879060,1411087f,69b94622,b9cb0d3c,5d106df2,caf4208b,b71c48f2,629d467d,16ee06c6,93ededf8) -,S(57efc935,59c7a0c,6ac51105,8a50a8d5,5646ab40,8a711711,5bc34c20,23da3aec,fca9329a,60b855c1,74bfba0d,92ae5529,27f959f0,5332cc4b,26272c02,b5c5dfd1) -,S(91f13a86,63da80d,a90b9458,55a9f3e4,171213f5,3683873d,cb6372fd,95b3677f,7405e0d8,6734f110,c329a7ae,92055639,e0332ece,134156d0,3cab4efb,419a90ea) -,S(dcc84d0b,46145e25,a83dfd64,b40dc5c2,c3322716,d1337767,5f9d6aff,a1607592,e46a4cf4,8e4dfeac,8df1526,f53246a,51b95161,a7030adc,8bba8ba8,1d2d6c66) -,S(28ab06ac,d5a6f432,116011e,6bf3c6a0,df0bfa1f,df16adb0,54250174,3348676c,51272a1c,967f49da,e9d1d6b7,a4ffcfef,cc31f42b,e0da52d4,27e56b63,97b0cb9a) -,S(7c01b21,f8d1dfdf,d3f2adb4,5915c636,d9c2a92,320c2d00,beff0f45,21d8b240,b4a48fcc,99906d81,fc6f78fd,aaa96b3d,6e7ffd62,d36d1aed,f76fa25c,542c8b48) -,S(f94eeb78,30f8e95f,2a362423,9c0e8fb,a0d3279b,e0cb5f5b,428a99ac,d14d98f1,c96d5b64,69676b9c,a5dc91be,8bb4a93f,7157221d,9513cd23,5cfe3ca,43649527) -,S(ea4674e4,7788cda4,bde0dd8,5f5e32d3,9a6d6477,30e9045b,d406f5f8,11ec35ca,769bf79,a9b9122,3070032b,a18bd769,fb622a61,424e9a0f,e1a46230,a75a235a) -,S(da5a7419,7f8f8685,1317260,682bfe28,19b7b38d,376745d1,7283c250,1fb40112,a60b5eec,5871e18,1325ef5f,5d6373bc,b5a19f41,2107290c,eb663e3b,95c37a39) -,S(c1017fa5,52560fda,18c6820,ded7b76d,a75ebcec,23b8fb6c,22ff72f2,26e9d41d,e947b19d,af2647f9,167da3b8,dff05897,9b5dc1da,6782929b,1b078114,349fed39) -,S(be7c0e1,4e814476,78a15238,b5809a75,1b964658,19bf0b16,4b3e914b,29216a7f,a30ebe97,f64219a6,f0b072b1,5d648e81,880840b,8a36204e,4f1627a0,feb392e) -,S(6758eec1,a4d6c0fd,cc118405,62fff82c,59e0fff2,cf80414f,cb53b139,97007cea,4653bc66,20fcd852,422c8898,862631e8,a0149bba,d0b9cedc,b4fe3eaf,7cb316b3) -,S(9cbb51d3,f88f4d99,9d80cf05,9e8735b3,11014de,69acddae,70d850dc,405b6116,dfa2e748,cad75b52,800e0ed5,17efc4d2,47c6381,9190a3d6,e2510bb,25902360) -,S(63a5aae7,b170792f,17350229,eaa5ad18,65328bd5,3421cdea,3d6e1510,d8bf0bc3,1125afd0,f25d5f49,f7e6250a,ed3634c2,12a261d7,8ce58ea1,95afb883,52da1010) -,S(adf96249,3e5f0328,ebae11fb,243da21,4e036d24,1da62430,b0fe2c89,b2f10657,509834ba,fcd8ddb3,2d018b16,d17d4b5f,219a29de,8a03f7f7,84f34b57,9b1ea1e) -,S(a0d8f5b,7fb44a15,93583364,e04d7225,bfdfa549,c2b25f32,f00765d9,e34d472f,61eab66,f84c2687,949da99f,3d97fe3d,630b6c22,f9f7c48d,d539b122,ef998ab2) -,S(b98308ea,9596a2db,adcdbf81,56d8025e,7a3ee0d2,5b27c33e,f686690b,ae61fc1,cdb4e317,7566a4ce,b4cc582a,3cfd259,445bae6e,586786f5,1250cd05,27ddbd37) -,S(e1a64f1d,37e3d6cc,119eefe3,793ba303,cf3969c8,db4abf63,7f0232af,70b98134,588d7ad8,885dd2f5,ec4d2084,b3f581b5,ddbd3567,8f4ecfc2,f955ced4,1c3231da) -,S(fbd5dfed,e8543aa6,e72253a1,bd711911,318929ee,7af14eca,49c2276a,65fdaaed,317cef0a,432c3516,3c405d51,65b8c310,f234891a,dbd0d6f2,f76cfbf0,193b78bc) -,S(fac4b7f3,b0a39510,84f1a882,2f7b6f20,30b87c4d,c0178a2a,e3077ce6,84da6bc2,7029b920,9e9522fc,160a5c54,a628fdd4,386ce0d1,55f19fae,390b2995,bc867d75) -,S(ca8643de,834fcf50,802c0296,41b5fc7d,3c29fc51,5c75c53e,e64a8185,43ef7c2b,907a6c27,111e296e,2436fd4d,ad9d9fa,f8ecea31,cee714c3,b26fa964,afcf17f9) -,S(71873649,d700ea1,7ea26b19,efe4b48b,a4a73b22,bc54066b,1202c96c,f3315f1f,f6cd8447,4bb374b7,753fc614,de5cf429,51512748,2042215a,bd82c11d,87ded2fd) -,S(67e738ff,21c3c732,26e57482,677c63f0,175b768f,776cbe6f,15ac3c53,48c5e3d7,14e5140f,2343dd72,577a5064,47cf6093,ebd2854,5d1326bf,ac79350e,eaf2bdb2) -,S(514b3f31,f875253f,205339f6,434ee17f,6c5a5c42,662ce934,280f55f1,9a198893,4eb33993,a2fbec70,4cd1c538,ce7cde4d,a61c0fc2,dca9669f,e469807e,4ae9a090) -,S(426acfa6,eab03e75,6ab30a41,418a0392,ca53c216,f84b3586,f9858501,8bc2dab3,c3d63eab,21cc10c5,c0a06682,d0573bb6,d34944d1,749da74,acb59aad,f1083926) -,S(b946bb46,68c05737,ffdcbee,94597c85,b8ad4a72,c58205ca,d420e8f7,a2d7a09c,cc700ed4,12633826,567e63a5,e65bc603,969ea13a,49feeb2c,dc723bad,1e3401b9) -,S(e6a844b3,f6c8b45f,511d7d3c,ccd75df4,1d1e38f8,fb28adcd,80335b95,d98e33ac,7f24789,3939890c,74a3268e,e1f717ab,6c4aa109,cc9257e2,c0b176c2,ec58cce2) -,S(43e62bbf,d9e052e8,c1636b41,5524b98c,493e903f,2313dcd,117d140f,96458001,f481853d,a90d528,30999300,dcff31d,ebee23bb,49ecbcec,8e147799,a63b352d) -,S(c44ef40e,3427476d,42e23e1c,41ddb9bd,e555a844,9125aad9,e94f44b8,8047f817,bedd4313,e43ee593,f2818e14,776f4ae2,38f664b2,db84c9d2,498b9ea3,8e236fac) -,S(a1b35313,dcc11895,c096f93f,5f8e4997,7f58f2fa,afd9b7e8,d408bde0,53212385,bd7eb25a,bf0d50c3,7309f9cf,5093d817,135a9ec0,20262c55,bdc8e8a7,a3079f5) -,S(48a6f3f9,fd6201c9,a37f2f0c,735bd98e,1382229a,d1589c91,b6748a92,1b5e964e,1b545155,3d41a8a0,64862c81,fa9d5966,2c73e039,53a5dc91,9712c50c,5b4481b4) -,S(8e01f574,651db06e,8a19181d,c8eecf1b,75f050cd,c5b2354d,b06285d9,a4061e9f,9d156ea0,9800e7d5,b6c6e90a,2eecada,7d7ba964,ba1f0cae,256fbfb2,275e108b) -,S(4bc0f8db,9e6db576,3eb68b19,5a79f8e6,28e375f3,1694a58f,43da4dca,fa05345d,c6a70789,a1e6b164,bba380e8,126a4a69,6338053b,6a32d9d9,8d0f215c,43a5b555) -,S(966fd0cb,5f5edead,d6230a66,50b7dab8,f4c7ee8d,b00ce55f,32d54a23,ba97a768,9d644e43,bb4f9b65,f5819a1d,ee0a16b8,1e8929c,a9e544e1,6546cf79,811a994b) -,S(6ab519ad,49522ea6,592dc7c7,4438e337,20d50eb8,862467f8,2962c510,857b0d8a,c5ba3a34,2b7250a2,62b67ec3,554c21ee,e82653a0,378ee0da,8a809151,a3ae44d) -,S(f8b0b8e4,3e5060f5,39bd0a0c,d076e163,e55f18a4,25327856,d526d6ef,aa76c62f,743de052,a65853fa,58cf29c8,62839aa1,7d5c95ba,43673ad1,fe1ecf6f,d4d48ba4) -,S(c4509ef8,579d8ff0,ab585c0e,5223d5fa,967e9763,9d15b0e1,6587a125,3ed18bad,7b91f7e8,ee979a58,5a36d8d3,574b8ae7,81199dc0,86f11cf9,7fe58e4f,1db08362) -,S(9a00135a,6ff450f8,e2207c53,894c0e4c,4cef732,cfab43c3,aacb00fd,ab42379f,393ec748,3684c5b1,4760902a,28cabb90,b481596e,8b847d59,4dfb8ff8,1fa9975d) -,S(3d775bdf,173f8d7c,de90c17c,25d3dee2,a484d331,4e525e3e,aa4a405b,6f488601,7e6b08bc,a560f6a,5bf287f5,59d74e25,38a4025b,89972046,b3de98c7,b30e51d4) -,S(cebafd3e,a60118b4,513380a8,d10a29a,a95e5002,d703d7b8,f5d0e983,7b03b529,19477ab6,46f59f61,ff603594,e33ba046,5f6d8b1b,f55290c0,fd61534a,87b74b4e) -,S(ae8a3cac,1ff3e3e1,ef01ac16,2e49b237,7ecbc963,f58adde1,58cb1987,cfa731b2,5a4b0675,2052b749,733f6af9,e8dc773a,ee26fd2b,114a7ac2,baca1e9e,51531efe) -,S(d74d38bb,8bd47123,5c118ede,e477ac4d,fd39b635,d0fbeb28,30843753,ade3b38e,f3e505b6,f17a2839,7a985084,31ba6de2,1ec0a0fd,3936dc32,5d66bb37,7cb54451) -,S(f4287675,7780785c,d14dc1be,fe075d1d,4d4f0b33,b0ce9db2,49595b14,f6beb2a8,a3df2231,eefc62dd,c658bf6d,a361ad6f,950f34d5,3ff25536,4eb1e1d8,60514b38) -,S(e91d576b,da19ad62,76bcaaa8,69cb2099,e6277688,3ca1d454,50dc9401,46378e94,b57e2038,c8da2cb9,9ac313db,83265d8c,20e7918,37e75db8,7acca971,3840779c) -,S(269944e8,7d77e176,3791b53d,af2aaa43,e035e1dd,f3c7daec,7e830cfe,38c66ea2,cb011764,34bdc7fb,528ca43,9b323c9,56764145,7b7eeea7,39ace76c,193707f6) -,S(ed41e68a,8f0b3681,1aa61c68,57bb1765,fb099317,2ff6ea5e,e94e01fb,644a3d1,f2cc907b,880cbe04,26ba1e44,83d95800,71c918e0,8cc085dc,1dd0deb8,c508231c) -,S(6947664a,96cfcba5,e2e36e4f,53a33d69,538192f1,3322113a,b0b79642,dfec0de,6481d1bc,5b65b6fb,a91b76c4,d6ade333,25610195,decf5dc7,7f95dc2f,a38fb6cd) -,S(aa3e187c,e22b63df,6a80a42b,ba9265b0,4379012c,70e8ef66,8ea85c57,1e27fb03,a638dd6b,98109fd1,96ffcab7,3010543,e8732f48,e5cdb29c,38fa91ff,8d011be) -,S(5de4e1,a4bef94d,b4a9fbab,6543fd6e,bfd5ea37,9124e1c5,eff9be18,f84a944b,21c4a282,693be294,b699513,f7744761,58f8aed1,a7ec7442,9679ba9e,7957e2d6) -,S(6533dcc7,2c87b477,81c96c79,3af0af22,fdd18fee,a33a30a0,9646c2b4,287a7ce5,7f03e5f2,3d82f9bb,ce9589fc,23442174,482748cf,a3aeccd3,f8c37058,837ccc51) -,S(139e5f3c,129e584a,bda008ab,85343531,c5109f23,a70b9871,a5ebb00a,64fdf354,497b7e57,41fb8eaf,a53182ee,98352b62,6bf011e4,826ac9de,6190a2f7,773f0a98) -,S(493fe9cc,f7e1e950,83cea991,8d8f2561,3ce57b81,81915f0c,7c779aee,8161f7c3,e69763fd,62fce1d0,454aff6a,6a3bb448,639ab615,8bcc2f40,88cbe4c1,67020cd5) -,S(ed675fdb,d8dd70b8,641ac2fb,4903ca77,900e3c15,766ec8a7,446e6b36,52a064a9,a61bb379,85cef5b4,6e0669b4,b0188ae,23ccffb2,5ce777fd,1f26f313,68416de9) -,S(173670a8,9a769e3a,797c14e3,15393d52,b6d48444,3861cb83,136b0ca9,9a260a4d,4dd43921,c1ba4d2e,95ea1b28,e4908410,d140b3f7,7dd82bc6,d683da27,c7bd4904) -,S(d5a5e3a0,8f87e154,6f11e05a,c106e80,a1da933d,2cca528c,df9e1f09,635d1610,7c6c55e0,daf3c092,8d0a9c6f,2c1ffb0d,aa20df74,20a35167,2552914e,5d175352) -,S(54f5e9a0,4ab321c,692f2e2b,94d6697d,a0a99932,74ee4ebe,4175a338,daf6fa2a,58cf13d1,75fa6e47,34aeb761,4f828dda,58a7d9ca,855ff42b,5cbd66d8,89f2de21) -,S(d6682898,154de995,62e5544a,442622b2,fd9a632d,94445d4c,9e8725bc,7febe6da,98091e3b,9ba3b857,50e02c50,a7971aa3,b2d5045,f760c1eb,d1371dc6,3190f206) -,S(253019b9,2af2c4c4,8d9f6e1a,82decd36,610becff,18c908ca,fef49bf6,cdc2da08,617d335a,d9509d74,e5eebdce,810872e2,3ffbdd3b,da53aa5a,495b86ba,397c680a) -,S(56f64ca,461bebde,560d2bcf,ac08f292,ced72574,50e44f16,bab67cd5,104da6cb,5b2085cf,dc278328,a992bca8,f2ee8142,757cb553,b903a3ee,bd83bf3d,593aee44) -,S(f39c9571,1e153a9a,f0e5c192,87e3ee38,5a31a1e9,bef312f6,4dded245,8f553420,4cc94ac1,1c206b9f,7879df90,8498c132,e742ef62,48bdfa97,4b882930,e3b0b1cc) -,S(437eaa8,cbdf873c,32d3dad,95c5aae5,b2f3034a,5de0c536,8c8ddd62,c13128b5,27d8ea0e,b00310bb,59424599,3d60da59,2f8d1b2d,df0c1fcc,721e3080,993c59c6) -,S(ade1a589,3f5d6798,4490ae62,11c57534,3f13e7a6,14ef71f,a79eb4b,a880e9b2,bd49c17c,537e6a3b,ac7404d8,c3c1b429,e801882b,7f241304,9022e262,3791c715) -,S(936275d5,c3091a5a,b9f57d97,7a4e1b6c,a87ef978,c7ad198f,d16e2d93,3ac1224e,6852690a,d8bd84c5,eab75d96,c6e224d0,ed598851,b17b857e,5aa01207,df6b9f32) -,S(29e55fd,3e8fd5cd,e046db20,5c80b9d3,e294971d,76b5e8c,c33fb5a7,6b9b786e,769e57a,7eb934b9,4578312f,720ce44,2bbf3e2a,d61a6f57,af6cde49,8c010a0d) -,S(df8362a7,350185ff,198b5275,45e16f78,3ae37804,7647c584,168b159b,809051ef,afcb3446,fbd4a3bd,e826b604,84b16c3b,735ece80,ee48da26,3a6cae0b,62af6bab) -,S(5f443123,9a35fe0,f9566037,96cc619d,b9a01e83,96cf433c,25415ece,58a427e,385c2812,fc0aabc5,29272b60,56aa9c17,37d81c72,48fafc90,6fd7d4c2,b0901ac0) -,S(c19c4215,53c6037c,525b77a3,1693fc4c,8c5323ff,5d3dd63f,4b7e3448,15dd2de5,9f76ea8a,879177e1,27116189,6d9e6b20,a19d2255,92c99822,159c8ec1,a93900a4) -,S(8abf3a1d,d1e02332,ead62fdb,36394246,14d19d92,a82113f1,d62a1423,af2d45ac,325a967f,dcf5ec3f,75e7a984,ecc2d9f2,defc2941,6dd507ec,7de1b598,a7e36dde) -,S(c8bfdf90,b93161e6,c4d4a58f,a71ea84a,57c1dd76,c0607b94,33fa3cdd,f759ae7a,23dc38a3,d172fb63,ed47efd3,c3e5aa3c,fd7990cf,1535ce5,b51944f3,270b20f9) -,S(976666c,35c55997,a759e7ab,85f90d7a,a26ccc40,5b77b8b4,43c7e86e,2d2c78d,6d342c3e,44facf25,bf2db2e4,e20cceef,92c52cfe,b4370f89,60551614,381ed0ff) -,S(e7790ba7,7737e4e1,c7bb8e8a,5bd89c3a,1fd65b6c,feb2273a,1c12a8cd,f963252b,2635e20,1534b58f,70e754ea,db28998d,f7138ff2,a9e92e1a,810259dc,ffbdba42) -,S(42cb817f,6bfcec83,f60e3ecd,5b986ac3,b471cec9,975f3efe,37577d81,4576fb0d,ed35e128,b2f9bd90,f2162050,a5737909,144a8596,5075fcce,2708a4de,c45cf49a) -,S(a0886870,1a239333,ffc60397,ae11f145,31902428,a4fd58f0,2450e0f,412f3cbb,c8486f37,1ad6e034,8e51995,b4887ebb,fc6002c9,9cc00ad6,d8a81f99,1883af52) -,S(a40cca41,9f101b8b,40fd8e8,b364a52e,e6a9642c,22661aab,3486f25,732c4bb3,f421b69,3ec096f0,2d1e611d,f0701cc3,b0655b9b,95009285,babb150a,9445a910) -,S(90aef978,bbb0472c,5a75b70b,c9f5755e,c532940f,141a350f,efe604a4,35beb721,f9f05c70,737cf6e4,ca88cde9,2e478ea5,93f58510,9479d187,a5f87e11,e14bbf0d) -,S(ffc23a81,a0f61f39,600292f6,8db9acb6,d73ae433,bb827f1a,7bc6997,ac3407c3,b76a0612,bce5e139,277c7463,d47cce0,4f313b37,a0746803,6865f284,574d4b66) -,S(d3ca7b94,40bdf990,4262bc16,298425a6,742c852e,df99ded,2ab0ff50,20a112a5,9daecbac,ca7e825c,4f44281f,9813ce2c,5ef191b7,341fa2cb,1f9780ff,de4d637a) -,S(2a53a2bb,720ab31c,2a6b7589,ce0e1ac7,469b21ac,d55eeb41,b23b3cca,51bb9f06,11aff933,ffde9646,7a4d0f52,220d06ec,27f7810d,ba44b256,c21a57e3,d451f84e) -,S(487e5356,80c40287,a6fd2f77,bb8f5cbf,22b2fc71,7fb7487d,5a08474,ada1ac96,53bd7fd5,46070d63,77b65326,d5130445,29c9625,520c3a73,1e990d0d,5aa849c8) -,S(3e5a5fcf,291da0c1,fc332cfd,62f4b629,cf23c0b4,8209fa29,63de5b99,667b3e16,86987f2c,43389a1f,4b028df,773bb130,8b33d7ef,7f55dc97,b060ded0,fab86825) -,S(4f90afc5,15a847c2,2c42493d,22dd5704,601840fb,57086b8e,d5f7d779,e3e256f,46e31958,ac2e6892,335f6b08,9ac0d3c2,4ef93994,2b585e33,226ded0f,aab831be) -,S(be07392b,40be3ea7,a6a73807,121be982,c2ff4b38,a4585a17,82c585c1,e23601fc,3a158457,657c9e8e,7bd775b8,1dbe2109,43172771,e66ec38d,a57a8216,f1f258db) -,S(86c274e5,2140375f,222f9e6d,47c24e06,ecc2f741,51b5a603,e0563412,fa1108ed,4a02fab9,4065d590,32eb90b6,4c98987d,2703f276,f92c03a2,aa009692,40a96ef8) -,S(4fd3a6b,e7923898,127b3056,1dac13fe,287277aa,21127626,2678e04f,3573cf97,6498a1a1,63cfecb6,c6cf4b4b,43bc7e96,f07ebea2,3b4380d2,38c0342d,f11173e4) -,S(cfa435ca,5423bdd7,8aafe78d,1fccfd07,cd2a5f86,ba81918c,b68c7695,dd117c94,bf4c891c,2dff79e,35b77854,66845389,c399b53b,4a9f4cef,d7d68357,10ce1fe8) -,S(aa5acb1b,79533cc5,9b29e927,77469afd,414119e6,1f3c90c1,cdf93e2c,3e1d446c,b0df29b7,8713c001,fb6d3854,e183767e,8b11bf10,9c75dbc2,6bb408f4,22a498ab) -,S(1b93c2ec,c21bf558,ddbfa1c4,41bca52f,435c09f5,4d06d175,6353e0a1,545c3d15,56c455ff,718190e6,5ace8a5f,d5c6d263,f72e67b1,a20dcc4a,eb53fb4a,33195ed2) -,S(1744cbf0,2566d20b,f639438b,55f72b0d,c8480092,246410ac,d8551498,2fb91760,7e77a7a2,32b0b5c5,9d1d5da5,7a7d2570,68dc0f8,4bda1f6c,683f5229,df4c66f5) -,S(a0be98a5,ed448c02,8c2f8ffc,607b316,1b9cb9a7,a2291bed,d24a8407,ff02582b,e7cc2c6a,2393525,b4d44462,cf6ac8f,76b86981,ddd369a2,274c1971,11da6ea) -,S(e0e593f5,dab5f7a9,562b2591,d8d75ea3,8b2f2b19,cdc8fe71,14891006,7b845882,9088c762,15e35db5,b3bc2614,1a42ce2c,b5464dc6,49f469c7,e785f5c2,cad67334) -,S(7824d895,a4982eab,d6f1b928,de7b0d65,ffe5796c,5e492b40,8b9fc879,c29290f5,ae175c68,8e428528,38a2d8bb,fc232c60,d6bcf117,57cdad44,8a4af01a,bcc7ee88) -,S(49d2e57e,e0b611dc,214e4a2c,d019ae2d,2aa51393,e976cb5c,4211cf10,f9d96e66,ffa0c4ca,88011f72,779b7919,829bb9fb,11c81e4f,a78154d2,5cfa3cb2,bd5b770a) -,S(da605f6b,8f701a85,86012e8f,83898aea,eeb3de32,e9c7bee8,be2139cf,c75ead00,5ba0c12c,e98a1c1a,89f0ca5e,a93f50fa,5a24307c,6751f633,d699e5ce,9411d246) -,S(aeeaabeb,cde94e6d,5a1de2bd,1d9c380a,9307be3c,1c32e785,652ffd9c,bac16ff2,30094755,8510ecde,500a52b,f107093f,b62e491a,c2596460,6641abaf,d50bf840) -,S(62f1892b,35f3fe64,b1ad1e1f,4305f9e8,66ca0a0b,e5cb778c,b0e1feb1,a10c40b7,1a44205e,e600bf4a,2e287f09,c5bedbf,f1f89052,2d14a883,8e1813a7,3f5780d) -,S(c2091ec5,46772d69,28ebe9f5,50a68083,3a567b33,dae25e94,4ac4d589,96979382,599a765b,d2e89d31,735fa722,a1fe1946,eb610c69,2d5a82b2,3828502d,cad4b31e) -,S(bfd7c15b,19519235,700e1b23,79fe7c22,e50a2455,5f83dba5,97d00fdf,1b242367,ac6de7de,545ec735,ea127213,fafd287,f4cddac4,8d6fe694,372bd46,bc66b17b) -,S(d4d4e784,3cabfdf7,903d8507,3831da81,9581629f,74f3cfd1,16b5f635,132ddc7f,1e49611d,582cbacb,fce65a28,44755cb1,d1cd6d4e,2b8f082d,219742d4,61758a6) -,S(1e575009,c378b34d,f3b434a4,95dd8c31,4945b4f8,df617d02,cddc11c8,8f908fdc,5ce37fa2,810c95a1,2697458c,b8f209cc,10bf2123,3ffa8565,5bd8587f,cf6cdb7) -,S(b5a66a2e,ac237eb8,a1f5e690,ffdf65e5,c9268c6d,37104ee1,108f95c3,b9408fd0,99005ac0,aaa4f6ea,60842ba8,68668c6f,f8cc3280,307630de,3c43ef28,cbf72798) -,S(1da39d35,2599593c,66c90b06,3baeaf8d,66bc3a30,21e3f6e6,cfc3ee6,7f26fe0d,9272a05e,b6b0151b,5470d076,c01c3000,f7e58aa7,8fc7fe48,9f285b85,c941311f) -,S(7f3b10b6,b10000a7,652862d7,21f428fe,4e900c5a,f3844500,2b374434,b5a971b2,b94a2fe0,7907ee33,113bd4c9,256fa08,8c4a4f74,df3c3a9e,1f5d205c,a2ecd385) -,S(426107c6,61850f9b,f6beb61a,e200c2da,e5dc368a,3f5d18cb,baf84cbd,7a4eb2e0,e1fa7c78,a9e6ed0f,8d713488,bd3afea4,857cece,8e8e54f5,40f8c70c,67e511af) -,S(555e2656,708fc4c4,312093c2,1489cfa9,d6c94099,680f53e2,fa374a43,45be9697,f5efb7,1e3bb76a,22566e06,c674ba11,a7822422,c6f44cb0,2f2e2be,284db6e7) -,S(7170b17b,5736e07c,262a927e,725b709d,3360625,4642a8b3,af8fdb12,917dd290,ef437ea3,f8998813,b5ad86e6,9a77ce0b,98b2c6a6,b6df5608,627ae735,30973b1) -,S(1ca8ab3e,66fefd13,49e329d0,72a44f1,eb4de646,c8930172,aaaec311,5a5c2180,6fc641c9,2a87d776,81dda2a0,f4984ed2,c70103a1,5531b274,fd20efa6,3b0a3c49) -,S(8352546a,f6d42e82,bf150c1e,41c1a72b,85f057d3,487b4797,7d5e4f8d,c05366b8,76be5ab2,7ca25b12,a888d7e7,21c2b1c9,ac92b0e6,ea0c484b,1383a835,86c5fdb1) -,S(2f112f7b,1730b9d5,63f988ea,765c48ef,353123a1,4d92e44c,3e988459,9c904cd7,eb348e97,f6487d5a,32f70b16,d2ad1740,27d7a8bd,41a031bb,743a6825,2e34a44f) -,S(e84023c,164dc6c7,1d72494a,d410a5e4,2eb6fd09,16a70f1d,5192508f,3ea5648a,634f3585,29be0328,89b2f510,622816bd,225aa031,ab145b8a,48a6fc80,1ef4462d) -,S(951c4d17,45daf527,b803929,114d57f4,4da40342,31c669af,d6e40127,8e28fc6b,f9083b11,a8b30fbb,2c696f60,8ae82627,b9592ef1,c72fc921,bb2ae4ad,5a27f0a7) -,S(adaa9457,f60b9f3e,e0a5548c,51f945b9,78845841,51ae87fd,689b892f,8ccb19f4,834657f9,2145fefb,8df9b047,55674997,f899b951,40ce5830,2e468588,1761caa6) -,S(649296b3,9800a3b,516ef3d8,52d7fba4,597f3e35,1d303397,7495fdee,619e6ef7,44ce9c90,10215167,fdc5f078,e2edfebc,5c8b441d,d88cf853,5c78533e,d61df105) -,S(2c1d7e97,908575bf,38afe2ba,7875f1d6,9f1e9db6,b11f92ce,4bc94d3f,6006266f,9eb250bc,30abd08,bbbb4e4b,bc09cb03,8c6c8ec1,fd1a6ff5,ba23726,da2cf7f) -,S(b130ff8b,ed4ebc32,78293b10,52fa197,b44adaa7,d1bbd74f,f6d56f9,744647ec,4a0a45e9,b785c7f6,76fd0a95,66e4228,136f60b,dcc1806,212590ff,eea5eb33) -,S(4f2a5997,62ecb2d9,31ae9c74,ccd71cc,29bf684a,d68f0117,32a0cd50,cb0e6231,debf8db4,5cfc7083,fa700dde,7309edc0,fc44216,cf7bc237,377c0bf5,7ccf17de) -,S(97f9e9a1,7fbe6e25,e41419a1,8a5a24da,a178c0b,a99e30d1,cab0d2de,7a23c0b,1ab1226b,cceb480,fb4fdc8,70fb5386,6cb622bb,e71d3c0a,4ddda232,57559128) -,S(e17f3fe5,e9f5d17e,40182067,3b710940,bfd486f1,ad3ef4c,bb93b47d,9d9d8cb,f1126a52,615d3a8a,6b360b26,305124af,44ad7d62,e03ed96b,59c2903b,b5272f58) -,S(1a39f846,7d638182,900c3e94,538a0fe3,3ae66853,aac36688,7a5a8bb6,7b2fa2de,ae7c1399,5a625a4e,42b4dc01,9d7c7501,18492f3f,bb4567bf,28ddef5b,82903aa5) -,S(8a5ddc61,27f6fa44,90a93e52,f4faffb8,baa60581,5142be68,cd18692e,b42f5320,5eb62325,853dddf1,a42559eb,bd5dfcc0,328e69a5,fc787389,74c80d1a,896b0d8e) -,S(117dbfb5,74b7d6fc,d47dc17d,56f5b5da,b864906f,f08d190f,7afe1f9c,fe38c299,4acd2151,30b7144e,437bc923,302640a8,c504712f,6b903b26,bd5db8dd,5d90196b) -,S(b0c31228,431c7eb5,7310706d,950a2a60,eec84ec7,418199f3,f2985a39,8a70a537,a7de9b34,792876ff,e98c3237,260d8237,85e47c,438fe419,a1048b00,b064ff78) -,S(7c210cb9,f493275a,e17e6d5b,517606be,736cbc86,5a5897e0,8d1d1f03,f243946f,17b07523,a8bd185c,ea4a92d8,7af1f1dc,920a7fac,30faedb1,c38e3529,1759c63a) -,S(172e5167,578bed44,6397b519,2b0eca17,177b14b2,f4570aa1,38771610,6ed6e650,9c15752e,4776b805,d63de803,83c73ad3,9d3ba817,c1f88cee,1737cd85,33830ba7) -,S(161afc40,df25fda1,3637317,3dad8046,c95a6ef3,aa9c19ca,47e9ce2a,20030686,5e6fd083,c1265f76,b4b9c819,3a45e0e8,9926f160,b6257759,ab90d6f0,126089ce) -,S(b991f2a8,e18aed33,4d769cf8,b6e39144,2d194e90,ee1518d9,459d3ec3,8a16a85f,1d2ba9a6,b89f71c8,ea169d3e,923d2c1,7e6e590e,21b28e8b,1a0d0cd6,1bcab7b0) -,S(dae0689f,5a6cee77,f796f488,1fb3647c,7d623348,7d5ab502,6f1ca30d,44ca8afc,ee67b670,f730bae2,a15e6964,33be5b95,43ccc1b0,314cdfa8,c6cc8873,c39c329c) -,S(47a58ccd,75f89c15,46a17ba1,4629fb5b,d72805a4,16a12e61,aeafd8ec,8a7e4e41,c15e7fed,1bbb810e,b4be60bb,61fc1f0a,a4bc43b9,73d94767,9b954f3c,29fdd889) -,S(f7ae2fd0,2e3b6ee3,30c0697c,94ef65b6,d7582f69,5c509698,cef09b44,6b040e3c,ade9f8aa,c527139b,c54d8e6d,ddd41ac9,5eb49565,79934ea3,6a9dd8ad,d419ca03) -,S(155f9ea8,9be2ae20,8d7e9c21,4c244a58,ae61cf24,5d5f8dc8,b6c448d9,7c12989d,1204f5f3,840cd19a,fda04abe,6cbf4490,cf5ea60f,4cd17680,8c1ce9d3,65b009ff) -,S(a83cc9c3,933b5f14,fa5348a0,e0d3ee39,e35057b9,13c5a51,89a61663,1e9d74f6,40aa66d7,fad68476,1e2a9c78,e1fbe478,52b91d11,a283e1db,e30d4baf,f072a74a) -,S(ca4951cf,c07b5c23,298a20e0,fa44b554,d7acefbd,bf2a6cce,11fc3ea5,67b5f5df,186a8bd7,6700cafa,c79791a6,b28c799a,35aac545,78586050,b8012c4f,9f4afc2) -,S(cf92dde6,1bad101f,5e71f2a0,dbc2438d,d6760ba5,b84791a9,ae0ce712,9eb6787c,a7d351b7,f3e31e6b,cbcc1f05,329458e2,6c9d8a9d,1137d595,28f53e23,5c3bcbd8) -,S(b1ab0b3e,cfd8283a,3b79df9b,e83e8b37,b06154a9,6e2a687d,8f51985,129c1179,cdb7f2f3,4bab534a,41f4cd97,b812900c,99e97395,3837f058,12d5d0d6,e9506bbf) -,S(a1743329,9cd4c9e8,4fb99295,f3febad9,197296a2,98b30354,24e9524a,e1789ce,40994ef4,4cf53577,6f078088,adcfa6d7,5bee11a4,4f2f3fc4,4282f5d7,f77e1afe) -,S(241b486,4efcac7c,3c7b946a,61a55317,38b31846,607f1e0b,d0a1a2b,d9c0573b,5cce8848,eec61cd3,325f3ba8,fbca403c,2f980159,bad3997c,832f5c98,1fa0d574) -,S(81f88209,64997984,699559ad,f799ab0b,e3efd354,d258137e,d753e3e4,de91b387,8f9fedb8,5bfd7061,1b9e5caa,5f3cc8da,43bda599,afa29967,a32c71e6,aa26d15c) -,S(49d64231,bd2c2145,200793d6,4a2ec254,c22da96b,655706fe,8fbf5d49,464e5a5b,faec8eda,b0d72cad,81df8121,671c6dd9,bf986440,3f1a702b,548d4333,c751e825) -,S(74c14c32,4fad3a41,1c7e1f15,9b740980,6daea24d,9476e938,7e77db6d,66e0ae4,af795203,1fbee5cb,f031a2cb,946e6b65,3ee0165d,abdb89fd,5aa73880,e0641a41) -,S(88bc209c,7342d94c,be3f4215,81383c6c,930f9c19,d09d91b2,a984b6d7,12a1e7c3,acb7d745,76dd8723,89a88866,e287610d,b817ebe6,1581aa23,46ac994c,4c5b3e08) -,S(486c8c68,c81ca88c,df7b93c8,5a1525f4,9bee242,676aae77,c1bd85ce,2a6eb3f8,e0fec94b,35fa97c,d5e64870,6f5e6849,d6249004,fb33e34e,c1add26f,4fe52d54) -,S(4a1efa11,6c588e23,7b5e30fb,5d0ddf37,ba39043d,6e5faf14,e28ceb90,4a681a3,bb196737,3c907165,a8937dd3,1bce476f,65f2acc1,41bd8d53,8fcfbf1a,997b64f4) -,S(d7745c06,c69609ed,db17f30,8efe7bb4,2632e85b,7f7f792f,8da44294,78eb28d2,7575a75,4d1b2bd5,5fc46e11,b1addb1a,5371f007,f702a97c,ad13f082,39b96a73) -,S(bd752f2e,a3db27c6,a6a08ced,df74a87c,dc333d50,fd9995f4,9ca7afa4,2be68def,378f8aaf,67478d20,ba4725ed,26d50c62,ef5c576d,da9c24d7,91dec38b,a5e9491a) -,S(ef588333,15a3c7eb,c6602bff,ace00d5c,55eb304c,7f3301f9,4be457b0,1f224d21,56eb3aab,6253dfbe,3d9a95f7,e843751d,eb52e054,cb5a523f,f46a0c12,b517abd) -,S(2c1de374,7355825d,a09beea4,f42df241,6b495ce,7edf1f1f,c1dc6043,5253727a,98593660,9082f5d8,8f9986bd,f77672a8,5ff92cd0,28d2c588,73a3b1d3,87a150c2) -,S(49f8d71b,23e60140,f50c9001,6f39b2e8,b78e2a22,a88f2535,324ff50f,280daf99,f66bb665,4807e7dc,330ec339,3f6fde20,308111c8,1fe42546,22b93a86,b58b04ec) -,S(365c9f85,754b61ca,2b2a30f9,954f3a52,d18fdf78,db593ceb,6df617ab,189f37be,c43fefe6,aca56bcb,ffa6aced,60a32794,7681b601,22369a3a,f1405a41,5132825e) -,S(1cf2cfe9,e89668ed,c1a446c4,da311cf2,7e2cb53e,1984a310,8e24e8bf,21f1b5af,71e56dac,43c53094,7b78f104,1a685f23,aebc7b12,e2caf803,6731ef5a,20c966b7) -,S(f3303479,62660226,f391c26f,a7e87796,219694f8,e01cbd52,25dce636,b48ca3ec,7dea0bf4,c110e945,dbb59ab8,74f83a42,afa585c8,56a93002,6f48f8fa,62762827) -,S(b689244c,4bc16c88,398664f9,2297ea0,8756a969,1ae7adf0,587c3253,e4b27154,9b488748,1357368c,c97f89a9,b4a75a0,bd7483ae,5c700364,c27d19a8,e450c856) -,S(bf34fcd2,d6b4371c,fef2f874,5e4be021,a78b4302,240d4517,f3eb1140,638cbe41,ce6888d2,7e326eae,8e772914,e1b43bc0,1ef6a238,27f67546,5464e195,5f97ac02) -,S(c2097a6d,231bc796,ce85a594,44c00250,d51ffe63,c45b9cd1,10ed4821,118d74fe,58b06413,fc4ac173,e1e3a85a,ca674885,d1f92b3e,5b99f72b,1350b6a0,bfe4ac87) -,S(874a6222,3d8804f3,a11b1de,3c647aea,e3e81798,40db2618,4d46a330,417afa81,4132a5f6,7986e622,976b181d,5c98f356,b31668e0,ef70f8f,6b13a0ed,af80b429) -,S(ac7c6e8a,1a05d592,8142227a,b0c3ed46,1f28463c,ccaa3b85,b9784e0a,f5bc605c,1a59a195,581e3397,eba60a0a,963f5c71,c107a9db,68794da4,a08b14b3,118a2186) -,S(3f13e2d8,d825a3f6,8875c01,a1715a5f,44bc12b8,2f254a65,575b163a,3333342c,baff6882,fb2c2611,ffef76a6,8b5e2293,6a2e6ecf,d7ba6724,3393fa1c,5825e3b7) -,S(1ebeb354,515e7f39,dc3e2631,51d0630d,aa7e400f,4c9f7cec,4d5f95ec,bfa8fe2d,a2e35cef,c2cdcf,384a2473,c185f3a4,c70724b9,84c72dac,a6ca11f7,ae5c85cf) -,S(c2dcdb65,b211e765,e6c59218,d12b45d8,b47d8f9c,e22b99a0,d2d19a1d,de02b2ab,e0aa5b9c,a960117a,7289326e,9259f886,8722e032,c96b5237,b146f50e,24f3be50) -,S(495d69f7,e2a9d144,8e2ed8a9,c038f6c6,7f360b8,270c9b85,841e8791,64bc0d45,5fb3fe2a,1dabce7b,83b4465d,74fac6f7,c48584be,134283e7,bdf59e0,957088d2) -,S(ceac4569,2139e4f9,701be43d,8da3f515,270a9477,bad5969d,2037ac87,3453bab2,bd1fd9d8,15f4e872,b602f2bd,9604b6b2,f385ea40,d5520b3b,ca32c160,44908070) -,S(7ed1d0b9,3196b8c0,1cd284cb,c0a206af,4e6dba1a,d6cd406,82f55897,9407e0d,e95a3ac9,6ba60be6,22f4ee73,2d75a9c5,11018ec0,d840ce0a,f1bca18a,1d2801c5) -,S(72fb366,4f42cec8,940fd436,5ba7cc97,ac5fe4b2,131250fb,a24b7178,a1040b04,c182b1a,93a211f5,f5de5c9b,4b52ce90,63d551dc,a21ee9bc,dbba2653,c47dce41) -,S(dd06cd8c,9ca91e45,d6720043,d3e6d857,4690192d,59154309,2160f04,6008beea,cdc17327,6eebea3b,f9fa8a7e,e83ebd81,4189705b,900b3ce2,72b85dc6,c41e7ecd) -,S(80f6129,e90a7f0f,1e650439,8bfedb10,3c708c43,2e2c743,da8a9a99,3978cd13,74d97812,145feff4,a3ef594f,85b644a6,d95a3082,3828c00f,e7226d4f,39deb82a) -,S(56af34da,f56b508a,eee970af,bafb9dd2,b48f83c,4c051b24,f5bc27e7,105995b6,d41dfe52,9e788e19,89105a4c,c219dcd3,decca65a,dcc5f34d,8a3ab0de,d1ae68bf) -,S(820225ba,795565b4,c45e29c,4689d91c,148cf693,a1a1c1f6,ca33c44e,4e3f91ee,3622ae5b,c89b9c2e,66bf5a3,17826928,11a0f4f1,4b387334,b24028be,ba4b7db4) -,S(7925fdbf,cfcc202a,895a1b7c,a8c7f09f,ad388db1,5652b703,3bf232be,a2ea57d2,46f7ef01,c9cb7dc9,1559cf5e,c6d3f5f2,1ebcc21c,a8414d0a,9dc37309,4e90525c) -,S(4b224b6a,f38ae731,5b316eb,8dbd2b1e,6638794a,9bff79f6,1027f60d,5d81808,3143ea08,b1633002,bbb2ad2e,11ffe5b4,b6dc6888,1fc669d4,23ff9cb1,595c3dac) -,S(2c0767fa,4135f4eb,602a1a36,e6ce488e,2c1bdd64,aa4113cd,28daf20c,687380ee,ddc3effc,e78d3061,7cc2da71,1373de0,6a65d2b,1050b89a,5f71be3b,fbc16a7) -,S(83837d3e,e7179a84,ef6ed2d9,41a9f835,37b5a2c2,5d511ef1,982d9bba,50a7ae7c,62201e16,60957b4c,a86f1a49,5a6027b5,fe2294f2,7946c8d8,556024b6,e3b66dbe) -,S(cf075b34,e560f057,53a8e011,835bf1da,25e50d9e,1d70dd9b,da427109,5895387a,c73209d0,330ff4d2,38e19f6f,33df38d7,2b11d8dd,180d6a14,4b07184,a2127018) -,S(d583f8ff,9b1875d1,ef468030,e3ebb7,9d06ba2c,1008329d,cb01b883,7c8931a4,f8cfcf1c,3f092ba,6bfcfcc6,9596b508,aaac7c9c,333ba58c,d55be53c,6fae3292) -,S(551fe9b6,21d2389b,fc185372,342edb1b,27568bb2,da1fe220,3431b792,43eaefaa,6c76904a,e48563cc,c6aff505,7f31119f,ff48e5fe,971223d8,c3badd02,563c24e0) -,S(1bb778fc,74062f24,b0962be7,bce7c990,51f06394,bc8e6da9,a9d63f6e,d16a80b2,2754f53d,2f4ed167,3d2700b6,8ff036fa,60e9352f,1dd7bbdb,14be1740,61d88318) -,S(a150af7,1261582f,8949f1a9,3ff8d539,aa0744c4,e97cfbe6,e4a3fe10,e7e364aa,e22a1afe,a68671c2,f9e12471,56e1bf47,100737ed,5f96fab9,9e0df721,eaea4773) -,S(c94ec3df,727fdf91,d7963a03,8e93d68,835ed2bc,2578780b,7242e15a,e72e2a9e,a476a0e9,7bda53c5,46312b35,f0fad09e,11b2810,b3f570d5,a934d21,7152009c) -,S(3366b9db,ebe13231,7c542739,4235a72a,f186bda1,784c7f25,5f8b65f7,f146875a,5ea2478,95f52889,42321383,5439195e,6b620619,20171862,eea32726,1345d3cf) -,S(616c8e6c,e52265ec,cb85ef36,5092b2bb,58bec6be,444c2373,974c38e5,e0e8ba25,4d3d5543,3d6e258c,d8b286f4,5f41249a,724a9890,2f1ef3ca,ba049bf1,cdaa0970) -,S(74df2177,2e38e84e,8b81d86e,f45dc4a7,2617b3a6,32094b1d,432291f,6a651827,4c32baf,30f09527,fc4abc6f,9c9b9a57,2a9ccf1c,6a1b360c,48746d8c,22e01334) -,S(1814a1bf,76b74532,979966d1,5ef42faa,532f8dd9,bee0cce5,d68fc500,21accbd1,5f5df5ff,da9d439,b2205ad2,5fa93b9b,7af1746e,9b2eef3,154bfbad,acd46bdc) -,S(28911e94,98ff7526,badf2287,8e85fbdb,5f444d66,c422a975,c7476c02,b98625cc,5a341cf3,5cf26006,9d869542,fb221ba6,eac150bb,e3809ada,5e4c903c,1e638537) -,S(d5acff71,e82a455c,3a1ce292,689e8686,f441ce1b,e644e79a,bd6d0efe,29270865,aac6d48f,1b46e970,a044971a,ad13f033,ca8cde96,958d870e,dc7d80,1d26d5e8) -,S(5cf51c1b,2210d85,9d765e17,32109514,8f03fc57,51004b6a,91f098e2,e2711596,1eeb19e0,610df459,2c31e58e,aa2a2148,17fe9ee,a3995838,f395bdcf,26d5c3b3) -#endif -#if WINDOW_G > 14 -,S(21456873,b58e3687,52c75800,8d3bcae,9efaf1f5,c5727842,25e3d854,8fd421cb,a2f2d10,c85e8a0f,4a136ad0,5df991ce,7d3c5585,a263d5cf,da50a4f4,3db76cb0) -,S(c10de5c0,51ae2d73,28ac06ca,cca840b4,ed7ab204,21c6122f,1d68fe7f,7893d38d,ee30e086,a891484,2ad4041,f9ab9c57,cff1a315,f0642d31,b31c2914,faac99e0) -,S(be778032,f12c1b77,9bba3d9e,d290ca90,30ac7050,bdd77a2,7eac09be,eea65c0b,8657348b,a1e27a63,1dd2a54b,e2d5270f,4cca817a,219c5378,4d4f73ba,2c932e63) -,S(a05e7551,f8f090c1,bfc8ffcf,fbf7fd57,9d033163,67d5ee64,b85c4f69,33d0ff6b,8eba561a,f42d43c4,99e1fafd,43b49698,a8f3babc,c9c94c4c,4822cbed,a741b309) -,S(6e4d47f6,b17501b8,f3b220d3,83cf5f11,a395c0a,f0023988,c4e7b8b0,ef66ed23,e01c4330,16e3e6a9,535f1d40,905e9b3f,8be9f05c,b53e6143,e81091f5,4b76b57d) -,S(f626750e,b7eacac1,7cf24afd,43345019,c6c32292,c72503ad,d4125d40,67b7e66e,d669f903,67f407d4,5307578c,ee91fa01,f030bb9c,b66c7111,34b91757,1c993f4d) -,S(437acc60,c555f7c4,778595af,db4676a2,1fc8b3cf,2c8538f,cecbae12,811511f1,985fd2c0,7385fba8,4cf25a1f,46cd2c3e,de8dd359,1c6d20ac,584b4a8d,8a65dd67) -,S(8d50555c,6245e43c,a619fb76,ce45441e,dc585c7c,4fb2f33e,1c07965e,d4e35f5c,ea828c37,331ad0aa,44d168ce,c328a9f1,c7deaa35,47ee4757,c776fc46,439ea5d2) -,S(87f5f6ae,580ebfe7,1b2c19c8,cfe770ce,cf8d4223,62718914,eb853f1b,7f4cbaec,eb61df09,12e06f58,ed6d85da,7240dd72,aad00c3c,6a3a9c11,1f378664,cf359386) -,S(c1cfcacc,b95e6577,4e2a7d12,3cb0071b,3325c27c,5d58beb6,781a30d,ff6306d3,fa9ba55,cd95e721,12d98a19,8e3769ef,8cebb355,dde5b62e,e6f3b8e8,52a3e81d) -,S(d68bf50c,89f25969,a765af90,854bdb89,d67acdf8,f1e16bff,64868338,8b88e311,b62d1866,55835dcf,8064e13d,aca1e896,2157576,a02e178c,78d27c99,9cce81a9) -,S(b8d7c25b,8c20438e,702197cd,a3bfc05d,c6577717,c9b6a527,15ef84a0,2c0df867,316b527d,4be0e62a,2015f15a,17a412fb,72ebbffd,b02e53ab,6e5e9791,b771b45c) -,S(d98b3403,a299106c,9c6fd52a,8abd9ee5,cea9ab0f,17a15b4,7eafc809,c34e356f,bebcd24a,9300c739,9bb3af8c,12fa813c,78c6838,dbfa00a7,4ab09669,4df9700c) -,S(dcd15a1a,7cccd53e,db08c2b2,c6367126,de55cc46,a4eaf5d3,335ccff2,1238bbdc,7de57d26,bf74764d,bcc7e15b,72ec272c,58061f47,cc0715ec,48bcc032,60e63a81) -,S(2f6a844e,e758e3cc,8f299e01,ba5753a9,d35e6c51,6a87a683,8f5ce28a,fca17c62,5c29172f,f907c0ef,95e78768,2625c8ff,27e26eb2,cd86df92,b9371203,8b332e73) -,S(e63add7a,e511eed6,93f62498,17f89221,c7a3a909,253faef9,23f37a64,9e2a2f67,c392df22,5ffa1438,c3d10c6f,813c3956,4f94367d,6fa26c63,1d562049,99a77e0a) -,S(f9955ec9,20fc68b6,cfcd163f,34bd033f,4ed7dc8c,30da7f16,e41adb,908c9b7b,4dfc49e4,ab583975,90bdfae8,56ce97af,91c92f60,a17df9fe,9ee923b9,9fe2cf14) -,S(d974d713,bce1db76,c5ea1143,b63ace02,5a2362ae,fe6b84b0,ebb0c49f,22341d7c,991181fa,3ae5f188,38a94047,9ea9e4dc,e8ff9366,78583189,bc340d2b,40481577) -,S(4f0af691,424d441c,698dfa3e,c3e56bea,e2c52fa3,bfd9ca45,763d7805,33a3037e,caac2486,81590630,b0c67160,89db929d,26a4e15e,b06aa9a5,2e19c92f,a9f9817e) -,S(ef6300a0,70060df2,3f9818c1,6ff4d315,fb1c7d4d,fef41e85,c96760d1,3cea49e7,a0622360,2def9738,d87803e8,6405bc00,88afa82e,39666246,10f5d935,993334fd) -,S(fef30954,1cd2a90e,1d473ae3,699ea7cc,ef69fe75,54f7d710,33b1f23,c9e96886,c2479c48,59423c87,5d76f6b1,5c671ed5,c9489af7,79266341,4ca68675,cab64fec) -,S(457cdf17,b1230409,c3d35a88,390f1bef,859994df,3ba21d2e,ba5f826b,6dcb4fc6,5aff71af,708863df,3074c236,446ddd33,5695c0c1,a45bc482,e0787788,a0e4ede3) -,S(a66e86f,fe0e9cfc,686ab0fa,11b641f4,28499f3,450d69a0,dbce1895,6181ea39,de0cb1e5,ca720556,7c6756ce,868df6b,5174887a,61afd354,653e759d,b3e3ec64) -,S(ddad5a09,c37f0de6,67eab59b,fa2cb47f,b79bf6f5,b8b0403b,f689acfa,627f1014,8aed1b91,c9e567b1,9806082c,79ec433e,1a152279,69df00bd,239fd8f3,f8e8d385) -,S(45c5156b,f1439eaf,16a43b39,5c0a393f,a674e17f,76f96d53,9aa6c99b,49042c42,c9bcc2ed,c5b5c8c4,b17d633c,90d45b9e,1583898e,41bb9d90,1d1b5097,57f5f516) -,S(c83b3c9b,564906dd,60049c3e,9f6ed0fa,b848366c,3b93650b,7923e9ab,8172a8d7,5709dd74,1326ab97,8853304c,a02315f1,1f0bed5e,bffab6f,467816b4,4c60a332) -,S(a857354,dd08dc83,ce7b0324,7594e4c6,99692c95,9a4887e5,344cd0a8,7970174e,becb7001,ddafd72f,1f845579,ca8d56d7,2145c8a9,be816924,957ba324,3c396691) -,S(8bba6b47,88259a19,578adb4b,6f7f51f8,d09eb70,ea790d62,abb2ed45,84f94f33,afa42da3,8526a485,60919f12,d30549e7,1d19608a,81f4cf6e,8e49cb00,2492b143) -,S(bb4d27eb,412e73ca,d2697d6c,46a143ca,e4420ec9,30440025,47aefb71,c99a53d0,9ec07a19,842a1e5c,9cf9f76b,55ad98d1,9485e683,b6b6700b,c905e190,bd9da19) -,S(af6f6827,d197688,f00dd3f5,ded1849c,11fc2abd,f90fc7f2,18b33776,e5753277,f9227693,c9405a2b,10e9b725,aac7ed35,eef4281b,ca04e,bd75b143,89323646) -,S(40453814,445cc67b,e7a4b71a,55e0b993,2b8b3477,f093df6b,f27f55a2,8bad2e1b,ec71d7d5,4e823687,d01d7558,6de9a1a3,7edc927f,e221941f,46051747,a69baab4) -,S(f35a6c29,bd596f0d,93cabc3d,c07b5f68,300f6ab,8ecde5d5,da8299d,112c7bcf,73fe2c46,e1b13112,718526f9,7a39f1f0,3d47ced1,84a2e4cf,1e32c168,1c470121) -,S(ecc7ce7e,bbe5da1a,596bf41c,4d19b51,b77f7019,bc431aba,e5ecea57,b095fa93,1ab89d03,9e7c6ddc,7751c9bc,4eb84ed1,b077cc8e,dc828ffa,37426609,e089c8aa) -,S(559820d6,bb3e47e,f68f48fe,1259da06,cd0b380,1f6bedb7,970c079b,7e373bd9,2373137a,a4d88574,151540cd,ab8cbdbc,5831fb7c,4b901c27,8c9a593,172a64e0) -,S(9c9b7e18,4e76bd16,856addae,9352590e,310d653d,809ec800,415f3c64,149be4a0,182cd167,55eedfc3,21d71199,7543b26b,d08047d7,c9363e23,20bb9516,da37a146) -,S(88e4e3d2,2cc3e6f6,19e62ffa,c7a4aff,63b16733,202e5410,52cedde6,9cda2733,ec6e32aa,498a7a30,e1c47136,5671d356,bf174630,d1b984ec,d9453e24,d275e067) -,S(7f2f8043,8e7d7fcf,593e337,a91b06ad,3ad1c461,fcee7bd5,82df516d,cb1c198f,2cb484f7,5a4472b3,230369f0,79f5e654,8dfdce60,98c4e561,a1310224,13dc1d80) -,S(fe0c5945,c5e67d74,ed498120,dae194cf,33a3fe5b,ef0f1ac,2c64c292,59827d7c,4ebff1a1,7d59c8c,469fad0c,79ef819a,8a897ce4,c0fa1121,741c03f6,cab0f659) -,S(ac0662e0,1be37c28,be457bc9,4af19e72,34a9d3e0,8667c009,ec58ee79,7e539642,b3adc375,bdc81a76,8385c9e7,2ecec61e,9b2b21d2,55f65450,c5956187,837f3767) -,S(15e0f7bc,d74e77a,af933c13,6cdc5b1a,1622de61,251090a8,f8509b05,d7dd527e,4d51a063,1fb81f2,fa1ef534,5fa306c1,a0c64f94,66961cc8,b574b06e,646767ea) -,S(e4119d0f,b79bd8c,e1687abd,4ad63790,814f9972,50fac9a4,f1b52d71,93ce282c,cabde097,8f9a566e,32ab229e,63bdfbd3,89f01378,c7d27b0b,f101cc3b,36bf3fe6) -,S(27a5b030,2005a21,5d89c0b3,4e4ee323,5e94742c,262a89b9,29e286c0,ab8e3c24,4548d58c,3792f7fb,18238cfc,993fdb26,f755379c,e0ed1b0,4df26132,8f987a02) -,S(a18ec59f,7621c8a0,59bcad5a,12d3f536,142d5c94,4c7a54d8,b9206132,d993e08,abd8204e,867035ac,8cde70cc,f7daa29b,d47b888e,1faa9be9,b20744e6,ec5a43a) -,S(9bcc19a6,71b787cb,9da72c91,8d7b2264,b9497ab6,313de85d,c3efbeaa,2f492219,4bea790f,67b8100b,9ad9a301,61e3bd9e,583daec8,b77f4628,568ed554,70894bbc) -,S(7ccb2731,cc3eb3a3,36d36af7,f44a0a64,e23aa0b1,12ba0e6a,11280c5e,1ab36205,8d60552,1813ede4,dcfcbe46,c75c5aef,7ec40c69,99cf301b,28b0e875,3031c6af) -,S(94107245,fa13427a,7d21f7c7,cfe0c4e3,2943821f,da0f77b4,23fde091,ba596939,89846c62,7868b1c7,4c546492,dd4821d0,cfe15fae,36896af4,547deea9,295ccf84) -,S(959bf7d3,989d3460,5f4b8f3c,cd12ed86,cd0a2a93,a8d4e1fa,aeb5d6bf,24f1115d,7cc703f3,5417d7b2,b7229626,558be68c,66a915fd,7cc52829,dc98c81e,c0162b7f) -,S(8e92173,ff2de4bd,f468e2cb,fbf6264c,5fff8f23,2fb57e1d,2a07ee75,3b45e7ac,2655133c,8833040e,4ef4c98c,e5c75818,be781f42,cc0b7314,7baa3ef7,99cc017d) -,S(4acbd2e6,98f349cc,42998c5c,53de7b6,3dc29b1,c2b8a569,48cd3489,190f0255,8837f8d4,15b3551,4544878e,1a71922a,ba4a0790,22c74b60,325c6f49,a411b978) -,S(f79cfd2e,b63f6be3,bf0f12d1,fea3524b,1188959a,425f5e38,fa569648,df433fce,9e412cf1,698805e2,a92114de,5694a925,17c31f49,ddca7e0d,b2d83d80,74d92b2b) -,S(41910c81,78f7a61d,7957c065,5d7e2596,a0e6d5e9,a0a9cf23,28f23569,5d818c76,26b318c7,e8a880ec,94c59a6b,d6f1cad,84031d0,e62ded95,1e265ba8,c3603367) -,S(5a864466,9fd276ac,ad8782d3,51bc27b4,9445835b,75f70a80,2ef42a0b,4885cfe3,b2510d98,60be4e66,edb8c935,3c8ff8d,2e008c37,6dd271b0,1f77276b,f3a5a48b) -,S(5e3974b8,1b87348e,e3ae5c83,2dc56d1,85004b16,90445b74,1b8e262b,ecfe0e01,63f644bc,397a1809,a4d57ba8,f18f0372,cd4fd083,1c3d3449,1ef2a654,46275568) -,S(154e9c88,589ff342,6fe2eb5e,dd6e1db,e253498b,2c0b3e0,52e84211,caf9cc4e,3a897093,df7d31c3,754f84c2,68b0594e,85cfd4a7,c2731fce,e01cc3bc,2bbc383e) -,S(b95aa134,e48967f1,bd3a7a48,d89d550e,3c3c3c6b,3c73de48,f2e6fba1,81c93faa,b6f2d3b8,8d0821b0,6b1134d7,ddc898fc,e84898fc,4719f8aa,e3570daf,168b03e8) -,S(316564c4,ff00502c,f159db79,62984516,4d6d24c9,1f20ba73,66669808,95e58b92,6110a6d5,39ddc,d4185b72,cc576b7d,a4577e80,3dd47a92,d4bf346d,ec5905f5) -,S(222b179c,29ff89ee,d6f2a0d2,d38c6246,33237c5f,7803d8c5,e4315f93,6a9bd225,8bddc333,6eeb3cee,a0c3ac01,e7caf4f2,f44a50f2,587e3e31,7046c85b,a57cb6f4) -,S(10347fab,33fb4ee5,6cbf75ac,6cb768dd,f51f9b0c,5498466a,6679439a,32048904,a351f45e,30f32caf,e10d99f6,9e9e4be,c3f4aa22,5388984,bc45bb78,c0c5148e) -,S(7048c0f3,1e600042,4544e9f6,e26783d7,baeb411b,a2c29c7a,5aed8953,bf831629,4683ad69,1d9f14a3,f67131bc,55d28c61,1b78b2aa,329668fa,8fc41736,c95840f7) -,S(a65f7371,b35de05a,78b71171,40ea9e02,7b777785,13fdcc3b,484ad9a0,4bcfa1a3,41d1268a,77b31744,5a270f73,956bbcfa,3f291770,d248d1e3,364b4aba,72b961c6) -,S(dfa35552,8518d1da,ee31f04a,2673d053,11db4eee,cdc81f15,bce79c64,3267a315,19ed047b,4fa52430,18863cd1,d8ade0d7,dad60ecf,10b767ab,52f5cef5,9eea9a8a) -,S(663ec2a0,80564f1f,943a25b7,2f60d3a4,17b62130,3015e17c,85782460,c601a48d,fce25852,5a4dbb52,4057f8fb,a4393116,ebcffea5,5ae3459d,3d8b19b6,a0387232) -,S(cc714eaf,26f9960a,b2cb139b,d2fa0928,7a309c9b,ea852537,e10b6333,2912431a,c1c5c0c,48c98ea9,b57eb13c,fa64146e,67a95569,b45b8643,7752b037,9269d070) -,S(a6ceed6a,bb8f1ac6,13799527,38a19b35,ece44537,e74e9185,a4ce3939,c14f8e77,c0090ebe,d410f2e0,2e56b4b6,adfd5495,488c2930,2c5e7a61,3926880a,88beedae) -,S(e0b0c34c,8d4f77f1,dd09ea34,8b0ec683,cb5ca777,6720546e,27ffcf55,a5e5bded,ed4adb20,ab5da65c,2d1d5d68,9ad63ebd,90170904,65f7ad03,1bf3d811,f407d09f) -,S(2362ff0b,9a2d0f7f,d779a83,8b26da93,65730d32,bc4411ef,fc4fd182,d9e486a6,d3eb4ee4,42bd6157,557e4e9a,dcc9c103,892ca05f,5c5af804,f736ecee,d8a6fc3e) -,S(2f1636ab,a1516634,a00a464b,aa30c507,af25e83,3f7f6fdd,ccf0706e,d5fb57a0,a664c955,c24a54ee,d56f1aaf,fc853c2f,6a81c53f,1ee36c48,46b26452,fcbcc054) -,S(243a8fff,6230829c,73368eed,fb4d62f5,bf478b4f,1752400a,91ac177f,70c303ac,29318b21,9f371dfe,4048c4b1,2f5317cc,b2e9c44f,ed72b537,a2f56d06,65229235) -,S(b17182a8,5f442a65,839230ca,5cc8f67e,835e54b,e0296c6d,e2b62298,74ae804e,11a4fbcb,9f6f8775,9d131a81,939e0125,7f7b4fca,e36ea644,4da3cc16,a161e5aa) -,S(5c9abfd1,9cae1a47,bebdd324,d11cf758,a1224471,6e83795,e42ff5f5,a8142a6f,38a38db6,f64d9d07,4a08a909,28768bdd,adbdd858,79ec847d,28c94dd3,a122e0d) -,S(44a8a4f2,ec3dd02c,226ae0af,d73a12b9,726e03c3,2a41099e,b70cdce2,767e390c,b7e18dd1,e6adcd88,1d1dbead,e1c83ed0,1f1d7b2e,50246539,b6bc2811,d63233b7) -,S(8e477766,c4de01c2,5cc17218,7f3cb6f0,dbc8eb54,fa888911,33131b7c,219e6e13,ba8f447f,10286c86,d1330c82,2647a999,b4b60e56,4131986,a6c05128,a480d83) -,S(c5f862ce,dd253879,8100eea2,92e860fa,321d7709,596a4dfd,6faf6345,82fcd3ae,81ab1260,684fd3d8,1b47c5d4,d5f0c319,93ae7db4,fed1a781,61d9d9d4,50ff831e) -,S(a674db01,836fe328,8566d977,753ebc2e,d55f0116,5ebf0349,51caecd6,ebf899db,12ae8327,737f7db3,56e26fb4,1ab306e0,2294136d,71206f43,78300b95,60f580f) -,S(b0cf999e,f11dea14,3e6b6254,aedf30aa,ba1e8e92,96c500f5,481eee45,a0e15adb,e4970d00,e02adc6a,be5e2433,7e017dab,17a61de1,d977ee99,969591,91a5563a) -,S(b3615f09,29f9b2a0,6a4c68ef,c844ae5,54959ffd,f03f9266,f918f16a,b517380b,31a7675b,83677cc6,ca87c525,27fbba60,d06ea317,fefb17a4,7d7a4242,3595f1d4) -,S(7be97bde,b271f807,96930353,b82c3cd2,c6cce373,198572c7,d289511d,7cf262a1,1af89a8b,cfa4a399,bce5bc21,e26c97d0,5126f8c3,211d8051,626c4f2e,c6f128b6) -,S(692e447d,df9c77f0,2db1d34,101bc355,519d40b1,3fff2cbc,aafeb555,29473d4d,d21950ec,fb7bb723,4e4e48c1,98b93a10,8a85bb5d,5228116e,da6f5cfd,8968fda) -,S(61b6fe3a,21b0bbd2,dfccad11,5123db4a,98058bbd,4f8a61b5,e416b03d,b1414243,75d3dabe,f3e2266d,65d408ef,af6b32da,7591f08c,7fe7de,ff20b9d6,7a3a8a8c) -,S(fe0f9f,aa49555,2afe97f,8462869e,e8a584ac,3c3fba4b,886208f9,fe260ec2,a9c0fd7b,cfa239a0,299afa47,e2861197,f382a331,7607e129,967bb22d,3ae3077) -,S(7f7c9a0,a240180d,c645e77e,c628bff8,fff90d48,c85d2fdb,faaf76d9,b93e26a2,1b12ec74,f801fbe3,ddeeb37b,c940c605,84b0ef14,85e9d888,f3f81c05,607d1222) -,S(3e444ef3,b77b49c2,75aa0524,77da59d5,a68dc6ee,6288e2ce,140512,92e54c60,e211ba3c,6860a898,9e1ee04c,ea9ddf52,25ed88a2,c6ecd9fe,3c2fd500,88367b7) -,S(4844747d,d33f7e4d,39aee79f,138b5fd9,223b4e51,c86e4894,c917a3d4,746d824,68cd147,2560b5d1,6b9bf538,b7f1e193,d2f220f9,ed9f742b,d36a003c,28e2357c) -,S(f0211c1c,8f87fb96,bd591255,6a799865,7382380d,6b5b020d,9095f482,4e8f531d,649112c5,9cf7a8cf,7f9d920a,6b6d1102,d92441f1,1bde7561,9cda8eb4,a26d7493) -,S(918118dc,15520a31,c715adcb,3e02ca4a,4d77c92e,310ef057,3f9c7a4b,d5d2d54d,37d2c580,337de379,925506ab,c6b7d9,4a61584f,4cb2179d,560d3a7b,406873af) -,S(78734d5d,833a5d24,5546e5bf,9d3e5ce5,61f818c4,a4c90fab,c8ae4630,a2c307f4,4b150c27,e054fdad,73506310,80eb5308,b39c6861,23b851ba,aa2349f2,c26b5981) -,S(ee988075,34a02de2,9fda41b1,c821c41d,3ddd5d85,9c5a4ce0,d14ad743,25943f13,ba7fda65,4389494b,40a9fbbb,4b72739b,6f85effe,245b895c,b8c7e423,8d6b7973) -,S(4a821b26,bd1326a8,26be6fec,b90229f7,d7a37a2a,c49e97a2,5bddabef,e854e509,8a645892,37ea07bd,929aee46,6fad63bb,5612de36,cb951200,b9faaec8,b11bfdd8) -,S(23658500,fe8b5ddb,93dd3b50,a46f9914,d04af9d2,2a786be5,9c0fa7be,7c3eb2bf,840e5cca,f9f3e8bf,fe51c1d0,a84de234,d7122cef,fa1f0ed8,9f1701ff,d17c40d3) -,S(71dccb97,7f8e77f5,a03c8e8d,e4b2a30,11d01e13,549949ff,42af13cf,d7ecf208,b70ad10a,5f03ad94,dc8d91dc,e7797eca,6ace74cb,4715bf6d,2b628bd5,f767f34f) -,S(6174a230,e15b2584,7a25217b,9d95f07a,e183f2e4,74d0503e,108994cd,69d20e6b,18cda952,ccd68c2a,5d78060c,6849fb21,e2379b48,425003c0,6f148a34,bf876efb) -,S(57cfc1ee,38d905d2,897dee9d,105fd4b6,90967618,2a2a5d3d,70781cc,9134bb97,bf6b5fa6,4de9110e,7d26e67f,65cd2765,fcedc182,1627243d,a85bc955,2bdcac33) -,S(26605be2,e03705ea,7f199cad,d4d6e711,9805453d,6d4feea5,ec2ae3f8,cdba59c,ced5f775,b62bddf,5935acd,9786847c,e7825da1,5807b117,7459f51b,72fe5774) -,S(6d89e2a6,9ff96c49,a3110a5e,7e17421c,4ca2d07e,6e807a3a,98d79954,7fde2457,4835767c,8f96da1e,78f1788,d9764dea,e4e4a0cd,238ff35d,851ee7d0,9c915df3) -,S(e3607608,338f4229,d77c51fa,cef2697e,f6010c8d,5138e0c6,2b724ad5,6ae79a74,da6a0617,a42d6ccb,44155f27,7c56c58d,42d6037,d234f1ee,ffd720d9,2ae23373) -,S(c8cf20c0,c12de1ba,1ad4dd44,46f76533,7cfefc3e,213c426a,e0cd25ee,2e8bea9a,ef7285a5,ea7393a0,cd78ea31,ef74f605,3d3312ba,f17bf6a0,77b919b2,33227ed2) -,S(f3d2870,fe782b7e,26a1a4f,9c7c3ba9,30e0ee0d,df6593f1,9bf11509,1fa63477,e470c266,ae26fadc,b2780985,9b9d60ca,fcbd9de3,5dfdfb67,9f4fd450,4ed6f3fc) -,S(702a6778,bdf2f3bc,4ee954d8,1e7acda3,1df7127e,a7920e59,a7028253,9019c6c9,2ce19ef9,10d773d0,cc32a503,83f9e968,ca3e407c,c1dfb652,377d08dd,1dca5b96) -,S(ea85cddf,4f79d7d2,a5db06ff,f1c1e3b0,87b0242e,1d7de713,53d8f73e,1bc83888,3806d40d,ccd867c2,2d166056,77d2d64f,d7433dd4,b1e83e25,91860599,2e66fb83) -,S(d0631e8b,30ef6467,de6af60e,61b99112,1949b324,786ff1c2,fe633249,a832aec5,deaf31e3,703df166,b0f92ee4,eff1cc02,684911dd,40054bed,4b21d4da,17f4c05c) -,S(b56cb88b,617a7104,c205e089,b83320c0,5dce438a,50411e5a,d342e9,8b258a3b,757edc72,52d76fbc,24a5515e,417625ae,11db0072,24c02fe1,1e249064,b5127800) -,S(e91ffec8,bc3fa3bf,b0a600b6,89db92ea,7c3ad411,d025a42,95570596,f44702a8,38fd56ef,1f7b476b,2e36aff7,73e190b8,61ec6370,f6ae524,d5dea16d,cc4833c1) -,S(4cd9e6c4,8bf7b1ea,9f855b14,fc904ad4,5e3bb71a,5745b449,e1ab3165,3bdf53b1,b5a075d5,ca9060b7,7d3a00c3,6fbc6404,88df6846,c712afdb,1115798,f382b4e9) -,S(abb07ce9,c4b711ab,d01a12ba,45f0040d,e3ff5a4,e59140d7,cf4ff289,42b5cde0,a8a0e68,350a88b2,397a162f,fc969d28,ed937f60,4704dcf5,2faf755b,d21f503b) -,S(95fac51a,c9deb5d2,b794423,a71cd282,b0604afa,bb3160ec,557a8b74,c578f18b,da99fcf2,abf21cca,c6f4e89b,de2a6e9e,ad199cb4,b97f4122,4f68bb47,b7caead8) -,S(2ecd3e62,b79b4f69,609f33f,2042b56,bad2a9a4,18e2852e,9e8f0d41,1fba8ab9,ef964275,95061068,478e11ec,942b6a2d,99e5b557,830ed0c2,c4291305,41104046) -,S(437d446a,d139d88a,b5437f06,6fdf8acf,7b538798,6baf9551,a414fd4f,101a6440,6c532bb3,38a34a07,28d3273f,e9d9c70,aa79c484,6cb337ed,b41f6029,1e2caa13) -,S(63149b01,94b4955c,1b7e9d51,24e7e7d0,4bb5d902,7e86e63d,f3add9c4,8ab2a44c,c867234b,b4ed27d0,dcdf544,be060a12,4c460c5,7a9312b1,46d2bb61,fdfa6c1a) -,S(78e509ae,99e6469c,41c44dd6,868ee402,8fda1cf8,2c83be01,9fdf912c,1e638bfa,ff3b584c,5ffcb1af,4980e2b3,ace00f12,3be630be,cd91d045,4e031120,245e92be) -,S(cb1d5bf3,f97b2bc4,bb33babc,72de78ea,34cd0a0c,e841cb55,7b3dbc98,61e1544d,e619e8a,dac79a61,eb46add0,96bbcbe1,31d33a6e,b6c99220,123dc9ac,3f27df60) -,S(3247eaa3,9ed5b604,d3038127,9661f350,53ddad8b,8e29d0fa,5c27ed6f,551cf374,1d29a713,d7dd351d,87175b49,afab518b,f268ce81,7fa39ccb,f08b3c58,de1e5378) -,S(d493ab52,8d6c627e,aa3dbd3c,8d809ba9,8a9fe920,307a0c66,2917f8cf,f68b3941,30e4336d,e1621a2f,fe7247ff,157a37c1,edc4f83b,e9fbd84c,af4f96b,8997c7ad) -,S(8dfac8d8,b65eec8a,a65f96b5,571830d9,22469450,42fb2baa,f76a4db2,ea5258c6,c204e9c0,72f643a4,1f53d8fa,dc66e3f0,fdf0d000,c27a5492,6323b2bf,b376af16) -,S(331ca867,1098b530,1b1e6f12,d231793c,de67de5c,640f0a1b,fbfe485e,5d2adff9,b52fb89,3a466c80,ae61d534,cb03fde5,95078592,1da21e0a,a8103d7c,c2e3d8f3) -,S(f34a338b,bb05db6d,55beb49e,526c9d49,fd515792,f407397d,3b520fda,3ffcf26d,6a6921c,4831df6d,91e7cafe,869c4274,faada27d,9d09175e,e86a0b9e,dd70910a) -,S(56d97dfb,284c7417,2e08fb73,3a2d0305,ff774495,2f229bed,cd36e7ff,6058e75f,3775df48,aeaafe14,a8005434,dfc19538,2d10ca90,d05bcba8,edddb2ce,4a4ed7d1) -,S(70e668b0,e854cd8d,d3469cc8,ffab1709,2d9341c4,4831196d,72d9673b,43dfbf7a,60567ba3,5546cd93,f2c356e3,927dc89a,c43fdf50,5e33ca9b,52552587,c905e311) -,S(675af615,9fb50100,56ebed3f,4c9784d1,17538d58,afc5ec75,fa93ee00,29d32390,c501aa90,4f9dfa9d,78107844,983e17b4,34872e3a,a94e37fb,6677186c,fa1abdc1) -,S(99f8e5cc,86ac5587,81a67270,3059442,88b19703,551474a9,9d433d6f,37672d90,30148ff0,9fa33b4f,f4410d57,9afcb705,c1146663,bdbd0fbc,8434f4f8,eacb09dd) -,S(8dcec207,3d74b9bb,bd47f52c,394b263b,e71881af,363bcd80,9adc345c,b9ce9892,d8bc1ef1,79ac54e2,68a685a4,db35e3cb,5b6774d8,e8d6b738,f4d65b66,86782a5d) -,S(d83f7e8d,adf27d5a,f8502d8,3ab81001,a2219805,d942cbfc,76db2764,c4235773,48472e1b,2609f81a,8b12326b,1b19b422,763b0ed9,d6fd67,51751c2f,8aa46c2) -,S(e6f8bcf5,d9ea8209,cb46ab60,643555e0,d0569f3a,dc62ac76,edc09a43,e02fea2a,7974cbc9,5a9dde1f,34560043,7b628eac,3641498e,612c19d9,9a79ae4c,cbde2d82) -,S(d2f30716,e4c1a665,a37d0606,3987d0c5,c19c072b,f1cca8ae,cd0e4d8,6a9e8c1a,e26e6d9,9fbd198a,ab83d0aa,ea53228b,539efd37,ee7ee791,365cabd3,8850eb29) -,S(d7a891eb,551ae5ac,baf366b8,65755a56,edc7bbce,7304a806,2729655c,f7f61cf8,8a7d915c,3a9a1500,616205eb,798915fd,9b33d7b0,6671e9ab,cf02b5f4,667173ab) -,S(5bb03484,f02ef87a,fa07f852,e3ec0664,67ffdc38,39fa28db,de0da07,2fc31246,e0515751,c377266e,ff95f755,f9c9373d,226ccb66,3678e8ef,176af5f,2fea3504) -,S(58716b31,48a0cac1,2024760,60d3734d,ab066ad8,c0f8d8ed,cf5824ea,83e111ce,71ae487,701d16a9,c1d2ab68,1ec7c8b5,8367a4f0,179dfc18,6778579c,553cf608) -,S(4a344869,db8d561d,96944c8,94a3c196,8d649fcc,bd430c7d,4a66ef0c,dc2ca550,285433f1,ff0e7dba,5bae081c,1b33c762,6f30224e,dcacfe66,46787818,da0f810a) -,S(3ecc369b,e7789b92,cf1448ee,28c0448e,ebc5d277,a8bdb5bc,a22d3151,5e246f7c,a5532e1,47848951,cf11e065,3f0627c4,6530436a,5f3773f2,b02c9bea,c1b60e78) -,S(28a5d794,21db38dc,8d7c8cf9,d120a3c9,97eea170,f0f6ed43,7222bf4e,27f170be,88cb09e5,ea40b566,39cce9ee,1245384d,2f02f983,3b3116b7,31ae5576,daed7cf9) -,S(4f54f945,b3afc07,c38e1aae,16dafcbb,b7c5097e,4895a789,e70e0993,cbc905f,6ba69303,24adb3b1,2fc1f8c7,8ea58729,5115adad,52bb1138,7281b9b2,997fa597) -,S(f490bc4a,20f1ecbe,ac2dbbd0,56f2bb77,d258a914,9b0732a,f29aef2f,7ec25f47,aec6fa89,74c124a6,576475a,60931a6b,533d0da6,4e621fe9,c298f03c,a894336) -,S(73b2f8d0,e91e2516,d2ebe348,85b973d,4a0c7919,1ac857b4,74f713d7,348d343d,9dd7a951,efdaa060,19ec71b,e41b294,d047ab97,d0cef4ce,25a607f2,f11bbc26) -,S(d911f5e9,977489d2,847aeb66,8c3cdc6a,ffbc7b5f,4a5aff62,1761ee01,567c5647,3ee4afd0,2ef6d3af,a2b16d34,b59444a4,2c70b3d,4db17788,ad3aac57,184e02da) -,S(87b695f1,5c5d7852,88218586,96bca8c1,9c5a6f3e,f23786d1,fe010fd,d063b0c3,21b54a,46ee82fa,bb5ffe0,e3137892,31623502,9a8e0505,645a9ec9,29984895) -,S(39de5a90,4ba6989e,5d16dda,a7ff67b2,15e08f3f,b593d7a8,4b6babe2,ca25c658,eaf5e6c4,1e1e2fc8,c1581f6,211bc8cb,34dcc08d,58f570a6,e6719626,7124c019) -,S(18c1f673,ca19f805,c426162f,11e7eaea,c675974b,6b4cf0f5,9eb03288,83bb0af1,ad1690ae,65783091,27f602fb,93652b59,d7507414,e76d9b3a,82fef166,68b7aecc) -,S(8d70ebda,893e8d03,d15fbd68,67528b7d,308ddee7,b2620698,15e7f3c7,332d42a1,254be26e,d9e9009f,e4aceb8a,b97020a9,9196a9be,60777fb3,a9d1243c,66df1707) -,S(c32fa0af,ab39b1c0,c96852cf,8e2382e3,93e5b59d,2e83ed50,d5307a0,14ea330,381e8afb,85d47c3d,dc5da037,d6bd82aa,ff2324ef,ab0e48d5,5da3fcca,bf0ee3da) -,S(c350235f,e5ad084a,1aaaee80,d156b302,d34ec03,360a7c0d,3a883cb5,19f4b27,e5ea7c5d,3184e9,b62fc3a9,6c8bb9ae,72535fc0,497f1b58,67bbae06,672a1f79) -,S(8ef5e1f4,8d905df,dbbba4b2,d4b22162,db839ba5,b28c755d,46bc2f00,e25e20d5,6300d9e3,11971dd8,a3e88192,84f3a228,9986270,45b901a1,80f831b2,4153103b) -,S(9b3783f9,c638a6fc,166aa2a3,3a40d95f,35a4e7a6,c8cb5fb5,1e596b9a,f285279c,41b2dd9,c3abce77,fcf798a9,159f36c8,94b55ac6,7c917de8,75b18cd4,e70dcaf0) -,S(c262215d,720180ac,669f0bb6,885dceb1,2c941730,93e561c2,660a4a1e,cdf0a244,7fea7ed7,f654741c,c67b12b9,f115aa40,ce427cb3,8c6498f3,8bd291a9,d73e9f2d) -,S(bb72f723,f0a16f09,7716272b,b905a111,c290c229,94f400dc,c6a24814,f41816f9,52a83ee6,53214a5,3ed2b13b,a367324e,e5606fc2,e3dc05ae,7ce0cf05,ccd6c36a) -,S(d896a5a9,a833d66,51b17632,70b03d36,eb423236,bf3b2b7b,6b2ba97a,f9282a03,e8a823f,ecec375e,280e0d50,49625dc2,1f48e269,77ab5eb1,b467d3e8,a0fccb37) -,S(198cb33d,9a2b790a,2d6fa355,58733bc7,f64cad76,e3921dbd,8d7a1f,8db52b64,c7e93702,ad7df0a4,94fba344,8a8157bc,eba10ee2,8f66f000,7e7f7655,8e6b4a74) -,S(4354e475,81d63d84,df19bd08,d98b2315,67a55550,477e1c53,cd425854,e67cd81a,a612c262,74d79c46,89734884,5b87ef50,29d0f87b,4a06e4a2,8ab36bee,ae6a6ce3) -,S(d956c71c,1c8b110e,19f96ffe,5709f2b2,83a095ad,977878fe,287de35f,283b2606,7c029c97,9a807375,bb589c12,a20ce37c,75178be2,5d5af713,f4fd4070,429c8d0) -,S(2c04b299,1775ae36,ed7d5b1b,d9b0e65e,fb2bff8,ab99dc97,2cd860fe,19b1789d,8b3f3b00,6d63c81a,86f225a,bd8e658d,c9c4c1d6,6787678b,6fa4a692,bc7f78e6) -,S(c7897c17,debd6456,a81f8d96,c0ea580b,db5daffb,5fc8e8e8,9c8612b3,7b229f7,f7334550,d20a1a21,c422f73e,d23fb159,2fb3d9b7,ca61d7b,6e124fa4,147ea63c) -,S(3b37b93e,ff554f0c,7e7f36b1,864ecb73,7b33a93f,6ff31d6,9ea18aab,a9487505,50ccac12,e071f469,3f5e5339,462a0cb8,66bde539,5842ff44,620f7acc,aff09a71) -,S(4584ea49,8a2785e0,b12c86d5,2b839212,f21b2e33,3b64bb0a,9713674e,66216547,2851de5a,b67354cd,6610dd4c,91aaf4ce,b75c4c97,26d524d7,69ae0ba7,997ad79c) -,S(c0c971d9,f5644eac,851ae8a1,d87b4f09,a802ae07,32d9b5a2,d9589051,f139963c,83e07a5a,2b7614c,c064b4f,815b8a76,6df7eeb6,449fdd50,5c43faaf,b0bd075f) -,S(370e8fd0,858c6fbc,f479deed,f35fef5e,80cd2338,90d4b227,1867ea90,6cd15b5f,ef382477,fd2dec6a,fce439ba,9b341a21,17d6ecf4,c8c8d63f,b5775094,6cedcaab) -,S(ad402a30,99c5d5dd,c7ad9631,b592d5a5,862e8d3b,5ed47dfa,c288193d,69366625,b8c0d468,5d0eadfb,9f7e4ce6,11c61f5,7098da29,aaed61f7,6a50961b,b45b7c5) -,S(ec16de3f,32ea8f58,c1dc93da,d1cabecb,5ca33ce2,e3fa3bfe,bf0ee989,f3ebf5f9,aeec3532,c5391ce6,1e23bea4,5b7b5847,2c36cb8a,6c5f1363,e457c003,b18824fd) -,S(5a51f9d5,f5c48520,dbd826b9,49f62f67,c299a228,259e09cb,b3bd6fe2,f4b0e60b,3c498d86,225a83a1,f506eb62,a2e530f9,511c56a2,eeed77a4,18ddec4f,4404b9f5) -,S(9696865f,64523eaa,456ea65c,40ca6e0b,12c6e6a0,211cf8dc,20963f03,7980b684,8f879d8b,491f11a4,1f0025f7,b35dc8e7,c71e420d,7d7d9001,bf5da111,9ad6c2c7) -,S(80c43c8f,6325cc30,8065d4c8,6e3d7bec,6ed85f74,412f6127,4fc3ae49,b1e185a5,31dfbe69,a48f1f39,a0cca355,f3d68f28,cbf3e14f,7d47cfc7,d9e82e25,19bdc292) -,S(54940550,ec4a6ca7,561946c0,65769b4d,d4683f1d,11dfda66,4aa2f8cb,8f1ab2d7,f41aef26,64466fa,ecc076ed,cd383d3f,132b4fe7,5a17f16c,c394b6ec,e4079378) -,S(a9787f8,42b3549a,9a3bea8e,4182555,99addeb6,416118bd,901afd9d,ad4c134,4efc4f67,65c7cf5,ccc2336a,e9eb14c5,a1361067,7632ce89,68033d57,4bc686b0) -,S(fa83e81d,63b85491,92e800e9,7a422ca8,35c03bb1,5579bc05,bdb4367,198a24da,779940b2,ad301a1e,205c0504,fe3ea104,cef6a459,e0479849,90fc94a6,871954eb) -,S(ae9a8d1c,a8a560e4,8a373666,544a7b9c,84bf0475,9de1a63e,4a20b55a,2f25c132,b9b0bd66,4c46edfb,ca2a0bb3,a94ff043,c00c1441,9f1df886,2aaadc02,e25017dc) -,S(a2f47145,296dd22b,3a6f5185,47ab0957,4d3487b6,8786f87,6758cbe3,5f4c0ae7,2ec4171c,15e7a82a,f6ace24a,60176f7b,6239561f,3c369a9e,efc80d52,3fd216e8) -,S(1bdcf82f,a7dd441d,91332a11,35f50be8,4d275358,f95df300,25187f2f,9828f219,99f12980,92a3ecf3,dbeb290a,67d72aae,6acd9cfc,c21918e8,9ff7ad4e,548d3510) -,S(b73c91e1,ae33767b,11bd329,361fdae6,36642d92,6c2792b6,e19b6e3f,947a5be7,b6502357,11ffe955,be5798d1,467eafdc,94df5911,29d2aaa9,b747a2ec,befa9d7) -,S(b23b4ad2,e983e556,e941a35b,b84846a4,40cd25b6,82487f37,a3a30eef,eef15d1,7010f10,88749d1c,f95e52dc,eae1a379,b87762fb,55593d32,a65ef0fe,dcba2485) -,S(e3aad2b8,96fe34ef,9d775743,6e70a70c,b3bb0c6b,8436e616,a23174ca,985fd8f7,5d6edc38,89beb099,dd191564,eaa83c14,3ef0b74d,7789590c,d6083704,61c6676f) -,S(2f22a14a,f69e6257,b909e3a9,50aab3ea,dc09c281,ec52e47,8c578f49,68910244,4ab723e2,43c71baf,d2aead8a,479a1a2e,fd2aba74,800b5eff,56ca46d0,532e81d7) -,S(93806026,554bae5e,9b91f534,f864b79c,81e581f7,bdf3b2ef,dd007e32,dd6872f0,800f8162,a6836801,d052871f,6892ba33,b2f60f82,89a658ea,a8af25fb,f9d9c444) -,S(8895d121,ad1f2be2,3c578faa,1e33656a,e9403ddb,a1f1aea6,1cc7bd03,817a46d9,4f7577d2,420d0d0d,7cc9ed68,ba3645b8,f9466f59,570ddf16,ba168de2,8cfec881) -,S(1838c15c,3bcf1189,546a9e3d,69fb8a73,de39c862,f5faa4bf,423e1dbd,29046ccf,49484789,1b67ea0e,2e7f7eba,4a596d66,b3ed9842,3ffc54b0,e9292a4e,bd6f5487) -,S(111e8eab,d9cb3ec,5eb63cd4,14ecf59e,3a3f0d56,70959226,ec8f203d,947204b0,4ab9b3bf,dc853571,2c0db9e1,5fc2832e,4560e420,af96b043,e587d1de,d996e38a) -,S(80369d1,ec5ab7c6,492db1f9,aa2fa368,ec083d86,75d6c1,e7262e73,a612e493,cbb28c30,db7f7d03,6b8dda93,7e0c4e18,6a09f1ee,2407e55,7f6dc54b,a8c0553) -,S(903c9034,dbd3f982,41351979,c9306a8,42b88892,48cace15,c3e3a8bd,aafe1ffe,d55adb43,d0142740,71499c92,e9b851d8,e6ece26f,f82ceaff,ba63a003,14960f38) -,S(d6490ce4,74bd1e80,82c99e87,a0510a2a,c2c2772b,1921cda7,dcdcd5e8,6ecaacc,85a1fcc6,de4b93b8,b2314da6,31d7abdc,f96b22e4,b44a5545,f274f941,454e98f4) -,S(12f2342f,aa8b19a8,bb0e080b,2ed3487a,14ddd1b4,83e0bfa4,9ea08484,157d5306,eee0b9e4,30a51a3a,49da893e,50360ba1,21660b4d,ebd3ad8f,82805416,10f4b7fd) -,S(3bf1ef66,57bdcbba,a9d9a23,36c75429,c4df4a86,1d71a767,2d7e956a,deff234f,fa98467e,83dd1ca2,2a85cd8f,f12be1f,53d5a939,352f4046,a626a208,601ef6b5) -,S(d0d0f8b7,9a04ac8e,b6e010fa,3608926f,3b5bd886,f84c361a,8e1d9dd4,b01ff717,9bb32b90,6d7de56,c75bd202,b9353128,b6440fb,42dae8e6,74ade0c8,fc96386d) -,S(19507738,80caa9c1,f042f8b5,d1594a12,161635b5,a83e4675,35ffe51a,fcf631fc,9280d033,f7a8efc3,ff22f501,6a6ddfd2,f78159bf,1f13be4c,f758b150,21126ba) -,S(f4f50c3c,eb750a04,95973b47,53b96ec7,22cef833,f4ee7459,a51f884a,f9a251cd,41f554fa,d3d521e9,65fb0768,66caeac7,d9f5c6eb,ba7ba7b1,d1d38c9d,c06d85ce) -,S(8b669c9e,22452528,57e20692,2726f045,e97b8cf2,1154fb74,e199f49d,11951b84,550c47fa,c46060df,4d893afa,9f08713f,cc8e719f,a369e90b,fa8846df,7938c65b) -,S(941cb4b0,31edf346,64dd5e7,92ca135a,1d6cc6f,55341322,66644493,aee5fe32,cfa91a79,29b3b47,d73b8ae6,77cf64eb,cacf9408,3cdc76f1,79e25631,d574ff68) -,S(557e36b1,27307c56,72232c6f,6e92e4f6,f5da9d22,1567b464,8e79d97b,bf589023,ab741e35,109a0313,e7adee7a,2cec2c10,79d18d72,6c27f1c6,5a808b98,8e99b523) -,S(d8081ed,9e7cf1cb,e1ff07c0,b8ef3f9c,c7eac02f,1cf1c6ff,833f4b74,b2a33269,efa297d7,10fb71c8,43e358f3,e04ac308,53027f00,eea43d03,9b87c3ca,2b0fdd2e) -,S(b5e4fdf0,7a443146,263f6539,f6c8d991,7486da78,95b4ba7,fb4c9f14,78324d44,a3ef979f,93ec1a0d,602950d2,ddc400c8,4f018643,229cfba8,7cd9e3,f2fe657b) -,S(1a573259,a5100c21,d75efcc4,41d5a834,a81d96b,f4149731,eed4ae67,508bffcc,8a993dcf,49f94f6b,bc71766,9d37ebfc,614a45f4,1d70a1ca,f4da8834,5711223d) -,S(33d9f9f6,c9ba653b,f9c52166,c29e9c06,2cb7700d,ea2f40cd,28520bf,237b4558,dc80f57c,fc0e73ab,bdfc4a8f,f7e8f4c0,3353e889,bd54cf84,6361c1a9,af5a0a79) -,S(e4ca84fe,307c9237,4d39b2bb,b017b5b9,e478b26b,95236b8d,5bdfb220,f44419d,c0cfc7d8,92271c95,7ef235f7,2f310c7c,7d0ac297,97d42ffc,ba37061c,83775507) -,S(8f1f2d2d,cccb07a2,a8716b77,8c74f3fe,22990d36,b951e6dd,92f5896f,51bc23aa,9eaa792b,426d3400,31a862ca,b805d0da,ed9a4c73,591c204f,c5179b17,22aef870) -,S(20f7f6da,86eb5ae6,6a1b7818,43fd7fe4,c458e3e7,bfb590c8,76afb601,257b2ee0,6dfcd6c3,93e7e9dd,32c7e826,42f90d69,ff1e1ffe,18988de2,bc1cb9ba,db246fbc) -,S(3a3df365,8d65d718,2dc05797,8bc48fe1,5c5eb6d8,6bb241e5,9e178ca3,9cf9a010,ffb89791,7435e8c5,4865bc79,52fb7bd4,1578af51,6f611c54,1f7cfd5,651b293) -,S(7aa435,7dbbc5b9,a01b5f94,6b0240a1,36daa942,1ae1a1c9,b50f66c1,c7f15e48,4640c8d1,ace8f69,6b08ba1f,9a46d04c,f75c5914,3339d5a,181a7dfd,bfc92c0f) -,S(198e4848,8176664d,40fc14c7,acca9eb9,aa22599b,b2370959,5856d78b,5e932e94,fb9dcfdf,b27d062e,8ea5246,275d80e5,6fc7cb09,e81bf066,dfca888a,8df1de6e) -,S(25da8876,d3215051,75694915,c25056e1,2c1329b7,7795b7ec,1d4b66f9,3c911cc9,b8cf4a83,db78787a,6d80a157,c7c205f1,3664a71d,a6e78db5,b52b012b,930c4583) -,S(893d2e9c,3b6fa8e2,136994e6,14121842,bb82e577,89826ccb,eef51fab,de32c0b,d7cb9b4a,1d49b34b,f3f743f2,10c32a25,cf8df45d,8552a7f2,1268e270,ee6fed67) -,S(dde2e8a2,988fd777,4959457a,5c14384f,c8248d1b,a32c7ce1,a727af27,7b217688,1fe0272,137e4c9b,1c6df618,41a240a7,be3b5de1,7b93fa24,ccc055f0,e7972b1) -,S(52a73b51,5326198c,81bd988a,3033e1db,abd9ee27,9a91a434,e7a76813,453e27c1,c23130f,c4b8990f,ee308443,1cbeff25,62963b1a,4a5acb4b,a1319b4e,d77c745b) -,S(1b5afdc6,4598bfee,4ef31904,f0d06796,17b0149d,ac19e7ef,a1d4f19b,c5385490,fcc0c62,47d96d4e,430ae0e9,c19dfa2a,3719e66c,ce25a2cf,d7428d4,4c91e96e) -,S(76da558b,d533e761,4d97b7bc,5a1a98d2,af043ce1,1f2b323,185377da,c0e0abf0,f8dfecd7,94b3d069,ec22f01d,8418bd90,27c3dfc0,62beb597,e352bb70,271d3cee) -,S(17f01b77,d2417d97,e3c14f10,18af67be,c12c31a3,58521f6d,203f101b,227cdbc0,fe16d66f,a194c800,e3c14bb3,f1df0a2e,3ec319a8,66c69d9b,3b492d96,327bba04) -,S(6010e0a1,2cacb745,6e3a8f73,d5219a87,cc14dae6,54be7265,ffbf70c8,c4d5433,7d5f0faa,579afe50,2541a2de,4d525bd4,e7b950fe,2b2dcdb8,d67d3d9a,7b11da54) -,S(91e938c8,3f319320,baa876fa,23773a7b,d0fb81f9,bf9d99bd,13180560,bfdfad6f,b662f401,7a4fa2ff,6603864d,77a6b930,181372f2,5fd6a67e,12a1df6b,f75509ee) -,S(de2ef2ee,633355c3,3d259357,efca96a0,5b669f13,b515e64a,c0bc467f,2abd665e,d3d6254c,5c30daf4,64843190,7c2a8c1a,51baeb23,13605a58,b88c9a78,a6147c73) -,S(186151f0,dc37e48b,3178bdaf,900e7bab,49cf251f,7a2a1b8a,76da8750,2dee93a6,2a240dc,acbbfc19,876c3680,fdbd7ee5,d1085b79,96317e4f,db73d5a1,9f097f8b) -,S(6f19619f,ace0c63c,4dda566a,9a1e78f,a9568db1,1c46f3e9,771756b2,7d8a5c1e,4716efed,7166e06,722a744a,af89d145,4ddd2f0,f7652862,cc38eb3a,2beb1925) -,S(a0e450d6,fb8a6da7,e8f6e62f,7a08c2c7,277a832b,4e5c6dd1,8cbed37c,37db23a2,775223c6,3f81b2be,1bdf0831,9ed65ab8,d3e11c56,38830851,d55a8893,730979d0) -,S(6337ffcc,64f5d358,d90fad1b,646d8d7,46e2fb7a,2a6cc378,9b55ec52,3824de5,98286287,578bfd97,4c161a01,55f9a2ef,707858e2,a32c3fc7,319416f8,5a6e5427) -,S(914a8565,cc1bcf80,19e1eef2,87c9467c,bc42faaf,726d4399,6485efe4,6f99e32f,846c42d3,b1dd8c20,3a744f5,560396e9,b9a92380,2fccffba,c6ee22c7,65bffde8) -,S(dd79a02e,2460ef86,cb4e9ba8,3ee7e231,e99b3303,1d4a6d7d,6dee8b1f,b0050daf,d6a75b67,ba13f76b,172ae0e7,d63b20be,db3e54f9,e54a96d2,aebc326a,131ea271) -,S(b2776e23,3e759f8e,38c52394,d50fe177,c6842acb,f238eb56,c7638549,174c1b2,e18c89b2,dbb6453f,7b610518,8bf090c,f0410e51,97885d52,b50b2507,ffe4dc81) -,S(e0716c4c,c5e84f7c,282adc42,f294a36b,56bb26a2,58cef4bc,c36a7f53,1d5283e1,1442ddf1,57491db5,1692c7ea,5c92976b,8a2488b6,6aa6f38f,7a62946b,a24fc5bf) -,S(2b10c9f1,bfdd659d,9d1e073b,faaa4b13,2a08b678,f757ef39,a137e53c,b291df70,7d22ac48,f4e0aa71,8cf7882a,57a46746,94e0f456,f2cc3aca,30a3f8d4,2b240dab) -,S(fa762181,26a4813e,e97f2718,c6eed96d,da9f6912,ac463af6,a52f3aff,f80f07e4,8c8a04b,f38e2599,4cfd8905,27ace017,e57e3f8d,d378b205,2e767954,80dd5701) -,S(6b893eef,bea81e30,7ece156a,e79abc26,d9f0ca5a,b2dbde11,bb0d8192,f138e58e,510a308b,9fc47167,f72bbc4,f92eebb9,88a6512a,b1679102,f9016b0b,d82c559d) -,S(6cd9b970,332f421d,1aba33e4,75f26a4c,5c5fec37,4a549ac6,d8c10fa6,cbc40032,b57dbee6,68bef693,67188a54,52e3b4d2,cf1c8c25,8e36bc09,432b4f4a,dcc24086) -,S(ba4847ad,40530fc5,f77ea79e,ef7a1c0b,821b5285,5ec4ab8e,d238ce46,48a09fa6,627ba437,8e0f2044,20e61431,5f3d110f,2da9cbe6,2025bbdc,5bc1cede,c36030c9) -,S(92837329,4f59a142,ba84f897,7acf2e7d,9df06a27,74ad88d8,98689900,3750c513,4e938012,b6e55d6b,6f7871ae,c34511c8,40912a1,1a32012f,3bdd27b7,90f86c37) -,S(470c19f7,9aeb9a7a,142ba010,10ea4929,3de57e25,68658d45,42b5a626,864600b9,2e99dcc4,b93d9a36,7544b842,ef4a3085,2e24bc41,e98ff2a2,d9aede05,da703225) -,S(2496996d,c38e4bbc,851f9bd,f9a21b42,5fc7ce2f,2b06993e,97604a0e,db555c34,b6e02a63,f0e2e54e,1cfb9d28,7607bae5,8a68ae6e,a8300ee1,c1170f0a,9e567323) -,S(92366ed3,23ded4df,f4029e42,685c51fb,a8a916d1,999c42c0,a90feb44,4112a78c,88dc8af5,f6d1d14c,5c09d216,8af0e752,3fad76a1,5b311021,7ead491c,12b63191) -,S(ff9760e1,ce161564,22c4962,4962d89c,37e66e64,cd7f8e94,4125fd00,c05974a8,8ca4457c,a5e52e23,d70639c,a9a26f3,12312451,8f0de070,86d385b6,777a63a8) -,S(50d1d5ad,79f919b3,d23c16b1,428d971,5deb186f,2b92b64e,7a1ea1fa,dfca4981,ddb07de,d4ad81b3,cfefe726,33521be1,c7418c5e,aa759440,20dfe92e,b4653ce4) -,S(4934f753,29844b23,80183df0,254d1c7d,342d7d27,9fa5e804,68dbee16,4e9c2c6e,a4f8aba6,7a488a33,40e8e943,14f7eed,5cc25487,5acbaedb,afecfc2d,5405609a) -,S(d7b99142,9cbdf755,5cadf030,7b2c4a91,c0d25710,a0553511,eac6afb4,c544ff81,17bf03a6,83b1a0f2,366b944c,aabe57d4,eac4d86f,bfabd006,66693983,e0241420) -,S(834b036c,145d6905,58199bc1,e7a7bfc2,4831417b,530b0b97,8cc1fc16,af00b966,4a45a9eb,299f24a0,1c520751,2cbee44c,bfb75d0d,14a7eb08,b1668b58,ae58c47d) -,S(d7a8c30b,fd7b8aaa,78dd23bb,86ef2624,5a363857,6ed69739,25ea9d9,194bfb3a,7b5f9ce6,380abb91,6e041388,13baaf24,229ece27,3541f4ca,2883ad77,9e501fa6) -,S(ea4c7ed2,7ced8b13,4a2ccb2d,3828d29f,f80c4825,e5607597,3faace04,d2fb7763,a8454c9c,be19ec44,8a3234ea,97b8fbb,b256a148,11ba0ede,becd8641,42684d14) -,S(a2cb70b,f80d9f6d,696ceaf8,fe8052bd,e59215a9,99d4b92c,ce806a19,71d555c,997bd94c,e5cb12ff,886c1cac,bd21c3c,e2f144f0,3af644a2,c2aaba2c,825f75b5) -,S(89a91f5,c7c8700,175ab017,8c4104f4,a927af06,f269645,36cb78d0,19f8b8f2,6a2f8ebf,e1258b4e,31bf9a5c,31c51a3f,1cb58aea,6e18582,3e87920c,3df8e7e9) -,S(27d7191a,71ecb0eb,71b43dfd,5840079c,bd368c0,5ce62fdf,2967dcca,78f5a6d6,11120002,d0d0fa9c,8db51506,4e1fcc2d,92d8fa9c,8b454294,bfd01c64,889d5e6) -,S(cefb996a,d36deffd,c3c7ddbb,11a5013b,70baa98c,1057adfb,185b4c9,62f3384a,c93cab46,7523b0d2,baef4425,c9ff048e,c586d4c8,69c69cff,3ab9d72e,e3d80f83) -,S(5a8ff765,84746f42,4e06b557,77986825,e91312c4,4f79003d,c1b381cd,4fe5ce8f,3946177c,3c741458,7bdb9506,85ad0c73,b422a8b2,5cc3ad3a,cd486e76,99a42f08) -,S(b179dac7,d2f400bc,bb039f32,91e813e6,f9a7331,80a1a5d0,db51aafb,af582fb6,89a70304,d70cbb61,ffb3a499,1815cb17,458404fe,e43f09bf,d630d480,5978b1dc) -,S(6e14a53f,ab32be84,4eb14242,a3b6a86e,e178cd7,51dbb7a2,b14cb763,ab2fe6de,a22ed4a6,d98c59d8,ca85e111,cce0efcc,60e20df9,6b06615d,69aa3cfb,206494b9) -,S(12ac42bf,d8f919d8,c79a8138,1aae69ef,b789a573,f58332b5,79694dfd,27e7ff20,4ebc3b7e,4b0136f5,19a8df5f,baa7ff59,17f4f632,f85ab1f2,ce502fee,bb3a3a87) -,S(87bf22af,5e9dc061,eabb01c4,eaa867c3,4656599e,da744da7,774fa8d9,aad68630,d34f530d,fbea0d52,9d2d64d1,323fa44a,d80cbe01,fa2806e5,ff069e6b,fc0ce729) -,S(33fe6bd7,ebe2b197,76251415,8bf866cf,b6d3ad5e,1f68519b,edb513fe,6076c96f,c5970cce,f44aa84e,f95a56eb,588b7a8e,d9164f5f,5a2eed83,1f70d308,2320e9e1) -,S(5fc2f44c,fc0f7ab9,9f03b67a,d7b6ee99,d73fa9cb,d74eb5ba,6d931d9e,26ba51af,8b1fbfe9,de201400,6c07da02,4bbcf53e,13bb9f2b,ff3dd6d9,5135a6fd,5842f0f0) -,S(38fb5cfb,e4f348cc,1fa7f9b2,ea600daa,e8330aca,53308f09,b6a7d8b8,5ca8a88b,ac1bf91b,7f53e824,d845c0f6,9534291f,cec2808f,95acf58e,4afba07c,fc735be9) -,S(3ec2457f,fc848504,6f74912b,5c58b270,1be6eeb6,f88da0b3,c5cc4454,48750875,b63209d2,641c65bb,7105af10,61d7513e,409f153e,5d1b5073,232eacc6,f76dde22) -,S(32fe812,e67ef62c,687d248f,e75ef399,48fe8ae4,a01ae10d,ed65264b,fb5050fb,d9c85369,db22ddeb,baf7682f,53642962,cfec2afd,3a20de77,588e7473,18044f6f) -,S(97d7c69b,2aa0277d,2b20e9c7,bb1066a2,be6f443f,d0a428b6,d78c5fc9,6ff71b57,f84ba781,70837aa1,f75936cb,fc50c444,c40c9fa3,22d90088,ac6889f7,e7c0f861) -,S(3621a4af,4d698e4b,60e7f497,6e0c10e9,ca32834f,ff917aa0,6aff912b,2ad80cd,22cfd248,a17886a,ae5d0e11,53621e9b,46289acc,ecd8155,a1bd6372,120c4da7) -,S(ae79a6e5,848b1dc6,cb64958e,87b737c1,858442b3,63d4a2,e9f04561,7d73f8c7,c147238c,59885f2d,dc5dec63,de421eb1,c5a19438,ed0600b3,4c77f4e0,e7aa557a) -,S(36eec623,700e51e7,723a632a,55370ddd,d6b1f917,6ea39a2e,54a2a1ac,52598c35,29698c0e,56b4e2b5,5389dd9c,3d8b509a,e0b87f99,4872d865,3fc74269,7f5bb7c) -,S(50f70061,804dbeab,cf2ab4a9,87ebde2,1f5496c9,a4cd28a,4dd9da7b,310e876f,77e27710,edf831db,6ba9e64c,545f03a7,eb390842,8d9cfa3,3d0e1c87,61371706) -,S(c2ad6b2d,e84bf60,7fe77b8f,a9fe26ff,bb5e1906,1494e469,8da44a33,25843844,17b92ad9,d3938fef,7a17f543,a169a7ad,8ee65dce,36eeedfb,5e3c0c8e,a1b24fc3) -,S(a53504f,e2286269,427fd2fc,fcb64827,bdefdfd9,feb89d50,12651d2d,c60ae99e,6b9d73e7,e046d11d,ce78b114,8aea837f,770d8267,6642dac8,f3b3c035,c10eab45) -,S(5410db61,40a77b31,9f19c969,34a8364a,4881ab60,ad76a6c9,34f317c1,1b658dec,ac45bb6e,2e5fe23d,57297370,cd04ffdd,dd89a9,15a1e9ad,15d7f9e7,6d8b3aeb) -,S(882cbd69,fbd3e262,5093385e,ab82fc9e,7597c38e,45fa5df7,f98c94a9,3bf25467,2083f00,b25b28b7,f92b040d,a4294dc0,8a3d97e3,d951e724,da0e692a,5737a87a) -,S(3141e0d1,22b4c136,f7793c73,9c48f308,c5ec8043,19db116d,64eb14f5,aee83942,9c2d06cc,d765c6c3,cee09b70,247f8806,227d0178,13becbb6,96c5a344,b68b33b1) -,S(1b2f3686,5a63df41,65caea4e,305d8d66,1de6ccc1,c2a28cf5,2373527e,27cecfc,1239d8c8,d60fdcb9,fcf3f5d4,63305037,6d47fd97,4cd6bc64,99e0e951,2d2209a9) -,S(725168cd,9fd59e41,14918b77,6ea96fc9,6315b4f0,86672dac,1eaf59a5,e61ed25f,946f03a9,84a6735d,e72acb38,dfd21905,fa2358a5,e66e7b0a,2f8836a1,8f5d73c3) -,S(4207faa5,c9dc9622,9644df1b,a099a84d,654ec6d2,aa69efcd,a4a31a3c,61f2e1d4,ea72a92,836d1597,5275c18a,900c0e7d,d0502610,d97b6f79,1f6a28c2,1b3ddfd7) -,S(53900d38,a4740830,a6129a11,9dc90f6d,30f32847,708d48d4,20b77764,ff5b9cc7,66822ed6,ed941eb2,20aefe94,4325daa7,a619dfed,5c76bf75,1fc25342,8178d3fa) -,S(d0204932,a3fb8d33,9779851c,d69f6adf,be1a9957,59fcfce1,b8d4f047,e4e4dd2,8ded18ff,bbfc663a,9c658ae9,286f82e0,9ee9381b,3291f5c9,efabf0d5,fae318f) -,S(3ed8ce15,2d34e621,94b8b16d,55605766,41fb2673,14a08c91,d916fa14,f21abde5,48490fe3,9769c60e,38996370,27b57df7,230060c,2505f414,5a1c7f1,4ba16660) -,S(b7d57614,9b5e2ce5,edef3c30,b8cce79e,6f122c70,351d04fc,ed2b67c7,f5cb2aed,7c8fc1c6,bd42b25d,d45e37c2,5cb06f0a,bd2f7051,4a50e6e1,2a67c0b5,b199eda1) -,S(2489e06c,c8f0bfed,9d5ea722,c07ca795,e9ab40e5,45b036e0,f0c11f28,53c0d35c,dff65f5c,20766078,9737f1fd,5af05ce8,3b8edf91,37002b19,f5e1599a,e76c48bd) -,S(9b2140e5,509817c4,465e6689,a3bdadcf,b79c1803,883d493d,4e4e99cd,55f30a29,86374501,705fabc6,62e8c869,a22d2813,f7106006,ee09b6bd,b582b690,50186688) -,S(48d6fff7,d5c37c30,11c9e63b,b3342f92,776060a6,dd179e3a,e2c6bb69,d2f88b3e,783353e,adb6daec,536d37dc,76ae3ff,8dce14d9,65d21d3b,7a17515d,7d3341aa) -,S(35d46a17,b6951355,a055e253,42b4244d,8ce65459,c630f2fd,4708687b,e6a49e7d,13bc21d5,7cc2954,62927cf8,bc31ef3b,5407021a,62c5253a,5950e8eb,b9c735d7) -,S(17ba438,24168f06,274b2f5a,d080fda2,3c0dc34b,f77e81c3,c4413cd2,f594575d,e8b34f9,1ef09f92,7b5d9e51,662216a1,30ef8f87,2e0febe,3f5cce8b,318fc77a) -,S(2a09e4bb,4f6d6b40,f59d0299,93eeea7c,755eb00a,5eba0477,3fc0c796,aee68a07,cbe72772,e5d8b761,15ed6f92,f20028b7,cd06aea6,74e10667,899e78a3,df403f0e) -,S(f3838250,e9a03da6,87139583,2bc6b35c,2d427b60,4cb7d25b,149b6816,235b0e4c,164b211a,60562190,d415bcc3,87d1a147,66e45f14,dfbeda44,833ce45f,b815598e) -,S(b307de85,c4c2e8,4e076d19,647bd205,8c1a3c96,a0261481,322e73f9,f4a2e94f,5af7f6f5,ae7f65cb,b62f021,608473e6,b68d032b,4835540a,f265049a,e506b2d8) -,S(ff92c7ba,5f89d3d4,5273688,907ab9bb,794e5622,f8f300fc,804934d3,b5820e00,3b2e2d1c,420fafaa,e53c9da4,957e22b2,bc76ccbd,99f323d,763fa1ef,f92ea71a) -,S(49630ee0,a8ddf91d,ea678a3e,1dcb623c,688b7c3b,9e39196c,b578d30e,196e63b0,4c1aa073,d1375475,11d81776,e2e59404,aa08db5f,95b80e56,c39613be,fc2bfcdb) -,S(d41ead31,f2fac884,e762ccac,85825cbc,6ab2f8df,a069b2f3,fce3c6f3,d5c95a33,f15e3e23,e19baea5,677390cb,acf97180,86876f96,50fac740,9b6e62f8,b6d40652) -,S(5e62e95d,27ba07d0,781ad685,75a7a11d,df9f2776,48cb5cb0,869ba586,6ff02869,291717d,1a1ff532,e92f0311,881fe2d1,6c8844a,6f5ad7f3,b1ced51,e5088302) -,S(dbdd4f57,1f6d01cc,8a1025ce,3b92ce3d,56d396d9,635e456a,fd856239,27b53bd5,b929d5dd,816bcdd7,78abd34b,c15f2fb9,deff3f9a,aa44de0b,9f7b46d8,b8d70373) -,S(63a8349e,1a891037,9a74a60,babb68a1,4c8cda6f,c2cbc0e2,1a5aca7a,fff7a19f,38858c42,9cfb1e49,5fc90633,ce07abf5,b7c4a4fa,22b955ef,e2c137df,143ec70b) -,S(1805ec70,2cbb1e4a,5da4841e,9e24afcf,b84a3e45,dd6c39a6,cdb6a661,d5c6b1af,193be01d,d3f28479,e352f164,de99d21d,1b3fe8c4,b0af8587,8f21c858,cdadc27) -,S(2d6ff24d,fcfeddca,ab3b19ec,b6a79793,7f5c5d3d,373b9df0,6ec68549,6d075423,b8bbca01,551b2b3e,f6ec3a37,ff020f3b,6b1f5456,69bd8b90,f8a55216,3fb48fb6) -,S(3aa21099,52cf0464,4bfe5de8,69cb2d4a,19d3c4c4,661d6782,967dad8d,cc353a24,68252574,69dd7940,fbdd26a2,483149f0,f71a4b12,fd25b063,73765c52,d45985af) -,S(d6422a71,443b0e37,cbc06f90,4ba1f62d,c2351b7f,e4e0b909,5fc227a1,7f8f551c,ca92a69d,2c9aa758,46c2518,f1ae03c0,d7138170,447b55d9,37108604,f71b9feb) -,S(51e297bc,46529246,a36f8460,f285d713,b1e9ed67,2027eb35,37806d5c,7e756177,5d56e447,63bde166,b456531d,94be0d,7057081b,edbbb89c,be8c4732,13eb0ad9) -,S(378a552f,c061e796,c9ddd101,63851ea0,663f09f1,3fdf852b,ddbafd7b,bf6c258a,6396c9f2,a26b62c6,f33b73fd,98824958,8cbc7c10,e679bd4e,ea0f4ab1,dbf38f72) -,S(bd85fb00,1db4f2fe,95c61f1e,825e65c3,80761832,37be8a86,a20f6fc0,7a586daa,52c21cd8,9bf874ab,7d7e0f4c,d0095d7,6e8c737b,e2ba9d1,a21fb795,d968f61f) -,S(fe68e6ec,3c8e681c,e7230a92,e8762f0,af3e206f,f3b0afe8,be61ab34,2ca076b3,f8683d06,af0c88f6,93a0a6b3,1200cd25,ea2c7e9d,2b8048f8,b983474b,b1dc20fc) -,S(83e55d38,bbe2daa9,f8147b1e,674be115,d919445f,70d2b3a6,cb917a4a,9ff284d1,92d6c7f6,dbbcdee5,8b11a244,34cbe7c,9f9fc0dd,c93f6fa8,b6354a06,5bf90ab7) -,S(fc9cbaca,ed0e1df5,e9d8120,6bb55f26,67e114e7,30347030,8b333554,d0735ad0,d41fc02f,2d4b3f74,f4e9ec00,7a879540,54d12fc9,3d53242c,a45bd38,c75deb9e) -,S(7adf7a3d,12268d0f,c2568d5b,ee296d61,fafcd739,f081e5a1,7b39fe7,40132b05,51aeb855,a84f377b,899392c8,a7daa18b,70ec2a94,7929c93c,67ed8217,41adaa21) -,S(e9631ea3,7da9e68f,eb61f9c5,6eb91bb0,2fdb4d58,d99874c5,2c4af40f,9716aa0c,51d5a6ea,1a5fffae,39c598f0,158272ec,bdb48c4d,faa93da3,89af20a7,d2a1b8d3) -,S(e892f70d,15639bdd,ab70739e,83ab9f04,963e1dff,e2bd81eb,e075173e,6bdd116,2e78cfa8,30b68c55,68f635f1,b260d823,55f38ed3,f5f43c33,b178be12,dc006b4b) -,S(6f3ef2e1,e8d4fd02,2533f4d7,410778c6,ccd9a7be,aaeb3c8d,d9f01699,89598def,c4388130,c278f8f2,7a9947ed,4948f8e4,febe81bb,88bf873d,2d565b4e,3481b86) -,S(cf24cd64,84b07e12,37640f0e,da7e776e,3d4db192,6da8e929,19b36383,15de412e,a353cd6f,a796c46c,49f34c72,64d36df8,6d53f556,a36f430f,7f3f6ac9,3527ca7f) -,S(a2e98e5,36d517d6,528d6353,8bc2be93,4eeae1c1,cd8dcec7,a60080d3,fed33749,205e752c,49a09b0c,8804cba0,62b28ec4,6d9e8f37,9cbcacd4,a7cc9049,47bfb296) -,S(e5ef194,498445cb,718f7c77,6aecd0f1,949a4a49,73e32ce9,a4915867,dc27139c,fc774f2e,1e51f03e,71e637a4,158a0013,5aef5a18,b15ef0b1,e5696338,82bb513b) -,S(311b36a7,1a1d13b8,29c78813,6a989c0e,1b7039d4,d75110b6,ba97f000,749a8d06,2f441c15,6b80f4d,51dce0d9,bceca566,2f3fdd9b,965a0d84,55f6d154,3a661f7f) -,S(324420fb,a5076214,9be852e5,ffb88d20,d1120e1d,2eb9c132,32bdb13f,403a5f6c,378f5d4,1dc1011d,1fd338d,b6073df8,903fb4c1,e17b2122,bdad5eaa,496965b) -,S(7cf4998f,5095c102,a0db72bf,9935ca91,eac814c5,4120eb0a,262f246e,ede142d4,73e6db13,d6db9486,fc870698,7be096f7,7440dd35,67064888,e61dfeea,e98c1fb3) -,S(d6fe26df,d501241b,f8c5e74f,e30714da,7d690be0,91cfbe14,68ed6bbe,23598f7a,102c4907,60fed9b7,239c0443,d01f2742,fed0a0f0,fd7ab9f6,9fb1c58d,c5752fe7) -,S(805ee58e,66ab8020,c9c32afd,4c7fe30e,960f4c3,ae51e94e,da9e5242,af09c6f,19154d86,59fb1837,3d0adf6,daedcfc8,3937af0b,ef9a7d15,f990f60a,c5457617) -,S(491717b1,f22f93ba,d0a3cce4,fac57160,8ad7a746,ba73d375,1713e605,8bcd8450,9c38b3e5,4c89d38a,2307546f,f46bbd68,d4e4ad08,cc45bcc1,575fd120,acdacaff) -,S(a8e23e38,27c54d4f,ae2589ba,cf3c4e1,93f97e59,b11506f2,2016fbe,a9fc2522,ffaa8b74,22b50822,dadd781f,d31b5a31,eb384c50,2fa0bc2,89252665,1c602f3e) -,S(9fee31c6,88b0f7f7,78a39786,a84567e8,34da7ffb,350cfdc8,95d65c4a,afdf69c4,2116e31c,2a0d25f6,48a3ab47,1c897484,d71dd9e5,c678af4a,292a6388,d9e45e94) -,S(6256ced3,f08f1812,ca7ad618,383f1542,baa2bb06,332d4c1f,72d862c2,318854e9,9ae0bbd9,d2fd51d2,9347aa62,12b6c0ca,be530b55,bfd8cf18,6732be1e,c66ced06) -,S(ca1cf364,a5e1f47e,cd0ab0e7,52e785fd,935b8c37,964c5654,2cfb3249,a136d669,17412d75,2f350795,30db27a1,7394c362,45fa376e,d20583fe,b9f7a7a1,2c3b67f3) -,S(19004a4b,28e5352c,7c74def,cf129ca1,cb5c7dc1,5099b37f,dfdb0d5d,1e694400,68ed1edb,9ac650b2,965a4034,2812a692,23b3cf6f,24ab0a05,2e1b8eba,f7335020) -,S(c605e97f,27199d86,18fca176,54e44c9c,8dd20994,aeae0466,dbdbbf0e,ffd1b3c0,606955ce,33ff7b6a,cc6de4bc,4ef80b34,bdf6ea17,b29dada,4ee54f06,f61e9d22) -,S(3e89970f,15e79b51,fba90202,a16da6ec,3d3d5d53,72218d72,bbed0626,31affdfe,5d9e27d0,bdefa8cb,b02ca682,a062ccb0,61a8fc47,b2cc72a3,9b687b45,5f83182e) -,S(c077c861,575ab0d2,944f8e65,8a9dbe54,9fc1172c,6b7b7428,476af472,e625d5cc,c01e7abf,6a3abe2,d2aa2457,76068afd,9ba78fb4,fa39e531,8155597a,90fededc) -,S(8567c87d,c12f1479,5f351d1c,807604c6,636c670e,11edb286,92552ab,382ddaa5,71f0be2a,12ebee63,8a63e848,fc4d8116,e2dcbf99,ecdb15ae,1f4ec6c,84f359ff) -,S(9f1b7785,7421626f,87978ee1,780d0,1e9d0b28,df34c2ad,15332b8a,d94d8dfd,6df504cf,66144d9d,ed530e2a,1436a4df,634a84c6,9de752d8,42e076c9,1f129b8e) -,S(f45c2c6a,2754fc31,c5770e3d,38b19e72,47b0dd1e,5ade8ed1,f2f3219,ea7accce,ee07ec18,8190ce54,e736ffd2,912075a1,128d24d9,b178a7ee,72aeb6e4,9b593f4f) -,S(51a5441a,f3446fb4,cc63ece6,c9650a87,2fa5567c,4918f5b4,ec8668c4,ddba6e0d,413186bb,adad4943,6abc46e9,280a1571,a97ed7f2,a839cad2,935675b9,d167a54a) -,S(adee3e1a,e9a2ab1b,da34fd5f,afd3b3e4,f51255f3,5dbd94c6,8efb994d,afdeeade,f330f0cb,973fd732,eda39ebb,82dcc589,4c148165,428adfa3,b4ff865,1ea83e24) -,S(a8946504,eb084214,d0153ac9,c3437fe7,3ff5696,16e01672,413a62ee,27c97db5,3dd63d46,f74a56c7,2cd5d45b,5bd6f2a8,d913300f,b4ce536a,e504d4b1,b2e311dd) -,S(e34ce586,990e48c5,febc2fd4,70770cf0,4c81c782,3702cb5f,289be0,f4a97205,d1774a35,cdd7cc54,dc68827e,f7c723d7,5c167982,c314dc62,bba17478,611f5854) -,S(7a8a5d9c,edbc4c76,1fdf2958,8289bea,d524edd4,f7cad978,deaeca8a,de47435,559d473f,3a9a7ee3,4ee0a1d0,4acdffc5,6766db36,94fbf08a,5ccef8cf,31e25b6) -,S(848cd57c,62c67249,d84710a1,5c7abc27,93fcba46,497a6b0e,b23c2ad,f8acaac8,a48424a9,59922131,31a763ed,30369b72,b331d9f0,cf46f8a2,a15515ed,6726f735) -,S(6afbce14,1f2d2c4a,c52e7e05,5ba6ea60,7612a590,d74a2a5c,1344cd5b,c49f2f03,910d69d1,cce10aca,bb1593be,2d4d4d28,9745f97a,29fb78a2,a1eb6f0c,a58e4b61) -,S(61f3727d,718644a9,2e08ab04,814c4446,c5dfae82,c26540cb,44fbd310,a5315a11,56665e3,ee6edadd,a154563b,11fdc203,fe4365d1,ac36879f,a30778c2,badab836) -,S(582962de,e00668e7,91741dda,8e86ddb7,b8ff7773,ac1ea51d,1aac139e,a810f3d1,6bd353b2,e004d66,f1e90cc0,7c68a0a5,b532e709,75a7bc58,7a6b1c67,71022f6c) -,S(5c4426f9,f6071fde,a9304e6a,4a2374a2,e2591225,28b62d20,5fc3016,c471b636,ff6e8c71,fccddb0b,5cff9e2a,10c606e7,c571245e,8f5bb5f7,77e0a7d9,733560a1) -,S(ee02633f,c6b41f01,c3c24c33,719db7fd,a9e04b1f,7070395f,e8898a0,efbf6af3,ecdab00c,83cb3465,1d48a696,6a8e4f03,ebecfba6,f73a66ec,4d62a668,48f14798) -,S(fab36b80,e5bba465,63c9078b,b727e0af,c9bb0af0,2e394f9f,2c90e0e,fe9fb816,75173a7f,f5599da0,ab84519,c7c25be4,1f10172f,fea39762,8e7dab7a,3ecbcfa0) -,S(68a89a2,62015a57,5f882215,48c6d3a7,b4ad1f92,f5665980,367107a9,f4cc37a,43ea7b7a,79397dea,c8354436,d53e7731,c94773d1,5b067063,b108c559,c05bc46f) -,S(fa6e2972,87a0e97c,35454378,4a76fb0b,56106727,136474d8,a3edf8b4,e03f95f4,1e80751f,9c127fff,ce28ae,8ce5afe2,eea1c566,fb0a9f20,8030cc96,e1197725) -,S(25474cb7,805d22f8,7a641116,34628321,f086d1a0,40404c47,ebee913c,e9e02a6,2b3aac5c,85ce9672,61757c61,d6a72dd,4ff81e00,87f0b8a4,999b927c,7b069609) -,S(6f7051ef,10fc1485,a9c80ae0,8683397d,c0af15b5,f78fec70,fe4c456f,f33b6689,625086ce,ab7a9173,d9c370c4,c336c63d,2aa85ac7,b8391993,7ffe4118,f6a7b849) -,S(f4720462,2f579de0,701f1e90,558c74b4,ab634664,197c03ed,a85b0fe4,50df4951,c66a490f,f9b588c9,2d17b80f,7f66e5fc,a65187b6,d965e81b,c16039f4,477fdb54) -,S(3b718764,7e722fa3,de42fca9,e3ba181e,de982728,5b8b006b,d51a58e5,ed898c8,bf872047,f3cd3ea,d7a439b,9d4f7776,7175f940,d6cae8fc,930aece7,e1b92202) -,S(5255ba09,df1e199,4c99bf21,709849a1,cd7c4f58,a283e344,6b98872d,a416c40f,a1099eee,e3ad10d9,6bce7a58,839fcaee,1b43e0fb,29ac0300,4e0eb15c,63d1f604) -,S(f4b64a08,16dfe224,595d3a15,8173df8a,7d941a4e,968ac02c,bf87d9d8,93954805,e5585209,2d0cf600,b8b2342a,8371894,f422e3b6,68ec4078,2379a60e,944228ee) -,S(236d83ad,b789d7df,5fde69cd,86d45d5c,f20c5867,b7f2b398,b9373960,b22b29ab,9758044,d3e06295,e33bebaa,befc5776,5db45475,b3aab963,5fea8dd6,77a478cc) -,S(42071659,65af2fda,c9e87319,6dd0c723,e7d61bf9,b71e5e70,667c9858,6371f3f2,fddfce02,588c1d4a,b744301c,6117e504,8f9c2636,5ccafafc,8a6e19a1,ea7b1b37) -,S(7d0c2917,aaa71cf2,e79f1041,5e5e583,ff01b24b,65f1f409,240f794b,d346a452,1e857dbc,c86c1032,e748d8e7,c8f5839d,57295223,22e6bdb6,187b00f1,f489576e) -,S(f0609605,d6e39141,e5e4f0e0,6bb6d55b,9ea2ced0,6a58d4e1,7c46a3df,18257255,e6d54c0b,10826de6,e95553ac,e4689fa4,cb03b959,65472e65,a085988b,d045374c) -,S(86e66299,819b0807,af30c89,228447f3,71fad56b,75f238b5,30bef3e0,b1123204,de635715,b1997f4e,c367bcf2,8f8def4,7a7a2069,3a555b5,396dbe4d,19b1e8ff) -,S(7710dc40,f72bb934,f5f9328a,1284efbf,fad3518a,70c2a0a4,55028bb3,a8b87e9f,d2ebdd39,7dd91ec3,7ffcd8d1,a9b412c1,78f6d228,5e099162,76f9e8f4,a6a28e02) -,S(3d377c80,25607e9a,fd512e8e,7c37a2f2,8d316701,dff7f318,eb24cc34,348d935f,20d2d95a,e8503a11,de19db36,5bb62213,6cd55735,966c25cb,2a56f07f,19cb2664) -,S(812a4ad0,d004003e,fb190ea9,336659d9,7b7d6df0,29f29f97,bc9c8d68,f284a696,6303a024,b2d95d18,f04fa94c,df3d0749,60ed45df,584e16ca,d60a0843,551f94e7) -,S(51cb80b1,9c0dc55a,888421e2,411baddf,6c0eb167,ed9bd04d,294623ed,1bb61dad,d14f756b,f905da5b,6466bc6b,26685501,1fc90892,93633c74,479afacb,c34559f5) -,S(837afe72,82af09de,108711a7,998dd45c,36654f3d,a3cb392d,c46bee0a,b43cfc8d,88b0ae50,5c30a2b5,72c0f69,8e7ecfea,87ea1253,ec133fe7,fb2aff9f,6adc2e15) -,S(ab967cb8,463da438,ad360a8b,3e066669,231fbd,cd590904,fe827ecd,dff3cca7,d82043ef,c614db53,8d06f6d9,9fae98e1,ee6f5065,31b05822,ed2141f3,25ebe544) -,S(5a0b6177,50d828ab,fbf4fbca,576ff8ff,5bd19330,bd357eaa,a5564e39,c718eb49,f6e8d743,e528429c,2cacc478,368d7226,823a45bf,358d9128,9da334b8,5a1b4426) -,S(351b4334,83fae045,ce964f04,f63af62a,6964e0b3,5c1444ca,68d09edc,9a43c9ea,f571f442,7b308ac4,83bfdb4e,87987455,a2a49f77,73220511,dfedc616,20bc18a) -,S(fe64fb54,727ce446,c00dc3cd,5de496e8,2d5a0e9,b13a9a7b,99a96a49,2d0d288d,452c4c9,aee35675,33ce8cbb,e444590e,f5756f14,33865ba0,efd00c4d,26db7d8d) -,S(9403ea3c,773544f4,4eae3cb8,91457ac,89b11f1b,66c3c397,aea8d816,ccab1d49,46ec1e05,d13b40a5,f21ce743,b2ac9756,8ba98b2,8fe1443b,3b0c9cc8,f8a49deb) -,S(e81a5512,2af7093b,b361ab58,534df80f,dac734d,7a863ad1,b080d691,c4396dde,fb33ea54,fbc0c05,f9854f1c,49cfabe,90e259ce,9aafae3,353e8f51,594d49f8) -,S(b7511df8,fccf50c8,192dc3cc,bd79985b,15eaa528,89c4d01a,e21767e3,96bec9ee,c937db57,ddcf0997,aec742e9,cd522c10,d4a52b27,b50104e7,b59c441e,3d0fad4a) -,S(5625f122,4406dbff,a818d98,1e88b5d4,80039f5b,415acc20,ae69ae7a,704dead4,aed9f73d,5265c976,760d094c,e9ced8dd,722122cd,e0b1b34,a8296fb1,dccacfe7) -,S(1b89696,dca54369,27bcf0a5,de32ff1e,e79f6ea5,6f6ffeaa,bce6190e,bc7e2c8a,52bdf0c7,52cc3e5b,1cb9b5df,adccaca7,929046b,bb67daf3,10ba793d,9369b358) -,S(4ef2516d,796d1c0d,9baa8491,7c2db149,e7b89f61,a8f8fb95,e14116bd,473d730d,9a0063bd,6e25255a,70479159,d3089a75,834e54a0,a28c5c61,ea3c33a8,7ab20969) -,S(b36c8db5,51fabcb0,c3fa59e5,9faefed0,1a53b4d,5470ce15,937c889a,a93faecc,1be63f1e,7f85bfe7,2e782cd8,22776567,e3b58794,5f37e2d6,b137da7d,42c8cc10) -,S(7db8ebbb,88c7c04b,fed18b7e,1830df41,490028a2,2918098a,9b34b8eb,c110457b,73fe3f91,f0f8a43c,490f4cbb,f8bab5b,9a6569b9,22a69e9,93ab910c,520fa9c2) -,S(47bb0b5c,c207ef1a,db28a389,7606661d,e5d4c740,3b2858f3,209b7dc0,cac3021f,150e2ce4,44f541ff,7883cf31,79befa4f,5df9c3e1,9da098f2,1d73c37d,1ca48b16) -,S(7803d64,d7622ab8,70a8b927,74e012c6,ab97fad8,4bedfc7b,ac4ce6a,74dad4e6,2662e4c6,1a60a1ff,5485bb34,c1d41d29,3a09a69f,7fe8a049,95245e2a,7770cbe0) -,S(61a64d4a,9a801549,4fa670f8,85988b67,7d317b9f,9b75e3eb,fc6d734e,fe3d3aa4,ff25af65,16e639b2,b6b0dd56,c0e12610,b1b00c3f,d8c59cf1,3fbb1b74,6282d91d) -,S(f2de8cdc,ce609b80,af8b34ca,1c1166c4,3ae0ab9b,e742b510,2ecdd5d,2e94307,d624709e,79346b3e,81b98871,84bf252,949c7f21,861fe6f6,666ef5e7,18ec5be8) -,S(8c740f9f,386f5a0a,228ea52,18a43461,142f744f,87511e9,67080dd0,f3c65d2a,a641bdc8,ae1d4051,a15b1083,27581bf0,22e92b26,a5bbd186,86fb4e59,79f7cd06) -,S(b15a4b19,17448b75,df927416,2795eb5f,60cdb4f0,e657afa9,989e5133,646ae240,e09f731a,226189fb,429c76cf,1ed9fe62,2c148475,92f26b50,c2c45344,ddc73370) -,S(44a65d90,26bbdbc9,89b0dbfb,aa645860,d7a15652,5286a9e8,c67b5a3c,e2dde08b,f2f23e44,bb6cd570,f58ec2b7,b90eb66c,30775109,81279b50,2fc90762,3f12b52b) -,S(60bc8123,92f1e7a2,4eafd5f8,ca0d8fe9,c5880133,209f17d8,6b95cdb2,c9df479a,4d39ae61,cf4368ef,279231ca,b72be100,cfee501a,da7c873c,3db18742,82076a98) -,S(ad5b9079,36391697,61edf9bb,6ed7ae2b,f7e852d4,bae22afd,655a5ed5,754f3618,bdb40449,723089b,ad8221c0,8a46824e,cefe4899,d5e073fd,8606524e,a81a35e3) -,S(c8166cf6,97edc986,6f824df3,82a515f,68ef5d13,dba7e0d,43e85727,c6e15911,86804e47,8118c092,3ab97ef1,ab9dac34,2bc48c7e,3fe24e6c,fbaa74a2,2390f4d6) -,S(3e0a96a,94dcdcb2,9f0df535,970146d9,7f0fd71d,7a4196ed,cd626903,aafbff06,5f6eda99,4651016b,86d28c9b,39efdb4a,b8ad08a8,5c87b230,eaf7ba70,6062a8ce) -,S(e72351db,dcab669a,f1df2767,f5e5f05,ca80608e,29ac5f09,b1ff76ad,43178a5a,552249f7,7a8b3462,c9a268f0,fee20713,5cc14ccb,15914be9,2cd16d99,b2520af1) -,S(a08e1278,71ec784c,4f80099b,5d83c5f0,91978e38,7b0b37e1,f4622c15,80fea335,48e6aef5,349f25d7,40ffc9c2,5de543c8,7e0553f0,54990aef,fec51f0a,9b3585a) -,S(ffb6f3d7,92596141,f7d15157,d1a42bb9,e9b51e21,61a8e297,5aa05688,ba67617d,aea9ba56,8aa7cd30,b9940c75,29cc1e7a,dd60a5b6,8911498b,9fff470,bc4453df) -,S(9c644072,318933ab,4d1459b1,d684c066,d3df3371,d7659a82,fd396bdc,a9fc9e,a115ce28,5a7d9bed,a2a962db,5041cace,9d3b2a3a,12149b05,ddbae7de,30cf52c3) -,S(5cd3475d,8a6fee1f,a6e3800e,911de939,a7568762,4f0a6e69,26ea6160,4ddec04,20063702,1d1d525a,f250876c,c4b49590,9ca8b39d,74603979,8c8b4b39,fa07c17f) -,S(28519616,c035ec81,4e851ef5,191e0545,5f0bbb57,12fcacf3,2b36de77,1c351f88,42ed56f5,5c51953a,6a367398,815963e2,64363681,f9a0723e,7b622784,5cc939c1) -,S(a4e11f70,b3554f05,d0634209,86549001,53d2ed50,1f09f787,99b83308,4dc894b,331b9d59,4260e0fe,381176a7,1873a66d,a7a3b9f6,2a930e0f,696f68c8,6939755d) -,S(c5d7c22d,7a8cc553,7ed85a85,46adde7e,ebddff6a,f7e8a6c9,96f50df4,248a4ddc,dd4749ec,bc029503,1106812a,cee59bb7,acf41451,45883a71,3256912f,be9ee03b) -,S(b56ad6a5,c6fab0,934257f2,9e266052,cdba0bc7,8c8aded9,f0e08490,71770c7e,6aaa84a8,99a4f8f6,3ca8dee1,6df7c090,264e644,de1e58e0,49f99fb5,fd5f4c34) -,S(16c4dbde,37e8df54,aff88810,678f4707,310f29b6,e9e5fba0,384220b8,4f0dec11,4fbdd92d,56a3f76,56b4dcfd,8be6b589,eb02c645,8a247c9d,264fb65e,c84a3a3b) -,S(15e63d71,f02f6bd8,1899f95b,d3051871,84b68d93,6a2ac10a,d29c39c8,d5ba9748,20204657,ae0e1078,6df04a71,938055c,ae208105,ef1beeff,663d8cc1,df478ed8) -,S(3c07006b,8a1e1fe6,fcbc3a6f,fbb7a780,a0008ed,513c9967,853a8cd2,5827dcc9,b2fe428,d4c8d974,72066ca5,ddf32e99,18b5e79a,e81fd6c5,e00b8142,566ce904) -,S(c7f2ddf3,b3dcfa04,91846f0f,2341b1c7,81ce2cd6,ec20acf9,a304fa5a,7dbe73ab,595d0b02,faae2b6c,f6e84bfe,1183ab9e,dcfd6c9f,411d7125,dafbf9d6,60ec5d01) -,S(4c239c01,c05d9c11,3d25dad3,3d14ab28,f94742d6,8c9c748f,1773b739,445bb643,dab0d447,de6a8c79,6809563b,e77c89e7,956f6c9b,ed930d18,f25696a2,e436ebf4) -,S(9e1a100a,c44c33ca,543ae407,f98fef31,28bd1755,6a16e5a7,c1390792,187fac5,540a4e2e,9864a32e,3eedd96a,bb08fe11,b499a551,497e0c83,cdba140,3b303821) -,S(c3b4d7e1,bf3485e4,d028e424,81608ab3,9fe37649,de75733d,78f725f3,63255d18,8f8b00c0,2210cd63,c04f07a1,e10b1a50,f05ad863,b8cbbbff,9b73c84e,c59b5ab6) -,S(dc226233,8dadc96e,5feebb65,b290ceca,f8f5bcf3,e1794f9f,6ade4eaa,b89f3372,25bebe7,cae8b7e8,d755862f,dbb929cb,872e1c88,6b7d03cd,b32303a3,b8b5ab9d) -,S(184b11c0,a52865a4,5f530101,24cb353,dfbc2d26,bdb3af35,d5f029e,6bfe53c9,237a79d,b53bcada,f0a96804,d8072832,4f59f03e,1dc7a76d,ac5fcd01,3838b110) -,S(4ab97ea3,943e8157,3cfaa8ca,680252f6,577ff2a,a93178e1,e1a3dcee,242b460c,b8a6293d,f316c9f1,5fb8850a,87bce47,27d2a38a,d1f5f63a,39d08c92,e9d6d242) -,S(a531936,799791f3,cfc8bc58,4a2967ea,66328c66,98ebad8b,5e5fe8ad,8cd025b,c24d6ae0,8fac8028,a3e0e079,426b94ee,2ca7c845,8efffe1,58f6cb2b,c9046c3) -,S(37cc3686,a6e75e4c,8d7375a9,f291ccaa,937c833,f9e16d77,2591e74c,787b1f7f,557c1bb0,a7c7ed52,93e44cd3,75b04a47,7788181b,b20dc1f1,f6704c10,5a8e399c) -,S(94fab00a,9418e31a,9a229706,112f9386,d537bff,f5f0c4f1,b241c475,4d7336ed,14bced66,1c6eb134,7684cf29,6a303e0f,fa5abc38,ad569011,c09cbfb7,8316540d) -,S(14b851dc,c6b4382f,ca64791c,74a3faf5,adbefe65,b36de8f3,74e12e6f,e3c20e1a,6353d0b,ceff99b8,53557d0f,a893df50,598e0335,249f96c9,4e7a46a,3c02ce1f) -,S(d08e3027,5e05da0c,22991340,8317ec6c,e4362dfc,45b946aa,41e6b541,92c7589a,9553748,22228787,2ae61975,d0969373,8cb346dc,15d07e23,68800ab4,deb5d463) -,S(365ab0ab,6d51bff8,d4bb479e,a666e110,9a838863,2a5f8cbc,b3241bcd,5ba88ed8,bca2f90,ef0d4145,90cf9add,2a9d6793,d678f981,1ad851b,b2f54b6e,6bd093d3) -,S(879e8da9,e1363822,b113e70a,b8072081,f0e34a99,49d698ed,a0f55b4,6704089c,d5091dc9,d33861e3,daec5550,1f52378b,65b25a74,27a04483,c862e0a2,dc1038da) -,S(17006515,8ceda656,b23941e6,33ab3ab,ebb527f9,52ea9876,a8341600,24dc10e7,39a7ce82,b0afdbb6,33e74517,5fef5165,cd44c8c9,d81be0c4,56ee0251,6410b0f2) -,S(574a4f4f,67e294f8,2055793d,e94bf7f8,aa7106a7,f7ef0f2c,3bcbf2a7,352f017e,eac4aaa8,f4b4cf2d,ed8c328a,99b24623,16ee6e08,8805f1ce,783c4cc9,eff7baf3) -,S(4ab81205,32603ea2,9f88ba75,f2f0c4ae,330bb5e8,7f371806,de04f87e,69d5e6b2,1f1967ff,cd42f9fd,1f892f43,f8ea945c,c0135544,acb8010b,8285403d,5e621456) -,S(9a4e968,82b11f0b,5e431867,80dd208a,ba25b3fd,1350ed84,f34f2b43,f03c4378,15653ab8,375c04c3,d7488006,1acf13d9,c5d669f7,bbf70490,44dba189,372f611b) -,S(267b8cc8,3ed6ef12,47a93f07,b4f1195,2fb1de83,6c3e3fa6,782b5e82,80cbd8b8,19bc5752,1a41c7a2,a9dc29b5,cafc66d,7e2016a3,334b4be0,e2811ee2,4ab8599c) -,S(69a8b170,876bb1aa,2faca2d0,a4ed8c02,44d2cfee,a849293f,5ffb4243,256a1017,f77d7a37,5315381d,97ce835c,296593b2,80c395db,a5311a6c,c7fc2c98,d314b4fe) -,S(88aad570,3a4365c2,96946510,5a3a7fdb,6e1f3e66,618c3fbb,ee4c4e13,f333b1ca,10ded35e,c15df656,fabfc4df,a1140b09,196d10af,e1e99b3d,7e1113ef,f7fb8670) -,S(50709e9b,8620f7f7,7b8b6c69,1360062b,cfbea4ef,6448917b,471c3485,55691440,3946b364,3cb1bd81,818b828c,77c771d3,833a1d4d,dc509705,2e5db99d,6cde2137) -,S(1ac1d530,7cf465b9,8f1140ea,bbe7a939,df8155a1,bd656168,55ae128e,bd3959e1,eb02a759,82bfa30,1f9fe87c,75b9dd8b,fe2d64d,7ea89836,1aafe22d,448b418a) -,S(126a8f88,e7f59ac7,3226f2c8,8851773e,873f1ea7,a87342fe,da5d9795,3a1dc956,1ce623ab,abb29b2b,b9fcbde6,a6a6f12b,ec68bfd7,aa98733d,f2452860,bf9349f5) -,S(592fe608,92c09243,20fb32dc,39e7a42b,1f5125ad,1e7d6790,9978ac10,5471427,c4d6ed82,4d33f52c,d975d34f,b9df5698,968a0c57,9b44bd19,8a67fee,9935d310) -,S(babab912,e526a92e,d903a942,ae8ad2a8,930ea5c6,17cbf913,7c074060,6462f0bf,76c7ced2,4318c1b6,c7295d9b,52bbd4b6,707a4170,d020e7dc,1c7b5e92,aee7a4c8) -,S(6554e9c9,bdb1757b,408164ad,1cafdaff,4642a3bb,cf64e785,42c324c7,5be1a903,439d023e,f6c63252,311cf494,4c46a8cc,a3d684a1,d66556e5,dc488d40,e5ddd500) -,S(79ad3f8f,4c429721,281a9b17,d9c05463,f26bdfd9,c856451a,1050b3f7,805304f2,3be5cb37,da868333,4f9a4def,aa8711a0,adb6721f,d4b2bd38,5ad7298e,940dbb87) -,S(fe559c8b,e982e801,7427d308,e50e4d94,d7094aa0,635e553c,c591181b,c9593015,9186fd9,c9fbecaf,f4747597,22b34b72,49fb72f9,f02a67a7,627c1562,ae80485f) -,S(d2b4bcca,38d1b073,5248b4a,7f43f277,8e03f46c,8d7f3a33,ad2dd9f1,70ce0af0,fe0bfaed,846a3f80,10fca999,d0c3b0d0,b54e2fd8,7a0bf751,ba40f560,9eb952e6) -,S(f6b9ecb9,631c784c,8b33a7f6,3fd0903d,baec116b,3dfd2414,4865b297,5c290faa,95fa4ed7,e67b828b,4c685850,4b003928,8ad9e27c,da175b4c,81730fc4,5b063355) -,S(3e70eafc,653ef528,aa12ce46,59c90ee4,32979f0e,9df260fa,b9063f3,d30de2ee,e240ec33,b224a5db,3761796d,2c1285d8,9cff64b0,7c36a184,996cdca4,839a0a65) -,S(dcc76f61,46d05c0d,67bdb161,dc395c83,663ebd48,6bbc6e62,f3576335,a8ee0c59,e451ed85,a9ae624d,4617f11d,67552eef,7279811,6767a29,59708e,3c21208d) -,S(3bb03660,430c43f7,e3b68acf,fe692b,5ed6703c,c808d7a7,503b3536,381180fe,c84c669b,2822cee3,627d4ff7,7c01c9c2,57c57e80,f35e4fdd,eab84a6f,b96fa1ba) -,S(5e266477,dd106005,6a59fc2f,df36b540,e051bd56,c9120b9a,41471c46,b1c5c60f,d6a7ff4a,ee4abbe,cee617,1ad01373,d7916899,5370031f,66f62229,1057e6d9) -,S(c1c13157,56ce83c7,93ca3a0e,12dfc0f7,270a0bf5,38177522,8850863d,37e5e537,750dae34,9090f275,5487778,5a126ea0,f3c2c0b,e3cb9241,326a863d,3179af7e) -,S(c03ae6f7,96692287,4cd10b76,d06ac08b,578511cd,c502762a,cf14eac6,4f1a913a,b3ba2ed0,6cd40752,dc97e450,10699cba,90f38f65,cc4623b5,44d7a57f,250640e1) -,S(5938d249,4edde81e,6fd50332,d81342eb,6cd0d938,f1f02ae,562d1305,cc665bf7,b585c184,1e17e6fa,9924361f,8d06b172,89782433,1d65b3c1,7f2a109c,8be27b13) -,S(e3457146,bf3f5667,e0621ccb,500854b7,a08836b1,e4315d4e,6479b3af,e5c2bcac,3de9142a,5c495249,14d3619,a92dc5e9,f20e4603,5cbe2c8a,95a8e683,bb287fc3) -,S(4187afe,4918d05b,74a969cb,14f54b70,95387e68,c043a581,7dcd1d80,4ca917a3,4e1c19eb,b38f0a15,36afd31d,bda30d09,3c776545,f2d8d823,bc3eae61,35585569) -,S(60cabe6e,ffbc3735,dcc19c15,1abfdf4b,cf082768,e62a1176,f056c4be,ff04640c,7b0fbd84,ee9d787,2896b9c7,19448412,c68a1ef4,e5c6cff2,51ea823f,76d6c4df) -,S(fc6883a1,231355da,115af629,4f06eef7,83447185,edc19e62,b53f3156,e0f540a9,73805d95,d8b2e4f9,d0fb36c7,9f09780f,c315c1b,724c5de6,98d96861,c521a6c3) -,S(90f37677,e738ee2b,3abc9d42,54085349,9cd02836,474624c3,9513950b,c325b66b,90884e24,a4171613,da7fc192,f1bc913b,31bda925,38fc0501,6a55af21,e08bb960) -,S(55e68c72,f76925a8,52d38e8,172e6340,3966f148,2a212131,cfca2497,ca40db3,ebd22c3a,1388485a,e4b48b4a,8b69b98b,755084f7,9f9018e,36769d5,d78cb7e7) -,S(c74f257e,e1bd81f4,fcf512a1,f866b9a2,19586a3c,62e7abc1,112b5946,d5b90e8e,aebcdd14,5555164a,bfa127ab,9f352034,f31a19a1,d36cda02,f51a88ed,9662f44a) -,S(bc63fc6e,d1963da3,7fa064be,f7a371a1,fb471ded,5bf084d,946a6eac,fdbb8d36,a26a6ee7,e178a31c,4ca535e8,e3d1dfc4,dadee69e,140a37cc,a306546c,26a75a2c) -,S(9d11ff44,5e331ca6,fa99f29a,78f5e769,44fbebc3,e3b45a6c,d46ad17,74a1f29d,2f007088,110e9ec,66e5f134,b6d61ae8,70b14741,e9b6259b,ff06753b,fcbfbccb) -,S(5aa47205,f01abec,79b52b1a,2625b773,659166f8,1e300d9f,46bbcdd8,532599e2,f56747f5,c7431031,5b630fe9,b162fa49,26757780,c6ba59e3,6e91c29e,c82fd357) -,S(14dafde6,c8818744,2059563d,1e2cc095,f4bf18e0,f7e41b9e,97a74089,f678ce60,6f6a348a,a4f72e60,9a44b01c,b688ea96,cdc7c3f5,e559ed8e,d9a1c7bf,cf1747b9) -,S(ad8cb71f,1a3739c,afc8a4e1,ea77bd9,f5703d4a,55812381,c5a04847,e85e9950,238d1945,cd5d6094,dee8c6f9,41a19b48,d1eb88,5c986dc4,b8f3908a,508d46d1) -,S(e88df4e2,8b7cb050,aa81792e,ad108c4a,d95e735,6443dc11,f77d70b0,5968de2d,9541f907,f29d79ef,83c25f29,fdfbf819,49f21604,adb5a5df,e939afe7,511cdcd9) -,S(d6b6549e,1ef4fecc,ab56860f,c7a8a549,a354d9d5,63b9d459,9bbfcd71,7631c879,df7a0e04,18a86774,ba87bbe6,132028e2,927985e3,b1319c83,4e1a400c,7b0ae231) -,S(d919b999,faaa7cba,99c79a2c,febbdc68,6d94e07b,3edf8350,6e9a729b,f0f834d0,4b19faba,9b6041f3,9d33a21d,285fbf7d,638f3a07,63e2b15f,df102131,49b94ed4) -,S(b89d011c,57cfd499,fffd2d1,8734f604,83df00a5,6efd43a8,35d5983d,573d902,977f7c06,ed8cb0d4,980c3160,b152a7c9,294d489,2c90fb88,1da40f39,adfe2825) -,S(264873d1,cf9f6f35,d6bbff5,a2405f40,a5568a80,2fa35069,ce422c61,d9f2146f,36b8e9c6,e73044dd,b9b9753e,c682db1b,550d8310,7e3ea3ce,e8ecf031,500b3c31) -,S(d4c388e0,950d24ad,6cc1dfef,a3735bf,bd9e729d,99fafc8f,e4fb5266,8816dde1,3d583de6,27789a58,fd4afbe1,af3f931f,5d12df61,7f5adfaf,95830cb5,4b13743f) -,S(80a2e2fa,40aed900,a7a55f84,d4965f0,2c5632b6,1317e801,b83ec659,cc06e35,9e61e863,69c8a367,72d6a4b4,c2b7bd89,405fad38,4f99514b,485974d3,2342f47) -,S(e36eb1d7,72d5d498,3cdbeed9,b64fa04,1da7f1bd,e324f1b,a734323e,9f5331ea,6c879df5,4a96d33e,6a66895b,f4d12fef,46d5fe48,8d62f073,238fdbbf,d94126d) -,S(7852402c,a08ff966,44a4c1a9,3f7186c1,43f0e1fa,203b5991,d3fda009,1e0a4e76,a9b15d95,3ce9b219,a53da27e,e1b03aee,5431e26c,f035fa1a,a067f1d2,d36d5402) -,S(5d33032f,f7bf3996,14a08ee3,a5b67ff4,850f37b5,eed88e4a,675b020b,90cc4ac,ff5c96f0,5ba73287,f3279907,ebd0fb7,9e0b4866,c32f6fbc,2541d8c5,cbe12112) -,S(138d3701,98eb6569,17b3fc46,c2a3a1c2,3f7c95d9,d355d51e,c85b6062,4675030d,94314f22,6581dec4,3518cd7,61150f31,51ccd59f,3ecf79af,482c4dde,8a24e28e) -,S(3f6ddeb3,4756ed69,de83946,b48281b,c2b60882,d0cd721c,5d76c5d9,ff898c2,be8b8841,12fbfe09,9af67a96,8f4bdcdb,db4469d2,34d64d96,99c6a575,518c48d2) -,S(74676fc7,cf3bce8f,c0c4a774,89b320c4,736b9ed6,171d0b42,17a1433,eeee384e,fce3cf3f,630452a8,1cf3fb72,63c1b5,b66df4fb,864d4b39,7e66c69f,2913c54b) -,S(e0d1a049,cd49ee87,d71ebd9a,95eef0a0,b1d7450f,617841b,590eab0f,3e883eca,99e00118,42e6a78a,d4c3ec3f,f7a61bea,a1a5f8ec,2f4e9066,978e96d0,cbaef51c) -,S(531b455c,c6051fc5,f0f3190e,9523aa5d,2d0485d4,3901600a,aaf207dc,7d2b1fdd,b95f8c0a,b0e63acc,542df948,4b112b2e,e49f53fa,7f3e1dd0,307d9161,7c0f313d) -,S(b86ba09a,2b05e91c,c23db107,9b34807a,778749c0,ed725437,69ff6c17,316e7db7,a91c815f,f8a3b2b7,e5d44357,20e3a513,32cf405f,7501ca3f,b1aa1f59,a01c10ab) -,S(b63b43c5,af63f2ac,3f6e004b,c790404f,a146ea97,94b1bcfb,c4d0544f,2ca3f33,31654108,481b7dac,cbd48e8,c20de95,11406381,ef38fe6f,950b4321,4b145093) -,S(63a09087,e237e0c9,686f2a79,af977ba7,26d77118,29c8ed91,4f99dc43,90c64d08,7771ce4,a5e7d43f,e12b5e8b,c819506d,3b85f52c,fdb0f9c2,92c22bad,790d3b93) -,S(77640a42,4ebd84f7,71734050,7ba400cb,9e8462a6,a91fd0a0,b8f152a5,f5f7868b,516688cc,f422e660,15afa46,b5889331,3cf2d622,d6c829b5,f1d11386,bce41640) -,S(963ae02d,62739bbf,e75965f3,d1b7786d,c3dc6fc,5667aebb,5544db3,157f8a17,b3a109d1,b56570cf,2a5e5056,fd9feb05,2e8f53c4,f2ced1a5,27c3311d,87ba9dfb) -,S(81324144,454cb304,36f365d1,c78ea5f8,9a73706,acc49d5f,125fa282,c28ebad5,77a71aa5,54c0da45,31ed307c,c7fdad32,ab82a4b7,2f2a5154,cc405a2a,fddd3cc3) -,S(eadb105,e80bf2d7,cba9b468,6f6b88ad,34008c85,a7ac4d53,d3fff09d,dcd566b4,199ebce5,872f9dd7,6c14821,622fd343,2b7b6437,3484fe84,714b137e,fa782bee) -,S(a030450b,52b387b3,35cfe8ec,683fe625,884ad73e,2fc1c728,c8d9629e,dd2024ed,895545be,a9009f2c,dcb20441,33f2fad7,ac704ab4,9435fffe,b92836f5,57a114fd) -,S(57e8022d,816255a5,f4d577dd,867d65bc,7d7fdfe9,ed8f993e,d9b30531,fa36888b,9b0b7929,3cef66be,c21b6fca,140e6fe7,9b9f2e8d,48555338,868b6c78,d300233b) -,S(74c14e1a,d52761b1,7206b61f,fdff526,f7008f94,b3707a5d,e5c2a600,97b0dd29,18778822,89711679,c5e41fb0,41b1a806,9b12b709,b526ca1c,44839d5e,3b51e72f) -,S(5a9ce7b6,6368077a,73c09869,38656705,c017faa9,2d9cd40c,69d8e57e,63f8e229,f716b144,cebe2907,928f4618,821af2fc,9de249c9,5ac61bd5,99a550d5,e97363d0) -,S(f0fe4fd9,99c66687,3ab4c904,b9b7c0d2,7f033a0c,7e6c1b6b,4488097b,cdb49fdd,1f4643f0,6f700657,90aa51b5,911b4866,c286128e,de489dc2,8e2d6b64,972738e9) -,S(e86c729d,19347238,a9e97433,355530c8,7b701aa7,d710d26e,6b15ebe7,4796857c,d6260d35,466dbe3f,58d2aab2,1c8d76df,18271247,9715bacb,2a76bb95,5b75730d) -,S(b4e3a39c,8fcb0dc,5a23610b,bbb564a6,765c0135,1a8b666e,d680291f,c97df351,3f1eef0a,7a235130,b5236a2f,f8c9d2a5,fe5f1cbe,22326ba0,54557513,82ec651d) -,S(a9c8482d,a54adc98,4db2d7ac,8fac659b,51c1237,eaf1d524,9bcfcf1c,4ae601b5,446ec925,fc148900,8ef10348,ee167a63,a10686f0,7a01772c,10f7592a,2a544a9) -,S(17adc7b2,c36b1ff9,ea40b398,53246d71,bb973bd8,b469f7dd,fce49aa5,e77b8c06,fc3111a3,8dfc5219,7f41ea77,1682bd8,618f9825,bb2f842f,c7de15bb,224bf573) -,S(328e9a6c,e7397c45,617aefee,130cb6a1,dd26e727,efcfc30c,3d8f415c,187d23b5,6320e80f,e4a57574,1fed0624,c0f956f1,d5b30914,b5da88d5,f63e17e5,64f8b927) -,S(22188680,f765065c,360c52d2,851f3081,b2d3eb5,4201dad0,60b536bb,a45a1a41,b1107c8d,430df246,3b3e91fd,904883b5,cb877b,c10b6f,397a0cf1,c4b6eb35) -,S(620f5772,5919db4d,53b8f89c,5669fc6a,5a3f3846,c31faee1,1e93e53f,b1d20bc7,7d739bc7,4becbd29,2784be81,294185fe,db047d4c,c16c764b,678f9d00,6d27feb7) -,S(49b1228b,b624c71b,2c23e334,b098e84e,d3d8fca0,56303057,49dd39bf,5296666c,3f316e5e,ca9c1aa1,fd5d23a2,613e756f,8ac5e819,8ac16650,a9dff05a,1c8d76d7) -,S(97ca98cb,fedaeddd,b13b86cc,4b6bd7d2,140fde57,dae7b847,c51b118e,e3d6b8c5,1b95c9f,1d6c808f,397c3ec2,a2a2b220,6fdf546e,8c70ac2a,78086ad5,ebe28142) -,S(a679e7e7,3df904aa,e80270b4,d5d57dfe,f5ae819,f240369,b773fa3c,609a1ed0,93201a4b,17286928,be5fdfef,473565be,879cad73,24124c6d,6e1614b5,4e6e5124) -,S(fe17af2f,70887958,1b9b176,4d45d76a,afac0afc,ff50ac8d,9179e53a,c5e3777f,f59728d8,67c3ab63,6d387352,a029b5d2,e9f2d531,7a508894,9a0f6515,f5c4d61f) -,S(f7601ed6,fd64cf22,57cc15e8,e554dc8a,e19e4f4d,ad3fb3ea,a7e819f1,98b3946b,a3292ed3,ff088c22,e9a62b85,4ec87dbf,394cd681,501184c0,b841656b,def0fa3) -,S(3dec302f,cad72c11,54c6b588,ad7f77b2,9368557e,77a723ba,6dcf9357,82d9d917,6484365f,537611ff,49f157f8,6c4bbf07,25094f7f,d8db9a2c,b318ab4e,632cbfce) -,S(a847783e,46ccf334,d7b15f1e,d3aa7dd8,c5b3ef4a,7ced2501,c26d1dd9,4358adbd,7c56f1f3,323a500a,a3496729,ace84a91,6bc6dddf,90435a09,8ca51f6f,5fe5fa99) -,S(dac6ee37,3c655763,b01c5012,fe01518,c3ac1b52,543cfd7e,9ca24d6f,42e4bcfd,6b861af2,f2a82f0,d4c458f2,2d264d82,54f16f46,87e31cce,7199f061,bdbc941f) -,S(27dc7253,90de6a8f,6cd9918a,e3b2f33a,8ca4307d,ca4acf6b,f9c5d0ad,f01b4dd,2a0798f6,7e583426,cca8ab26,e6742692,ee790f21,cb3560af,271b0a09,eb9f8b31) -,S(1c6a5d3d,10983673,5e27dd2e,ff04adfc,7bae277a,870eb4c6,d6379467,de2dea5b,92658db0,8b6b85d8,5c20ad21,f3ad33c3,8de02319,4bc54d0e,4d758093,b4e8695a) -,S(cab35e2c,b731cb9a,402f77ee,44565fa,d6623951,be9deb97,88da09cd,d5abb56e,37bdbec3,638594e2,59018bb,9145c4e7,dfb55b13,bda50c6a,c33e975e,6c5d96a6) -,S(97e4cfd,9e1ec85e,cc49cb90,ada87b99,bcaf8160,9b04417a,70fa66e9,78bf54b6,7423ded2,bc56ddb8,11db577d,f1863fe7,dc758999,55989e4a,d344ed4d,5faa9ecf) -,S(f2a9b193,6f63e9f1,8333cc3b,745fb2ab,7b3749a6,c59e7d6c,42e387b1,1e9d86fe,3c6b6bf9,1c2c4a,859538c9,db95a2c7,abbf8c37,b6e172b3,cc2be8f0,f18b5484) -,S(49024a25,11bdedd9,6c84aeb0,707b5b70,f027afb5,8b4053e5,234a9312,771160c0,22ab8282,914e69ad,8d573e7b,841e9eec,2fdfb939,c76ff330,fb2fa5b4,14a4523d) -,S(781c9886,4bf29760,c44e1f98,9a5266e0,4d25c6c5,f941e2b5,cf92b958,99ecaebb,994a771d,eac92f91,58ecbeae,6227d2b0,4c09df72,c5ee4439,509f0b2f,6e361509) -,S(8f7e703a,ae008b13,590ccda8,b70d2cfc,4c98480e,2a5032bd,dbd5edeb,aefb7f8b,54226771,863fa87f,ec101303,9238da1c,74f9f446,26b50f07,f35d6b59,bb7ff81c) -,S(ecb2e955,ed796695,3eb1ee21,564125e6,e860935b,20fb99da,91556cd4,e5e57bbc,75103469,9b958e18,638f4e00,654d6eae,f5631483,4c890ebb,7e2d93e6,9f4d8bf7) -,S(971cd7f2,9ce90bff,4c46eef1,9df001f7,afa6af09,b553e8c7,792f4ae4,d3f82cf9,d4180c19,7a579e31,f27874df,f29cd17,98e5740a,36380349,6f7dd211,59bda50c) -,S(7ad3b286,3952489d,42cc8394,413545bd,90fc63d9,8558323c,feb8e7e2,50ececf5,5c566bdb,5efc3683,2b22aac3,c0b81f6f,bf656c11,5514ac9d,8a223071,168f139d) -,S(c905b52c,ad0e0281,a90eead3,3939c836,ebd591b9,26787a4,2983804d,e658aae8,df2a40ca,f95aa72a,181f3424,98024f72,f1b9e46a,3816cf3f,ba5ac699,5b996fc1) -,S(e2517e6c,84856497,8ac94585,5c80bdf5,7c074b6e,fdb01cea,e93c17dc,ae4b3ff3,373ede93,2f369807,56afd100,e2f65794,69247690,61a597da,80d10fb6,bbadd3a8) -,S(4d52a8e7,2f3cd95,2e25c8,175e82b2,726a8d95,b735c8d8,a0f1805b,6d94ad78,248b7174,61287611,8000136,dc92b841,de63ef18,a7c9ff71,a10a662,af76ff17) -,S(58e5b42b,e614cca8,e131cbea,24b3debc,9d9390af,469df700,35a01957,3307ac,be4a397e,7809c9eb,2113246e,7812c403,4d42d8d0,c353d841,3001280f,db6bc220) -,S(3f177142,a6e6eb65,ca5e1609,cc89df40,3e3c74c9,e5b291cc,49fb0d8f,eff86ecc,2a445bb0,b648487d,3b962bfe,dc74e4da,d1d98845,cea5f4c8,d2f0c4a8,2bc4c514) -,S(3389c700,9b2b0c6d,a25a9610,4660a164,172a4c21,d0ddaada,c6902bd1,c9f04b38,413344db,77b83806,80647da0,d6086ea4,d1b8394a,a0047a9d,4c21c667,ade67a90) -,S(ecf3f933,4b2b656e,24ea0b14,7528c490,c3a566ea,c4c51885,d3ee94f5,7370b218,3c07fab9,b6404f24,77e4605c,345d3a93,adf9a06b,649206a4,b369712f,7388af0) -,S(a090739b,58310867,5e460a26,7e29f228,effc954a,137f358c,12be2fb5,8011b2bf,a3563d1b,7f242a1f,7ff5e505,280c3898,13251c4a,d9392d82,d3b12a07,e22271f3) -,S(a251cd29,357e5300,5a8600e5,bb9d56f4,c8251f6b,46b4d99d,5dca7b2a,31f8201f,51764fe4,596059a3,b1eb06de,56c6e21b,d58e7194,8e1b6e65,51e53333,5f9721b9) -,S(1f9aafb3,eb39814d,7173b85e,b027ad41,be210c3e,e5c857d3,56288b3f,3b05c5a6,d34526cd,16e7d3fb,76ecdfc8,c11b1bc6,38762bda,b03c1c07,94565cbc,df41febb) -,S(dbd4b724,1fa4769b,db161472,1179fdf2,6df4372c,d3b0c4d5,1e37fce5,317e7e42,7e9bca3b,bda0e211,5f2e69cb,8fcfc333,fc1b8b85,70123816,802b22c4,9634219a) -,S(9ce40b75,7a257205,fdf51545,7d6f9691,7e54a5dd,32b76230,4ec50c2d,3b89b06b,9b128748,851dbe81,255f60f8,1e5e9de4,6b20a545,afec40f0,38beb9a3,f7402e88) -,S(12f6c70f,46efbb73,2150f775,5f597fd9,2a527a33,7039def6,5533cfb,18df3406,7d9f18a2,4988ea,a41a1364,2a1555c2,bc9bfce0,dd62ba87,fa628b84,850e92b5) -,S(3132e530,9b169a3b,7401651a,351f7fce,43471b19,7ded3d1d,cb0b768c,5620fc5d,3e377f54,92c99dab,84f4e45a,7cba38e,9b589fa7,77dfb334,849310ce,53294287) -,S(87160125,8a8a69ed,d52986a9,25a54ed9,51f561cb,8ee9e1ca,6c58b826,495b9977,c5484596,8ebfc8c9,5f317681,78379b88,2e9c2548,b3c579eb,f6da5186,5d51f36d) -,S(82674b33,ef500391,2dfd5f2c,26722df8,19fd265b,3b6e4cbe,239bea50,298653f6,bb6d0457,2adf23db,86b07019,f2f59fa7,ebb4fd2a,ac36ff16,6b22e92c,3952245) -,S(2efc1011,28432933,56af99ba,ea2628de,a518fe02,c5b0eddb,3688c8ea,39d4b07f,d54a087e,bef0923b,6244b21b,f260eccf,e7d590b5,cf98be51,856347da,ea48779a) -,S(f2164194,5de0542c,de90f1c,4be955cd,98f6bb14,ff30ab44,92691985,882fad46,a87f6725,e89afd3d,6f24db13,39fafd45,5f578c9a,104f6509,c83d0694,ef795dda) -,S(72d2c60c,6f9bf0e5,5de82932,88c298b1,4d851deb,6ba7421e,ad22f3d4,2b47ee88,29626eaa,712e6d76,d85b9f7a,7a17461e,132c9bb7,a2943379,c5eee30b,1ffeb1d8) -,S(9bc6dede,ebdbd843,a5534fc4,71212480,ecfba4d,96acfbf7,25e980bb,8a509773,24ef23cf,e1580173,797ffe5e,baff2fc4,3cbd3161,e87e32bf,463333db,5ca904ef) -,S(20ea6c3f,51565fc2,bd5b8eb8,1ccd20fc,f3aafee0,9ccc9de0,733df6ed,8caa9c81,78328fb1,ff260b0f,cea69e1b,77b35679,d6663513,8f136c59,127ec2c7,d9668dd4) -,S(aaa2ee28,a4724d91,f37044a1,3b264ea6,9dd9123a,b3b7b300,999564d1,73057339,250b6164,2ade568b,8a56ae82,4488e740,b9a65f7e,a2b95f3b,4b11b6a3,1b49fddd) -,S(a1e54535,4a8976a9,33c04366,f0361775,824383e5,2c3aff3a,357788b,38014ab1,a6a306b9,b0a7d3c3,d6530094,9efb038f,a0a2cd1d,79bd495a,487a95f6,ef2b7a7) -,S(f2b0c76,18fc3ca9,f9ec5d65,2f39b6e0,158598b3,cb90b20a,53fdaf97,ac58f7d7,1d63cacc,7e8e46ab,47ce7e4a,e5a3336b,8d3d9bf0,f05bc428,f6f769fc,7ec6cd15) -,S(91843b8a,90a43571,4d7500de,fff102a2,fdb53914,2bab12bd,d3f23576,75a9d62e,3cc6365c,7dc3813a,d51cb2a3,d86491c2,c4e38f2b,10a33181,374bb0c7,ac90237e) -,S(f73b2226,8122a4e1,a440f891,14fd8d72,19cad2c2,9798cd0e,3631eeaf,6b125a92,bc14e84f,ed149aa8,ac261f96,6b192168,26f5a2b7,cfb997c8,3f293101,e758aae5) -,S(e87cfcb7,1f2b1c9e,8506b0e5,c56b14a6,52201397,1bb4c53c,855f1de,45644ff3,7e3399af,b4a9f70e,63907a29,c02e4d58,b2e76517,e4f2f2cf,a3d2fdff,808d5b08) -,S(b9657f0a,6de5cebe,47151293,de1fc3fa,b2745a18,bd5c4b8c,62282f26,84404f21,89590e9f,a787f41f,79a0b8b7,682bc353,1ad60107,771233d9,ec303830,e8e8dad4) -,S(b62d02b9,de395843,eb69e8bb,4d974590,7c8d3b26,cd4b13a5,6b4a0e27,44f449d5,173cb5ee,60d3999c,7e795607,bdadf8b9,acf9282a,d7a68ee5,6a204eff,ce5fe751) -,S(b6998e3c,31e9cca5,251a9d89,1aeb5384,fa86c92,74a0f027,8f2dc67,34b5f8fe,7658a71a,fe032a5b,ccb80a1b,1516faf1,5a3e8638,6f74b2b9,b6d17cea,61c3ac5a) -,S(864d4c66,4db88b56,6471852b,eacce0b3,52b55404,46444cbc,afad4f17,204a0170,7001969a,fb35a3ad,fc553e00,b6faeb21,c8fb1af6,135e86c7,f7e91397,a826346a) -,S(22a0ec9d,ecf7a2d4,6f550ff1,5a8f1c8f,6efeff9d,3ff65d47,97512980,216c025e,9d60fca8,97662f4e,947c962b,48522cda,c7ba956c,5a23c3b9,67f46073,af0980cd) -,S(f1be1f63,769f74f2,947eb25a,194171a3,9f9096af,cd454ad3,35809b17,d7e69fb4,b78b3a16,b734c528,c1911d95,895bf873,fcab1440,b62211c,25aa247c,161af243) -,S(7b196c23,1a7650a5,9db8faa7,39b7ffea,488b3623,a0bd7a2c,48b51c97,f5726c76,56e84642,2c430157,bfab8821,9112124d,6bb968e9,3ddd6b77,7ee08228,9a7e1241) -,S(6ad31b05,5a1f1a65,f4e554eb,31e3e048,8570032f,8af2891f,4436c640,9420849a,edeafdae,d10bf173,5de8ffe8,41871909,79f6377b,4cb566f6,3386534d,89bde755) -,S(fb0f3da3,a44c0921,85d90b80,1e7f5aad,6c85d5d0,b9cc4575,ad95ab34,4fa6aa7f,7857f22d,6f9356b7,96020384,919e26de,b9abd707,4dc6db0d,768f630d,b3589b18) -,S(c39b4ddb,edb892fb,2394e875,7c7815e2,f487f81b,45c60749,1c314350,c929d96,530f0c07,68e66dde,e10f0d95,bd66c07c,ba10f165,dade7bb3,77f8b7ad,ac4a673f) -,S(c50b3ae6,d14b11b9,a74dffeb,a5bfb9cb,73652cdf,a2bee6dd,6cc3c912,c312e537,85ac82f8,e3aad88f,9af29cb7,ba66f8a5,8c340d03,a1f32654,2071ba6e,99705377) -,S(a763e636,4e4959d8,9d3047,bff6fbb1,912d99f0,c092fe62,947d4385,2427ec02,bd799a82,a3cea8e1,db94946d,c7d32236,13b008b,da8eca4,921c985c,c022622f) -,S(2abdc992,b2ba838,1da0c2c6,2b35d3c4,ec1a1e39,516b6afe,81fdc7c9,cf3715cd,8115c826,d214c36,36a8fcca,37e89dcf,4be7f34a,2cce7357,3a6c42ea,9e084a66) -,S(2cb83bfa,ef83ab3e,53216500,944b2db0,e8cdb6a2,caad1eec,c9e14c33,a16a07ec,5b1b1199,6e84c17c,13c070a7,99dc0975,3d374018,6f9ce89a,bced7539,7121ec7) -,S(2687de95,b368b07a,7808ebf,e45fde24,d66fdc81,a02744cb,3e96e847,f0a3ca41,5728b8fa,aec73963,236ca282,d1a8946a,b2a26f28,a239590f,9d38bdda,d05a846b) -,S(b143029e,7f32bd1b,a381fe82,8da79713,b53550e,f3cf867,4ef1e952,d4dff9d,a44a622f,ff5fb466,83b69803,c6ea5c16,8d86c673,3ed94058,81aff0a,2a8edfd2) -,S(4c54d53f,cefac583,6fcf3b87,7202afc4,ccd68695,567c7fe7,6068546f,aa9070d,7f42728d,78193fd5,946f3787,6ab124f9,b1045ae7,45df58bc,cab6f59f,a27c6f18) -,S(6b625111,556e3ff5,db9cd8f3,7f610b3d,718220b,e459f546,47314b04,b2ba9d6e,b3ae66ca,fc58bb7,5a057767,8bf806b2,c204b90a,fd114ae8,4ed51378,53b30a78) -,S(b3fb12d6,e16e4279,5fcdc1ee,23d42f9c,198debdd,56217af,5b76989a,271b473f,d38adb77,4ce1d0b5,e41b65c,7c973a27,10c5621f,594e6f70,d235f5e,a4a89386) -,S(9c7c908,6976b590,ba9c80a5,fe12c5f5,ce6bbdb3,5a4058a,3cc59899,82073ae4,399687af,4d3e221f,6168ded6,31644c35,e41606e,94583429,34693221,9322da67) -,S(28cdf6d0,f0374a35,4dd169a9,1c3beef,fc88dea0,4922f841,401ffe91,8bfbddb2,2b8f1d3a,6f001d60,95aab0d9,d6248cef,cf3b97a4,850d1a43,ad2bbb3e,d2ea4518) -,S(1974b196,a25b6446,2ceda38d,d99662b9,7dcd0d7d,15299c00,9b8d14b7,f139e7af,c685622d,96fd6379,6bfc3f2b,6eacd54f,83281ef3,50d2fed0,2507a157,9fcdb74d) -,S(3beafb9f,4cfa3570,3d3346f1,afa48acc,25909889,a60b76c0,6e7774c2,acfe4367,6c8c09ea,7233ce1f,cacc82fc,9c1dd357,51021b92,fb86d6ca,3749bd58,6dfa369f) -,S(b5cf157c,4586fdda,16a111c3,9a500daf,b1aefb07,e32f78ac,a23664b,cef3be73,1d273f45,58e7c2ed,6f46ed71,e297dac3,59489934,b10afdc2,cf0f4270,ad6fd53e) -,S(9bd52baf,cde37895,9439aba4,b1fd4080,84441657,c2b1b36,c45446a6,7b661d6c,87f63761,6dba07e5,96d71dba,f86df28d,c506a123,c6f082ff,47886a93,da068ebc) -,S(20cfa2f5,b391d687,b89cad8a,a4c5ac8d,8624d4c1,ebc94cd5,d47999fd,3278febc,1bd4a896,4641d8cc,f6926323,8b1be2c0,49141736,ee780ba,d2110f27,a674239f) -,S(e54db30e,e18cff40,56473478,2c61d437,c79adc23,51739315,ba845adf,c7e8b6cc,ef631e42,9529a407,cb3f832f,6aee6fb,a26b125c,fd28f43,b9f07e4e,ad8b0632) -,S(588f13bc,3dd3b927,7508ca9a,82ffe280,fabd5cb3,1413e848,2a2aa4d1,78a290b0,95c81a4a,44e6af9,5d8f6fbc,ba3884d6,d6a54057,1835184e,50f5db88,d08517b6) -,S(1927e8dc,ddc7ed4e,62a32a82,bd4a0977,fe24a571,10b1acf3,78826484,de7e757c,e0a9674f,76122a18,dc6004a7,ebd1da86,f98e896,5585518f,bc5f91d0,4699719b) -,S(7b82c663,aa2201cd,71dd7c2f,b8303264,8639f9a7,9de52706,e2deb38b,85dfcc36,90dd6e59,e98c611f,a7162fdf,8fc503ce,71b0ad1,dd150698,e4c21916,d5ded962) -,S(a15fa4f5,97086036,9e9c3946,5f16a458,c7b36ec6,6ad384db,7803ce19,555a2bbf,bd406283,43e40d18,25a02557,6bbf752,35e34400,dfabf022,6cf2bd3d,8fe80901) -,S(2b6199ea,7c42b7b4,2230da51,a895ba86,83950dd9,d4d5ecef,80512976,a0df55af,26ecea05,16faa497,3fb9865,16415ebd,93ce4a6b,e4b5cf11,3507d3e6,6a70b692) -,S(35ad2f4b,b5ba61de,364e8198,f5404ecd,4cdbf26d,7072dbed,d9892804,364b43f4,5481372f,7d1af5e,9e60cb02,ae8512a,6bcee9c,eab1344c,6ac5898b,aeca2e94) -,S(f4eeca4e,2ab38839,8a459df5,b94cf98c,68017522,353aaa98,bc606bf7,5008c6a3,e016b7f9,aba6e910,6a647662,1e7a5b7,12ab97f6,498f451c,21902e0b,9b6c2c2) -,S(6c488180,aeb6c444,78ef24de,21a47431,b2e26d9c,bbf059a5,84631829,a75ec053,ccf084c9,38491cfb,8cf0349f,fe80a315,71bbe0cd,dad9a7d,a4434cbc,9160baae) -,S(a52e5bcd,2214d405,57360828,10ebe384,a94f79a6,579a8966,6f1ef7cb,bc80f4e,c28bb594,e15c47df,9bf4ef2,2666fe4b,d916dd9b,e62b60d3,49c2ba11,506fb79d) -,S(c55414db,3374563e,5c79d9b1,1103ad01,7b7c04b2,3afb5431,8c469cb,49ea9754,f54a4335,7bbaf088,4d18bd70,6f3d69a2,44f4d527,a6dccf5e,52f468e3,752a998a) -,S(b7771609,335ac0ee,1e82539,3fd3cfad,5cb4b06c,98a05bb9,95966e4b,6fc1f24e,f305d878,33f95e99,ff6a3b4a,2b77ffa2,4cddd5af,d253ebcd,d60abb1,438e0745) -,S(da220e1c,c66af350,10736e75,483e2573,91f6d2e1,d355d05b,8471cbcd,4b64832d,bd028d5,5db1c54b,86f6f123,bbabe6b0,f3e52e02,ca48d92d,464311a,aaad3cea) -,S(1a680b36,991edb40,ada892dc,6c102b0b,186bce17,280f9850,ca50eae4,6951ac7a,f03d7958,b0789cc1,43d61fc5,11b70f9f,1ef17239,dd6a057f,ca394f62,225ed9f6) -,S(af8ca10d,b1975668,b8071ea9,5d474b5e,424d461a,e98b5ab7,bc240cc6,44da9c57,e74ea4ca,59f926fd,89bb2bac,61790ee0,50d746af,5e30019c,5b53130b,9cb9786) -,S(e6014570,2ad63dd0,5d98c576,c3d5158d,162857f,7b83045e,d91865ac,bb347922,52931836,4a9fe323,40f13c0e,15c955fe,f718ec64,4b45b141,33fa2edb,c65baa18) -,S(56eedaf1,fec96ae,c2f1e051,9a1c4a76,dc0ccd67,1781cfbf,7804d215,626dd5de,adb8a791,b73aebc9,c6406e2f,83e611b6,286761d1,a6c759c1,de85658c,a4788923) -,S(43c5272d,a3dc8c2f,edb0f5bc,a5bd5f40,fea4bd48,9f367675,cb578690,636fe0ad,52c62fe5,1cc2dbbc,57de501b,839cad13,b94c9e12,12b1cf30,d8463605,f7871c43) -,S(66e76528,7cd0ebb1,9d9e0d76,aaab4230,1aa87367,c3a3f96a,101c6125,84f816da,39a4d3ef,8d263217,3a3a8c3e,d9c1b460,e240cdc6,9c9cbaf9,89535604,a2f28edf) -,S(1a274502,31f1b5c4,9df7564b,f311a7bc,d5123e75,2471c243,65c0e142,d3b292d4,5eb550b4,ffcb5e1e,c695f22c,dafada32,1e967ac3,7e1fc20b,e0e695c4,324c1131) -,S(36f1c3b2,ab6a692b,5d3b1e10,f53b43c7,7d5c4e76,90e089dd,9e70eac2,773c3620,5553cea3,8e56a7dc,384458b,84c419cf,2d493246,1f75f16f,2d1a547a,6fdf0289) -,S(1ff0f8e7,8318fcb0,2b23a1d3,61015c67,6b1a446e,784bbdcb,c088b241,3da40369,39db7b2c,6923a1a2,379b58ee,cb91ad5,554ed5c5,60d5ddba,225c0074,e9fa4415) -,S(c5d7b7f5,d6dddac5,2a2021e8,437f771c,216bfb43,24c57ba2,e8b43a0b,dfd17e8a,78fc37a3,9586cdd2,f1145cd6,f9beda83,43e8ee5c,854c256d,419fdb4,1c9d2bc0) -,S(4af5a3c8,cf107e16,fdf3522c,47fff7c7,b2fcff70,c6c8b36b,7d66a3e0,4b107250,b1b6e5cf,de869937,45ae8632,c5e2860c,76a5f481,ac24ac86,ad135136,e9ff4e04) -,S(37b59d45,86fff48f,67ff3ea3,f31f721c,3daee8f1,a2ff960e,3f77b793,3e35b50,73a7d048,2c93b9eb,4c2f6359,3ce61497,ed455970,9b2ad7af,2d0f834d,6f070d98) -,S(6e9dd180,d5b7c41c,5f529439,e46534ae,b80bd802,b8b12e0c,ccf532ad,a99e663d,e981b043,e936da7f,ecef09e7,cd118646,5bdeaa64,45a00a59,1139eb9e,5628004e) -,S(fde9062a,9f7e13dd,39117543,be4aa5a8,fa10b810,a2285661,720b4586,68acc236,fa39cd20,a5eee1cf,3727df99,32c5289a,96b1409a,5721b9bf,1ad8f42,ee35069b) -,S(d7ef4012,ecc74538,16c392d0,4d1ffdac,76a30992,4c1489e5,159149bd,84847835,b2f5e699,9883a21b,edda98cc,ccc1ee2f,258fe291,c508cee7,39619659,e18c9720) -,S(8355ef2c,f0e37956,56b77adb,5f700f75,47e2c14a,b5f6a0ef,8716c99b,a919612d,d75dc6c2,fdf0260c,6682b16b,42d022f2,f03bdd1b,1e6ef520,da295465,a1988eee) -,S(cd49e795,63655bfc,87bbba18,b72a0c50,52568a26,53bc0543,3661f3e2,2ff159ba,ab28dd46,696b7414,1365316a,c8cd8dc3,2c2f5e01,6ae34302,d103cac7,4e37d25c) -,S(8f93b20f,28f89a46,1afdf08d,7550964a,dfa8df2e,ba2c00e9,9d351b84,2d6e0b78,92ffb09,812b6970,7746493c,c833bdde,6849a2b6,ee7778b8,2b41adcd,62b5620e) -,S(a7b3fa74,4621cc50,f6719d0d,5fd3f2d9,6acd3163,4dad1114,3ece3db5,d114ab2,948a3716,9394841d,68e5b64d,2f86798b,d78c8530,bb8d4d61,f82b5f51,ed0f56c6) -,S(e16b540,d62e3237,361ba514,a11f2ccd,ff72ae57,b37e58c5,d4c3c49d,2cc8fb7a,67efad5f,f02c36ac,a0c0ab0f,ee5e5135,fa7bb3c4,51472d37,abd0711c,6618a7ff) -,S(589645ff,5c3dc06,9d2ff542,5278a51c,c4fff14c,3de96036,b773497f,8940d240,1ea7ba1a,95f65259,c30ce21c,a95b3b95,83d11b10,3c8e633f,6dacbd2a,fbe44116) -,S(d551239e,3448ccc8,9a83b8dc,41396df7,d3db0c3d,f79490be,9d44636e,f5f0d0d6,779118ae,a8db8a05,f2231b5d,923e9d97,5e69a462,5c2ad551,5a8e7777,b1b25899) -,S(c45a22f2,9f611893,d8577d7c,9c1cd46d,82f41b48,a7c18628,ddb609e5,abc434f7,515624f8,5776268b,5a5c74fd,8d87f8e3,3e47648e,2eb8c2e8,27e9b57f,7fee5a1e) -,S(fb8e4546,639d9571,90f2840a,2f72ba12,a72063fd,85f160e7,18477d01,26132b85,3cead630,f8bf75c9,31d19cd9,6f4f3718,1efc4854,b937ac31,c3e0dc6e,363db575) -,S(ec51e7e1,6cbc70cf,1f053860,fd21e120,98b652f8,df9eb31c,74eb787e,87e5ca5d,bd5afa95,6996b7b,357b475,fa7a326c,d6c2505d,1ebf6fa6,feaa27c2,c2685867) -,S(52c497f6,f8b9189d,30fc42cd,9c2a44d4,2d4f70ad,815ccf05,4f50571b,2570bea5,35f54d97,a45e2712,b0f9a720,38adbb27,a31cfefe,c065ba9f,883d36c5,c070e9fa) -,S(2fd360f,1680b7b6,5f49f64d,5a648e8c,97e4a756,fe88e107,91fce9b6,295cfc85,7a88eccf,c4d82e86,72780c6,e1c34bb7,51a6029e,dea0cb77,3d29a85,b0689f5) -,S(7b328546,25307c85,f9ad0c31,ce2c31dc,e746931a,57ec42ac,16231165,74f63d78,6862d363,4360e404,9693dc03,772f4840,4a30f167,993c8f1b,56244c0b,af6e29ec) -,S(af76b473,4cf5f641,25124792,fb558b97,df60d67e,41c2b104,ba27ff35,e3be96c9,21e6d4c6,c1e0d3a0,69520227,c4cf2ef2,8204d85e,26f4ebc4,5d6f81cf,10defdb2) -,S(5b1237e0,54c98238,df2ccb28,a5b42b64,cabac24d,1126c8ea,5520ed69,ac449521,de7ac1bd,4994cce1,8800ac0d,5499c33d,bdde3096,1a0c9028,58de0325,b91ffc36) -,S(b81bcaa2,25743a49,36fec95e,13c8c20f,f818ee5a,6bda3850,870492bb,b3380d5b,6ea959d5,483ea6f3,5b3a4a5c,1987673,a8196c98,d8efe8d0,3aed5884,dcb391ce) -,S(5f6ca7cd,1054051d,3d8a2a83,73be30f3,516b305c,feffe073,ea2773fd,77eeab3c,89287d8,22775f53,61c931ab,bbc43d38,380488fe,5e35124c,2daa5441,3b36c126) -,S(ffb3a36a,8345f9ca,30369f21,f04dc9f9,d5f0282c,d0e1d68b,f5ca1cc0,c05ca91e,21ddcc3e,f5a94fd,8046295f,c0629b61,b1e8fea9,364fe659,d298e0b1,be5a6c17) -,S(51902e3d,8801dff4,e6bfe7e8,8f600d75,42eef0f6,e186df29,3a8c691c,d57b36f6,48a27fbb,cf9dd38,a1ab966b,f635fbeb,35bc3fcc,52f0cae0,d9a3ad5b,2654eaf1) -,S(f1a68a75,8f0f8937,e14a48d7,15c4cda0,679d9b9,12682182,493cd9df,c3ccb345,db85d3bb,b8431e56,d21e8c1f,4eb1c750,225bb222,38da0bc0,30e5da0b,d4f4a985) -,S(81d88ea8,4969d53e,fd0aaaf4,248a3558,f37059da,a4b3d32,da538bf,ca1a4d15,840fe961,11756d96,5c8cea1,32067ccf,31ac66bf,e1086f16,afccdbed,f16a2d33) -,S(b5830ab6,2e236cbe,345044f3,af940029,39b00b52,e779ce10,b02c446c,84163e95,d8720333,b210a391,499f38e,134a0989,254faef5,126750c0,ec2a5850,e1d4a821) -,S(b50caed0,a4e9e41f,f03d16ee,1848d92d,d4e6b76e,4e2332f3,793e8650,20bc4d11,39195ffa,13745502,eed8801c,40f36e2b,d9b636bd,11d62388,8ebab8a6,41d3ab54) -,S(6190402a,3750824a,149945fa,df942c0b,3622acc,b2ee1304,f260593,8de5c333,290f4d4a,73a1c72d,c5ff4228,41e2949d,966da112,5278d082,ab779e8e,d4cb179d) -,S(8966488f,4e991a1e,e34552be,c6246b2d,b9486442,47fda545,f8083b7a,b0435060,7daa3ab7,87283446,a7900c83,b726b849,f7dad684,6326148a,aeeb6233,738c6c4f) -,S(edfa388c,fd246c1c,6bb7bd9e,6d9d335f,9cbd7018,ff2a750b,4ba976d9,dd922b5,c74e1113,f10e6954,6848e4f4,11a5afe4,bbf7dfd5,d252e66,5789627b,b81ce714) -,S(304740e5,1b99d9ae,97de2a55,8dc1abc8,60bb8b5d,a52f6208,af8e28f8,89904951,8ab409b2,3606089e,4a111377,c8a94e5e,75ecf098,4f62aa63,faaf7e18,f93a37d0) -,S(d4ca8aa5,e31028a9,37d77295,96b011aa,c26f58cf,3a7ff671,99aa7f30,3e00bc30,5ecc09b3,bcd9afcd,309280d2,617cbfb7,e4a9350,b4ef79ee,1e46a8c9,56d46fb1) -,S(4110ec3b,ae03a061,59910aac,4f2e4bd7,77d5e055,4eb6920d,aac4b835,2d7cfb4b,c1237e1b,d6f1cf1b,6fb0f248,9e3712ae,5557e4b2,f72ea7a2,2c482e6c,d84eba92) -,S(f7c55f97,3e9df72c,c9da8e04,b1926688,1d53f810,fef5e664,99b81f44,e4f9800,4b45e93f,e02c3993,95238c80,b65533d5,ebd01cbf,1b3dbf44,4d550cbc,4652fa89) -,S(2de3290f,56fbee3e,15def5a0,5d65436b,9d722e3b,a435f269,a5ee0231,857cbd29,f80d2ac2,356ac72,f3106b47,5cbf3701,bf924e3,48e93c9b,f3327b55,bc203828) -,S(c8e3d2b8,21922146,1862d5d3,319c2abc,7dfd568c,59df4367,eb975a95,6e22fda8,d6ec1b9c,e758a8c6,47e718a3,ee8ae232,c416d763,d2887e19,54ae4c30,30404f20) -,S(50c1a147,c117d907,fc831f72,9be19b3e,e93733e3,aa3bf402,e64760e2,edc82065,acebcfda,80706b53,116e4cc8,cdede6d,5aa1b7ec,62ffc942,572f729d,47396289) -,S(7bab8930,55114c0b,e4f7637d,ad165491,c21d6970,c8036375,1387012a,7b785528,6e31589e,2ecb13e,b7bca5ee,39e3bca,fd2e5645,6574a642,131d6178,901c0d97) -,S(dc94ff4,44a12ca9,5180904e,58802ed3,d1be43d9,8396360,e9e932e5,622d257f,ee2a426e,4da3dbf9,8a6d5ad7,9a5437ce,6fdbede1,25e836fa,697685b5,989c86e2) -,S(efb2b411,e66f8e8e,186b0fd0,c572381b,e9edc68a,903e95f3,759a11b6,b6a9dc40,4a7af79c,a1383f20,55bd080b,f410f554,24a21ae5,7b57b63c,bea36486,6c30dbd1) -,S(2f37ff22,26a0c4b8,77a36da6,7a423f59,497a26ca,8066a651,c13573c4,4954599f,f9d1c91,2b74f663,56798637,9de41a46,683a7cb7,61ac6e3a,86d65094,d1e07a8e) -,S(63aa61b2,e24fa178,95688d95,442844cd,7e68edcd,98eb3496,ea071c4,5b46abd,9423daf8,b6c241f8,785b76ab,a40803b0,97da461d,cf6579d4,4308c9a5,e63ac4e5) -,S(58618e22,93c52375,4db8187,34e355ae,27b73f7c,4469d7d9,115623f4,e8e20900,8531be34,22616853,c2c095aa,138819b0,bccd7c51,1380c64c,65ba2500,ae18794f) -,S(61418bdd,2619e7c8,f32c8cc5,34097cc7,4a9a0c57,a38db50b,ad828a60,f658fc0b,acec4e21,774d283b,db9a8a11,115d20be,20cbfcd8,2d67b10a,3d57dba7,74537c48) -,S(79ed2dcc,dd4bd25,67dad04a,b32c9273,39a9c592,95a69b09,be7965a8,c779b2fd,64860dc5,d17e409b,4feef8ea,8a7d7350,3eec186,1fa15f8b,f5576a9a,39f65283) -,S(a20434a4,c51da2a4,c7a6699,84f41ef4,67bd4de8,a628fbe1,385693ee,6b6d8a52,e2a00a0,d00aa33b,b49743ae,6f9c824,d2fe1f7a,f51f7720,cfb0d800,94279dd1) -,S(d8c0bf47,530ff603,c140503e,84fdf6d1,ed908b98,cd27136d,ecb2c4ce,da9f8c61,19e02399,bd898b4c,b9987fb3,4262df35,9b32cca,430e7cd3,aea9d20f,530610aa) -,S(29f06c46,a20b5387,aeb6e490,ef9a7bda,ce16fc2c,8e8eb202,b75973ea,8dc4f3c0,2220f678,daae0cd6,8514c091,a1dd7060,b21c2630,138b5e32,e0d57d79,b7b06d7c) -,S(b18aa504,d9cda828,e67d4f55,ac51c961,e9603d0c,ff737c16,42f1c8b3,fe81aeb9,1f6d7e83,480a9290,789c016b,b62e6e8c,adb4b500,fac710a5,7969bff2,89578ba8) -,S(e7591f42,e649f9f4,477c9cb,bc8559e1,f01eeec5,e9f3a0b4,8d9bf515,6d2044c,24c8777d,5e7c3f7b,2c6fe0e1,cd0e3845,45bef898,aff192ab,c4e719d8,ae466385) -,S(65992fef,50a1983e,bca478b,419ae258,77ce7a52,339ecbe9,2394dba3,8ba72081,32491cbf,baa7f8a,9cf21a4e,57ffa85b,eaba7653,d46d9f95,b4e25212,7bf76781) -,S(771b52ad,e47d035c,ddbb1012,bb89aa9e,b774e0bc,aded4998,86e1e358,ccabf9be,1a897dc8,420a076c,5a723f30,206db0bc,e9760b09,1f698952,1c4edc17,f2dcb202) -,S(a7d5c532,bcaa8ed6,6846046f,d1570837,111281c0,795d3e50,16cd8108,5721d644,13ccc5ee,4bab0d34,2f740ae9,e538d50e,900aa30c,bfe99e54,c69cecc,f18f6aff) -,S(fb504652,a55d01c8,b45ed7,6c71d,9067026b,27e9ceed,c38bf6fc,aee16d50,a150b6fa,f37b0c6e,ce4ebbef,22277b37,44933fd7,a135a25e,5ba8f7b6,1a6b7d0c) -,S(6242a221,115863a3,73bea0fd,39974dea,3c33b794,68e04087,8ebd8bf3,ca09f1d,b806de29,fe9eddde,1556c09e,973fa20d,c4ff916a,3d22504e,19e33169,f6f903e2) -,S(30382a2a,fefc7110,77af1a7a,d8a4a4bd,622635bb,73e50bab,c58116af,d1e8f3cd,d7ff3c80,9845a620,d53299ee,98cf3c6c,499ade93,84791af5,d6618866,3b6b74c7) -,S(b69ab576,13d1527e,990d747a,bab1582c,af995b34,6b25ed1f,df3490c,5549f36c,cf896a0e,4878bc0b,ffa3a750,f83dd329,ade24fa3,76acdba6,dfdc294,768e3f41) -,S(36f6c331,4071ed0d,b2be8f45,fe19be0f,9b37a675,a56679e8,bb49925,9339257c,d593ff7e,a32103e4,9cbf2995,21ad3da1,5b1b44f9,d6c95418,9c794291,b1e6769e) -,S(fc312428,7a9ab1b8,3efce7f8,17f707ae,320dbe77,e5937cd1,513bbbbb,90ed9995,11bce5f0,91dd9ef8,42a46aee,6f3a1d,7cc23da7,381a5f24,4b5a2638,45b2bb0e) -,S(b0de8720,58e1165f,ae1207ec,5ec0888,5f14bab9,35a2fe6b,1f7212f9,7b4913b4,5bab24ac,2589b8a8,c5e102,26a907ac,391289ed,23fba10,b2acdb74,a142b395) -,S(699828ec,db84587e,31ad233d,c27ce5de,a8f4e03e,2c450706,d625e387,12c0af3d,db1d9e5b,9a74caf5,855aef9b,6b8d0c18,c98c27b8,ce0d8a67,c6bd8467,261f726b) -,S(8d133509,d51edc48,97830f8b,3f8a6688,7a16834a,5ea31602,1649e219,cf899cac,9d188e67,2940f23a,39ac6ae4,fa532478,9c5df2d6,57f8b4e4,eca17e02,5560f08e) -,S(9cd47f8c,a9d3ebaa,d94dab36,4412ac4,a74a4b18,bb516538,10da1df3,9efc7582,de1e5cb0,fd5e7a20,322636d1,883b1ce9,71bd0565,a0eb60fa,559b552b,34b42e1e) -,S(1fef4107,648ca126,d5c4fe59,1f190f21,57274d0d,d9c57fdb,ffe2c348,35d36ddd,abf8fe20,87ca3feb,d8150e5e,c66c5d07,45731121,9b759430,4465bb14,55f992ab) -,S(e372b12e,8d3fed92,9e01babb,1a6517c9,ecb54d3e,6d0524ec,42ce57f8,5351d32f,43e910a,32447627,e2d9d5ef,53cb9c0,ab60333c,b07e72d1,c2c6644c,83e7d8a2) -,S(37c346cd,ae9d76e5,7ba2f30f,d05c33fa,3e6058af,642fb1c1,1810b4a0,b97e2dd5,9939c619,e1e49ec2,bf716714,1c23e135,157c7e4e,949e4fcc,b7dac7b9,7d4932d0) -,S(14e337ac,39f0c1d,98333716,a6e596eb,ad0d0688,b815c7a0,c182b546,88e5c3bf,fe45e34e,bfb94cff,a72b6312,a422562c,8ba782e2,16d5ee31,6425651e,e67d3d22) -,S(25517b3f,79da61ae,dd50cd1b,69b1ee36,fce0a44b,feb572e2,e6eb4aef,d751146d,7d2a017d,b9089d13,9a072803,dba874f0,f169ea36,95786e13,7fcd36d8,8b28a213) -,S(7d5957a6,92fd532,b9991383,cae895f2,8554e6c7,83ae3bcf,e72e3678,3475cb46,fa4b9b07,2bc725f8,e35b01b9,590ec1d8,f205f6c1,3203e91d,d9d39954,922d7f65) -,S(77eaf892,c4f9e0d,f63e33a5,1c088e0b,323ddff5,6f854475,b143b458,3e0e2f81,93d0f67d,51abf50,ea260593,96effe6,7f985caa,a9d68250,224e7193,414105f5) -,S(812c11a8,2851f474,e5a0a175,fb527539,7f1c73e7,6a766cd8,7147c9c4,4c970ec4,f9e22a19,a35179de,30379c37,a616d226,666311d9,4ad62b6d,59fcc579,cd024af8) -,S(b633f071,57c5a0a3,7ff5f626,17de24dc,14b3bcd8,4eb43385,e5a59be5,1c371fab,93e70e48,68ab5a3b,e29dab87,8a50e2c3,a09edb5,bf5b47d9,a09ccf59,53b67673) -,S(5e78caf1,9a2031a2,d92e1ba2,1f43f91b,10a98672,5d23ef95,1bdc1f83,cbb16343,b438317e,9446b88e,92206d81,883d5f3f,6497ec33,d144cfc,3a7dba41,db53cbc1) -,S(dd082ebf,88d49fed,50b76df,8e64d3a4,a1d4bbb4,fcdee50,c3ad6d0d,a91e4ec3,9efe99d2,f15d46bd,26d67bc5,ccc122ed,bf5034d9,28bcc946,e4714784,5edb6244) -,S(1ba1e135,62c06b5,63db5c49,7ed46ee5,73399a56,15fbfb1,4e080815,874e6a2e,f298d5df,43111fb,2f050cfe,2a06b3,c9a1fa02,d409dbe8,a225a3e,bec2d8be) -,S(49477847,a590a536,e7370341,5380459,843da9c1,78a1d176,f2f0133d,6ca214f3,3d1b8f64,a1d94169,2baeef3,86b4740c,4eaa84a9,15e4d03,2bd7bfd9,f5d5bad7) -,S(c4336d6a,4fbc288a,2c69fcc9,691fc8e0,e277fb98,e34b7a66,bf29d2d4,32c1339d,64ca0adc,72f0ff2a,f150f01,ea243a51,e91da8e7,480e0553,c7bb268a,22fbd383) -,S(a510cb67,9970c117,49e4e9d9,acdb97c6,d8712ca2,7961ca45,ddc9669d,9e02207,afa065b1,46b75ee2,ff7ada4f,ac7b863c,f4937cfd,15ca2ff9,c0901c7d,faac88b7) -,S(7cd63347,59eec80b,666237b2,abdd6c6f,e5e24a60,9305165,b5bb1a04,2898cc7d,abf7dab,f9e12893,a8040b13,afe16524,1d749660,93cf2da,157e2a78,e89cc758) -,S(e0786f8d,6f339bdc,9ff47416,4070bc08,c864d0d2,6d507762,19c2ee87,61cb7959,892cfd2e,62f4c352,b296a508,455a1dee,8dcec943,f5109add,9d38437e,87ec58c9) -,S(d81f740b,123cfd5,9c5ceb73,47668148,995ca21c,a3ca1b8c,b48e20db,32f6b55d,3af34294,c83c41df,7d5f821c,68e71e34,4656be14,f09d1858,7a204244,6f74f4ff) -,S(f4ba0503,6ffc1812,efbf3fe3,81423d91,38eca2,a67a0f4c,2d0474e6,5db9efc0,b2b3c3b4,4af46f2d,e53b1e8a,adb83d59,4c32b6ca,a7113207,b7993bef,dcdf78b) -,S(aa6f03ed,50640e0d,72fa4de7,ec3964ab,82e7758f,5e6c16d7,78c18296,e3b1a527,322223f7,ecf473a8,36bcfd41,e50f871d,715f9729,93df1359,80794587,59d9767f) -,S(f2d48f68,23984bd9,e8e87772,28da095,4ca134a0,6b43e0d1,1a8843d7,1fd0232,f0b7d9e5,982d0f6f,5ef74bc6,78ee504b,6202f52e,8db7c069,e179d175,c6f760e4) -,S(70e9ec90,7db14601,9741a4d5,ba604187,a7313b7b,500864b5,383b3763,be303979,63f9ef9d,eea1d1bf,a84e0d19,c8f15665,60b4f1dc,839aef5d,b6fbef7e,d6dc6a4a) -,S(23cfe5f9,7198efd3,f34f657d,158f092a,29748586,29983927,9c58944b,146cdf1f,3b8fdd8d,cd82a757,44152552,35de0cae,c39e20e5,f82c7b6a,2afde8f4,1c6afab6) -,S(b1e2b9d6,4c14d667,4de9a6a7,5499cfb,12b30a92,b9bf7578,f8fdbb55,b6d414de,1e91c321,24341a58,e2c6d65f,18f3f735,f9f98d2d,76d124a2,c694db84,37cd0483) -,S(5092db9e,5bde4edd,f385c67f,357e43a7,c8fc8e09,f5c07c14,25bb405b,7e52d1fb,cbad30f3,f96767f9,553c9be3,2adbae2e,1f27f9d5,3fbb2f99,a361056c,ddf52858) -,S(59d39b90,2143ace3,3a1a1e54,a5cd83e9,6cf56f65,4a91f524,af8c8e19,e25496a5,be21c89c,baaffe09,4f2114be,72ff26a8,22db9a1b,818d96a2,bafa797a,3af056a5) -,S(89cc95d8,cf45bab6,9b3f86f7,9e1fa71a,34fa83cd,3d4dfd16,1c9df1b5,817edc16,5eff0aef,63fc853a,f8b65e8,8a45740e,6c78aade,4bcfeca4,c7413ad6,714eef84) -,S(6c2b8809,79398e60,87c756c,443fb032,f2adf5f0,17bf9ac6,44d164b7,d2aeed3f,bc46cb71,c9ed9f46,b34a22cc,e1332cbd,44318165,85407951,580e4b26,270f3eca) -,S(767ca583,c950f7bb,e3aaa6db,b6aa9867,792e0b8a,6930ab97,5c46d09c,30e14a6e,bb90634f,87133104,1c7eeaa0,4a09887a,e5946daf,e88828a,68761cb6,21412d49) -,S(cf742ea0,35c4d9a6,40fd0686,a460ab96,e2015d0,2c15fc8f,333ecb7b,8af4b08d,2bb94f28,bd69b51e,de993065,fd61fbad,c65fc62,90059a8b,d29948da,20b704e5) -,S(84d5d76a,a5a6ec84,52f024ea,b365290d,9c3b6be8,f33a93ea,b0a0ac4e,e6271059,f5565742,f1a47a88,8d0bb802,b002ea6e,f5acea8,864e2f64,fbfb1565,dda51952) -,S(8f5752a,8fbdc1a6,201b6e0b,7bd5db3,cda2eafe,f18cd6d,559724b9,56767d32,d63c0fad,de72b753,6d0c8606,88e0a82b,9f9e35d4,b1db7be7,efa9040b,82298008) -,S(20578def,f94e3597,50ee95bc,61ca76db,f8fc059f,e25e42c5,bf887d49,665d1871,5fc52a36,c95c6edf,46bd5c38,60e151b3,9f123e9b,c58b2079,cd165c1d,e6f33d3c) -,S(30f2b825,739fdf4c,5af0ca08,47f50323,d3ad6eb0,413b052e,525f837c,38f97a4e,d698b076,4417357c,a49b4306,7d73206f,d3d97036,26ab15d4,f11c56bf,4bc820ff) -,S(2350eca0,b4d0c460,12024be,6d458444,b37b20cb,50042830,182b5e41,d564e26b,5909eee2,e3999d60,4cbe0832,58012001,30a344c5,f72ff127,35e66cdd,904623d7) -,S(ea660cfc,45971e57,852d382a,ae8cc6b,1887fe68,dc1b84bf,31f4409,89f89b2d,52297e86,dfec0730,81a280f,9451623f,9e69c320,6f3c205a,f07e56a2,54cd5837) -,S(9cded450,2a7da3bb,77e06ae3,ef398954,7687d21e,df522f3a,cb6b4fd9,d3d49beb,7b13f455,35a49049,277abc34,3cc6f0a,336242e8,7b69815a,e27122e1,d7838a8) -,S(ac8705f2,cf8dcd77,d409a962,f98a6abf,198dd238,3a5eb258,6b0d2def,81daa172,892fa835,a0af6cf9,dd5bf158,44b22cf8,2af258c0,519955dc,ee4966c7,bd5e995c) -,S(fa026b1b,d5e5fe3c,d6b144bc,6b22f7e7,5512ca6c,9525f62,fc7fb4ea,bcd2282c,4ec40de5,7ffc1768,edb20cae,d3a11380,fcc32f45,f410ad9b,8b674d95,6614aad0) -,S(a928eb73,28285c79,5717dc0b,ccb5280f,92f9a4be,5a0b0ed7,67e58eaa,8b9097db,af57cb66,61a9d08f,4d4e9e25,aeeea2dd,e4c88767,c4e177b,37a87ba4,c2bb772e) -,S(bfc9197f,80fded3,c601a0f,1c8c1d77,cbccaab,1c8357ee,4fb67875,cbbc8261,6a721e0,241ef436,69cd386b,d07fa2e8,900527eb,ec3c0025,24bb457e,1bc7aa28) -,S(ae0de043,b332bb4f,91395870,4f3a41f,65e0f3d9,ff77c1d5,ec3add49,6087d5db,34d697f5,dbef1bdb,f581127d,bcd2755,a5a6b32d,73164665,ef84f6bc,145c2afd) -,S(4433db73,29d75b3f,7df0e229,538b7a33,e41183ad,7a7a5e3e,ccf5863d,6bbb692c,3a66630,a03ab85,9f23ae3c,a0a38717,d82ac240,d271b3a6,ccde1407,d0dfdfa1) -,S(bc7380bb,128a6f8a,5cdb971c,31ad12e2,ba593acf,718f5468,285b7f14,69ca2b90,a17af518,9a7b0445,cb37e797,a281c84f,8cf8ecaf,c661e601,4ecc2467,18f1d8e4) -,S(bb53297b,18d2d785,a4756437,70b387d3,ab0fe62,8b78c09f,bb6cc226,79bc92ab,5c34b9b7,cfb3737,bb515ee8,fcff8592,1fe8f30c,e97d21b7,47a4b084,22b0c811) -,S(1accc1c3,f46945d5,7b46b1fa,15291ae4,2f0a616f,df23f1c3,3f0dcf97,53851fb6,bb434ef5,e30fb9fc,15e99b15,b5f9d766,9681be30,d2b0a6f5,a4946268,158d5369) -,S(2fd61a9a,b99c588d,fbe74fde,e8ce95cd,1c0ee9a6,da7ae59,910485bb,9a3ed9c6,2c214840,e2bd764f,74f9db81,43ddd549,3d322dd2,b25790a8,a681c97e,2fda07c3) -,S(4bfd09f1,4cb492a5,7b9ef3ca,d245a0ab,c4bd97ef,12bf7204,8ecfee47,660f7161,57102f3a,ecc42742,657032bd,aa36526c,e67f2589,2775fdb7,e8b029d8,1cc7ec9c) -,S(f60eb13a,8e6485ea,fe653e74,de1c1376,2df7ba0d,4ff0c65f,24bb1c0d,74cea3fe,c5830078,5b74cc82,80128896,f275fca4,9be94edc,744f8535,128ba7a0,5c1d9552) -,S(2b4c7864,9f568eb1,ce1be63d,aaaba4e9,7c31349f,aa353371,6e9123f6,4c57b041,b5dc9c1a,b39325f9,3ead6f35,66c30479,5f817ca1,b3c37258,554c4fb2,51a0ca39) -,S(7fb057e8,5f559f11,b5d41538,6a25a77a,aeb904c5,d1be33cc,bece20ad,57715ac4,2352db61,6fad3f10,a2decdef,5a7fc369,5c8462b3,7d2d5ae8,bde17311,ac6b4ad3) -,S(a49bc870,bfd62cf1,1dd1bd23,9499157d,247ac61a,a9b34210,65d4d029,56f71a0a,b639709,88ffd1ae,ed1b62b1,83ba629e,f5f0c088,f8a9016,d7fa9157,46642e3b) -,S(30b1f21,f8dd3f40,697878a9,fa0b9fbe,d51c1ddd,165bd5f,ed9d1fd6,49ae913f,d5a55164,4628de36,25895fa1,471e0f5,77326d14,132d8ffa,37e0277d,a928532) -,S(8a015768,8aefcd7d,13cb3b98,373a8823,aad11a4e,718a6ea8,5fdb8a9a,6edfd879,e7d92909,4d198910,44c00be,69f267f3,84aca1db,642648d8,34a5b9fe,518e1363) -,S(810ee87e,45d8a5ee,c0e3fd0a,cb771d2a,5a3116be,f4dd7d5f,bfac0dd9,fe072778,92abfc24,9500ba0a,9cfa1725,da4c37b6,cf081f5c,c6cb6a8a,3af889ab,ddd2b7f1) -,S(a0eaaed7,687f6a94,398656fb,3fb15f49,6522c3dc,c19e04b4,598ac4a5,6408d1d9,792a67cd,677ae878,eae040e1,6378cc36,9583b513,bca68fa1,cca3cbdc,37aa61d5) -,S(ca438737,ffa6f30d,9aa695fb,3d29db01,f805f480,ddf1b227,3a0515b9,5f8eba97,56238731,ff5314f4,af6a3835,b30ae83d,feaf0db,dd4449e0,5736efba,8a8cd51b) -,S(b252f5e5,4b67554c,ba3d481d,66a2f223,a633b5e7,f335e357,29928264,e744279c,c6296730,5007e2c9,3fbdb25d,a33a9fa7,411218c2,87b937c5,dfcf8f45,472533a0) -,S(f61b57a2,237befe8,2f1545cb,131acb03,3015a5ee,f0cb77d8,c73add0d,ec0083f7,9b1e0c93,b326a265,eabf096f,f8eedfd5,9f765b51,5007c5cc,d0d3b569,838f381) -,S(30df434c,1051cc43,4ca35671,3957f964,af406830,38ce82a9,5cdf2c7b,55c50f7c,883bc89b,f54c490b,3be0d434,fffb6b,7e829be1,55280401,eaf44bee,7c445424) -,S(fd0ab148,727eb712,adee1fe3,4e3d0fe4,99bf8307,fbe18e4e,d20d5236,f7ac25e7,f5f38f32,df094903,b3219b02,8413cfc0,e56b8ed5,6ad80e5b,aaa00f4e,3877377c) -,S(b4a8fcf2,b406becb,6111c030,ae375f12,79de175,7f2f3b90,13e7ac55,12de747f,d1634039,59a6600a,fa05b1cc,3c459fa4,f1a5fd4c,27ee5382,c5f01e4d,a0259889) -,S(a6c10f0b,33d1518c,8f8b7055,b139aa84,c96e9998,8e8a256c,5883bb44,10687c72,8f0dfa52,ccaec6c6,789941f3,cab90b55,4d4f587f,bb6f3354,b5f7158c,758e4f9b) -,S(7188fb46,e244a5a2,6e38cf13,bf2e3c4a,ff5bdcdf,8d9f78ae,88213692,d866f5c9,8cb07d12,ec743540,3be09b19,4cfb2f1f,c4a85d27,d940cad1,15ab53ea,4b8e0d88) -,S(fe4f9f00,308670fc,48e45208,4063fa94,a6cf7141,d75a6ef7,4f92b474,5bf692ea,5dc45ab4,77f80594,4355698b,e95bc582,efea563a,970217e5,2bd28ede,d7e8cbdd) -,S(93f3b5df,43006183,47c7bc14,3eb046a3,842614ad,78d3cfc9,a6b665e,3327b7cd,ffe5f378,7ac36947,d635d156,7a28fa5d,45c0b5e1,70508cc2,7fd621b4,47b63b53) -,S(dd350a89,e0c3128b,54a3955c,bf802ff7,3a565760,39e1e068,e783ad00,36c13604,45cdb508,3c33c35,fcdbb29a,efddcc63,c4cf3fe7,c08a15d,8b2cd4ae,dec2c3e9) -,S(4f164801,17c1d338,7738b728,96442b9d,66f44eec,e3eeb7ff,ffa87d24,4226e44f,750e6348,490d0ecd,3be07303,5a8e653c,1b1f7c30,d89e27dd,4efedc9d,755b89ee) -,S(b7c62749,aaf79754,de281314,acb4b2f0,271f2a35,fd187307,20349a3c,a4b577a3,f100956e,ddc307db,56542c1,d2c8f176,e0636ba,b04877cf,3dad451d,edcb0df4) -,S(fa5c1278,1dd929a0,2ae4755c,70531cd6,c309261,36ef51ed,7d57c117,c1c8a885,57c5280a,5f08f0c9,393aab6f,eba0ae81,a32f8c6e,2a76c780,a871170a,e37856f4) -,S(e16d6dee,7830b0d,e6cc5e4,9b1cfb7b,50b7d89,57fa4e6c,42ce9925,2e6a29b6,cd5955da,4c1ba840,a3c98d1,7dea8d8c,f4a3d2c0,1e0cf164,2cdc35ee,87fea835) -,S(a2c659f0,a0ef6147,ba84ff26,ca81443c,ac8ba9be,f6fb32f9,50653384,a5db0213,5176a4b1,88b5bbef,3680e875,437e4209,d2fd2462,77c5f84,4a0eaf5,e9d8c129) -,S(7d507179,6a7c037,77fcf84e,62e6eac5,456f88fe,76e71301,76fe458c,8f301a68,14018264,59d3f62,6788fba3,1505c83a,4161674,21dbc2a9,dc14e1a,f45a50a8) -,S(642721c9,20d9b3e6,72db8d82,34ad60f4,bc74684f,11f2ef1a,8171d02e,b9eb1f12,fdde8b98,8aac7393,be2366b5,6e853c7,b72034fb,2cb176ee,770063dc,42b63d48) -,S(65fc35bd,2f604eae,48a1b68e,1d66cac3,627b1498,247d8376,47082702,293c97d,d01018e4,85dba402,17ac631a,9b88d240,de32ac74,79c7d47a,9f5d9188,f8ac01d7) -,S(65c8b230,2e51129a,b81de5f5,22217f06,f5d5360f,af191c56,8f395a33,2b04375a,3201b7ec,117fceb2,b225f137,877ef481,2be4d6b4,52d1c855,f73adb0f,e99b2943) -,S(b82aa6a2,86fb19a,d2eeaac8,9019782b,d0d6009a,8fa07a02,a0d6295,ea8637f0,426f8d72,ec1b08d2,72671566,1f77f470,f334e4fd,3370d96f,b0acca8f,2df99398) -,S(a3222e7a,c6c27f2,8b24b33d,ac78d873,1ce060dc,be055100,862e71dc,e6671a18,6f2c2a1c,4b80534f,8ea53777,71760fb6,5148d47e,ca097fd2,b7bb2f53,bb07ce22) -,S(281ffed7,48a4022b,c663d08b,5681733d,f1343818,d68c8b63,9f4405db,ad7020e2,b5f18609,d8e5c6e7,990808ec,b4fa7d2d,7d4cd106,b7ad2c6a,e356f239,9a535eea) -,S(c520ea8b,a481c220,bab0f218,72ccfcd5,d7014d8c,fe55d1ef,743af305,c0277d5e,e23eaf34,33e4369f,30d371d6,e396b0dc,a065506a,c4159967,fec4475c,8f6bf78b) -,S(54d39ed1,114ec02d,8005d7a0,82178175,78f827c2,1b55a95f,330a7af9,34727958,4aecf190,229c49c9,31862a57,9131aeed,5518cda9,4695e8ac,7ebf7667,d9afb23e) -,S(756b9bf0,1da8d7f6,1627cb2c,b3ce3ba,a9b6450,c2d24596,feae8bd1,2ef67a23,51c47b15,b2ac96c3,5d7b7dc2,d8c57ee9,69b347ff,dadb04e9,cbfd6889,a0ef70b7) -,S(eef22145,6ff200f,ddced960,f422588e,333a437e,d68c04ca,9758d77e,a938ac54,21587cf5,8b8ffb72,6d29aed2,3c984a4f,25df40b0,abc9b7cf,2c07436,ab7e09e2) -,S(b841b560,c0af44a,35bc9320,3c05cb32,250fcca3,f83dafe,30d1dbe6,61aa3d1,e7956525,3d07a89b,2335e2ce,9e11fb89,96e2c146,271189b3,461cf944,2ceee2d7) -,S(14b98f62,5849b798,48f32547,efccc33c,3ead6cd1,a290f03e,618acc2c,1ce065e1,4e7a2415,805a4486,476221f1,ce8234e6,5b81ee60,e1ce5eb6,b6a2e041,ac885e00) -,S(fb0aafb7,68c19f64,17e417b6,f1c22dfc,737bc74,fe8b23e7,4dc1c1c9,aad7ae44,88b83e23,631c58d,c3729cf5,54343721,e9ec7dc4,a889b85e,31cb302f,f2a6ab3b) -,S(885497ab,e34d1745,a3e2ff8b,bdea904,eeacf100,324540c6,86de137a,9756468f,63f3f160,bd266c3a,7c49b13f,c5b06403,d0614b79,17c49824,bf507257,2ac0b948) -,S(52dc7bd7,17e4d8e,8b634439,f6f06b8f,7121a0e0,cfebe7a8,3031668b,9832b8b3,90679373,9bbce1e3,5c48f41e,942d9f15,9161e9ab,273a2217,d9e857c4,3bdd0a5c) -,S(e6ed2c69,a8bd7af3,35591f4e,4dfba7ac,d82e87ee,e2b3bd28,f0f87f02,3abaa7c0,dfec6118,7396bd5,e32ba2e7,a8fc912f,1e54e078,6f2ee222,35adcd22,8feca28) -,S(9e2171a2,c1025129,1757e26f,ba979e5d,6b68c2b4,975c7289,2afe7898,cafc46eb,3dd062bd,210bfc4d,d30cf01c,51d810b5,cf1b8ee3,d3baf490,6bf5d381,b87c9a56) -,S(ef4b8648,3bf209f3,b1c2e166,a32cda39,44b21282,db8acb94,6ef62122,63bc44cb,903d1088,ccc0ba47,b5ac3252,33ef9b55,924e61ba,7ca80bd8,1925b269,3998920b) -,S(64ec6d14,7ecb6e44,6331907b,b9006b2b,fa4fb854,20ab9aba,f1026bc3,4ccdc4b5,583cad3,b41bbfec,d0817207,dd312cdc,26c0411,b888ce5c,c6ee025,baafac63) -,S(128cb9de,125429dd,e5b9b33c,ef9f34a3,e7b38ba,f22dbcdf,8e169894,3f7ae5a9,a10a01dd,33f5a4eb,66091348,c4dbd90d,62879ff6,7559229a,e53c2896,8fb4584b) -,S(a7d2e7db,ca0890ee,e07c4bbb,399a0120,e71fc284,c5b7c96b,4889fbb6,db95dbbe,b8caef70,404a19dc,15670cae,b19d5b74,e70b7492,50390b12,5f559b11,feda83de) -,S(298b17c0,b8beadff,5e6eafb8,ad7d756,8e961468,d8e12c94,78ff3870,dc722450,a0542f35,c7b95774,b1c10f75,3e9da029,ec7a54a6,97bcd9fb,46c98d26,91ac1a43) -,S(31a39bcd,a3d10e9f,6b46e1e,c30b41aa,557ba664,9b12db64,a13557d7,5c592d1d,814f1a6,15382d4,e57b8d41,351fd782,ce7dd9d7,86aa9bbb,c5b1ca7c,207ab12a) -,S(3317f1a8,1afa54f6,ffa6df13,bd3f818d,e9a29bed,7c119b6d,fa31560d,31d81cfd,aa8eb746,4e9acaea,19a42509,a23a281c,e9917788,6d3de977,4398c57,8867e095) -,S(85511857,80eab56a,274cad22,966ca547,3027d3c,3cdd7e25,7d8ed8cd,a5c6ef30,b13de0f4,45d71bd7,db0327eb,15438e9e,84fefc1a,464d8a2b,bcb8c6b9,f59f93dd) -,S(fdbffe5,7e378262,c32bc4b1,e84ae01e,a2d6dd76,28e10b04,9adf6a3e,ef106e83,f19d0c4f,1411ba50,35d3ef23,153f306f,d40b22c6,69e92ea9,22bd7d5f,83a98ad) -,S(7562779e,6aae0c51,52acc7ee,43bed76c,831ba008,82d89c9c,e29a5f3b,8855b3c8,c83c1662,7cb9e1d9,126e07b3,354b82a8,a0cd49eb,3936c14a,8d8d64ed,2a4e217e) -,S(130b292c,10d5b336,4635d43a,fb6d6e02,d5acec2,c2033525,ed72c030,e82a4a08,d534b710,e1201276,6f6fce50,ed6efec7,3e0c3e75,50e0bf36,d5d625b5,4855fed5) -,S(19fecb77,bcfc0db3,e595fe22,e96f1212,b3ed032d,183be5e0,ed4c1b8b,d0501bb3,6b0fafde,2f0636e7,2b4ea946,a0e5c27e,4e5dfb5f,e8b8a1d1,b36bdee5,75d02e81) -,S(ffc668c7,9c6f9fd2,f5c56104,aac1286f,cd4a390d,ca586af2,c348458f,b4130f77,fd7b748,d15f10b6,4eaf4946,34fb4ddc,439919a1,1155e40f,24f3eb2f,482445f4) -,S(b9797c7b,d4112aa4,8abbc827,fae12fd9,6d19f3c7,81626e21,5c26ddcd,b2d4552,ddb0aa81,3113288f,1fd2505b,d23f2a9b,a1ba0a38,dcbbfbcb,46da78bc,5c705327) -,S(9388c9f6,5bda9c81,62ec04ec,5345ff80,da4afe34,7281f768,4d8daa1c,cc3d7869,23ef5140,3f926d0a,d2ebbe6e,48858850,aa98149c,89490e99,65dafeb3,c82644fb) -,S(44cf864,6c2d2f30,e62f63fd,8e145786,80c1d5b8,a27fd496,a8e34bab,5f88270,9784e329,a434b442,fef9af66,b23ea917,edc0f6ca,8d28a992,bf6944ff,26c5cd25) -,S(ebe08589,930001bd,ecb83ca4,45c4a9fb,fd61b229,60ba9848,2e0fd520,1af5a0a9,ce2d31fe,3c271048,24ed891a,910e2cd2,2b99b39b,480ad812,a5d6860f,71ec817d) -,S(176d14f2,5491c2f1,c1d4fc87,a8f59aef,f560bbd9,41872f6f,2a1a6adc,7620f1d7,42c1e0f3,8a3379b0,c5de8a01,11b846b4,35db7783,caa9b84,8084a985,f0e123a4) -,S(74e96d3a,972baa6f,8ad6876c,9494f451,a12adecb,681c4d55,57eb58a6,de920fc0,c2cd92a9,994ad5,f4700561,e8b57201,96e61a5e,b4cb4a55,66959bf1,35a07f83) -,S(6751dff8,5079fa45,7f5df468,624c4a85,db970586,889cd80f,d4514bbe,8de42d60,7cc20505,deeb3f91,3d78a265,cb301c68,49cd5a53,dc029af5,c0db1876,762ba3b0) -,S(f9c63056,24d8cffd,abce64ac,65dd3a09,ebd344a5,5404d08f,b4140a4d,8489628d,49ad5449,bf1b6def,74283afd,2f315f77,3de82cda,d4c9de21,7995a2ff,c44e934e) -,S(69e8c4f7,3f757235,d0e4f39a,f2595cde,f7ff4d20,dd2d45c9,78f32d19,921b6672,8ffc35fd,8a6d541b,3f7135f5,643efb00,14f275ba,d929671,df610748,6f763f55) -,S(3d03e571,ed2aa88a,3309f014,caddfd64,26ae84a2,a526fe35,f30ceb8a,4e645e22,db95c744,6bf115d9,4af9074a,6b274725,adbcbfa6,77f9ce48,535003ad,dd37bc6a) -,S(e5b764c3,dc73619e,51a2afa,fb2292ad,db2b7b0d,e12b46b7,f14b66ce,f8aea7bc,41fbe1bf,41838b6e,9a57fcbc,b3e2e3c8,60170122,29a5ffe1,7394139f,5e8edf2c) -,S(adabcca6,b4252849,76596462,36b17b0f,9d1b4e9d,279af84a,c02f556c,e0f4c385,7d12959,9b411665,dd23b676,57229f84,ae46773a,e13284ab,1cb608d2,ccedafd5) -,S(963094f7,7ea2a7d0,3115e201,45dc6f6a,7318f8b9,a55ab015,8096db54,48e341e7,36bb26ce,3852ba30,dcb1a8ee,ec834f4d,d5342ab9,f7bbe85d,7addce07,62cb22aa) -,S(30ca6324,b4f34e1a,4c3dbe4f,d6dc6b13,a8ebcb35,2f632fc1,5725bff5,f260c508,5c04aa15,8dae7205,3bb608db,1b9245cf,fc57c10f,d015e80f,7afc7532,632eaaea) -,S(8356d1c4,55479df3,adbca347,fdb73f89,6027471b,e528da9a,d9e6a968,8dfba744,c325c86c,cd603953,8f610b03,21b6147a,371314cd,2c41df91,745e579d,8564a177) -,S(996ca7b0,4ae2dde7,b5ee87d8,c077bf97,9a63ce83,cfb84349,c7d231b3,1e15bfd7,cd1d1b48,d75f9736,68b91101,8ade913c,19a1d785,65adcf71,6c805863,fa6c1f17) -,S(8a15dbd3,5cc16f77,b22a87b4,4f93e5e5,810f0503,56e47d53,95769128,a2047738,cf96df1,9ecb6da4,3895641e,4fbd4f27,f00f58ce,cd34d38d,e258fa78,410a1f7f) -,S(23c1e11c,be9f6a93,6c5f8abb,6cc501a1,ca38b03e,f00b31a,79057156,f382ad7c,1d996782,9f709951,2c9728ac,68c16db,1889bcbb,7df432b7,f430ebe6,56b1e050) -,S(d937ad87,70737b1f,d52bfb7f,86e207f1,9e4bed5a,43b165fc,981685e6,24b8e84c,202913d6,1eb467fc,b488fffe,5914f853,73aaac20,1acde09,ef975cc8,a05fd181) -,S(6457f59b,2c744ca7,89537c59,6485abe9,7835368b,47de3667,4740ecff,72e5596d,30b6ffac,65e34e88,43681e64,f041870b,c85b3b5c,86c032b1,e290848d,ad2f7a5f) -,S(7101d56d,813abe1f,c50aa99a,bc7b2363,9532d79d,facc17c9,f2a5b4ff,50edf82e,62a0b9d2,bcab5b18,9075f6f0,e648a4f6,fa66741c,389a4196,a4c5ead7,cbef14d8) -,S(2dd4cb3e,5cb59cbe,b961af3f,d1154fbf,c21916f1,d5331ce4,c8a32ad6,8f7ad818,397dde68,7b1f6b5d,38e457ae,2f5fb332,74917949,801151e5,3d4fe19,9a34289a) -,S(509c6fcc,ae22b09d,b8f3d191,434e584c,9d17dc76,c268560f,2290d81d,53ed66dc,cbf69e20,c3f9ada3,41e32dfc,581f0ba,f015413d,735d33a6,260e0cfa,7a4e4d05) -,S(71babe5a,9458bf5e,112b23a5,3f87007b,66ddd721,32a45a34,2a9c521a,c2029aae,55ac872,a0275be6,4f569901,d84dca32,ea13e2c6,cbe608ac,de228185,34e031a3) -,S(f5f2144a,46fe975f,82b91da3,a98ebcb,6d5769a3,4e5fc50f,3ca640fa,152fa7fd,2fc05c22,2b20b895,5503f23e,627558b0,e023988d,f02993f8,f495750d,db6344fe) -,S(d6f274fa,fdfcf64,25972a56,640e53b8,15c4d213,8e4a72a0,b8ab3394,2955e416,738e267b,2fe0d9,5774afdc,7c4f559b,7bfe2824,ea6b7a49,d3220eb0,460ca733) -,S(81a12fcf,cc6acf7b,89f30fc,8f61e2cd,7882f664,55923993,2b8d3f9b,1d6e11e7,a8dbc6c1,cdca67b0,64b285c4,e2f69242,cf55f06c,5eb28868,d9bab656,eaf9116a) -,S(57019cc4,941f6f5,9ed34305,92f35a83,39a495ee,fb3e311a,fcef9001,cb8123be,a3d632f2,54083f5d,6f2857b6,9556205f,59578908,9d8d8fd2,4d10bf1a,e6d2e635) -,S(4205a71f,504362cd,576c4d84,c8b65252,3d4227fb,d6aa28a7,e7fc3d70,d1387c80,781bfe55,7fecdfff,c54d1c1f,e147792c,5ea7a1dd,7224954e,e110cc6e,18ab452b) -,S(1c42ad3d,f90472e9,e5c041da,52476ea0,896a2032,ccff22a8,fd7bbab1,4c3961f3,a5072a70,be702dae,f9f93148,4bdfaa00,1e2f2ad6,7d79f46b,5717147,17c5499c) -,S(6c9225cb,668ecf25,1f7862ad,999516c0,145faa37,b4fe92eb,561104f8,f1dc2997,8c12c1a1,e372baa1,4e9b1443,d3530548,d7d1d05b,fa354c7,f47ecab3,23993a31) -,S(72a0fd2d,eced2a05,6885dc81,fb61e881,b09104f3,8650a872,44e40471,ed189992,d9c67490,43bb493d,9aea4a1b,3a50da8a,e1c48523,9a480442,32406d2a,68487e6e) -,S(b1d531af,8faa24b5,69945ec8,1448915b,a46fd13a,f7fecb8e,16cd5d03,52c6c2ab,b3ba6cf4,bd36bee,66deba09,35bb85e0,b9ff7e62,5b5c793b,543a091b,dc83292b) -,S(da79daea,d6ea65e1,4e8747b8,b4546560,a9e5a99e,eb572f17,f2ebcf3f,9a307a86,f5b3c430,e0f2d4aa,2f278088,2d683c48,d84f926f,6feea88b,10e06930,6567a290) -,S(1fe7fb5c,99a69a75,a2276ca8,92f67da4,951bbb4f,ee4df8b4,a54c9833,d0d33869,e2b2b4c6,fe0f63f,d97fa179,331e9bb,55786006,f0425e98,71452aa8,361f177a) -,S(fcdb7de9,4eacf36a,9d662371,edd2b535,af33de37,1985ff49,6ce5293b,9d2ac00a,e332723c,7a9708e8,5172e56a,c4291760,baa17e83,72c98dbe,83a186de,77c2aa06) -,S(daeaa6cb,19bdb4b7,78077495,a9cead03,3be16d2,97e742c6,97ac18ed,e5b514c6,4545ca53,bde3c1ff,6bf32604,ef037da,93134215,7057ab10,cf6af451,e7753f4c) -,S(83e4b4c9,1a923321,196fffb9,b45d089e,7fa1f6b0,5ff45a6f,d099f7ec,fe283088,926c28cc,bf405fb1,17c5f168,20216226,4c89cda2,cf669937,2739ea05,279325d5) -,S(cd7f2b53,8363914b,2e83f1e1,c9bced9,32a682fa,cd72b46a,eda578c0,640089bc,ddf6dc27,a5281d3,b4d66af6,8fc80f5b,16cbb7b6,ebfff06c,6902d38d,4632ed2e) -,S(6f3f5a27,b19dbfc0,238bccc8,a9adcf95,adef6480,fd4ca405,454509b2,97a40928,36a56db2,abf62faa,b2255d86,d8a46aec,361fd2a8,65740c31,babb2e2,c551a85e) -,S(f7aa5c92,a523b86b,c27cf714,51f7dcec,fa18ef3a,9e839c41,a8b20c4e,30ba3b77,fa7d3ce9,8009f23d,f5eae927,acf1b28d,5ce4a2f8,8a92da7d,fcc1acb1,3c8cadc5) -,S(4adaaf95,5bfa6a94,b518f7f5,b0ebbdca,493798f6,72293e4b,36d5fdfd,5f641b89,ce675ffa,cff579c0,61e63c2f,36e77f3d,5c2571b3,aa99d3c2,74086b22,a862577c) -,S(2d737aac,3600371c,f6b638e8,8a29884c,978b783,cb843922,bd449e95,814db692,205d944f,13b21441,76d8276d,74da68e5,142aac9f,ba632568,79753c01,e54cf4f) -,S(7cb5d365,10ef241d,ac378fc,ebad8738,e8f2e6ad,6d838731,e5c82bb9,169d51d4,33b088df,5a572e8e,1010886a,d01b68f1,9f345770,81a465ba,8c5c784f,225f6510) -,S(9872a376,e530e254,8b623b6,b9dbd6d4,d123f2f7,30579f47,4d910831,7c714c0c,3de01ddb,3145d81e,6ac002ec,70086f74,6eb2bdee,6295f5fd,9d2cf8b6,1b222e58) -,S(8242fc8b,2e848618,ba0f26c2,6acac090,8eb21b4f,41a08b76,beb35f85,3b8c2f33,58b94d44,3379ea4f,829fc809,ce2632cd,78d8675e,45a29c58,e29fda43,785f2e9) -,S(88800a95,cf1682df,4e5bcde3,a96de21c,3353751c,5300dfa0,d0f802d6,7b60eeeb,2a35b86a,4e213e9e,c53dfe04,d91afb48,25bc8794,a1574ac4,53e81ff,4b6e453f) -,S(3c8e2755,9611937c,b7e2b2cf,8a87fa5a,e5c696df,fc6703b7,e1e65ac9,111ad87c,c54d129a,be0c774d,dd415707,bfabafdb,daedd1bb,2ea9cff3,bcfae0e4,55c916e) -,S(281af73e,a1f092c5,535557f9,3b5a8c94,54165f8,76650801,856bf926,19f06cb8,deaa8495,30951f12,ea157714,3caab5fd,d30f0dce,ac9b80bc,fcdb3477,dc01ea1c) -,S(6b353e5,3202f63c,69bce96,30535f11,1939fa,849dedb,92ad21c4,89f5174d,bd961eed,c16f285f,2eccfa69,d37a6d63,be5fad00,4858c80e,6fc4dfb4,2717acc4) -,S(68c184f1,a06685de,fd20f36c,82b5446,7446d5d9,8fc9c312,4852bb02,f35ed91d,486a3d16,7d94c66a,31f9e134,1652f658,76d49379,f3e3429f,e9f2da30,84f56532) -,S(5e884531,fa011576,3d36e1ad,74b22e23,f765db14,8b8e965c,80f7c9bb,7d561bf0,34c4f03,b137b627,3fbdb6e4,8ac09ef9,bc3c8ccc,e720853c,61ae58da,ee3a0cca) -,S(10c13f0f,313e5ad8,ea61ba5f,ed509aef,5ddd3016,c3339eec,ffc8f9d8,6f131118,28f6ad5b,324e44ae,64ee65c1,b86710a2,91a8e71,c33adbcf,a84f18fb,144dd67c) -,S(aa99d8b3,1031d4e9,8c078a68,7254968a,9141c710,cd8e4842,5a384bf8,414f5c5f,ee6eccfc,1dbdd5a,c9080cc1,ffedbc6e,64fcf847,ab9c0ce,fa91c4fe,d1de44bb) -,S(f087945d,a464e66c,4c73b58c,5034f057,b96ebe34,f5128397,cfadd7be,22ac6100,c5485411,d78fb395,3f229109,45aac354,1a2b2acd,1d95c38a,f51f36dc,d3cd92b2) -,S(2e4d8752,ac21c22f,e4d465e,3d2f5ad8,d9168080,b2b44930,e5de75a0,d9bf91ad,92f394c5,963c0817,500d5a98,2eccdeac,aa55043e,27a9a035,1a6ce245,a8d048bc) -,S(68b59755,44feb608,15a6ae70,9c2647b1,5c7fe073,aa6af8e6,202b9782,83daffac,b3745e92,fd86bfef,ab9d3d26,cdaf57c1,2a329889,cf646b6f,d6cf869a,f727e0c) -,S(15f5f668,e9576897,a287f131,bcbe1216,84f7a108,3c28c09a,afa77074,63dba49b,133e33fe,9bf06bb0,3b814938,7a099da4,77a3e758,82fb19a4,463ab360,bfbc368f) -,S(f2bf3cc8,ea752c11,db2ff594,d3f9b085,1dc9dff5,7999aa39,b5af2a29,30d50491,6e01a801,c5b7e4a0,a16af1ff,b011bc12,cb0483dc,6127fe52,c992b07a,9fd77635) -,S(1b04817f,46dae06c,120f8088,b3cd09e,267d4ed2,db14881b,bc32b5d6,345dc54e,31634e28,56f61b80,56a414e3,94a34ced,200bb172,e9a9aa07,6a224329,61f55ecb) -,S(693f066a,bca2046,ffb860f6,5e769ca2,3d1f46a3,6c09273d,afe5eb89,d2da45c5,719dd749,5c1b1938,a92af84d,eef309e6,ff1978b7,9adadb96,c58caf2b,625fff9) -,S(3fb25a02,bb232d18,c798f688,b16193ae,cb2eb9f5,e124c999,225f0720,63417008,90db4fbe,fdbf8a26,ff9b4afd,355e3771,c7c95891,68e2abea,264aba44,ad74707c) -,S(4c878f4e,6ebfed8e,e12a0a6d,17298b70,79d9de5c,6a7b5359,5ddefe4c,db82a79c,837592e6,927938cf,dc82252b,2cbfd9f6,cbff1950,405b4511,f2c21fdf,a3f72715) -,S(5ccaf6f4,2b75e152,49263cb9,5fdb34a8,770e8828,98a1a0cf,5407c48b,b9ad4ba0,70851419,379e5e2f,dca9613a,a9f92fd3,8ad8904e,e0ce0048,b2510943,ba8ee24) -,S(455907ae,713d1ec9,3792d488,7d9857bf,a02bc2ce,abd2c599,cf576f09,f7d09d11,1fc9ee5b,90a039f8,eb3200e2,ee58022,3f0cc699,60221d67,86f0deba,f13ca6b9) -,S(6f7acd2b,3683482f,c2c2d55b,eb62a89a,37578a34,417bcabf,ba7c56b7,bec14f0b,6049db59,b6210e55,b06401d6,17247d91,64e84e2c,b8de91a4,d4998c15,6f46d621) -,S(100f00d4,eee4ccf5,ea2558bf,92bec83b,223fa214,ad692ae3,b0a2ac93,c546d558,fe055fdc,1ae02552,1557db5b,96a62c92,556f918c,ca908708,46ffa1bc,8192b65e) -,S(8650c359,664c9f15,935dd776,bc6fbcc8,d9cb02d4,c22428e2,aee3e3cc,6e9d0c6f,89dba800,919866cc,8c16895f,785fc9cf,2661f78a,9e065472,652b71ce,d5ec8732) -,S(22b6df12,b3932756,713e2ee8,2d296c64,5d10364e,cca1ff94,9b477fa4,9a2ce5ac,ac58a22f,42769cf1,e2e23308,b3b5f139,4d329323,4bbd6053,4817ab5c,624e995b) -,S(ce87a23a,1554ae1b,9579ae96,863128cb,926a0cce,e51f17db,75155607,754b5992,4bb953b8,9d590216,e326f23e,66768c0d,17626262,6fecf80f,97435b50,d5dbd503) -,S(e3ae6365,29e3fe6b,cd1c89da,d72b17d4,8bf05c1b,c487ad41,d3b97838,a2cbc19c,4634e222,316b6ee6,c7616cfd,cddaee07,7fb2cd0d,26dd9f81,9d0ba43,313b3f4a) -,S(2825cc59,3a0678fb,e0d37d42,df72037b,6be96e98,18c52c49,fd426d75,324bd620,ea0079c9,2ef91a7c,dc587343,7b454763,f2fd4adf,561cd023,8379c8cb,1d281f6e) -,S(a6b2a170,fb23ae2f,943408ef,60fcb145,106735c,8876238,5d0fdd9b,75a2c46,1ab40091,e000012,60837529,58e3134,5f260890,d1bf6930,ddccedb1,dce20255) -,S(99a36f38,759f0a70,d719e3d5,b741a40f,daef1ad2,bcc65293,3992f134,39ff339f,a36d4b07,a7258053,61430332,6be79a,61ce8eb6,97944c6d,8bbf433b,a565bb66) -,S(e511e0a,de5a9be1,1b8513e,a5706258,6de09e2b,e2df739f,d647fd33,7890d36e,c6cc03ed,e9e50830,bd5579c5,9d6db693,dfa5c057,b1c214da,e4064804,9cd7ed70) -,S(bc9de66d,a406288c,a8a94e96,5ca16dfd,379608c2,63222a24,e3fc1116,20a82125,ac471a7e,579cfeaa,fdfdb5ff,9cccd4e,dca4202b,1b0149ab,ba9f6c09,aa219626) -,S(e98cd505,bd593bc1,496b1203,436f6038,ebe3fa4f,361ce4a6,54315402,a74c3a4c,1350c197,1c7979ca,7464c4d2,39b24a55,a1e50812,aaf92479,d566fffc,9135d977) -,S(47c0c788,2490ca53,37cc668c,5a549bde,dac661cc,f77534ed,d11f7ddc,9e0f37ac,ece10949,be122263,26819032,a2d952c3,60b27e2,7e527673,e8fcef08,a8f27685) -,S(e8224d65,35ea98a5,e3fd8833,7bd167cc,776f89ee,7d0ccfdc,46a15fed,93bee5e3,44b260e0,e0b1e1e9,383041cb,1dd985e7,22edb214,ae58f784,f174ba84,ef51c59e) -,S(c195ee35,5880dd77,67e01659,ecaf07b4,571e324b,b8a1a4fb,75265af2,3ea74709,95c39cef,f781f53f,31bde05b,d0289313,4e478b2d,1c55e741,aef8035a,2ecd4226) -,S(60d989b9,c9cccc66,139bbfed,e2902a95,fb9ca9a8,6c2e863f,21eceb4a,7d73c4bb,8295928a,a48ec1fb,775ea29d,9da1ceab,47e82f3f,1e6ef7fb,c7505e26,92bb51d8) -,S(a33b33f6,9db29609,8cfd34,caefd3e8,c3c0d863,ab695b06,b47d102e,f827fe62,669d9d96,842ee809,2cc31cfe,baab0f1f,4007c3e9,e7e41be3,7a08d221,1c6bc905) -,S(bd25afea,d9b8c833,fe332a2a,a9f3b627,d8328152,8fe1422c,5da90163,4b971584,35bb66e7,35326f67,63f4f38a,c18f8412,26da97da,c9e66902,f28904eb,b49cd78) -,S(4d7e208a,4264b565,d8563cd7,80773012,581e8688,a62921f2,d6a334c3,25625279,6729dd4f,b45ecd25,2c5cb033,dcb2f520,dc928ca5,71026fdd,b42943e8,b5da9988) -,S(5dd46f97,fc740db3,ec56348d,ed73fbbb,c440e3f3,33c64a3,a37b7a73,7f0e987d,7e2d9ee6,9e1c07a4,b764cac,aef3d780,e2d43288,2863f76e,35ff4cc6,832ede1a) -,S(4631992d,d72c02d2,2073222a,d35917f9,2770198b,ad13a847,8d3c9ca0,6ac91a3f,e28ce87b,35a69d5,c43b685a,e59d5f9d,ccf187bb,62517a92,90992b39,86d9e1eb) -,S(9153ad32,32177422,e03b6739,d5654209,7fe04d22,28b1e873,f02e990f,8936d1e3,8eb9f3c6,b54726b0,b4e867e0,5ab2fbca,e76d2e20,ce07983d,6edbd5fe,ebd0cc8d) -,S(939a7349,28fd798b,5036e2e9,60360387,b9c080a8,982d4530,78415667,848c2eff,30d2a2d9,5890d023,7d117cde,2eb3c532,e419770a,8783a7dc,dfe40674,709776f1) -,S(8e67bb29,9f11e01,b50be7fc,bee1f73a,5b335f5e,5ece8619,9a514156,dc243f3f,7fd0cb92,d6f9cd8f,bee9d337,90a4492,b8a7fa02,a0914c48,1f8becf5,d9a9d7da) -,S(a2cab3c2,537d8fec,b2f891a8,1da2f523,de4f869d,3c812806,855013c,73485ab2,765d058,c681af53,36ccbc8e,88d2391,b4894b18,15441342,4c4e73ac,1a8e0d71) -,S(9b39be40,976c13c2,faad320b,9338f985,b0718123,d2fb543,b65473a5,3bc2fce0,10f8234d,455fa7df,d09d76ee,41035515,9b560db,7b92988e,a42f9e9c,f7baabeb) -,S(35011530,6f2975be,73e7685,6456c94d,700e9b1c,4685639e,4f60efd6,9e513692,5992efac,9dcc0a58,ac6e00e3,54e44582,7e2d66c7,248e4b86,f8c216fe,a9e44270) -,S(df5a5b75,d96ddb93,9a341f58,7e1f997,3cb9e799,b04ccdfb,9907b57a,7b005d1f,3fd070b9,8d759043,8a53c302,b7ac0dbf,594094ad,7101d500,1cd5d687,e80066f0) -,S(91f14eda,a0db8441,10fa531e,eac54762,d52ca420,bb872327,6b383587,d40fa761,86cbd213,358d1f70,c3f6ac7e,913daf0a,47a80f8c,bd72445d,fcbef37,d0d71e69) -,S(53ddba06,46853311,9fe95719,15a9efe0,bc7fcf80,59d638e0,be6c1aa4,c5f21ffb,e59de2f6,5e583ab,5ac86c77,fc298301,70a18b68,a1979074,c21c0d8e,4a562567) -,S(56599462,4ad07c16,607afcd,76e86218,b15b50b6,9df84695,e60a15f0,3d7bcc49,c6d36636,ef58556f,9b688db0,eecb6bd4,5a7b30e,a9748732,68be57d8,542c966a) -,S(76fd5413,fdee9cb9,7f92fefa,5efa27e9,9aab744,e1e15029,241e35bc,743307a3,bb23f425,9aeb64e3,8ae82c3,b4691bf9,3b4a719e,a8ce076b,d0345a2f,d02a6d05) -,S(511ff159,2127502d,7499b988,7a3b3bd6,1242518,58bb62e3,dc1638be,89204a0e,21da5ba4,34b7819e,53b51e46,29f5fb77,e739ae5,97af55fa,aa09500a,dbd502f6) -,S(8e948cec,51635ab9,5a057404,39ff17c5,ae2e05e4,523bf2a2,3df28fd9,86de6b15,e16aa2ac,6c3d34b,9535b795,29a82b67,34bfa260,4a74ebe8,86110d73,ba564375) -,S(ebda8670,9277fecf,9b8507d9,40da6c74,210c8c7e,ddcff0d6,e3b52ded,3bf57095,3ca95e8e,112c8137,fe8c5088,bf041674,fb657260,70625890,1fdc5626,7655d654) -,S(eb5ffc4f,559f7ad,2469f48,1c730925,1ebf3863,357dbe72,41a29205,5b667682,b1f72d74,a5a16ef1,d55804ce,76974f46,61a49210,8a1a36f8,a59484da,a9bcbb96) -,S(2a93ae8a,d15c82ed,19fd2161,4a7a65a4,cf562432,623bf7f8,6c765548,b02fb57,5a949ca6,60a1430,9d4baa6,9be69b34,848e9874,62471d74,54c4817b,336584e0) -,S(9ac4a3e9,f1c8d115,138bd299,b6fb9132,c5d64a92,1fd94adc,82eb4ae,fa64704e,47f0eecf,a9eea827,ff339f3,48e67e8f,da9f00e1,a6b9086b,6f5441c3,7ae1d335) -,S(add254af,39d99d6d,355510d7,4f8985ad,3d8ec1e0,1e8d0210,27e80049,f555d65f,5b147a1,fc4bdeae,6c2f1224,b35e9e61,ad0799db,53597ef2,a23a8f3a,344dc526) -,S(d374d326,52cd006e,3b27b8d0,3ab47d44,bfb1c5d4,48adc992,5f63235b,c34aa128,3cc6ee09,c04d4cb0,aae8b1e6,6018640e,d0964fb7,148181ab,e9fd0374,642ad9a3) -,S(fa7632b4,78e5389d,cbf380d,8efbf6b1,d4bef9a1,70aa3517,e4c2005a,71a283f,ef2bcbb0,4b20be5,d4bda0f4,26dd0baa,31037d2b,7b530e2c,24105c3d,c817ce89) -,S(68ea197e,76af6950,1633ff9e,c825a817,80c7405d,ba513f96,6106632f,ea73ede5,633a5f90,587d4ea1,72129820,2ccefb30,c14a052a,6c0ca723,65e2f91d,53b3ff4) -,S(8874397e,1813f0c7,6946a84f,b05a0f44,224bb110,8aee722e,736e807b,b045b73a,ced2e2ec,85ae00e0,2952f55d,3626b613,641d2a8e,84b4c9ae,36177bb6,9ef80d9e) -,S(2ffe42bd,89256069,2e460701,b94208d4,85915043,8a85f71f,32246b8,5dea7594,6e7e4050,a35f1570,f8cc40c0,862e9cb5,59e744bd,8788646e,b0dad904,8b2777d8) -,S(c6d3a6f8,c997cfe,779a9a30,79de4bae,c19c226a,21f166d2,71ab4da2,cbc6defe,a8f8a618,3f6c8b2b,1486e60c,337725c9,9a9adc07,7dbb6581,e5b0119e,ca10f418) -,S(9b51cd75,442203ca,c4b8aba6,e9829b73,abe29f96,92b8dee8,500e1a90,9ea9767f,ed0ee32d,6042b6dc,dc818dbb,8cb00619,6bfeb2d7,88f35626,789cabb6,5d159c51) -,S(952c518f,775c8bc4,dbd7629c,8dcf8807,1b208033,8aee2ffa,eabad5d0,be6eaa1d,8a3b10a3,d9343d39,e7bef8c1,193f5cbd,717efa3b,cd2491f0,2dc1aa17,2e5b629b) -,S(49a18372,63eb11af,77a2e33d,2743393a,7eb269aa,f64589fc,8f81507e,55e8ee4d,7feb4a59,64b781b9,640d60f9,4e7eb291,6025d190,95945aab,7ac7771b,6f96cff8) -,S(cf974d8f,46aceb5e,a8c04e55,703b5a43,ac577e84,cb174abd,88198e1c,12708c9d,c50cf6d2,afd79d3,ce275e91,26bdaf0c,f46c1eb,536d0753,9dcf6c2d,d79afc35) -,S(461a831e,8beb6da0,df92dcdf,2697d551,cbf8f903,138d13f2,ec9b7fa,4a7d4763,e5fd85fa,c251705c,27d4e870,64af33b2,ff99b19,14496d96,6fa18916,faf40e01) -,S(eef4eb8a,9eba3f2e,b27e3aca,6cce7335,49f2656a,c26f1921,60c05bb8,fc3f1165,58f74526,a812ddc3,713217f6,fa4be02b,7062d042,2dbf5625,abd1f422,58b54c36) -,S(d674ace8,a7e8ae,d4bd4b7f,235b9f4c,41ef4355,4d9e6e44,3b6a26a2,d16f798f,8a25a7f7,896c0dd9,b1639f99,5c4b3df1,a3536104,b7d59348,c2c56c0b,bb21c609) -,S(a8eb465a,8a2869cd,6419af81,b3ad1355,1508727c,2b2494a4,93b5ffe6,2c1375,f1a27219,f59f29c,bb93bdc0,6157618a,454075ab,b95184e6,a4601ef4,eb2c8a1f) -,S(ccbd9d,6253fae3,f7d2527b,17854e21,58581e95,11a1f11b,55e3e04e,7326e6db,51ddefc2,5d9083ce,e9999e91,cde32f70,344ec937,d6aa5272,3dd62496,c4b0485b) -,S(524bc1e1,5c75e8f0,6718d2c6,da0f6599,c8b5d83,7cb9b48d,615e8e46,49dc6659,f6c91d14,72a50c31,1bb202b2,3d76f224,b55af957,c7bf3c19,69d175a1,d36ed19) -,S(520e667b,a0604a23,dde663ea,1a29971e,7e753301,9b2217af,296b02f9,de1df35d,9c2a2c52,290b6927,ac566ea8,4caa31ef,cb19b65f,29b4833f,5f4eae8c,f12b38bc) -,S(156282cc,65317dc1,3323aae2,d5d83e8,b7113d59,a50e54d8,dc54c1a1,ffc85d23,840cca23,67da3c5a,15b6427,72f0cd7e,675bb8b7,fb5dd58e,8cda9fcf,cb21606c) -,S(15afddb0,5adcc8d8,f1322a7d,f451fee9,873d4b8b,78b0c1e8,1d99f002,84aca6a,15465563,a129272c,b5e25bc3,ac76c52e,b4e115b7,b216a40c,145c4699,175cec9b) -,S(9eec4fea,e9508445,4bd275e3,f8d0d6d2,9040ae95,c8268f55,918d5f3f,2f75865,b7a873a7,5fb4ef70,3d62a723,81df2ded,102726ac,81685725,424a7733,8307ed7d) -,S(3aa7be96,660652c4,de1c82f5,cce1a864,c37725ba,848180bd,52e4dead,1a33f60c,f323d266,3e5d14dd,18fbab76,271f6c8f,32d7de0a,42724fde,f6ed3582,c886c402) -,S(bae9e070,a8e5a976,8347368,c32b4287,c7a6a20c,b491bebe,fc6acc71,aeeecea7,b5791703,f98ae848,1a9c66ab,878f7c27,d37a3e0,133b4e36,82ccb2af,b518e8ef) -,S(7b12ed88,be061d1f,7dab874b,17602bb0,ef5ccefa,54f9ff40,e753312c,335f5f86,70930f8,c465292b,b02ded5,59a235e6,c4c83480,9eb94442,8440846c,377498d6) -,S(9eb22b3c,8faad620,ba002990,4a5d8d1e,8cb4a054,179e3310,73f4ae8c,def4e1f7,6d58b972,ee88dfd9,4e429a2,4f6961a7,d085f00e,8d6f8d14,ff2066e7,df68bc34) -,S(bb2aa6cc,d8402cb8,e7a9a6f,a755c66,366c659e,bd2e5c85,7fa486e8,aa86b857,443e7128,674c040c,b0316d9b,3908bcd3,298e727c,c805bc8e,ca58894a,d51f4130) -,S(c58704a9,fc3bb18b,c460c4e1,f17a880e,c0dce45b,e2caf759,72f55061,d59d30d9,75216472,aee1c9c,280aef07,7208fe42,136b495c,f80d8a79,e8309272,c6c4d6a7) -,S(b7d7c721,70af0b6a,489c41a6,e817da2b,ce59f30c,88a82b11,83a6af8b,174c70eb,59481a78,52f3726,3a02ef48,dfb366ce,7bf170b0,af3c2000,2c1053e6,5dae1ef8) -,S(b1386833,25f5450b,f4f68dc9,93d72fa1,1e636a3e,8b881ac2,f237cc44,42f3461,64d18f1b,87f9463,10627931,cb003c09,981c4a94,969a0df1,7f717830,4daa6cd6) -,S(7e27af99,500cb8d4,d812a82d,29ca369,5e543231,8432c9f5,96f5b76d,c6d1bd8c,25a477c5,a275daad,10973822,40961da7,5385a367,6dff887c,42bd904d,8e885997) -,S(62e04f6f,d953c744,aeca984c,bad13c91,f4e09c1a,d5441603,2bfbc277,5ebbfdc1,4f1f609,db0befd5,fe781afa,d21efe44,846f9f78,9ed9f99d,f3291eec,3cf3fc89) -,S(b08a1f84,a3cbc3fa,f952247e,6d8d8d9b,1ba3ab01,ba03ef8e,836b94ec,dfe2e2c4,5027889d,e524fd0b,e6ada02f,4f33d1a3,4d0c3822,f0ca6651,ecebaa37,3c54692b) -,S(d417933b,c7a8f68a,9e023d64,498b5117,850f8885,b6254256,f9a12a47,538d5bd6,7ad14679,21349d14,10e35750,167282ee,9a6f6044,b6c9d71a,633f4475,5b432ed7) -,S(575909cb,46a36dc1,c270267a,10a62f31,941fb7bf,3699aa43,1a3bc770,fa37d5de,c12ef954,c937d6a7,bda47e2e,67d9ebb4,9434cda,e1571ec9,f604c41e,b49d6189) -,S(5298ad25,cc5a6bf4,d88b693a,d32a61fd,efd763f0,e4008ca0,eee17730,4365de57,75f821d1,66b60185,41cf7653,9a0cc41,597b8b78,10fd1fed,f0da4542,3a26d5f1) -,S(5aab0fa4,b0beb77,d5d2a8fc,c95d516f,1dfdc402,3e3d36b1,4ecb206e,ee8c5ff,7a4659c7,7c062356,c51ee28d,fd0cea92,a1f36d5a,b78a3ae,8b48ac9c,7fc63fca) -,S(482fc791,7c739041,41b69e59,62b0b815,8a9bfa00,f203afa6,46973980,9b250a23,89b117bd,485ac6ef,4de8eae0,a9e96edd,a3615285,e33282b7,bf0b6a6d,e11a9c8c) -,S(a576ceef,40728a7b,b63756f7,f3095c75,ff2ef84,c7933d02,b9dd8a0b,a6046653,b4c707dd,9d880fd6,d7a1ea13,87dcb6a8,e2433e21,8ef3a7f5,e348d2b3,f9a9796a) -,S(3c9d7c33,f8c62b35,fe977359,f290dbd,c2b46fb0,a2fe126c,d06e0422,54d1527f,cf92e34,3ce9f624,84c04c9f,d97569d6,67065598,9418d858,aa7368d5,bd6a2df1) -,S(56bdd1e7,363c52b8,2198cbe8,62ed6d7c,7b96d184,7da44036,2401368e,b2c83b89,505d385b,747c9545,6669809a,a9da035c,364e7971,7cd89417,3d1d5d58,298a1869) -,S(99e0696d,ed30d242,bff69e9f,ff4ec88d,eaa3de35,34dc7f35,c2bb7df5,9f8b440e,2cd1fc77,3bd071b4,c9695f25,458be688,f662f7ee,ae8f313d,9c373172,6185acc) -,S(7d5cb46c,81f4a4ec,f1e5d913,1772277e,d17de7ca,7a4b277a,d6b135e4,dbe61916,cc854503,d73e8034,7a6ad7e7,f5bab321,b130d7d,3d938423,9e0656d9,74971849) -,S(45cb6ec8,9dda9aed,5242347c,a20377bf,c93ebbd,50e48ea8,159530f4,4f4a250a,411a2ade,aaaf43e7,240bb0f7,cde77d8f,846bc700,4721f6c7,4d313fbe,70ae38c2) -,S(a7e23331,bf08ecce,2dda8c2e,a6c3c4ce,9bbbe3a4,4d40068c,e39e94fc,edea42e1,d1f12d24,144bb258,dcda7060,5348c1d,85faf076,fdd3611b,ecf6c34e,843788e6) -,S(d81aa0fc,b0a8fafe,d4c67dcd,6fddd414,80cd5548,cbd6aa58,35e5896b,18797f12,92af7ad3,89320814,bbe53ab,4cb5bd26,3df11ad1,8d2ef235,ae9ba163,74495d8a) -,S(8d379fd1,fc0acf5b,c96d03e,b73b340,5a7326ec,82882235,918a380b,c3e2669,f8c6063a,eefc0e2c,ef94d8d,ac4e5b5,ccccdf25,663d993f,7f9a0172,6756564e) -,S(5e20f600,6f533af1,8f3b6e65,17aaa2a1,2876b79,c99ca059,c2791a1f,1e466e8d,b23fb129,57640a9d,d38bf206,7649216f,50b913b8,69d241c2,baedd5e9,dafac9d3) -,S(1a0a4f54,80d37257,c62d1b0c,18dda7ce,f2b64754,be9a3d77,b3d80ca9,215026df,2f76696f,f4001927,9ceb5652,44d4a60a,9e353266,42bc2138,1191a51d,7661ca1) -,S(be868184,dc2e91fa,b11833b6,f78577f7,8c190220,a2b46551,53cc8ea0,73a217e7,6ffa3f78,1c64c118,68abc331,beb8c284,2919d593,12bad699,53edd222,2b98a31e) -,S(a4650db1,917b10d9,1fffa809,d9f9cdaf,f07faeb3,8f0ecda6,9c80e0e0,fd27592a,d5a6fdf5,647e26c4,1d7b9c78,7880c76a,b0cbc23f,d4c1840b,78717b34,2ade1422) -,S(944b1701,4a7c7eaa,754c9e03,d56516d9,e21e254e,9a871683,7a14f19a,9ebaa517,ee198337,3822c796,3ae7df88,24687dda,eea01e83,c82e66fd,baa746ac,485a6dae) -,S(f9e76020,cb9087d3,a60ba7ef,7ed5e552,3e5a3645,f61f9ee7,27d630b7,98d37ede,28371db3,433bcf49,f6d77711,d7ed9101,f5e478de,49c58103,b021457b,7a0b526f) -,S(7ac0c7bc,e17509a3,e4dc004b,d18c322e,600aeb83,8fe2045f,6da348ec,6f178b41,8b5cbafc,33469334,4886f60d,ee7626e5,36e9a977,60c0dd18,7bab7e45,6b264956) -,S(1d7ef98c,c8520f5,2310ad12,107351f1,966b651b,4b2a39a1,7a47f658,857e3bde,2b78bf4b,7be6f1ec,61cb235,a26e252c,71d91f58,69752719,8125712,55d47664) -,S(fc57f5ea,b40add8,f00c2da6,c7d24540,1b24b6b1,f102836b,4041009e,2fc6d5f0,11d3e017,bbc33913,b7861dff,bc11bca5,5aea26dd,f956d21d,2f333755,ef823af1) -,S(340c47cd,3b473c01,80526815,64e77f7,6ec29eb4,b6603985,d6ef7b64,29e2f289,994d98c9,c1de0dad,d27f3386,eeb7da40,6144e060,ef4db403,ee8a76cb,8e21bf89) -,S(81b13929,f08e9a23,69127ba,3e6e839b,8e9cd05,b19a9bf5,2292148a,26bc47f9,b6c33861,ae8fe20c,7a6c7830,4dd03fc1,a281ea57,59661e74,7f9e904,e4261226) -,S(6f325fba,15a463ba,4a61e2e6,82655af2,72603643,8a48075,f76c9882,4d7e252a,1f205971,70f9f48d,5421b73e,97bb6260,cd2235e4,6f611e9e,99b7f8ae,cf435d45) -,S(4b388e91,fadb26f9,b23b015b,398c8666,91521b8b,484d4510,b3c162d5,834bc109,ade8365,9d59c363,3191c3b,20e395cd,13ddabe7,1933045b,cfd8e941,f2096d25) -,S(2d1c0ab2,83c80dfb,ead3e083,76024910,c1d97acd,6c8be069,252bfd94,ac1a0db6,c4856c74,e5ef2e6a,17ebc35e,3b310f6f,8e7b043b,abfff733,aa3ed9f8,5a391c98) -,S(4c77a1b5,b88ffcce,1f98fd89,251c0085,9d4197f7,d45bee5d,edfded14,a97e5b87,48b8135c,b067c292,6c316424,2392fb06,f698b6d6,e98b2ffb,bcdb028f,4d85e5bb) -,S(d39cd5fb,11cabce0,e31f6fac,10cce3c1,c0bdbcc7,294119e0,2b433b0c,20e3a4ee,487695cc,8a8ec5fa,aafdfe25,3aa7d635,8d44e82f,77328e8e,4541f7bd,f629bb5d) -,S(238a05a5,519ff4e6,29b0f86f,9d259eee,4e620685,a2f0509a,cc9fb1eb,4e89f5f,6772f6b7,816018af,ec95717d,a6be2d05,3d740ec1,80241798,117ed39f,91f3beb1) -,S(c146bf13,72816407,b5f8532d,91210d59,a8a6db2e,54fcfd3b,fe910365,99f7ed14,e952ca9a,f88779c7,eea67194,3df6fad9,72b717a2,19d1eca6,33106f97,2dfdf0b3) -,S(4cd9154,861edfa7,c29378aa,1a7d6d0,83b134a7,572383ef,3010f34e,19d40bea,9ad99f1c,b5841c57,5f7db959,362542fc,40b0cbec,58d16ce1,54c5944b,6ff2aabb) -,S(d35f2995,2478be06,e86b342b,fd2d2cc5,ede30ee8,509da11,504bbffd,5884765d,a0f66db4,a21462ee,e51e226e,2d20d896,2c4edb1c,babc45b2,645968a9,c7810fb4) -,S(caf9c953,ef1f57e6,905bfec0,2fd64fca,92ded9a1,9435ad1c,a672cb7b,117c6fa,23b01776,7662984f,9c2f9e43,756ed3a1,3a574960,558db4ec,8670122f,472d0ccd) -,S(4bd40ba0,21d2beec,ec7317ac,df3b719c,179ec012,1274a198,d0ebd9d5,165bbfaf,9a5751dc,d7885a78,20d8ccfd,1db3e3d,aaa2bd65,b7b6fb2a,2d7b2902,c629d81f) -,S(560928ae,7b15a63,62eb4444,d4c0e069,1ae43323,77a2de40,83f056b2,70259814,ae97006e,fa5986b6,5da4ddbc,2bcea172,f12945d9,b6f5184,4027085d,bf644794) -,S(7870209,38e53dac,8e250835,9e41e313,25b09faf,95b03a8d,c25e83ae,f8255301,49fd164a,915e0af1,a66af8ff,d215d1d3,92e4996e,5ef68f8f,51a4b895,145bbd90) -,S(7aa3742a,6c82c90a,7e6c1b04,a41e4643,47925d,66f4e7c9,ab2aff17,e64932fb,7317dd5c,f2cb9b3d,5cc0fd6a,c433d1be,d1dc8345,b26e10b9,a2b8cbff,ce2db0c6) -,S(7a400535,be3b134d,4572e0bf,75c13098,dccc0f04,1c10068d,31e2b0b9,149c2e08,c00fd102,309626e5,a2f97ef4,e0374a3e,de0a7ed2,e45aede1,40521086,5d10466e) -,S(f4d71adb,438460c7,9003e150,c4143557,ffe30efa,eed122f,dd97c572,e1dbbbb7,e73588e0,fbae054c,140c0474,348b7ce2,92a1976f,e8c940e3,62c29ea4,31bb719a) -,S(34b68d32,810bd1ae,51d0c82e,ef99752e,8206aa04,8c5c30,7c3e9a25,b2d68b94,4d044a,6781875,6aeb8982,61bff840,a3ab951f,bf60cd03,e8befb25,97203c7e) -,S(f83b78af,f18f22b1,f2081707,3dbb9c79,4f180b0d,8871a1af,94d16d29,5c71f1c2,93ea5b8,c7847ea0,2cd5b783,5021d37c,dbbd395e,fe6eff8d,866e333e,9d6083e) -,S(a4a0d5aa,f521e1bc,2e818063,f4575f1c,99bd2447,80eaf848,2737b297,b2deaffb,3906373f,2111a47b,102b0294,f9fe1a4a,7ea9a9e9,aa2d9595,68ff8419,9f1abd97) -,S(cc211da7,28671182,1f0bca25,b9703fdd,ac9d0277,7e1829b4,4d9921d7,998011ff,c0cc46fd,5519211f,3a4cfa43,d84e5b3,bfb316de,39a5f4,9a50b1b1,8dcef321) -,S(8a07ed5b,e0397b5a,8c33ef,108df270,4b385c45,c8296593,1ed3e391,17b2f531,432023e3,8fc1a637,fb5a92f5,9911932d,f5cd23f7,eb16ef68,c8c573fc,86e8c1a9) -,S(8add7841,86b68399,b08a0bf2,a92a3987,36fca803,3807b564,f97af438,ac70d49b,758cdffc,ef477c3a,fb3028a3,2866d860,c65aa2ef,7b3d6261,9664ace3,658add34) -,S(ec6b9f2a,a1cdedaf,306b8a5a,b021e430,e9931126,a1c505d4,a10e71ec,3cc60453,8139b262,40e2c1ca,8ec89808,2a37d7a9,b78a7e5f,6330ed32,f9786cb3,c4ddb722) -,S(22ce2541,dd8a47ae,227dfec0,95ac361b,88ae2cd2,c9547344,f551f6bb,cada196a,68ce4f4,a677a0f9,60aaf4a4,f8e83a24,ebfbf46c,6ce2a470,255d2ede,c4431581) -,S(ee7dd0d0,3e5b6d8c,ae78caaf,27b902fe,4136201c,12a49551,bf208c0b,f88bd33b,aff0eef0,609bbf68,7ce2aef,9f48f87e,67aedd82,e5342159,3809cf5c,da4ac004) -,S(f7f9a352,ca18b2f4,3aa18c00,9ae0eb31,17679db8,d9fd7e5a,41b77e85,b54140cd,afd30383,ccd2a6f7,ae76b953,5bc80330,4419d38e,73e12d1e,dc407ef2,f3b50326) -,S(7793ef5f,8e57e872,ea9fbb18,bd710ab9,6ea4f646,134d3308,930cbf62,e73f0e1c,8d5b3b79,3573090f,a4a7e7e5,c38fd987,e889bc3e,720e05b2,43e856f6,32ae7cc5) -,S(db743211,ba814bf,e6371ddf,d03ba554,b558548a,a90e81b8,e1421321,656065a8,8236f24d,965a9003,84b382e8,d772d7e9,2dee2ce6,c3cb3388,3ea627d5,4a5170c4) -,S(48c22865,6e51199f,6306a6f1,7dac1e6a,13f82d42,61de0f0a,9158ba98,715d3cf9,19a2a4dc,35d2bd03,5bc5daa2,5526598a,8eac11c3,52e5fe70,be726531,747035ef) -,S(70a28bf4,ce75b491,582b48d5,9a5069b,9dcc1e49,c41702d,ee5d688e,6e643a59,7183750e,2995f655,1b58d5e7,21a5f33b,69045934,27f27f34,f8ebf62e,74e49de2) -,S(a90d8505,596b3d01,a5e8dad0,fe652cb2,4a008a7a,61ba3cc6,8401a7a5,5c2e3132,f98af047,6e925c87,e13bb7db,f992b81b,1be564b6,8589cf2d,b79e4800,3ff7b0d9) -,S(88647576,8e960c09,6aec9832,448decac,6574491c,df737dca,dcc42b84,d7e775bb,ad94bcbb,7309f483,19077724,2582f5cf,a39ead6,a4050afd,89a49ecd,7a9090bd) -,S(c505d2cc,ef72aef5,8130f472,2ab3b2c2,3a6864ab,bcfffd5a,725a6df3,fae02112,dcb82329,cc51dc7a,54e7104,462997c,3d135d6d,5c82463f,45e875f5,8738652c) -,S(24a1d4be,c709cf8c,8b8927a8,8bcfb11,43b0d579,10e0900d,68fbb682,d4e14df9,9ccab057,8440f6a2,edaa4f41,28f427de,adce5584,692b79d,624e8724,572a043f) -,S(48c44581,51df1654,fa78370a,6975e59e,576eeb40,e94f636e,72aeb37e,8fbdc4bb,f48e8dfa,bb085834,43a7b495,ced76171,348e92b0,41b9620d,3cd5a84a,d9ee4eb4) -,S(42a7838,d33d0b15,b4409534,18024a33,e93ccad,946b50cc,a543ea1f,1bb457da,dc2f0e6,4f30e973,cdf6289d,d8f6455d,51c2da02,bc4e1d13,6668250c,e4dd791f) -,S(80988f4f,c2dfcb86,f1f65196,d93a6cfd,5c664e1b,5f8875d2,61e7c4f7,b2ea31e4,1e695c33,b526d582,6210e694,49c4673a,8697e1d4,a197c9bc,a3ecafda,2a7d5b93) -,S(a0ae003c,65d7f1c7,b65cf828,124701b3,876d0be,587c2589,9a618c4e,7b79d480,d7f4ec52,bccd57a,9515e80f,2c79be42,a6b53ca6,253ee13d,ca33c917,ff2ddf02) -,S(392f57a0,ebe08b06,cb4946ff,3c1df6c7,c5cdd97,b9cb2190,dbd4678,cdbab3bb,1be9f9db,dfca7981,b3dbbb1f,daf50e6b,c5662fa8,1b8a58f9,9953eebc,d1d0be1c) -,S(cd904f6a,3d8c4ebf,6ebc4e5a,e536c544,4a04e278,389d771f,d5e7566a,fc592d3d,e3e10f61,a15399c5,f3f29626,af323cd4,3d6572fa,bad4f02d,cf76c0f4,9785919f) -,S(27a4480c,df5782bf,52ddb140,ea5a908b,38dc1ec6,a570580d,2b72b922,e7eb05d9,bd96ddd8,1a6aca1f,88847632,5a6d48c8,4d61e76e,b4d0d957,15d39f80,faa42f3f) -,S(6673ae66,3511292f,fa4dd8cd,bc0f7b36,613c56d2,775602ff,a8cf9302,4329f5a5,d8b4ffd8,8ca2530b,18d85762,529d056,e8048cdc,51730082,2d24cf42,e4053141) -,S(3dbae13,5c395043,d5b88161,4dde355d,5a669076,98c36b23,ac4c24bf,80e34f2a,b7d46059,3154fad7,eaa37c3a,291c6c67,16df2944,4274b044,a9f12ac0,a34139db) -,S(f2db4c09,1c3c606c,9784f6af,7dbfb26c,2b18bae3,b22f13bf,4188d761,6cbc1371,8c84e295,f57a9722,260d5816,c5d57719,c6fe2a12,3ba20a48,189bee04,ac252f32) -,S(918e415d,92e768e9,f5a875a8,aafa7dd6,66109cd5,8fb6044d,d2c8640b,f6b966a7,b53400ce,9ee9f6c6,9cc35b5a,3e04eec3,dc89c931,e545068e,ed4a818e,42073e71) -,S(5eda3e22,bbb8c368,82d46c19,2068b3e9,a65624ae,31feba8b,df725d5e,47bc3437,1cc2c541,ce3ad8fb,ac3cfabd,a492c03,87099e1,659cbf88,bc8f27aa,f9a2fe26) -,S(7df83e06,9cf09a92,5405e0d4,3cf0c7bf,52a8e603,d286e26f,f273e218,b455e61c,9eba2975,7f61b054,29c9e915,a092a591,ac1d6044,8a63a8f1,313f4018,1650f4bd) -,S(b778c25,d78b0bc4,68dcdc80,5de93809,1c3c36c5,b5f9569,a9394b5d,c7afb162,901a4ecf,b4821145,c7d9e56b,75e43ab9,cb7ef8fb,1d384a4e,27033e9f,90b80fc) -,S(dd4965e,f6fb759,104f7877,307e2a6a,f837ab6,8c19aa40,6fbea75e,e8a7adc3,45e92312,b5c77585,3c4b95ca,6b4c1740,a70b57c9,97124883,2c53d291,4b0fd4d8) -,S(ac971379,7dffd8d8,2e33f927,48ca063f,f1c8ccf2,5b88fb6,bf80946f,1dc9dede,6ce10e3b,ee4db87d,40e8de66,fb5263db,2a578d6d,be100fef,d6e28bd6,7377bc26) -,S(6046fab5,37fb413b,29797312,5a6049b5,5c085194,4b058264,c39926ed,fe85c6,dcdf9ed1,cbe469ca,2976333,5a159e42,af6f0d32,664ffb5e,173986d3,a277180d) -,S(a0d94b05,8e3b4d30,7f3b3f09,ba5ba28,d0285a3a,22cd577a,1d949b8,bd23f1ae,37fcdfb2,e3027e07,ea77f28,447ea13,93971c67,974304b5,dbb7621,2ad2db10) -,S(da15b971,1b974ef9,14433ca5,71175233,693cab3a,dfd5f6e8,cf034254,6f73dcd,e08c7f62,90f87fc5,4e2f4ec5,a5a93d19,f4484868,3b5ae9d3,810b0615,c7e79402) -,S(b26ba5d2,72a744f5,562cd745,a3f3f143,32980458,60be4e97,d737fbb9,b3b0d544,3d308307,9830f281,14de6c5a,f3876446,507558e2,95353dcb,738deabd,80c0ff20) -,S(fa26c55b,bac04fff,ccee0610,ba9b60a2,4042aa08,7a564ffa,b891e087,7a2185f5,5b5a62eb,1ff579b9,ee4c5d6e,ceeb57ec,e9881b47,dbfc24f4,3b9a18d1,4addf4ab) -,S(5ada4a59,4802163d,4da685d9,b7479f,4b70b489,5ddac7a3,b06a1c4e,a5f46dbe,2ec25e70,871b4958,81f6b0e5,cf821b91,febe83db,a52fe2f8,1a2e4e82,165c7e3f) -,S(a57751d8,895282ac,bef2384b,db4817a3,539899b1,e7fe7a62,2596ad18,5dcf878f,651eee9c,12ecaf92,9eccf109,635680a,a7499537,f2054e2f,69b0f062,c820784) -,S(3f17f0f2,6a540098,d18f8d88,ad323e9e,e300b029,b7b8101f,6aac6ece,8d375f3c,9c0713,79e35319,7f1e76d,55616e5f,8e573a54,b6bfa56e,5dacd2aa,e2e0deeb) -,S(eabdf476,d2e9d76d,775388c,da759930,4e1ebd59,b3a7e491,e3c9c62a,4d0968ba,f4bfd5b5,e0e8ab41,a04c4cd7,763b243f,b82f56ae,9f08a6ef,bc365f3d,fa227c4a) -,S(c5b76ae8,dabb664d,fc1fd499,36399e3f,c2b7366e,a21cba10,dc7eec7c,5c93e0d3,ef30249,19bc03a,c24c8544,9467728a,c160edc5,7c901e64,b947f298,9bb1242) -,S(7161dbf8,6b1080bd,bd6aa47e,dcdf8a77,17b7e281,c692e9d8,739caf9a,f3f23d6,3c30b786,b095288a,4522749a,3d32a35,5a8bc694,cc9cf7ea,989675e9,a1688e8c) -,S(ed6a7b49,9b74e62e,53183b15,6867d41,3ce902a8,4b71fdc4,fa414f8f,249c2ce,793d0356,1bca65c6,be127ce5,a1034b9,86285fe1,f52075e8,1a9b5bcf,87348c4f) -,S(fe6e1abc,3ee3be4e,22456f4c,bf93810f,282f0fec,96ab5cc8,2b35b08,54492bad,96c76282,3adc2cea,1563c02b,fdb25b55,eb15e769,90a7ed7a,3fb8aabe,47bb077c) -,S(979e7ab1,96e66818,b67bf79,31232826,713648bb,ad956add,ed594cdf,8aec2937,696a9505,e3c473a7,2df68f96,13c2e494,406782a4,f92a8fd6,5017a83e,d7912491) -,S(9f947cb3,f859f2af,11a63400,800c18de,b8813c1a,b396ebd6,a1d5bf4a,9689160a,8efeced6,7f1e6fdc,191ac965,5002a02c,386a20b3,eb2aa1be,7fc12008,b8bead1) -,S(71790030,58caecb5,dcd2e281,b42eb59e,57de1e6e,b77f6bad,7d2d1897,6a512eb4,abff54d0,e20347bb,c10a79c4,127f5f7d,868176a7,4e34077a,8ede1d54,7e339483) -,S(d786ec15,c140af46,841b7eb7,de5fc9a3,c0636885,3950bab9,ffdbad01,d836b8b0,fc90191b,63616a44,72efb2ac,a7d84da3,4892af1e,25bca0e2,d41268c8,d381d062) -,S(2d553f03,31eb83ca,edf2508e,67054734,d929367b,ffdd5b7c,dd78dc6a,2e724534,9abcef4e,ee588e28,fa1dee0a,b8c426c1,67d37cde,f8aae9e4,248c036b,baa1af70) -,S(326b36b,eab4d932,c40182f0,fde043ff,d6b84b16,72fe1dc7,3bc7e518,6ef68062,9d86868e,2e871ce5,c3488624,bec901d1,47b91bf9,a3154cab,6445870e,d51e8f1d) -,S(f7a6a26f,4e3583bb,9552556a,5d248735,7ea4af7d,ad1f7a92,717d19ab,34dfa11,7ace27e1,dab2dea9,704c01ce,50ea3de,529d864d,9a5fc11f,fbc0e8c7,81778b2b) -,S(8ca708ea,c072334,42eae4e9,eb0c7b45,83e153ba,84ed7a0d,3ece41f9,4df6cd15,33f41d25,e446c47b,68ce1bc7,d1dd1740,fc701538,3ac90e05,1dc89a9f,dc97592b) -,S(4fca2ed9,e1948697,208a87f9,a890cc96,4aa9e5e5,7c7274b1,deea92bb,586875da,98a9303,4df7185a,df9f557b,b7def9a6,41e7ad5,a3f24051,435673ff,12f0580) -,S(466da0aa,97c68c05,21b8fda0,fc70d74,bb586eb3,da7eab4b,6c104404,d9234d37,5834296,f94f5b54,beddc0e,3d7f6004,659952b7,90a6341a,de99ff26,5530e5e6) -,S(ae22ae10,d016b54c,c0b5423b,3f4c332e,3180ff23,c279078b,864e8e07,77e26a5e,ee21d64b,d6043d56,de3346dc,f93e2c40,b9a51498,b4d7df61,d476d339,7a2d0c8d) -,S(58cd60cc,ea7e0896,2f65a353,5d45ad06,517fea5,575c5511,277103d9,fabb5167,175a68a9,850b4026,bc7b5684,e859c808,edb5f3,7acebc47,9ba489d5,5aa9774b) -,S(4be8a0cf,7ce26101,49cd90a8,68f4049c,43054aa5,68bfb2a1,a5bfa386,9b2b485,a3bab0f3,e3bec469,f779404b,d025ca14,79e3f6ca,9d496f8f,8ce4aa6f,b7e3b404) -,S(428599d9,398a2c59,58c5f74f,1226605f,3c5c8e74,ad8f9bc2,d62b8d9f,d679d3c3,12a1b04f,add5d70,bdc5e15e,d6347f7f,6785c425,61f14ae6,275cf050,3a1bd5a7) -,S(134ba4d9,c35a6601,7e9d525a,879700a9,fb9209a3,f43a651f,daf71f3a,85a77d3,21c112f7,6a9b9b21,e2e3a7c2,8cf500bf,f48aaf1c,48e0e13e,f15618b9,ca62287d) -,S(d53cf8f3,cc5e5739,bc9f9144,a44e7b7b,bb8f2c36,b50844ca,9b2d9cf0,cd0616d2,799c23b6,c57aac44,90d71450,4388cfa4,689393ab,6f30a347,4503400e,c568e03f) -,S(a1e22cfd,e8d12f17,eea1eca4,ea0b520b,6598c036,d1bf837c,e23bc300,a384e5a7,cfbb52a6,e1fb6a65,77cd0377,8bc965b2,a3df592f,f73c34d2,a91b8008,74ecc295) -,S(72bf047f,a0da1391,78b97ea,7b317168,ed0576fd,71f49409,39a8daa5,2a02ead8,f8d93088,cb3457e,7828ba9c,bd8492e4,9eb2bf0e,2e23bfb0,4591e9bb,5273f462) -,S(c5373038,4b951abb,3bcd1f4f,98d983bd,cb5b36a,42719531,c4d1797,2e9bce59,d921f353,a9f7309,6dc16028,f9e1b562,f406bf49,54d78bf9,f2b4c8b9,2db26a82) -,S(ab20d194,e2a6c4a1,5705d3d,19300810,89342b15,e9fc6224,7be58805,a8682a5e,44dc39d1,8342502d,cafafe40,33c4893a,2dddddd8,ad7b238a,efca50cb,5d5b3186) -,S(1432ddfb,108ee664,2eaa9c97,585f47b7,b92a5ae5,39a38093,b8f3153c,e971c8f9,5362084b,5482e375,1662aa95,dd3b9a6e,65235aca,b0ce1eae,f5153951,1391e269) -,S(f199ede,4a69d778,61e107c9,376bdee5,6430e279,28c74d75,66e65589,be8c433c,5e7f6fb7,1b68a535,f407a9ee,2e42f65e,9835bcc7,2c34b8e7,712e5332,a65e9ac6) -,S(b24dbf51,47452b5b,ad94bf4b,493120ab,61ce2ea4,37b3ad71,62e568a,1d595d1a,b3af5a90,8d063602,6b3869d0,c9f31793,61afd6c3,8db99cb9,77b14e0c,46427518) -,S(d7fc29eb,b681e025,992d9ef7,295db58b,40f36c64,d1be10e8,c8e66858,d4d0d9aa,c587764,ca84b3c7,2f95eba,eb62494f,ce391202,90c42b9,e8b2105d,ed972595) -,S(5c71e90,d5f00ee6,e033f0c9,c1ac495b,d148a31d,143a8e3,59a99c7d,faa3cc9c,4acc164,ea3071b7,a4830a27,24135c49,562ea631,9dc4455f,808f1282,4e3bbbb3) -,S(4c9904a9,a33f7e33,9a3d85ac,c12b21ad,11f7d7f2,76e46620,76878593,9d11eaad,2387a445,b0967403,86ce4634,62dd101f,95650365,ac02ef1d,2417321a,3fac1df9) -,S(58f457ec,12d22482,2a91b78e,26f7d8f8,5fa39d90,59fb833c,bce4b1f2,5c9720f7,90808a70,79d4970c,b2b70ae,390844a,2f0283ee,eae05a5c,7d2dcdde,be656f2d) -,S(9867259c,51414805,3be6a73c,de522d91,a8d8b359,9f9bd39b,9c9575a3,90405bdd,9904fa47,34973bc1,77a3d0dd,f0edc0bd,cbd77b36,357734c0,a0feff89,4895f3b4) -,S(663b4991,913148b6,631d16fc,27471938,20a7ace4,ee85c335,17b60cca,b5e12b5b,1b295a18,16b92c5f,15b88bbc,177dc011,f6ef0760,15b5ea47,9bca876,ae072070) -,S(5e3ff13f,bed18235,fe28dcc0,72f09cfd,41394cd,a9a3aa52,5286cddc,e56acf05,c1488c2c,903bff6a,411697f4,44e6e72,6ed9c0bc,5aa87cbc,ed8f8802,6998fc7f) -,S(54c8aa07,2f1fc5a6,ade56cef,d7c6aae4,846f6855,34912868,b84b195f,78bbe14b,ef11dea9,5cb01680,e7205f1c,62aa5242,2c0db969,9b2a0202,966873f3,1fdff34c) -,S(bc69e00d,4118d8af,baef7647,6e435883,2ae9864b,f154368c,e2ccdadd,c58cfd9c,148aea9b,2babfe00,3a6592f4,d3788893,5be42ac8,a50f68d7,ba2cd738,47dd9c52) -,S(50ccf184,c0213602,af114924,fe100f78,1f0d0cc5,beafb671,9dedea00,c7c3ebe2,b6559878,d7c33082,4588dd33,3054c4d,2da86b8,ff23fa9d,6413920c,d876e36b) -,S(c24ca0a4,8ff2cbb6,235ef33b,42ba032,386d5475,3cdda799,e9bc53c0,5c299aee,8555bb16,bf4d7bb7,5c0cbdc8,8594454,bfc819de,72c3954e,76b65780,2be28fe4) -,S(cebc8853,3f6c3a01,58dfab12,ef52b4e0,a7473d1d,209b3585,bc94a13f,a83abf17,42fe28d4,136bf80a,7149a0b,7ddce53c,45e23c0e,7be85fcb,73c0e66,2c4c0593) -,S(7d921a84,65b11feb,7a755a4c,5d96b6b2,f17e07a,95db112d,48c03bd,18f61422,f0ccffdf,7f04e350,13ae7f36,411dea5a,ef69f220,790c37d7,354ce5e,83925f4) -,S(b6909fe5,6824e868,f4cbdd10,d3d00ca,23e5b4,35c78aac,c78a9a1e,321d178c,3d513c55,136d61b0,73dec253,e1ed817,782d9f76,b536d3f7,c3b0d1f,d06e6c1) -,S(5a3df3e8,c78c0fc,56971dea,ced3a6ea,e1ef668e,2485bcb3,d4e24408,7f53cb74,960721cf,316278bb,56bcdd1d,9f3385fe,8feea6b0,661bdf1d,44771067,661aaacf) -,S(dc65c06,50cc30e4,d759fa93,d4d0ab65,5cb16591,289206d8,7a988290,20c22f9e,be39ae0e,a41a81d0,2175dfd5,5e004e19,fa925a99,2166d862,296899e,2532b6a6) -,S(f659d02f,f2d4bc82,9f816525,24019a88,6ad539da,3f38b083,5d8265cc,bf3a67ed,bc9c7a81,9036c702,338c57ef,26134647,2a22b8cc,5543f4b4,4a4f7d4d,d4339573) -,S(b89bbc05,420a8a65,aa03441e,da1c54da,9ca84f11,e85a393d,47cc54b9,78b8e5c0,5f3a2fba,4cef4457,ca6befe2,7dd3f9af,a5d8b6de,86679eb4,c877c7b4,cf03c08f) -,S(b9bbb789,690b53e6,e42266bb,853cfbbb,f6788b58,b325097,a55470e3,d4cbc3cb,1f984f38,78427212,cbfc8a93,8c1f0d87,59792ca7,17635c75,71b2c4f1,29e35c2e) -,S(d8ae91cf,8a99ef6d,2ca0c15e,3132974,33cd46cc,55a2c8f3,9f909e96,7d50006c,4fe4696a,79d2f269,9fecfce8,8375cc1,81c2c2e5,4109f380,3377a020,5496d733) -,S(35dc2c70,181aea7b,ccf6a15d,1f708c87,cc8bc5af,93671c97,35867367,549357bf,6f27dad,a9abbe5e,5e59141b,78a2e6dc,5b5433ef,dc8c9cde,a6269c2a,68346f87) -,S(a4c042b7,d54b67b5,877442e7,2e81de4a,7edbe667,f00838f2,34f567a7,9e3791af,a8c6f7b1,6b23a9cb,64732852,c9734547,69ef3e4b,9165ebf0,a1dc4967,36c73242) -,S(d6ab68a3,353b6c65,3836b66a,8c39f2d0,892cf856,90ebb56,a5e8e4c9,e669da34,4847a9d5,f39ea1e0,ce392c8f,9e63e88f,8f3feb9d,7b2a05c7,23a932d4,b07e38e4) -,S(e161c34e,644eb3f4,fa217d33,dd3129b9,c2b85ad6,40b56e56,e20982d1,c5483d43,ceafd0af,a8cf7a25,be092307,22c30e41,b6ea151c,d027326e,5152aba8,d9a50749) -,S(94959a2,fdc2650c,b4b0219b,83ac99c7,c477132,eeab585c,1fb262e7,6cca22f,6243f3b6,ba7d4f26,24f7b7d5,8e070b2d,64610aad,b281b4a3,b93b030c,ac0cdab9) -,S(491129ee,3130c2,f262c4d0,a1bfede9,e470c3cc,8e80774f,52ea023,67e2e3de,c1e61e2,a5310866,762a0cf0,ebbae0f,738b9527,46001aed,a991e0ee,d95f0db5) -,S(e2967539,b0b29fee,a668eebe,eb8e47c0,1ed84950,a1f9fda8,6884a421,5ab6f265,c304cf3b,b7faabe8,cfeab6b1,b88d3d41,7e950963,745c2479,85211d50,888346dd) -,S(d90a380f,5283132e,7d6760ca,f2b28576,49445507,b8e8872b,d0e1d5f,56a15af5,97fa0739,7a1357c5,e24d0a3e,ce608332,107e41f7,c65d3c6b,98ed66c3,af30a4ed) -,S(cb917a08,153599e3,e531b1ac,63fb8e71,fcce572a,29fde1b,17de843,a99ea2b5,701c08a4,a9da11c9,3b4be64a,6832af1c,900ad3c1,4b4dbe70,c62e3e08,55b41b6d) -,S(e6ee53e2,98efb026,bce900e7,8d31f3c4,539108bf,d4c5139,16417f8b,49199a0a,bedd41e4,751f657e,8cfc65c3,2a82f981,4b223e62,95ec36cd,da5125eb,da736429) -,S(5f777c41,f4e3441e,75c66f28,852e7815,59d0f3fe,b8b05b59,b6966fa0,de84df2a,7fcc66b8,127d26d8,e0ff69cb,b80acf44,bae5546,edc9bc52,90b73da3,447a2731) -,S(16d312a8,1295ab9d,c08f9fbd,61e6445b,5ef1dc51,fce19d,89f04e7c,66ba2e07,6c555fca,2a1d2f4a,24ced2bb,c3966f4e,1bfc1912,eca39067,503df586,41a4d4b7) -,S(660d3993,fa887e1e,8b05d80b,96e2b70c,341c3ba3,351d2562,5792acaf,3859de3e,87b06f5d,4c6f854a,8714eb3a,55454346,f931c21c,c77da23c,2d069d33,7dcf12c) -,S(9d45e660,879b6e8,b8007a8,ba7fe7f0,c7090cf6,9c733bf9,43f4eef9,965a1ae2,c81a3fd3,9b6b83ba,d163c763,f3010359,ac050e64,a47167ae,2ca41345,c7d95662) -,S(c95d92f8,c81d15fa,a68f645a,c1ebebd8,57c6942e,e75ba13a,3a4eb9b0,c45c43ba,2f55ceb6,c1de7877,7b322a91,7f3e48d9,480b80f,d49e362c,99f8104b,a20f392d) -,S(95d445ff,e8cf8240,fc4e9856,9d41164f,50e9ebcc,1fd3bf19,d4309de3,34b4c97d,7c391704,a75cffe2,f8971ddb,417e8158,f97a3688,6841f02a,c4b699b8,df6c0d32) -,S(40f028ca,907d6521,df1f052f,ba5268f9,a60e705,bdf94328,17881b44,1500170d,4eae26bf,37d04379,126ce777,b1fe1115,8c34d077,bba66994,78ede7e,244cc8c6) -,S(dab90c34,e7460068,d80d2be2,2bd81f9e,667bbd96,4e30c23d,3eaa7a75,a61e862d,cafa2892,5128bf3a,4821cd14,8503ca8a,86f06388,d21df6ee,af92d514,e66c5f1b) -,S(6df2280e,381ef8cf,922505d6,7646c1af,105f91c0,59e8e7a5,3ae2e7e6,cb456be,d94a020e,7776b713,b31aff5f,d72be6c,f29bfe46,16ea3d29,95913db4,698ae3ca) -,S(a13d83d1,3c60cf65,cefc8692,f5d339b,2873582e,938373cf,3e4df54e,ae32ffd2,8f511212,a65d8963,d7df7ed6,27d87fd9,208f83a,1a4dd14f,ab0593d6,38ac71d0) -,S(ad4c1ec8,39950ae4,a7fa551e,5aa637a2,e5d40bfb,3fab696f,ea886a4f,40bf2167,fea9b599,202841d0,c3afbf08,ef1da210,cdd92a4e,6cad485c,a0d5275e,8a5dacfb) -,S(64188be9,af657254,1314e661,848970f6,35a0b6be,7e594824,6dcf36d8,66840610,58880b5f,c3df9b6a,45b49ee6,b90f6b5f,f3fc440c,37855167,a30ac013,3d48e53) -,S(9b71366d,a66b165c,6495e4fb,46ecdc15,84a193ca,d65ad8b3,7a01a3b2,cf2e43f6,d7315165,ecec296c,4b71a860,f3b2f0dd,fb9447ed,5c59a458,8b81f679,34321301) -,S(4a3c5006,74814f95,9e9c7726,595658ff,84e369af,636f6aff,ab579bb8,5583d395,1b495757,1a302c2a,d1cbe53c,2ba34a6d,66bf1aa1,8bddad33,679e4890,5f9a21e9) -,S(e4305e5f,72c43558,79a749b3,d563d4d1,dca704c9,c8867d01,ef503cf8,97c90034,ee563dca,4d31945f,c536a318,e9297d28,81954b37,af992722,9e4e0e9,1c16244d) -,S(3aea4eb8,ee74c9d5,2259f37a,da33ae1c,78f5dd8,d97511b0,2e0a0201,82840a8a,8fc58135,757b8c0a,a8f2c2ab,ec9d9152,20ad2046,f429667c,c4586765,10e93e87) -,S(58e8e94d,e9f85066,7cc4c61d,acd212f4,77454942,33deb015,858e500e,9530228d,5a95aa24,fb782a4a,e64e155e,eac2b644,cd614315,9b46db6c,9bb4fe4d,5e5fd690) -,S(6642c782,7e1df912,ff54dbf7,41fa1567,3e9c3aae,5e7630c6,9cb74b60,c070af1c,ff338a86,34a404c0,cb26af9f,59df36a9,e1a848e1,ac178b25,c37ac177,db45e947) -,S(c5c69fa4,65c79a50,a98996ee,cae55474,5c544a3,ea838a42,e12a733e,9181b30a,6e805461,5a424a9a,1fc229b8,7e594211,697386ef,189d1ad6,ac75eaa2,5727253b) -,S(f4faf099,fb16a1e0,e5f64428,5317d91,a31daeed,fbb6a6ec,b70a213f,ee95217d,ebfd8445,42fee872,1f721f3,11ef28e,30618bd1,bdd097c1,ca573285,5b079734) -,S(773b3e69,fda8abed,fa61ef37,57101756,9d9d2a6a,ebb4fc5d,d9049d56,9c66b76d,1bc051c6,302a383c,dc0756b5,114dfc69,1dd2180a,88a4ea9b,6acebccb,a59f27ca) -,S(bcf80e7,b2b54cf7,971fae7b,db8b3826,85acc1b0,f987f352,d9b0b3c7,ac78142a,20620b00,8c010ad9,7a98f093,8d9a381,f9935d5d,4bc9b060,af2ee6ab,151eedce) -,S(865dff30,47f31564,99337316,ea20223c,5967e034,83d92d54,7486fddb,fda959d2,2b655c9e,37697f10,5535b736,a31b2c6,7f5726eb,602f1438,f808ff62,4bac074f) -,S(e48e0e18,101eef40,f351067e,63d2b34f,4fce76c,d204d6f8,85d2664d,fbc92d3c,594061c,8d3f4748,bff85cdb,f70a4035,5ad826f3,46d44aa6,7eca3196,e433bb65) -,S(9807e350,7a03e134,9bca9101,cacca5d1,a564b647,8c906619,61ba503c,5ee15bdb,301e68f2,d584b1fe,3eeee7c5,85cb4d0a,26621bda,229589cc,2704dfa1,1cb8d927) -,S(95f94e75,8602dcd4,60ded52a,c9d7ab40,1fdf1405,b271acb4,133a86be,cfe5027,f08d34eb,e9cf1b1e,78e1fbec,452e1ab0,412c642e,1328b2dc,f5e08b08,38aa3c51) -,S(7ffa20eb,ebbad406,deec68c6,9bdb7b0c,7615a56f,5c62a646,a57535e1,68a82a31,230241b2,3dde374f,7a039eb5,5181e954,f0472056,79edc688,7c4ca6b8,778333e4) -,S(1dc7e0b1,487fbb33,d1ecdf84,7bdbfef5,f7df9f31,d07ff024,be063a51,53eb5498,ebcf72da,18a1a55a,5aec4aa8,efe09407,263a7b36,f09552e,22cbceba,7a3cf980) -,S(a8052e02,e39d9981,2ac6c4e6,2cef526b,9cb29843,127f2227,50a8021f,4ced5cd8,9011f0b4,9dad7e5c,11222b64,c5d8c9fb,297d9afd,c683f545,849d833d,f2697220) -,S(3edfc4d7,f1f699c2,8e8ac2e7,5cd93e69,fff31607,d99a8195,30603437,f9bfb20d,f901260d,68c6dfe8,aef8879f,ea1ba009,a1e1d931,fa6ba39a,ce1e2673,ba759311) -,S(fdf8ae7d,c10d01f1,c39bee75,3be3307b,53307caa,4af0e8dd,9de7d696,45ce527d,2425a3f8,c6147073,3a44d3eb,eff3d8cd,61e5fd55,ffdac357,d7906600,153a8dd6) -,S(1cd5ba80,fcfc77c3,d06e230e,e7ad8ff4,f9ee6c60,a71d37b8,3718d8b3,15d5a4e0,f90ac118,30b963ab,fc64492b,415db7e3,47eba55e,d2c5a64f,578a13ea,b4435cbd) -,S(3cdb43ea,b7afc936,24b80269,18319fa0,e75de21a,c0587af3,541e492f,1510257b,49b6411a,c74a2eb3,ac2ec784,feface51,8d5a5bd6,e76d694,bf5ab8f5,c146abfe) -,S(165b6f5b,9b1e6d08,14e44cc7,c7969297,bba7c659,58dc3274,7e7c4148,e30c09da,e715e411,2e6cb67d,cb8e1ad,997691f3,bd6119c1,3a5f0329,1ea3928e,35c04551) -,S(d4c1190d,da3c01cf,6c75fa06,7b4dd1ee,e645a0cc,8b034f4b,24580661,8ced0bff,c837ed81,b6a0e5fc,6a02d6d5,f837db1a,20eee55b,41ff531b,9bb642d0,52c42bfa) -,S(f7359bd0,bf7db6b0,48f1a040,a0163fba,285780e7,909ab689,7963168a,a7de9c29,8c71bc3e,95ac0f52,54db6192,5c6f9112,759635fa,95846be4,6a28573e,2b25562b) -,S(4d54a2f6,dbebbee3,8950627e,8cf2c65,6ca071e7,86687f3b,a0a77178,be14c55d,6579dace,73dd14c,695fd781,218786ee,bad84445,ccd910d3,43aa2478,f5576671) -,S(f70b532c,e7203208,d6440bf8,55e1293f,cc6ebd75,96a04b27,9fc056e1,2ee32dee,e9d18f7,126ed56b,4a657104,2441bc08,1778736b,91062c9f,cac28cbf,b8737be1) -,S(bbf3ff3e,577aaf34,157e32db,d977b907,e62b16b5,1ae0abd4,f14e71fc,cca11357,cc1a78ff,44af7c2c,cdf17423,9b3aec17,b660ff2e,fc07953,2d9f9d6e,55d3abf7) -,S(53bb2321,b36d1dad,226ceb24,f55d4292,be245444,b2349611,5a649560,59729700,a5db4fb9,46c4a2db,b1a634cc,4032b7b,cf23f7d1,717a0ee9,6c02f131,24f834b6) -,S(3b863ec5,5e4ff2cd,d32cbc81,6e645009,da444255,9bf96267,2cd012e1,15372186,914682bd,d6a052bc,25cb4d41,e9bb28ed,76e9aa55,3f5aaf25,75140e04,eca69fbd) -,S(4cc4a750,d641c574,5c68a48b,953ee51a,258239b2,fda1f5e0,80831417,7b837946,cd6f665f,6f32246a,1cc8fa61,4da2783c,f4c7b92c,4f42749e,b6bd4a8d,8a84c54c) -,S(6f9b5d79,efddf08d,26183b4c,d6001d6b,fdad9e8b,dc5853,f3a8c47e,7e6f9e96,b81148f2,1e50152a,8cd7727c,ad14862a,37fd186e,2054d4c4,a4cdbfba,a9076991) -,S(9e13d0e0,44cd3fc1,1c7596f2,9946313c,918caa65,bcb6387d,361eec31,ebaa6977,c5f55650,7691bc2a,b2c9e4b8,512f7282,24276490,257288c5,2387fee5,54bc9c0d) -,S(a4441292,d0e0db3,2a4f33c4,8bbc5fbf,d40650c8,d9f5c4f4,88a1f69a,d71571bb,a23ef48d,38abc24c,608dd688,d524bed,a3709a5b,3567ef3b,e43f0240,796b7ad2) -,S(def598a5,c4828c5,16b7076b,9682aa82,4e74ab42,e4d4692d,17c8f289,67f3cbb4,e6b4bf28,6dba0803,e4a97a1e,be55a088,10660466,3d7726e9,300109ee,a1d62a49) -,S(8e991fb7,372df8d7,7b09436d,c9424a8,5a14888b,583b3c58,6d2a19e6,91e75b67,1780f6e9,b8379b0f,ebb1328a,69a96878,9f58b45d,8e3ff218,81d753f4,8ed6c43d) -,S(bae09288,e10351fe,fa0b0971,400ac3d1,a7eed65a,b11d1ba4,8a1c6240,bb981114,dfc2979e,dcc2de8c,abd9abd2,27cf7351,4079d950,aba60e3b,f4c775ac,72c30f4f) -,S(4d09ae3c,b484fe27,411d4142,e41de523,2c54c42,b387c7c2,cf42a23e,e7611fc1,b94fa116,27eaf5ab,8fb7fc25,1345eb28,8f5249e5,ec65e056,d60e1294,41481375) -,S(32f57ac4,3cb29fb,f8a00d8b,c95da8e8,3f0f541d,ed6c9e78,8af17a14,6a2704bd,2a969b58,9a3f9a5c,26b51ab6,1a5717bf,c06eb438,85e4f4a,84b903b2,da5bbf09) -,S(595503ae,e179f59e,bfc581b8,7ac18e1d,55b4c794,87d90d62,492d3ea1,1ec57579,1f25d8ba,e38c0a69,50a17836,a842b418,b0f7c317,9486fb16,9ba11b23,d315ada0) -,S(5555fae0,6f1563af,238184c9,304e26ef,f8b2121,394e6856,79de6792,31a56842,6840bd14,faf202c6,60650541,48bb87,df27b979,4ec0da66,9ded6830,b0623980) -,S(714321ed,2f0432f8,a05c33d1,84619de5,f81fb8db,95ab3121,c24fc998,ab9b9ca4,4470cdaa,7067de2a,e6678cd0,6d613e19,35b1edf3,bf278205,da69ee8d,6086c2a7) -,S(d41b84d5,9a0085b,86e88fc1,499151da,b0b9a574,92b01df6,36cc2288,313bb592,c04c54d2,57fe5ba,691f6023,bd72edaa,20e71a97,1a760bf5,3c990a39,f5ef7c23) -,S(ae34a065,b42f5158,e6a5b91b,9ff54b0e,6d5bc906,f6d18c3a,82865e,e9038f34,bf2c90fa,30639811,2ca2ed02,b7ad090d,8bc990db,b6140a05,afcdc80c,bae8490f) -,S(9b3c2682,3050a52,a164ab,f4504ca4,7750c889,b6465f95,658ba7b1,c279139f,ee36938d,8a675824,51ca289a,55265606,cb9ae4fc,8cd274aa,41db5ea9,9a5b4299) -,S(27dc9a57,999ed109,c3dff978,58d44ab2,73987af7,b617e9c,766331d5,c06e0dfe,4e97536e,67e363c8,add07030,d59061,33a726de,38dec51,e5a20009,61ee0fe1) -,S(c3415e9f,9c823521,bad3090f,f2c48e8c,647e438d,70397e5f,7d7a6f2,b7d7d4b4,8c3bb607,c746147c,d5efbef,7e27d236,c4063116,89794cc0,40c235b4,6af412d4) -,S(f47e44dc,90c8bd2f,150d9dd3,e4922395,14990fa1,f2fc361b,a24f853a,b37e33a0,f4282a26,bf5f358f,2dac4956,8bcc15a0,d7eddeee,b43e6fd1,8f35d5e5,4295ddb4) -,S(3cfa945e,6044ec2a,da895f9,9dc24575,deee57e,df8b1a10,a2d2ece1,9951a812,d0ab59a7,46ac6edc,69307a0d,caa00aa9,e7b73897,b89185fa,9dc3899,ae7e3664) -,S(29df8149,9d83bd0f,8fe61eb8,8f0abe0,96a75e5a,2cb0a0a9,76d8d27b,6533a4ed,7eefc80b,63f927c2,e905a56,62d5ed34,e9bde8ff,4402491f,19215c9d,494e62d4) -,S(eea85a80,566d13bd,da65f553,b2077607,c8b9184,6a5a8096,f57afe93,ada9fff4,b5389645,fd772da0,1cf3b535,6ec40279,cf76d812,11f20a16,71d7ecfc,441d71bb) -,S(e1a69e64,4434db7a,54550d44,adc43682,c128c560,3907615b,9282cf1e,e2b74f82,bd434a85,984a6e64,441134e6,d1f1a3a3,adeab658,c29af8b5,4bc42667,634d20ee) -,S(2d99f69f,a7e9f3f6,6a53eea4,381a4c80,ed17e8e1,4507d7f,4a80ef25,293c5fba,25a6aff9,a23a406e,9e34ad6a,21627acc,96b6ceb0,7896382c,833b8fe4,8e603e0a) -,S(d2482127,1554a14a,7283dc8,1ca70179,42a35cfa,c8659b2b,db78c426,51807cb8,a252027f,3fac319f,c767652e,469421b8,d34decd9,c9042d58,f8aa0ab,70e5ceac) -,S(bd030cbc,5f0de61,ef194eac,38f7443c,d231f75a,a0b568c5,416c5b8b,917545d,ad0833b1,4f1e23a,76c0626e,71129455,60fe62d7,4b3a1b95,69e4887e,c0661e78) -,S(afb44b49,ef00b1e9,59c7a864,19d2a4db,71d9bb0c,4e1746,9550d39c,9a37a161,eee390a9,530a5baa,5350019a,f756185,8038c2ee,7f78c365,dd6f62f0,f0589aa5) -,S(9e584f1b,e06ea4d6,5f8dd96f,206cf4b,88aec6b9,ccf06779,53acf110,99e2165c,6994ce27,46b0eab3,d8608ef9,33b61339,d3e589b,c2acb7bd,aba3af72,b082fd24) -,S(d2265b51,b4f7f4ce,1d0966,e7012f9,76433dfe,444b2351,9505b29c,d520c6df,44414498,df439478,328b330b,6f8c6876,682b6a32,b5d01355,2494286e,a635bf65) -,S(fcd56867,58c797c8,3aa1f1d8,a9ba34a8,8e624aeb,666507fe,706b310f,3342264b,680e0b98,455f0e64,94622fa9,e36f76d4,863a9fdb,a3df93af,c688c45d,fdc5967b) -,S(bb9a0c0c,74db0525,370e8235,9d733aa3,494afc03,fb61a1b,7c2536ed,9903fd91,239929a2,1c0ed586,b9bc8f03,af422994,f81619c6,b2fe637f,a511c07c,d9421603) -,S(2358b078,1989d6b5,666d9158,2fc640b1,13d52e61,ea2147cf,a0a103e1,5ae80db0,73f84f47,a78fe2c6,e4d01d7e,3dc10065,e052401f,64796358,c784d59f,742cc8f5) -,S(ddb3409,ce3184a6,d9d7b4c2,cbdf32ef,ebea1be3,595ba19c,42933882,237dae94,59215423,3760cdf0,513442bd,2fbef84b,9c8c0fb1,ef16fa31,783d4dcc,50f24f24) -,S(f99aaa8d,8d42ce59,86ee8ffe,d4dc8a48,81810a6f,cdfa9519,46f00857,4ab1c3c7,d0f29fd1,32bd65d,7f9820b6,830a3e42,8664f9e3,9cb25729,1adc36db,4e177187) -,S(83042093,46ced0d5,a33f491a,c98aae7d,51f17ea4,1e5722cd,29c47f15,49c183aa,1f680d05,ca015018,664dc767,4de0305c,b09efffe,e7b164c8,c733d2ed,18c15d8f) -,S(339f95d5,5e293243,ec10b3a9,a8dba385,dcaa23a1,bb424bbe,4c894deb,c61cc881,3a4ec84d,67831768,e9ad1d9d,db82f785,52883fd8,b0b63bf8,38495a4c,455d5865) -,S(f94de87d,1123f6b6,97d4536f,7bb6a995,ff158060,b7d72b9b,3c9d74c7,1afb6009,f123cea4,bd4859b7,a852270a,17c76c06,e6050a26,9c035bf3,6c505fc4,1fa81066) -,S(71341ad1,bbebbb4a,17a7701d,30dcbf7e,2a70b901,5f6c5ff9,9fb614c3,d3338fca,6ab14a0,4b4956d4,a687acaf,30d7997e,cf70df2c,b49356fc,5b86453c,5ef6d55) -,S(79b8571c,f52ee30a,4d3632d4,965cc6f4,cc6ea06e,fe1cb7a6,ca2c9c9f,1e835bfd,259c0c7c,b8fa8345,57febdba,2183042e,78f8cfaf,24a41dd8,2eb0ad3c,426683fa) -,S(f3ce9dd9,d879e70e,21737426,dbbb27c9,7af84307,6855bf4d,af141d55,5006e402,302a436c,f8be3a4f,dd70a9d1,8f63cc8b,ecd3ba1,ddc9aa3d,f4285239,61e7553d) -,S(4a66f7b1,52a8cafa,78d0e98c,2f8361b9,a0bbad47,d23b24f,5184477b,e90d6318,7555fd5e,87676154,8f7afd4a,33511daf,b3bc4a72,c9f54d4,92327a2c,c235c02f) -,S(cd3b4037,5cd6da61,ff432898,fc592175,c90fbc31,373489ee,c988f280,3459bba7,b0e86ab2,2f2d8d97,5f68a7ab,3ffa3be,511390df,5b647608,fb07f29d,3155728d) -,S(e96f166b,84d98bc5,41ea8885,f7a48612,227bc907,795782c5,d0e2325d,96cb44a0,18ac220b,8def89a1,e3bcc2f2,7a66c0ab,3ee27c3b,882dc16f,e2571963,92b94310) -,S(87adb3fc,7fe6b07f,795bb7d7,ab8383eb,a3f91564,ce89d267,599657b6,9d793838,68677cee,bc7b3d09,efd0f118,d392d0f,d2d5f2bf,f2b50230,e127acb4,97f5c886) -,S(fdaa2f5c,ad1da3c6,3d241a7a,b4365e63,8eede0f8,229a8187,6cd76a3a,7020c545,5b04616a,a1a84785,c4315dda,da6289bf,e57cb9e2,80c42395,a1b13d69,dfb2ddfa) -,S(7eafa986,1a94fc8f,d263cd4a,1e481e1e,8bc1a385,c4ab748,8715b032,3bcdb52d,d655b395,607bb0b,c9092364,803798d8,17a4bdc9,a30e2844,94be8322,42af9949) -,S(a7fe4656,98538c32,844337ea,bc90fb49,feaf2fcb,8b86da6c,d173bf9a,70e62a53,cfb26d1d,689a9075,55057ab0,d4261e2c,acbf30d6,cdd09f95,9cf1830e,5d635aad) -,S(8bcc3b82,d543f365,478fe32f,dc9860f0,10d51f74,b7b5344b,ca6b868d,3c11264e,6bcc32,f7ff3e48,fa1775da,44b64848,f52329d7,d8bb0a09,338b799d,7452b4af) -,S(faf9aa3e,f1ccd659,2feb2add,a1b58ed8,27511b39,bb981cee,4fbe47db,5cab2917,854b88e3,50a6e9a1,fc7e9e45,f3fdb69c,8111c654,877cd620,fd82ee18,ba2d195b) -,S(77012901,ea269067,4d8b4397,e8976f98,e33b1709,c81624a0,7916da35,af75cb29,b63695d7,cc896358,e119eb98,7dc0f67e,22a70c5b,5e6e2072,e61ef62f,9333bc4) -,S(127602ed,f5f1a04b,813e2b6b,2c27f50f,803b70b7,b9525b7d,902f348e,c03591a4,1f791f7d,2427532,968f7a08,f94df6be,a95b7e6c,5490fa9b,5eb5a3f3,207455ce) -,S(17e82c3a,3731a73b,36501eaa,fde3ee8d,ca9f2573,dae1e4fc,594cee8f,e1d19179,8af04092,79792fe2,273e3f0c,e642f3fe,edf1ffed,59c5826d,a7fb2716,ed365a3e) -,S(3c34e27d,5d5737b7,78e968a7,fe8e4113,f802bd30,1e0367ea,41fc8b5c,14b0dd84,67bfc61f,bbd062ce,6224e883,9092a962,eb3105a3,b6634dcd,d59c61da,906a4ce0) -,S(b7a35907,c7b55a8f,7173a5da,c73e306d,64ee0f6c,cf4f5c76,3416bd4d,4f5359f4,d111c21c,e5a8674e,3a64adbd,4f56b1c3,61350b,44a552fb,19186b8f,95ed534e) -,S(6c7d4836,62c28812,7b904cc8,969ff925,8d9fafae,e88f6d3a,e6e4d771,bf8ee7b2,b593dc47,3c29694f,95b00169,286e3981,afeae4b3,dd7a788d,f32a14fb,6e6a8e7a) -,S(dfc406d7,625719b9,4f709993,c5d15062,4c725ef8,eecb2308,bfeec0b3,6050bf4b,651c0d2a,fb29eab7,d4740b5e,1fc2c069,54ced865,7a6bb980,2de8d873,a451717e) -,S(1631fa0f,4e9fdf51,a2842994,da94f835,52b5bb40,348c706b,54079073,665c6bfa,de202803,9a8d1ba5,b133ff28,6df237d2,a8d73343,a08e7c2c,4560954b,eda5ade7) -,S(fc52b3a8,8f712053,2c7667f9,62146d40,eaa3e924,327d959c,a49b74a7,da11e5f6,7bf890f3,daf8f9d9,49e800de,8a3f5458,5aa46e2f,25535cdc,18170391,e2101daf) -,S(6b7036e5,c5993c6,8a744776,abb0b5b3,31a886b4,93e49d41,bc7d93b2,28566fd8,6ebe771,42a56189,f272b6e8,8f70f356,ed1a3d37,ea2d5e4c,998e47c1,319e2ec7) -,S(b13dc5ee,7333e3a,4b13628f,7ef96ae9,4faee9d7,3a46297f,f1e357f6,e7a57a48,4f30b474,99c66456,33f5b521,9164a890,d8cdb78f,8c7ee211,1bd37fc2,d41bb2bc) -,S(1888e944,6fe20426,d4fd677c,5cf1043b,605e93a2,c8532623,b5951e22,34de08ae,9e1f4fed,d5de001b,378ad1a9,98e31f00,30af9674,c383f287,50172e03,ea0b0f81) -,S(2495b334,9884d5f3,166f8fdb,7ff81f9,9042383d,def7cab6,3c2775ad,226189f8,846850e0,2a1cc051,eea77bbf,d5f44499,673f40c1,190e379a,9b37201c,51a06e9c) -,S(e4c0e483,f21102eb,7dd2a78b,5a605b8c,410bafcd,f2ee4bdd,fcfe1374,ab32d17,b53fd34,568f5edd,a6a3abaa,2d2c3a4a,bbeef0f6,c37bec1b,fcf012c3,dac15b9f) -,S(8f9bfd7a,2e798812,eb927fc2,b0ad5eaf,81a0a30f,a97efbee,a1d6d9ef,19348a5f,1eec535d,1bee520a,13a8410b,6f3824cf,7c9d5a82,8208d2ae,dc89fa13,8bb7c2b3) -,S(1d95c760,f3fc2eff,df51cf0c,4b708538,efb56675,eba3ff8d,4f6abe65,d3f167cd,c2bb1122,5016ffe5,6859da47,4b777703,49e4e655,5da3d9a1,6dacbdd2,d42ab0a0) -,S(9df72bbf,fbcdc42e,adb71d69,1791f073,7f945e8,bfbf4e2c,68c5e3f6,5f6955f,24d47aa0,1626b0ac,ce77827,fd7daff,7424d4c7,1d76ad3e,b66d22b2,6f7d1df9) -,S(2df6ef96,7c0e1a41,2bb48bdb,f2cdf8f4,22829abb,4b7a42e,95bd9cbe,8b7f860f,bace2e70,7915069a,bdecd097,9d133cad,bcfedbaa,7eb9891e,ad3380e,9ca99401) -,S(82bf2a99,624e408,188da19,59599de0,eb947438,fcd45784,9a731a1c,15796028,3b6c668a,e5b8f394,3ee713c,a8fbfde5,8ef0f9fd,84054a9d,b626e274,37e611aa) -,S(60260fff,1f213916,9261edeb,5f1d2d0c,a143ca69,400b2776,21793c11,fbc89d41,bec4bfeb,9d09f8d5,cdb11e3c,f65c6a7f,d4aa87f4,e41d7f4,69717a64,5dcf9945) -,S(6391ed61,80cc46fc,33481faf,d21151f3,cb678e3f,4d667748,1a24a01a,c5e9180,c48495fb,fa5962b,44bfbc4f,491b89a6,a8588fe,91677b19,b872dea8,8e34026c) -,S(20807816,758361aa,d5f62d25,8e3951c6,da518890,26507a7b,c0ceb7f6,a96c141c,8526d53b,61c8427b,eb141d91,7a338fe9,f7789a60,cc1a4a62,15dc754d,a73903a9) -,S(1ecceb4f,8acc649a,dbff29c0,fbc62c11,498c7cb3,7d29ed15,e0ebdf03,e994b67d,1c701af7,a9f3d870,81efb798,2382bed6,5d56b8d3,f050bfdf,6da32b10,a18fd4d4) -,S(be82742,dcafe3ca,f646cf01,80202cb4,7086e0f8,ccea3c11,dcccd9de,aeae688d,236d1fd2,5e05d6ab,8651d88e,33d18a3b,caa66c06,b2b68c50,f6158717,f23b4866) -,S(15252ce2,3f666836,dfb47b60,1e642abf,6e56ff2b,5d58fc97,ab09f29e,1b4ec3a9,9a6b2658,f52dfc45,32e6b482,fe909e47,ba7b4442,3be4d474,a524df32,d6149913) -,S(b0429186,21f94599,f7032b4c,1b53bc6a,9259f142,27922f42,fe774772,4b0ee9e7,e73c32d9,ede68eab,e77d681,dd4cbd9e,a356fdf3,bf066f33,6ff2c367,59bed08b) -,S(5fe0917c,1bca66f6,f34bdf1f,dad88a5,b3dc5f5e,2e0227e6,5f3a79c8,9e66c888,885dfcee,c0947b01,71dbaf65,52c09ab4,c0414f8c,7373ec5,e3080521,401ed575) -,S(455985e6,44d9b679,85980752,a13a3f94,94bf9cc,8e6f10ba,fc7a70c2,27ce272c,47eadad3,15e88a99,9d3f5ce7,792ebc10,2fc68f18,cdfa1df,564601f6,3b26c22b) -,S(3562aca3,2291c1cc,ed072a4a,85fbf82f,6b3299f5,2626154,2b41840a,1c868d4,ab4b2656,11db5875,10c48284,7f72c75e,f822f46c,2e7760e2,a46070eb,5db7100c) -,S(54225801,f82406ae,74416373,7408e94d,d3990eb0,60581c47,b453a859,cf63042c,43834935,a6a7acb4,9c086391,24e80fde,72c0a876,1c13a340,1a4e48a5,d96f6a2e) -,S(3c253039,fc8278b2,8135e21,700af1e4,dad4263e,ddc867cf,a3532499,c2c1e48e,ee01ce7c,f8c56c74,1b4b3593,b0cb90a5,9c59cbe6,9a48235d,1295c1d1,ac657081) -,S(8adead1,d898eca7,9e043f71,aa735a32,763f75f6,f6ba7a70,bc47a284,4b580972,7a370bda,412df63d,5590b3da,80365c71,1267cf8c,e3fdd1bb,91ddb981,d213bcd) -,S(8361e522,34c8d62b,9051a95,8af3f090,4f15ee35,4b69a560,7155ea4f,69548037,ca2c329f,8cb65e8a,eb6488f2,2131c525,29df97bf,c8847c87,47145767,7f82c954) -,S(97d65162,d96feb36,e8f00221,52c92c06,2e97087c,703a9dd7,7241216,2262807,15a260bd,bd591c7b,91bdcbb4,c2684545,4706f039,8fef8de,9173e7fc,a3f31f44) -,S(2609f072,5ec8e5ed,4ec86128,dcee3baf,9e62bc24,aedbaaa1,eed8dd31,c9c07503,d51fcfc2,55398507,7e471397,ece94d92,e26375d2,2bddc0b0,d1b780a9,65caf2c3) -,S(820e8f01,5b4ec57,b884dd3e,6a740d90,68fce86a,a4833636,4b65ba6e,9e272357,bfc87d52,eaf352bb,91f071ab,6e986308,4f197671,298eb614,93152f54,345ce5db) -,S(2116bb76,7a56312e,71ac58f5,ff2a7071,1be5b711,1e9e56d9,aa098af4,b991db0,2ebd4fc2,abd618d7,d1798739,7e9b8eaf,8276086c,2a5066e7,e7525603,fbb4c40d) -,S(e43f029f,97f4370d,65826870,3f29422e,7b81112,61364972,e26892f,77eed56f,4e265fe8,40524def,23b7ed34,54c6618e,ec70d3b1,92ff30d2,1b9b6fc,b1f7164c) -,S(9b4ca445,5cada269,2a77f7e8,9aa3082f,ace4de3,898408eb,6a7d1cb0,8ac15c14,1446e397,d1c3fd20,283f43a8,4679e728,64f05251,b1d3bead,58aca70c,4c0fcc29) -,S(e2abb09,c0566f51,7947f99b,2d6fc4a5,637310b5,5f9d9014,84decbb6,ca22cbfe,f334bda6,a1d9cfa8,2b18f8f7,e90b8426,ae13e20d,8834e061,ab1671fe,4f4665f5) -,S(3579fd9,9cdf0be0,2d7e8587,2e213ed3,3a424650,5608d66f,8f936ae7,72511e28,dd93278e,ce754f69,4b3f09d5,a3c32c99,2c5f2e04,cce0a517,de750a38,ccd88abf) -,S(f307f2fd,d0f6c0b3,12841e5e,1e17b966,47d7ca93,4ba4970f,4f9c0c0c,3ccb071f,4829a5bd,40555e18,bf80ae66,b9742249,32679acc,d0e46003,e079e2e3,d20d248f) -,S(a462e750,9e718317,dbc72b9b,fce5909a,bdd2fc36,d56a525,97d3adc1,fe4b98a1,2f9ee390,13b70415,d2e6de97,7aba55ab,1f7c6f2a,a5a7b541,a7101a62,f2799836) -,S(72ec447a,245624d1,1e1270ea,1c4c060d,c6501f11,70c69f4b,229bb98c,e7c47804,cc32a876,33bb7d62,e660ba5,59cc1804,10a51cc9,dc48a9ae,fc3d8225,35fb8ff2) -,S(b97345ad,2a7eedfe,71ae185,11a3e2d6,c431e628,363e01a5,21622c17,e92b32a3,2ba1cb4a,abe0aaa9,619ea819,4e5c0222,3bea32fa,e4ee3378,ba798472,19670e2f) -,S(f417f269,de287f06,8a74a330,14331059,73ee691d,a7f5aa1c,4e00a100,1e2ccd56,1bb297c9,5b3fb72a,3263f126,719a82a6,b8bf415c,e81f6838,2c8b3a9b,42917584) -,S(cdf7b5d5,f7632248,be1bcc1b,61f56491,e81cfe76,1ee897c6,fcebdf4d,109b9b41,118f3f6,32f18892,d37a2aba,1c8d22f6,587ad56e,eacef09,b9202005,75ab7b11) -,S(3540c9dd,992dc4e4,9aba8fbe,8f28950a,24921b05,e1bae568,2714aa6a,95eebb81,841d9499,7bd92dff,53ee3c86,eafc5f6c,6ffac94d,3161ae86,2182caab,8d5a9268) -,S(70f4ef3,37a5519f,466cfdc7,ae779588,74c9a9a1,9a558550,8fafe6fb,d61decfc,413476f7,78f5d377,31aa712b,5c866100,bcc2a33f,ae1a078e,c5e5cbc8,4b7bac5e) -,S(d08990b7,ad5c205a,e5be2700,63bcf8a7,e13c2a,73dbf321,b0d9cdca,a1648da6,b0aa7acc,f47376c,115b0226,1494162e,d425b496,a2392aa9,254655f2,4db6cf48) -,S(53d6c5ec,f59c49fa,d970611d,b8423bbb,e2f5aecb,d4575877,d903d95e,eb88e455,6a954f77,532c80c4,42f2bf65,8e9d763,617c802f,369f1a62,34927e55,ac549f56) -,S(af7216c1,e51fbfb4,a5ec1e93,717f7375,9f15dbaa,86706ca3,6636f499,416ce194,4ed49771,f858a8c2,bad65a31,b5ea5a53,8841553b,accdced4,8c41e2f6,984470f0) -,S(c560d2be,2f2fa6d7,3f5224e,36acdead,8d91eee3,b99a219,a762adfd,a5e79d07,30d4b54d,a96fcda2,2187a2bc,1562d59e,24ab55ce,f9cbfbb8,570cd89,4d436343) -,S(30b40200,c728bdf7,510db9f7,a8a63792,ff70a9f8,c6262e89,4ef902b7,eb30fb8e,8c98fdbf,29f8c5c1,ce6d7d4d,61a2907,ab57b4ea,a25888b9,e8ce751d,6a19a88c) -,S(d7239e30,814ef236,5193c19e,dc91fcbc,955dab78,45b4f3ac,be994264,2a434e1a,454dc941,4500f4a0,f93f751e,1e2d4c25,8c0f10e1,b4f0c6f,3be39b0d,e5170dc9) -,S(60e511c7,7c8d7496,a3f262f6,376d3958,dfdc4645,73aa303e,a6e6672d,b1c21b36,bf86ea8b,c8a37a4e,c5ee1a60,d6e1888a,ac90530d,eadf40c5,b4f61a38,2ea1e340) -,S(55cd8f35,5a242219,3b64633c,27b1c1fb,7ffeed51,c815e1fb,ebaecfb2,3883d739,b6508643,7e53ad24,1fdf4dac,871e58f3,b5abb87a,d4920057,3c37a1c4,b2bd4b3) -,S(73cdc2fd,468a2d21,72a9e0ea,3d4a04c5,ab5fb13e,2e2ff2e0,8af5d70d,ac9bd41b,682e525d,1263abaf,f070bb47,6f754da9,f6c74d,27f319d8,5d9d2882,6d06fd04) -,S(e5f30676,3c9f620,1c5ada9f,6d01201f,97e36fc7,5bb10a12,4cf69cee,619f07fd,611f0f16,39aaac35,5e311a18,a5dd65ca,70e1a52f,452bed2b,3382ac03,dd50546b) -,S(c2c21323,b156ca78,5e53c41d,10bc235b,8e32e4c8,ee377fc2,42d089a0,d2a27d84,6b9f3faf,64331dda,d25d603c,d8f334c8,5cefcf5d,3bf640ac,96fe3bf7,71ce9cf5) -,S(599ff1d4,806aa8c8,b1440a92,9e2383bc,efd9b16d,899289a4,a335dd06,7e63d9,459cb346,7c387470,1b86aa34,c47b8214,7f48a0d2,7b9098bd,2b53d7d8,93e25316) -,S(f02ddd62,a2456e7,b4a90bca,1cb01e98,8b0a09e,62c90154,42db0f52,b635b006,a5666540,6cad4d01,aab99686,90a7ad3,b1ce936,957c317e,57bdb763,b8867583) -,S(f332b89d,1977afdc,aaf681a5,19bca58d,59852f74,78572346,b688d55a,d55a34b,988afdb1,afa1041a,51ed913d,d780b21,5dc90b8a,b5ae857d,73df2883,50ca78d4) -,S(d6fa4679,4fd4d05b,d6b7bdae,22a970f,8c3c3628,ea0d2656,55c0ebf5,2f1b3a73,d9f47018,86512ff9,9c4691a1,60b62e2,616f5c8a,fa2151cb,fd6dcd80,308ad947) -,S(2a13e09f,5c00016b,d974d62f,2c7c7ce9,e46fb142,e7334f5d,98fa2428,e26b25f7,f300cba4,26636d5f,7f8fcb2,bee6e5dd,b9697cdc,9f9c0636,b02b3fa1,820ca235) -,S(c6480cb1,c1bd41ff,e57cbf57,ea854158,36284048,e79dbb51,44a59027,13d13ba0,fee7ee1b,1652e63d,ad49736,8505b302,f135df7d,4a2f8720,74631646,244cd43b) -,S(559613e,8111c9e8,25fa96,aeaf4b2a,4019ea61,4c67446d,76305484,c9a4d7f7,cee9f4eb,2680a723,9187d407,f39390c6,4fed596c,b40f58a3,aa6c96e5,c8c9c2af) -,S(3a95b2b1,e6d19b19,84dcd59,501c33c2,4ca50b59,d410d99d,b9b6da4d,b1dc85ec,7a802198,a5c61542,81669bc0,640a8f40,6815d25,3bf8090,3ed894be,a1b09c72) -,S(5ae541d,b816522a,5d347339,713e92f5,25a637dc,75c9d9b1,5d834f2d,b265c2,e98a115e,f76b2102,7953f65f,cbbfd29b,a79b43ff,8cd6813a,b65174d2,b03027f7) -,S(88b5506a,72d681bc,d34eb118,3d6a7fc3,77e7f496,6d4c65da,bfa60a18,210ec487,c29638a6,ad91272b,3525ab40,1ebcd1ce,ecebab3e,b506cfec,e7e9df0c,6ee40501) -,S(2942de16,93ce8b88,e7e45657,daf88b2a,2118fb7c,9d2296ed,a1725ec2,f7d408a5,778f43,8b4f088e,fb99cb1,819fe6e7,55b0641,8d8679c9,d684faa5,16970f5) -,S(25c22037,e5a46e15,4adfcc47,480a088f,fb53410c,dea814f8,a4f2c387,df2afd0a,45cfaef5,5c5d3742,3380be3c,c38e6785,c85a90be,7cc92fa7,a390bca6,d3e7b3c1) -,S(b1f78a73,d0b935c9,80cd8ab3,b8237e3a,df5a40bd,5f875f7f,bcb13bfb,cc45839a,466141e5,d465c35e,37f80e57,c4923c84,c3a3ba98,549cc8f2,db6e0dde,915293b2) -,S(39405322,a57a4846,d8b42bb2,58f851cb,5570295d,71ded6cf,b803852a,8b4d8304,c81047d5,92fab5a8,c6139ffe,6887d966,e809d2bb,ee3a10b4,5adc5587,ffb302b3) -,S(7faa8352,31e2c6d5,b331ada,5e175954,6142b131,5347196f,bbc5759b,dd6add0,8779b0c9,2c176b72,5355bfb5,ccf5f739,5fc82ae9,48896a38,1be85e58,c48d154d) -,S(b786c145,61fe4677,54e14766,56d33daf,adddce8,e86e09db,ea93f1a,2ff0c3c0,4c5c35f5,99bb9637,75b4d61c,b30da8ad,a4e83a56,2cf7d2a1,fc22f06a,fff92aa8) -,S(ea4b9a9a,b4b509da,d1e70ebf,6604d624,8b6b63d1,c905720a,648e208a,993ce4fb,f5ab8356,ce28ccb,b6f1368b,344e15dd,372d732a,d8953864,21ce415e,6f0a92c) -,S(c986010d,6339bf7d,2ae3e9a6,c977b9a,a2033a42,14a1e9b3,e700abd5,428e2491,4156f13b,a68ebc80,ad12efe2,d5a0469a,a41adc0b,1dceb765,f651b4b6,b652a85d) -,S(385b81d6,e023164a,3662209f,5d694910,22e84b5b,7034e8ea,346941b9,c04df428,9d12b15e,c1868f27,362662eb,cb3c9bc3,1626ef22,36c2d75c,65e82c75,7ff81a2d) -,S(82196a55,104624b7,6710b4b,864b738d,36ebcfec,55226aca,990474b2,58aa978a,48dbd01c,5af9b1fa,21d88b0f,f6b994a8,38d47755,5ad85171,1a4e3d0e,14ab1914) -,S(dcfbdad8,34d74f6f,9df6c143,abd6dbd4,57f954ef,6323ff77,3a19c367,8d6616c,698d3051,8f8d7ffd,b45f0bde,c32c22e,2cb97acc,a8aa0aa9,c16d8789,a128c3a2) -,S(343b04d9,babecad6,5479cf60,e43350d9,8c56f989,69eeca59,5a5e97d,89c25489,14d00978,2729ea38,a79765af,ce78ff5f,16ada59e,9d275274,e6e0778a,facc25ee) -,S(25af2270,88a6beb,7c76a80c,9e87a412,ed166a71,d65d5722,a082e57f,8ac7bb77,d01d89c7,39508a84,5ea64e03,697c2867,5b14bbc,fb484f94,a530e57a,cf19ead9) -,S(1292823c,1759fa5e,48d0724e,67c93df2,c8ce9fef,9124c5b5,8a477aa4,dd3f5e32,c481025f,ece1bed9,26ecd3e0,3cd7eddc,3cc31836,a12855d1,639a85df,7c69650e) -,S(ed92246a,5a5cb2a2,1618deb0,794ea013,20560b42,273638cf,afc901d6,2ff0bb6e,3675cd33,825e611b,8802c746,9cd82b97,b659e31e,c31ceee6,681a35d6,2d5097c) -,S(8174e89c,9b3666aa,69ed3bda,6c73c572,ff3384e9,60863f87,b7d346bf,afd553df,154d75ce,caff95ba,4b5b7b7e,9ea99dff,499a522b,f0252691,cb6b92bd,98182d0) -,S(54169816,f0440f73,1f14de95,e7ab32b6,702c0183,62794ac9,e55ad632,95c4484d,12e541c3,ee64efd3,b5b8781e,bcc5e273,3544653c,d8b55d51,fa3f887e,d8f42465) -,S(c654d2a5,e31ce452,739f9cfd,b2784d37,eb974a4,fda45fad,13a2aea2,f7fdee9,47c9d2e5,24e7391a,f645ed92,cb04a0e5,6aef0362,9b57d593,edc85b1c,686ca4b1) -,S(59724a3f,eb1a1cd3,7fd6a5c,57c3d055,28fbdf48,5102e709,7ac35912,3f9c2ed0,4df18ea4,c0de4053,6bc5a6be,2df794c3,2db2a9cc,19367473,d88829a5,8603010) -,S(d99168a1,3fbeee0b,6aec4b7b,a0060649,1c4ca151,1cadddb9,2ab3478a,325b1073,c2b0876f,528de53a,f2f695b9,b8225fe0,4660a447,c9e9bd9e,4ba5e52f,beb0ce6) -,S(769c1b07,c26b402a,9a4b60f0,5bb0b318,d20f65b4,e941f525,43a15697,5a8f876b,7880299,413ffe86,94a76f26,9acde007,6e64a753,94701bf0,84324215,debf3d69) -,S(6074f53c,ddf9467e,b9fcc4f7,ea4b18ff,777abd8,895c9eb9,71195a9d,57b1b1ac,de1aa32d,e5488e69,eae8a06c,3c89422,a26f819f,af3cd9cc,762d7fa6,1fda3094) -,S(1f9ea27f,3e9e789b,1cde3fff,94bf8046,f5399046,867a2f37,2da59221,e85c655,c47b5ce1,3d399032,89449260,7db3f7a2,52a74084,20ab1846,fa378674,1e7bf7dc) -,S(c2551e26,5d3978ce,49cee376,ac86a0ec,7ba10804,bd894019,e79f51eb,ec9830c3,23dc4415,10635bfc,2af8f85e,c4cc59de,fed9e9e4,198304f7,e57a1f42,736871b1) -,S(2ca9e4d8,3358ea8a,40bc15b7,8c06169d,ed7a5abd,47147972,45078e94,75264d20,f3324029,9fe328b7,ecd14a11,6fd82bf6,5d925532,85a176a9,b7ec892c,ebb2cd94) -,S(e0db4052,8e3eafca,1f514b26,8b673afd,277c5aa9,e2dbe85a,74478d6a,f2ec1f94,f868c782,40dd75ba,3c6809d2,d62f80f1,ab7fead3,c67a90d4,ecc242c1,687376a7) -,S(d34cd3a5,764d99f3,16a260c,9659955,fda3cd9c,cb305f73,d3aaa61,27d422f3,3f3b80ef,74bec102,2e442e69,8fd4e28e,514d3a9,5011ba18,1299793b,b760da72) -,S(588dadd0,79d2280f,37dbeb16,3e05a70f,48ec61c7,cf3e6455,f3ea312d,4ab2e075,731a5c9d,f803c2fd,b22de461,d51af493,5874b745,4ab8417a,940383b2,9404fa3d) -,S(1731c955,931905d1,ccad3bc6,133f5d9c,9fbb10c5,e800be80,643ed02d,6d7477b1,d7e89b3,1f18ac07,6c7b7380,64d2449d,2d9beac,728ffa8f,6d8a7498,d43baf1d) -,S(e2f990d7,6818c0c6,e73d066d,5644e9e9,29f495ef,507b18cc,594871a5,88e45b46,2ca12307,fb565d0,7c60b6c3,e92c9757,45777970,1733c0ad,2b299a20,8f50925) -,S(b92872d8,a146c0da,ec576be7,35a22896,5242cc61,ba37313d,31b0e5ff,21a2273d,8178dd34,e552e97,fff949e9,b101b44d,35d6b57e,79c0e78d,f91ff3f,2817daf1) -,S(b980d2e,9440c3c3,be5cf393,6eb9634e,923cbde7,bbf2a07a,d7a97287,7d6caf11,51b7d51a,8685bf75,c6d376d,441dcd69,cac67b77,762f6ad6,97a9649b,f3d3719a) -,S(db2f9a64,3c3e3706,e9b5aaa4,5ebf08f2,ee9e967c,205a49c1,7dc76b8f,b20a3a52,d05d486f,ab967e27,b9e8c175,e93df203,4657dd,750ad788,1bcc4897,b80f3d40) -,S(5d5985f8,910be82c,538d70d8,9614ec3f,bc9e1f91,9a19950b,a8fc99d9,203d92b5,3efd77d1,27e43849,a710d1e5,7b18b681,c1acb293,2244fa7a,30f360ea,88565e35) -,S(fac2a758,a063dd8b,46b41933,9c70d2ed,3807bdca,69d3b36e,6369f8b1,23200866,8294340d,6154afa2,d7b730b1,301f5ab,322bdcf8,6fb5676,78fc47cf,b15809e3) -,S(cb92092a,d45ab0b8,559846b0,d02a0c67,a13edc86,7d0cce5d,fcc09e63,d1b6cbde,d2593de2,6371136e,390bd52a,c9811334,e13fddd4,e9b86b1d,942cacf5,4615b287) -,S(d715f4a3,66a4a770,bec8abea,49ab6c7e,99e9473b,73e479c,14011843,9470c844,40aff69e,ec6da9bc,38ec119,df4482ff,3bc2b67d,31284db1,8c757990,de6cd0d6) -,S(77312617,4a395a4e,f7bad07d,f2f38843,22293a17,ebf09f20,4732e7f1,2c418417,602cca39,d6352365,420c5ce2,9d2282cc,5d8919b5,e0669b09,22384b69,7bd48a7f) -,S(a7c4b675,f529ba17,e9f1ef44,c88a8066,66131845,dd98da82,4cb04f24,518a4071,d88edc2a,1eb0cd48,57283e3,f8658d8,2da27a7c,7ec16129,78fbb484,41ef438a) -,S(6362f575,d459b970,db814a7f,9a142605,f26f577c,4357be2d,dc16793,64906f7b,fbc9f007,bd08b6ef,cd49c1f7,1e199fa5,ede01123,5d9b015d,515bf7a9,7192f8c2) -,S(6cfc45f8,515813d5,dacdcbd4,c34c155d,c66b0298,8b8a8702,73a5342a,9249b623,f85c980e,394ea0b6,39bdc5a5,ed185de1,7b1f44cf,b7e51c7b,b9f56b3,496b5ee) -,S(d76c0b83,b8a8a8bc,4e8985da,f6f1535b,9ff3b4fe,e13eed4b,39d6426c,87cec8f6,15ddc103,bc6c4f43,6f7e23a4,78e47166,e3f4156b,5ad2d581,7f3a7ade,7d80dcae) -,S(c4f98324,57330d12,e4e26735,464f24a9,a93dcf75,9194fcd8,a2d12ce2,bce0449,e24a6f24,f9a09aa6,f58f29aa,f4e24a0f,864410cd,80280432,d82cd9a4,ea2ac2b9) -,S(e86da865,238fcc7e,d8c2721f,89c2619f,a2caccd8,5e05a21d,8d23a095,634cc439,85b35268,31871eb4,3323caec,13de6de7,94ddc6e7,5d44835b,7443137d,25ee2194) -,S(a6398918,6969469a,939e774,eabbce54,109b833e,b3dfb566,876cf50e,bdc7613a,c48430c3,fa8c730b,dccb53,451b5a38,888f2e85,1f510ca7,64360c9c,b72b6eb7) -,S(6986ef9e,88c8dae7,ecc8184e,a4c5d131,32a87ad2,ff8367ee,63fa0ecd,b7a2972e,e9acba9a,896e1eb5,bc1d2625,983fd2c4,13f54b47,3056a893,7197f940,92eb4bf0) -,S(47bf849a,e428bdde,ceb221ab,e0ea2fd8,c0a5bd39,175aab96,c2fddc57,e809527d,401a7ba5,1999aead,4dfa6ce0,fbad17e8,e7187e52,806a58a6,7033f653,67aa7c02) -,S(c0c02bb0,92af6a5b,73582a14,89067933,8b31318a,f2d5b142,d58833b4,cf07fbe4,a19dff69,5ead3a33,d8f9f7a6,76b8287f,4bf6b23c,6761b084,12d86508,830f8990) -,S(f2185913,405156ab,22baf16e,644063da,b3ba25ab,f191efee,1ff028e2,f7d175e0,814c64f9,9a4250be,2265cf8e,47c8276b,9e5245cf,16ec98b6,b789dd26,be894f3d) -,S(40d840cd,ac4060f6,de850df7,c37462b9,b4d5892f,a1e74f35,89ab3955,a5d941f8,9892b0dc,ff43a872,6974705e,3a3fd077,c2b91a2c,1c6ee153,7b728359,d3217833) -,S(6f6b79e7,9006fe48,5546c3e8,52a33dd1,cfb63f3,96b44d1b,af1fb112,93271b35,f5aa0beb,50a628b7,b5348817,8344527e,d1ecf0ff,a0766a78,faea2361,e8fde7eb) -,S(4edf60c8,c0488128,29e7bac8,7b03ce49,c8df0f1e,6a3e02e2,ea8ad097,f66163d7,9861393e,fcec430c,c00ccd49,3d4e2d2a,a45e1034,fd9a81e4,b015bd5d,56f16dea) -,S(7ab0c44f,f6a444c4,e0feb1c5,a6650c37,26249caa,38f53e62,b6bf225d,bb1e008,e7f9af86,a2839ce0,80c6ee9b,d86529eb,7a7abaed,aa6aa4e7,207e67e1,a500e5f0) -,S(6a90e50d,3dd2f382,1dde8714,57012b3,5c1103b5,80ee4982,f9bb78d4,2541f8b1,5ccd34c1,8455aa76,4cfe6c9d,61507ca3,cb613bf1,4b9eae3f,8391e1a0,9dec03f1) -,S(289d4d81,cccf40af,a61ef56c,242ef8a2,c9883267,54139e1,dbf018ad,5d251df8,f3fead19,c49de6b4,32869220,7e60408e,dcdfad25,26e6e555,9b022941,592081cc) -,S(a1ee466b,c561919,2e82a316,ac3b7514,b109f442,1c93fbeb,234f5862,d37ade3c,db12d4b7,246e8ee5,55dde2b4,9b5c42e7,408eff9c,a853af00,5a6f6c7,73aff21c) -,S(ab30a856,403a1622,14be9837,2ebaa8cf,8d946074,abfddf2b,8e65e2aa,51554329,7a6b7f22,a6ea52be,8c0c8002,29613020,a247c026,86eaf960,7fc56cb7,d696c56f) -,S(17c5f1b8,8e3e4e08,dab8a5c9,2a679c05,688a7437,df6336e8,7b0d22d5,ed56e5b1,96068e6c,72fa9b39,5993913b,305caf70,3186404e,17131b5a,24e14273,a83dccc9) -,S(a76fbdb4,b99e31ba,c434462a,64c0557,8e961a53,dacb9bd7,68400b8a,823190ec,52e31883,5ac1a3fa,e269a4d3,17bab065,7e890844,c3fe96c6,d04fa015,89c89f14) -,S(17b8bb76,10476261,ebd75e4f,299f1805,5c88f36d,ae65cc57,3c959820,25bb794d,1bd9a52e,585a40d2,67db59c6,b9b1bc59,4b8d5344,29b5d4b0,82bb1c9b,b54e0392) -,S(65aa92ba,8fa51cbb,3954b93d,68cfdfa4,d64d97c0,9e099b1b,d1ba853f,18500b37,a2b12d21,b7a1ffd1,af48e4fc,e80c6fc2,e624783c,7b0cdce7,9f01ae7a,5fc96e14) -,S(3450bcca,5d3b30b0,3743f0d2,6b61ea09,de6ef7cf,eed44b3a,c58641ab,93ad7867,4fca3307,5328a298,d310d447,4806f297,3b09d885,9fa3b949,11817d8,39be66ad) -,S(484bf072,134849c7,695ba73e,5f25a8bf,74a183f2,bfe35ad7,34b53878,a2036be4,a5295452,a0830b3e,3c45043,43fe950b,3289d402,73d3bd49,6c0cd7c9,156a1d6a) -,S(2cdf1bc8,920ec641,63fbc8fc,c72fe5c2,dfcb87ec,15725e04,163e1ac5,1b7ec763,c680476a,28f054a9,ac3a073d,67ceecf1,c8262ed,4bc462bc,44798e88,d0e48e54) -,S(59c3c60,8031a214,d3e6be15,c644265c,b6f3526c,2b37d840,86532c24,52359bf9,2248b28e,922e0468,fd98856a,41ca37ec,2fc7bcf9,a13c7a9d,b4135e28,5cdc1bf5) -,S(4f20493a,a7a1e558,a44e54e3,b81c889c,d45b6384,9b8448d4,20a34a31,c7c451ef,bc1adcc0,d00384e7,93c2433a,a76f1f08,b8b23170,6e285d56,3155dc19,d5aaaf1) -,S(bed9949f,dec9813,5bcf76b4,83117fca,57525221,8a6a52c6,a44f2468,29d48ff3,6ab35499,8cad07f6,250dec89,a0840192,b62777df,6e241a4e,325b0c4c,bdad23ba) -,S(1cf32b2c,46deaef6,fbc892ae,4f05653a,3cb69d0d,821a7125,3c2eed77,4e75f767,caa6268b,b8574b47,840b3626,74f4a479,5a2c6478,c440aa4c,36d88a2d,ebacc8f6) -,S(9d3f7c5e,5e0947cb,d9bef5a2,dc1a3e9e,ac22d6a5,9071d0eb,5f270100,3e66dc96,6ad63f62,22f3a787,9544c330,4c3ff653,2a00a764,5ddce01e,c4ac4933,a5c7aedf) -,S(a5a927a3,f03dcbc,b3d069ec,156a6ba3,474f48cd,4828f54c,a673e10d,265eab6c,b5e360fb,39f65847,b63eb29c,a8b403d3,272d9ef1,8127d3f3,7650d13a,9a5736c4) -,S(48de778b,7bf72a21,871ea379,c02b8887,5da9688,37faeaa9,93e68eea,926db673,d25cb808,7a7c13b,fbe8b1d5,522ac2db,6c44526c,13ca0327,586d6a5c,1aaca91a) -,S(a029831,66e7cb1a,fff65515,48faf447,cee8ab2c,d4937269,db002cbe,b8f1d1ef,ef34ec5,42554e97,1ae8897,b049097e,3430c99,d8e93c50,94377c07,a5619ea) -,S(6ed75b96,c4e976cf,75cf0b72,df83c043,5b15d2c3,f8fb319a,94a4d97f,1394df6f,9b63c36c,1e31becb,e1a5a6e2,1abb99d0,d5c39694,cec00fd0,ffc27b53,309bf6eb) -,S(9372c1d1,6997f792,688a55f0,8f246cb0,f206ce31,d0f416c0,c81cbdd6,8487aa5f,ff97433b,be60eaf6,6f19c182,e8a8bbbf,b24cdcb3,7aabf79d,5dac9f13,9c5033b4) -,S(269c7d84,b42f90b2,f39b4db7,5ea0724f,fa6a1a5,4c66a1bd,a21e4254,6f243bf6,8f6f8b36,e278c6fc,bb0c9918,7325f1b9,75ec3add,69708be1,b4703c5d,53d8f8f5) -,S(62f9cd79,921ec46c,d470a12a,9619ad4e,3bed051c,14f47071,e55f9da7,d103793c,92211db,6c846f43,2867b9ee,3b1ff00a,a08f179c,13aa7475,d64d0731,23a69e4a) -,S(fa432dcd,e7e3b40d,a127d65a,e0955d58,a009d81b,46b48745,c4e24597,4e589a8e,a8dee557,cae7e50,d96555ce,c56255b7,c64d10b7,6639b3bf,8d60aea7,58716f68) -,S(a424d18d,c6861074,40f42e5e,f2bfc95,f4c8f94f,e3adf681,79086502,fd9d80a4,cb30797e,1d973012,d488f54,6033b1b3,d6b50c8a,39badf8,fcc12bfb,3a1c4d0f) -,S(c2a6369e,e2857d2e,fce4ab31,49556c08,3ac6af90,6be418e5,ddc5677c,f2f7ec8d,a7097ae2,9fea3774,11ce3f81,b6b3356c,9a2abb69,986ad81f,46b13f8e,a0e7f0a1) -,S(f5eac1a2,3dc91862,d8022931,3be5c7a5,364c0880,23c0650e,53e22f42,2f91ec98,7dd62b80,3ad606c3,3d8d9bd6,cb397ab8,1cbd688f,8375a405,23bb7315,a3f48c24) -,S(dd94fec9,3bf7ec6f,cfa0ced9,df31a1c,131c39d7,e110b5e7,b988c59c,dd594fec,cb858565,6a32e03e,2eb84732,4bdfe2e6,3601148f,7bc7e56d,22cf9aa4,54f063f4) -,S(d3dfdaab,8f9db2d8,edd3db27,d96be5d0,678e9088,5448222c,5b3171da,38fbd501,6b210554,df32021f,35170e13,42e2da18,72be61e9,481a4b74,ec470ed0,b942025c) -,S(47ff9918,3e452838,f63eb828,a239d95b,62f8a746,8acd0b43,6c149985,2afbe3f9,33b7b8a3,a5b51b15,fadc1f9,baec6b8a,88e0da56,5a54bea6,1b2d728f,eabbdc48) -,S(1e99e92b,aae56401,1cc10c94,dac071a9,27565a17,2d6d4a20,224e1b49,c007660,914b98dd,a92484e5,a43d7de4,7bbf57cb,2346d852,f743fdd9,15dcedca,4393aa21) -,S(e150364e,d95ca778,70fb3367,64f9f417,70bb672f,7e794416,13678dd3,65d84fc8,23ddee4,30d7b565,cf545837,58df61fc,502bf86b,a4cbc1cb,7630a9bf,e339ab85) -,S(44dbe753,dd822ae3,f3ef4939,a1d96a98,33e697f8,c4979191,c64114f6,71e8fbb8,b909bdb1,e6e55571,b03517a3,c2345b49,a5793d21,15fac018,2afbefe9,c726c8d5) -,S(fb843458,725d557d,b1a17ad0,427b4d98,6ba189e5,d6da81a8,81867259,6d9d2858,18f1c9ea,bd8e71cc,72e2dcbc,532b101,c7381475,46c24790,d010a6cc,32d4eb10) -,S(48f43c41,b63bbb05,57f8d71,edc739a9,57baed23,efe9c814,848c54e8,54159144,cb75c418,d5557cfd,b29d4807,3f193343,6eafc209,bdf9685a,72f57b98,6676b193) -,S(5520f175,9be037bd,cb5af2a9,a0bdbcc4,9e1531c0,32fd17a4,66f59b38,6d7de1b7,45b933b4,cf256aa3,c6513a2,8a4eff90,7691a34d,e6cc2e7b,a0b83f8e,a7ed4e52) -,S(83936718,1d7d065d,5c15e246,ce8391a4,bec58c71,7f82419a,ed6547c,63f081a9,4c903568,f5ce9a54,65fa845f,985f24d7,6e66cbe,3ce256fc,1703b4b0,5dd636c3) -,S(66a82c47,e756062f,6586ece,86911ac2,23b84c9a,e53e5307,4e22bfbd,3eae6b30,ab2051c,4c231a40,c6da6ac3,5ee32b9,b7eeea17,222cb1d5,a3abf9b6,512db8ec) -,S(974ce35a,9d5a4ef5,84d252dc,3c365423,1335c52a,e3daefa2,8ff9b75,56bf3b46,8c82a9a9,c49d167,4f3995c2,90ae06ac,fa0a5c14,b1c5f41e,c1e449d9,5effb2c0) -,S(1139c2f3,60cb8a4c,e020bb8c,3d19bce2,1c6802e8,5fb3df33,8fc9ffbc,8fc231b6,59adaa14,7980b3e4,73801b73,9f1e0248,2e9f1e17,65df2ec0,183d9f81,d57723d6) -,S(c1bd3793,3b03d95a,b17c10bf,c5167556,4294e38c,740fa3ef,9b356be6,71883b94,c68bd82f,5e926a59,95a83f1f,1a8c2f4,5966b073,91ee74a5,ae2ed99,106c6dca) -,S(c7778ce7,ce668003,86db9263,cddcf608,aff769e4,b4755858,20554ecc,8407bbf2,92509200,9c57f224,8f9b4e71,532c698c,88b91b77,4a3907ae,1ef30c51,78d807c3) -,S(14aa1177,51626b67,8f32418f,1855cc34,52d4ec13,d2d900d8,8a22432c,70ec022b,6151fdf4,f4372a2f,e803478c,da340678,c18a0a7c,d540b0bb,4168f9da,2edd6d81) -,S(a53443b1,b6065cb6,abb18c84,1f171b3c,7152b34,293a7ad1,2e8599fd,f1398cd6,3a07e076,35254aaf,eb30efea,328e3ffc,3a7d280d,5cb2c8ae,9e70b412,38fe704d) -,S(35c3e3ab,ba4c946b,1eafff67,a9831588,d6631e18,9507eca7,66e22449,f8d294fa,94973920,58f6830a,4e5f413e,4d7d442c,4348328a,5115fdc6,ae5ab638,339e313e) -,S(1aabc2db,5ac6df10,1d097db6,26e3623b,295ae6c9,941e3717,ca849065,512a7fa,2d2781c7,b42ce42f,b40b737e,9100ea24,ecfdf58,fd724244,dd67d84f,4a6cb097) -,S(383103b5,5a4beefc,89dd082e,f0e14211,9bacc5fe,8acde710,7429241e,f16820ca,2000fe09,2b820a28,f065924,7823d6b5,18756044,1856dc46,a9fca8c3,84913398) -,S(2cb0f0b6,35022212,88b8be63,a0ed5d71,bc6b89ca,4b2fb4f8,54123124,49445107,9a9eacc7,cea4c27f,ac63a2be,96884112,435d5f6a,bf4ad519,461017c6,1c87b2a4) -,S(ae63a05f,306e6980,f439afe1,b34c7b3c,1453e110,e477e3a8,d7e9ad3e,fe2af088,6facce76,d579afb1,cded78a4,1dc64c79,b6e90279,d8c5f07b,fc2b0a3c,7243b309) -,S(83207533,78d5c6ee,ae26aee8,4f2a0833,a65a94ef,53a477b3,c8708ac0,35dbc24b,d8306300,4caf8d6,7fdcd09b,267a2d5c,b0e83e97,60fc4d8d,2b07e2bb,c2b387e5) -,S(f38888f9,3337633c,9873d501,8b9fbfc2,ad135870,89f6becb,528ea063,a817af28,8beb556d,8e5342f0,6fe06215,891e6091,f8b940fd,b6eebc08,ded95ea0,99985ecd) -,S(c15cc888,7d13a93e,c2411ea1,6f21e86e,4fabe47a,55a94a6c,aff7681e,d47ba1a4,5bcf5b68,91f3e01a,3754fed3,f70e5052,e33fb62a,753c5f3a,532112e7,f7f58f55) -,S(9b3b0b21,1befb305,b02d035a,1e7cad04,3b8ce04,f9315bd6,5067a73,f2680030,75828df7,eeec11f2,e0dab801,5c75213d,cd93cc84,7e873e19,b7d03eab,e368f989) -,S(2028eed7,50cc8973,c1ca2f28,a30c05c7,73e2a05a,db916825,60d41cea,3b4d0a18,40efea34,b941571e,98a0878f,a13c4efe,1e3410d8,d5166661,115cfd55,53bd0d71) -,S(ca697e9f,8954a7cf,593068b9,1078486b,c8c9a71c,d1f7a890,a0a3e0ec,e48521e0,4268dc9,28ef996b,56af66b4,2f410831,b9f8c6a0,2658d706,975a7624,6468322c) -,S(26c2615c,ebe251a8,a78b00d8,1733aa70,f8f9a97f,85c2fcb5,d9287e34,b786d4d3,ecd17c3b,e1b3232e,bde8f859,39f5158e,f8c340ef,cec4e758,cd54eb7b,df4df77f) -,S(7296b5f2,c4ac6a83,c180cc55,2fc79a84,691c50df,8e56ca8c,731ac368,2d8737f,d4410073,1f98235e,cd75e26f,d251bf8f,f93ee806,52446208,c9643fc1,1b938aaa) -,S(465d9610,c3f6c8e7,366ff5e3,9e1e17be,53ab9eb9,f299be2d,3d9dfe6f,fc601a5e,741cfef2,cd41ca9,4b847ad6,93f29e2c,7e0bef4e,6244dfd9,8e3bcbeb,8c3ae7c) -,S(d3264c87,fe435796,b4d40631,a0a64a34,570e36a9,809d98a3,7ffec23d,9f3775e4,e6fa5190,b66bd281,538787c7,40bdaad6,f37a1eb3,90b19c3d,cbc65b19,9bad22ad) -,S(d925ed62,5551d49d,151dd55b,2cde29d8,fa5dfa21,e9454c17,a834f090,7d744640,e398cb93,1c9fc1ea,d9912968,b335015d,162a04fd,c17049da,80a7ad4a,b3b21451) -,S(2f8339f7,72cc9ff5,c59ace6f,d38a13d8,21562e0,a0d5dc2b,a2c074a4,f697413f,d09d6be4,3678836c,e110e805,68a2fbb0,b87d1657,d568d7d0,e4ba1237,dbb4fa4a) -,S(f954909d,f67de727,72437ad4,d3229c50,8440d23a,9215394d,d09c7232,fa5cd0a3,6656c1b9,8e726305,644994b1,eed6234a,834f74d9,2fe16ec2,c945478e,ec53fafe) -,S(962b9348,d9b64aec,7ae38297,e80a5f80,ee1ea253,6964742,99c5196f,cd58f33e,10601c5,87838f02,5b6735c1,b711141d,ed04ed16,2fdc5bb,4dc593fe,9b804145) -,S(b70436c8,4c6e25a5,34c3c2c3,34f13350,7050b552,72a04032,84a744a8,6336efd7,1b9911f4,72a19b13,e8bad704,ad3fc911,3223a5ae,4939138f,86422536,da1009d2) -,S(8989063e,49605ac9,78705f40,cb916505,615cc465,40c4760c,db302cc7,a9e4c6a,e76c05d8,5b32b5f1,9913472a,be4322e9,ff5149e6,e224da9d,dde930c9,948ce8ca) -,S(9e2c1711,29d01e44,25e4d5a,802f4c5,84eaa0a2,2aa8fe0b,bc0aecc3,15fb00ae,b1385087,ff34618a,d126ce7c,dac3a7f5,1f0fec09,2a7a9601,b65c2786,c733fe81) -,S(3a88a3cc,164795e9,cc668d88,d9ffb6d3,52f90edd,c6b0aa5f,dba493e7,273731f7,95f0b3f8,2fc2c9c8,a25b337e,af92ca08,e17ef68,ae5abcd1,43bbf5ce,d68a1fd) -,S(f5cc5ffc,ad18ea3b,c15ed2e7,d0ee8e9a,141bcd7f,8e6fbe1f,81be287e,e7281725,ec049ad7,6ae3bc58,9a60bb7c,ae79dea4,b512fe66,bd812ec6,91fb3182,27d9a288) -,S(c8af958a,201a29a,bf880688,89c211c6,da59b59f,ffcc02db,9010bd6,65b7ccd7,3755194c,76d6e0a9,3f2424fa,f26a512d,f0605393,ecb5216e,d5f1d452,99b247f0) -,S(16f10ca2,a11493a1,361c80df,40066683,93c02635,78f11f2e,d9153dd5,5d6019d7,b9fbc23c,39323b8f,6fcfbfbc,b1a4b81f,e7eb1bb7,2855f46f,5379c68a,dc4680dc) -,S(1b218d55,81d012c,5e804030,ed342308,29675ecb,e1608d75,1ac1fb26,434744dc,8ac73d03,b888545d,dd8d0321,afe66cdb,e8dd7c6d,f1fbc3d,74f7ca46,c551f357) -,S(d16f309a,820828d5,e2d30f78,2f055428,fc8e7bb9,dcedf9c6,34640c19,7562685c,1f27768f,9a2c63f1,cda9f0f4,132f41ba,dd48a03e,5e387abc,d6c73a51,2d1b23f6) -,S(75c161ae,1b38e93e,b623305,e2566957,a277e515,44c2fe13,e02ccb8c,c72886bf,384bd613,39e4e389,5cddf7e5,b0cce8d5,35c03c29,118624c7,32b75a23,a9befea6) -,S(3327a22a,c4891ceb,2a704a19,e60d04fc,64cbb0d1,dbd5a1c7,bcb2f4b9,8a1d0d2e,1ef62067,d81d66,8a7960ea,a63832eb,5c6fe33d,3ed99147,b7f68eec,cf81551d) -,S(8c9fcb52,65eb08d2,90cc1f6c,9c3d70f0,2b553119,2a0c96c5,f59231ed,370c4036,c986a64d,f3972c00,5618cae9,4a84e74f,2566fe4f,aaa0e2b4,d3f52e9b,4acee6bb) -,S(2465bc60,19bab7e0,72bfeefd,9d974124,19bf47c3,24477dd6,c83ea3a9,e9a3f353,675034ba,c62cc0f3,afbf5027,23127859,280e2b2b,91aab521,9b48a36a,d5bcf77f) -,S(3eaaad77,af1f4e6d,a267bce9,e7095672,c44deecc,a71ec3b8,c86d8774,ad06805f,8a3277fa,6247ad67,e6aab22f,a7e7375c,b95eea16,a055ca8b,32615122,30033ff7) -,S(21734e43,c3ab4ef3,55d36330,adc76a02,7fef2658,92c29ea1,a26972fe,48c3528c,e1d82d68,612ba50f,cba70f17,3cfc17a5,d2d380c8,d62322d9,e6e93d3e,475ea6cd) -,S(d21f30a1,19f86a54,2c7d74ba,20796cbf,dc6644fa,2327392b,3aaf9f9f,ada97235,22d5e9ae,2940960f,6722d2bb,c077d9ac,aa12b5f8,b9a404a,e28224d5,5b604f6b) -,S(41741846,c3c6355b,69e39c98,fcedb9b0,73a5b526,75ef5388,819fbf5f,ce1d00aa,3978dffd,d11f4f53,ae1f5aa6,a04153d1,e9ad984d,8feffa10,9ab57fe3,f58145f7) -,S(cca0a89e,6612524b,a9c318a6,879ef971,d346e29a,4cca7c2b,4619a1a3,1f567163,8ed2e1b3,587cb5cf,37e18db,e9a95ca5,17795137,a8215cd5,293aefd4,92b74dd9) -,S(dd3be3cf,83feca12,c3dbd1af,a9166d2f,138efa4a,297c742b,778da203,dfff3728,b0a156d2,93dc289b,94abc958,f17cbdf5,94f04cba,15b71ed0,197e239,8b56976c) -,S(6c535f98,868e9ec3,31135e87,b80aae3b,a0609455,8d426bdd,3dd400e0,344a3cd2,30bb8bb3,4ccc439f,c343d3cd,ceabc511,3efd9087,d17004fc,37f70d98,94e3c04a) -,S(338bec98,1bbaacd8,8b82a53d,d1ec2ea8,aaf7fcfc,e5f502c0,a13b95b1,d5fd9000,dcda1b41,ca43c103,f0c6b294,5f9e94be,be971eb3,12f18197,b4dc795b,1efe13d3) -,S(b70accd5,24961804,40dbb087,c3c11f33,f27c7e9,886aed80,b89b121e,8d51ada9,6272d04b,3ec35419,be43ecf,72824127,ae4fd87b,640a5a4d,8e8ea05b,5f3f9b6b) -,S(dbf05f1e,b489594a,146de62e,c9423699,a7aa2d19,93919b0a,2a26b53a,a0f1a033,9608352e,a1abfc2f,47c42ed3,8f1d2ee4,bb28ce2,9dc98325,eb137acc,36924d65) -,S(56e94226,a4237f18,c57b5ffc,cfe795cc,b11522e1,fc47d549,6dfad2a7,2f109783,f137a96c,7965b8d3,2eaadbce,d86abe0c,5ee79de0,9b94bf60,8d72a4d8,8cafb542) -,S(c206cc19,28af717e,63e6e7be,781ea37e,d7dd1766,f1553fa3,2acc34ea,c1157bfe,78963ba6,f03b670d,602fdb93,d71dafc5,bb5ec7,b541b9e3,a84d42ac,1a444e29) -,S(8b579cc3,6455002c,372bf1c3,21012fbc,c29e102a,9acb149c,93c651ef,e3dee157,9fa8c521,e2f911c5,3438015f,48134dfd,66fa5acd,8916902,c1aadb94,7ceab096) -,S(3ddca5bc,e582f08f,ded36cce,395f4672,9fbfe7a2,c9aa3479,7fd2e332,352daca8,d77a9165,e281ae70,f1e9a265,630acb60,bcb79f30,9cd926b3,550b6c9b,644e5e6f) -,S(ee7c92d3,d81c3d1c,6384c771,b609de3e,e4979ce8,84df6312,fff84a0a,bd5e662,f131dacc,28415d22,729f2b70,934ef8e,3033b7b,c5a38dd9,1a11e4b1,7843978d) -,S(b9f80abf,ab86d596,521bf2d9,cf500e15,adedade8,b51fd8fe,c1d8de53,f4191222,82548186,bb97991f,1f28a93,804cd0a6,378355b,f7c7ed41,4cd585ed,af0afdab) -,S(1ab67bc1,50fcd943,f0b3419f,e5de2969,fb4428a0,b90981d1,a3893c6,18aeeae9,56fb8eb4,4671006a,805e161e,6e3f2bb6,b0199659,667967cd,3c72ba65,97a2c39c) -,S(17425974,39a91dd3,72c09b53,68d9821b,2acba5bf,a5440118,ddb5c494,fa0a807c,1b73d3d8,5eaad3c9,b37f7451,2a7ddd17,97e10e71,b640a820,181757a7,6cd27cba) -,S(72b080f4,d8e812fe,b485361b,59213f59,cd708e6f,d2f7ee71,27af3d87,971633a9,5b9c6a0f,d7a6f32e,f26a4584,542c15fd,e3504935,baa7b48a,d67848b9,67229f32) -,S(94e5f999,b8927b65,a2f4d318,8e3f2fee,229e42b9,ae3e6b46,9f7ea373,d3f11beb,aa27336,204738d3,b2a306d0,4c6efad0,2ae3a431,1da988f2,c6c1decd,b1fb3c92) -,S(2f59f652,2f045980,833c45cf,ef8f3a37,d65ed946,9b3beaac,2167eff8,142e8a03,9101d9d0,60f1a770,9f604eae,4b4243c4,6096c041,2f861106,dc4b8d1a,d9f9b170) -,S(95a443a7,22a88b70,32194130,a349a952,67b89786,e33938c9,7bef7fdb,d211b54d,3d80619,399c0975,a67ea7b8,9a5f6427,ac454278,42f54932,cbf71711,3ae460e7) -,S(c8430fa0,2ce95d35,96eef42c,69f68502,100a29c3,6ddd1f46,daca1e14,4f382d0c,f26c4baa,4a6d9711,e6de2b92,5042c6e3,cadfe60b,93d4f385,d759ec72,5a32bc21) -,S(67504cc3,ffaedcd0,c5a2704f,af1aa41b,4cf489d3,5c23b6d1,4529f4f5,c49afa03,b3858859,b3749792,4d01676c,d96fc03b,37be7b82,aee57e64,a44ba433,2fd936c0) -,S(d4fd8a19,6a56052f,71e8d51,ee3db667,7465ea90,f8449939,be9d1814,86fdb56f,7fc64dee,2bf744a5,ba155865,fb722e11,f3087010,b566182e,8a39f718,922953dc) -,S(12810eca,7f3087,944d3dd2,69baabcd,491113de,99b36ed0,65520569,484fa7ad,f25d02ff,81ed030f,1e67e002,6680a3df,3f27edd7,76155966,6f043f85,f82c9e4a) -,S(b347e0a4,102d2954,cf3ebf6b,7c0e5f88,6a823cb4,c134897e,3169b081,8bd35f4,78494910,3eaf28be,b2d9732,f88dc9a4,66a8b5fd,cc50a2b2,8b347436,2e05cc93) -,S(54cf5638,7972ba75,48dcd07f,1bcc47eb,5d99c95c,a18de15e,9d2ac40f,1435b27,48558294,410d7ed9,9fb008c2,32cc6ae5,33bffa9f,3f02f0a,76b1f390,9e78e507) -,S(e75c0831,ab9569f6,4844f67c,3650f691,e1f84366,46a28613,653c354a,3107cdb,5e2da0f6,83cf019a,82e44f84,e7bde49c,5d477f34,fcbfc3dc,2a9a2a4e,3ead0a1a) -,S(f9eb5462,7d88b64,5899b177,99257d92,4570b3fa,59fca83e,1e302f38,5c524693,dd187873,9fe69020,970609f8,ca1ff56c,3aeac075,43e6cc5b,bcf75af0,2932d516) -,S(8890093c,5bbdd22d,69c91acc,5608e19b,59d2b105,b75e054c,8e873b88,59865997,1f18b0bd,e9b546a,9a2955ad,492290c1,a041b61c,7b534e1a,bcd4db3,b5148bee) -,S(76b95d04,88c9bb7d,2cb28589,f7f3f9a,e2ae24a8,33adf557,76bc3132,4bb80168,590b3022,81649af7,bb2cb0cf,fa0e90ee,13b97294,1a7a8748,bc9ce53,88744e53) -,S(8b3526c5,afd2a987,f8a04949,bb5695da,8b073b93,d8418878,28f9d49,2a6ff4f7,387954e7,60f2ce55,17213bf9,c987a9e7,f9b9b05e,c4677911,22e7a28e,777ab4f4) -,S(2aaaa06e,244684c2,571785e,a77a76f4,2c4bca21,14fb290,ef66d150,74ff2658,49e3135a,3e8ed289,4dcf61d5,7e4cce47,815ecfe2,5bb1d8a,a5d067a7,924fcab4) -,S(981b94b,be061268,c02db0f1,fbc330b7,351d6229,b645e4d4,3d908be4,241795af,c294f8d0,7b6c70e1,c18ce6da,b3d28c4,d53f3e9d,1f8d9ba9,de18cd39,51c8ff5a) -,S(53721e95,737d09b1,49eb185a,1663999d,23429e88,51ab849,a671c0,d86efa3f,d36f27f1,9f812f8c,c9d770a4,1655ef57,efc1f126,ecfea4ac,dd5bd42b,13e20a54) -,S(9ab129e9,a4d92118,3ebf686d,97286d1c,9608003e,67b026ee,d3d06a8a,e21c0bcf,4683a375,85be92d3,331732b7,8e12f452,480a9569,4c309907,2bbb9427,602ab016) -,S(330ed8c3,3c3647e,7b80f38,f3a1865b,d33abc8,ecd4d0d3,390e8ab1,a20d1c0c,5e3db6e9,33d6d0d9,43cb4202,f9ed135d,ced588f,8742556c,2012989e,768dc770) -,S(66c40c78,6933308b,9397f3c0,3c4263f0,357d0f8,a6a9eb06,725c4c15,c226d57a,697777c7,13cf3b5a,ca964377,fb124f87,81743794,afbb1966,4b126a86,9f90bb6b) -,S(36ce2c7a,9c7f1267,c081c9b4,296a191b,951415eb,12e95b02,e5f5d3da,47809b23,ffad6d8a,e00096f3,878f54df,5cf714b9,6646b5f0,9cce0d06,ea38c558,140223e) -,S(73fefc2e,ca71a95d,2e9d5d0d,464a7408,e38e21e,4450ce8c,51ec9d6d,79b43f52,cd47ba4d,6c2ed98a,c369ccf1,a3d65e05,758f7f70,1ca87a02,5baab12f,5b765a20) -,S(cac2c00,567cd06b,d4e98e04,e911f7b8,7d4fcc19,28a5b58c,635fcb96,bc7c0a8f,fde04dd0,3235a3c8,9b304c97,7889506a,c3ef937a,e1dfce4d,ce29a1cd,dd385090) -,S(f6eb390,2654aad1,1c69c028,2d1449a3,4198e774,3d329c3e,85a8af7d,f6219e1,6403deda,8911378f,7defebc1,ef7a4ee6,20802e76,499993e,15b22e42,3e492d0c) -,S(91a7da19,ecc1a979,7d5dd222,edd74bd5,af76d200,30cc27bc,41304ef4,578d8773,a32b1a26,e77631f9,6a3dfe17,ddf16ef2,f38f4026,4d3fb882,dfb34cf1,5fee2f1f) -,S(90c3942a,7b00bc3f,7b852097,ed4590af,cef6fbe,783fd717,9fdc4955,a4fed12a,aa7d174a,8d9f1292,b8e4d9d0,19dd336e,da305ccc,ab69659f,90011b69,85366751) -,S(717c0973,ee959e19,6d11939c,acabeb83,607f9367,83dbfe6b,911f30a3,c51af3a4,f93d840e,88497801,223992dc,24dc976e,dc0b442f,2f845650,4903c9d8,338c1ce2) -,S(831f9794,c88cc5b2,2d202130,3731371d,a0ab67f3,c080cfa4,d958e6db,aa85d140,46ed65d2,1c8b5565,14e83074,e84267d8,43f47154,8774533d,cc11e6aa,cc655895) -,S(f6c7e9f6,69447c19,843ff209,72c47cf9,5341e0f9,d2d5f14e,c9b17abe,20eacdab,1bc7e847,a9f2824b,5895edf,cde746d4,5ef0fb67,b7db1637,e62d2d40,e046650f) -,S(c0ce97e7,ccec223f,947c0db2,62fe3865,9e06fc77,99a41581,7ec36642,9d5f120a,dc281020,af95986,dfafdfc6,ce122d33,e797197e,c24c09d,7e6f04a1,c5b4793f) -,S(e1eae094,f68fad14,5d905240,e79abdef,562ac20e,d52f3503,db34b2db,d2f72d43,71e4754f,ca9df5ef,b3b86c88,7e3eba7a,33554a83,cd68ebed,f6dcdea7,fecc6486) -,S(acaa286,bfd582c2,c938ee36,23a20db7,5cb6f0d4,95419f33,b0b35f2,59841bad,c3eea949,18a16138,caecb54e,ac03b6c9,282006f7,14d4b024,2bad29e9,aea7f667) -,S(87f6893c,137f60ad,22a5d543,2dc2cb2f,f2e05fac,d643839,38936c2d,206afc82,f6bc3092,1de852d4,4894d318,aaff9243,a9a521e,501ca78f,c7baa82a,3a118ed4) -,S(9df94d49,e9508ab5,63ea1,16cc4502,aeed0bb,7b1db426,c6695da5,8da1f59d,51786cb4,a7caea66,39546ae7,5826dcb2,5abc5a76,402fbe9,b32432cc,aa48adc1) -,S(8a902a14,5ecfe343,503f46c9,71693677,80499405,5df02c32,9446a373,e34777e3,fdfaf856,f777d30c,24ce54f9,d503fc8e,a3cdef47,e292ec5f,f98d6449,a69b3f0a) -,S(ad6128cb,8d9903d4,23558eb2,23fa580d,e31c454c,d3985ac2,6a2854c,733c05c9,9b69c9e1,564c9271,5562d4cb,fc040495,6ca539c9,691e2f02,5f41151,ca6667e2) -,S(c2a2ff9f,6d064f4d,551cae44,f726a8cc,b14c9742,96725620,1d01581e,5375e57b,ae53fd93,fc405150,3d6cf2bd,bb51720e,7555cb24,ef7ee8bb,9ca306a0,59563e65) -,S(56c0fc7d,c2ae8f26,4e132fb9,3a52a634,2b80dd38,f329fe9d,1871e2c1,6529996b,5d012467,cd511264,82399d80,c7f8d248,d9267251,e4d18aef,ccb9bbcf,d854414f) -,S(2131bb4c,5014e751,ef0690bd,562ad29c,d8db4461,9eda575c,9f0f75c2,da4e0f32,7bbb234f,7a83afa6,47599f05,8ab8f5d2,83f1f02a,8f8d5292,15c7cdc4,71f03fef) -,S(e8adbaa7,bb0542a9,9b9f7598,59637f1a,cb734257,13247db4,540b8268,6c14a462,72de1317,fb5ed43d,ec57ebf3,dbec4eca,bef50923,a4743359,72aee4b3,c03190f6) -,S(827e8e05,2a084162,19c8894f,ec6f31c1,a7902792,a1e8cdce,6fa5f732,4b428417,d46d9c86,4fb85e09,81bd40b,b6c3a563,8a74c222,6e7c8299,3ef6b408,4aaff5b1) -,S(3dca9759,338dc06a,8e81218,4c14c82d,3fffc50a,6d0125d1,1af0523e,d14fd699,e6c98f39,b3fd3ca7,66ac5444,be93fe24,3085a38,7b484f28,da571afd,4b8ba210) -,S(3ceb28d2,e59d3692,63432323,c36bd680,f531697d,c33245aa,bc7c5838,52bb8eb1,d2456980,96a36ca1,7301778f,d1661743,f43ed9af,3968e4e7,55ab39a1,6ded2d19) -,S(47ce6c4d,c1dc8371,de44ee1c,828e4b3c,6ba040c6,8dab0802,417ecc31,1e7d79ce,2d6b7bc7,c43e478,6df00ca9,75268b3,39f0ad68,7b0c70c9,ca857913,485419e6) -,S(ad6387f,fde71126,d0784af6,fc8a1ca7,be9bfee6,176245cc,2a18c9c1,c17f156,3233a7a,d7d50605,8cb63aa9,becf9eb2,bf8fa88c,afb2ce9d,a9236736,803dda1a) -,S(8c9c591f,e2afc468,4b64d9c,44b92627,e70babb1,aa9f7f00,6dd5b0ba,4ae794b5,5ed4c9cf,30c7d1f1,ab31e9eb,8d20fd16,77b67152,44db075c,c9de1b49,58607617) -,S(2d601d55,1b07c8bd,10db6a9f,516882b3,1525d819,9df56324,cef2c40c,6753ef7e,d32e4bd8,eeb642a4,38a9493a,87824f86,6731bcf1,6c4b1f42,240f07fe,ff075a2e) -,S(2c67af99,3de02d6c,b9db16fb,7fa99fd3,6e32aff3,69e855b3,581af5bd,cf8f81bc,69fc1c49,501a76b6,e21abdc0,27aca6b,a062dc11,5cfdeebc,b8b98ea,ae35d935) -,S(a904b9b9,a0abbb60,4be04958,74b0bf72,5c1c21fc,1ad75b9f,99ed5d60,d1beaa3c,a2cc5370,58dcb26,6677e730,449cafa1,c0135179,4afa24e5,47b10479,a2590069) -,S(bafa5456,e50152d3,115d40f,b9571d79,7ae8fa48,97801c13,238d8b98,b919302d,8108653b,f4f9bb59,de7e26d8,55f72103,20eeb48e,9f127778,5f05ed34,3e63ac43) -,S(fce057b,560e9da2,7621d46f,bb709275,4a6793fa,eedfcd7f,9a782aae,e35cd9a1,c59891ce,d7c19c5e,7a841620,8d0d819,c8634bbd,2466ed60,214a726a,dbefd784) -,S(b8dd80d9,6b6229fd,d13dac50,23f53657,3b353efa,45016033,58a9bcfc,ab61fe7f,a72beda2,c2cefe01,eaf1ceea,714b538d,8b052eac,3df84158,dd3530f8,9c5bcd25) -,S(c676cd53,7366b97d,9a056e87,2bec47df,e2c35e88,947275b0,53212536,a6231c5,9d5fe80f,763e202e,6919c760,bc96c732,844c4c18,7e7a3a1a,a0760c29,80c076af) -,S(626a28b9,c897481,19d6c4b0,bab6e81b,9d6747cc,6c49521e,6f032f50,36c9fa87,f8373b3c,748231d,b8aaf580,90898566,27b112f5,6697b18b,3cd6a73a,16f2203a) -,S(d72eae41,548363f7,cf5b5b9e,ab73076d,650f7616,e7584fd5,1a5ff2a8,ce1959b0,c867515b,46c9973b,53498582,5bebdc1a,54181a33,74b507e1,f0aa21d0,7a6c0e0f) -,S(6e34489a,4ca57c6b,f3b8a98,dac3b2a2,995a7bd,f90acac3,b81d56d7,678920ea,efe88e16,e60cdf2c,3e6a07a0,ad323e7,ff9e731b,26f9cac7,87bf43f1,b3401169) -,S(a8214f4f,1ab2d150,b66eb9e6,f64ea4f4,6ae08909,9248663d,8491cd2e,90a56ae7,5d252b54,ec694068,a0944f8d,4e0ead5f,2cf0982f,3981240,5165b5a7,e4d628fb) -,S(76591c34,fdb90d13,14c5f85,e76e18c3,aff3aceb,4385011c,d4a74bc,b36f775d,f13c54f9,c32fcde6,94d29b12,f2a8d8fb,a99d19be,80ed9a8f,903b33c1,ae52a447) -,S(17d22fdc,c48ec732,afd7bf62,7fd09d22,d2989437,a8ce1950,3acc99f,ef2c0cf9,3bf80fed,48c4c2f2,f25ccee1,9a717067,976f108e,b1cee625,1fb6257d,f1788384) -,S(2ffd19a7,f46bc028,9b11d7d8,2b391091,e08202cd,95c7a4f6,fc351713,d3645b6a,807ee1d7,af310183,fa9edc73,4c098b90,5b0d4021,6c19b797,1429725a,5763d01b) -,S(63496320,c4eaa16d,ca4ed516,bcbae7cb,124af3ef,10969329,dfec9a92,22f143ab,3ce522ae,ffd08245,d5dd6ce0,17ea6915,aece97b9,9314d61e,2d4e9fbb,5b92406e) -,S(685a372c,ead446b,6f8797c6,dbbdf442,e337a200,1b09c03a,84dd523f,674c1e31,9436ad88,7c61bd79,d0a73f9d,1d06ca0b,37f19511,9d9f9f10,6a6d6d97,f0654d96) -,S(d1aa115d,ebf2ca79,61b1a13a,9f8f2f38,8367280b,c36f6208,15cab71,d235b866,9dffc173,6590390d,a2f3239c,f85ac4c5,3e842aa1,3ba035ac,2824a269,c7c2a487) -,S(d12c58f,5e20c6de,34a27270,d29ed5ce,c2a36ac0,8f2a1b1b,69cdf2a5,d501bc3c,cf7bd006,5bedb875,bef1861a,335457ad,66042a17,c9249006,60ee461c,db0a7de6) -,S(95d9af48,d2d3ad22,4ca83889,2d7f14a0,bb4770d0,42ecca6c,d71b9278,79e69898,39e47d1f,6acf9570,5755c560,22a8faa2,e961b25e,c5ca36e6,3a5ecf5a,e54a48d1) -,S(6e4dac4d,1b6d8404,e84152ad,f5d49de8,d269c9dd,1c66136c,65b8f78,5cffec16,62d1dd58,22c06f57,f2ccefca,31c318d1,175a3c60,2aad99f2,e5c63e2b,c8e33afd) -,S(d026e847,3e8eec4b,d9ffb21d,49c13900,34a9a66d,5423174a,40c8b4b3,4f6fe060,682d65fa,cbb29cc0,91a290e9,305e4615,5a5d472e,16d37c7f,e06a9a40,f578c58d) -,S(683bda54,87643e28,8799658,baee6ec4,73ca9c66,4a76c302,b26f5762,877e766a,d3d80b37,117d6b18,c04174aa,2aba0774,43fbb78a,2649eb38,e5798935,75fa237a) -,S(fe2f54a1,830a0d86,ba30acd7,d208f6c7,22e2deda,4e554a5a,533e8e07,dfc76f8f,6a6f032b,5bb03b33,3b28e6bb,30b2b04,305e0aac,cf53e2b,53f215ac,2f1ab8e4) -,S(2486b52c,511b2499,7ef5d49f,8098f596,568fbd0b,756334b5,d5f01852,191d677,ef82dd7f,9dd36f42,55b75292,40af86da,bbbdeccd,6ebb3197,11fb3432,236f5ccc) -,S(c6fe27cc,79f316ca,5a59acd5,911963e3,bd6ae911,c50bfa1a,f2ae8b6d,69ff8ef,70aa6fed,ba4c57ee,5b3b33ec,ab6efe75,e05b8b43,41c3a7b9,bca5053c,40292101) -,S(be4ff208,8334d043,2d35c9f3,806e516d,fae58bbc,d2f69565,ec461006,99af2be2,49de6b17,c8636af4,25ed00f4,228ecdb0,4208d18e,b5c9c194,d6714550,26396adc) -,S(c5789253,316faa6c,2f87f888,a8fa4312,42618ebb,37a5184e,29abf20a,e6b4aea4,77647e3a,e083159f,afe92726,6c60f666,12e4fd31,ace116a5,11678291,185df958) -,S(27d2c091,b2212a3c,b2a827d0,951a4bea,6994953a,cbfff146,cac83f20,f164ffd7,e9fb5899,d757055d,f0e273ef,c38cf691,e958c6e3,943aae43,85f77a14,8189eb92) -,S(94d45ebc,ce92d10a,3294114d,743db35a,8e2ddb7b,7f5bee72,7d093c89,15d98d45,802386db,bd731bbc,5dc793e4,88fcf20d,15be9024,b94d1d19,edf99ea5,ab1c0acd) -,S(46739c9f,6245639b,692a68bb,8587499c,43184d0c,f0ff467,7b264985,b4a2fb62,9f8f41d7,2eb951ff,17d4517a,3fe7dfed,556aeec6,be518188,8c39a57c,913f7da4) -,S(5c9f57b1,baacb2f,67f1bdb5,3fc85aa9,3293a2d9,d85d1f2f,f62ff40e,d26e8c30,6bcc8a89,7ebf12b7,2f397b5d,ba072f3,c91f413f,df14e441,ae2a2155,887c1527) -,S(9ccb3d34,4c813c15,e9b85517,95ddb04d,c3c790a3,a1ae051b,60202b56,b735f3fe,e24525a9,fa784ee6,2576fa15,6ad350b9,eb5802f6,e5d5bbbc,7f4217e8,73f85916) -,S(f0826eec,162f343e,4cd7e135,df33219b,507876ef,5d29fa13,d8fa2326,3e7ca425,649c1d78,6547e29b,d266f2b3,cb70b823,8e71d198,6791fb09,a19ee4fc,1823e02f) -,S(8b672a2e,1b76096c,80b87519,10b6a09e,1b7204e3,ec139cea,46aabe84,4302dfa7,33f05056,ab88de5,e036f8e8,5bcd51f5,423ef431,4faa1015,7eacfd8a,9db71787) -,S(93cb8f71,9db52708,986fcbc6,26679315,fe79d119,9f8abffc,5c02f375,8e5a50e7,ed7d055d,91843e32,4193d866,81551f5b,36b484d1,f0dd5fec,f59e51ba,57b93bed) -,S(da506843,86019984,4004a723,7ae11605,a7132e86,55145d8f,ce9e0e50,feef7d5d,260f6393,886e1b8a,93986894,a4a98fa2,61771a46,16d04ebe,baf8bc48,29816d53) -,S(2d469c5f,26610e4,6bfe1cc9,43cfe267,e1bd0a22,e451aeb3,e74f17b,b9ec2f76,1d702b5f,fe2101cd,f5a5cdc8,4d4a4890,6720ac6f,ca626979,d942c218,163474a2) -,S(1ea83777,5513ab9,cadd3b53,66cd9049,da1b01c5,d347f7b1,c8a74f6f,658cd621,b9e312c7,2dee3d7e,d6e67596,70c65bca,5bec92a,2eb82fab,a122ffde,5b1c7f5) -,S(70bb25c7,9589530e,f129166f,cac1d5d0,81083ed5,fc5b9b99,e744585a,1d6b6816,63234c19,dad2914,3e99ff95,a906a5f7,a48b3e87,2d45436c,8d987baf,a93b3588) -,S(fd9989c8,f68537ea,a3248b19,ae721256,ba8d0d2f,d825980f,f89bb158,a700f0a0,eb76c5d4,93e52d45,5d27a12f,fcdba859,664bb048,1686e67c,e79e40c2,e0160c97) -,S(f1c32c17,8b36e837,b058e9ab,ed3c65a7,e2c76397,4936a524,838a480d,b3089b7,dd4101fb,92488a78,480cb6af,6cf73dec,5aac619f,3bb42594,c3dbef4e,cc7a3a11) -,S(842d8101,ed396c79,b5b19779,c245dbdb,b1ecba7,9ad77d5d,f78fedce,f9d83f33,6fe77300,9117a404,f4b28ef2,57441145,c5afc6ae,2e655ecd,2497486a,fb1ebc16) -,S(6e9e1a2e,847fb133,cc92a79f,767a5ea8,cac887a3,16903a98,f3ea86ad,3e8cf24f,d71de5dc,12be0a35,b996d880,8442fdfe,4a6cd810,7fe29548,da99783d,9049ce3d) -,S(f6739fd0,1f5429d,27c216fb,2b02d871,7028366f,7af115d1,e154f87a,812b5e37,15186c87,f776c8a0,3532b554,1e1b583a,5a465334,45bcf93e,dcf539b,21663c95) -,S(c3acbd98,43bbbd8c,68f153d8,553a81c2,81dbc584,42edb9d0,e51d056f,2b80e2f2,8397a220,483081ec,ea7de090,5d063412,1dfbcc32,ce70379e,c58b33b3,20f39d25) -,S(aa9c8bec,c845e691,a4c3daaf,a9bf687c,ad733290,32abe151,a26c2a27,1fb94732,b82dd0fb,c53fa616,74b684f9,7da10e8b,77f1f7e7,388007d6,656988df,e18df322) -,S(3df35629,654d5b70,db9547b7,5373efd7,e1781dac,da11607f,e4f3c903,5493c8a7,56fbe92b,25cbc615,96f2cd4,10290da,239ec3d9,360b3561,4199b006,c2d2b54) -,S(bcc8b337,98973e00,771a1955,89165cff,83870f8b,a897b8da,84c1bfb7,57168bb9,483a7f4a,70c8250f,62105842,310ed427,168382a2,5d687290,d54e65c4,c83bb16) -,S(bd2b07e,a84da89e,bf5e39f4,d3f03df8,658061fd,8f78d5cb,99f488a3,e992b870,33ae1dde,77c5b467,f5b3da9b,c71a6557,b0cb3aaf,892d0e76,d9f34b40,1fe60c9d) -,S(2c55718b,87b4facb,8ba9a6d,287a2db7,1b5a03cd,c7d933d4,c6014232,ec35d05a,aab1de0a,d8e3f72a,ae822bdf,f3ff70bc,bc5aa56f,1dcc5352,d1f81614,f3f461dd) -,S(eb837dc3,b2e346c2,aba58441,8c84b20,d144f93f,841180f0,860f7280,a7ee23e,6a342fb8,38a63813,e279d1c6,94b2ed26,79c3dd21,652d5678,5f47aed1,5230137b) -,S(827719c6,9b097381,da18519,ecefa193,9a9eba18,189092f4,89bde77d,33046fb1,e73b0e1d,76e40777,4ee6fbf5,2bafe516,f6d94fa7,c7dd1eee,b3c36f7f,6429dd3c) -,S(2b0da4f1,23095370,1f1b9444,847ab289,5cbfecb5,800f2d7c,16e7a56b,c6988d2,fa8b4d9e,5da41962,68e10a3a,7d69b1ca,7963d4d8,cbb5fc1c,83239212,dbc340fc) -,S(95744eb5,13436e2e,877fb0a5,20d5f1e2,1e1ab59e,15bbaf46,206550f8,d5563134,5fb1c034,62040ef2,28adad1e,83fc2c74,57344c38,7b7ffde0,d247bd35,6b5ed1af) -,S(4c805d94,78793e63,4833e90d,d19822a0,ab7d263b,1ab67654,bb77358c,67b327c8,863cb8f0,dbca3c1e,4011928,e5827619,53df792d,449f8980,bd10cef4,472ab56b) -,S(fac22633,3ffa2cc8,93c434b,46fb0cbb,cdee765f,e848cb50,b1dd6e70,272e0ec3,6a6b07ed,46f9b9c0,86e970b1,d2323fa5,d7d66b0e,3ad3077e,da5766ca,ac5b500e) -,S(b9d6af71,c59f0fed,ca4ecc31,25aaa645,f78d43eb,79c22034,1034de56,f59ec4ef,5509e17e,3d7ea457,c428e10a,7e9d8bd6,69f0fdc1,165169bd,a2101d8f,6f4041b8) -,S(57a68137,90725717,2dcd8c46,3a9b274,69c5ef27,2ae2be60,b10b96e8,e6b47537,9f294700,1c04c06f,2e2e5aca,cf4b9549,265db1f5,74b2328,ef4469b0,1c2bcb98) -,S(58ee2a22,9aba401a,637c4d34,2b1ef408,d9f47c53,6133fcc1,de030d00,25e2f53c,d361b0e5,5ef24c74,94cb9e65,cd273e9e,73da6e50,f452f8b1,7d30eadf,32ceabc0) -,S(b8bae4e3,f2e22824,7ac9cd8c,a68632e5,1bb13d4d,735fabb7,305a8169,31b0e34d,ae8ed4e8,6ac41b60,60ca3423,fe6bffcf,a7f215a4,7076f270,a2d1017b,887b8002) -,S(a81d5e0,f11549c1,373b4c02,a61c8908,dd109f4e,7f0cd250,a667508b,aea3feab,8c6cd790,4cb4bc0f,7e56d928,ac362cdb,f096841b,dee9dd48,429c52e7,23511bc1) -,S(fea67ebf,f8f092fb,dbb3110b,77d6981,efaab5c4,97a23c3,42afe294,64f4746b,1dc947e2,94b0fd7f,952a6d5e,1f5ddc9,5f0acde4,de8db93e,41f37ec8,965d4310) -,S(4db2ae8e,6b8e674f,2d79e1a2,fb7c7d10,921c9280,d8eff92a,df1a2b02,4485bffc,8ed56cea,38c2a96f,b6e0ecf3,22b745cb,35c43313,9b3dd28d,9189a9c8,9f2c055d) -,S(be31fba,3995348a,78303047,24ff117a,48dcf5e8,72356d03,ac059306,fc5ae314,8bf72f6b,70189284,ecf86059,affb4a2b,c7b5f923,d7c34429,6f401490,5a94061d) -,S(e8d716d7,18078be7,78535c20,4f9cb681,e8f49ac1,85baf865,e7b78e19,58ee703,2c79f768,c6d3bb3d,b0923d19,74647e8a,966ce69f,d06a8fe7,5601e51,61f49f85) -,S(20ae34f7,f3497d67,6b0496fa,1a68178a,f4fdd57d,15131ab9,c60bedbb,1a840070,21fc951a,2b29ab95,994cd404,b3da37f7,d21fa790,820339df,84f17b50,3572edce) -,S(73db09f1,3c8e7bb4,48629f24,83d56f1d,a207617f,454edbd9,d51ce59f,b7ae1ec9,1e4e5175,efe03956,cce3f160,791595ad,35bea993,139e8967,f591b973,785dc29f) -,S(14f5ae1f,af20b6af,9953fe91,db5bc192,31f302e6,cc03a265,d661b25f,8f07cb18,b790b1d5,ef6ad5ef,97ddb309,354756e,138f4db3,208a873c,17cff3a3,13a8be2) -,S(94ec6992,d2531cdf,3a1002cd,efb12e68,868be66,b704dc26,3dd422b9,9cc379ec,d2c4e479,ce9e0227,4d9175dd,e2a42639,67ed377e,d0416101,7e41e8bc,8adf7fe3) -,S(f73b5edf,c8d60e77,328279af,ae99381f,4ce0de22,17a4edd6,4c228b4,84816527,86758bc6,f44e1204,68555e71,786f7d50,da7f9c72,665a7475,e77c32e9,dcb13419) -,S(94b51939,45a518e7,c602570f,863902b4,385c8e76,c335cae1,b80e1d0c,e118b573,7c285008,4d398cfa,24c5cc6d,879868f4,d8eb60ad,ffc77214,5debabc1,3f154ea2) -,S(26acc055,2fa90d45,1dd6f2a3,9bd46a9b,99b0f66f,3e6e72c3,16e09e52,f7b265b,997dd988,5d5b15a1,957e1cc0,a45518fb,b0e1f847,d58fe9de,9be95273,cbe61b00) -,S(e8a5ac01,959edc90,2050922f,af51365b,ecebc967,8e57cac,420faa6d,4e2fce98,2c2998c6,fdd97d15,fd0cd228,e9975064,f2576316,6e61a45e,ae532481,9dd96227) -,S(d903bdf2,5ce9e855,60f63d72,512626fc,fee11c4e,304d249e,e13a4b69,60f95019,1027435d,bab3c246,c93897bf,ef7779f8,9a165595,a7c9c536,176fec9,1adb645f) -,S(eea105c6,fc04a751,cdc27e40,25f0d50a,99f8d01e,1110a505,eb95206,922e50fc,b93db8cd,b914dd8f,2b57b907,4df41e9a,d8cca9e9,c3a9754b,e8473446,ef3a6c68) -,S(801b116a,1fc2c2d8,fc8b412f,e9b1b7eb,b19f4e96,16b420ce,16f1b4b8,dad235f0,53def02d,8a6deddc,250de95b,d6a96d27,1c197d36,e137e640,4123501c,15fbaa9d) -,S(db3b8667,1b0dc54,436520fa,c8d437cb,7a4c23b6,bb3c3cbf,dd34b605,af406939,36562d35,a298b620,f7a06498,b1032f4a,33cc3b3,ee185e0e,aa8d3e4f,3ec5c481) -,S(7bb26eab,8b808402,a9fb3fa3,8f0e2f6a,7d82d7c7,eef75cec,43594713,dbc17706,f4f86283,713738b2,a9209e49,f82ae1bd,9bcc908e,b9565546,3a8a5dd,8d0c4b9c) -,S(e89fe301,8d87bdae,20fee2ec,7a3f6cd6,cf932d20,a026e1bb,a82f9c63,a47b97d9,92a7e80e,e7657ad7,c72f471,8f0c28ba,acfc748d,a6090026,1191912d,32b8a498) -,S(c9a10a8b,14d1845d,be6eb6a8,65cd2ce3,a4d0be4d,fad24912,b01fed8f,8bc812da,5852b791,85afd22a,6f9ab486,91340dfc,e9979cf0,bc9732b3,637434a2,25001d71) -,S(257df2e8,cf535cb7,954b52dd,7e3ee08d,24cd4415,d1075dba,8f75bf74,74afad3f,f72d1e76,d4da3c0e,5b41fa82,28639f2a,f4e114c4,94073ddc,3e8fb2aa,f82596b7) -,S(3c64aa9e,548a430f,a815bd54,713ed69d,bc32a0a1,30ae7ca4,1541ff21,a5314886,8377911,7426e30b,dbf84c57,b110cc3f,df5acc95,7313cbc9,86e895d,6e0ec912) -,S(cd509f83,3b65a7f9,671b9239,c5e71323,f183e956,2c2c115b,751046a2,33424ee9,579243a,c7fbd433,81cbd0fc,4330d087,cfe0c41e,449ef82e,12def6d9,8977338f) -,S(27adfe4,febc3501,3ca7a0a0,b5f7e525,3768df69,9d236f63,9ab80782,c2d426f0,97cb4e7b,73b065a2,499a1675,88fc116,be5606f,80619d42,ddb63286,4d20521) -,S(ef5bb148,98dd6802,6f25c363,16a34acc,c6131851,a4efe8af,219fcbf4,13a45207,49f30d08,291e60f0,975c93ec,403d2a14,3742aaeb,3777cb9,87ff38ec,b51967af) -,S(58df8d45,955e923,ec7fc327,f8081ec3,7ca6e261,7fdf7785,6eed51dc,95057034,cdfca79c,92dfe719,2ec63f6f,f93d211b,d7cdcf69,4deac173,d3393fd3,7655a310) -,S(2a4ca8d3,fff5ac47,bce452f0,1587a769,443e66c0,164558b6,301a6a2b,d3d44270,ed73b405,521274a2,3abe589d,c5ecd607,b6467691,f81e3c9e,6a2096db,2ec82366) -,S(84bafd1c,7c6072cd,fce244c4,8ea004ad,9b8e1765,bb8796d9,118d6dcf,a5ac58ce,86ab8db1,7c26c921,604a3c3f,f0155a2d,14bd7274,16f9e319,efb68f50,2b636c00) -,S(c3785528,7cc4e3df,f5e95951,c5bc5964,28705a12,10927e89,890726a2,ce00b657,302ebd13,5643eb43,f0bd14c3,65e385a4,c9a177f,96595054,3c3d96db,69ee8f79) -,S(c3aa3cae,efa22927,56c72aa,53507474,50f7a64e,2df1bf64,333d0402,5dc87d25,c2eed94d,ff9c5cac,248f77bb,9e189302,286db019,64214d71,1a199119,4818ac4e) -,S(443b9c8c,7d8c4f7e,de7168fd,666e79,5da85e6d,6c0f6448,7d349de7,66acff4f,2d4f1d59,b0d1688c,9fff0f2,f80e3434,db72d76e,6ff886f0,63dd63fd,e192b01e) -,S(2afe7ea8,688081e5,ee8a4ae9,87aec6d2,ede5ec3b,ca887bbc,1461709c,bfc6e5d9,5c319df3,2556ffc2,56194b7d,eb46dcee,59208922,1e55c384,2a03ddd8,78add90b) -,S(c62004ce,4d82ee0c,e2edb82c,e0ca98fd,413bbf44,55b96624,a86aa252,c346af6c,b68e4fb6,88f78331,bc2218f7,6a5e43f1,cac49fe3,4c5302cc,d6a3f1a3,258564c9) -,S(f759c4c6,e0bd72a3,9aabbb17,fc62c900,d57e0b5d,ab9ecce6,8f439025,2b17cd1e,6dfaaff8,5f9f3990,ad2c55f1,3c74e3aa,aa0f10b2,90def714,229cd3da,d5d18d98) -,S(b527a6a9,d27d0a1d,5adfc1c1,35308e5b,9a805638,132f61d7,e5e60709,ac3a9d9,e387f69,62ad151a,d920c82a,739af00f,628865ad,4ca42405,efd87e89,55b91042) -,S(ba23656a,6b0a5c57,f9a00d6a,9e6a331e,cf0c8097,3675f41c,7f0172fb,caf4eb02,b48ac68f,1a108de9,18d76d4,95a811c2,b7614aac,3c5f6b18,f28de8cc,7bd4041b) -,S(ad94ec6,fa161fd1,60dea3b3,2c63a480,9f7bbb91,49de206d,8cc61306,dbd18aa8,5240858c,ec88a022,7c1c12a7,862b4d18,e5acb344,5d66bf85,79ff9fc,ba866a4e) -,S(db4cc48a,de1bff28,c8987eb4,d00e1c5c,4c49fa6f,125d213d,bd814c34,cb81adc2,ffd64cf7,3c62c097,a2cb3b84,c62bc32c,54fce797,74479146,7b9a2cb5,d6f821dc) -,S(27d276df,fa39d889,beb0b586,42a0e479,8057760f,c392d052,6751f2bf,d0c75aed,c670b966,575401a2,a790440b,e5e5db56,2914aa74,e8304e3a,407aadc5,c87e12d8) -,S(7663e9d8,e34b525,b336587,eba3678f,488f95f0,6e9a6848,d2e72d35,36b569da,472b1c5a,8ee189f0,7a06addb,e6a8d90c,dcb87039,aa35e896,79143547,34e2786d) -,S(b2c81e15,1c1f8ef6,51ea1810,97eaa280,7e3b4a96,fbe210eb,b49554ad,6e0c0c4f,2d914319,f5ff59f8,c7038de7,dc70d1fd,6c4434ca,e5c0451f,4fa99f46,55bf8e4c) -,S(25131e21,9406fae4,ab96326c,7bf22892,1f18aa90,c52f46fe,b23f90ac,59ca570f,2e8a380c,eed5d51,6c190251,4937aa0b,1f39d3e4,42ab2537,e9e8d9aa,396e4c20) -,S(c2694b68,8e33025c,fb9929a8,c7ccd1c4,7fc5811b,9658ecb0,f41e4558,5d9a0c3e,c443d593,e68abc49,cbaa92b1,757ab2ab,c30671d8,4699a5c4,85a30b05,6b1ca701) -,S(8d528cc5,17a371bd,9605d8f4,e7f030fd,8a82d489,5bfffb9e,fb11f63b,be534fd7,ef2f16fe,64ceab2a,d261bd1b,314ebc65,4b4127b8,643466a8,f367b991,d28795d) -,S(409e69c7,62f856a2,4b6e80aa,baec8496,33b75c21,8943dbd,7280bf,e917b032,7f049016,62884d22,dfbda29a,c8061b7e,b82eb94c,13d7efcb,77531f8f,980babdd) -,S(82c9b4b0,2451fde7,8ae877c,ed9af540,1ec0e258,119e27d4,1938f71d,ebae71c8,212d6e4,99b91fd6,372db1a9,4ce3fd9,c5443b7e,fb37a566,f0c5f54b,fd8edae8) -,S(6c9fd728,37a39ae7,1f0b5852,e5c09d7d,cde66ec,e8f19a2f,2ab46fdd,d17c7f88,430d3385,aac729f3,8ef5ed,922e709a,73df8e70,eb9cdb83,c41e5958,272e8687) -,S(9f012582,e527901f,ad1f350e,1a64702a,ca1f6670,e693bea8,fc3eb0fc,2c090329,a2fa07ae,c15e9457,b2c75e50,56c79a6e,a4c8f431,d3c720f0,60f7b5b6,da6e3dfb) -,S(6a1a49b0,7b2b61d6,474834e9,953aa455,63910582,57db16bb,406b600d,bb01300,d4b93b7f,66ace505,cbbc2326,ddfa2fa4,ebab145c,ffbdc2c0,606e2ffa,9dbb41f4) -,S(981d0638,a585970d,4b12e577,95e76c26,1e10d65c,c5a94f19,43560d10,472fc9c8,f9babd66,3d02e030,1fc0ed0f,75cdaf94,fafc18ad,2cc68db6,d2eff7ca,e6c013bb) -,S(7edb47d2,b6295063,6cdda3d7,169b4296,3616b6dd,79e2e148,609a7722,476e564d,179a20ac,a6deb286,76fd466f,be78c3b6,789d31b4,91622149,4d7d634,d4bba999) -,S(51867800,4bd8a43,8f180cdd,efa17ff6,e16e29e1,e5fc4ef3,f5fb9bd0,bbf14ae3,306cc2c8,60ae5871,8632f94,c9acb7,321ba1f3,5092a0b5,72c33b9a,cd8cc956) -,S(bade1926,d8b0d136,69e056ea,ea46b2c8,2bf0f0f9,a25bc481,8a40ca8e,201500aa,7ac76679,c9807217,ee802773,dde582b5,6f0a4b66,f6e21764,285a6a81,4d584502) -,S(87815e7c,d1e5e88e,eb882b23,955de59a,d63f14fd,457a8d96,4b47a611,b3e40043,ca82343d,8e2eff9e,314ababb,15cd03c9,6fe6660c,421af876,63500d49,ade0d492) -,S(77d815d8,886cbf43,c1b4ce94,253e93ef,767bacc2,42ba7c1f,bfb7ffa5,308d855a,a8bb3f95,37ef9a77,ad7e282f,8ae05ab1,8131e59b,46a67c3c,7e85ca00,a2d3e1fb) -,S(49079a0a,7d9d9add,3a17ea11,747c8baa,d0922a7a,e766e5e3,fb80ae0f,dbb7d6a9,162b4e23,58f03e01,b4e09264,8cd0657c,f2cdcf54,f6c25d5e,fe7330ce,421e0093) -,S(28d61211,c183ccc,2b08168,5a4487d1,57bc0714,d3ffb16e,96bf0768,ff8075da,3da98c13,a2d1b07,2ddda165,3fb68a21,aad4a9fe,b4536dc1,507dd78b,7e51e0a8) -,S(40c34a4b,6196561a,d4591c49,df51b8e0,4106e545,26092e88,72018720,41448080,7a6e7478,3ce7d82f,b83f15e0,b74ae6d4,435593a1,67da6f57,f2e285fa,8c107e4f) -,S(88754e6a,e12e77ec,21e64cc2,bfaee207,f5c882df,80c8b15e,983fb1aa,99037c2d,5ae10e7c,e7464c69,472ce85f,5183a836,6ed5b3a9,1fb1af7b,d5078c76,2512f37c) -,S(8bb7094f,ed62beba,d628ef9a,84a0679d,7e0d2b45,a655fa3b,68d9a6ef,b24c738d,9f5370da,993a3811,48ad4da6,2d7845ce,4cc81766,f26189c,2199ca73,4312d102) -,S(79814e63,7bf2cfc1,cad39a36,b06fcc4,f7e865b3,ab2de1f0,c786f9f6,40dd80ea,aae4d149,f1e44635,e4800962,f533eb38,5f067114,3bfb87ab,9e68e27c,b56df226) -,S(d493573f,93018d4b,8599b54f,848c3afb,816e098b,8e218e2e,6304baf6,c726513,383c7ff9,b3ab6472,ecb80f72,2f70feac,7ff26989,bcb6f984,628d5eb6,a409b9ce) -,S(59599fc8,7d6a7532,5ce8f205,204596bc,4cec40b2,f3eae8ca,4530053d,1b7c731a,7a8d91e5,5d989961,889949a4,bbb71e17,84055697,b396a011,eeb33889,88f0681d) -,S(4a834ec4,da3c9afb,c62fec5e,898aa2c9,5a835e60,ef199346,3e4bf255,e32df096,8736155,ecbec836,e8d51d79,9176a5c6,6672aec9,548aa63,b7f5524f,6b20cf73) -,S(2142b447,f2707c37,45e877dc,8039161f,d222c69b,9236592c,c1b3f56a,d30a975,9a48f0a7,1ebfef1e,615a7d5,a9decf8c,70764133,88b0e57e,da554257,256e41d0) -,S(c3831b8a,eb58dd77,e21762c5,f2e88035,63fa8b1d,f5d1fab6,3d012fbd,27971797,45d1f565,6fb2779d,6ae18e96,4d9bdf61,924a5f6,a7dfbecd,2224f1c5,70292f46) -,S(a09dd11d,b78332da,663acf08,c08b3d45,d0f4740f,5df66e39,d53e6c68,f5654040,649959b5,bfdfe8cd,45fc89b1,ea21cff5,94f6083c,da8f5e5b,94525d22,3e326217) -,S(53b22e4e,8a17b408,6b119087,2b8fbc9d,fc667b40,223ecd99,27cdf4d2,a9dadaa,87eb7fdf,b9c6e23f,e7c6a8d7,fdf94438,88c6c0b7,1a3728ae,ca8e83a9,4403bbe9) -,S(7de0aeb6,d3c264c7,f39b087a,e62dfb5e,aac6fb17,483bf33e,bc34a903,f0ee35a7,43f92307,6a2205a7,f2f0737b,2167863c,43f3cec2,ea3abe32,9bba3792,6f070847) -,S(ef20ed3f,3dd1cd8e,a610f1da,64086eda,a4a646dd,e2bff224,ae72f069,f341b532,c3477d8a,a0acf4a1,e9c83a1b,c890e59a,1b739a82,55d3747c,7403034b,221fd0f3) -,S(ab21ffa5,3c7baab0,4ee74647,5a5e5800,dcae9a10,644c84f3,a108cd41,cb0dda53,3a02b102,dc21cf05,3abfe19a,2747f34a,35ec6347,ccf02880,5aa95119,110cdebb) -,S(ee8aa184,532ceae,2c3a5071,d905c6ba,bd1982cb,391151f0,fa869339,aaa50ad5,157d9d2,be135082,9eaf2c54,94e6f90f,8a82ad35,2d486dc,58068cf1,c96a421e) -,S(6b234cdf,fed7575a,f1cd7ac0,76c4251d,5853718e,2ea07c04,77959afe,5c0af2ce,223c14f3,d3d61375,d104402b,bbd51026,a7644b15,4f4d254,85e9a4a6,e8dc2831) -,S(e04eb879,7821557,a875d846,75496d9e,420ac3c8,6e718e45,347a616d,7616e836,59f33383,8354990f,2189cec8,af523611,df4a1b30,3001c5d,84e1de70,bbc6bf31) -,S(6b8c79d7,791e8423,788627b7,a99be936,145a8eed,178c8bec,affa8a2d,72965da8,28fece24,22f67bd8,a2d6ef6c,66fa51b4,c4abe766,7480b520,4f77bd8b,2e3863a8) -,S(d21a9136,eed220a9,708c09ed,2b22f5f2,87868a1d,493f6ed6,2fe9a455,42a4da0e,efb15959,cc7a2c02,7ab7f5f6,ec8a538e,91df38be,f78de45d,dabcd8ef,9b5394b) -,S(f950b37e,a5bfc8c7,a76ebefb,f228043f,de066a1b,cbb30688,b73e085b,cce1ce6a,6bc569cd,609a15d4,28ce7874,53ab8d02,fcdc9c50,c8c44016,ee2b62a4,16849616) -,S(75a72a76,520a5f29,368338ec,fba063c8,977548f3,7bbe08a2,e1ff5e97,88b9bd3e,41c140e4,5e2be58a,dee8af9b,e64cbe8b,4c82860b,98299d52,3b27737b,3266f978) -,S(4474da75,3d9c68d7,2218648,1ce835ca,4e17220d,533adb53,38a1978f,cdfbc3f9,b5e2d3c4,ae2c8276,5a337068,58e76666,52a81638,27cb6b94,3d2b80cb,36ad3eb2) -,S(e3f3e682,fd38b067,33f3e91d,585f3ef2,aaf90409,ca125479,b93039fe,3437388c,aaef5ad5,4bfddc87,f7c3f969,94564ac2,27e6d5ac,ffd345ab,246ee2d8,60d9242) -,S(140ea6a8,ad374157,396b064,f7a952f5,358ff408,951895ee,b66b6140,d969afc7,2f340af0,b08a67db,e6ea7535,581b763,24308f37,6015de2,a4dbfa64,1990cc78) -,S(257c1e04,2fcceda7,9aac2bb1,1f01bce9,37b445b2,bff51fcb,555395d2,d0c16b89,73b21d9,75bf23f1,aa0efe21,5141bad2,5a235978,e36645d,8503a60,3956cb5c) -,S(c243452d,664d2610,d1acedb6,ab5201b9,cddce44a,b9320806,4824329a,e0b7a550,50607848,db2b53c3,c9ed2b4,8c0adc28,322d2e,1b30c3df,1ab9dc37,64b001ab) -,S(a0ae37a7,3aee0e63,c0ca3e50,e59a660f,c7ced178,10dcab26,7f91ed44,3f265fe,8332d25b,94e0555c,21ebab61,cd209599,bab277d2,fb9660f1,f237c9bb,4327668c) -,S(2e4886d6,678f10a4,460b4ca4,a9964125,413a739c,64b6abb9,c44f675,1b47dca9,96f6bb70,9602de31,1be57a61,966c8227,e5dda6c0,48d3f1d3,bb5bafa,fc1e8de) -,S(855b47b,efa7dee6,2452a602,980258cc,de813ae4,6f580a46,d5d18432,5b423f8c,c27f5513,114fea7f,b5a405d2,3f25915d,775ac895,7fdc6e74,2d968bbd,d86c181f) -,S(dd360b5,38fe460f,9d6ba828,e2ac7973,46dc386,de05022f,fe48e891,a115e2ac,8fbc127c,d9e79454,a0be9bb9,cf25b7e2,71a02e7f,b4c68653,b7e08329,747cd68f) -,S(993aa6eb,47f7713e,e6c5bea8,1a65af55,1036d0eb,3df8a6f7,e091c16d,3f424c7,8478497f,a774307,d47ed357,35462f3f,a680eb87,fda11107,275c1883,e859ee34) -,S(4828feb,5e3abb4a,2df7b990,e20e1214,804ef219,4cb8acf6,cb8e85b7,5696d961,d8d2636a,6b664b15,f371ab5d,3ff31279,f7c42678,ff380ab0,9c220b02,6ecf3e3f) -,S(fb8dbd84,64bbb5b1,904a2610,2321e59d,ee9debbd,afdbe585,3e1af139,f8fc472a,54e088c0,91a67284,6c81d136,85b4edb4,391e5121,3c4d35e8,47863018,62844742) -,S(851fc8f,cf378f62,5edb262d,e0360d2c,2e9566c6,93abea8a,aec29e5c,275ecc9f,dbe6025,e9857155,83b38b7,a167adff,da70398e,85223a6d,9b940fa8,30a9d9e3) -,S(4d5d07c4,23079d83,d001c000,8c76fb6a,e03bb39e,325d5794,b5414b,46c6777c,d1c1e970,5b80fef0,8450f941,1b8d6197,21f1491e,87745c26,9458d58c,18d14678) -,S(8164d5c9,cc72b489,b6a54e8b,d9cfa9f,8496cd34,3a227a74,f37948f9,5d35340d,90b51776,9e8c68c9,20f5e948,755b4da3,2b294bd3,eae81da6,e0c0b287,ce229bf7) -,S(19a42dbb,9ff7a400,aa821c88,807281ee,ff7df5c6,e047cc51,9693c191,6145e00,369e9596,903c35a8,bb38f4d2,a74da3c3,cd2246d6,b0391e98,e01d6101,439a1018) -,S(7299deb0,a9b7bb52,76c8acae,37ba0ee7,bbfc9c0,7845765c,136cd762,7e7b7f09,8a0a1d16,f00e3090,cfd9cae,d8aed291,ebc56d97,66a131a1,4fdcf6c9,ce6b49bf) -,S(12c7adbf,112e7718,a3ec6774,1597d6e9,87763a10,4350650,e6a804fa,507ecf6c,b3eced7f,bc3073f2,5f86d647,6d822b8e,eeeab7f2,1b3263be,615517e8,ef3b1a64) -,S(b2d76aba,c1af6c6a,b4840b34,db1125c8,d5baf2be,90dc7e6a,52edbf79,a4b0ccf6,92938b87,641e0886,3f22f5ef,e27f9b18,80210d14,312ea6a1,eacaca0e,58c0f73f) -,S(818baa52,8251c326,bf545ff3,a56596b,58e0b525,64ae359a,c1d5199,4b52106a,9f8b4753,a7b56b26,e0e79b9e,9ae5f30a,64d0ce27,5898bf3,c0f12e43,faa69681) -,S(e08080aa,21c9b6ba,da128bad,62dddd3e,e8e5afc1,c460b997,45eab92b,b1663a80,2b878efb,95a19892,8b3609a1,cdbbc1ad,d1530a38,b528539a,c52fff24,2c382dcc) -,S(7a8486a4,1d774bb1,32321247,f7b87964,1b18a621,508f5376,99b31798,490f3e8,ee8c3085,5c3fa5c1,6f90b68c,89944aa8,dcb824c8,c37a0feb,ac796403,15ee96a0) -,S(f74e74f1,6e67c1f3,f5952373,e53cb85e,650a6dae,2302f495,f6882b9d,e2b71cea,1b15103c,8566d2ee,cf5c59c,dab607e4,97075e30,1443b75,42620545,2d1d2bd6) -,S(3ab4150c,cdfd6793,5f8718f0,dc961126,114a5d82,e1791c2d,48740425,8e8ba004,2a6c6f1b,9b546945,f9d327b1,437b1c58,30a48eef,6a14887a,9d8ca24c,c6bc446d) -,S(effec0ed,bb80580a,7bdf80cb,38cf775a,43b786e4,2c80d73e,7a254216,ed7ab7c9,c7c27bd9,57c996e0,42ceda33,2d0b5972,91ae5725,6df77e82,48bb1716,127c582b) -,S(5f49ea21,4d80f735,fd5f51d0,55d4e2f0,fbf0f804,a8f32615,340bd6c1,65a059e1,72e0f032,83684df0,98e740df,bcc39d61,6956ea36,275ca5ae,dbcbd682,510496ca) -,S(2327c29a,7f906,4cbfd900,43d28618,5c555bb9,bb64bab1,c3e20417,4cee2591,db1711bd,ac9095db,39e3d2f7,d2b84129,41dc6f8d,116115eb,7bfe710c,13b9e41b) -,S(12f2f427,64f77c84,f8a97c5d,7743bd8c,cd0c6132,5cd10fd1,76975a97,b447991,713e4660,cadecd98,3b0e4986,855c2c67,bc220334,2991a18c,bb0c08f6,8282b246) -,S(cdd3eb6c,b496141c,b99bde6e,a66b2c78,7264e6c8,74efdda,5ffc53e4,b3292a08,d1270d9,7cd63394,b385739f,4da31dc0,80f410a6,aee164fb,8147b7f6,9f2f1cc9) -,S(2ad4df2,1ff316e7,ce29d76c,da40cb7e,31aa7e14,49fce23b,93f0d096,e1b74159,972c77aa,160c98d6,c64dd9d1,4a0cedad,875e09b5,b0d5378a,7311cd2d,a7d641a5) -,S(df0ed61,d6c8f906,f970b9af,b4080368,2f12127b,e318575f,8e2111bd,514c33a8,e9e67c4d,7b1b0fb6,fa0a4640,62d72f,28180e6,bc8bef1d,60a1ea79,2c4f259) -,S(9572faff,160577b1,83aca01e,45d61647,7dfe147f,a6ae0b26,ca0264aa,23d2870f,b7de270f,572e1503,8a4a9b3b,706eb7c0,2a6e5e56,ab0f73ce,9f4b7926,a79c5c5) -,S(52583f1f,1d51acb9,bd25b63e,158f66b9,8e021432,427efd5b,bd629594,ba951264,3267373a,94719487,344c9af6,1eb4b726,a595bfd3,41d78b33,f3db8897,7e53427f) -,S(c95cd125,7e59d04a,6d953d7d,f68089c0,c29b6a28,90ff264f,74b469fc,af7cfa58,f5c7c7fd,82d3fd51,4031ce72,657cffd2,da83d072,9b0c4d6c,66180214,9e6ac90b) -,S(67a190df,e1a2bf4e,cc23972d,24d1f13b,803a9b4e,5c1f3cec,55d2c2c,3b0b2487,5c35f795,c29a2f07,74ded776,72ab5a7d,45902f50,e76a229a,212d580e,5edeb8c9) -,S(7ffcb588,ee9192c4,3bc5bd3b,4d0c8211,28c3f2a0,62ec3b0d,77752ada,69f468e3,9204301a,fd0ecd0d,26f49878,47c42c70,e526f7d2,e69a97f9,2aa1c357,d4140a8a) -,S(7d693f1e,6e35e062,83f35910,3c1cdd8a,5279c4ad,ed0edb63,d6c574ea,322e91d6,a9042da9,ff323c4d,46b2b40a,1d44970c,92e3cb32,ddd8dc21,d32d609,c5611888) -,S(7e0e5dae,8ce3c883,49a9ee95,fb357694,a7bd48d0,f27c2eba,49896e4a,3da04fab,a397f8ac,dd4077f9,58d7b5fe,28582bcd,4c46d1ea,fa253db5,18fe90c7,61dbaa4d) -,S(715ea4a8,e5eca76e,48605688,560872d6,7a499a8f,e84f715e,a91d724d,71fc0f06,9a7b3eda,8b82dcb4,60ba3515,18c22f59,fade0636,dc893050,a51530d,77ef8501) -,S(52a9c85c,ca99e4ca,50f5efb0,118fa604,b7e789b6,b589a5d6,368bab11,44c8dbda,3796e4e7,87dda75a,59c7503a,f27732d,8c973414,c1ea0a90,fb6cede8,a5066fa8) -,S(58f1c65d,ee5ea200,57644796,a94e4a42,771c827,fe032116,657e990,b56e42e,7f12725d,388a22e3,4f191714,9f48f0a3,3d537c8a,1037247c,de0594ea,a11de507) -,S(3ce165f6,5f569bb5,e594110e,ef91f30b,7e330586,e86cc4c8,347d1ab0,f4a8eda1,90480327,7376335,72d92c00,10313f96,9a0c5d18,c852597d,1f88020d,f69987bd) -,S(133bb4fb,1a16b008,80379e4d,ca980355,c747683,cbd7e81d,87a9eb8f,4219a314,30e76cea,f57f8b17,de6d31e,447fb926,b1678651,e980338e,8f8327d2,648ba25c) -,S(cb26bb35,4cf94461,c675838f,653c3844,24ce543f,32ed7b5,ec1b6b33,a2f7670a,d6f9be8c,7f3781ea,fc765264,c9e84f2f,6d2ff771,25b8d381,199b67c3,763c4f2e) -,S(7d944d40,58cb78ac,739b85e,6dd3be5,6b08fd56,767fd02b,1d5bba08,d4639f1a,79716d18,44baabcb,aded3600,ffa68989,45920de9,1f2cbc83,e6326ed4,e37c3fc0) -,S(c4577e42,ad4014,e1fbc0a4,d69fe37f,49937d1c,19a95765,74f2437a,d06e6589,4a76bf04,18a4a8b,af103581,b6c2cd16,727fccaf,12a3998d,52b1a095,c5388570) -,S(c71f462,9196f35a,cefd651b,3f6f2b30,485e35f3,305dc774,21535961,60a17a0f,9ff53452,52ccf823,b83d47a1,a6a70f84,b9c83142,db0136cf,d03b1f24,6ec57590) -,S(35acf6e1,cad058b6,7543eb60,ef4d896d,c21c4b5e,292c3885,d9e42cf3,85bd22be,cce4ea31,c9a37f8f,21e32a5f,6f272699,7cddc6fd,8ab11c0d,12c3ca4b,fe6b0e92) -,S(c2872bec,f2abb3fe,8a258b3c,51a2bf82,6712ec12,587cb33c,a6765a4f,e3a3e448,a739cf63,63cdf69c,15c9827a,f759e0fa,f7d92112,9bce9e18,bad86c0a,9f6bf467) -,S(50fa12eb,c3dfb3b,dbb61a16,a8b0cc6b,6e6882ae,f245360c,e5524143,27d2bfe3,873afcc9,5ed9a3e5,2f1b0515,d901e9c9,3677d49,4e64a478,11ec59c4,c3374393) -,S(3ff1688d,65cc134e,c6f27fa2,eba78abb,2cf22eeb,57163e2a,150ed7aa,17b3640b,ec8f8f66,11d8f7ed,a296e690,63b3393e,58d8bf85,90630da7,3dc2c0ec,e9e05870) -,S(91a113c6,c53b57dd,60b2eb66,e6bf7ab0,e721dac1,acd71d76,2c278b31,f2fc2701,beb6c79a,2fdba188,4f98ec5b,fd97626a,131f5c16,d4466a84,a9d77213,96220b17) -,S(732b5521,e6cb7053,ebfec5a9,c5b35f47,8da4a9b4,c4bc5708,42b0e8b1,242bad45,30afe970,fa640757,bff0e825,93a102b2,e1b619db,7f7d68f1,17f27543,e72f57c) -,S(94831570,f0146aaa,fd2a7ee5,11f992c,6e2999a4,b22cb176,dd516dbe,e0e16e5f,eb275132,385efd06,35baab61,5367697b,8bef0c93,14fac991,4a2c04e4,aaf785df) -,S(dadb60a9,3af95d47,cebb540a,1c0aecf2,839f1be3,e264a294,bbd03317,686726b0,8b4bb755,46efb999,cddcb88a,ad5b28dd,b73ae1c6,48c810bc,cd9d0f03,c200e27d) -,S(148ebf0f,7e23a220,52ca69ee,57237eca,6c1caf1f,faeb8718,b9b8dade,4b97be1e,32f68bfb,464ae6a2,b23ac7dc,3910a87b,89ff7042,e863ed3d,3038d75a,f3689f4e) -,S(ec532193,614ca440,33a8275,49c65e0a,af446a21,6705f9e0,68e448e8,6e882bd4,30277366,58dd1673,d9f701ab,50dc3238,f073a297,d579cb8e,2ee51dc8,bcd44b36) -,S(bcb65ed5,b16fe248,bddda875,28eab71f,d9357099,af71ddd2,9a8471e9,b2b26e99,ed827c35,e6e13dff,ade8b9c9,d2c620e6,576db5a7,1b1e22a0,3f943f96,cb7282c5) -,S(de30301f,18df0e9c,15d709a1,35c30473,28cd3356,95922ae0,f283290a,638d516e,89398261,37dbf197,53012e47,6846f6d5,45a48312,bd6f4c65,255b89f4,a1b9df99) -,S(2eb56a7d,b051e9a5,8a7c12a3,a92509d9,5da4956e,8b820006,aef166fa,92873644,30867ff9,7ef8d955,d497abfb,463838aa,c946d487,d702956f,b75ebf89,e25bddc2) -,S(88f839f6,d7f06f85,82ed781d,12062442,66d4f9a1,e2007a89,f660fd24,ebb30d5f,29ce1d8a,376a587e,96fae37b,521a8903,8f0bffd8,9f9934d4,eada0750,32faba00) -,S(112cb93a,8db33b09,641aef75,c3f9a399,b1808314,64e8a855,16e309c4,99ca9a16,66b1a1cc,f2255c2c,119bd0ed,a75dfe73,fe2e9d9f,3aa9a6d7,43a4b7aa,9d76bccc) -,S(407dbfb5,53b43e95,639aa6c8,d6868ef3,2f41f1ea,70cd4aa5,9d76ea2c,83b567d7,69fdde78,a4971ce0,b05a57a3,8891691c,d1fb371f,b1322a6f,97849c64,bd7b57ed) -,S(16fb5fd1,fb41d76d,ffc130d8,9549465f,7976a3b1,ecd6a4d,9e5d55e6,b2a6a40d,3d39a810,95904ac4,9559aa89,8fa087b9,b84ed72b,55f17fa3,aef8b32a,10e942c4) -,S(e40302f0,6c102ca6,e6be1370,2aa6e860,5e71fd37,6c87e2d0,c0ebbf49,6fcb31c1,d32d294e,1e80cd,94925538,2156db9f,2bea101a,f652309b,8943cdf,b82d75a3) -,S(8f2cfdc0,eadf8b00,f74305c7,892a4326,9cd31300,d716d652,92a7a36f,7f1b3b9d,6d0e726,838fd161,32d19538,147248a9,5d76c7c0,beadf1d0,b553e4b6,b7d1a2d1) -,S(c7a636f1,1a9cf793,4385daa0,5c3f3abc,8c3a1589,7be0b49d,ae789fbc,e07674cb,4f715f0e,e52c638c,954b8b3a,84baac76,6a891889,db0b7f82,6bdf81e8,4040cfbe) -,S(245aed6e,5fc309bd,980d5597,9380e8c5,79dcc887,a2758e13,24ed3a1,833dc820,a7980b85,c6ce770b,13a888ff,22a1356e,4136eaf2,49238c38,dd103016,f0d0b1da) -,S(91ea17c1,d90556a3,722dffa5,631286b7,f9db0f01,e411ac16,f5203c4,1a8a824d,281023e9,88fdcec1,94af265e,c407910c,54d25f20,69d64b13,c5261f0,c157a3c5) -,S(729db97d,35fdb72c,a354c65,a0e7f76,7bff9ade,964b1d57,a98f9bf0,39a74eb1,59596a57,7c888b01,6e00143c,63f0be1b,d86d95a1,ef59e075,fe7e377,1472bfc4) -,S(f8cb711d,f74a4961,1391871e,d8de6a63,89679130,b587beef,f4eebcbb,9daaae9b,4c52c310,c6f960c1,53f386ed,6842c4d5,bc1b4c99,433567b0,fbc40e93,91a5e022) -,S(1700d0a,32624d75,258d80a6,2228b6ec,91e66949,a463f3b5,16dffe43,b9fa08fd,a007bbb6,b687b509,f450908e,b617f176,92918f18,be3113d3,8a80ebe4,4ee750b5) -,S(9f2f3ee7,70a2c422,b9b92eb8,a52570ab,b5354154,57f0efec,fcd9141f,62894132,c977d79f,ef198135,b69aa3c3,77a7f251,3274911a,73736b2e,c543a721,17908588) -,S(86f75064,8a2b829a,91acae01,4beb20f9,aa9ee46e,8e513678,c4fbd7c3,2ac36e6e,1768035e,bd1fd375,7caacc22,495a5902,a3c616e6,49eeebe7,4377b996,30192b28) -,S(1d4207d7,adcbd969,d432bc74,35f2fb75,b35adbe3,fa1f45ab,bf3ee074,b8269f68,11d80191,accff888,928a0835,562186c7,30367e90,91d310d8,2a712a9b,13d70f99) -,S(f782bf74,2e55fd7c,ab249b2,1570d9e8,cfc12f46,5330d2e6,57eff609,7c3d19b6,896e9e48,a60ace9,84d07ebf,12449980,9d96639d,101b3405,59eed877,908394f) -,S(22bde2e7,e3c0d268,f556c478,82e50f2b,634c4235,9067cbd5,a0daed53,1a166a7f,5e03a94a,5baf0f92,7f4beaf7,6b7e9649,aa578eb3,f105515c,ed670c3e,e1fa3e72) -,S(85ef9f8e,b54cc4f3,aeed4769,85529945,7eb4f3bb,1e5849a2,aec7b257,a8a9a074,8a0245d2,f0c8eaf2,84a01114,d29c65f1,c146af0c,dedfb5ff,9e3be650,e2acaab5) -,S(3bd6c026,63620684,4d2e1a89,2378ec64,177145d6,24062d23,ce9c2d08,4f34ca81,7f0e5053,87fade82,8596f440,3687b04f,4a2693ee,25361442,1d9712e4,b3e0c179) -,S(364f9a2d,641173de,4a0cd185,972f6d78,75b06722,3cececc2,9bfb8aed,7ccd3311,39e7616,8d64795b,504de9d5,3049dcb3,a95fb3c9,affa2d5e,8e8cb35b,6cf71219) -,S(8833f933,f4049c7,98493b,e5f764bc,47dae8fa,baf420d8,44c7436c,eec27898,bf615e47,1b0f1029,1afb2839,2c874f83,ae55b15a,58e61be4,12b7c7a6,13868279) -,S(d4fa5129,4835f9dc,49cc3ad,b9401f61,97654f43,ec88f206,9a63852d,6abb4a6,f24535f9,9efed47e,80d66925,8924e56a,44530eba,a2aff32b,70f36551,1db59521) -,S(50eb8613,99f79883,58b9de58,88c47cd7,bd4547c3,96e1280f,2806efd0,d0715b89,dff64137,f74442a4,dd0c25ff,ea968845,f9e14ff4,d3e32010,f1c64ca7,6afb1be) -,S(f8608ede,92c5a1e0,5f61c065,606ae232,b0f81161,bcec88bf,b4f2b14e,22165cca,e583acc4,7ee133b4,8c3c1eb6,5d6f4891,b53c84ec,7bb352ec,3b6e41ff,aa6a2089) -,S(2c00145a,60e21169,98f23b9f,6f83223a,6ceafa12,c1b92844,2a17bd63,582a4fd,ed76c7cf,c65a881c,5dd270bc,7be9ce49,c2990e43,425ccb7a,eebe64e7,eff423d) -,S(b42d4c38,79f7aeec,96f212f,1d5bd79f,bdeb9850,ae44af81,b4b3467a,85c29c49,7bdbbcb6,1eb04e41,9ea8f9ba,dd5289e0,d718158b,63ef0599,55e3c5de,41f833f1) -,S(a5831ace,8c19fd68,85e9b9cf,34b9fa4a,9e80eb3c,36e256cc,44cbe521,6efb7128,e10dc489,3e0fa1ca,f2dee476,5b8ab518,c3778f4c,583abe27,af293869,c765955a) -,S(9fccb821,59ed46e9,18a407b4,967e1154,4566afbd,df6c0639,d5cced94,50e56b17,c430e829,438188ed,a443cb2c,aa7d6939,3004ed75,5ff61e57,8dbe9e64,251615ee) -,S(c1efe41f,44186467,cc0def62,eb0f0ac9,22b8bad8,e2347849,28b465e7,1789fcc5,5d73f89f,709d54d4,e167806f,a07ef07a,7fd1a7aa,dab9896d,33c290f1,dca74872) -,S(805c0816,43fffffa,c9055f2a,996fc2f,fa02b4ab,4fa440f4,8af5878b,4eadb694,b0a0dacf,d9b3b9d0,51ac59e2,b367a8f2,eaae274a,ee2b05d9,18cc0042,eb02b6c5) -,S(d5da1b82,9b477768,bec17829,1c9abc82,b595bab8,6240e705,715de420,fefe498,dba833fd,df1915b8,fb43b39d,dbbd635,8f12d4c4,31b547c4,af07a6fd,75fde785) -,S(73a2441b,1f1b9ddb,844caf0f,8cb0a91b,5adc6556,6f883026,8ceeca8f,7c6c5cae,512e46ba,b47e9eaf,64cfce27,24566bf9,ab43e32a,bb0e098a,5dac9687,11927437) -,S(dbff750d,bed18702,eacea6d8,b54540e6,ae60ea05,85d77db8,7a63a050,806037f4,1f349895,29ce56b8,bba91938,16e842fc,f74b56e1,568857d8,2f193e02,207f84db) -,S(57c73f7d,57c7882c,5d574f70,fa225552,ab3d7741,260bfd3c,b616d6be,9698dbb9,f633edba,f7f6cc7a,9d8ff9eb,75bced20,f865fc9e,81245e77,32db2ed3,876e42f) -,S(6663e27a,7760f187,a1f67823,64044da8,d4cb82ef,e296f5ca,90c5d81a,49b7cc5,4df0d12,4ca9c8db,4885f8d5,18cbf06d,f5b437e,242cf86b,b11df29c,5c83937c) -,S(83f688c5,88ee13f4,a9e72023,5169dbd7,ebbe0c68,4cb61827,3e2b75bf,5fc581d3,f76e519a,151ba05f,df5f11e6,f3cfbcdc,4b00776b,14c4598c,51783088,2b2bc6c5) -,S(2114e129,1f65c339,d1bd4373,6c677937,4385b3a5,5dafa8e4,a0515134,6b650389,88103399,1b682f7e,9ba02fd3,e104932f,802ed44e,b996beff,7fa9523e,c9c2a9d4) -,S(a68b163c,db6c8aae,8ddeda39,7d8031a1,394ddc36,48168f13,47774ad1,d569233a,eba470d3,4ae15c94,57ba1b3e,cf5f3d96,682b8095,f83eba7b,f319feee,6740d3e1) -,S(a44b2a55,baa92a2b,cdd2f06f,36874d69,40416b79,20bb6daa,2bd9edaf,c12bbaf6,d06941d8,28f1092d,3667ce3d,59d23159,54d6cbcf,c0da31d5,1663a6bb,ccedbb47) -,S(5630eea0,8fee5570,c094ded,917746e9,18535cb8,b0286bf6,f6cc294d,5714fd33,91f60b64,3457dd9a,b2a02ff,99f931e,b38b4d87,204de10,d8a30cea,ce576b62) -,S(cc8b173b,d3112432,cd0c741a,8620fc26,ac5c5d89,e05c18c3,13067fe0,a41b4b00,8cdcccfe,b4ca500c,34dc3087,58f424f8,52517974,9a33e27e,8859515a,2f7c0926) -,S(abe16c8b,e0c99bf4,d396e70d,af00af89,b5d95f5a,3ba33570,892d086c,4b807943,14b2bcfe,8cec39c5,826fad38,9b8f8788,51e1595b,b25b1a87,149d8627,1218e9b) -,S(62411146,ca2da616,b557f0af,ccc2cb75,d278b07a,4dacd864,7e449ddd,cf29c09b,d081b63d,67ff0c07,5f00a3c7,2771c581,87804c1e,4ec5bf68,faffbd21,4c71e15f) -,S(5952a672,a50af560,66de08ad,be4f5cc2,38f3e4ee,84160b1d,14534c4e,2b50ed52,f7d7e2e3,e9612005,a0344e93,454f112c,792f825,f3d3044a,28d9af6b,798da761) -,S(128fd5b5,420f68be,3742def,c987da3e,bca771d7,af1cf8e3,12d6b3ba,df162492,afe5edc4,80c1c8b9,5580dd8c,aef14338,c09fbf6a,a1c951d3,57ca4df2,9d3f183) -,S(6315678a,13cd71e4,6e283287,24499671,6adedf31,38841718,cf5168f,60d4bf8d,ff691d8d,c5f97f7a,f2ae319b,dc590518,6ec3bd36,7f492d0a,95cda47,9492ad3b) -,S(50277159,4169f70a,ab39095d,d8027324,e212f78b,c3b0865a,a57f1574,dba1bdb1,e31fb30a,58eca0da,aea93548,bdeb9f32,325d6c30,69b3d936,d610bbc0,de3b771f) -,S(51eac8f8,8cdd7ac2,46375960,c6b7d9fa,a89352a5,4024003b,cada1e6f,df389721,6d4c8750,95d6ccfd,9d8a5830,c4672c71,d414ffe7,cff2cc15,b7b5d169,48e872d9) -,S(bd39330,76c0f542,a0590ad6,398b2418,92b899ab,75ba0065,b1ace928,b8cc0ecc,12f4bfc4,57e97c3c,9d4a21c2,ad106ee8,8cb5bfc9,92d151ad,589e90f7,d65b5d8) -,S(bd0eb600,5ae967e,81214a1,889f7dc5,d1e765a1,af74a93,f5292758,539d6dd6,2e532797,9e6a22a2,63025e57,4805e4c2,6d62b33c,5269d35b,bdeee7f6,4a2cfc3) -,S(b7b068b6,8ed18d80,67a0c971,a06cb3f0,5c96ad7f,371dd849,aec3a2f9,bbe23eb6,89871d76,d3e6b605,9997345d,4246087a,a3fa61c7,dd75f5c7,b2ed1e20,59a00350) -,S(10cf2c38,643a08b,dd842c4b,79efa2c0,3b5dcd1b,c708b253,ef71fba7,f0e51f48,e37d14c,934524d2,dc562f6f,997227e1,44094184,e8342995,d5562000,34e71f4f) -,S(5936b571,20b6dc97,ee242ba2,deaafad4,5ab83795,9f1e7390,54a0c026,df7bb342,86bab74f,b9d4f776,e82831c6,3a409237,d5923c7e,7b3e0b18,12ae203b,64fc750) -,S(67bb9ab0,bc48fafa,3ca66493,995ea995,e36cdfb7,152d64ed,ddc56aa2,6c315896,cfa9a456,dc2c82b7,f87f4216,e365f5e7,97223d2a,820a127c,a5ee4ee9,281b71b5) -,S(5580326,678b44ad,fb313c23,dd8a7dbd,c6869fd,70cc58b6,d20f8b92,ecfd81b5,6d343687,f3dc733b,55dac794,c895e5d5,9032613,563f2d72,ee94afe4,c2a932d9) -,S(fe285767,53d2466d,d056d2bb,b7141cf7,e52c2b96,d0ef3c8,52c728a7,d2dd8126,f344b3ad,c8077e92,24c6c5a9,c9f40a1a,d8721351,6b8691ab,c5fa9f73,726a6c98) -,S(12f25359,638fe4f3,97a17f99,c233b2ea,7a794d71,e677b206,aa32f251,8cef615,dd0d68e5,324e4325,ebd45766,441677de,40c15792,19d65c6e,9c63f15a,91519c20) -,S(f1e45fa7,21bf7fb4,45fe3eed,29c26bb8,bf1ea59e,de7c1a6b,e652663d,233c3e9d,6d145f2a,c3a041a9,83b9865e,66775342,a0f8a435,de19626d,ca8b9328,797e20eb) -,S(6b6ab442,d2623235,dcc7e3e4,85d00ade,7f219576,509c528e,6a3417a4,fefd328d,5d627367,ed25278a,6d3505c8,e13970ba,253a26a3,c605d11f,1eb345c5,56584e95) -,S(83e10be5,d21bbef2,ed1ceb33,c4e558ce,bee76405,257d9573,51f5d90e,f219552,41f5e174,c6e9b283,2a39c2fc,4d4fc573,634a8975,e143243d,14dc4be3,434a4380) -,S(2ba25948,9571ce20,f792129d,f43caf4d,ddd93b76,e4c8cd63,7a9de68f,f8d615c5,9469a49a,d1a814d4,2f460325,b7d58f2b,eeb85183,a370cc3,69a685e6,a87f6e61) -,S(3fac1508,b669f540,77a840ca,3ddeec5b,b70c03b0,ff93a77d,f2f73df,2728f36b,dfbac9d5,ceb21745,a6d27c3f,d6fd96b,af708066,a3bf765a,208b7231,d5fb6955) -,S(8996dc02,9b79d0f9,d57b8c8,549fc01c,2e1c1c7c,2ce2cd70,7a0bba0a,b3420ee,d08fcc05,5194c4bb,2d17ad54,2f9ec734,f2a9ab8b,a7dd0467,c5d916aa,10f7b8b1) -,S(16af9433,c9baf15d,921f931e,f530a477,b04b2e03,e1e8cd05,42e20628,df7c3241,65863e2a,acae34b5,a1dd53e0,5efd423b,165235cc,69195973,2d0f64e,c5b56fac) -,S(d82af39e,eda70e3c,f28e2f6b,b8009131,59ada2d3,854e81a9,3798e402,43d1d3c,fe03de8a,326e8bd,b202b5b9,929c2f3d,4bc8abea,a2377cb2,29cd4630,d1dc1c50) -,S(a7ad92e4,7a442903,c2f91033,7e2ebc98,14bfc943,f2747eda,666bc813,c04382ef,ffba6b43,9379448b,56b20163,44439b9e,8d6da764,72f67a27,9c7f45a,359234c1) -,S(fe9b9274,7b27f7b0,6419dd38,53e61762,de7a5116,48008802,681bf521,21a1ff92,f32bec26,b9d24872,1a47c65b,48426130,b8e72e68,d231bd4d,82c5d4c2,bde605a9) -,S(8e22ed5b,e5d80940,970de428,5ca609af,872b8a4f,b8c93942,fa1e62d8,588ac5f5,6a461962,b74b0f93,afa72284,4837ec30,b99a65da,d688c161,cfa42028,2ed97167) -,S(bd3bb0ec,bfdcf06a,62f0046a,989b45e9,c76f4d9e,b3225495,eff70685,71518fb2,5592029f,3eed8e35,727865f1,dd2a6de5,e19e6eb5,f92e520,529fe97a,c296820a) -,S(50a9dbb0,b08a48b8,76dc65fe,6e2efd92,d44053ed,73b8c279,5b688e00,a1fd1455,4a1fae82,51581f9e,32fe8f67,5675ef70,dd7c2ec6,2a42eb3d,e1aa13e6,717df147) -,S(6c1dc44e,67b52cf5,a4564ce1,7a9da713,c718833a,6d527e7d,ebc6b1f2,c893693,89cb4508,681d58ad,77900c1c,aeb25c59,b307c9f6,c84f1329,35e32af1,e39f8f67) -,S(3ffc35e2,4d4fd0e6,ffe4d1c9,b5097d10,c12dc7c0,4356cea3,b5fad66b,5f3333c0,89718e69,78748c6d,e99d181f,137eb74,6e28b05f,27af7726,e86c5f5c,daa1eaea) -,S(fe2261bd,b40fc492,99be54de,1d0bf22a,634aec85,77b5e9e1,51626d67,3f4214eb,896bf33a,5c9b7537,b621a168,f3da1bd7,dbc94816,922350fb,38925c96,5e57c175) -,S(129b6e5,dba2fe86,749274a4,f1ec5999,b2fc682,933a1120,cb8e16bf,4f4131e8,24dce651,b0fe4770,6c78c217,f0d5ed4d,4bda4e7e,4e7ea6b9,ca59e751,b018b5bc) -,S(c2d1b280,79d91abe,1a44c4bb,96ab548,90323054,94075907,37b39ea5,e1fedd72,6974b9f3,80edabdf,e7961bbd,71ba1971,ded6ba24,90466d1d,a5715d9f,92472637) -,S(d8dc5f38,76f6049d,a9a5c9e9,396d287f,911e06cb,ac0148e8,26c8de93,15bd464c,701d0a43,ab41f321,b8f86ea1,b1f51d0e,c22a3399,c1d8534a,433ebc2,38ec248e) -,S(2b1a41d7,ebb9756a,b62a96fa,57909ad1,a747dad4,b3730da9,a12dac8e,3ee4c414,8ebb1512,3f43224a,c2cb4ba7,c90ed765,5470a968,454d0c81,1ebe3384,5c6ca968) -,S(724fe9d6,e7f75b52,7da19421,3c984e31,f63ac3f7,1b5819bc,344ea339,567bc179,a1db688d,ba1d85fb,20da08f,802b5195,163d179c,7bc60f70,4ade1f26,4e1552fc) -,S(835b30f2,8e54b834,5ce95569,7d71b7a5,7cd4b5b3,17ee3fce,57722454,7695c9bf,f431ded9,b7ba9477,ff041f83,22685e4a,8c88c91e,15a14f21,6b16e302,e243cd11) -,S(f5015d22,16cfe581,e650e579,c49b6ccf,b5ca4dc6,42561256,21df7fc8,19047ee6,45b099ab,febbb493,5356872c,40c06825,47aaef2a,72e80d27,521b65ea,e2d4918a) -,S(df0b1b57,f3a0dde8,b136a92f,bf953a83,694244bf,99782ea,98050bcb,3313f826,6f7c8326,bf5f6e15,538a1f31,273adea,6908e5db,7f38f395,49284822,12124d5) -,S(a5a24cab,96c04bdd,6e5180a5,8fe27f9e,51897bcc,3a0aa9d8,de06de65,53d2890d,4f6dfa5a,a6b44550,105fbf39,7dce3a4c,e0b42362,4a97d979,eb31324f,f1215525) -,S(849c2e79,422d1dce,4b568aa4,c80eba4d,d8acd237,71f6dff7,40849bd3,ecdb7e41,a465929c,a3ab167a,dcc4fcb1,7ef9102c,35d8937c,fa900ef1,8022918a,6ebfe79e) -,S(a9a98d5d,d8f8ce0e,ddcd90ae,671c52b7,1b09b75d,b4185d4a,1ff12c71,70b499a0,a4eb522e,3aad7f1,6aec7758,c9528bb0,c07184c9,e3c965f7,afefe128,bd285c5c) -,S(8d60786e,1ec1fbe9,61e056c2,d6a57c5d,813d7f20,bc8c68ac,eea0020a,2c4e57af,3a39b0f1,6cc346c7,fc695f45,91b557b6,3c1f8500,89d742b1,60c39744,90e55720) -,S(4710166e,65b9a2d,8de5b80c,192303ed,25cbb80c,b91c57a0,b31a38c5,5c218fd1,b4cd95bc,fa48a016,658382af,37ada302,26887fc9,8200f77c,2b8819a9,ef489206) -,S(e2183510,40815901,c78a304,e6f0d545,5a116560,a91d84fc,157f061,5ed6c0de,6c557bb5,358454d,419c5cb5,1bcb85e7,db3b04ba,d18e1a63,a75687c9,8fd6d973) -,S(807cf529,8730d656,e68b4aa6,5f8d8692,ce246c2c,4e668c69,b5e93e8c,d26b289c,b22a6fc3,d7ffdf57,f18e7447,38cb1bb0,aafb7b39,101d3259,d31574f9,fff644e2) -,S(568f659d,f19f14e1,5d91f3d6,bd2a4690,b274901e,cf6fc684,dd0d8615,8dfbdd85,28eaf8bc,1db68471,4ffbfbce,30977c7,606bc591,dfb8ec02,e43a31c2,ecafbde7) -,S(651dacbc,564fdedf,f4e5e3b6,f2dd366,37c69140,7fa923a8,ce88ed1c,a65e6b86,88dfdb8e,6f117a1e,b99ba423,89ed2db6,cd5608e7,8be2c896,334ffb8d,2e19aa79) -,S(5a17c956,8214ae71,80322b0e,574529c4,dd7d951c,872809c6,b33ece6d,8cd7cd0d,ba4b0cdc,7d7e6ff9,5a97e4c2,6af714ae,f00c9142,5e562ffa,16942fe2,852a3e06) -,S(6d564251,5edd2987,568dc237,b5b98fa8,de9b86a3,e7176e62,f2609dfd,65810920,a99a0d1a,12534f64,fa97227,825b094a,22fc16bb,e8777669,d5aedc4d,58e81ff0) -,S(e3687c75,c0689381,22f60fc5,b346e8dd,17b2dff9,cd7fbea,94aa54b7,ba1f6de9,4dfd4537,1f62a968,399cfaba,87a0b985,cb333510,dfca666d,395e0f8e,2b7f473e) -,S(1a3d974b,49e7e68e,bb2851c9,c9f22d9a,5929ccde,9d635e8d,61aff93f,f7244472,f6c9e7e2,98815ef8,d53a7bd7,9f10275e,ea74ccd8,5d97cc3d,cf2e97b1,83c97c86) -,S(8e0dba73,12c4afe,8e1bc508,4d9f4944,654a5693,81a64158,d7db7007,3f897cb3,560eb34a,2451905f,2e9daeaa,63dff50f,761bd68a,2321a714,45930de0,4801875) -,S(35d9eaef,6c4ded5c,371a655f,2fdbac45,35471c32,b369955b,f8f30d95,21cd5817,c5a084ba,7b2ea4c2,e3c3d081,dab53c9a,ee40e10f,607ce88c,899f0e3f,5850d75a) -,S(44d1dd16,c42b7811,f78374d8,2ec9983,7fbee7ce,4b3a8ccf,81ae4ed6,3b7d2c73,6a7bd35c,b10c4e89,60e3eba1,8f658510,3be8d1a8,5c4932f9,f1e48d81,e3f66604) -,S(4b7a54a5,e7153a54,e4400ef,9311d6,cc16f641,6695fd92,5fcae9ed,6b2738d5,43a7bf76,ac2f663e,daf0036d,b665291f,cf983c0,791a8a6d,a5ee1956,2dc18850) -,S(add4a15d,d1a350e9,e5df62b5,4a6638d,76ee221a,4007a19e,db5bc93e,87f11ea6,c26d6fcb,3a8bc1fc,f1474c26,31a4216d,740cf94b,a9d7e48c,8f01be28,885ee849) -,S(9b52aafa,119ada49,ce33340d,ff75ac50,ac9a9d87,775e8e45,da58452f,228a23c2,67640253,503b5e3f,89f7ad07,b9379bfe,77c946d,4f61b83d,3fced91b,69e850af) -,S(965916f5,89854944,26c1efb7,88079a55,f8109cb3,8bb111b8,42ef7f00,2d4a45d6,9aa2ef4e,61902148,aea7769c,a561d04b,cbe1b340,a231388,e332c30b,8488e531) -,S(3af7890d,c045aaa4,2f7a8f26,5fcff9ea,41bae0f9,87c75c22,3ae3311d,e09b6ffc,dbb31417,27adbd5d,e34202b7,f7a880a2,41f18b0f,b1a40a25,376c4a30,ec607152) -,S(dc465cfe,c07f839b,46406f4d,9a0078d7,57c2fe0,e62aa4e2,212ed33d,5b2026a,1ef12aff,a98868bf,b51901f7,2693f868,5ba2248d,91440380,53bd137b,24b3bc8) -,S(5ae92f8a,cb9e2ca7,2f4d4c70,f4daaf96,bd237bab,2a83c0de,693d8207,baaa0f4b,54e266f7,aa1b7f22,8f24ab91,5e3f0a92,3220512a,de239da3,1069bbf2,35d63049) -,S(38134bb,c6c5a4b3,63421af6,ae573ce7,20421d36,1f4966c7,b9e7f125,f49659ac,5d42678c,d6f89848,72399321,fa86318f,7a4e3f05,4c3bc6f4,6782be35,4ac4aa16) -,S(f2b807a1,3fd603b4,111ac02d,5c646f6e,eb819a4f,7893992b,9132aa83,76892a57,6f1beea1,a315c000,3c957d85,bc5171d0,ccb8ff06,446f4748,738a3c78,f9ec2d4b) -,S(debe05cb,b308a6da,a1eb55bd,73c3f1ba,248ade5d,ceb1ef3a,baecc6ac,7a5e8c09,f4fb16b1,44beb4ca,789aff58,9374e476,efccbbbe,b74e2693,a4d05ba5,a809ff05) -,S(15cbbf1,2720f8f5,fa1a7752,b6f33333,91cf3d0e,c40f0292,24f5b7b2,c966c099,be3b1573,fe38200,a464f4f0,c3c2f9d6,24bd59bc,9412110f,6eca2ada,2f1c7294) -,S(e4fadc29,2f0cf77e,4b14c3cd,b567f5c9,be82fc93,dcdf2b50,bdf20fdb,f5984769,2858e2ba,c9834a2f,942ea7fe,2e339d8e,b384c255,6a48d688,a9510808,a1235452) -,S(b0a8c6dd,f57434e8,a8bee1a9,530cb9d,3d4ac31e,edd17653,3d84780c,6909554a,4f7467d3,62185e38,f6d6c30,e4c3e4ac,e167f3cb,aefcab8b,eac754eb,c76ea3dd) -,S(a4398869,26e4d06e,5337e61d,dcc6f491,4f40c04,eb3ec752,47d9d058,9dfea2af,ac1fdc5b,70d792c0,7bf7e55a,b07ea1ce,477dcef6,cce8585,84cc90ad,c62b6272) -,S(84b362fb,1597f179,f30b7e2c,b516153,94619081,1131d45c,ba55fd1,94f369be,d2a80ffa,44965152,78c2ee3b,122b5c3f,e6d27f9d,6ed6ba94,9258c2fd,94eed4dc) -,S(75182684,96e2d037,24c11192,e9112501,f7c27d19,8b92fa1c,3b0e931c,2b85d32d,eddd2a6d,d884f93a,b6f8d225,c9fb32b8,9f396f1c,2613be98,d866b713,14a00d70) -,S(aa96e0b8,104884cd,7e22211b,8b12e6e6,b3f3e3f7,fdff04fc,202d8946,838fe15f,d8a9b5c3,9739fae3,dd3b2483,4fd2981d,ea529097,2ba52541,56905664,f289e3e0) -,S(ada17e80,82a0a15f,366f3d6e,6775b5ef,35c980f7,12ea7522,1aa796f4,2454988e,7df4c1e3,191214b6,e40fdae,2f5dabaa,b6e9837b,f53eb10b,dd28e674,230cf2e5) -,S(322a0524,20f0fdbc,85f35fc2,de6690e5,a61260f1,428ec662,4185ee8c,d2385caa,fc81cabd,789995e7,d36d3de0,1b650a20,1befd7a7,a415d250,697114e3,c95e096d) -,S(5082ad62,3bf2ff8c,b4571b9b,86303032,ecd137bc,86c5514d,b9f218c,4f091153,b29d3823,eb4ed958,9b0fbfc9,2d006fb3,698ab596,d3e60360,e435bbdc,be4c80b3) -,S(de9e45fc,e9e0dee8,3bc806ae,286a2c5a,a7978608,42ddf02,d29a6ac3,9fbec470,bcda9466,e7207f7b,7d986e,36b3f238,d5bc51ac,90ec35bc,56e0949b,334ef964) -,S(95cbc3a5,61ff4cfa,278678a5,6f8b16a1,efe2d286,c7103047,310454cf,a1a822bc,8720fda5,58d23b5f,af9b80eb,dd5fa625,93325a6b,eb5ffbd8,f333cd9d,9c8b7366) -,S(fa0e59a0,969de9fa,aaf7be60,24136559,cb384b76,26d3bdec,f70f3e55,696a0632,2e8af3c2,a54e837,ddbfc32d,8a47f342,a856b854,7ec4b0ea,6fb3695,48b8b588) -,S(56aadb8,2056ff5b,3337aa5d,337671a8,77168b0c,f0330e8d,8f5445a0,cdd75075,d6c4cd4f,db81d8df,b095f681,f7349fdc,c2cc80d9,399fc16e,5fa3e86,9460a5f0) -,S(7da6a13c,11d5b063,8132254f,c064ff3f,d3818a5c,e07168eb,ed5b7345,53bbc19,26e912dc,5b03258a,f914cd86,88d6a068,266eef77,7d4f45f1,7c47cf92,16d00c4c) -,S(4004b235,d58417a0,ea1a2071,32b30a8,1dcd6a9c,3ea875a3,6d2a6225,e2b56917,1c960bd1,443c22fa,96f06eff,a717b5bd,efe8b105,7402cd93,7a6aa909,5775e226) -,S(b12c4d85,6ec6c85f,3553bfee,c7dacbf4,f742ccc1,356fbc8d,ab3d25b7,52bdfe93,a8a11692,49dba87,8c8e6c56,ff8f699f,d7e69c6,f994d05d,4e0643a9,7f9cd2e2) -,S(a78d9a2e,8b74ccdf,97c6ea9c,aada2644,8b560287,7d7b0970,41d24840,91490970,39cdd434,1d1e16dc,b89fe937,665e70da,ea80a174,5ae7b99d,dcad04e0,efe841a6) -,S(c8233855,b1f242bf,59b86372,ae49a985,2528440f,e3aa8e,28d594e0,114d2ae8,6f515202,a14738ee,ae4b430c,27391144,c551bfe6,bf24005b,81f92900,bda92b7e) -,S(6da24dec,9d6ec569,8dda9655,672a9b79,4923f595,9157af10,64cb53cd,5e5e8f6d,59517e76,8b0d39d0,2c075a46,c1e653f8,cf876fe,cfb10746,a8c248cf,4c73fcba) -,S(d0c55dca,ab79e0c,84ef08ad,57ff67c5,b36336f,2f6231d6,8efa2fac,54558ef0,d4365ebb,4096888f,c9a74d90,1adc4c5e,16f5dddb,442cb5d6,b5e22b32,99aa573) -,S(d76f084f,237dedd,ac8a1936,319d198e,baef2c4a,3b81ae42,e92f96b6,e222490c,c7737563,9639b7c8,32e4bf45,efc8da2f,53e20e25,641ea714,85674a40,1dd5f14) -,S(6a1f6920,9196c02e,6919abd2,c8fc835b,889c5ca1,6bb25e3d,ef7d0c4b,9f4e6d29,84371bc2,7bd206d7,389534ef,f2a49c6,cca4c9c9,874f59b1,ccc8b5b,bd5df3b) -,S(693b3520,85e1ea36,bc5c8ce8,3fa49843,369300c5,170010c1,b11a3c76,4deb12d6,4441c9b7,808b1ba9,8199349b,243f08db,6cdf5326,d7453828,16f008d9,45c1251e) -,S(5ee94c65,70953f27,37c16a59,590f7cd7,87143bab,405f6b23,718878c7,bc95741d,8578d18e,a49f9204,e51513a8,94920224,70837b2b,ee480929,5e4c4f0d,cf5c7794) -,S(30c174b0,e7b0cec7,e6da6a5d,335f48ee,6f59ef16,984e8912,32e874d6,2e51fe2e,af7f955a,8807444,56b2c965,5c4ad915,e040a360,eef0c4c7,891db1ae,6983867) -,S(3121068a,eb60a54f,dd427eb0,92e30895,92335900,cf191eea,79118442,67b7f4ca,d9e8f74,b8d9c0e7,c35e314b,51a52a95,bf672adb,9c6fb104,8d2ea489,5135aeae) -,S(a06f5e3,6513a659,106ec301,cf1f2df5,6093e690,38daaebd,4b17ea45,9e977ff1,eb19f18a,15630965,d2bd8bce,9e350374,1ab35f0e,4b442f12,9c9d831f,3811cffa) -,S(a26af0b6,50967dba,1c4a33b5,5226c2a,ad445f43,84567580,3b97ca1c,f3d217c7,22c8aba1,604df49,abe16949,59b33cce,db11c241,cbdb171c,50b0fb0a,399e6839) -,S(8e4471cb,b650097e,d3b0e938,18b8ec5,a86fedd1,addc6ed1,8703a99b,4128919b,fa5457bb,4068bf35,7b050244,6eef2507,c1d87051,28770161,ef0e92dd,d2308495) -,S(e9116ea3,24650463,fde960ed,eb7d5dd1,f5754915,62c99f48,31b553ba,2663ba1b,e30d7323,fc29e388,94244422,63434cdb,aebc5895,8a6fb350,33141e96,46a4529b) -,S(8b2267e6,9052f769,833b0fb0,ffe413f3,4b8edb93,9a2009b8,59d6673c,4ca6ec37,97f80a18,ac047152,178432b3,d445a0e9,84755d9b,7ad43165,8707185d,d573fc5e) -,S(79947669,d7bc732d,ca08e0cd,d3e601f3,c4344532,e35aa7a7,12271b12,339ee2b8,55906cbf,e782d32c,13cea8e,83812e8c,84c76d38,472ee59e,134994b4,b7b92897) -,S(ca6d40aa,2f863c02,b6444727,d00f8923,ec58afec,3b4a4e51,f4be232a,4b4c7c7d,ec73856,b0529f1d,9d2ed892,b22b059f,35e4a91b,b60c6a6d,e919d611,d9bd90e9) -,S(7ba23bca,5f9a88c4,588dec37,3861b699,ddfc9f5a,5b277bc5,e6e16f54,513fe7d4,25f10a4f,eeb77ff0,e24170af,dea0e2d2,3f2289a3,e53ad674,1640cc69,c042dcf5) -,S(186da622,d0e8a9ba,e26d43e0,b601c68b,311d2046,4eb36f2b,f86c3e0e,5d4ffcf7,53a6f54a,dd11af9d,50bd82d9,70825bcc,fe9da1d5,ab55e64,bbe4582b,f5248d37) -,S(e9601474,568cfe7e,6cdbf488,63f11f12,fa17ecdd,c623cb11,4818eb52,cafcdf8b,96d51b2,7b5e4fd8,1bbb009a,2ce40fc7,65fc6a3,7f8bda60,c4927766,a52267da) -,S(811f5957,accf9f32,3e48ac3a,33fbaeaf,c5120858,943e7065,9c0da185,71d1d4e9,ede77562,cc8ac601,e3dbdfb5,944d59af,63bd1aa2,ffb35bf4,1f79c418,d1d67937) -,S(77424acd,1d55424a,edb0149,a6ea0349,afcf44c6,667caa51,302b70f9,5fddf277,70e15309,989a2512,422a5bff,221c0e0e,df608746,7a34dbaa,99e77f9c,62b56c3f) -,S(e9e139fd,73c2c50,375d3966,ed4af6f0,4bd80bb,439121,d61bfe66,99dabd2e,260efa55,805918e,d45c98b9,c119bed4,21483d88,722e0f87,de7a31b5,e4b541fb) -,S(a9a5313b,e634813a,b10b9b3,6b38ed1d,a971c0de,5b6d1010,4cbe426d,544e7d79,ef7b3203,2a95144f,17803f09,72f6e2cb,80e6a099,5196911f,916225ac,e97bbb97) -,S(ff29a1dc,b5c97b7c,c5e2b73d,7a0e0244,bef71dfc,765127f5,f7e0f38b,f8a099db,b8334f11,682b9a22,ec08a376,dc3994c2,7d235d5b,a4a77803,79ec0fb6,7b4d0345) -,S(c98df4d2,da452118,852c096c,bb34c8ca,a2ebcb6a,e9a3420d,a4fd3eec,cc31c5f,f4f9c618,44cea236,edef80a1,4634159c,72663322,7372cbda,4b2680,b5dbbf7) -,S(66126139,77cfafb2,283e1a92,d6327174,86add807,b88cf793,12fef2b7,197289a8,504387f6,70caf906,2db248c3,ed5faee0,269d0190,70dd5acc,c8599f5f,5e01d1d0) -,S(efa8bcf,281ad4da,2f083e6e,182765cd,ab0e66f2,e8411007,e216a69b,d73d5e94,6e1afd7,e97061c6,cd0794f6,837aefe6,e8ab76b6,53d80846,98747ed4,64e20a) -,S(d4f9fa7e,6e385f02,c068ce7a,1b80343c,20f85b7a,4699c126,575915bf,69a2f6e7,a6496004,f280f970,c1028b3c,e0d94187,34dece11,3f9fc737,2ef0125c,851de143) -,S(5980a5c,456f383e,f0add523,13fe37a8,874059ee,497b0a23,c6dfbb2f,9f6c494,e1da9a59,c8e3d482,ece7972,9c77308,e47bcd90,cdff915c,32a94908,db1651fd) -,S(988ca976,ac6bcfb0,b42125c0,939a1207,2eb13565,29da3e72,6b70b2b9,5c310e12,97368d81,79a76a51,7c7d063a,179a2941,fe5df19f,25f1e1fd,42a32af9,d5de16cc) -,S(ca49ad0d,25b36130,cc878861,f4b72a4f,e945bc0b,dbae2f4c,629a6375,3d88037f,5ad2c0b7,2e084bb3,95b9268f,22ba1774,c6e423e2,4a5191d5,b940c89c,e1039f0e) -,S(ec18622f,b9771723,c8e6e6e3,5096e517,38c4dafb,82b10317,1f55f900,b24c2e06,5803ea86,c839ddad,6c288b8c,b382a1cf,76a790c5,6f99df9a,fc9915e,eac6dd61) -,S(c53aa261,60e627bf,bd905ff2,6b50a171,18062ebc,af9d9ca0,c486430f,b6de5da2,7d6298e0,f17a515,529fc5bd,2b85c7ef,d183710b,96d62a2c,5a0195cd,ea561790) -,S(ad138110,f9161559,229ead18,4b7ea7b2,846384e9,dc22b8eb,5b771027,8c8913d2,135a3ed1,d9df6a0e,105c7c,e6ce625a,f8173d76,60ea04b4,9ee781a8,90595eef) -,S(46946390,304df8d9,15705fc4,5714f3b4,233a5ec1,afdaf145,b6c09717,9c6b43e1,aef28d5f,88f62a7,e3ecb978,6efc97f1,1123fde3,88ec1bed,bbeee3c9,f9d3e014) -,S(d464a300,df9de2ee,220ae23,4d59b6cf,44f4d280,7ab4f588,aa21dd1e,eeb80819,89988349,b1ab280,8b829754,7e5b36cb,e66ddd16,4d7542d1,cb0cf210,44a8be1c) -,S(5e99ed21,9ade424e,25b807c5,bcbeb05,9b638b7a,4ffb3c6d,d3bd054b,b7af9f41,a373ab0c,4aba0b04,878451bb,96807604,7d811fd3,605e8e46,57574efb,21681aae) -,S(805edc92,6fddf92,d33db068,9334d778,4b30f73e,4e65517,42e62c50,fc6ff2a3,170e4317,4361275c,2102aa8f,5406ff9e,7bd35523,8bf1e946,1a6f16c0,38beecdf) -,S(ec6e5a3f,bb96f0af,dd700701,8c046998,49a879ef,5ebcaf67,456748f2,f25fd18a,9401937d,cf584df5,a9399fa7,bb309ffe,80ae015,20933d63,df1fc181,b2979fbf) -,S(94f226aa,a25c710e,2cc68683,2b9124a,ffc5c3fa,179ace52,327c6866,cfdbb3ca,b92762c3,a4c56d95,1ef16db7,b3992e9e,aa2f9c3,ec48f077,62a379f8,408f94a) -,S(8d2668fd,5d46bd4a,fc84183f,4fc31dac,964358b,fa6b03f9,16ac5bec,a619a92d,c24f6815,3e49048c,a461eea8,ce50c8db,7794b10d,d8080236,2af6677b,45e45f95) -,S(2a3ef112,d00514a,c562de17,a68bc4de,c4c04db7,8266892d,b645ac6b,ced47f67,6e93173d,64333933,c3db0f56,8c05410d,8a1dc73b,6a30c6bc,2b0d5493,d9f9fe1f) -,S(6eaa1185,19d6cdff,45d88426,6fac5867,790faca7,4ccc31bd,6eb19551,8f752dd,affb02eb,277a2bdc,db79d91,10ee8a7d,58c9662,22cfac03,b3d26cd6,3c678f9b) -,S(d17802d0,1944d9f7,aab2b542,fac985ce,e56172b9,e5629e53,ddf57e0a,8dd07137,485ae7ac,34d13d9c,9ade04f2,b3fb8cc7,d0cff406,97abbe2d,4961e753,b8de013) -,S(9e4cd82,67c121f8,96c8104f,988a140a,71f0cf18,782b574d,407a4840,607f5804,c05f08,3fb5c4d3,9d3e237b,101f46e0,6547828e,f05040ae,87db7874,9d7f3bf6) -,S(927758c2,12452995,886e97b4,b1d16c53,4603c,7362e190,dd2558a8,43521a41,30e4d5df,c5ff4b5a,5f4f757a,3483234d,4c658b7b,f24dd509,7968627a,a2a86d56) -,S(589906c5,90a1e143,ae7ea4fb,84edc7a,9f00bc90,dfeadfba,1933c36b,57f2bd25,e9d1d51d,92223636,cab62cab,362b79b2,12a18be6,6468f06b,a543921e,bc9b1c61) -,S(5b516216,1171c076,b10d4987,3aff89b,c080d2b1,9e3ebc3a,de8dcfd1,734e2f35,572c40fd,24965ce8,a78c3402,381bfd90,b683d6a0,d379d7ca,21e66804,31b8ffe8) -,S(1603bb4b,3dced105,b1a2b748,21080a5c,2629a52b,56823524,84deb617,2f6a9694,2dc4243d,fd20fd16,d1f2798f,23e43be5,f88d5feb,1f6fecca,6fadd5c3,f5a63c37) -,S(7bbf7555,4c14bf1a,63ef9f38,ae3ec279,5cf0aa1f,335c816e,580bdeee,10d95ed2,d2e12648,81ba6d5e,e8cf389e,84e37ee1,7c178b8,dda63756,32d9330c,beeeac53) -,S(b2d3aee,d083787,eb4e14f,328640a3,c557724c,e06a62b9,17134ebd,fe576073,68cd90be,2df0fa6b,da2693b0,f18357b7,ea5205e,2a1f5fd7,5a1413b4,fd9ce0d6) -,S(dd10759e,86121fd,6296f171,57a90f2d,bc217238,53969f85,4a71461b,27df81be,713442b0,65546c39,1b71ef30,3bb6ebc0,659471be,fc165a3a,686aae0b,270f13c9) -,S(54229d57,3a274ca,6eda6194,62dce4b9,35ed143d,16e470f1,239f1045,6dd2de16,a6739dc0,916112b7,4fd6ab7a,134093fd,55541758,5b3fb39f,da647bc6,5cde08b3) -,S(141f3cdc,124460ea,15fc80fa,dbba8fce,d89c4426,74e9a3dc,55f74f69,66bb8ff,f0c8d7d4,dac4ba66,1768514f,c9bb9e2b,319645da,735e5be1,51790483,d7b477ac) -,S(e9795743,efacb0d0,4c91c74d,33837b61,8d08acc1,cc2603ac,f02b1610,16fd1363,9f1c8ab6,735f3161,811f710a,1b5703d6,aac65c23,35fc1af1,32ba005b,bbe66d7c) -,S(e5e8c40e,c6c9475d,d4cff6a9,c9db5cb3,f8202bf1,bf60ed41,3e213d6f,2c860797,a9570e76,482a8177,b1adf9a0,1a7716f4,b1e754ef,864d2deb,354a96dc,ea1decb) -,S(5292362e,a095d145,c002f027,be53a28e,d5244982,bcea97c,b56d9ab6,162f7ae9,e7f00a61,8e63664,4555170d,9f13420e,fe1849dd,641bbabd,d3648250,81934e37) -,S(a6772998,3d6a765a,67e9e3a7,45e7de0e,1e42f34e,46b7cdde,8ab20262,ad246822,53281b0b,bb45bbf6,a1e804e4,cb6f443,537b4bb,d551c9d0,8976d53c,1020407f) -,S(7ed3bc8a,8a68ea64,c9dd316f,48f012ed,229e5f9,1a294666,4546ef68,bb48959a,238e6696,a7cac135,ac551927,fef28c04,5bbf23ac,9d24ef52,3d69aaef,27312e69) -,S(96702aaf,a9e17a9b,5fa4fe87,d3b45633,b59779ba,57002679,63a3a5,7e7442c8,53deadec,73ed54d4,db98093f,9e269442,d9a4a955,f9b18878,8be2c410,84014a4) -,S(bd3e9c04,42a9b0db,b063aa20,b09e7e0b,4ea18ecc,55a5794e,14108aea,1ffdea66,b5e43b5,fd8cfa37,dfd49f34,1ef14b0b,c2cc571e,cf9f7511,f2f11e15,825a57dd) -,S(d95c6dde,f07abe75,215e14ba,e76a3be1,6dc514f1,7542a246,e48a2a35,108c0833,e49d6c1b,baaf6f7e,44fa7389,31767757,76d6756b,ce8353ab,ca6e648a,cd2e8fdd) -,S(86f7406,7a86227b,2f5414cd,12c9907a,b78464be,8a5c2284,7d8442ea,d585fe8a,53c73db9,3ebd3340,2856a7e3,d91d29e2,e9439a3d,c43120e2,1fb5bb04,384a8e68) -,S(bdd92d35,ba51344e,4deb6b77,126fde21,9e7030e6,5e1d96fd,4987f1ec,bc5ee6ca,a49915dc,b4f29eb5,af9d643a,6c6f581d,94a205de,3a8bf3f6,a26d294a,be11cebb) -,S(dd4b5fdd,3ca88300,74f19532,728a31e4,152be230,2e6ef55d,a6ef9209,fc70b65e,fed2978a,3cc4c8d8,2012cd5,7e06ea37,4ac5f802,a0032e8a,21d58239,860856bf) -,S(fab1a71f,f8a64cb5,14c94e0d,1c67fb23,70998570,ebbb0e25,9e09df03,e82aaeed,6208c3fe,3fd0d9c,640a1908,1a6a6db4,cdeaf7f2,ede4835d,46549734,c1c50035) -,S(4d6fcaff,167a869e,311e8dd3,f736230e,78634ebc,c4470b91,686018c,7b529509,e860a3b9,28927956,1cd132de,a1de3456,576c4cc6,138bb079,a166b9a6,79555751) -,S(502caf19,5004fb43,75b13ca5,16583e1b,3f60b32f,d9769832,b42423a,f7ec78c3,c0aadc3,36019a17,ebf7f2f0,5afc036e,e807df5a,c2869bcd,19c2aca0,1b5ccec8) -,S(35727dc6,ebe8f38b,1a84d201,2fb24a2e,9ddaedbc,63e8de82,e18de4a3,c4d021ac,8eaca26b,3b88adf2,d19d9d52,c84d83ff,89451750,6a77b4fa,fd717b07,4b414322) -,S(7ced897a,47b5b0d5,f4db6d9a,ecd9c5d,54b35789,91902324,6f270d7e,7ac4b377,1c6ce993,fb84c89,ef5dbdfe,68dad70d,ca39a4ce,29cbc658,d5332d1a,6f6cb157) -,S(60d1d74f,660a5f6d,bac1ee84,5aa43dd8,889c9e4c,6b0ce1ab,e9952ea2,7146972d,dc4291c7,db1dcde0,8e618261,b8d177aa,77b5b0f,2aa8f341,8afc9eeb,dbf068b) -,S(a8b28606,e7040dac,7941cca0,b9cec031,31db3f95,bee7d6a9,8d60c3a,1091f81c,3fbac401,61c81632,ac8655c6,d5c02744,7c836244,e228b9a5,bf5d799f,1fb810ea) -,S(6418a48d,2705a27d,5fe68188,58a61a21,4e4dd39e,4151aa89,9fc6d414,95f975c5,21abfd32,14d98ff7,5b154250,8480b32d,ea8c50c2,3400235b,be800520,1609c7a4) -,S(b46f6f80,c71cb354,3058372b,9ba5e6d5,2617728c,54c10cf6,6ead7ca1,de2700bc,2008111e,c4b86ec4,26bde7ab,f52bf201,10787bed,d7b2e922,e3a5a60f,e68a0f4e) -,S(a0ef81c3,c9f78950,41a8d90,69cc22e9,22bc0cac,4e61a030,495ddf48,eaa6dcfe,8617df0,b32975a1,6666f86c,136e8c99,c07ff948,ff8d8176,9d968544,aee5eaa8) -,S(c03cfcd4,21cc7095,5a3e10e4,a4ed12f0,d31abe86,506da6e9,c83cf6e1,df73d093,8d6f0b3,c0d6edf4,b5d2041a,94d13f89,91adbb03,22ba9f,a56b31cb,63d4400f) -,S(4085a2aa,95e4e8f,11b0e94e,2673c48d,d42506a1,81d93a19,b5f79d45,ab88b688,cc769f7d,f45cece,d3cddf9f,c75c4dc9,bb7018cb,f54986da,434128af,b26c0f28) -,S(a485186a,b21c4650,e9f7375b,2ba644db,f22e2db2,20933cce,2bf0ca7a,c404fcb,2d227efb,68649a60,bee9461e,9390ba02,eb133cb0,eb8388e3,f64d23a4,332ec903) -,S(9faa3103,b212c2ba,9a454898,fb451d17,c3632b7f,c9368452,3ddb88a,7599f14f,9dcb34ce,51f7c4db,7cebb0a2,1b50ff2a,d67c6bd9,7066e505,60132168,3be236e9) -,S(1bb9ddd4,804edffd,78d00b86,ccf6a07d,a798d91e,5d88f2a9,37575d96,81187564,6577e8f3,ac22184b,d46339b8,25a426cf,2dc8cc86,78767d87,999a8e63,5789dfe0) -,S(7b32d099,c78bb658,24868172,1b375689,b91f0650,45fe3d9c,8af4a331,2acfdf58,a4c92e67,f4bc53c5,aa84cef5,908a36ab,afcbaf66,a946d98d,4254271a,b4f088a5) -,S(daf23c72,c67145d5,e2a55109,f95742d9,28cc16da,e53d0453,c8dc22fe,a9eec7f4,205dac83,6614ebe2,a55c04a5,970d4ae5,a9ba4b1d,d8d51f52,50de622d,2a2a472a) -,S(6f156518,addc53c9,76a16944,a059a465,8c49f6c8,6ac4339e,82a2f69f,a3599279,50a277ea,6650fd6a,4a5e4c2e,fb09bfe2,78fe8fc2,c7a86089,b4bb0fa5,fa7262d8) -,S(17661b7b,5b5a8a4c,f700397a,1f819c7d,a6c44cf9,a7d28bcc,df6e7fdb,efe50580,dc1d7f84,841d8ee9,3a9f9fa4,6a03b2a8,365398c3,f94b57d6,77ad4238,264c7868) -,S(c3042389,1483fe1b,12f16146,f48ffe67,3a1ca3ea,ea330d54,db5f7c95,fbfce6b2,131d108c,14a4fda7,77d323f3,f717fdd0,a422acfd,20b9db1e,2b2c4039,a330ce3b) -,S(654da43f,70e4c85f,c9aa2d5a,12ce1a51,d4364a09,5c230ce4,f8ae61b3,cde7fa4c,f82cfe9d,bec57ffa,4109e9fc,c9d79135,49817f50,9fde8195,79190d38,f0afd2f2) -,S(c17be24f,d7d2535a,c4eb722b,bbc4444c,fa529cb1,283585c0,730813de,7219b481,2d35a0b2,27582d2c,b8155b92,680f6651,c0040508,ae3de034,cac87591,654c0c86) -,S(fcb1fa46,f8178153,fe5f10b8,a91a411b,cdc4cfc5,61b5eb2d,29446a79,8deb14fb,29c75252,4cb13054,2b9c1a26,b4606eae,6f40ba1a,f73d006f,5bac65e9,3821f0f0) -,S(7b86452,e43ae1f7,177c131d,999b5fa,a6e4a107,e0a06f6f,4305a8ff,d1ead9d8,3e7cd53b,b2f27d89,829e331b,8236f92e,fcf674c6,478846c2,c18307c6,e82691f5) -,S(8271b58b,67a27540,c1d8305a,840475f5,3faa0031,4e779e2b,9e578c07,366a342b,5cf145f8,6fdff832,6712be08,ca1f3a27,d3e58fc0,baee76f7,a052f7df,450dbed2) -,S(3f027c76,4ebf933b,50df3d37,77f60210,4b997d1d,4b9cee19,cb549c58,b5d0fa23,cb44dc89,c533abb3,e255fbd2,6dace4aa,836caf4b,2589113d,82ad1886,7eee5d80) -,S(fbeadb62,ffe218e5,d0245d5c,4bce7334,cbbfbe91,610e8bd9,f0b89953,bf472bf6,7e824c09,9727cd33,1aafba9c,6776815e,3f954fb,539efa5c,fc4ce034,db602c09) -,S(ee2807ab,44643652,12b021b0,dbe94618,5d22fae2,f500a740,127f4dfe,32ee4c60,d958ade6,cb9d3a,ae21602e,d25556b3,b3869202,beab0910,1a1d97e4,8e360e1) -,S(94ab159f,2448f865,f3d38d65,12273da4,ff476289,3dbf74d2,ef889807,81d6802,88739de5,da331b70,87c58bd0,d734bd75,5853753d,1d3b97fe,39c68555,8868576d) -,S(98d2e8e5,a41a0bf4,a880a510,b4b65321,7b9a62f0,c466c589,d0c1634f,557666cf,aa24bed8,a5cacda,bc3c950f,d56bbd1f,f156efb2,4632e073,ac822875,2617d1f6) -,S(64efcff2,76cda1b7,c8e5ab1b,12c73a48,5a25113,eb9a5be,496e52b,ec6ad16,ac29e2d7,18bbf63a,16003992,d85a9090,98ae89,834dcb24,293d6bf1,b8130e3a) -,S(6a8e3376,1636ef4d,b1116d54,34f3fa05,d8cde7e5,31b260ee,6aa9ee61,1c4cf5ed,5161b5ef,4bafa1af,f76a1e21,bdad444a,2526cf5c,c81636cc,36f18400,b8dc47af) -,S(4786ac32,6312dcbf,a1386ca8,c505715f,2bc7f85c,22b6049a,e4386bec,11648013,67c80d39,bfb6cc58,7fb312c3,8fea53cf,6937216e,8e7f3b3b,4a2290e,6d6df687) -,S(b87d2d08,ee206c18,646713e,8af6bfad,c77754c9,59158fac,c31928af,c66bf596,6110c98f,bafaffc1,7b40277c,17ad9650,15de7069,705019c6,b7a74cae,eec6e65b) -,S(ea9f310b,d088429e,236d565f,d1b3129c,7ca8573c,191d1893,c1c157d2,a0867d4e,61c95d39,c1893c68,fdc60ddb,27909f2d,98c9ddd6,efc67ccc,7482c0e4,3c05b144) -,S(abf862bb,9db85d51,5d6a37f5,5f3942b4,5404238e,d49d3124,59f9ab38,29b34ebb,30d13c26,2157c1f,1ffc8a46,a3679e65,35be1981,c202e7de,10de5386,db863739) -,S(80767b75,df3e69dd,757b4c4b,fd0b4be,f75fecc6,ae22b488,214b0035,a276e492,ceea1fbd,bcce30be,2d88b601,895a8fd2,92f61b61,cafa5589,f9eb9652,8a78fbce) -,S(8b7a47e7,dfc35093,77771622,482e45fc,84708ab2,c9c734d4,fdc9e8d2,499dd950,dbbd399a,d62e8309,14bd0ba6,19a9963b,8aacc765,cad19734,e2526af4,2b2013d4) -,S(13700ef1,f1e82cab,7e9a7d79,d76fcfb0,b6e8c18,ec1e6546,d27eb919,bd871f2c,97488000,f96aa2a1,5913502b,30ae5bd5,f9edc84a,f97dac7d,c79be68d,a0f7f4e0) -,S(51f9a79a,991fe61e,c5b7c93b,d0905bf1,2fea0e0c,bb9e9a7b,d5d99188,f42c8a16,a3ffae0e,92e3bde2,51c9a8c4,1a6d05ef,2fa2ed53,d7a21402,e759c102,65d96000) -,S(ec7c6892,644bcff,715b027b,be48936b,26dde18c,bb4a1a9c,fa1628ba,84d5b456,51bc2b69,b76646df,51644c28,8570bac5,d51a0e9d,6e9f0ce7,1abf6812,650b18bd) -,S(efb8249f,bed3299f,7715b3fa,b6a23bf2,86560ad3,72e31e6c,ec725522,227f5c2,f36f4624,59a7fced,3c621158,8eac73c5,54593c4e,b7c82fe7,b0951bfc,8987bba0) -,S(4efe94a4,c34083dd,49762ea,eaf58feb,72f6e283,9931b706,56427bc,e9913bd,5c8b9448,5c687c16,76605dc2,d414f37c,da98a562,c71e7e72,fb2b8d5e,6ae0d60d) -,S(ecc5864,fd6a1f7e,1e20a84c,d9dc7090,9775446e,2e0bf6cc,bf896bf7,97f9dd73,49eefb1,981d4b87,ff21ca80,5471770e,8e063541,58e9c1fd,9995718b,14d9d6f) -,S(133f3710,9bcf5655,48d03c90,b82d55de,cfae1cf8,a5f3e117,5eaee107,aa7eb121,1af96963,e9113d2c,588ab083,58df45cc,8b68312c,9aaed504,3f17fffa,b29bdd7f) -,S(a8b1b9f3,971667be,2a65072c,efe8b1e5,e64f652a,4758f51b,4888087d,4fb489b4,556d9a3e,c2861fdc,da258a1f,8c6e81d8,1df43669,e64e3daa,90dad4c7,c6c0b662) -,S(104889df,dd81534b,655921ae,5483db4b,b3227f2,fc3563fc,4af46e1e,2c4fa88c,a70984a0,ce97af36,b827aaa5,218a9743,73feb2e6,fd7e2a02,408590,47323ee1) -,S(4603c58f,4fbc4575,7e9e165f,8a4b41e6,b0d2bf09,b1124998,3881ecef,2a8852d7,37e5990d,7c50bed3,2b72a43a,2e6a0ac7,5676cc82,113e3196,d6569e21,3adcd0c) -,S(5d1ddb75,774d6419,9f07f578,21786ad5,9fd7119c,f895196f,deec090f,1240748e,519140b0,1b340a4,a7aa2864,fef5a066,feb59c6,3355c222,6805e45e,160bcd9d) -,S(c9f86104,62644b3a,ec4daa3e,bac656b9,de816cc3,a5aff1a3,633f90af,8401a97f,405087e8,80403629,516d485,f17590a,1277e058,840b3fac,4e02d3bd,7be92954) -,S(b774b1e9,9f42b296,dab0e371,6d4ee04f,8bd517e6,7846d0b3,3ef5e0f2,569e97ae,ec78bffc,d6cfa76e,513a2b4b,db638f73,519b570f,f423936,ec0a54f7,9ceb5f9) -,S(d7a1e238,ad3eddf5,29002e8e,87476ae3,6668d656,595b3d10,2486f1a5,c30e6a28,5c9fdd1b,e132b9eb,4d7b935c,2209e105,55cb28e6,c4616be5,7b248607,697ef6e2) -,S(832b146a,cd002cb8,199e800c,47b2a0cf,d96591e9,91f1b406,b2db981f,c0aff924,f64632de,b99254ce,9d60b026,76551e8c,e21b300c,86fa5bd,8bd7c32a,4a81a18c) -,S(635f97ae,1785487f,437fee89,9ec21d13,dd8228f2,e209637e,18c85ecd,6cf50202,b53fec65,1a1af1ab,2f51eaf8,8a3af104,e1a40e82,691da03d,9a179c6a,3b30e5f9) -,S(f882f983,99891dcb,d58b931d,c215ca05,a232aa9a,7cfe5acb,5226ebe4,f4a598de,3d0313cd,aa36668,5422a6e0,2dd7c560,11fef0ce,3c268a42,3509991a,97cb4562) -,S(5b16de8e,3f8b8670,a98099a5,250e3102,51107cd5,d04bb804,e2a7175f,48183594,33c3d3f9,e3099917,e707a429,3c83205,4a26cf2b,2a9e3118,fa64f441,e7561fcb) -,S(b47e085e,c7a7977c,be3e2329,ea417e98,e86eea9b,aa23fc93,67cc06db,cf06647,cf6f1cc3,f564879a,f9515604,4b7b856b,827335af,5cdcd55d,1f8bde5b,d3f539e5) -,S(afd1a856,e0624d6c,16a876c1,2f78ba44,303460f4,d3cc793b,5dd32a98,d8aca9b7,3b334e53,83301f24,df0e2df6,12cbd7fe,3e1b6650,d5355bb6,c9d3873d,f42d73b8) -,S(454316e,69f558ff,6e19057c,9c754b2b,83eab233,f696ccd1,b80bbb42,3c81ae57,ebbbce3d,4e1cf2a7,315a394d,d03bfb64,300ac0f5,11627d06,7a5341b,43a4ace9) -,S(a51f1d61,dc60b34c,65345205,b2a316ec,766560b9,c50d72a2,330f828a,ec978d05,d4e9b10a,58bfcc59,ef24379f,532784a7,ccc4c077,8aa11bd8,bf008846,44175faf) -,S(771329ba,3ae1f814,764fb9c9,ebe68f37,26b8260a,90d4e49a,7dfbfd30,80cc6128,128479e4,bbcd5b06,ddf46f49,614f6ae1,bb8914a0,7a0a5bc7,34b69b39,caf71b1d) -,S(aaa59016,d18bc9e6,2716bdb8,6d0c6bcc,e04f74f1,98f17675,c021d078,166c9fee,36cd35fd,53be5c17,84dec1ce,80ab3ff4,95abf363,17824a12,71cef620,2784f91) -,S(be187d0,b3afc0,bcbf98ec,bf31bfcb,f4121265,c4b815d6,9403d9ef,926cd254,a3aa0d55,8b5f6720,9d8a6514,fe22026e,66e8d972,912a6503,5faaecf0,ac2d9b25) -,S(228afb7,a9564fd3,641bd417,20a0e44c,d2ab5d99,844fa61e,264ca823,e197da88,24457982,391e3209,88cc44fe,e42cd242,80fe1f64,b87814b9,bb485d2,ed0d7757) -,S(dd55db40,e3333379,7b8ae013,297b477e,bca2f586,16f29300,6625aab4,6c367ee9,836a69d6,603fd34f,92d3f775,d25ce89d,b92d2803,48a21178,44f9273f,1a97a9e9) -,S(f82dfaf2,5113d8d5,728c53de,3b43f2b9,d2aac0f2,f90b762f,390f745d,7e10093a,1097ff80,ef2f5dc,88873c1,2b5acf0c,a8a803cb,ba3624d,4a036649,ffa07bcb) -,S(666f1006,57ebb1b,f05f50c1,2bfa7fe7,cdf11e0d,6cb37c99,4b39df89,acefc7e1,3e3ceb4b,eb292e5,3c00e4bf,ab6dd9d3,becfab1f,19880c3e,cbb93a4c,415f67a7) -,S(9769b542,3b098d8c,18871a53,8403ba2c,d32f556a,7ca7b089,ceb9134a,5d983e73,536e7c80,5c71c49,9d9acbed,c6fd94a8,3e64a2c,8afd8721,12f6848d,60851084) -,S(26081d34,3771ce6e,39ba59dd,2c2e15c2,4c6903eb,b6c157fd,b1c51dc4,e5343bf,82f6d675,39d04825,4cda5bea,e4879547,9570f86c,9ccbe1a2,ee0deb39,afcf5efb) -,S(feef7b4a,dbb0e287,a0762b14,445a8fae,b860e08b,19600b41,45d92447,be732bde,44e79fff,55aed478,f8d951e7,f4a327f6,c4a1e282,ce617a3b,5128f528,33851e5) -,S(ffb8488d,f26d306b,70b5b1be,4b6f2e4e,b6d6b2b,4cf05d3e,9502f3f9,81406cef,f2891496,f5affbf0,bc60c46e,b96baf7,2a4e6797,3297a28a,948adb92,1cfd5dcb) -,S(fd1ec3c1,736f2edc,5c080981,fdd99fca,9e301851,cbe8d840,38f03a6,59f21ea2,86755e0c,7b01dbff,ed701a7e,b5deb21,3566f331,d707888f,4f658879,cfbf3bf0) -,S(addbda08,d536486c,b9d0b4f1,5ffc9104,ff75be96,739d4641,a405e2c4,2775fa4d,4d70179e,1237e2d4,61a0a0b3,c3bf9df7,9483afcc,1b8fe02f,47d4b312,2f339089) -,S(fb5e9c09,8ff0520d,b162e57c,19b80ced,7c63ea68,1c7a2c56,2557a1ea,d2d7a46b,c4d9cfa0,d31cfac0,78c187dd,2ccea738,4667776f,b8eb0935,9330fab4,b9f67e2c) -,S(28c33364,1762626a,c9e4d2d0,53a1e5f0,771449e7,a0977f2c,63db4681,1c675b45,239e717,a76b80f6,2b11c6f2,c459d516,bf81dbb1,4dabba88,9f1e627b,5fcb525f) -,S(68e783ee,84fea44c,59c46bbb,170d7751,c47fb05b,602e9995,2469def7,cd061c9b,7054cae8,31dcb37f,ae8d8298,859b4e56,772f8a6c,d079918d,b49c7bbe,cde61f16) -,S(1526613f,fda17eea,1a7930da,c1be4a6a,4ddffaa5,1adf3c92,73f3a2da,44d69c46,c9c3d04c,996c4d40,b906bbcf,5b0ac89,f541ae4,81b7c5c1,8f9b5762,7b9796af) -,S(263e6099,2adc9f24,1cd1c16c,de291760,babe6e41,d4e3d064,f1a8768b,94bc5439,3ba3eade,1c5b8225,7559c0d7,97c47e5c,41f60195,463b2eac,74801439,b3a6663) -,S(ce58e7e0,73c871b2,673e18e3,c9ebbb8e,e6bbb2d6,226e3d0f,4bbe6bb6,73e72816,85ba41f4,13158058,fe8d068d,df70f97c,acd4f512,cdcded1d,ff9c3c39,eb1ce1f3) -,S(47c3eb29,1402d2d5,25a95ee6,fc54d1f9,721f29c1,e5b51cb9,d82d234b,94de6594,beb5da30,3383e0d1,4d13eca0,8eb8af0,14f8220a,81b1e8f6,47c1f95c,4503380e) -,S(8f5e8092,c71ce97e,af578fa,52f174d,ad0133f3,94bf2ca,ef5c7adb,bbb37ad,1ca41380,ac714a5d,3c6be070,117b10b2,dcff62d1,bef220e2,4063c971,89f6ffa5) -,S(edefd606,5883e90c,31215558,b05f297c,45c64fcd,34cb864e,3f0265e5,7e7d5a4,924502b3,1d0e8df2,2a54ae07,edf1b0bb,f2ad1df4,7de805a,43ae11ae,8cf3d628) -,S(31516a47,50773473,6e691ec4,e6891eef,601d6e42,d7f4ea4a,1e5008cb,b77e151e,7f243d73,6ec9d71c,d2047cd8,d97c159d,345003d8,72556e94,4f7aaa74,acb8562e) -,S(9049e0ee,149d379b,77963972,1027627f,5cf68f7a,9b1c81fd,189ae6dd,eea5c552,ecd60031,71dd9199,77ef92b4,262388a0,7aec9cbe,65d80882,1847a5b8,c758ad26) -,S(977ac11,98214ec6,eb92699c,aaa9c219,6246df82,85a6afd2,fbef31,a5a93b8c,27e01787,d6e29c74,f6308e21,24f9fa99,6a5b78b5,4f45fc95,b71430a,abfb964c) -,S(bd7ead55,e8ebc96e,5429f59,52427ca3,8dad3d9d,649676c5,52a01099,3c359a26,9e596b26,8c90186f,8cf38e1b,f47d6d6a,d7204c78,b557b3bd,25125bdd,c3ef7824) -,S(90c82d89,9178857e,e2563cdf,d822b872,2901b53d,3b93a6f9,2905a4a2,163be70d,3779d0d,c99fc814,8b2f58c9,fab70952,373365d6,1adb6e5d,9ac3f761,9f27e943) -,S(a312a0c,3111faf7,2cea8b7c,3e2786a1,65362caf,11919687,3368c77f,117ac42f,1b78c42e,af0e6219,ccbe3ed2,384f5529,dff57894,b9c82566,255fc4d0,fc798b6a) -,S(7cd723db,c046d3f4,5b0fa248,1197790f,688632b4,5f57569e,2f7754c0,9fc9bcca,eb5fb704,a5cc0b22,979bd64a,790f428,b57bcc79,3bde8fc4,4d6bc9b1,8c21e495) -,S(2b24dc16,59324483,3851815c,1675d051,60713a5,7dff00f8,9e72df7b,d1c7352a,ab05061c,224fb577,a72f5d2a,38a9e59d,18c52645,9564afca,a9539d0,c64c8fc6) -,S(955ffe05,c4653033,c2b4afa1,fcf8d3f1,3b55c9ba,80d67c37,598f6d87,97f11b1f,d3502a31,bb37b950,93b3e594,944d4bac,3314d490,d375e118,4e8c5a7f,2346e6a5) -,S(699392f3,c2baba31,1bfa8aea,180283c1,9036ea92,f287fc08,adb32fa,6785fefa,242acb3f,fcbce5f5,9dba097f,3d358862,11232403,2730700d,724488e,8bee3478) -,S(193d04f3,61eeec14,633c702a,f8e7eb22,2c3de17c,a0130e9b,cbfb3daa,94674d24,39b68a32,79e62533,8bfda780,9f0f8264,ed2ba2b5,ea9c0035,6459882a,a943e088) -,S(564387e1,ed778e70,baf9f876,2a0171a2,6a4e660a,bc6eaf1c,7ef9f00,69794817,7cf553f9,128d0716,e3c81039,3d1ca83f,1cf0fd82,7f7d4ff0,ff538637,34ef42cf) -,S(f0eba12f,b282171f,d20aef8e,192741e5,4469c5c7,bab13f51,7084d293,c3c294cf,bb0211fd,18229247,5238ba93,f6992d34,a41a7ae6,78750b04,fd34f3cf,af61f90e) -,S(a54b91bd,b09d29ab,f4cb354d,283c436f,a8e9cb20,d3a7fd35,e59f59c4,200bc13f,bae1af42,3459a852,bc16d45c,cd35fd94,c0033d89,5c86fdfc,f4fad5e6,3bec2cd2) -,S(a9294788,b2c9d997,18193553,403350af,78008113,ed58cbcf,a2816c80,46f75d47,dea8059,c24c1c84,44a0263b,2896725b,79c2c8a2,6d425479,f44bb7ad,225bed8f) -,S(b6967b59,ea3d2899,c14fd2,cdd4590e,68dce683,de275313,ec94d5d6,1bee65d1,67eb4a27,8813f69f,e5bbc586,15dcab17,11bca30,77327665,2fc333d0,52fd2a0c) -,S(ffc0f3fd,241ebede,ddb0c43a,a9b8fc2a,9e778963,1af8d54b,bf99c64,add0cd7f,203e3aec,321e40fd,414c002c,e5c6cf90,2f3e75d8,ae0e3604,61028ca1,e21da260) -,S(d8f86220,c390bcfc,f714ec3,8b6f6ee3,d37b41da,4026805d,6fbbc798,8a936ab2,7c0ad863,31ab776f,c22b2539,fd65086,2cfd2ba6,2f5d67a1,6eb957b1,8d812bf7) -,S(11295381,19a146b,442c3447,400b6e7e,9b2190ba,dd42a75e,24460ca6,45a3cb88,44950501,75662a98,793416c5,3c55febc,7babcd29,398d6099,23e1c3e1,92dac1ab) -,S(d7cf3779,236c4a8f,d592525,d30dc0a9,a3318c05,1823e0b0,43a6542d,f38d92d4,1f866df2,429a3dcf,1a285265,18308c25,262c1ea7,2aa2267c,39a315c6,dcd22ac) -,S(d2bb0f89,a0897404,25fc85ce,4d8fe24c,ca061808,e426b08f,ff49a525,137449b0,fc4c4bfa,2bf202e,4d10969a,2c4ca383,17a8c179,20dcb965,7de7aaa9,6b97ff33) -,S(832d95a0,cfb91494,5b43d9a0,4f037266,2ad4453d,353f6e78,47d4aefc,449dabc2,6ec0aabd,3c3981b,8ff55747,63bfb800,453f302a,8161de79,b6b623d9,253124f0) -,S(3a224983,f83c41d,33d3aa2a,c9d29ca9,55850388,a968407,664b2830,3967f25c,7cc31841,96c4fb8a,953602ec,3c79ac75,69e1fd1,7a263946,27826a88,7d651f79) -,S(81197d87,1452332c,2fb18793,c0ebeca,3d1b8a4c,f161b709,e3da21f,3917917b,56a0980d,1ed1f77,3c960de3,1ce4aad3,90a5ea76,fc410a2b,107ed82d,b8bdbef9) -,S(b8204012,c77ebdcf,790f48fc,4acb23f0,b03e5d40,6fdcf212,81545200,faa2b4b6,b8718e0,12ed5a02,16485561,8a5fb6c4,ee4db08e,dc9c1842,881287c7,dc7191b3) -,S(766d82f3,b602c418,d020596a,58e61400,20f58fd1,52448443,2f816dc4,8d437750,d17969a3,c71ea79a,3854b526,efd56f8,148b2d79,3ea3c76e,eb14ab7e,de5841d4) -,S(35fe7655,5d4c88c,dacad9ac,1bf125d9,924276c7,8c2ea9c6,a9c1ae87,52d1e323,9ce2d43,ef8fdb37,82a38d69,972229df,9b9c0c98,abad263,1df192f7,e0e75324) -,S(a29581d2,55efc206,4d1d1839,621daef2,ab049724,167ced73,7566f4cc,3a81f5ad,7eced1c0,575b6152,38db2928,964f7713,f65edd4d,c31a4b34,ae20b6a2,babaa8b1) -,S(d7787fd3,75473801,2370e71f,4d2575a5,b9f89e11,aee370ca,2660dff9,dc6a807e,2875ab09,bb1b2a7e,cc6cb39a,939e4a91,2ddb1dbd,5ca43ca7,93ac663,552ae91c) -,S(1fb6cf61,e8be4d39,b36578cd,8853da6a,1e62cc7f,29426838,a7ecf0a2,77395288,1c018114,2dfbefaa,6bfc2957,6b79c91b,16cf03d3,81285e2e,b74f71db,1986e43f) -,S(511e9c97,866e651b,c4e32e41,92f75019,42316ead,6a0cd78d,fa61e0f1,e76aab8a,2e8cd531,d55bb19e,886b86cf,f7105591,68a9507c,7d78d34b,9ec50f92,5485931f) -,S(74afe7a5,6387bd58,d5996a9a,9650730,44141ca3,1f5236e9,da977289,73c9d434,be7311c2,b4566819,12d13546,8ac1e26f,6113b960,3039c24c,5e77edcf,de452567) -,S(5b545191,25d5f8e,cfbae2ed,bb724782,d07ff380,10eca9a9,29ccc9c1,ecd0f04d,21126f87,a0cf1824,1040d707,4d37e8a3,f035471,63de669b,9f502fd8,92322dfb) -,S(5286fb50,1a525e82,a944d1ba,eab49572,52d86693,19af1367,eaa8d5c3,e73ee8d9,f2abec43,68f3800b,30da81de,5b81e564,f94942a4,9409bcb,a9faffd2,51daa0ec) -,S(7b01eb86,c102438,4be1f023,90a5ed7d,beea652d,cf3ef77f,92fd883c,f2993069,becae52a,915d1393,15435d9d,edb72e2f,fb9bda33,4b2e39ed,6e698344,9e1ef819) -,S(3955e911,874fd6d6,74e04ed1,ea3b43a4,486a0ac4,19735114,3b451c3b,3028a674,3552c619,a845adea,64951c82,75994959,8609a3d,2f691d0d,5947b474,4636e06c) -,S(b67801c6,d96aca89,22d8e7a9,96e95729,c4c29d63,180e4f73,dcf013f1,98eb0d29,876e3361,d82f58f3,f1292315,1509ed62,2e2a73af,d063466d,4af5cf1c,1ffbb150) -,S(1efe4004,1c7ddbba,1aade160,cec007e9,8abfcba4,7d292839,4598b5c0,1b763b10,d9f00f5e,d0868390,230168e7,c5839be7,cef8ebe0,b3b70d73,ebd92931,678dadac) -,S(2083d5be,389e4bd0,23f7685f,2ad00b23,e3687672,72183afb,d5d02384,36d122fb,11b6176c,c7554617,935304d0,4e12e8a7,4bacc20d,d438bf77,a1729a15,b424937e) -,S(8a9420d3,93ff0ba0,25bcbb4f,eaaf715e,4ab14281,85b2dd91,f8eede56,f3006e46,f48edd10,dff93031,2b5df63d,ec9c7a2f,ca373d77,65033de3,8a54d37b,2ab1f4c8) -,S(64a2e8bf,b42de0b4,b2dc8fd5,9e3b2c18,753b43dc,e914fbc1,478818f8,145891c5,82583660,40ebc62f,d5526ecb,9f952091,47f7048a,4004a0a4,7b08905,12ac098) -,S(eb97193,28c44e0a,3f2568bc,b99815a7,c5c2e7b7,90e7fcb5,a2e7f7d9,920404f,cfd26c16,e6709873,1219fdc4,aa8ed998,c6fef955,78d7908c,c72c04a4,4bcf305) -,S(cea3219c,e03a2433,f9ad8d93,73a6bef6,c1f30b3f,fa79d7cc,6ced36be,9abc9c03,13ea8ed6,a0dd8fa3,29bd7563,a34f3499,6442b03a,f2eb703b,d8d5228c,cc4c4e7f) -,S(2e1675b4,f00a0843,89b0587b,f0cb723e,1a833539,c024caed,36101cb2,bc4c4774,ec1d76d2,2752a662,5dafb3c9,6235eb94,f9af1286,2b3eff6d,2a0fb965,ad3173c7) -,S(b0eb3277,7c8d1b09,e22c9b9f,1c37e8ab,74be3c49,7ab6d73e,7fb6ec11,10602438,6d44054e,a4cb4a22,3811bbf6,6d2ab2dc,f7263d7d,6421a368,9a9ca4f,97fac66) -,S(48254bd4,8df24e2a,759c5ef9,cee30855,1c1f79da,b0a32695,2196ea1f,987b6d70,9c12a458,f39f4880,ff04b96c,72b8877f,b4ad0020,495626f4,1d9b32a8,84f7a36) -,S(e3c6dc6,cfd0b94a,57b3d34b,3a77f4f4,45328a12,764e4619,efef75f9,f49fe8e9,5c229420,500f2fa2,888d834f,a517188a,207d8f88,c98b7b7d,31484a49,c4d43a31) -,S(a8d9d9cd,def3362c,b260ad0f,3de51aa5,db066c74,4166d9ac,57db782f,656be9e4,bc696df,80eaccdd,bccc9ac8,960325bf,1a0e9aa6,100908b3,cd0c0ce3,43205db2) -,S(38281034,a34cd153,34b6fdc3,26fdc558,555147cb,534a1c31,89beec74,5a2eca97,f4371a13,a65de538,f31ecc5b,50ce4b92,d5dc5645,9e523851,f6fcdac6,5994b5e0) -,S(b745114b,449f0d7a,4521d7e6,728c89ff,54131e6d,8add9f3b,bf18edff,bebc6ca1,18678d66,781a9120,ba33e01c,ee3fb1ac,b7790f18,b30a651a,99b913c,e621eb67) -,S(5987629f,9c26a8cf,ff39955c,3144f4ab,c4d094c8,8270f3de,620fcdaf,93a7fa9,a554b7be,24e49819,f1256c9e,72b8d981,2aa5984a,c942bd81,5709ee03,67894a07) -,S(8fc9dd0,d84cf297,75ece75e,8cfd7c38,dc9f602a,b0152b01,982be4a1,f29b7290,ed128f96,2cf60503,7acdf6d5,9578ca8,9a232a0c,c432364f,2b661ac9,2a3176b5) -,S(c8b5b1af,90d64379,f2c02ac9,51ff715b,2978ef0,bc87f721,3edfd09,983ecc35,c295c0d4,964ef85a,59490ae,dbfd98bb,f6096217,d7633f0,44470b6c,a1816b55) -,S(b4eabf60,c44d78fc,298b2c90,6cdcf7da,a23d095d,867fd304,513f90c5,437775c5,82d906a1,2d10d6d8,e4c843b5,48ab645b,e6f32104,f07d8fd8,c128351b,e7b526bd) -,S(b19350e8,a5163076,bba0b2e7,2159865f,59a8ea83,b0154fb7,64308bc7,4d0bcfa5,29e4ca7a,554269c3,21a12b37,a4fd0fb2,d3e57ed5,4e79423d,f715bd2,ecda9907) -,S(fecf1ff7,663c7921,40f4deac,ced92484,8c66bec6,f4a5550d,c340896c,5543b886,b2621f65,d52538e2,92a50808,9008efa0,8f530fd9,a321bf30,6dd24f26,c9a1208d) -,S(ab70fe2,355d6d6b,5c5a3f5,a6bdb605,86372165,b8f07d2b,ccfd61f4,798dcb7,7adfb6d3,dd44adff,87ce3727,efef0bc,6fdf9f49,44fbd238,822974d6,dd57e8ea) -,S(5ae5d60a,efd1dae2,43df9d7e,ca025c3f,452b6c62,216c1c1e,8b315ceb,b94769b,d90d73b9,6e33cbe3,6d96c45,656f098b,e7e57d25,dd03be95,8b9cb2a1,d00bb434) -,S(fc51f965,bf8dbdde,b5fa4af8,7abee8a9,a380918d,4d8524e6,73f8501a,291eb96b,ceebbb7e,35eda612,47ad8c8a,5d54af8c,9dbc9bd1,194ba5a9,5844fae4,b658496f) -,S(368b51e3,778f8ddc,2d09e9b7,fc2808c8,ac793edd,244fe177,fe3229a,e5a6d919,5b3ff9e5,af4c6ae0,575b553c,c0ce17cf,fc4da66e,e19fc3f6,2d047007,e1716db) -,S(ac9c4efa,5f63ca07,35fafa0e,9612b459,1a764955,d435c14f,91717e42,26ec0186,5d4d3ebf,9a064670,e09f1d48,79bc9e3e,22198188,5610731,29aa403e,73d7777a) -,S(2b5f951f,360dbecb,9eb1d31d,b414aa13,9d9a7d7c,ed952a72,c0f93a61,d52fbc08,8d46f1b9,cb8883e4,cb504715,eae4326f,11187e46,de477dec,2108ccbc,2b3ddd35) -,S(25a3593f,9670924a,a35c2008,bd8278a9,a78d22d6,572841c,98c4399e,26f67cfa,3b07ab0b,8d400f1,af88561d,af8bb7c6,a6e4b7c6,a8bf5915,4cd85291,66ecd965) -,S(3f03be51,b35e265d,d9cb974c,4ac021d9,d22b2291,40016bb4,e9edf52,36193eca,a17df05d,e4b0e5bf,c7ecac3e,e3253017,cc1d47b2,9fd3d1d5,411f2660,c34932f9) -,S(edbe9bd6,f16782a5,a00d7003,488b9291,faa4f22c,9602c736,a3698587,995d25d,64569751,212d2f6e,c2e7a6a8,973be7fb,c49d7a0c,8857fe76,f9c48011,735179ed) -,S(1f477d33,1fb16ac7,45c29e48,77df8c17,83f69e85,5a111a30,e4717fc8,ebf85377,64c947cf,64a66ad,8a417bae,1bbc1cff,56826349,e024d3bc,bc4a9078,f4bda708) -,S(b8ef8b11,901602cc,9fd1559f,c4bd6bdb,22f9bb7d,8b289c6b,fdae85c3,e9aa3e9a,60b3594a,7349c920,33d816fb,295f41b2,7c4d1d86,b4c9d2e2,2cc3f4f,e603f582) -,S(eb6b31eb,198741f7,49e4b69f,85c23e4b,58e3223b,df8537cf,60a94411,f03e0071,576746c8,ba579896,969c228d,67a57cd8,8501e27c,773a3444,35b7e860,bec9f471) -,S(47193aec,aeae207,ad675228,f4506db8,40a316a2,6cdb328c,2af6c24b,bd5e9a8b,dc67bbbd,ca7cfeb5,981571f5,7022986a,4ec3e408,b641c34a,57b7cfd5,5139a1ad) -,S(ae3c9591,c2768a02,f99b0076,9c56fdf3,1a98fae,1eca3680,38698abb,1d44f961,ba9b0c42,90c2fb0a,ad84754b,e1c3fa0d,7e34f737,f3874af0,4ed2824a,46efdb24) -,S(178ef542,8c4cc38f,f088c383,71f0ead1,4e7b4423,6d90bc7e,9ffc3db2,fdbe9b9d,a5f01afd,74aa9324,b10f6041,27ccae19,24da7b23,72269ef,ab984fe6,ba1b347b) -,S(2df7e5c1,3d0fdda3,3ef8f69b,f0ebe1d0,8649b106,8c965d97,37a7e9b3,c13f4c92,eddbf5c6,324853c3,7d478864,a68d0b40,2c28ac46,295c00c2,2359e10d,d0693d94) -,S(671abd13,fe274da6,a5cb6119,f33fc88e,37ee1b75,59adf215,e08fcead,ee946b8,49d7cd3f,3b8162f4,a85787c6,91bc29fd,69eaccb7,1354bbc2,8ba17227,8a8689fc) -,S(b69fbdbe,e72b1418,6fab59f0,6b57d940,fb8cb5cd,92c53727,a0eed42e,532ed39e,71f488d2,e104d21f,c816631e,d774a714,94c0c609,c86ee052,210113d,672ea302) -,S(1d5b8e6a,25fcc50e,a4a5429b,6233e276,47d978d1,28a5f495,a66b1b12,d7cd8714,8428efab,d2bd23c3,2de8da3b,cb630ee7,ebe84541,ec3eff60,645ec4fa,3978a6) -,S(4844a10e,ffce265b,1a5338e6,a10c4f18,b95b0681,bd702e30,9a376e23,7fcefa22,9018e1d0,34bf225,b4826e42,565a76d9,43c868c3,168d74b9,33b34596,98b5192b) -,S(9567ea6e,231a9c9c,3ea5bd83,59b7340c,dff96e3f,d1fa7a5b,c56c88a1,a57d951c,507e21e0,cc59bab1,f2c38cb3,42b9f83b,f291992,a0c83edb,4cb62b49,6c54759b) -,S(60f2f714,71258f56,6de74774,eda196e,46a30d66,3dc0b308,1cbad662,72f07bcc,12588be3,f62dd2c8,1e485efc,76c754d2,de642f53,d3937c68,f058c61b,ed7b6c22) -,S(4276ad32,b33ba53,ef2ab0af,9fc42af6,6c7bb23d,c7b7a9df,9c00e1dd,f76b6283,9c477729,c61fccfc,a2dc0c3,c3a9ac89,b98f437f,bb221be1,268a6f17,5d0dcd9b) -,S(fa3ec157,f8186c36,3419d818,4473745b,fdd2d054,e0c16e1e,fccd514e,95c9336,a7864a68,91aec12c,fe8104a0,eb3cbec4,4a907380,11a3acbb,d5fb6680,289cfa2a) -,S(7d7d2728,b1db5fdc,38ad6a75,3f39df22,88d50838,b106475e,28ba6eb7,5248b600,25d9d454,8b505739,16ec7bcc,877f6aef,e2641eee,8f78f1b1,a7f74c11,40173e1c) -,S(8cb9cc7e,4ec87013,b6994670,aae06b1a,a4785c06,614ca24d,cb6534,6592ffb9,728c4a8b,36bf36b2,a0bedad9,144c3261,71df8448,e87d151b,d8bee067,769113c1) -,S(8a9aadfc,84aa81d4,46442635,d47a9a4e,988e64de,6fe8836,79b8de44,f57c0169,60f39bce,be18abd,10afefa0,2d076d49,73d9615,10017a1f,469eab8a,c15eab60) -,S(3ea01e46,3a9bfcfa,39125216,7b6ce771,5fb309e4,37d495b7,852be3c1,af2a0b5f,2b756a06,75da2633,b8d2650a,a2102738,d5918420,9c57dd64,7b4c6c2c,c5250252) -,S(a0683395,c5245bdc,24b2b275,e8c2a196,5068fda,253343f7,49ab56e8,93672c4c,7f25a7ca,92d25547,975ddfab,fe50c247,6b4855cb,8f9ec4b8,ecbe9271,779431ea) -,S(b8293e68,1e33b654,7d2902ce,3addaeed,2fcc021a,cf7ee396,9be12661,b2abfb5e,7943e6b6,fd0c90fa,824b1e8d,25d63a1b,c01f16fd,3c9e2254,e1dc35fe,416a5afb) -,S(412722e8,ba1809cf,2df25d5a,49c7648d,b19e42c7,3cc30b7e,1107ee4b,f0aabaa1,557a299c,38ef6a75,61d79a10,ea052a52,818ce67e,1b341c1a,d70b984e,8e41fa39) -,S(7a62c6fa,f4a1f6fe,4a45aa48,a854a16d,a2fb19a1,a5647e3e,28a35d0f,619b2844,dab31641,6241ad42,3e7ee774,acb52a96,26b4b6ca,a4ea0b4a,67a513fd,9637dfd4) -,S(c3915b0c,19df99,ac0ef05,3a07b36d,62643630,201073b2,8e3ec588,6714a695,8f21f136,3cb4ff42,a52f74b4,b10f1dc3,5bcd782d,b477ecf6,38866d79,541de3bf) -,S(2a373fd3,ddd12547,3e30efe2,5533316f,355dd52a,6854d7f4,8144d19b,648f4b59,2ba90aa0,b3de3887,c1ba231f,49b28294,677adcb3,2e81c2f0,3c563e0d,221260a3) -,S(d8729e12,46cc8a52,a5c9b7ee,dcdf4d3b,3d0ff8aa,6efafdc5,ddf37480,2dda4476,1966d7a8,7e527a7a,bc1e829f,90e4e3e8,f4a7df30,48f098c0,df8a5eb0,2a8bc40) -,S(ce45fb7d,2ccb83af,dd1662e0,3ffec83b,5173dd2e,448eaa87,edc980f9,10a20dfa,5973238,531c5a84,1388c656,3d4f3579,41283e31,44d84ea3,31374d8d,e2122244) -,S(230a69,f0fff585,a1163702,4b16481f,65bf27a5,3ad7992d,47ec8ff5,edfe073e,61ae3fbd,90f157ba,6332de25,a571777c,30d8144b,e12d9a25,42bc1877,1b6abedd) -,S(d7f91496,1bdd4fe4,7b538429,df2bee94,cc4d66d9,270da392,a85e8c62,1527700b,67ee9184,bb2cb2b,9671aaec,57634814,b6a1a9f5,dd0430e6,6c5e2774,5afa9f13) -,S(4f2e459b,3eac7349,41cb81d9,2d8b3942,ee7b0ded,b2d9d8c1,90ff390c,aff7e4c3,4188f6be,c3526afa,2b29f953,f5044bf3,8e583c27,395c9f8c,979ff539,b4198e17) -,S(8a4a7b6c,3b598e42,851b0913,209a95fd,edf0f8be,6f152b33,1dac61a2,6f9b6997,53c457a9,f8926415,63e85b0c,b39ac9ee,69b31c65,5e3bc200,d37d86ae,d4291997) -,S(a48f69c2,9dbbc922,78a5f8b4,4a2fa2be,f432a4d1,e6fcfda3,8ad60dbe,6d157990,f251873,152f4ec8,fe5fc88b,cdf28ae,acef895b,1d0f0ce4,44105e14,7ac0ff22) -,S(fc0ec54e,20f7e8b1,fed5cc89,d18a5004,b7aa55ba,7520dc18,c9cbd935,7c78eb4c,17374d8d,36116ef6,49b723af,62a48350,4bd47bd4,c17c7990,fb0e119b,47f21ba8) -,S(8203924d,9fc7e5d7,6e3c593,ad439d3f,8512c0fe,5c298163,c8caaa3d,f7b39755,a224b743,258a82ac,2dec871a,dca1dafc,2bfa8e33,b2217785,2b97e57,2e1344f7) -,S(c4f66a17,a595217d,58d5b5b5,da997a7c,79b870c0,f5fa9dde,e146fa5d,c21f9380,13bc8ef7,ce6f915e,fd7a3522,f5fb9c3b,ac603d0e,343d344c,74565eb9,e8e3c777) -,S(4341f0a1,efdd7d68,435f1998,559e43b7,7d1c6780,d3d3e7e6,212efd96,5b30cb47,1777a450,1a693970,c2bf759b,a253e716,b17cd5eb,9a247d47,cc382424,48ae90a1) -,S(865d8a50,ad3b8c21,f8ff0e92,8e853789,a607abe6,e155b04b,3b81d80,c97c29d4,2a506b83,c4166a1e,fdc32c2f,b2d027e4,837d9989,a82d08ee,a31a46c9,dc72b272) -,S(d8d95cfa,ac50b79f,3189093d,50b03b38,3b798532,3f01ba52,d76f033c,83c832e2,cddf6560,d9942228,5a3c0f18,58a7c27d,fd7b8bac,9b23477d,8677a1a3,c01a8454) -,S(d09fa59,8ae65883,60247b05,519aef86,2b1c5196,d38aed11,e8350fe0,5bfd6cd0,45f51a97,67445680,37b1bde9,86696834,6dfaca49,719c5174,a9f9eea2,92ed4ab8) -,S(e19796c9,c9b48a5e,59556b72,9d9b8073,71cd7267,812b044d,637aae50,d6d3d1d3,1b86acc0,d904a31a,b5637e18,872eb31d,32617930,2f3d6bb9,36016653,9f218d89) -,S(6a88899f,be0c3c82,96fd27f8,6f89283a,f83df13c,a273217c,fef69d8,b048afb8,68ba38cc,bee044a7,a026ada9,d51e8d49,97083dfd,f65bd483,a45eb58d,5cc774b0) -,S(e5082ab6,a112848f,9f5f3362,8be3e267,87e24cbc,6d5563c0,7addeed7,ee44662,c3c1727c,d0c09130,8323326d,210a68d3,68bcbf81,bb3814f,dcfe6631,d42968da) -,S(795f456f,5d0cc15c,72ea286c,c881d8a0,21294e05,cf80ef7f,4497caea,92235487,bea99154,424f54d1,e91322cc,c52d3a51,4627fb1b,2fe9062d,91d90177,20530ccd) -,S(6e9e5f96,8c233f4d,8d2bcb8f,25d9232b,f2230e9e,fbafc89c,dca17498,8d7909ba,3f8b0b0f,e60aaf3a,89f5de79,35f9979a,ac3f3fc6,fb161d3f,29ab2ad5,d50411e2) -,S(72ef1e88,89cb7f22,19b4a7ac,92d5678e,a04c898c,5b83128a,1f7fa8a1,63772f28,dffb88e5,3f348c29,411e4d47,3ccd7d41,8a0617a2,6a640a9c,4b03aa08,15ab10d3) -,S(4a91fcd4,32f6d2e7,ad20787d,749524b2,e3e1c348,31b41041,c311421c,1aff04f1,bcd9108e,6e8c6da6,a15156c5,5c9d60be,e4aecad3,b0756cd5,81b1eaf0,ad300b9f) -,S(5f5255d9,8c7465d6,63fb4507,ac985629,8a434d5d,429d5a9,7b645256,e2cebab2,7c38536c,31e7331a,362fc944,38510aed,bad4cf29,bf0e7cab,c995ac6c,1fec04ec) -,S(866b5f8d,a735ab93,e84f7811,a33f1604,40a51373,7b52e675,7f212c8d,65c9eb05,af2cfb6f,9e32f412,5f1c66ac,61393756,b8c6016f,9d45a58b,43e16c6,d3549be5) -,S(636aca,387e767f,4702fb3a,d7b50b4c,4b40fb78,2c8c44b3,a298051d,bb3a71f1,70e580b,6993c9ac,5a48c2f7,558773c1,f5c4ff3f,aa929635,a2a44e97,c0eacae9) -,S(31a28d8c,2205f5c5,75ddd861,df94bfa,5b6b6e38,83797d1c,7d4a487,5fcf7f7,a790eae6,788407dc,89df860a,9ac25011,8b8c65f5,f47e0bae,6aae95ee,2d733698) -,S(c7f36e08,bcea178f,7acb0b92,fdb32411,a028ce88,be5e3480,a47c2c88,891827c8,5c285010,4742764e,7df86e80,e6e2d975,472abeb1,bd5664d3,a994289c,112a9e9d) -,S(85a82c69,2a5e248f,42a3f0d3,e092840c,de52e31f,19a2a161,85b2ad10,6afd92d3,eeec281e,55c79f17,332c4ce0,7ac4edc4,a3d75e67,558b4b3e,4dc86532,6132155c) -,S(e67482d2,4c2e3a75,3c1fa968,bf120a4b,7883d00,950bb0bd,ef5472e0,dfb09287,f9801b51,e0450fcb,9e405ebf,cb535355,24db5e9,91bf1572,6f446aad,34ae4194) -,S(c6ba17e7,81fad656,c9c93e54,36409414,c58e2761,b0297b8e,1811dd68,62779f1a,92583a9c,515a096e,8691b384,4104419d,c4e86966,4da70b3,afcfceb4,b9d74c92) -,S(67cf02c5,a616b59a,ddd421dd,15812e95,f36e6d16,af501663,9e60dd4,a8706b24,7856ad72,8a5f0d18,bf4bc3d3,75468f85,7bbdb1c1,206fcbc4,7ae66b5,6ac91b29) -,S(72bb64a0,aa8c690e,7bb6ed99,847488b9,f37490cb,a7fa120e,a7b5df10,8fce4b61,6057c37e,198f6428,3b9481f0,53441e97,dc827cde,edc55410,5108fdba,a14d81bb) -,S(1b132067,209e179a,5b77977b,eb81aea1,c480b32d,81729c5,32d100df,310575cb,67482a94,b5ddae4f,cfd613eb,68680dd6,c8172553,18478bf,79b5c07a,b0cd817b) -,S(96f5f126,4b68fd7e,f633330e,f32951c0,3716b62,7d1f3368,703447,f9dbb5a0,941fa02f,c6262bcf,dccb1cdd,1637c9cf,719077c8,1b26e7e7,2bb8fe4a,4d530e19) -,S(95335907,9c15cfa4,a674ce65,113127f7,a1ce740a,ecceef55,da5ceed8,e4e56a51,57ee067a,5f506b14,5c1c20ad,6e5d6b11,9bca103a,60c2e6e3,b5049b4d,db15baa) -,S(72ca7d41,76c687b2,1125c290,e737075a,3281ce7d,76b72725,c7680956,e0463f23,1e6a85aa,246b0f1b,324365fd,19809840,242fef0e,6d658cae,cc84bbc3,ad56af44) -,S(d5376a10,2cf819b3,a439feec,b04d9fa3,c90d76c3,b9bb749f,bcd6aa26,39ed5ea,3659d2df,266a0ff9,c2854f6e,f5a5ab04,1c0d8547,77fd4f75,320e064c,c4d0a4da) -,S(664a26cf,a965b59d,10c05dd6,e0aa4e6b,c66f356f,bb61b699,113a83d9,e0a2b4ff,fd191a92,c88d577e,47e725eb,a3c38b3b,9074bc42,16c5d6b,4edb3af7,2c4e20f9) -,S(7729abf,ecf9ca40,e8867936,7fef2d84,29bd877a,56f36780,1e677273,8e8cba7e,d5cb7517,42c9de11,84dcbfb7,5c9e139b,a59b6255,b59c7ef8,539de55e,7a709d36) -,S(c6d5f50f,e8e784db,630bc589,b4df5810,a2001482,9ca1608a,cd3e3634,7bd8141,eedd06e7,95d063ef,3d1627f0,bc7ef37d,a4846580,61e472b8,89679d3c,d88ab294) -,S(baa60dda,3cf83a11,82dc2ef4,f79d362e,6b32304f,896d30a5,b363c639,56ec70d9,cc9e6274,75feba44,b93451d2,753e94a2,85315277,7674b3fb,c67490e5,3627043b) -,S(370243c0,92b957c4,74df755f,e0951321,49dd3669,1a89fa84,e43a0668,8ca235ff,bbe8ff04,6600f245,349fbf3b,1c8ff04d,8d51185,3e35d13b,30deba91,84383ba2) -,S(1182291,92b1e768,2abe56b1,9f90e41a,c882edb2,27b25559,ce4448cb,dd19ff06,24271274,e6156ea9,e3f82ba2,8a72d476,8509dfad,b985c200,244687d5,8a11c1be) -,S(dd134e0,e4fe672,38716aa4,edba1ad7,6879be6,8b5bb029,b32704b7,9edfb2b6,7aed5398,40cd7dd4,7e94c224,151627a5,62f6a519,2f0d0b5c,416e6f1e,5e8a337f) -,S(ab7e722f,458d3acb,ad28a29,2f90cd8f,c2e09b2a,2beff3f8,f08517dc,e673e3a3,522a2227,c724f9bf,1ae08d93,c4c6ffc2,f5434173,7fbfa502,d6e49b1c,2ec4c792) -,S(2fa16842,ebebd6fa,e6c67327,bd5fdcdc,7e985b1c,22dfe307,23a9e2dc,ec43df8d,f027937c,9624aaf1,ccbf7c58,66bdd9d4,5bbb279,c2a37813,9166b720,32030773) -,S(adf5e014,e1f18c38,fd1863cf,76a6dcfe,65827107,fbe0eb99,117a859b,c5268bc5,c9cb3584,728b1771,16985b28,f5259aa5,279e15a8,1c1cc6b9,2b9e5f8a,6206961d) -,S(d939322b,a9b2cff2,6a2b1c4b,5ffcd96d,822dde66,ad0aca31,c24a8260,c9fc6d26,162fb654,6118a68d,7fb88bdb,3e3ab784,9278a5eb,13a940e3,3228580a,2258c8f5) -,S(18fb2621,71f79e5f,46c0087c,ac8e55d9,66f29a49,e2c91363,58900787,3d7e3a6d,cac82dd2,4a0f75ee,adfe906e,ccafd36c,5b0c97d9,cb150fcf,d08b28cb,83787a05) -,S(b8c0ac07,5d009e4b,5ee44298,89864cf6,fd54092,df835ec2,6658c902,57b670d3,2dbc6d4b,6ff28cc1,14e1f34d,2b6cbe52,7ca7dead,24f84681,4407c4e,a0df0bdb) -,S(6477536e,43a3ba01,8988c8ba,753d732f,9ec061a3,49f7826e,2c426ae5,3f2232bc,ede465d7,6b7798de,832e5f68,512cf3c4,d17282a5,ef88725b,36d8af1,5c5d2679) -,S(55b052a6,52008a83,41135e55,ef7de2b1,33eca8b9,ea0c4800,ce4f8019,5f7067db,a823cc05,63efbc19,d47c2c92,5771497a,ef6377a3,8be0d23c,81a56f06,25c43e56) -,S(c86a02fd,becc3647,16c58f5d,f3f150da,6ba86499,2df09dd5,82b9653f,10cc9289,263d1b5e,eff52a27,1a9c46ee,8adf1194,1da9d3bf,e69f62b7,262099af,43d6fe3a) -,S(23c659e0,3a59381b,3d47beea,60f0244f,66af0596,5f903297,c53aeeaa,d143e90a,1c14650e,3aa16bd5,b67e6077,be307cac,2bd2cd39,b246d6f7,216d73dd,dacbaf64) -,S(2f6d8482,734aff4e,21094c39,2c5fe833,1c8f9756,4de252c2,f6f690ad,8b2fa9d,8b143db3,7e14b40,3fa98a74,a81adc79,c34f17ce,5c9e6f21,68770957,1eb639ae) -,S(6d58e265,d6b08c0b,b050ee18,5175a9ed,51b5c64f,d523ab35,ed1457d2,f9caf153,d0675517,eb71ed0c,4fbb86c6,a2b4a7df,259a7795,3293777f,3a87f620,2265edee) -,S(4af09f2f,69d7b9,6676f472,d7f2009b,f0bb6f0,986f502f,322afacb,7e9d570f,1f93342b,ddfe5896,52e8b64f,a348f333,5396012d,3e870885,5b31024,f14f8e7f) -,S(813e446f,87d923ab,ad8b8649,71b1ca39,d00217f8,232a71cc,d6346798,3a9a0e9b,8ce9f4b3,541a8029,f1476728,2bedf1f4,367ff257,60f2ccce,7b273b2c,dccff418) -,S(53c4fd57,ca0b1eb8,7f5ca0f2,3ecae8eb,c44e9c19,aee3477a,3ca8524e,dcdefaf7,b3db3613,aa916430,a3227d73,35bd0532,74c122b8,18e4ac52,858e513f,c3ab95a4) -,S(e0f8afc2,ec89411,d926355,2c33af71,328331dc,9c9452fe,b0665c39,ae90121f,13523c16,1a00784b,f15d2867,15cc05ec,227248ff,80082e73,ecb139e8,f229eb4e) -,S(fe3efcee,6b82a5b5,a8c9a51d,ccc11f01,ef8f1a7e,588ec4b,17ba1369,cc6bb80b,be17246a,4d8660ca,98d57f07,ddbabc29,650f9a89,9da60a53,d21c6c96,dfdee15e) -,S(8a5182ea,591089a5,11ba9f19,ce4fe062,31b7e2ce,ec4cf75e,5c11094b,9ddc8de5,73688cc,f13d97eb,19a86c2d,8b010406,1c69ca94,fc9ec90d,8ada10ae,37503600) -,S(2d95aecf,72501ef8,e20bc117,22dbcc09,38c552f8,f4e0596c,9974d62b,a99fc884,7d9c418e,e1745ac9,e8f5e4c3,9ada4400,e65acb22,d336bcc9,fa2cdbe9,97f7de88) -,S(7908e4f6,ede4d311,3dfaf114,9bf6e40f,e1f8e33d,72094448,5105a113,21d18b80,11d92d74,9b011e83,5e06d7e6,1103cbe,bf958d8d,bd47d0b0,1ac2ad22,2f7d275) -,S(2c6dc24a,687d8437,44baf725,c75e7524,c0e6571,f32817f4,40183b6e,cbaa9f95,9692bdaa,775b832b,48584ccf,713421e7,5074f1b7,ed5477f1,4335db2,7abf03bc) -,S(a019d9a0,4a9780c9,43dd65fb,b87534cb,ab7c0831,f845e724,d663578,ec7bc090,38de35e6,faa2a1ae,e0649333,898a6ca9,264dcdd5,ad9f289d,ef750110,9bc99d4d) -,S(ced934dd,5c15335d,d050af1d,a8295d2e,bd9b8272,58d689ac,f4a48d85,5ef8a0d9,bc0c9237,1ee7fe7b,69c7c100,e5258c9f,1d68b6dc,309736e4,e05718dc,3a49cb6b) -,S(65e5ffe6,502ea7a1,47fe9c98,9cc745a3,b5262bd3,888069c3,92d1d1f0,a08dbb83,c80ee080,84dc5e65,de8df271,c1132cab,b8be293b,69a390a6,fb3932e8,51ffaf38) -,S(f4466d47,2365b665,6d1947b0,6e67e393,4c0e4f3b,91d52ea6,1f4588f2,4d217655,17afe3f7,2d384ccd,9beb59c3,d64353ba,57713f03,b8644e3c,eef45db,c74ae84e) -,S(66a80bd8,ec0d08ef,3d9aca5b,4329198c,b949ce84,7933ef2a,10baac28,dc98cea,7457685c,600a707d,5fd5d527,9f309b9d,5b14e668,1656869d,b041ba77,97029537) -,S(240e3632,7c3f4c63,afdb84d0,8586bf90,9b359c8d,7012f9ff,aec81986,4c44d597,a701b76c,d369e013,7b627216,f75d0ec9,fa208b66,2d7075bb,a6b6d39c,6a1cbb30) -,S(137f0df8,cafdb26d,36e1b57,c427ce08,444516da,ad1ca806,9dd60e2f,2ee23f92,c2922219,9e4e7bf2,f9159138,13e68273,6bb6a998,6c015caa,43cd30a5,aec74a49) -,S(965fef87,a63bedda,fd4b2e35,e1d0baf9,17d5850b,1f6beca4,64d4fae1,997d3a41,5f19603,369108a5,c599ce56,22bbf02b,cf541867,a57cff2d,8b527148,30124ed3) -,S(1e2ca98e,519c60e6,cf7ff3c9,51cde109,209188e0,6c68f4dc,c22eacf1,34a4125e,edaf4c8d,8bb97032,89f9fb0d,d0023783,fd35e779,41773a00,fb4289cd,ef8411bb) -,S(e8e0e2f0,378595db,68f96e6a,882752bf,df039778,e261375a,47fd4394,2b68006d,75b42822,1e2fbf9c,42772d35,e4bf1e0e,8d3b1ad7,92ff25ca,a488b51d,4ef7186f) -,S(a405f5b0,28e89d81,79e7fa9c,2ebac86c,ffd20ade,60dc5226,cfe6c91e,5c2f6634,c27ea4e3,b0da9e58,665f507,84225107,7893d6cf,5225d5d8,a06f68d1,1d863550) -,S(bcbc3c77,7367168e,169f3fcf,dd2340cf,9e6af955,d6038a0c,b763f036,6f4564cd,c7c120cf,99138201,40ec5339,ec23f5c,1ac0dd73,c9f947dc,e19c034f,7e7a502d) -,S(fd569bd5,14843a2d,e86ab2c0,475e0c67,4959c04f,bc230255,db3e82d1,15cb0758,aea9c73b,bc083366,fc5e31fc,90a1da72,66a9c43a,9d16f6ee,67bd56b7,9c354cc9) -,S(c2fdf561,eca2e3b8,f1107475,9cc43b9a,789ef592,e8afe885,d88b9dba,469c616b,678f57fa,fb2e42fb,bd1482d1,e22c866e,683e4fa7,6c1d2714,6540610d,9cbd1360) -,S(50f20965,510b3317,2836e1e2,d6e00ea6,160a9c71,2aa30bbf,ac527c62,9d8f4088,fd9852c6,974c603,7e88bf45,a279b565,d1246924,e3c4a0f4,8877b716,69b68141) -,S(3f293417,1e371e20,cbe0a858,e5984175,ba465906,fd64a7e6,161c8a7e,5847764c,763e8dbe,571ac3dc,1e803f32,7e2f4585,7268774f,1a45c50,9390dfd4,96bd374b) -,S(8276d399,fe32e931,65f2ef6a,2f4198e7,944bb9a3,226b1a55,fff52dce,d2b92b3d,e955a591,5c496a1,623466be,88c45a3,f545527b,4edd4283,582c03f7,2a2d897b) -,S(e77e7701,f4b405c3,5c8b7a6e,ee7d0637,fa1f566f,d2a2cb64,531dbcc6,19a9e474,23fae4c0,7661e588,365ddde2,63b97f2,cca2023b,c70633a1,41a2eb,1d3799cb) -,S(7ae8112a,732d6428,25aa2eef,10298300,42939628,69e7eea9,3fbc7b3d,2c5210a2,3590e349,f878af6,7f7754f9,abf4ffdc,4d4f4442,48c1e039,6071271f,be5971ce) -,S(f9fe96f6,8e20a422,5b563483,c1d2389a,ebd8a97,b1b9accb,ed7bc51,8077771e,cf3802de,20b5ae42,b1d1db65,b033f2e3,602ca08d,972eed63,9234e1c1,48542478) -,S(b9c5eb6d,ab28292e,49a76b34,49cf903c,dfe79b85,f7797623,924a4295,bf0cd171,adc0a5d8,18926d8d,7bdc83fc,72b2ed11,19b87592,900ae961,ffbb165c,4d5bced1) -,S(b7e25a76,3f3b8bd6,1c57da51,bd90ab57,1df3fcab,28003104,30c44fa5,4a6a5765,c471aa74,babc3fb7,dc80138c,83940e42,961f80a3,23e9741c,c44607a8,258141d) -,S(5808e4f3,e01937f0,e9c887ff,8ea3a34f,8fca4d8d,7868a9d5,7de6d854,a0582d71,fee8cfef,2d78896,55dc9560,68e1a23a,4308a8f7,7962c2e4,f90b2ddc,87f011bd) -,S(92ac7dd9,8da0a4e6,60964943,3887974c,5ec4b32f,875c02ba,1163d06c,b424793b,857b2046,8104a986,a0030596,62039e60,71c8f950,b7f7f746,16fcacbf,b8eee5fa) -,S(5c38092f,fba5798d,48d0068d,d1037563,1f40a693,194584fb,7199c409,b85d52b2,32b1d628,15ee2555,f582f16d,d59c4658,67691e1b,389d1fe3,222b5444,294ab391) -,S(ad7beb62,cec8aa9a,b619693,eb40c477,53e22897,a0007693,f10ce664,21d5c15e,49f98176,a360297,42402a93,26e34a38,cc837278,3873b076,f887c811,e2bd98db) -,S(aa335f87,c61f2e9,7d87355e,2a1c2e51,f2a0ac92,1cfd3cb7,5189f256,386ef185,b39741b2,fc158d6a,435bfa8e,1a68eedf,13deab27,388032fa,fa22d649,c9c9a8a0) -,S(854ef509,24fa2fb4,9b7b7b49,44ad8c9d,87627883,60ce8bd9,36e64f12,a550356d,c5af2246,96c7e32c,a385f7e,3eb8326b,7d9e3537,43a95c8f,3010a160,1d6f534b) -,S(71b6366e,42a8e2c5,31ad6770,ff01481f,5a39c54a,d38e0ac6,f068117d,8d5c9d5c,d6684df5,92f085cd,aee8313,59bbceb0,1a357edf,b36f8e14,706245ef,f01db334) -,S(3a4d1869,55b698d0,5e760d75,8842bd1f,cd869e84,c2c29e44,4ca83bd0,3408d6b4,5ddd1b14,15ff793a,80fc196a,83ff2736,e9791418,fba7eb98,71b51269,170d9904) -,S(f596d242,7e51e5ce,403d673,cbdd71b,75550271,dd2d7d93,79883258,9d3c5739,cb9ef0ea,f6326a5f,83e40428,79675f81,188763b1,ec06fa26,3d7793cb,82b4ceb0) -,S(4bb25028,b5598090,15286b2a,a8858e52,227f3b11,9075077b,3083fe16,77efd4ef,cb63c7c6,9de6503a,d33ee35f,95d4533e,1e978f30,2762b478,e88d18aa,5c4ff098) -,S(77c7c018,4c89f974,df648e0d,ea57ee40,73acd63f,c6e22a55,6269ca4e,a5dc1c99,978faba,232a2b0a,9cf3de55,976ca950,ce3f197e,e774b2e0,d4bd1e5f,e65a1b41) -,S(834d038,926b1ff6,13dc9001,7d021bf4,5bae5,d3741460,db681332,61975c30,f5624b83,614f5e82,10190b34,9f966fde,cd4eeefb,e3e6b046,b3028d6c,3807b475) -,S(370045a0,a7f8a64c,a2b9c64e,85a07fe8,9a7f725b,2cdec8db,258b3d3a,d9cf379e,cbec192c,cfc58b62,6b89d6d3,9b4bf622,81e308b2,2aa3ddf,51d45561,37b1811c) -,S(61302164,6103ee82,1c3103d5,f4d2aba4,645816cf,a67d94d8,ca53dcc2,92ca36d2,935e3db4,5ee1789d,ed8f0ded,ac0430e2,7317f38a,87682850,9568feb8,15e20a1d) -,S(4d6868cd,4df5b1eb,8d27e045,ef04209b,c1dd0bd7,aa712937,8f7bc025,e569d90f,dc0079be,850ab0ab,ef9881ac,740140c6,958e12ad,edfcbd79,2f446d78,7157780a) -,S(43413ee9,a35c7c44,bc95369d,38d9e7ed,53175f17,6f9eb54,6df98540,93105549,9eaef64f,45b421d1,ee80731f,ed61f658,861feb4c,72b5b2b0,ec659825,63172f7b) -,S(1e728340,95183b28,a443e00d,6ae01921,75844d9b,ffb1c77f,c00d388a,80a6b76,d1931ac7,fccf26d3,a2ef72ec,e8c7ecef,c51ad264,ecca5748,7e9cfe5e,d798428c) -,S(7b5995f0,fb0b8246,c588e393,4499404,415f0d03,c9174317,6cb2f4ae,b06960c0,716c7849,b6963a9,f1a7998f,49cfac4c,42a329f8,77d7c8fe,5b35f958,ceb9c0eb) -,S(9c5efff9,2be6057,f5223d41,87fbafd1,a59c364b,239120a2,fa1c4596,4fdad960,4f4aa66e,e42548c9,4d6cafa0,81e59ce7,ab65cbd,78027de6,b1edaa,25e6d7dd) -,S(46970472,192c3690,3c7bd061,dee19fee,5f3a973b,a70430f3,581abae1,3a61e55d,4d232a77,62e04a36,c62894d3,41665ff9,ad8ba55d,353d52cf,44f392cf,7787922b) -,S(add62a3e,583dce2c,55e97257,b64c26bf,5e86b0db,92962b3f,a54e7c52,ac00b32e,3c700f82,c5365611,f3cb1ca9,cb6b0c2a,dda80e04,617142ef,eccfabee,178d3dae) -,S(526115b5,34b212fd,9836a98f,853ab3c1,24bb68bf,afc1d641,b47d08d7,39566c4f,29c983e6,2a4de19,4efa5b2a,9cd4971d,6a86c8e9,f535d599,ee04db95,120fdf4b) -,S(87908ac3,ee8f4e5f,31aa08c0,ac97e93b,81ac75fe,33bfbff0,7d4f0934,7c911f45,b756def7,52c71c51,3f69235e,8d515d6b,f3289a5,a579b999,a695a2f6,49586ba8) -,S(2d6e6ed5,d2ea8912,6797b396,8ac1b0e,f876904b,acbace80,a2613b35,d9bbdd11,b1b66613,50ee7a2b,d149ec9b,25a502a1,6ba6143d,32da00f3,13cc389a,7c0e480b) -,S(f076c9e9,8590180d,dfd36cd6,160c21fb,7dc60263,77435e74,30f74cc3,c46533f9,2c9decd8,6da7b49b,1b4d0a8f,47aaaf9d,19d9e8bb,365c383b,63726f64,ae56fb98) -,S(fb52489b,6d101de1,2f51720a,60a78207,84ab4dd8,39d05c9d,a3b9c349,a74452d6,f1a967ae,deb5329e,faac7381,f3f0bc76,9eb8cc89,78d5d56e,f382a17d,4c3baf4b) -,S(dc1e911,53b3435a,8f23cb08,a7b52f64,a5e2870c,9345896d,ab4ab880,9710241c,3468d632,eb3a51fe,133381ce,2b5dc9a1,64f8eb68,9c019b0b,7e48d504,50e85630) -,S(2d8c6759,6c7856d,b7062c63,2aaffbee,46779bdc,777f0be2,a64093d,41d4000,c7006eca,b64904f2,9cd7baaa,14a5226a,e5c4b3fa,68c62cf,65789066,2eb8e8ca) -,S(31e9d361,fa0041fd,bb73665f,2e1541f6,c41764e7,78023272,478cd7f8,e9552f06,62fdf441,4effb45c,5408a0dc,c0a78041,cbe39cac,562659c,ab8c2b89,1a940c11) -,S(792f50cf,66aa0f00,68bd7fb,ee12bf44,e1fa6662,41c43d2f,275a248c,29459830,633cf86a,a3f10f31,40aaffe1,d04ee094,aad1cc56,129149c3,2702c33e,40d91e3f) -,S(be4f52ab,8f6ad1f0,664e4d28,b67be76b,c3d318f3,9f455708,94060e03,2f8547b3,22ffbfca,44482e40,19ef36d9,209b4262,48d62591,7d81b6a1,57ad945a,1878b4c1) -,S(bb693c4f,7110d2d3,8bdcd6af,d8b29b43,80d003a7,d0f6420b,e8d02cec,3e7cf385,3bdfb9c3,948034e9,31904f13,e3dcfa78,13d3413f,5c2daebc,744bac87,9e4314b2) -,S(56e8a65d,2eb188d4,64dd4280,b987b5f9,8b92b8e4,34b6bb1d,1800fc4a,f8f2deb5,11cd5d14,63777189,f8c7d19a,c692461b,d21fa20f,f12d1976,3b915fa4,33006cbc) -,S(f09d5cee,514e56e5,9566953d,f8600a94,cbad003e,9c898261,5bb998f6,a5b8cbb4,d07ee0a9,a0e88f5d,6da3d918,d5f309ca,7234373b,d528cd8c,21ee9ca5,3d1bafd0) -,S(58671c9f,687ab0a6,f6b7c687,ef546765,7f29ecd9,d6250088,d588742,7b96fa6c,70355403,abefa39a,72d89348,9a8251c2,10d59df,80b4d284,f3f02246,f3f6c60c) -,S(e47ec1f,8a7169d2,9c05cb96,42ba126c,aff841f8,c2edfcf,25ec9303,772eea78,ce97644c,ca60474,4c269973,fdfbf169,bf0fa377,61737dd3,77692b9b,ac775c9d) -,S(ed95cc7a,a24a4ed4,1dfb019e,31abc80d,93ca5c04,b0515f2c,492e9105,efdb12cc,1602bbfa,f17e8c16,30ab470f,bd8fd829,b4a466ca,9f210904,7e0903c4,e012d789) -,S(b6fa3ced,a07a9cf4,db717242,9de8069,216a7b51,4145470d,d811755d,a2908a2e,64f695ae,7f19c7d1,17af6ca9,36dcb2df,8715ff96,c8134313,c111da69,7a354dfe) -,S(2e3047cb,4d210007,39b8d5ce,e4884a5f,ae969eef,898a600c,2202da33,239b3627,197f37c0,7c11943e,40328e3a,3c7c11d8,f2d77d16,84532631,53b7cbd7,69808c9d) -,S(df9c446,7a691cae,b8a01ec1,a4a8ebc,fbbacfc,ca347aa5,39d56853,c14ecd3e,acf9554e,906e86ba,8459c108,d49f7aa1,e1e4b2ee,9957101a,f16d43f7,7dfaf6aa) -,S(d452f3bb,2e3e54c4,1f68267b,f846f504,99f39f28,5edb86cd,68330ed9,510aff54,52c5d16b,41eb1029,7f86a30,28d1b610,6f6c5aad,61b63bd3,53d95b2b,fd214755) -,S(cc196d06,9ad60096,c4ba1057,fa4fcd9c,4a50b28b,78227074,22d531b9,dd85a5be,bd930456,14388283,b28cb67,758c792e,5f9d6c0e,2d4c1a86,745e0504,ec902b24) -,S(4974252f,9c246a45,1187b1b6,546cbf27,af9c21cc,d03c7b37,df7a604b,a3b6859c,276e69e5,b85e3241,33f9ec76,d628fee8,3af37bd8,def6e677,bba19739,9da14305) -,S(311548d2,d9f880a7,17e77608,8574ff4c,185cb0f0,a9660ef6,7a94d090,3e2fd845,82b2dfdc,2d0ca2e1,d403c1db,7593dc01,2043122a,fb50961e,d5f86174,18a3d7b7) -,S(30068568,4497d5d3,2c98d3ee,1136a9af,d5bbc79e,340528cc,4e0b3c55,74e867f4,57c141af,fd650050,79ea563b,e9ebb161,a7725bb8,e41e3c13,ec528b2d,df23430f) -,S(1c223f58,1f03b4fc,68024db4,876b743d,8a2b635f,988340f0,d22c389c,43d130a1,9d99aaea,d3bd3b1a,9891dae7,4a3dd857,3a86b643,6c623c00,6604b211,4e27c133) -,S(a675c89a,5d453821,429109cf,45cac77a,880e0e6,396a0b4f,16053ff9,eabfe4c1,8cda99bf,c3426739,c4888767,113b7f4c,9b321a61,1b63b4d1,2dd50a79,d80b90f7) -,S(e990a236,d7854ca7,3e40c661,93dbf3ab,74198351,1236988b,cca29eef,772b32c3,a3d42c05,851b8138,ef1bbb7b,41510bb6,fc893baa,928c98ac,91127b3b,a100aa12) -,S(2a6eff8,af4b8049,2c3d31ed,f6672d1c,d0b231d7,6deeb590,a8d0c4c0,83586027,2a7427d6,951e07fc,4d5cd4f3,ca8a3415,8f0d03c2,3cd2f250,541c0f11,8013a623) -,S(7dad1061,9c4a7bd5,1edf6813,daa8fb4a,2a9e494f,9835db8a,42f4b0ca,827df50a,3e3b2b7b,a44500d0,277b792c,8a529fb3,41667560,1c4e443c,9c2fb2e0,dd17f1ee) -,S(39d5b162,fd48725,1bb42303,b7b8887b,92180fa,ddbdfb7b,a14ef2e0,3cc32aa0,3a8bafa4,5645e4e9,bf4e0175,69fad346,210e65ea,fa92b971,413a2190,b64b6f09) -,S(f9ac329c,ba09d60b,5aa62bed,81e9ca15,7a3bc53d,acd83836,89742ef3,cfcfd795,9c2fff50,aad80c18,2e6593ae,796ada7a,e0a42a4,17ce77bd,ea7be927,161be4ff) -,S(19adeabb,6e9aea9c,fe245329,623b8bcb,3554eff3,999b0b0b,8e035450,14cd964f,c570d99,99e9c62d,a3321f3f,a548d43b,99f05df3,e17273cc,2a45a3d9,20654cf8) -,S(978f705b,eb9b6009,22285468,521eddae,e71f6521,1ae79567,3b122090,fd4eb3c3,8eaa7bc6,1ae92adb,506f9e32,c66f5457,4e1d929b,ef4953cd,a1cd3f8d,c98ff8ef) -,S(e29b57d8,f6808d6b,ec982a12,ac70afca,1c9c19ff,a7b0c724,4fcc5b0e,3dc2fcf1,f7d60b14,133721c3,471fd91a,864e576d,84e5a06e,b031b1fb,3a2947b2,a33b159b) -,S(72073aee,f39510e2,81cca2d9,7831e533,56cc6016,9462a9f0,45100dae,3443bca8,bd761539,177458ee,dff87628,d155c9a2,d6a00e26,51158def,6ce72c35,84d56a3c) -,S(c949cbc9,48db844d,2cd04810,433f982a,680b6a95,e3461ff2,108492f9,247fefb3,162ca70c,c9f19d2,d3da47b,3b0a2361,f5c21492,a12828ae,9c0ff9c7,ef1d7b20) -,S(9acb7d8c,e958f7e5,189676c3,e7248ad7,9f717a67,2d4c80b5,9c425663,e078810d,112dc86f,1b241c26,30d87412,2faad000,473bce32,95bd6989,8b6a4521,7773284a) -,S(e468a13c,e5ad4c24,4df9aaa5,e13987f9,50900b4,a32ba33f,430935c2,1250e4bf,61e3e755,a91bb2a5,3fc2ac70,bb232b2,c1aa356,d494656c,5df93232,a866e400) -,S(26779f67,75d8caf1,46638c17,71e33b02,b41c61df,325acbd4,506199c1,bea8310,e9de26b5,c076eb9,cf3436dd,d9bc7f8e,5772720a,a8401227,7af573eb,65a769) -,S(8c408da9,a816c7ba,ae2846ed,bd923211,926e5e5c,ad595a5f,f2dbb190,f48857a9,89373ca7,e9f3f96c,1f0bc7ee,d427dea,99808bd3,b943964e,f0db4bc4,a7a1256b) -,S(9ccbac95,d80bafbc,b7e699c,aaccea8d,3169db5e,328e1519,825a3f4b,adee6a19,5a8d6936,a2859d57,6accb35a,5e80c944,4d71612e,76cd755e,aa3465b0,dcad8aee) -,S(34c7b7ed,6fe88bc9,803567ae,71ea7c28,c9511f60,e2ebfa8,fffeba31,dbbce2d7,31a3bfbd,c42cffa6,c77aa417,955c671a,426497e6,b35efaee,83a58bf,84de02c8) -,S(7940ca7f,c3bc810b,5679456b,88a73cae,4b2abed8,47260052,ffcb33de,edef6155,8923cf73,9285b368,d32d690c,488d8b38,5d3285aa,c399fdf,6e263daf,4e0b35c5) -,S(2cb10da7,104ff7d8,d8f1742,43425c2c,5e8773ed,71e62e4d,cc0c2d4a,56ac3a08,610cb16f,53ddfd28,7a7ff301,a8047555,801c13b4,81033c94,4e145b1f,98458520) -,S(ced78e5e,58e2893c,3910bd9d,d43fc362,ce06dcea,f44c5aec,ca17eb0e,cdc1fc53,c66050cb,835c97cb,c08ae0df,242895c8,f0f0085d,85a020b5,122e041f,8fb09607) -,S(5e83a4f7,7c4cc672,a7a381f3,e527c8fb,331e8d75,f8578a85,39ae1007,51903f24,545cda31,25c29fca,b343c22f,824c86e8,89f2cd3c,d2a6f3b8,9e3308fa,2968b8fb) -,S(c62958f8,33217811,cb099492,fb8c13a4,5b3d04b8,12a0c1f1,68cac595,e7efcfa0,e179e98,1b92f1be,25c9f892,d6a71ef4,62f3e1c5,43127fe1,f2b711f1,bf61aba2) -,S(7eba00b2,f151282b,83c7fa9b,5df6d9a7,b764e7f,42ca29a9,2734859f,a2f0f016,9e3162bf,a619123e,8e87728d,da825814,4b760c2a,3d05fc2f,1fc25565,1d72a7cb) -,S(8f68c1f4,83ce557b,98d96444,4a2a7d2c,a05d8f25,e6f9f909,cb44b58d,a030cd90,30f15dc2,17e7ce70,a6fae901,70930130,8f7d8706,80c43840,765ee89a,5f864e00) -,S(393d5b72,a9bbc392,4f712195,51ba7f65,4bc4df18,cf93dcaa,bace126f,c4262b5b,976cf232,fe59a3eb,c6514242,19128395,2945cfb,f792e4c8,19248346,37f16e9c) -,S(e1648650,d0d4ca1e,8fac2522,cda2a042,bc93b879,2d6f870,29c6d888,a11312ca,4d919105,9ea261fd,9470ffb9,e60c703,6d21da3a,ce975880,39e1a820,c636f269) -,S(efc7519f,4676989a,a12d823e,8e49b1de,96397ca2,11fe729c,cf0fd67b,bc6d6a74,3f304e50,be6dc6f1,b7c79979,4ae38ff,ed11a253,778d0294,13a98547,e3b889d5) -,S(85726e3e,aa8f7016,1c3629c2,84b7a7ef,79259de0,84f8bbf6,9358f66d,a439133f,756800a8,11a472ec,a72604e4,c2eea080,94971b58,3738e7eb,2c817250,2595e47f) -,S(2e238f2f,de3c39e1,19119541,9eccde3e,b0c4fee3,e432fcf3,f58c4f77,4ba070b1,7ce6b671,c0c79a82,2fdcb88a,a10a8033,bcd0e1a9,2cfab941,d052c09e,4e5e4c81) -,S(9cdc6aac,41e79b7b,ae77a7b9,bc027e99,1d4f8c1c,2b4913a3,1eaaf1a0,9bd87f24,9d666c3c,3503b9ab,d609b074,743f8a3f,460c0122,ad7a0cc5,a22a6d17,9d948ba1) -,S(360dd1e4,608c9215,287936b6,97e5e819,390629a0,7bec616f,7fc713fc,5ef8ec3f,7628d770,5c744125,d5885c2b,de25693c,5afaf8a,3d5739a5,deeeb5e9,ac1c62da) -,S(8657fbee,524c5f5e,25aecdf7,7306c97b,78119e0a,5f155c4f,37918e87,12302d35,242172c2,f90ea26d,b1f7d2cd,dbb9af4d,78a1660a,32402a83,6e598c92,df9e999f) -,S(3ae7e8db,7b069528,acea3e0a,dc005d52,7ca9e1ca,dd3d3cdd,5564ea86,5e1a453,ac203ebf,98b7e46b,bcad5156,cc058857,f32a8d62,2114acc4,55cde626,591fc5c9) -,S(81bdb0a1,9852adc7,afcd9775,54143362,c7e724df,884f1a2e,796d88bd,1c1696cd,2f189af1,a90f9445,353d0549,4d5562f7,4a3d37cd,1362d92a,aefe0393,9b46ef0d) -,S(e95b0171,dd117d45,263141e6,95ceaa52,3498a8d9,d1f09ae6,855fad1c,5e5c3e8,dc8bf907,ea6a4824,9cf930b0,bad3e3a6,c179fda4,107a0812,76f02a9b,9c689416) -,S(20e3979,e95fb62e,ecfa4ff1,3aa3fd46,94b24ab,c814f560,ce180262,11b70bc8,c9d01545,50f1d7be,da471272,822522dd,d6924a98,f6331fd1,cf6837d7,db91da1f) -,S(e0405598,cda639ec,6c058a61,4c39d56,f71c43ea,693f9b86,c9df1bf9,e4fef30b,9df9b561,a7bb2ebd,67b67031,a92dda6e,12550d0f,5cc2368a,603ae64f,ed20ef3b) -,S(faea8667,646d1600,2dbbdfd8,74a59ddc,a2b8024,b2f7f6f0,f2c2036d,ab5c5e9,8112167f,ed386f1,d1e02307,de202bd2,363cd1f5,fefe0621,1c4564fe,eb0220a9) -,S(f01d6b90,18ab421d,d410404c,b8690720,65522bf8,5734008f,105cf385,a023a80f,eba29d0,f0c5408e,d681984d,c525982a,befccd9f,7ff01dd2,6da4999c,f3f6a295) -,S(5906b143,9b994465,c9f3d4fd,f7f09a4a,b9ae0864,262b0140,def21014,8b097533,2917b92b,d0368fff,6e6a98d9,18cfeda4,d039c73,a3cb865a,5d77abff,9fe7970b) -,S(d6443bcf,53ba252e,925f5ae3,5d508732,a3289059,308fa67c,7b051ed9,66b6cc92,e0155fa0,366a2d1c,af8d2c17,a4ad9cf7,f4fc0102,f1e1ec13,7f1b2b51,1af0e7dc) -,S(b95a72a1,dbcfa0eb,ed2200ad,b57d71f0,b96a9703,8bd3cba5,78eff5f4,e9454196,f89c7cd9,783a4c34,1bdd05d8,241ec4eb,d8815463,4d05cc84,d5601f4a,6f3fac0d) -,S(50b287b4,d8b41f03,88804ae2,2b56abc7,be632cb8,a20629b5,3a00fd3d,9a879b6,67c3bbfa,4d8307c0,bd32106,57f5c0b4,78bc070e,53a3024e,1ffe103e,e5397076) -,S(64feb83a,5a81f6d8,8218e2a0,4e6f97b4,6efb89a,6f394264,d905c93a,cb7e5493,3fa224d4,eda77580,4d6ba88e,63df4c3b,5d9fab1e,519eca92,1ada5f44,741d5035) -,S(9434b5f9,2d63c2c,c90ee2fd,b7f7289f,b6277c69,3076d73e,cc38b032,bc8b5cd6,c940b3a6,4c04e6b7,1de7f727,d6fc0883,29443276,6d2ccd51,6d24dc22,3998aee9) -,S(a6db8e98,6d1bda8,995015e4,807b900d,704f8d3b,8ac5fc49,aa16bc61,82390724,3277c29e,bf27d0b5,ef8af507,5e295f23,92c41f29,3803a8b1,6ce601eb,2abedbd0) -,S(50733cc1,dd80ddbd,b254ea6f,14d0679c,6839e6b1,73aa0bc0,9d0ef5bb,bc5c2f9c,246e1742,a5a9172a,ed4e1e0a,9c0d623a,5233334e,47bcb68a,aec41101,92771eaa) -,S(4252122d,5a89f621,2c7b0a99,5ebfa8c3,b980e142,f7a89e07,d4788d91,1163ad99,bc63b87b,fda041bd,f9ac11c,e2e8ab3d,a1368cd0,2e276b55,6419e0ee,3d7fe284) -,S(6bc86411,d3f9d25,bad0a922,21f0146c,9173cc99,d00470ba,a41897fe,b5678f5,e2c1cd75,3915e977,c20d4508,1af1946b,1d8c5926,cca74ab5,c4ec0bd7,921c4cda) -,S(c786df9c,6b2e656d,a30146cb,14da5372,64683e46,5569b1dc,df4c1541,580d40a0,b8d229d1,d8773d5,dedde14a,dcf8816e,acaa274a,1f4ebd01,2086159d,1feb32f) -,S(f42032f7,dc6dc676,5b1a9453,74ee45f8,486e9b94,6a57e651,7dfefb0f,9ea3164c,ad2d7a22,e477f5ce,ad0fbcc1,fe2c2533,78920fd6,cd9ed4ec,1095fa88,2189131a) -,S(3c2fb5d9,a5bc7ad2,d4ce0970,5090a5fe,ef54a6ad,7f8d827b,2ce51785,b29ba5f3,3ec2d878,a4d836c1,71f68648,f8cac869,472847f3,4c267139,5f38e0b5,e96b653d) -,S(b182d837,dbb1e47c,bdbe559e,f30f03e9,ae1efc93,a5a165e3,10285bfd,ffe47303,c40cbcdb,d7f1fd56,c486a35,67420a7f,e4ed4ca8,43a68bdc,81eccbdd,213d7c5e) -,S(75a35130,cea9cec2,81792d7f,ffe84375,a4aec378,57496122,9a77270b,43b12391,988821ee,b6ee31c9,8201a90e,853c4afb,8e330592,6349d405,90c4840d,fdf3fb5c) -,S(a97b9c85,97362b4b,aab43b64,db7e5e0f,3e4cfea9,82939289,e5266f09,87fc8503,ccb75937,fd647eb6,7da4aa7b,72e8d873,c9f035a5,cfa120fd,4d4881f0,9924d8a7) -,S(d129bad3,4c7674ca,60a6f07e,1c1ee8b4,aa3dce4e,82ff890b,cd256324,13a56fe7,b3c8d404,7c8610a1,a56af634,b54dc568,6af075a0,a0cdd4f1,75855fa6,d22cc4c5) -,S(d8a0aed3,cf37542e,a0f06c6e,754503d7,3bd693cf,c3c357f2,7445989e,137f73e2,ba4ad8e6,3bde0d8c,42172a7b,59e1f4f4,581f48e,cffc45bf,929d815f,8133e6a9) -,S(9f905bc0,a5f479ee,6162ed38,24d74a1b,d6d48bd5,4611f840,ab1ac55b,7b84be18,5babdad,4248a4ef,4606dd26,1807e25f,6206dc81,6eeaddda,fd8b5082,52e3da53) -,S(d51c86e1,4519166d,c2aa7604,c88670c6,ca44a84c,6735f692,ee4dda79,e957b85d,fcee6753,29130c5,f4b260a9,cc7efb73,d51e6ec,8ac1ec52,28ca0ab6,51d5b8f0) -,S(ce251fde,ffdf0f59,5a563941,179f6f8a,86402b2c,6bddd1ea,7b37b89,bc649102,5b26a79,882b2f89,79610eb6,5de06e02,b09412e8,bbff66c5,cc650211,d1b9ccf5) -,S(6168ac7b,101fbe73,5b9339b6,9c459fbe,44a6f6c7,bd488beb,bf0b81da,ce511f3,65b6e531,f350983a,2f55db14,588e92db,436f7068,5117255f,ed474aa2,53b5c9ff) -,S(aab2deff,7e77f414,59d4361d,2722b448,6530f0c9,46b93d96,975f5a96,eb4bd091,b416562d,c5b057ef,7e63ec2d,daf0aed4,84320d7b,60695809,c6fa3aa9,e4eaa431) -,S(9ebed934,ca30351f,44b7ea4f,f3f6453f,6d0c7f81,869226c,c8f4312f,d413056,766a6f8c,311550eb,a8500ab6,f3466ca3,52e6b960,c4a52cb9,870ff784,4191a2aa) -,S(a2e78d35,d51970c3,42d03a09,bf3286c2,3a131ff9,abc4bea6,352826d4,5fe2da0e,fcb844e0,4bdf8d96,f423c499,44275ac5,8885c384,57975268,ec8cd880,dc640346) -,S(1a49f352,5203a773,9c7cce34,d21c51fe,dfeba5e5,c0f21622,eb954621,e3d6726d,e617de36,7c6a9283,8d4bcfd2,bf2fd21c,15b53007,6a0367b7,6d6ea65b,af032213) -,S(be65c6c,de6c54b6,c0c4d306,65cb4d61,211c97dc,a74c57b7,13f41028,e2d14832,d7875fb7,5cce3a40,9a74e48a,9b577a04,4c09a43a,989606b5,b44fbade,89e6c03f) -,S(a1572e58,60b10c96,bb3e0b6,7a047d4a,9957448d,74bd8a44,823de9cb,50aaa639,5ae37e0d,88c9f6d,173026ac,58ef45fd,17b0a0da,40304954,f9671c56,93946d1b) -,S(21917639,b6ef2333,378bafe5,fed1780b,24d9fa82,17ee49e7,369099a8,8c9baee5,fee39df,4bcb318b,4dcc4017,7f1af605,f22c44ec,d67a15cc,297f02fc,dfec4eb7) -,S(ac2a8d9b,b2219c98,444d03a0,36db728,ffa182d0,d31831ad,f2643010,bb76d3fe,adec7f18,c9474dc8,d0741d1a,5e72e479,c8b86f74,327fc5d3,cd79cf86,869310ab) -,S(c540463f,bf62ef36,a972d797,2bf79054,80b8e67,415f1895,d42d261c,165d1b86,f04a3516,83039c2e,8bac5ef5,1db4e105,95a27e25,cfe680ed,e7d840e4,f70e50b3) -,S(df63238c,77e75ec9,b844431b,d15007d6,56b849eb,4b6902b4,e79f0d6e,9527ef29,63846f3f,dfba6f2e,46bc7f2f,17af5067,a953cd0b,dbe2fef2,52e73be,b8a17330) -,S(43dd347a,1bf0ee84,ad774d4f,70c67cea,594946c2,94cbc330,15bbdd21,890998d4,b6f58d9e,e6e13c1d,b65dbd28,2343d8d2,3f73035a,b4399672,15b0300c,f7dfb48) -,S(5af8e3e7,f5ba9d80,73c5c1e3,c8d0a62,52eef1c1,17043e01,7d610f20,8b5eff0,246c7a4c,6f6e75aa,eb60e256,756e6365,711e98a6,aefa5345,adefb632,321d39da) -,S(60e7513a,b327df8e,e3d44222,95e0d886,b264f560,1c4e3d03,3b405d37,f6ae8518,4c58466e,b68d6c81,33fa6639,12f4a12c,a4a9f3e3,d4e0f6e2,7e92a85d,4d541cd3) -,S(126520ec,f3129775,786c4d64,7226174d,3ccaf5ae,2e4a1514,90e1b691,f07946a0,d5a2544c,efec281f,e70f05e8,2494085c,133fb918,6416435d,4b7fe673,88c440) -,S(b588e8a0,2396bfa7,8512585b,cd0d0e4a,7d14b5e9,f76e1426,b4591c9,6602c585,d7c6a7d0,827852f9,e34942f9,a6f5eae9,cd0a7f29,d30057cc,46d13e2d,4ec04caa) -,S(257f90fe,4409ef7d,30730e37,d7358c7b,60a1cc21,57acedd0,355d7a1c,89b5750b,b14da56d,9aa8fb67,b2d1260d,8de63c00,a9a7aafc,6fb890a0,e1a148ed,5e371201) -,S(8072b8cb,47c71331,9ed2ce85,cf913c87,85955c84,d338daed,58528427,3f3a4a56,6d7a0ed6,bf3383be,8953b47,d93ac5a5,e40e8547,2fc6d3d7,71f89007,f8d20d39) -,S(fab935ba,b2b72a27,b338ef89,509b3830,b7800817,19c2b3ec,8467c736,24ca2640,2a610c06,77fb514c,b224dcd6,56c5136d,88f87f34,86fa0699,eb71319d,c85a103a) -,S(7c6364c6,4906b7c2,e1ca0d87,6c163932,7e8e146b,afd94c83,2330f990,f979ae52,c97e7b44,26b91f6c,88ab7e39,d57f7b7d,4a5e0f9c,ff15aad5,e58e7017,d51c5317) -,S(98beb1ac,48c8824d,447a10cb,43b51167,b8e7cf0d,9eb4e4c8,43403b03,2208570c,1712c13e,ddff8fd5,191fdb28,717efb74,ed52a9f,f47bc21e,b15838d,fcf00af3) -,S(f683a667,31241c44,4adcf062,156f3fdc,d04e8450,911908e1,95bbea2d,8c5bf918,460eac53,48ea1e78,9fdef168,a150065e,1e4a2f83,85268385,3355586c,87453f1c) -,S(38f065a7,165e5d4,d31238de,8dc38f43,4dd024c6,6eca026d,de03c4cb,b43639a5,790bacf5,d35a688b,130bdb38,29073b8,28837b9c,9357544e,1e44d766,e401d044) -,S(cee8a218,2b3004fe,76714511,30340b0,7cf10241,d9e933c4,97ae84e9,a1d525f2,ed373709,3e0eb05d,3ee2823b,25bbbb11,ec943848,1a3ceae1,89573d71,7a596b3d) -,S(164c6ee5,620f4582,35520eb0,8276d85,9a14e266,b7b59576,d0a3e0a6,636f124a,fe92dd66,139f02c8,76ff6e57,8c769a4d,63484072,5c909bc9,481d4a52,f60565f3) -,S(d4606a18,1a0bd363,eb63849a,81c77d0b,942ff14e,7f885c61,d1fb772,78ef1008,81e7b2cd,e7c5d9,29e1d69a,309a334f,2c01b084,e82b789a,835a7aa8,5d7e93a4) -,S(905f5725,1df1651e,83aa8b3,dec2d96b,a32155eb,90d7f985,b3ce5213,2092be07,e4acfdaa,9eb8995a,a4ac8a0a,2b66cbbb,d561fe6b,389c56f,3af6f62a,d7579632) -,S(2e3ab14c,d3aa69de,a35a8ad4,99130302,b16f3d3,9df06b77,7c30e404,91eb6dda,ade534e7,ea0217a8,88c50bf4,ef81dddb,a5c7ffbe,bc0f90e7,110df2a8,e0c7c2c0) -,S(98207cc0,23f50a6e,5f5ce8a5,68c5b24,d4f4f741,94de76a6,d1e6f44e,72619a9b,fdacc236,bd424684,52508806,b08fabdd,98a15b15,6751953b,95b4c5f1,40bce374) -,S(b6d8bc0f,894863a2,3a793c3d,a33a5e66,cafe8696,f9cdd40e,777a40ea,aa203ee2,7e9b246c,8555b4c2,47c45fe1,d1e5d160,c7ed7d37,a3a43440,deee6ef4,15dc092c) -,S(56d030ad,eb30f1b4,7f806276,651a56d8,7f0d8b6c,458092e1,61351368,8cd0f6c3,bb3a1513,155c5885,e084180a,1728902b,33e1a61b,364c8d9c,94d67ca2,e386f131) -,S(77251aac,f919aa4e,b7610a77,ba27d94,c85b973c,af04c885,92fe5272,a48ec088,ef27aac0,593cc67b,93535bc8,4d0a04a3,e8a865a1,bdf65312,85beac2b,d58e149d) -,S(cb7b6a,cbbbdc23,64711585,6d80df3,2ec9aaa0,c6380b3e,677299d0,13658121,1f818bab,72575e35,a60ce7f1,c720e9ce,2f59b086,63cba841,ea288920,16a40ca4) -,S(4a18eb1c,bddb4c3f,ed44fdfc,6242959c,29720142,21d10154,c7fbca68,5c475d0,bb24f347,ebdcdc0a,6429f8ba,49065475,9cce87aa,8df10496,6d2ebcf2,97e70ffd) -,S(384286ca,1003c97d,7d151032,97d81cfb,e3e3dbbe,5dc70c76,6a8dbdc7,c1e625c,7201deb,638d2ec,6cbb4db4,e955ee1b,a3015cee,e06d2ddc,f024daab,8f07a277) -,S(84b6d6ae,d5e00e31,73c24d39,80f05cd6,f61625e3,11439a55,e03ae2db,d79a7d55,a3da9e1a,4c32e4f9,a1d326c3,6670296d,3ffb18fc,266e169,a99d4d00,4de383b1) -,S(aa1cab51,f7239cd4,dd27a4c4,805e614c,5d972cbe,c2830ebe,7daf6ed8,781c37e9,cf8bb72e,535fc8cd,12a2f4d5,e8f9e257,38a28812,1c93b061,5fd4fdeb,368be5bf) -,S(7c4f183a,f4abbe43,d7fa6d5,77ea6c14,83302f2d,b863a7c5,bf072e51,3d2140bc,1eb08c67,a417c0b,58fe8185,1a66902a,a608db07,24dc38c6,706bb80f,5956c808) -,S(dc30f68e,58ff30a,4bf2f6b,28b30708,506140a2,1a971c04,8afe04cf,94b54d31,6f996e08,8d4f7f53,aa1c2050,644a47ed,bcc1da4f,519978f8,6496ba1e,c7be2688) -,S(145185a9,ac6b036f,d0d3cd25,c904b3b7,c8f1d0ad,3ffe5f89,d87b7804,8b017426,d7f6acb2,828ccbc0,db0708e2,79db6313,fc955d2b,cf9e2754,1a7535e3,24c7bc90) -,S(e8700138,5c0bc4e2,9911f29a,e39a5ae3,ad3cf1cf,d690cbef,32f313ea,fd190fa9,92d83708,2e5139d0,f8084001,8ebf8703,da250361,466caa96,717edd0d,6e7ada7f) -,S(5fac0aa7,9963a1e4,5e1c668e,3512d0fe,2eb2c709,d5ecc71f,c862d5dd,523f864,9c7bfd73,445e7d9e,139b96e6,813f1f80,2ec632c6,a76e9dfb,8afecf40,2788d16a) -,S(441f40f6,f3ca4dde,5a085c15,57f14cf3,fbb7c3f2,5716c33c,63ee90f,45c564e2,c81f1205,1179c2a6,f2614495,322cf40a,34cab55d,c90d61b4,d1bc3787,ec3baeae) -,S(a4068c1f,c63d8f21,203cb6af,b37d796a,3c454bd9,db974ab8,e8bfba8b,b832b043,b5318b99,e9354250,a837f8cb,cf8d9cde,d95bb1d,1db0becb,1e887535,4ddb96ca) -,S(44563417,c647b097,d0238a57,74998fce,3c809a26,f6d2b71c,eeecebfb,134cfad3,3f417680,1c15172c,ef636dc3,12742429,13d59079,73ad09c3,9fd8c6a,8a95104) -,S(d57a5fde,47873327,728f5706,d2f0d64,1c5386a9,fdc41808,a2c062ab,942acb6a,cffcd62a,c0c85aae,4a6b7881,f3be170d,9836abda,baa47d60,8c0b8f60,f9aaedd1) -,S(9dcedd10,d495fa2b,6f4b4387,57cb38be,d6f09949,17e7ece,7de913f7,8cb111fd,73196e22,59d4ae9,950725dc,77321567,167d7761,29cc32e9,d92b6dcd,4c056223) -,S(aea290f3,a4ffd405,d51f1c8b,5f11cf74,60f05300,a1e24c08,25b96910,b24e32c1,f6c100a6,3c918f8,f64ffe8a,95840421,dc384635,e3465cf8,65034bde,17ca8eb9) -,S(bbfcd317,5091846f,181696f6,35fb1b05,802e7659,7ca97040,31339381,46812234,2a0a4ebb,1f09b31e,aab4478,89000fbb,5876d7e2,dd889393,3001a977,8aaa3a15) -,S(2a3b4e65,d9d7661c,addfe1e1,96beaca3,ccbc0348,dff6d2df,21f394c7,a7f4594d,74c6f171,1a2c0c01,78bb6a27,b6e17cda,bddb7260,acbc533,a49b19d1,e0b4a110) -,S(d8e47e32,15cbe145,aaa9efec,ada428f1,8d8c599e,98d2f9d7,8177215c,c85dc2ae,5c4d4f6b,aadcd87c,7ac76eb8,22e1c0db,e7c81342,702bfd98,e193df1,809e0511) -,S(5b5954d1,25d77778,f3c1514c,6256ef65,2ae0ab97,151f8856,dda6c87d,1e04a34f,1c5ddf3f,b185edb9,14769482,95e687e4,40497582,26b36fc6,3502922f,cd1bf81e) -,S(e8097e1a,12c6837,a8f29eec,31ccbd16,f191e7a7,d7b199dd,d6d9ee6b,7f26ef55,84ab3d24,e2c4407b,53e4299b,8de1aa8a,22dab9be,b6efa5c,5715a943,65174b9a) -,S(495ebcc5,b0573416,f2b3e705,fe4a4bfe,1e756211,5f37b8a2,dec57688,dedbdd45,3bc65725,6783970c,7696d5a7,b04ac7ca,8c627ce9,251844e9,e7cca774,4d385be7) -,S(4ffc69af,b9cf40ff,c94beac6,aa020109,b7855e0,a993984f,5e59ba16,fc78ad51,6d43d1f9,e3283528,494c9783,cdcbe9ae,2ede071b,ed494c57,2539df6e,b185ca1) -,S(b047e0d1,afc92251,7eaf5c0d,a9d0a093,fde5e829,84c8483e,d256640d,166dfc75,dca2ef00,a282972,d4bf67cb,74fb31af,da5b8145,ec1b7a65,6636376c,504a70df) -,S(ea7b0b93,48e0b3e2,be800ed,6ca4b121,277a496e,84fb6680,2658f68,37b1d530,cef40d2c,e1cf820b,19b435bb,a541ff1c,fa572b1,ca3693d0,cfeb3b32,8ddf918) -,S(e35a53cc,ad74738a,bde75a3e,e2b10d7a,d4ec39bf,e32e1daa,ecc151f3,bef1966b,ad06a8ab,a0296c17,fb24eff3,b27284c5,6ebca204,f6eee752,276ab9a8,1f1bce13) -,S(70334511,ae9acd50,e094f034,17dbba05,4a104c84,ea8d6250,13e1f8f6,907261a3,d1f603e0,5af2e1df,4b8eac69,b4067810,c302ed18,f02bc964,2eba34f6,bc67e84a) -,S(13adc074,c3ea8877,4598d0b9,ad653285,c81bd98d,d4bb6a43,c126db2c,d1f08d7,4bbda9d3,c83c7a64,fcccf3e2,c4251a7e,f61966b7,ec48e89,c991d44b,9588c83b) -,S(4a2a5fa0,71702fa0,934b66ae,7c003f00,306f07b8,625d92f2,d2276efd,18ce5f0c,f9c2f4ac,d8c594a4,117a836,7fa5224e,a7ccbe60,2475e3ed,b19a317c,5feff6e9) -,S(e2f7dc14,79bac0e,a95b5a2,1a9f4e,8c42a23b,8f25d09d,dacb9a3b,fe3ec638,ae6c82,c4f3dc5,41f140a5,2eb6b0c,dd0e200e,d0d951b,e85efd4b,b9b086ad) -,S(eb1d6d07,8f6b74f5,c48a913b,8510e8d0,5cfeb954,856f3ebc,628d0db1,a253963a,f3d73300,e216d14f,d5a67c35,91b362be,f13818c3,36a93784,875ce9b4,2cd8c7d2) -,S(a22c6d71,1d79ae71,403feb96,6dc11adf,253a5d3f,d3d74b44,5f7268bd,84b52277,86d5212,bf37db8b,4e873476,36201714,3f295f0b,d69d2187,8904a53c,831af06) -,S(42f7eb02,797cc76a,21c95db3,c9a0014,4ec5defe,553a45b5,1b701c0b,6f5ed3d0,60525877,3cb86452,928e37d,ce19e2ad,4da63174,2f049214,9f9823ed,ba679519) -,S(f5250698,b37da26,20a3a80d,a9c1c88f,792677a2,6d2b9fa5,49065339,ecc1e95c,b0826c,66edbd2c,5562bb14,d6f8df25,a5d0bc54,7a1163dd,4a8dc1e3,7d140266) -,S(b845d4a0,bc8db805,43526506,cac5c093,cece5c5a,85750d54,317dd78c,7bc10832,e38db2fa,207ce0b4,d9b01ee8,b174a24e,f28591c9,9d203ca5,7d90080,807279b) -,S(4955d281,746b8c9,4bac7d53,26aa28c3,9fba7149,7b4fc036,f9971f7a,870a67cd,ce72ebf4,aef6e987,3fa5cf3,e66ec918,911885ae,848aff22,eeef12e2,e50e6cee) -,S(20fdca2a,a03d6105,50f2eab8,d5e7d47d,c4e2e9ed,e6d2c7b,bfe64d75,176b9e9,1e077683,2c44d6d2,19d19c7b,aec0a303,f4d3d5f6,4ad8ca35,83f87325,6aee262f) -,S(418de9de,9adbec78,769eba7a,cab3853a,9a85ebc7,2bdffc86,844d0f32,15de4877,20d521c9,974c8ee0,f817ee37,a0fa14d2,eefc4e05,2c93ce87,ee665898,9e49c5a2) -,S(135b5a4a,f64eaa0f,d288bee5,c1bb7846,30df305b,5d3b13da,d8c446d3,6e13485f,3e571c3c,fe32fe42,669b08c9,14a655ce,828f41cb,12b9c18,9234f4eb,1aac0437) -,S(7eb64f50,5e26671d,21d3b2c9,fefbe094,c6300348,25248e86,5daa8939,f8b7e90d,be847834,f303ae8a,55ebaf3b,5bccfd61,6284e836,13eecdae,ab43bb6e,d4d4e986) -,S(9ee1ccd1,670be914,f9b7a070,962f7ac5,ac9d069c,eb3e0748,72db2e08,32870fd6,7d3d9dd4,9e71fd68,4271b17a,a8203ab6,1d2bf6d5,2fe3773c,78a8ccbe,d256cfed) -,S(a256c06a,796cffbc,5c90d91e,93ded565,b9755b7c,b760794e,e3060b33,3c217e71,e9ef8b6d,7731c262,6c93fb06,b7a6b3fb,fbbe0e0f,54682409,e5218a74,d4a064fd) -,S(dde8a9af,ec32c1fb,be9470d7,a435b4fb,bd34416d,e703a1ab,5188fe8f,f721aa4b,e7dbb850,aced2fb2,fcf5ea6b,edeaf383,e4ae0fe7,98badf41,66e58f13,6a87f3ae) -,S(fe88599,811d0e9,f780d359,2e8106fa,2f54fb6b,ba1df66a,b7b0b41,2c130c49,b3b0b8b3,c7f36d43,86f30438,1989d885,31edab91,f25251b4,e01b3d3a,6ec97f2d) -,S(d7da001e,8a606b37,ca65ae71,32214cf8,258dd422,efe0fc83,adabd56d,64b0467d,97f503ce,8eee1873,7e422bdf,91f051f7,1025353b,3a1f6f1,545206f8,2a32aa5d) -,S(65237583,e3e1a640,c2c16a9,a49d09c1,f5dbe2d7,a3845989,574abe33,397e747b,2296a1b1,e2350d8f,14a6fed3,afe30fac,a45ff345,9f8f515a,370aa260,d435f7a3) -,S(419a8e03,2d8fd27c,afda6538,9b757550,313307d,12fd185b,4d2f026a,40ae1de4,2932ea7d,3421d738,d821030,f75b0343,fffe9d25,8b605cf7,e20f6b48,1a94db03) -,S(275d261f,7ae2ab4a,4ad1fd66,1621a223,7ce08787,beaeeee1,a537b103,c0a44023,da955bd0,4ef1256c,9e184615,c4ee666d,c9ae14c7,d95caa7a,5dca6f11,1e5e2e58) -,S(3ac6681b,d0a2968,290ad83,cb0e00c6,6a9962cb,4c082366,953e294,58ff3651,28348b56,38ede228,7578cf14,ae385066,4595a2a8,d86282a0,edcc389a,346066d4) -,S(d4ba242d,9407df55,a9f672b7,e01cb1db,99ef744b,d24d3e47,9b1841af,a6c1f05b,9e395144,aa1fe50,9d72d086,4a1673c5,24c4ad65,fb7bdb16,cbd52053,1c6f11a3) -,S(c6525077,2bd399d9,901d57b5,7e8fc941,cae0f5fb,6d47ee3f,5b3a7cea,3fba2e83,629f7edc,a6ec6b0c,579cf9f1,867e1bef,e3bf9bea,8d8e64b7,2b18532a,47280efa) -,S(f12daac6,d38fcb00,c2425a79,2c52225c,a94d544,c6b96076,7ec9c885,d6d4430d,1764feee,2584dee3,abf2aaf,737a068f,fa6aec89,6c02e2fd,cf0ccad2,7ee8f210) -,S(db858a7f,4a84d88f,236b5994,dca409b3,d7111df4,f7e5c009,4ad1decd,82036673,c0606c89,e4b13042,9e0a63f5,1c93b3bc,95d98832,d89a9515,2e5c1874,f2c94a53) -,S(237f5f80,4d4c50eb,d611b079,5cbc6567,101ec8ba,1a265976,64472f7f,5a725ed3,b558d31b,7647c4c9,1367d696,a67e5d88,76454900,f340cd,5b8d7490,9fdd5993) -,S(e962e9c7,7c97cf36,32bf0a88,d6e939d2,68af9fc6,ebca96b8,6fb679a2,d953eb20,931395ff,a50a854f,5aa29314,c50c253c,c3175739,9c2eb20,600b0217,9f8ef48a) -,S(890514d2,14b57796,85c0cd66,818d182c,3d285af9,771c7c48,92ea2ac,115a8c3a,47c5a,a4d76cfb,2a62993b,b499df86,fbe7e130,d4758235,7decd72c,b61aee8) -,S(8b058976,295a316e,65da1774,da78722d,8d729f88,5ea4402b,f20dc67b,bab7f815,aeed497f,57d52480,23b94a3b,5fbe9c0,e34d0039,2d57b34b,377bda9e,b8703335) -,S(6a4685e0,7d96a793,d55a6416,6b089623,755fe549,3a879fbf,fc9a5a74,7ee7991f,313ffb6d,98044c92,f37b3f66,81f1b4b2,d9b2e42a,7c34a5bb,db45b9c,6063aad) -,S(65157530,e4ffeeda,41064bf1,f8d85174,2b9b8f64,87a05ea9,3d2198bb,3f33fc26,5b0e76a,8f96facf,9d492232,95a0c6f5,6a609504,b9b07c38,a72b6f15,4cb8c9f1) -,S(9f6c288c,1e04703,46b02d47,8fc0a40c,dfc0229d,928639cc,6ad2ac88,96e55085,2af7c1c1,7210b552,4ae2083b,b45e9749,c9452776,c12d5e83,ce265c98,51266c8c) -,S(c566e04f,e5ef7062,7d914a04,40731caf,3a7dccbd,5415cc1a,a2d81328,b8a6da75,a3fa5263,a7f66158,67f43270,77d3b2df,8db1befd,552249ad,e96db0d2,8c439282) -,S(6963ffcc,cb62ca7e,565fa9e7,99db54c3,dcaad601,95bd2dd8,df70d447,c443ba4f,96c715c6,84bed531,27c28e3d,6d6a0214,883aa214,25c4626b,4c11cf17,36b8f134) -,S(50db27a9,8e0328e2,81139df7,5376bec6,37e9272c,f7c23333,510bf5cc,c4f46b2a,b5221242,9eec82,1e9143fe,af9e7813,c135be82,bfc153f5,2ac061dc,c1302d92) -,S(7badba3,8f23f854,2404e636,b96e86a6,84557310,2bceb7c0,241e71c6,1ae22ad5,bd000395,b5d0ba4c,a76ac682,5191fbeb,f6066d8a,81c4a210,56ceda82,e13459e4) -,S(147667bd,5591aa83,26fa497f,c60f8e7,a5ceda47,9d4b2f7d,93bdab3d,81bcbd0e,bcdbbbc4,2adac6ea,413fc3f3,6cd2089f,420a6183,a918bf98,fff27aee,3e870849) -,S(ee576c33,e8404e1e,11e1b5d8,6ea52335,cf8b0ade,49dd16a3,7a61fc10,cd3eefd8,722bad17,6e083868,b3c14ee9,a70013d9,89c01b5f,44188ec6,7db7bc3d,ca26fe2a) -,S(8e3cfa71,f3b7d3cb,fe59d8e0,b579b76e,d33d318f,41d3b76,121b02d3,2acdec80,86be156d,b76429cb,ff2c67e0,c015b7d,d0007c7e,33f6041a,d817ae9d,ed5dc4fc) -,S(e220362f,2df8a485,51dbb7ad,634c4bb3,714151fc,db3cc2f8,e483aac,50d88768,acb8e001,a81eb6ac,99dca40,2d62fed3,8891fe2,eeb8e023,6d8f2447,6f4fd200) -,S(1777fc26,9bd7aebf,c014c785,25dcd40c,f93db012,31541cac,448c44f4,89628808,641bdcb2,b87e04ad,3ea3a3d4,c364e93,1171b2a2,cf3c0205,77552b7e,594c649f) -,S(ddfb5269,fcbac0bf,a855d2c4,c9062c77,836af1d1,145b4df5,688b6a5,24c11651,c353674b,9520ea9e,eac3bbce,a85b0709,d0284c37,a7faf78,8b573ebd,67bac8be) -,S(b01ea11,d4704bb4,24cb11d8,b42411a7,3f227c84,dc10eb13,c2b20a1b,bf23258a,240844e,9ea3edfd,948d2df4,51538cba,ed57f157,d0632f2b,8b644570,5f9ccaf9) -,S(934e20a,46fbb416,fbe829d1,46bebdf5,2220c0db,958c2a9c,64244713,4509cabe,76b7a1cf,79ebb5fa,58f77e64,4395d33e,bf90c0be,37e7439,c3d29013,25b0dd76) -,S(15bfe959,5ee58bec,791981dd,13ac5380,6615ff53,95dd4661,28c23f59,ea236967,d6dd460b,d3d36bdc,eb7d3ba7,745fe6c2,fddba241,fadcbdee,44f377f,bd43ee00) -,S(5e1a723f,403cf56f,8019797e,6f8191f6,6e7ccf15,dfb1965e,590490b6,224ecd24,97342532,36c48696,645a7e60,552eeacd,4cba990d,6d73117a,dc6f2967,a6a0fdbd) -,S(1485fddc,85c819da,8894c1b3,8be82eee,762a052f,3830dbb3,7d21ee74,868c778c,d779373d,d503731b,52f9e689,805988c0,b916a579,921c637b,286c580,93343d5d) -,S(6f4b7385,f881c9ed,202ab6ec,c8302626,668a1296,36274f3c,ac4296e9,1eece7db,fcf6f192,c6c80fff,3f5c2bbc,7c6c4a5b,b0ea2e3,70799827,440e998,cf6b26a4) -,S(bc27cb29,33ca44d3,b56280d7,7d69af2f,9220f4aa,49aa0fab,685c7c54,62adaf76,7607d5b7,a02c5e21,cfafccc1,26e8439,88c10942,aae6333d,b5262426,1ed4da98) -,S(76f86b25,2530d87a,b04e64c2,4cd1e05a,e8324bf0,a717280d,3845cc5f,a6a1a733,2db7ce38,33bd24b3,55e95b89,ae6d8a54,19124761,e382745f,2a7347ce,fd7c382c) -,S(5615175d,2ec968f8,81dacc1d,1bd6c06b,df87c9ab,53fdef11,335818f,bafa918b,5f755638,6154cee9,e71d21b9,cee3971c,7d41e3e0,ca2c1ff,f66982b4,d66fec25) -,S(6390f1af,1ef24aae,20e2ce29,dfe9a0d1,50b2826b,f5cb3629,8e0dc16d,ee2bdf8,cf3e2b98,4f120d10,16f82e1b,8916928c,263f3323,52bbedb3,c29ae1ed,b0d49b1d) -,S(bc5df46b,4fbcb83f,7aa53579,ac8d5c3e,8482941e,cf848810,f9239138,b57e9378,d4d15516,624e72d5,9002dca8,3c8b5914,b224d4c3,75260dbd,cda88f9f,2f772627) -,S(3d069f1d,dd52177f,cd802195,c7c8b2ef,1e43c34,9bd88b41,43bc2d54,6a2b8d33,2ba48861,14218d67,1b1fa4e4,2aae97fd,66164e94,af1e3026,8dfe9dfa,7155fde9) -,S(fa657492,fab9ab23,f1a49c17,40079d7e,abafd7a8,72e481b8,7b30cb63,8a47757c,89d2c7b9,2f1ad11b,d2808968,c426a00f,e584ad83,86dff03c,1a047804,a2e98630) -,S(e2318d84,61f85ac0,7db07d08,aacbed7c,5f5a45fd,7e505bb7,ac86b417,6b3eb46d,3b0170a3,b6f466e0,380ab984,e5bf4b34,89cbc479,cb2808cb,445614bd,8ab012e9) -,S(defa0810,91d1db16,fc2f86b4,fa5a7331,f0c15682,55855134,10f41a6d,a2bfa6a5,8429db90,fbb25354,3e77ca0f,e7a731d7,f1a481bb,f1c997e8,5f585844,423ace4a) -,S(fbaa7567,7306fdd4,8c85514c,bcb78e04,ef4d693a,dc7c356e,f95ad34a,cc880db0,45c4972a,161f4a23,cd71f726,d5617b71,421b68f,b0611097,3edf11b3,8a391909) -,S(5dd76e24,e3cc0c5b,ded55d15,858f1c19,dfff7e43,b299df43,3ee77b46,2122205e,992de68b,87bd6760,a75d6b90,89dcb2b5,5f0b39c8,eb079ba0,e4451fb,dee8f2d3) -,S(890c7a78,d0f1db95,75b53e98,a0a63d81,8096422a,3ee18403,ede8ffa6,3af9418f,7a362df8,7430b479,11e8d310,558195c8,fed28b05,531b68a9,1631ef97,ac008085) -,S(4914f692,f88e858c,b6174e6a,9d4bbdf9,87f0e373,1bf6e69b,8bf3531a,43a37e6c,8751e02b,fa9e0384,2ff3e4aa,307cb7c5,fe4f7941,1069249b,c8b19866,b6169cf5) -,S(a5f97745,ddc25117,81693df1,bd15203f,9d23bc93,9015be73,c6b4e256,d1d05416,57a99674,cf64bff9,7b9ba0c5,69d253dd,52aa188e,3ec645aa,89466c79,5d0f0370) -,S(62da0bf9,8d32519c,16fac809,95869f09,b570b953,e0a7bd83,9623a9c9,bebbdf84,9b9ec74a,c960fa8c,2ea8bd4d,93ff624a,9ce54fa2,4a1822a2,37d962d5,64e9121d) -,S(5caa2062,c25d7df2,23718f9d,ff29a403,e5200d22,bf064b44,c9519742,4c448a5f,6063bf93,1f72f65b,9ca76400,de5f5204,a8a0bdc4,b19cfd12,2664aa33,79a7a27b) -,S(4a81083c,c18dcec3,5825415b,2854250c,9dc651fd,5d897610,2ceb7691,576ebe60,850f48f8,7ffbf26d,eaad1f8b,2c0b8272,5f7c313f,55811b98,408f8f34,8421f241) -,S(ba8baaf4,9d0c194a,4814070c,786fd9f,4b8dc012,c42ed667,7b39f67d,da7fccaa,ceaa8874,10bbe854,9e87af6a,15ae1326,d85bb995,19a8c4d5,dd3a8599,d9ae0ff2) -,S(4c780a0b,886fdcbc,a30f239e,21495f9d,5ea38a6a,7960ecb,ea4dd2dc,9266103e,7e50e1d5,b6c811fc,f86ee651,5d64e06b,26827ba3,656dfd51,1fa64124,224e182a) -,S(50a433f7,f528d66a,961d7123,7e6d2bf6,7321896,5ec6599d,b1f34b0c,db21524c,6bca1083,9ef8d450,e56829d0,cb23ddcc,81e2e7df,e79b53f3,2f8aab9f,e2eec15b) -,S(b98e05de,573e37c2,80d6de1b,fd479bf9,bd23a6b7,2f6ab34f,caf03236,c67ec5fa,d86f07e0,8a4c3d61,f087dff3,a2af2d98,58787d2f,424b49da,de0c584f,4d8756b3) -,S(d0cb5279,e76b8be9,b2e9cdd7,b0c841b3,33398541,24923224,db54a91a,81995433,11fcafb7,28a3307d,2d87f2ae,d107b0b,d64f6030,b89e845e,1f67ce7,4cf7ee6d) -,S(90c89963,619b1593,d5fd7eb6,751ef03f,aa7c6802,46e36bcc,5d0bbae6,25376720,6e8f2a86,75b803f2,c3c87f9a,98318cbc,61b99073,2b8b33b6,62197ec5,73f64a71) -,S(bd3ad39b,989c3a08,e45007d9,116b0d4e,2dcb6a14,26a44dc2,29bff230,6c1a89be,7e633d7,de03e6d6,a7a4a833,f338160b,cb914997,6dc2080,28c3e2dd,b1c1b11a) -,S(1da5082d,a6e4721a,499d5559,91e8d216,f26167b7,d6de224d,17bc4e5b,ac94093f,5f864511,4b89eb63,60ef865e,6eb887c2,bb0b97e3,9a0b7078,888049c1,29f63c77) -,S(19320416,52e24197,d195a0f1,99818925,35c19790,99d15992,8999073b,4028d659,2cf34c91,2d1666fe,1abd3b0,49b12dcc,f7086e58,b7700b23,497bec18,e057059) -,S(79a7b5e0,482523d0,85bf574f,2e6e431d,b3bd6ae8,4e921b87,fff0f683,976efa9a,f713e011,70de0de8,a8cbe229,b147cf82,efc7fe3c,d7171785,c85bbbfa,ef935755) -,S(c2e16cc6,8559a160,9fe16d0a,9be4016d,55fccdc4,2d22ee62,895e0eea,a64436b,22399345,d40c11bb,79b9f036,5fdf6a91,4e1f43e9,bb1f0a87,81d2ede9,fdb6a118) -,S(f76c0f67,bd3c648d,c320125,5c34a93f,ed656378,8c9f61a9,c60933d4,e2d55d7,205c9c5b,83bbf922,8e99191d,e7ef0feb,429050e8,2b9fb3ca,1dbd2d5,cd35f612) -,S(24a3af8f,ee393ae3,2c30230d,ed6f96f2,9797d591,1cc3d934,b16e1304,de7bd75a,302041e9,2ce00cb5,d4a667ea,90df7f90,576865d3,7f462126,400c77a0,a44259b9) -,S(2e8bf897,5f29a6ba,636e6ddc,1e2dcd6a,1373f123,c6f155b3,3c8f46dd,b18baf7c,a93f0c91,258ec64b,d6e18761,872cf0e2,c89f9713,b9008605,b0378f8,1ec867ae) -,S(a5d35483,7f90d71c,8d829897,b3a8fa36,7c38b41c,879a3e6d,52f2988a,b88dcf68,853a586d,9661cd50,12d1ae6a,1501b874,739405c4,c7e32bd4,23ab7c1,62382bfa) -,S(51a6c879,ba6f75d9,4480aa71,2a343be1,bb9aebc6,bb4ca3be,de16d33e,992659c7,3e636d28,f8b0a4fa,a3ecd585,80d46253,61f496b0,344382b3,5742fcc9,403e7e05) -,S(a1d34e3c,aba45bf,1772d2f4,bcacd17e,342b66ec,97dadbd6,780cc453,ff2449d5,6c3a3b8e,9717365d,2f21e2ef,d72308b3,45008ebb,10ca02e,969d14c9,1aaf677c) -,S(fce0f1a1,69034370,33de7e6d,b2364b0d,4441c5f2,ee405e68,5dc546c2,58adc2ad,c018bc7c,fc5ad1f1,36103729,e1a177a7,495a6195,915ca5ae,c086804b,8c107865) -,S(e380e6af,c47b11c5,1ba0c8c3,9b796179,39b07cd9,988896c,38011e73,a4f98a81,60ecd299,c22fbed9,132bd455,1f44022e,151927e4,7ad93f1a,a0539c37,2680f6cc) -,S(6382fb8b,2f4179e3,191d863b,a0ec4cd,94b52103,f24a0377,8f6ee27c,7c81115c,6e8d4181,9621bf4e,3c04c5ea,2b4c0146,dd0ed973,bd4530df,d671f39a,e54db63a) -,S(c488650f,d66629fb,927dcb0b,9f5d0771,1caaa3f7,ad6df39f,7d8f98d9,65490aed,b395d9fa,46475b16,6beed01e,90c9cfd7,83e6138a,7bbc6d5d,f919d41f,3e512c) -,S(5cf1f5be,462dd02d,f8d1e9b,6cb1540a,4f1e5be,de9c8d29,954bfb0,217e494a,5e8727bc,2429c9a7,5123967b,b598207c,46105822,5402bfcd,c3d070b9,b2351d20) -,S(9644ace5,9dba2b1a,f3f3a4af,da130ba3,c3bdefd9,39c3b52e,670ead47,54407b9c,5e83dd4a,e338fc0b,8c501f98,72295400,4b2465f8,4f1c272d,20e3a2bf,300b1b79) -,S(728e6659,f0bb9bd5,916846ff,3aab6f10,85517ad2,c17254e4,c2ce908,c7934781,7df32327,354020,319e9cb7,696b0384,6b8e5bf6,691cc73f,829abd42,44e674b9) -,S(80e68c8a,31d715a7,5068091a,142d4a60,ff30d2c9,42f625c5,d234bb78,31009e8e,fe04addb,b9c47f69,3dc0b126,67b0960c,1b4a7bf2,882aa626,b1888e5e,e4157fd9) -,S(e655129e,90211425,558cbf1a,4eeeb630,df68a4e4,f96a176b,db55500a,89f5af02,d5e3a471,ba698897,9f747ae1,a1aa87e,e10c5069,3df12ed3,ed52307d,a0202a69) -,S(30a9e289,f6ab5edd,7b56f48c,e7373a6a,97dc698b,511343c2,8c5c217c,de67ab6a,f4016c18,c4f75d52,927127bf,c403a83d,4ce304d2,8a4fb965,beef9fda,4e9d3f4e) -,S(8a6a4557,2c1dba29,c9499ecf,d59ea43b,1ebec5a8,78a3e2c5,2de09aa7,c0288e69,56e4aceb,e8315c2f,b9271519,80a21d,c17ebad,63223380,b24a7237,33ec205b) -,S(647d3443,9f4e4f50,cee5b0d6,8047f130,965f8abf,482f6166,8859c86e,326c1bd1,f951b5a0,b180894c,f74c5235,cc625888,fb830382,3b0d085a,dbe857ad,dbc22088) -,S(6d143d17,9f0a42a6,85031c6c,f62ef32,2cde46b3,978b04ba,bc37bd3,34de5634,925d0fd9,11c7863d,b0ed42c1,76591307,72b456fe,83bb8063,3afe5340,cab4b5a7) -,S(f21cebe2,7ce8dd3e,fa30428a,cee881b4,d65eddd1,30f9fa62,9d78291c,a4f4b0bb,4a6d7f43,f2ed3d26,330e58c9,27a87c55,850620fe,1edc6e36,c9a3978,8f922ea9) -,S(37883073,e227a5de,452c7706,a4a06594,5a891c06,e594fd4e,191d36f6,79117c35,224bb4cb,389f3d25,42411fd6,594ad6ec,bf4f1c9,11f723e1,53dbb420,33ae8ec5) -,S(c21520ae,e6cb0358,53a7da78,919c88ec,84c17d10,3ac13ec8,6a412d9b,96e57c54,56720dfc,f748ca09,e27e8aa6,e29ea591,c0205290,3d38bc35,3b0b0155,113a5bbd) -,S(96cdb3f0,d6194675,7346b2a2,1767fc01,2e6d1ca6,f5e788d2,f89e2fd8,89a57924,9f5fda94,e0455b28,1cccc531,7118b175,edd6c93,c212e7c9,fe845f0b,cac5a592) -,S(7b5e5f5e,564606bb,a71b8f1a,7d410b1e,6482f508,879e1bd,38ecdc44,b7effee4,92a3f1b4,84ddc60b,4b005282,89984241,4f91b9bb,fd55eaba,37dddd0a,dcc1c6e) -,S(541fd344,c9d553fa,1e87c9cb,72150cae,a69a9a10,771ac96d,fb292be7,261912f5,80ef7a00,6ce5ac0e,975ecd69,601fd059,a9860e07,77f6f31f,365187b1,f6c9b392) -,S(2b2b3929,50b07da0,5c20b72e,4101e36a,bdfccb6a,2a7f36d5,b57f58dd,1403035c,ff6c1ba2,caee889c,14414086,456f096f,d065a7d,d2f9c7b0,9ed4eb71,3b4002a0) -,S(23acbca3,4754dffa,8cb3176f,d1435d6,4cba0deb,84e12ae7,adaafe88,497aa60c,5d95b3de,26f703a4,fe9efaf,cb273921,56a49687,a71433f6,9a2813ab,5fdb35d2) -,S(5fdfa393,6bf9c699,24417a2a,f36054d5,95640b6e,3ae30807,5ef51bb6,cd63fe34,97fdd994,bf74c959,2a5435fe,f1baea41,8a79c5fc,1243fedb,5fbb0466,4d599d04) -,S(177cf8ef,58aeefed,2832d53,417c7025,c6b56fb3,8122ccc5,2b33f79c,71c461fd,d8a12d8c,69da9b31,832cc10b,55b57a60,b900c19d,f8f38c92,f6bccfdb,98d3acf8) -,S(14f90282,e5a3121d,a59e919a,fcd146a1,9251cf5d,c0d805bb,bd013eef,4ab78bd3,74a504be,928ed13c,f29032e,5c3dcb3,a18a1df8,aad26b4c,a64ebabe,6afb4244) -,S(31099221,e6ceaf16,81b22b33,dd8ee3ef,1c2a95f7,2bed88e8,15333f69,f91867b3,772e45f0,930ebd2b,7f5b7ca0,640467a0,8ab5472b,f6bd347c,903cfecf,8f80176a) -,S(a6a0a416,d8eb22be,49036f4b,dfc79c6e,6cd167cb,38813269,70e199ad,c5d1b5de,54d036de,6b84f308,84faebee,4f944375,fed61a6e,7763bb40,a283ab52,3335af10) -,S(c7c5cb1d,ce484477,82e7da9b,55bb8482,4f715a80,d844294a,3c05dfd8,3dde77cb,bb66731,1bb0c2a4,e493e257,d289a42d,3630ee24,ba0f7f86,134a7c6a,72dbc3df) -,S(f1bdcb49,43267948,fe1c9b7b,51afcc79,7027e4fe,f98c2175,d7d1b8de,770328b,271f57bb,a9249cd7,dc510173,5a2168c6,ea97b341,b44cacc5,4083d115,6de8e728) -,S(2815f09a,8f0e2dfa,d21f50c4,60b8f69d,3aad54d8,aaa99226,86050582,b954d912,dec68871,752d862b,32ffdf2b,482ce1c0,6a659bcd,3a2931a6,29bda260,cb3cbf35) -,S(622619ba,8b74a0d0,5f8fa899,aaddd272,c9e6d43c,49bb6708,367155ec,4907d0c2,aab9b1ad,10201d50,7bea05bb,5b20453b,6474154d,ebe3ddc0,c86535ad,7c701954) -,S(a0390604,a40611cc,6e36c81d,30cc3e75,d162e695,1ae0515c,75417744,c093b997,60428c28,8d32d229,7417b6d9,b1003522,8190a83,66cae58,f7887037,9fb99641) -,S(422c7d1e,b0498cc4,dbba0135,ababc80e,5416f187,11f0dff3,80f1e1dc,23bedf0e,9c47d3b7,eb5713dd,cbb9ec8a,60d931c6,3382452,a4c0861a,847a354b,ba57d9f1) -,S(982844d4,7f572298,afd6734d,98064369,d81e4851,4b176059,6d3a1e85,6f043f5d,9b86f6a7,678cb5f9,a4304f1a,a8d3458d,fa85e65a,ffc79da3,faa1fc8e,a2b7ed2f) -,S(993385f,a76b9373,422e4411,b9e8a85d,3ac0e09a,f9598570,63d50a8,67b67ed2,3e7a9a3b,222a66d2,f55fce7f,e33effbb,bce8cfc2,8991d8aa,376a8ce2,4e9b8460) -,S(15b05ee3,179d1dfa,61bfb0d0,1903f93a,f7e04f98,cfd40be3,2ec094d,1bd5a4a1,ed1301a1,451cecad,30e8fadd,801c9db5,5acfd697,3ed36621,2f2e3032,adddd939) -,S(6062aed5,7d6312fc,433bf7f4,9c10772e,829e294f,e7ad07db,177c75cc,9fe5e52e,96aa4495,c6eb07da,9a5a0e19,8771dce5,23a5d7ff,de314562,3b704f44,c4ffcd24) -,S(ef45dd6c,1213ac0a,5df18426,9491cb3e,bb5312d3,fb55c7f2,8351c98a,1ba564e3,91541d32,43e032f9,450f3605,cab238f2,703a9eea,8e429824,7a6ef63a,45540e68) -,S(a1e32dcb,c3a13a46,166ebb73,7e09041c,3487120a,6ec46987,6befb2a9,94f4a69a,ba88b7b1,8cdb2088,b5998b34,461b8a5,d85a57c6,31aa10f8,6ff808e6,3186e5ed) -,S(817e6c2,6d4ae706,f43ddd7a,cfa4eeed,6498ea2b,86aa661,9a0b45f4,e22ea33d,8aeed38,bccea5e3,4923b959,53bc9629,d9348442,4f33b06b,b02c882,25e47bf6) -,S(e734f5a7,736014fe,2ac9137f,d025f914,7574d67b,3696596,9f89b5e1,aeebf88d,74fe8220,7c83d3ba,ec54f032,f11f9309,9be25f53,565f0d60,5f2ab406,5287c997) -,S(87b2d307,414c314f,184eef07,6e9809d8,ea19c002,390b5047,38eb7bbe,ba1ae7d1,37f5c369,f5dd54b6,87729036,b88dbf37,45f33da,8c2bc9b2,64213468,f1c56841) -,S(dda23ad9,6c51604e,602b8e6e,9f08a67f,981bfa98,93194369,269c56b7,7986b772,6de02623,5ef973da,13e2577a,bbcde720,aa8fbe12,23c5288c,5724bbc0,228074a2) -,S(8d56a723,6adfe6a1,46182431,da5ff846,aee78931,27564954,f14172f5,27048fb9,c7cd6bfb,fdc51a83,252d4e4a,2c978cd7,67fa3809,521678cf,7dc5e514,eaf0b418) -,S(9da30ccf,f147de11,de528d14,863a4fcb,a2ef228f,506aee98,eabee895,eb618def,a4ab41eb,a16b4733,34a818f4,b6bd3c43,de4a9392,c15c9e19,a8b4e961,7fd4bbe7) -,S(e3339c3a,b14145e5,40c08544,eaa631c4,7be6c09e,563ec93d,2a05f219,f4afdf2e,fd586d7f,3a668a0b,f888083a,9ea84f48,43598417,f55dfea9,790ee89a,c412fed7) -,S(a6e08d07,66274337,f3b139a8,d6fc3f61,4dde9ef7,2e03fc52,45f7dfcb,1c0ab41e,d9620b61,116af945,708a610,c78f0b52,8abd97c0,21ee34fa,10d289cb,f3c06d4b) -,S(f8ffa0d3,b463fc5d,44e6eaad,caecaa85,8515bc4,69fe76e1,4ecdb25d,e503a040,e80dd6f8,934fa405,fd4d74b1,1da0d09c,dd723df,daf46221,796cd7e2,4bb83f1c) -,S(22a212a4,3c00408c,b4b94e2a,45a6a999,917c0fc7,aaa565d,c6f982cc,64b0d0d4,663d8ed0,3128ada4,f421853d,8ffd8201,1ec8b997,4b0d827c,ed318551,ff9930de) -,S(8d33b62,f162963a,f6636f18,ef33a83c,e9a17fb6,b1fc58de,6d271d,472a9d82,cf0092e6,60311726,e0856ff7,1893555b,625b117d,4698e4f3,f31611eb,21a56f5e) -,S(3bbf59cc,5b4aa31d,dfa0ce94,1853ff69,9db29cc7,a0021cb2,11ba28d0,1dc61d3f,d54beb79,d1edb94c,d6bd5ae7,11a3ff22,9f2baa0b,efaa139a,e4724ae3,624d8318) -,S(4cc9c2ed,3a7266ca,faffb517,d3ad4aea,2d4d877,d9b08433,a4fca2a3,691aec68,70ac52d6,1094da70,5f714f60,854a5656,8c25cb13,1502171,7bd4085e,8b489756) -,S(a997cf82,50d7ec36,125189bf,eb6b8631,cec31fdc,f156d34b,186f29c6,5d0b30cb,ca73d95b,93b43983,b2c51518,b4e419f8,415f14fc,b6356287,cd65d49f,92929d5e) -,S(5fae92aa,7c43ac60,b4bb4f90,ae2ac462,a6f88681,9aeada99,4d0694a3,a6dc1722,6b7ebdc4,dbe15dd0,9c1e4587,c7f297c1,74d5c933,6bc91511,f31e0cae,2e51b280) -,S(cf541216,323a9591,13561470,2b187b35,fffaff7d,8cf1993a,5144c7d4,aa836308,9d955733,feaab81c,4b03fe4d,25fe36a2,5075357c,b6ebf8dc,1822cee9,7f585f80) -,S(9c2c8607,bad80760,efb4ba73,442a359a,c1cb9b45,f81e54be,28f3f6f4,4699773e,7848812f,f3101eed,137b4dd1,4f503a42,9d71c157,449767c6,a5850204,869a9817) -,S(2f3bca36,fe504b7e,93f70176,2e65dacd,250b3789,541076ac,86352481,c896f77e,5af55f5d,b2e84dfa,38bdd0eb,fde7ea68,33471d28,add88dd2,a7e7c63f,dfe513a) -,S(f2fa3afc,fe4e5da,385f26d8,1848f801,7401b06f,652121d6,9468d2ee,f640260f,54cea12a,b4ced3ee,2ca351df,4310e96a,d3ca0d80,c3a3c86b,267c4620,bd0f69a2) -,S(82559cc9,ead1465f,a910b781,cb2a50ed,9a2b6ff5,d8513182,425b7dfd,983afa50,db5dd99e,242287bb,c94cd149,6e4aff70,7232e2bc,1fa4c440,5cd9f22c,fc4d239d) -,S(954079af,1494e324,fb707e7c,e9f1fc2a,751e194e,4ee058a6,e55e26d8,34901f5,2f90eb0f,43bfff96,c3b0f3a1,bd48c00b,85d3650e,52d1f614,ed65ce70,4fa19e99) -,S(c913a980,b1aca09a,19654428,6edfed20,dce31676,1fbff05c,1c05fa70,7eced342,17d2864e,df39460f,99b5b51c,91752c57,10ca7af9,a6e10c4e,c2b3e9e1,7317d3c1) -,S(815b7dfd,3b97ad9f,cf6ce427,ffe4a91f,2b541e2a,11305b17,2fd7b63b,82272db0,f0b958eb,fbf32959,dbc407bd,5290ca66,6f28bcec,2fa69d1a,7108a2ea,19d58484) -,S(7f7c1689,e93b7c77,20ab5b74,572e87b5,d2a907bd,624fb6ff,d5f29f3f,c64795d5,691a2f46,430c53c,375829fb,46ed4030,b5bc4dd6,70646523,45fbadbe,e6f8a1f9) -,S(8911275c,106e5a48,1c3dc5be,b9b42e2,3be8cf2a,5a76198e,e6749b24,bd9c5e7,747cb0c2,16d899c0,da5a8ed8,f279a650,f4537e7d,ca51bf56,b3ca8c43,92b5e99d) -,S(24cc2552,c907e757,9e85bf7f,fc868ebe,53e44b97,102b31f2,38678bb7,ad8c244a,a152808f,7d615060,ba9e78ae,720c2fca,a67772b7,fd99ed6,ffd5fbe7,ed114567) -,S(b0fc5873,68795dc8,55e3e19d,9236244a,812d1920,afef4c9,7f1e6c79,25395f85,f8b46879,5a0e40ba,2029538a,fb7cef58,9bde7b3f,fcc010a4,4ac962b0,afb8d7e4) -,S(cd6f4558,d634fc66,6dce566d,f94397f,d3ab9178,affd3707,55852679,adc6565f,d34d7be0,ea40586e,4f9007d7,4aca55e9,edb4b31d,8ad4f344,1f611a9d,94161b8a) -,S(fc5e8a3b,ada62f0b,6453f445,7dd4aff3,993005d6,de7b94d7,19fd487e,b88fb7a4,46041321,f7fed84d,2266d4a4,d86d836f,12f12296,d62ed296,6a7d5507,d6717130) -,S(dc72a540,55c962ed,90e64916,bdfaf6ea,aaaacbe2,fc180a7b,7e7bda98,f45488d9,e3b46394,41a2063e,59c4cb06,1a0a7e5a,a171fe39,812922f8,c04df63f,41c8e588) -,S(7d135c33,88bd5896,47f4cc3d,67fc7809,a7a4c530,e96fb5c,7dabe3b4,32a4fd90,79dd3834,8a61b642,9eb7a837,4e9c2176,95cff14a,3596a18d,19f84360,8aa0922e) -,S(7a56712d,b72ac3a6,353dad9a,15cfc9d2,7d9ff67e,9a35936a,e38e1c01,5980980f,6eda856b,9b5d4019,d0efb2f4,9f1af933,8969872c,126b2682,f56a8b08,97a83696) -,S(d3495480,25c7f966,d59b40d9,6ccb9831,2948c992,fcbe2f6a,7a7feb6a,946125a9,b346f8bb,532da4de,96908618,b0f85a10,fe9a87a8,d612e4ac,53bdbaf,9dfdb3c) -,S(22175a8b,d0a51763,d1818054,60951698,14af196c,df8648f5,29d27a9a,825e60b3,756d5713,81b5ce71,e23c0190,a1062fd0,645eddd1,7dc84c9b,b1c7d810,c13db63d) -,S(f557e381,37a1c6e0,a19e4207,4a1dd59b,17c5137d,97a58fc2,55d18be1,bf63877f,6cf0bb41,577ea3bb,7c9945d5,db33a862,3c1cce5e,d6fc13b9,b0739ea9,9af10381) -,S(8ddbadb9,c6a78978,2540d3e1,9ada3ed0,5ef35f45,a38be470,7083dff,75d501cd,75b4c5f9,51f70fb8,a89fec5,d52ea0b1,dbfc5709,3c1ee5eb,ff2ab0bf,f5854644) -,S(53f0892,cac79f48,2194dd9f,fc076305,a8ecdd4,977ac278,92e2d454,965a2aee,b39f7a9c,ecdd4ed6,d0fb1608,3b86d1af,68aa85b8,c733617e,5e97ecda,269ef97e) -,S(2712110,8fe28f55,c746525d,e7cfd4c2,f3a11b8e,3c6329db,a57a7b32,5a7edb40,cf6732b3,74681ab7,3448bad0,ae54b953,ee5d7bb2,5a8658d,3b366a78,dae5fa69) -,S(e7627b26,ff0448bb,cb45a538,2ff8ec9f,9376127a,b8425213,46e899b4,41cb5660,79842f72,e02820b1,e6b6843f,3a0c23dd,c0941ac2,b6fd30a4,39397ede,c78bc40d) -,S(37c48874,f07ce0c6,cf5be181,9ba31bfd,9a19aac,97b27011,1de59fcf,559fcb57,34dcc405,6a6dfa3f,283e0dd1,8b1722e,bad0e367,c30d9f1a,d552f394,9ce19b22) -,S(316868fa,33cf5544,1e9b9bc0,9f74fa1f,8daa9058,3fb8b3cf,8d339971,311eddfc,89fa5c82,9d9f4687,f7cb6b8f,ae20d6a8,cf872ded,a7f9b6e0,6e168c1e,45db4e73) -,S(d34a83f3,7b7673b9,6c8695f1,81ce837f,ce2f15b8,72664d3b,1a045c7a,bceadd44,e4f2cefd,59198808,15692950,19b9120b,495a44d3,4862323f,808b11b3,a8698081) -,S(687a48cd,4142060a,171a1efd,c41dce8f,8127ab64,ebd7c22c,7803f077,19168799,c082e152,41f7db05,ae6c1e15,e4ccc340,f4a7c8c2,cfd8bfb1,6bcd04e7,e635726f) -,S(70d2cd79,1d2d1418,9cf67e48,519aecb4,d58be2af,164d0605,2132517e,87f444e5,73b4c12b,edda1a70,89ae9db8,f105059a,2a558475,f5cf4796,1042c470,c9e190a7) -,S(2a6f2786,a191130e,dba1307f,f1bb0f61,c3d7b8ad,c02286f6,44871cc,170dd2c1,28a0c85b,8ec93fcd,1b9a0617,780da654,e5448475,a02a6222,f7065132,5ad64b2a) -,S(3f482e12,8d5bfc4e,d2f359cd,b4244db7,ec7edf92,f3fc5dde,5367d125,dde8c772,d41be140,cc4b4217,cdfaed4e,b09ce5d4,d3e95b52,ed6689ed,3f6dfde7,3c581cd4) -,S(96673e27,fb0f8a46,8fcc53de,12876045,77786d93,5afbca99,35545363,6614a5d7,f6a4eee7,1c4249c6,ef850090,59c12f6a,44adb8a9,cefe7a8c,ff2ac0a0,da28884f) -,S(be7a886e,499a9c2b,c05e5f64,77bcbb4f,26772e58,4565897,408eb36a,e25a9c58,24457eb7,802810f4,de64516f,24718b06,d61b0adc,bcf0d279,d883b2bb,45363a40) -,S(123985af,a3253837,e51f933f,8f25591a,823b2442,88cf8ba5,a0247ec9,94eecee4,a952096,21f7a9a4,3867c6a1,987dd661,1d3cf996,2aebfadc,dee0a5b8,6df196b7) -,S(75887ee8,c28bd2f6,a96086d9,aef71b7b,5a5fce50,80c3963,787089ed,e39b0214,47386fd9,a9216193,3bb500d9,a1ee8207,dc3edbc,17d3ccc7,32d9c90b,8995eb48) -,S(4f7642fb,12376864,29104657,2a2fffe5,2322df39,7cc097e8,f7a57816,e6709fe2,4f2ff70f,2e99354a,60cc5b2b,c3ef33d3,7e3e9ee7,16766018,e3a0ba39,efe5f971) -,S(8117d4fd,551c9ae7,4c9fdac4,5d87bb66,9bc7dc35,4b08de03,7c4a1378,734653b,13633743,d1ee8fd7,8482e3a,3a9e39e9,75b0f6a7,efb227fa,84feb897,693c5c10) -,S(8afabdf9,acd49723,d73c0deb,1016ddce,571abaa1,a71ae3e9,a20bcecc,ade5782b,2b66e3fa,ee86dde2,23dcc7b6,10ea8ed2,dd42124a,247b7937,9e190098,2580c71e) -,S(c4819cb5,b5af7aa2,895b81c9,31dc6bd1,de4a1434,daaa4fbf,abfca6d9,28c9965c,ae4db5d5,e1a09a03,67df8c9f,fbd2ae07,9f79ff96,410a9a5c,17229fe,5575c22d) -,S(dae02e8f,5d106f77,c8a1e1f5,4366daee,d312da83,1f86dce2,3e846e30,737d49f7,6d666cf4,73d269bf,aa7c3eac,4e5a2868,57df3661,c949b5ea,7f9a7a0d,11206bb8) -,S(a8762d34,c6f8317f,cba5c64c,68e25d55,e5bf7e4,5caadb65,a5468d2e,f9d779f0,6accd443,bb181cd4,591f8fca,210f9996,86460bcc,89dc06a0,2edd7bf3,d4b75533) -,S(bf503c35,fc8a0c55,fdf4149e,96b2d218,d29e4b9,1f703e7a,9b0d4da5,4153d99,7e1c09ab,a1437e02,a2be3d4d,7a444753,e475acd6,e3a42056,94e68ea3,cb7d1847) -,S(7898067,48cc0ad5,ab3a3449,ac82a1c7,d51f2b96,791ee038,dfceae58,ea0c5cc0,66b59634,96eb4a69,b87aa0da,2905449f,ffd2ae3f,ba1555f6,5c9b8ec0,e94ad922) -,S(25833d28,addd8172,c2a323d7,cf498482,732a0be2,c10d1895,8d097cc0,ff4c9a19,74708306,d01258d9,bac99a69,58ce1117,f245d6f1,4a1f92d0,dd48ca9a,4c7b7da6) -,S(6800bb8a,9dffe170,9ceac95d,7d066461,88c2cb65,6c09cd2e,717ec674,87ce1be3,d5228e3a,1e0bce22,c2d85b44,e670e78e,ffb1ec69,6c01a722,2cd1e62a,dc4e63d4) -,S(3d7d5874,42e4816d,af2f0897,dbb06cea,f6c673da,445a5342,c61a8793,420d107b,422b212c,93ab83e5,d6323ad0,35a55321,b7441835,b83f180f,c3803ccb,46fa4ba4) -,S(3c44084f,aeee2803,34db27ea,63339db3,9e8359b5,c9cc9a85,7ea49740,32d063e,36493b7f,1a732a87,db4703bd,61a76825,4a82846f,31d8920f,2cba7ecc,1d744491) -,S(cefffb5e,d26cf721,a51bfb2d,460b91a,a0b40a81,52073da2,cb75050d,f7fe8d19,b4e40e1,1eac7572,efefac2f,a97e5cb2,a0d042c,3ae8c541,e51be4bc,f6d33f4e) -,S(63add0db,5f5099a3,2f274c38,780cc215,bfd58753,144bd464,e75b0da2,dde97938,bbed5231,fe6d5b4,9679a13c,c3c6c382,5c300fb8,42b5eafb,13355c41,120c6848) -,S(ba5d1f34,63130cfc,425cc6db,dfe08329,4d7aef4d,cb207e3f,d1cefebc,7c791920,70df29d7,8030a8ba,56514df4,b6ecbd2f,ebfaa1b3,df7b23ea,ed16458f,f2f18786) -,S(7d363dd1,c6dd28da,94a7f850,ee753327,8b735dbf,f43e9456,67fc26e7,af75d6e1,46026468,2bd00bad,a5be02aa,5034e762,fe50d02d,6cb8dcdc,5aafa21e,423267da) -,S(e2dc0164,c9060646,904206ff,37f912ce,2d50458a,3ca186ee,fdda8d53,4184070,de5267d1,354d12ad,8d9a5930,443dbef9,65947f2a,5efa206e,146e7b1e,df7f5a2d) -,S(2e53caa6,35f0ad1c,7bc4c2ee,1e29b39a,972edbd0,7d3c0feb,9ab0d945,45815ee5,1bb33d23,ad85b572,130e93d2,fe366e49,8371c49b,b47ceebe,de3c1286,3f443b23) -,S(5dbefdc4,9fabdf50,e6bc1464,13d59940,cb36551e,5a6607bb,13213ffe,b56eba1,893fd0a6,1797abe2,fceb4054,c4f540a4,ed644ed3,13a2200b,e1d532db,44d0374) -,S(5ff207e4,2b52b004,6ab8bede,6bd26f5,316ae52c,d148965d,8a21e8d9,63374a2b,1b778704,daa94eb7,a36ad0e7,22a6d56e,c0b43c7b,a739985a,538bcc22,b9181bb4) -,S(da260b,ff4bfb8c,a54261ed,c96493d3,ffa90273,a55538dc,c9b237ec,e775fb3c,c7c744c1,dbe1cd19,20edbe3,c13f7631,1378140d,9ee64c3e,ab072401,86c067dc) -,S(b1985ca2,e7103268,f18d1063,c59d8d78,2250f450,c467d7b2,f4e41c28,1714421,16357630,3970159a,99a34c0f,e114b95c,f115d9d7,dc9b09ad,7c81d769,aeee6898) -,S(bf98e773,fe93f15a,ced03ac8,368e4276,1cf3821b,461cd844,2426d2d,cd1f7d7c,f4fe02f5,f45a9cbb,b67ef626,f239bad6,e5108c28,d783d70f,6bd889b8,6331185a) -,S(5dd657a9,ff99f15b,56c5143e,86ba7bc4,b0f34957,71d91805,71a3d003,ff008fa0,8da0b780,f644b14d,2b661b9b,484225b9,86b13038,a8a9bdf6,6999144a,4f5c212e) -,S(53b42d75,bccf2203,7252ee9d,25830f3e,36e7ed8d,8e1b6d4c,b2371e14,fd4fdba9,7791453a,dda2ca19,a775d684,9ee60c18,ca495808,6f8b56e5,1bf2b216,9690cd73) -,S(a3f43f6d,eb178109,cf4aaeed,a0666bec,481a1894,c25a4fc7,f4a87e82,680d63b2,d0331e73,7dc25db7,35625621,85073240,3a69a474,d5f78e54,93486b5b,3d1c067a) -,S(b83bea86,b07b217d,ddac9cde,9b42b334,c994cd1f,92beaa87,57a7e7cd,2c71b1eb,b68f8fd,66b45aa0,dd568458,73eb7829,1e613569,58345fba,7dcef9ee,dab957ca) -,S(16ce1de,573b3654,a0c00212,e878811b,25832f36,373da91b,9d9d7c89,d06ff12,264031fc,7441fe5d,4ce8ebc9,232d1837,7fa810a0,a0e19ba7,5ab16ae5,e93d5763) -,S(18fdf98e,93a7e380,8762e819,2b6e634e,f255b2ee,51c65b58,1ab799ff,52409e15,2d71afd6,c6298868,52ea0a1,943dbcc8,ff844ba3,80b177e8,62f92852,97868dad) -,S(3d5f8af4,ff89de18,866f596b,91300a32,a7aedcb2,a9423f4f,e364cf26,e2f53e96,46e9bc8c,ddc56d4d,ba25a2f6,e77a6a70,2e712496,7591725f,1d240e7f,9836548) -,S(69dc1e7c,11516a15,9edfa4bb,1afe0ea3,5be5b7a4,7695df8e,728a8dac,e2997db2,71be8ddd,d4c51c1d,5c13704,3aee6129,9541e929,799f7b6f,da08aee4,52f4ce8f) -,S(4e8278ed,ce9b340,1ddb1c3c,6b208539,164e1ad0,3adc082a,8d9dd5a0,9c63f737,13e6a5ea,7b2e8ebe,babd812f,2579b8bf,56b476ce,dd23c418,9be7b85a,940c5d79) -,S(91157569,7aed20df,771c1f4e,78b73dea,c89b2781,9b8a5ae7,5e2dc12,e6e7d148,e7114d60,218eb1bd,73074957,5b96fd10,50fa2d09,f37c0fe6,2887042,24ca1a28) -,S(3a37e743,bd2fe2f1,3f667abc,b6c03077,fd82722b,859d7bcc,ebeaf1bb,a6087d93,4192a6b7,eef51034,64040fb2,6b8d9928,21e321b8,cd611b4c,8d3e0186,646f5dad) -,S(d45b5787,9e4732ad,ad0996d5,879980a1,fc8dda5c,b628435e,96c3b44b,faf98f09,e4d4f5ac,1e4b039e,731143d7,60e2ef35,dc243097,d2e2382d,b86dc82d,eba0554a) -,S(ae5ff450,aa607a9b,bf4549d8,4d96adbc,6041cb0d,719793f9,2ec53b96,14522a00,2f061b20,e9bca3af,358e8d14,a04f1d82,97d1e1dd,a406d60a,d15727d0,66b2b8fa) -,S(befd3684,32785d19,7709ec42,e3b6407c,7a539b55,d97c8fe7,afd4f96f,d2050e17,65691153,b2efb4af,ebd2dae1,a50fd3aa,b648c7af,f5804d99,5270cc22,c02e151f) -,S(d13626c,bc00cd,36c776c7,8bdb17c8,18a2bc14,9612e0fc,7ab7888b,eab48382,ea4c3fc9,fe2238f7,1023ab83,fe0e09a1,dc167c0e,6aa05933,8f177cbd,241bdd45) -,S(9730fd42,fa9ffdc,414f90dd,ac790110,9619c01b,f43bfcab,e65a341e,2434435e,de61024,6152fb04,c997fd62,961209f9,44badeb3,6ea7774e,30e8c8a0,8bb0b496) -,S(a27e09ee,9dd4e34c,6a92f4be,aa1b8c0b,2a60b33e,99fa981d,afaac623,9f616d15,33e6d8f7,bcaaa24,b6008e44,377b4892,5f88e884,5fe73807,8cd4f405,a2747f14) -,S(d2dc7884,31e5a497,3905876d,bd6ceac7,8246c9d0,73d68872,f54685eb,5970763c,85f96d40,e31ecc47,dc07fea4,4856068d,15d2a999,735aeb3a,4959e4f9,9ecf5fc8) -,S(38fe7a6c,c401daba,981875a0,f0c2f528,30ce31d8,816a1d3d,47a3d96a,664a02f7,e9893a1a,87034596,9d95e644,313d9b65,5896a931,81d36f6c,7e390102,3cb28c74) -,S(f2d38ff,14100172,d117dff6,1522c61c,3a590eb7,ee9fca77,dc264e60,32291d78,94eb4046,ab31eda3,7593e705,792fdfee,2e3df8f3,655befa9,ef0ef392,4b02dab) -,S(9e23c290,94b6b8e7,4e112b11,69c5c775,4b690d0e,141b74f8,2988bd84,78d42021,e2528717,28fc8d9a,283bdfa3,a011d28a,f531f392,b5da6da7,1834a29f,203e747f) -,S(3054117c,33c15a,504156e0,97e9a0f7,d76be8a9,c1c88fba,e1d9d2c5,4e1c9185,998844e2,b73e9468,1b0b09d7,4ca48dc2,f29c6df5,f3c38f7f,b6846178,d4ccae2e) -,S(65d1e830,3421444b,7d5f8600,2c6de12c,16f15a88,504c6876,b9e94cfd,a206810a,71c9cca1,6e066545,b11e2c29,edbac8f4,8533ec41,1e331e15,a2bed53f,1b1878db) -,S(124b78b8,948c4374,7c5b32de,50cbb055,ebf9fe7c,56437573,40723180,131ec0dd,c0fefa74,970829d9,4c1314b3,64a8516e,3a3c7fb8,e1d49f06,b1b9c19f,be18ddd6) -,S(f6d81a5c,395ab698,28e5f1f7,84edc6f6,a55137b1,411baa28,615abdfc,36c18567,3a759acd,4b758dbe,79e22f4b,26774b88,40121768,f655664f,c3f9bbbc,91f564cd) -,S(e76bd19b,fe13dc17,ddd14619,da6b12c9,f2819514,6acef71a,9e7bc32a,7abbea8a,68cee27f,152177e3,afa7d47,903801cb,b20ba02a,c48fefd6,e23fc102,e6456bc7) -,S(7356c0d,ff8f26eb,7df215c5,cf923c4e,237fd7ad,cbe58f7f,d5c745be,6451a830,16a0d86f,ebcf42d2,e89e9a1a,803838d3,1dd7debc,527d49e4,a7db799c,e1eeee6) -,S(b8d00a56,43fdc57b,dd949193,c5df30d,8ecf5b4d,8b3a13e2,64ba3ef7,c8bfacc9,f05acf53,9343641c,3feac336,28e9b08b,9a4e3c49,94c029aa,470fde03,d5d8cf8a) -,S(f555e29d,4dd3e0eb,d03f3866,596be43c,677d1ac4,1a1a3a8,1936ca6c,89618880,171d88d1,9abf05a6,981eddea,8f030e53,117a2e2a,97c2f352,255038fe,32ecf95a) -,S(172e6167,6e7755f3,c6a59c40,97a8a870,cdc09d73,2064d24c,3db8ada,7ca50ec1,7c1e58e0,38f322d3,e147b3db,e9b8f311,135d688a,98458da9,f6f8a6d5,4d4e2a96) -,S(f8f5fee7,d4e8eb51,92cb7ad3,9ee26cfb,44724b7b,f9c74fcd,61f95e3a,f33fabc5,607fd05e,361bfd66,519b5e11,d00d22af,8b0ce85c,11b16cd8,eaba71e1,2ebe6bbf) -,S(6fc770f3,f6169350,bb8b247d,16088031,4348ef73,cee49e5,c0f56a19,d2d66491,47708f10,80e755f1,2b1b0d9b,3439312b,dca07d85,fe94fda8,414dbdc6,ed9353de) -,S(2b8c0b49,94d3f78,79776d8f,bd2980c8,7840df15,82427cc4,f07ac806,eb7f7e3,3a335552,ccb38312,92a71376,9c7994e4,19a7919d,b776ce6c,db2ff092,92e4d798) -,S(e473c99b,dffad22b,72b6fcb0,d741179e,afb78aa0,de4b5d42,dd19d7d7,72ab1a60,2d0f795c,61ed1ac8,b5691d5e,9d52b19a,42c368fb,9d0787fa,8ef3b275,2a3d9d26) -,S(f389dc2d,b76a47af,f9d7a380,ab49274b,1a40c4f7,970bfa63,729da698,b4afdc4e,b15c2100,b63f7f5f,911a6474,25866d79,5a57dd97,74c21cd1,4907dec0,f5f3afab) -,S(df6e3625,8fdefe31,dffa19ff,2416f8b4,9fbc09c5,e86569e4,4b7330fa,56cb6e1c,4b5fedbe,835f0b8f,ae20f627,c8e74f41,a5443c1,a764c466,65f673f9,f62dfc7b) -,S(27e40da1,a5d7cabc,ce586e33,a4ace757,da972cf6,17c3781f,3fb0e0c4,e6f0a70e,ffc4b339,9cc0b701,36d871ea,a7c3a6ab,fa9dc92,72625fb5,b8bde8d8,be55904d) -,S(71b6f20e,e558ac12,829362ae,53900a59,ae29cc70,77dd1001,d9d7eae,36b95618,e765adc,1125219b,316beb88,4c0434eb,a6f62499,b8b2d217,c209c7cd,622d0597) -,S(535d5fc6,1eef1a92,50ceaef8,e09e1797,8debd360,8b03f72c,bfe265a2,633332e2,f8453dc2,4ad1ef7b,819d4329,a4752757,26c98e55,65440cc5,b5d509d8,61c98a38) -,S(d1e2222a,26817cd3,a537f2fb,7437ce06,ce9fa651,9d3c1967,71aac21b,97de68bd,a131cb69,cbd27e62,cb65ab48,a7f3035f,a78ef40c,6c42e94e,da326ccd,2b452849) -,S(5aba9590,2b5062c1,59b9639e,f08912b8,e7eacda9,759a4e98,b0e21d96,c2597b07,896a74fe,e2596e46,1e93f4ca,178646cb,4bc5454,227a2dce,1bb5d532,e558b334) -,S(9f07bed8,4449bf9a,815a546e,ffcbd0af,f22c9016,188d15ad,7c353e2e,5cf84343,6fa14d01,ba16dd07,15f3e68,d57738f7,1cb56d95,61eb84cb,ad63bbd2,d9ba439b) -,S(80a1920b,14723439,cc2090b7,189f96e0,20e6eba5,5f8964ad,2f0be013,b4925515,fdb63791,6d074376,8e32f983,f2ff1754,43136323,50b98674,2ccb9ae2,7997a020) -,S(dbb37c16,202dfd9e,914f2922,e8930789,a70d4de0,9fe7eb25,7d9a2b83,aec2b4c2,f6bcb8a,2c7bfa20,491d3fff,bd36e82d,91a7228,9e4fb6f8,9e167803,a17b7932) -,S(f03035f2,f0ad31ac,59e64a6c,f46e9ee2,a2243ee7,de5ccb0d,cb30083,97551b4c,1a1aacb9,798651c1,2bdc6ce7,4146e259,4263474e,d7b9d42d,78026331,60748722) -,S(1886fa45,e7447e89,b0873362,605beafc,4e05965e,53fabe41,41e1c42,4fb234d5,eb5374d,a4a198cd,d9027311,6b4331ed,f0f6a7a2,fc52aa44,8a9274b9,ee3d7743) -,S(46a262a2,5b76baf8,ae0ba3f4,ed8f86fe,e4854272,cbd0ed41,313c4e0a,357471b4,c08ee494,66d7dc12,a8e08880,732574e6,f6fedbf2,71d6dc37,eec3c324,33d8070e) -,S(d521c6c4,a0db2668,5a36b61c,b73d3504,ea7b7488,e3d75410,494e89e4,ab404d37,41f334e7,6a28cb9e,25e6efd4,fe3eee2d,17480189,b921d726,aa027b3f,75f94bfa) -,S(8f44a4e3,c18d714f,62054e54,6e9ca86e,818fcf39,fdde40c8,3044ddbe,be3b951f,210ec152,f8c90d7b,8486d1f9,c5c49a48,68249795,bf7d0171,34d9573a,d5b22aaf) -,S(d5a74098,eb20aaf7,b664fb8d,63e08b0,430733f1,466552db,417ec648,36a31dd7,7eedeaca,97f1c85a,98496159,eb024564,1c8ef0dc,21c31ff8,9d06012a,3387647e) -,S(d2a63a99,d6ab9e57,a2a6d39d,3738c3bc,94505332,2a34d3d2,4cabd1ce,5111bb08,e50f6c3e,796ac830,e276fac9,ab6738b4,722fc87,880f2e93,7417198d,9c6c1323) -,S(a1b826f2,1f7abe38,c622b93a,7510114d,dffe4cb6,d3fe0627,dcc0465c,bc82ad9a,c9cec051,a253ab24,a8507b07,d24ee4a,c1d5a5c7,33f0c3d5,611e8a9a,e4aa9667) -,S(40719ba6,89926b5b,ca99a4,161a1bc,d999d40,2311fc5b,e2f5260a,c3c10208,9edb353a,73e9fdad,96ca6b77,b467dd9,c7d6d2c8,e041d8f2,19448ea4,c603bcd0) -,S(c0ee8dda,80fed10,721e7cd8,9dbd237,216f4e84,bb8f7138,11f8ca16,1e3a0977,6a786e53,2a0f49cf,eabf0338,1d64de56,1a1973c9,36d6a5ca,4aaf4cba,b8fbe1e7) -,S(9c75860,ecdeaf1b,c598a530,48a22158,8099afbe,20cb08c1,3afbb133,b2681809,d7019eb3,5fb61aee,56a1afaf,2675a028,b8735dcc,b3f5d93b,c3e29672,9203321b) -,S(e39df640,6dbf2584,fecea5bf,aae78b5d,bca93ef0,9054c754,d8b235c2,c5463657,33ab2fce,3a2e3e7d,e2ab230b,e69bcb7a,4d71c87e,a1ff5d34,eb8b78f2,d5c61a55) -,S(22480e,4a7cadd0,d17a418a,78074f80,c4731ce5,d9f1268b,1ca50204,1ff8282a,993591da,11ea4445,8ccf8bc,2cd55fae,69e96a77,89d006dd,b85a22ae,85316200) -,S(c613fa66,231d38b3,359c3b94,132a2337,e2a8c608,3c88b41e,58434c19,48a6a1ca,8087377b,c3d6ca30,8c932dc6,ff82430f,3fce21c0,1a8b8b6,c28bab78,d3ddab43) -,S(c0a94837,c2fb86ad,ca791fb,bb0838c1,3bb0c981,e23c4ff7,94dfa5fa,c663e5,1f81050e,d21fcd5a,471657fe,abe6fccf,a391f1e1,9a88c143,4644bfb5,e1f69f9e) -,S(87ab257a,cc2296af,d921bebc,8e52fab1,c9c21f08,ae09faab,18858a06,1e408ccf,d5dd88e7,89d2f2d4,3773854f,ca980411,3dd69475,a56864d,3c869205,d682027c) -,S(10d14c28,cf44c5d8,fbf5caf6,b307f6f,ee203968,eea1be3e,b3697515,2edf45b6,46926a1e,dd4f79ad,74fd506e,4443375,23ec76fa,e09d216d,3ef3ed4c,73b635fa) -,S(2eb78fea,63035a3d,db64149b,612832b0,c9ab7880,539c67e9,d722e252,f7e23166,4f72ef76,d3dd59c0,a4e1be46,6ca5a3ce,fd84d207,f7d671b,240fd41b,20e72af3) -,S(14d8ab11,402af341,dc5cbb6e,1116b858,14decf11,e6761b09,31b449b0,20b6f56d,91bf8c4d,cc717657,990e0e3b,3558a01f,ebbe534e,897d1204,8a7d978c,3a1d735d) -,S(cebc042f,2e7bd361,934da5e6,dd2dc8a,9e73537f,5d5e3e46,3a88bcc3,ff6d5552,baa841c8,5e0a7287,b1f16c89,8ef03f22,3097e92c,44952c32,45f2fab1,dcd988c5) -,S(4f28e546,ef539c7e,8f33191b,897b7245,8f48a01d,79f65b8e,a8f672f7,d0ab027b,b1c1db0d,55be796d,2b415259,89088a7,d86c41f8,cd8ccdff,2bda49f2,407123d5) -,S(c4d31178,b73cf9ab,b0e1d554,a2cf93db,ed9a7b9e,8f49c9c5,4d63c815,6e111505,f5e4528,7089cd96,3118e279,bfc6661c,1e77ab67,b81a71bb,4ec14fe0,ef0c13f) -,S(8e260505,bf045c43,f3fd972e,d4189725,a4db0774,52f94eb9,51e42eb5,6131f0f0,4afee681,c6069893,5ce21991,208457b0,11548d97,9a33a0be,cf3c840f,77c4b4d8) -,S(982818ce,69b4c6f7,631daac,868af6a6,79fa6631,8c9da2c4,bac994ba,f9c95d81,f5b13c91,e7593e5b,69c85957,6398b186,8c503b6c,25179270,7e602f52,f30ca9c9) -,S(75c2f2b3,53720779,8737488d,16a5ca6e,dade382b,78f2b2b3,226fd5ed,6ac6c855,95aec19f,b97734cb,8426e530,afda15e4,c3c3dedb,2aaa24f,7ca73b4b,af475960) -,S(606ed5f1,8e4dc1e5,3b6f5ae3,896433c2,a904cb84,1ea021fb,84537f6a,9dd45ed,3165cf75,26f277f5,b9bf22e7,36291513,10158d63,b97b7c88,d49d88d2,d63dde9d) -,S(a33e07b,c2934f5e,f02ae143,6b3ef5ae,d2d633f4,2b40e35b,d365fe2e,b8c72d51,e93cfd7d,f2e98817,9eb9c348,73530504,bc5cd8e5,d8393f0e,844073ee,df6d6511) -,S(5ee1d077,735a4a18,533b36d1,eb484f14,98b220eb,cd41746,b0947403,d6b4644e,7d4e1233,46a6ba1d,8a862514,4d4bc5be,72e23d,f25287c7,3512817d,e632f8ef) -,S(7485b837,2bb28a8f,d496f6a0,33b92ba5,96202661,8adef933,d6aadc56,55765b0b,a58defb8,deb4445d,80016c9f,5c04c2f6,e06986c8,cc95da94,3105d8fb,d0fe84ed) -,S(3a321f94,2268584c,cac5d8ce,5d6011b1,22169e73,d9093b2c,e3e0bdf9,ad680d21,99fb13c0,ecb6c544,1347a4fb,842a7269,1492219,f9bb7c25,1916f837,7d4e2cc0) -,S(c115a2e8,265c6005,10bf7108,ee30bee1,77893d5b,ab0a8cc1,754810c3,3f112585,e2f0a636,5836a24c,7a5c6997,45022e8d,e0b88afd,37737c84,d1ae437d,eaf0b3d3) -,S(d8895b97,cd390ca2,cf8e6093,c125541,1602fd98,97074a8e,aa11bd3f,5b0f3c1e,af8c594b,bd2308e0,12a632b3,1d05a25e,23247f75,6d7a22f6,fcf48cde,28056ad) -,S(4ad1fd48,e77fe497,b4a15e7e,869377bb,163d760e,105e46a9,a5477d69,fa944eb5,a96cce4f,e2f5f590,17af2359,1dcbda3,b640271e,95290d59,1fdcbd8d,ecf39703) -,S(62ffcf4b,7ce6c5cb,76766893,bd0a6f2a,e33ef821,d953c001,51c4be3e,67f2cd8b,d6b1d025,152db954,968ea1bb,dd2a89db,16103f55,47cdd042,9b7380f7,c4c985f8) -,S(e71343c3,cec5e49f,60fea970,6d256a4d,ba499e86,6f9ab33d,6045a1be,cac40a,ee1fe3df,df226027,78228bba,91afd126,a96fc10b,f5d2cad1,26091119,3a92b426) -,S(31766ef2,f3531ead,2c7bbaa3,279e81e0,b040182,ab78065f,d193061,2792035b,87b93ca8,91151ee9,775669bd,df2e5bf7,9f728d52,efabf584,352ba4db,8cd6f6d7) -,S(1e8764f1,982a97d8,b65a0a60,53a2fb5d,39f1221e,dd4f532,b007b2c8,c52d39f,8ed84e0a,de68b789,5ecf8c07,80ba0b26,53faeb49,3d23a453,cc23987a,b51f3a18) -,S(e249cd91,4e35f97c,92a07f4d,6f9961bc,d7f6efe5,ccdfd44,cb3bb698,9939fe43,9ee2fb47,4abdac66,5bb0178f,d8ff3bef,6381a90d,bfab05e4,a9e5566c,cc362ffd) -,S(b9a28764,d21db971,f7cb0c1e,87c9db64,ee6a1acc,485a02e4,5d5ffafe,ea1012b9,1b55a989,43ff4fb,25db6aa1,12d5c459,b1ee0fa3,aea913cc,54878682,f625e882) -,S(5d042803,9f8c37b4,dc92a9ba,43bf7213,971488df,be699901,31820bda,c0b6ff03,1ffd5348,88796c6c,a631c3a1,4773f89a,ea6d5914,bcdf27c,38949147,cab8ac1d) -,S(6d817b42,52986e2e,8ecb908e,99011265,df0cff59,61a82b2c,baf0c61e,c8b22326,55cac99a,d6a70b96,5559af1f,c5b67469,5d653662,bce7594e,22916fa,7c4b826c) -,S(9b069431,297f0d35,91451039,df8a382c,1eba93c2,f62f4e98,90e54559,39916ae8,70bf9138,a04b9f14,2841a2e6,bdc3600f,1b22c81c,ba27f308,19a763b6,e64fef71) -,S(dbf5e41e,d83110a0,5dce4bbb,bee05f0b,f9700ef8,273b4bbd,57099bc9,460050f6,e3e8f5e1,697b05b1,23632b89,28c3b34a,6cf1e6f,327b4252,c3009046,c8406404) -,S(c8ef12ee,22aaefbe,9ca024bf,ba8fd744,d7c5d489,663cde66,a3ff1dee,8174ef33,db64c2c,db21415,fc552968,fbef01ed,131db2f0,1ec8372d,1b9da98f,4792e8e5) -,S(3d086c8f,af84b66d,bb9212f1,512663b1,793d6893,23f45af,9bdd17ba,fed8d7ce,2d6a47fa,9e1b6c20,a2cf30dd,a99547a,b9ab9c13,5ef86ebc,280ac62d,2ce7847c) -,S(e173d58,714db8bc,cfff3ab8,8cf1be0b,547e03f9,db60c97b,ba5a6735,cbf4bf4a,44b8f991,6764f393,68b36b56,9033e304,7fe90662,70758fb6,85cc3f6d,e31b2fc) -,S(31ef8faa,90826125,66e739cf,299de928,68c6027,b882978e,f72d014c,4aa4f379,9fb9e021,fafac237,8d21caf,f1262d7f,bd9b8333,eaab0fe8,8a3499b3,d153a2e5) -,S(5e112e52,2997b67e,146b998d,781bc528,7e2ad47c,b2c5863d,eccb0873,fa088b3b,19cf3f06,d3c1fdeb,8147e074,a42fe178,c0b14135,2dda5274,50a7d5ce,58d3d441) -,S(9ba2cddb,c1a5153f,89e9144,e862acfe,c624095b,8cf8b7a5,b15edd6e,c7b70eae,f032469b,9527911a,92dcff6b,5847fbb8,9f4ce42e,f20b40d4,80b3a58c,72fc805b) -,S(9ff7e46a,4e2c6e9a,d5843f4c,c5e112c6,557babe,723203de,d75be7eb,179e814,ec890ac0,2ece651a,6614bab2,1e4944a7,d248c886,bebb33c3,36c28df0,69be91ff) -,S(2a13752a,1aea6e21,d25ea21d,b644ab0b,fb84b130,8d3f2083,be26098f,fc4978f1,18f4936e,65ab66db,11bf53e5,7eb7d114,4820fd01,ed827f96,652514fc,d8ce910f) -,S(a0647c4f,2b4f271,97f3fbc3,bd81bc7f,f72d964c,1bcc131e,caf9bda6,57b356d7,5e023102,9a8eafe8,9466181a,80440196,e850390f,d42dfbc2,1d3fbf6d,6373a56c) -,S(6abaff96,aeaca928,ba9a0503,dcff7a51,420feffc,33b1ad53,b1a7bd57,8c641ede,ab59c03f,7ad47f73,df424882,dc3ac2bc,dc2ae6ed,3eaae48e,b807b010,98dc0de2) -,S(442abb18,54161ba2,47fd366e,52d40d56,65293573,c339aa2b,28dc67c6,70f4ee99,c3f44b44,d13ee3ed,4ffe5188,c5134d60,a28806b0,687b5652,99924655,342a5898) -,S(9f54f23b,45f632c1,f05245f6,c5d1c433,9e18671f,da494eb4,3bd22be7,b1610096,25c9e532,1a5563f1,f47a1e4c,99d6def8,541601ac,8420de96,190157ed,aa17445) -,S(50296c0c,185abbc4,1c86f578,8dad10f2,7f76074e,24e931db,53944b48,6ddee613,81a02b32,b1edd539,37ee1c78,ab630f2b,45336e16,cfc560f0,adeb464,fb71b9f8) -,S(39c2d099,e2892b2b,1b6abb1,a198305c,ed59d94,f7022cd6,d521b510,9a8fc219,8900f6e6,3fe1a7c7,27728b92,aea4d70c,1316570f,edba940c,e626e94e,f03dddff) -,S(3581e30b,17067e44,664201ba,d7a6ada3,e0648516,260b760f,b406dc48,11c9d0f4,c8bac129,83e49250,bc478ee5,fcfc0660,37d68f9f,fda1acc3,6861743e,d7a794b5) -,S(72b67dfe,d341824b,9fa09057,b8362d1,38287eac,7292610,1169e41f,19dce477,be527b0e,52ce07a6,99065bbd,ebd360fb,72c6dc77,88030aa9,45fbbabe,7f038524) -,S(805af91,4a973e36,43712cd4,4a1da4a8,3d1237e5,9c991387,17175aec,4a8667c4,f6a7beea,205810ff,5d1f0e8f,5818854a,bb730c7a,1ddf02c0,968b1b05,92ed8a15) -,S(44794289,4b297a87,e3cdeead,5cb2dc42,9fdeeed5,b8038189,331874ac,88e67536,d67efdbe,8d7ab8e8,1e25c340,77687b94,d22d8ec,b89d7f5d,46ca212f,abcc1b5) -,S(b73347c9,baa967a7,5e5c8ac3,14f3c6cf,275cc893,72b26bee,731693cb,48d36df4,307f8fa1,98f1ba57,7ba330d5,816cb8de,d9ec3f13,6bec0586,53c64675,753f1542) -,S(ec6d499a,efd540e9,357f100,4a136049,d1f7df5a,d99c44c4,6e3ed416,9e40acb6,21e8082c,df4fa2a8,38327e80,aac15ee4,40549109,aaf6ea01,ccbfb95d,3f7a47c4) -,S(7607b7ff,8bd8369a,67d22545,c40a1588,aa2e50c1,b5be6115,cbb8794e,2085f283,6c4a9aa2,1dd2ad4f,7d6c4f02,23885803,ac3b06fa,6c0772ec,bfb610b6,a1d25ea5) -,S(dec4b7ae,42e8a25,2c414458,d4e0d7fa,4bf4d0,c9432754,13d3b770,8fb53839,bc54d902,6d035b64,35796475,67805bdf,af6cdda4,d0177206,384c4ca9,8edb5898) -,S(a7be1017,82bf48e8,37c2e0ec,821e37b3,eab03607,36561152,a95a06a7,fbb7ae2b,dfd27057,dfaae0a9,b9523a9e,dc28a2bc,3631e84d,5fdf8c3d,e1e65055,805fe0bb) -,S(cb398b20,29e55994,741b87cb,592e9099,926229a,aea60bd6,30eaa528,726a04a7,263e89b5,85475a8a,50723568,d3328fdf,56c8fa8a,f0f796fe,7b4d2fc5,9aafe2fc) -,S(438a6d60,c289dab2,e8933153,5c2e09b7,a677cfcc,a605ea72,8815bdd2,615c852c,109ed19a,51e01f3b,a9dbea30,f652676b,b3a8afd3,5ab5178c,ae557793,13025f) -,S(4db8d4d,882fe513,e5738be2,347a05e9,2c97816c,b39339b,adeef99,7b682e50,88280370,d13551a8,a9803a28,c56bac47,70feb07f,56a1a0eb,d132262a,f1ea574f) -,S(ae2ad953,bf13c4c5,c3fd5ba3,389323fc,260de722,e36bdbae,6db77b2,1c0df210,a5866bb1,7580958,df07c171,80606be1,25b3ee73,9c3bae92,8fa35e9d,8efc7364) -,S(85b3809a,3f772b20,dc526b9c,19de8cd4,9c2d9814,df4a9b60,1aadd016,64c66c9d,984a8061,2ce95364,b9819440,551ab1b6,4028f61d,3028b725,74dfbeb6,8c174cd8) -,S(7e2ddaec,e443396a,7c7eede7,ad96c2b,63faaef1,66109949,e7431b06,309259e4,3aeb7f92,14fd37f2,aeec1921,e64e7a8f,e6a4c704,dfbbaf62,779d0eb3,3b1e81cd) -,S(4565a74,6cd1d26e,962bebb4,447985ed,7b1622f3,faade84,1291d694,17c3ea84,7215d7b9,6362fcd2,320c0c29,e0b304d0,ab174103,bfd372ef,e6e4534c,64ff3708) -,S(aa8c5a11,712aa04d,a870bad1,606c9549,bbf676d3,1ea5b260,27bd1055,ed56f996,11ec28a5,a7435436,3d302f23,24eba092,68028664,f0ebd323,cb7bc587,7d92aac5) -,S(d9d5c0d4,b5a3305c,9f057dc9,8ecf7482,f6d825e4,69a641f2,caff9180,b7096e0d,d2b0eae9,cdf57651,bd296ad2,f4403e77,d643db66,fadd7a84,27a150f3,6d547ec) -,S(2ab2e7ea,1e1bf61a,8bedaa4f,e8fe3a7a,db66c25,ed1b7ebc,536efc7f,8de22777,28806bd1,fc7dca1b,a0cdc177,908e0588,605f8c1e,e76cbc07,ea05b6ad,80c0e5) -,S(2da97d42,a9d064d7,38bc7fc2,f2db39a9,588d57f9,8094903d,cdaf5054,238c1568,fff93946,e789b902,8694ff95,a68a7fb2,981ca0d5,d2b6de3a,b3112381,b8360f1a) -,S(470fd28f,31418f2d,70367e4e,961da5cd,af8d0255,5bf6bcf5,e7db8967,6dbb174c,59a49444,2a250264,3faf843a,cd242640,e3622df9,da6bb1cc,6c956b7e,5a26078b) -,S(e41bbdd4,6b78fad7,ee62c33,9664fbc7,e884f88e,dc184e12,715e8368,160a7ef5,40252593,7979b92c,f72bfa7d,b3f378f0,cb4de758,a6348c7b,2b1d73d,57ac9faf) -,S(9761799a,7e155a4d,e6aefab,963b23fb,1f17d8a9,cc5f8c64,6d4dd638,2359c553,493bb00,3ab38aab,cb4d4491,b6b9e8ec,ef068c9b,933fbb32,6e0e1c75,ca44bf1c) -,S(d59fe2e0,5fcdcc2f,dcc22cb,b9220051,2c936bc8,2205f5df,75267a5d,b45b1245,68af556f,949df3fb,d8299f05,f5e85874,57d109bb,4d395634,89d3ac77,3d4b7b2e) -,S(f8bf168b,8a03f3c4,8e7568ab,ef613bf9,3f515f71,93a24b62,827455a6,c6bdf142,434f350e,8eeba6f6,d8f07137,a33199b8,88907744,eb547384,dcd96aad,5f9f3911) -,S(65298ff,636b442c,8c45e748,c3cd2d1b,94770ff3,3bde1d63,21135bc0,89ed81d9,d0aca445,cf460f5f,47090202,2c84fe1d,ac0a81e0,b7458e4c,9b21dc34,8c223ceb) -,S(d1ac0d0e,25dd02d6,fea02b6c,c98f4b17,38046416,93258208,f04a81d3,450aeaa5,be491f07,1833efce,56197dd4,d3471eba,2a23491d,f09a87f9,8a4ff14,257d1dda) -,S(be876d37,fc1605e9,ea0923c4,e53497a3,8d51190b,dfc3dbbb,3191a483,949cae1a,8499ad31,ca5acd99,4a98caa9,2a91a321,5fd1f1f6,cd70c463,afb91673,ab6b3a72) -,S(7c440cd,aff0d8da,6fb5e2c8,fe27a301,c2906a63,7d9b1bf2,db848f13,175de738,7dd6cf71,cb013a8e,9494cca6,b418fb,e99e9c80,3ff34d35,e586fe25,8ffc4fef) -,S(25086ee5,f0037c83,e38abbaa,e0e3356f,c49020d6,f9006edb,235937a0,4d7074fb,35c21eff,8cb888db,d3271a5c,4dc1db52,2072e58d,974af68b,4d6cecd5,d13e582c) -,S(b1a7584b,6f43a593,363d6e62,edade636,55ffc711,48e6c9b4,2915d0d5,ebf4dbe9,f418f23a,9dde8808,59816098,ea06d2e4,dbad3385,737b7bff,a1b339e,1b556718) -,S(87e1c0c6,aece59e9,1118829d,ba8e0271,db30409f,c08dd790,4296b91,43fb7aae,4694c5cc,176cf309,e4bd4935,b88e2fb0,e7e1b63c,28c5bab5,d3356733,184ef152) -,S(19f43d3f,4bf0f2b1,9a157f3,3f71c5a1,20e2135,3187b508,e568dc5d,8131a2ea,3ff130d9,835e0eab,2744cdb2,5607fa63,edcf9648,d910e25f,b885ba9f,b340860) -,S(a7f9239c,5e8e371d,7d175c8b,120816be,2e543d89,a22c3f7c,5478ae1a,14f8f6b8,75711a87,561fc767,93510d5,47abe6f1,678d0cd7,335e7bbf,b87abbc2,cc3089e4) -,S(9f3598e8,f80cee53,969a79a6,d3b655c0,66283a8e,f2c5d7b7,8ce89e67,5d06446d,d9cbf50d,c2aedfd4,51fcd93a,46245bc0,772e9f9d,fe5a25f6,3af027b2,ea1edf79) -,S(cc00a72a,66dfc8a9,e7a4edd6,699764ca,c15140e7,216daa59,cadf0edf,d1e3267f,91b10836,c8ebd031,2f72cf2c,cf26c89e,1489c100,c72a04cc,71c0d08,45c27d94) -,S(2dc7758d,b176a48f,f3117aa9,671f7b6b,f0b2128a,4bc60fc3,f907eb1f,d20ff347,afc82704,39787ab6,bec0d4f0,7b7f2896,43073cfb,65e9d3ce,db8ff7b,791f2f59) -,S(2502f7f5,8dba7c37,bc4637ab,8c77c047,700dea3f,5b760ec7,9b68121,9cee008e,f6fea3d6,4e776f5c,cd293dd9,4109d6f0,1e55c039,c30438eb,6e626489,c92f078b) -,S(70d39d43,d7f2092,53967479,de620ed2,bcf963de,6ceae3b1,a80fd275,1801382,fef8bea6,45807be0,e1c5c3e2,4d391d8,bf0a6b33,564749d1,4fcf4ef,a8aa7133) -,S(a09962fe,9a934004,bc31f92f,526ff444,da7889e1,79453a55,b0fee769,34c69c2,dd717079,8cf19b8,1f55fdcf,86cd3755,f708256e,694fdaf5,f929c967,eff687b5) -,S(355a2555,4590dcf2,84ca548f,9ec9f40b,22482773,cf122a40,25ed416b,9d29c692,549ed0bf,db861bb7,4684ebef,7d70ac56,3703997e,c59b1f86,bb4b5dfa,574a2f64) -,S(4c145d2c,a165a5a8,b66f7fdf,c16bcd5c,c22304f2,f0ec3145,9b9fb0fc,797c9b9a,7cc14054,948caa4f,be04b54f,1b60a51d,cc482fc8,c94825f7,8de4f4a9,a63f8d5e) -,S(b5ac199b,fa591300,6d635fc6,86d87cb2,52c5c67a,6b897a09,bee578f4,9c57f8f3,41e164ae,d3d967da,94f0cd06,91cb3ec0,79c5712c,279b3a8a,d75affda,2879b234) -,S(ad619913,f00f620,38321c3,59931a9e,fd26941a,aa02a812,8d9f3bf4,8818185,d7b5a033,9e4b8ab2,bf66a597,45c0b496,b5825886,9084d306,660670f3,a9de912) -,S(f8314cdf,d7659ce,e8377abe,f4c80b00,9c99c1b2,f2bee37d,a726c6d2,a1deea90,db5a45c9,a7ea22cb,dba3a784,131ee81c,2a1d9edf,d9ccb9f9,6fc93d35,a332eab7) -,S(1fe1bfca,5df9c482,68e88661,89e238e3,7915957b,aa1e0c3e,af317d12,c2f84650,dbe03060,745396b6,fb22d6cf,a6b27329,3b3ed08b,a24ddb38,8942199a,765d7414) -,S(c414da43,814bcc43,31269d58,1c0a8c14,9e304f5c,13614a89,7f414725,9ed39070,ca194f90,dac3f722,6090b94a,3b94db7c,5c68931c,7461619d,8b912692,4fd90a4c) -,S(81a098c3,d1ebf427,69f621b8,3eced558,9dc0faaf,24206f97,480e40d1,25faba3,fffac91a,3b729698,b0b26f8a,e6391b1c,8f8327f4,7978b011,d7d1cebb,6b0ad8bc) -,S(f99441dd,e4332003,b6421463,b4bf6595,172121d3,f000763b,a40cccdf,be2cf439,231fa7c3,fffcee74,bd111f18,3689062e,1b6b366b,2fe14440,2061de8e,4688b3b9) -,S(2f930e6d,e3586768,792e565c,211e1abf,99e05fe8,79c01083,3e6e5121,7abdcc60,2d51a776,209a3da9,ca4dda22,7beea48,a93a90db,b51f0721,2864f36,a56424e7) -,S(9f8e96d5,99fd07bb,e9e0010f,90802d25,4b30e359,bf0fdcaa,d6e782da,62c6d25e,baeaf150,de04c7ae,d8d34278,aba6eeb4,9b3f213b,fd56585d,41890632,d6b64e02) -,S(57f186f6,fa5f4aee,e3e8b44a,d775301b,66d7fedc,4ab8c827,cb138386,64727f10,5a65c0c4,a69b16e0,1c32a95e,77c8f99d,53bc15af,5c168457,19bc8220,d7baf849) -,S(d344361d,dd0b764c,be16f46f,5efe166c,10a88bfe,bf532a8f,a1fe138a,78e0e1ac,dc1afcbb,a84b8524,a5d985ac,5506f15f,d0b92f85,875c2c4a,4144a93e,e455792) -,S(444163a7,58095900,e5c8fda4,88ecae95,24fe54ae,2592ae53,7e6db41e,8019344f,bae54b91,e69ddcb2,c1bf22e0,bdd721b7,a9ca51b,dad93b28,59e09509,77c26488) -,S(5ce2e1d6,46f10fe7,e4196414,37fa2c16,48029fd5,5340d2e5,f32d467,e0c4e222,6e95f538,cadb1b56,8313429f,35fb925d,d9ba571d,bc6f3970,ff4fd276,4228e82b) -,S(8b7226b0,8525a07a,84ee858b,58c418d3,1d4acdaf,9b081761,56b83a8b,fde6d773,684e6dc,37a2ba2d,89c0b01a,b4e1fcc2,1734eed8,2f7b1509,6724acab,5e276006) -,S(6aa5e306,36046384,ac8e3da3,f2f00713,8acaa0b,b0d12ee2,1e69018a,4d0554a3,2144dece,31a7453d,3a07e290,cef1b694,f393e5d3,f6cb07b7,a8c991b5,2a788029) -,S(8537990b,dd59836d,da16ccee,3871a232,3bd841f,6128f845,b0369857,66c7e0e2,beda6acb,946a6e08,43ec2890,c2d11ee2,404cadec,afb3f1c0,37cfb9fb,7b733fb) -,S(85a8cf21,1de57c,9c0ba88d,2f9a773,61041619,639c9de3,e2f2bc71,cb9e66d6,80d1d1cc,3c757338,f5a6aecd,815cd5aa,1d772aeb,5c1efa05,d5b64886,97ff6de7) -,S(d4f18d05,cb183c54,7594ea93,9330c174,37870e7d,48a613ab,4a920e38,18068267,32fc3b50,394bfc8f,a2a3f912,b35ebb69,d388c87b,198c3619,b04b6b3c,36b6190a) -,S(123e8bc5,65ceba86,d4c1726d,5e7e2a32,ac6f628e,940aa97f,c96ff72c,ec79e637,e54b4332,975774e0,748fb58f,3ddc5a14,8c3eb1cd,824bab83,edc76c28,e991d2c5) -,S(ac26cf03,c5a95e3,9a975746,a26bde6,8eddd6b1,6c83a3c5,81fa0a79,e93d0cdb,73ebeeed,b96d879b,882ae503,2f400142,5c8ed97f,98daa225,346a5b7e,9abc4832) -,S(54f2cc5a,a4d81daf,6600e921,441f5aa1,5bb51a42,7479e123,b9561d0c,8c71299e,3ff4e7f0,83f85039,d238a740,b7fd16a1,e313cbb5,b0c6fe5d,ad99f221,da4aa27e) -,S(8bd785,b73cca1c,6c405ca9,1ed4833b,428b7ddc,1a61c8d9,b0d1dea8,ef133586,fc5b65e2,5c3fde0f,3239ab96,625a9751,27a30cbe,f98e1ee,735c1f71,c86cf292) -,S(bd4218be,af5f92dd,f96a54fa,fe873cf2,171c2e30,a13c866e,e830bb2f,abb17d5c,86097c6f,91024f4f,8900853b,d17dbede,e2674e36,9f3fc69f,a2578eab,174e783f) -,S(a4006630,1b63e757,fce2f5d2,a7444e5a,1f2d7509,b7f59476,6951f38c,1755b497,87aef8b3,eb160df9,4b46a56a,337b6400,c724658c,a49c1162,c418e900,29efde08) -,S(5c5af5f5,65b2870d,6fd08f95,b4146379,15cda056,e18ef682,4cbbbcf8,adca740a,c7c6de6c,e679f0dc,84e28027,86ea726b,8eb0ad04,af4b9a5e,de516f11,583607cc) -,S(b5c3629,b86e9235,478aa7e2,d2e5b539,b70765b7,79ace9ec,ae76a659,80f0ebd3,86a8a06,84fef80,7a081bf0,3f08c078,7ad04420,76f5e1d4,521cffec,8b2dc96d) -,S(1784e06a,cd25fa66,72d1fc08,9219cdb4,54f5c711,4237bfe4,a2143eb3,20a0bedc,11feb0a7,d8d43ebd,5bfde5fd,21fcaa5e,7f091da6,3acf4b91,956172b3,5d3af378) -,S(39266c28,48f58af4,47e5ce4f,61cb3ba6,9c3bfdad,7e5742fb,ba4ca3f4,f175a291,7be4b872,9d1e2fa8,fee16e5,bfcdf4ef,2cff2872,e9c7fea2,c1997d6c,5d7f1efe) -,S(d6fbeb8c,72214cee,58b33bbf,2eb04924,f96e9b63,d104aa92,fbb09c8f,c2e4b1a7,cd9bbb10,a800d777,9d4cda4,561a2b8,759b4dde,45dfa2c,319e4e59,39938c8) -,S(42ee0a83,85464cbf,cd4a9ac2,73001bb8,592f2a74,b28ab7c,2eb7055e,2a471b76,d22c6ec9,d5499b4f,26947233,a5589aeb,14c94376,9a6166c2,af9d323b,e1adea4f) -,S(8cd2a043,4de9b238,f4dbc3b7,e56ffbea,4f025e2d,6c73a68a,4aa62bb4,9e9057f2,abfe69a9,986ae1db,52a807c7,c08a1116,a2dc7aa2,ec3b649d,7326bafa,ca74d21e) -,S(14c35089,62dcb50,d01750a9,441eda38,1a95abe3,72c501bf,a99f953a,5c94da3b,bc57dbf6,bba79503,f33be20f,96a54fda,fcd7be9,cb064410,3db11e3e,2034a3ae) -,S(2cddb646,76717e44,86fbe0a7,f7d6d853,7c3fff9,465e31e6,8da22abd,b3eedee6,136346f0,cf5fd102,932036c,3605179d,1429a706,71d95524,a14869a3,d1cae8f4) -,S(d806ee3,b5702d23,50c3f179,a00c3701,9c055103,318594c5,8f10b100,1b705aeb,79201749,21e69cac,a0ad5902,42e39a04,c3af8cc4,c665587c,cc0c89b8,3744b9b2) -,S(534f24,715e9b8f,f5f76a4f,a617839f,6fe2f175,3cbc3d80,331d12e,98f6ec30,e26ebaf6,4affe9d7,1ba2cd55,421c33ef,2e4a3fb1,c59a72b5,93ececec,65a40e1c) -,S(f33af0ef,4e23c8ae,7f3de5c5,22e8bd9a,6e527c8a,23242c8,4ae6677e,ec90b8f5,8510bee6,bacb5633,45f38075,8d85dd0f,493d179c,b9250d25,fe88134a,6055aefe) -,S(3cad4725,12a745f6,7e36fb92,1a2926d6,ae294278,8004386b,272d8520,f5a9aa61,d12ccf97,27da84fd,317116e4,9d45d741,776c8278,4b2c9f1a,e3773e1f,57b8934a) -,S(4b7fcc39,5f50944d,5cf3b3f6,2b1bbc3e,3aca20e6,d259e931,d3398d08,cb6fcdf1,99acfb05,a106a389,b7ad644c,cd275396,d76b046e,9992e573,dcead5c6,c7da96ff) -,S(9b5c0e8b,22a62110,bca2770b,778f0a2d,6d67e908,c57f806d,7470f5c6,abbb27f6,da52c77f,ea3056fa,dae674e6,daff8b21,100d007d,8bdefb12,fd56efe8,13c15a02) -,S(ee7b7f5c,e79eac13,d9b500ed,ee0b65d8,e7c93203,aaad71a6,9a935e31,20722361,e77ccd78,bf6380e0,5e5e8de2,20448a00,cabe7d6c,6b7ac318,56c09e2a,9a390778) -,S(b4774237,d36a59f0,e39a133,756bebf7,4df43365,2a4505c8,b0b84833,dd5b3a1d,5a5a03a9,e3463ce2,fa8bbfc9,afde9c25,763f4874,3cf0b2ca,7dc42c3f,9bf3accb) -,S(5827142,c69944cb,a066a985,79acdc02,83e1df82,8935ba82,5aa55047,5a52271e,c05c5805,6bcb6cce,ed5e8c8a,beac78b9,69c3b482,7ef5b402,c94fe1fa,f7fc81a7) -,S(ba06eb6c,a54fe697,9be9e9c0,f8c77be5,ada7bd7f,43894d1d,1705cc18,9c9b0ed,176be0,b5d3db28,7f235e2f,a9531fba,65f5ff8d,55b784dc,bf7271bf,864e3d5) -,S(ed84c2b6,11c1208f,2f059d37,a3d2ddc9,c3a0196c,9b9dee3a,5f2cbb0d,9383625b,6dff970e,b08bb4c5,4dd6ad6e,df25bbb4,621a5ea9,3869de76,2524dd2c,af1c6f6b) -,S(158b136,86fbdcb6,ad8ea001,9005405,b5cfc0d8,f614592b,d9e76b1d,8cdd568a,8c576136,634af4e7,9034b450,1bae33e0,9b5712f8,642cbeb,2b7c8910,cb28fab2) -,S(687d52da,10df8013,7232821a,990adf74,c54711de,110027f0,68464c9d,162c2410,dad3819f,8071b3cd,dd84fde,550d24e6,31785e1c,e137e115,8b5cc687,8cd09f10) -,S(32e8617d,de77c33c,a1d317db,d350298,50dc7fb7,148913cf,413e04b,384dc81c,9cb2fdd5,15231e83,21a3feef,804d62e9,2b8b9c0f,dfb73dd9,c3323017,b29f2ff7) -,S(a53a659f,7cc90421,21d96a90,3801753c,ea43b363,405af6,16d50b4e,fff054df,96734742,ecb3c201,742f8f64,df22569c,92212928,ca0d5453,d706f905,33c345cf) -,S(8a9e4990,b9b1a2b1,32ca9507,16170713,bcbf5719,2dca9d71,7fc9c4fd,a3993fe5,9542de81,f66098dc,c0bb0f89,44ea56bb,bb7e86f,9c63222c,80620c7d,2fac20d) -,S(5966c5b0,f92c5906,b9bda0a,7b3f10f8,e4c29796,f953db1d,35976175,dcb431d4,539665b9,90bc3810,4b7938f3,47ac94dd,7b9228cf,7270284,a825a202,ac62d135) -,S(2170d9c7,4ca5e85,305d159e,697fd1d,d32d6f6c,a2806992,f082ce00,9139c34f,b5cbf529,66f71e55,8015c90b,ea2b95fb,4a0fed8d,ef1f9af4,518789e7,39076c64) -,S(86e9b03c,2497519d,615f83f9,d0f9bf9b,101b75cc,50059e19,4d7b58a2,9b6fdf76,215d042d,7976ea35,a3dd586c,f5b286ba,a30e013,966fbb45,99845111,db8b56ed) -,S(2cc7d91,ba630172,ae56cf60,9a5d3c05,e27c2e68,7d607c85,ffcbf6c9,a467028a,9404f869,32385290,dff3f8fa,1a085661,5855aa6d,e9742d8f,9e2777f9,472ab5c5) -,S(84a89b0b,304ed760,c3a3d972,5a65764a,11d59ebc,25249f69,1d3b8711,10d3cc73,b7200408,fb1ab866,53b61321,10b6bc53,c8a0805e,568f8a0a,80a65678,c54c5829) -,S(4e9c88e,d10be9ea,a34bae15,8ba3093b,42ad9cb7,356f34dd,33eada3b,1937b4a7,b92050dc,95423a8c,759222ea,c09593c1,342c2dde,5fe382d5,6838df0a,877dbd9b) -,S(fe2883e6,6db454d5,31f2aaec,96f4f3f2,868ef393,d09c7685,a65d476,c6c97a99,1ac28015,1bc7c0a1,cc4be80,c6eff3a2,b8ae70b1,180c6a15,7c89dd3e,3e78568d) -,S(c74df902,ba66c205,e49f25c5,62d1eb18,f4f4f697,3cf49135,16000924,80f3f68f,17f7bbc9,59dd7e6d,9043ad38,7c0097b,403c8d1f,e676b8db,d7f2c63,1fa1ecd9) -,S(e7e7a72a,41f95b51,2ea42d1c,76da24bf,67059e,c27d5313,55c30e60,69a72c16,a20c2f51,6e9ba9b1,fd3a8473,8309ace7,da6006bf,bc42d4ed,657da6eb,6efedb8c) -,S(5a93859e,dc4ee632,9d36536e,1bf1008b,603d6a8,859ac6c3,a098748b,d6e18bce,489326a0,1e05c331,d97db6cb,68f098c4,6712d7d2,994e6c8d,be892138,e2106220) -,S(6161b293,71353343,a46d0917,4f6467ea,25a0f77f,fe614133,7fd3bf77,71062de8,57c439d9,a1682d4f,773c8260,6ee65e88,473544ae,64194ab2,3fafc2dd,7612b385) -,S(c35b16b5,a3808dd9,553c7644,400d6fe8,ca48c8ae,49c78018,4a71eff6,b94ce4ee,6c3baede,4925766f,3a7c59e6,d6c1c966,c3348b1f,5883498e,9956f3e6,6d8fe13f) -,S(fbdae49,32baf904,1d295378,2d227dce,4e2af60a,86796a69,86b777ce,bd2cd134,9ed9b5fb,df42e755,a9cd761a,cbb92877,6c66d299,35dc526c,f6950ba3,d63d0c95) -,S(6c5bdede,17ce2007,a3a1c18f,af8a846a,ce67b751,3d8bd602,23610ae4,b01b720b,6492873c,26a22bc6,39d4614a,202cbb2f,2a08b78a,753592f4,10c855d8,12f8d39b) -,S(eba4e62a,bf52b379,9305bfc0,eecc63c0,5221a0b8,b554432c,15e460d4,21dddeb1,e378e6c8,d6ddc7a6,72d83c3c,9d863c53,32b1cdc8,21ed458c,b817c49b,6dbdc519) -,S(5a79ee4a,1aab7803,23ced132,f9c67d5a,c740900e,cf71a0b0,ddb1d6c9,794cd90e,9f608713,47b3a231,548909fc,812624ef,26eb26fa,98630512,2b1466f2,665176cd) -,S(78b702ed,6d816c15,eb31dc27,619d5bf0,6ad646b2,e39750f0,73c31d03,e50d9385,9f1cc224,91befaa4,fbe9721f,86bebcb0,11024a08,4380e46d,bf11ce99,f157fd24) -,S(494e82e4,1c24936e,c291f69e,791979ae,3e2a6696,c8f68601,b57942a8,fe6b98eb,59f3af2f,c720847c,19fceea6,e3d2a918,ff7f564b,2e3bd7a4,beda6415,65bf5da2) -,S(28b3ff40,467a8c68,69fdc61c,33f002f9,73705468,4fc707ab,c0b495e9,a5c0b401,46a44995,b2c8f0ca,a32d8e33,b8e38465,4cfbaf1d,addc4d1b,852b2a04,58f84e34) -,S(4e4cf4f4,38a40e8a,aea162d9,dac13531,f5730d96,59c436fe,d8acd06a,c4c46be,4fb4bf3f,bc394c7b,57f81a59,2ea14c30,1e9ca990,5f48ee7a,5db08ea5,eb6dfd7f) -,S(e2ace7b1,3a9e3e22,a9b8ee66,c56e80f1,9370cda9,eb3ffb6,2d20805c,7f4c34be,1c8fcde1,2a653492,6428319a,981e1602,44aa823e,a82831b4,d0eafd9a,2159318e) -,S(e090ff27,e42469c9,91dab9a8,dc9a3a41,d46b7482,a59ba9b,cf4de93b,c95c7e78,d070752,c5679b45,4e1b617e,8315a48,1cd9d24e,eb53a671,3b4160ac,64e6f824) -,S(705c8790,7b976b8d,c8ccd3aa,897b2ed9,ea091c37,e285c37b,aa321c89,15ce089e,edccb405,5ae9f933,973950f7,eb79657f,e94fe286,27f6cb2e,784d667c,21ad4d3c) -,S(4aefb3df,663a28f0,d531e390,339a56a0,4da1c64d,4692c086,de232740,6d386d57,167af97b,43a36a18,1dfde22e,633547e0,eaac2f16,84e8753e,1ba1741c,2a18fe3f) -,S(ea909685,ee8c283d,1d7dfc4d,6ec8910b,b8d821d3,3997f24c,db5f5ee3,bb7bd72b,685b64,d3e02ee2,be2045ba,c3bb428,636258db,33177da3,17f6de0c,f8c805f8) -,S(5987cd59,ecccc129,b3498331,f20cbfef,f377cacb,dea76ce,2e221aac,d3aace8c,3427cdb4,f7367d60,44ba21b8,adfd5863,bae2981b,340c9bff,d0d7e93b,ee4d6140) -,S(e23845ea,e6ed3d33,14fd6f6e,f6d6e9f5,92f921c9,f448eb93,edb49869,97837eb2,89eb22d6,455cc139,e42c6263,b65233c5,4b1a3b45,34ec3d7e,58b788f2,6b11b131) -,S(cac7dbd9,7dcd353f,fbf60696,d325bf14,2e3920ce,26570b59,ff9aa65a,a6993199,6e81a4e,cd60a26c,90f890fd,6de2d159,50bb70e8,92eed375,25a48f3,31307620) -,S(9dab063,3a5952fe,f168d6c0,3ebb226d,de3e591b,4ad0c9dc,96b247ae,49a317de,846d87d2,7662b958,b3422b3c,a3410ffd,1ae549d0,c6757bf4,f96d2d77,168cc83c) -,S(bce277d9,ed439b09,f255cee8,af5363a1,12ec2d5e,b111196d,be30fb21,43f501e4,63f472d5,2649843c,42e8f900,5adfa50,d6a938ef,8f4f04d8,897a68d8,8c213328) -,S(df9f8700,2a6baec7,8b79cded,bb501dfd,54f376f4,5756501e,f03a6c7e,ac5f1d7a,2a1c5c92,789fa6e2,84105f4c,74b0a108,27ea2f05,5560bec0,5d0000be,b9b6c4d5) -,S(6211dcc9,307c40ac,3c7be1c7,5553511c,15d3224e,3b305c5a,39653d83,f134dbb8,545c00d9,f02b8833,5fe4851a,88cbde99,f7f02d05,ac674f5a,6559ac9b,d03febb1) -,S(d739aa30,8d9022fc,45735eed,3ff92f38,545f6c9b,b70994fc,b5f41f78,772c9378,d3c3fbb,9077dd53,d023838a,5c35b728,af4a90c0,1f16739d,12870e1b,15e1e6ac) -,S(9d85e55e,8ed84471,b6822c68,3268c35b,fa314b72,470e51c1,a7ac9f25,f8bceb6,8b01f444,e84436ee,ae159a32,7026d279,5c4116b3,b2e78f90,99f1035,1511ac88) -,S(25d39bff,22c40a94,b194c38f,be9d001d,4a632407,237fb091,163e463d,7c5c70f,33381905,11368982,445ad7f6,608be022,209466c7,98b9abe4,f4fca781,2c0c398e) -,S(67553ed3,f14c28d5,2abc36c9,3f15d0c4,7f6fe1dd,628b652f,36b29225,ef8ff51c,da5d42d5,9d41893d,10ed28d,569c0cbe,1cc077e3,36bb5c21,e3712bbb,9c480383) -,S(ea3e80f8,c800b52c,a6dcbd2d,399ec5db,65057477,8852a73d,68af22d6,f1abbefb,5cd8f55d,b5330919,377b48d0,8ac1bce0,dfb8c3ea,2b97a5bf,547b7beb,ea64a4d7) -,S(7cf11aaf,638b1fe7,3b8c5753,48bcc01a,41c61ee8,f2eb3279,c2ad21b7,f6f60780,579d9a90,3a8a77a5,6bef3ce0,53ffb3c3,cf969f9a,39ea5bad,b1fa075b,e918f048) -,S(ed377aa8,42897f6d,1092caa7,42c29285,2349bd7c,a0e0cbce,d3cda58e,ffaf5e17,44d1e8bb,6491dfea,cde53662,5e5d7b52,1ca11a47,1eeda260,647f6f0,f0c5f917) -,S(fcafcd82,dfc87415,6e0db5ab,2fa2b56f,dd488032,d22ddc1a,b7a0ec8,1f1c4083,42f88e6a,cf851a7e,ca3fc28d,f771cce2,bef0d7ce,3d26da45,a2d9c307,e9e7e040) -,S(4d372865,7fde43e1,68744112,26b34713,9c1ca4ac,c2905858,de50def8,5515339c,5dc438eb,7091eecd,a4868c48,a7933b71,7ba99d8d,5e8a946d,ca9605a4,7421df39) -,S(aea6fc55,47faaa10,a898f21a,f63249ac,a0625f78,ea819629,8bca035d,7639e470,4d20c80f,173980d2,8e6bf433,bd1dacc3,1882e283,35fa9993,ef808464,a5568d42) -,S(f0ce04bd,bfa81a58,e157a49a,11695baf,7233470e,baa7ae76,3a07f0b7,f71cfce,f9e4d701,baa6f197,d9912b57,d9df016a,b789e60e,d731afeb,f2e5f920,b4eef9f6) -,S(cc476e63,130a950b,b8284c8f,fe74a059,8d9d44d4,c0372a9d,bbabca17,517523f6,d2cd50d2,e2cae10c,df744ff6,61a6c96b,64e17368,5f81027a,c937a292,3ad7476e) -,S(90e0477e,8dacfda2,7a563448,65947a05,d0afe9ea,60634473,143508fc,6abfc73a,d117be49,166bb010,afb0b82,a46a4204,c18ffa42,e3c89764,3eaae0f3,303dcd9b) -,S(522a6781,951f6ec7,76b6cf9f,cd20287d,6977764c,517d4ebc,7209d55,5714b5d4,a109c149,6318d481,4cb22199,3567e5f4,5147b64f,c1f9216b,922d653,7637031) -,S(b0a4c701,725326e5,611ea140,325b0536,b22406bc,c1e7eef2,1f874ff4,e02ec2a5,df44faa2,8a60eb90,3974649d,54cf340e,293fbd09,66b7b7d8,884e4c8d,dc1ec875) -,S(9e874924,90f8d4ca,2ada28a3,2bccfdaa,51ead138,3421d7d3,482af7f6,6df47c51,a58a577d,d03a719d,1bbb64,6ec3051b,44535da0,5e7e04d9,fca42716,2e335fd7) -,S(650a307,7b8007ed,f0441dfb,b7103d3c,d5146ecb,b949f9d9,c8c99e2f,25df7324,aa05b394,8c909957,ed1bd7e2,720286d7,56c7e413,8aa202be,b08bc446,2fdf86e8) -,S(f891ea99,2a3ef255,6feafa4d,7dd3f7eb,1f1401c2,b75d65d2,6ab81372,bab6f932,f7002bf5,821837f5,8df109f7,2ba5eea5,6c767a4e,198a7594,21467d64,df5e0bd3) -,S(d35e82bd,44fe54b,5d2c0543,91260c04,a5ce8d47,32e83ccc,2f3035e5,56bf2626,b002495,99705173,e0a45f97,196b9e41,1a7f5d1e,33f1b39,100b511c,e51f6953) -,S(7dd56d5,1f139070,a382af7a,2db135bf,854c8e98,2a325b41,ed869de4,349323bc,a23a473a,7f263bf4,944ab5bc,2d82e20e,8e9256fd,b11dbc17,bc0e6bfa,a8325f5e) -,S(afed2eb3,c5a95b4a,e88ee73d,b57594c4,7013cf13,a48431b0,f7930d5c,27f5c3f2,26b49096,da666097,3403eabe,342ab065,78c8ec6f,bc3ac7d7,2b3c95dd,54735dbd) -,S(13826776,74f36fe9,ca81cea,ac65c2b5,51e9fad3,af246f,4cdc65cb,cec534c5,a78e8139,760a94e8,3b3f5ff2,a65fbc7b,6b2b55fc,978b8399,df2d7947,18b496f1) -,S(99200c12,6fed5ec,1fc849f7,e9769a7b,aae3178,bd6b59ef,2563ed6c,5342b80f,7a7f1713,38a84536,e73f358f,91eb80b1,6ce8ef27,ea55795d,16aa7f05,577fc13f) -,S(159febb0,27e04f1c,321b852a,3cca550,28aac30a,8bc27caa,73a069e4,df7029cb,6bc7e080,8834b880,c590d249,241b709,e7280a05,7cbc1897,9b8cc9b3,cc21a821) -,S(2add9be1,a3acdd9f,efebdc0d,a4272ca9,311567e4,61db8eb7,3519c1c,6473bbc4,357ae640,a88c55e0,d3559faf,b0775d78,2373537c,c25e595f,f21ed1ff,b36b5925) -,S(8e2d4265,1742837b,b077fcd1,488e73e,5dccd6ba,6401c6c1,8d36fe9c,c428b664,ee9a5b1e,a04ab8d9,6430ef39,7756f62f,a1dcf35f,fff314a1,c3eb1dc8,d9a1e5e7) -,S(79dd7d76,5b4d7db0,537a69d9,b94210e3,8e7a11f8,cb9cdd8c,6aed6a15,748a3ac9,868c4b6,26dc49fd,de693201,3b89cf13,e1dfa1eb,56fb4de8,9e5467dd,86e449d9) -,S(552c2ba9,96a13b57,32c3b2fe,d4e9579d,365e03d9,2bcb231d,f14d1d1c,288a963,118e11e8,646a0335,6834379c,bc93c1d1,3ad80145,dee0a51c,49b10e17,f6952f79) -,S(fcfde18,a53b5a68,9d33bbf7,79d0b699,2faee8ec,243e72c0,7ca09185,d997e581,6709b56f,43013d47,23f15969,ee01b0b9,ff0d9d95,5e2b98eb,7e78e1ad,49cf3d80) -,S(e9e9d7a7,4ad279c5,691367dc,9c4b7bda,b27451b6,a8e4ed47,afae1883,96d8d82c,292bca82,e6d1c88e,8869f33a,7a6df2ec,ad812dca,4c46eab4,5c56c3b9,15f79497) -,S(514054e1,3e7ceee9,3a19dce9,96256b5b,5876a55c,6cab3c48,74b15547,4a58f285,f9ea80de,80403f34,2866dc40,cb0a9aa,4b38b98c,c4c38e3b,37f4da03,fdf7f5e7) -,S(ac0364,eeb9e7b9,b9589051,635de6c9,447b327e,8c820272,f04a4750,6cc5f290,ccde3ebf,13b5a291,a73b0c8b,9a69414,4b217661,7b0a7735,3a6e92eb,4af21b7e) -,S(cf558594,4a73a11a,ef500dc9,60cde799,ffb4983d,ae76826a,a027fd77,811058ba,369ed987,eac1683c,4e8874c6,40049a33,867fa0a,520e5204,df328d89,f197bfaf) -,S(ee216b85,62eaf12c,9189055e,32cc55c8,2ba5e3e0,237de083,a6e77878,63c56291,2a8bad1d,a697832c,856f6adb,e1cc5058,77e543c3,429b090a,1d3cf0,d2df6248) -,S(89903a70,55dfcb5d,175acd28,f7161862,c9fe22dc,ab752d88,3f52801f,92ab1892,e89c4f9b,7954c2b8,cd3b4868,ae171331,871a2693,9355d88b,8d37d4f6,b90c143f) -,S(f9830f50,66b1b44a,89231a81,1192a284,9ac94ec4,13f5223d,51d1e75c,a7727884,18ac8170,58795d51,cb9a5c2c,c249bcfb,ff3fe3b9,1506b721,763c8fcd,7e2ae44c) -,S(326be8c8,55c9f742,19228eae,f7d79c48,b02c2e04,3bc28e9f,275d6754,31afa8e0,293647f8,76b00450,b223e715,5faefac5,990322bd,eef964c7,185acec7,7c105d06) -,S(6117b67e,bbd6b120,906da047,88ad7dde,3549bc5f,c4f80e04,9b216b00,d441dc9,7ebe5576,17dabcd9,f41aa34e,1443e12e,715c9a7,ccfa04f7,ec6a9a25,74c1e540) -,S(1fa858e8,aed841c0,902db240,aa0e4c80,f26927dd,94e0e404,7e8ecc25,216dafce,26566614,2111086b,caff0e12,e4b38940,ecf05a5b,58f3e705,d7011b49,413a52fc) -,S(dd77d202,96a15eda,eef79ced,9b59e77c,1483b936,6e9949ef,ba3298a0,efac4886,b1914a11,80cb154a,f791a934,8c89bb0,70f2ac9b,acc50c5,f75b425a,df6bf125) -,S(e5fdfb45,1e7ac947,ece4e8c0,5b87b9a9,2d49aae3,5ef95f5d,1d18bcad,18053337,841d054a,47b4998d,d3ad8dd3,d2a1ee68,406a195b,1975bd1a,d4194417,fdc4cad5) -,S(decd87d4,6fb74380,56a83258,bee67d9b,1a49e170,bb1b549a,a5c2a2bd,cbc050ef,5ccd1cd3,614fad6f,601a4ad6,e964ee69,a1e06e8a,2e29edbc,7d19562,a4aebc5a) -,S(1a94991b,939bf699,468c465b,5aa4b064,520222,c0ccfcff,193a8484,6f6e4b8e,31b1e6f5,30147e1d,ec0199ae,1830a36c,bcf4fce1,e1258441,3e89eed6,889b9d1) -,S(f32874f,d0f18d03,7f0ae5f2,ddba8f16,fe7ca4f0,d694e803,b9216c59,91bb456a,1dd8f5ed,f228a9d,53cf881e,a4e3c479,6017be43,e613ac30,690435b7,84a4056) -,S(1c5991ef,154b79dc,df2ceafb,3f7fd7b0,7ce7563a,9312ee6f,1dbe5960,f91ba569,497d2a93,28ddb18,221b0075,3432f510,bbf042a5,ebc44cf9,3090d064,4a252a7b) -,S(3c88095e,dce54996,3bf6e312,4dfc14ff,4ed4ecc9,d6240af1,6ecd5984,5f01de9a,499a17ee,e13c81b9,bb7b297,5e7ed1a1,231d9094,348d22fb,9254c520,a65be01c) -,S(c849c359,1c4fdb68,55971840,c0b78bd3,59d1de02,130adf7,e277cb4e,f6eb7748,6add7151,b2640b78,b8fcfdc,fee4310a,4c4c97c8,bb0cdc2e,3bbdf802,750a7920) -,S(f53017aa,a5f79e34,5a0cc318,f40115f2,52ba5401,614b9eb8,ac9245cb,3ca5680d,2d8b8c24,ad89361b,6d77bc72,fb0c7da8,ff129a5f,2bc00e26,e635483e,c4c44b1f) -,S(b3657e9f,84975313,640b7302,a288ef4d,2dbf36ca,651c0189,b39fc10c,87d7c4b0,d821329c,a2f18f94,7a71f5f7,51ac1b2c,e56aa432,992e7a3d,ef84e631,db61fa14) -,S(79942dcf,a834e013,77bb3eec,b7fa31a7,b4eabe7a,578c46d9,3a0dd17c,b3455f61,4c08fe53,c3afcbd1,7fa0a809,bd4ff7af,88713a3e,d7713f82,18c4d4d5,2a757ac4) -,S(e5f14474,619e3acf,905da5c2,3d1bc311,7f1d58ff,8c63ed2e,fe939a22,5fd9d9a8,d4d225b5,85b6b319,431939a6,8e2dafbf,8ed90a6e,5fb559c0,70779d67,7c03028c) -,S(bc5ca503,3ca4398d,5f3c6240,946c5d7,c9102996,e302b9bb,640aaeed,8c9b54d2,ac15cc8,51e59843,fbb2956f,55d39f24,200922bb,6cbf1e86,68ed3ecd,6fae2627) -,S(2f3abe56,d63a2afd,35e35d4f,9e964c61,a5483402,5fea8cfa,66ba9aed,f75947b2,7adeb38c,e14ebe73,8dceae8c,77903b24,3066aed9,bc4886c1,356449a8,27496d5b) -,S(704bf0b5,f564ccef,4d6e5f8b,eb2e90c2,4b46d581,93cc0a41,5bfee2fe,95021b75,44618d17,c54684e,ea1ffe1,53892090,b74201d8,ab3f9312,e7359ed6,5ca94c27) -,S(a898e473,d4b59956,2a905ede,afc78bcc,9f374c6a,f524fc37,86a91375,83d749dd,5452e556,7d72dab5,e085ab72,1168b5e9,c96a0fce,f9d5862b,9c5a0daf,3769395b) -,S(fc4f83da,817b1648,a8a1be3f,dbd0f309,db712225,2988ac8f,64774c29,e8d9d573,57876e31,6a0ea473,3e34f34c,b0df75b1,1194017b,258cc944,7ccded35,19edd00b) -,S(63e97e30,82c36634,d151f0a8,837956d6,16d5d4,64c66373,253bb94,ed5c8236,af68f06a,e045e5be,88242af4,2e314ecc,d719f76e,33092e6d,8b69f791,446c2acf) -,S(4c06073,5107e9fe,f27dfbfd,5df447c,16f1c911,8ec5cfc,8083a588,9dd82b23,8c8508d4,b86e9eac,2058a912,f2581ae7,fe81647e,e27075d4,fd01b051,fe0ab636) -,S(667f609,7b6af1f,cff58520,83175f85,ea01a1d3,c508b12d,a2e19281,c8d8e443,ff9fd0d7,4a0cb42f,3d7ff6d1,67e5a65f,23c34679,caf3f94,ed5d1073,af31607c) -,S(e01e169e,7fbb4365,58e07dce,8f8dead,e2ec2e27,7d18db95,ef8e9f85,ce800fd7,f49f594b,9d60c59d,155ea702,a1b5e3a7,b26aeec6,71b275e7,10d0139a,21041960) -,S(ed10fbe2,565f80a7,65fc90ef,224c7893,cf9df84d,aa0a3b2,9089f7f1,c014ca50,ffc44137,c3ac6fc6,fddc65d1,87d6b456,819ab1b2,df461ecf,899c70fc,59387031) -,S(4563833d,d0052218,5a43bfaf,7e55c2d2,62a12feb,b76254bb,e8310687,e917cc36,fac05d5c,c781d49e,9bab4cbe,384b511d,1c8c1fe4,f68cdc2c,8c576be0,1c669e63) -,S(bf5907b0,1d05136c,b0a1b514,73682fa1,68772a1b,9f5db994,3bdacb3a,1e8c47db,fc69b036,4559f5d3,f9e0c1a3,e4da38ac,b9968e9,17311288,69da2158,2e334cbd) -,S(be106d73,d01ce0fc,5555d4f2,379c906,1ea6ca18,ef8ef8fa,754ecf64,cfc27fd5,9c84f04,947687e,f7d641ba,ff89a11b,da9e9769,8f8ceefe,54e2a4ca,267956e) -,S(5bceda4,2e94ac3e,68f6a3e4,e4509872,4724e9fa,59ee0918,859884e2,2c98f15f,4b19d70b,e1471e3c,7907f797,7311f5e2,ba78c6f5,6f2ccaf1,cb6b684f,7d048934) -,S(e0831b14,fcb2d4f7,3d17b6c7,f6d16803,304cbb32,2bffcd6c,84bdb891,9d7cc9d7,b474a715,5520cd3f,65b64d08,b8e92ca2,4b2238b3,11d91db2,48720a6b,65444038) -,S(df818b88,2300aaf8,41cb3962,2f0c9166,468c1ad1,3aa284f5,89dc354f,bb1fe97f,40f571f9,f63fb358,231c204b,3b9707f0,c5cf11c6,d7ffb93c,991cf7f8,dcfb3895) -,S(d9fdd569,bfc89237,4bc56a1e,e56bab5a,cb5e0ce9,85939b85,c929fde5,82a07bcb,5c56b150,4cf3767e,e22e4b00,fa467b75,4c9ccec4,c1364216,d34ee210,aa5b56ce) -,S(11a93998,d031bc3e,d55e74c9,ab327945,cbace727,647bfcd7,5ed04a2e,4836ba,4aa311b0,6fc8fc86,b67e8eb2,1e75d997,189fa22b,a33e7e99,b07d610b,1c94655) -,S(7c4fc747,7319464e,2d71f787,80aeb385,aebb0420,d8f8588,9652d5de,aaad580d,31d6d7fc,2cae58f7,b3e4804e,f615d7e1,edf9d06c,d1035b30,ee9b55b,21b06eae) -,S(83704a5f,4ef8ca9e,a3d5b163,2bb3df98,acd774d6,4e07b219,b9a36a9,ce88e1b7,52976995,faeb6179,bde4c123,1437dc73,b53b6f90,f0cce08,1e3e1644,e1ebeb18) -,S(5de15f19,21258b5c,f12f240d,147bd38e,fd5e3c3d,dbf148c5,9e541c01,ca7d724c,c0e18562,1500f0,e3fbbdef,45550e16,5fc2a2a,adc72558,e49f1e3b,f5f4fb00) -,S(f5d1fb46,e3288419,1f2cc8e8,2ba81ba7,5bf1d7b5,97ff82ae,8731d27b,7f059938,3d5118fc,9acc8394,9e0bcba5,c7c79fec,2f0cad64,7910976b,e4e8f9ff,43d8baa0) -,S(8ebe619a,985f720b,9381a99c,db63d089,6a787dc9,7d007354,fa83b931,223f8596,7968b6fd,e3dcc13c,512aae25,d9a8127f,313e2d9c,34489606,864732b4,c3b5ca1f) -,S(5b14482d,f96cb0a0,5664bcdf,e4ff7b87,6169db9e,8107b0b5,78baba9e,b1f8fcdf,19a4ed84,cd2ab376,b1e0c2c9,ecded5cf,2e874f09,6d84d946,22be5806,9f8a5e82) -,S(ae810d52,7f94dad0,d140877e,ddc5e0e6,cb636325,f4c926a,1a263f1f,beb9a8b8,c94f0c8a,f5ceca8f,ea29dbe6,c8afa649,f813744d,39e303b,c1f0c135,867658f) -,S(38853d15,d74060fc,7eb2a56a,b8772f6,855aaf83,b731d853,b99fde93,e7c06e7b,ade73ce5,4f513c89,531b5bad,7f47ce7e,a498da85,e378639a,5ae0507e,1f27fa7d) -,S(837a1d99,db477c6c,da832700,37f111f6,eec5402,2bf74773,4c18bbab,35b503b4,ce852762,ed9b36cf,65602da,cfd3a250,c547a971,1977ba86,64f72cb3,89ac1f8c) -,S(3136acd5,a1460d8d,717e452b,a2069b88,4eb6fa81,756f8768,932c210e,df08173f,42ad61fb,edf97b53,f59ed7b6,afaeaadb,831134ef,73e33b1e,26b2816c,99fc330) -,S(a9609269,c3ef7f09,2a43e394,e482483c,119d94df,10bcce43,6691230b,b77d3201,8c580df7,9147069a,5c84abb,73e28b6b,ab9c7c0f,7803d6f1,d9fa86c8,f324be1f) -,S(3cb613e1,1ce19ea4,a8a90eda,cb182c09,5b1601c4,92822974,6ec22fda,be699e08,f05a18f5,aef9dfe6,87e69a9f,287fd868,4c975765,284f578,50294598,51538b05) -,S(b41c56a7,47232950,7777847e,178eaa67,ce61f561,21c7f21,2c525bd3,e7adc359,b0026b4b,6f9dc954,7efedd80,d914a3e9,65b17378,e6e0055e,527f6754,c5c589fb) -,S(f44724a1,3cdcf9fe,5b4a8f3a,f0d3e076,4559c14d,87eb8ea3,803a41da,9ee9dbf5,355b54b0,7ae7c477,9eaa314c,953340f2,f5583ae2,ba730339,acd231e5,c3d64627) -,S(6fceab96,d5851eea,b5db9caa,9a0ff7e7,86c2e097,5c2207d4,67f343e3,cb36ae1a,83f2b505,20094ad6,cb8443aa,69b8af96,b531341b,81cadc21,565d28e7,43bf2c47) -,S(2acc57ff,ff168361,9275273e,9a821fae,54947539,7f6b1936,13917af0,ef83cab5,764b04bc,9068fae5,75a202c1,f01f87,f3650358,3f5d3042,1e246020,9fdcb94e) -,S(2ac302a,28126e57,5e6aee8b,2b12ad19,f5e1c056,2d63d73e,80204b1d,1d4227d2,74494cb4,1e7828f6,9d2dd529,a70f2e52,9bf4b524,26a2a3c1,ab10a974,99624589) -,S(c5de085e,4dcf8dab,497a645,c7abd513,4054b225,32ce8405,f6e5134c,515d9de3,d1da7171,31a859a,a2c90816,386f0318,9759326a,6cef86f9,f3425bf2,390bed7c) -,S(54729254,5f78e410,db85d01a,182bc5ed,84bf6843,3b5784cc,852d3e70,acbfe90b,618b0f0a,7919751f,46c0ec61,1dddd798,cd89d4dd,32d1acac,31432308,d1a615ba) -,S(c6fc6b5d,84bd05b1,ec8b0ed8,fd4eceb9,dda38669,3859d90a,a0853c3,7f75e8a6,d3d8ffb4,988f7e47,2c26bd4b,83f95453,149d1534,bfafa97c,39a1e8d2,70c53582) -,S(1e325c1,ef4a976e,77d6e76e,f9a6dc51,175175bf,23e2c46d,7203d6bf,86ea05ca,60f35511,510aad52,e156e265,6e7ec137,c319b8c1,a1591258,590186ee,be4c1471) -,S(bbca6232,ed8c6093,7ad123f6,87af56db,28947e01,99340510,95850d38,6ac1d89c,d1257327,269836af,2793a1ea,21106bb7,ec95885f,de541f66,1a4a7c38,39c222a1) -,S(c55b1ec1,1f7aff98,710c3b80,34021aa1,83645a14,edfc6926,cd56eeb,f1e5332b,e541bc98,7ecd2b66,d10ce29c,572272ec,28c26b1b,1703919f,d0b28e76,4ffa87df) -,S(f026dc49,feb91051,68f76b0e,7abcb9a3,cc78a5c4,e520c2,57d2f688,5f1c49df,2471f06b,5dc74f9f,6cca7d72,86571c1b,54ab3813,d30bfb57,53274a4b,4257f5c5) -,S(3f721c3c,605169fe,dee4a4f2,b07865be,e1f0838c,669f7eb0,f234e700,f2fb16f5,9691b1cc,ead5fba9,9d9f1feb,fae6baa3,cc7717ab,c5a671f3,8def1556,e27e100) -,S(65bccdce,bb7e968c,a1c5dd12,2d5440b,97b07014,9838f4ae,95962044,b822b0ae,bd594952,f8424625,91375009,3cc6716f,cf7bae14,a6fbab35,4a962282,ee0b3fdb) -,S(6c155658,7020a902,c225d721,7b1a5f2c,5646179,df5613d9,b95826ff,7723f42f,1ee346cb,5841939e,42aa41ed,84bd24b,33075490,68de1809,8e5f8605,59e9c073) -,S(d2c9f745,8f75b42f,b48dea34,13b2bf9b,dc045542,8c5a3dd4,2a08716b,bfc4367,e2a9be5c,8f06a432,6f148cb3,cf58f767,cfc8f8ea,1ff4656e,ec19a64b,183f650e) -,S(aa11c12f,5fda607,aeb4af7f,8430cae,3f5df00a,43910ff9,e413b3a4,7295a38,e506e63c,a0568d96,2c489851,489fbb62,acb60d9a,fb9dcf1c,7aba7be2,2e02c67e) -,S(a355e383,43937932,21affe2f,843d2541,3faf807a,900bc299,5a201f10,d5748f99,22ce77fc,c627019a,ff0245d3,ef2b31fa,55687ea7,69a4948c,5656945c,c5a5c74) -,S(d8f4e393,8b93f252,da68e1b0,16fe8889,d837ea8e,61e5d3f6,8928bf32,22643cfc,c895006,61003ee5,3d8f739,d6fb7cea,e2f7b414,28a65ca1,bf493a3e,27a2e826) -,S(f69ff0ca,3aa0ee7,122a00a9,4b6ef41e,13945263,96e8c590,84ab2b37,6b899cfe,a5211104,271a3020,d65ca305,c0daa6ac,cbbdb1b1,d349a2ba,1abcfad9,bf63a7d5) -,S(64b1b59d,7415d433,7f5b9a3d,98f06d10,7e647525,b347011d,6d3b423b,2a377592,12ea2814,ac8e0bf,1da8e617,c8f051ad,5799593d,f9ffc1f8,abc963b0,faf202b9) -,S(bac6a7ef,9a3de971,51044204,ddc3a2d3,4668613e,101a7e6a,5f93c25a,6b20dca9,7bc2b764,57620478,321de1fd,8ae8afe9,6047d087,b95390c5,bc69b972,654b97cf) -,S(fddae798,dad79951,a4c3b803,11ced882,903c9dcb,4d4dacca,c4cadceb,b837f688,2e21e1f9,f45ded15,76829823,4892d2ca,26ad5b6d,7b0baa77,c2dfbba,b1dbca19) -,S(3dc783eb,40779120,25b7dfe8,f493f073,b3a8520c,ef0c94b2,1c3a5388,b0a9a01a,b3fd9020,2ca16d20,fbe8cee8,fb8bcbcc,821696c1,15545aae,84c414a0,c4401bb1) -,S(299a187d,299c61cb,6893a5d9,cc8831e3,df92ab13,da2f0048,555d1358,e55e866d,ef0b105e,52a18751,56080cc,cefde2b2,848d43ba,6d650068,2b71fb9d,d34b819c) -,S(b690b4aa,fde43b5b,362de597,100c74d8,97cbc750,688a46b4,cb1093e2,e253dc4b,affd5af2,30e4de4f,9971627e,dac86808,c97bfa30,f051af29,bf91e36f,c3edf0f7) -,S(7217384c,1596318c,2a98db2b,7264c909,f823de21,702f5e64,b19af937,cbb8be39,b125b7aa,1bd67232,df7d2d3a,a671bbc1,bace159f,3ba2fad5,e82a1ae3,965d5c01) -,S(4bb4a86a,58f1248a,11f61599,f420fc69,bc77b7c6,86d2838,f4368971,67013852,29909cb1,3bce655e,88300d78,4f7984de,352c9b9a,960148e,a5b65acd,99b62d4b) -,S(4b3a9328,2e473993,9d7722a,7de44fcd,51658eff,93c3711d,3a8f0193,9a54902f,9a012a8e,7df3b988,204fe0e0,50cc197f,a27618ca,d8d712cf,520c7be4,cf4e0f02) -,S(5488985b,26978af,50099d93,8d7b1aa,c545b07,44938190,e0b880c2,11782b26,b51f749a,76b998c0,83dcdbe7,21d5fa0b,c4aa4392,f81821ab,3436fbf0,37d37bd7) -,S(7f2ff4bc,f270b566,d2d26cbd,ffeb1b9b,31b2cd7,b647d89a,2c86c003,b23f644b,f48749b6,21ed28ae,47223281,fe8e633f,35580bf4,8eea29f,d6aae487,ee8e0588) -,S(3305c475,1d63baa8,18f5bdc0,b4e46c9,acdf1c42,9ff5d177,bdfc214a,b838efbc,491d45be,85ae9675,310ae85d,258c6c9c,8e28d7fc,5239363c,911eb12d,ee68a435) -,S(4195dd13,ae5ea569,179dc64,b07f66dd,4a2e2878,d81a222,304d6a88,4da60b86,bbdb99ff,8d4ce150,543b48ee,9109f127,5234c69e,52293758,d0171ae4,ecd49677) -,S(8dca7466,8ffbf319,7dd9826,cfc7f450,fed841ed,83e1d466,e92470ca,1e2582e0,2b19be5f,69fae0e2,563a3f80,2f9450e0,fc48ebe5,973f542c,4c12fbea,97627e57) -,S(e235d150,3449667e,ba23d119,9b5225db,1b26220f,60f84476,70c6bdaa,f5eb7aa9,3d4d8dd6,b0c8c2e0,c8f54f6b,dffe8dd0,5ae22d5a,b4f9dc18,f17acafb,3fab327) -,S(aa214fc7,23c3c458,8bbfd962,b86cc3b3,e1ed52a,25524ed3,ee5c4933,1748ddf3,9b54e29f,63240e30,434f7a22,2679006c,24593e26,90254978,35a60897,d3578e18) -,S(1c468a51,cc9d2632,860bffba,9ed83e5a,e97dc1d8,c8bc3577,5dfef223,b3ffcc73,fc569e94,8eb20528,98b4cea3,86486afa,cec0188e,44dc4e0,25b34855,f1466e87) -,S(c663e752,ce62dec0,81f8ad57,3e4f5c92,138e6a8b,e6c9d015,d5cd2cf0,ccd1a203,ffc249a7,554fb97,c0f9d96f,4cb06fb7,ce6e868c,e7e60b30,f67a2b9e,919f6f98) -,S(949a84d8,5f68f70,81f379e1,9d673748,bed14bb8,dba2458c,34327c03,c893067f,1b9fe41c,f474e57f,8497f6f6,76472a28,fba6b259,91297f81,474cb6fc,f31380f0) -,S(6a4bf3ea,5798c8ed,4b35c629,c6cfdc0e,d16d0d27,39f8bcb8,c34a9105,fa35fed,6f69e357,d5123305,56d04946,f9265353,77610fee,20667815,e7f3cb01,e8196b24) -,S(d0a99a37,d1df89c0,99b0dc1c,16f325b9,b2ec1455,21d4f80e,ad67da85,4f2a5357,7a75846d,eaf7c4e3,5c0c87f,83732eaa,7f6903f7,b721648a,87e1909b,53d3e9c) -,S(e2a45683,f3781309,b6223a7a,5ca64c4c,cbc5d45f,29c66082,912568ca,3ec6d3c0,8e386acb,63c52ed6,5aaacecb,fab458b9,9585951e,cd0e35a6,19c0fc39,5ce1c0ab) -,S(9527ae80,10ddd443,7237c2b3,c8f3afb9,f31e1696,5b10fedf,f150c296,3cb8e60,6e0843a,87833be4,f882c417,7198d985,5af8b144,11e78c3c,497fc49f,5f728479) -,S(15f15c4a,2cc43062,d4360a8d,dcf8e0f,52bc4741,c7924f6d,e1dd9f12,a06b9b2,66a127e7,2c55db1b,57050f4c,a0d8abf3,9ccb455d,9785a4f3,2ee67a42,3bfe5ccd) -,S(558648bd,64c52dd1,189912b2,67078e8b,d3c68952,47e6c848,d7dc529a,7a24a75b,12332187,62872867,5bc88378,88deadf9,3a8f2c5c,864371dc,6be0be63,44fad7ed) -,S(1e87928a,b6e10b59,6b231b08,87a823f1,3c6b3ff3,2852d35c,d1167244,fea2db0b,4cf60a4,767783a9,1c9747c5,7abbade1,3d7fc02f,e833b474,648038c3,b68d96f5) -,S(7a169de9,1d4c3f0,3296279,2c3ebfe7,f2eb4410,f7b9a34d,c402ae64,ce9231fb,1ca2e8be,7a7603b7,d95820ab,86487a04,c91ab3fc,c88e2f0b,514a1589,3908e463) -,S(65185a2f,bbc8c96f,cf9a6df4,d002128,afff1f2e,5c0182a2,95639a7d,9fecaafb,10b6902e,e83c5683,3d796b99,665cf365,c1e41d63,41fe72a4,72e5ea6e,39dbb9e9) -,S(61c45212,4664432e,8fbcd950,1dbbcd9f,1fb8842d,c8e61758,439b6d5d,bf8dd626,2a9c7c57,48509dca,ebfc5062,4d7a0b0c,21c9f5a,45733f8d,e0441bf7,f2b359c0) -,S(f61aff9e,267b6d91,e3d4ab45,73457987,b1af9a9,38b659f4,1ad5cf57,8cc59d62,51d0b694,e5692be0,6841a3eb,160474cc,6c248213,19c9648,c32ea444,29cb2553) -,S(29f27a51,8fd448cd,73aee0dd,7316e566,c655ca44,afc5daa3,ee359ae5,b96f8bef,d5957a97,a6447a8e,a8301219,5fd53c1b,63784a8,14c29c80,d0061fac,2c6cc1a7) -,S(c656d66a,efc3597a,2ee977ba,bdb7357,a2485a6c,d654c56c,bc58a0ad,598f202d,f8267b3f,f293a5b5,11f4e466,dce0fa88,a37f1603,a3a8092c,934fb824,1427a59f) -,S(f28477cb,efe654fb,ccd3a9ab,e816f950,3749e183,3b1faebd,418c85c9,112a5135,9df0f505,6ad98099,ac0dc723,34af973d,9c98c597,ee26e22f,a0a7a60a,a3b76cb7) -,S(d007a1a8,b6f05046,a66fe0f0,9a02e510,3ca7555a,277c40a8,87a71920,5a429e79,d9a68c51,f17fd51e,b19e4946,694e90f5,2cf664ed,d2d45489,5f880400,b410b8ce) -,S(348f74ca,7e5b1ff9,e6ccf3d9,90ff1f7a,4e3a8296,725075e0,33a85b2f,5ba0f338,1648c7f,32a206a4,e21e7309,f1a68a4b,b2ee116a,f3fab3f5,7455da93,7c4afc7a) -,S(1f54e125,7ff3dbcb,f1b55720,564f0c72,d322b8e1,f14d2b9c,1f6244d9,c85f6f70,34c23405,4a970b58,2cbbcdce,e67cc564,6e187cd9,b3024dfc,731a212c,c53c2861) -,S(a984f8be,33360b3f,a012cb99,65ed10e6,43a8df49,26f8188f,24719a7c,ad6b5238,79a592f9,15c925a0,98406d08,75ec4fa,90b5015c,4001addf,1cab32f7,9f06f213) -,S(2ca5e948,76db7877,fb828609,68e39c8e,a413a057,1a39e20e,a7b98f93,f4cc4887,b1ce7c2f,8380eaff,57299cef,e840c552,53629691,7ed367a3,5c59c3b4,ae67a02d) -,S(65bc7a84,15cdd07,5f493310,de05b7a4,ae7c874d,5b5221d4,7ee556ef,4c21a0d5,ad20620,aa39a14f,dfad58b7,9f1ad70d,2c637119,d9eb33b7,ca9abca1,f5dc3db3) -,S(a0b6b293,a9e25a97,18fa0db1,16362757,6e39cd43,83140822,b2241fa8,c432f276,2cbd88cf,29570778,8a6d79a3,b451833d,c596fa08,8b26c6a9,962880bc,48ae2b19) -,S(b4d308f5,74f7832f,4f402626,5ff81788,91a86724,9df74486,f241baf2,28e130a3,ca82dfe7,4c5768aa,46927fe,70c93227,cc7c30ed,c2fb6303,9a1552db,534019f9) -,S(819b48da,f19c48c1,f6efd0b7,c4ff5996,dcd5e99e,7146bde4,1c83e333,ac891b3e,c15bcf4,c9a630f4,e1489585,e5719746,ac55210e,c9b82da3,898a0d88,4eab0459) -,S(66528e21,adf8c447,526d616c,777dde1,fa7469ec,175facb8,3ac9ed2f,db773f85,c5d38c7,c13449ad,4f346498,1eb7abbc,a98de561,d94f46bc,edf3dd10,1839d91e) -,S(a26e3a0b,6f61c611,28c2afc9,15ddf48b,8d3d3901,df93a2b2,aeb82579,4822e605,41f4e806,787884ec,84716647,ed72f331,126f141,6837a232,e1612ac9,99c7d115) -,S(56623040,c198fbcb,9aa32066,90da22a5,a0496a82,5313a2fd,529fc9b,26647d22,35867158,42a4c950,e67b9033,23c55fe0,3ba3bf92,a9ecc5f8,39708869,7e2e1e98) -,S(acb401f1,b535f181,75ba9cc5,8e32514b,be8b6d19,1401248f,20500dba,23ad4f,f57fbfc7,9bb94ec0,eac7d09e,52b699e6,d8407335,e6dda706,f7d1bfe0,71e09f6a) -,S(9e02a873,fbbeddcf,b760d48e,6e29e6a0,b37cae8d,6348a8d5,bd651be0,59ecdb33,9f926735,cb2f46eb,71005600,56dea853,9fd6d140,2a57d05a,e884e8f1,1a293c39) -,S(3e88f76b,ec410c46,ca20cf7,2d90c66f,476fb966,c46f20b7,facb7f50,17f71617,bbbb4d9,a453277f,a7bb83d2,eb8b2950,3fe51b0,7d4b93fd,5e993663,9b78438b) -,S(cd39870c,a6484a9f,e6d30e47,3a6f5e8b,3ecc1702,e191b5de,3d4d6cbf,dade08e6,234240c2,8f2b2233,9369298e,f22cf32a,7663edb4,2524f02d,6879b4c9,f4ab442d) -,S(5de275c2,69799058,3348c4cf,8c039b44,daf431d2,b7b1f862,98ae24ea,271644c9,adcf9fc3,10ce2d93,8459db47,30273255,cc483342,3f6bd4dc,56593f06,6466b8a9) -,S(2d986200,bd9dbe51,eee40ec1,2730701c,621333db,9e71c232,1a6463e1,f26cb76b,57433deb,d9149b32,37315114,e9747758,228d17be,5f7c54d4,f552e730,1e094329) -,S(654868b7,39d6a72e,75223cac,d0f827d1,789c410c,fe0d5ab7,24cdbc2a,c9bcb269,3d8d4270,63cfe,6724f8d4,77ddbd10,b24899a,3ab0a33d,87683646,9f4806ba) -,S(d97cf5c8,e1a40197,75312099,fb1a2d62,2b3354d0,e524cbe7,bbd3187,506f909d,53c8784c,cfc900a2,f159e98b,76481239,3d883d70,8a953905,44691b5,1c8c97d4) -,S(697707cc,9c74c828,7396d53b,9e5d436b,24b861d0,2fcd9208,dcdcfb54,8ad2d903,bd203dfe,7f4a3484,1f5ec966,f063d251,a89b7da5,468bb2f7,32775a1f,3a62412f) -,S(36b4329f,fbbbd80b,e8eecd1,358c05f3,6616b456,588571da,c23d7752,edf15d65,7c42145,d8774827,a0cbe9e,b9ca7b90,2353c6f6,118291ad,950dfee6,124fef3f) -,S(dad2b02d,a182ef28,5b00b0e3,2af77064,ca6b3c1,41766194,7fae0663,4861e144,ece34dc3,704d0561,f6029366,aa45f192,a2b55b1a,1786e8a2,d84b2361,eb2c2af1) -,S(4cdf386a,c0e7cbc6,e19c5f85,1edb009a,59b0526,f3f4d0ca,3c82f280,dd33531,3f8b3eda,4ae484e0,95916efb,ecf1ed3a,27bcb034,6cbae87c,6a388488,331ddc86) -,S(d4b65a7a,eb74d38f,2a8e9383,2ad27a7,2e2a89f2,2ccb5c24,9e4e55d4,da7a0cf1,a080a32c,ac9e0ee2,6e6538a0,233f2374,3428b2ad,821852fa,bbad2a23,63a7d7e3) -,S(c41cd230,d99c5f66,7d7ea000,53945fed,70a2a807,4893d488,5be2ee46,cadff9bf,4a7faa2,3ea4ab42,5f21e12d,dea7530d,429c64fb,c05e1b24,adc24f55,c34af43) -,S(4c67ce59,9a841ecf,ec147a89,c120619a,227100ab,c5dd0ba8,da6d362,6f687824,aec0ecc4,b65694f,150da4f8,fd514d37,52f4c6d1,aebd8b5c,19846ea3,bf4b13b2) -,S(e765b00d,a067b5cf,a40bf02,dc8ed6bd,4e59b470,ed6eebad,c02b49eb,1d20c37,23e0df00,9ca95773,a91c0805,40b024b8,34c0d7de,4dfd6c43,76c979fd,2665f21d) -,S(18a8cbe4,d7585fe2,3b958cab,a9303d9,505928a5,7ca1058,21a9f192,ea52298c,9d00506,4a1f3406,c3864d73,2ebf3e1d,b6f20234,d0f5a99c,3623ed9d,530d71cc) -,S(2dc043ea,a53c27b6,50e2f1c,b6fb7fd8,26c4fccb,9572bbf5,103356bf,87b3d649,2695f192,af96b031,a41b72e7,a61593cc,30672c07,cedb0908,35ee207a,5cf18271) -,S(71699cbd,e1efa1f2,914bd0ac,9b28111,8053f7ec,d51e79c0,44daa4ac,ded9c9e9,8519592f,a3b05922,86797110,b222231c,fef973bc,d51ea4c4,34998999,63637c05) -,S(23f4668e,40761e37,235dc0cd,41b6c7ff,1951678f,131763b8,7d394e12,6be4c370,1cce4181,2279761d,8753dfaf,8bdd206c,e4cbfc5f,ccfa8826,9d2d4327,431fa689) -,S(92366959,9a173d3e,826233c7,8062863c,2a92b525,106c1159,4885058e,4a7797a6,d1c9f57c,d03c0042,38f898bd,cb45c064,a1f2cc56,222bbc03,a61997fc,877b23d4) -,S(a2dd03bb,a75a7bb2,fc9915df,c66c0b22,76a7347e,6cca3d32,e5727cb8,b54bfb70,9ba4266d,b9c66907,b25c41bd,b96f8a94,a9559830,f171a878,66372067,51c7126e) -,S(79174d3e,2379484a,d3191db7,26073dff,d69a31c8,94314f7b,282ed68e,71395ad7,1cada148,7ded181b,f1a9cd30,21afb04f,4402a171,3a570d7e,9f4928c1,2069315) -,S(874597e3,80449235,af5c10e3,7af7eeb8,f755ebe0,6784d5e3,ba0d1021,fcd3b12c,2ebbde83,58c4f2ed,cc89bd52,e6cd61df,a251bcf5,713858d3,d247750e,266a6129) -,S(f23c1888,c22a764,c85c6328,387e9126,f4ad772c,fa0a6034,914d5f60,7efcddc1,6cd5bdba,cb3c6cd7,4c2c5cf8,1c62e774,560211ac,f1ee8096,be9eee5e,b716881e) -,S(a4c2054c,3a834498,6dcca592,db5fbe06,7f80d32f,8c492436,79c57b76,ae13b96,7ca515b7,8a3d5590,6100ecda,f7066459,db9db34,3bec1b4c,6a57626e,1f560444) -,S(d6880dbf,50d3faa9,835404e5,d723eec8,b1bae88e,b8ca22bb,a85fda5b,6a8cb669,a08c4200,718edd4e,42b775b1,1beb9a6f,eb3bb93,b54c57af,5218eeb9,7aa9fa09) -,S(2dfcf2b0,babd3990,c305cdbf,cae7795b,a2fb3cb6,3ea0cd17,787122ab,5af86bb8,e0e921a,15882601,c151fd93,d7b7c607,cf033633,e6498004,d29cbf76,7fb19f6d) -,S(d1dc82f9,aae7e02e,177680f1,e5d73ae,8a178207,7b5ebddf,45b56bac,fa1f11b1,4c9294c,e3ad0fa0,ceefde5f,fd80905f,ce57a5c7,c6807da4,186c9b4a,7c9d6237) -,S(ff111200,4231109b,d131e7e0,f6434461,ff699d8c,6be3e6bb,7eb9e827,9af4a4b3,2c30b8db,bbe56de5,3d8b3307,9dd741ca,8c7aa596,78a3c75b,a781a77a,e470620e) -,S(9fc4e1ac,28a8f268,c66aec12,f5e795d,f3dc23d5,c515c5ec,11c394c5,e6f2a11b,188bc037,ab114fd6,508627db,12317d0d,fa194cd1,bfd56c1a,4ba25d07,206aaaa9) -,S(bdb0b373,5bcad639,386579e2,aa78fc40,ec2f4700,4b3174b0,1bc2cfdf,f4164f95,45d65b9f,eb1f60f3,29195060,78d5c016,8c6b1820,6afcab34,a2623e1,d2bc70a9) -,S(1386e11f,3950b8d9,e87589da,c3dc9a47,bf36b0c7,8378d2fb,253e5bdf,9f704465,415f50f4,f048413c,7eec4c2d,122a4f7d,f4908265,31f9dec2,313bc7b,b1b2402e) -,S(be246169,75b321a2,edd491be,90b7a11d,75a36c12,ca782d20,732a285c,5a6a1572,ca9109cd,5b041864,5026977,9490edc9,d239778c,25609736,7b52d82d,97f588cc) -,S(baa5965a,c352a017,80b1359,3945030b,32c83b60,805bff01,476ece26,cf89384,c83a9515,dee6663b,b5688d5b,483f0a2e,51c8180e,a130e0ea,48f7a4f0,1d3d06e6) -,S(17dfb33b,957bd5d3,36c918f2,cd1fdc95,23e2980f,20a7666d,bd5e8a7f,8ab1f83e,32ffdb3,db6dfa31,ca67a5b0,27a648be,b978b6cb,7ace4241,a0b6a7d8,ceedda20) -,S(ec5dce25,af07a01d,9dc43a9,e92dfb51,29146307,cef69b48,cb7b6e85,d9cbd91f,1018c449,949bb2cc,e185a9,4a9a06b6,bca4c8b0,1a3079b5,3f86d830,21d46de) -,S(a56b5b4e,d4e4e3a6,29701889,2cf21f67,868ebf37,b8696ebc,83afd980,b5c63817,1cea139e,521c70e3,f0a4b02c,c20345df,90a579b1,20ea5dce,bc1385bd,162adfd7) -,S(2ff27783,681d264b,540df574,b478e3a6,2b919e0a,c4ab1b66,3e279083,25a707b7,3a477dcf,65b233e1,34ddae74,7fa5971c,cc0498e7,be9f17cd,5e34bb0b,480d360) -,S(aea30054,dcc9f7eb,c9dbbd45,cbcea779,49780d59,11edcc19,937e6352,a726b3c0,7ba5e2d8,9f681e00,bb74a353,f37c36c0,7264acc,d6a31529,cd5275ee,94a631fc) -,S(78531772,142432df,81802ec2,84884682,5ae2bc93,aed1fa8b,e345c106,7e23d059,6b8d514c,a0a13c1c,6425e5ad,f808aeff,f88fc6be,dbdfc788,1d174868,efd21063) -,S(c104c683,8448cda2,c94b0303,7b5ddcca,d4db1d7e,e744e70f,5f9275b3,244b8405,ac9e6545,3722e2c9,d7d97aa,767c3235,2a213391,aa2e327d,3884ecd,93f4b133) -,S(d4b02b47,3f851a30,604356c0,e9310d4d,7bd0f9a1,17db0c90,54862b58,969887c5,d451896a,5eba571d,4e55d26,9c3c8082,55c5cf18,f1f2d033,b8d30788,224a68f2) -,S(93d2f6a3,e97e4aa4,10fb6006,f3853f85,65bd14d,aec87192,e61b8f97,93f29b32,a0a840bd,336034f1,a98a0239,c6ab3ecb,eadd69c2,51b2e03c,339dd4bd,7a407308) -,S(7d7d7357,467e23a1,2022788b,2ada9a69,1243fbae,486cc61b,56458e2e,781f8f3b,59d5566d,97bb583b,940de406,44e19530,b1bc7ced,2a00c50,f4bbef30,d899e7e6) -,S(ea80f7b5,8c72080f,f2d83604,ccf6e4d3,28a71914,abf94888,8dc87c42,15fd4a6b,ecc6e626,f01f73b2,5d7e92e0,d1220b82,8f2f8ef3,3cc92111,3d15bfab,179ad8ef) -,S(c74366e7,26949fa0,6913e6ab,c41cb17e,c3837659,253c3038,30d543f6,ac0e4aa6,671ed272,2626ab33,14b6b1d8,1cda24d2,9fc132f9,51f97b95,8e72bc0b,9eb42d3) -,S(6170ed4d,c3dc2218,2b45c1c6,fcee9fc1,3897ac17,fc32fb25,aaf2880f,4cbd11bd,cb40f34e,7e8faa89,71338834,21cb247a,4c938f3e,f6a97cd3,1711f803,c872621) -,S(7dacf9ad,5775fa62,f99e093,5e948526,b94ef22e,912ae95d,8dd4e5ba,744a2ebd,69931690,6c73045,d8530a39,d33a8e21,d5912969,9f7b721c,1dd0c616,725d5778) -,S(b1d113f2,ad7b487,908767a0,b6faa413,6a8b3dad,41dad9d2,b6e8e7c,9f294639,7c802cbf,4596903a,90b1de93,649bff3a,6f63ab85,a9e3529a,7d907b41,7f973b61) -,S(d09d8d8a,17a1b113,aaafc270,db36ed63,4342d90c,64b6ae97,9733391d,eb67f3a4,c48701eb,738c3edc,a4f78313,a56660f5,3da8ebaa,3cd8d469,d1dd5910,c618851f) -,S(c264ffb3,c223e60f,fa34faf9,feb18668,4b05b7e0,6770db1f,9561ed5a,ea0bfef7,e4df501e,ebb4cdce,bbe6c4cc,b966de77,18ac5479,3e403e79,389ac330,92928e6e) -,S(55505edd,605e4299,afb5a69d,81f6df34,c7c2133e,dbc7bb10,ebc49187,857d7c49,ddc19610,7c3bee6d,ad955e1f,76afb31e,93a88e4b,de8aee59,aba50864,c295a487) -,S(9d61801b,a07c358c,f9942bd,d3614d3f,74904b8f,8f8aa8e6,a957eadf,79fe99ef,7d9d5980,2fb5dacd,93ec6c6a,92ef86bb,6079076f,7d964d31,70e3ad3b,7bb854a5) -,S(f1a6cc66,3dbf46da,e1ca98af,610f09e5,e9251a44,f6b9915c,b68c58f7,9038645d,e41bc6cd,747c0390,6d29e29c,4cbc2dec,6817114e,daedf220,b7fce48e,7e6f42ee) -,S(df247558,50b523d6,de15c3ec,38537a3c,af9a90fa,2c0e8b25,35696289,10517a79,bb567ba,e42e9899,85fc478a,4303188c,2da741fe,bbd1742c,818ec1c,e64818a5) -,S(4dc30b60,b174bb78,1f339277,ce3996f7,fe102e13,d80873b1,1a9e6b4d,54247cef,b13e5069,a7344a99,4f9cd284,1d9291a6,50e1d969,dd3061dd,ef34f037,7c85e20f) -,S(e77aac3e,946f7715,b9d0999b,1f3aadfe,de9c31dc,f8eab336,c5bcaa51,f16f64a,9d78c14d,90cb37a3,835d23,fd8d5a37,2b8fa160,1274e5f0,2bae50f1,587a11bd) -,S(24f29bd3,51e62864,3a7d2fa,6c47ab78,a6d0c6f2,c73bdf00,864e8bd0,c3f038d7,4a34c7f0,22e43220,f6d30d59,3d3ccb54,dbbcc50b,4b845712,e72636da,d0cecff3) -,S(ad4b9b47,b9cac9f8,a5f3728c,ec610000,163ac2ec,6a18cc34,b630134d,9fcc9364,afc8726e,e0f988f0,53247177,1efb25ae,e07b70ba,ec7c425c,50e3eae,2898c077) -,S(1d38128d,ce7ede1b,265a4f8c,4e6b911c,d0e28087,87244a60,dd9f646e,2932e509,857a6c8,e4f43cfe,129e11bb,462101d7,9c76e99e,c7b4aed4,efc029be,b1b9c1c5) -,S(c171b7a2,7badcf84,c3c61afd,7568d23,5a14f0f4,fec777b,4a91c92c,61358677,cde264a0,48d2cd4c,d53d7371,8546802f,1ab67815,d6ebb3cf,b6415f4d,5cf4057e) -,S(d50f20d6,f4781aeb,eeca2a8e,85e8b75c,187c6d34,a940266,daa16876,96acef4d,9aa99671,35a1dae1,af29ed05,9fa15eb2,a4aaca27,99d98c64,5ae0ed03,7f08f37a) -,S(6b83cb07,7bfd33d,181fc835,63eabdd3,a50be6d4,abb64a16,e338f18c,c098a977,3e04e660,cfe61fd8,1ec67b2,d20ca9fb,f9c6e038,71f7c838,b261ade0,51b564e9) -,S(2e75abad,dc0501f3,afa90484,e85972b2,679d1d04,62d6d206,42c73830,15213b19,4754077d,a6868edb,a0943397,3c60a581,88a55ced,dee38351,93ce045a,e93517de) -,S(8a322085,d749f63a,38dcfbba,624d0c87,b9bcb66c,e4e3d84a,e97f7781,a0e9a164,3b592b8f,9d8cc10b,58fbdc7e,982e3fa6,7aa67c90,e9ca884a,e1f57291,6d7e2076) -,S(b890b7f9,ba1f1945,2a7bf1bf,944f9949,36bb4ad,5e2e0fb8,15ddc1e,2f30d72b,c1b652c4,f8e9d91c,8a92f76e,f6f72ed3,3357b35a,5ac00d63,a039df78,eb778a46) -,S(cdf33d41,c54c8a0e,dd3a0b1a,12290d13,715de82b,21af5306,a1197444,acfdd5c9,2d7b78f,31d08fc8,afdb3940,ef1afaf7,3bf37029,1e1be3c9,5acdc673,ee2150d) -,S(20b24e10,c0f85631,fb891ae5,c0b0b36e,5a3829df,a5018c1d,8b59fe87,b051b55d,b5b9204,67394039,df0a34f1,308b086a,454c7957,40d31fd8,960f6ab8,33998c41) -,S(61976c23,257b9adc,48147038,ff5ace08,39d88274,9810bc9,25590555,b0e1c709,2b31a4c2,a712edd6,6b2da3f,84447c73,f2e3f652,d22b81d,d37ac4a9,def5390f) -,S(4ff22758,a2a25681,d28fbf09,e4cea5f4,74c00681,d9b4fe6d,ef3227e3,6092b52e,4b0f517a,4e56697b,37341ab0,6fbc92e2,4ae3d03d,392c33d2,377f7432,10a89fdc) -,S(46145b19,639938dd,9c6c84eb,d4180cf9,752cf9fe,a77ca609,5ffc8f7e,ead61f35,5b7b55dd,8a5e7d00,a3b62d20,2f371d42,8eeacc9e,7556547d,f2396c85,9503f6f8) -,S(32464689,a5d7626c,fd02b5fc,da68a8f8,dec32eba,887b523c,4b4e379b,c40bee7,6e9cb8c5,3fb716c0,b583b356,7ba6890d,2cdccd39,646a49c8,132ef061,d89f6710) -,S(56438894,2c9aa575,efbaec77,cbecd9fe,79fb4461,c61ac051,195ae384,dc0d6ddb,663528a4,29696073,f9d47d2c,bb2c256,9bf6c452,c171ca43,7cd3480f,95b69a05) -,S(f04fa37b,9c510bea,ec12fd4a,307b1b0e,d934fa1c,78cbfbe3,bf904b00,91491e4e,19b7da4d,826a314f,586c4c78,457a3075,76f3ada4,61af5bb6,c374178c,23a79326) -,S(36fe4596,b1ca6409,741f7a0c,b899f89f,a727207e,eedc8e57,504847d,2cb304cd,78f11f,4473b124,5772a101,564b6468,43d4bf76,afacf02c,bc45ab39,c7221e19) -,S(ce3e6d1b,f2deae03,8ea4333b,ebfa026,d1954ffd,f50df66,e2899b05,1ee87b0d,4cd4635f,10af69c7,50e96ede,e4f38591,2a14b104,ed9023af,60ac6e93,a9b9bcb0) -,S(33ad3a7f,a6008875,74bd735c,b2ec5dff,10ffc5dc,3163d8d1,62644086,888d29,8c959ba3,2f7b8ed0,4cb2bf2f,2b5e5f56,b29a851c,8d1f6bff,b48fab31,5335b3e0) -,S(7101a2b2,36aa7903,6348006e,cb8f81f6,b481ed8d,8a3081aa,40ed475f,13fde43d,d0a93654,51471aca,80a05745,57b4a24,9d627dd5,c1428ed5,79feac02,5fd2cd2e) -,S(ba3b4042,9c0bb526,c31cf602,3f9abe17,69974344,5e66566c,851501a5,d125471f,7db3e93b,e9944c42,b1654407,6d5bc6a0,99806c67,6cc7415a,9d110661,f4c644e6) -,S(57c6a582,1da61528,dc291aec,3a9f1a86,229594a2,27767583,5687ee91,15acd72,a9e4750b,5580b225,7768ce7a,b2909466,589a1a12,2e54a7af,35f44de,44cd5dce) -,S(c8353ee5,847efb7a,ec03d949,633132b3,9ad898e8,9a367c77,7b4a2ece,c47a7c10,dfce02ff,71060be,5e12d377,524c798e,97bafd6,e9aa9e10,27c07a8d,6f7d3a55) -,S(b0f6ef67,78b4ee99,6d7807ca,9f1f6f44,203eed8e,62584c6d,666e3698,e41c0eb1,b92763af,c9ea095,f757e921,ac0bdb02,605eb66e,d3e1735f,f8f17e63,dee5460e) -,S(f2e4015e,62645bd4,6f858b25,cb636f97,6ccfe5f8,da065b65,1ec170c,ecf5c411,8c05cf9b,19459597,7c1d1b6,4ff6e902,5d78a175,6416e0a,ebf33c21,7b3d5dda) -,S(ffcde722,ad4a2223,24396b52,5a95a233,31dab41d,95a4e19c,1a23c2e3,db7460f9,f7282903,525ac2ed,3f9db21a,92d3fe4e,b1635a8c,77dcbf8b,e671146c,8eca8115) -,S(81dc05b5,2d9a210c,4904bbde,cfb4eacd,8b3f08f1,d667e9f0,a27345a9,7d37b37a,747aad1d,bd0003a6,d89f9d9c,fc00977,719d24a5,b8ebb807,98d1b644,87105f5e) -,S(5b92318d,a267772d,94656087,8d698aaa,7d2c721b,28dfbc20,9e4a3e8d,1b0eef1c,b2d274ec,7aade417,4f2f8766,1b5018bb,47c83d32,b2fed50c,437348a7,93041906) -,S(3eabd0fd,6b5bc51b,c187c943,511c3005,8f86e474,8547fcd6,49595070,26fb805c,95e8bbe,8187398f,fa4ea4cb,b50bae2,19f8cc5a,5f09503b,3edd115f,729b2101) -,S(a64d3807,f92b91e0,717c310,ec799908,43e3a394,a5ece3c8,7c3bb209,8d3123ae,50fbacf8,be11f6b0,ea0e36b3,5c46bdb0,8fb79064,59b52901,9af59b1c,e80ad239) -,S(db9ce153,7cd47f3f,4b08858a,d429c975,9ce6738c,2e6d56f0,fca12e70,777b83a1,a91b2016,9fb1e2f,fd52192d,7030d86f,66358516,5ba32829,6c9aac95,192afbf6) -,S(bea03f49,76ee0a86,e00bfddc,79e52173,1baef841,d751ee47,9a46cfe7,89de2399,feec1fb0,3901a923,862054e6,7024ba7f,4c485c70,2ff22aa4,1620e857,6dcc863) -,S(cda308eb,6975d59,db439e23,32505d29,4ebdca67,5373ed79,25b52a6e,f60a33c9,7d2053c5,414c9bcc,5155f17a,6fc206d8,81cc882,54341778,1c5db51f,3ce4c224) -,S(430bfb3a,802988b3,a68d5595,c989cbe,75d409d2,68dd84b9,a1d4a5b9,42360174,3de4c6e1,3c87338c,8bef6195,6559335e,bec503fa,2025529b,b015cac6,6d8060fc) -,S(b4b1b7c9,932be243,6b06b2c1,e5de312e,4a409498,11a226d8,5bb30c5e,1487c36d,e169a70c,b95988dd,fe1a98df,527fc172,61cc3103,88d41ed3,4bff23bb,31da4dc0) -,S(7a954055,d2d6acda,8dbe81e7,46310113,e26af09b,91cd59dc,92a479c6,d6079ef4,83c6d3ff,4582eea7,becaf8bd,422c0558,a2bc8d6f,cb615c59,7c46982,47cabcb3) -,S(aedd36fa,91a7f95f,2b2f32c9,1be77860,75783bcf,8fcb20b5,f20ca664,dd89474b,c747f32a,174ec6a7,936f13a4,7e80a2e9,324b7f5,e163b396,218c4c35,9391e565) -,S(41052d48,54402d09,a813492a,2f9362ee,9799ffa,3d270200,45a0ae07,9f913f60,97cbdcf9,b60518c9,74ddd987,386d60d1,3d10defc,8fe64511,843d5bf7,13774178) -,S(886e5afb,69f6debc,c1c5be6f,b636eea8,7314ff1f,975cd96,9070e376,c1a9973c,6a8ec4b7,98fec5e,b4a8d645,c7b72663,d6bf4aff,8f4f4b36,c064bf3b,f6e7b5ef) -,S(c93adec2,ddf85ba8,d9147c91,82ee4fbb,5727081e,a6938c0,a4bcfbfe,6856dee8,9ebef5d,2b2253e9,4474331d,b52739c1,71214093,aeab11e4,e51a2be4,e201dfb1) -,S(d97166fa,94a4e51b,ad21e1d9,76e01011,655ce24f,5f5afdb8,feda67bf,8ae65a83,815ac894,57f83bf9,5579fed2,ea470ad2,ac1c83f8,546ef3f8,bc383701,1bc62a48) -,S(c23cf94f,c5a93aa1,719ea8d4,4f426fd3,d48220cc,10ea558e,e4680c1a,dc91b18a,64a4dd89,8f36efa6,efce9354,fa30f506,be3766f3,a31839e,1fba56b,5a07ebd3) -,S(7236b1df,88751e98,2689e049,c5084b71,b8d7979c,2c412a3c,995e61c7,2440929a,67155955,bf5d1916,9e36636e,ba56fe44,f7cef6d1,b0afd3c2,beb59b26,5e3b67a6) -,S(d1890a85,df4f7933,ff72fad6,5b95f5c,c9fd8683,3c1bd2fd,56a3b7c3,e90428d,8b4896ad,4b4469d8,af074eba,ac38563a,ca68888c,5411ce0e,b3701ced,75d4f87e) -,S(41ae85b1,9fcaf4a6,13901d2,3cd2376,62f299c9,7cb306ee,8ffc13fc,75d54e15,20d99cc3,215f0b1c,20922ffc,6e111b53,e88ffb39,bb6e118c,61b9e3ee,fa7d01f1) -,S(d125489c,4e07c44f,35d39008,e4e29c43,c28ca505,3e370570,a7bd34c7,57e673f5,d142e19e,825ff93e,b6661160,b60d4e06,b4393388,43500b29,2d4d62a9,28db2bd2) -,S(8c50b3d3,667b2aa1,a60c425d,1128d389,f2786b3d,656ee126,dd57af96,ebaad9e4,55eb7ca1,c2bb5881,7f82cfc,c8b5ca35,5c2aec5c,68dd479d,948261ee,d342fce1) -,S(3e77a3c8,a2e995b7,582f502f,9bb1230b,35311af4,dc8d0744,9211a13b,444fd42,99c427f5,8365ca18,75272508,7dc57985,d59d72ed,aedfd5f9,d61517c6,1fb8679d) -,S(73ffde64,80547448,658ae5a8,529755d7,2ad7ec84,5711f0b3,20acc53e,a15ab609,786de118,c6a0daee,48f3f585,d10b9f2c,b4947661,b844ed51,59903ce5,f2cc8d18) -,S(8f2ec78b,47c61a39,c2ed1110,902b3a43,4fc9ddfc,b11b1ed,75c675be,5b8a172c,441686b5,c1327f0f,d2bee35c,5d8f2aef,b6da72ac,e6206982,6d6812a0,5b937346) -,S(c36c0376,d360f87d,28069511,7eddf1fc,75ae7118,5fd5a82b,b47d8fcf,519ae4d4,44c31c56,cda1c2d4,41161ab7,45f3c0,25c4ada3,72396658,cca23f93,bdb6a303) -,S(1ff06490,3cc7e686,d408909,4812a7d8,531c4188,ab8aaf4f,f10bcc5a,9cac352c,87af78d5,3122ad89,9a6a1297,fcc87c1f,252bbf9c,d8cfbf57,f64cb6ad,fe77f3a8) -,S(1265a4c0,6e1f1a6,126a9e37,a6e4f90b,290fe449,49b82bca,8ea73759,451e0b25,4f0f7a6c,9bc7f00c,42b90d95,95871176,d723941e,38335581,8f7aacdd,f830d15d) -,S(2595358e,4d45d362,5fa1c89d,a3249cc5,a26ec3d1,e554a863,51b79fc3,4eeea90c,d9b8d147,e4e00450,1baeeb5a,8440235a,88913063,bb1ffa78,9402c3f7,2c603899) -,S(3f432621,7a5f415c,b028f338,40fc226e,5906a09b,d054eb55,45609fee,90135082,a572303a,131fb0f9,c63d88e6,3520ef2e,77bcfea5,1031fa60,fada909,a610c830) -,S(9ee85c9b,4cb0102a,6b21c517,947d798c,c26dd853,7bb5d6c0,46a50144,f3297f45,85b798ab,c2e4fcdd,bf3e17b0,49e2a495,6239ba16,9917ed08,ebe109e0,4ac8016d) -,S(479c2ec0,28e8c83f,d7946f43,8d802ed3,d728179,55d94c55,bdef5050,67774934,c262229e,23eacd99,f9d3fb37,b7b9040,47cdd5a6,6872f4ac,800dbb3,d87fc3fd) -,S(2a52f4d,821cf4ae,758ed477,6cdc3bc9,2d3924fd,97a12f1f,4dd5a646,24766b4b,28500754,6ca8f142,6f3a4a6f,6ccf8437,37c6a917,7ab59b92,728f588,f11509aa) -,S(d89159a6,d5447ab1,bd03d44a,a8db3410,c86305b4,4f06b25,b88c4244,5ab1e929,c539ee3a,e7dec645,810c4a02,e1777977,d98ddba2,281d5701,2ed2a4c5,85057013) -,S(c91267af,4c303e07,ad82c1e6,2ddd45d7,cfae00a8,d27a34f1,eea8d15c,1add920,975967db,347415ae,24b427a1,b8f7229f,8db0758a,7ea13f7c,582c260,c0711b85) -,S(c860be31,18ce92b0,39b27a50,960d3caf,88e24bae,6e45fd8c,5a253a78,e3d0e6cb,15b8374,922f44f3,adaa213d,5e3facdc,9de1ff6,4da677d3,d89f6e0a,a800413f) -,S(eb8b5f4,2fa90313,b3dd7d4b,d47338e2,9861e52c,b492e9dd,6a1897ec,4da14c14,9d1c4d0d,56c570b,8835e188,517fe7db,490aa6b2,bfbe1564,579e7af9,c0647bf) -,S(151e39fd,d5961da7,44ac5871,94081a88,666d3dda,6507404b,607d449f,1b3c005f,476bca6d,6bfc5e2b,2c183794,563d35ac,aa8d38bd,ec3846b0,22831bda,38fa28fe) -,S(b46d2d52,b764f922,7ead0399,c391a9db,1737c9ab,35394951,5a57c76c,c3c05c59,8aeb78db,db1e52bb,a8030a3f,b9f57f6,644332be,6d0ad41c,34b7fbd3,13c6eccf) -,S(a89e77d,30c66dba,a27a2dfd,5af0684f,f6ccc84e,49b8d98,f402a88b,20e5bf7,af45b2da,cffcc49d,4f6db574,29f13971,c74f5321,4dd4af49,2bc7ae5f,10abe1ec) -,S(8d774c5b,eaa0cc57,7479873f,9bf5ff6c,808afa4c,6fa6f2be,88b53841,4cd088c5,6b9461a6,600ae1ac,4e617149,73fa8b48,74dd7cc,9f331eb6,e15bfcc3,2e26eb63) -,S(34ecc029,105f5e19,d6c2471e,eae5b671,cd55f2c1,bfba7dc8,46787c92,ba7de2a3,13e3cd9a,db98a6b2,433dba08,ec7d40c9,c2467878,f6f4bcd0,ce60397,67aca327) -,S(41b10298,6889f83e,e89d4f8,fa50898b,c9bbf650,2d153c36,85064c9b,f3dc3c43,559f5bf4,fb827bc,dd068d3,cdb14d6c,ace08a47,c30e3fc7,8972ceb8,9f88c21f) -,S(4a77505,79ae33e4,55228533,b8856da2,b14f70a8,d13ac2f4,f6bdc5eb,4f5c9aba,d365922e,3a487635,3ee1b02b,511c7926,e5c5edfd,aac153e2,686ce4df,b623ed2f) -,S(173af9bc,efacadf6,c107748f,278adc1b,d42174e6,8fe06d9d,f84fe278,70eda280,7b120d62,2463b94a,57303cfb,2c477f95,49d41a66,d6ee7c2a,4c652284,b8535faa) -,S(f0fa5cfd,ba53a5ba,df707983,134c3459,5ba232b5,7fb67a94,5c5c0f25,a0539be9,ccbc91a9,c0a2efd2,3bffec87,cadd16dd,f4292aef,a59b3d31,6e9c7082,742edb6d) -,S(a5df803f,751c4846,10799c60,db405439,9b1d5bfc,c99fb316,fe884468,e57ab77b,27f8f706,a2f08ff3,249f8b62,ac0d59b6,31fe52fa,7ab08ad5,2d09ff2c,4138dcd4) -,S(d165fa7e,d61c251e,a93e8f16,c9291b09,1f258720,fd303a3d,c573131b,d98628cb,cc0dee9,f01f0dce,aba94461,1e48f9c5,282a7480,eded0794,81d0b8c,a9819a73) -,S(87703371,46a8694e,2bb5cb10,76ffcd94,309c9c8c,be6e8cf6,5a77f4ca,4d31efb1,ee64af6a,5569a205,2cd98c10,871b2ba0,6addae3b,3cec463f,6002d86f,b16e5e9) -,S(1c7e4ec7,c090906,3d98f786,dc22db53,da4d258d,6e75cbae,30d4b99e,f4ca47d4,d2001df7,3297e6ec,c0aec17,e72cfa6f,5951e2bc,f03e4aa5,5f329c77,47cd92d8) -,S(d485ec0a,1a0abc6a,69f308d4,c7f8b8bd,fff5ac6f,ad4ae4ee,271a87ce,973b58fb,68f51764,ee705265,3e2f7d7b,7415847c,3856e3e,1a7f4932,6fbfc9c6,5976cd48) -,S(ae5ab510,48215ea2,3be55d93,4e0dce0b,ff88f09d,10c8953e,390b79f2,da26e43f,9f80d71,36a5da61,7f90d0c8,a6d9aecc,5cf88abf,6bbc2181,5f8320a7,2fa8929f) -,S(cb879f42,4613487c,24aa73a7,36f211ea,96541877,33fd7091,40a824ae,7641a708,d46a4ad5,7f607301,f61648b6,e99891d9,ccc41af1,af29a66b,b894575a,a6b3d5a2) -,S(1e8d6ac8,ec0b543d,1e0aea66,7f35b556,87e30be0,72841fc9,3f599c81,4a750d7e,8965853e,6519ae5d,c523cb52,720b004f,ad2f03e7,aa3e0413,bc68efcc,c0617f85) -,S(dd8e5b0f,be63df6f,5c20e447,778f923,2e1b2c22,4d28cfda,b2c672c6,66d05f8c,d8b75f77,f955219b,d4d95e65,35d5cb0d,23c2a1d1,671b9416,2da9c4c9,b2d4a94a) -,S(78ac44e9,938bf51a,691132e,93ec3a42,22be3185,35209054,a76b87c6,645e0252,c0f66cf0,3c20dd,d136d1f1,cc00eb17,efdf2a4e,72d373a3,99c20da8,8342299d) -,S(d53110b9,5034e916,d904cd15,1170761d,4f3492ad,9e257265,3ef37739,df9bb035,c091177d,796d199e,5c05abeb,29d0df1e,e5ceb93,d272e6d,d254b6d9,a6dd35d8) -,S(868b2732,3debb9aa,60942498,3be71d0b,451ea44b,64c22225,2af3d63c,3eb512b,8951dd34,39774c8d,89cf4b4c,485889e3,df2503a,102ae568,c63fa74d,23ee659f) -,S(672de7f2,34e96153,d83da7fe,3e199099,52ee988d,961620ac,b8c6b4c3,520fc50d,ab02a8b5,2a2d9306,8a83a0dd,23ff882f,b1052f22,72a0ad11,cea13c63,4efa33a2) -,S(4887f473,af8189d9,c46ae22f,c86ba6e0,f03c81a1,490de032,72b07937,b63a7527,a2e7a713,e1e6691a,ce09dc0f,a86c92b0,a0097899,7fbf26d3,98581731,a577a21d) -,S(f97ddd77,38bb419d,ec051fcf,a93753ff,e3dfa122,6cf02e1f,23afb376,7a121440,2fa9c241,f747fcda,dd09139,437eafc8,94e7a47c,ec8a7ffa,1e054ce9,21d73243) -,S(ebe75f9b,2c92af9f,11eefb04,3456f6ef,f616d1ec,b616a9e9,9e7f8960,4f1d62fe,40b5cf37,b06cfb0f,294da3c0,f756c867,af06449f,e2a916c8,a327117e,9a47f74b) -,S(10d376b1,1f0138b3,238deefa,b57dc84,7ef66849,14e9f120,1a9619c6,b1715a13,a216f393,1f398b67,d68a2888,1d5a31f6,e5e0da82,e2b5060,4c6f6322,9cd21748) -,S(69e26679,f103a1f9,8a9a4d88,c973874e,db7c82ca,99e48554,37284445,b55517b,cab62aa5,13b41a9c,56ea455b,6a880b95,9d400bba,74e7a203,7b60ccb0,4a89b8c8) -,S(3acf827d,81e39933,64e99fa5,63f89305,dcc60b62,44ecc0a6,b101c6f6,ecd5bdab,77e3bd28,40a99c45,30ab7767,4d8ed17f,f57a4f1a,4ab91732,7059114c,c06fadbf) -,S(2e5125bf,9e263d80,7a220063,434f928,d9a4907f,68601eb9,829041e1,a7b89bc4,9810022a,d7d3c333,d7c022d9,d0779b9b,5807226c,9fd41e65,c3fc8e1a,a7a0b51f) -,S(7b68da4a,197f6bdf,56948023,d2baf10c,9449d6b0,b18addc,49385125,e62506bf,85a92b7a,190aec87,bdcb9df8,42e93917,9254ae6f,b45e6764,32e410ef,4b28434b) -,S(60d4b53,9a29562e,8fab8ad7,3b699550,3fe7d6c1,e2ba1465,f05c92b1,61dc829f,2c2ad439,8fc7c836,5b2efcf2,1e4d0156,1a753f5e,d945ef2,bb1a3394,203d07eb) -,S(5a3a1bd,30250a40,d22aed42,71892b88,3c03ea0a,baba458,6b65cc50,4c79b107,9bf3bf42,df1637cb,80c1fef2,cb9bfaef,dcbff761,89cf9f5e,d00f0f4a,e551e31b) -,S(9b9d93b5,6b70fc67,5476c6a,6913e173,11ed1ade,6ea7b810,b9c90977,a8f3707,ae01a481,7a9ce6ef,5584a48b,fb96a9c5,21d5bb7e,2bf73cb4,b71f4dfe,aa7da298) -,S(44bdd82,86a3a4d7,6ecad7f1,ef66022c,6a49b916,3d7a8ccd,e54bb017,814d2f70,26d345a0,52034ce8,b4382905,f60f8885,e20afd4c,54df6d6c,ccd1c2e2,5d06adaa) -,S(8de8205f,e44946c8,582dcbe7,152dfe3a,7eb85e7,bc070282,3c972727,54463869,1dd97d78,e12a92f0,cc2145ee,db4ef561,af21d3db,f3cb123,ce0bb582,6791a30b) -,S(c36a713e,3d88ae25,f79b4add,90c6a724,77be7d9e,a62ca0ab,2d5a800d,41f9321f,2df57da8,6cf17f7d,63ebb85e,e7570869,cf90b462,e76af48b,641c07c9,45a638f6) -,S(1ce37a88,f25b8b81,941db8a6,13a7d952,c2cf868f,e979bc0d,5f35410d,147207a8,7fab8cb5,f6611850,e541dce2,315a7833,3999041,5c18ab0a,718dfe32,e0ebe992) -,S(e489744b,dbb11e61,a7e827ca,ad18ba55,41f4c02a,b50b75a0,353f4a2d,f504d575,6abad3b5,3ad97e6d,a301ff7c,7931f37e,55246ab4,c7560,363ff214,2cb9a398) -,S(cb4ec0aa,c1cddaf1,c7a67507,5cad6762,cf8ffce7,6a06f76a,38bb88c4,5181ca3d,7f15e726,5092287c,d2ccf3c5,dfcda0c1,8c63f2ad,21c06a2b,469bba5a,d9e4ff36) -,S(aee1c436,6b923847,40127dc4,150c6dcc,ea62864f,394415ed,9a39d539,adda44e6,2496d2da,97990e6f,5fb1526d,b93e92e7,8a011c33,61218d,c3d3c56d,952f8666) -,S(a099ce61,d950fa1f,19abc21a,79c74021,472c46ab,d8f67798,34df0429,ba785491,c4dc483d,6d61ab1d,7578ee0d,7548e0b4,295891a1,39774c22,7d073232,f2f3ecfb) -,S(6c57db5f,b194dde1,b8cc9686,fdb65fd4,eaf8aba1,84434344,7a770ddc,9055e429,2dfb48f1,58663b3,6a7747e8,4b5a9001,163ea20e,f07649f7,1d7a21b9,b11995e2) -,S(f6efa15f,20b2e91b,cd7323a6,51e5d7b7,a8b323df,924c616f,21a7d6e0,e34d3c76,ed48a439,2bb4d596,58e75757,95a0a4d2,7443415d,7662a535,a6246d64,3804fc1e) -,S(e7983476,a900be4,e9dfed94,42f575e6,4d9af362,1e874a99,576e06e5,d31485f8,9d21080a,8b0534f,6b2dfff8,9eb8172b,cb5388ff,d910fdfa,405ead29,9df779be) -,S(88ffff0d,7b415f76,8c515d80,9c607949,b469b07f,3978caff,1ba64e,ce198ba1,6816bd9,ab0e773c,38b73787,2881e96b,8eaf381,b155b205,79b24a39,eb9e0fad) -,S(e5fd2c3c,a1c85b03,3d93a3c1,261a5c1e,c4adb72a,7700405e,7c0bb108,d8fec1fe,97bdee17,50801ab9,a96e3fd4,ec4860,e59034e5,c02f9168,79b1e654,5a65fd39) -,S(fb010f18,146336ff,30dee37,b25aa384,9588b83a,bf943125,613d2c72,c2f5b3c4,4b0ff7e,7a6f15c4,d377e92e,73c8935b,d2d9f7b3,5be91cec,da891f61,c7631bbb) -,S(9be574b2,c28b1460,a1d67d94,43e4bb85,c46a6bcd,a957499a,179cc8f9,7ed33c2a,16aada1a,367def6e,d4f34409,e0ff5d41,f3854494,6a764040,e1109574,109bb310) -,S(358e97b7,6799ae09,b80b6797,90e34630,3d61fd4e,71733d6b,3c90fdee,2ad44bf1,3eeb5209,175677af,c16a3869,5ff7d3a5,e9704201,b802ec33,50c6c2ba,c0ff4144) -,S(2ed930c1,c941b209,b6e7cf3e,83971e70,9e36bed7,a4d3884a,faaf013d,5b589b59,ff6a5a5,e601377b,9dd974bc,4fe71e36,403f2cc,90b16834,b1beb6a0,98553d2e) -,S(d86110c0,6e8b20a2,e6da1930,fbda70a0,d8c022e3,e68255f7,262168f3,2bd58986,34dd600f,9b7157cb,2ec545e5,c50b3f95,2f422b21,4afe255,b7337815,1f3dc048) -,S(4e7ffdde,305ea002,f7dfadbe,e2da926e,6d2c2714,596fb052,7eddfe92,81d4fefd,fb4dc1e9,476cb2d1,3bef4548,9ab7ca86,6ccbdd71,4cfc937d,bf024f12,ff04eaef) -,S(6ba04fe,47c4c99f,849fbd68,7e1ca6f6,3e00179,3ba3a08f,86acf668,df0afdfd,dad78b7a,9d34c738,31112801,91476b92,b8eff31f,fcaa6d,a0704244,5fe32e37) -,S(bda2c2c4,86029d0d,b804f1ea,e9215150,34276a88,179154dd,d5d9f176,cd7f50ba,a70291fa,47b98bf1,fecd9aa5,b53ca619,41d62c9e,c8b02ea7,91c79482,afc8f1c3) -,S(99801a16,4da92a6b,de6ec7a2,69c2798c,b421af01,5ec24c8f,1b090169,18980a5,3af209c7,de27a683,56f242e3,8805a368,66cf7780,60c2806d,76f9eb06,35c18358) -,S(67fcf955,dba84390,638517f9,5792d09b,64c056aa,ba98acf9,d63c2bbd,df5f021f,96f96080,b5758233,ee15e8c4,7ffdc3ae,bbc752a9,d7697e1c,3ec3d479,4f912d2b) -,S(c15990a0,50c2946a,e4518cf6,84ac9cae,1022a29a,bd88f8c2,c8e724c2,89b954c6,611bc99c,e4ad5b6e,3ac932cd,e2e70e0b,a3690ec,758bdead,5edb3b0f,b5b95d56) -,S(c5261ad4,f6d03a0b,c15ace20,aaf95bf,94d9ab5a,95a45d90,6ce7a622,3b09d59c,5fd1b7a3,b22732c7,4b5dc1ca,fac99882,467bd80,53f2f606,ca5af8fe,6d741448) -,S(b0bec3f4,eae81fd7,2b70027,72a49acf,46a5c50f,48358df5,e174eea3,c0da88a4,13a4cf63,fca873d6,cf1b8c35,ce25f439,4d74a5d2,f2fa2799,d4c3bb98,8b50ab67) -,S(e3d32fa8,9218a38a,c503780b,dfe23dcc,e6a7138,d84668b3,f71b3fdf,891b6256,246ebe20,7ab7c536,8f7c9795,9e7aa1fe,69909d50,f4b24263,c32b8bea,7674b85b) -,S(ebf3bd9c,1920f625,4c32467b,7c1c138d,3ac6a4c2,b185557f,6eeffd7b,2aae0d63,58ed82e1,25fa2241,2bc4397e,73009692,af1d5feb,f640a422,f52e5cb6,42d4bccf) -,S(d062e72b,3dc76d03,5827786d,a9cbcb03,b710ea61,2eac883d,b7f50df3,fc6f7175,cc56b076,dc3cf1b9,e544858c,1a31723,33ba9848,a8c463f2,abf2c6d0,dae14a6a) -,S(97444eb2,32b09240,fc596530,374da035,f5ebd37e,6c74b51c,8158eab7,8ae30f89,fa06190f,d2072bad,b9144f72,db18819,ba76399e,d171d4bb,1293c20d,63d70391) -,S(3e1ffac8,15f68300,4714f302,1ed39460,d5e4d63f,6fdc445f,12d8470f,b273c242,86f0839f,8610c4cc,6ae85d54,b951441e,efb700e9,9ce54aa9,fb6c7988,a8494c25) -,S(deef1e7c,12e498e8,6542acf2,3782ece5,2a02b13e,3b4e71cf,e39e79ba,541d2679,e039a94,f4b169fe,a13ed182,f9e541e5,2b117536,d90024e6,9f3bcc7c,988714cb) -,S(69ed1a62,b3de5c,c5785b27,c7926e52,4ca1527,9f8a00eb,b5e1c247,a6c8265,9c5fce7a,84b79a67,9f3030cf,a179a682,cc22c464,11ffc8b1,ceb885ab,4753de36) -,S(cdb36419,5c3be45a,bc9f58e,e5a499a6,ef58ff2d,296ff989,9fa987c6,b753f82c,34a1a6fb,7a6b6c95,2a604340,d2c30c15,69c46123,e5cc5318,833f3a3f,bd622e47) -,S(c5749ad9,f4583689,f2ed313f,dc35fe8,acb6a85e,dd0498c5,ddcd4842,fa21c555,f22ea47,ba61044b,54ef967e,c8c82167,3d14d710,334784f6,a7b46d48,19f99cf6) -,S(fc86862f,b2fac126,e4341121,c82a9e14,d7a48b9c,988b8458,300dc3a,ba10dffb,42339dc,e304641,f814327b,ca5a611f,3638d610,85826d70,3d94c76b,8297f6f9) -,S(66dd174e,446ae0c6,3ded267a,faa20ba5,62131459,5576d10a,1e44ef18,69e36ca9,d93a449f,6d3fef4e,435f6fa6,3191b625,b883c303,1dd8b380,777b556e,acee9df0) -,S(736a80e9,15b39c21,5e5efbe8,ed6f8fff,7aa826f8,5c940110,3c7ce372,86d952c6,4a9e17d8,9066ecb2,95447058,4dc58c36,c84b3d9a,30ea45cc,e62454fc,ae13e0ba) -,S(7b747f80,f4a324af,e6042edb,d8682d3,1b8fe12e,19936844,b44c3e73,f6b7075e,c2684490,56e7633d,2add97c9,75079594,b9c0d038,cb864331,aebddd3e,18830199) -,S(dfd54b47,e4d2abe1,c40e0a1c,2916469a,7e8a61b3,bd95a1ea,8b5fa182,903d8339,c705b4a6,761d2ca,49f87fa9,ebb4b39,35c3c633,4f6b7643,417c8a29,95515fa9) -,S(992a5fca,521a86e3,dce0ccc5,fd1b2ca3,656f44c1,f4967931,8ccb7a28,7879213d,ca2836c0,496c75b6,4c56c13,641d0402,b64cb2c7,617c9fbb,d820245a,9321217) -,S(38e59093,acc26364,de9cc5f4,de398799,54774d68,ed4b0283,2bde2a26,cfcd23bd,953c21c3,14ad2e0d,511d3f05,678358f9,eec2fa48,d6b24c9,6ed4efd5,da3b3719) -,S(889ea31a,5969b77a,c41c0a39,cc5d006f,6ff14f22,a62a5f26,d736ebcc,f5df8239,4c2fa5d9,c2f0316f,dcd6462b,e7571f4,92aaee96,c3c888e5,21cfabcf,78d2c3f4) -,S(f70e24a1,6807d5a1,8e15fdd,f31301e8,bd210ed,5d3d614d,82eec8b0,326d7b6e,dcf95677,b29a5ae6,15e2e7b6,c370cf69,ccec71e8,9569f0b0,5715963e,da6a34a1) -,S(d6eb7425,9c17d292,e1b1a4ea,624e6876,a78aa774,2b14e94,d3fd1b43,562e35e3,c05013d1,4056ea0f,e5f1fca4,b0c74b5f,776a8564,ac973973,c929707b,b3f078bb) -,S(df7cc5f2,69faf306,6050409a,6a03cdeb,8f33d1d7,4e30658e,e871de09,59701b16,3d8a28f5,f604c765,5f28dcf,b2f3407e,6a63db14,6b879fb5,bc785e65,59319147) -,S(e6bfa4b5,85f6df59,7840119b,6a31d0e,4ad800ea,239bbbbf,a8a1a36c,f8c6b5ba,312b5d55,35402ae1,37f9a02c,aba859a0,22a8ba00,88a2305e,4afe8283,98844dba) -,S(3c762a8b,acb68a13,2e3e022b,35634b3c,1907cdbb,261ff639,9520352d,fd94b3af,2ad358b9,65555cf1,e0027e3a,b93d46c5,b104324e,2c62f9b2,5f70930e,bf49f385) -,S(b4d94e26,9955b213,8025e5a5,bc5ea171,c2ea6d04,9ab60184,88f47f7b,f6a6d3f5,197b20a8,81e9280d,96b5b4d6,ceb3fa20,38a28654,63e76ff,d0b5b401,8b59bd1c) -,S(406e616d,907a0f72,12acdf3f,d5341a79,9b482697,88976615,388064c9,74cd8ed1,72730d26,b2698e29,7f62fd98,2a3955c,da516ebd,642d6619,2d33a915,ba39d0ac) -,S(1762d974,37705ae8,37603446,c8c11568,c7878053,f25baf9e,e3bd23f9,5babdaf1,1db8fe6c,77f41656,1fa4df40,23662039,66a8f891,e5467b55,3a2593a5,1ba796ba) -,S(f5fbeece,aa5386c4,d75c92a9,88ce6bf0,f957a0ed,3f0caff9,42f1f29c,7ad765ee,fa45a4e5,85ccc691,88426bd2,8ae561d,a2f59d10,e4bd63b0,4f8a53ef,1cc3ab28) -,S(7e0d92d0,d12bb892,b87b8bc0,993b4422,cd1e9d95,144602c3,a2aa3c06,bc945ecd,601b1019,746bbd4,ba9bf00b,4ffaccd0,b1bf885f,57ec49d2,9fc91744,8aa70761) -,S(64cfeaa1,4d4e0cda,db6b6a2d,9e2c2820,d2fa7817,43d7b2c2,8211b1fa,e17ee0db,f0b199a6,1a1856b3,360f519a,a6056900,7a0ee623,69e0aece,ea64f0d0,8cf568f8) -,S(c90f70e6,99ba1a75,86073eb4,5540b3e0,80bc78a4,e811069e,f861b048,5f11c88b,7a8257ca,cdc7538a,13b55285,939c614c,14d6a94f,70509900,44b286d6,7eb84e14) -,S(3edbcf0e,b4e5e640,f40afec9,ad370813,426b5488,3090f8d4,b72b1680,6694f42a,ede4512c,c4baf93d,f05c14c9,cb17b1c1,fec46052,c7087306,2214a05d,60743c80) -,S(77adf15b,ae449ae2,f63d7c44,3c56cf9d,64d43840,5154473a,5948cc79,160b64d0,a1bf9aaf,7804cae2,c377f98e,86b75e90,6886d293,21aed43c,77e330dc,df9113d0) -,S(350632ea,23e39962,3daa53d6,5a916f31,b2ca02bb,5bca1f58,35b85165,b430398c,41931339,48282550,bfa1cef9,94c28873,ee0165e2,fa970d04,e51f8ee2,b87916be) -,S(3d6aae93,5ee4ab6d,46de768a,d6938703,262e9fdb,13bade31,d38fbd0,9fade000,62674fcc,6eaddef7,b971e964,5a688e32,14186605,615982ed,a09de4ba,13eaab23) -,S(856e564,a155a29d,c1b739e6,309fbbe8,5ea4debf,f12a9249,347a5435,af674993,a0e6deeb,3777ceb4,6017ee63,caeda231,e616fda3,c105f0cd,6174a3b3,dea84256) -,S(95f8b405,c1ca86fe,d56727ea,eecbcce7,32d2c521,415eff95,b3cb42dc,5230cc7f,c8c66b1f,2637df4e,2a5375e,3a2e5e4a,a89404c,810322ce,c4b2bd1c,91163ccf) -,S(b51de213,54aa18ed,6ea589fa,e3b92d90,732dad07,6c80b842,579d53bd,2089e0e0,8f069737,1baca2db,208f7db4,c43a85fe,d816eca4,e35fe95b,780e2c4,a3f1b948) -,S(e36ac0b2,c4b73783,7a96b372,b8d0779f,41605e99,2a0013a5,3c8eb4eb,d5e2a988,d41ea6e,ef06bd62,7c2acd2f,645acd8a,75e353c2,448aba53,452787b6,670eedd7) -,S(4d08e46b,a3e812b0,67071dc8,b76cbbb2,4effce48,cf4a4c5b,ff4e15af,71c51635,fcbf2dd0,ba055845,b70cc545,5a8658f,39ef2176,9802fbda,2d3ab98,ba914c3d) -,S(31421774,5b1a6b68,918e8afa,4e8dda05,6094a6cb,6024c3e0,c10fdd99,245d7501,7ea6ac19,1c0db139,eafdc961,e8f91f1d,79269f69,cce275f7,abe9598c,2916fbd5) -,S(79bb2dbd,f9afbc9c,f605ad45,4768cad3,14d48241,724b301,7b5abd51,6f8dd4f9,d1c9dce0,30fe1a72,5d100c07,d842a78d,beb689a,606a933,ca865051,49007b8c) -,S(112abf7c,1d5d66d0,cbcbf42,1874bcb8,88d3b3b7,5c2cf36b,1399fc04,17525731,b3d3ee4a,f44b5372,8d0957c5,e388094c,34fe0f5d,c51abfc5,76c1e18a,c920dabb) -,S(f6257a3a,60365e63,471fe77f,893a8ae3,174d30a1,9aa495cf,251812d4,c5040400,293ef8f3,91804cdb,34845404,996a24a9,5554fd24,185ec85c,3a27ef8e,c89938cf) -,S(ee7c8ee8,bec75bae,db32c6f4,3b3b7a04,2c10e903,de9e7d21,5ca08135,d59a682e,e68a0137,398fb186,d5168e64,4421ac4b,30a635fd,c15527f3,e56b21b7,c0008ff6) -,S(e292a4c0,fd63ec7c,c661ee1b,25c9d5c7,dd805a97,fc6e64ce,5d3d18ad,ddc92aa8,ede226,7fa6fe51,1d4a510f,e7f5e14d,8fa29fc8,b77d61ea,2e140739,29644745) -,S(cf914327,85a05d41,2ad06146,6df68649,d3b8e0f6,86a83a70,d32c2fdc,978d8124,f74c1223,7b0899dd,53afaad1,b9b06704,c61c6e97,81456e86,ea55e65,96b0b13d) -,S(88e58d21,95376fcf,b3f0c44c,b013f2ba,3379ba55,2ceca46c,38ed48f1,263fe894,f2f38177,bc673cbd,70853432,6ece1090,5863ad84,1140c59a,2a782af6,ccbaa71a) -,S(90ada18b,df0c62d9,dfa35e14,d1eab9b3,48d09579,f4e82cb3,65dad65b,62ba53c5,2c4e704b,fc9a9b97,7d330d92,602c677a,4a06040,74517775,d441d0ce,6c5e5e2f) -,S(3bdc1eca,a939c8b8,c164e5f3,1a02a6dc,9d2712a4,6c30f54f,e2159934,d492d1e5,e53acd26,28f6e646,edb5f53a,d9e1639e,43b4ee9d,b61a3545,a9874609,9b3c1e94) -,S(54a206cc,48c7d529,c8bd2ca3,91501ca2,1b58f5ed,921ba11a,95eadfab,3a720bf,83f4f820,b9a07ae2,8c5e137b,c9ec4f0c,31c875a4,b055b0bc,8de38f74,c54c06fd) -,S(2754b021,13885a9a,f44cacd5,2999a03b,d16c90e,4e3a7a67,cb3426df,f6abe546,f8969b1e,e955f8e2,dc0d3090,167c0116,66beaa68,35bbb1dd,e721c4cf,768ef566) -,S(ae438153,4cf07fc9,1dd14a40,68b3cfe3,aa6e608a,bf1d1c1e,13ac54ee,e0759165,e7807ae7,395fd072,6f77d7dc,956c58a0,69243b63,32bad336,72d2eebd,662fb99) -,S(cb9d28c5,357165dd,fe18010e,4263e626,65fd6315,60ec8126,c7b60603,6ec067a1,86879039,f3264d1e,511fa8e2,4298c9ed,6f1e7625,897666ad,4db9a43,3338f5c4) -,S(763534f5,52317771,551524ae,7ce33579,41da627f,db77d4e1,a9cf72a5,f182d276,9fd8ae13,b1706cce,ad190066,9b1d2f46,8c177970,b5173f76,55efee54,ec5cd8de) -,S(3990fb8b,39d529d0,b2d38432,3c60ffdd,3b32f7c,278aca88,f49f1523,fa16ded5,e43c977f,427570b5,b238edd0,77db9df8,b1b82e20,b73b8d56,84a2ee37,886edb83) -,S(6b76502a,22280e31,d0b6375d,6dffef0a,94dad7bf,e640a406,2ad696fc,2744cbf6,e667122c,b6861cfc,97fc4ed0,e6193883,c79a896c,79e31603,a67063d2,421845a) -,S(7ac03be7,2ff15233,5ec9c349,98e77ff7,79e5f348,a49fda4a,e52a69cc,6b02c02a,74a9e36f,af0ef72d,b493617e,9474b112,593de375,c845c8dc,c1028ee7,9fd17599) -,S(31a83e18,c03c570f,31c3ecbe,bb787aad,6492cdc2,3e07d3a4,43b56ca2,51c0888f,3cbddf10,9bf08e81,830dfa49,d4d3cf95,224b7a4e,fd6d9997,9dceb64a,a8d7e440) -,S(ec13f2e8,53935ae0,705c2644,d1512bfb,8ea4adaa,d45a454e,f761dc68,c7ace561,54139641,97e2f5c5,5b4b7f5c,5267ea7a,bf36b01d,cbd62765,ff56322,c107f321) -,S(ce8e23cc,aa38e603,70defdd9,37803f02,18ae79a7,3679c363,4dab15a,bd46004a,1ddcf92,92ea77c8,4a1346a,a5f79f13,26c9092f,14ce1992,dfc24bf1,a2da35d5) -,S(77d80689,f7cd8585,fc03cb20,14d02425,3b547962,a282beff,17aee956,88292ee2,466283f6,429248fe,301e18ef,61a89784,47142fd7,fcc5c496,36dca83e,ae8e9f03) -,S(6eed61a1,4e7e7ea5,54a4e43a,61fa7eb8,b8e7fd0d,52de9ad8,e4e9b130,78178a5f,2cb4d228,90af9cb,a3c050ab,12a3dd53,1f1c6d6a,e4393449,219d86e2,6465bbab) -,S(10cb3737,a7916d84,12c955d4,32d1ad46,d8c7a60a,e44936ba,f62b2a26,b698e4f9,35499a5d,11e356ad,fc5960d5,8d6842e8,ea0615f5,e8bf39c1,8c217cc6,7a1faa97) -,S(e866ac84,6040f92b,c52d298a,6ae110da,e16bc797,d6958858,1f63c00f,6cc68211,257803b9,ef7bb5ac,59c6b59d,32a49d53,64c6659a,cb0482e,a9d57530,4e244f90) -,S(5e75ce15,aeb91c2c,e4ce06a2,decf02a1,db85ef5a,a43c42b6,179d4a,2eb4e404,a08d537e,529a6654,a785969c,8d8b0b86,e3a76f91,d9b72d92,992f8215,1b61bd1f) -,S(fa80c52a,12afecf4,7a5b48fd,60fa35b5,ffd122d,8616ca07,1c1271a9,bfe2c104,74487acc,dbe2e60e,e054643c,37cd624b,3dbbc3d3,4aaa6009,9c97cfe4,b3d69e81) -,S(ddec1720,dca13ec0,2eee97cb,445044e8,d6b049f5,694ce5a,efa664d9,d89b6dc,122b68af,feed4f56,b72a4a7e,e20a7f8a,8daa9883,9a797857,8dac0851,1b843872) -,S(85116566,57b70a1a,96c5da0e,fa5d3025,49fcd00d,104a4989,442ff143,a08b5a59,2c96bdcc,430c6c28,9d54806c,9c17961a,8121b10c,5168cfed,a0dc8edc,9f4f551) -,S(7de80b36,89b9dfe9,de2f4fd3,4dbcedba,9ad39842,f105f580,d8d5f6f7,e1eb3e58,43d20653,db727ee6,155998cd,f7bb70b0,9be15c7c,a04593b1,398b4586,baa3c417) -,S(e66179d,366fa7af,a982c480,9578d469,91731ce8,c669d8e6,bdc399c2,a2484b1a,9371d856,28bfb10e,d07c3390,b9f08222,98793229,ca2cf2ee,75d53d2d,e8144441) -,S(1d435048,d7b8bfa9,6df91fa8,f8f6d1ce,913bce85,c2c7a1ad,cc199afa,5da012f1,4e389f26,4f36b2c9,296934ad,5f567eed,30f3179d,6538ef70,f4205219,2c3eac82) -,S(5866c91b,619f53ee,3256772f,56191a35,23696c7e,2b5140a2,89f36c11,c1cdfca7,67090999,33ade86e,3a5d384c,840fc584,2a85087,10085798,913c41b0,e2dc1737) -,S(1e06d768,20c95907,405fc2c6,bd75e1c2,fb9c4d0e,4cee156,94e1a4d7,65a77a01,4aea359f,bd26d7a6,1b1e9f75,5544363,27eea590,fd2d5eb8,87ece7c,41759674) -,S(ee415cb8,5e1ef106,28c149bb,2d2f9e1b,a8083367,60a7b56a,f122cf4c,9b59e5c9,f52aeac6,e2fb8a7e,ca5a629f,b431736a,eec16a06,c1a4b876,94ad8bed,bad88ae0) -,S(42da5368,b60f85c0,9f52c3c,9aa82e66,4868ee37,4b1851e,d37ba6a3,fb717e6d,71f65b16,a3937a5e,b535da,ec530798,d1c91c88,722fadb6,580510bc,5f27ed65) -,S(10bf9254,6300aa51,bb08f849,5acf4e53,b1eb4e57,1328fef8,304189e9,7acb81e5,9b519bf3,482c9516,132388c6,dabced4d,971d033c,52bb5607,6c788a37,a9eb49cb) -,S(2f6456be,5c2c184a,1dbdde7c,2dff16ac,8f504a9b,d86de1a7,d9d3c1b2,bb0688d8,6bcdc62d,4e6184ef,1fd39720,55da6e7d,45cca6d9,4d15c052,8ddfa715,4aa68336) -,S(e68e8fb9,beec6d15,207e7017,c3574e34,102fd7f6,5e5f18f1,e533487e,5bb2fae5,13624e45,da0b6edb,df4ae938,82148590,63094aac,1b25d534,f80ca56c,814a944c) -,S(7d314f19,4b776d00,b946825d,f634f763,e0b5aba9,b1fb0424,833301bc,ab1e94ab,80d402d6,a8dca19e,709b9e23,4dfda4f3,9f9f758c,928c1b9d,842b2d5d,aea3fa54) -,S(fd78e68e,5b5b9522,14b35d5f,a0951f4c,4d5df056,28c5bafb,9c6144e5,c2c33a49,49c62b9,aa91e5f4,be13a209,7f941c9d,cefbb300,eeed9fc4,a12c1e45,37f4535b) -,S(e751f61a,11e0b68b,205fd306,9f4abab0,b2576131,3ac3ffc4,eb4c525b,f2b28f6d,aafd8f6,2fe20722,b180ba67,f9c3b6e8,8ab2b96,956d603c,868a8867,c09ddba5) -,S(6db64d2e,281e6734,a8908de8,554dfa93,d7811f01,2852a306,9e6ed59e,c09a4823,1c1276a9,1de36164,309d83a2,d9fdd003,d889612c,6026817a,cda97f8b,d2cec77a) -,S(4de91b17,fc227eca,652f8d15,8cf0c696,c6902df2,b44a02ea,d05dfd68,e408a17e,130fd485,d59456b1,48458cba,922e9ce7,79968340,d7e5267,b2f288d9,6df924ae) -,S(356ceb61,8c57db92,931a305,4537ddbf,8bad8cb0,c13f447c,1c3fa485,5c0ba01b,6f52d242,ec189e41,d8ca010,cdd645a0,8889206a,4df81651,1e820e0a,74bbaa7) -,S(595d8d68,1ccf61b0,456ec03c,53cc5a93,85e553b5,36033f8,ec56c575,db49cce3,773b50cf,f0718e6a,6a269cd9,65b5001d,f5613238,3e279bc8,fb937580,a76ad035) -,S(b076afb7,234e8fd4,4107caee,8d31338a,5122d785,4707605c,2e5dae93,2e6c935b,a18e661,1921080a,84a74df6,15006847,981b552a,4c3021fc,93967c64,b19d629f) -,S(834a4467,bada612e,2705b0ae,19fc9f1c,b80e6e9f,7c4c01e,5899fba0,1f60cfe9,9215b4e5,f8194645,813f00a8,58f77324,e28522de,16e93e80,93197310,38ed9af8) -,S(d00093b1,ba6eea04,c08df30c,90b2f7de,6e13b42,c645b01b,127003b,5642aae0,87739294,746ec547,4497a951,c26ca6e9,12ae4638,1d0e2804,5363fe26,de088434) -,S(66a33bcc,71bb2f0b,ea36e5d0,f1446ce5,f3d44a9c,b715e6ba,ed00cf70,4c4ce1d1,27d0f5b1,a40fb2f1,e1f9440b,c1c15731,50efa23d,b8997928,cbdc0e03,2824a6bf) -,S(ac65226c,dc40fb92,a9632724,20983b87,9e1a7615,fcbde26,ac9754ab,408211f0,ae633790,687f1c02,52115aff,3a7d5c92,9064bbff,616b5eb0,87d5c1ee,57cf8d3f) -,S(a4b98213,78cb0e23,d46b1359,43b354da,3825e27a,76f33334,147a3ee7,52a81913,2786a9fc,3701a6e7,caf07030,3bb382b2,ce6d7c52,42496130,13382f59,92fec4e5) -,S(6f58e6ad,e4af1dcf,633d3f35,8ac86836,cf0968a,49c2e85f,2434ffb4,2475a34f,70e30dbc,dd567c8d,a6aa970d,3131009a,f5297a36,f80750be,6462f1e8,336db9ee) -,S(9bc7ace7,d55fcd7e,e67a0484,7d0d6902,f053288,ef17b3c2,64072dc0,ae0e94d9,7f57fd70,93f3d09e,53a82818,e5ca4cc1,6b46f73d,2c00e50c,698d5963,8a8f3f7) -,S(248195de,ab1ad52d,fe739d17,a03ab762,927e058b,ae666f2a,4f7e220,3173bb3d,1b1914d,3dc9f584,51ac3346,d05f033a,b793277b,dd80262e,d2ffc219,6965b96) -,S(f6008de0,21c5cd46,d9d811d4,4070a7d6,46105a55,2a68c389,a11161ce,9baaae2d,962cd254,e5b0d724,5ddf7114,32ab2800,16f5583a,b8fa02a8,61b7c3db,eed77d91) -,S(f6dce5a3,a919eab8,c1d850b,4643dd3b,96e5c7e2,a1923b58,202543e5,4ece5b40,c1b88f2a,b3d516e4,7d289ecb,b16b9bb7,4082a6c0,8ccafee1,21abf691,73734c08) -,S(23fd6281,b4958fb3,b94ac9cf,851561ca,415cc979,7ed619bd,15192ca7,7ad39a71,fac12f70,ee38f19,b2dbbd5c,3cfe02e1,b69bbde8,7a45f8d0,bdfc909b,640622b0) -,S(da3a5c2d,7cdeffda,1ff2085f,fcda0ded,eb40bd40,3591395,e4b20b0a,25a1aa8e,e0d90d58,a6cf6038,10bf2891,d51da508,77d3aaad,5ccc971d,944ea960,c943e3be) -,S(22113f6b,8015b2f5,bbff28c2,cd5dc253,c495cc62,88361c27,3e788aa3,58a94554,7b6f7bac,2db4f198,20ca6e90,bab75cd0,983536bb,80051e6b,7da589ee,dd2ae962) -,S(3b59d8f,d59a2e6,89c9d1c8,a4e2515e,73317cf7,41e38108,eaad880a,e3417c72,bb96d412,50614b50,8903c28e,b5d39ed5,b4e735f2,ea10bfa,1265aba7,f21ded5) -,S(3407e5a2,4831b572,abc0eeaf,c587b20e,9339dd05,ebf395d5,378cb151,e0dfe661,49214182,78e4d0be,31cd4e1b,9b0458b7,7e028840,4a0745f0,40960dff,b9022926) -,S(9540e180,47717f7e,f6ce71a8,31368919,e4acbfb6,18c1582d,cb4093f7,caad2601,6fe0f64c,3f0aec37,5b36758a,7f65c7b8,e9329f62,3309900,efdd58f0,7bcf244) -,S(bd02f758,513ef045,af72344,f5d790cc,1c549a23,147a2743,b8c0cb30,891af3a1,3c605d60,13a560d0,d792c5a7,6ae2f739,7631ea13,7347864,4c6bbae6,dde96079) -,S(43b10d72,cf1ba39b,17abb149,884fd00e,56525f61,594f9654,48683c16,88f3e69a,cbce7dc6,1bf71def,95bbf6f2,fb03751b,8a0c6350,9eb9ead3,713366d,8cb71407) -,S(32900344,9ad58567,6ba2607d,c873a8f0,80d9c0eb,2f7314cd,9746008f,3c569642,8c6560c6,9a037d5a,3b2e740c,270ff543,54abb60e,b32ce5cb,4d18ecf8,1ab7ef60) -,S(a1495bc1,91188644,4991e097,5334c9eb,cc277640,f568a7b3,1350e4b7,222b885a,c5a1c341,67cbed14,7f28f794,d9d2867a,9019948e,56f986a0,e69a0d6d,6ae7dd1d) -,S(4640f683,f180cf5a,4929c2ab,5169de2,85861055,67c7c2a3,3db2d01b,c3c8d726,7d6ced33,7e752ab5,c87fb211,903c3a91,e5b0ee78,361a43,b716754f,d0daad8) -,S(91b3f9d2,7e989062,ced571ec,f373ff66,f8775213,95e625db,7d1b5168,e895473a,d7efd35f,56ffd001,bcf0191e,2692e832,99d0715a,edc1a19,2b74d8f3,c0b23b80) -,S(437cb866,aedcc0d5,8d89a41f,95cf5dd0,b355f244,7885843f,c163d54,a3839db3,9d644bce,31992f2f,302c5daf,67e42b78,74bf3f9a,a944e936,aef17203,5ac2bddf) -,S(be8cd347,572e0e46,5c745c83,26799611,a5ebb1ad,3ae74bf,474a6386,6f4a3705,6d39457f,c1010837,eac6bd41,bd4a245e,10bb39f1,77c5633b,92bda8a2,c50a3dd0) -,S(f40a76f2,130d31a8,c560795b,54fa119b,153a9a75,bfe7dd28,cc00ca35,2d258331,f92558a4,69f1055e,251c8814,7a94dd08,44bb2048,31f2d33f,d95858bf,dffd695) -,S(17e01809,b94d294f,c4438a92,6f90a295,5a9ed96f,a201df62,b96b19d1,7e837876,c9506f35,8efcf330,35603c30,880d5625,db15175c,486f3c5,841a14e8,8e5f4e72) -,S(7dbc457d,7ad4752f,8d57a09e,d4e8cf02,6c8b009c,bc29afe5,ce2ee745,61630da9,fea9908b,ca852ed8,3c1b44da,207e8bc9,221b8dbc,7e8b61ba,ab8d29b4,14eb29de) -,S(89fe19a7,6fe2208b,ee4de72,249a503b,88c63e22,71794bcb,9484fd11,1df7902d,8a4853de,c3cd9e1a,713e46eb,e771ee97,b88defe4,7e1106d,88ccd713,4e3a6779) -,S(3753a13f,531da9e3,5569ba37,7db76dcf,b43b5483,1e65fd50,a6ea560e,e70f3eb2,ace8aec3,867312f4,f095b4e0,d08ad314,2005cae8,b1369223,d1301e29,8e51d4c8) -,S(30d76056,384beb45,4c54b4bc,fcdcfe0b,1c1ad5b0,5e693384,8794846e,c93a144f,f79b9c96,8eee678d,b899f349,412bf193,5da9cd,c0ccdec8,2e45ac5e,58f3d3f) -,S(d9864700,7c74872b,40ec273c,59aa149f,8059a1fa,95e5b47e,378ec515,841eb2fe,782a39eb,ea47da96,9361a337,c5e2cc0e,49d43dc,6c6f9da6,6952f347,ca51845d) -,S(40d665ec,53720f95,42ffaf3c,30e8602b,53c52123,e9dd3b91,6a2e9099,8d534fb2,cc420012,490afedb,d840a466,bc27f66d,526a965a,ee653886,8cee46a0,6a58ee30) -,S(f31507a5,516719bb,f07438a8,7b6d6d93,d02a88ca,c18fcec3,9190f358,bab3647c,dbec3898,f884cb2,aedfcdff,402ca4ec,8c8f8727,485060c6,8da0d2e4,edb46eec) -,S(62573f5f,75db743e,7939137b,6b5e1d0d,41468ed6,28d2b76f,ca26ed2d,22532c03,9a4da6c0,d7966d8b,138497df,af25b0cf,2d14215f,ff039065,d42897f0,df33be40) -,S(d0887924,f15c5069,1d7ace01,7eeda410,e8d0a10e,f6091a4a,7b5f368a,42c54416,b2fdc385,527d34f7,a434c1a4,1f9fddc5,add3b1e6,82b63838,da0ecd91,16571c4) -,S(f7585b4b,5f3318b2,2307f34d,3e4bcedb,d4b91eb,180be664,4d031bbe,9b5e3d90,b6fd16dd,49993bd6,4d05398b,9ba7714e,798d3ffe,95393231,395c03da,b3ccc819) -,S(c9cdc99c,198ca8e4,458e5473,3e5cc0c8,100fb0b2,2dc6f07e,b1e99d2f,6a4cdc42,c4c21204,67198733,a845efda,33a5c1b7,67cd8ad3,47a16b6d,4a6f5ac,995dd680) -,S(1a054d1,5c4fcf45,384ead78,e1260eda,dee9e907,84021c99,179a9fc1,c7a3ac49,50ac5d54,d4fad7d1,5fbff150,d70a3ce2,9825e79e,206f4279,f1030d29,2de89a07) -,S(b0796a05,52245e66,56b3ce51,99864d40,aed71b62,3b9d55b0,d99163de,7a8e3455,a061fa65,63a84b15,1ef666d,9f99abcb,f1611e3f,6e26dae2,6be7ac56,c0f2768d) -,S(66fcf877,6ea02717,aca92a3b,5c19387e,72658125,f6e20da0,7595e376,804c3738,9fc66cf2,3195dcdd,7a72225d,96a8c5fd,1c84287d,2189e414,d0deb6b6,76e67518) -,S(3c7caf6e,d3da8c0a,effd832c,f5356114,55646982,3a62dabf,2ccb3de3,452ac96c,e44ca4ee,bb290527,4cf8f554,40c92ad9,6055fe3e,1bb344ab,ace5c4f,80e3b984) -,S(edf616b1,1e7fd6c5,96df3fa,77bfbde,f3f82e7f,93e5addc,53c83933,844e4b73,879982bb,b89ac019,e83f5c,dac1fcf4,fb918e2f,53a5ec35,45be03e1,89bfe152) -,S(7e9af2ac,b3044985,181de5aa,9908259e,77207ab,933c7915,9dcd7aaa,90527eec,e4cc83d9,d29778a5,eb83936d,97bad637,370e74a4,3254eca7,65d0a449,106ee3a5) -,S(32dad830,3bfb015b,6aa6759b,c2e8d4bc,2a9e356d,92d97286,c92dbcf4,53591aaa,ee27e7fa,b36a2450,f04962f2,ee60f9bb,68a1147c,9ecabaf7,e0981564,c1164fd7) -,S(d20720f5,73f1db82,c1a2dc61,d3684d7b,a3943186,cd513a5a,9eecd59a,c9225a82,3b29448e,cac88f13,7dcddeb9,36f02724,6819c6c3,3f03a2f8,cc40a6e6,f8704570) -,S(3a732b5f,5dd6dc77,1d215321,f8cd223d,22f2195,9d45c708,5b000129,94d5f03b,3fc75d80,ea7a0663,c90cc7e8,8a6096f1,b3a8c9c6,9849ea50,f1fd5c94,7928cfc7) -,S(201961f5,412beebb,7e190d75,70977b50,230810bc,b3b69e3a,dfb5e259,d811333c,eaa3f681,3816ca15,dfb9aebc,8888b578,e592825,82dd1b47,ea50cad4,f59b0101) -,S(cb184267,70cd3b68,151f7d82,cf7a12c,dae332,868663ab,4546c119,fe26f4ad,6c395538,eb09c00a,3e973def,8272eed4,27a3ca9b,a77d1a0e,c4e206f8,74591a40) -,S(2c13d3ca,9ddbe3b4,2920f0ed,28622260,2cbc0493,e5156655,30b53da4,7ae3ba59,f7d9f8f0,c58510b2,db28e723,6d9af034,658599dc,fae14274,efbff408,dfd18613) -,S(3ae7b7a3,86ae6c41,90b3a0e1,e5f1a7ce,4fffc405,84f05043,93e716a4,3ec83d41,643043a8,55603964,c46e3ba0,999c73e6,ab34703d,9dcdf9de,1743db7,71591bd9) -,S(b5eea0d4,ac4d0a9d,e37fb1d9,6825233d,a00f26be,86c0b640,f0fb34c3,465bc441,9cb5b93a,56d35b2f,2d921c4f,15b4ce0f,fbb9240d,30754ace,f16b3019,54732e1c) -,S(dc049453,9b8d5200,d513eeed,edc2afdf,e76146db,358a86b4,12ae9e28,e8501e3,6f6f2d25,b331a4b3,686adc14,c26814,96004900,34524b53,8418fe5b,9776a3bd) -,S(821e937d,a6fae1b8,3b6aeb4c,f5315bcf,77b2fb07,d0081889,80478765,cea7f398,41405d00,33224982,2acfc2e7,87be9658,7baca419,14b70315,c1a57843,3f85aa21) -,S(818bdf95,f55a8e51,c0d08d83,29574c28,1ae3397c,f6ac5224,4d82ea53,8f465c60,bfd41438,46dbbf6e,3fc442c9,7a66e8b5,32445d39,fae8c473,51e0ee9,9a9a53f2) -,S(e3bb3262,36533fd7,84fc6d9,84cc5590,2b03a19b,6c956665,322c0bb6,264b6d72,bbe4844e,2be51197,d8d84c75,ab83cee7,c9ed7dff,51eac125,1161e09c,c1078aae) -,S(36e3355b,5f946199,b33dad7f,b42d1245,4cf8126c,568c4be2,cb2abe4a,b83decd2,fbd5d87a,8c012064,3ed3441e,ec686237,1759ccdb,4a7f564e,c2ff9584,ab824833) -,S(bd7fc193,1b06bd7b,c6c274ea,73d33e71,1e1e57f1,e6bf7a8b,6452d979,777aaccc,95b84e3,d8c41224,c74451c5,ec8a23ca,35436798,c2f34ad1,b1cd095,2f0170ce) -,S(b82cb5d5,2e026caf,bc075968,6e1c6c18,206231e4,f25c956c,b3a05690,8c72034a,6417cb0e,f1a18ad5,e1a2a5c6,945f3b38,b0522ac8,70188640,80a0f33e,2796b042) -,S(47d70d51,e97fad87,fa0b1c10,43246c0b,32108c36,734c90ec,9de5a2cb,c6227682,6d5a2cdf,e916fe8e,8b45d5fe,14ce650b,79a3cc9c,e4f99aae,2e9c449a,a79a4a08) -,S(13fa7ee2,5ea49c25,200b40e6,b9232eca,16dc6840,4f76b43f,510c8a12,d520dead,2722287e,35c9f98c,6041cb15,845d515c,870f5943,74a1ebd7,36f973e7,5e6dc30d) -,S(c1350b7b,2a4e73bb,90d36674,771d5537,1fa647ff,c490726a,3748e7d2,e72fa7a,2370f4c9,403ba7,8e950274,bc1f87a7,bc80c1fe,7618169d,5c9bc5c4,81e1badf) -,S(dfe512c6,f884588c,80c1ea7e,1da4b3db,ab8d4beb,60749f40,9402d583,ac793e05,b52da5f0,333b904f,678dcd37,a890b79,e985dbfa,b501e61c,89930678,5a0bdf09) -,S(88da191,2face14,e6f5ded2,30d303fc,867f9b26,d85c2299,bfac1a23,9757b34f,4236025e,f82eab9a,f1fd3c12,42a73cb7,fa305e5c,ef6ad5ab,ea62cb8a,4d74bbc8) -,S(b7a82133,7cad0eb6,c1de7b3c,8aff8798,8ee936c,921a7dee,1434156c,c6505abe,d03b693b,4fbce189,a552a66c,3ef4586,35454006,308c40ed,c7dbbc29,75361b7f) -,S(44971116,c14d80b2,f0f88829,fa1fac44,ac44124,11ac6e92,fb898e72,a0aa7ed3,9171395b,3cac83ba,18e9a0a0,34fec786,986534d,667b0521,801638ec,e19343f9) -,S(95f0aa61,8bd8573c,81b2dc3c,aa16b577,6ee636a5,a8f9c963,b8a45370,7f35a618,7f2300b3,90006ec7,37365423,2b488d72,edf5192a,a1d5afc9,4bc95a18,edf5532f) -,S(e1bd29e8,778a30e7,d9d91da2,3db2da23,bc2e8d08,d5cd170e,8e753e3e,917b728b,592894f2,114c11d5,f04dd5fa,6b341cb8,29c58e1d,a7adb51a,19d881be,39f87eee) -,S(f6110619,208f64ea,8f0e8164,1ffe9f32,8e706427,87dcf8c9,28ca8629,adb99e7e,cff63452,a596744a,75c5e8a6,badc4937,e6f2c860,39196251,30784499,733651a4) -,S(4a3f7c9f,1ba0f01f,d6d42aa4,284e4481,ed1433c9,3248da63,76f25b62,d2d2348b,dcd4c18b,2ee4e447,3515c727,1467e6b3,86b6e640,834598e1,4ce3f679,47f5c2b3) -,S(50fc4d78,3964a68,b26689df,34d996cb,6f229f2a,ed017a98,4e027407,5fd730a,7ccd6964,c6c5ab52,5d31db1b,ccefc3e2,7a0882b5,8586a955,b76c754,9698a7c6) -,S(1bdc6b52,e92022,229cb15a,6436d601,26c640da,bd9697d8,bd0c49bf,606ce554,1ddb0cbd,e7b0816e,b65d7ea3,98da0744,b3ff390b,d2e13cbb,f8fe85eb,8f3d2059) -,S(62dac912,48f29712,c3126524,90db807a,af92d3fb,36117f6a,f5c7f5f,de317000,b3bc4dd8,97a2fcf7,483c0015,f793810,29bf6f01,7be37530,18b55e35,4250ee0d) -,S(ea552caf,1d0810ff,24eb5089,31b57573,d8eca976,2b314f9f,38301b04,ff5e2193,68181368,108c4fab,7c58bcdb,5bac3a3e,31eb1b3b,837c7ead,e691b56d,e24aa832) -,S(7d6132a0,9e2c0af4,9e3359de,a750551d,7addad6,8bdc602f,e65af48b,bc1127a9,5bf6234c,903e5f72,45b46187,9d780ffd,72aef438,c0b65c7c,d0b5fc2f,8ad29d16) -,S(916d0d6a,3d08a94c,604c34ae,8c930edb,5ad57532,4dd5fadf,7a4841b2,775c475d,e3cd9b7f,79572001,a1ad9c19,2921ede7,64b12210,4d4d8796,a435eb13,d883d391) -,S(804128a3,d982b50d,203135a9,c59449ec,c43ebb35,b2bf5266,6b710975,a3847524,bcebda70,4364414,dc269d2,6214968b,95ad5bce,239ca9be,f10fa1bc,d6f31757) -,S(850314b3,4898b572,5898dd9e,f39196f3,cabf4026,8248844b,1c3d2f55,a3346f2a,eb8d17e0,3c9f7fde,29276d95,c20b657f,af2173e3,7c620a0f,d2ea7ab5,f4706b33) -,S(fd879539,8c0ee90b,89aa731,a4ab60b7,be0375fb,59932879,7bd73390,58d7aa8,3fd62aa8,35d10f6f,8bf3338b,b48bbc33,8f235cb0,6bcccbe7,56716129,abe8159e) -,S(51536953,12e7c4db,bb18ecbc,26c51224,8f841792,e557e879,8eda9db2,c9840357,175d3e7f,92ddce9e,5595fc26,725f2c09,fc322b2a,251fc323,ad3c6f08,44badaca) -,S(8783f2c5,f7325f73,e5941ec3,5f91449d,558e31f,28af335b,2fde477,86aa2808,dc602736,ccef3e41,60b100a5,ef99c6e5,c59734c3,42b545e6,21d9b03,daf0030c) -,S(c871ab31,4afd8d5a,a58a0cc1,a5eb49aa,f25b4b3b,6e0ffcf5,38851576,27c0726c,d06b7e2b,f44d36aa,fcf653df,a675bbe1,36a18938,60864df1,fbc9e604,5a3707fc) -,S(40efd5c2,1a9807bc,b34a44,71066619,a2bba48f,c306293a,ab59d9c4,b30e9b23,85cf348,4df34dad,2f7aaee7,b8a6f585,4de1314c,215f6f0f,e5a38e61,f3decad1) -,S(7feb5d9,844798a0,2413cae7,cd791e6f,54250fb8,12f998ed,e0ea6eb1,435986e,d90ca7e,8e800e6f,fd0ea027,b8a379b3,9030a03c,7b111d68,465d2a05,99dd358d) -,S(1b2da7e6,f9fa412c,ec873512,7328f1e9,ea77501,5741a284,12018290,76a79b2d,9fe58682,ba3f6ee0,c7b73933,d14ce656,e3fe49dc,ec7a5643,efa07a3f,1a4f26dc) -,S(d7fc1f3f,7a6bcaed,1a84e8e5,7127a6f6,37d935a4,35500e21,47e8fe03,d3b06066,29938603,d89fb118,14d33850,451f5c1e,bc5a5943,70c2d8f0,1d9bed34,f0b2e940) -,S(45352264,1cd962bf,35d8ab65,3d8d6c97,75782706,1454a2ba,3d957152,e177ee5f,de5005a4,3989b6c0,cee0a71,b534137f,b946b262,bfe353c9,6a217c06,c23826b9) -,S(91733546,dedbbc4,c7c32af7,760e0a4b,c2bdf82a,73e2a91c,2d70afb1,100b84ab,e60a6ca6,f2a5b12a,307cab41,8793b7c8,b7ecbaf5,18166c61,acee16ea,83071a3e) -,S(26bcacdb,bd4cabe3,e7adc5b9,27465ac9,616725b7,dce240e6,37117a5d,80a9ffb,172208e7,6603837e,4a9cfeea,22bc6002,a5cb8f1,36d73dd7,ce30d010,acc05db5) -,S(18b520f3,e997b5d5,46a1d81,ad95c52e,7841f14e,11e9d677,de918fae,7bd408d6,51b0cc1d,4c6ec5ba,e6c587d0,d6489663,dcf74bbc,d93c4839,6e4203a9,caae57e8) -,S(e25c2492,b7b25c37,cb88da91,cd76021f,de8511cd,27188b0f,d4bb4fe3,dd845e8a,244facfc,a7dfe65d,6e1d1d84,9bec4e4d,17af0d6d,2611333d,b8b7498f,96c88bd6) -,S(97e572bd,300d9649,b9de3c8a,b02d4ce3,bfbe4ba2,68844329,85971951,5c34a535,324a34a9,39004c24,b2e55e66,83577259,6c9cb2f,84378bd7,e77806eb,75e77070) -,S(4d31f4b9,42526f1e,769bcf70,85f39523,60475a0c,3f8d0a4b,c1fd6a07,a4765fda,27815d6f,3b083965,8fcbb540,925986d2,bc6d1fed,d1c254e2,9580f413,99afa899) -,S(7344c521,23968b7f,7ee12500,e9efa4c3,859a72fb,cb1cc9d7,af91e6b3,b5bbe152,4794848b,1541a965,b7527533,a6d43398,d619df34,2608021,a26bf9a8,76e0e4f7) -,S(1d099181,8da474dc,38e08fc6,d97ac823,be34f4a9,81adee58,806f68cc,ffe1ce9,f5449d7,c69816bb,6f04b32e,69e46771,c7910f3d,77cee6e2,af75c293,119f729d) -,S(84607e2f,ab205637,4b708486,51e84966,9c386eb7,c6855a1a,837c8fb8,5da8e7c3,975b5227,26e4625d,cc5c55ee,22dc667f,1fff7c4e,417cb4b1,45bcb3a4,53180ac3) -,S(3d2ad8dc,11a9103b,2f03b3b6,24d93114,83f4faee,c4b9bc22,f4f8f559,16bae70c,b4f79cd7,27d433f3,72735afd,64ef4da7,de9ac35f,98b3b6fe,5de956a5,ba93f9c0) -,S(2ad5f6ad,c7fe8540,8b9bf547,a564727f,374e9194,460f6037,ee299f83,e842c883,f613f0b0,8e306fa9,fbf39919,e3040d16,ede4dc6f,9d45ce42,e63f4b02,70832f9) -,S(ca92aa9b,e8893819,e49fc29c,dc98a42f,e23084d1,fcc37d19,3e9c638c,db0f2f93,462a5ee3,2bcdca5e,c6bf6819,32ded511,12ca847f,7e110405,a893b011,874a66a2) -,S(4e435dd7,ce2783f1,5bbded75,e832665,e4b4cb00,b50e2a69,d986d2b6,d3d893af,cddec0e7,1615f7f5,769cf2d,ee649723,1218fd34,91a07fa1,fe619f2,26673042) -,S(b1d936c3,fa1fea01,e3e28332,51f3790e,1e0f0038,58656e8,af53a72,118cbd6b,183b67ca,8039f372,d04b685e,c515466e,8ca1fdc3,7b2ae8c1,ebc5fb02,9c0ced9a) -,S(77282290,d994b6db,10b06247,1b86caab,e4524850,22a1e63a,682f92a1,ae65019c,feff37f,1fee0cb5,569db439,a7697327,1a2e4254,a9125ce6,cd94fbae,110f6363) -,S(acd0184f,18bb7c72,f7b6ac5a,7ba3f617,c40e159b,a3dea242,ed8e6c23,ad89dc82,3ab71793,fdf23305,aaebfb52,982a2603,e56d7b3a,5430585b,557d3406,42fddfba) -,S(933e3401,91e41c37,69b60410,fc0ac56a,e5bb44a2,413921b3,d25a52a7,14015cf4,ad3aa53c,76c106db,6187f4ab,755d077d,c6d878c7,64181565,77bd5d3b,affad12d) -,S(6e02abec,969eb027,bcea0303,6648fe60,da6a7c67,d1e4df3f,a34c1225,36de6fa1,c0283bd0,9fb2bc2b,19bf5086,f1eb5c6a,a7dfa258,64c73647,8a6cf0cf,c5ed5c14) -,S(2b86559e,82e5ea58,423163f4,448327f4,2429f1e3,14097621,667cf1d4,f0af1ab3,35bcfa55,9e2a71aa,4ea25edf,f9e1c59e,2274ade5,9354e22a,9cff37e9,31258107) -,S(1c02f45e,5787587b,9d68df04,66df67c9,552301d1,3b32f50b,8c9a2d5b,c826606,5f5de968,b39e9263,c1624aa8,811a4391,35150e,f8167698,c381388b,18a232f7) -,S(d0a65374,7fdd0c5a,68c55060,dd4ed734,34956730,1997d07e,d333b5a8,79894eed,272fe0be,bb192ec8,9f2f64fb,43f3a3,cceff7d2,cf92cbf4,4ddd8fd7,b104b85f) -,S(bb48b81e,e0dffe05,b6b8d05,5e1d2e5,37481eb8,2ce2bb81,cfdfbcef,bca5c6de,717b99e9,63d59e1d,66c0737b,9843231c,9c5e1bfb,26820215,78e8e01f,9e5a3fa8) -,S(23901c4c,625d77bb,1d390891,6befda04,522c698d,3c4e82c5,227c3975,3d7bc3fc,2434bb8d,98ebf9bc,42459328,464c4a7b,b26f258,2d454209,af66edb7,e84effbf) -,S(2a150d7a,961b5c28,434cf4de,ab9bdd3c,d019f667,67437158,c0f3fc38,54de70ab,e0d4756,9cec0eff,b155d7e7,37ee49d9,863374b2,4c6f4ac,876a80f3,7fdf7461) -,S(d42bd53b,1de9e41d,6e5ada81,3b86370f,ec1cfe1e,cc8ace39,edeccdf4,e16e7111,e3d4de0e,e5cb0d3,e3dcfed5,a09dcc,28c9f1ec,969d70cc,ffbd34fd,d0ceca5c) -,S(2a865f60,413764f0,d50adde6,4825eed1,134c6875,d1712396,938cd8ff,784b743d,4b628cf4,8e2a56b0,2142bf67,8829a388,929a0c0,5784426c,ed114f21,ca1dfade) -,S(2189b2e2,e88054d9,c71c2321,8cd229f8,a0165a15,650d1557,3eccc450,671817fe,6b9e0fbc,f9b9c354,644dd8df,3ec14217,66fb6783,5c698a1f,d598d074,aae79d19) -,S(e619a8d8,d63ce9ec,7f11cde4,1cfd33e9,62884fd7,471a4e67,9b9fd1c6,8537fefd,d819f364,5438c886,915f46b,40fb5c6d,6932077d,6f9726d8,86b9ddc4,d5a552a0) -,S(80c0df21,91bd2fa,2fa21bc7,ea86e54b,ee25d9ad,43893869,1cee20a9,b5792763,b27d7eed,198a695b,405cc3a,9204242e,45833ab,3b9feaea,f81db33f,938dde53) -,S(cb3926e1,eaee7f44,6f2eb390,64d4ced3,cf8bfda7,9c54a25f,6894be15,61c2d02e,35d9e098,6612e1c6,fbc2dcf3,54022f34,5b2220de,139d1ca7,5dbaabe,46c69160) -,S(82e82221,5dae0056,917680ba,a3233d29,23a2a0d0,68939d9d,2e2fe013,9aa2a8b8,f28975c9,b27352f3,f6a2972e,ef33eaf8,5d0d0a4c,673e3495,afb71869,e768bcfe) -,S(6b48f2d2,d756c7f1,77d5d33,cf62e419,b32fe0e7,352e84d4,d3056571,fd837e52,d4741717,3212dad1,b476b8fb,7ace774d,fdd545fd,6f99ba1e,b701018d,f762ad14) -,S(6cc8e1cf,ca1a026d,c1db0d97,46029b6e,b9895d7,61f66549,4f29cafc,1243b56,429b0dfb,ca05d077,d4d87022,d5ab333f,d9068170,5e246fbb,6861bd07,7e85b500) -,S(fe3de551,3fc157b6,e5bfbe45,d88f9339,71ff5ad3,c436ca5f,21794899,33f01e9,a50a9cfd,8aee1546,c422c5e1,494dd42a,db36bf43,89bac501,38211c21,803be0db) -,S(25140d46,a9453d6c,9370c901,6cb163a5,a5faf371,50152526,b01c7454,56b995de,6e00dcdd,82ee197a,3d5ca028,86fd7fee,56319f7a,925a39b3,becba6b4,c806cc11) -,S(4b9c4d2f,bbd879a7,de69e578,a2ffc7c8,8a0c700,f27f2e7d,cb8e0c2,ba3654f2,4c876a6d,7778cd81,bb02c450,5867d448,c78e9884,c72af037,55a66d7b,848e248e) -,S(2c11d305,3eb4b59d,8e8319bc,2b62624d,b97244a4,47326f24,6b83e959,5797c2f8,41e096b6,a1d2082b,c852782c,74a02cea,55dc09c,64b9d19,1265c1ed,9c306340) -,S(9a515c26,394d56b8,77c2b70e,ba1745df,9322810e,63c379ac,1c2320bc,48baa2f7,5ccafbd5,d1dc3d86,4a7ac805,adab05bb,5eb27f8f,dfabfb1f,708b2e8d,42e097e6) -,S(791a6bbc,91321ca3,6e017798,1a611cc0,db9d2600,34d2c26f,5f6fa5c2,ef7a5fcb,4cc5b203,db4459a1,f396cb31,acbaf9ca,18446f1c,cfded245,a3b32100,38417ba4) -,S(ad40b691,d3eb6ee0,e22e6d7e,1e0eafff,7afffe6f,2e0e3b75,103001f2,3a9653ec,ff7b436,47c2e09e,84f90910,2b2abe7c,2d38dc2b,151abd2,4f92d214,5607cdb0) -,S(52eeb361,405a56a1,331e3fa4,b854156e,7c403961,240f6003,135df1fa,8f3e475d,128e88f9,1f089e60,61d3df85,fcb2c50a,b0e67ec3,a7e5b3c7,ef1f53a4,5d5336c3) -,S(fe1a5ff5,162731b9,7b4423d,ad1b5169,5401920a,6b1a07c3,6ae9a25,ec3fbd18,22076aaf,ee720a1d,96e0987a,c7bb8756,b04a6b25,ddf5823e,e2f93ac9,e54c85f9) -,S(4c64f48c,fa628f72,b2897c28,4411684f,c0795753,60b8633a,188a89eb,e7fe1ea0,2eeabfd7,1b976ac2,acff49fb,bd029ef1,a42344c5,489334fd,393cc4a9,c305b4d2) -,S(44cbb9b1,7ec26b5e,3489c17d,1da0776d,539d2efe,d9317987,b86225e8,77b4eef4,f5c58a8,6ef02531,bcffcd80,ce788f5c,e43f5ad0,37e940bc,70d8411d,27c32673) -,S(2a5a456a,99eeea58,761c8802,7a86a310,63cdc681,b4ba0e2d,e5bce690,db8f3e84,7c3a47de,ce538330,49e998b3,4415c46a,2ac5c633,1a074e8a,8b4cdcc2,c6d1770e) -,S(566c0ddf,ebb82deb,bc867f76,e2fc5ce4,71249a9d,1b659237,2bfbf9ed,4eb6bf04,76989cd0,e0ffe1fb,a5992e71,50272abe,8a483f5c,6bff023f,3e5e1265,3598bc80) -,S(6fe42288,6d5d8232,4b229084,b1b2924c,b6c45080,3aa095ba,aeb2dd14,7b6def9f,b3b394b3,fc2682be,6e8c1e5a,ef2c87ce,eebe8d98,31aa60d9,ead74896,d7d9a38) -,S(35b45332,b65703f0,4feeaccc,39e04e1,72e58555,db94f04b,1899d835,9abf996b,6643809e,ae897680,5e37891d,3a241094,27ad6dc5,48429a07,64e2e12f,e89c2d29) -,S(17288055,5c0c5643,bd740b89,bbe47949,58ddb0e0,786cbc80,84d64ff7,838930da,f60cda88,7f85da2,3fa719f1,29aab43b,8b9a1578,53f91836,3fee5bd4,fcd16a2d) -,S(76eb57a6,c2d7bb45,d6faee14,4ba7c798,2d8ab2f0,5240862,aaf32c22,77dbc985,ef7cd7e4,d10ab9ce,4551c6ad,18a3ac6a,bc851768,18fe0805,f1c6107a,5c8c291e) -,S(1e5b38b5,81ad0859,454370f5,2f636726,5987e7b3,981af60f,a987c4c0,2440040b,d9817e99,89af200b,da690446,df5d8681,92808bee,91ba077b,400e8de2,712c2ade) -,S(ee17e98e,12a9efb7,c27aee78,15da31e2,af0d3294,40e7dbe1,9783caa0,2bef5709,a78346df,4d7dded6,9146931b,f1ce1b6f,1aae295,50a877ad,5f2dd0e6,adb43e42) -,S(bd574652,1eec6a76,7c2a14fb,15c85590,f7a19e12,342d09ec,67dd98e1,7739a81e,f26894f2,b8eca34,493bf871,dd6a133f,efbf1ab7,687a15fc,336d885c,6f5698a9) -,S(63852cb9,391a1ee0,23947718,b27c51a,8f9a5d0f,2f707f2,d0afd728,6596aaed,9d7c8c01,102abe28,43a7cff5,a1b15fa8,b56f50ed,1a034963,2e867007,e946d639) -,S(6c3fb2c2,d49c1c29,4eff674,158a3971,f65010ce,93f53614,ac9e0497,e31c296a,ffccd06b,98cb8021,589e833c,9c8b3b38,67850545,7e8dcf2e,775bbc71,47243707) -,S(3c29a60,103f7f0d,6f9a186e,48ac242e,46a525e2,380c4430,609f26d,6c3559bd,9381e8a8,7b4bdf9b,361acf28,cbe43e1f,a8fb073,ae2d1d09,6df7813f,bbdcfe22) -,S(bb76e94f,6f9ceffc,53ee4b3b,e27d99f2,d02eac69,8a4865f,9cb0293,a68c5eff,9ae48507,33f5984f,21726a37,c6ed7a79,e832af6,83afa20c,ee5d117f,63ab7472) -,S(422fcd5e,d2774d45,6d5f6312,c716582b,c142fcd1,342b71a3,d729643a,d022b492,b6d75412,aa9d6ff8,9be3a0b0,17384764,35ad4408,b544b53,acb5ba63,119b6bc1) -,S(328db4a7,9fff0037,c79aedeb,e8895e37,75b1e6b0,4d0a7a32,e2fcabe3,29c60dcb,40a2fab2,622ca3f6,39711923,812d8687,9d92b15e,ceaf5855,a970cf32,854b8970) -,S(4269bd58,abcd5e92,c62b0895,1c5ae948,efa1c96f,39ad3601,5e28d809,74da818f,1d1412ac,57ae762a,c3918ee5,33577c29,a8e63afd,c33b69d5,e6758416,6ff87b65) -,S(6c08ab40,97320e51,f3c571d,3beb7d7e,cfb690b7,af3d449b,50bfd276,290b8830,aba73078,edbed082,2164c850,5ca4bc58,6e53b174,83675f9a,26734cb0,747320b8) -,S(f4929f5d,99d0a5a7,3d20a223,c84261c4,6a085af9,fae2fa8c,4a025489,30174c22,afc89b10,7a38c32c,a24e947a,d8efd761,cad69f7f,ce0d595d,d4cfa849,201f6178) -,S(5cf5baf8,726c125b,e1499cb5,3f33bc0,37c983e3,b03f37af,6b48f3c6,29827611,17bd2e3c,d12adb0,5502a9a3,aa418cb8,c3809868,56d00c5f,319c34e,66074a65) -,S(c4639023,b41d90eb,2b275a2d,b7ab632a,592535ff,b439491c,f0e4e692,8188904f,738e1a93,5ace46a8,fb4f6ee0,b9026314,d8c243a,8fe08f37,b23b9c11,11763de2) -,S(a21b2fc0,2a60cae4,e694f206,1bd083be,5ed681e6,53af9271,a8ef9983,5807ce92,7f80d5e5,5a684392,939d6d1d,537919c4,99e799e3,4bdbb27c,b3d79587,f08d5194) -,S(7841ddd5,80f9f3a6,e702b0f9,3e1a4158,5e2c10c8,fcf98add,2a0f6286,c5d285b9,4dabb8e6,2aef6506,392b0fa9,4e2005a5,ad03c4fa,5fb6de65,2e89b31f,6e5ed166) -,S(5d5fccd1,378e4983,8d8b05d,41f89660,1b3a7c0,58df493e,2a74b55f,d8210356,a7e7b0ad,fba08a37,6fa3cbe2,75dcfbfa,bd0629ec,e8a5830d,d6993ec5,15ccf447) -,S(7fbd50a7,360c09ff,fe55369b,fbf6be2f,70cc5965,340e0489,77e01b68,2ab6c9ea,17ff93bf,4fc95325,26caac54,89e22f4b,265f63c2,cf46ff6e,a5b1d387,98a9b72) -,S(d6c8bc1a,479ea533,e99afda5,95365a32,cb1f3a26,72b4b960,2e039494,5b379061,cbfadb4,a6039cad,67ded1e8,8513dbf4,bb1dd3e3,437c989a,1df98b31,d234975f) -,S(5753de48,683d633c,11103cc5,b1bb04e1,5a935e99,297c73f2,fe851d91,5d5ea18a,10ef5d7e,ca1580b7,31ed4fc,3cd606b9,e6af8b1e,dea8bcc9,b91d522a,af361376) -,S(fc0d0265,b6cfdd0f,6b755a8a,c87f0ad5,b5a19894,5348c719,e9593566,91a638f,c5f31483,3c166c18,8c62415c,e58297fe,157fc6e4,b8e36b16,ce28cc75,df9017a6) -,S(61570f72,5b030b63,def84933,d0d25039,cabc8853,e5185302,d3f2d3ed,2611eea3,b3edb685,379c0068,9e9f522b,a5ad9163,9df723b6,b5c3eb96,3b05e5e0,a4b8fa15) -,S(5fa72a54,36b2b7eb,c15b34a,fefbb908,acbada63,23809159,66785d12,fbb3d6e1,1c027ed3,a34e892d,4b3d56fa,7a93ac18,663e475,a16a3d2,fac0ec90,be6d9ce6) -,S(5296b2b3,9f179516,d3cb85bd,5b86a9fb,274da608,be6e95b6,c44267af,187e2371,728aa26,e5869775,9c392558,34d00992,73eb6986,5db38b3e,df87f394,31c75dbb) -,S(b145c8b4,4c3f3c77,658899f0,a5b97c4b,dc2b195c,aa56b328,e0535217,88c80298,c73d96b6,47c2e764,e36caa26,8ebfe40e,c07b1e0,947e392f,be2a9095,7dba2595) -,S(bb585531,3cd05f8f,7fc96d8b,6e5194fd,2a70ff55,e7a7c067,cfbf54bd,129d87c1,31ed0367,8d24c231,8c4295a7,90d31094,e54ca68e,47b289c8,45b2f638,64812607) -,S(c6ebab34,ab48c0aa,aa5243f,c82a90e1,9a2012ad,74c925f2,e4e22f6b,13d6e5e,8107a95f,28e11f9b,bcef4b22,c4228c0,b530cdac,1c977640,53828b8a,15fc065) -,S(92e6ec9f,83dd27e6,3be3b0bc,8ebc521e,d84219bc,177f15cf,1bc840d5,be2b551b,931aabb1,5b3479bf,994f7eeb,34871b04,81efa404,c40e063e,59aabb77,2553ac79) -,S(280280ef,424f01ec,3fff321a,61dde1c3,4e674a56,7142c8e6,643ad1d7,e2dc4d51,84710eb4,5a88503f,b1078d06,26522501,fc165ebc,ce3b90a2,925ab1be,3c9ebfc4) -,S(6326eb72,abc4017e,c3f55af7,6a50a4a8,d0074ce1,2f5c9e08,146682ea,e406d047,53dcc346,7b61d08a,204a70b8,7658e4b3,c4016c8d,b5f03004,af6b545a,60223871) -,S(6e59dc29,408efda3,1bcd7b05,276b9f8e,bd9caffc,7f22c207,61f9fd0,a281ecb8,81c60999,45a6a834,8f2bc7e8,4ee002af,ec5729dc,aeed8187,87060c68,c2763887) -,S(100b0cdb,ed05ba0a,fcfbedde,94ecb25a,5cacfb8f,bbb80fed,1a9d87ab,72e4b5d6,1ac27087,8d6764fc,ce5f036e,ea50294,cf38c4c9,1ca9c3c2,87718505,491e11b5) -,S(95865771,e313a1f8,5629585,7ab9aafc,68a124b,6ae61f1a,a7b6e9f5,fb5de6b4,1c5195a4,338bfee5,9910935a,f5fa6091,7d06a2ff,3908fecb,b3fbe30,b0b52b41) -,S(6962774c,9035ce5e,fbb8e715,9d381004,a1828d67,38082e1f,45307ea2,d1d60eae,e9c36d21,6a2acbe5,5f9f9535,bea4b38e,7b75a149,3a281e4e,11b19064,e282c036) -,S(8e0fb8c0,d2d7977a,23f19efb,aec886a7,5170cd08,6a035386,ac784b15,9fec90eb,1218a3d7,6306cd4a,b3debd20,9bf9238d,ce00984f,47b5fafc,b715e2a,655ca9d9) -,S(6e9ea5e1,127c4c60,a01cd278,ac1dc091,e768acd,41566200,47aaa32a,e9cdf5e4,bfad3214,9a299887,c74bcb20,33e01704,ace7c646,eb00dc71,fd1e0461,af05a6eb) -,S(60fd55,9198e1ce,86c401a1,d31d04a8,fec7da21,4efd01d7,f2081027,1c49206,4f234575,cf4e6150,16ad551c,2f8e7635,3718b626,70ed30c4,a4c15e9a,488e0755) -,S(d413c7fd,2c2bd34e,2ab3e871,38495543,3b5ceb32,cba0e9e5,1e0ce198,cd5ea806,b585f836,7ef44ee1,8e32dd1d,95d6f8eb,555d8e53,451e5d8d,1cfca993,b23e344d) -,S(e26a95ac,c0855b56,b702cba4,abcf2004,c7343cf4,72056bb6,161ac077,bfecf98b,36a4834e,4532fa30,eb1caa21,c1572c46,efe4f7fa,e3c370b8,3f1fc221,632f8c2f) -,S(f0541a0a,d29e3806,e2812aab,ac185a55,687e058a,eb17157,e00a1cae,5a9e3d9a,40e81917,4473fbbb,58d40f1e,ccb2444e,ca4a616d,b0efc710,8f887c09,dd04b4b6) -,S(db1112bb,394f5e1a,b315f575,e2cfb59,4b83b599,6c82365c,c2095bdb,eb7c3cb9,c53249ca,30eb726e,6dfdb792,4db693da,f9740213,d87c410c,afa3ade9,51f9f688) -,S(2ad80407,9fdb7722,c96abd1d,35e76a7d,30948c7d,7b1e62a5,ab0994fd,667103df,5289aade,9f71ef7b,dce049cd,3052f8f9,653a9b69,3876b607,7bb42d77,9829bbe) -,S(7bcd5085,eea0f429,238c23bd,bc14017a,f8dde478,9d99b2de,325503f1,fcf7e738,7338f8a,7980de0f,404764be,7fb22578,ee820c6,16044f18,ad12d4bb,4b35a2a7) -,S(85819e4b,348ef2b6,d141baaf,3297248,7f34b594,8d834249,df465fc8,29a83188,306e8693,e7e718e6,39f48a1f,7dd5d977,9da12288,ef3edc6b,74afb1a2,906f931d) -,S(8d035a4b,5905b0ef,7fd9b050,ac1c006,2c0a8d84,1ab342bd,9444d101,92ed4a79,1ede85ef,aa83c466,4ac1cc71,c2d4027f,632f7ebe,2a097d98,9278cda6,35e2e0a0) -,S(bdc84795,289c3268,628904fd,5d8ef1f1,a89587f6,652aa883,5e83c47d,c008c282,1d8342d9,e330c123,7e232067,6fec10ab,b19c0d76,744915da,9980a9a5,6459a61b) -,S(75dab97b,d9e6571c,afbd8ce5,ffef58b5,72b6d8ff,838777f9,21834b61,1079c079,d048e6d1,fe2598db,31adfa59,8a445f0f,7f97ea3f,dbf8fe92,f2aa495,ff033bdf) -,S(b2a4a872,4a6ccfaa,8b8bde86,64fef1fd,bf9d4edc,215f9f71,738885a9,af19b42a,9bec2c2e,76be8104,f2dc4ea1,3e1ec916,23baf856,a92863cb,33b2781c,35f9060d) -,S(caeb3a77,35824f9a,b24e364c,789fe66,4729fe9,d6577ab3,f9cc857a,e1c2bdaa,ad96c92e,e91cf44e,8f0480cd,106b115f,23f0a30c,fd6ab638,86ee87cb,ba5ed885) -,S(a897e41a,75e6bfb0,78c272d,ec320e70,13afb506,478d984a,b5532b04,6da0502f,136cff6d,896be55b,5da484b6,15a09e9b,13453973,79fe4157,64ac5b5f,35aab82c) -,S(a33679a2,dc5080d4,a77fee11,5de9eab6,d32e6479,bd4fa795,3e4a03e5,3242412,1840b712,9ae52592,d99ee262,a56ae597,37e2202d,2871681c,6625de82,7c57819e) -,S(3183fdb2,b5ad14cf,9e2ee00c,e23b2c42,dfbeab54,acdbf786,622a83f,4db62fd5,7501e003,2ba129c8,50c0f17d,2a16b3c8,602c5225,1bac7212,6d454cd5,fc35a92c) -,S(aa6ac020,42f80323,ca77289c,88dc702e,e354fe1c,eedc720,2b87601d,7641b00,3ef01b0f,8b396221,8c5118e3,2168a6aa,ac901e02,5610db0e,8cf2ab21,bb06995c) -,S(f952d843,386eeef2,64b1078f,d835308d,514bc162,559c8f3f,c8ab5c18,378b40c7,fab32d0e,850f4bac,9a4af6d4,7d15976f,2e6fcf3c,958a72fa,b8db1817,cbc5dedd) -,S(75b58bbe,a5a1d00b,40f2fa2f,9e2ca8c2,eb568bc1,fe5559c,7e40ab8f,a0148e67,7fd6db81,7359736d,26883e35,727f4b21,2813be05,8d5d2477,1563696c,feaaf021) -,S(504e2324,34a12a8f,a96f64e,d39a7c0d,4168bd75,1e0b6249,6b24ab05,eff49d46,3bbb93f8,3d2ee95e,2e2821be,c3d98f4e,1f2def75,b5f8ed09,6947c4a9,1c933ea7) -,S(563fe95,1482826b,38f21deb,207a30d0,21271292,8b53c790,c33080b5,c4fc14d5,9b875a5c,70ee8bac,9e6d7225,1981c9f6,c3b5bb49,c8772243,14c4b287,e990bba3) -,S(91ed3211,161cf1ee,96499e83,7baa574d,1f56b244,56fc1589,d61f4d40,dea01443,f1664cf2,578f5ff5,8d81c281,514c7f95,56bce3d2,2150db9c,6f4a4df,db73d14) -,S(27526d79,f92c2519,838e3e0,a9ebfd02,f66e857b,d49cd8ec,6deaca31,d6064be2,9e4b644c,5bf8d50c,96892f3d,6843c94,f9afb359,55fb10b8,6a2f166a,6fa17f00) -,S(3ad1833b,df1ab0,effb0dd4,d535285a,900060e0,f38555c,ffd3e7f3,392b5c07,5c37afe3,89bf6e88,b88c9a34,6ab5a0f6,2128828a,22b6f907,8f9bc6ff,ed5c311a) -,S(eeda869c,21a8911b,cf713c68,caf261d1,e7fc58b4,3bdb0fb7,e83e677a,ec3ff6d9,f58e7eb2,3a62a9ec,f7a13dd7,b6b6809f,5cf8bc2d,22af477,e002f2c2,9c44d444) -,S(c7a806e7,bfc982b9,342fd4fc,e8f34786,9509fb0c,f0f54522,98162dc8,ec5a398,ba895fb4,f9084463,3eac5226,e91a08c9,e83281db,c406ab37,fa3ffc38,421a3647) -,S(c59586d4,ecde0cfc,3a1f5744,45cea454,aff18703,720fb4b5,1cd7b0de,de79c9b3,1eefa71d,5e67d9aa,15231b20,966951e1,93ebebf7,ae54ea34,e84b7c98,7cd853ff) -,S(3b259287,5283a78c,5aaebc13,5ba13c5d,4e5a1e6c,cfa196ed,6eb7960,e7eed0be,274d3739,5757e482,1ee56c6a,f56c8acd,f58cb337,6bb5096d,2cff4e33,ebb3c1c1) -,S(d062159c,e511418f,ea6e9853,b1e8d769,96c686dd,eef71443,e994a347,3b90e239,95ca957a,b37c702d,c707a3e6,388532cf,26cd3db2,64e4e9cd,fe0aec9e,77ab27e3) -,S(12a2bd87,c4ca2337,7915bd12,3f39e88a,fd7257e9,9587d70c,a9d8fcd3,2aa7ce4b,85562f37,ac813598,cf59e427,106fe886,aa1a078,1170f14d,3968119a,9ed65e61) -,S(9214dd98,2737e4b1,585b3363,c363ef83,b40a3228,53d6c54a,f5b1bf1a,a21e43a8,dbc49c6d,abe985f,d95202b6,bb925094,8b98bbcf,71486065,9b77c447,396e8eb1) -,S(34439200,b0dd5b6c,4fe8cb57,2e26de38,3311a479,ee39ea47,221a179f,fbbc124e,b8c15197,1ea4149c,d2a77b4d,14cea316,6d70b971,a7f9ef3d,315ce741,2ad43e1c) -,S(396b4410,cb5a59ac,15fa6034,7215ac8e,4ce3490,4dd15b41,46e90679,ca3128d3,ad4eef77,94f0c541,e70fd5be,45652364,c43e91aa,34683525,36c8b1ee,c061cba8) -,S(8ee1b02e,3ddb0913,dc781279,6316fde2,4489c98a,4e4c3cfa,c84b4350,34d53d65,9a4686,a5241a7a,cd4295b4,f1c9f094,3f8991a2,b7edeea8,bc4e9c4e,47956cfb) -,S(78f4da51,26b42e21,1d69c640,4e128c71,cd08fb67,efac0157,3bf128c6,73bbf6e2,b3836f1a,e397d7fd,c88d2089,6731fe04,6a46b2e0,b617117b,161e1e7b,3a2958e6) -,S(ff5c1378,c8a233e0,5edeed70,e23bb9e5,a5eb65a8,4b37c6c4,7c0a4952,e00169b8,a7275aab,c73eaa15,22328118,68de268f,189d3adb,da113553,e3f9d36,7664a0ea) -,S(18ff6e74,87ebb21,dc935fdc,265616bd,d3a4bc2b,35037483,c911f185,596a93c0,34209cf1,2710b007,821ba024,f0491e54,bade44da,5980f505,37869b8,b410d0dd) -,S(3ece6ecd,1c52894d,90043c67,59d158e7,143c9806,658e8e65,5fa53867,6609b0b,4b1bbdb7,7ed6deaf,fba0d241,5f2b7993,89cf7df0,7acfb8a7,a22f42d7,7858c622) -,S(a5356c78,6cdabe6,a1c379a4,ca18acb7,b41fd691,c32c31ac,6cd0edcb,9fdc5694,ab8f37e6,d19af264,58ec5b1c,78f54a4b,877c9416,ad76b646,7e91ca4b,24f988f2) -,S(e5dffa5d,961253d7,f99445b8,f8d8aadc,5415c550,da64a987,ee604278,12de570c,401ebeb4,afacec6e,d41006e9,c60e0ec7,a4840c2b,c64527ad,80d640e9,70800186) -,S(12c46133,4aa32bb8,465c1e9f,afe68d91,63a7a9df,e11940f4,593697d5,fd0c9140,e4fdfe80,be2fa183,4c32598c,a096a5d8,15386dc8,67588354,300018ff,5b2e0c2c) -,S(bd8d9bdc,ebfeaaae,691a19ec,c20cca22,af76db4c,ee54f904,ee5aa8cb,2010ccd8,cd5fca87,4a6cc17,79658266,158066a2,840e61d2,28bdd4cd,f2697e19,7c6c994d) -,S(597d8ca,babc10d5,5402f3a7,48987270,7cd5d3b8,3356ea13,6c8c5135,cefe3fc8,bb21d384,a48ed346,eadc6ba0,2b1e2231,7b2014bc,62d17fa0,9196213,6e12ab88) -,S(3d91a096,24fe1048,dafae0e8,c693226,cb89157b,980aa490,a9a12598,e77d7c19,738fee86,ab5a6e43,753b22cc,d6a28732,65db5dcd,38a6be5a,6635e8f0,136340e9) -,S(44addcb,55d0870a,19682075,116c8fc,d8f49b5c,5ef767ea,aec513fd,8d71841e,5e126cb7,8d13c0d0,55c3363,b236bba1,21cc5618,40e3cc3c,e100722f,1cdbdb63) -,S(5bc89297,4447eb3f,54b7b451,6da3d1a8,f23d6d42,54ec7268,f3e9b2f4,78d88467,6d708655,6b679453,253df54f,68541560,b5e542ea,8f1a4a9d,a023d8bc,6baf9559) -,S(8fe4f040,553ba9ef,47a0086f,a8dbb75a,2362af22,a58e0739,7c62d2dd,2ed2fc40,b2d0c561,5afbbe3a,18fcd594,a8e91e14,ac714af9,e34938f1,74a2c7d4,2028f65d) -,S(e36702c,2af02461,4d5f65a6,b855848c,6d72709b,b3ffbb5d,f08206c0,9c481a27,c5558c45,9cc186be,665a54f,19ed5f67,983bc004,c1c196fe,80c57310,59f1505) -,S(45b0165,d5eb9c2f,22c6f2e6,3f2cfaf3,5d4a71e7,460a41a3,9d3708c3,111387d4,8fcc8dcf,9eba288,f0183ba8,345c4b08,1b44cf73,b9df77cf,3e94c089,1e53cbae) -,S(ad02f6e7,378d62e8,87d651a4,eaec6d75,9b15f4f3,b7e999e5,2e9e493f,7d765205,25090d49,2164feca,33270e1b,3b08ead0,fcbc7ee4,aca4b4b7,7e06d865,5259a63f) -,S(5684c664,de3844ae,90bc93ad,426bbf69,5f349b97,6080193a,710b6125,3d6fcb0a,c5138172,4fb53812,9dffe038,7029b209,946a913a,cbc06370,b3b58f1c,759ac8f2) -,S(cb36c4a0,f6d2beae,282e9783,2148704f,aea7bea8,af0abca,ac670a7b,3808a2d6,d0aaf774,d65b7eff,589afcca,746b02e1,edbd10b3,e2938d6,5a0bd17c,f71de58d) -,S(143e1741,5da8c61a,959643cd,bcbd1eba,169257,2a935eda,1d0e2495,6eeee4d3,c12840f7,7a9fb642,50d19be1,5f35199e,1da83a3a,54fda063,99a6908f,87c9beb2) -,S(b6292192,d471ab52,fee206cb,64bb526e,6b8519c4,3df9ae85,4e4aafca,d53c1509,3d6fb4ea,45ae494a,e2c4c776,29047e33,f73af147,4fd217c9,856d5d1,3b837c56) -,S(d490352c,70551c78,9951a057,cb02eb17,fd710a0f,27dceaa2,ff224ec5,3c566a14,15ef3825,97ee6d88,ed8840f5,9d496c0e,6685349a,f1c62c27,a32eb7b2,bb193fb3) -,S(4797be1f,7ae122c9,2193fda3,80dac3a0,fdc14361,110a2a3f,5beb9f26,f3d85449,9377f25c,591ca377,2ffcdd37,65ef9a3d,6fa7c2,79d18e45,83901795,2e5fa3af) -,S(fcf5b790,98cff1c3,b02be521,76e1c6c6,ac10bcf,f083ae4,5d26ead9,82839614,8d94f596,5b075d45,a8f732dc,9fbe679,dffaf0ea,d2c90d16,b2c7ace1,1de05c45) -,S(d7153203,1e8cf246,683ee529,b2dcf54,1a731397,89e5c354,3bffbf4d,f95f76f6,740af4a,40e7849b,a41c4dea,4b7e0479,ca377fc2,69db00f8,b484c7a8,c4c745bc) -,S(27946ccb,dba75dc2,23663d14,2b56bd9f,2e63cbfa,73290de1,8fb7e988,31b44330,52c0ed5e,abb069e0,84fd8363,dcdb9134,364dcd4d,87b46025,9c3460ed,63e04ad5) -,S(cf3ea523,751eff3c,a785884a,b019199d,2a0ccf3c,1d90679e,141d4e75,74e41f61,b38d0808,936a2920,ece323ac,a707e1e4,914b51e5,e54843c9,63abf292,88ef17af) -,S(d06327e7,917280c5,d8a5c516,7e0d0c1b,e5fd9e25,4c877e9b,9ae6b264,6d9a126f,c3cc3913,9d0d7b8b,6a6b0c7d,b48213ba,eade2202,544dab7f,9ae42e08,fc7c781e) -,S(acfc233f,28f98688,2ac5ea8e,61478f62,505b8b48,38833499,1ccad1ed,5ee2a871,244a188a,64a6aa7,9f74e940,8681b45f,88b5c65f,d120650b,1a25674,eabb338a) -,S(87fb09cd,b3b8a514,f6a02da6,1d9b160b,798fdf7f,3f05d7ed,25c1c4fb,84b19253,586effe8,c4252dd8,c225a6a2,8e515abc,e36568af,107f8c75,a941e936,acbf6e38) -,S(77225acb,8ae251d2,be2f48a3,2eff0c6e,4f558287,13dc8a6d,3c6b7bb5,de9538de,d6eb8501,2aa7fe12,285e28dc,3efe9cf5,b0cc8e91,6fd63f71,c28c3f5,60259a8d) -,S(b03074f3,f2effb45,5caf88ef,e0eca7d5,6f901b18,fd04c01a,f0425c58,1f13dd5a,c8e8c915,fe06d774,8ceb2da1,78816b8a,4db1d082,6df3064e,7a4b0f85,ae99d461) -,S(992278e5,229bad50,82c8c346,8542f91,e2761305,62a34627,b1d97aad,a5999908,56ef7d8,d360d7b8,5af0f210,161ad17d,dacebd13,c45b9c8b,34f1ac73,bd6a1ac4) -,S(b73a2eca,5e9d0e4a,ef4f6ac3,e9610f3,1c72c67b,6a152fb4,82681595,8d44be12,c621ee64,b03b17e1,a25f27c2,aaea43d5,eb2918d9,e0949306,d2ef720e,8975c00c) -,S(7f6dba94,39e3302b,e4f7e0b6,f2363609,eedb30e,dc0b135d,e4aef970,cbcbc607,61685e2a,eb8e8244,175deb0,a006b5c,4292bd73,40b2fa1,3548262a,db98a3d7) -,S(88f0e36d,345aaeab,e8af18a2,d14191c3,8330c5e0,d4e32c5f,c562e549,cfad763c,bd062c83,13e44ed1,891b8048,2ee93ac9,95a0142e,e0543a92,a215735d,1e94ac05) -,S(da3a270a,bc03e6e5,3f572a27,94c8075c,8ce4590,b1b626e0,8a83fba,45dab386,884b46e2,3ab44b4b,c3d09f5b,97994e4b,109f2db4,ee04bc77,6752fdc2,6f0df055) -,S(df346699,77cd82a4,8e3e1b11,6311a5fa,3bb0389c,1c500fd5,15573af6,da0b2cfd,2ecf1fe5,fcec27d6,35c28d58,5fdb01ec,2192c8a3,848a72db,f53b7759,7b8b3735) -,S(11a4dfcb,3a443c3e,259c9f27,e24ca426,6e08fbdf,e4bbedb7,2e6cae42,569b0116,7fc6c4cd,1e3a0e22,d0ee0249,d6940def,bd776bac,9da5a98e,23cb6025,42b3de9e) -,S(2ffd148c,132eba23,e235bbd8,f09be1af,dcfd6e4e,5f2f0b49,6e4fadec,b931706e,6a4def93,52d875c8,31794fb3,6cf0448a,8c9ab5ae,804c6397,cec41b0f,24583acf) -,S(109e1f3b,7043c5d6,fb822b8a,54c6949f,117e829b,4065c0fc,c3ba5e05,a79142f5,c976793,6c034671,e5aceabb,9b08f5fb,af3cea75,a7a4485e,6c08f7fd,a63786fc) -,S(bfeea71a,8bb8ebbd,ca6135c6,26b739bc,eb2ada11,9babf946,6db9f4be,c7406610,44ff78f4,76074ac8,fd7ef860,cab01522,750fec0e,4b86f11d,831eecb5,22d1f682) -,S(4d2b7cd4,6cb01842,46e7846e,d0572489,e306b370,81515cb1,8a7c6cd1,dfb51665,60ebb290,44169e56,1d10a8e0,a2971b69,82276f1c,e7d11f60,ad7decde,e1fe9c95) -,S(66f2068c,e65a1a61,ad95ff3c,a2f15f55,29e0ce3,ad522dd3,d6083d5f,793e0e5c,a95bef60,2bb89e00,98723b4d,7fb421a5,b2cc751c,e8862ed7,439c1b36,efba2f72) -,S(4908ff3a,27aebeca,8697ec,dd7d5483,c6e56427,9d78f013,129e26ae,2ff459df,4c5def88,b60cbb2c,a3430911,aa84e4fa,1055fe1d,921c8fb7,bbb83b45,62b0f5bf) -,S(f9a90175,3a0f4236,dcb612cb,fcbf3f31,d97a8e6c,cc4f9e74,3887407,5d19ecb6,ed3c6f61,259943d0,310208e3,dd8d5a40,a5bfa646,35fca871,a6df79c0,830e24d6) -,S(ffed50c1,2434484c,ae866c1,86b88550,b0bd02e9,db04657f,aa81a672,8e321850,f16e95db,d44bc7c5,66fa0a23,669827e9,9cdf4372,6fba5f4e,a3e28d86,33edaa77) -,S(8061e9b6,2dd9d027,d43d13bd,1361ef3d,ccb4e599,c8d3d015,1d3adccb,6c762eb9,d33a9196,419b283e,5579ac98,8c1b6e60,378fc692,69b18da,a38f362d,20ca6895) -,S(ef8d0e44,e8b6b5e4,857d3d87,c82b01d8,f254c516,fdd139ff,7b8d034b,45698162,8325ccfb,6da9438c,e99dffa2,92afddbc,e1a101a1,20955945,cfb1608c,d35e7065) -,S(a31af5aa,cbc4f6ac,aebb9abf,de164046,1b631b2b,8cc43eb3,edb53185,fc1822e4,c3dbc990,691987e6,a8c318d,e381202e,a0c2297c,f06668c7,a2f027de,e5118a2c) -,S(81e47ea6,b60a3819,2094e7f8,f7bb3f48,a839b26e,d2aee7e3,e159bb39,798cac0f,186a8c4,97ba163e,aa779f6d,a8cf88a2,9f5d79f0,43e6f195,9c14bb1c,b1a53967) -,S(e15af4c7,8c61227,ffbf080b,a3b1dc2a,4966639b,926aae67,f2bec480,5c1fd232,76fd417f,4fe9e7c0,96db39ea,180d38ad,2360eac4,2730186a,b1da32c7,33fe9a63) -,S(3a185818,fb47ffff,640f265d,a2c712eb,f7e022ff,67a21a22,a2e941b3,f72639e0,8d370a41,1f133f43,34534b15,655717f0,73293f59,3bd34c5a,fc5c933e,120e76f1) -,S(18e05d9,2f227564,b572069e,18a271fe,2fef9d81,14eaee28,adb0fd2f,5f078e07,75f390d4,6e8f464a,d71067bf,b0d6596d,a945ea44,c7ede2f8,a9082440,d7e9a263) -,S(7bb788b2,4f4e5d49,2af81fdc,2f3a0274,6eedc5a8,cc74d1cf,ad17c2d5,4e80a107,5b28450f,1cd8c61,2b73038,ae889c39,d33cd64f,d452ab5d,28810177,dbb6a28f) -,S(a156cb3f,e4425b79,3334e19d,2b1208ce,5e6e8fdd,78748c0b,a1116031,912fb9d8,b2571319,c644e959,ba401415,3cba9b3f,cd8ac2f0,f8fa1f04,2d59ecce,5de14d21) -,S(eba23049,f5228794,1651a922,f60bc406,aa15acd1,59eaaf37,d1f2cb31,e7d20b25,ac8f8df,155b2703,d65b33a9,af581a02,8afdbe06,f4927a4c,5546ab7f,b5b2cada) -,S(8203a1da,56c4fb7c,96816507,f99a9a2c,950da51d,af7d21bf,123402ee,a95954a8,913884dc,10a53ab4,6b2be70f,5e2d201b,4c6bb23e,b6644817,b4257664,ed2ece88) -,S(d46609e3,ec19ef57,97ef86b4,ec51b8e5,7a854643,f817e7a0,9be4bc7f,291e7795,e1b3a8fe,3cda0479,11ab8c09,ecbbabd3,ce96974d,8a309ba8,c38c1d04,ef730830) -,S(1ffa9ab5,8eea8682,76849108,9e12ee5a,cb0ea4fc,e6f68436,377e985f,fabe919b,302140c0,7d64e9eb,6ea74636,f9efff59,e907a16f,5c876658,2f4a242c,b52f1236) -,S(4032bf99,32057d1c,8b6a8923,1575d3bc,6e2d6d0e,e1c7aaeb,ffa9ebe3,bcd9a0e3,13ae5217,f9f70a4,5f626295,b30eba49,e9f7c697,e3ed7cde,95442a03,b7916a54) -,S(8d32845a,14575fa5,ea061425,5e48e37b,f3a55bd3,9d924648,209d26ec,b94a20cd,e0416169,8f1e1626,18ce160b,e8b502b0,20a5ab81,7853903d,ad7ea792,b76266fd) -,S(403754d8,1a0dbcb7,1ff4893c,a5551387,b73d64b0,25bb612d,5e2187e6,7acea8b4,134dd3d6,8d642070,cb7778c,7ecc8d78,5c1deeb7,2582e25f,5c58b19f,2f59256e) -,S(4fbe9818,60e5f281,cb1afa62,8e8787d3,28afae7c,fcb73637,e2d64337,bd6e08fc,31a10b4d,78155900,7cec4099,3b5c59f,4bbb2328,b00a7550,572a604e,8d55b6c) -,S(a5414064,747b2ac1,e8868074,3a0fb05e,7ef510a2,a48d4f44,4647663c,b5c48b39,4b3ba626,56cbe6ce,2f228f8e,88d00ddf,135d6b81,979286d9,ec41c81a,f74ef7e2) -,S(5af99ffd,9f27830e,6ba54e05,63b3bd39,4bd8cdb5,764f78ea,b103405a,dbf3a01d,f625b35c,f510f9c3,db948363,3b2951e4,b2209b37,1397bdbf,1d899a7,400a4318) -,S(7fa7dbf0,1b2fd3f9,3ff4ee6e,17115c19,1f663d95,ff446dc9,d53d3e31,c98026af,f8aa82d5,28f2ee61,1a71b432,d553eff,ff1aafcd,8bf18e3d,b6dfa38a,f33eff7c) -,S(4838c0c,ed78e7c1,e3707d85,7311b2ca,6c7a4396,5be4e363,d4a374d3,36324640,4404fc6f,1a6c1751,3354d364,ffd43bdd,61b874f0,714430be,8a5571a1,808b5150) -,S(309c59a9,b42b374d,5c88136b,43310fbd,fccd6ba,e439e7ce,3a9c5e7c,ccb8dda1,fdded8d0,661b8ccd,834e4762,db87640a,fb1e9636,b894dd48,e1b4fb54,863863d0) -,S(1cc76e1d,788111f8,eeaed575,43afecba,548785d,3d66296,223142a4,7be59190,560e4685,6204121e,402c977e,76fac50c,446560a4,9bd2be30,c6dd2c58,62ef357a) -,S(188e8999,b9de6190,a65cc051,f936585,9e7a0498,4452402a,3093b4cb,24116589,aca3c642,dec398db,81fab67c,d05ffa2d,948a430a,e26eaa0b,ec3b2cd1,20b01666) -,S(2fca76ef,b917fadd,88e30d06,d6f398e7,6803307a,b8ac9817,4baa2945,9e9517eb,186c092d,95755005,4292ee1b,986b55c8,ee3be8ad,8adb6387,5e4dc582,c1105078) -,S(41d690fd,b5eb4f10,8aac4bff,26eaf866,86489227,b6e59b89,25440780,10e3eba3,251f34b9,d69611a4,31fe9605,7be2e10,6d058db4,34e0c814,b0b8a0c5,f2e50b63) -,S(282f850d,344e63bd,abc4542c,66cf1f1,a6807b1a,19ed7864,82d06a6f,a03b1e05,de82333,48fc960e,b22f5641,5265c1bc,be290ed9,4ee81fae,248d4676,d38a1a5c) -,S(bdba09b1,c1810ad1,ab2f5da1,b628a44d,a8512221,993c83ee,4a9484fe,6416bd2f,7049aac,e507d6f8,d77587eb,b8759f51,1b7bb2c6,5de0481b,d82a2f82,246d229b) -,S(e7e238af,4639d3f7,e5ec4298,65aade7c,c1127f41,d04b3d11,477456c2,b155a79f,da29edf,1e3c0ede,5546ed8d,cf8fa801,b5bf0dc,720a02dc,d9d706c9,a9c6bdaa) -,S(53a635cc,4e24790f,3ec5c17f,f854e2a1,800b2529,fa882945,50a0d237,58d622f7,ae6bf987,2d3a31a7,4f97299d,2fbae146,58c32dfe,418ee242,2029fff8,166656f8) -,S(10750fa7,df634f7c,7d8bd73d,e056e48a,50c413fc,282748d9,f4d0b485,d0ac5c1b,fdc72a01,883f0ed0,52d97ffa,8e6935b2,3f684f58,5e6c29b3,702f5147,dc645e04) -,S(881e3e57,ed8f639c,5023e45c,4e843bf8,e7d13323,289f92c7,143faf66,a65c3fcd,12f991ee,3390b45b,af1aefa9,dcd20da2,5891ac5d,35073750,47836a0d,e75b4dc) -,S(6be50501,4d72c612,bc0d5df9,13beac50,bafefaf0,aac7d032,824a102f,25bb45f7,4a0e0d0f,f2477287,ebd8c221,5bbf3e33,fff7194b,4217f9c7,57efa361,1b3abfb4) -,S(2ca955ef,23ed3481,615d1f0,db0fe5b3,f0fe5f1f,1b7f96a4,bdf814af,c4a58987,2dffc8f1,ce4ceeaa,d09a7610,7ee08e48,a591a177,9de2c84a,765a53e1,808e3c78) -,S(250da25d,5be3561a,92b56f0a,a7ab8fc2,bf7398d7,aca09237,3d416615,6991a05a,b0e62549,ca492ef2,9ab753e2,62b9c3a0,10df946a,99a982ab,812aa48c,def60c81) -,S(57606839,4791a29f,b66f2314,73b6bc6a,ff383623,c889695a,910c1894,d9c060b3,bac9ea05,7285d6b2,7911b19,b32fec7c,1b25db58,ae39eede,f4aedf09,46c04ae1) -,S(46edba34,d53e958c,c3e4e74a,ba8bb4d7,c6266aa8,9fe804fc,e27bb8eb,cba98e2e,2b85a88f,136b201f,9a1747a6,dc55f59b,41049a69,f824e3e2,f7f00787,f687aa6e) -,S(5d4f6ce9,ac52d698,1a13e73c,3156dff3,918d5b72,5e42f415,a503e573,bd6611fa,4c633703,1de35eed,dfc5e646,e8b0f812,2b951fa5,343d7b59,ceaa5c85,e1ce5c08) -,S(c77db927,f7e637fc,24a38bd7,f605383e,91e4e2de,8ba5b1ca,baed4376,8ae120c7,347f43e9,47b5d13c,c7cb6fc9,fc2caa5,2991a0e1,bbd4bc96,d98ff26f,1a81bc5e) -,S(ebe2ccfd,ce91b78c,95cdd34d,79fc9a28,478c406a,224bfb4,668dd5f,197934f4,d7866df2,d346bd30,84ad837a,a0c65cb4,62cad5cf,3d23b0e4,bd260fbb,f4666ec9) -,S(ddc5f94a,d4420ae4,8ece780e,26940338,294b8929,549fb897,82c06e09,b7935549,25802633,a0127d73,21ef0a12,a2a6eb32,692f2d30,5e7d3cee,f137eac5,8896ff71) -,S(e4000918,46f79f21,71b299ae,6b93108a,9377708a,e7d3f5c3,147a98d0,95e876b4,c8d8c4db,8fdecd8e,fda047f,b92bd9b7,3c999493,27c491ce,df19718b,6152c434) -,S(4add9850,90e16b5c,525de57f,a15a9c38,97527b6d,8683e407,3a978cac,53b29b66,dfa1601,d36d2021,6efe432f,8a335e2f,42b6d645,7fd6f032,d727157,32a85dbf) -,S(8a5536ff,ff9c9dc7,b2a67823,5d60ad10,834c9029,bc243f3a,f10d7e14,4ca0a78f,72ee78e4,e0a618ee,191dc7fb,c1143e4d,70ffd570,bd50ce8f,d368ec29,c22bc926) -,S(9f708795,6233a0e,59757e17,5a87e34b,f7a7485c,94f9aa62,61854b4b,3ac62c05,ff9902b9,6a6cd1cb,6ea35965,3527decc,7827318,97b5c8dc,c24e2399,fb16ff15) -,S(bfa5d3b,e3fd56da,d8e70330,dccb79f5,bcc46cfc,220f4921,4cb8e700,e7cd0ae1,2a4870ce,aa2e001f,567ac21a,79eefe94,8763b5ab,c63fa649,8a5cffa4,126c6d0f) -,S(a965e34,47f07286,b91df55,3e4211af,e6b837ad,a9cc10a4,905975f,1983f2fe,393bb45c,3f6eded,b6de1e70,5a706501,cdd10ea0,2548279e,c75e4dd9,15f0da2b) -,S(e5e38677,c1e4a659,51358301,dbba1e3f,c44f5c23,af7011aa,5ab93ad3,c69b18c1,7939d32,de371524,c3b14f5c,745ea023,34f9222,31f29d8f,c8294802,b334821d) -,S(473453e1,80511622,cbe6df28,46f479c3,b8638efe,9af11beb,21dd093a,24d243e,e2b897f,eec79c08,5afb9daf,c9ead107,57d21019,c655d0a4,e5254a69,941962c7) -,S(fff734d0,e5f24c63,dfbc061b,bac37c88,ec5aeead,4974cefd,77f1eb5e,86219772,ef8a22bb,c29c9756,37c600eb,82ee5873,778d539c,a289a50c,5490b5cd,8ee0bfe2) -,S(d0508f53,85f92779,809a1892,43a58f71,47f643a2,a8f5876,510b191a,fa292dd2,329eae7a,2ee52766,a5a2874c,3912d777,e23c4aee,390aca18,140ced23,b8e82d8) -,S(93170604,98fb43a8,41d09d53,98807f99,23405879,be9f224d,52d21971,130fba89,e84fe72a,cd89fd4f,f7db1817,edab493,5f809b78,6d0c3448,f19505e5,a79e60a) -,S(63634cc3,ce570dfd,8bf90307,f4543528,e26f2637,ce32d690,75cecd2f,63dd127,bd12dd78,7ebe0ea6,661dc389,5bdb6478,7435e9da,5812d06d,d9188b47,e1a31939) -,S(30c7e2a7,925a47a1,5aa1e2a9,6f564e31,61b7a559,3af1a696,91088dc8,9ee64431,5ef4f2d9,cfefe53f,3dc76f96,1a04bd71,6aeca894,73553a0,1faeed0f,6bd2d506) -,S(f7b7e1e,d56b7caa,74f60145,98c18126,d8bf10ad,c37cf1bb,5e6c88ae,f9f6e6e4,a019d45a,7e091a62,8b7125e,d3720f95,dcc091e4,2ff17050,da596fdb,58ebc508) -,S(c6e9b0e1,177dedb1,2e19a0c0,d1167a8d,8095b2fa,1f2dc402,adef0cad,d5d87d3a,64440da5,2b3ec64,4565ad12,6f732ae3,c81276df,5ef15605,3318693c,91c12b43) -,S(653d41dc,e6ae6cb9,45533e54,63b50a4b,72f6efa9,7884d878,52c32eac,fa0f59e,693da28a,13a9cde,d1b7597a,c199e00f,fac2f6f0,6bb0dc58,940b6734,e5eb934a) -,S(b9830b38,f0f8d466,e363fe57,38124fd1,8c9f60f8,cdaf6fd1,a10205b9,5c7212ce,a3e31906,6ace61e4,ad861027,7a12d498,5c35969f,62e5573a,5bf4ac35,277cf444) -,S(94d9457b,eb2bf3db,cd38a667,adda8750,f449af92,6a92fc93,f1dbaa85,457182ec,ff1bd647,8f00626d,1b203da6,992a2366,2ca2b39e,f6c1528e,956d7d81,7e2497c5) -,S(816f295f,1648ccd4,360b1807,bfb9b05e,4a84af7a,140a1f2a,f4016527,1d4b5b80,98217f98,6ff6f38,1987db34,7c6d432b,f24b664a,bb47124e,641d0677,aa4ec143) -,S(3b830637,17254b06,16c1a5e8,999dcdc7,cf3cac91,67284981,75c6909,92e2b2d8,dc2d471c,5323eeeb,611495f9,cb37840c,905eaeac,a85cca33,76d24705,d152acce) -,S(33282bad,f48bba9b,3db3cab7,c3b46c83,867a63b0,db393ed1,2a4bf49f,cd2f7c5b,78733604,b1c94144,ab9a4886,80bc53ec,9d67c4cf,dc77af88,40bc3535,f2c42309) -,S(58e15e93,95c3abc5,2ea68f94,6e3f7943,b1ddcc8c,e258aca2,8cd9f5e3,14b257ca,d7c15bc8,53dedf6b,f7dfad87,bcac6e37,f90d32b8,344d95a6,44879ba1,e170070f) -,S(c9ee3e27,54e8c8a1,e99c39ee,cd3d0b50,f8fcd03f,ccdab94b,e503a1ef,b66d900f,a1ce86c4,7f78400,51c87612,1b26922f,2b4b2358,e302c568,da6310f5,14909db5) -,S(6e2621bf,dcab8898,7d50b5ac,b27eb94,b52cfd9d,29e80d2e,befb5478,a3c5a514,ec4c657f,ebbe25bd,9d6b172,68ada77c,5bc4f32f,57f325db,9556ae0b,4d1adda2) -,S(6e3c35cb,9c86216a,250ae256,f8ab076a,76264ca9,97b1a6e7,41ee96da,5cfb2c9a,d45f0082,46489230,268e5c99,56dcff9c,bf6a0621,f8978be8,f2183920,eef3dd74) -,S(f3b5baab,882e20ae,b0f444e7,47688392,37acdb60,e7c878ff,40ec0aab,7896c278,7d8d6b2f,92addfcf,a248aa96,e8a87e92,4c821c1c,cf7b343a,f588ce7e,93e37260) -,S(b89b2380,110087ce,8c8bfded,7dc98e40,3cada8dd,77b2e68d,120361dd,6beeca0a,616e00aa,4aba8494,9835b0a1,eb0ff955,6268d2cc,91b7672,d0164693,848389b8) -,S(6659b720,1db6e160,58854e12,dd78b89d,40d91a17,b7eac836,ab8453c9,ee3cdbe5,5ac9db66,325b000,1983df0b,6693d93b,adf7e35a,a18f76ea,e2053e34,b1b8908d) -,S(6fc76d79,bf3c34ce,afe73e9d,7a77af23,bcc7e894,dc555f63,8b9d53c6,c15803e6,c366b411,1d6ee57d,52d3938e,f2c0c620,746d636c,92ab73f0,bc812888,ef0b5ac0) -,S(a06b2395,238326ea,20545cd7,b021a5cc,9e21e9e3,26c28b1c,fb50f3d5,e0f6e069,8560335b,a5c16aec,a297f185,ab09e976,dc57934,61170b35,b8a3b6b7,4ff622f1) -,S(bb8064ee,177f3753,19e45c8c,4dcdda70,ddc4bfff,1a866b7a,ae7922e3,13d1515a,a3be84ad,274704ff,e7a76277,d87687ff,572633b,2fb46b4b,40f601a1,ccb98d7d) -,S(27f08788,6a2c0ab,8f26ef15,a85d2d38,f6fb8cba,622acf21,77ac20f2,f05962be,ab2f2929,45163b83,c9cda8e9,4f6d8f7f,167bb589,50d4226f,827c5b5f,a782f8d2) -,S(f51d558,dfd8f74b,7c9c3768,65f82932,65c1bbad,d8aa64d1,ebbc09df,b7f6de1,101c88a8,170355ec,ac23ac98,ab5aac67,7a68a94b,9343012f,74cccfe9,308c039b) -,S(60fed665,a3ba26d,eccd1ab6,c956ed2f,e33da384,dc687f41,6c37b550,123a5441,4bc061b9,b2d7c63a,ac042a7c,efb2b5c6,a43260f6,8bd0f843,fa218cc2,3fc9b5bd) -,S(fdb04aaa,f2958755,ed65f968,ce4fbb81,ccd8c616,32e9494d,510a7b3e,d2564256,afbcece8,c52725ce,c0ef2aaf,a094385a,831afaa6,7c4cdc9,57712bf6,1073990a) -,S(7f45848c,cac04d5a,d9caa28c,e60628c,aea7f076,262689e8,27fc7084,d6b94dbb,51e16503,e044b101,a0d12d73,3a57d8c1,546c1f04,386721d7,a6f9fb15,458e41c9) -,S(b4091018,4c556249,30ec006,95f02723,b9cef749,57996d50,72642d8a,b492c9be,1b3c221c,235e721e,95bdd451,f0f0fc8d,a6a18260,d47b0c09,5f3e1b1e,f6135e5d) -,S(4d5b1a50,d00b83fa,93ab4746,3f84dc21,d0ff4559,2e697fa0,bf8e8f68,5e1c9713,da52a118,24ed00e,6a2434d1,ab383f0f,1e495dac,d08c6a2d,2425e25,a9434af2) -,S(63fb80ea,cb68910f,69700533,8a1769f0,69acdc85,da71618a,9cc03557,1d4bdca4,7f2e51d0,4446763,9cfdc2fb,247c7cb9,5b8e01a5,e27e6bda,6713ba98,1936573e) -,S(f5035d5e,12313edd,b0c31851,266f7e92,6f16c1f5,a6031aae,bd5e14fc,18304faf,7381fc4b,cfb33c18,7bb59e22,be95081c,6f52cefe,dd84bf6c,799f419,453f61fd) -,S(f62c9afc,5a2cfec6,afd54b78,375a73b0,eb5a73b6,f53e24a0,6d1e9111,ff20e835,a5d386e,211845ce,9ffeb917,76a8b91e,27f0773,b2d53fb8,2ac44b8e,83198350) -,S(7477749f,3824c134,c1a91bfd,d1b646f6,43f8109,c2f46887,22799f6d,53e6280b,232b459,2259cff5,99e4af77,1e03c94a,11fc32bf,f2598beb,2316d3aa,d9461c55) -,S(2e2c5f43,5fcf4fcf,72f9629e,ef6ac5f4,31073f2e,7034d6a7,64af194b,1e84b6ca,cb94ef61,c794f44f,2c7d1115,b9dca665,7fd1c184,e30f6f60,caf40e75,142ee26a) -,S(8f7e4f94,fd2a651,86e4624a,93272af8,2d362587,62a0baae,f65cf47a,bcd8214a,9edada6a,d23cf1c0,dd98b1f9,d9a83879,4c21654d,239f1a9b,dbace84e,de6145a2) -,S(e184ae37,4704eed2,b054b667,33544ff5,6ce55a9f,bcd7625f,740b6a67,621c75c3,ea773744,2212bf1d,a26fd119,248b0c51,c413ebaf,75e52de8,97b4383d,b397e144) -,S(fa47fd9b,94cb72b2,60fe208b,c022dfe3,a2bce2f9,ec776313,a497cd91,4166850e,9a12bbf8,a6e0ff91,5176f71b,16327c7,ea5d928d,816de31f,c8de2be4,57b0c185) -,S(98d36e76,a4caf051,e848fa49,64e09bfa,815109f8,63cd5e99,405e64ec,d526c67,706b36aa,6e67352,8fed83b6,8118ae7,1e043964,f444c477,590430aa,8d80d19e) -,S(e7722849,c00c5875,44751cf9,a88fe964,9efc05a3,4d810788,f30a2057,cc1d0c72,d64ba14f,978e1769,51951a4e,8431af78,57e6d97a,f5fc5ba0,2a1fd46b,1c215e7e) -,S(93374edb,547efea,e5f22d56,acd80ce2,80e4d47a,bddd1d9c,9d85afe4,aa6fe6e,e9c40824,cdedb038,9b42e2e7,2e15009b,215d9080,7df6316e,6e81ec9d,40dbbee3) -,S(840eb546,a076bf81,e4954196,6eb8c437,3a055239,8dc4deb8,62a73b76,8b380e28,97b69f93,ac1009d,a3f47ff1,b62ea845,f2900d7c,84e8a1d1,48d96f,df6fdb98) -,S(fdc4ef19,59ca06ae,92587249,e45d456f,d7484278,6f4b3381,676094ab,446c3e8d,c832aa3f,f0ce9f79,1fbe89e1,5511e25c,6a7a4230,401471c3,7b9ab011,1b304366) -,S(42abeb49,83403d4b,5f529eff,16bb991c,ce705250,5a61fd6b,96467a51,f661651e,d815247a,f807af52,b454e83c,9d46327e,d80d3ec3,60f84a3c,dc88b9b2,59efb05e) -,S(176fc9a0,b44a34ff,fd652cc8,bf715a12,a9d5f40b,adef6032,24536660,5e0680af,a47100b7,e0fc557a,f5ca7dc1,c220b5a,770231ac,184f14f,57e554d6,11daba35) -,S(11fa2a03,aba7cdd3,1940923d,37045c99,ff531ba2,a1266fc,26ce7a26,c6495e63,360c9e1c,54fbc823,9878d725,30254bfa,70453c3b,934915e9,5ea4542c,1026b272) -,S(b2dda11e,db5f668b,8d90dc96,9d10f8dc,6c95a16a,a3e2cbb,3a1ccc03,d9acec22,f4d44dc4,8c260995,4fc1316a,2d5bfe6a,18ea754,43bd9a55,2b2f2f08,aa0652c5) -,S(baa1d433,e2adc426,5f87f407,1c8c35ca,423f3e76,5a835a70,2d804593,cfc3f7b,3f55a493,9e25a77,8a9d3ad5,4ccccebb,8a45486e,1aeb817c,dc0a2799,6e70e996) -,S(478f18c,30470c65,b578a6c5,df9c71ac,934e3439,ee5d5d23,21f8f5a1,7adfe55c,c43dccf1,9a9e48c4,41ebdc12,f2876cbe,32852cbf,d3bebc9b,a3708fe,6cfa450e) -,S(18223de3,d62283f6,c440102a,a1769ac6,f5e1a0a2,cf3fdb2d,ec62563f,4e149ebb,57fc95f7,f8e3151b,80fa4e68,45349b7,961fe72a,d6ffe725,e3a0a0f8,907a4555) -,S(2c8c523e,179bc8d2,1e3faa5f,5db5dcf2,cfcb0426,3f138cde,428746d9,94a17276,c3f00baa,69061521,5d512c97,aac1b858,40842fa0,d8bdc773,4e11d370,4f6330f3) -,S(a001d77,af44959f,f1e83be7,d6b16496,2aecd428,3ae2c38d,f3ed3fb6,a0f12460,e68a305b,6f60a1ae,5a01eaa6,7675f0d9,8e6c5baf,75d725bd,d0e2a499,1c323770) -,S(cd8a1d36,2ba4a2db,255ebbab,ede7ab7d,383b641c,515250a5,cf52a2b6,a5b2ea9,20716fe1,e0857b5b,55b836d9,39d3175,188a6f9d,d3cc42ba,8c61a7a8,d9a7a1d1) -,S(7796adbb,7949b234,6df5147e,c3d7e0c2,5b61a874,43fea9f4,b4e742fe,6c1218a5,fc338089,c80c6415,dbb32994,cf5e2af6,b5c3342d,d291d7da,def80628,a904edfb) -,S(3c345146,27eb74dd,88ecbb47,aa9933ba,b7fc8cfc,bd80654a,f96aad51,5c1a7017,cf4318c4,1c021c06,5c100913,dc84259d,2b8d6ee8,102e5c6d,c3f809a5,7f8f2beb) -,S(cb4470d2,d5715339,acf391e6,5e3cc397,eac932d5,5acb65cd,a94538fd,eb684f67,15e6e6f3,383b8bd,1b674497,589ed7cb,e0f41394,e366ec61,b7e1b927,daa6434b) -,S(954a527f,c4496d02,915f0b11,4e95f104,c500be4d,a61eca3,2fadde9d,c1f118f2,96acbc82,d0dd6226,5652b61e,226b7ef1,c6f00491,91bce5cc,fecaebd2,fdd28ed0) -,S(d3be92f5,697a11cb,b8374938,9fe89418,97707ffb,24fcce90,16debabb,a4faa4ec,23d04ff1,e309abd2,aeac3159,ed9acffb,9c5336f5,517531c9,f1cc2dc3,a2d300bb) -,S(7490df7d,5a7ca290,fe029f3e,d92f530a,23a7c983,654bf19d,5c9ee21d,b4f57586,3d7f28c8,81b259e9,f5f735fb,be608154,b80f38d9,b5131bd9,a6e2dabe,7ab2bd54) -,S(992c4a82,1176a784,ba2767ae,a3d39697,5f96ea50,b7bc8947,2356fd98,20aa666f,519d9792,458fd39,7050829b,6ef7449d,da4ebdcf,fecb2a3,8ca0f057,f051c851) -,S(f070e211,b384b497,3d2dac23,3373a3cf,6dc7b9a6,2529af9c,b2fb1e84,b40901e1,175cb1d4,f8339521,26d4b41d,9fe27781,92a2a1d4,7d5faa48,1e96f51,beaad506) -,S(108f6113,c2795472,244db9f2,3a1002b9,349bd34e,f9c9d70f,e146df96,be198ede,2bb9d195,d087015c,253af145,bdd6134a,1845dd92,45d7d8c7,c12ad2ba,2027ba2f) -,S(ceea04f7,9b611056,ed7043f9,707bb318,e3ad332,1da82104,9790b1d9,d264349e,5380e9f,1c52e5ba,6ce18afd,289f49bb,c358bb90,9db23d67,a851dcf,9ba5ec9) -,S(1c74297b,14a4fbf1,2a6421f7,561c549,414147c3,2a683391,c4cc5eb0,79948cd7,581c9642,98232591,bd5469eb,c1a01be8,37bd5d43,cb63e21e,8540ee84,52b12ab1) -,S(14bd0f2a,ebcbdc9,22fe8660,c63bf12,c6db8521,f1f0acf,7406e982,a103bdc2,46c3002b,1e5f25e3,98c8d7af,e340aab7,23ccb0d2,7e24bec4,55d547ff,1df59c96) -,S(32c923a1,526240db,b234ab72,565d6880,b260e7a4,33747aa2,802da713,c30ae9a3,b79bdd74,6ce4ecd4,a554d66e,b787e312,a1ed53e9,c77cd6fc,73b1bfee,8b13d620) -,S(af0ec2cf,21ecdfc6,a71c6edf,6f73ab6c,76600a89,86b62006,8b246008,7cdf168,d229f3c2,7db8019a,eeb8f25d,84f3e341,681de4ab,2173f510,51ef4249,7a9dbb0a) -,S(1d648075,8273a9a9,c970cb10,5ae7e537,b017aadc,8be5044c,a1f6a3ef,4d2cb275,3faae8a6,87925e3c,e9c3482,d34c76a5,702c9bea,a307aa45,f2ee992,efd86387) -,S(160ebccd,b4d5561b,488037ac,25224afd,91c66584,660af970,672d9514,87376568,f510b49c,b58b09f9,46001627,2fe744cf,e6e7abef,8f54552b,41b6158c,2ce2db5) -,S(50867128,704795c1,a190077d,49a87c99,8b10601b,c37b7aa9,908ce92f,28969c30,106fc462,a115f2b3,e83a5474,7a692101,8c73853d,83d8a1b2,2b0bb785,bda8a896) -,S(3ff4aa26,7e8d344c,ac75a46f,7b17af59,5d056078,fe860a96,573a8f0c,164c54ee,2632d1fe,f4b34a45,ac38a80d,236b51ae,de92fb72,47b81f6d,af1b9554,4d426d82) -,S(739f875c,ebe795f0,cbb846c5,88c2b809,21468ec6,4ae09034,6032a97d,fda93c1c,8393a2b0,f3e68c9e,a57d5c8b,f8355d8e,71f4699f,201636da,5451023c,92a1b98f) -,S(717bbfa2,b2c4818,ae620498,3506a421,8cdff59f,2e040521,764b8013,b688c7bf,9229cafb,e99cbcd5,3f73938e,82723d2f,e7187ca2,13d9e0a,57c12254,dbc7f63d) -,S(cc0a808f,2618d1f4,27f165df,4412739a,6ad9af38,e8c25a2b,14bc97aa,1c5b0f7b,3b83d5f2,3d94aa87,9769c3d0,5e921731,17c345a1,3418ec3,2f92d4b2,c1e275ad) -,S(4a0b31f8,8f82abc5,6867fffa,6deb20d2,d8e7613b,aff466db,b260734d,1ef8b1c9,375d7c69,83784dbe,a5bfa8c5,8f8baead,8e94b9b5,95c01d9b,2747a06c,5fb7272e) -,S(52149a1c,53b2da97,f39e9dd0,23443cd2,b21e404e,b6235014,ce04c616,9f5d05a8,a9f9a4cb,ea6d202a,c6b5aa93,28f583c4,45db83e5,8ba7fc25,3eb43e3,df7f542a) -,S(6e294aff,9e9fe4df,9345bd93,1229a7b0,955a3b63,fd19d1ac,57bbed72,50262b8b,abe6fad1,5fe423b,e1a55867,137c485f,85639823,beb6ab2,81dd9e1e,ed447123) -,S(e9a70c2,c5e962c4,dffe24f3,8930e095,c2b0b540,cca2d891,2f6f5b4f,e4592e9d,8d115293,95051750,ccc9369,63b987f3,96bd05a1,49915103,1e47baab,358decf8) -,S(e6c934a,57ec5422,5d42dbca,715e62fc,ae957590,52849f8c,b5f282a9,b82d4adf,6da738b2,40ff3070,bf0c4ac5,50ca5a77,31db8a07,20312e2f,f9de572d,d7b67d4f) -,S(89b46ad7,cbcf1b6e,8741e422,ef53beea,49662d96,bcebbffb,57baf0d2,1441a0a2,b7205431,1798624a,3a1708a8,986ca47e,374d9704,22f7d3fc,57ca7f22,94913e8) -,S(5b949cc2,69f0b0a0,c3b85fd9,e45b737e,7379a4bc,70d926cd,cad87ae3,4e7a686,7e54863,c1efbe6a,a98d6466,65057347,7291b068,a43f1783,9d02b190,9327bac9) -,S(787baad8,9882587a,97b049cb,9906db7d,b909239,aa50e073,d476081b,4a73d7eb,8e3bb416,b57585f9,8b337b72,b23c2b9e,c790ef6c,bd397b18,ab78f8a8,cb662425) -,S(58460ae1,5a204740,c375cef9,e447edc1,2fb6a0ae,2f8d18b2,8e82ba60,729c82be,1bdf3641,d16d89ee,378e83ea,302efb0e,2a9471ac,9bcbf1e1,662885a0,81c7780d) -,S(c9bc29a2,1f7383a3,a90ed3d3,fc5f6d32,1697e354,a77173fd,77899d17,2012f63f,1c850132,db81d86e,e866d9e5,75c4f7b6,270599f,2e48c0b4,94317dc3,97d1043b) -,S(d4c54b66,a1ff77b7,63f8c520,181e4ae2,6b82643d,758f872d,cddef933,36cb84b7,23e64d9b,f7456086,ce8b778a,194f8b8d,f1f0bf38,fbb8454f,d271d062,ddb9b9ce) -,S(a947a90b,b27db3eb,8b4ca4cf,f947e587,54fe6a48,7b922ab1,9ef4b5c2,99eabe3f,c83e7022,f6e12dbb,f95e95dd,2bde8b94,3d72cbb6,5b222f57,94d13251,c9fb975c) -,S(d83f6040,4099d448,8ec6785,131524f7,3e58727e,829b3d58,7d445197,cb367746,6d50285f,831e1173,cfd7de2d,d1c7c29,532a391c,3f450b7,f25e758b,f412a8a7) -,S(75d60448,78902615,467175b4,bc16c936,14bb10e7,c9fae9f4,57d4a210,2d506a0b,885237bd,b4277447,fc7970c2,4e3e7240,ca24a07c,e46b8bac,7a91272c,ad9c5854) -,S(1f96a542,2ea4726b,b639d270,17eadf33,43bfbb7f,f1fe9307,a20fb5c5,f1c4fda,5f80a9b3,ec8b0fde,ee914ae8,e6052100,77701a73,57829803,4cac5d44,91ce0a22) -,S(3c0159ab,4f27b61e,c2599ad0,a79b4228,9000fcb9,ceadb440,24e1527a,f5ebb9b1,77df26bb,659283a,37abc70f,9f465794,ef3fb178,107ccaa7,a5404c88,a67a12ef) -,S(5b250c4a,25293ab5,34f287a4,9f9f966b,7ebc1c93,e5a774f7,c98980fa,7980e07a,dd6c9c36,5c015685,9e1ec5fd,3a740d1d,7eaea301,2311d1,a9cf505e,7e594613) -,S(20a6dfe3,71696c50,c3a7abf9,3341c41d,9d6d2111,729fe45e,f3ceb49e,977151fb,bfdd0224,fff97fd7,ac3eda1e,ec0e6f02,8bf7a3b8,23cb49d1,52d643e8,fef3d820) -,S(915fe7ad,5840d789,b94d1bd3,2d555340,3c9152f0,340a5f87,6862ca40,19825b79,8d2f0ba,3459615a,2036a07,ca57d0e0,f3a4290b,f5fa7327,2431e3e7,bc44255) -,S(d6aefb63,618e2fd0,34e4f17c,eb766d5b,c27c9a15,d796b16b,7cf8ba71,31a2404,f0abb6a6,e862f6e5,d71b062d,e9bb7b9,dfb2e4be,1c5a85a6,dd3e0c25,3617e8cb) -,S(4c804837,7d65a97e,f65a342b,c4549e16,5cb1c50c,cd1549e4,d2d2ec10,c663882d,e1ec6bee,d0bb7243,a384e6ef,100e5180,4de6ac00,b06d7b67,3e445dc5,7b76dc8c) -,S(3a6df802,f372b56,1ebed30b,a4740d03,d257d256,4931422d,fd3c8c1c,619847f4,d168c60c,9a86bea7,e48e58db,d8e6bdcf,b6ea7d31,d57f8996,70f79e33,241bc439) -,S(423eedec,169fa4aa,52588642,a62ec6d3,8acf2ca1,c8098c24,4a56a6b3,169f9932,4887b475,7f27b4b8,d288c05d,3efc1d98,c0428b5d,e4db1cb0,6dcc4782,10cc6f52) -,S(2864f372,8f8c5ca7,5dc56dad,8b968c71,a008eaab,80b8bf28,16bba436,78465be6,14f5e2c3,423f863,64962871,b786c840,50cc07b9,f537ddfe,cf81b95a,a276b813) -,S(cb96234a,985e2ada,d8130ec5,472efca5,7ed7331d,ae7570c4,dd42f4db,9597ff08,69722bbe,5b367ce,5868b30b,31f67c8c,a5f047ba,a7f65202,48041458,66b88d5a) -,S(3be93dc2,99b7e701,ddf0f239,286ac598,bea1ce42,f1e21ae8,1cdf07a7,66c1123e,8a9c69a6,6a475e40,d81b5d0c,7734cec3,40f528f7,4fa0073c,ee92161e,cbb92d00) -,S(9022c43c,7acf3552,fed52d25,d25dd3f2,9aa61fa6,988a5499,6aa3626b,88b7f497,c514a46,f328c9a5,dc2fd03f,81ce3fda,915f1e8f,127348ff,55e4b5ca,2eba0e53) -,S(a24cade9,47a24abc,a050ef7,f62d138b,85c96d0d,2edac403,dad58ff7,8a2a9d3b,a209613b,c05a7b52,41697e24,73fa7fc,412f8fc5,b2fd0447,a2e20e71,949cbc0a) -,S(cb2010d3,94259307,ee3491c5,58efbaaa,203cef1f,8a0a1e99,67a4ff3e,719495f7,1bc5b6a5,b5acd447,baec221,141b601b,a5a3a640,7f84b8f4,319a760a,6226b0c) -,S(fda8c6d7,c6302b27,76172f01,5e59da8e,4af1e96c,3bd05f2e,a393fb7e,1dc1ecbd,87ce1baa,ef24102e,19c7a17e,b267acee,7681d40d,705f7058,c514c9c1,f615e666) -,S(b459fb13,5b9902e1,760286b,b37ffa03,ceabb618,e684823c,17ba97dd,c95ebdf5,6e35fbaf,b5175d3f,ac60f2db,97447cc4,a79c212d,5496ab7e,4b536ddd,797a19d7) -,S(ec137d8f,23b119eb,a286af6c,583ef011,5d21f335,8a1a2df,ba6af216,d03b4a36,344fd1e4,869d68a0,87a1974a,d48b9704,5db2940c,dec017fd,a0605c11,8e5c7bfa) -,S(8e0be401,9f2d3cb8,9ab07348,cae295c5,eb7fd7aa,fa5a83e9,3d68d994,af68e14f,542fcba8,51510baf,6f962401,e8a607c5,34a32971,22645ebe,2dd51867,b26c80d4) -,S(b1dc8611,3cc18708,338542ac,698a6981,a6192261,7c1f71d4,3b72baeb,1c0dab03,f3e61423,5b683727,f1cca8e8,41de0474,e8c4da8,d2bef431,3cc2da5c,c4ccf38d) -,S(d438b027,7f6c7048,c1eba2c,c1d7e554,888a7025,3f513261,3bccad8f,a5a0a9d5,fc419852,23f6ba14,adda0abc,389d2d16,4a910dab,b464232,298c2a1c,50ae64be) -,S(5484d618,5cdf3f21,42235130,62ddf251,1f53a84f,f0fada86,602c4b13,3dea0f70,6e697180,33860802,6ff41cec,cea79f48,b695aa37,2a76d046,47603a67,ccf9615c) -,S(8c1856e7,6842f5ce,82c09a82,4d343a6b,ac67ff27,f6d32de6,7117dd75,59df362c,70f78515,c4bd17c,23f61049,d6ccded4,100234ba,b7e1b9be,16925635,a9aeea2a) -,S(48052022,94350095,8c904f57,54285e1a,7a17ff81,dde1f50,8586273e,40bd531d,7f1ad451,38b44b15,33327a0b,15fba2a3,f70989e9,1c271b1,461750c1,5044294b) -,S(4adae425,86b0b95c,fc26159c,6aa0b1ee,dbbc936c,83fd6056,f2b730ec,14dc17e1,e6d0f9d0,bfec452e,3f2f9b39,4d73c72b,990f9683,b6004fa3,8e8831b4,f46f9d4a) -,S(d296fd2,926eab53,db70b1d8,d5c999c5,7eb36987,62537954,2074ae12,af5844f0,b4472b2,c33661db,50b4370,e0ae7811,b16646bd,3f4771a3,113d677c,7f1c0cba) -,S(1dbf607f,5d1ea26f,ee8e416a,52c8475e,a8363cde,6bebcbb9,bc04cf4d,cd19cd54,832c9d78,60c8acc4,5d00a568,2d28fe07,4952a897,619f8b23,42dee2b5,e20482d3) -,S(12321adb,c5997830,8689b103,ec1552eb,679a3ae9,70ccfc46,f4adab54,f8dcb2b2,92dd316c,bef2864c,bd5002f5,ba052712,3f920db9,44992ccf,1b2f967c,b70d1f1f) -,S(fa2c024b,76460eb7,a64d1e1e,fe059496,c28372c8,1d00cbec,9ea76f62,546642ee,5a848904,a654469b,dc3eec26,736d7677,ceae5fd6,d6f30adf,8c3fb95a,bd8e5d8f) -,S(a77dcc2b,218b5acc,d6172931,91e8ac19,fa4d74ab,4c88b84,775d2f35,3f51e7c3,de872263,4e2ff356,7d9e419f,26ff51b6,c41fbbf,48124d01,8409a516,9735a950) -,S(83d740a8,52a6139b,53b60796,50d64902,9f9fe35f,87689977,66246b2f,91e038a,1c630f32,722468ea,72bfa970,8a27bd9a,97b68e53,12b7799f,66ede01e,9c75b57) -,S(d894b986,d74580bd,84b24a68,eba87e8,32a9c34d,bafc5717,cdc03c22,8758c9a9,f0d68c3d,284574ea,21a357e8,cad5fecb,90a57b52,62f6ee06,1868d970,458d502e) -,S(67b4473b,3f1420f5,a8fcb39c,8671d583,cc1b9f48,e288f311,2af6241c,4190a786,14fb410e,e33f4a6a,3fe5dd9d,c30d581d,a350c756,6b513290,7f3ce97,29310b55) -,S(24522965,87039934,a6927d0b,782988cc,b126b61e,db154f07,18d97d41,6dc8f0c6,538c4e2,a7e180e2,14e36785,6dedb105,f688f1c5,9bf81d30,d92a8a93,d3c5a82) -,S(b47bdb89,b087a27a,663f9884,7ab44a64,43fc43df,bb61f4d2,bc5b7ff9,234644cc,ee508868,402613fa,1a200032,afacf672,9bb3f7f2,43b2f415,383f4067,d0212483) -,S(92eb31b5,79ac7b0f,d32ac278,4f3d2c63,93c285c9,567bf912,584c00af,3be97d8e,518e379b,ea24a823,e725a3a3,3608e62a,7a40aaf5,318c2c,41afefe8,ec9afe7) -,S(a5e06969,cd69f1b6,c30ab55,1028e1c6,1bef12b4,b2c2d1a2,572c3648,fc739332,378a3b33,3db8d289,667bcd98,9a3cbe9f,f20b08de,4047164c,7f4bf9fe,5d1f93b5) -,S(604823c2,f1ab2bf7,eba63c65,610fe0eb,c958e8c4,7f509c8b,42b79934,7fbd9bc6,29f532aa,3707e872,2169a02c,210fa9f6,100c6b1f,926c73e,a3bd0427,a1844733) -,S(1b4bde22,bfef0cb0,ec9e84fc,e3af2e8d,ce7f381c,e9766b1c,c1d5fd90,9a1bc891,ab20347e,3f4c7ba3,2bb773d1,50868756,69865df1,18297657,6c283704,49451f49) -,S(10caa116,2067d668,5371a20d,97313b54,4d79b61b,3bb41a87,980eac97,e82f58ee,7ee4f118,32d9c2bb,1f849731,d779d12,571a084a,4ecbf4d6,128f33f,6af477e4) -,S(71e7f07,513d42fd,5c0ad06c,c96ce17d,3542a4a1,a101e581,f7394c2f,d89e2072,e214ca42,1033650f,e420e574,e2266c23,3897de25,90dc3999,bee41181,db0a81e4) -,S(fcbe392d,82b4859a,2424ecec,dd8cd47d,bbb89d15,ea2b9591,f5ff1067,e2cbadaf,9b06334f,6ae45d74,44b5f09a,995fd91c,a2712ac8,b159126c,8cc0120c,513f0bcf) -,S(a64d9e9b,5c583eed,aa7934ef,a7ad036,8dc9adc1,9437f97a,7a16b645,cf46e262,9357dd,1aef4b07,a376b468,99692754,9ddfe9d6,7982a7fc,d607f02b,8a7158a2) -,S(e634938c,aaa4010f,f4a1e760,d87a253d,5fd645a2,4f85a75f,8eba78bd,d876fcd7,84be5fa9,c11d8c3f,54f757ca,d9ec4e18,86e52db1,4b3cd0d3,97f666fb,f347d24e) -,S(4640245e,23e6eb75,6e0a44f7,698c1faa,33ea4f87,7a52f850,3477ad4f,8ae2f4bc,ca2a72a4,1348d3f2,6a7fb977,d3106710,2494a982,a96c6514,7fbfcca9,1ed2225b) -,S(c2a175c7,badbfe95,cf7db594,626a42d0,1247ebe5,160c58a0,2437fcd5,eed8c59,94814fe3,7692ad4f,ef0f4fd3,41c63f84,b282324e,faafbc59,38d88f4f,eff210e) -,S(b1296159,d0651519,d76bffdd,98013d1a,bb17de49,111e3035,5f7a1d40,3d8d9148,ae3c442c,2dac0847,bd8d9052,a5470b9c,80536fd9,feb5f820,e4c54ac1,78aa44e) -,S(d30b1976,b0867b57,84d5e619,a5a63516,13980093,5a9458ed,59e4a3bc,ab69b7c8,1b1eee49,690de06d,7a71c334,4fc0a647,133f2fc2,99a8f096,a8a445bb,27f5b96f) -,S(fb1c3b4,5b0f6f0e,35b93a5e,ea157e60,134b00c5,38a6e429,301962f8,38fe51ae,cf79bafa,d7c3fb08,49e1c2cd,48a90ae4,af507bba,5a42f3fe,bb1e101d,7f5fb818) -,S(2bc4d2c1,d34c6d41,9d97ddc0,c758fac9,ff6489fd,786065a3,61ef442a,fe37199f,5b932f15,9500ef4e,a331be88,7022f42f,5148c54b,30957b0,424a168c,c6d76ceb) -,S(2744c1af,3459c35f,d8e1b27,668ac653,eb25f017,e4fa15d,6c1a6bae,e50f3a99,12f95a25,a87e482c,c647b1a9,f22286cf,3297a354,4c7b575e,aa888dd5,6db2844a) -,S(6429f3ff,d37b53d4,88024393,d3a9dabf,f84e3974,ef60f446,61ec9da5,efc736ee,e8426421,f15768f0,caf020ec,3999e8d3,a1aafcb8,24339574,fe119500,a168016a) -,S(33c132ef,437e9dd8,ee9c028a,2ad51c9e,5a836eb5,4bd97e5b,4b5b6bcf,38d006af,e2527602,e5e74d67,5a5115cb,9a89c579,c760445c,c70d95f1,9ac82a1e,6ca16c6d) -,S(3ac856f3,7d53e19f,f6ab49e3,94da6ed2,c8645e65,f4666bfb,163778ce,7cd910ab,ef40efa2,55d7a5bf,99e39055,8993f753,8fd203d6,7fdfb7d0,81cf8bc7,947cafcc) -,S(5ec9648d,b58770e0,314217e,f090c776,396f47e8,ba27c30b,98c35955,aab03247,3d3402e0,8fb71448,6ee97fd9,15293e53,b095fe03,9cc3100f,21240a24,d70819b6) -,S(54955c84,3c5dddd,89f60de3,828fe4f7,1666d807,ff88006f,b46c37bb,8a822645,c8745950,64b3c721,9eda8253,633deb6e,ac9a7825,8d1de2e6,c2dee05c,f167405d) -,S(e0e845f9,35054008,fa44cc4f,1f2e538,33b58e73,bc6a04fd,c16faa76,c1a92d3c,edc48f46,2a41dc1b,bc604e0c,82d993,edc2990d,f59fa034,11702d86,46dd1c1d) -,S(bdb43235,19acce9f,b95f83fa,485940c5,69108af1,376cd09c,884e6419,718ed14e,5669c5ac,84bacd6,eb6fa8e7,39da1196,dde69170,f5d4e5c6,2ad528,66b6d9a5) -,S(d208bcfd,f9754dc6,7e099754,983fb58d,e5679bda,96d8404f,266c0e65,9e4160ee,c602f6f,f0f586f6,7ac771d1,fbf9d807,c2edf68c,a2c10cc2,314221fc,cd3007ee) -,S(3cce9096,450e620f,29b2446,39e8809a,39000315,a887d6e3,da141ed3,32b1c30a,db0ee91,b8447860,18289da1,11b3bb62,289d21f5,2aa8f436,562e982d,bab44be1) -,S(6c351350,d0fa9ae6,e1723848,33e654a3,f3f655de,7530d9bb,59d92462,1dcf8253,2e5ea374,7a368904,e4cc663,feaf6f92,4060dd70,95bab9,ca2e0773,4c48df83) -,S(c64b42da,d63cff5a,ec1eb168,41fead6b,3dbcbd97,f6786efb,5336da16,35950d2f,73706863,cfee031e,3fee4be1,9241cd94,42c24f4c,c57faf70,f8ff8b81,f094ccef) -,S(c4b99a41,7b2277a4,159bf3b4,859e36de,399862ac,70ffb482,b92e1b11,99c748d4,6ae88f86,1ff14b38,b545ec86,1a808c5c,cc78c3e7,91b48f29,350afe20,9efdc33f) -,S(eecf955a,f1ae50dc,44b57715,5ea67ae,1ae39cf3,fd306eee,e943908b,a7a42a56,26c9e114,22cd3db4,b278adb0,8e4c16a2,1a4c0a9f,b837a493,6cbdb70c,65fc5be) -,S(454ef33b,402e3a59,d437925a,b62100d0,974abf69,8803c04,436b4d2d,5a5819c9,4a38e398,1e1d9809,72df7faa,b06bfa96,20fe213a,36ca0227,c7c20ca9,2ef31563) -,S(50f11935,c20dd410,7a2cfb65,2c94e39,8df7d985,c183259a,70f6a04c,6ac5734a,aed27454,75f207b5,dc1e9f4d,f8cf1108,c9507b03,d0e889d8,d33ebfb7,3b10e670) -,S(43bfd366,10b67773,a254a077,624c2b53,4d8ded30,bf53e918,4f10e597,e2edd980,fd0655e2,e6b257ee,a249a5d4,299146d0,e08653cc,cef19a88,5ad6b33b,ae8f345c) -,S(7ad3c8d8,85cacf19,ed6aca96,4607f344,91448d7a,651fda8f,2446686e,bd06a9f3,9cb921c2,3e338436,73fa1bd,101dc4f8,a9a714ad,7fb91057,dd5af779,835000a0) -,S(874346d6,9cfbfc7a,2e13c605,baa69c5b,d39bd69,36841594,1cc50cd3,18c17380,35326549,dcc29eba,4d35a559,e8f2f0ba,b4d94ada,f2c18612,a45c9c90,8d99ef4f) -,S(1001f64a,23afdd92,789390a2,bfde9ae1,d85737ce,3e5087cb,b1bf2d5c,fd0e6943,184b6a2d,ebd086eb,6e04db54,2146059,e6ee341d,1c8854e6,e57345fd,5dd237dc) -,S(659607d2,68695906,fe752434,a229c309,60b33825,a41589d8,6e663230,c1610fe3,77005570,df191869,38a56d95,4643d991,486c70cd,3d5c336e,11a9667f,fd8f7862) -,S(eab041d9,67f89c37,c04bc6f5,a9059d69,a53e5fbf,ef7c17e1,7cef48d7,e346abbf,a2c2fe6e,63e38c06,477d2821,d22b4a0e,4edb0b55,cb1d9fdd,6cd01ebb,d8fa51c9) -,S(4ff2394f,377db94f,e96f51da,d7364407,ed6bc1d9,3822f24,91630c3c,abacda99,4a77b936,a42493f0,d739afce,b769c7ec,cc0d4720,93e839a4,330054db,22e93b31) -,S(7952c74d,e0576ddc,c85f42e6,24937e98,1502b2c0,105b69bd,4e35f59f,1c2847b2,e7159304,dbd9183f,3abde60d,5ad65ab,5a4972ba,19739b65,1d50c056,ebdd5b81) -,S(b3149a8e,f602b6a3,c69a769d,893d561d,c7438a74,bf47c2f8,ba07941d,b0dd214c,99e591f2,2f8da0b0,c9d7024b,c82d1031,cc4336e6,bf1436a6,bf03bc11,3f041979) -,S(ac3bf353,ce672165,a7e736dd,632c7018,1e454200,77471380,7b875d3e,c81ead58,78def098,2f0f5936,5f5c6519,1857463f,7376ec93,f15c01c6,980d352d,17a40195) -,S(9edcef9e,d26ac408,61d3fdc6,66e09068,a9b1e05,cc23202e,1d0b6e03,faf546de,b1387281,71de9aeb,b02b5290,d3d56d63,b6c98c00,cecf8b0b,540f70a3,79556f2b) -,S(fd48622e,8dc91972,7ac21c30,c0fb8d02,d8cfdead,dfc39a22,59853e17,5d8e6d26,4bf26514,204912d6,8bca0ce6,71a967d9,921bb882,33099b76,7a056967,3fd42bcf) -,S(e6dc2ea,c28def67,78b0a351,6ef0f4b,104fc7c9,88a03a46,8cfbf207,ca0ae0e8,d1892329,e77d5770,d9a84e59,c2d6f6e1,db6de419,87c5e3a0,ea508ea4,a11b3762) -,S(e8ff8f65,559128fb,3fc52650,ba063717,cd2d140e,ed3fc4a9,10dccaad,bb0503db,f35c361a,8ea9b3a8,139676c,3ff31cdf,5511535,7859e5f9,3590302d,bd21e21d) -,S(2e18c597,d4e4a4c7,d54bee9,215a1ee3,d149dce3,25cdc4af,f62a3da4,1922c2bd,3e8595ae,4b6cd57b,7f685a75,87ed61a3,281b52ff,d76e9126,4a0f0666,701c5354) -,S(589924a1,2cc867c5,b2289f81,2d93f324,c2df420e,3c948bbc,e74b6bb4,6d30f262,f9bf3d02,cd0001c0,bb9558ff,515ee86f,e39d4357,fd39cc3c,8ce73c75,72850466) -,S(ef55eae6,4a07199f,1a3f3463,5007a8c3,8d39db17,48af39cb,584d4471,d3d32e18,9d31abdf,91bfedda,3c1f02a,aceea672,21d347f3,5d355042,75452c91,5f4b19b5) -,S(7a8f75a9,41182eee,49883295,56588c86,3021548,70ecc05b,31b83a1d,74be05d0,bda4d0ac,ac72ccc0,c07270fd,1c2bba00,4cc9ce5a,fc927f,6d4bc0a9,b2fb4a64) -,S(330f8a4a,582dad9c,159e0f9,a47101b9,223fed7f,896679e4,f764b02b,3d1d9eeb,50695f30,f9dc9c75,6df20cd9,aca3a06d,7199c138,4b3ede52,2dfa0816,31fea2f7) -,S(6dd34c6f,b89722cd,182cd5b6,a0d83132,56814bc,7ff147ae,668618e0,30bceab1,8998216e,8ccfeee2,78e5c0dd,e206d3b,1fe058c3,990159f,be3beb2a,2a97cd60) -,S(66c2d4bc,1e1ee63e,75481e23,1e6df60b,82c73758,36d4c9e9,fa99a576,304ceb8,f6871e84,fcb56780,682bb226,a8d2f46b,89cf516a,7aa0de01,2ccd981a,b739244c) -,S(560ac5cb,b9a55c0c,8bd6a36e,9dc90922,9297a452,b83f8db0,e0899577,cdb8d04d,b6255568,4574e609,ab7dff47,938008da,5b11adaa,480becaf,287f2216,cf1c7891) -,S(a2377a79,e597dffe,224988b1,63ca63c6,67827b81,ccc645ea,cc23ddb2,2a1503e8,7663e301,4dcdbd71,620ff660,426581cb,7e723605,72b651a7,103faf36,480834bd) -,S(fac987,e1c77065,bb1eeec0,fdd92f05,5d10e738,befbb155,152bde06,87c7fadb,c6fd2faf,683f4e87,77a6166b,59c4b93,e7f5d803,fec49ef3,29e1a4ee,9981e803) -,S(81ee9f52,9b5c6b11,8fc6ec23,88f3ecac,4120f8ec,d134d22c,f809e2cb,1e88a490,e8bba906,3a3ba848,7bdf4a82,c5014493,40da0e2b,fda93fc2,b6440b50,d24536d8) -,S(e6439a0d,545c7431,cd8321ea,420dd3d1,9932427d,475df712,529bfd17,99dbc4aa,6c86e739,b6d0f23c,d3570bc1,86fd9e1f,e617fc41,8089f2a9,d42d0b91,2b4c8d39) -,S(e08169e0,f7362908,a0d207f,bf49a44f,5839c76e,7ad80a74,44e7d24b,573f0bfd,948ce18f,15ef6e2a,23f2db47,db402d38,2a4a3cc3,a8a3756a,c382cba4,f608283f) -,S(5687e6f5,7b2bacda,eafe58b5,94bc322e,70c7afe7,884ab4fa,4d46467a,7a8ba729,994d9091,e432b4f6,72e7f711,b5e0a7bc,b07fae10,b6e05ca0,5a088cc6,e4d89d80) -,S(6edfc830,82a178b0,d9160f4c,f0b01004,65c29bea,e3c29d31,e3826aad,9fa1979,5f4c6676,3df8ac3c,4490ec9,fcb0695b,e9c0532f,df526e83,f27ad47b,5bfff2d9) -,S(28128135,a17d0e29,4871831d,2542c2e6,80dcd79f,6b4fafc2,722b7db8,4ed449ef,4f7e515e,b5c7eb7e,415d7b02,83ff11c4,8f3f3ce,a724c476,71d02d1,50835702) -,S(f55371f4,2d617023,dd5542fa,db9a9127,c16ac04,1545db5a,a18cdbb0,cca4cacc,d0c795cc,54057d47,5bd080a1,acbe6881,3263f593,917e012c,dc1bdafb,920b3ec2) -,S(10fffd7d,a62de848,c07b50b9,64e3b31,ee6a13ed,996fe92d,565cc54,fd0b7c1b,92107e28,5319ce07,61e5f212,5724f2eb,fc61498,f838717c,6637c7af,8f0fee23) -,S(a6a73f68,bcb103c0,523c8f28,f14fafd7,5b8d399d,617a68d4,6ad0a1c8,6f12a46c,d18efb60,37f40a9f,6567c993,24f3a7a7,543fbc30,feec0252,87dc862e,b22fa279) -,S(2984cd0d,5c4f1c06,3854d233,6cdfdca6,50c94275,975feb2d,1b0b5bb1,c7dda582,41b0a86,8064dfd6,5c2653b0,27dfcc75,50eb755d,7c1f5c78,b0c13493,acbb4db0) -,S(a701d075,7be9ff89,67c67622,dfa8ff9f,82f7d5d7,814f6c29,c73045d0,c5b16589,ada61af5,62851c60,66501019,70953ba6,fca0d99f,42378b8a,5059ceb,2a0835f) -,S(f07463c9,c37479e8,259a32a,a2e8f283,27cc267b,95aec8c1,1242a092,bf4c47b,1ae9bb16,e538ff69,1e9ecc98,838e112a,a2016657,c7af104c,ee92471c,df6cc136) -,S(fdec5a71,21a17f37,b4c2e93f,56d910a1,788d2da,b3cce509,b3e2f3cc,f141043b,a62e32d9,336fcfd1,4bab6cf3,26ee3f31,4d2ad023,430768ae,8f093408,e3505d90) -,S(be32f9cf,9a13d4d2,652d122c,c0ce07b,da21fc85,52c0808c,23dd5a5a,9ffb3599,a4a73b26,2b5f8239,e8c279b,20f79c71,7ea47a64,1c084f52,f1bd4f3d,dbcf9c43) -,S(735a1f6e,2575ee01,9ebee00f,a4acbcc5,93bb6572,c4db9505,bf96a2f,43b66f38,20b1c7a,99c6cfcd,58b3f00a,3f9d7739,f9cb682d,946b33c8,879f041e,15e198f8) -,S(a0b840b0,6d92eb95,4f029204,1229b9f0,f1838bdb,4ead7432,4d8facd,70f7447c,383fa2d6,47d88c1b,fc9b04a8,a27b3a99,1a22b82f,7c99fce5,5cf30855,ed1c22f7) -,S(3e54abd4,36a9763e,52b7f46f,4955a339,6db284cc,77d0b351,fee7a568,e4774c83,1c64ede4,fb372325,dd435f71,e4dc914,391da9f1,ee08a21e,2eb5ec18,2834b0ab) -,S(24675c97,67f69242,4e1d43e3,1c46ecf,b418fe9b,3fcdb495,822362b,2a8adcb8,9e38e08a,4359dd9a,a9ddf4c0,8fd1147e,c70ccf1f,8855cdbd,49f44dcf,1edcc36d) -,S(16e0176,9f5a5c0d,f6db88e7,fc95419a,96f836f4,f8255a96,77ca2710,2330e317,30641d0b,fbf7a1de,24c72692,b7032355,6996bf3f,1b541dae,d6ccfe8a,f847646e) -,S(a2e30015,a53829d7,c95d5704,3d6dac44,bca932b7,d4115826,c602aae6,8e4ef847,33ecf0cf,e81236c4,e8fb76e9,645e4827,9bfa617,f6d2760f,dde2b110,77da6ce3) -,S(cd9bcbcf,b7338c75,3fe393d2,2e2e44f8,45a09b83,fe4ce29e,546f2a58,7d7422c5,7683e5e7,f990e09a,e15902e6,c57b8db9,e2b1d29e,8d3bf33a,f90291a4,616c794d) -,S(77a00bb9,6abb918d,774a2a4c,3828fa5d,c7d40bfe,aee10091,f5d92cae,cdfca277,f3febab5,3310a2dd,5dd7a5e1,33572b3a,83950172,be7e4cd6,fec7575d,10142e02) -,S(be2f342c,ca1f161,d15f98cb,ccac9f2c,806c6d1b,f34656b5,c671c730,bdae8efa,c9c7a70a,88ed250d,6a7c0307,d3dd907f,ca8b399d,4affce18,e988ce5c,e0efb5f8) -,S(538bc08,c3c775bd,33edee48,c96c6fbc,1435b0c,f00aa42c,6c15fc7c,5540dd6e,9d8b1293,14283325,8d676a92,d479ebb2,c5ca171d,a43fefae,74c7740c,7e956eb9) -,S(d5e26827,fc0d8283,ee020376,56e83ae1,3ee306db,92d0bba1,6b3fd99c,7af15578,b41d4816,b9643a41,c4f8c5f,4121cddd,d7eceeea,9f2156ff,676d6d2b,61b7d210) -,S(7d18f6e9,95f9077f,c371fcce,729835bf,aa903ef6,682404da,bff6949,4b7faac,1423bd83,89410b9,a2cd8c3d,3d13b495,d856b103,eeb96e64,8c258ecb,a77d581f) -,S(fcb3cd95,fb0b4940,bdf0bd4c,ff534d94,26489c72,953b19d0,cedce320,6e3eb556,46043aaa,3d1ce85a,3009911f,763f49bf,df3d7fa6,347f5573,4c6c36cf,97f15702) -,S(a0e8413e,f66527ff,12f6de1d,2ed4eca4,6617064c,afcc4e98,495f2694,34492800,ac640fc,e3d5d094,54ee6811,81f8bc5f,3fb1bac6,84c8c572,b24fe3a8,66234d13) -,S(fbf60da6,aecd3cd,9137b28c,f7bfe541,efe60e65,52470f80,e301884c,1e9cf33f,aab83f4c,9d9e5ed9,ee35be7d,33a02bec,ebca4f40,8f6fafaa,6f385a89,8f7d846b) -,S(771c8d7f,73bf2b9f,4f032e7c,daf17c39,c375ce1d,2e180758,fcffd82b,26fe206c,af22f29,ac2ec5a8,ecb69e2,aa954f49,63d4a58c,2d6769b2,5255e9ae,2689f756) -,S(a30bea5b,4a911ae8,de11a310,a9cd3616,54143337,30aa182e,ba75601,3d12ab80,aad0f1fb,a9a8d6a5,71301b1b,dd11f4bb,161c26e5,3d3d5143,ad2678f8,9960029a) -,S(55d93940,b0a76283,6aac5bb8,c04f490d,e7ad8da0,4cee090a,e1f381e8,5c13fd27,f1c58d73,b90819b,bab9933d,60f54370,7a625449,d637f01d,bfcd6b44,bb467937) -,S(f6b03260,ae0373f5,b2ebaf15,1a74369c,22535844,13ec4356,ea4a9a32,f2132f81,4fd750b3,7f377f97,7b62580b,6ee7176e,a720a434,8df7aa86,642cc6b3,963cfdaa) -,S(80f7aad4,3deccf41,cf4540db,97150bd4,f4665ef7,72bf6c4e,e551c566,d11d13c6,20a9b836,67cbb397,aadb1211,fbc9a78e,2e998354,6f263403,1d844e7,b95766aa) -,S(4f574d76,130e2eac,16bd6b64,85bdd2fc,88855c3c,68a232b0,29560509,463f0c90,33dabadd,62ec0192,9fc3ad15,587150e8,ead8518,327207c8,7ad2a7ec,c712d268) -,S(41b6872f,f47a0d4a,764ab086,764e1844,a8b4c775,cb2bb06f,643a7c13,5a633e6c,301d54fd,d55c9204,4d337b83,ff17dec3,3faf0bf7,ddf7b5c0,afc8934f,65d54e17) -,S(9f4c75f0,cb44460,ad14d416,76c8b60a,1ae979cb,1ff6a506,b5523cee,8acb1bbd,253d8a0e,985fdeba,1ced50c7,aa3724ae,79c75c6d,7c82315e,65f3b579,5fcf70ec) -,S(25db3430,667796c3,b5f3ec0a,cf4f11e4,73518ce9,aec19932,3f0c5adf,e32f4a87,cce88dd2,ec02e348,ba569fec,15a3c527,ba580e44,c32f25cb,fa6f99f2,a1eb4250) -,S(fa71cf1c,2312c228,c706a7a0,2dc3b9e2,f571b468,913b9cb,3fc5ed1a,faf730d,156df61d,752533f7,afee2781,30763eb9,45a6198b,a78a8288,f30e381b,a809eb61) -,S(f5d3adb5,6d77855d,8e0d0b71,300e620c,f96a45f1,5948d97b,affc3ad1,7226294b,95fea642,5be2e987,968f54f8,f3fb30f1,e9a1ba5f,57b68b1,101a5981,a47f9f4c) -,S(907eec9,6db952f0,eb7d0436,c47f5980,dcae53fa,ebabe57c,aaca00e0,10361460,1cefe286,19dfb7f1,969c7618,e0ed4775,e23527df,6a214754,4cd066a4,65f92468) -,S(abbcec4,36e06bc7,bb92dd79,bcc5d9d7,73189ef9,2546dfc4,54b5d624,2c96e8cc,d1546a38,1f335077,ef40473d,baac9c37,66aba23b,8040c4c0,60778d13,8603be7d) -,S(42f1594f,b1e088f7,2020b68f,7fdd9027,b9638619,b0320410,fc4bec4f,4fbdda76,9a417cab,515a08fc,9e7a7c64,7029a457,9881caeb,df8430bd,c1712af1,3c6b02ba) -,S(a4aace90,751aafa1,fe3e14b9,ead1d460,e1cf029d,cc82afb2,4d169248,e63f83f,97ec83af,dbf32c34,df9cafe7,de0b6ee0,67460d5a,607e1ea,fd13a96d,51999d54) -,S(ac7ef2c9,56b41a0d,824999ca,550ddce0,83f2aba4,8f2bce5,644a579,c0e248c4,d97b0ee7,f3a109bc,bd308b3,e4d4ce2e,c1a65878,e7e5939a,76c9d8f3,6959c5f1) -,S(e9cb9aa0,ab09aa1c,18daf08f,bbdd0457,25d4ac95,8607a88e,5bb14c1d,61d826bf,a1cc215a,124e31c2,e426e337,89736101,b739a56,b6d4e139,ce65272e,2e4b9a5b) -,S(885de0dc,e9700b34,9e10dc17,68f9fe12,2672ed3b,ff9d20cd,93b98e38,ebcc67a4,f66a36d3,75272f66,cad46fcc,cc5d3df6,8c023da0,1ebcf766,f4dfbb0,60e1eae) -,S(8ad4ade1,ff9a19a4,fdc89e75,e4cb61c9,1485ebce,b1e4c063,ccb8001a,c5038e6b,e02acfc2,19c22881,d38a8232,fae54d82,e0b1fb77,e6b8b741,890357c5,be261ff0) -,S(5b395388,a62979a2,b931f243,7f3f65ab,292ddad7,728e67c0,e753565e,578fa354,7e77c8a9,7c274030,b22e802f,f0fd69f4,da65e54a,b50953f8,b9945b79,20fb89f5) -,S(271982cf,eb593e95,17a8fa5,6f62fd23,ddb6c7b3,8e5a87e3,712793b6,f10a2d14,6661cb55,543414dc,e02b3650,8660d54f,48086cbe,4b517092,564188d,6815d2ad) -,S(458be91f,a61f477e,47d7b997,931c992,86281efd,21445349,af820000,58b2a93f,48725c06,e7dbe303,f0c73d43,a5a62b6e,131d004,2bae9dd9,ec12cf97,8df04c49) -,S(763f00b,348c1cb9,e922c6dd,a7e72e22,8624fae0,158af602,457fffc4,cb0bf3c1,8119c3e5,b190c6d8,7f3d7066,72136a3b,d0f1b198,d9f304b4,cfb383ec,e075de74) -,S(4fd5e9e2,77fdf260,8ece7268,10343542,312773f3,2518b363,7075fe98,dcf7719b,c234141c,d3e83309,539aa906,2b17ee35,99a3246d,86ad20d6,2885cfaf,5a88162f) -,S(c578afee,a7e492e6,30ca55ff,8923d9d0,9a6d0583,5553c61d,fe871b6d,e1d956b0,bc2d5e2f,add48f2a,50e357cd,4d4c120e,e744fd96,dca0a959,c0bf482e,2e081ce5) -,S(df02c64e,7a60b87f,73b4add8,5ad93b40,bb6a862c,18e0fba4,3f722650,c0439107,d86dc018,525efc69,cc7b282,cd145650,3b9bddae,607e14ef,3e380d53,c266fe29) -,S(9471f488,84cff3a9,2a99dcb9,4cad96f9,d4761570,c0bda860,bf1b0a9c,32a27a4f,23471d9f,6b3905a2,6d9481ec,dfa10a2e,7c7a5405,119dc8db,de839140,2e063e13) -,S(6d1b5784,f58e5393,fec90c50,a674278a,cb841f46,97da9eda,12013447,a2e0b863,d052c806,2905ef3f,6302892f,48b20497,e89cf7d4,3c345ba5,94233cf8,2586a17a) -,S(94eef4c8,be627560,17e13634,53f733a7,fd590dc1,294cefb6,4d8965fb,3d2ed1d7,49a1e5e4,d72e6a21,14e7c4d0,eb9c9240,b3b988d3,21d2999b,46a562e6,1a203c97) -,S(3206fc87,582d1267,92c2a68a,7400a29f,61097fdd,3ecf4cda,fe495993,87ec15f7,c9a7af2b,88df18f4,fe453bf,fc4af355,519fdf21,9251bf6f,879f291c,32a38eb2) -,S(fcd215,45f8a36a,a5a81bd7,1fb1804d,b3fa112c,c21542de,27cd34e7,f7309a1,191c6b9a,42b0adda,bacffaa9,89bbebea,3424a3bf,11345ff5,2af9c3fb,6193ad0) -,S(4432309a,40f6c71f,cb7fbe26,d6390778,fe6f816,3ee50264,2b2027c4,86fee04b,550981ec,b4d2f6df,fd25f26e,6d65f62e,5e549c1d,79639c4c,d07b6282,2d075847) -,S(7cbff748,7bed64ba,7d6346f9,18e23992,a3712ed,1b7cb89d,a6c0540a,335b582a,ddf155a2,bfb25607,ee6bca12,f6df2a01,98513445,9b353c60,9806fbbe,2d9fbdef) -,S(f8cd164b,ad3e65e3,63368645,76c49035,a95f7928,350c855c,fa534f6,80709789,25412c86,23bca2e9,8d5531ee,d57c80c3,ab01abfc,498cbef3,deeff0e,ae6912a) -,S(6fad2644,990a231f,c27bd678,36ff84c0,11fdec01,120dcc0d,f114b032,1d60648d,6beaeb65,ddd28481,a23af85a,5a417323,350d057e,1a574b0f,5d994816,844d9d98) -,S(1fbf086e,d0adb5d1,9c49947f,d019046b,289c5703,1cf876d0,8cba81e3,7739dd6,86e3511,3d4593f7,a8142c45,8e915fcd,685efd0b,f8cca8a0,79ebded3,f4453acc) -,S(30cc2cab,fd0a2244,2c8a6e00,5b6220e5,4061dbb1,4f8ceabb,6215bce,f5f5b312,b5a1f70d,4a05fff9,9716ac44,57a4342e,7d4bdef2,6cd07fee,b515c56b,19fe72b2) -,S(156efdd1,901ebad9,70eb167a,bb99ac5c,676a0929,3feb0b37,8ba19ba3,6c2a3935,b1d39453,32f0e107,15d06df2,d784b1c3,bac221a7,f184bfe2,4824a368,9ff33051) -,S(48682e29,6b8e8123,c9fb6246,5e8480d5,54350734,bc763757,f319d40c,87f2ddfe,efa5e5e2,be832508,e71b15f5,3a7f1d77,773129e2,e57b2b86,9545cfc9,a20360f8) -,S(d188747c,968b67b1,88958f37,b9990bb3,1a54e3d3,e3fe9e06,7aa9b1a0,87f5e3d4,6d60a049,25660c21,81efbbd5,6a436409,6bbdfa39,b37f70e6,4d13f3ca,6bc76b92) -,S(d7cfeac2,7fdb5922,a5f534c2,b1d325a2,903217f2,ff41b6ea,1e5d2264,8095d3,19618c66,87bb0d92,52133c84,26fb8aa6,4fe1355c,86aaea97,b9ef49fb,de063e75) -,S(dd795951,27b0ff86,94dd131c,e85ca6ef,9aa2022d,d0c7f053,4c83735c,43096c02,caeb4cdc,2633b01f,1b51f7e6,103ede8c,a0ccef5d,e33a8ece,5ddfba8f,736e2adc) -,S(5b2bf207,9a319707,52496851,68aad1e9,5582408,7e5d361e,87b77900,d9c63939,728df41e,69c939fb,59803668,6c44d0b6,f102dc4d,ee146a33,42e1c04c,9b6e30cc) -,S(d2a26a5c,313aef0d,6ac190cb,11c84771,abf97d8e,c7e6e67,bd3313fd,15c2ba11,84a1fb57,1507d012,9d98ebf5,34fac803,5de7a43e,48868269,d5e9656a,773fe768) -,S(22c22c99,860b2b6c,630487f2,5263e77,91b62450,290e9df,379efa7,1edadb52,d2b227b3,dc85c1a1,ed64a7e5,6dd6b178,ce0ab5e,68647b50,1178ac78,4b7d1c93) -,S(b811b039,d2cf5f3b,95e38e2e,14da67bc,417cfd8,623593ee,1f2e924f,d9a064c4,a860653d,ca39030e,8c1ed7bf,aeab73f2,a68cb8a0,5263aaf2,431b6f8d,9c862a28) -,S(59ee23c9,26b38d6d,d6c091a1,d4adcdca,b3a5a548,a5cdaf92,fee9fe2b,c3cc2957,67462318,96e4f107,67e39d47,b03268af,5b54edb0,9f9e8e0c,3f3f89a3,e9d204cb) -,S(cc79ede7,ca5a9ba5,a7c5114,d2039d5e,c6a54db8,fee6c102,577a20d9,18ba857a,2cdc980,3a06af30,c19b262a,12f54132,933ec985,afbd1598,45c40be3,2e24861a) -,S(1319c7a6,2f3959b4,cfee1223,b225c6e9,9070753,a1ad33d8,8f3a8b78,a886f7da,d8a75f9d,b8266ea4,2b650265,6b6c0ee9,7f3598d6,3d149ad6,9a5829e2,f3c29085) -,S(e4ae90fd,74e9b229,b9100cef,1da59b80,753b4f0a,cd7790f6,34930a92,b1eea356,370f1c98,f72e698,73c8d0a4,e76fb117,d7e5a9a4,d13521f,f4902a1b,ed3688e5) -,S(286a98b7,b0b0527c,310afd37,717b5061,467be24f,8a0b5528,52ff26ee,d658988b,d10699be,f79e800a,519b964a,163cffb9,722c3ba5,b56694a5,c1a9b883,b32965d8) -,S(9b8544b3,79746ba1,8524e084,2d15b853,46577b81,7084e02f,7d0cb820,7448f5d6,8421c0f2,ba15f648,246f9cb7,3b10d6db,1de7aefb,fafd9b52,16234dab,8e70218e) -,S(81efaf7b,50a18c8c,2481299,bbd2adba,f3510ac4,f871c3c0,f849ef6d,4550681a,ea8567a2,9c871ba7,fccea923,fe07e8ba,2071d7db,25d33ce7,a6125c0c,2afacd17) -,S(6680fbdb,dab850c9,115d5765,344f1466,b88cc5dc,8de9fab,549f281e,974ed7b,c7871b4b,2690f4ad,1e67ea81,e2cefac2,988082d8,b1c70e67,4389c79a,bc880368) -,S(4c38ce7b,a8e3d317,6f615d6e,27578edc,746fb80e,4701efae,f7557469,a1dce4bc,f6e73d73,61ff5407,10dc9f1a,4bd5c1eb,a7d8c8d6,45f0427e,a4fc3e45,3990b88c) -,S(767146d6,bc1d5bb9,c73321b5,4cf6bc61,e8209703,fe4dddf7,2b3d6089,da60be69,86df7dc3,6894f88e,fe24a4ee,fc78b1e0,fbb5138d,31666be7,97b8934f,d0b9a37) -,S(bffd4856,360c02ac,ee741a65,486d5a7,44e2a005,9db5ef5f,f87b9e18,3adbed20,c11246aa,3bd4ec3f,71f88d2,cb3b96ba,2c210f90,d8234c21,99bf7781,f96ad781) -,S(ad19b5f7,45556650,eb496450,968d056a,fbcb55b6,8852f510,ac96df54,cdc677c0,f78295f8,59445c52,d6ea285,3fe9baa0,5e453bf0,9b3f4d28,6c99e858,62a04bbe) -,S(5924f679,bb94f6db,d8232b01,ca8dfbcb,37a83d24,d0e7026f,b526162d,c82aaac7,baee6567,6a526460,ec7563ad,42482d37,a42f2fcb,f4a5eb7,b37b515,a6c3f1b9) -,S(dee240ea,c90d5399,89d3b3f5,764e0680,1e601a4d,f2c09226,21eb0b7f,bb53ccc6,12668b,72cc139f,5f9fff4c,ef24b5ec,d0648e03,64c17417,f35bfca8,b819316a) -,S(e288a00b,e18b0987,9765940e,caf8972b,1a09f67b,fdc455c8,8e3b4ed9,dc0dad81,fd81e0a5,adf1df8f,42c64825,6b107d44,887d01da,f4cf89c9,11529124,16a1e4e0) -,S(e747d6c7,3f5366ed,241501a0,ca6dc04a,aca7241d,8effbd94,7d3e6a0d,bb6eadb,9954822b,15f44840,9c9e73d,97722194,1eb6a218,ef1ef4f,269ab118,8f9c773c) -,S(57b8865b,ac78b9a1,c244452e,8057be3b,4fe2c6de,9ca9a295,ded04377,2b61aefa,d0e46172,8828f0d3,f1fa808b,1dea8516,b0c30d93,4acc8c90,6ca2bcad,303f06b7) -,S(abda4b38,47ed5cee,7ace4e8e,e652336f,26a8f4bf,4bd610f6,e87e5936,e4e8339b,8860963b,8f266c30,9c6a00c6,cdb44048,a9a1b76,d0a5a652,b4453f7d,330bdd9f) -,S(7f05f2d9,5621d06a,d344bf91,7fa8b9c4,2ceafa3d,fabd0620,bf7086fd,9539e089,298ec6d,8d5a9506,8d916678,dc8e62b3,7b6fb9ef,7967da8a,8419433f,79922f29) -,S(99e4f06b,b8845bb2,12638573,63f7cfbf,3f15570,44256dab,21b5a8fb,c43e2453,5d76066a,86d5c498,323af928,2c3bf419,acb758c9,7883d236,7d9d9e3f,eb8e1417) -,S(ff994b1f,6447ae81,8bbbf97b,8b6d655d,900b04ad,eec06fc1,f57eab70,95375094,6a63980d,3a9324a1,9339a073,977130de,d0fddc50,5b86ff73,464dae04,c3004a68) -,S(3e9af52,f00d1993,8b6205dc,7b6f8ef3,31d624da,fdb2f09d,fd701b78,ed8b0471,a674914c,ac86037b,f0585de4,d867424a,ab9841dc,83c0ca8f,347e16dc,1407167f) -,S(eece935a,e5cd4afe,baca6998,63c5e8c2,e0b338a3,e2ae7dbf,e34102f6,f1c613f8,be70c210,b925dc66,c8546e65,ae9600b4,21a9f668,c3a09a01,8bc5b88b,91cf4d74) -,S(bf10e625,7d336eb4,a962bd97,4cbd9f10,76787b8b,90575250,7f0cfc2e,121d1276,1d93f629,8ddbce2f,1f670326,265c4ba0,f7f5256b,472412f7,a24f999e,f4e1c64c) -,S(73e43284,c80d4ea5,c992ffe3,cdce4149,d490843e,bbac444b,f47ed5a7,3d6e0bb4,82cab83b,c7d2d2bc,87881618,54034d7b,dab132b0,6340b316,964854b7,f2ee3e6b) -,S(5410340,b614b676,63173725,ecf0b8e1,67c2de61,ce999639,be2051dd,2695f8b8,f191ec95,9d6fd8f4,eca243b7,8d844214,976d97e0,65218487,3366ca25,f2e6a091) -,S(203d28e2,694df7a5,6c9b9d42,907c1e02,192e8030,77ead781,8198b2a9,69b127fe,c06fb7ff,2361ac16,a884f0a7,9e4f5a19,b0b5b207,9901e634,be237643,ba93852c) -,S(f9a1e3dd,f53e41b8,84f7c4e2,c2b47131,8d14705a,4e7362df,3221222e,6b2c1921,cd150a1a,abe8ea0d,853245eb,509c1d4f,e26c54b6,98cf9aad,26849a7d,e63b6264) -,S(e82e5e89,db35aedd,4d63b7e,4d55d637,cd2eafcf,f16ffbd5,b0fd1444,c7c783bb,6701a95d,ccae2272,2a834957,e0a4a3b8,3cf5ff19,2f41e8,1619dc46,b8238cda) -,S(9fb768b7,16032fd7,f21315b7,79776882,767d5d64,c9141267,a0ddedb1,55d4ae08,13474a8f,90fda6a3,43e3ea23,e858327,dc2f4c40,4a445f77,4b39b92d,a312574a) -,S(d0793463,ca7cdb50,3622f1cf,90032794,52af3fa8,1866e536,159fd23e,ba6082d7,35301f6b,66858d6a,3e97480b,ec3d2a53,8dee8465,ff5c15a9,1144ede,a208bd0c) -,S(cf8fc191,273383df,f1d703f7,bb237ea6,cb5d1307,8ce8ae62,67fd20da,4d845e05,efce641,3bb676e5,5c0b64d7,589ad771,23900e0d,60feb71f,93270390,ec66ecc1) -,S(f12aeec7,55a7138e,4e91024a,3006db3d,eff6ec84,ffa73d96,da21ef00,452064fd,f0f0660a,22cd7cda,25206f10,e82ca005,3a40d539,472cf41c,b86ed8ae,3d29abd9) -,S(3c40f94d,ab460ccf,c8e47a1e,d015b074,ebfb6142,fbbf5b4d,e77aca70,be67c57a,998efa4e,26df60a6,f1a466f4,c27b2dce,ce6367b2,e05a5ad9,dd71ed8b,482ce55c) -,S(f2fc6db0,49861d3c,a01a6778,22299264,88184967,3802ed49,503857d2,2860f00c,79f0f245,1cc6c5b8,d36c330a,ef8c9c84,95619911,1d4a01a3,d9363382,8b609576) -,S(35d3e3c0,29fdc9e3,88da1cf3,d52df6bd,9ac0ec9e,e591adde,26d3e414,f4fb92f5,62ba2346,6d19ec1b,64d2a6cc,9822feb8,e03df178,3f526a9a,13d10fa7,72de3219) -,S(5628da0b,cc2c0583,902a56ae,711a2217,455bba47,c7222dfe,d60580c6,461b4ae3,1cee8f17,8ce4c7f9,8cf2a2c5,92bf39aa,57616913,bb66f232,a813904e,7b574ed9) -,S(7ec54044,c3fe53ac,8437a540,968e0b,b725e794,a8c240c6,5dac1f12,4ce21be3,f6290891,af9af62d,5dfe10b,d567af1d,6b4b22f2,8177a14b,44edcd0a,be811c0d) -,S(eef7a7c2,a0224a78,aff7c61b,d2379259,7b307a20,bf1c253d,6f03d57f,a8a84203,5c7d6875,905e26dd,2fa4e5,24f73b00,6f4bd0b6,786639af,5d222411,bf69daf0) -,S(3f1e6459,38e4285d,ed30be98,1d149f68,24b264c7,df920f0c,c5d776df,83228cc3,a6a5df53,856be619,25e42d58,2f705567,39c3d7c7,a6e222b8,6385b63e,d1316916) -,S(c83ff186,ae3f42d5,a2c39b43,7712d607,92b9006a,d8bbcc89,97bb9b35,d1663cc6,2380aa52,44674eae,3d96d65,f484e7a7,62cbfa10,96c5a313,9eb4628e,77b72d40) -,S(41d20761,160125ae,c669b1cd,395110bc,94e09a,ffb52ef4,e7e86e,1f4a61a5,c8509f71,2c20aeef,7399d11e,7c438d0e,9b4dec72,76c1013e,a4c76d31,ee5c7496) -,S(cd358f38,d2cb11f2,9fb54431,dc5adee6,721c444a,8fab5743,1149e504,8ba0dab8,e6ab91a8,79a51f40,cf75e405,e508cad8,ec54dbd8,2dd4115c,fda7b255,b1a6fe1b) -,S(d1e1851d,cc95a94c,a8c77b42,5b4430a1,ac10e526,e3f4c6dc,f20267dd,7c5f2d2f,889de789,43c6674e,6bf28470,3ef8867c,8d827681,d2df8bd7,75384ad7,15730ecb) -,S(89268637,1febc520,14709cc6,b2aeb5dc,32e06b14,cdae3d76,b1bc04e7,b9b5dc8e,46823e42,9c0815e,ff99cd7d,f3712f78,9c102af,173b61f,8de08519,f19a3783) -,S(c7341942,420d4e63,263a144c,8a10d22a,fecb1bef,64f926a7,83951e0f,6490caee,925019a5,212e9de7,2e6e2336,c3e2aa75,9511396c,a171412b,53c8f9ff,3743dcd2) -,S(fdede5f,38d83f9f,a4ba3218,fac6f0aa,7c9f464e,33dc59f9,8a3444e,fc0ed7e7,26e4cd3f,3dcd6a6a,211bc8d0,65564250,49c6db2e,9946dcaf,43cb42f3,b0f20449) -,S(b2b5364a,eaedfe4c,f046193a,6777ec1a,1841436e,3cb17c34,9d27f42e,8e536618,32b886d0,f0f94a7f,1b1d87e7,4f2c7dcb,ba4a5dde,8e93c864,f8f48bb4,50d08ffa) -,S(4c3693f4,52a95b79,85e39982,f316897,93d289cf,66b3326f,3e1cc77e,457f64bc,48d7bdfe,fb8c3abb,584db0b,d3407ed3,3e543715,d4ede995,df0e1b8,52e12123) -,S(5cea23d4,927f0385,57f6bc1f,b926e594,93250b3d,6d934a16,9265ae08,24a35e60,5806886e,b01ca724,8434f2f8,be33287b,d9cb3c3e,b927bc4b,4fefbd51,ba98b5b6) -,S(db0a50f6,b4558c10,61a3ff88,1da60f9a,77b42469,a9713c8f,8339b8a7,b903d93,7afa6cd2,57685f49,9635d15c,bb7defac,d6f94c17,aa19be02,4e2efc70,d84c45be) -,S(b0029adb,25f32b75,8023ced1,632de91b,3e3e55a6,1abb56d5,aada032,f2c01ab5,baadabe2,2ebc5fc6,d5dee65b,262e96c,63c99fc9,13277d84,9ec8a730,e1bbfe91) -,S(c336b077,3ce16975,bc204169,8126a40e,f8cad886,6a52c50,c5081ba7,b878af5,6f46f5e7,b82aec01,ad499340,fb90b81,420b4a3f,977579af,d3eb0ce9,c7d752bb) -,S(f403fde4,7232a9db,9efda1c0,5df49636,2137f5c,aacdfc93,1346dacb,d2501451,ba30815c,197de8f2,258c83d8,dd7ed0cc,cbb5388a,415b8629,2cf5c271,2e75bcbf) -,S(85cd71a2,20beec1,3edd0133,6b0b85e2,da056a1c,4a48a328,f371af1a,ee502c30,d6accbba,491c915e,88474b92,bf23c740,2648085f,88a62d51,b26954b3,f6d2d4c6) -,S(324d65,b3c2bc55,d3b2a125,1b673ecc,d26d2b23,e333849b,7549339f,7f0d9a42,83750e95,32086164,e9aaec58,b6a2f00a,3838d76a,208d6453,14042334,b4af616a) -,S(322033a5,c90d7a31,9439c368,b1301f1b,d088974c,91560063,793b6f2,63b401f3,a61f4714,488bd2bc,84bdb122,c615ac94,a7d05157,e6d961df,4f873f5a,582e4606) -,S(a414ed01,691f2a43,b18dbda2,2d3d009f,f94f8b02,672e49f0,58dc2323,b71f5836,2fa3e483,a12ba874,12d709a9,47cdf22,6b96523a,ac7f4afe,c93f98be,f97ec01f) -,S(774310b1,7752d7bc,d8b3059,f7f4cac9,e661a841,9dcb20fe,355bc7be,3a4c65e9,b3333227,469ec87f,19e14e3c,98148b4b,45bde0f6,698829e9,3bbc9313,56e18b12) -,S(fbb23c7b,5c15bbcc,7ad0118b,6826e385,3f6c4078,5342ea57,11109f8a,27dd11e,b12ec70c,9b4c908e,2538f4c6,b0b3d548,ee199f9a,1e9b6535,f1c78081,41664ad5) -,S(4bf836d7,fa7308c,89b075df,1f336fc8,af3c6ce0,64e1253f,853f623d,c483b400,8b368da,424e5a83,48cfe987,93d47a1e,1e9bbeb7,3f5282af,82e12e4a,c7eac850) -,S(91b4a84a,e521232d,71e3d202,49dd1b3b,d134509f,e3e1ed1a,4e8b5062,a438bdd2,52d30545,4972471e,6900afbe,2471e1c9,16c82ce2,2f955ab8,454f9b65,b70ed759) -,S(9751092f,62147caf,f3953cf4,8a117082,37a78b6,5bf0de56,848da1e9,4c3c3a42,57fd0a15,fe069db5,5fbe870c,96d4280,7b9ebd87,33908bd7,49ba0121,a900b08e) -,S(54439284,6f6d46c9,8ac10a58,ac3c34b7,3cc5569f,8f9fd7f3,4e7ad2be,826bf293,1aff0b85,e5b9033d,7c44e877,57513317,a17734d1,13043cd0,780da032,2dc3ed03) -,S(172704b7,fd7f5560,f17cb6ff,ff9a0144,9a05a113,29b86df0,a8d3256,ce139a9f,a416c0af,b170cdfe,169f894a,b10aa97f,2c068a4f,d70a6878,ec9f359f,e8323bea) -,S(2236799a,a82d4b64,5f412aef,eae944b5,e28e0996,8a243ce5,b8986861,6f735dfb,7f20b2cd,af70cbdc,6aeec02a,dae1535d,4bd919c2,631ed69b,9913771c,2f482c1) -,S(6a52af7f,c6f75636,c33047b8,9f0eec31,66bd97d,8df6579d,2e2a441,6ec4fe8b,4eb0813d,220849bc,e0b948e9,a6efcafd,339f8861,eacb9885,40ff8e1,acf1efdb) -,S(8696e0b4,ae3f0dea,bf6d8dd3,854faa5d,d07b01a8,86f710ad,9b4cd84a,5d61a617,67633be1,a662024f,77931f06,38884175,d2c234cd,c4709637,4711c79f,42a897df) -,S(6c4b727e,3bf9af50,fcae1ed6,163ecb00,142d9a53,b6d3f54c,8aa14064,1358ce7e,c4f2665f,395af262,b30561d1,48bb0f4a,f5603102,80f57f40,1506ec37,2bde79a3) -,S(a51d2296,98aa29a9,6d0e5510,f3e815f9,cfc6d492,dd0b2fd5,bbfdefa4,984a6934,861f0848,7658d4a0,141e9d38,aa0e268f,40bad7c9,e2615a37,7a4b974a,6828d525) -,S(1afc4051,cfb5635f,9c2a8477,7dee5fd9,fc4d40a8,3ebe2f89,f36c0b9d,8327288,61ac4eb9,16567e13,d1b03ae7,ad5c3d8d,ef85bf6f,387c511e,bba6c237,96e95f7a) -,S(f8fcde05,5a2a92de,c65d1842,6607a939,b3475abe,2437c5d3,88387fd4,afdff590,4cb8f7e2,825625ba,e3f179bd,4ef94560,6e186346,61edbf48,8ce51ea8,ce1b0404) -,S(cb3dad82,7e7464cb,5fed0cbf,7e29e6ec,112ea411,706d10e5,c1fe6fbc,a04a3e9,a33abaa7,6c9afe3a,a8ce5add,7a2a056,b396cdda,2a002161,3de97556,a0364629) -,S(39d2cea0,acf8059b,a6275a08,ec3a3664,f09cfc43,f143c317,bed8d751,33d4ba0d,6beb4ca3,d3009ac8,881d6d15,e0a29eda,6738befe,e31707d7,f95eacc5,fbd77192) -,S(90bfc4da,3be2d74b,ff9b5539,d0787bf4,4a1b6d7c,2baa14a1,dc6801d4,42187f96,1254e7ee,c8acb35c,fa0695c5,85f61b69,def3ef5a,6219fa97,e3b09dbb,351152f) -,S(50772bcd,454ae992,f97ac3f8,9d8193d5,ed50b69a,b2e62e04,d6a115a6,6e71c977,f199a8f6,f78b0b97,cc20316f,66177383,64338fda,3eee7f0,f36eb0ff,64accdcc) -,S(afe51284,f033bb43,ac6feaea,9520e83e,f2cc1e42,9e273bc3,1b087161,52ea6926,77ecc481,9ffe6efd,33592907,17d22ceb,f4344c9d,f5f5ea4e,4d443d17,25c8aa1e) -,S(b0caf67c,151b838e,4ecaee09,c7908c95,bd3ef86c,797a5a8d,71cb3bf0,3a46ab17,10ae756,7bd2f6d6,712c448b,34636eea,2c7c3d99,98901308,14825b4e,423284bb) -,S(f2766b4,8cac8f6a,80a7cf39,81725834,d186e88d,735fc7f1,5135ce58,43b3dc8c,63590fcc,a4e21c39,50cd78a0,569c0d2e,959254e1,4bf2ff22,8d8fb216,b53601bb) -,S(80d50e7d,28269280,f8ce0dd3,6afb9f43,38df0403,d5661c99,27ff817a,46f60a0e,22fec5b9,7472824a,9b2ff25a,68d947a5,a8952ae,b763f37f,70228978,514cd22) -,S(18114ad0,7097b5f3,7d788165,e45ca1b8,462da0b5,78e5d37b,e4be3632,35d2fff6,87c5f261,39cb366f,25fb6bfa,fcc8408b,f4c69c81,29df3cfe,9190213f,8c15a66f) -,S(3bd52737,68294cd8,73a48831,8f958e45,85871165,c82cf6a3,9126e378,43975444,8c92d391,e39a50f3,4388510f,c8dbb686,27f29251,92ae8edb,b2613948,c01281ac) -,S(acf47eeb,526208ba,8a3de26e,481a86ac,f17f5f88,81d89d43,ab8a5a26,e00db5a5,b451b4cc,8be8339e,4203c913,98b9a29e,de86a91d,3e347688,53442446,429ace0a) -,S(5e39f375,87a07536,86bcd792,1183c424,20159044,a9f66ecc,2bdd552c,62ec35c2,b7131328,297c6995,7df6783b,d9bc550d,5c553e1,30bfc3e,fffedbd7,5e2d003b) -,S(315b67c3,d980796f,6f0a5505,ff2d25f2,8551615d,12bd73de,b10c4897,580371ba,dfaf812f,7525e087,2d11e10d,612004cb,3e2a7024,8c40416e,5020ef66,82d3bc1f) -,S(8f6764f7,73810396,62537cc5,aed6a8e0,318654cd,a95d8695,89fa471a,edd0d7a0,b91cf5db,2994d207,135c1dbf,b9d9d78f,7e3adea5,8c176630,c09140b7,f5c67e84) -,S(e844b948,118fc6a7,eb2f96e,ece3cab6,def55940,75c7b7af,fcc5603,f2012f96,707668d8,89db03d1,561596da,a831aa92,771a0fb9,e1b21273,d11a3415,82292314) -,S(fbbedfd8,4144785e,fa71e234,59973cb8,87deda88,971eb62a,3007f350,1fd0ae4e,51d23941,cf84f121,ff1e6a5d,651d9528,6ef1d803,819ce64,3aba8d16,67ba7dd9) -,S(a0190399,c692b9a,db172ba8,348b404f,19442b60,4df60142,f6330f36,ca6bf352,6ce7491a,b5329042,25556069,71502da1,601e3a04,f38601d0,80b31654,20fb527f) -,S(d240e135,4b9e6dc9,110a6b25,afcf35e0,74fb02fa,f3dbe484,4f46818a,89bca65a,d704be81,e2597460,6014ffcc,ef12563b,45faf24,3e070727,64f341b8,7dfcdb7d) -,S(39bd84aa,f8a15b0b,809888f,133871f3,c40ea5f,2825582,a35fa9a7,808e5e87,94ad6588,658752fc,ce45ea1b,752ecd02,2b621c5a,26908cf8,69c44584,1d831d33) -,S(2172be6e,dccfd021,a56a553e,53f814c7,c7cdd55f,d181d671,4ade45e7,72093142,b21439df,f7229e61,cd3b7c77,fa750a94,660f60a7,53da96ba,d8ca7e20,69abf76d) -,S(57db209d,a40f30ae,fcca7838,2ba525e2,231343b9,250a1b1f,67fad7f4,d4079594,34ce9bac,bd35557e,2f73c718,4287b493,c524a3a,d6b403f4,ae777026,42fd37e3) -,S(845c2bc3,3683d899,8b90a2d5,ff299064,5214b272,a056ed93,63621406,d3a4cc11,44a46738,839b2e3e,1b6b19bc,56a1ff06,7754126b,20654e51,3a1f13c6,de4c6535) -,S(705af30b,251cc64a,26edc929,e3e9ff3e,32ada2e,69c2cfd0,eefce4cb,a37329d1,c0e693eb,94c0c1f6,cf1a0ed4,8c9b13ae,faba8ebd,926c4fe3,ec9071be,2db463dc) -,S(9b2a64df,9b1f8e,34844e3d,920b1af3,14df1b7,78b863d6,f1a6b94a,869061be,5ff03134,722faad1,ab6f87f0,bc3c6abe,8406bdf3,6506b662,6d066ce1,fa6a7cf7) -,S(494967f0,1a0c07df,e7d9a8b3,e6a4ad13,893a894c,2619238,7384e38a,d514cff3,11ba0803,72bc4ffe,b86e25c8,b69ea450,5f6e3b24,504b5e38,210beff8,5d82e1af) -,S(fd547247,812e4233,55c4a977,4dfecfae,812ef2f8,f3fd832d,a3af2ac9,257d50a4,65ed23c4,d776baf4,53faf3d,d3edf65a,5d9935ef,9e22fef2,53319e22,ca4bf51) -,S(4aa16ea2,68ae95b3,2f405fd9,6fa78478,7c369015,4c124733,a07c1953,874b6246,4306725f,579fc013,2cb8c640,7361c7c4,685a2a49,532fa14a,36010779,7f5104e7) -,S(de6fdd33,8b6eaad1,bec84d55,992a5b74,aaca294a,5f804015,796d69c2,cfe67add,e58564e9,d2cc10e7,184d65b1,7e0271a7,f2e59073,bdca05f,ae664f82,7e6fba13) -,S(c8290adf,d0da5f1d,1805f36f,288a8709,eae0b93b,1a7490da,5ffc29fa,bf834592,ff161787,f096e022,f513afc4,e0b84d73,e7f9f347,798e1026,931271b0,8f1c8a87) -,S(1b95c512,815603a6,19750d6e,463d5a33,55f09c22,56484ae9,8f1c76c1,10ed8fec,93b3750c,3a1272d8,bc9e4c52,b5efb6bc,d794c2c3,939bbea6,1848c9ed,423bb39b) -,S(ac0d9939,104bbaf4,d2eb2560,356f2bd4,f1037ee8,397f0703,b7ebfb49,463a22e3,c6e6d039,d6acc470,c1ee1013,722c4a00,4c59e472,11da3025,49351216,f0bb8985) -,S(d8c8f5b6,366c1d29,b2f28f53,8645b17c,f001ae59,71a19f05,fb6ebb3e,9e36faec,5db24ba,6d78e76b,42262b65,e631390c,8540b72a,746cc5b,edc1b681,8b1a113b) -,S(d42ccf6e,6d1c663a,3dd95fd3,c016d535,c50e394,fd63b353,2949716c,49315737,e7337f22,2d353eda,651087c5,13cfea43,96e9cc5e,22aefb4a,5fb3ea8b,579c7298) -,S(53417fa2,4871adb7,6d875c05,8c46065,681f6372,95d221db,ea76d88d,f687b817,d014e6ea,e00c4ec8,ad931dd2,5cf569d2,efb3068f,7aaf5ded,d4978546,1bb31d76) -,S(202e9476,53b677a8,d7aca305,c52af8b9,d33b1ec4,c5ec94fc,5f7775aa,c478f150,539a24fb,211da532,b378f3e5,cdd688b5,c57343c8,2e03a637,39544c8b,34e3087f) -,S(434f1027,72aa0555,8bcb2f6b,1f64bc8d,72bf1bb2,8b972c3a,f6f342d5,f1493f93,a9db9031,f2d1b8b0,e5840fc2,b4534970,90aee2af,5bbd83d2,c14a5ad8,acbf8c14) -,S(a0e54d1a,f09c47f7,cf56d3a5,725d6777,9fdf920d,3c1dd566,caf71666,de7d5d17,87f5db7f,197185b4,73cfc293,7b0661ce,1ea92099,fbb51151,63c2b26d,47ba97f0) -,S(2d43cada,5455b682,f6430cbd,96a2e316,ac0b4b27,e9fb8777,a94dd2c5,81c0e350,bcf18180,1c1722db,1bd9b8f1,8a1989c0,fb372acf,fecbf9f2,c37ec4b3,b459c916) -,S(e5e6dd12,6340f04,431552e9,903ff4a3,c309ea1e,c498e483,e19b9cc1,37418d4d,58d35fe2,24ab47d,93cd53,fba32252,4a3ea9b6,d96390df,25935a1b,dd12126e) -,S(b112e4d3,ff9adc6f,706cac35,195843cf,302324e5,6aa7305,9c8b5f3a,6dd7dbc7,4fe76714,6529e6f6,b0379366,334595be,efcc7cde,d3596ed8,83e3b30e,780dbccc) -,S(d26b5261,ca7be739,95de1bd4,d75991ef,4d357fa2,5c8d513a,e209ac6f,64ad960,5f3b8e07,74e78bb7,5c395bcc,8512f2c0,1b6c451b,5c8d6ff4,18f9ef35,30c6d046) -,S(e2e4f568,eaf2807e,cf43ce08,3146e961,92271bb8,d6d9b24c,e7315b00,1cf04fbd,56894a02,58093a34,22f2ad5e,548158fa,c55ce47e,d00ede05,40434424,4e204b93) -,S(a62080a4,2d8aa307,32255b2b,a239d9fc,19729eec,1dc24bca,67652705,9b1182cb,ae848a12,893c34f2,260c33c8,ce2bcb7,14fb1438,8e6f3f06,d9192549,6a9ec13e) -,S(684c1647,7771de55,ddea8aec,290c1e25,65120fcb,fc8ce0db,4316dde3,f5ae8d91,ba85dda9,44dcfdf8,cfca86dc,ba902675,3d99e751,5719e579,64e0fa0c,3be1f06) -,S(3d730e7a,afa97950,bee35934,da18648c,d0bd62e6,9a49281c,b63589d0,5efbd2fd,c28545f2,3dceca1a,ad0a9c77,23b61519,44a3c984,d57517a7,cf6702ce,f4dbb630) -,S(337c9584,b49a49d9,29b1212d,dee7ecb6,39f007b8,9ba94180,80c9548,459c48b7,b26db317,3e996893,fe1e0797,f75cd05a,2eb23ddf,4806407e,1f173d29,48bb0bde) -,S(7013edd6,f49ba92f,9c9757d1,d3374229,706078df,c2e9c64c,c2e84cbe,85c6b5b7,e850419,7975353b,2863b577,d6f0c392,a8c5bdb4,2dd557e9,8e971114,5e078de4) -,S(9877cf36,bde592fb,5f4a4581,2bc3c39c,68ac9956,23b3487a,635d6e45,89e26e1c,6207d384,737a0d80,fa9f42e0,57684584,efe1fa4,5cd73eb7,bd50abc3,2722f159) -,S(6d35bf57,1c91a2ca,1765ed62,f9b2f680,cbd0955,bc76332c,c83a7378,4bf3eafd,47a589b5,15a88d78,6f94f64d,674182e9,7dd12450,ab3ec375,a9a31d8a,375e5f7d) -,S(40ebcc0f,be3a2a59,968bf6cb,4d638873,5468b532,80a9c96b,639dede3,171db2b8,c2181816,ab9f0d72,c5cb167c,5bbf7e57,9f17d7f4,484996e6,3a23e0dd,5f5d3a8f) -,S(90de4b6c,3a5ccf14,cb033478,577461af,8c347731,9857ff40,79e6ef27,5e557b87,c534bd97,a4af903b,f307c1ce,549a9976,70edb69b,c76ae827,f277ffe8,133cf394) -,S(54e89b59,b73c76b6,cac52433,305c41b6,8f50df66,9b99f47f,599504ee,93ddb110,d307e828,1e89cba4,86ac125c,1c5d8bc,943394ee,222b4b06,f4e3e5c7,b5da176b) -,S(f2ef67ad,60858ac9,fb03ad25,f75f85e2,e5ac151d,95c96967,93ca080,58756f2d,92c0dfa9,372e1e7b,7363f229,2776c059,56742f60,7b100be3,56dffefb,bcda8cf0) -,S(65b7d935,a71dcb6d,eac70b64,91b9fc50,35c63f21,655a856b,afd00a33,52f5be39,b0773657,cbdd3813,8f50813c,558ddbe0,3f8ad81d,e420401f,175bade7,1429927d) -,S(6e950ff,6471cf66,72ea542f,cf05aea8,2c2e1e0a,c2247021,4c78895e,e291ee22,c0ca0886,f0ac828e,21a5c60,776494fc,a6f19e71,741de92e,c11323e7,e874788) -,S(c3b15f8f,96c0079b,471896ac,89d7d11,8ea1607f,18a20627,fb18e1ff,24ee3c1b,33a033c6,68e3cff6,414835a6,ae3f89f6,643326cc,7e149f56,99ab4fbe,d5f506b9) -,S(9e333d9e,1c022776,da901c19,e6936c3c,1af45491,a93e9405,ae343c54,775f36b4,c6734e91,3d013610,6c77a1d3,ced1babb,a6c6723e,316c3fd,34a7911f,cef616d7) -,S(398d2109,4c0baf8a,ab63ceb,6aa6b64c,678bbe86,f7e01b3b,8c0ff291,450244bd,f1ffb185,112ee219,24a1702,183f9075,471611e9,54fafb4e,36f6acc8,4ac7acf7) -,S(8f99c7d,553ca4ea,b160a07b,6d457058,90634086,80c709c,530aef44,bce43c8a,52a15e23,2e90d233,211d707d,5849e214,1f56e8d,189783ab,3c09f37d,b86a776c) -,S(8d798338,b2774399,487fe227,e2d883c8,39698301,5f01bf00,d154f4f9,296512a9,7cb53de9,9303a6be,9aee01eb,3a5c115d,eff0e18b,2cb5e852,75e9b7ff,53e35666) -,S(c9d6aa,ff6b648d,69416bfc,6e4688c5,cf13b711,29c785e7,3ad1e04f,ba02be57,9fa83446,5405aa0f,332a6aa1,922e3fcb,90de108a,db01796d,9045d423,ca0c2632) -,S(f736cad3,f1264671,f2e79bc9,c21551c4,aaa5da0f,befc1928,b9e7fab1,f59c8c5c,2ceae81d,16206893,b3810abf,d2aedb5c,55b79222,1346cc9c,908346e7,cd3e661a) -,S(7748965,7c1fcd79,60fa4a8,36feef6d,835f960a,d3b85009,7462a71e,8320a34d,cfacdaa1,2906f705,d83212b1,55475160,e02cde20,71fc5c9f,6a6d59b6,8e100aa7) -,S(279f43f1,e26ebe73,34924bae,563a0e34,e5cea7f0,eb9f5702,129fa6cf,8b0c67a5,eb5a49af,bada9830,7ceec508,70a49027,7d1cd6f7,6f332249,b2cf2505,82a2a828) -,S(cfccc083,9bbcc7d3,5ceca575,3b9148e4,ddd4464,5727cf47,26f33d62,d83a6a03,e3cc09a0,9d26889e,c969c734,a3361dcc,d638b17,608baa1c,e7cbb99d,a5bc23fa) -,S(e60b0451,70c2e3bf,dd627fcc,5eab1218,d3d598fe,a41f6bf1,dace1a35,2daeb287,a493847f,4f1d3bf,9e90c022,851bb652,691af15c,f4c6c539,bf2831ae,9cf8f2c8) -,S(11875535,ebc90fb1,eb7a08ce,90dede09,fa8cce24,b3911fa6,44ce8111,8848b433,2fb1757e,38148919,bb197d43,48aa536f,c0f06f9a,859ef737,ea50b1fd,82968ce) -,S(c69559b3,75cdaea3,56003ad2,3edd8ca6,c415868c,a13a30d9,11d4c694,f5822179,a39427b4,914b58fb,dd35408a,67ace872,8c299a39,278335da,9228ac85,24652906) -,S(625ff5c3,1e951b28,40f431fb,4842f510,8b738722,cdd52c4e,fdb495ed,e42f1f7d,a3eb00d7,4eb30337,d3f61ae9,d595996e,c7d5a3f0,ceb39f23,3df0f5ff,43298d7a) -,S(1e2fb107,bbb46666,8c31a927,3ce57baf,fd1df905,3fa28286,196a03da,74327c2a,aa882338,5261bb03,a8d8793b,c8f98330,97c22731,46ded3d8,966b16f,337643e2) -,S(d0cbd747,970ab0f6,19e5e4e7,78709399,b65b3f14,24a084b4,a2dca8ab,10d76ebe,7b5f778a,94d3d75d,57b5e979,3de246bb,f36669df,b7dcc24a,ecf4e153,2025b73b) -,S(ab4c057c,a40b84f9,10142209,a5c173ad,6ef31616,db80bd13,61959f11,b739f9e1,598f12b3,4695bb27,ccb2fdfe,a0911ece,eecf2cc3,1063a3bd,42dd100f,e93c7ced) -,S(f9c11e91,2cd3cf06,d31e4795,40c703a7,4f5f3100,8e6ce299,30d5f08c,7307276d,f873ce74,bab3785,156468ce,3d6a8cbf,c532db23,2a0a92fe,91d290cb,ad08713) -,S(2d95744a,79c4d234,40e2f40c,a83cd89e,61576686,21293dab,6716072b,2089b77f,a25249bb,9dd8a94d,44576a4d,7ed800c1,9adc5e26,82874ea0,5d63bcff,2f6b2704) -,S(3bec0dff,e9a96bb1,f3cbccf,cc96ecf7,e1335b1b,86f13b63,6467fd31,5cc33abb,e31f8a49,dee2408a,2d0b9288,4e381379,9fe404ec,1d8b96ab,39413f82,52b85b5f) -,S(23721d31,616051ab,60287a0c,2b4ada42,1bf00825,127ea0eb,1341beaf,a207fedb,8cafc4b5,40e6f3a8,6fd1b546,87ff8c3a,fa2372e0,24696071,59b6e195,f633b169) -,S(ff8e494c,446cf1c4,bd557615,a4a1ce2,b8d25bac,62a89929,993cfd,51d45099,113e1b98,555ddb77,b8680eff,c57eeb96,4038de04,26a05289,8744f8ca,4f3ef028) -,S(f170cfff,f158e368,81cb677a,c9d9512a,3c1705c4,850d5a85,17a66636,7b0cdf21,49512fe4,3ff0f91d,b9ab918b,808ac11c,b5eeb4cb,ed905f21,adce5e4e,42ebbf7f) -,S(e9ff6261,d6c05d6e,4e35e373,57fca0cd,3c3ea884,4a33e504,df3dfa2b,a524d158,4969683b,9af581c1,963525b4,e8244e5e,6b7e7e48,f85c1fe0,1e9f0dc2,c66e591d) -,S(c1c4879a,b614ad86,cb64d15e,cba92aaf,4d1c7742,76d6aec3,4b59f731,addf6cde,6d7185b8,fc1b99be,383a7a5f,385a08f,d7125e3e,f72f93c,25063bfa,d44abeda) -,S(deb0c036,3818a101,ba38a657,5c0db8e4,a65f824d,57014dea,1c110387,7bf2d9ca,f658d43b,f0c106cf,6b45e552,3fcd066e,e754180e,8510b58,43708b5a,b40dbe32) -,S(c4d4164d,f782df0,f5366667,83e5aa9a,8b05c7c6,91c47a49,14798685,1da3fc9b,6c394d4c,3118c8a1,30bea2,2396562f,6dfcf8cb,8f0a91ec,20a43bd1,548bd80b) -,S(94d83b82,f6db0da3,f1bc24ac,8c5bdd0f,6e89cf2a,bafd33bd,2fb3ca87,9cf63a84,9e8658be,59d64a28,7cc0cfde,1f35b83f,e3e098dc,6212afac,ea234437,2591f2ab) -,S(9de3fae6,e6934304,a84eed5a,58e077b3,76da7310,61859847,d6abecfa,fa650dba,7e4cd395,ea8b90fc,20850be2,4ba8dd83,e79dbc4f,4efed68f,504eec04,f9bcb212) -,S(251869eb,7a567c9b,7866c9b5,a829206d,867f2092,8f3a6fe6,46ebc3d5,2df7d99e,bd87d706,c49690a1,9e0ad77e,4b3b8f0c,5efba7e1,2a448a3b,b4ad3c7d,44e35e7e) -,S(e92e5aef,818b2980,43227673,3d15021d,c84192d5,bc9307fa,1add63a2,8e888a9d,ba3a3157,96ab2051,ad53b5e7,a058f700,ea90e40c,c5855712,d2176a0a,c232f94f) -,S(b6a8a783,c2716ba8,9a37c7,d7022dbc,25fef8f6,76c676b8,267038ae,64a33258,93b09e15,8bf081ab,9e69c4c1,6d965743,cc08ad85,a8eb248c,9c67043f,fe61ebbf) -,S(26e95f26,7ee205ad,50dcc75d,82330877,394c56c,84546cb3,72fecda5,f57c2556,dfc935f8,63840ca4,71bed804,d0c2d14e,c9528a9b,ba1e6f25,6545311e,5cae673a) -,S(6c1ed40d,dd086dd8,2fb00bbe,d969ea90,7e363496,97c350e3,2d0074d3,3e05bc13,854d177b,5593cdc3,ab1e4903,c64be02,2b6b0cb2,25c71390,9316faae,a235b269) -,S(a9286b2e,81030401,c37d69cb,1e73caa,b1c68a4f,4ce1538b,11ed850e,67d11aa9,64ab5453,c3a1166c,18f35115,1f031117,e29b1a31,237cb2ba,51f1a873,529766fb) -,S(a2b862c0,ca02cc3a,e1bc5737,876f81ed,83dffeb2,4e6954c7,3cf97bb2,50050cc0,db3a03cf,d704f98d,dad8f48c,5861988a,1caf439d,b50c196a,32289622,b9a49b3d) -,S(19259392,58c25edd,953117d1,fc7a74a4,a9cc2fad,892255e4,fefdac84,4784c917,b86a1bfc,b7bc8844,abe424a5,b7409abf,26e8ac62,7983fafa,70dbdaef,43a88eba) -,S(6b85864b,194b2cfd,af1d6550,4960370,306ee34f,87c91187,230de0de,42fafd09,54a9ddf3,87458a54,cd305e06,61dd43f8,3911e88a,db6f0256,d19cdf15,3ab4b388) -,S(407cbd77,b88e6d47,60b07e26,f53fefd1,2b98bed3,5403c693,e7ea33b4,cd74b5c3,eb73a1d0,fd122265,dc880cb2,920b4eda,610ff1cd,a74660aa,7cb91323,e5485d60) -,S(f65cd6a4,594299a9,6cdb5f9a,7889cf44,62cca331,d3329f7c,43ecb224,d58c817e,8c906c4a,11925697,9f84722a,9440d2e5,f97e483,542658b6,8538aa0b,f10f5572) -,S(2ea38854,775422db,43eb69b7,bbd47a6a,b8ef1694,28753fa8,8cf49c8,9efc6e63,bf6f2d21,2b21c740,a25dfacb,bd22436b,5118f1a,2004bb90,adf580c9,6f21f1e6) -,S(f2bb4814,94677f3b,6af8aa4e,6a3b1100,c2e0e99e,289536e7,eca3e61,a20793ee,a3a788bb,2a810267,9a3d98f2,6a9a2740,91a3a29c,234043ae,aacc488a,67849762) -,S(e157c4a2,84354b8a,73d5e5ec,58dc1ceb,2396ca3d,7f651e6f,4547aa78,99899daf,f06970d9,5bef3e0b,e2bd4597,a1c96581,275c9719,605f63f,9618816d,669a0bc3) -,S(25aa7f3a,3a14731f,c7fa3b81,31a569e7,4bf32c9e,3492e626,aa4a4316,f263cf12,e5c2e210,a8a75180,31778f4f,4737a0dc,bd1a1312,1dfb40c5,5c435803,4bc3eeee) -,S(73ba2208,8cb96b2a,c23dd2a9,7b3cfd2d,c504ccb6,24c2dfd,5062f8e2,bcc442ee,ab9d3a1c,6bd762b,9cd866ab,7abc0e1,f898c567,61c7071a,d64d5233,caec0ca5) -,S(da94893b,3e73246f,6a72041a,44c7279e,dd8d4d3d,55b20db2,eb0e08df,4c5837f2,6949f652,8601b0fe,e572ac03,89fc3530,6b2d09d7,b59c40c7,a1a607cf,51684006) -,S(908480b2,35c49b11,12bd6504,5b3a8e13,7cbd4820,3046880,1688ed05,abb8b7b5,8a887f57,622a7482,3fd40b26,f58ae7a0,18d2d03c,d5ed31cb,93a529e3,387fec7b) -,S(682d7401,31c966e3,2a8bd150,27fae9f5,4452fce1,360c449b,1b20bbd0,257d58d1,ee7f773f,9d074436,685a2fe7,21b1b829,9369f543,dcac37e9,9adf43b6,4525c19d) -,S(c8661c4e,dbe125bc,a31e7a22,83aa0f9a,b4b3ae70,8512fab2,21bdb4d3,8c89fcb,30299a17,16d3fe04,7f48627e,36195b21,e6800d4d,a26dcc63,96c7fea5,8f25a2a) -,S(5112b1c6,2b88e704,f0d2c731,834019aa,d51a108e,1a8614e4,f6e62f68,d7372b4,1bfb5f8a,ee37bb82,5494c9ce,651d32d8,d47e5a29,4b9123e0,7311f260,9ab4053d) -,S(b9214d34,49e16aac,b90f6704,ee589f6d,8fa45126,be235e9b,61ef3ebf,2150eb99,c9465341,2dbb107b,965d177f,de11bb25,53e8795,69814d17,34ee9ae5,267529bb) -,S(94185601,f959999,1999c919,82e5042f,b7e68583,533f9569,73788d5c,3a087b2,5e51c755,de79b6d2,eb640039,a4268d3a,601750c8,dcd0a942,eafc9339,6fa36c98) -,S(3cdad3b2,2a707d9,90fe4228,adefc934,e8c69a9a,8a4cbd87,844a6ff5,a073f511,f6de425f,26e17045,5589e22e,7824dacc,f8cb8561,832db31a,e8fd2910,558ff9f3) -,S(ca986704,a0d1935e,1611e176,60394d00,7d2aa1cd,cb17357b,b4a557e4,f5a4b5ce,8d527934,a73f2b0d,b3cf571a,ac53b3de,11ac99d4,6ba995b7,5a09195e,b10bb5f0) -,S(f5920156,3ec396c5,82fd6090,2d98ac,2d5dcf5a,cd37e651,a1e80c43,f76940e0,2e821f19,7e27f927,20230f1d,9e26dff,5b3d977e,4b4a6cc6,7482f3ec,3cd5523) -,S(9ced8c1e,bbe0d213,b396fb89,8aa8c24d,870d305d,e9346239,b2cb0315,c883cdc,79367b21,4a2e21fb,1e9b24d9,fed6a0dd,b377534d,4da2b501,6999ebf7,f77de2c) -,S(5b07b283,ca262751,4a10817e,bdfc8044,883f4de3,38cae14f,de955f18,9713dac5,b8d6d9f6,8a71aec6,3b7bb44d,1d2b678c,75ff83c6,37c254c8,3a14be30,a5957b5e) -,S(4c2eb4cf,3fe64ba0,21297b8e,321cac6f,a8245614,45848933,19453052,69337386,35ee2473,1830eea9,85171af0,96b6bc0a,72f3e83c,6d83f8af,8ef1131d,c8b52c8a) -,S(5f24fcf5,f8c0bf43,43b8a0e,b3b6d8f7,2901c902,6d43f8de,4bcb1cdc,6d5019cc,87c2a306,138265bb,59b2b2b5,6992fb37,b2ab28d4,ff4909f,d6067e2b,4f312cfa) -,S(e26bda51,c385a875,5083faf5,6a915944,3eb351a7,88e1597b,f17649b9,b23ab8f5,35d66322,ba25896d,2a14a0a8,a3f5bf91,d3ceab49,9b2683f5,db7f58e,68ca1071) -,S(ae5be06a,b1ae531e,5d2338ca,d929b5a3,4c283035,95282aee,7c3ac259,8196bbd6,f4f486a5,bf11191c,9134d522,62ccd692,cc5c6686,c9013ed2,782b816c,da416d25) -,S(d143463b,4661a173,6b88f274,6b3c20c6,d054683f,9efa5221,ffd3badd,14804880,77b28055,7aa11d3d,b2ac8de2,c9c5757e,d0c9b0cb,af6fca3d,bb295bcb,c3ff8afa) -,S(54804f7,28ff88d0,bf6fb4a8,a24d4eb0,ee5379f9,30f890f7,8e31afca,87f23343,79288e99,a38accc2,c59ff29d,9da5df60,42d63089,45900378,c40dd765,2f0f5626) -,S(68c21fc9,93d41345,484cf5c9,8aa93bf2,25fc2c01,922a0151,cb3e247c,f130ba0d,9c435478,23b9d8bc,2e8ba0f3,8f2b60dc,ca5b6030,eef51c6,cdd20eb5,a02c6245) -,S(2f50b870,96b2e15d,6fb35001,cd8f95a,875cea3a,edf21a2b,c433b254,7798b856,44b09dfc,e0b8d522,17e7d9f2,9bbc5d6f,9886fe9e,3e360688,8d7c4e70,c3bea0ff) -,S(9d054954,f0c22da5,f330b3e0,69310a93,66b72129,2fd3c98e,76464796,847d16df,45962d48,143c94b3,57400130,d3e050a7,4defd464,223ad599,e6aa947b,12679a85) -,S(31980b95,9f51a6bd,4cfd9a11,b86dda39,af66ffb,97713ba7,3edf8c10,462d5685,d0a02979,5b45ba4e,7464fc47,7a09a90b,7265f5aa,e6b0d655,fca5828a,837c2840) -,S(e9c0615,f0444234,1f522d93,eda33b29,8951a267,7c4cdcbd,fa02a63c,a57d1ed9,7aef87dc,7095f483,5ebf2b3,156be9dd,ecedf54b,1b0c739f,c513ebda,5c5f296e) -,S(fec8bd3f,f19fa6fd,17523af6,27384c7c,6c92fa85,aeab8bf,bbdd2178,89b12650,d01a278,6ee8f9db,38b1ceb1,a3fb1df6,b631c0a5,23e92460,d0d51367,1098e414) -,S(2094133c,86322dd7,ee1abf80,2ddde826,e6385342,6bc87510,dff63f3a,b94f54eb,efb2ecd2,13bfda3a,227b791e,c24ff627,17ab559f,1bd289b7,e7db992f,d941e850) -,S(a34c3385,ee882646,b44bfbf0,f64225b2,fb86df27,c616a2ba,6cabbb68,cf36f3bc,e99bbaac,57c9f5ef,c64c6687,6f2bd6d3,b9ec8eb5,f9227c98,9a768f34,23e91422) -,S(df09dbfb,564515f3,a6d86e05,dca59a0a,c353746f,b291d9c,add27d68,6810cbec,90738e50,6bead3aa,c0cc4a2d,cdfb8529,5e752945,a7b2e357,1a99c901,49017c47) -,S(df9817de,89526a26,c61e4294,f245ce06,8b5e22a6,4937d5f9,6898b9ed,74078989,c4db6e86,c6a44091,23227adc,345d6eb7,d2f12acb,f2df3b44,978a1743,94072f15) -,S(2e713387,7a0419b3,7bf77874,b24fd0,7cae9fb1,59919a50,223437b,7746eada,5dcc4c1e,12502573,b0520817,16fa46d1,8ba43ff7,e7f8c8cc,e3c141ca,6176f805) -,S(99826364,f0061305,1ba033ad,63b95884,97158ee6,9542d06a,f2f86d91,3bea7a2,5f109254,24af4592,2ab30701,464d504d,6006969e,30a9ce5d,76a3b115,6158c6ea) -,S(19222e8b,5fec6d2f,33a35fca,83c3b9eb,effb9e3a,f2ca9c53,929fe5f2,a43bcd32,c79b4f98,4621b2c1,d627dade,f01fe761,8af239e6,b80c23ed,a2dd1b1b,e750549b) -,S(e0ea59f8,6b7925d3,ad511280,8b1ae5ed,c0acf6c6,d4ed0846,d870a663,5573970,bbfa69be,ef531b32,5272ee02,8c880178,57ab2a32,65b5a6b5,38ef81db,83b5de52) -,S(7df189b7,c29c06ab,83f7d849,58ba3d1e,7da3ebcb,feeb9dc4,64b60420,3631fdd0,88e00d45,8287fbea,5c14ab33,6a879948,e81d9798,cb82054b,772728a4,4b69e56) -,S(42b9867e,7cde3ef2,b4b73f3,e4df7504,b7f06cb0,67aedabc,16edb276,97bbca58,eab47aa1,df9af0f5,40d1c6d2,ba7edcc6,fd436f56,c944c872,1e1f4958,63144390) -,S(9ffd9a,5535bd30,a697f61e,e6fd0ffe,b1a7e5c1,9459bd3a,708a7112,3a3da54b,79fb0a7a,8334fe38,64fef8a7,60610920,af2741c1,fa41f582,37e92acc,29644011) -,S(13ea8e5d,1116a57f,8b223a5f,79c750de,6c25511d,558e6878,e92cb134,7b81e393,a41efd37,d35ea994,8175d989,cde449d0,e325b40e,a247edd9,e8f4eef,e6a4d283) -,S(110d401b,d7a1a0c,e484fdb2,34cd839d,5e40cad8,6244cdee,5c4f2ba3,ee1e2eb3,cdd91a5,4dfa47d2,98a46f15,c021a38,975ca108,f2653019,46013427,349d7ca) -,S(48a9f1a2,fe29b05e,d419a14e,8ed288de,46affeb2,296522a1,f2407b76,a8f6b040,f1c5ea7,887c029f,67202b41,198113cc,f1ba5617,79afc1eb,db0e10ec,5b5d2a91) -,S(d8c4d9a,feb94e7f,7b831464,77aa4e3e,a48b6af5,35015941,4047cd01,1beb7176,fb8af9c8,da06c2b8,8787793,bd19d7ca,6cc64508,7713af45,4f5fb4c7,eeda3c2a) -,S(34e84417,2f5ff4a2,70a9064c,d5994327,9cefde94,d295f424,2c491efa,bc1f0839,2da40cc0,5120e4e7,8e84435f,895a3ed7,6c507bda,4d16cd14,b602deb4,366ff9fa) -,S(ea802ca2,f07a4348,791b7df8,99639d06,c6db8d15,74ae8441,b29c2d18,18b7a6c8,ea475a0f,5f74e6fe,ccfca44b,ddc38a4e,3cc19c49,e2bffa49,a9572146,6338a155) -,S(d80542c7,a7be8da6,6346d867,4154f65a,b1cc8e94,19299d81,6a5c874,f25ee43f,5e85d69f,b5c72ae,bd94b1e4,67e0d30,df8da61e,4150f4ec,e3efcfae,78d88d25) -,S(bdb35e49,7c1c0d1d,7a120366,cd259e7,31cb253,1bf804ae,f0c82cdf,561d0c0c,2675a4ee,aea6dfed,8597c08a,69fc251b,7bad9869,e83f485a,73dd1638,605915b0) -,S(5174e27a,9a1eeafe,6411f3af,b627223c,db0da11,6bca0ac3,d39a3080,815e22a7,b1223046,5f58d183,fcda2603,e4593398,51ed87ed,6839d9b0,4c845459,daa3d5bb) -,S(c8b1299b,1b2880ee,7720ad03,62588349,44bcc309,6a7081eb,ce10ef20,ab1f6731,ead86be8,85584e4d,34ac18e3,d787031f,72feb217,694a32a0,76f2f88d,a04f3440) -,S(fc1378cb,c42fd6e2,f61be9bf,e60bb2c9,b36c5a0a,4aefef09,c8287a3c,f1310d31,ae4ff85e,5b22d2fc,914192d6,28324d12,51ffc469,1ba8ca13,f8347edb,5a9170d4) -,S(7c0bf943,23e7c1a,8004b23c,c05327a4,d4127c7b,eed27e3c,4a825e41,5f3c3a6e,30ad62ec,bd19f80a,a9dcbb5b,145d18af,3248eeb2,1d14e648,d7fd7217,f1089728) -,S(2ede5f01,232c0409,34b07b70,1ccce3d8,27f85ad,2a56c987,e29cd6ee,d841efdf,24cbe9f4,69f036a7,6e140720,f65817dc,847e9562,4820dbdf,b8a1384c,8d39bdfc) -,S(decd1afe,faf01eee,d2dd89c,bdb9711c,4f1899fd,437d0371,55cf74f5,9aa0858,899d1c8c,49b0b3a1,89a24445,568becb1,d3b1420d,ffb2c7a3,8fc291b,258f8ebd) -,S(1dacbc1,4be6e70c,4043f5be,3f972d36,3cb456a2,2ee1b1ce,3e207578,8233a79f,fc3b04b4,f502affd,37d71c58,d6f1a61e,b126cda0,e156608d,7f2ab786,e0734486) -,S(12ad0f7f,cc7cddd7,60cc6a3,3fd3de83,b1ab0e3d,cca013a5,68d5978b,a176cc19,b4e0cf97,335b374,661f6c21,46aa7315,a2c4f6f2,b839f88d,5376e256,99e6e216) -,S(f649bb96,e477a5f3,f852dd31,65496c07,5e14a85d,fa929794,64f1297b,d56fd1c8,46e37dfa,7eddec82,88fd18eb,9ac200e6,79337296,e2cad24e,d67f98a6,2e61d040) -,S(34f5e5a1,248db96f,a165950,a9b74392,acda22d9,95496808,82760daf,642c600e,a8a6637d,a1cad7d2,f72fe1a,df67eff8,49d0ab0d,7e06d7c1,a11078aa,de9dc733) -,S(26e940f9,ab45caba,adb1e4d3,23e5cf70,575c44dc,dd2f0b10,1540174d,d2aa715a,972aeeed,c5fd01ff,3b04f236,c799039a,9c7fe6f0,db1348e8,b97dc885,c57926e5) -,S(e3ad36a5,132f1067,503498e1,ed4b315d,4d06cc67,3a9207ce,47224497,12f51a4a,4fa719b7,37cdf1b1,cd5b963f,16a47e6a,e43dbe0d,490423de,fe5deecc,5baf9e8f) -,S(413fd0f9,4e231525,1aae9d6f,61aa0038,dbf7cc03,10c81185,394c8cc4,8b721a9d,9281c5b9,ac1f56f1,50776cf4,69e57118,8cc6989c,ae41b950,f72ff25a,d6de836e) -,S(9841a473,600446a5,5ce0ab4f,2e77ad12,bc2abc34,1e607241,c0c61d2a,d87148d5,7d1bb113,ee4b5199,95231834,1e05d87f,f9bb355f,df958410,3d161969,1d786f4c) -,S(1d4cdc2e,3e06c052,69958eba,f00484b3,36594f9b,be1ea98c,2382e608,cf78272d,6cf5d126,766fe5f7,75bfef7d,c2d91b48,66d4bff4,c8eb4e59,230d1903,16ac6bb4) -,S(da74f388,86de9c6e,36227258,758111ce,3b9414cf,cf8d5cfa,bcd9b3f5,44f1262a,d9231255,e3d9189e,a8d0344a,80978b83,3f1afb57,5c799f01,8b4ab73e,866a38fa) -,S(b2ebf119,46e37704,e1e12345,c68f70a9,a031c0b1,e85c0833,c5df9c0a,b836a6b5,c1652832,1666f0f4,19806a4a,86f4aa8e,46fccb4c,f7b6493e,26d9699a,9db2bde4) -,S(9fd899da,eb6f84ac,edfdeb4b,fbf8b521,6b5757e8,10d22d4e,56afc38e,da747cf,2daef35c,7ef36b82,d6158256,2466895b,9656970b,4beee8cc,2e0b12da,83d7af64) -,S(eda65e56,9cf07e84,19d07f6f,4aedd24,3c46df2c,bac92772,bca7edc6,ba17b217,1f394c99,b48348e6,fb709e5c,b4b4b77d,41eac2aa,bea2a4a6,353d1982,a9985281) -,S(78567d1a,1a96df56,299c9ee2,1d916472,303178b6,9b18fb00,a23c10e4,f093ed5b,9321fb0,6c5d2dc8,52e64d6e,453d9923,bff7c626,efaf5e50,245b4ff2,64158f23) -,S(c639e1a5,90f5973f,148e96f9,15c94d8d,7c7ec36c,bdf15150,83503aa9,9ef5636e,3620e7fe,faaf7581,886776e4,f7391599,94ae3e2f,2a59d4e1,ad6d508e,f4db90d4) -,S(73ef6655,c49894,7aa2b63b,89b77f14,3ac096a1,d7333494,d9774ada,5467b60e,c04509b6,2135fa8f,816436e,6ec0f513,ccbb23f8,782e2ca4,d5eebfea,6a5297af) -,S(bfa4506c,dca70a3b,a8fb0188,e0384bf7,3afbaa0,6818d503,df5015f4,f10cf341,9fc7388e,2edd63f7,9a5d328d,1b949a2c,a364075e,f94c8de8,37cda5e1,7d566ba1) -,S(2d594b,814a9e92,7ac9433f,3400c5e5,1a58457,6f47b8f7,f5f0b8d8,f48b2cb2,fa9a1577,d565b906,1acb9efb,4bf415ed,f264b662,594d1ccd,51baf83f,101183a7) -,S(401ae44c,a4039850,4d57390f,66044f6b,cf1e9fe9,f0f2b057,3f64f026,b6d5f3e6,ed947768,36ce65ec,f947b81,9dedd31e,c8ceacd0,16a40a35,78a592bd,4c2626f) -,S(43f9397e,a000ac26,8a315406,fc9cd047,b9cad513,8a7dab38,2717744c,ec6662b9,14d5bbe0,52dd8635,29c0b0b2,dff7379f,3e2ae95,6c5b4920,b36452d9,56085bca) -,S(25036a12,d8eca48a,78cb5e84,41aa5a53,16376e83,e2ac7819,db9895c4,dcf2a22e,14c421de,dcfdf9ec,b69a24fe,1c289ec9,f4d0f9ca,6f4b9409,35ac9815,a4154209) -,S(30e9c9a0,d9b9c92e,65794acf,a2cea34a,8d56e3db,d5b56205,59100128,26bf8991,999e4729,bca75c06,18f0bf9e,8ebf0455,3460031d,4ae47623,5e4ba182,2f62550b) -,S(a8fb641,fe27c40a,8e410831,fe1b0d2,cf74072a,bb626b19,2fa51341,e99ca538,f3832ab3,4eb6917,3e2f3755,366b2bf2,4dbe257e,eb516e39,4bfb91e0,a63cff8) -,S(5e09a349,98a824e2,f3ffe2ae,34a835ce,6b2f0d28,43b765fa,8dee010,49df7867,20ea03e8,4817593b,931d1612,2d01dc7e,52715fb9,36838de9,d2c9fb69,9c935025) -,S(e62a12e9,d02a5a7a,475dbcc8,79850ba8,340b638b,a5c3b505,8d3c7ffb,c90f0dcd,b075d21b,40e5897c,7e849529,bceec7f1,d5f87881,318c115f,acc99680,31d17f55) -,S(45aa5534,530265c1,c358b529,de15487c,b6bef551,5125e835,e027b0a,a69a9cb6,2e56d88c,acb32ed3,24068fc4,4c03ed2b,1b70392c,9facfc2c,2fafc696,fdb8d397) -,S(7fe3d940,50e2f358,31b410ce,e54c7c82,5eb05553,981f1c45,b136a24c,4d4a4b57,97b0cfad,4f6669f6,efb2d35c,42302e10,87c03b3b,1c22e23,24050399,345165a5) -,S(110dd614,85bedfa6,c09a2e5d,5737ab2,4a5b35aa,40129388,c6ce876f,bd3d9c30,7972ec2c,621155fd,12f0a1cc,30927669,13a9165a,7dab66aa,8f8fca53,7411041c) -,S(7427d28c,aecb7a35,a4100c42,9fe03d5e,6d3f2f91,a5067866,c618c4c4,5fc53547,8cf74ed7,1324616d,bf4135d,8f442ba8,b473ebab,fe981f2,3a426eed,bbbcff16) -,S(9779c811,98040c8e,754b9df4,b547c09a,a9f25410,1ca1fdde,365b0ef8,34ed95aa,148280a1,d26c8ff9,51774c55,7590081e,36030a10,a148c322,3c7379,67d036b8) -,S(41113833,f7da3a4a,4736fa62,ad7b4508,74ef5b9a,b0961665,e30f3081,7d861adf,98399ec3,485a984,cdbb6817,783223b6,59884450,881d2f41,3f4e59f0,ed5fbc65) -,S(f9830e6b,9a9a9dbe,50abcae1,d44d4856,3a92e505,aefd52d9,2259c41f,4b8b14bd,12061be8,5a0042ea,1baa46df,b36d6f78,62c11cb5,b8a070aa,6c6a8991,62ea1c0d) -,S(71284b2b,36a4c8a4,40fdd713,6b647482,bc73d680,3d6d0142,833d34bd,f2794077,6e54f5fe,8cff4ebe,bad1b47c,4e5d6407,44be9171,b391492c,df48bc35,10e195df) -,S(524a04d,a1b7ba04,34377531,99178ceb,7ea18f36,2c300aeb,a8daefe8,6e63e9d5,1c71ed93,861c3b1e,41a7fcd6,57225e92,b2ddc507,4d54652e,3898683,8c3688a2) -,S(e1fb70fd,2057dc3b,c545fb80,eb91cc9,479cada2,93c3492e,260b0a75,4bdc0222,aa799a9c,25786c64,d5138ba2,1f801e5e,88fc2602,d4e288f1,96c8d79d,7bad2278) -,S(2bf126e9,8302e8cb,407570f8,c3fe1206,3c91bf2f,63cdd9a9,3dcc403f,a8592d29,6452a6a2,20edbb86,3ed65ed6,cddd70d2,6b4975bc,e843a41a,10ce6ed3,d38591f2) -,S(faa217d0,1d9f0517,5950dd5d,e02972c8,b2c88076,36090d2a,6f17e7df,2a70cd7,73077022,dc1cb45a,f9e9d056,19635760,66ba7b07,bc79601d,ae7dca1c,a6cdc033) -,S(3d184ee0,ed45af08,6a7263b3,47b12449,a7270887,b8460b7c,6428ae4a,6dc4836e,d002efdf,1259dd8e,ab5bb606,97e8892b,4cb5376d,c26d08e,52b7c9a,760e8826) -,S(3c825a76,29890675,bfdcdb73,27f37c4e,43214a91,c6ddb6d0,f31e13d3,cd26eae,45bc7ae4,649d70ba,99df5d07,92e89130,87a272b1,bb2d6043,dcad0fda,a5444fac) -,S(3a8822a8,d5b230ef,62f657ed,31a12d63,2862f22d,eff16f08,8065981b,ed3e926e,ddca63dc,57ea2ecd,b25e8d03,2868b12d,abe8f7ba,8125a4c5,56d80a9f,9784a04) -,S(d0042da6,aa3b60a2,463e3396,98229067,c80f8924,12d8323e,7482ff2c,53ad86cd,40697e7c,4c5d6c,4ba11cee,fdbae25c,e234ece6,7db446df,daa03025,5f8adf35) -,S(a06e32ee,93d70c5f,a45a68e,2a180be4,7d8a7f60,17d035e,47c94d47,6f3838df,f4bc98ee,c7f50d34,4e88ee87,d8705b50,4cc0fd5a,5bfba498,5fe0699a,df811bdd) -,S(21426073,9f41da95,2dcfa74e,dbcc2f22,375fb359,93f83842,99e3735b,e39b45a5,697f2d88,74cd2249,cb84c9aa,16d20956,f5c40358,9d5b7965,ea4b46d1,9cd61249) -,S(84d52769,327646d6,13e3e1ec,2d20791d,76b765eb,fc5fafaa,20097164,dc9cda7e,d87be4b4,2e2e55fc,8f87dab5,c8c64493,f09b3996,87ef8fb,3a6c653a,a2250cf8) -,S(ca48382b,49283747,d433be3f,ee0569ac,7d3714fc,bbd76157,ac5229ee,ee25dd0,b67165e7,60894bf4,3cc80df5,6e3109,db7e370a,bebc7503,ce20836d,3f0ebb2d) -,S(8a6a751f,816c206b,91e67608,58fd7def,8ea70956,598b1c61,8e0699ce,602cda79,617ea6f1,c7f98cb6,41f01862,1f4c8cf,12a556e5,675765cc,c7bb1283,cc8ed073) -,S(1d035f81,fdc7c483,9936692,9bebc7d9,15fd3c0a,380f3348,13c65527,d82344ba,e4203070,f687298d,af8f6d66,6030f3a0,5826b0b9,31f0e55,8c356aea,b3464712) -,S(d28f1a4a,1198f572,a8130bbe,3f25e585,348a33c,2d73053c,ee7e29de,8a3ce79c,2841bd4b,c46c772a,57018c74,8510fc7a,dab16644,f157d51,9c38391c,4470f7b7) -,S(41c71a1e,eafbd926,4a49ba4d,e976e72c,691026a2,b1773d4a,88670b4f,d9c57fb8,c2b198e2,e4557f8,41203c16,b511d61d,b39e8a67,21b776e9,865158e1,91ea5ac) -,S(3f0ae72f,b1a06f84,803ff8ad,fa0e5c76,ed0b596e,d52568e2,6fe4aacf,6cdbc3ee,69a9dc3e,a0ae93b0,6c4650f2,941ebe38,fcd4eba2,fc9cc0b2,3fb9c127,81c53f78) -,S(b59e2f6,2f01449e,d6728b04,e9334f10,54c4c8e2,db4a422f,70566b55,ba4d2e5f,1b6b73a5,7444de3f,4137f2ba,722e70ab,e6a785fe,1ead6fae,9f2ec5db,299f00d3) -,S(42145fda,e72df9aa,fa3c20ff,cbf11a0a,d357515e,ec6846a6,5cc6ffd8,8fcb1347,4a34e518,c9d39736,3c88ad65,62ecc0ea,2652c6f,48955852,99a0de0b,5f42b6) -,S(17a085d7,8d8013f9,b98a8509,aad7553f,bda81df3,33aa6f7b,2457a74b,c83f6739,412d9b80,efeca81b,29619ca6,8bdcdebf,7cd253c5,88793675,6a379655,d10df76a) -,S(f5ec770b,2e0d0afc,7b155abe,bf310270,28bdff39,a08d113f,b0409624,e7049ae0,e9ce5d46,2dc5d255,a09ba37a,a7a5edcc,aad29ce8,6f9c6b58,d2781e81,5d88a25) -,S(45e3976b,749279e4,486d2db6,fbbc7731,168e7311,d7d75f62,b754839c,2fd17918,84f0c079,c0127eb,d1064724,927459d9,ebc22eb3,502a99a0,e5876e15,29c8845e) -,S(df15c304,378da361,7f821d07,d00d1bdc,189fae9b,7aabbc71,51c2117d,8fe0c21a,589daf,cad5cc54,58544b9d,a69dc510,9f8f1e82,866b1076,ff1d229,5942deb4) -,S(c5798ca4,547cea39,75e3b613,911434e4,e5f503bc,9ec6e9a4,8dfe8386,a371494c,2864334d,fb2bff0a,4690f2ce,d1a1d1cd,e3b13f96,325f295a,8e0d4f1b,b13413f6) -,S(773ba0e2,e1a80ca3,9060556e,2fa8d15f,83dfd018,dd226751,9262651c,9765c915,e59a686a,3fd13284,e380188,fa40e9e8,28991374,20c906b9,ae882512,7dc7dc60) -,S(6ed4cac2,e1685eec,16c12251,db5dbceb,90f542e3,854177d9,83ee6024,d6e7a740,2558db33,ab598118,1802a84,e6ed32ae,49c25379,606a3150,6ad03ec0,a5308b98) -,S(21cfc6ee,d98915cc,1bb52da8,e83aae9a,64970d4f,ca3e70d1,6536043e,bfb60fef,8154f487,290cb8ea,73cd147,c1286d5b,9f471665,d9e0ee24,c2be264a,2f1fbc36) -,S(f8db764e,bb8f031c,88921a73,92f75323,7d1f4a22,7bc8cc64,8bcfa9a1,235cdc11,82c25fea,2d0a1e37,e16dc4e1,b6737ee2,281693b0,b48911db,c79c1470,c4e6274f) -,S(d52f4eef,14a5a860,983eb0ac,8e02def9,53f2ba03,604cc60c,80882e56,ad6b3dfa,b34b3131,7e37b973,9559bc2,6f85226e,705bf06e,1fcd818f,d5b88eed,f2d6b7ed) -,S(3e9d0688,b9b67517,e25b526a,4e46be08,4e95a171,f9d99ae3,4cca6c14,66adaf6e,e1938d76,c4349375,1d5b9876,4ada7b7f,57144878,78805540,70b7c27c,9bfa312e) -,S(c74f8dab,54590ad1,3fff217f,b62f43ed,7f42ffe3,6c8fddac,fb6315f4,a3406094,1bd8025b,57dd382,5b5b6896,e90ab5ba,fd31ef46,8f02846f,29f1b1fb,f90302d9) -,S(71f88089,a8e0ac,6cd92e03,b1dafb04,76c0f489,f16def9,75985abd,5dcd02ed,839bb263,7827e6ab,f6941b53,67c9aa09,835c588,3956733c,267fb52b,6be767a9) -,S(983d1cde,7d75d70e,328a8a62,ec82a96d,5174ed4f,c9676e10,7c282be7,bd408b07,5fe2426f,287fd353,173c699a,39407e36,c365c413,76986640,7c12f11c,5dc436a) -,S(3cf9defa,a067fd0f,6b012fe9,8b05aea2,83c332e8,cbc8296d,c777951,9e62519a,3fbffaec,c77d872,7dad2011,aa314690,2806f763,b73b780e,375508a5,c77a613) -,S(f415897a,cf653c3c,26fc5231,f375e28f,c23041aa,af05455a,e81419dc,25546e30,3a9d5669,806ef66b,7a0661dc,cb941531,d81fa7f3,e08fec72,ee6312fc,4a7f59e7) -,S(5bfb64c9,cacbd09,244f3a96,d5a6800c,4a012297,95962fbe,a429b659,8e085eb1,e5c4ecb4,9cc4c685,a4fadc80,77889298,b94e779f,7f462aa2,130ed8b,ccc0604) -,S(61a5a78,a086ccfe,9f54cb0b,750b7c8c,5c8dc4b0,e32f3c69,c65ce4f8,9009587d,50193c13,affe3a34,1ff3b8a0,b37f07f4,b49667c9,f8940311,9ecec58f,a76d8c60) -,S(e74514ed,93784bda,ca6e30e4,da2a9a78,c7c70bf9,42cb4ba6,afdc357a,c694ed1d,ee4a8c9f,7d55dd09,c51117d0,754d301a,cc36dcb,49d437dd,ca46a920,7088440b) -,S(dd9aa58,f2cc4c0a,8d2bf548,6dea653c,b4671e40,c0073df5,352b2a9b,95637617,6478aca1,582a65d2,6c0f42e7,48f06e60,ab85a494,d0129b85,5b5fdc62,7dc7f580) -,S(fd7f2622,665c2005,9bdb8c46,d140ecda,ce013ada,6dcf3503,e28eae44,c2dcd83e,536c948e,5db2978,31e2ab3f,fee860d5,dd7fdd16,645cf561,67e484,f4a62c61) -,S(9635dbcb,b2595930,835598a7,149a8a37,be64f607,c227b307,4d8e8184,c2ae99fe,1b2cb226,bd9f23d,bd243ea3,eb57baac,163f4e49,6272d220,9f436f81,7b6d9442) -,S(642ead1c,c24db5c4,77d798b1,515083a7,7777476b,c3a03993,883a7ab5,e1abf814,185293e9,6e6dcd7c,209fc891,d96f9dfc,4012f756,7d3e2f1c,282eb0fa,5de46eff) -,S(3c5be7eb,3aeab34a,2d982ebf,3a766962,822ddb39,527ab79b,83540818,a4e2931c,a161ecfd,2b906280,46d6d1de,c149eee0,e6c92ccc,5f936a51,e2a4c3,82e555a9) -,S(c1a90946,6c0ea8e4,b60611fd,6c61733a,6d90b0f9,d1b7a761,1f9e3e84,6423bde9,f928d301,b6c27eed,79b8a8a,ba388ef5,24b17220,7ebd7396,5623e60f,f650dcf4) -,S(e49d97c4,2ec1b8f1,43180188,382b265e,4216bdcd,82824a15,3a0e1d73,83207541,8e521e4b,95a1f4b0,934753af,cc3b73b4,7b3eb00a,a9c7af48,7e4e5a02,6234b733) -,S(49f71f26,f0d828be,9e9a70c1,bf768117,ad2fe6b4,6e9f416d,eaf17695,80dccfc1,86f4404a,67e8e6a6,9a901589,d7c09873,eb553aca,41b0cb66,f4767621,76ff0d79) -,S(487d806f,67635c8f,b66afe46,3754a5b4,64afa469,2ca69541,5d91a6cc,8903e853,b610d414,26951e55,46bb7216,6dfb62fc,602b3d20,18c38670,760f55a3,6c45c688) -,S(47af5aaf,cc7b69e4,bc536d57,8f57b958,3fa17666,2d302141,54e3e35b,57357e38,b79a4c34,709d215e,dd3b0fe4,9cde9de5,b45ccdd2,af25bbd3,602a0c90,9834dbee) -,S(84f79cc1,a257fcad,546d8218,5caae7da,8a8d523e,7feabb79,16ad7d8f,5421575,cc84b844,55ef03ea,59913a0a,1919c0d,cde9fd92,ce872029,57a998d3,80ec1986) -,S(550b7e54,3d3accfc,eb488b6f,b2b48d0b,9017a5d4,ed54d55a,72b8ac6f,c83f6d14,91f318dc,ea83ec1f,f43d5172,bba5ab1,7891f3e1,2e162b6b,8c512589,5f2e5141) -,S(f691885b,eece383f,1f56593f,92de0b34,1627cd58,389afaba,f442663,88aa6a32,1e6c920d,2eb76656,63c7586f,7907471f,79e5faa1,b6fbf4a6,c905e422,9a441638) -,S(4e3c52a,96889e52,b99aa469,b5f07dc6,f6720e49,29f3961,fae2c59a,98ffacf9,ba3a3d9f,dccc36fd,a8642167,7f54de2d,4c079b2c,e70b46cc,926d7d9c,ef1978c4) -,S(66720c8e,c638367c,c934347b,d8768338,54eaaa01,a81a876b,d2321e41,40381224,eb595ebd,67c5a08b,24482042,5035ecad,f20fcfe8,9a84a60a,93f3c05,a926d574) -,S(4b01f86f,f9feb661,eb33d7eb,87f940b,74302cb7,449b0bc4,84e97af9,56b79d2c,2680db84,1b233e25,16b74190,fd3a0cdd,b8fce285,ed8577b1,e13c2205,9af0d3a) -,S(dea430d,6a4b5e18,fa04f77b,55f85d36,df9dcd47,87ad5899,c16d2533,74494867,46b1f5b6,307a1c05,f3b42ff,e7a272c8,c63c2a92,19bd2971,d70ea793,5bd508e8) -,S(3f987bbe,d7fe896b,8a8067a6,de49de63,670e7260,f255e5c8,a926b9d1,fb62945b,373b2f51,86d7d9eb,18570d3b,9e48756b,663cab9,df388899,7af923c9,bd79971d) -,S(6cbcf291,56e3cb2a,b0d3c03f,3f4c0283,d953a641,9f7e8655,d8c46566,e3990b70,535c1017,fb40108b,24de2a8,358d217,8e47961,e5f4cca2,aa7e7c2b,339c60b0) -,S(d253488a,5610a541,e4ce2cac,bf4d4901,5fe63dec,94615e80,d795b39d,9885201c,c58ac205,e7323ca8,9bfd284e,9c9bcf3b,89b05571,b84d3afc,d69a9a96,9ae4fcc6) -,S(bb77470d,cf0851b2,29494d6b,e69aeabb,dac44010,17200af6,391cc2d2,352bd9e7,187cc653,b6b56e6e,6c9969ea,705a6d9d,3539d4b8,b8777371,b64deff6,45307942) -,S(438c5a3e,1ede7063,eb928da9,693d7602,809b9e08,e49951f2,6a600eb3,e929ad1d,d2918af0,67d34eeb,d8f179ad,2f3f105e,a5cbfc9e,1f416cec,372a5175,8ae797c5) -,S(35db0905,e28b3e7b,b8c4425b,8d9151b9,9cce6a6f,b6e11561,65b7e356,9191e69c,25963fe,ba45cdbf,5472c046,3da3279a,60a3f1ca,9ace47d0,4c4648b1,52d2e560) -,S(6ef2e9b,79e48447,7532ba0,1b658af1,e27b13b1,f1635317,6b47d994,cf3c6bce,88cc8a3a,aa1f2040,7976ae7a,9bfe09f4,f0c1fb85,72f122f8,4aeee871,b87867ca) -,S(c85fa35,4c064f00,ac39d455,7884f8a6,420c4192,aef2d6af,8afd61ec,2b977b33,3d17f849,6ba4a79a,bcdaf502,87fa5fe6,15d2c24e,58f27ab2,7cfb2d86,140a5f0c) -,S(7f47028b,4e84f4a4,21909f01,85df2743,e3f18f1e,134f90ae,166c4089,a9d44803,4c025c2a,c2a1af49,fd7e1e3d,2ddab9ed,104a0e21,17895fc,36eaf9c,7a550e9d) -,S(6ecc57c0,5c7f6b98,6cad9c94,435664e,3b036ae7,325ea091,234ac216,3dd0e324,67086288,9346eaf7,e6bc8ac5,25d60d5c,41bd9701,f5cc5f58,7995fd6,1c75def6) -,S(46a2a28f,61fbbf15,c3afacaa,e181f527,2b957bb4,7f127465,fc03d021,76359328,88b36e79,2c071ec4,adf1a34f,a3d1114f,f9813f91,39b2db5,83320bef,134ace83) -,S(a2072cb2,e25bc045,fe40dead,8fd3f7d6,449f8d7b,57adeb47,b6ae9b7f,7d6a5b2a,fc019c0d,8c9263f3,aed518e4,44c1e5bd,dcf796fc,7d16cc6e,c90c4c59,7877e36a) -,S(fec203e9,60d4ead8,e3510545,3e73999,1ce5234d,a92a20f1,813414a3,599874c5,118cddc6,fe918be8,d2c5483e,c985aaa8,4d708767,4af70444,1fc0692c,b92a540e) -,S(fd166bf7,a69d80da,6e03c740,2ce6f4,a05f1df4,e2a131a,daef89a5,86f73681,1e3f6791,7f2d3824,ba4ef07,86ed8f08,c65860a7,e6913fd6,8cdd759a,2deabf29) -,S(a479787d,b514baf5,b46a578,6a221d72,2eda896a,a7fc1e43,4817f125,2bbe0d6e,1a6f7857,92bc5fc4,e2fcd87c,6b82ed34,20426f30,a9c6fde,4f09ae14,9ce426a1) -,S(7aeeb17d,f75e9c7,2dab575d,2ad1cf87,b3eedf99,8df4b14d,d42b50e3,7895f041,8060c0fd,5f903934,d47f3886,8731ddfd,a6fc1355,53be9a44,38418174,37b79fbf) -,S(6dd254bb,63c3fcc9,a5d1758e,90c0c6d2,bb1a19ae,788b351d,191d0261,cba75c76,b00b5cff,f3246b0f,ec835345,1d9df948,4fd903d2,e278ac2e,59d8ca20,647c2ba0) -,S(d9e76bea,acd64f55,9a9c2888,5834317f,c24fe5f6,7e540d27,6233c187,76cd7323,4d079fbd,15ab81b4,f3aed0d,663178c4,33f976d4,f69af7dd,ecf61a13,b831e71c) -,S(b57b26a0,55c4f224,865b22,287c9402,4c801618,c50b00df,33ef8509,a94a0f57,5abc4303,1701260a,f41a0e49,a100da19,8d033179,8b26026d,6401654d,39d53670) -,S(e03c71c7,9d902be8,5caf4df6,aa401a6d,18592725,2f10be1,f4190b67,bee3bb8f,e5f16a54,ce5772cb,1390e49f,966a00e6,893ceadd,5a753c7f,9d82a2ec,7324240) -,S(b7f3b64c,980f19f4,e4f46083,c1ca758,70f4313b,3c23c5b8,6acd6c8d,57ec0de4,5fd0d8f9,2a70c9aa,bcc1523f,91fa603b,e17fa73,fce73899,2c1d720d,3d55b1ca) -,S(27b24868,2a1b9186,3a1f5c9b,a5010a37,2349c417,e1d7acaf,dd94c7db,c5e12733,c54c23bc,4e17418b,deface22,b8e527e1,4de1aee9,71c921fa,fb3f58eb,e4778125) -,S(5d4b2b1b,5f9e640,bad96aec,6d3bc5b6,169411e9,5dac7346,d1f7f885,50679a14,80f0e3e7,7e8d6c48,62b1f6c9,c0ee37a3,3b98be7d,e1c6c8ef,12759b73,c20a2e3) -,S(790a4189,63c3ec0,ba6babae,18ddb717,463d3ec7,c0b01852,5e760e96,ac5fc2c1,6db8b456,9f2fed97,783a6e80,413d8ff,cd0ac6e,d512f712,4cdacad4,4845242f) -,S(38dd209d,705c3f63,9cbdb0b4,22160943,4ddf1366,56f2cc8b,22d27479,c5446f99,8b793f60,3621f6b0,1b1ac36b,cfd92c3a,7dffb7fb,fcbf831b,1db077ff,7482c25a) -,S(29c6b2a9,24f95c8,58857951,cea2baa0,bee9866d,77b3f7d6,3cf9debb,16437528,c408f565,cc78e5,15a6e0c1,7a96392d,2952e25b,d067a0f2,d2f10eff,b54c2ce3) -,S(19f1ab5,b54c80a5,a32a1fb8,1bb3f389,ebb53641,6c8a844d,3846c2cd,350420c0,38a56a7d,7eaf4155,4f5b8090,c06fcbba,9f516a23,340617e4,dc5951d3,35b75de0) -,S(fa3d2b8e,d73ab5c3,24980054,27830806,3715c17c,7981db6a,61757048,1e1d780a,7bc0b4e2,4cde1ca3,e30ec601,73121a43,f87f679d,cfac6db5,a9bd132b,d6a89454) -,S(908e538d,730377d9,d3585ae,59b0949,c46a6aca,bb04e725,70b189d5,57c26825,5e108800,6cddf00,39f7d855,64252cfa,d4a37761,2b58b6b,5fb2942,7e274af6) -,S(e57bfd8,f38d456f,2e977090,d9f81673,db11a195,568a85b8,dd8bb725,a30d22ec,b5965e5e,e680e791,e87ceab7,156a3e03,dda7e9a0,9a9dcd76,a72dc838,d9e2e6a1) -,S(aabc514c,b88112c4,6e6e1221,d61e2abf,dd7a3bcb,a2c7cb78,4d57dea6,1950534b,96e3d9b3,f3a4c3cb,1473f61c,e224dcbc,a535c90a,7d993409,ed079d32,3c8facc1) -,S(94a800a4,6eb9506a,8f6dd737,ba45c697,4e563c3e,1df40959,4198d1fc,e499d2d8,627ef26,d39e19d,ab4d6bfd,9d4fcc0f,4bb4d97e,b0886426,40b7ca31,952be814) -,S(1022de3d,6caa7542,ddeb47d2,1f82cc3b,6e04170,ed9d4ef6,81b58b81,efd6c3a9,2317f1e8,37716a0d,842884b,cd77cc3e,d6235dae,9fad5661,9f20a883,af459b5e) -,S(9509f343,17c15f7,a54cafc7,3d4275bb,41e39183,53858724,4031baaf,97bed951,dec71a0c,7f8108b2,5e296361,2d6623b6,7b2f6d9c,69d7b6cf,d7273503,fc72b4ba) -,S(bbf19e9a,efbee2db,fbd5eef8,492f52be,2e2f9072,6b3adc1,d16f0627,f4f19d25,d9e691de,f2ce976,c66d806b,f35a2b13,56f9fc07,7b7bb239,30668081,4b52cea0) -,S(b5997bb4,5b359516,b28ee935,e4d59c39,ae434c29,5e5d98e2,2ddeff57,4afabc5,fb6d36a6,fb2e1aaf,d9b5d89c,39a854f4,a3cec053,1e1a776c,b4267b4a,d2bd8ac7) -,S(fb746cf0,cbf2f56f,6a3a99dc,71e84cc5,af76899a,3a7d02c,fb272391,b77c8384,d1e4cf27,57373ab2,d1ba3f2d,d5bf8b26,a74d6814,23a5b16c,9621b788,a51e9796) -,S(644facf9,e6290462,1a5278c3,f4a2ff8,84600c23,69eeb557,bc412540,c4966655,5b5ee0cb,449423fb,67c9b542,3868f7b7,6d1968b,9d7dd751,75e7dd5,2f994b88) -,S(c41931cc,9c311617,f77faa3f,6b6f6e21,bd030c2d,9778b065,6ca105f,cdb8658c,8a759dda,8db8a8ed,eb1f2972,12858879,bb2f49c7,468d8edd,14d28525,ca3c0746) -,S(e8dd9063,48691527,e4f4fc96,2a0e5608,d151aa68,53257e2b,1acb7d94,56f66aa2,470d108a,4180fbd1,2a377517,c5e472d4,680ec468,52bfa472,cc400ac6,91541a0) -,S(6b48efeb,ea6d0d17,346fba31,8fa33deb,301062d5,94b254bb,db6dd28b,ffe27451,94cbae78,eff2064c,cf91bcc4,fe1ae3ef,3d767b63,6eb4720e,35f2340e,87c1e941) -,S(1cb08c2b,72f069c0,e1e4afb,7ea73e48,a33f23cc,cb89fb08,db1b0919,62bedbd4,64d3500d,5b6577e6,6c18d3be,fc0a7dd0,833d3245,1ad03257,b45a31a4,67c14095) -,S(2150558d,bc64dcb6,55224045,6d943208,7b7c7182,3901f78d,9702a736,998906fc,b49e2adb,321e0c49,ddeaa152,9bf83095,762ea96f,6c1290dd,b6ad29b3,c84b8657) -,S(530f4c16,58284100,55a67001,eebf528c,f9286825,fbb60ae5,da4ecac,e3d7f4c1,80b147ab,1eae8922,50bf82fe,1a9263bb,41573617,7dc02e91,fe7e07b9,66bc6af9) -,S(c5158947,8266dd62,fa495d4f,94bbe77,b1230f44,685ac488,7642576c,8d92e6b8,1705fd37,da813af6,2a799e41,3a45a4e2,4d2121e0,1065e692,ec1de149,43be7c90) -,S(e6963d21,b576da6e,6aa6f1ec,da7674d0,d827d533,31e19d85,83ba0e7,31553f86,d3560d2f,91c7219c,76962a5e,3b2aea76,604b5ad4,82da8f8c,419cf2c8,7cfdbe61) -,S(c5aa5963,a249a9a5,9445c0da,9537d482,dcb6ed9c,8372e455,4d440931,3c3f169,7e7f9c15,4ba213f5,981389d6,22af8694,b1efbdc8,18998923,92c9d654,92ae7fa6) -,S(bd04e3d8,5bffa429,81310c7b,2c885f04,69f01977,2819f6f2,5e69621e,5a32752,dc4da51f,b88ed097,b17358d3,da4fb755,254d8ceb,5b0df72c,9dc995b3,8e145d9d) -,S(f8f55476,4418c668,3390b604,c9f9f452,1ef63756,58000c49,d3b8b1da,80261dd4,9943a6e4,1b928da0,fad12667,cc997ea5,6af49db3,8c499a2f,a2343efb,52ea450f) -,S(77dc24bc,5f32159e,7c3b6a3d,168a6698,43b12253,e403299f,b4fa3db8,74350dec,240d860e,c38457ab,6d741edc,e4fd8c51,67f75733,f12fe892,aece4f9a,578c6bd5) -,S(9f238f7d,588d53f1,52da8118,2691194d,99a56fee,373745c9,aa2a3a7e,58d18825,dff57ffa,c2012315,ad6516d6,92902476,cdb2d3f1,58803c3b,4dc854ed,8ba9b756) -,S(92f95782,a59da5c3,a12401da,34c24ae3,fbf3822e,355ec948,6020ac04,3ebbbb6e,1c6231c4,e09c414c,e0d3cbf,9be73bbe,4f1fdd,b3d65a41,c716f0f9,a39788db) -,S(1b40dd47,f435579,1474b560,66a0efb9,88271a1c,19186bcb,b1715196,84f3130d,9fe6dcec,991d652,c9e13099,66b0aeb3,53869f99,28ebc955,6c64973a,4d983b5a) -,S(473f6b8e,d4162f9a,2f40d48a,8827f79d,180052e1,7b28b240,4772fe1d,64cd82d3,743450df,fc8315db,72c01f1b,21c4eea,9c0a39e4,c1e92e33,91096576,37e97fe2) -,S(40cfc629,a550b437,9e0941ae,fa8abc6c,8b492155,2045a8b7,560262a4,86954932,e627bc57,9c84859b,d2a9ba9c,9d7a69d3,8c8f06d7,ccd9e68e,fbaa0697,655a8a23) -,S(4c91dbc9,8d2d2891,a7861599,ab55fce,943755f,5f7c909b,3f0f85a2,bbb75c95,5e541495,ecf13109,6ac3aeda,5324fe5f,6f761ddd,d2972fe,812242ce,12fd23d5) -,S(1fe3c538,ac185172,44461f82,63961364,c3c74bc6,9a91bb4e,69973971,8e729d23,974c02cb,d7d97c,65f89b90,327e6dde,e627d96a,275c869f,22c14bf9,6be05389) -,S(fbe873db,56579349,4ca9c844,8a6e0dde,226d4e4a,2f210661,30fe1075,bb11dd6e,c91061e4,d03f9f09,21f56d76,eb78640d,4df80464,459fc41d,4ca33d4b,5ebbc5fe) -,S(b58277a8,3a6d6779,82af314f,7a41a69a,b1744e6b,1cfb4803,f52a25e9,8200957d,c8faf7cd,59e43256,33403b90,7abb1b83,d3f0cade,ddb9884d,77c5fa54,b55fc51a) -,S(3949cb,e84b7790,a7a110d7,9c41d548,d379604f,ec567cea,e3aaf0f6,fd0d9b49,cdfe904e,56a9c88a,76292c3a,5da21100,57795a76,fddc1610,e7efab84,750617b3) -,S(6ee9ab2b,537aeea0,bd8332dc,d810cb7d,36f8f7f3,57be2bb3,5d84e236,f1bca531,d75518a4,d975b0d1,e2780851,4b726626,dfc182a3,885900f0,4d82c839,1c64722b) -,S(c2875d78,3e15f959,33bbbd48,8a24c65d,2001f599,3536fa83,8a3e056c,20a2eabe,e5870c25,20adee27,83cbeaaa,cfae7283,538446b,7cfd7ded,12e68ffd,3f66de8b) -,S(88e26c2f,dd475547,8795e8dd,8285f73a,dd9eb9b2,68c1b16,65f1a701,cb3c81e9,d00344e1,9d14b3f,1dcf5c7e,8269237d,a2af90ea,93a9e24f,3a0040ee,d3f171f1) -,S(ca8e8c50,660f3928,3cb72105,43710f56,9a1518a,7948689d,3d7e2ce7,a038bc55,57600213,1892bc9b,5afede4f,e71f5ec1,a1516039,ace088f,9a851278,c52b2487) -,S(ecb6e53f,4330d0ec,b9aa3605,b6e6d209,222d611,72858b1f,d2663797,772e0249,b054af9,4c535d01,bcbd955,61770aa2,e08678ea,cd8de0db,d8efcdf8,623e9eb7) -,S(a011ad64,55123316,9916b20d,ca6efe7d,e78c6b58,feee97fa,7f9e3fc6,8d889cfe,f53b71eb,63f87651,aa0de66e,a51f56f7,c5e3ee26,ed4ccdf4,1978d7b6,f0191277) -,S(3ddda2f4,ec1b4020,31a73abf,ae69dd42,8d801bb3,fc96fd1e,b06334d3,cd7dc27f,eb1b6b4,137ca36f,5b160112,38fba958,32c5e5b0,aa5560dc,39600db0,624b6c1a) -,S(13f5b643,e908dc91,415ff856,76357687,bb777f21,3972cebe,e8157828,53982d8e,bc2d3402,f3af6ee7,bef0ec2b,73c75e53,b70309ec,633d97af,b9ababc0,62d20ec2) -,S(ed9fc1ba,60a7db8,93db8148,48790e52,4a246279,d938a04b,cf168ae5,71618e2e,b241c920,ab995cf9,4ab1b707,b06bbc7e,1cf7b8eb,80325934,d57e9e9c,6ba08459) -,S(89d4f6fa,f6252ba0,d036dcb4,54fa5f1d,311ee828,1cc5ca85,73fe7607,7b16fadc,5f441ff0,56fd4e24,ca4c9efb,859d6e16,2e4daa4b,a7f3fc58,e42a540c,23b6075f) -,S(4acfd390,e8a1b430,9af0c28c,87f51308,a1ec5741,8c194072,45c96c79,30498a3b,dde7b57e,5e5ab271,78f2ae5b,6494a578,2757f508,bafbbe64,30b96bc4,96728d2f) -,S(8320cbe,fa7483dc,4f5e7b7d,d74cf492,b95b7e31,b1bdc651,6595b605,eecc134d,e766291d,13959f5,805de8f2,aa59cd66,8376d93e,4b775010,426db24e,b2ff41f7) -,S(fbfa6a21,deb1d183,cfeda065,687a0b96,6d8e50fe,475a17a,7b690019,6e7c696c,f5901c10,5f30f5d9,75530b0,3f943caf,8de85a12,f54e4c7e,5685184e,8bacae2f) -,S(70695a81,45fad213,aa14a7ec,d3c84f51,53e3906d,5483db4a,c6e8c229,ecd2c3b,febf34ba,9744a37d,6b91335f,c735c426,1208595b,3b8d048a,3fb48e76,2008e90) -,S(89fd8cfa,8fd5bdda,b6a80bb9,96ebcc92,6074a15d,371622b6,1cd772f6,ae1ae9a9,85c2cddd,a8065ee2,244b3d35,61e9e057,87c6cc4e,d4b1ff59,53b736cd,d3876108) -,S(342256b4,cfd8e5b7,5f5d088e,3a919d64,ccf38827,b18bdd00,2ee9a6c3,fb4dad,c54f4704,f3512e55,4d96ef92,3005e4aa,34a157e5,8bd6b180,e219dd51,16c4be16) -,S(cbd38ba1,189a152e,bf78ea23,3eccebc7,16f4c28f,273f5c8b,ec9df397,9dba0dd1,d3df2ea,fa52ad52,9089c7c9,581dccbd,a2a0e060,7fd4b902,cc915f28,717c2d29) -,S(5f7ae38f,61dcf176,45affec8,7514c624,85b880ad,38df28ae,b695cac0,fd1d27ed,9b955855,f74cc040,63cfa4d1,fd098e5d,e0030c4c,6dedee41,71bb5e7b,c0939226) -,S(72e72eac,aef492f2,f3c5ce7d,dca58f40,c919a194,3662adb4,3d855a8b,532d194c,d7b5e558,a0cb091d,3b39407e,1dd58b95,30fe7561,6b4c3352,bfa51320,509d2d7f) -,S(925a19f0,c73d85d5,674a62b0,2d5496c0,5868fd41,a43696ce,eb153a0a,2e5b8051,2ff229b9,6c23cdd8,2bdc56da,37495c29,78fae40c,b429a1c7,3111d392,3c5505c3) -,S(baca4fb3,33bf98dc,165cb9e4,3bec920e,bbded256,e990820c,8f902e84,3f6e02bf,af304697,137728d4,e96a38d7,95b830c0,6c18579a,9b46f4da,a94a13e8,d3a0341) -,S(fbe24c7a,53b90f3f,918b92ea,e58ef633,bb72e695,2eee6c6c,2210f6d8,8da9e0df,1febd844,af3d057e,c9ace544,d5fd57f0,c125c55f,1d9df636,4f6be8fc,bc53e3b5) -,S(73b7de54,ae8a38c6,ccde88c9,3f526c2e,54d823de,a6415488,5e864a2a,1b0574,2cfa6943,634201d8,9438e6c6,fbb7224b,c2e6b313,538523f3,305c75c3,5c68aeb0) -,S(84960402,31a60cd4,cd623d4b,80bc69aa,7cfa7c0b,52cd88b4,2f22ca66,17151dfa,b5324b5c,af293ece,38deafd0,76835e10,469997af,7dcccd89,172ad20e,f36162a6) -,S(b6de647b,98585f7c,61f0712,76c6f62a,40926888,b1bab4fe,ad64098b,4b9434dc,f7180d81,be634f34,d878a645,2c662e8a,db9c18e0,ca7e7c13,8bc51e1c,1a5f5c0a) -,S(e062011f,da416281,bc296718,300a080e,fe7ab89d,8469e8dc,fd50680e,12dd9348,c33030e4,1ec1b1c5,4ad01bb9,8c4e2c48,32b2516b,1b2b3b22,adc4add8,1b690787) -,S(f7c7545,649b4659,49618dea,7fd15a06,1e7ee032,5d955649,b76b66f0,534a5501,2a929b2,a68342c1,81b2f55d,6b543584,ac06077,d95ad8f3,fd3f3ffc,24f56a3f) -,S(bd90ad48,1694f297,6506e2bd,e97d5803,b810f9ab,7479ae90,dc1fb146,38d4d5a0,f973b70d,8dca64e0,c9384b7,ad3b4ab6,4d3c74aa,722f9284,a9da82d5,5c6d02e2) -,S(cb5d91e6,68b3c202,b72a38c2,f98e6e4f,14bb566c,f7996d9c,c08aaa07,210b1b1a,68e9920c,597b633f,9bfdfb8,72814422,4ad69ec1,e435e843,73a9255d,79f52d7e) -,S(d251bb9,83bf849b,8f058ff6,32ac6bea,bcd12649,4fea947a,f943cdf0,6e0c240b,5098026d,b8ec5c54,8e3ae103,f0d172bf,e84281aa,b8c0b131,16295587,ed4500f6) -,S(27235299,c1f8d73c,268bca88,62d2b6d6,635f151a,d148c662,6c0cd5cc,1a3d2234,5b03cc60,f9224aa3,10d8193c,74e70cbb,6513ba73,d6d98ad3,2e1c2d,7f78ad52) -,S(1cf437b,aef8e007,ba02a24e,735d8444,698e5edf,2f9d41d3,cdb28cf3,3dd53851,e3fcdb74,b580b8ce,8f6edfe1,c276c478,da11323b,4e96862b,926ca4c7,f739a8f3) -,S(aa872c85,70e9449d,6cf020c6,77669c8a,7ad408e4,d9fa194,99867c6a,f77df918,572579ea,3d1d9575,e60a79a0,7a2aed83,4fdfba52,61b962ed,42e59322,c02fd873) -,S(b3224a2e,80c3a174,66a9994b,717b4c37,424f12bf,9dd3f17f,6eecd801,3ee2ed56,7ad1cea1,128c1605,552b8be2,a5fb6bb8,907e4290,d76bc82b,e17ecc32,1be6fa43) -,S(29b8f73a,7fdf6032,4c907022,b0107c72,ed951eef,29687feb,a8de56ab,4e47b8ad,19b849d9,bbdcf00,a6bba6b2,f1058695,4f286884,9b5be608,d6b4c357,1098f54c) -,S(3c2f5680,96f946ce,3d048364,dce939b4,a05ae9a7,c31c2a11,d2a29a1a,3fed06e2,47701685,b698de43,ac515062,9c40a15a,bb952a0e,bdd96,ba4a1b4c,5f61658b) -,S(b80f00c1,ec0d059,c9f5c69c,10cfcb26,651716d9,3d0b5702,b2c7b295,85af4c55,aac197db,ab42141d,31f63425,5df908fd,fd026d10,1263aa7,63d99414,adfdd02e) -,S(66af071,6b78b854,16572c86,fb3e51e9,b6d66ebb,bfc2a2f8,dd664010,83c83435,b8b2ce8e,fe794b13,4fcaad05,821dd884,9a8318db,614d858,8dfd4d2d,65314398) -,S(7ce8342a,6ea85f61,559cd2ab,e82debe,82eb5aca,142153e5,320562a7,6ba155c0,8a930243,5ebf4269,d75363c6,93ad4255,59f493e0,e492150a,9f110c90,8d7750a) -,S(cfbc37c5,184fe206,7f7b5c6f,c5e50adc,ed58ae61,d9059bb,4ff64a19,f48483eb,bd567b19,3da2b2fd,bb8941a5,be9fc72f,11d9cfa2,4c4438c6,a4db3091,9c8867cb) -,S(728c27be,52c5a742,859774d3,2d33fbcd,41e997d7,25d6be46,af480c8c,f9ec436c,745c7738,2a833cee,19808d12,9768c213,7500e8b0,b140e3b2,94abe97c,9a7c73e7) -,S(4553277,fbb30c09,a1ac1ac6,cb7d38f5,88cd5f3e,d4ebf6bf,5b5f6e78,12d47d5c,3ea80bc9,dac9f1a5,ac4beedb,d254cc15,728f0ee1,6949ce97,53f1bfbf,98e3c78a) -,S(7b752d90,9fd6d063,f1ac0f22,d8cf1e6c,78a335c6,ed11743,88192fe3,cba54cef,a252376f,e482ec59,2ac440e7,3aac3b46,a149e35,1aac2d51,244ffd93,f51d11ec) -,S(e78e796c,eaba974d,89d344f2,b610e84b,d51443bd,1fea5422,d2bea957,5467a376,13f0797,376bcf76,b6ade4c6,a95b6446,962ff925,b32fef9f,4549aa1d,e64e2b1a) -,S(1b7a8c02,83f25ac4,cd4a841f,4045035f,92a39bd2,c1903c90,4071eb44,5e8d702a,1843f757,7d03b6b2,22bdc28f,47c7fe6,fb83b25a,8d795b46,9e3ee9d1,ccf7623d) -,S(90d06a90,6ad81dae,20cfc2fc,6be85b2d,41dd9f23,63e13423,c557c4c4,bf3e5e4f,6ba7a127,58861784,2d7ee3d5,9b71ec99,86a72ae7,71312739,79544095,1e5237dd) -,S(d7bb4e18,ab61d8f1,de4b5bd9,9a5d03ef,1e0185ca,55ef14fb,be1f0b5,4cc4803f,311f268f,a672975b,acabcab5,1dec5754,48eb5a82,685e339e,e23b41fa,112873e6) -,S(6d5f1808,f17e0b81,a6bf12aa,34032644,b708882,96e99861,fe5ba4c5,5546c44f,8eb304c8,92cee7e0,70649d73,ae76893a,610504d3,fdf37af0,92d5dc7a,9eab1094) -,S(e4f62cf,9835a4e5,c2b7a456,596498df,2973192a,af2c80ef,c036c71,69df470b,874a48df,1a25a003,ada8939b,f727e0ec,b7d2e4d7,1efbec4,7193a2b0,50ecaf28) -,S(7fb31d8d,b3d5b77d,4aa9d0d2,692013ce,c82ccd6,83a2235d,848037b,dc6bf8ee,ed5cfa61,9fb4e350,dc37e2a5,2bb67104,90dcb484,b19af368,8101e59c,f9f0f0a) -,S(8887db9c,e3eddeef,ece414a4,f46ff048,3c4fd25b,14354869,6c60871c,5eaa9ffc,50294d61,1040a466,f826e654,3fb93f94,b4d60b11,d589287d,6ea33df5,a8dcf366) -,S(9d9d224a,595c843d,1f70297c,13b3645f,385eec97,80fa9e50,d27115f7,b677aae7,af9d5f61,24594cd9,a3aa7100,ae6f169d,dfd467c4,1affefe9,c9a0a5e6,6d7f2802) -,S(743d9b40,527b23b8,f165b6fb,9d5c14ef,450e1ce6,94439354,ab501eaa,2f34137c,6aad08c3,bf602b52,7d43e3a6,e7efcfd7,f24222fb,f8213f25,e8195501,9c8f0885) -,S(63c850eb,f0cd6fc3,3bb7a4f5,6d43c389,1f93b11b,5f67e3d2,f9b7537e,e5a951e3,29d214e8,bde33612,a5a160e0,f7cf3acc,3b83686c,ec5d7c36,dd90ebb1,d97c7ab5) -,S(b95608d9,84c13243,63809f82,b42cd16,fcf3c6be,5b19ccd2,249016eb,d93b4a54,41aabb2f,e7083dfb,ea380fff,2467a843,c88ef6b4,9740e73b,33a088a7,649fb0ef) -,S(8361b632,5eeafafa,f01e3624,6bd8f0c7,aab461ef,cb3484e6,c1ee871a,7ef95114,34ac956e,791cef3a,baed24de,7f0f59e0,bf34dc75,edd10159,b3870248,255eef36) -,S(807109d4,931731c0,a94127af,cc98e487,1fb44467,6d8cde89,88dfc252,868bc853,363e3944,be00a734,4c50afc9,cbb43183,f56eb20a,c0a5d9ec,74857484,ed9e1d61) -,S(25ef876e,d1654570,244ec258,e7ebda09,35b11784,bf5afb7c,8652e5f8,bdb34055,63459bb2,b8affcb4,1f6ad9b,9437f3cc,6d8082ac,d400928a,29f11fdf,503c8553) -,S(1aa87b1b,54eb6bd3,5fefb162,b27ad9dc,eee4b5ec,c1b69d4f,1fc6e230,d1848435,e5cd86ac,23c3790,369d7fcb,2189098b,a4fb3007,f82e5090,22e8ce5a,b44258d) -,S(cce2b0fd,9497190d,e6ea068c,98bba7de,a8f50aa,12930b4d,9060808c,b1ce6152,b6aea7ee,becee274,2bd8146,d792a6e9,ae75fd79,bb8882c8,11135d0f,8d5e68c3) -,S(fe421506,955b7cf6,f6a84228,30f7c6fa,95e4576c,da711415,5a49c238,e0bdcd4b,4e4a31d5,9b70b51,f73a4d02,eb09e4cb,7dc74a29,bef959ed,86558fc7,d4c8f401) -,S(cb26c118,264778ef,512f8acc,385e5ac3,10b489dc,88991e15,13665b7d,587d713e,7375bbd0,9fb3051f,a907fee6,80683f93,54403c76,85ca7eb,97a711eb,69033c6) -,S(8f286ae6,171d88d7,d82cdc28,93960bcf,53768c8,9cf1f149,fba0acc6,f5056014,6852d427,a888c5a2,4e748f2e,e482d38a,42879db2,2e824d1c,d72cf15b,8e32b085) -,S(b7af4b6d,7eb4eb03,e827f099,fb8b02f4,bdca366d,811d031b,ae827941,235e75a0,7cea697a,e8cc53ff,8c738ec2,55a64e4,4a499643,4bc5e16,422ebb9c,17d3dd12) -,S(c8471c9f,53eaa3fc,850ae514,dfa1109d,e89c500b,e965682c,6a4bc2f9,105be1e0,7d5f32ce,d1e758ff,e38325b4,778e68b6,f0ae5509,fcf9195,c1a79d41,57dc519) -,S(8d192ced,73629184,ff6db80e,b2c6df4c,a8ad77f6,dfc98c52,9406e7aa,dd506536,3b01ec04,ff45b037,c1444255,9cb2f629,7b4f8cff,e4c3eed6,3b95d4a8,88fb2137) -,S(318aa156,f4912dd9,7b90ae6d,c29b0f8a,99f616a2,5b023f08,ad35a8c5,10ec5015,b398cdd9,5ad52ba1,d7038cdc,67e36c74,5625fb94,f62b1b9f,aa2eb5dd,be6ce52f) -,S(b7fcf98a,6a385f68,a1c6f9ee,c6f069c1,81b0c94,df8c05ef,b59b49e3,aad66f54,912e2098,e3b6e44f,46eb6382,83f554e1,80af035b,16c0eb3a,4e000cb8,d4ea2da7) -,S(599b7a5b,e7a7cc6,3e0b66,38171c0d,41d78efb,92a9bc8a,1d0e8f48,b2b92fc2,afb3343a,1983a867,c8e196c5,92f745c,9060330c,1f0c0509,375e30de,3a214b7c) -,S(c3578705,3221f18f,69dbc241,f927ec48,3280ade6,44c70129,2b30a11,a296db9c,2b75b2e9,fdef6060,29633ae,481ba7dc,8ca52847,d4d0a201,9da74056,40a980bd) -,S(9e2020e7,cc4153b0,adc2b1ef,3cf607ac,305a480e,3a8854d1,1907fca0,4811fa7,19153a83,2c9a0612,dfea182f,a855a039,33035757,2e98e5ef,43f26699,3b8bc6b5) -,S(1e0c4c68,6e5242c0,6645f4ac,6ccb18c0,82c5d5e6,c89322b4,3b6079b6,ccb5a5f3,63c4a4d7,3ab71f2f,c49f5532,b543e381,83ce223a,c8609be9,d6b72981,8b5dedfc) -,S(44b11683,5f922e88,e7ed4328,cfb212f6,aabb6199,64fbdf3a,87dc7f24,faa761e0,a9181b5c,341cd78f,2e1446a9,e99acfee,7aa5b91d,4c7da20a,b7cf200c,f470ffbd) -,S(940baf24,717ccfda,e539064d,f6e4b670,2ad8b60a,c32e38cb,fa4eadf2,6a7bd3e2,bf5ab95d,2cd9b68f,cdf535bb,84b967a3,f4fc44d5,5e6d21af,d09e1de,f5f13ad5) -,S(4191f800,85767106,a9e5fa6,8521366e,a3adbd79,ea315b93,9e63f797,2995e7c5,662791d3,407f50b3,7a68e15f,5ee71991,2e893099,a907db3e,f818938f,9c3bb2cb) -,S(1bb8ec05,76ce9cad,f96b418d,cb5c7d46,9b49ca81,7f253b15,8b26cca1,cb9a472d,762e9c6b,2335769,72396f,36a56efc,f2618754,f1c30923,30b521bc,4e0198b7) -,S(c5216da7,91635b83,e55ec5a2,d9f3f8be,b1a2b0e3,cb097528,654c50a3,315be78,2536358,e58ffcbe,789d34e3,25d9f59a,2210c247,a80eac8,c716214b,9d5e520e) -,S(7b1488fc,83a02d7f,d12b9eea,555922d3,f4a9c42b,52f030d9,bdd39156,f0890225,ae7dba7a,d95420f2,8c8185cf,5aa2b777,b9fc5c14,b6c47048,d8ef071a,77dd4397) -,S(e245e4f9,7d6c69d1,5e244f4a,668afd07,d57fea2c,f8401b2d,8cfb6ada,f01f8891,88a0648a,ed5eab1,d57226e4,63411b9d,3632537d,699f39dc,7d7cbe5,49e76900) -,S(ed78f3d5,1f4fb987,5918a0cd,d6e5280d,6516f5a5,acdee916,d3e7c7a1,d757d188,ebc569ce,9b3cd325,528cde0f,9a2ef54c,d9f920a2,1ba7785f,62ef40dd,9463a81d) -,S(3e8d870f,bf768b41,8264ad34,89026fe7,8870e201,3f98696c,81dc3b7b,c0b1b599,28558e59,a6a6c255,a352cc9a,c20508eb,55af7449,8d75ded,c94fe414,fadeb218) -,S(96125a01,8f901790,fe25b41c,f2f7fc98,50cd30c8,cbd05ffa,cb76bc45,94d5f5a8,125db476,3fc8ccde,492e7eb4,45873147,8f8ddc5b,6c2b588a,b72d9b1b,fcd4c43f) -,S(779d9847,6fd72d41,937fe1e3,e12d4076,5cc61f41,19b37437,3919782,18a3dfa0,75a3aa4b,95523e05,42f38dab,b2d80895,cf3738fe,5152c8d0,96a587d5,90442891) -,S(681e390c,323224a0,7ccd9520,23c9d89f,4069100d,3b275c5a,e773efe6,170f4e4a,a9bff0ee,334bcf6e,a3bc44e7,5d85acc,f753a471,ac008e0d,47b19ac2,476b184a) -,S(d7b8530f,3fa18d18,ed94b938,2906e431,44ad5994,5eef1d53,e3290887,5c4af2b9,2efa5bd1,acc4ce6,73b8c76a,beab2e87,6399f84,94a1450,bd6833dd,debddb92) -,S(1277ad75,6e965ecb,c8c04ea6,c22042a3,ca3e71e0,74334012,7063d3b2,da257a5f,38c90310,ee2bd94e,5f3149f1,f38d065f,8df110f,92f126f1,3a69013c,515134ed) -,S(4e66e596,94c521a1,8114b232,427dfb97,8c7f14ec,7b5e18e8,9c11cb5e,6a2f6f65,47d553c1,8a858b59,f1aa8f4a,51803450,c237fd2e,60b137f6,d13647e7,6683caea) -,S(1fc1e8bf,3eae2dfc,b141be5e,ea612378,209ab1bd,7ccce45c,d51fcfb2,8f192aa3,5632d350,ab6b3da1,599779c9,9cd8d7b5,e317ca9d,ef3245a8,eb62af95,ef769c20) -,S(7eca2d92,8d2bf4fc,ed1a8336,eb87c5f7,b864b842,b3057c8f,97d5dfd3,76771d7f,969da039,7a37997c,c243d448,90d8110e,fa580359,bfb35342,bf69dec7,4bb17337) -,S(2531025f,8fddd665,cf34baec,52733303,28e47e4d,827248ad,9a1e6c4e,be3db9a7,e404fbcd,d180b2ad,931b4f61,5902eb06,cf00f66,6f1323f7,bf0652fa,94dff64d) -,S(dd28941c,bf6e4bd,76b4bad7,88f700a6,8c4937a,67958c3,bf6388a9,d5e26441,cc45f07b,9ea1a81c,8d89af84,8883ad1d,53ee8a52,2416c445,c4963791,7a366909) -,S(d3af9e12,53ffb85,ec7829a,4d41d704,1ea62952,4d7452a8,d9ab6ef0,1d6b509b,9c115e78,91b383ec,20739d37,6450a2e6,6f332e5e,c7a3a97b,2eca8c0,ae819bbf) -,S(2c59063f,13ac98a5,ed196aec,4f2aba11,c8647d78,42be85f4,ab87a007,2b49001,e9738418,cbb6e31c,f588a3b8,70883f90,ed3bd8e4,86e3c77a,37fd1152,c22637d2) -,S(6c0ace3,f182c963,45deeee3,c41c5e51,8dce984d,3d409a89,6d766ea1,b1ff0e0c,17e09dc8,dfc53cb4,952fec4c,92782ce4,3515544f,6181bde1,1d1ba1a,bda709ee) -,S(f161125f,3a229d29,2053fb9f,6f118550,43d80e33,9bd45af8,c1519043,2098c9d9,1b442ffe,a186cf2c,343b90b3,66a3a008,e08edf90,f073e740,abd5d20b,8dfa1327) -,S(fd081f05,6b219fef,56a3fc1b,6dc7873a,fb054b40,1b3ae0b2,414384e0,9080827a,9711912f,4ceb0036,3e5921b5,c2f7ca49,387b78cb,f1b9c2ac,9c5d5d1d,1bd8203) -,S(72c6eecd,d87657bb,ffc3a03d,b6e1f9dc,83252d2d,c73ba3f5,8642fc08,fee42b4e,282180c1,7737b51e,d047cc50,64d53cec,6340eefb,d969525e,a1524f0c,a305e39f) -,S(10df231d,4582143f,1ad7fe00,508cbbfb,3d49775d,f13dcee1,d6155768,c14bfc51,b7743bf4,e7cd49f8,88cd0d26,ac196037,e1da9402,26518e07,407bad1d,20af7dc6) -,S(354e8b0b,e40bd9a0,36620006,744c0913,5bd4bcea,34ab3371,9561e36e,f465956a,3e7407a2,2b9d71eb,a04239fa,600834d7,5f643c8,b4ca6308,475f6c9e,8d35fd4) -,S(2ae99ec0,6a4e080e,879a60fd,a93a47df,9ba7e0f3,b87a6772,be6d7e23,9bf2c42f,3fdfcc57,6a36adbd,52467e01,f3490fbd,82766cea,b956f80c,7b1d29b0,5066c31d) -,S(f47ff09d,5e93e827,72e73c7a,8f1623e0,823b09bf,86ba3023,a223a680,fd849bd9,379ad3a3,cd546d27,35fbe5d9,97c3dd8b,8c45a3d1,ce8e9c49,b23bbaea,e93a08ea) -,S(252c0934,acc3a624,c4d8b409,111b248a,2242dba4,7d57718a,aedc9cfd,20647cdf,17b7a015,a2ea993e,89a7161b,f50124ad,561ef131,609981ac,fc92e495,cd2ec91d) -,S(b7f6bde6,7cdbbf9,4a3e06b7,dc1bea75,d6247197,a8617a6e,a1f65f44,a7459006,6d6ad596,fd3472c,9d7eff56,943c1a03,ee4f540f,29782f77,afe999e6,14f5e316) -,S(210c956f,e0a741a7,edad58d5,d47a2a34,fface7c,5edad0f8,f4953b72,28350b2f,4d4498a0,892a9a9a,4e87ccdf,424d7910,bf90fe95,186653c7,6e6966a5,e7a816b8) -,S(7ab93adf,b8f35eef,8af99e5e,e37aaeee,401a1936,fc0b8c88,518065d,12f4a74,4f0782b1,c78954b,8ce37bdc,7e533145,3b885d92,da1dbf85,940da9a9,b7f0dd8d) -,S(bbe1b787,9c93e7cd,891f628b,c9a655e6,f4c7cde4,fa799596,74978224,9fd05fd0,493d3dd7,be33acf1,38ef5b73,8eb8f8f5,4e270323,8f70078d,5f7bd9e7,177088cd) -,S(61f42d35,ffcc6151,f8c93b21,5df0cab1,fb804cde,f9c68818,fc4f413,b804942d,46ef1e12,d6add082,3917a758,9c137d45,c38ae2ed,eadd847d,aa574e06,18708396) -,S(18542b75,3e78191c,b3dabcf,f9c64a8e,5e4b075d,d600fe60,b830e732,7fbc7b40,6a816e01,41b17e86,65ec280b,f6da9dbf,8061329b,6db9d13a,a9f10c0f,41340118) -,S(ef83d0f4,a3d2963e,d14e708c,6d22017e,aa97b2f5,23b06f1,140b4105,459781d0,5587e5,13725819,1b10bd40,e616e06d,16a50392,7a8b1394,a562c396,973d98b6) -,S(fe73429a,7714dac6,ed0db327,d6949d43,30d2b16e,a513d3b6,7b74452d,78a82a4d,7079088d,fd828815,ae087319,c232817a,4928f743,843a4966,e9411276,d16214b3) -,S(2e8b8a63,3048900c,4b82ff8d,fd86a971,86e3f1b4,6206b252,f06a8c85,82555130,74e10dbd,ca84d796,b3b37ae,b32624c5,2c5aabc5,d4fcc5d2,21c1aed4,71c940b) -,S(9f4164f5,4f34a59f,3a7be378,66a8204,def2fd98,8dae6dbf,5d471e0b,caab7017,4b662fde,bf2615c0,8c7b53d0,b2915d50,ddd2916f,a3599d81,bb2eab6d,80e93f57) -,S(c6f3a26b,adab6699,aa08fcf4,6f0ac900,2be3597c,16133225,6a5e6577,11b16ecc,f29db1d6,579d0e36,4528c297,36019f4b,6e8f060d,ad5effe6,d357d709,882a250a) -,S(76a4f5ef,6a869e28,e6494cbc,ffc6eec0,1ca983ad,1b8219cb,d2b84eca,96f8b910,e1d8bd7d,55a297df,32ee185c,c60db286,a2e46cb1,312a8995,5923a068,cd3318d5) -,S(d2c25c8a,cfaa0b2b,3f6e70d5,bf095700,68102f8b,24867970,ef3c8000,b2212d1a,bc907681,9c7926dc,bf81278f,7dbfc4cb,292a8071,177ce8a4,f4e9346b,a2d9e500) -,S(b2fc2ca,5a30c678,61b0bd22,5bf2c088,26d799a5,9c9a680d,dabac9aa,5cb624fe,d4abc7c9,fab915d0,fe9dcf59,a0f83ca,56b27566,6e9841cb,b5b14874,5f6732ee) -,S(110ef531,7824c321,ba7fa94f,ac98de3a,c6cf44af,db92b7be,1006c751,9b425065,cc3daa20,6c0eb83,6bdfe640,1f7461a,261e7233,c70e615f,db82a991,77b83cb7) -,S(fe21a607,7419ed88,12d16ba7,5485e01e,3c063359,f95a8634,3aab1c84,ba6ac00b,d6e08c98,4b7a5282,bc1857b8,82604fc0,692a2fa6,40cf5a5c,d298f344,54c836b7) -,S(c5e45275,ec85bb32,edd32702,7d7d87ac,8394bc51,722e0bd9,58281e61,c454fcef,9b158ee7,89034035,fec4f06f,2fc81755,59f9f762,38742715,92ca6ff9,e5712a8e) -,S(cc68f3f3,36360481,5583d65,7da51968,a4a44a69,1264bac8,289791aa,dc7a4ef4,9db5cab6,7b31f3fb,f3b5fde2,273496f7,93316358,6d14e80b,bbca4613,319df9aa) -,S(6d33be85,5fe8bade,89109a3a,8c089aa3,f7e9d178,969100b7,eee7a693,d83ace80,9312736,87c08455,c43b4cab,afe71408,333fbd69,d330315a,3fc9a52,a9d473d0) -,S(5aa581c2,fc48c38c,2aa2e176,c12f12b5,4810ff6f,862fa17a,196c06e4,812b9e3c,adbff08b,bf6fd5e9,9f91f9f0,9881cfcc,a7b5c2af,709bf838,6055079b,2f75f3c4) -,S(12eb2dde,dc6ea4e8,dfd43067,9d45052b,b882e4d9,bf516b,61edaf00,305fe883,8f948ee0,f8514f9a,1bd8a71f,20c95e4d,e30caa5b,bb3a383d,9561f027,34bb1950) -,S(3d0d7eda,43045e9f,62dc680a,be47e933,74a95d59,945b69cc,60acb89d,e40dcded,45c53d35,e369af07,eb223a79,1d148ea7,1875cd1,8ca066d3,399743f9,65e184b4) -,S(173d4741,5803d266,7ea94abf,319c5917,204256ca,e217647c,c024a9b3,be7b70c,2da6c348,cb066462,eddfe8bd,3dd00ec1,34a0a060,4b7e17d7,e6cda389,dd4d5463) -,S(10659655,e2f1ba5d,db390184,c2d6d1df,1cd2abfa,4cd4bc18,c89decc9,5b5d6319,5ac2793,3a88870e,d5c7752a,459ced45,69435a09,7cd0e030,25608cf4,ac2ae267) -,S(e462be7c,380d7bbe,cd45c6dd,8fe60219,404b0c9,4c5e0e4d,31a23064,2b5b95,872183ec,1ba5b854,1f3f99d8,ceac80c5,9e84756d,cae2e694,9b43ea7e,d1cf752e) -,S(8200badd,1df41faa,19b20cb8,efa424d2,2f39b1f9,26b692c0,2a0ef6e7,feeed67c,8402fa9a,6ef0f83f,42546b05,360296d3,74db551a,d89be995,f2c11866,5be528b3) -,S(760e2457,a3e1a165,526e9fe2,2b5bcad6,e8107581,337cecac,e2ae87dd,a3c54592,c5111ec3,24158a21,56b897a3,82bee2bd,de0f9df,af9ef611,a7fd3fc7,4a635b3e) -,S(ba6229c7,1729cae6,5275719d,9a35691c,f260a003,168f1a25,1ac00b09,aa17872,7d281600,6bd8981,82126d21,70fa0ab1,d5dd0c7b,cc377a88,c43cbf61,70a633c3) -,S(a2cf1392,571e758e,6ec74708,dc45f70f,90833ad4,135e7a34,9d2810a1,8efb5216,2420ffdd,afe96506,9e6f9266,1e3839ba,c9b1db40,d40149ae,3acc8683,86acd175) -,S(f8822204,27cc4b37,33268925,fb80beb5,a52e5391,b2c8e31e,f6e99592,1775af20,6cf6eb9e,b19825da,6edc5d2a,66f3987d,c9eb01e2,b70e6395,abe2903,d43acee) -,S(eea28950,fb676991,444f96c5,7e42ea16,aa380e3d,dde63111,fac35708,a4e45b3c,34d30722,98a686ec,7e1a8095,4e2911f1,5e11d426,ecacf11c,eb45a5cc,7204114c) -,S(7f252a72,6f9a1497,f61bc4ee,7b194a31,432c0178,2f40b16f,2d36e9c3,7279e25f,8edf25c5,f50c6f0d,f8a17f92,611bf024,14e02d0c,de38aced,e96d5a7f,4467c449) -,S(d3da23fa,56881cf3,a42a50a7,42e1067f,54ec24f,2de19921,b1ae7f15,fb90509f,b4ec4b17,8e555cbd,15210f09,bd1ab43,28e458fe,6aa3e800,44bf0093,ea08f90c) -,S(6752f294,f8ad85e9,60b6a88c,cfca7874,5c80ed7a,93f6f05,3782ac73,d96e31e3,976222ef,a6f6358d,42d6289a,4f11bd65,e7e755a3,845ed49e,3c972b5c,5fdb2418) -,S(4fe21b06,24a45b69,7f42aa54,10e6385d,645a8d49,2a61ece5,c8d5b2ad,1fe74efe,f7666c09,7caeea3a,c4b2993b,64f4c0cb,ac934099,8870ade,b7cee48a,c3c2c413) -,S(15af87cf,6dc1acc5,1d323a36,b2daf163,ccc8c201,a92f0677,6a26ae27,7fb9d766,53fe4566,6a975d35,ed20a5a,7bbe63c4,4cf8011d,45e7a171,d5d72e57,5debefbb) -,S(656f3686,c60039b4,4c39a5d3,ee82cd08,e8aa8ed4,b9a943e,42281407,4ab6821b,9f277baf,2da730b3,dacc2a43,512411c0,13ffca65,7092e695,d49c8d24,a4cda4d5) -,S(a13286fd,2c17a61e,6bf8d209,d64f5879,2534b037,cd854470,a09c8c8d,95aa0564,9322d3d4,c735a485,5d76e5d1,fd27fdbb,a8af2fcf,ddf7bdf3,f9e26f97,7f4cd1df) -,S(3b355928,4ddb285a,1eab73c5,6e6bc554,9f40d83a,2b859e01,a30032f3,a5a7109c,780670b5,67755fa5,10fc3385,7745a69c,bbe73e3f,8186b3c1,8a82c51d,5e1d9be0) -,S(b0b15be8,6c2dbfed,6da6e7c6,51c10b17,504070,7d1747c3,ff2dddbb,256fa495,8d2c438a,42750adf,345332d,f02f6c4,55a07fce,afcc51e4,96c270ff,913546e3) -,S(c754130,bd717ab0,fc17e14d,dd6ec50d,aa6bc02c,a338cd9a,798ee62e,72d517db,fddf938b,28500dd,c9f1fe0e,70104564,d1bad398,d3bee900,ff609c8d,f56d3b26) -,S(ee615579,33d877e4,9bb228e3,62766ada,8615d382,c022c333,39f78ff6,5e5d9ceb,3dd38b15,5ce01a1b,3d5434f1,b2e04a26,6a830f47,fe89263c,b0ad1b5e,18bd8b76) -,S(f830dd7,4d03a39,d7f5ba3d,132b40bf,130b33cb,9b6609e2,12b6479a,14287c9,9183a68c,33c2d25d,c237f8ed,b5a63d44,4dd2bffb,d1255631,221edb9a,4c9e9e91) -,S(544fa477,3aa3589d,9e63c8f0,f30cd189,a8b6658e,ba908212,cb1b4caf,2d5f64ca,bbf57d7d,b5c6b8d6,e202a7b9,8ed06edf,e1a9ad01,381da1d8,11405fcb,8ef717c3) -,S(9b270440,132f5b09,6fec6214,dac1e27f,3e6c6f7f,25eb2cab,680c3fea,e0b41b1e,a7e591d,eb990617,6bc87263,6ea19e04,c9a3aea9,59059078,2a757fd7,6d99c6dd) -,S(bbd69c5f,f0b9228b,cfeebb97,32b3c316,c14d9a54,d5a3e9ca,ebb337e1,e33525e4,78cc6c84,8c246e7b,7636949d,4e3f2b94,989c77c4,812b8189,cb857cd1,3457c403) -,S(a920edc1,4ddf5bda,56719c0c,2adaea7c,9aa8aab9,25a5d6fd,41172725,bc65341d,b8afac74,46e560ce,bcaaf438,69dc9287,2805fc14,122cb19a,bb59e51,8336ff80) -,S(3c6e9595,a201956d,ed27e83,41b22822,445148e6,d00b2fcd,ecfdd66b,2405ae3f,2b8ef9a7,d7c37d0,d2b77309,74718eba,16f221a5,f3074678,317f0b6b,7b0841b1) -,S(c35c9e45,3f487f8f,ae5b6010,e1bc1ac3,ebe4ee53,33666876,13cc4b35,5162ed91,7a8e64d4,9f827631,579421ad,3c7f7ea1,f4866432,a341f955,6741c521,c757addf) -,S(8fc84331,a8f8dffe,28f30d71,b39c105a,ec09aca,4876241c,1c81a223,a1953637,aac7257a,cf0fce3a,ff8fc7ea,e8d19606,2ba6d7ad,9b7987bc,35a92b9b,20360174) -,S(b43ca4ce,f1b4a2d0,1a20fc64,2f3e1456,317f729a,1ee69798,4ed88bfc,1c5a2908,39ae1e51,f352c0c9,8a79cca6,cc859eb7,92bad6ae,5318f99d,d62d3bd4,d8fedad5) -,S(7f29c501,75628aee,5d39db41,cc4d89a6,9f133f00,47500f6b,aa7a90cf,e13159d2,cf17c6f2,f6072b50,257f722b,5756d8ad,c7486cc1,d21a925e,8cd29a15,4b514cd1) -,S(3fb93959,55ea2522,61b0488,212e15d6,b28e975e,5ff5f357,15337538,247f2a54,7c3db409,e06d6980,d834639f,e9e357bf,e6a4e9b0,ae6b4fb8,f5e45143,ff625ddd) -,S(945ad871,18199665,a4078a46,a9596bd3,ec7cab84,b6323a0,7ceefc63,d7ba29f5,6eb6d896,a24d02c0,630c909e,65d13d4c,2eacf1ef,6e600b89,1b171594,aa28c206) -,S(513bfa93,57c827c1,b3c0289b,c4ce443b,cadfbef0,b28b32a9,265ab85e,67efaf4d,645c5b3f,d45030f,1aaea514,baba7069,91def89b,56fdc292,4b684241,6653b6d2) -,S(d41b35bd,421ef7bb,1c03c794,477c2851,dee92831,714180e6,6e57e735,caba5835,beea2116,9cf971a5,ffd83596,d9bd77eb,cb1e0c7d,506a45ae,be8c0c7c,22738f9d) -,S(96006d64,fac8f0de,88f93e05,da8e76e6,40afc1b2,8ee09a7d,5633643b,d89ee3e7,1404173d,e96a97e9,ae9bcad5,c9093d05,cba96479,30bfe6d1,96664d0b,13c93618) -,S(ad528227,12257f87,d1ef82c4,4af5f046,648c2a72,497651bc,2327e971,1170e7bb,2ea908a6,c742f542,324be959,4746ee48,4229d497,cc8bd535,e7989525,aa36f079) -,S(b4709a81,c067f6e3,93ef97ab,c26675da,6f01a2f7,e3f35275,e7089ea8,ad5644d6,f655b89b,d6a83838,ffd23f6a,fb944bc0,57fe7f1,1d321a0d,2152568d,91751d99) -,S(3b7bc8ac,5ba85b40,2080612a,84e0226f,3b43c8de,c0e54b6e,ea779b76,812782f0,8405dedc,a02825f3,5a60333f,190001fd,98ea3995,9dc6e61,c28c5e2e,5213fb0e) -,S(2a76b67,d197e7a3,7a38bb10,d49d523d,c4beb4a3,75336974,7e22e407,9e0310ca,6331389f,b9cf9fee,e89b089a,95abca6b,a3c2aba5,38725c1a,6848fa46,997d0e87) -,S(9938e808,77c2baa4,53e0256e,d250439d,b11732de,1abf7555,949a7574,f62819e3,250b061f,bba0faa4,468a080a,fee8264c,f72fc12f,2ac91dd7,13ed92a1,1b281124) -,S(7366eac0,7e5e4573,333291,3e42f111,e53a78a6,5069898,52db2355,de089230,b8dfda33,31646343,bfb60b2f,25050967,e735861e,1654f0f7,ff42ed9,5dd652a4) -,S(10fc632c,cab22fd3,2583599a,a2efaaf1,6e1b01e6,a5a96c59,50871012,33022152,cf53d9ec,c74aef44,7019150f,ddfde494,c2382a07,b2dfd73b,c628478f,7fbae0eb) -,S(785f4da0,240de52d,bb50b1bd,bc53994a,47318076,9a1fe06e,5a40a8e,e677ce63,9b5759d2,f77bbb9,e40ac169,a01500ca,6dd6bd70,6a003871,e7ba4d66,b32db9e6) -,S(a7f20615,593850c3,27aaa06f,c03e0d46,d3ff20a0,9b849810,1759638d,8cbb9cf,13b9ebb6,f0cd59ef,54e0f935,87a14fe1,2337e346,94f5e8f1,10323fbd,d7604d3c) -,S(cf083e4f,e0ed4444,85dbd99d,8e6823bb,483eb749,b94ce672,8671de8,6105aa4a,36eaa305,37378494,17050dc2,8290c74d,d9ff9df4,cbfa434a,2b89de00,e06f3099) -,S(9fb8c370,bca485d1,dcadc251,ee906f58,6f3e177,be37baec,6912e535,f5c7ab0a,df5cf77e,1ad07532,7150136e,7ebe7f35,1db47415,74444b24,e9cf2f4f,31ec683c) -,S(ff9e2f29,170dd456,2c94d48c,eeb0390d,db783702,c13574f,8a8c6a79,6427adca,784c7b68,3c824603,5077911f,957aa33b,47534180,d70a60d9,f248b860,736a24c2) -,S(802343c3,e07f9f9d,ed2ca436,3e455427,367b852c,d23ffd7f,fd690eab,90b4162a,b093f0c5,f0fc7d01,a5dfb7f6,bf9d90d8,8595140a,a13fbfc0,f7d6af2f,54ff5ce0) -,S(ae74ed87,11a1a684,9e558e05,47ff8f9b,f6337551,1dd3d272,ee0597fb,fc2d6914,c304897c,e5afb5b9,a383cb64,e85071a3,cfbb2981,93ea6ce0,55257ba4,cf15bec6) -,S(c099b05a,dceb601a,14892c97,7b267152,f29ea71e,fed6090e,7267249e,43c2390f,6c3ad3eb,8c95c72f,e0030a7d,34329945,fd1eb71d,8c4aa1f9,8fa4656c,6bef067f) -,S(97c6949,a25581f5,945814e9,9d590dff,67d936d5,94101005,4cac33d0,fb3658a5,cdc7faad,5bc387ce,a16a10f6,6971e5ee,6d32756b,596adc14,57081ad4,1dbd2e4e) -,S(14a19edc,a1ec89e9,524548ef,cf3dbc03,81b14b46,928f7425,87b11df1,7aa721f7,f83c4d0,aca08709,63a017b6,8db3434d,6088015c,2ff1d8bd,739fd620,35d1a19e) -,S(4742af63,c7597424,e6d04a8c,cb43142c,54c5b350,175bf5a7,27c39820,2187d00e,bb1f2f72,b21e15f,ec17af32,2147edfe,1ca80ac8,3e030dfe,8be39fdd,f340c56d) -,S(a6597869,4d168b00,d9df41de,fcd48ae9,68313394,db683407,330ffae9,f2559a11,6bf65c42,13317a5d,fb561e8c,872c8b1b,90bdabc8,8a8d2e1e,39919f8e,5043ced3) -,S(9e62e468,1e22abde,4d7a2fa1,2f7867f6,ecbfc15b,54990e26,821a8cde,fed76985,4877297b,a64fa8ed,c039ab1a,e62ac72d,8d7bbf05,7513d1,4237b8dd,9f1acd37) -,S(d24333b4,de55b0f5,d47c72e4,88cee8ee,8c960903,260a64d2,c89bca45,db7352c5,688b20b0,617ac12d,5be38fa2,ab52e785,69766a83,2d8b44d5,cfd6ee88,b19b9f1d) -,S(d203301a,13d1c8ae,a8c79007,1ef8116c,3916bb3e,dd5110a7,304b9145,465be838,a606dcea,398dc313,e61c8fbb,dbbc3874,3c103297,164e66a1,4412a21a,5319e55c) -,S(d1aa98ab,7010146f,16a9d6b,cd911535,2595bfa5,1bccb3d5,5e3a4a87,62666610,3abafa4,999294e8,80e3fae9,edb4206b,9b9786d,bddcaec,e2d01cf1,ab715690) -,S(1e20823e,81051b2,65535085,9aefed6,3631dbe,23b4e79,abd3c17c,21f053f4,e238adb6,86592008,f7fe34b9,9b934060,15c323ec,55981b27,85feae6e,5fde7186) -,S(d878afb8,8527a861,4b4276d8,fba39300,72196017,6f437014,980b7bbf,d4320ffc,7403107b,fca8ac64,baa94a4b,128e72ee,4a015675,845519ba,d5609331,1680e7) -,S(53f86d45,61deef96,ca88a685,38fd35ec,a95740a4,3a52c601,faaad0c2,aa3ab72f,667a6ece,bfb97682,c5e9e5df,b6d29156,9604f63,d9ab00ab,8cb10000,e6b01514) -,S(20990660,f1055420,b885fb0a,38824740,3b141c37,5aa20dce,8a29191a,e77bbb16,7d434476,9e302e38,9e14c02e,f5fd8a5c,64cfcf3d,e9813f1c,f53bc6d3,4da93559) -,S(1e70619c,381a6adc,e5d925e0,c9c74f97,3c02ff64,ff2662d7,34efc485,d2bce895,c923f771,f543ffed,42935c28,8474aaaf,80a46ad4,3c579ce0,bb5e663d,668b24b3) -#endif -}; -const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = { - S(8f68b9d2,f63b5f33,9239c1ad,981f162e,e88c5678,723ea335,1b7b444c,9ec4c0da,662a9f2d,ba063986,de1d90c2,b6be215d,bbea2cfe,95510bfd,f23cbf79,501fff82) -#if WINDOW_G > 2 -,S(38381dbe,2e509f22,8ba93363,f2451f08,fd845cb3,51d954be,18e2b8ed,d23809fa,e4a32d0a,fb917dc,b09405a5,520eb1cc,3681fccb,32d8f24d,bd707518,331fed52) -#endif -#if WINDOW_G > 3 -,S(49262724,e4372ae6,f6921b82,aa4699a1,f186aea5,40122630,3ea42648,97c2a310,1337e773,bca7abf9,5a2cfa56,9714303b,6d163612,a75ff8ce,c41b681,5e27ded0) -,S(e306568c,1a240c90,d5e253b3,e477e2f8,4dcc1a56,ff06db8d,1384b079,cebd2d31,eac6fe3,78934260,888f2b10,7f7d0db6,ffbc8042,be373826,692b4083,92546e44) -#endif -#if WINDOW_G > 4 -,S(3b9e100e,2428cefc,271b0e76,23fbd633,74ebf8d9,aab41dd9,c530c39e,363136b0,fafb9815,2d16bb71,df1533eb,8f475b26,a2ae28a3,3ad31f81,953ec16f,6cdbbc8a) -,S(bb0aad49,712ac9a9,2b76ca80,f5dedef7,17ca0768,8107beee,9608f047,2f485d3f,ea699c53,c5835479,8ecd201f,7297da34,895a5afa,31670bff,e7939250,3ca2f975) -,S(79090ac8,e4eefcc0,d4e8eb19,7afe0113,e1e58b4d,b01123de,4aeed33a,36718dc9,eaab722b,91905b8f,13d816cb,cd9aaa56,dd36afb7,ba9008b,963322b1,1cfae7c5) -,S(e77c81ad,e9f97b55,1c03dbbc,e549ba66,8dd71de7,cd775ad2,a269694c,7f60c7d1,3acf1478,eef81321,c5fc3b32,3ea81543,631470f7,1c2986d3,4ec581f2,82d72449) -#endif -#if WINDOW_G > 5 -,S(de2b5ce9,dbce511c,f2d8878e,3ded87cc,3d633dae,a2d45341,501fb3a4,55ccf6b0,f10576f3,d3c3e0e1,bbf717e9,8b1a3744,65b8c45a,c66318bb,34829eb7,11100666) -,S(d07bddff,d491a2fe,1ea59fbd,7c121217,29659ca5,de46658b,26b1460b,13c03c56,b2ad4708,cd3c97dd,f9c40e2,a1de04d5,61d963ff,8cc2eea7,6be3f60c,2b405ce7) -,S(82403e7c,5d3016af,3765ec4c,396ce8e1,f8da45c,434b8257,10edab41,bb6a4d51,d09661b,e27cb767,4456badd,b3e84051,99ab6ccc,4ec67c1b,11e92ead,7b463b19) -,S(eadc3131,fbd626f5,263faa58,c4caf4d9,930f933d,9541c23f,438cb486,750680cf,d3c977b1,c9b4a897,5c64b36c,972d5d01,a388fb9d,c3791a74,36094ff1,2c87a914) -,S(3903ee5f,6758ff24,c518a4b3,86748f4f,36bdd65c,b77e78ac,609f2909,fc7987d9,e92194e,a15241d6,40915934,bd234749,8d222a18,4927a8da,b0cfe2ae,182be83b) -,S(d0803b78,39ab48a3,8475bdcc,f9a9f219,5759c343,dbbf8e93,23e1f882,5be6a5d9,2cc3b180,ff29c97e,a12ec15f,b38bafa4,4ecf06c,e51d1d24,2894a926,64582f0b) -,S(1f56f096,b18a7499,a153a5ae,acf8be05,8496dd23,da8e6c19,215628fb,c0567ed0,fef22b8a,3b52f490,83004436,b65cd69,c94189f4,1a93c0d5,1fc13cb4,379dff58) -,S(1d9f69b1,a4a47432,e386f525,234aa30,79e947cf,cf203297,4e0fc05b,638e213b,d898ec17,949c0761,b38500c3,a2b1da24,5438d5b3,d3f6f720,41f15d6e,e4d4ccbb) -#endif -#if WINDOW_G > 6 -,S(128c913,4d9dcb78,12fc4361,5c67ad0,55213354,dc8008b1,aeb5a9dc,fb629efd,fee3e54a,dd152610,d9725936,99d662,c160c8e4,ec6f76e4,5ff41818,be67c96) -,S(21ec012f,5a95b94d,244b8d51,9756075c,301f2854,8e2c51fc,49c0e3d9,d1a9685,2def2105,77af497f,4c7fef71,6949f28e,7418eda6,fd5fc162,d128de19,3cde08ae) -,S(688f5202,fb9d8bc0,9e480e89,4c7cfc74,761c3be7,7dafb11c,58422836,3e331cc5,96ba7d59,63b541a7,2ec7cabd,92403434,1a393eaf,89eebd94,62d9c218,c7302cd3) -,S(fb5c9eea,1cb9a8f5,b3314c30,a50d35,744d0ef,e8bbf68,2e4d3ab4,f7f02baf,29fb8844,e18fc551,fb28bd26,95c5e95c,6868e0cc,7e526af0,91157e9d,fb630418) -,S(f1479fe2,2eedae3f,2f5f6a5d,84a9de1d,593168ec,7b52380d,e0b3625c,cac03421,1a642d5d,2fd88b82,13b50d1a,3fbd3419,c0b4630c,48352131,cb856b2e,22764606) -,S(2273edc5,e8199774,93c5b0e0,9fe0effa,f60f7b,2898565a,69f5c7b2,bf1a7950,b3aea238,8fd978d9,29f1a1df,98495358,b64691fc,4f50b530,906ae39e,fe7bda12) -,S(99f8480c,30504378,b47d10b3,2b39da2f,496d59f4,b1462856,56f05ad7,9bef5214,e001d55d,8e224286,8d8bd397,cb5aa99e,d930e437,e4e62151,71da7ae6,6264b2cd) -,S(382257f,e4751280,d74fdfc6,993c8642,9c000d5,87f57635,bc9656ba,996a6f1f,c2dc733d,fe52cb06,265a4f1d,a6b5f1f9,30dbfa39,e3659973,1c672aad,8b51d474) -,S(23a13632,9125386b,e45f4e1b,2acc847a,62e5eaf9,f6d5f452,6e145e7f,ecefb24b,9129777e,643ba22,2bf817a1,af7155f1,413cc370,3734ba6f,49f15f55,996854c0) -,S(6659ea60,58a664de,a35791a1,8c5cded4,8cf5593d,c440b9d4,8a30ac35,79149f0b,2adcc705,a85d836f,b347b69e,742fc6c3,5300d1d8,e534f1ff,c820c6d6,b2f2199d) -,S(52dc3bc6,e1acd3b4,7ece6f6c,89fd2a3e,2899b487,41421033,37a67dd,1ba939fc,5daeb346,32ad107f,bd83d9da,15a3c4ff,1e8f6ba3,ee5193e2,709e89c3,43d05746) -,S(524b2a97,93cd5745,bd9189ba,9c947bc1,693fbceb,75f074f6,17376b10,d5573551,9e8099d6,cb23fb1a,9deb92cc,3e8a2fb5,a6865ac6,3dececa0,2d146e1b,bcc80b71) -,S(732181a8,e2bc5953,923e6c3d,d960e9b7,525b7b95,e5906997,6fe79156,1782756e,2516c6b3,5592eb0a,42ba193c,bae98ab,e3c42d96,148f1d84,edac621a,722e4823) -,S(b8e8942d,926e38fd,f338496a,c2ef6fca,49a7ae3d,f76eb15d,8d570111,e502664b,7990d56e,7dea588e,4d670ba2,2031e6c7,97248641,69e51d77,f792f5ed,befaf8eb) -,S(144e88f6,3e73abff,72cac11e,7ddccf79,19e744e6,278941ae,18d1b797,e098e4e5,63cdbf3,5df3c655,c58197f,ea54633d,158705cf,7dc2eb3b,4e09f83c,3021837c) -,S(9436e3dc,489ecd8e,2d16a739,c9c73e3d,60e5bc93,68157039,75b8efbd,5c3a9081,1460531f,50cb6ebf,d1aa7806,ea84e7f7,8e8d76b2,b3a66d5e,3a0bf60,39a7e59c) -#endif -#if WINDOW_G > 7 -,S(9d3c2561,7a56d10b,46d9b01a,1710d193,e840e005,df669e76,1936c275,20890db9,6bbdc0bc,4c4ae9bc,c2dfee9b,82da9b94,1f89ffcd,e8af2aca,4467ce3,78521ea3) -,S(29f98e50,f51b7f8b,e18c6ae0,b453c4f2,d0aca5a8,b0e61d2d,dda8506,3fdb76c8,daf3bcdc,ae8e031c,73eb8b21,14058063,58a6ec30,ad379186,df80e3c7,f0e5d28f) -,S(d67d30c2,c71daa36,1805e31,1dd6046e,17a89752,94d76e1a,538af074,4dc22c94,48b9b0e7,12c807b0,b92e690a,a2e068cc,e87ebbbe,aaf4bd96,9c1114bb,a54f670c) -,S(f22c2ba8,8ce9c2e4,b772c9b7,6d03a017,59aa7b9,97a78334,83566027,2fc81649,6aa9e710,f190be16,243a4e0f,1570270a,2d92dca9,8cf99a3,cbc06fdd,f9b7028f) -,S(c5e718d,6b94c83,e52533c9,ef3234f,36b722ed,cfc074a5,eff30969,9ac5f894,24961051,ccfc6619,dd64e810,fa9c504b,f7f8ce9e,cc445d7e,642b3166,eeef436) -,S(26a8bcaa,c836eb7d,57618999,ef87ee4e,c291dc8b,333554a2,c1f66f73,7944d611,c20051ba,7236663,ace2da29,c1e0763c,e57192d0,e199e7a6,c69cc65d,bbbcecc9) -,S(388e3570,fb7b1545,9bf01ba1,7a6496d5,6bcf65e1,764e7aa,2c083346,2dfa098c,2d4e0d22,a2eb0ff0,545561e5,ae344be6,99120d12,45db6bde,a9500f5f,a07be798) -,S(68189bab,b5a0783e,23227efa,4eab2c6e,da2d1c,2ea57fca,7a7f8f72,15250709,bd30bd83,3694d3fa,a14954f6,251445f8,3e42d517,30d30855,a0eb834d,3c7ae856) -,S(642e0823,bb347795,967b7aa9,418a25,ea6ff683,fd7b3d42,b88d90d1,292190ab,db73dea7,86ec052f,e3674892,639daf39,286b4690,63b68903,210639c7,f3b4000f) -,S(9ab6ea81,e5bf5505,751addea,5896afab,7f4eff2f,d3986027,f916835c,64924afa,38c06aa7,4870a5e7,2ff29efc,bce4b3e7,dd951c9b,29966f2b,47d007ac,7629bb6c) -,S(b09805ae,e567f69c,71a98248,e89e64f9,e059e015,bde01a62,dd18158e,e94a8ee7,62aea16a,7ec912ef,cc5382eb,6d220ac3,dea885a8,e3da12c,8147b28e,1983d221) -,S(3d632a5b,636ed5a3,4a58bfbc,9831691a,91d6b5f0,975bfb5a,82b4c1bc,107e6e5,577a449e,75bf16d9,2eb6ba0f,9cb4d496,7a7ee09c,f1605aef,682cfa31,cf395a1c) -,S(6b821bf0,f70d5ff2,ceedb69d,d96ac8bb,b51e3635,3a36d50a,b1c1a697,40cef707,5212ce11,993fc120,88028674,5cddea94,6371b4,dfa2f47a,6d83b789,c6d12e5d) -,S(bf294951,4496fe0b,8527740b,5cd9394e,dc33b330,c91d996c,789db854,45728b23,790aede5,da35ce7a,343f745c,410de38f,4c53bc2a,bb41bbae,c13272b1,e912782c) -,S(a55354c3,82bf968a,16668267,c4498946,4906f69b,114f6f06,742b6035,1d75ec80,2809bddc,45661a5f,28b31967,6cdfb5b1,9dd6d296,d1828c88,179a630c,ca5962e8) -,S(fc015036,abcd8311,bbfa1574,ffb4980f,b893f8af,84f519f4,5a6fa344,2649a693,d0f6a278,1946e04b,385cd004,29acd3f6,f5542aca,3e7c789,657f676b,f19db819) -,S(6164410d,9f81f352,272a799f,b4afbe24,59caea6c,511fa4ea,b7578980,d9a7aae,92bc1480,ba19fcd,3cbee69c,95b9396f,4982fff5,d4e7dac0,abec7153,ee5a7966) -,S(ef816535,8de9d737,728f9a9b,3182b4f5,6e25917d,1ec05fc6,faa0fc85,170b5f2d,dc372426,403ca9c4,50649df8,8b6fd32d,f1721dc,cb1c7d7e,155c83ea,747ec595) -,S(428c34b9,89a436dd,dc704e68,170d2c40,178c5646,841eb2e2,642c0a48,8987a8ed,b1f24158,251c4646,ca04dc3e,64369634,3836f97e,71945f4f,51237abd,3aeebe06) -,S(6eb61782,f909157b,415e6243,7bebbd6a,5f19da73,7eda64a5,5acfe206,65417a9e,4fe7c546,baedf2b1,6c92f168,f99c42f6,af03edee,290ecc39,4c4efff,e8577b72) -,S(992e0af1,466d4fec,5ef83009,98ce31df,cb6f9573,d14c1646,e4371c62,a376fa4b,d0e3da69,1e4396b2,eb01e3a9,964365,50d000e6,31d79ae3,871690d5,29f9e825) -,S(fedb564b,adc70078,f20f31d1,12496934,513e9903,8cf5b9c3,1084383,5721d11,1a8e2a49,57e8420c,f2d5d97d,657f1602,ba26ae87,d5408b2f,a9448def,38157a39) -,S(f3f2068a,4dd89d18,1247088d,3c424916,3e683226,6274b575,e54430d0,73b24bd,f2aabd19,a7f462,1426ab1e,e0aa7e33,12381c5f,e1f1cf0e,75c1a7f7,7ba2bfa8) -,S(32b9225e,4217a359,8de4e7c1,476a8581,5b6aa458,d93dae02,b3d30772,3ca13680,7466e804,26856340,12985683,dd071e97,53246214,733808a3,96f35d0e,5a133802) -,S(85008a87,385ed6b0,4ff89979,2eb592f9,ee6c6b93,fa24dc7f,c6299b9f,dae64a8a,1f279e2b,8a5b0576,fb9569f6,c0825876,84b5b38f,a250e362,2ae6e284,a504a2df) -,S(4dac7833,ebbeab0b,ec8edac7,cfc49bfd,b835362,f0130e9,e44452f6,a82effd4,fc9d1970,f230aa68,6114ada5,7b4237dd,133dc3b5,db8ec1f0,ccd09aa,23c740a) -,S(9b755881,45a65d54,19b40226,e535df5b,4b44de41,1b93d71,31f3102,d56dbeeb,d0324171,d6937b7,c9b38290,7dbba3b5,c1516061,59e7ce1f,a1ed9d11,e089a02d) -,S(1bd6ceb9,2592a7d7,a66e6e8b,1b645db5,98b525ca,461dc4bd,b583ed9a,cbbc8bdd,9a59de87,84a98bea,48b7abb1,a5b7055,5a1c4ce5,551cde4e,7b790ac4,9a29944c) -,S(25a8b2b9,3b360941,6525b08a,7fe786e9,6b3a3c7d,8b444637,268f5355,bd5b56ee,3c58ccf7,5734687f,dbd027e6,3ec6c550,45f131ae,df71a40a,c45e4e8b,965f22ec) -,S(244b2833,27c33efb,221a5767,15225d6a,bf5a1caa,8da543c0,d88b21e5,17ed9f5f,220036ac,e48d8953,5aecec92,a29f5012,37f83ce6,44380db,c229f0bf,c1f53d7d) -,S(6f97ac0f,27b87905,6b442d13,e566978e,91f0cc1d,d6ac1e64,e9764a35,325dd1b7,83c6e70c,fac6c707,226ce1cc,691b38a0,7e937f5a,5f2d9c81,4dd0d3ff,9f433d32) -,S(72c5d60f,eb014e2d,ba8265ca,d454f261,2d6abcd4,b2236bad,c94c4801,561dce1f,e3119a19,7ef91963,b3b28216,3c5d3acb,97b281b6,d246cbf0,690b40da,63978fe2) -#endif -#if WINDOW_G > 8 -,S(a96d2da0,1b10186,6998659d,f441a1b0,2af32b94,aae8c6ea,707d9ed0,d5f33825,660d7d83,5da5235,9f7cfd41,28c370aa,5659ea71,16a91690,6c0e8108,a513f9f) -,S(2cce6f63,4d815ecc,1981d200,87616677,d906aa27,990c4875,17314dc5,5be3c4fa,615210dd,bd599e91,1b6f997a,fd05475,b33cb274,c9ecb6e5,d3c23323,beba4b50) -,S(992b0084,525dd399,d98602d9,8b8d53b2,4558fafc,758a2f46,60e89bd6,a645f0c4,83ca98d2,26545a29,8c45f40b,11420602,f5a5c70e,595eea57,2da64d61,a4e2f98d) -,S(434efb45,3089619f,cc761ee4,3fd4b77d,c6b0c69e,b45eb88e,44ef766e,9beb7357,3dbb0d6d,1c0b92e,5965586d,236c0be9,26967ac8,830b9bd0,1e9efc2,2a9291ea) -,S(a2179ad,2c683306,a2e4735,93efe304,f0dbf589,c4dc2b88,4bddc5c7,e3fbc156,ee4539f8,ab980176,a18e6dfa,bdb609d2,88a2d223,86dcb20,19207afa,f6033c1f) -,S(3934081e,d3e1e147,aa52bb40,9221ef6,a445f22a,66718f14,6d63907a,ef05a2e1,bc370656,31391b7a,209e79d4,9f1e959b,d3a9fefe,752c6062,14fab290,a7b5b3c7) -,S(35bc24e1,59a2b939,438354,6cc4255f,f1f3f7e2,105293db,39688e07,df95d8ef,dee1fc70,a9698da,f7abeb5c,56724f8,e87e0cd3,8849edfa,246ed0a8,9223ae15) -,S(f5d1e75c,251fb473,8552a0ee,f05d8e65,63aa14e1,bcae5b48,bc7e5258,b948127d,e260c1bc,7044f058,8f409134,d298528b,e7d586f4,bf7b6fe,92d212a8,6f7170fe) -,S(ee0a76d3,6fed282f,a1170dd,6acb7743,f9617bb3,60350f54,d12da1cc,7eb121c,f8cfc2db,eba6960f,e6135ef,ff9e10ca,4e56c458,4b42b516,6dbf7af1,420ba5b1) -,S(9e3b87cf,78927664,15cab377,f1774d14,4d1879f6,16da5676,f94790d1,9ca689d8,f8f34522,da3ca2ac,b273b0c2,b1b1f26a,7a9c2d96,b4547482,266a8e6d,bab3b577) -,S(e26f256f,d08942c0,3c85b89e,e66b8b50,12f409c7,4f625152,86e5b310,eb4868f0,bab3c4d9,6fea49fa,6d08c656,23c9b127,3552c23f,3c4f12f2,1bbe8bfb,56f210f9) -,S(8ac74046,a5d38398,d14b6763,4f07abc5,a3f5c852,ea8c421c,f0858980,11da6c2,d20ca793,f56e3198,854f5916,35402c2,4a71af95,c84288e,1495d324,7229b3dc) -,S(5b00e095,634694cc,93d531a8,6e81d29e,753928bf,b2c83a83,ac677a92,55932bd0,8d2f267a,8071c48c,616daf18,d587e,42882b33,748032d6,4bc3efd6,60a99656) -,S(162190c4,80c5d7b,ab1ae4ba,7b2a6611,546ffb9a,b4e9ea87,2c0357f8,9e11f0b1,db5e2104,12448a9c,e586d7a3,13bdcc6d,bb84192e,98c5d9d8,79693030,92423525) -,S(f6a84421,b4b383e8,87f8520,e06017db,476774dc,9aff636c,f26a676c,85b145b1,504c71a9,596770ed,7a2da8,2e8fe1ee,93717215,bf88e0a8,ed74a80,4037a3b3) -,S(1f02d142,f0b5d3d8,b3f8937d,a49f908d,83e5919e,55c9c134,55a759a9,932dd6e5,e6a5cb33,8ed36df7,50ec2eae,5db7c9ff,fbc9035f,48ae0348,fb3882da,39863e65) -,S(61f4d96b,c326a1fe,a2ae38c3,73484a56,68e29bf5,12d77a04,34a62278,1d78899f,651ef738,62005ac7,64f97021,6180c25e,2172724b,375e6b38,b3a37ad2,d7b4aab8) -,S(ba7d5c0d,623c5e79,8088a71f,8d2916e0,7c7ebe2b,1afa19c1,9c917cae,31c11616,da409f40,d7e3f6c,78655153,fb35595,a1ec37e7,e66c8958,ce45b07d,bd5f5a51) -,S(8b90a590,eacb977c,6e6a68ee,6dbc3e19,fe5a92a6,9abc43c3,bb16f9d1,925bdb09,a5cf5f42,ef655d59,ae734e1,f746a752,4d01ef75,d829b9a9,2a035180,fb5df718) -,S(87f35227,21914cfd,ce8294a3,cb5ae171,f0d994ff,f55b25b7,1c9e9aac,dff4fe4c,cc71d1af,530bc5e1,eae7c1ef,b9a91335,f26b283f,222a3552,dda24c28,64babb2f) -,S(aeea4d36,ba405159,bf0ffe8a,5530f1f3,83d5509f,187ef58b,6c1eee4a,cb77a15d,db563dea,e7403df8,7d3031c2,48aaa28d,96958f7d,ce36b3f7,8d55607a,60d3ac1a) -,S(300fe98d,3996eb9d,57c6f1ef,8058d4c,d8dda436,5774edb6,2a338a59,afcc7111,d148a017,8fdda40c,f937913c,143b76fd,d2e6e226,d27225e3,a49658b2,38c40e77) -,S(c700af5e,22cd146e,839095a1,f6743e4f,d01e9c1b,76d4c73a,a5005f42,99c19fdb,3fe00181,b1f01c27,27ab1fc6,bb6ea569,d4a3092,c2d511d2,8b5546aa,194b32c0) -,S(d03d08e1,17b94138,1aa147af,38448539,94228f75,f96bb4a5,941c3748,cf50bc60,5b119ffd,2785bcc5,2e0bfbfd,c541da8d,f47dd076,e91440fa,10e071b3,a896e31d) -,S(6c6710fa,17a520b8,56d7fadb,6af81a5f,ea9c983e,c94cf832,b395da5f,c22bd361,db4efd26,36e281ea,419964f3,c0897b05,b036a408,25ed4ad6,4fba393c,f2804941) -,S(d7b5c239,9df47a16,6b6cb900,d08a5d9a,5ea3bfe9,94f861d9,b46f3fbd,a3d91bbb,ed791f4e,4ab1c25e,9c83494d,794ffe1f,a3c8a065,29c0b710,cffd597d,64efe8ba) -,S(90f699ab,8f728152,e2deb8dc,ceaaa3ee,53ff2f23,2341a952,4aba9e8e,50f66c06,8bd0c3a7,7f5312bb,9d46d80e,c36921f8,561558ce,6e63c08e,641c82c9,fefce91d) -,S(4d0eae3e,3d7adc34,c91eaead,6a16f569,37557dce,2b68744a,bb9ae71a,8dfb65cc,816b0806,a9508731,ba99a685,142aa52e,6e874c99,5096a53,52c6e2f2,1fa3de5a) -,S(46cd9edd,ec318498,dfb4f815,3315185d,689a2399,8e06b1d0,2438f7c9,b2f7de62,3b5bc1a3,d5fd7874,8c964a8b,b813388b,e0d5d168,1247d008,10a846fa,561f29bc) -,S(4aac80e,3f6eaab7,1c576297,b4552e40,653748fe,21a580ae,bce4eb83,2ff730b,3d42a00d,8014f46a,80fe2dd5,bac6a046,40d331a9,4f1de050,9e435398,6c8c7954) -,S(59bea661,b73d9c09,131e4573,199937a,e03e96f6,2ecbc637,4bb681a5,582a4114,31a20be8,ee8a2c2e,81d062e7,8e891504,d9f2639a,bd5db5c1,30be3d2c,b1afa47d) -,S(7fe9065,88b2ee92,2b19acd3,fec7a4de,9ee089a4,a4e1c338,5e293567,90ca6037,dfb45d90,c5f43eeb,1f5eb326,20763ff4,2659b763,e7ec72a7,c69e9369,35e5c128) -,S(db390f91,32277889,784b5e4a,cf8f2fd1,f3a5fc47,f2c8262f,19dc9518,95322157,4364955b,241c831f,94fd7d4,da63db19,2aaeb5c0,ade82dc8,d5d61cac,d690bbad) -,S(34dd0266,e5fc19ac,7daa9e61,5ae8f78c,985732a6,1c53c29,e6e5d407,7391ebc8,c2d6b6d8,e73fe00,e6013b1d,2c2b48bc,77a5db6b,45232ddb,6611ea1f,c5dd797b) -,S(eea7f72b,7e31608d,d3dfcfbe,16e2ef95,5e6c7ec5,328f84db,336e3df1,9d1772ab,9662c8f1,ccdea4c3,48ea6d94,739aa747,17219556,c6be9b8,8af0d30d,514004bb) -,S(c6af087a,f1b10eb3,93de412d,de856129,9376d264,36d907fc,10d3e7a3,88c391f2,ba99d62e,31856457,8ad8847a,9cfeaba5,e5ff9824,2c614959,eeeb4ae7,50825144) -,S(eae34735,6c715740,ab73d034,bcb43f5a,aff37fbf,50d35518,1364c999,feccefc7,b9386c75,da8bf645,cd6f15d8,4944f74b,9685256d,b61fda98,79fe6639,92fe4703) -,S(4a548c25,f4d8f54,4f9a27e,64e49626,41b68ae3,1d90461,65c24ff7,fb40438f,ae9f2c85,bd608cf6,ef5e40c6,7e29a63d,4c274215,c2a0d578,38252f28,196f6d10) -,S(61925679,dd6545a8,ea19743d,7cb3c0bf,453318d9,e180da53,f43af2b0,ecf744af,a0682d84,d7215372,e9ec062c,a3e4aa1f,47fc551d,44e3d1a1,7260a44f,2bcb184d) -,S(e1db5e86,9574ab76,d4fa260d,2425ef62,50267ab8,52ff04fe,25f0150,9137ea2a,c8eaf421,9fd5f7a3,6c1a99a1,d0c61250,836e204b,fb496774,83f43c81,511905a8) -,S(3062cbca,73923842,2a0ab862,a1fd84f0,38e63691,cfc204a7,d2f9d263,d248c7f1,8f112e57,e3f2970,dce89eee,1e184310,721a85f1,cc9feb2c,f55c047f,dd9670cb) -,S(67c393cc,aa9736fc,eec7a861,eb53f953,9da74ff2,97764f4e,4e814004,4da4f739,93d329d0,9a165fe2,2f8009d5,ad59b524,33ac24d5,46c7d394,2d147c4d,49853203) -,S(c67471f2,36cf2187,ee5a5619,d581cc7d,ac5bc5b1,e8bb728,f943084f,e899bf5e,75c90c9c,787b318d,943c3247,74cbbcc8,3a533f37,fb684aea,62fe6848,8de2c513) -,S(d5015fef,d5938dd9,2133d7a4,25aaac5,12143acc,6547070,1827e98a,e4ed1b52,44305616,a02236f1,5c37c0d6,51d845dc,e9966860,b798f79f,4006c25d,7cf03d6b) -,S(aebcbf65,aaa89615,cb48ed56,4002ed9a,243ca309,1cf503b7,3c1929ce,8164f2d2,4fc1f25d,1a30ee2b,4220305b,a9c88e86,a6ee7f55,55399ee5,35e7d37f,e4b3f019) -,S(15cb1617,1727deef,49ad6821,932a39d1,bb8f980b,b5370d81,5ef00ff,ebb30e43,64ad8c82,87fc053f,ee35c1b9,9734b34d,2dfff86b,490ead93,b1fe7d2b,f80ebd7a) -,S(d404209e,8530d674,9bb88a5,525211a1,19fb2523,63e2698,6bd03080,4c49c123,3763fd68,fdb85d19,e8506275,3b5a327c,46ef87be,8a3432c5,62bcc622,40a7a128) -,S(f3abf8cf,c232849,58e330c2,fc327ac4,d40b4497,f422aa4e,d42e9381,9bffdd96,50861f05,d831327c,3e907643,2d7a7621,d1dfe9ec,7ccf2061,cc720e9a,7d5b0d5d) -,S(78a32893,2ee9dbfb,3f84755a,651b9d23,5cf92b46,c3e4bb4e,57b7ff6f,7c874dea,925b783a,966721f4,6eaccd87,495eab7d,b3c36eb2,92c1a473,b4617f6b,9ac85895) -,S(8165210f,5d146f8a,1ac1ed91,a7bb678d,1b7d15e4,3ed55e8d,f6503209,a750cd4a,fe390d3a,19e22bdc,cbd45875,e396c713,85954166,a1edb63a,384b8587,915d260d) -,S(75269de8,6c2f3d34,cdf17dd6,f3efa198,ba73431f,cf0072f3,633ca57f,7dfe3f09,b162a65f,d19927ec,4446e3db,d5ee8850,f463f39f,1df1a0b1,f5ed153e,704805bd) -,S(5e36ce8f,b393949e,5b9c4e10,44fb2ff7,c520a7b7,a9016b38,9544e512,427145b0,7c40e718,292f96a4,1d9822ce,d54aea90,22074c5c,c82ba4e,7d39a4e0,7811614c) -,S(c8cc7129,fdebbfc6,c0576edc,6ac983e5,c249d360,76da7d25,b05c0b6b,16632746,48a8cce3,a77e4498,76d1a332,c539feba,2653fbaf,d4f75e68,e4674d78,4c716fb1) -,S(9fe1db36,f1ee3e6d,3924d2a9,ae3ddcaf,fa85798b,7383a1dd,2d6c0c14,ea46973f,1d35b6a8,607045c0,95ed9658,80212b63,43dc55ec,beb3223e,7c2e76ce,2c74f6d2) -,S(4ca8ab8a,3d45748e,6e19e02d,dc351279,e23648db,d26d2465,7c9713f5,bc8ecda2,8a5866ad,9bb7db92,273c9f23,c0876c95,13b8a68d,bb20c5cf,164a9a39,4e3e73da) -,S(c8d0150,e4a989ec,5cdbc724,21b1e29f,f1f30818,1d8117b1,3d376f58,b72060c0,5c5880a4,c5a73a4a,1ae42a9d,f0b20032,7ac4a732,cb26e717,49e63365,5082ebd1) -,S(3d61557b,b4b9fde6,49fe1b7c,981c9883,9e368444,f130bfea,fc1e1a0c,12f2aa31,933167ff,62cd840b,3a960c90,e6b1c37e,1e233695,318ea286,71c87992,de5b56f9) -,S(67569f9f,fd44ca09,5b478dbb,85c3ed1f,feaadaed,cb624552,ccfaf169,24e69e2a,62bb2948,230fbd2c,aa941288,7adfb24b,d16619de,af0fc102,feb1b26d,67eb7fcc) -,S(6313d13e,debf1401,eb7d279,2c66daa8,6e3075d0,3cf0daf7,f3b753e,7372fbc2,44621230,50eb1245,86975455,63e06e2f,2839f874,beaff9c2,f65e26ad,d3573ef3) -,S(6f8ec9e7,fbbe6e8c,d0e3085b,47c6cb2b,88529f2,15f13195,5e2fde24,4dd23968,1fb61e14,523b3fae,b543b215,dc46eeeb,23e1950a,8301c78d,c510c76f,ed36cd79) -,S(56613dac,3c5aa1ac,bd9a0ec2,f839b4c3,36f0ae58,e0e02244,7bec0546,710b7f6c,247263ab,86c398f9,3b23319,4434af8b,530908bd,dd7f716c,f7b73aa9,8eca79e8) -,S(c9de15e7,b4147219,137e6e57,c5a7ddd6,17e91ab0,6859dda0,41eb3c21,87aee08c,c7178ea5,cfa056d0,dfd11c87,715591cc,40cc5db1,f5e4b70f,d8ffbfc4,3f8b0009) -,S(7590a4a,627d5e90,e42a4b0f,6be6497a,f906182d,d2dddc48,a8b6bbfd,f56c0504,d611e21a,b5498760,5c97e878,baa464bc,cc5bd875,353b69f8,1f93ce2a,a6c38587) -,S(94b1da0f,b310e056,db0dff72,81db3362,1fcc555d,bf3c973b,76097908,7fe19d6a,8318893d,d5b41a56,33a2ab4,ae4b953c,45c42e9c,8f2fd159,85286de3,fd4fc217) -#endif -#if WINDOW_G > 9 -,S(b5af4299,bcdacef1,e07d081,daec2cfa,d6f8f821,38e151a5,f20e6d52,84c9a6cb,c0984407,8a7db82d,f572987e,b137dc09,c8cf65fd,aedcb20,43b2479b,ab95448d) -,S(5f49ad43,70744587,3980a153,c851829b,f8ef6141,9889bb0c,3c476847,6939c3e3,5c40d385,20f56c3d,ba08ae1,b40fc24a,2ae25c94,45cae0f7,d01d1800,747e04eb) -,S(f6bb067f,88ccc11c,64e30d1a,e6893942,16bea3bf,26ec9c64,5cde1b9e,487da385,315a476d,7268978c,d89d4ec8,adde4a83,28dbfdd9,f2bf44fe,ad4ed721,78288f55) -,S(7b47cede,c02b19e0,94daea0e,ec000455,52690b49,44b3f10,beeed2bf,f9df6950,1bcda5f4,9beedec9,6ebac5a7,957918af,53b7ccd8,c211330,280ed93b,e0efe9a6) -,S(ba69d7f3,82d56d9,eb65e1ab,2d70f52d,18223621,c0029035,a78fd660,9940876d,5f44a2fd,56d5289c,f36bdb9,50ee2538,1d1cf935,ae1aec76,84b6d11f,975d393d) -,S(a3b70894,d226c195,223713bf,330ba39,fe7ec35f,9743347d,1d3dfdb9,7bd929ff,5d0cbdf,42755aa0,355ad2e1,ab39479,495edf2c,20bb0aa5,93cc04cd,56ae6135) -,S(c756e23e,bb2d81fd,91fe73b5,20eb3bfe,5ae602b3,448cf84f,e8da37d,d1c804e5,89f4b6fa,edf86b9b,ca9f52b2,9864a982,5a4faba9,d4fb35f8,98511210,34df49ff) -,S(36327c35,6fab94ab,f791c234,1c39049c,65410e9c,6cdfaa00,d172ee84,3671822c,fe3588a4,698c8d35,f0e01f04,e94f7039,eb745631,8c25927a,be7d061f,d3ed4c6d) -,S(3b75bfbe,8e372311,f46ecf6f,c5eb2af4,b66051b1,874b0c32,1189e106,37dd21bb,b9144a33,e3c3339a,4595e248,87940b4e,2e42a095,d7d1bc2a,ea50aa29,5a879908) -,S(44a61f10,57b4e88a,c55ed72,1f8f4477,5f0272bd,379a97b4,d92a7f75,f0d3c5e2,e870ea65,80340464,9716ec1f,5b79392,18162306,6dc14086,111de144,82d80141) -,S(11ae02f7,663c0a,24c6fe5,ce9206ed,1ebed2e6,ca294acb,74c9a227,97fefd,635a1b87,a262fb30,5008737a,e70422cd,a4e35766,940e424b,d697d28c,dfd6a36f) -,S(c751310a,dfb25d14,2e6ab1b0,ab31b37c,8e987af2,105d5981,69085ca,3e142f5c,a4630dd8,ed2717a9,f10485a4,be685c5a,ccca851d,4bcc1886,4df943ba,ee821014) -,S(fff4d7c6,4009f39c,41757b17,3eb2536c,a639b72b,e15af7f,790bddb7,efefe46a,694a798e,ffe22d1,1030697a,292a4bb1,4c110d6b,dad7edc6,e8976450,ce5080e5) -,S(7d76ea39,c13c9f46,e931e8bc,1cd43707,932b1a,31254d18,c06c8ce9,c3f90534,bc14b2ba,8f0a3d8f,34c7cf7c,3458c916,4cee438b,39a5a6d4,d2a1c9fe,8be415bb) -,S(b6efcad2,ca6ae4f3,6f080707,530aaaad,625fda5e,825f77e8,a6730e95,5e07ad39,4868d8ef,8a56d327,3f6f4a3,23ea6ad6,4694301a,1f6405f0,a421939,bdb1c765) -,S(1a04b12a,a889c4a6,d37f9050,e75406d3,48e38faa,c0d2ab4a,e30caa6e,3633a32e,f43a0c8f,fad38d90,6c817dca,3e7ea09e,21e1c801,7af86966,c246ebc8,dc75911d) -,S(adaeb0fe,9b345190,4e878b12,6c8edddf,b70e2500,5a4d6a6c,531aad51,83209b7e,2b26b16d,dd4d29a7,8cc6b4e,198e6ede,b1c59def,c6793173,f33cb039,d37522ad) -,S(4e4ca02,3931f3fc,b512121d,2d632764,d97fa125,8460d0d1,9a94eb88,2c6e0679,ef90eecd,3704a6c9,454c6860,928eb332,cc917b17,f2594348,515822d1,84537467) -,S(a1f3c279,df69c13a,711b5ee4,139f603b,5654ecac,adc02a22,a7c2087,c11e2971,57249794,54cb78dd,7ef69916,5efe2326,e8aafad7,a8a923b2,252523ad,b6a16b2d) -,S(aac76f81,488668e6,f4b0c911,bc9675ff,c19424c8,6a6903c4,f4b13e0c,e798c7a5,24ae16df,dd6c7d6c,1391df3f,73609bc2,c3759536,eb277189,588a72d1,84dd2978) -,S(70e94171,e59622f0,de360166,6498e6c9,ddce496,a15e30a2,a5bdb701,d0034769,d6d7c0a7,75a9cbef,2b84d4e8,200f92a,446111bb,cf46a57d,5e244f1a,1103b757) -,S(ca17e5e7,11d44492,496fa849,c6ab1c47,3426706b,5b8282b6,f288e096,8ec78890,b3ddd632,2ce577b8,ddb9f501,e17d32cc,e6c58fee,4e283410,5e32f3e8,8bce2c2e) -,S(1a16a58d,8d70fde8,6ac0700f,3a43ab9c,255ec001,8d5fe571,7ec6324a,2faa62e8,f2cb2eba,65aff0a3,dd7bc137,257c1d30,dc2eb6f3,7a3897e1,16c0eb1d,1a710c27) -,S(8f2dde65,b4ddf10,c29c6bbf,5ab2ac11,2dd3357a,e3e5f01e,98190e32,94b9d4f2,e06b8cf7,e5a736d5,4e954bd,8591f7cd,79df335b,d3279f5d,80493fe4,df4c6afb) -,S(3314b553,f8213e7c,80d4562e,cdb3564,ba1d7285,6c88d8c5,a3adda90,4950162,33e83c5e,e3f7c550,f94a7434,e3cad51e,b4dab462,13acc24,fc4aa1f9,fc43532d) -,S(7c107ef4,65ac0c2f,fc5b11a3,348a7cc3,fa589554,ee2b6606,2af3c5ba,25304000,6b5bcf12,2e8a0705,d067fe78,e56d365e,89b5a979,c23f124b,508e63ee,975702c5) -,S(e918a829,325adf67,511e257e,e5596d08,19be4605,36b20cb9,7b76a54a,5be4f8b3,1a92f0a0,b46152c3,e1ba8f0d,12119c15,b70af0ef,3ff0ebf,a9dc9207,cf2fa8ae) -,S(8770da03,d4f3a4b9,e92dd2e3,be309c81,c346c97d,2cea15d1,e3fc94cf,41b9b079,d025430f,dc633d57,18d372fe,64f57fac,53f96461,1fb5005a,10ce842d,ab123c03) -,S(c6b4ad3f,ae2b2557,b126a57f,6bbc039d,a6589f70,c6283ea1,7314aad5,acd8b22b,e8523dcd,2c1c3412,35df278d,e49c38df,85f2888e,cf3c76fb,46e1affa,d8d29bfe) -,S(9aced948,6ffbf984,373b1e91,ff871619,4622741b,1e1ab968,9c88cb70,37a86e14,d7a7eb1f,1b4c31df,ff43cc32,1949c1d3,16e1e7ec,a6a852cd,e8e7f592,8b352d9) -,S(af51536f,fccbdab4,c4f4015b,1e8aca69,b08bf055,e038b22b,87c54f5f,1b9007f3,b6bb0b4c,95c07ecf,49ffa85b,abb1d308,cbe813b7,703a27ef,cf849e,47130f7b) -,S(ec5306df,3ea0abb5,6fc45a09,25c1c925,56e02ffa,18238c3e,5bb2ee53,11823ce2,c950cdb6,720f65f4,18065352,43c90bd8,9457f4bf,d941c9f6,89812840,2dee8b99) -,S(293b1ca5,be127bc6,1a397ecd,59164363,587f468c,81de4d87,6c5d9bae,e72d90a0,4821030f,238e9f05,e93d81d9,1764863d,443a524,3d18e61b,ae26f74d,ba35d821) -,S(ebe54b7d,99876ab6,b2951f0e,e68bfc10,16877142,22ef83c1,2561f486,b4865488,2a1d651c,caf8802f,fa699d91,b8242f51,58d84fa0,d481bc47,9246eeb8,6d381c07) -,S(88f77523,3ab0d69b,ed220109,b29d0d99,33ac8325,445d19df,d38d9c69,3464acdc,8f915122,fbd95ef5,31ea2cb1,aec6bebf,8e059059,459c0d5b,79a282cb,cb276702) -,S(1d84753d,e7210dd8,9db6cfa0,8ebe9797,c7fa40b9,6e94439f,b8117359,a2b3bb01,f7360b5a,ba53a4d8,7440b6d6,f540c485,2e889c33,9f34260d,abfa7861,f1f41ad6) -,S(19e69df5,176f82c1,cf1ae032,cb388ce3,36f82a3e,5e741e1c,27fcefb5,311d4b2f,c401f4fe,c9ba53be,be175dc8,cc1d17b3,9d9f7af,5bb496e0,b95bba6,cbd5c143) -,S(73189e02,c1f125ff,df1a9399,57f29aa5,19b04f5e,42adf729,53d354cc,aee3f2c9,52b8e88f,1c6e7cf8,621d21b0,1e406038,d901de1c,4101d424,1009c01,a537f704) -,S(c5ebe082,8ff1a8bf,52f8956c,b747f1d3,278fd2b0,a5ae7669,1c256e9,2887a74f,ce58cb9,62e74b98,1ab97dc9,2d736b5e,c506e51d,6c09b382,3eff1cdb,cd259860) -,S(783c1621,f7990e01,4296feed,3bc883d5,1a780867,c83b9166,435a0562,4982da76,370b3e2,c9a189c6,9c565c3e,8eb8019d,f5224574,bd5ffbc6,22f563e1,8a36da30) -,S(555e7e80,ccc6a46,1724cbd6,4a53721d,fad66fcb,2c71d579,4d799f6f,fa2b3305,67bbf165,d39d7042,18f5ed31,28fe6dd6,db9b4809,b3270eb,63bda603,f44e9e41) -,S(40c49a26,ab1cd46c,f1e8467e,242c6b1b,faa40a4,cacdd50a,4b0213a5,40243471,16950b00,5002622f,e0b9fdb4,c34224c3,ad55bf30,67f4e96b,dc2813f6,2fdadf86) -,S(eb6b3be5,db098d18,9c810b9f,5593c746,47306226,d77e162,7c8b62f6,d7935298,3d295584,3f356f5c,1f990231,701cedc8,c84e9671,44be22fb,9bd74f0e,15c5bc8) -,S(177218a4,2b55c169,1ca0a073,4d061b53,a0683536,9a04fca9,3f670ce,5eb26091,9611661a,a8a3bc73,7717f243,e5e8b97a,57e0e72,759f0f4e,cedb690c,b3a5fa42) -,S(841a8fa2,f3bc5f8a,7d028c00,127c267a,ea0c3762,8b07ebe3,7f883a67,8fd2a680,579bf37d,b2fd1f77,a0057712,88dbbdcc,526938c,4f9ba89d,9a42d4f3,452cf1b0) -,S(b01ef554,3a377f1e,c801421d,a399c53c,3585789c,d7e51691,32250a61,6edea82d,28f30ce9,7e29b2f1,3af626a0,7a37f14,82e119d1,e66389eb,9620200b,25a90265) -,S(b93e014e,8e3cc643,17ee70d6,ef8c9918,ba344e7c,b38a9a6,2591b0ac,4f38904,129c185,5bdfd10c,6bf152e1,2ff89b4,d0b368ed,c0ae01f7,2b29fc95,240ac3d3) -,S(e0f426f2,43c50d9a,ff80a1dd,26d63189,a00601c6,8ac81373,5fbf548,7acd522,96d883e0,951adc5e,304bd848,ccf39c2a,1c19382a,eb24ad1e,1430d705,deb749fc) -,S(e11e9c74,40e897ad,2870adda,63b9ec04,d5379f14,b3bbbdf2,147ea9b7,9c73233c,49d6e54b,29197532,3f5a9df0,3e22e359,e125e34d,d9f3d6c5,cb9f0a20,6dc1f019) -,S(91ad584b,c5ef145,3b796eca,20027cc2,ae38ee70,9ac4591c,79cf67a7,a96b2c2b,d815a213,a620c531,11f79e5d,b5d9c3c5,565dfd97,ece841e2,3e9c1ca7,530bac2a) -,S(3e725392,f4fa34f2,7413785,cb322f35,1032971c,2303f3da,bfe40461,4299f8d2,8e323a51,5addeed5,f3548217,6907efa5,4e0c1d57,7895839e,42223e5,7708ae85) -,S(5e87bec2,1a589ab,483c00ac,fa863f35,91d9119b,9a0239bc,ed4f5790,45a98160,a88a3b84,33c75c1f,9eaf3c15,9fc39a6e,33625f1c,d0cd7263,3a825023,f2e7d47b) -,S(c2e08613,2cb93b35,749cb652,44e99909,da18260e,d252cf32,489fa1c8,d268a0ed,d3f2e3ad,1f16365d,d47038d6,854e0773,28e02e64,d05a4764,4ed0d82a,8c8a5761) -,S(99304c5e,ccf09869,7b2193c2,31dd9432,3b9053d0,e4b9025c,74517ba7,f1978af,ee77fa7b,638b1396,6f7e77e3,43dd04a0,ba1324f3,1e0da111,338019aa,209dc789) -,S(40e108c5,59adfb37,651f04f7,9ef895b,25a79f03,650d6b1d,1c21322a,b4c5c6bc,8980ab38,5733e648,84aff3f8,c47fef44,210eb2ab,a094eb2c,fc5e464b,679db653) -,S(98c88257,2d190721,20c31528,7f508df4,6d6276dd,c9711aca,5bbeacdc,88c6a78a,5d1aa976,1f5c5ffb,d12ea7f4,8d0510e8,b57f270e,e08c3256,f3ee676b,41a61c92) -,S(389aba7a,25e92306,b84eeab7,a16c37ae,d7b4cf09,806ff740,c05dab20,60af6fed,673ab0c9,ec48e2e8,d372ed60,812b2990,49c32637,35f61c13,d6f0ecf6,d065707e) -,S(9dc64fba,832c956e,93efda62,e5f11b3a,6619eaaa,e539b732,61453eea,ca53df17,180b38a9,3c56ab10,a4267ad8,d8a358ef,8f60a9c9,9483889f,956bafda,f45990ac) -,S(71118e18,e758c2c3,6203528b,8b6707ab,b3439b0c,d3d508a9,6759c155,fe4921f7,c2f61af1,2c1b4e9c,64908719,f11b52d1,76bf22f7,e1cc800b,5ec79e28,aa104ee0) -,S(33bcedee,11b9f3c4,924e0990,9adc5fd1,46218b23,6531a242,45cbb2a8,3ec3d096,15f4bd1a,6c22c673,941a71f6,f4694fdb,f83b3e8d,5e317e9d,655057d5,acfbad0a) -,S(4b599b3a,4ab5e9f1,f161e5cb,62fdba55,fbd97740,759871d0,e66b20dc,4e13ccb4,635039da,9035272b,8b706411,9b342144,6c96019a,2c6df423,2b18299d,4a3fb523) -,S(19f6bf4c,dae54ca9,41b8f642,95136026,decb8dda,35e97627,5694365b,21269d10,a24c3fdc,90b06dc,264bca48,db27502f,6cb31a6b,609d3f3d,a1c92c64,cf3c95d7) -,S(bc3df1a9,8027d14d,f6629adf,7ad073ae,8a270875,b177a67a,58dd46f,1b01314c,99dd3a91,54f51d07,2ee33e89,8d915189,93445065,770745e7,b6bb30ab,808d1f76) -,S(977a4264,521a70e8,4d25f5b5,ac1ae5f6,c34ef31e,4dda285e,1ea4a9e5,7dd72c3c,f1bfc819,7aab2fe4,d0425b61,cd403fc9,dbf44f68,32e1c41b,4fce9b2a,2b9f5a0c) -,S(5fdfde4a,85fc5a53,3ed4a7f5,8adc7b1c,98b2611,3e271b47,a1c12c69,dc9b339,3edf2baf,bd6a94e6,951bad5,26fb24b9,731c2588,b2f6eb1c,e9744f49,16c6555a) -,S(b8bcd72c,dcd28afc,eeac1ac5,fb7db8c,afc17abf,82268747,6ce01423,e9e9c50d,82633c5,2e6dc057,9bbd9f2f,3771a53f,9cb6d0e3,6a7566db,f2c45125,3c55e9d) -,S(6c20b999,133bc37b,c65d01eb,6e946565,721bc2e9,da735c72,8be8a41c,1f75c77,20caf674,d8ad036e,25f42aa4,7a5ae475,5e36f44a,79c5ff20,cf6df115,40b71e53) -,S(bbe49141,69655f15,39ce4bf2,f2e919df,f877b5fa,163b7a70,22bc91ad,315adb07,8cd3e025,6618d23c,8c6b5ff6,db8fc0a5,a77b847f,ec876ac,40f76e9c,cbf93a1e) -,S(748b3078,e38374bf,7f39bbb,c5641737,bf6dfeae,d3980c75,2fe14c68,65e73786,7f7cae0a,61a7dfa2,471f2c80,217fc847,ea86b6b0,6297aeb2,8f3c94cf,2a811ac8) -,S(fa63c7c5,b89a2559,4615728b,2272cf68,5d39d592,d052c0bc,d23d48be,c764e4b4,c4c32ba2,77519d60,e1e38a50,6d67d041,804724d6,5cb4dd31,fbe7d692,8ca47c8a) -,S(c2ed7197,d014e380,a365ea13,d948314b,86978eb0,70e3e444,6c953871,cc56c91c,5c73c293,e7c1cd18,f7854a09,d8b9b0fb,3404bdb7,737dc070,9bdc01e,466a595e) -,S(2514c1ef,cb1e0bd6,c2f34e84,6f3e8006,6c2b3a04,c0d9fab5,f22fe872,6fc266be,c5a0ac6c,7bbb2d9,ff844346,65f66ec6,507c35dd,8ccf9ad0,69a1ec94,c64e3eb3) -,S(5bc07f05,11647f2,58dd2e28,9a3843c8,e2318bff,c96a081d,f6b6ef94,4e286350,213ce093,1217ef04,8d87d059,f2584db5,7a91c465,1e112c66,a41f85ab,ebbcbea4) -,S(edb56e42,97375b03,8a573f70,67ae464f,db9c1335,f6a03dd8,862a1731,9a3cad8a,d3e61a70,16f8d546,61b8414a,426f3be4,35862053,1d981f2e,5314447f,15ef5fa7) -,S(2925276e,78266481,3bf60998,2e028646,6849088e,d0d77d55,817c8d9d,73d5d732,f53157a6,a97c989d,ceb2d755,dbb0cee1,84b33213,20dd6d22,62213fe4,9a87296f) -,S(2c4579d5,bda0f4a5,37209882,937019e9,91286379,c3afb37f,a69e409e,9bc0a034,e150bf4d,d889c3c4,655acd23,f3107bca,a319d467,b1b9b15c,336ca934,5ef7d99c) -,S(5f260a00,11f9f876,bbe29587,af31832,25f21b8,42698b3d,5688545,a8808904,6ad33a32,164caa1f,7a4d2ce0,6eac3d,736fe64e,d83a3a9b,53473a89,8ee02350) -,S(3bbbbcc6,12095ec9,52fd430,f3fb3d6a,9d1f2c69,e8885100,d65a4d7,b6ac4b8b,328e828,3846a6e7,db5b090f,8c9581da,40d244cb,aa3b5948,7e4f9faa,550b0c97) -,S(4985027b,dd0fd8ef,fec9af44,bc222f4a,343e80ca,662d917d,affb9d81,956acff0,58befd2e,37a36e41,305561b5,f2716a23,460b1014,fe814654,68c16c22,3b8affda) -,S(214638e8,d2e30891,9b5eb2d8,803b3dcc,6e826ecc,e1b59b,92e263d5,67959de7,9dd8921,6f131e29,35ae0454,ff5fc9c2,dc22c0f1,c8de7dd8,ad9d41e4,f632342a) -,S(6ced8705,5ced2d6a,f3e3532b,965e0a31,6876c110,69155f35,444004f6,e6f3cfdd,f51b1aab,c86f556f,8b7ba4e2,a1e6aee7,55b17c01,997fcac0,a83eb56f,7e546ec6) -,S(95016e67,876c936c,e3263498,7859d1ad,7fc3ade4,4219727,30a1c886,c9dcfacb,299e78c4,e6e266ee,ffbd284b,81005bab,4df7232f,2e43f160,742bb392,6af4f660) -,S(4bec66c8,30401c39,c42a8019,fc398cf0,c513d20f,9db30763,51315319,ee6f23f2,f1dffe92,3b7d4609,871aa916,28929c63,4fcdeda1,543fc3d5,8e8b2735,938514fc) -,S(b50513d1,40513b97,6ac0015a,60e53ae5,9088c4ef,5ab27bb2,7f3eda78,848a59c7,9c41cae5,1182e6c2,3fb254c5,1b786ccd,dc9282c9,a6674841,29a5894b,99c36399) -,S(59792653,3989a039,6a69bda3,8a920ac9,d1df3845,26f30c00,3e415593,b690708d,7f2c14b7,274887db,5e656192,19ee6737,4c750cb3,97ae4bab,3a3ed02f,1aba648f) -,S(7ba2b766,cf012a93,478fe2b3,e916d665,251cc7f9,3ec16dd3,4db37056,5eacf6f,14fd8938,f950798c,37121286,5e8bdd14,3dcc7e8c,2c84aa69,3fb311f,856404bb) -,S(3062f2fe,f69c90d9,fc947af8,a9e839cd,7f9e9d22,566bd3a7,1c43df9b,eab5d6bb,db84a833,49916d41,7fde7b71,9d92a716,64047d4,21a36bba,ad9972bc,6f5ee58) -,S(ed5f949d,69dbec8a,77f4d695,cb446700,f6fae687,e327cce3,db38c2fd,54b06e74,4724e060,57b3d50,65104ff9,29950bcb,2a690723,f15999fd,ee62febf,2d8930e3) -,S(4d655e03,30028276,e9312fe,a6acc010,30e12950,9ebd68d3,d7170e46,61b7cdc,90efc122,6c27549b,2f5e046b,69e97f04,4399579e,278ccd0b,7bcee523,10ea99bb) -,S(f6b60756,b888efec,d0a9edf4,a483f95b,68e05e80,c351a60d,bf166faa,eaf1b35d,27bedebd,aa781584,6a896b24,1afaf9b0,cb57e98f,bce5df6,bfd22a3d,38a5fb8c) -,S(cc592caa,942ba237,72c4db94,58d6ea2c,8c81c538,8fc7cb51,6ca30188,a3c55748,36e2f7cd,358e5608,36e77d10,361c3f1,bb6bd2b1,d640307c,63d512d1,db288158) -,S(4acba9dc,a5bb4698,21a3acb8,cedf4304,f9372161,976d0edf,6a7a032f,f6c1a456,b36e983a,b2ab47f3,3e72287e,9bbd02cd,d6fb302a,972f2166,9cae4e85,52262437) -,S(c8a5185e,42279d3,2b50e0c6,1b9ce961,7be3633d,84a9472d,97446ddb,eb061f91,cfaa50b7,445e189b,d64c1df7,4668eeb1,cdb7cbd1,ff65c0ff,3c38d22d,9bd4b5cb) -,S(c1c95567,7f4f611,365168a8,89de10ad,535faf08,65f8d20e,52b1041,d35f18f9,34f7bc3b,3d956b63,9afc1eb,956f4472,543919e1,3708e7eb,537ab941,48033749) -,S(8df4fbb7,36f6736e,b4a09370,33f7d256,8bb68d68,f3e1f8fa,8df1ae51,d236a8f3,3d7185fe,8e9a2d00,3987af26,71bb3850,cef6b0f7,70770c81,22977764,5d02122c) -,S(d635f0,e35c7cb8,f2aa1ec0,c475011d,c2c8bbb6,d1ebc297,c2baa5e6,aa5af3dd,926ebd,c588e8b3,1a990a5b,5907ae5f,441e5a99,1853c643,5e36803c,7ba51a2f) -,S(b58d12d,5f865375,7514ea38,30e38e05,3678b525,e8b51923,d6460720,b46a4bc,f7b59183,5b0ebab3,935d587c,e995c0b4,d77c9e40,ea4837f6,48e44841,7438d3e) -,S(bb7c6a8c,b4013640,ecfad075,578e89ae,12cb4253,6461d780,11ba76db,da9a7f36,7dda0258,3774d618,68995b83,5708295a,3c2f5c40,306dcba7,d1c20da1,4836581c) -,S(14f6f0f7,92cc8cef,9dca990a,7fa5b7aa,f116b819,722cfb91,9683b298,3514a9e6,88c35f92,7a07598c,90ce5aac,4b3fecb5,2261045f,f23800b9,7b96f210,3a4d7055) -,S(4b95e5f4,eb9fa118,5ddad896,457f4aa2,fb60f4d0,496ad4fa,76bbbce7,77448541,1e100787,513acb31,ba087f51,201201ed,502d1f08,f7e2b8f4,d27706d1,45e71d21) -,S(e9a17fc0,67f75b2c,6384aa31,223355a3,a7af5366,4d85dc16,dcecbd2a,364b63ae,420a2388,ad674523,62f8fcf0,12b601ab,a40e06a,1b4dac1,9560c085,de7fb8c7) -,S(39d8536,f320ec81,4ee3d066,c0834130,96d4ff43,8331a81c,f10ad544,43ff9169,70ee89e9,1478e898,60d66a55,6054abd0,c7434535,13a7a3be,7a76e367,c28ca248) -,S(9779a0c8,8624d6c,beb1dc72,f371ce26,9f95b993,c49ff20e,1daa3c,2fb636e8,9d9e27cc,67296c50,9da4b0e,6037920b,369684d8,a64cb907,d230a4ab,a0c2712e) -,S(cd4c584a,1dabb48f,6a5c09de,9caf36ff,4a97471f,d1565586,bd78b4fb,66f0b401,95902ab1,eff06e2,b3e104b0,cad2c28e,6fd60eed,c47657f0,bc433411,273446f1) -,S(46ca11f4,142362cb,513164f7,c72b776e,dbeb3f65,5d527196,88eabeea,2561aba4,8060431a,2a2ad442,dfb6d3cb,d6263c61,bcfd0946,6204e2f5,e832c4d5,a434c9ff) -,S(dfebd179,1ffb63f5,76f5c753,50031a21,eb712de5,7e8f83b4,75ac39d8,8a94a513,cfed6c7e,39b2b54c,206aa0e2,2f7c610c,6576af2d,ecb28f0a,a71cb1ad,c7be75de) -,S(c71c6532,82fd063b,44633d9d,7a3b94f9,43daf1a1,7967ffcf,e1238087,5d2c2469,62fcd7cd,e006a10,38df8aed,33abe940,f18a4736,52adeba8,620d1b54,a9d376d0) -,S(63ebbb4d,dc8ba09a,4e2640fb,f48fb75a,6864ec41,fc1647b1,e9f8aef7,34c0ff37,e59d034b,fe16f4b,41d090e1,97360a85,dbf1ae4f,719c62df,77261205,da4ae28e) -,S(650498c8,cb51bf16,58eeac61,61b5892d,ce6e5c1c,271d40bc,eea14db9,dd12814a,e7e66785,5d8e0193,24457769,bbd5d14a,7a614585,70ad5e6e,e3058af9,64a65279) -,S(14a1e03f,14c00863,81599c07,b816df44,90815a8,40c1032a,c41225a8,47c43fd5,35244a59,bc6ba88f,46f66bac,9bb8ef5e,4926da38,50532ddb,6d6d606f,35fe98de) -,S(1c9f6eb2,f6a8a1e8,ecf9a16,71154fff,a4f14c15,bbd50f08,4d6f5315,b6903c5c,e6bde1f5,2ca4ff63,9b66fc51,150eee99,5386383e,402f987d,d266065d,2a03a033) -,S(1de71eed,bade7b1,7c80966,4b00d56c,b43ea61a,c0e069d9,7cff0218,f970f8bf,8d4b2de,77edeeae,d78d42e1,6b7bc94d,ea99d65d,985769bb,5c67da66,18ee1434) -,S(f4432a80,ce954d2e,baa2f062,8bbab706,479f7a39,838d8c3,5a96eaab,5f5cb4b1,96fe6ead,ac34a40c,3cabf47,6fc09382,91f3d077,29c6302c,c67a189c,bed579bf) -,S(8f71e74d,17964af4,5623d3f9,68424119,cb37e1ca,c1524737,4828b5e9,2519fb21,6990f0df,d7f0ca4b,a77678e4,ebf6946e,5b6b1720,869c91c,ec07854d,604865ab) -,S(22293157,5e3dc25e,665546e2,96a83a0,5a09d052,cef701a1,20019c49,c6a6745e,aad8f887,42585607,c792bfae,8a941caa,83d05082,defea859,86a6ead8,e5c423b0) -,S(6585fe63,2ef3a69a,816bf5f2,9e627650,cc57d069,3ac217c6,3b73aa2a,f248a096,820aa3bb,20281afe,edd9ca57,76ecc55f,dc8a893f,de11f7cc,12f37a83,6cfd9f8b) -,S(22232479,e55c51ca,b2963ce5,abf06281,aaec472f,e610d339,1951e41f,93f67bf8,e192fab,2cf22d7f,e67f0514,bc1329a2,888a8f18,a8d6504b,b7c5a9bb,ebf927d2) -,S(da8d02fd,e4ba069e,bccaba08,2b396c94,4460148b,70e98f60,8267db02,5ddf16fc,1a30213d,e337084a,47d67e7c,17a2e64d,579756d0,8b66f4d0,59a76021,e63fa2bb) -,S(a6f72c62,854e82de,f1b8a006,64c4e8b9,ad49e092,78ee6501,708a9f18,92202ebf,8355972d,b08c8104,b7c56ab,c2318ef4,2e270989,1a83837e,daa35537,1d03ba4) -,S(2074fd3a,309e85a0,5c6f8c35,937dcc56,a15077ce,99f5a8ee,8d55ae2a,3bc7db68,e11c02ea,cb783c94,2e58fc0e,806a9816,3061a4e9,aea9582e,53ae1f08,322cff97) -,S(49ed5666,fae9aa2b,70cd316f,62a4b62e,29aa59f3,1826106c,8611c50c,79a1a5e3,5ca7e49a,ae144e2b,dcc0b19e,f986967a,1477c209,2a8368b6,324bac6c,807643f7) -,S(2289ec7e,a1f7e4e9,85f472a7,13722335,b582c4e9,8e191468,3ed13622,5d6c1b1f,11e2b18,689a0867,517bff6,77fe40f7,b03f898b,d70e8902,61a512ca,d9cbbeb1) -,S(ea852ebe,23f1efbe,d8ac64a5,58ba2ba3,fbed0e52,ffc70635,bc49cebf,85859164,bde2ef41,fe97a639,73266583,c7a4e415,25ef1351,5b25cfaf,c97aa635,41cbb824) -,S(5718f0e6,7cc07d3f,1ac1a954,8fef08a4,290b257d,a4179855,3fe9be1b,d302f0ea,98ec4d5b,fca65d7e,e72d8bd5,3645a6af,a6ffcaa0,a2eb894f,d4e40ecf,69acbe90) -,S(df62a2ab,d77afd7d,ee8f0650,b75458e3,10269c3f,780cdad5,50bebd92,4b810a4c,6a6606cc,e384d27b,80bea2e9,588663e0,8d39fe8e,9fc8a8cd,54c4829b,8e4c034) -,S(1010fc45,4b0c268b,c339bd19,809508e7,9ea7dc0e,efd779aa,4974cdae,805e6668,686a3adb,681b597,2b30a323,c6b6bd2a,d51194f1,9d3d801c,3fa65fab,e96410e1) -,S(8ac79852,75673818,69fe93c9,6141493e,72ca344,790487b,d5425ed6,9f5c5c18,bb314248,fcbfc867,d1972e04,b9ef1f90,775375f9,9d25bcec,684c72c9,bdd1c08e) -,S(560e9711,88cbc7ce,c61f3bf4,45f0ade3,6f3f174d,219a160,5f9c8692,3f848b9d,9e92dace,6775cc67,bfbbf21f,c64e6e9d,4d133f8a,c18ee277,bc80ef6d,d1b9cd2f) -#endif -#if WINDOW_G > 10 -,S(8c464204,4b95eb66,cc95ca08,8469a1c0,28eea52f,7f709fe,e6d90700,f5fb943a,bf10fc5d,7bc25181,301b3a61,5ebea597,a3492025,953c3aa5,1a11271e,689d0223) -,S(d293f74c,f3578b71,35377247,cd8b0367,7f2245da,f87453cb,4d8d1cc2,871eb5aa,86c2013a,61dfea14,63e45931,eb09050f,f080e3d4,ae357423,ba7afbed,a64a6f26) -,S(35997241,ae757b1f,c767611e,c76eb935,fefbf7a7,33666aff,4c6bd744,d7687d35,bcbea61f,246bcd4c,c3c7fd35,7bd393da,2f36e0ef,cca0df9c,5994f96f,c44b2aa0) -,S(d096097,7467197d,3c1a0ef8,44ee35dc,285a17c5,bd9e06de,15f36025,7f6464eb,342af6a5,1e06db96,692954bf,c79cde9e,3dd44869,9e88b03c,d144b70b,bd3e8783) -,S(8e875c99,2aeaead6,7033a375,521b0f85,62125797,23a25470,bfdf898c,ae41a777,24aa273d,2d2f19bb,4e0ba10,13127ad2,a5ee6686,1ec6d0c6,53f7a989,73c0bbd8) -,S(bf51d1f3,2703a4c,d1ef47d8,172c5bb8,d622f444,8569aee,d2de1b9,ae541855,8f81e352,b6c60acf,bbde6e40,99353d84,5918d931,4433c30f,3c60a710,cf9aa484) -,S(6fb6b462,9726856,22b2d141,5083ef56,2ebb115b,6cdcbaee,696a8d4c,8341c26f,9c08f7bf,f9cfcd9e,cca923b3,e578ba45,468f2530,baca2032,a899f060,b83c9c73) -,S(75583ac1,8b5cf78d,7de6a21f,aff045fb,1db56f68,6b2cf89d,678df62,93617438,8259a22c,b08546ff,e237c7d,9c669c96,71fe014,9840082d,f6790340,9b69f900) -,S(42611933,a5d759ac,7ec51c89,31b76e95,4aabc2e3,61010f36,cdd8ff9c,b4c0ef92,88a644ce,6b8acbce,a378e2bd,54eb84c5,58cde403,f99cbf8,7830151d,21ed4261) -,S(243a6dbf,6128f964,bdae776c,a716bdc5,6dff9c95,24baf845,8a43ade3,af520d2,262a2e8a,5ce4db48,d0401850,e92bdfa8,3dda744d,a3d9025d,6091f1a5,201b7e50) -,S(212bd175,1548c6d2,41e9307,a7df15bc,46e57e2c,5a76bd58,82b1291,d8c2ac76,82461bc7,6cc97273,267cc788,a8b24082,57f04ef4,719a9aaa,e33cbd77,79391bc) -,S(da6d030b,21f96d2a,aa0b3e56,28ae0ec8,8ca8a546,10bd61fb,c1a7c16b,4d61177b,5b5bc635,8fab0287,4a2b8596,1b49ec29,2c2aad1e,1eabbd0a,1cebdbe7,2e3f9fde) -,S(dc230af0,55a243b0,a581e101,2eea48fc,4a43137e,cfe80108,86a9f4e3,f6c1f01f,d0f98e1b,e70a458d,7030120d,a3d7feed,2eb5a9ab,601718bb,950fa03e,568180ca) -,S(82c2de3a,c815c686,98ce73b5,6f232684,ee9c5972,f0a44797,dc16d04b,a9089df1,1c847065,c6c2cc18,fa253b8e,c1fe178d,c859844,2c1fa432,54462d97,93b8573d) -,S(6ca2de88,74e4916e,e1965dfa,200af89a,cc439f20,6a4077f6,67076149,e20494a3,6ef0b344,97aa85dd,a43cc1aa,57dc7ce6,cd51119d,ae96ae06,99b5119a,9a662043) -,S(ba2687c4,1728fb65,206448f8,28400efb,cf1149a4,90bd31f8,8d33af53,7851d97f,96ad25f1,1f2ce7aa,e8b803bb,3c62cd32,3345500,243b1de5,d61f20b1,86b4c0c4) -,S(ac362040,1947f301,16032d5a,4b303323,d311f533,e46a1aa5,f1ea2f08,d553e0d,53839f95,fef32884,5a75881f,a17db91c,1d5b981b,7b20937f,df171c3f,2cb30a22) -,S(6780ecee,5b1b7205,68d4241e,c3b35c9e,4158c7c2,2dbba46b,ac769476,79049e13,9ac115f0,31e0888d,2dc90b9f,3562e732,46520d57,ecc7ae4e,e0fbf401,3057d9a8) -,S(95377a47,e7a2d5d5,30510d62,2bbd3439,c0f7653a,ab294254,cbb10390,d2a63732,57ac9110,9dafb62c,fe1abe4d,fc64557b,bb01f76a,36649d7b,91be523,f8195fc0) -,S(4f195bf,98fd83bf,7ee97c5,9bd42af5,486a8507,3327415e,85f17a17,2add8921,a56acf25,1c82323,6327cae3,6b1cadd,1a057bbc,f1ef3b59,a865c7b8,691cf3dc) -,S(eccd1fd1,efe8299f,d2208240,adbaabce,cc0510d2,d7b6f6ba,d9e291b1,4cbcb53f,ec2ff321,6da50fa5,c57d6f2d,3198e019,2d9b6f8b,ffc26b29,13580447,a42c667c) -,S(c757444a,f2c3425c,728ff41c,f7cb7475,502e7601,c1edf2b,1eec84e1,b058f438,e1d481b6,169f143e,29701105,bc8b6657,9cd267fc,685014b8,fd070283,6362e53a) -,S(3562837e,bff50776,58d99662,7a11a367,aef3255c,1c470ac6,36f1b57c,645250b8,cdcf4a0d,97aa58fc,ccd374bb,bcafc00,fa1d0d35,ca7fab9c,f4d72d66,299234d8) -,S(ce9dc245,f62e97ab,d2d339e9,7fac18b7,b1f2f07d,fb654a82,b113317c,86d4a3a1,f6e1e325,342afb8e,64fe8520,ec37abde,fcaf1b30,be6ecb79,27ba5615,f0d184d5) -,S(ac022f3b,48ee44ba,9d271a8c,1a01fa8a,aab4818c,e5383dd5,42d9d6e3,2c858a12,1e0563a8,91f8d11f,1989e091,739611de,191e497e,66055aaf,45db9ba9,72ca76fa) -,S(d1d4f682,cb12cfaa,e46e57e6,db6f2277,55a83782,88cca4ff,3a999c0b,a651d9f9,1b19bfe5,870e1931,4c23b4b0,71672233,1607264,acb8e960,488598e7,85e71a36) -,S(79962171,bbddaf94,45fbacd4,f9bdd1a8,892e754b,2d0052ee,2435303a,ff1c8a37,b8ac27de,2a952beb,45472f77,b34c1354,fe47b6a9,daf0720a,b8515be3,7bb98a7d) -,S(445a17c4,2390b604,bb3c3573,b061a2f1,20ecb3b1,83a0f8d8,cf032e3c,509d3b90,b75f4088,7c07fe5c,a0c057c8,7eff4966,4ea76941,e409a6aa,e34ad4b1,693f97b1) -,S(6166b5f9,63a9f47f,5fac49a7,8d175763,8c39cd49,11d16ccf,b0e83bc3,f402051,ba337661,8302aeb2,213e4620,4ec57492,933d6df5,5a045d7e,5317ddf,e92430b3) -,S(cd666e74,28901afe,8e67d0e4,48de7e3,30b6dbdb,a34db4a9,29315d3f,8b251531,af72d8b9,43cba540,e42398e7,49fc89ed,44095951,f11b24f9,e5451810,3802304b) -,S(c833be8c,fd2f6fe0,46d837a1,1d990355,5a6285bc,d7b8814e,e839cbad,523ac72,7ea8f90b,44112363,a8d75153,150c3b4e,b6c07dbe,fe8c8ed6,3a24984,c9a6af03) -,S(cc185f36,3036d385,d890ac1f,5e95b162,e40e4a4f,e8427613,98200369,f25ea477,e0768836,146d9c98,98aaabe5,a9ce12ef,f66d0775,4055eb42,832eeb9f,26338236) -,S(148e0863,24bbc2ba,b67c9be7,407b809,77ccd910,e92c9770,47943c29,8c9c4a5a,89e83c85,9cddfc80,9de733ae,6138e97d,b706a331,fb7176ee,55dfe3ba,c2408797) -,S(9b1539c1,aba5b583,5c88d9b1,92a3761d,cf8b649,54f53a7e,460e0122,bec95c76,391cde19,45be59da,d4c895f1,3aa1ce24,d8472e42,a232795b,967f21d5,acefdc18) -,S(68a2e6c1,75fb01d3,76a9e575,ff427cc7,a6032774,a974bdd3,e93b8a73,e4495cd,153e6484,c8c30dde,5f269b74,1c599647,666cab7,e273d4f2,5573dc4e,78e00752) -,S(58fe9049,35a5a40c,3b633440,533cccac,7669e9a2,e7c2f0b6,6c36c228,61dfb04e,b36905c5,92450e2d,71d06e2a,2d599a77,71ac1e27,15a79555,b39fbb60,5536e1bb) -,S(823c0f96,dcbdd9b0,bfdaff2a,19b6027d,3e9bca6,e298378,3375a783,5eac7080,d91546cc,f34d9a58,babeb6d5,43bf3c36,8831a2b0,d9043db8,895cd208,f2ad0a7f) -,S(4a56aeae,e908f908,55fe7b71,3013ee7,d6812152,4f7decaf,533cde20,2d14537,7e60c801,33b718d2,119995b3,3790eb9a,3129a7fb,2e030d8d,21af90a,c622b7a2) -,S(6c0f3855,e6c4f5f2,c4594e2b,8881319b,82a64bf4,9fe0968a,71f6ca3b,f9240334,5c8e7b6d,a9efbba8,4b5ade85,305aead3,e1478ad1,b4d56fc8,3acfe34d,23b5203c) -,S(d9cf8f2c,d1704907,15dde21c,f172e648,496e40b,5248f331,3aeba2a3,35ac9632,92a7c251,b440f930,bd98299,c35d57f7,15867e90,b6c3e8e6,b073815c,3c934344) -,S(4bfcb492,8b91dc7b,afa7ed43,d9af3039,77592728,fcf1b9e2,7c6767f7,b993d898,276a06f1,ecd9d410,b34c9a4a,e3aa33b8,1854a4e9,e4703dda,7bfca949,a45d14f7) -,S(abde5893,ac4032f4,4ed93dee,8156596e,7cdcc575,e5928792,944019ac,23c434e8,5e03a809,2b9e6044,e942af7a,7cef02fb,46162cb2,4c19916e,d774b00d,8195c40a) -,S(205d6307,7a98a8e1,178814b4,9281da20,4482f1ae,31be20a8,3b3b0fd,526e1cc5,4bbe295c,943e3560,6b95cb19,d6e64bfc,b9cab7d2,55657614,7a79ff50,6fe4d780) -,S(cb4c4c83,e6673a1c,6c228a42,36e6031d,b59653bc,45bf4b7c,3b98cdd2,441c43bd,142e0276,39267ea0,f7c2ff39,75afe714,62f3340c,1fea5149,cfe4e8ea,e31a2769) -,S(25a1f4b2,7ff5bdfb,3af54a4b,493356ef,92ccf0b2,dec7c4f2,b5abb225,2cca77a7,1b25dd93,153f8341,7df3b3af,c991f2d9,36c32e8b,288a7fe9,3e9ff97b,335c3c38) -,S(222f76a7,7eeca0d6,a511c863,a657cb89,5a1b7154,957b66dc,89ca77aa,2a54237b,a8f2bee0,64eff88d,87a598a,8665d295,a205c884,2f6a3492,7945a02f,2cb0b289) -,S(32d4328d,1ad2651b,41bf1015,6936b406,379f5c26,99f1c2da,ec3cbd8f,3b4dfa8d,9f6de6e2,3294a33b,5f4d4062,3e478096,df5de0a1,d069290d,204ce930,7988261d) -,S(cde9ecbe,6948cd70,3b193790,6662b7d,187d0830,cf991b14,e8265691,81f1d3f0,84887b32,e1218d2,9b77794c,e8ad56c5,f5abe8ff,f95515e2,4bce81b1,5b029720) -,S(bc89f45c,3baaef4c,a8343582,6506a006,509f4e7e,265e4b80,11d53d3,a748947d,eff5bca2,714db146,7a272fce,534f79be,9fa15af,7226ba49,51129f5e,6fe68475) -,S(62678cc0,eea2bbfe,2bd4ba65,5434a9ad,39b409b9,b57efdf0,9940f748,ddb51d4f,8d384f4f,d234d31d,1c161245,ef6dd54e,a5cc8ab9,e7bcc883,6735051c,37a74acf) -,S(15e01d39,c63ae225,63dc89cf,3dfa2736,df7c0ac3,4fe86f8a,f219f933,86bc93d0,1f563532,314fcb81,c1725133,49769861,e7efb999,fa317ef4,2bc75588,10cfb13b) -,S(4f8d2b49,3493258d,ff98e813,e428ae9c,52c60103,1bdbeb9,7b8f364b,2bac10e3,8c7d117b,67955db6,c0058028,3f919f57,1e8c58e4,216ca1bc,d66b264e,169b73f) -,S(d14ce31a,2bf16b60,983e397c,ddd3588c,3b0d77b4,f449136f,1a789276,b56f1d61,9a15f620,b227d83a,3722ca6e,4dd7bbf5,833f24c7,2584f356,11ef3734,ad3f0910) -,S(35221b4e,b8c275f5,c10d656c,9bfea000,24c1aa2,c4130841,9c3e8e3b,66f780f1,3d1c5a02,5274afcb,bd78382b,b2778657,6888d46,1b5dffa0,f8ec5dd9,3bf8e808) -,S(82ed9c3b,1c76c1b8,f44ff6f2,9f443b20,83f68617,7270843c,49eac0aa,34a8ddc8,262e9e6b,c2ab2b86,7342081d,90002690,e81f5a58,aefd6fc4,8a91dc5d,e95f1340) -,S(919e960e,acf2aa36,e86342f7,742e97c4,9c49b64a,ff5c6118,d181e349,10717b85,4b51a94e,a3ea1679,cd9ce9d5,ac329f13,ef530d42,c7821650,5a082fe4,d945b861) -,S(cdacae3e,20ce551a,beeabcaf,a643ce62,edca3de1,acf06c30,65ffd366,5bc3ec7d,aaacbb13,872b076a,e28c326d,fa54f4ee,235df4a4,b341c9b1,3d322071,6eb95bb6) -,S(1a4508e2,1bd05c09,f3d80f82,90726f08,de3a62ff,b663d5a8,f949ce26,92a5f2ab,52780ff0,976eb033,760459bf,4bf02994,c6e672c5,6d25d3e6,2b320f5,2cca97ba) -,S(8e46eeed,5686f25c,a94f73d1,3f26c98a,e9129f77,f3aa18dd,d5214262,803a0b45,ee56d38d,7041eea7,c87f2ed1,e7f0aeb6,7253d556,610e8200,782c9af6,1dedcf4d) -,S(782910fa,3bd6b309,dad797c1,5b618469,68d6171e,7a0a0532,a92e5bb3,697e4031,ff178365,c44c2a28,e84c31b8,946b0a80,717914ff,6d3f22dd,ee409753,44e4b3f4) -,S(2ab9e8c,c5a710ca,6cc2d0a2,94f1d7d2,65c50aa8,f9069041,ae93c91a,e5f64e8a,aabcd0f,a2254bad,67cf23d,a5934947,18536602,a13d81c9,db23afc9,a7f89b9b) -,S(d04667c4,4fb25b22,8320cc53,35252937,a094ddc2,4610f7a5,fcb1bd1d,6382c9e5,7c93613f,8bf048e7,86af436e,cac4fa86,6e5a91d8,3064f5c,e31d4794,b2b0f74e) -,S(b9c476f9,799cdda4,a51b0476,c5838994,f157bd29,c9361252,def4af83,6e86b0f7,2ec7619b,c77948b3,f25cefbc,46845527,d1a9b0da,a90529ef,f13aab4a,ca97932e) -,S(90bdedab,f13f9940,4b9d8c56,5d64739c,4ef765ff,dee2ae0d,64fda841,286eee85,a9f47882,d9a848ab,4be812a4,8187d26c,7f8bb8dd,b94f7725,5c628104,e0cf21f5) -,S(a0c394a8,2177734,c02b8310,74ebf0ff,ff4208cd,dcd59e7b,a680737a,fc485c84,c4f08932,b4c62f34,fc82434f,e9b7b164,e835cab6,2f34ee3f,d640e5d7,d09364b) -,S(1b0319bd,3896e8c6,284f949c,72e7694e,bd3c2923,ebeac273,b9aab50d,30294c3e,15dbfe9b,17c3aae7,e5f8233d,703b7b1a,1401b672,1da32080,53ed52f,a2ee339d) -,S(9914ef0f,e92f16be,a27a9354,518dcc0,1210eb3b,3a90f2ab,6992e3d9,bfdc719d,7a0bd065,cea0b11,e8df3629,faf65a30,5e671d2c,86332b83,98ddc2b1,b3c4086b) -,S(3a68fa19,5599f638,7dafa176,395c9615,5798ad6d,7ace7810,daaedd13,ddf60d3e,74575ae6,a3f569db,394faef1,e0641ca4,de158eee,9a8ac54f,5cd96bf7,d4e71a89) -,S(b7361d41,e2b67e31,f1872b1,b1bffc8e,41193dec,7f012385,9da69c60,5e88b2e5,fa9d6b95,66d49bca,73cf5890,f6e7acd0,315347bd,f10be9c2,9b0907e1,80668344) -,S(341e9987,42d84640,f6fd1354,3fb7ff9e,aa93a4d3,12e99bc6,37b85b83,25174e81,c49608dc,91b46187,611cbcff,762e5fc1,e95b4e9a,6ed747ac,8612b6b9,8bfcfc95) -,S(83d6a445,de34f557,40084909,402c9718,1f6420bf,af87426e,2a0f75da,c483e6f6,7a86db44,58c8fb53,5edcf48a,14a94dd8,e9fbed09,277db0fd,787c121b,a1dddfc1) -,S(4f11235a,14bcae9,89082bf1,c6a499d8,32d17686,2fcffbdd,a40b84b9,26ac351b,b50624f1,5f31269d,168021c8,37739cb7,8678ded,be59e288,6e963339,e94a2acf) -,S(8fbb5727,21cfe12c,ea685907,ab6e3d7e,eafb3892,c082115b,998e9a9c,d3ee2b89,da7fe685,c8148e1a,5cd8de8e,2a5b5aa4,ef1bb1a5,af8bfab7,91c923a3,66906680) -,S(804ca63c,b9243f5f,76605b1f,53f5989d,286023f2,fc672bd6,3f52c59f,5496c3de,372912,eedb1156,a1b8300e,eaeb44f8,865fab6d,49c89fd8,43170b05,d75233c6) -,S(b2795c6a,b83ca824,6b18de87,5660d04,60b48ed7,1de9bbf5,8cc1769c,2d2a5365,66e8c2b5,88530b6b,4d351044,186a8a01,db684157,9bdc041f,90d0935b,2a49d820) -,S(deb5304d,b61bd914,c0939d07,c0464eb4,caf3903b,1903a588,208c5e05,36d9dad3,18d54f43,e7e45e76,6a4b6249,1e48073c,40507dd8,3f7b3b27,762a06a9,4d5777ca) -,S(111bf502,d177ec34,b6c61d69,63366901,eb79d5e8,5749f5cf,7743cebb,9b7714c4,be80d52a,bc38bbcc,f036bad4,5e47a0f1,7d8ba20,fe6780f0,bf8c38d7,696a4e54) -,S(94b10f43,c15c5393,e8d4e71f,db863865,daceeb50,674d0f8b,161bd38,dcbe92a5,ec55af2e,a34e8c36,5b3f7729,110586cf,8d087dd7,f1a0ae9b,d25b9b77,f5be6dc7) -,S(4627abf2,2d447784,c53e529d,62d3036b,fb4a422d,10146248,d3b1f188,e895593,8b341d8d,6110b59b,738172d5,6651e948,cbea9ef4,c7e8dc48,3a560503,eb7b3e4a) -,S(19ce15cf,dfeadcc3,7375727b,5ddc5327,585dcabe,c172aa80,757ba468,297c355f,506555e,ce829141,736ca9ec,886cef26,83853e7e,5b3ba66,25cccfd8,4de60f81) -,S(75a40681,8293fcae,8c3e97d8,e1f916d,2950682e,16d3def0,fe6dcfd0,ab9a3e55,5292d5c0,e02ee24d,8139f2af,495298b7,4526780b,f39f5f22,a047d155,dc8c7930) -,S(a7eb8b8d,ef4b7686,b47a341d,4f4a7333,88cb82ce,8f3226f1,cbbf79bc,1f3bf578,85d98b6f,e238577c,b3b52bf3,94a72589,24407ca2,86865cc8,80cfc93f,bd8199a1) -,S(a5b9a2b5,dcc91d67,b352d14,3c19f6b9,6c9f8344,50e16c00,e8a938de,b3da647a,f12d4fa8,39850471,64335aba,1260cff1,26fc4e13,fd16cc29,63472f28,7b9571c1) -,S(7999c6ed,48d589a6,5df7c20e,e9b0fdf5,df58d831,78ad6171,57c09cc8,44015cca,156f4505,3706c3a1,c54b3fec,bd3f12c8,aaacaf0d,22755014,5bcb731d,418f5756) -,S(88fe81f3,b708edd1,b85baade,6c05c7ad,42202058,6dc2e8e2,fead379,c49829b1,cd62e24f,b04b7d2b,b1434150,260a052c,8972a8cd,daa1db10,d99d40d7,df727c01) -,S(18fb0eb0,cfcc61fe,423192be,b694a77d,91216537,5087a64e,89557d5f,4fe86763,3cf72b1f,dfe8b565,38e88e23,ed871d7,80f4a6e3,55229922,b1f28c5d,38169785) -,S(dadb3231,2be4f2cc,cff171d5,baf18e76,4719fa,eb5fcb66,d919c86,efd38aac,8d67945d,752de8bc,b0740e42,3a154449,50e0b330,c6a73981,3d9f4b30,f98bc0d7) -,S(f0b9a086,7cdd9f64,6b3aa0cb,e3105ba,7b17e09c,6c1c39c2,d8057f06,a39e5c8e,2b534e56,25e6d180,40dcf431,9821cbbc,3ff91303,c14bdc81,370c9e0b,5ef4e9de) -,S(dc0e0b05,2e49c3a7,e5d0e253,672e8d43,1cd60166,648b932d,406fbe8a,c2fcb7e0,ff919786,8e1c651a,4cd39cb5,6921e24a,223e7af3,821fdbea,86547e1,c7b791d9) -,S(e71cae98,fb6ddd47,35ec365b,515c6ca5,6bea748f,11811038,b74aa5a2,32eb91ee,804ae818,396c20f6,e2fc5bc7,5dbd1f41,9ed731a7,2801d06c,e6682bcf,1d600266) -,S(50d1b5b2,f7b2e4ff,3b594d48,6bd2ca6c,6b5d5368,2079bb9f,88d792b4,d4ddfd8c,556cf4c5,18fa0660,86b9b03f,aba18fd,5c554fe7,4020df5b,6e34bc88,4d5cc744) -,S(c087403e,2bd5d954,df8c5e86,f23f6cb4,96634886,b4709747,325321d1,bc2701aa,9db44987,d8517300,6e3a549,eed87e06,258bc14b,e2b00679,3a2252,a3507712) -,S(dd1037f7,f3843422,de8988fd,3f68a299,4d45f8f5,1e9242b3,7980f517,bd6d6894,ca8e6d61,5cfbbcdd,8b1ab8b7,673093a6,1a9c08ce,56b065f2,54fc191b,25cccce1) -,S(de229a19,67ca589b,f4a840c3,d18f764c,424dfda5,6c099d14,73a9cc7d,34b5ceb4,958fc9ca,84ca63a9,4323f4b2,ae46ff44,a1d352c1,1b8e8be7,2d5115b,54122b22) -,S(15e33c9,cc9d84fa,16225f48,70a35a42,f8a3a3dd,67a8dcb1,143c7ee2,4cdfd9c,413c0206,ed48cd5d,36205836,45e4ad6a,a59a1e15,c7f36256,2f89b9b3,660e920) -,S(53422561,ca3c4d87,2d23e317,3b21ae38,dc010b99,b7ab0fc4,394e408c,a3d6bee0,6ee906e5,e505909f,6507c7ab,779ce1c8,20f2c50b,a71bb8b7,8debb3fb,6103048e) -,S(829dcf4f,9b2c4f37,32800bbf,f5cb71ca,308bf0a,9176a74,a031d972,9a82b2fc,47378200,429e538a,4e249d3c,9f58873d,abe3f8c4,615c5d3,3525f6ae,5f8483c4) -,S(ed6f6eb7,3769b1b1,4923b989,acff97f1,c05594ba,1d5f4ebe,450e65c3,8ae911e5,dfee6f2f,3fe584db,8b98cd0b,69ff6219,d52e2d9d,a372ffbe,18e500e1,a2c38eb4) -,S(47e52398,1fbe720e,8fcd1982,df2b184b,70616ebe,cb4913da,30327205,c0455503,afd2dceb,f360c30f,6820cfbd,1de0de70,179f4cb8,6c461251,5eae2f4a,baf3e900) -,S(b02937d5,8f48e1f8,6f3f1170,f5e880e4,ba10e2a8,c13dd0df,49fde04b,a9037312,dcb0a4f,3e4c8456,316de580,5355e17f,8a6c7924,f68cbcf5,347d3c7a,28c18c4f) -,S(9f993cf5,3578c1c3,25c10c2d,c3c066eb,878486eb,dfdc65d4,4ee57fd0,ec1989f8,c6b8d40b,16b8811c,d666ea43,2e61baf9,e83eda6f,d38275d,9143b386,31c8bb52) -,S(943b6cc2,5913ec1d,f12730ed,bdfd1d0d,ce431784,f36fe84e,599f9b89,dd3240e6,e58102ba,cac2ff3f,d42d7ca3,254ef55a,9604d3ff,fab5b16d,9f77482,4fed3fd0) -,S(9b0e67e,69b3f9ec,51843da4,f7b5a7c8,59511dcf,47f58a64,81fbf2f0,19acfe0a,6a4ddc28,17a4ecb4,ce2defc7,d7333ca6,2e074c36,f7e49c67,4a009d30,edc54dd8) -,S(97dcee33,9cd8d18f,8c3b0fd4,48ca6e6,c8246b4,136bacc,72ae8673,a4571651,6163a205,cc20bf39,8aae36cf,c8933dc6,29b95246,48823d51,d82d2d2,74e693e4) -,S(a1e5e6f9,26961eda,7cea9c26,f4a1ba02,798c940f,2b7dc267,2999ff7a,d2292ced,50274b7a,6a710f74,ed138401,36d97657,cfc07af9,3b9e8fbe,ca18d31b,8d5f19d) -,S(473d5fcf,7cdfddfc,52fc9bdc,6fc77180,1c21bdb1,840821a6,1a984296,5b4884a9,348836a7,ad7f550,feb2d703,6c82d95b,89ff95eb,e8be6250,eba7c5b1,8fd856af) -,S(9c187442,7384b2d0,4fcc33b2,70544c98,db8c1e13,2bb149d4,54c51ea1,4796f613,2d6dec43,970f0079,3da12e47,595cefba,c1825d36,c71342b,7913f7f5,fcae0a19) -,S(11ce1c46,9150e2bf,b742d826,be740e4a,ed63c729,5f5bf51e,c7a6aa6,562b154,6e86514f,ea38280f,abdf8b93,be8b7d92,67f3b28c,af2a4271,aa3b6a62,1f4fa33d) -,S(1e037904,e4e2de6f,2893c354,18d1cc6f,dde2fd71,4bacf1cd,4d9a5c56,79656042,1bb759c9,34c26821,2a28aa38,a0af035e,3c81ac85,3c01e21b,462e81a5,8c960755) -,S(52fc9467,23f899aa,f1a94f24,f9e3620,3f8d505e,31cc6800,9951d9a7,c0071d82,4632ae0,75430820,20cdfb99,270b47ba,39c909b3,4b3a39db,92419697,d0bd6dbb) -,S(cb585905,997519cb,214f9e39,496f5386,35069eb4,d78dea4f,f9e9d803,642b20d,1b9f42e7,a5b475a1,e42a0f51,ce2d5e50,7131b2f3,5990ed45,64e3913,ec93ac7d) -,S(382c2857,29f14558,75727584,5d37bcd3,e7ab180d,a11c7a12,cecae00f,b4a69c46,cb27e912,20a70fb3,6e258684,3f128693,495907a3,e0b248e4,a25c1e7e,54039440) -,S(16f086c6,c2850e49,8f8456dc,eb33a692,a4dd613f,b2f9564b,6dcecb88,4f4e5024,2e152a08,88eb1188,3448ca68,25a65034,73cb5ece,c9ad5df3,12deefed,279339a9) -,S(7589bd1b,1f0a3577,5530f0ae,446ea275,4439a51f,66730950,6eed6177,65a02492,2d840e12,d3758153,1e5771bb,14d3634,4076fc3,630c389c,ad9765,98462d49) -,S(18b9ae40,cce63a51,3dedbd2b,c3beee9,a80cc5f5,a26b4446,9a0326f4,d4930890,24b86a4d,d5ed3c44,71b57138,2b270d0b,9e0032d7,8e0ad18a,cf6a4eb9,2a2690e4) -,S(8c1f74a4,acc71ef6,4030db5d,14be8627,94e9ba6e,102c89a4,ccfe8a8a,d3ebb48a,a79f0119,98aea529,1e3ba735,c8b26c86,1af1c119,92d5dc94,16eb1673,9245677a) -,S(8d80592d,36bfaab7,5b557ba0,d03825b4,2c0fca08,8ec7d046,5cd2c203,c2bfb080,3e479487,91f27453,4d0a1bd4,a533fd2a,7671a654,10cd7a51,859b466f,151d3f6) -,S(eab0bb19,f477e158,ec85046c,f2c56777,f36782e9,e0452770,f7125765,670ca248,a27d7081,23093af4,daf55e56,32ba071f,37f0bd64,3f189ebd,70074cca,7cc04640) -,S(ff0d0dc9,ebbb2fa2,6d3b249f,d5260ce9,9647e1d,db48799b,db532c6a,2a0a039c,12b0f6ae,7f161f8b,ce1c3505,5d9b760a,fad5b0f5,66211023,3c43942e,fab31fa9) -,S(d89a3235,71dbbd1b,92340346,8b08b7be,be22b320,3ee6b0ad,42a2aa96,3837d526,25da35b9,9988f167,3108124d,9e6f6f1f,db4a0490,5546fb62,146b7421,36e3cf27) -,S(f150023b,f01cab2c,433cdafa,86751f7f,13ffb315,55d34a22,9ec4c012,925b43fd,31f70e21,26ac896,6dc966b7,17a9e483,8ac37a6a,2072bf34,1a9c3d33,3ac7a9cc) -,S(d98ebd3b,2d580978,72ae9d5e,2c2cd0da,76f442c8,e0b4470d,9b3ee019,c83af2a8,9ed5b6a9,5a061970,34bf9873,da6c7224,930fb358,a514c823,e0017c92,75dba3f5) -,S(55b62d85,833a94ee,dfc2e313,df3ca816,8173533b,fa77d827,583fb01b,cbc3c746,9f848773,cb95af7,b79eb921,19a7a139,1f4dbbbf,44c81897,15bad111,364a835c) -,S(dfaf4d76,fef73f93,44c69de8,f6c1c3fc,ec759c49,a2a7a1ca,2860fecf,bd718de6,ac4af693,44e2c287,f6409f94,c36d93ed,7fba1f15,195bd971,357d3142,725a0671) -,S(84a444a3,4510922c,37420f29,a16ee22b,a7839f3c,5810cbf8,38b7f3e6,c5fe29da,ef733d80,2215c12e,143f420a,673069fe,6e89af70,cbf975f,a1898550,1114f06a) -,S(d7c84e11,46c87008,3ddd24d1,296811a3,2c337749,83892548,6291aa53,a72212af,b187dd58,a3be40bd,c3d357e5,480aec61,9579b2d1,4d79745,f84cd406,10844ac4) -,S(fdedc27f,a70b08be,f3a9f616,575072cc,c7fca4b5,71a2ea06,9ffea788,5598051d,fe9b7b1a,1c575a9e,354d279,ba7f4de2,53f6f54d,e7245fbb,3ec462a4,7b9bf9a) -,S(cfa7478a,d3f2cc6a,92022b35,58437b3,f950c250,4d96b9a5,c2d5c795,ef122e77,f3e48dca,e9592835,354f8eed,ffdd4c2e,2ad7800a,3da863bb,158945b2,261409c4) -,S(8e9157f8,3fd62097,70fb7493,d7678fce,aa1584bc,d8dde3f8,337dce8,ee0eefe2,6079ba89,8c05dfb6,ba4f91df,4b4b229c,3322fb5a,44fa988a,c8d9f3a5,3a05351b) -,S(7bf5efb6,103eac30,ec4eb80a,9bddff22,9d422ffc,6a7f9dfd,bea8b928,3116f75,efadb659,64791edf,e5935554,25796141,2cba4b4c,3553fe67,ba138931,3ba71a3b) -,S(f5ba02b7,b7b2c2d2,68c7b1b5,37697079,690a13fc,89d1d53e,85f27820,d0e8df0b,66316d26,b2640e41,bfc329d1,9d2d4430,a9266b64,c3c793a3,af7f1515,9e465485) -,S(5eaacdf3,dceca4c9,6d2bc3db,f22951fb,87c10da5,f1250828,4a1498bf,ff004475,cb3db3ed,9721ce09,16985d40,4831cd04,b38f5810,977ea106,c8c25194,ad1f122d) -,S(1cfe5c17,b8d61134,53552ba6,ad513371,d1320abf,4fa2de41,77c5a768,a64a5554,53837cf6,4846b887,1e64a2f7,e319f740,99bcabe6,7a0894,5edea46b,fd1dcd5d) -,S(92a83f47,8a2ccc86,1cc91dd2,a1210fbe,286f47bb,44e46880,5e21f0a3,7a5dbc10,fee35c65,fcd45b02,f8270b8b,c198132c,cb69ff9,ec35043,684f54f5,c999de94) -,S(172285ba,d5d539b0,f4d86ea1,35bdb79,73c07ad3,24bf5dd1,4f74ab69,cad277d3,45abf940,cf356364,e0bafa15,cee3e20e,cfc29040,288b4897,314c22f9,aaada654) -,S(ad17bd53,92e19bab,8554ae08,bf9158dd,3126ce81,3a05c32c,7646eb73,cb164762,a129819,1c833987,775d4f47,d9d70d4f,8139c651,896f9b94,e164574c,8d065586) -,S(10421b3e,91a4a89c,1f6ce9e9,13e511c3,c23fd307,c4064a12,5267cb31,2ebdeb1c,539bb5d0,9e49f0fd,186b8a51,73118cb,98569700,dac77cc1,92359286,3aa53319) -,S(c43adcfa,78152a3d,dcb9eba6,6632aa5,2e8476de,1e0e30ff,39735b06,21de5bfd,6ddd09ca,2122580b,847d04f0,5dacbb7b,1e81c6e2,6057d880,1a911a55,9cabdebf) -,S(f7a99ccb,603a58d0,4c6b9e50,d9e7d988,14434f1d,92aae27b,5c8d9006,98bf9a73,ccdfc244,76f4393a,e96d6809,1cb74130,5e62934c,cafc9b08,78a3a77d,a71a7ccb) -,S(9abc95bf,70174ea3,5038f44f,4a2ca9be,f602d516,9d249aac,b3175be7,e09c826,6cfbceed,3e71f8a3,d427d2c9,f8cedaca,22a9fedb,4cab7763,617198e0,d7adfe0c) -,S(8a7ca893,35c84873,ecb4af06,b493c9cf,d7bd08fc,d0535c5,546bb9ed,5c5d8d82,2518b372,90d3c08,72f1ee4e,54144799,209ae3fe,d2f285ba,7b00193,21e31bc1) -,S(70c8e379,8649628d,969182fd,862f8d4a,b39fdbdc,c246fb79,ff1c9227,a64d1c3e,c7931ad5,27ec0a4a,ec297d9e,fd56208f,936c9517,4efdb86f,7f50e321,26ea3cbb) -,S(d783f6b4,6121ee0,71ddcf61,b4808fdc,934a82e7,c185876b,9572d628,31002121,aa92bd84,14226949,9e107c82,b9a64898,28b3ed15,694ba62c,a031d98b,5e9c7fbb) -,S(c1f06a1c,29abb43a,cadffbb8,7ea8e4c6,b7592795,9c778758,1a17e4e7,7b654c18,1dae0de2,f1db42cf,ab9b0e7d,9e5a098f,bc102470,aa418547,6cd1925e,fbecdbf0) -,S(2ad74e11,3205b587,866633ea,32172662,d1498a27,48698724,87b7e62e,52cc5105,c70c7507,de1fa1fd,625aa7d3,755c83a,b5c85159,4b8bee10,5de45da0,d0ff779e) -,S(f490e9ad,72246a46,6eb74e23,371c4f57,a9e32b57,74ac9ac0,3d800978,d77408b6,546f367f,8fdd1687,ba6ef15e,4c258507,77e49a1a,8b449fb9,63a0f01a,a9dc3d6a) -,S(20502891,8357b697,e05788b0,55f8bb32,80c431c5,de07055,3f123373,981d6149,39d040e5,44110e22,58da6771,2852fd09,9489ee5b,5c77a777,7966abd0,468e3b0d) -,S(6e91bb8e,c169a3a3,eef59915,d4de9296,e4b78299,e038c5d1,bb001eb2,f86eae95,d2c21297,88f8c9f1,16434063,a89fac48,45305dd5,d208c887,2ae94ba2,80877dfd) -,S(cf2947c8,39fc40b0,610d0d2f,e1e5ad53,39e7d0ba,9e7dea01,90678bb1,6ba34905,6145a70f,7f0cd53f,d758d7b,172e875d,8db00f6a,131ec7ba,aec140b2,3f37c63d) -,S(b48f8387,ea93a6c8,561c9b01,ad32a28,1c8db1c1,ac3c6864,ad161874,fa2366f1,2cab333,cbe07d3e,26fd971b,3609cfc8,9f46bd81,df84276b,375315d2,7a2d253c) -,S(7c4b5f66,c572d34,e4cae58c,696fd43c,30f6054e,8145715e,f391eda1,42a1f827,3cbe264f,be125af0,3907c5fc,c61232c2,d0adc2ad,5f94f3b0,8ed32ad,99843d97) -,S(e5796368,d4649e19,6227f989,78758d9,8fe24e51,f5d5a567,378a85e0,850d86e8,74bb343,c9a69128,9ae880bf,67a7e4be,1fa111b8,d6608896,46ec354e,f6c9d4a7) -,S(dfa1065e,fe83e9ef,c19b8841,6e3ca5d9,67c1ab26,53c7d650,9f02ba58,fc4d637f,22d2567,eb0237ba,2f270e04,685e5352,e23fdf19,a2aa0a23,1ec83eed,ca5042d) -,S(2ea1d8aa,d436c332,8fda3ce9,8e710b80,8f463844,cf131f2f,2347b37a,928af132,33fa7e0f,b8c2ad10,580a243c,ccf2a4b2,13ff9620,7a034432,8fc61f31,e98dc4c) -,S(12ae1451,8122af3f,a788298b,5e59df37,ab6a976c,f8a931b4,c0a51de5,d567253f,85ff1dd2,b3271d2e,de2fa732,9e3f0a5a,1c3ff9ae,b55555a7,926d31a0,1d24877d) -,S(fd46e1ef,b588af1a,a72b84fe,dec75a3b,125579ef,55ef8270,85645930,95bf6619,d06adc6e,ceb6292f,60c7d477,c73a2aff,342e6b7a,e81c5ea4,f57cb7b,27a51b17) -,S(ed7d93e,b8c0d1ef,1c49e1bf,be22acd,c7a17946,b172de61,4a290d0b,7f32b52b,4d0ec30a,39a81c3a,f8f6668a,742abeb2,b5552284,a68ce246,f368ce9f,b2303ada) -,S(fccfdfa5,cd0e79a6,9febda81,475c06dd,58517913,3624f4dc,9d808b6d,e9619ef,79b9040d,11d09bed,f89959c6,992a9636,ec62324a,d60e1513,9bd2441a,dd0adf49) -,S(831762b8,6a9b9afe,d2a044b2,7bc714cb,16823ea7,22b44010,a57a5564,4b4ac477,147ae062,8ef3bfdc,b48b3f77,f84dfd77,2754c1dc,a626aff6,9c3169e4,9956c708) -,S(33448c01,a84d5303,c8f70adb,bfe0ccf9,f92cc461,f2656fb3,4903b99d,4ef26b01,e5727349,ae8ba61,c8ca8284,ee7f906,208ad03c,6fd7c95f,736ea541,ffb8f2ff) -,S(920a1261,6ddf1304,157ccb8c,50ebaf6d,60df85da,b19b24a2,48254cc2,7d215a6,19e4d4f9,cc91e890,3d2f7a11,ca8c0b97,e2cb671c,e0c4ee36,9f1a3ca0,f28d0f4e) -,S(1df8ce1d,3e370b9c,3f60ac00,cbac25c5,458385a5,c4b926b7,fcafe62e,536b1ba4,344df46e,e3635079,52af6160,2729094e,3fcbabf5,bc701083,533e7e60,5099a92b) -,S(7227847d,abfe26b8,13c18175,c37a0526,2e2243c8,d80d93b6,286b2881,d38b7b72,bede79eb,33da3cdd,95289c93,46165cf9,28b5aa41,c46b364,622988b8,a7973d24) -,S(6defba59,e1218bfa,b02571f8,ccc84104,3caff74f,26d8d995,9729f292,eff7fb8d,4d7baa8e,21f2fbc5,96f770d1,bd34e77c,2c188c05,5921c1a6,95696a8d,4c340a04) -,S(c667f4ef,f5127d24,6b31ae02,2adf53be,8302e1a,b631a0f9,90b16051,e02d6bd3,3d7bce76,ce11bdf6,fd4d822c,37d746a2,f8de283d,527af237,3e80c4a4,dad34cf5) -,S(ed9e8674,441620f5,990dcc24,23a2ab00,6fbca1b8,e6bb3d23,55c2c72f,ce29d866,64d5ed9b,b4289a2b,b81a12f3,30930dee,7c03dd71,1ec361a5,8297c22a,5806ad30) -,S(86a36c57,e6b0cee0,33c00b25,66344ef3,219e57ee,ac452ea0,b0eeb98c,3176fb24,b4f4bdda,9e9b58df,4e103874,89592b5d,b147b43e,79a1af25,135e8db3,eafff739) -,S(2e237784,45396ff3,a0e105ac,ba151e3d,fd02bf82,1de70e04,33792280,bccca913,f736539c,e77983f0,610464c4,3bbcc904,f43726dc,a336304f,c0b716c3,67148551) -,S(ccd3c14c,7790d936,5226dbcf,11a0bc00,9db88a87,ac2d68c1,6899f980,20a1390f,b240b35f,bd6d5dd9,f33bac2a,f1899320,f8a9cba8,7df0a67,81cdfdd7,1c3af907) -,S(7713be7f,988d7b1,c6c6566d,558978d,eba4efad,b82761b2,17bccd87,3637b018,8fb91a6f,a9d62baa,2eeef7c5,15fab341,c75f31e6,64ee7d94,70db34c2,74475781) -,S(5485ad60,35dcb3b,9520acf5,6b0855cd,34c739ff,1c59798b,1ab667ba,a4982b02,1dec6c7b,1e7c14ca,743df62e,589311bf,57cbd455,e7dcbf9f,cd439962,96a90f0f) -,S(a597503a,d3be484d,1d2d1cf,c4e8540c,411bd201,f2b05ed1,89c9a3dc,b0ee0f19,35113e7d,38001199,1e2cee66,4dbcf490,becbd6f0,765c94dc,e2855ee3,b01113cd) -,S(ba91b251,abb130b1,57dd07a3,dbd2fd91,1ae24937,80c8046c,b94de57c,dd91ce4a,cfcc2080,500aedfb,a69f33f5,4f642fbb,8377420f,e1799dcf,e1dc3593,d3e1f6c) -,S(adfb5a58,83cc7bd3,c6fd3386,95c86414,5c6d2f4a,603fb2e2,fb045bff,86d324a4,16574ed7,45d82dfd,c50415a1,8c30da91,3a525753,cc975722,22a5553f,7b0cdc5c) -,S(1084914d,dd710a5c,ac854b14,10a4be35,ba1f13a4,e0fba3e2,9d94edcf,a3561ae8,653ca135,3240ef60,412ac6cd,adf8e664,2f2b74a3,5908c3ba,be6dcf85,49c25e99) -,S(704aa271,9af38b14,17a8abe5,b881efe,81876a6a,f807833f,133cdcd1,6e6c6f7b,a6fee2b3,48c1180b,c48726c9,be2a1a41,11395af4,42ba7b92,63f4f66e,a3769e54) -,S(46048cc1,7f5d2a86,5c1f5734,893c6683,fe68b0e8,942c9080,51d7b836,a8aec289,d85cec30,89a8f77d,75bf9c6,bb4f8a33,2e766834,3841b277,a461a079,8b288efd) -,S(50f1e6be,315d3b21,636781ba,8598d2f9,7d04ccf,5ba1fc76,3d547657,77fce9e9,f7dcb7d6,2057b9f2,8cc24975,9dc9621f,25dd0ce1,47e00db7,d095fb0e,ee6b0b00) -,S(7ed0a244,676655ad,10efa03,7748d49e,944df1f3,5bd46d0,3b7ffcd0,a63501c,a8377a65,593f227b,446eb266,936ae475,e9b3ae65,a60768d8,2690d0f0,5c18c21) -,S(d039ca1,ee66c2cf,611c431d,cff1bd2e,19b29d3b,b1f37342,c29f4632,4febccc7,db0d0d82,14f4c661,629ff5e2,4cfdcc84,6e652ee1,15a6476e,7813104e,696d736f) -,S(c27973a,cc55fe2f,4531768d,94cd4a0e,8e36729c,aad61579,7beed810,a7b092b7,cdc310ea,b36ab246,c56d5402,9b9e3314,878e1f1,ff7520db,43917a14,1f41c99) -,S(36842942,cce3c683,25472e48,de202d15,ac14a180,3a2dd84,6de0c33c,6446e945,5000b3f8,19ab82fa,3589db9a,eed5609b,208d95fa,ddaebcb,57403b96,7b8f2f7) -,S(d1aa195c,338621b5,19ff3a8c,55abb454,74865ef7,85e0fd7b,c4554ae,6d62d0e9,e7e1dd33,dc293859,b4634576,d8840630,832ce773,a9a8bc88,c2e67251,a7b737a8) -,S(4f423d32,607439ec,366bd6ff,5766ec13,a59b2c2a,8cd008b0,489f267f,5c0f00f0,5e3c7e9d,7ee94c15,c048e6aa,272c888c,b6c3e058,4b4f4ee,f5e1d787,a4e7a9f4) -,S(6bb1c680,ff8991ef,17c0859a,9b5fa9b8,ebcb9afa,af7398c5,9101bb99,7f06c4a,318da775,d912ae5,d17c242c,97615c5f,217005fd,535b839f,189ff3c9,8669a253) -,S(14095d4,4713a46a,5fcb251c,9fbee2e6,bc393423,30303b8b,d0f2d09a,c0096f68,647e000b,3660b374,959e632f,6867c7fc,1c7aa4fb,b7f5593,22dcb2ba,e604a2b1) -,S(12112bf0,346e9c6e,4a8f831f,6c087876,8943191a,38e9fb83,8b2613b0,4b5e5323,e4149ac2,cb4533d9,4c3abf62,aee4dab9,faf64065,89cfe10e,30a42986,9657a3d0) -,S(f99360cc,c2ed4810,d80974eb,eaeb59fd,4f2197a7,8459729b,4f75c370,8bca5738,b92a2f5e,86d77a8a,c2c1b9f8,6e1971db,a06e4414,935020db,c0c83a92,ee6f1cb3) -,S(2dee5a4e,c81a3ecc,4872112b,be53f51e,64ae779c,49488567,a654e806,ea809ca4,1e2ea8a1,df6d47c1,c0aa1bcf,ffcf260e,bdea4d63,934ff3b1,bcb1e1a4,c73d4954) -,S(5baa6a2,139eeb78,f49638f7,b0dc5010,b73688d1,bbd746a5,f2382c7b,d461229,72677383,10a352f1,9f2a75cd,9e42509f,b08a0ca9,60154693,cc01d595,25dca81d) -,S(a3f77eb9,321d44d6,b774a6f3,b1319e46,f60d102c,d96e983c,8f8568ba,82913d70,f93d75df,8271e70f,1aa38630,26bec1d0,f6db1765,77470077,d3fceb8e,5c613a05) -,S(46ba66b5,fa1f9274,378fd62d,68ae9f38,8588d766,ebbe97db,72f9084d,c7f2cf08,5473e24,3078b8df,92df9b55,52ad5055,f44bf7e2,ecf0785b,72db5dd9,238897f9) -,S(db6a0246,ddcf0260,b2b415b6,f551fad0,bccb15c,ca196af4,291d21ce,ce80dbf2,396cd446,f93e1c97,a56c6f6f,63cd0966,5f88856f,e75e1c7e,a985917f,28591d3c) -,S(b82f8d1c,a7a298da,3992c4e5,8dba1b0b,38187eb8,66992e8c,5cc1c834,6e6c8fa1,4b0ae76a,f9b0413c,8d4fdbdd,db767c6a,b1b80589,533e3ee0,28eb6036,1483461) -,S(446e96a4,dc9264af,e9cc6348,aa612861,d106fdd7,b7ff94a1,82e0f018,c485f000,32dfe3d9,21593a58,1fe23b7e,ccf677bd,2771c40c,a612a507,c8e33df0,99568440) -,S(c86f10,7bfa6dcc,b9f00ca3,465049de,5c8a3e6c,d85bdfb8,1ada1d39,303a2eb9,e64f7066,7e910814,ae18c6a,7323474d,9dcb277e,4aaa7ed8,88bae4ae,7c34219d) -,S(bed8eb6e,cda14299,e4cd94cc,202be7b8,9201c2ab,302a5cdb,83e5f5ba,db6cd710,15736cfa,b375a40c,5d367b9f,6692746d,16a1f03c,20941256,708489a5,5d411aac) -,S(b3efa7f2,c5f6ad10,41f171b5,ad759480,665e0a52,de82a881,da1926e0,8f64d38f,3df63c84,32761a24,eb0dfa,ae98e034,b6dbd361,3fb53ff,c535fac8,ff1677e6) -,S(b0460da0,cd869b5f,235213a8,49e143e1,8fa9afc1,651ee921,ebdc525d,2715cbd2,c11a3ead,f3541877,ce73b4c0,2b57b299,46b4725e,cf630eee,865bb121,b86fd7ee) -,S(28b09517,a17452be,b2c19187,12d600d4,b4969253,a7d0d52a,49cec3ce,d73bc071,36696708,73c7591,11163518,40af594,40ffd6d0,690ddae7,fce7a43d,e920a326) -,S(521becd8,192acb58,7ae76b7,c0bf17fa,ad86afc,47157753,6b1a51b0,fbb5f136,648a54c6,d7aff13e,cccf399e,15451682,ee06710e,edf32669,1dc7fe83,75ac858d) -,S(b7bc19d0,b7fd9d65,26c9bca1,b587d84e,a2a200a7,76d39082,368b761f,79f6cf67,5adefabe,e0d0c8cf,4252c29a,773163b6,4a1e9ffe,ffbfe3ad,2f796e8d,1f70acae) -,S(e48e3be5,1b6ca8d5,41f0c241,21558cec,66db7b6d,c13e7114,dc931f0d,397aea8b,dbcf6357,5b16e2f1,30f064bf,ff12b465,f6cb3a3e,f9f74431,4bf41e7e,e0f28ac) -,S(395c6de,71c692a6,a3247596,8e28f2a5,4ec795b5,9759e890,9b2f4290,9f455751,ee5e0118,3c7dda2,c1eed4e1,5aca155f,b5b097e4,499bc3c3,fcfc2c85,a669a13d) -,S(28938ac3,b1184399,22741291,9c0fec36,663da3aa,8a4e89a8,1a66052b,ca808d99,4ae8de7a,b1ebc1be,a2beadb1,80cb9a10,da168295,ba1ea5f8,310b986,4f174603) -,S(5c0f618,95e88cf6,205472f2,3e27e853,be3af64f,d0a376f5,8523ee6b,5248f5a4,be5c3c55,cd09ebb3,b7363456,9fdb50fb,8473e3d8,3441e624,b41b1c3d,e44be51b) -,S(abe1f7bf,22d0f733,ed28e125,f7ed05ba,ae2e8f13,1eba2ec0,1554dac,5e3ca1d7,2a5a48db,3de31f6a,9708ffe4,b996cb33,e553e6b5,95aeaffc,918aa2c4,1ab0ab4e) -,S(c3042427,57d370b3,79124907,ea609129,5f1dbeec,442a6349,bccfd29c,e08d8be7,67a64eb3,3e0fda75,535b35e2,f8c9811d,528959c1,29e8f144,8bb75ce9,b1868934) -,S(65a59946,356f219d,77af0b6a,9e1a43f7,3152746,6af41c21,c81532fe,3140f5b8,64e7128d,5d3e4fa0,518cf27f,c070da20,1692b059,3d84641f,2463a61c,74f35918) -,S(6c7d2e3b,48428c87,46b066f2,bb99da10,60311cb7,d4dae19e,de2eb53f,141413e2,4ba47bf,c2e7c670,4de2864d,1ed7b383,286292fe,28f7c7ab,2a664bcb,6cb7e3a1) -,S(dd257bd,b99c89c2,b47798a9,bc93ff57,5655797f,a45399cf,44acf58e,93fdcdd9,f8d670f2,a9207f25,52e7e0d7,14289103,e8194f81,6390e0cc,1af2ae36,c1b3e4af) -,S(2516034e,b8ddc424,42952b8f,acd47c62,6827b87c,b08f263e,b2aab5e6,ecc23d7b,ad8e8879,f5feea07,ad3545bc,a731dd30,bd2ab534,4b486826,433c75a1,6216ac9e) -,S(7e723054,27b591e3,b19834b3,8211edc1,7f075215,6591980b,907dce0a,d934246d,5c91fcbb,d8c184a6,f21671df,1098760b,2506bee8,e32474e3,3b080147,4e63a71f) -,S(1b1f9d16,ac3c0d2a,4b87691,45a6f6bb,8d4fb57f,ef9df33e,72b5d399,6dd1898b,6442bf1e,5ffe450,b14a399e,16241a5a,15e94453,94519bd1,24d0a67,f35b4b1b) -,S(e0f1fa4e,57cdea43,a3b9f671,596631c6,65b5144d,93c51a23,e9006c63,fc872f2b,c83851fb,54890d14,2f605617,151dd47,74f9a3de,cd27d864,a49c176,af32e564) -,S(ae95bbb,697c820a,251a3667,b2a0a078,40efa027,99d7bd0b,3e9a12eb,32728c3a,e0dbba97,280096d,86ea4da9,45ae509d,1140e0dc,7b803f10,e685b148,6baebb41) -,S(fc8ff885,d52ef42c,1fe529ea,853ff8c3,afad1ae,6e7f1b30,69e34076,682aed31,525eced4,b26e8f62,7b904f1b,3356d01a,9cced71,432ac850,433e0a64,b1e3dd14) -,S(6613136a,459d625a,d5b5753,3a965a0c,ed68d63c,13652546,c629cab3,32c8e810,10f29ff8,24d30a94,b3d732b4,3b168bd2,28b4cb01,4012469b,93a9853b,655b65cb) -,S(45085915,7b683327,c76309b3,96ef3b63,19dda841,f6be1b91,f24f5a37,ddea56f0,b9a71446,584a88e4,6a155e34,f08d5a6b,2b6ebbbf,b4b1aa12,bbc7654f,91956821) -,S(168ee3bd,8f10ba0d,deb82576,cd5e1711,be58af4c,2274464f,e32f3f7,7c8a4325,6eef1e63,43ff409f,a916891c,982f8700,465fb184,5820b886,68b74202,6678b34c) -,S(b3191d97,763c2341,4eb4db8d,eb2003e4,fdd86b4c,6077931b,71802714,ef048c04,b4ac3085,59f975ca,be7d53d8,3ebdd5c3,ce6860d6,37710a04,f885a83c,c2152edd) -,S(da9d5c5b,4e73dc93,3c72acca,1e93f4bb,3ec477fc,f201096a,51ea0226,3a2f8738,7fb6a2da,65f966c3,689b93b0,d6366511,400c05d0,8b0a15b5,b4b3209,a812f8aa) -,S(140e55d2,a7e75678,1791730f,c526470,8d1cfaa0,954e215c,1e65bcc,e4b0dd66,4bfba0d8,63ea2597,91e470d8,1ef36318,87e2d5e5,c897918b,ce805941,953d5b3) -,S(15a9ccf6,4b95cc87,cee9bd01,bfe3d8bf,b438f7f8,66344a1c,f3f399eb,16b173d8,4f5472cd,bdebed25,605e51fb,f0b31a93,5d0ba59a,6e51bf90,e0363c8d,9bb33f3b) -,S(e86e364b,6776701d,b7b3d3d8,fad181bc,c7ed5e91,2d0a888f,814caa3d,88af6e06,22fd460,afc040d,3e995518,c6286989,24a466d1,4a624915,f834c357,4dea7b92) -,S(3c261a98,cd25f0db,2321134c,723ebce7,b1f81d3a,a6d5bddb,fc282fae,5a500eb6,2b8d2145,5e498211,8a4b6ed7,ec96a66c,4027a506,deaeecbc,45535fc5,77abd9c1) -,S(49b6a811,4d55b517,6cbb1f6c,177aacfc,368c3b5d,238300b,d66546ed,f4c955c8,d1b124a4,9f0e7c1,6b8e001,7f1b0b2a,ab94411,391d5bca,5b535838,a3815b94) -,S(6ec8e861,f0d3e5a5,3f9deab6,20cc4b81,6cee801f,f7a43f71,f34a8dac,c525f6b9,42e0545b,68ccafbd,3309c4f7,eb6b5eb1,1e01a871,c63fae27,782001ab,a6dcfd6a) -,S(7342b341,59aca5cf,d305a2e2,a8f14da4,4b527e57,4640fe1a,c08898aa,4595b9ac,b5261302,d2442ee2,363969a8,4ea61281,27f64f40,ac86dac1,21b5d234,53160124) -,S(842b30bd,54ef350b,65dcfc43,df26967c,b2747757,a609c54b,687d30b9,5a686fa9,4ffa9e92,2caa36b9,ecf31f63,f5c8de57,7d594f7c,71e7e77b,9cc5ac83,f336ead6) -,S(2dba435d,d589a7c7,bc3fb60d,495757ef,7c13bb0a,3e91a153,9998e04c,19f94862,c440720e,a4b23cb9,d238eca1,6775e500,931d3e5c,7df853ed,55cd4889,5e8cc0a1) -,S(9d1e8524,8f84ce5b,2a75a457,819390be,bb284fbd,3d035c07,998d3c45,c73bec02,8e40ee4c,c935ccac,2338bbc8,4a8063f3,6d62e8cf,849bff40,1298074c,94eb9ead) -,S(d2735ac5,d1fba75b,d4f63912,11549755,9a7f8623,62e25cf4,e76562d2,d8b441af,bd2ac36,19f9f339,77b7cb0e,5b52f3e5,b4ade86d,1c9fb31d,a1d8fb36,7dafc081) -,S(b0130e38,f46cff13,ad1a68d3,15729395,b27c2b96,e0a957cd,ca63adfe,b0a3e11a,3d9f697f,4a61401c,87eff844,3b11776a,610f1516,4366c1b5,535599a0,c6aa3c4) -,S(e0aa062f,15306af8,b662d8f3,3b89de8b,f59faa78,29942caa,ed82e668,35ec76a7,c5f5f0b5,6ea77304,a5dffb8a,cac98387,34305b54,25fc6181,79a4457e,c15e6f2e) -,S(ed1626c1,a8e6d1c9,187e15c4,ae9875ec,2156d685,997ac413,9f44bd0b,19432d5,3c0d895b,9dcb4a3f,4235e531,ee7373f7,7f0fad46,c5938d7e,69d50429,71f0c35d) -,S(a2cccc31,4e18fdaf,8cc25aa6,74c974f8,664744db,86e04be8,431d2ed0,4dc92833,b6410e49,d6d471ee,d20e5536,8672f5e4,2e1b9c88,c06438a8,46c3a74f,c759d71c) -,S(5bfc192f,db15f62c,4af19119,b2d96a88,b3b24e06,3d54b31f,a35f675b,f668bf27,46774374,acb4e140,90431bb3,9f62a38a,dbe0dc62,4021e23b,6099e198,47d99051) -,S(66842a89,da73c404,32a2e553,97efb009,61eb2155,886ac90e,97dab5f0,9227028,3a8e83c3,511ea048,88d2dc9d,f1016cd9,da171bc6,89c9af4e,90b18091,21941de9) -,S(ec823197,3ba95f98,d45f8991,3ee8b92b,e3a4a84d,d59342f7,1810766b,cdc516e8,532d3c79,f5113f4e,1973bc88,2a953b5d,77d5476d,ac9972ae,f1d25e19,ab7206fe) -,S(3b65fe78,bc516176,aed5e5b6,5f3ed39f,e8e8e26c,32ab07ad,1ac2519f,72fc140b,856d36de,5190eb9c,13f7f976,466f95de,566a1fd7,314cec1b,9c9f7adf,98208d98) -,S(3ac0eca,51c43525,e9e545ce,83fdd009,f9f31eb3,2722b945,18262036,d18cc346,dc72018b,c3b2a4cf,3244ef31,340e0944,325bebc8,b134de50,9ab3024a,a213a7e6) -,S(4929658d,6c50ece6,edd2db7c,217d9be0,bcdac8b9,bb50972f,fbe53a04,2ee23508,e5aca42c,61aabbd4,b8555980,a2328741,6dfc8df8,d7a10c3a,7284bd90,aacec38a) -,S(9d16e76f,4bc96492,f0e9e748,8c6d2297,7830e2ab,491a6278,1d60ab5b,153a6291,e6590f00,e4ac6922,5436318,9770aef5,5eaa988a,44e9711,da7266ec,895ac7ab) -,S(b0649c4a,1327e7fa,f52a9bbe,7ff97add,4e13b36a,27c0676d,5e09b2b8,1f5df94d,991c8316,a6f36848,e072a080,77f75a8a,d79fdd08,1a606d12,b355c3c,3891acdd) -,S(8f194a21,f6303ded,2c9ce51c,44a4a16b,eb39a8f6,5fe13c9,6b7c12bd,b052235d,bd1df3d0,c9af82e2,545afb23,e9a2dc85,c635172c,edfe70f1,bd755d26,9730739e) -,S(1da71a97,cc7a4cd9,4777f6c3,dd5e665b,3872b721,c6c2262a,60e87f1d,efe21ff0,78d17a41,39036e1a,7af2b9af,1273afeb,a4d30e8,66a3e6e8,7f0d0468,4be6a06) -,S(9fed363,e493f262,d3efabb1,c52291c7,e04e401b,b181290f,7a37af3c,df86aa45,130cc33e,e164adff,bedb1827,6a5c965f,53a54f36,90dfcd6c,b3fff836,703de729) -,S(d166eccd,221c3568,199ebc38,fcbb6140,7a601a3a,c1e7a98f,ebb75a87,a7a1e49f,262222b7,e7c200bd,5dcec562,85485434,b0628c7c,ce5483c9,93795f76,a072f06e) -,S(e7853cbd,3e3770c1,cc307839,294a2e8e,b998a56e,393435cc,2930920a,8ddbe0fd,7977e6ca,67147cc4,965d2918,1023c3bc,cff1e7b1,8fa4850b,80a140f6,980e5a8e) -,S(a8b0feb1,cb140201,2bea3cd5,6b1a1f02,51036ce7,423f511,480f49c5,6227a17f,ccd7c3db,9d3ab6db,6cceedd6,d3801c8f,67afe792,c8977b5,27c9dcfa,75ba8a9f) -,S(57ce5dd9,e1815755,31e90579,74f58b98,6d02e406,a846ab26,c9059f6c,56d617d7,cc34c090,4399f316,269598f8,aa8f9aed,829f61f2,5efc9bc4,e851ac63,fe142d14) -,S(479790b6,4f60fc6d,befbbc1d,365ab3e4,8077b6c6,cbf02f2d,6c8b986f,d0f9c858,157f4982,e3581925,dd25382a,e3e48fa6,5cff911a,95e9bf43,5df8b356,87f2f9b) -,S(55abc7b,1ffe0a41,2181b622,813be76c,8ee0a0ca,3cb37b1c,cb265087,fff17c68,bd134249,23e94c53,4cf9e603,a1dd259,606272bf,8283f2d6,69bedd4c,a971d99f) -,S(6ca7e032,8bf5d67a,b804d431,e5f709e,bd3156e0,1d4511da,1dc67394,24d2e659,c428b133,f3683909,6551c2ff,2f870d80,d80aaaf4,6d2b1a69,7722057,5eca2647) -,S(60df19a9,83e9086c,4cbd20ba,fbafa8b2,346ae4ee,9c1ad4dd,99959e91,2df530d3,dae7b854,29f817a0,421c2f1e,e4e8e4d,a09d60f8,84701e31,d7a8b7b0,3b79cc48) -#endif -#if WINDOW_G > 11 -,S(6f18d50e,5ef5f2ad,bad80ea1,c59a3847,5c22ff05,6ba52c7,e1d26d6d,d3686bce,d1d7ea0f,a166efd0,facf5c83,bc3786e0,d3f3405d,5b4578f5,13a336ad,f0d7d7a9) -,S(b634dc9d,5ed51336,4ac9569a,8ddee9d9,fcdfe00e,65e59233,b3be8a07,2fd949e0,d72e46e2,c61b2575,f25a505c,bdc3456e,fdf18976,6562a1a7,e86d036,eb31db69) -,S(5a37fcf0,2dba24f3,e6646171,43dbc5ab,40d91983,69f5cf0e,4fc566fd,97445910,a960d1d8,13f8746c,662a9582,614c7847,33e6153d,2975cb59,c3342463,75c69d1e) -,S(8aaf16a7,37318032,c60201b6,b196d8fd,eeeb8f8f,1aab29e1,1b83ae1b,f112661c,c461ef56,66a3a4a7,563cc0c2,845f2ae7,6d03a795,987c615d,611bab48,ab9a8e44) -,S(456f0ba5,a05f15ef,d93e7f49,e0729c45,1d85a693,42c2804d,9cd4b8ae,af5e3434,a680f4a9,99221a8b,7f46da13,13041e16,13f616bd,84b9135b,b0f7ecb2,7311cad5) -,S(f89c36a1,f1905409,75f146d9,31e12cb9,4bfdc90f,a178970a,9d0b34cb,38f5c741,3b562c80,58e31b92,a1186615,9c1ffa3b,4b1df38c,eb4a1646,579d2375,9c44099b) -,S(7f6beb11,2e1d8600,d8c4903,1d69cfb4,e23876e6,32f30428,9d2c2503,41f3f76a,a1937407,c0925afc,be994b9b,51627b98,8d98ed6,e8cf6fb9,cddd0ec,a4ff4a9b) -,S(905ad0aa,b585c7c3,78b7130b,ad1d5001,1010f543,194f40d3,827dc606,12d73511,bfce0701,c3ddcd38,150130ae,e91d16d4,a447821f,a2e098aa,b83b8025,b7177a9) -,S(f559c2d1,62122fca,7201e7a3,b6033d1,e54187f4,7550b2ae,f1d51521,f7408b6c,3f10d622,dfd0eb14,7f6f04dc,43108273,7695ea42,38ced7f2,5dc167ad,34154481) -,S(19b328a4,fa17149c,ccae5830,a8bedf53,7c0d8a0c,c3616345,6f4d91d0,718ce8b4,9a1ce80a,2a4e6923,69925883,8e786779,fdff7f09,25d68855,12644d04,9e582f64) -,S(afab98a0,e75619bc,ebcabc24,c1a6a0bf,2743d4f4,921fe53,3a393648,adad5d4a,bf1b3a87,759139a5,79741c09,21f29a10,7c8e5be3,13d75715,7dfd39be,923a32db) -,S(c2cabf7c,1d86a34d,addb36d9,c83a8ec9,b2dfe0ee,8176d085,cca91fd8,ee4181c7,5b32b724,53f1335c,724465bd,6eceb8f5,159ab150,e9c972ac,f51d27aa,4d91070f) -,S(92839424,8e847452,29a8c534,7c14355e,4f6e9cfa,2c1a2be4,f5ad6cfc,2a89f593,bb9c585d,fd41ee06,99ca7b4a,146faf68,51983b15,d652e996,c888a171,7c8c3a07) -,S(bca2853c,389ef184,208cba64,617bd7ad,55e55f12,d0c9fb4a,a8dc30d0,c73c7dfa,9f41289e,f32aeded,3d45952b,16a62fba,fe9a142e,1e65340,17588d79,e1df63a2) -,S(a4ea7bda,94b565a8,ebf53aea,5ce672c5,5745b7bd,37ca77e4,a0e4f281,71bf56fd,c9507485,1405ea90,9b9e1a28,42c5953e,629eef31,37bb0fb0,970cce6a,893e96bc) -,S(71707d45,af71139e,d7327ced,89a2403,da57c18a,8527bb1f,f754e78c,60d5e169,24b36484,fe4da6f3,a3f4e4a8,55a477dd,3eef0f39,fd3c585f,1b9de9d7,10223ef9) -,S(52c1de03,296f591,9d5cf4d2,36b8ff51,5b1f5ff6,d73228c0,7dda706e,4fdf9a05,db958d59,d73d574,384066e4,fda3b785,c9509714,90607c51,35d1d34d,5a344d0e) -,S(7b09c0b0,7852e845,30691989,cbccbb87,74dc2007,df827120,d8b1ea62,2368912f,4edf5717,ffc52817,d0eebeeb,782ba4d,9545a5c,da979f3b,e9c09e84,f82bd263) -,S(e99870ce,b29ad1a8,2bc08834,3e3b3c03,f26e7062,66b32540,681c689d,ffb8300a,8080ad92,78947d65,bcc12dbc,614d17a8,8ff75e3d,91230fad,c6f785a8,cd597f9f) -,S(c7e2326d,e28b8139,85db4cb9,c3d4c5ee,2dd2c2bd,2b912444,adc3a434,205c38e7,5f2863f9,cdc0cc95,1fb87000,e177cf05,d31adf8c,543d899d,195bf5e1,c6ad940e) -,S(883596c8,4ca7bd78,3c586bfd,28fba489,4c6bb66b,5ea52244,1199b55d,3e3f7965,fb114be8,59255f10,c96d6d4a,72945ac9,47a22f5b,68ecfac6,9406bce2,58e9282e) -,S(7f73a648,a19640f5,b0f029dd,37e56e7f,5cf61659,5e532dcf,7ffeb7e3,f20b42cc,4f76248a,f931aedf,b4e2df3e,ba3b426d,8ef191b,9d59507f,4a94ffa8,80ff4feb) -,S(c89ee34a,3660d03a,ce3b5604,1196a66,18c8739a,8a4795bd,db9c382a,9741aa3d,a4a3b888,35fbac57,f2f79ac9,d0ef292f,6838764,b99de084,684d1b95,12923884) -,S(24be4c56,d7dc0c4e,50050cf4,31d81f19,b5c46889,430563fd,566c4ed3,d941d5bc,e07236e2,4936315d,5f0714a2,af1ad769,f6a5fc7,a56fc1cb,ac09a085,f29e6213) -,S(6c31e71e,caa91c00,798ee5c5,3237a9f2,2866a91d,26936852,c4eb9853,e40b94f5,65aff323,2b5f2cd1,c1117e0a,c30b94e9,34543cd9,480f7922,5723c385,9ccf8cd7) -,S(506c373c,8479693d,3e03c022,9b61839f,e470a574,d31fa286,92601ed7,8e58b7e7,4fd0bfd3,a57c5035,268bd4ae,707fee83,e24f8676,e0ffe3ca,1673faca,1b7ab65) -,S(59d9a5f3,ea1a6cc6,16e7b097,871f731c,57571a09,1dc01b45,b48c5332,c98349a4,94ad373e,ee6496c3,263c348f,a7ee539,53aadf13,1aa6b638,21c16e0d,55fc8447) -,S(a524cfab,65371648,f641912f,a6ce67d5,c6f8929d,366448d6,4de381b3,22d75c69,14c26ff9,87fbd599,17a6ae90,bbe7c79a,ac1b6158,c3f46144,71aa36a9,45782823) -,S(126c986d,f83c6307,87c0d3ac,6a6b2393,8aa3fdd4,df26e76a,92af2c65,7f48c550,808539d3,a56a6f8f,3bcf04dd,31ac72e0,3f74ab1d,5e9afd39,7741656b,3d4c5c5c) -,S(32cabbc0,1aebcfb2,7e1a9d5b,4cd05550,d8ff25d7,b9a81db7,3188474a,ce39722,7d30120a,e08031c4,12c070f,6ee6b52a,be191021,faa9f5bb,9576feb1,8fbccee9) -,S(3fde1cba,f7ded6f8,a98975ab,ad5a64aa,8a9f0864,16dc25da,359e1cf8,22f42c64,e50fcac,61f0f174,b0e93cae,691212cc,44ffeda1,60dcff91,9ee3c960,2f5ac075) -,S(9cad22ca,d6c3dfbc,1d3a08d,6b102727,36e9db37,1ee1f26b,3ce932c7,11462e24,5ae84f1d,873dcd04,7f0781cb,aabbb53,422bb119,4e59d5a6,8824db95,50461c6b) -,S(9859020,aa807626,3a8ca18e,91c1afad,c20cf9f,9249c24e,1c652d19,7d5872ef,454323fd,21ab7d6e,470976f7,2d85fa39,a084e7eb,b332edd6,a3d054b8,d3c73e69) -,S(821699a3,e7cbcbd5,a2b093b6,c825281c,ac00bc53,c44b33a9,d8c31b9e,464eb2b6,f7d59c17,2400cb9b,72b44cbc,bbbd3e9f,e62cf451,bce6f840,23b073ab,66a9726a) -,S(bd06d4be,36423862,795fc7a5,5c48ceb8,440b3cc3,fc286dad,74ea7f6d,8cd370d9,3b09193a,fdcec88,ca4a5663,2cbb808f,61bb1253,fbcd1714,accd508,6183b90e) -,S(2c7112e7,9c8cc78d,f04a4ed0,e043c6ca,bb4b734d,9177f822,5bc41123,4bbdf4d2,c81ccfad,d42e2248,7612884a,d900f61e,bae242ef,65ff1afd,6e03ec42,38391243) -,S(51ae390f,a65d772c,833cbb8c,9ddf9ceb,b7f5236e,f1983905,762b7aaf,e122131e,3d7c9f80,80406b06,282f2a88,87dbb714,f1e96e1,e84eaec8,1256e1a8,ed7ba06e) -,S(c59de112,de237a43,2bcb8348,e3b31356,c7432672,6b9167a1,77d826e4,dacc59ea,36109f16,7c5eb66d,9f09c1d9,c5e1676c,aa33e403,a8e052b0,2854c689,d5903b25) -,S(8b99f23a,b7509d9b,151cb89a,45753026,77ca1e6,9219f0f7,57d01823,f556d978,86a31aad,f53afe44,f533cf0e,4bcd573c,d338e12f,904c8e9a,dc8e0080,f56a4164) -,S(4c670f65,7d6fa9bd,9ee4135a,1ef1882e,61f5fb7c,9deea717,39fe0ab9,78369dd5,531a8226,5d4b5363,12875dc1,7f891d1,b54e0435,1b539dd3,c100b797,efe65417) -,S(8e967e35,9daa0f95,fd7024e6,e57f0640,36aed9dc,9df0f33d,9388cedd,e0f38548,36f8055b,a59afaa5,8c88b833,ba110381,45fa0ab1,f0160d2f,1f1a1765,190d218f) -,S(3f611915,9c45a37d,5c7bfaa,cf0cc959,5e2e097c,8c7bc3e,c82e9e33,3b2ac9e1,c80134a,b7437dc5,23e08757,8eeada53,b9d2f3ee,25b754fa,f6c32e02,d597d7d6) -,S(3f59e49d,7c61412b,53fb203a,c7ebdedf,66bba683,87070745,9f85000c,f47641d9,bedd7088,4243dfe3,d238f101,f5dcd4e,64cd0978,986d50f2,ae3e2563,a43ad5b0) -,S(5b7d84c9,b64836a4,3bc44b5b,fcf170e9,ad46d4da,197a2781,bbbcaf87,5bf6d490,9f55b29c,c7d6b0ff,facb8975,507df04b,f2164e5b,9928156a,7c73fec2,b34d984f) -,S(e1ee74ae,ac3e83c,f73bf1f9,aafc3eab,90decf0d,a071aa88,962c29ea,51744b1c,9e86d2f8,b34e8525,568d674,8839839d,eefbe15b,80c66216,50acc508,f1277030) -,S(fa1ccd5b,8d489448,e3196c22,e96ca7ed,eba721ac,beee200e,5ddc496b,6beea871,e2b7f59a,326a6654,9d6479a8,a7a56d7e,8513504b,fd2a9829,d25e5855,2f9bc469) -,S(ef1e1cd7,f386096,1f6199d1,ab4a63ac,b292316b,f7a5e7a0,4c9f0c3a,7bfdc8bf,4cef9c01,a9de111d,8395dadc,e411e532,5783d377,559dc687,eeb510c2,ba98ef05) -,S(db714eb9,3e75d3ba,dfa5cc4e,d4813db2,fe9c395,95a1ee8e,9b3e468a,e1326120,3dc49a86,b81278f4,84d30311,c8816840,fa3cb701,665c067f,618295aa,6a71a206) -,S(5997f38d,bd572858,43ccf936,ee9d3feb,d70c79c7,9ad1c452,29af32fe,e6ea5d5a,adf7d862,b716011b,b9749e08,965c1ddf,1f44b678,df548eec,45a69a56,97e4a224) -,S(97d6f6d9,a920577,7b08ae66,6fc1fc7a,956654bd,3bc6c039,ea4eec3d,3bbaeb92,b450dc47,ff219854,dad5ab97,13dfbbf7,ce03fedf,4e7ffc68,4bdf1b5c,c20068b9) -,S(4f453fcd,5ec8b72b,69549ae3,c4eef99c,40232bca,1d6b10ab,c4b00d00,5ad307c4,aaded568,c4a8bc87,c7a442ba,f960d9e8,bd61f15e,d668f816,b94c0d2,9683f7f) -,S(5a604a3,50593035,c71c0a6a,caa7946c,ae4c4490,c0db71e6,49972705,949424d6,e578fc12,6d8701a7,a02b92b9,3fa89d09,ae82779e,2f78586a,8937a6f4,133be9c8) -,S(3f3071a2,916832fa,1b64cf0d,5b5fe8ee,2de601c9,34e08498,5d118696,7c635b3,e915b199,baeb233,b22adb6f,69df0e43,8712f25c,1be4470d,53851e4,451ad3a3) -,S(745bc1cd,643189ac,fcf02c5f,bf99c222,f7476a6c,2ede6c45,31849491,901c06e5,59a2bb4a,8703775d,e9a519bd,10e59db4,be16cb41,d0275d21,87291d06,d29933f0) -,S(bbd06e8c,adb3959d,853591a6,6387989,ab396736,8a6c1942,17580911,2637238e,ae0d8296,b484e5f3,dc46cb88,90b86a4,d562b003,a65a0c2a,2b4eded,38b8b690) -,S(fcda8db6,128dbe66,850b7e43,63a3b35e,9f3eb569,b7af97a3,85e53fd4,922cf07c,4bf3ddfc,37a0f9a8,5f758ee1,4c4d5c86,cd11f1e8,2a05ff28,3a0f535f,f9551974) -,S(6325dfdf,fc9c7ded,2a65e113,27210ccb,4ed2da97,4eded570,5ca1add9,9873cce2,89fe4c99,683e6fc7,170ada7e,26179fea,7ce1930f,af1a7358,4d7d56d3,4cf222e1) -,S(77594ca6,93495096,3ab5797a,5279d0a7,513df59b,41a3ad59,245e3f29,22ee0d7f,195eb112,2ccfbfc8,fdeddf45,ef2ef58f,631df03b,ca66a4a9,5818dd83,e5faabb2) -,S(f356ec67,ea9b242f,4f1348fd,c6592772,e2defd7e,308427b,ede15452,baa67867,3d2265b9,e23f8ea4,9a2b7145,9c98b03f,d75a2110,8f104121,e4a2fb4c,d633ba7a) -,S(3360ae12,9b0fa48e,c78e3091,4f8ae6f9,86149f0b,590a12ff,cadfdd2e,f8a205c9,79b37bf2,720d5a11,3ec09872,22b0a626,3d7a2051,e337cb83,dcb52df7,25d18a34) -,S(44e90f52,c703c50d,b331a4c5,fc47613f,b29040ab,9ff0f282,3fc15ad3,f9e8727b,62dfb341,92653e6f,636d013a,718932f6,95c2491e,26d16feb,4009ec05,e2f55f17) -,S(e5d367a9,b5c3ae22,31195876,4b28fe35,c9e04289,518aa09e,e7902b5e,4ec84047,ea1b257f,1abf0fa,6fb37c06,907052e7,fbbc06b4,c2382ace,9c9a98bc,e6f8bcf0) -,S(8478e8fd,7910e5ad,3c061e6d,422806a5,559baab,e083b8de,1005413b,59a63957,4f793418,5193499,13fe38c4,514bd4bf,2f3f1ebd,b492fd5c,fd8c1bc3,1a2df1d6) -,S(c38327c8,587731b,f5b5e224,79c9274,10c97dff,f6855b6d,c2ccf761,2a84b42d,eb03afac,cb1b102e,7e87d61f,5012ce74,a213fefa,b855db22,bc657d52,4dabfcd6) -,S(b9e8a812,5348a672,558f48c9,d17f28a2,4662b4b6,604ee14c,d622b521,bc51f10a,35c2780d,65fcd07b,51ea0224,1771b523,3813e7bb,97a1744c,e3dad732,ef1ccfee) -,S(a54aa2d5,95cfa325,38d2e483,70ba86af,d3c3b53d,2141b0fd,cc68a729,a5cc713e,bf74dc6e,63c02b2e,e676b9c8,6a851a48,7e9552b9,a32eabaf,4e1faa06,8bb8a159) -,S(d45fec3c,e2df54eb,844ad145,fb8884ac,420ce2ad,85cd55ea,4cc19e1f,da9fd956,ed8cfb00,65aecb6a,6901dbf9,b8c208d4,bf6be1e7,ee74a08d,205c48bf,8cb81bd6) -,S(f4b44e98,f728b318,ca959829,d4cd836c,5c0136ab,8e433101,87be24ad,53192172,ef5521b3,960bce49,2c841fd8,8cf7b8dd,2febdd8b,f0aa64e8,4d3c2a09,89ea9fa1) -,S(dec6d1bf,d349110,faa0cd40,e8533078,dcec40c6,e260b9e2,8412d424,353d67e3,73a16f81,3609c901,71efe44f,32ffc90f,9451b0b3,24107b72,54ca2fba,65095895) -,S(1fbcdd53,72e17c41,9310b9c0,2273534d,265f1c24,bc1a6039,238b5b7a,b3ff013e,9cf4ff4a,6a61c11,20c4d14b,97275547,b2358f75,8a2a774f,22bc77f2,4c6c27ca) -,S(d9cef0cb,38c6ed7,7aed53f4,93a31daa,50ea1ff9,aa43b890,357012fb,e2ab593b,32a416fe,246872d5,b68e6654,7f19dda5,e161cd13,ed041486,4d0c2dd,3653303f) -,S(1641b549,88e22a18,45e2135f,88d2386,4e2f607c,ce33fcce,de174a60,1ff03da3,edd3f0d9,ed718767,3664e1b9,540f816d,48e3ffd1,cfad86fb,5b68dfbd,7d94922f) -,S(99ef6c16,3c5d9ffb,1b638b21,1ef60166,37938f83,ac4ef76f,96c5366c,3a243cdd,6b6eef62,d819581d,e1dd7796,df043e02,7f912bbe,6ba1e499,a311769e,d6f66b48) -,S(49358d2d,c24c2e8b,80ff79b0,9c53645e,b9c47fb2,8ea4ffe4,e2f4679f,5b5bc97c,512a14a7,f9df40eb,ef7c1cbf,f8e1caf7,b8c80748,7bee3865,37837cae,dc1cf5b4) -,S(e31d3fcf,b1dedfe9,2549c5e1,a14cf383,c8c122a5,a430aee8,a4eec846,7ceb206b,7bc3c266,69db747b,a3ad1dd,e83464f9,effc4dad,b4de7687,e6c3ae56,a5b0449b) -,S(a82ec9d6,ac86bcad,fbb32e66,a28d7483,ad1fbb7f,979a15d4,4e324ce1,86c64adf,bac87d2b,c28b1ae5,f4ab46f1,ac779936,3a9efad0,b1e1f81,6c4ec6d3,cf74c89) -,S(21650994,2bffa2e2,479ab82b,18cd3aba,dc370c3,18c71c08,1bfb53d4,c8ea113d,97a8246a,2f653450,be513b6f,62419f90,f84511be,9a5f3103,feca77c9,c81fcae3) -,S(735050d8,208d9688,7fdf8070,e448e905,e4e666c6,3db5857f,63ceb362,c6dd4b84,2e3fb438,563661c9,e6fe23f0,7c8219ac,216887cb,ad307918,90001f9e,2ab9e2e9) -,S(1d021861,e679dc08,a34c3813,bb9c3e9b,65f87800,79dc08ba,197b3b66,47afe506,14b6d0b9,2303483d,9e92cd0,e295bf08,4a10e84c,ee0b7c50,ceaa6ba7,a6fd2f1f) -,S(7a7eee74,86ca8973,a858c15d,54eff96f,f91c5577,4985433c,1bdc4f4e,46d7810b,5e83a07f,5d9150e7,a7f5057d,87d19ccf,448fed1b,bc1e2297,c7012cbb,77b498cf) -,S(811c3d4,fe0a3061,47c05cce,32a32ada,48593802,32f24b51,f50e726d,a702beec,a6fcc16c,6c9cf4f9,2e84214e,35ad8577,b28e599d,31ed74ef,c95eb2bc,833d9f0a) -,S(2ca14438,89ea9e8f,24d5b1e,e44b26d3,ca25ed08,30ae950b,4357da49,21ad606c,7b48a6c6,92d8a29f,a82c656,f8e6213,c5e90be3,7413d86f,42e10e63,1026c551) -,S(a980ffe1,61041afc,339566d2,957e6624,5dd3e0a5,deee9c80,d57b1f1f,390277bf,3276f7a2,a139343b,87744079,7a174d99,457d5005,71ce47fd,10e41456,7a1c64c) -,S(e570a3d9,cbccb74f,c582954a,998d9371,fde41d98,e65de6bc,9579d6ea,d9cd80bd,5a749177,6658398e,99d3035,12c168bd,9400bc6b,c7dea2df,2739abe4,16973a52) -,S(f5fbaab8,952cf50e,66d3d985,d9280bad,71bd25fb,662358c9,72b954c3,7bce1110,1aca2123,6179f821,a4f097c9,b48a744f,8010818d,3ac6cf,b02f57f3,1fd77175) -,S(2e5942fb,ecbda8ac,15408d25,84ab7c75,6f9e525e,c4dbf375,5559dea1,718d89be,95106507,d14199a7,8f123d6c,f6b59262,30e12a1a,8c0ca016,40c556fb,14bc790b) -,S(92bd04a9,891c99e9,6c9e7f64,a9bab705,a9fc83f,a739413e,a2f33001,b55dd296,cf5e3733,659bfd9c,e5417ba6,817b6a0f,5cc71c34,22165fbf,13019fad,822ba587) -,S(30ddfd9f,a50feae1,e3cc5426,93ddcd62,4d0e52b0,867248ff,ed7d3041,a7b11083,ff15d0fe,2bb183ef,a18389e3,df4269ca,21bdfa0f,87ac641b,14bdaf66,26eb42ed) -,S(8cf5150b,df8ac68a,af319688,245719e4,67ddddb,72fa7f1c,baf39de7,252a9f4f,4c28497b,a299bb19,83b18bc2,508c98d8,2a9963ab,4145807a,2130fc05,4186cfd5) -,S(1f4b4efd,50974efb,3caed9f7,4f6dd979,4a8e3c09,8decc1b8,69032885,265e46c7,6c4b04c7,f7c6b00d,c38adeb8,a47c7c0a,68535229,26500a76,ee1c6feb,179fd399) -,S(9d524900,979afa33,8d5883ba,d13d038c,3f915cb9,f2e29a2,2a028b18,d091af81,409a113c,37c732d,1104453d,6b161d33,db3257c7,b9a73e1,e0f1679e,6802be38) -,S(52e1e4e4,46eed9d0,fd5c124c,1c23403c,5b03984c,f3fb0734,c627f34b,dda2e3a1,674a5731,7375ffa8,c3c4104f,12c1713a,e2dbc630,75a77e5b,26243217,88320a7) -,S(827b171a,8eef4e31,e6ca8b6e,7c6e36fa,e0a6c93,a77d7148,fd22f7a8,16401c8b,65cd85fd,d9b801cf,7de6d14c,b78ba114,1d58c7fa,129f9f08,8275f364,f7ca7540) -,S(124f45e9,61d89642,6a1abc32,e582e246,3db29954,1bea0383,c83f917b,6cdf2f9b,734e2fe4,110b65b1,2d60626f,c6288f87,e48e7a7d,213a4f83,58bb4d67,978d6c62) -,S(3b71298,18b2b324,10e4f002,899204c4,fb4ac9d6,c08d1169,5f5f5699,9a4d67e2,28b6f78b,cee16b5,5c010c51,ec465609,54ba6368,a18ae218,5607c1fb,42c27c3b) -,S(d271d87e,63b5363,e664485,ea6ae70e,e2b887a1,c7f7e0a4,290033b5,512d8a00,65d43804,7865e280,273122ba,8d8644d0,60ef5927,34971c9b,510238eb,9d6da847) -,S(1d1c6d85,2db35160,67cd2d82,e2ba552c,c5ca0c9,ae7bd661,e8494b25,cdc03a7,bc31f4c5,673a0256,ee9b6840,7aeea035,e19f874c,bdd7aebb,ae8b1005,4e691f62) -,S(8fee89b4,71e394c0,ddad274c,ba07de4,bf8d2ecc,695647fb,1d3756fd,46efdd9d,5d5ed0c3,8479578f,d17ae148,7198f9cf,4ba5cf71,46a9b4c4,34ca62f1,bd2b8c6c) -,S(681fcf09,55a0f351,6026302c,ce3ee475,8ef9385f,908dace5,5d7fbd30,8810a6ec,4307f75b,99927624,80187edb,c4c6575c,aa54e8f4,190f0885,e6d358ca,2a38faa) -,S(717fd6dd,fcb5a71b,6a584a28,904cd3e2,6f6c1a89,7fc32918,90792937,b3a6971b,b403f829,71d4ad04,dfc40553,27f6da8e,1b05e25d,341d6511,d7cd859f,58b17992) -,S(f2b95723,94eb9786,dc1f4998,6ad8c340,d2983279,c7323a34,227013e3,754f2ff6,b553d381,3efdcd41,7189645d,d9917b73,bb69e705,e7a6520d,dbaa497e,7766763b) -,S(58714be6,d7d86c89,65309b52,414135c1,9ab6fed0,1d56d7b1,4237485d,96730b1b,c011f34,3e38ce5b,deab84ab,f0e31537,4039845c,5fa4fcf8,1c9a4d5e,6fe3e533) -,S(d33ce5ab,c828f8c1,b9700d49,e9c6b4fa,b30819fb,b2bea23b,7f915bc0,7a6ff3c3,739b6222,39134988,22372ba6,3fbe22f1,ef59394f,37db956f,caca4c11,75a23395) -,S(82202e32,fc7d0128,4eba58ff,42f7d94a,24904808,d6f920d5,9837b26d,63b55479,fde63954,50aa55e4,fcc4fb0a,8ac2c880,63aa3202,9a00004d,edd033b6,2563b4c8) -,S(25e63218,5bfb4c88,fa300e37,c8b64a,941e6487,a34262b7,419fa7c,2dea7781,ae696b07,4802ab99,4df2d84c,c6731d7e,9caa124,548c2a11,42ddcdbe,f716e640) -,S(e0336a05,b9254e1a,f2468a36,343a0dff,9da8773a,1efdc487,53c1a95b,605c114e,41d75960,377ada38,79b97455,346266c5,5ba05915,9ddad050,d96d9d8b,afb12a18) -,S(843363af,7fd2b1bd,1c9a9253,e42489c1,34ee875a,db57b752,62d731aa,9a996662,e5c0a2d1,dbfcf013,ed4bda36,f153a328,12c4b3b1,66e48473,4d2d3562,ffcde6ca) -,S(adb210b8,1cdb7f18,f97955cf,fa7e5763,abb9f202,9d283c05,26df6332,951178de,2c211f05,d8182aa6,d784721,948afa11,364db5ec,2e1becf0,68eb91a5,74ea0e35) -,S(ab0c5fa1,a2fe2235,ee93854f,59a13792,2034604e,5857b6e0,88b65142,f24d7491,e54725cb,e36d6e15,71ca7384,7383553,b9dc48cd,eca6932b,8d92f785,b80124d2) -,S(3e5de77a,1d2163e4,3f3124b0,af4f5473,868a080b,67acd835,f9cbc88d,7885deda,a6ed34a4,2f9503b8,b83e66b8,377f514a,e1927dc4,c37ef6d2,254e651d,15746630) -,S(60c68b3d,31d1d326,5b71f068,8f32f671,32184815,f83a9ceb,50eaef6,4991ec05,977acc61,9f7d24c8,a95aecbe,987737a5,89886729,500ed32a,9d760fca,7c00d498) -,S(21b052e9,b646e595,b6c04a76,a66b9b25,4a126729,6bea0654,64fc5b31,69c135e2,1029e4cd,2fb3d717,6e87292c,4b0dfd7f,18db6ed4,59aa9285,38f0989c,540779e7) -,S(700caf3,7c664515,ee501e66,60be4cca,f58bb2ef,5b11f79d,c027dba3,7b523d68,7df76b88,f1c346f3,2e32487c,19957830,8eac9b7e,56edc948,e1a934c7,6fa08be1) -,S(c5ab9bd2,1293844a,ce5f1c9f,56458315,5d34aeaf,565a5696,29969664,49541e8d,2d2081c6,c61d6c8a,a0df4467,8ec53a7e,9b34d90c,57db2f29,c0361304,1c422d8) -,S(8afc3f2e,d53f5dc1,448d15af,8c2151d8,5713fbdd,5d46a3df,a4ad376a,16d75a3,11f6393,2627bed9,e015a99d,42193e6b,6767c513,f3457897,64db1a4e,4b9b6c8f) -,S(414ad9c6,bb55eadf,cf4cf729,27ae3682,c0d69867,ede9f4d8,6e173c50,3a5007a7,c4bcd0f8,f4de9b1d,1102306b,667a546d,dafb6f82,edbdffd6,181dd3a0,8f603585) -,S(8211e240,b84b7317,a9c5ec88,fdc426d1,a163a2d3,aaf088fd,b2317247,cb04a1e3,ca76a59b,b268bf51,4f06c4f6,d5961b33,a74f10b1,70a9e9be,4e7942ad,26722bbb) -,S(a54dfd32,363add3c,75ec4452,3094b27a,3f7cd291,43ee52f4,29e59daf,22ba700e,f160822c,59510098,3e38d130,49b44865,3639ac74,6a93ebbb,2798d92e,bad4490b) -,S(77d64c55,52b29b18,a7aee1a8,1e1e9d3f,e2921a43,cfbd95e9,a3ba7cb9,498860f7,e97bb8f9,5ea9c8f4,440ad9d7,36d9a06a,fed03a9,cc96597,8d06f2e7,8208ff10) -,S(485b3814,b33e6bf1,1f47f0f5,f0e5a189,1b57c103,60f13d61,ba7947e1,6e309ca9,e6bb7870,ce607c62,a6050dd0,946c8653,f998576f,2c781b5f,15282632,4e38bdb) -,S(ed2381ec,a90a78c2,def618be,1b6edc51,7ced2ac8,14aee9aa,b0a7068f,72739c,cb0873e0,ba326452,380c291e,c635381e,d6859916,2ca10fbc,3de45ffb,134954c7) -,S(e444af79,d36bc127,c83c7369,a4cba0fe,955b6a66,8f2e7a68,4a65e57c,44ed971d,a7876f03,27b6823a,aaf55ca1,6a48998a,ec50e5de,10d34e9,dd7c554f,d3785fff) -,S(af8c34d7,7de75a2d,5f64296c,152fea4f,b8677b8a,96cb278c,7ed7e50,69fc1fca,48ce5862,ab6ec1a8,ce55899f,24632be2,f3c451cb,8b81ca8c,f9ecc3b2,2984d673) -,S(e999d466,243a44ed,18e745a8,1da04a31,8940c88,760480cb,e315436c,f67efe13,f41e8e70,63a84661,c22ac0e7,5cdedbd0,ef55d3eb,7fa813cb,2f7d1fb0,237fe36) -,S(c40ef8aa,7d8964ff,a3cc923a,2fdebec,72cafaa,58b72d66,e209b644,604bcc72,480e35b5,6549a1e6,f112c3b6,176f3378,ff50ebc7,b3efac2f,696f0627,b7238ce5) -,S(482ee41d,e3f9499c,8992b546,e209aa5d,679e4b8a,22a26615,1bd1b0f3,9a52982f,510e6070,d2131815,2d52eff0,ee10ec6f,563f92ec,a0e549f8,32efee81,dcd3de3d) -,S(4660a468,25a3c1d6,67003c69,4d36f8b7,6df7ca32,c6029fd4,65dcf726,5c58fae5,3d982bf5,46b5c296,988acc72,2dade97,791de8e0,150397c0,700bfa10,ba23f618) -,S(b85e624c,92ba6f0b,3fb1dc03,37589994,d8a3aee1,76314d87,3c8bef0,eb5d8f8d,88936b33,20a55ba4,24bff93e,fb36ef77,e2cdff26,866cd486,88c61868,ad75679b) -,S(a41920b5,361a26bf,bd187eba,b62fd5b3,b3be282f,94ef94c6,b1698754,902683e3,7790a196,29d93b4d,3d27201b,32053e02,c95a8f9f,260647d1,491c7a4a,e15ea98a) -,S(93882da9,79262a60,3252f01b,bf101d89,ed1abf8b,15507937,55979f4,fbb7f86e,938884d,f0a716ef,137450b,ad5f022e,23e570f1,3ed37e02,15a40910,189d7e44) -,S(a10509f8,3efeda60,acf56b64,3709b197,ebfa6a59,e66efb06,79c23225,c8952e00,759083d5,559bde4d,9a37df5,24cae4f8,5a06e7a4,7c0e15fe,830f0677,c24d1ddb) -,S(2b945a97,6ea74278,73d7e587,dfe75eaf,c55de704,8aa26d29,4b3b1ef9,2beb3651,423c07ed,27ccbf6b,9d1cbabc,e00b451b,cb488d10,e5daf752,6980ef65,6893c65) -,S(86f9d9bb,c1a0bfe4,e03da0,13f17017,f6951691,28d51073,b594457b,fcc37f0,f370c624,2e303796,9339cd4b,fbc19e8f,62388f02,649247ed,df3c6c67,464c32bb) -,S(f8995af9,555e044e,6238d895,8bdb4e13,3aa9cc0f,90a9206c,16d0f83,dd61ed91,b2d4d2e3,1bee12c8,3b8bdab8,34fa2e63,1febdb93,4af194bc,d0825921,4ea8a060) -,S(ab55a27f,69eb352d,455eee7f,bbc1c74,fdea2621,63d09dbe,2f554417,819394ce,8ac56493,60f585b5,72373bc1,74a930e2,4d54674a,89789353,4a166200,e31b801a) -,S(4fc106c9,c428df98,916a8906,95e98353,ce84723f,fadae522,e8a89916,a23b9fa6,90d732e8,3d54341e,4f4c88be,3392687d,fdebbc4a,7c19afd1,92531688,9eb92031) -,S(c9c85980,8831cccb,77d87b25,73a894e3,874080db,ba076b2,4626bc82,3149a91,9fad4ccd,8c0949f9,be9a6355,f0bdfa36,c5f99268,780566e6,a6f302e3,b2abf0b8) -,S(c0cb5b7e,2293abba,5ff78c46,aa1422fd,a278eb5c,ddd58cb7,aee77149,1c5209e7,8101f42e,36648586,5db6b572,d0df4ca3,cc72789e,ed8d27d5,1330d733,4e10c47b) -,S(dbfc03c5,16d93f83,472ab60c,391bdd69,af2f70ce,fbce15d,140f1590,d8ce0b63,f838e14d,7228ca2e,9a33ecfe,c376aa4e,4811fa24,debc7b46,4658c153,fed26564) -,S(de260685,eea13ff1,1571d891,35607b0,435140b9,62e3baf3,7cc3f3d3,484f59c8,6bc23ec9,a6025865,e6363335,bb66f1e6,c1f5f54c,aa5f8acc,d7f8fae5,99cfbbcc) -,S(58d78d60,b8cb8fdb,1b62f79,f6c17ebb,1ed8129f,c7819e5f,6f73c58b,faa2e71e,7cbbe4f2,fd6bc671,8c222f5e,16391133,b04d6d3d,bb263531,40aa4053,b44bccc1) -,S(e72b9b1a,eed54fe5,ab0869aa,90014e3b,fde1af12,f646d738,211ebefe,2c00a490,cd92d14d,8f595833,842af020,a2cc82a0,d9465969,77d25d34,8cff3273,90af4fc2) -,S(6a86bae,d55a5be1,8b7cef97,c9dff8a8,b725f614,2221485b,3b9f348d,570fd658,138a2691,4c3b3015,10312140,7709fa87,60a14f14,571a9d40,81c06d67,ef2c5724) -,S(1ca08cf6,7240f244,d6cb0059,564fc283,b17c39e1,b624716e,e100aee,bb0a1fc5,22e24fce,655d09ec,34a36317,c66adf07,deec2743,4e9c016a,b3447b3f,d9ef0a55) -,S(d95dc128,feba49c4,73e1ee30,bcddf76e,b7cf628a,fd495607,f558201,824a0b0f,d5340ab8,fea3e137,d1061274,c69b68e3,633e98ba,ae2fe116,1612c4d6,c7c7e8a1) -,S(2cccd22a,7f4fd501,6c3a14e4,769a88bb,ae7e288b,d9987afc,f3c073f8,ccd83857,ae82663c,aea89fdb,4710f849,ff8e4fb8,c2a7b614,4edb5f3b,f2564dd,73b389e) -,S(ec17b5f6,c8e4de23,937bc003,7dd7b411,ae4a9ac8,1f2801d1,c5eebeb0,95628a43,b3e0d51d,fd5815b0,631fa298,968fe70f,74319620,f0798734,8e66e6e9,6658df83) -,S(a63aaf7e,62907f4e,1a613cdd,ccf1cc98,cee8e12c,8bace3ca,95685889,6c96b6f4,2f953ebc,dc5f9973,e9d44ab1,23255a21,f8bc1a7d,e800cdee,ef754031,aee8216e) -,S(8eb4ff30,318d8d0d,6b45636c,b296d137,90e345af,19a14b2c,550e0169,87ad32f3,4b8e238b,ae7ffc7e,7d600151,c5ebb776,cc01d51,827f171,8f28af77,ca4a3e3) -,S(ab1420af,bb5b4397,f578a6e5,74a63aec,2432fa8c,b4712341,4374add9,8276b8d2,faf6328e,a197e927,65b9df90,a79558b,8f264acd,7f75b574,90ce657f,64b94396) -,S(daa1890e,6b2ba1aa,dcc16f1c,c1d5999d,5102aa6b,348ffb5e,9630bd1a,886f680a,19facb69,5a63eb94,cb6f6005,cf2bbd23,8744f05c,2c220510,94bf6dfa,352fa209) -,S(f199f52e,5398d1b4,899a1b0e,df8ebb73,cb08a642,bd22ff2e,b1cf647,7f2a28e3,3619abab,a5e2131d,4ccf8747,67ef9b75,2d5278ac,5549bd9e,5c1b5985,9ec2f454) -,S(182a9e93,a5f9ecf3,6bf20bc1,497a4a35,e75c86f5,9c9fc046,e2752223,f046ad6a,c6095e88,c39dee18,ca867693,d85617c7,e0924dca,34af07a5,c731e488,ffb8bcfd) -,S(8a4cb53,636fe66,b660a701,64277fb2,5ac21eae,906327c,3b509954,b214abbb,693e5851,4cc6a941,23ee707f,ad25d638,8efcb85c,25500bbf,63fd6926,a1d0ed1c) -,S(4901335a,3b40c33e,115e3105,82c55972,f495178c,813bd8d4,2b208916,5c8c1282,47007176,429d740d,dcac70eb,9e1f0e94,f26a9a0e,4dde0166,24d9d801,c84214e3) -,S(8180e5a7,7c34362b,461b49e1,4b9f2e05,df64f55d,cad82b8f,cdf41232,984e01dd,34cf5621,d4b9f100,aa34b0fd,5ac91d,cb3fb49c,130f3e65,de742ac,af05040b) -,S(8f71227e,fea9f4a8,9dcaeee3,58eaa5d5,a90e1d7c,b7d232a4,b1085fe1,3651ee9f,a4da15bc,bb2b79a0,a27c344f,3b914c7f,e272676a,bc045aae,e90daf4e,9655ad73) -,S(dbeb9b74,cdc9bacb,83592a2,a3cc19a6,d1ea8eaa,5a086a3c,cc68d423,cfb58264,be668792,83f07fb5,830732eb,79e16bbc,18e86df9,b659e2d4,5b1009a3,40576161) -,S(f328e93f,a7f52cac,3c7b09b6,280528dd,7d9ea4df,8317a958,ab0a617d,71591933,41ce8c59,811f9e90,61dc3f3a,7d85d394,2f780c17,d7ebca60,fc042311,f2405547) -,S(56d4f403,416b1bec,49c5f44c,2021c245,d4ca4181,5131cb7d,8fb0cf08,30fea051,cc5f6133,948f77be,934cb637,3d5dce8c,51ae1a92,e3d802a8,d35a3ad8,50bd39ce) -,S(8e22e04b,8bb476b7,ccebecf2,a327fd41,dd90c9fa,67cfc49,e9cf4ebc,39022b8,1f8fa60,3204696d,34d03c02,31d3ef58,934e7992,c2c81d6d,3e4193b3,8286b8b) -,S(341b22e4,b9a77c68,f93624dc,1cfefade,b396eb72,bf9fce1a,51867d7a,ef064f6,95839f87,7bc36957,59562bcf,dbcb2db,af11ed72,7d329e27,cfc8ff8b,92d9441a) -,S(3ea42e93,9f234112,879e8680,94fb8a8c,e6af9799,c000b050,45eb2026,3b324763,44324167,6f5aa6f0,4fe4d51f,fecfa8fd,60a5c0a3,38b16f59,1866bd51,2e01a623) -,S(afe7b44c,ef10514e,f94faa1b,b8cde91c,23d8a660,a71c3173,42f927bf,535d625b,7617a788,51218772,bcd51f18,54b063ee,6cfcdd77,7a388427,51cacfc8,7c8b4b65) -,S(a360ca02,abb40d4c,6e0ac725,f2c035d1,12f69ee3,ff0e1dda,37a3fbe6,a2034d2b,161e7178,3fec3ea0,305d0f72,3a60846f,9d8bbe79,255a3814,fab83269,916b646d) -,S(10484e5f,f7d9fe7d,9b65d989,9b2ecdf7,5984d18c,1199f61e,c914a85b,78011b88,12d1c0e2,1e137357,9ede1086,c2c1449f,e7f4e03d,78f7b184,4f744d6f,9576cdc9) -,S(76c2dce1,5dad9ddc,24276c40,eda7de6a,b11245e6,5b051ba6,7eec39c6,d256b138,d9a601ce,585b0839,92e3fca2,a43739a3,61a8967d,3eb0f605,ed4cef15,fc64ce82) -,S(671a31d4,c3e6ed98,b044fcb1,83dc60c7,d1d83988,3a547356,27b99b75,11d4d2e1,6fdd8d15,2005ef3f,7ef3762f,bf43a849,281f185e,a52c1b3b,8ad371b,e053088) -,S(91d0f565,a2da6903,12b72998,57f71c18,c2343a5b,a6f17243,1bee12b6,6e898a37,9d6a55b9,1956a288,d56906a1,1f7cddd,e6393ad6,7249147a,41eb209d,7f32f681) -,S(7e59f058,1953a2c3,cbd4d0cd,8f4df7b8,6b90d8de,7240b2d4,de9ee9ab,628512ba,33b0d1eb,74cc7d60,ef419b0a,f9f03714,35a012fe,328fbdbd,9d9b69bb,9a42a173) -,S(ef78b65e,b791bed,212652ad,ab1f32ff,f43a285b,e040380d,d3492afe,1f788a26,9f3e2538,96d5afc2,3ea7ab1b,24ffac00,f156cdef,93957910,abb1cd1b,6508d306) -,S(78b978d0,199833ee,417ce2f5,fc12cb01,cb0c0e4c,ee752e1f,50a8cdf9,b56b7cd3,9f9c7dd7,372606bb,e3170141,31591f5d,dd631f91,71460cd0,19709478,c1560dd9) -,S(5f785b31,f9945a20,e992f5e8,80abab72,906ffdfa,7ba7ccef,f1b3d26d,70bfe64a,a3cc480e,b3cb386a,ffa1988d,3227911d,57522413,e5d0846e,a6d0a17,2b881c1c) -,S(9fee7999,7cbb492f,cf3aadfa,44484d71,2c3887d,6375c887,fcee9fe5,7806b3d1,43114327,7e94c760,1fbef25a,60e7d448,c0f0b8f0,c6c64437,a129d4ac,fe24c22e) -,S(12f2dd5d,b75d8885,7b7befd7,cdbd7c76,c0f46213,f9a53102,acd8b0c,4ee3f30b,ce27598b,e85049e,9ad3ecfa,d3864070,f8510570,742dd021,6dcb4aa5,334097d8) -,S(c694aeb4,3ee2b51c,3f0e2bef,bc1b718e,fbb86f9f,1d2a84d5,3178325d,cf997bd7,41481f3e,b6a69311,2cac3e5c,c85a6f83,6fc5190e,ae71f226,bdc887a8,ed050977) -,S(fe266a46,14c5c05c,baf3493f,5af3befa,9bd16100,860bab1,49ad78ca,81047ae9,e2e18ebe,c44694d4,b7c614ad,a772a5c4,f58ca087,4957f20b,741b954,18471e6b) -,S(7975e1dc,926b07c,487abfa5,8c183f21,daff04e7,f67a7250,d2152699,356118dd,c984b97,44e2b300,ca54b779,da94dae5,f943468d,9b9729d8,21cfc709,351409e5) -,S(93573cdb,50183589,a0909e8e,6186d700,7022848e,b7fd6951,a137cf16,a18a2b06,7a957c66,3047f6ae,d9490039,d136cace,caae2d8a,fc9f50f0,26590e62,18bf47d5) -,S(c0bd2e1e,a60f6feb,8e0ac7dd,485fc4fe,6771d80e,e29b4829,fa37faf8,81d77660,685b74fd,9edde1c7,69076267,d9f247e8,2effc83f,e25af065,56aff25b,335bacd) -,S(56bac0e1,93192207,906e5f45,d55d5919,b676852b,daa43253,8c4c6984,9c24bf3e,e3bf51d3,9856b812,d2e480bb,c8b118e5,f5c0ae9,f8d09096,a5d207ec,2fc18ebf) -,S(53b41b13,fe7cddd2,ebfec7c4,a985fded,5225fa0a,b93dfc65,2314d1e5,9142c06c,90fcba57,44e4f565,5d2e038d,ccd2bdff,cb4ecf20,48f2ba98,8f62fe9b,c3b69c4b) -,S(bda05e31,ccc0edb9,47ebaa26,9182ca2c,b1136400,674ce5f5,d55fcf2a,c2e765bb,97275979,31236982,a7459356,7308ea97,2fff08da,ae8f707b,447dc6ba,7acf75e8) -,S(48dd1c6a,8a900820,1fe09f19,a8f65f82,91196e95,1c57189b,21aede15,4b0413d8,79a1f6fb,1a943dca,6517e287,80e72f85,c5a6150d,9c50d7af,78c8b63a,c09b98f5) -,S(75406269,e28c428c,8eeff4e2,ce9a2d48,2be8346f,3446451c,13c04380,292f1f2c,4743b097,211c807e,23cd13d7,692efc44,202c44cd,dde5a89f,9e7cdc5a,133e996a) -,S(1aa55d93,bf318133,8840ae4d,24314ffc,74420002,4ddab165,4018604a,2192ee5f,babac354,92d59e8a,656ac7e9,9b6cb2cd,7a6a8e88,1361118f,41e38f1,2cbc3bfc) -,S(75be4c50,db7bc629,e64fa850,3d89f722,34d214f4,9b176fba,b937120c,477dcf03,b5520bba,8c606db2,833d934,3c860c6b,ed2e5e2a,41a6c3fb,51154c82,94b6f819) -,S(f3604822,e4ed8b2d,d4b2486,b611b95b,6508e10a,1c725c7d,8d638254,3cef6c8c,f405ac79,7404bc6a,25a1a412,f2cbd698,75d99d2c,b23ac105,f9839446,222dc0f5) -,S(6c9216e6,6f9326be,fad5f727,ae0326b1,da54ee91,f041d2bf,2d87dff0,e77cefe8,64a021b9,bc1947c8,df546f92,2f5230df,1ec2f372,50651704,557377fb,39d16517) -,S(ae479bbd,ce97732d,df313861,76807678,988346e2,5b12bb09,e74d474d,6905668a,a3ce0355,c5996087,89936336,64d9bdd2,b33a6f97,ea3f28b3,f4b7c0ac,92612929) -,S(ce92c179,66f74db2,1c6abcf8,36cfd2f7,9ccc05a7,aaaf74ff,4807052d,754898be,f3e3d3f3,530f38c4,ca59cec9,c8e3456b,8adebf80,3f10927c,e44e79ca,601bb978) -,S(8a0bbeb6,815275c1,77553d87,5988c4dd,a96f5ae2,378a3b9f,477cf162,6e6ea68d,958b795e,46f45412,acaa9f77,85a4e34,a7c74eac,228476d6,4e917983,5fe77f4e) -,S(c2a44ee9,975400e2,912a033c,5ed1e7a,7f0e97a7,1c86e8d0,c2e5136,8dd9ccfe,956435ef,7d24a507,dbfb69b2,93b51369,70cd17b8,ebf6bc60,596a9545,3675668f) -,S(b615f625,534ddf61,47b78520,85443bcd,3d3bbe91,c815dc29,3cc891c7,199ea1e1,4cabf4f1,99e21468,62a90876,4f65c624,fe3afd1c,6b399e12,267dc1e7,6ec3ea25) -,S(afccaf8d,fdcf272a,cf56dde9,3980bee7,b64a0c54,f80830b5,5fd0b93b,e8a75a0e,8d8ec5d,6f6fc44f,89f6d9ba,735861af,e7d6a660,7d88e95,54f2c141,1042a63e) -,S(534176a8,c5311b26,1f39395d,f78300b,559d072a,cb3873ac,32833c8a,9b135f53,ab84f84b,5eeea7b4,87ef6639,8fa756fa,b16155d,683ef643,b03c7e6c,8ab2f436) -,S(5f7aa173,97ef95cd,f47651ac,6220f3f2,8705abbc,6531b93e,a65fcd14,1b91f34c,72f7d898,3cddb34f,2ed1b28f,17a77d8e,70cffcbb,e0462ab8,b7548561,9881da22) -,S(d4fb4a4c,c1e2fb72,b301db19,335afd7a,b6a95258,6903f449,aa287fc,ac8f3d3b,76b572e8,4a9db287,19d098cd,5dee787e,f213adf7,9ae90306,8881894,e14154f9) -,S(3dc67563,843b2f3a,f793116c,23db0dd0,dad0975c,5abbf569,4c6d454c,9f7a9ff4,ddf65b9e,4db83b7f,43d0ccf8,49a8088,4894b277,4fb39fbf,78076a60,356753ae) -,S(657912bd,1edd014d,1386c449,50cd1667,9c3e415d,b36e36b1,3bb5c82c,a2f897d6,4e2fdfdb,11bbe240,8fc7fb3a,acd06c69,78205e48,c9f5a143,4300927e,fed505cf) -,S(5a453b3,5f82585c,f64473e5,f3fe937,6f412b5f,c4ade7b8,f9081717,3fd69f99,fc169e11,3448b590,4e1dbf06,f4aba1a3,ec2fb4b5,7f2b4c4f,a29b6617,58097ebe) -,S(c3adf45a,c24b4bc8,69acfaf1,f96a3043,d01c68b2,f4ff689,93b37b3,a4052679,3d923207,cd374b49,d3a85bea,972b8d09,4f0d4b83,cedc97d7,edc2ac68,10ae19cc) -,S(1a32edc8,905ddc84,2756420b,e1f25daf,5bd84f0f,acb046b6,e9040fe9,5e1e1d56,7f467d9d,113a77f8,c1cb73ad,16a62f4f,f1612c80,f8cf859c,ca42164,68eb4c51) -,S(70957d98,62e5977a,c328b7da,2e51024a,f925c142,eb1a46b7,b4a3bf20,a74d6c98,269b56c6,2e42cc34,a0951348,881d2c53,7d7ee231,f2327ec1,441fd273,bef09381) -,S(7e69416,5a02b16c,107ae454,b6cdf25,bf6dd256,d976ab44,bd7edc84,837537a7,ffb874db,38360c11,e2d0d2ce,3e47363,a6aac21d,78a37b24,3e66826b,445185f5) -,S(4f81a159,7b42e9b5,24be7ac6,ff4405d8,3b9d8a75,e37b58b6,eed5525,6ddf9678,b2531207,18676065,ad8ffbe1,6d27df4c,3558eed7,992538b3,77cb8497,86e0a78c) -,S(fa250368,577065af,b60be8d,e9381334,9be6fdd6,1bdd02d9,3591a35d,294fd547,f0b991e3,96c77cbf,5d642f0d,cf5ee10b,3b0a1fa7,7b696f06,d4d61cd4,48e81625) -,S(f4df5ebd,67162bfc,3e3da517,23fec6d8,6b61d6c4,a5876c4d,440f025a,272ba3d4,b23ba279,8bc75fb2,d590e384,c9e375ce,6380dc5b,90970d44,674e32a1,8052212b) -,S(ab5b6b1d,b3725b65,fae28e5c,44460d6c,51b8971a,655541c,4a587076,a1ac5015,16d2c457,ecdc1718,3a9d7876,d785adf0,424f72b8,d08b6a9e,286ea5cb,26ee2ece) -,S(a8a4ec7e,13db5370,40680dcc,470d38a4,2e08d99,3c30f981,ac877ce0,28869e55,4a9ded9c,2cdfee53,897d0874,965878a4,754025d5,babb07bb,2d248151,cb7f60a4) -,S(337f54f6,33bd60db,583d08,165c1011,6f914dd9,e2abcfaa,5f1b1410,b8245f48,9453eb28,696afc4a,40b5452b,d3abae4c,679b58e5,408b0a94,ea456771,8176dbfc) -,S(eee337ab,dc2baaf1,544c767,41a5054c,f6db480d,529d20e4,33b642b5,fd901b53,65ad5b88,2cc00d4,a4ba1d8b,a6956f88,825616cd,5f6c9830,87264247,869c27be) -,S(59f52e18,57cb000a,ec1aaf0c,b43f1274,f56e477c,50f010b8,4513fcef,752f1548,d8ca8f6e,8db03b19,8047006b,a6ec1e29,4f225461,9978ce70,a1ae0f53,9e1698be) -,S(6c200a0c,25fadb2a,8a9618d9,d7d86287,8583ab10,f2b4915e,8f5a5f05,406f3e12,14d4984e,374cf35c,145af24d,a5c0d0f8,504649d,b1793a61,7d6ed949,ef8081f8) -,S(1654a2fd,51dfb6f8,71aad878,239b657a,f8144ff8,98a3c2a0,32cffbc3,8aac07fa,8b6965c3,82d98569,b6cdcc1d,4c71705c,e36d46c5,fa5df714,8d59043d,161a839c) -,S(c48033c9,ab473556,c9982f33,953f96d6,7b3ed1c0,7e98efae,8de232f7,67556d77,af3f48a8,7bc43168,10787382,8dcffaad,abe4a54,828b02b6,f897ab4b,ed968bac) -,S(5dd977fa,a9d228d5,1885aaea,557f7a98,1a95771f,212c3ba,f1a4e428,3c3c6032,3bff9d4a,ba178f6c,d2ce5204,3daa06f2,abb06acd,274beb45,49e72a37,8f2eb656) -,S(2a76dc25,dd9a96c4,bcff1d8a,f3c9aaeb,261e4c69,a5d832ab,efefdf29,ce42a564,493452f2,3ad5cae7,de8c972a,af5c3883,7ff82aa,df616c5b,2fcab4c6,d5244806) -,S(cdbd3506,4c0e7923,822bab4d,b4662b2a,fd3935a9,a49e6d6f,f2db8f4b,d29a4b8d,b2126f2e,b61e274f,a688a84c,386fdb5f,58b84515,1543f143,a8ce0a3c,557a90ce) -,S(983f249b,2cb9d4f6,34d82d6c,e713aff9,2bcfd525,a4146a75,bf6f725d,2b54d978,79cd2406,850be02d,a6c4d25f,5a02dabe,af302e77,238833ef,cff0484,8a8abca2) -,S(88c765b4,a5a0a9f3,a257e21e,ffb23e51,9e128489,fade1383,96fdc18c,38afd4f4,f4d5fe64,729995a3,e505cc03,1d144682,e3336ae3,45c28697,1cf89b7d,595f46c2) -,S(197505ec,d603cb0a,199c7d08,b88d0e63,1d147d07,45603692,6b67a582,b7d52c31,947ec13b,f2d75fc5,af5a746,15a75aec,2f212adf,a234e08f,49a561e4,f9057f15) -,S(98184232,e10f605f,58a700c3,d6bc04d,9a19790f,eb638fec,668320b6,3b2eaaf8,ef3076ed,c0e2fa39,30ea837e,36c31f59,dbbdf192,ab18bd7f,39578e1c,eff9c85b) -,S(50f0db35,cba0134b,790f47a9,e322670e,f0c7d081,6869a764,892f8e23,6c0bc002,1c1b1c13,d98a84ea,e77260f6,58e265d8,9e466b44,b8604edd,83233fcb,68396072) -,S(d9e340ea,1a44bb50,ae4bb19f,3f4228f4,99ac8516,cd6bfa86,80c1dc31,d5665502,128a1688,335a2193,ff805251,b83baee9,341445ad,25048f75,355f4b35,5b4aaad8) -,S(15aa8133,1b84ddd,8c706702,555dc19,d42cb4a9,a9474c9,1e33c0f8,e87c539c,79530720,96586400,ebdd2ba1,7762ccbb,2a14bf47,45f63b1d,e22c6a6d,8942dbc1) -,S(6f708704,53d19a4d,b910d169,c7c7be23,d489dd18,23604242,55e182f8,7a5d34d2,e0531956,7c1c2bf4,a0a9beab,d7c4dbb9,c15246fd,5a6de101,35578aa9,99c7dde2) -,S(31e920df,cddca3a4,89ad97e9,168854f7,867f9a58,fe2d3f1b,f33f8dc3,c7167674,52712c3d,b0c6e58,15157660,ebe27dd,244a9c5f,b12cb8af,dbe82900,c3706f39) -,S(93300e11,708ff01d,96f81fbc,f1888c96,8258dec2,86a315ab,8d01f2da,4c8d51d8,15368647,3b6a208c,8449b53,66584e4c,9e0b7636,1256df46,4c93d4a0,e26c33ff) -,S(8f7ad50b,f62d6702,616cfdf,3712c1ca,30c94632,720797dc,ecd54f65,cfacb3db,5ac10a32,7dc52bc,33290080,a1a194c8,1eff0d71,65f9d34,7e4f8b44,8443c637) -,S(6ed80b82,76270d71,c468f5d7,350c608a,7f5cf51d,c8efbdd7,4458a487,2989f4a9,bcba2bf7,38f6e77b,465e47b7,c687c7e1,77fd3cf2,163b5a2,e00923d0,89826dc0) -,S(ec6c1d7d,b94989e2,962cb85f,777eada2,7c2b11b2,86949e38,eea2bb4b,7ce3714c,add9f9af,6042dfdb,1d4089d0,ebca5755,8ef2664d,52fce516,df3b030e,9ed08fdd) -,S(8f77cb2c,24dcc192,593a82d3,510859b9,c59bca8e,9546735c,1fe26084,4a37f093,51674986,fbf499fa,70b55bd4,f0a70cb8,423fdebd,587e6213,83199b3c,4fe07202) -,S(e2addf74,dae831af,aa4c4ed6,2f4a32dd,1122f2d6,243d049f,1fd78c1d,64b6aca,7dbcb394,1eadfb0b,8a56022,4da66128,a73a1aa0,20a5b23c,cf58118f,e28b2297) -,S(bf7af1bc,614d31c9,9afb7c6d,b8cd45b3,3a22b151,34ba872d,3e845da3,2b1e3eb,108d39e7,8cf88a22,fba9e255,23267bd5,2b850464,f1277239,7542ec2c,50125a21) -,S(88ffc7f,cec6580,5b92c5f6,952d82cc,35b4f068,a7581987,93ebc59,8efe50e4,382dacca,94b42c3e,ba1558c7,82394564,d39193c9,8b9e8cf4,a63dc4da,4d378a4c) -,S(b114a384,ef4ae60,b9c569ae,636eab27,9070e207,34cf83b7,a28353d4,7d3a152b,37c7673c,e58ee20a,6076438c,9bbe5cbf,bb826076,6d8a7001,b188c477,cca3fa70) -,S(e411a42f,e20d23b6,fa768fa1,e310192c,cfb0cd2b,1914c9da,627db3a8,c7e801b0,feb1b79b,43ee7980,7252bbc1,728af29a,8f6828ae,8aec480b,91c85008,959b1039) -,S(191f687e,46432313,c085182a,ede5e7c4,31057ad7,f1f48fd7,cb814fcd,74ee1999,5464b42b,3f77ce2d,59a39efb,83808cd8,43e5c540,3d5081e6,e4f4b1e,926dbc72) -,S(63ff4977,33b0a49e,f618c4ff,1aef537,9837744c,85a19bf0,b2208eb9,506bcd81,6ccaef97,ca835931,f3a87b50,a93f2a4,39535d8c,87e26090,3ae49b29,30593d3b) -,S(efe36425,c37705ba,69e7056c,2e8c628,f4ce72a4,68d85556,4c57e5ad,b7fc2c1c,392b9b5f,27ac49c5,831a5f52,c2e55bb2,8faa7f12,521732d0,8dd910c0,51970ad5) -,S(6d2126b,dd7cc08d,1bd41910,21704a1e,841d4737,4e5a0a99,9880051d,f77e94a5,2e9b823a,cda1be97,52f72ce6,ead42127,efb4d4b0,8daf55f5,5da6f956,84e6e806) -,S(cf7b9ff4,297d9c5b,91c6340d,c1cca93c,6d453ac9,86b4ef54,b20df6a5,4933743,8a57808a,2c07002b,111efec2,bf751b54,c20613c4,1e3612ca,83baa3f,eb670c15) -,S(b160242b,4cbe5ee1,d1dba4e8,e2d55a0,27f5a5bf,f7c023f2,c1524fe6,5f7e83e,ac35795,6cf31260,7ee9f54,fb39d3e,4f1faaf4,67d09567,6075b8c6,3c0fb5a0) -,S(7a86452c,4f8918d9,86d3dce0,22619a72,1744d9c6,dfd0e733,c02cdaa5,6abb050e,30d30b1c,b558b0e0,fbaa1fb3,596cf454,542370fa,43d8a85a,91eb6bc5,c90de179) -,S(a279bc1a,64d206ef,ea96d3a,b97c6770,af41ba40,9381d372,408052ff,582323b9,aefc853d,701ebc44,679a7ab1,fe033182,e96199d3,4b58261d,a1b4a6bc,6ce42046) -,S(e8e28570,5c16016b,608c301a,ac59f868,f7691886,261eb01a,d4e6ec6,a9e5cc76,92350315,f8e78051,b703b7a,49427272,c988ea66,27699eb8,f2fb3eac,9f0a983d) -,S(1fd9cef8,14f3fc81,8055f300,a734f9cc,46da1585,b939be73,459e0ce1,8a9f2bbd,dcc4f73f,a50fcc8e,6ec3c71b,c045f020,c26d79a9,794a25cd,26488c0d,9cabb55e) -,S(321b1afc,70275fd6,fd48942,df364f6f,c609d4b6,cf4e574d,39f1ad06,927e5f11,1368ecef,808bb311,ae9ad36f,8a4c81fb,725a80f8,ed029680,c5b54463,80add33d) -,S(4dff29fb,6518e393,dad0cad9,b0dec257,f9ef1e9c,c50cd741,8108c42e,f6d7bf72,4159786e,5aa4e82,4d7bfd06,713ec8f6,d92f8f8b,48304efd,e4d0f4c2,30dfb70c) -,S(937a84a5,eb63055c,65b162e1,1a3f2e54,c839b972,95a8c1b9,274373f7,5ced1e0b,a03078bb,bf11a351,da7fb3b5,2e3e7a2d,62c122b1,a9cf9954,53294f37,7966afc6) -,S(be3faa9b,7cab73b8,4fb2a87d,25db7fc5,56f07393,b3177c7a,56df0447,e96cc3d2,e7051ee0,1ad794af,571dacc4,4e91f7f6,9276446a,7e348ee1,2998968,afaf77f) -,S(58b39c6b,cc36d506,765d24da,6058d7dd,36928d13,b0fbe1f8,c680df15,756c9b41,449e9691,aaa846d9,a7412b77,73f7ae6f,b4ecd99e,c57863d,ad72d3f0,423d74ff) -,S(9b18a971,b1660b46,720e2100,865742c,8c91282b,1c72c7b2,8192bdc9,c3765798,2812e522,98adf83d,2cc07a93,4a065016,2be28d37,59cfd50,6c792e31,32e0f49f) -,S(a6c44c03,dbacd4bd,7a35e207,61778826,c86740c5,c92942d7,f73a1b3e,dec0f59e,73316b7c,d1fa3410,76b73727,8aaf39c6,2258d29e,c40c80e0,797493cc,7056077f) -,S(1ffb2755,628ff8d5,d837495b,94ad78a0,5dde2043,bbfa3aaa,21a05a3a,21682ee3,4a0478f7,6b8b6c,ffd9962d,f70e2a83,a71243ad,c690efec,5f95aff8,dbb5943b) -,S(aea4c48e,36051144,482538a8,8ee5f72,b67a21e7,8fb425c,3d6f1e78,419b8283,4517cab8,c28eb397,bd89d216,ce711332,82c7b530,6b64499b,2216bba9,41a80b27) -,S(ddc59bfa,5f8c0270,8436fabb,5003ca6f,b972f14,382bf127,f5297990,b4ed3eb,f6c3f19f,b80e75b6,53c370b6,742045e9,ad7dbc80,3a996696,99605345,ebd995c1) -,S(22184fe7,ed301b2d,62bf83ed,64742f6f,94d204c9,866a637d,d03c58b,54c80a8,9db27528,1073a3d5,617a389d,c5698255,3bc55d6a,3b80cab4,ace36140,8179b442) -,S(e58617f4,74e46f4a,74b0ed2d,6bafc3cb,6488c510,87136eea,f98aa37a,f201cef3,cc6a7375,52dde05e,71bf2047,d49a41b0,c6b141e2,e4f519d4,36d4f8e4,f2aa2220) -,S(c1aa4092,5addc5fe,de6c2c5a,ba73b3f2,b7394a0f,1d02846c,5b2a0379,824f8e41,9713af07,e30af560,9516ce73,5083ab53,2475bf26,5713570,28b586c1,d28c687b) -,S(4aa5d88d,89576459,1ccd1c2,3064c718,69e4d320,b0b71b5a,c08d291a,c1df6168,1d0ea41b,915c288e,c6b36cc3,f7806481,c048482,dce586ad,f240d32a,c913e6e6) -,S(93876d91,73137834,dca5e192,fa869a02,738d4171,391df1e7,43296f93,a2a8a977,7948463d,32bad450,24e63d9d,d5786a69,73fc6c8f,9d2a7c3d,e2d6fbad,7a6457a4) -,S(c80cd7d,30268025,b233dd13,f2f2af37,5d18080a,54c406ee,50e4890f,a91b7b28,9f73b58b,1f1d11f9,1648f904,ac7ad275,9e6260c9,27870292,278fe521,b718bc4b) -,S(d2bd24d9,7dd4a345,a8c4e857,97a9c30c,e8e7e7c4,3ce79bb8,fba4250e,a0c8c5cb,330f0cb8,15cb1931,90331055,809eb028,55ae895,ee1a30f7,665166b9,6494b9e) -,S(d4e4a3a2,90deea18,fb15457d,f3ab9815,5d722589,515a38b8,dc303307,5dd7e9f4,4854493e,77d0ecb1,742bdc9b,a5219e9a,71c57a6c,b914b8a5,6eec21dd,3e7d1c21) -,S(f0fb6cf4,810de399,fcd1b246,f0e76e2b,d318f82e,1601ebea,2779be6d,47236d19,e3ad5160,66480239,88b0b197,3eb2a41e,2cc9b4d3,7cf58d07,ad0edde7,ac595daf) -,S(dd4ec58e,3f4c470c,36991740,d02b0fc7,9a4f9df1,98647ab0,ebf73b10,34858939,3a6ecc86,a3b058ce,f278c839,541e92dc,737a6390,94ffa464,17e37da0,40a3bfe3) -,S(ec56910,1d7ed954,d4efe1b6,c4f6ade1,2af12f3a,ddc75a8b,8fdaebb7,ab904e51,3497c67f,5d594f71,4327111a,e22f2621,be7cbaad,b2cc1d6d,be0b7e50,d450c54a) -,S(ca45def8,51856a5,7ca5e1aa,64edc3cb,e25ef6b0,e28abda5,a85d9a19,dbaa35c5,db8b2357,268db9eb,e013fcde,111372c2,6eb4ed69,5a7a3df0,4d1d33db,703521b2) -,S(b44c5388,964521e2,4803c8b6,3dc8a494,40f8ba15,435ce2e6,5f6dc092,15b49a47,2e16435d,f30c4b80,cf125e04,b85166b9,509890a9,c1daf1f5,72462a83,de198d00) -,S(95b735e2,35862f14,e9291a5,4b46d977,33a20ce1,b59b4603,666cfeca,e05dea26,e1281705,5f38be19,9bc9977,b6e80c08,f22ab5b1,286ea553,21145675,264aabb9) -,S(83d9d867,8fbb0263,6ce8d231,3ee4716c,a15c71b2,66c1a7ce,e56928ed,73e5bdfc,e0494c2f,be92f132,effe7d78,499f4a00,c35027c2,37df8545,9918687b,6b949246) -,S(98b7c85,a04c546d,bbf6bad1,6914e247,1d3b478c,f30dd6f0,2e843770,49bbae03,769c3b95,3733dfd9,d9027da4,a10b0a65,ce4106f9,44364972,e569c63d,3b2ace57) -,S(3ce7b677,852d34ec,34358a8f,4da66d53,75019cb1,19a45dfe,864062a,a3b12e45,68d2790f,1838b86,96272c4b,d5e418a9,2cf03d9,de44f218,e42562dd,467e409a) -,S(a0bc28f4,d4da7101,41d0dca7,51542b83,6b50bdc8,997b291,e074727e,cad7836f,6ed7e149,40f2781c,d685a581,99f163d2,177eecbc,ca785224,2a8b4859,97e47c88) -,S(9a571ba3,52b1d62b,4e5d290a,c0d41983,97750fc4,9a18cb68,18fe11ab,1e185c0b,1a91cccd,b2b1f58f,9cfc0dfe,d3464917,f6c2870,9bdd8128,ff61e295,ad1b4ad1) -,S(fba0544f,cdd2de73,d24eca5,55a8c4b0,4e135c1d,8348cb93,d53f647e,2a21b9bf,7a11a425,a4ec6acf,2eafe631,ff83be6a,f71a6cc9,f7dbe3f7,aed57e04,2774568a) -,S(d96b253a,1edbf662,3902bdd7,1c3bad9,ecad1115,45614b48,5f7abca1,d4920a9b,2bc88998,f951b831,2f27d09f,2f331536,1499f1c8,b172f1f2,408d0660,3b18c2e8) -,S(2b3c17ce,1081b825,94ae14da,f9723f9,9823382e,947c1356,13a4b8a6,42267c2b,a4cd589f,2ebd245b,88c7f1fa,427a2ab6,e77205c2,dbbcc74f,dbbdfa69,336048ff) -,S(69698780,fdac522c,69313ea7,2e244d9d,3f6bc5c9,4fd86125,2eb56369,c96439f9,e8eeb3c6,460f475f,c06b5943,9bb9994d,8d6e4314,fe20020e,c1001f77,25a03154) -,S(1e344611,4cb4dc4c,963e172c,9bfc2f4a,d1577efc,ae2ffc6d,76395ef9,a0848c68,debbb8df,e6f59a0e,b96d464,3bbc6d51,a2bb4621,6059de1d,a473436c,404f5b19) -,S(6ccfae02,4c7f2a9a,ba12c191,bd35e287,d5c30284,c4273a1f,c558ae8d,286aa61a,c2014174,c78a2fd,d342ade2,51e4588d,94c4cdf1,ee83ade8,54e48388,b6e7cb11) -,S(5b5fd487,69b6a133,35bf0a2e,61a2128a,db43153f,9497c77e,c32b16e2,ca4c728e,9954353f,b23c9d44,eadf2632,168711b5,5a54c9da,53c41088,50fe77cd,8cf00c77) -,S(6b74a257,27af44dd,61fbbbd2,7323b63f,e6a41d9d,f5412215,65a6a9bc,35d069e,a4e1214,f17b8dff,b5bd689c,5f004c98,39b87a46,15245756,48099d33,f432a34c) -,S(5171a187,8ae9ed01,837408b9,fe08f317,8688606c,aae04b2,63cbf143,b8e372a2,b5e7de6b,964153cc,fe64a472,8a8f20a4,44da8e15,c593b7e8,68140276,b172d06) -,S(df9e86a,4337ef32,3518568c,e52958ab,dbce8a92,840b756c,279e96cd,43c8e80d,5442baee,c72f460a,110e8ff6,1e938132,50b2ccdf,61941df,5f591bb4,73027da7) -,S(ce070279,eb6f1f71,af876ab7,3903fbd0,ac9e4693,7b6d3307,2ec80182,3887c850,de83ddf9,88f9d345,e1ff2a79,e91f8ad9,6ea23097,538dde84,aea0ded4,b6a155eb) -,S(a0255c62,44afc84c,58238936,c9d08d36,96e5789b,ed28c40,7667f348,4c2f35fd,93e2d407,aef898d7,c898293,fb20f222,6cd5017,cd62669f,17ee0d16,773c6f7a) -,S(ae82dead,b76d5dd7,140e1197,a383ff62,138e1840,dc2f7ef0,d5126dca,86f0d86b,239dbbac,caaa0779,a9f6d8ec,2e30b590,72d36b58,199a27c6,5f5815ca,5720964a) -,S(cf0999ce,bee65e2e,d596441e,a8942461,97c597ac,9c090884,44c375d9,16332393,6620cbd2,f074edd5,1ff8cd5,45adcdbd,1c664ad2,6935880,8655ffb3,3a748ca4) -,S(5fb4af74,6404b01b,63bff1b4,1bacbb36,9ec06801,9454622a,76258033,9cd3965c,464cb2e1,2cce697c,d409529f,a48e7448,916a51b4,5954fe93,d99ce392,272abff5) -,S(15af3c0a,46b5232e,55e5687,a2bc4acc,2c7a350f,8114e3a0,1993a0f3,1b3216b4,ae03739b,bdce38b0,4735acd9,3a3ff7ba,86c8189e,56a5bb37,ad83a574,cdd45a83) -,S(5d0035d1,d008ccc5,42cb8b5d,32d973da,32c88787,640d0465,76d33e36,540b4b10,448ed8e5,bffa9f28,6689061f,73a74f17,76db8a8c,d5b4af39,6173e7be,6e54c465) -,S(944c70f3,9cf749df,edb9d322,ffc69e3a,a40b0704,fc4af915,e027bad4,83c95527,b0ac0c3b,bf489332,64a6e95c,e49a669a,df10acfd,48e22fc2,1a18ecbd,b86c6f0c) -,S(fa5219f0,82ec3c4a,3f246754,dad62f04,52e26225,6cd28acc,846bc5d6,151e4402,32ce81e9,d6403132,d7b64f26,a0289031,eb730d2b,dcd0065a,1b4e3f3,a7afae9) -,S(c9f4aa30,ddbee263,509455a,858b8518,85c6a16b,5d9bf032,70443928,38a30ede,5ef717c6,b438af31,9a892799,46b73ba7,add20334,c2fa5bae,a15b7632,34ad7b7c) -,S(2f4cf3ca,7454d569,5b0dd2fd,c72d4ffe,529b362,deeea120,162c178e,7b770319,dcda920e,3566ebcb,f47c1ce0,fb767092,fe7c87c5,ff146042,d5a0ceb7,a2f7d487) -,S(2417f576,2e0cd74a,f07a41a7,51f91b3e,a1cb0a42,2246af4,a0a96b8,79969945,6a96d755,f8dc71bc,adad0a3f,61cb44ed,741ef96d,96baacee,fcfba7ff,1e7807d9) -,S(9ab22f84,305a1c1f,675ca5ba,cbb3dba4,d43d060a,ee9148c6,6cfb61b8,5888852c,af0506fa,a2588e3a,7aeac12a,7acdda3b,b51d996b,2cca9c18,e23b517a,a428a03e) -,S(f7421ea2,24627926,28ed878,7e154724,77a91726,5a162f52,87501d1d,24a72b6c,db0ae665,e4484132,f372ca6d,8cd46115,fe1c72cc,885804dd,8f508900,5743fcf6) -,S(35756af3,548d57e8,dc0bb791,8b9875b1,10a912bb,7d971e35,4963bd7f,df5c6f75,1ca46dba,78a2b4fd,d4ed69ae,bd4e1961,86d94b8e,20b1660f,c517098d,e077a1d2) -,S(a7e9f00c,494cfaf2,16449d9a,b0dae7ff,de4041c2,fe031bc0,241c44db,1bf01837,f2aeb9ae,480b406a,9753d009,3b5fbb74,5a7760de,4ef508b7,d10804c0,161a0280) -,S(69451dba,92872879,7737755b,7655ce70,64838aa2,9084fc1a,c88f5e6f,ca62adb7,26218fa8,d40df091,31d845d4,96c7b950,1071537b,51a3143c,c73f1a7,b02b1cd9) -,S(c49c3b30,15cca66f,ce986a37,588205fc,89a92d0f,c520ad3,5eb6cce3,daabf06d,7afde84a,665b02b0,e0cf9ca9,9d2ad097,6242919c,53e31b5e,6216d67c,580e354c) -,S(e9e181bf,b68e6e38,c5b6ee1d,f11c14f8,90c0c744,8570387,1ab6b624,6b9dae8f,b0bcfedb,3f394317,907e260,c3651aa4,d1af5ca5,e1a34018,fc6c26a2,d5ef5e1b) -,S(a428586f,adf41cf,5b5c9e52,e0d6e1f9,2e7d8738,ab99e8bc,4062e302,de392324,77c3e18b,fe71c937,65b911e8,b49cdee9,a2a7413f,4de831c8,3f967f08,95b8d142) -,S(f5c92ed2,de1d1a25,4b4a4830,b656a674,38077be7,5efed94d,785dd0d9,72712cf,7ee98d3a,497849cd,5b5f6dcb,c51c5119,228fdf7e,1a67f1e,d7c670b9,eb3958fb) -,S(a85707ca,6c85f506,311b6930,767b5571,e18c19c7,ff2574bd,f268f018,b49c3f66,1785fe71,cde2e189,aaf67d10,337b8fb8,53654335,4d5ba73d,77518d9f,5e8aa050) -,S(8866f5f,a4c8d1c2,f2de0cf8,19eca5c4,d084ab60,67a7d97c,f9942fe,c0a7468d,3014226c,3f33907a,2f6c49ad,c762be6e,2915288b,a7ec009a,fe693048,3588336e) -,S(425f6d73,37eb2d68,e17d07c8,bda406cf,92af22b5,6461bd66,f40be14c,ae0688cc,e865526f,7c42e391,1ab73290,e80bd9fc,9643659,5871bdbd,ef8d698f,d04d4980) -,S(f70fc3e,1de3b3fd,55418441,43deb4be,36bfe6af,3bc9d9a2,f8ac823d,68323139,8b47994b,1febb309,e3774a82,d6b18d78,8ae5750b,40aa944a,dae404b5,da24ce03) -,S(1be960f3,38d2a16,703b10c,eafa121c,d59c66d9,439e9067,58a0b363,2a83116c,7fa4ca2f,8218ee04,351549cc,3b0100fb,647e0db,19eea010,62f1c0de,3de29aef) -,S(1f2a2d3,bc5c80a3,8af51e9f,5694a80e,e915eb89,4831ea7e,48472d53,320cf385,a18cea39,174b4c49,f9bcb945,5e6701f9,47053f07,6782ce9f,f55653be,6d3940e5) -,S(61d6b60,70846b0b,b7790861,17cafaa9,9aa67c37,fe77140e,88477f3e,44d04766,c7f4be90,86849ae1,632eb59a,6c96de66,b7c4b1ea,caf724d2,5338c11c,a8f2688f) -,S(2b37093,2d9a6451,79508daf,4be7f26,6d540538,9276fc4f,e6ccf0d4,1ee6cc9c,c002a3f4,2c8998b1,ee16a1d8,616ce0b7,91cdfc44,61839d9f,5ca0090e,295beca7) -,S(48f5c3ef,aba8b7a3,4d7fd136,fe9b01f,64af0e95,6a27663a,87cd6629,f2708858,8cc38cb7,fce46724,7c2f09cc,52f973be,90aefdbf,b52895e2,b88f03e8,fe32b5ab) -,S(e609b597,2e5ec227,6f5cfc87,67b6d534,adfbe9e9,9e60b86,e981dd9b,3e62cfa0,6be9c1ee,ff205fd3,e3b85e3d,bbf1b27a,335ca616,9ae189f,a433e65,f2b43081) -,S(ebe40b1a,5b2c9cc8,46eb8ea8,1ef0c1ce,f19a767b,2da6ab0b,2ab66a01,b16d205a,2f7710e8,e4fecbd1,39899bd,1964f5da,967d6920,d70b2f4,45d6f914,97c67058) -,S(97cd4c39,9391b1ef,653d32f3,9b062bcf,dbc72d45,83d81b3f,f70df659,358e3abd,a05a6184,a175b6de,f9bc35c5,6e9f5cae,263acf2b,a233bfe8,13dd98a7,fbf37968) -,S(826928aa,1d3fd0e8,53cd99fc,e6559ae7,257343aa,378100e,bf64a3c1,bea7e6d9,bc4a2db1,a3bde90a,ff50fddf,cf6f844a,faad7f8a,89bb399b,20b07b2,2e1efc79) -,S(3e754097,f3ac95dd,176e9181,410bae7a,83bd1431,6772e398,967ed39a,5fa19121,746cce99,c6a2cff8,a0907ea1,5cf9436c,ca7f94,7f3f1801,135fe675,a518df32) -,S(ce539464,b49b9947,808a236c,8a027066,82991f46,3bb828fa,44653266,329365db,3578fec2,b8bc4763,61f2fda,29c2c38b,a7bda79c,11b2cd41,a74d4c02,762e5dd9) -,S(c933d9d9,cda615ad,7ac41d6a,e64a77cb,44a2b669,21533669,2c90c3af,53e349dd,4a6da24f,83baebbb,8f2a8ede,298babce,a25b054a,a1c4cc11,f9f0b0db,572c610) -,S(459aa43b,1aa9815f,e9116f2e,78ddddef,a78e2def,28027d51,d081a3bc,800b2ac4,1acedbc3,de995e30,b16900d4,cddcd1f2,5c615156,fc29645,4bd5fc7c,63e993d5) -,S(5f2aa5d9,9862ad29,eb467564,639abfc,ff445334,9a30c4d4,3b27f913,1e3b0a5e,571eca2b,e61d0bf2,d9def9ba,445b39b2,5acfbbb7,dd4e2cfb,ce7541c9,61ace144) -,S(ec66ea1d,e6cc5d59,8c393e68,1a338549,fc2c3d7f,947b40f5,75681e60,88f4fd1d,d711ffdb,3b378435,5894dfa9,d0a5497a,5540739f,a3706597,8ab7dbea,a9280f52) -,S(6ac53df5,aa097f2d,9983f018,bd1cab39,69ad0638,c78547ab,1a481682,ad6105fe,95f69a81,5127b919,9488f224,24307969,3cd51796,bba08578,abfc8e05,6618a598) -,S(a8a3e9e2,9e4ad0fd,c466dcb8,fdc02cf4,16fb5c85,b3454fd,3842f129,9f96c0b0,df86eb3e,3006dea5,ed6d152,f394d7c3,169b8d09,bde3685,ce138a55,6716dc2b) -,S(50a764d2,a0d8741b,95ec84a2,feda6df8,1dbe987c,31861166,32c40c3d,e6db251c,b28203f0,233917c1,4b67632a,ce9b512d,76a8c7e2,430a4a40,85cfb422,7fe41055) -,S(c2c314b1,5ef9df1d,26856c9f,a6e39cf9,1bd9c584,582893a9,423746ca,1ab51ef9,a27f9286,ff7fdfaa,b949a9f5,d59f08b7,a22f1e31,e7175d44,93e219a4,e92ab759) -,S(ba655585,da44c8d1,2b3ce375,e220a4c3,64868b75,370fdb75,dbf6bb92,76a9d3df,3d64e16b,a03a385b,def18f61,432cc49c,bdd9d04e,6fc8873b,e51663bb,ca4fda50) -,S(3d45fa49,d4d100a4,b5a76a65,1a5100e,56bd0d13,b9e141c2,aca5cfef,a46e600e,92953c,38eeee42,e1da93b1,3c75ba48,da30390e,731801ec,ed5bdc2b,58059176) -,S(e464c346,e40dc3e2,40e5d96e,1fb2c10c,83e5ab7f,45138596,4ca46b04,bc8c3a8c,63f14b46,182950bd,282205aa,374cd67b,ca364a4,f57cf90f,c7ac90d6,5204cf4e) -,S(14a7e12f,e235b307,5b0d218,bd3dc720,d56f3fe4,c73841e3,fdf42dd5,aea42688,d79683cc,40cef482,ed6a22d4,8137a4f0,eac31249,9ae13809,9eebf3a3,15e9ff2a) -,S(8e7afbb8,21af73b2,25b34ffa,bb2ff6f4,61d2ee2b,85d5d936,a99fb078,963828be,40e4776,5aa0768c,f055bea0,e20e1062,bb528470,dee61ec1,6cc9ce7d,ae6b1853) -,S(9d641162,3227bd0f,4bcf9f1f,9e5ce829,7d844055,8a7ec246,5b160690,53297573,ed0d83a0,68001be5,70067ea4,70fec09e,1f8630d5,da5d1b2c,126c35c3,9b07fc8d) -,S(6758c6d6,d9e49d9f,4125b52b,e3da74e7,52bb40f1,44af0f0b,7bd80589,7fc83eaf,749ae08e,c2aa2c36,3a229b3d,e9577dbc,5f7d22cc,d46826e3,6a1cb434,184fd292) -,S(b3e11a0,45702d8b,14d93df6,3a4c11f5,32632719,b4a33fb8,da11514,bc61d73a,c6e152b1,2b267ec2,1a23892,8cb97044,9660c6b6,34b22d18,9a86fbd9,a9d562eb) -,S(50a325ea,3b309911,1371b0f,e0b9e276,137bf43c,22108b98,994ed5a0,d66fa5f1,946dad1f,d39e0aa5,8a758527,9b39efea,8a99399c,2750739,dfeae140,3745b70e) -,S(f7c8f249,3befd5a2,cf6802ce,8ac508ee,a97341a6,a46efe39,1214e322,e95e9661,3c072cc4,eec1f370,144b7ec0,598e4d96,573883e7,fa3f3f5d,4e33d88d,1e34cb67) -,S(302d3b50,c1543386,f0b0b94e,9c49ea68,38c7e7bb,86c28cc3,c8965dc8,38f85b6,988047d0,d891aa2f,60b66e5a,96c78c91,3588d128,d4e7f720,5672d25a,88310744) -,S(cb8ee728,2e7e5ba6,d0e8ecb,55ede89a,1d3810fc,b0d8f86a,fbf53b7d,219f0eb7,4b04ea2b,efad1099,8c9a4e3,cf0491c2,bc10bd60,e06a118e,75fe0163,ab8094cd) -,S(645caa2b,4a0cd8aa,20cf6f04,ac73a49d,74f92035,f90bd31b,211572d4,cfd5fd42,793f2996,35f9d7c1,de62b64e,afe516db,b0aa1323,7f51d0a6,b6fc8346,fb7ef5b9) -,S(4d37342f,6148b5e7,5434b8df,6617d64c,f00b1c73,3d85f4f3,e69c4a27,395f5a21,6400092b,d4c5c705,464a7db2,b1b6b667,4eebd7dd,38d05cde,d1577d8a,53a708bd) -,S(e634bf17,24e07b2,b4ac6285,ed28bd39,747a2134,36e76d3d,bd693170,18c0e0d8,cccbcade,4b82a51e,c31d9d8b,6b113876,5e9660fb,e897ca53,20db873,13e9f021) -,S(80a00de6,2767c513,d5bff535,431d259a,64c49006,3bbf992b,a5111005,360cef38,7dceb589,e8d73366,c467e23e,8fdc7e03,b2620df7,9530b6b2,3fcdcdf,628ef572) -,S(606d50e6,d23d50ed,9a5b8409,f11d5c76,baf5b765,f719625d,5b2e2dd,9e8f8a0f,19f55492,45b1b4c2,fcc1d220,6c171200,4cbb41e8,bb7c8cc7,48c4366b,3fb32788) -,S(9c8a0a14,f7d44fb7,4a7ea835,ae4a1932,266c3083,38d66a24,7fdd60ee,e4f0420,42c6c237,31578dd2,31eda621,81aedd29,8737fc7a,3b2be8b4,d0187459,e5d9169a) -,S(d6ccfcf7,81a46f58,ff9a0154,8a417924,1a32d3ca,43a8e59,cebc33db,1e35da1c,a1caba1a,ce846b8d,8b4824e6,1570f832,87cbcfbc,910256d5,68bdf223,861d084f) -,S(8cfaf36a,3e4c3ff2,4556f446,4947c8d0,6eed5ded,a40ec0da,4596bad9,f5f2e3c4,991b6ecc,ede6cdfd,e33f81d1,c1067f22,6b72373b,96ca31fc,c80e0692,d8f3c4d7) -,S(d46c3d81,5b0f3a0b,bcef3973,8c6a6cc7,189849b0,4917fda0,541c08eb,b7e664a0,35524bb6,d053e5d7,c8adc9b6,3a84ed81,58cffe99,4041e642,1fece58a,d967c159) -,S(8ed7f0a5,2f1f8df7,f82dce33,e4637dcf,e2ce9b75,ca02ef04,90c23fec,2b7adfff,f02460c7,b418d10c,96c27225,3dee3b66,4be1aa5d,427759a5,5d90c223,628d99ff) -,S(433ecadc,a8a351bd,52ba4d6c,aeea3ff0,825c46b2,8abd2c2b,cea85f6,6daaa2ca,4d3b71bc,c2d7d177,45cd03c4,86f390e3,f6d396fc,83d0438f,983a142f,162977e5) -,S(c0771ef3,10377f83,7a9bbddd,81f6642b,ba04493b,15c054eb,249b3f9c,bba006e6,3e53ddab,1d816a02,7898c6b4,778d4c48,e1ea2b33,a63955b0,784df258,ef4ccb1e) -,S(dc2e0226,4a6a87b9,53997383,e35c6cd8,92072ba8,a741fd23,8ff3a9c5,f597ad7,898ee746,ecd5f723,440ac0ff,6f597e85,8ddbacc9,cbc80e01,d8a3c1f1,7c12c74d) -,S(16bace34,59ad8cbf,1fc5f781,19cd9e31,d043d7b2,ed839f03,11f0b760,6adab771,f64532,6ec697e3,2ca23979,72b2b834,66e835b1,2bd49243,e896c1df,c02fb1c4) -,S(afb94d8f,3a271439,146539a8,68f00346,9af55eda,839c81a4,725f3a5,7d69c736,afdb294e,a455031d,a70a4eff,7563d764,bdf37fa7,5594c9cb,386e8bd1,a35201d8) -,S(bb31d236,4a98f7f4,1edb0ae7,6018e5ea,ecc33780,5f781dc7,6b15aa9,d0e89b74,1a064c03,1f47cc7e,cd49f032,f4dcd95e,87cbc28a,7b9d9c27,a92a4c1f,da031a9a) -,S(f73b1b6c,4bbf5da8,16604ee3,ef6e83b,241e486e,d727e700,1c3c115,3c4318b8,9a28ad6e,9d64cba,b58ac225,5c01b261,25ba08ef,3b7d5ffb,476f9b8a,6c8c9b17) -,S(63bd212,d0ddc5a0,84f8ea7b,69605b2b,708c8766,f0d3313,b236e921,91afa8a4,ee6f4f6,4824032,afbb0b3,a9fd342d,2fbca8e,ccecdb0f,a3307698,c56c3e67) -,S(6367d22b,36068022,30a416b7,8c689078,967b955d,875fd629,9e007f86,1abc6465,c3ee1f2d,14e6793f,17e444ad,5595f9b3,118d1647,9259e0bb,ec628897,f69417eb) -,S(64e2e543,fbb7f52e,57901e3a,448394c6,c922d0f,b632c4f,2df061a8,9485976e,641a602e,336a68b4,fc447e5a,5863a4e6,89511942,4fce011b,48f937df,fcab2a4c) -,S(2e290afd,18c835c8,d1d79e86,9d9c1322,e16e824a,60e67f38,d6bf3031,e3fee1c6,7f85628e,d2fa6b67,7686b0e,c29a3626,da18ccac,5e373874,96266458,79390f21) -,S(859a208a,c475d3d,f5f22907,988c7774,c0ba2dcc,d80ba42b,17ef1087,2cee401e,a667c645,778e743a,d62ed1e3,cfa12fcf,84b982a5,f1349e31,33627ffa,8b19f5d8) -,S(c9291908,ccc50aae,f19c0b86,829fdc63,b608d3db,d92b0939,b92ac02a,2bcaf21,e5c52bb7,47111f58,c71352c8,b2fc89fb,20cb7d45,77c6231a,17d8d01b,6cd2599) -,S(50359490,42b5b620,78ab0141,1f1a1d4b,64bc42c7,58da4459,b04d41c4,61cefb26,f61e823d,b68c064f,f80d9bd8,f272f817,347c132a,f7bd2af1,e5b451ea,bf4f04e0) -,S(f9bcfae7,d6a3f1fb,612787c3,53b535ec,39f29a01,9f45f43e,7b61f2de,c4a4cbf3,f4d86e6f,273ad7e7,902d5a99,50fc846a,a6565862,aeddc67b,28fc07a1,232ff883) -,S(1c8fe8b,901cf050,e93c0004,b0764715,602ac4e9,7f8d5dba,d7747039,f14a9152,b25ddb34,7c452942,92143b6e,cb19f87f,b42a0f27,f6f74c4c,99d7b80c,7d36769c) -,S(3c50be1,4cbe3a87,d363947c,6eb534e0,8ff676cf,412bc4dd,2c543131,e786f552,4434471c,6e03f600,d8a27775,4466cad0,194f553d,bb653238,8a0ee4a3,9b05a74d) -,S(64cd71b2,555472f8,fa968b4b,4f8c8b24,5b3e91ad,6d9dd409,fe72702e,e70522f5,f1b1cb3a,e9fa4855,2d7fc2a,819bd629,40350a3c,168782af,5bff16d8,89ede304) -,S(c1c00444,c584c346,d1bdded8,7cc40b0e,fd8f69e7,d2ec8bcc,c41e3414,619af7a8,d631b494,3e3febb0,87bb391a,d5810b61,f78dbccc,bc6de38e,ee09005d,3d879436) -,S(fa509582,dad5bb61,c7450fd0,3b7e4ba0,2fbd0c28,af971b96,cbef5956,3fa2a7ed,267c2764,617c2f78,9ab890d7,56be2195,2acdff5b,3490b816,165e2b36,2f3df4e5) -,S(655dcee6,864e926a,a6e05f04,b604c2da,35175e0c,f7d264d0,50920d46,c1a2386c,da2eaeda,bf062cb4,ba2d36c4,67965baa,5f1dc238,b5e22df7,2bbe14f2,cfee19c8) -,S(6ab5e1ac,1b7be624,97c8fbe,fec5c4d4,2cc1de06,d15a1beb,7606fc0a,df3c213e,26f983b2,4eb319c,7443e024,7fecdf58,f833928d,4e809d3c,f36231e4,d0a9e466) -,S(c7da869e,39caa2d,e9f73a0d,3f73ab73,6224e2a5,47ef5af3,5f5a9d51,60c25f3b,e99b1102,49a607d8,12af4cf6,76ae4c4a,cfdc0f89,9ec2175d,c7942b6b,40da579f) -,S(2a6d4ca1,5f1c3ced,ed68091f,af4d149b,e20b6854,bf015084,a9cc0d21,4944ef99,dfc27688,ae9295e9,ab8d9284,6a703ac5,5cb44bf3,13f179b4,ced6b638,e661ae0) -,S(447260b3,bba7224c,aa659f70,b1e7716a,92600a27,18129575,2de62cda,11c846c0,f17e3e0f,33ef2ede,8980c922,613947,8331e2a6,40260996,db8da1e0,dc8999bf) -,S(8cdb1cad,baba7003,8d4b0f44,1b312aed,5a8788a6,6e5356fd,5b994f6f,a7781969,b3a5bd0e,262e673a,ae7be06d,8d56c203,b88750e4,ba06cfa1,7c177edd,74536977) -,S(28be0f50,fb60f905,18323e6c,dcf46c0c,bc3e2c0f,175d8576,85126a85,d5caaefe,5cc058f7,fb188c4c,e1140429,568c3176,8d986fc3,e96409de,21bf9ba3,862b7320) -,S(b6dccba,dd2dfad4,8b69218a,d9cf839e,837e2262,7f8f0eb6,f23484a2,994673a0,e1c14ad7,297f1626,774aa2ab,5dcc730a,49623176,ae81eeaf,b52cfd4c,fa2de992) -,S(e45ebec8,8813f7e5,7a7ecec9,dc5fcda6,b9cbb0f9,19bae1d,be770955,e3766a87,3a62a0bb,4ccf3783,7c384885,7acbaa9f,f915cc7f,13a46856,3ff135eb,dfbb07a) -,S(de926f77,26f39d48,1e0b9e55,22b7c874,59bc9d07,df65f0eb,7b21fea,e8dccdbb,9d190ea9,263d4240,24b618ce,1239f6e1,115be2b1,d721aba0,f5f367f6,304d8e05) -,S(f7621384,20669c04,6d794807,569722b4,91e4272e,1305f091,b54a03f2,ecf2caf0,d0c7e8e5,a227f2a9,5c594528,4590caa3,3088c92b,b4c7cf6d,12d293d0,4b9e4914) -,S(4e795e86,44ffee08,f44d472e,8ba0eb9d,a5cdb1d1,619a437d,4a8bbfe8,565ce751,5292d8e5,478268f9,bb9b4be3,c751e587,65038c55,99cb3549,749e83e2,1590a4e0) -,S(70e64689,a944b03f,32b33a97,c8923531,cdf75e8d,e8577559,bf45d2d2,ddb50b3d,a675c6e5,460b89a4,a2dae263,c71e6edf,925a93bb,a916951a,5364d252,c225586) -,S(21637c2e,682b247e,cb8c1c,8b4bff1f,477ef390,3b9da0fa,b08b5cf2,5b67056b,e357165e,3e761a55,7e4c2b6c,727d8387,c5716b58,e24d0e04,8314979e,4e92d882) -,S(7691a399,8dad2e1,741a4135,18bdbb,d8ae5bb1,7466a949,a40560a3,9c1d1964,225f1404,b05b5bb6,cdbf2296,f76e7f27,257280e,28c68be4,d8c81c47,a422b74) -,S(748316a4,f3950849,9af5a14b,27eabf9,b0d11e91,d8752cb,69899af8,79af9302,cdcdd4d2,6bd709d8,c3d87c12,6dd8a2c4,f600fc1b,9e84461f,1793047b,5bfd7ee2) -,S(af588dab,3839e85c,6dc84aa6,c1e05294,a9708951,8006b390,c2ffe0ef,f6ed9b8a,a3d37640,1b06548f,2794131f,5e002aad,616ca135,8cf0c81d,87015416,37d9cff0) -,S(bd91dc60,31706ffb,19b61796,995728b0,5f869d07,6f0b6537,35c46e10,d9b42dc6,3c963ed1,5a74f5c6,1a28db8e,de070870,cdce2cf7,d6525a6d,16171076,44f153b2) -,S(e625c4a5,91460bbf,5c3aa583,c4cb1e1f,c202c82,7debb82d,985732ed,ede98f47,d026c5f9,a9035396,1de50534,8e4ac600,812a461,c913299d,7fddccc1,5970b72e) -,S(6bd227fe,d4b193af,8b94553c,718357e4,122cd057,d95980e8,ebc8fe5c,7fdaac1c,5f3fe540,a98b044,9ed835d3,b0a2b4e7,c66a0549,e4b7b9f0,22fd5249,c621a9f9) -,S(27707a25,895e6f38,523d3872,c5b34e7c,68a0f0f9,54c6ef49,5cff6664,1edb2609,ef6f4f8e,c893d697,69f34b38,f7f677e9,e5de5c91,48cdf35e,3a18022,3ea777ee) -,S(6052248e,3359414e,bb7770ea,4284d7c,c01770c0,e75466db,1f314e0f,cff0ebde,3d982058,5cf0d546,9fa62e02,aa556fb,1a1ac7d3,1cb9712c,8b118e2a,e3f7b7a2) -,S(f2cb5b53,4fa6124c,16d82506,8b229857,4d4fc666,9b45550e,6c75a114,f370f6bc,5cde5707,63a5cad2,13952def,43cc779f,8ec9dcbb,c5fac8a0,ad7a740b,7241112e) -,S(77ad8215,9fe6b9f9,e08030c7,a75c601f,4989b51,4ef6db20,aa9d0b23,e87a502e,9268a1ee,ffc24932,74856add,2ba1ebb3,c13678,99af932a,87fc680d,ea9b703d) -,S(4418748d,171cf80f,a7f80fd7,c2d7891b,5cc9aa0f,ba4ec1c8,a114cbc9,4a8fd29d,5130285,79f01b7f,72f18322,b279fe7a,9916c16a,a67c6aee,babbb418,fb1835c1) -,S(16af4960,6f89c87b,7e5901b4,d11a826d,126e59ff,df7d0883,1d37d7e6,367355e0,1a138440,537223c9,e8e131ca,8ea3b38c,12c8e8ea,50ee09f6,8ca4c2cd,4cb04c2e) -,S(22d2043c,ab4431b8,cf77ba0c,ad81848c,730a730,35277e4a,ae6392f9,de120f9d,d7795dad,5e5b46d0,9c36520a,c7fccf9f,4d71f9c9,8ed3d45a,432f4f6b,991b8acd) -,S(57e7a8b,34826533,7e203360,2f6244b6,41d92c8b,b2419734,9fbb3271,57676302,4d9238e8,ba4bc8b2,c3abd2eb,6bb2e545,5146afdd,3d1ce2a0,9752803b,4599b83a) -,S(45567f60,2755027e,282b39ed,5ddab1c,7ea19a82,4c0609da,9ab455b0,26acc359,db55ed5a,77a354ed,e4229161,141392dd,82c1ccf7,f726fd4c,2fbba48d,4134f5a7) -,S(968fb554,91059347,9dc1933c,a8453201,798a0be7,1a284c38,3e8fa5a0,f67fa80f,63586b1,6853f550,c36d8394,56718376,1c14101,dd03cbd0,b164cca1,24e8920e) -,S(f366c649,f633cd7,f1fef522,b78f7b85,3d640acd,11af2d17,14c14251,ad873107,5fc396af,38f4988d,82c4cfab,59d415ef,25b260d5,711ad546,e56fb65c,7482c6b9) -,S(aa0c4fd4,4a2e68b2,edc16eff,d2b3c29c,59b19289,1503e6e9,ad068743,fc201d06,614e3224,2fba7977,464b5c4d,b76270d0,2763aca2,54aa5b82,b5ddf8b7,ff3fee33) -,S(6c886cee,19b2cec6,91c57abb,da830e45,da4cbdcf,37484ad2,b4444948,8f2cc876,24cfcbbd,9ab4df87,87eb384,fec64e5a,a197e897,bcf2dcf5,def4b94e,afc16a1) -,S(4d600199,c33f76ee,c81d1686,f116d4e0,fbe5e4ca,df3bee43,9a81785b,c6095554,cb414cce,b769f70e,115d4321,fdfed743,2bf73dc4,9f1628e9,dad15f32,5fae614a) -,S(377dd0a0,196d59e0,e71e8472,4b65bb16,12c3caca,d2f2230a,a675a25a,5d0a4fc2,2c727e7d,8c8e27dc,a5ff7c27,b349752,1159c736,2b51f38f,e0343c74,acfeb560) -,S(9cc0cf8a,23afdf35,1bb1826f,9d900b8a,e8aa5019,8cf36552,9ca928a5,9c820f46,b572f15b,e2aac0a8,c8142c53,ea43a0a0,693e5446,5d5531f8,b068d347,f7e67256) -,S(d55dfaa6,41492b1e,981d154a,2be0441e,4cfb01ea,a51c40ea,d4a4d8ed,19fa3050,2e795dcb,408c74c2,a9898f31,523a1e72,da0c4c77,c2dd2eb,45fb2e51,8f238ac1) -,S(46bf63d7,2d113152,3075efb3,fac6c07e,e3d27e87,279724e8,46306dee,7d210fd5,771bb1f2,30fa3253,7e3b433a,2905c4a2,dc4a2e37,32e282fc,94cb2c88,33b0b199) -,S(4bcfe388,3e77c17,8c6f1826,f75e7c3b,594ef8b8,c1a9ba3a,13f00597,50ca3aad,b5562e93,9dcf4672,fa283cf5,6c05389c,ec5ea923,b47d09b6,2ddaaf54,8a1b0129) -,S(c9681af4,715e69ee,d7cce802,34bb2a49,6255ba39,1df76c57,df9747b8,d8c241db,c8b175cb,b03d5206,5f2bb846,81bdcb04,da530e81,31082e08,28c21f7e,cde038e6) -,S(9fa0a1b,56bd6ac7,f4a2671a,3b4f6ae9,bd5538bd,4c6b4101,790b16bc,c2fbc33c,27f9eabe,785c7cce,e4859959,348b4864,16056f68,6d445fb5,c08fd8b6,33129e63) -,S(15042df0,ca178aac,723e7b9,8677964f,a87203f2,bc0e1fea,a56ec6a4,73d0381e,445db657,dac86b0d,f8f9eb59,a143e75f,e271cbfd,2420b3a1,677ee3bd,8d0183f2) -,S(354f6a63,d4c1877,e0e7da3e,921db767,6b7f9dd0,eaf8b65,eb08b032,1f37e9b2,1000503b,d65b80be,eb72f480,a43efd65,2eb784d8,650bffea,5559aa2b,104ea8fc) -,S(19c36161,7a448fc0,49cd8864,d2707d6e,9e4ba74e,79ae3d8a,c11430c5,99de065c,2f9f9fd8,fd38ee81,94ef570c,1b7299ee,75742d18,1610a2fa,4dd06f30,989acff5) -,S(3739848a,d2ab8a66,b6a7a2d4,add9fa8f,5a50807b,56ce5d39,5bd4c146,7083f88e,6fd71820,611102bd,f4dd2056,92e188cd,68a5409,1036951e,6f58162c,65f0cbc9) -,S(9c22cb45,261c2336,7dce66f1,f84b84f5,2dd7e58f,8ac6dba9,50062eac,1c10aa35,ff84e3f5,8c25be72,910bead6,286dcb9f,605b0017,1996d46e,c8dbee64,52a1116) -,S(572145c8,7f311732,7ecc71e4,5e37c555,5a412785,7513fabb,d0fbdd49,6db4538e,163e63ac,5e3908da,2aed5166,c121548d,5338c6ac,4ea7550,242c7910,8a38871f) -,S(c9f07954,d8413eb5,8ef213b7,51a966c7,4c641ed9,8db8685b,d931e321,2de940ef,9e6844bc,804f3d3c,a065fe7c,b09bcecc,92cf5af3,ede9041d,792c184c,cde17fd0) -,S(ac297f46,b07c8a29,d664a24d,f05a8a51,f7b0e4aa,e8800c3,f9291a13,787f25e3,686e3b7f,78e45ad7,fd1bbca0,54a5d182,b1556c77,753c1858,75e98de8,29b66cbb) -,S(6c5913b,b383a688,390274df,121eda23,5ad55dbc,80bc198c,21897934,98b3e1b5,54b9b83a,e3649f4a,2f11ebf4,61e24a55,53e5b4b5,d0f78dc9,1c35aade,2cb9ccf1) -,S(b9926fa3,f503356b,eca59ee9,2163cbf9,846e3efd,c793db45,cf7ea8e5,af2495df,d6dd7c5,33d4e7a1,ed415c51,1fc15e05,54fd00c,100bf047,bb8f9054,42e2a512) -,S(4325d1d2,f2cabe77,fe0ac758,f6073057,cb36adcc,5357fd5a,31473ad8,74e69556,de437968,2ff6315f,8870562d,560cc48f,818c8fb5,c45ad932,ed5a7d4f,534904a9) -,S(a183e95f,fd84bfca,4afc9059,ce1c40f4,eed924dc,d1bfff11,d38a8c1,14164917,11c57610,c7ffca41,145046d,4cdf95ec,c38d695d,bef057f0,a0d01bb4,41d64b95) -,S(b340d0d9,ad6528f0,d9651414,f48fdbc2,ab7af5fd,3baa8091,84d5e881,6cd07114,85ed726a,9ecd70f7,f964dfbd,40e4b68e,ae2671a9,b6c3d384,919d040e,120dd4e1) -,S(b52daa88,35992fa4,1595f0a4,c9e075d0,b146fae3,6c0d640e,8e6f34c2,16719377,6088b139,9fa83889,a6cb5cba,d478c7a0,4f42f082,24b169df,85ec90e4,7a4ad7ad) -,S(90bbd15,42b0f88e,9f7f82bf,7c2b5fe5,f269ba36,4523a18d,5dc5709a,2ab9d8ad,c9df924a,51af344c,a71461d2,bd3743df,c6958490,caa68743,e06e7348,528fc4e5) -,S(f72ee5a8,1696194f,ed3d4603,f2c9312e,b31c54fb,438b1fd2,2788ea6a,a3aa8365,e2963d82,b6ca0f4b,8ffc1078,cd45a72d,e66f4cc,78567074,4fc1721,e50fde8a) -,S(108aeb71,5bc70525,42f5d6dd,dfd348f3,66a10f4d,d99f9298,c35a8397,e6b9fb53,8388b339,75a58e04,a0f6df47,23728986,97b8d970,ac6bd45b,49b9cf1c,3209f1ce) -,S(dc3daeed,87345ebf,824a5ff5,c7f46268,fe54c901,493e2e86,e2667fb6,ff61d5b0,b5a7e641,238e0467,196c1683,bab47f66,cf001079,932a5d56,da20f89d,d93411e5) -,S(3f96a83c,2be16120,e81e1d26,e3853ef3,a82c5f32,f8d6bef9,38179c06,4265c589,eb8d370e,797cf20f,d5a0d734,9fbd027d,630ba1fa,bafffa0f,2ea37131,6b5c64b3) -,S(27caf86c,e1f423e3,1cca2278,244fbe3,b358357f,af1b7866,1de13b96,eff5c4f3,e8f77718,647acfb4,633ddbc2,3dbdca0f,2187e24a,2f2d45a1,39bfa1b8,a2b30f61) -,S(6681cfb9,e2418786,1887f964,84819645,2d301a1c,7c082361,67a24c62,f74d04f,9c89eb3a,7849e944,2f5f521c,c08d11ef,f1ce4869,98d4d760,8dcb4a37,b815151d) -,S(6711b849,48664639,67274709,2fbbafa2,fcac45dc,1795e80e,67fb0e65,beba8da5,ca12c83f,1c8f5ed9,222d8cec,bbcaa51d,6b986a5f,60d2c118,b812b259,294cfcc6) -,S(5ee9cfd0,b1102cdb,a0fd22b0,569875c5,fdd73467,22769011,8b7843e2,b71dd94d,1dd7a4e5,bd7f9ee4,e17c518f,19b60332,60d2294,8b5f463a,ed9021de,87d7d86) -,S(586dad7b,13390be6,f3d95a46,6d0224de,d7538f1d,2d2d9785,e38a3f2a,edf4924c,c777eda5,a68a3582,1735bd33,7119e58c,bc2fb101,c995f986,7bed9786,cc2b64d0) -,S(5a752d2,fa012c7,1924b6e6,90ddc7e8,867f6ee0,ad8eed91,84f7250d,665091ec,57f2232b,32b36429,f15029fc,5789042f,ec1ace97,5f2cad27,d53ae819,47b95db6) -,S(f93cbeff,22bc577e,a9cfef22,378eb142,426372e0,7be72e60,2a8064,a53e638e,abc772bb,401bdb42,94b16670,2279e4f3,eeadb75d,57190a59,96f34237,83afe50f) -,S(8c272c9e,96130972,2efc34c3,6a6e63ac,76052cfb,856eb8cc,3dd014e9,d2608a9,9987d168,13c57162,3ba7d226,18b54003,731e3716,3495edfd,e85e927e,6e4607b3) -,S(bf78a0d6,1519542b,a54226c4,d386ddc0,38dfd84c,9f9555e2,3e187c11,4d769bc5,6094e1e4,d84ec081,e6014b59,d42959ef,e160587d,315bcfe5,5d26ec98,b1910280) -,S(5b264b76,cd092a1b,ffbab651,f42485fd,497aaa5a,e311eb28,ee1fdb99,32e65caa,944f9359,4b68d7c3,6610fdc8,85695b06,1dd84722,d5d88c84,c8c188e0,69d70d78) -,S(a2473cea,8075a0d1,33bc1459,8d147705,322f7151,274e797,4b7e042a,c082b559,64de830d,b6557b06,d9b09d79,4f6c905b,5168d32a,708484b5,d2c68a89,a2575a18) -,S(3e18d5e6,3dd0c514,4341535d,a7087bd5,f14b0708,a292350,6528a803,609efa45,6e9c71b9,7d007382,f82fd041,be53470c,26dc2f16,26a9f0a6,e1d9ff67,54288c5b) -,S(d1acdbcd,b91e6315,bce96eb0,9c229086,6a767441,4285984b,71af6156,8294dfa5,5e3b0cd8,9872375c,3f807201,73e29d3c,accb67e9,66b99452,2c9e9f88,613da5a4) -,S(3aa999e2,9344e0f2,b5ecc880,a35ecf75,25ddb028,c40f64e1,a210aeb7,d850c90d,cd2ce25c,fbe3a1be,dd2e6fcb,e9e9a881,28c454e,c7ca1951,5673aabf,a543d42b) -,S(98a2361d,7c3815cb,ecd0aa4c,8a3a6ca3,3e1b31e2,5a4b6398,146d6709,61a5017d,1f33df78,3040c13,be821395,8d78e039,516df25d,4d9d0de6,d397128a,2c09f2bc) -,S(528b9d8c,907ab870,6d7a5562,84cb69cb,ff348247,be1b7cc4,61351674,53d98d0,f91eb836,d6665778,7c6d67bb,800a1141,29700d53,194c5051,aba7ead3,ddeafabd) -,S(f1adec8d,3d1b0d20,8bda6a86,6b8cf730,f4be50e6,2c8d993a,3556c1ce,625029b6,478324aa,c3bf6182,25bfb61b,32d47956,57e4a754,e08a978f,964741d4,1bcc7224) -,S(ab2ef133,b1b115ac,41870cf8,d75d4aa0,e0181ca,742a8f10,f74d50a7,3924a099,a2c47b74,c584eeab,57949ef5,38c0af69,2f2baace,70a730a5,75629ab0,566a91ea) -,S(9d4eb41a,f6da6f83,b1d20e2b,f9370868,539a617d,111b8c72,348c9b27,e0576f85,c1c7b00d,b786c84f,a8adfe90,4353305f,73acc3c7,1c2580d7,cc5d6b33,c5f30eea) -,S(30edd57f,7b1b2c81,c886dff0,5d9e9062,a553638f,9e4311d0,18a42229,3fb916d9,6bc4774b,16d257a1,81e20b48,5acfce30,f7449e64,aa288502,d44e7c4a,44842ee7) -,S(28e3eb9d,9a2b855,65c58fc6,a492014c,f10969a7,1e81066a,41d1c574,31306583,fc653b87,80734067,e5245c,8c150ae3,59ad3c15,df4a8e7d,dc93c8fc,dfbb6c2c) -,S(cb984735,e3c842d0,a2fbe578,ff3e8263,5a3a8bb6,749d8e08,c91571a6,9aac75a3,e935a0cc,7181c3f5,3013f977,ad714af4,4c3e257b,e9936268,b481429b,7bea8367) -,S(36186672,7e8307ea,eea83b10,6850dfcd,5e4d665b,20aa37a3,ed0051ab,a40fe170,ec626ed3,2ae6dc01,f5d4c710,ce2cb349,ab27cbf2,da5d924b,e32ef8d1,707a6d) -,S(b1a40d5e,69e9f365,c2accd54,dc8267bf,4260abb2,3b503136,2183b17,4c6b7d2e,76619dab,2a7b41f5,2401ff89,4ef632eb,31eddea8,bae27c3,af04730a,3dc186ec) -,S(abd488b3,dff60a23,e83f0ccb,22620064,b32a8f35,d4c22be2,42eb1427,15660825,6eff80f2,17dae3af,96c7a463,d1848bab,fa994904,91a1105b,e1bf7f23,840b3a89) -,S(ac0cfb04,d91ceb48,2f497974,321bdb10,2a572115,73fe4598,c92510ca,4dd6aa22,6b5f6d87,4a90d0a9,658ae4a,64474d9a,3950314a,4662ade8,1c5e5605,274582d5) -,S(1fa8be0f,476c4b67,697c7541,dd1d8be,a3a0bff3,552948e6,87baf11,afc34432,c6b25084,8038461e,32961d20,181c7187,fe79df6b,8f5c5e54,96ddb5ab,80788d33) -,S(281b43c0,d3738989,a817d313,755c5f0f,f336a4d5,7e8d0ec9,b29fb425,c1f90e56,26b5070e,ba1059c9,b73e3db3,1227a6a7,68683044,7f823689,921a9bbc,bc9f4a9c) -,S(d64e69e9,54e81ec4,7446327f,55e5a82d,3b83eb46,2a92af12,f0b2694,c88f4052,aa7ed55f,284c3ca2,9be75565,f66ea54a,27a8f00d,afaff0d5,8f394797,3dc8622a) -,S(f4cdbaee,d4b01db1,f0b5b0c9,d6178235,483fb58c,5421ba54,17bbcd4f,e4e7b028,66d590eb,29d69904,deb9f48c,5a250089,b2b92447,8ea91302,1ddbab19,6c63b47) -,S(8ff94c4a,6c46e334,feca809,79d21a0,761fc1cd,1de76f4c,7243ff0a,93c9dca5,123ddc33,5f3c68e3,29f42d4f,187fdcc5,77207134,a8bb777c,2ab08dae,f149abf7) -,S(c7869b4,6e34186b,7e87c0e6,23b64fb0,efed70c4,f2af5e70,5c33ecd1,27cf267a,66295439,36620898,2f17d95d,7da2bbd7,29aefa4,69005a59,629720a7,5c11f48a) -,S(e0ea76c6,ad5dc87,bd26ba9e,25b5041b,9836f72,6eec0142,351b2431,6cce1a4,8bd724e6,632049ab,88aa620a,78922b65,6a3a4417,c8af7dbc,5a03d4b8,d4eff928) -,S(2fa63ac7,3e5f8982,36419f1f,4883f52c,e8e357d2,4b4aa7bf,c6aa7eb1,29e30159,57e1601c,d6323fa8,f5a5b314,6b5e5c44,7251db28,6f79d51,7d0b038e,b8d8c3fd) -,S(74ed4038,d4c50930,22e783fc,1bb7a671,49d00877,b202012f,6aa6d32d,c73026a1,5b74f70e,65d009e8,8cc618e4,9f7bfda6,58234f80,38e9835e,80e6fd42,6b28476f) -,S(71d6aca6,e38713dc,6ded1f93,4fdf20fa,16ce75dc,dc405148,eaefd2d8,f0025f97,b4314533,7d48dfc8,278c6c4f,b19f69d2,72ffd4d,a22dabae,dd3e60a,7067e302) -,S(28fb47f1,6e91bc9f,9a2d5720,f40297ae,ee617ec6,897044ac,8a174acc,5bed5292,d04b6961,d72472be,4fcdb605,9943c1b4,ef8e7aed,2ba7859e,bdb84a4,f8b498f7) -,S(68fcd5f5,c8655b5f,5d2fca79,59a7b32f,828c5a5d,e262f6f8,94270ee2,1f47a37a,57480650,33627166,c372bc4e,7a710275,7aa1ad4e,5460dfb6,d3d27f32,778d74ab) -,S(c7617ad2,f423abc4,7ed7f8a8,a7a6002d,17c9744d,1ac6be97,49110685,95aa36da,d9904b67,fba96cad,cbe7a9db,833c614a,69e330fc,a06ca2e8,d597f657,b7121d9d) -,S(a7ef4e9d,2396fe16,c0e78b95,5259a9d1,474fdc21,8b24e8c8,df566192,a6487cdd,d6782604,91c6be04,98c3f7e6,86f22f37,23c1e4dd,4f7655c1,f40509ef,5af67f28) -,S(f3be7846,7ff03676,4ace420f,4091bb2e,71856d18,9e24890,eab6b436,771e2578,f3027657,45cbf3e5,67a6966f,6b27ffc1,dc58f3a,6811f309,434662bb,636dbc5) -,S(5c947f95,5bd9ce29,5214c30,3ebf4f35,6c8d9e2a,4e173470,94d3f755,36f0259c,b6b7b775,3e7552a3,d2dfdf49,8578a24d,90a81d8d,68ef39c4,68fb5ca7,b75e76cc) -,S(236fd960,c3b1735e,279b8702,8c25a074,2c54c189,d1040c13,4e4cf40b,bd8b2c68,9ab59bf7,c0bac18d,d0d9360e,b79a76cd,b44bacbe,b425d181,873ac390,59bbc279) -,S(c92c9f26,17cce2f7,659d0243,8b9d8932,c1a9e9ff,ca8b0d99,cd7613b3,b1947b31,abdea94c,1a5e64eb,65e70769,51ace2b2,e4804ddf,1539d50b,725fe09b,52357a51) -,S(986087c9,142c608c,33783a12,4d22c316,733c2ae8,bc1fbd2,8bd1a142,6da94fc0,14925bf5,fd76b51d,6be82c65,4562cdf,8f5baddc,eb26c68d,3fa6113f,ab42a1cd) -,S(465a1f74,f4f6baad,7c644e21,f35650b6,22424e93,83b421bf,91478621,a48a1d43,26da71e4,179430bd,ee6698d5,7db01553,d41c147b,83247157,9f2fe923,c788cb48) -,S(dd7658cd,f28117c4,4ff3c88b,d0b46adb,c7aa2ed9,1590ca00,785cee6f,5c9796b4,32317c0d,1e10e997,a74935a,8e45d27f,9a9b8ac0,f77dcf37,c1c7b340,cfcc43be) -,S(55bd2abf,a803c49e,b4548b17,725f52fc,6222af8b,dd9aed09,715ceb87,57c72033,34ad33b3,9d7344b3,abfc603b,8dcf2a54,96b991b8,41564e35,53adfc85,3d3ebf43) -,S(77be5c06,d10c226c,8c9616d3,15b1e1c,44006876,4189fc36,db0c88a5,ec12fcde,ccf2cbca,5c474949,88f27ae1,b0361b9c,20e8b55e,d965f7f6,ec8fd9e0,429ba01b) -,S(fab72486,3eb6f261,f0460b19,bea7dbdd,80b890ee,d4bb5618,30db6af2,f52ab21c,914f03a,408a2e2e,aa9174ed,99d80e68,b67f6afa,fa9da5c1,5d22f74c,8876d0b0) -,S(232a2039,fafe8b86,50a671f8,de78314a,510db65d,5cf105a1,9db8082,2a0b2f66,14ca7082,510bc1e3,533b9f6e,e216ec13,3be3a6e2,64d2e218,d95f3ec2,ad78576a) -,S(b3482839,612a4ff7,a0584752,68f13e69,deee9fa2,894a8cfc,64e39054,1b7f58e7,722d02ed,df30025b,eb4e9fa,f7c58de1,653b8224,66b1193a,3f2fb71d,5d26ae44) -,S(d3873a57,b0a7587,cab10871,a9322712,cf6fd84a,226dd7b2,85823996,5a353210,3b7e4984,59c7e706,cdff95b1,c55e3351,f1f45d0c,c9fc11d6,60e5e27f,5160f186) -,S(8828788c,eeebb2b7,71d289a7,147c0a7a,26a049c3,26dcb281,cc9b2dba,162c20ad,e428a195,87425f22,3d798922,b4971c26,5da2fa2d,de4a364c,c8c65f48,c07b71a7) -,S(79fee531,26d0c00d,74986c18,993fa174,52f8dbb4,ea75680a,37f0b3f4,ea7e537d,fde50071,3143f994,b4d7b4a1,43ab3abd,525cebbe,93d5b5a4,560017a8,802cb5b6) -,S(f44f39f0,5a9f5f79,5f0f3a8c,e03ab50b,3672429c,bf699cba,ac1e58a8,66814e91,b95e45d1,e4de1300,950a27af,bab28bba,ff75a246,46ac70e3,fc09da30,d59a1dd4) -,S(1138e209,baf9c9b7,b89d7d78,832cf7be,da45afbf,3c2fa148,50426ec2,80aa9abb,15c28d6a,3965b2af,ea28520,7e67f2eb,ac7d5917,9672f88,3727e499,f06a0d6e) -,S(29d3e942,1b98d78c,60e4685a,aa503130,dcd3d3f1,5afc2620,472b83f9,34912c1e,90a514f8,49680969,215d46b6,db7c53b9,411c8c67,c88bace1,a6d45ca7,d2bf5825) -,S(a8a36a94,5fdd33e0,4f0c18d7,cd2d4709,d6efeb88,a53fa0c7,e90969c0,84ff3eb8,1dd7f905,edbfcd70,26aedbe,1cee1cae,23db1fcd,479f02a9,bb596af5,f56ab564) -,S(5a048ece,b3fa944f,90eab4f0,c3e7a06c,3c35f2ca,81263fd5,3670c212,6a981eff,124f1bae,b70fed65,d53caf7b,5e88077c,8e330d05,692199b2,4b3d6d4b,b7c886ff) -,S(32070282,c5ebc2f,665ee579,c645fac4,fd1eb4ec,d7297158,3dc81288,e932b8ba,8f69662d,d68407e,dafb11ee,8842707,c17eda9a,803cbd55,b86dadf2,85bdaa17) -,S(7c22865b,fb04d3f1,bb988a7b,80a49fe,c7810593,27a19786,db77a47e,57afe787,a02eb26e,30f599d7,d5599734,439f19cb,d0830b72,60e70d53,97f06e1,d036bd3b) -,S(a0ba4c13,30ad8252,c06c8269,a3dcc365,fd842e5a,aaf33a4,22de13cb,b9385cc,58ecab13,5cfdbbf7,f3b6d2ce,277b9e84,940fdb14,47568960,c13290e5,fe239bc8) -,S(42ae6042,c8a2ba5d,c8fe47a4,12e2c0cf,7be448,70e67819,4e31ec23,44f76309,72ad69ac,7ba38bf2,2210a6e7,53c64467,36ea3a23,cbc96c3c,e19f209b,dea1542e) -,S(8f3ae8b6,45507a2e,3ea5d82f,47020739,d8f35f0c,8fc11e7c,6e802d5b,87b2a19,61bb8e35,3028ed54,1b83420e,fb9b1473,60425927,d3f9b6a5,d1d2b80,ee5b4cfe) -,S(3a84ba4b,1e151920,a0e4fb4f,30953e6c,a7ba1e12,62ae44c0,d91b437,b05df32f,b20f6579,43525f14,7b23abe9,c90e1d0f,32c44eeb,cddc6ce7,d3cbad9e,7d3e20c0) -,S(6481fe6c,b04a503,3ecc102b,de462e7d,7b87d181,2bc145b6,2d25fd88,e7316210,bcc1b4ab,f5f32ad0,9176538b,808c9187,d4e88b0e,aef31075,b26e5c27,8f64560d) -,S(5340174,722c583f,af9cd365,1f73b33f,8e4bd1ca,cac0af4d,1ff13064,d551a094,e4902135,448a616d,e435180,f85d0a95,d9e4655b,aebf8a41,a3bbe221,1a66a8e) -,S(c0693eae,a5825c4d,6c24e08b,d57bc32d,6c9ee2a7,90dcb49b,b350f852,4e2867cc,da20fb4b,7627411e,5c6c601,bcb8fb55,f4f6178a,efe0ca04,62c85d86,33b9a05e) -,S(c51d0f73,72fd0502,d17f9200,ca189821,e63e581a,8356735c,a91b6e93,3cfa0d9d,8d10e6b2,7ed7edd,2cfff134,54eb979b,a2797a7d,3c6fb413,b3bad4c2,2e352655) -,S(16811856,4d2d99ae,2daf79f8,58b52ad3,3666008e,d9d2c59d,be3160df,bec3290c,2bebf1a1,45617848,e81dbac3,4522cd0b,3e9cc84a,3c08602d,1adf77ba,292e7460) -,S(7ae94933,e1438525,b2ce1622,5654aa6f,b15999a,57835a09,20a49748,7c0afeb5,91912e37,830a645a,138282a5,1e3331bd,a13b87b6,f443f901,95a2f4f5,bd9b95f5) -,S(e7792d97,d02b76ab,2414c5f6,c2d1bf0a,c27709b0,55b2c36b,179599a1,3019d4ac,9f4d9689,5fceb179,b98c75a0,d5d56cc1,dd274614,a2816e8d,16fb98e0,ed3f2b52) -,S(2ffb9d4,946fd63f,24cff64f,4ac79450,3d97d706,eea6c4f7,69d9e34d,3247bde1,66b1c74,34881531,2bd6907a,6e3608ea,cff18832,5576fa9f,f32257b7,eb81014f) -,S(4544ba32,f90ceeb1,1412aafa,b4ae7351,aeb6f4ba,12e00ea3,c165c8b1,ecbb2fbe,62fbd7b4,c2a5cee8,bfb9ede9,b02dbbfc,2bba538b,834797b3,948887cb,9f8f6736) -,S(250b01b9,25d9ffa2,75eb156d,d8c67b5e,5d981ce7,8824d37a,1b09e3e6,7918980f,ba1d924a,32f0da86,e532bcbe,6766259f,eb185161,4042c0ff,261eb81d,3e09c481) -,S(9cf30e54,1f2a5fdc,73046807,32e962ee,62e0b813,901e30f5,ecbe1fee,abeb4d2,7cb246cd,1281b77b,19601d14,baa8ff62,848259eb,6567c741,c6bd54a3,b5510723) -,S(edc9e8b1,3c61a1e0,8f93be12,495084ed,b5a90eca,4f11dc03,cd217b1a,56285a2c,66c2fd21,7e8fac7,4fd43b1b,58c80661,b0e8df85,a2fddfda,5e9f99fe,621e1f3d) -,S(dd94295f,8388a498,2aaa4164,927b81ba,cae9d002,b3ddb6b6,97082c70,f1e2c66e,838c060c,d409c1ea,9bcd9e8c,b1fac83f,3b08c2b2,482d8f4b,fd3ebc18,8d6706b) -#endif -#if WINDOW_G > 12 -,S(7e068e04,dfc0be48,e5c0d3b3,5bfc734e,96e96ddd,d0ac4876,92f74535,685ab7e,df2cd146,90d225c8,d04052e6,93f14bf,69351e08,79883646,2c88401e,4ec70d0a) -,S(73a9bfcf,d10aac9b,46e659f,76c439a0,b7c2a073,7dec217a,21f43f39,949a5052,73b91529,3ea7b052,682062c,8f86cbf,bf379df6,91a9cec2,4a1424a9,b3be10dd) -,S(efddff84,c8cc754,e6e34678,d85809bc,55cc224b,f69be05a,daa847ec,d408c55b,65dd8f41,8264aab2,efe6ed7e,c45b4ac,8aac218a,3b6713fc,1736dd6d,c2f188d5) -,S(46a94585,7118384d,8d23d6df,a4386dd9,dc264f5b,171a7585,7565688e,bfd73f4b,3de5af7e,a298c18f,4dbf16cb,38e7f617,1e684ee8,e8df2a6d,256c011a,65aaf35c) -,S(6890edb2,7ce3c265,d4afa17b,be160a94,45dd0c8c,9ad6d93b,910ea47f,3821cd3f,60f47c5b,10ef5494,cd8810a7,ca8802ab,7c24beea,eb67b852,dd22040f,77cbd1ab) -,S(8cc9eb6,340b886a,81ec4b32,87a251c1,e33e68c2,1f55688d,952b44b4,2a05f5ae,9b176b0d,90e38290,8911981a,3bc475b9,f0323870,150c9c95,5078bf02,307fb6eb) -,S(2b062f5a,da48de0b,58001cca,e96cde15,227875e0,26c94e0b,fd1fe2a,495b0475,537f1c68,3d5170c5,8097bad,4bf17276,da9de994,8eff6805,48b35390,2f1eab0d) -,S(dd55b91a,84b3d53f,4332ff7f,224e9231,cd358bdf,27f30082,52d7a8be,bb7240f9,e6f1a08,a40b6530,ed737609,4deef969,774d2173,a3ac158b,ff681908,192a5c94) -,S(ac5127e0,40b1a979,46c0cdb1,c782ee2c,8986fd80,d7151e75,16fc964a,f2c59c70,849e2249,323d0539,dda0a82e,1764593f,8afbb097,880af8e2,4765ea01,b7ae5db9) -,S(df2f2eda,f0b6ce9a,3784e9ce,1e1ddae7,9d136423,153174bf,f72212c1,b5311123,b9d98f8e,bd78bc20,316da64f,46644026,fde6ab44,162027be,dbac75f6,e86d46a5) -,S(fd83b387,d630c176,23b85e21,62113610,97bdc5f4,3fb08027,73ff93d7,a373e5f9,9a962a7d,375f35a5,9d7503d4,c0fddc9,115805bc,38438837,d3c670b6,ab6cd2ee) -,S(d8fbdfc1,155ec8ac,8bead443,ba3feaa8,d565ca1e,4206cc95,5feb8e1,32cac4df,f9453c0f,ccb99cb4,739258ed,febf7642,7fb1fcd6,1f963abc,9cb9a5ea,751f73ac) -,S(9fc9749a,20a3e8c0,1b309389,16aaf3d6,85f00872,b82350dd,c89110c0,dfbf86d6,a2f679a7,6c92ac59,5773bca7,8f0f18,75c85cba,e75a6379,1094a799,863e19df) -,S(29e0e346,71a91ce9,bdabcf25,2e2196bb,65b81092,d3728f62,b58c815f,2f476a3f,2f440c61,b82e0ae4,798a35fb,9c66b261,1ce5ad0a,ab42f9d4,174bd698,d4d0c0e6) -,S(e4068a15,398955a0,f27e6f92,9cc3dfb8,7fbee70b,a86ee78f,8736b519,ae102d7,a3f2f2ad,550f9cb6,aed99943,84a9a350,16b91143,747d4e7,7d69e698,8f165086) -,S(51b45e10,bb1bd989,8bb156c8,a4c81978,10f16364,d3d55092,48a42028,726c9f2c,e30719d0,4225de63,281ac479,70010cc0,8a1f1d51,48c57f6b,b478c95b,e3e141a2) -,S(14cd5d29,7b8ab6b5,e92ec2e6,6c63b3d,64dc492f,d5a0c5ac,f6fcbfa5,aaa0b83e,5bf307d7,7cdcc866,349ad1fa,fb1c7d8d,5be19270,2a46b327,9b72bd77,e3666805) -,S(a5a8a711,49d6d146,c32254ca,e9c18288,45e9f2df,419ed68f,8c3cddb5,d22c4da6,9f47d887,7bc3d345,af4ae693,35639bf0,b003f481,7833d2d5,49c0bbad,3cbf6c2e) -,S(359328d2,4baa4232,d75b13dd,d146624d,bda494e5,2cc778f9,99a4c0c4,1f9372cb,d31556b5,71df399e,99084afe,c8f680b,b6695d7d,648f7050,a7881acf,241af6d8) -,S(c9eb81ca,4f2a5a2c,17268a12,d901edb0,c8fdacc1,d26c5e8,91af95bd,e673e7fd,6d4a512f,c974fe9a,711ae19c,d9bfbd6b,5acb73e5,355608df,76ed2942,488adb66) -,S(e26631f8,16f3b308,ac4c9f90,eb6102e2,48e55730,24f41f38,6ccde5e6,c2ca8e2c,16e0b2a8,823aecd0,165e2f10,20518253,96cfb814,bd5a248,58a4615f,eb9306bd) -,S(f76e9af3,65c0e7e5,7807b24,269c4732,677e5af9,a3b0a965,8db8355f,f99110ba,80cbf439,d26f164e,bdaf2542,385f9d65,9d174c62,96ada102,8a0cb013,bd2a9407) -,S(dcc8145b,af891483,295d6ab6,9a88fce0,bc333d54,841e7421,e65f6270,852c5dd9,cedb3770,a620e7a9,b40d6cd1,60363bb0,296155cd,80d89480,ccac619a,f31e2a19) -,S(7645e13a,6a1c4d0f,a56a199e,cae93018,7660bc40,41edb847,ed33fad3,c603e4fd,7c8ea51b,7990e5d5,125eccbb,5da890d2,bcfc5353,b22c42ee,1864c22c,be91e713) -,S(ba26886e,d74cbcef,afe7210d,51c1b6bd,4658225d,45e20fb4,4222b318,9e2f3f25,fd885db2,23ddadee,9e65fa64,abba326d,e0b89627,7359e893,bdf50db8,a2b3409d) -,S(68b500e1,31005b1d,901bda65,4a525e80,fc6578d,5e792c92,299d21a5,19050fe1,71ef7d7a,b3544a94,f3dac8e8,77da5468,8df9b127,83e02022,7e05d5f,6b12f96b) -,S(2ccca7e2,613fa83c,27ff851f,12c6fa07,5b19f7c9,940a5064,b84ea75a,da7996ff,5ab70a22,22dd1ad0,d0db2d2f,c59390b,cf37af8f,bed4570,3c6ae0f3,27d7707f) -,S(6d797d2d,6a56a45a,1b5af718,3cb6dca4,383ad9c0,4d5cf3c1,827f4da6,f7179f14,aae34e5,d203d18d,99e84bee,7d6f5a8b,b80e541e,15a3aea6,7b162551,e80edf3f) -,S(aa6997c4,37be76b1,9553751a,d96a53e4,9a565a58,55f67b5,11605996,e98ee327,6034a421,9cdb40e0,9698a15b,2e2f5f1b,6532e277,a1f4f4cb,3cc0c33c,c684835) -,S(56c40fbf,fb8e1d70,a345d53a,7b0f897e,1e62484,dc01adea,d010c5be,ba2a0f48,e9d06789,78b9290,27ba0e09,173d8ca9,676a4a78,7e299f4c,458cb6aa,46f0bd01) -,S(db6ff6a8,3963ed7b,dc262be0,8b52c3dd,b6e1e237,2a535073,1d2903d5,17918d89,a40112fa,f30fd44,b42f6b18,c144ca0f,e248d65,d757bdc,162b7118,7d951769) -,S(8df55701,a46f63e2,338e730d,4a543013,dcdd1173,754e5de4,151ca180,63402c6d,64cf9c9a,64b63ff0,1396ddaf,b48bbf62,b3e69665,bc89ea93,b9dd12dd,57a1c3df) -,S(9d10bc2c,51018f57,407ae460,e5dd5e45,66485cce,de258af3,7bef48a0,1b0588a1,38ea3c08,b2a4e171,7edebe44,e03dfeb9,726b302e,aea0eac2,fcbc9389,84922c04) -,S(13bbc875,cc07a787,2ca7a706,8201606e,560257b,fce7e66,2e4b9807,37640367,b4cd971a,47c82a66,d8ca19ac,baaf1b1e,d2ea3daf,d6f54769,7fe474b1,c0c2c708) -,S(8f26dc37,f617b174,dc947630,d0da6dc9,1857d9a3,13c92b1e,24ec9cc9,5ea9c3e1,3848a303,1d96bf27,4e423877,6591ac44,f887f2fc,1553375b,d5cf76e0,e73f15ef) -,S(2e1e543d,f290916f,5e55236f,660dbe13,a23e0d9b,11065041,ad3a579a,4c7b5f21,885a4527,626e05da,c10cd9f3,218434b7,947bc083,28fe2d28,ff10ad2f,b5473846) -,S(c83c2ca3,e0509ea8,bb876936,e3eb69b5,8bed8f50,e8c7b85a,1238082c,ee3f3109,2b9602a9,bc808de2,b0b0da10,d09da554,74b75e75,5301cc0e,3b07c331,329cd5ed) -,S(8c7903b4,e2c114e5,3264111a,ee385311,afee8b1c,90606700,578d1fab,d3d29607,dd02dad1,964df94d,1eebea9,a2a343e8,b488c401,88299b25,28d47376,f1025731) -,S(48263c54,dd7575cc,b30adfc6,c1c1eb85,b5185786,654c89bd,a38a681d,a6569cc0,e6f107bd,dacdb528,ed98e49,a25936ea,e223ac5f,55cb7955,ddadfb88,1213167f) -,S(6a7c050a,ea7d1f58,7918644c,63cd5d98,accb7127,c54ee274,95fb2546,16f0d2d3,fad19261,27a2646e,34bf733d,c089b0ca,f80f7383,b4bb1546,28d7256e,d821e232) -,S(e1f0a53f,62fbc202,df9147dc,c31cb09f,ece879a,ccc5a3b,f105a198,7f5c3ea8,3930a10f,b0eea30,c314848,94037780,3968f692,fe2e5d8d,cfe920f1,e5706277) -,S(bc0fb113,cb0fca5b,fd66efca,e8a4c866,da9b6a0a,6d4e613b,48526675,d3182b7b,e11e725e,6993eebb,d2715f69,13ecb148,37892c56,745c601,31ca1c6c,bf090f31) -,S(1fe5a0f4,9c438f48,64bf9ebf,89eae7b7,ee7e6a1,74a134fe,266b0329,cb42f908,db8095ce,f912641c,92b3878b,cfa7b596,694514a,ce9b779b,35ad6109,c675f66c) -,S(5de3fdb4,90167002,fa6e61aa,eabfa53c,ade6ea83,3f3c8f6d,e434320a,aa524cd4,b5cbde88,862ad6ce,b344a1dd,88d1ac29,6d7e9ca3,d5e98535,dc158579,147e08f0) -,S(93b06993,a913dfcf,5eeb0be6,294a645a,b2964f2d,e2196073,8adbfcbc,23da54f,7836782f,856cb744,4187330e,fca3c7e2,9c151ad8,1e8b507c,4d14a14d,492ae0b8) -,S(705740d,27d90741,e685a044,f6b055e0,9c33369b,e3815851,886b7860,8e762f0c,c4a58fbb,738d46c6,9e93193b,529f12ac,b2142b32,1fbb3c55,d3f5dc99,173d956e) -,S(7619a000,fc485526,734a20e1,99530f0a,e5b78767,61040864,34a1a1e1,1d93e296,7f300de1,182f479c,f6fa0afe,a2ceb59,ab26f675,77203201,4f8be86d,46ebed6) -,S(fe20f5a8,ddbb5201,6cd346fc,d281413d,cc0d54b6,384e460d,bec5428a,599ff2fe,5b488ae6,e2604871,afebe551,f9957b0d,338cf47a,b4ecae0b,ae7a92b9,242d879c) -,S(995b9727,ba7e52cf,2dd29e07,73c751f9,70768121,8ab88b84,422e1e3f,42ad11e2,c3c9ddc9,7ee41468,c4ec5e5f,529bd8b8,49c8d585,f905b91f,42af5c6d,2f7fd26e) -,S(cb4f2e4d,2ca94d7c,79e91344,55161921,636d26a0,d84c2a16,e267c242,702b3136,215eb6ee,394940e6,cf00df48,f7e2b8b,1b9b2f71,7a68ee49,bbb879de,803ddb9b) -,S(ca0a2a56,34b49144,bacb1070,7668eb67,4572b69d,5e1a4e6f,c722c256,b9fce397,92079cc9,74ab2fbb,a5098c85,56ada7a7,6e2562a7,bdb5ebf,e958eb82,d3f4841b) -,S(fb82332d,c6c0c0af,d72f27a0,24ef163a,bfadde89,67b4c246,acd6b922,e3af7c7b,1a697119,f21cb690,338beaa5,2e2c4b1b,2b90d399,19ccf0c6,60dc540c,a934c7ee) -,S(d056ee05,d9258def,20e184a4,e2018bd6,d07550a0,63db4673,6afec42a,5c513dd2,af2c1d0,d222e356,67e7cfb6,201ad727,89ab0fc4,d68dc31c,276d998c,bc15bffb) -,S(3fadb222,c6584262,c4046c59,4b778635,c6325712,cd828726,7aea1253,42526f12,da5c8c07,fa6811d3,84ca7e8b,fa1d74b7,d181e0e1,eab86717,58666b7e,c199ae96) -,S(d27ac969,e222e50e,5dd915dd,39d3e453,214b818e,fb67e924,8ab4263b,1d9c4b61,c4857694,baead305,6e6709a3,28403236,9a7c55a,d81e7f6f,9b494a76,cb3a1c7f) -,S(412379b4,8b981ae6,a5fa4324,bffd69ef,99cd3a01,91a1acbc,d9340f01,72c565d4,f24036c9,c7dbe4f0,2ca523e7,ebe6ab57,c755053b,245523ab,ac9d3e87,fcfa280e) -,S(d8234eaa,99374c13,b9a8cc3b,663d00a5,bef7909f,b21243ea,ce9dfaa3,f79336f1,b8cbe8e,c4b465f6,6a3c1593,292babc,1845d8f9,1dc80e5c,b1ff904b,6e755c27) -,S(426f8b35,68c5ff9c,bac0ea34,9d8d3c00,427d323a,3d877bbe,47fbaf2a,5d189009,4e02293d,ce023c7b,9c7a1ba7,27cb82b9,9931f57f,78853bfd,7dc4399c,bd00586d) -,S(f1c706f9,2ee5f2c,2412a7fd,c9ca5c79,8717576e,c780f6cc,fe72760a,4497dfa5,c5e1a1a1,727f55c3,b3978700,51a09b84,9ef75895,d6b9c4d5,9f85cfac,2bb7e740) -,S(84e2e07e,cc1d5987,968d6682,525356b7,5982001e,67598b67,608f1869,36c2c679,41ab1343,8ab5ecdc,cbe75a8a,b7fceba5,2903f4f6,f5b43bb6,28173866,cc28555a) -,S(7935eec2,fe535823,44abb699,3a18cf6a,3d599b0b,ef0f6068,9c689b40,76ad2b54,ce2fc96a,ab978861,b6ced574,fe4f5c85,b77480ad,e3d75b40,6c4cfbd5,53371910) -,S(d542a4a8,319f6d56,b79abbef,9da3a009,3e8c2689,421e3839,27aa6a30,b0dbd9a0,5104a162,65d285ea,8f99f3e9,c1951a06,6badb70c,985877a4,f1979aec,7b8173e1) -,S(bc692619,42289890,4af0157,a038126c,41011b9,26fb232f,d3c27d9a,44ece2be,8e2f10c1,47e2a630,9372e854,3cb8ef77,11e2022e,db25f4f9,847369c7,fe52f3bc) -,S(ebe1b736,bb178c08,deacdd80,b48ab650,ae079a90,95f43e51,f4521bf5,d18d8d03,ad81c659,b1450de,45f78ef4,b2a8126b,782f2061,fc8eebbb,cd0a2ea,cddb7514) -,S(e626b908,49e1853e,4fdf887a,df8f0562,666d094a,9382be7b,de152dec,b9e2774c,90cf55da,a4192a27,caab406,2cfb8758,2dca7342,c59627c3,f513ff9,f4834ea) -,S(fba7a057,ba048792,2313b8b5,ba4514f0,d8f571c,bc7ac0b6,1a987a9c,e4381e67,7d2af7fc,142653ba,bf05133f,958a57eb,7cea5b90,ee5300f7,18cee7ae,d69ec44a) -,S(144cdb95,5b5d5181,5a2e5bdb,57033e67,239735a,456579ea,1e3be689,94c35a54,e6016f89,e896fc59,80150d2b,8135b4b,ed0a108f,8a2eaa83,91987a77,6253f1e6) -,S(538de6e,e7ab1b5e,cd74a2d1,a9599d9f,ad28cd8f,2679eb6,81c25e1f,183c0a24,36c0a747,79611193,5bdbac87,d5b38a05,2482b973,213d0960,1de8404b,14121004) -,S(76914f0f,d28f73ee,20ca3806,263b757c,7876eba7,54bef2e,9d10615a,ebc03794,6de24dca,e16855bf,22355786,1626c62c,59330752,f9f8808e,c3930680,33a12642) -,S(69915e6c,f675f7da,f595f7f9,6c912f29,86bee7bb,aa5800af,27e32baa,9e34e4a7,6094fbc0,2f109855,77b53c91,8dd2da3b,139bc31b,77674d56,df72cf22,2b9513c9) -,S(4ee6c20c,900bd4fd,be942dcf,db91182e,2c37eb35,e4287e5d,859ba847,18ce3015,84ac9769,863d618c,4b738e66,8c293d3d,42e2a9c6,4c47cf75,90ed50f3,2062cd64) -,S(a6813c1a,f57bf8a3,8ece11dc,a4c8c581,aa598211,af9ec6a,d2271796,88a0fa61,6420274d,f4e29631,5b7e2335,e98fb2f1,d415c99b,dc5a00e1,d182e809,5b8edca4) -,S(421003b7,107b2897,24dfc743,275db49e,69d91077,6ee53d6c,fdfe6ab,710fce84,cb955569,7b924395,c31cb149,88bcfea6,a932087,3aa8002a,c218f33c,76f9427f) -,S(9cb19e1,cb8c4fc,4009d362,eacf5f25,5e125298,5b546df8,fc60bdc6,48c8c522,227015d3,2c6ee68b,63e20e70,ed7cff86,8fd286e0,905bf623,1b7e894e,c7d70d12) -,S(c7413596,8193588f,38f412d6,4e2ce0cb,c4a7ac4b,75e33704,36236362,8bb953c2,7bee7fa0,1b7cc4d6,d22dd4c9,ec16b39,5e1d70f2,52778801,9ae75ef4,a908aa6b) -,S(2a8e8a05,321f4926,e8fac1ea,8a97cc64,c2f8e398,e86ecec,9dc2e676,61df22cc,63b86507,4e4fdcaa,acb60c21,c0d3f813,64f0c007,faff7780,9c81fbdb,981fae42) -,S(f3ef2e60,7d403594,48aab014,ea8e2dca,5af1d8c7,c6f66127,3552293e,d497a14d,dfcd5334,214b9f44,bc5d1d96,49d78c15,9e9ce44b,f43dbca9,c637c31d,622cccc9) -,S(6d5c41c8,169c33a5,d1111b36,1b1d6713,a9396424,bbfeb65a,80e40280,4857ead9,4c1f74c4,9f01bc2a,27a91d37,f59bde,3d674220,a521aa4a,6a0c548a,a45e84c8) -,S(5d812a61,c6a986b0,2c5982ce,34fd478d,60822322,47e07c73,488c71f4,4afff85c,37083f7b,16018fc4,25749e16,4c923484,680b1517,8bed41fd,cc8da253,ffa960b8) -,S(e01596ec,b82ff347,c3ba9710,82911855,720177a6,9efa7d5,dc6aa847,7f73093e,a674c832,849884b9,d38da5d0,6a58e4a7,a17acac1,8776577e,5547eb3b,b45b3bdd) -,S(67a5a900,313ff2e,7b32fcae,adcff7f0,ad52b960,ef6b0d0b,8344402c,9980f55,e77efddb,5e8e8865,eb807575,37c41e0c,9fdf928a,eb8b6a03,f41703c9,3c0a4a02) -,S(2b96879c,2e2d0ad8,281c1647,7de62583,53d77db3,57281c21,7df0d7c3,6466b277,dd5d3473,43bac32b,cc72408f,64a9fe7e,7e0dae06,786a7074,3cbbc846,80b62b25) -,S(ab94378d,f08748d7,2df137ae,a3e3e123,639b054b,fb726bad,825e2d9c,310367e9,5785ce24,40037d11,a8331865,c78ddaf5,7f9d769f,f2df11c9,9e3dd018,43a10f03) -,S(70782556,fd6fde3,8c93def6,ca3b6c8d,2f3fd4db,87be4985,fa3aabb0,43e7439f,7913bf65,ecf15020,cc5274b4,8eaf5351,51894bd8,fa236af,8f9b3fb8,178ebec7) -,S(3025d070,138bd507,b338c72c,1024a3f7,6b4d5e80,efcedeb3,e71a018b,77ca3942,3a8a6a0e,175eff95,a94172b5,f2a4ee53,8d503295,63a5b096,f83dd669,eb470ae) -,S(3fe372d0,65e97abb,94069e7b,2a8d01e6,576081a1,93897ac9,901a3d18,b9ab0b6,2efcee92,3154dcc0,377315e4,1d67b5a4,82403552,ce260c2d,4c1020a2,54842e5a) -,S(368c7011,3a9133ee,97ebe8f9,cc06bd7f,c3c373e0,da810164,bce5a30,2af55636,21bd40fa,4870a8e1,6f28b942,bc169712,eb7d70e5,a6faa4a1,35bf86b4,d06162a8) -,S(7df8ffd8,beb45e4e,1e440f23,ad6d713,57682f68,e54fd003,87eeac94,ecd96810,3d9e4cf9,908e5a99,44857d78,94c7ffe7,dc55550d,a07d3c9,ec07667d,982ed0df) -,S(cb6ad939,eb49c7ee,7c216262,49b11276,88269172,504fb8bb,dd2dbf7d,b6f23d4,ec8604db,18f27367,de1319c4,59f8e668,5480ca65,e1789cb3,45e0018e,ea98346d) -,S(5ae526c8,fc319e6,e054e6a7,59d9b205,d8a1e042,e684c53d,39098f28,70f4265a,da1e1281,14c25a90,cff3ef80,d5577c08,a03f4bab,d9e33850,f2488617,d50a9a63) -,S(868d7889,6ddbacc,1bbf2b10,e00456d6,17477767,5b8d3323,a8786ae7,25ff7661,d92d681d,189b0df8,e2be57ba,a9c146f6,46e6ce48,342a0ef2,96fc3093,af22ca1d) -,S(9f2f0b4d,e7b881b6,c4dd1f8a,74106a32,23bd3298,47c325a4,8341d899,d7686b74,6fbbd511,c2974af8,b5729ca6,658562f2,deca285c,b47f16e3,c444fc14,8e440088) -,S(faaf222b,813b0df1,5bf2da98,3ee2eaf6,c522f5eb,e8c08b4f,e6950376,d3fca8a3,bec53e69,2e98dac6,8fb2ae87,44f12abd,47f00e6c,5d6d1469,b2cdb41d,440b472e) -,S(7f5209b9,db4ab9fa,2c2a7ab7,6c5c62f,13c81c80,a4ec4008,fd67d229,a7161475,a13d6cda,f9e8699f,f397d1c7,6f191cd8,a58be40b,9acc4ce4,e69cea0b,4a48d193) -,S(f436156e,80b136f0,8065f395,e2700a14,50c7b492,405a0c04,6834bf4f,12c84c2a,cdd957b0,5684e01b,a760807d,39b007e8,e7aa890b,8882a0e5,9118951b,bd7e60c4) -,S(ef9aa749,5c5b37d8,2060c2bb,3454fa6,88216754,2b24d69f,201f1c31,3cf1d06e,f840da4d,f1d84a8f,ac125750,e4e6cd7c,50003aef,d1f77666,54ccf4ca,f27a4aa9) -,S(7deedc43,e96eb93a,c290809c,25e7936d,6d9e1cc8,a5971d40,b122896f,fb5de05a,e65c0e66,27b9d0e4,e7b349,ccf12fcd,de6683fb,6bc93381,22026b65,26a8e0ce) -,S(5a1bef15,6669795c,47be7495,582f361d,878384f4,f283e15c,e74b3ce,986d6459,ce985a81,1fdb02b2,9e35b97e,1833e380,69b28b81,ddf8cd61,b1179c47,2ccf39ff) -,S(d8123d39,233413c2,b14eeb78,983c6fad,73b8fdcf,84b2383b,fa453558,e525fa8e,ea9d399d,905b7200,46ff78a5,abb3cb56,835e35a3,c958095,ea226947,a633ef73) -,S(62f43dd4,f1f4c310,266a36c3,909afb5f,10d3dfd1,a7a6b5d8,93931334,e4d4bc8,bb7589f1,f83bd647,2e34fe22,53a101f2,75525829,daa2e8ef,89fa1dcb,b590f3ed) -,S(6cf371,d549c045,1415aa75,cf594d4,865f6e44,6f62df4f,cc1cf312,f79d72f7,f8ceb62b,5c979bd2,82a4ce20,682b45a0,2b3dee9d,68ce16a,7581adc5,c9e93af4) -,S(5bd7b780,770be9c3,7c1638dd,8f954086,49aeb371,516bdf3c,509efc5b,47cdd7e7,d46c7848,8a87aaf4,f606b91c,5add0c25,efc12c03,2a28b1e3,2190999,286ba9ff) -,S(c7704954,a319bd4a,e5a08665,3b959ba0,81eecd7f,f15681af,e6bf3db,c36b6a62,373543e8,24784ba8,3f53b9c6,189ccc4b,e508f600,b15c7378,36e3b3ca,516d0fe7) -,S(2b4f27fe,41533a9d,d807da70,7102c1ee,d6e92c8d,9e43958,8fedc6d0,39b19cda,98ba8310,ecd7cb1,c11fadd4,a92f4c30,49ba2180,24015d6b,89e2ad9,f81fb424) -,S(e7d4171,b3dc34d,2600c581,d6931f97,2c920c81,3d7c3db5,4d306c8a,5d4c0e5a,b29581ba,9a825387,99fa97ef,b5a6c4a3,3e75b71,d1cd51f7,5b6144f2,4a9a409a) -,S(6203022c,18f43577,5270043,56a2717f,2face761,e806e84b,2b5660d5,f1c5d52e,18a52f25,5d0a4d75,275fe97,3542b97e,212efd6,aa8864eb,6c80865,136a720d) -,S(bd81c7a2,8c1c80db,a0e327fe,3b0fccca,48987679,791e6630,e81c004,92e43b2b,ca50a84e,a14bbc64,9e0831f0,7f185536,416064ac,e93a8678,db1e2347,803871c0) -,S(9bc43e1a,d3c1390f,cd1385cd,603a6e0d,b875eb4e,6f3a554a,626a9b4,fc4bc29a,857a58bf,9aa54bb5,7acd8b34,b79717b2,64ea39bd,d8f4a22e,6b12e6a6,e0cb2cd4) -,S(3055a68d,194de3c7,9ef0117c,b98bfaa1,5e5bfb71,c656f908,2c8769cc,a7e40f33,183f9ea,dfebe1c4,bf0218cf,b6aba6bc,acbd8c72,a7fe086c,1c9233e4,340d1d10) -,S(4adbf984,ad1fd188,c9271072,43583b80,2cec1231,7d8bbe1b,71079fbb,734b08ac,14527188,9560ceff,3d950766,8e3f2d0b,2192ceb6,f79f5954,7094d5e3,d7ec04e6) -,S(38f72dcc,27e041d9,c7bae397,9cf16d22,83fc6a36,aa074b0c,d00651d1,a56487cc,5238c97c,33a106e4,1370d6f2,c0b6ffc6,49610444,2e51988d,f7160c3a,933dc0bf) -,S(de55bd8a,7bdffde0,a1413828,ac59ff2a,4560647,47c27813,322188c6,655be2d3,477861b0,df5b25f3,75f9d097,97b0afb7,67bf9d51,b996d51c,e65d3bb5,42d9da) -,S(c617bcfd,c47e02b8,918edf98,666fe912,e19340ea,6c567893,8739b89e,5e3bcc66,b90ba117,357e7683,2ae0f4e8,644cfc49,a6e04672,b5b08d47,3b826349,65117072) -,S(4655c196,1b5188c9,4b6402f1,e92b3033,c455f4db,ecadb672,4adab3bb,f1c84758,3ceecc93,a2575f4d,fb202df4,f4bc05ea,714600c0,28389b5c,f2c1c6dd,e6fbc4a0) -,S(fca90f40,dc05e5ad,3693c503,fab43da0,110df431,9c1dc4c9,e5f86e8d,d7726a45,f5822f9b,be3e6604,1af37aeb,19a70a6e,7478edec,68c8e1c3,e6cc86fc,5f5771ca) -,S(3176cc4a,dcb28258,779e88d7,f90d3b3e,a31cbe05,78c7cafb,93ff151b,d27f61e9,3863f2cc,148a0a43,c94fe7bb,afb5ab5b,6a18ce44,56cd06aa,c340c231,42cc0135) -,S(63269f73,d124210a,d070db15,14f82cc5,51d9c19c,d31a54e0,b811e650,ebb2ddc4,bf8ec7dd,8a787a42,4a74114e,5088c387,38246bc,3f6aa188,e300f0db,d85cd0ac) -,S(679a1d32,8d0f53b6,1ae7f544,541326a8,f07e749,34dd2708,dee3ce54,632003d0,83ca1348,8f21eca3,11be341d,5f6ee9a6,c9b3eb55,c9a3485c,349018a,725c350f) -,S(69a27d79,29982c84,d3948568,a54d8933,f7172f9d,e80276fb,846cf399,e0b38b28,f411d207,cb0f0bb8,574b16a1,22f39bd7,69c8b7f5,ac2db4f3,a02163e4,3bb26168) -,S(298d5057,1af5042,cbff2171,6029cef2,abfdabb9,cafebc7f,9dd56c8f,6773ee4d,f4343e71,d271844e,412e62c4,bf6dc36f,4271bda7,9ccfa220,75e3c055,aa97e9e1) -,S(3f2983da,46d1f101,8f8eb984,5bcf3930,e26f66e4,544f63b1,f8f8b979,200c4653,4973a914,c4ad33b1,36d57e6,b326d380,9b2c38bc,79d81b53,b26c5995,9d71db0) -,S(f836fd3e,30ceb88d,942d64b2,a1d2a6f9,54412ea1,ef6a3b13,59faa8bf,7e3538dd,720a3081,53476b5a,709fd29c,158b7720,c8161ee3,6e6aba3,b28e0282,cf7f9367) -,S(dd72eb9b,911e38a2,63bc8ee4,fe991fe9,295ed522,1eef930,b3ae2df2,ef583a,2a0da5a5,688bf7f9,79285d9b,360b53b2,398e86b1,43f10b86,83cb40c9,40c1b2ef) -,S(551e2650,46ab255c,c427bd81,8258b7f3,7cef92a4,496119be,283f033,4968a619,317c33d2,4cd8f35b,9b86a5ec,d1582a6e,e5ca16aa,3c6ea23b,2007a370,e7bc4f30) -,S(6683de92,131de3d0,ecb19a30,47825591,ab28cb61,5c852a90,fbd3ad78,5336c650,49eea58e,7fd95523,f8a9556e,c46fa0e4,b3c3b2c2,8e5d9e4,d636d089,282225f8) -,S(b5b3b1e2,84a6ea65,e0a9b146,e8f895e9,ca99ef3d,31a4bac7,bea49c89,3cf97805,a1720a94,f333e296,f2b91437,e19500be,3cf16cc3,547e9667,ffa4ee88,e5b6fe0d) -,S(a5019773,7c337684,9709a232,9718d463,ccdde43a,55350d10,11a2401f,9bcbf466,9cc069e,ffefc5dd,e8fa5e09,b6b751eb,c51fff8c,fbf3c27e,12efad87,a9d429e2) -,S(9ec3498f,eb2bd861,42841b66,3b1c58b2,e5cb7224,88e2f849,e1236b63,ec1588fb,e00c91a5,e14b97f0,362719bf,2150dfed,e517e585,a807333b,a000652f,c1f5f12) -,S(e10b6cb4,adc13185,750b446b,ab926667,581f97bc,5aaf04b1,f4731abe,f3c5b6b2,53a51213,7db20477,f3a87bba,5b65c01d,d5520b42,f2660ed3,c1f5fdc8,35e2b9c3) -,S(b754a967,e36ea7c7,98c93691,e02b6043,60ace927,13b18d0d,3ff61ce1,dd3ae314,8a9a3963,9aa7ee59,a42f8d5f,bab01e50,d83ee029,933cf59b,e12b82a1,5473d849) -,S(5fefcb61,c10cbf3e,6f8a51e,6bea569d,7999a275,6340ac8d,489183ff,32efa869,d81b3093,cbc4835c,1d88c093,28c20541,dfe49950,9b349207,15bbe1bf,4e881e83) -,S(fe51a3bb,4ac97e1,96009400,b27c8995,f0ed6f0a,b29b9184,70aa442f,27d2d848,8568fce0,a4c39e44,f2b8aaf,59f0b183,d306254f,83cbd6,ec5fd568,c9116a58) -,S(6a3e4629,9fccfedb,c58d5d38,aeb2a420,391df798,e447558d,7b591466,fab7dee3,1bed8fba,7bb15d9d,d42e7b5a,3ab1d9e6,89873eb9,e3161a91,aec3ee9b,22a5e548) -,S(adfdbcb8,3c40d4de,f7d62d97,e16bd32,33db304d,392492ee,7457ffc8,97450c37,7b082bdc,163549ec,2a8b588c,4156ac23,8fde7819,2e1cc195,6be85b87,f4138e0e) -,S(96850fcc,9c202c54,83654c27,2d17011,509ed7dc,6ecc6cb9,f06c3dd5,113bf61,10404432,7f966c49,af0c05da,c7ec18b5,b9fcc455,a01c3b6c,88b8b0,d281aaf7) -,S(2ae21197,8f78ca14,d88151ca,804379a7,1703f514,166f3ac4,f09409b5,5c458bbe,4de74cd9,576035fd,451c7dde,387961ce,2328e327,fa0312c8,6cbc9dc4,19ecf7b1) -,S(edc18742,e1b5c996,2661a332,cd62c426,7e5816e3,c52746cf,b79eac61,1a987e57,80003b3f,c63309bf,3f9d484f,ebabe579,29ba9032,30311bc0,2c021a34,5b4fe5e) -,S(7802aa2a,5fa0f0ae,29a90885,c8b94368,38b35d49,843765aa,1d6a640c,fe43a244,c7f329f,e63239a8,407297e0,416c49bb,7e3dda11,85baa5dd,7f5f7167,9192a803) -,S(fb774579,b124475a,c36ede71,2e3fc5aa,c2173de8,35e72386,bf67bf7f,992335cf,c0e66b51,63c17b7a,e43ebf0e,31a8d641,b6f413a6,b763ac01,cdfcbcc0,47a82c94) -,S(d81a3d8a,43abae9e,32f94881,fe9c1200,695a9c24,a31b6982,51e21b3,fcbc2852,630dd811,e8a8cb6d,7bf51de7,e0a98db5,a693e3a3,c9064dbf,2ccf6bf2,dd12673f) -,S(519fcfd4,97cf068b,804da0c7,e2268cda,7cb2eda0,4be5249f,9bf776b7,c7324cf0,bec6f4cd,198ab3eb,be691646,6e44ab9f,a357c8ec,3bca391d,c20e6ffc,9562fdb9) -,S(cc4ad3e4,8fd66073,5e193853,e0f9b1c2,3e31b284,e2770441,24f9296f,868ef592,88af158d,8583c474,7d5520ac,67b03c75,9b12151e,db25af68,996263ad,d783c27b) -,S(add950ae,6f5186a5,98b40cf9,64ded6ea,c06a57a1,4b85de33,8f709034,78d24117,c59ca4bd,2d69285c,debd6853,a0bec744,111f6dfc,7004d65b,c047bff4,a3affa7d) -,S(dc071b45,43097de7,12bc8173,cb358af,ef0437c6,7c4927dd,d0bc3f6d,bab383e4,793912a9,899b304c,173b2adf,c187dfbf,f28fcaa0,fb11b85f,9e410b40,e95ca8ed) -,S(5dce337e,6db6099d,a9c37da4,a96b7a72,fd97a672,47f6babe,94d79b1a,aec167c7,1b887fba,1f098a43,b6482991,f16ba2a0,eb35bf56,64eb21d5,7549dbd6,4e4377f6) -,S(516eb6ad,8493a662,6d22ead8,e808982,900a83f4,3e6109e5,ba284cf9,e1f5cfcb,ca350ab3,8085b46f,48d8308c,61d3f947,ef6a8511,bb36fe3c,68d30fef,ece05042) -,S(f767c150,3b1f2da1,e5b91211,4e917c87,732b3fb8,8c860a3,35af1c7c,f00e5e75,3ecef8c8,cdbe467b,888f64a2,655ddab5,9ec610e,153cd657,95bb473d,a1aaab54) -,S(f9bbebcf,f792c8c,a7bbc5d8,f177de7a,4185582c,2cc65e75,31f3ac26,73c977f0,290ab4fe,fecb3a26,256f767b,8a19e55f,ac751eaa,acecaf52,b8c99657,49614a85) -,S(c6bfe1fe,be5c8db1,f55bff42,c123df61,6ec3adbc,c9b08e8e,af477fcf,4d47c45f,c595f882,d6d6a2ff,d832eddc,95679890,41c27101,347ea995,c79ad56c,d641792f) -,S(56c2d771,808fb4c8,71dcfe6e,5170bb47,c5559521,8b872425,761829e5,e0d3ce1e,6de72ae6,9e03e626,fdca9188,9e721c61,12ec15af,7163629f,5ee0fc9f,540468ba) -,S(20218b05,ec9f5be5,87a96d8c,3c0cf7d2,da9ecffe,fc604fb5,66a3667,5109d663,2ec1a7c2,c5357e24,1f2ea0aa,7a7321ae,b41bfa3a,88b42e12,e79283bb,ef8f6993) -,S(3a089269,a04ccd9,5bfdb4f3,3494aff3,519035f4,bb3a4f09,e2afcaff,976be4ee,e5680e25,fb0ba1fe,91693757,b3404b32,bbeba22,640da757,ed91ad85,6842d1a2) -,S(8f9f2296,a0cd8b53,db0fd0f2,59860496,dfd3e101,b2975a2e,2856523a,f45b3f07,61c15907,2cacdf31,b229015c,d6290d77,8ab3be0a,57785920,a3fb5722,b5c625b5) -,S(86580be8,695bda97,cd1599b2,6d4b6328,97e2b90,d1ea106c,836f474c,fe88070e,abae68a1,7e19ac58,38a2fe5f,d07dc7ee,2bb220a8,9dba4ac6,166c51ab,b17d7d21) -,S(fb6ac38a,1e69d589,ecc5b4f0,e57aa1e5,eb1f9458,fb187d04,8c72dd29,72b4d762,d601dd16,bec271f3,16f1d3af,2b82b5cb,e5d1806f,b960014,7fb01301,86ac32c1) -,S(7c10606b,c54fea81,bf3aec94,72bb09ce,c5bb7d31,b66e27b4,242b8dbe,7ea5f0b0,12215180,d3d65643,76583987,240b445a,2ea522a,3e0250ab,d14d77db,bdf68f54) -,S(85e6ab94,833593bc,74c7822b,1d9f384a,740a5be6,3b846495,2042b017,2d52a1a6,f5c160d0,68d6f86a,8f651213,8cd28e3e,d6e69fcc,dc75f0f9,81fe5ebe,1fae93a) -,S(7e1e2d3a,99cd1ba0,51b74ea0,e5471f50,5e626aec,b880ca27,f02113ad,ff51cfe5,413ec82e,e9d4fe37,8c232229,136f1ade,c1eb96ce,c0062997,81f4b009,9dad89bc) -,S(589640ad,813735f2,ed7a08dd,6931c61d,6a9490ac,729c2bd2,928ebd01,e87aaacd,89d6b10b,8a89fb4b,3679fc33,96c4cd5,7a1e909b,e343ee15,c1a02719,20485429) -,S(7080cf4f,f3465ce8,fdcdb0ef,3741c19d,91fdd7d4,44118c5d,7b7ad040,5e6e6608,7a3f0da9,5cbc0ba0,b5c6d334,f80db1d8,3033489d,34143d34,7dfad89f,8e2441fe) -,S(bb660b4c,2d400269,2dd96bd4,d7737c31,91deb03,6553e61c,7d59a876,26917c55,b494ad13,a7560497,6068403,15e8b86f,f150af11,18dc02fa,f5ea3f40,c0983c24) -,S(73a241ec,7ebf15b2,4408161c,5d8a5c65,3f4f4fb0,8cddae0c,1e2c506d,9f221b27,80534bb4,33a0a56f,78486504,1d480d8f,64bbe192,a2f6f32b,5e1bc175,d463640a) -,S(fdc1ef51,f08bfdbc,7705741e,6a2b58bf,9e45f202,c3d7ba6f,89a15aaa,78b1fe07,7e9d00dc,dc1e4878,647ac05b,55832540,1684f714,755f4e36,880e5a0e,996c0586) -,S(204842cb,a0ce5cc1,3ab44736,ea0e33df,a15ab13a,912687bc,6d6733d3,a33618af,afc92205,a6e991cb,fad18741,818a94f2,9e1804dc,2145ba35,896f92ac,c96bd521) -,S(a03a9c1e,f82c3151,81009567,50486869,a47c4a99,83bad93e,b2bcb60,157ed768,786f9164,fb9c6980,eef3e5ee,d9a43b8b,2158ba2,dcd8663c,a26cf19f,f6090a65) -,S(5e3b6e5f,6cb41784,6355e3ff,7da813cd,fa18bd42,c54565ba,ee19b15b,dbc00ed2,b9c3a553,42bf2284,fc3b8f9f,88d3e4d9,9d6f358a,c5c8acfd,e340036c,42ee603f) -,S(19b0960e,82d1280,663dfbd6,efb2746c,abf76476,1029a54b,154385c,a05dbc70,f8b28bbc,440112a9,45f35645,135d041d,33df5ded,92116f31,2d2664f4,e5504773) -,S(1061e900,7597bafe,74b9b274,ba1a22cc,6f1c2d1d,b6be8d05,9876638,dff3677e,707ac922,dec592ec,44d7b59e,be2518a5,fe2ffff1,4cf4cfa9,8155c781,21444b21) -,S(c9184c11,60fc7d87,5439b567,69a0e501,cc0e221e,3b155f57,9a71cf1,f3030b85,880b69e3,7c04689f,d6dd30f8,75f23899,8e83e594,9fb1ee30,8c43e982,28327805) -,S(a35fb304,4dec52cd,8fc5af94,e6c26ba5,c8fa2364,2622af12,d37559ff,4374cf04,1544f375,692a3584,ac7adcb9,a3422dcf,8b360471,85326840,42dd755c,112242fd) -,S(ba8c03ad,60ffebe8,118efbe8,eb130f6a,1b2c501a,78000a8c,1b204bd1,b90929ca,e95ef729,a3f341e0,faf73211,2f7800ab,65b88d47,ae137722,f11369c6,e3aaafbe) -,S(d2ba5755,842d8a77,97fba189,f49a010a,fe08495f,5e64bba3,361d1b52,8f30ddb9,da3669b1,cad179f,784bc5f0,c3a55d60,549e72c,390b7d47,7c030bfa,53df7957) -,S(3e04eb58,7ec988b2,77b1d2b2,880ccb24,d3de1579,54ac994a,86db9ae,6c8703f2,fa412113,e6dc85d9,eeb1d650,3df96fbc,ff3c6089,cc5c207b,b98cdb4f,e728dd9c) -,S(efe5bb42,4339a49d,3e19aefa,91f466d6,60c9f120,5df91ca1,7a0da3c2,699fe7f6,98c6212f,fb39640f,cea21db2,97cf9fc5,e3576b0a,7cb4408f,f9e3e9d3,245156e9) -,S(a29442e5,a330336d,eefe6591,5c4e0ea7,bca2dc2d,9816c8a3,2bd66a4,baa0908b,a1bf8829,7320e47c,3b774c13,a6fb9e6,dc5e7789,44666311,2db427a9,dea135e6) -,S(454bccba,6f7225f6,a91f632d,1c9218b1,48e877ff,8018d371,4da8aa88,f08bb792,da0ded31,2d532b01,60a1106b,202ea0dd,8157753d,a07e0e3e,918958b7,45ec713c) -,S(3163940,32c39566,cb0631af,a2505404,56573782,e940dfce,d425834c,dcc2dca9,18c561c4,1b15b0d1,a477464c,6f4d668a,67f0895f,a55544dd,8445a8db,cfcc5fc7) -,S(54b5375f,53f07bf2,f15fced,ffc7132d,5240893a,3bce0a92,bc4fc884,49b07703,31be2b3f,a944251,e52922bd,fa2ea218,f5df11c6,d67226a7,b3f163ee,61abdee7) -,S(283ce31b,745d067,2bfb9b6a,694da3cc,de9033c4,639e8328,d2b7ee6,58b3bd,f6a948a4,d452bb56,e3dc24e7,6e81d2c9,dc1c7aa,67aab38f,f9d20044,d8c0245a) -,S(b5e74f53,117ba754,7b12419c,b0494579,48d5f831,624bb3e3,a60167f2,10e99967,5f635754,d635f9aa,a83c22e8,9f383008,3da8331f,4cfd9b5e,10d48280,718dd3e6) -,S(681e5f32,cfa33183,170dc776,fcd51daf,d587c34b,1cd27134,a856713,cbf83080,c587d8b8,d144e4dd,7b4361d9,b7fcf30a,76f646ef,fbe390e3,8f241a54,7279266a) -,S(1fba5eb7,722f289f,2521ec17,d05df56d,2f28b221,5ff8c621,b925a5fd,29f1d0c,df1140d9,97ecfd4d,fa7f287e,fcacb66a,34283b63,5b2bb7d1,524dcbe9,eb11f5ba) -,S(38bff4b0,df378b3c,ed38fc5a,733f1bce,17855b64,cc254f20,31e1300a,6a0d0a77,6d4f065d,f634296e,64c485ee,32537475,f35a5065,e73bfdc2,520dca1c,6606b1be) -,S(707013c3,59a9264b,be4050d5,27b5798f,779df8a0,77cc95ed,6e08f74e,e57de831,b9f379a0,315386c0,657b8dcc,53cd98ae,582313a7,632e4c3f,da9c9157,14ea422) -,S(ad94ed2f,70282484,e490abbb,320905ab,fc5b8c91,9de6535a,73da3f63,45642ef5,9dbe8813,a554e1f3,e98011fe,c6545216,fdf4973,6d026bd6,cb8702c2,aac88457) -,S(47b56de4,e991876a,499ad155,2443785c,fd174f87,58b881f5,4f545584,ff62612e,a140537,5855beb7,7c56117a,5f753777,383d92d2,d4912d9,86bd59a5,7cefdced) -,S(51bce64e,9291a693,1f24643a,f11f2813,f31f624d,cf336af,3cf7b48,15f431e8,8f743d9,a3012247,ee35d28,4120394f,f40c4c69,d75ae13,a063aaba,ed07e552) -,S(76287cfe,b52c5a0f,ce98e56b,49b4ebe0,83b80bee,3bc7447,a0cb9542,e7f7a43f,736b7e56,fa5744bb,d39d064a,50d98b07,e9e3399b,dc5847ff,13e33eb6,e2a7a7bc) -,S(614d739e,ad01010c,3191aaa2,c1b7771a,8dc29bcc,f1c4d55b,181acdc0,df6b8f5e,5ccd4e8f,e8607b76,c8a96c2c,5000464e,5591efdb,aaf07166,4f4db66d,c2f8085) -,S(c38444c8,ee8c35f2,b339404d,90d53ed0,35cd5889,89663808,3e2d33a,5e4e1bc9,8b4408cd,de5452eb,dc222109,287fa9ab,1d2ffc9a,16b93f44,1f4bfaf6,6ccd29f2) -,S(8a9c9649,c6016f35,d819bf02,852bfde6,56a1c197,2dbb6539,2391df7a,99c8f349,b2dcd957,be2c19fa,6c4a6030,a4cb500b,1797aa5a,339181af,dc6e974a,d769a8ed) -,S(a0f5cd1b,e4449709,25d0ea0a,6cd28d75,96292ab4,1d1766bc,ed6b3311,bea04b03,d270b1e9,291b29b0,ce045d92,3e449ce0,c8d7931a,71cf4b8,68af9594,927ff95b) -,S(a78f2336,87675987,7afbdbaf,28e2590,25c64ddc,a9543a64,709d4c11,1f3a9614,1365fac9,a5d245be,e5245b3a,b1f50d19,de34aa9a,439f5e7e,e241f042,32a6de83) -,S(3bfd37e3,ae482c5b,92baa6f5,a413a46b,af6cae30,9ee3fb51,4a9fc3e4,b391769,2d930818,34bbb0dc,66e424a0,7778c9cf,d0219c06,4dc7fd66,bdc554f0,396d1c59) -,S(92cac49a,261d23,e776ea75,7e796d2a,d426f23d,602ece5d,1b41cd71,d13881a2,8c76ec13,8e0f37c8,99a3e587,a8c0c5d8,c7a43ac8,187a35da,c0d8492e,571521c1) -,S(cf6ede0,ea7dc67,cc370894,1493567b,718944de,7a96dd6b,82940214,b56842a,e2b717d4,e939608b,7ad6128a,53dc8c52,fa070d0,f591842c,a76e8d0f,54627cb7) -,S(6204c998,ba512945,26ecb92b,bb06e218,968c8c2d,11e0435e,3dd1bf82,fa91e17a,1690a15f,e78365c9,c8fae21e,f0af2a3f,d1ed18c7,9a607939,d12d8add,94cd0ea4) -,S(a2c4fb48,cc5500e1,35268d13,a6ac2e16,d8ce0707,f2237f12,ef71affd,e4c0aa5d,3809440e,e608c897,cb7e3906,c58123ab,c403f57a,8d59b950,9e5f2d70,3c0cd839) -,S(d8af7fa1,cc303e4b,c5da36a6,d3b2e309,6acc8ec4,d73224f2,b667873d,eb656f60,9fc7f2bd,5a5533c5,dfb39f9,7045b135,5e14d81b,9edeae5d,dd4ccfff,f0c6de0d) -,S(3e9a00ad,b873291a,604e6bbd,b05304bd,3770733e,d1daf90a,864d775d,76dea0e7,deb49457,f6d1c4ef,53524e37,f19a8d77,20a5cb9b,321b4630,51f8eeb4,901ded0) -,S(bef5ae9,30aa620c,9854346a,ac1b2ac9,760ca8d5,ea189368,9de50e5,d3dc3d7f,20d80c42,f7925f59,b0212b9c,7d4041e5,5da98a3,fe373034,c0fdfad6,48dfc48f) -,S(cd4169fb,cd28d507,6c174308,8f39645a,38215e47,888a435d,5922b490,9155f67f,f9e62ca2,1a5564dd,5a65f274,356c1b68,a170dac6,4b5aa5b9,29dc2f26,35e74674) -,S(a4b691ed,34cd2624,fdda2504,797d76cd,4bd37b11,4cf3921d,538b6042,ed5a4c28,c65374b1,6781b4c1,15b0ca54,53e3397e,5c045a77,72c72d12,c336c205,d26af55d) -,S(5e4e916a,4226b788,197cf68f,aa850c0f,c2b3a615,bf9e847d,c9e55dbd,88aa4818,3f3c3ea2,5c7c52e6,5c9991f4,464f4b2f,f3395d05,3eb27280,8d984a31,b798951e) -,S(dd4782cf,f4d69f72,c951b3ad,50a4c601,f743e6ba,2194d05c,a5f474d5,eba74a7c,97a7bb5e,9854ef7c,5e3dd6ae,8628d8c2,5d3a791,d4db281d,6c7c12c8,20977b99) -,S(a1530ad5,4ab405ec,ddb94543,2669c07c,281aff41,13e4af0b,cc080991,c1adce36,f3d25221,2732842e,5dddda78,1e2aa5b1,b18550b6,fdbb968a,77444958,4a63e756) -,S(51924ef7,b438e4f0,614523f,232af64b,e5ee0d32,ad8e5323,4a2d76ca,9e64719e,87c115a8,11f94db5,6736e82b,8b644bfb,fdfe6e55,8ead8176,26858c77,128a8095) -,S(82cfee68,e137d874,107625d4,be20a9d5,6ac9055c,6b97563,a3bd5568,53fada6e,dd49aa46,c4f5c51c,72a804d7,6dee7a72,a363e978,502a5cc0,6ff67987,30733b7a) -,S(a3738876,f7f1ef44,5a1346b,36c7da6,e02b70fd,2cc3bf30,a4efd7e5,5f2e623a,6596f52b,e1ea52b2,be0de46e,5480331a,b1204d36,581b2edf,368d9611,ea04a21a) -,S(ae4ca6f7,aec818d7,2b624fd6,b2ccf24a,8d8382b3,18b0dd7d,d8203658,2980bcbc,6a7ada03,35ad7c57,1e2a29f2,554c8bbb,34815596,1aa995e9,2378c97a,dd8f1ae2) -,S(be33562b,fa9d762f,9b18d198,4dccb9c8,4d6ac894,2d8506b1,400f7dfa,89d12732,b666efb8,77c666a7,35336cc2,14e874a5,c4f5c956,903048fe,473d2e6e,9475d442) -,S(9d7da6d9,815b3db8,5303b288,8a60ff6b,f382891f,5c45ecf,37cb92da,37c74446,46c29073,72ba5be0,e61f6d73,4b413d44,df3d2c0d,89fcc1ac,5402b68d,755b12a8) -,S(39233d31,e513c2bc,c0602849,8bb7b3be,b5981fb,7c99a366,b62a9df4,3b0d4d3f,fc27857c,92e0ea4f,4d8ac3e1,c61fa774,1ec57d4b,a9affc81,f97e384d,b916dfd8) -,S(5be2d788,db90e83b,58d02dd,7b58f41a,547e6f33,a82d84b4,3f7e5143,db7768be,b8cf3a8,6b2dfa33,e71396f2,e84fb6cf,d585ef6b,9a264875,b9049f2f,6fde1026) -,S(3ff59de8,191fa14c,113600c2,5700479e,7c53a0be,3827f5d6,82f7861e,88f162ac,25d5985,6ab0b6e7,beff5f60,c279a11f,8ae4efb,5e79a4df,d815cc32,2dc77ba2) -,S(81dc9c30,ed221920,98ad9475,da00f8d8,b61a18a4,e6305b58,75f75bc1,719a256f,2970745e,5c44cb27,a6f8f9c9,869a25f8,9cccf024,4d40ffc2,ca678d28,f54682a5) -,S(ba3e1e16,579c4099,1576121b,230d4f4a,ea386943,bb7a8d24,f765a3e4,9b70e9da,a1eeb808,653cfa67,8a9d8d9c,7d30e7b1,54eb0de6,55abaabd,90f82236,32c72f4e) -,S(35ffe81,50faaee1,141f52a5,1b7d1e69,fa66d194,3b96f04c,a0589c48,83f854f8,d66a1822,e83f6dd3,fcca09b8,df1105c0,b4ad3163,6070dc9,b7dd08a8,c9366fad) -,S(398ebc22,1435f972,1c214c0a,e38b9817,8b50d7e3,e5724f68,5b950aad,60763a06,c2df549d,eb2eeab,fccd4da7,fc2c8ce9,15551b87,14903011,6825b804,80811f46) -,S(2ba27f33,e7d0a75d,1d18511a,84e5ce1e,9ca89d2a,a44fda0d,6cfa1389,ca89e96,5023684b,832375c3,8f39946c,c91ca114,45c2ac54,fcc12f19,c6bb662b,997cf4a7) -,S(4257063e,7ec51f92,4ecd485,653182eb,2b54973e,f1ff0144,65cd151e,f9e829c2,47351f41,16dd0515,11c9ab35,b69abd64,919f8b5a,812ad5d7,47c5462b,55232c1c) -,S(77e737c1,b5b3ca56,94218582,d2e56519,80da8195,88ee46eb,e3ef172d,9b4063a8,f7cb5c5,e66798ad,37c8d4f1,1cb912e3,651ae45c,4d7b07b5,e0e20c2,89d1587a) -,S(dfcbb64d,71018c1f,bdef98b8,2a4cb72d,ef027d43,47b5e8c4,4a7eec7a,34cdaa4f,dfc0cdbc,c7207588,8af379e8,751c4f09,bc2f4e58,2dca9a92,e06b0c5d,97972a23) -,S(8eb686d0,a7871e8e,32ac5256,746d7189,b39855e2,2a52ce78,ce6962ad,d355ae8a,ea8b3611,fec52837,fd0afe42,4c22c5fb,89b79675,6e8a6a5e,d71e331c,6ccc30da) -,S(d17d8713,ebaf2dd5,316703ff,8c4c20fe,ee56522d,bea7a987,85a96b1d,36cc3e54,ea70b7e8,6d7862ca,9d8a7a19,bf8941d0,e9fdb872,4e46f8b5,6821d85b,ddc10b54) -,S(7d4c77e6,ae050a1c,856d28e9,c14eeeda,249c471f,82cd6cfa,3ec037e2,30b3ba89,c5a07653,f5fbdf93,4b180f39,327d102d,900ad68c,3da1a7bc,ea773fe9,6265fe60) -,S(96381109,451e5e68,6d61d51b,3b250bcc,3721dced,de39e88,f4f50c1b,4d7ebcab,9498f419,b088ca54,7f17642b,dd6f0fe6,9f06514,a7228394,7f15d165,64801b64) -,S(7400b550,54353d73,7b2da8f2,f8f4e953,85f44e83,fda3cd20,8afaf90a,978c2ba7,9933aca3,ce503677,e2129a04,cdb1d5ca,e36bed1d,275048be,6b18aae7,fd909771) -,S(3d7b0c11,fff7bfd2,71ef5963,9f12ebd8,d1de3bc3,93b51be2,a011e4ba,66ff59f,b6397431,7f7ca0e5,ce1eb57d,8a886144,8bddb12f,75469789,b791c4cf,32404b9d) -,S(4944d9ec,7ebf7f14,e6312545,5c8dd996,45d128dd,fde3743c,5cd6f4cf,65c46328,f0655193,13baaec1,329cd408,c9d1f3d3,5c2f49d9,126c9d1f,5bf271bf,2c589996) -,S(9960432b,4764b1d0,f8607d6d,8e08b355,f37b9933,69bacb51,89ce46d2,79bdecf1,304ebb4c,921d2fa,29200ea9,ec214adf,f7e1a9f8,debab865,78fac56b,7160ebd) -,S(313f535b,63585658,fc3409cc,726b5ded,9196cc59,6331681d,9ca84aa3,bb3de4d6,e511a48a,a55fe0eb,e5f23bcf,d01ff4f1,59b049ff,8c999fb3,dd64092f,c56c9716) -,S(85c4586f,8cd36dc0,db9b9006,ef4f74ec,c99478d6,5c011bcb,3ccf034c,548ed7b2,cd6953c0,45c5d6c,dc632592,3f9b0070,144c8c5a,67639f63,a75b4d10,5b434229) -,S(968bc6d2,a7fc359d,1edb668d,b7381eeb,d489b20d,b64d651d,21d706f9,94671af8,fb0ad6a3,723d707c,c1b2f330,4e59517e,de88bcfc,b52f3ce,d0bdb7c,f0725186) -,S(2325aceb,3722e77e,e6cc7221,56ec0e87,26d343cd,cff6a420,e58c563,bf28985d,601a7f53,dd295978,f2a59683,6f3e9eec,19b9c8fd,e81bba5a,21acc8ff,878d39e1) -,S(8c6e76ab,b2313bea,dc0667f9,9aaf32a6,4b1c9335,87c31dff,5407fdd,67acd2e4,27e3b850,d422df3a,c93b19c4,229b390e,3d7bb92e,340daa46,b3f5112d,1e50c29f) -,S(e31fee31,34468d3e,4d6b2c72,8d538a14,352e7a8,8b9837af,9d8d4230,5e36748f,89b096e1,2d1948f8,937974f6,b9a101e2,37f9df3e,280d4139,e419a1b2,6d0309be) -,S(596b586e,849404b4,7c742fdd,7e5a3398,da748ab0,67ae2981,215c17d4,b0d306c6,e96c5cc5,912cc711,5e4e8f05,edadf219,2ac27760,2b2ce791,ff6e18f8,62a0a16b) -,S(200cc167,5cf500cb,a199c3b7,1195270f,d453d5a3,8313f317,71452486,15aa1c02,780aacc8,7e34429c,6445c133,49240371,1905e24e,c17de4b3,e7b79cf5,5320ce61) -,S(7e4d5432,e10e1fcf,79148f8,77a4f247,70f0e96f,81331767,dfb5e9dd,2ad2025f,35f5dbb2,6ee82837,f37f5fd7,d417982d,fa58f0ca,13e3136e,ec0b5251,63aa432a) -,S(c1ed7508,95c97e6e,7a78f800,b6eb10c0,ff21f879,352870e5,776bb7bd,9c0237b7,90723a06,8dc0aa89,9c31e89f,64ffec3d,a38e8095,97209bb1,d8b1418f,eb418fb9) -,S(e5fd4ae8,a53e809f,83d239b2,a15d8dd2,9948ddae,6956d8de,fc7ce730,b2104770,6a4dda9c,1cbb2197,208e8ebd,35f2ddbb,50c7bf5,df4c112a,de02f0de,f71c4fa2) -,S(3ce75f2,4b33bd88,7ab72cdb,42f9ecef,e3534d15,f6733f2c,a766eac1,da51f30d,9eda315b,51ddf6e2,62ce9b5d,828af559,a43eb48c,d3dc9362,13bf04cb,1a838ed7) -,S(98c04c4f,33a81cd4,e498d8ce,77edf598,527fb9a8,8e19dd34,ad8cef3b,8813391c,fd2bcd67,f853f812,f4371c46,30560957,acb4843a,8ff21949,483f0617,ff8bd3a7) -,S(50e9c88,2906cb06,cbce62f8,413ce43d,f3d2dd28,6e4141b1,fc8a079,a87bbf3,43c713b,b05f19cc,685eefb2,ba04474a,479a615a,2f3c8a9c,e1c6243c,d82fa3fb) -,S(5d41ba17,458bde3b,64faa66,3f21b76c,71bf6564,2a73e3a2,eeb8a831,43adf2d1,17effc54,b3082159,2b39e22b,7ab058f,7f64fa7,68763510,87cc445f,57b6cec5) -,S(4e332cbf,2a02593b,6e83cb8e,1d92e076,6b34cc60,646fe3e7,89d38f9d,24d5b077,50fa745c,3ab90300,95b69985,99e391e1,744ad03d,decd1955,c8b2a859,e79e1f95) -,S(1bbf629d,27ee825b,c357455e,43410507,c83cd47c,dddb53f8,34716ebb,35a2dae9,850908c1,e99753f3,4f40070e,c0bd85e5,8fb72f69,601d3709,71ffa894,3de9bb75) -,S(a9149aef,f9dbd62a,ad0cb3f5,debdcb30,23aece9b,dc79db8a,a25f5b01,b5cde650,a7bb4b46,e6db111f,468a16d0,9df686d6,ae3c148c,61d99a79,918f0bf6,b4c327bd) -,S(801009ee,185d642,19de5b40,6b21dacb,b98ffcdd,75f8037f,fc5e1721,fdb72a71,e8216609,57c7ad6c,1dd36f70,645c75f1,38283905,898650f2,daf2e5af,37e26441) -,S(c070e99a,e466f67a,b234584,66f132ec,96c6b639,3900468a,b7368a86,c0ba6770,883fabdf,358d4f56,8a56f77e,3b291fff,be6f8fcf,9c0f0171,a1544905,50769362) -,S(6be89639,cf612761,78f549a9,ed0af9a1,8e028c53,1dff79da,71c5ff1f,54109f4a,777aed7d,dd379131,26a92f38,ff9970c4,ff2dd6f1,6d766e0d,8215fdb3,9604cf14) -,S(d1fd31d4,1ce71e4a,2052e79,6dbb1a87,10094505,2b9d9009,2195afc5,9624ce8c,f357abd3,78a8029d,eaa796d9,1860e5e5,36d5f2aa,ea2bda2e,5b510949,253fded1) -,S(1c85382d,66fef14b,3cde617c,a426996,614c328a,ead99033,7aed469b,8f169d9e,58c5af1c,b236e6a8,4f58702a,b727d9a5,e2406a4d,fdbf9113,a8f895ef,78a71f9) -,S(2d8fa9ed,d5fd67b7,42e5c2d5,2c128ad7,eec32cb7,43cba12e,272edfd9,4f36b5ea,71b15f39,37eb2a09,f9533af4,bc964c32,23145340,f780731f,aa9ad1d,8f2cd37d) -,S(4f512379,d9f6c596,700d0a15,950ddbde,40ceb1c6,87030c95,4c538122,dfdbafb4,54de9b05,f864df5e,ba861980,c7dd8567,4b320afb,e0381674,c7f7c083,4248c05b) -,S(9a5f91ba,48562c21,58e60949,6d43eca3,2c69995c,ed93e834,168d22c,d9e7cd1c,9f88a3ec,c668eca2,e01b1126,6acf9c51,29bfa33e,e12f7638,2d40d2a9,b722b86b) -,S(dda30502,d417fae4,c4ccc6b6,e833b75d,d84d54fe,d58fcf0,6577dd8,52f9f610,fbb88dda,2e74641e,6d45468d,102e2a42,7f4c57a,6c7fab0c,5d4dbfc1,155469a1) -,S(8d2e9e7c,5586141d,848e50cc,631ce5f4,600dfb1,618d65e8,e88da5e3,5b26e117,989c39ec,ffd67c54,d55ab4fd,85c2a556,bb72fabc,f763c9a9,e33a1ed0,251aa86) -,S(726ce076,e6b63d6c,b071cee1,c3d1da27,10c911cd,e3d59bbf,a27a7ca9,641ee995,4e41baa0,c91ff8d3,4d2d01ac,d8ab5d36,6ea5e81,d489595,1c49622e,610af9c1) -,S(debc91fe,183503d3,fbac0dc2,c9e95062,c0d42971,ed2e97aa,27dbacd9,bea43a1a,13593715,a6fece9a,f33b2ab8,d5f26e6,6dfdf3c8,ff688100,d497a333,be2d2f11) -,S(c5394335,77914ab8,e7039e8c,472ff2d7,237c794e,d6b24f41,c585e910,f0fd4b28,2805359b,628a9c4e,7b304112,80aa2a0d,23c26cf6,9a47310d,1fc6fc54,cd26087b) -,S(9a2892fd,33c300b1,802bf1fb,e8a8faec,72b81810,4bee4e1c,c998bc79,a05f29b0,997f123b,c2fa0136,522ebc53,a5ce37cc,5538705d,f5fa8beb,b37f72ff,45186e33) -,S(d4a22cac,f224fbe,7ed7fe42,7e0bf180,1503bbbf,d73de79f,4c558104,b39a351a,8268fe97,30622e09,2a513349,548e346a,23260311,a82e860,341af6b8,3ace752b) -,S(4a4cf3ff,15adbe1d,8d414963,b0709fb9,11d4d2bb,877dc03c,77594fb,9cc11659,57c84583,36f1952a,62441810,ea64ad3,5109a30b,c39ff36f,c2dedd60,d1ced874) -,S(58c0eced,b580d530,98c836cf,42ca2648,e85e0b27,871caf44,1f69bf0c,158e1539,eaf79c49,1e1dbc94,4e63d36f,702cd1aa,92e54a09,fa11ffd7,4121783e,e842467e) -,S(b0fbd0e8,a60c7e89,38a154f3,fe586a33,26132302,7f4e416f,634cc9bf,724892bb,27ba767d,6757f40d,b54fcb50,104998ba,6dd83f93,137c3d07,9a0330c7,82a5d3c3) -,S(a94ae12a,26b0135a,125fecf3,e4ef1844,ee90c2f7,84cb4081,8c16d8c2,d992f0d3,a37447ba,665e7595,c7816a6f,6bba3d66,e046fe36,8877c95,bbc8a760,218e2050) -,S(8cbdb09b,3eb74fae,32b6c484,4f9004dc,c540e240,7305aeeb,9adbe308,8cdcbeb5,2b863a2,91f6efd2,ff07b14c,4e5a169,912df745,1b49e3b8,10e72cf4,34c932fe) -,S(3f8cfac3,b70eebe1,cc6fb89e,d508abd6,ab3131c,40d37afc,f8f39c87,34cdbac8,dbb02111,846ef25d,794b303d,b48964b5,a68b5287,b443d321,f0c493a1,2d58b65e) -,S(b61604e0,cea3e79c,12fe9a4e,1816630b,31fcaf4d,b3ac84b9,547da60,df15b25b,1aaf2bad,9ea0fa5b,56665b41,ba1264a4,317d5388,9018d92c,ea2e9d98,29b86801) -,S(eb0e7410,3c6ab38e,1c26630a,7fbd68b6,fa51bda3,64d1ca3f,7c86ef0,451327d7,dfa05017,57c4d3c1,9541c9c7,d9fb7438,45cdaacc,2ee377d4,4c36817a,e0e82e6d) -,S(636fc503,be51e64c,8dad2812,6762c04b,1fcfdd7e,4b25544f,4bcd0bf6,9556b7ae,57b83b0f,5104149,7f3b6735,a8b7d886,b633c8dd,5052d1e6,9848703a,313f4cd9) -,S(2fcc70ec,4d42235b,c6afc2bd,1d2de19c,5ba9dc65,4ea3e288,c15c7358,e52ab330,6a356018,2bfa1e22,db64cbbf,cfcdb695,35bde8e8,2519d069,39577e65,256a30ce) -,S(115006c3,8d38b8bf,db8969eb,d6bdfa95,83be81e5,bd5bc7d0,1cd10e22,7ea94b54,6043ad02,16eb3fba,9af39e83,f6e87802,3fac023a,73252780,2505a1d4,2080e08a) -,S(17d565a,15ba1c29,60ca2da8,2fe54d01,3756a986,bedc19a5,15b653f2,8db3aaf1,917bb9dd,42040b3e,4b8b05aa,b9d31252,7a633819,33534c35,f274ad7a,9bc7399c) -,S(dcc2489,88501c43,b8598f7,a3e5bca9,d2af8f8a,b482f30e,2374c6d,6b221ef2,a859757d,d5c6ec52,b1f102a6,ef00decd,cd14cab5,99f1eb0a,57864646,4f652e72) -,S(a68b2b9f,4e9430b7,cdd919db,6e808a7f,ae2cf9c3,d43cba03,d833fa8f,351f0b0f,e34b8a32,d3ad0923,8e95614d,92778021,7f45b14d,f2f9cf66,d6525bc5,94786526) -,S(2f954e5a,938e1198,5d2d11e9,ead59539,fe7e2f17,4702d3c2,3190829f,8d0e9462,b2f0d379,fa8b7d40,ba2fecc8,46a393b1,f6aaa6bf,9f89ac61,e55ab1e7,bb16dd5) -,S(223d3d13,6bca94fd,9b3fcae8,6bb2ddeb,3cc33c8d,3ccff556,fa93938c,c27ffe4f,87e19106,e317187c,c256f7dd,83d6219b,27f6cd8a,53bb4ec0,9c74ca58,51512915) -,S(5591d8e8,291161b6,43df3a3e,9b4f495c,b614432b,a0f3aabf,517834ad,9e8f7b2e,2c8d6a35,f6267e52,d9bd454e,bba4719d,30b3fe7e,c40a1416,673ef594,e6d07c2) -,S(eb2cfc4a,d15d1a14,870cbaec,b9e9aefb,4141841e,2e4e6252,c8e93751,45f29a29,78810e08,10bfd992,b7b04c79,c7650150,e62f210d,6d35cb95,5bc67215,7052e5ac) -,S(6112c3f9,9680a818,5e4b1d4c,539cc436,bdcdb47d,2e19f927,d5e3e9,eca3f74b,6e860bdd,723c8bfa,dac8f9d4,1f6ca96,f2579d7c,6a690f35,3b8da52b,98da4403) -,S(892120d8,d552d8b0,c42c23b,9a0f17c3,b9b32914,d7e31579,7b391ded,a7d58b16,e62523ac,b3c778f2,f913d1f6,4bdcc037,cc4a9496,ccf0cedf,32502316,b5cf7941) -,S(4758b456,217ad3be,2315583,963044a5,60ca4a49,168461c5,ecbd1e91,1fc4dc0a,99e4255a,4f30973f,57eec6a,1c30ac1b,bb74987b,3c4e7ca,9604878c,d9d83679) -,S(ab0422a6,9a207a87,97fa0c6f,978479af,a3b95dc7,d962e143,b99e7575,6e5629da,73398d0f,fc9855,ebc280c3,2b8dfced,84af0f70,4994edfa,7a06e2e3,a5823faa) -,S(1980432a,ccb90b14,30d0b4c3,5829374d,852cc7a6,f0a1b20,ee7ad43e,d545d227,96ae3873,bfbc8ceb,2afd1a0e,9b989bd0,69c919f8,f2e51546,7668da5b,9e8b05c5) -,S(4288137f,e2dffb3a,ca761cd7,2abbef3e,93b8a015,743d50cb,b716252e,e0e93f17,c02c333e,36c366a6,fbd855f1,4da07672,71fddb04,59e788de,456086dd,aa238825) -,S(d65fac35,5bc89da,afc4d16,aa73fa4,77e43276,e0db7d3d,52d9281a,d6b6cde2,e6f4c975,a6c5f337,b4500545,603862d3,8e9f07e4,18886b13,5678478,c007383f) -,S(7029b144,e62dd27a,4fe8b54e,1607936e,beb96784,d1b294c8,43e19978,b98f6ca7,8b10ed66,58056c6e,3a2c90c3,855444f0,9a1af347,c73dd14a,a478f2a6,7140a25c) -,S(4f2760eb,df969bdd,e80ea87d,a5da0c19,fa343e4e,44715711,50295b43,cf9183b2,43e2c17b,f3f9ef09,fa01fd39,b8f69b69,15d8625d,4daff425,d4629677,83e28167) -,S(cc996aad,db4196a8,f355f0d2,3b9fa539,b573ce57,f2ee7e52,14372615,c374a5fc,b1c40f87,18782935,c30a9cb6,6be85d11,44284bad,bfff9923,2c09f2dc,a8ef28d) -,S(c7818ad3,f3e3d905,b2c38e39,85eb7091,cd9b3285,3bdac631,3cf4303c,d54ade42,55574c4e,7bbb850b,14763fb0,fc1443cf,3403a5fd,d1f5f937,8007fbaf,94339eee) -,S(6cd03584,6fc48ebf,f4344d1f,3ae5d258,9a45dbc9,e779445e,52a75737,2589c4fd,afa85b7d,b165e371,adf67dda,8e4d1fa9,4d811c92,8d2d4723,a44e8cc8,93416e34) -,S(d652a205,f716b1ae,632b7235,91152314,f5231b92,474dcfd3,bfaebbad,443b2e0a,d2198421,b78240f7,cb82f0d8,5de03d8b,c4646a23,ec166dcb,a458a06e,b93bedcf) -,S(a807d04d,cd844a1d,f99b3e4f,e3400459,81ff0baf,d34e2d73,a6a052f8,dc52fb54,188a78bb,73939835,3bbe5079,ffbbc718,c385c047,97cfb151,af019e9f,a2e2cd9a) -,S(1efd2bbc,a5d6ad48,e93acd07,d6cb02b9,b8c3a95e,9f4cede2,24efdc17,cc9eb2d7,f951ef88,1b98c7e6,357e191a,1bb357f6,2a9d2ae,a8af1a05,63eef3,66745b39) -,S(5bc5e54,d27d3db5,982bcd04,497fe0e3,ea0ff13,7c3bdf66,6ed0b9ac,2395888f,3555bc02,d4f4eb01,661f8b85,7321b36a,5a22d975,2710375,4c1f65f2,82ec3300) -,S(f600a8d,26b08d0d,e6e2ea80,e8ad2f1e,158cca71,15be6f22,1f5b808f,746a3247,23be5a13,4bc3fa5b,7ef75b2,8e8e11ba,76c753dc,6516caa3,cd5b3ab1,8bca3523) -,S(fc7e4e0b,2ab2a7a8,cc5712a8,be590135,f5119bc3,6c73f81a,e492bd26,90ccaf7b,4bd612f4,1f274690,6ea862b8,a6dd8929,e4a682b5,aa835cdd,b31c90ab,381151a6) -,S(51325f3c,fe12d00b,fac67eec,d79b63e5,41641d58,76aa9700,bcd3b3b5,89442655,d6a894ad,7b7ae6e2,db962360,579657ff,982a35e5,91cc3b33,a4437a4b,133ef941) -,S(2db3ac27,1a55f608,f21bd2d5,717f003a,afee9a6d,b8fefa09,5626e4a,c598aec8,c526bf33,a0c01c60,c1cc9fc9,d66609f5,3c662168,b47cfdd6,e0de0c88,9bf9533e) -,S(9080772,93deb01b,5eb05b55,47de4321,35fbd436,3f391be5,1e1d205d,d5fa7dcc,fe961eac,17243337,653d318,b5c62159,64dfef84,d3cc3f23,e034c102,5ed7442d) -,S(32a1ad81,e5a64fc8,2dacc03f,6790cd4f,45557ad,3d3597cc,e2ec37bc,339ed9d6,87abcf68,18010022,7097b63c,a795cec6,79cb55d8,a9076cf3,d1371062,627cb07a) -,S(f7cba8fa,58689c51,a0f1af76,971d17a9,8c5849d,55b396e9,a3771d17,4d9246f9,f4b0aba9,10d5a9ca,eda4d733,35d5fba2,5309a0c2,fc83072c,ac37b9ec,af58ee45) -,S(cda6b104,2da900d9,d65b6b7b,c0579a43,fab75f55,ae7046d5,8ee8af82,6329ea81,70c86c0e,acfd7401,5a1171a0,1e3601e1,a8ee20e2,9ac7c0fc,68d6f1d,cd1771e3) -,S(a261a640,9c5b1ce,9a8f27b0,544ca0bd,a46f3bca,d11b7f2a,c23878f0,f67ee58b,1e26a71d,4c42dae9,b4e9cda8,fd33d725,85da67c3,52594d4,20c6e410,f3fff888) -,S(bc70c967,fd7f842c,c018e885,d1fb6d34,9435aa3c,682f6884,6b394ba6,e9f4db57,a2b99d3a,837e2de0,c40a0784,7865701,3032efc4,87c47e57,18d84e11,f8bd9468) -,S(364152f7,5dc43149,4cbfdba3,ffaf234a,c7a26567,1051e026,9c60389a,7077a9c2,ac3ac7d9,f4ec8543,3038ae4e,7ede71d5,3c8fa601,25bcd8ea,e084c32a,546d265) -,S(52fea4be,d57d5d58,d92f59d8,e4022df9,d82ca42f,a3d89326,cc36dd96,94f3043d,b7e98328,52f98a75,f738f9a3,7a67b39c,5708c608,5b6ab99b,2495428d,8c4feb35) -,S(34fee910,c8bac880,f973a096,a9ac3ffb,9c32ecc3,d2be3ce6,7b8d6822,863e1a4d,e0f01096,9c9dc446,c78db14b,122e260c,2231f6a0,971d08b2,24355620,689c7a17) -,S(6af28f0b,f4c9d2e8,192424ec,31f076f7,f815ab0,f476a4bb,4019b3bd,db49c65b,2c55fd2f,bb663b31,1a9aa346,917f6064,17d1e1dd,bca45d3,f1350feb,6ea45248) -,S(70b6ab66,39e4b41e,644f1b6b,6ac5d36f,a4f0ad81,3baec03b,8bc74f72,4d320e46,ec6409e6,4f4e4fcc,d19ad5f1,96d3cdd,96f7135d,dfcdec95,23780c18,8a913a14) -,S(ede56f11,4ab975ae,adbeff50,ff7dbbe3,614196a,138600bc,15508481,a065724d,9e7fae4c,11f421ed,26d839dc,61b0684b,71906b63,6efdd73c,2dadfc9,5336ecfc) -,S(83c34c3c,840a7310,3d819d74,66648e66,5de54af9,f1683efe,6857c3e4,556df8a4,9c238041,562dd6c0,eecd9771,9ce2eed2,90aa8137,f109840f,d31d70a4,c86cd10) -,S(aa2afc90,89b98,5228cf03,205e87a4,52cbdb45,24d377c6,1020593d,a0c7e200,3443196a,b382ac19,d3d3bc4f,a3161e00,6d812924,fe8a86af,2db5cc27,96be01f4) -,S(e42ec7dc,4310cc8b,9f2956a0,2fbf71fb,e90eb045,881ee800,e3a75730,4155c520,939ef2cf,a52d91cf,e20324bb,e8da54d9,2d000945,58abe7b6,93c2679c,d625336c) -,S(bc0bdd24,937c5200,fd78de47,a16ef9f4,181617ab,267fddd3,4a3c5606,32ec2b21,db04a4c,10b521f7,986e0e1d,192b0870,4a028511,205d7ac9,df6d2993,52b63035) -,S(dc88c9d8,9b43a733,5e310fbb,3f760e29,55c005d5,640df990,6264ebae,adadc8e7,2d6779e4,6f984794,65bfc677,79feb7b7,3fe37b32,cc23d636,25a3c8d4,fc2fc512) -,S(a7ae0d8a,b0c932c6,2ff0cb02,e05d76ef,5ee3dc50,88c57210,f6f9e349,80111c20,d632abc9,d63162c8,98b9dc94,b321de53,ac8dcc45,69233cdd,1d07da1,92e553a2) -,S(4620236e,e7bd6eab,db203af7,57da6e64,d631ac9b,a5f03215,592a5acc,5cbe0e97,5df4244f,69ea1e2a,6cf30cdf,4fae66a2,707851bc,7028d8c8,8fa97690,28627c6e) -,S(804cb84a,3d8bd930,51f50aca,cf932301,5cd35fff,349d8a38,e2bd991f,27d8f671,4b77b812,9ee0f835,96ab2f19,20362128,cdc39552,bbe6d267,bbc9a8e4,70ae8d3f) -,S(6ea5370f,5382b2f2,b801fcbe,ea463912,b4f6fb4d,e207237,8e71dbbd,b91c2ed2,f5b4f909,d8f3ff08,e92a002,f1959ec8,8b513ee2,d37825b1,a8bbe141,90b2d88d) -,S(d8b8de1c,4ff575a6,12bb0852,af61c6b3,1ee56403,b81a1f47,69fc7072,a2e22ba6,1e3c4190,d37abf89,896ad827,55c256e5,f23cbdcb,47b05892,8d538df4,e2468c0e) -,S(66ac1864,4a0bd6e,9c73f3ea,43a00d6c,80d38467,5080a9e,475c8291,edf1b147,2cc60c0f,7db6b776,1503efd,551e1a36,9be98ec6,73dab0bc,a61881cc,4fa1260e) -,S(47194a2c,4ed223e7,7663cf9,38b5a5ca,f2784435,c375d85b,ef3c5367,3f60e942,b0fde11b,5a64dc13,7bf2738c,75027d57,5808a3ce,abdf7604,5f4484c0,d3d9f920) -,S(1141c859,9af2d983,88274742,88dd768c,9fdc1b2a,c5f06290,10bd3cf4,2a4c6186,7a431f47,61ed4613,3317555a,578d0f8,5392a0d2,ba98ec64,d6b508d3,eef0226e) -,S(f905bdd8,e80afe9e,d65da689,bfb8e549,487002d6,16ac651d,4ba300c3,e7496f79,1ec7bf7f,3bfb5045,d461b03b,a7f05067,cd999fc5,f9f4c0fc,a7e25b19,77bfcf72) -,S(ba54b8e4,fba452ee,23c4faad,b14f0af8,232ea62f,ad47a3e5,573f1fac,f15e9e0,af556ae9,efcabbcd,bbd8e48a,82ac80f3,9c96ed0b,11370b8,da1bd4a0,60f5cda8) -,S(59d3ead0,561f6e24,30e87f3c,f361a2b4,1494a042,3a775e9,c08a28b4,a26a80a,9b26f47d,50a92229,c28a278d,427c7306,f5f1ba1c,c2d095d9,ac51e18f,a9bc8) -,S(2a6e5a3f,ab4cc928,d8f2924b,e7e0f3cf,15520a08,eff00f5b,129d9070,ac865d47,55c0350,58727023,86d19196,4609351c,919913de,e93800cb,38b77183,5ca625a5) -,S(898f50d1,c35bee41,88afe91,842cf659,fff1fb1c,5aaebd84,6828b002,a8907502,b2456e80,c97c2ad0,1ae02e49,6b84c02,fc9bd0f1,4a3c5a79,dafb8f8f,62f3267b) -,S(d1854ab8,b49bf0cb,1f9d2304,e9ee3cd3,bda5d9a3,ac04fbf9,422c4671,d6af85a,4e2500f,d8818180,5b16a077,53eddf34,d7bdeb02,17df7fab,d0afebe9,47155c20) -,S(861fb88a,394db6e1,f03cc787,d968ef7e,4a417df4,2856d303,a3edfc66,feaf4680,a5d7e95a,ab8b0b13,23fff11b,638ce02,68f3c38b,dbc018dd,dc6d2362,a135da6) -,S(9544f768,b9fa9dfc,3c155d90,b676cf7b,ea526903,39fc111c,b0ccf62d,813403d6,cec4d92f,cbde624f,851ed21,bbf5154b,28d87603,5e302902,53e99670,806e047f) -,S(f7722192,f80a66be,23cd7b07,89f3a094,311cd40d,3b7149ba,2cb5cca8,d1db68e9,41d0e9f,3243d64e,73e26661,cc851e5,1c11e320,277f7462,d40efe0f,c81b516e) -,S(876b4c65,1f88729b,dbf9927a,89ea91e5,b6bd8e7c,439f6fc1,be9e07ad,698e14ed,ece2cf81,1cfae9dd,cf787b88,f62f2537,7b573084,86ab84e1,6ad31ddc,f96b49da) -,S(706af4e4,62249924,88461427,8917899c,721be8f6,3353b127,b7ecb03c,7b70b10,c972d972,c65d200,e695bd29,813deb74,cdcf0ee0,e612f545,aa6506e9,7e58a5f3) -,S(ce97a218,c9c96262,b5cdde0b,a27e5f4a,4301b75b,f9d17dde,f1495b7d,f3863c9d,e9398e1a,20fd1426,88916410,d7af68f1,c12900b2,72b03f55,c5770aca,2a1ef10) -,S(fb625b9a,92cf831e,886a1f01,c2db3d53,7dae0feb,e9b3d9bc,a8fe6449,d53be895,7f783e74,ba569e04,a29d68f,12cbf223,1fe2a8c2,a651f44c,30d597de,82599a37) -,S(81ffbf69,7a7d2b8b,51b9098a,8833244a,f126c6f3,b42ddbc4,c6b2c5a5,55f4747d,e2c67357,982eefb7,3213d530,3cdaaa7d,90b4d1de,d0fd4d0a,8b002162,f006f33b) -,S(6dfc0f66,8c30ab7c,af16d4d6,309ca2ec,679d6b77,be695ba8,c0f31b55,6a0ed0e4,a41ed2b2,d9a0aa74,3182d7a6,20f441e9,36772438,bfddfd90,5aeff87d,b15a563c) -,S(1c6bf1d1,b953e56a,ba1a9b5b,f63c328,1d5715df,88bcc23f,e77f94c3,3b501b44,c667214d,b4ca1782,19c368b,f7c2ba4a,8f1e74df,91a22d3a,8e336089,e4e4b0ef) -,S(b69112df,5d999f60,5d863231,9144d2f3,5417b9f0,d1e78ba6,b2afd247,fadef93d,2163cf7a,302886e7,70fafeb,8acaddec,464f115c,89422020,9a034c63,558df4ae) -,S(bc038732,ac230f91,7c58b8fc,f9ef9229,9737a2cd,8e01687c,da464bde,4976b6e0,3392601,796373,603e1d6f,a7e23385,7a7ae0d9,df638ab3,7191c046,a25682d2) -,S(96df3295,1047ad4c,6aa4d9ae,e59bb00c,7489c20c,aded01ae,1833ebda,27e32d81,418f6c2d,74ce633c,181189bb,f5d0f066,cbfaa8f1,e6674466,1818c4ef,e2e2034b) -,S(a3c53227,939e40ab,ec6fcefd,eb6193c1,cb6a65fa,2f3501d2,63cd2fa7,6a304979,4468caa5,498ea6f1,92f29ade,37a2f667,f46798,dc600de8,cafa0ed6,dbc967e4) -,S(93fd8207,3dfd6d6d,6b85f1b3,1e172a61,7a0c7d46,b91d5a92,601af0ad,2545eb2b,601beac1,9a8a6a41,1bfca863,6acfebb3,9611559b,20b8a866,88397d47,d563a847) -,S(ba7d3bef,2e2c63f1,f9acef,2468ad8d,a5bc0d9e,b45e4a2b,ee87a0ba,86ca0a9b,ffff9a67,33129e31,10d33ed0,bc5b6bd9,376f29b1,7bbf2e09,7c6efcae,a55114dc) -,S(e0d955c0,2a4f9c35,97597258,2964d7a4,218898fa,97ef3011,1904290e,36157a8,176fdf9e,7d420bb9,a0782f0f,8707789,b28cbc69,d5a6797b,aa2bb985,1c617f0) -,S(16b2c140,8320cb93,112da689,c690d6ab,6cd226fd,e1752dcd,a444750,bff81ac9,2a2face3,dafd3932,f2617488,faa17b6e,5025f792,53c65edd,2abc7790,d98bb281) -,S(2fbb0432,9c823e2f,645d61d9,795a414e,220db4b8,eb4da0c7,fc22bc10,e9f502da,1adf66ef,15eaddfb,abbcda69,c87068ab,cbfe58e,69f58246,a0ab6259,90ebc31d) -,S(649134da,f42d2579,b6522f2f,404d6456,c178f883,8c9ddccc,e132de4e,67208ebf,4385abfc,3c554bc2,78844648,a9aea5a,e7709b51,fe644e8a,4a756c3b,f09355cb) -,S(b95544b1,dcb81f9c,e0601c17,29c7fdef,128d62b0,b8993023,dbcedf8b,d3991cd,f871fadc,ffbade32,d51f2d45,4f0726f,206fe760,93c0ab0f,33cc5383,769dcd2a) -,S(cd403bfc,5034d0c0,a23df5b4,a4b1b096,ace1ea17,288f89f,d063c0ca,5dd668de,c1296131,aa56f46f,49f59760,f3a4bf0e,3fa92e54,a5d8f160,54ee1fd4,26717742) -,S(a4aaf37,d7f8bdc9,90202074,c9a8f56a,1ad78479,95b4d939,4b6ea478,3c04c581,4cb3b6f2,dc02b61c,fd2594f9,40773d73,1a8cb9cb,388af431,9348d3,af16da34) -,S(57102ff8,ebdf048e,85edd3c5,2864578e,97478fc7,e6e7b937,6c37d9f8,abf438c4,c84f1d9b,eaec1962,e79e308c,251b2f31,915aef16,90ab5128,8331d8ee,f8161d4f) -,S(68fe98e9,3c5c5fe1,108c08c5,8fafc701,12424685,c6809774,832b0623,a3c9b6ac,492ac417,fd956b87,ee8078e2,c46f21e3,cb5ea58f,ee871cd4,d6480cf9,c4df273) -,S(d4bbb6,9ef5e23a,f0932cef,2eea4ab,d97baea2,b0893d43,ec08be40,2a4a5e77,5818e60,9c1dae31,f65e223d,f0cd08c5,9e74884c,2a2dc166,607fa4b0,47c7c98c) -,S(e9627957,a8eb8b72,7f0d872f,28acc53d,23a5c53f,763f3b5d,68c7e690,5a83192a,5da92e7d,dc291696,d9466d17,d4ca6cca,cab1057,4f5a08d6,6e59ba87,cd0d984f) -,S(49f21cad,a83bf2eb,7c508ffb,70f9fe84,1cd547f2,df83f207,6dd2382f,1711caf5,1c7d8129,5f834ed8,ac73afc2,132e6eff,2447611a,4fed8114,ca18925f,39f31931) -,S(58282a9,40f61d53,14d1d110,c18713d4,6c34a8cc,5b0ff64d,fd6d0182,aefa792e,7855e155,d3e0f2d6,52370145,7d83d7dd,2a96ee49,3eac091e,677f0a34,105f6ddd) -,S(c9c97a32,4b07027a,7b5db6f1,d70bec7d,dc3a14e7,43d492e5,f5569199,23ca118d,f601f40f,894ddfe1,c2b1e99f,7c2032b9,15d600d9,e2ec41e8,747d74c6,9664b56d) -,S(9e4dc175,8ed67501,86a7bcdd,a11f9273,9bbbe0cc,aa72862b,8d515a21,159e054e,ca11c31f,2bb866a6,be0736aa,19b7e36f,fcf4f4c8,715ebd3b,c9483813,cfc6c0ab) -,S(fd063789,3ae0030b,cd8c1e5e,8cdfbdda,8e5af1f6,268f552f,7a7f0c6b,8aafe2b5,8c09eb0b,68d744a,20468a8e,4326dc01,f4a35480,df1a0435,b2e21d53,dc8e676) -,S(37dfdf3b,6e7a7651,9ba81c3e,c1377580,d85360b5,b466ec77,b3f2b272,fd4af04e,cc3137b2,7b732758,d78f3b07,80129e77,43dcd85,ec941727,ea3b4f8e,d0fb7844) -,S(45ef106a,c8a5e25c,771a2f18,bd2be0c9,a69cb49,de16d8ff,e72a45d4,6c1dbae0,cad6a40d,742e7db7,3f7bd452,e0163490,60e5681b,31918bf4,2ad8b698,220ab158) -,S(258c52f9,88b9ca25,73cde71,472bf58,99648cdb,c1052d14,be02469c,11fdfca4,4491d88b,26ea5c7c,6a66c9e2,1a5b61fd,d60d0b8,8394cffc,359af9ec,29939dfd) -,S(bc92a4a7,727c4e36,3d0cddb9,d36f1d9,d4f8ff67,de881c83,afd51193,a9e65217,76ff6a08,b18b4795,61f1c024,d464e9c0,331c22b4,ba3779d7,9dd13122,63aa5120) -,S(8a19e8c2,58c04834,f11ceccb,c156bbe,23e4e837,fb5ff353,249c12d1,45f27ebd,15fc6c70,bff48ea2,c56caca,2b978fe1,8f50a9cb,85c19f06,5d65e507,e4e92c1a) -,S(e59b82d1,ab90344d,b113c1a7,a39968bf,e6f3b1a8,c2a44572,d9c911ea,55d70eea,91e33d8c,d58c6a1b,e4df0bc0,12eaa76f,6634d699,814b80,cc22afc8,313b91be) -,S(f994ee5f,88244cd6,bc417db7,2f941bea,f3456d2,5dacbeb3,330031b0,7371a7d0,9026f86a,ecc299b3,302bf9c0,4dae48f7,d9c2689f,42707d40,51440a05,ad9c62e2) -,S(776c4c8c,32d1fa50,27b17bc7,9803d121,8000cccd,565d95ff,c1e3a693,7800410f,40ece234,438e7738,6f8201d5,3d3e319,988b64a6,38413803,165f0bad,c8785149) -,S(393675a5,dd13b001,29caea3d,8bf25730,32c1968a,c5e02620,fb83fae5,b5c9b12e,39e6cfc4,793400ce,ed16ff4c,4b0ebcc3,2e5dc773,4e742dc0,3784a69f,a75a8b00) -,S(d7cdd294,22edc7b6,2cdde130,e90be1fc,94dcfdf2,7bf38eaa,2f09fa8c,c3401b1e,dcb9cb28,73cd18b,b74ca141,dc79eb46,728bdd9,8bf14302,db5c7065,354fb184) -,S(bce3f127,2726449e,3f620671,824949d1,9026137a,9885a1b9,9cb67dcf,6e56bc2c,a4240017,ee92dda4,be968f04,ad125ad,1c33c37d,c52a497d,296d5786,e6e76217) -,S(9df098cd,efe9414a,79adaf44,21e35faf,70080137,74399eb9,738dee97,ff5d6e52,6bf9235f,ef36943c,d0f17bb8,6917d97,f04bf4b4,dbef1baf,3b788eba,51abf15d) -,S(9958582e,e561dc4a,9a4839a8,292713a0,5d88ab4,72222522,e8dcc94d,b3d43f1d,e0958a14,b63af23e,86f76cba,2259b37a,850008b3,43b5cdc7,8cb4e88d,68c226a) -,S(3e7fb8ce,7d7b279e,7d292447,c88c048b,dda93379,5233a871,bad933c4,6dfb1f24,4279d08,34108239,2d77a5dd,906ba4be,e36352aa,9385f09d,2296ecad,648806e5) -,S(1cd05450,f7405a11,cec93ee,7826cf58,97611d69,fcb681c7,1ac0a6a3,75e8ed62,85bbc70,bb52b040,d620a3a0,20b9536e,5759d35c,9931936b,39a203b,af34d0f0) -,S(5047776,32145a3d,f6f87bd0,1b81032f,93cf99ca,fb4c5e3,c76adbf7,d7c9b367,7badf59,919c7771,89eb97ce,6c71f418,a0e67b23,884cbf7a,1ed60804,57d1d2c3) -,S(1ea912c9,49b64ba8,309b8d87,ad1498a4,79fd302b,f7f2f0be,636f7a0e,4470e6ea,9b279fdd,b1211de,8414896d,3502ae8d,4acd50e6,cf83ab4d,29086d0,42b7650) -,S(9b3fa0d3,4b00076b,cb4e0b00,95f03c4b,e1ed329b,d2f4c7ac,8c03028f,21a01628,10117a48,b2a58ef5,2e0d5dcb,cec661f,8cef81d5,50efdf41,26e9527c,27d420de) -,S(65fef7b8,1d39dc4,b3ac7f7f,5bad14c3,6200d128,d0257e22,ff678fc0,824c94eb,3021e1ee,680c4fc2,77373b9b,36ef276e,f2dcd6ec,7a02b2fe,3259af09,2708b475) -,S(3e77b23d,af763a55,644c0f2,bc2bef5b,6ef5e1bb,8fdedd46,c5a2917f,7f85f9ac,55b278e9,5bb07879,9c7f0766,a2db2c79,8d4fc785,10fd021b,415b3e4c,2a4f3221) -,S(2ac4dabf,2fec922b,c4615fba,1cd7d352,f69fbf8a,3232f783,96f8c08b,21de2965,2c33c017,76238bcf,2be6018,7f85a518,6d649425,1eff089f,a92f3eac,219f957f) -,S(febc8a20,67da04d0,855feac7,42b2cebb,748be0f1,97e31558,68d54285,4d62c66e,aee39287,3d45e63f,f9a9d583,e105a771,e3db346d,a262bbd1,a554a8d2,65d96083) -,S(a41174b4,a5982751,88c2d10b,d5c5401a,2654202,dc4e38d3,e1c8f689,8606a569,bc6b63b9,9fb5f85e,c6965337,e82b651d,6b589f2f,8d90f67e,3bd087e9,1f732a00) -,S(122196cf,5d10a3af,3bb97fc6,d12f749a,907c194d,3caf2ae9,3a3a464e,5a5de220,ccf46742,b3c1e213,544e2c7c,59423fdd,674697c5,d405b2b9,46fc6e92,9304e533) -,S(77bad5cb,104dcc7,e1bbfaa0,8c867761,9f93ec61,e8e3b73e,799b663c,2e1eadb3,889747b,ad8bdebf,48e1214d,df2522ed,4023fd8c,5ef08fea,411e8609,c6faa3cc) -,S(1e8d4075,8c49ad41,6ad45163,73327e6e,4e3f6c89,695e15d2,f5517ebb,12d4a98b,1d16ccb0,730a619,c9b379a2,ecbc4f83,98d94aa0,d4881cd1,25968160,e3b09f4) -,S(c87a656b,240241dd,487f4974,afb5b535,880ff2ac,f4a028cf,b1869fa5,fbb6ee42,16f25f3a,6fac9538,5ed74412,fa6a790d,34f694a8,b4c99cb7,6ddaff70,be757beb) -,S(96b01407,482c6e88,e9769944,cce16a05,669adf16,e7393b80,71fbd9c2,4b55a4eb,b32be280,590384f0,e08d68de,38688018,82b786e2,1b178ca4,578bfffb,94b50223) -,S(120f68b3,739562e6,81e72fb7,46d08f54,b2afd162,22e1deff,7ebbf884,6dae4af5,7c1eb74f,2b2376f9,477c6729,bd90e14d,2f4da9d,615c8743,dedc1690,300bcc78) -,S(e64871ec,2789b455,8608be2c,f248fee8,49a4411d,285c0989,b65c5dc4,e6acd157,2980b2d1,4999b0b5,5b79ecfd,45ef91fe,f3dbfae5,d02f2145,84376294,58e10a6b) -,S(608b1009,b20d3e2c,25324adf,c73e5c86,43daa1e2,53a8d266,eb43863,aa6798ad,826e5a03,ad5c9638,51181c68,ccf0e663,a021e13c,43efc38b,3b4fe2c8,8d0e13df) -,S(8c978155,8132e45f,60a61435,36f4c1a8,cdc4dc2b,6850b3e5,7c65f841,a1bb152a,ca3b3098,394d81ef,a9083c5,3864f194,1875d63d,9c31b44b,a6ed4137,db7460fc) -,S(353591a,c73b2482,f8d8e731,ce01106f,10072757,68210627,f80c8f8d,9821bf3e,2b7e3d1a,501ab469,ac6306db,2608eab,70ae8981,9f44bdf9,d4f84c7b,41eb6412) -,S(eb2dfd88,ec357372,ece70a67,178fce32,3c387b7d,a9fda978,b05dc430,9cd78857,6f2bb6ed,1f5a5521,c441a8cf,9852372e,3dd7aa7f,ca0a1f63,18c47ef1,a24b88e4) -,S(a41c0ff6,5db1050e,6998f3b0,7eef66dc,abd72ae9,8672c487,b29ff732,992eb279,56fa7b20,5616ff9d,f619d7f8,65210727,bc0786eb,2aacc244,ba951eee,99a99cd4) -,S(8e748b35,f5bb1500,ca45917e,859df11,615d85ad,861bcea9,41524e57,a2217e92,55413362,e226c6a7,84bf8604,3973bc50,825515a3,96cfe66c,9ef75e3e,fca46df8) -,S(a83f6007,cce70624,73cde2c7,b7ec7bfe,bc506c27,ccce7708,f35d535c,26dd17e5,ad48ed2d,af217e5c,63397a37,9d50d615,5a1ac614,887a2cbb,26c3b74c,626af268) -,S(f9ed7a92,7e451624,9380246e,bfd397de,5cf208dd,b47573ab,f118afed,1282d2fa,c1574616,3a6f30f7,80d5d53c,670d380f,3c84407,b4be5324,87bbb5d,c8237b70) -,S(a2bde78a,175ec7a6,7f917707,8f09f812,c7dff012,46c5255a,f0112672,6c2ea08e,7125698f,e82d4c0b,6d7d2741,9dc503f9,3b5dd62a,a5db9e20,b091323d,c9ca12ec) -,S(ca8c05c7,9dcb6736,905cc0e9,b8e1690b,6b37da42,e1875a56,e62ea231,bf9899b2,504c51ca,1e19adba,66560c1e,3fba9caa,2751259d,71389996,41d0f19f,1487534c) -,S(fc106ee,61db13ac,4137ecdd,15018278,61fd4b21,c979f97c,617b019,54eca02b,6da55a28,4fc26638,2afce9c2,cdc5a2c2,971f2cd7,5c92f08e,6bc99651,7bbef3ee) -,S(2cb21839,f47b1068,5419a321,7ac7846f,504f674b,c2f8f90b,8b9b6a71,6492a8ab,1feb332,ae75044a,f6807feb,965e2fc8,63726433,45a97af,f1081249,f00a5757) -,S(678c50ee,759c07ff,fca2963e,fba55edb,56ba3572,79970224,5d4f2132,5561f3ae,1989b787,abbf04c1,c93afce2,d389e1f9,780b1657,daa77107,c498bff4,aecba96c) -,S(ab63e1ce,aa2e34d9,8215097c,30b2f266,75d407ca,41f3dda4,1b21c910,824aa6fc,ec65be61,1150ff72,715d3da2,c4541ad6,812eb7e5,7d0f4d82,4792556a,6ce2363c) -,S(a69399ca,fad59597,5a639a2a,31264983,ec567279,b052bcc9,f5c919ae,903dd336,b525c659,c30c4f4d,a7a799dc,c93ae348,1c87304b,63491755,1c43e12e,c50d97dd) -,S(32bf4282,507bcf5e,d25cb5ed,439c82d0,bd7a48af,d3be41fb,e13753bd,c0fc5f3e,cd92017a,4336d9fd,25682f90,be347e82,6773c598,1e80033a,c20bb695,e79bff2) -,S(a1fcc983,7e720096,7203e2cc,11450716,f2fe6484,f681b2ec,5e42e9b8,eedfd862,1e16b6c3,17e8fb89,dfffa79a,722de49e,a419affd,bc17fa96,4ba6c316,31ed4fd7) -,S(d85a314e,69617e50,18df1e82,21cf738b,60485cf3,3abe8838,472b32b9,7f0ceae0,71a0ffee,e92dde66,66b4b5da,a88a79b4,fbbcbacf,3308a4e8,6e1aa367,e00a52f1) -,S(189226fa,688c70e,415b20e3,1356eac2,f5a53b5e,8043e24e,4ee03faa,f20c2e7f,d9bfd8ac,40c7d53e,7bcbe575,9987cf62,fc2bba7f,952e4eaa,1a0587de,f1515aa6) -,S(d3542e0a,6a931162,d7a674e6,32cf2135,32465d25,4d2d9241,ff70709a,559e1330,25e8f51,e2664234,34cbe5ed,622bbd83,dbd42784,4b1f2bf,9a079917,4b57c369) -,S(514d9e86,fb2cb612,1ec6e6b8,25875856,9a8c0a5a,adbfe45f,2876be18,753a2bc5,700785c0,be5423c4,341918d9,f65f79d9,1b8370bc,48629791,45ca8418,57cbf261) -,S(c9f86365,12e9ccfd,e1f1db33,5ae606ab,43f9aa62,2d723f6a,d6d684a3,ea3fe495,30d3a631,3868a01c,9c6f9445,ddcbe3b9,b7b80b58,f31f5db3,a3b3beb2,1e30270b) -,S(226f20c,8fc089fe,98cd96f,a0e790db,641200a7,2b908768,357d206f,2c2deb93,2e23fbb8,b43e9362,3fc2045,24b43da9,5e02626f,ee180cff,1c03b95a,aa5f66bc) -,S(a1b27668,d4b6f94c,7219bd9e,6b8a7e61,9fcc79fd,88d9bda0,a38496b6,cb5350bd,3933fc5e,b6e1c16a,e7aa62bc,200fd5ed,c96b5f74,b72b9b94,2644f32d,d6d68a32) -,S(10f13657,87bc31,1f7b7181,808eb0b,57dd4e7c,1590dae3,8c40df7e,afe28887,1a52e487,9bdc3ec,4e6c570d,91d4edce,291338b4,a79a3995,db5c6e85,e3366d84) -,S(8aaa0ee,a984f583,f9f55861,500dc5ec,f613b3d8,8f989884,273e1841,cdbe3e46,52962154,f85277d,c02c46ab,c2f246ed,24e56458,156d97b8,f2197d22,a133260d) -,S(32805a71,24b1b7,9b397ce5,f7a93a98,dc9472ef,a5b8b4aa,3bd66643,f1c89d2e,af525c7c,b7c139f5,cd2d0a85,82a74ed6,9e23c765,c0b882a2,f4d50e58,843091fd) -,S(c72f10cc,909ad449,7fb0835a,4f3a520d,58db0c2,87f6ab12,cde50749,a9412451,a5666e7d,5197ba9e,37d5ff15,b64b60f3,b8e2ca32,67467030,a7a112d6,f2c7c65a) -,S(6ec768c7,870211b2,415a74ad,c203bd41,72c0fa5a,d4c05f97,c0320865,77fc9a22,18394a22,aa2dbb0,925e6710,549c8c3,b51cbf42,db67d4d0,5da260ce,af1b09fb) -,S(de36ebbb,ff99d156,60506143,87045fc9,a846e7d0,eef91e61,dc93a71c,3ca64737,c5817652,f3cb37b,40647dcd,a476c4e0,488208ba,1b4d0c81,b39a4b4e,900f4270) -,S(f534155d,5538fc68,5ac01ef8,6dea6f4c,19bea322,b46a297b,c0c20ab7,3cc00218,4fab7df2,979d98ca,eeeb38a4,9a2d1253,f9d0924f,14dda603,d3d5706,b3b9523c) -,S(dafdb850,a1db9025,80ecb98,155b687c,8db2088,d0dab521,bc7fcc1,3286129d,43965ffc,ae6c4c14,3febe601,f36fbbd2,7d0ccc50,60ffe91a,a2ef2fef,651ada22) -,S(ac9a0a21,1dcabc85,1816893e,e33cc69e,2efe4069,680b3721,2999f9f4,99d705ce,16ebfe40,8281d2bd,ffa1e02c,2d00d712,acf64eb1,39f5ba88,79c3971b,98c728ef) -,S(afb37bd4,b48cf6e9,5e1eb8b9,7b8b69fd,31ae2b2f,3b7aceb,1db81ebe,98503030,1ccf4164,f8d9cdd9,6f231af3,e5fa313d,c47c06de,ce44dd84,d3fcdb16,a4b7929) -,S(1b902ef,6c294f83,3ab18e7f,21d6470c,f553682d,2b1287d5,1a602925,3888e709,7735c5ff,34e49fe7,2385e9fe,40d66a4c,66ca0102,46c724aa,24b1ecee,dcd69ebe) -,S(6e4e5b10,8a202958,7c5b4ec3,d33220fc,c61b41c5,8c3bf0b2,55e4e28b,7c3133e2,b49f8306,5c336af4,469ea410,648915a4,b55ae504,6cea2f66,f14a99d,9a8fcfbe) -,S(87ce3f7f,bb800210,5b853276,d3931b9,12342d98,7d81e80b,5b10d1ab,1b7e9714,56c6a847,79dbf39c,293c386,9c1e3385,6b71f898,dd46ee16,d1e1973a,4cf0f635) -,S(8724329b,b7ba649c,9c019372,45a1e946,d368a706,2747dd0c,9f6667aa,c9426b2d,44458e8,48d7d44b,5dba5a5b,b0fa0479,55b109d5,21d170d8,9d090ff9,650b944c) -,S(b91befa6,4735c091,32db18b6,b64d7d7f,c6338dcc,cec845cd,7d297f62,b6a1a4bc,bb3961ef,8c9b79c6,867f16cf,be4766a0,15e7ca0c,8f9f340b,14cf701d,e0138467) -,S(4321ea59,332e97ea,3bcfbb89,68a3489c,9ae3d6b8,65cd696c,d8de3200,a0d08fb3,97e480d4,c5149d53,d7582e3f,c73a35ea,3f6b023,5ce50f7e,e31cb600,84cd538e) -,S(dc4597b2,836d96a6,431051d2,5a98d421,7950a8d5,e88c2069,5752ca6,f6f1bc6d,c712580d,16ba30ca,e84e3a83,c35725ab,362bb4fd,e4c42ad7,f9b73f20,53df36ff) -,S(ce644ef0,85ff3009,b261750,8de007bb,c5f19b65,2d9f8992,9972d39c,159a009,9a41d0,58db965,baa00c92,f6409ab0,c9402a69,20a66c17,c089906c,d73cc8f7) -,S(ba1e35c,b6c7b4ba,b81aecf4,23cb8ef2,2ec439c2,584682b4,a7444e01,9936b41a,f3b3c652,f91dde46,3e178d6f,7b17a8e4,1098b33,1cead28a,d2fce694,35bd6272) -,S(b9f98ea0,2a331bbf,60fc839f,845d8f43,6988c747,1902d14d,72ed1360,86e3920f,9fb2501,a7f23a16,cc726f5e,8aa17c12,35d9b04f,a94bb27d,318fb292,c60d03d3) -,S(70591746,55f90f81,c478e702,ffcff930,dc10dbf1,16d7aed0,9c1a369e,807e886f,8267a0a4,b9d6f0ca,db1ec92,560aa3f7,d09d3f41,d1f36f8c,64b95509,b205a59f) -,S(efda78bc,c43ca063,a7b6469f,84012161,14cc5a6e,4e31c31e,b76221ac,c25434bf,7b436ff6,ef45f859,f521b13,53193d13,4cdf8064,449af2aa,92be3781,56fa2864) -,S(229a4b0f,5d62095e,3a630988,c8056aeb,35fbd874,1a2f0e,4306d094,750ccc34,170d33af,491c74e3,d2d694ce,f6a519bc,741acf35,dc6a3428,8bea3595,e234de6e) -,S(c770f48e,20a02132,189d44b8,3acd0f93,f91860b4,81a6bf17,8ce8e2ec,6af07100,7e1120d3,8b2a191f,9ed43aca,3325beae,a6d8dbbf,7e0bf8c9,610f8621,c0266eec) -,S(a5db2c63,3901d52,8b60a48a,20b189a9,e89b8998,3d424af8,eb74869a,f286aa44,b9961d92,6a93d5b0,1a74e6ab,d9c37eed,384e186,8051ba14,46fe1a37,24af1e50) -,S(3ec7169e,9f330288,a63897b7,c168db9a,4b447e48,cea2c5ff,77b298,da41db1c,c3fe974d,e8e60eda,22c4aa34,ed34a4d6,4b3be268,12e58b49,e4477835,f3053fb2) -,S(b733de17,c3311184,d5860d4c,f99e48eb,810cff93,ce92eb77,7cf2c114,fb5bf3b3,c75c0dd,72d20ad3,2000d537,ebb61571,57fc4ace,9f26a90a,d28e1a43,480c11b0) -,S(57d6e208,d555bc24,15d49616,a158075c,27db59e,6a821df2,8b450161,6c2ed278,83870a79,d130da5a,3528e353,353b34f6,74b5d02e,6cf2a891,fca34c6c,3746eba8) -,S(9e4234f1,aa69a478,3bf2fd3c,3208f6f2,6f069409,fdb2faab,8d792588,6ad3673d,5f9a4773,7725ebc3,e8bed041,47a05841,9fb42b16,affec29b,d753733e,288d0653) -,S(6fe3ff9d,9fc12ffd,bd896202,fd8ae913,22e4fcf2,76068a75,8d43f1f3,9ab68173,ef0d5682,1d414608,273ef7b5,9208c59,bf94e16,3e7faa3c,2ab3da22,b509fa1b) -,S(2c31e54f,d2586e19,efaaf415,e54cb499,54c49257,d11b161f,ff2aae5b,b45c4631,bedfb0ad,364ab1ac,e7f53c0e,9fb825e4,39af354,1a70708b,d8e0e423,13311346) -,S(51597259,23148c3,478ea2ee,2b933858,4d745b89,49c2f782,3b8660e7,78203ebc,329f6153,f688b743,c4fdc470,25790503,b81ff7ce,5a613362,8a59f3bf,66aa1817) -,S(188b3324,58f7d7b8,dc3fcb3b,df51ccfa,d394684,cde37d60,70d41e46,cdcaf1f4,4dea5da,d112a117,31a6b04c,8999c6a8,3d1ddec2,88aaf104,487656a4,d3901910) -,S(92058e41,a503e158,8ceb0a49,4e13e2a8,85f804cf,7f13c90e,307372d5,cfa6e471,368072d4,449e685e,17e5a230,e2177e95,bcbe177a,58cd1510,68e7255d,84ec108a) -,S(6a6f5226,44e06506,f27a7a68,96eac537,726f79e8,9e83105d,5b647883,34099fcf,cf3edd4b,d8ced83e,b167b664,574987f4,7104e79a,5a4b5321,4c19a32d,a5132586) -,S(7e37cea2,340cdcc3,ca21e0ef,ad548f37,c77c3402,34f0148d,89cf926f,2376bb26,c72d829b,42a27c6a,b062938e,5cbc22a,6b02d42b,d31cb69e,83b9fe9a,cc9a0016) -,S(1e6c2069,cf0f6cf7,bafb4b39,bc97a8dc,800d010c,52c3cc5a,d848fb82,d8d0b667,c181e76,bca1d846,86ecfbdc,2cb09140,49146986,630b7e81,f86c7238,8e60196f) -,S(5566600f,e6eea4f7,b06336c8,d44b47ea,f36ba43c,ca404be3,5203ef5b,6f07e16,6bbbd08f,7adc1979,ed4acb4c,f372eda,69e5ac16,7695a78b,5a7fe1ce,1057e55) -,S(435c634d,ed451c5c,21c5adc,45d94f8c,69045016,d529ba76,19ad07d9,31c791b5,31ede268,8252a50f,2206f959,1953c0ca,85009876,2b6f6c14,24b4e47,c74d4cc1) -,S(6fb8cce6,a66071c7,395c0612,252a414d,f19a0d2a,f855e7e9,dd142342,9c57b9b6,17f94249,e2f05314,d4799fad,68232626,183dadee,abfe34c5,b845d89f,2768e052) -,S(866f3e99,20fc4c94,9496a695,f54ee634,11c711a2,99e05890,148de8c3,2980dc36,e99c55af,4f8dc3c1,d38a11e1,3c00db2d,f5211f02,e837909b,ae188786,d18d62f7) -,S(80c13410,b7164899,a724f723,4dcbe505,62404f0b,7c027c79,4616f618,80468b2d,8631942e,71a01e4f,d7b59281,9dc69d39,bd6e8fe1,c2c41621,6d8df895,280b91aa) -,S(8f85bdee,ef4e9d88,53e68be,c17bb6ec,bf37abc0,a4ba44d2,c3815dc1,82a7da99,36d45bdf,8ae9342c,af0f8ce7,8aa591a3,4e8c295e,49ee6962,b4a9fb7e,ee17897e) -,S(9cd0b2b,3393cda6,ccedaf4,ee8a1b3,17a920e4,826da2aa,4404a01a,49600749,3831d35a,51d9650b,b1901e34,8f0c4ea2,3a00c492,a4960463,414e5dee,aafc5a5a) -,S(a0c5f1af,15c67ffd,6cf832f7,974c779a,3ab7ca,dffa32d3,bdbe0377,d49f33b0,6aff40d4,42de6262,41734412,3620c5ff,3079392b,b8843c57,80029682,1cb91ec) -,S(af396f40,13e217,d7e1fbf0,2ec4039e,c0111370,37cb2d78,90a82313,58edfacc,aaaeb9e2,5a57534a,2dc35d16,705f0e5d,6754c599,e85864bc,936e94f5,9acfb936) -,S(fdac3c57,e3e0ecc5,e7e871b0,dbe35979,87d4c071,f2f89307,cf1e71c4,91ed0eaf,3028a0cc,a22ef096,73c877af,ccfe36d6,b14d14ff,5da10b18,cdee6068,3ca09fc7) -,S(e3aeb123,9587baa9,ae12b6a9,68efaedc,ae745fd6,aac5103e,14a471d9,eefa88b7,7ed1c786,52c1544b,e306833f,bb27d1a5,7b460305,a2c8f6cd,2d33397b,caf769c7) -,S(96baede3,382a0162,fb4cc663,c91acb94,eb83d7a,3e3e0a0e,6055a50c,d78352f5,78722e97,b3ad2824,388c3a80,fb930089,5100d61,ea58f997,2adae059,f0c50cbc) -,S(68704956,16975637,f35e1eda,4db546fe,ba93d122,446a3e40,8de04ee2,3bf5f5b5,6247d2fe,b5f7471f,3a06c7a2,4c4261a,934bd226,772405ff,46e361bc,614ca494) -,S(71ccc634,2ca1f858,8ae02d72,eb0dd2b3,62eaf652,f83edad7,94095e09,f4bcf749,487aebd9,23b10e69,4a8e3f22,2703e5a1,aee17794,42a96c68,6cb9f983,dd2a45fb) -,S(6fda1dd0,65739a2e,58cd183,1e8b6109,713844ba,f249cdff,25d0b3ec,f635d3f0,a2ee44f4,8afccb72,4f8a96c3,2a88a8b0,a232a93d,553713df,60a965f5,2078108e) -,S(d3f27709,ff5ad97b,45e395c1,39947115,65cbfcf5,838e7b64,b1016cc6,d5147f45,f96cac16,cdc8e1c3,54e026ed,29bbd6c7,29006ee1,51d9d61a,4391567,93265077) -,S(27ba1944,a28a6eff,78a7d064,bb8292c6,68f82793,8e2be786,41ee366e,a4a011d6,24bef875,9d216430,e7312fc9,458f0571,fcbe305d,574694d0,a77f7a98,4e7bdcab) -,S(fd37b812,5fd87ce0,82fca9ff,7872e0e9,772f4c44,1870748e,e35e7d00,944fe190,9450a525,d9ae198d,db9b8c43,fb337df2,8ec68a44,60106951,1847b9a0,27dcb453) -,S(d9967cca,92583e0d,8d329b63,f32a8017,4467518a,595d8b80,2c24cc8a,8e071c69,6aca3673,c2c39d69,3bc86dbb,92e5af27,28361cd3,2179eab9,7ed64ae9,73376c25) -,S(8ee82d3c,4a8d01eb,d22798ef,bfd95c16,f53cd45f,e3d044f,3d89ed40,b94a0a3c,e0b0ab7e,9167fb9d,aa71c3a,fd5b9c0b,79c8b6a0,db3ae2f0,36c626c7,791e1b2d) -,S(461ec3d2,817cb549,a9fea029,15029707,8d709ccd,bf22da47,64c8a1db,c562caa,661b2d7d,cb5c9790,510f6e12,61650401,26cdf80d,b086259a,db16af47,af6684af) -,S(3155885c,935caed,469bb7ff,b53ff6b8,59f51780,f3de5890,673101bd,41f5793e,603594e9,92ac108f,8d0bbdfe,8f3576e,8ca6ac2,69c7581e,28d434ce,2043dfff) -,S(5cac93b0,ad9199c1,906267a0,ad8874e4,c68a60a2,b9fb6f0d,cad42758,2a4ea9eb,836faa98,a116dab9,69961fe7,ad7483eb,c48e7295,37e6634a,e423b99,880032ab) -,S(1fb6d3ac,afd5ef56,8b6eea1c,4a8f0179,54d05274,24487904,7e3ec56c,6956cc42,b8ef91f2,f89e4f32,6df6a1ec,50c6362,7431be48,1183c839,3133dafd,2e2a5411) -,S(89c0b1e1,52f0005d,a30618f0,3fdee7b3,69fe0157,f7bb2bdc,d31fc773,d82b28f2,61d6e357,bbf46816,acd05de5,b26c67b5,ad8223d8,ac9f47a9,25477ab1,80b4a507) -,S(7c5d18b,1f9d1afc,d663875a,34193240,7cb968be,f31d751,807ab1b,b79a211e,45fbe7ea,985bda0f,bd23b449,5d4e945f,d136b5b1,296c9b3b,6dcb9c37,bc779ff3) -,S(c827cfc1,9393108c,9b31ad4d,b5eb7f00,b6afdad3,a5e2f792,ddf9dd13,f159f85c,5c5fe07a,3025d401,54fe12fc,89951e2c,330ea3d,d6335a12,9c31aaa6,753a1cb1) -,S(6347b32b,b1f3f7dc,205e2fa4,6b201b4,2e0dfa80,550741e6,57117875,57cc5d9b,f8f30e10,9508d34c,a48d7255,3f8ac26d,a455d3f3,b170ee52,e22be1a3,ae8c3ba4) -,S(d489f595,e822101d,5f6e4283,7db032ae,bfa21f3a,94998130,e0a1d226,67ae1014,8b112e89,8dc4a146,8f64c33d,1261f8c9,2bfa98df,eb9500c2,2b4a66d9,227c66a9) -,S(90cb9c63,fb4afbce,adeb8f98,1e76a645,2200d73,d43bc0b2,76f058dc,b8a6205b,894afdc0,f6ba7f1a,bbaf19c6,720471d8,2611a77b,5bf6c87b,a02324ce,52e74645) -,S(40df68bb,19f121f4,e566a1be,f0a98954,869bb06c,699e818b,bc49a795,6a196af4,70d41c09,d0cedf7c,31c9f830,3610f6b6,e1d6b3d2,a431e69d,a31bdd63,220cec90) -,S(4936fd74,a0ac5045,91c962b6,431f17fc,a888dd1e,b35549d7,8b41143a,83da41bf,33a8e1dd,6517853e,d7c68af8,5b3f1cf5,3fc5b72b,5dd0f392,c5ab5ff2,1bff4f92) -,S(17177538,811075b8,f5baad59,2958074b,c1a0c6e7,b2a3f594,288e82b0,da023557,583d4814,efd8742c,5e7a0c5f,734da121,b163fe28,239a8775,4bbb072,c1b10837) -,S(a126b7fb,ad5145ea,b414c82d,8f21f208,6abb118f,3692bab,586770cf,4f8926a2,79b4ac17,b601b4d2,1a2bfdb7,41f7fec2,88d46594,699e4394,452cb2d1,ae2ec669) -,S(51eccf61,f8840048,d55de51,2d865a52,3485db8d,869844fd,ba30e703,ae871163,594ad253,97bdc9f0,82c0c46a,200ea090,12b2c6a9,57a53dce,e87caed3,2ea8d50f) -,S(97781633,6f1b7131,f55966cc,a79d25af,d8984438,8b516882,5105ba3b,52b3c7a9,f1df3541,b4b08fe0,cdda20e0,a5275eb6,105011ee,f4355516,e47e89d9,3b214c60) -,S(8bc2c43a,72248dab,5c78cf6d,b1a35ce8,64231d3a,870bbf01,cdb79be0,2c93f7fe,d52e2e76,173e9dbf,9e8106a,ffbb9d7b,b428f07,80269b2e,f49bbe0e,14cbb425) -,S(59ed7881,6c7ca119,ca4abd03,34b90b37,6c327175,e899e0d9,79953e50,5aef9f2,239fc027,690c0feb,e4db46a2,8669e0da,20779425,34bc6133,152a606a,16449910) -,S(bec399d1,76714995,d4192390,72a39c59,c8ff8e9a,2cab6520,ca0cf6b,2fc70fda,ffc4bdef,7831208d,23a1ab9a,de52f346,a21a2f7c,efc5ffbf,70999bfd,ad0ba8e7) -,S(93bd25ee,f4cef1db,fa5f9951,7d22a77d,9e3b87db,58c63076,68a35885,9e0c4d34,dd7d1412,97361b84,9a43b1f9,4f89970d,fa008c63,3404860,794e6a87,6735b4dc) -,S(b203a657,fb4e4d51,158b2e70,87455a57,44e553c5,bdea4f8e,3e8e6c92,eddcf58,98246948,c63e182,61f0d4c7,543fba7b,c74ae5a7,a19afa6a,ac80359,5ed8c99c) -,S(af38b53c,1dcd27b5,8118a28d,11da8aaa,3e20ac21,4cff64e7,be683dd,80f6aa69,91e38936,ba8b2b42,34686723,7a3fac67,5ec10179,18f8ac16,acdc32f9,c09fd919) -,S(55e4da5b,b99d805,e2058756,20ab4cee,988ed472,f5e6d86,2f8c574f,6bfd8518,7368be34,75179d32,e15b5976,c34c366e,e7713b25,8f179309,40b16117,aceb2d35) -,S(d3d7e82a,a7ebe240,83e1a15e,1d817d91,a3608c6d,d25a35d9,183a0c9,e42133f5,a5245cc,e89537c6,895080b0,6c5e2772,4b1c6d69,6c1bfbfc,ae6a7d4f,fc5d504b) -,S(8bd14f9f,e6b54437,9761e803,1dcc9907,beab754b,68c6c3f2,2316e5a6,6ee48799,f89dc150,a3876257,51663a26,35633868,ecb2eb27,d9ae8603,89110aff,6978fe19) -,S(b1d72365,3f50f42,cfeb0858,972a5a22,3a7dbc5b,4823704,85c88fd2,22212932,40597dd8,594ee1f9,b74aa52d,385b21dd,6279864e,7d0255,70bf3716,c02143ac) -,S(44d303e1,cb7d920c,93be4763,e045cef5,c22d4403,5e1d3a8,593f4f72,679d3023,79fbdefc,5ed6da2f,31bd6fcc,83e3cee3,e77e41a9,a01b2004,76912c61,5d89a70c) -,S(1655ec54,447aaae9,727bd4b9,60eb996,92558999,83d4aed,3dfeba12,3b0cb3ca,8e90e578,cf96e31e,988f7bf8,a9f06d94,6ea28fa6,b1dad744,3b9ece50,6626fcdf) -,S(b02ae3fb,530566bf,66da9326,18990e6e,7902b104,800cacb1,9717bb7d,845a3f29,c6d32713,f4483031,19bb7631,1b397427,d8c05232,92a61051,62a0307d,7b006876) -,S(13c46566,53a0042b,8755e140,2b12b9ad,8e123699,a153ec6e,65e49cd,10c5bcd3,70f3672c,498f603e,3c521ea4,3ac3e10,7bab13a8,a78b02b0,4492c51,6d41c88) -,S(e7c7562b,3fc37b8,2e9c7bff,c5e97b39,dee483f,141df4c6,361eda3c,4f1483f,734be460,3d2b4958,c1bdce51,57a16d0e,1a937298,1dbb2833,1b12f8e6,c3454066) -,S(de025d2d,fb6cfc75,342b2ed1,ebc7b27f,332f3921,c304b8d2,263d7fba,2959aefc,46c609b1,6ab6f3d0,2dafc30c,38373a30,1a88c31d,80694598,5e676f1c,16de12f1) -,S(21e788b4,fed21c3d,25ddb714,abaf053a,25730af4,83817e4b,6a42c323,3eca2e01,1fe716bd,a7d07592,b66af9b8,32335b9d,b249b1f9,cd413c58,ddd29fda,e5c1c4c6) -,S(a7db27ca,7481d50b,1a458242,c75b28e6,d1bc1a9d,da97e012,e39cff10,7b79edce,c4f8686d,cabde6c1,d3455fc1,795a7cc4,84239d2,3b11e238,85136183,71ae73f8) -,S(c5205173,2790f240,e2161627,5ac894cd,e80a7d3e,bd5bdccf,41af64b6,5e2d477a,e9aa295b,209410a0,f0e8e216,deadc3f8,af87700a,40543cda,463beac9,f62ba20b) -,S(487bf4ad,99d1daeb,f1c25f86,d36ebcd9,38e91eea,8b855d05,ea9371c4,9572846d,81293837,ac6ded0b,ee04b2a5,4c18ae0,32f72970,86de0ffe,791a9576,fcfebf70) -,S(bd6dd2a6,bfcf688b,84fe2d55,e56025d,35567574,20edfcb1,3cd14483,e08cb53,c86a45e1,84c83806,38ea1501,c2851598,c467d2c,d1c51a1a,1b037324,d9ab0fca) -,S(94a417fd,fbf188e4,1334fbb6,906731e8,70dbca18,672bece7,936a4c7c,235ec737,e03c6607,343ec14b,81eaf124,bcfb7d97,564e9f93,546f9765,299a443,d9be8e34) -,S(2a57dac3,3fa13b26,a96d9b73,317a23c0,2ac597d3,3968fa8,ebd88d94,66aba51e,1754a6bf,1db7b3b8,b0a7996e,545f34fd,3b05bfd9,805b50c4,42db2937,e8c13b61) -,S(ba2e4a71,6142a39,67c613e9,93083c32,d1c66da1,2c3f9742,eae90b7f,ec7e7df7,c262f8c1,a704e83b,ed7fc60c,5adec65e,ccc6de35,8247cc97,1da7acfe,834cb07e) -,S(4ae19743,b3132512,d28a12b1,1fbbd824,8bb0b9a,730d5a8,a862ea8,ecc01ca9,67b7267d,48fa3ea1,d1c1ec7c,a6a8ba0,cb27883c,3f9d4193,20b4c8f7,a017eece) -,S(4cfb26c,81823667,f18e6ff9,d77493f0,778b9bf,411b63ad,61850ea7,7706ddcb,10df8a3e,3a8c93df,4d7af16,407c3211,aa6c6079,c397a0c7,78e1e277,24e4028e) -,S(9f9e4566,a014b66f,fbc3ef,b3c05062,15f06102,6f7d6561,934d3db9,5d130349,492b8ba2,76d526bb,98fd0c17,c5a0aa7a,ab6e5c9c,ccfc95fb,a417d25,9396c592) -,S(e36c0513,3641b560,b0f9f4c1,1159e2f,ecf2a194,b55f3bd2,22ecf1f6,ac239301,c7fd74ba,48e7fc40,6322aea8,e9f83a82,20e9a113,ac2b0c7f,aa05a5bd,bb43736c) -,S(91b013b3,b94d4568,78737580,bf1da11a,a0bbe0a4,e3ec65e0,33e9f824,d8480bbf,15e3707e,c13a2529,22a6f824,7e33d172,948790ac,3d367f00,6472f22b,e8cfc5b4) -,S(254d1788,8c676d52,236782de,2d539f2c,41f667a,d75d0107,7d43f723,ea324f56,f7042d2e,93511e5d,13f4aa03,bb2dbf27,9bec3df,97974275,5fd25133,c814094a) -,S(452d6b7e,ce7d0f71,2afabe44,2a22f16e,34fce662,99697f0b,6135678,56f4079a,21ea8ba1,28cffe76,3400d69f,ce13204a,9a39ee59,14132d23,db3315a4,7f776998) -,S(1580b9d0,7888f41,81b86b85,5b1982d2,81783185,5f28c163,1f151479,cc4c508b,4d9d1e9c,78b3d9dd,73bcbbe8,778c1b7f,65b69faa,f6576dc3,ecdd00f5,c1d689ff) -,S(79dda23f,c31694c9,16d1470c,2cf25a02,45a5aa7e,d084af45,c43960a,a2fc2700,7c7bc169,a58b8d8c,c4b74e0f,377031ce,d7158c21,a156fc03,c34f25a3,a95bc978) -,S(866da7a9,bf80cdc2,13e500af,b5f4aa0e,419b4905,44653b5,fe2daee1,4149dbe6,626d38b3,b45d57aa,6867e8ad,c8abc49a,81a282c,6bc6524b,239819ab,766bd3d7) -,S(432bc912,bed271e9,321624cf,c6062b96,cdb502ca,f990522e,1024b80b,9411d374,e645449e,dd7c4d41,41e0cc5a,cc5d45df,4cb341c2,baebb605,bcdce6a3,e411cf01) -,S(ac3d3b28,83ec385a,15297086,525d937b,717f5ad,83a5be4,77b3ec9f,6410518e,d126eefc,c9ed7e75,c10d01b2,c0e790e7,3dde58f9,54185a12,5fcc7268,84b9b8db) -,S(4570834b,2a82385d,6db696d9,56ae2667,fa18b262,960d064a,5c13da43,abd6aa37,1e9d6083,b249bf88,7ba2eb59,a9597e7,d9d15c64,ad6404e1,21a486b0,61236f28) -,S(88e9a6a0,ffaae05b,7c29bf79,2163c0aa,b224b051,36aeffd3,341355d4,b983ef15,ed382a2d,fa2f63ea,dc4ef5e2,579abafc,fe457475,d1ae8413,99969324,718d1e5a) -,S(16810eb4,de3327c6,a505663d,cad7f618,b397033b,d6c9748c,4fd8748,2adff706,352ebd8,91326c9d,2159e84c,40dc29ae,30693b7e,5a9ed119,1fbc2cf,ee60c81b) -,S(d7d03a92,95064981,1cdc6503,588d157c,88c861d9,43fa9cab,e2e3301c,994adf7b,8c820bfe,933c2c05,1ca3042d,5ce781e6,ef419c8f,d9aa83ef,2a915e36,382f9627) -,S(5b2c9504,f645ac90,24e25c4a,e880ce7b,f33aed77,e45518d9,1c6f2652,ddcf11b0,500b37bc,c7764f32,11d681e5,e8f2a407,440e1da2,4eaec354,fc289c76,29296449) -,S(d18e26ed,d2c78bbc,16982675,9d59eec3,bab1a64d,f579dc2d,6284add4,8cfbd761,1a1e0172,37a3e78,8fd8989a,a5bb6944,685915da,1392e1a4,4a6c7ef5,7d0770c3) -,S(5f6b1416,9bbc4795,8ca21e88,df252546,dc9e46bf,85d64772,24f34ce2,8e58222d,3a8e7616,4d5a0501,947ca0bf,163e64bb,3a57918d,e383c600,e02aadaf,4b7fd6a6) -,S(d7a625e8,dcc8b456,69802023,8fe85691,ec2e050a,25421373,39bdbc8a,f762bc7,8f1f9935,a8ce2607,abd7bcbc,fec1fd8c,208683a7,10000806,20d50b4d,36ea3643) -,S(a56a5419,72aea4f7,15dc891b,3a1b34ea,7ffb42c9,5e02a771,6bac663e,8d5913f9,47b3dfcd,ad785671,180f7bbf,a7f5d144,59b44023,640e3897,1e999a90,6bc3f994) -,S(1ebb89d7,e574cbd1,37b1a3cd,4a306b44,30325db3,361b7c3a,d93116fa,baade31e,2039c52f,bd30c84b,4983d118,5422a342,ee020c33,49357e6c,b9550075,38da4dc7) -,S(b5728208,931a6575,4b5cd1a4,a798ec27,e189effa,3ee4f0c5,ad493a88,b49706fe,aba785e7,2da3d301,cb29a612,562078bf,358f680a,317836c2,14ddf7d1,bede9ee) -,S(56661670,d67b7c77,202a00de,effc1ef6,f5162a97,47afca8a,a2457c85,85a775c9,adaf08e1,83bc5107,4c55122,e549d3c1,4de8a893,39f199b2,ea044a25,4d8803f6) -,S(18ab56e1,ecc86b69,77104243,35737b51,c18521d1,b170a3e9,3fd068f0,ddf2704d,cc694c3f,43bfba9b,20c9572c,acb30563,df74f07e,ce1ff9ff,46b8259e,8119e94a) -,S(bc12a874,48270360,1575b754,bf5f50f,6e945185,2e0f27c3,c1aa0f1b,ce0ac357,9c6ce76b,ac175ce1,d667783c,7204ace4,abe12d56,62ff36f9,5de017c6,f1ada1e9) -,S(a4494c26,99b2da0d,6edbdd6c,353eca75,75666796,5ddbe457,2c27ac46,79054584,589804d5,8360a9e7,d3e2a914,61d5b1ba,e8f0cf69,3b8add03,5545386d,5082d621) -,S(1ff846f9,6d0e4e7e,be34de77,d036a027,f1baf9e2,ea3dc9c7,8284ac9c,ce3aea6e,8a0a336b,9f0e3560,31f5d1a8,d4c0b68f,27ba3eef,a52dc974,8d03e12d,653f2e6a) -,S(33181aae,91573ddc,728839e0,4173f716,6862d724,35744099,ffa8f1f2,9510b374,1252129a,8cc8ce4c,1ddaaa0a,4c34c4a5,f01ee26b,3e1a9fed,ad0e7c9f,bdc5223e) -,S(e687832d,fb0e44ae,f7649b15,77274a94,64426406,fe4c6ae5,7028c9e5,78012594,5e5b3897,6b734b7,b65caec8,c77ffb7f,c5de4f98,eecab002,8cac0c4a,a513b7c0) -,S(354bbec3,ed9371ac,58174b5e,2a18c76c,c22951,df4c6aa5,755c72f3,94b37def,40d0c876,9283416d,b3613ac7,37401e3f,3c2f4def,bbaba44b,5c2a83fc,c614c29a) -,S(fa46ac6c,5205b81f,3c9e8aa6,8b5ebef2,a8bc68bf,fa2f4511,ae36f726,7439a485,3853f9fa,b016d2a8,1cde37b,13f91185,f25657a,765fbb35,c1b4d52e,3f67d180) -,S(426f86b7,33255f8e,1e85263c,923fb86e,56a53d77,945f6688,5627ed43,3024328c,92ec0168,5301c89d,5b13c4c4,57b22215,658c6341,6aff9148,6a2efbcd,4e8c4fdf) -,S(5c8d1c9b,f9a72d5b,e15d3f4d,17d48cf1,7685dfec,b5ae1ede,b47b6e58,80bc64e3,6205550e,286c8150,6638a3c7,c20f0dec,b6a26b53,641d2dc4,e18d0f7d,29bda7e5) -,S(3a021dbc,7bf7501f,ddc31356,26a9cb01,be673373,fa663c80,271be570,e683422f,64a89c54,ddadf89,784e508a,d056492a,a7a71b82,485fcfff,54c7b0de,4c1bfa53) -,S(8d82aa49,1d719f00,75d2dd9,11d642da,7c0062c3,2296726f,a504af27,23ba47bb,6e616f50,6d1478f6,988ed10d,6c6d3c50,7c2ae8fd,4760e699,1ff5c62c,53e4e77a) -,S(6feee988,fe488e1a,6ed5d60e,fcac1b3d,bbe5451,6e7aad76,f27f08e5,3c5e536f,ee9f95,839fba96,ba26d848,425b68a0,73dcee61,35e04eef,f482998c,b044c502) -,S(36240979,bafd0d57,72fcadc7,314093c6,3063880a,e895ce5d,2df3e59c,ae16fa1b,619d0376,58ef3d85,a7afe326,77d832cb,eb20820c,157836ca,65f17c61,c84afa48) -,S(4c2b8847,4da56053,c2046fc3,26e81704,b78494c,91877407,9984a3,cf6a18f4,459a9e69,17a4d711,61ca0b43,85c5a823,734286e3,d0cab398,dda1fe21,3b28142c) -,S(f921c9fd,b33211ba,a7f4eb5b,15044c34,d6e54f50,af7b85ad,84e12fba,b1478ac2,38cda9b8,c850483e,48c6b16a,5f7f624d,e31faec3,5cd594f9,3171490f,ae016973) -,S(a57769e6,6181d68f,8f86c8a7,da3fdb4e,850ae07d,f41e78b8,ca42c6b2,1b19b257,212a987e,644bc42b,f757e00d,54d50ba5,1dcd6698,280f8eb3,8829dafc,527cfc6c) -,S(95a78104,37abecad,888c9195,23c9b16b,375a2714,fed74639,1ea949a,c7c11d9f,eae320aa,227b056b,242723df,1f11a494,ec642876,91a22748,9e1ecb2,a2cfdf78) -,S(76a7e034,f7ef3e14,2ada9a64,ce984008,9f034a5d,8584a0e5,d10d40f4,29cfa42a,999dc0e4,9633eb3c,2a4ec931,9bc2eedc,9f2e4996,522a2404,79c9468b,668effa2) -,S(eba89396,47567805,1cddf92,9db7d82d,427010cd,5e94247d,f4e8cd1e,eb5881d6,b92ae1f1,c0885214,3f37d8be,616cc5d6,aebe0f8a,8da4a6a5,d4a69b5,dbbca552) -,S(a53a48d8,59fe156,6b14f872,aaed4735,dc0b7589,713ce8ad,dd3f3e1d,6e23704f,9e738da0,7e85a3a8,3d89403f,3ee7d564,4f463418,676cea0d,2528b515,39387fb6) -,S(8326590b,dba5f8a3,8e39b148,105063a7,c831cdf9,98288fb5,95b4fd5e,a707d3bc,a02cf88,a2a1dd25,2d00d62e,cfa4130f,61b7d4f,297e6b06,cb4661b2,bf768982) -,S(6a492194,ba8c10bf,e31714a2,17a74b2f,b0c35a2c,95c54af,7f5ac6df,17916030,3cf0bd65,8e0c937a,92ee8b4f,b4fc3289,c531cd00,6febd45d,b6b6c522,f8c77b87) -,S(b4ac71c6,ff797eed,61d80c49,46ba221d,3b34bf13,7e3d4747,4b6c3068,33c52a57,46acb2e4,8fb6fefc,ef3d2343,4624e0d6,14ae3b60,df813683,90503506,d52820f7) -,S(8b11711e,65bc29e1,16bf05b4,e557b211,13b19b93,a1c1ef9b,49a19316,c286e0bc,79c4a0cf,cf383538,21ad695e,5b4eae58,faa6bcf5,c722c491,aa9078c,8aaf0dde) -,S(b8b00a76,e86b2579,97603f82,e80fde24,727362c3,6d7a192d,8974f643,4408e098,5db6718,8b0108dd,7cc6fa1c,fead7b2e,9e0b9ffb,78487d0a,5851b6f8,513e56c6) -,S(884c3a1b,fb6b968,53427a8f,69b713c6,bebe8f69,645fa52,c50e2d2d,61d89814,3dacc0e5,94b2eef,3743f821,df54dec0,ff28aa4b,d5b18fbf,14d658ce,7a3749b) -,S(3d0c1dcf,51aabf63,fe04100d,cbf6fb4e,c004dd1a,aeb637d8,496a47f9,74637596,576ebd5b,bf5de2cd,6242a6f,599fbb76,883fe013,3e2ef05d,22843236,a5df51c) -,S(56b3edaf,61539adc,25c57f79,a277b77f,1ae972b6,3d5328fa,13f811e2,dabca8c7,40383900,a2b28602,71ab3d2b,5dda95d0,96bdfbab,79b3d347,dbdac66d,2d2e98eb) -,S(426e29bf,50f34c9f,434eacfa,845485fe,5fbb11d8,319f9457,a74905fb,2bcfd3e2,eac47ee8,eeff40c6,20d10cd5,c3b9df40,eeb60b88,df1f57a3,5d613198,33cb117a) -,S(955737c9,f4e24d7e,c6d419ba,a2edadc7,cf0a91fb,5bfc3ea6,7ed50ca7,62929308,97bbb89d,18fd9040,2fa78314,359bf645,b69831b5,bb82e608,67baceed,481675dd) -,S(5d72a813,d46427a0,f2fae639,fd7e7ad0,704e74a0,83a784a1,cbb85017,e8b3e514,c92f410e,851fc61e,559d6839,a99eb95a,2e8c2636,f51c45ac,9bc1613c,b8876c2f) -,S(c7da9359,e9bc8890,620876d9,170495c2,dda7849c,7852406,22551bb7,e769b6ef,12278168,71508d00,95d90787,24a0c7d9,cb41f6c5,c82f01c6,d3794c3f,5c10653) -,S(67080a26,da7af0fd,c2fee080,f20ae516,d92697d7,fe1adace,9729064f,569ac683,ad9a07ac,fbba708b,30944107,e510eac0,8e08c5ce,79f77714,aa522cfc,2316d94d) -,S(210d5a39,d61428f7,6f878ddc,82e3afae,3947f404,5c155a41,63a00570,5bfc0dbf,617effe6,b0a629c2,ed14cc29,67a9193c,2efa804c,93e997ac,96eb1803,2e8c511c) -,S(5d0b9231,ca1511b9,c53242a9,37837d13,9b8e461c,6ff655fc,59021d04,e334ed98,c8070121,f4794eda,713ae1b4,a9e7d6cd,1a2f58e1,f6f8d986,bd13a66e,bfe924ae) -,S(687bb82c,42101161,ed0c8bd5,44c71975,9013fe2a,fcd10ab6,3ce78a67,e2907392,eaf63d87,758aa3a6,f9fc721c,f8b209cf,fafc8e81,10397e35,6a25e966,100d9eeb) -,S(51a44157,b8048f68,1a2a3931,ff2c3ff3,c63527d1,f4bccda4,e66a6d1,ce5f5d33,6ffc8d16,519c2940,14fdc8f4,20a63890,1a0c5667,2db96a1e,c5127fe9,e847dd31) -,S(b2862572,56f515a3,5624786a,478c3bfc,a5dd7b2,2bd7c4f9,89f70bcb,8de86775,22ae96a8,a5a5396,b7a67e5b,29292ffa,f53b64de,45f17692,abcd932d,4664f3a3) -,S(f76b721e,201078ca,eebd89a5,ca396213,6ee129bc,fb92ae58,4bb7c7fe,835bc30,599c6ab1,8419840,3d6b3d17,161bafff,223a0a38,1e96a4b7,a062f4a3,e6c0d561) -,S(12f24a87,63adee06,e82f20b7,ff696911,d9a3b88b,36dedb97,93b07c34,c4178e9c,59fd7b9f,96f01fb7,b265d939,c2827bee,b2427fdf,8c2e1b7,35178d58,e055b7f1) -,S(9e1b8a90,de6c6bbe,2a082d47,758240cc,bcfaf145,c48f90ce,fa0221e3,1922260a,fa5e86a5,b54bd9e0,7c2a54f4,2097d004,8a71eb06,ea48c0a6,6cda5981,b390f9f) -,S(63f05903,20b73eb7,b01b6a66,e28e31f1,ed4117f8,6c4d20a3,8c109031,2fbaae9c,24b8c9d2,d34a81fe,6e88967,a263877f,40bd68ca,baf5d9c5,1abe8b1,9501d8eb) -,S(447c7409,f5402a3d,a1f569a4,ad9f2855,e5c89b6e,99c743a8,e27992b4,63905999,d44e8d9a,b34a7a09,47b37723,be016c08,716baa73,8b93f28d,b7790370,ad49e154) -,S(74a4406a,4c5340af,ab77db0c,20f197e4,25eed4f4,a3f986df,1bbf10df,f8793254,162d678a,a4ba712,8cd36907,d1c46b16,dc4c07bc,52aa46d,fc7987eb,67742023) -,S(f7035171,31872637,ab0e63cc,841cc7b6,2bf5e076,53a45ff,3a23246e,8f047c07,c84b0391,4f470785,721762a9,5972b59e,b3c7eec9,66718936,ccaee9c1,da1097ef) -,S(ec4fe07b,57b23581,2c53bd70,6b0a4152,2194d168,dca164f6,ac999f6f,72eaae11,af495291,45deb29f,ec2b1dc4,e9b76051,b2f9df79,bdd304d7,b5528f5c,a2fff789) -,S(17156de8,fa96174f,7a0b274e,e168d0d4,c6552047,11f36388,78dbab4a,cdd2ac9d,2ae3ec4,36c1460c,984e37ed,6decb88f,c2de9f84,79e28ca6,abb6803f,1461ac3d) -,S(e41b462b,9c5a47fa,cfa9be56,dd30cd,549cb90c,9506a6a,abfca643,9a1b2ede,108fe2b2,8bda60a,c68fb353,38c6958f,e1b3604c,22215311,d380bf11,17507f4) -,S(ba6c0159,20a67883,d7880051,51a8038f,f357ea78,c53b95ad,38a6f437,7744aa38,da49c0e7,deb6b746,83366aa5,c0e8e710,cda1441b,6686f680,4579b5b9,16002cf3) -,S(26f0186e,883a4b6b,87102ab7,f7e52663,7e8a9553,8495729c,ee283568,f8cbf1ae,eef8de4,bb2197ca,ccd51980,995a18a0,aad78823,75702d3,98b245db,4bd5f47a) -,S(10b93de,80c0cebc,351b5588,c0140e63,e00874e3,da663cdd,c4501ca5,b40c9d22,ed3189dd,f79af36b,e7986b02,7ec495ec,1dfef7f2,14358284,2d05b4d0,1c903258) -,S(e79ec274,337a82c1,c97b32da,8f5a8c55,7a159540,76c94255,8bc9a3e7,77769dde,9f23079f,22dafce3,54a4c175,d888f3ee,e527dad9,83d7502c,3b651762,628a06f6) -,S(fda0175,44f0ad3f,c8b9915e,8e0caa4,2be265e3,92041b0c,1b7d31a1,6fc101e1,424e9a27,85d59c6e,bc7e4298,1a505733,e4d49a76,b84a030d,db2f5c1,858902e7) -,S(681f01cb,5380cdfe,50314725,88bc830c,8327d8a3,cbcfdb31,577cf11b,a099c6bd,bf9d2117,cdc3b05f,9c06cef0,6fc9e757,59c02fad,8e0d98cd,794918,f39002bc) -,S(70c25a6b,2a2d2cc2,dd251f4d,9aca250b,d6fe9f8d,b9eff961,1de2095c,dbd12f64,c9eeaf68,a386b2cf,cd3f4dc4,793ea5b7,134dae04,d991e1f4,6b299a4d,1a966126) -,S(464ded2c,404b42d4,fefd5ea4,5f408666,3b466e85,fe8b304,3b121b8,9fccbb9d,ac113904,6ad3f613,23ad2d3e,a568367,610bb47b,e41a5260,79627122,105d910b) -,S(a32df72,48e79198,5d455109,a8c5dfc1,b7ff8990,1b5ce3f0,2ad2f134,13a103db,6db4b4fb,9d60906b,9aea2d1d,876296c8,cf9ad8d3,3e65e173,8212134a,4b160e72) -,S(fe49ce9e,7ee5d39c,97029774,64ec4fea,3ccb74dc,2a5c7fe9,a7695315,165179a,653f553a,35925dce,eefb9866,26155723,90bfc582,b4c426e6,3f58f0fa,3fe7dc8c) -,S(868b2e55,c895a7c2,4da24750,c126b10d,ec0f1a0a,2add5a87,8aa7316e,3354ad14,5e288874,cdea19fd,71f03594,1a6291bc,776bca82,804324,efb61f24,7ac299ef) -,S(fe0790da,90ae34c6,8ad3f1c0,80fc486b,d267ff7e,fd32d1ae,c63d08b5,8c098461,ad331393,de35b283,471a0244,422c6132,cdbfccdb,5680bef4,16f3beaf,6cf7177e) -,S(fe7fca8d,f4f80dc,ff16b196,167dfefa,42a23bf5,66837955,7f6d8279,6fe9a9d9,bbc4dd8a,d7ee925,dd80cb3d,681476ae,ccc5729c,e1815b1e,71c8f1cb,d8d4eb3b) -,S(a236c270,aa4ce20b,eb51b11b,511cf4c2,ae797598,e9f03fd2,3aa36858,9434cfc2,593599c5,75a7bdeb,41cc3ade,608c210a,8bc37040,fbb69f4c,4863a31f,2088f29b) -,S(d6a04a5,6bb8c27f,3ea8a348,538364e2,800472ea,d9e1f644,565546fc,76519248,4b95470d,50b97629,22b099ab,a5761243,dbf6e466,226e8e07,9b77069a,b542deb9) -,S(d09cd377,d64a045f,e1a76f97,4d701a24,67773228,3261aebd,74e02ea9,f8a30e7f,9f0942b9,2b702b3,d76ed2d0,1caf880d,41a342ea,ee06ae57,b90a924d,6588ffea) -,S(d030c72c,16d01a9d,6c2e5245,61c7e3fd,b9a469bf,ff0a7440,b2ed0ea5,e5d98b8b,c6b1308,dba4f981,16b60ff,eaea843b,fddeee67,ca1406f4,73db0f11,531f2c8e) -,S(56c456c6,d2c04a7d,441980ab,80b39a55,57d0c6f7,5706bba1,100c6bb1,e345a691,c5b2f0dc,2c735d0f,8ef10ffc,2753c2b2,825ce525,a0613189,fae34e64,26084819) -,S(aad5adf3,b505d1f4,28dd1b98,dd4fdde5,29d911c5,e0e5837d,75e51bac,308400c9,e94adf67,4f7994c1,123aa411,b790c68c,f55569f2,1df4b6e4,6afab87e,2777acc6) -,S(ac8cd8b4,dd76b8f7,4886b089,f18b4cb2,ca1d43c3,19ed034e,6b1867a3,5e6a0ef0,71d70894,f9daab15,7413f827,1cadcfc6,ffb71db4,9bcc81f3,c759d4f7,137ba96d) -,S(3964006d,f110fa45,409d7a4d,5996b44,93eb4150,f4217948,41dc5357,dc47ca1d,e4a11c6d,21dbd93a,f922a2bd,23f057e5,c2f24474,36bfd7d6,395a46df,3ad7cdb) -,S(2be10b92,27a312bb,74ea37b1,9bf910b7,723a1ff8,fb43dd55,1a0e1fbf,7bca56ec,19aa8afb,c886dc0d,293ecca9,4290b24b,755b2de8,c1dbc0b4,59052edc,c6df59ab) -,S(379c1556,2bd7f51a,1d219a34,dffc8bab,ccc1e417,1c38d342,a4c6325a,b5ad6ae5,47a1f28f,a6371df5,66dce223,10d95535,e7bc6734,7f20748d,b983fac4,2f185907) -,S(24054dc2,e675459d,2af584a7,d78110e9,30a36290,989dd4f9,914cf7a8,1fce9809,6572ae1d,3e05d0a7,1c4e06d4,820d16a5,3553dc81,a6f02a76,12b584a2,e57ae592) -,S(9812e6a6,f46ca979,ab7cd879,1023b32,913199c8,b850298f,a3bb4c8e,a02420a4,468f6eed,dfecd933,1bbaf36,986f9377,3afd963b,56577151,52a12b9c,88f937f0) -,S(46058644,6a348e4a,d84c928d,62c9de2a,9f6c14fb,95c83c6b,96203a5a,7f13c700,9dc55ee3,ca3d701f,e6759c20,3b18840f,4c873f11,57b21ad,90401e77,622d57ab) -,S(a8dbaf97,2d5b05f2,a44d862f,e4aed0fa,1cb877ca,639ac322,8e909507,bcbe006a,3db54c03,f082937c,4f98d38c,6141d0bf,253e6729,b83c9902,51ac4a97,176fa4bc) -,S(9b8b39f4,f4d91329,13324bcd,44f9846a,8b3019,22671128,74178009,391149fe,490a4f72,1c452e5a,88ffc693,90b0d1b3,4e4cae7f,2e0ab097,6b396a99,1c52c1d3) -,S(334681d5,a7ef46db,196404ea,9e501f81,7406ce24,27a64597,73e358ad,314615eb,2b23603a,1d80cd6a,9f04775a,52069de2,e328fdc1,37fe6b6d,6c165442,53ad6c0d) -,S(feb8e310,c63c6ebd,294639b4,a4cce42,bd5f8372,b7aeaa88,2023f0e0,29c32529,cb6e42ad,6a0cd780,aa57934b,86682260,68a45c63,bdf7e617,fbcbf86d,db43b213) -,S(f4a17bc2,c7334e92,dc923252,3b910a55,a8ca5cb6,2b3d93b3,fcf0f2c4,8705cb67,812b7795,1b24729,4b3d55a3,2f45260a,e7f4a9e3,d5cfa304,bb0471b0,da6e9dfe) -,S(8ec2ac7b,85514349,5496d596,bfcaaf4e,c330a995,f082324c,7e0479ba,4ccf181b,ea1588b6,7811d263,7bcb3bcf,5cf0bc4,70e92797,27b1c258,ce4ebba9,35250130) -,S(b1e6d61b,d9aecdbc,c9c4b6d,9e48c6f7,e4aa9eb7,7da3c001,53443c6c,4d4f19a,43af7b55,b2e2c976,8b1fdb34,48d6f339,1bc20aba,eccb1a3,5aef98af,b28cbf4a) -,S(4d83d2e8,210d47dc,3904a397,4db35433,1a951963,2d4e2e4,b69f2049,2f13b2be,7ed96c83,3874fc97,be45f1d8,8e5842b9,7a0e3bac,95400036,7c8572f6,3d37a6b3) -,S(1448e92e,fd51fc21,d6f5d514,35527f67,25f5c5ee,b0b29c36,b9eb6e8f,2bb20b84,248a338f,c8be83e5,2f91c9a2,2868973c,13336aa6,39e43f4c,ea8bbeb9,96e344ad) -,S(e23b03d6,9c2250ac,2cdcc7d4,4e0a218e,39d928b0,2585fe63,dcf7093c,924e4ead,8c69c7d0,4a8a4b7c,1997ef44,fadb04d7,80b91cba,13dee454,2effb8ae,71b9aea9) -,S(4cd1e35e,21fb3fe6,946a929b,9aebfcb8,78663224,da66af94,e5a722b4,32b5d7cb,6b1112dc,5e865b10,ba688780,32978617,eca892d7,730ca984,cba4ab07,7167e3bc) -,S(f3cebaf8,92cb7b0,27cb9212,3596ece0,bf25c6b0,d8f1dbf5,f2efb204,a0db647,a615ddeb,8418c013,91923b88,7bba5d3e,cf3c7172,efbdaab7,e12582bc,a968d8e0) -,S(4b8acd28,500bf88d,68337c81,33181706,dfe341de,7b1d5736,a3a85a2c,6d655e7d,be93d7c3,825a5675,84d6f76e,52f3b06,7b7c5d87,844f18ac,624c96e0,fd219bb8) -,S(8dc7ac81,d04e0088,63fd2de6,2cc68de8,3e567d81,85aebc53,d4771950,7ceb9fe1,62d4b64a,be7b1931,c47a7755,e25c803f,1eb14c89,2ee100e8,214b94c4,11fa9198) -,S(aa63343f,3078d48d,942bbbe,df4f2c19,a817c257,9003e033,7104e530,c1b89a23,277ef834,23a6730f,69c20f4d,9de94758,13befc6d,ce389bb,fe7958e6,6ea7b524) -,S(37de5061,9f301e40,8e9096c0,1a37df3a,dadeba61,bc217495,5d04d7a1,5121d30,7e7049c,33e40b96,6a136516,c005597c,e3f6aa70,d6db4c31,f5732fbc,e538898a) -,S(6d18cf55,506d59ce,a3e8cd44,f347481c,3ebc6682,2f91445e,11f2c0c,45eb83b4,e930e9c1,ca8b73f4,7fb9818e,5d4db8a0,220f7ba7,ce807854,c8ff2af7,b8a30cdb) -,S(77d85660,6de7dac5,dd4203c4,90152c9c,f70243fd,eb1d1c0a,5b797b39,16caa7d3,3f57cfe3,9b37d550,c9db0fc9,4b3c0e3b,1a2722ec,f920522e,8c37d848,f59c659c) -,S(5c2e69a6,c44b5bb1,c55dc8b5,6f9d4fb8,ea56450b,d69d9229,670e635d,f381bf16,f082049d,a69ca9b,a2821a8c,2fd0b46c,9ec21af2,4c34b049,f1af0126,75a3588d) -,S(329c01f5,66d925b,251944ed,92beb06a,aaacb98d,89b2aaf1,918ce400,b5a393ee,7e29b038,427a0fff,6ad50c80,aa49252e,e21c2c45,3d4c72a9,c3cafedf,faa57abf) -,S(4c2e631f,18b2dfa4,37ebb401,771d7b0e,b670f4fc,8546499d,f62b49bd,629525da,8a95ebfb,87423fa7,4c131432,6b7c204c,50c6c2d,a3f85370,1f789ca3,fe9a6f9c) -,S(fe121b93,d254465,c7f7cf02,ce10a575,d3808ce4,c6133fd9,392fbf1b,63d03fdc,33129b07,7bda4311,94fb997f,9443a0ff,e59438a,f360b635,2a80cbce,a49e0ba6) -,S(323ac27b,1cdbf3f7,74e20521,f1e74b8b,2cf8c5d4,4180316d,a532ae61,2f784c23,21156108,f6a64ac5,888b15fe,834ba9a5,c8489e16,f3d31197,bb296b2d,3fc3dc18) -,S(11478f62,fdfcb1e0,3a5f0ed5,ce0c2101,eeccbca1,e5934d37,41b1a8d2,7afd533,a9f79673,2fd3ecc8,644cdb17,6d11527a,aba8d0b2,985366c,70d96999,ec5f9153) -,S(9f0909b6,c9d3c1ad,eb88acf3,aed5a6a6,bc8d82b5,767896e5,e7343efc,20b9d078,a5161ca6,c5c95d64,dc663e30,b8f65234,61a579d7,b99a57a3,3b0f3844,e47db181) -,S(4960a875,32a9ad42,299d8cd1,a1af80bb,2807acb1,b52f1711,c55957d3,a64a6b9f,578e51f3,f1b46628,eb48f54a,93f82f24,4bfc6202,eef77dd8,cd6b90b4,de976625) -,S(675c29c2,bdb265e,5490951c,bfc9f73d,d142d536,4b5ec668,54b582f0,5d310354,22d1f669,3d82de84,202d4f9a,186bdfa6,8cb8ad5f,9da33a49,83229047,e08bd6d1) -,S(c4096cbd,6c75d0e2,6a922177,916ab32d,a9053adf,ad849d36,f65b7c9b,107ce605,5f236b47,2ae3c979,2ff61efb,9633ae05,b2b97e51,24a3c2,94f5be53,95c2bb46) -,S(9ea0d341,ddd05401,f01205ec,2c754155,b1ddd460,1fa3789,dd80ed9b,3b905c0b,3bf48101,97e7d0b7,6f3692cd,53989764,ba7ce059,953f7b71,7e615c20,da28e69) -,S(bdebbed7,84bffa33,72a6edd2,d9815b0d,637367f2,de3768c7,b4dd75a4,32fb92e4,5ff3437e,b62a9b62,dc16af10,5a20941d,297a431f,ca2b0067,6734c4ae,cfd0b9c0) -,S(a486fa44,b46e34f2,d6aea82c,8f554210,cbfe674,77b560c7,bccc7d6c,9e910932,1ab7e36d,8a15e284,8a3caa0,f54ca555,b8ad5baa,7f47fca8,3231c822,f897317a) -,S(4463a0a5,57a1a926,aa204376,a20aefab,66e7abb1,18c7f769,fbd1a7d1,29cbba08,4a823aa5,ab7b602a,704f01de,20b8ad13,7dc08152,25ceace0,9a9dab69,d034af0d) -,S(d6e08a4f,c45e8dfb,ab713584,d91d1d8,8cbdc5c6,2eeb4b4c,593a73df,4d825ac4,2cd85bb4,77c0d0ba,5071ae8f,c0fe2dbd,8be98d9,622fe506,c59800cb,5eb4c55f) -,S(b626e299,2a69cad4,e6076dca,29bbfd34,546d31d0,a4f8b656,a433fa87,f96a10f1,6df4b2ce,ba919268,f1568632,55e27655,62ac5e3b,8cbbfd34,3c656f43,43cb5bc6) -,S(3619e6eb,74645070,b2dd6196,5fe4d25e,25a4dfeb,619e3b05,7e31a566,947139a5,964b8989,ba156121,9d36c3bf,29467c7b,79940c3b,450c1431,1aa0d725,1282093f) -,S(b3529b5e,6718843f,c40a3a65,d5330961,41e5c060,e326aa84,7ccf7f48,c8bda2e9,49e6e0d3,7ce1bf45,e9c595ac,285becf5,31111e7b,2a67b057,9d4fc552,59c1b935) -,S(e51f0067,5bd7145f,fcf85527,dd247ef1,4a199778,94035598,d42afdf1,2fa9e05b,d59aaf3e,8b4d72eb,4523d5fc,69b047e5,7d2e175f,30eb6c8c,ec729cbf,c1b32666) -,S(8a87f066,f64bc468,d225eb6a,a0a7b54b,91c930e4,d4520720,1705f831,cde79b28,a92a5d95,e0057c95,b219062f,5d0e4277,249c34ac,6255113b,b5eebea5,66800227) -,S(d8a81015,aa878ee5,a69c771e,bf88daad,3a926afb,b8aef632,cd7d987b,fd310b06,af77f7e8,f276ed4e,963e3a26,2f3942c7,ec9f31da,199ead3,d5e5f53f,e20acbdd) -,S(88c3fa19,4f3f4d93,dbe5b8a3,865d28d6,51c9abd,519af4d2,c3b743d4,ce0cc5c1,104caf7a,f9ff822,7b3671a7,e7745bee,26b5deda,9982b9d9,a9d648e0,760d8f8d) -,S(f8738725,3434b0ea,f05e9c76,3c729a8a,22070111,6c5a6484,5532c3d9,41ce648e,a8b5eed1,d4ee7913,b69f6627,d3e1be,4c286e15,78167201,46fc9e21,786f7bd7) -,S(5fca538,5afb021f,94cca826,5689605c,7b35c8f8,dc8fef60,6b18420f,909acc33,1d7fa51,f5c28bfd,eb1f9a52,723eb2bf,c5b4d078,d5d4b639,2b791af5,d5b2b3a8) -,S(47484548,d4b2acd9,bb2cef9d,bed4bd0f,f1fddf4f,e1561a51,891464fa,cf5007db,ea61e154,f011cfe0,46fa2539,7fb444fd,b93e223b,ed882bce,3ddaa3c8,328f44a8) -,S(331f17ff,b14d43f,ec69a6fe,b41a8021,dd8ef56d,2540234a,b466ac85,e6c5b8f1,ba20bca1,8d774731,b6b64a0f,8a19311f,37d8c061,2c4699b,68d569b0,9eec144b) -,S(6aba62d,200bd2c6,4ab88ce9,80530e56,5b8971c,f9c427f1,5e9b146d,dbdc68ce,e4c936d7,d7d98919,acd26ef0,cf071f2d,fcf65fd7,78dd8c5b,ab026,e9f832c8) -,S(c76b6c35,e72fa19c,621022b4,d9ec6ece,c0cfee8d,c73254fc,f52cbc69,23ca19c5,5b0ffa7a,48ee8599,9b74d0a1,d7fa0289,b49dba85,7b21bfb1,ee7ba831,fa13efc9) -,S(c056ea3d,43f33df9,b01590fa,429c14a6,aaa438ed,415254a4,4a93854,ce1bb77a,d5b194e3,2337a9f1,2c479e7f,576a571e,58355a02,8ba0231c,c337b8c7,eb3dca7b) -,S(3d688ccc,8ddf0ef1,137bb897,e6b8f3b7,7df652c4,93cac3a1,47e88b3d,bdac938a,bca94788,4d7ae1f2,960daead,111558f7,38b6bc9a,7af3bb4a,691af22d,4d5879fc) -,S(4faffaf6,69ce1180,a9145f0c,df6fd834,c59d7a9f,5f2e49cf,3924b33d,8d2a179,9e015cac,2dca2ec2,5580c16d,8c910abb,dcbad872,79bcc485,b71f5561,60159d2) -,S(47578e3,7cd7eb78,6b5a44eb,3decc7c4,e8ba0c7,6699ef61,4ac30579,a24aecad,948ac817,a6bee00b,c68eab83,fb628ed8,7fd0066,9ebc8569,45eef8c9,67171651) -,S(9aade275,3eaa646a,24ad1a35,f74887db,8c72fda7,77b59dfe,103e1a95,dc618836,b651c384,8f4625f3,1e6e7a05,c94483f,ceef2fed,dc7f4256,87e0373d,d02bca96) -,S(b1b0c3e0,b1c6ee75,55a81852,447b2bcf,321c9b9f,629caf9a,276133af,63aed711,493accfd,624e6ff3,dfc1d0dc,aff17113,c2c74167,58cbd571,759bab24,300ac827) -,S(c557758f,b192a058,eaec5762,ff391a9b,2a0ce462,7bae01c,156dcf3e,bf2a8ff6,1d4e9b53,d209e195,9f10f671,b1bfdbf3,98921284,a7719766,39947969,6d1bd3b3) -,S(73522ded,5120ed4f,b49b5ca6,df5a1b6,edcc082,48df4d07,cc9ad923,2b7b5e0e,47569d94,cdf0270e,d1d299ce,d5bcfdc7,7f87db4e,c9725a96,e4388cf8,dee08d74) -,S(16571c0d,66328963,2a3ae46d,fc2bee50,fd6fbc0c,f0ec73ad,72bb9c2f,e8323506,65de9d86,9e001c60,ced57911,e7ce6150,a936d684,d759f143,d2224448,4bec68d2) -,S(f5fe5564,2eb630a5,c860cc8d,7c9ef86d,b1810d2e,82dcb343,dbe2f958,98e5f090,5cee7a1f,bea9dac8,ca340dcd,fc2c097a,eec2dabd,d7ed7504,e20c913e,9fadfa87) -,S(ef09db32,70d09043,43da67a0,b87cedaf,7aece017,58d78591,8814e3ca,396e3592,5934f805,ba246e9f,965c6161,cefdf4e3,7df14271,2ae076ea,80ca239a,c7b675e2) -,S(886cdbd7,27d2f099,9852b102,bf201ed2,5e174622,f974b0c1,3edfe523,373a54e8,dacb328a,7fca6e5a,e5351825,564e4f89,5166f687,38d46142,6eea7b09,dca73b2b) -,S(b7d86bcd,4f7bf2e,8529ff84,88d9f3e9,62071308,9bbd91f9,6e4ef82a,ce237cff,c6b0aff1,375a547e,a8546dc4,17574843,3acf2a4,ed0d002e,e32fd88f,3b702f0e) -,S(d7d171b2,8132ab85,30791059,395d94ec,c24f5e99,67bc6c4d,22bfc7ba,eb388c67,983770e0,2421e2b6,55d3c135,1bb39bf7,7be39682,97088744,bfe6543d,dc1a8f8f) -,S(ffe712fd,881e30e7,229f1cfa,833dad90,f01a1896,c1493502,a429080a,9794b1be,f4299e03,75d084a,10b11ae5,8f2fa2be,f18b037a,53165586,cdac18ce,54505da8) -,S(563c92b3,3226951,cd7cd10b,3f7b35c7,dff3f0de,6f03d66,9f664655,57d13f7c,dca1eef4,85bef41,80b0ccfb,2416f948,9bb21094,854f5f43,769cb37,33ec10c1) -,S(b8e76ef3,3a2cebce,614056d7,efa47c15,dd52c228,66a7d3dd,9a0d4d64,68f32437,4454e79d,652ae799,a3a539ba,42619a1c,3076ccc2,109dc4a2,2aa41a28,918651c2) -,S(36db2304,f60703a2,df2e429f,b8a99841,7b4a4f3,e08642d2,c5675460,aaf1c971,a0536e8f,5cc30aa3,d9b859ee,e26b1abb,ecf7f9b4,8c8fef0,f842fc9,a684b5cc) -,S(c5d4e51d,1521637d,d6055e52,9e9ae2a4,d537c1a1,b7c6a314,f9d558a1,88d9a5ab,c841eeed,6a13782c,fbf65b08,c6570994,aaf7093c,4b48ad0d,e04db33a,6feb3f6d) -,S(50c03dc2,985859f6,ffb79ed3,f635e17a,b0561533,600af220,7cd98f9f,71c4bffd,c68c8797,a7ed229a,f59a2bd7,451c748a,5c425528,8b7f6b0a,68b64a77,d7137720) -,S(2806d84b,3e7e6f9a,2e10ae5d,cf5bb0ef,98560691,71d31ff3,3645346d,f08333ef,72f23443,38e34ccb,4ccb5ddb,f3a6b58e,bf8cac26,4243785e,54a9b503,c87b429d) -,S(40d70ddd,1ef58dd1,c43e33c6,29840fee,82bb9c1b,e222b53f,4c58952f,388790a4,9b1a9d57,b6dd9932,338d170e,af4d5516,e654685b,3946930d,96b2a1d7,f70770d5) -,S(8850ec32,4e71213,bd77b193,ee21da82,ac733804,17983905,d0156608,8b87c835,aafff7a0,a9160b91,92df58ea,a65c0716,961480b2,b0cb4d3a,7d637f77,ddc160e2) -,S(54951509,bd7c29f4,77f9d4a6,2be485d7,de291b0,6a308bd2,c240cf71,50ad6e8b,2fdb347c,f2a23b9f,a3a45c76,44cc1fa9,b1d8f79f,77c02f27,f136c732,c7ef2722) -,S(9f5ec355,cdf8eb4f,be5af1ab,70a3e7cf,1c3d3e8b,e643621f,acf8f69f,af7e5d44,b203dd5f,b38b3550,6fda94b,ada1c4bb,12b8be5e,92bf8a58,4886f2ca,19d3c06e) -,S(812e4a9c,1bba9e52,8cb5e606,c8b326fe,8b72f0e2,3062837b,bdf371a2,2ec0b3da,2ba7b5b7,14a9ae39,c62bd36a,1ed00135,5d98d248,9ef90f24,d10d1c58,f8e222a1) -,S(e6035ddb,cf85616b,540ff16e,cd5d7fd1,af52c6f6,2a26ec36,c5c1ca86,2a3d924a,a945389e,f687fcac,6f918718,a1f29f19,173d3104,69c5954a,d6cfb5df,f01eec86) -,S(d788a5e8,d771d471,b7169693,86b2339b,2643f129,a6b50bc6,321e752,6a033446,34b85622,5095783e,fa57fe32,a7d91b65,c0c9a42f,79fe30e0,b2598967,e97d3990) -,S(663733dd,29374f9f,1db5f11,6fa32b56,c8ef42f,706bd802,5615d4a4,77c6f41c,3585d45,3ae0fc59,1614e916,a1400b79,85b59f66,6e2553c1,394ec26d,d078676d) -,S(5ec6e728,5ae1413,3dbad4d1,19e2e3d5,6affda33,356146f0,a5ab023d,b323ad9c,3dd241bf,cfc6301e,29cd609d,b1a0fca3,d35a56e4,668de9f6,45c23d69,c0884579) -,S(f18fc442,1fbb66a2,7c336647,1459717c,87532be5,d4416cee,e4a674a3,2cf8f3c5,d38a0881,3bb33df1,fb4e83,6686c0fa,26847e5,f7580de9,b4f229cd,1359d560) -,S(818f549e,d9bcfe1f,14b8d336,21342465,7dec0dfe,eea1d719,20622442,39f5345a,37ce611f,cca2f448,45c1a8e9,d7f4b3f8,48b24c5c,2b9f5368,8cc2c8df,846602ee) -,S(75e2c791,f98e3fc8,2a74ee3a,532e8796,4f4fa8eb,6421aa64,17a5b00b,1edce942,51f2373b,a4951362,68aa17c7,1160855c,7c4d37be,222a8b26,f2d54cd5,37e5f6b4) -,S(711f8db6,4c0c6d31,daff4ec1,f9937730,9b44de59,9f4b9119,9ca6836e,1e3954d3,485955e3,432ac82d,f3170fcf,7b3519cd,6e4dfbba,170bbeb5,b75e3e7d,70caa4b0) -,S(63502c26,6f755a1e,4be2104e,e8ca9c2c,5216f50f,e21e003a,16071bc8,df3ba6a5,a5c829ea,c8fc3f4a,f55075bd,afe77977,3954b88a,f1f3a8dd,90f28aa1,49bea942) -,S(2a677459,ccfee070,1b5bb82f,d2ee57e6,13f5c3d6,3927938c,92d10954,c2850872,ff6e9798,5c5db0b2,9bb1cbf5,db03e0c4,401bbf28,eb39e053,714d5c5e,ef7cbe71) -,S(68f85f87,78fb69a7,9db4a22,3d7faf95,5b359bd0,5f230d99,f051b008,32b52cbe,dc2e949,f4fc3189,c4f7b771,f8b56b85,ef9c65c0,b3bdf89e,405d5f3c,ffc92210) -,S(7ee9d5b7,3b542036,509fd8b9,de590b24,9e9883c8,6f4bb90e,1c2904f3,d2b74ade,98122413,241cf205,f91c6977,b925ddd7,4920636a,9dd67828,2c30ee,7343e62) -,S(8447b090,cdb19271,db368023,d40e520,102b5d04,79eaf391,3817553e,24aa33c8,25b43fe6,55a27481,c02eacd3,9025a523,121d02a5,78896a78,c14a8c21,f7c0bdb0) -,S(316073b9,3f1550e6,b7951f56,90c5ef3b,e45e622e,77a2f268,c89a8b6f,2816a645,557ca5ac,2fc70ce8,c3e54a4d,b31d5c77,a1a6f38a,18646caf,6a52db31,947624be) -,S(fae2312d,a2ef21ac,358fe949,5c011b18,cdaa8ef1,c99284ae,5fc1eb77,4836d6ac,6f3bf661,2d99e865,b0cee7cb,3fccbf08,aa948ad9,b29b4b8b,54eee8d6,3f0b76c7) -,S(280a2bef,5588dfdf,b1e1691,d3162aec,7d4c72c6,b76f23e1,2f8ce783,54f839f0,f00ded1b,c31a9774,a87be1bc,7e440585,b2b4ba63,cc0d9c73,ca7b4873,93683f72) -,S(3f43e77a,9b7b92c9,92b7e5d2,8c75444f,4d0609b2,8aa65ddb,86bf6ac0,bf7ccdcd,b3117903,bb3c0a54,bc6bd6b9,92b8d85c,ac267855,50075536,6cf70a84,4c72a2d6) -,S(3a0afdc8,387bfa34,87e53929,51e10e,9535500d,f6506296,46df162d,d469f2de,75697cc8,f0f690b6,e1f86dff,3f2ca53d,907d4cf7,c8ff324e,8b4187ac,c9bb29c7) -,S(3f972b64,209f723e,99a6e7c4,a72072a0,2789d0aa,8a23d660,949ea417,7970809d,7a482428,7a6bfd9c,afc26e76,9a02c5ff,9a7c053e,e63f2342,b32a4f84,42e47d15) -,S(938ac0f,fa73364d,11df1ecc,4b84e3d1,c21ff85d,71f404df,e8daf4a,e889b0b4,a1c09ed3,d526b381,dee8820,eda06a10,4e968995,64cb604a,63fba74a,45be0312) -,S(5355ed75,2993e74c,275eb9ed,3bd34575,631c9b5a,64e99071,8311ec8a,f4e28bcc,bbb1007d,680aaaaf,ac10279f,600f1851,c8188547,3091a40,ddf7253c,fc6ad088) -,S(880e32ed,70ba76c6,d83bda46,a4340646,b033696f,ab62e457,4e989311,fbf277b7,76feb2cb,8d10d5e2,406763d5,f696686b,8dcdaaf,330e4e7c,623cc7a8,6e0410bc) -,S(daf778aa,a2755b68,2b8beec1,14b74e9c,857ac503,daad6bee,bd6d11f1,8f11aa8,1ed85c62,710d3017,9f0f3024,d6ed6976,e38325f0,92981c88,fd4982ee,98a5f428) -,S(e5c3e9dd,75633d27,d19c0a4f,f3533f80,9a60b95a,42c8c464,1cf7abda,8fb474dd,f1e56af6,5c5c087e,ab303699,f20bc9f,71b7b7fe,16332afb,2517b241,8dfb0dfc) -,S(5d403f34,ecdfd870,977f3bf2,ffb274c9,6859c20c,8cd7afd,d116837d,c0096973,6b5be47c,70246cc5,9781ba70,71764d72,2335c334,443e5e4a,5ba12939,d8f6aeb1) -,S(50ba053c,25511f71,b35b4caa,c990ab27,993bf034,f3e55f81,3896458b,5e246b12,d2f12a45,5c7a3170,67690399,3063dab0,9f8a22a2,bccbe5b8,8a7fa2bb,f2291f63) -,S(385a80ea,ee4aa9ed,a07898f0,b3658793,9f290622,399c3a00,b38bf02f,66629cf,a543320b,d72ac6e5,d750806d,6a90b8fb,8cfe4902,46991eb1,6e6a6974,befcd50) -,S(98610b9,904ede38,6e69de6c,3d40518e,eaa669a5,23620a9b,276e1996,bdedbef,907755a2,eb6aa100,d0cd0c89,25b5ff8f,b88f72d3,61d83315,c4ad0d94,8a06b581) -,S(83f10807,d9640d3b,dfc7b0d3,dcbbf6a2,19ae215b,4754f29e,d4579999,191b7fe8,f62d231b,5095d6d2,860e69c6,509de2c6,fe719e4a,fbc2b5e2,489a6f9a,7293364) -,S(51d22293,927335c6,2f82b028,52759fd1,e3f287fc,67b6059e,74dca17d,4fb1c246,b9b803a3,b5145b4d,188b909e,23c8b126,f7184bdd,3128587b,e05219df,6c63745d) -,S(be6a6342,e5783d43,d2691945,826c37c5,3e8cc24c,5a09fc70,3689def1,4f465006,81c718fc,3fc15279,da9efc14,13ddcfd8,81bc7e4b,1c36004c,2008dba2,7c7ef000) -,S(f21334d9,c36f1284,a4bb043b,58b27070,448681d9,a82ae81,a4e8f226,bc790036,44851,3a87fd30,453dcc1e,b21e293b,f5f143b8,2cf2708e,428f4753,8816eff2) -,S(1558c4e5,af34463f,810cb1f1,b73bd27e,932a832,9253e2cb,419eafae,c9730508,cb8cc650,25e14132,3663f3f4,1a75085c,6921bb37,428a149e,2dd1fe4d,f4c917f8) -,S(1853a32c,8f6020d8,1b4d3596,a88e3825,b575a4ed,99072e64,2e090a1a,665d71e2,8da2a31c,b170aea0,e364aedb,b1861fff,eaf26888,b29405e8,9e3ed982,a03a8367) -,S(ef585cbc,f0f03bec,21df60db,cfafa9dc,2da679b4,3bdd590b,8cc35388,cccd323d,2bc5e203,aff91f6d,38592e07,82813905,f02ccdba,1daa7acd,d93f6d80,78c2f296) -,S(3f4c2e37,e1ea68eb,befd9971,424b3c7b,1fa45864,e0d13471,a1476808,b2fd5c14,678990ab,3d283b3f,aaa665b0,4f329b51,51b9c17,b54385e3,30de36a4,7e0eeaa5) -,S(2b001b8a,d557ac4a,181cb20a,b3abf2ac,59fc9b10,20b5533b,621b4119,e421693a,fe4f3007,f8d19db1,73e6f8c3,48b2525,310a328d,2ca0c675,8fa29723,82c6b94a) -,S(6589d1dd,7d5a08ff,8deb5b10,81fb0ca3,79c90d27,58ba0bb9,8d05bc93,452cd229,82409480,ed842993,4bc8dca2,3e000fd5,fdc5475b,192bc7fa,a1179165,9a8149a9) -,S(c233fd0d,f5d3835b,8e855316,276a6a90,ab4377e5,a3a3a8a8,3b89f0f5,27950a6f,8fe8e0a8,775a9a43,12cfbac0,85aefe06,31468031,86b8b84f,49422392,b4f6f3e5) -,S(82731a85,2a848eee,d6ee3f57,f75a2bfa,a388670f,89f6f6e7,b65b13d0,764cc14a,c00c509a,307c5e87,f1b09688,38e34a21,1ffacc9b,8a7504c1,2080e4cd,39117583) -,S(e21387a0,e5d8b1b0,5aab5150,122942ec,c9dde3b5,53eac977,7eea6d0,6d2a50d,c74de509,f90d93df,343c920,74ac5dfc,fc81c95,93354349,bb2810dc,8db0ff83) -,S(180871fd,2fa443d9,c5b5c341,4d635b8e,92780fc1,6d04236a,bc9a49,5b9fdc25,d66c7150,6008f37a,422014a8,bbe025c6,1f25e636,e2778146,59985003,ab14d120) -,S(b5a9de7e,ed112a8c,1ef29a9a,31156b90,d64dff93,4d83fab4,b44d30e0,bccb2c42,5675a679,a81c3faf,3b0afe66,ef85721,30315ccf,b0ff3d91,130a71f4,3539db38) -,S(9acce472,61f1e50d,f42baf78,c05a5cf9,8ce5697b,6d3b4d,40d011fd,aee7d6,fb7c413c,40464c69,e5756830,4325a79e,6cb8c831,add29e0a,95f88feb,9507a05c) -,S(f80ab79b,7bef7712,2fc7bc4b,2193deed,916796e3,67d85100,a02cc0eb,8b574e5c,c6d4d03f,842d8b25,d9b5834e,d6cdcacc,3a1ac585,b5d22aa,c77019dd,1d5c8f6d) -,S(b431e355,cdb4230c,3005845e,f60b24d9,25d81448,ec161aee,faea1f98,bc9366a1,ebcdadd4,ae230a14,382ddb98,552b6e69,7aebace5,5cc7390e,f69d176d,da41c1cd) -,S(7aa60b9e,8c93a63,51eb686f,46dca4e6,efe56edf,6c2089c5,93f6a800,6e75f1fb,4c81e2,17700bf1,e053e389,2e33e694,cb424800,b4068c98,328f00ef,5fa0347e) -,S(1a88250b,3aa4243b,7441d1a4,da37b4dd,d304fbef,272f696b,a72e7610,1286b30b,625b9d05,57d3815b,e06d8cb0,f056a9be,b33b7658,f459b3fe,3fd5f4ab,69b7a473) -,S(5b524eeb,49fd558a,2d34db23,cb5dcee1,6c4ca47,1eba9966,82dedbc3,aa2b57c7,2d5c2c97,56b7ce1d,735b163d,56e02bdc,25c8b227,2bca2d5d,bf252906,bb8ae50c) -,S(ae60e777,6d9fbe79,d24cb8b1,f756098,191550d8,433bc7d1,8920584e,7676d2c5,430fe986,73772472,ca11be83,eefc8678,b76c36d4,346a311f,fff926fb,158d7784) -,S(323a5e3d,9e29f668,d460b081,a5dce6fb,53e8d730,9c42f105,ab4f812a,62efb9d4,2b457b3,69483f42,16656d1d,3b5ea9af,da6216a4,47661830,c2fa56be,804776ba) -,S(acd1b5b6,591e552c,864e612e,d69429b2,b3db8649,7a5962a2,a8b36511,7a7c1c9d,e6131fff,56f6900,926ba772,92526348,67544d25,1ebc4fa3,26562190,8e6e88b8) -,S(6b4e2c70,817852e0,2a26286b,155248ce,f2e61e60,84742cf1,14ebf74f,785b36f4,8400951c,7a529bdc,2007130d,1cd5297,7398f7fc,d66e5a1a,1e4e8644,e5b893df) -,S(c2b2c727,d67b0a46,1f44cb91,48c34744,4e6a375f,80a817c7,1517969f,8084ab31,fed64359,ebf37b0f,998aa251,9c281fd3,a52c47d4,89051718,82481fae,c36d5f59) -,S(3385eeda,b5b2bd94,f794609d,978a0f86,2ec56422,bda0ef71,2207ca1b,904f202e,2808d2af,1db8a8ee,1c5975aa,31a9f441,b12a2186,746a474b,4907bb71,603d7443) -,S(800f6cd7,f2cb437b,8470c292,3fab4786,edce15f0,d4c52a82,33519c07,14c803f2,981f2e3e,ad11aa0,cde06ca5,9b26028c,23e0a88c,ec397734,ad0152f4,d4a37056) -,S(73aa0bff,3a9f286f,d3c103c6,d7bb6caa,ebfaf4b7,614f1f32,4741c600,eeaa2f3b,30bc529,81a9b983,cb89fe73,dd8bce7c,a54a2e3c,4fde6846,701f1da5,18c6f7b1) -,S(9280fce6,ab5c13f6,80bfdfa9,c3e7612f,86380498,9bcf29ca,789169fb,a178f2c5,4b96ecdb,c5bc2e3b,2fd397b1,8f7f5bb7,aeb6a7bd,db0a3b23,3e74f7cd,ccae36bb) -,S(72055c4b,bb50b9ef,b589be16,270d12ea,9f438780,e5eccb81,7dbf69d,a66e03ca,aeaa257f,c30a77dd,58574693,51a8623d,985ad705,aa1fe3f9,8915a6c6,f6bc7cb) -,S(f0f3cfd0,c771e3db,ba687c7,3fa827cc,eb8e887,12abc8e0,3085d047,e7c1879f,2c612e7d,8b744c54,f8f0c4b3,24fe10a3,1bf8aa5c,cf6e2e20,eff98153,a4936b33) -,S(97c78b65,70b0f270,6fac8fe8,ea4376ac,d8b61177,e5e7b3ec,67a7af9b,e6f5dcfa,1aeb950c,fea95858,a97da765,c3cb5941,1334609b,347c4daa,1279d58f,3be14c3d) -,S(b39ffa1e,967e6fc3,d493a9de,48b077fa,4b7908f5,33a73eeb,9b5c9efe,9e509e69,f55f3951,81ac72cc,d618c00,71c817e3,f76c302f,11219e16,f3b40e75,ea65dc05) -,S(159b9f7a,5ff27c4d,1bc3fcc4,d91b160a,1b2a972,8b1e7fd1,7351c663,f8e7baaa,b0aaef6d,86c54ffa,eba1c7f0,d789fd41,5e60127d,578c2697,a8380b7c,a4c4360a) -,S(25810fd1,8d4a4b16,c7d07a62,b626fc45,6dff76ab,3c1361aa,f729f7f3,cb85e44c,f4052325,7794bd70,ad295526,ab4b8b00,9252dd5f,33578f44,2fcd2219,2f6a2d9b) -,S(27e20a4d,5860a328,c499864c,9075881,eab36291,2da641d,6e1934df,473352b2,c1598cf2,888cb50f,e270b490,503c11a7,d3822a2b,e86a7b,65cb9499,3b45203) -,S(483f454e,517a94e6,6708f465,ba217b60,6d684a68,4d9472dd,685f3bd1,341448a2,c13b3144,d93b9a36,45d23346,c5dcb70d,d338d06f,f0c22aa8,2ba68a61,7f9ad11f) -,S(4f47b2f6,31734aa6,5ae4c9a3,c1532f2,67ef068f,83a4f266,e2e0a59e,be04e6e5,58f1f34c,f11b9cb4,5d33ebcf,3edab72d,6824392e,dd547a27,c0134d66,58d99d2b) -,S(aa78eb7e,835ce84,b4f1774b,8e810cc0,d6f42a2b,11c44574,24fb6341,7797db07,39640139,d957d47c,59cc7541,d3f72e33,ee9ffc63,2171311b,cf493ea,185e743b) -,S(d2598985,83c00560,11dc0655,c37580b0,31a3f1f6,aa5f5944,17eb0ce8,cc033d49,3641c973,9de8818b,a294622a,2dabe172,b6a83006,4d04ed8b,c841d11a,5af24b08) -,S(4f023ba0,ecccb74f,56f38f87,7435907b,f2d2b85d,59f7ffaf,48712a48,55e26634,f80efc33,b15d5125,b8fc35ea,393b6c3f,a2ae094b,86a6ee95,bc48295f,b1a6a456) -,S(9c86f08b,48abd097,7bfe13cf,a15ac8be,8eda4128,f7c143c6,70bf7e2d,763a1589,11511f87,e9ecb88,39eff453,d29d4db2,17d4eeda,c8468a17,1a152f15,c1c2df45) -,S(3808718b,72e95cc8,fffaffce,cd57e269,c5e6ac77,69d8120e,9130d8b8,ee137576,f40ebdeb,cf5eb722,4dae59cf,8ed8b58c,c614a61a,9e3ccee,db789fd3,31ea728f) -,S(8defd15e,399492fc,71c80a1,3eda0244,eb349f47,5c7dfb42,55dfa752,fcdda3df,d3dfa778,4353d0c3,b4fb0d19,ffc39631,a01786ce,e3b0cc7f,f9e4c5f6,7bf7a771) -,S(8dac8d42,5ac1d07e,3a805248,798fade7,ed99f9d0,c324bd46,6eaa8aa7,dc24bf8a,f232fdb7,923234fc,d8b2f097,d354dd6e,62e9d926,20d28087,d6410b72,aaef8009) -,S(87ce6443,f3bce6de,287178b4,f243c3d1,e45d26fc,6f811d35,329cac04,7fa90e1b,a897019,62414ab4,c582799d,77edf3b0,f0af0d4,8f70e875,fac33e95,39724138) -,S(bfee6bfa,bf2fb77e,9eb60a3f,8b7775ba,124a21c8,741af3b,d22966c6,a8fdf08d,29a1c399,541e4bf1,7f26f215,52fc83ee,cd2e8be8,40b83fa6,9c9ce5d5,fbba76f7) -,S(c30fda5,b553a800,2341a553,7aff72b8,44873af,8381b41d,aef9af2b,5cc2bec1,5ce3eab5,87d88d64,fa44aafc,ce34046,8a96f76e,65dd562e,7d14153b,439fea6d) -,S(5e7151fd,594119d7,c5cadbf,e1b419f5,4d922607,728d70a0,f1dd4d8,3400ed97,6a8ceea5,a51d4a7d,62d36816,ecbdd75e,4c64ec96,6257820d,73bd9531,ea108917) -,S(a9c8eb0a,66cdd5f0,f33d0620,8525225b,e974af7a,b50d47c0,4bf690db,ec86100b,f209cb9d,898731f3,b02a24bc,ff290cd4,a4371e88,f3aeebf3,29c9e1b2,8b8e0a2f) -,S(955e79d7,93669150,471b1659,52ee6121,cb804373,5faf653b,9468511a,e3a2e439,68daafe3,2a9b67a0,10ea3bcc,1a56c7a0,2e82cddf,120e6826,1de0700b,cf930d06) -,S(22d27293,d3c1cc6a,5b3bc70b,3bb7e1d6,bef24805,3c8685fa,c192b409,dfa34a71,c74b44e3,4fc855b7,53c4e42e,740dbb59,4d5d76df,b39de389,e6c837e9,639b3357) -,S(d19fcece,f74b1767,4e9d91f7,1487aebf,70d46e8b,3a037835,b2f4e8c4,2137abc0,5b904bf6,3dca0981,3ce224f7,494ccba3,34ca9fe5,f365ca83,fe9adb6c,4adb7580) -,S(6aa1722a,adc74800,d6609113,6bc6a6a8,1723c36c,524a873f,2a437c91,c2336899,8e97004c,df495b4c,63164058,321549ce,3d9709d9,ed667c36,9a4f1ee2,d6319d07) -,S(79bd3623,9ee4d220,12d07262,e96ad186,b16e3b6b,720d052,f736f851,b0ea6efc,a4b43db,f568cda4,1dc972c7,1c7c92c3,6a31166f,ad6b80fe,42df4dbe,f418729e) -,S(b5e02b2c,146337b5,67583c5d,3690c0cf,a1c7d820,14028c9,e401182f,a4f16ce9,4b9646be,3facaa70,e793516f,a0e8a142,1a819ba6,718d26fb,938e2795,9069e0b2) -,S(8e33e271,de2deb4d,6444d64,387f790d,14a2b685,4b38857d,d05af743,7a7403a,d82d53a2,c7a4a1dc,eaa011bd,3e0ceb0,e08d73ff,fe9d71f,c913d6e2,89ecc429) -,S(4ffef442,77dba780,e5769b73,feda37da,abd6ef6,2f5ec36b,74593ca,4c19c2f5,a8a30857,378aa0ab,9ef6162c,fbb09f9b,796755bd,67bf9d69,4a186813,d392f854) -,S(878b652a,633805c8,b58b0334,11b9246f,f7e42ed6,ecba6bde,fb737126,e9f57368,2cfbeb3e,d691158c,d3ae71f0,b4a41d42,148c9711,d274820a,d541efc1,56e85836) -,S(ef9a6a15,aee2aed1,46b99ee6,a79acbc1,a0aa0b2f,1b082783,dd40b106,9deb415e,9909e2ba,7fd53514,a1bc4480,2b49c7aa,cffd9cda,19c54d82,6d9bd08e,49e97240) -,S(d5c248d4,1551d230,60835885,5db0ce8e,c7814e18,c2d548fc,dcfac207,645bf37,f9c5e89e,7bf01f82,8cb78c88,c14d50a8,3cbeb45f,82daa9cb,3c3804c1,15a36f05) -,S(edbf25cc,a526157d,9676e614,81455682,6dad0c0f,96ec289,f2c5919f,57227d1a,6845488,be056456,4a833c13,70d37257,d0ca701e,f6e574c7,409dae02,ee99554d) -,S(5c12026f,b8e2e376,2521f5cf,cf9286b,14be80b0,dfcf378b,26fe6ea5,4ccf09bb,3d98d5ef,4e2c6528,7950154d,581c9a44,94b81a50,40ba9047,1bfa6758,66daa596) -,S(c27e6243,5056055d,614dcef7,f67338c7,ae728bd4,af3970a0,b434d2b2,e48e2d6d,76b586fc,703cf946,f78839ee,bcd28c56,9e372d97,856333ce,d82137aa,7d8525c9) -,S(a298c704,5140186b,4d424e8a,f98ee604,7f67603f,ab14a7e7,b96daede,51abaf8a,4dc70158,2a1b1935,4a5b430d,b4a0c21c,463b779e,ba72f108,5d7d638d,68108fda) -,S(e1fce957,82dae8b0,ac204fb1,9496a332,fdf40014,88ebaf07,3a62f33e,192013c4,40517ee5,d5786ff9,6aa2b50a,a77a10d5,e8ca6439,44f308a4,a264e367,1dd02f4c) -,S(e719bfc,5f06b800,8e4e49bb,62361544,1a2b0c42,f673f3a2,1e139bfc,b097d6d,f0c83c1d,83f5df68,a1e3929e,e18c4945,d14e2c33,4f9165e1,a0a462c2,aefd7822) -,S(77766a4b,a9d8cd62,840b1127,7e697dba,dc27c50,d9c8e35a,17f4c38b,50ad0a4e,5b3a2ad9,448327ba,22265ac,86c190bc,60b7586e,6f6e4554,b26b69ce,231b6431) -,S(f237721f,6215a855,f8660cda,41063690,4f2c9dd7,6260c292,597f28e4,348514b4,109daa1c,187b9f9c,ecae8c6d,33cb9874,46f5ade9,d57b3651,bccb9338,1acfef79) -,S(9408f5d5,e8891a1a,3cc4e7a8,a50dbc83,97517b3b,6c5af3b9,f1953f09,a67b3e08,1b82f212,c32f1ae9,c95f87b9,5ced2bf,ca33e954,32d9eb90,ed879ec9,59691555) -,S(b2837655,11707926,c9f214f1,3e90675f,883649c8,8f1660f4,c4f9f6c1,552a7064,89553739,15be8962,e6f03ca4,5bd5516f,be6ee041,519c4131,829b0bd7,6d1abfcf) -,S(ce42ba00,36b5f54a,4ed2a9dc,b6c0d29f,98641331,3f92f9c1,43767bfe,4b78f4a9,6e547292,cf35baf4,768c9179,2f706bfb,39b757d8,2452a802,4a7bd37f,e3a048d4) -,S(bb3da2a0,1a063a97,bec9325e,8d4af420,d3942bbc,42f0807d,8e9edce2,eccbcc59,7c28e7aa,bc39907f,ef58a19e,cd6e7b2e,25d6eb00,8da14d9d,5c559d27,fad70b32) -,S(25d84c3c,97f3a074,ea76f620,d6fb2691,dd3e9592,6de8eacf,5392c0de,36c490ee,5e0e7745,88c8a9b,7b91ffb,1ad6fd27,4153096c,9e759540,16f73a43,16d5651a) -,S(8baa3bfd,ca256f18,2e55a01d,e7c07617,7649942b,e743b4a7,faf39446,84d5765b,6147e897,8bbe15cd,171c2816,4730b211,587bfe7d,7e71811,7f308b80,d30506f1) -,S(507d6a0a,5b7d0385,11c65dea,8024c706,4d3b6b9b,287c7192,74c69797,21f5170,139f1647,70ea83ae,47ea8141,c3ae32bb,c12793d0,ce30fb37,2dc3adad,7f7bf5d3) -,S(7c6992f7,a059c5be,99b7354b,10fc217c,e45620f3,b4ff30d6,d640fd3a,26bbd846,964474e,fa63641c,2aa7062d,7139fbec,1f64e6a0,50e1ad03,2741a0e3,b5e0bee6) -,S(f62832b0,1bf65b23,14850750,9ea6f157,3d5e3317,bfb0a38f,cfcc6692,5a698bf2,d7314810,7b8fdfd7,3f6ce6f8,84f375bd,1546cc3b,8c75840d,3668c2a6,54c1ec95) -,S(aed21cab,d8e4ec36,2b4e2091,3be3c7c4,594f628a,cccca657,deff8b9c,6bd1ebad,f800ef3,833c7ffa,a8ade1ac,2f41d456,b880a205,60251dfd,f9cdd672,bb7100f8) -,S(46de78a9,343a9a41,6b91b877,aca94252,9e0ba8ca,b6c01f66,e06cdfdb,714bf405,c1441252,4f3ea73e,e12809c6,f19184d9,81f30b87,8df8bf6,6c89d98b,ed4d2bcf) -,S(2832b5b8,ab82e932,5356ae19,3043b99b,ba4b6591,a750a174,a6303b42,54bd41bc,c0363e03,3f59f149,23ece534,cb86695,a8275224,f490849e,249e63f7,34aba440) -,S(5b57c502,4b5c1621,77cabe39,b0f36bda,d85bd04,2736c7ff,9395f0c4,cbe43f9a,842407,dc0c0473,f1bf57b9,b35d84ed,b282ed4c,7adccc06,8530c8c1,bd20766c) -,S(b384da70,8063758e,825bf821,196b4a9c,814c45d8,a9edbaf3,dac4cbb1,c1c2f103,e6e661df,6400cc40,74f92596,590757fb,aa237515,af30ed13,df30befd,230fa325) -,S(36ffd991,563e448a,9b0a5da9,61a5466a,82a5b672,15ec8f8,e7300c5a,5c9a5e1c,97067835,fc17d47e,94187320,84d722a5,d1a742d6,4b513b6,32aed897,bb961c) -,S(8367e452,57c20367,e4e60ecc,33adcd87,5b9d142c,c6c362e7,f5aab34a,ed89d81c,fc7ff090,3ffab26e,d38a9e74,df43819e,b77ce2d5,bbdcf27a,f1f3bf19,948be121) -,S(f6ce47e4,8cc9296f,b40539e2,41238658,4719fb9,d4b1ad17,9c98969b,dcb0564b,368d2b6a,fe5edc0b,6f159017,5cd192ae,b524a606,7800aa60,930d60a,87950e1c) -,S(438c23e4,bedaa6f0,527d20c2,a725645f,194ccb58,8ff9eac6,5091da7b,f9fae013,54620a30,c7218257,dbdc93b5,3722a213,e28dc6bf,f8e48b45,6d6131a6,92ff15f8) -,S(1cf672f8,cc9434bf,7ace8722,85db5017,a1fa1dab,2eec7fbc,84e8492d,86bee7bd,d6d23d25,8bb4dda5,957ccced,b767cefd,8932b511,e2479018,16734bc5,b5cafdcc) -,S(47464e12,b0fa29b6,6e9cd157,4f7155fd,94305263,8af28bf4,4325a23f,3e1a2861,209a41d5,3bcdf566,5e966e80,84869a83,a2468db0,a1b19e56,81da864d,a2b05141) -,S(a9adfba1,c884c904,e6877a0a,9bbf73ae,c4ee223,e0b02ff8,717c075a,6aa964a2,ab16101d,a7bbc35c,73f371d4,afeb527e,b2d809a0,8487a36c,6cfae404,83f79dc8) -,S(2932fede,10600312,5ac983dd,659ecf95,824421ae,5f417f97,d3101c6f,c58edcbe,8601a743,e666156b,f2e34fe0,6f4cb11d,2df54fe1,7c842176,e1075423,dd76d727) -,S(5abf5528,2f87ad04,202b62c5,8ff7440c,64f9ba39,e6989df3,e31d665a,73a50216,71dc4e16,f2705c02,2ca1b37,edc5ce0,610b6f57,282d69c5,d3269295,5a1fabf) -,S(419495d,9a121cad,41887fc2,82c2c7e6,f359cbc,d24093ec,57399c3d,a801843a,9152e197,40295094,11afefc7,83990732,d5e6617c,d8e389d2,956536aa,f73e0c31) -,S(fca38482,ea2be49c,3c27979a,5acbb158,a902bc4e,226f7eae,4165ab7a,29fbc3af,1260735e,5fe62664,90a35f0f,7296c441,bad50a75,7b00e34f,28856a6d,cf46f5f4) -,S(bcf05123,3d703688,aca13530,55bc3ab2,d499ec40,8c912de1,4b7af456,55065d06,f32657f1,645690b,35484e63,a3456885,c16d4991,7670e71d,5f5cb65f,a5fb8bf9) -,S(4e70b42f,6391b424,b159cf74,f5fc96b2,68bf6cc4,a26658e4,79dd8a4b,8e9a92e1,8ba78811,1af31c06,77b24fa4,4b6ce356,66c595b2,3fe4fd36,591b33f7,e53b3688) -,S(3fe853d7,331c60ea,c213703c,a7628dc1,3cdb83f3,8a25ce6e,1be84f0d,e921742f,fb7dbb77,c2c6dc13,6f596154,f24dd3,f27b5125,9b60476d,b230e54,5ddca5d6) -,S(d803377f,c3cadd40,a2aa810,4e97641,ca42f582,3ccf65f5,ee726349,f648b9be,6357b84f,281a8080,54ab7fbf,ecc113ac,aeed2118,5ad12900,d824719e,8fd6fe99) -,S(5ddfdc7b,6f9e7162,2b7128e,77fa5ed2,90a05114,d6d8b845,94106c9e,70bebe1,23eaced,fa1efb7b,fae74c81,a1d03066,714b6dd9,1198e1e9,d5911ee4,55cd76ad) -,S(5f150243,c964948f,e91353e6,b12d167b,7913b46e,d7214411,5bc4cd4a,3b6f7dd5,36abc949,7a2fd102,14991e2,ba360c4f,b18147cd,955754e5,71cdd4d9,b8af903f) -,S(24b4fc97,5b0c4429,7a4cc89c,2b127eff,539f022,61544e14,97969bac,50942647,bd3e3fdf,54ad07d8,5faf8881,9014a77b,11d96f2c,a43cb8f9,a823a257,9eb5c207) -,S(a020eb35,5556b5fc,9de5ba2b,28644187,f11b18ea,ae61e76e,1dcce55c,e42202e0,9a71ea1f,1ad2f457,16b667c0,a982e2b,9765ac6e,beb71880,27e9059d,56639f66) -,S(60b79064,f7173eac,60531de5,961c47e3,8a224c78,ccd58a0f,86f6afda,e1f37a68,3ad04a4c,f6a47d6d,6b9fcbae,d8b54a7d,3437e4e3,627256de,cfc5f38c,490786b7) -,S(835cf1f2,b57d1e54,4ac2d915,9c8e3fdf,d2e233b5,d1109685,1777b7e3,a1f7d60b,7d23dd35,136edb13,bbbf7733,9e1c6e01,a7112f95,7c929b16,1665ca07,f6a84b31) -,S(faf74350,1f1edad5,2e1d8ad,e4b319bb,606cd7de,3188cdca,b1d39527,837f77ed,dbbeb0bd,bffb580e,4b9a0fa0,39b7acff,fbcd11b,85751476,16d48bdf,fe21bcc9) -,S(396c6fc3,e072bae2,3e7f74ed,f121271d,44091a5,d3b2a762,a39dd77,d2de938,5de522f8,a143544d,4cc49940,96b8f54e,9fb0e076,f46aa479,9e99d162,de6fa667) -,S(f8ab940,ad8df2ca,1c2622f8,8ef20c,ae8e605c,1e43b684,881147ee,d44ab88,99fe5281,fa7427ce,c9857163,f804c429,630d28f5,33e451e0,4063e70d,ddbff796) -,S(a6202868,af6dfffc,1e122219,a829c374,8197af4c,95901e78,75841b46,bd772367,2607a20b,c82a49c1,4fa54eb6,f8d68d8f,fe9c4fc4,d83b0e4d,145f7bab,5e9af45) -,S(b12d1993,49a98616,90764484,23a4fdbc,cfbced5f,b76a2bda,4d7c4984,7067e41e,a66dd4e0,ac6c8ab1,29045eb3,f7014449,73fdd555,7001b7ec,99c33d,c2d75e31) -,S(8dc8f55,b4990f5f,c6cd3b97,b1938304,9ae0a734,5cdc9c64,fd67bdc2,15eb3b3c,1be7457d,62cc8fd8,cbb54cc3,88722f4a,c00ce438,c847c2f5,fa641119,e5435d83) -,S(2c0b7337,d1db9e4b,7d521c4b,36351f65,f128643d,add0c53b,1b6d619c,658feeec,e8a27b9c,eb7c1219,f7bdae62,c07cee15,ef765b95,3b082d9a,d8b99005,b39bad53) -,S(891fb4a2,50100689,a48a0d1d,22414ab2,b17ad692,bb5f0d0e,66d06c93,da3bab35,41685166,cdf43c13,be93c03b,c347f3c8,52d06c0e,661a4c7c,cb53e24,e7260f6) -,S(4a3379b1,511c440f,e7213729,de668ef0,39fbccb6,1f5bbb02,ed99ed3b,69ca1738,b12a3dc2,39e9191d,a89d75ee,db44ce88,17b3bf03,d4172b00,39d1464c,a3ac0f6f) -,S(b8b2a7c8,54936bfa,62da360f,83bf8d65,7dc58e3c,1c8780d2,2c57061a,5f815521,8f922c0b,7719362c,25ac7001,252a89ba,1cd4412c,17c2b021,c065a3d5,f6a2d15b) -,S(9066fe19,d1dc52e5,7a9341d,77cf73a8,2fb56ab6,22c97a7f,f0191247,db9624fb,23d19b43,6ec3c575,d81d4929,eb6789a4,c281f5bc,abbc896,2153e7d4,711baf50) -,S(bf9ab14c,19c9e9b1,ca1a18df,2b5b73ee,9f32c8de,6e6757c2,b0534d75,7cced8ec,ec969923,3c3863de,aa72418,837a3af7,85e79375,d5bc91dd,481f174,e9759c0) -,S(68b2686f,9c654a02,225b7e69,e8eb7aaf,78c65686,e885b1af,10265e35,316f9d03,1d3d7504,846826bd,8554d407,739272ab,b6b407d6,f4f7419a,f284b81b,f14da9c3) -,S(20dc8385,5251a21a,94c989d3,92c9f36a,4d3bf669,bf7bda7d,e0427003,710bf2fa,217e6ff,713d329f,f9080c4b,3608c877,975d6794,5623e24a,974760f0,95aa749f) -,S(f0beb49b,555d998c,a39859bf,8c59184a,5c822e46,9a875568,1689a1ca,b5fd0368,e0e05ae7,a23ddf94,ba33b3b3,a75d3f4,2e8ff7f0,160c32f5,3bd08b40,72664aac) -,S(8f1aa973,270ff9eb,a41ad8ab,f2cf4c44,16ddc1ca,dc8a62cf,aab5a3b5,c4a0ee57,90aa3660,e3409b17,a86a441f,12f6eba0,2bd6bbb0,2b9a0a87,71e30a6,595920ec) -,S(c71eb135,278dc147,60cca847,a934b880,fecd43a8,aac9dfb,41382283,928a9957,41667f77,485281b8,89307ad5,decc7f6f,51d23ac4,7e71b299,a9d8715e,b6003804) -,S(e900726e,50d66a9f,37d09df5,d4965c5c,fa904d3d,bba1d180,b0fed651,bec41c81,d520aa30,db036f40,b34e64f2,cdc7d7b3,117f7725,786e9d5a,921c5f09,71028e39) -,S(940ab0af,a15952a9,ba3a6d6b,720efde6,58d72dd7,4f87cc3b,edae63b6,123fa38,fec6d747,6f788a19,b85e443a,a49116e1,6e5061f0,53c40702,f8765d28,f3bfcbcd) -,S(9a13de6d,643e9866,4df3ce9d,412c5ce6,a03ba46a,640c6be,8b62e70c,a8c76949,42388296,6c2d8d87,8b4c914d,4bc6cbc9,a4601630,2eb6a499,6103953,6926dd5e) -,S(438429b2,b31129d9,4a86b149,7d7f62e9,b76d6a5d,bde09d6f,256f83ba,76c577c3,e4360186,a7229be1,b33cb600,be833bdb,b2398e98,7c46c6cd,2e44f932,5cbc1c7d) -,S(3f63b25d,66d472e5,fac7b524,e4300e97,c8bb59be,6a3a8f01,8c1677c6,96d02605,4587042,158e19cd,2bd19bbe,5cff2c69,d9971aa2,fbdf649d,44c95f3b,50ca39dd) -,S(661fdf7,17c7a520,a384f90b,98dedef0,47afe5ed,6cfbd3d1,e1735c5a,bb8cc0c5,bd9a243a,b43c0e19,2592f00e,a52f820f,b83b7433,b1d96549,d9970293,7da80abd) -,S(b9c1bb26,daac6af7,d0c27c36,7ea2d4c8,c999d7c,75bc58cc,279c5f89,5ab951ce,a4d3bf34,a42b86bb,7c66c5b2,eed5d7f1,b872d17b,b58c938a,767b87eb,1b140f4e) -,S(cf5ac4a0,fc6cd9d8,50aaf473,3efd2bb9,7d9b23ec,bab5d099,9b11bfa0,b127e8fa,44926316,c37f1718,7fa94fe,3a62caf5,ad465d77,fd484287,2caf1605,f91070ec) -,S(aa52b2af,ab8da32e,3b882c57,ff0a34fb,749caaa1,b3c29b74,13c86471,beb3b422,4b562728,4a7be595,1b68df35,e320252f,73326084,16c60244,ac4e3ecc,c0859ce) -,S(610f22e,b3aa08d0,a9f2909c,546896bc,7926b056,7987217a,d347f183,4868211c,a52e190d,f35fc4b3,19571e6,166eda3d,2dbf637b,c27746ea,c1bc3552,4819e6bb) -,S(13f24c3,a485a58c,e0454330,79512796,db65f15a,4265fb44,acc3cc34,c51a6d80,faccbfb6,18e069ff,3cdc4327,cf807366,f07976d,b24fae61,1a44984c,7f3bc3b) -,S(15cebea8,49279b29,cb0112e6,922c5a85,caeb18fb,415cebdf,92285d9d,a0eb0f24,23e5ccfe,158ff9bd,539af7ed,4a77b1c1,c36de452,8d0c0d05,821e89f8,e075d833) -,S(2605a18e,fb7d5367,dc41b1d6,24d61a,cf92e0c8,96f29a5,5f2dc872,4d97f6,8d6a6774,f111b7ec,dc58ae51,80ad6fd2,fd6d674c,9402e2f4,f944bd50,5e66d375) -,S(e588e272,a78756f3,7fa36d6c,d35b362a,25cd0513,3694b56c,33d0b05c,be7f9995,15beb983,20b84296,9b8715c6,ad23e53e,115425c0,d071917,66e56ffd,5472fbb7) -,S(80032522,f264edc5,b6b205cb,f79ca7e,3a02cc39,93458b6c,cb98750d,bd6b46a5,479c92f4,fb4e1eba,98f8b93b,5aa9725e,fd2c1de8,d4c3d043,bca7183b,851a44a8) -,S(950c040e,e1a581b5,70501308,a21287e7,94b525b7,f916d3f3,c166a2fa,1641bfaa,e43db20e,911d70a6,9f171725,f760237a,52441a88,dc385a75,1e4ef1db,b738ea71) -,S(e899ff36,423fee57,2e70aeca,db8bc0f5,a634b9be,282dd875,9db5500a,86c391fa,7ed97b0,dfe6b68e,26710034,f87a911,88611790,cb18a790,a0248c7c,b43a9bd1) -,S(d236688f,c206b7a,8f8ce5c7,66e19fb8,6a7415d2,9c57845e,8332a5cb,d8a1a51b,72f2359f,e3d54a60,fe6d6508,5183b525,d5098887,55219113,adb05c2c,656ec9e9) -,S(8d3d7c71,da4b2f24,83e458c5,85c628f5,430eab5f,ddc2686a,e94e2fa2,119dcccf,33c408e4,7948f20c,bd79c22a,d647ff1e,1f435c03,1f594aad,82778f58,1f61178f) -,S(320f137a,e8918199,51a542ba,5d1063fb,fee4b750,c56168a5,87d7fd9b,b72651a9,b840546a,e2a4e1ef,32275a02,153bf003,8603698,a8c5e232,6795bcf3,d3c402c5) -,S(9e8affce,3fe6b259,f4568607,2d46401a,7546c87f,9a46e0de,8ce577c6,1881352c,d0ea3701,d83b7f7c,260ebaf0,97236525,af8639f6,c53ecf92,73e77bd4,c29d02f1) -,S(5df465b8,1d353987,293c915e,a24121ef,daf70ff4,9ad2bf53,9bec72b3,c61eef64,3206c5ff,5ae4c841,58c193d,40f46083,8b38047c,f33c3e54,38541a7a,d5e690af) -,S(999cd326,a18c350b,f4861d48,826ba3c5,1312bb39,886a064d,6e1465d4,8ef28f58,2cd8ab2a,d6dccdf6,7998e662,99551608,a9fceab0,be884b0d,d418911d,c8b1ef12) -,S(81d8fcee,574d9c16,fa2ba6f4,255460cb,479a6667,4761b4cd,c0ab026b,6bce163b,594e7f34,f5897a6a,3b79a996,f5a69814,3cf771fc,fd7c8ca6,38cb4ac5,98673143) -,S(9e83d724,b9ac73be,f932b42d,56f85183,85839c9e,c953a0dd,4da6d843,d096d278,f8b18cab,fed05acb,89efda95,ac496ec5,d3a000,a4a1d689,a1afa5e2,30c88869) -,S(98ba38b1,3b443c08,aecb1f64,73b2d901,908ec33b,35baa317,64f91144,3e320c3e,343f61d7,fc2232fb,f5d2f972,e6f42f49,d8ece7a,3434a0a4,4df1d602,3f99b84f) -,S(2092ea5a,9adf5eec,5a7a9488,6e970671,5822447b,e6c35285,de704806,52a875ec,ddfb72eb,52382722,a94facc8,e2616661,95a7e9c2,6594228f,304adc7b,ea4e7f35) -,S(f9ee909a,8f45a05e,ac77bce4,ebc97410,c044c639,95a1de76,5b9304c2,2eeb75a,861031ba,93f5b0e8,473e50fd,2aeaf13e,3a39c0d3,7e2e9d51,a41ee4ee,1301705e) -,S(a13878e2,3bc55a7c,b342dfc0,2eea9bf9,5c676e27,c63e8603,c75ce535,35df101c,35c0ced0,3d4bb091,92a2f83,3d3e81a6,233f0585,35c72ed0,1bfff82,7b108427) -,S(e8ec81d2,cd32dfd8,7284cfce,9d80c03,b863a7f8,3a71865d,34f7b1b6,104ae3e4,60be9b77,ee12dd7f,f532b01a,f517bfc9,1d24c4e8,b0865e4e,c6e27227,417648b) -,S(f07cb255,1529dc43,3470b18f,e4e06390,d48e9898,69b9a97a,6642b898,1cf35b60,bd46eb77,6d74633d,59b4b941,2e2355a9,c6e85421,59513d2b,a3297a6,c223b550) -,S(39bce423,dcfda9f0,a97189ae,a60b836,42becd3f,2f2cbdd8,2fe884da,baaf7f51,c1599caa,4b71219e,74490312,7303ec91,f3430be8,14979a2b,2db78bb1,ea2c8e4d) -,S(6da611cb,d51db814,18b3de21,13c9e4ff,58142f67,cf2d8ec8,e0fd105,1e9ad3cf,6bc2f048,3250f654,fdbd494e,bb03480e,f7fe5568,2e19cd70,4d178ff3,41e4b7f) -,S(cedb9c03,8d2e0eb9,8a4a5e8e,fa7e95c5,f4e13a47,79470c70,9a3c9fbb,8b1aed8a,79a2fd31,de42d8bc,820d5d56,ed084f40,46804fa5,f7f5e8fe,eca6ad4d,859a0d40) -,S(7d895498,6d1106d0,32f40458,f6c41fe6,25393f84,d00ded8a,3a07a107,5ae3d82,5d4fb6cf,ff1c594b,61aa117c,7e0ade0e,edd110c2,b2109866,ee7d586a,1a6d0d61) -,S(a4f29162,737043af,eb1e2606,93ecec60,851aaf50,c6e9daa1,75a00c43,d7dc3df7,beebfce8,fb764b15,38fabb20,145aaed3,92265d7b,c4628846,b2726821,c79c4439) -,S(b6389dac,de4ccb08,ec0ce964,e689bbcc,e0ba8165,6680c0a2,9cb162f0,f91cab70,e440c7db,d2d02474,17b2826d,28e31fe7,9ee836a7,eefdacdd,679040ca,50303529) -,S(72ce6dac,f752c36f,978ac2d6,aeef37f5,ae4ee016,999ccb49,27b8aefb,f6fcc9e1,ce6ac297,bbd84403,d60c6d4d,5e01027e,8ad38acd,e796bbc6,7c45f10e,d79bbca6) -,S(efad336f,cfd7425a,560931fa,a6bc50c1,4fb3e5ad,f8ad175,31b13846,6c255f06,3fb784f4,eeee9a11,ec7ab559,71817163,9eab6b09,4419203b,2b422e8f,e15a82c0) -,S(f98d4a2d,4bb2166,7c74bd1f,393ca57,22002c6c,f382b49c,2895deb2,34eaae3,9875e31f,7e3778a8,34750763,c6147cba,97a26f8a,d669e69e,9a36cc45,b56fd148) -,S(768cf74d,2bc24233,2c5eea34,2ac13ed1,2b0d161e,65876eaf,b0b89460,c934183f,42337607,e55b4d7a,f86e9f72,dd06a550,af083b32,e72e6265,4ba00fa7,a2fdc34e) -,S(ac26f3b0,1d05c625,915ec27a,aa916d0b,d34cfb6e,22525c59,9791274d,a5beff7b,e36760ac,89b61681,d1913bcb,1ebeb199,a3005576,b8bde54a,42fcecdf,e94f4045) -,S(dadd4181,741a0be2,e665045e,1b042a3a,fcd9050d,a08d1285,21298f34,1f74fbac,6cf46fe0,da78dd04,261e4e2c,863574e7,f6a4dfbc,a902802b,8056e00c,e4a84f60) -,S(e5651598,ce9e6a86,2fb139ed,143f1b73,2c4e1eea,91a88f82,a6fd0ab9,1a86a3e8,bb421336,69ab6c10,109723d8,ff4d5f6c,770fd8a,d569a21a,9e9efdb2,f1f1ac98) -,S(f26f791e,b4f0f596,39b69b45,401ee3ab,2d47a2b7,dcc3d65,de9e48ae,270f5b02,22e34b25,1fe5bbf2,5183c799,ea45757c,2693c591,633a84fb,e1a9bc0b,470ff699) -,S(a50cf10b,95612f48,7a9da048,a84dd8a3,2d2bec22,9db798ac,19fde68e,623da9da,50107d3c,a76a264,1db9f9f4,7cd60598,ce345ecd,cc3de888,e4c81553,bdcc576) -,S(c74883b9,2736c1b,d5f86a5c,1817cb9b,e917e5ab,5ec5cc10,a1197f1b,a45c13c,e03c43bc,e7393cff,d53e73b,60ea2759,d1c2bd55,c2b7a32e,847f4bd1,2c8beedc) -,S(a3437d0,1741ed88,bb05c00f,629e2c8d,be7cada4,dd002e9c,98dfe800,9e1c0a9,a627e05a,257fcabd,1fda00af,a4d3eef8,fc268e67,bb41c9e,d2160713,847bca1c) -,S(a6cc4988,f179bab4,de98ba89,530686fc,90c00c77,4a3f093,8329ffa3,99c8312d,f4eba473,7db25a79,29bcad7c,11346471,bbba86ef,4f611643,712ff475,9d70b6df) -,S(efb34a8,f5778d57,b3333077,6ca1abe3,9e680183,13936f24,da1aca,70b84dbe,a94a216e,fc53fa98,320878e7,167536ba,7e5845ca,149b2595,2f029878,7f428d3f) -,S(139846d8,1385e6bb,b23914ef,487fb9ab,19ec3b8,3fa45a94,a2c5fbd6,fcdfa07a,4fb7cc4e,599b10cd,a99f6aff,28dfda0b,62d837b2,e8c96aa0,9c34cbc6,acfce099) -,S(660923af,98ba567a,83df6eea,ab53ea62,49c2090a,13299bb7,a538cdab,adf2a101,b28b58ca,b1a29722,699890ee,8462f440,ee2a5686,9715478d,4460f0d8,8c94bd29) -,S(f18092b5,8c7517de,3f389d31,f1a6345a,d2f86bd0,c1dc9a98,d3e03890,f52be3c6,a83e7a04,91484ed7,7dc27697,33b0321c,440ca763,2a36c6d0,7e8a9afd,68f9c906) -,S(e8d0aa0d,1b2c540f,38a6a6e2,5b5fb295,7b700467,648cff74,bfee1138,81d0ab75,a324cbbe,52055c1b,d0cc3f29,88a80982,1abfc0cb,feaa56e9,f19bb8ab,d314409a) -,S(2586a0c0,230a0743,f9613df,51f7463e,1d8ee72d,503025f3,c7d2dfc4,6f526c1a,a29735a1,eb2b470d,43c7b469,4850f5c3,ce9b1da2,47406653,ede03ac0,9816c735) -,S(217cfa88,8d826d46,c31bb2d2,7dd7c8f5,8be68254,e42c0e48,a12cab42,677dffd8,4d5d9c30,9ff0fb15,35f9901,7af91ded,34179c57,f48131a0,6d96b6a,c01ac4ce) -,S(4ea65934,71aa3b8f,9e6791eb,37cfd67,943af3bf,100d7ccb,8203a353,1aedf4c0,feed9ac4,19a302c4,58047403,5c95e997,ded8a534,c88beca5,6c12984,84b7b4c5) -,S(974b828b,51026aa4,ea522150,c497eebc,7d7759f2,c9645f7d,4faac24d,18c7a1ae,c0369da0,c3087336,2566f344,ca81f261,65cd3a03,fcb05093,96d18fed,4faa9d26) -,S(d9815b79,d572d7a5,94dc8ae9,3cf45b36,99bb4544,ed1d5755,529c7096,9c978186,9fcebacb,f5181954,ac4ea24f,508fa67f,5b6c20d8,64ed53ec,d67e358a,e75241fa) -,S(52712597,d9bd4e7,cbd506f1,bd65aac1,478208bd,f9f6ad38,efd2b30e,b8368837,52eca996,ba2cecad,9a0911d1,65368010,68bbf0c1,12d6dd79,aef23262,8b3df18e) -,S(d94231af,d890f5f9,ef70e1fe,e8a8f4e8,ed2fc89e,2b8ad818,6af55de8,449abf6d,26592b6e,f0789218,273475fc,32d865cb,84278ff4,8cd0de27,e0646549,219e2867) -,S(64851231,7a69d956,3b3a99d4,b763eb9a,b661f7b0,714d34bf,e5328a4d,a99a7d90,eb20ba33,515040e3,6fa02088,5a3e9216,1e06d3b3,78122fb4,af4920a3,51d46bc6) -,S(d0a4b11b,ef662f17,98f413a5,fc062567,70df9edf,ee00217,79c3811c,ef68a8c2,d4bb9920,18e16945,c38ef5c9,9ab39eeb,748b7a63,ff4d4dbe,8b329f74,dd70b9cd) -,S(1d89b886,c4b24868,1fbe103d,dcbd76b1,dcf54637,3bd5249b,3dc07f06,985802b6,a339ccca,aacd1057,7e36056b,a3a70c6a,a7885a45,42bcdf30,30d0939f,6369535d) -,S(b6cecdd5,936343e4,f136682f,a38ba0b7,9dbab223,beb0b6c0,10a75cb2,e4dbb256,2935c053,87dd87a2,5bda5d1f,ed813666,5f77d12e,8242dd58,3ba8db03,319f7be8) -,S(84b244e0,a0cad847,35ca6c5f,bf581968,40f1b491,98682c4,28aea50,bf2f8e24,62e28e8c,7df80b11,f5713087,ee3a5d8b,148c8e62,da0de1ba,d8289ac8,861f7a71) -,S(f95eccff,2a908028,39436610,2e377c41,66433159,43feb6d1,638df6c1,cc114d1a,bd0da83f,1a0306cd,b8d1b9ea,189856ee,56d16e81,61b4f9ca,7de38d2b,e558eba2) -,S(7c4cedfd,3e613de4,af2ccd25,59a2dd23,2a1e6335,e410d327,27fef321,d10f55e3,331f2109,d9d00536,c697f73c,672a660d,11d4827d,41306696,cdc224e,e7d7b1d8) -,S(235c2e38,1bf2d829,e4b918de,435e276,f88af866,ed31a1c3,4b9f7203,a0269713,50dcdf0d,2671092e,e7c48614,44eaa87a,815a1304,4600fd0f,f26104ef,a0dbf929) -,S(2a961cd0,9ab50975,517ca488,d1c4a388,cdf2686,c5dde923,76128683,ea07cd73,85c91076,b2ee46d2,3cc0f7fd,e7654723,84f84c2e,edd7552d,d7f93be9,2398abe5) -,S(958bc491,f0afb8cb,8713f591,cbf183f7,e00c4775,93d1b51,a628f40e,4cfd65e3,bf5be339,fa21dfe4,9113e026,af0761a1,b2a09a7a,ae8f6eef,92d50c6a,89a65b3) -,S(6e960ca3,7b5b7abf,99f5a2e2,46b7e953,adb5ccc,6424e73d,dc865bd8,3d5f78fd,53ad4bd1,d5e9643f,5f2df612,ea16fcc8,dcc4b0b2,9ccd5a81,bd659b35,6a5e0e15) -,S(d7ac920e,9272bbad,dd961525,7d91d6a8,e747e4a7,a48ddb5a,8b2ece8f,f0d05871,6381b9fc,c37bac5e,38c0b96d,c098c3,9d4c7620,61b66dc4,adf66e24,f0c87ed8) -,S(9b0803b,1de95706,ec123844,ebe941ae,4481c12f,f2d9c078,b6c1d531,5d730609,160cf3d6,b12afdfc,eac2ed01,fe4b801c,5a5ff0bb,13cc3ef2,f5f0962a,6b3fb1b0) -,S(5d50746e,5b74e006,9dce0153,aba04216,991bd509,f022f3ea,689553bc,a4c5fd88,b0fb205f,d2a14b1b,bdba2e48,429c92b6,99cb336f,b6ed0e58,9276118b,6b259ff8) -,S(e1bc2669,fa27629c,92708748,36008c2d,ef4483ab,c686ecf0,bbd01a85,fcbe04ff,6fb7af71,83c0921,6173fd43,5b3a1b2b,15e8b149,3bed8e78,3d409f84,cd95ecf) -,S(cfc9081c,b5a893db,40c51979,7dfa1cf2,f36ac620,cf7017a2,fe90dccb,d8bfbf78,26a88d23,50772fc3,2f377c15,a9bf817c,db321d1a,55c4d659,b5f29ae6,96a69ac2) -,S(54d9c9d,12bd68c5,3961246d,b98ed78c,cd8ad158,8458d4b0,5fad9df4,2229bb9b,b5e97c31,1dec2259,630c961f,ed33d7d4,f8de7005,849225eb,a4549d76,de1cbff6) -,S(8a914ee6,7e9d6619,d00f1924,8735c7b2,bfb11eaa,61fe42e8,d64b5a53,43057dff,1b91e1da,3374da49,8bc2f018,c2a6fa51,99c51846,a2f59b05,a6311ac3,1bc040c8) -,S(d4b81177,3e641dfa,bc704fba,e9ab0ab8,aa2f4c42,fbd23b03,a0b0595,d0240522,ac30ce3b,1ea4a14f,4a5bd364,20f40df1,cf2e6835,17107b8,ce6fbe05,665cc726) -,S(b810a787,c232357c,bb82c351,79249f64,6f3c8e2e,72e0e004,36226670,14780ba9,54364034,1078dd7f,216bac76,9abc8467,4a422c30,f1b7aef7,6a2dbbb0,158319e2) -,S(d71f88ce,dc738ef7,1ad691ea,c3a7eed0,d29c762d,8ec7ce0d,14e72d3f,f534a833,a47cce83,1aaaadae,a2d9d0d9,7b4c5125,97c1b514,95c3aad9,d2a4e716,cfbcd99) -,S(170cf31d,4cac628e,139d9d89,662ce5e1,1ad7092c,cc6c6174,96c99d71,6d147ffc,4fb3b894,e741f585,15e8baa,addf3119,adf6c4ee,695253a4,6f9a5dec,cc6d77a5) -,S(8e7692a3,b1275e80,38ccbf66,ecb9a55b,bfd48d49,4085b4d3,1729a644,ecc316af,f339c1d3,af07525e,26500665,ce66a91a,4fc0bfa6,b8a46411,34cab540,68c504b1) -,S(5d1ff338,3dda5e81,32c47002,ee2b77ce,a07ca869,e7684d40,a27cbefa,4aca891a,a1adb3ac,b0decbdb,6772e62e,74c4516,fe843833,8d2979cf,5b091801,bf5fbb8b) -,S(d566cfdd,a9dec66b,ddf2605d,a37ad558,375e1c5c,5f5403eb,d75ff6ec,3c2b8af7,13e2232c,78586da9,741598bb,25a90a4c,b6007bd7,bfb75ed8,427ade0e,619c78bd) -,S(cbd708f9,cc713af1,999ae74b,2b9ee3db,3cb85bce,249c5e33,764997d0,2fd96493,f01a1d6c,4ca9b0b8,9337a5af,889d8dd9,c264f4bf,6b8066d6,55cf9267,684cb2cb) -,S(fee1ece4,e8ac73c8,8220bea2,153800f3,e8d049b8,f89053f4,ad4b5ba3,f0ed0fe2,9b5208ea,17c80640,a353354a,7cf42f6a,f9763db0,bdb0954f,53d56a2e,ea26aad6) -,S(c6aafa66,de444853,8d7a6c3a,fcb35a8d,db916f33,14c15dbb,79c48bc9,46ee843f,8a61c6b6,7fc590f7,bc81a761,7a6e24fa,34c49d5b,30b11bfa,7cdaf3bf,d1505b1b) -,S(ac351560,83d91f7e,4898551e,7666bbce,dcbe21ff,f005ef1e,a866781,d9aac415,d709d997,77109afb,28c318fb,eeec8a27,5577410b,8da6d494,5ac7d660,1334483d) -,S(a89c2616,7c024b4,81455d19,93ac04f5,7a212e34,95066ef9,21968f72,3d914e18,551d3662,6127866c,77df092f,5ed8dab1,3569ce68,433de199,ac8219ee,13a3c1ab) -,S(9951831d,b58499ea,e94018d8,cfb9162e,b045b95a,fd246a3a,72e8808d,1ca3f06b,fe39aeec,b9d5f867,d5827146,fb384808,81696ea1,5b0d1188,fd487b16,d9e4d773) -,S(b71e17e0,14564447,955be26c,61ecebc6,8615e2e9,37cd2e8c,78d26922,681fba96,ebcfddf1,d21fb8cb,95e3cb22,4efe9553,1a6c5ba9,cc92bdc4,3011c50b,63b9e3bf) -,S(e170f81e,dbdd9ff6,d460ef6a,1c3d4bcb,2fe89fed,4e6742c2,2d683ffc,15914074,93f110ee,f971cac,8ce206e3,df6f9caf,801fa7eb,c7df14d2,d6f67e72,ab96e67f) -,S(431a5547,318d05c5,5ecf04ed,a1fabbb1,4ac8dd8a,47dccc73,acf5d5c8,1ec104f2,3e3188ad,7b141a36,4afa1f04,57ca827a,7a6f1f70,75ca8dea,6fd08bf2,bfa779e7) -,S(299e6a6e,e1587523,2be26ce4,a1f80cb1,3c193291,7f0b5eec,383ffec2,62203394,5dbb70ed,3ad4a211,bfc8e8bf,4c00a055,23c9b3e4,ed3790c9,3bb2a77e,5301575) -,S(66db488f,f2b58869,b2fb5f78,61e7f825,bc99ac9b,ea02b59f,b0978c9c,c38934ee,ab76e112,b51c83f8,b10e997,2f6866c4,6040e7ef,eb14817f,c316b730,e8ae6a5f) -,S(1259856b,66980d52,bb3912fa,78ad5b70,54c812b5,fed402a1,c3c8247d,26274932,ead7cd3f,c67895c7,edfe0557,d5681bc2,d70dfcbb,870c7c22,45d458c7,f2150383) -,S(502c8614,cbb0f3dc,caa5272f,dd252c7c,4269968c,efebecf9,102745df,fdf1cf00,711bc688,7e4e356,fd9d0695,16af0a38,1b2f4500,6487154c,10b90995,3bc53c3c) -,S(e051193c,323c6403,f69c1073,47b6b7fd,f43acdec,17c00c42,2249bcc7,aa8d6fd,2102c271,ce428ee6,16d1d2bc,f25c2630,c574d9b1,87f8b9f1,c85117e3,8a560455) -,S(c9187bae,d768d32,29fd90c1,5c3b37e7,abe7c58,b538acb8,ae0741,adf1dc46,c130d443,f9ebba4a,197d0252,615ac29d,5714f6dc,f27fc0f8,d7547335,89c92c0f) -,S(5b08567e,b9f3b3ee,2b03ae70,1c6b0641,23dba4d4,4e8297a1,6eaec8d9,e90fe897,ad071c15,9079c91a,cdee9c72,6e8f4cbb,914d4b4b,750fed92,aa81a987,a90c27c9) -,S(ae5b648a,c5817a86,cfb06a26,d62691ab,8a9cc554,d0eaa86f,839f4a51,b43ba7cc,1ea8ab0d,b665c22a,ab0a48c3,da17c629,66e75212,a6fe9983,d5e925d,432db311) -,S(3b9bacd0,a092856d,98eea5c5,ccc9abb4,4f2e0d3,27e578f0,42102148,890178d2,b681e88e,9603ba1c,57b628d7,ea929ae0,b79be447,f181a491,1fdc65df,21bd5052) -,S(524df580,a74066da,d522f827,95e415ab,f6dfbf7a,1c1f6d7e,e8d05a86,4659fef4,3facc728,5f3bc1e1,a6fc210c,ad302ef1,9c72c5f9,e358b9c1,ed2aba72,2652f35f) -,S(2e0637f2,ade775c4,87d09a38,3480b875,599a34ea,7fc70cdf,f6ed309d,450e4363,e3c6eb08,7e2f4e49,cc78e903,e4ad55f3,1aafb7ee,ada72369,6da8a0a0,f764738e) -,S(f7fec6ad,beafbd3b,e413fb33,587b9427,3f785728,226f764b,bda6130b,aa0cc483,f646a974,8eb457c7,fc8fefd8,e63b976b,dd42093a,e59fc544,c66531d1,9e08c68d) -,S(75f94ce0,6af64c43,2b6c95b1,2d892dc8,cd6eb497,4d826299,29ad8bc4,8a3608be,bf8716d0,a2b7906a,69316b32,21ec0076,6e32c892,2c7be6c6,22e8877b,b1958a29) -,S(410296de,5e0df3cb,c4f039f,cc869090,f62e07e9,d3011043,31bdc1cc,f3fb4d85,e963579c,a314dd96,ab8a82ff,86265b82,da74267f,c861f96c,383f72ed,3ffecfa0) -,S(cc824eac,5f5e16b,2f7c1703,d97da67b,69b4e698,16cfbb23,cbdffe00,d73ffa05,17c30da6,9f414ef9,5dc58218,27c7880f,d18c6f1a,92afaaa8,b8cf10a3,353e8abb) -,S(acc1b0ef,4d26ed8c,d78f0b3f,d3177077,d2074b64,fa5d8d03,a83ff113,7e6e5820,6cce44c6,8519ae91,19d2a80,4f8fbeed,4fcd24d0,169e8000,11150c8d,9c3ce6c3) -,S(1cb3076e,ccce1d9b,774bccf,4318b921,583c2b8e,31877825,7c2fc71b,c90da922,2a2f276c,58605d,82a17dfd,3ecdc5a2,a6372df2,cf25bb04,c628748e,4ce373cc) -,S(6efda451,2a22f49b,587ea975,9e5a400,8cb3a521,7a38b978,3d5825aa,84fe13f2,11d44ed5,6dfe2fb3,1ff2a54a,de5a2a5b,60673cfd,bcbd5039,54a94758,878e2424) -,S(47f69619,aef4378b,5cc931ec,da8fd996,e2fcf1cd,17de9cdd,51b30c3b,9dbf0858,149556a1,9776e3d6,da457af2,a4d70d66,d2fa28a,c33abee9,bf890894,7cb5e274) -,S(dd3d8e1e,97f5dd5d,539032c5,13a19e26,8b2eaebc,1a47cd4f,8ff48335,794d28e4,7968bc00,20f6a83a,a973d7c6,382ebf33,c2233bb,34be9c2,e0ff9eaa,4c467e83) -,S(2bd454ee,a19d3a6c,be55737c,d3cb4b32,7de2a2b7,50535f91,97aad2b6,65e16d78,a70b0f0,d6a1278f,34271c66,7ad40feb,9f7c6248,87e3f754,9c1f1fd7,129f7f99) -,S(8cfe75bb,2a7e74b4,4da035b2,9a26784e,915462df,13ac2d91,4733184,f5a5ee0,648ffc56,bdc87c86,4f6226d1,c9245540,b65c2da2,7fdadca1,eeff2e24,6607cd1e) -,S(5eff34ae,19c462cb,c2fdab83,24b57bc8,5e046a68,4f112f6e,665b3255,65724d36,198fb5bb,9db347ff,c2289629,d2e01051,d551e783,47c6a6b0,ccfcde15,a04d68a4) -,S(9aa54554,f3673b08,e36db624,47631774,a2c51bb8,1f18aa61,426639f,78f92b91,8744a3ad,4a6e7404,d2e22faf,272b50bd,1d167b46,5f25c6fa,75c8d784,61384806) -,S(4b837575,8cfb5970,dfc7463c,5df06ebb,ac88a2a8,b9d7565a,955cb53a,5ff259e0,87591d42,bda1a53f,6e474396,a1233df6,ed70766a,ab7aaaa9,9171a5e4,fa8df208) -,S(5d4b74b4,9134f90e,673f5a57,959c7cef,c49dc725,85734428,226cc5ef,76428bb1,1b2a8910,f466ee15,abe6bf3f,100d8da0,cdc2f6bb,f19c3cfc,b1f07a0f,bed89425) -,S(d50be2c0,c55244ce,5d93bafa,f62ee680,2d475441,7ab9c2b2,5702a309,57cad2d8,fe207e4c,6ee89ab4,c0185461,7eaa5de4,5a4dc0f2,bc4544e,f241cd5c,162f583) -,S(bb0f61ce,8e0eb384,64e48915,5bf985aa,f93bbff1,416db2e9,a1da034e,1075bff1,13a715,2ddeb0df,30ea1032,cbcb08ef,4e6b0561,31474412,631f6fbf,b77b7d0e) -,S(3ce6bddb,473f01b2,170e41fb,22fc5efa,63e22b9e,14d9bd22,88632bf8,4ddcb2f5,43086057,f4b3d298,426b7308,110dc52e,9a84268f,1bac1edf,8d47a25a,ace0922e) -,S(ffdfb14a,ef1680bf,c90b5490,c7cdb75e,bbcbbff1,a56c3c85,bd37460b,b38f81aa,f3045def,2f1f19e,232880d0,e948b5a5,24f228c7,3bbcca54,7c216ee1,eaf4af0d) -,S(1ac1f2e1,9ab4264d,8126eb60,a2330aee,c828d102,507ac0fe,d59fa4c0,8223172c,7636a4bc,339486af,b215e3a8,f80d8f02,d8fae063,81b4e7f5,133f1936,d8e18bf8) -,S(52534c0a,740e89a,6142957a,a20f2339,b1a1a6b6,7e6c9a2,2d6661ec,adec228e,cf6fe6ba,fe41c899,c1ec2fa5,d884fafa,e1a31835,ae8022f1,365a97cf,3261b669) -,S(40920285,7cd22c2c,78cdccd6,137d32b1,4f36f2c,964a278d,5b9f6462,651b09eb,40c94f73,a5fa3e3f,66dfef1b,f4f16091,f6b7738e,b8a865fb,3bde12c4,2d031d0d) -,S(8b1d3c33,4b9ccdb2,14aac6e4,e840db16,25a5b3c2,4069d9e7,c81bc51,9b029289,114fd464,2acf9599,1fd65898,57822277,8020769f,145f86e5,630d6db5,5e23e853) -,S(ae14de60,b7c7f13a,59c6bbd2,64162dc,8a6055e6,3d3460fd,7e473979,f4a242bd,8b960489,cdb5a333,a14463e2,376f2113,afccfee7,afa00ef1,6cac6a3e,4c65a412) -,S(f37f1c40,99c95e6c,3e8d4e39,5dfddbaf,b8153948,137de420,788386e,2ed3e3d7,1f290080,82f6ad34,b2283d76,9cf76577,a564411,4f51af5,310c0a3,b3fb3606) -,S(1fb07fae,9636889c,34441c1d,3c2496bc,a13f8933,666d05df,aa53ecb2,1b017a84,128189c9,3931576a,c4b68934,b7ff551b,58e6da46,fa97fcb7,b8df8c9c,637753c0) -,S(44d1eb54,e112eced,480ea2b5,1ba22ba7,2afb0721,d0d6b715,52bd9728,4815f3cc,a6e13b28,574c526f,12673e02,ed7938fa,ea1855b7,d5b6e88e,3c3a9b2a,f2ed7043) -,S(6980972e,5732b875,7fe311cf,f76f7bd0,ec94918a,759a7cbf,d8795645,a103238e,7b9fe832,4ffb9143,21776b24,a92fa09a,ac4a0fce,17c5bc26,2d2eb063,63d26a5e) -,S(6a3a8c9d,405bb1e4,de59639c,4f6406a1,a8566a62,9d85b79b,f7030255,50efcfa3,3e8abae8,7b22d04a,8fdb408e,196b47a4,2e0f59eb,9d51924d,ce8de66,cac038ba) -,S(ff3108d4,1598464a,bf5844c4,dbcfa027,bfb6804c,946c3683,1da390b6,4412ed0b,805565e3,3ee1d089,5c6abe85,77054648,11f5d4d0,219cb515,dc072d47,cbd0a317) -,S(ee4f76a,2f8549ab,3e134e53,335dcb5b,49972750,180491bb,2139324e,95517d73,6bd90167,22402b11,68989e89,9c942767,8307367d,8a29075c,8fe81049,7071a838) -,S(c21175cb,1ca958f,36a3b720,5cbaba0c,230c6305,8cd09966,ac78f51a,4c53e0a4,6a2183a6,7a7ca0af,256a0ecd,2c085d81,585a02eb,2ffe6a44,ea923688,cc72bf51) -,S(2d5e4c08,a9a0b398,34e46e39,e7cab91b,953141c0,c5f2d292,c409cbf3,9a37d6fc,7569b9c5,31a331fa,9234f37,e9005ed0,4b512721,dc4ef054,d6164046,75c6e15e) -,S(6302c041,bfbbeb09,cc012408,631765f1,5d573b67,6b799c26,ef7c2a4c,bb15dbc3,32a8f20f,67ce42a0,ac4ddfed,d0932e91,a1e51488,49e463f,915af082,7e491025) -,S(3e61516c,198de08e,f7dc9cfb,89ef9b94,5b6c67cc,2deab08c,a3b36612,5934e2d,1effbbf7,4d5f7104,f7784944,70f62784,5692f3ed,48e4dbe,e956e063,37520d9) -,S(a008bab2,d7d134d2,4ab35a37,8f330521,b8989219,108b05a7,d8aab0ae,e542fe30,77a377ec,903c06e5,463ec2fd,e9c05e43,f5454aea,82b99de6,be09fe31,51b475a1) -,S(7782ff48,b928962a,950f42b8,2e43017,28711467,16f22f8,c389917e,a624005f,78f23e49,38a03e0c,ad1b766d,b9bafe30,8ad2c9cf,5b22bc18,c78c8898,fb608c15) -,S(233b4a78,c26ab44f,d1019d64,8c896eea,f6ffbe71,8cfefc20,d20676f8,27ddcfc2,de508436,d976df90,487ddc1a,48284cdd,f553d342,2e0977b5,18f3ed9e,773b655c) -,S(8014aa29,6eed493,d83d7aed,2d8c3342,3f7a4623,295f2a07,92c5de0c,71b8bb0e,dc58729d,f2a5bc9b,1170caba,4856a9e1,695f39af,81a1e444,f3e6dd55,f583d92) -,S(8a01e90b,233dae71,1bb050ce,7bc61c8c,60882aea,ebead2c1,b284ab59,dbbbdfce,580ed75d,c9e3693e,92c06cc4,12c95a77,b34b72ef,20a51cf4,ca4ddbad,7691fdb0) -,S(50a2349,24a29158,70e6372d,582ba07f,a569881a,96bd1a4,4cbb9232,1ae733b4,6943c220,a97701d4,a79d8e2f,a446fce3,aa21d00e,2f7cfcde,3edabcda,678cc751) -,S(cbf49357,8c96744f,7ab07bd6,182640ee,b51b8f6d,a8a655ce,cbd2087a,eeaa6d83,4d1b36f4,5711db99,404bdb1c,9484a04d,29e79fa5,87d051d5,e75f07c4,ee8d4bf0) -,S(737b3d75,e4edd296,8d164c2e,828b31d8,7c63d11f,fa4ebd89,ad59ba71,8a8efe38,ec7f7ba1,8aa8e515,4527002e,edc8327a,ff1ebf6d,d3877439,e7c822b5,35f31586) -,S(29cb2864,251939ae,6c7f46d6,9d7b4416,8812e0c5,9aaa8b8b,b7e22ffc,ac38813a,c3ec280a,7c98b2c5,c96d77c8,b410ff1b,b5f1eb51,debd38f0,528bb73a,eca2e6e9) -,S(1858aa59,24282fbd,e44dffa2,5197954f,f3668954,24741d35,2c9594fc,5e28fe9d,a0e891d6,b0a69fab,9fbd7879,a7e4ab4c,be50b1d4,4be76485,96fec281,d2d4bd46) -,S(72ce7c58,1a420eaf,67bae314,d4f092e9,26c1378d,d346c4fc,2a9e9174,862eb75c,2329177a,5a9c3e0c,f6e236ae,30858bbb,8bec121f,f7462ff3,6284bde0,7425ae1c) -,S(34c1ca5e,5dfab6d2,4abdcb83,9ddf9bc,a3f9dcbd,ecc315,17bd6f46,af112903,93f6fead,c931cc97,37c4aeb,6a589a08,80088a24,eb49a1a2,7aca807b,22a1f803) -,S(7c5ac4a,80af5867,f803100c,cee3d676,8d348b47,9ce26243,284ba0dd,24392c36,a4468964,903be647,31fdb23d,1ea7ab84,a3201cfe,ab585b86,3370ea40,66fc5828) -,S(be2ddd13,244c7728,1a98851c,8683ff7d,b57bf3d,a746cb35,e594b7ec,4c363caa,adb75939,af8a2cf,1cf3e5b9,2bc7ba65,8c45ea85,47959f25,7dfe4592,3e580fa2) -,S(6dee1f6a,3b3befdc,a4a44471,d62dfd9f,7f7b222b,819979b7,901a1764,8ec13806,5d9e8501,4fa5f6ff,f8c0356c,eb013122,1a9a2431,f641ab6,af3b9999,5c2e5651) -,S(15f264e6,8e2c8ed7,490355b3,a7b11512,c764386b,f6bafc31,80ee6fe7,9de68c19,90574d26,302bf408,ef9053fd,371cf29b,c41291ab,a76ab74e,ddf3f8c5,70326aba) -,S(3d7cfbe9,4cc890c,ea592b78,5a984c8d,6d4c5e7b,183f3666,df9805e,be9c91a3,d55cddd4,4ea7065a,f8f51694,f6a84b54,42b30b48,e7630d12,6827dfe5,e7f62808) -,S(54388bf9,d7951dc,7ab5dd3e,74971201,1ec637b0,7febee14,45b1dcd9,9c3a1e10,17b36788,25dc2a5f,9bc8738b,3f560d23,725f99c2,a9d6fdcf,6fbeff54,aae5a547) -,S(3c229fdd,9a0080a5,948a0d2c,c9281794,425327c5,52063c94,be5f0197,6a088313,34975795,a84f83b4,af883d12,c373c505,192f0a71,fed21d8d,3a8dbb8d,2a926a1c) -,S(b612bb6e,e14659a6,e1691f36,8fa8d7ad,1974e74e,36f1ab26,15705271,27c63210,5948c5d,d623cdf1,f9477733,dd5e8eaa,5240817,e8e08dc2,23b6072c,a4df5bb4) -,S(ec56e585,54470dd4,28341ed3,e900e33b,ae381e42,2efb3d64,d2edefe0,7b05f613,ecd7f151,acf6e308,dfff2bd6,578bce76,86effe0c,d3b156d9,df8f66cf,295e9c45) -,S(1bef3ca,85ff9f8f,bd80c8ba,f9b15b26,a565eeaf,e4d4f08f,25ee748f,fc11f80d,fe0260bb,96be497b,a194b892,71bc8989,125f0a0a,de88b135,272c5683,f92914f9) -,S(1bdbac4a,522b68e2,a90e4265,3d2bf4ad,c4b27e5,a2ebb251,68a083e9,9107c20a,4d60e326,3ede7fa0,10467b9,d2e8b206,5b09e127,e3fba9e,3d228439,50d63ea1) -,S(e9032f9a,567ab8da,551e0f8b,1b2c2c22,6e601b7f,e894b837,3bd9eaad,3662fc84,ac563e6,47d21af3,a0cb0a49,dafde0f1,21d60994,8dcb4000,64e3196d,74eb70e9) -,S(7ce746ec,44af748,a5508044,f56e3467,a9608deb,c8a051a9,fda907c3,8f79c75,8f0879c1,3166bd23,be7bbb80,46f3c019,2c6b8fa0,52fad7d5,40640fd5,f2aa426a) -,S(e0d52789,19de6d1c,a0929856,46cd3200,68862dcb,ef369fc9,6c6de4c,bb59eecd,98f4679d,b4ebdd90,a4f54791,29740bd5,f46680f1,d3ebfce8,8cda2946,ca886b20) -,S(c6a245cd,cf1f4b58,4400a4d4,82f2088a,e28c8b85,641c1f18,a13aea,7e5ca397,d306dbb9,f8f2cb09,958ff944,ab5e6cd1,cb11eca8,33021bf3,605e6768,961ac628) -,S(ff956c8d,9710f082,a1f34ace,c99987fe,4ade0919,4a0deb06,a1b286e7,3695c910,fabec52b,866afd46,1fe8c832,fd8a9375,a8086aec,b0e2e39f,b7823d0c,13bcc306) -,S(549dda4a,d1a604c,d0f44fe4,5c4dc276,5cef1216,6f4accc7,3ff12152,26c23af0,71e3afc0,e05ba826,36eede7,1abb15e1,166fec97,562c4381,a33f765e,100631ef) -,S(66d3df09,21573cc,e69896e8,2dd91f9d,6070dd12,edc21723,2077e644,9e776416,93981613,59a2ee3e,d9429dd3,eaf058bc,9ccf1c9,ea931ebc,25ff279d,5bb46d5d) -,S(61bd3dbc,9426386,9c53ede5,a5c4f186,8a4d7a82,fae1be7,37b702f5,79e4f8d9,8c056a47,e27d4f49,2c9ddf54,efa48c,502aee81,e2336caa,c1b572b4,e082e780) -,S(8a6d8b46,4a31daa9,2702f784,9148db1c,4ef20c76,fa67c006,47d6f3b9,80178f4e,d1f406ee,e4087601,96c82f9e,38205147,c31309a1,93bf4d8c,cfe67cba,ae8f7407) -,S(e2b60e93,99eb8441,700aa90e,1edd981d,37893b42,5acf6b1b,809fd1e4,922e573e,68a0c65f,e394829a,8ae09dc0,ab35d789,bd8a38ad,800e9ed,63513eea,4e19f7af) -,S(4c76030f,e85cfc92,64f16cad,99dfa541,fc23b8c7,2b558574,ac6f26cd,d4f55e85,44b352d8,9a31b4ec,c8f9a574,51855f7d,e98c63aa,98aec090,2d959be8,a12b7bb6) -,S(dcba96a3,59103c35,aa2c9ef,538c13a0,2f0e8997,3663d580,fe454762,5fbaed2e,af9e205f,727698a,de9f91bd,75bfb73c,b13053d2,db2d83de,b4d14c22,176544b4) -,S(fd0497d8,f75fff9a,cbfd3e03,6c9edc73,e682427f,e9b66a43,3b5b2b31,f2dc7883,d23014b6,9c8d1077,ab3fb2fc,c0bde4a9,44576289,896de135,9c0badf,fcd62d79) -,S(5bb401bb,b38e413,43d1b779,54e83f9e,e705009a,eb8a1077,542cc6ed,edf48040,431fccb5,acec1391,f68ea628,378e3ca8,ca944573,ecfa5e,e7a82bf8,82599c14) -,S(1fa96a4f,f9cc6ad8,b2741c38,b35c377e,3acac704,67bc5d20,a262db5b,48bb283b,c3448c92,ffc65afc,f1eaf7f1,f9e149eb,6404dcc7,1b222ac8,bfca8feb,eeb963eb) -,S(9534aef,1ae551d2,7a638453,171d0a63,697ea420,2fec8f11,61432291,642f86ea,cd0c943c,38837dd0,33d48a4e,ca13e96f,46fd7f21,2cbff849,6432aac0,ef729591) -,S(ea72afed,43300390,bc98d08f,3aa4ff4a,138440bf,1a8f8b7,b57032a0,d01b8ceb,e174dd8c,3692cc2,9ca856a4,4eae7e94,af4fb044,85172809,25ea66d2,d858663e) -,S(39593534,3ca2523a,603801f2,abf3a1d3,16569862,35d79fa9,a01f86d4,5c122327,acd3e3e9,2cd76dc8,551cbf0e,94475125,42a5b887,ac6c975b,45d2e000,9953dd96) -,S(d57b2a2a,375e5a0f,6967d4b5,3dfbb51b,4f74eff8,72742a3f,246e3e09,ec2d4721,12d6f848,4d107ec3,10ec2091,3482781d,c0aeeb94,71ae7b03,6a0d2551,d3ed306) -,S(9f2dfc5,1b99eef6,e6c781a,fe0135d5,fc5def8f,d520119c,59bbaaf6,442f1082,8f20962,fd273048,fa3ca6e4,ea96fe0d,7ad1d758,99e25a77,e0f8b56e,5b20dd0d) -,S(b1c30bc6,f030c913,49b36c1f,9c0deda1,afa58776,58c5a16a,9352c1bd,229884b,f8a459d1,6e77888d,cd5c63d1,8a2e28cb,5563e727,f53b59f1,939390c6,1eecdfc3) -,S(8a663e7,40cad237,12dad6f9,1bb5d266,30542933,853e02eb,665e198d,a5c6e53b,e206b399,51175d15,daccf711,63b0918c,786a8fe,2077812,c0c1eee6,bb5c1e99) -,S(2b0956cb,e0ca91ee,f44fac0a,76cc0b00,5f4a5ae8,27e63696,fe1aa8b4,a92941a1,a31e6fa8,dd454eaf,90ee1e11,62627e3,3f84b8fe,da29f423,ddf2a962,386cffd2) -#endif -#if WINDOW_G > 13 -,S(e0144151,7a2ac970,eb6381df,7e11fb4c,6b009980,6a0d330,d5429126,e662c3bd,8238ce9b,a691c80c,21563934,18d18dbf,aeb3fd34,48863a1e,7f4ba360,408dfcee) -,S(be3213e,8b062f33,caf16c53,5a0b666,f344e0d7,1e28aeba,8b215a3,7ec86c37,552523ba,eaca38a4,cd795683,852a2643,550fb83d,d1db0adc,3f1b29c9,7d51cd1f) -,S(623393b6,bfbfbd64,fc7aa1db,9e58e274,1c18eb6d,b5eb30ab,c4fe167e,a9e8ff2b,7c0e4174,f0fd5bf2,a025e316,fa3b7b97,1339a197,b52b0b50,bad4dfe,34e42cd3) -,S(dadeb702,dd0a1e87,669eb624,b8cf40bd,bffe79aa,8afab26f,bc6215b1,dcfe97a,930890ca,e4c29b41,2d660acb,8cd39bca,5a522599,a1ab0bb4,8fbc38df,17253490) -,S(b528d3b7,83179b82,bb1c9cfe,c26184cd,ac98ad5,8e253c13,627fb778,c9362f33,63203af,1545122a,63940676,ba2d18a1,aa902e08,8bb444f0,47c2bd52,db8babab) -,S(2ff223e0,93986e22,ae418a5c,804e9e81,7a4de562,d7436e0,2d025ab7,11734a6a,c5c8d188,ec9cda19,bda76d8a,97838ab7,81990475,d4a00096,5efa79c0,100f678) -,S(cb8731d5,e1e53c9,ccfd2c39,3c8ab1cd,9ec839f6,99fc712f,f946e74b,99eb1742,cd2f9df8,38fec504,dd125248,92ce8a4,a9db3848,e487076d,8c18e53c,f6d19fb5) -,S(1377ac45,d776a5cb,76ec265a,af272690,6dac52dd,be987799,36bb1271,e0cf4a2e,a4b3330d,d5954932,d5a7a818,7d9493e0,25ab2155,d4ed0d4,f34aca1e,c2a04670) -,S(984b9bf2,f140c75f,e03489bd,88041faa,22fbac73,7ac10724,c511a253,641a5ccd,c474f639,9733eecb,a750ea82,ac4d50c7,d82f4c9a,942a2bb5,90b1431f,c8d14ff3) -,S(4b8fd000,74f57cf9,b135d56a,c002bf99,d5050479,7298cc4d,857960d7,afbdcb06,7c044103,1df0f6f7,721937a4,c60cf76c,95560ee9,4c6d097e,3a8e37b3,34c703bf) -,S(57316653,68412236,619250b2,58bd0ddb,34fc751b,8becc0b6,60585683,218b6079,d1d56e4f,30f01c57,48972898,b8afe142,16f8335b,e3a39c37,da64050a,91652904) -,S(c9a00197,a0ff16f2,fbf2cb59,767d43f4,60737367,4f2bbbd2,53c7220f,db69f286,177c6783,d739117c,1de074b0,c605cabc,6b4dfeed,a531f4e4,9cc518,40142f0b) -,S(e23416da,91df23a9,db161618,579b3008,c87b9ef5,7ee8bff6,45eec6ce,a61881cb,e556417f,84043691,e7ec82e0,e1718296,e42fbcf4,a3de0137,93772dd5,70b8da15) -,S(9f96e3f2,369d753c,e6614c45,77bd8a9,14293eee,8a749c1e,3b0e2955,638e9ad8,f5cd1268,1567a4da,71650d10,e413e0eb,9b01a396,e529cff6,b494b2b9,a21ddff1) -,S(48657ba4,b24b0123,cd54317d,de6a3245,ae488078,5ba43d5f,1d94fbf6,b9301fd2,191edec0,6eb53781,2813ca77,2a9021b0,dd4931a0,929a7e36,a4a8c66f,aef0d890) -,S(67b322e9,d72e864d,8cb15511,11402d7a,c6c858c8,77832d4,e0187e69,6a36f24a,cfeb12c2,6b58bf15,3bf87058,c5faa833,e15c867,f7f9a208,c3dfdf3a,c7f6946a) -,S(42e8068,542bdd98,fcce8925,52002db,c545ba13,16082d40,fbde06f0,a44ded15,1645a9b0,c1f33cf5,27364915,8c4f261d,a1ee814e,7aac6402,bf644451,bfc4aae5) -,S(8ee7dce1,339c50dd,55619107,9bbac005,3e058cca,4a8c8e30,7588c105,fe90d4c7,ffbd0af4,8aae8279,2cda6170,5dbe9fe0,98e102ff,1e6f11d2,b4669a81,6ec9d5f9) -,S(abc9504,12926a71,6adaaaf2,7b209216,37a935f0,cc66eece,55978a82,1fa368e6,72e54935,e9b461e7,9fb75c48,4dae4fd2,155a4a48,d3a467c9,624c5f6d,71f79203) -,S(bd250320,81e0e9b5,3b00568d,40378fcc,fd72fd8d,783f2f3b,433ddd1b,a6976ba8,5adb8bdb,85855498,994ca879,717b8e7a,e8c4c87d,29d6a1ca,4c3c6395,6c3ceb39) -,S(b4fb262,fbeee84e,49ae9167,7e7aa0d9,b31609e0,48888740,c018a5e1,8ae25f71,34df3f86,dc091d51,258ecbe4,1cf616e9,265d6d36,8ea3403b,24cdc7f8,e176e5fc) -,S(d1ba9b67,66f24eaf,a145ad14,81063b5f,e4604817,21b361c4,95de8833,be605c01,e80a6cbd,17de2f1e,663ce7f2,8917e3a9,f871943c,a4b8ba75,68476a3,d9e8400a) -,S(5c98b6b0,3a3e5a8d,2d46652d,5eb9e2ab,a80c6702,69dc5ba8,3732752e,922639b3,81e2f9a,145d0cdd,2c51bd13,f907a04,6a35efb6,635292e0,6b8f6513,c50f4a54) -,S(c1fa4688,f75fb86f,61cb7071,4fb25f2e,908abf0e,a87aa84,c8db5dd,4c2618f8,f2f74a77,6d4bf26d,17f55d0b,1aa913cb,9db869e5,ab861d9b,2043ccb9,ca8397ea) -,S(5e806e9,a644eb32,51c62ba2,f09a755b,96aec78b,4405df76,dc22ba6c,f7227ec1,b88c8118,d6a1829d,6aecaa05,742313a,b871d2eb,72f31bba,9d84f87f,a73e614b) -,S(f9d147fe,fd2c1a7b,f623d965,bc7901bd,968636d,eff54c14,34c6326e,d1c8de9a,c7887249,ab6686c7,93a7d77b,41173060,40de44cb,84980c33,cd548d72,d29caffd) -,S(b98cc956,85f6d11f,a8d38a1f,50799634,9f7020ae,3171023b,abea0fec,a70ccdb1,f074d495,3689e8a3,6ee4cc0d,40882355,3dcbdf21,70975f49,5712adbc,990ecf7f) -,S(f161cad4,100817e7,ef9091dc,714bcba6,18458493,f3bb6b03,4648a649,6817b474,b7eeb92e,396af324,22881eb2,45e62515,c4410af9,fa519ffd,61289f6d,9b740904) -,S(7c8b6c89,2ea4061e,456abac2,46edc08b,fb54aff6,8a2678fb,1b7b1c08,5326914c,f08e1f02,6ea1d2c2,9ff5eacd,2b34682,2960723d,cdab95b1,d69c8af,5e7692f8) -,S(4668c29f,16334658,195b93cc,ef71a076,3ab2078f,724dde5d,d3635eed,24f28729,5db228c9,8391ec52,324c723,39d99514,8fd22f7c,2f61cfa1,29ee7400,4c74ea4f) -,S(3443d0f3,9dd6da5c,19a39f8c,f3672652,96fa6729,c9290b2f,4e21c7e5,3167b65e,4b6db639,9a088ddc,8ed31f63,7c079451,14a4320b,b7ed94b9,2a87c0e8,97429234) -,S(d3ce3501,17a04e95,58281e69,3574c096,458dbca9,afac20e8,ffec7810,8bc227b4,bcfc77b9,628f6ee9,3541e47f,8d556ad0,7696ee6e,90ce384a,9b77fcab,6eb9908) -,S(c4dc6363,ad772452,221f8640,9de0ac28,f2bc1ac3,cd2d7080,23301560,f95127af,78c9ba8f,d789a666,439bc949,38345250,38a79c5,97f6a71b,3e096b8b,752d3038) -,S(c771f94,221a47ec,fcd78d7a,123d2e0e,1bf4edcc,bbcdd075,b23d29da,6d5ac666,4dee3b30,829f5aae,f4471924,65de293f,f2ec526f,5b8f5980,d9155f71,ce8d6091) -,S(bff88ce8,96338f7f,5b6516e6,448a1f25,36a1e9bf,275afd50,e772517d,79e6e199,8f3f0c7a,b62010a4,eb0b6211,7e9761d9,c1552629,bb55bf68,53274158,a788c206) -,S(4afcd064,5d57bf24,e850e7e3,d3cac224,6a467e76,f2ce02da,576a1f2a,9a3b97a,52f23b54,87b2af93,6cc692f6,1876d6c0,ef927d3b,c06df93,984ae54e,4d10f0a2) -,S(c4bc122c,b9bf0e20,57f933fd,94db012f,79e23c34,98007abd,f8a8ba21,32b1f373,e40c47b6,a31d81ba,dc45d427,3ab56d77,1daf76bd,7bdf8ce1,a8778861,66fbfc6d) -,S(487a19b1,d1be7791,ce223d27,bab11aca,837a0f8a,7d34d9dd,b4c68f18,51f821a8,a53cd743,16ff4e9a,8633554,45415e35,5552403,7b25ce67,f519e44a,a5d0ef98) -,S(274a3cec,be06c748,7603516,588ccffd,f4ac3d80,a85887f8,10632cb8,4301a326,17a24be3,afbe8b45,9a72cab,5385cb6f,5d06b47a,63bf19b3,ff4989c4,85a9f40d) -,S(32b31f77,b0cb99ac,3bfc34e,7558f9d3,e82fcc6a,be2c4,8a079106,33afa9e8,447b44c,c191da90,e0eb3f71,db804472,17f422d5,b1732a8,993da80a,5d8f5bc2) -,S(78c39dcf,55561468,dc339d46,ffd09337,945285e1,66dfc29,25d8b85a,24a2752,d691ddbb,4e41ca85,eebdf63d,5c023e62,a6680931,5e1109ce,89088467,7ba3ac55) -,S(5fc75911,a4920777,c4502116,deefc1a8,d2f21f96,2b1e725f,a04d6fb3,9d34e5ff,59f36f7f,18f5885c,dff524d9,6a139749,f3fe1662,4b728d50,7a460bb3,497512f2) -,S(ca1590e9,152b2b49,a6d0fc16,4e346e19,fa62dde6,f693b64a,e38289d3,ad08fa8a,46a7bb3c,1174ed75,49e9eae1,7126455d,535ea744,936947f5,24a8ff30,8046dc8c) -,S(5c715266,5ff0bdeb,a7f6e660,bf66d5ad,743d94bc,5ba9b7f1,f3d50cdd,9d11fa1f,7da23b15,56e995c3,a21ee9dd,ccccca4e,e41684a4,f208c39,b31ffe9c,4473a03e) -,S(c7f71da3,6361c73a,55dc3877,4f2e1033,fa0c09ce,1c9557c8,c29d8684,e4177e82,8d6e47f,b5c2cecb,6b22dbf9,a04f0f95,77c6f50c,3429df92,78edb85,59b0dedf) -,S(6e91bd9f,5264a13e,37925900,433b7536,4130b4cc,e6fa716d,a0101c2b,dc58afab,5baa7455,506b5849,5d820c20,f209aa01,ee0f9434,1df5b449,9ed23a51,b4fd604f) -,S(1f00de8e,69ac7cbf,c75c789d,f3322813,244907a0,35059072,68954196,baef0d33,2892ce90,f32330ed,2800c30b,4482b67a,e65fec8,41ba6fea,b2e83703,dae040f4) -,S(c00133f5,7d8c469,421efa3a,d71d8d58,1a2f5b0b,2324de10,91d79145,7d300638,3c76b182,d3ee982,dd05ea45,59e8e31b,1aa3dc12,fdcb67a2,f86434ed,34f18895) -,S(af639e7,95e8269e,12cef756,4bbf970,cdb172e0,66cde48d,2f8e9083,c60cad49,1bd01179,ce92cd29,e414a74,cd1de487,c479daf,5673b219,8082c474,2426abb4) -,S(e6dbd27d,5447c044,18fa0a5d,8ebcb9a0,ede58538,8b73ccd5,4e979797,31f4c9a1,77f38524,f2848320,3d4c780a,d0cf8bd,a2071037,348db8ee,6b5deabe,3d242153) -,S(f51a8d23,c95b70aa,d02dd904,ec1119ea,8d1e3e1e,e405646e,4c2dfd53,336360a9,426b2c9a,1d703cf6,c748871,4959acda,ae5c6aab,51945138,73e4b1a9,c0f46c57) -,S(e12f11e7,fe437b7,f578d8fc,33ae3a60,a3e4d1ac,1ee45863,42944d50,a0f6bcf4,22d15d58,35fa89ab,563985b1,4114c957,8bfec8d6,6dc7d253,e3c6d900,4419f5d2) -,S(e758860a,8ec762d0,62f51e56,d958a14f,ac619351,9d890bb9,bf6bc7ed,e988e14c,42d9e0ef,10b84f21,fb88d780,dcb4750f,10438682,3b003b23,ec41c297,567ecd78) -,S(3c933fe9,ba21e5c,d822b90c,78a54b7a,d4799882,ef91f2c6,e423a398,20a64163,c1eaa0be,531922e2,ca5b23a5,6700b4ad,7fc16135,11f67f96,b672ddf3,669080df) -,S(4757576a,83c9066c,b6eb6b08,e91a79c0,df828e4e,3c09ce07,939134fd,ea857872,13f22fb2,62d77f15,de3e8388,d9270c45,818248e8,9d950d7b,58ee6c6,c38277a) -,S(35e63903,70085140,b19df903,9a7fff42,46570fcd,8661caa8,129d6b4,31045c7,2855f4bc,aa9d60d8,6a44f022,b3c28e84,53cfb3ad,a58691f1,b0e9cae5,e5b9e8c9) -,S(ad446e01,1f118207,3565f031,6d0a85f6,ad5330dc,6a8be4fe,82be632e,32126fa3,240382f1,decee3f5,1f92b2f8,1ac0eab2,1d8acb54,2f730d43,15c194f6,28e83e39) -,S(fbe9e5f3,eb01ac37,820af752,9c4221a6,89164ef5,d77461af,f82d6400,6a718815,f2f30cad,d85a2e0c,e393e088,44de9215,ba207384,2abf8468,47801ff6,12d088e6) -,S(1e675320,d81ff430,a0549aa2,482cc9b8,b9b585f6,32d32916,6e952f13,3b038135,ca0f1276,c9c7d995,c5baa5de,2988700c,2e2c7f1b,366d1db1,b44b4c9a,f0686aa7) -,S(176dc770,23b0e52b,a2eb8068,ad27924b,94c3f643,30e0e85f,3593917c,d6267718,d2dc6288,5df75b06,f450686f,df660950,548d4f6,85d1a701,d510f3fe,297ca8d9) -,S(3c8536c2,32a02b3a,b36feadb,ccc7c541,7ac83942,3cfc8dd,99a0ab7b,41a9c938,a684eea5,249cd12a,d24dd8f1,73022ad1,8ebc7f52,d6a3bd9d,bdc4f5ad,a25186b5) -,S(48aa73ab,c61a76b6,e54c446f,ba881198,ec6ea003,d63c54a5,605a322d,7af006fd,c28c5eee,ffb20882,2d018506,5cf3ddf3,5977fab7,40e4d4e,cdbf9935,8e403a64) -,S(74732762,abd028d,9dad2b36,38baca49,263d170d,ca7e4cb,d83a3a1b,53cc1ff1,ca11df0c,e8dfa09f,3f2ef7ce,5c023b6c,927a88fe,60ba9f3f,ddfbd69d,e536c2c6) -,S(eb71ab09,520e5915,767dc918,814fe901,a4042725,5247c02e,b8672c5b,95698522,5fad7ae0,a7e95b38,ed6563cb,2023b2a9,c81b6901,c007f1eb,8749f56e,4d48e995) -,S(2b101bf6,c7763df5,72eda74b,eb179cc6,af5e8695,965761ce,f8444371,7ef5be6b,dd16c8,4e1d1a3d,98d4629f,ef258421,f6664719,7f89a597,67fe862,3f140ce9) -,S(a099efa8,2c666552,5332b050,75e81ba2,13976afe,8f3b33eb,ca2a4436,6e0ab337,f883957b,5cf1f2b3,ddd6c7fa,a126acca,fb1e33b5,e5b753ab,dc0a99bd,5d136c07) -,S(f4396856,a61c3ce9,5b72ab6d,470bdeb1,8cc107cd,2f58f15,3d5bc99f,8b62f95d,6e3ead1a,a8edb0b0,67240ca,f3274e63,df81c2f3,e1ef2567,cfd76c01,6e9f6133) -,S(da732197,26aabb18,4a0aabe5,a493d803,53215b7c,49458008,bd5e387f,694050c0,e2075f29,17724b68,6bcb987d,85e954e1,9489af4c,e7ce1b46,66d84604,e9a0eeb6) -,S(99171a1e,19596183,f4259c09,b9740201,8fea44d1,4d0f2f45,75f4d66f,980a6792,522b840c,83e1eef3,e7f2cbd8,e07bec0,66af1bd2,e7607f5f,27a767b1,75219a4f) -,S(353cc684,8a2c4f36,2408997a,944889c0,1db7bcf6,9133323f,8f0d34ca,758cf08f,1865bc62,f4ba0156,7e2b283f,702834c8,97effd14,6e0e5fa2,43d5124d,ce67ebe7) -,S(8b16983b,5053d3d3,8e67c77f,1b6fccc1,b9ed7e3d,d57a26d5,deb242dd,7a312852,49d93f92,fa5953d3,956adeed,cff49ac8,caeb3d2,c72a0e9f,be6c85e5,d85d47c6) -,S(68f5dea4,b1da327c,227b2513,83fb622,efb36730,3bac02ef,505e0464,750cabc9,26740f9c,5d624b9d,aed25774,46c9c742,146de045,71cb750c,4356898f,e3d31782) -,S(faf5207f,c3acf00c,8e19d8bd,7208a6d7,cc936706,98559244,e74bb202,20c699b,fab7b446,17a6c6e5,4ac186ac,971de8e7,d42c1527,8607eeb,b8564a0b,cef1936c) -,S(c3d1aa91,b541c5bd,3da04707,a2f01a16,917c0420,a26604a2,bcaf5081,e8d17630,5b57806e,5a58c405,f06d7ce5,4e5f7b45,c9b631a3,44c92c64,d8cd1435,fcd9ce27) -,S(23278a35,4970b920,450db526,391b30f2,54b5bd5a,fe2c1455,623c99fa,8ac8db1a,864d81da,e8df9e47,1ac93b74,660542df,3570486b,fbd2144d,55dee441,90e1888b) -,S(602f6181,33cbca4d,74de4ab,29dcd101,7c12c32b,ecaed25,485765c5,478c0146,4c42cfb7,279ec350,f77d2da1,599b9c85,9ffab342,ce6a011f,91c9e460,27aa968) -,S(1dc4cfc7,126c3b2,5d82aa46,3dcc8cff,c545a9ab,c7962690,fd4ecaad,25843ee9,a9357982,5c535575,35820f17,25e32afb,6002b1b9,2a9b43ac,18225e61,b3fedeb1) -,S(3694f121,6e02bc79,14cd9910,8ca65fc5,887a95df,8b04e8b3,3c6c23cf,ce35af82,7ffee291,b1c41976,d456e742,88458b9e,c61e57c9,9b8386d1,d1c36424,38555d88) -,S(743ada75,a9596420,7b8725e0,af06c2c4,457be03b,a920c3b4,b65922b2,1df1bdbf,8f2b81b5,5ac4c5d8,9cc23ed,92dc1b43,5629b9f9,39b126c0,b16d7175,b40f908f) -,S(bfe9397,7c7cc4a7,b9cc42d7,f044607c,f047cf2e,26d6f94f,210af7d6,b2420085,625d6059,8f80dc83,1ef2b51,dee53d5,666c3dfe,a02e1d92,1260906f,ae373d64) -,S(86c02c0e,6ee646c8,c2944751,7867a1ad,cb56ebff,c8795f83,73e6d8b9,1b240eb9,659b5e9f,da4b1098,b76af529,f56f809,59d39f48,916477b4,bfa66af,c85be4ed) -,S(3b281045,857f01e9,995d357d,3a84dc66,6c4f8f47,4b82ace5,dc3a9229,387bfda4,9948272c,cdeb1542,47c7c42f,1f313dad,e318a123,3f500f8a,16d80e7f,d2e9fd4c) -,S(cddccdd3,b54d979f,504d33d,46d6ff2a,9859038e,33087a3,da9a5284,fefc47c0,9f2a13f8,369313c1,44d91e5e,807ddd65,196c991,a7eb0321,2133aeb4,56683b8) -,S(98100502,a6023ddb,ee34462b,d0232711,8f8c2e9f,33708088,40352c34,870e16d7,1a8bfef4,69af3b3b,1e381c08,454a84ec,4cf8fb66,bd721a57,47a94e90,1969b9cb) -,S(8b76757d,b2fc179b,9016847,9b82124b,c26092f9,b35de316,c90223e5,99978179,47eaf326,588e65ca,541a71a6,a1167321,ee449268,1e8b4960,6eaf9a73,42b16f05) -,S(e66ed7dc,897fb660,6f44d8a9,46b0c61c,45c83bb2,d55ea771,bf2571d6,7ecc3b43,e536f79b,8a9fff4e,c6cffd47,8a405bd,7f1745f9,9374d810,518cc5a9,f214dcbe) -,S(e0600592,cc9c0b9f,8cead065,6ef5c115,ead63209,6a0a0d2,2626aa13,f2bc88c8,628d94b7,8b84705d,16e55254,4c138416,e7f75f5d,d549ff7c,a42d51cb,7f5a584f) -,S(1b0af242,a9cf25d4,cc758fc7,63e2f07,62db2e42,6b392cfb,ffc5ac07,19152767,33ae8aa5,eec30559,a3d28da0,d9354048,592dec4b,2f975a0,ed043fc3,c856a2be) -,S(e204ffaa,142f7eda,3505beee,db0bcbf0,9b80924d,ce5bced5,439aa4d6,af5acb7d,a2804d9b,98e11519,adeacdd1,aef2c22b,a02f7030,479a559e,6924db49,5d8911ba) -,S(afc40e67,651531f6,214ea1fc,13173d4c,a35431f4,92845964,69cf099a,d515ed5,57ef6ef4,1e480de9,32ae8596,3b04d267,5e629707,cd3bdb45,5896d333,b648e0) -,S(59538bdb,747b641f,800588b0,45c0e3c9,72963406,5ca601d4,690dee22,abe8d226,a030486a,3c919c35,4c26547a,3de96087,52ca7a28,5d378e28,652031dc,ec2d4438) -,S(6a91d34f,c38d4028,c63a4bae,bedb2a76,b964cf44,1804a6f1,efbe469a,a997ed8f,32500c83,6a0b5274,2d2ead10,dd3e73eb,45f221d1,ca6cea00,f2b01d75,d9073260) -,S(9260e687,b11d97ee,97dc44ab,5e21c344,332ae39d,c85c2ee8,f7760cc2,8ac28d61,f47df3d,e8d8654e,f7124f5e,2dcd9d95,c1d13e83,a33e5d18,92ce9851,6223e778) -,S(3490e733,7a66f301,f678561f,4b4f293c,b48820c3,dcf9be06,a0390410,4cfe3cba,49591a79,7edb70ac,74f87636,85bbb22a,a8169536,532886f1,f5ea0721,5e9bbd6c) -,S(9729f4fe,1f47a9a3,7dcb1311,ea9548a1,d71d7a81,27803c8a,6ec0a680,8d07b4a0,56e1a5d4,ccc4fd72,8e7ee569,e22efea5,c8f03d73,fe8ab86c,2dcb8af2,eb17f896) -,S(af63904f,6da423d,1cfd77a6,680044f0,5e694eb5,80ccb4b1,c37d8d83,ae9c2caf,6decdc2f,5fe2b948,d15fa10b,4a7e2edd,b8cfaf0f,7c79a400,f3d1b306,dbe110b2) -,S(96271f72,1f4a1f21,a2274edf,87c294fd,403cf0e0,c7b7b1f2,f242fb7a,2c435a3f,66ffbc73,1fc8cfd5,2bfbbca4,49f6e949,71940077,ae411e79,51cf5b21,ca5adddf) -,S(a42ef215,1f0cc5a0,15827287,eba8d960,dfa5a13c,7ee2696a,95bd94ca,4b717c7d,5e491ed4,5f08a591,32296929,814608ee,e3243172,b523a1b,a4995f6b,50046fec) -,S(193b3ded,e770a757,d859c289,68be2780,fc4ce92b,135bec2f,7fb2c07b,b862e5e4,192c4bba,ffbb735e,a1d5cd1,38de0556,d1d1d740,980c5775,22d19b5e,f0716700) -,S(ccf9a075,da6f44e4,cf3b4fc8,26feef3e,54084b0,e2756029,e290a7ce,8c1e8dc7,d04f844d,ccf2c30b,9020f0a2,308219c6,a5d6491,ffe9ba67,bf6b20c9,9a35a183) -,S(7ebea25b,1d69bb43,f60ec69e,f9853208,d3ddffb9,6dce3831,873e7ace,d25b0140,24540af2,bf87d637,54f1a47d,13a3f38,2a948375,8955dd16,fc83e7ca,4fec3d65) -,S(c9eb4a,c2a31b01,9b7ff038,38478b6,674662eb,d729ae45,d7111c63,84a038c7,7e2ee03d,caed3f4e,bef2b90d,78ae42a3,12f6e8b3,29d116a6,e26bdded,81f32240) -,S(45756e0c,8c84e9e,a7b23bc5,cfd87b4a,cd0b290d,86c547b8,7fed946f,e5acd867,9c3f522c,e577c017,3db984c3,d7dc16d0,31326e2c,85b08413,4611da0a,70acdd1f) -,S(1bd58481,21bed636,c789e341,665e2477,59438de7,10aba25c,e4a0db7f,13e3c0da,cb0eb897,bf905399,63a8a7b7,50787430,ffd4d6d7,9589c8e7,350f4351,4786a90b) -,S(f199562c,8e809ba5,84aa80a9,759dd98c,32eda7e0,ccfa4063,547ced9,d9324dc1,33519ead,76430498,949dbcea,33ca14de,2f7ea811,cdd38f32,4009ac7a,b408d1d0) -,S(7fb4e910,e9e37dc1,f56ac3b9,30589522,975319e9,84dcb559,6743d3d4,f45ea6f3,b74a03c,cdbec9c,f36b59bc,fe3203dc,5f4d94a7,bd54c628,55f0d04e,67c960ee) -,S(503d08fd,19839d78,aca27020,54dc4233,c1a1d68a,6b9cf136,4c6fa9fe,886c03e6,84ad95db,9a09eb87,bd905914,473d23de,698459d5,7c436f77,58937bd1,8e448e0a) -,S(335c9204,e6aed3e2,586d0dea,c87158a5,62db42c8,e42fac25,9196083,51e1e713,15b359bb,10f8bee2,940849d4,212fdd84,49b60c5d,d3419ce6,7ef9f0ac,f4c1c2f9) -,S(ba68e5cb,e0f7159f,821117df,5720bb50,f218c298,9ce3f5ef,30c44134,2834bc9f,2ac25bdd,ff34e4e,ff45a2ed,e412a287,101ff447,71c657f3,ca57bc94,40fa5d72) -,S(93d6e713,311d8430,58c20267,739c494b,446d7943,a1e47a0a,2a5ec20,877e6baa,5997c19c,99a2fd26,e0471041,b509f9d,e10bf615,7cd4f24f,db56a65d,201a0856) -,S(7a94bc1b,5cc77a0a,73a84fbe,c5d1b68,cb8f4626,8ecc0c22,ac7500a4,5f397172,128c1c6e,82a4d52a,719c9f8c,1bedf4d3,32d3695,16decef,34af6b4d,578bee5) -,S(f031eda7,c19383d9,45eec848,f6f3e467,75fbe52d,bacadc54,c213c596,c821b809,b4a78d0d,1c17e4f5,db81e2e7,ee52f195,eb505d36,af96bea0,5170c776,23cabab8) -,S(86ef1acd,5c17e082,dd4cb924,c74d0195,ce9f375,60ca7608,57ab7d70,2039907c,6936a13d,b9078ac9,426d34b1,6d5673d,36c3105c,9cc77de1,ef7e0ec2,4cf3bb3c) -,S(fceb6cc9,c78e3a35,49b9beeb,62a14fb8,6d24eec9,2ab10bc9,40916b60,cbc6d720,7c2e6024,5f561f1c,e0b69701,512ca518,9f8d9292,ea75562f,8b17873,77f7583d) -,S(a1d9ed1b,9a36f348,1f426d83,7afe4380,d475e36e,3b140f3e,cd2213ee,dfa5c8d9,3683c97c,a1273f29,ec02cb77,9e9fee54,78bd5e3b,e6aa8c60,7d5bf07,dfa558a0) -,S(d98de999,6311ed55,e15bbdc7,58affca1,3e8f629a,77eb3dac,844f90e0,51bd48c7,8af6194d,272a8ee7,68d1b810,778e5c2,69394353,969d77cc,7d449f2,84ef2a22) -,S(78328db7,cd6afa29,b6f1ba80,d65f8050,60f4d223,9897a3ed,bee8ba3f,a99aac60,e37e496f,1d143ac4,8123377f,4e136442,629f8185,c4996f01,f35c7a9e,76fc5efb) -,S(3d701493,31faf0b,37c1e1c0,9b29ee6c,5d9747cf,cdb26117,223d1f66,e336db5e,d1e99140,8311b20a,b41f7ce0,ab4e9dd3,414ea3c5,b87f88b6,648cd1d3,e77600ad) -,S(f619acc0,47e0d4ab,bd5ba2a,7a54ecc4,e223986,fdbf7a96,e90f762a,ce288628,f24eb63d,e1545d10,fc96a2d7,e7fc1ee,f9cdccdf,cefb5de6,8fa4eca6,781564f2) -,S(cca809b8,71f85a00,3344a851,4f797fce,91718f35,9e2fb489,a1dbc00c,aad0a2d2,b7d72ab8,35658359,2258f260,a1f62f97,aba642ed,382992f7,12b11c11,6890b037) -,S(bbd19766,ee2c501d,afb4eec0,30fba145,aa26c45b,51c1beea,a7d3ed1c,7dc81958,bc709dff,70b3612e,7cf0a6e8,9724442f,6c1ca4ce,c32efcfe,b98f1acf,df5250fa) -,S(6a6fdca0,e4a58197,267a1938,1644aa5d,ca8f0ee8,3a68a5f7,9c34d4af,ec1cfadd,c28b1236,76585255,cc104298,d7ebcc70,6bd7ff6f,cadb0c36,db6517e9,d2732081) -,S(922e3e1,fd401a22,ee7d693d,e52f0ade,9564af2b,17a4be0,2c553216,df5c8006,a7b10065,aae84a40,b9b79e0c,5ca8a227,696841c7,20b944aa,3b9eb1c4,1488f757) -,S(53ffae4e,3526b553,f92bd9da,e3cbd3b3,aff8a6da,d4895490,38382f98,a676eac8,81fdfcae,b51f80b8,3d23b222,8ce860ec,9e665292,c456fd23,cfde43ed,99f8c6f4) -,S(14a0ddd1,c94596f8,9d3e7028,929cfe4a,7c2e70c6,b55d15b9,77227862,a03d119,2b5dc071,febe1d1d,df7e1483,53dc6558,7e8c94ef,b598ee83,806f1fbe,976dd086) -,S(7368240d,fb74f35b,b51a2542,8caf3b90,bebe272a,739eff4d,c0150f1e,3d68c8f9,95392b17,b4c5e82e,774c7168,7c46469f,21801a72,b15cbcd8,fd2ba85e,e4a7a27f) -,S(4c0a8053,b9eab39d,2396825e,2416885f,5fbdb610,7bc5879e,6400d010,20580560,85a222a7,5b7de532,617f67f6,5408b79e,f5a6f826,6083c2f0,93ca97bb,d7db5427) -,S(ca0d66a8,24a6f8ac,bd9447a4,933dfcb2,6751a26a,f5790a1e,91e32053,3ddabbf8,61cc898d,4f8b0845,11dfd49b,1ef01e43,6f7d7d08,a5f16b2,1550f329,79395d18) -,S(646a0775,e62f6a36,d520763b,5c7fb081,a3d7dff7,355cba76,45358a6e,55e9d6d4,3e528844,e7380a64,20db2366,22c936f9,b1100046,e17c66f7,a6b1a01f,7b7dbbb4) -,S(435565ec,f3d6bc13,142d7c47,7052da71,bac77f3e,a81107f2,30303003,6455d070,4ed52896,89fd8d96,343ca8f6,c9f0c70f,ab6edc5c,1ae96d15,9fa9eb4d,a4c9f6bd) -,S(d8b01896,9328544a,a51f22fe,e605c693,7a014aac,37316f,ff6a760b,93aa8f9d,63f51e42,a2b879ad,36d60719,c1497b5d,dd412782,e4c620ac,989f7259,3a06edf3) -,S(b9475950,4a9b3052,94af6f2b,6f182e5e,83a30abb,47f0799a,21ee5446,d63d48d7,cbc74028,37a899bf,79b89676,9e358ad6,9680277c,34ae1018,4290689,c2fb876) -,S(14317c49,2972d5be,c5a01b5e,34842135,d521b467,1b262f0f,c3e6a271,ff8e0ef0,cc4d2235,d1cecfd2,2e6a476a,7db483d9,d318e79e,4c3486cf,c2090651,c2069381) -,S(8bbdb357,5b6867f4,4f062ab3,38928d52,78c4b873,4e95c5f8,fcddd4e4,9d44f8c6,d38d3387,32424054,c05a67e6,c7d00e62,1279eca2,ee1b59fa,90b97f33,5173a778) -,S(7775fef6,36ecbe78,9279786,b996c0d7,380b00f9,4ed31476,1ab0b190,f06aa685,53152a73,162dd659,dce57d7f,cb885c44,34243153,2b8318e1,2a996ebf,2f55407b) -,S(db5e4bd1,39ebe377,bca64950,29e72fb4,bc9b0ea5,5450e42b,a7491c0c,39693b48,a6468113,a5a796ad,a337ceb3,238827dc,416ca20e,bdbe4e62,14194e66,cc5a0abb) -,S(eab057b0,578c52e2,eac11be3,9f069cf1,6ebf0631,709560fc,2414ff11,f1c619eb,5422023f,cf69b8a8,458e5c6c,3c2de1e8,6fb041ce,180c5f75,cddb455,fd023f67) -,S(e955fcd3,c657d611,7e2d43cc,651333e,c231ba32,418e6fe6,d021183f,e7f5e44c,dd0eaa98,65212f27,2454953a,4c46c5da,973095fc,b2e36369,cfe228f4,828e6b57) -,S(5f5a3c57,58eafc30,c311f596,f1d6605f,ec0f5e73,eafb27a7,2a07f91b,42d8e49,3cde0b0,1d1fb2ea,9d85a04a,aa4536f5,c6d9f55e,84ca890c,cf23ef2a,5dcdf1a2) -,S(fb7a31e4,ff0ade1e,efffbd7a,e04af118,49c82cf2,6ad219c0,7572d924,8b99bab,ea87aa0c,431de57e,ee86bc4e,be463dd7,9e69102c,736345a,5502b07f,31df2a01) -,S(d57b1d6a,a3e87779,4b9f8dd9,683ee3a3,6ec18d3d,e6b22b44,e411778d,4bae1ffb,256ffed6,b85bd2f0,9dadb0e,43ccbaec,9fcb9e57,22d88ca,73f8d7ab,dc0f62ee) -,S(9326fc52,d3a24a38,ef0fc90e,183697b3,f726832,c70bcb5b,bd6ac548,cbb8f1a6,863bd0a0,cc0a2bea,d21176f5,c99fafa8,d7d766c2,54d57308,1a58a6f,12889a2b) -,S(58362cd5,abc9b5e6,57617e94,620ad087,d5d310d5,313ef6da,36079b4b,a93caff4,5f2a404,4e86bbd8,d73b673b,2e432233,d6923cf3,c262e1c0,3da48d42,f62fc52f) -,S(7dd488b9,cd06e68f,e01b3a9,6b318d61,b8c4cd69,7e9a3681,34fce81,841738ee,fd7aa5ed,130c897,cb770846,a3d292a0,d963ded0,5266010f,34a99ebe,99782cf) -,S(9bf78b02,524c1554,3330d7d5,a3b41705,1fa2a324,6ba8061d,f9550640,cfe798d,59f537d6,6d2e6801,d79d5a70,3b4219c8,c7d06385,76964f48,10427548,90cf5a83) -,S(4c816973,743ad5cb,18db4f87,9bbd6d1c,e71513b6,eeebfc39,3663dc36,eb3fc47,1a6dc6ac,37a49400,a933ef09,f00f9650,44c6f8eb,d516c254,ab142d89,d41105f) -,S(60636bc2,c7486343,59296408,40f3a26c,173f4e5a,7f0031a8,35c1c56f,b1051be8,71a78b7a,3aed2bc9,70a4190b,d1be56e,efc2e6b,7cf81b08,541dd8f5,dbe88e8b) -,S(a6e772de,c3e90a70,6c663fc9,4d5e6cd3,12211537,40ca4a2f,47a0f3,7f8d00a,25b8fe1f,5c727181,4a6175a8,10aa1eb8,f1090221,d78c32ca,76ba7c73,d0eed520) -,S(79c6653c,60307215,fabb4b2a,aa8bfbaf,1692f613,166326c9,19324e5,7cb89262,36d5ed12,b6b49496,e2b79da4,c0955cbf,c24eaa3c,204e28f8,db1e7ed2,d2197bcb) -,S(3f556b2e,4530fade,d4774af4,ce4454c3,4a2bdb4e,aabda42e,d4ba8546,d646cb15,bab1d321,1ce84331,3be8996b,f5c5c4e2,c9fd04d8,397cf9e0,58829389,ecfd25c3) -,S(eda59a23,8d21fe9f,5e11e0fb,cf731fe2,d645c52a,f3861dd9,3b7273b7,3fb3913a,22f22f01,4ba320b8,2cc29c06,d75b7eb7,d3cea857,40cb2562,4161b9a8,712bbfee) -,S(7a1ea77,323dfb4f,36958adf,71d4f03,3a2bea2b,a9f62cb0,c42a4279,7de68548,4866ce25,ee7a2b5d,a276f976,6261318c,6d2d7f51,f6f41940,f6cc3f20,264825a0) -,S(ad0fd3a,ad62d6d0,bae7c51d,590876e2,33d1028f,62d5c178,a0ecc3d9,a323de2a,88e024c5,9672469f,54f4a64e,b792d761,d163157d,ed982787,a6d40382,83b0601) -,S(1bf19432,f4044a69,56d6e9d6,7b84a5cb,ee743771,8d634dfd,20706cdc,602729d3,4114b200,afb6a1a0,75ef8e3e,16c37e9b,4f2acd9c,3fa4e922,63d1c430,7c516aa9) -,S(514616f2,bc2dafa,8be3b9d5,f00b694d,2fb1af5f,12d219af,c35204c2,e121d93b,3e5cee53,608a299c,f67f4e0a,65adbf2,57ba8eb7,450058a,74072ccf,922eaf9c) -,S(8e3fece8,5338ed31,93721d18,1cff34e4,fdc42330,6a8e1a1c,3b002da1,6921a661,b095734b,6736486b,676dfc24,9cac99ef,12894543,8b333b2e,77664f8,20f686d2) -,S(46c06820,df101ed2,92842186,7d8a20b9,6db1eb9a,ae63355,916d438c,a7ad4447,fcaa10f4,59bb73f,c48d1b60,1147b535,d7d43958,1bcfe26f,9acc7abc,ddf1afa9) -,S(56334df7,1f9b390a,b001e406,ab37af71,3fff8c69,1c2eedba,fec7dbf,cf722b31,22d04394,340dc156,a73c4b0b,f49a6c93,8a3724c4,4744690,4af420bc,726707dc) -,S(202e246d,89045f8c,9dbe3dc9,7ca52d23,b2fd55fa,1b5cbd37,cb882663,ca67c4f,f4e6cf89,9cbcf023,1c9f661e,c4588072,7a6241e3,513cb365,9a2e7b20,a17a62b1) -,S(c8054ee0,10211c2c,f5bc1ff9,43552eff,c56b635c,d65e409d,ece239e9,9b9bd4d5,f50515af,51601cbc,de6842b4,3b854b05,bf1ebd1,678c46b,46e22827,17f31057) -,S(9c29788c,235eb61a,d2940708,4b9701a1,ea3282ae,56f984f5,1c625538,14438383,32111eec,efdbef2e,236469db,4ad30e30,c116cc42,99dd286c,2ab70ec4,9759ead7) -,S(5854e8d0,b7b5c394,7068dc86,f94c3cd6,72999023,367509e7,4bc1745c,19a57ef8,7e7901c5,c06bebd,f50c4113,4e0d2d3c,edafec05,417d45f2,345b75cb,a63eb98d) -,S(8bb2fff0,f45be789,a0446e1b,3547a44d,1104a5dd,9c8e50b7,4d0fa891,f73fef34,c332e365,a5343ea6,6c571e2b,c383f767,efb979df,72223a79,35da9173,73b182c1) -,S(ea88e65,6ee43387,86165faa,cb643cda,992f5656,dc7333c4,5ad8b561,8ccd209e,c38c40d6,4a7a343d,8ab357ab,845725c6,af9f4f4a,843986f1,fd0a83a2,5df0f909) -,S(c0c1d4df,857c7ea6,13322c2e,e0d4ba2a,a3b18ab8,cc8d9ff6,6981d6a9,4446295a,247115d1,e8eef7d,ce6ae1db,ec9be46a,9a284648,ebb7a918,7292fe05,9d72b981) -,S(91e6a4f9,407d3600,2a808d8d,db723ebe,67b8e212,792ba65d,b74e028c,ec7fc72a,ef6ae560,35f58be8,5cce98f7,b2106e0a,12e57dbb,47a4a995,47ee5041,3c5721ba) -,S(cd749618,9a8c1d36,2995cf61,380d0366,24a7a402,e21cf078,18794e08,fb208454,f3dc92be,15d1f912,a03debcf,88afcaba,2dd6ba2f,1d23a4f6,ba02c5ed,cbaf0bd9) -,S(99f5d12d,2e68e70,c304f3fa,44eb24a6,85f63065,af0a15e9,f71752ff,82943018,59f1921a,d97ebf33,68f962c9,c0a297b1,dff9f980,246d5dfb,61168dc1,da0b8a9e) -,S(63c6cd30,f9c07096,11656b1e,75d17191,a6ac02db,9debadff,7b3d602b,b9f7608f,2e439373,70a41b8f,e0e5f0a1,3ab75be4,6d8b1ef4,ee71723,4b73ffef,461083f0) -,S(b7407f26,90a5ea11,d9b7fc55,17e6c1b1,9e04fe47,180b1e93,94cd5e97,5d184d92,1b953929,47dd4984,7420f727,7a6796e7,828ee880,3e0d701a,aed8cf7d,513de6d2) -,S(24979116,161c8840,dd521e96,27a50056,c29ce48d,d86b6297,150f9a6d,e383fd40,13dd71ab,3dd69cf7,384d3e32,5fb16648,76f99943,f7ba3649,143e09b0,28b9a70b) -,S(f109b6c3,6122b278,8656c80d,4c84150b,b419919,4650d96b,6f2de8f7,f9d73b7d,a7457369,bef8d54d,c0a91d4a,39496f85,bd971f6b,4a13dc77,142ead5d,791c96ac) -,S(59b303f8,2031c370,4f17c929,7fbd0ac1,36be9900,a26b5516,9f0e3b6d,69118df9,30c7c4dd,1666271a,5ac8c936,b35068c1,9830306d,c695e02,d6c65ebd,2fd678c3) -,S(6627359a,eb3910db,4ba54cd6,c7b884c9,a678621a,d2bf6cd6,6023974e,d462fc52,bcbcf9ba,d2de78a7,fc486734,79379778,feab83dd,ea4f50b2,555c457d,a910d487) -,S(76fdad80,c4fb507d,9c9d2305,90e818ac,ec7efc04,1184281e,9212785a,dd51f1d9,cc8cc7cc,349cf307,f34adf7e,f559855b,9b88b70d,7fc9d19a,18cecddb,e3a8c346) -,S(7893406,e99cf08a,52fed9cc,4a9bafdb,7f2380cb,4c288700,b983b791,e1313330,ec15e1af,39eafe5a,d081acd3,fbd5b8ec,d0c2e83b,7a5b8074,50ef80af,2511d149) -,S(c454aa4,e8d02133,ed93c229,d0e834f5,18f16cd,d83a39ff,3bbb1ba0,838c81d5,a98e61cf,89c43808,f4895924,529a6e59,8af57be6,debf5f5c,67e3b3a8,73ac51f0) -,S(ff0bc21c,cbe5c122,dd2ba8f9,64239010,97dac1ee,3957b27b,f990b611,72402880,c34089c,1f7b2181,8d4cd5f8,9e445ec1,ecd634f7,52960da,467cd396,77bca50a) -,S(8e4486e3,49a0423b,d8132e39,812b78f0,3a0e61e9,d3eb7735,86f1e279,3731c301,897b24d4,37cc260d,52e1866f,4dc222ed,16bbf084,c108883c,a8a7b9b2,9a2053a1) -,S(4f4ca57f,84f5c4e9,6aca30d2,351089d,bf7fb6c,13847584,590fa5b4,4dc579e7,d53db7dc,1691556c,36f1cb1f,8a1b91a9,33634975,8f28d0b7,17d250e5,ade63a9e) -,S(fe8924b2,d7a24fa9,5c61830,aed8fba,79b3a96f,388b6423,c760aad8,cfc203bb,bd303e29,c6be0e2b,f4e79df9,cb17e0ac,e92c3784,fa8c26a,7e3cea32,d0b056be) -,S(3099f75c,f6a8c72f,8685895d,152f99b3,8ed9a3,320f3fc5,dcdcd14d,c46abb5d,fbb5bc2a,ec76529c,a278a32c,2a95c2a7,4a939c4,c0e2c0bc,6fc20b2e,a6fc9f1c) -,S(3b939f83,f84126f3,b6632de0,12405c9f,43244322,2ac384b9,7415c2dc,9c72f4eb,843b7353,ec454380,e9d4cc20,23a138b5,c1e602c7,f48be55f,1d3c24ca,f05607fb) -,S(dc7506a0,4a50e345,dca3cbc0,6384a938,b032f197,d6d30932,7b0c646d,95c732d8,fe942311,f6d49d62,99f9559a,3d16f43d,c6a39d4e,b623f9ea,e8dde39d,9bd5772a) -,S(f5a4c596,c6996a35,172fb61a,2721d75c,3dde68fb,4abc9433,f84d20ea,83b30dea,175e0d3e,77d2f63b,bb2ef922,d30b962,fd783b30,ef7dd8e3,5ae680bb,9df26572) -,S(7e9038e2,c499049f,e5d222ae,2f79f4b1,373c2f69,262f133,cb9be1f9,aea4029e,3592e66a,343335bc,e016276,6550a363,1d7dc64b,2223bdfe,7146f32b,8025c737) -,S(80f22f73,d16bfc6f,d6c28e92,1f990eb6,e2cb803a,d920850f,af489ff,f62b1f41,8714a5d3,c5ee74bc,73e11fd,24cf4d80,370e6711,c726ed68,2a1bd77e,7b503b28) -,S(498a2ae9,e86e53f8,43470a58,ab96fe0b,7c3107,d9d23535,fc887bfa,fe0c897d,47aa9eb3,73e841e1,4260f651,6ab3081f,7ec3809d,53b8609e,c3cced3a,6401bb53) -,S(601af64c,d14ce184,ca52c542,7a78c746,8e9c069a,80277b6d,960ddf30,3b3a010e,2900a63f,ca1576d0,11b46c27,32c87ef5,56dd579b,3bcd59,9161cd20,ceb7fa18) -,S(8fb2e0f0,7b2fcbc4,ad58b06a,822aa683,957f2bf1,5dd5984,9a1341ff,2d74a25b,7cd82350,8d797cea,b1b386f7,5d5f82af,6137dc9,9f6d6e6,b7c68cb4,75070aa4) -,S(336d780f,e9d14e8,b55a1498,72c63bc,83468eaf,aef3282c,9bde58af,6a69e6d9,92d1004,be45bee6,b8eeba68,2fd0187a,ac3e6679,f4fe0fb0,b723214,a63d2261) -,S(507ac721,f4d58704,4f8d2cbd,fb03aaea,b0634303,cce3e1a5,e4e47efa,90d5872d,b89a398d,e7db05d7,a1055093,97b83d60,9ba53c95,39caaf0e,917d22c8,307174d9) -,S(c42dcec1,3bb7fb96,29171026,f66c012c,992c604c,bea189a0,46e688a9,473ba343,8aa37731,a53223cb,a021bfe7,c413929d,8fe010ec,353464b,e3c1ce02,e54f7bb5) -,S(b02ea2c3,cd6093a2,d5e6b5c4,5c510848,857eedb6,50038417,d9f41947,2a866a2c,ebb45c50,cea190c6,1bb7c505,8cfce93b,ed1d8ee8,c75a5bf8,6ac9c127,2fa5527c) -,S(f4d193d2,9f20ed2e,273dc2c9,aeab43b5,85626d41,59b7edb1,51e17c45,ef70d84b,bda19a3f,19b834a2,c493f8cf,14cda579,1f84b6c,611ea7e7,280e5196,1add0974) -,S(8740dceb,19eac62b,75859b9e,4d0302d3,cc84f6bb,1ff6e857,eef7fb64,fe5f1bb0,a729eb0,4783205a,2e1d5b6e,7eb5221c,f2f151de,1489d1b,1d98fb68,e7c6ca49) -,S(79ec464a,85a29f08,d910bc94,449ce88,50aec626,3693bf6c,92a5ea23,84fcc9cb,77d170f5,b52ed0b2,9aad476d,85abae3,a1d7c544,c625ba2c,d44e68ea,ef53b39) -,S(4f1018d5,dd54bb71,cbc0e29b,255eafd4,6fb3aac0,45889238,847efcce,3207fceb,c32819e5,d23cc2e7,73a9b2a0,271fbe3b,a64531d9,2d416222,24a2f64e,3be7dd8c) -,S(dfbf1936,2094e85f,ddb25de6,8ca85cd4,e53768ab,81780eb0,33a0607b,fbe969a1,25ea0b59,33ba21c3,2ac5f1e4,932debcc,a2ca3aba,e0b7c671,93d97e1d,af80e563) -,S(184c66c0,2c36883,2c1805f1,8612449,940a371,54174f9,b67bb41a,85226649,cf63fe44,f1cfc791,4fb4a24c,1e0530e4,736f815b,a910b487,ec4fec7d,f8662eaf) -,S(daab3606,d386e04e,e39a8a51,a8242e43,ede9de09,f50322e0,a0f410f5,f043686,c0ba1c4,ebe7d10,6fd0d0ac,4e8f6e8c,fbb2b682,3a9d55e5,dbb7718e,d411718a) -,S(a887f4a,5311f252,ba0219d1,f848d334,26b0e216,69020dfa,89dcc339,7e04530f,5a7c04bd,8c37cac7,f429bff3,eda01dce,a5b4fa44,eecd3195,2878f79f,9dedeace) -,S(1b315664,409feb98,4d5dbfd5,a85afbce,4784a907,b284958d,28123f61,7c2d207a,2972cc7c,ba348e5a,5841d463,4597fd57,84eea5ba,a99bdc37,3119c568,aba205bb) -,S(154adfd4,27c30d56,d5f5de1e,d7e8465,6727e69f,82ec8d1f,19dfa16,b1fe4984,5ba86e8a,324b279e,449f61ba,a7fa52df,882477c4,921f2079,98199775,3e0372b5) -,S(debd69f9,fe55c15f,b28df417,cb1af3c2,585fe89f,b44c2f94,94fec0d5,88480994,98d8cc21,55c16d24,e8b1b831,4fcf616b,2564ff,9345fc9e,f8de3cd7,57f9708d) -,S(9fcd3490,2a7c54f9,a2855fc0,9558c465,e0316c3d,fb72c66b,71d4492a,efbaf9e2,a7ac4160,c2b5a416,89e9e49c,8d5aba67,143e1de8,26498be5,1cfa691f,f7f5d14c) -,S(59cacdf6,fe4bae99,598fb1d2,df3de7e0,586fd792,eee0d9bb,fdabfa73,8943a727,7c730d34,7b3ead16,c74d349e,191c484f,624599c4,d379acf,ed8d2341,160df035) -,S(5ce1abd1,fb291d97,db3a4c9e,c4ace635,34e6b373,407a8821,67722fec,7fb226c,abc24634,b4070973,d8a11025,5ff7a81b,a39de6f,5275d3f,7630de8f,23b7526) -,S(f783628e,bd0a0b4f,6ee68001,5b3014f5,e70897d0,ce159baf,3afb1aa3,207d73c,d06438fd,5b96b88c,94a68b6b,1f5fbf32,6c7a6efb,83b2f1df,2849f809,cc39af61) -,S(7830fabc,cc7229ee,35c7130d,b441d2ea,9a988d47,72ebe00c,6c159658,537ba0b3,49e8b58e,6aead178,3d5c901f,a803a33f,78acc889,27f2d57e,835aaadd,1b38fa7f) -,S(c930390e,a8901286,21a4399e,ef9a4a90,6416d549,c28f7482,6252fab,5fcba9e1,fa0e87da,3d0618a2,f54e8fd,d14b4bca,3bab137c,daab0197,4d110ef,b161cfce) -,S(2a0da867,20571917,6f949876,e5f00ec3,ba0924b0,a5e758b5,2d0c23dc,da9cd28a,96cd04fc,69350959,595b4870,f6df11cf,90c1fa1e,cd04ddd1,975d0bf0,fc907647) -,S(f64881e2,60da581a,f576e92e,3968e24,f2bef6ce,dc1c9c53,256374b3,1446fc83,808a945b,660b67f4,43ef833d,b491fa56,2aacec09,f8a2dac3,863b72f5,e7c8b94) -,S(970bd933,5ec5f0d,3a3cea17,5090f1e0,c181e488,1565c341,33017f99,ab81f052,4d1d270f,e284774a,fcbb6658,d5cc019b,8eb30bdb,39464a79,6ca1431f,1ae9fc48) -,S(dfe94b31,24c4541f,4723ecfd,f5cad197,2c058886,9283073,35415bce,e4c4779a,cc283e53,d547606a,a0fafe8c,5d3403c5,d047aff6,8b194b1c,1855a7ab,9540e23b) -,S(f1813379,673ae594,8fa30bba,d8737d0e,16c8bdd1,8f7047e3,bf33a39e,858df800,acd2c1a6,139a2dbf,9b008d50,d0b4d1f2,20bfb9d8,c24855d2,ed54440b,a87d294a) -,S(f4fbc156,fb631bdf,51192bd0,1c0db0c8,8890ec97,9c368f3e,c2106043,6d423740,3cb08cf0,5b07deff,431faf91,e1874baf,9cfccd3a,df487f4b,4f69026c,1fb7149f) -,S(124da4e8,3b079d72,4a7a9a72,5cc45a80,cb92675e,74541bbe,d36224e2,793de6d,3e700066,f12e0cba,4d6200fb,2a759554,1cd15531,ea065e6a,c6fb4986,548d00e7) -,S(749721c4,455e7826,1de045bb,266b97d0,6c2b112d,2ac8c16,428ce961,b78d1138,27556aed,a3f331c2,fe95b237,d3326c7d,25bc594,39f07b87,86559fc,55a3032) -,S(62cdca49,aa58f55,21c60dfe,d50fbf58,257676bb,fd4c4e97,9ff9a91b,7627a028,8bd49b9a,e16d10ea,7ee1528b,4f433e8f,17c4a688,a7148fbb,d10ed605,595c37b5) -,S(64d650f1,39b13aa6,16d3b227,5ed164b1,1cd3a1e8,81759344,7895a4b1,686478c6,deeee52a,f7572d87,f339595b,79643402,f9e2a065,7b95ba42,6b83d87f,3dfa5c2f) -,S(d08a3e55,66c636ef,3417c17c,d8526df6,37cb935e,db00365a,1ecc9f4a,9ab59d,2db049c7,5eec5176,3fcd3502,33856da4,e9ed32fd,24242a54,9c9ae462,240dc103) -,S(8761705a,35bcc509,afa20d62,61859afe,97154782,49ba47c6,f4b8df0e,30f20d89,b34c25ee,bb029622,4929c3db,78046a09,fd43b9e,be2dbf64,436f0df8,adb726ae) -,S(e3453933,4ce22643,146cc317,54e7ce7e,e35f6f4,e37b307,c4e9e11a,3c6f5f85,73ee178a,941e81be,ff22a0ca,f2bb4513,1afdde7b,336a3bf7,ad05c1,d465d97d) -,S(8389192f,6609a7e7,ac8e6f11,fdbfce8e,246b36bf,95e0de27,fac36082,34ca917b,957073a5,50448ec2,9d67b681,ccfb1aa2,67c88976,e53c99be,c68c378c,f2b636f) -,S(8bfd70c0,67bbe25f,e2e78029,a97fd863,bbf287fb,7a24eb8d,e5a61af4,c3c5d387,e2e6c66b,ee7265cd,5a1b1d64,4f24fcec,8b59001a,6edbb1fd,5d894740,f3f952fb) -,S(a5d0999a,a05f0bb1,59a1582d,980520b,eaf82015,68875269,fdb593e0,e6ff257d,e34d9720,5ef05766,676b62b3,62ce4b34,fe6d27d1,a644050b,f9c65c34,c423635a) -,S(44e479a7,b949c88b,507942e3,89ffd9d,17645185,92d4e544,2827baaa,5d5043ce,7b86ec29,8c12c463,b0a71416,24a570a9,e2b10d77,ae12ee23,2504edde,213a7087) -,S(60dec943,d9797811,706e0251,e0abd0ca,3f37bb8d,559213c4,3176ce3d,352aa558,2dc689f4,a31c59f6,c5181448,d6985335,16b0764f,8cc6fd50,8bc109d6,69fcaab8) -,S(5ca58d38,5b5449e6,f93c5c5,35941b98,d4ab829f,e641bb24,af7e7ab3,1f7709b,82afbae9,80eb6f48,110ce090,7f39ddc0,945d9d84,d5d3feb7,4d96581e,c17cd575) -,S(b775967e,a1b1d60c,9b09cf3d,26bf86c3,b9a23ea3,cd329138,10099048,d18b031c,d2b7169b,ecfa1055,70d885c4,adcfadcf,66f12d8c,846f70b7,12004097,840fef1) -,S(73d8d4f6,7d602f61,3c3595f,b9aa05d7,a23bc4c1,1fa3844e,92e6b79a,40220f96,bf722a2c,ffc9fee5,bea18530,9ecd14ec,bb17fb3d,568fe85d,331575ab,2400ce3d) -,S(e8104df9,f49f7822,152bcce,79c6df0c,8b1e9745,448c24d6,1e7b1180,99182b75,dc2fd539,ec8f2beb,1bfb0da0,f95ffbb,e14fc682,1c5d5023,96b1253f,82137361) -,S(ecd72ef6,fb6c432c,8e1449b6,d16180e5,777e5524,4900f209,e89e995c,546113e6,1671715d,358fba99,e509f518,e1458600,4252913e,268129e0,e00d64eb,7a26e135) -,S(e3b5ccf,be829bd1,6f1fc6b5,fa6d7c35,464bfe10,7e9d6455,a9907050,a4fc36cc,ce7abb9b,5471c1a6,de17a2c9,b5b671fa,296cb5f0,10b5ffa3,31e7a87d,a28044f5) -,S(f3591a02,ffab91d4,eb7e75f7,f4ebd22c,41c1ce4f,25f89c5e,d7ca1ab9,27107734,345a2e11,f2bab926,487c7d53,5314bb6b,cf04746b,be2edc10,18a57c2b,94fa4b3d) -,S(ca4b045d,ae54ad95,37d184f9,ffc5a950,c61349d3,227ae1a6,5501ad97,cb45c635,e30f817e,255ebeca,352f3c24,b441d1e9,4660f456,ce9cd72,eaf4c4b4,d7c1d806) -,S(f7cc5740,54a9ea61,fb8ebdb7,b76a95f6,30094720,675aaa72,dfd29bb6,6f41ea38,9d463d8c,fc5424d9,18275aeb,5e046be3,b3dd7fbf,f52d4990,f52c81e,b2556eac) -,S(f75b5f79,fba3e3f8,ee64bbef,7d34e8a9,b4fd9bfb,27b6a9f8,76b1f70d,ed6ab6c2,220b40bc,5c3fb77b,72c48e36,2745677f,7e0e8266,f85a14f9,d4030ec0,90a43faa) -,S(2aa367a2,5060236a,627d89b6,ad0a398d,89d86a64,735a4fde,e88fa4c,d9cd450,2bfedc25,2491b1a,764a802b,c4d77d86,1e70ecff,e9aef8f6,e829448c,d841fc32) -,S(ff7f49c1,11783cf6,e7da1e22,15827b07,a1078ce7,b1eb3257,65a37c38,a141620f,69550c9e,2e48058e,8bca8b54,21251dfb,a488c585,df644bea,d519acf6,54702733) -,S(31d05358,1164f4ec,a45f7338,fd3ebb90,76d017b4,5e679601,6fd02a0b,5c3aa39f,f124319b,72177ff1,462fa90,2e1f8d23,d4d3ea0e,d1bfd1fe,6bccd92a,9963f575) -,S(6eaf0edd,fd1203ec,a2cbf2f3,8da9ad7,c8a02d3,ab5f06ea,bb88fb5f,7e6a3bd0,d9336d01,2d8e9474,49c521a0,10a3b83a,815a0c74,a31596d4,125909c6,73e05f08) -,S(b95a519,77991ab7,fc3943ac,ff5fa88d,68e759c8,11cb91b9,e9a1ba97,7eda1347,8cf2cb5f,446d448a,5a98fbfe,75a2ffa6,9758bd15,36eea87f,533822bf,6de5ef23) -,S(4e5301d4,8ce5edba,f3b1dc21,2e804e7e,1fd386f5,6b90eeea,da6c1c58,211427e8,f503ec3d,e169fdb2,e1d2f684,cbd9d684,dcabaad9,376d96b7,6fb0a5d8,1b9f0d9) -,S(4fd1a9e5,9031b43,715f92cd,c49c2d0a,fc7c2b54,ad61d7a3,9142033c,3cf49cd2,73ecc11c,ab0165bc,3ab4b43b,ecef694a,2d99c9be,8b877160,2c885a6c,8e4adcb1) -,S(67406865,b32543fa,5ebb7fa4,a8d8fae0,384070fa,2e8a4b86,74510099,20257c84,3fdd9ad5,93a4e0b9,4f4451f5,e3227df7,e829a45c,ef3d271f,3fd85896,bbc62008) -,S(14b955ae,d6ee5be6,ef3dcfa0,edac40a0,de7e8dad,19c8dcb4,e4992a65,a46569e4,d4b920b6,21823f81,8481eff6,761353dd,7d9f31c2,5ea9d1eb,ed60a5d5,fa2daf70) -,S(14f283bc,5608d5fa,dfaa0b3f,fe42fd20,4003e434,c6368fb7,22ca5f22,3339ae42,b2415e3d,c3aefd3f,c644d4bf,b0a87fdb,bf0ba630,2baec8c3,7c1577cf,9edb7397) -,S(3fde0c67,7d3ce20a,6e6275be,7f80cba8,5416a55c,58dfd09,8e733a32,1fbd1c1f,9b8ef7dc,610f192c,949782f9,bea1f08,9a018b25,8926389a,1155d033,1adaaac6) -,S(9c55e669,df5f3d05,f15c74dd,48290540,b993bf4c,41dd9247,df5332a2,ed17267,23db0ce9,30c97665,175abd78,33757fc1,8c6b3c32,2d260810,981b4e0a,6e4979f6) -,S(bde84df,ae141a0d,6e8da60b,30f41746,506d2dc3,4b3faee7,d8568a92,82968d16,45a33214,ff1361df,e724697b,99a6c686,900374f3,6c298dcb,468f38c4,4ab3ab04) -,S(1940294a,b8f3c2ca,45f68f45,4c60c5a1,e5d97085,946b30c0,54939daf,c99546a3,563f9f99,3816c62a,1e60ea76,77c61bb0,848bc926,e76e386a,bfd96bb4,ece3b81e) -,S(dd6ea1e0,d0d13e64,7d0df92e,ad22d838,757a34d6,373ccad6,6829fcce,b32ccb0e,c018e9e3,6bf4e8b2,853ad27f,a49e5ff8,384b557c,aa00c3fd,d8e008f0,ee33c313) -,S(657847e8,c7844562,e26656bf,bbc27b84,dc104737,42c4dffe,c0669616,5b7fbf19,dd90dfb6,58b6ada4,901beda9,a4a9a8a,42c6a4b4,e79a4172,5b5f6ab6,95f2df5) -,S(fb7024b1,40be9d6e,906d26c2,edb781cb,49b8e71f,396b8d3e,352506b3,fe3dea6b,de408ff4,e50b2328,b6ad961e,9dd1ac46,fea36005,1407061c,5a0fca32,eb08efdf) -,S(2d29c008,65a7b279,d3a80179,cd3e8944,b3f2be0c,49a398df,a3113350,d1d8e8e0,caaf127a,ee704a4a,65802748,59649e45,25c55005,f2667ee9,92e9d923,daefcf8f) -,S(db690474,79b7209f,4de8d42b,a3c1be3a,39268589,a7c33632,6d87c1cc,53d5662d,90de8be9,5c3587aa,9913ce32,c83e24e9,c58c1fbf,2922c63c,b777770,fbaa4e00) -,S(9806506f,922e4f0a,afd54ada,258d6fc1,723c7087,ccf13f0a,df247356,c941697b,c07e2018,a8cab841,37698eef,3d31cad1,b97fef49,77b277c9,25245a12,f16bc237) -,S(ab868d3f,e6da25ac,5b11c112,28f14621,661e0ad1,e33d25ea,ae1ae7af,60e40187,ee24b698,334a9850,1a1195ce,d57a7fd9,4b12c488,bbd301d4,d47d5f13,3cbf54ad) -,S(e7561fd1,9d2a8ee6,12056be1,74257e28,3122f366,abf66f49,31fd89ee,fd8dcda2,2052e74b,e3656d8c,5c766ea7,3227b75b,85bcb190,8a07918d,5a8a8001,3e166d5a) -,S(5f19523d,84bbe307,be08f2e0,fa844cb5,7b562f01,39950820,83c2df9b,e8f21e6c,3a96fe16,28ee1dde,2ae9ad2d,5724eb88,33377542,6e91acb9,d9be7c41,7265d7fa) -,S(c9fa4668,3c949b11,2422ec1d,c5501efe,2fdcad17,255c7545,69837d28,d9c10cc1,1aaae75d,18f691ac,cf1dcd8d,9e8e0348,b5b6e734,76d47ffa,b5e23ede,c7fd1dba) -,S(1da90e2a,1e911879,ccfa084c,393b8205,1799b2d4,15a42401,b1ab793b,beb8d8c,3d3f7c69,11ea4d38,46cbae1,53b3fc32,74994ee5,1f4fd332,2da4d28e,c89c0b63) -,S(c6fcf10f,3851e432,6bd504ac,b7847f7,707e4098,d8f66915,3e6f89ad,f31b3186,d0ac89f4,a16a63d8,6e36ea10,8f8ee5c8,4e2705af,a9c98bff,3ea5253,93a50ced) -,S(15057a2e,eb56c67c,cb6b7d4e,f1257ae0,3cf236b,1f9b6588,fefd7f46,16378233,4dbab530,ccc0a7a8,c49543ef,5e3d0a87,6f205a62,2f9a90cf,5054bb0f,dc4930c2) -,S(37eeaee0,72d5ac0e,6ea7337d,d07ddebd,45bf1cb7,8c02dea3,6d1e419f,308b20f,b0c64496,5d9daa14,19c77249,a32a3a3d,a5761adb,bf5a394a,ebb91630,f361d506) -,S(5a207bf8,3a8bd0e3,3c71cd96,d928bdc5,f1d6ce8b,7ad9bebe,61a27362,2557745c,3accb757,fadc9b6a,2a5494ac,15744113,ee878901,323c6138,19ec7666,60f54dad) -,S(fe08dd6a,1a0fe325,5a391271,e81befb6,f6b2ee08,907046d1,642d39bb,fbabd139,42c342d1,3535822e,e4ef1b43,69f204c3,665d2326,1379b0d6,c520c64e,181ef40) -,S(b7d262c9,8dfdbba,6483edcf,38044cad,d6d859e0,3d1ddac,a39cb999,78706111,96086350,b308b397,6a007c8f,5181b5ba,30bb4c11,653d689,ee97fe47,28d798e8) -,S(4b12ab2e,23b33775,3ae97d7c,1badf5a,7d354b57,dcc78407,6836f802,34130c86,419d4e0d,9f708bf4,2e11e73,a1fe5815,2bc9649e,49ae45c0,f52fb8f0,f23c450e) -,S(fc6d2682,a96eccda,4b49570c,8bcc47c4,8f362bab,7750b4f7,4f30cc49,d8e88dac,1af56527,30264580,d1f22612,e90597f8,694aff0,96001848,8a243ac,f4beedbb) -,S(c7b9c3a9,a189eba0,54742c40,c4afdb9e,5e07e6c0,e442cf06,32e9b655,1e607e8b,5bb68277,2f2274db,62084cd1,9c1a545e,ef6b38b8,d4dc3e30,fc58042f,f01822ab) -,S(eba4d342,30dea72f,29a339ba,3ed4306a,46c761c2,bb6f9627,3406fa7,50dfd956,fce17a0f,23d278b2,e3da1747,706840cd,d31b01a5,8793506d,2155cbf5,dd237cee) -,S(a4d36dc0,2177d471,35b4358c,6adec285,3595dcf4,6cd9acc8,944a569f,82c04155,85a29779,63b21be0,e378fd0f,b5a60fdf,65f3e45d,c2fafad1,13377f4,81f00281) -,S(4916d063,ae8bfae1,e3f5bf56,fde73abe,eb165aa,4e6d4a16,9060ac95,76109ba2,a7916703,4a0b40d5,f967a08c,a536b7c8,3b2b0b4f,67638656,4ae9b4d4,4c3f22ee) -,S(761cdb10,b2966030,85f8f1a4,404ab49c,9de01979,85817f97,ecbae412,eedd046,1d115720,763b545d,72f8f50a,b881e7fb,9789f0ea,8dda90cf,2ee2f3a2,2e193db7) -,S(d7a2570,4d718e92,df85541b,490bc13e,860ff014,e8ddd9d2,e05fca2b,8dc64ea3,5e454b9d,21346767,71c0e035,fbc6dec6,6102db85,aa3acace,c158f43e,534cb90c) -,S(2af6004f,7962c52b,b0ebcb06,32975bbe,a6b9a99,4dc5a5df,eb20a43f,3d4d3bbe,6988a9e2,26f8cc15,3108e3e,b68c6596,be1deb1b,53239933,d91e095d,d81a14f3) -,S(a92740e5,3bab0860,1127571e,5d33184f,ca805d18,75ba4959,74108f5c,a9504255,5df2851e,2eb76b71,66dfd3d,3aa84e0,96d49c85,10daa44e,68d75eb6,c6d2379f) -,S(90d0961a,510d8a6b,60a87c44,93a0c8ea,76856770,d076057,bcc7ed98,70014939,74d4753c,1c913088,66b6f7a8,a2386ad3,7c13dc2f,85b4b4d3,f8d7603a,ccaa545d) -,S(ce52bea,f2e3a604,f62bfa27,92e2e083,8dd5c6a6,ca338ded,249be611,4ecd12b,a869de73,738a0a2b,7c824444,925f3d9b,dd08670a,8f8ff1a1,a4988008,2d5c009e) -,S(99ca8dc2,10e3fcd2,ffd39a47,1c06ac49,12215441,6cf16be7,cc3e350f,f3cd05c4,78087a80,131adc2c,6bf26309,ef0720be,4550fbe8,912142,c6ce496a,dfbc4982) -,S(be442cc2,9f5a7bc5,d07ff1f4,322deb90,cbfcc6a1,7d8e611a,b51ec610,a202d1c6,6250f2c4,680ed934,8028f2c0,1acf5bb2,fb3d1f25,e324b734,11156128,77c084a2) -,S(53f5f5f4,37fb010,2130346b,51b9b14f,e75d95f9,b8f80e65,67770bb0,e4ec8e54,8da52b53,c6e733f5,aa0dd2ef,23e2e1c2,24c0d571,328520f9,cb1cc5dd,28c62f93) -,S(206ce565,e90ebff,7d799e3a,134a56f6,a897ab19,186ed554,11de6daa,5c8c4d6c,c2ff5d22,bd2d6dca,7dfec5c2,e79d5320,aaa5d53c,38ae0675,4dca9a96,a6a75804) -,S(d1dcbfbb,87ee2fab,811f2a72,726d2b54,2176a20,cc23f744,faadf2ac,7073f443,106c63b,41800bb7,bcafc27e,3f8337d8,f71da693,e1f4350c,1870f968,edd17db9) -,S(d21aa173,c54376ba,1eb9d432,26ffc9aa,a516fd0,ef17c2f6,db117392,db749328,37cf5df4,e01480d6,604f79de,63a754b0,2326f9a4,ed74cb24,7724c682,6074e424) -,S(5234b024,a22c69a7,569acfbe,2cbb7ce6,15e56383,f8e1e031,78dd54eb,7d1fa3d2,2beae442,651db52d,62bc3b04,2a5b343a,b4103895,a74aeddf,d9189630,8bc000cb) -,S(9e6e9875,9f3e21ab,a709dbd4,f598894d,f5048dcf,5ee6cb6a,50941c13,35412f64,2b670199,e38f2e5a,424dd169,e047189,43111033,a7e4f4a9,2dc26906,31757ea8) -,S(8416e295,9a718e77,10df8a92,72de9bb2,89232c73,832597fc,d28f2928,8743ae45,6ef49202,801b408e,d81b7904,4cd1f002,20732a74,764c44db,4c77121f,1133d139) -,S(852a4fa7,48a3b2f,326405eb,e52ba2dc,27462f72,9ea3429b,b108e27a,d53561a5,3e06c046,ee0d9c23,6b0e441c,2cbeb672,770b99f7,8d062ac6,a81ccaf3,a562e520) -,S(2880dda0,2dbe56be,b93b876d,3c083ced,fa6097a1,cb234c5d,3282942e,3677c1bd,dfb0ea10,92d46bb4,fe95366c,5370dfa2,3d371f78,40e919d3,bf966441,f1bb43a) -,S(cb6fbc02,9e828d7f,c03dbf86,99a676a0,37b53555,275c86f0,7709ff89,f1819c65,fc4e2d9a,36577399,15cd50c2,1cb76cb8,ce9161fb,e05babda,ce516277,86062266) -,S(8087bb5b,ff1c3438,21b24106,606d0ec3,abc76a5,8a872161,5f6305ef,f81afebe,578b287a,a602c02b,8f5c5030,ae9a4632,23a4437e,944f4353,d9bc17de,824ce72) -,S(369f54bc,30f2c90c,7af0def2,2517ce58,f8ae829d,124ed482,653a28fb,42d3a33a,b8f2eaf,35af7e32,c63c97ae,f5962143,61f466bd,c4cc1b40,b4526157,b9b59d16) -,S(87be4c4c,1b2f871,53bb2448,ffdb6ac7,df294628,6be49eb6,edd3d533,1fed8f7d,7ef474bc,6386c0a1,5771ec54,21cd51d0,71fdc8a8,66938a2a,dfe6f4eb,ca0effb1) -,S(7b6678f0,18f75bea,8c310eeb,239edbe2,80393f1b,5eed1cfb,c013fa29,1e14715e,78e8b8e2,666ee69a,7388275d,2aa1bbf3,d985707d,3dd52890,c181a8b1,f38b1fd7) -,S(89ec641,96729e02,2a9608f5,8fba388b,77d2826d,6b37caed,90d27394,b160f135,5def3142,108d7387,19ee5a7,41deb18b,5e3030b0,d919a1f8,ac94157,a4786cff) -,S(2cbec739,3769090b,3aa2acba,b78c3fac,8b83749d,641f9311,99e6d1a6,36177f8e,3140e7e7,57ad2d5a,cb34a007,f4f26aeb,67fea7cc,8902fbad,2ca92083,f3de8886) -,S(678cefcd,a2d6a58b,53e7b116,d03020ae,29d57618,4663fcf0,2ebcf0ee,bd946908,f45be9e0,13298eef,37cd56ee,932b2a41,18834fc4,331c1713,314bd028,e6a3491) -,S(8ddbd278,adcc4ece,4692305a,94cdf011,5073b073,c88c1524,b43f1822,c73ec0df,90510edd,3c52c6c8,caa9ea1a,e28c7784,5d2d675b,a33b1022,68b93b17,80fc5b0c) -,S(972bf082,b162ff5f,22b149c3,d238260c,607d7878,aaf70739,3041d0c0,d7e36626,4685b3ba,f61cbca4,d99b64f4,3e90a442,6eca9f24,d0235324,797505be,4c4087dc) -,S(42af0d52,66604ab9,7de801c5,4514d23d,d8c1f760,bc86280f,540cc57c,bbc97230,5649b89,8c9029ed,4357160b,d97b74d5,cced0668,98de3b89,77192bec,1699ce38) -,S(5366770,87296d1d,8e6138bc,a9a1a0c6,1748ee21,4c0410a9,fa5623f3,d7bb30ac,e0683a60,786ba0d3,52619c2f,672d90ba,7c297b2e,59591f31,fd8b8fd8,ed5cac1d) -,S(a03b6284,e85bb18f,f04308d6,bce40e91,7d5d0ab4,ad920255,9de55c11,fc39fc24,2739ee82,c22cc348,23fe7235,a939db8a,c073005b,e014b564,4cad5a8f,e8785493) -,S(2f394ed7,268a53a6,bd998055,a24f7dd,f5801dc9,99233a63,7332e24f,26b66e97,b52b4f3e,e934ba86,d1bd3714,a26bc4c0,e49d09f,5d055413,8d3f4cdd,73918d88) -,S(91773010,527e537e,3aa0c19a,611ef5fe,7740bced,ef0b56eb,bb35a12c,7133f8ab,68f937b3,28b64809,27e1063a,bbbc36b5,b097ae5c,ccfbb965,f4814f,ea9fb5b6) -,S(2851bdbf,cddc8af1,7a20c1ae,bd529df8,28486bc5,50a00b24,763600d6,904af615,d302c085,702e27ae,6d46c376,33035d6,ee2acfc8,3b731758,5d15b2d6,dccb1356) -,S(e986d7ab,25499f1,45610b79,1b47e597,8be3d363,5a6f29c2,5d34da48,314bdfef,d0638dc,b3b3c150,10ec63b9,61104559,cfdb182d,31c41c16,5f53c331,47de35a6) -,S(bc45db2c,5639b2ce,2dc1c5e0,d831d824,ab44daca,7fbfa099,b2e648e2,8f8bfc03,5d93e3b1,27b289ad,49e32740,a9f53e0,79a80580,82606884,2c1f9b52,7213e32) -,S(4145d67e,47d9809d,2c67b4c8,49e29101,849ef512,ca7b22fd,667498cb,50a8dfc6,5471f4fc,2a4f7f82,9708604d,90daa64f,daeae007,d6290ea9,4922173a,4513f096) -,S(2d157f7f,4cd79d56,bb15314a,a738dcea,427e3087,e7a5afa3,c1ad740f,5c686825,c1c4f318,76159f4b,94e7a29a,2766bb46,962a4e21,3a7234ee,eabf1ea2,296fc1c0) -,S(2f426284,77040b2e,5dfe26cb,c12a81b,d6e89696,8226987b,361d7961,a73933ba,bdce120d,141b2879,effcf601,c75532f8,a384f942,879f24bd,45e483d1,8144075e) -,S(b419cfa7,6cc91302,e683c9c0,eef23ca7,bf9f8f44,37ea220a,b8a1fffc,3bbf527f,bb86954e,290f2419,e4891a70,b48806b4,a911e956,e3cd0dba,3c0251e3,aa929517) -,S(cdb4a6f9,5734164f,c7af2913,f0ded939,2b17bd09,b03698dc,ae2d72d5,4925236f,89eda236,bd1bf5d7,e500c47,d4996451,d57c963c,4f125ff,c9ef8e6e,aac8e7aa) -,S(ed4ea751,a45ac44a,33e6f2f1,50392fe8,a12a8c4c,2233ca3e,321800f8,f408c256,9c7e9da7,4a2b349a,ae9266d4,d04d912c,a296d963,98ace64a,caf40634,970ffef2) -,S(9b06fd38,fdf963c2,830ccfcd,1df08a73,84a74b02,fa79a87c,96decd0a,3cfbf5d3,e866461c,e7ee6015,aec4ba3c,d4dad0d6,3ede27a3,2a1b20d4,eb29de00,6b226416) -,S(df11481e,efc1cd1a,97e13f1e,e0702056,c2b7894b,de1a44ef,5166e521,1af6ae75,a1411856,35429fa1,ebee1f24,de73e2cd,80c76661,717abad4,a8354aba,222b7e02) -,S(f8328d01,b1f3fb3,d07bc65d,e807c619,46e4df15,a518a845,23da032d,12a3c9f5,e29dbc74,7746d478,9ca9a6d0,b5ca9ebe,de174914,7a709df0,d5e0f100,cdca6216) -,S(3e3afbbd,b7fc2301,f9a13590,acc4fb5,ff0d1b7a,92e09e46,1fcf0093,4d3fff86,1fc7f7e1,b9821c51,bd44c8d0,9619aeb1,a5c2af1c,3ec28742,f0f26212,6eb6ebd6) -,S(aad17eea,68348015,9cc19f8b,69d335b4,78ede880,4c551660,74d1ea9b,1ff86125,e993b8c,ebab89db,67cf45bf,361ee910,dfa1749d,26b488e8,ed6cf9df,9d365257) -,S(213fbb19,5515c686,fe8f44b6,fe26a178,286442b8,fb29072d,37ce9972,910ea35c,497b951b,7df7f4bb,2d0ee577,19876203,d68c3958,62781362,18e8969d,ed52a852) -,S(cd7f72a5,78ed819e,3e93321e,c8b8c7a7,eba91b47,92821a2,92493790,370120fa,a3d51c70,99280f2c,fa2c537d,991077e6,ca4eac91,93e97ce2,d8ff5fcf,45bb1148) -,S(70a360c7,a72939,f9a3a28a,1d1a9e2f,8240aec1,878f9b19,68923e0,b67f3b51,a1d9c07c,53a4dbc2,2ea4ae36,b6a0bb8c,dd175c98,6d2f61b7,3eb05552,ad710259) -,S(544a615b,4f8e2b66,fa1dd19,99e9cbe8,eedc35fd,9cda6d33,7a076601,21b5e46a,75d26db9,c76fc8d7,65286aec,bdd9c97f,d7ba7a9a,7308e6bd,75150b35,ba8451e5) -,S(4218d79f,76a073d7,af19b265,74d5b5c8,f8b779f7,36c23c92,a01c3467,8ec8acef,6815f631,49073b5f,e65c05f4,eb284c21,87e60355,e207cbda,f2c01eb9,becfb28e) -,S(6ada2638,1a82acc1,8a333759,8635f83a,3deca5d,9e4dbb38,64a2fc1a,a269b0a9,53d356da,65f7526f,60d05f32,b8b5f841,2e77b6f8,b61533ba,e8ace229,5eda6c08) -,S(5fa99d01,d9f29a59,75518e98,7c382c41,8bd46ea4,7813f579,3366618e,e118b09e,d479d238,38deb81b,dcce381e,4982652a,f15f6602,dbec34cd,6fc0e82d,33fc3b39) -,S(cc6ed576,34cc67ab,6ea676d7,2fef96d3,bbb4a00,b2b7fe44,12d0195b,44d76f6e,b15c15a,d50999b8,aac9e5f1,5834284f,dd801b0d,da4be94,f520af62,f7bf820c) -,S(e4cd0fdb,5323ea3f,deb10bf8,90a26b6d,ff447679,d8747ddf,ec32ee3a,40ffceb4,fbdb40c8,ba9c4357,656af718,db7629c4,e2caa87b,c41f8c48,d5d86a30,d220e1f5) -,S(77fd722a,ba51b929,ac1e3ca1,a2346833,b3c1fec,7a756568,6afb7cd8,9b88a8af,d02519e1,d6e9cb4,4f378ee3,1df4bb74,6b5b555b,2c7b0691,9cf90f5b,3de98505) -,S(4d391fbc,a9dd3d47,9d3ca57b,f299f4f8,6291e523,95ff73e2,665418c2,997a41dd,5cc9ec33,b55e606b,b93e9fcd,593c43f3,e5d4a3c4,39ec6fce,1a9ebf25,b4ce899e) -,S(740bc446,17b17b84,5c99d63c,3c92fe81,2eb232f8,8161a2ba,83f3a445,73084e97,fd8ec6e,f4f9567,71717481,c1301876,fb10742a,99028c67,883254af,f8355464) -,S(c258c21c,adeb8453,5bafd8d6,cced030,c6aa12c4,1bdcc392,b2d10e5b,1b46e5c,7cdf037f,3e60bd7f,739d08af,a20de5f2,b73646a7,5ec3e2af,4cb62139,5d171d31) -,S(8fc88069,733a4d5d,bd80261,c0c9ca65,fac22a5e,1bffd768,dbeffb83,24130d44,4211a94b,f88c042d,54d37ba7,41cee691,ca5bf0a6,38f0ca95,954f4aa0,12fc946e) -,S(cf62ee1a,40321c24,7fbb0e0b,ce99d314,f5152de3,32b827c9,67a61bb9,c96ad4c,6284a7c3,e64f7b8d,4bd978c0,77dc0d22,e6137336,6410d5a1,9bb09640,1ec4a3fe) -,S(53351f8a,4d447760,ecc88443,19b69160,bb00b3ca,fd6fd9d0,6c0040e4,549f8ba7,83844e19,3816e6ff,755c148f,d5488384,c7c1cbb8,8c09ea0a,16352bcd,377f6b83) -,S(a02063ce,ee2c9191,94d0e1f6,2ace9407,baa0157a,d2e600a9,e173348a,1d06bb0c,630461b5,55653f52,da9b40ea,c4448a8b,fcdaeeb0,1007dde0,5f4c186e,9f146339) -,S(70bcbdcc,25de1764,7274f374,196608aa,c360c09e,951b9857,5a6a8d6f,e1d35660,3bd5bd9b,716359ce,80b5e719,a9e1d40c,3a1c7430,94a82b64,a90b0f4e,db461d74) -,S(df8ad77,83cfc3c0,6fbb1fe5,2a515de0,54b161c1,74155fff,13812d19,aadc8fc7,bc4090f6,416db0c,9d34ff20,a0b7cb99,af38401b,1264c604,44ec7355,80069569) -,S(2504e9cc,ef399800,5f2fff3a,452d56fa,8788df47,e05509ed,777a9d9e,540a30f9,73c506a2,c6f48efc,af7f4d2f,ab5fd833,6fd6514e,db690a51,11659f79,7390612a) -,S(24ee0724,1c920334,3a6a6fa5,68979fce,18a9ce0c,819e3a61,571141a3,5bc97025,ee642ecd,605b84e8,68940a6c,cd7f4d93,fa0c6816,2fb0bf6,ba22427c,b0bd7b8a) -,S(1ead5ce0,9665c05a,63cd8eb1,12097f35,4961e12b,25c03093,e1c6d919,7a3929b3,1800df5d,a1abcc4a,b1c32fbe,a1dd7120,7284b5f5,dee7009d,c2f4aa6d,7156fcc3) -,S(47cf2ff2,26084f8f,9020b0dc,d838874b,160c69ef,2e5e89c0,98e7891e,ea05d507,a340d3df,129b5aff,1044d0d2,c3866464,bca2efdc,8dc83516,cf8fa522,d5fb7d48) -,S(4064fb9b,8e2e4952,a218bb8e,ae474a4d,51f050a8,3f9a7e75,b04e39c4,42d6cbdd,ff9cec76,a2ef1930,92d3e02a,aaddce0d,18ea66c0,d1adfd2b,9c7886dd,b835de10) -,S(838ac8d6,e58e20d0,321e0150,ba6d401f,cdd70a40,69d980d2,22de3353,fb81904e,993a6f96,2909dbbf,7b9a6b25,14153331,b1ef24fc,e892710,5f95488a,d95614bc) -,S(a5e36d83,189d43d2,34d6ea26,ecf5943,5aedee72,bc4cf385,5fce9b5e,e202f266,78c02c3c,e25c3b89,9dd2933f,b41435a3,dfc2d1b5,e7ebbfe9,54ab1c94,79822c55) -,S(9e240cbc,d357c4d3,34f31209,58d6f7ad,5ad79e7a,9b51f572,5ddc8fe3,1fba72c9,aea34a5c,ed60a062,ec1476b7,b30b3c9c,68cc5e10,cef9f0eb,6729172c,b511f06b) -,S(ad1b0646,bb315380,5c22b91d,1ee47a26,dfc9ed5a,860be0c7,ea8daec3,b6dc2eba,ee2e61a2,2499c509,1a910c9e,ea159873,a298daa9,6d30d8bb,353b9955,92dd2083) -,S(4f7b0889,11d8f64a,550d8c7f,11ecaa6,fa12df74,a236a0cc,35cb7cd3,5b0ec72b,931af41b,d297e18,b4d9ffac,8d7f8691,29b94250,f1de1d99,3e31525c,4dbb21e3) -,S(dab2a170,e4108f3c,93fba874,70bb12fa,834d0274,35695870,d2d3523c,93d3a7ee,262f12cf,c37f010d,deaecb24,d08ce35b,293a5c6f,1746651e,7bb0b2fb,c573ae4d) -,S(3437257b,784d72e,419e5082,311b5a66,d499f687,c4bcfa31,7abc7484,a3cf39be,ce9bcf07,6da8d68e,8453fa14,3b06d7c0,f38bd0a0,76f1cec2,a49b3bda,a5c398d3) -,S(4594ae9f,82611ab5,bf786024,ea34bfaf,939fa409,34ad155c,9ed5e736,899545b,2255c7f5,62b0ba72,c3834e72,e77b478d,77d3f15e,3ee0cda4,c4b3f928,ead450f5) -,S(7337705,12db06fb,36b21fc,26b585a7,3aebb036,b22743c2,f13212dd,81898819,753ddd59,725fb0a2,561cf461,c587f3f8,848b53ed,29283c51,5150c57f,50307887) -,S(bd915814,4d2afef3,552d81c1,8c74abc,a53f4c2d,654f72e,3f2abd66,d69790ff,1af609e1,7f27e373,b42b3277,a5f4714a,31ae895b,95e0c5b9,50e7ed2d,1827763e) -,S(8a11cd4c,a51dfee2,28c1ced9,3d8870d,67782740,1f49fc73,d4ce56db,915bb557,d30ad7ee,ae9f9c97,eec27822,9f47100e,ca46b3f0,27339719,6be0f619,56f5cf23) -,S(7929b5f0,2802bfeb,6c23e688,65b0272b,cfd058d7,c0a45ea6,97d46d87,6f9bfcfd,f9bbae21,8039783d,4d1e366c,32a890c1,8c80d1cd,41f08b36,963b54e2,f4fde5d0) -,S(80df06ac,1d5b966f,8080e79b,cc9f01f3,d55f8855,9b1a58bc,f6e4c526,3bd89d01,346926d0,a59558a9,2625614b,ac010f36,5ee5c337,2660fa7e,be41aac9,41136538) -,S(74545478,9ff383f2,94a92b4f,383ad13b,ed4b01da,d20f4ac6,efc83315,be5ccaf7,36489f77,81ee77fe,de1ea165,c4cf2b5f,e8217361,9e760cea,fae777cb,c160fa9a) -,S(2c6d35bc,b213a8a0,95c11fdb,42828b7f,e562d7d5,f877de67,de62bcd8,5af8fe85,aa30e370,34094f9f,4502206c,72f23298,2e60139c,2bd35631,44dbe6b4,c75d159b) -,S(8353657a,9d934eb0,2811846a,728cd162,4b43429d,304aa7be,830da70f,b2e338db,f8400438,20ffa5d,28189c5a,ce693c8a,ed4a4caf,3aff83b1,66a9d404,74e02b71) -,S(f216e93a,54ce56d7,c7ef6336,561a6299,2177ca73,4ed867f6,fd1a8ddf,aaae494f,db0a3f13,a0fe8326,63e8fad,b11cc347,8da296b7,2f1b672,3f43ea44,acd30611) -,S(dc371221,9b5d73f9,6562baa4,b62ec7f4,2e9a3dc8,de6e7112,273d0811,a88324fb,eecc9092,ec563e96,3720acaa,929f9bb4,4f1c9015,7c3300fb,581b154f,df57c004) -,S(db34736d,48f0b4f1,e1ef6029,6ef534ae,b10f047b,4256516d,d4499072,36649475,1c29cd6c,f7a8c786,952c34c9,b93e5188,1a116966,164d0fdf,dd1be4fe,ac586bec) -,S(a248457,20468424,f355af53,62f5bcf1,971b09ed,358fbd33,78fc7297,3696add,9a703d61,37d0deb8,a3767a56,c2e24573,baffc931,bc850694,8c9a3776,26547803) -,S(bb7b806f,a9ac753b,bbeaa429,31f68d0e,3eba38b9,8fb25ed2,40c9faa3,124436c4,8f812574,a1a8bbe8,d9b682e3,d9b0150c,7c6ff9c,f9b42e64,6e5836a8,12426752) -,S(6703c476,fc28a023,f6619427,69e0f068,489344aa,74495ad5,17b096ff,c3ecf446,8b48023f,7c9ba723,584211a3,6731e14,f42699ab,522e15e,ed3ac43d,28e2a38c) -,S(bcaaf8e4,bfa4b448,fe23f3b7,a1612b82,14cf0daa,349463b7,1b44ba61,e2dbf6a2,bdff2700,e2cc953f,e9d08835,dbe8793b,b07498ec,68ccd736,d6fe1710,d5c7f404) -,S(906b4fda,1a557220,1dd5b446,d726a2e6,21794517,3ec74f7b,bfed8791,9310cd49,d753f2db,cd2c4d28,d0304bc4,78690871,cf838490,2d7f4f93,441a74d3,892653cf) -,S(9ec09783,18f7d95,5180e326,e1bfdd04,fa5369cd,eb786905,8d726ac3,9ef93d5f,9cca8057,994b1641,53ac6842,4d28fb70,ad22baf8,f894a049,d1794add,97acf205) -,S(53347906,b75440ec,28362a96,f114d2f3,6f823cbe,bb0030f3,a2de3314,12b8209d,ccb38e0,471f8abe,47ef1bf0,29550ec5,59581680,3e19034a,b06a090c,ca0c1fa0) -,S(27c53f29,61b70480,93e24b18,eb357807,a33e5411,15215337,3b98f80d,d23a4870,5a3f4b8d,e18636c4,71fc70e5,9ac8c4e4,703fa5fa,880594fe,2f3b888b,da575601) -,S(921927e3,7a115f9a,12a616ba,cf55c213,22ed51a3,e75caa5b,eaccce75,de59b68f,bdbb7c7b,c1e4c5b5,98afb590,6263d779,55884e71,17864ae2,e0636c4d,727b141) -,S(973b3c87,6eb81ffd,677c692c,ae432751,efb3e609,1a3d9ff8,dde6cd6e,3f3ea8c2,340df771,129510b,a4112c5d,adbcecd9,8684b0ae,3a9683b8,49aebdd9,57bbb0ed) -,S(20b817de,f0533767,9938ef03,69204700,d5972c32,12656ce4,205e9ac,1b01ae71,2ae2fe5b,e2daa016,1c65c352,94a0abc5,c6b1ce64,fea99c12,34a14aa8,8395707b) -,S(63e2544f,7a7e9181,7a347b7,f72eb43d,ca9fc5d6,3d931402,aa6889b4,a3c95876,e62aee6d,20d714ce,5cdf52,18bd5fae,adf49cb1,f86e6067,f91cad71,280d16b1) -,S(2f90de10,71508cf0,b3583abf,c47d762d,a69dd472,e4183421,6ac39753,e22aeb80,5371bebd,4a0dd74,625e5e02,5a118488,880f3a89,9c23e64b,76193abd,3788d389) -,S(8d423ce8,faa96d05,45e37cf7,5e5a351f,7c9359c2,ad1c48a,c9adcf29,d2ed7209,83d4b83d,ee76c401,a18df794,8a655c3f,bb9d23c1,5ac0bd6e,ea80b129,bab40f2) -,S(12fa4142,5e028aff,303111a2,9144242,a9c91d88,55b3ea3,becec110,80181efd,6b95b370,8e792b57,ac10eddb,362eb10f,ee5c3b8b,b2e37d4d,c4d2ac40,e8c3ff57) -,S(923ca95f,2a3bdd7c,d7505632,cdf2d730,ce70196f,ffd0cbbf,f8347882,8a706f73,f8b0c866,c39b6173,b383983b,210cfff3,1903afdb,cad0b2ee,3e541ab5,2746abbc) -,S(844d53e,878240e9,63e3875a,728f4704,64ce3aa1,66209776,a869e0d6,88893646,c60cd291,92bf8c1f,f98c47b4,a713bc75,1c84f9c7,19fb32b2,5b855e73,6feeaca1) -,S(43786fd6,c5471d8d,ba277ff8,1005a5df,8838299f,66636b2a,65e7ac21,f1dc98f3,d292a2c2,9c8c5bbd,8f79109c,b8706fe7,745ff884,f98c127e,9142f52a,56091b51) -,S(6d1bc28d,f5e9ecf6,38783f71,fb98a2ce,bb0dec45,8b07257c,e94736dc,ae36d7ab,c2c54192,bfd80447,86214cf7,a28108dc,e2c00e07,2321638d,a0e80023,88d549e6) -,S(6bc4ef34,7f74ce3c,2ef3f89c,c3e265d5,6c742ccc,ff84b7f6,7d8956ab,16ff86c6,eb4492fd,2d2ab04f,1276be35,c6bde62d,be26a6e4,60c5c66b,8b0fccf1,79b46408) -,S(6af45075,fa810958,d42a756e,d08d5c,d67a62b,cb33cddc,b35fa99b,bf678b38,adbb724f,e7682c7,678ffc3f,ab738666,886c7b93,84960bfd,5287ff9f,ba5bff28) -,S(eb6d8b76,36466365,a96f49cd,355b7460,939f340f,905ad1ca,a24e8a66,55260600,7ae9cefd,aea30b7f,b9ba11ff,603b81d2,41f7a187,33f95c3,3c2bae0d,7fbea3cd) -,S(bd0c2233,2fef7d3f,6738dd69,4bad4cf5,b34d5e9b,ad6500af,11e4575e,91795068,eaba5c4e,2ea0b21c,a9100b6,66823a4d,a91c4d57,3aa9d136,76f820be,9d1cf209) -,S(c5e23bbd,c5049419,3483e083,14249157,aa56d9f,804374b5,54c9879,52b7e392,4caeb8cb,f684217f,bfdcd02e,3aa4ae3f,8d59e766,855b4fe2,f7f8ac7a,6e597751) -,S(b5717631,f3aaab92,5543edb0,3d21c604,17178e98,dea38bd8,10867cf8,8c92d2a3,e74209cc,324a9ef,8b31874,524dbab4,d2bdf0ac,8f1d20e9,a02409f2,8c11942a) -,S(9c456099,49601f2f,caca85d5,d30a07e1,b2d17b7c,7b838cca,2fe4b5e9,5d305cfc,2d7a1540,a109dc7c,2841b61b,31e50078,329273c3,585c8674,674ee06e,ff04eeb6) -,S(52ae2946,c0ab36c4,a8aff175,73b6604b,e33dae5d,73228d54,98c77a51,8aa82f63,70e23d9b,66061bfa,4d03f899,b65493f2,7179f5c8,643104d,24dd771c,777f87b4) -,S(149ec3bf,55ff462d,dc1ba490,384081e9,89db9ac2,c29efdce,f4f59f0a,394adf9,59c1d88,b91db942,2ae8fbc7,ce6951c8,49642b5c,df949801,341a8bc1,789dd7af) -,S(aff89294,d66718dd,dff83534,61538da3,dbe14a09,c14d0576,8a163810,42ea7ea7,71866beb,cf5887a5,ece2352a,cbc256dd,7b615491,2a88cbb9,a924e764,4d59266b) -,S(de44f478,2cb30472,ad52d49b,303e2b41,33887eb7,38e2ab78,da7bb406,584e76fc,6798ad84,25bad82c,57c630d,7ac8ef21,b13d08fa,830edda7,eefd23c9,ce482bf5) -,S(e0bc7a73,76169366,c172c88b,e1ba02c6,b3a380eb,2894e134,5a2ec7c7,39682e61,bd147eb9,33b18fe8,dfe7c0ec,87b7e993,5ad1f7c2,ab5424d3,c23609cd,262cb2e0) -,S(5ee34f27,2af69f33,9473cfa7,a536a22,ed26139a,71cfbb11,27c7a476,32f0e6d,c1df8f96,dc0d4d82,f6a57de9,85cdefc5,1316bf10,dc3636cb,80762aea,c4e13b8c) -,S(4dca3bc1,77fa7a63,9b8c274d,fe157d7b,67296846,bed5d13a,68bce5e8,e599a0f2,8fd2b558,36fb9aeb,fdb3fd75,8f59c8e9,2fb48968,52eff2a1,d01c32c5,3d2fb234) -,S(554f6bc1,87560290,ef9ed937,3e993f54,98081034,a03484f5,bc184751,f8b48136,b454c3b7,dfd512a3,517834e0,e8c3f50f,de80863a,1e0fd83d,2064a6bc,a172b26a) -,S(95a81b50,a6c0879a,6a960b2e,162dc22e,955af87c,b539eba4,20b2825b,85592ad4,be55e8c4,dfed22d1,f5872b75,f38aa4c3,7c7d5086,f67011af,2651ab0c,c45c712) -,S(907b6d53,9e496a6e,358d14d3,431f5582,44a4f8a6,ea291d85,3efb8be7,477e5c4d,b3d3d694,3853bb9e,67817fad,1dd7d1d5,ff33e200,2922665c,21f872e4,77150eac) -,S(8527c81b,b342576f,67737cb2,33f17605,c8884c64,6b7a8357,5bcccc09,c7f17aa6,b6d675bc,db8d5249,57b1930c,145777f1,9cd47b9d,33386a64,5044e8f5,877604fc) -,S(8e1e3a7d,5a320d92,4ea13436,f906e9b,bc6bf83a,819b9e9f,913974e2,efab00ec,d94f03ab,d81d5f25,c323dad4,ea792c50,792e07c,79281c4a,ff309e0f,f418b0b9) -,S(fc02cb93,be1f4a8d,9acbd86,bc68cb6a,dd0d8949,5cc7434d,72cfab75,519a8d76,71f7a532,729e45c5,98a6ceb0,885a256e,ffe4cd9d,967e84e9,8b73c772,7e4d4f94) -,S(cf981302,a2858b3b,b1ac44db,4f08751b,ff76357f,9b2ed6af,80a289b1,be6e7b8,237e9c12,bf23666e,70205ded,984f1fa2,f1a8a828,b88847ba,d3a1be88,8d73b528) -,S(3e6e45dc,1408e920,3ca74cbb,ac8d50cf,71718d1e,ba05228,e97dc4be,a8231d82,2e3fdb7a,2ad3a805,f61f287c,a7ef86df,961009e1,f0fde8a3,14774677,3b1ef848) -,S(bb047795,7581471,10809088,8119b0ee,3ce1b2b2,df2668b3,749b9eda,707d4657,95a72efc,5f95f3a6,af5ad697,7dbeeed2,8d6ee55b,fce29bc1,bc439168,75c67587) -,S(4e015d42,b8b02c10,4aba3103,4ce04cb5,fe356d,81291939,3f5d1b9,68dd6748,d35b20e7,dfbf6d71,d94e96ff,c9267422,746419fa,811bcd2d,d3942c00,70a870fb) -,S(609a4c57,90c8b210,9eb7391b,d68d078e,70850af2,410df867,92a37459,24a49daf,f3a6327e,bc965b3a,581cb14e,78a4390b,14431d00,d1f34e8a,e35502f,bad0e98) -,S(ccbe0736,2a955ac0,4e1b7558,a17ecf61,b9ea0761,305b4aa1,780bab03,a27fc730,f96b7c16,6c98a1d7,65ea4e3a,e0643298,d981a012,4b03fabb,71fc47f9,1c92cd3b) -,S(6ed60282,85df2302,e6b10ef9,4e11ce0,9143c569,a84388c3,e2151c69,c3ccab14,675ea3b0,687a3b78,e8fc7564,9665e62f,e91b0d1c,25852608,1d591ea5,1ad196e7) -,S(bdff05cb,a0cca14c,55b3c592,38515532,70806177,443dac7f,4c07ff69,cb49d8e0,5149ad04,86cd8ecc,274a7239,833910f,f09d7993,aaac9798,1dd106da,6e0c9a50) -,S(64ce68c,cc70325b,22be5366,579aed1c,af9f6e55,c2c7386e,ed579911,4e2bff2b,f8c89976,3c8a9a0e,ef61dddf,2213cbba,11bf1be1,eab6506b,d596aede,45cb1cae) -,S(cd42e46f,489150f3,dcaf3c06,e1e5a2f6,b40de7f5,626107ed,af01471a,18ab2bb4,d9c250dd,d2026967,b4c921f4,e253a788,17f11f89,f679e5c2,81dfda0a,1bcfada) -,S(f7c29007,e7145420,e2da7e8e,3ec4daea,5e9b121c,35c4ec43,59d55f01,89619735,66451406,4dbda93e,637735a5,6a06ddb0,5ea2933a,36cfa3dd,c2ba4a33,eba493b7) -,S(6339c1e1,d4944856,26b3d221,4715835c,377609d2,d91150f2,c5c1f679,5e93b7a8,efbe6dea,47b4e8f7,ff55a20d,8facb8c1,d10a6960,98762d95,be532fc7,3ed59b28) -,S(fccf1f13,7d22ed06,5f4bbcf1,e9f4eb86,7b1ec78,d9f40b4d,aaf58014,3489b37b,a5a77c2f,ef9facc3,881559d9,d9756b4d,6646beaf,21b3511c,64a4b550,7dbf3e10) -,S(da97ff10,6f284ec,f123b554,17bc8f5c,a13434d7,58ec3d4e,935c1600,404f62d2,65c2168b,4900330d,f2f1e3d1,cd8ab92a,4f308222,881a493c,f8b301cc,af12e168) -,S(6676a4d5,428a24ce,36957556,c1b44593,343ab6f2,21f0b9bd,dce2d898,333e4fd8,45bddca4,b9332535,f5f4d3d8,3467d793,b7afcf58,45a19593,854b1c5f,3daf7b41) -,S(791e6abe,cf461420,54a22c7c,d3deea41,53396e7a,2a619ccd,30212ade,e57859ca,e4033bfd,8c55c93,ec732990,aff43ecb,e2ec07dd,17e4ec92,68a7b0cc,fadd37a1) -,S(3a7c7bb2,d5181550,a78985aa,84b73246,c66dd947,4bd7c5ae,20717f31,af0018a1,2388eb17,e03cedc5,221f732a,9e505f8a,b6c38d25,184afd14,37b52d45,fe9d7459) -,S(249a2db1,86801c96,9cbca936,101381d7,62b74017,2b454c3b,ef720bc5,413ab999,da185c41,76aa91c1,d783cf9c,85c075e8,2f708e0b,3ec930cf,f71897b5,d1d5e7a3) -,S(b25e0d53,b4e0cc09,985f21e0,c5655e50,32c0857f,b792b136,14da6885,6b4f8590,1bd17aff,6b02e3ac,e1cfac42,fd28d837,ac5b80,42b21055,d6b84e67,5d83eda2) -,S(73605368,5e83388,a869db66,f110243e,bd1073f7,517fecd6,1359eab,b7862fcd,e9c7a02d,842c5a6,fa43407,6e12d41f,e767fae5,5a75e913,d6912536,6d5f9d56) -,S(ec2f0b56,71392e97,2f8a0c9,af259d42,2e5b52da,5e70fff9,7115c961,77f1b1d9,47f7debb,adb24e59,c8571fa,98e56d32,d49e072b,4fdec818,2049498e,908183a8) -,S(7d7a8fa8,250dd43a,91a2ad2f,320e18c1,afc25595,213778e5,cbfa6058,4be2d378,6b48ba16,89627d77,2700f11,9bc20d7,fab2b07a,413f752e,2a0e111,60fea3be) -,S(316a71ce,52b6723b,a67aaa01,e26082c6,6e59490,cff4c366,5c695ff,aa6713d7,d6f1c1a0,7820c612,12b44cf6,e5cb4ba1,84152ffd,cf82e020,e95af73,d6a1cb9e) -,S(21a2a8c3,ade89ff,c32e5fc6,ead97a22,9ace8857,11db9930,ade6e72a,9fbcca51,95fd3d04,38df517b,5712aafb,432f0e35,726fd438,a2b941e4,7c56c1cf,8882e4d0) -,S(3f181867,b3ad8170,dad46c68,f513afae,1ad2cfde,41f9535,5369ec32,728f94d5,a51a94e4,e9f20eaa,d5599189,4222ab0d,91abb8f0,38b00a91,5f09df10,a2317527) -,S(e9673139,11be39bc,f11ecb9b,690ecfb4,79b7aa6d,3158ea69,7d0092f0,89f63c1e,c100cf7,6f8783e3,8de2017c,32022a0,da9be6e8,61307546,1f98142d,4903abc2) -,S(61ea8ab0,1407ac7e,547e94b0,6f3986c6,d3096d43,2bd08cd8,61554fae,9008b122,e5c55bcc,a6f713a9,76490488,e69f1cee,150167f4,283fa792,a105ca8f,f4a4d182) -,S(ad8fae7a,17457fdd,9f481554,239a3f1,49673df7,24a3a402,cab73f93,bedab9fe,53b7dfef,7966c4bb,bb01d037,12563f79,48517220,2ed375d4,d777efef,50f03e6b) -,S(8605cedf,bf7f2e54,d3f62f27,44d9d436,cdf9974c,9190020c,586818bd,b6a829d3,5af8a55f,ca2aa1a,6209fe4d,a7708ff6,e7a33df0,50e85873,d786f54b,7d946b88) -,S(bdde544b,465b9ef4,7dcffa5a,7a794cf9,6e83253c,2f22d4c8,cbcd2d6c,ff921d87,6c536367,7ba867f5,5ede7d23,81be6ab,ec97c8d,f88a1a74,14ebd6ce,8caadcd8) -,S(31882a45,e8b088dc,93eeafca,85c28f49,62a47bd2,bad916bb,fe3e7346,32fe1cdb,b3588f0,c5f86e1e,12ab833c,12e028c9,d03557a9,e02aa1a6,fd11d693,55f176bc) -,S(17be4052,45800f9e,db510b72,603b8e63,e49fadbd,62798883,b0d04f76,a5dc1202,1504ebdc,df8855ae,28f7738,e40d277d,81667e55,a2f59cb9,c9e33a4b,8d32fc54) -,S(c633bd33,bb697d2a,6bfc4e69,707f2b28,a303eaf5,a601b08c,9c56afad,cb629537,86e3f413,2d4764db,f2c06b92,461c64f3,9f3b7f78,33139eac,2b4d59b7,ba18cef8) -,S(f39e208a,f4c710f7,190881f3,a33cd113,633434b6,3b460062,570618f5,8260bb52,90c56805,807b36f6,272e2b66,4d943c33,d0171ee3,ba5cd4e2,bfe52f92,b9e2e62c) -,S(ce984394,14f29607,a54ddfb3,72db8ac5,ee4e5414,f59f73db,89360232,f4a16c54,1a4805a1,d1057b13,c72f7835,4d40ae96,bb80542d,ba5ebd7f,627cfbae,ba24e0d7) -,S(5266e79f,81107a4f,ba571af1,885d755,94504122,a15a673f,6257f633,bb0a76bb,5e7ad1d0,9cc85f12,8773ca39,77b55c20,18d38200,fb739918,d3b0fc96,a559b457) -,S(4fb9de57,63f47aa3,bf370113,c778bc8b,67507009,5126f5c1,1ffc158f,be7056e4,2cd97636,8eec7197,aa2fa34,72fe3db2,29fe0275,8789d75e,52e87553,1486f7ef) -,S(ad168024,a99eddbd,aabec840,6158cb92,4ae7bba8,d233745b,ded57407,23cc0226,ab105015,968e4673,8ede230b,b53c4be6,9ee6386b,91ee03cb,a21f7040,f14095de) -,S(55829ae,f7cc555b,733aea9b,f1b307d,277923ba,148ba8d5,5a7c8001,73719cb8,6a7b2eeb,9c9b9585,5403b47d,6c60a7bc,382969f6,c4bafd3d,3c4f09a7,63267689) -,S(2119f233,8efa4e0e,2204bbe7,84e9de01,4e1e4c43,450d5910,960ebc38,6b78b935,9f219dc3,778544c6,7a337db9,69c513a8,52acb469,34a71957,11c36913,b8e7bb93) -,S(11fc3e1b,9491be9,d7de53ca,a2558d36,c5227498,3f5c1b32,57f0fe5b,b1295bbf,1c69c74d,ecb05933,6aa6b6c0,231105ad,91b8d188,d109ced6,2198c528,844cf6f5) -,S(34b6ce6f,ea6e5143,95091bc8,67e606ad,5e64ac18,99085821,80abea3b,dfd2a908,5b6ed904,f4bdbef3,fb9e41a1,32c7a313,28e9f325,4e180694,40339642,2bccad6d) -,S(6c225dca,b45768ab,3b1c567d,97ef745c,b326fb3d,2db6ae2e,22a40c95,3610a84c,7e85d752,2180fd8c,ebf63cfa,2d843bdb,912fe042,d00ea29c,d72fd768,402a1084) -,S(5f776e5,41dd95c2,32fcc757,14b688b,cbfd2020,e7043e3,2a707144,5a8ed7d7,3b8c5c78,fc6d8354,3a09de0b,9a64d529,c116803f,6d0d62ff,2a20b369,8b273c0e) -,S(3e26d8c5,531543ef,5e37eaa6,3244faa5,d5371e48,16fd94e9,b8bbd932,891b0e23,30a09d1b,43a4a036,ee1a53bc,6c3ebfa,a5b4c70f,6d8af4b0,c70faabe,b79bb65) -,S(c634da91,c17a3568,aaa970ac,26553e45,6be8afb,ee12c85e,8aa0dabf,f18b36af,649681ba,e1390a7b,d05d34bd,98d87ed4,16eb9f99,c606f46d,6d522019,f1a925f0) -,S(ed335d6,4d643598,c6eab4ee,fc242d7e,4e8361b3,ac8d747e,806962df,2e7e9a7e,f0e7c3f8,19c97aa7,2334b690,98f28bee,5a1552e7,f578d5e1,eb56b600,fcaa93e7) -,S(d37f8c09,411359ec,3f63dbf2,2870ffb2,d10be164,7553f28e,d72d9585,1e521581,da7cbfb9,ba3ae036,72df1be7,56d3c9be,831467d4,cbe3b51a,191e47b4,9d1f1922) -,S(ee3121d7,c7475ea5,c3aae061,1c6b420c,5b32d05,ee86f919,43c3352e,7515c360,703b2e37,97bea3b2,9b447411,dad7b12d,b809164a,ba690281,b76f245b,bc4c1686) -,S(7b42c9bc,5c2b114e,a0ef1a59,492a6132,3f5c7290,427572b5,fe98017d,1987a12b,5cf76382,e85b73d7,56fcd92a,99242725,dd57edde,30ddd9c9,dc7dcd95,260d27da) -,S(9af5ff9a,b13a53a2,93f9b6b9,a0f925d4,7c8f9b84,5f6933c3,ad074922,f8a555cd,ca93ec9e,89954734,c8aa13fa,5908c855,13a9ec19,6417042c,a336f1fa,be5d4153) -,S(5ebfa274,1a2df1b,6e1d591,f70983dc,a5b2b850,856bd7b6,59c81877,3848dacc,b0adcb9,6ac23c64,2904c15e,822991e8,46e12411,f472e0fb,5fb69fc7,a0f7ad18) -,S(93b58d08,465e5eac,8518382b,c1f6ebec,daeb486,7da65dd3,ac125e6c,fcc81e6f,54be8918,c3151784,d74646c3,6bca9c8b,8a50b8d8,63b1db8c,f4fb3ef5,1a24a4e7) -,S(a28a579b,4fb46474,ffc943ee,32b40664,5bc86899,edaa111,32c31f1d,cb6fc858,40ee91a3,d5625648,196605f,f650ab7,6e059b14,faef6396,46c9b153,9af14670) -,S(e987909,781d5560,b71f6029,750d20ad,add7cb47,f90c9078,e8de5f2a,d606ac9a,7121ac3,4c80dacf,ffea346f,5c5e1a81,c55318de,ac8cc907,10274f18,ee9819d2) -,S(291ff11d,158780d7,fc0ee62a,e395456e,5c84bca9,75e84a7d,1d2b3bf4,61e1dcef,c5c8cbe8,abb6854b,670298ce,8224a945,71e79e37,9335acee,c230366a,53ec2616) -,S(4adb1390,9e28b53e,42bd9e57,373aa131,efda7d16,b8dffd82,4bd9803e,fde315b4,66d7eb12,b827ae7c,970a796e,5c0c99b1,24eb7002,4fde63ee,fa2ecdf5,d4b1456a) -,S(55e25f4b,95240efd,e3c7e47b,2254601e,1707a8d,e40bf384,6b3a7024,da7591ff,e9f2257b,7e98606d,743000b3,72dcba0b,e4491ae3,22e82266,4b1e2b5b,78c830c2) -,S(d24e7493,e41dfc32,be7a6d8d,5463834d,388ddd01,8c213ad8,aa3005b1,fa747eca,e73a8216,a51b4b16,5e9f5bee,414d49f2,6d7feba0,982b9e93,fc4b7863,48c26cac) -,S(a510b252,6d015da1,cb7e4600,3ed61af7,caa03562,19227d9,ed8eea13,61fd8b2a,3d98c2a0,9015abba,63eb15a2,80c6c479,eaa2b2f2,a0011adc,3565d2f3,8abea726) -,S(c04d04d8,127500d5,15bac63c,ca55d76c,8404cde6,fe681f4f,6b8c2b48,87b314d1,cb3fcd77,9fb80eba,99cdb937,31bc0814,e3cd4458,df7fee1b,98c4067a,db4d9d59) -,S(ec9c7c61,146c3357,ba851e69,18ffa770,6b5dd2ff,a789245a,df70f90,eebd0649,9a09d3fa,10ca6923,c068803c,e9161923,b36b0709,b12627a4,dafd0e3d,3d186170) -,S(95df5d3f,5d504c45,f4b7e840,3805e54b,b2598511,2ca53064,baced58,a0488cc,a43dcd85,89b85305,b07d1ef3,23eb305a,35079cdb,743dcc21,c7a6ad48,4ce8ecc6) -,S(b8eece0c,3a950c52,c46bf50e,b5dff949,2fc8ec4d,6bb19651,c72d447,633a6d16,74e942a3,1b75bf83,ba6c1460,d969a2c2,4a49572c,ce3fb84b,8d0b08e1,d5583744) -,S(599ece16,d1f69c22,53deac51,75121ea0,c82b2d77,c5e2c0ba,520bf1c,72dd09a2,48a10c3,25af3d0e,dd8e2e72,5d7baf48,b2fdb672,66423859,9f73d231,a911bb14) -,S(b8ba5a06,8d9458a9,6e2fdfaa,961acd80,7fff711b,bba4e3bc,35a5fcdf,e82ab32,8035ab22,7554582e,9038845,44d32a53,c2d82417,6e2ac7e3,2d44cecc,50f8ca4d) -,S(b6846be1,cccd7865,e56d3d7a,f1b1fff3,ae806380,a1710c50,8c35ed17,227e65f4,bbdb7025,32945f0a,de989f52,68230763,361ee9d4,9c0e6241,77fe6fb6,cbc7201) -,S(a1ffa65e,69872bbe,ed009e53,f846d9a1,20dd31b3,a11932ff,c3580ff8,da9d0fe,aa32e580,d5763bf9,dd054999,68b6ba6f,31c210cb,26846ada,dc0045b1,ceda215b) -,S(9b38176d,67091c7d,f448c707,80cef08a,2ad73cd6,de65eebe,b62f9a21,730d0fa2,22d26b19,c0fb9b7e,f1ec86ba,b8ff5996,64a45988,190499d2,6fb604ed,4e609207) -,S(bc2ccc9e,209dc64f,bb132553,bdab43fa,accfa4d,7deac898,1fa52841,35fd0cd2,47366adc,176ff88b,674931b,a8791fbd,350d1d13,71891343,74d58305,a55ccfa6) -,S(1ce000a1,65452a62,5d036f51,4fbd2a30,d4518734,e7f93aa6,7a7dcd7,24730f6a,e09103fb,5b90f0ed,54b34baf,3e3d5bf3,fa288acd,b6b0ec19,ee3062af,35c6811d) -,S(846c569a,887d64c0,e8fb26a4,49c62447,4cc63d68,4da0909d,63dcdd0a,dde0031f,547753,132c9f98,d7facf93,d4ff0416,7dcbe44,77987be4,7df408c6,fa12c07e) -,S(6365a8f7,28656e23,c9c58518,5686b18b,701f7b1f,54c84b82,f5c81ea5,74fe59e9,8c7cddfd,a992e53c,ad151d46,c9cc0b3d,be27f2b5,7ffcc23f,c8d9cfa7,eb16c2eb) -,S(ed425f3c,89ae3d8d,97972619,55e8fd17,71dc5bf5,98c5237f,bd267f80,7d2939fc,4226abdc,14f7a03b,cd7285fd,19cf14f6,10c98d0,6e3c1d74,daffd602,99a3590b) -,S(cda5246c,2e1b7ebe,8d667f23,5ae310be,85a0bd7a,2e903d56,62a6dca3,971f00c7,791ef296,f8ea9b34,918534ba,318a4fea,96b2c2f3,21e6d3f6,eae8248b,29247f56) -,S(b42a84e6,ce79c1e1,bedd3f7e,596a11c2,f5017d98,386fbbc6,f906a5a3,f4eaf99e,2e722cc9,60bb3718,36ffad5e,47509fcb,cc3d0601,70b02610,823fa40e,d407e6ac) -,S(358be08c,e1e2e9bc,b43149df,58700875,be23cad0,ba8524c1,6d46a01f,ab0bcf90,f3c4fef0,70baaccc,f64fe0bf,b6f5111b,462318a6,36489b00,34f05c44,1f9d1308) -,S(3ed6435d,e5b36230,a4f74bfe,14571041,427d16f7,9b433ac9,85c9e135,6016a789,1c72e85e,142743d2,b5be677e,352d3dff,ee0dc56d,5aa56d91,4b92762,6041f26f) -,S(249f7e2c,580dda16,5940d7e2,672176f4,afb7e50,b9250610,c253d9e6,2416c910,6fc16311,49e9916e,8f70f842,3dcde36e,1630f508,79e96e48,6dc7147b,3aa9f50c) -,S(97b3b144,e8381ba3,1b0f6f0b,752cbf91,14d2d76f,6f418d4c,69f0de6e,c89cc85f,67c9bd30,33b720b5,a1449257,f1de85a,f7282260,9e411dc2,1820444d,c988724f) -,S(3b38459e,868b2912,51d0fcaf,41245087,80610d0e,395e9b68,cfaeef1a,5f395a85,be5180dd,bfde7454,c78cc9a2,b77245eb,91ec4c25,9b17e3a3,c3e8e49d,5225ce6f) -,S(4e6f1790,9f33e08a,914974f4,48270fd0,74fb35d1,49a017ef,c54fe21c,96163ebf,fb6578f,6f47156,5b6d3491,3a9a5e4c,dcd2880,d774e6a3,e56cd078,e6b9fd15) -,S(9141ac63,e408937d,7425a0a6,70a2565e,72e301b7,75619a92,18db32da,315c75de,d35e290a,56bec3e1,3cc55e72,12aa57db,f10b34df,bd7847a0,5de91c4f,546d6045) -,S(ec9b73ca,72052751,565c006a,4fc9200,337c9162,88eddaa2,e212c611,395ba578,37e11ef5,c1a22e77,38d5f3ab,4c74e2f1,ba192275,4c4e7905,1b15010f,3c224887) -,S(56fc14e1,bb1a928f,ce0430b1,feaac6e5,aef50208,be530d7e,f0f5b81a,ce1caca3,4e5a6084,f8680d07,9f3101d7,a80f452b,b05e597c,c38d9865,f6d7f307,90209001) -,S(aecd741b,2cebd4cc,82b7c362,70f1b22c,cf3997c3,f180e1e4,d803a89a,657df731,5f104b33,6c0df49f,1936356e,8dd09b3a,256bd317,afffd4d,8ccc57e7,f90b8e21) -,S(516267af,54f83d52,24a22b9a,4309e9eb,9b5c1072,31c3ff0d,418f8bd4,15836cb8,4187389b,9e062c17,f4ef6fd5,4b6b8439,cc37e85d,8a3db13d,86592098,7befe4fc) -,S(68bbeabd,8d3f4473,f91a0368,7383b4ff,6e7658dc,6e1287e7,f258f543,2466fed5,cf63c80f,ac99b42,7a67f7cc,d978d5b0,8656fc7a,6a383c27,48635ad,97049c4) -,S(20ce22ab,69467e9b,51d59213,8b52c1e4,49ba908f,909658a2,b90dbeb5,b07b67be,562da07d,9f4173f6,9232d17e,49ba2c17,31649ff1,4a9dcc3e,68f20dd2,de97ce2d) -,S(b5b7d6d3,a4a59f92,3afc1ec6,a5215786,9c86cd90,7ff80b07,d04160ac,6e798f78,d05e32c9,775125ee,dbc55af,4d1597b4,45b5eaba,5bbf6dbc,b8ef3e79,fe9d4de5) -,S(955bd489,7a4280b1,5de3d848,f75f6dba,3967e593,6b077d4a,cdc4c30a,33f45df4,4bbeb7cb,5d79991c,ef3b9fe5,bf25dc01,6448261b,44b156b2,749f9734,3d453a02) -,S(9f60e951,98e7370e,b3c02fe1,8bf53735,50fee849,9c876211,201e47f8,660a5a98,6395aaa9,33ed5866,a02570f5,9321d89b,c865a7ea,62e28a6a,3a62c4fa,4cd613cc) -,S(7081f0b6,f5923d0d,be4041c7,589a7100,9c2b6459,a255468,999f2d4e,50d776ee,9cb60005,e067019e,93aec9c9,1bf28b4a,27f3f0a3,288c4758,403a9ff7,668f9fc9) -,S(e290180,d8d5a7c,1b0e982a,bd63ef9a,b607d605,87e663ff,fb0ab73b,3369561f,462776fe,77289a4a,250ccc7b,80b54e51,993f741a,14299f78,61b88d17,d4d924f7) -,S(8aea7328,b285bd5e,b63d5939,c5c8c6b4,ac254cdf,c42cb521,2f4c5643,58598bfb,b682da77,4fc55ff,eb4a559a,8ca0580a,13819aee,990d9e22,8e0192f8,9568ec2) -,S(e9d108b2,54b24b57,ea4fc287,45865c09,27302d7a,1dfe90fe,b3a17906,2f256e68,fff7274,6d29d9fb,e7b0fc0b,1af14365,8d0ba69a,a45a72c4,8f67b939,aba128d0) -,S(9ea1f93d,1f317e61,786d4909,429e4cc8,b81f2914,17d28913,6d886b86,adba0fee,231dff25,d3b0b351,6e63ba6a,afdee115,975a5c00,b95936e4,5d9c6be4,6980ec0a) -,S(e8a12415,e5fabbee,7cd687c,43e8d530,80701d01,85980c5,7181b68d,481e7a0d,dd69839c,e263e746,99462f18,58745727,ac53bf2,2e0385dd,5d6a21b9,922f62c6) -,S(e287f3ba,ae486145,a1c2e04c,7f6d5c1a,ed796840,27636cef,b4446ff3,6c3def2,9395413d,401db0ea,4ec53bae,ff215580,5bcfbe8e,7e6bd6e0,be5b9fbf,9d968c63) -,S(8f99f79c,ec205ab0,e79756eb,a14c8e7d,fb23e232,6ab77927,641960dd,56ad1194,805953e6,15cc6d6e,2f61b0da,389b24bc,89cbff4f,c9f0ade8,c5dfff99,e819a2ea) -,S(9c87ab6a,8cb723ad,e0cdfb59,e5a1ff6d,3adb63d4,7af33e14,c6b3c343,c766f586,74798122,7a3bd79e,7d5012cb,bc81cff7,6a3699e3,75874200,4edc6e8a,a965bb19) -,S(c52c8608,6f245de4,baa10b7,fb512ff4,6042bd50,7d88bc3e,c75ec75d,d99dc00a,e8c2813a,bae8b8bd,9c8762d8,37d42fe7,85e5406c,5fb5cc2,ca05ae03,4ab3f844) -,S(b6286e1,94d5be25,9a79c6b6,ebd634ac,dd7c3fd,66ab0de,d8d4e160,ba8dafb2,72ec2ea8,ee0bf270,777cdf7b,47991524,27eaaf24,2a0334aa,18b3855a,899b5910) -,S(df7b56f2,45f2f8b,7213792e,370ca89a,45c648a0,5f3ba4ce,8c5d6d34,2f086b6d,386ced48,3850bdcf,4209fc90,d039b96d,39ac18cd,5d97ecb4,3df23ae6,1596ab4a) -,S(2acf4c9f,4cd42357,3e9110ed,a64aab59,459b2b37,675e420f,48ecd068,6d46a3b0,5f1a5829,aea5e981,cddff9bb,d2521ffa,58b37baf,9544c0cf,f622857d,5a2cc579) -,S(bfaf95aa,eb55d378,7210033d,b352372e,6a64f2ac,a420b877,586b684d,9cd33f36,7d22bb13,bb61e76e,2a2fce3e,bbf9ec83,78c6ed2e,5f143b0f,60803cda,b0a3d8ee) -,S(78cdd360,4eaba890,da793c9e,f589cca5,faacb6a9,14a29f6a,6add7d8d,74f31421,ed7e9c15,5b801d1,16b0d60e,fb5e2287,76430c8e,faff4bfd,327a38dc,ea19a634) -,S(f2ebcfa9,50a391f,c7b97713,566a8a49,edb8944c,7cb68276,d9843c22,8d213d2e,b1c7630d,956f9f13,c53a180c,569d534f,9513d16,4f3dd900,bb3f5e78,b0fa4eaa) -,S(43cd60d,83bfcbb3,cc19943,34552eae,857593aa,e8158adf,ca850b9d,1aaf4c2b,ff64bab1,f721e6b,9e23d659,224998cd,996230c,4fccd302,47e9e110,607e8f62) -,S(41925ce0,c01a49dd,7be0c3a3,b27f13b7,2168dfb,a5ec1315,f9209709,f38ea93c,5346b95e,cb6a0ac0,1a2f49c1,9b02d9a9,a725a676,f144ac26,c48f0d8b,94f77110) -,S(fd231210,6c762d82,a851bb47,8d0ee0d8,fa1c232,7e26feee,3e6ece5b,323877e5,39763316,f5a6ece8,baf748d6,234eedc1,4bf33462,1db3e66e,7eb2fab4,f96fa162) -,S(fe3e8a98,cb7abe1f,36a54a0a,a3d1c9f,d5ad684b,d05cb2,6ea683d8,f4556ef7,7d220677,34d80663,a1ff05f9,bad5a648,837b4475,abe0746c,3fa940e0,4f1223bf) -,S(e602a764,ae0d1bdc,4c3f9b1d,271717db,38232e94,84181ab6,9ba8eb73,4f5ec5dd,ad1038aa,26268b10,2c1f951,6b77b482,8bc9bef5,7b483450,d513e6f4,cc916fdb) -,S(871895cf,adb772d9,719cd962,5dd391b,3218142d,364764e,eb0bc6ff,8d81e086,49a09064,f7916421,9d51ef56,53861350,dda2c9ca,4e6269cb,555c8996,3f37722e) -,S(e229d56e,77755805,c814ec27,8fbcc56e,8ed4ec4f,4c14907f,4ab3a0e0,fa7e4b4,cdb07ebd,66d68055,bed7a46b,63ceaea8,6d42659a,ae6ebce5,795ab908,14e48af2) -,S(5535f85,6b0cc868,88ca3118,9d20d68f,471066af,a70addd6,ca4a9537,68bbf8ed,8655c844,245e2a67,8427822f,ac3206a1,f6f52953,4f7a6c29,6ab4825b,770ac5e8) -,S(10657905,4b37ce9a,e240d78e,3d1066c,b8c48d21,fb7130c,dd35ee5,24767ad6,52836b7a,508a6190,28eb013,c0355f70,4393a5af,e133abe2,e8b81dd4,83e125f5) -,S(3366b207,2521d023,99e9e311,e3447778,e796db0c,87428e4b,e6cb0ff3,a0868c1c,ec6022a4,22a8dd2c,a7f2f15d,39998394,ac908c64,74a34ae3,255a28d,4311638c) -,S(4a789396,339be46c,73608a1f,59fdb41e,91bd0164,66417332,f2630316,b5953ca,d45b657f,615aad45,809c0af8,4eb8618d,6e6e0346,ae1ba101,3a123ef9,e5b4c442) -,S(ee4f2484,fa0a9c7f,dc0c64ad,4df60628,d75d70b5,7ab9f0fc,ae9947e3,89f1302e,52b77894,d8ecdfae,df7dbd0d,8dab74a3,4092073f,47a543cb,f81ebf42,9f80170) -,S(4095b5c,163f226f,7937fbb8,3035f6a3,9aa9b760,c5086c0e,af9959fe,25f30a1f,1ce180ac,65554d4e,e9b14595,5c059f64,6a15d032,930465aa,d5547c58,5dff7ab) -,S(6a225d3b,67d9d42,412ecd9f,d018bfbb,7a36a59c,d2f53494,3d6cc62f,b0436a24,29b3d63d,9352e0cc,aa23c91e,e300592f,cc698abc,c73c48da,6a384f99,ea7c2701) -,S(23efaa41,e5f9bbbf,c6953a89,e3f4b9e2,17249254,94f2057c,f46d0c8d,71d36e93,cc89a7b1,7f2671a2,5bd7075,5c269219,88cea3a1,1315b86e,f218e493,7cdb789d) -,S(e30c1e97,f7f99957,58d591bd,6a398ae2,f972176b,f637c66a,258ad081,4f3ae55f,1a70cb6c,3e66e925,fc1edb4d,4d29bd89,3e8e4755,6825adf3,11e64b01,866509e1) -,S(be64d782,acd416d5,2b612f53,4601876b,f05aac91,13c8d265,b57ca32b,df08e278,7a41844a,43e837c9,293b81c8,73cb504f,bff8f15f,5a21e61f,9466acd5,87ad7e4a) -,S(caac02be,e009a61c,672b4c2,82fdf2f0,73ada0b8,d4a45450,76d24c38,f23822ac,7d93e4bb,a040f4e2,23acc304,75c455e5,72a9a64f,c66108ea,500ca62f,9216d06f) -,S(da2539b0,3a9cea94,9209321e,e1719b3,c1ef94c3,86d0e860,fc0ec1e7,684ccb3,e85e1387,bef1cea2,f67f601f,8067e9a4,b1b1306f,6a33df15,7795cbf0,ce3cf9f5) -,S(bf2ee552,5c965248,64bc1bd8,ad9cfba6,4ce4fe7b,be9b4198,700e936,799cc0ed,889dea1d,b1298a24,a11529bc,30339023,5df42398,e760304f,6343030f,6058f18e) -,S(b3e4b141,cb0c3662,9fe4c9ff,7a42c635,1130602a,720a6264,30b967c1,47abde36,f66f7118,c38a828d,8c4ff83e,5d6affeb,eff979bb,2e419f56,a7d7c8aa,52865657) -,S(451eb24f,fad7211a,11181826,5a223649,24a25593,63c33e01,4967ba58,889475a0,889ff940,49f6c3b7,9a5bd321,1c1f33e3,4cb2f8c5,bfb141a2,1fe5419e,44565bb6) -,S(29ab658a,6a754778,2127a0b0,c4b8af33,ea4c77bf,4bc0fc53,b5d65d07,38f5984c,aab1bda9,c77d6c3b,a619f9a,d72da6be,947b8baa,b80b16d2,15ee01a2,2bf0f2c1) -,S(9b59c407,d815c224,5bbb9c0,d1da59fa,9d9e79a,c654f8ac,2879b341,297b24db,a4ef058e,e6300114,c2827811,abacc0a9,17bb35b6,9b1b76c,c761ab8d,a676d190) -,S(87d27b65,82aeb975,8b9b970e,76c3ac77,78e69a7a,52ac620f,c0564e74,a66c9fd0,3ff3b3cc,dec29337,41c83e08,7f07f41c,4d03d5c,93268b1a,cd9098e1,37511e03) -,S(fbb3684d,38958163,bd85a0ab,36bcb93b,7fe7d383,b70d8bf4,d9bba6f6,989701dc,7b07cdc6,c9c5b3bd,10dc2af7,b2606d09,759e7342,68a5d4c0,301be264,87b94504) -,S(82022ae4,ccc42b9d,223cc1ad,c66e58a5,a3ef1494,f95274ea,cc7cf79f,4314a453,c2424250,9ddf2da1,6f0481a,9b4db450,3a81805e,9a8eaa3b,b5cd0e49,15d2b695) -,S(ba5cd45b,3b51cb37,bbe475fa,e91f8975,ab4e657c,57d0801a,1dbec958,be20f901,2e0d4fc0,f8b4f58e,3407eddd,298e5324,7f9eb718,b58e4164,78e3a01e,cf41b0a5) -,S(1293c841,b316d1be,76ab4444,53e72e22,cfadaf3a,df5b6d27,7cd065d8,8a6703fc,98f58f37,40fb4988,b844ab52,3420709c,2488f144,88049749,28670aad,5133c2fa) -,S(ec9fb3c8,54bf1bda,dbb972de,a8ae36c7,987d77e4,8d8437c2,c69aa988,df5015c6,d5f35bfd,ea59e974,961d6b36,4832560c,fe425d54,bfceccb2,a00411cc,a5486d3f) -,S(2ecce03f,4cd55b69,6cbd4466,2e7d58f6,9950eaec,6adaed62,7694dcb7,2544d244,e14f30a9,7f1cf747,ead403ca,e07cc4cc,d1bc793f,de79082f,f6615e6,43f68879) -,S(ed8faf7f,a63ee520,7825e7fa,56f6ef8a,4c6ad5af,ac507c3d,77c025cf,566fb3b2,df120b8,ab21273c,a5af1040,7fa3e54d,cb0636c4,8ebf88f2,c9b046d8,83684a9d) -,S(47cb8f7b,8780dabe,c1eb456a,f30fd917,bf3fd9f,3c28e3a5,bc078c5f,14c32e4f,f8607a02,1f16aa6c,68afc948,f21ee2de,c5889d19,8978e9af,66931bd2,b4aa3203) -,S(76365ac1,fdebab2f,3b9a3ee3,8afe70ea,d4962047,1e38e5ca,cf215a24,3d762009,2cacaf72,8b4bb600,ff37d3a6,97d45fa6,5d778334,dcddc32,11fc51b5,4e53aa28) -,S(c9dd5de0,99b8e552,e1375055,63edc83,9f09311e,11868ea8,a233309e,cc27b424,4bd4d238,4e615eb7,c68f134a,eafe7d2b,38163a8b,b117f9e4,b382236b,b8f8c1a5) -,S(22b6a7ad,cc406ebc,7c1c2f96,bdbcb6f8,9a1e08b7,822e2a31,83e5932d,ad0a8961,52b86095,bab24f4f,d2ebe9a9,534af2d6,87b553e2,77536d5e,22c1eddf,ae0ac794) -,S(3ee808a7,49fa7df0,c37017fe,cab7f6be,96f06c04,b2de4d24,a331a9b6,9f81a158,3e954cef,5f1f9ecd,887dc174,64cffe5,6c4b1356,d841ed0c,1e23c1c,2439cb4a) -,S(2938bc58,8a7a4896,de69ae4,4d5b6240,aa97d302,7043048f,3e49c222,b8fa4803,f26bbe61,9fad1d90,de74826c,ba6ea02a,9ea59a1c,59cb4818,65b054d0,39ada03e) -,S(682558ec,da97c9de,4cbea34f,5df43274,94962e5c,df72b0b1,2c3977d7,e1a15451,c4c2e765,22c7013f,19253c4c,c8ec6cc6,8b543f33,5aeb620f,112824af,b9fedc6c) -,S(720d8c68,fc520da5,79f6811d,e1f3d045,cbfad09,f7f7d8c,8ba68b4,6493620,b867e8a8,4f7a6d06,4d6fd4b,8bbb31a9,7ac26c3,b485fa29,50d545e2,644c9cb5) -,S(967fb3e7,1bdf658d,356153ec,6c0463a9,994d5d2f,b3aca9e0,2a17f5eb,f4b84831,b84a65f8,861724b3,2f5d0926,ec9a84d7,e3cddfc9,c7887a09,4cf602eb,547cc83f) -,S(1d9fd25c,77ecc3de,8e5fc113,1ef13b9a,73f6ebd4,f8673d88,db2a418e,8bcedc85,54a06301,d9720fb4,bfbff58e,23fa4233,33012c9,d62bf0e4,aa6adc4e,ae8035d7) -,S(80138158,a1137af3,114dff5f,f346e339,7d04029f,9050d44a,b4cea89,f1311c0a,16f49876,e6d6ac18,c25cc712,da3afe70,bc5e9489,7c55dc36,bdd234aa,6a5a6b31) -,S(aab4021,77fa5844,e3a0906b,3107df22,33aa3418,222a8c55,c6c37933,c3ef632f,9b83208f,3ad0dced,382d5876,7a089711,9a062039,9a7fbd2f,7034e5e0,3201b092) -,S(8f3fd14c,7670f464,d9ef1e3b,3014be60,3c523237,14bbcfe1,d3612f13,fa72f10,84cb7094,7901b81f,bbfa593a,5c8606e6,862ef6f5,d71c30a4,b546c08b,4205c68e) -,S(3ba9c91c,aba3c06f,eaf4578a,33979ec8,df69a903,30cb8d88,e49953ed,4a1f4933,7048a74c,3eb66231,e8410799,591bbef,fdcff65b,b492072f,582ee47b,7a6f99cc) -,S(2f8c37d2,89dab0e0,d5152468,29f6cb61,7344c21c,29860645,5f29a9ca,dcf36a7c,37f0b64e,9d02710e,bfaf145e,69c79965,4223d093,7a834201,d2f74d40,eb508396) -,S(45e6eba2,c9209d27,b87f6050,a656fca,73fc6128,cedbd2d3,ec40ca,76dce846,a3e28d44,ba1882bb,d1c91a63,5ee22582,81386757,4e66ad90,8a062c93,bf5f16ec) -,S(a5ecd3d3,80a0cd23,4467143f,fe842d9d,82ea7d9b,98ad23cc,605fb8b1,fd767ee9,22f12823,8ea84269,3fb31fe5,b5015cf2,c9ab6c33,d167b95,9bea6e29,4f11353f) -,S(f7f45a71,c4663b0d,44369821,318374e8,51eb66a9,ff6034a2,c943ff90,174be83,3a1633cd,4ec197f5,40d3d6e3,e6a3281d,7fbdf46c,f52fa149,8acc0a43,5b46fce5) -,S(92582286,6b314e17,5af03b7d,e5717d42,52bf6c82,a55ec832,a94b274b,487cb59c,fc8e9584,736809dc,65234670,495bbc7,d6c2f52c,ddfac4a0,369f0527,4a811f68) -,S(c15fe8d3,2303d00a,2f57fa96,6ae6fa75,1d7849f1,4dd527b5,a7f76cc1,e556da4,36242bd0,4685dff1,a67c445c,50cd348b,e017c06a,e2e9cd06,7b5fb109,81c10951) -,S(49ef826,152aa60e,310372df,270bf0d4,4dd7136,7d72be5c,a464f60c,c62b5355,7cad4ba2,dc4480b,9a1c572c,77a93e16,4e369d2e,b565e165,d9c7d2cb,20c4c645) -,S(c8de09e7,538ff94f,e12c876e,163133e3,629b2f1d,ed6686a3,be4ae122,9c91a18f,b5a7f31f,e58088a1,5f1e872,d6096562,9cecb10f,1a76fe88,5eab6247,697c2635) -,S(d86b9fa4,616f43af,1d7a6cd3,d9af24a9,6b3d5119,ef764576,9461ffeb,96abb344,2388ce8e,8f931b49,9481b660,669cb8e8,56df6f72,e392e539,fb570e19,f003bcab) -,S(a2cd7618,f351e2b1,3fa7b719,30fe3041,87c4969e,4f3ec55a,7433ae6f,cbbf88,3e0b5c62,436a363b,1455711a,b310c362,29870cd3,a096324a,a8dd36b8,5d19d685) -,S(b7283cd4,e33e4a3d,7836e4f6,b39b5576,ad6c213b,ed2fab87,ab442ccf,2100b2ca,918006fb,111c2307,1821e7e3,25eab3f,9083367,4248fc,2733173e,8eabc9ea) -,S(b1fd2d2e,9707ba8d,355b123b,9ca31365,d12e1854,6efccd9a,cda40f6,48b9a769,8c37cc16,8e8f55de,f604d222,62818bfe,1a40cf3d,62dae94b,58c9ef4b,475e674e) -,S(1b0997e7,4242e85e,cb4be32,885b5a6e,cf6077c7,395d262e,7c0d2b82,cb39f90f,55b4d8d4,27cd1d8a,ed8c2d2e,f3bcf8ce,f30fae12,4c14b183,fa36923b,6b7760b3) -,S(56ffbbbc,94ac925,dea36258,8ee1bbb3,4f1dc9b8,1bfd7e69,8e055065,d98d78d6,aa73208f,46d72bdb,20af3d23,5bf1c5ba,a517fcb7,b8036208,9f8a7198,d8edc65f) -,S(c125fab0,7ddb7f9c,3426cd36,812611e8,e3908191,67228685,3533e0d9,3ad7045e,2806703f,622f654a,f6c3f118,92c1dd8f,1f235ef4,4df464b6,8ccd30f1,9b77e5ae) -,S(e7ede9db,e4e0c742,8b1fa6fe,e81e80ae,dbab85fb,f259d301,48a51423,fe7f4a17,93ab277a,9fbc5cfa,c80d32e6,5e7f50d2,e236925b,c2dba1d9,e635a56c,d33fc066) -,S(74701763,f1bd6bcc,470c3da9,d853f967,a47c1628,c48b1cc8,aa395159,a3df93f3,ab2c011c,7c5510f3,37393dd5,f05547ba,bd22237b,28ed69d8,a4b6ed55,5d8ac8ee) -,S(8d27f97,55baf71f,e6dffb8d,83784e32,a65541c,5c656576,89c900d5,e79081b8,a7176e68,f3c89601,4ae1f837,bd52227f,f308f90c,b7f31386,e5586125,1ac250ad) -,S(63e06afe,9040b531,eac0a0ff,1ac25db8,71b0db01,8e9828c1,f5798ce,accc7ea9,aaa11884,a9dbe08b,6b28fcf9,9049aed5,c911244,b2a6a13e,9300c007,f4910aa5) -,S(dc7ea1ae,27d60ab3,42d617d0,23e4b1ab,6bf8bac2,882084b5,dde95894,744ed50f,93c7d76e,2b95c5ff,bbfe97fc,754a5a3,b63efba6,e111540e,48a0291c,142f3dfa) -,S(f3aeef6d,f69cef4a,3d7dfb69,1b5aea99,36e40239,bb976253,2213bd1b,f6e842d7,57d37dda,339c7002,f87bde03,1cb1e8ae,72e5628e,f493c115,1fbd0f46,2208de5d) -,S(825bd84c,316e64ea,dc5d081,23d7272e,ae87dafb,28f69b67,816a1aca,76bec3ce,61e3a7fd,ba8370a8,6a3e3f69,d62f87f0,849a2564,97658f1d,c28ca11b,40a52251) -,S(310a2cd7,4dec5370,9d2988cd,8e9426a1,edb63b9,50ec3ba7,f5aeeb93,3856a75d,5d6d86ae,dfa5e57f,7f2b4ab3,aaec250f,e3ff1eee,3e18c228,ffa3b81f,17122c97) -,S(3471d475,62a512d0,f82355ae,f9bb6c3f,69f04db8,977ee4d8,5af582c0,1b425217,272dde70,2fe0b69e,bf86d68c,5037b425,ccd444a9,45040358,aed399eb,db9cba31) -,S(bf6d2563,bfafaf24,20a2b3df,6829aec8,aaeee4eb,ea3538d,8086807e,4c257a2f,e8077a00,7e7b496b,64f847ef,755746b8,3a2738c4,4c1e7ff1,a920ee2b,40b496d) -,S(eb33cfc4,a883f718,52fce42a,3cd876e6,d6f4d465,327223fb,bdbed425,2b9cddc4,9bd400f2,ef608bd9,904f03ad,27de86fb,eaab9137,e25de8d2,a7dada4a,1ee5453f) -,S(1317e0d0,3e5df319,fb383edf,7de95645,6b123d3d,a0d8d08f,82091d6,ecc2279f,3bf6424d,5c6f9d56,b0d22b60,706a5471,dcae4297,eacbbb25,2a9d2292,33675afd) -,S(81b09f2e,99dc43eb,eb22cf5d,c5406f30,7e00f8e4,267bb456,c99bce34,309aeb56,9d4856a4,b300eeac,42f5b1df,92e331c9,1dbc5f6f,ebf17d7c,49580180,a3361932) -,S(deea567,a32ff19,722626ba,ef4ea337,ed436d32,d23df7e,98b86644,855a62f2,5c912697,c61a17fe,8557ab3,40c1792d,4a8310ef,69e785a6,dfe66d43,9d032414) -,S(ce4ad083,5746d173,e68e02ff,a7a91b9e,96ae44b1,cee86755,ef3dc4e8,e43444e5,be86cb89,5238d4c,b553e289,1545fe84,df7cc81a,ff1c2a20,d3406f62,7f03aa7d) -,S(9a993e3d,407f1af6,e4d19a32,48a0715f,2e36384c,7d8184f6,fbbce7ff,530b077e,e4a1a52d,80a267ee,99a7bd6f,e6d96ffa,3f87001d,c543f4e2,481eebc1,301a7a7e) -,S(1f10df2d,7c7f05c8,1717ae6a,1267aa63,9247c7ef,45aafccc,6b36112,fb9bd0d8,670b265b,71e2db79,32683b0e,c967e9af,e45ad643,27cc29af,fdc783b0,58760410) -,S(70ceb257,29c9208e,7db17633,dca775de,d57d1dff,9d914a5a,bad5711,86621b53,6e016e91,b3f3455f,cde11c0e,c6d1d75a,ee9825,7e9d64a,ce7c1ec3,49df0c62) -,S(ba46e5e6,4dc882fb,dfb7921,a106060,43fb6c4,ace9f2fd,46693f7e,74694e3e,eaeb4eb9,79381ff,8a208e06,9d8c436,5868d0b3,dea049cb,f342c88,7d789acc) -,S(bba3badf,d233ad20,e4179bea,f3d7579e,a631d154,e048f7a9,e320d388,3c30d81,f2a7c70d,69dd44c7,317a0af4,e765693e,2bdfce6,8c8a51e8,ed3f9003,5e1b961d) -,S(6df6a769,d300ba68,17e58f1b,f41e0af2,57d491f,38e59283,d93750a6,36d3f8a5,63a083b3,aa51c772,eced1f31,ccdfb4d9,ebf0f492,99f12819,dad9a36d,a73a4a6f) -,S(affd131a,4b8c9a98,294c7ea8,793a5173,4fab1953,1d2fe236,1ada5c14,a7174f2c,4c3de4d9,ec4a3698,3feed322,58a9788f,3426891c,b3205708,73429671,3411be6d) -,S(2da31049,9e54b18a,19dba546,4c7c708d,d42ccac6,bc2196ee,2f0a2453,3b0abc7e,f354ac91,20ad9f8b,56d09d44,51c4d052,426981a3,f7b47e7c,bb0549f,232db974) -,S(3882ec53,cbe3f82a,e8d381ac,edb4c31f,23cdd201,eec93f2b,2dc7d0cf,92e57b61,1d34315d,e5a7bfcc,492b0046,b2740646,71a43d53,2fb0bc78,6cd80ca2,ef7e6e3a) -,S(fcab8635,6a08ab26,39bc8e4e,8e9eb5e3,46825975,2a65cb28,d559bb48,7387f9f1,af4080c0,d08f07ce,57566753,ad3570ae,bef2b38d,4ef7f54,d7b2054,c8fceb94) -,S(fd34b8bb,8a897e12,a29dcd5a,57540caa,847bf011,a1548ebe,5dd89d75,9d36bb58,51a66aac,6a56f973,57927eaa,723106e4,d19b603b,d0d5a55b,76235197,7910b2f3) -,S(1e89bd20,c0d85bf0,76c7a167,87c7d817,1d3b4660,99dd82fa,808d98e5,87d4b469,4f53a9d0,e5768760,3dedae47,574f3123,dcf11590,fbc4d353,eafc8629,3cfe882a) -,S(8a1ea7ba,66909ace,c8d7d93e,aefbaba9,ddca459e,548c448f,5fb3a957,7baa05ed,d58059e9,64f37a4,39f7655b,25018031,ea1f1fcf,8ae94f99,e09c04cf,8b7be091) -,S(e0c3780d,80d59926,96886549,af2961b0,e4451f0c,b5572cb,d7ff76d6,1d1331a1,99d9d2e6,a13c3b1f,c2fe6f1e,5230e7b3,d827ddae,bbeda551,1144f68e,4945491d) -,S(964354e6,ed23ac12,16fed36c,5daade18,8e7e1bdc,ff20e60e,f7cc8c0e,83996035,f748a09a,8563c6e8,72253198,4e6f0622,7e6a408d,3c633529,aa8bd326,3428998a) -,S(9809e729,5125c862,fc6eab86,969861c7,8bd09415,585414a1,ab1dbc3c,1afe3f9b,d8536228,bbf55568,833909f8,6fc84a58,ab0fc089,432fc05e,fd46bf63,987b9fd7) -,S(195f4d02,305e4c42,28d83bf9,4025fc7d,1d8d7173,da14bb34,abbecc4c,f01ed17,957db8b4,97aeb9cd,68152e0,23cb4467,ce13845d,3a88e21a,726b8766,7c9d637f) -,S(562eaaba,3eb17e34,efa3f726,d02490ea,b0203fe6,81b836c0,f2c44a1a,854e0b37,b4e658ed,9e664804,2d3a35a7,70ef4253,97093ba4,d7b32da5,9db56a6f,8552b1e8) -,S(84a2c5eb,1efa9014,80c57969,3302f34f,de3a602c,a4b1a28,8d79f28e,dec8282,700d51c7,88cfeed8,587261db,adcac440,c703313f,5f0da023,bdf62b36,46207cf1) -,S(83d12fcf,dbd9168,b14e7340,6c6d4b84,b93e2bad,77d4c7fb,8ba00973,3672f913,e4856e26,bf2532cf,bafc78b3,682ce9cd,3c0dd6fd,861218ee,523b5131,e7279a7b) -,S(9988a6f2,bbd9320e,fbe73bf,9f4643f8,ce64d522,9ed4b701,dfb0068e,dd5451cf,bbb352fc,bd3b2650,d0a44e4d,892f89a4,d2f431c,2abe9910,ed5a1dd1,8a882d5b) -,S(3e92183d,cfa615c7,33721d1e,2a2116b1,83017d4c,2aa70b51,60f80a10,afff0724,c7888251,f4bcbe62,f0dfe545,3a73f3d2,76a2f30a,74e57d7f,22680b39,142dc945) -,S(d9175300,fa1efe3a,4cb130fa,fb36275d,e5f85b98,5ea5844d,e7763d6c,8239492f,59138c65,e9592a0c,d9a36220,d165abfc,fbad38d8,85eeb521,c5566702,9b678b4b) -,S(6ff5825f,7c12bee6,5d17f7b4,7766e677,ed74c5b8,7a95d068,b4741129,36d933dc,661ae9de,cb7974b,2304be0a,4d2b8d80,2ea9aca8,40cd0381,31f80248,378c0edf) -,S(ed6cbeb1,a8761064,3067d580,ac024f7b,9560366b,bae875ab,15ceb116,50b1c31d,9140687e,d1e889c1,6564d60f,702e8101,1269c476,f19d7f45,19a7d66a,8617dede) -,S(5f8ccceb,32d75aa3,1096b56e,eb132230,853bf6e,38643ca4,43abe04a,8bd69164,35f72a3d,d0c81dcd,4b6ac0fa,c4f5834a,4f6576f0,21cd2d45,6bde5b7e,7995da3a) -,S(81e02085,9bb23977,522896c6,7ed66751,86580d62,f015af7c,479a6e23,982d0b7b,8791fa9e,4159f26f,b42ddc08,85d562b2,fce84a38,e2af9960,1ebdbc64,cffbb669) -,S(de226b16,dd1e5c26,9b7aba7a,d63badc8,3eb435e8,7aca85f1,41d42712,95d8f721,62e1e399,fa2ce72c,3f87dc03,de33d913,3428416a,434dd20d,84156470,1ac8423a) -,S(60a46f42,3fcd3295,fd058be5,9f7ff164,fa762995,27cbd2b1,d13a0bdd,97d140f3,9571d2de,7b789e17,e46bc31e,1a03cab5,912cb854,ccbfec8e,f4d370e,df7f1219) -,S(6fef445c,e1b4bd91,fbd3a77a,ba0c6364,80d7e759,3f42a7f5,ce089fcb,c32249c0,115fbcfb,af46db83,9ae0cae2,e581796f,f82e73d8,7d4c9a91,9a92c5e9,f4fa347d) -,S(6d37f51c,a8d2f953,a3e5f7c2,6edebe57,a9892b5c,14482a30,9145c4fe,4293522f,78e511f3,6718ad4b,de6897c,d3b90e08,cbefae5b,a884bdda,a967eee,9d5309af) -,S(c0ac827,5bd0701f,5c9cb035,eddbe996,738aa155,fe74acea,a76b0351,3d46098,e7f32a2a,188fa708,6a968490,60ce26a4,31d76231,6a65a6b7,c3e83201,f8e3cd97) -,S(9000dba8,6f895023,1fc507df,85faf4a5,822a648d,4b256b93,5d012060,50cde108,9b7ae836,94b2e9e8,bbd8383c,2f4cb03c,32331902,2f58cff1,779d83cb,654ef3fd) -,S(f1109bf4,b490bc8f,36609253,26c2a2e1,ad58dea7,463e1d9a,28aae8d6,969098a1,87431a27,9fd72c10,80230514,1c8c17ec,6e3382c2,c325b022,4a800509,5d2f24c5) -,S(4de871e5,4e9cc6f0,8c4aac8b,36d61f83,929adc8d,4f6e18b0,d1dc855,6e8c0003,25d1fcf,ca98e8a6,c75d7fce,19de16bc,805f4b70,e9a3e9c7,f0187f07,70d3bba6) -,S(a23cb675,92972bbf,3a6e89ff,94e10010,8f47b467,fd8cdc80,b66013d8,62766ece,8dc70b84,ed05c23d,a1681126,77d23aaf,cbca18cd,fd7e9dc7,cae5aeb9,47cf548c) -,S(295d0cc,e96d8f8b,91ba9dd3,be703cc5,79d3c938,a5b7c32b,bb40e149,584244e5,a6d45a06,a16bd4bf,6af0fe37,6538ae5e,745e078c,12b3ac95,2653f7ee,2b03c926) -,S(7c683b91,9d5376a6,d40b13d5,1fbd1769,6cb40bcd,efd248af,9e102545,eebabbce,3da0c9d0,3608856f,5b7ed30b,8d9f1562,197d4e5a,7c23ae39,332b1ada,adfd3f73) -,S(30f7512e,d27e249a,95e0e21f,fe22ec23,8505f39e,ca9f41ec,df5e7ef8,1c0c3189,2f5fd85e,25ea3a3a,15928651,4b473197,9e4e7f7f,56e88164,fad41e42,e4875169) -,S(9377bf8c,96584f27,324a41c7,78d6314b,1c7f842f,b4910835,431f5a76,2f514961,d599cc55,e2eddb2a,e7d7fe92,aed830d0,3cfa892d,3a89cad4,335fd6d3,69f3df42) -,S(3589ffe8,67f20495,ba3530b8,5f83c54f,28a66e78,6bff4ca2,40ac1d55,6d31e9be,98822eaa,983089e1,209c22a8,9f133dc4,d75b3a67,8fdd385b,581a9274,6d224c89) -,S(39c1b1f4,b2dadc4c,e58e0f84,1fcc6415,2c79e77a,11d53f85,999db8b8,ea3f8935,e785271a,d9df3389,6436991d,eff9da83,50bb8a42,616cd31e,6289aa84,d4256721) -,S(dcf11459,d3d62c2d,99879918,8b6118e4,b103f9da,2453b72c,ad5eeded,8b25be33,dc038c1a,af3270e6,345a92fe,7c7dddc6,a190f6c8,fae7d7b3,30a3cc72,f3a1c074) -,S(614929dd,1de9b0c1,3f4d82e5,5bd8050c,a32ff05e,6eb238f0,eed635b3,6623d1d,afe8517,c9e7f17b,a1918e3b,e8180ff6,afafdc43,1acbea6a,e0eaa75e,c4d8a24b) -,S(f4a72228,cff6da94,a45da35,5ec8adbf,ef81609f,b59a8296,a7c1b0ba,9cce743c,545200fb,de095aae,9de90f1,569c6bf,2fbcd025,3cca1e50,a25a81a6,e19cdacb) -,S(63cc4273,6caa5597,46e62fbf,5371b943,57aa164c,fc8fda65,b5fe524,e2c93f7,1fa4ef5b,c5a6413a,d6ad2bd3,4b08289,e7d8224e,450f04fe,9b47c45,ace5665) -,S(ac175228,118438a6,d2cf761,f345cb04,aa7f9d89,9678c201,6b84be2b,8eab8889,dd7df8ae,29643dac,27ab01b6,8f7765f0,832f2989,99a13396,3435a982,aa4af2b1) -,S(9dbb5eb9,637c41b6,c4a5a2f,72efab5b,823e8622,f3786c03,dd678816,9e4a0e48,772d6ba,13f4d61f,42dcde34,b8519aa2,5aa0107,89c625cd,1ba38d4e,b7d924d7) -,S(717095dd,d2fcc135,1015b586,65a0d888,4e88f599,b8c32fb1,73d5731c,3ef7dddc,1de0f109,52b470bc,fb23da3f,3c7b640b,4727326d,d18e020e,581fdfb4,7e4fa5af) -,S(5ac230d3,f829b1ea,401e3964,c14d6e9d,a32c4a68,2ccdbb2a,3319a964,265872ca,fac3c3a6,27dbf66b,c5e06a16,e319ca43,423484d8,3217ae81,51bdcfae,c9c026ea) -,S(d27ecaaf,a39f415,e1457537,b2e74e1d,382496a1,51118100,8577cf76,1f8752ef,fc480b67,46cbaf31,e3d8eb6,4121b68,d5938e84,face3ae3,5dcdfa4b,71c6c037) -,S(e08777dd,f92d99b7,c4f87d53,9fada8c5,703af619,3a088d64,77f1e20b,f2ac6cda,25a4f88a,c6cb18b2,4e96ecc5,3ce10d5c,1202c4e7,edbdc070,db05a501,29ccfee9) -,S(45ae7ab7,afe9580f,bdaa6a13,8896ab97,63bbe3e6,88054776,753a1180,699ba6ed,dc1af7ed,127fe06e,4d0d440e,3d96f43e,502f797e,fefcff1,6c46e6a8,a156f322) -,S(fd28cb3b,71c50453,b3cf509a,768b4c2e,6ae26514,5801c045,327e1de4,f4d00590,b0684f95,4867cf44,aa5081f0,8174ce21,3298a22b,257f6159,c2666518,5ce5a7b6) -,S(f226f00d,ac6f49f0,a195e4e2,23b9fba7,95681660,7671dd7a,158b3260,1c1d850d,d05d5c4f,6925a38a,b4630e53,a1986fe9,d823a08a,3691550f,10f71b65,a109ef86) -,S(3cc61613,a80d8480,87ce23a7,2b3038f8,a994e1ec,8c9c740f,f0e44e90,760337a3,8474f96a,24093af6,94221f09,f95ab010,90377f1e,52a173f5,a11dbbda,cd3c3956) -,S(721ecd89,8cd99712,bd3be233,1f57d686,633e7ed5,c95e6223,e5cdace0,ce60e736,31d294d8,6fc07cae,4a09450b,fec633c6,21dc34a1,2f7668ad,532ac192,a0ffd69f) -,S(dcbaca58,1144d9b1,b2586271,5e58fa8c,d5b1062c,ffabaa2,db0fcffa,2b2eff38,9cf7621d,339f6cff,90efbdca,5e2c6174,708b53e6,1af38689,e6d3b257,21ec7d34) -,S(ed314e93,e649ec2b,ce491938,2c7a256e,b9300b99,528e7878,3421f337,15db8b92,70a81aaf,229fef2,e2922355,e1f15465,53ea0348,e3dfb18b,c837ddcb,60744a11) -,S(6bd19bcc,7a59bc8d,19a97768,95f65ae8,5f5c7eb6,429c09,85436b8c,29c036ee,51346de3,f4f65681,bdbea28f,843545c5,31803ce7,78b5732c,bc42735,4999090) -,S(99ed1e15,6ac8dfb3,604228bb,5be088bf,ebe9d640,7ad8be15,5777c6b1,d43d9acf,75b159a4,478b4cca,80ea0ac0,472436ad,69f57e9a,f447c61,e19910c3,9d2c922) -,S(3e166f8c,793addf0,84add90f,b0303970,f00c3c3,8c36171c,c7fe0877,b2452045,91659a63,b0cd2a65,ec330f6f,b9a6cc6d,9f07e382,7b94b8da,1921aa8,1d5bbd59) -,S(fc1baad9,a3a95f38,bf8d1b16,8409d09d,a1b1a432,841f656,cf8559cd,176df936,31f7a7bd,b013b89d,5045f248,982b5b4e,e0b4d791,21b6e638,84a563f1,a08af43d) -,S(80b3ad3d,4b371eca,c903c879,53386884,3bd31843,4e9c925a,5a5a819c,ff7ff340,fb1ca8bd,aac96d84,c67ed7d3,b65fac69,108ae28,7347abfd,f20e4cdb,712af178) -,S(bad065ab,2901f727,d76c6c36,48ef7aac,2a87d49,4d727422,73cc2e4,68616af2,ae9d7902,16b5eead,4d9d69a2,eaba2972,fa925a34,13f15d92,236329c7,470a37ed) -,S(d1f046d9,d700ca6,995beb99,cc8781e5,a2fb758f,7e81bca9,bce435f9,129b8fe7,274ede5d,7eb815af,34716718,84433143,3090fc0a,46575017,fca345a0,6111a4df) -,S(db535f55,e3dca80a,58dea798,d29aa0f6,99df1761,473a7ea1,751a047a,33f0a22f,e7d8015d,931a3bca,1193df83,7e7a8f10,e61b86d6,477a37cc,ed3528ad,5b53ff6b) -,S(da1dba06,a56ef0fa,f98b1a5d,b9a4f184,8635b7e5,164cdd50,82ae691c,ca42a80,86a8383c,a69531bc,ae806621,5cb4160,8807e265,b2179508,d928e312,a210c9ff) -,S(267c26b4,d980066c,7dd4f29f,f7b54277,3b176b77,9b3588ae,ff5ec28a,9aa42e7,3390c03f,f4e5eb25,5d230053,1d93daa9,d584658c,7fa30341,42ff20b5,827161d) -,S(8024af52,4e6ff955,70c7915,208491aa,5561fd29,fee5c27d,4f3483ff,c1cbea0a,c9de78d0,498f726b,8078fc0,609e76ff,df7a8a71,7345ca16,dff1d7cb,b2dd86b0) -,S(11ff6a68,c7beb420,7f0d7dd,371cf000,dc3dc195,406882d2,77953445,6208f661,b53ddc25,254781b5,1e7cac25,c1f7e3bb,916b75ba,97a7fdbd,658c1bc0,a7b4092c) -,S(562a1083,f9a68203,39a32d7a,65a9982a,b70d6596,b00751f6,aa88c27f,36e3c929,a380ec7f,908808b,950e7d25,510ad741,66ec2061,50923364,55744acb,b1e05b51) -,S(4efe70fd,327c0d69,3b6a7598,7ef64573,e097fa5,4cf077af,68d082e2,d341c413,10d47b9b,92e0b62d,d9a8befc,3ed1db10,b110a346,8cec98a,4a1abef2,c8ce3dc7) -,S(4d64bf0c,d7f128b0,bde8576c,91e01c27,354abd98,2cd3034f,f9ac09c0,23a51f20,159e741a,f57fdffa,de7bf38e,14dbc2e7,da3c524f,3d4c8d6e,b9dc32e5,e8a5e28f) -,S(9a41634a,ff3278d6,b3ef0064,ceecefa3,466de2ac,372ae43b,c48f30b3,a187bf,eefee0f,aebb77cf,8447a193,6564498a,f409e530,f4053c3c,ad27eaa0,6aeae2a) -,S(e1804fb,9a6bde08,8efec2d,2e5c6774,2c85cffc,e78254cf,4fc4ded2,9102418b,e9cab1eb,9c1664b9,c2fe81c9,b3a665ae,447e93c3,183cde7b,fa56ab34,7efcdda7) -,S(a603744,c0247b0a,f821705a,dff44d2c,717611f0,25f9fb41,1eb62f1b,64593212,820fd32b,706a7638,4335c0a2,f8713b9a,6dcdb015,a96b9d9c,e5c19bb8,ca603b61) -,S(a6f1d9b6,895b1298,34972a2f,ec96064d,a1108ab3,aae276cb,66a620a0,495f20b0,9a95dcd0,df038394,63ff5ea8,18679c3f,7f55d7ef,83a06880,29c9d543,6dc8273c) -,S(4ac51432,7822b63,e00f920a,b6e22142,f09f30f3,bd74c418,93baf126,cdac5c48,abf5d148,77e94a46,45fda161,f9455bbe,7ff037c7,720f6a6a,d7e4bc31,a0f43885) -,S(5a2cf55b,a16eeae5,8cec588e,1b339422,48af6e37,33604475,2dabbf7a,f7fb7a9b,8f27be2d,32ff72cd,4fc5aeca,5de55a21,a45f8c1f,7163dc4f,e0c00040,e69322e2) -,S(e16f23e8,ef48c1f6,4012b27,f6ffc4ea,a876053e,30cb388f,232b3d8,db011c99,195ffd52,b0afa5c0,da95bb97,7bda614e,47ffe3ea,13429799,e8c390f,b8c56000) -,S(65367cd7,ac109f71,50de4263,cdd86e92,28923a3a,ff96945a,c1bbd163,8524fb84,cf0b9ba,fbe67dd6,4d09b170,beb4fe8c,a7687c95,68086b6,8a7834a5,1747d731) -,S(10a8840b,39443b8d,7a44228b,d6dd6647,89da489c,8e954d54,a5cef366,6bd6eac2,7ff6f76e,e4aa58de,185163ac,ef7fad13,d8cc4055,c4e10a60,7987e034,c661eff2) -,S(3fefe8a6,c01b8202,6bb9d038,c577f16,7b1db5ea,91ae80e1,528b1327,5245d6a0,a96df5a9,37e6144a,454a0b54,39d68eff,a959757a,7c9fe350,ecd58c3a,3b637b5e) -,S(ef93d77c,e4162e9,6bffb908,f5d654d0,58595fd5,d6184c62,6c3ada21,c4052b61,40088b85,c18d97c7,f59a23a8,645d169d,e535261f,6cd7466b,953fbf40,f3cd0bf5) -,S(f1789f5e,b0fa903d,485edbd8,4971b7c4,9224a2cd,519bdd40,d627bd82,b0ca4872,4c845cb6,5456457e,a2f570f4,77b1f4a1,9e36a905,adaaa8d0,5830161f,a71a9da8) -,S(d0bb1788,ebc75ed0,20c0d15b,ad4e41f0,64193890,8a8704bf,ff3cc4d4,cc9b3274,3a120ca8,95a327f4,8e687796,30666649,43ac5524,44df62fd,8f7abbff,222a7641) -,S(164ac10c,f7807ae6,4d6aab31,72110d42,2f05e461,aeb9805a,3facdf7c,dce8963a,8dcf43d4,40f1dd90,bb1d6f85,849f98fc,9b6dca26,301f3209,3f9dc59b,ea549b69) -,S(f122d965,a8e40e3a,b857dcf8,92949f0c,cd3aca29,739a2e40,9876c782,941fbe5f,4d994b9d,d9e68983,78a192d0,bb670bec,71504372,d218e257,f50d0268,da447371) -,S(ac971547,75e5a92a,1aee2cdb,f5781f09,b975fc21,816e7829,662143a4,e48870a8,249fb603,795b1742,96767945,278dc97a,53fff7dc,f8bbfede,f8943c71,43c9aa71) -,S(959ec91e,dfd5fdcc,90d3da81,1e9c870e,fb0add6e,144b3fbd,d48c485d,2d330906,1e5ec128,b707c761,b61b5ebc,653585fe,29f48975,2a4724b9,aed90a22,6257ebdc) -,S(590795d8,ed7d8232,457b2d15,76de09f0,3c6abd8d,23b5e8b7,c59ba93e,1e982859,5edd2a86,1a3c8841,60e16490,a47ab42d,a09cb123,a9d803c0,6835292d,34576708) -,S(c5372b98,7439245b,eda17853,5cad1507,48fdb4b5,bf1ba555,89714dce,a3e0ba9e,f82d0b61,7159db8c,35536a5,46b69c4c,767afc43,8b64b5a0,22e899b1,60bca987) -,S(f3d959fc,ae39cbd3,ec8d2016,630f26c4,10161128,7dcbdee1,6534f96c,e35bd38a,e1e55c1f,87602783,2ffe2f97,fe460147,da586a03,ed0ad6ce,1603cf17,ac9b3562) -,S(922bc76e,be3ce378,2be3d960,489b064d,3a28043,f8a92cf8,dd5cec2e,537fad9e,b3199f57,2508efda,230b9ea7,51a95218,116fbf5b,d1032b54,352c0995,f5122109) -,S(45c7dd40,7a6d2c95,79ab1df0,8070acca,2c461d88,dbafca12,99a38734,d9f0360d,3a17855b,5f2469ed,6c3c4e04,4dd96f4a,d076eba6,a60e8e73,2644d25e,67e85ac4) -,S(6422d998,dfd4b00a,3dd89a5b,74411c14,f1af5c9e,1f090d5b,33ee2d26,b959bacb,e2358f34,491218a1,93d8cea2,276f5b3f,376f597c,703bba09,cdbf7d89,37a3bb7) -,S(8e048214,33196d15,1a4640f1,92bf6c1e,95b1a3cf,5365a6f,535cc82c,c4b0535c,d6d2d73a,1f652c55,9f282ee5,35f55aa0,20012195,8ba94e65,b638ef50,e97c34ce) -,S(5a2b3da8,b5eb2f0f,8a25a9e1,7124613e,b8a7080f,15d42c4,a1c0709f,e64a79bb,607c791d,eb54aafe,6dc95f8e,6ef9d8a5,a6435a82,6b824cd4,4227f188,bf86e6b7) -,S(143587a3,5cf614a6,750f3d91,220abf49,c5296e00,3cdde13e,1a0d2d5c,f6cd7ccf,49bc85fa,de6cc58b,49a1af49,46c340b,15f14c7c,2e83201b,6622f2df,86a653d7) -,S(f0080c42,8737c74c,c3b2c4bc,8c9d8505,ba357b7c,ff25f1a3,ac81be19,dca93193,bdd0119f,57bf674a,7d7cfe32,7027d1c,1c6a5ad9,2ca24f0b,5cf25c39,4a3951f1) -,S(877ae373,e547fef4,36cb26b6,85d7c426,3e162dae,ac0749ce,f7748d50,5d130034,1f0af495,b750341a,ed956b79,8f268ca3,e1275e15,32e5ca8e,6f9f6df0,d4dfcf5f) -,S(a418df6f,635ca18,8c96a071,469a272f,e55f0706,b73aca0,d1df2ab9,e8e619d4,2b06cdbb,5bbb24e0,fe499a6d,aa5b5918,2e755818,694b8856,525ffcd6,2f754e3) -,S(4c213d74,bb6fbad2,25edce4f,44c7b0b4,114dc209,4eb52967,1d907637,a2aedeab,741bef9f,ccc65c15,8752c7d5,48afa9cd,402fb5fb,206c5be0,e480df73,9f970b51) -,S(a37906fd,3f94e51b,1a94073a,4890011b,2cf93bc3,bb4cdbff,ecb7056,20deb13a,60a3b0b1,c14a9b1d,184d5e55,23314b70,8a8a16dd,894aa332,f01a2d67,30e6030a) -,S(2c677eed,639eaf51,64b8ae3d,26bb4652,d6d6528e,5b85225c,5e84ec4d,4de72301,df0e4c06,d3bb7cba,17f89240,cac07c24,5fe63931,3b2d278e,aca1b9ff,7ee832a) -,S(b551f814,eaf86be5,335fc3c,5b01c001,684473b0,cfac8939,5d61df4b,7d7e77b4,a979cb35,469715f8,3033f923,b4ae1e7f,8818b6e6,11a4cbb1,bd399ce3,646664b) -,S(98d5c718,5c8c04ea,f1f61ad7,40df0c71,2cd47ba8,74141984,fba82146,ddf45c39,aca52591,5c737ec2,eaf88f5,f1ecea89,9d4a8e2c,428f5bc5,b36d2ba4,a0050804) -,S(5148e2f7,260fb652,68c10485,4fbccc62,ed1e1386,ef8fbbc9,a0b23e2b,94cefc7c,65b4dd2d,35dea498,5ba4a8cc,b1a08dbb,9e9b2716,7ca96e1,29672452,a7ca2500) -,S(12c699c1,8c9d6410,b8a40ccc,bbeb4514,a08a227c,982df1da,f91e9131,8e0e753c,7d953c42,89b55724,3469a197,50516e88,4889e968,4ed28e1,20b022d8,932fcc99) -,S(4d0d3ff8,a7734011,b36ecac3,7ebb2312,134e4479,5039ac63,9dc69d48,120a8d20,edff17a0,e0984c60,3c4f1026,197f2173,960b3d29,f0b0ea57,3979605b,144ec64) -,S(ce90b70b,3e7b7a71,a91b0985,a668336f,ccb069d9,81a9fbe4,48125061,5536e42d,8cde9d56,12e0ead7,524640ca,2875606c,d3af73e6,457f1e67,2e63a478,5569000) -,S(28c79327,6bb1879d,99fbf985,1d2fa908,d197f5b1,c83be97e,360c4931,563b2d8,c8944e40,e2f3b546,5b6b10f6,ae1cfbe3,bc0f3e3e,33d91085,7c18496c,ec643868) -,S(6e2dad06,2413cf01,804c2b6b,55b707f3,864d4c80,87d30665,9a1fea53,e7442443,9da67c64,e05d6914,30a1fba7,39c0fe36,497bc028,43441f7d,c4c035df,129430e0) -,S(bef94ac8,3763946,c434d03d,fdf437f9,19f26188,923ee54f,8715b724,8c4d20fe,d2324534,e5fc1dc6,6fb83032,e95e1406,38648473,ce7e38aa,ee7ced54,31e25db) -,S(53548c57,f1b45c1d,ca166a24,c0f2653c,9b7d8664,3d45d125,918cedaf,818e433d,cc138946,f0c207f9,c01307e2,130b13a9,c36aec5c,3cad640d,b6a93804,f10c3b44) -,S(7fd4f784,7f25c901,4e8b0e09,b8b723ed,2aee71ab,fd47988f,90f6ff40,4b5867e,ffc3debc,901f12ad,96605805,a6e402db,58eec18d,375fa976,41b5d226,74a1bd9d) -,S(444a8a7e,499789b4,49c62424,cd9046ef,d4251bf6,9cb883cc,d3dc79fa,5397dd9d,4cc5f03b,3356b020,ae8c775,708d56c2,abbe8e41,bf393f82,8f7c45e4,dbb30282) -,S(ff05c877,84d8625d,20694bd0,a4201c7a,4af8c67,8e62abc1,acb0cea8,5726bd8b,7cf0e8ce,6ac26253,cfa5a0b5,cbe984ee,a55f6aa0,90bd12d9,6ec2de7,a996eeb3) -,S(80fdf7ae,6aa31b6b,ce894ea0,83fd9274,e29f4704,88f0a7c6,79b8339a,de7e4ab2,77d7317b,16962745,6344a8b4,bd4575c6,49e066bf,bde58fe,3f46e60a,3952fb75) -,S(ac38a4c8,10a307ca,d5020a74,f0d772d7,ef20227b,7eb49589,6854aead,41879214,f49c4cbb,3c675858,416f77ca,92e229ec,d75ecfab,3415d213,c7cd2cea,1f5016ac) -,S(b3736edd,f1e10262,fd562f40,8f502f19,3a90a435,de9ab6fe,a2691155,a5f75514,818cefaf,f190353c,f01cb068,2a15ae0c,eafa2de,657ee751,4e483057,ad5a78c8) -,S(66d67e12,d100c116,b57f6d5e,ac6a85ab,e698d4f5,cfb6722f,12738b33,310dc295,9cd4fa1f,3a0c9a54,d3608ea7,9bbd7ea,685faec6,32d7318f,d4e25fea,14a05dd3) -,S(b856d75f,756ae484,daaeb651,46ecdf0a,9fa10c6b,a7b9b33e,b8747135,3eb59043,5c8542b1,2f249649,4b3a177d,8df246f2,6566da1c,727284c4,b041a7db,89cb0a38) -,S(683bfd7,3202393,458142cd,661a6543,c736b15f,b8595548,afc52951,f9c47d27,90f52a40,f5dbdf26,51429f84,ac68cd96,420387a2,8d94d746,b4163411,762de166) -,S(2feaa1f0,811e1e65,13895934,533a0941,41ee1ca7,f8975896,3d00f8a9,1b2923c2,9dd80976,b884d401,5d7701c3,5e6ee1ef,690d1820,7d06e02b,7e3a10f,e8499c1a) -,S(ce652937,da9ebaf3,a9765e9b,144d20cd,847070aa,1a968097,80e07b58,2287cda4,c1c46ffb,5f152dbe,5a9db378,29e7ae84,454e1736,eb7a1b68,1b321f3,41ba572) -,S(9a695bd9,170163fb,ab3f9738,a750bdc7,556087b6,b04dc8a8,4fd5fe68,78976211,f40ba1f3,75accd85,9a42b133,294868d9,dce262d,64d6bc27,d0c9cf12,3eaeda70) -,S(e5baaf68,bd3083ec,bfabd6d0,9e4da4c3,5908b0a1,75578ec7,18cd3223,bd34ba44,ab8651f0,365cc3c1,50476d0e,da3e86a4,5feb7f46,a9afbdbc,e4defb99,ba27fb0) -,S(2c26cea2,b507fe77,d8f3530b,b7ee1fdb,dd0c4dc8,bf63d04c,e06376d8,ffe59cc7,b344e3af,54d03eb9,b0b67151,b5845297,c30a1cc2,aefc004a,5000b69c,e630d62e) -,S(7c67539f,52af2e61,88deadaf,a07e2f6,4d53339c,7fca7a3,c2a149f5,c8bbd0e4,3f9872fd,c21c9136,4ecc97e,c6642ec7,df7a2cbe,61b63038,96ee73e9,309067c9) -,S(4b5ddd2d,ec8b0bc9,3b6e1d17,e1da71c8,3345614f,74201aab,8f9adc1c,aa249574,cfada2dc,aa3eefdb,434d18b3,d2a85a6b,6e16e755,6e55fd69,5dfb36a8,aac5460b) -,S(d775c2f2,ccfc0835,86a66edb,873a84f8,f9bb6680,2eb0be59,216bc35b,88d80e4b,c8a5d9b7,988a2231,cf6aa0b5,19640a86,ff56ca57,91135ea7,65bb3a4c,fc53ddbb) -,S(71a3cf09,78810f9d,fb01d984,43dc3da4,b005b07b,36ad4dc,d3c803a9,bcd9bb4a,8aab8e21,7db0301b,9640c5b3,9617ad55,bd4a3c4d,8989df5a,1ad31040,bcaaa55) -,S(bc71a054,92b696e6,200596ae,3d778ef6,a82f7d05,825c0d3f,ddee8bb1,991f53b7,15789125,9785b8d8,b1374460,630a908,d1125536,e400fb52,b07aaf61,729a2a15) -,S(9d220919,ee62bfdc,fb81ec81,a0f60e58,e8d94a0b,c6b79f7e,6f891c64,fc847abc,8149379b,1a073c2b,8dffe886,59f4e94c,75f3a7c8,a7bfaa16,e530bc7e,6ed0c675) -,S(8369766a,d30bbd19,a330c6c9,1e3ad594,d25bff1b,4e3696e5,c6c8c33e,eff33425,a27f7682,b3f4575c,858970d9,c21f7daf,8ed5d28d,8617c8a4,e4b958b9,72e79e4a) -,S(4e277875,e4aeaab,1a8d36b5,487fb427,e91f51ad,1cd68ab4,57db2e8b,20542451,9faeff65,5bbc4b81,f96bf1d2,a152a546,d138fd0d,a8f8523e,7635020e,a26566e0) -,S(27f907b5,1b9dfff3,e68d202,72605a91,825046c1,b21336b1,8b91023,39a0d2fa,115225c3,6cb13600,fb84bf3d,dd5c49d8,105f459,ffc4068a,cbfd7b0c,52d4a15) -,S(6d9feb20,650674c4,437ff42d,41f70f16,ef0900a8,f3cd6818,64b42eed,56b1fab3,82cd97ec,d82b3c1c,2e55f857,653afa3b,5f7f7b00,39aa2444,f60574d2,fa02065) -,S(8981d2b4,3360669d,361c3b36,3284e729,ecb9cdbd,3bd17558,857f2cf7,8187bfac,1b9aeb27,d5a45d1d,8791bf73,614ecd5c,216b263,6c27645a,3e86d781,70d48498) -,S(84a67518,e47ad1fe,25540d55,77e92ce2,81691685,6d3c10ce,9c5985a7,72e1d72e,d3cb93af,85072ea2,e6c11777,dc4b73fc,16ca04e2,699ef356,dc8a5341,c5631658) -,S(d3e66756,72a6cf77,50c111e2,e65a6674,7e666cdd,b9dfb418,d50c28d1,aca8c683,7776ecaa,20e5c6c3,ab5aca5d,8233f83f,4e2e815b,dd1063f0,7359fae3,a6556dd9) -,S(ede97def,71d45688,804e76b5,ee52563e,522a7684,a68efc4a,f7b2db38,65b87bba,92e6d20f,c9c1276,60a279f9,5758a80e,85bafb8f,b77eb513,7587b692,fdae702f) -,S(3359e142,e000484e,cf7db3ae,2312e703,6ff84f84,247ac6ed,25a0b9c,eae8c871,67b039f2,3c845fa1,f38c98bf,739dbf28,d00ada09,36e4377f,87166f9d,d21cdf66) -,S(e0d0a972,c0502fd,2654a3dc,40914a55,96f675ae,cf0d958f,8fd62c7e,122b44a1,cbeb1bc,34575a7e,bbfd916e,dda11903,3ee29e2d,1b11e171,8db7bd47,576b0312) -,S(50b89367,5df77704,64031ac7,a1f5d5ed,4f332019,d8da2605,9397df84,21a4c987,c4765d81,63ec9eb,a089c3f2,56d6ff0c,45c38253,3d9ed204,cb04f335,d292f293) -,S(5dc62d8e,66775ff6,f21e84e9,9f8e8123,7f80cbbe,41ce9113,91ce432d,cd6d446a,4b456b7d,e27045a5,76e1cdab,d163fd5c,b020cabf,125f5de9,9ad6eb14,1773a9c2) -,S(8ba1778f,c7921845,d2632e18,790710c0,4e56ba7e,22efdb03,fdcd4f96,22c10971,1f31fcff,a8359658,b39d7d43,59707268,48ffebe8,8f418c53,f48c7af6,3e3e3854) -,S(a3a14614,7d1ea7bb,e6bad055,fbf9810a,999a102b,ba8b694b,e7ada06c,8db9fc7,c9827731,d4321284,23ccd6eb,3531ffcc,b3bdb87b,1a727d57,a697eac3,886ac294) -,S(9620a847,bd2034aa,c81671c4,436682c5,f6ce1af6,4d8df286,21ad1c2f,e0af78f5,e1cc6d08,a7e3dffe,cb47e32f,4156bcdd,6168a205,e8959f0d,99e1555,4d826e1c) -,S(a40d86a0,aa7d6a79,3f0b6a52,c48d8fff,95b2c57c,584996ee,bc9d98e2,796016b,ec54d4e2,d453466d,ad94c15c,b25617d8,62911b4,45f44873,96ecd950,a351ea2) -,S(71ef35a6,f60f268a,57573b97,9745986f,7e5f40e9,ba64efbd,5ed90779,b3484c80,eabffa1e,9ff3590a,c577df7f,6f5a6ad7,2f3693c,be475669,8751637b,4f8a1ba3) -,S(bbd1a408,c742a3b2,e49ffa52,c5f70958,5308abbe,f103e674,86fc76d7,a4f68de2,4941cbec,9d07e13e,1b0fbe96,c7328459,ee6e1e08,50a079a,2ac0b61b,5d246124) -,S(169ebf38,92116df5,3e09c92f,f2c89b5f,805d60ff,9584d2ab,433f1f9e,84ba9009,914f5516,e7667ee1,581b5ade,bf1de48e,c997d149,1e932a08,34503599,7c6228d) -,S(8f157abc,4c5ec7fb,eac11545,890d8e45,d71c8d9e,4c4e0c3,9777502c,f8666acc,d41576ba,1e78a9fb,9899883e,602bca3e,14dc709,8982e1bc,63518138,3ff25908) -,S(8cd338d5,694b26dc,4ebcd8,39a006da,84f71f93,94fb8100,91ed8cb5,b4ec9a8d,40318c10,dd88d9b9,c080eccf,45464ab3,3fd9d34,c2027d95,2a6ecd21,d0002578) -,S(20e47e2f,7ba5ba2a,d36171a,f4ad760f,a64748c2,94892e28,cbf0ee3e,293272f2,b96ad220,56b89821,5c052089,789e4267,162ddaf8,76c720a7,71b15254,67be00bd) -,S(582ed8a5,a0d38f9c,db6942d1,1f411dee,f9c31ec6,ffbf1579,3f3cb5e6,5f2bb880,14928c0e,4f9d9d3d,ec4a8db5,64baf4be,948ea892,34a6e352,a4cf4796,3ce8486) -,S(f4a6f59a,6e76c11d,3f7daf30,b8c046eb,b0bcab8b,6d1f5e7b,877eb1b4,601896d6,2d39c6e9,e5d84156,559a05d4,a9b148e5,ccde4641,e4bd9abe,edc8a648,b070f0c5) -,S(2a820c60,f71cf5c,76e66bf0,15623f06,fc8564b8,c763a52d,2c329af7,30957b24,b38c0703,d7429599,e6c9a1d7,250078d2,36f77f7d,b9956d37,fd92646,77ff3ca2) -,S(8c2d9c4e,9fccbf64,871d4802,6077a3a9,33634d3b,c1d7f872,6231848a,6e2799e,ad50136c,ae43bb6d,8c49c534,e80985a7,cf032d77,604c2db8,d5954858,a9351a7d) -,S(b18e9053,744b3ed,d0b991e,23927593,db00d25f,adfc4490,6eb0d19b,74061ba9,90f5ca44,c829b2c6,771edd73,998034d3,43a8aab8,442302a7,2ffea92,b33877b6) -,S(cf1d157,b03d435b,905d2f58,cc53bfa1,d124827c,f4ac4109,33078dcd,1ce835be,ee37a9a1,5547c7d6,a0f03cf2,1451cd64,3ea656df,61eeb1ab,1196d959,ca71b459) -,S(8d8b9d8a,d91a840f,b2e1ac36,a6f4bce5,92fc13d1,f22f84c1,562d63f7,e54a6007,9528be43,93ca8f2d,dae0ec3b,439abded,ee9227e1,47ce6ee1,ce61b46b,b842dba) -,S(604b5544,bbc5b0d5,716c936f,b0d9a4cb,7ae04a8e,1d5a506f,2561b463,fc87fc9d,33fe2f9c,4fb9a6e7,41c1e5fe,7d3d9edb,ee3cde6f,106a1d8a,3e319254,a16ac8eb) -,S(3e7ed414,1058ee44,6057aab7,49e14ca2,cbd16d64,7959fe53,9ec0916,fbaed8f6,fc15b241,86dec6e0,c91aa697,10a015d1,f66bd361,82f18648,1ba24568,952e79fc) -,S(d0ae7435,86c17b8a,c9524243,16cf42c1,26e46f69,4c69cf26,736d0527,7943f326,bfa02de8,b983588a,d4398865,abf6b69c,fbaca03e,8bb5f04b,1971ce1b,f74e0757) -,S(ef5c05ce,d4f343e3,7e6ce2f9,45380ade,3627bc65,9de0597f,5f851eb9,88be1441,d9267c1b,379f19e,3bd0e40b,74ae8e21,b681e7c2,ad49f635,d60c619,74103281) -,S(176b8feb,d7998ad9,7c73015c,3b09d9af,d7cf4265,c7bf38ca,8dc64864,5c8f49ae,b4bcbe4c,8267c9a3,69cda190,5676c781,7f989f5e,a014f4c5,fc821bf3,8522f1b4) -,S(88f683db,cffc14e,ebb58d69,fb6da62f,b20771dd,3542fa00,97b3a766,bd16c3dd,bbef3de,812103c5,266797ca,252b74e,cf80096,b2972219,f52ff718,1d1cb601) -,S(a65d438f,1247ec44,fd8c4121,c3d67891,8488b082,31fb8854,dd1fe238,f637abaa,5f65c84e,551e433f,dfdcf3c0,b4c771af,4bb50095,dd0fc986,d4d4a82f,9a3f36a3) -,S(bd6a7e51,c5028bb7,f7e08148,af1597c6,d5cddab9,2883d2f,f6a5a6a0,6398cc27,3f2280c4,247cdd22,e8b97979,b9a98e93,c1ed14d,a76eef66,2ddb70f6,7859d885) -,S(a672436c,2896a0dc,54b1814e,c5101451,58f7a3ac,74d36202,34411a09,909d274b,dee80293,468178d9,5baacea6,badade56,c81f3d9d,95642654,a7afcece,bfc2ec3f) -,S(ca0f55fe,d3a1d0cf,1adb0993,d7d2daa6,57891ba9,321104bc,8d9e0379,f03a24b0,dc01b8e4,63462dcd,91588baa,ebca8d8f,52016683,9671399d,b5843e6f,5a3cfa6f) -,S(610ff08d,9bff021e,544961c,cb2fe206,211843a7,ea0c74cc,b91f0b5c,4b6429a1,4be3b18a,ee965fa7,dabdaee6,8fcd3e12,d889bc36,35f160dd,9b0760be,d1d46b28) -,S(2d6f8215,a70aeccb,78cf006c,ddf8f0a2,6b695dc9,622dd622,38fcc638,a9ff42ae,3fc0964,e2a3c969,e61e4e5b,ed50f337,7a988715,246c50fd,3ff45487,95a3927b) -,S(8c0e99b4,868e39c5,b610b132,de1a09ae,99846826,a42fc4ea,70b0c630,88a1bbbb,32b8ca42,f0a240cb,2876a41d,e61b8c17,6ead992e,8785a95,c384c536,141cfe52) -,S(1528ba8f,9000ae75,e3062af7,74ef6d77,658c6d1d,65af87e4,dbac9eb0,8fc96ed7,a8dd278d,54df6bcd,1d4e6466,5753a8bd,2d39f0d5,c731a53a,5faeca64,513b5651) -,S(c1466ea5,d9256a7a,f13a040e,29515858,104394bf,ac5af7d2,fa09ef7a,6ff1d7a4,cab6fec6,fb36d879,f0684b54,6003df0,d8bab3b6,e1050a7b,c05457b2,75be5128) -,S(ce8bb093,e051089d,2a297a87,cf90c3f2,2ea946ba,87a76b56,c6f11812,d3e98cb4,a8dbba51,b90684fe,6dff556f,bd13baac,679cbcad,90b0e888,4c252e95,e03a0470) -,S(76f3a73,7c9d9e15,8d30ddd9,b092a94e,7c426763,a17a96ea,9186582e,6d6c86d,5b1ca07c,4f345e6c,778ad27e,c6ce3f05,b29c5302,7e40443,b202a022,e5d16c8a) -,S(f757dfc3,23390b21,3bb98872,5dd7d43b,2ed997fe,af7681ad,ee1572d5,a74017f,d0b4e4ea,67879726,700b63d9,88eb3957,74ec4f67,ca1a56be,461d244b,a5b83cf8) -,S(59bf6198,a2deaefd,f080ec6d,3dbe3c67,f27a5769,d91c65c,1492a87b,9ed5f5d0,bf5eb739,9011a282,3110834c,4d467855,6e02f2ed,601529b3,a2f3d70f,8410f8b2) -,S(b1d02f0a,c86d8757,48685790,918c15a,a7b0e85c,f12cc52d,53f8082e,549ba16,7925e03,99926b76,8a80878d,63f3852b,97297725,96d3d06b,85437fc2,571a19d0) -,S(cd27372f,41d8e07d,1bd2ec1,27c41842,7e5267ef,14f3a908,882e4e40,381d1905,cce36e03,661b9f33,ccf810f3,b411693a,c3329617,52098352,2acaf0c9,5dc77297) -,S(112644fc,26ca3599,3b68940f,5cbaab4f,ad2258cf,bbc81695,b01db49b,dd9d3ace,8685f790,7b5ab95f,2f7a49b3,bedf09d3,7ff1362b,3be9db90,4e74d049,15c0bf60) -,S(918df72a,99ce4a16,20e84575,935a24d9,92fb51ea,eb8498bb,3a606e2c,d97d3ce,88b339ec,9ebbff98,f1b8b0d3,c90794cd,bb6b7918,2749b065,602ccfeb,bb8a8461) -,S(9b8f18f2,65c4ffc8,9425b51,d48a770,436e6424,f34a1af2,a7dacfab,fcdcb83b,bfb95e8,6a34c1b9,2c2e8c78,fc628139,476c4af9,3f63d247,5e454a9a,d585ba55) -,S(ad02f2a,c396626a,42abe52a,1ea1d8e4,3821740a,d8b3340c,9b9c78ff,bc24ce30,fcc738e6,cf8a7872,ff827cfe,1b7bb7a7,ad8c97e5,e254db13,255c2d07,1a2885fb) -,S(359afbd,5e60dac9,8ee34f3,f5acf126,9b5c1928,8f54476c,84bfb9ad,da6d85a3,2e2aa1e7,9cd3fed6,71272155,3932ce17,44358636,a18230f6,b501579f,b3088955) -,S(5639aa3e,230f2f1c,e10c34a3,1cd6c78f,c3c15c0,2061f3ca,55e09116,68b279de,e0b6e95c,15de7f0b,3fa3bc26,3a9e83e2,e3a7d51b,462709c,8ed6c2ec,b511bef1) -,S(309cffcc,7b2f959d,85cef3d0,c25efc2b,693d3b6c,ad42ce4a,d8657652,d669ec44,3abb62f,d917b1be,79809520,5521d522,32f949a6,7999274b,cf7965b7,a950077d) -,S(51f3d5d2,dac1d7c0,5d8eab6,375c9130,534a026a,48abf3ca,ce91af6e,533b86b2,50b1e7f,4bdc48ed,9f3fbfe0,ca05bdda,34f9cf2a,ad04235a,ba998a8f,a3e99f74) -,S(8f563d18,33aa4100,4540e0c6,f501d327,4158b0f4,8b3e4e1f,a3fe25ee,29c2a244,4d4c71d8,5ea93371,57f5248d,a012898f,3d031d93,c1803589,2875928,67432193) -,S(36ca2909,d68fdab9,cbc45b39,fb096ac0,3c4853c0,ee19d108,ee7c72c8,a77177a9,64f511df,c8252960,85f3d095,31467a5e,69cbf363,30e12ed6,90516208,d24301b0) -,S(f628b8d5,1f3ffd7c,c201ca9c,2db26f0f,58dd918e,b4d70cf3,80734702,8ea306e0,bd6bce3,ea82e9b,2e8d6eb2,7f557def,b7c2d77d,e6329c1e,a2d360bb,d8adc2e8) -,S(fb7a6bf5,a82c0b,b2a6922c,9d0350d4,b44fa7d7,61002f25,86e41152,c0e67c1b,c12a1c37,f1c9c703,1f1406,efe8f3e9,8419fc33,23a1acfb,345ebc9,4a702da1) -,S(c2091919,5c3e2af2,df14080f,400c8c75,bf8ec01d,a5a5b033,75391fbc,fe78d092,b307b56f,cbebdab3,ef87b1fa,3b66c327,7aec3818,e880de6c,3826b632,f1adeb9) -,S(7627df89,3d1727fa,a06d7c4c,93774a48,73c3bef8,d19bc03e,8d1bfe28,bd3192d1,35d2676c,36f455f7,aa29a865,f0776c52,1326dacf,f6d366f4,bcf726b1,b68451e1) -,S(26666518,7c9f33a9,6d25df65,8dbfe035,a3df6f73,cb059639,ed54b296,2c62b9,bb30bbc7,d34a5e26,a51fe757,8356a876,c4e7fcae,f4a977ba,468025a4,c686630d) -,S(3bda9185,fa9802e7,7dc6a02e,8f2a6f71,ef8b125f,735837bb,c7abf3a4,c62ac683,202edf2b,c11d1784,d7875a76,a0ae3876,22b3475c,bb0ca118,9362e54c,a05b85) -,S(2f90bcde,4486b64d,81313c71,48570d22,3be1978b,7f524097,bc033d6b,983a5c4d,63864e50,2028d475,365b2e30,cca99dd,f4aa759e,cf579705,270fda71,bc384f89) -,S(8893f5d4,e9b00e6f,dc992e65,4c9fcd71,7083edc2,6c71dcb6,562bcfbc,c8becda7,1faf3055,8e631074,fbf566a1,fe0c6996,a80fa29d,6cdb8313,fe313b4,b238ab50) -,S(acfc4ae6,86be5de3,eda4fac5,4da73510,f482fc25,309ce37d,855c3495,8555abba,387f4597,d1878a6a,d37a5b99,8ec291fd,76423f7c,f9bd037c,b9071685,2ac52d87) -,S(2ac4d090,a4c5e988,2f3a892d,d28a5229,d5fe35e7,d74660d9,5422a55e,2017a469,6058f516,2aa3ec45,47a79f2d,7d8e6869,927d172b,f75a1914,a3bc2571,df086c09) -,S(137ed3f,fc13c572,e5bc235c,d13c7e62,c9b1a3ec,250c024e,9c9f584e,7ebadef6,c1e95cc,3a464f51,b43ff02,3c8758f1,319e7c2,f37acbf5,4fb8536a,8ec6fdba) -,S(28a037a,72148a3d,2c89f606,81152b94,6cfb16f7,58f0a002,cfe4d857,ef3ecfe4,b2f4b650,135cde9b,8d3788cf,5c6e7a3a,ec595124,fa903aa8,a1bb3984,fb973d10) -,S(303ecd51,8fd433fb,ce9d426e,8761a76f,78ad6d5b,5f34c0ae,3bbaddcf,1a7a9eeb,6a7fca44,3b73b19e,967a5945,a275cb1a,cbd8dc3e,89d85385,ea956339,99abb602) -,S(cf63042e,5680f71c,2641defd,9d6569ba,c69cf079,f8b3140a,50923381,51533202,39f3376d,fb17fdc5,719a2052,5e1aa428,176643a,f50dc9b6,b8ff3401,eceb4ee8) -,S(cfafbbef,b4a49fb6,96923b6f,2e56c493,34a229a8,e2dd968c,44f485aa,1b1fe4b7,dc0ed34d,4a9c17e1,ddfafbc7,1d76f71,f3950698,18faa16,b5d25c6,c69f9007) -,S(ec0e3de1,fd527ea,6a493ff7,b3c6aa40,4a7ffd76,9a08953d,785d2f31,390d363e,94bddbce,300234c1,82f3c6a,717f53cd,723129c0,ff353528,fc5c285f,8e7a35dd) -,S(f07d3cd1,914422cf,d4b9c0c3,501916bd,13e9cd84,eeb02f7f,84be2a40,4b2bcde0,cf0c96fa,cb393218,37c48de5,16d1f705,dfe91206,8ae2d810,3aa1f77b,39637320) -,S(4a4254b6,6f2e204e,a3264ac0,a00c7a63,8a6fab7d,e67643e2,8217099f,3648db10,b5510e29,be93fc35,efbef989,15f7df95,b187ab08,bacb157a,c26ab2bc,2ee5023a) -,S(56f3bcf,b38eaf1d,35e62582,9f671945,910285b0,3805c1d9,b5d813e8,e87774a8,a9b964e7,9e6b7f9a,9abf3e5c,a147f773,8a1e8270,8677e6ba,c57a7a75,d1ed9dc6) -,S(f89d8f4e,7d32efc,c2d95bf,feaa4c9d,af6b9886,51fe7561,ace561be,6b081295,ca632f11,56a33867,63a65691,17186994,75e48f51,48d770d1,449ec719,8dbacc69) -,S(5c3791a0,d3e716eb,50ae4a07,51f0e92b,2890b933,c6d9aaf9,758e5205,27c5530b,44ef13c6,2de52d11,179e30da,e913493a,c4ed861c,336ae1c3,ca1f8bab,a7b34616) -,S(2748765a,e6baa4ae,62cd7156,16ceeadb,8ab94ef0,d3a3e331,15fa0132,aba38d27,71d4d19d,de63770d,60905bbe,6c7ae92a,f36b333,a93b3359,cd4f1f2,77f69e48) -,S(964f1fa2,f8ecd778,2ce4ee1,87ee3e78,d2c41a0,45a95453,22e363be,bb27e254,c744bbca,de64a883,e9481a5f,a2cce621,5137ae00,3b9822e6,77556610,d4138a2e) -,S(8bf60775,8709c9fa,8503594f,e6c379ff,ee758a07,4f7d2754,58985e25,79b8ca3b,3e638992,b3fbdd72,ff51cfb8,fb118d0e,ccc193ee,718a7715,a5ae6188,87dd51a4) -,S(fa107123,9189239c,2bfc5a95,ddbee798,fbff70d8,ee0d5f5,a10238dd,2e06612,a60cd5e,1a4eb0a5,99133ea9,71d5ec1e,315a6be1,2d773936,c624c468,f968e7f1) -,S(5b48c6d0,9f6f97fe,c03d145e,f797cb8b,3fe2503c,a8944593,83c34e51,44975588,44d86689,352611bc,c1291762,d965f136,173d6c45,28077d83,c6410a3a,906e30a0) -,S(80e153e8,23aa7e3f,2865d1ea,1e5e88c8,5d4e854d,54bca5b1,ae8f1bca,eeb94fd0,edd3fe29,e435c11b,13a92d8,ef4f6413,c888a12c,71823f7,3ed7acba,a06b9728) -,S(16e225d9,77bf7526,c2590dd1,54c6e29b,cd25de9f,7b1fe3d,ae7ed6d0,79ccf2c4,e0702d23,b9b57554,6d2db82a,fcdc22b7,40088c52,e0fa274d,d85188ac,9710768) -,S(a3440a09,15a16c74,8221b65e,7825ebcb,bb064aa2,de3593ce,7a691efc,d9456938,ff7c7aa0,3a582a8f,5641323a,7f437a67,26fa5d3d,e7c3e26b,be970904,d4dbf40c) -,S(8154334c,d1164468,2320401,f2d59385,8d607203,93eb37c8,a030e9e,cdaa2b5f,bba4094e,5f97e4e7,b0f0676f,4a091488,17126ad8,7d573d54,150139c6,5b3d5142) -,S(c91348ca,27b5baca,3a092b25,74e09976,fe7f2361,3e1b5efa,329e6a5b,7d4d93c7,ce241d0d,e9d49a2c,5060e62d,c01bfb59,e7c37295,4095f639,9d61e73c,5976b44a) -,S(9408b5a8,79fead4c,67635e99,59ca9649,cf362940,737e6436,3ba2590d,7e6e8a88,e10b410a,26c710c1,bf2858d5,21f46094,e02155d2,84b80fdf,cbf17645,7f994fc0) -,S(b851d158,eefe48b8,79e0a159,f8582aae,f80ddf90,d9021b92,e7d3e7e5,d6bdd2ce,290ae2e1,792421,c1cc53f0,69c7d580,60facfd8,e537693f,6abdaa2,c6d85469) -,S(9d320b4d,4a7c2007,65805387,5e536093,87e7a5b8,54da05eb,1b971e6a,e53d10fc,4f6acb7b,6a1f190d,6822acd0,ae783b0c,9b44be61,ca68306e,79603f47,25d7c456) -,S(6d779810,7b29ec65,4ff86799,d13a4d89,eaa49114,d00744c2,2f30a9e8,358ac7b5,8f7993cc,105c4f09,ba060a2a,ce265cc5,77b2a334,3ba3880,4b0a3e79,db823950) -,S(bdb2d2ce,77e14fb6,9a17d62d,b8056d28,680c9607,2c82772d,73c91da9,e57f6489,9c1ef71,d43c3b19,dcf8eced,ea6f5648,8a3bc00,3c2b0c1,84c9e42e,5baa590d) -,S(49a8ccff,1ab70a94,a4db4787,f73bb058,1f7897a8,d0a1adea,741ffda3,f055b3fa,f298d277,2049ebd1,ee2414ed,6e053ad5,15b41914,fd6de43d,8bd9282a,6c6ba426) -,S(ca3f7d6e,b466b7b0,56267992,d317a02d,3b3d5652,b51040d7,7f1a173a,769d2236,a26d6225,9dcf384e,f78e6f2b,f96a42c0,90e538ad,f6f1a1b7,126dbb12,8e145c37) -,S(b672ce14,f1c427d1,b478469c,b0d08b99,902e9cad,a66bc65b,c00ea630,737176e4,176c0979,15176,27a0f1af,f3c5a56c,83f4f550,b8c4bedd,b818bf76,68865efa) -,S(bdcbab57,d4ad621b,d6db6866,f43778aa,2c26dd78,8f2e968b,da3c913a,ee9c199b,79868872,9bb213fd,7dc75a33,8d6168da,1cee9f0e,e93c7c11,24055232,88df5603) -,S(f5f25f1e,382f7df5,74c64aa9,6c5f423e,d5beed0,82d80196,1cb384b2,55fbf9f5,ea388f0b,5ad84aae,58393a82,9a50a4d0,f54bc068,e12724c,98a9dffa,f2210221) -,S(d2a10464,f9f8ab9e,1ca6e280,b2747c43,60372049,85a2650a,a730b894,16ae09c3,d19719ed,8dc46533,28d8dca,f2c902eb,2c9ffaeb,ab3c1b45,4fdcf68b,229c5962) -,S(89255afe,e6724c4b,c5522105,8e5e6aa5,19058c3f,f3ff691c,c5f81a00,20410038,8d626dd,9560c934,11b52ffb,4fbab500,c833c3b4,671713e6,9147d8af,da3fd7bd) -,S(5e468c42,c5eceeee,2a67d73f,57819019,5165e3f2,6c93f94,beb12fbd,556e3952,af83e24a,467f97e2,ab8b6a8c,330e400f,ce1fdeb4,3a4ae1ed,c3866505,8cf240de) -,S(70c2bfac,9eca198b,f606850e,8f54ab03,552caf8e,9385036d,7fc85007,e99c4e2c,60322365,f5ffae57,8a8f9939,20cf7596,3b45d940,d2c4591,544feb6c,d6ea37b3) -,S(16143d3a,fe5f6b42,500f86d,7c79630f,bbb0db1a,64e901ee,ab641c0c,b9c2f318,7078e814,bdf81d7,81109561,d4d1cd37,9fd74924,4cad1e68,ecb8b247,d76a8a94) -,S(8ac33ead,a9341644,db25b034,60ff60ab,e1326eb7,73a0bed0,29f6e966,16b62bce,6d07756,6f0d18b4,bd055d0e,d99bda50,ea9e614f,da46005d,c6d9dbfd,18945cc6) -,S(476b98b8,9e7feafd,ef5f0116,6e0c8eb6,70cb3325,a10fbce7,71ea9e06,2566e22a,38dbf041,83252b86,7e138483,c012f220,fd98bd5d,b80fbf47,30c5d0e1,d6a91050) -,S(e4d262ef,f0de9c3b,d3302bcb,321adfa1,2e383a7f,19297058,a19c453e,ed497f11,a1f830fc,2fd6120c,8f2070c4,9ea49001,953d0c0e,7c02050b,fec7cf7b,ce2781d3) -,S(67bc850f,48f0be1b,f18c4f7c,b9f33e67,e2e09279,4196d987,1bec0fcf,f0b5cbf8,e2560470,334aa4b2,4693e927,1d2f20cd,b7e6fabc,92e0f355,526dceb8,5f52d32f) -,S(50dcb2c5,c0dd4942,2564be02,2ab274e,b543a6a5,a2712b8d,58f51e12,72ef2797,2cbc036f,b69c44c9,9c7854b4,9705dccb,8d2ea16a,2f77fca8,90d89f8d,4ab04ea0) -,S(6c9bc577,784948f4,1e8a57f1,bddf5665,f860804e,89912876,44ba7b76,8758bd6e,84a671f3,5998ac84,7329ca3d,1224901b,a0401915,c9280260,cd40ff44,ebb3ff20) -,S(5dac93c6,d27cdbb9,9f3ceb36,18c6ead1,28b44146,467390e7,a337c494,8382a868,86572065,1805082e,7434578a,a97704f8,8a91c2b8,e315ed8b,ac2a4bf8,342df508) -,S(207903c6,5e1c57e1,7a6e9484,d3073c0f,f6b2a40a,b46b996f,2ed2be7c,85780c86,4b568420,29564d4f,6c4fd310,73e17a3a,bbdcb83,115a6c14,854633c1,47f6a442) -,S(da025f63,9be593e9,3ab35113,2282830f,6ffbc94c,829111dd,29546221,2edc2f90,9b4acdeb,a315e576,f0edea9a,21acf5c8,714defa6,5ef4ae68,eb694383,916d2723) -,S(327faacd,1b489c8,2126ffa6,b87cf191,2a0f61f5,ee47eea5,6030a50f,b2823cb1,634ab42,6010009b,144c5ac2,903e5f8b,14c00c67,5fe177e9,6b7f9ecf,b8c33b9b) -,S(44cffbee,1619f462,a853478b,a9d1bfd8,6c9cab17,f5bf50cc,79a24558,7b7e8084,b08983db,62079e28,7eaf8c28,81079a45,76442a1c,fe35f64,563c714d,748e7da4) -,S(c5d945ca,13730ce2,c21ad679,734d1deb,beb19785,480f93a,43a2170e,6a6fe3a,a3aad11b,4d8b7140,f67f7287,8e4a9c1f,74102ffb,ca3ef04,46e7bf1b,ae3cc3fb) -,S(f4d8cf19,84dfe935,11b2694b,8f1db0ed,d4bf22f6,435359e6,77fa42e1,cec0de31,83d02d22,3aae1880,d7ad76bf,c7e3bfde,5b48a55d,4fb0ff02,c0ba5c2,e9a30845) -,S(13d721dc,8e7b0bc8,90c6380a,fd0f0ee7,a2dce0e1,e153ae70,7e50ae7c,1837c4cd,c620c1e3,e1575411,7eb9e823,70af7e4c,9309c412,d5f14d28,e976112e,88841116) -,S(e5f9efa6,66fc6728,207eb55d,94c1daf2,5164824c,e27b1783,92862e11,6265ce1a,500a9fe6,18302bb5,22ff9fbe,163d79b6,1f0f3cf,53e0956c,7712f23d,5c0d9975) -,S(73ee3cbd,a1ba137,65a7abb9,827b1b32,a48ea0e0,a43e9698,8da603c3,c319c9ec,d96832b4,4093689c,beb30bd5,a2e825f3,bbc909d0,20e18744,b0a5ec5a,1ab38f58) -,S(11b92fc5,94046bba,813285e7,122750a4,3e028501,f027a55d,f101d2cf,c5990d91,e08b24aa,e20fcfe0,40dcfcd0,80949b2c,23b324cd,1d957b63,9fe91716,a4315417) -,S(3043669c,22be0dc5,fb14442a,22a625d,b1bf4952,362f06a0,623ca1cf,9160935b,dc4834b0,4bf47d6b,fad52c04,4d26e21b,41eeadb2,5c92ca22,6dd2c86,24d0eb34) -,S(490c39aa,c290d144,2b87622b,407dec4a,3f92aa61,6a9c8495,132b5c7d,3d5f9a0c,5c76c0fd,57844aa6,fe81361f,73cb314f,110f87de,6773e1ea,b3d68dae,2926b986) -,S(fdd5cd58,67d73347,ca1fb212,772b0c42,3a4caf94,a3e0bf2d,2bbb2433,9002d03a,efe5f407,d1d26bc7,6fb5bcc0,6bc94da5,bd69f84c,85d89172,10bce909,77411995) -,S(bc8a108e,b0830fce,443db272,2655ac40,e2d35989,cad192d8,e9c5017,14435ea9,924c0258,cbc3da74,a708a384,b93196c0,76bd3af6,2907cd60,22069b93,e3c979f9) -,S(ed809b6e,41f4b6cb,86ae431a,718989cd,2c706ea4,10152e3b,3395df8e,ae924b44,135d805c,3295589,c8d42ffe,947aa88,bede6699,b119f8a,324c9bfc,64315da8) -,S(26b50ac7,5d871e07,4147d2f1,ee42d6a8,4398212,79e9f276,7978517b,6cda52d8,26599c63,86426e9f,b14b4c8,3494f0e,1fe37ea0,521e4518,e346bad,545dd7a0) -,S(cced88de,27d0ccd4,7f6746ff,98907cf1,679f6b10,67785dd7,25ab94d4,9fe8efd5,5b0ede2b,4dc584ac,b4b6adc2,c52b4268,e2beba67,ce2bc825,fe4df43d,73f5729a) -,S(d8edf7cb,31526332,308429c1,178886ce,bf3fe516,18f472bb,52da883d,d83c6249,a56abc3e,c155eef6,d43427e1,30ba691d,8c71b80,6b487343,7f3daf07,17984be3) -,S(ed82c3c9,f8db3a75,50949aa5,cd6c8fce,52648910,53f66515,c2fb71c4,7564b4ef,5ee59949,6d9d3c7,6fa9a26d,444a8a45,41ddccc8,15fccf39,b06e8fe5,20b2f0b4) -,S(6e277bae,e89aeb54,5e6249d,56d50848,5853b3ad,8588365e,7771ae44,3d8ca937,84871bd8,1e6f94a7,c31a3fe6,63a1170c,8f9623dc,4e24a5b4,3f7d023,39f40b8e) -,S(aeb67ac8,67271210,565b1229,3e1aff94,f2f8b642,76768967,f702afb9,48a03c5c,fcd3c588,94259c03,cde7898d,66ff5ac6,747100bf,3707e89b,6980d21d,78bde197) -,S(9f07ff4b,aa20c756,94c967d1,e38633e8,45753193,a3d13af2,3ba7ce07,5283da79,ae8b7f0d,49d06168,ff3c5f36,3aca3f1c,14308cf7,d95bae36,3975fb7f,dff2136b) -,S(24046d14,a026daba,1644b3ef,7bc5501b,baafc3c9,76acfdf7,243395d5,713e1520,265485e9,6dc40a31,ba93cd0e,915534b4,37fd5380,bad0d6cd,321867cc,aa029ae6) -,S(1376926,bf8fd1c6,80344f48,c574e6b9,1806afab,7d9f90c9,13bbc233,2b3de519,a34100e7,c4b44c26,f86b2198,e7d3696d,8aed9051,a1755ced,56ebe795,d5a61fa5) -,S(943c6d4e,816cc668,87f7c85f,b116ae82,5e4c38a6,581cd5f1,1efc9a3e,ef5a7d6e,d93d4724,f618da6d,29e35165,7883ee36,74112f70,3169eb24,eca31a60,969de8dd) -,S(adf8041f,159260fd,cafc9e61,d5f4f867,a0f46e94,af60bf53,d4d0808e,885432d9,c4eaba1f,99d2516f,3d731bcb,be90b36e,c055ff5d,e6c3ed95,2b95a037,1be57958) -,S(15c17f13,a404ae08,11ddefb6,707a9fa9,dc0d9461,8325dbb8,d96537c0,6e2dcc44,8740d352,21f95e8,36842b48,2512d79d,a799fb62,60d65dc6,79df383a,e9b6898e) -,S(87bbbb35,62365994,9c5bd575,86b813dc,966ec9ed,1ac31435,80e4b7cd,cacb8ca0,159992c,1bfc3c24,95e14ccb,e24a3e9b,6a28f4e9,1cad4a36,f83624a8,d22a48c4) -,S(39bd144a,96454c1,9e082b5f,eae9c433,564da73c,d5d44daf,95b5c176,9f1fa105,ffe8a11c,30b5d4d6,f8abe12e,bc3ca8f9,dadf1527,330319bc,fa277b13,256fb207) -,S(c4e4eb4f,9bcec0c6,6bb99bfe,265b2f4c,a1c69676,ee970a9a,b78bbd64,a83bca7a,1bb9a83d,316cb9c4,bce4be2b,d05e6381,2ecb493b,44fc3cb7,c2248a0e,96bfc286) -,S(c183e783,1c80d334,f0ddd2f4,48ca035e,8b53f034,f53c1801,488e4aec,cf244e69,f998feaa,c7711d48,3db38926,8ddc080c,8ff2f95,494e60b1,59330d8b,d9a8b820) -,S(99d1d7ac,22a2e108,f093b630,f374d9d2,7ac812d9,5753bb6b,e39c2401,fed47d92,a67d334,88dfe341,e8dca3d9,b36a897b,52080a3d,c366c8b0,39cc4de3,52d0e1f0) -,S(e0700a5d,16cd89bb,df3d6f18,76909082,985a3339,e7f5d2bc,5c3ccc92,ad61cea5,26f6abe0,38953fa8,40bec97b,c9d59c20,1fd08b29,4a7ac7e3,bd994e07,70a0b0f0) -,S(b19bf6e8,cf36d839,51b813b5,67aa62ee,5415e95c,d3fa668b,55487a3e,61a7e721,630e78a5,ca2cdb2e,cd59f59e,4c10e712,46c1055b,a7709041,fc03f8b9,1970153d) -,S(25009156,e90dd0ec,88027adf,a9701474,39abaf72,1c333943,c6fe6e19,ff71fd44,324047dc,86477632,214ed74,cb933859,b7825500,2d19ddec,9c466e1f,573afc11) -,S(45ce7fe8,bbe45d1c,9bb0c98d,9d4c500a,aca5011f,96238681,771b8538,61a3e4ae,8cbc22af,d1adb8f0,a5c72570,2b6c7f65,9e41b176,1358832,7ca062e4,2392f8b1) -,S(73255507,d3a27fc6,7df39212,a286ef6,b939e953,43b12683,4e38148b,619ec059,3174d6e6,e941020d,db0f3ded,aed6c8cc,eeba10ed,1344ce28,a354e93f,25c35b63) -,S(96b2cef4,1c6c39e,1ec9a945,8c8bad3f,6025962d,a1207885,97800ac1,c811df58,ed85ed21,41b4ad26,3adab5b7,c0c0035c,2fbf9e2d,983dda99,7d1249c6,8a7fa8cd) -,S(5764181c,d941b28a,a307bebb,912ae87,57f23cc9,37025cdb,b983eef6,42b9c772,e8173b4f,c23908fd,db5f6437,5457a43d,2495764c,f3ce1b8e,f2c8d2be,e0ac7089) -,S(38ec7839,7e965056,2b1e314,5d5b2782,ea16d2a3,82bb6c60,efd29edc,93ec1b61,acf04ea4,c7b6de2c,d8acaa3b,a4bf2656,f522e631,1cd51089,744d4c96,318ec96e) -,S(6ec4ef80,13d01c79,758439fa,108f7389,79c9f7dd,4b285eb8,b7aed579,76c0b572,2328e642,e618ecdf,3a6560e,3eb6af15,7a6d266a,f5f3c4df,13c1ba2f,c898be7e) -,S(d8da1f6b,30c27b1a,5000fc14,9a768683,4c40a581,c4ed67ba,88492449,ef77141b,ccb532d6,876d92cf,2b8c310,839387d7,d92464e1,727287dc,49a3b348,2d519758) -,S(84f25402,734970ec,966aa9f0,eca84a1e,6894d36c,338722b4,e5fed162,8f7ccb90,f2d7fd09,f07e6302,cc97d283,d9f06319,9bee137,d3946944,983c2192,335cd8b1) -,S(ef6752b5,58874372,859190e3,91d86ff7,3adabfd4,cf008038,136b2ddc,ce9503e3,23d9ca50,13cb479,7cbaa675,98dcf98e,73f949e4,614390f9,1e6159f8,3f131c56) -,S(f88d8590,3b3fe67c,f641cb52,c77c776c,fe198f74,fe116a46,602bc2c0,1085ba6d,58af2abd,2178ad68,a3695714,cddf14e4,21da61a2,8e6cfa32,40507fb7,ba08742d) -,S(93b739bd,d366b95c,675daaa8,c5ded7d2,18cde6d5,d15d354,645de017,2db9c01c,24ec535,6c2f8eaa,633af5b9,6ae0fcad,7afea5f1,c7c8bfb4,748b886e,25cf3627) -,S(732cf404,da7ae5a2,dbf82f80,180c1154,6d313b92,58980f95,d413f223,443394,858e8326,1758b90a,902eae58,a777b56,e8820084,153c9e43,1b7d789a,4d596953) -,S(efde0719,2c40002d,3f82e024,a1b838b7,65fc252b,5be4af75,28ea5994,a9d36e32,89c1d35c,3a153576,91a63585,183a9c6f,b8dd69b5,69d45483,f0c2f80d,3dd9107b) -,S(9eedaaf2,80693392,76420c1c,da950bda,f114e65b,9b1a74a6,b42dd90c,1ec90a15,1399dc24,7fa540cd,3249728d,a4d28c52,26f427e1,ac3b533,7de8ba07,d3164de2) -,S(23f0ea8d,342aa214,69deaafe,bfdb487f,775805c7,d4ba17dd,877d3d42,19433195,dc1c6e31,d2a481c5,5d32ca8d,1d4e93c1,63444dc3,9e7c306e,4fcbfd46,b699b03) -,S(d85270,58c29e60,58916e82,76a305d2,edd47c0d,4e33052c,74cb76e,abe060b8,9a0e4904,e4db5bb9,5ec9e510,59ea4993,84d497b6,8a9a1258,3a2fda6e,bd0cfac8) -,S(1b34c95c,ccf91204,5922d2d1,90cf3860,f7d36b37,7ab3763a,d4d9046b,309f28b8,70c2320c,3f5f663a,b6478c3d,2607cb4d,f7080de8,91bb408f,6f14a11e,2951e948) -,S(32558fdc,ae5e596b,b756d4e2,f10707a,89569d36,1498e8c2,8fca1473,4b84b228,7759a8b7,5ed5755b,b23978c4,3d5aacd9,fe63f6e0,74b6fcfb,501906f9,16038d86) -,S(64818b77,37d2bc57,391a3820,2040afbd,6028d7ec,fa3d6bf8,577cb1e8,dd984acd,4202b934,6ae9554d,9227b891,4a6304bd,2cf895ec,a7267e1f,5707489,71ca2300) -,S(c6af6ac6,ec2d7cb5,42aa2373,24288551,bcd33705,72e1b1aa,e572d87d,8d77b333,fffe5559,4ae5a2df,18e393bc,dd0407ed,5d5af18b,85f22352,9fcc7cda,dec78cbf) -,S(91f8fc44,94ea12f8,fa2a031,7f32fd44,2e7a9e34,28eeaf13,a8b0de3e,a4f1cef0,6a0a47a,d81b1dd0,ac6765f4,20cc26af,e76c2225,eaea2a42,481ff6d9,a554dbcf) -,S(e159a9fa,6a26f57c,879b081f,dc015b46,dc610a61,2335d6c8,e353fc42,11c1c017,c209c643,445ae009,a75656f9,b4c1df2c,f1c181c7,ca81d0b6,bd749afa,a93e8851) -,S(e8e9fc5e,135f3a97,1211eda9,c06d283f,1a705169,b89e5813,556beba5,a4f9330b,e8b96899,3b73e8f6,da7b55fa,6f1e44b5,c88423b9,f3fc5553,fe0b10d4,e9af0abb) -,S(f3f5d529,d5ae4c0c,36c27ec6,e13384b4,11aa9818,aeefb5b1,64243536,bc0edead,3f740643,1e40c133,345abbc4,ffc5e0aa,1dd1e306,43e52ae5,33f5be61,db3d34b9) -,S(c5b76430,f5d8bb9a,e1b9acff,e1417602,9eae65c,9ca1606a,2e4f6d7,6cc81159,80689f09,70089098,24087591,6915380a,29b13933,9a000fad,d2e86d8,cf2429c1) -,S(954aa4b4,34f59074,45ed30c9,ffb6db50,ff275564,72894261,e935109c,cfc09b0,8023ca86,1bad2c25,6cd76be8,b3b0fcf3,a808b76e,80a70ec5,83265d3d,c72e4ad) -,S(55da8bb,4803f339,3020c9b9,30a58336,1b96ee54,4bbb4249,d6df1335,6e3d528b,dcc44b88,ca06e9f5,86cbb209,da01785c,2387b14d,355a2575,799ef7ce,32e5b64c) -,S(8084e800,d810b286,b0ad48d3,d262b4e1,db59eabc,a176e368,77a7f8bb,a3a1de03,d8beea9c,59f865fc,9f09c12,9bc5f980,70d60ac,eb348f85,e0888fc4,63dc1480) -,S(1b2bb6c2,36c87f88,748f49a1,5094949b,d15e0217,b00c0bd7,f85efa41,5718b39b,2164b195,6aadf36e,f1bdd018,6bea9a4,c3c3f42c,b0e81dc,8101ad14,51029c74) -,S(fba687e8,125c372,e5dc65ce,3d2febed,de9139d9,9f91ad84,830da38a,54377872,8944eadf,3b89501,ca4a7a82,105a9613,55aabbf2,57f4bf83,923ec12,73e001c9) -,S(b58e4b80,a5f1c16f,f9c699c9,75a2d797,d21e155e,f091ba94,8aae2dfe,fd560cbd,fff9caba,1429bfa6,e571b7f4,12d6aa97,4606f7d,9025efec,937a5128,52cec3ec) -,S(8ebcd526,da5d6c21,55222551,e05c6be4,114fdb7c,9d43a900,fcef17ce,3426edec,73a0fb98,6b3301b6,3eaaafb1,a52f5467,de11f034,aeedc21e,ae97df86,513aa97e) -,S(fba4540b,924b29e8,95dc68f0,e971549b,7354e032,64040d2d,bb956691,1bee325e,529088c3,3b9857ae,342ba0d0,7e52843a,290f3c27,16f5321b,6c9e6f51,9105ebd4) -,S(8b7a2c97,a1a7d324,6d86301a,66f3f36e,ce014c97,651b25b0,ab46f4e8,bf9c44de,b82854ab,699c35b3,6786c1f4,71ea7536,7c88a684,43fc17b9,4cb328fd,a4b247c7) -,S(9df11743,5adb7154,e7003bbb,a1ba909b,93179677,4bd4896f,40c39a58,ead2279c,a7922f4e,a216cc36,c36913d6,e7ab8641,d4566865,dd7a2f83,77ef219b,41b884eb) -,S(5beb7b84,749b444c,82efd9e7,37314892,c54b6215,c1f9be9e,414adae4,56931cd8,99e425f,32cd0a7c,28e753fb,ff308eff,d32b7cfc,eb51df7b,64f60e9b,2fabb95c) -,S(2a830c43,ff204ba,78c5114f,4a3b7b09,c9f8ed5d,17066f43,cd512af6,4c788879,12523a4,e8882652,eba827fe,d207eb00,9ba14809,9ee42865,61e96230,62666c84) -,S(f71a46a1,4c1f2a18,e68ab408,bcd32d94,985a7714,19c1419,1b69221e,1c57486a,adf19b3e,ea79a53,4fcce36a,4cc0da0f,4fac443f,b281cf0a,ef675b6d,20534875) -,S(2b80e5dc,aa9c2b31,678ae2d9,f7d63c0c,bbad2bab,36c412fd,cb6436a7,c69d193b,bc83e04d,71d60062,b681ce04,c506247b,8f3c9019,c2084ffa,27621d62,22119c3) -,S(49cbdf3b,e521c69c,68375b58,d4449341,75424a0c,3c45d5b,b975235c,e63beece,c5615eea,f0f0e7ce,c3756aba,d3a136ae,91d260f1,563997a8,ae46c49a,5c62de7f) -,S(ce4d4714,b643b115,9215e2f3,1dd070f7,f7aa663b,9ca87739,79c5ba31,ce9ee1b2,b1f35e12,a2fc3aa3,4db59ef5,e62101b0,479745b4,200c10aa,d6f8fddb,1efeac38) -,S(6827b6bb,aa905ac3,8d93bb1b,5d5881c5,a8bef479,ed7c5656,2992d4dd,61e10054,8524a87b,af65020d,91848427,95801f54,30fc3727,7ef2064d,1aff8ecf,296bb869) -,S(e71e4d5,48f4d7f1,c7b7879a,a03a49a0,ab947218,b16dd125,19af4ad1,8056535f,495d0461,7098b3d5,6f7e3bed,ab5c9813,83aeed68,3ded1c09,f0d1bb38,e32f574) -,S(ef683979,7429fb30,d436aa32,a3feda68,65652816,873ce542,6320667c,6e00e032,b4b18e4a,de1197e8,fded846,f188a6ac,2f17506,f014d404,fbba3635,534613f) -,S(c729c1,ac8f7eff,e908007d,e2eed85,dd557e36,c1ec645b,a258b03,e52deaf4,2e83edc2,18584f6a,c5ebade6,a335a087,12365b89,ac38f27,bde7ebf4,561305fe) -,S(cf1d3919,9a716d53,b2bc4f2c,3ae2ded1,290d54c2,2124a88c,c1cc7fb1,115735ab,6b44f5a5,7ec3402c,e8980970,dab8538b,c276c8ee,ad542908,9b7b70d6,dd00e6e6) -,S(6cf3d7a0,266dee28,f3f1f772,ee90da75,a9c28a7f,f82d8f55,cf9d609a,5becdeae,3bd18fb3,1e11cce2,895b9cf9,4d9a99bc,ede5c9b4,c44ede14,34dfaeb,49bc58d4) -,S(da4b5832,ae63eeca,cdee4274,f00ae932,56393cae,cf830be7,f28749c0,7d395542,9aabb23b,d2d940f1,815610c9,d1684b92,106374e3,1b694ec4,dfec8818,cdb2210b) -,S(f91ae350,23210e16,f9c63270,cea2c6bf,407d1a10,e95842d4,b8ad5f7a,4330bbfa,1f161ac,d1962573,5969290e,fd3d1af1,53c91543,33651e16,1b51086b,913aa1c2) -,S(7e1bef52,cc3e2a2e,45847c86,27328526,c72e3f73,fa1c8255,56c874b2,f2f1ac02,be4b0f7e,a706e4d3,db7048fe,e0fc4f50,8ff0523,ee8d97f4,4c4c1787,e6f6e6fe) -,S(dd2695d,30dc2ee3,748e256c,cdc92eb7,706567f1,4be720ec,b27fc814,d3d5998f,9af32c44,f1028013,9ee7cf99,845472b5,bba67740,f0f0b96e,d1a02a19,a32dc74f) -,S(78fae650,714763c8,d12602ba,33b76da,125fe395,43fb37c9,4d20b337,649dbb9d,78dc4c0f,726cce6,f65826e5,eaf1fea4,c3b92532,6624ce1,21de2351,bfce3aa6) -,S(1edf521e,510e5dd2,aa1d3e00,d016b45a,1b6fb6b8,591d98df,ee692636,8dc98bd5,9a0d016d,9b2e9b8d,d0f4d817,71ab0f20,aeafd8d3,63beca59,7518da41,55311f86) -,S(8607bb0c,5e53b60b,9153272c,d3cc69e4,7ce28694,37562b4d,4166aa18,d0101d39,15ca31e,c83c6541,c35a294a,a648af8e,38870757,27924e98,8ef566d5,96eb519a) -,S(65fd300d,9a0503f7,80a0dbb7,c42b9bb7,37f9607,912f2df7,166b65f7,96d02eab,fcd15350,84fba852,11f94540,1f6b43f2,904caf3c,d44ecaa5,335b928b,4ea3b5d9) -,S(c918b3a7,6c847ce1,c01845f0,34ccbeb3,36d031a9,33093f99,f47f1458,cc02d148,f256f403,dbbb2e20,32063270,faa6e62,596329d,ca85ceb5,3ed3adfd,7f728568) -,S(6ac2dcfd,2f0b879,becb429,140ade0d,532e54d4,dbe0bbb5,c1352ace,5661817,f2c26310,abf9396c,5af23074,e72251c3,784c3de3,60466dc,ccaaae16,4a9e2af3) -,S(8d71c4ee,54acf389,cee39b94,b5feb2b2,cf8e95a9,45f6a95f,5b0bff2f,cb3f3d19,98442bd9,5a02c1c4,7dba3881,e3306103,f0bc8857,89b44cb6,54875847,f1ce52d) -,S(e8bd24d3,fd557118,f2c0abbb,511e874,2e5d7368,a909b072,b3dee124,44f583c3,e1d2c3a6,e28622db,65b7992a,6716459e,2380285a,cd60f43a,4d4b1bf0,8bce6538) -,S(62dc2975,5cf8cf89,e52c8c51,6311e3b4,483fd024,ab2ad1d0,32d7255a,3c075217,799e132,d80d22d8,e0f01e9c,d0954251,8b3fc8a9,48f3cd1e,9391f8f,5c0e2a97) -,S(37db13aa,cf727e60,cb102709,9c7d3c07,4d43234f,66a95451,a6050496,d44c0e13,c383bbe,8f8ceff4,196e9d07,e013a1f6,d3402a6d,d09eafb0,62924334,89b1066b) -,S(37bfb765,eab7719e,c858e17c,472f1df1,be9dc439,2699ec39,37875b30,fb2aa1ab,72718bfd,865dc4c2,2f935f4a,98af8ca6,5cf44b5d,66f0eea,23b53563,d1721364) -,S(433ede12,87fcbf35,5fdba6e1,f62148a7,b5d5c3fe,1200d456,6dba452,a85d1b94,b27c5613,ad6e513b,28f0c959,13e30781,137a4c7c,7aee6e60,5715d949,4757c20e) -,S(e582d9f,c5ed0de6,92a1917f,6ab7df46,d23295d0,b8b27b32,3af9a57d,3e671861,33ee8785,e2770dbd,7e79faa5,386cb1d1,d1c9e073,1b78dfd6,5571deff,d4073154) -,S(60b07b40,634bf15a,ee2d4e5d,a0f06ade,ad8fae01,4a6a189e,4e428600,4c9442c2,fee087cd,d243ba,62b4a2cd,68d8aac5,1557f29c,a57b0f37,ff2119b1,bc4b283d) -,S(4b167276,1e5f7ca,a245e35,b6e88fba,643e6da7,ce37c9b2,10265ad3,2de03100,28aacf02,476887e0,90d26c1d,cd51f15c,cacda02b,b6314a64,73b90c93,8ed8dde7) -,S(5d56113d,6d797e74,c4803e63,89a88ae2,fab97de1,4ed4e7b2,a17d2f9b,fe2a3170,94ef2a8,534eb2ff,a62462a2,7eb2b34e,c6545992,e2d973ab,ee42b1e7,d9cd524f) -,S(a9d03fae,75111ad8,d1157287,8e8c4473,f4a06cd8,f28dfa7e,e38b3d06,3a34f828,a0733c0c,c7319879,2ca665bf,968f6bab,480c94b4,c7de262e,4d9d1f95,33517881) -,S(74199571,2b1abce9,ed4db3b7,7b3f7e70,58fd3716,1666c522,50855f25,660e1ad5,710caea8,97f7589,cfd3b8a3,22726000,ea3ef2c1,8aac385f,22b67bd9,da44db) -,S(9f16990d,bf81a5b1,eeba1e5f,84673e16,ba0106f2,acc68be7,cabab96f,25918dc8,d60d47b,62321042,34c49d39,c03806ab,135d46f1,ea6587b0,f0b6588c,50ebc4f5) -,S(3b5069bc,4f12b9a7,ad91c888,fabd15a7,c99143f4,c8b24619,b6a70c0b,2301d57d,dbb87cd1,ae59a944,9fb4ddfd,4b311d66,da18544e,a86b75a8,979828c7,fddd1a79) -,S(9dea63a9,67b5a36e,bbbf9af,bbfabb31,f90cdcd7,9b75c68,1159b946,dabaee90,b14bb99b,11bab958,e31a605c,e9180d23,5c7d2eb,94d4de57,b8a66627,c6bc4464) -,S(d0b23392,1da36a84,2565cb53,4411e63b,9fe6b2c,c33c3a18,8e0ddf48,55e31e79,80ed93ea,1a6e5492,dcaf1cfc,c350b3b2,99117276,43fb6a75,15c435e5,f74f8e9) -,S(8adc9655,966ae44b,f98ca7a4,9f441e3f,acfe85c8,f7111da5,52c817b3,90b03d20,ce72054c,6a717312,180c80ea,c9337430,5dd1d566,db1b93b4,eed1a6e5,73c0021e) -,S(f6f76bf8,cf6d3dea,700800b6,d018a4a6,141ac610,e2e13fe3,ec916726,1e0c1670,b2c478af,e1ea9876,98e5e2a1,6b3a4ee,63e4fef7,6644da54,e241c395,3f9a302c) -,S(d58287d,38b7da30,174fcaa1,873b3913,2176388d,6da5f9fe,f873d86f,14b898e5,785fc934,69ed085e,8318f91d,114ad0cf,da2b8ff5,61e545ee,3502e9ec,6afc8402) -,S(7772ca23,50c5ee55,9ffe810c,6d8702c1,538e3d11,f4b8354a,2fbf674,39a3661c,5a2312de,853fda14,5b48aefb,23e98e4f,fe3dd3a8,ae1fcd6c,931d9a43,686edddb) -,S(a2f9f976,c50f3687,7ad0ac95,efc3fb2c,46ce903e,76ade308,69705df,72433ad5,ec565311,24c289f3,35e11b22,bf8d7445,f201dd4b,68afa38a,22af056f,c8c285f3) -,S(e20d9765,85f8c567,24d0ec16,5ad27110,26fce166,b52ce11b,cb221a80,4f8b15f7,63b61933,c7f63862,98b48b6b,c6abb54b,21d08220,166ac31b,fc85d4dd,998f33fb) -,S(8868b59d,ca1de2,cbe98d94,506db1df,659ba688,b2bf093e,42dcec03,acecc18f,f02e9b07,96b98fb0,51dbfe8,4524ebf6,dea56251,afb53076,e2215d83,fcf2fd0e) -,S(1099f82f,e32a1361,a785f86b,9a6bf0e8,99c83226,7826d6a4,3f8581b8,89fb677c,13fb83f2,9aa7f271,2cf20cd3,592eac46,cd2d3e61,9afe9aac,7fcf37d8,9c44445b) -,S(4af9c696,77ece7b3,5f732969,8ca61b27,deae65ca,ee2d5d31,ef2051f4,35cbeea3,73004596,429da976,f96e3f80,a24408a4,ebfe5196,8130c698,5b210826,664e5ef0) -,S(9680cbca,5aceb8b0,322d4bbe,8713cab9,300d1f8b,d16ee045,edb3b543,57dab473,2f293940,e36ba1d2,ecd4697c,209b33e0,6904ee3c,2798aaec,e9131d9,bd0df58a) -,S(7eefcc3a,fd6347f0,5f9c3720,31480c92,3eb7fdfa,d6e9c0ee,4e2db9ae,27fae7c2,b8e9fa75,4f745c14,7c753e42,17bb1e28,7bb93d9d,aceb357e,9738f10b,fb5cac06) -,S(b823156,d63612b9,3461fbf3,6894955d,65e7805,b025c2fe,98fd46fb,2f9fddb4,f23c517a,826fe91e,45f453eb,fe9eadd4,d0b537c6,a2a8f60c,dab9dc58,10bd465a) -,S(e801d35e,2035fd54,92178706,e2e765a9,bfb9de22,e89182b4,4d5144d3,85bdadd9,1e648234,27dee6f0,818868e0,419e37a9,1c216200,3faa7478,48161809,76956a26) -,S(e9d4610e,56b70969,284369e5,7e890fc,29fd7750,8489a1c,2f348f52,cdc67f3a,8e5f6aac,357d82e1,a29bfca2,2ee4516b,1df0e622,257c2c1f,7d9a84fe,b48e4a0e) -,S(71c3ef0f,51d6ddee,340d7aa0,94680084,b94bae8a,e3528ff,4a481af6,d3b7609b,4d1674dc,2f8087a3,138adc4d,aa615a43,db6886d4,4992fca4,544f57e3,315f6b96) -,S(9567ce43,b6f5c41f,bdf8b44d,938abac5,21aadb83,c157b947,ce999c0e,4a7d6f20,c9d86317,31ea318,a647ca8,945cc35d,1fd0fdd9,b2de4fe3,5e2a0021,33a35538) -,S(34523d4f,81166739,10b3de85,11a1921,4f8fc753,fd8963e,b9db22b7,8edcc141,900fb9fe,268b88eb,9b80a066,277d8ba,877bca84,f277dce7,7d6e90c4,8422ac90) -,S(69fd1f7e,5f1c43df,a2f4350b,f20e5cf1,f2993dfc,b61cd278,1590ad79,e3c1bd98,633726cf,8b74940a,edb15665,a9277973,2d1c923,2bcdd615,43c9f3a,6c51d7f3) -,S(e4c2c424,c28cb8f7,3146dd39,bb4fc6ba,411b2a75,e317faa2,a9f878af,e94a3de7,fb8d17e8,468e5ef4,8da60739,820515cd,c861378e,9b3bd158,fcc8a949,eb21ae89) -,S(5710459a,ada916d0,9c1feb59,c494863,98e44513,226119ea,5ded7b1e,34e32773,89deedbd,d2d83a58,4e56b409,30a8355e,905bf12a,f33f49f0,7383eca4,e63871bc) -,S(d56faed4,171806e1,5ac17f91,37101b27,59a3a8a9,90b85bc1,89b217a0,6fd48e64,fa871ec3,3408b2d6,b62f513f,5368f549,ebe43977,a48878c7,6d731447,34a6652c) -,S(e7416eeb,da0b805b,68b47be8,eedf87dc,cb5cf012,804d03f7,604525db,aa599bcb,8610c716,f11c567e,313eb4c7,77e4314b,533d4f37,13b11185,bbcf5442,b9a56c19) -,S(8ca59862,ebdd3541,91c60608,13ce32c6,a4fbfca4,6e60175f,2d5f1607,d5fa997d,aaf3480f,b132feac,6adfa195,2b14d0d,113dd6ee,faad71c6,980d5691,e37698f4) -,S(6496dc45,1fd43b45,1915867a,846c5203,6eb8e4c5,28c2a181,72fba6f1,53243413,44fdc41,f85c99e,e00a281b,9292cf1b,153fe2bc,5c8b3e87,cb14d624,e44da1f2) -,S(3a424463,aa82416a,a38bc248,dcaccd20,67d20721,d4e8f5d6,c9cb2fc1,91925a5d,71a56463,fd242591,434775cb,37c81bf0,d4857abf,aa527ca9,c3178464,8afa9fb2) -,S(6a945b05,51d55194,adbf7985,aa85fe63,8811781e,6b787418,1574d109,d178c2e6,186d343a,1ca3a836,32421fc0,d267ca27,80df9af1,32625d31,924e99ff,9b57ac44) -,S(13f1f692,682d04b7,b7e7381b,8c5c13b1,32baac0e,b7f8c8aa,c9ffd77d,3aadd47f,572a05e4,9622ff88,9eb36852,85d1400f,43372533,38c47ce2,282aa4ae,26e99f0e) -,S(79fa13c1,4f0de8f1,ed98e7b3,3edb77f5,a2700707,e54ce522,a516634b,d2804330,a094bd88,e1969ee7,3f41e40e,60f7198,cf2484ab,5a2efaa0,96e891ee,d5987c65) -,S(df1ff6db,d2c61bf7,c273f735,a6dab3d,fb08377d,bb3dd101,9dda03db,e533130a,2fdc7ad,68c58689,92e5c969,d8d14a94,cd0061b7,5ab0e824,fd19611d,923f886e) -,S(a8223280,5f5939ad,180f8776,810cc7,2bff651b,df7972ec,51d86d2a,1acbdb34,9681590f,982e3632,b2aea9b4,40043751,e7f2ef2a,d4b125b5,2784ffb5,17c2dfba) -,S(406b0cc0,49f3bf58,6990ada1,63c73932,b3780fad,ba3fd8c4,79e6a688,484c7c44,aab0e4ef,f2508e54,79074fe0,218aee7e,8b217932,859192d3,1bb20817,df6503dd) -,S(4e7043fd,5783479c,3dcf103d,bc4d9bc8,523c81ea,dbac9460,4b73300c,f516bcc8,196287b7,3ed01bd1,e8033ead,66c92625,77c859b6,73a4c7fa,98f53d69,e82d1133) -,S(a9a2a671,b945a5f5,90575c0e,ff24c070,a7d55b00,e9d2f44e,43cf400f,f3e9997,6cd45e20,cb972715,167f957c,af7f2f3f,9ae22ce4,3b46d4ca,5b2a58db,6e0c6285) -,S(692a1394,75ffae88,fba47ae4,9315a6ef,12b2dec7,6807608b,22ba3ff2,883d3c01,74dd5b4a,3c14a54,c0a86732,1a77d160,c834773f,8063406,85a65c16,6ee46131) -,S(36f915fd,156638bb,88928e75,d00fcd49,63b44ac,f5d016e7,7ddaa8c8,d62cfad8,3f11eb6,16edd183,5ee17d02,722cf6de,991dc8b0,e37fce3c,cf7f5db,e842e8b9) -,S(3f0f6f5a,7e010c0b,5442fd6c,a3643144,a5202a7e,bb3ac8f,99aa38d6,4aa53b31,2574d7cf,5b33e29a,950099ac,db0ffb3f,ab1f9ed7,f13cdf9a,b869fd07,c35c649) -,S(8c58faff,71f661d,b21d4258,a92aacf3,508a9dfa,bfc00cfd,26b95673,34b7b067,38d1e894,ea1d4ee2,843d08a8,80b11325,e9a8a171,59de273f,694a14d6,73944893) -,S(d806731a,205c1a3c,64b91864,2d940b12,dbc6f580,866b7a9c,f287fb7,c5da78de,870a8430,2ff57abb,735da831,863525fb,70402006,d241eba8,d43c2ebe,cdd0e05e) -,S(7dbda37e,195db041,a4dde151,5a7cdd97,416bde09,12b9a741,3354204e,2b848648,83c89c7a,649d0070,fde84ff1,32f60a9f,e1c0261a,87a8ccf3,885fb003,10715e71) -,S(8afc23c0,c803b0e2,df78ee09,3b776cfb,410a1b52,7d4be45e,58d8cee8,3ec54a1,b041eece,4f4ae4a0,b3a52957,386394be,bf7b11a2,b97eb5b4,1bee89c,352ed76b) -,S(4e4424c2,2c50fab0,4b803b4b,2562114b,1b2531cd,e5786112,36fb9021,3652207b,22bf6181,51187118,fb421e4,fb0cf243,889d5ca5,c14b6ab5,7e7b9d0d,d9796e6f) -,S(60717788,5a230af8,a0816e39,6e39b34a,f394b1ee,c93ba382,8fd92941,e6e97453,a84df29f,2b9da41b,14f24762,df6db87,fc0a18fa,89e356f4,9f8f4017,dc4b26) -,S(c9f73d20,384e56ec,37bbbf8d,facf70e4,a271f169,2dc22ac,6022ca24,8caf3213,7622e7f4,c77f9581,b73c9bfa,8bf5b578,89070e8b,97616cb0,69ea25f8,8dfb5437) -,S(19ea5dfb,dab5a1d8,c3c2bfea,48d90f6d,a8b9959c,630bfc4a,81ea5eda,ee45282a,c21295d,14bd81,7c3a4d62,af307b1c,870a959d,7d6e4c65,3b8e1db8,fdf1d56c) -,S(564bdb1e,30b2c292,cdf0e149,1bfaf852,4780669,717de5cb,290cbe6d,c1617b58,9a8da0e8,6fc0b95f,99e84198,877f5ddf,32508c1c,ebb9984,7004f74e,7e2b1c0d) -,S(5bc93842,4f3ee6cc,926e2123,7bee0739,50b39d1d,e0dda3b5,4bf46953,7d0bf06b,d4e9c3a9,662778be,b7f4bd4,cd753a50,32bb003b,694b5e00,c119dea4,20fd5d16) -,S(19432e94,829e8b57,3eef4fc3,181c7d7f,5b2a5f2d,a2e8c3a5,980db9bc,5cb7f99e,f75c999e,5c5b8567,bb69316e,36e01acf,2e860781,5c5703f7,a4be72bb,9abcbcf6) -,S(d399281e,6196ce19,a2ec28bf,a0b1b559,8d0235d1,beef1672,ea230cda,20080b8d,1ca7e95,20ffce3a,33e94931,95eba433,d5483cf0,d5edbea9,6384d1a3,5168aa19) -,S(6c84e35a,b220fa9f,e55f5556,302f6656,39372e97,74ae26ba,e21ca8ea,10e73c88,98a11b2a,bd442c0a,d49711e7,b0e8b234,1d15465,71efe9b8,9a7b4c02,1101b2b3) -,S(7814cd8a,b1b045ed,a1797f14,c83bd807,ec4205b6,e9df4858,1180a80c,a0f8f64b,ef917e40,edc8b8ff,f53e8b70,4de63adf,6bf17730,41af2284,1b0e38d3,b515f33b) -,S(7a01ee83,1c8e22a8,bfdaccfc,cd280532,444e710d,7138b993,fb6e06c7,996235f,fe512d09,19895c2a,b62f2e08,90dc3bc,dcb06198,18160b41,4527e7c,281a5519) -,S(655ee6bc,df86c9ef,918b5660,5d4a5e79,512e856f,3f3e40ce,72e8217c,1f9bd908,cbeba5a6,91fcb085,f3996ea9,d081e69b,7dfdefba,123df5c3,cae94f63,12f87721) -,S(ebd68009,fb0372e8,eb0be25f,e78117bc,3d4d4814,440f1d9e,1cf87ee1,de5219bb,8efb7e38,6f96df55,bf0aed2d,6bdb75f3,6da8cdb6,ff65868b,d8ce79b4,ba58814b) -,S(87340818,9ac05bbb,4e95cf05,17d5abd6,8b7834cf,1168f914,9f1d63b6,19a3865b,9f1fbd27,72ce0f15,c91d4dee,dfae0a3e,7d24c0fa,de2bf30c,df63f93c,14480838) -,S(61b6b213,b02a7bb6,4de62e92,515690cb,5dda3a4d,aa96f68b,a12f2c63,30513df3,cc71b8f2,4eff8194,36ad2962,8c003a1b,c42c6ce6,53997d56,e0162508,c2b6144e) -,S(4ba7ee4d,77171ae2,e39c9e66,3849841a,ed5e02e2,182d872,98f0a064,3925fe37,5cdbd5b4,fe344f16,cb72158e,b80a726f,5a9da4f7,751bc4f1,f1fdc734,8e96dbd6) -,S(d5827a7f,c4d5dcd4,32e5bd7a,46892e9a,6f9a3971,fe9e1de2,ee247e6f,208badb7,f790fadc,9d0e0c0f,61efb534,9b23c60c,2fb667a6,3b52cf18,ca0f0a1a,6098e1fa) -,S(81ec5159,7f950cf7,c0d44d4a,89efe691,e9086dfd,ca25098d,411cb9b2,93237633,885b27dd,c9eff80c,94653f28,ef92fb60,741d3a2,aa828065,5fa60b73,eb9a1e7f) -,S(28fc41f4,a0d4f680,76a3e06d,af0aff1e,6e723779,d8ac9e68,4cdba2fd,6ab6dec7,b1e4af1e,7affabc7,3eab9415,c15b235d,482c6a8d,b1085f54,d80ca2aa,49657225) -,S(d5e753d6,c5bf75c7,cb0f5b85,77fa2f9f,6341a88c,cf59b5d1,328b18a8,f7ae4f47,d1aa54b9,8eb01a32,2518a10c,8ecd66ea,fc2f380d,d97953cf,faf0c540,c4a1bff9) -,S(1682355d,89094297,e6008fac,44c1a5a9,257d413d,7589286d,8bad4873,1476e836,4f69c762,e29f90c9,e8459b11,d53ed84c,2ec9c2d9,ded4ea02,78d04546,eb09cf4a) -,S(9ef7a85f,b64cae73,2eb511a7,8cc46e22,73425d1a,d02272e7,9030240b,23e781db,c720356f,6f6a5a47,3f35e2f2,f5e92e2,78a50c9f,3a77604b,3eb3987,d09ce73c) -,S(4f6aebb3,6f429a52,4cb1be48,ace0eaaa,2174468,c13cf612,dd7ec70a,2e915ec,406ad94d,a8b6d790,2ad3609,252b6d7d,b28f96e,8780f6c6,39620b11,cf8e761f) -,S(4cac3e0e,5ac02e66,66710dae,5c0d7e8b,7a3cc7f1,a42b1f8e,88561bb,223f8232,9396ec8e,aa96f3c8,4ffcb9c,d8c29d27,dca65556,c2fe5931,8ba05a08,cb263142) -,S(86f3463,3aa2ac57,2c4a9dd1,64c7606,f61fbd78,60619937,38ea0a60,f79367b8,c802fd2b,556179db,5f776c9f,db4c38af,cfb2aa61,b5ae712a,3f23e58,25824f05) -,S(5323f145,7685e123,e7a5ab4c,d1d39fa8,bcd6f23,ba3d74da,318dc7ff,347103a9,3092fb79,ecccb29e,12dec977,cbbf38fb,94cab4f1,fee1e8e3,46100378,88691cb1) -,S(d3d70d46,402711c7,e680c45f,3a0e1c5f,f85cf106,983ff0e7,1a7f1178,33ea74fd,91982773,d9b90f31,16893b9e,eea7fb9,e4f722f3,e1577c90,fdf6f625,a8d07bad) -,S(df63b937,28a87613,2db5d71,43654f1d,f8cb89fa,1ab1efdd,6fd864bb,db6d4359,7c3b79ca,191a3ecb,6c793034,832fa5b2,a2c7bed4,84b792a7,91bacb7b,62ce5510) -,S(f1fe9222,8cc334d9,5f303169,a4e2262b,28a99494,c7decec3,9746be85,71b70c74,5588f3b8,4e65fa72,a2b35f60,f99af1e3,b67a2435,8c28eb64,69de5136,e751a10e) -,S(9030e75d,918ca330,edfec14c,b7cb28d0,fb0adbb5,fa29fc7d,cb3c9085,ba74fd95,7df20128,61698984,c0928821,c38aded7,5a452dc1,3bbdc4cd,71ad99da,38b427f7) -,S(1cd3c139,35bedb87,134f628c,576411eb,dfa0b586,2c3cc7d5,ddd7cf5c,77ad641a,2154edf2,5488bb08,be93a25e,c847b26,88264cf1,30fabcf,5924bde1,4b9a324d) -,S(e56e0737,a19fec7c,78b9f462,1ec0d5bb,bd6e91ff,ac995f42,202f127d,2446ad96,8830d827,368c760e,40a8d9bb,b693e975,1e69b42f,4b2ed776,98f889aa,3ead70d7) -,S(1b0a6ac4,58abe5e3,63e6dfeb,24ad8a65,56fd0886,78086657,587e63f1,5fb6b101,d2df6fda,e64263a2,b133e5aa,bdddee5e,9a35e86b,2e1f5926,5212cc49,335178dc) -,S(10a14146,8fd4618e,4ed390a6,246d62a2,50bb1676,45cfc679,d80cc081,23ea22b2,3383b868,dd7fdd1a,ecd13dba,f4ebb151,f9a09b25,bc30d562,b033800,fd40185f) -,S(9dc4ab51,5378a351,6db8837e,568afa72,e357f7d7,95d546ac,8a73e419,a43f5e35,8ddaa2d,9bcecfbf,e2a422be,1ea591ee,bfe05ce1,90439a06,cc68d66a,6305903f) -,S(aa93175d,e7a4e1fb,c538eb19,e89b20ae,13539e99,362035de,1aaac76e,3ced7196,edcedb04,c1344568,9f3e133a,d8b48004,c18d146b,ece3da05,effb864a,c2afb9ad) -,S(8171f3e4,da02d9a0,8bb6fcbc,6d06cc6a,94f3cefa,35d4ce27,536ef6fb,222edf7b,e91be5fc,aae62aba,1c02b55f,73c1a64f,c32038b7,a658f189,7499ca59,e9e6dd6b) -,S(51f6c983,c89128e6,635888c9,3c79cf79,893fe627,437464b1,11b08058,1aa19ab6,5d2ef149,4bb164f5,20c1dbf4,1a8dc650,b8cee400,d5e37252,a3d0f059,3881a067) -,S(c0a1f184,766b30dc,6a5016b1,9db0dda7,ec34dfac,74dae580,9500ab8f,6fd7d38a,bdcad3e2,c7b6daf1,29d41051,624d26a9,b27f361e,c695d490,52893597,eac6f01e) -,S(b1bb1ecc,95435169,4ab6fe0,7341efba,fde9279b,1eb78a22,2bd39472,33a0eb02,df523f5b,525342e2,c0cdbf0a,671e0c95,4b149084,de4c61d5,5a7bfab4,c81689a8) -,S(b5cc30dc,86d04ed5,88539ea7,e437391e,3b0891e7,6818c470,1803de7d,640b5dce,f1cc0d9e,45c7312d,fb1acc8,62e03f28,9f55561d,fffe4b65,ca41e62f,42d4ec14) -,S(de2b49e7,5f0ff53,28155b3e,a7d5941c,8cacee23,51fe16b0,da8e940f,9263ccb6,34d7a42b,b12dbf67,b0d7c680,178154ae,4690d5b5,703572ab,74b4d93f,6d8de99f) -,S(8b18f4e7,c129e117,e898404,65870cfc,ea5c0db0,ef2ef11a,d515f3ce,57cc8f51,6b1e1086,c8674a59,3c5e9d6c,dc8edcb3,72281c27,e6b2caff,8842e008,99111f37) -,S(727162c0,27cec888,918e46f1,762a830d,822ce424,b6a5f442,f9e582a9,17c86889,de348296,1452a369,e6fde5af,693e5247,24865623,cc516e7e,8416f38a,2f223cca) -,S(4ae4fc1f,4dd17483,f18eb9b8,1c2494be,946a75fc,a3f61605,6d0856b7,3505058c,d87e7812,e901fc17,da034a05,bd878470,59999b36,e2c617a3,9ae46921,f2563e7) -,S(e90bc9ac,e9e873fe,91826f01,66affd02,72007bba,4ef690bf,58b15206,5ff43cd1,4bc820e8,9acdfd68,51c9b0c0,65b9bfd,47f0762c,d2e56d58,905e6360,4564fa87) -,S(ba0ae6a1,db432fb6,f7a1af7d,be9ef746,8340ba5,7f051020,9af4076d,f51450ba,7d3839b7,4099420,1729894c,51a2c30b,51019a18,c32ea908,c58876af,912be720) -,S(70661b81,f77c6531,1d98b403,ed7b97d7,4f9682bf,2981fa5d,ef882022,d3accfeb,9022b973,18959f4d,9ae4bd7c,fb06fe66,7b4eeb92,5f46677e,4e5bc4e4,a6d06387) -,S(fe1b7b47,28153a07,11f81b81,7d9efa38,29451c15,8d1f11d8,e5e0922,fc471a47,95a075cc,68cfb7c6,fb115dc0,5e4c31aa,85725bdf,2344dfae,19c8a034,d2b0f847) -,S(8acf3bd2,bbaea907,28013d04,f27e3a5c,4325bc37,ec5c5e86,7ab70f7e,9acc3fc0,f679e3fb,36da27d4,f29c06a2,5951f80d,b3e2e0ef,dbe2c785,ee148657,3e16174e) -,S(1d855d37,25fc7d5a,b87fc6a4,7f62ba7c,d2db01d1,ca0f14f,1d6ea8d8,4af395e3,ceb263ac,2d41654e,d4655183,f6268c5d,9b0a9ad0,da8912a5,815dc8d3,20b1b90) -,S(1abb4566,30c24ce3,c84ec6f6,d70d19b7,9934498,451f02e,3926d70,592a8cba,4627706f,6be87fd7,2ad886ef,73245452,1778d293,41229863,f4b19548,74525885) -,S(1b4790fa,672c12ff,965d07e2,44a3f30b,620e5c66,4b098a5f,b86f2bea,93eac036,eed050fc,a758e2d1,f2a2a9a0,6b8391fd,7c19fd70,9c9e1283,1b018d24,e7edd60e) -,S(61878b2c,fc9cc88e,30ddcfc1,2561367b,44c106a0,21e3dc98,a433732a,68de3dd3,fa2454a0,37c279d,1b54cb77,498a9efb,afc6f50b,6b13e29d,436000df,1eaed78e) -,S(84048df0,2767feb1,7bcc21ec,f4502238,abc7271a,931730b5,3354010a,8544308a,d4712e4a,39d608e5,d47f9814,f7763c6e,605accaa,438ccb7c,838c88ec,e993c32f) -,S(eb7ac4e5,6c96175e,c3f1e1e0,37e89f95,8ba37d0c,a88055cf,889bac33,ca683a94,4941e267,2ccc274b,6d8bfe07,513dfc6f,cc07de33,2f517011,2bc3814f,5e85da8a) -,S(48a36ac9,877d4bda,b62b452b,a0288dc1,4cbce455,3809feaf,1a4195af,22142e91,e24d6d8a,1256288,6c6d8848,4e950d8,27eec39c,21ff6e25,30b50eba,ab69659c) -,S(9c3125d0,5a62a25d,7869af3b,1b23a00e,e817b664,c82d2a91,2522ce16,bccca1b5,c6ecda10,f6707168,18417277,4e18f5f5,38566361,5506b450,a189b6bd,39e5afe3) -,S(33e81e21,dcc7670d,c7f3843e,4dc8be3,10160bed,49af116b,c2ca91e6,90f80d68,e694c1d3,a0a386d2,e6df1167,8efe38ae,9ce417e8,9ec05bb8,fa592906,55757b6f) -,S(9543769e,6899e0fc,bfeb1071,50959827,5c1d0d4b,8a68f056,d8e1c033,1b6a1ad2,700cffd,afc58410,7635f148,72ed1ceb,1c4be86,7f668b16,3f579534,ec9b0d7e) -,S(4f41ccd1,73e62c39,7d481e6e,5b50807e,6ca9b163,e21dc203,a0d50826,7439efdd,fbf98ed6,aa8c1972,d88b309b,ab74b254,8fea56bf,e158d1ee,d95ce77d,c69f79d) -,S(4cfb6a45,584b00df,be3fd9c3,38eebc28,a667fe6a,4651bbd9,64ecf20,645f12e5,2ddfd6da,fe080e87,470fac21,d1255900,219638a2,5e72b12f,5501921a,f614652b) -,S(9efb8bec,d9bba33c,a5e217fd,8fae533b,8e536bc9,1817f982,1f217757,75eca626,661300ed,529c15e,918bcf9c,1a7dc3e1,8e3573b8,875e2f8e,9440f8ca,b0658fb4) -,S(c2a80952,5be7e4c0,b85ab953,ebe6dc5c,f5d3c0f9,e850e470,da9e61da,e430e441,1d2ded36,bf72697c,7da6fa22,1c09fbc3,6be06363,d50d277b,4839c4ef,809d9d2d) -,S(42b7ff6b,49ae822b,f5a16276,4c620b13,2501a1b4,1bf830c,a242e02,3bbaa707,e41fe058,83f0e400,712de994,dcbb5a38,fb2c7595,c5ea8b0,eb90a236,82b71d6d) -,S(ee0bb129,d420b641,2afe1518,55f78f39,e00cc3b4,7ee3b86d,f781f0e2,abb0c28c,f71d0e7a,5a4fa247,67c6204b,60edbadd,54b17455,54ae9099,258343eb,5c0aec61) -,S(1f1d8a07,9cdb3bf5,2671a716,26c503c,77546ce4,2a252e78,9ca487c0,78ef5b9a,c611130d,ae55512d,ea8e8e6f,9fbc3064,180ee4aa,63d1dcfc,5c39e98d,97571c20) -,S(5bda9c06,ecdc9fb1,5926ebe5,5418f016,7cf3136e,5f9317b8,b2912fec,d2a31310,358ffb70,dce1260c,80fe59d5,b72eadb3,89076168,a17b63fe,b728dc28,45ecad7) -,S(c32f6503,fa50c727,66652dec,8e0efd71,edc78973,48061be9,1f847544,df866ea6,67234a26,7a13ecc4,7b09443,cb13f0b0,6a34af2a,20b80856,6deb9c71,1fca304) -,S(5483d511,b71feb06,70e6c83f,29612640,849bb673,896bb069,941cdea8,9489caed,a09a6a62,d3233437,40adf0f3,8d8e4ddf,494d5350,7944becf,bfed3927,d88c1148) -,S(3d2d8f5f,f0b86ab9,1ecb9342,5a6cc246,d5e3c6fd,9c43d047,2d518958,ea322ef,4188348b,4c23ce05,1879cf4a,b71d7608,fb45d7ec,a184c509,c739f364,d955b830) -,S(3a5c3939,29ed6780,5fdffa9d,f936bc10,735ddf03,aab89e9e,40b47574,21af1dc0,760b1919,76752916,2ac2a7de,22975c83,44dcd52b,a945c81e,dd8224e,90a7011d) -,S(a3d522ac,7c1cc06e,3ef9272e,fe24a0c4,64886948,3373df90,e5dd484,d4590a83,6f53ba2c,b739dd61,219684a9,50001697,28c377c6,93054795,5661f2c4,ee1b6be2) -,S(ef0b0931,13992018,44078583,62e02aa2,c1437d87,ddb95d42,36751445,d8e8180f,73bf4407,8d184772,7d0408cd,f92f8c74,2173520a,41971980,1b9c842b,9486c634) -,S(8140effd,1498ceb9,c2211899,161185a6,a770c15c,d1ca3e07,f26f40c,6d15da20,4c74f3df,6d2db7f1,be68b7eb,2162f03b,51c1102,a02dc3e,45fc49fd,22a474) -,S(3445d720,8e089f1f,93d32f4d,3fd6fd65,7603c7f0,378b74,215a59bc,ebe122f0,6d41035d,fdb54ef3,3a3c8626,f036e1a2,38da0637,e82953d4,b63e23a4,890b6d5b) -,S(e14b2a5a,6235369a,1d1933f9,7124cde1,789a366d,5fe6ab9c,72c23d43,f7a58cd7,216f06c5,2f63c102,6cafe6ce,58a9e589,d67a9f19,625513be,44744d0b,f9fc8f8f) -,S(6d9640bc,8389bc44,fcd0b2b3,3c088170,eec93106,67348dea,f8f3e92e,2d891e0b,4b4c1485,6e42db64,9fe04759,a42887fc,68b5d4b0,8161b31a,1852bc41,7d04227d) -,S(272f1404,5c461f21,3f67cc60,d7c03b1a,fd028a05,b9e06324,62a0afce,fd9b2916,98635ec0,c0b23538,a63f78d,800eb0df,fd6b7583,31544b1e,825cd433,ab348416) -,S(a8c99928,eaae745a,631250be,cde1ce3a,4152334e,de916257,681329ee,1f3a07e3,4ccc2686,abdf3f7e,8e1149aa,5162fed1,24ae51b7,e61e4620,9f5cd611,e7351621) -,S(fb024b33,7f93d565,899be686,9b1e4c81,1c660d50,fd31cef,fac38600,d8975409,339686b7,8bff3c95,7e8730c3,9457966f,ee562ca2,89d95e12,7b072f47,c4c7fdb0) -,S(e0e48547,aa613549,773ecfe3,691b84d8,a6cb14f9,ce4494f2,35187057,28562f9c,60b6dd8b,56407580,52748838,9396004b,778609f8,69f47676,a6d76eef,dca7b307) -,S(bd6c402d,378b8b53,9f74d29,605e1b0b,ed9e383d,dfec2169,8076ef59,125d16e4,cc3aac9c,bb761c7b,3776a8f8,c8c6d2c2,a276924b,79510f10,75521b22,9def2c24) -,S(e6919231,eefa4f44,144e2c55,4f695235,d5886cbd,e150aef5,52c217ac,5e451c0,e74ee1d4,d34d2612,b4d56133,c2a11cfd,73a888fc,6927f46b,c2aba9ac,63b1cfa7) -,S(1a9acc6a,2a487874,4d92ac5a,328bdb3a,37c481e,8c145463,f9cba4a1,a03d03a9,ba6069a,960e3628,fae22422,47fe1f5e,df71fc81,b49b5ca1,26a7c588,fdf0fb10) -,S(5b52bba9,2e5fe301,f2c4e939,52db99b8,abfde642,3d6da8d5,36ccef4c,f6070910,108ddbdd,901e227d,118c68f0,a71aed0a,cc1ab1b0,2fe74341,f546ede5,b747ae29) -,S(92c13760,1ebe82a9,b11a096a,73be2828,652b0a4,d7f9a286,f1338a6,b1e05242,2e3e93fc,2dc6d0fa,5d43dd57,85f6c79a,51a588bd,d14e0275,59fac06c,a449d7c) -,S(3cb6f8da,79964c17,73a1c749,e89542bd,94b4f279,f6061d69,a12ffe5f,1d4318b8,42e4c1a8,b4f45ad8,dc23bd02,faee2956,72a77771,6e6b1d54,d05ba413,6bb11956) -,S(5fed6351,d34518dd,111a5110,50de0e5,3c60a14d,9a80183f,66415145,bdbf5db,6b79a590,de07a4d0,b74140b6,49bd8375,da77e01e,295e76cd,56a6588,7746c3f6) -,S(2b88f0a7,81c384f2,b7c245d3,7c061128,a14132b1,fd0fb56e,7d3193e3,d95d3840,f787e7a2,11446e57,655b6453,c2244974,c1632bb9,4838a981,bd4873f8,89a0e10e) -,S(c7b247b1,5a3f55fb,35b0ac3e,1da36719,18507f94,e988efd2,47bb02d,83293443,4ab40437,34c65f11,236b6ac8,bc27c548,c3c8e5f6,64f3cb67,99e7b8d0,6db85f4f) -,S(ddfda933,8dcb9481,5c08a20,12c137e0,45df69d2,121d4534,4c6aa375,e03647dd,e95f79fd,2a116bd,5972e93a,c58712d0,95f91255,a46fa091,bbcbfe5b,57795c1b) -,S(dc8da645,5084b105,6c7e3233,b247e87e,9d15a6b6,677f8c29,da04fefa,371da7db,c2a345a3,fde3ec03,f6a07fea,8bd7685,8fc66d28,6637cc80,93132048,441449c3) -,S(f53f3b26,c5fcbfa8,f1263bc7,a6439056,a31547cd,3a8c795b,8e355482,d1ff5333,113ed45,e664b9ca,98d88f1d,a17c4fb3,5249e8ec,7998b1d1,bb68be3a,e6716ac1) -,S(648d23fd,c6d4b5e,4ee1d647,7d969df6,7d754686,9313ba39,1d89dc90,b646cae9,d035e045,239375d3,4e6ffbd4,bae0697c,9b336454,3261206,15edbe28,3e18962) -,S(92e6dd0e,5dbe580f,82473f3e,dd70b343,bd51bde2,b1ca91cb,1c483fe1,3c2839b1,cd90dffe,a5447bd2,592d1a46,5a09b391,a61ab01e,a10c9201,5ddf4614,b39577a5) -,S(1315e58a,7616ef8c,fa223ec5,49415a54,eaec0583,6be6fb78,2ef4ee60,f49f687b,729e0100,802d60cb,c54e1fa4,5dac72aa,2fe189a1,737da80f,1ac58426,d7e1431c) -,S(3c8a9799,9857fd85,e26b284,a3554e51,86b001d5,e6d075e6,c9402148,ab3e2a3b,464f0492,acc720a5,59487b3d,60502067,a722e915,a10412f6,d6c69dbd,28b25977) -,S(ea417230,cc94c5f4,436b37ca,e6f9ace1,bf3c7f8,ff03c879,f862ea76,127591c8,961238cb,8d95d50b,baccff1e,b9cd4040,6f4ec475,7026b3ac,e916067d,85a4faa6) -,S(8eccf9c2,f271079e,329a8c81,62c98af7,48496ca0,b0c5840b,ceb19a15,361a6ceb,3e259a19,165bf1aa,630c6a7c,52f37b29,c8ac5239,a132fa5b,b53d687,b17e56af) -,S(32f0fc83,b3503a59,6873c34a,b54eb6aa,7bf3d913,842cd556,77f398b5,4f0f296d,d4736d6d,906f78b7,62eda345,9cb5f7b0,311e50ad,cc9a1e26,655d8ca2,fb81a811) -,S(b7d63110,77c83a8f,a43c171d,a5ff7cbf,e4fa4cc0,b2614a9f,63831836,e0d7accb,6095f640,56441552,a8ac27ef,9c1eba64,8b84a5b4,c19237e3,5e285ebd,796be9de) -,S(ef6c904a,22df4fb0,a54cd74e,6563e56d,588b4f8,d6926cf0,6c32694b,be536954,308910b1,44cd37a4,e5bc3d3c,43715e22,aa7a0492,e0e9cc9f,b1095a22,65dbaa4) -,S(19e13bd1,e62825bc,acceebf0,b48e17fa,b375241e,6eaaae27,672d7ab,22941a6a,6f22c329,7005bc1,155308bb,dbf8ccc2,855ea666,e4af3bba,d3e3c90c,28b613f7) -,S(57d9bcdf,10f2f790,79349ae4,5f2980b0,9a98a7ab,d792a5df,967b7b11,1c8e9420,bf665de1,d9b7854d,e34f8fcb,1cc027b1,42ebfdf5,bfe4e65e,b5068a72,9a65db68) -,S(37bc6685,7c3d5e8b,878874e,3d1ed324,bb530a21,f13d057e,4e3f87ae,3df06b2,15419bdc,764db12e,f12abbea,c1ca7bbf,77764abd,72f5eec8,3a81c452,4c998539) -,S(1b30c5d9,9ca59151,33c012a5,96512c2c,b572e11c,a7412138,7f3658a9,f9c2cec2,dc42320b,2a0dcd0c,5404d842,17af8c9c,2344f751,16a5d691,1db0590,5ef39697) -,S(96831db3,50c55ac,dd329f4f,85ad4a5d,e6e89f21,85b93e65,b8db4e1f,c1efd0bf,86f43820,fd03739a,d0e75ef6,17072f2c,82bd8bd5,a1f8cef4,55e49ed9,cfd47837) -,S(cd2f500f,aa1f04a5,58309f28,f7acd542,bce7999e,a17cb792,66b93cd5,44e3d8ad,1f977080,ddfceaee,97c743c2,4815f795,27dd1b05,63ef009e,92994046,c8dd8c29) -,S(60392a7d,237c9e27,a3318ff9,d3552928,802f519e,60a783e8,ff32be17,4ad01c08,eb7f3147,df91d1f8,d8994afb,df297c44,88ae9e1c,539fe065,663d856f,22893fdc) -,S(f6cf77ad,df6ab73,20d68fb,9f3c1d7f,d8abb679,179b3c90,d22574f9,fa37ee9a,8ffa29c3,3587f716,6b5d513b,7df76311,77e81eba,1cf9b523,280c778e,2442ebd1) -,S(57c8015a,f542c514,595b6f4f,f11be2fc,944a0ea2,d26a4abd,1807142,da7cdf7a,b67c779e,80153cc6,7b6b32d3,3a3754dc,ffb692bf,d16e3e3d,2c9c673e,a8b05da9) -,S(7fe08558,ac184922,ffbd5c51,cae99931,2f58a17f,bb643b4b,fa1e419e,6b4fe462,7600477d,8bbf58b5,36e7e9e4,cd595858,7268cb5d,1599079e,5a88fbe7,79ec7a11) -,S(2e16f56e,73b39bef,d729b87a,d8e7c4e,3d81095f,58be177d,87bd9f3e,dd517b75,4ce271ef,57323a0d,baac950e,668f0981,77aa59f0,7a0211aa,69b4e417,375fcb7a) -,S(a4d4700d,456d7802,be781f66,6ca24a68,49200de6,d2dd97ad,9c2eba62,18ffdedb,c099f86d,e7ba0f0,e8f0e762,8864a4d8,9124aae5,af12f6d5,efed434f,c66e4532) -,S(b4764d50,50119e3e,a316c921,91e57ae5,a2327e74,187f145d,c048c199,db3fc059,e39be8fa,cc272129,3ec831ea,9016a188,4f127070,4fa4f092,c2f3d56a,4798653c) -,S(3e686ba7,d291abf0,ced5b352,e84fc696,c29fe123,aeb82235,5031931b,e7e2d0e,7b35c0ab,7cc3c81,f84caf9a,9321b9b8,5a889b07,98c9eed8,8c7dc4c1,a985d266) -,S(d7886f2d,1d4c70ef,c5961e56,33122317,58400105,288d3346,db49407c,d24a46c5,da645ee6,17c46024,b2e25903,d4d7dbab,c5ef503f,814f23e8,68d94040,54b9efc8) -,S(7cbd23cc,14654d40,5aa57ba7,1e375466,cea867f2,325db475,d3a7990f,ba17a40,eddce5af,96e66db4,b985541e,e638ecea,88d327f,edd37039,54ce5a1d,d2dcbc51) -,S(54626185,c279e1da,eecea0a9,233c2190,18f877bb,58614a5c,5d2b9894,17eb9795,6507ed85,dc8f8454,bf96730,5cfc7919,8cfb07f0,dc64b09d,928d0b86,e0e9b6f8) -,S(edcef155,1cbec2ce,2bedb20a,addabefa,59e68cf9,e2200681,89285c08,563c32e,ade67143,75592853,c296ab45,bcba4db4,bed59efd,9df68b33,b03d7a3d,be753179) -,S(e027a953,ff6ef9d3,f27db47f,bc91db7f,6a30bc5c,c834add9,9cf8d086,23380cd,1e6b244d,e18ad020,8e52d174,ac452a81,62eafc80,975872e4,c7e362da,cba2bbf5) -,S(a5006d68,db980242,54ea251f,3787d527,66dbf92c,aaa20960,e17ac6f6,72e2b2d6,a1938d7e,e854dd5b,94d98766,c0f74723,72d1e6df,5cd6dbab,fa63faa5,6a0b2b9c) -,S(327075f2,1a1fd9e,da69adf7,32995919,dbb02025,ee504e0,3d5e5066,8427be11,41a57eb1,c32e94be,948ee335,6d855fa2,611a4ec2,4519adf3,2deab381,6bc4debb) -,S(97e1a5c6,66694bca,6b10cdcd,7e95f74b,9c87ac04,c623799a,c1c7959f,1a3363bd,3cc9a48d,1ec7561f,7b72bb6c,4d671c25,56689498,42546a9,48c9b927,c8ab5e88) -,S(450fa640,a7374dcf,d11bce28,f4eeb4ab,d0a2d868,9f6fda04,7f790ed3,b0c07a21,eae88298,dc17cfa1,d482a1f1,70d1dd36,aa35a56c,7eba231f,c4c3ca16,efa77f4c) -,S(f5aa7340,fc0a66a1,2da09ce1,f4094240,d81fad91,87e944a8,a7a1ef4b,9e0a6559,1255b3da,9ef992f1,c62e7738,f84dba74,899d9810,9db522e3,49ad9fc7,2aeb5017) -,S(6900965,55197836,a7b23841,97fbd75a,8857ac8a,8b14ec8c,90cc94a7,8a42f1b4,1dc181d2,38c976d,b4627107,2be05f32,952b5bb4,e9ef4710,f1bad8c,171b027b) -,S(2b1aa05a,8ed84136,7e99f377,bc3760c3,bc3bc0f9,33555e87,8ff2d212,c3f290aa,47b25af4,1eb8bc31,915f5896,57f368bc,35e9000a,cbdd0a41,7b267e58,cc13e280) -,S(a4e6b69c,a18caff0,d993540d,3005e5db,454b1e39,d4c81a7a,b5315d25,d052d81d,7cff2103,9c587904,a42d78ed,c2e7a6ec,df4fcb21,17c89822,36fadc01,a15d70c5) -,S(ab44bb96,c74fca4b,3e39cb0f,d9dd7795,f728e1b2,80a7cfa1,7a36916f,b39d2582,59d91ba4,519fd8cc,9e773feb,b1915967,7edc0dd8,1e794ab7,cb76a2c9,9026f5c1) -,S(83b0c85b,3fb9c3e4,8c96a31a,e5442288,93472975,5d42fcc7,715dbc23,9de332a2,e99f5640,fb620582,fd833b34,2f086800,9652d739,2d6494b1,e36d301f,35a6da6e) -,S(ea45313e,624ecf81,676911ee,500bc0f,e5bd10f4,40e04788,41eb215a,ef954537,4ab8b00c,e2359cce,203bde53,b9e8a454,d5afb101,4d0b644e,81ad1313,6c0c7445) -,S(936c10e4,af823d96,9f7f7a26,98c927cb,ae6d609e,37cf7412,ac4cea1f,51a3cd4e,46f72bbb,10dd850b,8e3e5bdc,f0359f6c,bdb9067b,13d2b60,bf68e8df,b17b7213) -,S(436a5d5b,61aac3db,392cf8e1,36a89b31,847bb116,5d1e296b,36c90d60,f2e9bfd6,f81e688d,ae67cacc,1978559c,84a90f9e,5e342bda,e73647e,33655686,2f36d68d) -,S(9eb95427,3fe789a1,3a24b929,e54f6262,d931a442,2e61867a,abd84d80,4b315d7,38bfc192,7dc0e640,820fba,8effa82a,d29f204a,fec11c60,768f95a3,4d2ef59c) -,S(3826b6f5,87ecbc0a,cb6b4328,a00f63e6,ecb77a0d,bda277a,e6e4ba5,fa280d8a,d9435fe,dcefe69b,213e6eb9,eda63f89,db35e293,8ba3d6e6,57232f04,3a4ef271) -,S(a348cd11,ae0ea1be,3f993bcf,84364b9f,4dbdceb8,db3cca21,cd0f8ca2,4a1dde2,1fc851d3,db7cfaf2,6a1c202f,212b68a0,7078ebd,6d6441e9,1d1d4884,1c83ac75) -,S(bfe15639,237fdf3c,4e67646d,724264e,5d70d1e7,3cb70205,3c4e9a06,2bdf7329,902b37e6,1ec5e59d,9c3c09d1,d7767483,345488dc,e492e3ad,f12d04f9,2b5f88e4) -,S(e2fdb14d,81a1b6f4,d40dc346,c8205821,2642ae10,2707e944,14413cc9,c03dfa5e,3011b4ed,846e8551,6c66925a,e7676062,131e37b2,9b00c408,6c60a3e2,3488fceb) -,S(bbc659c6,8f476748,17663659,db4ac222,cf1119ea,ac27c38a,535ddec6,913c7416,1f8b6ee1,9fdb512a,fadd13a4,d3fe13b,48250120,975b8c7a,47798267,7954b954) -,S(65bd2a02,9866789b,dbd6f743,af85a789,ce9141b6,fd9ee056,cef4de8d,a2505521,32dbe030,1cedb7bc,5d5644a4,6c3e6c56,990b184d,710a770c,6b65f39d,3378f5a5) -,S(1ec0e6eb,8382cf7c,24d75a49,fc0f3724,e9318d90,9e05d406,a3a5916b,2278e981,e50e129c,f486bcaf,eac8ade3,c697debe,fa56ac06,337cd9fc,240cfc2b,3415715a) -,S(7390af1c,203da259,9e1aceb1,ea101628,c0399c92,33658d9e,10dcb10f,63a9eb8c,7d215496,60647b09,d7bcad45,1debe7d8,2c3adaa3,39bce418,320e0df0,977c3126) -,S(99a51469,7b913764,783ff7f3,7099cc45,127baf1e,d8931eb2,b4b71e81,6a1a533b,49c0d00f,7503770b,fcbd57d,bae748fc,809d21f0,8ea38d4c,8a288063,a7e2e8e4) -,S(e4d6e0b1,3b4804cc,cfb7dbf,ef1b7026,320ba2e0,c4fc98cb,f12fad65,8a0394d9,aeb0eaac,73a006fe,6a75ad20,3e0ce2fb,af5fc3dd,81865b6c,75075d36,3b761a41) -,S(488a4141,507ce5ea,cb3e1c46,ad23fb3,1a9aa058,2b553459,d885116e,19fe1a04,6bd6a066,43ef8c7,4cdeaf25,ead63b04,e82f8073,a5fd904f,d7235f4,cf12bd12) -,S(c0ffe24d,ed0ca54d,1ad1c2ff,d2dfbac3,2cb65b47,ca42e8c5,5d2c15d9,67babaa1,d15cc63e,29c54df2,19dbbba8,8df7011f,a0a330e1,6756567d,bbd7c6bd,7e7e9289) -,S(336d9b02,6c74e25,9dedd36d,d8fc5ef1,31b05d0f,f20bffb2,8305b923,767780b1,4aedacfc,9886a707,aebe6510,e1bdb89f,2b1b6461,1471fd1,b055e7f5,414e647b) -,S(98353eb9,8973a7be,3bbd3711,dc7b86e5,9a2a175a,ce8464a7,6aece2d,2dcf04f,a877fac2,27894a43,8f610887,305e1c12,8e45b4a4,3d6c596d,9807461f,aaee767e) -,S(cdc35e1c,17fff9df,63639cec,b54fcb0a,71c9fb77,c38eb905,3f37c361,36da1e61,a8ccb6ba,fe917260,df64f0cc,dc14a31c,87ae559d,7d629778,2bb9b668,9494eace) -,S(912cb1c1,5e62a0b2,71458409,39c06f15,5d7407ec,526ccb5b,5159a934,80111941,584c14d5,1723c447,cd0cecc8,6c70dda6,6fa710b9,8348f5ad,bf4bd587,37049bf6) -,S(2145e17c,7c1e8acd,99eec6e2,cff40341,ffd19568,9800d02b,5ddce693,c3bff3bc,3b8a71a2,40c0b373,95b0e9b8,99da7bac,a5c43088,afafeb68,957bff4f,7636356f) -,S(e4a09336,7e877272,2224f7e1,d03cdc85,43e0910a,20bfc4ab,3aa2ea94,8d0b1692,24b1ec31,33146f03,8eeb8315,afa6e34e,898f48dc,af7d0f80,328155f7,c2cf846e) -,S(fdf526dd,464d459b,b7f387ed,46402875,2b1390d8,4006ebb0,f579b36c,d328db40,4396e6c5,679216d1,dd2cf776,61264ec5,9373269a,a745c963,14147c0d,e53a3987) -,S(6c85c16,b3e37273,509933eb,caddf3f6,52ca4c49,4e751da4,fab5bfb4,ec729f86,9b530fc8,520b807e,5e649040,c5de9929,e592ce99,1b9f9cf1,21766f16,eb648d6f) -,S(4fbfae3c,596ee2c0,10c98ce4,bde00cfb,4e7da2,25583203,feb0c791,2ce28e58,fecf0504,ed0e364b,95edcfdc,ff50fd62,396b8a65,83bc1799,3e73557e,da6ff099) -,S(9bcc3b7b,80171179,3b683c2b,90e9c811,97c1d7bb,d3c281fa,1503513e,778bab8,da2eac92,878289d1,a77825ab,9859baa3,a887f009,d7d8be9f,3b70b917,41bc0b43) -,S(4415a040,e70a3b3,f5a95695,672d1314,855b0a26,3b5e3c8a,24e02f9,6b635150,d8a53b8f,cf55a9f8,81e92160,39afd5c5,6843ac56,39f3223e,c58a5869,da3986be) -,S(55e759c9,cdafbcf6,a38988fc,be203839,b617b536,2d537092,4d2084b7,45b2341,4a6933ea,ca8a3405,89952483,4a231585,3c1191b7,42eb95d6,cf7f82af,f931bb95) -,S(21021f25,bee23c2f,a57e072,bdc83e09,8d115358,adbde4b9,5ed63488,5540e9c8,9aef5691,a7700eff,7c42c98f,8dc822a3,4ed8dc1c,7f8648d4,ba5bfe3c,f9a8c9f0) -,S(2b4e311d,dded1aff,edff3c64,10d40b8a,c70771ef,6904e4a7,a28c7982,cdb376d1,145c30f5,6b255b07,fe43d02,b57f5b96,48b25dd3,6c792575,d20ac730,d709b05c) -,S(5190b21c,7e166100,c90dbf5b,e05d25b6,5ed91caf,904b091e,8b98b5f4,5d5378b3,b83cce47,1fbdc5f8,b50e3f26,8be0d540,1826d26c,216c1166,4040b4a,66650073) -,S(2b211ee4,54c65c0b,3647c7b2,87608189,88b1b009,77d016ae,1f2f4030,545b56f7,75743959,17d8fc1d,571a2563,47a61288,fff74669,b863f506,f9b70ddd,76854f5c) -,S(cb30b792,b41e0aee,3478ec37,ff6ba66f,a3caad4f,9418e1b6,d4af94ae,e64134d4,45571ade,cb3a9f4b,922b8b4e,c0d1c728,9142300d,daeb08e7,71b1aab6,228358c5) -,S(f4e437a8,d2fcaa16,e9749d07,89be67b,e4687952,7eea12e0,65c3cd32,4e4bc6c,fb52d28b,7e81ae8a,30de51f8,bdd0ee28,8e7647fc,392249c4,3449e62a,77ba97c4) -,S(a0a676a7,6a2a19b3,bc6a726c,193d9df8,ce85a94b,cb678080,545c53cd,df50d518,647fe8c6,b1b7bd21,b9816e5,aae40700,41198d68,a3c9bfe8,e437fc88,8f190a71) -,S(15dd4fea,d7f39428,b10544ab,1eaeeee6,75a2ba5d,15d8971c,7860a5bb,b7ff7b7e,89955ddd,5fab2154,7d231342,7b7322d2,53924d1f,1b1fa961,8442c471,9c38445c) -,S(a806b800,40294b47,6377a188,ed74dd9f,1bdea3f,f72cd2b8,850f6321,930ca522,4b6d7365,47d8b1af,697f1fa8,8ab3bb86,53e49aac,618910db,9c6bedc8,deb97213) -,S(41e3723d,ca086487,7a36ff9f,6e431ee8,58a983ac,f3c0406d,f31ba3f5,5b9f148b,8ab166ca,f27c58d0,1a80b136,dcda9fd2,2753c52c,dffca007,9139481d,3b8392e4) -,S(63b8a0f2,78558c89,d9ba3e58,70946615,690e0447,f8d4c953,ea00bca8,65bba3c4,321fad41,85eb8b49,53a95da0,f004c80,8c09b297,728b3a0c,2d300b32,43cf787f) -,S(62beb7f,aa8b0d3a,505cae5f,82229a61,c1ca21da,d2ff856c,8942a9a9,b14c5963,e3d9ccbd,7120c27f,5cd88655,3efdc43,a36f4c02,2f5b7045,1ac9d7bf,56bffd4b) -,S(b75a180a,f524b89e,be5d79a9,92f0313,bc133fcf,3cb2d99a,c65f2c48,1bd20427,e7855056,b11cc054,d37094b4,1e62dfb3,6a636964,633eed48,c39b8225,4a1d2747) -,S(4e5bbf6d,5298fc76,97ddf9cb,e4d063a2,6b51f93c,eef032f2,f03eed04,fe4949e9,66702686,40cd9dc6,54514a19,ecd80930,1871fbbe,99254119,476e44e3,16a12188) -,S(a9778c3d,f509f069,3baedb83,6d5fc1aa,b78e86e6,dcb61200,74bf6df,c173237,33a9c991,86a0f913,95fa0e50,d0a85d65,9230a41c,8c0be5d6,90ee013f,29d0cab7) -,S(f1b3aaad,16664be7,c49790bc,1a4936ac,757fb3e7,26ccbc95,cdb7bb63,cf570449,d1dfe1cb,ea3fdc10,3f218398,14626782,643426,24d3aa3a,52b0fb4a,7460cc06) -,S(d66cfd3a,b015d585,6a436ad6,a4cf019d,9563a05c,af4ce2d0,6988a4c5,9349f598,5ea179b6,d097d9e5,663b7305,6db940f8,d8e91bbe,fb951756,d07cf6fa,111efc4d) -,S(a532a4f0,924b5d13,bef0f30a,a982edfd,5d87a16f,2c0d8470,ea8fe3bc,da0ac7aa,c2e62c19,ca4e3481,3cc3de70,df50386f,74fd1efa,ac6217ad,5532a927,1f8d5c1c) -,S(a9ab2512,5df78835,ffbd08c0,9e07b632,81ebb3ef,3fe2fb3e,1a3e5ff6,28439b70,58ff55db,56e015aa,9aa43698,acc35df1,f2eaadb5,4e950c7e,3501a5b5,85877514) -,S(ce058f84,90813dec,c184dc83,915c6d5,53df174a,41ed6521,f2cff46c,460466eb,414d38c4,58817414,5a815a7,84f4f71a,28237741,97b37d47,c7646b2f,8af3e745) -,S(991fab65,30a2b36a,ab385c7f,31644de9,afe9253,9db603d4,737beaa9,6e406299,2a29b576,77c544bd,f156dc9d,44da01f4,5d373cfb,7ada94df,4f82af9f,e48eed57) -,S(ee6cc81f,bd034eef,cc841921,5ab4817,ddfdd2fe,a13f1e14,e91c3f2,af715d8e,b8f79ffe,48c3e965,21c7358d,ea5cbc04,df8fd847,a97bca3f,6893af3b,e386d8be) -,S(66a2d372,d6426657,5544d5cc,5141e003,16ff2dfe,813357a3,c5daccda,159c5ef2,b57d2d6b,91c6f48d,389423b9,af265e04,780000d0,598229a0,5bada3f7,4dbc8929) -,S(20a02dd9,f697de3a,15043e73,fc7f36a3,7a5798e5,acb4cac6,adf5c692,3a421da9,1e6cf100,d162361e,aa6ab61e,711e3dca,ab4ab538,2fcc6b97,33836c30,cdcf34f7) -,S(a0b8ca43,7818e81f,6be98b15,4da25331,9f92b79a,1ceda110,92e3a303,cb7bf552,4541bceb,f447d990,50663ca1,10fce2da,218508e6,48b630ba,a1abfe5a,3d543be6) -,S(51714ead,73dce488,7e15c25f,b5cba9cd,e0d5018d,db5b8ffb,9e4174eb,1cc52c63,47b794a0,82ef561e,bee272c7,d66dd201,a5c24831,99977097,73b9141f,9bdafebf) -,S(18ea2763,1fe4de07,3e7c41f6,a9921e91,7da195a4,13417a2f,ba74ac2c,d6451c59,398a0b37,fff6bba9,b33e0428,e8d7c93c,d31b3b83,2e955e6b,106aed50,d64df316) -,S(e1d58b4f,c39e1834,a61ec341,acfa985f,c3d1f0a5,9d75b0cd,e8b9057,17c5a87e,1b62ee02,15fdfdec,8fe2ab3,bb7f99e5,af82153a,dd9c7f2,cf299225,9c6b3c47) -,S(39793917,30d3c125,7dff5ba8,eb253dc3,2c19c541,11caf9a3,bbdec3e7,716c5a84,d6a1fb50,189f36d9,912cded5,c851da8c,be7b4ebd,41c2a1e3,f78aa4a7,f5f18015) -,S(49b49e4b,601b406d,381dbf88,8b02519e,1d57360b,24f2aef1,5520f17a,5b9ede88,fcf3ccca,2f2d7b3,59be7be1,9e45a3,a0a76e9c,d0e42fad,bff7e772,f969a38d) -,S(2cd8190d,b42f36d,20d88548,f0ff17a1,d64e38a1,2241e4c3,2bfdaa45,28bdc871,f729c369,22141490,5aa84f45,e5abfeae,2fff780d,2b16aa67,77ef59b,68259187) -,S(1fd0fb11,17385466,2da0cb2c,f1f9d19a,b5b642ea,45d1c6f2,30808626,5e41025a,3136a688,fec60820,abc7825d,1c7012da,94e928d6,dbb6c08f,5579181e,469ce0e9) -,S(f08e5f3b,d7f8b5be,18648a0f,5bd844e5,3f93d5bb,120d3871,7de4440,7af3a141,3dd8725,9067eae1,cab61bdf,cc94ea0d,bf7ea1bc,df1d289f,a526e15f,d9902fac) -,S(a0033c06,b997fa96,373a046b,b5c6bdd7,a0584cf0,1feec5a5,d3f5cab1,1c5ee207,eed61931,aacbe48d,708c2cda,2208d40c,39a577b6,3d4ffa17,d140a8db,c3e268b4) -,S(77deec08,68bea671,df01e29b,117791a7,83ff8f70,4426bb1e,1ea91b6e,62c16f70,b908a228,ba8f73f6,3271ae7e,f19f5e9c,fcc1fe27,c0a224b5,dc426b00,5664861d) -,S(2fcded5f,fe2f10ed,1a1bd1fc,63506b3d,994a03c1,c188d960,5fd5aa1b,a9aa72b1,155bebf6,f09a86f1,d20d7c12,e12a0c66,b4df6628,4ff9d45d,3fab7d76,6bbefc6) -,S(1f0c0b2d,fdf5e733,abcadd0c,9ba47c09,8667f8ff,77c2a904,c8310e20,995db3ad,bd711bcb,84cef55f,5139b761,33268489,70f63182,85ccbe44,8efd7566,577bc566) -,S(b4a8544,e7162c44,60dbdf3c,5edf654f,d603fded,4aa885ef,465ea8f9,a37dcf8,53c04391,b3f2e8b2,32e27b,2292cb38,99f8ee6e,dbe1934c,13938a3d,203c62b2) -,S(df0ebe82,dcdeb735,38f31cdf,ad307397,d00a900c,6d94221a,9d85b0b7,2c5bd68c,c3299639,e7fe2e55,447b869e,3a4acf8b,4a1d07e2,d70701c6,8a2f4733,88decfb2) -,S(eb04b9b6,d1c38c33,e1eed101,fd28f89e,f9fd460e,5b379576,ec7c9267,3c101c0,4f26d849,7f47f80b,2b13cab5,782d6e9c,f5ee7548,3974a4eb,8d8f28,f5e0ee9e) -,S(7bc9efe2,197cc6ce,ac94b37a,cab9865,7db4ee0e,ea7b9cfa,ce9f71d0,d3294334,d931bcad,52347906,a941d940,4b5b3a51,ad8fb493,1c15c9a3,7ff782da,5da72013) -,S(8922d1e8,f4bd52c6,4bd0c10c,66a3e8b5,1321dc50,cc964844,e0a41ad3,b73e0b9b,2b643cf1,7d23e21e,890e6abd,3337dc52,61c9eec6,d5edc318,2a02a7a3,4a41c431) -,S(42f2ede3,3a9312ed,22f6a842,ac46801f,139a7da,77ca0e9a,cdc19d1a,f2ddcc72,50d45bcc,715c985c,b9260edf,fdc8e342,ab95360a,6bf4776a,c70e3497,8f26f99b) -,S(7bdc9720,1862feb2,58879255,726b5e4,627549f2,92936ea2,f3b27051,4d6761c6,700eb72b,7f77adf5,76e6f0bf,f8406660,65372ee4,cad6269,f1ca8541,2da4fa8c) -,S(b9b527a6,4bf549bf,5e42e0d8,5228e1a1,f79d1647,d2102306,6b6d98e1,746314cf,8e1b3464,2a721f5b,93a2a2b6,802f30ea,e35b1539,c6d84eb7,499299aa,aa0cd93f) -,S(b65de529,34d47765,1c29192,93ce1177,d187c431,590d2d74,978ac258,75e3dda9,3d6fcbe7,4ab9b5ce,b3dc5535,13036457,f0755509,ecbd94ef,324e36d6,3b9fa529) -,S(18eab632,608751e,af3604f6,a3f05611,a036edea,3405aca5,c2e66366,ce7c6b9b,89eb07bc,94671119,36e11f05,79f91e6e,ccd42605,24bd7dd9,9d12b365,95074c5) -,S(a2611066,4a479643,909a1606,596d39db,c7502ee4,a31b40a1,4eb1c60e,ead360d5,4b45d74d,88025576,3262d9fe,38198218,85721a81,f323cac0,3e87f372,75814901) -,S(789454b1,2c108537,a019dc58,35cf25c9,c77ac0fa,f6001959,5da9435d,3c08a8a7,6bee870f,ed2859fa,cbef4337,8a0bd760,8841da03,252687a2,591ae0bf,a5829041) -,S(1977c206,fb4f65f0,11b683b9,c2e0df95,f81570f9,9f6625ed,7cfe25d4,62791569,de76dda3,c22244aa,95ff435e,5a9ebe05,9dcc79b2,75d91de4,67de435e,bf698479) -,S(891f0df7,d259d536,40fe6086,1ac34d7d,ec3b5ad4,c3f56585,189ac986,65f4222f,cc5e0bf7,f538a2a,1ee7a601,1a8d6b0e,5c3293ab,404257d,ba90ace9,1b2de219) -,S(8534bbf6,9262f81e,5926c282,f412b4d3,50169de0,3c5c5e55,c80a937f,fe99530b,fbeee581,e0bb0737,4cc764c0,be5451e8,f70cfc23,4d415cf9,fb08e7eb,557423b5) -,S(e5b6f564,4e7dfd3,7474eafa,354598d5,58fc897c,f010198,9e44b07e,a86f63fb,4368bbfa,68a83a8b,76de7d98,38880780,8e153cc9,b380ad0,b2c6ce26,6118da79) -,S(f9591a8b,11c3e514,983dc5e5,507247a8,46e184f3,b4e38e29,f7c90d4e,6c2b850,423b6436,2361f587,cca4e288,a366a1fa,957de393,f29ff2a5,1fe97a0a,d90ff6b5) -,S(3d3239d3,252f5e9e,ef9eb617,c9646379,7c995059,57bc7821,2f2920b1,ff72384c,1c3e37b6,fc9bafac,e52798bf,695eb4df,ef860ee1,a9b67df7,8f73ca9f,22a2e57a) -,S(f4089723,4b574d76,86a8e855,408612a2,a0a6ce61,c1f14055,201d5c67,bcc5dfb8,6b8283b7,3e72fc91,54aaac24,2565a79f,c3a62fa7,602ffaf3,c7453209,c0a56a4) -,S(ace076e7,aea9c745,f6be65f8,498b8b47,95058ed2,b0413c64,bc4b462a,2e267ccf,b62c617,377fa9e5,eb72ed6d,caf353e2,dc58f362,a994520a,31f1dac1,168b97aa) -,S(70ccbba7,408c6069,3230b848,eadb1d1d,b4e63f33,b4fdf6af,29d6fc2d,86ec161,fc1cd9a0,46d30e60,e4128677,654a80ca,5a4ff338,71fbeec4,d7782c7b,a14d6959) -,S(e6e7a8b2,7c0c5b0c,5ea58d3a,4af5abc5,9e33fcb3,9970aede,7a8de629,e758d372,d40d11c4,c8c8b5a5,d511fee2,793e2c80,b40df3a5,c98bd704,9a8db3e5,c98d4a66) -,S(cdc495c7,e0a02e68,329495b7,19e2c424,7910e9a5,cff6739,117b1d32,23216346,63664f6e,9306c0ac,f29ddcd8,7f1df6ec,d51fc68c,6ce422f0,559205b1,681583d4) -,S(2784e89c,2fd721e0,22ba33,3b824dc1,d0142f19,6f35ae4f,825975d0,7a2fc5cc,ba58a66,bdfa661d,354232b9,b25628f4,5a391e44,f00841db,4a335ef5,dc3b8cf4) -,S(ab699b62,ebcb7380,2141dd83,184ba3cf,c9118bf,f6af4d0b,9b98ecde,b01a2390,5e548210,b71420f6,c5d42547,da0a7ccd,2be0117b,79847e71,a609044a,34766905) -,S(781ea7a5,67ffe37f,b9fad6d3,96dd1eaa,2209552a,9835ae08,dda3d4f0,b75756ec,3c76d87b,46f63b97,e4d48174,4ba664cc,403a507,dacdf4b2,af9505a0,f2637256) -,S(75ab2d30,dd5c0a82,a5c04fe7,b8fee5a3,a0e1ce3b,e20b33fd,39d0bd3e,e374029c,aaf46147,fdb1393a,cb9f6f8e,694c1cf7,30536efa,b5ef921a,72215fcd,61914b9f) -,S(294b6698,37303da9,6d23caea,684ad56d,8712433,d11c7ced,85a10cf8,8ddaff0,af4d7ef7,feb73e9e,a9407fa8,b38bf1f1,e5861bfc,82f9cb42,22fa64f7,9b46f7c1) -,S(d8676aea,7433639f,c9683b06,bd97011c,f290f6e9,1257ee55,ea3c6e34,b824c8d6,710c8876,35d45545,90f3e5c,d6aac133,9017b2a,de71e30f,d71a5b71,97a7456d) -,S(5e4eca03,d90f5ac,2ac4771c,6d86a458,cee71427,a93b7544,fd8bee74,161270d0,44fe0143,b970f8bf,affa6d60,33628894,a93bb4a4,f48cbb9f,f0caf0b7,40c97351) -,S(90152daa,244fba85,fe708f21,29b55485,265c3a3d,dbc761dc,157f125b,8580097e,1694d2c9,200b8690,b59fa3b2,8fc2f613,8a6d392c,48357939,b9435739,83ef2cf7) -,S(67dd54f0,96f171c4,53fa953f,acbf2b9c,daf3a199,732ee0f1,91fb3c90,8c5637b5,5327db43,2d33676d,b6502236,5a338c62,5fd6c4a4,536645df,b36279bc,4ede74b1) -,S(c6496a83,8f95ff57,65a0f144,774cf543,2e770457,55efc790,142df95f,bb6c51ef,cc0041d6,604d1d73,92d86f01,d8b05b53,1177b51e,3a38b8ca,ca8267fc,bcd752a2) -,S(e799d70a,b163bfd,475e5e72,8810d9d2,425bf4b6,9461e9ad,933fdb6f,68c11c74,fc34745f,e29bee3f,9b0adcf7,618c6d13,e504449d,1a272b21,5ef9fc18,14ba8600) -,S(6d3c97b0,151a9011,5032aa22,1183d82e,820c8774,c3dcd75a,cb6f45ac,5d489d3b,5aa8bd01,3d15d77b,8f695d43,8cedd9ee,64b57df9,ee672323,1c2cd5b1,4ad4749f) -,S(86e53e00,1c1e7de7,419cf2d9,a4c6a39b,b96d8ec3,a82f8165,45658eff,a517539,f8b1b70,f2efecc0,cedda525,40663114,c24491ac,266df520,ce475f01,ab44ad86) -,S(a641c339,ac877cce,a9a3267a,78edb33f,75feb90,1f3c8743,47c50843,52a9880a,d88a6d4f,2b275ac5,3c7dc101,b7d69ca5,407559c6,afdc9009,c34a7256,f982163) -,S(3a0153a9,4d778266,4581de43,6de31754,b925aad5,4090cceb,9e013568,9d82511a,f6ca48,94935c5a,7a252df3,8ff06cf9,11154b0d,9f0ac55e,35a33d7a,58802035) -,S(e78024e8,a131c9ad,40526b31,d26e96f4,2c2e51d7,c63f458c,5bec2a61,472b170f,c540a14b,1ad7b18f,23493d9c,edab65dd,3a309204,976408ea,f197f658,9f4e0c53) -,S(7858c85e,8351f0ec,740380fa,b1924668,7f05a161,e2dd87cc,7df13338,a86a5162,cad94344,5313a06f,c382897e,7c444d53,7e658e06,5a76fa60,928d7e5b,36a6de1c) -,S(6643e28,1c5bddd4,35a68c17,965f334,ddb9da8a,d599a4b8,2f37147a,cb0263e6,9f9f9e36,8ee1aa0b,9bc8f928,284968d5,6f2dc8fa,6944ff36,d728b588,a72cf79b) -,S(5f36d937,a286f14c,96fe8f9e,3ea05d56,b3132523,e9a135e7,106592d6,b9b2254b,9d6377c,c8265ff2,dcebf753,ef2fd39e,9adb0e1c,3c86acfc,2e54648b,9056310a) -,S(212eb1ae,93d3a0aa,5f626f26,628503c2,310f9172,461ea12f,b17677eb,c63e2224,51e57e33,347f2016,c738d9fd,cf528269,bbc5afe,f5fd6fa5,1dfcfd47,4b6d1b67) -,S(526952c8,940b9f93,32848145,203ce261,dedb3b93,8e6f277e,9a085d77,35e9eab4,8657cfa3,56df2aaf,9a5fe2fd,81804ff8,1d9aa58f,143fa109,52e4f4cd,85a42918) -,S(20f1750d,ef762812,e4ba8778,c953a2d1,419e03c,b97ab6ef,8f98be07,4c1c099f,d2fee9f5,3e7ad2a7,fb20bf88,16a1ec2d,d9d97b4e,5abc060e,bd8e8b31,bacd485e) -,S(e231a3b7,ea011665,c223cfb2,7f13c691,dbc7f5e5,efb66496,da2936dc,d67ee910,aa645c2e,18e80131,f3e7316c,7cdf13c3,45e4f602,fb17011e,96eb5fc0,bf65d53f) -,S(7a4e4d52,3fd026dd,3daeac35,552e7299,d01aa962,687a02cb,ed7174b6,25c702ad,351c12b6,a7398e5a,ae461204,4cd7c9a4,7d2bdfc1,1f941b84,71eb3304,fdb965d2) -,S(fd2f707e,76965670,67ca5a5c,a0010c6f,9a858967,19a23eaa,5574d1c6,cbf137b3,c45a430c,1d5ae473,31f9b161,3ce55f41,df00e287,9e3bf8aa,1ae75306,f8315408) -,S(c506cc1e,8cf2f4fc,e1011d67,6d304877,6c2ac2a4,f8265373,f3f918d3,f02bb89d,8de6dfb3,74029b33,2fa47f6d,1f7ba609,bea33d6e,2f58ef0c,58641e2,a5d3118a) -,S(2ea7ad02,d9ccf999,86ab901c,3c9cde3c,ad1bb4d7,d8f86eeb,b8204b75,ab5c0369,11222bd8,6d750302,763648dd,daf76947,2b213562,494ebd9c,e4003195,eb0ed43) -,S(ab8cc192,3555e4e5,2f84b421,ba2ac134,f8a6023a,ddfd279c,4c338cd1,9e159c5c,2c48e3bd,cc268dbc,23e9fbda,6c449079,5a5b54eb,54ca8ff5,14d1f23f,8751ee1a) -,S(88fec2e1,cc7c41fa,91b48e1c,2a71089a,c3778427,f2cfce04,c54af407,f5dad430,ccb45e88,4f696653,5fac7a04,9b035c26,dce30666,fb1fecf3,c4b89deb,8b3ed80b) -,S(404587ae,1accf5d1,b42c3127,2ea0cdce,940522a1,c64c757c,11d3768,774b0d41,e8dcf25b,25ae61f4,f7368c36,9b351b35,63401deb,5ce55325,f96a393f,ef0e787b) -,S(8a701eb9,cadea8c0,8d0cf20a,b2750915,28a377cf,bc4d9097,51424d1a,7eb9ab8a,4f045982,82a9ac70,c3c76154,ca98b5a1,265e8b26,6f02d43a,4549cdea,caba5a45) -,S(c2812978,194009c2,9da141fd,b108a4c3,66e15e06,c6d64389,29b2aa78,89ad3d56,85409efb,6670e969,a2834255,dcb1e546,9c9db5e7,6e549afa,974936c8,b75db5c1) -,S(9ffd36b1,c810c843,92bb04d1,90b82be0,f8ea4b4,2baa6129,8adfb810,71d72fe,11e27a4b,a11f0df8,1a42955e,bfa9fe1a,6f25fda4,6a65fd87,1caa3d6a,1b38404) -,S(ac4a0044,bc92b017,cad07210,750eec62,39e43147,5e3feb25,f1c6f879,a5a48b96,41c7c3ba,731002ff,1e749853,344c1f53,f526bbbf,457b4de2,d5f88ce4,1eb8dfe1) -,S(c78b101c,157ca920,b3fc83bf,9d19fc5f,57d8086c,d764e142,24ae4e86,7b06eb5a,1a8d2c6e,b9d660ff,faf5f533,b4f3b8f6,b7a9d7cd,5c29c1d2,deb37f19,d38126c8) -,S(d08f3b05,572348b9,5f3c1c2d,baedd921,c24b0db8,e6d17d13,578e5ae8,77147cd2,27b5fcde,a067cbb,69ae3e5c,90a38523,4987dfaf,5dfe0696,91461e26,762713cb) -,S(40ea043d,5060f61e,b81db0f1,c7c5c1fc,1091cf51,c5808489,3d08c4b2,a5e312f5,2ef11ec4,2836302f,e02719be,259f1536,43de03e,fb659f30,84816a00,1d66b27c) -,S(f9d104bd,fb53b4b2,de8827b2,8242eba5,17db73f9,dbb1eec3,9f184ad0,358362e7,d7644a0b,6c371948,2ba707b6,d7d43f0a,68f4e3c1,4af6f167,296ccfcf,4d771877) -,S(dd276aee,14c34829,4e6132b4,9a05dac,fea5f8a2,41712b6e,5703778d,eff9ddc9,9be617d,5d92eec9,7fede655,39690d0f,4803f760,2b74066b,7bc98353,a5ceb7ef) -,S(8522f839,d5f17bd0,c67d11f6,7f0db8db,2104c7d7,785252f4,c8be84f0,61155d49,b7791951,80311f8f,6cb9b59c,ddca495a,e01f3edd,599f8777,3163a959,5a3ea117) -,S(732802bd,b4f3be8e,fc02a62,4614672a,51049166,4bfce64e,eb2030d8,b6b5b225,7bd4cdec,590eee1d,6a505f92,cc0b25ce,d9022d62,d1155f8e,35a6ab72,46a3c6f3) -,S(1b3641a1,2c4f8352,21e73276,b8bdea15,f5ffcbaf,c4496fc6,8fbdb573,5967af62,3d50ef5,e5d12b7b,2ede2e15,3b4cd01c,b824c32,7a8e1ce,f0fd866d,99664048) -,S(d3034e18,4e9284ff,ed6cbe60,cb66d391,c897255,dbbe8c85,2c79525d,3f01a7ce,b3666304,16ce50e7,2a094b05,85f1ba1e,11172ac4,eeb353b4,8c4f8f99,f9d09e25) -,S(8e7a8200,bd22f5ef,18fa4461,8f4f85a,61c6db2a,a3ad176d,65c3270a,69e9db17,841fe3b5,1cce979b,f87536ed,c71f4cd4,4a482475,19b35cea,dee4b3b1,f3530568) -,S(fcccb4de,29ab8671,d1aaee27,61421ae1,c4af5f3d,839009e8,5dab0b65,60a4027e,a0229f96,203b89af,d5b6ac06,9e977e71,a6e269d4,bea29c47,fa6bd22e,f7f993b) -,S(e68cfd7f,44358180,84c681f0,aead705b,9e74a476,1f99e576,9252c007,e44c8a26,add9c0a7,b027e2ae,42378d50,cf0d0eb5,71229161,8e9f13c1,672121d2,c428f82e) -,S(8b6f0fad,4b81ac16,4866de7a,c8bb3252,63bfe008,b726e9a8,72e0461,2c6891d8,9bad6508,a8d604b7,8088d328,ca27fe13,91493e8f,a6291288,92ecaed,ba4bc9ca) -,S(108a0caa,37ac1949,263178cf,20674616,470f8943,57a921ba,8cfd499b,d64b78b1,68150d22,be05956f,5ffe302e,1ff517c7,9b7c0452,6112b2a7,5a819f64,a265bf55) -,S(fed18333,844c579,1d32daa8,3370a5c6,ab8e13a5,2654a08b,42940284,c757edb6,67bddf37,8395ab84,eba29a97,6952ea34,b1b52c2e,d3f89e56,f839c1ff,36457fe5) -,S(bebfb39d,ecd56cf3,50bed6f1,a4cde24,848b2d84,23518da5,1fb2ee0,90170a2f,1302b4b3,bb86f887,22925fbd,e146d948,5acb2db,a61e751,97dd40ca,2ba11573) -,S(67135aed,2a58d3b6,c4470d3c,b4da7b56,af8d5057,9d28a86c,9c67bf28,181e716c,97c40aab,2786e3ef,dc8f3e77,8f374446,30fa2f3f,53eb040,194809c,8efd6664) -,S(b00eb5bb,9566e5a,cdb09dd4,14d6df03,c3dea75e,90db8b9,c37928e5,4354f90e,6d120e41,1cb6e674,e9973aa6,3999af3a,ccc3a670,112c964d,8aef93ee,e69b1258) -,S(721b1a6c,be8d2022,f09db6d3,ba39b2d9,23337592,de9efbb8,ecdf3384,f3bb73a2,cdb41b62,631a0f47,75ae1f2,e94f8075,4acbb2e7,950be088,5b458c8e,4a05310f) -,S(cb8d78ac,15b12ca,8dd47cde,190c420e,42f60b83,9489bf71,d10a3e44,df8a0837,80be31a6,a3073675,e8cd3846,cfb2e127,abdc448b,1081a2d5,d177ccff,ea96dbc2) -,S(491cfbcc,4919d884,d23f3ae6,6d143e55,37e5c52b,e2ee017a,afec785,6c781920,76321b50,26283088,d344d29c,c4d9f2ec,3ba714d4,edc1bee6,2b17ecc4,56874189) -,S(6ca33ee,48992263,23aed33f,f822303b,8145d146,c5ebc27c,fb3700b3,6ab507b4,96b73ab3,f189d064,1e0a20cf,d09522bf,8c376a0a,9c9dbec6,44e3e8d2,c0b11f4e) -,S(6d1fdfcb,3c48971b,6cbb33d3,822cfa68,1bf602ef,98160f89,97ccaba8,19d842c7,82bc7c4,66088262,5e57c062,96f04600,fa555ac4,5596b769,9c6d29c,cfb1713f) -,S(a3e81699,1cf92f41,a69ac3ca,36b23796,daeb533c,3e1e9b55,c88e3fa9,fea43554,87a6fa9b,e802467a,fa206b0b,45405309,65887df5,786d20fa,25e94832,312855f1) -,S(fc84abd7,cbfbc329,4eac7438,d50b2ac4,7f570e4f,3f2ffab5,71f8c3e8,7dd49c70,7447b269,71356b0,e59b3f1c,d99b6416,589f6c3b,a566c75b,6915377d,a7f73dd9) -,S(beb23240,8fc515ba,180d3125,2eca15a1,af4e02a8,73a69769,53982408,355d1b1,12fa480d,6fa8a9aa,e5edeba9,31b765b0,e2bbe6a1,5eb9e95,b3bc343f,519c1459) -,S(68891679,cffad7f3,19a373d7,1bc02529,a50e63b,60434f13,df760364,1a99eb8e,40b78db7,6db28aa2,d2ea7c1e,86d01503,7736ce96,2e6ec524,da07b5b7,68772fb8) -,S(ec435ad,1ae7b040,fde2f736,e8fb5d53,b42e2fcd,428e9d96,ed401ee2,bb068817,13bf6eaa,1283436f,4a828a85,66c4f795,26860c45,d650fac2,44bbec8e,fc96f9f2) -,S(679f5afa,661f688b,7dfb7ce7,f77e4904,60a75576,6216a49f,374594d0,6bde3033,ff3fffd9,6c254fda,558f14bf,c8f05cb6,c8fddd32,a487d709,4e0fb35c,6f617ca1) -,S(9febd8ea,5dc26e5,fbf48aeb,64307b21,1aa2fc02,eceb6d68,ba89a652,f633be60,c0867bc8,ea6238a4,ad36e785,cbbc5e0f,3fc5dc96,2c778992,72be4364,8e630bee) -,S(d886b154,c534b48e,db6bed69,6dd8f9f1,347b381,1b593acf,e2137c93,600b1601,a4cbc118,aa07daa9,c4e246c8,efeaa3f7,d74028c1,93b77964,f10ab5d6,f75d077) -,S(af8ccbef,c187a3a6,83f6ab6,8ff217a1,96a8e27,dcec349a,b7ee4a74,446e9d47,3ee327c,99880392,7da5b625,be554e6f,1662a733,25a8fdc4,990716cf,6be941f0) -,S(1e9800e7,891c261c,a3451d22,44a54a84,42d33458,a997b365,4a6198bc,7dd3d26a,322f8986,bd6ffc0d,d5f1a321,e82e6b37,978120c9,66f753bd,5669a773,65a215d4) -,S(115c62f2,9f008009,5840dc97,f3a90f30,aae4ffa6,a2d255e4,15d64c56,77150044,4d944c12,7e37ce5e,fd7660e0,1e4fdf0a,cceef95e,8bc2da14,a8fd7e32,ead8af95) -,S(1cb9f9d,acbf79dd,b34d78e8,e51225bf,3f53135f,f4282ba2,59855968,2ae0178c,8fd3a4e3,7a189bc9,421595e2,bcf234e,d7b602d0,855de84a,50c68cb4,bd1a4bf5) -,S(62a15bc4,63e4c167,4bab2a5b,dc991e39,af86d258,f9de770b,66a79ee5,2fbfe357,b78fca9f,d9467e4d,256da69f,e6f45522,d376fe41,e8ebde9f,9f7bde4b,8ef52749) -,S(574a6ce0,5bf31948,31570914,a73bed4e,6bd2c82a,5a19dec4,54b11e93,5edf505e,e7b2e2cc,cbd6f338,f0ea60b8,c1a9a50e,d02dbaba,8bb5cb78,9b281a97,5c001318) -,S(64c6e37c,a3a361a4,baf9ceda,d9ed24fd,c5ae50ab,560e6319,4adad1d5,264084e6,e6e42f56,56b6b404,9c54a07,f35ae004,4b7a480e,8271c8d3,f7996ed6,68116067) -,S(49065a97,fe4a8de5,55646af8,475607a7,71b27746,ade7fb11,55308107,4900fd84,985d689f,67a03090,9ab8eb43,c7b2767c,94e7217b,fbb43342,83485f1a,d70ae7f9) -,S(6fd32ff9,185790bd,876a683b,7e889f32,8500c91e,7e5889aa,44394caa,330999cb,12fe8084,1be1f25d,7a93784e,9c6bf01f,efbd6493,8f1a678c,64497a8c,85d2de3b) -,S(4a67d4da,48189c8e,6ff34812,f7094851,2d6d12c4,26fdc98b,4ebb92b6,62d3b185,58ea83f2,f6e5b777,737c668e,efa71b8f,3e50095d,389a5540,684cea51,7f8150f5) -,S(ea1ac931,d3a92770,5d20752d,b9adb464,edecf4c5,95c20c85,987e1beb,a79f4db2,cf689b0e,25aa9601,58316597,b06fd91b,426b5753,68a48830,9c3f6f34,6722b83e) -,S(8cb35a6e,248a0527,d572663f,7abc99c9,61414af3,f196c6c1,2de4dbf4,dd545c5a,4b32e4e0,47dacdb6,66edfc3f,a08d500d,c43292ab,f36bea7c,4a3952e6,680cfcfa) -,S(247c800c,f150c2ea,cfef8dfb,f4581560,84318684,430788e3,c8d99ccd,d27f21c8,cc82d8dc,914fd1a0,e626462f,5829eb7e,a708395d,db3e70a7,57942e85,1f1d0db6) -,S(6543d7c4,7fb927c,fb0f3566,6103708e,5e0c4a4c,ed202482,c9f48647,33426673,e252b29a,69b4ad75,814ae0d1,631ea750,20bbc730,3fdc819c,88d8f3d4,7907ebab) -,S(c4f11255,d81c33a3,a09da4ac,af5c9c16,d5e759db,2e1026c2,9b3556b4,c388e6d0,e2e636a8,1af48ab5,814e5530,e48f518d,95379eab,186e94f2,4fcd551d,1ca8fd49) -,S(cf186a9d,85da39b7,7383d92a,14af5a05,b082848f,c9e60598,1bad8ef9,5e019eec,cabde21b,c860fe08,53f672a1,64010968,6b49f37e,61cc642,48f455bc,b079e3fc) -,S(e6c3e353,ad69dc13,e595c2c7,a88b8fd8,fe9d1d47,3d45f7f6,be9ae903,86ea8f32,7d3becc9,4f455c1d,21610800,a4985f33,96b5a920,d5ed2b57,2107c28,ac690be1) -,S(3827b3a3,9bcb554d,54695dc6,bcf22911,d1ba01f7,730d1c11,8d6a7b2e,c1060988,32413047,b7c9ee83,1b818c5e,cb8f4c10,c800a362,419227bf,d9f50aff,ca25a211) -,S(ff37cd38,a4b149a2,a8dae898,c40b0ef4,4b55ed85,11b5413e,48f5608d,cc6d24fa,5e615919,8f4c6665,7c3a489b,86853a95,f3ffded5,20433cec,a6832cac,b9c49048) -,S(bdff4fc8,5b492fae,1ef34322,9e83b751,d9e53c7c,455141de,f68d3e8a,320ce509,e8fd9864,9dcc5d66,6155088a,29959e12,531f8a4e,44d70b8a,43b4fde0,8bde3d20) -,S(fd6ba29c,313ff2d5,7fb2719d,9018f11e,e59d1007,24146aef,625a9b3c,3bbcd0af,187daf5e,913310c3,39f584b,3196b877,5018dbe8,1e38abf6,de73e97d,f5c1079d) -,S(ea3c422d,48606929,ef72ae1c,3ac30178,4f4b5f78,1405fb62,1d0b710b,1b29ff28,e458b41e,c6c3e06f,c37637ee,fa316e25,d10b377c,ef99aaf2,564fef92,33bf208c) -,S(46537133,4982d600,8d228924,f0b459b8,2ba8aed,af1b3c39,f87053f,487b3978,fd96654c,13189def,f243bb29,e2143dca,3b2444da,3b895700,6bbff65a,4dadf3f0) -,S(fda493f1,1226069a,ac76227f,9f9e1051,b5b29b4a,a2d0f9dd,99637176,8578d8f5,5a33593d,f63d136d,f43a69d7,f9803a62,e04e55b5,25633a06,d8eb86c7,e1d46fa3) -,S(74fc42e9,5f09018a,5468e283,5ea36fee,7ab5e757,c57200cd,966174f,39f3e4c1,ccaa0b40,3802c914,da86204d,45f8f5d7,3760e075,4bfd10b3,2a8b2521,218751f0) -,S(98cec4a,997b79a0,cb818da,58e41477,d98f8c2,8140fbaf,e118bb1a,ec483d53,2fce6058,14945cd5,367b82fa,182c19d5,ac422d9e,840eae4,d81689ac,7eaaec08) -,S(c742ddb7,89a5cbdc,2055119f,697fd575,e4fa1540,96cc5fc1,3c2374b1,13cba60f,9b0af128,34a990e1,d402474b,e6dbaa1,b32248f4,f2b1d680,13fa0dea,46f3532d) -,S(dba2e04f,9a78066a,b5897913,6c4c7224,5b5973d8,3b13819b,77409fd1,e791eb89,34747922,3adb5f74,168240e7,a178f077,aa0e90e0,870456a8,89dfca5e,633baf43) -,S(6d4cae43,6e598586,7b984dcb,6c2472b3,6cc47f86,eb69fbf,1069c69c,42f6538d,c7fb58c9,f0c4f7ce,dd7c53c9,23efef52,125c2b67,d67f1ced,b98bb1f3,d5e0a84f) -,S(4c457f6e,d5b67b05,5b664ed4,3bae291a,9ec5b539,6fd9410f,9cc16a03,b8523982,492e5bcf,20aae19f,5462ed68,2a72827a,a435f47f,ec218e98,8e91fed5,20f344eb) -,S(4d7e6922,34778a41,f58033bf,d74ae295,51fd8ac3,64cd817,9cdd441f,cb46eb3f,756ec0b2,ff5c9d3c,3a453879,17ada4bb,6d7bbd07,bd10d2ad,c092f46,c62750c4) -,S(ac5be50,69bad479,bdbc565e,ab74ef94,4a48399c,a4af915c,fefc47e3,7d464b2,3246e3fe,bc5810b6,37722c54,69ce45d8,8bad5daa,529b4381,928b7cfa,de874345) -,S(7da88d41,21350139,bfe6a481,2534b25a,24f91e0b,60d882d1,5d69e840,da3995b2,9888ad8d,62a7a4f8,700bb03c,f9772432,6a2d092c,98adbeb5,cbc20348,f0b9c587) -,S(389ff31a,63239cd2,c9aa3eb,4d3ceb49,5d3b922b,5d137d4,e8b52be3,b1abf149,b0ec2a2f,bc840bf2,8a22ab22,b76c1485,42f54ed,5515ad49,dc3c0037,38fe7c93) -,S(c1cc1acf,5fb128b2,ea65afaa,d3d5736e,a94b2e49,8dfcf6f8,f3c27a5d,596c4370,8903584d,1986ad31,6cc6bf2d,aa2a88cc,ecfec6a9,c1bb153b,27c409e6,934fd38e) -,S(399ace52,b92768a2,a4740be8,31c96c04,2a34957,e91b3cf9,8b3518b4,87c9aa3a,908314b3,abdb3a47,a117ae09,5d609fa3,fd9af1c3,ca04a869,786eb134,48800005) -,S(69543fd,8c9d01a5,702d9859,305a52b9,470cc606,cadbc76,d8283ba9,ba06d0a2,e998e7d9,a0c372ed,2e348f17,b3298088,404eb1c3,8a901d1b,6f4e8a19,731057df) -,S(2172d54f,df9b46ef,5a1289a5,872b1c28,911e553c,f703ad6d,400b6af7,e8200100,2121b47d,3b790e5e,c820df5,772b226f,34a8fbeb,f642b5d9,edc18971,1b687a8c) -,S(f606f7e9,37a324e5,d0e6847d,24923965,cc27133a,10e43f28,6d45f7ce,9d5e8b56,70013fb8,622a21e2,d1337944,89324a13,f5b80580,91ca08d1,a30e7571,3e86e007) -,S(9f1520c2,dfceb64f,1f432013,b342af35,2f95bb2d,d49aa14e,dfcd8e71,7c40fc99,fe8fca26,feb1f004,8fa4fe3b,764a907e,d53dc0a4,10308199,6cad54d3,898e863d) -,S(6670af6e,7587676e,eb0674eb,75c93d38,53afe418,cb286605,18a9370a,231eaa08,2993ff5e,dfc071ee,97fcee9,bb12fd8,fb59fccc,524d8537,34ba4cee,4beb09f3) -,S(15c6d58b,345cc4bc,e4ca4e2f,ee954c2d,40650a4e,ad6c9524,65f59a94,b3898350,894c53b,47276196,65a0f3ad,f528d2c0,221b12aa,73df2cf3,a6b0e778,a363cf7f) -,S(bc4ab6bf,60dbde42,c9293ef1,75f85a48,adfffd20,960ea454,8a919977,75389621,fe28a0ba,24a4e2a7,45d6bb68,ecd71931,791a74,61549a44,37a34761,19040e42) -,S(5dab1c63,23fbf2f6,e495e87f,1c703ba8,64f20e50,4007dc80,54ef2e11,d3e6ee1,1fd0c200,cf4460bd,ae6db415,3e68bffb,e7f01ac1,6b30e305,9c134a86,52695d93) -,S(2df1cd57,d7357c44,7be28dbb,c339ceb,5cea0bd8,e702fbb2,dd67c189,6a8acaf2,33192011,20cbc8dd,c3b9c031,94db76f5,86eefa67,995dd741,492f425a,e2f1b9e8) -,S(2d81ac17,5a02daf0,83100585,ed2bac76,3d9f9764,15356fea,584ddef,60d9ab8d,f9908cd1,3b1785f5,78297fd4,9e6c26e4,21052e2c,ce9f51c9,cd58183c,2df9a0b7) -,S(1fac1762,fb732e73,2440d40a,5356eb17,67b1e7f4,f11e8db5,9ef90702,437dc097,edd5784c,a58d5113,2b5a08ac,e75cb30d,5ae7ce27,129f158,4df5d95a,7b9b8729) -,S(d06a0b5b,4694b90b,80c93e88,4aa9086e,45cabaf0,99b15a9c,c2b19678,38c8c98e,4cad46ba,2777b24f,cd1b391b,222ff3b1,14fcc814,5f78ada4,98620cfb,747def3) -,S(4928df27,590240f9,9907928a,cb6f0695,870059b8,cf9b1d69,29b152b1,7de53445,b773e60b,655b3b0e,7b0c400f,37dc336b,240b83cc,286a8ac5,3dba751a,3300d505) -,S(a61bcdf9,cd541811,4ba99261,7322827f,f945d450,c331ddda,1b8639ff,87a28390,3e771d6e,d6fdbb28,54601b2b,301fe24d,8e61b370,ebe644ee,b40fe807,b8d93a68) -,S(535a35b9,3e2fb7ab,b3b1228c,a7977,fb8e34c,107f093f,9f641b15,11db93c3,2471ff35,5657cc8c,38283fba,27c2e3c2,92475fb5,e8d52e96,f0c9fec9,b2ff786f) -,S(e68a652c,e0140f29,376888bb,c6be70b0,f23ad42a,d10b8acf,a5f790b4,c465d4d0,49d7390c,c368060b,3134ecb6,dad52120,ea6e0c7e,b80c94c,6cf9c1d,3c1a7385) -,S(e8939e7a,74dfccd3,ef17855c,3ea20e99,f5f05f6f,8bc4757,6b4f0e99,37e25fde,6b48a73e,ff0a55b7,c90c0fdf,449e4c2b,3773f454,da2c388b,3e0829fe,d661b173) -,S(496013ea,31451874,800fa293,a6e70ac,7fe16483,67c31daf,bfd00faf,48751543,b5715111,8790556f,8a4001cb,282b3312,581e1508,b8537f65,6142e2f1,ab8c4332) -,S(444735b0,b1efc3a9,56957a07,22604d09,bb0f6c29,e7cc5201,89ddc3c1,804b1e1f,b1ad60a3,461abab3,a9732a85,7050e55a,3e9a439f,32a5b21f,9aebe400,7e59d6e4) -,S(5805ac8,4acd7d5c,f85a40e7,4b9c98c3,e8882189,e77aa475,da3b4114,3ed9511c,c952923b,fbba533f,7bd70dcf,d8d69b7,1ad0022,aeae363,bb48134d,6a3c07c0) -,S(8ac11518,30fdc785,5e1c53a1,2b690202,c12619bd,c46c8898,dcab77ef,279a9501,29fb7cc7,7867fa0e,1d015493,abfb2000,d5deb3b8,ddb3053a,d59d6bd4,a9ca4fa4) -,S(aa47add3,e42998cb,68fc8a7c,cc7beff5,4d70226f,22f41ec6,7bd7b444,aab542d,cfa5ac81,ebefd98c,3af4f9e3,9f67459a,4f8e8c4f,c1959816,f771e75c,c43683e9) -,S(f3504127,a27a14ee,92133f75,364922b7,d3984898,e433d3e4,19e88db9,e599889a,f1af9f7e,9f9868a8,84ecdae5,47bcb886,56c6d423,a066b313,c09cdf08,601b45df) -,S(33730f44,edcbe688,35887076,69a989a6,272d3ce5,9261b98c,7c6eeeed,7e4bf08d,3f833928,d87716d0,4b2a32d8,1bd2d789,b6fd057e,cc70a794,8605cbe6,e1775a6b) -,S(3169d6dc,8c06f584,880bdf07,29249cc0,a33d417f,be137478,6e5b4a14,3edfb0d6,2a91422d,ec563839,ba782f59,68f428c8,a311600c,2fde77fc,ea163e86,aa74ce5f) -,S(d8c64582,13aae81,cf07a64d,5a8dc3eb,c8c43a45,d57f8e9,80cfccc6,f02a4429,c4873051,968863ae,8c92f195,c9fee3b2,c4773d47,849e2a7b,e7f48c4a,93822aea) -,S(ae67101f,307e246f,7a7cb039,5631b884,7e59c8d8,14da3fe1,7891f69f,402b6f11,f5f2dbb4,a90b09e8,b96767af,a9f9a357,1d3900f9,7d8222ae,e411e1c7,11ed44cb) -,S(a9e87231,83ba8338,1c0a7dc9,c81a2c5e,b4e2ff43,82574f0c,1a9d7f14,81dbd8ee,96810599,90d90e33,d69fb59b,ee68344f,333153ac,3d73a335,4b7ddd6f,96468901) -,S(616bf21c,ae7d40b,2694f43a,a33e6848,694ef879,fb5bc48d,ad141e34,e43376f2,bec18f83,2aa8a0ba,83245115,3b5a4faa,4a27725a,a3d9e799,bf05dc94,9880fc77) -,S(121e8335,601f33d4,78a882b1,1e9be5bb,39be47cf,701a695f,8d351098,af3f5c2d,2e992933,18faa04b,7d85fdfd,cbff81df,10dd070,4485b659,f682a298,4d03b3e8) -,S(bf884797,3025ca9c,9413948,fef1bc48,3a83cc28,4a909933,25c8c97b,b89f1141,1953a326,3d26d1d7,86d5ae3a,7838d125,6de24760,6abbb63f,e2713f6,6ead5386) -,S(7c28e9a6,5a3800f9,85c94d4b,ddc75cd0,dd1b06e0,faeda124,e86600a5,6af811f0,a3756db7,e339f03,8914cedb,707427b4,2d396fd6,f2e43863,13414863,8ab5c277) -,S(e5ec6dad,45e62cf4,1ccb5bf6,bb92387b,46be0791,31bc2b9c,b8b93172,90a66077,d0045ecc,775703ca,f854bea4,be3c4d21,2bacd092,7a210eda,67c33aba,e44f0e19) -,S(6fc96e1f,92039545,fb31c352,544a5974,7036263e,34d8e043,58336169,118c2fed,d032de87,1571de8d,96b0457f,84397e36,6ca7c20d,d90d089d,9aababad,8b8a9a51) -,S(89e3d351,1c219c47,42e79091,47c13146,1db684dc,e1a1149a,cf49115a,746e4133,aabd970b,672e8468,d84b53d2,303d57eb,52fde5bb,bb224b03,6892f918,630c5c90) -,S(2b7a60f0,b2136453,878eb44e,aadb8da8,c043e947,fea1de8,4ff8e18a,390d5890,c829b16,1ba032a0,59340709,1b38b365,b806686d,19026f41,ae8bbab7,d04a5244) -,S(464b9f1a,c2c2aeb7,e6f7c3df,a8782f25,bfeb9879,9263a9d4,2f872050,6c9627e7,7c260bf4,59e1bcc2,df7761db,e503875e,9a23a107,6cb4e8aa,dac5b5b5,b6f7502c) -,S(79253e30,43572295,e331519,e774b670,b25141a,986eb5ab,268b63a2,759b616f,da609d7a,55b62353,b20f5bae,969665ca,ed6467d8,f2577f69,10003586,e27f88e1) -,S(634287c,e900c0cb,5c2b1967,f55190f9,19acb09,43596773,87642d16,dd399556,a2350909,8cf01601,30c042db,253334ac,223c473e,312bf758,1fcb461a,c3debead) -,S(761121c3,8bd8fd5b,a3418557,f6a75b42,d7ef2f4b,91620223,3587f183,421bee98,4014715f,f9c17435,10e6eeb0,1bb29226,76070e34,afaed040,5c897bdb,52dd530f) -,S(2618c8c1,bfbbdf1a,59da3078,4e50a2b0,77990fe1,c2f074b3,e63dd606,6d453413,ae539a37,20f5b6ab,18ce584b,4ea3cb46,4bdaf35b,326fdab0,58169ddd,32a48da0) -,S(d429fccc,10c6f025,fc7a57e1,949308b4,d91699b5,c099820d,ab31f1db,90f685be,da2b15c1,ee155918,de414ae9,1be51688,a8df043d,6fb6c964,689bd4e,5a648edf) -,S(6a18e3c7,c04b8cab,36e07625,ba2daef5,bf1e0cf6,36650b6d,56dda8d8,e4e8b705,66291330,f56c96db,ebf9c9da,bc52541d,20e75440,25fcc49e,d6215d8b,c0e94eec) -,S(985b6846,d1c9f3fe,5482fa4a,d6a21c65,d7ca3eff,a41b3220,1a37a122,f8f97756,3e2b23dd,98e18f6b,76a2f2c3,2c543f8b,bb9dc6c0,8d391592,d56f5440,aaa3a92e) -,S(948a0ddb,4ba838a4,63eee339,5c7bcca2,96fba8e3,9654ff33,55c9296c,9e6e8c64,c5b34c25,da19d83e,b67b69b5,2e527d61,c7b705ed,2f794d2e,12c4325c,3cf5c1d8) -,S(4332d02c,1332b03f,b7a46b47,e82617b2,a437fcc,694868c4,256aa40f,a8a3de2e,e6e5196f,5f9c555d,a94327c0,39411780,393985ab,73765de1,e1bbe0dd,8aaa5289) -,S(5dc977b9,2ac1c895,f3150b68,a8d69f5a,f7e12dc5,6b211d96,a67cc3fb,722a5aa3,45888ca7,4bf1ec9e,1cbd2912,3cc696d2,83260c34,3410217d,10fd0b95,9d07844d) -,S(5b9cf534,ca94f124,a9b0cb6d,f0003924,605e3bd7,d063a2b0,c6e1a81e,3fd15764,44e98dc3,b0516ffe,bda48790,fa0b2d67,f9ba4b48,ce88bd1d,d81bcbc,897458) -,S(84353007,3a63714c,7d26baf9,c895e2de,e2feb4b0,9746ca66,97fd7ff6,d5372f59,d7373a9e,37689d44,4cb7361c,f2f3452,3f9fea7c,826c62d2,3ca3f368,b0c7a175) -,S(9cf0000e,3eef9b5c,89c8485f,c3826e78,8f1a28df,f8746619,804030fa,c21e6a61,2b3dab3a,d8684b2d,94e1fcb9,d2005c20,2764cd76,aa91e0a1,ac2612f7,fe91543c) -,S(bb292fdc,5897188e,20888b25,b491a757,8ee02853,83aff5e9,99671a24,4ce1235c,d3b6d9c3,50ba7863,bcb83990,95893348,d5e9b8f7,27e1a3a0,9e02f59a,412507e5) -,S(95d6d1d8,9835ed57,6a88a21a,9239b623,efd2bc6b,f27c5ced,2d770c90,fb7d680,c91535ad,39db65ce,fab4ac72,f3ce692,b39e7d38,c72ce468,e40bfe06,6cbaf048) -,S(cbe3f20f,a164ec20,9c2c3fb9,ca0c95,15ea3787,df2c8fd8,9ee50a3a,85d09a46,cd589754,faea165b,48e22280,4186e6ed,734a2251,a6588e8b,8252eff9,afb9a28) -,S(3e01dab9,9bab9e20,59b1c215,ba67835d,2942f4,487d6094,9f39e293,b39f604a,b41ddc32,33365044,ee350979,8679f3e8,d0a556f9,e8b6a267,bd5cb5e,8523d481) -,S(298974c0,5543dc96,15f1cfd2,e4b6331d,c798918e,15e3f350,97213a64,76afef7a,68018355,55f2d8be,a74e02e8,747f60b2,22354ea3,62cb657d,e5cd8060,7a99da2f) -,S(1d70674d,54763c96,ea3764b4,641d14f6,2aabdec8,a093c3df,d936793f,511fdc61,9674adac,697e44bc,6324378e,59753f42,80774101,623dc10e,8a4eb4be,38dfe632) -,S(75220107,b43ab970,6261875e,c8f8b634,73c47aaf,91ab8fba,cc0b1c4f,40fece1,29094e7c,c3bf07d0,12aebf2b,fb56efb8,41bc9ad5,9c350b7b,885602e,a3aeaffb) -,S(cfadb9ff,b3474ec3,27db31aa,b0bac83b,fc7f4c8c,9d0efdf9,2e7e7922,f779720,ffb7657f,6f7b8cc5,78f22ee0,2a99fa82,97d41806,cd2b8b06,ab00b993,d9a09b2) -,S(24ee919d,be3c5603,adee46e1,39d84aa7,34a7b4f4,d7b826f4,64ce8b6b,c1cb828f,44039756,794b547b,9360b63c,539b8f11,ca651476,ed57fe29,364a5ea6,17ff1506) -,S(5995e246,2f755256,f4d6b8f1,a5cbeec,c50ddb53,fe4391dd,1b530eff,7cb100f4,77ddda7c,7da05165,c46d7ba2,40127ff,fe78ac6b,13dd018c,e08161d6,d81dc64a) -,S(a7233471,97dd478c,e129fa20,59193c08,364f8c37,1cf19c2,9dbd51c3,234d54dd,2c4e695e,ec2b2ccb,384a5fa0,1a96664,9cfdd711,1a1d19ad,92f2eef1,31796e68) -,S(6466ab69,d5bc21cb,d7e75fcc,5de9fcc9,a57cfed6,3ad41c23,4ed56cd0,132251a5,76e7ef89,6dbb16e2,76622f5e,5f6894da,2e0c1ecf,c4af05d2,990dfa4,25294dc9) -,S(a5eccf90,a29388ab,de6fca2a,bf216145,7fab8bb5,1e33d4f1,1e0acda0,f5c28e60,afd75916,468a11f3,73e88643,56690adf,110e74e2,c81123f7,94805b26,620e3ac3) -,S(4251bac7,493678d9,f26e52a1,e3ed9e58,6a15d060,4d1c9cdf,89ed5871,ee9c2779,fa1df27d,92e6716d,76990c60,e6603bcc,4bb023c9,dff938d,3a15ad8b,72987aa5) -,S(77a9e6a2,4c3cc21,d8cf6b97,3181e283,f40c9d0,26a81903,f042c2a4,fa7db30e,a1ef4fef,23f25ccd,bddb757f,aaa10ccf,e78d9310,72b2f180,b6e3de5d,18155aa0) -,S(33fe7961,c40d4e1b,d6ade73c,4577fa2a,e9c0d20e,999f639d,e751ff7e,6fdbea6b,91b7d5cd,4eeb306c,e316e7c1,464c30cf,9a591994,7232b037,5840b8c,d5f54849) -,S(43f66b2e,5ee52211,a48a9d8c,b485be2f,39535701,5249c311,5b682170,f9179564,5370b55f,fec0ebbf,c30cf7f,e63f5f88,3555e699,728e6892,1dbf7874,2da46a45) -,S(4ad36614,97ef1074,d74c7f6b,446ea87b,ad2f0b43,73f5970e,1a745b6c,38b19bfc,8f5dc1aa,769a5bfd,5eada00d,436f850f,6f9eea82,329ebcfc,cd4cd60,ef5cfd39) -,S(9799aaef,95204d54,f3734dc9,75b797aa,59336866,9b2f12f9,155d5953,c012754d,4b6b34a3,d31fe173,43a5b476,bc492d54,44c256ec,ea236f3a,9845a875,e83e6353) -,S(c86249f0,c6e4635c,2d03f252,50e35d67,c1c22f51,6f9a8dca,fbc9d41,15d828a1,e21770b,37dc4d0d,f4d260b3,94bc76b2,46523893,469f1025,86d99467,ee95ec73) -,S(b48dfcc5,de5687ef,c7282c84,cfd4060,61a08fe6,92fb08e,3accdc2e,6656038d,87e3e1f,ec737074,71f69c7b,c7147665,c0b52a95,37ad1566,277b6d19,fce8927c) -,S(77dceb6c,62d65535,c625c828,fd3836a3,146fa4d,36732da8,58503fcd,4e357fca,d90b2600,5a139713,525b8521,3d370ed2,4304d08c,87fbb67e,9091d1ea,18228bd4) -,S(5b588cbf,4cda0184,4df1cd63,3cc70ac8,69cfb43e,332f5c17,47364750,3175e49a,1424ef1d,f9e69e4a,84eb823b,2f95fce5,a52e1978,474697c0,d47890ca,fad55cda) -,S(c087bbba,83934208,8c70251,8c9ddd93,2c50cea5,11c443b7,da107685,9320b20c,77f26a69,717555f3,b030e345,5cbe4b30,f637c23c,7ebc2b5f,6ec2207b,9209d996) -,S(8d16057b,68f8082f,208b3e7c,fc2c558c,247d7d60,f117ea38,35e474c1,3031ed94,3d305db6,62ffd13d,100f6e0d,19c439e1,6ffb8ca7,eec6b14f,ed551091,d6ba3eca) -,S(75fee0a6,3d32bc8,6dbb8cd2,af7371ff,d17daa96,5e1e19d9,242fdcc1,edc184b7,c2b1e4ff,abc30975,fe7c992f,f8091795,61ee89e,9a040409,10bfdc64,93efa2f8) -,S(65da3959,b147093d,7d092599,a87710a,dda7fb75,460e47a1,10d5c1e2,6f368abb,3599e1f5,2f92c1e1,c3f2b463,d9a30230,a6f53028,cbae3ce9,5e345c5c,21862844) -,S(6561fc10,94632125,d76b787c,a7539870,5dda1a5b,f4407f4d,f8140b6f,967933d3,4c06c7ce,a88e2828,3eae8aec,ab6e8802,cd083f37,6d3a1ad6,29fa9b55,920e6337) -,S(c9a53f80,70493701,523041a6,a9d23343,c8a3fc30,6664d6a3,5ca5e7a4,80c4410e,9af470a9,b2e30d45,ebef0dd0,6e3b2736,369d4dad,f2366d42,18344a22,b6e4bf9) -,S(5c1525f3,443e56dd,b009f45a,1b9a1540,c203f814,5f577bf0,3c734597,33b89158,967892f7,cb3ed91a,d74f4c80,3625707b,58574afa,cb99fc02,f5b3493b,eb4f4f18) -,S(3565ccda,d87c171d,714add6d,472fee0e,69bb6ea9,75f61454,d69939cb,541648ed,9f7d87bf,ec2b6358,5dbd09bb,d008b197,4f02d3a7,6a8d54ed,d486a2d9,3462aef8) -,S(4003ef34,c0f5e1a8,afcf29df,42a14a5c,4527d3dd,138b5eda,bd8de661,1d0e3614,67203152,44894cef,cc3d0a76,35839c2f,3d3ead0f,36174e2c,d3c4c682,4c3048c4) -,S(f5c4df5b,37965079,3ebb7de3,9b495a26,13886422,929393,1cf55d1d,912ea57f,b0b93c3e,12a98cc4,5a3672c7,4a3610d3,aca34da5,7d31a968,f30047e0,31eb3482) -,S(bc9f680,e21186cd,ba63533e,56580289,cbe8698e,69ced0b3,97a96793,569e213a,6adffb78,8105518d,50fb94ff,87d204dd,7bf54ef5,b91e1d72,713fa9,b32e06a3) -,S(4dce8797,f1fe8811,453e15d3,7a3e2621,549e8347,4e7046b0,55f99d2a,c9a16516,ea5e6b77,cca7825a,95cfd9f3,7d70d7b2,fc8a8aa8,749a9d43,37ce0754,abe668ea) -,S(f49b5aba,1ef29570,bd72a0c0,40009382,af2a4f85,26511eee,81869d3e,9759b16b,2e496c20,b996e8d2,696125d0,f60abc66,1d2fb343,b4181202,8658e459,d57c7f7d) -,S(26917d4a,7573e1d2,7b4ff765,72bf2948,a2d02f07,7d7d7fa0,54a1bee4,92125ec,b8e47f7e,ae9b66a0,2a6fd2d5,cf8c88c9,7eb12530,a618678,ad5ce83,7cd8f97) -,S(1b4948d6,285a2fe4,98cb71da,f213e6d8,7ead776e,cf8bbcb1,cd7faad4,fb29d290,1ab4081f,ef87d925,9b736c7a,92d28618,d5698499,b2f5e27b,dd30c1b4,24d3bfd8) -,S(14d712ec,8179baf7,9dd9676f,ea99653c,f8b20ff4,a69636c7,7258bd57,99ae64ca,2e1db8a6,424650ec,32b0df37,d72ce3f0,6f38538,53bafad6,d366e04e,380c6ef0) -,S(7675220,41747684,9e1967e1,54445913,a1111988,8b5bf813,4d9694f7,1d952453,3f1fb063,6457b603,3a155a90,6a722de4,de1a5c3d,6094dc27,37776843,ed82fd31) -,S(5ac8e534,a8828b67,40016d02,80bb1e26,a53b16f,96b24937,fc84ba34,dd49fc63,193d020f,68f5fb7b,2c5a429,6909ce70,18568f87,115e987a,8e5e206e,b8a1fc73) -,S(87cddeb2,8d16562a,531135b6,193449e,d618d0dd,6acf6c43,3372202d,ab4a14b8,5c1de4e6,7c958ad9,9411cecb,de2e9129,cd709425,135c84b,e5b68cba,9f846e2e) -,S(c431ca25,a39ed09f,48e1dfe7,afa86630,4d4f8b7e,eb0d6d52,f8c778a0,424c84cb,450607d6,5b2dbe6d,35cf2d11,d3129330,489eded6,e35ff429,2aeae0a6,7100d825) -,S(8c5021e8,985c1a11,4bfaf3d4,40edc4a3,aaa93002,5c2f2c1d,9bff3683,88a3dd5a,4cb960aa,8077d81c,71d74ba,6096fd4a,b6d31fae,d4315db1,3c2b60aa,a12fb108) -,S(338e54bb,38a47485,8c17c07a,177dbbf,6e7a14b,26781bb7,70b9d717,6e513d4f,7876ae4e,84cacfa4,c22951de,f67763ba,c44a6ad5,52ee66fb,92f80cf8,c4420548) -,S(87f3bca9,efbb3a21,917683ab,ccd268ad,3c7b0fe1,7eff461b,cb06ee8d,2f1f3c5a,a7a1d2a1,ecccfc54,4881f258,bf5fbbc8,e5cc11f1,a117c7f8,361a33ed,55229b61) -,S(f4023df,8ed85856,8e56a037,5a6a78d8,de27d6dc,467c9aad,52407bbb,413a3e40,b2499142,fc4e3a11,6aa30e56,6d59f373,d5e2c545,3e274161,5cff9f6a,1fe178cc) -,S(cfb51fc6,d55a8a22,89d3d282,fe63b2fb,453b512f,374e01a8,92708564,9c6f2d3a,8d4a3223,283811ed,28ec120e,761e61d3,e4ea5312,1cb2525e,b567fe9c,9070635d) -,S(59a44a0b,97050147,bf219db,22249635,c45f77b1,1721c486,8937ce96,ae43c539,31e1ca6,6a910f3f,1de1d0cd,55eb8a76,400ff959,13774efd,158d931e,7039afa) -,S(b99cee56,ec277a37,6ab44628,14bb3a8e,d8e26d73,19fd786f,8ab570e8,28a8ee7e,46e0f398,dda05d4d,7253b16a,b4d80c14,b6be5d31,d1dce230,62ab1135,c23494ad) -,S(a39e136a,d96b1a22,6d039872,5da75b38,1c6b922b,52947cb0,25207ad0,d172bd2,7a5c0758,74de08e,3d10fa71,79639fa8,7dbfc977,8af1a3a2,d910a1b9,b6abb532) -,S(6e8b4125,3b2eb74e,626dd59a,eb7512b7,2c23c855,35f479c4,5b48d974,57001976,cc0b88e1,e4e8c045,5e804068,acb85aa2,715bc82,ec21ab47,873999e8,cd2bc88e) -,S(9942b6f5,681e4189,f7fb6ec9,8efd1343,cd1fb66f,1c98e418,9c44478a,51abb019,200d0ebb,b0cc2d52,90a11e6f,f7c989e2,d2fe986b,ed266430,56951679,8d0e7a9a) -,S(7fdce1ec,3c57b949,44166918,b48af352,759636f7,2eafd744,642e0f7e,5078506d,d7785aef,c19a76e3,73b786ed,1e2d2ce7,53cfb979,65d3d46b,2e313a2a,d7baabd2) -,S(6f13205c,958c83f0,f170906b,d77c79ab,5f51654d,88195b04,a70d4e06,93989c57,8ac9a15b,b386e483,b268d4f1,c950da35,33deb99,55116c99,e848f13f,73b55ee0) -,S(f955a35d,833c69be,40a0665,f4dffbfb,cd405f4f,5b4247e6,e50cd4b6,3697654e,89f4fbce,22468389,a4af2407,f40eb37c,f56e80b2,7da1983e,4e2fa4f5,8bc9ee44) -,S(dbcd152d,619646a3,42a25743,1df9798d,b58b8d1,89238132,e65fb6a8,26248007,66fa717e,c1948fd3,e4425e9e,2e6830f7,e57d23e3,d0219dce,c02b4d36,32d8ba13) -,S(f1aebce8,e57b909f,ac7cfb1d,a2e7953f,99f713b2,8b35b5cc,71eea153,5e6e8ebe,8755fa14,3e77e5aa,60dc24d0,92e4f596,88b0bfd9,585fd57e,1b7f610b,e5d9d516) -,S(a202164d,941f84bf,f89ceab6,50430905,c002bc5a,91d505f5,fef6e48a,4b55187,e0cd42b,2bc268b5,1e572e97,8b9bce4d,b6d4b095,ade884c1,bee3b3ef,c2f057ff) -,S(572e1657,46fde7de,9480eccb,287f8b9a,b1344da5,8026861,e784047d,ca8ad68a,c174ade7,c066abb4,8d2461eb,405dad76,39eda86b,a0fd170,47569617,31eb5d9f) -,S(f4e2c907,fee4d753,c08b1052,b76e49e8,b67047ca,59e64dac,58acce9a,5beba31d,b243aa2d,3a92d2d8,e48b8317,ca8fe897,2b76d134,248070f8,f41bf871,2c11c42c) -,S(a6fc6aec,84455716,f5e9e436,d68809b2,26698781,f24d0463,e06963a5,fdf06dd5,dc16a615,548efd18,6ae135fd,f748d9f0,a96b7f4e,918513d5,73900aa,1818ca8d) -,S(bd806817,5fde9652,9ccd8eec,937f2cbc,c4ffb3ce,b04cc9bc,c00cde2d,5a05f026,b2791ae7,8e014328,e0fe6a0d,8b6bddc6,db048274,5152bf76,bce228b3,64a26216) -,S(f888a667,6f8c3d20,b9d5e810,ecae6b8f,2d8614b2,3a5da51e,16386dd3,5c0165ef,fb4ee20f,e429f3ef,f6f4bfe3,9c7b1ebb,57978853,de242239,42a3dadc,909a0dea) -,S(7c8d1e05,5adbaa71,ec9023a4,8d160fcd,c3182ee6,bda76fd2,3ba8877c,409ae200,8a3b820b,ec595523,d96936f4,fce83779,c489b9a4,f2c8c524,f16e1764,2f907ceb) -,S(18886ea4,ee257120,610ccd71,593baf72,6dfd9bb7,5229959e,75c14e76,26fabf43,266c6695,f57068b0,d33ad3f,7d02b7a,898a3184,39889d31,ffa98d86,e091531d) -,S(fea70f1e,38c8adbd,3339a44e,cac036b9,1242a099,506789a3,184fdcfa,6be52cba,9dff6df5,ba8c1b9,ddc58093,a36670b6,76c0e2f,d745c468,83e26ece,3b9e7915) -,S(4de30389,45aa3c90,76d99142,e79451b8,96dcbf7b,fe420c8f,b1dc4b4a,37d1365a,cee74e9e,9093de64,2401eb2e,201b3377,992ac0a2,13b0b16d,35664ed8,d287cba4) -,S(67d09dd1,eafebe79,c63b8c40,1c102982,8c2d8e6b,6b5bfda3,73988830,1a104fb2,10eb5508,92660d96,8e99049e,818f89bc,d4f03558,d9f2c984,61ffaa5b,bd360a5f) -,S(2b5d70fe,186834f8,d3b96d4d,87031cd5,325e55f4,ffa31b5a,f5ffdd77,40e6010f,646e7e53,24d2a373,78b1f54a,fb2081b4,38439890,c9f53b1f,7bda4d47,a895ed02) -,S(cb426299,8700a76c,193f7b44,6aed0ad0,5d600b23,ca24c752,527f62df,e17be248,92843e13,f3eb60c9,e5f74eb,8cce7723,bcfd0250,4c2186e6,5ace939e,5819a8b6) -,S(3ee6ab7e,75b3bc57,135ce4d0,1e6de88b,22d0b853,fd8e0d25,f9b04ded,418e4e41,69c83f98,4e52519b,931b6afc,933f5200,6ee1ab4f,680ee768,9ad55368,1b4bcc87) -,S(583774b0,a95a5143,17232df6,f17d7829,6918acc7,2a385724,e904085f,c887e7be,33bb1e66,ee8cf17,30c16073,665c353,f8f047fe,150b4424,18c736aa,807c3e7b) -,S(af32e1ef,39822787,79082b77,2a643ea3,eb334100,9a7a3fcb,a8838e0,7079dc1a,6985e28d,c660123e,73aee7e8,b1a36697,16938331,e4b4b7f8,b3a9ecb7,4e95fd4c) -,S(6edf7fdd,32667551,9b60c740,efbfc3f5,50f7249c,deabbf9c,948adc16,e034d0c4,f08c5f18,5def7da7,5fb0de81,9b092691,64534f14,bb7d96d4,bb4513d,ef46026) -,S(3b9a6645,5d268f94,6c504120,a81821e0,86257a60,b3fd9f00,72a0a4f0,1f16b42,ed583a15,aedf6c08,95f60109,6190106,3dfa4848,645b0117,e2e1bddd,2cfe7c7b) -,S(bd035b08,2b5cfdb0,d17cbdf0,7a012b0f,27b52943,82e8bae2,d683ad0a,747a1039,6494cbad,ed4ad7e8,aa135ccd,572be8ac,e94a23c3,8b62bf61,ac90f9a3,9bb2ef54) -,S(e25fbf19,fe9b180b,ae3316ef,89e0382,4dda59b1,41022ff7,a8c45b44,f15338c3,45ec47f6,58a3dd52,34241258,1852e694,7c2c8f11,9f4fbbe6,f6388363,174c7cf2) -,S(2e231dcd,8ffd7356,52ebea7,50165405,f30f595c,3871ee6c,7c072e64,ecffc9b8,c664452,db15961a,8458f3d3,ea24ade2,7610d4cb,ee51927d,29cf3164,6f59317a) -,S(7c0f29c9,3932626f,1b1ae126,316e065,fd2a4174,a66a6048,3b458660,f5338fc8,27ef533d,df6f1272,c0255d7a,587f56a9,b76e2c4f,98c98162,350233ba,75cd037f) -,S(e702d61c,ea6f9fef,fb43e014,4794fb32,7bd857e1,70b299ba,31bb6a20,7cd5bb48,c4779881,c924ee3e,7f228a71,2de07794,ee5e28af,ca63af21,12ec0eb3,1a3f79c9) -,S(f1780044,eadec1b5,bee75c11,7c1647ed,c362c5a4,35a66d8,cc2ae45f,66c852a8,5f8de9f0,f31b3977,f08f63ac,1380310d,e8b7a304,85c9f0f8,9a677572,329e1c18) -,S(7a41b37f,22ec5b18,d4952c53,326665a5,1582ccb7,1660b69f,8d00701f,1f12dd9e,8440be13,2c57259c,80cd74d,2a2f1e01,3448865e,2429c2b9,db750951,607fc443) -,S(94fff7d,8111d69e,198f4e16,57c3551a,a5ce6316,d520a779,ca4ccd0b,282db6d3,482c9270,26c0c05,578a75d3,8b1d8ed7,42541d30,3a933b90,9c3249bc,505c6fc0) -,S(d6a6d44e,8a3ffaa9,56cac76b,1b05a4a9,d3775989,2f70e560,a54c9440,17f4e9d1,48c3bb22,cd839de9,9163bbe7,83a8a057,c7b93e87,de388b6c,dc57ba57,90863e1a) -,S(cc0e25c0,8e24edab,1e5dbc47,71543b92,c47c0993,95b93d53,699204f9,50cdf80c,20c52cb3,7170cf3b,43b76ab2,cb4a6d3b,1a977c55,2431b8c8,220282bd,51fb70b) -,S(cf953f68,4cb7d1af,a125d0ea,cfb83cb5,efddb6a4,41079be3,db72573b,62f8d827,70cfe366,a45d11b1,a847a7b,8e3e50a3,b302fa50,1afc89ac,b89eddb,30909c0c) -,S(1ac22694,2b34ab06,ff16b711,2fd5fe1e,f8ce6975,143ab19f,bff99d6b,6815d5dc,a43d457e,2bd0975,4e9b7fdd,d9e16681,1bd823d2,24476615,4d9e3fa5,ab6539fc) -,S(d02bbbff,1153804a,f0f800bc,f959406c,496349fd,a412e9e9,bb9f7232,7a4d65c2,5de80de,3c7832f7,1d744f9b,9ef08b56,d41e682,1c20f2f2,876fffc1,b802a384) -,S(3ccad347,8d464ee3,42e1cc2b,2c4b299e,d8a60326,4837a040,25a8525b,4f1831a7,35ea2a4c,a59b55b6,ac79fdd,6ceb3401,47492f3e,49b5035a,f3036b26,d02691c0) -,S(eac4d554,3e69c3ce,d762e90,fff84b3d,b3a758b3,419d06b,80f7ba43,36033688,aa64fada,c54374bb,fe8449aa,ddaa1846,ee00fb6d,c9435dbf,17f6a12f,d1deacbe) -,S(3d2879b1,73d93713,3326d0c6,133be281,5df62465,d3dbb7a9,a028e0cc,63fca753,576ce64d,9b95b5e8,a9e3eecb,34cdb8d1,fd38a08c,2a6a8c9d,8f0a7296,68d6e0f0) -,S(3f58ab8d,56a9682e,25137087,ca8c766a,72358a56,99ebbce4,cf74e304,6976ca14,3c9053d1,1a2a8a8,1f30f45f,1b480dad,f6bce20a,15e6315,447405a7,b321f29d) -,S(4f5f1289,b48dcd19,41a9df0f,a8aeae42,2a4ed913,58845b97,3145ddb1,13fd12d7,b5c3e32c,c40c6577,3e286ed,a233ddf,42ac0d6a,5a3c3e86,77f8256,e0dc1428) -,S(a64a29e2,a52dc6fa,e74e70dd,da2bacd7,e4a9dcdf,f9a0bbc5,ad0392dc,93376a76,ade2f8a6,faa9b1b7,7baefe87,33ddc365,c776f2cc,b0e5730b,4ebb0166,418a9590) -,S(dee0aa12,c4d6f88a,d1d86f94,e1c6d3e0,b8694b5d,e234af04,994cc7db,c8480e70,cbd9acd4,cbda37cf,a9d368df,332d30d6,413ae1c8,d34219,3d4651f8,62f93389) -,S(8677a99d,c8af6ae1,b653e294,80eb66fd,772b958c,882fdf74,f9c0f188,d5796936,31c668c8,348c048e,4b7a24f3,a0861f44,6621151d,4dc3e9ed,783eaf81,ff97232e) -,S(51117d3a,cb73a7cc,2b229bc7,9bd6d676,f44aedc1,98cedd80,ed6178c1,f6997fee,5c638c04,123f85c1,170651d3,96343e,78f20770,321c1a4d,174e568c,39110cd6) -,S(48d8af64,69670828,e87585d4,52ea1242,a83c9f8,3423e468,9c3ca383,9f141b12,558a8f42,f07f49a7,c6a9843b,9055ed05,1998dd35,9406c40f,dc4d64e3,5265e9de) -,S(62ba9ac1,b0fdeee5,a143d457,41c164e9,d4060c7d,f5bbb17a,ecbe80f5,f6966d2c,65a0653f,2290416c,5fc96494,b70b3b99,9329fe67,3b034aed,b586c118,a5d9450e) -,S(be4df7cb,679da56b,50ef2058,3c79310,508d8d05,43f3004a,486297d2,49febf0d,c1b56550,dd5f3e7f,a898cb8b,aca88694,ca697306,fa3fa09,95f6c43c,d5f3ba9b) -,S(e49c036c,cca2e068,5acdf34,8473316,424eac2c,ce1550c3,a0c435b0,28c9979d,456bc25f,457fde5,5bd0d273,d27afd7d,21186b1e,3b42bbca,b168992e,61609a1b) -,S(ae6845ed,a81d5d90,b3fddfc9,cb774c2a,976e701a,ad5c1302,7057a6f8,97fd58e3,529bdc55,322ae360,9926194e,7539a534,4501126c,e69b3e11,e5b4a675,7ed755bc) -,S(52a1d8f8,bcc2b772,cc8717e0,2d713864,4c274499,4a19ed18,3fbeae31,bea25e1b,da2a0b2c,e7f17894,848e77f9,53b7528b,dbb80673,c70341dc,9f869e60,4189011b) -,S(ffbbaf01,d89a7804,d5d19f50,dd5a4abd,cc5529c,90d26918,425f3805,96a2250a,88b5f7b7,eba662bd,5aa47a6,c2fe1322,2d514410,f6b1a145,38c37ed9,9a9880e2) -,S(6ffa438,aab51ab7,afb840ee,d4f85725,4473fbc8,ff6051f9,fe5a59e0,ff8c942e,5b0226dd,3b88a040,33860dc6,69613bcb,50a0e95a,2ac7df8e,66884c7e,e602d775) -,S(9c895658,f92ac47e,318f5ee5,91d26a10,c2c1b77a,c8bc8cb5,a45ec943,8a2fc79,708071e2,665ebd58,f1655e28,6de258ec,ef4b0115,ff74f38e,516acfa9,c01045f9) -,S(532e6e0d,efba35b1,3fdbffd1,8ebece3c,a59bb3ce,54fbbb5,df1df6f0,c1861ba9,1af465da,d326bbc3,eb732ed2,464b4593,36f04b0f,a50ba7ff,f61b4754,aebc5b8a) -,S(99043321,e3f27092,cdadd8e,b50cb4a3,8a8a9f80,83da6ea1,38d48e00,e5fff425,11be8597,325c250f,d9e5b1be,8e52c336,404ecb24,df29b786,ef9d1f04,8f77ea6f) -,S(96799080,3a0934a9,9a0a6e94,120c22bd,7d79085c,c331e172,87daf46e,7c4084f9,ea90012d,18450bfe,6a520b5c,9b2812ee,574903aa,d75cad04,7dc46c23,98005e03) -,S(74f5d157,915ffe10,cf6d9981,9eff7616,1f36f71b,4fc386ab,729dac37,3aa0afb9,54a0011e,4922bc74,12ae225c,dcc8c447,4e4ce4a4,941a409a,2c49d421,19b29eb5) -,S(12692753,81c63955,5700ddeb,e8d7a751,76e5f3d7,2aa0631e,3e7cd6a8,c1927855,b92e5076,811002d5,44c554fa,1e1d10b5,3eefeffd,513357b7,2c5e0cc1,c39ae553) -,S(84ef81b,1d143d73,5b6ae35,af18d810,d7cdcfbc,dd1c68e1,1aae007b,80230d9f,cae39a2b,a5b4ce8c,21ebcf2c,638a2e5a,b0dda645,aa6e01bb,33ca2edc,b575d42a) -,S(1c22ada3,326e6ac7,6647af5e,ed62a85,c8d89dd2,a733ea62,dd71512d,ec9037ad,f5a598c6,1562a6af,99e46283,cb9e6fd4,bc4142dc,99600b64,49304981,16aab458) -,S(6b91ca4f,f08eabd5,aa8dd35f,e9e04153,c00f1f48,50bbff4e,73671cc1,fa4aff1b,c6cdaada,85adf99d,4fb68c8b,6104f585,b3c9551a,7dd87977,8cb250fe,11b31852) -,S(57bb4999,6d2e2157,613f0321,983736e4,b99063b5,e8f7188e,23f7895c,edf85bc2,93b46dc6,72eea90e,9274b9b2,73a82da,d0a1ad14,55b550e,94fdb765,ab47cc3a) -,S(75790b27,ebf7566e,1056d9f2,463df8f0,67c38a2,78af81cc,b40f5260,4a33ba6e,ca0c8ca3,d99b0a5d,b065decf,346eadd4,3af8dc71,9ae06dac,6be99c5c,b89d2045) -,S(ca7a75ad,a90b590b,f7f2b6fd,e3004a1e,8dd7b4f4,db8c4a08,f32bcbb5,474ebe9,b3278d9c,5c9351e7,bf4e8a08,e0f1dc00,51273259,acdcba1e,fd3ded69,83fc69e3) -,S(a6dc68b9,3bf46294,392a8d6c,e52bb365,47b65a5a,f318765c,7a4f5d5,2f90b2d1,41ba6d67,fc575561,a0f3c76a,931dc62,37f53348,819224de,8f925c33,c90ad45b) -,S(da2139f3,f8afc90a,c7f5a025,20c36110,2fafed4c,3f525b56,fe0dae1f,6bb6bba5,95adcb88,fa9ed816,dc097522,de5a394e,71e92c1d,f5bac36,9ad06067,1b6349db) -,S(a32b2475,2f0e0063,acb4194b,faba9ccb,2159357b,23f102cd,f5a8e24f,413da4de,57df4143,bd8b27fc,c7716ffd,8c35036f,e09f8ab8,34f053db,ddfd3161,ebe576cc) -,S(aaea491d,33824ff3,c7319d8b,a233c73a,741718f2,2c921392,b893894c,ade9bedc,c8fb291,84d8dc65,93a6a3a1,a5aed86d,a7ad0d32,d5f8ef4e,b24b6154,4c1a63a7) -,S(2935e0e2,7a8409bd,224f3eb3,d68fb639,ccf75d5c,2b0315e7,ed388acd,887f2c75,c4ff024,62c9ae40,983d0068,180d4c3,977e900d,fdfc164,c89a938,c568aad4) -,S(7fca8076,9e2e7253,5834259a,abeafecb,fdebbd96,5066181,63d244ce,770fe577,a3ddc3ab,f04ded22,cac3b8f6,ffd14ffb,69cfecba,7dbaeed9,9a5e13cd,55bc3542) -,S(c5b5f1c6,1caa4a7,fa5e665f,57b45134,bc129ec7,131642a9,6a7b4191,5e8b483e,26cb3816,da5098cd,a3f58fd0,c26011e9,73dabb66,d8cc9257,6d37bfbb,9cb538e4) -,S(410da274,df436772,64decf4b,f790035b,d7d5b174,cffdb4f4,56bfb6a0,79a50d88,71c81968,188eb349,6dc2ef1e,841979fa,254a1939,5bbf00f8,8e1d2bbe,ef9a6abf) -,S(3d9928ca,334dc800,abb6c5a2,43a2681b,6f7976ac,50abf387,54058d05,cf67769a,cfcc01dc,766127b5,3e183cdd,80a0a1e4,62bf01ab,c4df115b,2e4f4e9f,95d2beb7) -,S(65a8f57b,c523e4a6,4777ce31,2000a322,d858eae1,f39fc919,2e4f436c,c8040cec,820698b9,9e953745,b1ff7b0e,a22bff63,c9df69fc,c2055b32,3f07fdc0,61192432) -,S(84e553cc,baa606c2,ffd3ef5c,a62725a4,55f4e539,24a72153,1ac3e66a,5d92fb79,34d6af32,4aaa9465,fd9f7731,1c01221d,4c0b5f75,1902dd67,4dcfd0f3,9cc5f8d2) -,S(3b4a7558,28851226,f391578d,5d146da8,dda3d4b4,f79a36ac,5f8c166a,773783,e37c96fc,4de83cc2,eb4b3cc1,44d4d35a,1a4249bc,4cd7c787,7d0084c1,b1a59e53) -,S(6dbbd12c,6164e8d,ea489819,37fcd12e,74339578,6482ddb8,9226d9ef,50cee6b0,89e48f49,b3f5d154,52e47c17,e1a68ace,eed3bc6,8002a70,33316116,ade02b90) -,S(b64180db,3b926481,74a0b743,1f84af72,f1118e9d,6cc1fe02,f0bfb72a,97c441f6,b394f997,83d00816,267a4f0f,8c95a05c,33cc19db,eac704d9,9e1f0c2c,4fb25fd2) -,S(2173f38c,f47377c6,d977fc08,ebb67f29,37e96fbe,e46b2115,b260f03a,216b5c56,bda02a78,3c4a684,fd88c6df,6becf56,3bd1c61a,4e79d36f,27e22fb3,212e2abf) -,S(9dd9ecd3,f3732f0d,864df0b4,8cf35e06,ea2b89a6,a8a2756a,222e266d,fc5c5214,e42ea720,2ba68242,ed9256a,57db94ad,dcf00b1a,50ded06f,a70d712e,17e921fe) -,S(705f9fed,5cebb62e,dd549526,af729092,9d398232,604d136b,2a121cf,e7af71a9,bb2cb17d,aa4472eb,12e69a4a,57a7863c,2b32c100,a1601d2c,44d2cc29,750d30a8) -,S(f1a908d1,807169bd,7fb7fcd8,cfc125e3,3fbcdaa2,8d8df1a2,17b84c2b,2cef4410,e86cc08,804c6c56,f81cfa75,9851e67a,d792bbe4,87812cc1,4e7aa468,b8911512) -,S(db0c5d79,35693c81,c752a475,6852260c,5625e434,5247cd5f,d40cdc24,e1355f57,120c5ea9,fb00d295,37721f1e,2539ebe5,d0de9bd5,354ce629,fe8c2e8d,c683daea) -,S(5e4d5935,56007e92,1b158f68,3411da86,e979d470,7b53caf5,9a2ed94b,ca423ec6,71588b00,1a0e9ed3,27862fb3,7ce6aefd,c309b5a0,928766dc,b947773e,6272d935) -,S(1a79ee08,3c46e5f8,8e97fd11,22410164,a264d106,7ecfabcd,4872af40,4fec7f28,f928dbfc,49bf7553,356289f,18a5c8fe,54f94bd4,d9406aac,c4df7a32,32349111) -,S(e693f88b,e3be0c46,cb40a2d7,f3a0a435,1c3a1812,4abdf46e,86ca3af3,6cac5468,55f0b7bd,24ab2a2b,aef2db89,d8aec5af,fb4f354d,66538efb,78f094a6,dd649cc4) -,S(6d15e8b1,f3c73c76,f73b12d4,f5e96e28,43bb6157,5d0d7e58,1bcc551a,329ca25e,f21f3ee1,84386427,32a0d05e,419f8a59,173f8cbe,6e3b765d,b74c3588,2d7f069d) -,S(48b8f127,b2614af4,95303f2c,f6593d16,20dd98e4,ff536dc4,8a5aaade,3bddb682,8ed1b9ba,ec137c62,5127e23b,55d786d6,a50d191d,6803ae99,c7ce57ec,2f546e3f) -,S(2ec32631,ee1e4510,94719f29,1a32e0a0,8c29fca4,8ff7e3d4,170a7c0f,5aeb3028,eb861d9f,e21b536e,58d0ee35,9d07d09a,491572f8,13eaac91,6105785c,697aa945) -,S(f7960ecb,3b35d4d4,5ed2c13f,b55cc944,7ab72f66,ea1857b6,776b8ca0,afafce3a,90245cf8,d40f6b40,a7140334,da02eea7,d8f7cf7f,8f87c510,cd6d9ae7,8410f08a) -,S(a94ccc3e,4b22f7e6,ef385780,d58f3aa1,139b29b8,c7dcb5af,7a247125,ba613ef2,ef7050fa,dd6afa0d,a89ba357,cbc6a66e,782471cb,8cfa4c45,e94d445d,a2845409) -,S(e48a7ff8,6d80f430,d3d6f57,6c56f026,8c42b3ed,17086399,56d62f54,f5485c38,b1695229,b4997b0b,229e3c65,c7ffb42b,e429b702,47b98231,a7bd9c5a,5e9a6255) -,S(df99488c,7d46c83a,cda5b422,b2a633d6,cccb09bb,f6488d9e,ac79e9bb,7f22d2ae,89490280,a958f45c,4501a878,5bd3c72b,aaf83a45,d91a38c3,e0477562,f345fd4b) -,S(a150c6c0,4db9f9f4,6f64368e,bba348ef,2bb4e43e,29b27770,553ef41a,ef22fd84,61dfaa74,e1525a0e,c3922ab0,20e3ed1c,e7b5397e,b4485cca,e1f64f29,19c5c201) -,S(9b7dedfa,452ec6f9,1d7aa167,bc984a28,937392ff,d856a4e1,204aa541,f3aa0edd,a37f4912,2f5168de,bca0ef6e,7c9b31ab,b4262c09,ccadbe79,10a4a844,ffd2c74a) -,S(c7d77a51,6d0cea71,b20f75c5,579a5906,ad1aa83c,f9209a23,d38ed358,28e51904,399a7c7d,9e1a3660,37b0a7a1,49b0dae9,8e5a288,cb5ece7f,56de4d8d,74a44bd6) -,S(d313a829,8e4de5b9,a166c2b0,f73d9812,fc1d1dec,b3b86e8d,8062794b,42fe73fd,6524463a,7eb26e2f,34f062c5,dbbdb4db,b8514c9c,60af6a16,fc9a8830,1f708fe4) -,S(4bbf363b,4d66c693,6469b8e,83c4f18e,2e6c2a3c,498f38b9,787607fe,97211e5f,9e42ca4b,243872c5,8c7b6406,11817743,82bb0d59,c0de2562,9f26e8c0,7d1c60c3) -,S(3be10ed,23a0ce86,d4a7ef1d,a667cf19,d471bd37,7467403e,3f84535f,861e9cf2,bb959378,cb317c0,6534748a,49bb9fa8,edfd2090,cb95cead,a7b0433,4066d885) -,S(fcd1f880,d723963c,829074ec,8d29eec4,946da198,cba5d96,b169cdb3,5dca2076,9489bce3,a31362e1,c4cec275,5fa5fc86,d3b105ae,25bed346,7c0919d3,b2a87b01) -,S(b5fb358,993d3662,b2e7114c,d8ea0681,f39f42a8,52cd217c,f0ec0271,fab317c4,89d88eb8,ee622cbc,f0dbfa82,8b04ac27,80a653c5,14df734a,791b3bbb,f3a71b43) -,S(a86bbad1,7fca460a,4740f39b,d2ccab3f,30fc137f,604e77c9,55624815,8fe274e7,c26dc259,ba969ac7,8d294742,e4962c07,1394ede1,263f5a0b,d03b7a29,30753fb) -,S(ed321f6,348cbc96,7e34bc7b,a935d129,9dd3fc94,c27d1467,88792180,1330d29a,b4078360,832b5de1,c77b44d6,cf07bdc8,fc5ac402,15002135,1be0d251,a3f7c3b5) -,S(c8179275,e4ddb936,f55e827e,de094c4a,2c425b8f,701fc979,96ed7194,1ad17dea,d99f1c5b,e241d165,eb49b0b9,266486af,8ce5e963,c52b2622,e16fe99d,d82553a7) -,S(6f08f13f,23b9b383,49274328,3f8dfcfd,eeaf82e,1d91e512,df1d0d7d,de84985b,96b6a829,f99f433a,6ee58ed0,50370ac5,665d61e,22cc7a76,a4a3fe08,d8bd602e) -,S(9443a7e3,410f9d4f,ef9f8b60,9eac3e5f,e6ab5d6c,a11855e4,b35c7e67,9f8f9d5a,d8c507b5,78188c3f,31bc93e6,d07abc22,ac9b2add,5a11db53,8fa0f936,3beded57) -,S(432ea8ca,3ed53681,ad3afcfa,570056ed,d38c8848,de293d2,e37703f5,133c502b,9e19228b,70b52bb0,8e66a49,826c6a61,965dddc,64270118,faa3389b,6bedff71) -,S(1d17589a,42f82fd8,c5a584a3,d3c7fed8,5e22ffea,e2b732c1,30f903fe,1982403b,9f7bcfb4,8f18d208,26564ed0,245f0c6b,511e965f,be5e0e94,54e0f552,78c39ceb) -,S(743399b5,cd84846f,65e778ea,790412ce,1ab8c6ff,ff7c098b,55436a1f,e18e6b2d,dc6cc81a,82801be4,e6566d3f,c01b6fd1,e84ff49c,e5ccf145,fb1f49b2,d8b784bc) -,S(e4378558,3b2848c1,62e3e80e,3b5f9242,5330d232,e05f871f,a279a0da,7910b2a7,c39b4171,aa4978e4,7d3f99f,8179a189,d5e2421b,d076d1f0,80cdacf0,55624b68) -,S(eef768a3,1b1639a8,f1755ac7,d00a6463,8f8a99ce,f5f42a10,664026b3,6718d63e,2a9005f4,cbf4e686,1af0043a,fe97b065,878efcb8,8be29ef5,ee648473,1e24a991) -,S(15db4687,2504612c,f40dce1b,d601d848,fc2afa9f,b2de929a,1800caa1,bfc91fe9,a8b6e64e,7d508d9a,504678a9,d90b82ca,1e72360b,95a2f515,f17710cc,4e7eded8) -,S(ad45facf,2529a84b,9d28d2a0,456a1fd9,d2b3303e,fc78e2a0,c7757bad,d4a4191,1a78e571,473f3035,16ef5867,8f77d5ad,bf8d8109,60f9925a,a6b4a88d,3654f069) -,S(41a03744,6e027b4c,eb775050,a892bac2,1c19b66d,5fa4bd89,58c949b5,b9151824,ed7c44dd,fa96d38f,a721cb2e,60e07a84,27c53acd,6435ce74,bb45437d,95140317) -,S(2020b869,58f4c7ff,2cf64589,f1043d,5a70d5d6,dac0740,56011f1d,27217ae0,111959e2,2757f431,a1994617,124eb1c6,b37f5961,29d52aa0,490b94f7,e1c4e9e0) -,S(2f99a946,859f74a9,50f3bf27,d85a169e,99c5f755,71000180,283383a9,eabd4ba1,3e622182,d3caeaa2,47a4ed24,6e608592,36ecba9d,4e8d79fa,12854f74,df89fc53) -,S(ddcf3989,57f65390,167688c,2e227f29,e7c5675,d4a83a3c,177ebdd1,9e369baa,a700c63f,3fa6833a,239a3cee,a90dd021,c3c3428c,f2b11b87,3da1dc01,2f4b2431) -,S(9863a7b8,4252360,19e2fa9e,9319c5b,92df1eaa,c0b7917b,73bd1042,191ace4f,49a499a9,281dab21,4bf09f8c,724a30ea,3a1fa7ae,4f1b2b6a,3bf63562,e03b69e6) -,S(6c5465f9,ea2c5917,34f3734a,64b8e92e,19cb4def,3c6d5d2e,467a8f58,dd733886,57e22bb,179df35d,15aa2616,a319ab3f,768f655f,a1c07c8d,3dafc443,1e0e733c) -,S(ab375513,360b3beb,d0ca387,fb0a0690,25acb654,fe703a53,d979f14,50f3fcdd,3e9c1149,309a2de5,9b7842f4,3c37a6ed,57f0f776,503ee7c5,46445c2f,6c41be4a) -,S(6acbe3ea,4a72eeb0,b23aee37,905b22d0,ff0878a9,e9143111,4821207a,4c2603d2,1ecefcbe,9f934d96,a163dad7,6c9e6806,ac2ca23c,e495a533,aecb19d,df0d32b9) -,S(7955d144,58fd0c42,5e4ac9f9,c766e253,b4ddd105,7f1c8c3,653f95cf,3a955d89,8fa9c5f7,304387f0,94a89225,53a20287,40c6723b,d25245,84735024,9650aaca) -,S(b5972d0c,90433f,702b25a2,27bd3da2,d488ebbf,e5782132,28c20cd8,35ace377,235470bf,7fbc3de5,279ef70e,d174b2fc,e3e78f84,5c0bf212,cf3d64cb,42b008fa) -,S(a266a810,33a5fa68,a204f3bc,53cc79f2,cc500d7e,4495f8e4,d9cb48bd,4bcf886,31a8b1a1,958d15b7,664390e6,a46f3e37,d52b7824,5b0b91ec,b568b7bd,f55949f8) -,S(1c6412ec,21191b63,5bbbf47e,1e9f7c21,ae7f4f3f,7de0f123,451e421d,44b9cc15,833f8a2c,1111c4f3,f5973851,d0256309,6e7fec1b,22ff969d,82a62284,c42c685a) -,S(ee3532ab,17575b57,9c19ccbe,fee04ff3,8172677c,5e625f68,a7462107,3e0b7fda,f12e10c8,b2fd987b,83dff04d,cc48ee6b,4b704b4,92b2cf53,a9af4510,6e7e8718) -,S(5ed10fbe,4867937,2ed2765a,f7f5b4bd,52ef9a4b,96515e,37944d9f,ee1a3838,8c4eb9b4,9fbe3924,ed8ac641,25dce66,a4bffd7b,5fbc68af,2a8c8633,b4080573) -,S(fe348a21,f04c85ed,69fe7345,f73420e1,b8f6b859,7082152a,15a1d535,d01378d2,d595d446,c9f5abf4,5ceabd10,3e38e423,5069473d,7d9f9911,7fa9cfd2,81f2b7b) -,S(7140369,b7b64ba0,861e1c0,b5ba3973,b573679c,c091623d,bda88745,fb2436e9,f0770350,f9799607,28c3bc21,30c6672e,40dfa362,72c50ad,1f376a54,83a12b2d) -,S(6d14c4e4,8e981e3a,e7ec6b88,b1230096,a7465db,a8381bd4,aa82157,99dad15d,25e4d2aa,a5f2d12a,a4e635f6,db58b2d5,f9c6de8f,b5bea99a,50e5b050,e7e0f841) -,S(7931b9c6,a6837d7e,3620558e,55504e88,4dffe071,5bb628d,aeadb0af,1a4383da,586caa73,320925c6,ddd12128,bf3bd38d,96b7a904,8422c2ff,9d5cfede,fbe80c0b) -,S(149e9d6a,35b83d43,5d0e1f32,a1518b88,88dca145,27aabd95,b0ecd0bd,e5cec834,45807aa0,fd84cc65,e91d49b3,8d012fb4,f87b11cc,1906e1f,cbc74c5a,ce5606f5) -,S(656b276e,b4b351a8,222f2b59,d7949010,1bf6e696,c284bff7,b809bd27,d297394,8746f309,5f8643a2,928ebfa9,a0e35893,905eb6d3,faa8e5d9,b6473281,7b763291) -,S(60f399e3,68086989,ee62370f,f7852e1f,3656a720,539880a6,9884b60a,f1eb02e,55dca05a,8347be14,85251676,d20b779f,9e5976fe,4def267d,4f1b2b6f,d444ad59) -,S(4dbda303,a67a41c,a46f417,54f9bdc1,34a305a,9018ce0d,4cadbe41,886eaa13,e062cc86,fec33458,d65f9fe6,4433b745,909a3b95,d23d7970,c22585b8,3fa48fc4) -,S(816ae1ca,4d64cd9,5a7c10c8,fd819c6b,f8c8b1c4,f495b111,d07f2a00,dd0363d1,c09f6bff,c331d6fd,56ea5520,8e9d13bb,b12187f2,d49366b,2dfd1c18,66526009) -,S(45839f9c,983fe0a7,c3b2b8fa,e5e288ad,87202944,c16d60a0,f18daf,8081b52b,f9368e07,4de74eb4,81f7beb,30835af9,aff40c6b,cda104db,2a785a6a,65dd8649) -,S(50ae4a48,3a49203b,1e04c482,ec2454f2,44b7157d,b23bcd50,63c5b6e8,d4223465,e1b8cfd7,e7bd2e1f,65f2031e,c583bda5,a619028,5c364658,36dba37e,7d5f3008) -,S(df77b231,60395089,19edde15,b21ace77,c5d8bb4b,ed26f9db,a694195f,616b72d6,8a4b75b8,9ecebfbc,b88cff82,2673665c,c99e270c,b33f3037,17dc9500,8b4344a4) -,S(ec6c0e19,978e2f18,b74419d6,70274075,6d2d238d,63b2d345,437b0b8e,f233277d,f90dab9a,2dfc4cc,62571dc1,35bfe4c6,96bd3968,173ced8a,4a363f0b,2636e553) -,S(2874416f,90e7fce6,a6d4eacb,1a722218,5af2a885,4852be4b,a4619011,617b3329,1f323675,f6ced648,8ba4c9af,7912ad7f,b8628e49,5b4da82d,448dd265,eaeb4466) -,S(872367ec,586d3a80,f8c87f3e,83b6dd3e,529de5cb,897c9d2b,e7dacf3f,70ff4247,e5bb60e0,fae0843b,788768b5,e427e009,7dc571c9,e4b62eec,eef68512,a6a3ac05) -,S(c10f2004,baffd30,ae430ce9,40c4af34,4339a0b2,13bf1f48,91b8da3e,424713cc,37be9055,f0c39b36,c546d456,b3f82edf,bf6dbf79,6343ee59,c3537fbd,8631c7ee) -,S(14e12ee1,91c83005,6bdf0f15,3353e80,733b8bb3,b93bc59d,a356dd94,70d847c5,e9707b8e,e00c1781,12b32ba7,c66d7245,d487f032,18d20da,b1550e3a,9befcfb2) -,S(dac3ba1e,2583379d,d2cdd89f,6ad053e4,3687eab4,ae804305,7b57823c,489fdf36,45e3da4d,88211519,55c20ab1,c2d1ec4e,d13a6942,fd37bfa4,7614745c,6fe2c041) -,S(d9bfc67a,5c086ae,e879fad0,b03a5a2c,a2507dbb,fdd2cb09,2644dcfe,bf800bf4,e015dd4b,5a39f5bd,1536c8b1,e93490f6,e5bb4e8e,b23e6ca4,2fc14634,2be6730) -,S(de6f3452,2f04ca0f,170d7e58,1d965982,8a9a981c,12f6cb34,761873,7996c61e,1ec16f3b,28d74fa9,43b9c251,f34e15f1,2fc6d814,ff024e3b,826054ee,f72a0cc7) -,S(432ab355,338e17ae,884a15ef,2365283e,b35c873a,4fa8cd93,f54bf828,a0e30eaf,f56066a1,a130dbf,8a3e076,720c10a5,caa9af0a,7d86ab9e,8703dcff,95447807) -,S(3d2e3507,cfa127c3,a350f546,d95431d4,8d96990d,b5beaafa,35a408d6,7f7c4d99,da60885f,4711c373,145655ca,b0f8a235,7f4a0508,2bbd2ac5,1b255593,a35f74f2) -,S(7f3f431c,b96dd4be,37c29d0a,55f3b71b,f781c7c6,191983f,4576e518,24ba87ef,f4df4345,7649d24c,2b8259f6,f7177b96,cfdb08c2,4e9161c1,695c8027,60b8bfec) -,S(4270bf59,f2c87000,44b6cdd8,b558e6ae,6f7b67d5,f128d716,3d604a7f,2f687143,358cef,2e8ff919,6865da0a,15a25524,6c4a180d,ed25174e,d08eabd,4da99315) -,S(c663722b,9930fc9c,4113af50,d51c6539,b7931cab,ebe2ebd,46f95b8c,7f603852,3443e7b3,2cdf23d8,eb532a31,3ca4b32,b94768c,78f8f13f,719708de,925ecfab) -,S(b0014864,e396ff02,cebd7b65,c66e57f9,168e8f3,95ae614f,21f8f162,c86c4e14,3f6c99d7,e2ec94de,ee65007d,ab501230,4a80b69e,a0e0672c,b7dbe4ba,182eb876) -,S(64c9cd93,98fe9da3,5d3329f0,ccb82e43,c2d735f4,d2467b2e,1250c410,da84f41a,d24b50ab,71bf6033,d1206fc6,dcedf049,c223ef78,ff50905e,c8d95115,564372e9) -,S(ffe0841d,51e05862,4f759706,b27db960,ecccfad4,cf326736,ab4fd9db,cd29b766,6bd1f1c9,f6956c10,4fec1595,24d8064f,eb5d8391,30b34a01,77c07491,79cf2562) -,S(d1dd0c0,c053c597,bad38d63,c40d1e7,4b451861,cf0f20fa,47fd3f9b,77ca7432,34aa97fd,b59495f0,3e7b5628,daaaf66b,5c9dc5ad,de929032,80ba23bd,6c55976f) -,S(87a436e8,c76bd7f7,a3e49cd3,af996f1d,9153f704,1b185d8d,f99eca45,ae8e5779,8d2cf3f9,12553844,ff905d5b,2a1fc36c,369ea4ff,6a89a027,b6dbe797,f11006f3) -,S(a54500a7,4899c440,384f707d,a8fd62ec,1801070d,cd5396e4,b59e9ecb,df27c379,e216444a,6d26bb06,5f5b5e5,72c927f8,5315df3f,11da2cae,2f334572,33cb2668) -,S(937ea4f7,99a319f4,fa5aea85,b48d6323,28417b72,8690a9c,88fbd51a,57d8187b,2931a7fc,9eb4aec8,b7dce4af,d14438ac,fce77bda,a7d3e7bb,b24c8554,cfdc9d9d) -,S(50793c76,bb914aa3,204dbc96,cb04ff26,c7060863,8d497f07,a1eb05d9,b7fa6f36,afaafc78,b5e30762,b68940df,41de9ef3,d963b603,6bb1ffbd,eb13fd67,4bdab21) -,S(8b600630,fadae564,dcd1c570,9bfe1ad5,f8da5282,61d55bf1,3a29766f,6d8bb5a,fbf1b64a,3bd0439a,ec45a7c3,859374c1,7885389b,9c201f4d,c1142120,6b2916c0) -,S(14e88bdd,e32a15ed,a37c9650,ffc18ba,1fc61643,22b167bd,635f3d02,e78c8458,82c1ec3,dc240faa,5fa355be,475afe0b,5cc2cd13,760249d7,35b1efe9,976f02c9) -,S(c201e4a3,24b68472,d453dc02,8c78b1c9,975a3d92,efc70a30,a912fcf4,991c6c06,263a954,41d6e6d0,8ebf3e50,3c786a12,a82f5f8c,d38dccee,62469e9c,f0e2dc08) -,S(4097665d,319a8b3f,71861b1e,11828cdd,4094182e,611b35a7,c5d10ee,99db4fb,ca0d7ceb,b1aa2b1f,576cd1ef,56ffee03,322a6b95,505727a8,5dcb70d5,27a506a) -,S(173d287a,eff9293e,dd2021a0,4be052d9,3713341f,37a537a4,45deab49,b427fa92,9626e204,f03a1886,c27c37b5,85725465,72e5302c,d3f9ce54,1fb9a46c,16432548) -,S(c923c74d,1b114f,30d4b03c,92629bed,227fb8c6,8f1f39e7,8f121a44,694d4256,58edbe6b,dd5e1382,108d1e08,ef022788,c9f91803,d8ad4273,1f413440,5b5b3d29) -,S(92fa7906,b1f25c2d,3df104c5,196cf31f,93e5a8be,6cb91a57,c88c4ab7,cb92d46,a12162bd,79341fc1,e8f74db6,2bcd0d9c,ae99a75e,ce588240,79a61751,c887f307) -,S(37477df6,f51f78c2,a9c8e17e,ed30d5dc,976a9c91,4aea94c,691aa3c4,8639140,6a6a26ed,1955656c,64c6e15d,e50b0453,25c3da66,f5067730,5c2d5fc2,a8089872) -,S(b5b2ee59,1195f38d,f834e78c,abf00fb0,be9bc724,36c5f596,67ada098,dd0521bf,10f36f85,95233008,46dd276d,951abe90,cc8baeb0,fd8fe44,314706e2,15ddd5e4) -,S(b05d1b8,443f1bfe,36a415e9,d307ef2,56039335,76ecb630,94845b03,d2a137bb,99fece4b,ddc90b2c,3102a415,6f0d63f8,54098f48,3e1ef64,65f7f062,7d066cbc) -,S(e5d711bd,4778b3bd,cefd703a,e9525b5b,d69dcd86,6cd0b179,de76ae8a,5d918fd,8af014ae,5aa05b29,a0c88e21,8fef5690,9685d524,af389327,5421c35c,6db64248) -,S(7703cab8,377a482f,bff1c6fc,4d137998,1e217d11,c424beb9,f4f1f786,86fa4f30,3323edd1,3c80b8db,c7e247fd,5568c92c,8dd329ed,420aff0a,8e903571,e884e8b3) -,S(f834af29,c18bb488,366cf722,52a44357,2c87da2c,c14b3085,5405f626,154f3cc8,2e8a0ac0,ca5441a2,9e27dc09,4fd5bcc6,6bd8f7c4,717615c2,82001fed,bd5ab248) -,S(783b093d,13f33c60,1db8ee84,51d852ae,13bbcd7d,1d03a79,4c774336,4bbbaee0,3aa90b01,cfde6abf,fa0dbfb2,ec2cefb,6b5fb1c7,41701ab,66ec9b82,74ae5b4b) -,S(be3cc435,a7770b99,14a243b,48ef2c77,3ae42e82,1c18a266,6f92da59,e01c3391,f0d3bd36,9118c58,159fc64d,e61ebc58,a560f705,25dd5c51,e6aa9276,5ce4a701) -,S(3e980bd7,adac00ee,fe362454,5fee1ae1,97f89e06,84576a08,fc909285,783b606d,c64f0e41,204c946c,74473434,7e091147,67455e30,53fd488a,34d333fe,e9c5c228) -,S(a6b04140,aa621e6a,34959bf1,29790d72,91d7b154,5dd5e7c3,35bbcfb2,d582b442,9cb2c9e2,9cc05d97,5e61d151,542af6e7,a997f8d8,ee42d37f,8041c169,abcce830) -,S(7ea7a83f,c133cb8f,a109a6a1,b29b2c3a,29ba432d,222382e5,1f280e2a,47fa721b,cbe384e8,8a1f7731,831c5562,ad1430a6,6aabab75,e38571b4,5bb7dd8e,a699d7e8) -,S(8525e87e,f0fc9ebe,2f82b5fc,a14ba6d4,8189f9ee,146aa6c8,d842aca6,90fa042,dcf06a78,f311a3cf,182a393f,2a34a570,192873e4,7dfe22a6,86c70e75,6b32c86f) -,S(7555a77d,fa050d0c,9ed29c33,765fe967,16dafff3,6cd04fc0,952a7b41,bbd56dce,9854c0a7,bdc3dc1f,d8bd0a3c,d0af3111,18dc0392,830699cf,d0bd6f1f,17152177) -,S(9ed142a0,7a0adac1,14e6f026,133e00c4,972bb3bb,bee62f71,beee17d,9aac296b,c1eaea41,6c80e3b8,d24d4006,f699af50,9f4dca85,11c27f6a,39150a20,2b7a9d08) -,S(a3fd2cb3,784d8ccd,92aa67c,8118fd80,c9d761c4,2e0169d5,fb13b1a8,dfc56b79,75cd9b41,55db55f2,d50fcdd4,8c90d58a,b0d13df2,7a09df6d,659bfd5b,f87ea755) -,S(2ab4be05,217e7ee8,799ad598,b9c0e211,554338e2,8bb6d42f,c9952203,605ad251,2c2a1a58,da066d4a,7fc8c8eb,83e1e47b,b788afc8,3c8c5dc7,bd8f5e31,5476d853) -,S(4afc2888,af8c1aae,af6268af,566ecceb,8c95d09,d9f8f359,2cea567b,8648c383,b1e26b82,5e69e92e,98902579,7e99c7eb,cf3f284b,e1de0054,58b59336,a84f5eed) -,S(dd800faa,92319d2e,48038600,aac1c2b2,f63f5fc8,dafd988b,548021b5,2d8e3d4a,59fe8092,6e0468d7,60e522ac,91881bc6,8fdbc192,14fee60c,e8e1a977,1039ed7d) -,S(84aaf3d1,daa3a5f8,89b9bc88,6afb07f8,7bb5182,6df9d7e2,af5a74f3,c6378c91,f4164ab8,45eadd6f,a6331218,ecce096b,a04fd586,b744f0e8,11c2a48,3835afbb) -,S(b770f2c3,9e2e9db8,a92823a3,adffb690,d2ffc180,b88cefcc,8adad3a8,27c40b2b,f7c6e37,9894982,5d1b90a9,16ea564f,7e319c97,ca6cd22e,79f599e8,dc0d53e6) -,S(a60608a8,a0d7e556,70145c5f,bb107cc9,7cb1db87,2493f362,36a21e7e,babb2b29,3423527c,4e414548,96406f90,6d4a3819,a289c91f,b580ce19,6f25c57,7b54de5f) -,S(80f470f9,7b7f393a,5e6b4e5f,cc911a73,20f6b0f7,fcabf2d9,21eb649b,53414597,57d8f2f9,6e1bbe0c,1328faea,13c3f3b,770fa14e,4b5b7e4a,fa1ce9f1,2bd9adc3) -,S(4e111bf2,1f5248cc,3fff0096,c64a7b58,72e4a3db,1f0397fe,261cb33a,995abb6f,249cf172,102733bf,5fd829c1,d60bd930,c03af614,31faab0f,6d5acbb6,96eb2b9f) -,S(7d8c0cb5,47fa1d8c,10254660,a20e85ec,960cb70d,f38174f0,18416c68,c62844c9,2d79ba3c,17ec4d79,a157335b,f358cfd3,72b0f1ae,1f6bc743,40400571,5f35a271) -,S(bc0d4cbd,95896fa5,7f23d48f,a5a9f2f0,14b132b8,9b5953aa,f612aaf9,670a0034,f5d06670,7b316581,7a641091,55773bcb,83d7563f,28ea5412,480a0f48,2fa0639d) -,S(b154a2ae,ad08d115,95eddbe1,c9321e15,5cceb0a6,a7e646a4,2dfe70fa,b6d37a40,9abade21,674dd12b,d01e586f,695c896e,17120d8d,9e3c756,c8b5e53f,3216592a) -,S(ef603c34,a6ce06f2,7053bc31,841fe2e6,314be756,7e477325,5315ca58,5772e1e4,f9ebbe28,96f3b0b9,923a7e57,d819a231,15fced8f,3bd08f51,64aae597,c49ad65d) -,S(a601176c,2d901ebb,ad5a05d9,1adc0041,14f7bda,1ac496e2,c04e23fe,82aa9376,f781ddb7,ce0c3649,3772fb84,9e914377,d59abcf9,d3eade68,f8c8a303,1ae88ab8) -,S(abc41547,b6b3104e,fab968b9,bc9a9027,b1c7f0ef,3a9007eb,27331539,5c31e6a7,cd2858a2,28f21d6f,bd8a1821,dd78399b,594c5bd3,52628dce,879b8a37,d97e0ec9) -,S(92890105,c9c721,b2e4c430,26e413a,941d1da6,d31b48a9,2f2e3a17,d87f5a81,c1cad87b,1bdcc617,1e432e17,c13b47c4,15c22399,a7cbfe2b,b3097f28,da60a5da) -,S(e520dea6,9f4b35ca,46a46831,9947690c,500a7a80,6bd64228,ad144a7d,c37ca563,6c00d766,ac3f8fbe,90355dda,6ad4e2d9,e2330b0a,db673356,638b0d3c,8a2a82de) -,S(c0337a23,e2b3f1c1,a57d18a7,9d6ef25e,ac2e9315,18f0ffb3,7502d701,c57fadc4,fcea5873,be22df35,4729c3d5,b07a570d,7ac7e938,f6e061ec,cdd2146f,50808b65) -,S(276c62bb,6a8e2c07,6b5fb6a7,62d1d624,1b796a96,f53593c,fa51279b,2981ac04,5c53a65a,bb6b01d2,3f9284d7,d696236c,773c4578,88f692b,73e2ea17,6e1afc1a) -,S(604e1e87,e5051dc2,b837ccdd,43c8ede4,c4a2de6f,67a9ded4,fad1ddbe,8d663a5f,f70fe23c,e3511973,93d4d675,9444d862,ace4c473,99c34349,2d06b27,8b429bee) -,S(f2fc151f,470d9106,d58b05be,5e9039ba,4aba16ae,f7e4ceec,3b6e3887,5c41f6fa,f49bd2c7,f1aa5c63,d8e7f2d6,e0769060,d4188773,9c16b7b8,5d2a9216,e1e98de0) -,S(8e031346,e9f34ef,3b81d9cd,7e46eaf8,7ee0b294,d66b0315,eb0902e1,340ac560,ff00c8bd,a5e21e1e,5127441c,ee0504e,6b028c,ec0dca,450145f9,2c394296) -,S(a8680f1a,d75b7a8f,27a1cbe1,6b2954eb,d4e26eb3,a85d1a0a,96b9f40f,e5a9970b,60c6bf41,a55bdac6,397281f2,a3f52896,757401be,c42964c6,9501973b,e6070c01) -,S(4d68a1e7,f4d82ea1,e03407c0,5085c794,9ca8c00,d4dcb066,128e6c6f,504f4658,85c5de11,e5dd3691,2aa95d2d,2c36dd6d,26a9550a,3a672af4,d36265e7,a3d1ce76) -,S(3708f41c,2a6d8649,6983cdc1,bd02eb39,758c0bc1,ae78a483,5c6a20ae,e6c2a7a9,310b799e,79b7f5dd,5c9ae0f8,7aab193e,3c2b7145,c70af9e7,f4553faf,abec4152) -,S(8c883967,45028c5f,f1b96181,43f5b732,2d1a18cd,3abb1a92,f6ce3780,a115f059,24563ad4,e4ae484a,c344180,66dd87c,40128e42,5c8dce10,b008a7e7,620725d8) -,S(c445e76a,7b377ad3,bdd0fd1a,94a7263b,652e83c2,6342305d,a0e1ff4,d58f8fb0,4bf5a41a,dc8ddb61,3afbd3c1,3aae7dc6,f60ae2e7,23065b8c,c94cea61,cbacc89d) -,S(4ad9613a,c8a635fe,60d9f1d4,da4b9fd6,36949d5e,edaaee8d,eb2f65da,8e419f16,5a9b5b06,8f67a0fb,3ad31c83,ef1a81b9,38745877,b4b07316,42ab4951,68b0d7c4) -,S(beb3eae1,958bfe6c,9ab49d77,648aa662,2e397fbc,58e90b0c,20d1d29f,d760c943,d5a46be,f43a67ab,225dc6fb,5aa68daf,ec76f27b,6a822678,dbaeff88,382c9b8) -,S(aaa9aab0,bc0e21b3,be3f1dae,ad4a076b,4623fc14,3e4018ab,9df9a19f,d134f397,9c7d7fe,19642c65,a6c0347e,8fa2dad2,d3f094f8,bab6790e,d3c703ba,2742e40b) -,S(553c1e89,99d6f446,2fd7ae86,f1cf9d24,d4011661,9fd5d356,604d6a55,ad99dc52,26b40d3b,8410ac5a,6d2ba776,f7c5f0dd,3f6fe494,379344ed,6460bd6f,f550cebc) -,S(859885ea,36378fc4,398dae9c,4725d604,c3d56509,559ed28a,b47ebf82,5aa1abc8,fae5aef9,fc74b963,bb2fd930,5b2d1636,e6e84aa,3c40b066,9e531fcf,f00687f5) -,S(5fb0a118,679c5d48,554bf7c1,63b82345,89e51032,a70c654b,bb7bdee,f0368f93,e8d55f0,4a6816d3,bfb02111,eb95d868,5b9966ad,39d94c70,a4cf1826,6bc2a2d0) -,S(a424347,86f3e153,c9bd737c,1e70ddae,bbed445d,77ce4302,194be82f,94f91dfa,27d1cad6,abd9fda9,c1012f4d,f25b69fd,a54239a5,8ec12496,97116548,e7beed46) -,S(5d007508,63fc1f3,a0a8213c,c729310c,39465945,72b083ee,f571b921,a0c821e7,e538fbc4,5d055a07,b2cc2605,61238486,d99bfa81,6b0407f9,39f1d12b,feb2df3a) -,S(a3eb25b8,97b10286,934605a0,e4aab7f9,e80393aa,71cdea52,5f82f5e8,282e3db9,e2b354c2,1430c45e,4236baaf,128967c7,6beec58b,e6890c6f,303d83f,71e7f77d) -,S(73f63220,8a133202,96f3f51c,d10fc816,1e309e51,4ea35f0f,ff72e09c,e897981b,43412959,cc78f32e,d6df7ded,349a92e,3095257a,8a1b5dc4,15ed073,a420179) -,S(5f0825d1,c21bb5f3,8f0d9628,f6046648,7760512d,f1bb9bb4,ccfec4e7,48da41af,debac60e,1d95de12,84f1abd5,b6592824,5becd4b8,c2496323,b374239f,fe5c0cab) -,S(cc42a6f2,b4a8e9f2,fae3f624,cd12294e,efc26dff,c66a676d,a10259fe,f7d84294,91b26600,f92cbd05,f13f2adb,2b5fb17f,118a7ae1,6a011690,1bae0e14,3b230519) -,S(7d56e0e7,6eebe13f,a81aad7a,8efbcd1f,4de0c5d6,bd136261,8f0002ec,6f635a17,95462707,fe55e3ee,46dca813,eea5de7c,51122ec,55a91754,f7d13ac2,43fa1ad8) -,S(7972b61b,4fe85ec4,acb605b3,aadb56b6,fba8cafc,3c764dc6,add54c06,f7a5be61,ba186670,2642fa6e,a7cf5141,c46a8e92,4764c4ce,5d45b7dd,9f4926c9,32b8c7d8) -,S(edc8a440,347b1500,899f6360,9674f90f,4344c87f,361fae0b,bbe08235,d5025626,2f812740,9a14bf59,9bcc7cef,ad140b2e,7bf84122,9a51e486,4d01ecc4,1b2cd77b) -,S(bd9b65c9,7a8cf4d5,2f727b57,19f99986,d4ea1bbf,25560d18,d54877cd,3db16899,59cf7127,4e878e5c,bf0d9e02,dbe4f861,ee9c8e3f,5dfe99af,7db98e2b,c2fe432d) -,S(27635e38,1191e8cc,d3756571,44c5d8d8,72d91802,5950a106,f3be2acc,4cf35782,c359fe47,a019870d,7fa3ab,8f51bad4,eb5251f3,7e6b8ce9,db1992f7,cd1ab7d) -,S(4492dcc3,16c05300,a96abad1,47a00e98,359950f4,95dfb261,839ddf21,3b21d85c,edf1371,a4e81e42,dbfb8c6d,2229dc5a,fafed4bf,a58c2433,18934ed7,dc9ad35b) -,S(f8124c40,409e01e5,8de8a386,9bd88f8f,25887fc6,cee37c01,279aa606,edf9c67b,e0071d1,d31fee0a,8a26269c,3d7f3662,2b0f008c,61e749d3,65560c21,a26fa6bc) -,S(cc597b67,66eccdf,a2c0716a,dd5e51c2,ce3aed33,8f55f0b1,b5784bc3,9a05a2b5,12e031fc,394a43d9,d1e12ec4,28e8d5b,df52dae7,f3ef22da,74e3a418,74682865) -,S(142cb2c6,bc1283fb,d2164270,7d525dd3,d4a45f71,a63222ee,6fdd31e2,805aeda2,bde93d12,c72c422a,e4d5b718,bec6458,ed082bfb,7c686f2e,1815edc6,5ed66ec0) -,S(fbf4d602,dd765941,e696704a,1a8977a9,c3327375,e3f0d479,68fd9148,c01d2d3c,65b46df7,99e895cb,a6d4cae8,e68f6160,c7b96fb2,9af7d18d,8ef1396,c06afa8d) -,S(efdb5d57,bb5fe8cc,e3300ea5,ec14c50d,f09436db,cc58ebc7,c6d123e1,8dbfffb8,39083803,d9a90c62,6219ce93,167bd89d,d444e47e,ddd60deb,8137b8a4,203fe01) -,S(5bca4334,faa30557,b4b36c7,b6bf2d4e,921f59f1,eadebd74,97690742,2c3f35ad,3c97baf5,e2a663f7,22bf2fe1,cd646db5,79d27f2a,353fb45b,520d227b,c21206e3) -,S(9aa1dbbc,e90cf065,5ad8a0f0,54aa6641,ff921e97,1a73cd4c,49ff1f3f,51156632,cbf6e81d,8bf1e85d,b802f0f0,b9cc1125,6e0b337a,b90112dc,6513bf40,2b1a4200) -,S(2fc7fc55,86ed7676,4d5d4d23,ddec2827,5386e56f,eff09b86,abaa9562,73c2d408,5bff69e4,773c34ae,e477b0c3,e0310b5d,6019a558,5d4c7f3f,54f9c810,69d6285f) -,S(8e5fb941,c3ac6f2c,43195487,80df9116,6ef3b210,f2fff34,764cccbb,d34190b2,dbe2c1b1,5f6668e2,c63ae154,ce7b32fb,8d29b59e,dcf1ac4b,1df9baeb,fd10d2ce) -,S(7a5bbb59,4748d6dd,5d3389e,aa95b8da,dcfbaa07,26693690,4801bd61,b3d49c6,c2d28043,a42d33fe,8d8b755c,61235c68,ca13861c,effe3fa7,fd4edeac,634187c0) -,S(95beb8bd,f0d33531,ae73ee1b,1b631ce0,917c2fe2,22534745,f87faf21,bfb76753,c6cf8600,d9c55975,527e269f,b4a0e4cb,b9bd7783,7e230ada,a43c2f0b,c64f45b) -,S(f44ecb0c,6d896dc0,304fa480,90ab9793,576dbbd9,76b8fa32,540d223,e2968d25,545064f6,29644329,76a03c62,9ea46a09,e20e470f,5e76f810,6d19f353,c321086a) -,S(8dd32cd3,3dbd936e,6173ef50,1f7ae265,d56d68c2,77061e07,4fb49d26,538109de,6b110e5c,80daac20,5392bca8,a47d6d90,ad158c25,a10c0851,ae985f70,7c3f1e76) -,S(3d4afd30,b0f0f578,d4fbc77e,b71d044d,fea5e3f,891cda8c,77075dda,6237997b,2816e0e8,664df57e,c793d442,49c23ada,ae286ab,e748493e,d83b1efc,58bb9ce) -,S(a9b739fb,beaa3b22,b295ccac,86a07ba2,b8391381,2d2be020,a5ffd17,85d95ff1,a1d08230,21d6a6ae,f696d732,3c43fdec,d3c5d42b,8ed7ad40,1a55b2ae,bfb84f1b) -,S(e9009747,e51251eb,fc2cc754,c8b55966,a37e5d67,acf9b632,bb77f46b,9203715a,34258967,9ea8f997,71b476f2,5571a588,756f277a,17ce3907,d9cdab4f,cef9df72) -,S(7e348ced,55aad74c,c24d09b9,6b332084,2108fe41,3ac4c6c1,a8376439,f21a3f2e,39874f8e,3b722795,d8465706,e439e4f5,c884c22f,365920f9,1edcf83e,b4389e5f) -,S(a7dd6676,5ec2d701,56f2cdab,f0fcc0d3,8e340fb6,8a0d1220,aaaa74a6,fbb1f55a,b7091bf2,ab00a63d,292ded9b,b00bbe9,63710dad,445e8e73,760a50e7,2f41d447) -,S(b8579e9,a8cccbf6,dc033a48,16d8934c,51c0852a,4693fa96,a308d51e,3f57025,e696ecdf,4d79151b,2f164a3e,bc11bda,42c88833,6f694fec,a8bcdcc5,7158268b) -,S(7b29c45,9de0080c,bf8c8c72,e7b59a7f,184f1c1d,46787cda,bb42c2c2,bff57af8,40de8367,a6d8d13d,41901ca5,60376ede,817578b7,25f4e614,5dc46de9,5f801799) -,S(1ceffa6f,89b65be7,ac20e34e,f0b7e503,d1c4e9d,b31fe14e,179afdd,96f00f9f,6fdee8b1,f05930bd,ed98feb7,81790e10,8e293bf5,bcaa6da9,79a744b5,1a76f179) -,S(556e2d6d,11d301c5,6d5d01e9,a01e2ec6,80ba4efe,a004de47,ca2d97d9,15e58d74,9588349b,b633d7b6,b55ba7ee,feecbc99,3d66e6c7,2f4d8961,8a2c5d7,5249d711) -,S(b3506e88,73b93dc8,ed04518a,42b62ea2,b97f7bf4,e9ee66ba,6a7ab917,a1e51586,474f8100,1230fb7b,fe693eaa,7acba9fe,5917a39f,1f8fe3fd,5823ae4c,1b0b3b38) -,S(d186af3,89cb4908,db01a886,f90ee67c,1ba7ff3a,19994504,e9774b96,bd2628f3,3b39782b,c6567cdc,b4778c75,a862ef36,d01d746f,f411821d,5d08f7ee,f2a2db7d) -,S(f951d921,e1065ac2,3fa45900,62c639d,19e8c980,2a810d55,d6788572,ef987bb7,dcf7ddc1,87f8e975,27db239,7f553b5d,51abc66,bb76a070,55d098c7,f9d7d950) -,S(8dce8e16,7bac6fc6,1161b75e,8f340e0b,8bcbf874,fc82a42e,bb53e0fa,c4d915ec,11ce53a1,4a9eb9eb,9b4b410b,34d26ed7,9c0287f4,9032f674,e3212617,e0ae940c) -,S(ce2d3cdd,a0a7a43c,d7d2ed15,ec12a7aa,755dfc5a,ed5a85dc,4f439eea,99e26e2b,6a96aebb,e7ca2740,ea75c285,3c582207,6a8eed64,7e21809a,36b97c60,7a5a145) -,S(239466fc,dcc2d4c5,cef367b5,c8339248,f712c40a,558c80f0,5ea390a8,dcd92092,f2ce223c,9b49f08b,ca63ee8e,98e01736,65d176ab,3b7d718e,d0e855e1,27ac28cd) -,S(220ab764,341d3c08,d9c5bcd8,331e0973,4a2f3c64,4766395e,f6a5fee,3563e033,ec1e4460,d03013ef,467dc7a4,2b520c03,aa51a9a3,57817f4c,f9dcd837,56df5011) -,S(d5455dfe,16406a6c,70fffd81,f3c4d10e,845f0b12,64fa3db4,ee2ffe80,904b469f,a0f93b8d,257e1e62,265d99e4,9158497c,28a20af0,2af959b8,8810a10,60aaf9a) -,S(52367377,a1f6f05d,df054665,f1eec0d2,f5039cf9,cfc1d37e,1a9d89f2,88e60c72,78d89f55,430fc352,cd58d047,7e2497a0,d05e7016,d98f9ce6,a039fc5d,9ec7bb41) -,S(5b996113,3ecc9422,26a3dc88,67364125,a8e569f1,912e6c9f,4c1ddea5,5fa56395,bb9d7764,12076caf,5d8ac902,c5e2fd5f,f7a0bcaa,10898f19,10142af6,4e436d0a) -,S(f36cdb5c,bfbed1e6,58c7fa4a,5b0a6773,eecd1a43,db96cf0c,7c24f32,b84c13fb,cfc6d2f0,5ee9eda2,9156aee1,81b62659,993744e7,479379b9,3156c919,18c394c) -,S(3208c58e,25107af2,b38bf754,5531266f,842ce33,10ec7e44,595fb91,7079a6f9,831c6dcb,5346b6c9,605d9ab5,895ec2cb,653599a2,c88801c6,45a4758a,32c785d7) -,S(a6073a07,1f8510e2,aa021b80,b44d7356,47253583,6501a5a8,c5253918,8c9927a7,e93a9fc5,4c8a7612,16718baa,dcfc9bba,6fefa30d,85803246,2a9f191a,6364fec9) -,S(3350b462,f79eaf7f,260f2147,6aa7ffe8,f7ec1a7e,35624713,9e335758,b9f0d913,1f0c9db3,fce1222,fbd2341,ba8d2e93,20f33bc,482a4d4e,80571711,21152959) -,S(a54d5b17,bc82a74,9207c89b,5a1650cc,1773913e,66f6744c,11de24ce,3073caa,3c243b5f,5309dd11,83c7fe5d,49222c9e,fe62dc26,f92b73af,cdb7b7b1,32cd3ab8) -,S(6590a2bf,676a7a34,a1424f7b,1c7863e,8a7d346d,563905ca,e5b25729,4a04cf8,11cd5803,490419a,1382d972,eea2f734,4f8d0cec,42466f09,39650645,a3e781e7) -,S(b3c09c02,9fc7f48b,d2f461a2,a367011,8840393d,fb5b9592,89e96ec9,c7cba9a5,e7b5aa6c,bce54ad0,197bb1bd,ac030e2b,c6a3e6d6,af2db60a,b97cc92b,8f5cfa9) -,S(d7968ea8,44a137a,7db36143,98b29972,cdc693ef,8fdd4644,26a92939,18fa8bc0,82402589,2901434e,cbd5dd29,410ce2e5,56dd3174,d74da2e5,28326ec8,ad57a75c) -,S(8a57bc6c,2f98f9cc,d1eca172,b2501adb,3bf6edc8,4b50365c,6d959f00,838e8304,2ebf5462,a0f85985,438b5d67,cbfa68c1,bf643410,11a478b9,92cbfe0d,87e7d14e) -,S(51886841,684750a8,c3cb8d18,f8c863cd,1a555dd3,7f0efb4e,551d0d50,6073fd22,eb05f09b,9e983ad0,a6ce0f15,c2f5983c,6a28ce50,6c52f691,f30517da,36f3f192) -,S(fea8c35f,27e4794f,a9eab856,615d55d2,d3a02616,9b9eb7b0,ab7493e2,f67c85f3,c325de97,cf0a6e3a,98512337,8e2ba2e7,b24158f5,4aa97c88,9b54a502,8c148864) -,S(6612cccc,d7bc25e4,f8dab955,d5c1c9cd,d79d5f69,7ef4c510,77b5027e,d1f94b63,615512c1,7a378d0a,e7aabab5,253df9b,e9bd6a80,15c3b200,73d0499a,3457860b) -,S(c998b07a,499859db,4c9d698,33199956,f8a7ae67,9f6d3533,cbdbd7e4,a86f8746,d9e01371,919e775e,a259d81b,ea206e9,37d6b5e9,113838a6,6af11bf0,8dd17138) -,S(5c0e4669,c5cf965f,854fcd0d,23ddc908,c32e3915,460d44bb,520fb0c,3a4cc1e1,cfebbbaf,7e0f9a4d,d2f35ffa,cd0f7cb9,89f5eded,c8b3c554,64fb909c,675adea1) -,S(d0fdda48,30385167,f06f6433,c6a9d3fb,7ab3195b,64f9750b,cb2dbfb8,7158c0fd,4cde5577,6a34f61f,c82e1359,8618336b,f5c6e315,d10abc35,8f0020e3,ef1283db) -,S(d925570f,d78bf65a,5d48265,6222ce74,7cab153,19b7cfd3,7bc70185,fa4a3e81,3c399a,c448ba90,1a21a5c7,b9c6575c,ff52bee0,cdd00ed1,673d8370,87c1924c) -,S(45d2b56d,81f84bac,2077d607,484b0802,a023cc4f,d7818f9a,1d0c2187,98374c8,14ca18d1,92a9cb37,ad50506e,a25663cc,9829411f,848bbf05,3064041,9c19d7f4) -,S(6ad3ac11,8588c5bb,f793404d,df9a10f8,ea8c1978,65a93fba,5b7170b7,9e157400,fa25741f,1e242c3f,edf20e80,fd76292e,382eb5ad,1731ec97,a8762fe9,811686d7) -,S(5da24445,b6dc960b,793ea9e3,912b21d8,26d54028,2ddcbf5,28e1ebf,4a595f52,bc18ff8c,ad1dca69,8995063b,ff8a2fd2,fabfa0d9,8c8885fd,1b401f3,65f16026) -,S(ddff6468,11ce86d2,93b9b89f,865d7133,d7b5f189,d527cf44,5ed15efc,ad32b346,7260e994,cb22016b,e121ae08,12b01c3,4d236b67,13ea510d,b1aeda36,567f5737) -,S(a8b9ff3b,9120fa93,d0f2f50b,c8509846,c1030d98,dc9d5243,6ad9e69b,f897f029,5cbfa29a,4e516872,ea9a4c2c,a3b07efc,c866aaf6,a2b1d7b2,3597e332,8466c591) -,S(943077fb,177b9d6a,723c18ed,ac8deeb2,62875264,868eceb7,a2fc1a01,51dbcafd,219a9fc,41ad01c9,d3f8248d,ac7df93f,ccb6e312,fa5fd442,e48f4a95,18e7eb4e) -,S(75cb61ac,9c9817a,fdf60f52,4245ebbf,82b33f9f,a564d74e,9e810f36,6458b8e3,aa8135bd,f66f0843,460986f5,f9df6b9e,66441477,cd58cfb8,5b3adfde,ec03c367) -,S(1bb7e177,27cb8e85,4bc922b2,28e7f0ae,c34fdcf3,b9bad0c5,750e7c8,e31fccc8,bbf72886,1e855e70,bd9e322c,2425cdea,855ea00c,3e6263d5,2380da38,c0221ca3) -,S(9443384b,39e9dbf3,45b4b41c,f05d0f30,87f02471,c98e2a2e,afda94da,8bee8dbb,e3661173,ccb211f6,38cac6e2,27e3939f,e7b5da57,f6f7a504,abae01c8,fa4544ee) -,S(49bd15d5,a68caab2,8d51638a,ec1a9668,b4c27d54,d6691839,61ccea76,ef740d25,648fc868,8760e47d,fbfb9f0b,d995cc0f,77563b60,eacf3e57,9db7439f,3f18c6e4) -,S(d0c7b78e,92809e85,84d3684f,d078907e,c151aa78,a5832f90,73f945fd,7acfed85,a80d95ab,be494a40,b5529046,bc305203,be91e475,22ad9d57,7ab95b3,8e970c89) -,S(debddd46,3ab22232,5e98f9c7,5cdc875a,7c4c28d8,79748bf0,cd96bd7d,92eb9275,d103c8d,c3fffcb0,5ffb3dd7,a73af259,50d02064,b12bc754,ab594c71,ab9799c) -,S(1d79b17c,192a6a15,8ea2d6bf,9da07312,9f9ebcc8,54b02dc3,3f64012f,1bf33998,6ec818b3,dbc1c8a8,50d986f,bcf64702,c787682,bc408a12,b78e6bbd,4cf60a5e) -,S(2feb76eb,ff5d47e9,7289c38d,7d1535ff,74bd3b57,264c5844,9edfd36e,6e81ca1b,45bd4e4a,7ba3a823,dfae18cd,1f9cabc7,bb462e74,7899c899,378c33bb,89f93b74) -,S(14d0d90,faef5a77,f5372ab6,2e4f5efd,3eef1b39,498653c0,6372fe0b,b0682573,517f169a,80c2b930,4f530f51,d7196831,601a4f97,72ba1312,36ba92f6,36081453) -,S(7306a7a5,728f91c3,384bd9ad,b10b39b2,ad094137,46d2e476,fd522abf,ff313321,215e22ab,a5b9e87b,35bbd4e4,f492f1b1,574c85ed,25b86a85,a8e17b81,b7a915a2) -,S(85d8454f,870cdb8c,b32873a0,698fad20,fd24067a,737e9719,76d4d362,6a55aaba,36d63c0a,36eb9e8e,522a0715,cb9c833d,539fe7ee,111af3bb,951434b1,3117e4a2) -,S(c68f6782,993067aa,259b21cb,9e19122a,2f7da28,96d8cdff,c1f0a0e4,b34384c3,74e6e96a,331c3387,7ea484fb,995d6a3,8dcd493,6b2994ff,b7dc3681,3079e94a) -,S(81448111,5dbe5550,846d5c9c,3351c89c,e29cd850,6870a17f,e18e3184,4214dd3,75dd78b3,d4cdc29c,697740e9,2478689d,540ea33e,5edd6785,210abcb1,670d19a8) -,S(310b5b19,de24d478,f5f25993,a706f21f,24214e1b,cf614ebe,3e204815,60c945f5,8b42c6ca,f01d205,e09d017e,2e840d69,bf04cc53,f02a21a1,47e33327,104318c3) -,S(cf8a47c7,4bafe2b9,dfde4bca,b2e6d451,b0a90f11,c684f420,a025974c,bc4bc3e,f0b7b264,a9a78699,786331e6,2c8762be,614d8a69,c0a65c3d,1cc201bb,e34c97d1) -,S(a0fc6226,7352a904,e70100ec,63d3b60b,ab553388,69b982d3,3d747af9,8b8650fc,ba3ae54c,16b24eb4,64b88c39,521c399f,cd162eb3,f9966497,e2b96f2b,3b85865f) -,S(aae5dbe2,535edd47,584d0339,10045333,2e1eaf70,a4e1bfb0,7dce3c23,6cff8bdb,7cfaa5f6,e55806b7,bb278439,2473732e,a51d85c5,a3558321,91195533,b7a7449b) -,S(8a4e9311,5b897550,cbc0792f,b2705a18,5c317226,86da5bd5,b0a17bb,503ae39,1623adc8,d85f08c7,1751b976,daa17572,2442aed8,a9dc1692,2dde923f,d17cef2c) -,S(cbcef535,eca90b09,5295cd61,29010259,8627e1a0,ccbaff26,a51cdac6,87066463,651c2ffa,c2a2c99c,3fcafb9d,8c50e156,498fee17,3462fc25,9d87fb8d,6b212653) -,S(25971559,4d6a2bd0,baa90e33,62b9c841,bf12c4d,2ead6609,9902eac1,ed0f8c99,49e01b6c,c97404cb,8144002b,c33e8bb1,d974dd22,d0a26a82,94bad2bf,2875245e) -,S(b754d68b,2b049f6b,ac389044,c80f0364,a707da5e,3e9b2a89,1672cd29,b6f1445f,1b29b7c1,625e23d1,67092e3e,ddfc2f4e,bea55542,5f4ddda1,af2aec5e,4de37740) -,S(20aea5a8,50e68f39,cc7ca2fe,2f38b5a2,ab0bde8b,d294c40a,afa898ff,4f084037,6ed576b3,f17666ec,6aafd6a5,6fe7e1b2,ab1e883c,31230fc2,b4e1df0,3f59444) -,S(26844e02,919de923,3288cba9,a97eb85a,c6939fd0,7cd01e7b,f0d5e1db,e31979a6,3df9a8e,6a5fad1,266f11e,518fb60c,cc08a6c2,832c45a1,6c7c5520,5c9ebfb7) -,S(11afca61,33a69aaf,27cfd413,becdf9b4,efbe0a6b,1a38b3fd,485dca95,dc28414c,8d4b8790,c0677fe6,22847bbf,8e47b400,9e4678fb,b9c9377b,2121f5ac,db737b1c) -,S(c46e14d5,2fe25d65,37bbe09f,ce7e95e0,4986337b,23e7160d,f3d78dee,e8d2a63d,a200fdab,4211e9ff,2d008dd7,7ddf67a5,1f04b9ef,43fa1758,9b175d58,f5d2b723) -,S(570aa12,578afe09,245f598a,210a7605,2412283c,8f58e142,d31d9cd8,d455e4d7,c28fdb61,f8e90de1,d43439e0,8512a071,9a2beda9,5d0a5601,b932c0f1,2cc50ac8) -,S(d312db5e,88a1cea0,28570b84,e3854e16,224236ac,cfb14d1f,3a33108d,fbc3fa64,ca5e5089,1843383c,845fa0aa,e031c930,64b8aa4a,ea72e6cf,36b617f6,cf97e1de) -,S(1ee22876,9981670e,14da9ad9,9279f001,c9be5eb8,76224a6d,1fe4ec08,aa398087,62101114,e303e37a,dfe42c65,54460d4,b68603a2,580c7452,6ff31c9f,2176dcc) -,S(1fb9cacd,e2b84ff4,ae85511d,1c964c01,1700b9d7,2d4c04a9,4afa9aa5,57bb81a0,430b73c1,295c5f2a,d6d9f59f,74201435,15b1306b,2cfa038e,e0456752,5f737fcb) -,S(d04cc82d,d3cf0b47,69f2934a,9807e743,4a998bb9,fa44d145,f191a176,611c085b,7a4a19af,b551d151,c42cf1ca,ce123dd5,8f4c13ac,c865b92d,15520169,1be5fa9) -,S(1e4cb208,8bd4d17e,ba8b97f1,f27df5df,8a544f8a,548dde15,712e8704,cfe7e9aa,d805c61e,b72933ec,e799930a,53fda3f3,db066396,5c71be51,5e8466cd,a59b828d) -,S(520aa398,707a85a0,d672bbad,cbcfdab8,8f769f69,df3de8c7,17d6dc48,de51590d,98d344e4,a9047a22,c09095e2,f1176aad,3b54724d,998e052a,39a52554,4ee9ada8) -,S(3a9fe3de,165bef7c,2e0d45a0,60693fc8,e7080ac9,783245d7,a79cac6e,7b614ef2,5189446,fd3fdeef,c7a895f5,2934c888,7607ff49,aa6d798e,151061ef,73038d4a) -,S(9c929dcc,c26c0805,e4289a3a,2b6d68c9,8e3c6806,43730056,65fd8e73,da149938,6dfbf940,b4c29209,3f39f6ba,b102762a,c81edf2d,aabe6dd9,56aa140d,396ba2fa) -,S(355b60ce,f4e00651,8baf1e42,e5e7a08b,ee22abab,c69aca66,d117748,89be419e,7f478a3b,b277fb10,5fe0eaaa,cb53fb73,4fc01dae,bb44f1b1,ed146f43,fc2604e2) -,S(76bff14f,21ad4442,e1389bb1,c11e1019,ea966091,97439705,dfce7bf3,d7f7f37f,3855a291,376aab12,b5f4da79,bc22e02e,a29a34f8,9223f07b,93f6a549,8289d763) -,S(91bb9cdf,10577a3b,7e23aadd,35883396,becbb4bf,fa22e1db,fa08f8b6,6156b454,ec6cbb9e,4f149b02,edc53e93,d1611b5c,a3edea42,c2ca9a1e,f2cccf25,94edbb91) -,S(9e56b10f,1ba86c61,36481204,f0c45b09,a7dde7d,4eb32537,f8c310a5,a8865562,cdf3453d,8552c16c,48bca1a3,79ee8c6a,8b523eaf,d1862d5,16f4361d,5a8aa67c) -,S(4e73594d,af286bde,4e6e28a4,23930571,a11dcb75,4e9a4af5,f4972d,988e09f9,a59f23d0,70c042ce,e03d812c,ea274035,af0d8e53,828a418,cd1b51f1,458a36e7) -,S(156fdff7,e92d89fa,691d3c55,7cb2c614,393d5973,4b11bb1,d9fac953,3923d860,4e929637,c448760c,ef6d68f6,4665023c,bff653cd,23132ee,620eb013,a13b360b) -,S(f2c8b650,eb372336,5d57a905,23d34db9,70d23d52,1f893569,98b0a7e7,ae8ea03b,bd9ac314,84a99bf6,973422a5,60bde9ec,204488c7,6739583d,72f42a87,181a7881) -,S(27dd3657,a4a37430,5f5bb92b,a7b816ba,88d526a2,1ae316c,d4a4e67a,c751e3e3,880cfdd3,c0faa401,6afaf3d5,1fe975e4,8a756b01,f7d84e8c,226424b,83be3304) -,S(f6c25e0c,19f7357c,3cc5d98,1cc4b7f3,7a390182,c2673708,1c64f163,ebb3d1bc,8c80b3ea,7c05a0fa,39944d66,643b3589,29534152,adf37c2f,183e7c22,8e89e43d) -,S(c678800c,71305ea1,ea2847d3,d9d37612,ae280305,716fdf45,87ac7f4,a7fad4f2,be5ffbf4,d2fb2b8c,ddb49a42,ebeaf5d8,55d41d39,f106e2d9,2d549e88,6c0b63c6) -,S(f35db221,e66b7786,fc9e2d3a,68f0d1ee,f98177df,a05bfd30,931912e8,13f6d560,4899a808,e6b2040,89974ca5,afe5b1ee,9eccb15,36a7c7c7,bb67cc00,e43f29fa) -,S(2b93e37d,a915633e,db9843d6,c33888c3,5d944f04,c4074deb,d021c639,93e69de9,eb3d1095,c6ffa1cc,93f72a58,f1320efc,366a4a5f,c7250167,6f2d3c88,4b0522f0) -,S(818023b3,90454716,f51913ab,fdb406f,e4875b94,8b14a331,60901d1,66091b69,b3f5718a,6224e447,c5af3e1,f38e4f2e,6fe57389,fa7d8990,f98e44c2,a227e7b1) -,S(1676e6a,244ca69d,b2ae565b,65b14184,6645ce7b,213dc1fb,db33f060,3c662bb6,88e1cba5,deef5dc1,26b20830,d2c7c0d,aeb9689b,16ecc1fd,cf4a31fb,822e0298) -,S(2f931a1,a92537de,38629d73,323e2f21,d9657454,30e32e4c,3912cb21,dc298d54,93292d08,6fbc0fae,eef6fe43,f5626711,95a5b2d1,bdbbccc,52e1dfae,a30ef904) -,S(7ba4d612,f0dd8c91,8bff20d9,b4f45486,be8a32c1,122601af,2d1730c8,a1fd0279,8aad7aa1,f5b06431,b2e20af1,4cd049a9,3018e3c5,bc4c4310,d0234e78,d2401179) -,S(e8dfab0,85fe7a91,6a79b2be,723799eb,d6974d08,ccc8e3d8,5286aa61,c81d5e78,2121686e,519db556,e6595d47,a5487bb8,fbaec53b,b18dd81c,37dbab40,6e3f926c) -,S(7d5623bc,b1597ef4,6f907106,17eb2e6a,ea751da1,5535a64c,94c90c9a,d84ab5e,dc639f31,8004c4de,31514b70,ebe2e8b8,701b3cd4,5d66b7e4,204dcbc2,a0ce7575) -,S(8e81e2d,8074bec7,48986194,b3b82200,1e4ac916,81de2ad5,7b9c84fb,88a7ffa3,4085ec1d,f4a34480,ca56f6cf,762d03f7,fa94e99a,8df93e6c,dc781499,59fa890) -,S(a9d5a3e7,8290ee62,5e18affd,169c6829,73e68ac9,2b5cc52b,53ed3a85,a68da71e,1cdaad6b,f9eb5889,5189ed29,8793388a,8d6e8b20,ce47a536,ee89be4a,b4805fd6) -,S(4f7c17ca,bcda7c0e,3b7b313,4312f848,984985f0,e46ac497,d64b123c,57dba2cd,860bedd9,5f470c3b,f3cbe7c1,d5070cd0,c877010a,9baa8f5e,888b5ca8,a34a25d7) -,S(478f3d7a,9234a7b9,a91bd016,f55734e9,34b8c3c,535725b5,b4fbb0ab,9fa64921,db97a394,f0253f18,ebabca05,c21e9a7c,3f253054,d83f2101,8ffb4d93,b8051a1f) -,S(ace7e57b,73d96e7d,69f7cc01,b1da179f,3ea09aab,61fba329,f2552eb1,fe7963d5,fa0251f2,2b8dbd04,ec90f824,be025965,7e213e4c,1030611b,796efb89,26908918) -,S(cd56e867,f5170771,8253757c,dcdf69ef,4401f2f8,a1d09f24,374040e7,a908d1fd,878f7216,52cf0ba4,8a2b29a2,2f620c7d,83e4bd84,277b7b90,a454bba2,7f338fe1) -,S(3042ea5c,d9d2f89a,64b1dd24,97b25da5,67a2c672,ba067e33,e923e513,ee4d5329,b84c144,d5516a14,a0a8568c,d6d227a2,d3fa1d86,8e05e612,81ce41b3,5a68b1fb) -,S(55e088d,a094ed26,82b042,bafa0345,30a2e291,57af3f1b,ce351ec9,9e712ec0,c6f8297f,64398324,96091933,514c5449,cacadf,82d51db2,82c9d2e,c66b33e9) -,S(bd2db13a,69dd93bc,a37f9181,7a57a0e9,e0e0da83,eed71875,e63b4691,3b408966,46e12660,f9489b2f,123c25d5,f65b3f8,187ee6e4,405b8cf8,78a742a,9b0da2d) -,S(7d7a5110,cdbb8455,5fe678e6,24ed1a14,ef7c5219,986a7ecb,6095624e,7fd3d210,c9578dc3,c0a54524,f819d640,abaa4a04,626a46da,15c0867,72774a59,6ac6c37c) -,S(1ef12317,513b1354,2a966981,34edabc6,fd4e6d29,1bd7782,5bdb30f4,937a3fa7,e0e4b688,a391bcef,3451cee3,36a8c9f9,12319899,4684c039,909489db,590e1ade) -,S(effa0403,766fb976,dbec6b2e,332d2f12,9f463b86,8b9a1d19,49d30cea,1606baaf,8c5b1c83,bf3efa64,f38de1b7,da03de17,b0cbfdc4,5b4a03c2,38221def,bc1cb082) -,S(dc9271e9,76a9a042,5565f022,273af5bf,20bf780d,9d0ea069,df5da661,a087d65c,dc8679e7,b27bd30c,986f11bb,1c73b76c,55ce7c7c,621490c1,944cd8a6,b63d6063) -,S(ae1ddc2,1e1ca02c,218f6946,275501d6,a1336b93,ddb1b2,384ab414,b8264619,21c6b39d,300b6125,ec8e5c8e,19aa76d7,32466bc9,a887c76a,1ff4220,7db26b48) -,S(aea2c00f,fe5835c9,2b892480,83164635,33dd989,bf2bca12,85cce3ab,4e82cf5b,615598cf,935a6112,42a20e84,e670b193,9aad65d4,53ba967,3e8193b2,93dfa97f) -,S(913d0e16,34b43a86,f55b30b6,5914767d,b45e723e,636c866b,6348c8be,8aebf696,e14c6607,51affda4,d02574af,43172024,39c0c10e,148d4305,1487a5c4,39971a9f) -,S(4f0b3354,775cac80,5e0d6191,6bb0f9c8,40fc163d,8878c05a,301252d2,3bc26fc0,b0b75486,3aedfdf8,3a6eb2eb,5f3e25f1,6c0e1077,6e855ac3,fa8fc3f3,bd8da1e3) -,S(5da21940,73cc978f,7673b2f7,5c65ead2,f469df96,f80883b,181a3da4,f316129d,8516d080,743d2670,570d5e63,e19eb543,237b1db,6285b1ea,f3bc1459,8ef311d1) -,S(76e1b330,ca7af91a,ccb92fb4,63404d36,a8fbc132,269d163d,d4beeed1,6be74a23,10b39253,c5908ef3,ec96f2e5,2ffa0dec,2ce2800,31a791,bcaae0de,1e7f5326) -,S(c4be488b,2f210ee1,82f91263,78b23359,8fe8ef57,671ddbe1,d76975d0,ee393e64,bec1392f,a1a09a54,480beadc,b98ca024,b910cd70,f807eaee,10d4e270,bb79f449) -,S(546918d,a141fd77,b1f13848,d3d608c0,25f5be00,4d36a542,56d0ca5c,9333ff37,3d1d4c7,9684be1a,5cf00d71,6cf9a1bf,b0b82ba4,833704dc,c2d23e8f,39914ac7) -,S(cdfc6fc4,2c51ebd1,2df368b0,98ff0f40,2e6df8b1,9c67e10a,320c1960,266078de,5985e930,23e5264,547bef45,6b3774f3,c2689411,b6f7463c,febe068,fd89cb0d) -,S(7730fccc,593b14a0,6f21eec6,2408e146,36f0e4b,4718ce99,c99bbcd4,7cf03034,f17d0fe2,736e412,9c30151b,492aa7dd,52beacb7,6f97001c,cc28f991,3e016b72) -,S(8aa4c3de,474308f4,674c7b55,9f895bc5,d855a7a9,5fadf090,5726b354,7941b3ea,f275c44a,eac2623,1bf4ae9a,df403ed2,78d9da42,150c98be,7dbd5f71,5cb8594d) -,S(15926da4,97a4e925,8976f87f,f8940491,f32d33dd,7855b13c,5cb54d10,d325bb79,15ac60b6,5b1ebfa8,e871bf67,ec9f71b8,1aa03c78,82880d40,d35f16d8,67ce8e51) -,S(55f4f4fe,aa741574,79462b48,f001688e,fc99f545,d4566dbb,35faeebd,f5b1710d,80ecea05,63f24c84,e767b894,57dfec3f,d015a4ad,b6e3fe0f,662521b4,bb02d15f) -,S(95a56acf,402f7f33,fa357c4a,e4db337e,f04a60d7,4cd73e0d,b137f68,e0e93cee,e72405bf,b7c9ba84,16f4e72c,a30c9ae5,d21c89e3,ce5b61a4,bd521b4e,ef6501fd) -,S(28a9fd90,b50d7bb5,13034b7b,c36a9783,c2a697ff,499bcd6,4b0881ab,8e7a2aac,76b151b0,5c7e7ea4,9a263596,81508781,a37cfaf5,14fa1720,b583faa3,9794a788) -,S(6406dd13,6d6462c4,a4116b93,eac38eb0,b571e2d3,99cdb93c,b36fa5ef,e734b672,3974c77b,92b8e614,52d9c9d0,62a911f9,b4c5eb1a,977da74f,defea358,5dd7fd1e) -,S(8fd8f23f,cb62e1c0,94fef903,9933747e,9d40c37e,376703c2,e3c8b666,f1066529,8b0b2f9b,de10175b,24a9099d,75926296,5ba19013,20912baf,3100e057,d4ab5c8) -,S(51780a2b,d4457368,9c0679bd,c8c94e43,cc525bab,2d2723cc,3e0eec15,63a1a24b,5026cd9b,e178d1e,c746e5db,29391c4d,4b6b08a3,3530fdfc,64603fa2,f0e01109) -,S(aa01493a,e7c7f9bf,3d2fe0e5,cd939dca,5b8c8534,6848d065,beeb42a9,8c283561,a08f0b45,4a42b5e3,6463af14,5199e3d2,1783e908,b3e130f0,e9e88110,2cda82d9) -,S(cd8ab749,d4bbe6d4,ac81c4fa,d6a27e81,e4456d4,196cdafb,97fa6053,18ceab70,fc6c7739,bd68a20d,e01c9249,3cd7ad3d,ca862183,b0529231,da32f1b8,5df59beb) -,S(e69cdef2,e824501e,7a17bc54,e0bb4886,379f56e1,c59a27ea,e00bec5c,55fe3e32,e80ed10,40375398,10125338,f6291791,3fe735e6,6c4bbc80,f41d858d,8ac41cd4) -,S(5a4e72d9,182b1f7e,efb08af1,9e3181cc,f6b6ec69,790184a2,f30188e0,dbff8a8d,2d1cf7f2,d5a857d8,3b31c588,5ac33a5d,7b62ea62,7b5b0bee,2d912502,2df9da19) -,S(9e000859,48bd6211,410416b0,3920a79e,d78f154,5dd0330a,8f23d1b5,f8984a2b,36ae0492,412fd3c,c230680c,edb0dfc8,151ab85a,d8d3338,db611674,c88e3f62) -,S(7e0b97ae,b12f8734,ecad35d4,aea425c7,99f88485,f0bc8d18,ac82f213,258bc6ff,e76f4e24,a4be1b6a,3fc3b0b8,ab0b6e5c,ab95fb40,4692f7bc,cc7640b5,69f3946e) -,S(62285cfb,1bdfc495,dca81ff2,867878fa,b3064be5,81be0c86,b9336c6,61038ee2,f2c91be4,5f60e9f3,40e85ea0,8f159dd4,a65ca8d8,21a6e4f7,71f4dc17,849b5161) -,S(70234e81,2de1b5cd,699870ef,36d5c19c,cd3765ba,eef3cac8,6f126a,a6c82623,e2dbf98a,f92a777,263f3c92,4738ba,3140f769,fd5b6ec,7139bb8,41330736) -,S(ae770461,8f31d5cd,ede40ef5,7434b0a7,7dc1b4e6,7f4be5e6,136978a7,cd5db07d,a4e25164,65584487,3f520e42,74037c,5cc43e12,95167b01,d46d3e93,d93d16e6) -,S(cec7ac8f,e4db698b,48ab78fb,768e6094,5b7f4ce7,d643e604,9e349b6f,246f2b53,491bb545,99330685,433bfd2a,7a4fc831,7f5d3cf4,80d6bc32,5ca6d001,b65fadfb) -,S(80276e96,b051e49f,276f62e8,35622979,852e4cf,c2ff8665,8db4d5c7,7c5eee36,f510d696,882589f0,870d526e,5f7513a4,2c4d4ce5,3733f30c,f06d7dc4,f42f6d9d) -,S(b19027d4,9d85faae,e6163934,ef8f8508,e9e351c9,82bda741,b8944317,da85b27d,c12461cb,dec0e69c,b378443a,f2eb042e,8439f812,205742d6,dbabb372,ea47a824) -,S(57599d4a,cf07c001,d3d3fc78,aae147f1,989c656f,fbc43081,29e05b2e,570c792c,5cf8ea0f,d215ba16,e18e181b,1b4b4f02,38b57af3,9010ba23,f13bbdc4,18514b0) -,S(5ab76283,fa110b82,c53cda2b,653e763c,306e6f8c,2b07d490,bad6e418,eae6e4b7,ff365643,cc2a78e3,17a7de95,b37b3f83,aebe8272,4162a884,f7437aba,b55e8ea0) -,S(7b93d9e4,8602d7b7,ea52dd45,fa0031de,66ea88e4,4250c898,64903e7f,959d4a85,99ccb201,5ab91fe9,a0f50a0,fefad6c3,f6dd060,1f2ad099,a4851d33,162b52f0) -,S(2d5878b6,af642776,41101be7,2b37b4b9,1de26a21,b9610a93,7ee2ce2,fb96ebb6,138ee05d,df4b004e,820815d9,46716f2c,a887066b,b7d218f5,47d4bd7c,2cfc585a) -,S(1d637068,eebc32da,24a0fce,2e41cb57,cf1ccff5,38cfbee7,ac13269c,e560af3b,6a932df1,a2896445,6685ce54,2ddca0ae,d589a494,b7ee89ed,1b4ccfd2,c276eadb) -,S(82babb6b,460e1235,f3187a68,912b057,26a478ef,fe929a3,9479cf04,467de64c,3a9f4e33,603d0396,1f3c11c,94d58369,5de43a1a,327d0faf,f51089e1,1345647f) -,S(ae86e71d,4e715bfd,b63d899a,9daae610,a01c5134,c1b9262,c276dcaa,b48090a,3564b48b,fcae8f7b,feac4df9,3b458678,6f2f9e83,9c9c6126,a301de29,4cfd7b5e) -,S(35a5c2fb,fc661cc3,f4ad6ad7,f1eb32b6,664c50bc,91f4000e,f5774364,2aa413e8,4a5029a2,887f6648,3e072782,68a81c85,b901d692,4ccae752,7111bcce,cad6cde5) -,S(386bf07f,4dd508a7,61e7c29a,dd251d9a,76324496,6c6d760e,cbc6b069,5858e2dc,d4f14804,9c1fa038,1d903e19,68fb14b2,f07c621,15a81f41,e811ad87,de407696) -,S(dfec381c,9bd6f4cc,50ac445e,c9104d87,f9c46c7c,cbd70909,fabde6aa,12346f96,5e7344f8,25b6649b,df97ef3c,ad96945b,d1ce0f76,a48b7f2e,56ccff02,797553f1) -,S(3606dcc6,4db04cc,5493e0b7,ea0bfc2,f8a24302,d2358aaa,7c1ea8,842abbb2,a5c8743b,bc4d9b74,b8b569a1,feca3667,87eea8b1,be2025ed,bb547e78,5687301d) -,S(3441e737,e19096e2,9a3025a4,71d192a0,db086038,8e76d2b6,66052825,e52b0016,6d10f7e,d5cac98e,73c3ad47,bb233a39,5eb9bd4a,37861b9e,7dbb60f7,81eef0da) -,S(b2c97c2e,460d8c34,b5ea7a5c,456a9cf5,b1d902bf,5cdff030,25410a,26636e99,67133081,a8c8ef30,753417b3,cf6973e2,1f151e1f,27216bfa,23289ea3,e2057b7c) -,S(2740bd8b,59a43ddc,f8ffdabe,d59027b5,9b7932b7,3db45a97,3b6c1501,57e045fd,8106f2b1,f69f1ad4,2c0787a6,3c137753,987aabe4,b0ebd82e,1ea7807e,93b02a85) -,S(a1acffd9,bdbd94c0,cd8b4f40,3f9400c,aaa8e269,d8cc49a6,9ee565e1,89b6c21b,62ec7d7e,733f518,974acfbd,4f4e4f44,bcc4fdc0,cc194a66,df7c16bf,ef0235b) -,S(50bb2ad6,8d524acc,3278c0f1,538d3aad,9a5357bd,332d8cff,6301f417,57349847,d8fc33d5,d03526bd,b97d4c6e,1ef018ba,ba4b33e5,9677f139,b8535287,fbacfb32) -,S(ebdfb262,6031b4fa,d675e860,12288101,948e2ca0,8fd0d32e,c9fd0838,5f4fdbd9,b078066c,c470113d,db3964e4,466e319b,4f853a42,8951aa0a,9c4629a7,a40dbf2e) -,S(5daf4c23,65482a2f,bdef73e8,208fd5ad,d57b35f8,171541f6,3a48b742,e98bd48f,9015bfcb,5a248607,f5ffc83c,4fa3dfec,9cbd11f2,c230327d,b2cc75ca,2e87f967) -,S(22db9c20,5d840814,67a19517,f353f825,238c905f,2b12a77d,8551cc9,ee8533c7,680a1bc8,23432a28,a3219264,2b9acf0e,7ad19e29,b604631c,85f7038b,386dcdf8) -,S(404435d1,2e8be51,92625213,f86e6e55,9fb44658,44694d4f,4db72861,d4c100ae,9ebce682,b321eefa,e8e04776,8f82491a,dd734e5a,941e0f4c,b6284f78,6d1586d1) -,S(dcc36eff,6831a6de,f8600d1a,3d52da1c,fe59df9c,cc69c9f2,60c26532,e837530f,8609b5e6,7360b7e8,5ea98c13,578566cb,b6b385ff,6990d4d6,5b795acc,1f77a893) -,S(ef0dfb94,1a1c383e,4a44cd04,c633cb48,e991d140,45e2d9a8,b4353e79,9c1a1514,2685d60,f2a75f9a,b733afab,f693ed05,9c3599bc,3e3346d4,61e5c86a,f76f6f42) -,S(24884cfd,c6c3efd6,b4d2e18f,2ca66b06,410b0fba,d9d61b30,86abc537,1d766b8a,7c1cdc85,66f3daa7,d395c6bf,8a23c130,86a78619,aa68519e,4657b17d,ace2267d) -,S(541b6691,c7004a81,2c607756,f81b6f05,485b0708,678d9a45,de74632,4acd8b20,ddccf301,8a3c429a,c749f0d5,2383784,cefff3df,ae98517f,c7f5e764,c5c609d7) -,S(5462969,67262e3f,a905eea4,ff1f8296,f792cfc8,bb9dbb9a,138242c1,a1fa822d,63012289,8e429527,4fad8e7f,9865659f,da2d7370,10f6e185,70dadbfe,21e6880e) -,S(94070912,ad2c129d,cd122bb9,704616fc,3ddfd949,6ce9f6d,6e18020c,ec848e83,9c3b38e5,6bfac9f1,4c901080,b5a732a4,b5d261f8,2b571536,d1fba6d9,b714017b) -,S(2a6330e4,8ddc661e,afa8071c,c1417b92,ea73b060,3653a017,3edb92a5,6e3ca6c9,b38c51cd,4754c350,ba2d56a3,fbf4fbab,5802bc38,6b5516f3,d8b761e3,c3fc7d79) -,S(9142e493,5f95da17,5ae4078c,5ff5a7d4,8c418c1c,7efc4c39,dacb047a,d3f7424d,15165a74,c47133a9,e8684ea5,5a4f9b05,37d0ab7f,58a7eac0,e698adcc,b885cd05) -,S(2e198b29,5cac4dee,dba63ef3,888d47e8,bb8d372,7fcbd69a,d1eea656,ca85804d,31dd5db3,e700ffbe,152b0c2b,1b1c830c,eb382468,1c522e63,676b9ec,6780fd52) -,S(b44e35e9,b2efcafa,f123e52a,7bd9bc58,32a671e2,fbf0264e,5a3f536c,b272f72d,8d489fe3,beb39fd4,2632b80a,1243e64b,f80c81c1,3934ab08,71c16a5a,5aa43423) -,S(dc99ad01,e1324b6d,b5ecf365,c22463dc,f609f0b5,90e6d3be,efddf641,b83a3cd7,b4b422ca,2feabeaf,32c0ad6a,4393c087,a4c1e794,47a043de,cf0fe486,ed11b682) -,S(e174838e,eb991c2d,cfaaf89b,b868f4d1,3029ebfc,ea286376,48fc51ba,f962a359,f80dcc87,27cbddc9,4bb1b60a,4da5cc74,238dc62,821a9ec7,c05ad2a,a0e7570b) -,S(6240358b,15bd16d4,42cd79a4,8b739eb5,4ca21d18,b568b497,65d10dfa,a2583d33,6acb054d,724e7550,ed6d8caa,8a436d51,fc546116,df33413f,a613c0dd,6cec2d00) -,S(a757fceb,560aac0f,543a29b4,bfd3af7a,aa61c077,2c1c07b2,e6268342,e63f8d70,5864ceef,f80855d0,fb4713e2,7bc6a202,b4c07450,6749457b,39d0c40c,f40352da) -,S(f36e1073,57c3149d,902e9416,2e509d19,d4b1f498,bc74814,3a1bd411,2f777bba,d4d7da2d,139a2693,e40d9396,76c3fe48,45f74b43,78f0c25a,14aa9698,3bd1993e) -,S(84ef2d4b,55a40ff7,13934949,b6277ef0,4a8e0e4f,cc49420b,17269d59,224af99a,57affcb7,1d3508f,65ff2b7a,b1d6752,60465e76,754efe3e,80a83085,85ea73a6) -,S(138ef64b,274ff66d,7defdca3,4ff28bae,96b046df,408b3f47,84f78784,3fce7576,ebdd04e5,1d517c43,412010cb,d03252ed,dfe97912,ee4a7d4c,ed98551b,fee1ecf1) -,S(e82f03fe,2ba05692,212a1145,550d3057,2d454728,e2d9989b,435cb608,3d1f318c,191a6fb9,cf295881,92aaaf1f,ea34e123,613b2937,602650f2,eb25f63f,5812dcda) -,S(56a68400,676b6fac,7eb5fb3e,7f345ec0,11117098,c0d1a96b,e44bd2c8,5aafb317,3a41827a,5ae1b7cc,5b9dcb5f,4c41819e,f49ff2fc,ce1d1949,3f5b0ce,9f1dfb4e) -,S(82f5747f,1b353db4,f3afe255,e1f2660a,8f735b1a,e40a5008,4efa3c32,dc1309f5,42e8b903,f4ccc01f,7e87e4c6,71572bbf,d05f9ea2,a4cf7bd7,dd5a9906,264a0144) -,S(89136941,c47b1964,a4b89e0c,376b3136,80ef76c1,19e02bb,bfad594,76e0cf13,b3a2a785,fb6a564f,f4871bc5,177c635,d722e659,77f621a,f6f7537a,2c2d3f3b) -,S(c6250969,c98f580,f0cb51,eef5d8a1,b9954bb,97671df1,c7360a5f,42238909,83d0324c,915eab22,4dd3f935,e197e0e9,552d5bd9,6b1ed240,219731a3,58ec724) -,S(e2399ad9,63913200,4664a481,dea99d85,ad12938d,dd0e4184,27411fd4,8fc7e3b4,60fffd62,beae28e2,2ea836ed,389c3780,5d8b1fa1,fb10f298,f9b54df8,93c69d47) -,S(4d00b1c,186d2992,9a6383d6,cc8d1796,a59c5d7,c27cc7b8,5a1f821c,3003d959,8752ead1,27eb19fd,49dc8ce7,a0b7c7e6,dd4aa3dd,6f8d5cb4,687327e8,ce487640) -,S(344663ef,8b8b52c9,1aa548e9,8b7e1c48,933cbfa3,59644318,5ea973ae,9264121e,73d099c8,9dfe8eec,b957e624,bea5673,6fe3885c,e2f72b06,dfeae760,514d9efd) -,S(37ff484d,dbd22a98,333038d4,7949b4f3,f411d3d5,7ca319e3,5c788bbd,a0de6648,55a5394b,51618d81,d2fb1455,4ec1f5c3,a45cf086,83980bfb,a9aae6a9,20547c67) -,S(cf3bcddb,ad5066b,909339d1,4cc6d3d8,d2881f70,d6f12e1,4d795b06,17556ca5,e12686bc,99e20f20,6220e402,32760224,b61b90f7,8b7c0b1,3c197a47,11678a6f) -,S(961d02e7,db8fd1ac,a38f9110,13d74a5b,d35e47a1,49818d41,49f02edf,5da73402,9462eaac,d698677c,16515ca3,bff217e9,765dc8ad,fe2fa82a,1db05158,71fed240) -,S(43e62f90,574a8e65,25d22ca6,74814ac,3648b724,45a535c,5e1af97e,b46ec3ba,6def0a56,17c1cf17,9369e20e,d18d0503,e141dc85,9edc73a3,18f6a35b,3d939734) -,S(9e682b79,9d79018c,352113cf,98de93b2,457e4b4,a962d160,33b80052,57dfdbb7,9db9cb16,bfe96343,89c468a0,6405d2c9,b2983354,ee9a81e9,3f23ec5d,5049041b) -,S(790187a7,8079b59d,b2a22d13,8520192,5f9682e4,2002c8f9,436876e4,d5a1a8b4,25c8b46,f6b43180,3654381e,56a8e6aa,ade0ad1d,6a6044de,17e9592c,affa456e) -,S(928a4b8a,6c744b33,99e22d65,35a21ffd,662a0dc3,d5bab1d,683ce555,f0169583,251fee84,c064954b,e1daf7e4,5fec87a9,323d55f6,687fdeaa,75d4dcc9,9a6fcf84) -,S(684e88da,81182f2c,ac5872de,8c98b86f,a6ffb73e,9bbfbfde,6c16c3f4,be084c88,c451b59d,fc9d62d5,921ae45f,f7557ab3,ad179eb0,6afb8bb6,bff0645,cf6383fe) -,S(8bdd2e83,a403b0cd,7a8ebfa8,6949bceb,8e8166ce,a8596f6c,ad7b7bfa,4d174343,7220c147,97f682f8,7d707b2f,eec937c3,643bb359,e9effbad,8ccbc8f,a8177172) -,S(c3fa3b21,6e3c4952,85258ef5,f921f6b,b7195869,e46948b4,b69e80b0,be399543,eb2044ed,21f6661b,77088050,3026c2c5,5a519ca1,748bb10f,c8eed953,aec1796) -,S(1c063c13,eb2d2959,379fb0df,50d355e0,195a8bd2,e642ab48,3d6a38a7,af7e63a2,20538f92,d14c9ff6,75c5005c,8c40e26a,b0042874,7f446ed7,cfcf5737,870f2abb) -,S(60c06797,7b54c18f,4b82dc6c,227cb539,6c6086de,107e3999,81f1b5e0,f31d452,3f4546c4,e3eb11b2,e6fd2617,b57afafe,ce0e8bf7,aacc13b,73755f18,dc98429a) -,S(fc15cf99,92256abb,cf263e90,a231ed8b,421cdc2b,af185722,c0af008b,fea36856,abe346a4,d9c40853,70dd46e4,69a3bf24,c01dbd97,f5c9997e,27634dd7,c635d798) -,S(f6143985,18173bb7,428da262,bc8b07b8,1a92b06a,65926ee5,c6f8fe44,27249454,b1d832ef,3a2558c2,d41f06d,4be8e5e8,11fcede9,9cc784aa,b9f3ce18,d701cf84) -,S(579458a9,62218442,41e68542,76a116ab,1f1fd43,109d4bc7,ad5216dc,ee61b5f5,33e56474,68c157c6,15cc8d46,135bed70,21274a4d,97aebe23,7bdd4b61,2c53e2d8) -,S(637553dc,b0804132,b5562678,fe355e8f,abab2001,fe17e3bd,8c051e7a,41fe62e7,28bd6dc2,ad586e1f,f1a6a951,167ba14f,6989b296,874e0d3c,31917920,9b572dce) -,S(eebbd70f,6f64855b,e21ddb92,3e54f583,89e99ddb,577fa8ea,66c3722e,b580e2a3,3d1b6979,15b50345,4a55606e,ad3ac4ec,7c986698,3df60e1d,edc86827,32fd4d68) -,S(4ec8931f,2bf4b1da,6891135f,37791236,3a6e888b,6e5c5ddb,2e350e42,686c56fb,d5f6c679,4c2b306a,bd719770,48dc3e28,3cbab910,556919f5,35d9df23,56a09bc7) -,S(6b5a7f76,fc5b7e7a,7d84deab,ffd5c771,8f49375c,cc4dc1a7,35bc253a,bee9730e,1e935dc4,8fbf5f6a,b12562df,11855757,9eafb8ab,f6ad8b7a,f8f9df64,43b58af8) -,S(2a3129eb,f620958a,4264c759,17e29807,5f5b73f3,21d4cf27,683e4788,9e013af7,e940f5e4,c1fc28b3,fa346ede,fdb8ac7d,4066732f,a6c276c6,89a1921f,d1020da4) -,S(8bfe81c,e99443f3,78307f34,5bf2c826,94a8723b,c4836d12,4c6f5163,bb28b5ab,58b16e27,857e5faf,9768edc2,68d177a4,87de9848,52e65348,36464ac3,f0433c71) -,S(47820cd9,449c566d,2d39daf3,ee4d356d,5423692,a050cf83,1c1337bd,8ad61be3,48dfae03,2988a810,6d069d,22f27445,1200d38c,a9aea665,5e5f28cc,9952c2e4) -,S(2d7f03ce,8e453605,89d221d8,84c3ef28,f9e8dc52,41d7d131,cd6e9921,55a934e2,8414b3c0,5a39f38e,1f14d55f,e28604f9,16a7b272,6d6c843a,57a2b8e8,b7ee9c72) -,S(83887cec,919d8c86,c2150d4e,e842505b,f5a5b06c,b3b1e67f,1dc2005e,99d8e37b,fee0e7cd,f5c9eae2,78d34fe1,2e58845f,fcea9de7,f9883e32,7a2ee941,92b4c009) -,S(519f9e1,138bbab2,da8c03f,565c3fe0,a9d0b709,1a7b50f3,f37df191,d1ca1e24,64d6bafe,2bffce42,3f631ec0,781e96f5,ef6cd6a9,ade6b9eb,367c036a,1a61ba9e) -,S(8091f78f,84bc74ea,69ade208,72936152,3946ffe6,63edee6c,3cd13ad9,4a8fba61,1aaaa58b,af84688c,1cba5d90,d700aaac,6765faec,39e7a212,fe13a9cc,b0bda1a) -,S(50abc00d,d3fe5748,7c2a5343,4a36f10d,8388cf20,56cd5bb4,9ed8e97e,7adb3afc,ab8bad95,14b6040f,b1c64f01,d9b9db01,670fe0d9,3add5d6,8a80e41d,8ded25ea) -,S(a9a428bb,4da01f44,a9e4f253,3436ae75,20e5722e,6d12931f,aa20772b,36a2f110,ba05121a,1830a26c,440f0582,2fa53e20,f8c226b6,85b437a0,557c8450,774c0c5f) -,S(d7afdbd4,6314d677,727fa11b,211e99a1,d6948be5,b7753ecf,64e9b1d0,ac7a83ce,b5f8b97d,748a4abb,a390ed9d,79cb42ab,ee9b2afa,517288f4,80aba1cd,34e21d04) -,S(2b6b834c,d2b54466,a3d41694,b672ac55,13f19b1a,d518ba99,d622abfd,9b6de265,c1922593,ddc0b3d2,ad1d52dd,3cbeb2e5,74ec849b,892d9df1,87ccec50,7ab9b0d6) -,S(f393cf4a,d7f93fa3,1596ef7e,a9c11c6b,f29c344b,1a3ee5a2,51360c9b,a96ac8ea,4e811ca9,de67ceeb,90e48016,30d06125,fbfa56b3,35e3a7ec,41bedbaa,7a8133e1) -,S(bc3b9250,4e14b254,81305012,a248a94,bbc546bd,52fbc0e,848d75e,9c8f418a,9a52afc6,f8b487c1,7653a911,f11d78c5,8f5eca38,c761a2d9,af0ef2ad,a6a58223) -,S(2f5a0e73,c601fb8a,7321e170,4abdb1f7,e71edc3b,bf6f9cec,1467eef,5f6055c0,d8bb1d0d,142d2cb1,3b9d97f8,f807212,b79a5ecf,13d942eb,c5a3f442,6553e393) -,S(b83e51e3,b4fc69ac,84d099b9,6916c11d,8d8d8d7b,f5cbe15b,fa13ed34,73a54ae8,232e0f88,69c53923,22018084,a7cfc251,daeb7a84,6e1daa78,f3f365c2,ca3dda5b) -,S(10971993,50b07a32,1532b372,2ee89058,e90e9b30,5908cc0e,a249a40b,e7516377,69a0b67c,7bd55a04,9be3a3a5,e308799d,dc735f9,ce56ff67,2c796b6e,5a0a1055) -,S(dbeef75c,c95d5018,f3d71711,a0299dd2,62250814,c1469647,dcb27a23,e85c4477,dd4712cd,16334f8e,2baa6855,6c5237f8,676311e3,1cbf9753,35e76a90,88d66413) -,S(28cb1199,2bdee938,f3405f18,537b410f,2723888,e4ca0d29,d96806d5,6baf114f,e6c63fe,bbe5dd81,e3a9fc1e,83a5ce89,c3e2ef6c,c2a57fea,695ebf4b,e81e5aa3) -,S(f0a2df0b,64efe99e,65f9f176,89cec5d4,caef385a,e4676da3,790ba2e2,4e9f60ba,a7ca7e08,b900f664,14498c12,aaa77da6,6a2520,7bcf1a85,713b6d14,807a4519) -,S(d1bb46eb,38e54396,dc7ad4f,f553106,54fe9b06,9abb1410,799dffe5,482b0f00,14b0619f,e08830b6,d0a5463,96826b6c,d03bbd2c,af930b14,a031f922,eace4214) -,S(27bd2e56,7705126a,5f5adb31,ac1d09a1,85d74002,c548a84,15c0cce0,1f69517a,12203dd7,cba21cd2,9f9ce428,a8e302d7,202690ad,8734c08f,65578192,a5468d32) -,S(6b2cc790,1c72e201,693835ef,ab2b676f,55441add,b8dbc3bd,61d43201,bfd21d9c,59973406,deea0493,daff90d4,b62ff38c,6690bb05,18e75560,1bd5b3a3,4add7456) -,S(75e85c3f,32f953c5,632a8bcc,6bfcd6bd,c63c3b93,e607d267,5df09fb5,94840f27,22f5a376,8714c73d,96b24f89,d426e668,bc59aca0,cbf6dc47,723f01ed,6cb6bb30) -,S(d37a3071,969e152f,41c0eed5,7e28f1e6,f26e1752,68c52683,15e200b9,f86d56a7,53d52726,98751d1d,dc4b1fb,d9621723,70e296c3,b47436d3,abe20356,76ff6181) -,S(715bb304,7f5e6973,36546640,8e183bb2,67693198,94e341d2,37d5101e,a7414976,28440f5f,9e82d5e8,7a5ea672,2e95c3d6,a89dd1fb,3d81aca,db7609ee,a1a968d4) -,S(f72d142a,4f5b1595,a7b4a52c,c6812ec2,8e4924a4,b087c139,68d8adf7,dac642e8,501b644b,b5d8042c,f16ab9bb,bc594c14,585486cc,fbaf47a6,5378f97a,761087dd) -,S(7b3eff8f,b4ca8a3a,5fc3cf02,a469f34,3840846c,d8fbff28,243b962,c1284c26,be2588fd,15396124,a50bc555,5e161022,3bbf636e,fd510522,811902b5,b1748579) -,S(2441a8d7,71fbeca4,cd365225,7974e4cf,ec2a7035,ff2b58a5,9cc5fc37,8a113dd8,54b0776,5316713,4bbf4c6a,7ac23360,fe035d2d,9316cfcc,ae129893,82447981) -,S(c20fca4e,d05467ca,45b916b1,2f4ab386,512d097c,b64b824d,e78e9a2a,14cf7591,8851acc7,96ee4072,ca87e69c,9dad10e7,931fc48b,238cf46d,2b2355a,e4eecc02) -,S(2f6b0e8d,1375263,b74e415a,ad758130,a34c6c6d,690ddd67,63492eb2,49ec8e7,d0c791f8,438cf6a7,976cb614,eb4c9f67,adc72275,f6236868,e384d538,daf25dbe) -,S(bfafc1be,426f056d,6f8b3ed1,1374db21,fc00373c,3dd8c762,c5ab91ea,b2b665dd,9c41f297,a4cf003a,7fa7b071,a106da4,6dc40050,a7592781,68436115,150e2a2e) -,S(cf711dca,90560273,6d776f86,759d74f,895980f7,1728dbe9,1df93076,cdcb4e8c,52a379bf,cf25216f,e3556def,e889b23e,2f91f6a6,47ece012,4e140aa7,734f1cd5) -,S(b9be95de,27aaf198,c3001ec3,63690f2f,f516fd75,1864794e,1c3516c9,abd1384b,68875f97,dca1dc43,3e9b614,488cb8f8,1ff85d58,2ba853cd,27fc1227,1ecb6df9) -,S(f5f257e6,c4d06a8c,53442b37,7519ae03,7bec31b3,c257f331,fff53773,28e9638e,b6a1e60a,48d03213,bb52e3ed,d20d0ca,c80beaec,bb40169e,35ff2165,43e986dd) -,S(fc35c74c,17e38aa1,15803603,30af7d92,a5281b3f,cb6cebf9,df09155e,64099ce7,6e2f984d,41e8693b,5a4c1c58,9814d131,8421fbbb,2ec8e45a,c6239227,db79dae9) -,S(ac135e01,49d97363,7405e5a9,89ffaca6,c1bc18a1,cce34aa7,4732fcce,d54384dd,3e38bacd,ff954a6b,6bccbf63,9f8d709,d8e54553,6113dcb1,c471a162,af021d0) -,S(60a013fb,efb3c5d7,802400c4,e791a019,bfd8f657,cf4c1055,f3674f92,9f5f345d,7e763c48,3582fe3e,2a0a5138,ca320013,9907e364,5468b5b2,711205f3,38a1bd97) -,S(a099a106,5d907a8a,43a3d027,3a789992,ceb3a659,bef93a9,6ed04ea,19a7acb7,137f9ffb,fe3c22ff,c034bb57,9f0c9b46,d5cca4a0,db1407db,6fe3d7b,5bc5a50d) -,S(9ba1da86,d02763d6,187ea5a8,c11c9da4,c6ed7017,49f107b,9ef4fc3,94a792ab,f19e22d8,ab5459c5,5bf87908,90175184,8716aea6,5c2d9650,c472199d,6663f741) -,S(3642701a,d30d1430,17be9363,3f28d90d,b5e02238,9350934f,63a514c9,a677ada0,2fdf9ab9,c76bbbc6,c4e79f48,7a8bbd86,6432fa98,4f52ac22,3440de3b,f1aba970) -,S(29f79c58,100b7098,d8d53012,e2c98719,6188c0d,54712c31,c2ea3a52,d6941a5b,be9edd99,eaa6c1bb,d0ec42f,586a2806,919d5bb7,2d59bf3,7216890b,9a2d524b) -,S(e011aadf,bc35284f,816d5030,c3feb350,4b470d0,ac5ff061,e5ed2c47,89ba1bbc,e0a98f93,4f2b591a,36e6ee97,f293be77,21ec1a9,3f4b2700,55a0c01a,3cc979e3) -,S(a5c8816b,fe5356,37eb54b6,88b9221e,ee06a51,77ffedfb,3ed96ee0,4fd78585,3f86637b,9d63b11a,44897792,9a6aed53,7d65951d,aed6476f,e03be5a8,c9ff8e5f) -,S(3b952c23,7e44350b,95207798,e708fce6,2e6d49e0,912a2509,abef16c9,c7194707,f784972a,419e6c8a,c9d41a38,57912e66,e6ebb631,6bcdeeda,ff49b59d,bdd68936) -,S(8d9796bc,d9d8152f,80c7982a,187a4aaa,b75dd611,99f86632,72502f24,dd57af04,fb9b1479,94a31e3a,28d5695f,2d689951,317c2d2,98e9892c,89c98202,b7e611bd) -,S(96b2bc5b,2f4e6445,1536f689,d7889669,4fde4d7b,6ef67f51,84517704,6a02de40,e0b76d26,f91982db,5039bbf5,afbfce51,914eee9b,352c178b,2145c4a1,88e89cc) -,S(9bf7cf10,9f129500,e2a8f54d,8658ef97,4e3ab2b9,a1d0d036,25bef5d2,432e2d79,2113d7ad,f77e1c68,51b8bb52,188ebd25,dd6373a7,19bcc20b,e32d0f19,496e8582) -,S(10d3ffa7,20375b5e,afc8c741,4d9aa184,c91f853d,61d58dab,11a04f2a,f3d4f1b7,c1f84b2a,8a96f43c,b215c704,6f8c3f02,c98d750a,d416f21b,eeb10ea3,f298c90) -,S(56d64e2b,6adf1cd0,b8d63692,1b68733,e92577e,88430e92,c0e679e8,c3a5eb6,1370e,fbe98423,488427c2,57d5e696,5d4b687e,25e4b824,51b1a6eb,7ef71cc0) -,S(fec4a03e,1c83cf20,75deddbd,20c24792,6dbfa352,a56821c1,420adc34,731528bf,a152b2af,8670e42d,3bba0d98,f387e9bf,1bab788e,fd7bcb2a,a787e6a8,bda95509) -,S(580a7517,7ccea9ac,63ae6d53,e8959e5a,a45d11db,29a87001,779c260f,2fee92eb,793be69c,3263c64c,2048c411,115375a4,86733a90,d8c12a06,862f4f9c,669e8edd) -,S(9286bfe5,78931ceb,cf97431b,1137a19a,991b46d2,d0dec2f5,35edb976,6af636f6,7e774d30,e962db42,83cb38fb,2053b780,c55fce80,51edd5f2,8cb1b5a5,d329f516) -,S(606d55a9,9b702652,5382cf2e,efeec65a,803e3851,da60a041,e5422c1c,28f4890d,dc895a6e,3c2a6411,4a04a1e0,31b8aa17,79ae2c05,1f4eee54,7f8a54c,50eda1a7) -,S(a16a0d40,833ec1cd,dcfef2f1,bcfc8ed8,11387dc6,4e4df6,6e807f69,75f917f5,548d7d37,13de4a53,151f32a8,2880d087,7fd281d9,63011388,ba991bd8,822d6527) -,S(5949d2,be574e23,9a3e3e7a,ae20726c,4a687a15,edf5a62d,9b79d0c3,4f9f0329,71dcb25a,167ab25c,311d9427,5480f78e,f7f4e777,9723e55f,337a9121,445288a9) -,S(841f4e4a,e67b0d8a,49d7b295,e9c1ff4f,cd1e2333,82101536,cef7c4e5,7968b240,1f561c9c,265fa4ed,eb979f4,a8dbe679,ccae8037,8cd73d5c,b56671d0,571f4161) -,S(22623df8,c748e9f2,88bd4b83,142788ff,faf680ae,a2640d,dd43ec1e,46cb7442,380ef00a,dfcdb592,f964381d,ce9f787,17d5827b,494c3aaa,d5e0e013,87a55da3) -,S(816067c3,6438301e,ea07a21e,5a60a17e,670083de,b3b66e2d,c88c6548,f45185e4,5afa391b,9a95e9f1,f04f4e8e,236fc39e,2eeedcec,45026647,f5982aee,4dc4cbf7) -,S(f8f23561,4745c531,24cf6431,ba8e0425,7d28af9c,2c196485,3546924d,ce085c1f,a165067,e3b41b55,a548c1b9,3fe76b5e,bd101275,acd29e75,7f66753,6734750f) -,S(21325584,e25b8a15,c25537d4,c70853b2,28bb933d,de04be23,7753b933,57f2f57a,3708c8f2,78ef57a,f0b00d5,17f21a6f,f627b5f1,59ba1f53,d20b727e,86e873e2) -,S(b2f4f7fc,f48519b2,c00c24b3,7ffac141,88b0baac,bc915c77,845cd6a6,3fdfbda3,b206b59e,6f52ee43,3e7196bb,5f4cf3c7,de49723a,cd5b3e17,1c94e28c,7d57702c) -,S(b4e65d4f,5f420006,b7c70fd3,9564f9c3,fd9c5c53,dacae064,62212fec,ee7f7265,307b6ef2,e3993bf4,f321723e,a83ec2c4,3c75b8d,684665bf,fc073506,816bee0e) -,S(4f104593,9ac609ad,25f3968e,9798ee93,aa58b61d,43f4bab,8f2352b1,de3a7240,ed8d87bb,988395fa,581698f5,c55a5093,ed9d0a89,3f4aa4bd,186221ee,7f8179ae) -,S(9b5e74ff,e515c125,9fa6b215,7ad7529f,90018e85,23888738,d097c016,494672fa,1d55866d,4c4e30f1,7bdbf70c,43fb3b9d,fe2df3d8,41e18bc4,3db3e3af,21fece15) -,S(77bf442,ac8cf718,102968f9,49387b1b,30f8a2c2,c76a2cf5,10d817c8,7e17e302,bb0f9e61,1d90046b,1d3b1103,e6c5beed,e4daaa85,f6eee1f2,6a6e756f,d32af0e9) -,S(27de125c,d49f2049,6b028f34,b16a9988,d2f5d469,30834fe6,4bcd388b,78c266a9,f43d86a8,483dd92a,2ad9dac2,4039ad2b,84cdfc2d,323979b8,1a43de25,5cb54bfe) -,S(21bf7178,ae1d75e1,94bb60ae,4efb5a8d,7f026cf0,7f845b13,2250989c,4be9c116,6caa82ad,bc21df15,d1744466,4d3b58f8,76b52291,5696481d,434f689a,edb8d967) -,S(249254,93ee016a,41b65b7f,8289da2,dc9100f9,9c0b956a,66d245b0,5632e234,bca30194,1cb51f98,1504c536,74f6f904,d883ff46,7aec96f8,2ed5ce31,7c45b3d) -,S(d3f644c1,e3472b4c,d46d89b9,6b937108,ea8e9425,9b9316fe,230e7538,7d867f76,91822603,fd629732,a3b37ed9,d5227942,2e536ae,316bfb7c,597b2da5,d8cade5) -,S(c8461f4b,e2bd14c,a88e52c8,147f656d,915c2675,46252e89,d0337f7a,e325b261,18971181,97ac799b,3f632868,e46efdf5,fa3b615a,a8a92b07,e38ceeda,9cdcae06) -,S(b6e5f590,be20a938,c1b57e1d,a7bd6ca1,a8c2406a,aaa5860d,9133342a,c395a380,a6728cf1,a2f2eade,72d86569,ab5a6305,cf01eec9,6a6de026,ff146d5e,7d8a04b6) -,S(3d25179d,465701d0,56d4eee4,b5efc10d,8b70138d,f14908c0,3124ec95,59eb5d6c,158b7bfe,1d61d7ec,633e88e2,b3c5897a,3b56f7a2,ac557c8c,3e032a71,8b95980f) -,S(abb5d54,c7171499,95893425,bda27f10,d8515511,91af6927,9849a597,46f94d99,4cdfebcc,3be28dea,36d06e89,ff4209c3,7012ff0a,d93d7ad0,4e454422,c4b9a161) -,S(989d0125,115ef9c2,900dedaa,4e31cbb2,f1243386,73ec624c,52352907,b325c73e,d3699ee9,945de070,fc1f28ee,14279750,d553df63,2951c0c8,d1668206,94c6c8df) -,S(c4c5c5d4,29c3d1ff,628bbe4,e0edf70d,5e05db13,c82a2af8,2d0e4232,5e013884,c2c76cb8,825188a9,fc29da67,70ade97f,ccee860d,d13323ee,f2ba7e7,efa97eea) -,S(8662d850,c623b65c,8db5080a,900a0e83,be947111,ec0b9edc,3601549e,26c0807b,a71d677,b0c9e7a4,f66a72b3,2918083b,f91e724c,cf8c9526,b3df0f6e,35da840b) -,S(d26fef49,7e7359bf,33309b38,93abbd44,543b73c7,c0eaa626,cbdedb17,1d083898,ad8bb209,bb090b39,6b501ea9,a5070f90,4d60c20,d48dbad9,56d381f8,79851395) -,S(569be8e8,c584b682,7d742ff8,5b402112,5b4560f5,f173c983,8f8785d2,229d8d0f,b09381a4,a8267d89,a8d5581b,f9a49d52,47c74a33,5e26e354,22edafc7,d41b8559) -,S(de34acc3,4d1787b3,ad967bc6,c5960d8f,842f82bb,c95aa255,d4a9e794,d30116d4,2fddb41c,b2b6b52a,57cf4d3e,883d3f0,e322c40b,ef098505,b6cb3d77,a21816d3) -,S(47430b48,76dbb762,6d549b86,1742a5b3,ece85240,70dd83d5,5446fa99,c5c50b1a,d75592ba,7004573,58c6a0ea,dc8ec772,b53dd048,8ddc73e8,5af357a4,af200df1) -,S(f1d1e0b5,e6687266,ba17339b,76bbab6d,8c2d8ffe,f6c68fd7,9140b097,d6e9fe13,a56226,fc233385,349c5483,72300f97,a1d8494d,a67db50b,b96543d5,bf24e580) -,S(22a6f735,76140de1,3dbd0426,e968c374,6e8132ff,383f44c3,c0515b85,f8cdbcd0,9dcd89a8,90270e3e,358dc004,40f95a43,430a399d,a8405e48,e69e3455,fbd18d1b) -,S(2ddc5328,afd8ca0,9bb0c6ea,57442e8e,fc307b30,c29e2867,b46654e3,e1a9ada2,7b9ab90e,db84e6e8,7bedaa6e,31ff90e1,7d07793,19977393,b5fedb73,c087dee4) -,S(60b6f839,a60af52f,d30a116c,58b9c65,1fb1c854,546dfa9e,1a01e2c1,95da0fca,5e77f69f,28cfb414,be39b07b,2469d8eb,b0e74306,1d856bcd,ca54d83e,20d26c40) -,S(2790c19b,9b9092e5,cb06bfd,f95ea43a,2a1f1f28,57c96776,dcd26a7d,ddee53c,fdeea120,d04e6e78,b2387afa,a0217098,de067759,8b2bc5b6,2715d9f3,714e7f64) -,S(e544320f,9ee8bc8b,127576b1,6fad9782,db181ea3,4514f7c0,d7f9046,f5113803,b93762fb,2397444,e69b63dd,9dce7c32,3c73680a,e26b5e0f,95211972,c0510741) -,S(6c7f25ae,73e428d5,860a236c,bbd4d74f,8e2706cd,69bb4cee,39f9aafa,db55313d,d8cb8fc9,e33f9b18,e9a0864b,e58ea921,8db30c4b,d5dff091,6a44b581,c8dc9121) -,S(289d1b28,ff710d47,4d1e9c3e,f3952f27,dd9eaa3a,30ef499,121ea53b,9b93d4e8,f36af80a,aebc2dd5,84cd5cb7,245b3cba,64285932,77f4be38,cf2b394a,ee880667) -,S(f02ab597,ac01d673,25e87b5d,29130c18,2a6f4a8a,d4ef7476,b9fa1da7,5910b5aa,ae88c02a,ecf28b13,ecec5379,5c34633d,d3262d1f,65ecaaaf,fe89640a,cce38adb) -,S(a9a974f,71a73106,57732c82,d6d4c6d3,c625bb70,4ec29a8d,2d8f8418,dca0413a,c20df433,eed4e96f,d5ef222d,860ed1e5,af1497ac,cfd1dc21,26e8925b,91b372cd) -,S(7866190d,728e0899,19a0e9c7,8634b55e,4cc392fc,1650471f,4a21cf40,8d77496a,1bb5fcd9,540422ef,caa8e265,c35a1e64,29d79de3,a9369b23,3512913,ac0cfd22) -,S(c8a7ffe3,44b3b8eb,f00e4e2d,e63d9540,25cc115a,9110c773,ce0130a4,8333b9ac,ca1ffbe5,10c63b5,674141aa,5ca87246,ca91280f,da97e806,dbb523fe,5ee67b6e) -,S(6cbba6a,13ff6ad3,83419e84,e4da6871,9cc1e633,d4cf3347,2f9966e6,4f9208ba,35122582,c7893f4,4fb92c34,e9c4661b,5859889,62a7d1fc,fac8a2a6,1e214a88) -,S(e07f8dbd,691a8611,eb5450c8,2c765dac,ffe9aa81,49ba3e12,87b23fda,fd9de719,932e35f0,8e39cfee,a2593799,4e118c7f,acb0c6e,5b526bc6,894b061d,8cfbc509) -,S(62136898,32fd9416,cde720d7,1d3f32a5,51f3e238,fccc69b8,4b633a2c,86d2c5d4,137e9a4d,62247e41,8596d968,4f1e5997,791f3b6d,69cbcf68,206f715d,be784e9c) -,S(8b010588,62de6706,253eb2fa,f710c086,40a318ba,1ea684f2,3254e8c0,dba7b9eb,54a48862,dcc56c60,cccbf43c,f7a33f9f,dbd7e419,56f0f48e,2ce2371a,19bfd264) -,S(12d3908c,14af8346,fefbbbac,e56bcbae,3fb2ed87,dc30b1cf,eaf480ea,84f213d8,fc4615fb,df7ddac9,84676421,2c4d99,fef41e5d,98e5824e,cb181a98,9a67fdfc) -,S(219d05e2,a7b8cc69,bbce368f,62922992,b474286e,df7c13dc,8da62d16,1784cd2,8aee4f73,9a7eb1e7,8ee9407d,e8fbabef,dd28203b,2161ede2,761e178,a34c7f5c) -,S(d7d0cd59,9a76fa91,f691fa23,ad265f38,49bbe213,c38cb074,852005b6,d85de204,f349572c,60750dae,5ea1330e,a725a0ef,ed1a2d60,c0b1d9d1,e938f37c,911ce2fa) -,S(a3fa69f5,a04c9023,83d8b73f,6fa8fc3c,9f65cfbb,2c77042d,635f4978,eabb6c6d,c798a1a8,9994aab1,4af95b18,f389a2f1,accb2d7,59997e83,72c1ca5a,c3cbdea2) -,S(902e881a,825c457d,79872e71,e5d94170,8540734c,1d050e92,cc5c8afb,13b2d1cd,ff075132,63bf6fb9,11163ccc,f62f8246,de099f07,ccfc9e33,8ac82c30,bda62d43) -,S(325f19f2,4c470556,d361aa2b,3f1932bb,6923ea5a,4f8cb505,d34cc60e,729c144,f4a9aeb8,29a6a0cd,f981bf35,81bf8f9d,73e3e9c1,61996178,2a57c46b,9e94bec4) -,S(6994f3b4,41a6cf61,53e5f860,2cfffacc,bcdf7245,eb078247,63bb07c6,fa1edd4b,ec2fc5ea,892da897,29c479d8,d3f05152,198ee4ab,87f73bd9,27db1160,1874c174) -,S(21855832,4e8f796f,fd51bd2f,8c1f6a8,5663c5a2,b5bad37f,3b7a1052,6acb2d8c,e77ceecb,33cec03c,99690d44,b0343bf7,3b93c495,5d67ccf4,b15d1d76,a1897c2d) -,S(905daa3b,32f2a801,a567c312,ae4772b5,3196933f,487aa1b0,a5674cef,9d91b099,bf6285c3,6d271719,13691d5d,767fdc17,82b64843,5b2ca1d6,b695871c,41cf369f) -,S(df7cfb84,34b60524,75fe5161,3dbe0e7f,1b685376,315397f5,b39951ee,b65339f1,e725cd7e,1419e455,2d953393,dd9651d5,d1beb3c,6fa44d2e,e580ccf4,df558243) -,S(e7fb9efc,88842b9e,a3c96b82,1ca5eb80,385cb276,28cf64a5,d8c5bcb4,e5732491,c8e676bc,a6f9e037,263b8390,675a97d,1353c128,eddabd5f,5e928153,78f22331) -,S(d1a35f0c,272ba216,1e6ac0a3,fa440f59,bad79715,d71e12fe,cc12369d,cd24285b,1f5b70f7,d475716d,b9ef2f21,bb156400,49dc41a8,96102ec1,806b949a,c99edb3c) -,S(66ba6e8,5f2ddd4c,e17da74a,c7ae629e,4f420429,45932e5,55110da5,2a7b079f,d8ebac5b,eb8eefbc,f4da4f35,79bdffbe,21967904,36487733,263089e7,7a80402) -,S(6f7f69a,26881052,b4bcf806,575f9c50,c36e7c22,1d7b9e48,7b1f39a0,b4f3a749,11d06b84,d89b88b,ab4352b9,cc160e50,bc183558,25bb602b,89235aa6,7331a4c4) -,S(4be16d6f,571d503b,26169906,75c01ac5,41c23afe,84cadb90,eda0c21c,926c0abd,1041ede,ffa1f2dd,61a116c5,dd33fed5,d9ede78f,cb2311bd,9a04fe32,9ec1d06d) -,S(8af88c5d,b55eacb6,760abbc7,91698c57,19160335,ee569bd,33bf050b,1e75886,4f5b850b,6bf2b4b1,29aeeb24,596007c0,ca203eb5,d2be6bea,f61bf596,bdd9a12c) -,S(ad33e77a,3316eb8e,1a764849,13915e81,edb69518,8ce7507,2e2b6088,4cef8672,fa0161e2,4bc88bd9,da5157fd,7950c75d,6c4f4f89,f158f13f,16ca5e4c,af7ccd90) -,S(444a81ef,7620afe7,91d96ee9,b1c34485,cdb51e1f,6022dba0,69ededb3,d9d8c2bc,a88017d9,a49d4ebc,2ee811c7,fbfcd9ba,bd268329,1efafb52,e641af11,9751e2fd) -,S(5b1e07a3,9530f8b6,60787e9d,26503a2f,77af3ad1,24ac8aa5,1d10b663,ceaa5c51,fcf4c0d3,8d55e0fb,2731e59b,686a806a,e87cb510,7bbd013b,4500c470,f77810b9) -,S(3e8c17,e986a86,57b4c403,3317e67d,b1d42e7d,9625e844,ba533ed1,73174309,deebe49f,f4f5a35d,ea0f396,63c7ee0e,9db702f5,c296fe5e,696f5521,94cd6caa) -,S(a1096eee,5e9bcb19,9d24c078,b46b528b,6432af90,7f1d57e5,746e83d8,4d112c1,bd13e4fe,699436cd,656b3019,acd54f3c,97eace0f,e1e92fc1,3f08a76d,d2e7c6d4) -,S(54758579,4218de75,db40a6d8,99a75ee8,36861093,4ded0938,98c071b7,6665f2f0,3bd55642,13e1c689,70cdcd94,fddaa656,6bcde4bf,29c761b5,c6f613f6,19174548) -,S(4eb32992,fcb4bc44,bff56604,f4f74586,a4400290,5ee9adf7,f7bbc694,45456057,8576a8f2,68349f01,ada77c67,30510030,e0cc9d8c,66db7609,21661540,ba45c3d4) -,S(350b2def,d2eb4933,c6d428e7,5990a7c0,f291723,f92e5ea2,69c5b4c8,b661a22d,61acdb00,add9f34b,f36126d8,380ef5bf,70f807a8,1320d59e,3540fb25,90de6943) -,S(914ea8be,ce7f8819,5337341e,eaca129b,2da3c96b,306b017,d7afd984,75f360ff,f2aa5548,ebef80a7,483b563c,e8b242db,582948a4,9fc89213,d3272a63,85ac7b53) -,S(f656e17,38da25f4,baabaa6b,d70e3f5f,ad6d44f9,c53e1a33,4596246b,83dc0fef,40a8b4fc,34639287,a65f53c,f373c2c4,c742ce4b,2040fef5,4c31dac9,59fd83e5) -,S(a47c8af0,334e3ce5,464310bb,c0daa66e,d77e1023,a2124182,ce3e6771,933b618f,6dbccb54,56d7c75,5e71694f,fa1713eb,41ec5b2e,8715ec4b,52295294,c0c7f08) -,S(a8a2862,5e1d04a6,5e87947f,82178d5c,3b5fde31,1eace688,6766ee9d,30753ca9,f82ad6f7,483aa04d,a79e672,efa109be,1feb3f75,d73923ba,94df2f1e,2efc2169) -,S(a01ff54e,5f8eb855,e26903cb,3fd407ef,4fe06208,a0f44837,1e83f7a2,31c017d0,2247c6f9,c52f1a68,84c18ec0,77d92514,9fd59b00,27663ee2,f0e5b2ee,f2edf92) -,S(e7b09c3a,626ac89b,6caadbd6,99a320c,61ef4fe3,11f6072f,f2d7c875,8d42aed1,8ed996d3,6a7b50e9,8e5c64ac,e03cf5a3,37c3c5a1,6d99c5e2,c0faefcd,38609fdc) -,S(3bba9e53,336c2a06,ca89fb52,26059041,96307c97,373cb717,3f35a45b,863ff2fd,f2fe9109,3faffc16,f58ccaea,e54e9b8c,419d5123,6e8c960d,52ae8341,27d24799) -,S(f61d22b6,dc660174,22122400,432f533,11950c21,b6240acd,af905f9c,2c0630a3,6068f5a,1a662cf3,93eb7e86,5cdfab18,692bb250,15de2796,1421a457,49ffb05) -,S(a5b60855,6b1aa22d,8bc38dcb,8f3e4721,891c45dc,2702d13,7189be70,e8a80962,f77f97d2,d5e305ca,1fe20b99,e6c182ae,3a9b3a69,7cd5e34a,7199032,fcb1ddb6) -,S(70c3aaf9,eb2562,e1cae950,be6f592e,f030301b,28022ac1,be3aa5cc,85e1a259,3f2cb7cd,31a8d319,ce4626f7,213aaef7,3f91f2be,a17addeb,61f217b9,4c587583) -,S(1dd70dd1,a8755e37,28dfcc4d,443e7911,a67952af,c33e7d93,b975d136,8d06e530,4684f974,1f5894ef,47040074,2ecc73dd,240e677d,b6bee0c4,141dfcd,7190d084) -,S(d44d698d,7aacfd4b,d8d6bb7f,2d0dca82,f5d37c3d,46573546,2b180cc6,9083fcf9,a18d803d,4232965,90c67b0f,4c415bd7,c0c94041,3740be47,2819bebf,87dc407) -,S(84589ae1,30455742,85522ae7,4b1bc3bb,62730a10,6154d9f9,4109c010,51b34ca5,b979fa08,f2a9af49,bf6ffce9,b2fa707f,de14fcba,3de3b903,49bf6235,37b3606c) -,S(3dec8fdf,89118996,bed31c1e,fff15c1d,bc84e73f,fd04c6f5,469d2f04,8b724627,b143f3c1,e20b5bcf,dbd1a555,f4ff88df,dacccaa2,bfd4310c,16ae2710,1beb2c8c) -,S(367a5fc5,519dd9c6,39bfcc4,70ce465e,23a8dde,417b412a,2f0f4374,8cac160,5b8fbddf,2c6bfc90,e291b136,a3e0f8f3,faa64820,97a87cc2,dbafac5c,a7f021a6) -,S(8aa5587e,7777606f,60bab6b3,20d88e93,1e7c2efd,487bacce,5fa3256c,9463efc1,ac5ba76c,98bfa132,c16921ec,aad52289,50beeb34,449e0c18,88a39fd1,d3f091dc) -,S(79c00191,ea632ea,30fd9e6,b0d11c6,af3aa441,eca678c6,a5d6bf3c,c84cae0,3f954070,3b19a941,3ac0b659,bf401c2d,ae9c8bdf,2bd19e85,472d2d82,39dfb899) -,S(c84de722,21a59e95,cdd951a0,66483255,e858aaa4,ada498b3,d4ef8bf8,3a04fc8,73cde958,915abf28,df811109,a6220449,548fcd2,f639102,158bc451,4af0a0b9) -,S(8b1b8c50,c6327d61,e063822b,2a3c5935,fedf74dc,fe694c21,8cb6b892,b5a9d6d5,57bd8952,9f156435,f47dfc47,9ff4314c,c036766b,5b6437f8,41f60cb0,fe168b) -,S(b45eec8a,3ae82f98,52117c4a,341f8184,33a31ce7,719d7650,e783fd52,48702c52,cd556b5c,c7086b4f,905d0fc,ea01497b,25411785,9ee9046d,c988c6e1,9e0a1c90) -,S(a2d5dcdd,d93096c7,67b4871e,ac58cbdc,31ab7013,865a9cd2,c5707780,80757319,7aa406b4,b130b23e,9e6b5978,b1e0b537,227ae8a8,af62c1a6,a6d46ae,4b064547) -,S(712036b4,e5d35950,a7564ea8,3509bec1,e97f6e19,121ae5db,3d314c19,b9ed2b2d,25862ff3,8d0560ea,4698d2f,425342c8,e3a32232,f9c9572a,21d7414e,68a93616) -,S(5bcef0f7,d70fc8ba,942e58c8,79afc973,dca402e3,795adf0,7562b552,f0bfb392,7cc85a4c,ecb45bfd,3efb0e12,c3fc56f9,1a444ce4,73256474,54ccb089,baf1919) -,S(dcd5702f,9d508a1b,afab9f0,af5c4e9b,b9e5f214,6767ab0e,b5c1d859,39741ada,f7eaead7,ea13e3a7,dccd40a4,a2526501,3369d558,6f0c735f,9eb2518e,ddcc1fa1) -,S(2cea30d0,4f629d,91c3ade,1b8b7176,363bfcb9,25d3eec9,784b91bb,e6cb3d9f,a83f4bad,a42ab171,cfc9a76a,a3dde34b,c48ba454,b39b36e3,44446096,a1c42624) -,S(858b41f2,767b191e,df15fcb1,3a41934d,150e54d6,e95035d0,9c6dfc7,a1c32f8d,8180b97d,76dc95f5,478a2172,4802a28,b34d6e9d,f65d5358,e5cecf82,9fde8dd7) -,S(d5c98002,bee359b8,6d1234e5,ff418013,3eb9a668,d2f1294,245fd020,c30e81e6,4e522da4,cd2bc795,65a2e4e,e2fc87b7,a0b6bce9,1d90376d,921aeb49,5b3781de) -,S(ebf9162,2f9cea9f,71a4ddf5,82de4b7d,34002d76,da8acfb7,d4d6c3a1,9520c1ed,eee75322,3e1881cd,8e3fb483,318c75aa,7e43d049,8e53536e,cd481d18,5ad4e251) -,S(387f6a9,d08756f3,8c2e111,af74be68,acc4504,f3669ff6,b406f6c8,a61db4d,288595e3,ea1d5f91,26df96d5,dcf5cf4d,ed0bbba2,37224c4a,59db552e,87cdd28a) -,S(897ff1c0,989bd52e,383a2d70,e5920144,9aa409ee,9fef20df,25574956,dfe46714,3cfbc0c9,308c6529,f4e95a00,644a873a,de094069,36dfd6c6,bcaecfa5,9adc9d1) -,S(3255a8a6,8e0484c7,8b6bbf21,e2d8b24f,bbcbb337,6f84feef,b577ef1a,b5a395af,17b3c002,f9204b84,e6d4a426,d2d74893,79ef3fd5,441e881f,d8122599,2912aeb3) -,S(2ca4a952,d4d9e3b0,3943eeaf,b1eda225,1fbca101,e7071b7e,2778ef9f,ddc55599,bfacbacc,df02c18d,f81a2c04,4748c7eb,e98631cb,63ca16a0,9892e163,23891e00) -,S(c3e8289c,478c334a,d47b0410,e1b6ecb6,46ee5f8,8a4dbd73,10505f6a,de4383b2,5792c2ce,b0431238,647f4309,cb4ed220,229bee,2727b91f,de4004b3,d6f0f55f) -,S(2bbdef60,a86292f9,867ad63c,67f98420,86fb968d,db92d9d5,f87bd27c,15119049,f4a4b762,3536c479,29099d19,3d40d4d0,e75dac62,54f03538,80286756,60a85362) -,S(77a6e090,9e7dacb3,18014ef0,714a4be1,fe3ee47b,e22afd2c,e0333cb9,ff2496a9,54f0e475,b1a9906c,d1d915d1,81961492,34461e27,e163c384,3815d188,5251065f) -,S(d195b96b,78719254,deb4f413,979f64d6,ea94d5e4,79350b11,45c39e45,4f40ff0,238a4440,613c846e,9472d4b2,b0a4db88,b8245cad,a5af469b,d997f729,c0e0636c) -,S(c39aa336,208aa65d,75bb0f3c,6084f414,ad024d15,48da5bd8,113a619b,4815b1f,7aab1ed6,32741dd4,14883b22,6e573ee6,455a0053,6d849200,4b233153,1126fe5a) -,S(e80ca23d,baf82db,cbe0bd27,24cbb31,d6661c70,44d8a8d2,2967764c,fde31f30,a153d1d4,73187878,bcbc583a,5eb83e5d,f67e8142,46861713,8c484744,a597451b) -,S(395b7a65,a5a9c23a,f96723a,4d595a7d,f3e8505f,e0aec120,711cb7b0,2e72ef80,59020dd5,47476e39,36ad37b1,9a256543,4f88cf03,2992f4b6,2229a5e7,e49bf990) -,S(67a7e8db,b83e23d2,7b57e2cd,9512a5da,e8b49545,ffef2577,644fda22,910b495c,7c01499d,3791b9f4,100a89f7,8e80b410,41fd34ee,68ce1f15,a8753032,e8965735) -,S(c4038e7d,76d2e7b0,86986395,2cbe2ce3,ecfb4b08,61423892,ac9b3b3f,6dc0c7e7,61bb3b0d,9efc9b7d,326a27ba,bc34fc8c,129460b,6642629e,72f20351,65e92f3b) -,S(7705a5e2,26a4d3ae,ee69c52f,5fc3f575,b9bdda08,70a19a8,8a525698,c3a25e5a,458e096c,f01906f8,c2426973,d1c6a982,44be9e02,22406207,3a883e4b,53c7a1b7) -,S(f3ce8bc3,5958b5e6,16a994fa,1fe0396,68a5f1f1,b464a875,9e4a3475,34ff48d0,9c1a1d97,be3ad78b,67c8c441,f7aec63f,8dc92aa0,87500d6b,222a2473,e10058fe) -,S(905ec120,de69cebd,b9a9d764,e01d6f88,3ebb94ad,af5685d7,6649e7f3,3ca4e0d0,92617e99,3974aa3a,774a75d0,e51c00ca,4d42ce12,d79ab0e9,3a8e449e,9ca9d554) -,S(b1b74a4d,a3578592,8bad0edc,3664c1e1,27d48447,fdb246b4,f15ada68,9b21eeed,c43539c7,b84e9e8f,bcce3823,1322c4d0,c14e4d90,33c4e132,8f5b26ea,9d3206d9) -,S(d440165,c72f2d46,b2fa2a47,1c42dab7,8dcf814d,12d3e025,bd5fb963,3d8bcf1,e0864950,261f5fac,e97ad9cf,fc7683df,fabab749,1d80422a,ca30721f,5343ae3e) -,S(ff524c4f,722c19a7,f7b910be,6d573a57,fe08d5af,6580aed1,de03f939,5053b303,fd4ad4e,5b25aa8b,b3a62dea,b320335b,5b9f1368,62f5f913,98fbaa61,b753bf0d) -,S(effde0bd,331c1083,e4b76a53,c9c1ba43,8fafa2b0,4a3ada44,63a5fef1,8d8d091e,fd7a869c,a75c2105,e6ae5420,86ccef0e,c563bddf,2b41ab9a,ee0e14c3,1d947dde) -,S(a5e746c0,99c8d99e,88b4a304,b583adb2,1115ba64,e409d278,f40c4571,2f3875e8,7f832112,c2af3830,2c4baba4,f073f7fe,84170939,dd9e8c07,fd2c1eef,2e934a68) -,S(6accb9e3,af5ee943,9d8daa72,2fe45513,7df5e274,486fa46a,1ba19093,32ccb431,f0de1658,842d6580,507c26a9,b68f92e5,a3faf108,1fcf5dc4,43ec9dc9,9f28dcae) -,S(c813d055,e40d32bf,6e8e782b,3ef85698,b86f3d31,ed0123ba,1ec8978a,f72b6d4e,baf6d757,2f924631,c4da4191,684c6280,47d37ef4,2bb9528d,28879011,8d068ca6) -,S(8b882012,2cadfc62,44fbaeb5,8be4d587,599dfae6,2fdf1177,38a844d,97c7aaf9,f5e6c293,ac900da4,f716e131,fa5a42a8,7867c8a4,76808b2d,4093c782,6f7a6a3) -,S(8f075050,f49ee582,b54a5acc,4ffaa443,bc02ff34,4d0717ee,9619d83,2d7310ce,13b901bb,7ab3d325,7cc555c4,a4799a3d,f1f9f9a8,6b7021c9,b99a1315,b5f7fd3f) -,S(bbc852f8,cf643e54,3c65fb1d,f2f72c97,89a456db,21c81f66,921d411f,b0374c58,ad08eabb,e7971e24,b2bf604c,fb248b3f,a27e1c2f,84f032cd,4c14bba2,b30a590b) -,S(2d77dc4b,662b55bb,878edddc,9dcc2dcb,9278cc,b1e549fc,ffa02503,1a80bc1f,288bb0d8,4fa7f2a1,ad1a62f4,e76ef6ee,c07707a0,89caffff,a8e60870,ecd058eb) -,S(bc83f71f,f3b4a86e,b9bdf7d9,94bba6c8,c90945ab,9c858b4f,fea7914a,d7ccbdf9,18e91fa3,e5067d23,809ed455,3d119541,fa3c2563,a3a88b30,20d3e49,4b232292) -,S(7d5b9657,8d9b88e6,b0e11b7e,847d0524,45f83dc0,e2bbb7b3,205db435,2c200919,1e689f7b,8830c10d,c28e7230,c569af4c,b1c9e672,aafd4d35,2faf5570,90515ba9) -,S(85e9f364,8d758688,31dbab4c,7460c4a1,51614887,cacc3cdc,1baf928a,200cdc80,7f4ce518,d5045c0,5865224c,c07f7fc3,5ba5e4f4,c03ffa9d,d5f8e5a1,31369e27) -,S(425390df,c1c094bd,34855816,dbbdb71a,9c1d1077,45b1c65d,a101d974,4acd0810,81f14cdd,20ef4d70,69026d94,f09de176,707547c3,8c0f27d,1e277d4f,1f49bc00) -,S(3cc7cf0b,66dc93ac,250d00bb,60a0f75a,dbb59409,bf8e4419,4cedaff6,413549d7,331a632f,c3dbd899,f688bcf9,9df70e66,ae17b719,a2beb23a,664c1d6,1c204a58) -,S(fd72088d,b8a1bce8,8fc923b,cff789d8,9d6a0b2a,2be3b5f0,17e2b3eb,ce70853d,d3912b23,a38819ba,eb329638,3a0bedd9,93db4aa8,df647494,b710dec9,9eaf599) -,S(3e558f8d,5e0096da,4d8940af,9a0baa25,c7318541,c7dd37a6,b72b35ac,efe65060,2a403d7f,69d805c,3ebbdb3e,fba95b87,f78f6431,7fec0dde,7695053d,e660e90a) -,S(70708223,f525f222,16c00149,fe1b745f,721ec32a,90fd0b01,e82f2049,d8694a7e,ef4ad787,f0b4d53f,19d86ac9,7d943b5,fce17d88,6366354b,410dabeb,efd12569) -,S(eca29625,eabffaf6,4b9eddb7,11e4cf76,440b4a94,def9d2fc,6e5e9114,aa414f72,f1f83875,75afa3fc,b23bb227,4c5890cf,f798b628,283989dc,d3538b8e,237618cf) -,S(5b7c4750,542df0c4,c4606db4,6861925a,da7423a5,66d6c108,77838f65,5f297695,42811366,1ae1889f,d6ccb1a2,4cd9a6a5,de04db2d,5e805079,5f922b9e,791f784d) -,S(af1a5fe6,40cb2ee,d36982dd,1e7882fe,bd5da168,8005838c,b379b986,bc012042,71570549,305fa634,a63d12ed,1fcfc8a2,5768778e,863d4778,b7e41215,ad3e6224) -,S(727443a2,46787e70,f83cd1be,1189c4cb,e1e8b18b,1d57746a,9a319676,9366b1d2,86357826,9bba3e89,a12565cc,1770e5b4,4df56ac0,d202fdea,d68928d0,6d16d540) -,S(967979,db34e62a,149e6835,213991f7,ae2c9a2b,abf3d255,6c5e198a,12640b8d,99dc1d4f,52445651,3cee44ac,3bf3d1ed,8547b827,251b3b01,4d4c07c1,fd9edcc4) -,S(794009db,8f3491e,27ef9d73,905b06b2,be56937d,be57b8b1,59dfb883,af203601,5a6ad64d,7ee5e1cd,15a6a087,289d86b4,5db60d24,243917e7,50eca61e,2ada40b6) -,S(87cbda39,6f90b090,dba9470b,1fb0dd1f,d2f4212f,50791511,cf6297e,a9851d10,9ca095f3,a2a4f997,501fb4c9,c5585dc7,fb8f7952,e11cd3e7,73a92005,a41b63f0) -,S(9ed57b03,475d1752,58c20772,1be7e12,cd1f3ada,5b95fa8,4b245b01,b910acb0,d58c9054,43bd81af,85c58a7b,d0cb3e8b,25310644,8e1ef50d,324eea36,a3bbd5eb) -,S(ef8d0a22,92ca4498,2dac77e3,86113363,35fd9521,fd266be7,d5d354e6,28b0402,e55c4b4a,556881da,a4a23e5b,677c1a9a,f2f547d2,e2b4037f,f9758a74,3cb58b6b) -,S(6dba21f5,a274f29d,502d369f,4fa4ed08,2299f6e1,b12f5c75,abd01597,d127e3d9,7685f72f,a0ce41e,8c4302de,3e6e9c81,c951f69d,d2df0f3c,930da77a,51a39d94) -,S(8cdc3ebf,857ac235,7dc1b0f4,26ed2a52,7841969b,7fb332aa,6ba44693,c8399a3d,234dd3c1,915ac714,6cd8724,9b68a19b,df250dab,2748abec,a5876fa4,b7f910ca) -,S(a00829c8,caa665b4,7e3391b6,f4706898,a9c790fa,29344de1,e88fd882,b5eca2da,b7c8fcc7,1e834cce,5884b129,98318254,23486297,6068eaa8,184b5316,fd424110) -,S(5872f762,446cbeb1,4a12e54a,1d4f22d6,a4ed5b2e,eff7c5f5,640801dd,2149ce6a,8aacd3e8,862757fa,1a70c29e,24364ef4,4c37d5d8,bbacde2a,c75a0c1c,28ee198f) -,S(b70ed5c0,5dba7150,f22677d2,e5b532cf,53e7ceac,919d3b2f,ec4cc6b9,2fd34f2,7e43f528,cc74171c,a2fcee0b,18d8fcb,76c3d69b,8560831,26bd4482,a4d28cf8) -,S(4beaa213,3c6161d0,c7da6d7c,8eb09cba,2e8ca505,a790a7d3,9d0c16b,8053bb52,da4c083c,9cbdda2e,c6626d8f,e4b2ee13,703496c,c298bffa,db1acdca,99d4f6d5) -,S(a8d31ec6,53ce1834,a78de363,c5f9abd1,8594b34,4d34f5fc,8a10e81f,5804831,b4d6a9cd,7cbbe370,9edb5601,cb7c8ba4,8c462c18,594a4bce,64f4c286,dac5cff9) -#endif -#if WINDOW_G > 14 -,S(a8f11586,f3df4945,a753c485,ee0fd4d,e410771d,bddc1b26,c9ff10e0,77b915b7,a4ad6f16,dbd741bc,71b2dfd2,dd2d340,3816bf73,4e73cc10,abcfa6bb,d0f161a4) -,S(13e697c3,812d4772,254082da,372892d4,e1a66e1a,eb16bbd4,f7a0d531,c979cb2,87fa7baa,f6def12d,31e42c14,f672c0d6,a9d0e2e1,ceee2546,d65bd01,c18df57f) -,S(3cae4590,821a9697,a5963269,b44f0222,98f60021,b6048b3f,49c6fd4d,8650c7a,e03f8745,60418449,ad97f28,41664745,349329d,268c1c43,86e25147,6e44b234) -,S(6f42f6b1,cb6bbe13,cf081480,766cbb36,9d2e63e,e691722e,ac81621c,66e0fccd,e5d8f8eb,67702ed9,e33c7b71,e3cd7b25,cc9cd315,314815b0,b67e8622,fd35f022) -,S(43d24bc8,469cfdb7,51ca7d82,98727059,6fac14e2,11d37041,370f3bec,90e411eb,2129d618,fb1f7030,9715b2ee,d8e70aad,8b172b74,425cd747,3a3fe40,d7c50dea) -,S(259170e1,d48b6f36,6a281592,3474f0de,434f4ccc,e45126e4,a15c503e,c1f8b97c,9ec06188,dc194bc2,be131217,bb862943,aa9cf36b,7703c45f,b1ffd282,c3c12549) -,S(18d547f0,426139b8,7837d1c1,ca0f5f06,883581b2,c001e8e7,2565c9fa,80fa2719,26d9dc3,e1145ccd,23ae36e0,5c133f6a,5ebaa9fd,bb954792,3e762a8a,9fb60260) -,S(23b5936b,f2dc961f,2fc93814,4c96232d,dceb477a,753253cf,1bf05713,1b9e58be,9b678070,1bd976e8,8d66e740,2c00bec8,e4fbdaf4,976289a4,4391b28d,45519b07) -,S(46de46fc,209df62,6185387,938724fb,702c3239,fcf29113,2807894d,148774f6,cdc2ab0b,5d37a348,1b44de55,d9c50ce5,4322f8be,6f284ed1,ee49f04b,65f4f2d8) -,S(d3b78208,f5876faa,c4d3c970,3a87a586,e897c11f,dca9a7cb,6573c814,9b5d5da9,112ecaec,9f4451ae,23485579,9cfee804,ee053df7,8e65713a,cd43d953,471863e1) -,S(52d51f46,ac86afc,391e6a1d,8ab1d862,2492ae18,b3e86f13,5e42fed9,4cf3735a,cea47627,e7eefa90,7b8bfd12,f3212ea0,bfaf9e00,f407bb4,8a86039,d4815215) -,S(46451d04,48f3f959,e133723e,b9138a73,b3877adf,f294ff15,6303a845,65a4c39a,fd1c4a00,bbd9aa06,afb14790,5c0530e1,d6c3b5da,c9001b9f,8ec76df3,c7bf3c76) -,S(a12f5e51,16c58aae,90d8532a,9182d54,f539014e,e2d8357e,5ac7854,26fc78db,3db94e9b,f37ced91,7c9f466d,2a6db2bb,21725e9f,f4dc1482,3e6e384a,265e0cad) -,S(98999fcc,38fe6b71,97ebfd61,fe8942dd,be944f98,6f139c4b,7bd6bd3,28ac250c,48adfd3e,c348281d,c23335bb,8702cf8,acbdfc84,9ee34a3a,14bf36ca,b7dd0ae8) -,S(8ac22420,f9b9aa05,705b31f,bdb57d05,218ad72,ce09b489,4d0b515b,4e5940a8,37a7e2ca,442b2446,686f91da,db6975b,6f63454,e3a96df3,de8c62a4,364d30b6) -,S(cd0804d7,b1aea00c,13a94a33,f75f3736,f5759080,96a2d418,c5b54c72,de31d619,c7f68576,10df1c38,6e677bb,dd6dc121,b3d9e9ca,e54d22bc,a5ce1184,a3dc755e) -,S(b6c4bde6,2f8fe3d7,3c32e641,573098c1,c559e847,e40f60c3,49d40050,49b0411e,62c691f1,68510458,3e5191b3,758d7e3a,b2cfa31e,7a00d7b,97e39f88,786f9a9) -,S(c20990dc,70134917,42cec766,8b725c26,d918cb46,6cbf7ebe,7b1f37bd,63d5df0a,6f1e71ce,e28b22e1,9c6f180a,4d7a48be,9fc696f4,cfd418d,134c1196,6e285d1f) -,S(ebf16672,45ac7f7,385b5356,dbf977a9,3602a11,40ada114,7face805,dd93f9fb,24b15faf,3b3ac9f9,833882db,b81a976,9a37e6ad,1a4228c9,a4f7d0aa,fcca3400) -,S(1c620657,63199ded,804deefc,c33822f9,cf3d4c1d,72f2022f,37714eb3,83367621,600221e1,48f74ad4,dae118d1,b6dca782,e00117d4,92881c23,b5a7cb79,86cad767) -,S(40b300d0,7520348,38bec63e,f155b527,286db841,754702d1,d512c183,345d492d,29305ffb,31b1feba,abe027b5,f432679c,e265a57a,3960b8b5,a66e6de9,5a10fee6) -,S(5768ffa5,c8b56772,1e10c2ea,421afef5,dfd84120,a8d40e13,751a895a,fccc6c2d,52ee5ce2,e60ec485,7ee62e81,fb2eb118,4d2a6ecf,d8ab7e09,dd728d16,5e508d30) -,S(d906e71a,b6bc6697,858c66d6,82aa85af,e8d80ced,5f470ac0,8158b5aa,4cabf2b7,c75ace8c,74552756,8cad89e2,201dd954,bc6f4ae6,3a671d2c,9bed78f6,40b7e70c) -,S(f71937e,f4553a81,a3f155d2,2f81a5b6,e080c0ac,bd8f5c5a,fd437960,6a63460d,d6e4e57d,422df901,e6292a28,c83c3bf4,136b5700,f6da0351,33099feb,f1228b19) -,S(3c498699,da858f1b,364c464f,b4317b76,5d085393,1c187888,83072cfb,39ee337c,cf3033a8,9749a0f4,fd4ad867,67b919a1,c946dc67,cc46524b,af5c0015,833daa0c) -,S(c416570e,cbc5576f,97090660,438dc3ec,be269c42,6e36fc44,45d53b0e,b2c5d54d,cf6380d8,76e20ce9,5cc181ac,4fdd42c4,b91d7132,d1b1c19c,4cc0db01,4ed782e) -,S(8f97b2bd,344fcf8,62846992,e826f5b6,7fe7d103,28f34231,8a9f7de9,20d71110,e296632,fe41f8cd,b3da3ca,e1c356a4,2424c649,11dcdd58,c21aa1f8,cee07ec0) -,S(6283f371,8e67e917,5b8c1bf,28e66bd8,470dc4a0,1a720a8f,cf1df325,fcb0e10f,5e80225c,87c0d6fe,3432db79,e8cf4365,8640ad4f,21efd2a4,333eb6ae,a46bd342) -,S(9e29c616,ba66db06,bb71e56a,2a049727,e07b83ff,cdbff6ab,898a73a2,f2f9d58d,b5997133,bdfa29e4,431494f2,8444f186,7c4fcc1a,516ca195,c8eb6fe3,f5693dfe) -,S(7a0db51d,56a2b33b,8ab33329,a1d41454,a30e34fc,3db33a31,45c1cb07,923ca061,334164ab,64cdd8fe,9a106f2d,156a16c1,5da4f07,fbd7f1ad,e9d1fd7a,c8630fc9) -,S(5994233c,13ba74ea,19c1c65a,c3653a6c,cef79c4b,bbb827af,e736545e,33ac05bc,2175bea7,3090437c,9af6f994,b33023b0,5fdb278d,c0c59063,eb3b805e,a6b6bf6e) -,S(11e13de,2371f715,4d15373d,d52c504e,50811146,10ebeaa3,f47a3335,ee4e17de,fa961827,b81e71fd,60696d97,17820d67,ec86e8b8,74d3d4bb,f50df644,61f738b2) -,S(787099cb,c8896328,dad08bca,4e682e4,90461574,29aaf740,23795a1a,47f25ccc,1ea5755,bd653ed,ee7ee8d0,b3e6214,df2e31d7,731a1c9e,47a95f46,8c3c8ac5) -,S(c644c88a,fa42bae1,27bec7d9,528cd695,7bf7d906,942baa4e,14ac960f,46469cd,9d7b39cd,22007b04,f61c5905,3a3b7614,81dd45a1,532d395c,baf8ffff,377f2644) -,S(79d1abe5,cdc8b0c4,9508a87d,46163d1f,ada43640,ca1a5e89,d2f1c07,8c58820a,465cdc,983f1be8,948b850e,a9a4d9bd,f3898781,65d5a186,1c94d3d0,3fb9289) -,S(e8d4fa8e,db2a1612,d7b6fd8c,d6aa2f1e,a8f1ba1,32572d6e,dd0826ce,bede0e55,92aa3d43,e944d032,afa03d23,dcdb4604,56cb0363,1fe2f8fc,404dd9f3,f832f065) -,S(6f99e75e,b09110e7,3d5e304f,bf569037,577554e,51861356,40c2c69f,4a92e88e,63b5bf05,c554aa30,261a09e3,b292b9ce,8f1bcbf0,ad91c35,aed04f31,567757bd) -,S(cb089170,d912f8ae,e59f21f8,8860c0d5,182b5252,3b2cdf35,b9795d1f,20c37815,4e8c5b3b,6d79cab9,9f2570de,8c58c34e,6b6f5e19,b285bc4,6988ac86,20e645b5) -,S(5c248793,51e487d3,af1b6d16,b25367fd,9d2b7185,9923c565,5d7567d8,ffd621f0,5806bb36,ac3cca86,2624401c,27c54e90,c76fc747,7e83e6f6,ac89f22,35c84211) -,S(f1d10f0a,2ce54b90,ee71ccdd,eb6dc4d4,c2cab0c9,5cd35bea,5f20d3b3,51d15896,7bdb4d3e,cc613f8a,8fb84d25,541970e0,6c7385e3,c04022d5,82e2efb8,4998eead) -,S(536a5966,b594b460,bd27b4f3,aea6b555,95940f06,311970a0,36dc0fa2,3a274519,c44b0b54,cdb4eb87,b5d70d9f,bfd4a601,5c34182a,31a882c9,880878,7910b3d4) -,S(7f8165ce,ed27a393,41d542e,ba9ae875,554265f6,1c1c56c6,cc0bbd66,2ff88686,6993724,26c18b1b,dd1207e2,f3bcc0b8,673f481a,e7638d5d,45134835,9b4e39d6) -,S(12214607,c610d012,83b9265b,c59d7458,4e0a79f6,8a4e8535,a72809fe,11a6830a,5d26e498,9e3edaf6,27cc4bb7,105ba8de,3344e506,d9bc9a33,8f1e3219,e473e609) -,S(9ad7f097,1d1c326b,8ac468ef,706f53a1,9e8fff25,8e599f0e,72acaa15,b21d58b7,2e7c0921,2199c7cb,da8d3645,a5bd7831,4234849c,41a238c2,a3dd7fad,fdb8a880) -,S(355f75a4,9df69d8e,4ccad41b,1fb0445f,619ba9aa,34697a5e,24ec8e92,f5b41068,9ca83421,4622ad8a,90a09469,d155bbec,717295ec,c071894c,6c91a7b6,e1345f24) -,S(bcde8058,8336a996,fa6af5bb,5ebf7441,ed3bda73,4802ab5d,5c0eac31,8017c706,49e40844,78cf1912,ddc91907,26411814,a782a3c1,452117c9,993d9e8b,4f247563) -,S(372cbbc3,3417320e,21ac4ba5,f286a9ed,273b6425,e8ed22b,d0c352e4,f0a97270,6e05363c,bbbd6b11,8f2842d1,243dd629,247e90d8,4e7c9d02,c3677f93,d1d01bca) -,S(a1122e8d,82e97ff6,ce9fd024,cd4ff32c,76aa0aac,c1c2849d,887240a7,a368e064,ef97035e,1df99943,1139cb88,e03bdcf0,8b3a5c86,d4b42d13,9b3acb12,e4e7df3d) -,S(e0101d71,1d0c7b60,8093997c,229bbbed,63b05224,53c0079a,518826f9,2bfc9d5c,a0acb9e9,c3d3d384,7f2d38bf,29da71c9,af0b5a41,5bf738fc,be24e367,c8db2fcc) -,S(6df3e575,4b62c92,41f8aba4,12804ddb,74ec864a,12076a34,d9cdf9ce,be336e8b,bc66fbf9,276fc85d,767c2155,ef481295,963cf371,c0ae6b48,50140d1f,c32f80d6) -,S(e5794801,97d3eb68,fd859d0a,a616912f,a2a52a7e,f3881969,626f43ae,4ac20586,3ba69743,176c43f7,7afdabef,a06eabf5,94b9d0ec,1114f352,7cb1b127,697a5275) -,S(7b290c31,de7dcb10,177313f1,9a15d751,c128bb2,16823c5d,69298baf,575657cc,9d3b3707,d8f2b17f,e14b6b1d,80c55d14,b747c3e0,8c79d55a,bb54809f,d96f99e2) -,S(4ce2adcc,18632b7a,560bfc3,beb7138d,8ab210de,6cc7f6cb,47171b45,13e991f7,5aa8204b,689d8f69,a42e08d,5ecd2936,97ba76b2,1bae122c,e9252659,25a874c6) -,S(dd798cc9,97530af7,d7ce96d1,a6a93aba,c29056db,c69eebca,f4649648,4942bcb3,e9ed537e,7b679852,88bab4bf,36ed677c,14db982c,9ce8714,b4f3a32b,56609e49) -,S(356f4414,9da655e7,c9ea5a3a,5c4847a9,f908c608,aa492efb,15e7cb00,8b065b79,2adb4e6a,ce059ee,44ee8962,b4aa8c71,a4d55f31,28f56877,6c70c4c7,19fa6332) -,S(b607a62b,c16ffea9,b30f61d9,c711adb1,d110c6b4,357b1e0b,dc71c8e9,4d06668b,6b933ae0,9ba42b06,96419a90,e6579a33,8f4f3fc7,5134abf,70cef838,efc5270e) -,S(77fec5c9,24fbca2f,f564bdc2,96ebbfdf,d52f0dfb,15011792,57085c0a,8fec498e,6c7729a7,c92a6626,44f33fd3,1ad5142a,b521720,24e31308,dc11f73c,ee29d69) -,S(804dd2d9,8014a95b,7fea2651,195585ac,acab7a46,1f3134ad,f2c4403b,3de98461,66fae33c,458de63b,dd04fce8,1c425938,dc13194c,ac03205a,c278c071,918a4e84) -,S(65866c36,90a6cf74,95ef54a4,f222bf9e,3ea803a8,98eebc19,2214133e,9ad35234,8cecbc5f,4a152864,6350711f,c4df57dd,8a2c44d,4133ec17,c95e00d8,b49c62ee) -,S(eaccdd6f,2a9616ed,d6f8c3dd,bcb04c1d,49f0c4c3,8d8c34fa,d47174f9,2323e15d,15a435eb,e23d23fb,2313b59e,2fe0367b,17b6d9d,e900332a,20430362,19c4591b) -,S(860d382,8ccde42e,b27652d1,c159d9db,57a0b9de,f290b071,e93e36aa,f730c53e,b4688879,ef616c7b,87bd37,641e0381,115dd487,d5fa3e87,99257afd,26906aeb) -,S(fe446d0e,8d174570,49394416,9c332f9c,eb47e70,3f214d83,2777398a,dc8189bd,d4cb299e,760ef11e,a3846dd3,9a49f34,4d5c10bd,ba66dccb,a43e3647,718e598d) -,S(e4e6bb03,528f913b,bc34d910,2a96385e,bd0b8aa9,a07a863f,9d5d41c7,b982a578,46ed6885,471b4806,aca3c265,d0c40535,4bd63da0,af35a89c,e8a86896,63d38690) -,S(12d69042,a5515732,8b729ba4,4fc3bac1,95c419f8,ec71f438,e676d722,4509bc56,80d7fe55,52e88a74,a87d24ea,de1f9e35,de5c45ea,b8a9b48,9e7a0b8,4bcf5d31) -,S(d3ab5380,1f1b1f7,36d94c4f,2af00a81,ee1815ed,83dafdb6,ef5189e4,13a32552,691c4594,657c0809,f7b6335f,fa4fddcf,8af5b729,9262f790,2ef12e34,f546a401) -,S(50bd549c,2da95051,7b4c72c3,67074539,412f3b4c,45ec69cf,aed0fe61,25b50d7b,147f8768,515cb545,2f291d4f,5a627f36,5c88b2b,d19457b0,1fa711fd,9bc71abc) -,S(a36bfbc2,330165f0,728578b9,ec81d14,c0417090,e6ed73ac,e8aff550,2ad9c62a,acb88155,5251f37e,f31aca05,bf33f9af,9ccc57df,58692067,4f11b787,8c7c9337) -,S(2be3d416,ca9627d5,9f259f0,1d52d915,9972f50,c391531d,70a6b79f,735e7413,fc0eaf6c,97d11c6b,cbc2722a,b3e821d5,363b04b8,edf2b700,15ce37f2,f70e51de) -,S(7ca7ca3,393a9884,c94430ad,20731f2b,7629203e,9c892d22,ae6df1a9,fa66aecb,c05c74b4,e2580f6b,9be6efd4,379b7631,26d3e0d6,d4e9925d,1a7f874c,fd620f43) -,S(6805c83e,19aad851,6fd7a4b7,e9bbb82e,28d9d0e7,1f1608f9,dcf37a71,3b434893,2313791b,8fc68b18,444cb309,9cadde98,f4c95ff9,88ddf601,ea3eacb5,bf1c1512) -,S(7540f073,3a358a90,80d2b07b,64e179e6,5de8010,6eed4eec,dc8c879a,87d007ab,998820f3,bac2fc51,48b0823a,d20b5f77,eb7acf5c,fb2e968d,2b98711,a1ef778c) -,S(6eb9b5ac,960407e4,465a0c22,8d98621e,47f169f7,61189aa8,f7de2fe8,79daa64a,6a32f21d,379c38e9,229ed85b,33b4a35b,9999281d,f96ecdc0,18d2482,67d85d54) -,S(e32d3fe0,80d92f46,58331d25,f0f2bbdd,43671885,98cda416,7b4920ff,afd5cae,61a8a2bc,aa82c5d1,1e958a0,fbfae374,138efec6,84ea8e18,af1d13b3,5388d1b4) -,S(22a0ca56,c95c5221,3ca126b,65e5382a,5f14d17c,976da5df,54942495,43415d70,4cfbb8e7,7e3f04c8,69e62ffc,edf23907,e8b17a48,13fc95d3,cf307e2,978e0bc6) -,S(ce3aeaf2,dceb0f4c,50120b90,fc027d7b,b5a4cddd,fc337e05,14298873,e3ff340d,49f2b65c,4a64b462,69e93c2f,ca6cdf14,b0c81982,b095ed3,644805c,cf333021) -,S(75251b27,b360b236,9c0cb297,c5f6ec1b,70f6afbd,5af1acfc,38bd765,9c9dd5bf,cd0559b3,9b18ceef,85c15189,fbd7a93,1ceb3f7f,6cc93d3d,7681f564,17f3f891) -,S(9d69e5b3,32a9ba92,17884f7,e7a1ab91,53a65c43,917c566a,c2969f50,accb9047,9ef330b9,d347c93d,a9441706,a502491d,55d27723,ac1138dc,751308ee,fc6b3a37) -,S(783ccac1,f7d6409f,758849b6,f7c4d5bc,401fe5f5,b08c2f84,1e0e3fc4,fd7a2d47,e5c62a27,65ea5ab8,6aa1aa00,9297d1fe,57248127,a5d3c36b,9665cd93,b6255f83) -,S(dffbb444,8362773f,e45e0272,eeb1a8b8,fefee1b5,59a6bb12,b9613fe,55ef33d4,fd539cf6,aacc930d,2ff104dd,405ae6e,e4a6b3ad,1a9a0038,f4ffb4ba,1a6115c5) -,S(cfc948b3,c14d06fd,c528d299,22305663,d7a427f2,fe08cc2d,942528d,dac8ebe3,81ab799e,5be02ce0,d3aece6f,c6ce84ae,988872fc,ab640d96,c3ea6bbf,3e2e709f) -,S(d9fb08fe,6a7cb6ce,721cca32,74e20732,5933595a,e59aa0d8,811008f5,cee83490,2c7f1287,8b6ad3b5,88cf9483,f08a92ca,ccc18ece,93c68297,4d80ae31,54965938) -,S(4272b558,49ef0ac2,d7830183,bfe3cc45,65ab9d9f,32b9366a,b0477d1,ae93956a,caa07aa5,d117616d,9f442b94,40549bd0,f64e7a2e,3cf96053,bd14faab,196c698b) -,S(69536c0d,6404b026,61598e11,1e6eaa4f,e50a2cfe,879b0f74,4df57727,933367fa,aeed065,2c5325a9,53913334,7e4fc4b0,d2583608,c2086bf6,b2e5ad25,261c6bfd) -,S(199589ed,5c4b6e24,65d58257,2fcfc194,60f7643b,7019c02f,8038d04,70368268,c48567e7,ef7a3507,14d1b479,1a70e7b0,5c1d4351,eabacd9a,1d8d5e80,a5da23c2) -,S(ef3c4f9e,53ed652b,f48feb4d,1c7b711f,5526dfaf,6588007d,1c2ce942,86db1f4,128e416d,570c3eff,d45da6a6,31246fc4,f45b7d2b,8cf85a93,22b5f65b,361fc49) -,S(6bc3a126,11ca8f8,3d0790c9,f5b5b137,4ce51c66,6c553ff6,9d103370,3b3d7cc4,b20988c9,4b882f50,a0ba8194,2f168bc8,f29eb6fc,4c3d0149,571968e4,81b76ab4) -,S(a0100574,5ea131b1,4c180c17,f26bd3c8,1bd48ca6,c2310c4d,34bad277,6bf51aab,177551d,299c9ca9,92de3e9e,f82b115e,6d3cea9c,fb276955,5509795e,4870a546) -,S(15553b6b,defdbee,532599ab,9e0de23,b4954dcc,912f49e8,f084ebb5,af6088e5,8dbaf203,351a1119,16e8aeb2,e5eeaade,b0ee5d9c,2f5020,62b9f5cc,ca40cbf5) -,S(ae84a42d,49dad25f,f0a5320b,d6a33f8d,79c9f2c7,2871f41e,f8b02cc2,c469452a,9b23f07a,234782b1,cfa524b1,ad539ea7,b8fac3cd,e9bfb867,799a2587,95a48ca8) -,S(eecfc7a7,a41f75dd,43e2b85b,5af33ad5,f017e0d4,8f9b9bee,f0cf4499,a3c762d0,65526d26,73b9e5b2,8ec256bc,a524e376,f0e40f62,2db6e492,e1c53820,a3180d11) -,S(35e427f6,d0be7dc1,2d306ecf,be9fd8ff,107a044f,81c38c8c,5b9a181d,f4565440,de09eefd,27a8bb89,d8fc38e8,d32aecb,5c6bdc57,5cdf91ca,2f18e926,dfcca94e) -,S(d27cec9d,11130024,7f71fadd,4ace1139,cbe3168d,174c93d,4c756c42,89cef3da,5747fbf8,c4040895,fded5c00,e1f60403,40e07827,8924ca96,2f83b3f,e50ed701) -,S(df30926a,ca9062bd,7bbef9d9,e312a1cc,49442ebd,9994b93f,dc652e68,25efe5b9,8d1ffe08,de113447,5c3adb77,ee5aa58c,593486f9,c3f27c32,a20df570,6ff5c572) -,S(c2602b7b,56d0eb73,ab494934,5eb77e88,787e54c,79558ea3,dafe3f50,84f96682,45885bf4,65996b12,993efe44,39861b39,84d5fa89,5242ea8,f498695,57391182) -,S(d6d606e6,28c55e08,61a37803,72c17b1,6a2fe04b,e68a0cc7,60fdf7ac,85c8816c,76b299fb,9e716eed,7f09c879,ea8256bc,a953454e,490edabe,c90a2e5,dd277da8) -,S(d1bb671a,10ec5393,9d67f6aa,3b09e1b,57bb6414,e1f707dc,b832ff67,56289c4,47559cac,311f20cd,55760ed6,2e1e87ac,cd8603e4,c1d0cba9,79f6802,6b294a94) -,S(739ab4bd,6b6132f8,2659fcda,5fb46836,7adf2133,37f897fd,70a9552e,786dcb91,b562e798,2bf508ba,1b932deb,3e6b5962,70bba4ca,402db3b4,d806da6e,fbf6670d) -,S(a710cd7b,2aef0005,6d8db954,2abe6cba,2a6c6132,a48a6670,c501fa82,4de21388,4a6037d1,87db5b52,2996bb0e,47fc7509,1ad9eda8,e15faa56,92d56006,e72fb220) -,S(cdbf59c9,b38e40cc,d63b36b8,b6e894a,c6baa22a,93a1382c,9d7fd070,58e69b7a,3e836c78,6954d509,348314df,8ce08f0b,59967aef,4e5f0136,9c6d0f91,2682d77) -,S(1d32e93f,6e5e138e,7d226636,d5e0946b,8117f91b,bd59efb1,560a15bc,657e4dd3,82c43daa,bc1e23d6,3632e167,6bbca422,9797551f,f729cb5d,c8ac1460,46ed20f7) -,S(2730066,cbe72e84,304e3563,a18689a1,c6c8e0b3,e92d8c0,d63a96c7,e3573337,8804d5cc,6aa91f7a,1ae23506,17332f7d,811b8f1f,752fea43,5208b770,94e67c58) -,S(44624ea,a1607e8b,8bcbd736,9c67f86e,6b0f5226,4cc76a3d,b40042cd,bc621cc4,95867a99,d110d9d9,e382d3d8,a5dff78c,d8db012a,972a87ae,ac24bb42,b2747e53) -,S(8ba805d8,864774eb,4494ca5b,f8257bf6,980466f8,30028340,8aafd665,7f1ef49e,1a1164e3,c1b243cc,57507b07,7348495,95cf67c7,b40d4d7f,f10ad096,3f3866b4) -,S(297d0130,25bdd2d3,f4a008d0,d8c51a3c,7b16b605,95958d9e,93e427a8,7ac01267,56361e70,22138026,683b7bf3,1a6bedaa,988d3938,cf8399aa,e0f3175e,61d7e2bc) -,S(d866bb84,23527208,e66f34bc,e26a8ac0,daea9d03,27c9dccd,cdf0e2a,a0588f52,5e16262d,3564736f,30f26e68,1c5ea26a,b6f63429,f0b25dd2,5635a3b3,1fc45584) -,S(ab1e9d8e,b18e016c,d8ec49e4,388636d,5dd2ab55,8b3dbaa2,433a976a,ad8f16a2,a14cbcec,6327451b,15d47fac,d3f3cbbe,fef828c4,6ea07a0a,9c7155cf,2a2f291c) -,S(cf2f035a,ce393efd,3032cb05,4f4e92ae,5311dd04,bf8f3653,5197748d,2094cd30,75b38e90,9f02bb50,7a778243,35a1c97d,75bc653f,c6dcffcf,615bf8c2,ec6b32f5) -,S(a801d552,e63ba120,2c3ff08b,8fb025df,e545ed35,1adf00f,1a08d982,9e8bf9bd,bdb9274d,f5298fab,4cb08f42,252639e4,a24b553e,892cd1ea,93499c47,41c23165) -,S(f7ad7a63,eb2b90aa,3de2a80e,844e5336,287984f0,6075d9f1,26f24108,f4a5869b,d151e7d,9766a81,1db45134,7cc22654,c5ac40f4,a1d82d96,2de02c58,d46cda31) -,S(732541be,26fcc3e8,c824d539,28282611,96717b00,2af01bc8,57f4c0ac,cded0a80,d44adf28,f26370a8,3c9eee24,4e870dab,3fa7a508,bd14a56f,17c9a845,5055f8ca) -,S(892ee5f2,a5266a86,5bf2094,14c31225,b92dffda,7a3ec00c,ee53dc0b,8c3a3367,21bef833,3b983665,7d243b85,c0b4e2cb,6a5b339d,831cfef5,d676c7d8,87a0df00) -,S(1a4597e3,77569fed,70875f9b,f8f5531e,6bd3b363,b96a345f,9275365c,e1e64424,bd142738,fff7b9db,cbff1c,93a968b1,f0ef3e63,8279b745,21aa53a7,6e611f7a) -,S(c7306404,4b4a3a00,6a584193,e915a174,631c8a2e,ac45973,c815a2f4,aee82f35,280adb29,4f9642cc,cbcc4345,28bacdc5,74beb7df,84c06216,68cc2fec,d78731e6) -,S(c06d9d55,264e4ea9,e160fa78,78a7e4fb,1757f6db,fe610966,503ae03,b4723f2e,c0d82600,ae072564,b29373a1,ff1a036a,45f68f22,9d1594ad,1c9584cc,ab732743) -,S(e878c0b2,bf38b500,6c309a51,5121a3c4,5b13440d,74ff6e27,5bfe71d7,51e6926a,4b8be149,11432ff6,c5169731,1c1db30b,c921cc95,b4c98a39,5228c08,b99b6229) -,S(d1f6621f,89ac4421,7ef39a54,a0922c77,dc7addf4,78b15796,2558ae72,9b24f65e,657556fe,e02492c1,97c9c97a,67bf1d6c,eb689415,80a1ce6a,1e4d98d9,64902f3a) -,S(f9199ae3,ae51f441,d88d72d6,9c1ff64a,d5cc4979,b5fd6a23,c514e9b4,66ea0a5a,3c484bb8,8ec31009,eb95b971,69c7ae03,c20dd833,eef53cdf,fdab8cd5,7a82d4eb) -,S(4e059bc7,516d5fe2,510ae63,d3ca9543,f840bff5,710a744d,62de3965,af6a657f,222309ca,242c5858,5a792045,bbfb3e55,b61daa3c,afedd1ee,19a0038b,f929a47) -,S(c1673413,d8b4298f,6ca04741,a3c32d79,83a7d5b3,dd39ada2,53013d3c,9750ac65,333b1660,7b998e8e,fa7e3d32,2d51c052,1de24d3e,9e389f0e,9a00015d,6cc32d54) -,S(c078723d,8abfbc03,63f12766,cf9c6261,9c31173,5f3a9654,b653a8f9,e08f551c,880fa5d0,be09cb8e,4f145749,1c7f54e1,ceef1477,ba7ed718,5f27013e,32deb89) -,S(c77f3351,4b44b047,3835e3ff,abe8d7ac,ae5f912d,aea4e6e0,4ed03feb,78c41ce5,cade531d,26ee668b,5e2fc7ce,421de2f,d9a14dfb,87286c22,c840144e,1290e910) -,S(90e14c45,4ba40739,10f800b2,bcc7b017,ec58660,bdb1e72,16cc6afb,8320277e,61dfb75d,f5f74d47,287f828d,c4ff46d7,fa351a1f,66da99da,40e74758,2c6bd4b2) -,S(34c65f34,23f2474b,7e2f294c,ed4da6b5,c05d19ef,a2b5a792,103b681a,be1a3f68,d0fba1a3,b12d3e4e,f18acdbc,68fc285b,8ef1365,6aa900c8,c86ae191,37f028ee) -,S(fdcc63b0,aa5017ce,215735cc,2802eee6,aa5ef53a,6a258dd7,a128ed7b,9a5df38d,217ea863,5c9b88c7,19c7f9e6,1286844b,d4f4b758,81535954,7b24df0,1fd5bf03) -,S(10624260,58bb9f6,a5e83740,59595ffd,e7013492,4392c753,15853f4d,9c7070f8,84a92509,e809874f,86e60bdf,85c75d7f,2cab596e,185f56d9,262b06e4,e79cf785) -,S(e21f29c6,70cfc7e8,b104921,bb524414,53acdc5f,fd80066,39417966,ca235c9d,41be8bdb,969ddd53,9093dc1,b85dbd4c,a78f7e68,67fa916c,36136d24,b6c4af38) -,S(154a85d8,60b532cc,16bfdcb2,2769fdf3,6dac818e,cd2daeb0,864eee0c,f78a5c5b,15f2dfc9,3e5e08e4,9d340ce4,bb805afd,79f940dc,f97456eb,c73b47ea,5098e429) -,S(ae6f8b12,d52907e8,4ae5063a,114f8e2a,da7be317,454ea505,571f2132,5e4acf42,49376af9,1aea68bd,cdcd637a,909b639c,b7ff8800,ee003fe6,540d6797,f0f296d1) -,S(de42ac26,47fece4e,69341582,7e3c5b7d,a19dbbd6,22da9fa8,58a3be29,8a47bb65,e57cc346,b83b33cb,79a34805,42811d1d,4178805b,a2b88de6,d90b4fe0,ba8e2740) -,S(14c2030a,c65ec50d,2f7c176c,45256587,59cae0d6,55cd57c2,c1ea970a,11d7bd0e,f3d9f0f0,5881801c,ad4df439,3a3bd2df,1a045181,af7ccbe6,7500b02f,61edece) -,S(32fd40e4,7a94e51b,e4c927c1,42b5f470,b2abd2b6,2773934c,a29a5ff3,924b2e8,b3d74958,f17147e5,1da38ded,7cb09c27,96b7e36c,3149d85c,9b7db85,acd89bbd) -,S(fe468154,cef5383,4820fa33,ad85c158,33635cb4,a55870fb,f588fa6,b8d2918c,96650453,25235606,7bcbc214,b0a04021,bc71c9c5,4617b1be,dd34e6cb,dbb42873) -,S(57826e08,8fa3841d,a33ad3da,e5b5a688,1ee770f5,bfe45f5d,507b4801,ccb511d9,6cb01dc4,4da6d83e,77a6e8a6,d374275e,7d8484fb,4863b5f0,34bace60,30e6b3be) -,S(61bf08fb,1d537624,1dca6119,19f0dfcc,7787090a,6747cdff,8757b037,a1ea59ae,6bcc632a,f4f43c6b,547e6ac5,5854268f,1801614e,5bc9d4e6,ea0dcd99,79f7adb1) -,S(f54dac2c,b5521855,9dc274ce,25b77645,6525e91b,c011e657,5ff812e8,d846ea4a,bb9734dd,af492c18,82bd36fb,f365009,bd41b8bf,1378d9c6,a18477b9,ed627f11) -,S(640ebea4,b85cafa0,d5a38ef7,7373bfb1,36b9571e,f9694724,680e92fb,13efe03e,eaf8d756,c70ee813,60dadfd9,702f660b,516fe3a8,4c50043,92bc7c1b,892a43ac) -,S(6c4814d1,e3c6c16c,366c8776,93b6df4e,266b45a4,26fb0d5b,a2d8fef3,a3803975,d9330c82,8fb02d63,33d57990,b6bedffa,ccd143d5,1b5eac78,5c7f058f,af77a37c) -,S(8dca10b5,95293452,7bd2f264,6170b6fd,59d636a1,f2578b6f,cbde0c96,8bb2db30,50da6972,64516689,57d2273e,55dd046f,1c398d1b,9e5e864d,ae6746fb,825ec83b) -,S(1409a8cc,34389c3d,3fd1b482,fefdb25,3ba32070,dc23b7ae,6b8a1ac0,2f00b776,f8f1c0c6,3bef8011,27ffaf53,d5c07c,430566e2,6c4a9591,f92d694f,82d7a9f8) -,S(1c752b3a,2cdb6257,fe8bb102,e7560b8c,6f86e7ca,e809892f,58df3b16,728c0999,9f1341ca,61dd07f8,882596fd,12531577,d09fcb45,5a086b0d,17dd5390,8326c741) -,S(ae8bb1ae,a4341bf4,c18e7d99,7bc3ebb3,d9f13c9f,b01b93f,885cb32f,d0586999,92eaf2f5,c4e231a6,851a2324,a146400e,6b9eaf63,8eca473b,9d4e034a,3d5c8e6b) -,S(e3d2429b,ba45b4c,2d9c9bed,45f384a1,7d74cd28,56c87772,6d9a98fe,67bcef97,729da85f,927c04e2,c1db1458,c133bdef,c454d0d8,88262b1f,418f3420,5df2380c) -,S(858ee23b,e5166c66,b99d48dd,24cb5078,fcad23e4,a8df9f91,53ffcab2,fb8624b,c5088132,3af436fd,c4f63b91,b06061d4,b26fadd4,6bccaf05,bbe1a8b7,338cdbf2) -,S(7c6a82f0,e2d6c5a3,ba37be0e,1bd8d4e1,99f9aa3e,c9c58054,a66099b9,a4938a1e,881916a7,87e1f9eb,b38906c,c101b0e6,5d245fb7,733c0093,9a7f6f0a,9b4d113b) -,S(4c980c4c,144e4060,c00e7476,c782cb83,42ae8b02,6a155904,c29837b9,fc25caf2,fbc05490,a62e49f5,6daac9dd,5c730f90,183ee565,d62ca949,5bc7ce56,61c2e8c1) -,S(c9b66a8f,6c163037,f5bbc7b9,889e9cfc,357ed5f7,a5e5cd17,6a7e4bd9,6da2fa3e,4eb8b3e5,365a6a44,4b277b4e,89b89e04,2b44cbf8,b73f183d,42c9d8b6,547885d3) -,S(f2f8fb3e,2bd3cd82,99e2faaf,bd5809f0,12190658,b1efa389,f58ffe28,c1056fbe,db6c4cac,35f78015,8fed40c4,341a93b5,64af02c0,12d4817c,478726fe,4faf8273) -,S(8556c286,895b9402,283b5d2,f90ec950,f91c4dbd,6c1c8a0d,6b27cb8c,3bc7da8f,f2979daa,81ea79b5,d3ee2718,4aff3805,9bce1bb7,fa36cc53,4d139b83,c176badf) -,S(4d4c2752,5f24a7d3,ec3673b6,a3c8f110,f5bb5c5f,e9675776,3d81620,90579267,43ee95e6,5834075a,83675a88,15babeb9,824d4703,763b5b09,8c3aff78,837b353c) -,S(cc6689e1,d08b243c,a49a7020,b08ce4ad,817193c7,456fbf4a,97fca02d,f1ccf2e6,32f00dd1,1080c238,cc7e8c9c,60a1b7dd,7503417,2ad0464e,1cdb4221,35ea580d) -,S(966525b9,26bb6596,584cbb3,5da78cec,e6709134,700974f2,6cff34a1,23fba535,b5c18347,52894cc5,26336590,d961af5d,2453d9a3,40bd151d,259d8be7,6c5a9e7b) -,S(df7f51dd,b0e6c595,c8f3de9e,eed5da8b,b05e2cf9,a4555001,760888e6,38b11c4d,19759148,2d4f49cc,b69ef50c,a1cbf3a2,49e3958a,aa9af2c7,becbb72b,8d53f8e2) -,S(4ac2754f,93745ef5,61d6d213,7fd2339a,81cfb619,b6699d9d,21897ed,975f6fea,854a0153,17ce38ef,e070da13,c07829f2,1bf50d40,6458109b,5700a3ec,ed6a3c0) -,S(7c062917,2c59c7ef,2d488806,b1131193,b6b6f0e0,221d1ebb,eca1b358,43959694,77f73272,291c1c73,5d79857d,60cc9db6,b6128e86,4613b3dc,92dd970b,d5dba9ff) -,S(c80152f1,e4b7728a,36acf22,158b8215,d8ce0ea7,401274a2,1139dd71,59d81557,dc0c54e9,88d2ee7d,e8a56eab,d358aaaa,4542a45b,a170db58,89d634f1,dae95df5) -,S(9c2352fa,464cd430,31f43578,53feaddf,7d5ee143,c6403ea1,230961b6,377423c6,841277d5,71934bc0,20f71b36,dcba2293,65819fa2,b20c57b3,5774a524,d6fb20d8) -,S(8d7554f5,fcaae19,cbc20c7b,73f22f30,aaeba42c,a22bef77,3d780205,8c8e1d7a,c6bfa4c0,9db5101,d33abd0c,47c4e125,bffab86b,8ed50864,6b6a2b0f,322bf5d2) -,S(1e75acec,28a2ce98,5929479d,e0842826,bd556b56,6961d5db,66c9055f,b1b63635,89cbe475,d2036dbc,9227db67,d62b51e9,ac669a22,76e4e1e9,d0be9b1d,58efca6d) -,S(9fe62187,5e71bed4,7d9f2d79,91e76b41,88b2c8c6,10f20d33,5b38bed2,eee85236,9a3fe290,fbe192f4,8a44177d,4f0d037a,fc6fa8b1,c57032b1,3d5894c8,c426e8cd) -,S(8dc1710f,8869b645,73c361d1,ada3f43f,6f2c175e,b24ec358,6409e978,1687a220,37a4187e,bce1845,9520b60,9317a4b8,f33b371f,1a768ba1,96316f41,373ec87) -,S(71ad2a17,5cf75568,214fbbd1,f177c1a9,9eb75486,c161f1b7,ad47063b,567e8d6a,29d80786,e42d9cd,4c801f96,a7d44eda,5e325acf,3b82e143,2576ff1a,3b334850) -,S(be0eeb11,aaab9c1c,ef7a2004,731e3ca4,435c8a02,548b36b2,db68ea4a,56ad8b7a,cd7ad5,c9b7e867,1a1c7889,95e45cff,bcdfe42a,6222e0c4,1054a0f5,f7bb00f2) -,S(364154a1,3a7d9fa0,b349c6fb,ec36ea43,51cdabfd,8fa79318,88e4ea5d,ee8bf6d4,40b40474,7e8b30a6,a3cdf3ba,f0956fa5,f7f61a2f,89a8cf7e,c2ed7445,504a71ee) -,S(19daf7ab,c9f69a31,8b2cf1c6,69d50532,5bbd7254,c4bc4126,d7b31dcd,e7b558f1,6b740772,606874b6,5b1f819c,c7339ffa,30669d9b,2770506c,e9fb243c,6ee4a925) -,S(5ab3dc00,eb9efd03,ae491844,50fe176b,765c5da7,d95ffe6f,61aa0073,7366c918,2603f1ce,935e3af8,af5e3d1d,d76a3410,200037c,87c17a93,96e11018,260dfa01) -,S(47bc2c3,d7dd83f7,2b2160a2,64640e58,16316d0e,3272abf4,b859dd0f,6c7b27d7,1ceefb1f,23dc61a7,2f663d9c,3cdd6625,441a63f9,f9cae8d5,c4ba88d1,22c0f258) -,S(b220435e,e903f1bf,3b443549,5a01e739,250be2c1,43f08a73,bd7dbfcd,75602ab5,3659abe7,953b817f,fd1c02b6,56da4e54,9df250c0,7c28e9c0,89ba315a,bf25e1dd) -,S(be25604b,d52413fe,2c743031,98aeff78,c27086f8,97fe4b20,be5b6251,52fa2fb4,ebdb5191,aa195ee,a0a39bf7,399bbe03,76073830,fe54cccb,a3194eef,d8d34fe5) -,S(5cedfbfd,633f16f7,8ec8a8f,3dad7cc6,edc1a6bf,3e37cf3,65069731,64aad0e3,70e687a9,d8632ed6,ab188f14,229f2e31,34a3adc8,727c7b0a,d7a16d78,1244c9a9) -,S(8109ca32,a86fa712,690315e2,1bc09265,bb6bae74,588f507,1bedebac,47e54a3a,e7f3342c,6e8a3dd1,f6d02bf7,5610511f,d0cffb40,1c14633d,308c2939,e662cbf2) -,S(54264a0f,dfb894a6,b29b6922,b859d715,77f0359,ef825442,e0d43b79,a0fbfe3e,4884ea59,cb88fb60,4ca4de66,110b7d98,ec529112,d4574cbe,9a2e7a5e,5a4a644d) -,S(f2756955,a6a7db9f,eabaae3c,844cfd37,5d86ad8b,a84dcfba,582bf4a,273f90f3,b24c14a7,d2f60103,a7d3652b,c5e68988,390c0e67,1f0fca22,ed927f6c,96302239) -,S(351da3e,6ab7c98e,840d0dfa,e7231d21,ca21a81b,3638371a,673892d2,e40498b9,e1c5ffeb,43b443ab,d31332bf,aa314fda,5a4c2634,afccfb97,67bceb3f,13ed5f3b) -,S(b5107be0,90f84c7a,e3d89782,c6751b22,f9a7ad2b,3a1810c8,f14bdd8d,52344357,3d5571d2,36a7c9a1,aada0835,9e8ce162,c46a878,5e09265d,bb52b419,144c5b6c) -,S(b6172135,85b2557b,7c253189,9422c428,79825eaf,64d8e8e2,2f7bae12,31c9ceb7,dbfe3609,df9b8e1a,33629219,eb241daf,42d8be2d,b9a20a0d,942f24ce,1a117e3b) -,S(5eeaaf7f,577b445d,13481c9d,a567825c,f0a5a3f2,9ccfbbbf,d8f1f8a5,36e712cf,84a4352d,c40556ff,ab75acd3,b5a63366,39119d8b,f814feb,e55fb3ee,dea5821c) -,S(c1bec874,44b0210a,9a86ca9b,94891d00,e1fee6c7,490aa26a,1af61f97,5dad1c13,14a61af6,d280ea47,433d795,1786351d,f90a9879,7678781a,8d9d8884,e88a06a6) -,S(34787098,f0df9eb5,e4825449,6fd7eb6b,3118dd45,aa0ccea9,f606a794,126b9ad3,85c30ff1,c8dbde4b,88fe9ff8,20c9908a,a35a0c53,c2175524,a5929eea,5566a564) -,S(6599b07b,5d31c19e,ee02e287,ccaa1bce,70890b14,cd739140,6f1d862b,39d794a6,d18396df,27e6fc21,a9c36a1,8d8f73ef,c79e6c56,ecbab9cb,83750220,a816d5ff) -,S(27b50b15,c92c010c,60feb473,5ac6ae0f,9ec0af75,81e41a90,a3a940da,a1a44ee8,31c2c3c8,61e64b7c,df8ca011,bd4002ba,5373ec63,8c3608fd,619bbb92,3552c1b5) -,S(40aed5af,953f3a17,f5d17622,127f16bd,4cc5bbee,33e23443,5f49c4f7,a48e7a32,e47011ee,96c702a1,1eff428d,2940ddab,d17b76cc,6765d5ed,126876ea,2496f6e6) -,S(cb56977d,f69956da,cf40909b,69fe44c1,4a5ad547,a025d684,c9815ff1,b5331ef8,9904de7a,9ce0f656,2f025ffc,79e8b3a4,2e410ad5,8f0caa16,62a13e29,f0b00bd2) -,S(11dc40ff,58c6d2a5,9768a776,41c611a8,2aa651c1,15e9d36c,bd3ebd18,ac7a0df9,4717af95,274f820,28592bc7,4a84e467,9d168dfd,826a292,5789edf4,a06e0e50) -,S(3baee366,3d2033a7,f3170bd0,723eded9,2fad6501,702fa530,b26d0623,8d6992d0,47497025,41900ac2,fb236a26,81ca09db,c34fc84e,98ca289b,63e07d17,2e4671f4) -,S(6b19e8e6,b2010e2b,d461d716,66f691ea,88417df6,773208f5,18ee5fb1,e0fb580,a7c74380,9f744b05,99b6c4e4,709a8b86,241ef931,effd9323,9a6d15f7,22916578) -,S(412a2c52,b31158ab,9d3bf4ac,d4355eab,b7e94e98,6a839681,94a7322c,72bff9f8,c649c493,b19b713c,8b3c4e30,567547ab,472a599e,cc95ea73,d36d373d,c92f7dc1) -,S(b5e0c57b,f79e7364,9826a818,bed1d521,3cb88645,5dc91a4,eb157a8a,dd869c24,752feebe,9614e233,3b876297,175078fe,f9adc63a,4639242,6c88ca94,aa06163c) -,S(f656ab08,9e75bac0,6eaaf373,1cc71347,6a636347,35ab57c0,222589b1,e914160f,d05493f3,52b660e0,4cb00b45,5cede6b1,74337488,dd1650c8,4ddeaeee,b73a6ae9) -,S(bd2465b7,b5af290d,2d1157fa,76e4550c,ddb23922,7d30c255,8f0cc3ad,ae5fa32a,63a28c79,cbb50c21,bcfc85ab,269090ea,d56f6396,1fcc6dfe,b3a000e7,3284880a) -,S(d53c8d24,3dc3600d,fa32dd69,11a87ab,722108e4,192d7cec,4d84eefb,9b32a351,af681092,6afda47a,ef5bc91d,97f273ab,78a21c01,64f59c0c,ed66f7a8,5b67ca24) -,S(4a83ae18,ab379d5e,f6cd2be,77f64abf,8fc23b52,edc88ea4,9efc1bfe,402432c9,e9eef9c2,f595ad74,abf10b85,6ea24ac5,603d46de,c320f9d9,a1453be3,92eef8a6) -,S(d1df4416,dc7cce22,832f9ab0,b74d927b,f9b3b7a5,c52acee5,3d95812f,f26caa82,9e5242f1,163a863a,a5702af3,cdc21f7d,b0143f76,ddba2a2d,d592676c,57c310f) -,S(e6add3b2,583addd7,8299fd2b,14b87155,93dcb13a,3231458d,ab6864ce,87b9c890,384bb2a0,930ecde4,1e9945f6,247a6530,58e26bf6,88226c8f,ee9a1ec7,a1f07740) -,S(7d3f5447,295479f2,96c11443,eb9b1fbd,fe81a258,78ce4195,d2f01290,7e01fe4,d12e4fd7,9f66a45b,2596b066,651d8686,83e62627,95f681a4,12022046,86304ac5) -,S(60636a7,45442fa9,57f21668,7fbdde4e,a6f7f80a,ea2832e,ca3ea43b,d1f12709,395ef963,bec2979c,fb211f8b,da3f4b4f,2c129ce8,26a35367,d955243d,3b40022b) -,S(6bce0837,39c04ba6,b9dbba8c,f668bea9,4d8a8b38,2ac17b87,765bdd52,86e47963,a2d85e2a,7ff5c433,c2c77363,666ddd3f,3fb28f8b,2b7aea1,16a8f42e,384a0a37) -,S(59e4e7e4,438ceba0,cad5f146,bc127c1c,df7f4735,f581a0b2,6a53a366,947d4581,32207f5,95fa4cee,3c8ea269,9578b28b,6290a3c,33eb0ba7,e3bf7267,b2bfa445) -,S(ae2cb18,d4f053ea,3a497162,8c822f6d,72806f79,bd39dcc8,364ea256,f30af032,583d363,b9ac6fd2,709985c5,79603d9,4902da04,1563879d,245433d0,abc54a1) -,S(bc4eb578,630ebde0,f58fb192,377de006,c630e96a,51219379,43e9a240,c30951f7,5224d403,4635eea8,e63b9e87,2875f27a,129de5ff,fae3d516,5f6d0cfb,5bb7e584) -,S(848ca19,6fc34e2c,e484f74d,79565ba6,9685128e,7b2d21fe,8cf0e4b1,edbd3b13,2a41e449,532de110,e0d3fbb2,bb794fb9,32d0d4a6,33aa65f8,ec40e5bd,5c4314ef) -,S(b90e1d09,4257ae30,bd12debe,648d4cea,3f063740,e3f9d3fb,c67eaa4b,8ca0bcfd,5604b475,31b28a6a,e0a13a47,31f6cc70,de91d429,d2204d45,e1423652,5a5a4b43) -,S(430752bc,3e1191f3,6e084f2,5f3e30b,da104f40,1de93267,62dde1cc,39d94c71,e707daaf,841f62f5,6d9c45fd,3304e616,30b6af9c,d6871476,6132e127,40f5ebe0) -,S(ab919243,c8bd75b9,d67f331a,b3b487e0,ee9c97ff,c35de7b7,e29827c1,ab643be2,d4d853b0,3971f1fc,ce365db9,cf4a54f1,5e6059c3,c5138b2e,dd765c51,7bdc0c7d) -,S(adce8be3,2277c2cf,6ee46781,f1da8f30,1cafea51,18322adf,8d6b8a29,fc3f7551,e819a7fe,73311592,bcfda0a7,3609748e,6c039066,feba9e5d,41e125e8,4dd67fb4) -,S(d6ed759d,15f5d47a,146e7fac,423b952a,5eabc238,a0382762,c2a226ed,8c24b601,456caee9,1c212f19,acdc2d82,9eb90cb0,2ac35a72,8d280042,658af65a,b6840e9e) -,S(3583bc8f,c3ca09c6,6f2f4fe2,83da5c47,f0ebcccb,fe8e94ab,fd315173,fd3fb2be,ed60aa95,504e9b31,81225d0c,a4f513c6,6da2a2ce,9fa9afaa,c12e04c4,f1d50b59) -,S(223879b3,b9e50b46,7bceda29,905d09be,1acb206,5b23a61c,686d6f39,bf0744d4,a8326789,ddb38afb,e993ae33,6cb1c3f7,92addfad,e47663fa,52a296a3,b6f2873f) -,S(29329ca6,c6ce20b5,81a90873,7206d44a,95ff382f,1ca0cafb,755a3450,83883d69,5d2aa87f,59e13a0a,8ca4460a,4db7f496,1c118ab9,b4f783e1,305bf43,ed44fe71) -,S(e1c6a08c,593454a4,aa116edf,13345cdf,6dc00b1d,b63b7a64,fdea70bf,e4301ea,e0f9f3ff,5e7e395c,42b3e093,87b8363d,37092335,31c317d8,1b61f20d,f06fa662) -,S(da098bf4,133f656d,f2a09d95,c437eaed,fadb4c9,8102d164,b355c7c9,38e65216,74ffa0cb,1fe7f0af,8a1a6ed0,531f8e98,28be1110,90b580dc,5ff55fe7,b75d9b66) -,S(f3f7c27d,54b40dec,5b3da04,b2cd222e,1507aa70,bd236bd4,2d6e5c95,c71bbe7c,80e17f04,7cb2203c,cc58c364,d77e9a1c,8abb092c,18a9f8d5,6edcdaf6,1ae4062e) -,S(466b6e28,8981fbcc,92c4ec3a,a54eae4e,2e266041,5b242aa5,523579b5,b1fe93cd,9ae0e0c7,d056b2a6,831f540c,67a97732,33bedbd5,bdcd2904,2a8987cf,1fe2a86f) -,S(e15af336,8c59576c,a36b5f80,d9ec0458,d9534bf2,6650cc26,a2079946,ac43fcce,7fe0423,e6ea121b,308d167b,ada98cc2,fb8cd772,f95c3d84,c1907f09,66e5b46c) -,S(c20ab235,6dfe247,d8fd1a9c,d8c4f16d,a5322bff,692efe70,f256521d,1b990492,3c0aae11,e4cf9a17,57feb324,e1a2f0e,48d5978c,6007429d,ab32b2f4,d1a19bd6) -,S(d8b6c190,4a848755,f126651c,d96fe374,7c5a3744,1fb7048f,e15c4693,dbe35e17,fefb5310,e7e38891,70fca6ec,61ffd2d3,72605ed3,4bd22d73,c852a92c,c22fd30f) -,S(a8256823,5416b18,a01d2df0,f47757d0,f42c26e3,780ae6ca,2421aef3,83361f8f,c9192412,77948b80,87d1c45c,a95224ae,5f9c294d,fa74c1ec,42ad6004,f8646540) -,S(28f2a237,c4dcad5b,a6bb5274,1e743020,e90bc598,8ee66b39,cd672ed2,ccac6c33,416c59f6,c1b1b036,f38a5523,722954eb,52848872,8ecfac4b,5bfea63d,cfc181db) -,S(e65d92b7,571bbea5,4e541862,a4dc7890,bd546782,bca886e8,3c1ea17f,33d77e9f,6116ed43,13def2ae,6b0f2b92,ff07c91f,4139982c,12511152,fd7ed5fd,851bd04e) -,S(68adb9ee,c7ae0198,726b0457,91fe52b4,b5c2ec78,4199da86,bceac230,d55914b5,41ff0808,e42aae9f,e93ff704,6f08fb38,4b72d7ec,7b1dc6cc,e0071306,7ee5cfd5) -,S(3f0f7d6e,6bf73a97,40eb842a,35cd4800,85db4766,f7fc374e,1ac915c0,e4d6d6e2,392aecf6,8b446346,2d37a106,8299a09d,9ceeeaa4,f0ee3397,dc54b2f3,5e3332d6) -,S(929aa2ad,48a1f3a0,24fbf7ea,70e9d57b,9ef65afc,b3cb2d8c,5041a933,321359e4,b1cfddf3,4693ff40,ef16d8f1,8fd1fec,a71252cf,ee13ba4a,16094c20,3b4fbf66) -,S(9a9ff691,f16ad46a,d0b753a6,fb09025b,e196b443,839114a9,580eb2e7,fc494e2a,3776f83b,92c135f2,5e5e600,27f65e2d,582fa2cb,f5842c3f,644fb726,1e305c67) -,S(6752b226,65900d81,47ea6b73,25b212a2,9bcf899,799eb1e6,213857dc,6959d32e,fafdac9c,2f791be2,d1cfa78b,7530859d,c1b2ff43,e546de14,1f42baef,3d6d1371) -,S(9fc32749,e636e845,aebfede1,1d0928a1,8cc6e3b4,5a2536a9,fae0a2b,ddca6434,9021fa85,56c5fe05,cc87bdd3,6cebb00b,3d1b77e1,80ce2f8a,a4d155ee,84fc6441) -,S(60ca338f,ff905b58,b1d70d5f,89c4cebe,15600495,698b262b,e1550da,a0054a99,6d57de6b,f7c637ac,4d728090,9960ce01,4b541abe,754b82c,bfc87ad1,5fbe6ede) -,S(91537a09,697d3658,b06b853,d07153da,6d0228f0,786f334,db6151c,64becb87,231a2595,e04dadb4,b3900188,9f34b43d,5cd3c81c,f13fc6df,d432a377,4f53015) -,S(93a85356,195e109d,ddf054d1,2a901d83,b10db692,fc17e878,849eecfa,5d387fff,58f2112c,3df38b46,51e347fa,5aa8569a,48d95b2,670c76ba,d0de339a,72ee87e4) -,S(d5d1f0ac,bc2ed1f,50490030,43fd020d,7a1afb27,cdf78318,6a043bef,b0708eec,c473908d,4d754fe2,a5fdea86,62a6ad21,b711560d,77ad85d4,e3b47175,b5133e52) -,S(afe283d3,8cbb257c,5f2c0dde,2fd1bd56,2ad33e5e,605c24be,51a255ec,5725b1bf,a050f64e,978a9ee6,36885656,5cf22d7c,2fb45e64,6df60abf,6d3f9e1,132311a7) -,S(179667a1,72e0c37f,33e835d9,b5b6f326,3d963f37,1dd07d40,e790e0a1,21765180,da24290e,e38be6aa,ea2e86e6,bf683d4d,90f5fb79,20257b78,aee8be4d,fa65eea1) -,S(9add8ed2,6feeca4c,d3e583f0,88398ecc,f245d30,a888e135,b86ac1a7,e4e42d05,41bcd07c,c2e6acef,bc488d74,8a338c9a,7e6d3e43,85029f75,63dcde83,54d82232) -,S(25ba1237,6bb6e146,5195db78,29f51889,869dc972,fc9805d3,f6dfabb8,bce6b,a39dfc2d,223f924,47ae617d,537a4877,e6a47e0a,7e5fdbca,e1bfc956,a9c42571) -,S(dbd78620,c9a75ddf,55d0a41f,7312ec44,d3108f34,e7d75195,d3d49f99,88e2f986,c184bf06,ef304b72,1637bd3a,d511dc92,297dd5f5,9bd8d053,a048702a,fdbc400f) -,S(f8d67c64,b71d14af,b07d734f,675913cb,7a1bebc1,6e4a4916,44f8f4f4,6eb69448,eda6023e,5df40a5c,89a7bd26,94767a5,f17042ad,f95fb4f2,88bf9fdd,b91b280f) -,S(fd5f3228,56c096d3,4683a672,64ca5d76,58a8b7bd,41c3c1f2,5de2e6b3,164c8fd7,8372223f,3fab4f89,f6604b16,dd66db85,b8a27eaf,30741bd3,7a90d34f,f19c154a) -,S(ea49d0e1,b07948b8,b122d52f,8e8be6c6,e470262e,1c239b40,483a6076,c005136,b81ee77d,3d8489ab,42a9978,48a2ba17,273517fa,604a2abd,f2e1e726,d71b7e19) -,S(bab8ce82,c1210a99,ce17a5cf,3636baa5,52cc793f,89fd25bc,b6f078c3,92149bc8,afe2bb15,d00cf460,953a7c1c,8e466556,136ebd4e,ebf61a76,e49726f1,e3aa8e73) -,S(98802d2e,225bcdc7,9e02e746,891cdf12,ac434154,c08c2e78,589dd9f4,27277e1e,1eeb6b5c,4fc6459f,28e3fc49,6d9a6baa,fc66ede0,85d4b0d7,4af45840,78987514) -,S(5dc54290,2b33fd65,7d37a22c,c669ff21,75825cad,b34e1ee4,7aecf7f5,2dfd750a,41fb96de,60564df7,6c8ec857,d7f0ceda,2b330fda,2195a70f,5f64f973,ec0144d6) -,S(c4894f07,f6679f4e,13369495,dd501aca,73666303,2f7bab6c,fb81d7a9,1495834e,31b7e5c0,35e81c22,89de373f,85d648dd,892021e7,1d120742,e4ac6af2,44a25a8d) -,S(f7c9950c,d5c5afda,ede613bb,8f21ca15,b0e92487,81e16378,c7f2cba,5efd7beb,1746037c,b9211262,f0867180,16f0fed1,75debbb9,5eca39df,ed757c02,aa282d24) -,S(96703c67,4e7e2859,f274e7f8,d458f7a2,89ac0bc4,961ef3bb,b120a1e1,b82b5a55,1f92a15e,5e8b476a,a165823e,59da387f,2f9ab551,4703010c,c35b787d,c7d8ddf) -,S(4e8fa83b,bf9307a7,8b997e49,68227e86,a0402f0,643f98bc,5d13837b,63d08156,81f1f92,bb2a9ca8,14cd212a,6de7ebe9,7a04ed97,4de89e5f,cd8749ba,6e49e4ea) -,S(bc239122,b0cb1f43,2ed0c2ec,bb3c5391,b7eebafc,c4190fc5,8f62d313,7f58c1bd,5b3cd401,d9cf971a,6b9f70a4,b6f8fab2,d0026a24,cceaea2,a86aef0e,a76a3cfa) -,S(90b7138d,5d2e11b2,86d29b78,521aa9d7,205351f0,1451e134,8a593b78,fe5f1778,77cdd3f5,829af7d9,937ac98f,58a78b99,b54fe9d7,593415f2,18dde880,b5039a37) -,S(631d0fd3,27bca9a6,aec8eff9,54fdde7b,df43edb7,b1f602fd,a32c387,825841e7,d6e8af71,273702a3,a2a767af,3c438f0,b07ab614,2fd0f67d,74a9d358,74e29100) -,S(ac2a0153,d810371c,6a7bc097,ed09be67,14ae9935,4a9910ad,7ee77ab9,6d54cdee,39707795,a4f01640,87b5e149,2ec8fc1e,be11d8f7,c43555ac,6f4674fb,8ac5b0b0) -,S(89751ec3,c1aeb288,1953d3d3,f2f634ee,29b1aa18,c55b8b62,59d5cadc,852ac99e,8b4d51e7,e2f94c0e,ef80e16d,9b62c935,2ac91394,902537f1,e93744c9,72f22a3) -,S(849a6cfe,5e3ab81,2e21f491,4c6ec76b,5233d405,7ffd487d,bb0b5091,2ac499d2,a490b967,b5fcea21,d0135ec3,c9ed5efe,ecf7ac6c,81e06648,66cdca60,a1be7037) -,S(4ffa897e,17d760e,41859b6f,3bfc421c,55fa1e31,eb999f72,5028be41,cc8a9ed,87b4b5ab,d9875b94,aebe632c,64ea441c,71ec7353,5ae2c83b,d9b904e3,7f7fd326) -,S(4fda56c3,8bae34b6,55b2ed2b,621e5074,7ed1dc13,a1a815f3,be12a223,d54c43c6,6cfaa7b3,c53a1dfd,a03dc7eb,6086b84f,ac280c55,7c357d16,fa5938cb,c149bb10) -,S(b572c9c7,9ecd2ee3,154c56a5,9c81444c,b16df1f7,82198eb7,40a78c7a,e5c7e99,a1fb603e,42d3ac6a,5ef5dd74,ced31624,fed9086,5b02b3c9,2bbad21a,ffb1b79a) -,S(a77038c8,e79abb7e,a94b4e17,35f0f5fd,a07b1ad3,367047f4,895a5104,dfeaa623,e9bef9db,e8e2078b,346aee0e,efd64657,2210e451,ed2e8d63,b92be059,c577e1ea) -,S(3158f3e1,14de5071,c6e2bff9,32f1c269,7e374dbb,786e960b,7e59df03,26e2e1c9,1d0e950a,9124a626,4553d29,3e5cb8cd,9dd05d45,f48de2ba,f60fcee0,ca42a9cd) -,S(b0825b69,373aad7b,53c256c3,1258169f,2736d47b,1c4aa22d,a052b864,375a807c,23ec01bf,a857fa0,1f3d46f8,7857b211,f7533c9d,611dfdf7,951d190a,d7ef07db) -,S(9578e6e2,1a738f66,ca04647c,ec610da1,afc5602b,1e72e096,bd192ed,f19c205c,fb5da982,7208b4e6,11e6dc5d,dd8b8ba3,569a578f,275e6d21,3417fd37,7e4e6cae) -,S(a0aa979a,5448d27b,e42c39e2,2fcdf40e,d3b64c74,42b2c40e,2f6d38ff,fabb196d,7a9bf938,937be244,38aa212,d9342f98,ab9a35dc,1361fe56,5d04a25f,176eaff9) -,S(f535145c,d57aca97,f4cef68b,ce57d5fb,62ccd1ea,b48dfeb1,3b87b188,4614be82,1323e73b,dcd6b16f,bc481294,198d8235,b98a1885,a336f07d,593e5df3,a21ccc11) -,S(587d9e30,2f9d60ed,eeae03ca,252cd2fb,117bd07,fc91163d,a7cc569d,1b023f9f,7bcd5b42,3c01038c,9d3f7f71,ef52b4ef,a99e4be1,6de4314a,5e517e8a,950f45d5) -,S(b1e3b70,aa8a0cab,ec119ca0,5430396,ed98d9f9,e3e1a650,94cbd985,4cbd0932,3c9496c8,eec7dd92,9718f7a2,8c7a67b5,c4e55d88,5a943cc0,deefbd11,fa4f8de2) -,S(8f7001e2,928200d3,a478ba12,424be4c8,de8f16f2,a932e000,1468d9a0,48d57816,bedb10ab,72eacf26,1ab17a34,e5138686,34995952,545129b5,5bd6c7cd,84b50bc3) -,S(c95bae04,e1c397e1,498822f7,b7910019,922e43de,83119ae4,8517aa9b,aad6f35,8fff7d3c,d8bd7af6,c8523375,84f73aa,2f1b03c6,585c7987,98fe29aa,36620486) -,S(228fba21,ffe5ff9c,e04017e2,7cf04c71,1cc454d4,534d3404,49bbd1c9,60d2230d,825fb4a9,169ab67f,50963731,10f27fc3,f6f7acbc,9f2918f,c6f0bfa8,a92ed32e) -,S(89610875,bb7c5f53,87929e38,22249817,ade80ed2,a69dec5a,eee31a48,6c40e316,f7d5f522,92a53c2a,447f9b6a,5c06b3f,22fcf19e,4a200ef0,9167c255,a373ef47) -,S(9f0542f8,8e7e2b4b,c20b7b5b,87f051af,6650f605,67dca77b,7b6e1ccb,2a63f6e8,2b80c840,5e343203,d0a7d1cc,ccc99736,4bfa10d0,6e71880d,a0955cc0,b1ff98a2) -,S(859b6ce5,b7075222,549b59bd,3de967b2,1655d163,c57e94e5,6c9fae12,e5222061,25b8cf47,baba2000,19036027,fc86f03a,1c4c406c,4a8b2c34,398b7191,bf125aa6) -,S(e6febd1c,91e66c5d,afc7caaf,4150a023,b70c57fe,2a14f84b,c9fabce7,34982ddd,b606e3cc,f997b627,a0a02c4c,e147e0ef,58e3e275,a43940a3,4ac74760,457ae5e5) -,S(956912,ea1f5ce3,52d39e67,a41e4ec5,8c7106e0,4552e1a0,48e4b195,6cff8c01,b1eb2fe7,7419c11f,f7e34dfd,a752064,39fa2e6f,b9f9d34f,70740950,cee3cf40) -,S(1bca39eb,9b6a5d5,3575e510,6955143d,a6fe9d67,999500,ea78cb89,d832ddba,47afc8c9,358e5f7f,e92370d1,44ecac99,4e69afbf,6ef1af7a,32adefb7,9331173f) -,S(2c6db85b,c4d84c2e,61f0b5c6,2f330e7e,dd672c63,a14fa534,9e4d1488,ad462c5c,bb488565,cb2da5c9,be8a6f6,c71555bd,d85b4a53,20ca0753,f524f91e,ca1e331d) -,S(f66c0d73,36bc153c,5f85e297,52845255,8957a08b,603e4d3c,746e0c19,572c9f82,74e32022,faa58df3,1e4a02b6,f00ce5e7,bf34ec93,d8095144,a1af69f9,c637f01a) -,S(774959ef,cf8c126a,67012f8,10217d39,298040ad,da97e973,9fe13f9,927f6757,c33b9f7d,b2901f8f,171151c5,dd8b890b,62c0a1c1,9b7d4691,9c23ed00,cdafdc24) -,S(f59361a5,74b69786,f7ea4abe,44eef2f4,5000328d,dd72c2d5,a6dce9b8,63037ca6,34deb360,ece45bb0,a2417618,e7c67adb,24b33620,80d464af,a1ef20ae,35da05b) -,S(add233d,31c179da,bb62567d,2a5bc5d7,9afc5c50,93dc8196,9767ccf3,8790a5a0,b9ecd675,13d81a64,8ca5ab2f,4d580d3f,7f7d4def,909f2759,af61e497,b6d8f82e) -,S(3d204b0d,1d705714,7e947150,52a531bd,b6749743,5c94c7f4,8f821579,170fa257,ae20862b,cd86c6d8,e8344911,cfa8914d,f40e3a80,b762fd54,e2b7f704,4de86017) -,S(22be58e5,1c5ce0e2,f1ee6f5e,523a2f55,e110c4b7,bd3135d2,39d7a25a,94bc13f4,56894dfd,6c2cb7c8,5689cf04,3c1d4221,a7dfdfd0,d05b1e68,cc41afb6,6a472a04) -,S(6e015fb9,af8ec2d3,9f101509,f8f1fc9c,d95dcf57,82621ead,4651a062,c8487687,c7dc43db,d1d068da,9cb751fe,51251bf8,7f6edbc0,bb19925a,bc02cf6d,d7cf8554) -,S(3baa1e60,42844786,fb720758,67ec526c,2e0f7fab,ac8e0eca,24eff876,47720c2b,909d202a,b40037e,9afe2ef4,d8638491,d27a1d24,98e497a0,908a52c1,52b1f8da) -,S(689cad9b,2cde514,b9c25275,d6a3e68a,ce0b2216,4418a403,a83d88a2,4dc4d25f,53e7be29,165632b1,d1887aab,94c525f7,86166f32,56b44e70,295dd0d8,bb9f22f0) -,S(c1cc4802,101d0251,76875033,ed9fcc07,a66a57a7,71ca1374,63d7c7b,655fdb6b,ffa73601,5dc4ccf6,8afc41e8,e254501,93eb75a1,60a98c,6c800d0c,f10edc5a) -,S(888e34,86eef22e,2a25aaec,9bc9b84d,fec14fa4,c98e9d57,4fb9e08f,5b0f76a2,d2e3ec7c,db9286b4,b0223762,234d771f,a5b6f378,b6a4bbb3,c94c3303,af49b4f3) -,S(ab355f17,a43d24dc,330a9195,c2be2ed5,6894a9d,e38d3dd1,1a31f9d9,9ca88a93,7f8f8748,c07cfbd9,fce0ac7c,b624f2d0,f83bc49a,53276b00,7ca2b821,51988e6e) -,S(12a65c28,aa2020c6,5f56d916,c1cd111,10f68f0c,2408863e,635e05f0,1dbe4141,48bbab23,1be95484,7a0b61d3,89913ff4,5a8b97bc,384a0780,294d97d3,9c9b9be2) -,S(9d96107c,591d95b,42854234,1371290b,370640d4,2dca9fb,5f5397db,84a5577e,183fa1b1,cda4719e,869c8b44,e97cf214,3ab14e5d,e5d0d781,78e5d68a,923b3dc4) -,S(7ad05c26,aa642731,9eded7a,43f72faa,d344ef4,d413d884,67bea154,4459ad55,cbd8ea0,7fcbda54,813f990b,a6eb8450,6faa12d1,cd478a9b,cc278a32,511ba8f9) -,S(d1ddaa71,27959090,65ea358f,b887e4b0,894028bd,457d217,f1ef6b9d,143a2292,e040cd3,d5f19cc0,456a55a3,88ccb81f,787eae9e,51a289cd,d8ae8d25,881e6ed2) -,S(ec3bc5da,a9be90e5,1af0c1a2,bf41adfa,8023bb4f,b40e65d1,c65a0e82,6bdc30a6,d4962737,f9df1f4,48df1d9c,d8f7a140,233c2175,5d8ef5c6,f292b230,9ce263cf) -,S(f3135904,dc55f515,806dbecf,d51b8106,f13dd1d3,43f78e05,91de1f94,86fd193f,c5bd3002,24934faa,2f9ec634,53fcb3a8,20af608e,efbeb963,23871faf,a7dc2246) -,S(fb5f135f,b2f7638f,36bc332e,1bbd2050,335c141a,49db5452,619f266f,df85e8f9,6e71e045,827c3ef1,b75bffd2,ce54361,1e627cca,c94c8d3c,9b8fff62,e10b7b6) -,S(d1dc12ca,62a1285,e3c16125,f71a1b7,7b0dfa9d,c1068ba,2bb56bf3,98864620,6a6bda82,232af467,afaecb2d,f4a7ca53,3c41d63,d8f7093b,f04a2964,6e4f19e0) -,S(52354730,2d24cb39,f9117e35,d9374ea8,f3b6d027,cfcc23b7,58f0bc1d,b4f2d94,83719f2a,ccc79c43,1d8ea584,c78dd5f8,daded80a,fc3341f2,5789181b,7671d586) -,S(fd8247d,d208839f,93eebd97,f6068ae8,a6640a46,48c16b65,6bc992b8,4ccfc5e6,dd560b93,9b530bf9,a8bfd5f9,614f498a,49e54061,61107517,e9ab0104,54e42f3f) -,S(da5d83a1,9254990a,c14af844,df04bcb9,accab655,5468d08f,3b5d93b8,425f1600,9e5a8786,6be51fe3,54bc2412,6315f8de,1f0113cb,ae78b72f,cc70572c,d978fba6) -,S(1205f8ce,b9c89dce,13cd44f4,9ef0b2e8,14b78639,372d9f61,f0543f54,bdef2944,6c820a46,afd1dd98,499636d6,afc34ae8,218a8c90,2f210dbe,530a9211,a058768a) -,S(7d94e0f3,3969c5c8,164739ff,11aa05e0,45b32702,333d947f,8a0cbb80,57dd3c71,7b92b367,33f92723,17948d9c,a1875303,865fd47c,ecab145d,9ac9d4c9,864d62bb) -,S(d7f22ab5,6840dd87,d939c4ae,3bbe5a67,75e7a2c6,dc969a96,40c7f65a,9c18b2d8,bfc60718,2509244,b0ab951b,f4032852,54b73d5,a23a19a0,b4ccff25,1e5dbd6a) -,S(cee33146,2accf4fa,5f06b598,cc36aa06,342c83d7,eb4b6aff,90b9555b,fee0fe61,97583a48,5c323459,ef4b3f02,bf63f9bc,315cdf91,6163b389,c6a48cf7,4127da34) -,S(1e1d2d64,1ec550e1,1a29bc03,cf7c8442,ca13f10a,182783c0,d4ee9bf0,8c3c8a18,1ca8ff62,fadef98a,4d1faa0d,28e75e5f,117cd890,2934e457,e042b870,d8cff1bb) -,S(f10b2e75,8246bf49,1b70ff95,a385e701,dbbf333a,95a94652,6df7cb7a,4b4cb68f,ad15b5a4,d39d6458,55e57a65,3872d9d7,5f4b3168,182bdee0,a6289f68,aa7f99af) -,S(4674dd8f,16ba5557,c9ef32a0,2b6be805,e864e7af,c4fecb8f,666cf396,f7e6b0a7,c9d95120,73388bfd,45f702ac,8851b5b7,531edbe2,df04d855,7bd58b3a,c889f48a) -,S(95bb741,da472f82,8ff1f98,970c2bc9,1dcaa4ff,2cd4c0eb,195978b3,242c66f5,1e097cf6,d47dbdfa,8c3f2ce,90e0ccde,5adbd581,9a6e135,957ce258,805a4130) -,S(9a892056,42e03fae,b24d8fe0,f94e4f6f,d0c72581,604a65a0,99e3d28b,b103d2dd,c6bee4e0,d94c30de,b99c1a21,5d28d7cf,930e89a0,7865ea1c,87d39f5e,1522b33a) -,S(ade39c3b,e9540095,2176bb09,20541076,dac8e68a,a20903b1,5048e5db,4b0539a4,6bec56bd,60596cb5,7ea8a355,a6a6a4bc,90871c81,de902b0,6abd45d2,5802b204) -,S(45f808f8,bab4b4e1,a790240a,f036516f,bf0a8eaa,dd4dede1,eb88bbb0,7d248b8b,3f3bc72f,bced768d,bb90ddef,5b1baa9d,aba634f,1fe19842,c3b4b456,8957794a) -,S(ac9aa903,845a3081,2ddb195d,d79ffb6b,6e8ef0e,d34d0a5,49b577ca,35a116be,368ddbfd,1c5a2fa,c2c183af,19097414,82b272d0,52cec4b1,745fba6b,4a9fba89) -,S(ba26fbbc,ffa6b9f3,584f18ca,255da089,f561c30f,29a378e2,9f76de9e,b756f6b6,55f67b11,81ff78c4,c4c86e7c,931e314f,dffb392,306a7145,5efe875b,fbe39ba3) -,S(d4b1a902,1ebed925,9d53f2e,d76b03d,25b4241e,d5f932d3,a54c4dd5,db3f0423,6f1dda69,9e60053f,d9d2f5c2,c2ed2ae8,ba3337a9,b669ba05,3e48d974,f73c2d93) -,S(bc91d139,b2de4778,458ca891,fa97e413,d4cf32b1,753cfe0e,540726c4,648b451e,b56454c3,4f568840,6d198248,19ba350e,aa291f16,5676d7c9,fbd2d592,169c76e7) -,S(cd7a85ca,a0f408b,26b29306,3e01dee4,acaa8f9b,36f7273f,378290f,a4435450,1d9508b,1e7f5bc7,ba8fe5d4,f44e8c57,2bff9a98,887c3ef5,2fba3057,f132c5c5) -,S(497f8e85,57880856,32edbfec,b0065ac8,3267fc31,da9100ce,c2b99cba,1e7c26f6,e6729428,fabdec3,2db731bb,f33cf45e,5001b890,8f82c0fe,f7cac291,f89c6a46) -,S(68a607,4065c372,a95e7a6d,fc742e32,e59cc4b,86f9127f,f9465474,a466e30d,58e59131,1cfff974,e9e9162e,e974de92,904ffaf6,ffb97f49,d9dbb1ca,bfd927e) -,S(79d2dba1,67b93ef8,82ca60ef,b803e1a6,eadb4406,7f9dbf6b,d45c1a72,23da19b2,a59f1b7d,9ca146bf,93b89f2e,244dbf00,31511075,4dc03050,aabf0d20,41230ad0) -,S(5a2802ac,f4b92bf8,1c98c431,28ebe1f9,c921c211,910b6648,6391ca0e,4c6ad50c,5a0d7b4d,49b5835,dc3b395c,83031571,f7c361dd,840b41d0,405db351,14d86eaf) -,S(87b8a84b,1fd98b53,e9eede06,74555c7d,806d5b7f,4cfced4,16203280,18c398d5,a38c4d7d,549bd5d,28fa39e9,805e81bb,975cd137,64aa8c7c,a7055d63,bdec52f2) -,S(f7ca4d9e,7ac11395,70db6a06,c7f00833,5982181a,6642846,5d0899bd,907a9223,2c3dcce1,2ee6a995,52a72eee,e0968552,919502,5d4962c5,a33035d4,501badda) -,S(15bf39e1,5a11ff6d,216c0f7f,f1597f7e,ceeeda34,91b450f5,3b3407cc,bf7ced7d,325462a,6591d018,e495c6f3,fedb3abd,75d5a4f,15e9ab99,e43418cc,4aef1ecc) -,S(2755adc5,e69db19d,7caf52ee,117c6907,5b342e73,4af64a4c,77b369d4,269897b0,199bbefa,7e0b1c10,bd78ead,d5e65a6c,e6b3ee49,1400b9ad,a7874bcc,be580d5) -,S(96ef0e89,80602225,1d8bb9e8,693f3a67,5152cc9c,43c4e953,5310b9f2,c4338d8c,2414e799,14b2d6e2,a9be60ed,52508d6c,15765c0a,7fc1746,8820fb99,a9feed56) -,S(c1642d67,339fa6dc,c553233f,116f8086,2edbfc24,5512c2bd,4ca6e348,712bfb19,65e9a14,c7356a36,625022cf,873161b8,ef43ce38,a99586cb,9b5c8189,f3c6b8dc) -,S(54c536b3,cb6da9b7,e4483ce5,d5c9e660,bf973ef2,f4c8b095,f52dfbed,ffdfb96e,777f16c3,b026b75a,c9863f38,d015f04d,e1067f2a,a9cbd15f,9ee27475,ad46a4b7) -,S(706041aa,63dee9bd,4a441238,bd343bef,14e69929,f6e007e,181ae87a,68362926,36e15a44,57b86f4d,9b233dd3,37fab91f,67e4c811,3340463f,8f443b50,5a0ba014) -,S(49acc336,116c91af,6f90a6a2,d69b9d3d,c0be0a16,afb9830c,c1af0b5e,749b2765,bc4f0f6c,725e037e,3a9d9be6,c5d4f80d,67b3e28b,92e5d3a8,fbc8f66d,9ba97d52) -,S(96bee384,ff79ed86,a9d816cf,32f3d569,d1ae03d2,d154c65e,a117707d,74c818b1,848e45ec,27eaad75,5328d84c,a76a7235,ef4f492f,5be115a,a622171b,51dbac8e) -,S(3b2b0810,c4052498,189affe0,4c7ebce7,b9050aa4,6a702d0f,72c5c770,4ca4d1ec,f782ad72,1bec3b8d,b1df97d4,7765434f,e4145c81,27acece3,9dbba604,4df2543f) -,S(54c3547d,e4873721,df6215fb,ef7bcb4b,b9acce42,7b0381cf,2de151f7,c69549f0,5e7ce1b,728a3b21,e94b4138,bcb89af,f4778dba,fd21aa42,16d83a7c,9ae81edf) -,S(9f1c53de,e7b895d5,6081585a,c6eb3821,d89bfa61,55cc96d2,e8b6c472,edf57f27,38369e41,ecbdb4ac,619aa7da,4d708eaf,4c572ed7,f1f2c079,d0bd17d5,3ba8288f) -,S(e79f75e,a1a224c2,a0533936,65a5f705,15eb0aed,b924dfbb,5aa30055,d1d82b44,30c65139,f6a6f5ee,5304334b,1ce9dd15,27ba6031,2ff2697b,8eebbdab,67105171) -,S(7f95a1da,79cf25cd,a904b7f3,11674d02,fc6dbf34,ae8ba7e0,b179b48a,d942821a,3d3dd8bb,31cbafd3,247ddceb,be1faeb3,b00e057f,7e90bd1a,78f89cdf,648f7c8e) -,S(41e83f7b,9067a7c3,bb6ec755,ab7c83a4,dff74c93,65d0259c,cb635bea,718a416a,a54a4b56,5286b26b,d0bec338,2053c349,2de80062,2189e2ef,ed10e3c3,9457a34e) -,S(81599046,453d0a96,2c5f3b47,fee7f827,537c7c58,c5ad068e,e5e6ae6f,7a9c6848,4a83b015,3abd0df4,177ef3f7,e8a7ac7a,e8e5afb9,a2fd359a,c30c13ee,321f943e) -,S(11c9aa76,2cc334f0,a3274f15,17a1e60f,2f0eedfa,d603f83a,120162bb,e87830d0,7c73d374,26f648fe,4a9978c6,a64ac787,f4c8d79f,b58b0f58,70e373e4,d317136a) -,S(2b41f344,b285a31a,ebf4f4fd,f0c4f463,49fcc794,e5762e04,dc39efc7,936735c9,7eb708ba,3f683d48,db8e0c25,ac8a6f8e,5c340749,c3d6ed5,7936d515,7f3d6e73) -,S(dc063e66,38098e8c,6ff55a73,faa20099,c10d0258,87c19850,43d1011b,ab211b93,4abdfdf1,285ca3ad,65bb9a85,7ad647f7,fff01782,79fc6df1,6179e1d,495d212e) -,S(7cb514e8,b6361aee,f9a7abe1,f84ef401,97de721b,609c3151,a056eb03,71ccdf8a,4d359c89,7d03a633,369bddcd,52a67387,fd4d1e00,2406502d,9ba6e967,a5efd0be) -,S(103a6644,ee731721,bf29f036,97641fde,9775a642,9ce8d97a,26b06ceb,f9066693,127b6948,6db0d230,6ae90a1,4b8c8ecc,1e9293eb,cf154371,5ecbd579,e886a726) -,S(adfaf771,662d719e,532ba045,72a50f12,144fafd0,afe93f7e,1d8edd13,99226e5b,b4d0335e,8b600a4f,84d919ba,514bc249,e3048cc4,281db3b9,a7c62013,4f00bbca) -,S(609d9352,30f3c6ed,bf64275a,23a9a258,33fb8c3,9c25dde,4b55ce22,e64b50fc,cbbae84,c57f9c52,67278c4d,3b0cc5de,9327ba71,ca1a1bb1,8aec9a97,bce17552) -,S(5ea5aa20,1b958a8c,49b70510,b7c6a29f,86d9ded9,afd4e833,77c433d0,f62d9ba3,27c5cee9,fe3c0bc2,af8d0e30,57eb0f57,b1fa4237,996bf8ef,5ccd25ef,e1b87ecc) -,S(3f801115,3603a689,800c04d2,7d3b3fe5,c415ea29,c6e11951,7a56712f,20a10862,4280ab61,65b122e1,85abf4d4,14a31961,ac6595cb,421db183,34e57cb3,fe9bd059) -,S(54981ffb,5b692a3d,6d9ec7ce,f027fff3,c5dafb7,aaab4c5,572522b9,e1157e5,893183bb,554c81de,21c84134,e395b9fe,80a5a9ee,b06e3b67,2ef93127,24c307ae) -,S(97c18e92,d499ef62,77585c6b,28f36fec,e9a2e118,f793260e,32750861,a1aeb813,38a87702,7f1df077,d6e734fe,18a023ff,36c6d4bf,4a7bc7ce,d3a3d38f,c3069f33) -,S(d5507aae,97bb6e17,410bc87,26d9eb2d,11558b96,6c54e7db,6428b44a,3589820c,e78d0140,7468dda6,d9c4af92,1984460c,e523c101,79f7aa15,d8004dbc,4fc63cb9) -,S(220d6c2e,6c500d01,9ded2aa6,5de205f7,cdbb15e5,69038ba5,7bb1700f,1182ca70,64b68506,c387ec2d,9e030448,797bc28c,5e09e8a9,95f5f80e,70c26a1f,db7b16b3) -,S(c1a45038,da6aaf1e,396595c,3ab404eb,9584ec90,d894985c,18e779de,793d20ba,1a443da1,72e281aa,4393e1de,6f1e4f89,4fe5d1ec,b3a5bcd9,607cf79e,6f20b533) -,S(9a66f9b7,f3162c80,d22d0b5d,2a659bc6,ac01c74f,46804ca6,c908b6cb,90fb419e,3465357b,209c2b,a7c766b6,9c17abdc,69205c54,787fd0ef,e744692,16b95d3) -,S(8b305bcb,1b6156e3,22f0f0df,28265cc8,79e5909b,b76b546e,eb223d62,89883387,929a341d,dfa05574,90cf5293,244d924e,852b00d0,d328ffe4,7ccc5356,623a31a) -,S(4e36ee67,b5398169,8ed9460a,cb450023,7198f249,4dded391,4c2ae003,63c8f664,a784c95a,9a443b7,5859a1b1,373eb750,150e1ac9,d5120ca6,f273578b,73df77a6) -,S(167275aa,38d02988,c53e0a36,d8312e32,369bc677,6d7143df,cc6fb83f,66747caf,f26b9851,31abcf45,369a6415,84b2956a,7122a51f,b909bc30,5427eff3,916e6e14) -,S(c93d0b74,c99358d6,d24a962a,15adafcc,8a4e57ca,df0afeb4,9d46ef53,cf619797,f93b324a,b144c6df,336e34e1,beef5c13,b931668e,54ab34a5,eee1a8f5,5acc683) -,S(8bcaa2d4,671bb4b6,8a924109,32128551,fbf6d924,d4854027,7c1dff57,3bc4a8f2,88be3e1,6482477e,62255fb3,24512abe,27cbb4df,f63c6d8c,93c3c923,47e519d2) -,S(69d186de,f9a7ea8,be833f2,590db08c,fc0acfbc,64a648b6,8ca412d6,88c03808,d776b644,43a81bf7,527f658e,45d92324,a08ce171,6db6c259,898fab8c,f3d6d41d) -,S(4a53595e,e2cfbc6,7bdc9f07,308f57c,7ff5afc8,a35e27ec,e22cdbdf,6efde161,e55913de,d481077a,ea36c502,494b3b72,b1691786,335b0278,3e40fa1c,1a1b0876) -,S(90856f9a,5f7bbc14,557dd419,516ce5c9,aa451bce,13c17ce5,5c9fb1b5,f2924995,ca083d2e,b5a3a067,4a2534fe,e03bd99d,976b96bd,2b7f16ea,6e2552ee,648e934) -,S(2eed315e,d863298c,aa374ca6,2bf8313a,a0ca07e1,9a94bc4d,58eb235b,52d36dfc,afa36c8f,90d7adeb,ec33ec69,40c08d1f,2a4044a7,477da88a,6653d90b,880856a7) -,S(345a7f2,ab7ef064,eccdbe6a,ebd11dc5,3c7ede0,b62ab3de,f8e409e6,258e84c4,c0c0dce5,93cf9647,c0228d8,42b78407,c3b634ac,799fae19,f0e685d2,6ccfd73f) -,S(5a669d7c,209b222b,47843a5a,633e0b53,48442258,663a58cf,f6ee3cc4,1b893d3d,7067be1d,8636698,2b808b16,3c05e57f,2be77d1a,2bf78038,e242f5c7,4ce10523) -,S(3f0b0f3c,30a991bf,927f5119,6fb4af39,e1399d01,1766b1ff,1f0ff2d8,a3199062,be8f8781,4c06a75,97d062c2,196a49ef,93a73923,f43d16ac,82c015e5,4789d472) -,S(9d7f2c64,98e78982,8492b8c9,2e0e49c7,b5c9d4b2,e86c409d,828447fe,4a2f5a13,95ccc540,8202dbc,78323d6c,7ef66d51,4af34699,5be50b56,98a5864d,34e502cb) -,S(9f741436,55b3cfb5,39917a7c,79fec4ba,164503a8,3958aee1,f6e8f34b,3d861b78,345738c,ff8f3c64,f5cda5a7,a1aee7ef,f3a33141,a5139c3f,b891c6aa,feaaa7ad) -,S(cf1d3136,11d4b6ec,5f1a9728,c9a7b037,d9c16d65,bad95fdb,17376200,b1a9a97a,51c72169,bf7b1ad8,6159fead,dcf3b0a7,a7fc13cf,7bf12d98,409dc3b4,fcb7a9a2) -,S(7e04c6ef,c7433f3f,fa2bb827,3fdcb3a,e0470abb,cc7c8dc5,414ff77a,915868a0,781125c,2184eeb8,87019f7,c5c0b4a5,5922d11c,53c3db9e,d5795bc6,e7539cc4) -,S(fa6d73b2,a97801b6,16697ac6,102b002a,53d29d33,289708f,d8f73964,77f3d57d,543db558,25c67a4,cd010413,9f8a093,7ea7ac2a,380799f1,c2249569,3cf557dd) -,S(d0fd7208,8deac18b,1bd63fbd,6d5be0ef,5dcd34c5,538a9b64,ef43daea,ef321d1a,7a5e1e2a,1b290241,7879f223,8cc8928a,65988130,81366846,69841b93,3ddc3a1f) -,S(e856e67,e28330ed,77d8687f,bfdce5d9,ab8ec155,4c94ae0f,491d1e43,9361cb99,c51585a1,9da7c26a,4fc07c6a,f17999e7,a6718542,d7500fc9,1bd21fc3,8acf1eea) -,S(389cff20,9f240748,b9beba0,34d36e0,5e758a3c,95c678e,28cb0226,37db1bcc,ae5a0d3,db1e17fe,30daa2af,1e1f759e,905811c8,95706b7c,e5741051,2b7ac4c) -,S(28ce0f42,ff79cdb8,16b666c9,c3014051,d46e8df2,e2377c3b,619b78d5,17f21a1a,4e835188,f742237c,fe581edd,937b7294,e06fb295,d401b35f,5b7b293c,6d57f875) -,S(3d955bfe,5b27beb9,68400d11,3b8666e2,63af6ef0,ac6ee49e,8628e2ac,4d1e69c4,1fbd2aa9,b6913655,e00f1384,a15a7215,d3d7340e,4891893a,a67faf39,88801e9e) -,S(53dcaec1,2dd48ad9,ee65c9bb,ef21a023,58cac930,316263d4,9d607074,8aceb771,5b976f2,411d7624,d4659e5f,db624b05,9dd5e06e,f0b65740,ba394020,b9d279dd) -,S(ab822568,f7e9da8d,3f1220e3,24752c80,b02a8124,f8d9f65b,3b4532ec,3740881f,6c2152dd,34451ab5,b47b7c08,f7edada8,f9f230c3,5fdc2de3,35cd93d9,e25703c8) -,S(36719c40,1518b976,684bbdd9,2a923485,ce92b321,dc26534f,e5a0473e,4c873c30,d5d58a83,d493cccd,d16a1282,68aa93e4,94ce8638,41ec947,930c72e0,887564fd) -,S(360c82e6,18a53dc2,e44677b,a0bb8c2e,2a08f6d7,afbe8498,15d605c3,2e5fa969,ade18222,e1d0fbe0,a31c55b8,d2cb947f,1fcdea11,1e08ea3a,4f3dff02,e3e38b70) -,S(ecf50737,25a3b81e,dc621bb8,6c98fd59,f805d6b8,2f08380c,64270df1,95f020f,f5431b8a,cba5d27,1da26cb4,fc3412fb,14ccf088,6e0e08ff,ce0db47c,6b4172aa) -,S(3b751389,e6dadda0,85298860,76076249,46df960c,e030caf6,91f91d46,4d05be4c,244b0028,48829fc3,824dbe61,168fa1c0,3e4d3835,d3da3a53,7c729f0a,191e92cf) -,S(ee6e33ee,7fd9d7e7,aab10b8d,2c58f2a7,26ed307b,6fa69b3b,f1f08a74,f1b04ffc,4233398d,6ee49505,c5f21525,6cc9112f,5dfdd7e3,4bfb9a8a,476b3cd8,2645b8f) -,S(e7141075,e20f0903,f39fa384,f91a5708,7f24deb3,68571939,572caf0d,2fb543f9,5265e24a,bd84336c,26b4607,dfa25c44,49c4693f,adddca01,599d814c,21787cee) -,S(d401b043,ee9944dd,7429a8c9,4291dc55,7e5827d5,88375dbf,1513d394,a778826a,9ac9b417,5ac3666d,7c6327be,5172b8b8,1dbdc96,eaf8578b,76f01128,4434b937) -,S(d48c45cb,b90394d8,23574c16,60898091,75d503b5,99d936f1,f60246d1,79c9cac5,4e6b2bad,a67ebb7,a0743cf8,52298052,2737f0fc,6cbef646,fb270d44,2a285612) -,S(19f6446,fabe1899,ec4476ee,1d61f6af,961da42,ada1f77d,2ab41cc4,28791c64,7a0aa5b1,4f2ae030,d9711963,bbe160ca,424f6a7f,17b6a709,b5f0dce5,af1d0498) -,S(2db1d56e,f19a848f,6d6747c6,82cffa47,78444b3a,d57ea076,b0560b1c,4e57c83e,701a5894,d1d6b6cc,b421b168,fd34aeaa,e85262ab,44f70c65,b8ff61ac,ee541cf6) -,S(443597f7,9da3df8b,5fddf8da,3bc3a060,83f2cb6f,affbb1ab,8a12db92,59661adf,31b2c4ea,362a0cbe,2b9b1488,719b7ac4,3a85f7c9,63e9f2bb,b46ee055,71e2ac2) -,S(e49ad52a,7bd2db07,d972def2,d1ce6684,69aaf6b3,3c7e3427,52d79fa0,9d2ee9ad,b2063f37,1ca78c2c,429cd401,c5e46d6b,dcbf373f,5cb77163,5760b8ed,b4f91ba4) -,S(35b3fc0a,4a625cb5,808e1c2e,73c962e1,6ab7dfb3,28109ef,fdf81e15,841afd0a,cb558481,145a5f75,b639133e,8ce42c98,d36d8fa8,5348c815,d92a2c8e,cc993bf1) -,S(1cc238ef,3f64a075,c3c264b,ed42a0ac,aa6de195,7db40d52,86c482cf,f62f609a,d3382317,2b8a1450,bd918aa3,c57de76d,3012887c,98452f7b,c1f58610,f528af49) -,S(f5a2794f,48885192,dec727c7,79fb0b6f,c2cdf399,4ef7cacb,94e35791,4d138e84,d3ed4f1b,912f5dce,5a0842ff,d2e671b7,f3ae8448,b1a73f43,249a1acf,915b9c34) -,S(21b41016,a8eb7c6f,5519d94b,adb0fa7a,5c553822,6d080e3d,6d2956e8,8a9579e9,802570ed,b9b01b1b,ed79b6f1,76ebc4b3,55dfdd16,f43e82e8,7803be0,fc44e274) -,S(9b5611b7,938ac10a,9818bda7,3615a47c,1ee0f072,75aa3dcc,b8919dcb,e7beaa88,89787c01,d088e3b3,603047e5,2f49981f,7f007c8c,a88502c1,3bd9c327,e3c83b1f) -,S(28163c9a,b08a7ad9,38c7b35d,b19e700b,3865800a,55a3103d,2213c9ef,2c03858e,661e089b,df356bd4,afcd0604,fa5ade9e,74c5663e,77ab57f4,a069bcf9,b8b227bb) -,S(bae9ac08,aecc06f0,ffb8540e,2589a32f,11d34a7f,6d899e5,7a8f5ec5,bcf1601d,f5b63d9f,8a5d23b0,80d0bb6c,b8df736,aa660a3b,6f987683,cc0a54e5,f7d1b4d4) -,S(19f48542,3ed01783,cb83d2d,2efd7264,a10c6c23,1f5a242b,112eccb6,31d91f7c,79ce383f,f011ce13,87537ebc,3e70dcfe,2cc2764a,3d180fdc,74a21062,a5b75f50) -,S(cf459ca,cc8c4ff2,c827efae,6593a52,838658ec,bf1a78f4,75965856,a8ad007e,786781e3,3279964e,da5e6374,bf088fa7,5d18901,df01a0d3,6c87b62e,b419dca0) -,S(c19f2008,e6945d10,471a13e4,8b16f3a6,381de3e2,b24f2d92,77ded25e,930d1f47,7179aaf5,322b51d8,7758219f,cc30e9d6,bad5ab77,b35dced9,6a513b4b,fa7fe147) -,S(3fc1b649,3b6cbecb,1767d0e5,6202c84f,39a6b41,87f05ac0,d659c45f,5bc565c,db9edee1,1768e29b,4eefddae,c6234622,55d06e0f,1979c8c3,5c366f4b,5cac3f5b) -,S(502f74d2,cf589c65,e63b2a8d,b2b1e4ba,5f851715,bbb27e8f,165fd34f,29cff7c5,755e6c73,765bc45a,c2f9d4da,499198a7,36743571,40846ce3,6afd8063,981a96b1) -,S(b9eb62bd,7cc6d1d8,b0eca2b6,1920be5,9227534e,7fb581c6,4dcec4f8,f1ec44ca,ac567b37,891e3eb5,c40fecf2,d4c5b106,bd222c8b,64ab491,f7a028a6,a02178e8) -,S(2e5280c7,25a109f4,c5de565b,9fe5357c,718f9fea,db53aa9c,b07a0f3b,f5030ad4,4783be94,1b162e,79f58d4c,448756bb,8ea18c4b,692e236b,4b2b3ffa,24a456b4) -,S(bd59ac74,92d24606,9b233efc,1b68c371,bbc9713a,284f7f0c,699a1d5e,ccca64ab,1abc71f2,fce8372a,a4a16abf,1d75bd87,a19c08ed,c8843f44,fb71bb7c,a74ec4e3) -,S(6acd12ba,4623582d,d769c8bd,3d6adabc,2c13ba3f,bb67e4ed,ee0fe70f,3f832f5b,982fce11,ff1e6c05,2f21be20,ce1710d8,5cc043dd,eca9bc43,5d100d9f,f68150b0) -,S(601f4285,8b0cbce9,90500c64,e7eb77e1,c433dca5,55e6ddff,5264a98,d688decc,56110eb5,d5b3ed79,5906ed4,c0275827,79cff7fc,ddecbe7c,74d2bf10,ab2beac1) -,S(4d393daf,c47391d8,8208263d,b8132156,e9fdd6b7,da48eae,90489d12,832dc938,a14180a7,898a5a00,6ae5b8c8,d034c233,93ed2ef4,faf6a4fc,42c4df1d,62d0ea7a) -,S(4ea24f6c,3c164285,166bf2b,1918b3ee,3cac8631,5a1175d5,4104506f,68b7171c,87da621a,a18d1a18,b1dc222f,af37b5a0,b149714a,e755ef03,ee3af91d,f2a7f5ea) -,S(eb1f6f2c,a5749f80,b88a7359,f0b67230,b2b844a2,4fb72dba,f5604e73,cf6e432a,6f58093a,55e3cb37,8830e58b,10612b24,56a35fa4,b8e60409,1b9b8304,e35cca51) -,S(2361315a,3d41b82,98a9d768,be7f453c,eeb977af,bf1db132,c831bc00,aaccc9ab,90df3be,336d4b58,7965778d,9300cc1b,3d954d4a,89abf173,a9bfd99c,29492dbd) -,S(44f432f0,46c7defb,630d5535,aca1bd47,10505012,6b2454b3,4591b079,7f8e9b28,1fdfbcb7,25eee981,c19f98b4,6bd19dff,9b6cbdab,730ca2e3,1643d415,e3aa0489) -,S(d563a475,4c130e71,81b60a66,a3f2ee52,7040f9f0,eac9e26,866fb226,f93db593,49fab7c9,6e320961,6f4610dd,532d547b,b24f7f07,f916f10e,630ae5cd,b40d3b11) -,S(2fac4651,f0ac9876,4a74c066,16e7f1b8,aa6d2bb2,99ef9f0f,43bca81e,7a4089b,fff2b7b8,c330e1f9,86a69324,a63bf10f,fad8e78f,dfbb6062,c96a67b9,eb460d5f) -,S(b6f60ef3,d8b793d6,5794aa89,12e8e1a0,9ef7604a,5c9eaede,b803fb31,e8195dde,b9b17946,4057de11,9d0bf993,fe92e4a8,bb633d6c,d03ce8b5,10200166,467e6bbb) -,S(d08c6813,65789ba2,4e580637,2eaa1ad1,d1254462,3cb64d83,5ea2e1d8,6e34620a,e94875ca,f5beb1cc,f88fa3c5,e2776203,a6f3cb5e,b4803618,52215d0a,9076b185) -,S(dfda222c,a4ddbb56,661f56d,b9b74be9,a5a7c34c,4761483d,928aa48,9bfabf52,bfac4ed0,ab4ccfa7,caf64d8e,ffdf1aab,6aad50db,595b1b49,7fab28d7,656b6475) -,S(3f72e4cc,ef5c0bbf,995bf8b4,67759969,d93ee40,8e738a4d,41f55896,17f241ed,c42ad857,3f49218,c7daca7c,8ebc5c7d,f9ac301a,2aea209c,ab6648f9,8ea16f5c) -,S(6e85f587,91431b6e,dd848aa4,70101103,f63881d3,2fa9f1c1,e3324161,e9ebf0ee,f7f00d38,31e09d69,f0684107,59dcf837,eed3d833,90efa352,40a9ac5b,2daa2a57) -,S(d991fc76,2f75235a,5268a32d,64dbeac1,b2333a34,5ad552a4,cedfab54,9b191f14,90d58a07,794983c8,3f6edcfb,55ed0b68,8f43d9f5,eb7678d,29610299,63c748b) -,S(24cd7922,7ef207bb,6b9b678,5156bf76,77101e6d,f5fb5576,a9d33175,8d7c00,44608974,5f1157bf,9c9f45a1,b212a978,8e348a0f,55129935,b038940f,84e91468) -,S(5c053ed8,367806a2,8545692a,47314850,66910d02,3373b89d,e85bc7a1,c25bf6bd,9a3e45f8,dde03e64,6d6c546c,cf4c8fc5,a253054a,2d6df43b,d8c4afb6,385311f2) -,S(4f3a4d88,20948d82,b598f118,1d350719,ffaa5ce9,9a7f614f,a9e3cbf2,e021a6cc,149c6722,980a41ce,5d4c0b94,9cbe3c99,4d94f2d7,c36ef45c,d7b9084a,79f451a2) -,S(badbce64,8d55b579,cf8d6dc6,74580211,a6bff856,10804077,adad7c2d,238aa542,567d75d7,1570d7e5,184f4f4c,a53fb92d,654b67d1,f6bff96d,fddcc3fb,932f0343) -,S(d2eda540,5f828eb2,cd3bc5c1,9f9a838f,8a1186eb,3cbe9575,5cf6642d,13601942,ecb3dc3,655ea992,4773cb57,f4f4c8d,6380c665,69f08184,f521dada,c108629c) -,S(191ad0df,31c7f3b8,258e5bfc,ec9d1ff1,2143b240,24d93a17,893da095,97304f1e,4ad4991,6bd2296f,b6f6b697,dbf5a3cc,4c3ba136,6f6dfade,c859b190,48fb523f) -,S(f108bdc4,a1874aff,35bd1fac,b8e81b5a,7a7ed597,e78dfb7a,c716bf7e,7a15dcac,b88e4fa0,d630d92d,bbdeda05,4a6c6624,e7bb1d5b,a6dded85,347e5275,e08c9414) -,S(30fb7605,7e2a6cdd,59fa279b,3574cf1f,db9d5159,19d0e523,990be02b,da1ebffc,5743e72a,752b558,1b959a48,3b6229c2,33fa1b3b,2719ad3c,a6f8f9ba,1702ae8d) -,S(6facb1e2,6d1ef1cf,ff413145,63f3b2e4,e762ee7,3e43378,c4c15f85,1cd948bb,92000e2e,a3a5bdbf,f6eaeae8,8619f2a,48b649c9,19972b7b,83cbac22,62d484d7) -,S(741c1253,8cd4da52,c596840f,e6233558,fb480a0d,43232756,2a9e2d59,a574b981,79040b6d,580efd7d,84356117,a93941f6,b47e6c0,a53627e1,bb80fcbc,e6881234) -,S(2b86fe60,2b2e87f,59498185,4af1f986,7debc5a,84ae8bf,94d2d6ab,4ec8be09,cf4c27b6,b33b5020,2ff7fdd3,ff0743e8,f28ca75d,3cb74d21,ecf21dab,ad7ae079) -,S(e6e7b676,9f0ed86,4163e9d3,66a7e2a7,a37f1ee8,e827b105,3119b8b,d36e7b84,c2e5b9b1,d82b4504,454062de,6c24430f,53e03bd1,819eb1e3,2f24606,73d09be2) -,S(86600d22,e7bec946,5b0afe05,5e733b03,f8f81548,ea44e008,740ac807,ddaabbe1,abb367d0,5e6d2fd0,a2c1d0af,5ded2926,1439c985,ef287860,80614bf9,8e8e33fd) -,S(67171261,5cbe2da0,b252a773,58f81c91,fbe561f4,87df09e6,cedc8a55,cb3414b2,bf02d81d,10a47287,2b7e65e4,93d97cfa,e3bd6ba4,39977371,8cde674,8829b0a3) -,S(97db468e,7f3a25c4,c34e202c,e9b2480a,4344aa9e,1b76a147,4bd375ed,6d10c0da,c58ceb67,a28f99de,2eca70ef,e8af24fb,c381f962,d5db6e3c,481cca6c,469c4c27) -,S(f3ac0267,ef19ae9d,762c4023,4ba97e33,a88b015a,e6a83f4b,cf730d84,405aed26,cfb8a3ef,d1104873,8c1c927,b31ebd05,105bcce1,d57c7fad,1972a5fd,cbe84f06) -,S(fa44128c,3c258fd,5a99c85e,775fca63,4e8a46d8,4fbff953,b373bd50,6ca3da85,f3196e74,d17cae3e,3c9958cd,ca591374,ddffcba,7e362139,17e5e119,a5538b1b) -,S(95244462,1eda0b2d,acdc1a57,41725c1f,a7c5660c,feafe18d,ff8789ba,164e7dbd,214bb6b1,7af1584b,76a9e5a6,2c32eefb,497324d5,7b00f71d,24b162e7,1383bff9) -,S(11de80de,c03a732d,6769e52c,64be4d2f,fb1d696b,2a658721,94aa384,392dff9,e1eb8932,42386216,f543eea,a2d1099e,531d8e27,7cb2e5fd,ec76b3af,e9e9c7b7) -,S(7318b452,a2b9d23a,eeb30bb1,3883dff5,b373be94,94451c72,36a2c02d,a4c37e75,26713361,aaedfdbc,2966fd1a,ecfa705,772012b2,564b077c,7f5db7b2,c810861c) -,S(82d189ad,e5610825,1b03cae0,4b138ff7,dd2d77b5,422535c5,cef9be7c,1899cf75,3634267b,1b3c3de0,d2dba36b,924949b6,7e05d790,29c9452c,18c6ff70,252d570) -,S(e5dfe995,82152513,80859865,f16fd0fd,e4d60c7,be0e2aa2,d9b2af4f,3714f8f7,e1d87d8f,fdef889,52918e62,5bcc90e6,83f337a6,103cd000,1cfd01d1,eef4b9bf) -,S(54cdeddc,9fda5fe4,63240f72,8ca66c34,ec05394,899f2472,d82d2378,28a06a3f,27bab620,cc373ed,10a71c18,345ff27f,e20e1bef,98052afc,bb45fdc1,80b94a2c) -,S(7f96757b,8b473785,e1359cd5,bffbce2d,5b26e8fb,579d7833,607d58,a791c47a,d4b43e2e,20a43fa3,5a96d1ff,93109aa0,b7831fdc,2d2c016e,181beac9,c1cfcc4c) -,S(eaed18ba,83238fa5,ce4e6c82,edaef108,b1f9929,3148f3e6,2d3a6d4b,535455be,1017291b,805f7b1f,eba367f5,9a1a10b5,f7501355,7e6eb921,20838c50,aab0d29b) -,S(91ca8ba1,da9c2625,66a135ad,81f57b10,65ea4632,5bec5d42,ca1ad62b,826f04fe,2d5d619e,84fac3c1,e30343ba,a61d3bfd,e1c4a9a9,8d968e92,d560956e,138e34ee) -,S(8a31ad57,12e32254,7d0d2907,cb73adfb,a9a1ed5f,fe98d645,22082e6f,1cdb1364,8ecc3fea,886737f4,f94a2984,e6edba9,8128b2d3,bc79a209,2b2c1a7b,b00bff9e) -,S(123acd6b,ca673170,400bfc4,1071cca5,4e03daf3,e1ed1458,88470c04,568b972e,e97dc60e,cfec2d5,c6a6e173,9d60f7e9,838ad723,ad0fc7e1,52b5e70d,b48b853b) -,S(d7c26043,ad647f0f,d056c10b,4ac932c6,6a545bbd,509de346,d4391942,52e69df7,6bbf2f04,2c9459cb,c72e6aa3,1b6d8e4d,e606eeb7,d5d4e0f5,7f729a79,ab1f5e9e) -,S(67c4eb00,548e2cdf,50626c8b,1aec1173,8370da41,9280c9b0,1c8783ee,91e018d0,ffff201d,91a4538a,97ceb50b,c9aac646,bedda1d1,3f22a121,c709bfc6,23b95a67) -,S(7e1264ea,486b08c5,19c7d8e6,5c80e1d4,d2994bb0,95185c72,63172b1f,ead93428,1797609c,816f10a2,e82afe39,65112a35,798b0874,b24503a8,f57c983b,6ce7ef6) -,S(912cb164,5f7d7bfe,5ea443af,1c458500,a95ff22b,212109e3,12fa01c2,41319cf8,bab658b0,111c48f8,a2f620a5,fd130d53,e1c70e7,62e33dec,55b22d87,38c1eb99) -,S(1d60694f,15577a40,f6b9f299,be5eb62d,251f62ad,b9b5651b,df804e27,df919fb7,3799eb92,e18335b0,bdbc29b1,f8ce07ff,3f7cd409,5840d5,dd324bca,2f902a14) -,S(8166b50b,811bf53,4a94af10,7672ab4a,4e154b2f,c5cebee8,c8ef6ebc,18cc3906,6dea31f3,343e5b45,f5b08c19,903491f9,349f4ca,29818fa9,16f5e02d,85e09ef) -,S(4852393,e42d0821,6664d5d,f85eee60,9660eaf9,54ccc6d,fb1c31f9,da17923,e4cadcab,17f64d8a,f5dd74da,eaeab7f7,13be1de9,600d4db1,a781a058,5ed2006d) -,S(f40031b5,ba171b26,e02be47a,c34173aa,18ec3850,1b1d529e,a922a418,1c3491c9,c2db89ec,2e50105c,4074b729,a53ef0a7,9371d2a3,354d2d23,8fb39bf4,bcb5028c) -,S(8926d233,3c842f9a,213547a2,fc5ef5de,b0bbd603,e69d347c,41e7d49e,aad76cb2,8459bc10,b7b2617,b0d434f4,b62a4452,80bb951e,b4ada14c,fa800389,b3ff892a) -,S(7f362b16,9d9bd514,c6289cdc,70ea4b77,e7518db6,a2e33acb,8acefcd3,d8c5726d,dd1e69e2,71d77dc,2629cded,72869345,7c63ea2c,8636c712,e45e6af0,4c15fe35) -,S(261b8037,98ca780b,50dfd56b,81093f32,d7c348e,4f093b91,70470ccc,4516ee1c,5723ca6a,5959d589,4a24c12b,5f87a5af,84c7a6a6,89304000,344bf5d4,81c7752a) -,S(d137c0e8,edb32642,12f6b958,8b527a9e,9e57f3fc,c358a2b,68f11d61,89fbd900,d1043b3,5f809513,ae370588,4adf90c1,9d164c3a,8166027,92ca55df,74c71466) -,S(96274665,253f4479,753de9ff,ac94af8c,943b8231,b1302040,bee72240,2ccc445e,8ef6f9fc,f1e21c2b,d913f877,98c6ac9,f53445f3,6c2b1678,a301a4f5,17867296) -,S(bc6ea584,b1f9b006,5f39226b,e31a866f,7f90229e,12aade70,136dc747,b37f70c3,23f1c4eb,99dfbcbf,66539762,4d20c4dd,4414bf15,172cde8a,b7652ad6,f87ad5e0) -,S(3e968741,5adc1afa,696e3222,fe351939,1d3f19b6,feb1de83,f4f1aec4,d25e2387,e3f4de27,67ea84c7,8baf1382,4b7917dd,477bdc87,cf1cf38f,8f5da1,e096b528) -,S(b5973535,c9c9d4bc,2b2a9b38,57cdfdf6,4995d64b,81c9e68b,abe4d4eb,4eee489,907cff05,5eded925,770280de,9ee0e025,1629796e,8ca05a47,48ddaf98,72bfdc3e) -,S(d616bde5,acd5f345,d23e8b2c,3d95038a,a1d7a354,a7613cac,57ec3e8,d07e11e,6c88c62d,d795d065,c6c86478,cacc56d3,2282b4f8,f3059aaa,55388555,449879df) -,S(540345c6,5869d3cb,cf4099c3,ba7422e0,feb87ab6,ad67429c,2dc99840,e6bc82b5,9f424998,bceafc7a,a58e5f16,c58e53d0,c0d51f64,285b0afe,e84ec9f6,b22f8f37) -,S(6b7893d0,ace6ab5f,c93f2e80,65a3de57,4d552e5d,4a89d660,714113c5,a256fb84,81a016a3,7be94a2a,f45b1bfb,968006a3,58398fab,424811f7,6765fe75,d4438d5d) -,S(357ea5e1,7a0795ca,cac47e4b,9e59bb24,45d1b6cb,2c713f04,7029f6de,2be57734,571de7e0,27dd05af,90bebc29,bd7345f5,77babdd2,75498bb6,d43a668a,8a4d6206) -,S(7baa2739,1db2a0c8,679d0e18,8c5e7c8f,ef1814ad,b7bb3955,519b4189,1a63ec40,73b56168,20fddbb5,749e8dfe,ef834f74,e266df86,e34510cc,f5eebb52,a868075d) -,S(4d5251b2,dd778e04,5143169f,8cab93b,9a9b7428,1a0ea1ff,964225a8,10b1e578,9376395f,2091036,16a95686,4e55382b,39b6934,2b2964d8,34face11,a44f491b) -,S(3c0fb553,b0c6330a,3cc06bb3,b0cb4c2b,31be7582,55264b29,98bbc166,ff57f7ca,f1f409bb,cc227824,4dc08c3,147e0b83,3522da9,6859400f,8d19272,e33ef1d9) -,S(6dcc7ba0,4b3b0827,e3bcb462,7b7db8d0,e0997c7f,900d27de,2d6c87d9,aab2c373,f2dcb11e,87b69faf,4400e9b3,186eeb6a,4fb48cad,6d6da276,3943772a,4e18b450) -,S(a5271e35,ca54c1b3,16d6113a,40414ed9,26bade46,c3258c6e,82a63e9d,927ce06a,e2d6051f,bf42dd9b,e0b2e00,1fa4e308,66232871,313f9c82,fd6ee37,6e8e376b) -,S(574d1ffd,976c616f,60371e4a,76b2712e,84b0a231,8d3c1c0d,3b56b10c,e978efe0,13733a17,a956efa5,733dc130,cc4c848c,19ecd6f8,7fae5ac,82c73de5,6d1bfa0) -,S(ccccd911,ea84c247,262a6e61,8028b2c1,a147f55f,b637b570,97400472,fe3e27ce,cc4b4f5e,491f32aa,eb6d0404,5965a97a,e4119e73,33bd1b39,f2ea9873,7d8f33ef) -,S(df1e4fa5,410f1438,9a41ca26,31eef376,4f10868a,f2f05a1,50e2c7f,8c3a2643,8185a88e,2b4a343d,bbc10da,723d4cb8,29014cd6,3211a82a,63627b01,1b01e87e) -,S(2ca6b7e,b53516c7,2e216263,213c0d60,fbb02f,dd227f6e,4ad29069,f6da9213,81d5fd1f,5264af85,53a8227b,7500d82b,84ca1fb5,87ea30bd,ab30fae3,67e3d7b3) -,S(df4bd790,ac3a0db,1663a8fd,aec1cdb5,b30c7a67,99ac2ed0,16f1c474,5bea92a1,db80f378,f33f920a,d0f4fad9,595b0655,44ffc36c,ebc3f294,3db13b83,cf609bbe) -,S(792648ad,8c053cb2,102dde19,789d3782,79e0e0ca,c500f40,d46bce68,97af2839,3c2d9b55,afa4ba1e,1ce3d142,5e17ca6f,191b4013,7b7d8162,8de35e8,801f72f4) -,S(dc6fe845,50fc1136,1f648fab,deb9b3f8,e7fee837,ea545228,b2fbd432,e53a8aab,2a4bf746,19fc5408,b4bc6421,f4a570aa,172ef263,c890c853,d7b06aa0,65960dff) -,S(10d4786e,9151f2de,89f368f8,9502b7fa,74b7b9e5,7a1485ab,f82fccb4,9c2deca8,15da7f51,bc84f421,2ce948cc,28663e57,8b4b851a,f6533f2a,b548adc8,147d2243) -,S(67c7c0ae,e82dfd5a,194dc416,41388947,29ddce96,5b7d50f3,ca922512,6e730bf7,a8bf40e5,666ba93f,1f723414,24d8a7a1,6a2aed83,7f022fdf,557e6082,e3e515fe) -,S(602c3df0,8a2efee8,329f391c,a9f7b2f8,31ab6d32,bc4623c8,92272934,1f78a4f0,ac17903b,3808ee52,c0208342,696f5250,5789206d,515421ee,8b1ab28f,5b788eb6) -,S(c3441893,e78910c8,3cf917fa,44b608b6,671ea508,37a7d2e0,4e658c6e,2a91d9ef,b5388381,17c264a4,a0876c3b,7c261bea,229c2d0,a7399c05,114f520b,a7185dcd) -,S(49dc68b4,412dc3c6,c4b265c1,6cde755d,bcd49f0f,394d552b,76f67ff5,33c7fddf,f1490a38,cdbb6c88,d270eead,7de6358,132cff29,ddb6aea0,1baf6353,4c0cdae9) -,S(89080197,4a95beff,da864c28,36997c7d,3a4c0fc0,4ad59eb1,5ba4b124,702d0f04,86e165a3,b2e7eb55,9a7996ad,63265609,aa6e3385,30b51d22,4ae4f16c,d30be3c0) -,S(c9671a3d,f749d635,5684de03,1764cf19,1087bd06,965d23bc,4ea0555d,29ee0804,33cc0d4b,b02a1910,c158db0,ad2bcd66,c9585f9b,456321d7,61752148,e6224d85) -,S(f3c1a76e,1d4ce622,dc667a4f,dc0f4ede,7eb7111a,1539ce5a,bca71d2,fd48a26c,269ebdcc,e1d42428,4e0dd49a,73968676,58857998,7a062320,6251ccd0,ac9f9e2) -,S(12002fa6,68924900,8a540429,50ba2901,5870a70f,7fe95ae3,dba4b07f,aa6fa460,51543d34,34568008,74e8b1f6,6ec72fd8,e2936b6a,6022401c,d13d50bf,931996ca) -,S(a59df11d,d3fcf1d3,264028b3,6e26dcf5,62083e44,f91f3d27,f23acdcd,f1392a9a,4dbda718,48afff3f,faffaab0,5c5376e5,5fd15ced,68b03ac4,4785ab2,201cbe70) -,S(89f738a9,802d7deb,5cf2895f,60916fa3,d6d74bf9,e740d2f3,13ba393a,b40cacaf,293aa5b5,b03557a,e7288066,5ade09cd,ae6abc71,8e7d445b,cbf85a44,a035b73e) -,S(d0414978,6252c5fb,b4bfdae7,56092769,dfcdc2f2,ae38a5fd,92ba9df7,f91a9ee,53ffb526,a24df2b3,d6e8faf5,ee6d79dd,7f427d8c,14d2d5b5,880f1863,e7e95099) -,S(4a638f24,ef3528c7,a4e42cdf,3f5bb946,81e6435,ba2c99d3,625dc282,b941d341,39d97ef2,949f1338,bc016ec7,89585780,832043ff,33777357,9ecefac0,ae40620b) -,S(70a25f6,34d32af1,47c4dd06,5d52f78c,eb5e53fd,64bb151e,18e8629d,f4f8088,1b6bf3d8,15a0f919,68dfd6a7,7ab7417,d4aed9c0,a52b93b9,9b4e4e41,d1e558ce) -,S(59ea9490,24765add,f99fd908,11c65ac1,d0f9ee8f,27e459b9,b5851765,8e96ab82,b38bc716,896e0337,e4a1b361,59e2b5b4,e1680ef5,beb4b47e,c5934b4c,8d6675b3) -,S(874a6ecc,6260617f,c6d4f334,40c8e080,3d993594,ccc2d47f,be2869af,9881f2aa,f509e39,6663327f,7d768a67,aa0d2ef8,353b613c,bb60fc38,bd2715cf,349c02e) -,S(dbf3567a,1e634ab1,63a860ce,244f3046,c7f486f1,b12928d3,1c44624a,48bb5df0,bcdfcc85,38e4702f,99f9d55,eaa55216,730405a5,66fbdf07,4c62b310,6baf7ce3) -,S(a534bcb1,96450965,5593155d,2da069a8,4800e4e,eca0b504,62d844eb,d179ac50,f86b38e2,d558be4a,b0a216a2,906099dd,f3cc16b7,30e784e8,745f39cd,829ff3de) -,S(e11bb840,b79063c,4e090771,29d2bce7,8f291f10,120b57ad,63594780,fd1f1905,7fcac0ad,e0cdc573,67c9d74,1c6c9928,15b7c3fd,3a19b266,e0e5a94a,9a9ef9cd) -,S(d79bf0b6,552c5b6e,6e9192b9,765e687f,ea226d86,c6f83f44,b427ea9f,14b404f8,54e7a54d,583e2cac,129f17d6,835597aa,934b4732,6ffecbfe,deb503a9,eb9660ad) -,S(103396a6,57856b61,5507969d,958de14c,251bbbd4,9851a5e9,ea64e0ae,2f87817a,9d66ba9f,cf3e0c2a,655cabd3,91774015,e209d771,334c461e,d27b683f,f83b477b) -,S(9b49e25d,ae607f4f,fd876837,5ffc0fb7,142f9cb1,f0fde836,537f320a,9636723a,3472462f,f9fa5ab3,1fd1279e,7953dbc9,85623021,e714c951,bf00f632,e9f72ab9) -,S(a017d4f8,8e757556,b7ee81b9,d4c9b260,ba2f7f8e,5e1b69a5,fff94abf,723cc438,5f2819cf,53fcc35f,c9c15d2f,13dd51e5,2c8dd134,f012aed3,4b4383f4,8b00cd95) -,S(aff1db2d,3fa6dc00,51a8723a,7127d57f,69ed0b49,ccbca35e,25f72bd,19076211,7cccb7c9,4adc2075,9c7f8870,fbeb1a1e,9f95d644,af0411be,a6b12d3,aa6f00d7) -,S(21ccbdab,f6902a86,d368d445,dfba0f31,4f80de6c,c7f05f7e,9fd1818d,45a174de,eda0b8b8,7f40e9f1,bdd5ded,e65bd72b,6cbe049c,bb1575c9,6b779818,a67251d4) -,S(c3e58ebe,36b0e5b7,2e15c47e,cca6848f,5312369d,d270dd18,93b589b0,56ff7082,212df92d,d724e3aa,c42e293e,b1a2de5,3c340712,7ebba791,b901ff87,9fce94b0) -,S(f19961ea,da1d77df,2fb9d976,7d7c664e,c0400066,2ecd7244,12b72dc3,c5de133,74f321a9,1287943a,8ed14d02,96b05ada,1a24fb52,a09d467e,8e8175ef,8f04a2c9) -,S(3aecbe48,2aaf6af,35e63dda,fc919adc,f974e89e,765c4437,69ef535e,cdc05e01,92b854b9,30e5e4a8,85397592,fde89d3a,601c733f,d88d230a,a1168e36,ee367273) -,S(55fdd639,b87de7c3,9acb95ed,33222935,bd4217c0,fee1c924,f1060f54,fd22055d,81f4ef46,16e51585,cb443bce,f16ad8e2,36d6ed18,87ddfa60,ddba2089,f4b83c4d) -,S(b86a6272,ceed47d2,4ef4cc67,bef0b117,c0761b4c,29548c8a,367d8ae7,bf90744,1c0de18c,d5f3331c,5439020c,5964404,be582f88,3feec4c3,112396ce,b657c4fb) -,S(d141a7ae,9d92913a,26deec5d,d2acb7a2,115da997,63be5a76,c5a0a415,8b5b8170,de784bc0,9308c82b,ce3be9c8,9abe41a,4ed9b9dd,cf817aab,3785e344,dfdc2ecb) -,S(af340559,6902ad5b,e3fe3464,3cbcea5e,7a478a32,b1bde828,ec966837,192344e4,3f65050d,13e7b969,35b013c4,9df385d9,833d419f,aac0f754,5c395ca3,75ae8965) -,S(b70dce7f,870d3d12,472d3c5,481a1288,cccfdb2d,12637a9d,973f4e12,b026cefd,4b4f733d,e5322132,80a36e4,ba57894d,a563f4ac,b1a55a9c,83c8dbc8,96a7fdf5) -,S(14fa3dee,44dafb00,d2e71c91,5d217cd7,a9c2b50a,edcd0025,f7aad2d5,b6c62ce4,67c3a65a,65bd4292,d271fe13,9a8c9d84,343bdf68,cc16e50,11676580,6bc30d8f) -,S(baaa6a53,26a7fc36,e519d9a2,48dd3aca,f6f0628d,a6406021,caf0d0c,56d9bb3d,4fe9c638,c1078c39,a0fc39cb,e9a81bc3,4b15840b,631ecbd3,8ca4a2bc,10d1f3a) -,S(ffe2afcb,5e53bc7c,9ee07740,c8094a3a,32c8e627,4dec7eb8,cf2673a2,dba11725,68d7092e,2b8b56da,1653dfd6,42de49c1,799d3ad5,864e052c,8829815d,b2ad952a) -,S(a25d7c5e,83a0659c,5ead610e,b581d325,adfdd3b8,af03736e,4039ee1f,40612431,679ecfcb,b1da355f,d73d02e8,b79fc949,bdc9fb5b,5a4e28c,5e68c244,7599c806) -,S(1c5d082b,3121c4b0,2e0e2244,88e53b8d,ac5500b,bd396f0,7fc218dc,7311b299,a2a435af,4838d028,4d459216,f3955427,59f1f51e,9a15f28e,d83987dd,9c09e5b1) -,S(d8d21200,2cf2ceae,6c9a90db,89f7d0e0,42a2e97c,458b9024,437e28ed,a775ca26,b31b6a02,4b01de6b,6159ee51,3c118921,f61a536d,c1442525,cc613290,364b9df2) -,S(b5265664,54579771,947bee20,f8e7bc48,1e15d07,2adcecbc,3aae7b91,a4d0f3b3,170ad05a,da7f67ee,f7c611ba,3c55c835,f054bcf2,445e5c1a,399c7cd7,640ba8be) -,S(1d0d2a24,8982635,18a28203,b78cb089,acd5c296,98b86b7b,48fd4db6,3c80812b,71e2e1a2,7bff3bf,9e85e145,7f446048,7643f154,1cbe829e,f600d861,dbb752e0) -,S(cbbd4ee6,33aec586,ec7ba712,c3bbffaf,a0e6497b,8618a476,b64c660b,340046da,d792753f,c73090ac,177ec5e3,40aada73,3b31dcf3,a1f46952,625dab85,7e9b9795) -,S(73cfd295,99b6b80f,8757a873,ce9166ea,b1960f77,fa8f1d55,ddcdc90,9420a751,17832aab,c1083af5,683f8cf7,23c6376c,c22d190,241e1e37,6b1ef2dd,7333c873) -,S(20572bf8,abe50ea,37a064f,738dd18f,531b9404,e7e4d693,2c9fc34f,ef6dede3,41c79375,11c8911f,3146bb2f,63750887,c663d2d6,f3fbbd53,30af73c6,9d332191) -,S(ac208805,2f1518d0,3724ef5d,cb149f36,1ed713a2,94392f92,96173857,94794f70,1820bb1a,e843255,9025f3ac,977d9f59,4e812cd7,e27c390b,b2fe905,ae2b7017) -,S(33467f95,60aae872,b5c9afba,7f29cd32,a213f197,47745d8d,945d06e8,295afacc,44040bd8,138d9bb2,76181e21,79f4bf98,4b0c3965,a1a47d34,be8f47ff,52e15af2) -,S(1a77910,75bd3497,cbaff6a5,d5e8bd6f,439f5bb7,ca3eeb98,68033ef1,cff83f03,d8af802b,daeebe88,f823c43d,447f1906,63ede3d4,c4b9dbd5,caf82a3d,b4f1cecd) -,S(dfacafe8,cc15f85c,f829d913,9a9aedc8,6a98e010,5308572f,94c183b5,533f5bb2,c076b6d,c708d2c9,895e22f3,2fe42f4,33ad38c2,a0c55aaa,5c551fac,fe601916) -,S(3cd975ea,9eb5fc56,14955bb2,db0ca413,b83116e3,a09454dc,7fe973c5,7ee33ca9,261e5544,2fd503f7,7c1c7a49,de96fb50,aeac56d,30cf3ae4,8b2e1cb,1b9fcb6a) -,S(168ac250,d23cbce6,23eeda,1389e261,c56bc718,4234bebe,6b108bf9,bf6df45d,add3ffb7,b0a9a860,21ca51e2,f3d2e2d,19206bad,78d9e661,2895068a,c880fcb2) -,S(47bae439,31966a6,984241b2,2afc8b86,94db88c2,abdb1737,728e1af0,e3803968,a7cb7d64,a07cd13d,2c8dc7a7,8a7a144f,8edf915,5cec20af,102260b2,d8d355a4) -,S(76e73a26,730b1444,8ecf60e1,3489de8b,93355af6,8943669f,20da17f1,4f04d517,41f75520,3d5d528b,2e81bab1,9ce8031b,bf9c73ce,7927645d,178ad762,669b99fb) -,S(f6f08712,d85f9219,bb475122,1ada6a75,1a8d4758,f5dd72f,f5231d56,e634c19f,d72cfc42,379ee25,eb0fb134,338109a3,7752fdd8,1ad102b5,f365a276,1d133f10) -,S(1acac95c,9b0ed53b,e6c37d03,7d47a796,2a371caf,cede380e,799d0110,b0634f7f,658c6b74,44846952,93a5215c,63695a5b,fc80f818,633e0278,f6a1193c,6d441bc1) -,S(5759a8bd,ab76d449,13258631,68773369,5b76d2da,7b1e4004,1bf99198,bb25f218,15c1dc97,8ecff6f7,cfd6cbb5,44ab8666,83127b41,951c247a,f44855,4afde3cd) -,S(cae1e14e,c28ddbfa,379a97d0,5f3ae379,3771750f,5a9ec743,2039f440,8fa7e2f5,eef09268,6b9f60da,8e64ae64,8f13d01,8f7b9ef6,aa849f9f,72df2f9d,f80fbf60) -,S(9aaa132b,947da7e4,9c1de2ea,ce06e3f9,ccdc37d7,6d2081a,be5f3a37,9b0756a0,e9bee628,d6a64476,af601737,68829c11,e8646e8c,beba7174,806d800f,56f6676) -,S(f38b62b2,4d609d01,70cbe85a,cedde44b,7a766a30,d8b7db6,8d935735,c4d0d204,8b61a5f7,e3caa2f9,17ef9ce2,c5eb2499,667558f,7c4e4e84,2644dfdf,a57666c6) -,S(25c121fc,74c57f34,29a143,8ff3c47a,f06b5de,74c4dcef,4a093b87,3a2ab659,69254121,eadbd76f,289cbf3c,21cc96fc,436ea33,9ccbc8e6,fed92b2d,331246da) -,S(95666156,c40929aa,8a7ca656,c42c64d0,e24c3789,ad3781f7,9e2a0ea,c7ab9c1f,116f5750,7e07b846,92106d6b,6976741a,59bf7cf7,909733e8,e1fb54f3,fd77e783) -,S(cdf1c010,7c48b65b,c001df94,c6e84d12,d8885af5,820d65a5,4e7ffea1,ef4c0081,8f3d1be4,206bd313,e1c498e1,5e7a9995,64312ea5,aa823196,9c566349,9c3a04b8) -,S(955269f2,be0d5e20,5382b2c1,959103fd,fa2c2386,9bbdd33e,a09487fc,294dd1ee,6306a092,4ce63798,41b2d773,8cf97ca5,e259f81a,a67b1e0d,42903f1,beaa869e) -,S(78013976,449ddc23,4d32a793,5ea525d5,9afa3617,47e0a8f9,c8141d9c,2b231e14,8d28142c,bb88abfa,1a72d583,4e509d69,3cdee0d3,bdff4788,83618ce7,a1ace69a) -,S(e6d67a8d,fe513147,2c0fe227,bb08a8f2,25e2606e,23672969,ad3acd65,155f972e,46c8695a,5b9d931b,adb568c9,d3f9a8a9,dd501508,fed00c99,5159f518,bed035ae) -,S(1779ea78,eed6d974,563cac2b,b3e72693,409b7029,789e0188,d061a182,3f18e962,82590ffa,6b9e0e13,d2e72bef,96d555df,9f7d2b81,2423a947,e0dae41f,91cc0722) -,S(28ec208a,6e929f8e,a815fc17,7b927086,7d482547,53ba5c3d,3b56fa91,acbb67d8,b4453dd2,eb964348,94cc1cfa,25616a2e,2f0803e2,8796206c,dd31ccd2,dc69aff6) -,S(c218c6d8,3124c9d1,c988981f,d4614af7,ff85a572,dd89e4ef,6209e80f,e7656de6,7259c421,45ef6e9b,d4f451e6,e2dd226c,2e750650,8ff7834a,965cca4b,cdbfede8) -,S(4c9891e7,5559d993,536fec73,a433006f,4f0e4e42,f427300f,7a3825df,85b1cd9a,7463ce1b,9f9af66d,7a5d2d43,ab0f09ed,186eb132,92c75431,ccee645,4280aa2a) -,S(a89fcff0,694ed82d,537399eb,b59a054f,f43eb74,f8e1fc95,be0c03c5,9889c931,3ef3c627,e3011b2f,38d596d0,8ded759f,fe30ffc,9db95356,4e01c8a0,2949ea1e) -,S(a8b3ef89,561da88d,ca9890d,5e4be652,8a4b8fe1,691d1522,54bcca43,1e7ed801,c86fc397,52254f61,88ee5128,4bd54347,8abe7390,c784b51b,6d41c947,5d58bada) -,S(6a2fd5db,da9093c,2f7c7ed8,9eeeec7e,efd7e759,eacc2946,5d1f3a15,baef5b42,8b71ac63,3886ef25,74e212a0,499c34e2,d2c7c1ee,b70fe7f4,38e08914,48395e4a) -,S(d33dada5,30626dc9,1d23d16a,620dbeb4,7551ca44,dd6c8b18,fbf136b3,1ae4e097,4161f6a7,8273ead4,443c93f8,2562a29,1dea1adc,d84ba0d3,75a997d0,f07d4ed0) -,S(53ef9ef5,731d9473,93e70829,bcac3396,3b7a597a,1f3c861d,401af7f7,fb1559d0,8654f8c3,63e53905,a4d1e2c4,378fc3b5,fd5ffe3d,e7fd3adb,399d883b,3d1b9e18) -,S(5f13c5af,6979832,da1bd43c,4b7df970,1ad837cd,e59d8f15,381858d6,6263b0a1,3b0ec16a,1024c902,666dca02,4649c110,2a17205b,e4ac20df,26ce5b92,8baf90c1) -,S(674b7de7,f65337a8,c66dbf23,2f86d6a4,feedabbb,b71e83dc,fd854926,86f14f86,e3961790,a662c6b3,70460e16,18ce3b6f,42bb6142,78fe9e2e,6bb1179,181c2aae) -,S(291eed8b,47c3e2f6,b3c2967f,76743708,5c460c5d,d5d6a75c,489dcf0b,4d98b8eb,e19a9d2a,72fa37e1,e10ec853,9c772565,c53e36e9,160651d,c2a8e364,db408ef8) -,S(e737a407,1bf4fbe4,ee5d3d74,7df3cb54,cca38f48,f977919,907deccc,7090ee3a,ac66d422,79441d73,2809d695,68f700a0,3fc5be05,8241da39,9be3a63f,8da16069) -,S(67fb1676,7c3231f3,428b39e7,bdd082d7,1194a51,ae99a7a3,6c113e87,d338712f,38c2ae1f,afb521f2,279aae5b,6ba5c636,1dd34c04,a7726555,acb9265d,31c996f8) -,S(9b3b4788,71bc413c,5e9d2b9c,61e0cda7,f2fb908b,805f3370,45639,5e616230,7028b68e,af818a13,d32f116a,aeb0bf45,215d3d62,6e6ccb1e,a901544,ef1d696e) -,S(63193415,59bb1e39,2f92dad6,e5f8576f,7f49d4d1,439f4f61,a6f2be0a,75bd99e6,259d5f21,6c780a8a,5bba3e66,2242f26f,1adef829,a535dd97,11f8e786,f0a57932) -,S(4163082b,7720a8eb,e881b398,dae059ff,3a65fba7,f8b93afb,6e3dae6,6a969c79,3939395,d8e90807,e77e87a7,4c89f861,c689de81,a37caf6c,32788310,7b938ffc) -,S(b3a6baad,15c01677,ad6bed54,ea5ee415,4d0bcb7e,3ce59f17,7ff26,ef23b82b,711681f2,1e56c0c5,f2c2b011,dcf75716,300e305c,110f4071,51d11890,25bc4760) -,S(9011d111,fcebd882,b9a228da,fdee1297,824c4007,7d5ad9bd,59e603b,43be8f52,d530102e,aac87930,eff135f2,e55b5310,7c03ea00,d24f1201,6653e3e5,5d778246) -,S(d50adaf1,d68a746,e1e7b148,7660e90c,f268450b,df460d52,e1f761ab,bf7018df,4ed454c4,5eb30cd6,e6f1c4d8,7df2bea,e15ebc07,e4b4e50a,e4dea733,93abcf8c) -,S(cf886295,d1eca9f3,4c95acfa,b86a5061,82e30324,ba5b495c,70318cf7,9e910d70,59bb7068,3147c26e,45c76e7b,e018e467,1f47f488,2c044484,62a5053,8023fd40) -,S(38723d58,ffc69ea0,9a8f2655,dc225da3,78b9224a,f8d81e7a,bf8f29ee,292ddd24,c41d67bb,e699e504,3198adb8,ff11a5e0,4033b66,98d3ec18,256bab11,93db5535) -,S(5b41d5f8,1e2443db,d13521e6,e7b7fdf2,4a226cce,f369279,22b353ef,107f759d,8ad730a5,bfb9f01f,853434b,24866a49,912fc756,e086e781,a07ff2e7,98ef38d3) -,S(4f3c24c7,7dc7e41,843e9018,400d3bc7,5d1dc958,2895c11d,3855b80f,4709373d,a485adae,c547a5a4,e0695913,c4c2fb5d,ea16a3c,5211c162,4819d704,5b0d8d6b) -,S(f603e0c2,8b40c8b0,a6a0378b,c4289059,5a4cf4c9,2b74199a,4e4e231f,a6b458a6,a73aa12d,76572041,f01c33ea,ca599a30,9ba0b838,f1d67fd,67a9a5d5,c3ffe258) -,S(84ef0a98,229c7af,9404cc25,60f4fe1b,4c8e66d9,1aa96118,53fc4f25,eac78a61,653df937,3640b28b,2c2c4061,1d79c4c4,a2d577af,b572f5f9,e50cf3fd,2b2dbcd5) -,S(e675d998,6b3bcd4a,d098ec95,c386be9b,4e96e448,ce6c9371,15c5dedf,d97941b6,4319799e,c4103d65,18590091,e333cd58,9901b020,a62565b7,f84219bf,e31003fb) -,S(10837b33,3603f33b,e528f391,b5b672c8,93fbd813,99c5dfea,f6126e6c,2a2633bd,cdee9534,2456a261,8a293b49,d91ed2ae,f620addb,ed83fc66,d169da3a,a6d0e2f6) -,S(4cb1ddb6,6ad3c1b,68c6b0ea,408ba1d7,dafdbe54,89c22d47,7a62dcc7,77a8e013,6c005484,29e789f7,5c34d8cd,a473270d,75eb8f1c,3db13856,87cda96e,5cd4b370) -,S(db72d671,ff3e0102,b1c52481,b66ea142,8f7fcd43,15e2792,eae234a9,291926e6,71c55f71,68a088f9,980bdb6b,79b052d7,4edd0b19,7ab7359d,9a2f9ce9,f1c5a5d9) -,S(99f92125,162e18ce,7493e6e3,91cd06fd,681371b3,2e147ab0,24ae3799,15f586d3,9286b3de,12ee578a,12ded341,75bdb712,d939b7e5,555e86c1,82f1f283,3c1b1d40) -,S(a2b8b63c,8984a666,2b09c18d,b2d7f263,796660f4,3bd78eaf,af7c63b,986c92d9,2003787b,2af02879,642b0a2c,f716f4d5,85dac86f,e58c7d41,d1959763,310a67e1) -,S(9292ef40,21bbe6dd,8c26a862,c9b7da54,4292e479,a9e89264,618e3a47,9773b446,d1a51e4,65bdfdd0,dbf74fd3,d449f6bb,ea862eed,ad369c52,34a695f1,d229ead2) -,S(8d5a920,547d838f,90159068,ceeab220,cc6aa126,d423edd0,2e136cc0,1cea5d4,c3334a69,f7694e9,43ccb182,2caf2abf,f4caa83b,a006af52,bc010bab,8710b596) -,S(7b62f4a7,7b79c09,76dd2f74,4ec08d9d,21511fa0,7891ff5c,52b8dfa4,ae3430bc,70ab2073,cb3a7cea,350e6aed,dd0c9a6c,ff8e02eb,69bd14a8,a09e9b8e,ccb19a0a) -,S(e18a9c02,5829b47,cdd34c11,f97f2edb,a7fb9b9d,fa4777a6,dbdc3cd6,85245b12,7386fa51,881fe49a,adbd5327,8d6cd0c5,1063dab0,aa830b7d,88c7a4d7,9998e743) -,S(ab9b68ad,61335dea,767c763e,3294d414,74a6d4ce,e4ab9a78,7fbb6749,7307d0f,aab48fbf,53f365ad,bf94f823,ea973a25,f6ddd341,397bd81f,8e825f60,c916852b) -,S(3412531e,8423364d,8d8bac05,bb78973d,7b8d375a,9e52d81e,bed48027,2abdedeb,1b9f5eae,59ea3385,9de752f5,db973a86,4c735e69,fa8882ec,e1ca8350,77d77335) -,S(6a6425bb,af9f65d0,1a401330,46053b50,7ac8d45a,77b30de3,69eed52b,956799b0,7cbdae81,93368c60,5671ae9,faead4ca,2887bd8,9a06062b,dd6707fe,f849f484) -,S(87860648,af9ffbad,50871c2f,29bce0b3,e9693835,8a067201,5c1156a6,7107a4cf,8660c0d8,f1aea58a,c613f6f3,5b27baf5,53835493,fbc0e203,f024ee36,27bbfa53) -,S(35733610,71c55057,5392c685,3cadd8a3,6618443,d80b3625,53a2f197,d3c52539,42935628,adab5bd4,e0aad0dd,a7d76627,58524b2f,34ded1cc,d3e44249,6d213630) -,S(82d21949,2fd48d51,65bea027,6ac15cf5,d27bd736,45e03271,24f0f689,8a2f4a25,f13d9063,fed02a94,1b4e5c67,f42d82b5,33f18ff9,ca4622f6,79c6aabc,ea454c21) -,S(ba1a1c83,6dabf825,e517ff65,549e1d5e,729944a1,d7b17cea,aa4466ac,39ec6eba,f01dd751,3557249,d2fb224b,40ea19e0,57b4052e,adc46787,af587ad1,458bb4f0) -,S(5cfeac36,6bbe58d8,45a36cd7,de6601c8,56943a07,522364b2,23a1718e,6df8de8a,6651d3d5,a344af69,25fe039,c9e29e77,95544b96,66752f4f,c9a3bb57,c5586c32) -,S(e5e314fa,2b2bb630,6fc235ba,cfd356ae,bbf88bf7,eb039629,165d8651,c0c7d5ff,c727787b,a63cddb8,feef96b0,2f6c8d0c,9722fb4c,6274e034,32d9016a,eb4d8cb6) -,S(f84d8db4,b745cfc0,bad4844c,b5a28d7c,80ed5fe,6baefda4,1d9cff9c,158c7ec1,cbd7bc36,a8313a27,feb8121f,a8847bd7,937fa53a,d56ea066,fa600411,d87dcad8) -,S(8806a2b9,d72156ee,4948e86d,43f4b3ac,cb24529,e1b2b2f3,5ff94812,e9534513,aff42464,773f6535,b4dc5eb7,76a3f7b0,7bc2fdce,1413587f,c4055cc5,afca3129) -,S(e2ddb5ef,a1105437,b6107305,bc715e55,ec0266aa,a0ba1bcb,e12ab801,45af7eb2,43e4d056,804f229d,da5a1efa,8f429189,6c9edf94,fba505f3,1f22b511,8b698ba9) -,S(636f32ff,ea843368,c0cb708f,43841ef3,20151e39,35683ebd,bb1f476e,af2f8c5d,7fd53321,517616c,c7d24b51,851bede6,b03c50d9,82269773,dd51e36e,4898365d) -,S(bbcdd1f,f5b47391,d728a06d,b4783d5,b0e279cc,107488de,44446e36,9d11d143,6ac7dfc6,47d25b37,7281abf9,ead782a,b5f815d7,b2c9f6a8,46a8a6eb,9253014e) -,S(af0ed949,22336a4,337e9c01,53357e02,3d7a2728,3c649712,3e117944,39ed3577,d8b9c03,958dfa89,ec2105b1,d9542d68,568797e3,7df16cc3,861627f,298f3359) -,S(11ba75ae,db365552,b0d3f938,f03a115a,544a0818,b2f54f50,e4873249,6f80ce13,a6bce69c,f9838317,70f70370,7073e87c,61b65c0d,bfd34dea,f0c549f9,c58e674f) -,S(e7560fb5,79e5ca35,f45881db,b05383f4,c5536ea8,a5438fc4,ec198ba8,7543d3ad,ff48d1a0,bcf5e510,9ed50a0d,ed8e5b83,44da25e1,a1a3d421,606d19f7,e28fe79d) -,S(ce7e289c,61f4927b,bf933eb5,193fd2a3,a0686435,80c8f235,1e24c33c,e418cf10,17246f2e,e87f4ce,f1c8596a,ecdb1f95,1407ee7f,dd839c9,98102344,2f4dcbcf) -,S(b765b875,32ba4db1,211c612f,b833ba18,156fa0dd,875aa61,df1ba9b4,7d1c405d,862d28f6,d85a8ad3,bebfbc82,437404f5,2e0abafc,64369b51,b75364cd,c827171) -,S(400560bf,d2863ea,2bd9e246,4eafab2c,2798cb95,b976c022,bb9d2153,e5978a0,92ca9a1d,938e53d5,d10f1f83,54abe43c,e8f8c2c9,d4e851cc,a363ed59,71e2681) -,S(7859190b,8e619c98,76af21e9,64f323e5,221cd4c8,83dd9fdd,e56f691e,e3db91a2,e1874376,755165c3,72abd73e,415f2663,bd94cf28,2009492a,e5034da8,6f6bf949) -,S(87d90b40,bb472b84,f9d24caf,ba7a6437,b50febd9,5c643aaf,e235750b,12527ef6,e6a0f719,25697425,23517ea6,183faa64,dee1ef63,183ab1e8,3a603b98,20452c4e) -,S(dbae1ee5,a1b6affd,f9b41ff6,a1f2790b,2c492ce7,53865690,ce5281e,a7f08177,f6a2be90,a2c3cf,8e14bf87,4cc52648,b60f9a26,2930f6e8,9fadad4f,d919db6a) -,S(943a79cd,88260475,10d90c99,4d8d784b,32c03d1f,f2478102,96125f7b,28576216,48d4477b,f97c4cbb,4a96ff99,e427d4ac,cda9a367,2ae66930,88d8cc57,3bb3e2d7) -,S(699911a3,81ff3c7e,71b3a458,14133f3c,ec644378,e3244d66,6d083c55,7b6c040d,3eec684,3190d6f3,85b07116,b3b1ba15,4ecacec0,63e02933,9b83afad,5598b22a) -,S(f002302d,9ca256e5,cc38ad82,e529b461,efb69f28,52513917,fb8d63df,45e602ba,78455ea9,708b750a,97dc74ec,8939c880,d76010d6,78e0c112,3616483b,fb4e788f) -,S(5f701ce9,65a20314,a65e2c0e,1cedded9,ddfc9d01,41a1e095,e91b9915,cd2aacb1,57e770f2,d04e33ff,c9d7807a,4c3d1edb,3f9ed2,c19771d6,7e85e618,463e5663) -,S(454c122a,ff85c42e,49d6f033,87744462,8acfed31,90c41255,e8e34928,83563fcb,9d9d6435,a2c4d146,d92f34cc,40b32a7e,55584885,82143a,52039fd7,129fa6f6) -,S(d9abd19e,81f392d8,8382918d,6ab3f89d,de793abe,2eba3aa7,b58b0ca3,1e614e51,8c1a0f80,8b8d9e56,aed21554,95f8902e,a390505e,15cafbc4,2b71cf05,575abeec) -,S(20779414,b5ed6524,b3613a8c,d0b6e9c7,ff3b14b7,7264cb8d,7b266ef6,cbb224b7,c1437dd7,71f46cc4,3cfa52a1,28c70367,d6682553,28942150,c4068da4,8c218d66) -,S(141739f8,503f2225,feb40431,21f0a5ee,844a7707,62e37d1b,3e43fad0,81c631b5,a0a13de0,10566ee3,1af8c6e6,38411c1c,a3df6c63,c8ed67da,8ef7bd19,5fd6e73f) -,S(de8d06ae,dd58b148,91184145,fcd9bc64,634725fa,e4a77d35,70b21c8b,77890b60,a046f351,eccab99,1d3d1c1c,642387fb,fb9c3f92,75bbb93,46688555,f7aa9460) -,S(312c7ad1,53f7280a,9bb86cab,ac573944,d271bcfe,bd59291,c6f05fe4,ec003a81,3c6428db,5eea01c6,9fa2556b,1f20c1e7,4e65629b,e73e6429,81b971ad,b6563866) -,S(2eafa04b,d276e33,75b8d063,b206785c,ed69f763,7a5a8b99,ef7d3de,bbcaf35,f06464db,56ccf55a,1f41efe4,d1cedf81,a642da24,3cbe68eb,6ddf7ace,f67dac6d) -,S(5873091e,dcc8a95c,a0a47570,3d88e54e,1381c2d7,a418f615,eea97470,2c2c6fbb,5a91598,b8e47d2b,2fee6cdd,c33aa309,9bec74dd,21688542,9b76543a,c233ccdd) -,S(e713bd84,ca505ad3,aa022577,c0cac85b,466874a5,b02f4ab9,e8d14bba,c131fcb,706dab4a,fe49e6cf,d290913d,358d1dcf,62e8b4d5,b9bd46a,322ee4a6,5a660849) -,S(aacaa633,6fe86d41,b05feec1,cf4866d,340fd268,f869f912,c2373e10,bcd95340,d933cc5e,c01024e4,77d1e80e,c533f293,e4fd0dcf,7d1156b8,7ebd9d81,b9489c57) -,S(cbe0ce9c,77649031,25590e03,cd9643b5,dc45ecc,604d51fa,d5bcb8a,196b65ee,d2287fed,c331d56f,e585bf1b,793fd957,ce425492,df41d8b3,4faf84de,c3bf4d22) -,S(f9990413,deca9f9a,4ea6bb8,fd9b8732,57d15ec3,70e98187,f4170103,dd416dfd,b0593cb5,dbce573c,f0a75f2b,c4756781,963e1a2,e988e0cb,23efbe26,c215ace7) -,S(2ee21d79,bf3e82a6,2bcaef34,85276c5,3b51bfd8,becbc9f9,6ad316f3,a74bab97,fe3cfa79,b208de80,f659cb81,bed12184,ea2c2524,dc0bea05,64acefab,1acd8fb1) -,S(af5c91d3,44fccd3e,70345a2b,ccefc0d2,19287be5,aca40ebe,e61de522,56f25faf,bb58da83,bebb5346,9b345695,fc23853c,bc0221b8,5d75ced1,da107fc5,c106875c) -,S(2cf50e13,477d628d,117e0bb6,1d3ff9e6,1108fe94,bf82a6f2,4138a743,6077e0af,339c0a53,77a6465b,29377e1b,dc344464,875687e2,7d1f392d,96a275a,e259793) -,S(c51a6610,1522f63b,84b98ec9,31984865,eb3b29ce,fe115b28,a87f89c,67bc441a,240b9717,6af4beb4,b0502d7b,2caf8c7f,47a9362a,9f9610c5,826762ea,a2a2be5a) -,S(27478eb7,b14d84b0,80426792,b0e2e510,8a4804e3,a15e80b9,c430d7df,c09d05ce,eaa0a072,86fac65f,3da47bfb,4010fed0,fe8a9e17,ae42ece9,233c2078,2b36422d) -,S(531ca72,e21caa6a,43f0c9bd,d0bbca5a,b12dfb9f,70f045b2,f0865077,cdde192b,c4ed88b1,a0397589,3cb14ed0,897d6bd,783dc647,ba59772,16c308eb,630367e8) -,S(295775cd,950d0702,602278a1,56c1d05e,4343474,a4b3ae87,63f4a686,7688e42a,907fa8f,1269cb64,41591004,f6e62b14,4d6c54b5,f6ed424d,6b0a8a75,26935b49) -,S(e88425d8,bf6e89a0,f9c9f525,97eedd4,3c331058,10936c23,4da69d21,9a86f82,56d53ae5,e7a354d0,d65cf742,d603da2b,199e147,3d42bf3d,639f83a1,cf91cb65) -,S(4d20a032,c44453f7,b374a82f,f088d816,c1fa9338,57dae8c7,b87295,98869a4e,a7ad5993,af43cd42,1620e87f,fa0b3305,e7da39ef,704319f,ae5faf55,5e3fb43c) -,S(b98e9728,e9288607,a7ed6df9,c68749e3,9d7efa1c,4f964428,5e9bf81e,246e936c,1620c470,19b9cef8,7c1f0612,cf56adfb,5526573c,f7746a98,48a0d40a,3a92d38b) -,S(562eb109,e9988778,bed85413,2fa7d086,6b37a8b,fa2d2d3,470da3c6,97996a48,29f4f0da,e554e380,613156e3,34207e6,fe8fa678,4c08f2be,c3d6a59d,1e0941b1) -,S(b189e864,8dc0ee06,b09ea73a,9a01cc06,b6fa74dc,f626e41c,ffad926b,901ae851,4e42c870,3d04838a,9f0682fb,bc13c849,a515d5f2,f248f393,e2caf0c9,b6d61d0c) -,S(3894cdb3,425c618e,1da2c6bd,1177109c,49362a4f,24030692,244bb0dc,27af6913,20c0021,5c72939a,497f08f0,bdb03493,8d04ddd4,8fe8f3f2,97dfef19,ec9397c5) -,S(394f74a9,9146fd43,9035266b,ccee72e9,36ff59cb,eab7bf4e,925c6363,fce7d4f0,c7da15cb,c1cdcea3,21efb1fd,c56bb3d1,2bda06b9,993b6f5b,2293e493,5aa3e5a) -,S(44fc66ca,d6e67f97,be95c667,fd5dfdfe,dc82edba,35df2bf4,737b3ba4,14d15c27,9c485757,351825c5,245c6eab,2ec4a51b,ac60c9db,fff7988d,8f28728e,60f418d) -,S(fa355672,d9f7a1c5,30b2d76,f183720f,e50840cc,ba413b64,e449d2a,8b0518dc,63fe1c7f,d97c7744,35613167,660926e3,b7377fd5,97dad03c,9debba5c,a5a76e3) -,S(7325c269,50f1bf21,2f9cff6a,170e446e,62dafc2c,f05dc50,4eb951d2,6322eefa,5f8fa04f,ac5232b6,cb553630,5a48b647,263a57d1,2c485363,6c930497,40965f00) -,S(7004b364,c89ac7ba,ad03a03c,c8e2972,e5fc52c,bc656165,e08df216,afa216c2,971a4284,80556797,ebea8b1c,b37de6a4,1aa11abb,df9b28b7,7f50d362,b6554974) -,S(ffd45087,eb9308fe,e7644817,9406d9b9,77364732,f3570ebe,80a4710d,a0ef292f,f4ae4df0,5af2ee0e,456cca0a,2c9d93a0,83eb9751,a09c2f8c,5bcefce7,83764ffc) -,S(ad899e8b,a7aedce9,e53d86ac,5ca15408,140c8f1d,be3ba4a4,275f332f,b0320572,a914795,bfd9850a,24251eda,98bced8f,2e2627a7,8a1bf6e2,8b66ffec,f11ea105) -,S(7078718d,e94255ff,ae25f1df,4ec2ad90,e59ada11,5ad4a6dc,8b305fcb,93a1114f,ee736453,927cd7ed,bbb55010,32eaa95c,c0f6bb42,be77db4d,62b77650,1094ed7e) -,S(30858d4c,d39abb36,51b8d35,58800c18,5495bf31,bf23dc8b,176c1f04,171e304b,3aad8415,4abdfbb9,1eb95aa8,4e7ace9b,fd8b5f6f,cc8ea08b,e094c874,8161f85a) -,S(c06d6d2e,5637fd7f,df08b41e,5573478b,eb19dded,ead1f0c2,9309fd59,9551c787,78cb2514,37d4ca62,91bab9c5,57e88244,edb9dc30,fb1a6441,78217039,628e1db2) -,S(2f93455c,279d2a26,1cc7b724,4c32c853,459e5d99,32692fd8,ffe7ff0e,493de2c2,455f0902,74d698dd,a1a97586,fe797421,899f7c22,60ef0bbd,db0664e8,fa323156) -,S(c00c345b,b4b53f5a,5dbc5f10,597dbad0,75e28162,32e0ac71,fd778c50,20b663d5,c30f78de,3495063e,ab98f001,83fb4bb5,5cbf58a9,1bd52ea5,36a4a38b,cfe89288) -,S(7d78faed,f86a22b0,14e86e1d,f98d425c,fe2e65a2,39b37994,ab25a4d8,5c863382,cffee7d6,5181e361,679c9d51,feff7a36,e8d84282,32e752b9,62689eef,a1ff4441) -,S(ab492cb1,da2e8463,a2536c0c,7cf143a5,9626497b,23d4c179,d2af4cc7,f2b55866,11d4205f,55a74f81,e9512496,becb61c4,6363c42d,baede671,9bd7f2f9,3e00b14d) -,S(d1a3790b,478bf657,360b3459,555e1dc4,ece339d6,93b5b51c,8a3af121,79578688,c6028991,3ea89956,802f8b8e,cfc8dbc3,5894846d,1aba2074,9a55153b,83f73891) -,S(6fbb6fcd,36fe0388,a4bb648c,95a004f9,b3c64e4f,9aad672b,42d8c649,4c0cef3e,51be473c,74ca2609,c3b79c60,2fe90d98,62eb9d14,b9e52aa9,ddde106f,7253da44) -,S(db150ec5,680299af,681ce826,794e4818,c0d6d3d,e3c392e2,79ecb408,aa55b243,15e47cbc,1c4689bf,fbf7ef42,1db5c57b,e3ab8c16,b69bb518,2ed8a1cf,20067de8) -,S(51ffc919,afe67f04,a889323f,4438da99,72d2161a,54f9e81f,aa1e644e,9cb88835,e4b579b7,e985b38b,486d0600,3f825538,52a9d0ca,b8fc98d4,371a7e33,4898742b) -,S(fc86c54a,48052ae8,d8480235,e4dbb7a7,6d05d830,d2c0cbbd,297db0cf,3d2d6cea,6cd61522,e2a22531,da973c1f,9cca1c77,98ff66a3,8f568935,e378f73f,9f1d7dc3) -,S(d440de01,20d619b0,6add3d7f,66184864,5754a424,f4b1054,479a83bc,7df0db9f,3f09b245,91124175,89071c56,84215cde,a6999b17,b5b2f664,6074e7ec,6c38f68e) -,S(f3310bc7,7556f234,e7c83d69,48afebf0,5bd91a25,b516cf84,60d0d6ec,8483fefa,1d10f23c,e0e35816,6b817553,cbae0792,9e34a4a6,ebb47186,1d401341,1ef2b3e3) -,S(ea770a59,e88b598d,493fc75c,62eaa9e7,485271dc,edeb1d2f,76df983e,54cbb51c,e2a4baac,96c9538,3de82a29,5bf3cf30,53bfe2e4,6fb0861d,65c60c09,978601f) -,S(2cd56ef8,6fd04d2a,ed4f8520,951798c2,a1c69a38,8e635a2c,edfeb08e,3af0e331,3b9de80c,42e0c683,85aecbd9,c8775b56,86a8a376,39efd24,98664343,e712707f) -,S(37bb0206,c96d8fd4,5315e96c,860f5cb4,a44d2b6d,af17844,bc305b4b,59c9c649,c77b4a05,373c42e4,e071090a,7da9b4a,4ccbbeaf,d399496d,f6fea1d1,a83808b1) -,S(55fa08fb,f83dab6e,ea7034db,15bbddc0,ab2b472a,b29861af,543a970e,d16033ff,73c8a90a,86542970,4e25f370,a5caa4b,a68eb72f,5ede1edc,5549105,491858cd) -,S(4eafb675,281fe8,98593817,efe128ca,c59fb775,82f6006f,339631e0,6e7d2e7f,41347946,6630f6d3,9fa97404,6808067f,fca9e173,3e1c4149,6567eacf,47a0bc6) -,S(857587d8,375f24f9,e6924793,9ddf3a60,e0469f38,6ea0d55,d990f1e8,4ba5c7dc,1913a118,9d867c57,2f947fb4,3e062cec,3df37c3,e8edc6b1,927b315d,10c37be3) -,S(89e334d8,f71eacef,6cdd0a87,b1e03352,1078a1fd,20dff144,10108202,93143815,8b49aebe,71b60eca,c9256794,3cf74d9,80bb3e47,161b2730,9ed15872,7accd84c) -,S(69902d6,8a4ecb1,d2e496e8,cdaebf94,58f71f94,8f4341a4,11fbc2dc,524f694a,19a54c4a,5de17930,6c50cc03,b0b8d54,b613cd31,6f0bdfb7,851db63a,9c605896) -,S(52f8a3bc,832de46,1bade518,50121b5d,2ff475ab,5eb0e71b,a91ede46,41f0d576,2a946bc4,42f24ef9,469b8121,31021186,5b22f3a,adf93648,5b7907e4,791236e2) -,S(146fc341,4ca1c497,73734f6b,b78ee9e,56fedee4,9487ea01,a31d3e4c,152d2bf,82e21722,e415f5a4,1a076f3a,8324db4,2436da5,a3776f60,b5c6f53d,e5419db9) -,S(9e22043,8458e463,b1bd7399,28200a4f,ef7c3760,a7b6357e,afc29a5e,36b37b94,b1f5fd78,c1c40d98,1473fd4e,72af64d7,7387c28b,7f005191,5ed2587,674877a1) -,S(53190555,8d044a1b,94caad4,526cbed1,82807c65,2bb053d7,61301ab9,68323f1d,ce591f2d,61b47a8f,8707d8f6,a8717139,68ad569a,667ba4ac,f2d18356,ab6d326f) -,S(b93b3c6b,1297cadc,392b0cab,da322a1f,69791a68,b48b0ce7,4352ba3b,b8a3cc8a,136ec007,24fd378a,53d5c573,3aa7a06,15b2fb20,4fed82ea,934bc131,7e7ef22) -,S(62e6af72,a9fcc956,4367d44,c0699897,3674e3f7,b79c67bb,8c8a82f1,6d3f744,4c1e4e33,2e9316ff,24a7b38d,13ed1b30,a659a8d1,8423db6a,af6324f9,4e7d5475) -,S(c91facca,aad0790,886c4421,d28f3ce2,9d64dc87,514f06d,cfe95063,dbbd0e3b,e7a0c83a,18d655d9,7a555c51,4bf8f117,59ce866c,61a7e691,8ecb1cfc,21e50710) -,S(72b3b928,bea91ce8,767b2f22,958458ab,9a23f455,78f836,65c89717,7e7ea502,773235f2,c9ec74e1,c06e4e7f,89247d12,27f303ff,2fa354a0,663791a6,ffa40e49) -,S(1b014ac2,7213cc08,67877fa3,c0c07b1d,91529259,23f6164c,f1d204d9,addd6f4e,e0dec57a,c1ec264e,380909bc,c62394c7,413cfd48,180b1de1,c5440d08,99c67f2a) -,S(985e8845,97e2831c,4ba48888,ac219b3,bd891dc,63176953,4e0d8a96,bf583a83,5afa0b31,1e909594,4b228958,657b95dc,a198b008,6f5cda96,c3e4da6d,e444a418) -,S(ec3cded4,cce88ac6,22315a51,ec99ed3,1ba2cb32,74a43e6,98e033d4,e490bae,1c2a2236,2704a765,252b2a57,aa1ecaa5,4f1c21a5,2d67c050,a3dba077,ad4b4480) -,S(f882c4f7,7911f6e8,64da7cb0,5f09da54,b9cf7125,21504815,e6fdb9e5,73f24be6,9ba4a4c1,e0978ee6,1f83aedc,b1db2193,518a71d0,c112b9fa,59c629cd,d42ebde2) -,S(f06c3a4a,9f1e80cb,e2ee6b06,ff50e447,13d8eddd,5857243c,cd02c5d2,7996eac6,6b38bddf,fccb4888,da20ce7e,495bac5e,7b9ec8b2,2feaff5,8d4329c3,c546e839) -,S(dd1c366d,5be82883,eb86da5a,f9b5d5b2,89de6b9,1165b91c,20ad7b73,ab4de421,19bb181,70b31a81,45232ba7,ed0fa93c,273751f4,838633f3,c94647e2,93c06bc0) -,S(e965c1f6,89b3f7a5,97d23d9f,378b9a03,fb1c6e29,5354de36,a5bfed53,3338372e,d98295bd,890e98a5,9d6dd93d,bd9eca2e,e79b028c,7459779c,2d3fb665,46692242) -,S(4f9148b6,cf21f5fd,911d7fb0,e92132d4,686d3e10,12da444b,f5a89040,69c2fcaf,60e9b3ef,924260db,ad68793a,d684c316,6889b0d0,38474c70,6ca25978,4a5fa7ad) -,S(d9341e6,6a505a91,dcefd533,90abbd54,52b39594,42deef9f,6a67dac0,8faa5e00,eafdc1b5,2b7c97f2,21ba8635,d49b58fd,17cc7983,92e09d13,8c41d679,6fda331) -,S(b948bed3,4f426bbc,e6c24ca1,fd1d2092,1de6f9d9,f561c32f,877a4104,afe81ae6,5cacf40d,f6fba19d,763c5b0b,83aaa284,f9485705,ad882b6,d51bd46c,b12f532e) -,S(73011c97,dbeaca8,8bf04371,311e9558,1e494b73,1778a2f3,cf906cdf,64dd781f,2b5abb31,c2e56a38,e8236f7f,b28a93ec,1bef3fc8,9be46d92,c2fc476c,42ff4ed9) -,S(44835043,1373a095,13f756e7,36ac8342,24004348,70d6cc5d,ba31f74d,565056ce,748f041b,a9c990b7,70c36f68,5667109a,acdad74d,4569b107,c968e517,143499ae) -,S(3463b029,e9dd1907,bba2b582,c9ff1f26,4a5ef4b,40f5af28,2a00c136,97145ffd,9e30bb18,fbb70c1c,edff9065,968523af,33665b53,3f14457f,59d7edbb,d5f07c5c) -,S(5d95aa9a,9fc67758,56e6655c,21a62670,c567e236,a41b523,436beb2c,18e69c97,d6478496,4220cd62,b4651e8f,965bbde3,22aeacc0,6557f656,764a20e4,649a1ea5) -,S(48c65239,d03715f5,71ddc36f,313a1723,b014c047,30cbbd8b,ca9617b,e8fb3874,c0bd39e6,3cc00fde,74c991cf,f6d711a5,356b029,5b6eb9c0,28c445af,21de8325) -,S(67c610ba,fda8dfe6,c7977b70,7a57ebd3,9654c7d4,c9a0aef2,80c896e0,e8134078,c3d4ffc9,891a4267,612aefe9,6c1093f7,8e1b9a58,746c986,c5265381,3ba46aef) -,S(4605213f,4a21b15a,4a471e10,f157d0c3,faebaf0a,f7cd05c5,a27c56c1,88b6d430,9853c145,5f4b3d38,200aebf9,d08f87ae,3eb4a99a,3d94ace2,94331e03,876fb751) -,S(6277ce5d,fb56c2fe,3d32e28d,6754255a,ecece179,70615443,b0d33e5e,b54e475e,dc7a742f,92160074,69d53e73,da526102,a6f68e7f,e8f07a91,98614f0c,17daf06c) -,S(7fbc032a,fdb50898,3270249c,f1a7d27d,198432c1,6815b7d2,c929ab67,bf12f01a,dd696a37,fbc4f852,6db85ca0,6bb498e8,6dc33480,a4f84564,2b49775a,6bf20ae) -,S(dc849e28,6b934ef,30cab6c0,1cffaed6,9ea74ab6,96578027,4c88845b,8ac264f1,6d7f94ae,347b9b18,bfa2bc0,d6b9a8c1,13ef1a70,78e317a2,53f21590,667f4b5d) -,S(e29e0833,7da9e0b6,b6886c7d,fe010cd8,9a4b10c6,f5e4ce38,c1202f59,94a69016,de082f4a,9c21db41,573dde9,d2ca8256,57c67173,207d43ef,e42ea81a,ee812dbe) -,S(407f0e21,ddccb63b,5672eb15,742d72f7,1a522f9,20d04247,3e1438e3,7bdecd35,28d6f39c,cfb36986,351d7619,daba6271,3c9869f9,357504d3,25c112bb,74ad336e) -,S(653286df,15bf657f,1685bb92,98462383,7c819def,84a8c332,77f6d777,4c8dd3b3,c5ea3d4e,f7a97324,96a98abe,f999c25,9a8c622c,944a099e,146c0708,d108eb34) -,S(47613ca6,ca7fe67f,4286f12d,3b4bcd86,455a1863,94f2bfca,e162f991,3bf6ed7f,4409a6d6,2ae63ffa,a3f2be74,e7d0e5e,3ad4704,76282b0,c2919750,72be1386) -,S(8f9bf4cb,4aee791,12162fff,75f35393,509fcd4d,aada298,655bd58f,567e6adb,893c8b52,c2c25f8,e2ea051e,d1a35a3c,8ddbbf9f,508ac792,37e53143,7818102f) -,S(4b25cee4,2f955db9,79c85682,4dae806a,3925a33c,42e6b6b6,ab4997bd,884f68b1,ebe38f45,bfa13922,d3112af9,1324f526,1c5f864f,4d722576,24e3afe9,9eb7ebd8) -,S(a8a40ca0,56b5e168,6fb9a348,ae26b15b,cf812cc5,b9c5abc3,44f86021,69958e81,a55421a9,4f1fda1a,f6d64e48,cee3e4a3,434293d6,b49a5cde,b521c0de,49cd31cd) -,S(1f7e97c6,198e27a6,48ffebcb,55c001f0,d591ca64,77c7c1f9,43928e2d,dbe88dfe,2dcf0a3f,f296f744,dd402fd2,48d29c96,49abc871,28624da,28134cf7,6242e6d2) -,S(7ee29348,7d6520a5,586b3ba7,4a0a660a,a4392e5b,77529e8b,890a5927,aad1ab71,a51d3123,b4faabc3,77bcc565,d66d4c40,92decf92,f63f81d2,ba3a4f06,2a8ea485) -,S(30880ed,b4f5f2d0,95c34730,d10a8c02,11efdf6,784b4886,4afff98c,407734fe,4ca4b106,41c55905,9a19cbaa,bc6837b5,300aa1c9,8b0d8a72,8caf5cd2,914ea693) -,S(bb7ffe45,b725038b,597a20e2,6f67d0fa,c77730e2,4ebadc9a,23afb4ef,a01b4d50,dcfbe717,46bc35b9,81357857,c0b4564e,1ea11852,c5ed8372,bd15eb69,e674e14c) -,S(ddb59e25,20a5842c,62607d4c,6d31f2ed,b79e387,527dc12,5d96fd04,84385e51,2a167f97,85ee4285,7471c45,2c38639e,69940f77,b3fcd54c,a697100,37d9e5ef) -,S(3c405df1,36b1c6f9,99fe0b3,2bf5a305,bfa4a6e9,994a1506,9c5fcfc,318dacf5,ba5ab8fe,43a2de82,ce289cf1,2255f554,d7881d08,a54017f1,e0c84180,d963f3b8) -,S(ed4e6e9c,9d4eb277,73f2249c,13d6fc1c,5c07be47,9ca48e35,913f6fe8,384851a0,8242617e,36b3c298,b13aab58,b7383dd7,93ccd4d1,7787062e,195456ec,43fc4198) -,S(60fb7766,9f312be7,11d0a269,a72a85c,e06b70c8,1d34416f,f7ce1a28,41d50895,ba2097a9,772a616c,82cd5dc7,84585c80,65206913,474f49ef,71579a3f,8cc0d825) -,S(1336a678,bd5d495d,c688c039,a60b256,a09fc946,830fa80b,1622890d,9c8f0881,6d57f261,b1073b42,f6eeb514,58e994f4,7406b3f2,7245a0e7,528748fc,65a4937a) -,S(adb7e6dc,72c02a9,fb99645e,a3695824,db60df0b,f9b6a420,75cf02bc,4e3713ee,96325866,2a062180,20f8b86e,e5ef1e04,57d01fd6,d5541d6e,50798883,9f03b3c) -,S(674d6e5a,6501f824,87efd592,c37bc14a,ab596cec,4d5e6e8f,1be44a53,a9d2f416,e6ca1153,76af0429,1bc2dd6b,2c47a816,c17e0ad7,c252c1d,cdede8fd,c9a18630) -,S(ed73f5a7,93dd0359,68e253ba,8ac4f2ae,83d7f290,24eea4b6,fdc418e2,4b63dcdb,bf687b81,4691d48,5296e192,d5371ec,daa831ea,ce2d502,4e321add,b62f0faa) -,S(601cc630,47ce63d2,c1fbbc49,f3b2dbe5,6edbca09,17ac41e9,b39f7ac4,5cb3ff8,a773b9b6,d98c7b35,458e956f,f9cc71e0,8539b118,bc2529f0,fd496e54,efc2b25f) -,S(a31ffa07,e16fd36d,2edd7d1d,944ecdb8,2da2641e,cc6ccfe1,88219a67,5677a740,c2253d87,59ab43d7,c919710,9e9ecdae,df1f2d82,d34c5d82,d113958f,cbf1e3f) -,S(131060f1,ba302b06,b26360ad,de531db3,422a6bc9,6ca1e9e2,98b5da8a,c8266249,4dae16bd,40159bfc,96665d6a,d64c6c5,3ce90fe0,95a316a6,8cb84844,ec183cf9) -,S(f4a29fd7,90f35f1f,4b3240d6,c0cbb983,3e701a9b,ca241d3d,bb7630a6,da2de25a,b2ecd794,5afa51e0,1caf3c21,5334dd9e,9f9a1f6b,8f35767f,c63a3f00,69c01382) -,S(b30546b7,c5e45266,854b90ba,53afdab8,be115251,5ae22f1b,5e0c472b,a3b44042,f14a6b95,178fbb85,5aeb9cc3,a4e65560,3e8b18c1,4cc54cb4,1e059597,faad7f4) -,S(b6cbbb5,10ff83fb,c8bdd55f,cfafeae8,947f5e83,4cc78eef,dce45dee,2014e175,d0e29276,a14cfda6,f518a3fc,ac6a4163,13666f91,ce5ae7b9,7abfdff4,925cd415) -,S(fcaed74f,19199482,564ce4b0,7e1033ca,c17bd418,769981bb,6547caa3,b61bafd1,c52c08e,f5331ccc,271b108d,5e7794ee,4a493ce4,f6665773,f97902d6,ffcf40e0) -,S(c6d1ed83,29ade032,c9924945,189ff23a,c6b1befa,e4a33794,8b1b4126,6d14344d,6e1c0e9f,da231092,86d23cb3,2c588799,507368b8,8c0628de,b8a79c97,e4ba817f) -,S(ac7d0edb,a7b86cdb,60963277,cac43674,19dc5d85,ccd9a649,bd335dd5,eea2a9e2,61790bc0,ddf5307a,56fce870,4bc9eed6,9d61d857,f4d2fd34,d53a97f2,4c4c5206) -,S(fd9d0c61,d3dc3ff9,bc3735e2,b2c7d5d6,4a740b1a,bcd46a7a,860816f9,84a64645,701e082a,5e59460e,c3e3ca21,40137ed1,5bf9ef49,fb4673c7,4fa5e4ff,2ad8b762) -,S(82ce7d44,87101716,6ee31310,11bdf02b,336fe44c,88572c37,930a33ff,5bdcea1c,d7fdb097,3961ba18,b53b421b,21c0424b,7b4807ae,256d883e,2e3a6f22,9bc44c0b) -,S(5e507c80,bbd32e0b,efc31714,b464580e,f7ccd3a5,2004f2f1,9fb9b0f6,dad1a767,95facec8,a3b5c996,e0bc9d5f,77c11407,d0ee071b,9cf5af3d,ed625025,3aecc75b) -,S(640d6b4e,bde998b4,1bc86fbe,2e981683,a83789d,b71bca76,76715a29,143c9b55,61334a92,358ae235,104aca00,a632006b,769475a,da8789f4,f7047f75,c8b1123d) -,S(e951dbb6,96ceb16b,6059c3ec,9d84ae8b,8adb146f,fd79a323,59c04677,aff990e,d3443900,ea47be0e,10ea9178,3f1524f2,fe5c5720,efb62458,987dea0f,1612a94e) -,S(2b601b8a,550333aa,2a0e98c9,a4b28043,aa38f20b,13a72cb8,7a8cf212,cd0a2a92,2f3f309d,ff296fbb,a406602b,be72d9bb,c3ca0578,f5f0aa08,6e65ec0d,8989f670) -,S(d803b242,9814658d,df7cb378,bb9708ed,6ddd7270,ffb7d712,b64da007,158a5add,bffd353d,c4d664f8,6d7f150f,30e44ace,fef4abe3,83f30369,15b4d5d6,5ba3c131) -,S(d5a8348d,fbb9f9d5,798d7d1f,3515e25d,a2707869,26ae598d,500186d8,a284e86d,ce31c62,19960c61,f2a8a7bd,2fa36f0d,6ea7838,5463a4a2,9dc1ee95,2f37905) -,S(250dd67,781128de,65f0529a,11b2405b,eab01ee0,1e9bde06,cabcc9d3,cd038065,524aa9b5,8dc5c6e0,6951aa70,c4bfdffe,a2dae26c,1e8341a,5f63a180,731a0dcb) -,S(f3a2017,127dab2a,917dfaba,5eabb6da,bebe554,431e796f,a3b09771,66cd47ec,69d1de46,2e63beeb,1334fccd,ce147b96,23683942,21c4865c,d50fd687,5c1659c1) -,S(15626140,5aabf9f9,d7dfd218,3d7fe2c,900ee051,784537b8,deab8bcf,20c6e0e,863d8797,f2b20b0d,ca1a5b93,9a43a712,4d5f0725,8ae7caba,4b76d308,65f9a98b) -,S(3261fb49,2c55978b,20d2c5b2,3e6ac5d9,5e3b40a9,462b748c,62a41035,2efd227a,4072fb7e,3fafe456,8f62f4c9,83d0988f,f9096c14,317f7584,9fc1aed1,3e39708) -,S(2a5e6aaa,f5cd7466,b851802b,80305dff,3e655dd9,b0456bfc,fe704eb8,582836ac,2e3894d5,762e70d0,4d3595f8,83dbec7d,5125720,c516fcd,f361ab22,be67062d) -,S(e85a7e08,13294e2a,6eebb00d,2e3fdd76,318b7520,dc682705,8b3e923d,536cbcd7,5a936569,77b89e9f,10c4ba6b,7dcb1611,fb6a85fd,af0b1136,b19cf222,a2e9a477) -,S(8e36e66d,2f080ff2,a24ac836,25e50148,e5017b7d,b898820c,b7d73214,bc198b28,edf99b43,c2b976b1,6eda2a75,f8bf5aa8,6945d700,9965b528,bb78b530,3888c56d) -,S(99ead62e,11cc613f,2290332b,9d5ddb98,8c121ed5,21a0147,589bbfe7,db0f0c58,6e73b10d,bac646ab,44f3a062,4150da41,d666523f,ed55fdc1,c1146fd8,c4a262a7) -,S(15e233c4,783fced,39c74cb4,34e77491,83004e2,6e16c372,f6f7f23a,e30efb13,c9954660,eedf09c3,af8e1642,3b57af59,227ee5fc,e1885837,5ac5a853,34fc5034) -,S(3b33e0a1,254d310d,efbf526a,8a2314bf,18bb490f,e592e36f,6763b174,96f57a67,e4e6a395,a6e6c730,67fb2e0e,2c5dba63,9745daf8,bb9d6aab,e96f59d0,8eb24c83) -,S(8be3fe6,f3e45fda,270d54e6,49bdfa8c,1dbbecf6,35922aca,2d605c66,6933e859,10269847,15eddf7f,b7b23972,ed1f6fd6,882481f9,1a12eed7,f8fabad9,da0917c5) -,S(ae6863ae,e6d519be,773edc77,8e7bb5a7,5e0d30ca,91dd0920,aee35870,5bf6effc,d104a8c4,1939444a,1a5843e3,92fc5fa8,d2dd864c,1f442938,9dbdb543,415988b3) -,S(58a06c8c,658430fe,e03b3218,6ec051c1,18174f8b,ade2cfb4,a98cd9b8,13e12dc,17f4ba3,da575c84,81cdfc04,25567dd5,1d2b5e94,a8ed37cb,346f88fa,e6f3553c) -,S(cf0b0d64,3843e10f,142ff912,720373e7,2fd18576,1f3d6c71,52647afc,1ebae367,8ed9b909,f4b622d8,cf5d5b19,fa2e1cc4,bdb42133,c4dd9261,22f1aef4,6dac4c64) -,S(8be41872,15902e71,8f75558e,4b1a5ba7,9d3522d2,e8a2d723,f863c4d7,3c4713a9,f7be5a77,6b8ea8ee,1e59765,ecc6a33d,210eadbf,df4c5586,aba43710,49c715f3) -,S(1e6bfed2,36a10a7d,9efd88cf,af1dc1f1,9649197f,785b4a30,c68391ce,808f713b,90200be1,29c5235f,41a79bc7,2d4d10a9,b00911cf,b9f27b5c,6d47eba9,8530b8c8) -,S(97176463,8cee344b,1ebd8c67,17782c6a,86108b76,e1eb74a0,791527dd,b18e14b5,ccb128c5,2295ca09,626ccd39,b5827ffc,3168a628,6633843e,96184aed,d7bf898a) -,S(2fd20134,8e0b7259,415cc828,c3e4f79b,2184735c,86e534dd,77f1c5b9,9d8cbacb,41fc80ab,25ca1a82,67582a89,f901ac61,2237b942,9d724a2b,8cd0dcb6,c96564b2) -,S(5ba918f6,6bdb4013,481bee06,6aaafa88,f741c362,b5c3a4b,28dd4555,3c1aadd2,230f6c20,f39849af,9de4ff99,8e39ebcd,818d5d6d,8056ca67,8f04f33a,c4fafac5) -,S(69b5676d,b8e2a30a,8870c86c,4a859ba0,dee25a28,493909f0,9ac88af6,83b70797,4831db1,98c1b4dc,69942571,e4908ac7,41ec4568,e27089a4,682ee7c9,8ee905d2) -,S(faab5a9a,c530f7a3,343c71a4,273935bc,fb280258,24a63ce,8f8da6e2,a60135ab,1443a23e,793eb339,f4353371,34937bbe,9bda0eb8,c2fa2d50,bcd85757,68c79797) -,S(c70ef20,284cf135,7c437093,10451a9e,5ef10cbf,e3a0ebfd,b90f487b,8ca62d9,8970b394,35c29dc2,b8254d1c,9c4cdf54,6df52979,ca70ff8a,7dc171b0,5a176ce5) -,S(acb67abb,fa6dfd52,e9829767,182f5ea5,66dfaeab,42a2f2d9,aaa545e1,2e9cc68e,4a097150,2367b1eb,4f51f6c,a394d351,b734b30f,fb36dba0,9e53b4ea,3f6ebfce) -,S(2da4ea09,315e0f1b,f5b6e0c5,b8af330c,c27e26ef,54affcdb,fda834bc,cd578a3,a4097d6,ad006cca,53ea3391,10c80150,f63694be,c5ea7728,f77ebb83,2362a407) -,S(70cb8427,c2d5ee86,59b26055,3499374,63e7a482,6731ab85,6b3fd10b,be3dfdf,f44efbf9,a914063,3e8378c2,6e9676b8,351b6ddb,33f7e7db,5ced5208,e4cb7361) -,S(b14283ed,9a9db980,b135557d,97190066,60e4e1cd,3ab288b8,dccba9b1,67b24934,95fccfb3,827332be,a813457f,28a63a89,87dc8c5,340a8f88,76788a60,f03b2606) -,S(ca24774c,727efbb1,15bbbf12,20e59841,891dfd50,9f99744d,de815f5f,3e959555,2519e414,a9703de5,60f7412d,8949f509,bacecf3a,e672e7ac,58c5f98e,33162bb2) -,S(5a5c1b07,ddc79f18,26bb95e1,13e03894,bb63b593,c808f0a4,2bd44b36,dcd3765,a11bc328,2f672c9e,60846826,521add7,57b891b5,d4fde6c9,738c6329,dabf67b4) -,S(2caf2545,1daf272a,b169a4e9,b0eb9c0d,26888c18,ae7d8357,b8dd2b73,ee4cf7dc,bf8d8ea3,afc9d56d,9799083,c79f1289,7d20d7ed,48ba38a1,acb039b1,2292a3c5) -,S(af6650e3,4022d1a1,b66e8c3a,b0a8e9f3,baf44318,f6946a0d,d1c65aa1,e3f9c9ce,1b0222c1,a5f3691a,248154bc,bc9e5e9c,6b2c96c1,ca468feb,97a7c01f,2551bd5) -,S(3653e476,4215cd7f,83ff59e2,f63f2a7f,dafb8795,95006bd0,182e0e,78ca5b39,c91824ee,6ba3c685,2eeb2695,9a3b136b,371c9bac,4141344c,a1eb3051,8a6d8ab9) -,S(7826902b,cdd4e7b5,463452e1,baf88534,64723588,86643d49,cc89b482,298f6394,dd5bf1b6,91647ce2,86c745eb,6246d087,35cba4f,22c26a37,e326ed1c,4e3d968b) -,S(da19c301,4e77f987,abb00fda,8a5dc50f,d2777850,1fafec84,2ce7e5f6,37edd1da,757fb28b,366104a8,cbd26981,3697d8c7,821c6e0e,5acbb33f,9cbd5fed,25cce98a) -,S(efa31697,2a61cf86,df713186,c1bc61f7,63a618a0,8034c26c,462a2457,907436a,74f17527,e6c7aebb,ed6b28c6,26e612bf,82d61ad,cd1ca156,b971abfe,2efb15b0) -,S(379d460d,12fc351,4c46567a,ce05cc9e,ded3cc35,fb416bfb,76d14f3b,c5164f7e,f548ad44,a5c87313,aeb52885,5ac3a955,178c8992,2415837d,d3e7863d,685004fe) -,S(e3b66f05,ed217cb1,6e3f8ce3,56704f70,36b97104,e39c5649,83bc204c,5b112de4,8a2ee4f3,ab9c8cd4,40afe707,d8dc0fed,473db9c1,be2b6e7,b14de905,ba38ae2c) -,S(b14ebf0c,ccda021d,8db1fd20,a4108c48,750d10a7,e0659cca,64f3e6e,ee8c7a4d,c94ca9d4,d2ba47e4,576aaaad,c15f9019,f335ebc5,763cf232,f56f215d,ce42322c) -,S(1ffb2e29,df24e7a7,6a71f607,f4f03608,43d3715f,c3e468b9,92b684bf,1352cee1,27c39636,54ab505,4b008e5b,4598d025,ade823c3,df6aa7c8,18d4d4fd,32442990) -,S(63e13d75,38f1eb8b,7276ee28,acd56bf0,448f026c,f98c77fd,5f743c24,4872b70,845d65c0,a6cd8b30,7c7ea0c9,8024773,86a50daa,3f361539,57cf995a,43705cc4) -,S(169b95d5,417e6173,b4393c6f,1ace153c,21c83c7c,971418f1,27e1abf3,aaa04673,bcd1ca4e,5618a183,420b34d2,52d25dfa,e7cf699,3e936450,ffaae3d4,61a50c50) -,S(3dde4fce,54d27794,29b6f6a5,8c5315ff,ed682bc4,5601c623,948faa88,2309ed27,2b22dfb2,dc46f625,4f29f8a1,4cb4496a,dcef6806,26d4f499,a17c4751,4a1802a7) -,S(6b37e3b0,2422eccb,299e2b89,1a150be9,ef56a628,62c78c11,f3411614,9fd37802,a9c347b1,fa5105c5,a27ed367,261a1cb5,5d54a071,7a2927ed,29d45eca,6e958295) -,S(7bd6703,ef78de4d,f32f0d7a,274f6371,2d0b0a9b,fafc3f6f,5c03b654,599b443a,33d9b1b6,8254d47d,6aabb7b0,b66298d,8447d674,4612a2b1,f722a597,857fda25) -,S(2e9a4aa0,a2062c8a,63b18e5f,91a609de,b60ae126,93d7f1fa,757057e9,ce169b61,65a55523,e34dd131,3597b250,acd11763,62df6b07,1d3f0f1b,907fe0bf,46ff87ca) -,S(f90c1316,9524f407,8c7328a7,126c48f4,eadd6d65,8baccd1f,403a0b68,ff95e7e1,1d6a1b16,6f5b4f7,9f51b046,42306f53,bd84b7df,2a58457a,a8869,4111cb38) -,S(a7bf0bfa,8e84b448,9ee29801,a5d06f66,a17d2374,a6d91eea,2482354d,66c60074,e60ec871,7ea63cc0,e4785455,478848c0,363f6717,748ee9f0,1c928370,df0905cf) -,S(dc4ac1a8,372c06fb,ea7a44cd,11a352e6,fd204df6,f6868cb,5230e420,9ab36e6b,f3a1b986,c86134c7,40c0ac9f,8f2780,82a103aa,e9e4269,84516e09,659f668f) -,S(538086b2,aba47aa4,dae137a4,4bc747ce,9bb225c0,6aa015db,e9478da5,e2c9cdb3,42ed59f0,fb831257,84b15d27,b9086eff,9aec4d8b,9ac36f87,10f93bbb,2ce7d971) -,S(92eaffc8,955f3f06,fca49a8b,881734e8,6750b34a,d253f160,183388af,f18b8106,fdb45519,36f9e291,9e2e2e6f,7e5d2dfe,16e14da8,b5704a27,60e92d9b,13758767) -,S(63fda46a,4350fdea,fba277c6,190c5f37,c4cf7c88,ab1b2ba5,7b0ce9ec,60249c46,b64fd169,403a2687,f5f41038,91e811f,6dbb344f,2c3a1492,fc408f74,433c65e) -,S(f9f7568f,d2e444a8,14b03934,72564798,5c16424c,1ea6fa80,79f96df2,ff3c73d2,8ae3a292,fbef875d,ca18fd89,8e1e882c,ef7bc222,64140183,1cc2d268,ae795a14) -,S(43a5ef22,93462849,ecbf95d,3c92eb63,ea89a39d,2e0a5da1,eb261c1f,2e8e4bdd,896699cd,e580ef97,64ef1860,19317dd,f7c17ccc,34d340dd,b23621fd,5e5ea5aa) -,S(1fc26dd2,9a3ad966,4206f233,82e54363,6ec9d95e,a58e7af8,a4bc8aa4,736c155d,5f6c4cd9,c6f954f3,f0f3bc54,8bfc4a58,faec99d5,9f3466c0,bcc09053,346bab63) -,S(9a63cdf2,84ee5189,34b73c8f,d8b3932a,50ff88f4,8ecf9b40,c0056c7e,168956b3,e52e7902,6a8d4e95,c7f473e3,84b9966e,16347c60,8b6fb6c8,484335c1,2872f4ad) -,S(aabebcd6,8050337b,1e6caa45,13d279cc,ddc4c218,f849afff,8c1302f7,6b728bb5,808fc6b3,90c2f001,bff1993,346a55b3,663378d6,e457c639,b9a73f87,78ee8d09) -,S(9fd45b70,59cd26ff,2188167,ecdb5ad7,62efbcf2,b668830b,475df22a,bf526239,6fa79fa0,e76536af,92eeace7,77c1b735,19092fd4,870ead71,35634768,700a1241) -,S(ebb3ab2d,e71844f5,b6ff8baf,637cc0f1,1004611a,e8a3b570,1afeebb,a7a4edd4,30eed3cb,55a23613,3bec9aec,b620f1fb,1f39a067,8a44622e,84b9e271,62294133) -,S(a0e7ea2e,33c6a3eb,423138d,8faa7ae1,d7802a73,507d48c1,bb38bcf9,29838ca,31158fe7,ad132036,62449ed9,76c4aa17,67382a8a,cd42c842,ed22badc,882d7d26) -,S(a19abdde,db579ade,1dba9264,9d58b15f,1bf3b87c,eae44520,2ae758ad,f2164fa0,508d24fe,f53d8f4c,77e43ef8,eabecf3a,ddd04eeb,acfbecc9,637b6c07,fbe88084) -,S(e86ea1ab,95e23d10,f086c91f,289e2f80,d10ea0bc,aa9d8f3,1873158d,19166976,4b6bc016,6d95e08a,72c4dac7,9eeb405f,938346d2,ae45ea0f,ab76ba98,8c4e910a) -,S(aad23857,d8d835f8,e3785020,6b1cf1f1,efd9c9b6,ea15d42c,70444ed8,81710ca1,a550855c,381bca50,44be47c1,42d52259,af2f486f,622699a6,aec28138,554cf06f) -,S(b5c04c3b,436fe2ac,97bf2043,3ba57e9b,897816bc,eb8383be,ab11d488,e231a138,b1ee4b56,1965ab9a,9fa87112,57a250a2,d7f06de,7759918d,85c69d66,5546a6c0) -,S(eccf5dee,9b6e3fe3,1e3c02da,a2d5c408,72766edc,29da88b0,cdb01f4f,524b0ad9,7770c7e5,d97ca3f8,cdda858f,ed5976f7,cf2bdcc6,60459a64,daa495e9,28f4cc37) -,S(4c34b06f,6d02467c,9e667ceb,630d9865,4540b18b,8832292a,17e74d9a,d0cabc6f,57671dd,326be6d0,2ada8789,b5f27c7,b052c8c7,d300b2b3,ef881a24,53bcb6eb) -,S(9493f9c3,98a50b50,4db602ed,ef50cfce,5bcc9f0a,bcf80ffd,d5f65d1b,d030ca31,fb45d7d3,fc1216ac,6b948369,42d33e82,932af020,fd7c29f0,f2959eef,a41dcb30) -,S(b0ca3c54,153d435,b9d6427a,20ac3456,ab980b67,ee92c6f7,605aa934,faee0bbc,2e2a47e6,8b959402,1ed83edb,d4968c6a,2eb4be8e,2cf128e3,a3778751,20f27b16) -,S(d5632117,2e9b97eb,4b282d8e,1e303cbc,d50656df,2a99c9fa,bad35909,1888ee8b,30157215,efad51b8,20c03f8,2e4c9c93,11d15bc8,3dc75bea,e44e1e52,7f1ced7) -,S(3a0f593b,69396a6f,62655efd,97c103db,5e209554,8d45de93,8963cbc0,dbb9b4b4,66ba5298,590d027b,30dcd9cc,e4605e4a,73adf43c,6e377bcc,cd19eb92,e20e267c) -,S(10eb3c4c,cccd5ca,e15bcc7b,92d108a6,de762cec,b71bd78e,1917752f,b3f6cf86,6d65809c,79395f45,153d7650,74597eb7,edff81bb,598ed20b,f9780e45,bd91d077) -,S(40ae7e81,e33791bd,154945a5,105be36f,57477fdd,d36f83f9,d31fb73c,862e70f9,71511daf,e9cde10a,7e4ff05b,948a0454,e5fcd355,d98b2bf5,8ed3ca54,1a568498) -,S(994dac9f,3c047519,823c007c,57851a8d,41be0480,7c6ba5bb,88e19869,261fd12f,913e96eb,bcef4fe7,60469aed,51e9dbd8,4910d606,9646255c,9cb3bb7d,55b1e342) -,S(f0d9a17d,112e91df,63c106a0,5df3cf41,6471b817,a3ede631,d845b604,3c04d0a5,3ab43cb6,cefaa228,5c84a42a,8f1f41b5,631bab61,1d006946,f06be576,bc817f18) -,S(20919d38,ef12de1a,64992396,f7b265e6,2ab8267c,bb988d1a,6771d8e,724d16e5,81f79a2d,b629ce97,47f146d6,b16cdfd7,90fccd71,c46cf9f7,fe526e58,8ed1eafd) -,S(b92087f7,43494d53,71978b1d,63e11ae8,a1595239,33b87a44,704ca3d5,30f1b02e,6eef6ac2,49a8550a,135072c2,9bb42afe,5d27c8f7,fec88aee,6274d27,36dc0eb) -,S(f69dedef,a8894583,c05b1fd1,ae205fba,3ba11a37,ca628150,d287f01b,b6920b34,a9f88097,66d18287,9d97e01,5544c7ab,ca0cf8fc,c5b9f305,ed0bd9e5,58fa5b3d) -,S(8bd8b3c9,a301a76,9f5607a3,e116edab,9d87bf79,e4099d62,a328c1c5,f8b8b6a2,167117ec,ce6e15da,47a076c7,afd851a0,cb5dd1c3,d8187f4a,9aa5abca,cc0af771) -,S(d7e2bc76,e2a87357,82611,2619513c,10a2eff8,857fe6fe,a2e2c00,c6f8ef4f,85e1891f,531481a5,e935e80c,448d8da7,32f1d061,dd234e39,d55c58ee,df8cb93b) -,S(2701bed3,778a857e,c7a9095e,6487e92c,555ecc9,32ad8e0f,b1b59d70,4131768c,9e38370a,8d30d5d6,6aac5302,efc7496b,cd5734a2,20d2e76e,fae3c72c,a793d991) -,S(3662a916,a05a80a9,13bfc287,c81cf28b,7295dd1f,aa52badf,5ea1c83f,e1b90521,b14bfdf0,a33c9286,eac83a4c,b982f5ae,82e2e134,99bcb3de,3ac930e,2ed0c931) -,S(d778d74e,317063ff,6556388e,2d2ac429,410337a,d62917,a94b7654,6a04787e,f7d92bac,c92600b4,e8184960,11f135fd,adef70da,b72c1bb,9da26bcf,7a81f0b7) -,S(7b05001e,388f9197,ff3504fd,402a5291,d1257621,c8eb202b,dba87b56,154b6f8c,8c9c1c9b,5c151be,39f2875d,b31797ba,2899047b,6e5c491a,56f7fd28,1b897f2f) -,S(603546d0,1fe46be0,eaa9f00f,c99b2a6f,c38fc225,6553bef4,9ff47442,ffa7626c,1f86de50,aa457ed,ea306251,91cc3cd5,61cbd8f3,2b41145f,139110f0,64b73b74) -,S(80f9318a,ca3b7aca,65cb1965,a36981d0,86ba3b32,8a95cfd2,9c6bb718,1f662c25,c195025d,794abeff,49c9b1f6,724f72ca,70b0bada,d06ae11f,2101b49d,d592ae18) -,S(61182e02,a877565b,1209dce1,bc84c62,f3b1007c,48332c56,6dd6e697,664cf64f,d21f9259,517656d1,3efe7166,750c341b,6c064b0,542bac29,28424a30,ce4b51cd) -,S(21cd4f22,ec3a190c,77073680,58562d82,36d463c,f7706f10,fbebd283,c19378ff,2e04af2b,155beea,daace708,c510555b,467727fd,145426bd,680d1964,fc1b03b) -,S(2d3f6c78,94479443,6004ac92,554a507c,5a20ffd6,f275f715,b176b3b5,3d2000b0,72e0e16f,9d9ceaa,2ffc5a1a,71a2cee0,eea64e44,7f716eec,1fc417be,ba16d92f) -,S(a9f45433,c040d1ac,6bd36d33,5b655fd8,eec0d3a0,bf1a622b,df422039,239de17b,264ed6a,8da4a169,a66869a0,a846229e,81d52517,22fa4c2a,4c775322,f33b1184) -,S(16e052be,bb65657c,309d67e5,b68ea441,4179ace2,38315c8f,df88626e,84281ce,91c007f,fcd4633e,597ee06e,b28296bf,2837f30,8cb21be5,9bdbd52c,4ae0422a) -,S(ff6d96b6,f633beea,1de80512,73c06bbe,181a1098,db737c8,41a48d44,cfab935a,cd9a8011,c22b643a,90f1d9c7,54b7330f,1c1970fe,5ac04225,c2720054,fa6a8444) -,S(dc2e3b1b,a2619ea0,6e4ddc09,99630c4a,7b94c78e,ed13517,25b8b8da,137fa467,f97e82ad,49bb4389,84cd752e,820aac43,bc6cccc3,f9b0d9eb,c2337bdd,89cb83c9) -,S(d53b97c5,8e23d50a,3b855c43,80a992c9,2d667afa,bba4b028,20031f58,dd6947c9,24a54f43,bb9a04c0,8b93aa96,9dc61f92,e705ab75,e644a3c4,40391af0,ad375ec7) -,S(b598a510,beb9cbc1,c4e03f8c,1ff610e0,7123ddc6,ad69dd6e,f9fa7810,f79c8ab3,b895b8f7,68a80a37,77d8b5bd,46754473,c9590768,a56fd586,58ce97a,366dcdbd) -,S(cc2296b9,ee9726c,17b0cc6c,745a038e,38b5535,5e19fc49,e89f4ec3,372b2a05,6a466fd2,f9a5c412,9f5b2faf,aaef4cf2,be71406,590ae031,d68c482c,86e3f89f) -,S(3e84c76e,254c858d,51cd4e74,72c22ec8,364ce28c,de81ddbf,b7b3093f,44acf9b3,ce8ae6f5,f56814dd,21186370,f70196d1,339c264b,c78a502e,bd57e771,b438c81c) -,S(976f67c8,c626f8de,9de43f8b,39585d7f,d4cb35c6,e4211b00,68669ca9,a973a3db,ae4f1f6d,25af4ccc,3eca4b2f,6cda0cad,dcc28f78,c8e881c4,eaca9131,2f0b057) -,S(b28bc958,aed50ba7,6d5293f9,7c419828,53bec43c,21ef0f96,9000fa47,49ee95e3,e7d4cc8f,f68182a2,15dee707,4df2c351,906d5527,c47e6414,54e97c1c,b57525b2) -,S(e54dd5d2,16bc5903,9a630bba,7cccf5e6,81a3113e,be8fb57f,83c51209,965cddb2,86352dbf,5f2b2327,ca50458,b3b2cdd1,8d403629,a2e2a776,5562240,7e8407db) -,S(58379e1a,10115a0,8f2b93a2,3f2f4e2,2787aaec,cf129910,b1911b43,c209f379,a526d32c,abd99175,e63b4493,7a0dc96e,e0feb99c,bbe00c91,1e606537,c871c6c2) -,S(7858a68a,cb34cfd3,e1cb7d06,4d233322,ceefa6a7,a2de391f,991b94b4,da9ebd63,f54490f5,ede73b49,946ffe19,d5ae6f7f,ca026c07,b1dc0138,b1409383,5d792db0) -,S(3c8c636e,d20d58c2,f03c26ac,bbbfed70,3fd13304,74bdf2ea,7526f16b,4fe6f7f7,550069d1,cec630e8,6d22af01,5981f20c,ffdfabdd,6416bb00,f2dd8c6a,44401759) -,S(d03fc7ec,eb716cbd,f033d76e,8db97314,858674db,48ede8dc,1a1c7dd0,82ae7f93,16f7a717,a197fede,dadc25b5,a20b0486,1cfaa63e,3157e5ce,ff0c81d5,bba296d) -,S(6d6c983e,d60601d4,ae5ef4ab,c73914c9,b9546964,a6a3d2a5,681b09cd,afee2c22,13f5af59,61877fb9,2a2ac09a,eb691a88,20ca8361,81359fa3,96558ad7,b2276b1b) -,S(92a9f5d2,149065eb,1241d82,fd06ac2e,f1f48003,3bffb06b,ae3a9d88,a1d05f8d,f0be5964,75545835,f64b0985,1baad682,b84d7a39,91ea0f49,1d19b7ad,77ad75d) -,S(222aac7d,c2fe0066,b766e1fd,179c1912,5f289e98,33cce93c,749afe38,ce0aa74a,bd6c4d8,43e5923,b5944e40,8d309733,dc0cd9c8,b266dd8c,2df162de,fde5bf5b) -,S(28b14628,3a7e1785,1c9d1831,6c9ca17e,56a13c25,7877ca3f,49ab2369,ba2898f1,292856f9,572ecc,5f000e0b,1e7ebdc2,3ec72619,3c97542e,8ccb10cf,d608eac7) -,S(5031a6da,df8d12ff,9eb19209,b844b008,dcc26de,c4a6f9f1,bbaa45c9,daf909a6,ef31dc6e,3cb5c39c,64011c0c,89cddb04,7ef9a881,a0d718b,5057bdfa,3f5e1ffa) -,S(925835ee,ce55e98f,130008fd,a6f01768,aee2de4a,f96f239a,430d408d,95a627c3,cac1b7d7,60362e24,f3b5f277,e370ba70,f0f8c6dc,a338c15c,46c5fb4d,f9f1bba7) -,S(6b7253e6,9dd65781,8214fa04,67f59e92,a4671648,c465ea4,9c993bf3,de8d9e77,50a9cbd6,b429c3d7,32bc3b68,ec581327,1c2b0a4d,2d8587bc,7b26ee15,ee7e92bd) -,S(f82d660d,cd5df408,714213aa,a7406a3c,868a8d05,1fe37689,baa6fbc3,effb3e33,affe0a1a,b7bf498c,83b331fa,f3e7b723,2a2dbc66,3b93da28,e12f0d56,260677a1) -,S(990954a5,5342c5a8,db3fef46,da2b31ba,32b6d597,c67c8290,9329a90,c39845fc,d764f091,40891e20,a2130696,216049d0,b3eb1af5,7dcb9797,4c42abc,5298977b) -,S(d6b8e341,f8bad7e6,ff434dce,fcae81a4,1946f237,e0467120,fd420,f3dafc0b,a8ba941e,81677d32,140666f3,55fc28fa,7233ec8f,8fd13703,214bdf8f,340c389d) -,S(fabf5120,8632ee4c,81ad6d34,cc84de68,728197b0,fcf07971,326d4c04,7017b905,79c781e4,aa7dedda,4663b8db,7fff3cad,f9752cf7,ef2382e4,b0254489,7c6c04b2) -,S(e62db266,d9b208b1,83016754,c871a8d7,4b6848de,e496ee7,e2c1447c,2029b0d5,ef7410f4,f44d7414,53b9c1c6,8e5689bf,37cfecf2,1602e95f,3fe053dd,aea24f77) -,S(4bd90928,14753ea0,1025ea2b,86ae2310,5b581b48,98359481,d1b7d36e,d9c6e478,2f12e4b7,b825c858,5362afc0,d0029880,45fd638d,65f1865c,6ffb31ce,424baa50) -,S(3e397cfb,cc5c9fa1,15519366,c6e814ec,4b0ed9a5,dd093321,219e4028,28126ed,31c352e4,d4bef7cd,8929d3f0,aeecf9b,1d577ef0,e8086a28,40d46966,c1165dd) -,S(24bee951,54baf31c,f5322941,ffc01fda,9e89f80f,2662f5b4,edb751b6,5b372ee8,9568a4f3,a34ce5c9,8f591550,b75f2a84,be5cf67f,1fd7713c,c126f46e,1c3b6883) -,S(d242bb09,e4c6cc42,a2bdcdc6,bad2a02,8e4bfa21,430acb16,3f0e8a70,2ad2f0d7,2eede9ec,799b9e5a,13c40c4e,4cf6dc0f,9640d472,2a78cc6c,d920b610,d070b913) -,S(a57b5fd8,f50de3c5,98073cef,bc6fa56d,20dbacc0,72dbbf81,347bf0e8,7a36ebef,a99f123f,a45b1369,32394f8c,1f7ea2b3,563ca2ba,9c0da00d,b2c9c119,e6f20287) -,S(82a43e2c,a533abf0,6aab1199,fdd20f9e,1616a79b,859c6467,ffca4b27,989da9e,19cd40f5,8c997e78,311e5ba0,c0b3328a,b845da97,91dc8ef,a6cf7e5d,efd51c6a) -,S(95bf3b4d,b8ef8bab,16e00f5e,7dbe9907,b54c98f9,2331c4fe,688129a5,5cd021c9,2b4c46e5,b9d9f915,d5d020a3,3c63fe49,eeb32931,9373bf9b,e359c40a,19328c47) -,S(791ea768,4d333125,893356ed,dd8ebe4b,3f98ae58,e25a2d1,67006a4b,5c05799,5f72cf68,7827ce2,6bebd598,539f6519,a50788c,9d093766,9c3b9c29,f52d5422) -,S(85138ec5,a5d3f0a7,881ce23f,e34fbb80,fc3038e,bb7c2a24,ccfeb2ae,5ef07b74,8eb9e80d,8664b11b,d24753f2,bba612bf,c06bf9f2,a4bd061e,82ce9037,895b084d) -,S(3b4c1149,1d98483,9ff33b31,39da0341,f430175a,d5800c80,37e35dfc,a68ec256,574d6475,e225aeea,dace647a,1489b2ea,873175ea,83cff3f2,fec684b3,fd2ad143) -,S(2ea17f9c,6a028f58,396474bc,8c51b1e3,cb9ac0c6,7f73f533,a428281d,4101b04a,19d1f021,8b8cc0c1,bbfb8925,77087caf,ebed3409,69dc2281,3a1dd6eb,9d6c44a8) -,S(67839592,2fcc7ffb,627486db,e1d98a45,25ee1338,5a98c01d,6b3b9f8d,f64c507a,e13ed82a,a1adf761,7cce3760,d049a72c,7572508a,5ecd0615,1bbb589f,17e10a7a) -,S(54a0d2ed,39778fc1,237ab423,1e4384e6,4156c1a7,d5e999fb,2c92ba42,ef40ee68,3d879ff8,c25ed54d,df848e5c,49e3eeda,e8eccf33,afcb1c1f,67440810,8b3e979f) -,S(263ff1ed,726d0ff3,8b47b398,c713455a,3030d499,3a77ffac,b9cde4a2,cd12f7f3,a5f3fb33,c739bc93,c442508b,ac70884f,d90c3699,34fd698d,bc27f7b0,ca48a0ac) -,S(43b2fae4,a431beba,598b3ccf,caa1e034,91e7099f,c19508fb,8e693de6,dac9e3ac,3e43aac3,379c321a,5313b412,7cd00a1,bd8cd177,49c4240e,7cef1e97,22daf69c) -,S(a73e77a8,5733a296,2da7fe71,f4c16166,cf0acdc8,2d5288e1,8cb9479a,2a31f362,12b393ee,e323fd52,e44a9ab4,3e19256a,f7a8c892,76e9e6c,9052f0c5,3ecbc031) -,S(f007a9f2,bd3d0d4a,8cb9524e,a5aae499,6b2d0c1a,19aaa56d,4038a21c,6dabdd86,517a6a7b,3b75b68,bb04bdbd,d6f93414,c97b4b75,47b8fe22,c5828d6,7e979702) -,S(bc64853f,111371d0,8381c082,c72d2528,823e18b9,99de4303,c85a5fb8,87250833,51e7dc7,23256176,62a9f6f2,70bde4c7,94020e61,9e8dd87f,3f266d99,71596146) -,S(144dc699,a063c473,4b9bfd22,845317da,c4b55e92,a232b92f,965967b9,9c8e21df,a20a7982,7d57de38,85e573d1,6d22025b,648b9ed4,c656c48,bd6f4902,2b67c681) -,S(834ed659,98d49650,c3f525a1,b34ec725,89d167f7,a3cc6e86,8e4cdce3,b2ba3179,6bc2b06,c97a108b,2abf4033,152065f5,24c1bf1a,e79adbd,b7eeec17,9e598cbd) -,S(efce9278,6052c989,adc9595d,cd1500c9,8e93eaa,dafe2b87,2011bf55,3488b1a6,48ca33d4,cc89b486,c0930829,91f23147,d910f29c,c9d13787,7bebf55e,a3dc92ab) -,S(5b150240,c3563354,39adc9fd,23e9f94c,369a6cf9,27f45bc0,f0110cc1,b7321f4c,629b62e3,1a85fb44,b448c7e8,e76ec423,b059c9a,c8144c64,9d77a4da,eb044aa0) -,S(cec8cb02,3f166bd6,9fe04f66,8ef6e949,f4e3d26b,d748c30f,53a9b9f0,9ef3f9dd,997f9fdf,dee5cd89,352e6c38,760c4cd0,a7bb2696,94916567,ae60fc5f,39b908ca) -,S(58427cc8,edc5e616,3726519c,7522980c,30443eef,7e72cdbf,b135ede1,f15c0890,d2fe9c00,7eeb0be0,8295e972,e69db2e6,a54193d3,ec9a3ea9,f2515e59,6e34e88) -,S(a7d0a30c,1787b9f5,8ebff502,e4e38000,6bf896a,2feaefa4,4670dee,6030bee1,774eabaa,863fd4f1,63b3a16e,4c17078a,fd0a1761,b39ab05c,3c6b1d36,5e487592) -,S(9d70eeed,55ed86a1,ba17e817,4c400cb8,ab0e5da7,b568ca81,60b585df,d1a84e74,f4c1fde7,f11b329e,f3c3e196,bd78a3ce,5387662b,859f99c7,d61f7962,2d01b5f2) -,S(e0715fee,9639817b,8501de6d,6561e623,628de7ff,d0dbab5f,bf58ee4b,a365f684,e34ba5d,acb60318,c6ccc001,871800cd,98ba2c5d,529a42a2,fd145336,7b10c22c) -,S(594612b2,4cb1912f,fb945465,1036bfb2,79be0bbd,e718ca26,973552b6,93d20143,d68338a0,d03fd0c5,e6c6e3dc,7070c78,72eef1c8,cc2154db,cbdad699,b594b142) -,S(f4f41087,1dbd5394,5fde2583,b08ba65c,6729dc05,b32ec3ac,c8aadb72,a6c0d8,8e948ba3,853102b2,99f2f558,ffc66181,310bc676,4b82dd7e,85fd075d,70d92fbb) -,S(efca7b38,69f2981c,406cfa40,2bbdd00f,15ba56cf,c6e9f66,9bdfa14e,aa9b1d21,458fd928,a07fa32f,d6a0ffd6,64a16b21,2bdad00f,a4534093,209b0c92,f507f9b9) -,S(25b2384e,d9e09e70,8098971f,153ada48,f3f4a9ae,fb946225,77d213c1,e7b326cd,ef50fa0b,4cd30cdf,2667bb4f,7dff0287,df666dfe,7d5bdb9c,ab567af4,b77c7535) -,S(ed12b20f,aa2ac5de,db62c17,2bc67cdc,f0534a33,6a32e26d,b325321b,81901268,9245a6b1,35df02d9,3db1224b,1a0a296b,a39f07ac,ce7ccee8,eda552b9,748eca9a) -,S(5dfa472b,b84ada50,da3ede14,8bca4f0d,aa885d2c,61633336,b2a8a37c,76b200b0,f314a5d8,2d20fd30,ee237487,7a922a54,f4c10468,656a5432,974cc3db,c2c7fbb7) -,S(a9e5c0d6,5b6d4b4d,b242d87f,57c805a0,5b7f243a,515c5d34,a037ddc6,afcc4470,d90fa599,de5fc8d9,87a42c57,f3bf9dac,d5b766a,fdfa07db,4c56c0d,3d71324f) -,S(4e9ccc2,c0e3169e,e25a6701,a82e7f02,2663d3cf,585100c8,2c6b5da4,d8c42e8c,854aa160,d48d241d,f5bdd1da,2c74d1f9,a00fad7,effa29fa,5ecedc42,3ba43484) -,S(2122c569,da05f145,48d42f9c,5ce3a96b,bbcb49fd,fc5b2dbe,1a7ab0ea,84aec76d,40796418,39879018,93bac618,8a7286a8,f8745709,58a40cd6,1202ac,dba5867b) -,S(aa8cceb3,415df249,b5069899,75a853fd,eb409729,331b1807,ca2242e2,a75c6968,5362b581,fb676eb9,9f125fd,5f674be4,800d89f0,133a1363,f1cb30ec,1fa5b468) -,S(beaea0f0,1fd8e442,50648032,530e41cd,7e3c8271,f4b83b4f,7493039b,b21013aa,e21f7d1,53e5d411,794fb472,47897cc6,a86396f6,3f6291bb,fe2f0f12,a263873f) -,S(8eaa225e,63bb92b9,666bb318,22c166e0,3843ff47,482cec9a,69ff584e,d1a750a6,aa26b32,e69c5d94,19663e05,6c9f7a60,1274aec8,a839ff1b,b5a43c2e,136ffd64) -,S(bcba926,40d8b4cf,8d73c0e3,7867f5dd,81eef91,70e904e0,15f05f3e,1bf6591c,8913cf87,e33aae4c,a16b1391,75d60106,ac7d05f4,a8f10db2,b0569a6d,ec121260) -,S(2d03aaf,6828d0c5,9ffadaa7,5d1b7e95,b3c4a547,46faa5c7,c428fe45,1a9f3332,68468e2d,597e7534,37b3865b,3c968e4f,e3f6b1fa,996e6b4d,296a12c3,20e61cf2) -,S(b39b4de5,be757b36,b1e88773,47cdaebf,11f8d6b8,ab59d780,fbaf2263,a823b5b9,1b609d2,de73faa,d613c4dc,6ac3c2e0,33d62b22,7ca3fcfe,4aca992f,eef90b0e) -,S(eabf705f,b6996148,170b23,9fb8998e,df6214a2,cac27fe2,9c66a899,63d2f0f0,e1867fd2,98603f79,d17876f4,7aea4437,cb39ee7c,bdafbf0c,5452b024,86182d17) -,S(a4ce885a,ebe9335c,6ef43c6f,395e1644,201f578a,4caa7f74,65c12542,27f1bc80,bde32eef,f7fdc498,1c50942c,efb38cf3,c3f1a8a7,5addfe7c,f11723e,f57d0c41) -,S(db8ee69,b0e00ff7,6a094251,a53c61f2,e00dc65e,a11e00e5,553ae121,ea958361,24e7ba71,22742e09,728108ac,59c5f46,aba40d1d,c308edd2,9d494f39,d156b2d) -,S(88a5b43a,d6cdc2b5,aa3d58db,9a9a2e1a,6d70afa,808efa87,1d7f3cbc,509cf064,88483c55,e5bc8717,8114605c,1febc726,e14345d4,4211b670,6b6185d8,ea6b7103) -,S(e3cb24cd,2130716f,10a4d432,d4e59229,2e11a2f5,3190bffd,4f478da2,216b0051,df432db5,caabb417,f8252d37,dd23e117,38066c87,101cd934,73a2883a,1b7e8de0) -,S(d9c88471,97f04254,731794ec,e29ba74,f1d72f19,8f424beb,8309e1ad,e09e1301,12037266,331f04b6,db4264df,ae6d934e,5f753828,35a646f5,cfa4ae8b,e6defdc1) -,S(80bb740c,3510574d,10afa586,a6e541fe,b5368797,231d2a63,67d2890,8877dc58,24ff9389,bb268f42,b04f1702,f7b7c6c1,7194c7bc,c5f4f63,bbcd4ca8,ef476fca) -,S(4b8b08fc,400d6fae,da05cb19,65c9c785,8f93452e,d1be8f29,28c83e6b,4d2b06a1,70a6612,2549ec2f,6cde4a4a,9ae8a528,1b05081f,8eefa8cc,1111271a,1beea7ae) -,S(d2708078,4d19552b,13ec8473,1eafd2fb,bc0ae927,dd746a8c,be1dfced,d072ddc8,9362bac1,806dfc84,e736758f,22f1039d,57a5e44c,40586195,885abb78,f75d3355) -,S(7345d1a2,7b9dc922,f51a0466,57721451,cea5b54f,6673a484,7a210b4c,339d1f18,293053e8,c180ee0e,d81bc4fd,658fcd5b,99bad329,9e62aedb,74867df2,3ac12d98) -,S(3b3a6baf,b9003f37,ca27889b,a2be2a02,748ba52f,6c6dc719,afcacf2d,578b1e24,a9749973,c49ebecc,501f9b18,83056505,6c88c286,2747496b,951892c6,8a61ffcb) -,S(b2d1a3e9,15b02709,1abb5ba7,206ad2c,5d07079f,8d4c7fae,3e6837be,34159226,90007202,78d4188e,b8efc45e,8306ab47,be1c6a16,d88284dd,fb627b1d,92959898) -,S(298019e5,5de972ae,fd0b4c94,9a9d4eb,46689fa0,9b849947,bbe27805,4a3f4a5d,5b7a4298,be50ee99,363b5f9a,1ef103fe,4fec0034,fd8a2364,5cc76f8,ff804f0) -,S(604f1e62,7f503661,5b55fe74,4540df91,67fe575,e0aafe13,8af68214,f1080eb0,2ade0355,b373ddce,2353669e,6af5575,cc6b01ae,58b2a581,2b63f36b,58effd5d) -,S(ddcbadcf,63ffbfce,326db7e9,2df0d483,9a35df32,fc576070,9f2422f2,6e07b8be,7a3bf369,dc3a5ae0,c91cea62,1429ad45,76f7110,b654a1f0,edda9b57,3076306e) -,S(160a19ff,10c8b334,7683b21a,880226da,81d536de,d9dcd357,d4f2283,18853837,91dd522c,f6d1d276,e88287a5,a37afefc,ba010111,82b93eee,1483cf56,e6cf5218) -,S(bc1210ff,d75737ab,51300e3e,ea48a264,5f363793,1f4c6f95,e8507034,84834819,8acc70b,363e52ee,779e6342,ea7dcb7c,d7d09946,5b0eec60,e35ea360,e8baa7f4) -,S(c2da24ff,f2c5419c,3d2ab241,e55cbfff,5f41b9ae,4efaa105,abcc173,a81fa1ec,3fed4d9a,4eabf3bf,6b913bd9,279761f1,4aa630c,e278d0d8,4bc82ac7,af77481) -,S(73a495ab,b26d4be1,bd99935f,f5583f6c,f5c86d79,fc86a4ed,48f87f40,2f12259b,f4126c3b,3e9b8dc7,ead63ddb,5749fe5e,6cb0bb3e,3c85426b,950326ef,9092301a) -,S(599baa65,fdf949f0,f54c44bd,ff605ef6,2f53d68a,f0e44bf8,274f0b73,ce251227,297ec5da,e3893363,617f5448,b13237a1,91fb5a20,e52ee897,a124daff,9f1eaa9c) -,S(9a032a50,6786e1fb,bd9ecd25,243ea67d,57f9e4bf,d1083879,e309690c,fb07f253,a073c6cd,15445d6d,80c51af2,4e7f540d,f1b75fa0,89a4849a,ea14ea09,ededdb0a) -,S(792160b3,eda1d493,48ea96d6,857d8631,ed1e198c,c7f185d6,b9d2c75,2b1cae63,d12d76d8,bd73a681,9bc581e,cdb84efa,dd143704,5554984f,8f1132c5,fe1bc32f) -,S(8fc4cc45,9639aec0,2c337f16,589c09a7,e787dffb,69ba2907,37b6c465,db9f12d8,b2ce3c2,57ccb79a,b677a9d8,49ce1833,2a97fca7,28bf3e83,6dbefd23,5343571a) -,S(fc06a9a,5857b2e6,df0c3be8,b5840946,ca77f690,4ba114be,44e760e,267eeda5,6662078e,f0de0e94,5a770654,b8281a74,f82168c4,49455250,136dadf6,87c5bd2a) -,S(345da4f,e1e89eb,eb27b353,4352c5a8,32d3c9ee,456c01e4,657c2885,733b5f69,3db274c6,b89e7400,cec4e2a9,9995ece7,be8b98da,39a2fa48,bbec96a4,5c758be0) -,S(309850db,36d8c2b4,610cf8f3,e1c12431,3931aebe,1a9d2099,cb3bc7b6,fbd8b0d8,edb3a9bc,f6417672,af9b1379,9bd8aab2,f953391b,27cdf167,320005d2,3fb3e4d1) -,S(8a35d7fd,8c7c75f4,e22ba36d,d84533cb,f314a54a,2e17a43f,d250c941,5025b0aa,97ae015f,fe364a2b,6c12cc42,fe526eea,7250092f,79c40b94,ab7102c6,fde1fa5a) -,S(982d9d66,dbe6b738,2cf2820f,c72ed491,d6a61add,f1eff091,de30fcb4,96ca4161,b4a7b42,2e9cd74b,10cde7a8,12b4d88,f3621324,acdcc911,b39d0952,3cb3b501) -,S(1396bea9,57d47670,735ed20d,e2ecaf6b,afe7e067,5f2a0f65,6b3e719f,573cd1a2,cd77e7d5,a49d6cac,5e7871c4,58df45d8,821d77e,f3ad3db3,56989c1c,700cf484) -,S(6857993,76774ed8,a08da47a,9323241,71d09fdc,964893d2,aa5e783c,b8030057,640c986e,befd426,8fbfb131,8133ca77,879ced3b,56ec251d,12d0a650,28bc9d3e) -,S(801865ee,fecd50cf,4970e6ba,efeed453,769b3e14,c103db6b,2632e241,2405fb6c,b3d3f23c,8f75e475,8784016e,6ce1b91,8db76599,8c7c1aaf,af047282,ebd7a636) -,S(f09220f7,27e57fd3,209eac13,1ed93f96,142c400d,b9bd708c,9e716686,20f1793f,8280375b,1b2f4915,cb82a72c,43c9fc6c,f3a7de5c,32762b69,43187a8f,13510eb) -,S(1c814b69,6104f8e6,5a51b98c,e6b0c4f9,f26b5633,8ce24ee2,24a5aef2,967ab705,1cc2bbfc,61828277,90502c11,bcaa1f1c,b5e34891,a7c669f4,dbbb604b,df2e3135) -,S(22fff436,de961dd2,a7ef38c2,f588aade,320d0721,55e6a42a,3201bc6b,c7d24a54,6f13476a,f48f9197,3845af18,ce68ba91,77a0d4f,a835acce,76814c81,f6aaef5a) -,S(39da98ed,a85b2de3,c9bba6d4,1af633d5,5a392dac,b1d4fb9b,654fde5,a3343a65,29b89534,35045e6f,2ca41bfc,9e5c9ad2,55eee426,95f41744,b239659d,460fbdaf) -,S(6fb84bb6,3be24203,6e067346,1a5c1fbf,7d89a0b0,c98ad2e2,25cc3ba2,191fbdc8,21a37f8f,e4f821bb,3886333,c554d6ea,cb8924f2,bfdd7ebb,339a8a92,ec9bf8a4) -,S(29080a3b,7c1d33e1,13b70c4c,8388fd4f,59118a86,c4bf697d,25346368,8f60766b,745ea31c,e9731f68,89aaf5d8,1e7f686f,b345c9d7,3af728c6,7ac2b8d7,60ffecc9) -,S(a54f7e6b,aaf05de6,77e7d98c,5385d9e9,57f68d2a,8e3c24bc,11b6435f,50cfd955,f7d61099,22ff9c98,ee79998a,597dac10,be885d5a,e7b53158,fb671e38,470b5c69) -,S(7472bc8d,c109d56d,a5f150c0,bc41edce,7e378335,15e17267,62f50cce,e8845b2e,3c59290,820b997d,3c9109ac,7319048d,e37c5280,88e671fe,9cd85487,f03917fe) -,S(6f4cbc32,ff1805da,6cf83c64,b0d0eefc,6bae76d0,586de80f,df2317b0,a4e68267,29e492e5,89bf6c68,17731a29,76577124,c9bc9e32,1856bba8,8a060bf1,6a6c9d9a) -,S(1a93eff,b60cb865,8538cb27,d8c12490,483e6886,16320327,e2689591,c5413a12,d96609d9,251ea2b8,f150664f,efe6bf6f,a0634cda,b8846cc6,5f6c8a8e,97697c9a) -,S(79b82e7b,bb23efda,cd79c0f0,87f2d0d0,e2d3db59,97696c73,e6e94ea,8cb72027,bf16f23,47e594ec,fd087189,48d531e9,8306b173,88546493,d620218,b25e3758) -,S(a806c902,28fbc405,ef56057a,aee9993,ef177261,74d456fd,818126f2,5d93f986,fc49c640,7d9d26f2,f043a1b8,8a41bbc1,3ced6a93,bd669ddf,3186dab2,9eb7c5b7) -,S(227d9094,69eab478,9da2fe7b,3cb618d8,d781e0a6,54892f86,92eccce2,f41e9a1,81cbb45e,adfe3fc1,de5975cc,f87f0a44,e9f106d7,19cfe796,f33b5c60,85de7691) -,S(14f8dba6,4bb5aba,f7f58e8,1c9b0425,2c357f3f,fa8aeee9,fa4ac700,8c49e060,26b19dbc,52b913f3,b6aafb31,3de99445,b49d64ef,2503d28b,bf2f9e2f,4614609c) -,S(f22646cd,553c5008,aa3c4cf9,f01a05e9,20cee021,4e9b0553,38a75c1f,23e5fe4e,52cdb77b,7502794,ac16003e,2f4e859d,ec3e68d8,c84a3365,a307ac80,53d3089e) -,S(515de841,814df2fc,7cd43689,8780686e,f3bdbfff,83eed568,af19c75b,5ee93a2a,7395bd22,705a81a3,d62f3130,ad416db9,268961c7,facf81a4,44d2ed8f,e4df1282) -,S(59f4aed0,38f07bd7,b2aa6600,ca6f15f2,d396310f,e4ffe212,4e6a89e7,3c7c4ed3,47a048be,5d6e45c2,4fa69329,86b86edb,b990eae2,f5dc6524,3eadc69f,43b2ed3a) -,S(7492492a,d7f94293,4287c7e2,5f05203c,4c70b8f5,80d23b4d,4822d1ce,fa3450a1,19523158,2fa06da5,eb5368b0,f0b19971,1a1bdba7,50d1c6ab,80ca1b4a,d649eed6) -,S(2e12d13d,464de937,372a69be,b90dac92,78977cd0,e7b954d9,30360d6e,a51cc3af,35a900c5,6c7cf352,8c4a5af1,56dbebaf,32d2a128,8a58e3a2,ddbcb539,bc3e3505) -,S(ce4c4b4f,a52f06d1,11dce52c,402395e2,a6ffd186,dd8275b7,bd43e941,9f4699d7,957b994d,c5bcd5e0,179a67e7,94a40ac5,cfc074da,6d23d178,969fd8b9,2d9dc455) -,S(c51f1cac,5814de82,f4bd5d2f,a8e4950c,38fe78bb,8d09bc5b,628ec13c,e3084592,721122a2,f63289c1,f8925ce,34d810a4,be52f7bc,9bfea232,47617f95,8db1cc95) -,S(9fbaba14,8293f578,46c717c8,718a3a9b,9dc5df98,63ae10e8,9c3649a3,e26128b1,4917061f,ad964c4c,5d79780,7914b2f4,b6c3e730,3bd440b7,bc00f15d,bed2b497) -,S(a4a9ed86,ed3a1dce,5423c1e,1bb5fb9d,fbc1ed41,66a4219e,bd343922,8542ea9d,fcf6821e,46386764,c61eec0,19b1a84f,6a8851d,89be0da7,9d2768af,6eba9d89) -,S(a6fa3567,9a732aa7,b58582b1,5f3e95d1,f702ab16,5249e9e7,89a5a395,3858d1eb,3bd67e4e,c0dae02c,43d32cfb,d25a4b2a,75898bad,eb2986b5,6cf61825,ed2830ab) -,S(3b3992be,8f7e1b1b,4d8f5710,6feb825d,568b176d,af0e41f5,9c2fd59f,f67d9b7b,ddf2751,ac17a413,2ffc5c08,3e8c7728,a74b0063,377228bb,a60cdb87,1b5db297) -,S(e9ccb20a,8a279cef,2a15de57,e34f510a,f60ce397,3fa2ec2c,4558f166,7ad20201,b70a11bd,1b5414de,1b30035b,3dcd1dbf,17558bad,368c78c9,d5d9136,6592fa53) -,S(98083dcb,1356be80,b324aa95,e38217f7,c437f421,5a7f3e98,ba803fd8,5cc04445,bc0d9ebf,ade6c640,d16b82b6,5328a2,d5ef2f8b,52aeadca,e406ae25,e9b756a1) -,S(6a0f3b01,9e3b2a9d,453cc36d,275fae6a,b94aa14e,e0b4103d,137b1741,8b446ba3,ef30c9f8,46c54902,c10a4ee6,c5013b25,709e7109,fc004b6,e291b1bb,a021facb) -,S(83a62b60,6a1c4d03,1a18473c,f2230088,1d767332,9513b7a9,4f402f18,3dd45640,b23888d9,98bb9c00,ea57c9b9,517080de,95e6491d,cba0d7a5,729ab99b,12a1246) -,S(d2781bf,4b059449,75da8b83,cf82b43d,b5ee89fc,168186bf,74f22321,30678492,76fe1955,18e00974,6af44fb3,6e623f4b,fd0ae8b6,474e91c3,3ec364a3,91049d49) -,S(e4445252,dc6acf3c,f7b3663d,7176d46b,efe95e40,3063d1a1,68fd5742,2795a986,cf7613dd,eb200aef,e665bcf5,a6dd7fe3,cab6ede3,877f6a28,22b6620d,1eecda68) -,S(51f59cbe,68f523b5,b435633c,ce11c0fc,ed2129f3,5d392b2a,ef789044,722052f5,10403f8b,e7024887,3c4f0aa8,e4d0fe46,11f34268,178368e9,1eba8e4,d9b318fa) -,S(7d1806b8,410ec629,77fc41c8,8c86ebcc,74da9a0f,c6b35c43,68d069a2,c8c974f4,efe8890f,5aab9bd,c2da2956,bc089b58,b67ffd79,957ce0dd,9a53da,b26d68b5) -,S(add67544,8cb87ade,f8cfc3c1,85fbce12,e0d1525b,812fb5d0,2420481d,b22dde96,bb80527c,b22a3bf6,728ba305,bbff36ce,c6b44d68,9cf79ffb,93030460,8f461174) -,S(ceb2968f,fcc7b751,f9b560bf,b08f40ec,ba1395fc,9a3f63f1,65a1be1,862c3dae,67727357,b2dc8d2a,47606c1e,ae61ce54,1d79ba49,4a5e310,e0435b,383cf088) -,S(3a03b03a,1348cf01,afc60665,26b6fcbf,b3977ecd,7c17725c,a9f0c494,f31223d0,3e71c6e0,7da0635a,a2fadf5b,78c892c4,c95f794a,88594b72,183a9b2,4dcbe7a6) -,S(42ac22a8,c708f2fa,559f9b9c,fc7ca705,4356d18a,95a69137,bb8b8b17,2b771aa,ef669b2,85ed6abb,477dc2f2,bf0517f3,794c371,9ba5b267,8f622eb4,aa4ce374) -,S(b2ded9ee,ab06f1c4,19c5aad,5163e731,722c4923,818185c0,d99d6a8b,dc603a06,23bb4786,f84e6c75,e565a708,2600585c,e1fd60a2,b935bb4d,390d07ee,5e8646dc) -,S(ea1faab0,bb0b6cd5,454e63a3,d1546747,cf9707c6,48e4837f,3fc6b6f,a2ccc5a8,8fddc23e,651ebf4d,89e54148,2043fc34,7c26b66c,b2ad2d80,1fd2fb7e,77d4058a) -,S(487920c5,14ce0cf0,9d939ce5,81e13409,9fcad06d,3e6974f0,a3b5925,12cb3a86,db447217,8a92e9f8,65a1b022,3baf54fd,618a87a1,15887f02,11cddbe,986dc927) -,S(6828652,aa506655,60349cdf,132ca8c8,9a6f9a1b,8baf6adf,64e10c12,9ef9217b,9615f563,20db2860,9062aca4,7a136e85,40ebab0,3f8b5f7f,93bf0369,aeee0cc4) -,S(b66a66f1,9c94868b,3e45139c,ef9d7586,1a6d06db,72027814,83dbefbb,41157a94,5c0763d8,8aa90b2f,ee04eab9,fb96b280,5ed5f7e0,58c9805b,64fb17ae,9a0f224a) -,S(5318b13d,a824dbec,eced642d,d742ca30,479874e,31c1013d,d770a0b3,c9ddcd9f,13093540,9b5d56cc,d5004948,3bb22009,4b7d5a5b,6d357bd,76b79117,458e60ef) -,S(6bef6b9,555f29fe,b5277c48,863c990,8f1fe2c9,5b4b45fd,8c5eb482,3ef4964c,36c00eed,4281871,fc5e15d7,7acfe3c2,6793455b,9b3607dd,71f3e163,9790e3a2) -,S(7972f783,4c010837,89b92a08,d21b8b8a,b6ff6ef7,92eabe32,fa1c92da,4c8dba6,2c3352f3,f458a538,f8228321,c1adf9d4,a2df9f8b,bd22675b,afbdf041,9538f1e3) -,S(7f03f087,168dfd24,7a93e840,e68cd221,f02735d3,93d777ec,c9d2c9ff,7cb0228b,663dc741,fc8e98d0,7dece960,5b506b5d,a5f2af72,1b64480b,1dd3e7b5,a0ee7743) -,S(d06ffe61,973be011,2f17bec,6f4dedda,9b9d310,4ed22ed7,d4c2f009,843d2c04,175f409c,edd739dc,5adea16a,187a951b,d42df4de,d1aabfae,d56f1ac5,26cda8f5) -,S(9094c510,3a34209b,45f7062e,ec65c14b,72fa75f4,13999117,38cd7f6b,792119d9,da541e51,7211db66,272f8f8d,413e1717,13cf499f,6c9cd694,b98e53df,45e9d501) -,S(22bb9cee,8a5b99fc,d7ac7d67,5e232183,3f71a72d,55248a3b,451699f4,9f151eba,841e7292,93a98297,ebf2e9a6,6d106325,265d91cf,f7e4c245,845e5a40,522b94a0) -,S(b548dacc,944b013e,d50dfadd,fb84173f,d5829b2f,69a2242b,c152684e,7b8a3ecc,6c7b70fb,9ae39eaf,583939b1,1a1b8aad,673b18f2,7568d2e0,b2680b19,8c662a88) -,S(34f46e0a,2281a617,f8ab78c3,86ed27d,f837f23e,e986dd20,bf705daa,1b0188d,4ce4df08,bbf1e735,6760e05c,6e5d3f3e,664fea9d,6e1a72d6,bad17bbf,a3c089d5) -,S(3063ee2e,3834842b,84cce6d9,50ba5afa,1d645c5d,e0acdb00,a9cc4ce3,c266f649,b08247a,f79c2be1,a0e4e021,7c9ccfde,f76d1e46,65f3185e,8623aaf8,63bff9b6) -,S(d7232b55,3740b2fd,464a919c,46168ef1,e09638e3,65117eea,979130aa,d40fc525,f842c256,38e84dbf,47d13fcb,1763a296,47b72908,1b522623,4e307dc0,1a402ded) -,S(6025e82,e2ec643c,32b10e6f,62ef310a,11576957,96c10f8d,b099dd4e,1dd8cffa,1e5aeacc,cc5c5455,d542dc51,b12fa3d1,75061cc9,45931548,7467d09d,945e2596) -,S(141d07cc,256c4d2d,44ddb7f2,ef720aa8,4bef767b,3597ba32,3b39915c,1d84f175,a842c439,9366b2a1,91e850df,333c9cd4,6c983158,cc57989c,588c305a,1144ead8) -,S(ba4ad105,6ffde493,54d13149,31846519,86fee8b2,728917ec,bd1a0112,b986a90c,97ac53,f84e995d,92d14f0b,b156f47c,be5b6506,2a7f8b07,7e235da2,808029c2) -,S(5a6ed894,bae212f3,eb44304d,98ffba1,4a944cde,ccd12517,5e52d767,5e0f801d,d8160707,d43053e1,e5806d7a,bc17563c,ffaf92da,ac51deee,55fcb9ef,715b08d5) -,S(d82a95b6,56bd1abe,50933a3f,e291526,7b257807,c8cde42e,5f1648c7,f35c4f3b,748904dd,3157bb07,65f94c18,7528c74f,ac639a36,be18963b,676b9b37,83f54591) -,S(df7c9de9,8e748188,74967340,34a76645,c1e55bed,3a90fc65,dfd9726d,a2bd3826,3bd77fe3,e4a4018f,3e256ca0,2bb5c8b1,b783b729,21ce329a,fff9caf6,b530b1fe) -,S(d3ae1d68,4614c95b,51cc4af5,a9e8a05c,4ad7eb4a,ba4a65a8,9a151b96,d91bdb68,a24cad0c,ad0ba98a,860d6d74,aea57c3c,23780812,5fb2356b,b55f0bf2,95e25e67) -,S(ca85c924,48a27be2,2b68c9f4,c9ab431a,b380ccec,2439c8b1,944c234c,bd865758,c53177d7,6b16e0a4,389e1e32,7072d460,90e92f48,22043bea,924fab46,4023038c) -,S(34309aa3,4e9fda0d,f2c20da2,3e8f8f31,eebea096,1e769c92,6c4251bd,5440bb04,f655cca9,d5811164,577d0525,2f5605d1,b4e2b6d4,dd5540be,aefed4ae,84caf3e6) -,S(40212a4a,b2bfcac9,62442617,8a807655,185d2929,7e26c437,4879903b,41307b3e,26624605,6ceb4509,b481df00,79e25f1c,4dfea60e,a3768e8a,462ac273,8166dfea) -,S(2e441425,d121e140,5d2118b9,7a3b305a,fcf62e91,4f24bb72,46e92aeb,1ebdd152,c3c7a567,51dfd709,9535d07,23778131,692dfdb1,7584d9c0,c8fed42e,5eb662f5) -,S(31539912,9e59668b,49d9b8bd,5ee66b2f,aa727ff4,96f457f4,33400a20,b5242b5d,5e90a20f,a700c59c,fb0ca2cc,ae3f2837,6dde44c0,3cf6af64,365e4cd3,b4e6b3b4) -,S(3b586e2c,30eb1959,bd5171ad,54b81c36,cda6b0ec,b5e77b41,a7b5b0d3,e1ed4ba,6782aac,d675436c,d969f413,c471edf8,ff7d89a,d0a07575,16bb695b,19ef40fc) -,S(f4299c9e,b3453201,375b972f,fa39f01d,90c68625,a63c9d06,513fc9c,8c623fc3,cbd0e2a5,f9b9ebd3,f482a5bb,c5c17894,d5c320e0,28744292,31c94fe5,55ecf68e) -,S(96d35f35,eee50b32,32371acd,99d6db8e,d2b7c4df,1f62b867,5559543b,785503d2,c0e8bce8,8bee1e02,29a5d2ac,113c9f2a,feff0260,869ecde0,7cdb1cd6,3ba5f73f) -,S(ad3036ec,e2bcae0d,1fc34680,be2d293f,b40d9133,905af375,1ff89c49,2c183e1f,2c0773d4,bd30833d,24222f89,3a4f5e8,cd6abe06,63d66d63,2d5fb832,4c260f9a) -,S(a0f340da,909f04df,70a33195,1c48901f,6353f4d0,4d22f99b,3763f567,be9d207f,caa1d9de,46a37b8d,623a39a8,6792475c,bf3bd694,597351ac,515ecc8b,1a4fe78b) -,S(2adc4874,af0b3cfc,675421b9,5369ff0f,950b55d1,331aeee3,dcd0adf3,859be4d,6ad9fd3f,a840d02e,ddc01fa0,ffa61bf9,4dc1db4c,ec733976,bf1c6e41,bdd92b79) -,S(b9222a37,c14456a1,cf931410,d96cd84f,a304b9f8,5a96edd7,6e67f928,43536175,4002a875,dfc4cda7,4ff7145e,ca46aab8,8cfc5ed4,53b34eeb,1e5dd859,4793e3d3) -,S(530bae23,c3796fbf,76f86f6a,d8b59b80,801328b7,6c46e8f1,cba6398b,270919f8,d4d3b34c,6701f07,bc47d1d9,fb868fc2,b46ff397,2086cbc0,517e29d7,38a7964c) -,S(a7f2ce51,5b932506,c740e84,40f254d0,e0da57bf,4d9199f6,acfa3664,ec36b823,4946fc41,3ef1b3f1,86a2c781,6c05ce7f,803fc7de,a00fbc2e,7e6c4688,fcddadae) -,S(8ff613d1,1c81c4c9,fda3860,cbaa71f8,eab9ac3,d9263f31,55317949,d6ac1d53,54f683d1,fd382305,b2193554,bd3a6d2f,bfbb99b7,5d9c3e1b,876c3b52,e2bdef49) -,S(6fb3bc81,5ef3d8a0,d7aa1a69,dccbdfb6,3f7a58c4,7a12f98d,b09cc105,4306422d,798fe7ac,f9fc71ad,7023a8e2,c9376161,8fa632cb,ec607109,d28a63a3,9a4228f9) -,S(c32aa38e,bf0ec0ac,61bbea0d,d2c633c0,bd49ddae,d77179c7,e0098c8f,4488da8,e01f5fa5,1107cf4c,f4c1c5,78c3b5f3,a1baa059,90bb8913,9e2abb30,2e9e5042) -,S(ef5e1efb,d1ede40a,810434ae,833a4681,5f9021f9,41ef1d82,fb8c1399,16c4933a,94a9cd1,5f160c1f,4f85ec8,16fd1834,9cf19f8e,96ac9247,695ca37a,dbad6ef9) -,S(8e3aacf5,33de35e,4f923b36,c378ea57,7a5aa477,70ea6390,f92c73d,50fbfed2,49cd7650,ff69ed12,b96ac3b1,420784,7677497,b731e0ce,316eed65,7e40e014) -,S(84521790,204c64cb,e026152f,474b0da2,25703d93,25943821,7d66f20e,3ae0d06b,c1da2f7e,438fbc82,57f7fe4c,7e49b73a,446a19ae,775e7f1d,20c8fa31,edc3bd20) -,S(604cd900,97fe538d,b27cc2cf,a2d6c79,692f2e2b,c1b1b23d,1f0eb949,df560697,914d5288,29765538,d77f8e04,182c50f,d2d9aecb,2412ce47,4888d666,46b2258d) -,S(c13a44bc,9a27e241,5531b8a0,5570e66e,6763b3bf,a80e00bf,59d6124f,b3d67858,71557bf0,4c261c2b,19196d0e,9e459f3a,f629cc19,84f411,31835400,3a60563) -,S(14f3399d,5204b654,23d9318e,4adf3af9,dc43099,eb43b719,eb4644a4,897ffbff,13808cff,4c096655,72329034,d489433d,976cc011,d1a30ced,702ba4e9,5892422f) -,S(bd84d712,43dea7fe,f151b207,5d03d2ee,170488ab,4175965b,128411f3,f592a36d,57a1c602,408fee75,ea9e683f,43d7a984,bf03d66a,37513c50,5cbec6c6,6d286fc0) -,S(f319d4a9,b5f2c1ed,6619ae06,e5aaabe4,13a2a6c,265283fe,4a51c7ca,6c49b572,bd9d90c2,2a369a03,1856ca9c,86426171,db952537,edbb1ba8,93fd16ea,35aa43b2) -,S(9649689a,424ec9f5,aa4cf4c8,45588046,c50eaf9f,700d0412,83e02640,9a80c61b,5cba8567,95b0440a,53e0d1c6,ad560364,c398dda9,d2e97a1f,e594355e,1402fa33) -,S(45fe12f5,a340034f,381764b0,adf503b3,8026374,70eb26e9,6f4181e2,68cb1c38,ab7715c4,52e5581b,ed940fde,355892f2,b8a16a3d,d322123c,14a57a23,72f244c1) -,S(98bcd24c,3222401a,a4683213,5a378790,6c9812ee,989b8f52,fa522c6,d39adcc7,14c7cd38,7bb5191c,f49bbe41,52af8b03,7135a6a,bc7e4697,35a72a38,e44433a4) -,S(6dc56512,7be34196,a7653057,f79b854,83c275ab,65c05c2e,83663da5,31d7d652,a6839fcc,ba7db053,affaf5a9,4c95676f,9d65eba3,c2474472,cadbde17,2ad3692b) -,S(7a7f66de,b04492d1,fd2fb9aa,dbc4ea7b,ae5a3801,47b86e68,60513a57,eb6b10f,fffe4f2,b722f36f,1e555671,90d84d9a,39b819e,fb7a3436,29b83adf,f6045f05) -,S(aaf9f188,3865e2f7,eb500794,3888b4ec,9013371,f7162947,2cf52adb,bb5288b,df634c19,e7496b4b,478bc10c,7c00ac8a,5fc24dc6,4f193355,f0fa9c62,d6048243) -,S(6304b1d7,56988ca,25afb747,476acbad,2e5afa5c,86136090,c86a82a0,e52b373,91a2d829,2357463b,ea1a7cb,33d79be5,8bd71732,f1d2cc13,ba4b2724,6fd39f05) -,S(6eb17147,2aad3d80,bf4e06af,a36e37ee,5fed9c18,bbaa1c4f,5cd871dd,c526515b,6afd615a,e2512fa,70c9670f,b56682d0,f304a0c,6a23d1ab,fe958a7c,2a4173fe) -,S(9113b613,ba815ca6,43e7bf66,27dd71d9,8c2d40ea,5c00f596,6216ca9d,d32b1ce,8790dac5,bce4100b,8e4e5135,66a104ac,b55d3ca4,3d6ea083,d23716d3,3894de2d) -,S(5c7af38b,8821169e,2f7e2edf,18b3b73a,c387e6f6,a8ef1cdb,441f5a13,284f365,e12619ea,e2a07b8b,c55dda85,6cd37927,d448cf2a,f4028459,2e371e10,8e91358b) -,S(becf19e9,23fa7b4,1cca0efd,937a5b11,e227fd18,22743fff,80c42692,6631ff0,3213c209,9f255eee,93323d1f,b440cbb7,64e86f1a,4021b82c,485517b0,3440ed4a) -,S(f22954be,430be6ab,34dfbf92,264c2406,df3a0a7,19ed45a4,d09cb161,4abb0c91,a60397e3,ef3308a8,12527744,311673b,c18bc43f,352dba00,4dcd4124,7b84846b) -,S(c50ae8c7,61776e62,5156f9fe,7d863c36,79d43126,c5f3fee7,5b837a38,1803e770,be966bf5,99b67e6c,ffc421a5,e6d12e4b,cbde12,4d84eadd,781ea562,aac7dab8) -,S(c6c3a65f,e849c113,748e9b6b,c9a9419c,1a919503,36201a6d,f989bc5f,fa07d359,fc205b83,b4764ded,ef58082,11eef120,4d9fa959,4d5b7086,c2fa2c9c,3e56f37c) -,S(73466c27,8d5f13ad,dc7da10c,b8855c23,9069f57b,6ec5e80c,e27191aa,196d9b1a,7e7e2cfb,533cfe9b,24243cd6,7680ade2,35abddc3,d8d00faa,c8adae39,15ddf6a1) -,S(6315ac10,35eaf884,8919bb56,759f7013,92fe442c,771a42dd,dab88ab0,2fb0df2d,a49d2c97,6e0e66b4,50e8511f,d91f0f71,a7516fcb,70ca61a0,98f135ed,8e19396e) -,S(fa195146,fdb7ddbc,41daa8c5,98e1f811,36c33eb3,bf23dfc2,3f20b36,1c8e7bca,324fc70b,38677dd4,c8e7bd82,4b836d0e,738dd757,ca408ff1,95bdd5d2,bcb5cef2) -,S(ac40bc48,87734bd,51247e91,43e5e188,e5e2bfa4,2e3c0392,f39755f7,3952bcad,75904ebf,603c2f07,4eef9435,eb22c663,1279afad,94d3bbca,d5349881,7dc4a472) -,S(15b7e1ef,d2c41c6d,416b6dd2,5f6612f0,a0acb0c4,1b161b4b,c40c5ad2,a92604f6,a13da672,17501833,4c4057d8,85be8fb1,ceb6d369,6979b805,83fc0a37,bc27a0a3) -,S(adf4aea6,6fff705d,5bff3c84,93e8870,4ba4019f,ed550cc5,c203439,ff8512b3,53ad2122,30528e1f,4fee43c9,2369dca4,3d071177,3ccfff26,aa16a502,6206a3d1) -,S(da0d5286,fc261d92,1095e1cf,f67e729b,501f21b9,45e8d84f,ba2c80ff,335d105c,5632ce7a,e8d9ce7d,aac7cf26,2ef7bd27,418613c,b288e793,35a0a638,6abd83f9) -,S(463fd081,daf02794,18b95a48,bcb8dfef,3a9dc67c,2237d2e5,dded1522,f714d6d6,3de4cc76,7126750e,4038fb43,bf6af17,63ebc0b2,ef56ba8c,a376b815,6b4f28b0) -,S(15e37b9f,58ce033c,2f0ad85,d49f8207,2e2547c7,91c7ec52,a8606974,2badb586,38816873,5e37c957,c18ad56a,e7ab81ca,8fd89a2d,1710f032,54393ae,a046490d) -,S(2e121b79,765d4f4e,8e7aa8df,5c70e4b3,716b976e,9e4536c0,dbb3b5ae,4044a345,d7ba59fa,97a7d6b3,8b70ecea,312cb01,f9016b33,c160d1e8,d33fdf50,ffcbc928) -,S(8d4c7aa3,c59dede0,bc146b10,38f8f823,8182c4a7,1cde0d8,e17005e8,64ad29db,78aa343a,28a48f90,edd7fb31,849d6d3e,fdb4c677,73cb523f,82c0b187,2c17f44e) -,S(1ae12a1a,19a5d1,3b2f42c,35a385,f8302721,86a67801,c22818f6,94438c58,5cb421bd,990ddad8,16de9439,87bd96e7,e1ddfc5a,8d0f86f7,b30e3483,897815d3) -,S(7a6f584c,d48be9eb,a7b73377,8a173d5e,3833aed3,a603a226,741ae1f3,a1c21bbc,5995b840,bcb6cc28,b83d048,9faa5dbb,c6a93190,46b11b13,59827266,d177d27c) -,S(2dc5ccb4,8f78db2,3f0933f0,ef67bea0,53c7f2a6,80788bad,b71526a4,f55fe758,9e4743f9,ddb46206,a5449942,71743b44,713522f5,f358ab47,34c9afcd,f528736a) -,S(f7a5219c,75dc4426,4322bda0,3b603127,26a6b3aa,c471f42,a33072b4,a44fc9bb,9e1feda5,5da277d5,cb18381a,4471939b,a12c692a,a40ab965,fd03949c,d8124ab3) -,S(a1bc311a,e29e3926,5b3be1ba,23d7ffee,df0de8af,fba089c,fad797dd,8ba67c68,9abf66cf,109821c7,68c98164,b0598068,c4590d7e,b9ff4c53,594af6e8,e0ceee8d) -,S(2c2ffba2,e3fee930,fe8d061,3bbb8290,22429fc6,654d5ed3,61eb8720,1d6b92c5,ed89f28a,bad9510b,acf44d05,5934cc64,ac7e94e,2dbc72c9,986e6cb0,acbe434c) -,S(1d157e13,97f6b22c,3dbfe448,d1168b8a,bc963f86,bb3bda29,a8011f07,d2cb5ffc,bc7cfad1,e1633419,cef1c82c,d0249ee8,4c38b3f9,d628337b,aacf0449,4ca3c0b4) -,S(1b9e9723,56f8a4c9,5e8d5fbc,8e2f2cc5,99c77d62,90b2fd44,2e63b3e6,dc33c772,59db6eef,988386fd,21e8a772,a1fe048f,95ba77a5,122253c0,1a52830a,bc12742d) -,S(80460a3b,16fd9ba2,250b07fb,c77f2526,bec5488d,7d6c45ae,6f480308,39af48fb,bc7648a7,744347ad,e17da2e0,5cd1ce10,db704acd,26c81fbc,db251ff1,c6fdef10) -,S(c6903a0d,d8c26c8c,cdb675b5,972aa050,6912813c,a6f0c8b0,2edfb792,491222e7,f4759b4e,9db7f1db,7c8a1c38,dfe76d86,c3778423,29280aec,12b1be06,d8e49ff5) -,S(95ab78f3,a4268c8b,39aa645d,8c9fbfd5,b92469b0,809d6369,3d57d076,d305a241,8df4c8d0,ed85ac01,a965d580,78f36a5f,690aaa03,d9479d1,b2297a52,53e3c6) -,S(bafa3ae4,40a4b8d0,40862a18,cca806fe,8cd0e780,483b396e,41543486,db91d9b0,d7bd60f0,c0ee0b8e,38aad85a,85a42ede,56c66d54,ee73d371,a3bb7cdc,e93df670) -,S(7cbf5d9e,3bea6864,b87ae157,fee6e352,dc3a4f32,6e7cfc68,377fd199,a6dbb71b,42d082e7,5d55eb62,9771942e,3801c27a,fd80b502,a997ccc5,9f5a95f7,d7276999) -,S(9108db63,751b8a9e,f4870524,f1198f9c,c4d3ec20,af54119d,6011f263,de13ca29,8c1d6c47,aa016e83,d2c8f76c,df0935b1,b6f909b5,bf5c90b,f4203493,22c711d2) -,S(a705e7eb,c20ac4d7,43be660b,d61340c,9629d069,1b08ef01,a59e78e8,2d8b347,1ed8ec9,13ba19e0,851e1912,5854433a,f71b21d8,df64958c,afc5d7aa,cd29ccfd) -,S(b75483e1,60144d46,78af9a3d,701c4ffc,fe154c49,fad45ece,3945289d,c3781c3,a4c0455,13cfa7fb,ba2931cf,722fc569,87b2c79b,c4b94313,5a458d34,5ee16d57) -,S(c59aff26,bd4fdb9,37468989,763376f5,64abce,c00d54e3,45b6dc2d,9b7b76cc,c396c194,db446fb1,a22e86e1,8a37981e,d114e675,474bd24c,784daa96,91eb15b3) -,S(2f6701c7,815ba7c6,37c4649d,d05a31d3,e909d8ba,931e7136,1e0662e,3ea19985,937eb67b,9262bbd5,12a21e90,393f9e65,66e03203,55c77afe,cb98d1f4,bd25e8c3) -,S(170d1e33,f0862542,dc72b1b2,950ba98a,812cc308,74ecd0c9,23ce7c09,ed7cf9b3,5148ef39,68ff35f7,a633ba7,dab6cdaa,54dc6f87,510f1a7d,4d3019f0,c00bc868) -,S(743b02d,b02301db,453f8694,cd517c6b,433f609c,e205cac,6f6a49b8,55890708,7af6350d,56130339,1a9ddce5,f566b9b2,9c10d535,d5183850,6c743124,8dcd707c) -,S(ba6df8bc,f9d83988,4991c6fb,e0aa0ecb,d0b6cdc4,d0e372f,3ec83b51,da6a6570,7d27b176,3a01a8bd,fb7dbe0b,226dee6a,73ed3644,807ca33a,1f5fee61,cc161fcd) -,S(d3b63a2c,364f01db,6a6f384b,4bba6c2f,2fa46a02,86090826,1c8b5045,4b92ca5f,df6b9cfe,fe7aa14,a38bc44b,8b627b6,e0ceeca7,1720d630,cc4fabf7,b020e2d2) -,S(638c2b1e,374ff6b3,4b634f4c,bf363bbb,55d66c8c,af4d3fed,43cf436f,a1daa7f3,9854873,37b48f32,4feda3a1,f267dbe8,8831aedf,d7bd36c8,6cc8d862,857507d7) -,S(1749ab4a,607d7864,5c4cbd30,4bc34c06,94a7a636,9c8c8f8c,be4602bd,16c4b4b8,465bff86,b459b842,dfae4df6,99be1758,8b1aca97,f9802827,d892792c,748ac92) -,S(9071a5ff,ff23ae4e,2d81b2fe,d341bfa9,cb86ae6e,ed32870d,d549af20,a1db9feb,c0e3d4e8,277d099a,9801ddf3,3e513aa9,1761218a,967d530f,21d70894,ea7d38ab) -,S(91bc0055,28e2d857,ac644954,242fe0c7,bbaadcf2,9119837e,898244e3,a305ba6b,6fb63758,3aefe600,46997b88,315d5a24,683ff955,94398694,be304dcd,8b588f67) -,S(9663913d,48c865f6,312fe51b,6e8e7c6c,51ae397b,d141aaf2,df3d6ff5,edebbe68,c6251751,7e24d81d,b1da26a6,6627fbb3,28b5f818,6477b34,43f7c36a,918753bb) -,S(e88e8702,7843b941,61c71887,9a0a9a90,cc0d6dd3,8329c73c,a18acca4,3f44ffc9,7e31ae63,1f9c927f,bd055f58,e682935a,3225e778,9221a062,f2826d86,97143a61) -,S(5ad27e79,dee03a52,be771a9c,ded6a02a,58337f26,be810d1a,f8cc5ddc,f1eeb917,91c18e01,dbee34e9,a5302a7a,11bfa7fd,ac852e1b,e53aec2d,3138259b,bb53e6f6) -,S(bb7f4694,f2935a5e,8711ae47,bccca550,cee2632,4347b468,58e40c74,49111ead,d9f94c14,332ad75a,59dc784b,d674e8c6,146a2b74,566ac1ef,b0ca17dd,9eec8d74) -,S(ff77ae06,e0624cf5,f6d905ee,b0de7281,5377c026,3e01b6c4,a139e4ac,3304e82c,1f27acf9,933d08b6,f0892199,11805d14,1611a318,661e6e7c,75014b84,cc35c395) -,S(84c15fb3,1b12d39e,ae59ce0d,f8646e9a,67c85492,8d6c498b,4b836be2,eb19a060,6aea0d78,d54090e3,2216c3ae,be0dd433,a666e67b,44cce0ec,1609804f,fde33f74) -,S(9a48086a,8bb9b150,a6ccb966,3978f555,41db6d48,1b3d5266,e958cbd1,df9ee7ab,d8eb2109,13ee09e7,b5767661,13157905,b3cafed4,641903b6,da0ebc08,a0ce2f58) -,S(db32ad19,45f4d9f7,eff1b8c6,b87c5545,1b0c74d9,8f1c4ffc,6ff1e79a,21ab3033,2d56e65,a70bd23,617f85f1,4a5d0e4d,52aa6a70,a8594158,36d02d87,309c7eef) -,S(4de7f1aa,b9089f5c,b6d95b67,a04952b0,d4696cc7,6640e1da,f4bbf7d1,da985851,96f2cd33,5fd4b816,4499ddc5,5e81f5ea,c4db4399,17f2151a,f86d2ad1,e2b3612e) -,S(74bcfa73,5aa43e8d,1fb540fc,9922362b,21878c09,666bf541,a0e739b9,dcbfd1c6,84b26fc2,8b2a05cf,a67947d4,99c1ffe8,f94ed4d4,6ba583b7,cf26ee81,ba60bca8) -,S(9c596bcf,3d2e1df7,cd8d9807,8a1ab17b,f16e27d8,66cfb582,ef58498c,48ee0fc4,14dfc093,48f72d7d,af9e3599,8b5f18bd,5287f3f8,381308e0,63666028,dda9ac56) -,S(8e2a0d3b,2786d67c,a15cd72,4f2cc6dc,16cddfc5,cf080ef8,d9576b2e,e5b0ff9b,2ec4853c,c83c72d2,68555129,ce30c836,50fb59b5,17a3d61d,56ac4273,1b33ad06) -,S(25ec4838,5fee8fab,773498dd,85a23ec9,46c59839,14fb8a9f,d1239ea8,ade3f829,123bded6,5312030e,d4760047,1867aa4d,b7537239,b363b6cb,58ecff98,44986924) -,S(a1cd9872,7551e2c5,db7985b5,1698b97a,31b90d3d,32fbe60d,34f8ec2e,398df76e,40858565,aef814bb,8bd91fe1,410f9556,3f1bd170,345c1283,b64fb268,4980c398) -,S(bf7d3973,aae2cc31,e831390e,f2458e85,9ed6847,e9eefd6e,cf91e3d,4a4924ef,c2829fc4,2127b303,c801605f,35602b84,32357564,d9333ba8,d962d639,ef21a6aa) -,S(5a5299ef,e0d394ef,f4b510ba,96dc73bf,6332d358,e276bddd,527ec290,b73e3313,9ccd4618,17e18104,d324e1e8,1597eba0,cb6b475f,4e5f2e02,9cfd2d63,b613de79) -,S(90efd8cf,9e4b9d74,5cb36c13,20a8bb0d,b5cb8578,de49ea4b,c289043,e2ea810e,87a73339,aaceed7b,af47b5eb,97aca554,d80a4f78,d439ee14,4b2d0fb,f8df5e3a) -,S(3a174294,4db7f2d7,2498e2fc,e2026d5c,f8600ed6,958db97c,24ac0de8,417f6def,e60c566f,f3fd14e2,2ff0cdee,45c4c2,31797951,7aa0ca68,af91a5,e41f5f60) -,S(2213e0a1,3679040f,73e4d68c,bb941665,6ea83640,33abac76,2e64d509,48a97656,2b87ce0f,bec2728a,aae6586c,bc6d9a89,a4bb9b9a,211de522,cc909279,5860791c) -,S(382412a1,ab396523,8b06c47b,e941051a,bef3b215,16efb280,3ff3a1c4,824954c6,7cae8b14,1938312f,ba482980,ab9073da,c66c1ca0,d746231e,8ba8f331,4cfd9cea) -,S(3d76bfac,89c1269d,53b6ded6,bf13c785,361b1fa3,84be2ea0,d582ee43,f06de56a,18b1cdbf,96d12859,bf887b89,6d8f2e6c,a08b892c,688c7687,8294974d,af6d6284) -,S(715b18a0,68d86cfd,41a20541,847b36a3,ed7814c1,b5528751,927042f9,85e7ab70,2b8e0228,b0a4d39b,85a3d3d4,f5a10db,c6825659,f4b967c,361da449,24890911) -,S(a31a10ea,e38e6a00,ab4f004,8b45c8a3,e57856b0,d0b64e47,fa90e234,e17943f9,5d4b5150,7d3f3a82,87e5d51,6bb30b89,2cb9f540,96aa5962,1f77e028,480e594c) -,S(b397f965,1dbbb6db,34708066,a1743511,d4a16332,95f53772,72c43a6d,6e21c1b0,673fd327,45bea2fa,748a759,30679b2,471e4004,423dc8b3,f34f95ea,f88d2b8d) -,S(2e4b865b,c1245325,1ad8b3f6,e8776bd1,a5878b93,ec34f847,65af84fc,146d9919,b3e7d479,661ce034,50094432,c538f55f,c8be8693,73a91fd0,350c8089,ec0d76f) -,S(9a38c790,7c0751e5,ba750bc3,485b4a4,72b661c3,63a3980e,feeaf59a,98533a43,dad7ac3b,65493036,d30068ca,72808000,d54b42d6,d263de93,a1ced3d8,fa82ca71) -,S(5599d251,3b3c8337,f8af18ea,70d1d2e1,83f3e363,63735357,2b3f6cba,b4371d9b,7ccddd9e,ec8dd507,69f6f633,cc70488a,6a4e322a,2716218c,5de50fae,45398dfe) -,S(610c472,4699e983,530e8a32,b60a8077,c7f60226,cc3b2010,e49b2e30,f2a98afd,42157de0,fe6d8e53,17a3f565,fa450f53,8755679,6d98c7a7,ba0b3e96,844d25d1) -,S(89c082e1,1438e2b5,6a4bff8b,cadaf804,c9d11fa0,8f47bff5,39cd0741,76f24a59,f4dad4e6,19ccf814,e899d48a,904a88e0,6db6ab19,a2e06a7,b359db9d,cd0ad0ec) -,S(bf810fed,48d1ec4f,77cf3732,ed10a44,df9e4540,2e1a1e1,6b29c82e,32537565,6657fd30,337e294,fa31d30b,409b426d,546a47cf,38cd23bd,75aafaa0,b527d66e) -,S(3b1317b8,bb3c9c91,964ce369,19ea811b,90a8bd5d,ebadabc2,d4d1af3b,50fb3524,cfd5988a,78aa555b,595531f6,5fb0e3f1,e756c1db,626cf60b,4c1b17e6,caca603f) -,S(88520439,61558d79,7b084143,783d9e03,791e6183,c932d1a4,17eed30e,bcec0bd1,271097c4,4c723ab1,c1d13e9,93b7b232,235957ef,f21a13b1,2b3d302a,ed46ba1) -,S(6c420c30,343cf500,da0cc05a,c315d3c3,45ed8aa8,e0551bb0,32fbc512,732f34d7,fb3c0808,698d38f8,3310fe1c,15587cf7,137bef2f,666229b5,bc789dff,1b2f1111) -,S(b12e21e0,e060fcf5,580d75ef,22e8a800,33e2c19,487d0660,615f7d51,ba00e430,3931d63c,a6e0da2b,295bd22a,4bbb27f5,fb52d89a,3c4ac36,795747e6,e74ce944) -,S(4fb9da54,4da95655,c0de5654,f68c2820,a7884734,4bad6934,e671d56,e7bfe11d,16586701,9bc89b28,f5fdec40,78a2a51d,6e087ee4,29456cf3,d258b97c,209d44fb) -,S(18f8f6ef,23bf75f7,a7811025,5babbeff,792109ca,5a550472,245552e4,35588e7a,e712abe6,3a374f25,fd4b18c8,4b1451fd,ea77692a,43c0e3b1,cf3469fc,7a9acd55) -,S(d730d167,1bd36654,7188c07f,78d82ed5,6775d7ef,bd0967e6,1abddea7,7ed6073f,49c4bf3c,ad4e31df,d840045c,aa8be15e,43f90196,818e30f7,b379c74c,1d866553) -,S(a915fb72,7d4c40ab,547c983c,24a4f019,1f5e89ce,7ab0636,e903aef7,592208a6,fdf28a3f,6557f27,5813ccf3,8d927f40,b910c5a9,ddc3c83,14a48eb1,6a5956be) -,S(7abe8d85,bd95c580,cd9d532c,c1295f5a,ad5168d7,e3dcaf28,b19f5e76,95107157,694abe9b,9a6ed0d4,c3ac1db8,79b49038,6fe9d2f9,443647d1,91533fbf,aae3cc02) -,S(93a83e8d,c80c7cd7,64dafff1,edd148b2,9c336de7,cf978b14,fbd35625,c965942c,91ea5775,db50bf9,a7e3f79b,77c7d5b2,deddfa08,a1d455e6,fa21e547,356c634f) -,S(a334ed87,dfd2e1fd,699ce1f0,a09fe921,487f8321,6cdcf75d,fc8d7e5d,cbbd1af1,42a0874e,d148bd32,ba4324ae,eb0260cc,7f0d20f3,f43388,38904640,8f7ae7e0) -,S(811597c1,f4129ac6,e150c231,bfd8e4b8,4ad441ff,2c698486,affd4ac4,c22bf8b5,5f7fb47e,11b476cd,acce1552,95ac000f,3acb3838,6ad3c6ac,191dc12b,d1e299dd) -,S(cf754ed2,47c9eb9d,24f3129c,4b4cefd8,94b5e58b,832f158e,2e82911f,8177a59f,262cb605,2991777e,bd1ed5de,d2e7ce29,76dd73d1,ad4c9bf4,9fb5d8fc,fbe4a3d1) -,S(290ec604,a6b4d816,ffe75715,419b0f33,452530dc,94f48883,b3982161,4592b229,4235db3d,df2e3f1,b61ac412,a90f543a,ddcd519,4f4a315e,d889b32c,ec8f76e9) -,S(1f90b869,4bf9ffb5,7697ee72,29b7f20b,52b47997,35efd7f4,1e4b9102,51886858,dc3d7a68,abaf70b3,c84d533c,48ef38f6,9be7d26a,13c4e834,5a7bee29,c6d3c87a) -,S(ea20b4c0,931087a3,44d5642f,6c018aea,2da5f189,a4d25968,96110281,88545ba4,f9adfa96,f945e745,88d2ab41,e32ef5a,76b370f3,f0362e57,129c3998,e32cedeb) -,S(b8bb88c1,21948c01,3a61fbf9,bae86eda,28e9bb4c,6870b0f1,7109e5b7,c00cf4e1,90685129,8607d7ac,25bea5c6,1cc4feb4,4148e07d,2fc3fe7e,449773d4,8245019b) -,S(2345a244,f2f411f6,ef091904,81eb9083,9128f7d8,67e8b910,124d1e44,d116c529,a8eaf530,c69b792,d6595967,4f23b9,b0e239bf,b69d05ea,466f9f5c,9bd5affb) -,S(75aee824,38bb03a9,b9208cc9,b725f13a,1fee1aca,20ed129e,e5ecdd59,b92c89cc,fb6bc8a0,fe0f684,ce4cf153,2053312f,b97aa1e3,739fab8d,407db39a,737ee51b) -,S(ca46d3eb,c981eb1,764867,c99cd7fc,c414bdf0,31b2c9a8,96829ebd,f31e2e36,46363355,862a64b,97541f7a,7fc5cf51,ecae168c,c6530db5,3a7f2394,2e87bb96) -,S(4fc1d258,575c4830,bc7a03d7,6a259406,7d633e9a,da2c734f,45ce4d9f,99dbbe7d,cbdc616d,fed2bae2,9312c5bd,9e195bb,bfdeb2c8,d1aee5e8,cae8fa0a,4bd6baac) -,S(4edae08,54365c27,f6ad83b3,8f68c7d3,f0a09c6c,153791d4,df98b5f2,3f0b9be,cdc8a485,8ac66847,c732a2c5,4be86af8,d6d637f3,e62c7802,dd71c7b9,2eb18223) -,S(624dca60,16beeb28,c35bef5f,e97d320d,d725619c,3faa7ca5,ed79d491,72b12469,cc33b49a,6fd125cc,98d65a81,c0713cb6,2a7e687,276e7fb,641e2f76,52646c12) -,S(6738d38e,760e50b0,6a18a9eb,b5e3676e,c38f3487,e34461bf,2e5d52c,5bbd6b4a,c3ce0343,9b9f624e,a92eecc9,860ff680,63a907d5,b57c43e,465ead5b,bef5e709) -,S(bcb74527,10f178a9,eb48655e,3d373b56,8f02036c,e9ab826,4ab7cee8,52f7f9c0,4e928392,52ee05de,587c91d4,6eaf5e5,92ef41e1,5a2b5c2a,da9e4512,c25bb416) -,S(3375c7ca,1b5fb4d1,1838ffa0,c21d7e03,de34ca5c,92bb4592,bb4598c4,2b490382,8c284e32,f016d186,875b87d3,3bf4271,4b9013c8,ea159634,b39b7365,7ea837de) -,S(c347409b,336c0677,ee95de61,f93fad4,738268d5,6f31059d,380af075,60e496bf,37dfcc4c,c13bbfa,5df43c69,eda0c68c,42de70d6,ab64a9db,a4ed22f,1cec3fdb) -,S(305ea4ad,ce72ff73,976544d7,a3deb346,452ce997,f280c3a6,106b7c9e,3b9bf5d6,bfc33cd4,ca178310,c4caba86,5b87477,77e9e572,4278f0f0,56b86a86,1f2e13ea) -,S(8333f714,70e57841,312a33bb,4f1463df,d237651d,fec4e1a6,40c0ebe7,478c5a9f,d39b03d1,11657c2e,19ad78d,3e1208ef,f8505695,1bc67098,b891c42e,b427bcb7) -,S(500af03f,eba3b646,a0690f0,74cac255,804c8f8a,c2aaa1f5,f5cee4e4,41913e7,5e67542e,8a8f0411,e9985a76,97ba626d,f0607f66,9f9c11da,826b47b1,a52cfa2a) -,S(e440385,c16bc15,5023cab3,3e7a48e0,5e7e0c57,e0fe848f,26b146ab,237a3abc,dd8ac982,b627fc9d,7fd83c26,51805de3,d7369ef9,2e970664,8744badb,3db060aa) -,S(83eef59b,b0a26fa6,60c94e45,c097bcfc,8622c37,cec46eb3,f9e93aab,d0fa6438,8b51311c,ff685570,d9aa7a66,5b47a3ee,b6bc05c0,a2709421,c73ef814,bc703723) -,S(930cdc95,f723a7eb,d698c1f2,46692f39,e1add95e,f8cf84ca,171d4700,2a7d759c,ff161a2,31fc8964,5bb6dbb9,f595daf4,86cf01c1,944021ff,6ff793fc,2613bfbc) -,S(4f7cb0a2,c83f3520,86085b19,a6e5ccc1,b0beb700,35637e6e,8a79fd78,337c2616,aa32192b,82831ed,a9412f4d,6ac6d148,f68ef492,5b438cca,12a73b37,b4a8fb74) -,S(c7238fe3,17590be1,d8403ca1,3eacc6b1,71cccad7,e2e8f659,f11357ad,70590424,59079180,90bdc74d,aa06abf0,940519fd,d09f24b8,88c15cb,a632b814,fe8910fd) -,S(c6afda17,e6582427,95cd34e3,edefb600,70c73737,2d99f6c,b2b8dd3c,99874880,d805463d,15d185e8,b4461293,b6e6f6fc,a0b58a49,eefd4d0,11ef48cd,da5a16a4) -,S(4a14de26,ab18ebc3,414c6856,1a77d62a,221821f,8c216496,700bfbb8,21d95b2d,8037ef39,d1f190b1,a24078e3,e554ad1,cf86d5cd,f731478d,b34b6b5c,c9174314) -,S(cbcd6696,547fc496,8c6e7ba5,4caa4a74,43764852,43f479e5,558e2be5,77bbad00,8e0099e8,559db5d,dba0bc72,21505ef,d42c1c95,876539ab,19dedb2e,8e561482) -,S(37f168b6,4b41be85,46abd1a4,7a5ab3dd,5d690661,e41b16c3,87025106,caa4e2ae,8c617348,bce3bbf7,54a121b2,37342794,5d734e38,da08066,c4de59da,e60b5c89) -,S(3aba7081,55dbb35e,dc4a3fd1,1db54446,a7501ea0,d67b0286,8d2e6d77,99162697,829502c4,2dd1105c,cb046e0d,41cd68b4,38437394,b93f17de,5534f014,270c4602) -,S(84842bf5,fb46c697,44eca720,7b1be6b4,e5f5809e,eaeb3e9b,1058eca5,4498cafe,f4210fd5,b49f6484,2efe3089,327673d7,95642ad1,73b6840c,7323b7c4,16d61fb5) -,S(88383dee,ee0db44b,959edd96,feec2bdc,73d6ab56,9333fb3c,d4b18b01,ed8af5e3,8f0cf362,7aba3ceb,104009f0,baf84ed1,f57402e,fc330f10,6e0b45d5,4e0626ed) -,S(ad0a97ec,2197c5d7,4e8eb9bf,9798a24b,aa7c3e5f,ad6ac263,1acd5109,5178d8f9,72b352a7,445db832,2e33c93,5619e7d3,266f254,64a4c4f0,96051ebb,1e37065d) -,S(9b727e4,d107418e,1f62b499,99c1f8ec,55ef6e91,a9a10ec6,8905be97,33903d85,27d6456f,5ea52aee,a190dc81,647ce31d,15ac8c36,de65685b,4784eaad,4a32e41c) -,S(e86bbef3,8d740a44,7a2cb0d0,a89c2106,d85299f8,c38fa540,a7075efd,3a02fe03,8a9f75db,ecc532b6,ade5be9,b855a27e,185895ca,d6a6549c,f6c4c1c8,7e151b04) -,S(b72ac468,9209207,2cb735e7,d424a18c,5ef097c9,3a9b96ef,1ab7e29,d0f379de,89111544,27b03712,e2236fcb,12cbad35,98ef794f,b8141913,aeb1ad8d,ed9e6467) -,S(f8f5819b,203b2bfd,ab2dc532,53277103,2f9caf34,c53c7ec7,7253b314,2e731ff3,433fa831,3dab76fc,aad5bafb,12362126,6d8d7c09,9d513ee1,1b633c6e,e3f1e96e) -,S(8e4a8890,a15da3a6,c14d2df7,d09f6157,d5dc95f7,4f9518de,8aecbc4d,c0ac62f2,c06063ce,1d3c2a24,2494a1cd,db381513,6200827b,78ed080e,3cd14f4,5e545acc) -,S(b1f6dbe2,ad730748,f906d1d9,160996cb,f3f2450c,fa656856,e34f2481,40767081,ee6b2a03,3f3245da,76d01bc6,e61afcc6,94a9e64a,4f0256bc,62acb5a1,82e45ae2) -,S(2139dedc,a8365bce,b9c49cfe,3834e4d4,27a46750,d6b0f0a3,4e7672d3,d12509b4,b20a9101,b63be2a5,28340f58,893e10d9,d3c63fc7,77b5c6e6,a9a67193,13725870) -,S(da3aa585,85c00e41,87db0240,547ff665,376aebea,a24e5aa6,67d477f3,c4d3b914,92405390,d255ccfe,a6bc7dad,4fb1676b,c741e530,cebdaa3e,669bfabb,d1c4780a) -,S(89c47de6,84e1eb9f,a5828e65,dd17a852,7226a75c,3d113102,97f5b8f6,5b67b210,970bc229,d60b00a7,c2354a70,37ec8569,ad615faf,ac77ddab,f5847a09,c1fa57ea) -,S(48ea67ce,db716a95,6b6066f1,e5e9fc71,5994a4f6,f4e2cedc,bf0c09f,4f8c8fd1,513e45eb,159f9865,5ac821d0,e18f4e06,fa3cb8e0,9d45c3f1,8d3c3bfc,48ff3da) -,S(c5ae6651,ded2c479,a3b6c9b2,44fa35f1,2eb1eaf3,fc78b529,42ffab7c,4e33a1cf,ae6ad807,435d4a9e,e8bedcb6,3bc804e7,e67e9418,6494bc8e,384b29e2,31af8cb2) -,S(24e485b6,7c27af76,e18ed116,90c9dc90,73a0b80b,e93f5381,6669e2d,3c0175c9,fcb183d8,696805be,789d83fb,a197fd24,996d3542,b2f3eb5a,c207950d,f9c079b9) -,S(3bb47a19,b1bdc527,a8fe262a,ecee2d7f,1e772627,e5cd5c70,eb2a8c39,f1977628,2d10cdb9,91fb5042,905f822b,68846390,a922da1a,7b7b313c,47edaa6,85217fa3) -,S(7d4233a,cd50bad8,71e0587d,e10204f,6013a784,b65b6540,73307364,5f3078da,be85d3d,dca838a,1f35ca11,1333e943,fb498cdc,63258ac8,74bd6acf,2b934b77) -,S(b5d0d791,b6685aee,2f599505,d01bd3,d41d5a1c,531ac7fc,e6c33b97,cb0ed264,47fbad30,413084aa,619d7bd6,62502cfb,9648e64b,e757d6eb,24fd5e2d,6b1629) -,S(bd6178e5,b1c558ba,432a89a0,482585ca,40ea9922,7c94ce,23f5b081,d606c7f0,9cdc6bf9,d32b98cc,73bad7b8,c08914dd,b9a8c937,913eecca,fff72dae,fa1cddfd) -,S(13ca834c,a5f41671,ce7f0978,a310420d,6a82fc38,fcbd997b,88a1e79a,66fb9375,ae32a0df,7f269c8a,744e409e,16ec3d8a,eaac151a,99bdd7e5,50287005,6f48f6a) -,S(96322802,87add117,4040f802,ed5c71c8,5f924398,1ee78480,4f16e5f3,f0fecb6,2d07de71,cfda4b43,44baf838,7933a372,3d536411,7e4c0f84,2b402156,3f9b56b4) -,S(961efbd2,ae687808,bbe275a2,cba1769d,4ca537a4,1046c5ab,ff269c1f,b9477ad1,9d22a10a,294666eb,5c816bf3,c4dc2c44,d7836202,e15bed89,e3d28822,8193251d) -,S(4e7162a3,8926282,84ac4df5,88301fc8,5d91c869,2fb854a3,ffd34c47,7b216ee4,6e6dc88c,d91b9702,cb38cff,2d6a38e1,d512fb46,9d85f878,8510ed97,2704ba27) -,S(6c1f707d,51b1d3f4,ab261d52,6d0106e4,3e0a5b1c,76a59868,62e9d97c,bc6e3e38,d2563843,5dc8b102,c8f4ee13,dc345f85,289cd499,9bcfbe20,1bf3dc7e,7dae1f74) -,S(3ae98e6f,49d363fc,8416f965,4e57beeb,d37635fa,4e78d8eb,77caae69,f2201798,ffd95480,fcef0686,9ee781ef,cd2693f0,e6be2e27,f207411c,39a18465,4d2c3cae) -,S(eaf94fc3,fae4eed6,35382e91,2cf963da,2bbbda8c,3197e522,e0054cf1,4cdcd5b8,a838a439,3d4bc0ee,a57e6235,5dacfd97,7d70afc9,16e61209,10d13fad,7c1c22ec) -,S(7eb52e7f,bbf5b802,2fa6d66d,801c3632,2c195b6a,4eae4050,5295612a,a184e2c8,b4591e5c,c66521e1,b991f63f,456306ce,cb2e7568,5227788f,a2e9a75a,bd58b384) -,S(d22b8dd1,6ff24603,5fda0ebc,77129644,a8469373,99b2c7a2,60d8e985,d4f2a215,7a9a092,e8473776,6718e2b3,9068e163,e06618b1,6d6bc046,b33e2d76,8649611f) -,S(8f6eff05,f746f0e0,9b328ec6,2089e575,ca64175e,d950ae4b,c67a7ce0,83afa1b2,3681243f,ca51a6c5,7ac92100,f38df1fa,d1093fd6,ecd53231,bfc01fcd,89e38305) -,S(ac9ba060,ff520335,9a4111f5,c8c536e8,e27a79d7,33528ef7,9da7b21,36243a07,2ba3cf76,3dfc0860,ff3333bc,e660ebb9,c4e5a988,909880d4,1ceb4219,89f23f77) -,S(d6896830,62bec27c,815191b3,4addf36a,cee1cfe7,475d34d4,d83a83cc,6dce3992,9f038f46,529fb86,30b19b08,db11c630,70593570,70bc51b4,fc1ced24,f43fbd00) -,S(e815019a,f6923eb7,cf963f2d,476db569,bb04cc7d,78a0bbf5,3b422ee1,caf43b70,984c16e6,593d8642,de871694,800ca14a,a103a61,20b91c17,4e06567e,2d731c95) -,S(3670e86e,e9aaf036,40136ef7,3344152d,c792c8d5,a064c0eb,a511e14c,41d6f7b9,eac7dcca,e491cbb7,cd27a522,a7db96cc,7d300c35,7413433b,9bcd430e,152fcd33) -,S(3d03f819,4802149c,c6428aad,851bd879,189c557d,cc9ab1ff,8e2e4cdf,f0723308,1f56ada,27f2c923,27ed2fe5,88d8736a,fb68259a,1d5b1c14,7f85669a,eaf47615) -,S(bf2ac011,9e417837,d4815c9f,74351869,4395ae40,77429013,7aab32,980748c2,17a47bb9,6f7a3e7a,31b5a8ab,2adc9fe8,98fd94d2,9ea7c3b4,a5b6c5bc,9c367ac9) -,S(c72eea14,ef09c0e6,85c22840,95e73e0b,6aafa64f,9410eb0c,97f6ad4f,64dea571,9a46c93d,256f67e4,1ccb609f,4ce94390,df9c91,38a9d2db,9b993456,13346031) -,S(25463446,6da168cb,2d816bdc,3c9e3a43,7ca3463f,8c8a83f3,62704996,c1bb5b96,3d69cc73,6aca2a,cb97e1a3,cd57be14,243e458b,305df59b,3e3a67f9,fdc17b6e) -,S(b40dbb03,7062dfd7,7151013e,7cb0a921,15096a04,c39f7e2e,66188aaa,368c49d2,34923fac,7b1a4570,e824c3c5,2edd775f,ecf93573,2198f801,8f617db6,474fb519) -,S(23fba417,ff084b42,afddc4a5,c070305b,553ed7ce,1311e5d,4c1f7b2,772c9aeb,af4a342d,f9346ead,89b3caa6,6a3f187f,96f2b470,c0a26752,76e895cf,c5ca4adf) -,S(2e7ecc9e,d4f21af3,a3118799,d1ab7e3,a30d011,edc53e33,93dfdc5,6e80927b,b3959fdc,f6c4876,36813bfd,e7e83b4d,7ee0f1c3,54e0491,f3195b4b,aee2df72) -,S(1c68c34c,8aaa0f2c,7daa215a,961180af,3938599b,1324aec8,7a1b3841,710db2c3,d8d68179,71acb598,5cceec45,fc5a754e,e002d09d,4be45e8,ab6d2bdc,ad094b24) -,S(fc0ff082,ca6708eb,9b9294b6,fabef142,2cddb5a3,611dffc6,f06c05e7,f1eeddea,6f67fbb2,df22611,e2f1e796,c67d6c3d,14b17f98,2b6e39a2,7bef257a,d6955b70) -,S(fa683ae5,8dc85748,1a7ddedc,708865b9,267e9fe2,e485a243,1d005e47,64130548,4d9759ed,76326207,891a9649,3b4d2307,b9694fe2,c15e2327,a79dced,db8277e2) -,S(3cfead76,5ef36c3,fa9903bf,6d43cdd2,46ee8fb3,3fa1d13e,42fe9818,6d299009,85a18ee1,da24ebc7,3dd87aa3,ca1e7565,8f868fec,50225e2c,d5b5480e,cc0ccd49) -,S(487fdda7,364dacf6,2fcec7a3,fc2dfd27,c38079ef,d48f0220,85c62746,2c8ac658,1479200c,b06440a7,186a946f,83a137d5,7e5368b6,7ef8a66a,9540a131,e4bc9b8f) -,S(f3e413ff,81c2ee72,74c079f3,451f41c4,bbe1e51,f7c3a1ca,513392bc,9edd487e,46544553,79a33a0b,13fe5904,504cce47,55d0e2e5,6c4163a5,14d5b902,906caf54) -,S(d93692b0,53ad5194,b70b9be0,1dd80926,e2c93754,328b3eb7,bc85c45c,63e6258d,7221837b,3276bd2f,9ba0981d,883cd68d,97d2ce77,9dfa1073,d59b01e5,df311ec6) -,S(e85af4c7,42fd5424,2964eb26,b531fd77,550d3b2,eb64bf39,e97de203,ffe2d28,8368322c,e40ffca8,49ff1a53,76cacb17,98fbf4c4,38f58690,54dcb642,f805b9f1) -,S(9e4e35a2,d913a2e3,bc931c59,298ef6bb,3893b086,ee40c978,430d8436,49fce4ab,ccca94d7,d4bad95e,c15b19e7,9555579,d47cec60,9f42112d,3d992035,6d31f7be) -,S(7d72793c,dcd78afe,23e8b000,41d67983,6528b1f2,6978e262,4d022416,7ac5e741,1189804a,2558ff1f,63a7ee1f,ad5f8ab7,50a412ff,a83a9783,996e5f26,637100fa) -,S(3b8dd2bd,ca65d7de,6a7c55bb,47dd5ef1,5ce6f533,96ab335c,84c0c9a8,4e06a7da,2ac78cf3,e1baa981,b27dfc9f,e1b7cd2b,1ed4c37,f96af6e4,99bca1f7,de62aac) -,S(128aa84b,3d920356,db64bc95,b52d4c8f,3054cf5b,22c6039d,1d21ea60,b2274c44,5a748932,6a98019,824a9d7e,cbea2de0,5ccbd9f5,a2cc5dd3,ee0b3dcd,a92e8758) -,S(de8b04b2,c761b876,4c41c344,a3b57c41,fb62e6b4,ba25ab19,8fc2ded,2849e151,134ae148,d89de734,a222b656,b878fedc,886d5928,fc6bfab7,bdd0a74c,3753f1fb) -,S(f643025f,9fc3824a,6ce70677,23475aa8,8df24d59,682f5a6c,b18b1c0d,5e297017,24eb7c8b,e3de50a7,cb473bd8,81db3515,8f9484f8,8574af66,a15f920d,3986a049) -,S(ce2e5454,54324680,7035594b,1aabcf6d,5d8cad20,729a787a,7e01b61b,106fdf19,f3a2e5d6,745a16cb,3403a768,c1de8f73,cd26388c,c10f296f,f00cf9f5,209b1555) -,S(bafd293,dd071a21,25a857c2,6acc5afb,ea79093d,3c9771c3,cd3b875e,b74b3280,2d56802f,b8f26950,4adb2a51,a91ad2f0,d1ee6501,f8c9279c,6a27b524,8dddbb70) -,S(10e0909,5dc7ae30,9f1afbfe,1bcad71f,c66489ad,56256c3c,a648f554,c000f414,47a5a7cd,968dd158,e8436399,40c30179,3807713b,c09fb0d,83c6c851,c6b7029e) -,S(73b8149b,4e7bf050,b6cd9f4,93c85bf7,61062329,2dec76a3,2d7054b0,c794da63,44cb915f,b6813c71,dff3830b,ebb6888b,76312778,897903f1,d9988c37,3c362bbb) -,S(59a5dcce,9773617e,73c529da,6015ca40,bf923956,339a366b,84a69e23,d0a60fd4,4c62abdb,c4453ffa,2b806a6b,b823fbc1,59f57f23,2234c8da,a471192d,3081ee09) -,S(1ad2aae4,f571c6ff,1abfd45,35b3d085,1aeabdbd,b3a340f6,7bef0f78,f7afa954,1c394b1c,94539758,85d72498,b36a3be5,56b4f80,8ef52977,b0157885,649549b5) -,S(2403f66c,a6a7d60a,254b51e9,32cfb700,f37ad73d,193f25df,6024bd51,d0f337dc,9ad75d44,24517aff,7df86c,9bf4f315,cb40199d,4a2a5d5c,74044c4a,9c79d69f) -,S(f3139f4b,50dba596,87080a7e,b19bcc34,2b58df9,26576bc7,dfdc8e7,4914c524,fbaad228,ab34e8d4,451cf6b3,a1dbe225,bd46bfc4,8a4bcd94,10c150fc,5636c687) -,S(ec415f8a,81b1f559,714dd790,2441eb9b,c5c7bcbd,e87190c,c109ca04,a3e75149,9b90bd46,d27e0200,369fe995,3b50752f,d00b9472,fd31383a,f01bb88f,b223bc5b) -,S(5e336f17,264a53e7,d0899bf8,6f676440,f83ea0c1,5d53fae4,f19a71f6,998a3ca2,2a86fd9a,8358daac,828d42e7,9c6c0fa5,bf977cfe,56899db3,27ea32fc,cdf09f3d) -,S(98828ad8,a6ee9ca1,37f9ec2f,f0cac84f,5e664e09,68455773,3f8fbab3,ec38570d,ae7ba3cb,e617e9e1,6e67f34,f69af863,3e69c9ca,1f46b182,88126f16,9ec0e548) -,S(d6a7c2b7,169348d5,1d98f0c,27464732,6f67ad5a,4809acb1,6b783fae,36808436,698cc098,ebe430c5,4dc74fe5,dc300f64,7ac0a002,4109e002,d2f43ffe,89fb3d9e) -,S(9bf4a4ea,9fc4b731,5391b653,1d3ad3a0,f0fbaf59,b99f76aa,7807c442,f8e63bef,e69fbade,598fccf4,6f1f0931,f37f3c55,900dcc50,64e54ae4,191796fd,a4791068) -,S(38a09628,aa450076,3826f384,7e63121c,d6e9e645,f6ee0f,8cffb106,508021d0,5460c8df,56fb7d67,992928c7,fd969f95,d29de37c,14c2c9a2,2d60d661,6cb7c383) -,S(dcf8afd8,ee73bc87,c17c97c6,807fd3e6,a9c57a1b,cca058a1,ad24f2c2,6e9728b6,efee9612,3e78cfcf,1dc3132a,fa4ef492,12369710,fa2e8e99,3cc70b48,6ba78709) -,S(9c26ca1b,f52eb7b3,a0d40dc,cf546591,38945c43,41e0c611,40d0662d,1033420f,4bfbeeaa,ece9f2e,e11cc672,24749c3d,e12be6d2,d3d21d90,ed742d,31541ec) -,S(2209194a,6a3b76,1ddb2b1,3bca12f,3697248,4bec29e3,102d7734,9832ae6d,7dde1b85,cd00a08d,38035f68,fdef0576,c458476a,93eddfc7,4bd4927a,cbd64543) -,S(6ffff27c,ce5efa3,a8f8af72,edcfc736,9874abf8,5d15e1f4,cc71a186,9a7a29f0,27a0e163,bcdea297,1abe52a8,a92fe191,38b839f4,67772c83,81504328,fad94a2e) -,S(34e91b7e,e2c5f407,8a9d1ec4,7e2b2c02,1b8480b4,8c3b6e47,19cacc36,b4250382,8d60947a,42d88728,e0d67d2e,e9a0559b,55cf3887,92c733a7,3ed50b25,3706cb82) -,S(3b2de979,9106333a,98504128,e2135e5d,7deae86c,1c921c58,529aff14,12fd62ff,4ba40985,8c5b594d,f4bf5e81,bd7eccc6,3a7bbbaf,fb32926e,9a47503e,f031d86a) -,S(fbd44acd,9e593ac2,12fd1f64,c4e18d31,c3b3fffc,ae1c88c4,6aebaddd,ac608b2e,9f4feb5f,2ab68e29,ca64f458,d162dabc,7a05c552,2e38c4cb,74529e3e,41d805d6) -,S(d21c3321,bb6ba2aa,dc0cd52b,be68716,864ce1f8,44107374,c0481c0d,91729b39,2b51f18,7b95725e,f74deb00,8e9d96f4,f1a9bbb5,c9aa28fb,275f700,bd964566) -,S(ea2d29,f85855db,78808749,9ed79c2c,614406c3,adf64663,8756b60f,16166578,33971e79,39faeedf,15b14607,37fa7112,7d6f49aa,fc423f63,783e808d,1fd10369) -,S(2a1a6709,301ba6ef,c5ad4958,e29fa73a,caea18e9,e01214a9,65291977,8bec874a,56c971a8,d29d6641,9c05fcc9,9b0c0156,a1ebd007,bcab2cec,b9e920fc,85f796b9) -,S(aa870dd5,6434af8a,36d89551,a7109cac,c1d0c5d9,f5e43630,17bba88c,579cfb6e,d1fab1ea,cb5652f3,cd4d5836,82aa3cb,3b1b6854,c0ec1157,41486028,73625dd5) -,S(e979a3bc,5165f53a,60042a1b,11e8062a,e74f35f2,d70aab2d,b250a4a6,f4507507,4de86928,b9dfb2d,8509a1c4,8efdfbd7,a5432933,e3f12789,cd51ed9b,b967ff1e) -,S(620979cd,f37b1cc5,b1fe3e01,f761b8a2,ffc29bfe,8afb7cae,7ded5cd,37f97829,cc971616,6ad43824,4c6be489,7cac0b95,afe5ed6b,11be673f,d67f0d89,6d58f7d8) -,S(90a5df7d,986198fa,70152c7f,e2abc14e,2c80d5e,6b75b42b,aa042e03,f3aa00b3,77e0ad,2f3e1eed,472a543c,3852925b,327e3eb7,aae59030,2d7e12a7,862201d5) -,S(17802140,e10d8be8,ef210b69,b7fa1afc,16a85d9f,ea1150a6,c6e5e234,cf638446,af4982e7,fdcb7a8d,b6478b54,a5bd7cd7,c48d1dbd,2a3d003,7e87b6e,13c9f5f0) -,S(1f2b8d3c,fe515cd2,53f66b0d,59fc51b1,4cf75ac5,d9c7b4e8,4c75d92b,f0380b8,6902b31,19f38b04,5b979f94,cc140481,d4e6f7ad,b3efe12c,4de1bfcb,c71be72a) -,S(aee51eec,9e5dedb2,1619d114,5594ea7b,27e21a4b,37accccc,d5fe522d,2e46d29e,d40ef18,86725504,fca42c2c,b8b80dc2,c1028b71,1bf3fb18,9fdd579d,f7f0ff8a) -,S(40fe6d08,b714ee12,a4d643b4,21b331c4,fbac165b,d7cd88fc,ce35a873,875bed7f,c32f1cd6,3083a976,6b7dd8ee,7133831e,6796709a,c67953d3,4ec5d8df,922d2743) -,S(5425c555,8a6f9068,946f7075,db347e6f,cb6c723f,c5ff829f,1634fb2,13b3c820,c218eba,db4e3ad6,e41a28ba,129a0c1f,8626ae2a,16839b77,ba12257a,a6aa2318) -,S(83663c0e,f024207e,16ba74c5,ca534d37,733a7dfb,b2d531bb,21a28243,d0572a00,2699a48b,dc9af87e,bf18c9a0,929359cc,d7f2f137,b84fc070,2bc3497f,69c83d45) -,S(bf931d61,e72f217c,3b820b63,282f5d4a,c929134,efa06fff,88480f86,f6247535,82553f48,bc40dc42,cb8bb098,ecb84af6,5cb3956a,aae7bd0d,cfa9e181,de93c21a) -,S(1c6e0876,3c2242ab,17e2885a,537bef4,e8920782,9c573d00,64fb83e4,910312c1,b7c14efb,bea753a7,5d8a597c,7f1a716f,8ae4298f,379aa64e,d070ab2c,28e66185) -,S(9a2cf62f,9eb5810c,31b27614,1592f201,1eb158a,3d123610,99af0b77,7d42c0be,159ac59d,728d1c49,843a0207,e47d1cec,7b9b773a,9ddaad52,3ff27d78,d2767d7f) -,S(3596950b,393a56e3,443c3b93,b4f8288a,7faa8d74,d26cab37,dd7a5b4f,6a9e183f,f99bbbdf,c566b3e4,e65dd63a,15c727a4,403cbe85,202e45f4,ea5d3462,173babb7) -,S(6f556cb8,f5da812,24bbe628,6dc4e379,ec12b124,21cd95d8,6bb1d580,a13b5c37,eeee3133,1dc89e57,48fdf10a,1fc0693f,1c09aece,aa27dcbe,919d60f7,4748d656) -,S(b952070f,fe60bf94,cb14bf68,b37e3e54,bd9b8063,ec8cd4d5,20408756,bd318bff,57996eae,d38f066e,cb3f8113,aab5e4f7,f322859e,1fc075cd,69ad1ce4,3fc48ff9) -,S(dbecc166,8d94b2b4,8d37c133,26fffedc,3e690b76,87563677,23352ac,1eddc2a5,f124cd3c,e42f56d8,a7588145,e53931e0,ce8b79ca,ba5195f7,3dd861c9,9027823f) -,S(12dde570,aae95b1c,7cbc2da1,ed2d936,bbfa5155,f61979b3,e67057d1,5fe5e1db,328711a9,c30e4455,e2716e60,3bedf4d9,8fa25d1b,e892ac72,b5be17c2,b25ca311) -,S(64bb18aa,fbfb7def,3493c920,d2faf9c5,57856710,766b0bea,275db46f,f8271282,717c28ed,e9284844,49cd0db7,180cc5fa,20ba79d9,41c979bc,c0a8f274,3e2e2901) -,S(a798f4c9,bb3ef48f,d2ba3df5,2b040611,d0d5532b,9134aa28,e21b5585,d2379ee7,91f903cc,a4628477,b208bdba,59ecd246,bc50be70,34620a44,b55e0e9c,214e563e) -,S(7bfc5902,58f80000,82946c5f,a1a352aa,808fcc59,4bf2ed7f,bc6dad3d,8bab00ed,17b5dde0,3bf6a814,efbed180,3e5f1950,59499cc7,13e727d2,405e0748,2f912cd6) -,S(23bda819,978c9a09,864a1c53,e0fed0d6,ddc18777,b614780a,1c6fe08e,c35a820f,aab57ee2,7d226f88,6e55b8a7,c4d7a245,7badf96c,9312906a,3efe2cfd,3292af5a) -,S(8f649152,54696b2c,1804467b,e1619ba9,d37cd874,88db9418,1259d69e,135e1455,b05b39ff,241ac0c7,7e2fad78,da585b09,c98815e1,b368040,d493bbf1,3ab54ac1) -,S(177ea3c9,e592ca96,e9e0ef4c,87cb00a1,cd51ccb5,1e1d5252,963cfd08,77f30331,57185496,db5e5971,24e55b14,1042ef30,99f206c4,67415318,ccbefdb3,b18cacff) -,S(16042996,9ab25db9,e4ee4231,7497a607,360bb1fc,96e74d66,cd87cab4,44af2f36,1dfa3d9c,c3acaa95,1f7ad037,bea4c20f,c311a8d4,c2ce9cb0,bd30078e,b0ff64ce) -,S(10210453,fae1b545,de76c4a1,4b6ea5b6,172ea157,1fa60696,25753231,2630e29b,ec8aa759,5708f292,72e2ebab,eed6bdaf,955b27a1,469758b8,44c2668c,42acf576) -,S(659574c0,39345165,e35deee5,ab4c3b09,5b873ba1,fa14283d,6bced3f1,d562abc1,1a8b17c1,bbd83037,b20fc2ed,495b890e,526461c7,8f0b8d61,e94a35f1,bac9520a) -,S(a8a00f02,174b4d3b,9ca825ba,88cb1ec4,4c188343,5478a00f,38025a5d,1e2cfe58,fdac00d9,55b6872a,62a36dd1,cf666423,b4dd6b4f,4558cca6,d931a1b1,1e42561f) -,S(3ac8f67e,b4c2c3a8,2cd90fce,f612ec7e,7daa1072,6e4f8da3,57d9ab96,56e30414,15f71b5d,17dece22,a696fbf0,2e360226,bfaf685b,6575fb99,68fd52fe,7a21f9d1) -,S(87c56593,9fc7bce5,650e57d9,37e77642,a1ef510b,dadd117d,2732d316,a4f2ce19,59908fd3,e2b646ea,210606ed,c790851b,4077142c,ec7733f8,613dce61,3431570b) -,S(6531e4a7,f9cbc2f3,f0448bb7,f8250542,6cf5c7b9,d4a1ec6b,80098799,d5e43101,622a2201,f3c0f766,6e81be2f,22f1ea60,f4b45807,6800fae8,c353c283,b6ec3d7) -,S(e2a5b419,cf421b15,859aac6c,9beaefe6,29293f39,3beada53,e1ae567d,9bb7cb34,3c20b681,578aef9b,138f852e,90f49526,6d30f3b1,6ea2d3,23dee943,1af4a5af) -,S(d4e9df61,35cf81d2,21003bc6,e167b6c7,9e912c1c,2dcac775,f7d9d07d,6ffc7334,c8f54f41,513d7bde,3055c7f4,8436c812,898770da,754ed9ac,d6eaddfc,a80f6c21) -,S(b83ec734,10a1989b,988e2bfb,a46a421e,dc3ce47,d549d838,8970102f,98a6943e,4e0274ef,ea2966c5,200dbca,d8090f78,98bc66ea,44164fdb,31507ad1,e7e5db5b) -,S(ec57668e,12f0590b,e99a75c7,82c02ef9,88354f47,522c114d,bbdb9591,238d3eb,2b3c508e,81a3f696,389a5ec5,974a1bac,a572c042,69ad2709,25001215,c58ad7e) -,S(5acca76e,7578cb86,8d5ba7f0,aadfcf40,5ca4cc52,d778712b,785764a1,2afa01bc,7b0df4a4,5e048fae,65a0683b,ea0185ff,f867a578,179c153,5fa93561,54138359) -,S(bd563b91,6419f92c,43a7c2d,7042fa71,fd88e5e8,41115b5e,36a673cc,93de4e07,4ec5b773,b35a5579,b7c729fe,1cde3b32,ca34f97e,83b989b6,fe756597,3cbc840a) -,S(a070b055,839d93be,2b4ca25c,a4a6b133,5ef7d09a,268bce7a,fb1406c6,42e71025,d3fe8577,1241be24,ed209e8e,b5b28ec6,e3a0bf52,27f36036,3a7325c7,5eeb6acb) -,S(9c50323f,c758663,346c5863,84d5aef1,123b4338,eae00ec6,86aef2ed,e19b2f06,1dd9442c,cf588e6,6a3cebd7,bc68f2f,6f270d7b,bf01f088,a49a5ce6,da430229) -,S(90fe8f78,166e3f6c,2d19bd0,685fa2d0,1f6bf06c,2ea220ba,cedb0f22,ac9c558f,826d63c1,60fe3875,9c5887c9,cabe8f93,905fa1a5,e87a8272,670cfaa,ffeeba13) -,S(d2f44fa9,b704491e,69488c44,cc8ccd29,6addc630,2fc66900,1703afd9,a2a5d3b9,2de1d619,247636dd,ce1de2d9,75f14515,ec5807a8,c7c0cc4,5c7d03dc,fc19352b) -,S(17f1ce71,9e3dfefa,106e95e6,62786729,e8ec2bf6,25421ede,ca71ca14,5782b23a,62b51d27,74f514cb,5452cd29,e3907a7b,b39a9b9e,400d78bb,f6cca78f,cfc1aec5) -,S(5b1dcad4,5974f0ee,e99d7c23,83e48585,24428c94,daa956af,cd692c4d,5a63213f,6958ca48,f13e31aa,c52e531f,886da246,5ba713d4,748cf6e0,de16e0a0,366c33b4) -,S(ad284e67,a0682585,f18be40f,e966b605,8cc787be,c265606d,12f202e9,31f3067,c86ce860,ac3c3955,28321cb2,508e4da5,abb4dcfd,2844b95b,ede54ce5,b17e45b9) -,S(9ba71712,dee6f0a2,7352cfad,59f6c0ff,f133b1b1,37ecf884,a537b672,a4275c8c,b910f036,f906a419,21fd37d5,5e0273a5,332edf68,43dd8afa,43070542,b0849b40) -,S(cfc757d5,171c9d6a,ed8b9123,a2b4a405,d8e869fe,e80aebd,75255454,ee6319a9,43dc370a,c2eb8fb4,4f78940e,b41d614c,ccf2cd7c,c4f324a7,92ba37bc,7e48144e) -,S(b8288ec3,2e4a569,27df3e13,6e81498a,bc9a52af,80d74bd6,c85eead8,85e0c49d,a0d53c40,d2234ac2,df69605b,1422bd1e,4a1d77db,fb0d7269,13de63bc,a2f96078) -,S(3808cddc,497c9065,cec574e1,3b82a10,fe2323f6,65a99df,1e724221,3eeb9a79,eb046225,eb6aeac9,5659f1fe,75dd910d,2932cab6,9b4b810a,d83e7681,e0c32907) -,S(a1620bae,cc99c311,7b3889b4,7bca5d99,4ecfd67a,ad5a7461,646e55a5,19e46398,5cc4b5d2,edc5f7a8,54cc3054,1c7ec571,e06c59a,52bb5cf5,5882ec18,1b07c0fb) -,S(f1d942b2,bff74aa7,1f9cb411,91ee85d,e6955802,4a4d46eb,53ac02d1,32fefa93,19a564a2,8352bc48,a8dcd932,50274bd6,496cf488,6e2ba390,3cf91631,453f57ad) -,S(1a4e3836,a34db30,c47ed6d5,9ba6fb83,fcb7a5a,a0002ad7,1b93b154,a5fd566a,745e195f,d94900b0,aee3c5f8,7c6fc62e,fdddc18b,984900c4,20c77ba5,4141cff5) -,S(af37075f,866d7aa5,9371a08c,1e7aaa5c,d23ee51f,54428fb6,84c09b27,93b432,b32e8869,fbe53ef5,4250e803,facc93ff,a100a84,becaec5f,872d0548,da4ae9ad) -,S(88e39f4e,83a0d6ad,a1e01ac8,9021a7ea,fdd1f9de,740bc10a,4d572c46,fcee9330,a14f6881,bfaf691a,96249322,37522174,e8a17920,52da7bec,a6c77d4,5fb8a357) -,S(8e406574,a46e56a4,dd4cf780,9a7ecfad,5a1f9225,cfc2fbdc,6b7bfc84,a5ce14fd,bdc6108e,d5616bc2,3ed52c5a,1314642e,a9272707,20f00be9,62e48945,3550f167) -,S(aa31e1fc,118e00c9,8b8f561c,479c6427,8676356c,640304a8,3b687a34,8ad4a091,31c95ccc,2520c0db,7c7440ac,7e640be0,7a8ba4d9,c0020b1b,f31418fc,98d9eb17) -,S(ef278702,becf4f15,ad43fb6d,d0114077,d9f8bdc3,ff4c78d4,d0a2a15,8fe160b,377dcf3a,774d6416,58bf108a,87201b9f,f28c70fd,449a77f3,966ff441,d89246e1) -,S(d1903199,b9762761,fd02c4da,99fcc503,ac15332f,4be01b7f,a044c5c3,f848ebc7,662ca3d5,9ff2c5fe,a75ad64a,f7044a94,60abbc25,defd0a3,aa6b0e6f,2c7f4f3d) -,S(682ffe36,6838fa12,827ae055,7e38c12a,bb571227,47643f26,9cb9f1bc,922b07ab,4531b021,2e8fad86,6f6f67fb,d8eac752,1a360968,f0f9792c,a4568a55,855924e5) -,S(418fa3e0,b32be1f3,f06b96d9,728aeac3,3294ea8f,16f35139,76b30801,81d8e833,dc1608cb,68bb0480,859c9983,6baf9558,9451022e,b9966e0f,498245e0,2183ef80) -,S(e3f7dd7c,f5898b7b,174cd809,5c7c0890,4188bce4,bd6487ab,e974d979,f7faec2d,5ed5ca26,77d3bce0,15a6cb51,9922a55e,9ac1adc0,61bb0774,503e79e8,204441ea) -,S(810ecbe4,f43814f4,e658ce9,234d71b3,946556d7,2ba9c3f3,6fa04b,4dc25cf9,5fc57520,81397434,e395a752,560a8a76,252e6eea,b9ec067a,16befea4,1f1bf1ca) -,S(6dc50f0d,7e9518ab,fa16bcdb,f43ecb2f,745d5ee4,7269225e,36811819,6542b7ff,dfd5e416,2d596f5,b44602c2,20a87cfb,77473aca,6dde260f,856b3295,527bb87c) -,S(d39c9858,5ba2a859,a6fac25d,602c8e1,fb205a88,7aaf628f,5d1a210c,bc648fb5,6e92fc09,9df932e5,1bd0c6bd,5b6567f,61a1e8c3,93d69add,111e9320,661ad724) -,S(d7fd8580,59c1a86f,1b81c05b,ee63bda6,8ca93c4e,5ec99e91,88d9c7f4,40dae0d6,ceb56f19,cb3e5b39,64a4c58b,5cbeddcb,c736f0a1,8a2f8f3f,f0758f24,525a8fda) -,S(2e269d93,319a79d7,513e6f73,918638df,c4b1b7c,4c19ec83,b254d780,dc45fa87,650b6846,4e8537af,583cfc48,caaff61d,f31dc67d,5a48e0f8,5857d7c0,9bea1d70) -,S(19f396b7,7147937e,bef30096,44b292,2a6e3c6,5b5c929,22b73118,7120224,4751cc23,4d49e926,651a9a29,c2a8a55a,f7e4b25d,9cb4bd2e,83530bdf,494b131d) -,S(88f843b4,e3689ba0,264d6d4b,4d310afd,85de2ea1,6fbe7275,d33112c7,538a7c02,5dba8024,30d31ef1,412f2310,3ccc5951,66e903a,55bb2a35,8be1e715,27fe45eb) -,S(b1301f5e,1474083b,3828ba5a,837efc44,21990da5,275f6b1e,bf773b52,5ef14a1b,f9fa0af5,b508ca7f,2345d06c,5bf1e5e4,907f2b19,3681837a,802259e7,7208864) -,S(63bb3295,b57ac21c,4b96ae49,92b8f3c5,7c23743d,44ba348,195c5f58,d5360bb,f5e6a98,96683293,af6b9ded,f9f163ba,15b44017,120c61bc,c9e51758,f3ac793) -,S(dac9f722,7d0c012e,e3e1ce88,a99cddeb,9a23979,14c1cf1b,915dd41b,8ce27687,85bd90b7,7f2917c,cf1ebd47,3bfe04df,386d37de,69893cc6,9e79ae89,2255a12b) -,S(ef05aacc,a8082759,33719aa0,e0958f6e,4be6a6c2,3458f243,f84fb2df,9aa422f0,d6006b80,bf611afd,3f1ed523,988b3e8f,d44be73d,565ef30d,911e4226,ae546f23) -,S(dedf3d9c,807065ad,8c1e3714,f682ff86,4f6ae08d,6bc15773,53f27677,ff86783e,7bf6f3f,1f3e5ca6,6902639c,a0b071d9,50dc2331,52f1b47b,5c68923,9a1cccc6) -,S(3db2b461,d18b367f,cbb4aae0,7a73ce9,6c1b4cbe,140099f4,d3839764,7414b5da,515ead0b,a8ba7b25,9f04484a,4c55b532,5686b882,77562b99,21827706,a036a142) -,S(5516a03,3da8cc3e,28170010,5e8d57f3,daf5bb84,596c040a,3d2ae05b,41cecd4f,6bf44084,f0ad14a1,f129a267,e13b0717,6d2fd274,2d4be75a,2192e54,7ceeebf1) -,S(7bd86d5e,6fa18e26,cb0b6e2d,faf2a4d6,a784e831,2e7168bb,8e660e3d,92514c3c,9b634094,dcf4ade0,eb49eabb,a26334f1,7770bb94,b776de46,64d847fb,f1574afc) -,S(a24a8b40,d63c242c,3dcd2513,fbee3c04,cc15117e,aae40daf,b39c3373,e6a83bfe,49163714,afef59b3,b503eb73,ee091349,e599c563,bac4aa37,13d7a6d,6f5271a3) -,S(acbbcaec,8b01374b,454208a5,19051ebd,e5128307,785f7b25,706642f7,775a932b,102283d8,1bd1e9e7,e5641b8d,a701f51c,86047d76,51becfba,89478d8a,a6226572) -,S(efd5654,8f37a094,19f9fc11,6d818523,c4d76725,860d49e4,a1cd8434,a0cfda99,d521204b,da2b9db5,dfa47c9c,6ae4616a,52b3caad,5440e4f7,f1fc41ba,766bc180) -,S(15600bf3,ffca622,a163244f,47789725,b4c112b6,e3d7652f,fe829a6e,386041c3,b1a1ddb3,e2b0e170,8cc9e6db,13c7b111,93673cc8,397d9b59,5b4e8dea,a39cc5f7) -,S(8d14cebc,62f7cd8d,fc60c2de,d144c76f,55d9d6c1,be5380ca,1e1ecefc,5a85cc53,244bdd67,5030a8ec,af876f5,99a34f98,ef7388cf,e6705734,540f57f4,15641220) -,S(e3cb7328,29c6d09f,6ee940f6,5f30c79,7dbbc26b,b8b8c860,f6e07088,a485ebaa,e50a5c44,6768827d,ddd57e18,68064e61,51c8951e,e4cd920b,b664ca06,67096db0) -,S(9a18212d,45364ebd,3ecf4d76,3efcc66a,ebd17b7a,f8bb7f65,8679664e,16888e47,85297209,abebf492,ebeca275,bdf3bd2f,987d1e29,6bcee299,9d6e59e9,2b890143) -,S(43366191,859bb3bd,5b44f1a,d9076ec9,5439c082,c99f70d7,4363117,8020521b,9dd6d890,16666a3e,6bd8c0dc,76cc9792,fe5d76b8,c49cf9e3,75e031c8,bfae2556) -,S(1b77e51c,b11e514,29955ae2,37659c5b,a8050ddb,685e5b74,fbe38506,33bf9358,f198ea65,1ed4a743,a14fb905,fd0bfefd,843bb00d,675781de,5fb1552f,c7f382cd) -,S(7cc6fcc5,558cc6b7,156a62d2,e823631,e0b95e8c,57fb79d4,b4aa3ff4,9cb718cb,526becaa,c0c84e61,b3fc85f,60d028d2,eb90567e,319bd6f4,12b1a36b,9c3d30ac) -,S(18c1e51e,10a7dc5f,7783d511,6f2c0457,664ca2eb,6541ff29,591ee59b,f9f958cf,7f72840e,ccf4d03f,29ce01a6,725f6b97,d701a935,bce8a2b3,c1e44904,cf98a300) -,S(3b9335fb,b191bc9d,17efec98,77960307,2648edb7,2c427521,34df37b6,f1620c44,ca526125,8239c80a,1ae893b,268d28c2,b02d56f2,d03a8a7b,aca25def,34d6d694) -,S(f39660c7,ba9bf800,381b8ddb,d783dc6,acf8c183,95f9144f,688db8c9,9d7874f4,c5037625,2abd41f9,7574a607,52be4c31,e5ef2874,5e9d80a8,da2ea676,4bce5cc1) -,S(d1d2872e,ee06a4b5,d3b735b1,9db1d88e,cbbf9ba6,89c1e411,980b2cde,e70c86d6,dc5cd630,859fb9da,70f25023,5b7bf2ec,938743a,a9f04fd0,69d1d746,e3ebbfef) -,S(aa4f71b4,720f6470,8b6261a1,ee97bc7c,ee85b274,caf71a6a,1f7f000a,b06a1948,958fa65f,acdc42f6,c1e98f7d,f67ccc39,14dc5e8,d20bb872,32d7c898,e451c017) -,S(85904824,63e69633,42cd1e89,1502c309,d74e1722,fad8e766,d7e8f566,49bb732e,585601b5,5bfef406,ec5f71bb,6bae29c3,c5e77247,befbb549,5ced52a6,da64a2ff) -,S(dc899ab4,89a12ac4,4152ef63,48553ed8,29855449,c204327b,bcce6418,75df4d99,6791a965,65fb749c,44f133d4,b3c9c8d,77488831,c8a99ba9,7b66c9b,43deddb2) -,S(2fd60f25,3e0b4f1f,2589a096,f9a0ea3a,405906c2,690fce35,ac7df791,f106020d,872d52b0,1cbfc3b0,ff699950,5be33b51,64a7054,bb00e22a,9a87d692,dccbe782) -,S(a74830c1,7f816549,cd617b94,c0360b8c,9206b382,6782d351,650785a7,fb71212c,fa928b97,75b28be7,4e340cac,eabf866c,fe7e7299,7c276680,2d211b1b,389823b6) -,S(fd450d48,c59fc4db,e3366b43,caf00c2,bd10045,842311ab,20f8e24c,6a9a10b7,512d1998,db747e39,34451fb7,9aaed7af,48801051,dc8ef756,4580db9f,bad910d) -,S(c0816923,9f2bbbc7,34d52def,79f9f4bd,cbd8c435,d90561ba,fb23f12,f1fcb93,fa00c81a,8c5cc2d3,5f78f0d2,475851f1,73f70cbd,cf2c950,8ebad1ee,b35a0852) -,S(247c4075,9a0e7098,25a5d82,4fad3419,55103052,bcdc7ab,fe4e559c,84a04a66,8da3cae,878260ba,1b95a5db,900f20c,12597187,4191cf21,939ab6c7,fe378067) -,S(fbe3b30f,16ad6608,32f9ab15,2f44076,2f7a09a0,b07b12b6,4375db15,37fa4e9c,98cf3e68,2a914c3a,ee54971a,793a9309,8c63aab3,e2db5389,3f05450d,61b9080f) -,S(79f71ab6,fce86bad,be02055c,520e6e0d,88e98def,d37f2d2e,488bf455,3ec954c1,b5de6a0b,c1745341,3023a650,45262a31,e9264089,8a655b0a,4b3042d3,a9114330) -,S(d190f258,e2e3bb8e,6812da59,606f2f4a,2e3fd1ec,34e2c80a,9d280f5e,e1e9c4cd,98997b49,afec7d7a,26a26f50,9d4948c9,b5ebf9b4,3eef6183,3a2b7a8,6183c267) -,S(24f355ca,c0e00545,f47e199c,3818e76f,534eca88,776ff6e2,54244686,24f0b636,37710da6,5c3afbb4,308d5906,7ad044c1,4df30f03,427ac83c,23b829f5,37d25b46) -,S(bd221461,ae73e639,6b23d269,ed6907ba,330544d0,80342de3,a769d3cc,668cf536,a5f25513,3967fa67,b22dbe31,917d9d1b,ae11a1d9,dc7ab731,26e8f0e2,fbc8deda) -,S(cf0371e7,22194be7,ac5d19c1,1b447978,b38f8a1b,dc1dc3e2,471d4a8f,75d0f6cc,4bb04426,94fe9d55,cc49dd4e,e168b604,564b95f5,99566f3b,9fe2fbdf,16084f1e) -,S(ce21a5e0,287752fd,ae9e04ef,363540ed,f6736c34,266a2d77,b5d0bb5a,868fc32a,fc30fc93,bb5a2731,8b81b942,4fe330d1,878e710e,b9a44fa7,bf4cbfa7,10c7d0dd) -,S(7c95d800,da4720a4,102de774,d585f230,2b849e57,1f42982f,a785bd15,334b4b12,244deb56,fa5b4367,2c39693a,f09083f9,2b153a9d,4829ab3f,ff604fed,a266b30b) -,S(40bce9b4,f90489f4,d392fb93,3f98f71,e9281976,164b25b1,982cfcfe,338d93e2,5a9ebed7,25bf11e8,7bbec766,c52309d5,e2036454,447b8ee6,6dc79dac,7a2a9b4) -,S(f15a2ed8,2c00ed9b,9e7a9338,2d08c46b,33ba7bb5,dc15f5df,4cc29fdb,86f11c4,d02ce92c,e556287a,3acd4115,a190767d,2979dd7c,7a32dfde,cb6d806f,6e7d0205) -,S(4230d263,d5a4a915,cfd863c0,e38514b0,4929d352,d8a90c00,c0ab9ee0,56215932,4b134eb0,51699656,dedc7704,3d5586c1,62134b00,e21ab1b4,517bdc54,5f05fd69) -,S(6cd6bfa9,63327c26,fd2c7aa4,fc159956,1a90096c,dc88f414,d5cc9c64,df6a9e84,6741fda,1f774c52,20b04db1,9ba7402d,9b77eaf5,b8e9e2bd,a000d2df,2022565c) -,S(118face3,ab188a36,581cd1ce,1d434fdb,f1d06f50,1e9a64be,bfed2ea4,ba3f477b,a263037e,c8d5a9eb,be1a8b97,bbfa5624,ce00e852,44828af9,8cfc38ee,1da9052d) -,S(6be81e79,5fd1229a,fb24a395,fccfbb6a,ae4fda11,28f93faa,f74bfb76,c39794c7,edd0f9ae,bbbaaf0e,bd1c01f,af128730,5d5fc5c7,732885eb,327eb21f,62683869) -,S(b9a0023b,6fcbb06a,48f97684,509b8b9b,937f990e,4c3f1a61,27a8a18e,e4c96c3c,e1b25ce1,3e8bda89,ea631d71,4c07adfd,c31fc6b7,304b5e7f,1cc7221a,6597df11) -,S(4e384b06,ee4007e8,e70f22a6,1af73d89,4528722b,cf58bfa1,16eaa29f,e1f2334,2fa6ecd4,8faeedb6,240db0d1,14c7eb3e,63540e31,788f5f55,98c52fd2,538ef0d) -,S(14c8267b,6462dbfb,6ad45cff,58d9b22e,9fb0de4e,3d026999,9357acc4,d254ea52,86da149d,e14de86a,20becddd,e33e99cd,158a50aa,2da085c3,cf675eac,224b292d) -,S(42d0c7fc,21129bdc,97318985,73b6d111,568005b5,cbabcf55,c1828340,4f5de376,8f83e957,92880a3f,dac6738,e65ea463,1399daa4,defbd1e9,41a5586d,a42f652) -,S(bfb03349,2fc28eb,82bdf9b4,417f02ee,f93588a5,b138c520,77250499,23e9f135,c65872e6,9438a5e7,a20c3492,7a3de7d,85c690c8,b20af801,915585d1,98184882) -,S(1a111410,d04e1278,3cded32,b3602007,7dedfa32,6493a780,999c68a1,dee18047,874723b4,c6b63cbd,d957098f,d0124779,3e711a56,fcb8499a,a046f5d6,36d5be75) -,S(a47aa995,3a999aed,9c1d1f77,da8b736e,6d045d3f,9b32ecf,a6bd4225,fa66cf6e,c4ae1566,4da8e033,f0e3fbbe,472e16e0,70a4b40d,f210f7,3d0a6fe9,3dea782d) -,S(52ccf2b4,5cd2555d,5a0a5765,92b5ca7f,5ffa329b,6bb12979,8f2c10d4,bdf34119,92abe502,d23e9f61,f420e4a5,44e42864,2462dd0d,7d7f386f,ff7cf2b0,b3a5043f) -,S(5d2af6df,77107953,e6221a4a,ccecadf0,a2a8d676,5e720d2e,38c386a3,e6b48e4,5a44be69,80ca8082,5d435aec,34db8be4,6dbd05e9,9b8fa176,45888bd4,2260cfaf) -,S(e0f9b457,e184de7e,7484ad3a,dff4adbc,4dfe508c,14341dd9,d2c4f584,807e3fba,d0712e1,3bc4ad8c,78261681,3d00a237,36383731,7de79d0b,1f52264b,6ea70526) -,S(6797c2e1,d1c2643e,a831372a,abf36ab5,fcf88804,9a01f052,a7930792,acd2a7a4,ab005587,69f8d361,2217de,8d4bf205,925bde,7817e97f,d155fa94,8f084167) -,S(f302e07a,8953b3c1,f0b3796b,55bdf133,84809aa7,3dfe4fde,a0d56ae7,a04c2f26,339d529a,a6c0c8cf,f46682b9,c36390d8,28b2861d,6f4906dd,a4659028,c74d780a) -,S(aa4c04f,b8261965,9254f9b3,2d9e25cc,ec651f79,b710cc3d,bdf4eb3c,dfc207d8,520cbe2a,c8c0382a,23d2cea6,6a18f28,bb87e773,6bf60dc1,cca64a58,9fda48db) -,S(cc4bbc6e,7f4b02b5,ebe6d484,6352257,4651fed1,a079767b,fa53d1e0,dc38b5b9,4be5e0de,c97683d4,939077d1,edffcf6,dee4a88f,f7d42894,c3d50302,70c9554d) -,S(6a4bada6,cf1e123c,e80fcf83,2d6934f5,486901f1,6d3ad0af,cc87a4cf,205e6e79,b79145f8,24d693b3,832c6676,e35a73b8,d8acddf1,681720f6,c8d5ac7,f81752fb) -,S(d7ec4d61,1d440625,367b2c5f,a6904b8d,cf6f0d81,39cc3bc,16299e1b,50c9024c,18c402c6,3e818647,7f15bdb6,d514373c,89d1f7ff,bdab83f3,5267eb0c,daa81d89) -,S(4e21e4fa,4b570b40,77ff6876,a1d7e4ed,1db77d0f,56d35445,178ff508,5b197169,dab19080,ef84f0c8,4919d869,36de1aa3,ca85a1c0,aabe902f,b46b31b0,3b350580) -,S(32aa04b7,53752059,7b4ef603,62aa208a,effa6891,240a587c,e1cae58a,28a6075f,ca649475,a58a3ebd,c3802c13,f006335a,7d203ddc,88bbd1fa,f0787839,b9452f21) -,S(306bcc2b,94214994,e86c7fed,4f510ad7,9eb1af11,b824d897,a1cc7564,9eaafe0a,820c2986,abf17343,35089773,5b4da35c,56265a25,4a768346,5dc084aa,ecae6dcf) -,S(37d23716,1044ed4,b395b044,5d70eaaf,864530a7,fd8490c1,fe2d1ea5,61f4bc19,a6a9da7,70558993,ce38d5d4,c69dd25d,134f37f,c28dddef,2e7edc0,c1343b83) -,S(1f324230,886ef594,aecbe39,2d7a4434,fbb9fefa,fe22573e,9302d3c,dc81490f,39e53099,f25e977e,da860f77,6d09338b,c0e75446,42557c8c,b05761a7,c18537fa) -,S(256d4808,d6dd018d,392a6716,2af909f0,51bfeea0,9ce22a76,6266d1e7,61df967,d5643938,c7d9163b,38fc8072,609bcbf3,e063d78e,10cb8cee,32c00abc,6341df09) -,S(58a91493,ff7aa600,1f457506,624ce8ee,b1c142ca,d49f67f1,be099c58,3a7934f4,bde8d64a,79d5722d,6a96d240,897a7f48,8e20f19f,259fc6a1,e4483448,e0290122) -,S(b4a80e5d,eec9391,8f146b4b,e0d91630,606a5c79,1c4b7b87,d4363de6,e2691f2e,a6ff5b82,ca6fa424,efc00b20,7ea90991,fcd5af15,d23140ab,96da6cc8,bd532297) -,S(41bca570,b4981232,f21ba765,4f23d5ac,27f3bab6,9f1107fa,e3dc5102,6f8dafad,5a14cd59,9b0bb884,10ed1475,8445c49,3af3b7c9,2cc6435c,5560c4d7,832709db) -,S(bcff28e0,bb6c242,a7805142,122848ec,6951940,bb4a2e3,5ae05137,d73e8264,43661933,9ff9f2e8,278ef17,329682be,aa801596,e4a12b0e,615fbe7c,4b24e1aa) -,S(8aaa2f44,fbf66c2b,809180,bdbb4e2b,e25ff178,232fcaa5,a2c2563,8c1ea21c,69dc0de1,686bffad,1ceee711,95831b90,c57900a9,baf57ac,2f34a917,6d33e21f) -,S(930a3df,f84583b0,ced82f81,96c39c16,b9318f2b,44efde12,2be6c10c,70b33dc9,ae802936,2b10029a,a81cfc47,1251ffc3,6b586de,da9c1754,4a96d3ec,31cd6d1) -,S(907cf1c1,92b98461,8021a33d,1c9d22e3,22dc83ab,d5768a39,c04444bf,d4e76df2,527eb629,ca0a2e2,7da96361,ee727a34,97edb8c8,68694871,6a7dcca5,13b6f901) -,S(f9d32e84,76c666f6,29e86e0d,3804eee8,abe1ab26,ae2eb396,b584e4eb,e9583b88,d92f265e,9e6c5f4b,bc05a432,6fafeace,1516f823,3e5dc280,b239fa6c,bfdf7fb3) -,S(94772c31,70e50bbd,9952bc69,44e0007f,3d928cb2,c86465b2,ef040fa1,b4f90d9e,29021913,9326e358,2cfa8ee2,428c4307,86cb2de9,6ea2c735,eb71f759,bab14637) -,S(2b49cd38,8cec8c30,e984d40b,f1409c6f,df7ff24d,36cb699b,5f3c24c0,fcc872fb,9e65a427,ce5dcc20,db83a96b,720f29fd,df643b2b,a192736d,c621d92a,6583aa8) -,S(454f174d,8c344479,9bb58158,423d8413,ce87def9,2fd25a,5164807c,982d84e9,bf324810,d9894da6,1eb1e3cc,5a30639d,6500a453,c14e8a40,78353d42,7ac67ee1) -,S(df4461b1,dc1eaae8,5b4b7fe1,e87753e5,546f48f,e39da02f,f1012b24,58a79a17,ac4fd2bc,af8e0b51,48cc5a5d,46373209,8993b377,becd718,732fa339,95412fda) -,S(32973a0,d1be4c6d,1342b2a1,44ffb36b,81fd9b38,c0b7411a,65b8ccab,cda9161e,558b278b,f507b498,fdbbf73b,524c4652,53a0082b,d53a87f0,75d5a49a,bb601b69) -,S(cb63a9f2,d1a11b08,479275f,e1f0bc64,37126875,5bcd8a21,3481be2c,818c69d6,4949d3dd,a31db2b7,b2d42f2b,4709a870,5094d470,1e742f07,b6f86670,e43bfaa6) -,S(543ae5d,a0c271b8,41542353,277e1651,b7b0f587,a5b18ed2,856c2e07,41c28914,22c999cf,aba6f95b,21f87ab8,2f2edb2a,3dbb43a6,ff413506,83835ae8,bbcd0a37) -,S(7ffa63ef,3df62097,a3b61289,4eaf5bf7,4fb39ad2,9ec63f02,2c6f310e,77268c7e,9d26cd72,8fcbfe54,6eda19db,5ac61978,1b456699,59a21628,2500e5f5,389679ca) -,S(72cc6606,b02943a,5bd9a476,6b24caf4,e0e2f83,ae3bf671,5f05b39e,3436122b,f35ff21a,39503637,d05b744a,77797565,1e290541,326d920b,d5bcbb6f,74b56c3a) -,S(f5f21182,de67c3eb,396055f6,a8f64f5e,54043376,cdce9f3,3cffa601,4a348a4c,1fe09f94,8ad7f78,6c184675,3105cbd2,e0f8be91,f9160e81,9201fed3,3208b3c7) -,S(1cfa62a3,70171431,52fe149f,db07b00f,bd8d7928,e5eb145f,b4ff7343,fc19437a,1efe47f,e41677bd,337451b3,92eddb1c,ecfc19d0,5ef04727,12927d4c,77b2a742) -,S(b6609139,733864d3,abbdb6bf,4b827b2,3861594f,ce9e996,4637ef14,f0fb6849,2e807df,ae409cef,b7be1ffe,63351d8d,8de5fbeb,f3be5069,31befc97,d479c006) -,S(13da7c85,bffeaa0f,e295ce6,38de0b05,1b4aaf9b,d888f5c5,5f74fd60,abf2e016,c0477fad,fba6531e,f6369aaa,be663871,3bd6954a,d1e5df1,269c7208,31cd5bc3) -,S(2abda634,547a86aa,1188b2f6,ffaffb36,dd126d94,18406bed,8b81e29f,596526a0,7db36141,2e96e02c,34c0e39e,1201617f,2a7f2100,d5c3cf64,6dcbe563,e2b25524) -,S(4e161f2e,22785c68,3ac494d4,1e3cc2d5,e6b87be8,bd65e85,8aa255dc,8ea8fba0,c81a4e95,a2cfa101,fcb62112,b60c574c,623b5df6,5a1fcf51,e6bf2936,45d5f17b) -,S(586be2b5,740b0ed6,6f5c5f6f,217766e,ad5543eb,8e983ffb,928fc40,9e76397a,f11acf99,8bc2a25,48799529,9c7ea84d,98c6a525,6cbca56c,3ad534f9,26c6b08e) -,S(a76c4f91,1d0dcd58,9417fca9,8124f62e,789e0b05,91a9ce94,13e0b7d,e7d5986f,6a49fc1e,2b32aeaf,6f291184,3995602f,903c8d76,858fc532,9b3a1940,2c2c9b7c) -,S(15f11b1e,804a6d54,a496ee4f,f3030167,eb510e9c,c1754bd1,d46beace,1211a68c,f8968e8d,21bca271,75a79de5,31ad810,ca6c6da7,72ff96f9,937ef824,8f4fec45) -,S(f0169f41,685292bb,4ac93afd,58b2c239,3985ecd5,16acc8ed,ce46f325,74b23e58,6fbd711e,fd488c8b,43151ecf,e3a42ad6,25697053,1df18afb,68f8ad71,ee9aa05e) -,S(2f241e5e,2596d32b,6cdedc4e,b6de5f53,374e358d,8db78d08,9e772b37,6250f359,fe79f0a0,cdbef5a2,7287c86f,afbe917e,4c26c4ca,512f57e4,ab066d3a,3f7e71e) -,S(a14743eb,92bdf49f,5f404a54,ab193100,26f3fbd6,fc5a06e3,e8c6b33d,1f7a5559,3e7e5f24,b1d0425c,ee5c56ef,1e38098c,6d67fd12,f57eb2fb,1ee76c57,41d57c54) -,S(2d097299,db14ce88,8da72472,da686f67,b8ecc812,5618cae9,2acf6457,a011d2a9,e9cf7195,32f71130,5bae1fd4,ce3a8fb3,c8d71088,df35b49d,ad9c16d8,8734a187) -,S(aa7257f0,d7e51fbd,95598b7a,a994fac1,41aa76d6,318cbda0,20d30471,73317f2b,15e00f94,f684c30b,5cd4a978,c6245e6,8d30d959,a30fb39,834e97d8,c18a1b27) -,S(ae524618,e2877095,d52ffc94,67a081e8,b27b4b16,566e2b37,c8d11b1f,1f7416a0,d0275a1f,6d49a7c9,44a07a6b,ee5d5095,7b22b698,2607f822,8ad15253,a546ccb0) -,S(e7a85ef,ff8b0443,eace4cd8,81d768ba,ef4d93b9,79b17eae,fd237e8f,c9ff660f,4b53f073,8f07b360,7d66f720,b1222df3,eee2dd,ca20f40c,630a7911,a0fe2aa6) -,S(daa96eca,b8412eba,75f58a80,84a302a6,37dd7d77,bc9dc502,a2d083f8,35bf242e,ac3dfd97,a01557af,cd1f199c,afea0cce,52c8e3d4,975cb331,1c817c9,fab0815e) -,S(34dec21a,965b7027,44fa7881,4ff6f782,790d551b,7be35c,18cd46b2,e189baca,ee825c5c,5cc289b9,d7f01b43,4de4f0d,d250f9cf,c22c8d20,a1e54175,9bd23694) -,S(dc2178c1,2f015bee,829f0567,566d15e4,d607c8f3,b2992801,4b6a5607,1e61247d,fc86780e,31cf57ff,5da387d1,c3c25a19,36a263d,f6571de1,d098153a,97b41db8) -,S(6faee1e9,354bebe0,1fb65158,20b7e992,9517cb40,23d49d19,2a002ba4,e4782db4,a4915992,ceb8813b,e2778fb0,47766b6d,3958cf72,f18e9172,3f74cef0,1d2276a) -,S(a2bcc012,4112818e,571c8dae,3cb724dd,e45faa06,d04d7128,e9a71dce,22f300ca,1f594d9c,64ba43bc,11764c61,f8fef5c2,e31fda39,3447e7d2,10d004bb,c13870e3) -,S(b8cba39a,c51d86e7,d83a50af,f5370240,cd7b20f3,81aeb799,f951883f,458ead76,3a8bfe74,2b3a05be,27ef835,39988cc4,616365fa,e3738d35,29f9c0d1,c15eed4d) -,S(56e532dd,295792a6,ede9da94,c43e0b2a,25b72725,333f8205,7a352ac9,7a1991d3,a617e234,18bfdccc,8facb454,649a4914,2f0abd64,f30e06dc,838fd80d,7a141fc3) -,S(4803406c,e4049575,19f5306d,6daa003d,2aeddc1f,c1d4db45,15a8d35c,aa39a6d6,7add51c,12412f4,49d7b0e4,b7df38a4,83151126,49660956,da6273ef,8b53fd5e) -,S(bd61ad65,2e44effe,ca39620,2f84e4d5,d81cc579,2a2390f6,52409852,cd79c459,f3d7071b,8bb18928,1d827f71,ab7b1ad,5289033,ab28d20d,643af02f,a2b4ce5c) -,S(1b543175,e5b6f271,58048588,f81a791b,3ab216a3,578e2f79,354da6c9,5e4ea9bf,67a2e60b,321456b8,5b5499ca,e33cd6a6,d5445f91,eadb5a5a,f0e2164f,324417d7) -,S(2035953d,3319ffa5,9f75d86a,8d1b52c0,e8118ec4,d830d15e,d9616215,cb82d080,302cc0d8,5bc1e667,b160bc8a,64cc3bb8,763066a5,6652a0bc,c12691be,c41d7aa4) -,S(bf2a9739,f65bebbc,90413f9f,d311e095,e7628dcd,d76d25a9,8a4681ef,f4f84035,83932d07,cc950bcf,380cea81,28e04322,26b9a4bf,8536122b,fd055517,e7d3b2b7) -,S(a915504a,bb62b4a8,1288c44,8605e8ab,bafb4f0a,ffbcef23,c9c2a26f,f2cb8557,2fec1059,abe1bf4a,834c50c1,edf0e5a6,2ef21f7f,9da2fda,20989bae,18acd442) -,S(318939cc,fb2eb0f8,30d30079,7e209f00,6e28b899,8aecb548,b3b97900,9ea6aab7,5308df9d,10c7d151,cbcbe417,91b627ad,b7204db4,dbd2e01a,c5698e61,bdbda375) -,S(ff9e4851,d3f0c9cd,818facdf,4781cecb,7f622039,c23e236a,7e4b7368,64af1a8b,fd69f241,bac1c6b9,a52d6dd0,6e7bcb6,4a4a79a4,9c3881be,6ef8c83d,3f462c5e) -,S(497113be,a88d4888,2c98ac14,ba0bd0aa,d3c75c8a,58d374cc,86a7fd0a,b6259cc5,9029d9bb,96076d69,a264d2bb,6fea2f15,423ff1f6,ff47c02d,4699943c,9cbfbc4e) -,S(2b2cdb82,6653f563,dfc4c373,96d738e8,3d1dcc5a,ec5f4886,2d5ca84c,2ba69103,d1985cb3,f42e4ae1,7da33b7f,f8563236,6e2f5c89,b849ac73,afc3a7a8,1d049d85) -,S(c55dcffe,fe63e948,af77c8c8,32cb6c0a,c09ced5,5c338bef,fc27fd21,dc63b6c8,edef9fcd,b00fb62f,cc97c03f,26253069,de6f8d00,c13a5666,f574feb7,fabcab6a) -,S(52a0dbfd,371bcfb0,e2c69160,c9cca2b7,8dcf679f,774c9d99,706d306a,30eeb3c8,fe01f320,781275bc,a6c031e6,d71df467,56473d8a,780fc54a,6f8eb1ae,5640bf65) -,S(75c4ace7,6bb32bac,13141f21,615e11e,7608fda9,cba4723,9eb6bb8f,349a9e86,7fde50af,19506ba4,65d49b93,c8884478,dc34ec91,9bd5e22,be6bf71e,a870a70d) -,S(69cd7caa,b220abe7,8f36f7a4,633802b4,85969ac0,e9c4a244,7b0ad782,29daa879,4140a70b,8d9025d1,7fb3402d,2ac8afda,e9e0269,b29d488c,2266c1bd,58accc9c) -,S(b6cf3a30,d2a5ec8f,4480df82,ec6104ff,37355ca6,f16418ab,cad3a0c7,bd8da064,f12006b7,5d406558,51fde0eb,c68113b8,50441595,dfe3dddf,86c17a58,94a6d923) -,S(65c4a081,656d9b7,445131e8,6081b306,3a6e0c02,5339d3d7,cf48e9ec,4e8f59f1,51f4ebb9,4b63b8bd,2cdd6d88,c84c8608,bb380e38,c748ddb3,3dabff1c,f50197fa) -,S(c243570d,e74a1fbd,938bea43,bb17a929,47a228b1,ae47a6cd,15c37524,b034fa66,ca57366f,e3886510,903970ca,e1a5dc5e,bb857007,cd4cc56a,37fc7fca,8aa4cd40) -,S(9290d033,1c95584d,e2bace9b,788c50b2,f7fda83d,d45a4a37,5705400,45339d7,dcb3032f,c4a41076,8b8e442e,46cfb16,b63f4fe9,f94a7d5c,f932d0d4,95e699e6) -,S(295df203,cfa65b66,6afc86cf,b879d650,7075f75b,d1eb753c,709760f6,6ae9df94,2cf505f8,8220196f,9e5478e3,6bd82501,671c6b91,a404fc0f,b1fe00cf,12085934) -,S(1631e6c1,3f89dbca,36cc78db,1056a461,6ce2dcca,62f90b0c,5fcbf232,77d41116,acbcbff3,2c164cd3,b57d3b89,a326b5d1,46b5769f,a5b35df1,efabd2f4,407759d0) -,S(db0b2c5b,eec9f06a,9bb43e4c,de18d978,59a95cfb,9b319d2,5ba619ee,abc49e31,d647147,d8330315,1446a405,85bd857f,ebaef109,22ddd0e,3ac62231,8ee91abc) -,S(2581d046,9e8bdc16,e535c787,1a37c48f,929aad34,b694ac2e,5d264962,11e744f,7bf3c684,3d953b2,dbead1f4,8614646c,d18b0f2a,cdf6fbfd,3ca68498,ab25bc60) -,S(9db20da4,d576f564,372aeed6,eae78eed,f512d13b,13d4e9e2,eb3133c6,13c4b80,40f8b2b6,fa113b6,ed7dce55,d62587d8,a86a43b2,9e0b4876,c5607b89,9144d255) -,S(849b193c,e490990b,e2aa48a1,c31694c5,fa041f96,7086a83,cd1a06b6,ccb5e3c3,353b49a,6ac0c705,5a3d5e31,fa428e2,391165ce,402291b2,5e1b0496,bda41e1e) -,S(ae83dff6,5a1dcb6f,e2f56437,c83162a4,a388a16a,bd387d62,f5c5ed,ea08fe7e,e9c57ed6,5404a00b,a2f87613,4d484842,4a32246b,def6c31b,533caafe,7029eabb) -,S(24724eab,46175b4,efe51d4a,5993da48,1a62c6e5,f05d16a5,17e4f58c,fdb103,94465b42,e4e378c2,1ef0d1d1,8b25d140,fb17f51a,fa4d37e3,450c73c4,72468b04) -,S(c2e2f802,4ac48fcf,41a3790e,e9916018,5a301859,3cc3fa77,c7840552,6700659e,b1fe219,1563f9bd,20c4dd45,615d8cc,400911d,20cfb7a7,672b06,20d32a2a) -,S(8b889bc3,e2d1405b,47a1a05f,fd0c17ef,9b4dd75,4d30640b,e3c4de7d,f70791b5,e2d459ca,285629d,956d5046,54c5e907,6ed92fa6,c95643c0,7d746b78,e03a044a) -,S(336c0585,8f5ee169,fc09fc73,a181ccd1,3bd62dd7,c454837e,1a5d7676,abb2faad,5c29a656,e8f2804,6e855c6c,eb0d908e,38f1b62a,69c67948,9d6a03ce,64a90c2e) -,S(c9a6df46,411961d,a703ab23,605fce16,fe021576,92a9b80e,65b9e4ab,efc9ee93,8b63a4ab,18a4b190,89dbc53c,ef0b0dc9,20c0ec7e,1fcf075,195bccca,58d52f6d) -,S(6cea35c8,b3a45063,75456a6,2c95e8b3,7d84a6d3,e909c5a9,cc4800eb,5bc28367,68198888,eacc9380,4a3233ba,1801d586,e5bcb2b2,78efc7da,6764bd5d,edf0ee90) -,S(f13d4ee6,ea31999d,d8d1220a,13ce8353,7c350046,319a0412,e562cb8d,3e4ee80a,5f7afcc4,37f0b29a,ab11a8b2,14947521,bbb4b622,261b9e73,f989e1b9,9f43a2ab) -,S(7385b644,2e43ab56,f4df8a57,4d0a32ac,6e5a7114,13dcd992,f86c0b04,33830307,6d27608a,8ea00e22,4197c8a1,9e9511fc,7ecd7083,86e94ab9,6aaa35f9,c8c2c5f3) -,S(35923ab9,a784ee6e,5a4e911a,7552fa16,ccefa4e3,dcc90083,e5a19e31,4dfeb06b,c900475d,980cce8,7d5cc091,7a28c18c,2fecd5f5,cd2cc66d,e26deb61,1c5acb89) -,S(d88b6907,3abccb02,2e235e60,4f3e2877,ef979f85,a5b3fc4d,fdb166b,a4155d9a,1eefcc82,69a20b9b,48d30d00,e7ffd021,a9b7b171,378a299,819d6e6d,19d5ed24) -,S(b86c5281,cfb9f3b8,4be4f83b,1d13d33e,1f6abfae,bbedcac1,63362a76,8740a827,c1a32696,fc1f8507,289f111c,85483b23,23d228a6,773030e8,dcf30f6d,57857dbe) -,S(d2813221,9c730094,97c257f3,1fbeaee9,1afa001c,84e4b813,d7ee2452,6454c640,75d722d9,7111d6f6,b6324598,8720ce39,66fae55c,3d81e4d,ade294d6,1269b4ea) -,S(445addf5,bf941ace,6b4aad55,6f174ba1,ee793bf4,9f46295d,19fd8e2,807f8d3b,cbe249f1,fbb39f8d,93079d0c,e84302dd,52212b6c,828a1626,b7446f91,4f6727e) -,S(a2dfad8d,66fd47fd,38fbcb74,b983d366,c57a08d1,b04f1acc,4fdf047f,100552f2,63011d2b,43822a21,ddcdb1cf,ef4dc0d2,5f595165,26939761,953fb738,77586c9d) -,S(c4e84511,6644466b,8c573b8e,c7dd3788,ecf1c6c2,63ecfabb,b13f697f,2b2e3a7c,1e53964,a70e83a8,ed9f5d8a,b6b79629,7368bc5d,cc90e6fc,4e8e6f65,542f63cc) -,S(63c4cc2c,cf368a04,be814d1d,81fa4250,653ebeea,ccdffea7,944801f6,efee1aba,6fc2bb4,a7e573f5,fea2cabf,abd9a145,c7c36d62,11928341,e9553e8a,b38fa90c) -,S(51eb8782,a3445ef6,43f01634,caad6fe2,29585dd6,f073acf3,62cfaa3e,960343c6,56d20f56,8e6d868f,491b6e1b,80fa5c88,e3d625d1,433b1dcb,5ae2d35e,b40a960) -,S(d89ea50d,ab6c4c39,48fc4d4b,73d7812e,a6b59ee1,8e7a51e8,bf6249bd,ec59d068,a1ae85aa,e842ab60,95feec2a,d6ce6206,e81a6e76,7f0b7b20,d41cd28b,6a8c4258) -,S(d121a6a8,11f953fe,a90d8f3,4487d654,fb48e4f3,c5ac4db8,3e3f50a5,cd7bac9c,a5b9e6da,e07a0f1,dc1695e0,20502f55,5fbf136,df11b586,4ecc63e2,d7061a6e) -,S(83f7dd06,e5afbb3f,7b2563f0,faaaa3cb,20c32db1,5bdaeeb5,73219814,caa599b3,c452f49,1e4482c1,1cd4bf46,75d74c5,ab054163,b6d1b837,dd10aa05,950f199a) -,S(1f5ba7d9,b4cf8684,cd073892,4aee1919,1f611d78,a943d49b,509fffa6,31fdc19,a017e13,7a8a199a,e361dc18,527f0135,51e48b02,c2f7f102,a6c1ffbf,fdd0baba) -,S(d25fc73e,a83ef669,c2e127c7,1615df3b,ec61ee38,4a6b3396,cc52066e,c3b70b8b,9b5d55e1,c8dd008f,19b5e989,363ea737,e7d7bea3,f7b0d9b6,951dd78e,be6c5334) -,S(d749373f,ecc1814b,dc8ce6d1,2ebe84c9,e09806a,9cbec814,cf98dab2,4a46ddba,88012af1,84f7ce23,730a3a4f,191d0687,4d5652dc,2be47214,61e9ad31,b39ee397) -,S(8e05da99,971ba37d,38e7642b,693856af,a90d7206,2d360611,6c8f506d,68316b9c,73de534b,5833287b,61f3f985,2723be7b,e8e22ee3,1d1ef4fb,f45d6931,827e3db4) -,S(e71e83f1,c6b285db,157f4a14,825aa540,558a7853,673900aa,fdb84556,ae5c891e,e37980b,c180e3d2,481d81f,f9aa33cb,b297ffad,7dbbdd79,4fc013f5,43ee679f) -,S(bc66d644,dd9da12a,299557d5,fd35993b,ab05ac8f,bdd3802f,25b35890,db8eed32,5fa8c7e4,bdf77750,573a4ac7,1681ca04,4f796ea9,c8379cd5,ed55631d,bfdb8405) -,S(537f194e,efe43985,8dbe1eb2,8e27448f,fd1b554a,b12805fb,3af43538,fe0e37f7,e82018eb,447b2810,1502453f,db4c1cb6,666330d2,ea3331d3,f79d5652,a1d64af7) -,S(4af2a9f2,e0fa4b4e,731dbdf3,676538c1,110f3232,7b8f2766,a7f489de,8aec3b4b,cf2e0ca5,dc830856,43151cc0,1507af4f,d84b253,2f0fdcc9,6489baf8,6c1bd4ab) -,S(81369bd2,a4945c15,389aaea3,4e2855d7,6343e200,a9407ed,d05ae927,5585aa36,a9b4ba4,e26950c6,6648b573,3c0c4e5a,22a51e71,ac3c1fdc,78403eaf,3a667161) -,S(1c0813d7,ef91aa73,9e3a6f0c,e3c7edcb,2b7117a7,2ad1dad6,1aed130f,c61cdd3d,e3390572,67ac3bfc,5373cc31,14bd0f38,ccc3cb25,862b243c,912c0aeb,98bb86d) -,S(8a651923,d2622057,59e5f82,b38bfae7,dc922488,749ea56c,e43f0f74,c268f9ab,f3df434f,14f67030,fe888ba0,185e25c8,38520bf6,6e85023e,e4ff4f04,b056d9d1) -,S(89d98548,30a2a572,dbe91018,e66b28de,835dd02b,f793a469,2de3d720,d70e8f43,629868e9,9e434bfa,98bdc4,f191a08,72e68768,ce8a918c,7c2da42,75e5cb3b) -,S(97d0c83c,5d83d399,c567ecd5,dae551fb,7f1838de,1967e84c,7f053b81,62965fe9,fd716683,73347fbc,407543b6,70734733,df623a55,1766f55,8a02059a,2ce55c4d) -,S(20807bb2,650e6d82,38a66ed4,b239b59e,fe073a5f,9cbf0d6f,e3d9a16d,be427de9,46a25a29,c104c56d,8436155f,64b1d84a,b974fb2c,951470df,17a9704a,be5c1f9a) -,S(3cbb1786,945bedb5,c8ac2d0e,dda1b0bd,ee314cc5,faf56b75,fa878bf2,b218a8f3,ddcec0c0,d05403e8,ea2094a9,6ea910f8,3261932d,701a2ea0,4e93581a,7e4b7275) -,S(961d0144,1618561d,c3504859,7e1701bf,35412ad3,2d04486,704e5593,b9278734,7e137d6b,2060572b,ef66f8b4,c8ce535f,b858327e,26dc2295,6ee6c94b,c83859bc) -,S(2814918a,115ca2d,688f4358,9010b7d8,b8b560f3,6a3dce2,8fcc05e,acd4845b,dbf76f51,ef80e324,8820cb0b,bc7f0c2,4d50ae48,6387d206,c333222c,5f959dd1) -,S(6c4f3b00,c02c19a5,ddb0ab1,798929ca,222a9538,b641cb3c,dd61736,77c9442f,a91d13a4,d3888b82,eaba5173,3ff76fae,8022fb10,8cd61f19,206cd78,7d1c99cc) -,S(8f48304c,ac37d495,fa1a2ff,2178f442,4af030ca,70662a1d,c750bde,5f5d8dd4,ccff6176,47cbdd3c,3d0c588c,37a98723,c2b2aa14,fd17cf9f,ea45ec72,eda8defc) -,S(ae3da559,e3fce253,f5c1fbad,8e12a52d,ee989ea9,8552a192,93f7db0,eaac9405,430b86d1,322191c7,9aed5bb,12eece79,f2519bab,17998346,8aa13b69,94032ef7) -,S(90c093fc,27fa9de,66a1fdc4,d921e5da,6f4fa049,81cb6f91,e085f89b,96561471,1bdad536,4ae198ae,bbb0ff88,3bd5dd2e,dfbaa91d,e989f45a,30befa9,76f2db23) -,S(730a1c4,5ca28743,538fcacf,a65b7d90,b6f4b1c6,87364cd,53dd6585,328eeabf,7420e8da,cc64a059,b46221c6,c3adb4b3,46eceeb8,8effca39,1a1e36d0,d665257b) -,S(341eabe9,66c6ce4,65ac18ca,1eda053d,4e6137c,ac0796d4,36a942e5,99ef897a,d298003d,fdd9f529,c1977b3,ed426d6e,2df46098,539b20ef,c2011a36,b7e49cde) -,S(8f7e1b2,cb538fce,4b4a7775,90d1a95c,2fef8331,9792c0bc,8d5f3493,54fca169,71b0849f,cec62c5d,fdce37a2,61e2a06d,32b3e0de,87c8aebe,e5a95cab,b0c3f798) -,S(c7ea6b43,ce1e0e83,819bee9a,31fba823,3ee03a6b,14988b98,e80aef2c,eace0d56,e9f1328f,dca6a16e,2100ad40,138f9810,17e37e67,7e7ca747,c3a57ad9,24b8891e) -,S(b16ea5c3,b03e58b0,e6c217c8,6eacc4b9,3032add4,30acfd7a,e50eacb9,a0e5c1fb,507fed89,5c14380f,ab9e54e,a3624e5a,cbdaed64,b2712f88,48018b90,7a88f47c) -,S(15cf4de,7c36b72d,f7b98c00,8e928731,a2e71c69,cd0427f3,ac9264b1,5a5fd487,3865beea,6b36732c,5ecfd21a,562ab253,d618546b,c1c24745,8881b20,643d7e2f) -,S(394efbbb,fa740f53,b1e70eb9,d12671e7,55337357,b982921a,79915acf,ddd18218,8f1f1980,6c1d631e,6519aadf,b563dbf2,37b75db1,54baf06f,6fde8218,a0a68eb6) -,S(e6c3e152,27453d32,cd4449d1,ab1ad78d,58f5bb6,f29d813c,e7c6628f,b284399f,89d87957,4b640a87,abadc6a,dc51a533,838a83f,53de4448,9ff0640a,502dfd62) -,S(e2480000,9db30642,f925ef8a,e31c54fb,1340e88d,b6d633f8,415ceac5,f583cee6,39ad28f1,8ecd8302,5cc1fa72,ae4e9897,81318cea,9e506794,50abd959,f19758c0) -,S(1c134120,3c2e7e21,f5b10ecf,402d52bd,33db3278,70cdfcec,f3b277e4,78f551f4,cd6907b,57cfad79,5e14e7c3,b2a06a46,17b7a27c,ff476bfe,38d68d0f,1470dd63) -,S(6b2fbbb1,515c261c,954a0be0,279a1cd6,63daa083,1fbd58c9,c69b7be7,ee6047dd,d38ef59b,4e276fe5,6f1f2fe6,74b6974d,5ef1f4a9,74abb2c8,17cc68cf,78a164a) -,S(dd5098a,8cc8ccf0,7db82096,b52d1fa3,6bd26c2b,57f0cbe6,2ca954db,1773e9cb,a198ec1e,71c53d73,5b50000d,678d7d93,de64a72e,8ad018bb,f515b4f7,c7840aff) -,S(f6dc494,3baa0613,59a000ab,3aed3456,1972d425,34df86ae,3eb8e5e7,cae23c22,7150f3bc,5a968248,d8c71ea8,32b116db,73ff34e5,35ec1e6b,64b2474a,947174dc) -,S(e115c926,5930dc67,bda89798,e267dc48,12c06d2a,a05e4a5a,6519b0bc,7096f84c,5b0dc7bc,82b61275,2aa17a13,c1fe2cd7,6b60cf1e,ceaa9234,ec9e6609,7b2018ec) -,S(6687f498,98a22d8,58ef88a1,bcbfb446,33d51eb2,6c1fc2ec,eeecdae9,e0960c56,fd1912f5,7c0e691,23977524,ba58ea04,5757aeb9,309a5b94,3c993a93,57475ff) -,S(366ea4df,3aa8da52,763b513c,efa3c739,af61a497,6fc4c884,e879ddde,c2457d1c,876520ba,cca3c711,a23186a4,833db7c7,14b3de4f,fc86e8e4,cbd61cc0,9a48f34a) -,S(f7951805,eaddd012,2bed030,f3013e15,6fec02b9,80ba8ff1,1a0b978a,3fbeb778,b255b5c2,db866de0,a145a108,f5eb4b69,271c13aa,8db75fc9,f467843e,a59549a3) -,S(c77d217c,5c7b8fbb,f7bfd244,b2a2d2db,372d8217,43eb4a03,47858678,471d8be7,55573d9b,dd16bda6,ad916820,874d64d4,b260a489,b4a93427,1ea5a79a,f57dc5c3) -,S(c803dc3c,1432ac63,19db169,6d7ebc16,58021b8c,b92c0fe6,a59d1efc,2056f214,ce8e23ae,c7dca471,8666f61d,d7d8bc10,e06d1929,7fbad7b7,7d45526,9e207b09) -,S(676c4c3f,617b661,2affb2c2,dcfe072c,ddee8b29,dad9124f,dd24e87b,52a80b88,6df8c35,be6818bc,b6857f47,f59a11b,e05cebae,ee6c53ed,8cb93fa8,92c49e0b) -,S(8b0c8502,bfa15f59,335cc34,20e04c90,becc2308,12d40c7e,14fc3e30,88b8f34f,eb75d312,9fa4db28,27d20c93,de9c5cc9,4237bbb,a9710371,f767f686,e5ddbbbd) -,S(6ea07148,5594bd90,2d0d526c,28918bb2,cdb7d1cf,d3ad0b1f,a3ebbf76,71a2f90f,3a30be2c,2058cb43,c6f8ae98,1ce8986a,8b4dfc3d,81d49a80,4e40c81a,a1fc8220) -,S(aba7df4,8bcaa5e4,c4fd9a21,6b4bb3fa,27617205,693763bf,71b8b214,9cf83c48,6b1b719f,a0633abc,4580a9cb,9c1210a3,3e5e3bfd,177bc76,39057e51,3fb9b3fe) -,S(ccfca0f,ee5bebb7,26e2062e,2b5cd592,847031d3,5edc7767,414af809,9b3ac2ad,135b2ff2,4e40f04c,adef93ed,ceededb7,380c1e9a,e32a499,467af149,cfb532cd) -,S(9af36417,f3076595,42ea54b1,4671d2db,f7582ff9,b7e659a7,6465ee2d,4db88e35,dc5d07a2,58d4f5d5,ae649b63,e07a4253,8b8b3e42,c65a6ba3,44900028,c84df8aa) -,S(e2f308a3,e4d99e74,d6b37cc1,dc41d9fd,e98a4472,6e86764a,89fe959d,deaf922e,f5f8eebc,d9252e1c,74b9040b,569c9d5e,11d12af5,aa21051,8f87043c,7b47776a) -,S(a62581d4,c4fa4b6,aee11db0,8fb698e9,864cf336,578c536a,8a887d1a,89b43e35,b530ce21,bba9d034,d53dd490,2b76f25b,4391914a,5f87b6d8,2526f7c3,def132ba) -,S(11ef91f5,dfeaceaa,52f434b0,fc03085f,60c12ea9,4441574a,5725aa86,52c259b4,a2c81e79,cb5ad0d6,bf0221ce,2bf7497e,bc91026e,adf0e25e,6269dfb3,2ced7d8) -,S(ff549a04,fb86bf9e,3ad207b5,ac76a74c,2532a1a6,516327bc,96353baf,66269c5c,ef1088fc,633f639f,f0061bef,4c1e4c64,5897ba0e,ee229d44,d99be0d6,95e494db) -,S(11c9ebb8,893b6534,b323909,961bb8ee,4c90c854,52848ad4,18fcf223,c80eb7cd,4b0229e0,89a1ca0e,d60ce2ee,590211a8,769d333,5f4ef32f,4460f8be,940a0dd2) -,S(e86b3691,f8ae48c4,12a6216c,c3633f1e,88667299,f828d6b1,3ff88cac,e060b1b4,14d95d6a,61298fb5,1fc974fe,f3957db5,4aac7130,a1ed873c,cee5cada,6eec0c6a) -,S(e5b9550e,eaeed973,5d8068b2,2c48bd2a,608fdabb,563c0e5a,6c2b2351,24c49d19,506ff679,2ea7c37c,254d7ae1,a459204d,aca23016,93c1598c,2449b758,6d437de4) -,S(cab58ba0,cb15982a,c1ae5b51,ad65574f,55540820,d057e11e,f9c9f9b,a1388335,ae1c9e22,74958b33,2ce0f0c7,ef621a49,4d5b0ad,b04748c6,539dbcbd,6bd4ef18) -,S(715e4568,9bd663cf,e9c83006,82fc7c90,5ae2da55,42b0ea4,40cbe2eb,36e1eb43,58ccbf96,8860cbfc,6b03f6a,a5fe05db,14be0e3f,3d6224bd,ce6eb54f,7372aa85) -,S(df92f1de,4d22a7ee,6d2bf45a,5728745e,f59b6b07,29614536,722c7de7,965c0648,59e18767,f0e22894,be586a13,46950c03,88f1529e,cced0d18,50439dd0,e5bc192c) -,S(885dd01e,dc8ffd40,c5f26d7a,bcecf670,7a791ac0,b2332b91,12e69cbf,11399808,4ad58276,6e763ddc,3f4ff718,569f600d,8c764659,87ebd74c,d506c2,ba886ac8) -,S(d3fe74b6,17a1ab46,c773549b,af4bcbff,917c7ecc,fbedb63b,651b2197,89c1ff9e,b2e6bbee,5d84b593,d43467db,7372f40e,493a9fdc,c5d88fe6,5767f45c,837acf93) -,S(c3730836,74b97237,66d9e9de,f7b6d792,93faedf4,f7d86301,75862d62,d4ada8e3,b669a24,a31f8277,8686d2aa,6b2acd16,872570f0,8e6f06b8,394f498a,dc29f099) -,S(4ef2ace6,422be7ab,6a614e2b,fc43360a,2fdfcdde,51cb31c8,372a2042,2df4e100,86868f5c,37366665,fc6121e0,a8ab3a86,92ba1714,f5b8506f,9a3c3025,eaf9fbc8) -,S(51110764,573c540b,813ebc4e,79d59277,67e30ed1,70a951b7,9ed05f8e,8d142cf8,ea8890e4,9668304b,63fad75e,33f42601,f2649a21,724fc495,61110e79,d7ddfea9) -,S(36cbfeec,5491e1c2,f853d98a,275c1baa,e74dca33,2bd3d830,7d896607,c1cb651c,f67659d6,677b44cd,33c0cedc,d5886ad8,90eac77f,5b393fa5,6cba1077,54489eee) -,S(d1ff3875,e1ef071,eef96f05,bc19d356,aeee18a7,f3892f02,4d07b43b,c3f09dbf,ba825e43,72b4a644,dcb5b8f9,62e0099,ab75ef9e,34b54874,f8d68197,ecbe8eae) -,S(45e7bec6,75819b22,f2761ae7,575ebd6a,8ef87727,a15e33b,3edc7ead,dd58fa5d,3482080e,edaea330,240b539c,7d6a2e42,2cbaf40,f93d5052,28c773f9,6d80fa86) -,S(8ca5d7e4,bd79aebb,bcc5250d,c86ac1df,373eb3ce,1d8cf2ff,5916cbb7,1e8e016e,1af3f417,afa5c1c7,89474f79,a0755bbf,a9a268bf,fdf242f4,c1599dc7,b7cb1e55) -,S(56bf2e78,e7c43841,6324e581,7330a6bd,208edee5,3b5d61cb,a141f9cd,ec3002c4,e8f91e4b,3984a946,29060a4e,534bb4de,f345879a,f4884214,63dd0299,2bfc2fde) -,S(af152859,31540f00,1be4a65c,e3f55437,f7be7d8c,db0283bd,f96bf71c,c004455f,1f58be49,77cf9b8,b7ddf7fb,74f7356d,62b8fe33,6bf798de,3dc435b1,86122b40) -,S(2f4d8117,bcffeaab,7db186c5,7aedcb00,80d67b36,a560c5f0,e323b7d7,79be70b3,e0a50d82,80677ee9,caafcaaa,5d7d1747,3f4980c,73831f43,29b15452,94e71829) -,S(bd96815c,e6b6d0f1,3688cc26,777c42bf,50fb8cd8,cd0aa082,94ad498c,620d1f4d,8a882c49,6592b186,b0a4071c,b0b556ca,27f2ec82,417aa246,ae24b415,8e4ddb23) -,S(cf64bc04,e0796fec,112a5ef1,2c3cd909,5c041b46,2772b818,3e6656ea,16d046c2,6a05162a,eddf163a,fc2cc91f,34f7a7bf,41660b4e,a8ac7af5,698c259e,47e77e86) -,S(3dc4bd0c,2c8253e2,4ed942a0,7f45c2c6,390a9d07,6d334f3c,80dfabe9,282a86c5,e0994668,7cc9c6ca,e2d04840,6d34cd22,e4f8e271,da4416dc,77e59af1,7057c43c) -,S(40e00b89,e58de390,6a56133a,fa574019,51be1efa,6156baa0,45fb3987,94f7ff11,cf675e01,1f20efc4,24b882fb,b7bb9ca5,5a1134f,b628acd9,a597fb97,968641d) -,S(5626496f,1f49190a,48929e9a,403f9f54,319a6b1d,301cf256,692cadc0,41301c27,21702c7e,2ee0efcd,b98a0170,110e3495,e23fe5b9,9674bb0d,b6f09e57,fe76b48f) -,S(2a2c8f2c,a580145b,a9593b87,dfe0dcdd,caa3cef0,20b0e2cd,3792da6e,2f989a11,4aad23a0,e01f6a43,3f6c2a40,f480f945,d45c89b1,df42d67,acf6b0da,3f46bba8) -,S(68a74703,a88b88d9,ee974a87,af7b1be5,1866ea40,ab4cae9d,90a4c2c6,5822b565,3660b266,c74b8be1,c98d3b9,b1f14dd7,e039b476,733a1322,d2d7d2f6,9ad59700) -,S(b50ad45a,4898f77b,c5544dc1,cc8c0515,3b1e15ae,d043d2f1,40bf9dd7,29e413e1,1a59e623,3bea3be0,5713c06,b18badce,69b84693,636be68a,532adfa8,c617a773) -,S(df18b016,3ad015e8,da7e87ad,e6fa5312,d665c696,e42e466a,5e9e2a82,18337c22,532d4260,eb34306e,691f42dd,c215ffdf,2f6cf3ef,cc1363c6,46b8921,ccf277b0) -,S(405bc408,446bb0bd,49eb838a,eaadbf1b,27d413ef,a15fdec9,86e8446e,2c799391,1293bad0,ca26e4a9,f80dcdbf,1ccb70d3,fca9f403,89bcc331,e917d7e4,bf4d0b3e) -,S(1230acd2,75b02450,255fdebe,dd0ae807,38f081bc,5faaeebe,4542664b,ec57bb15,aa31d16d,b145414d,acc29c11,b0ed9fe4,fad90a7c,451d9706,4f7ec6fd,75b15703) -,S(4015c1de,3e09dc64,9ec990be,898db42d,1193e1cb,81956b08,da1c15c4,b9a2af48,d58b2d0e,553dd49f,ab07e5dc,c5a66543,b7dd351d,84375fdf,2ce1db56,8185e67c) -,S(f3da2f12,7f47b9a7,192f00a1,5576aeb0,8bc36211,7fe1246,ad61421,85f79009,865ca0c6,4aa629af,b84f761f,b26a4938,25fdec29,ce1d4a66,9dbcd138,41bb83c0) -,S(15f1e896,f7c7cc94,f3f921e7,6dc1e30c,f0d43b99,e9fa0352,42e56a4b,90a0c736,61e85195,215b864a,6f5bd52c,d0274526,dbc80af1,4395f9d1,ce60bf74,27c18b33) -,S(3fad3455,470a113a,2f773ed1,258111ff,da926643,f7fa1cf2,8e9f7b80,dfd2105b,ffbe436f,a1975bcd,ee4eae51,8dece7d0,cb34aeae,ade738d1,b39f4c6,6ca08a05) -,S(62bbb9ac,282329dc,65ae7b4f,bd15dca7,70a088e5,45850aaa,bc4c09b1,9177f92a,9c000eb7,f6104a03,51e1bd8c,d8ac8f7e,22578291,35eea222,866f2632,2573dd72) -,S(9bf86604,a46cf253,324f5608,b7bc87c8,72939597,131f12c0,eae3482d,b1935e42,e9f2dd2,15cce5af,16149d3f,1116d79,74f51267,1b575f8f,6ab6367f,fede26e9) -,S(a2ec976c,b5e72001,a25f95e,bbd7d354,2f3b174e,80ee3752,db082910,895f723,dbcb75c8,365c6248,c52a83fe,1c79d7b9,37ca8ebc,5060ba7f,60b881c1,964105d5) -,S(dd91f713,ee212c4d,f94b1fc8,c7f246b9,cd162a9c,5c8988b8,f3adff0f,fdb0aded,efd02821,c4eb853b,bb8c55ef,c54f41fe,7e53582a,230d52fa,c18a53d,ca40c81e) -,S(504e6ab0,c47fb3f4,b6b74a7b,1e67f6e8,c28ef108,62c2db35,f16f31cc,e71d423f,e7adb424,3200ab4e,71e50453,2d849315,1eae2247,50ff7a59,52bf2656,65b3ded1) -,S(1a9ea377,27fad3be,155f7ed5,1caf01ab,1d30195b,1629fba0,dd04b7af,c1a4b8c7,2140f144,e531dab2,22cd4137,921b4720,59efbd57,c1c97367,ff2083e7,f2420206) -,S(d76324e8,31920463,d5d94ce8,f9654393,89d97ba3,eb5e91ac,56898343,397b34aa,189631be,df5d46fe,fa8f60fc,a8b22fc2,ac987d23,b21ff267,560863,6ef3a72b) -,S(de87a315,50a6f146,e681d8a9,f9a7cde6,7da28c7b,5cd7a70b,703695e2,3c9bddfe,d33a05e7,77ba9e6d,155bab56,2b8cbba,27f4cc63,13038f7e,d193137f,d14b8502) -,S(d8381e05,7fbc1910,8b5a304,fa984e0c,cc0f5d27,303a3287,9ecfbf73,a1137974,1dc513d5,ac96238c,79d8f740,c855e045,e5c4e567,b3f44744,abb3bf46,ca394e8) -,S(69da86a3,b355f0d8,138bf809,79e314ab,7cb34e64,45be4842,b8f3810f,11b2ad66,7db776df,68bcac9a,c0f8f55e,8ee6a7e1,771d4148,1f5d953e,e9bf832e,cf713cfe) -,S(698f8b8,66093996,e2e357d4,d671d21b,230726a8,84079fbd,766332a5,4e7f18f3,5925e34e,dcab3458,ed959aa,3903ac93,c39b8ebd,1c562691,3f844150,d41ad20a) -,S(37274120,6cb7047d,aa97274f,b12aa8d2,e5eabca2,f3ab0b4b,daa3fd7a,3d5365df,30d36bad,c10337a2,db6c30f2,e8876226,5ccc6a1,7104460a,6f438a9d,3e8e9300) -,S(4e8c8df7,30f5d411,77355739,84a530b3,8ca4012d,3d4c8ce,f6c00689,b72cbeca,d9f7aed1,f5073c8a,8d2948d7,86ce6dd9,93a405ba,393a20a8,719287ce,797163) -,S(1e62c3c7,16e4f6ca,77b6d325,8553a5fd,59f67df,f7295115,cd6e4bb1,19b4b5aa,7df17da2,a7397df9,e314fd8b,6b03d293,ff7325e2,769d7477,ef3802a5,7d8010a0) -,S(c79f25a4,664cae13,d0971832,fee6a316,ff338f15,40c1f3e5,95c707c0,6e035db,5ef7879,c46266ca,7b342264,1594e81,5c189ce0,f057f187,e43a61fa,10330e85) -,S(768a47a3,64304a44,34b097e5,132edab2,b9840584,6e543dd4,755038da,e355cb9b,79896b63,eed7e866,32c33041,d037554e,551f2a73,6f2c2b35,4dd7d7ac,f6562344) -,S(131671bc,604d622,eea3f06f,200edb52,f7223fc9,3fc8d4e5,496af1a9,f72e56ad,5a6614d3,7985f503,2ad7a53,9b99ccf7,7c453f94,3975983c,e948dfe0,ffb867d6) -,S(3b9e6127,48d11bfc,1d2d0081,24e79a9c,604bdb94,6b25ac57,749ca6ef,302d7a58,379e7cc0,fecf689c,f905e84e,8516388f,3e1cb41a,aab8192c,aa024de0,3332cc70) -,S(4f9fdecd,10e8cc9c,f5f2573e,a2fd231f,b1313468,f516af1f,76af0eac,9ad51d76,26d6731b,71382ea2,1172142,fc5e0f5d,d0f7afa2,c9409fdc,62bced0,e8246194) -,S(25f313d7,ad044b0,538bff0a,ead5c689,d5fafec5,7cddd9a8,31b9a4f,59b848e0,f28c77b8,9202c9fe,e64c0580,75a972cc,a4839e20,42c32b66,517605d5,87470c40) -,S(24a8d407,e26c4cae,3f8dbc18,5820f345,81bf4355,7ad036a5,200b9b7a,68bb8d6e,fc6a5d96,4fa25fad,4d09a1a1,a4ec4697,818e46b0,8cdefb70,367e3453,2462b98b) -,S(ef4df8ea,5cc100e2,768aeab3,112c7ac0,6077b754,75cab97,df3ed51d,6d397f4c,fbf555d2,27eb051f,54965eb3,fac1e21b,82d216ec,807b1485,5074ee56,1ad70883) -,S(80c9d594,578f6e4,e8462dc,228cd99,9b621493,63d55cf5,80e1c524,627055e3,b6d5bf04,97b44e3a,7c7e52e3,28f63214,5eedda41,f80c44df,c7ca6d29,77436f24) -,S(35961cd1,57bc1774,40dd41b1,6a81e31e,52349a5a,e4085248,fe4a19c3,b10f7a45,b999ee7c,b32f1051,f0e7eb9d,4689fb30,fac7af1e,b410d53a,85e79f27,70a7566f) -,S(4aa49d09,32a7fc5f,77a76a12,16240142,596a82d6,6b59d388,24f0d8a1,e7f70948,adb5b12a,5e40bd0,a14c174b,13c242c6,c5f25ee0,642a6265,60d293d9,64a4671) -,S(110d8320,a9b2c5d6,5b06f0c0,cddd243d,c83cfe4f,671db970,d1213780,f6c4af0a,a97c2689,5c7b6ea,a3a02564,d2af735c,9b43ceeb,9f6f2557,3fc468b0,467b12a1) -,S(d01abcdc,a363b065,d8d2bb08,388c3545,cc8ee88e,90ee66c6,18a9f575,c0caee80,317409e4,a70e30ac,279914d7,135f9d18,e19fe520,4c83c472,5f86a614,1863b4f9) -,S(cea07679,64506753,8dc24b68,19bc3332,f320f16c,61eb7b85,96e25bc4,1499796,edff87c0,67e97ced,4aa330e4,e9dbec3f,d800934e,ed7238f7,8e97a46c,a6ad9ea3) -,S(d4463e7e,da5fcdd8,8ef0133,a5dbb1ca,c93aefb5,64581da1,3acc3871,cb94ce1f,bb1efe84,81dff341,dc7a4a8a,c2e44ca1,b071bcc3,81e7ecdf,4d4b7edb,6996547d) -,S(89cb575,5e9323b8,7771a2d0,58dc78ab,ad8bba70,6f845a8e,9a45a16e,ffbca1bb,f7e743f8,a24a6728,f8e8051f,5a303d71,f1f47059,202d332c,23f3a293,9ab97e37) -,S(d035032f,8e8e955b,b71006d5,a3b098eb,7dedb73f,a15d0d36,7e01c390,18bdea9e,1ba4cc2,fbabc437,a9d17ff4,f3c59f2d,2a416d2d,c07c0c81,c3e0a180,260bf2c0) -,S(fec9ff6a,e37da167,208b1247,b754cda4,6c6eb072,8d6b65b1,3754e2e2,eb3223e9,305400aa,27a59f3f,f19d1513,3c5a3655,464c6f39,94fd2ec4,562d7f85,fccfb767) -,S(3cfcc8e6,9e872314,5853743f,efd2802d,bb1a05dd,a03a731,77daf6ca,da9007f0,42b23158,fd0c1401,29298d42,a6cce708,743924fa,624d582a,94b682ee,4beb222e) -,S(4438bc8c,f41b7916,dfcdb038,5c9b6806,83362409,69ce8869,c294990b,cd340e45,78154e51,a4dd31d5,14885a18,b7185fc6,84c699de,2862f480,937c9697,6155ae70) -,S(d2ed1c29,faf76c12,fb15b514,6a31cc2f,c799cc4,5fb226bd,c38d3b0,176b5d52,54984b30,96d0c2ac,763654b3,32666baf,82c04562,d0d92310,cce6db16,216bb219) -,S(37f21b9c,d1243170,5ee6db23,eb578ab7,31f4b470,ab07e1e1,68e69bc7,539b170a,afdc95dd,6379244d,cbcfc811,54aa1917,e8093b54,8ec2be73,5867574a,82ec10cd) -,S(73fe29dd,54c8584a,7d25641e,c62f257d,400f013f,763c504f,f0a3ec02,d1ff8067,197ada53,ba57463e,e23b9831,ef8a6a69,d3d2f84d,c7225782,e7569603,fe1d1c83) -,S(56b27676,f0e88c45,3db1819d,36a73d03,95aae3b6,59f612a9,fe28714e,20bc73c,98660256,fb7d7d75,aca14107,dda9e7c2,28459341,ee6de72,9e463c2c,17367149) -,S(fd898f2f,e7f918a4,61f8e57e,f30380bc,5192a5d5,e1f520a0,5b99658e,8d57bf54,6861b3c3,5b0f6943,48bc4886,15eab8b1,36630618,592ac04f,80cdd632,aa63b620) -,S(fef75974,2911ca2,8057e141,6288b351,ccf2d490,634c98a7,a80153f,e9dc6929,9d5d0031,3417797a,83f0ecb5,d4f45890,d679660f,b1b19686,ffbe060e,deff716e) -,S(2c4338aa,18a27e60,d1daaa92,3d837414,f199f585,8d33b66b,471c6562,c8324bb1,13c28f36,25f2b273,8646cda3,5a2a729e,eac1de3d,80430cd1,6a0f3a9a,cb859fe7) -,S(53d6a5c1,deb56159,34416235,c2f597af,f6e10ed5,444d15c5,d9ca82b6,8e1820f8,26a5d559,cc04f53c,6b1ff3c2,4d5a62f,f63e50f4,b7c1b619,9dc54c20,628364c9) -,S(e432c338,e550a635,79ab747c,f01f3ffa,9e39d066,b221fbae,8b44429b,873decd5,297e10af,3006b09b,80d0ae19,3c1e8b3a,80ae9051,3dd9944a,444b2c7c,42d0066e) -,S(a61c5ac2,60f3048f,92cc2af1,6d3f6a4d,696e543,f044192c,9d840962,493f5cf0,1249d4f,83608025,331ab42f,bbe338b4,727a5ccf,b086aeb3,f1d9c96,26859158) -,S(a2f37e43,c3c2ffba,c45ad316,e912b586,2a9ac698,f85ea54e,98fe9a6c,e1fa038d,93e95000,6bd329ea,57397b25,71dc2e78,a466c4f8,76ace5fb,36d945b,a6e9b24c) -,S(b2257994,44c2ed2f,3114185a,6ca617b4,bf4ac15d,40d73b62,44a81852,d30260c2,fd4607f1,3d4ee761,adb6b139,3f87bf8,e8b05156,5561d650,a47efacc,5ef01dc3) -,S(d0607bf1,5317662c,73df9f40,805c9b3e,208ca1e,7fa8c04d,ab9766a2,8c7fffc2,f06da1e2,7e721799,41a9e128,e25ec992,eb030ca3,6161c02c,8ee31d22,388bd999) -,S(596aa391,d4831e61,55d80829,35a85bed,a1ea3190,a499ec6,374389cd,1bd5d8c9,cd9240b2,9845911e,47ad147e,ae55a0c8,639b994,8d72d2f2,72e89fdb,578d4ff9) -,S(433ec09e,19b7543f,a460de41,e70f63f6,6097ece6,dad9b5fb,f4030c7d,bc5862c1,dce03718,a609efe7,1858f6db,184708d1,9275ec2c,76d5e93f,e55a13e7,927cba95) -,S(343b03eb,c285418f,ad522784,f91707e4,f268451a,394e85d2,824c837e,fa48900a,e6595234,643667c4,bb885b8c,1ced3a29,a71212df,f2904549,ccb91de3,75787922) -,S(6094f67e,41b23bbf,4d594e97,b53391af,f10a978a,19244189,63814efa,ccd6488e,ea874289,dd943f7a,c109939b,8fa545f7,58359804,ad81ed0d,26cef135,cd138954) -,S(cd0c3700,bba5677c,8d0ff53d,f06bdbf5,c5adce29,64921c9f,a1591c91,ae0a375,720b88ac,9374709d,1919854c,237cc5fe,dc53b14,3897e4f,3502af17,d7510c63) -,S(d37ef1ea,95ae727e,5166dd59,bf5ee82a,1f215720,79d82e25,6369464e,d9a87cc4,59c5321a,d700c559,c92e500b,1d3a4589,15a88575,df9774e1,4bee7b2,ccf9bad8) -,S(238158e3,d58e7618,95f7a0b1,cdad8a24,3e19bfb6,d1c65929,ff08e766,e62c2b12,1f65fb1,8969ccb7,27d50e46,39c7551c,5b3f25b4,90b7d70c,cc5e4ae8,7293a0b) -,S(260a340a,5245a039,4a2f0908,f2912f0f,63ed68b6,aba66fb1,951128dc,9d542512,d30646c1,e8aabbd5,e758adbe,980715d2,b0b169c6,fe09c502,3beb7f5d,b5422be) -,S(7333eee5,d111e138,f6e0b2d,4b476ba3,6df4357d,b28c8e7d,f232c61a,6c3067bb,d427a423,a4de1e60,e8b73098,b8582e0e,18923637,c44c52ef,fa0b5f90,8ccf786) -,S(c411f215,dfb87aed,be2530c2,82a61e5b,37a0df71,1ce61fd1,25624b44,b7673eaf,ca3d89d7,d136fd46,161fdbd6,3f0b075a,afe90855,51e075d2,391f3206,382a0441) -,S(275b0a1,9dd09495,78298aa1,c4b62ff,11e715fb,6c3740fd,80d7ec03,3f2635e,30dcc412,faf3f389,c9919b6a,f96e7b28,6eb8abb4,ada80525,b9ca7eaa,f3ce74cc) -,S(9f774052,6818bbcc,b068c11c,b400eecb,da60c4dd,22353a3,4145e3e0,91f81617,a9e56fde,8f38116f,cafaea93,35ee3688,50da5107,a5a3e571,92f2bfc,1b55033) -,S(60fb35ce,f1098201,353bd7e6,89b42fc8,9f86dbc6,3eb400e5,3b8d16f6,28ae4358,1906ce1c,6a6f41a5,2f45424e,86633937,8ed56578,ffd94174,f4f85960,ee0f5c2e) -,S(1390a621,f999c3d,1737c72c,3235e542,99ce4796,d65c1ec5,45f60b71,19f4ae25,8f1cb557,b101a876,296881fd,5d30556f,55d739da,5122c0f1,43c04add,3485dbad) -,S(15f372d6,9be09ee3,8d43c453,dc488f17,42f53a7a,7923439,66946210,60f1cfcf,c6007ae8,a836a1fc,b5a4c0f5,e584fb7f,2c468d68,9efaefa,6303bd6a,beecb05d) -,S(bc2b2a76,17dd9fb9,e6d60931,ef2d5755,d33c7174,7e8e28e4,be151b42,14537d80,2582a69,b6e9b9a8,c5bb4b79,4ffeef15,96f383cd,670eb524,2ac4e7ba,375509e0) -,S(5f8e0957,61e307de,26ffd39c,92410937,5dac9c83,7a5a62f0,b0864cd8,a37f2686,d342dc84,7657354d,d524b32b,62f5f69d,5b2ecbfd,71831b28,565cae36,777534c7) -,S(5451cd91,9e849ec,b8dc75c7,9f939957,69a39234,38159544,dea98155,cb001c5c,e00d1d37,f9ec02d1,ae8222a,744381,4f16220,800f84d9,17cea9d5,9a9e2a60) -,S(737b89ae,9d9951da,d2b489bf,f2ff714b,dcfb13fd,829160c1,39875a46,7343adc7,ef9e2ab9,f8246113,726e5be3,5c1da48c,a6b4fca0,53d35dfa,8a3d826e,e48c5ced) -,S(8b80e227,9b0a91a7,6af48413,71ae6fdc,68f4f5c5,58de6efc,1ec0034a,36a26000,909b49ed,6ce8c555,25441ab5,1046956f,d25a3a73,5d979c04,43ae5891,fbd43df6) -,S(9db9379d,346cd59e,ed0c0d44,abc4baa0,3b7af170,9f034c79,151aaf54,69296780,1a8f9e50,918a104d,b525c439,bb16b64,179dc4d5,452c86fa,e87ab757,61e97031) -,S(3aa7c8c0,293e5c9d,fb50b63d,340851a3,88b1641b,b864cc08,fe776500,76f98d0d,974dde95,7c958b70,e0ff9399,d2d03da3,4dfc3437,c1ca557d,2240fdfb,3ae1d36d) -,S(26cfaf0,d27825e1,6014e5c3,19bb907b,7a3b777f,b6bc69da,5cdafec8,40d5b4b5,2eabc11,73729fdb,d31fabb1,722be99,e5b4355e,8c2b4bef,53b21dd8,3cf81ba4) -,S(ee495a13,bd1ba28d,cc26fc72,4cbfee95,3aa72852,57c883f0,cb09d6aa,1bdf3b20,b340a2f9,978013ce,8275b7cb,3fad5c1e,857bc6d7,b43782f2,1e737681,fb39b619) -,S(2e04dc81,831bb465,59d6c354,c4c6105f,41f61301,769d6006,adb290b1,b75540c9,d086cbba,4d221cc3,7cc96b20,adceff4a,6157ab9e,686d1fd5,5d56801,dcf4b779) -,S(557b5b41,b2b2e4c,598460ef,22888da0,aa2ec3a4,7980247a,e8bd465,a6e64c22,6a3c62ef,f80832ab,83a9d698,f61f7903,b7f64e41,9900950e,c7d79369,403d57b5) -,S(a0ea9ddc,e2797fbb,d384a1a,2c26d7c0,edf866f6,9addb763,dc44b112,dc1cdc5d,a085725e,d947778b,40a2baee,98dcf460,b084aeb0,3f96658,4f990895,b15e3378) -,S(1acb89f7,55a51f58,d8ed16e6,99a2294a,b2f4bff9,2fa2d1de,9883061,4ed4b5fd,5b243df,31c3bc95,79c47c57,58eef875,c18bb896,424c0293,22d729a8,b7a32a21) -,S(fbced690,b601e450,2f0ed32b,8c2ac448,31c4b327,a4ad9648,97637b08,2f3d3912,3235804b,549210ae,8cb5bdae,e5b1b474,e682cdfd,8af4acd9,8c0c19a3,cb5c017a) -,S(75339a0,82043d85,54ff592c,186a183e,4597a0ff,48f280ac,d760d134,9dfc6b5a,dbf1aaa6,8bd5db0d,8cdcfee7,de6635b4,b7877ef3,6da38418,5688fefd,dc584b18) -,S(d83caf1b,2994a763,77a2bba0,3c644e48,7f170d5,845a7d17,b8be8bb9,84b0ad1e,e479d930,6d2a405e,f0be6418,3d4f8dfc,a7f58ff,95df1e38,c92a401f,17745879) -,S(35fbbe06,39d9fc5e,d595a67f,442d7adc,ae6f566f,4641fb76,149d6c74,42af49b8,5eaf204e,6217ef53,1ab09a53,e6cf4d12,46d6c4e6,b71ae8ca,4e821474,94d00680) -,S(d5563a62,bd6fba1d,e252a5a5,9c03bdfa,6c570145,71cd1a31,bba43700,2a7c1251,2f83b6a3,2efa7b70,1b4d3262,9e7a8755,8b681d17,cff0b992,1e102b7b,f851f543) -,S(8f2a2a14,a834ec79,107153f0,ffaf8f46,5cbb46c7,5a72d07d,5e2af498,f3359b75,30ac7456,5c946e21,73bdbd9c,dc999e79,260445e0,dad2467b,97234789,a4de1184) -,S(74482ce2,45605bdf,f7d586f3,c2e343a6,8f9579f2,543f7f7,22a4b352,24361b4,b2cae040,9ae59ee9,bff4fb5a,34847ca3,e4acd880,e35e4d5a,5ce47b70,3cc565c7) -,S(ca0c158f,cd362d9e,3724bb2b,f07305a9,5adc440d,24270efa,2a8f208d,7f540295,9e1daa26,5a5effd1,29f62b,bf0f5c60,c0c2b73a,58ddbd99,c832125d,3927e7ae) -,S(9c5403ab,b8b04f47,5eb4ac6b,5d526784,8d237d3d,c36e8698,d59172c8,a9d9e268,89cd0c87,9d02beeb,ffb6dc2f,fa882711,2071cde4,ee71a7cf,669f64b7,d463fbb5) -,S(e6bf2997,5eb88332,64169169,62f49080,29072e85,797fb699,df05526c,c4ee0de9,ae9de06a,1952c472,6047bbb7,b967e6ac,db33a123,24b07165,d2caf737,3fa40068) -,S(ae4ec439,e4392deb,5e1b1565,2310d52e,9cf5c0a9,8753a95d,d7b51e1e,5889a744,1400b900,c3159d2,25ceac35,4e566d2f,4e6f057,f4664b8f,465b0f53,2ba61852) -,S(c6351ec4,27d1d6c5,64c05959,ccee21d9,b086a881,3f4d7406,ba8d0ec8,6cd139dd,b7173d5f,bec7a8da,89c4cfbc,a911687,f39a455a,9293640e,7d473bd3,ef2dba3f) -,S(fe44937d,a54556c2,a50d9538,98abc367,6da5d722,6c6d3379,20092042,d1219cbf,c5c2e2a3,174fffd5,74761486,669b0cab,5a5eb21e,be669ba,c5c5a4a8,46e404b) -,S(760dd500,b18aa066,19a3977f,ddbb6947,d092649e,485f2b6a,d26d01aa,445588a8,cac47a22,6da2825,38126d62,38751a4d,93daf13a,420be353,3fc0f7ad,db68c20) -,S(8bdd111c,e271b136,45d00636,f2d33c92,df570cbf,6bbdc156,69fd898c,ce4ea8ff,884f1430,8ab84796,d61e557d,abb4d15d,15114c0b,dc770388,6ca3ff0c,622df5ad) -,S(406c6d3e,79fed3cd,16d616e6,7fe004b5,4f589594,ecb7ca6e,24210224,c5b4eeb5,aeffee19,f82cee83,d4796668,8545f0b3,b8e61877,f34a0b23,c6a3573c,b98c9b7f) -,S(c645ea95,2580652e,8e05df6a,3d208df0,83e00eaf,50cd7d4d,a7c51458,324a41f5,8b4b9cc9,d3f00fce,332d2ae8,2874787a,6c6c8008,a7577ad5,d225f951,82e8bd2d) -,S(813cd833,dacd8916,76af5b48,5d1ff72b,df03f2ce,c7657e6d,249e79f1,f12d7476,c364d1ee,f5f1d5f2,7438c58d,ee926c18,7162cc71,383e9524,b80cbae,3cea17bb) -,S(fef2337,cf88e025,d70e2a44,e68c22bd,95371f36,14ad9009,f2ba8286,290495e5,b622fc00,8b0a0f9a,9a36ddeb,ce10d871,e5dcd7e9,65ed2784,21ab5891,6aaf7404) -,S(8505810f,22888b4c,c8bb708e,c1e4df79,a3a361d9,5ac2b259,acc18d68,e50b0952,b80fd8aa,b7196e00,3fe24ed,fc6742d3,e7b2115,967f838a,2ef00345,3dbd4d34) -,S(b7aa2500,c77effba,3e93a4e0,b09a0f52,92240fef,4282cae,4c8036ab,2e5e5561,85823a06,1fcf2328,2dde378,8802d211,fb2cda3c,316dbba,d30048be,1295d7c) -,S(6dd2e626,181f0007,6ed53763,32493f55,a77cf5,3c268524,2be805c,7da06c95,2a6a76bc,b3f96c70,78920303,c5ed3208,170fa969,6c5264e0,c3cb1d86,ca322da6) -,S(ff5181a7,ab79b40,a3afdd39,8ac729cf,e49a6a23,2fa46f9e,4ce0bdc4,696e9f9a,99c20ca8,b11b6a05,47e81074,8a34c606,140eb3c7,ce5c843f,60203249,62858aad) -,S(a5dfb758,32aa580a,790fce58,b4c04a1c,9de648f4,19ec33f0,92491275,e8243ef7,78a66f07,e1466785,edfd5523,99fd1935,1ccadfb,e3b25bf9,d5279ed4,1d0b9fd9) -,S(fc5e4688,ea6e4553,610946a7,dd3497e,a5f698b,82d6b439,6a21e082,a9aabfce,d1b32a9d,761df7cc,3d69b5be,d7aac28f,976be204,7b2aff0f,2824fb00,b70d697a) -,S(179fb126,a3cd9931,f135cbe7,2604d3bc,83cd986a,d9a7900a,17436875,d3507016,dc2a57cb,b0bd39d6,c8daf32f,fbe6b300,52cff0d3,12e84b72,c00a7d76,3578e749) -,S(af37b7e,cac16810,9c51fe45,b2d6da7c,3505c1e4,bdc88b10,5a386fcf,e30a6c1b,4dc24b79,61e9199a,f594974,32c9352b,4ca9d735,84dde4f7,a4c0127f,21cc17f1) -,S(62d66f6,b534cd8a,66236ca8,5b7de9a1,eeb49aa6,e65e5298,edd1a99f,96fb1dd1,83c05dc7,e69dcb3c,86dab3d1,153d93f3,e9861239,6e25d3f6,6a6d637,248f237e) -,S(6a40f396,1587f5ab,89280eb0,568ec9c8,6958b4d,d8a379ec,2ce2489b,7e451ece,74972d6,1100a0bf,7751a400,6093ec78,1fe16c82,baaf0e69,74142a17,a405da36) -,S(2838f8f0,c6e20e53,9ecba383,c6e07a2c,5022d436,904e5da2,b91b283e,40bbd6bb,6bbbf962,2b7c41a4,6b72a30b,d051551e,e1227362,b0664dc2,509404c2,819b4985) -,S(21e927c2,82cd4635,c9c19c00,f18ddfe8,7aa9b60f,f3000c3,2019871e,a443333a,6834c23d,e05bc59c,f6fc64a3,af61f049,7c247d86,f76a2ada,7771dd16,999febb1) -,S(d9817ec8,f88f9cef,92cf9df,1fa9099f,3f10ac61,fa641ddc,9f36e854,98822571,53c57b49,4d84c3e7,679060b7,c7c8d4ad,f2db0c4c,c8cabbc7,5c29ad15,80b963a9) -,S(6eaafe92,1994519c,1c61bbcc,c1ad6ac6,f7a2d0b4,fd88354a,6a458e78,17503e30,f29a7f85,f3e91dbd,9e011055,f47a5079,7f55fa4f,46a6b188,ea4694d5,a086b4e) -,S(2bd45f,1625722,2352b5bd,a6d8e2b8,e7d23c3,f8497fe7,348a8d59,97b5cdbb,b5f9d5a9,8ed6387a,41397e54,6b3ff76c,4c6bf446,3093e979,2d1f8748,7a6b725c) -,S(176d02ae,cf4f1313,ff804e22,326d6a13,8b641e2a,3fd4d38f,2c27a35d,f1f456de,5ac13641,d2f19a4f,77097a4e,8eaae498,2afe9494,9188e411,e03ed031,fed9eb40) -,S(6d0bfca8,6296255c,1fede5ef,8d04dad1,2b6625fd,7bc127f7,3f6b82d8,b257ca8c,3c5c434a,81c17be8,8101b5d5,ead55e60,9d9dfb10,c5ce1b41,484d5fb6,f595fc10) -,S(b67d3fe4,f6617324,a4063fc1,142ff4b8,2a605a26,8b8fa146,697db96d,570ecca8,63ed93c7,a95a0ea2,9ffd6090,5c096042,b5562997,4957f47b,2d5bca14,21114bf5) -,S(c171bc24,fd80dd05,4eb3e3a5,5f50c9a5,322989c8,a1213179,be4503d0,2fb1f1a,2ead84ac,7528e7ba,982fec81,4b68ff7f,7aecf675,281f126f,9f41a7c4,5deb2e03) -,S(c4936f57,96269373,21abb8d7,df07e4ae,48ae1f18,ee1f8ea5,6682ced8,ec911593,52ea3664,1b441154,81805582,dcddf216,80eaadf7,4fb324dc,67439b03,aaccb1b2) -,S(b0a38c84,ecc73fce,200658d3,cb43cbe8,e0df114b,5d1ff7a9,33158b67,b404dae0,40c381dd,fc600cfd,ff24d7c,988cd4ce,74c18fe,130f4248,2ced320b,b91f2ff3) -,S(1610da0b,300d59db,d8746d5e,17d71ab2,e7e9c1d,2b43b688,656e570c,60336b82,8923b2e2,fa3fd34f,eff4ad22,7f9f6638,745167d8,fb769b34,b3bb7e12,a25c892e) -,S(f6723495,10cb5b38,da909d65,333adb86,d22ed855,74d24d35,83294cfe,ac88d999,6f726bb3,891187c6,3c74392f,a1e3ffea,f55b9a9e,76e3b584,1d13dac2,e888c740) -,S(3cda21c1,d048a768,d2863f4d,1028459b,c9a91c31,2626940c,f762c074,23d85796,af05c34b,4a15e00b,b6ce97cf,501316a0,85ba33f2,cb536f27,324f5506,54a8f03a) -,S(24e1bc3c,84c0ce3f,52e1443c,1ce82330,b69bbdca,f09724d7,e616135a,d9f99c0c,61385dc5,e5c36e42,275109b7,9c22940d,3ee4c679,99802e67,3163c114,be7fb0eb) -,S(f9511548,94dc4fd6,e2907990,7da4a5d8,ffff1eba,4fe12201,a3ebadec,2620a2fa,d40669dc,1eee21c8,ee1110c2,def5de0d,4f08ca55,6758dd14,b6f3ce64,46b2fe4d) -,S(c6808c80,61dd7e3,f6fb5ae,d129d23b,c2101af0,130537d5,4bb99baa,1b8ee268,2fb3e2aa,77870909,993f9d91,bf670cf9,bcd5abfe,26ea9990,6f9805db,c8707f84) -,S(ca952b81,f79a35bc,effc9f2c,c66c9928,cda6330f,42c44f9a,3191ea5b,5f473c3c,aa53ac41,f34fee5a,2028f7fa,8ffd5106,23cf2dfc,cfe5a1f0,99ef3649,d7f846b2) -,S(679c1de6,521c29f1,9b0d3c5b,ab481e53,d01ec2ca,c719fbe4,16054bae,593c0592,61d4eff3,5daff1f,a4bb875e,bbb42722,9cc996d0,405c74d0,6ef0c6f1,31ade7c7) -,S(6f7ac468,d33618d7,8c59d849,3571abb5,1d445a43,af10fbed,c5d25b13,58170f76,9187ac46,f2076aa,5cf4de93,52e5437c,4cbd2220,d8070172,807e84c8,10a05090) -,S(f4ce85c0,86a4fb78,2f081fe5,379984c3,1a7aab89,ef9ac386,a6a8a11e,596278dc,89d6d9d6,75983a6a,d1dc4c45,a3dafc1,cf951dde,2a038261,b414eb94,f9899886) -,S(18b0b225,19360c19,739623b1,7850107c,32ca6b61,295a8161,fc9d2e1f,8d1e60d4,4d8fd58,98ba10a7,3aadae04,a9ed18a7,8c48bd94,7825f0f3,b42685e0,d391dcc9) -,S(3f75a866,537d022,f6b9b18a,330ecdc0,bdfa7aa7,5b213f4a,876705ff,635d8eb,fd0f335b,b4f41615,7ea2752,2b8aa40e,dcdcacbc,1beaa051,97ecc250,f0782cc9) -,S(58310e74,290245af,c4acb91f,20b29db0,f5195039,24b9f76f,16952141,875d0124,f79e457c,364b374b,43c8d6ee,b408cbb2,94fe8eae,c6914427,83a74757,c8b27f98) -,S(90692ace,4fd3c4cd,3c808952,d5ea0781,2192c807,4619b8aa,4274426e,feb7f6d4,3147db2e,7b3b8506,625c21bf,8803c5f4,e7250b0c,4523a6bd,e25e874f,76d1622e) -,S(154d18c9,6c441173,ba7b8d2b,5099d9d3,92ae7e0d,57419144,229697cf,52384f73,1c196518,31ad8cc5,ea72b3f0,ed0d30f,78b773a8,1f54fc37,29043a35,6fde93a5) -,S(311ebd4f,5f52bdca,290dc97c,73102ecc,421a0b07,4c53c052,11b0bfc7,3b6eb94,69d17492,eca55f53,72b04c34,6696454,ab779ddd,8c7eb07a,34c8971c,b5168019) -,S(f62a716,6976f82d,b62e48a5,1eb45464,c845b71,6436d639,a9aa0a06,feb57d0c,a0b93a32,3fc8c047,3c4198e1,5ab5f499,e3eaa4f1,4bf99a69,b3ac303f,34839448) -,S(c23e0cdd,5e39eec0,d3ad195b,19294bc4,30c11eaa,67c6e87b,a4e2a88c,60998ed4,a521d1b8,8e409682,bf7b7daf,ff45f697,6254b8ce,6c63985a,ad2d9cfa,559208fe) -,S(742ca7fa,a8b4a98f,28040f8c,15db6045,70353954,b862c223,c7979eb2,3443ebfc,251ef412,e97a7e21,292ad45e,46c40774,b97a78cc,7826e45b,cef481f4,a64b838f) -,S(622a14f9,7bd04407,63eb5d52,c15c2f3a,ae185395,e89dda70,3cc4c439,60c5592f,e5db52cb,ee60b303,69da59eb,87ce10c3,c485c239,ae1c849d,32e0e239,df4d4d46) -,S(3d6dbb7b,4e28da6,b731c67a,6c038107,c2ec325b,6b10e31d,9b7d5273,fc81e20c,f0b619ac,febe82f,8c4caf5e,6d4710b0,caf89c2e,1a20073d,66ebe05d,69fc2c9f) -,S(d450d441,bc191b5f,9c2556c5,a56d20c4,48afec13,c7e4b9be,320ddb90,b4c320e3,661be65,b5eef8e8,b357f521,d360379c,585c9e71,c27bd038,f2d63f72,6f6606af) -,S(82f9dd1e,ddb046b2,2b33bf19,2970e41f,c5df0c45,f1375133,fe1b365c,eed1ec7d,cde9eef5,554476e5,e775e829,1d38a572,1d055c4a,925c7eff,35a389b1,388e18d8) -,S(5227c547,834a79e2,d6fb0c3d,720661ac,7ec0e2ff,5a1480bf,3f31ac82,cfb2650d,dca309ff,621c591d,aea1bada,bb1be76d,2fa30a0e,1c83b4b0,d66cbd59,7612c0b2) -,S(3eac813d,7e2c8034,f1d58217,c4372a96,a1fcae27,b29ed9c4,e870034f,7faa78ba,94005cc8,7b8f7aba,143573b1,79aef942,c1519b3,9c63b58e,e420a875,7c4c8b80) -,S(9373c48b,50fb0243,b42762e,3b80994d,61986116,ba2c0677,a38daeac,7dcb21a0,295f694d,70f8295b,cddc1c76,141ed17c,a1cd8e5b,79909785,dad43e92,9247b250) -,S(14019457,db851046,42b51ece,50fb8d94,201a80e0,f29d52ad,1af35e4b,8d82c6a8,c47d97c9,df2816f9,a6147dba,7658b5da,f9588dab,8aa393c5,8f721786,9c498b9a) -,S(1b01f484,ce98064b,f60333d3,65d926fe,ee1cead3,c1497c88,8409be91,2288890b,6817b86a,86c98512,634bf90b,564ce109,13fad61f,c807a256,36a5d6aa,7f2d6005) -,S(5bad5660,f615f36f,6bb9ff3b,19c07b74,9519caab,fffd98a0,4520802c,88b6cb22,4d23780a,e6796a72,324c369b,1987465d,90540788,88987513,13dea0cd,69f90dc0) -,S(7044bd7c,29d2a7cd,d662bf16,90d5ee35,93175691,b62d68e3,f8f66ef5,8304c509,f263888d,52d74133,60ddfb1e,d1c09b9c,871d6eb1,e5833949,13d24973,5721ce12) -,S(186411c2,f90c5402,6445dc4a,4764318a,f3acd811,52c01dcf,d11d13cb,a8c02afc,462b9556,1bf18dff,8a4211d8,89f420d2,122c4ea9,7fda3d23,558b6304,d25b7aa3) -,S(62ea528c,185fd551,745c1512,6fbfd40e,5f8933de,4e1e3b95,92a93b0e,b762ec3f,276da42e,3c8a6755,6be49e00,2e42522b,e3b95e15,39a4708b,36429a94,4f6a86a3) -,S(5e2c7621,efa587ce,bd3c2392,a1b8dac8,50b15316,c42570ed,7270b521,a65d6cc0,c7faa23f,eafb70ce,723338d8,19bebd10,bae703d2,1e72b496,f2f95b6,e83d7d22) -,S(7e27207a,b80f124f,9694f143,9a0cd895,2c67a719,4075d9fd,1bb7c9a5,a22dfa3e,322b729f,e19d75f5,89749527,80f3ae04,48edf9e9,d8c24267,18812dc6,bef5e602) -,S(3de40b43,9077ea26,8d94aaa1,93e9c7cb,98e362a1,551b9b10,d5eb64ce,15986582,ba36c2b,e0f9d3d0,220eb47f,4ea66d01,59236411,2898172,8582d3c5,19576943) -,S(81e94808,7e89846e,6c7e5ad4,feb8f0da,4553e460,e3e4620,d87a206c,9d3232b,e216962e,4068a44,920e6a9e,f03efd5e,afae7f96,3497ecaa,dc741c37,7e9943b3) -,S(3056eeb0,d00a19cc,bb5a2ac7,f320ea3a,4e931187,498ec23c,daadc820,a34f49da,c6803559,271b265c,80257585,1f0a78e9,85abeaac,cb570787,f398766c,aa21fed3) -,S(9b1e1189,752fb763,7a61246a,7134145f,86b973b1,e44a5e7c,c59998a2,77ed64f2,f6793c87,9b8c380e,65296c8b,eaeb98c6,b66e0be0,d03865f4,4a09177,5dcfd332) -,S(807179ba,f1f9ce93,bb1f7dc6,e3c6514,99077419,472b9d8a,1a8cc4e2,f35c0c5,36807219,9966eb7,f18dfb7,d3316eec,54f1a9a7,7214d4fb,ce3f3ff2,935e2ced) -,S(60dd7b7c,cbcab93b,8ecfa461,8cfef03f,a74bdd47,9cb90a1,5e46ca7c,c1bafcc8,1d24d147,9987f779,90cde228,22ea0cd4,4236875d,943eda25,fa25096f,e16b8ce6) -,S(19daeb26,23383b3d,d15b0075,77a5e92f,bcedee4c,91996546,a7c52200,d243e4f8,12676559,3d67fe33,b1c01d4f,cae44be1,5f5f5e31,1149962,83ce8f92,f6485e3) -,S(f42f8e1a,813dab8,9e4db5de,27445215,c0fb1cd8,91c9a96f,ca5ae1db,14e84361,3cd2ab35,55705994,42070743,d01fe633,34819d2a,af95e97,6dbee1b4,e3ba2ae) -,S(1a2b774c,d5d0dd28,26d7c4e5,886d65b7,a219952c,6a413d2b,9fa8f765,73fe2bd8,4e2d0ecb,384a158e,e57da809,d065e39a,27830625,400c51ab,dffdf615,5d88032b) -,S(e9fa7d8,94c55075,1ad1731a,b322fab,fd3d17a,889bccc3,73e44e37,b4c2c880,67528cad,e7987d12,77c61681,36abe0c9,5dfdce09,33129f27,ffa9d36,53673bd2) -,S(5347f349,e54c301b,abcfd8cc,50f6fe6d,8fcd0fcd,861757d2,bc36cbfe,39f460b8,16d08dcc,2a837b6d,f9fe2ffa,b188a966,9d39181a,ed2aeb40,9ed17c8b,554e9d27) -,S(e20e8cea,4450bf03,149bdf60,e95f7ed3,69fd79d0,aff9fb8c,ef6e5287,830c7ddc,fa256932,fcc569e2,613bc0af,5f90263e,6db633f3,6cebfe46,4c70b043,9b886058) -,S(69132e10,b3a919a9,8a7188b3,e9afcf6c,2d53859a,5955e114,a41f1310,55ef8441,e6c339cd,ddd26e0e,ac4a1c2b,39e19cae,2d67e726,8518b750,94cb5e6c,b525d84e) -,S(11e10c95,9bd9f79d,c2819a87,e17c0de7,9105af6b,fdbe3f6b,88d198a7,106c861a,27c29227,4a3677c7,381fe385,8382ca38,d4b98e91,af4250fb,40540828,246d5c16) -,S(785934d,e1b1827a,471d7e59,2a4c3475,3054b00e,b8aae372,444b00ef,d9d894b1,7b8dd2e,a038d4e6,23f0f1f5,a2f75dbc,fe34e76f,6d106ae3,33d88a07,56dc4a60) -,S(f09c814e,8e66b8e5,930f1a49,28b28e5d,206f4108,fe99f04f,ead93096,1cc17605,469bf934,b4059a4c,4a942214,e1d86fe6,dc900426,c7d0eddb,8d89e86c,76d60f24) -,S(732901c7,26982b9f,ff1229a,3e8f7c83,2f47437b,412d0b3e,274a73e4,24ad6480,6b82e2d3,d4830086,cf416593,9b04ff7a,89b835bd,81cccd8a,7a29d47c,b70da3b7) -,S(b8369a11,d23ff4ea,99ce166a,4708ab9d,389cefed,b1843d8d,6fc11f74,7260faea,f4346c36,63ec0ab3,6ac12df7,f61e9848,c2d4cbd8,c8e6e173,2d104d0b,aecaef9) -,S(5499e409,3df85dad,411b8675,c09d0c0,c25bfefc,2afb0228,b94f834a,34ff83bb,7775c877,8fc6e8d0,519a67a8,7d2fe9c,c8abd8c1,15ae1700,ad1a94d7,925a4c78) -,S(fa5bc8e6,fa9b13e8,ad787ba1,497a6b97,5c34a64d,a0da5b5c,836bd71b,88c93740,8c919cc1,19e45de1,54f6d0d8,f22d3b51,169b3f0d,181bb40a,56213cfa,a4ad126a) -,S(a871c481,a84f4447,89ecded1,e2b1f525,9b1d4ab2,b16af331,199f89f5,730cdb0b,c478609,30b85d69,1ae45d62,7aeca01c,9f10a119,500d5d4a,c317fdd7,8de4a103) -,S(63d3be27,66d33bf8,f7a38577,aadd5d9b,234bb77f,d206b056,379e023b,ecd25616,9509d09a,6dad6da0,aa5151f8,dd8e3800,abd8a799,2276ea0d,3c958f76,498ada87) -,S(413ab945,c133d383,d70e81d3,34bda75c,be7bacf5,e49d71e3,7a884489,adb28f8f,c3d49f0d,6c65f6d6,1c9c84df,a4138076,f0168916,393612b,837c1df5,df710a02) -,S(df070f4d,ce208b39,e2614db,77c6aa32,2a50bb26,2ec7141a,b1e26835,911b85c2,b0b1f453,1815fa7,83609235,da7bec0e,f1bf2ad3,b0e71f7f,7c18de8f,83f55a3b) -,S(1ae86e7f,300efbe7,8cc933c,f8cda339,1f0f8f7e,411e6c0e,708a0d75,a1ab1815,d322b34f,f0778782,7d2da5c1,4d6bf17f,f8afc8a1,8051a724,bbd719e0,f5f31a2b) -,S(2a38dfd9,ee86308b,e0c76ca1,8dbb9ec0,fbaa86fb,51075887,9283c070,f31106a9,69cb45,94832b55,abd6b686,f67d493a,9d45e4a1,7d557723,fbbbbb83,7ab30cc4) -,S(2c6d7ab3,b1c3301d,65c79d40,583b566d,3ee39014,345a4553,a77a8e46,95b779e7,eb392dde,318bd27d,446b814e,73f9cbf1,380e38d,fed25022,bd584585,d671e470) -,S(758739e8,2aa2e25e,b1d8e027,b0e401b2,c82db2ca,549ebb9c,e1560ec4,531c5c77,d3792987,c3da2cc5,5760e52d,a19ea1b4,d0c2cce5,3f612760,bfc28414,37090975) -,S(7ef11cac,99fcb66b,71de229b,b34e82c6,e3149f85,ba1ffbf7,f22db64c,6a72588,64d7c546,28892864,1db41465,a134cfab,bc08ea64,11f5b2d5,b1de9f0f,7ae41b70) -,S(a7d48b06,c66ef847,f17b4b3d,ec40eb97,cb91bff1,c06d4a6,5d6db8c3,5561e4c7,2f22aae0,d6eb7221,d24f025d,ad1768a9,a619d6d9,db9d8e74,948d9263,3d0676f) -,S(a14d7354,1bb93625,d80f654,af67febb,d774e42b,6430a14,a907c52f,84088ab,adfe7f75,2b080bb6,89c031fe,c7c11d1a,bc303b7,f1a0ec2,38a4dac4,afbb2a5c) -,S(16076f95,b067381c,9d71cc9a,928f10db,43553332,f747e33e,367cc7ca,ffaa5f88,5c05040e,43a29d4d,e16b5e42,b672f618,8f0496ef,f307c269,13df7c79,ed2b1502) -,S(973450b4,a297ebf1,70630a71,fa74ae2c,8f3f8e39,18ff73fe,41bd1e65,5a5acd29,ba04c21f,e92ea639,99d5d87f,77181c31,ae8ed87c,dca22054,2f746fad,61f63039) -,S(aa29f7ef,d2f06187,108ab23e,16d9f3a7,74ab6459,550048cf,e1ddca0b,45fb5942,431cbd5,c77b31b4,d8b8568d,b092e721,a02d643a,75621eb6,1016b363,9728e2e8) -,S(bba61b3e,52614d14,358dc227,e0c0ea6c,e4dce364,fb7e0500,72d0d780,14642d9b,f33e0e72,6e9ee195,21fb4a80,2510156b,230a7ff,6e4c6b38,cd38b3cf,65336d6e) -,S(911443a6,979ede22,f23df6af,e4b1ab,73867dd7,a47e9268,3e3cd83f,241bfacc,a0e5be1d,31cf0375,7c2469a5,90f3493b,e43a99e2,755af9d8,b87aac67,ee7a6488) -,S(ff2126cc,5698e6c1,2da7f441,b031ea11,30132b86,23994f64,b332a8f2,87616d41,c616d5b3,79eeaae2,b072a11a,d2b316c1,b2c851d6,698b6d86,7fae1abd,482e91d4) -,S(2fe68e9d,de151731,12e1653a,2a6abce7,615062fe,a5375ef6,a2be1e90,67f6d8ed,c24e4b95,718acdfc,cd9f39f5,eca6f2fe,74fe7f9b,ae6aa352,e3651bbe,5d81c9b8) -,S(dc08aedd,90e96f6b,892ee62b,1f719619,6af44975,58d70f1e,7294863e,271ddb99,7250d846,1ac24a2e,e74bc5a7,53d5361f,8c012986,4364d84b,4afe22cf,c94aad99) -,S(e9c21052,f350d1dd,caa82594,b6eefb5b,f8f01ec4,1a423278,fba3951b,fcc7eaae,6992071d,becaac44,a5cd1537,cd066f2f,c432f198,621b70ab,360ea8d1,35757784) -,S(110d5ac,7838b9d2,d33bdf5e,8aed8529,5ceb9334,d409074f,3c26e3f9,f0cb792c,7879e339,427d8425,b597e76f,56a7a6e7,9a8cb00b,374ac98e,9cbec66a,47bceac) -,S(92982af9,ab48532f,cf2ece2c,9ab346b8,7def4729,8ebcc03b,91869aeb,42f9bbda,c6bf5a6e,8639e2ca,772e8c36,5f824b3d,331c7be9,4c13e9a8,ae6a779e,208a157e) -,S(c3f07f47,5246bb78,eac4e9cb,263c774a,3447acce,993a9707,14c1b553,79013162,f1931fa5,d6fd228a,a5781b35,45faba70,df6bca90,936acf17,f81a1155,4897e136) -,S(37640e7a,eef3f326,a598d363,df4f46dc,8f0decb5,ab6e368e,62294c53,ef3fdc7b,54fe19ac,83a074aa,796feef6,8d39358c,7be8848b,433e1eaf,9982701a,3eca7a1d) -,S(e903363b,6c90bd,2bf15176,83411d1d,aa9f0bb4,a22b5f03,ebbee32f,8f0cdf4d,fa44eae0,78b4b6fc,63abac71,ce0a6e0e,16b42d80,94179f1a,657eabd8,7eea2480) -,S(3c5fdd9f,7313d178,312bc477,849ce90b,a22770df,867a815b,2bd1d1a0,600afb6f,d81524ea,9e23ad00,bd7197ee,63457745,75795d6a,63b8b15,a19cf606,72159a05) -,S(40b540cf,43713ef5,c8b919af,6c991632,e60c198a,677887be,33b84c70,7c0ede8f,54586256,7352c824,49ebecbe,6eaae259,8e1cf694,fbb296bd,c14a4a59,240798e9) -,S(67da332f,f57adb72,8eb8b926,5a650e23,bfe5271e,396d74f3,9878c22,6f912053,91aec263,d7b74e09,b4fcffa4,87cee236,356e4fdd,bfa257c8,f3e3be0f,3a3b16f6) -,S(40cea066,fa029178,5662c994,db5b1153,e59fa121,c9133c2,fe1c6d20,91d44d98,61475cc7,a5ff5251,558f258b,aa8d69a1,52ed6497,c8ffcd55,2b66baa5,534df64c) -,S(c4eed050,248cf186,f8e2c079,870a139,c0cb13ed,2cec040e,d98a18ca,9b67ed0,50e9997e,263c7441,9e71405a,4d342e76,c5548e,1a7a3cc2,97e4e00e,91fc476c) -,S(676b60d2,14e309a6,8c7a8470,70d5bf62,8b71b7fd,322ae568,56fd4a48,9f3ee83,16e0d8d,371ad6bd,4713e9f,7c5f329c,72215cf,21a48527,35a0df71,205b733d) -,S(af268996,29117c69,c3beb193,c5cf7944,d4d3cc1b,7481d08e,1a190b45,c03e1fe7,359e17db,bdbe179c,8cb75ead,8a0e3c86,2b1d7d28,4aafd2c,e45e7b9a,c6d83ebf) -,S(62e15cc5,a30d1388,2b3c3890,4e1d11db,97b0a7b7,c658175d,e438591c,ed1ed489,fab66c6b,ab7b5ed5,815c81ca,65cf364,f4cdf8fd,7a6fe8e9,ab5ceb66,3bb4e8f5) -,S(6c7af496,df980977,41f5068,f34d0477,7da16397,c853539c,1b0c1263,2e43ccaa,4eb0e461,5c6fd9e4,3aa05201,88bb264b,d55b3a05,fc2b6c8c,d6f5f51a,4314f6b) -,S(757a45d4,4c662311,289be914,4ccca5ae,6ef89f51,52d66a2a,9be64096,cfc8fba3,732ddb9f,62fdf217,44d7daa6,35ca3e92,c3b84061,bae4c220,13339e06,fd4da7e0) -,S(14978c08,f1eaa9ce,4d878db3,29f0bc94,43301fdb,24b525e5,4f9f27d5,7fc114f9,439d8e8b,2b9fdc0d,85914620,9c883731,26e961f6,82407867,b10bdbb5,3074e5b7) -,S(3f231c93,760d9198,4a8d9adc,abd83c1b,3ae620c8,f067d103,6d1e5e02,2a72bcf9,95eb3a0,a928d3f7,dff3426d,763cf6ed,20d6df2f,c5dfb17f,c53ce0b7,90412bc7) -,S(c90268ee,75cc8e7d,7fe84298,b1db4255,80c3c45d,3643a280,e3d5d0f6,7337b616,f566fecd,1158d49c,c12a1dde,d0b1fd7d,d9cafbb6,ed3fd09b,48689f85,b01cb59) -,S(6457f0e,4d6cee8,7a2c0aee,85306a02,42c017d0,1e1c9807,5b460732,5c1d82f,67bf2f81,262de4e2,ba9d29aa,aecc9315,ff56c3ed,2e73d438,2a3dfa6d,faf9808a) -,S(ddc591c,1abcbb88,3de13bc4,490a66d5,3d96c97c,f1e21ae5,6a430c1c,39b1b629,80ae50f7,b81f043b,e3db78c4,da7b6078,871d4813,1e076ad9,de59fb27,b942f72e) -,S(22b19bf0,5efeb280,44b43bfd,7a6b3427,2e8b3c1,f6635ec8,d6966a,6667a252,47f504fb,ef2cea6c,8692d0a5,1f492560,151429c3,e522c23,2914e880,9ffdeef0) -,S(d5883bd6,c13d93ed,50371ce6,ed6c4263,395c5d28,f589c84e,cb9fbfc7,2dca651e,acde7b79,969cde2b,9a580387,d8e3a99c,45f15d38,f2e2ed79,688a3a95,80aa9a8) -,S(9615736a,4804dbbe,439f2f82,ca576623,a1675aeb,9ea9e40e,f6b910b6,c84af16b,a0967216,67f9dce6,25ce5331,62d45477,31be7427,74eeb1ec,4e3fe578,343c46be) -,S(ea36bced,959bc461,95e730f2,26224652,2472c2c5,70df6832,befa40aa,5c600e32,dd52094,82eb08c4,bc233090,2aa54333,87d06885,a9357f40,246348b4,4d97fbf9) -,S(44814860,ddf61b77,77cad443,18c21686,85c614b0,1c5830b3,b178a52,d85539bd,f3e5fd15,c71050b7,280643dd,bd2c55b9,219e7fda,cfbd2e98,94fa9a4c,9cc7ce75) -,S(814454b,cde86996,56b44c39,69bf0a8f,31b6d032,40098f9e,43d52266,cee66f49,8baf21a6,601db25f,2e18f5fe,decb9f31,9a6378c,adbff6ec,99bfa2ff,8d26b5c6) -,S(1ff790f1,11f7bbb5,b6db5f83,22ac696,c1de09d8,e50b9f4d,641ef76f,d43fdad,145d0aae,c218d6c0,219ce9c2,313b4962,f873c5c3,5424d3b,536c1543,14fa9517) -,S(275cc6c0,6a8faf20,c3c1e88b,87e27d35,661c6401,d3a1bd96,18cb016e,fdbc6d0c,45cc522e,97b61ff7,696c5780,638054cb,5e97b6d4,fc4a813c,7000a633,4e9f2a7c) -,S(9c78cd3f,874afab,23874f0c,8a84fbc8,a6d032f6,7fef6c6f,29c90513,bb6926f5,818a2406,fedf958f,7efafc4a,584ff6b1,7bae1b65,f67d1086,c3e013a2,cc318b1a) -,S(3c060395,f2cfe9f9,e3bb4afd,e5a71e03,c5a92491,323de27a,c9ebe1b,170153eb,344d08c3,8021fea2,6f55c0c5,85af3954,afda21e7,14cdedc6,8ffa3771,43b2ca27) -,S(f4b61a9f,7392b960,752bafd0,ce521e4e,57bcb898,cbb2dd9a,b0f7db8a,3ce5ff2,e412589e,f3678029,15813dfd,acfe8056,2a59894a,4c87640c,6044656c,e8998d5c) -,S(418698b7,6230acce,49505275,a0c01e9,4eb356a2,e3c242ff,470b64be,fa91ce85,cb9dfaf5,4c64ed94,f97e03d,30e07876,9e5a3142,d0fc0902,5e20ac2c,21c4ceeb) -,S(809cbcd7,91c1f309,864ca343,3d9a11dd,2db3d9c4,5350ac5b,27f55e19,b9941ce2,8161347a,92fdcb92,263f1d85,2923a15c,42d5012e,30d7d9b8,623cefa6,12b06bf2) -,S(6410c007,1d1025c9,8ce11509,5359e962,58c6a115,5e7f34fd,30fc8862,f9569f23,d76363d6,2661a55c,6c211bc4,13b1dd7d,63fa6964,a03d9461,e2870f2e,54c87d29) -,S(8394abff,22ef6051,7517e352,12a4dca,103a19ab,4091c7e8,fd417a,98fcfd2e,20d0ad3e,bc0fd15,fd405417,61bfbb40,8e37975d,a77321b,67ad2ef8,35732c0b) -,S(dbec1fa7,765386c1,d7558cb1,f19788bf,ce0e9fa4,7ca41edb,2f2d9ef8,78a04308,5d7c918e,335ef23a,934fc963,48dfd8f6,ce79885e,f4c463c5,b2645c8,48083ea0) -,S(9d6fe17f,3f53f921,893a422f,c9f675d4,652cbe09,a870c81d,8b2ab9ee,9a591cc2,fae9ccd0,b22ce7e3,2e7faed,2d47c36f,25cac5b1,e56ea936,a6811f11,8d485a2f) -,S(622f8f9d,65c4270b,1479e4d6,6f82fbc4,cf23e7a4,d09a6537,22c20d9c,54f85f55,e87650ee,4d9ac5d9,c6566612,1b6e4679,7e52953a,d7c3aedc,2fecc22f,d5b76591) -,S(cb1db853,b615cb5a,b92d0340,7ad7891f,2e7b1d4d,120ba3fd,a1ea3565,ee1d1436,8362a39d,9d425eae,2451d601,27ac2824,3819da08,856d0db2,18f339d6,fcf20046) -,S(5cbc6a63,59d9d6a5,2ceb093f,ca5cae,f32892f7,c9d04091,8245d9ae,ebd594cc,c4c18f88,7436575f,39b9e7c3,27c4efdc,6a3490b1,23c50743,ef03b1bc,34566bd) -,S(37a3cb08,3a9b7561,78ff2128,e7a5b9a1,19577af6,61974869,cf555dac,ee2d11d8,1a8a6297,4d0b6c5a,12155e9b,cf895c95,f6fd2b1a,2776c32,8d6b56f8,32f114ca) -,S(8e0611d7,ae0914d0,5d39e06b,9b359400,f21c3beb,73ede92d,bcaa6d96,8a995b95,ddd4f522,d1c6a964,9629727f,52740664,43e80ac9,7d9c68e1,225e60c5,38129bd7) -,S(9ec34a91,8a4648f0,1c1d726b,51b1874f,36410180,8bee25ac,c159c251,fc115510,bc5ee2aa,b5e43b01,b34ab989,5f4cd71d,1d3e6288,915daa2,e84ed531,4b388b8b) -,S(dc19ec7d,c901e215,f6d0603e,bb5494ca,aa9b5409,67a5a339,8915c4cd,84000654,b55b9596,a18e53c4,b82c669b,92defe5f,bb5e58b0,3cd227b6,3b439b4,ef13bf13) -,S(51bc3804,bda51e9,d0c45087,13599f12,b9a8599d,6e8ce949,5a3f595c,7d38dc8f,ef0d6522,fe3a3c4e,64ee1092,b9ae8f6,e7847bf,94044693,a3ac7cf0,f4aaa37) -,S(13463b32,dff393d3,dfddbe3f,bd6ade13,190e0bb5,83e3f126,344b5e01,3105e234,ea3df1a8,b8270f70,24910f40,a519cef4,9944fcf4,d82a4300,63b2026f,8f019ff4) -,S(c49b3261,2e286adb,606686d9,67dbf4b9,57819dac,9bb75f44,8f1416ec,f900fa5f,ffe45b6d,8c19de7e,c08256e2,96667d89,f290f5d2,25a9e380,c106972d,79551b1f) -,S(10fe7aff,36a8f4ef,79e2d8ac,619ca92e,2300878b,cf21a271,70f89e9b,6294dd28,f67da70f,623fe6fd,2c7113eb,fe6458fe,d0d5471,ab639050,685a0fd9,33afd6a3) -,S(d56037f6,efec78c6,e31e633c,570c5e46,96f96276,b86d0b89,e993f014,53592300,2499b92,4fd99b5e,a56f9649,bd8e53c4,b2f20dab,9fc1de83,dc199022,1f606b37) -,S(a3c1d0c8,939cd4b7,5cce8ce2,f3be0226,589fb32e,55457fde,8e700a77,a60bf003,b9054f66,bf6450cb,782533b9,33190084,d6f5944f,cf4e06f,de72d483,144c941c) -,S(85d0c4ca,e1cfe42f,b5f73f31,42e97e6b,c0855f7e,db19b1a,8668e413,4efcd249,d8372bc,937fa754,b81631aa,33a8ecbc,a25f86d3,d5e0627,d6964ee,5c08e68b) -,S(3092eae2,d41d0ccc,10af9d81,fe8c80f6,9ae27c9b,74b5f696,7a69211c,8d6ef98d,153f0882,f6b720bc,c8ae5924,923e0608,d6163c3b,32d36742,68718d6,e7f35e4e) -,S(4aeb6ac7,fe874a0f,1c24681d,884d5497,3486f293,9b01ebd9,74c34ea3,429be71a,d7077161,c508a7d9,63006566,f652afdd,df87d0b2,8daf3fba,21f206ec,a94a53e4) -,S(729bb0f7,be975284,a68363ef,40003a6e,c770fa4,5d6e6b99,ab0c5042,da563f32,1e0435d5,ea85370a,7293396b,407da43f,c540aa04,24f21de6,a002f555,cccd4480) -,S(96164ac5,1074dce1,3b973689,a39b6795,9bf5756c,4de94829,66bbdd23,9e665fdd,5cf13b8f,56c92710,80c11626,6bce26c2,14a39237,9aa68ed1,b7a05d65,7bbea247) -,S(6d45d79d,9297bb8a,326b889,391b18d7,31af609c,67b31be2,9b4273cc,405e3f80,2d99909a,7b6969fe,148111fa,1b9c9326,97fb465,494a8225,a6c62626,555ed02a) -,S(70091076,b5b81f33,42170f0,4881c941,d2fe9b0e,ff156221,66f0c92b,4f9e8e71,7c676c5a,4fb434d6,58f635a8,20b454f3,4c9795e8,b8860d27,4d0fecbc,ce7824a2) -,S(d04c0a77,c8fcb3a9,a02df253,b8819853,63dd47ca,bc1f8881,88d5e56,87a7db74,302d1b96,c35a2626,22bbc6e2,841b5cf8,efb77374,af428f9e,d69b2b11,6993db09) -,S(3c93d2bb,7ee61cb0,7a25ef65,f3e22eda,6e74d2eb,f3ede111,b4f2a28b,b4f206d5,65ed4db2,b1647b39,7225741e,241310e6,7a47f0ee,4f459ab1,3d29689e,cef70336) -,S(8efd5a54,a4c7567f,bd971cce,7ce3006e,3524dd81,cb7a4ee1,a5c61e12,62961037,6b9688d7,d73db9a7,1410738c,80430ea6,ea329145,718b4177,71e542a6,93b494cf) -,S(e7aa8121,34fa1f75,efd2ff02,273becca,18bf1ea9,47d168e2,cadd6e9a,6c448425,8af9da38,e2471dad,128e004a,d7b03932,2976d84b,7c91f91a,af471546,dfa5acdd) -,S(e4335a32,b3218d51,9c582689,85138591,4b7cd8fd,4e4eabc3,b5f9e0b4,c3212b84,ccfbfb0f,50b5fe75,c849510a,bac5870c,3016573a,53eda160,b14602c2,42ca02c7) -,S(aeff696f,e98cf587,745adbee,3fca1ae2,3f8f5768,56bbad5f,4a26afe,904a17c4,55dfb880,250b9a5b,7eb971a1,fbe0cd6,ad2d375b,88d98e52,6afcafeb,7ac4617) -,S(72fdb2e1,eb120244,4b20bd6d,afd6d49f,46a56f25,63e679c5,2de98cb5,bc999a5d,e29f2,34ad3637,7b4a9cf6,c307b8a3,a779cc22,ae472aac,eb519c10,8137162d) -,S(eda9f183,f89750bc,8c12ce7a,fee54145,42edd9ae,9fefd508,ab588bf1,6c7da0e3,a9328c5,81b0cb02,fc09fcfd,2a57d2c8,fa313ef5,4e205902,9bcf0846,811be308) -,S(744683c1,2a0150be,1d7655e,b5a3fc97,4303387b,e53bcdeb,41dfbabf,ff12f6be,df2e4b05,a459aa27,2d3de8dd,4c211dec,e35eb798,67050285,57dd53e3,5b9950f6) -,S(9f3cabfc,106653e4,65daeb52,e86d99ff,e3ac6df4,5eef90f0,61226cc0,32592ef5,9f20d174,1b78c8ec,d7425d19,fc0a4c9b,1f1cac8d,b97514b5,8585901c,41862306) -,S(9dc15715,9f59c338,d56a7d9d,ce63579e,9e95424d,e6db6927,418b024f,ed95936a,278716bc,3e131fa4,75b9ac00,6e868d88,ce17e6ba,d7ecd202,33fbba0,fb34f0f9) -,S(b6c91d90,b1bf3b46,4b526186,69e1c118,dcf8d6f9,c8ca7473,5a361a28,b53c823e,15132dc7,69e59b7b,fe5e9966,1b82e47b,3ee4c3a3,1c0b8201,517dc567,ff90a4bd) -,S(56604a9,ab972c4a,f18d5f8a,d5cb6d94,2d0c841,a7defd1b,b94b1b25,c31df400,3d2f2a27,adc2eb70,336b4b44,5229e09,a74a113a,f1b21bd9,1e3f2351,15f6a85b) -,S(a5b57de,fcd3016a,917ababf,171c3c31,ed62957b,cd8d233d,c551fd9,6216561d,3731d822,155afc28,8bd7ed39,30c3f6e3,58a46f5d,d9fb3ed2,6d7c7da2,a8dee233) -,S(da179b61,81e27ecd,d545af40,ea5967ab,7c0ea9ad,68a8c0e7,4d4a5aa6,4aafa549,c5c97c42,e74f4991,55191cf3,3118f05e,19633eac,ff5ea8d0,7ec866a0,7fbbef29) -,S(42a0e864,1b594b98,90357e4e,8c32422a,19f368e8,190170bc,6d8abca0,9cf12f1a,bac7a5e5,baf7ddf4,934aaeb9,5078e0a9,c449de0a,cb932b13,a93f474f,52312d85) -,S(74c85e38,944e2003,435bf345,124656a,6a409bdf,fd1c16dd,d1246d45,cadcaaf7,bc18315d,caf237d5,5f3ffc65,41bf9ca9,f39af9f0,cdde6fab,f602e888,dc51bb7a) -,S(8ceda42,698e5995,40091f6d,f50388e2,7c229b0e,76e7def7,f8986b6c,af975e79,a8915f5e,7c524e55,5743c392,2b31c426,71fa938f,84679389,b3738af7,59e92430) -,S(f44e2dd3,ffe43da2,66fbaa1,990d1f19,e3e4e44f,bb565ec8,74af57d5,feeac498,c307b3c1,a90da318,bf928a1a,a8894080,29874639,ece7700d,4f4dddee,d005f6f3) -,S(7e30bb38,c9a603f9,d5fe78f7,453d1c81,30c140b2,1ad7706b,601d6b77,5c703984,49c9de1d,1d057fa6,b135ebdc,f0b5ad9c,f9f51cef,95a4cb7c,ebc11d4a,3bbb6d7) -,S(8e1e53c7,4f7e1595,b4a5f7b4,5b324f0e,435473b0,a61cdd8b,1607c0ef,d11e3c56,584781c3,ae8a8beb,f6cd1bb8,3938fb12,35994977,2d1facc4,240fa43,7bc241d2) -,S(63d0cd75,54bf2c18,bb180269,2d19b4a5,4acd77c,d2eccb7f,360dfd5d,4b9f22bf,ed79b7af,eee5ec82,e498ebeb,467380b6,1369802c,3dd995ae,c844d3d2,91ddd756) -,S(feef5d30,b382dd6d,a0ec0d81,b18ae45a,8dbe12c3,dd695648,cea27c14,7d075be4,20ba81b6,b48ebc6,b185d6bb,2fb7bea5,c6a011a1,24f49550,415eb8f3,cde3aec7) -,S(21bb575f,db07a152,5ff0a7a2,d7d2c189,742df276,9306bc7a,30c2c3df,f2125b94,8ea74299,b7b40a93,3db6afb6,6577ce64,dd10d24a,89bc3907,1f656f5a,71c56953) -,S(dee2dc59,44cad7f2,310afc94,403067fc,5c1c3d2a,dde88ae0,55ba8bec,d6e5cb08,606542e4,5301a6ac,86c5c794,444006d,d77e2bda,11c8af0,6d883689,7a6b6dd7) -,S(4768a2e4,98ca0472,67cef4b4,18e6398c,81289c73,e617a2e8,ca021155,edc576d8,f8c574bf,beea93d7,1a2a331b,cee494f3,75c1bc3b,ea918106,9f1665fd,589dbc3a) -,S(53d75697,160c2b90,aaea7f95,ad24bd66,b5fd7681,f2802bef,d2a71080,74f66b40,4b04d94b,416a8098,144dccab,bcd8742b,13e85b2e,ec8817c7,7b7e5821,2e8b56c0) -,S(832f268d,ad5f3bb2,dafef9dc,f94bacec,b369d4a1,ffbdfdae,bd4fcd9d,77404e99,a6495805,c9b439b3,26e32f78,8b06765e,8d984a37,86ccb4e3,88b36bfc,c9cc582b) -,S(657acf28,15b8cc12,83265bcc,9c826be2,c6d5329b,351fee50,2ed96f4f,bb1a6333,171a0a97,b2809b24,a89b337a,cbeab96e,7d1d850d,dc577a10,ef3c757a,9c2da9fe) -,S(7e3d0a00,a3378c89,741184cf,36e41bb8,758fd131,eccd970,638f60d9,31b8348b,6f2cc777,31f94565,2a3b4c42,29be627e,bb70d5c1,67648d16,df5470f8,90512517) -,S(649a30aa,4fac6630,c7bab764,19f9a34c,6676f17c,2458fb1d,ac48317a,734242cc,fb3f07e2,5737d6b1,a28b074b,880db818,c9623c12,80268b02,dad90da1,c8d246d6) -,S(6b65264f,537fa580,9d21588,fd86b246,4d1818e1,ec7fc43b,94af9211,c835c986,537365ae,4e61460d,c2c1caf0,62ac870c,9536d8b9,436a0ef0,dee6a39e,2bf25611) -,S(dc1a5599,d5cba6b0,2d692eac,304b642b,db32afe2,59e2e8fc,3bdc8f40,72c66c51,bd18d5f8,f99c6070,b7bc06af,568e28b9,2b39dc31,ad49a842,4bff4a55,d11ff42e) -,S(726d39f4,86401794,9e7a5498,8e8fbb53,b8b13ec1,cd5fa3c2,88f0d933,894e193d,f23e9fc5,68c9e0cc,b258dba2,58b3dd65,7aca0dd4,d9cb7bf,274e62d4,f65543aa) -,S(78d76006,857c2f36,889c14ee,90a8f993,79c1e0f3,5344cafd,592c961f,75aa8ee5,76dfacfc,994f3985,70d98c75,4f5e6d00,ae3ed428,49cb75d1,580e81f6,3d7427c5) -,S(d69c3e30,88874c19,71bf077c,89247826,b464d3d5,292196f,88ef0ad6,892375a9,cc7b98de,86017934,c472bc7b,e56f14c8,7494cf5,6f2791a5,d3132c07,26315cf5) -,S(9b4022c,907c4aa6,87631f88,8d47bde4,faeab1c9,23e125f9,280dcf86,7920ae84,c7468b6a,a7b4db67,a9b4a23e,11fff527,19e454ee,65ed88eb,3b89e231,e504c284) -,S(e638a253,84e985a3,5dca200a,5e3786de,52617824,7ed0c9f7,9c9d598b,8bcf8447,69211bb0,be8fcd6f,cdb0ebdd,a8782be8,a47d8852,7bb74b3c,d98c41d5,6aae614c) -,S(e46758ab,e2838a28,42baafad,12376137,7cf72960,d6a93105,3270330a,203134b4,2c7ca1c4,73d0c3a5,8f5ca754,6604ac75,8c460c82,64f5ab4c,832893c3,fcbfc7c) -,S(c8c8083c,3bd1b84,9b9402bb,9472263e,37e7d2bc,53a77b4c,b0ae9b3d,bc70342a,9085d285,6ebd4446,127ab4c2,fe7e5c84,d5c5c114,8ee76a1c,da72933,9ca6578d) -,S(cf21f3d5,75f194a9,3133a382,514ca64a,f998b099,eb307655,46e2959,f71f838f,657df357,aa09b443,c4763432,45d3eae,4fedfd1f,7fa86896,2ffc5174,d61fc4ba) -,S(684aa68,d4aabda9,65adbb29,1056db00,1c41b900,e11770c,c77c687d,ebcd702f,c6f0c4bd,f6f6193b,928d81b2,812c4303,7e6b90eb,598a50b0,742dd21,8d82bf3f) -,S(b9a4ef5c,acf4a82,77b81803,6bcf2672,945ec080,e16e8c3b,19f7b612,c408c884,1cca67ba,9e98e737,b4a55145,7f254d4f,5d793d4e,22b81b35,f4ab48d0,92b9c745) -,S(ff439f87,d4784ca7,490da489,e2757106,e59836ba,f3fe2e4d,f6700c08,cdb2327e,98f21471,84659fa9,a9cdb709,f894236f,18ecdac9,f5834dfb,b91a7bf5,8edb7461) -,S(e1750c62,9c35027a,c1a5f1aa,c9fb4076,badfd925,f5915b11,a267672b,15945ed8,e17610ce,a0b8d837,d1038d7d,9300edfb,5832fa84,c4e630f5,2b01ac64,a79c0e17) -,S(2b7057dc,1c59ed7c,e64f187b,86adbbb7,1d228e5d,eea347c,75c73d2d,a73b3a28,1b136a49,713b433f,f2c79de6,77b5a322,8003e614,2b845470,5ce884ba,329e20a1) -,S(711c07c9,ae61ac68,f1041b58,c0f2ed07,1106c2b1,bc47e104,527d540f,53690434,e9199a45,2f5a3a39,9506473f,be6bb46a,3105aa70,2c517051,7b4c810a,5a194c09) -,S(54dc7650,68c38627,4619d9a1,faadc0d8,c2ad8296,dd0d00a5,f2e53c5e,1a1a0d4b,2e9b7179,3af2f752,c111fd71,c00f4bd0,8fa646a0,428b4813,885d4e4b,ab7e3fd9) -,S(9c5aecba,3f8b3507,db7cc231,c2c1674c,3c3e27be,84757fc,4f1521f9,c3d9323c,413455e1,9e157ddd,17f51c1e,618dd726,d300c023,f0a0d24b,518c93e3,f2954630) -,S(c22c2972,5f67e23,a369342d,9a4e1f6d,dc1bf6f5,88d63086,fb54718c,f5183a,a26ca30b,d97ad611,4ea4ece4,cfdd3928,23c02838,9723d53f,32c3b38,320eb707) -,S(8f87ac94,a29dd2c9,d37aa130,f8b4e67b,da595ca,a22803d1,e2d8cd4,eba4f2a9,551fab10,16227763,6d7ad2c,bb055439,21743078,e02fe0e1,b7dffd6,8749b04) -,S(bc486976,76c0f638,a116bcce,d7ee781b,876ef486,111fd680,4dedb176,8125dbd8,16d7c6d0,19708ccb,510ddcd8,698c2fdd,bc6978b8,7b0639d7,a1c8ec6e,ee3ea383) -,S(5a6ec844,201d9b39,92a46fe5,ad4f05db,6e8cf251,24ecae84,3a28da7d,46e75ae8,9e1538ef,f27344ae,8f9c1049,c12b49d0,2d5341fe,33652a8a,9f2eb512,c74ef224) -,S(dd6b2c56,b13f0ab5,4e0a75ec,526219e1,4d43ad78,7deae379,1dfb387c,541f4d6f,7379c5ff,1b793b97,c8acba99,97a3c079,f1c147a0,f63a2ec1,a0a771fb,fc3d432b) -,S(74e27534,4d7d8cab,e4995d08,6d61d27e,942e2514,3c6e3040,8402a5ff,12a63ebb,7b5914d7,fefb7b3d,2fdeb49,359878b8,355eecef,65ac589b,dd31ccb4,c270d854) -,S(bea186e4,b5e3663a,fb00230e,d8ac1660,67b022b9,b69b6e75,aaecb88d,d750d34d,35807d83,5b75e3ae,670bf35c,d415d37,6fbc86e7,4f99afbd,c60a0b46,9153a0d7) -,S(17ef6838,a07f65f7,cc094d4f,77743c6b,fde12ae3,b81625c,23826228,650f30f0,9d696a8e,a5356fa2,10626ce2,cf312fb7,198b0937,493c9dde,4711dba1,333eba5c) -,S(b3e1bfcb,38c89fac,af3baf39,80b21e47,d6465473,c9d6a29c,8a08cb18,141bcb7,aa33ab83,2a9d4eaf,2a50f9f8,ba55d0b,c5e3b120,69a8330c,23120928,5f6b90) -,S(689d499d,c754f099,83372631,2f307f0d,807f4f6,d67df40a,318aadd5,5776202a,dd4f9012,8a19dfbd,8f5f96ed,df2c7d79,d451f84f,fa63b1a5,9845f84b,759377eb) -,S(4bfb2e58,9df27505,91a73a4c,6ce88397,a2f68f6e,8f866e1f,d3af9df1,f3c96bb4,a9d94c07,29948553,6433f0ec,b4618d1d,af309c6b,73fa4749,aa949e6f,bdc24b7e) -,S(97a3004f,26461f5f,b6cbbca3,13eecbe7,5026d958,a1804c34,6e661722,c67f91d,8b8e9bfd,b9b704d5,13bb5a50,a725bae2,c7ceb6a1,ffcf8c49,8e87c6ff,e47844f9) -,S(a07a76e2,48f87384,48e607ee,7f30aed1,db657b9f,b159ac9a,3d38e8ad,61050c28,7d7749b7,aa6dcd68,931c3c0d,87eb73d9,6bd5f43a,b633e7b8,f77406a9,23fdd47f) -,S(9bcff8ce,3a280998,fe077cb7,a6e4854c,4c834e21,af118937,9a133986,320b8e25,da3214eb,5cfea248,f1f8a1c1,e8b0dfcd,4171b2fa,5e133854,84a6c99b,215c9ca1) -,S(8f1d2dd,bab8242e,fad20574,c0f28976,d2e98df7,5e144d27,e558b9c9,8d75a036,8bd117cb,294db5d6,a39097e9,8976c701,1042af41,680637d1,c8a1d56d,30800bab) -,S(73910449,2a44d0fa,d27b97b8,df75ca46,caefe44c,741848f5,36b78986,8d966991,d31b7807,e1db48a3,380608e6,5f865cf4,445c47f6,c6094819,da2450e4,6b78168b) -,S(e024cfa9,4fdae1e1,2895590f,222b167d,8a41a87b,b1a6b720,61ccac0c,4caf9dc3,d62f1129,cd84f36f,bd1b9439,6f5ce037,fbdafe41,fbebd066,110549fd,50b0ba05) -,S(a378ab39,e3dce826,6805bcec,b8123eb3,ffada53d,883c752e,e46ce4f8,5bf093fc,db9d124e,4c0a8d1f,14cfc406,4498a7a6,513261f3,300ebe0,99a41f0e,701c7dd3) -,S(bea5d211,b808e4bc,5aaa1a96,a9b8842b,5204b60e,24d5e518,4b4e92aa,12d8968f,caf8b92f,87c4b8fc,4692efb,889ccd64,610fd604,b9669dca,e033ae9a,453bbca9) -,S(7ec06291,40b6bfd4,cc4bd45a,8a953fc2,653d73c5,d366b5e8,b732dd8d,5d30428,e96c9515,da8dfae3,a2f4e01f,f02ebad9,8499a318,8905c0f0,fcbcbb58,87360a08) -,S(9f9698a7,6ccc8bc5,31dcd9a5,b21f3f8c,9d143194,8902312c,b5ab89cf,554c3b26,e08acb08,2ab0eb8f,fc31f7a3,1ca8dfbc,d4b1863e,29d155f,4abb8d54,6c59a221) -,S(ad955b37,a45f2bfa,1779e8c8,e6786af0,dc49dc9d,d692281c,da10b25d,7517214f,b2048fe,ee71c152,8c8f5dbb,cedde340,284af2c7,71ee86e1,8d565285,5de918ef) -,S(e7e56815,9412123b,7737b006,f48b3f32,513023a0,70c595af,1749c564,8222e21d,3ff11313,c2992218,cb3a1c01,e333f2fc,ffdd05a0,c381f8e2,24de6add,85aad0b0) -,S(4afab50b,55c2a433,488adadc,ca5d11,2e225f81,9ab817bb,116109ce,71dd3439,d232e25a,e5a8f6d5,68344997,442bdc54,de9cc597,cc474555,5f64cbfb,6252808d) -,S(2f739ca4,6559727c,cc2fdfa7,c66da19,b7d2660f,cc63b74,155057be,d55313bb,c39350a6,10a844f,80730a2f,27bbee8b,a06d7ae4,a279f490,f975111f,eada018b) -,S(f3596671,79f9343b,bc3238e7,bab4686b,5b7aaadc,95848f20,52adfc33,d15a990e,8b5759c8,e0bfb8ff,e298e824,ef18c042,65d7f886,1af8252f,8c9d9d92,c1822849) -,S(b3feced5,8d79e1c4,d0a210dc,de416353,404f533f,5a1295bd,4d888d59,b43725c3,b07089f0,871f7c3e,440ea905,cebf66de,52c68c04,a6aae237,e23c3272,26d99826) -,S(85c74622,bb28186b,5f1bffc9,74d51ea1,8bd7e6f9,1a02285d,6d8818df,b87d2f9c,8eb95100,63263c67,976fda8a,18910459,df0755b9,307e4145,cfdd18,15b799ff) -,S(3823d01,5b240e83,44c936a,c9a5f7f0,fbbe3059,1c20f39c,ca51be63,98ea7a7d,6e6539ac,8f404753,dda08dbe,f7ad4e48,69a67a93,f0efd0b7,b53c14be,130435fb) -,S(b73ae7aa,e97af1d1,b6ae34b5,f6188c62,33ac811e,1ce5818a,a9f20703,7deaa539,cf495bd7,2df163b1,f6908b7,23042bf1,137a325f,bb8ebd78,c0d12086,e7b76005) -,S(f6724463,faac9880,41dc4918,5e27b97e,889e74a1,81f35b58,2601328b,143688a2,a290e04a,f10a477c,7c0269ff,42285277,f1faced9,eff88272,45f2d069,58897554) -,S(9eff8038,1d546c1e,e1b5d562,947f3a98,427e17f4,84d0007f,eebd71c8,261ff959,bca422aa,d4748c66,6aa99f76,eb8e75b8,55f89b0,917ec29f,401caf83,cec111c9) -,S(93384df7,33d0fece,931587d3,410f2520,6bbbd992,5e6fce75,5432252d,8bc1bcc5,9e3beba1,b9a92647,c630cb4a,69b9bbf,80e301be,fb8eeafb,fa0021c3,ae27c38c) -,S(ca85653f,975882c3,71902d14,6f50b3ec,1dfe1fa4,b6e6d5a9,e5068685,632074bf,a64fdea1,66808f60,736f7d84,850f841f,588879e9,5d1adcf8,ccbdc4bf,4f743bba) -,S(b80a52f6,951aa063,1094a2e2,866d3a29,b95cf239,48753ea5,cf5c6f6e,8e082f90,61c95d57,d6fc3ca7,5f92771,61ca211,1f20a67,9a85f4f,2b8b0fbd,494d55dd) -,S(3d5d3037,3a97dd67,fe45b273,2ce21e19,b29587dd,301f3dd9,b411432,e642a3c8,5c8e3a19,896ef1a5,5cf1ad28,41e47dd6,1f207f22,3388c6aa,23d011d8,fd95929a) -,S(b274f8ca,29a87fe2,8a3a1269,ddc35b5b,44f9e4d9,81af118a,187a7c36,acb155c8,410d9c55,bc34c21a,6368155b,c282e449,c5317dd1,c4e5758e,27493fa0,4f028ea8) -,S(f1557792,8cac518,66f59814,a70c14f7,beeaefa5,33d3b535,df19d31b,ce1cacf8,113dbebd,9fef9cfb,93b5606a,e4b48aca,5b7e9c00,a59832e9,6865282b,80b70ecb) -,S(fbe3f262,18fcb657,7fe56753,42765926,59ff099e,f36252f4,cb5af101,622c40e6,4c872d52,f1202df3,e905a0d,3f9c89f,b347723c,99b1b273,8f3dbb83,df0fa2ff) -,S(ef7d13fa,25ef46c5,3663eddb,a677f6e3,b24c7e7c,6895e731,2c6993da,3d9384a2,cda2cc35,114e06d2,1f6f896,666c16db,78fef74d,2ee46fb6,a4a34e09,8546935f) -,S(8e34b93e,afb7f027,cdf8696f,a6407213,91860119,cae17b66,d4f16175,fd7118cc,3198f5fa,27ee190a,e56813e,910d917e,3bb8c850,20b0376e,e55e88ea,eb56397b) -,S(a8291a3b,8e544240,a0f0dcaf,6369b2cd,98ab80bb,4dcbc2fe,e023cea,1fa52399,f8305f7a,b1993569,82b8f2a0,1fa0e808,46a506ef,5cf0ccf4,fcba9211,284e15a8) -,S(bd36854f,90dcd6ac,978c2545,7800489,35c4cca,79a0f9b6,bf461da6,5522c88e,631a3d75,7c05e2cf,4a445b22,73cf663a,332610a,8461dff3,846503fa,12e65ae2) -,S(fad86e9a,ae78aaf2,e55e93f4,b8ee049c,73b86524,e942ab93,f05f9dfe,8b783116,657988b7,20822c63,dadaef15,a5cb3d49,be52946d,53b62ed7,1814ef3,b5aa4b7c) -,S(e1235938,db5e1f30,fa0b4d4e,a9e1925c,6308917c,23efde51,47fb818d,a39bcb2,7641244a,7384acbc,3133fd6e,9ed61af4,40e3b951,751f9d0c,384328f8,b87bb2bb) -,S(40ec62d9,7c9bf05a,cd4bd50c,137cb143,8e3331ac,554098a,57b6a92,afb137da,8b1468fa,f334dcfd,5a43d405,aacd3f31,7e868af2,73498367,4d0e5a06,67186a8e) -,S(f6f5c9e1,c7d94d25,9abe1a8d,745dabfe,59e911cb,c917fefc,e2da2a63,cacb26a0,7f2454a8,550b385e,f49c26fe,bac89a9f,33bd6c9c,2eb05c98,4303a16,6b21ca51) -,S(be4dd8db,c703a834,9e24773a,acefd0d5,70dd2ec,ef07bc70,ea8156bf,d5b516ab,46a7dc2,5d56052e,dc64a0d1,b414da49,dbb218d8,5abe14e5,c753eaa3,84b958ee) -,S(273f227d,448ee218,1e43f2a9,89d5942,54eae85e,54fe9f76,fb67ce81,169e1be1,67cf461a,a6c7ac60,1ccdd925,b4b38e84,1998cbec,cabf9441,29575438,a855f35f) -,S(94ca507b,96c063b5,bfa9d74a,c92e656e,db186570,9a017ce0,e5270bfc,8a8c4a31,98daf409,49c48c6b,8c674361,17aeb669,36c76169,8d39eda8,9922490b,4fa6a25d) -,S(91d6f747,c1c7e012,440cf7c1,34ba64f8,9ef67b54,3a57196b,d2bd6ae8,f5ef4356,e2117eb0,4d4d29cb,5b13f628,f69e5eaf,2befc095,2fa361fd,f757430a,168c19d6) -,S(8e2c4d62,c17835b0,97ba07b,37947515,e710e825,15bc614,75a66ed2,ac4cfb84,7b7f7e56,22bbca12,2863c230,5271ad25,b5e4195f,cb96e5a5,ca2be6d5,273d6532) -,S(55738482,d32c4248,1bb0d1a0,666adab3,8bd2441b,9436b690,77925e15,2d8c948f,93a6705b,ba5e5b36,e73fe83e,e0ea81b,3de393c9,1c209e89,af90c539,9af5ea2d) -,S(7faa0f45,45fa7d68,918396f6,19beb941,43d93f86,c5a26539,5016d386,b3e85086,cde251a8,3de1f2c7,11b884b5,33226baf,cac36791,1ff30e19,25f499ef,27da9c06) -,S(61a766a7,7bf6f8f3,a07ed7c6,6648606c,69134c6f,4ab4931,9033f9a5,e8b7d191,7dfa24d7,6bba181d,7bd77606,c73b1635,46f41751,c05c34dc,ec54773b,4abea4a) -,S(64317c72,4f1207dd,a6009736,6fd2d189,8b702e71,8cf84fcc,7c50427d,7eee171,d1d45f23,b1c5fda9,ee05652,dd30f898,c75923d8,293d6eb4,18a0e892,ae400895) -,S(4c328f82,5923e7c8,9cdba421,92ad7a37,5a328323,71242c4a,e108c771,fc47356,322421bd,92c5142c,efe89e59,4689a7a2,e8e5507e,be8b505f,9dc9ac86,9d90ae6) -,S(360aa32,797804f1,649c44aa,b38fa9a3,5d011301,708ac7cd,a4135c13,d86a6758,ce4b0fb6,6957f5a9,7e4ef923,ebfbd850,4f6d4098,5333db66,1152f1c,ac6eef59) -,S(5b110b6b,d9ec8ab6,635f5016,bc597f31,ec22f7ce,cfeedd2a,1e6f883f,64d2379e,9472fb70,87ab6f91,2b10c6ff,995af03c,5086c034,f0f69860,ead562a6,e409c8b2) -,S(be27b39b,5a657cf2,9ebb1b16,45f5e1d6,bb6e32bf,e3a52b08,a916e091,9affa38c,93fbf27b,5d03ae3f,471ad91b,69e74fd5,a8f2f925,2bd16473,62c4feac,d26d1dbe) -,S(8ec65d75,c599fe6a,bddf3cf4,6ddcb4d6,1e9b5324,f5e7b7be,5407cb5e,28a9df4f,3d52541d,49ce4b07,7b543747,3a219db8,29680777,3cdcbf80,e4b47786,14ca082) -,S(6edaa1b9,ea8c2c45,6c6a34c6,13ad60ed,aed18a04,32e96030,ac7305e3,2dbbf94c,c64c8279,40cbabbf,fcdd4db5,1719c53e,f8cdb650,67af48cf,fd731618,bd304b7f) -,S(3fb5f6f6,60847e2d,e04341e0,26c4102,68d5a1fe,880602de,c07be98c,22640a29,ddd43c38,95e663fa,5aee3227,4a16f532,df3a180f,e0813ba,3ba113d6,f6fbd9cb) -,S(2d740009,d7addda8,a802b263,35d41284,b3b9a119,248a3b,29b4a532,654e84c2,cbe1e2d8,1bffb79a,6f9292f,43ccbbad,e763a56d,6d68cde3,d946f310,dba8f28b) -,S(15bf4abc,1d74793f,6ebf2fe4,aa74e34d,b359ad76,3d5624d8,19c24386,33517436,5efdcb90,259b5dca,39054a98,b6702fb0,f2fd4b61,235ed4c6,cd1f3dc,dab15f12) -,S(feabbebf,3c6ee0ab,9b584162,476c8e9b,f7523c30,7874d7cc,c4a6b88c,b118d423,c51d328d,276502fa,f79168f7,3787d3ac,b4e7bb7e,1f65b421,64ad6e93,2d405460) -,S(e3664247,929c3455,e98de868,60010f47,4258c686,4d4a7c0e,4bec28d1,b9af3188,7cb4bd55,ba579fd4,a3066f83,710a3606,2fab9f87,34311609,902407a5,88454bc7) -,S(d570f391,365aa2ee,29b6db92,2a96e4db,f1820a6b,94fbb8b4,aec45ae2,f97a21af,c0841986,2b0adbae,1cb192e7,bf80dba1,830520e2,35e1e42,569a31cd,fc0c1543) -,S(9cfce5e3,5119ca91,38629b08,c75b77f0,db3cb593,b2bf8dbc,b7d6fe3c,d1eba55c,33891655,226885b4,cd74d8ce,f29e978f,60a71bea,be99a2c1,d2071f53,239e4f12) -,S(186ecba5,f9998439,f6a3dca1,a179608d,a15adf9f,f4d2f386,4268ec3e,e62e4407,ec7eaeb9,bec50709,e8dd761f,6253248b,2fd064a9,638953bf,510a38ae,c7c6d24) -,S(ad52f2f6,fe0b72ed,2a0fe483,3745aebf,acfae58b,b40a0291,21767058,3e0f6b83,b0cae754,85e3038e,c6dc8d,b4e95a54,63e3e6f2,1b99d991,2f521663,3eea0c71) -,S(aa06c0be,7d72350e,6b094df,f4dec4c1,993588f8,5bd82a1c,158f92cd,eaa7804,ed628163,29369fde,f0fac2f1,a533fcb2,a704637d,6dfaa1f4,a3b57f74,4efbeed0) -,S(5f7a102c,4bdf0a06,76e1bd4a,4df17a3f,124bfee6,312b3972,c49fc4a7,14b3e867,85f153db,ab40a9e6,747aef3b,cd30f59b,fc9776c3,93293222,8f534d59,9efb30e3) -,S(31a4309a,64c225e,69567574,e05bb994,3fe01679,6f09a0d9,358b1237,96cd3fe0,9b9862a2,916ad0f4,1e588567,5a1e357d,19ec82c5,b31f967d,af058e1f,da7cab16) -,S(8906bd2a,505e8401,cc89e32,b9362c84,3443b4f,bafb7c03,75bc883b,11c3e59c,ca78e1d0,1c6fca33,b39d690f,5b85c764,ee15dbfc,48fa78dc,5f7d7cc4,5323d187) -,S(41cc93ec,a27c4fc4,19fc1c8e,4568744e,dab8917d,d8936cd3,2723737e,e36b4f9d,c11d8299,bdb95efb,842ba828,a6d89120,1fc6a28a,9f208430,c1e2f748,bce6b7ae) -,S(6e1b0bc6,199c3b84,220020e1,1a698e74,2fa97a58,c498254c,d3af1e8b,23ef34ed,25e0ed2,3f04706,6b4134fa,b6252276,b2205bd0,7a8ba64c,636e0b0e,1d6d0217) -,S(b55741a5,7b9c7270,dd1e5115,995ecc55,8729832d,9f4e373a,6824d9a2,83490eb5,9adffc91,52eca815,465e533e,c82bab6,ec6b37a0,dbb3b6f8,c3bce25f,6e3d944b) -,S(fde1167e,67f0e084,251d50fb,bafb538c,9c375e4c,fd6441bc,59a46104,46ff090f,662451a2,444d39f9,58593a02,e9a94ec1,4a1b8d87,9dc80c5a,73bb68fb,67af754) -,S(bbc374da,188df5c6,5a633621,804d22e6,f7474faa,47a8af94,a1cb78fa,aee68040,c2c74abd,17acf272,6c03bbfe,7dbe06ce,eb1f4e0a,b0001aef,4d8f342c,aef50186) -,S(bde6680d,414ce86,548504d5,55c83b18,c9f94e45,f55b6683,166cc81f,583e0eb,2b1ce8a2,6b5bbd8e,a087eaa6,49f49a48,2891abda,87c2037b,a73409a2,69b5e2e8) -,S(8f9ba006,faf50323,b9637f00,9aa29cb,8e402219,75d329ce,15796428,6c84e5d3,1bb33199,e5c30e98,5f5eaa1d,65879a3c,703b7a50,cb04c7ec,a6c7512c,94180e16) -,S(19f03bc4,3b61d7a8,62bb81e0,f4b84c02,7359a170,de0108f0,e9b9e9d3,95b63481,8239d21c,f31ae885,ae10c62b,8be0ee1a,95db0368,cf0488c9,4a110a76,7d22dd73) -,S(667c2647,2261828f,2653a0eb,e70de204,29231fd8,132961dd,ba3e4853,8e332941,5758f0ef,4362f75b,c4356b3f,cd8cb2fc,3c77cb25,b7d65c8f,ef7b4096,e0d879e5) -,S(86558922,618551b5,c4c66c50,9b81a622,ca376318,7c558ca1,8a00a00d,cf100ca8,32cd16ef,955deafe,e3fedb4e,55fd2071,8e35c1e3,736dba12,9f3c3287,4413739b) -,S(255bfbc3,d0b0d6e,385905b4,af6ee2a0,18109db9,73788509,2d5fb275,f1b47b45,b1b1078c,afe453b9,a35fbc30,c5f605b8,4a1f61a3,1104b406,ab5014db,57e2b167) -,S(acdae8d2,eeab48c1,9507f575,6ba60b0c,e9d5b6be,e2ac15ba,d31e8932,fe89e14e,b077540,ab137999,7e7dfb3f,5e3fff46,10c2a369,2306ac0a,418d5026,caee0466) -,S(162b0c77,da3bc13,a62753f2,b7b19c9f,3fe864ca,66fa2dc4,226c5cd8,ca8d7112,377956e8,59c2f465,2af5159,bdfc86c,df0bd742,ec7f9eca,6e675b47,d6eda222) -,S(9453c9ef,afb6a23e,40ebf013,eb1af363,c28a6e14,d235c7eb,58d3d142,9d1b498b,65e3b737,ede3c00b,5f322b38,9b09a68c,2ff44f30,c7737932,4e9c94c9,bdd78961) -,S(8409ed29,38a5bec8,669e24db,88c1b6fb,b397ba64,d8a1826a,f011e2e8,32e85506,573a0053,1be979e,1ae3f2bc,3d28ce2b,7a3ec55a,bd00242e,73523a2,582500dd) -,S(3b55d457,b1878898,9c486cf5,3d1ef107,4161330c,64fc2250,81096148,f5ea2c45,24780fa0,3e83919b,9e3491a3,7e0b76d0,f5d32f2f,a4c3aaf0,d2e7c955,43476fc6) -,S(d3fa2c21,f4704812,a5b582f,9096fc87,422af325,5c5d006c,63e1e9ff,d2d9ebb6,a6aea607,9ed334eb,9355fbff,27650096,ab19a007,191d57b9,4a8fc12b,a59bbab9) -,S(a938a4a9,9dc45307,29f3bac7,4fcd7241,1e56cff6,f53fb048,c727087a,9a54b374,3949a589,388ef8cf,aee8fe82,fde39e01,41ad91c5,2beaea97,e7494659,1a27bebd) -,S(792220fa,aaf49862,479a6de2,35be75f7,e811d12,7420571f,e46213a3,e77aa93b,5f274791,31fc7585,8b82b021,52057cc4,f1686543,3eb6e22a,de56bea5,8823131e) -,S(b1bcdf1d,57699459,1bc11d27,cb15d84e,75eb3d5b,2f9b4bd6,1c848c14,e9b7f2d1,a2115735,8c35ac77,e116a0c7,77917e62,e1d09897,316e2389,41d8e170,90adeb50) -,S(735b746f,6f0d453a,c45cf288,6941cf13,c63899e1,a41ff3b4,cc1a4c74,a9b2ab33,e4c2b67a,c6bd7917,2478b52a,994dccd4,475cb24a,ed1eb77d,a39fbcda,9c02771f) -,S(1640d0cd,ba4b4fc2,f3670b35,2485027e,2724ea4f,df918b72,3807870a,39fbcb2e,a0a71f4b,ba481eab,999dfc3c,15275eb6,b06d129,48000828,be4754b2,749bae30) -,S(bff651f6,df72e476,a097231e,b496618f,6e7d621d,dfd45356,8b08c718,e138caa7,10dbc188,2d0a17fa,d769f855,bffe1a81,14183445,5d9ae144,e6eddb52,8e67f99d) -,S(1a3fa743,cf429f3b,49e122c4,5c6d6e8d,18c633b3,f9903c9a,207f0405,c2716b69,b1b2c87e,65faf1fd,debc377a,bd9648cc,24abeb81,75efa4cb,5f0a0b06,aa2f1e28) -,S(bc2a9ae8,e2940908,ef5420f0,9ef4c2b2,ae988e5c,c0c0efbf,62f8ea05,b305ff21,ede884fe,6b48627c,84c96869,5944be60,df3ed5c6,66f16b56,188a9e1d,6bb14e80) -,S(8cee080c,e9204a62,502ae88a,15965abc,b2a8f18c,80f6c461,24b073f7,63990ec,3adc08be,7bea0bc2,b2c5ca91,963f4c40,bdfdaaea,318fe3c7,866229e7,e53c8fb5) -,S(2fc784eb,f79f916f,7f57dfc5,8fc62e8d,bcdc7dc6,70d6a444,c13f397d,ed528e2c,56c58a3c,be510393,90a88028,12d03658,20141c,b1b24241,241dba91,74d6eb37) -,S(fcd83e1c,ec7a6db9,1aef0894,cfb2e1e0,d2b48fe4,88bcd28d,c14e7824,6e62aa35,a86c9321,e2dd113b,cb7ec78a,d9d4db68,b5ddbc01,70aa0f67,5586b08d,6694a853) -,S(4e4fc5b9,65584dc3,40cec4ed,87ab0610,d674e1c0,9d76d28f,e28888df,7f9be562,d2344fc3,de7e5372,ebd87d0c,ea5431d3,2364249c,f6c350b6,d7aa2353,26e9ac7c) -,S(8df04fe6,e93afc18,b0508831,320caa9d,b21fb740,46bcc364,aa80564f,6f89270e,d7b37dd,2463e50c,583dde08,ca253215,4d52bd8e,a4252c55,6749641b,71ee7214) -,S(f662c961,3102fc4f,afd27352,cc697de0,1f4a1406,f99a0656,6597b96e,cbc99305,43783b26,759a2eb7,8ba4a3cd,e865d1f6,474b1ae,26eeaa2a,15220353,f6bce384) -,S(2052f92,b66998ca,f172ce,15cde941,484c5ee3,d3ae329c,87f339df,ae944439,3e9ef8c,9f4257d,c563509,6df8efa8,ffd2312f,60684baf,bb9e5d,9cbd04ff) -,S(730aa6c8,9c8abb08,855bc551,1938bc46,bad8f226,4b162386,9f2e1ef7,c2d6702c,7523fb97,799e2bb2,f13ba1d,59510bec,ee682f98,f865aefa,cf3c6578,bf46ff81) -,S(c5773c0,7d65fcb9,7cefd396,b07dfa58,1ab237a6,be3c1739,e6db944b,c7991c59,6afea6af,44ea94f3,ee67d071,4b6654a2,b1b335cb,e914d305,1a60b05d,44cb81dc) -,S(3ef9a63a,5bdce751,48d7c585,5e3e9aec,90d34ca5,1a3b4829,979d67be,c38c83f9,145e65ae,635acb42,e7949060,fe44f350,3535d417,f3ce9e42,4c3b3d0f,b02f2c73) -,S(a1632263,42b900e5,887b1800,196c5be5,11065746,52cb88c1,4011aae4,6d14bdc8,beda5e2c,40b55506,31aae0d3,fd9997c5,3f37169a,2d810b5b,402210c7,7c372cdc) -,S(8c1f5646,65449ca1,f16015a,a876bdb4,4d965993,7ca6936d,5bbb80cd,c2da6d65,7cbacf98,f6f7363,8940358b,60beec4d,1cd1a1d,900f84bb,9db5f784,d4565034) -,S(693ab562,230c1ddd,3493c64c,6f7e2bb3,a74cc535,2b7efc30,630904,e700d5a6,db890cb6,d09d5be7,ddaeec01,299880a1,2e68acdb,dd950118,3c8f5f07,739cf4e7) -,S(d761653f,f7979336,f833ca51,b91b9e90,b2bc04f,7b7407eb,be3c8462,95d59df2,f81a5d74,446e9762,2391368a,ed154b2f,4faefa60,af93d727,8357fd6d,98537c5f) -,S(41de1c8c,a1315711,3435ce37,c2d2efef,24a67cae,59347d23,44bebf0f,a2cecc64,77629b7f,46cf1d57,a03898fb,cc9f4e37,937daac8,12c4df74,846d8c89,60095559) -,S(21f89207,4e3a00c9,39862265,c1762dd3,2662d182,397c1127,4ef144b7,f598b650,e6e30e11,566dce23,b7a6a06a,11e12bcc,978a6b7a,fa9297b,8c978f56,40f8b4f1) -,S(6163f61c,628b4800,dc49f30d,dff19310,369012a8,f31d4a25,27c790b4,c51f068,4e87a17a,12055cd0,4c4bc19,e052a219,7dc5847f,ec984f9c,aebb8f81,7a7065ec) -,S(a68ebde6,43ab3c15,72f5ab0f,85d683f2,6e6eaada,550e2425,f85596db,8e2dd200,487604ed,38a6387a,27e3cf1e,9d4865fe,7fc67e7c,ee26ab11,1f03e0a3,316de778) -,S(9b9fd342,4e065ff5,b82e0c4e,e5efa0b1,d0991087,684c46d5,7885adcf,b352d06c,b11a7a46,570eb251,6562ae87,90eeb403,823380c4,aae99329,de713677,5b5b5e0d) -,S(d80c347e,98db32bd,57ba5728,20c7322b,b295cc3a,ae326fd9,49e7557d,27151fc2,6d734eee,40229d19,465a0e2b,a011af39,62ff5c08,f83a2e17,e5c2783c,a430cb42) -,S(c8aba983,5f814895,e5d05139,7b23988c,7fefedd9,aed9dd20,a9bb0025,49e63ef9,3811b18d,8310a67,532be770,45461d82,e40c0ff5,6af355a7,55ed4708,f1ab0c7b) -,S(1bad15b0,a186d418,bb84a87d,d2fb9255,9aa64547,cf47a93f,73d23953,86b0e301,e432c50f,662da1ae,f7ee8f73,f5d7ac4b,4a4da6ee,5a943d17,7557e64b,5eeab1d2) -,S(720fcf05,dcbb0609,e5b45efa,e055811a,66d84384,16f7091d,7ea66186,922779e1,9045fb14,37d2086e,ae7d6a64,49effaae,17e3a559,571ab010,57f20fb5,80535906) -,S(96a540e7,8fb6647,63d3b129,8a1100b0,88a2c3e6,6da3ebe1,4b6c39cb,f01c4b2c,4debf0e5,c95b9a1,7bec7f14,12018197,88a1c325,12f60973,9d5b4909,f087b5c2) -,S(2f068148,d385bcd9,6fd6b60,b7e331b5,88419085,3942ed16,18b464c5,9c3ca99,596f3fb9,2fa7377f,a9ecc8e5,be8421cc,77339f62,c6f1572d,7a28266e,eb66ae52) -,S(466e9733,ef167fb7,233363de,16d9d510,74d8e5b6,35abaf38,20a037d4,f6b3e45c,73548e1b,d4d5b78b,821fb1d9,94919bac,a9d4e12e,13a2e8f2,d4c5df51,2553410e) -,S(f8a841c,a8c7fb3c,9a334f12,cfed9ddd,d1dbd4ac,764f3c6e,87a42818,a4a8e51d,57ebf669,72e9c4fc,7c435cc6,a85d381,6a969d02,ea85edc5,63c57187,34f0f926) -,S(d8c7d6e9,6719e74b,2eb7ae7,59d82ad2,6aa003ee,58e3d9df,ea97c7ae,6d6b887f,f1bec88e,5e8df038,b069692b,9e44245d,a11feed4,c89ff45f,17bbb6b7,1b0e43ca) -,S(afd5e13c,cabf51c,19c39c4c,815618a6,14a4f461,5fbaab69,624d366d,540ab638,9ced3d42,5c361706,16cdba99,653c00aa,e5212c5e,939c0bf0,3e5a1cb0,a05cba0a) -,S(fb491696,a4a1b9a1,572b462,f4628f66,b8368f3,3ce957d0,6ec29a0,92ce994e,b4fa2340,68741570,a56182bf,4f1c71eb,2c80d6a0,cffa42bf,a3e9d9da,59507de8) -,S(96e301b1,efd54091,80e3aa96,6652a253,78ce4bd3,cf587238,f0367a58,ec45b0a2,1bcdfe49,5ed90efe,7eb853f6,6fdc5b7,365ca2ae,e1d9b787,afd41b9f,c00f308c) -,S(9cde8d26,40d197a0,9ac00167,9b93092a,6eb8b13a,4d9fe2e5,6365a5f5,fc38d809,c86345d9,cf95fe50,40b2b2e6,2bf4267,72cdf10c,988a4f27,836d960d,c98501ef) -,S(d33ba473,10c37342,43e2219c,f3cf4881,2e843be3,c7492d01,80239bdd,20a829f2,ac774707,a5b0888e,b2ffa131,b71035d3,6af5be1d,3a3605b5,751b92c9,9e58a45a) -,S(6b364a32,1b5aecb3,749093e0,1b5229d6,5576e65e,1bea096c,29065a87,e26cf2aa,668ba97c,a01f659b,3687cef8,ac87dcd4,7a8a4f85,4a434f49,9592151c,b8f96152) -,S(d0009cbf,1d0d0673,5f66c16f,5cd4747b,d33b3347,fd7f096b,a026355e,917b5015,41c10a72,3e82bec0,b92e560d,3bf1e0d8,15a22e50,3afb4bf0,e5caf771,569a7dee) -,S(e618f641,a5b443d0,704102b5,40efb697,c470955a,8375e6b,a845c299,f377b701,9d615e53,edf6463,9b3b2d0,8684f8b6,15cf4122,33991a4b,5b7c85bb,f5698825) -,S(789c55f5,d393228c,7cc7920,9e705d29,867a6e9e,750d05da,9bc6dbdd,36c5c49f,8f38e43a,338058c9,39c64ff4,3f8f7bf0,2a7910bf,dc2f9af9,532049df,ca236de3) -,S(8fa4f0a8,1bacc20c,5d402478,23401597,bfbcc47b,973abe3d,71d33e2d,fee792f7,7dfac188,c5d6c17d,9e7430ed,d9038a6,e6fcf47,174347d8,7a68aa4e,cdc46c38) -,S(4d5f8d87,9377b056,afd4c8df,54a48673,c43fce03,d05be56a,56c42a23,356c34a2,b064c60f,a3b75513,577c171d,68acbef6,ac96f665,6a899d54,29e9427b,533b8e36) -,S(7a409ee0,8299930e,ddfc1e4a,db8475ca,9a99bf4f,a178a8b2,540ae448,ac87a3b1,5c4873af,c8a079cc,38a385c7,2ca039d4,4363425e,67de4cd4,15d09514,50f28e17) -,S(ac327275,44973221,dfb8b577,e33bd935,76407a86,77a1a842,bb04832f,68304e88,2b41b0de,3e406560,a57978e6,3359a911,6f993a91,9dd1c2ca,79c9a36a,6a4c8815) -,S(f9168fd3,973728c1,30dda9c6,907912d3,2e6cf9fb,b1c7a058,cc948f4e,44282720,c7005217,a6adf515,d8d3a87a,7e8a8b2e,aeb470db,c014824c,733e9a7b,17111677) -,S(818b9a9a,295d8f3b,bfb69d3a,f4749e5e,b0c1c04c,838ac3b2,9e74f6e5,dc73281a,141d14ab,64b3023c,597e96c9,3fdf393a,b53f45f4,56cd17a2,bd917af5,dca8daa5) -,S(90a416a9,dba0e05,bdd25dce,2dd0b0d9,200aef56,a6c0e16c,748e7d4c,99cac1c7,bc871391,95a2f128,af9c9c0d,56bff605,2fc27648,4e0a855d,6472f0e9,a779e0dc) -,S(678248e3,d48fd800,8e694890,b442d3f8,4f851881,9b152a6f,da24a6ea,88e1efb8,fa5d302b,51a36e66,98477693,9ba9c095,eb8b78c1,8f1bb114,53cb1904,a2185615) -,S(c2333e2e,742bb244,b7dac90a,18c2e65c,1dcb447b,11f8596c,bb3fcb8a,1e85195d,d15b8771,a31ff36d,b46b9ca1,b0ba345e,b877b7ec,48de20d4,71792a78,17ee826f) -,S(7d562291,9c72b694,d81bd71a,e78204af,995a63bf,3e8ecb3c,d9b3f589,c75ef8d8,aa554f52,67d9d3a5,8d35cf02,191b533d,ffdebf32,dde4cf07,252ef949,ec7df6bc) -,S(c5023f92,698f955e,4fcf7fda,288673ba,97b4d275,7f26f25a,c63ccfe9,155232b4,7d9dbce,def550c4,ee4c881f,69010859,c7a09ea5,36a8f7d7,17c1573d,c5db971f) -,S(37dc82b2,ed0e9533,e87867e8,d1eb57ed,707f335,b081d14d,d57aa247,645bb1d5,ff0c021a,d28649f2,3f000ae1,123f909f,1c803a9d,98ef2487,bf5d44bd,a97068dc) -,S(ceae1d30,2bf19dd3,a952ac79,8426244d,968b6ddf,25e16357,553f7636,a15ba8ed,c5a3a752,4d05206,39ecb8b,bf4282df,a1f9c795,ea74410a,ed9e064f,9a37c70) -,S(8bd49da5,fdb92648,f321bfc4,2d8145c5,20b8dea1,46b2bbf2,7a054698,3eb6574f,f769854c,5b5c9058,20ab0765,1a6d8104,e9a9dd1c,7aea6425,2b239ba9,7b0609f4) -,S(d1553a8,9a5226bb,3c5b6296,9f094b2c,1b761aaf,2605b0ba,b3793f6c,6959e8ee,d7b11159,d289d42b,8ca2889,f3dd7d01,e1cd0e5a,745b9f12,ab98b823,3211b2fc) -,S(ccf443ea,d8b17d4c,ec59ab81,74f1b1b4,8b6c3934,6e64a955,c617336e,aa6abc89,5cdbd39c,64510cdd,b342cce2,62915966,f8cef7cd,e10f4a7c,41a0d495,e5bdccd1) -,S(f95ad24e,7accb2b4,ce6afabf,6c1a40a0,172cf2b8,42871778,881ad94e,3f3d8d57,f3142d40,377543bb,6dee8195,743a6d73,e60dc5ef,4b0756eb,68d09d6e,326caf5b) -,S(464189d2,52726cd2,6f5ad4ca,5184503f,c546144a,ce7dfb32,5e4b4147,da7bcaba,910f8aae,acb04646,3c6a2a31,6174510d,8ae8bac9,fdce4c47,6c0dbd62,5196e2f9) -,S(637d373a,7355334e,70c78ae4,99429ce2,a5d97257,c0f407b8,1cb41704,d1b36415,469fa81,5dba5bd8,bb53a5fa,aff5b4c,18e7c28e,fbf21f52,14359d6c,7114c818) -,S(b489330e,2a4a4a6e,a99091aa,4e5aebaf,dcdba016,2bbc38df,5a49d4e4,7eee62b6,e1fed3d,93333ae9,2198b85e,fd68582a,35f6fb60,ff268494,720b387b,b3a7543e) -,S(8f2fbd92,70781f54,9d32ca01,2479438,2ec9cad6,2151c893,64c1cefb,c2324b12,2ae5c8a,2e018e74,2089a4b,12082c73,ba466dc9,851e7226,388e48ae,b1270a1d) -,S(a1871963,e9a65bd3,9e1b667c,55fe1a1b,87fe4215,8273c6c,f338f8cd,9119a828,e6881210,adb32d79,10dfe9da,c46c728b,20bca3e1,ad130240,f0dac7b9,fcc0cbc7) -,S(4a91a506,e8b32ca,13cbad7,99c4e3d7,21fd64c9,7ac8a1b1,e7f4bf2b,cc0ffa1e,66a0ee78,cb63bdd0,1a7c4bed,7bb565fe,832eb2c2,d32f2032,c33935f3,f16a40ca) -,S(61c960ef,2a3a6244,e8e7ee79,d4f5e98,88539c0a,b8be739b,314a100a,375ab66f,13b94913,ac8f600d,dbe9a82e,8987a061,3672629e,45d7d887,822faff2,60fb9e08) -,S(10325f87,f797c48b,2e6c7acb,bc0aa0e0,537fbf59,e74ab9fa,a7630c9b,86a04b72,685c5ae7,26b5c9c0,31e1c830,d513db4,b7fda140,14f8b723,7a9da11c,7ce9403f) -,S(71bca019,c15a3534,e5bebab0,6e1e1821,1ab01e97,dd24e1f9,1f89f834,b2cfde74,102387d9,a8da4f7,a483480b,316f0303,2178e668,f7a72719,2ae7e54d,27314a8e) -,S(7d30b01c,5c93abf8,9a50d14a,535a88f6,7cbb535b,1e58540,661fd7ea,91121fe6,e3d7e70d,1a9c0cb,2d6c86df,53709d18,b1989a5e,7642c1b7,cb381338,f6ed96d2) -,S(6f0322af,c1617968,b2550b3a,cafc8d0b,9445fd7a,4692f933,3ae9146e,fa2d3a4e,ba402962,d311b424,d05f199d,31b07d5c,8534ccff,caf817e0,88712bb4,2e6496a1) -,S(a3719ef2,c34bce90,feb7668c,a07d1a23,e2e6fbbe,1eef4b93,d2995e84,2c74688a,7164f77b,67aadb53,30b4127c,2d71dc46,f11e2d72,25968163,f4ea7358,134e5d56) -,S(3cb0007a,d2f1fb76,aa9752f0,218e2498,b7217440,a6a5136,68e95a78,4f71a72a,2f498749,12e8f469,e511b7a2,5a5046c0,f922a343,24620b51,3f6f0160,6de6b308) -,S(26b62d6e,f46929fd,88f00ca5,a699ac87,e090ab0c,8f02a078,393fb3ad,ae18c055,4fb9e53d,1b643585,4f2c78ed,1a818a80,1ff62c5d,fb0f8f23,d5e4d096,29886fbc) -,S(55e9ad69,68f490d,bfc2e17b,4e90dc5f,58335c1f,7bf30d44,79679acc,8cd7442,d4df7806,f74d9701,378ea804,be9a6270,85767e0f,b816ddec,4dbe34d9,536fe892) -,S(74a87add,723320ea,f1f9c35c,eddb6133,79835723,c74bc043,af36aeb3,5e1cbc45,5c79ef91,bccc2579,eea907ac,85ff8c0a,57fb48a7,c273f9af,6113e177,588fb14c) -,S(d4f1a9e0,2189ffca,c1d9914c,177fd66e,9d9a41cf,d1a38626,aed6b82f,70ba8020,923bf669,6ad7c71b,bfd696f3,9d68373b,9d0cbad,f367363e,2f70a93,4a0dea5c) -,S(593c7afd,c178edf,9eae7fb0,85984992,bc5ca489,16a2a155,a0314d8e,31fed706,ef39bd47,64f3b3b4,cd505e3a,628197df,5aa74126,30d83793,75c85b27,76a1073f) -,S(6622a6ea,569856b4,23e9f68a,78bab680,759a0089,3f6f645b,2e0eae60,f5dc9d3d,e84d491a,1bfc3127,3cfecf5b,65621213,bdf1af30,2dd39d26,d756e75c,4f9bc86d) -,S(d7149e32,fb34d956,1f5b25d0,650409f7,33a28fc1,fa4ad822,eabe98c6,74b3437d,2c249dbd,a1a82561,51b6eca8,a44bad96,1b2d37c6,d01c1d1a,70ceaa38,9b3f5039) -,S(64058ff8,7cadb65,8efbf32f,a68b7b3f,19915f5f,b434830f,bd5ca208,a4a09b6f,71c6dc90,f4d8082f,72d5697e,48fb380b,8486d7e1,5f113cc,28365ef7,d3ee9999) -,S(6a6cbb7f,5b571865,d70ec29d,425115a0,82d1fc1,f0209e8d,47be5e5,a9965dfc,fbf10d18,f3af0e94,b2a6ed30,c610f17f,5bd571a,41d073c4,2b2a4dce,c98ced0c) -,S(3f9a9be2,9a72cf7f,2086d9ff,3701a35a,94a7f81d,4b34a364,916a45e0,d8652874,25b12751,5ff033c1,70feaee1,189a35d8,ba0b8da,d4c943bb,4fdcebd2,1cffdf72) -,S(873be5e6,3cca17ca,95980167,9568b487,3d34c5ce,68abd305,169917a7,30dd206f,6ea148c1,280396a0,7ea5c5a4,17980f48,d076bdab,3df1628a,89da4c45,14bcbd4c) -,S(17865995,f28d4c4f,43e2e9f5,9b20edfd,830a65cd,d632cf9e,e7024ec3,4da0834a,6773c06d,478f3822,86c749c,5ae09a10,910b5666,5b6df747,36d20adc,af58332c) -,S(efe91146,fdfc4865,bd784853,ef79b8d4,d2f020db,3f901f45,38c74c80,bef49172,a81a34a8,dc3a229,8348109c,14d367c8,7abe6753,50d013e0,b1b0372d,2a6ee5ba) -,S(7ee6fb63,36cc88be,3b3c2821,1552031f,d017aa4e,192bc122,973545bf,924e8a8e,a656fe25,846e8173,327ab11b,d8ecd2ed,9d1909fb,21d1f789,588b4fa9,a8ceb0d8) -,S(449677d0,2a78e9a,ce374016,e19e7fae,46efd0d6,4839680a,4d5cbc42,173ee605,47017ad3,3357db8b,ceca2513,c6477157,f3daa99,9cccb709,bbe88340,29312013) -,S(ca9db080,12b9fd4a,cef2255e,83f35fb,e20806f3,9839c2a1,699c5d03,d7b5762,6a1a811,3d82a60b,677d61c0,af995bd1,4c598f08,f915e971,d9f17e9f,8398487b) -,S(d040da2,8dd69fc,67414651,714d4e94,5a27c4a2,9fb44612,d6d87f4f,80e2ba45,a1a72b85,957a01ca,8c8d5d3e,d9ae6a2b,31d2d192,cd7afb9a,4d1e4629,aeb9f356) -,S(27eeb708,fd2d52a9,47f69872,3706b67a,1d6e29b,cc0c86e8,111057f1,e3655608,7f67db4c,25b2e88e,275e53c1,c52eb47f,c2dab668,64b91236,522229d3,1b001a94) -,S(3bc82484,daab22ad,6d887a01,ea9f4b38,bb70e272,b15a7b4d,ab5e3dd2,439d8a23,b0ec952e,6cfe3ed7,4e6246d1,46c9c354,dacbc024,45b1af9a,6a668f0f,6fd52ded) -,S(d0a00060,13596198,8f070ff6,7ea731be,7f97a51f,68faf899,95eb0ad7,746aec69,dde4a735,d6dd08cc,28e2588e,9af0eed7,57017b38,790d381f,74748f30,9717a989) -,S(8efc4c50,51c65e10,56f5ccb6,a4be2014,a9dd043b,641b7690,cae2a8a9,1bbe8ecb,26fd1112,e1aa603c,91eb458e,3874d010,db58efab,5dd9ed20,e156886a,5f39fc13) -,S(e42271b8,881306ce,f166138,7d14f0d,da0db64a,b379368e,fa79969f,432cb110,d2b9999e,7ce9f3c5,8a6c77ce,a97cb9f5,f2860299,9bacdc7a,b7d5487f,8b5c9f5b) -,S(bb068f3f,8e7fbd31,f3aaf96f,de53d134,e3a88b63,9d8d43c6,4b3a2b45,2f8de740,574410bf,903c173e,23d88fb1,3f7534fe,566984c1,aa10f0d0,f54eea9e,7883819b) -,S(a3d0bd11,d728bee1,b166dff1,81c3682d,650fde7f,285ed5ef,b2ac5033,5327cd66,3e290c2a,42afb4ed,8b5a685f,69bdd379,44215104,17a61d8d,bd3dd2cd,805c5f44) -,S(9884434,78bfd51b,d27d04df,b5282a72,4cf82c21,487a8733,9347e560,994debdc,545574c4,359fe553,b694803c,5a07339b,b4e1a95a,b9fc72c7,5d4c8f5d,ec6ce4df) -,S(8cc104b8,58b8fb94,e0771dce,a103a7ae,adfc50cc,dea4cf93,a5f4ec9a,d44acea3,ad73883f,57c470cf,d477f228,8badab99,938b6723,516f97b1,22578f2b,f893b506) -,S(1627b08d,a822d244,ec8fe2e7,d8f02094,111fa362,e7190cbc,11229a4c,2043c626,41f6b029,80fb1370,c1e800de,39507798,8b6f315c,f910bb00,423ff727,e9e04c3c) -,S(459d4b1f,2676fd9c,2aac5937,376dc18c,fd4244d9,dc937407,d641e0d5,491df69,6f22ce37,a6ea6a5d,c9823197,22b0085a,e61fe140,d7558fcf,7bb44976,5de7aae6) -,S(cdfc7b3a,b755c181,72882e37,ff641e2a,94fa4e5e,b1b2947,4cd6e94b,f4f9387,76a11dae,107bced7,c2870dd,62ef183a,d45a02be,ce33e333,dea061fb,d89e787) -,S(5e189861,b1615f76,ac416236,e84b0961,b2639845,ecf6e6ee,8dc33217,b0952afd,1cfc65b0,9194d1f9,71136626,a2c3896f,5a3de705,ff1009c3,49a09c86,ea1667e1) -,S(84749eb3,3d482c59,81cc08bb,8634bad,fe0572d1,42367cc8,57a3c399,821d12c2,146a4fa2,3fecc0de,f00299c0,19406b30,dfbd9ad0,975717c8,7630e726,6e96022e) -,S(d73a1958,e9aa29b3,b1ab0807,2165c06f,daa38c90,6be76384,1851fa3,5711bca3,41f13f90,20633dac,3a5eca40,229ad15b,434c4f8d,4ea570ff,76d15d4f,63ea882e) -,S(1d77616e,1ccf1fda,bd4f0beb,6b60c1b3,1b94576e,bf2b61b8,c085cd79,caf8c018,7d3e5813,cf181271,55f3d084,df1077eb,2bfc9d6b,8ab6ede9,55c0ba4e,5095f23c) -,S(bac936d3,63887dab,cf27ea02,50bd550e,db37cb71,a2a8351f,fabcb1d,6d6ca9c4,7aa18819,8bd513e6,b45d6633,aa1af70d,b1a9c432,ffd1be4f,8a8fda79,a38c47f6) -,S(4d18c5c7,51639d86,b21712fe,b2333d52,5f4bd3f5,e4208537,e1e3bf7a,9343475f,2a60352a,4d8fcb6a,ce01b4c7,63619f16,156868c2,d85e882e,a2e7fb80,16f6500d) -,S(8e473caf,d74fb06,b483d955,ba3e35ec,e99a4495,cc86485,a8b6fada,c4c8eb4f,41708d5d,ae2de832,c7c38389,d0ae46c4,46add069,8e83990f,52a545f1,6ef66942) -,S(91366f76,48ed27a9,2ab639ac,f37aba5c,44e8bea6,1402e075,e307c4fa,ea2cefa8,868fe0f5,565092ad,677eb1c9,8959affe,5af504a0,c929bb58,2f5c3263,114ea371) -,S(1eab20f6,51b63685,a0a8489b,4e3247ce,1592c4db,40cb2f90,7eff1c58,c6609915,c142e9f4,b9522b0f,1db90912,c6f83c7,add6d8a,6bd1de4b,c54503a8,4e873cce) -,S(a0652eda,796ff72a,eaf8cfef,371594fb,e1528929,1320230d,2bc6a252,f4b49484,67e6d40e,8aaca7cd,f2a2047a,fc0a59c3,b4eddc1f,d3d5662f,45bb5792,9e4dc9a3) -,S(83915afa,c936886a,3deb8958,70e926e9,7ee4a6ab,1a5c66b,a1602c13,c4f959f1,86dad7b8,e870dba7,712ca968,1ab63524,2ed55fe0,36a148fe,25b1bdb1,1ac2da4c) -,S(293f0bc4,11454959,86b19fb8,6f738d2c,814523f8,b75b280,f8f9021f,95db6061,12d98ddc,894669fa,86b073e6,5855a0a1,760733e7,b7c5bf5e,868dd977,82a4fdbd) -,S(a829b1c0,d6780732,321871da,2d28ecdf,18d13311,4ddc33aa,8ff4caf0,58fb9ad,c5375298,501294a4,dc38d1f,a8c96f9b,789ee9c5,6533643e,1142bce6,8e1ef5ef) -,S(48133900,866a344,68309fc0,cc18f79,c0e01dfd,ed6a7bb4,e5a4697d,4b9cd462,335b7188,ccea4687,50fcdfc9,a6fa6034,c239fe6b,27cf6460,182a1c0e,c8c96707) -,S(7fe9d310,bbdaa101,b28c1e71,137a7ab5,181dca39,aa8d1469,bc06c856,3c7a70ec,18006c39,538a5141,2371828a,4d73e02,f4699a34,7e887318,57e394fe,75c8143c) -,S(1bd5b65b,d79c3eb,54ee1ce2,541b4352,1b7d6c37,d2a26f21,b51d2c07,103ebd8b,66e81b90,a120f04b,340adb2c,42143ef6,5d8a383,46e71856,673090ef,291d7bf2) -,S(237374f9,306e5714,5f37a1ce,1418a238,73938fa0,8bb971ab,fb5d97e8,e5fa0206,d8410815,fd4049e,f54abd51,fe2053a9,bde7f3ac,f40fe992,21bdcf8d,4b9808a5) -,S(33279bf7,38cee621,c17f75eb,bf78af4,58c1a4ef,a7197456,b57ee679,f2c34bfd,d63a21a4,5dc29462,13750d88,ea5e12c9,900b110b,ce433c49,e9b37382,7de327ac) -,S(ee274c71,b1f43251,11d7e100,5d7e9d97,ed1590d8,95cc6504,3e8ed6e5,5a87a9b,73f2bd1b,1baec4f8,ebbcf9ec,f613869e,8a262d99,7bdee49c,c5b2fb22,b652e9dd) -,S(2f49f0ab,c24536a3,3bb0857d,57c35846,f5dd036,3851a873,46f93d0e,53ab8de2,66b3dcd,d367958f,fd06121b,e42237a0,a9edaf21,79ded853,e8bf3c5,b6a81531) -,S(2d122193,ea92ca9b,46eec10e,2a23268e,9b1f972e,91821489,8cb12571,1e3094b0,b54d4b85,a02f77a1,57a48001,c0a26c81,2c038d0f,b91575cd,835183ff,3a0b7071) -,S(9047eae7,841f346a,374131ee,d4299fef,970f59e1,e4bb1fab,819fecb7,3026ad44,d59d3d2a,2c03be1e,553a54d,2dc61c9,e13364bf,3338a5f0,4e4466b6,86695061) -,S(f689480d,c0ddd61c,ba5aefe3,17aaa497,c2d051ed,d527cc20,16877986,12d7c8f,dac41495,a948d83e,37a9f310,18cd7abf,6d5608f2,213aa5cb,7a2b8f90,98d87398) -,S(4a01c418,be472958,5bae0c45,cf6233b9,ad0177ef,eb6e74ca,ded59788,a22d083a,8a12550b,83de095f,22411b16,937a85b5,a079c7ea,b8137f80,ffa66116,2a1c53f2) -,S(a6c715ad,cdc77020,febc4ae7,c6caf5a1,107147ba,8281d3f3,7945682e,72a5da7c,69b4ce46,2634da4e,e9e43559,72f87511,a26718d1,d232f726,577f0d5,6b49d165) -,S(68ecec4f,aa19ac3d,dd8b928e,8362ed53,3be24406,15f5ddf8,4b8a376b,cbff327d,f725f978,f6129f28,49a1c9fe,b07bc2b2,78fcdf4a,96a6ee3a,70b9b943,98a89f3d) -,S(5701d52e,2cdb7b71,a9ed91e6,95396487,1b656bc7,271299b,62ce0a4a,78dc69ee,eb8e4539,be99cbf0,ad730fa5,fcf785b7,35e1f5ad,f5c16c72,85abfeee,4058ea1b) -,S(8210f0c4,4b2f54b0,62de4761,b7c62d87,42424b13,ca0448ca,ba999eab,73b26409,1c79890,e4149248,b9dcd496,1da563f1,517275ec,79949969,8c6b864f,c03f8050) -,S(64cb2793,4ee57641,9d52cd81,6144543b,e4319d16,fdde7a7e,2bd824c,113bc1b7,c3144c3a,518eaebb,51a55bba,d87aba0a,12d3add5,5a5e00c0,94a2e227,80f0f6b7) -,S(37eb1010,acb889,932d8536,b86648e7,c124a8f5,1005c0fd,ec40bdd3,6369c82a,1da5703f,b387312d,d5a337c2,2d3f63b7,33dcc994,38109c2c,4807fc45,c02a2717) -,S(84bbf980,b54d60e1,ccfacb7,e861aded,b4cd7bd1,a3f7baa0,9a1898fa,22144d2b,3820c4d2,7b545166,2515064c,dc9b4cf,813c2435,e84a4a67,ba47068a,e6e09045) -,S(29e74c02,6b43add6,939ae05b,dc0a5e0e,b7d05bc0,536e23f8,8fed55e0,6f93f1f7,f0f6fd9c,798732c2,1dd1c550,3cfbd56a,71b335d3,aaa22359,75fb0c89,9571186c) -,S(98f3530,1122a0d2,629e5adc,579acbf8,8c0aea34,c3450ea6,784c4ce5,ee9672f1,427b899e,74e0c5cc,c289304d,b9a874c5,1d401369,55dc5b03,e0713bb0,8c3ec3ac) -,S(16af2e5c,4c37b50f,5f2b6e94,341e365c,90548d68,2bd9af37,1d849126,ad2c6c6b,1dd1bef1,6077f6df,32054335,c81ff474,33b7c1c7,d6243dbf,6a2564b0,fb9d8502) -,S(56998d6,bd5b2da6,d452f951,5343a9bc,4ed64463,adc6b8df,6a3edd64,e75e1cbc,ccd52462,9dbda3a3,10f3beac,7b3d3bb2,f1bf3c50,bca242ba,224861c8,1f26760f) -,S(f1732044,ec59c52,86273115,3c53aee0,c7f1c4df,e6e55cb0,e7e37d62,c1e11ce9,16a547b9,a61a6c10,4df1d1a9,de99f54,b42e0ad1,104a6a30,e6e616c4,dcadb2a2) -,S(6e5fcc4d,2df77b2b,8d2f95dc,56ddb885,6030f9af,aa51d86e,20d4772a,854b8973,11939a24,26c1ad6f,90db151e,c5c9f036,3f0b6898,2464fe92,c33aeedc,77347660) -,S(74a3ff02,98c3cbde,ba066554,d6def895,3954af05,f0f72365,680b7b8,4c5e9fc8,23b5f011,e50dd2b6,9c5ad6b,b4dad524,9c6a8abd,f134c232,f40de18c,3c65206) -,S(12a40a59,169e806c,8e32deb6,7e64c615,77a3ca,5c56723d,ebc98ed3,11983bc1,9d97709a,9c644c8e,3fcda745,a70cf3be,c405d230,eedac78f,96792bce,a715c081) -,S(f25dcc0c,5ae3f442,7fc17acc,bf888557,82673050,c3594abf,cea7eec4,7a4662af,52a20297,bb9213cd,d1b4f1f3,4f6168aa,ec2d326e,d9aef5eb,5b497c39,e0642e0b) -,S(fe31ac7b,ee45ffd7,99941eb1,8d65cb2d,38618938,c6278e45,4b87e41b,3c7d0f90,a5f1be4b,e0373cea,c3137a8a,c5b5cab3,e1209c93,2d49b245,eb99a0c6,469c3e64) -,S(c0ff7403,2855c2c9,ba06c2fc,6c9a8fc5,29b4ebb8,be082951,475196b0,ca4d6711,2c53707e,540e0c03,27a10980,25e356a,81fa6a48,b1e41d78,b7fe5515,b022173f) -,S(5b23e392,b87bef43,a3c08956,e1930c10,cae049e,b6f041f9,1bf3de75,4a84f984,c905adbc,337b9e7d,78781dd5,deaa0590,18e20bc3,5114c842,72343879,7a37987e) -,S(2100a6c5,b6b96ad6,37e13430,8d92e2cd,97902da4,7a016ccb,63a20cef,e72ac25c,a1fdc3cf,93560ea3,8418c470,679c5389,7bcc12aa,dc87ee6c,3429c68f,690f7e11) -,S(d57874e,509198e9,ee6ac826,b101ab2d,fe952895,ab288184,55f2d85a,eb2c3387,1c7bd36b,cdb6debc,99228b,341abac2,94dfd768,c9e00e73,8aa58339,d226f940) -,S(ff91057a,e46817be,b3874656,42afecb2,a290d31d,f18c6da3,d6313565,99657c4d,a2bb1559,96ca6cbe,2a375c3e,510df603,69d0cd8,f66d6571,9f9866f8,c6e73675) -,S(7f20e461,ee306c4d,7db625b3,49906235,14aca551,21b7890f,244de5e5,84d18b7f,8cc69fd1,eeb89a9f,9e126be4,3983ed45,d88c22fc,89f47006,ecd57431,4eb5d1c5) -,S(7ca32320,75421226,257670e4,5f277f4d,32cc7b4d,53588423,317203cc,b787696d,1e940799,8f25b7da,8f1212ba,c1dceaae,ca7b1952,26655535,6a98769c,b3da15fd) -,S(bcb7060e,f2685623,9aac249b,f603ce7d,b5c253a2,c998e44c,4ed60db6,730d5450,e03df58e,6d279025,955a4f52,dfce586b,f427e376,ca72e09,36d80c31,5047f57) -,S(30387990,3157ac6,fed71113,a004284e,82fdfc7a,3e08c0ff,1ff5dbc5,dbdfc04c,7132084a,1230ecfb,200ded60,9a1666a5,2f574014,d29475e1,6a061330,fbe19e7f) -,S(c5b3aa24,1147d664,a0b80f33,5dfefed8,a8f7c1a8,c6258686,cb16e3c,c365a249,fb5143c6,5f8907b9,a44f10fd,27064fef,93ee588f,9e77a65b,1cf64e4f,956f5748) -,S(11d8bdb2,b750146d,d78d8c55,6e6ac45f,4d34f1ae,35332673,cbb46bdd,3d76d9a9,1ea28ad5,c92761b8,7df96987,6e5b3243,9fe97661,87b5978a,d7515288,f30a5970) -,S(d6db4c60,742914e,c9c7bfa0,7a716cc5,f5492aa8,5381f31d,f76d089d,a773814d,b0ca5fa3,bc5d1fa2,c62a657d,77215b49,82f72e89,b138552d,bdea8166,359b6a3d) -,S(d28a6123,3b4e073,f1242c4f,5292bf70,9e1ae15e,a654bae3,4239133c,4a8a86e8,89519c8,8c44b38e,ad5c2ace,52d01de1,d74ee0de,5365567,cf1b21b2,2ae8b95) -,S(ff32042b,6a943772,d6f5794a,43420218,2ed31ac2,447167ba,ec82d19b,86751337,16961368,e20f2550,383268c3,9fe62fe3,b5d356b1,da2e4231,8f9618e3,13655f0e) -,S(f2c6177,30a9870f,5999ed69,d34efac3,589baa96,9f660cf9,ac839eee,a10e374c,fbb2480e,b6f191c0,15ee3c58,bd950aa6,7bee7569,1681250e,502e1d76,b6ec9069) -,S(dca14b70,e5e33022,eb559d90,1cf3a533,4c40bd45,7a43df85,e87acd40,90342539,7d038e51,30f77ec7,efe84748,4145594f,87d613bb,85a95715,9d0cd377,91678d23) -,S(9cbb407d,acc7c2df,2d86a258,d5ab2b43,31a18bea,9480f5e3,7727aef7,644416cf,7ab9fb64,c5f54f6a,4e5529b6,eb7834ae,80283bcd,c3f6b24a,8a014d02,b3b80b57) -,S(4552c48f,2d96ef41,aaf27778,a7ab4945,e4f2a2fb,7e1564ee,c375e50e,3516f555,e63da54e,28b70a99,5f35a1ac,3a25e384,6efafcbe,4e8f73fe,d84e095f,126524ac) -,S(b4cfb90b,168dc850,36559181,3d2d084a,9866512,9396f76,879280f2,38e4af3f,cfca0080,37006c35,7fd89c5a,1d444d19,5fd72d4,17fee670,e7b743dd,57f71b00) -,S(8e264996,e4e8a858,a1e32c59,b0df640b,a096401c,e77be6ee,ccd228d9,67dada3f,c9f5a8bc,89322e56,838c6d8d,859b6012,6d0a40f2,8377aca6,b5b4dacd,44931d0e) -,S(34ea02ae,49a4dce2,5ec2dc07,c71e3400,390b3054,83b8f30a,81021eef,5761ed99,b4b6f9ea,c41bf9d6,c4bba143,4639fd57,b8735d27,6098e374,d9324319,3def4c1b) -,S(bd391dfd,8569db85,b567c36c,5e6c378c,c152ad9b,c23d1fd6,1af23e29,543a56c3,9bf167d2,77e6bca3,a8d3cce7,61a36abe,91fcad0d,8d6ce398,877d3748,f2f13bf) -,S(67b295aa,440c8807,95369b98,c67d1d5c,1b9265af,58541994,7353c0bc,47ea8483,c94a0287,f2983c42,14f3baca,a8c5c791,d4d88fb7,30eb5b3d,4309f5cb,c5706f23) -,S(755e0335,284ad31b,5afb5775,fa191486,32b29c84,f38cafce,1b0b3b4f,2d073a42,c4506c75,c8cc96d2,8e31766e,a8ed1cf,531f4f7c,73888831,65f825d2,2b74c47d) -,S(e4b0cb3a,6149079b,5e47ccd,bfc4f351,64e575c9,20cd9827,a83f68e7,e5ba0a97,1604e71a,afa83b19,61bdd7ae,e4be5113,f9e9ddc2,29957255,cfe40341,9e45e5f4) -,S(3baca490,3147531c,905a2c73,277e4f39,c27ff6e5,41f6f2b,3ed4f730,3af0c4a,cf36fade,87b988ee,a4ccec6b,6b70ec01,d057173f,3aa7c79a,6bf4d412,d4bcafbc) -,S(229519e8,2a4dd2e7,ae77d713,21fbc8ff,f31191ee,6604823c,a6aefe03,19d06d95,a70e9af6,14ae7a1f,76224b8f,f5d1fc26,2e34707e,a6bfd26c,8cd7fba9,b5627e15) -,S(59364b22,4a53ed1a,7dbe9753,1b3a2600,2f700045,b0576733,8ee87a9b,2559dd54,b08cc507,70f5f3d8,851908b7,ed79ebc9,7f4f7342,61de0752,e14237c2,14eb5f6) -,S(d4b681cb,f3467c9c,649fd640,7991b4ac,3c66bf50,26ae93f9,e9b0238,9fb7c1f2,6df1a03f,4a5f00f4,8356bb9f,b23f1621,bb18a8e0,5afac4ce,4edbb01f,99a27000) -,S(49784426,fb036d23,a289f4f5,b3b92535,76da111f,ffcefdb6,a4163e55,2c56bc,76de5ca2,16ce703c,6a62ea4c,a0f7ae07,3744a22d,6db67389,9b0e93ff,a69e2a9d) -,S(5b213b9d,3f84b248,a98fe326,929b94a9,7bf78521,106a83fc,adba632c,8ed4892f,8eec203e,d015749f,f01402b1,722214d2,b58af86a,95384ae1,c39a7780,5623a204) -,S(6bb55cfb,9e3f5468,966711b8,6343e4af,6e372d04,ee7f570c,6a12005d,628959ef,75359562,9d633c9f,c2432ad5,f4c9f00,c6f54005,cdffaf82,438e3e58,70d14154) -,S(d760efaa,3a9e5c7a,967174a4,705baafe,d230dadb,4c957cf0,c025ab55,4b2eeb43,c019790a,b1b8498b,58daa784,ba02b7b5,672ba2b6,13d312cb,b4563f6f,e26675ce) -,S(f8be7bdc,6a361b6b,2844c60b,af7fec1a,216d75f6,96418734,337f9ccb,ae9117c0,df66b665,21e3dccf,639a323,5d773c21,4364062f,c5260323,3007e2cc,457d783a) -,S(6bbd2558,84348c88,c75a8155,6529be50,93b06a4,885c5d32,f1047357,a11434a2,842f9093,fd41b2a2,153727ae,ca2cbf00,a494ab7b,eef1a2cd,8696e972,1b1491d1) -,S(e692623d,cda3bde3,d32c1c01,f480d21f,9ccf8f1c,416a7dd5,17f1aab,12d3f3c6,30dab6f8,71f4c6d4,c768e086,fd6287ad,3fd000bc,3b04aa70,35cf441d,44764b89) -,S(86dbfe13,5db905ef,9ec7483c,6f51b75a,71726a1a,27e5131,8d6c0b2c,b0b933c2,371f23bd,45c46d3c,18056f23,10ab6afa,1259c88a,3a55f8ce,cecaea71,aea083a0) -,S(7ee329d5,9c625a92,594e620,4cb48559,458514f8,da94c7ba,fd2a4835,a4f10239,80a58a2b,e17f32da,dc80038c,7ed57de4,c7c561c6,69bf6786,57ee72ae,dd2bef04) -,S(e16a922b,8255d2c9,6ef776b,cda14285,b1cad5f7,62f75465,f8c82695,cf1065c2,44bc0e38,df9ce403,a927cb01,849e166e,6838468d,c7a8bd4e,6ec3fbbe,1f3465bd) -,S(5311e064,23145aa3,10737d38,41adf49b,988c1ca8,e8a705ca,3ca67f98,f756fe87,21c3f6ef,73bcca3a,c376e20f,dec775af,e22e708e,7e500c24,23114b4c,84ea8678) -,S(c09eda1d,dad1ca36,a9aaefdc,d16c5f50,a6ae499f,2cdefa2e,e5b61ab6,69f7fdf3,2220cbe5,bc279362,c5506404,e1df076,52624966,e3222b7a,62a1f7f9,faf00500) -,S(8888e104,18fb5c16,fc3c2b7e,b9ea06c1,da2df71f,c647b989,e71662a1,731628b4,7444a776,fa8f5bbe,959c71e2,c919b761,a2f8fdcb,5e66e5b,65e561e0,928e2d73) -,S(5c70258c,c1030231,d897c9a9,199df5b5,8b920f59,18141ece,d84bbcb8,b9b6c243,d627669a,e3dbb6d8,57d65a42,ec53bdf1,c688492,d189b1b8,67b75c3,f003ff90) -,S(eb58739b,878ea9f6,74b16f8a,406e7135,1ef06377,d9be32e8,1f657648,60e35ae0,752ae84c,8db0c7f4,e956d2b4,5750a5ef,24ea454,8f275f0,52b59ead,e3405ab5) -,S(996af698,ef26245e,35e4845a,dbf9c45d,6fec5564,c1fab0b4,8ac78f06,9840e0e7,a86b564c,ee788008,bbb04ee,e3d66c42,3c6910e7,7988aa54,420f3a4d,3137a1b5) -,S(bd03f2ea,a505bdd,7f39915,23f3e3b7,7532335a,6b5a11a1,4e303542,c00b8f4b,345f765f,cad902c4,56211eb0,bbe520ad,aacf55d9,e9c67787,aa02f18d,ccd88ea) -,S(8480c77f,3dd59c6,329c221b,ed8473e0,8cb0446d,c4e9bc6b,f2dba8d1,7ddf0f1,b055a135,a224f1e2,965cff1,a4f0d764,fed265bb,c644c696,2f3570d1,9af6e360) -,S(f46b6845,fa45e8c4,576b7c74,cd1a308e,f1adeedc,1d539d21,1158318c,ebd4c584,e1ed2665,34a14e05,c1ecf136,8cf8d6bf,fd9f0258,a5f0a53c,8abb00a3,e953c425) -,S(596db19c,38d91452,ad238f05,453bb773,9883df63,a0b545e2,47e5947c,d9f52a2e,bcb35b45,b172aeff,9e4fc5d1,714d6743,46bb4073,6f571291,e6575d34,f8b0d929) -,S(4cfbd998,f9544921,e5f1658d,e3ee95c6,df85b3f9,309f7a85,f6e4d08b,7e535497,ccd54e2e,437e4aff,7fc2ef17,3bed5ce6,b7d6e34b,4b386f36,72140d72,ceba71e9) -,S(c3f056d2,357ffe13,4403cee,6dd5ba3a,a7d2d0d,91d83f25,cb2cee44,34e57f94,1c31cee1,595b3682,fd85840e,312a61e4,40cbbf68,55418b30,bd6b24ab,c3bbf7b) -,S(e272370b,82ffc486,53274eb8,898409c5,9338e024,202be5e7,e18b5ec5,7f824680,d2f4e6c,619f0d,71e38990,f4e52881,de27ee31,ff7ad9cb,11a7f735,80a546cb) -,S(81537bc4,6a5fe897,827aeba4,6e66d576,6cd05a35,cd3fe1cd,9c06a2d7,194be59f,6706c254,125be3c5,92ad55f,6fa6289,4298f23f,2f4f397f,3bc84f50,79bcb8ae) -,S(50e161e2,6bc89d2c,816030ad,45559a3b,49c8606c,b28b6307,6ac6a051,9226d2b2,98478bc6,3f8d6be9,2db02910,67e5e359,e865d046,a5dd853a,fccb7592,72985c67) -,S(76ce7272,fcff02f9,bfc355eb,24286fab,88ba08ad,b15e099,22724b84,315be56,88f98fe7,62e37fdb,b72c1526,59528cdc,fc4c4203,c465e772,38dc8618,78a5a14d) -,S(77935c1,3a7f5f47,13098101,6e10ec54,d5ca10eb,492d4025,365d5265,ef7e6ebb,3c15e7c9,cf230340,44444126,5e74456a,4f3b72dd,7aff0ac1,aa76c67b,ce77dd0a) -,S(b37c3ecf,5813b5a5,2f52fc4,42049653,991d9241,e8677d2a,f9779fda,43c7a255,4361c742,c070b356,387fef42,1a9cdf79,58dd47a0,b7c9add5,57fa425d,626a1786) -,S(90c64aa3,28d43534,271e2f37,3460d8af,d17f9585,516b909a,6a7bea2f,1b12d2c6,79394191,a37a451f,e439e538,5e876c2d,ac397f0e,dfe29114,d14b9363,b76823c4) -,S(a314f637,2362ef7c,c4bec6a7,9396c318,568d9f05,9b6ca38a,c5f56090,c33e5e5e,b3a401e4,f7741130,95179507,2ce3b0e,53d2f51,f2dcaa9,d289e25a,8de01519) -,S(15c25f4e,80a7de90,8c49fc7b,649afd24,4c5a4be4,dfc15b2f,70099f73,6ad003dd,4aa9fb98,39855fca,c9f8bb26,b6322c95,e5d7adae,5aca9bf6,de073949,eb364b86) -,S(445e6d34,90f4ce76,22b6713f,584065a5,e0998d47,1b7603a,2527ed85,5d67d7a0,ecf994bd,7ba618b7,6eaca0,b852e0eb,be7b7f86,70d028e3,f52d1b2,846ce8ea) -,S(def695be,1ded66c3,650e9918,e942e4c,bd420fab,3a4708c2,43ab4e3f,1bf2101b,63569e13,532bf299,a0cf8d0e,a4addffc,1e782a1e,98a2f7c0,e0b64f50,8dd0afc5) -,S(eb364f1b,89938b48,2d32271,551f9529,5013185e,3ee2b534,bf01a288,9a534a88,9e6091fa,b439d0,d96f6a9d,cb468573,881234c1,6bbf4c50,32a6c950,99e6e6c1) -,S(7efe80e6,5c0134b8,49b6c58c,7d4c54ac,873e43fd,1b47f9d2,1d33f9c8,ee26646b,5411262d,63357cc8,d8280243,41d1767f,c25a0972,4c8c7a7f,3ddf6701,d12478e7) -,S(5f412876,3774e9de,6f2f25d8,a1d98de9,edf959a8,884643a4,fa18ac7a,26d6308,d3f6eff0,e336d4f5,abe35a12,4c47ed4e,5dbbe6d8,7d563fb1,8ea89242,aa454411) -,S(c63e3b34,bafd384b,2b60328b,4aee3a28,c7b3ed30,8a7cde45,87aa6c75,6c49c2dd,724fbbfc,11d05623,a5cb449e,a2f9f65f,a3de167a,a811bfcb,6ab9c3d0,3b123ad7) -,S(cc92795e,a0be5e79,757a86b5,147429eb,ca7a7c7,d51a8d3c,93650178,4f6ba5b5,92053ab3,db369d61,3af1093f,50829c73,4618c1d3,610ebc57,420d2824,935ae2ff) -,S(ba73d310,b5170cd1,57bbe14,63bfe944,ce7cea80,1b1aedb2,da3db11d,f1c7ea5c,4114e55,15806ca6,323edc6b,f0b75a92,834c72ff,9579d1f2,27fdadd6,d773c577) -,S(6047bc6,fd3a1c7b,9a36036a,94139542,7d9432c0,f652259e,1d52d709,e5088b22,bb119bf4,5d8ac9bb,1a918e6b,95cdf23e,6e2ccbf0,171579f7,ecfc9126,6d236b8a) -,S(a0600a7c,484559cf,3da255c4,935d2d97,1628fe8a,e75b88bb,1f3c4eca,e68f78d5,a439ac58,42bc6ee8,be096973,d87598da,349929c6,92e37852,e57ac941,eedef402) -,S(bfdef77e,1efac235,c1c49f04,290f89aa,c2e4632c,85f40481,dfdf5c59,d479e2a,e6e451cf,d76433ab,1de85511,9abaa5c7,8e4499a5,fa48ad77,f098c825,206dc7fc) -,S(81ff778c,373975,fb041cf8,ce4bc337,e2c977f2,d6bb2c61,9122240b,8e21234,3fc02add,e92c9928,e94e0ad0,218d6204,d71ef295,4c32227d,96b30b5b,9a61f640) -,S(84c4653c,d1af54f3,fc59dab4,5bbaa470,48f8eb13,4afc8f5b,60a8974a,cbf03933,98ff808b,a4682139,68b73ecb,67fe0a32,85dace7a,19d300dd,bd517e3d,b04ddba9) -,S(9d7ed86a,69f39ecd,c448de07,55197029,f81ee886,7c9a61b9,62d13eb3,abce35ae,d9b27e39,41c6bd1d,87dab6e9,32e8ba57,1dcd2c58,67177ce8,e7ef0fdc,668fccd5) -,S(540b7fe1,ee263e6b,3610bb96,1071d817,b9cdd162,77aaf28,87e7e5fd,df72f5b5,6638015d,591305c1,7a598a44,ba6871cb,8d1d3628,3ea25c5c,846bab2b,cd910340) -,S(4799c5ec,f1fb2112,f479abab,217ed0dc,e936c6bd,14215eee,6bbbb34f,d811cbe0,abfdeb73,4ac738cf,f607cd93,de58c0a3,237201eb,da47a808,3bccaee6,da5c5515) -,S(70a58362,b360c280,626a8698,7e4f2aa1,abdc9f8,f0b8c216,bb88b0cc,133c2312,5e37daac,d2835f3,1d924659,e51858ab,68e3a874,947360eb,c520767f,ce4d46d0) -,S(f345a0ca,857102b6,e225dfc5,7ae1cbbb,dd5c2737,116adbd8,b3d1f74,7d132b01,16fcaf2d,f7cae2ec,ef25da7b,3d51afd2,8f5e9920,5c0d74f0,c1e7b360,17eb2fb8) -,S(c3f4282b,29f253d4,fae8deb7,941484e3,9d2555d3,f96889b4,551e7d8a,eb2a209d,fc562248,8a6e83f1,6bb1530d,2a35629d,b25c8280,2eea7057,d22d109d,4263ac1d) -,S(5542218f,606e7cf3,9cf646a1,3677b0ed,4ff61aac,1dcea3f5,da5dd4a7,d4727632,f1bce63e,a11d5176,f47e576f,66817f45,4b51840b,a79695e6,3a1a1cd6,fb6c07db) -,S(65e81ed2,7d6b839e,5c3829f9,24beda63,98264de8,b2223479,43881582,4d124b35,2a17e09c,e4dd6e6a,32d85d71,e6cc2378,b53b9356,ee5790f6,8fc3040c,e6b6179f) -,S(5066b022,e43a5f83,c4290064,9e2b611e,750a5ded,7c89b8f5,892126f1,e112edf3,381e92b3,e407c6c5,d1c0ab40,6fbe1a99,57643da9,a2118cb1,3b8c6243,9328d9e8) -,S(8df78ac5,c5ff1cc6,df1e1dfb,58ef889b,17886433,61bea73b,a805c3ae,a83e2373,dc668ddf,5b39eebb,7b692997,f22140c1,8347e14b,edb6d343,96017e09,d37ca4d3) -,S(426c1767,7d7b00ee,af8d7d30,1bb11cea,1cebfa58,fc54bf0f,de719937,fb484434,4fcfa5b9,ab7b71fd,560ecbfa,985db2f2,418465f7,cbf8acd8,fdd71af5,7f9519d8) -,S(4f7f0061,bb90e396,63f6aadf,70dd3312,f781b2a2,3867df3c,566e18f9,b4a511e1,1308473f,d8956b35,97d904c6,cf73c05c,fd7c075d,c83848b8,571e666d,dc44b3df) -,S(7393002d,d2e85925,3b23db69,6c140258,8272a847,d834982c,5b22b256,93685107,b61532fc,6706f7ad,78548e76,b334a836,c899a49c,46afa1f4,4579b5cd,27641528) -,S(c41dff65,e88e5c6f,fca3b0ab,6ae69bde,c4215194,cd7c57ca,fd9b38be,feab4e05,9a9ba27b,a0b7e217,d31340cb,acd8506,7f052d8b,f92a4be1,cf59fbe9,6241f0c9) -,S(f619dc9d,6dcc39d2,9155082c,2ed9bc60,99296a8a,982327f0,60fd6208,5765c518,87961d3e,2b850ffd,f080d5aa,cceb1912,120ddbc3,4e0ad8d7,96e74afc,aa4871fd) -,S(6becdd5d,f02a7bbc,d1cc811c,fb83901c,46aa8207,35e81c29,a8d4d4ea,3f5cf99a,a45f7dd1,8949f842,2905c7ee,836004a6,5bb106d2,fb623d68,c2690c14,f181e39d) -,S(cd2390,db1e7c53,f424a893,c2529660,69a8f151,6f60722a,524578e3,e5427196,b817ed1b,457633ab,a3439454,6ed410cd,8140b9d2,e7e679b6,3322eae5,f3466e90) -,S(96cd9608,7f1cbcc9,b017ad2b,c7824285,4047dc3d,f98e7951,2fc09fbc,e3cd33ab,dfdb9090,c8a5ae70,13b8faa7,855554d7,3df381d7,88fd5569,d3a7ef7d,f729d625) -,S(99cd7508,5e9abb74,5fe03e3d,b100f2c5,2a43acc9,4127bd8f,83314baf,70d72b4a,19c98b68,2ded269a,57e50e3a,28b9cd65,344000ed,dac3d3e9,d8ac8370,662ee1c5) -,S(f53c2afa,647496ac,6c1220e1,4627c138,186286ef,b776449,55f9238,b39fdb20,1598c495,106a200,58fe1fd9,b29140e6,a93996d4,fe4cfdd6,74ec10f0,75badbd7) -,S(c127dad5,3b9457b9,51192c79,5793734a,d0a84671,ff6ba236,f53cc40f,769585f8,688e6264,da4e9d1e,fe66f5ab,db078c56,98696ef3,53b3bd42,c344b3f1,3d3ad744) -,S(882bc4c7,651634c,930384d1,3daf5a91,41508df3,2d34818a,e61bb65,40e92bd7,5c456414,430eece2,fc6e95b3,7700f608,9815f5cb,12a09ebe,8a87e370,85bcf255) -,S(4cbc141f,55c0b001,cfd934e4,dbbc2c2e,4b5dc68,72e3388f,2388e54c,e2a91bdc,1749d8e5,30d21894,221b2aa5,96541f1d,e700bbc1,e3427140,24f0a9b,9c0766b0) -,S(bff11777,6bb9bfd6,bbf872a1,3b9b6a62,32465cef,f16c3c75,441c39ea,2975528e,9e7412e4,ae492669,58dbdc9a,b7b1f4c5,d2edefc1,d4f0a483,27f2fd69,f992eb34) -,S(251416e5,887b294f,c752a1e2,3e991f11,90b8798b,11c97033,e470bfb5,b7bb6328,e6981dcf,15fb4b98,ac8a37da,267f1bb6,a2a38b86,3919d20f,72b5bc34,cb5e329c) -,S(bfe2490,569255d1,a62318c8,416e9114,66dec59a,bcca5df4,e64c2f48,46d050d4,f78bf673,577508c8,3846bd5a,312b9284,2283c47e,d4df7651,79d33bda,ba6eea54) -,S(e50d0a78,40779b75,fa121def,456865d9,3d7bb9c5,d566d790,58b1b56c,3fdc7b15,2f2688ee,4abcfa52,9424d4cd,eb40a8a6,a6de26b1,be8946f1,e4ba429b,5b32a6c8) -,S(b3a9d7ef,235df6ef,262e177d,19bd1121,167a056a,3957ffd2,a3d22d00,9a199bab,6a7adf,40ab5386,21fc3447,77c97416,66537460,44113c5b,a73455bd,9658753b) -,S(ec7277c4,20af5d48,3a6247d3,a1da7243,31c0e35a,85d6057d,55a3e526,bb7962bf,2dcd3e8c,5abc47d4,56bfcf,a8086889,89354e10,8188fb0b,c9ab4578,7b91d69d) -,S(91ed86a2,330ef91d,e085df2,a947c9de,f1284b8c,76d9b432,8dee9342,bd297242,fcc226b0,c46a36f3,ac56ec31,bf297360,8375f0f7,d248c669,f8b31ca9,9d056713) -,S(e2a09eb6,6e76b287,36c5824f,829afff2,439d973,e5be5b4,f3c55cea,e83bbda4,6b217b22,123bf3db,f35845f,315264c0,4a67ba18,a49abd08,6b2acc76,ca0b016c) -,S(78501449,bd76ff1f,58cdf2e9,203de4d8,3325ce45,1bf106d,2f474e91,bb0545c1,d0bbcc92,acbad044,218a830d,5f461332,cf488003,4b6f89fa,2f58b708,63aaa585) -,S(c3626c48,95df6e93,2c79d5d7,eac22ef1,d7679f1b,1df1259d,2be08aaf,7217d978,a594df74,250bcb50,dd9f294d,e7322b25,f72cf935,700856e3,c31fc5f,35e61b67) -,S(5c6e0358,ec09945a,c4240f22,3304f744,63269e16,c4f87dbb,99bbb744,bb4afaae,e6168dcb,d719ad05,8020dbc5,b03ec4c0,61b1fd87,d530913e,6df5d498,69e340d7) -,S(4a3fb364,d55fca64,4cc03c40,5a5956b8,a794718a,5b43cdf0,795e5d5d,5f79e7c0,4c4e0c11,5f88ef66,545280de,af9e3d59,3ff7d1ec,d8f20779,70ed84a7,8d660d28) -,S(fdc828e6,e305427d,c925de61,6f57e13f,5d0c8777,b538e511,49cdd304,1b022d05,de9e1037,db0dab0c,fedd8544,3b926a36,88e8bc54,7420b27,c65e2c6d,bbcb1662) -,S(6d70ad6c,375119a0,f4b2b65f,51257d7b,e73a8d69,ab944dcb,232b8fd8,e7021583,31de3a22,c8e8034a,d812a7d,234cad97,978aba7a,1c2996b7,aee623f5,858770e2) -,S(faa9dff,68f63fc5,7ca8c39d,8d950c2f,78a90317,c5d7f787,6ffa035,fcce8dc6,419b6c29,a7c02ea6,c8b7ed5b,c9b6fe89,1b3c705d,2ed2707f,3ef7995c,81a17de0) -,S(53d9472b,eb9a020,e84e10f0,1d5ed8c2,6219d24a,eab4cd67,dd30f084,8fa47a12,624f4c9c,64c02832,9b6ad395,dd51f960,41eeffc3,b3238764,57d21f85,d8c674ce) -,S(598daff5,aac2831e,21d5eff6,319e563e,3208ea18,e3ffe13f,2bf19444,73292f02,3db66869,2538e2f,e3689a41,dbb05504,bc86dabd,e033fc1,dbd7f84d,dd4e18c2) -,S(eefd321d,41fe6468,a7766276,5932449a,d3956209,c4c6a548,c4392db9,b4e39a97,6a372971,d5515d4e,c691b3cf,e73ccf6a,a491df97,570c9f52,3f29b108,c626c319) -,S(5a3a8225,49ecb78a,9c5aa12a,49e02c5e,10c168ac,e053f85f,30921724,96177ee4,482a65fb,f57726d9,d4ad61c6,75cdd5c3,25b6e59,899366a5,3ddbf239,96016448) -,S(e21f7d4d,b2343eb0,1d23d1c,5ec76db9,89e1e624,2fabc41a,b204ca64,838eee55,fb64c87d,ba7c54d6,f1d68d7f,a49d50b1,bd79d699,a75227e8,4363ed30,430b2605) -,S(fd688c92,f80983b8,496689ae,fcc0820a,a3d91fb2,aa4d599a,f48de5b0,98ed491e,7f946da9,9169612b,dd6ad8b5,d686052e,3ff25610,21432c92,f8728187,29e860e7) -,S(65594f34,947f182,bcd1703c,dbb1ddbc,4bf59b2c,2fff23f4,1d363631,cd54af0f,e8d98a21,a603eabe,cc1a1b83,9ccd553e,fa5eb258,5dc94e10,d134f40a,63b5bb1b) -,S(4f47f3b9,8bcf3917,464c07cd,be99d2ea,adf31166,8199324e,d120d087,e14789e7,279da4fb,d718e578,b10d316b,9994dd05,ffa05431,f85db2d6,6d4327d3,68aac28a) -,S(32cd8b52,c027e4e1,7991ccf5,6460f3dc,1d2ea6be,6434067d,bd4880e8,a09196dc,1d3066d3,76961716,1882da20,e467e035,4ad84041,f391a042,9e94d8a0,5d89807) -,S(c454b400,c7946f9b,b35003a7,c51e8037,dd03fcda,f0a19b14,f8daba3f,310d8bec,dffa7652,86aecb65,2744c9e0,21229687,1c305d91,6279b414,1ca1a,acc021b9) -,S(151b7159,4fce7438,2ac83025,6d98abbb,6ca309b6,64ef0235,53495342,34f7b4f6,fc61aa0d,722156b5,dd7ffd24,38100589,1bf236be,a41aff71,c3f1964f,15978a28) -,S(59716aa9,6b60ebde,848783d1,a686e9ab,e337b87d,104aa3f9,4cc7af46,ea8b8710,2e3062d4,a7d290eb,f53ee38,31dd8e80,354fd671,62a01a4c,73c57fb3,4582d345) -,S(81838542,7622429e,832e7a50,b1a670e1,2a626c3b,97cc69f7,abaadd5a,44a92395,18a88d63,d42e3ba2,af4b6c36,9971b0b9,35363e5d,77417116,b58de2d,8b6afb42) -,S(c95cf1fc,af7dd741,479a54ca,40a0e264,a989f0da,99b3a1b3,c4f67284,c8ae2a75,14b32e26,99662bee,51ad8534,fca1925a,a835cd00,9807c5e6,915b8283,63872f76) -,S(9362c939,ea51a649,2ae2dc2b,c01e4bfe,ccdf4612,97932668,2435bf44,e9c6ea1f,944684c5,2cb534b1,4871f48,41e889ad,933299bb,474b392d,a1e85ffc,5763c2e0) -,S(8852fd51,1e5f5e93,c6c3c7b8,4b0544af,cdb7d0b8,497d4bfc,90cb7322,28a77040,b0ea5bb9,c338a6de,7333b4cf,ac29f997,36c248,405facd2,6ce438f9,cb997a13) -,S(59105318,491ab266,2fb94506,532ed81b,74c8f82e,a13581ae,ef6c0c77,80696ad9,3417191f,bdcc1dd1,43323ff8,6e6051ee,921dcf69,9eda369a,afec66ff,a06097ec) -,S(c78bb701,8e96901d,3f13681e,ecc24df9,65b124b6,43f72904,ddf00ce8,bd28a127,ef07ce8,1b9c1cf1,26108dd5,f96ff86b,e0d49bdf,ad3d518b,1004b3c9,4c79bea0) -,S(9eb55ba5,2b5d11ae,3d419ede,5a5480b6,c2aee921,6f9aeb4a,96e51934,e8e4c11d,50094963,25b94022,2642ca89,1fb4697a,5e643e50,19670934,99937432,f020eaf) -,S(79ca2986,d40c7786,dc4d3e6f,71c33233,ad0b65fd,96822383,c11949f1,ab42f5e1,275db48a,fab1f0db,188e1298,4b391ce,6872e216,85c04c0f,3e62d42,d1e6d310) -,S(a2cf65b8,fe2a7abc,b78bcdf3,f25db18f,432ada89,1ce7d99f,faccefe8,e9673463,418e9be4,f6a1dce9,200823f0,5a6a0e31,7924a0f9,44c18b2f,1602a2fd,1ef13a72) -,S(7f6881f3,9f4684d1,3bf35c4b,c350b64b,28eb3c44,2adf05fb,c5e2c1e0,307fef19,20ac47a9,b954e805,db6fa20a,4e1a04f3,36c058f2,1946aff4,d4c24f63,6bd608eb) -,S(abf40dcf,72704e6c,65502d17,aa384bca,5834a802,62ec0de2,fd46ca2d,d9316ef,f605192b,a8c56b66,f3bdb35d,9c1df4d9,94662b41,85e8e6c2,9fde9d27,45039564) -,S(4fbb0d5d,ada948f6,2877c665,9cfe5f57,c6d5be5c,8cbb7bee,71cc575a,f4c92989,d2290911,45c718d5,243e1ef,92b8f7bc,2c77af95,f8666ce8,15900462,35d1c3dc) -,S(6c62710d,d0ce5eb9,5196e202,7c3c1d12,5a25f329,878b1f38,fa883146,b8ccffa4,c70ee1dc,174a6a4b,908b54d,69c94ec,5829bc8d,f6513c82,b0fc02ce,f566dde7) -,S(83ac175e,e220c800,a40adc87,df8450a3,963015a5,2c9e9497,602f930c,37af6c12,b7dd932,95601178,f6db7b5f,98046d7c,e42371ab,34e5f11,31f7cb31,59d37994) -,S(c823727a,348e275b,f52c18b1,43653c3f,8f0a5c0a,e8f48432,a8016486,ec3674b5,760237f6,2222cf21,fe1813da,4cfe9437,edca8286,cf3be63b,5bb05560,fa71235f) -,S(388b02ce,506784cf,2ec7e315,e765f126,23f764a,7d1ef836,fe360355,cb3f0517,ed0998cc,9069f336,c938b639,d6a74e8c,672a7d2a,2fe1dd1a,d7e18969,e7e57b20) -,S(517d4da9,e25f9eaf,7ab6efcd,cc00e6eb,7bfb975d,e8287b2b,d7d15914,4b7a981a,2ea7196b,a14b60c0,78444a20,2b67fedf,8fd119a3,7a39738b,17694cd4,c0dd712d) -,S(eac89275,54b0f71c,4ee80260,4945c5e5,578fdd50,ad68c478,2295670a,80432bee,dfe1ac53,dc9e18b7,1a930e73,cea36af2,8c8326eb,3615f858,fa1d3884,446f59a7) -,S(f77a0877,e7ffd2e2,cba9f0b2,c419e886,73711125,7cee4480,f6529851,6013ce29,fb245db7,29acfa2c,145011f4,42c9d480,5fcb0be8,b7f27dd9,9d532f6,aee2d57c) -,S(747d96af,94b3ae3,4cbcec25,fe8f4b74,e8d2077e,31ca2520,6d0d5613,3a49bd7e,b13d780b,8d322848,de5463af,3dc9c6fb,4cee70e0,da4731db,14916252,4b6d8d4f) -,S(9bf6ae06,6db68c50,4ef9b1cd,6d123efe,1d8608c5,3a1a2276,f1f44493,f8b5bf72,5b0080f7,694a756,f306714,aa9d8b3e,617b7c5e,84d862be,470df13d,e79c8994) -,S(91d0275d,e99c876b,d6de2cd,481fd72,13d9f6f0,e41c3444,4790dd80,cbc72e72,b12126c0,8b03b040,60183216,d1468246,d32d834c,57e687a8,9ce42ae4,d4eba7bf) -,S(e3cd4480,6585252c,8eb09442,74222016,5ed4cb90,462310ac,ddc769b1,b9a111e2,d8821a94,f1bd3def,434557ed,4739d625,c74548d1,44bd370b,180fc4d9,ee04afa0) -,S(3502269d,e8a68ef1,a0d74a0e,1423de94,99b84d3a,1fbef636,d9f38801,ed00d64a,9c4b6259,8c1bb627,449800ba,d9e93c7a,265114eb,99f9b5,7bca5b6a,72e3b302) -,S(244e51da,a54a3c4d,69f7a53e,6ef82bf4,7907bb40,7713f5e8,84694641,1daa2ec3,61f00ad5,f30928ca,a20cd38e,5af6b3fa,afd4def2,f8433609,4f08e82e,d46a0320) -,S(4f00186b,5d6f0420,88ac1221,a13e3aa4,60190cc2,2bd8fc26,4df81f44,1e508032,fcf58149,b8ab94c,67b30d73,4a3a5835,c7f89e44,6aa8d2d9,291c5f6c,b17b2e3c) -,S(10a96b69,2f522f4d,58d1c9af,463ae371,73e6f72d,93aaf756,6267b3d2,f62a579c,fcc7a656,c9d72dcc,1540a638,51328135,85d3a0f4,ba5242f,f5aa35f1,88ee3070) -,S(ee66c2c,2b19242f,4d7a22bd,df36fe3b,b5c151f7,1dd8a81,93fbae52,23064f9d,9d4f46db,7639d9a6,95d51d1e,44b08d6b,4791e443,744042e5,cc9e3933,cc27aefc) -,S(872337c4,e34a3dbb,f4b274a0,a47c1398,f78ce842,fb11b994,b550e9e2,e21934c2,aa8a7840,d6dbf62e,d91577c8,8b8c6baa,69e01f94,5294e3fe,4ccbadc4,c1d64221) -,S(e2eeb213,bfeb413a,9093be1a,7f75820e,5f48dc34,8515ef1c,7026c116,9be224a6,a49c846e,9132e039,9d66da39,57cebf1d,2e673831,3a89f682,c28d2230,1792d36b) -,S(fe264a9d,63932bdd,5cd4629a,dda37c9a,8d2bbb1f,5809d333,80a561a9,66af74c5,543b7920,c6c27b7a,515b5adc,b8d144ae,64118447,dee21638,1d6cfd2,5627fc53) -,S(13806a30,2d32152f,a1ee8060,67b07cc8,fce1e67f,16f21859,e7b60de1,37debf51,ffcb1150,7be5c2a8,90237923,5335b575,4cd83460,423ece53,18be988,c7e5e978) -,S(db67e361,f9d91cff,1d8b99db,b7bd2584,f1b91cfd,77473802,f603ee9d,debf4dfe,6407a133,7604fbb9,35fbdfb,9fd6e2a4,ea6d8f28,a63e7524,172cebfb,d3331e2b) -,S(606d4f47,d1d4cc58,3e30f214,e1ee57cd,98e68b6c,91c852ad,cad6c32c,989d8bd8,81911891,8a074dd6,ebfb95b1,c97b4fd8,5ef0887c,15ae5e88,ec6e97b9,cba46701) -,S(51d60942,e93fbcf7,e230c116,77528c0d,3b63f7ee,64c1da65,692aa91c,af482ecc,b82db22e,3f104807,6338369f,d77dc11,d982296d,e630af66,36cedecc,108ae433) -,S(2553006b,b8474473,29108ffd,cfd9c91d,22b7ad2b,6a0e7bb,72f98a0b,770da376,6173583e,e6b238be,ff3cd6cc,9bba1b48,d89dcf6f,481868dc,773eea98,59ffa871) -,S(52e35836,fb0a1c1f,efb092fe,3c95bb32,26bf9aaf,50fd1ddf,29ef0ba4,b100d794,639078d1,cd1cd22d,135ca950,d754d3f2,bcd11a95,91abb6c7,c4a5177c,53adc86f) -,S(332e02e5,5c089c84,82ee9863,a4dff4ea,b01a7a83,4747ff83,512fb567,7a8ee3d,b1edbfc7,9c1f9264,10c4cc3b,8919b4f4,e89bad8f,34135af5,f16b1c66,9a28b87c) -,S(d9113a61,7d5a4a75,2080931a,84bad37b,ce2f907b,cc05adf4,16750e8b,8951435a,ab1f66e5,8d3a5887,2f664b56,6c2468df,f9d4d76c,a73111bf,57e10d1a,f7df7aab) -,S(71999a85,799030fa,b0575523,fab4111c,f4b60351,e03f8703,1f5a852a,f22131d4,eb171070,d6124255,9adbd82,565c8dd3,fba6b8c0,df939501,4223b2e6,148668f4) -,S(a9436d74,a39c7193,368ccbf0,d24098be,41309668,87ebb8d8,4213e0b3,436c23cd,7b93ba5d,e2ad9b42,ac45ac85,43f7ae59,7300e745,8fed1359,bc392015,540e7a19) -,S(f6288f25,57359179,cd3659c6,1cceef6d,c5a69631,174f63ac,115633ef,83530b2a,d54f0f2d,51a365dc,7ba8b630,67ae663c,b4102e2c,59cfa616,b8878483,6ca85722) -,S(bf685c41,863c9fee,dff2fdd4,ba47d726,1f0fcb6f,b0432a8a,3b7c4f6d,6f52700a,336b1d57,43ca6d28,52e20cd6,ab276441,61b2ed82,ea4e0051,d88ea92c,a66828c7) -,S(672eaa18,1009f3da,3fe74eb7,4b479e24,4b73b54f,206f7342,eaa865ee,f945b00f,3f056594,a113cd63,810adf1d,b76efaad,babcd42d,347282c2,ce66ad54,37cb89d0) -,S(299deede,3b6722e4,4c5e7600,214f85aa,4dd70ac9,df75cfe6,c020ec58,c8c859f7,92ecac9e,4a6326a7,8b01c0e3,6466723a,3d00593b,6597b6e,e16924cd,60105137) -,S(e4268a68,7e6c26b9,2cec18b6,8581bf03,8b25544e,2040d505,7b9823b8,b01c07d5,35d1c370,95a9cc03,f91db5d4,250a904f,b9f9daed,9388b5cf,d6a3699e,b03c30c0) -,S(7164e9,bfa6ade,a42bcc27,db38cf5b,fe908499,eda21bf2,27063fb6,369b1ae1,a2367f94,fe683e07,1cb7ffb4,287cce88,b11336ca,98e6769e,178262a6,b9103d9b) -,S(84d8d32,a4be7402,1c94d3b6,c0913724,b2db26fd,862fee1b,c467a37f,b98b299a,46b92145,46603cb9,1cd5ff05,a237079a,e290b496,19d868f2,8143d660,94e61cf5) -,S(60372ba5,d0eaaacb,c1445979,74a0553a,6e63c4d,15001b76,39f5d05b,84f626dc,8fab368b,c4d011aa,edf7d98c,2e6a0359,5737b1bd,bf701060,d30c9f0e,a8e8c847) -,S(453c17f5,5364f812,a7da0f75,d7c074b1,81cc0901,a938447c,df55ba92,a7decfbc,53d465f2,6d3d86b,a76ad1e6,f147d208,474989a4,64ceb6ce,79972cc9,3e2e2c3a) -,S(cf1f79b4,b765a894,2b967271,85d0c2c4,dfab4c4d,d679693a,4b35b343,c411cdc4,b89916ea,4ea34abc,63b9292f,591b5c8d,5ce802df,9d4f2be,275ef244,7e1ece) -,S(74b07994,b7fe3a27,eff2f9aa,72f8746a,299f9eb7,81f09b15,f3ae595f,a0c4ac37,5464345,f4873a6e,9f4cb569,acc8e551,a9acff9e,5e0a92ca,e2c3f800,1888f905) -,S(f9de1544,89b7a06e,40115de1,fcb7897a,f6bb2b91,5a1e8971,8d5d5ee8,68bab74f,789b5c55,2b352db3,4345ca30,328f542b,ad22e5cf,d98e5b8b,e85646e8,d47a0e6e) -,S(c011f3d1,897cfe72,827d2cc7,c04a6aa7,496273ac,11f0df10,27ab4d69,aa745c5d,8e31fcd8,3842ffbb,a600e771,feb0cc2b,1fb257ab,7c19fe61,67802313,cdec95ad) -,S(16567ed2,4ea1cb2a,15418d66,c70c0587,386201f3,4dde86b,82f687f,95229648,fc4aa805,45366f8c,3ee336f4,51397e3,7f78188e,b6dff3ce,d80c7e7b,6d9f7cf2) -,S(8cd33d56,9acd3607,979b3c17,bf5c2175,ef6f3428,7a25c18e,89a1b38c,979d50e,f4312cbf,f301e942,61b7da0e,cadda424,336b1201,82ad73c3,c907be8d,840f8614) -,S(646e22ba,39927176,4e1df1b3,16767718,79d7a16d,587b9e47,5232a331,42ea2a5b,55378afe,5f29feb3,2a3152ba,4d83305e,f77b1025,79154aeb,7bb8b8ef,c5958576) -,S(2699d984,462e1fa6,208a833b,8af2e32f,58cf2d02,7707b4fe,2e3f888d,82e8e2fc,ed6c46a5,c5121755,5f236a62,21399a40,5fd87fca,f4cc6603,fffb440d,54b888c4) -,S(be4b6631,3fd3e2fb,163530c7,2fa4a41b,e36d04b2,638315a9,1d07de72,c4ced54c,a7a71077,83a27b72,4e8aa644,a88ea181,c770cf6f,489829c6,6660c44d,45fd2ddd) -,S(1f2ad69d,a1438b51,fe02a47,9cf865e2,18bdbe01,259b0818,1b6e7e6b,762a72a6,d4da99d5,7aa328df,3c587a45,2d756bae,fc09c626,fa5516bb,c8781b9e,b1ecd29b) -,S(b1adb241,721a1622,35540622,f8e84291,e1c2702d,70cad33a,89aa3806,f7acda43,e6cd9324,12542fc4,25b8f16c,c0820f3f,26f33e11,1ba0ca5c,b5aeaa54,1fa3d9c6) -,S(b604e2,f06df266,1163604f,2a1941ff,4d6991fb,84796c40,ccbe74e4,cf68e207,306936ee,e887427e,6005b265,38af5ca,53b3cab9,a3aebaaa,96556c46,7db96e88) -,S(afb935fa,1e30617a,9b4f26b2,e7b150b3,f33566b4,7b5b4a7d,6223fe3,9c0dced3,83624f43,66dd82d6,8e4cd94c,464b6322,db0b1774,9fa1125b,a0944503,b0c63b0d) -,S(5cc7252,a08ff892,93022eca,b56a5e9,cd2eb4c4,71161d15,5d7a5113,8b12d235,c272b6cc,42461529,b31943fd,fcb51a59,7a0eaec3,ae8c2754,827fe1ce,a182bcc4) -,S(6c17c206,7c72a1ba,410f2446,e4ae2012,6eccaf88,aa4fea14,522a7607,143c1122,7172af08,2adea428,2f6a3cbc,7946db2f,c0170975,50ad8ee7,f4c514e5,dcd693eb) -,S(fd82afcf,c55d226b,274cd62f,385e882f,716210f,9a14be15,baf7e17f,b98eac8,4aeac666,a1153851,6d66390e,6c7818d3,3de26fa9,3d234eb8,5e4d5b42,853eb3c1) -,S(3d0121e6,c758dc91,8ce3bbca,1884788b,20717075,1e80742c,49b202d3,c2f8012,ca6b47b,306cef6c,662bf21f,77bae3c4,25009561,72dfc630,e2b1a6da,e733413d) -,S(488306dd,3bf3bb5f,24160f1d,67b8c053,bceb8da3,cb1b05ae,7ae9fa72,e3f7b0c2,2356a8e6,77ae2f06,6135bd88,1fab5b4c,6aa57769,3e2d476a,1b2a4db7,fc6c27be) -,S(d7e91488,6786009e,eaf12d14,a23ec6e7,fe41e406,aca5a5b7,47010ee8,8441d6b2,c98389a9,143a8fdb,df4a67d8,7c05cd4d,fff75fae,845e7e62,26c61aff,3dc4dde6) -,S(873a2877,9c45280e,3d196725,5da756d0,ee5ac567,cbb7c52d,c8e654a7,ed78a1f1,9bb9672e,e76feae0,d52be301,983c182d,ec99b228,defb2166,5310a4ab,cae7eccd) -,S(410a7c98,85f531ab,46d99b26,b6fc2576,97723e4,bd9b9c57,6544542e,2cad2ff3,8bc9e686,4f139032,cd443148,4f43abd4,3234e3eb,3825a0a7,db8176be,cb5207cb) -,S(39269060,b38b4abb,107c2230,6f541353,d8627901,3399b368,8b650ad4,cbf99144,780c2949,aad303f,ef8fff3f,b9734551,b45639cd,9437935f,d93f7d95,bc9d1aa4) -,S(bbc52d26,36e861e1,3e593d4a,c6ad573a,e4698ede,f101b3e4,f4aaca54,325b9f9,4a311f44,9f16bfb6,4c5c554,5ba373e9,fc41b7ec,beadb4a6,a929cf0d,79f37922) -,S(bb74e659,5ed6d931,9716b8e6,120f0cb0,57dcce87,150cb26a,cbdf5b1c,f86ccbcd,9f2385a3,bb460cdb,8ec74db8,fc5e6014,f4310665,c5b69e1b,cf96203,1afe085) -,S(67e64d65,badbd97a,bb204cb4,f9009f5a,973700d8,34f6b6a5,395fbaa2,c6eb0672,a122f76f,67490b28,9977d730,df544f7,d725dfd0,93135ba4,4bb348c9,e4dd3303) -,S(dbd294ba,e0775f43,f58ee677,6240eaca,b9b29ceb,92fc3354,de4d4b20,95548050,1987ba2e,3ce8ef0,5b71acbf,4c69f706,e2cb4d6f,354f0fc6,53a7a9b9,5dd1c115) -,S(45c946f3,93658d3e,589fdcbb,6895c97d,60352342,3a3676df,680b6bad,de6cee1,629c7238,db2cd3e5,29e5b30f,a8ba5629,dcbb1ccd,ada1eb22,294f98f0,4cae2d00) -,S(33ad0e14,44be7775,3fe47875,2688e384,2be7ae06,7d38e473,6b7dbe0,c106e14f,d89eed78,6518775e,1ef441d5,fe51c4d4,b2a1e377,eb1a4cf7,804c2e1a,5175f1ef) -,S(f9f78161,4cd463fb,6e358274,e47812b,4b0113d8,3f426aa7,85756c6f,b9e7853e,5eab09ab,51247c76,f87f592d,77e0870,238877dc,a47cf6b4,5fe72940,ff4469a2) -,S(ed3015a6,7a1fec82,f0f7a59c,45cb69ae,8aa0d883,39a05f,f6959c9d,b7d761c5,b7c94a9c,28389f1d,17bdf197,307411fe,1c395483,da8a097a,fb3b5fcf,e392e16d) -,S(301af330,de741ec5,61b71fc3,c5048a42,6b55d58f,800934f5,c59aa8f5,914092b0,3d3137d8,262d196d,872fe1f9,8acba295,fec02ee1,30aa4c19,8c888765,357b67e4) -,S(21e197a7,85953a90,226c1ab0,441e35a0,fd8444b1,92c0e5ad,65588063,f40c1246,6811f94f,18a9569d,4df2ffa7,fd8d75ff,5f66ad1e,62da2a60,c0084381,4437a2c4) -,S(325fcc8c,27804b7c,e73d6687,70db7f5d,3ed4b6ac,feb04003,c61d6262,8fd41385,2110e8d7,24e3a03f,46183536,b208b595,8586202c,2e69b954,d3ee1500,21ae7d8) -,S(48597aad,ec69eb0d,90f60e6a,abf83129,1de759f5,eff24d81,8677248b,ea87d945,c3fd850a,cddc2597,499be90c,24e249b,328728ff,5443fbd5,6515a6f0,4111775d) -,S(58648599,8ac44bd2,e937796,d8dfa60d,c56d94c4,d53cfb77,ee0e380a,53ab8f76,2f47f278,6a285454,475d3c9,ffe9ee44,a93e15cb,b17772ec,67a30943,d3191110) -,S(bd2761c5,722288b1,409aa7a5,db7690d2,73dba76a,3847d94e,3e3d3a7f,2dd35597,42590713,6ab6745d,5e573412,663d4d93,29c4a284,4430899d,68e5ca64,197ad58c) -,S(fac9260f,1d420371,7e468769,1af8c270,dada5d97,5ceda9f2,64deffe9,1990b52a,9ce17c1,ebe94ab4,e092d1d5,850194d1,7e6a87e6,7b283ba4,ba68640a,94193314) -,S(82e65b52,e4585ec1,4bc03591,249cf4bc,e5391f69,7b813175,b3b4b403,a64d6877,627e196b,42d327be,48526318,2dafb37e,222578a0,ccbcc443,7941eca4,a82ac893) -,S(b9473eb4,dd002597,464965e5,b6d95842,543cd14,e18c95d5,b45bb654,eedbd6da,1b6e80a5,377ba31f,b5b6fcac,633321e7,f6e5b2ad,4a54e143,e963effd,6805c3a9) -,S(31113d99,4caaea40,40182db0,17a880ac,64b183af,1746b820,2f29fbd0,d1bcc524,3f476b72,eeeb7c27,f9d04cba,71ac54aa,a25ec4ab,15d77e17,8544a651,653e83ad) -,S(d04adc5e,73e21fc1,8c3b047,4d34f8cd,1cdcebdc,5dabf14,e258af57,860157d2,b21150d6,ad94a07c,d11a81c7,b741a2f0,5cd6a5ae,aba194ce,b874bd19,bfb6c326) -,S(4e59356b,f280f51a,c492751b,3b3c7c2e,3fd1fb58,679b4fb5,5abeeb65,bce6ac2b,33a1ed9a,1d9c34c8,42b95e4a,108c7985,21c1f06,91f3716a,68fa5c5f,89dc73f) -,S(53d76685,9ddc778c,b4f719ad,55f74fa7,85d52300,65c06b1e,4aafc560,39ba3547,168b5451,29170fe2,c53abea9,68a25dcc,2719090b,e0814635,a1dc7267,9d83a01) -,S(7e9107a0,d2830362,7e53e06d,6e82efa8,b1a037a,328df546,a6d04c30,3037a63f,222d8b81,2a99860e,87fa24e0,aaab4ddb,b903cbe6,39c46cb6,3f2144d7,f8856489) -,S(6775b2d7,b23dc08a,beb65049,db8552f5,565a092f,fad86865,c17347e2,a744106b,a6f23c87,fb639e66,9830ed33,34c6dd42,6bab0e23,aadcff44,1d4c73d1,a61efda4) -,S(559885b6,a54fd0dc,b275662e,f66566e2,87a17219,e9c02f68,8c1cc8f5,6f814673,2ec87df5,917d1d7b,f217621e,82c31844,d2bb138b,bc35f873,5b52309a,baf800c1) -,S(6fb774c1,2971b620,b40a17ec,74dccc9a,8c711844,a44a3e4d,e8310d47,bda53428,68ab0f6,57b823e3,35df55d1,ed9632a8,f0825f67,8a05d5eb,9e115ea3,e43ff4e7) -,S(623c155c,2787396e,815ecfdb,5f03bdb7,282aeda1,7c9298f5,306ec10e,21dd0b90,69382be3,a4bae926,47252910,ad1ec62f,f4bbcde5,6259cb52,10ff2158,6b111f66) -,S(c42c41e0,63db66dc,9b32c21c,af94a158,14fd5b62,aaa975d,3ca06925,f6d6ecc2,e93159a3,ad6fbcb6,38f7b09d,40601189,cafbe5c5,90c70103,b56fbd47,d36ccfba) -,S(1103e98e,7a1659ac,4242ad9d,6fb012d9,21696e58,413f71aa,e19fff6f,1c334fbf,9f2d4667,ce5a1285,524d91d9,265d7a5d,da9f5ea6,cd508cf5,90076d57,a975bc62) -,S(9e113cd5,9e7177b9,19859144,598263cd,630f72f3,4da00ad9,84964043,9d82878a,6a09bef7,6e13f2f6,8e70ee90,5dd5af4,495f5965,859a1d83,ef149f67,2643c9f7) -,S(c03c5ebc,d04bf8a2,bdec182b,32d8c726,1913652f,e4547892,3e0dba7a,1fe275ed,f567e3c7,4b9313c4,11ac9411,11f1b62f,74a16f79,e7d90817,b54d4d89,958cda21) -,S(205c4c44,7b84661b,cc8ab2f0,221343f4,140c9efa,fb107c59,b5095b48,25f54b24,94a10344,ac5f48a3,600309ef,8ef94242,a8050865,3c018e57,a7734d9e,da18a55c) -,S(e393821a,58c9e9c5,6e45cda0,334bebc4,359c4b3c,1a60bab3,f1dce2de,c1da81b6,5469cb0f,4edf5f47,80df616,3a6b7074,7b26291e,8830d113,79d84aa2,15814e6d) -,S(38fc36b7,a866b165,a424f0ae,74ca34bb,b05922d5,1bdb447,5df797ad,4d042e2f,a9279b50,4b3edff3,aa8fe039,3415c21a,556609bd,8089383f,f5dbdd34,291c2b1b) -,S(1c4a1aac,3c3247d9,99a75a00,305a4092,c5f34321,d3a33b66,b110331c,85be2b27,a10e4138,a835e3b1,16d7b6c9,46c752e8,dc92c39b,21677968,147a3cab,fa5a0f1) -,S(41d70c82,207c3b7b,716a2d4f,784302e7,e1034555,a79965b7,d951ebac,b7d62c00,7311a36f,cf3de546,37013e84,b2162c35,3eba0387,3d296427,220e5942,af398bac) -,S(bada1cce,dcf3dfc,9834c49d,200fb82a,b13cf2d3,d5da9ee5,c9c35448,352e660a,42e0d3db,511cbbe7,942ff10d,a7d49805,972d9373,a75545b7,206e490b,6c5dc651) -,S(233c0c68,4b9fe726,baf2b7d7,a0503e,7aba8b1b,3c4f28d9,4d095107,2b429bc2,a7bc02a6,2b81154,c3bce0f1,6a0b4f77,d412d162,1c713372,11ac1c61,a8f6fa28) -,S(a675f208,a0d48078,93525e1f,b6c5be3b,ef24ade,8d3ab14a,afac550a,fa6362cd,3f8edef0,3e0600fd,1fdf10e7,c5562ddb,af4266a1,52bfca59,e1235d7,c9e8223b) -,S(4adffdf7,a8a92b65,6f747fe2,92e6bfd2,cd3deb68,ccfd7f01,5639d779,7d21e48c,4d4079af,a6e89720,3a50015,92e43c6e,97fa1e57,11f21bef,c9df4274,441f7d81) -,S(c786e96d,fa658a6f,a9f1fbfb,a15d7021,835ebbb4,3e8ed3a2,c7ea573,c2944dba,81130470,7a10b1e8,74f5b856,b7223346,eef3c562,8959454b,d536494a,f075393f) -,S(10df82c4,64b75895,2c54f335,6fc24ace,cda4578f,d34ae82a,8a1eb2e3,d0830349,dae5c271,86031dd9,2eff2db9,6af91689,2a131cb2,44534495,c3562cb8,dbc5e1b0) -,S(55532c4c,c4483aac,26b049d7,df1da7e1,ef281c7d,bd99d21b,72626443,f2c748c4,58160e32,da446337,d0642596,c17500f7,b0e64081,1017bc1f,4452c4a6,8d2c2789) -,S(fe994c5,d63149e0,d31f6cdb,fce5b941,239c4adf,8d5e6866,37990411,d88ead47,200532b8,4ee2fb18,b2c27cd5,9c3940f3,58c6a2c1,d96ad043,4d826c8c,2a457dce) -,S(c7690e5b,3148cd96,592e654f,2eed33ec,a69d2684,545cbadc,6f6a7e8b,4d3cfbdd,98e0018c,36423854,6dede771,b78bc4b8,c52d956,d26eb22a,e447ab3a,144cd394) -,S(8f1f0986,d273476f,b31d4ddc,de949584,97ec74c9,acc6b0eb,900e4cc,2c98cac3,31f420f4,b9209657,1656b663,a06804fb,78597071,6c138106,119ef214,43aa765b) -,S(bee7ab1c,c23f6101,be01ed60,574ffca,70fbd4db,ae73e5c7,128da065,9f78c042,9187835b,66b2b634,a87d1baa,7666bda3,57dd5ed,26871976,8e0ea9a6,ed102dfc) -,S(8093581b,3205e5c1,90e9d38b,5b5ac422,b48fb5a3,9176bf7a,e1d377,c764f74b,3a3e06f3,4c00cf7f,6216e67f,2d55236d,db54640f,192897e9,fd68820c,bf22ce39) -,S(fc018da2,70dfe007,871e0be7,f5edfb7c,30fc30bd,bed5052c,78a7701b,50954702,9483d20d,af9fb123,723e0c17,7905e94f,462831c7,dceb0238,6f0942e5,188f3a90) -,S(f4ca4cab,7f06af06,d0a8bd7,97d6eed1,7354420d,65d80e09,32f6eaf1,ca12a39c,76770553,69f93094,3f368b0f,2ef6e412,f3d5a45d,1c7edc3d,9550fdd4,ebb1950) -,S(fb03fae2,87265749,787de276,84bfdab0,4993112d,f384113f,1dd41e6a,b438bdf3,ae8829f6,80f60534,50113930,2aba238b,1dc295bc,6598c060,af8393b5,1153b479) -,S(b76268c2,6b873f54,9438a569,5e2d5e24,a92da29a,ca26f18e,143e3290,69638a45,bb4543e,23abdead,c3377320,dd8ffb6a,d38967ac,ea90afd3,23c69373,eeb2407a) -,S(87db8064,9a5a31a6,487893d,f487c00b,143c09c8,fe878621,b592b25a,6c3d8646,872a4547,520d307b,a537d42a,ffbc8e9c,e04d1c80,e3d4f506,b001b0f4,79e92972) -,S(fb9295d5,a7c2cda9,c08b0f39,1fcdea4d,b768b086,dd170d8a,966516fa,bd476acf,62496929,a85c828c,cda71d2a,ae70c429,7bc12f03,5a99ff75,7d66cedd,5fb5135c) -,S(96f749ed,a1fc306,6d133829,774293e0,b179a598,327c3bde,a2e94200,770d12ba,c16915b8,af011de7,614fda0,ce1c4a3,ffeabc2e,2e891e4c,a2d9c277,247fc8c1) -,S(1564d7b9,77b4eb29,e7b23ba7,a3cf453a,8eaadc50,87448fb0,fd9310ec,653ec66d,6d8935ef,a7d41cb7,5c5dad07,c3ca864d,89e49f0,f74d4474,af85bf05,c408009f) -,S(93db7b68,9ed6ad1d,bb61223c,dcca7280,9cf4a49a,14d94f3c,7cae77c8,f1298340,9088165,7b4979f7,26b156c9,d34430db,4a0af993,eeb996c,d091ad5c,4f7bbaff) -,S(2656af7e,d8a2e718,9849cd,793baf93,1c23374a,a3b5596,d8c88841,2b6a5ad9,dca0f4b2,7c7f1547,97346dfc,589374d6,1224048b,ead5442c,9f8950f1,63689045) -,S(a7dc8558,c0adf996,b7f57c08,1b509e34,7819131d,42647498,ba819c12,6d26cbf7,9fc494c9,2bbf6116,14527eaa,1de4708a,f0c19847,3ee9164b,6b9de909,f6a4497d) -,S(1f6d4701,effe09fa,17ecc014,a7a0033c,143fbfac,ba4861cd,d7ee2fe8,5bcb2cda,84c5b017,81ce481a,e610bd8d,96ffa58b,b7a158e9,d1cccd79,7e6436dd,b1308de6) -,S(eefe37c5,d547b779,d905849e,dd1038b,f054233b,f2d1af47,1684e5c2,a1e69960,b5f00dee,8b1f7960,aa068db6,78b6b41a,f8c3e14b,27c1f43e,10f9b34c,fe8eefef) -,S(8d4e8462,60602ee0,948ba5c9,f0506046,d0bf3fd5,e1b93073,bcc8a6b3,30af96d0,62d0e36b,bdffa309,f1257b23,6327506,5a5e7999,b314dbed,edc75800,b35534ba) -,S(da22079d,352d3527,5a80b95f,80b7b8b1,3eb6d178,310b6889,a94cbf2b,9a9a898,e8b06b65,37aae428,cd25fae,d0c1af8b,827b296,886de122,c6690a19,fe94df72) -,S(beb411ff,67cdbb5e,58da6353,172813fe,e386c7,95550395,1ddc23e5,d4e579a4,919f8f30,41f53020,4d3620bc,b0bc80e5,9d87ab73,355c046d,cf2986d3,c9995866) -,S(b0a5732b,76b4a526,e8e742e3,528891c7,3a1febb5,c7657a90,4bc1f95b,96d462b6,a5e4f134,93f9e24,75ac7dab,479092cd,fb59a931,dd042add,3d875e22,76965a9e) -,S(5a87a782,13130193,4ce6180b,714e99c7,30fc8bd4,fd4e8c59,f5b6aae2,f3622561,a929d120,68a64953,90c559f1,ed8ff0d9,bef92431,66117208,d0e8a08a,de9a3d0b) -,S(777ba7aa,6c50e927,64ed93ac,daf56285,9909b031,7c3c5ab9,38ebba26,d62a1748,27a32172,d7ff61ea,b6a26d00,c252f99d,bcf614af,1434641d,cdbd5f4,10e6657e) -,S(ad0f9f5c,8fa07d5d,3c18d4a5,7dc16bc6,3be0dac5,9166fb42,6bfca8f0,65b76720,d2c9c778,3caf2c93,f6c3980e,60ec0fcc,1f1d5ffc,8aff6af,a912b5b4,245fff6e) -,S(8904706f,17aad850,7a71f0c0,94f981e0,5e5a42d9,7f5cc3ed,99b4f635,660e227b,371d5f58,a63ec71b,3cd8b601,ee622586,2822a2c3,99ac70f4,ce293846,23ad8198) -,S(ce32a220,2e276dd,3f5b0a10,38a70f21,3c29ba7,58934c4e,27ee3bc3,c9dadf00,e43d28,80486b34,65e545d7,6618d80c,56874afd,29ea4ee1,e79dbe5b,b1ec1f42) -,S(3d031c0,c717447e,19266420,cef08d59,ac2aed4,7e84c84f,8980e8ed,ee59c7c1,86eabd82,d6a5f57e,cdb52825,a8c726d5,4a9faba3,6272441b,22627c4,a321d970) -,S(9dc08947,fa3983dd,44730aee,d8e94f2c,78eefc44,df126804,281f740,53330b43,58838246,3fc02261,c0e771b9,3d4a90cc,c2c19f7,2893ffb,22fe6d5c,6c5e7318) -,S(f9fb51c7,29646acf,94ecadf7,30989d5e,669ca4fb,3b4dfe66,dad9838a,f239057e,d4a04a8f,f44b86c3,17ce4350,1a2325cd,46b5decf,5f4e14e7,17ef0c30,1241f8e7) -,S(d4a1c33e,816419c1,884c2838,abc7148,c61f05d3,71fe3de8,9f06b580,cc5e1006,28d8f049,a1daec88,5d186da2,66e2b8a2,893d90c8,5e720d03,a53cf8bb,f8a10208) -,S(1b1c6ab,74436126,203ffd8d,8e9c58b3,e18f2767,3a72bfb4,ae4c9e25,ce17c570,ad28aaa5,eaf7128,fc8788e5,b9c1c13b,a4cf16e9,f651da6b,6c43fd1c,cf2903dd) -,S(3d791154,b2c062fb,e1f6ad1,dcc17bd6,b648aadf,cd573cb7,d29f9e47,e089e1c3,a578f2d,a568b0b,e95e1189,7bad8311,3098787d,62756c99,7dc3d795,8e0d3745) -,S(6daac2f7,ee7b01f7,277b3a5a,44785b4b,c6b6adf9,b112dd6a,227b2b46,9f27940a,fe9504e5,75c1e349,9267624f,2b2e603,55befd7e,d66d7fe6,80c521b5,e0d1aaab) -,S(ea6343d7,73a5966c,2ea66806,ed59079e,8b216a9f,4fcbe8f6,744808b3,2478c26f,15ab94e5,cc1f4a5a,33955f6,b30571e2,5104c615,c0aef2bb,6a8f6693,64639f6f) -,S(ffc78cf2,4b436203,dcc1b892,c77fb336,463a8070,332783c6,1824acb3,f5cc55c,7bfe0b6d,666b28c2,3259c4f9,2c0dd94b,fcf53921,91d617df,da1c651a,1fcb81a3) -,S(db38103d,5156c309,67189677,9317879a,f31dcfa6,b8d0f5d9,1f2bc691,6090e6b0,b5b3e45d,9bd41082,cd3115ff,824ff027,78f47a0b,d0ae71fb,32c48d72,cd540c84) -,S(4c08de87,abf89885,2791b455,126e7e54,d660903,f407b842,7b4fcd70,53e0b000,a9f83c6f,dcea99fb,fcb301dd,c31146c8,25c02978,6e5019e8,7b1b6db0,731b9189) -,S(53b6a23b,8f93200c,41bf45b2,bd0d20a5,e6fa5db9,a3686a7c,c669815b,993604c5,31bbf5d2,21023fc2,fef75f0a,f7bc33e,b4d38323,cbdaa511,c40ed497,ef42a850) -,S(b39ebc0e,53b74f35,6f573a40,1df6f8d6,fe1e4fed,f7d976e9,949da398,a45b464e,9d58ae16,a633ea0e,86bad1de,39f0b203,c1ef0b24,b5f1d824,48fc606c,a97fdff1) -,S(182e4920,f4a60741,a0b94fc3,e3ff0bef,39f1d459,cd6c18fb,16b072b8,de0bd416,6d048d0e,ffdf4e60,8097cde5,46955541,491721a3,d6e051ef,9279c5c0,22a32fb6) -,S(7a39e7e0,a2da209d,8cbb9797,5f12acce,840dddfc,5acf7c5f,fe778a11,829e1003,c24aa083,20e6a786,1c161e14,f37b1c7a,65117e55,2c252445,20b47b67,66fb410) -,S(62e6173f,2273d3ff,d9fb640b,87d5cb15,e5df841e,3462bc5f,6b94575d,a110914e,7c424010,4ba37e57,48404997,689a01cb,851343f1,ea8259fc,938483dd,d70ac5d4) -,S(3960d4cd,96de0126,5c2cc88,68e94d66,40e9ac8a,f2abfcd5,2108848c,ad62467,fb24aaf2,85a54405,f75db03a,464bbc29,3bcaaa44,344c763f,dd44656,fa7faeed) -,S(463437ab,42694ce9,98ac17cb,fd4d9034,ab7a1be0,35f911e2,864441a3,eff8e3e3,370056b1,24b894d6,3631087b,194dc5ca,fcd2475c,a95402b8,418f1954,d47599e8) -,S(65774018,fd428788,e4234b36,42c8a354,770ddafa,c38040e9,49f194c0,ff7ad3a4,462ec7,cb17abb6,5200a88a,9874c7f9,40469a51,c48c1fdd,6c0938ad,67741467) -,S(738feb40,e7f16fc3,19ed6649,2507406e,6501308e,5112dff4,db9d12d3,bc0f138a,4923678b,84470212,cc5472de,2163ac3c,51ed5419,dc1b1b1e,78dc0946,f730b940) -,S(546841d9,7985d80b,a0eb3448,3dc5d17c,441b7eb5,d24b6216,ab98b14a,d320cf36,719434a4,952ee43a,b1006ce6,f7785734,c6a5c018,383eed75,e3660f7,94eb6829) -,S(31143de9,1a4b96eb,be7efe31,56b6688,5d39ce66,fa8ce202,57626dc2,8557ece4,d8d8bd18,36e5c388,2273143e,721bef10,b0c3005a,5e2fd3a7,e471ae33,ebfae7be) -,S(ad8076d9,29feddae,a52c009,f3967726,a0a94301,dfc12d59,da63c47b,df6566fe,39eedd66,13fb7141,796c0353,9f560ac,e23f844f,d0d3d422,5b36e41c,b6707602) -,S(b01a4f7b,9362be2e,78f5cdbf,d9e35f21,4d296a3f,3e233d93,2cf33c71,95b3f613,245b535f,c58254a2,157caa87,38e855ac,fa9b071c,1b6182f3,5260da9d,18e385cb) -,S(50f3458f,a781d513,a944ebd9,6f6b791a,1b0cedec,1421f9a0,16a7f350,2d5f429a,4972c646,c1ad5958,18766bab,5bf54ea9,e9c4fe3,19810f1e,27f46cc9,41594045) -,S(d7b606ed,e8fc3a20,925e0a59,5c9462d9,4e04b5c2,b64d13cc,19a47d1,ccf10b0a,dc39a8dd,d5447a0,f07b5e7a,6ea35286,ec01679d,ffb6eaea,6222711a,d57cc63f) -,S(7629836b,73691a1f,f3ae6c99,7e06f597,34fb9625,2d1ec88f,2af15cac,f89c199d,296e4034,8eacfd71,7f64beb5,76736398,62114296,5fc818a3,ea89ba52,1b1a410e) -,S(88f6a162,7baea31,3a2a5d5d,aeda2f4b,4becca6b,812a60d,4b5b4e22,6c822a1,d3acfe53,d6189ab8,31106ca8,2388fc28,5b567e5a,5172050,5be56bf0,187534eb) -,S(8e93c72f,cfeae58d,fecd373e,dd3f31ab,3e4fa28c,f53681dd,ebf37d40,c376283a,e9c82571,2d0cfc0d,e6f35e77,acf0597a,7e2437e2,80f13420,cbe93acc,52901d71) -,S(b2264df0,eaead63,111d7b05,8767cc7f,36d386c7,edf21792,e8aef135,9958b2bd,242eccda,5e4324a5,40e8d098,cad23ecb,88955bb1,126314fc,5da973ee,b1d83313) -,S(9f1c9e90,7a6813a8,da520f6,84553a4c,aab650a6,7eaf4f0e,f2ec212b,95a885ce,416dae6b,f47aeb47,453fd0f4,7da6375d,136b6ee2,450bfe75,504f3619,84a0f355) -,S(dcc7585,132b95e6,a4a24450,d557a0fc,3ec93506,fd1f5f02,17bd0f7a,6943fa1a,c62ca95e,d976d1e7,2bcad48d,9bc3a316,a35e8496,952a7a07,760ecbc,8903b001) -,S(e3c674b1,eeb380f3,f08b1d64,32f4dddd,77cb602,915ac478,4f3c769b,dc2a30fd,fa8b08f9,8bb4a1b7,568c9d3e,754292b,1a35cede,1b377c99,fcee16ff,a16bbe5e) -,S(1152da70,2b7341ff,69e8d3e,6f5ce8d3,bdcd3a03,27df54bb,846ac8e9,18e747e4,7c139d20,1e2ea5db,984cc8d2,4b66c64,8adbd0c9,48c0b085,d59c73ce,b4d7a91c) -,S(3449cac4,abbd3ae5,e09dbc5,c89258a3,df93ead9,1f62fad3,a5add3f9,87a2f83b,197ecb64,5dc998fe,eb9b0df8,6267c7c3,f7af9647,96fea60d,88d4de89,33171e2a) -,S(ad5cc468,11c5a39d,ffa313f6,578acb00,cdda9ce,b3757479,9f2afd6,a8df7a19,4fdf6093,c8fa8a92,7702982e,7e638948,b982d84f,ae6658bc,fa839354,6d6e76f4) -,S(acad447c,b57e8f5,f528a113,347e5c5a,2097766a,b4664c70,3f496635,759a7799,88e1b4ff,3bf3e967,d2c6c948,4bb727a1,d13231cd,acc45463,d421431a,b6fc46ad) -,S(b74286a7,e2699aee,9802563a,4da514cc,d74fd001,48534822,9214395b,36158246,8df2b491,ea018b23,b1c7fb54,b7a05db,b79b0ebe,1117e2d9,ce73e70d,d097bf90) -,S(86bc560b,19d583b3,62c1634a,139bbd16,db30e823,75913cd6,fb688e4,38ceca4d,2126168,75c3adc6,c2aa16ee,2e028052,9e6612b,fe4b1aee,e4961feb,f530423c) -,S(dd79faa2,e97dd468,5f3ff8b8,d5e55598,73736de3,9493a3f4,4e679516,f51e495a,2cb89020,efaae785,5376d901,4d1bc374,21e0ee60,29ac70c4,65bdcdd1,e240e57d) -,S(caf6318f,825ca3d8,6d45c681,60d897d1,76875e26,bcd36d00,82b4e1ea,e6d8c142,d7abc304,55a5fab2,68c6d17c,3763e586,5b9e266b,bc6211b9,48b5ff3d,19f5df72) -,S(c49dbf15,70c3f0ce,1afd166f,884af550,1f26905d,2f726185,7c026405,efe9a2bd,54eaad70,8bdb7b2a,59f5d69b,5be6ed79,5fbc4137,945be17c,b4736649,6e8cd3c0) -,S(a87447c2,83c88db2,15630cb7,6029132f,47dadd57,5ea6f9bc,10d1b36d,8317a91a,8489d3c3,6334d65,fdf6089b,df19c3e8,7eecd697,516e1756,5fc8b977,be82c363) -,S(7467b357,7d21b028,dab4100b,ebfa734d,36345024,adc60b1,10b8f96b,c7860889,b2978a5d,dea9765f,7877d8ff,fba66c0d,f7c8e0f4,6854deab,21908da2,8572b1a2) -,S(6af133d9,bf2d6b57,ef69e0e7,5eef6d,eeb82d31,af490320,bd26f4eb,38ffd42d,7f4a4d1e,ce23c530,a4d64c23,cf0bf8,a46c59aa,74dce4ac,2854c6bc,d11b056f) -,S(faff2662,5a41c80f,c0889d4,83eaf50c,596aa571,6807b118,1e94ce5b,581b0a7d,32f3d057,4afc487b,43b129af,f83bc7dc,d495402b,90fdc30f,736e87a5,469e8aa7) -,S(8c6983d2,8047ab24,ddb292cf,1c8836af,7e75d7ad,6ce23149,e022cb64,2439ba2f,70a10314,447eaa73,924fdf58,fc607dc1,c69a69aa,29b84dcb,156fec4e,568a5bb9) -,S(bfdda2aa,b23a37b2,bc129bb4,280a2c45,926360c3,2719872c,ae1e81b3,1b3d3d02,e8319769,b7d21199,9e5de1ae,76021c9c,2bf75ed0,4c9a6c2a,c52da4f4,88cf78a5) -,S(80e24bf,3559d05e,c0cf63af,21dd7adf,237c23e7,ed930c7b,4124ad4,46871de8,c8f37f91,4e78e037,602ae9bf,ea3511fd,2c95ad3,6665117d,64f9fbbd,ecd10063) -,S(7f56d940,2d6fb0ed,dc6ce187,2ee8e55f,45db30f9,8defa84d,f7fb76ca,aef5e800,f43b9e6c,b60ce85f,44682fae,d8a48e5,3d9599d4,f19b4757,74f7d6fe,2fb2554f) -,S(437e7a08,900216be,72f14ef7,33127d49,9130309a,73369d2e,58fd4187,a0d428bd,3f0a4c4c,63dc779d,69dea37f,786a5157,43b3560c,16d4e56,4a1d7802,f40dec83) -,S(3bb8db7e,8cb3534e,d7f70f8d,eeb1cb81,3ab21dd0,552c311f,f98f38e3,63321626,9ffd98a4,b3c271e7,83ec8c72,98ba83b3,f4f0a5bb,61ce1edd,5c1095ee,eb16a569) -,S(21de8ce4,6aaebc6b,4ac51620,e2c78904,f9300b6,2930fa79,699e2782,5dc2310f,12a21855,50ceab27,aeb2e7cf,14710b7c,b3dc837a,67a1e4d2,6950e2b8,1942b9c1) -,S(6c24ddca,e4245972,5268369c,545bc910,ffddd8c3,49d83fec,eb27af78,cfc0c965,6263abc6,ed17a124,c8b2c5e5,c91b157a,13512939,b9d60e48,929fe6d8,4d032338) -,S(ddc0dfb0,49f7b6b1,cd1d03c6,f8ed2470,ae320f04,bc6f13f5,a88ba89,7bd1f91b,57c5f0df,8fd22e02,da44cd05,74fbcc1,c8b4a903,a909f906,aef9208a,89eeddd0) -,S(6fc5fdee,78c61421,a3ec2284,583a56d8,f18e66eb,58c54dde,e5209a1f,3e3761eb,baeac905,6101b825,8b08a807,72c977bf,60956b2e,d98d1b25,e71b2b7e,10e3d25e) -,S(1b6735d6,ac2f1db0,1c3781d0,cf42e2cc,3ccbf030,2e3837f1,3f6655eb,ba0dfddc,621e8c0e,cedfd28e,608c3da5,135d63fb,93dc6919,2a6154db,bf63e315,2f7db68e) -,S(1a875a0c,ecae6600,4bbdab3c,4fa5a57f,925079dd,671bd9aa,e8ac5c51,b21a5e83,2317a0c0,81c17bed,a15e1148,f44beb72,d4e65fa4,96408778,8216f85b,3924d9fa) -,S(51635c0c,ce51684d,9631c8ad,f6c9c4a9,3f66dc04,a372c891,294c42ae,2be5a84a,5c6cf3f1,bbc9c21b,124e78cf,ba05b2f9,ffb9c902,3895d584,48622259,635d3517) -,S(c548df8c,b685f457,71c564ed,a3e9a77e,a4734faf,7cef877c,b0bd70ff,d85afe0d,2675d6b8,24f99a19,8825f1ee,19510492,9eb633d0,367c01f7,c922bfb,c2cd6dc2) -,S(121592ee,aa39a310,3c02502d,72e360f,f500853a,7d2e449b,16c5e443,f42e700c,b5cfa2c6,689d973d,e0578a39,bc687720,acc0305d,6ad3b678,1d36941b,7f0cb435) -,S(c2a8b66d,cce99233,b3d83699,b20f0c60,21a83ee1,46a491e6,d7e69ebc,92a3e046,e0f3aff2,64228803,d8c1d729,88780d2,ae8c344d,f9571b86,70254b39,b4243705) -,S(b2b703c2,56ab219e,528886a4,4d6b7772,5cfc1b5b,17865ecc,c46e2d2,2420514d,b6aff027,b4408177,8c6cfaa0,123590a7,4615394c,aa83891d,15013d35,ba28a9cf) -,S(d249c36d,fbf43f5d,c6ddb196,d78d4cbe,898d64cb,3b239f89,1e8c4245,ab647afb,4e58c9e9,4199e0b7,8a0179c2,c82b6442,17eb3fe7,80c687e5,166f56ec,f812d092) -,S(ac3519a1,92c13eb,b37cd560,1a141d80,817226ec,7c86a053,42655c1,997b476,3522765a,afc2fe6b,2af9b489,27809189,74c2bc57,58ce502,13777ce1,a569083a) -,S(e9b69596,8983ee86,340b96ce,efd9a289,e86e6d49,3f057962,77b99067,af83c70f,983a83a,e1b08fee,392e51e1,c12a8e12,731d592a,517e240e,ea508f7d,b34059d5) -,S(e11e982f,10e65120,ca357106,f273c5b2,9900454f,81456781,36f52871,65444dd6,e961b155,81ee9ec5,1e6a3616,b7182da1,bd2e5db4,d08dad5b,46bee558,44c21850) -,S(f63f4434,bb0c17dd,3a17c75d,2d179e41,10a7810a,847bd4eb,37827997,94e57b14,480bff24,69c2e268,a51b2147,3d6cf7ca,23a3c61b,513267f7,c25b092,7dcc8549) -,S(cd8ea46,d65bb2da,7234508e,fb48a828,27678525,d102fa85,6d26475,eadc1a69,ba231ab9,513f90be,9cc8260a,fc63b05a,5aaa0280,3502532c,916d99c7,20b7b2d0) -,S(af9a2285,ec491b56,9cf53c8,6ec188e0,5bf18d1c,d7e898c3,c881a5de,481bbe13,a0cca7f3,714f8d00,92af7bc9,62abbe5,4d106dd0,a6089607,35a6d9b4,73d9ed58) -,S(5d90a039,55f41998,62e5cef1,af05ddd9,114632eb,abf27d6b,9b92c6c8,cfed8640,a0025e54,482aa49,11d8a556,2205c2ae,2a0f75c4,6f3faa55,7463b9b9,cce1281d) -,S(aa1f071c,55541753,3a47b490,c5603aed,2d2e5282,71acd0de,6ea7c5bc,ba66a348,195d8b00,fd90b1ad,15e46620,22d78bb2,47c1e9a7,8ab3b018,f341a005,6267a167) -,S(4225728f,ee2495d6,73f64d5a,cee2e372,2713a3b4,dbd2f098,d20415c9,3ab513e6,76c17939,461504e6,e1420d53,c5b07449,ce7f976a,e4de178e,69552755,75e92412) -,S(669c2815,b3357084,bf7bab89,63753b0b,ebbea33e,5b731ba7,5f969890,3a281eb6,23fcf486,e2839e2d,91fb08a9,11ed7361,81de7406,54c13306,575c576c,d0459c28) -,S(7b29749b,393869b0,d7f0977b,340b9e07,76a20ceb,ff6d8f8e,f4650348,11773665,a0d68cd,b6033ab6,a4c92113,c8f07110,aa5cf600,2335d2d5,2ca9b956,2874832b) -,S(6f096ed8,56f38c26,25200774,77ef7ade,19fb616e,30ed560a,ee5b4987,5f43a7db,54453b3d,1ffce3dc,b5e72ec9,3f15b57c,6725b271,d3fe8b7d,8f30ed00,35845b6d) -,S(1354de01,ef040d5c,681318c5,a6dfe7af,5c8eba0e,ab581674,acd5335c,e33c4bec,4002513f,ed215b53,c65686ad,8366cd7e,38711fd9,98d27750,bfce7e24,dda317b) -,S(5f8afb0b,3800c535,47cdf93d,61ae5c67,233c2525,17f99c38,8e97e7a9,1a90b561,7dad53b7,a64b7068,967fc0dc,e7178a43,a06e56f7,7aab1a57,7910d69c,23540671) -,S(901d50d9,b88abad7,84e75135,85a81d9f,a1d167f2,c9f377b8,e2598cc7,b249f3d8,7242b591,3c80db3e,748c63ae,47ee6229,2c1bc29b,e9f9088d,fb882259,405c3dd0) -,S(2f5e27e7,4c7e00df,c0bf6401,7d1a888d,1bb7a3e1,3ff66874,f7c306e3,806a48d3,87c3836c,7fb767f,4b5ac585,62c48a18,21dede2a,7d63fe40,da75d967,cf9191d0) -,S(8b2277a1,70464589,1d8b54cc,43bd5fc3,54fa6f1b,e7a062e6,6349ac2c,40eef8ba,ac3a007d,6b3278de,1c043476,13b254b7,69c9e14a,c2f50f9d,5f025046,2e06081f) -,S(4a6273a4,e9f28e9a,82c3532b,e7d3e564,66e87273,ad1fcfad,7ecace6c,54890de4,6d8b0fb2,1cb99844,610a325c,9592cc1d,e7c8b32,d70e19b7,ab7df472,8fd1aa51) -,S(f07330e,2ab0150e,435fe3a6,8c703091,4e7fb52c,307d58d5,d5120bfb,891f84d5,25b6ebc5,4c1d9206,33891a8e,39aadebd,988bd98b,a29b04bf,6ce4c283,a4438b08) -,S(3a30b22d,6f1fd617,9fff2c21,d6635828,8c21fc8a,94a274b8,993ecb91,eaab54eb,94035c56,6ea179ac,d58eb0f9,d12cb41d,67b94fbe,65805110,61cd9806,890946b) -,S(8c4f39cb,87d7f65e,591fa10,fd46d08f,fc5de3e1,67d8c9e7,718bff95,b112a5a,726c4bb,c64373f1,9399db5,18b5f823,3faef361,3e363b84,ad76052e,bdc8f2e6) -,S(38118e59,63a1929e,74f6d98b,c80e44e4,d9b32254,6a0f1eb0,690d08f4,f3bd4bfb,23167e00,c29513e8,e82d1140,bef5bf02,b806a652,fee592fb,1dad0811,604a4b50) -,S(75d4246b,db065274,550e9784,f3c9437f,3aec0fde,3af54a0d,61430cdf,2626bf5c,8392f570,3896cc62,d66f8485,9f7f269,4ff40a81,9505447b,7d79bb98,77f8f621) -,S(ab3bb0ae,c1f390fc,8d1bd3fb,4ecdad66,3db868c7,c4fbe0ba,6cf4f059,7068ed87,91382a2,2dcfe0c1,b51148ce,bad2140,24cf099c,e3e5e3ee,867db7ee,d070c7e4) -,S(d1453e12,383386e1,1976cae0,8a448b63,1a977dd8,47c19d2f,d7a212ad,5090011c,7044d595,fa8f68c2,4a972658,590d7ab6,dfc06ace,b9d8c320,205b858e,ba0402c5) -,S(894afc53,b0d1bb6a,c948d117,7e83c42,b4ff4084,e593fd75,d0660680,2ec0a4eb,5c5eb493,73e74fc7,39ca4fba,1940ebe4,6912d896,7cfc036c,7402e8ff,8d071d7c) -,S(f1dbde60,43133dc6,8699e89a,3dcaddc1,fbcb5ea5,e815eb5,8e7a6b87,dea2e6e9,96a7b1a5,b36e5492,68168c91,775d6107,a3f87f9,fb5c8b3b,acb75dad,5dc544fa) -,S(ad9126ba,6d35d780,dd2841cb,2ba817d3,f0267446,ee99abd0,ee2b4910,a4450b8,f77eaa1e,66c0f3f6,88268d92,9c9ee53d,6dbbc20b,b74e864f,d7831cc9,3d47280b) -,S(70d5638f,d3fc43c7,6f321157,f9715994,3b797d8b,1d366f5a,a5a7f1e4,ff1ff7a6,ba6f2d41,7af1c5af,dac8c83d,dcc289e9,4d6f29b4,2631ab7b,19414bdf,4a9ece36) -,S(e43bb23e,1f82bcd2,708730b9,3d3ed915,e3b4ad84,61904f68,bd91a065,80a4ebad,3b528db,117cfb49,99941b0b,63f51ef3,926a6230,dadbfcdc,28fd1d6,2bd44147) -,S(9daf3516,a015bd59,b648fd9d,9143e76,46b2e3fa,df5e446a,c57f2e22,9c9dad2b,5ec57ad4,808a9f2,ed297f7d,a7794e2e,3f1bb14c,bef58047,e0bddfb1,8ff11149) -,S(13970b21,3115c499,5eac245b,33633c53,1f2be101,a541f129,7403a727,67df16f8,3444e05a,7e49ecfd,633c96dc,99a0fc81,cc3c359c,440ffcd4,5df61c5d,1c027e97) -,S(12aef793,66978a2d,3fab4377,7debd5c7,4315b002,829b49df,c80fbb4e,1eaa94c1,e3f5c1d6,ea42b741,8bb3446d,c23679f8,e7a96d02,a8f33d1d,3404126f,71f9e37b) -,S(62a2ef7b,887de5a6,19c753f5,e0bc45c1,7c47b8b1,ffbb0ce4,8b93caf1,d1ab4b02,7d00482c,20c25e01,ad6ae35e,89c263a3,5d0fc816,952a96b0,9f2c2fa4,b8fc9bef) -,S(e6b03f17,92df5b1e,ec324ea0,898c031b,d745221e,791d2406,2aa917fc,de6f8a87,b4ee4b18,41153d22,1ec0ffe0,ec05b1c3,408d71c,5d2ca29e,a01ef9c2,e669b205) -,S(dbc02e03,e03e2f14,53ff6410,afded1f4,f0d51461,5ee00f75,d041ee33,c4f35783,6a3a332d,99ffedd3,d442b44b,aaa9d12,9d93e372,36dad034,9c47bd83,7c7674c4) -,S(f11be23d,6884890f,78ccbcaa,c1759ceb,5e7f98dc,19073aba,b85d85be,5fd23ef0,9afda170,dc1270d2,e43989a,4ffac7d5,c848ee6a,51e03b58,c308a4fa,39e2cfe9) -,S(16ec4f95,1db5c83a,c2c26209,f2577650,e9c48c44,224b221c,c09b0b19,1c1c5552,e3959034,d259e9f5,163a44da,f87ffd63,7a35b220,eea5ec6c,301cba9,eb09dc54) -,S(3cf701ab,8991e981,e9cbfe30,7b3aced5,c2147c47,f76bc2a0,733ee544,3fef3f99,1e6a3069,d4d0bb8c,def98d49,cd303b51,c45617ed,833be051,ca2836bc,13b8e1ac) -,S(96d093fd,1a8efbe,4f93c544,d0d7e397,cc83e114,4574f804,570fa3ec,58d5669c,2a29438,a05fe50d,b980db60,b343b06d,1796ddff,7e7fe39a,356cb608,69c05ccb) -,S(a6457eee,21025732,5094d3eb,6f6ea05,21e83184,adeabfa7,b6cd1206,9a9dc9ee,83e436a8,b234778d,9c7be0db,88639177,1d7a48df,19c29c47,682fa2cc,30b5e7f2) -,S(1b366505,1c858ac3,5890e7dd,b4aa7984,dbacbbe1,f4d2b62d,5337b530,da9bb0a5,39d3c2d,42c5d292,40b474e7,2e94a64b,4612f5a,68f5b6bc,586db5fc,a41025d6) -,S(e09325f4,68328cc4,d69a71d4,8ffe0380,bc118cb3,b8f390d3,4c1e56fd,27f4589a,16cbf183,78946fb8,3ff9763,41c6cc3c,9b2f451d,7661bc3f,3811f7e6,ea89a01d) -,S(6a8ea7a9,ddfa0f9a,8473c47e,f5667e44,3e64e03c,5c33a9a1,f0f1257b,40e1ce62,92806471,56238c84,9c0aadaa,2e9efdcd,e5a56a2a,78803f7b,66210333,88f525db) -,S(480b30ca,dc57c623,9ede2763,f113b46e,599076ae,ec687c49,33343178,c620f2ea,b5aa1b8a,ffe1e5ed,de587df3,341dd34b,57180cd4,752a1bfd,d06e4c2c,273b4433) -,S(134be6f0,b03ea43e,98e2364,46a45253,ea5822df,46227aec,b24b09d5,b25a34b2,d4841d54,b7fc1736,b293d314,bf6352f2,c7b08ece,4de652d4,2c1b985,d1fd78a2) -,S(7c84e23f,c54de6a1,a4ff6c9a,c7c88ac6,732d019f,a53b1a9a,a6eb2ab8,a3101f31,4ca88bac,a8d52f44,3703fa27,4fddde3d,ae5924bd,26b062fc,6f7fd0d,43ddf5ad) -,S(7c6a349,911f02ef,2aebdc3b,ce77f639,94c4dd2a,a842b567,141c023f,4f2d92d5,9b4f2f9,6215aad9,c7e0edf6,efcd8aa8,74dbbcd5,4a0c4cd0,fb7e01e8,ba6884af) -,S(9e1dffc6,a919c9b8,4e3d818a,5ec60f7d,5a2baba7,7d2dd65e,137d2ba2,8a1aed3c,cf26f543,bb7ef705,e2d3c429,f0ea27,84e3daae,1a71c556,38d281fd,aa3b1738) -,S(e24f6abe,c7519588,33ecc765,7446ae36,937e310b,d5754c5c,343eecf3,6e140079,c38a0399,774ff24d,90f8e599,183bf011,aa3c911b,9a66bbe6,920522a6,7510e62d) -,S(517505bd,1fe28c21,2fa85f18,99823b01,bcc3bd1,748169ea,54f35ab7,870f0e1,da94c34a,5de41881,1184fe92,8b3f08fc,362aadf7,5e7abf87,5d5f4798,fa712f3f) -,S(a02217de,4ec87155,b877b7c9,dd7425b9,79627f0d,ebe127ce,27d4f3ef,fb988a8b,cdbd866d,7b69e8eb,9321d07b,2a5c9d8f,6eec8be2,f19a6d24,4c987a1a,12752bd5) -,S(2e595023,c8ba084c,1cbb2d05,96ec35b2,7c366bf,cde27666,35d7e820,8fcb0ae9,ac08f27e,b8fd5ac4,deb1f46b,23ac1c5c,aa02b918,9761e6ba,d7c1ebb0,f412d8cf) -,S(ce384358,fba557d3,b76df62e,d2264cf1,e0bc7b43,bab30be9,fd6f65e1,a82b6c2f,a3cbf24a,e067ad85,ae0fc86a,6e8490b6,1e44980b,52f29a75,4a3f7e4b,a79ad119) -,S(9715da8,79cb1c5c,4291e00,fd2822c1,7f067d63,664170fe,463e86c2,d25e46,c5179ad3,a4846fb8,d6f290b9,2f957e14,cee99f6e,12fc8066,ec4dfaaf,a82edb99) -,S(19f61bb0,4cedc19e,5054eeff,8d0bc384,6cf62a35,1af3ab95,e03e45d0,786e1aef,aaacadc8,db84d7c3,f869931b,bd33d295,45fb37cb,7e474fa1,7a69a683,117c05b8) -,S(2a69afa7,581777ad,38882f6c,659ff4da,33fcdc17,a5355583,d1f8ae37,7dcbd718,878eb429,d42dfbd6,435df1fa,c5e0ed4d,e7b2fe4b,6f7dd6f2,6a3150a2,213fa619) -,S(c3da1980,cdf257db,f2a5eda9,94267691,a5e1e679,79d4908c,c06f7f50,71002381,2cdf4de1,90ef2995,a984d882,598c24cc,35cfc47e,5cbd2d53,53d880cf,a944bfb6) -,S(19294eba,9d19c03b,497551cb,7cc8d8ad,3e3b2130,942ca8dd,c8bc5579,1c424d2d,5523ac45,e676daaf,2d8da00f,5e9240e3,d904a536,63e6b704,735889c8,84b680ba) -,S(d8b3b307,41ee7ff8,2306615f,2d2ef361,6e3f7cd7,fed9d56e,69300fb8,5eab6bd3,7d57c12d,e65bf3c4,6dde736c,373ea374,d090b240,6e1d97fc,8049e21e,aa10a74c) -,S(e2fa1bd1,164528f0,87c72a18,e9843e33,43b376d9,b5616b74,5e0c3d00,eca95fd1,72dcfc41,15b35406,8bd3057d,506d592,771eb3fd,60a2c2c3,dfc2645f,86b249e5) -,S(ac587775,bee32b7e,90031ad8,9786df14,8e4d9662,55a06399,e43c0441,883fd6b4,b6d3eaa,6f6a50ef,ef84c578,b241591e,4a718eef,fb40ac34,99a57079,b74c45b5) -,S(74976cb0,77d481f5,e6bf700,6db57a13,f362fabb,e6aaf25b,6e956452,9d093bbc,bb40be31,7cfde25c,75ea859,2b622e4,9d42a0a7,30602241,219bcc84,a5f4bfe1) -,S(e71e6967,f32647fc,2c13a94d,4bc1410a,cf9728d,1f543522,681d750b,2620a668,33c4fc82,720210d9,afb9f1fd,51671f3f,fc1df5f4,e61a5ff8,c59f06c7,91f996de) -,S(bc36cf57,161e9b17,828e4557,74204c59,805b35e3,abdf4ba4,daa9a5c3,fafad6d2,df34c492,3018e879,bf459cb4,528d2983,340444f5,a85efc29,71e260df,29cd8a20) -,S(925251b3,9c8761c6,317c2066,717a2e8d,89e43acf,89527ddd,6078fa49,2d040f95,aa7a084,8b2633ac,ce551f1c,63312895,f4ece420,5e224665,2c486beb,b8131f10) -,S(4ec27df3,d9e755ce,b93e1ca0,e0e43f44,595b529f,6460e3f4,e6cc3765,3a2bbb21,eee3fa06,257b4be9,387ac7b6,6cc1ff6a,aae43583,37d6ed71,27ff753f,1fb179ac) -,S(6f733e9c,b86c3a17,5bce6c08,347577eb,69cceb17,3c19abef,c94b6646,92859812,2a895d6f,c4a7a4f5,610e8b8,9e7361bb,db728625,ee31e6de,927c74f5,b10ad0fe) -,S(c631f4ec,f205b1b4,6bc0fce5,3680e6a7,27f9e64d,5ee3fe24,c37291a0,d3a69b53,f0de9e0,e4bea2a9,cc01a5d,2f9aad2,f5af7ab2,7c2ff98b,983dd2b6,38dced4c) -,S(9326d449,4fcb3049,8badc221,6d3a90c0,131d31ea,cbca74f7,2cf7da2c,bb6aa2b8,c3f268ba,4c9a9ab5,3f9edb88,74f2786c,4e4c065e,ab58487e,cd8101b,7132511a) -,S(538c52d4,8fa6c492,cf546349,675d6a2c,ba10b442,8827dfeb,69f0303b,1b7ac774,c1b1db4f,d6d50f3e,c7533ee8,cea0d47,883b57e6,dd4137c8,2132f846,3b81ebf9) -,S(5e58a25d,8bdb4576,d178fdb7,23158d26,508f8486,ad553727,907901d5,6e99a680,97c1f814,8880cd85,51c9f1e4,9ae58eb3,d1a01285,bfa8248,44bc794b,7d83ec62) -,S(1e9830ee,b75d6c6d,c70989d4,ccb85e62,34a1cf94,ef81b65a,49b25753,cb6c13c4,d0780a7f,9607e530,d80dc068,68b1cf8b,82d3047a,2977d204,65187ed3,13c94c6c) -,S(c5b441c2,f7e97a03,dd690cbc,ac605772,1524dce7,fb5068f3,f73d78ce,50fe0183,9bdd2242,e35008dd,4f907600,64eb3b29,427ee9b2,bbeeb548,62878688,a916e410) -,S(a5f56816,e9448d0a,aaa7593e,e3145678,3be74521,b129f13,f11a276e,d419492,8406662,65c275da,76ef289e,d36f8af6,6ead9be1,48cec081,7c21987e,9e8af9fc) -,S(c5e85955,44004f79,2260d553,25628858,ce50c95b,9362d868,90fdfd20,8d1184c4,6a5f02f1,c0f381f2,7fd21eb,928f03a,c8524dc5,9bfc1bca,d025a290,7cf939d1) -,S(d5dd810,9e691f5,8694c87b,59907ed5,ec18d37b,8554799c,1481ac78,825d2ac9,ffbaef54,fd35a5ab,a49f9946,a11e5ad9,2f29590c,20e28180,9f4be3e4,b156dbe0) -,S(ee5d42a2,c705bae5,a11d9d09,af3217d,2ec16588,64a60a56,d8e4a1cd,4313c61a,f08f0e08,89c015f5,3a2a74c3,3dd625da,b329181d,1d0f4fa0,14ec01e9,5d113d88) -,S(90409eee,78af819e,249f62ea,3b4d70a9,26557f8,731e50ed,532c0b30,4616d615,17aa7a7f,8af635c9,c4ea353c,56c89da9,70df599a,faec8916,ec9a6d82,cdf957f2) -,S(5f19aa1b,a6d6e3d6,9445e8cd,71c95e3f,a3ddad6c,ff0dcb4b,9e09aee5,65ba9e46,f82b3170,c2953397,a6cd29fc,9c87bcd9,76cbc7a3,5f953948,5a57a940,63c2e570) -,S(5081942d,1039bfcd,96a759c9,27583c45,8dd4c013,59fea307,40c65fad,d020606b,f6f204b0,97cecd15,b2619aef,c25328fb,226598b,fc9384bd,de99a4d6,567e9b8e) -,S(43eea7b1,acbb1450,c9a49b0,262639f,702612b1,b184ac15,675d6496,a5df1a54,a31636f9,ceecfbd6,60f78f,f6cee471,d4366d7f,ff863db4,9a5a652c,71b94797) -,S(f2860e98,a30a6c14,ac43dc9c,61bbae1f,b8ecb294,36c8f0a8,7dd43c01,486706a1,bc83bfae,9a4effeb,4beb025e,962108e5,4a5d7979,cb9ae2a0,7cc44295,b95a2e9c) -,S(6b4a8c28,7d5c7af,63ad8d34,9751116b,60a613f5,7cac229d,7ef0d9c8,166d69c9,48333ada,f4810cf,94c78d43,88f8842d,fdc9fd7c,d391e456,a592d8b2,200bd6c6) -,S(d1efc808,393d4498,50837323,9b791d0d,a814e888,2958da8a,87136d93,bf1b7d74,13247e74,3c323631,9e557476,4ad4dcf2,b91dbc97,2d38244a,fabe4c0c,d08a9924) -,S(d3fd7a6a,fdc7332d,f2e6683b,a05ab787,e3c48262,ce837f9e,d8ebae1c,1f6f7ab2,3d25bfd3,3ddd4f74,8ff395a6,b4f36d19,cdb28ce6,b56aaa55,e783e9f6,3d74e70b) -,S(816f76c4,c5ea8733,5f220c54,28b31cc6,89fd8267,e498a675,4d6a2620,a60d9aac,d3b61647,f6624bb3,9fbb672f,51b66613,8a441a3b,660bb223,1f255488,806e79c4) -,S(1e344f97,98f11372,aef5c6c7,6b32a568,16198e18,8e611026,1dc78338,2522cc93,474e0218,9bb4f698,15e304d4,8166e3cd,717a1bc,a9cf4e4b,1f5c5d23,a36e392c) -,S(4d3bcef1,d6cff8a0,e0582d11,22eb7f67,28aae077,e9ef7960,ec519ab,3c6d6087,29f1b01f,a70e6812,3dade19e,d5d2689,6c491389,27a2da1d,3c628965,bccf38e2) -,S(6d5d596e,467ce203,297cdfe6,ce4807a6,1686a8c9,f0606283,5e0fa194,894d027b,ef58ab41,1d6a002c,12f469e2,e9f8ded4,4291b270,4b7490c5,4c70c94a,cb7b24ce) -,S(86f6ebc9,c25f6866,f14af018,88486b22,6c89b1fb,64bd9ac6,e523e503,e2cc6819,b0725647,4d9f3b4,8d4055d,e15b72ca,ce599bfc,247ce9a8,4b0d5e72,16b30425) -,S(520115e9,a47c3df7,23f81df,8422c03a,ea0084df,b122759a,8d6a5b75,540cb339,93b12878,44f22aec,9d5ed727,3d204d85,d3bddaad,73e3545e,5725b171,2b8417bb) -,S(19c9ff30,e5e50038,7e9be1f8,efddca98,7a72de0,d5cad8ce,7569d4e7,2b381009,b43b0c98,402748ee,16b362c8,b68ae79f,8493a7ef,293b149e,3faf7247,83ee3661) -,S(bdf0f8e0,928affd0,87566820,3c95b3b4,e6baf9f,f1da25c9,73814c27,551ee4cf,5f701bb6,8f8a6795,cb4ad675,e00b5ca5,761a0eff,32a1d3f0,9b29d5b6,3885163b) -,S(5c609591,37a48dfb,f778dc26,80de17ce,390ec33c,ea5cace2,a969ee9d,1e413e1a,670078d8,59a2c138,93946d1,e052552d,fd92c380,5fdf2ed7,8aad7795,2ddf2f51) -,S(98f22ef1,b9a62928,c5ddbdf,70e71c08,eb910ff1,fa6a6a1,56de82bf,bed8fae,f87be19a,9433d279,8088c882,5d122e31,bec9102f,c580fa2,24d40f32,2a2db1e8) -,S(d1842bec,2bfc5fc0,d5208d7b,40e04b76,88f26add,9b5a6845,751147e4,b4524615,f0405ace,6dc9bc88,48d18586,b713ca3d,67b76ad9,4f2f794c,55fbe9d2,f72ffa56) -,S(732cdad8,e0aaee77,473c0140,9702cb39,555ee048,357fa448,33ce8e3f,5f50bea5,24666502,448268a5,bc2c693a,85a1fea9,dc5f010b,a9b0cce7,6bf36124,bca1cb0c) -,S(6c86ebd9,5200b1ff,dbb6ce6d,e9fff6b7,1b6100e3,1144239d,77e7201c,db2e8af5,39c687d5,abff0ec7,c7ccc4b2,a4a16ba9,7324430e,a1ef209d,5ea126d2,cef24539) -,S(655d63c1,47441ab0,e65f9893,dd38f3ca,22d2d8a,a7b2c87d,a2e2293,b24ffe0f,d19ede94,b25ca138,94ab8fe9,842cae29,92cb58da,592c19eb,57c4184a,45121281) -,S(8efc14d2,d5845886,ec264438,449ff49d,ddab7567,69999bd3,6191cb39,efa41b72,9f1052fc,416db1a1,d9797e66,a816b403,475ac091,ded4dfdc,e262d527,3c535293) -,S(31a7f0b9,1686e695,d1fae6e3,8fcdbeb4,246fde30,f2ca80d5,2d9fde31,c728eef2,9661bf7d,46248da3,8ae1ff52,a8aba654,351a1f58,4f3bbfed,1875d439,3612190d) -,S(9dd959a9,8c862275,93dcc957,e369b2fe,5cc1d411,d4162ad7,d8e22b64,633adb85,78ccfeef,d95ede71,32a7011d,bd39b9dd,f77e38bc,47f7432c,f90d6583,5a6e665e) -,S(51beca99,fe3cedfd,1ba44caf,58c0fe4,8b926e72,50e5ca7f,8a187cb4,909b1892,12f38fea,aa9de148,7c14eff6,96cccf6b,c7cb23a8,6f2b7e0f,10fa971f,3545a0b2) -,S(1a84e21,3ef9b9a5,9f9a4fe9,d21dc1cd,1ec7a102,fd91557c,1129921b,781e6b51,aefbd931,17a42a75,13db0e04,782aa0b6,9cd79d36,b074f026,bfb7682,983cb78c) -,S(9eb14847,2d02a287,cd197450,78d81963,3943183d,c76c2090,9f68b94,12eeeaf0,6fe4b5a2,d18ac52f,9a129a91,1db00993,ca505380,2054b5c5,48f35380,c6d467d) -,S(9ecb3cc8,da5475cf,1a66ef54,3286f07,f5be1196,2c1fd420,b394bae6,c4256441,b4160952,e3701895,6f25c5d2,98ce90c7,91797571,267902a0,bba53d2c,2fe2cde0) -,S(541e567c,b2160fe2,75e9d479,1beb8ad0,4c07d6b5,12b43d49,888963f6,d6696ce,2444e184,66cc09d6,aec704c6,ea8ef670,4ed1488c,dd8107c0,c625b783,6534d6f4) -,S(8c061b6b,b6b55fc3,7c6d805c,808fb3e1,6fab1cb3,a05853bc,4933eb39,ca7b3580,20430304,c3780c29,a977f8d3,54424539,67924c2e,9a1353da,40716ef5,a0a0d37d) -,S(b9b674ab,361aacec,bbb69f7f,7c2b1361,44e55da6,1566ed97,cd58152e,4d391033,7841975a,4cf0b5b7,3bad8433,10866275,8a8eb93c,3b5db58a,15346083,f3d10386) -,S(3453c3d2,27e1dfc5,3e22487d,cce25ab6,18a3d25a,48f6fd1f,8e9158ec,dd6bfa1c,aeef1768,b754d998,fcbc75db,7a750396,930d169d,bf933c1c,15dfe041,17ff63a6) -,S(f36f7b9f,28463b22,d2c43e29,6b96846c,1b3401ec,53490c5c,35ec197d,da2c440c,9876476d,e2cfb7eb,b1cdef50,a39d20c,4ba5000f,9edef22e,ab7b96c6,f0cb5585) -,S(77c64190,33ef6119,ac3edefe,ed519632,ef5dccf3,f46066bf,6d5204e0,66788b5d,980cc59e,a103486a,9c8cfccd,213cf704,3e6aacb6,abbf3293,c833de88,e5b2716a) -,S(818911ee,6051c4d5,19fb7785,d52c6f27,a82e2d79,a4a55623,909f3d6d,b549e851,5d031307,a2d66fce,4b607967,f662bc0,af855112,11cc209d,8457ff41,968fa325) -,S(bf5900a7,7c211a75,231ebe58,17f91748,c957f5ae,b98377b1,9554fe90,d11ff226,d910b2e3,1760f0de,838cc159,7da6915d,e6c3fb29,80bc0e65,e87a36f7,749cf1f1) -,S(654b4257,11f03dbe,75b7d60d,b578d75,20e7cb6f,4923f774,8799b4a1,df06fa16,12c9e75e,26d3ab4d,645a7a64,d97eb6c9,356a3951,fb715bbe,9e42f500,a0c3f44c) -,S(33a425f4,f178af6d,48b78873,cf70da66,aabbaae0,397e6673,7a9c6074,15ab3d2f,1e5aaddf,d76b1b91,14016f02,1812d7ea,18decd14,ca3e3925,89894151,92178cb0) -,S(cb088930,f0ba3995,d7542d48,92ce47e5,5d8fdd5d,7adf60d9,3651240b,12fe7636,aad156ed,f0b25c30,e4bc3784,a1b7857a,4cabbe5d,2ceffb72,ca2cb7d2,45ddb024) -,S(ffa9e81,afb11dee,83a54b47,fe9b41e4,de4191af,7279d19e,90e1c528,7c205c0a,405233e,b20a4848,80210b40,18c098ff,a0a17203,c5a13b12,5ec0fe92,1d1c3567) -,S(92ce3be2,8fd6c9db,be1cd4d1,f58005b2,af0c136,89181c52,a67c2503,2649a6af,cdb840c7,7e0fc2c3,d4b959c6,6fc47142,622c8a16,b30168a6,c62ef368,8bd23932) -,S(46079065,b64bd3d3,3e3efc91,374e1443,69adc4a,bcd2bcfd,91ebed0d,88f78cff,b09653a1,1c0710bd,b737611d,e5d80e67,a516dcc6,2ee3f63f,e2d6a7,f3794ae4) -,S(5cf961ff,de982138,958471b4,b316cae3,6246ae74,e1309400,a3acd118,e4736c93,ab8e425c,ab39325b,b94925d7,795d8799,18efc449,e44c9f03,cf7bf487,fc32b185) -,S(d8fa1009,27c1aad9,6ba97005,f8a24013,bc29082b,ada0e0ae,f6f72ec9,8abc4240,38d88e5e,183b2c09,d53adeb5,8d0525f0,83a512c4,1dd64cfb,a7024602,f39e484c) -,S(cdabe8c6,7d0d4627,54cdd3d5,3e70bcba,e2ec925c,a46a4536,ce3be9ae,e0b37d8a,c2032dac,527cd15a,a1d812ce,1c658cc2,a0a379a5,2a30613c,2737812a,6e683830) -,S(394fbdd6,7069d83,8fdf87f7,b1c179d9,1a491ca3,680f0103,46de3299,37e92374,5ceac741,828ac862,7fcd587c,69844243,d17ba038,901cdb42,36e96685,d589a693) -,S(84eb6d44,103f56df,96617c7,11c79dc7,a6161189,157a0782,74fec78,fc5f6c37,57a16660,4d1fa3d9,cb358e7a,47984a00,6926df57,4e06a313,7b3c7524,2e882320) -,S(295dca03,657995e5,d432a606,da12bec9,fec8f4f0,582d75dc,5657c973,7cf1051d,c4df0ad7,b1e3a29d,cca4120f,478a2d63,f18fc67f,bd201be4,e2fe05fa,66ba2d6c) -,S(b42d81ca,1bdfb038,d7888194,deda7307,eb846bf1,738d8b7d,89663bf2,8097fa7e,2d913cc9,93ed5118,1082c85a,42495133,ace8bc6c,65530309,c6e15794,aceff5cb) -,S(48484186,4f6d8f3e,94977a3,45bc0db3,1330910d,4c555032,da8da876,912df644,7a78a8c7,68c9d9ef,b5242fcd,b7a5946c,5fbedaa3,2914339f,8b0c0ac0,eb8a3146) -,S(7376d600,9a7a76b9,dfb7e225,c0da3186,b683fb13,daed9fdd,25ac6606,7e7d2316,fc733036,dabd7c4a,719b699c,da115547,8a52d69f,387b8a94,28744144,c0502901) -,S(9be9c65f,5fd6cbcf,522eb9ca,91427f68,152caa2,a152051e,3919307c,9f67ab8f,14da6642,fa3b7c37,41c9f953,d1e01c09,267b7885,8414fe5f,24f47c4,b44c413e) -,S(7d0ae5e4,18d6c6df,45f6d26a,7e962335,4ea1a338,8f183eac,85b1eac9,1962e2f5,551eedf8,264763b0,913307a5,14fd9e09,479f43a8,87983e69,509a3688,d09308be) -,S(d91d965,d3b85441,acec7257,d444cba0,6243b34,14e9665,9cc62cbd,89aea7db,54e26ec,9c82bf54,f06cce16,2cfb924,2a354c83,fe530937,9bbe733,6010f44f) -,S(44c8fe95,aa48f8bb,6c0a32da,a6263918,fc2df7b8,6a68f277,6bf405cd,1bf0566,87fc1fa8,3fea76e5,52f53612,45e54053,9d70377,cd865915,b6b78acb,f73a6e03) -,S(c7f8e825,5f2ddcfd,f21c5c20,ea84a527,2c5f6c59,99843c96,3bce9e0a,aa7ef398,5c1cf086,9c1f790,b1e59ddd,ec9729dc,2b73c6a1,be333dd7,e423a0be,bee50243) -,S(3a8ebd85,a2bd4b1e,6c0373d0,63e9cc4e,a91e6e1a,f4bd7af7,501e0160,8fb7f4d9,4d9351b7,3c3f6f36,1b86ae94,ccecd211,ee3b13a9,522d799f,e78c87df,4473f23c) -,S(bb01a4cf,ad90f3e0,5355f0b6,d1b28420,786c09dd,9db0ed5b,38a56506,4da77e9e,1742b511,43bc276f,273afb9,8473ee3d,3d962050,7462cdf4,a8c641ef,cc2eccde) -,S(eee45594,1a04bdec,a02e7e85,1d86987e,798c27df,adcfd5d8,2979960a,3983f4b9,3cc75025,9b5d215,37570928,1abca8a9,29f5609d,56c8dca4,3d1b23d3,cba3fedc) -,S(d2290ec5,120d591d,2e4e2796,3d10c0eb,e73d8b9b,600587ca,84173ce6,796123ba,c4760011,4c68baf7,b4053666,d8bd494b,b4ef1786,c1d7a522,8a656f10,1c837304) -,S(21e359ca,9b7326bc,b3380282,b9017df0,3cdfb7f0,af95f326,701bd8bc,25dc047a,68b866e8,555206e9,7cc43461,34c3a61d,ce2a50ab,2b514935,a05f8e04,ad95c70) -,S(b4acba20,94b35033,5095b208,9126367f,3203efc3,35caa43a,51857181,f4987e42,fa0f72af,77db4913,af6d906e,54eb33f0,a3e9d20e,d366c878,3b7c513c,c5165c16) -,S(5ac6b2da,18754c30,9ae46ac8,3592d673,ac5d61e0,35ef1b4,512aa9b6,7551862a,e93b1d74,105974cd,b6bd3043,c0dedb8c,b4eaa81,c949999e,68d52fa,4a3941a8) -,S(4a53cad7,2a894cab,9b761157,38ae78b0,c36c293,c60ba8d4,b87300aa,792c51d,4b0dcfda,b890ffdd,cf8a6a71,15f2a351,d883ad8,fe3d15a9,118f3e04,43f840c8) -,S(5edec48f,7d8c9b4c,af3371c2,6e054392,755fa073,1e660971,4e089b04,2a07bc36,b18b8d1e,407f934f,e526fa5d,38b3a408,76bab92a,2bc192b5,b7c206ed,6ad040e0) -,S(986b120,618abe6a,d965f9d9,6f50fd7b,29f1b897,8276ff8c,562519ab,8aa92890,2c981569,23ff1809,1cb47459,bafc0d51,699740b,ca59dd7a,14e07b9,432f681) -,S(8c61517b,397d36a6,b30f0894,98d525ff,bbda959a,126e9be6,f67b9831,e5e7372d,f7608f24,130ce8cf,56a7b762,c1563519,a4be88d1,79e90f1d,b432ac05,d472d771) -,S(d6abe67b,e30fa40,b642483e,a6ae7ecb,4217a07f,35546f97,469aae99,a286b8f6,b5e5675c,91aa08d2,a5a77349,5f1ad2bf,8b6b9dbf,4b35dc6c,262ff1c9,8eaa70ed) -,S(26be12b4,ae013009,45c8ec05,58edb030,e19a75ad,872104f6,8642bf5b,c30f7934,1086891b,3ce97d8a,a568fe54,28164f25,4fc15953,c97d40c8,f32c0ec6,6ed49fcd) -,S(3f0281e9,1dfdf1de,69d5112b,1b86ea89,d737d09f,1cbbb71d,2400d0e7,719987fb,27451e9a,2cb336a2,998d55ca,ac12e16c,fffbbd5a,3703897d,5f566ab4,5f4aba92) -,S(b84b8115,7b1782f1,e4b641c2,a001daac,ac7d53f5,b3f1fa5a,d0a5ddc2,732af3b0,a0c8f7f4,8fa49815,7a6c590d,4ea18dc2,c586b332,2a303061,c19edf44,ebba25ae) -,S(790ab328,fd86da4c,66f0989,296229fb,609de28e,cc8cc6d3,d315eb89,fdf31e38,cdcf83d3,44d103c6,736bb5c6,375bc2e4,3fcc46f5,777d6e5d,cc407700,15d29aa0) -,S(d5fee68a,f9b7f182,20ea6525,6a591f24,da79a642,4ea0fe31,88a0b658,9006fb51,87b8608b,1b3d0d71,c9ab2c9b,84654408,af6551c7,1e8ec6d4,a8f26cb3,20577532) -,S(410f9801,4622b22d,62eef39a,3c5350c9,e80ecef8,48c4295e,2ae279ca,9623e777,53dbc737,5766d9f8,ac0b8b7c,e4b852b0,3214fe70,24386915,84856c83,6376821) -,S(6cbfa6f,fc7a6009,75edf0b,c260bd2d,258bec55,382e650d,c464b16b,e5f34eeb,de72cf4e,33028bb9,18ed3a41,d885faf7,e1d5901a,ad7a325f,801f1a36,2ed730c5) -,S(2a75c02b,3325ec0b,ffa42250,e224a4de,e0c4c12b,69b71039,4bc3040d,80e5c504,ed666a2d,8ac26964,f0445d21,f1719ada,fbaea128,9edd69bc,94ae6123,a2e6b8bd) -,S(ea2bbd57,6c0b20a5,6790ad87,29f25475,24ef97e3,86663aba,2473994e,fab39134,d98d55fc,daedbd5c,3aab619e,1288634d,f526f873,19743f81,149ba85d,535172cc) -,S(893e9899,fe1b8a92,439c1594,634ff44d,1d0a60cd,8a0183a,b810bb8e,f80d0400,c680717b,aa2ff029,7baa807,d7290190,37c73d0f,a5a1878c,9fa2a6dd,d17cbb2) -,S(d75b0a2d,1e9a20c5,398fc3b7,cacc79ba,fd53a14e,ebe23196,e4bdf4a8,f8546422,37a8efdd,618bcff3,3dd0c0c9,f8bf3192,2e131764,305b610c,88a2b74e,44672981) -,S(96c84a8d,5dd2ec9b,44a5b2d7,af3b65e4,9c07786,969452c2,5e8e64f5,a264c14e,292ed1a0,dafdf3f4,83a2a419,6e1b6b28,4d7daf88,88c7268d,70e556fc,ff55341e) -,S(458895f0,77782a62,43abb775,7daec5af,264a71e0,6eccaf8a,3b23baaf,fbd7343f,809eb056,87bb618c,a0f4e1e7,c8d05e48,95f18393,2e949b22,b9ddab0c,55d32b93) -,S(59dba4a8,d7956515,7f639316,75fecc7b,58a0e91a,6c9c3d50,7dae6d40,2e67a9df,718094a2,83e47265,1ef52d4e,db25b0b9,9e069f,391ddfb0,d9987596,d2f4ee2f) -,S(a5f92445,b7cd75c3,9a4b3199,96baf00b,f855ebf,ab3e19bb,71d4346c,878b4bb,9bb1bdb5,baa4d56,5b9c5077,c86b96ec,953ce381,17cc8d53,7b0f3957,a582ddd1) -,S(f146eff,2a9ee1ec,a3f26d6a,17c89639,a1f3505d,2776e340,ae89449b,99c8b198,1674daf7,a66f1a89,7b5378e4,add6a196,fd27795d,88969a07,a210d33d,646a64af) -,S(e67f5967,d98c1d3c,3a4d0872,12d3b65f,6f8df216,5dc14633,92c23ecf,ffc17e1a,c3dbbcab,d1971eb7,a8b088c8,c71d65a8,328bf43,58f0e685,9025db87,e5391380) -,S(32e8d775,ed37cc2e,6f69c85b,71c95d65,d40f033c,b5eef362,86d4499b,fb6071f,2fbb1d8d,a6364791,95ecaf52,6f63eb86,e4604973,edebbf82,b796d88b,ade44334) -,S(b98c7cac,475ee4a3,c1815a17,e460f76e,e5334b27,e1ea319f,be8924b5,819a473b,d7f1bb1b,a653f20d,c7145420,d8c8c339,d789ee60,9b9ff0ce,73910b94,3deeb88f) -,S(d9830fd5,545dcca0,ee37a402,9f406cd7,50bbaf59,e60a80fe,da976bbe,ff9027d0,cffab795,e45a2833,75e7b861,728421d5,f9e22d03,44f835a4,c55207bc,6479b947) -,S(399fbb5e,4f4e27ab,3e737a32,d065fdd8,c003ecaa,84a2430b,4a7b4d40,eb6f9721,93f7b541,121d13bc,480f7868,ac9d8302,6706d2f1,a46955de,a3912735,c5f02e0) -,S(64e067fe,17127128,6ef0fbdb,b2adb4c3,395a1ddd,f2ea76e6,261e6cf0,112c6227,8ef6afa,4bac7536,a23f08ed,eb8656a3,47a13f25,2dfacd37,c215cc3f,473687ab) -,S(57eb5e46,40721263,97f0d12a,532aa1ff,abef7822,4ba9b10e,8fc95e1c,6075a071,8a700d2c,80df0b4d,7e2c9291,9a51e565,8dd6ba5e,59bf1503,7bf7a0a,935545a1) -,S(b83adb94,ba1874cc,c61ade9e,43093cae,5bd86ff5,e86615c1,abca14cb,6eb81877,93417bf2,1fe01c85,5c6f7782,a5cdb01,a5d13b29,d719f0fb,a2373ba2,8bada7f1) -,S(7a90bb49,71537bc9,3d1bed23,891e43c6,e350fa37,ef8e73a2,3fd46ea0,5ed879bf,ee0fa59,3a51af19,70a6d8b7,22d42bf7,ca253572,2324a59f,c041b3e7,305fa3d4) -,S(195e4afc,6c95d6d0,8273cb0d,fda2da3b,4696b569,650d4230,4d396fb,3e653831,44075199,9dce9d6c,f10ef736,7888dbb3,a713423c,f2881cd5,76a681ce,6fee2c8a) -,S(28ec566a,29bd09e2,f8b228b9,ff2ec49d,56660734,f2ea864e,856be0ff,fd6f60ee,5b4f5e34,298b5a56,a6826143,8ba59d25,4922078d,f36dfdfe,d4e8972c,647fe031) -,S(1e005b72,be1bb77c,80512581,58e940e3,544cc133,a76ddf49,b681422c,1815cd22,9c523adf,4ba5d753,93e432f,491f8e1a,435165b2,f40f79d7,889d82f,8951a25a) -,S(f54ae39a,d074c399,636f0dca,682b9405,4e87e87,3132d7f9,cf79ad85,fa82586d,db2e9b90,1c2dac2f,f4851f4e,b0ffae7a,4c0cdf34,ae9f964b,841c539d,84040667) -,S(bc8dafb8,d385cfca,3643fc75,c8a93f9,792d2b9a,715269b9,ec40d581,5936e6c6,dda791ce,186ff28c,db7636ad,4073996c,4a2e2875,80da17e8,90d03886,1c14aec9) -,S(60b6ea82,627f5414,16978e7d,3c9d911d,9d9de92f,3baa0975,a8de4e3a,8ed3ab2d,64693ab,fd095109,ef89cdb2,204f2f3,89dae035,f451fe28,58fcb4f1,dbff0999) -,S(9c8d1352,bf291803,22730718,5ee65aa8,b14211de,6d73dace,2937cc6a,1ee79134,3c6e0d66,48f3fb6b,23e6e4a9,5df3911d,797afb50,9c12e90d,7eac557c,7b1a9505) -,S(bb2a8344,2997babd,6cefa2a6,1c9d2fc7,a42db3d5,bfb19334,c7535bd5,630be896,20de4f27,69596e65,edcd695f,61a0d8,3c8925a0,c8707470,9e84bd41,615ac75f) -,S(ba8bca72,496a6046,7b250a38,cbb536e3,b9fb9ab1,43800655,8ef5d186,2b66d50a,81abbb33,e835f864,3d075858,7ce59671,7e08c1c6,75af4c5b,eb80429b,9dc46aec) -,S(529fde52,c4d1c978,405107ba,d862f7b1,995ffef5,cba4a59e,d71b366c,28e17b46,ed7c2521,d39ca130,60d5f509,d0a8b0b3,40eb78c0,d4e4fc4a,83318a65,226d0a05) -,S(6e0e10c9,4445acc3,593efdd5,4b8ea1f9,db4a45a1,4c2d0a27,edbe3fc0,7a90e91d,43537a25,d2091290,f753460d,8816ff10,41308e6d,fb04b7e7,d5a108d5,c9fd83a) -,S(b2f90714,6fe2e01c,5cbd73a0,c0a358c7,a05aa730,97a060ff,491f362c,75c20e90,d0e680d8,f7d27eff,12b332e8,a92b846b,4242a746,9b31740,6c6af499,5ab51948) -,S(bf631a7,933e3ab5,f7b8707e,55a9498e,31ec3f36,970bb9b3,f5efa0cd,1a3f28a0,1030146a,387d4fd9,c12544dd,a448133a,49b5a6e0,d4b96933,cd47e89c,608dd5b9) -,S(cd7ec470,e9d5e3fc,a4c344f2,9edcd4df,4b7033ef,5e7ee99,de0db6a8,43926034,3aae77b3,bb008cb6,e982d673,7f78e920,f3a587db,bc106c0a,25c65d45,df8a4f6e) -,S(b3ac95ff,8365813e,e71199eb,946b5888,7dd34b1b,a214482f,dd3b7fa,3b8ce6b6,e3d9bbdd,aaba7887,8e763360,abd370d5,9d941ba5,cf758d33,3b480f00,ec5e7672) -,S(7fdc21a8,6962fced,e6f9fbdd,77e60a00,4dfb858b,5b149362,dae4b4f4,a4ab84fa,2ec0f21c,3d1c6d60,f22817a2,954d02b1,ce6e8b91,d826c11e,f8e542c4,245a55f3) -,S(6f019691,def39afb,103e524a,598bca92,3c99e44d,7dff4866,f76fb6c4,47e6b40b,a225b484,cda916f3,559e5782,3b519827,8bd7300a,c31dace1,7a797582,2a2e2a31) -,S(cb9a979f,c4e8d887,f03956da,9ac89637,579813b0,c3b27874,82961a54,e54c16a5,ff42bdc3,1a837d98,b7d37a38,db3c74ee,6109e868,d06b7c33,d5562dde,b11ddbf2) -,S(2ccee51c,9d63f3e8,99314da1,656cbb15,635928bd,309cde4b,69699860,c0e28736,dff9a128,adb8b4fb,7bcaa1eb,6bfb390f,226b2ae0,b72443a4,5982d559,91d379eb) -,S(a239538c,c5e0b53e,879f484f,7202a52b,d52d1cdb,ca7ae7d0,639850cd,b2c4f57c,6cc1f9c5,8998e347,2c6db0b8,6b1d9092,d3cd0c84,267bea8e,75a172f9,f4879dd5) -,S(e77796ac,c619974a,63476635,7bb3bf33,6ad1e87e,8496bac3,378db956,7beaee90,3eaa4b63,c9679050,59d8cf67,7b7095c,4064534,1c592ccd,ddb7626c,10586f0c) -,S(52c332cf,37646a2c,c1bf25cd,26a6131c,3b243688,9c44d804,d2762fae,618250c6,2279bab0,a19f78a9,43e695d4,53a0dc3c,f0312987,6ccbb70b,1d61eae1,e92729bb) -,S(d68826da,36e5f78c,bf728468,88bbe6ef,f6e55d34,f8b47a9c,8296e662,4ad9bbb3,88ffeb15,5f70c6ab,9b83f9e8,30e2f449,7e661dac,889803a6,d30a2ddb,11bfca5f) -,S(af92bd8a,2a5b0034,ea074d69,a1d7a517,808d3b61,58f5f7c2,d3fb08e4,eb825cf3,2fef9245,a4a3c837,d4b57ded,52009294,c077a801,8f633313,b6db2d4c,92c724b7) -,S(df86fa3f,63d95d73,98872011,c7545b3c,f5f27fc6,a821bff4,5d09afd1,bf76d895,a891e766,12953c4f,37a463c5,ce449574,b1906c63,c192ba4c,67f4f78e,d1e93a35) -,S(a049a35e,119e27f6,e272774e,f470ca50,9a1da9b,a4e5d781,6e64a13a,23383c24,4cb8e2eb,ccc82ca4,a2f82841,34eb3a05,f85a2335,a3b1b117,92886029,96fb3fd6) -,S(b3193cbb,f3c8f3b0,b47b1a0e,5689461a,8da801c2,4c8d51ab,fc2e67b,1d9f331,2032a290,3f0cf0ad,21b63de1,565170a3,edee470,a4dbbabe,5f3d459a,3827c7ff) -,S(ff3cd387,554fb3a,89142ff7,3e97fdd8,884964bb,2f457283,e45b79ae,ef1d692d,24475b62,c1ade1b0,ba36ad93,27916e19,637071c,22fb59c1,f2108fb8,d38ec5b2) -,S(c095d24c,42b058d,c2f77e2b,463a2c7f,1ddd1dae,dd6f6111,11ba78db,26763204,d2648519,61974d6c,cf66de22,1028943d,ceccb181,ae03cd38,fb5aec22,fae54326) -,S(5365a446,389f54dd,8279826c,e1e7df5d,b4a9699d,b8208efe,80d1eff,2d883ee,74625a49,b7856c1f,b157776c,cd79270a,2957862c,a437bfc8,75986264,401e714e) -,S(4c073085,e96134b7,75248412,c36b3b33,77afa275,24c83369,a2477b8c,9851f15e,fed40d9f,a44f64b1,59c290e1,63d1add6,92bd2782,51de71db,e302cbfa,67e508aa) -,S(71edf152,ab95a066,2b7e5190,8af75f38,d03d27b0,3a3b6607,4f472b7,706a3114,c3e6f145,dad44a3d,5cf056d6,2c608b4c,840608bb,aa15a101,c9bd3cca,e511741d) -,S(1b7d41a9,3cba67ad,c145962e,7b2c6353,bfbc8eed,34eb4c27,bfc181d3,1ac0a802,b165e7e4,23c5d880,1bc3bd1,ee0c6778,50986b35,9dbad06e,aabb2f57,dbe553bf) -,S(ce997626,cb41ab98,58f591ca,c89f7a73,bc1df836,716ee74c,45c4c781,eef4ccc9,be76f81f,a8e4b053,f63be23a,5e72ad6b,7aa359aa,e9407b60,98bdcadf,e367b167) -,S(5b0cfa70,aeccd544,cd634d10,a2bcccdc,33e4525a,54259ba9,92c40100,698bbf2f,ec50e655,163994b6,4881369f,b3aab550,65df1a5b,dc6037a7,7c01e56,904660d2) -,S(a03873b9,695ee82a,42b72a90,f0cdfc68,dbedbd2e,a50d5ff6,e120d811,ce8d5097,5947c8e3,56e64f71,b36fc1f7,7ecfc7f,a31c0f0b,cbb05102,775648bc,f2435758) -,S(d6b91cc6,6dd31e59,f04c6e58,bd7448a3,fac62753,68579214,11a8b42c,66084ed1,fec7fa6d,778c0b63,e7dfd72f,ef044da0,903ccfc7,1786f0b1,85edd004,f691a0f2) -,S(896a1313,e0a96d35,9fd42841,7790baef,a40647cc,f56264a,ac3b72df,687b5692,831d4b47,52f5fcd3,4942ca26,95dc86d8,4fe49c73,7c2bd46a,f892eef7,304117e6) -,S(779e7400,8e564167,56795a4f,9d2021b7,94aa9689,eaa37780,8e3a6061,b5bdc04d,739ea3a9,4f38be31,df57c052,362d1872,333d2777,c6704c2,e69271d2,9f78b123) -,S(f20988a9,3a3273a5,a015866a,c4de930e,507b5b48,cc5ba52f,a2a71e9c,185e72a5,6c861907,8fadd612,c0535163,dfa4cf39,648b59d6,4b056bb0,4e06695b,3b51213a) -,S(7e8520e2,3151c78f,9f48bd10,5aff4087,dd90f9c4,2ac33e24,19499ab6,8e5b21aa,995827b,43c276dd,61403388,27b2fb9d,9fbb46ec,af10b65a,a8025971,608f38c9) -,S(98f0e4b0,9e72ec0f,d80ce3ad,eab29913,fe84fa49,1786bd79,7f6832cd,7ed4dc6a,58c42bdd,7ca43579,b45df8f,b2a6db3d,41f75a3f,89dfab0e,e000383,c9e04a54) -,S(31cf38d3,dec1162e,e75eeac6,6827aad,22fa3ee9,abfda002,b6956600,6fe596ec,ceeb4b04,fc6c31e7,7a6260ca,bdf92569,92841221,d60ca74e,81309472,8fff4442) -,S(60766d5b,50cc4d46,a1234c92,1baeec1d,29900e23,4493f174,2f06ada3,ed9dfbea,13debdc8,9795f421,6f796a53,74b87aaa,bca4f73e,fda2ecf,7d151870,179c44a4) -,S(1b0ebbaa,35e8ecb5,a76d9c30,ab88fa10,b211ce3,e7c2b428,117645b6,881c7895,a312adef,e1c4a34c,d9f75d10,bb2ceb29,79184181,bb955439,e317cde4,202b2f83) -,S(b3129f71,c3438602,c9c24ee3,2f997341,26dbd76c,60cf7713,200ffb68,e486fc94,bd4beeb5,70966285,6a15002e,a25046cf,996a1cc7,9a570549,467ac179,b4f145f9) -,S(2925ca17,662f0905,3927d40f,f2fdee1f,66cc5c13,c3587e78,fe48effc,40cc075f,6d37757e,64f0438d,7bfb3658,5df58dbe,a8ab8cdd,89871670,dbe221b7,4c416185) -,S(8d55b85e,fce6bd0f,ff8906d1,6497d35e,4b69e701,da7845f2,aec1a049,39c9ec45,435416dd,9fd01388,b717ba9a,df574456,785cc0fa,c115dc04,8a242270,4a3c77dd) -,S(a660a9bd,b419e19b,16823b5e,dc3fcdde,f1021b71,4debd17a,9a0619a3,aabc23c9,ef6d4bbc,e963bb1c,2edffa5c,ef70e330,bddccb4b,3b23cc52,d5b4a689,e0c76c32) -,S(8896427f,c92bdbfd,59699ec2,222b4bbf,2198e160,94945c77,1f207bbe,4cdd6b0b,bc6081fa,abd2df26,b087acbd,a2c67c63,2eb1a8dd,6fae2454,6f3fa747,be421ff1) -,S(47e5d9b2,3f429484,61ee9f38,2f14babb,f93e318f,32d67063,ed20e917,9894e993,bd17f8b5,6084d3f6,62facae,24e93e3e,29205f21,68903ade,4f7476a5,ba70e8b1) -,S(ff352870,69bf1131,6f530ef3,b32a487b,3f11e6e,f8518c15,b1202a18,4e6d5487,8920338,ccf36f98,4afde38e,1a74528e,86fddfc7,8d7a6964,cad4286f,231462b6) -,S(2a713d8f,eca88def,b5fda7f8,8de9c6cf,9b97bf0,4c070173,aa47dad9,197bae2d,5ba64900,f7d18ec6,8887bd26,d2769b0,26d22e96,1007b58c,b27b8983,a6e7adb1) -,S(853d813d,3133ed7d,a85065a5,755ca0c5,3f32f156,154853b4,b018668c,b165ace1,fda8017,e00d20db,6ee4c0a,5790b504,afc376ad,170d74bc,1261abcd,241ea020) -,S(d5c4dc15,37b048d8,6631fd14,7d896d6f,f403ceda,7de8883e,1ccc006b,6d9ccd99,9ea2829e,64213434,eaaaadc,43ed10b8,28e706a,5001d7df,47146058,8bffa8ed) -,S(f649da82,d50fa298,8c598d5c,caf1e7f7,2bde2cc8,8073b55a,2e43b6e7,5d44905e,4438f4cb,d3e1938a,b461b1e7,b94d8f6a,c6e287e2,50d06da6,67aacb1c,609bb6cb) -,S(adc3515d,4fb7776c,b1592a69,13254d7,afcb20bb,8a4d7529,7ddba70a,c35a7193,49b7bd8b,3f280916,c6024e46,afb45e6b,da5bb15f,3d3497fc,85e9a46f,acec3d80) -,S(d78c46f2,603a00df,b45d0495,c1e2b346,963dc82b,84512cac,c2227acb,383f75ed,76b02870,2e7a3da8,79272759,1e2f81ef,54ed02f,debde8b5,38f9ff1e,4335a21f) -,S(13904467,59e0fc27,c2a499ec,384e0906,bf293dcf,c13ca16f,d3bedfda,d320e466,5320c884,b74bcdc8,6e0c21f5,40c16f65,dc61f19e,9ec5e8ef,385fb637,ee7a3701) -,S(93700603,543ec558,3fe48141,310b184,aa8faa04,6058467c,389c10f3,b98c42f0,8e0acf55,bfc585df,4f8cae06,131753ee,23a7bcca,68354182,61450e1d,e1a136ce) -,S(bdcb9434,4c556618,a247c935,29c5ba74,c68f25ea,a5507148,1431c00d,6926884a,c29b7b1b,ad6ec5a8,e7046cf7,cdf99c6d,15f6a3e4,3c6ce718,9ae2acbd,531bb17a) -,S(839ac85a,9337818a,b07b5611,f67eb16,6342c1a6,8aadefc4,6842c023,336afb08,88b30690,e79fb157,3e424c80,75bc810a,fb9d57de,5464a253,79d06222,ea656b69) -,S(2959c32e,bcf9289,9882e003,c8a28e71,3d491402,4d24d878,ba8bed88,47b949c,ba2643c3,95fac027,6b7c55e4,d2d2f530,318665f1,ec2065d6,eaf32c05,123e04c0) -,S(71116eb0,5def3abf,bff3e235,a0306605,b18aa465,b47167b4,4eb3486c,c442f3aa,2652a726,35be8336,f9b51607,76b3af84,26a23716,871fa64c,898520eb,822d6630) -,S(400c1bcb,dd3e3978,3ca06e8c,2abe8b0b,9b45034,a1655cde,fb748ef4,e2a477af,1471c86c,c8b27b48,1d4c45d,1533a5c8,d46fc3cb,ea4788d6,c48dbdad,6f7670e3) -,S(2a4abe28,5cf94456,aa92216a,dd635abe,71a7e825,712d775f,d61fdc98,a4c9288f,3c0d2483,3d6ffcad,b471d234,4ee8d07,15c09719,b18cb581,8ede730,35d89c15) -,S(cb0113a,1832843f,7e32ce25,15b0b23b,8a803ea7,50b500b6,3fb89f6c,e7bb1884,816d7056,b775f13a,cfd94a6,f88f442e,519495a3,6e74d8f8,359a8a03,16583bda) -,S(4d7be7ae,5c4271f6,c1adeb7f,4dac8467,beae22bf,ae00a71b,1e353be9,5ef172fd,cd7e6415,5708d20a,9fc3b0e9,85517642,f677281b,49490439,14845a36,afe6ca56) -,S(bc285658,fd724cfe,e6ec8c7e,35f9197f,e9083bf5,439fd4d8,d9b262bb,7a3c38f3,80c10d7,59f76b4b,8330c96f,38a1af24,1d1b0db7,4e6befc4,4f085180,c1c33729) -,S(a829ee43,221d9955,38ce8aef,e80c49ac,dc6e71f,4293750c,c0585c1,69963f04,144f6b56,d996a18e,627d4c8b,8115b2c1,c369f410,ec8924c1,73382302,3758ba33) -,S(f5450bd7,efc9227b,e7d28ad6,75ee14df,1b2378fd,308e6c5e,68945ac9,a47d82d1,20201fb5,cba463af,cc46e6da,caac8417,63356e64,5cdcfa5d,9d810c48,272cf8e0) -,S(7dcbdb69,46dcf79d,454095f0,b61341e4,45243bc7,c2262817,374fea5,37a1a380,bd2cee4d,c7ebc71b,46fb3bec,bd6787eb,d2be3128,703a884d,98359c5a,43875977) -,S(f1d6c1db,cc8d33d4,fbff821c,8c788d06,2d906063,2f44a786,585a6526,20ce776a,3696a3c,8473bd07,76e77226,8cd09f96,3dbcd143,e631c32d,5d83254,ada29340) -,S(f1688e1a,d5df4e43,67caec6,f2234534,f65aac3b,79a94ca,32a786bb,9fee4b49,efb620b8,e2164685,c9a3837b,5c6eb70d,759824,96541aed,eb80aebe,4193e34e) -,S(b639e284,3ecffb0f,66c2819c,73787e10,527086e2,5d3da074,e037a915,e06a5813,61fde1dd,63ff304c,8ec99d4,67ffbabe,e8000637,b9856bec,344b825a,4f198407) -,S(11a4ff89,d5e63ec8,6a0ce18,53dde8a8,875c9a9b,f563526b,cd25b830,6e3314dd,9f7ec77c,9a3f88cb,7f64b1ca,f2b5c7cb,d70d65d6,dbdba9f2,68832f3c,a2e117a4) -,S(323db783,26abfd99,2b13d67f,3ae01415,77162203,c50322c5,7a7933e8,7d687d3a,92c8a67c,ec834653,d0f1a50e,a7834b38,631d83ec,ee38e50,33ed927f,7e14253b) -,S(2907fe12,c8433ab6,2e6283ec,85b93342,ecf14d16,6d90cfdb,b4061968,aa35170f,160f9790,66291ed7,d51962d4,be02d85f,8a92ff8f,258a9a07,55b8a5ca,2d57c2c2) -,S(67cef7bf,a58519cb,6c5cd8c4,f69d5cc8,84cc77a7,854a4b6e,a40b6dcd,57e43e17,e8071d35,e590dfa7,4d4f4da2,82033f1b,590b9383,70b571ac,ebb3bc11,b9b48482) -,S(81e40522,3d4ccb14,3952867b,b8398cd4,e5ab92c5,d91066b0,d1fdeaed,55c71165,55357564,af12b507,b2e24e6a,425697b9,e6356b82,da36f111,2b5c3394,183c0d10) -,S(4880abe1,47bcc598,a3743304,1afabe99,fc525daa,564c4b05,2aa60c27,5c814628,b6d944f1,ec69e7bf,2cdcf621,864ba76,a1df44a7,ed15ae15,290ddbe5,b91f585e) -,S(fa2bc507,19131dc7,d5f23fe6,9e60377e,2d2f11c7,f8a9a451,82aa69e6,24eef53e,9b0f2017,5f287d80,41f58930,6cd022e5,9b63bab5,1b26abfe,1a295ac3,46a2e9fc) -,S(aaa18fe1,25e781a8,901ac351,38d2bffa,83cf7c3c,99a4c7d8,54b30c70,c9483e8,6a8f9e1e,a40f6383,6008a0c3,596f7644,c044bf53,9700a142,ec5e3c97,c075b03c) -,S(d473950a,8465711f,71a6f1f0,22f4bfcc,1c16ba81,4bf73c2c,1eca244a,da4999f1,6eccf9c8,aafb09df,46ca0d36,ee9028dd,1df62bdc,6ade77b8,a5d410d1,a69bc775) -,S(d7e2b17c,f8e1895c,cf9fb163,b56f4be8,ad99133f,f00f2ce8,8ce911d3,3b8e36cc,b6557693,ed9371ce,69bf397b,56c0b566,21d38958,ebdc0b96,ca488570,1561e6bc) -,S(3f1e73f2,a2192809,acaecea1,71d175af,683e796,e1337db2,11b6b34,8ba924f0,a593bd94,96308bb7,76b63703,bc11e30a,c5f01c17,c8b9748f,3b4c8015,56f52c3f) -,S(4cbb68b4,27899c92,1c0d969c,94341d8d,161f3b8b,3fe4cfca,2b583a63,eb383dd2,6b3c29d4,97728ac7,b45cf7ce,ea618789,95935bea,bd146e1,6c756f61,4698b6cb) -,S(e41b826b,52ff9bea,354af41e,3004b7b9,edd01e13,8cbd466c,ba4cbab8,d63bb4e0,75d5b642,47388aa1,51d4d8d5,2568a804,fcf66ba2,42b3f56b,dee0350d,ecc527ed) -,S(d508dd5b,ec38f795,88bf2d9b,6bcc9f8,aa96689e,91c1381b,9f8db311,94588028,9b144547,1a2ee559,6584c927,2d779fa3,123a760d,9faeabfa,1e39d3b5,ddac2595) -,S(5276f127,3bad7149,ee5ff022,2769dd6e,973018e2,a9948070,fdc82148,ac637de0,73f778c2,caca737f,acd3d877,14e24d83,964dd47c,f22915e6,212bfb09,8e804e21) -,S(2e9ebbb5,9d108d21,71d28c27,32af659d,b534cd10,c5457cea,3fcef018,4d7761a,229d20ba,cbf0104f,b385621f,dfe386df,4f40c287,7d956046,60eb3923,46937bff) -,S(ad819539,5b94bb1f,4e60ab85,932b24cf,2c79c20b,79a972bd,db1e4201,c49f1d1f,9226c45f,4d161a1a,c5c3c0ba,a0536def,3c6052a4,ec22dd24,cc803a37,b5d791a1) -,S(f5d4baf3,93ee5acd,944b2057,78cae170,8a622f30,68d3147b,62bef05a,88fee96f,9a187396,9eeba528,9f5fca32,6bbb922,2eeff5f6,6d205a0c,78b77dea,ee17d1db) -,S(1a0f5e1c,b2fb5d01,fbcbfddc,da83693e,9619ea60,1669c728,7710733a,e6ca778c,3074e8d1,61da2d34,38be57cc,fc437742,533e415e,5f0c888b,834a2fe5,5d4fd6bf) -,S(a78f6f7a,110cd16f,99fbe16e,9be52782,248518d8,e621f478,2167887,f81cdae4,e3f78e8d,507f9af8,11653ab8,5f2286dc,db34d9dc,8106e9f0,57610267,411f02a0) -,S(c53e4243,b26ebe40,a1abffdf,3c42129c,47e92cb7,32bd66c0,3d4a4290,c68b1c25,bd4f96b5,b5801b82,300b2132,2c39fd2c,65b2d084,e657ba2d,7db5df15,ab960e34) -,S(a3a1ddc8,56957468,2e9b8a57,50bbc738,f72dc60a,1c09c95e,a6559b2a,736535e4,94887a0f,a4381d9e,dcc4faf5,1525ce98,fc43116d,29f68c99,236e4940,6842a741) -,S(8160ee7f,738f54a0,698806b8,35ed4bca,113bb568,b23fd331,ef5f1cc2,80b6230b,382ff30b,f13f1e28,95a38af3,13fcd099,249b195c,96ac42a6,6a929fc7,a907b17b) -,S(68552ddc,6b219554,dbabd276,e0f2a5d9,33610bcc,776bc40d,7efdc1c6,1b992e35,eee09352,c82dec92,b0ae8d8c,d6918ac6,df620dec,86a0e4ac,abfe8025,52a0ab5e) -,S(919fef57,f308255e,1fa802cb,5acab880,c1810c62,c79a4ecf,c2251a2c,cc02ef51,cb38c163,8f7890f2,d61a980f,ed712ca8,97296366,7927ff7,39de824d,207ab566) -,S(d7e493e2,e2c33635,ee8d22f3,76fa8de9,31ed4eb0,9771746,f48ba201,307e04d1,ff7e6d72,f712f2be,2bfffb43,2764f677,62917509,3cf6bfe5,eb5cb7ce,85c1a8b4) -,S(6b642a8d,f4131ddf,7f31dc9f,c26b96c9,286e1f80,de2af96d,52e383d1,ffa73a41,1e55e667,5f0ee13e,76818c02,ce424d8f,48cbc930,b25dbb85,363019c5,fc29979c) -,S(7ade4aa8,1df8c53d,1e64655f,bfe0ad88,4057e0b2,1c88bb2b,4c8d5f19,34794191,cb0e9802,fbf1027f,dd8d2167,f4f4680c,f9e18f4c,3bc3310a,c4014745,530a06fa) -,S(6d578cb3,1ed19dc,812fd360,a367996b,91a7ba42,7d2f74c3,e2a1721d,72e1c017,4ac9ad2e,aab987ed,dc994b74,733fc710,19301e1,f691999a,5161cb15,ba11e9b4) -,S(df95b5f7,7bb79814,21892d72,743abe4e,828a7544,f9f0e774,b1f5ada7,a054978c,4ccd011f,a966604b,32f70bd6,1a3c1515,c6d1b261,a3ce5c59,7078cc9d,f723b32) -,S(d7392d17,1cf72e1e,ddea0be,a242edf2,c418e9eb,7dcbe1b3,aa07ae7f,a11ef08c,4b696f78,20a9ac8d,a5f52c8e,9d1a39c,bbb3d3d9,fb5b38c8,1b46bcfc,90e869ef) -,S(f01f2aa9,82842315,98f414ae,f87c9d7b,6eaf21be,c4dddea1,3967677f,5d2a1032,7c3be753,da5485bf,13a4cd72,a9e3fbe2,28fc6a22,c502b19d,1b6f7d18,149e2b3e) -,S(cee8f811,4b1829ab,a47e9b5a,54de7cba,1f6edfe,624f30e2,ec4979f8,3145242,4b01f7b4,cebb1125,20bb0ab2,7013af9d,11d19c4,14b0c29f,d142c7d,5b903a09) -,S(f4215bb,973b5586,ec051388,203b1c99,cf69b555,6b1591d2,fc711842,759e9832,5d8a5ce3,ece7c011,df3d414d,e62ecd4,2d716c73,cab02e29,621307e0,658e6fe5) -,S(e39ecc23,90c9464c,32b08759,9a44586a,da09af95,ba8a3b30,2cb015d6,4a49b18a,bd7957c6,e1feb061,f5535231,4f5c5e5e,c8245f28,4638f390,d079cffe,bd2eea7a) -,S(9e6bbe6c,402e4cbf,e298e789,458fa9a6,68cfd407,3efb3d25,4699278,760589,989bf3f,9912b242,419c848c,f82c3fb6,8690ab05,bc23372f,eb9a850f,b4dd44ba) -,S(67504bbf,57824cd9,8a3bd82d,34fcb59,3d20590c,a90b5652,c4ea4695,1f48905d,93ebbf6d,3678478f,56ae5a54,cde812f7,d8d40928,21b5e82,71669dd3,f0b263d3) -,S(4e5bee50,503a28c0,9252b9bc,dd28af66,cecae127,2128e88e,fc431373,7324657d,d6891df5,3a4cdf2a,d7ab610b,817b0f60,c2502442,2e40269,a7da80dd,2672e0f3) -,S(7481d5a5,bef3d397,533e01b3,640b0809,fd6ff946,a1e5481f,b90f0b3d,dd05c21,21ee7275,9c217d19,3999df2b,e3cddff6,fe59f26a,e570e0ae,58868441,f37e342b) -,S(778dff4f,dd32f251,6defcd94,188f2440,26b9f789,ff4eefd5,84b2c15e,2bc61d62,996a2edc,f43e10d6,93cc2d00,c6f4506f,45be1dc5,c762fe20,3dce124e,34e320e0) -,S(cf531271,3d65d471,929f6108,12db63ac,b1c52203,eb879ca4,a8ee9f62,774580,38e28f4c,881391e0,55fa7148,2c92c097,c842dd,74a58d6b,5753d6e1,2f773b19) -,S(99702d01,9420286e,723625b5,62c8152a,2dd5f1a,eff84437,8a182cf4,25582031,8c4af2b2,654f1631,82d08bd6,e7f8b6ca,d5365b9e,d869fd23,e5a3c4d4,7e5990c) -,S(68614c88,6b59c198,c49245c1,e1232cb0,b4bcce31,e0a2aa15,9fb2331d,ff1dce66,49c870bc,7ac78e22,b635c2b9,6f29e641,3b29c6ec,8ec8b3b7,8fa6597c,90180c7c) -,S(f497a9bd,3c0e923d,5d622ab6,afeb9e8b,d9b4525f,d1f30cae,2a44d0b3,e13256b,af4d0273,e088adb0,b7de7724,b387e109,d49d20a6,eceb369c,12e07eb4,f28c9e32) -,S(50a764f7,f5e29cba,ed7ababb,97d2ace2,22c06c65,9ce87d77,83b5bd0d,d165bbbe,4abc57c5,4c9f1d54,e73cead6,d77a85a0,8be25ba0,ce96b8a5,1b4fb460,5eca949c) -,S(fccfe1e1,e312e6a3,92e83cb,97274576,56415255,b127ad54,432c93cf,4ae29bc0,e681795f,d8340902,da0018a0,dbb8a424,870e4bcf,7de95f0e,b2c7e98f,47a46c58) -,S(66de61ba,48c1fd44,80d5c78c,3f06c3e2,45ecaf25,e4c235d5,8408c90,e1b62ed1,bf3bf086,a90221ba,711819d0,d80194c,c45177e2,57b1408e,7e649f15,a92aa6a0) -,S(4373e7ff,e3995503,97bdee9,c9d3d70b,39f47446,45fd3c1,63b2012d,58e148d6,440a1376,16096124,42c7bff3,5f9a8aa2,3ac64e8b,bd5ca839,bd3c5a39,b84e6fe) -,S(c8774ea8,7d83fc06,c36ab357,b1fa76b6,c647cc9c,ebf2e125,3f3ab303,9306ef1d,ccbde78d,2e4d2c0d,ace4e660,efdc4d1f,a1dbb44,4cabb0df,bfe29de3,191f7249) -,S(748cb6cd,c57d89d7,8842fae7,731b1e28,3b59ed18,cb761c88,a4d2e4c1,c3359fc,62f5b6c4,11c72d4d,a412148b,8b038b32,8f98aecf,ece537a7,237b9f87,646b9a3b) -,S(35a83610,30fc10f3,53d2fdbf,cf67655a,91b86555,cd3d9eba,f962996f,ecf55cbf,6fd79f5c,df8093db,5c7f3a94,52dbe6ae,bd1ca410,199deb04,761ffffc,77ec9fec) -,S(cd05bbae,d0a8d78a,2e05e9d4,1c33cbd2,8d59d384,75d42389,43f9cc35,3a8a30c7,9f7336dc,8e77fd55,bd0b9e8f,23eedf1f,d0c16f69,921994db,dc2588dd,ff72a8f8) -,S(da3fe760,2547c831,2d4f515a,5ce530be,29379325,41c6de36,364c4b5d,ead43c58,df60bf1a,d2fca43f,6d482df4,61fc180e,5e3cf692,995bf8c1,7d32a263,730b3ddd) -,S(bbd7996c,25ba5c24,a14742a9,745dd2,8c18a598,8279581b,f8b5958a,8092051,896a39f1,310be1c5,9de4b86c,7c9bde10,8035ba39,864a45a3,69573d16,4afbc2d) -,S(bf7c20dd,64ba5f51,2a996bd,428fdbaa,df1853fb,f814e6c7,a415fb64,a3e16070,afaec0ea,2b18c89,93a1a565,f3db58dc,748df9eb,4d9f8a04,a18cdc23,4710d5c6) -,S(919d0aa8,10928129,cad99b09,85bea5ba,7d4ea114,9f9d5d65,2b6c0e0f,20464903,60d9352b,d053b01c,83caa121,63e8c9a3,e2153cbf,b335943,7a2a788b,7aa02dfb) -,S(5e7c2a9c,6ab8251e,8f8749ab,e0ef107c,aee593e1,a8632a6e,1e0e0c4e,d3cace9c,74186f42,6f03f806,36d79258,e9edf593,6e21e0b2,d882d933,c0241ae9,7d761582) -,S(2815184d,af1e838d,86d63a32,db5339df,24731743,aee62add,21e3a6c2,c2b0b1c0,2a4951e8,3ec61221,b1035c6b,a7d2cbed,f6ef93e8,cff69e01,295e09d9,20e05919) -,S(e3086e36,91432a20,8602458a,87d82955,c8920ca9,fe1c079,3eed878b,282ec3b0,13db4219,50388269,cd591c5c,d8e07ba1,b532f01b,485829e2,aae4f55,f05e4362) -,S(8264d534,2db3261c,d7e294c6,eba040f5,461fb9e7,e3fa13fb,dfcec29c,20f2fa7c,4dc311ff,10b92db6,b67f47ad,86fd74be,24e3dbe0,d6a74842,92f35d9f,6e95eac1) -,S(9edbed6,3c4b66ce,a8c2ac6d,89622d61,6838e1fd,9b93c363,c2bde528,a629b2b,c1706a02,5b1f9419,2dde89fc,63ae2a81,ea015ab2,964beb58,d5ca7ffe,84266644) -,S(68006753,672e9ae0,79fcdee7,9814a904,80c170a7,f644302d,e5de7982,7684e12e,fc1209de,88ca7c3a,614252e3,153df13a,6d0e8db0,4c82d83a,fcbe65a4,5c084398) -,S(acdfba80,9e519114,a11b1634,1835d7e4,5b93a6d4,7094846a,e1ecec00,18bc4531,a4e57d02,51511f2e,5b729309,4c50ebef,4f8d3cb0,d930ff48,20d0623b,d636d664) -,S(978304cb,e99eb899,5ef43f94,c67c471d,6d42ec19,f83f9323,3a44b9f2,e2d13896,ab26782d,2c1dbf16,a90f90c,8e49d250,1e1172f1,3e1bd20a,3deba979,85fcb110) -,S(8c8b561f,9c857510,88478c03,866b347f,46e06801,82482343,923d7e27,c67f49e8,e7908d27,79cc5b19,dd00f2f0,4ab52474,5c35cd6d,4b85932c,99614fdc,64048cc4) -,S(d4a7ebc1,987b1abb,5d02e598,190f73a,36d1176,d7f0f7a8,cb9491c1,b86a3c55,4f321dec,9c1832e3,b0d0c974,798834ab,6a410bfb,398ebf58,177f39a2,22ba4e50) -,S(14bbfb6e,7910f522,69e544f2,ad3175d2,3a36b7aa,8209c24d,1fbb4277,9508c261,d16147c7,2a1df442,d8e831e5,aecd54c6,8bc3f225,4d0f51e4,9a375053,73e8d08) -,S(d24ad71e,81de43d5,7096e101,6bd4d99a,46e52e56,782d99ee,838217a0,dfea0f5b,ae574f68,e07cead9,f214976,67a18c2f,fbbcbddf,2bfb6c95,3b7ba673,7d08903b) -,S(ac96889a,f0b46b7,6896b763,8e1a13f3,dd24459e,8601f892,c3367c7d,8b52931a,b68a8631,8672c378,d99b0b20,44b06190,876ab100,eadb12e6,c16c2ba7,c1ee2381) -,S(36b4da52,4f4ad5da,d7396445,1e79bd5c,20973df0,efa82bb2,da4bf68c,55afeeb7,5cb7598b,576f0db4,db1093c5,e6c9723c,f493bb91,450a0017,9f79c8e9,92dd6136) -,S(98c7bc3a,7054f928,d062ae65,b4140dd6,293f2fb6,cd16fbba,e00d39d0,b11befd2,82d134ac,3e614e4e,62b1b475,bbb5fd80,a5e6d3e4,e4572dc5,7cb666c9,a06131da) -,S(95bb18cd,991cdf72,1c627d62,aee4655e,aaed0b6a,b1e64537,fa89a0ac,f60b4a52,c37e37ee,5b87a5a5,e61824a3,ea519f03,dc3b0a77,f755485,d337ac79,f1f9e8c9) -,S(41e45ca2,b88a4679,6df9106b,c8b53180,81674c34,9646545,e5ad9b6d,e5f6cdc6,151ba666,b0fdb7a7,18110f62,83e3cb8f,8e40fb8b,fa1a1854,75958a3b,ec10d197) -,S(32d15f16,dda923d5,c2f1bf5c,9c003b33,b77d2450,95e5ad31,2ec62956,ae092805,58d64c72,96ba6976,d61774f,f37a0d1,6316cd19,3ac0d930,bdcf4924,cd904095) -,S(41c4e029,817de516,8dc04b2a,9bde3850,7ae48602,dab08db0,3272c694,6cf099eb,303738a8,7b888601,2f9e2053,5bb8b610,92f6222e,96968afb,98940d85,98181458) -,S(28b8ccf,b14a86a1,84fc3c3c,a6a7dbd8,763415,91a67d8b,4109f026,1dd964c5,899f98fd,5e0c59be,69150d8c,5a917d6e,864fa15c,63072769,f75f6353,8cb276e6) -,S(f2776367,762d6468,c9cc0e38,d3921813,16dd394c,eaeea519,786b4353,a5044586,1a873421,1b170183,a117e420,c41d2725,84acf219,a415778a,4eb0c34b,bee9a68c) -,S(7a1a5f53,6e96ee57,e10b1337,6bb1e895,d0703c6,5adfa4bd,f24937da,98bd7144,860921d5,67fbdd1f,11aa3ced,103453af,8c3f5037,b92ff10b,ee70ddc,e4323206) -,S(d82e79dc,5d6de6ff,8863e039,60401bd1,610500f1,57fd2b41,f20689d8,889c3f76,f1947dc2,ca625df3,af5ec97d,32e62c09,2139d108,948795ba,5cb164b9,351bbf34) -,S(6a2e184c,23ee235f,93f036c4,3875db01,22416a6d,26ef54bd,85a2b465,defd0351,6c44297d,724eb2d3,2f58a197,2f52a7ad,ee49d30f,c8f8424d,7f26c6e1,73dc6868) -,S(ea0d5281,bd1417c7,2dbedbd4,dff37c49,bf143417,d2a40dc2,573b4b3b,2ccddcde,c7a35ef7,685faf18,c5a4cfcb,2eca27b7,46b21d65,ed71aae9,15185cc2,6d2b54ee) -,S(d5432c9f,8ed0b4a4,c3e42dd8,28098f13,11d2cdf3,94672331,51fddbf2,a6030974,1e047ebb,8cc01a43,2ee6ea04,578513aa,17ad2bef,7fc7653e,936b2d22,bf8f6c3) -,S(c99ee053,655c9d53,1fdd2298,3cc03756,299f47bb,5e1d0a4,d7b861fa,c3b5e332,61c5187e,4e12f8fc,617a5fd8,746f28c3,368b6b19,1189172d,8c56e2f4,679f6b7a) -,S(f41ee431,170be2d7,fd488c3f,5f21f3f3,aae5e501,1a3c4ebe,d0f6db8f,63e11e55,f767b289,118391c4,4d27c1e0,76b7c70d,110cb938,e9c5c62f,1af200ad,7e9976cc) -,S(505a65a4,29388bcd,55561f5e,fb3090b2,2d553bac,2f8cee97,6c0685da,40006e41,c72c9e86,6b4de925,3d463d7,e7bcf7d3,d6e7c351,1fe6c4b4,7fc436f6,d793e0ae) -,S(ca34be0d,48bc2931,cabe71d7,9cd2bc23,ffa928a,5d532d67,f3665acd,375dc01e,263008ca,4dcf002f,8fdd580a,65701694,bf4530e8,baa0438d,b77ec246,75b4db4c) -,S(d52c25e,9a76600,b16dfa93,cf9c2df3,38c806a7,d8cff18a,1d262662,5fed6d7,80309810,6055c3a4,d5d1e5ac,945aa815,bb8ca3ed,10b5d54f,156e4336,39c4ac77) -,S(83e43bbe,62e39426,a0a74ef3,831cb4d2,776d7ea3,d5a2d57a,8280bae6,ae0bd8d7,a1c2c1b4,ea1140c8,cb4ec2a6,98a3f727,666eaf81,1ae9b89a,9e09db39,d1a257d2) -,S(12326a97,ad8dbe89,3181d76c,6d7507e2,74d62cca,1f0a3517,30e9ddd7,198de84f,79e7823e,7cfa4df0,bb31e9dc,ac415297,edc6e061,4fca2f18,1ac7fd46,d27fff48) -,S(1ad3375e,c82aa917,88bd787c,37fef8a0,2071509e,aef62e8a,dd5c5e4c,b096cea4,f9f9f10e,efc1fa79,454c6d55,b894d65b,ff5c445b,f4e9e46b,8c82a4c2,a94d5a71) -,S(8e8bf9c3,a752258c,278bcf19,7aeebae6,fcc198f9,2310b13d,d114c1a7,d10fd2c9,e2f41d5,b7d94378,5f61f572,763e6e88,df7b321e,9baf0445,482d9f22,f1160195) -,S(c44cd33a,144e2926,b7ebfb93,d7d9ab56,3888f6d2,694efbbf,a5665e10,f6e0ff7,c2d4afed,f77c22d2,88f9cf38,a057df90,baae8ca3,1e074d11,bb8f89f4,e9e1bf4b) -,S(b960f0cc,bd7d3431,4138accd,aadc2efa,d5b60071,7c69f1c5,92900a40,ea68b24a,e0cbda14,801794eb,19401935,3f8ab80a,f525b8eb,2b64e5ee,62afaa5a,da4680b1) -,S(f7104560,8fe120fe,5d036260,5bc3de58,76e24b6,20684413,a440cf56,6520559b,2e208f0f,fea3f78a,9a283f9a,6b601ce,db4df4b,b2fda7b6,306dc8b7,3d514f35) -,S(83a31aa2,cb10fc14,ca8cb2cd,b21cc163,41cc9862,67a5f1cb,75f3f90e,1a92c59c,be18918,400a6e32,b4fa3469,ea6e3613,251ceabb,29cbbfaf,2c16af07,fc5413ac) -,S(3d7b800f,8802e521,341f83a5,efdb355a,b60669d0,adc15531,72c62097,8106f6ab,f9b179a3,aae98427,e02d4f00,89b3cee7,250e30e5,ed72d59c,198d5ae7,1d639e72) -,S(7bef4e27,9064400c,48d4f27a,a754deaf,8af74b10,d5dfc497,98c38216,803f50e8,bab0d71f,d02c67e6,b274693f,6a4f402f,831aa4a3,5fd83014,fb07c5c2,e62d561d) -,S(e6b2c83f,2a6ea201,f56a024c,482a8076,2f2053b4,2e4d2901,4a5178d2,3361bcc,75d1f7b5,209cafe4,f98e63ac,53052a40,487b3390,e4ab73eb,ac63acb5,cc3dc88c) -,S(eb4f3b95,f12c16a8,e5e13446,d9b8ca7e,92c56bdf,565aa4f9,bc1c47af,914fd145,e3776908,e3f3228b,ba0c0523,7eaf1963,1835797b,ffd7eff5,61b30fb3,9fcd6307) -,S(e2926c0a,858b9732,82c1b34b,4c4ba4b0,3099797d,d29c5fb7,4447f28d,ff962e54,2730f3b,e59e862b,37ac50,e5375d08,920cb62,b87ee8d2,f5ec9975,886359e2) -,S(8bf4efd6,c11d7251,b06a5e08,99ff2e80,349f8022,387f3200,6d9de060,bfbf3f68,5514395,457848e,a79ba6c4,39a7c151,b497751a,a4a1784f,114686e,e351afb) -,S(4ea97c1b,920d2ec5,3c2182ce,d6f7e1f3,df49e673,1a14ecd7,d67aba0f,fd077c78,5e958afc,d3894757,e0aa89ed,ba26e035,f06e4b11,da13675e,29d382c7,b21fa9e) -,S(1b12e81,3c7c19be,18576f93,69d938f4,bc81bbfd,7e9eb443,cf2b9ef2,b8e2b3ee,47220a1f,718c36af,8eb8a9e7,ecee3899,ddc49127,91421438,8760d6d1,699a5ad1) -,S(7c6c144d,4f839904,ba40fba8,b739913,54f40bf0,f5810329,c4e3b961,ee6a101d,6eebb976,3ceae5f4,f1ef2473,a50b795b,a6375c72,df67d15,f310b5ca,9706b5eb) -,S(ec637ec6,bea71803,2bae7631,9227ae58,9581d3a7,131323ec,35f0d9fa,27a3e285,c12b830f,f273fe72,4f3bfdef,4279ce4a,8ae6d0a6,de5cbad2,b0a7b4ab,643c79db) -,S(33c8d6fc,d2b37103,2426910,6b9adb76,6c76f788,9627a9,6807572,e0af0f84,b3f01db0,7ed82f45,252d494c,af735e6d,3934ff78,c89c57e6,6c42a663,e5d6a792) -,S(35ee32e5,f7204f0d,d48b1a80,cea0a418,1d71205e,c373827b,2afc25eb,e3ab7e20,d57bc815,684adacc,756291c6,87d0eab1,63067976,a7c3a2a1,98ef1d8e,bad12935) -,S(97362395,200d807e,623826e8,3bdfa37b,e98793fd,6d7057f6,370720b7,5089a6b0,c908e9de,cd1d54a,172973b9,1706fc6c,c3367d75,2216c2d8,1085dffa,5627f06b) -,S(bd37e01,eb944b32,b379b195,16256ad7,4061760e,4eb44361,5e8e5fd4,34eae9a,dadb545e,2a613e54,6067cb6c,179fbdf6,d94b7b8b,c799adef,391b2957,2b93f57) -,S(b332b57a,4f070d20,35986e86,d82cc6f,7180293,53bd360f,d3f883fd,68e9c5ef,eebd3a05,933526ab,ba9e63f8,cb24ffa8,550e50d6,8cc7a4bf,215c551,ab89832b) -,S(fe5bf27f,9459e640,7489bb32,2012d1d1,69d40635,74dc05bd,6bdd6c38,cffb61a3,72c6318a,3775b8fc,5c790d6e,31bbfddc,7ee07a71,93e5f137,e3c3e098,bae25da9) -,S(f27cbe27,ed93086b,517c5859,9929310c,ad0e05fd,482f1fc3,af041852,c63a2a23,cce74e61,4e14bd09,8f11674f,23e30be6,b3276f4c,f85dedea,b3cbfa49,5a716e4) -,S(b328535,1a1b22cc,51b7a590,3582dc27,518bbfa7,410dc36c,e63da663,daa8693a,1b260487,7d3ad6e3,db75a0b5,d6b89df,df507809,c203b4c4,cb0712ce,ae2e3d2f) -,S(bb47bb09,70dae4b5,4f4c3aa4,ad4c966,ae42691e,ae39f1ea,a6711d6b,5f04b81e,2edfe19b,b52b7b0,2b4cf349,aeeeab0f,67524375,7f35b6e7,b920d343,e71561d2) -,S(fb6c9735,d4333142,5bf6ad83,50c7241d,b82e35a2,9cbafa37,d822304a,c1b3dd02,946a7ec7,1e0e6dd,a4d4c315,2a6e7489,8671dcb6,8a219781,3e2491a7,6a9e3357) -,S(c711f224,40cb6e74,a60509ec,23daa2d9,fbca44aa,9a093475,524e31e5,43575a3b,e4259800,352d0d79,c5e22d3e,2bf59f4d,e4b42484,68d15c47,ab5a9cbf,854294b2) -,S(9c748d45,a07e141c,639ef97e,8887ccc3,aa84bdc,ca0618ff,4f43b1bc,7496c83f,3dab775e,c3001657,e71a9d46,bf8cc120,9a74b9d5,1025f97c,4dbb9457,e932b5b4) -,S(9d5e6479,81a9278,6db60938,4a462621,23070938,d50e1bed,8df9474d,bee12513,30f2517c,6ff04eb8,9a6ef21,e4ff33b8,e14567ef,e38871bd,b9dba6d5,584c8b0e) -,S(4d24d6e8,91644ed6,ac1aa619,f9eb2b58,a9932c5b,3e8c82cb,589694d0,14b1d472,6ef1a21a,9dcba4d6,850e6593,3ee1a259,91203278,2f478fae,cda13d6e,5abdab22) -,S(fa226c4,36b389c4,50143041,da93c906,70258092,a8de85cb,d20a0dcd,284bc808,524d2992,655c77bb,59258257,5db3d663,a7a345f2,85572ff6,e9dd1dd3,21bebf6a) -,S(d4e659a8,e9af7543,2d9ec769,5dda0371,7bd79ff1,9ba73f07,ad0bf13a,45ad3b77,5f4a2de8,db9814f9,9b73ec63,6c77f847,1aa48356,ff67c8f8,3f0b6aaf,1ac7ba9e) -,S(157b6da0,1556b23f,b6c46b06,145727c0,21d6e573,782bcded,d594ae46,598df23,737d45d5,2c247718,e720fed0,56352768,ce111425,72730890,5a84a545,c53c560b) -,S(d97a6087,19c8572a,78b73938,5479e4bc,9a2b249e,a4f064a4,550ce127,fc4bd45e,f11e233a,75ba1651,144368b9,55bd4dd0,f4ba1f2d,2d0bce2e,82315e5b,78e0d76e) -,S(d2fdeec2,9b5f4ef6,374c2b87,57e4867b,d2e036d8,964a2ae,15632ca4,6f79a294,2d2c1502,a935f5b5,960abbda,9db42aea,c9f58f0a,bfaccddd,f8d59881,e2953872) -,S(fbc6a2b1,b3c0b039,9abc55fa,835bbeba,b0461db,41f3d9f3,160d0154,72861b3d,54421d5e,a5ed3abe,f22df1a7,26a2b5da,a298b41d,acc69bd5,a72952a2,13f928c4) -,S(7ac224b,cf7efd8d,b214db6,a6601d51,829d57d7,28c4c3cc,398ba57f,5079bf99,edf12fdb,9e281367,5e7df40b,1cc3c572,55213edd,c0fa07b,4e3f750d,36d6935c) -,S(f2bc4452,4af39f04,afb480c2,f7addb57,a04db86c,3691b26a,922b6ce5,a1724d9a,63c372e2,4a659127,ace8f54d,33969635,1d890dbf,7e2a31c4,251352ed,53c3a0bf) -,S(5ac48ffd,bf27b452,ca37dbdf,83f2fe6d,8f704040,f3a56180,ab991228,a74ad88c,c7ccab4a,e859e7bd,982310ff,2b7eb408,678b6f21,f52ebea8,41021f3d,fab6f091) -,S(daa3d659,a4defb4d,3291a16a,d669a43e,b6891e90,dbe0147f,568b650d,1213750a,af36d811,9ce1ff85,5dd637a3,bd475b10,50216093,aedf5f24,2c98da62,29bdcdbf) -,S(381d3791,30d4beaf,aed138d1,4072bbcc,b8d71d6,dbb13226,ff168f64,3bf55d37,fbfd7b62,3ce32a4,4335682c,d5ccd4b4,aa4430ce,d8fe3d34,9582bba,fedaf9c) -,S(757c7b23,ff6b6ecc,51ac84e6,26ed70ce,4e6e5c74,e4b65f3c,fd17c304,e19b1ccf,56848ab7,f814a047,2bd286f6,b386af5d,34b27c4e,a3ece71,f153dcc7,7e4027b8) -,S(ea498d11,ca35804c,d6103185,ae468bec,6c2f4f6d,ab025173,b1de4027,551b913,ee939bff,8d30bf5,9e3341e3,58acab90,17de8fb6,e2977847,f4322ceb,ca8829c6) -,S(9d119046,59ea5dff,30105d1b,5ee3f8dc,c9291bef,15844057,66e07d44,72ee1418,45355041,4d4715d,e8c087d4,f05b5f8b,a424ac3,49b3ceba,bf806b9c,e657e139) -,S(97bce776,90f8790f,e7d82b68,b7dc1b38,f3baded3,f7c67655,1894fc4f,cd1b834c,fcc18c2b,4f743ca0,e00f4b34,509fc237,c030b689,83451d5f,e7407b81,ed04f7b4) -,S(5339f056,abeb4926,f46dce7,3b8d735e,c6e9c4a3,2057c22a,49c86400,f15d7ed9,5be6a0b9,37e26dd9,f6db74a7,74fa10d2,cbae30f6,bdfafb,dfa2922c,58a8e37e) -,S(27f22d01,4dc5d3,162f39c9,7de3ef62,f2275b5e,cc6d5e32,6ab064ad,f762a446,6aebbb58,d671179,d712926e,d56cd280,8393fd85,dee45558,300a0f8a,a2986f09) -,S(94af2fff,61741cf2,5f158308,e7333e3f,678bf1ee,56adfd56,629312e2,2435f9d5,33a7269,79df6672,b13198f7,e674330,806f2dd9,50d8e82,1774f381,d9ec24d6) -,S(ae8a0e18,486273a5,36d526ee,3974031f,f3ed095b,a6835a68,2e943dc7,e19b37e4,23c2a51f,69df1826,9b21413e,505c0785,576fbc84,acbb2812,fda146c7,f5e8c8c) -,S(623fb527,d3d99023,9f720cbc,64478e0e,a0b84b28,5c0c3f3f,107b3e3d,7dc430aa,3ea48a8,d1eb543e,ade4a55a,f909e62,14e47d26,9471dbf,4d98a3e0,39c72849) -,S(1ff42295,d85e98be,f7aa84c4,47ec854,29f01b4e,c87371f2,b2025ba7,1e31a768,d9500f9,6e8c697,7ecc51d5,7bb7dfd1,3cc97017,58bb4196,b0b11d1b,3c24937) -,S(bc808b0b,67bedaeb,2e7a4bc0,d328efbb,1ff35dc3,b51716ca,3e501a3f,956aed3f,6af0de4b,26a6378e,6d86378d,d1f54243,929c37ee,d5c10bbd,86b80c3,ead8e545) -,S(e8ab92e0,17a9e956,354203b5,5d7b15fb,acc666a2,79158016,33a91865,b5bb46af,3e87cbd3,66926e66,3f5faa,426a9db9,811a9db4,de3a4bd8,79073b7f,c1e3197e) -,S(a7bf0061,c383040b,6e89ba95,b57102ae,2c291ad6,72bb5027,3c27fcd,f90613ec,79ac8ff2,4bbc79cf,431f4159,4852ad4e,2f0a9f86,ca72ac11,9d4e3fdf,8746539f) -,S(6841bcc7,22b705e2,759ba4e6,83d6b83a,19ee6b4a,375b38f4,5722474c,ca41894c,dac48021,5c168519,d147a966,451dd63,7838d236,5667803e,80658faa,1029a7e) -,S(d67e6d5e,a1606817,512f1db3,9033829f,69089a41,902189c5,20f0202b,8511479f,9cb4a747,7224f93a,8447152a,9fdf4c92,36a1b698,2e9196b5,a4355715,b9fd6ee9) -,S(61b3a7a0,53c477b9,e03d0a96,8ba38de0,b02e42df,162a13fe,8ad538c2,840eed06,94c07520,fa19457e,8d98fdbd,d9a9bf93,57642cd8,1b48fa58,b4b14a89,cb6142ce) -,S(cbd26d0e,a00f7dd,4b0b26ba,7358b2c7,587e233c,3a13c86a,d5022ecf,c865e4ba,50e832c9,d84ff55b,7ba79035,559bc889,53700622,59dec3cd,8b3eda3f,1f2b6e67) -,S(17a6f57e,d3d729d,c5ec018e,1b69394b,1ed78e59,6c7a5e31,bfe5dc43,f9c67e56,34f16cdb,c23e46e6,bda5db2,7538d7e1,f66751de,3eb05543,96c66a54,36bdfe9b) -,S(eaeb62d,93fa13e1,ff9d9a4,9eda40ce,dd6006e5,ced0e8b8,c02f7ab9,98f06f31,7e225365,b4b39204,b01c8890,4476c141,1c166f75,1726718,8ad917c4,9a719ad3) -,S(d09999b6,c35d5d71,55605a17,e7f82d3c,dd8d68ce,9be252e6,99493031,a39c7487,9165e761,8dfec3d7,cf733fcc,e548f672,362637aa,8687f47c,b1eb5c18,a780b061) -,S(2b4cf8d,7fb166d8,a6931bce,e67f580,870c61c7,635632a0,71166fc7,4a11c693,7974e2d5,164771d5,2e7a121e,2b015565,b3a874d,d6313721,ec69d3aa,b44d473e) -,S(d5c0045f,a411cdea,470d85a6,66aafa44,49ed682f,a1903c5b,c9594d19,5cbebea6,ffeebc77,5b24e736,8a8b46a3,64837466,85df5c8c,b40bf2b2,291f370e,94c6eca4) -,S(1eed08dd,d9569712,6c0a4039,c6aa5ae5,ab4aabe2,a88142c3,b9aa763c,632b5e38,d180547e,c4640035,ca86d925,10a70a64,5dcbf2b5,d3add4b0,3f6d0fba,5f4c2f8a) -,S(9591b04e,3de43104,3a6982e1,29a2e79f,f525888,846689f0,44e50b18,ce14413e,cc4cc696,73279c51,4aa4fd63,474050b1,930e627e,a1bd9d55,867d700e,fccf8155) -,S(690a17c1,b2dc7ff,520aecaa,380b19d6,d4a28669,83dc5df5,8ab2bfb7,6c7b0600,bdd8a858,e2d989ca,79fbfd46,60ffdc0b,e0231562,711b13d3,47cfd37b,7a53d4d) -,S(800a632a,aca6b505,f9fddc22,14efe53e,4e7ad2a1,a6c07d90,27d8109d,893851ab,bf242683,e0c1a24c,9220c6ab,deae8baa,12c6203c,a0080856,bc5e5ac6,4c3f3261) -,S(6dceb824,c48159d8,57a92334,4c72b4e5,cf2005c5,6fadedaf,5a8b780d,3ceeeab7,e6b961f7,6162ab6a,d44f3fb4,5aefc843,bf0d714a,1a50d13c,68036f42,30a1ad10) -,S(3ef5eff1,2b76432c,4bdfd1f8,23bdfdee,f60b5d0f,5d0b4051,2a3e22bb,665f2b0,8741e43e,9f78066e,d57d317b,d50252fb,11d8d235,3c2c9d57,76191c21,8798b0a9) -,S(4ce8d33f,a53f2e1d,aa696e9a,2de694df,2192db5f,8e6fe88e,b5d51340,83791c17,a023ff40,69587bb9,49ebb15a,d047f141,9985b521,ae915f54,bebc6dbf,5320558f) -,S(da030efd,a3f6363,926abcd1,182f183c,43c4a6d8,8bcb0519,3d137827,6dcd3fbe,c14f27d3,2251248e,3c4b8613,481e7c48,f1493b6e,5c0716c7,8d5e3b97,876ccf3a) -,S(65c12034,87b729bc,3709759d,beabdd79,ee7f50d7,ed2cedfe,f2c2b7e9,97192f40,f440d69e,d59adfbe,e087ef70,9b75b95d,13ac0e06,20683d3c,6d49762,ddf68a01) -,S(82c052fd,dbd6aceb,1f429f21,eed34d44,f915e949,7190aa6a,d487bd6e,68d91c20,90dfd944,c7c20ec4,4ce35d2d,4036eb97,894f5b93,6bef62a0,f2f65082,b0f7678d) -,S(43e2f20e,cab47065,e71abd8b,aa511163,e17e3efd,3e17d790,ba924de5,ab402255,6b1ff657,e37b65e0,bf2c5e60,47e36c8a,2b7ba965,79bdc711,c3ae5935,d2c47bed) -,S(27f177cc,6722e5a7,70200e2e,a9198bb9,f227251f,8efa1988,ac7342b0,985a3853,a76767a5,3743db5a,1062ccb,64452ad1,606d5065,9df8c0a5,64f049f7,764d6a99) -,S(6b1ce20d,d15cf54e,59aec7fa,c1919791,c40c926c,55801801,75c09ac0,dcce0147,c90a76f2,627d2510,8b89df25,23f069a3,6b102201,c2fb7e9c,932ae678,4a28906e) -,S(f9df6109,27b5ff70,d55d2a46,ebc6a734,df165bab,3bd27398,24a60727,5410f62b,4da454cf,7a381056,581fb115,d36161a4,4beeef74,26724d,d4f5500e,3a6c1612) -,S(16bd87e8,2f87778f,6b3f1da1,a04bc048,3b14de01,420b0074,81aab07d,ad806cbd,13a50b5d,886047b7,6898c85d,cd1bfb4,87642f95,8304d54d,12c03b25,9429170b) -,S(f35175c6,2244f0c3,ddb104fa,3ae57557,424c2d0e,f6a20246,e2fa48d3,2908dae7,dfc1ef36,8ffb4e8,2076ae27,7788444b,33880ee5,b6d5bd0a,9a2ba79f,30c4d1ff) -,S(6a9ec43a,b8a6cb70,465ba668,5e15fe2f,9e714c0e,31f1f227,186d95ad,2faeccd9,ee752bfe,4da4feb5,e4c0266a,57929e56,62483704,6e927e73,9edec593,8d538708) -,S(92e3b0b1,3df6dea4,371601ba,3d92f507,2388a23e,302edf74,6da973b4,613d2292,9442966a,dff82878,f6e0b8d9,9e56f99c,68eea310,79b365cc,5f057eed,ec38496a) -,S(35427db7,f03afb34,d13ba232,420e5d9c,4a8d16c7,924a2043,a217fbd,4287230b,5cfc1908,108fa47c,95ff8e02,634351d2,523dd990,aee1700c,7cda57c1,b106a734) -,S(a61be939,d3a33b8f,65b8fb5b,897598a7,ee25e71,5797014c,fdb087f1,90895825,fa6b7a9c,f2a4a71a,857bb126,44fdcf27,c9f4ccf2,7bf6a0d0,dcf8179e,af1a3396) -,S(659868b8,2a9422d7,1da877f8,59956376,b999dc3a,657278f0,89e1b7,a3014222,9ecb6c01,fb97f691,92402a76,13f7932,d8a82252,e6b97c66,5c727d9d,e6b2ac62) -,S(12667366,d27bbe3a,d75f00c7,b28fcf20,86e9caf6,e8b5615e,eee0f180,526602ec,dbac0f9c,32895bf1,21c90190,d5bfea81,84289a4f,a0cf498c,3a3084db,1d4a833f) -,S(74af3ac2,60461898,c502229a,8eb4e7e0,962c8f38,897e43f,6e421ca3,3240b7db,72f03ec2,7c24abdc,dbc9af25,41e10f51,5e470c7b,19ab9680,24eecce0,954c84cb) -,S(9aefb23,d88c5745,da9606e7,ce81d4f4,5a39c8d0,4f5d5f07,62653594,d3a34732,f797796e,5c1c0a56,9886af6b,fd8a8299,29ae1897,ca43314b,cb6ed78c,6c0b0572) -,S(93a3da8b,1f686078,1849ca06,24c2cec1,796f64f8,4f46da9d,34766eb9,dfc1f018,e5c50d0,fe7d2f53,fe1053a2,985d2b15,25125981,30de3cce,2ebf300b,4b944c0) -,S(ed8d18c3,f526a062,bd6095cc,249b7d10,ee09d072,435218be,f2ab6c90,c5ed66a6,42084909,f4bfb751,5ec6da47,2cba7678,7870a9fd,bfc86fba,669e31ff,233a72a2) -,S(dba838ae,b57fad4a,6ecfae8a,acb50123,decb0f60,b702a9cf,7af7d78d,814845df,c3213cec,8f225c2b,fc02519f,dce1f67,5ad59b20,91381f0e,feef93b0,3c6536b8) -,S(f1a033b8,64caff57,21857094,e1038fec,7879765a,3b977a4a,c6616162,68c1d8fe,9592b8b9,e4cc6a7,ce173980,e68fc405,88a83788,a08c6027,8623ef61,ba81b652) -,S(53967cf9,7058ad43,1222e9a,46caeba2,d8fa447a,6b0295ab,f40b8aa1,af1f0097,e8e86c76,cef5299a,9a15a6d3,4985411f,2a71b8fc,99f7a76e,230052fd,d5309017) -,S(2477d3a2,bc3fd88,6daba319,8c6fa6c9,5206bc1e,955e9d4a,c6e5916e,5883eae3,baddd174,ce70e285,1e7ed788,cb81cb7a,3402276e,d94e6e72,f20789bc,ec4f5257) -,S(b483c05e,22824454,52f44e9e,287bc21a,634018f7,babd1252,d7a6bc70,24d9cdc7,5d7cd9d,23ad04b3,3a7ccdb0,38676342,5b2338bf,48d4f910,853e9100,e1f3aadb) -,S(6ae41ce9,6c8f0a33,674f74a4,587db25f,7c368fa8,83abe414,a3f6bf13,840d46f8,d52f2dc7,d4fd791b,36e6448f,5c8f746,759e68ba,994de0d6,48c6b1b3,58476871) -,S(bd1a4d61,e19ce013,d06740be,c3ad88fe,bc3b2391,45563be4,41768f01,45f4c450,88c18e77,c5313848,bd19bf27,374deffb,1f40e479,9687791e,675af225,1141fda3) -,S(1d2fccee,47b4553b,215dd2c7,f26412d6,73319507,43136454,35426bc1,29b358d9,93e52147,c13791f6,aceab8dc,95df1637,83d985d8,3a4426d2,f825d126,e7b8c564) -,S(322cdebe,5aef9ab,957b355c,e8e4fa7c,23f23f83,bf311785,f0fc40be,ce0f7453,2eb8c80e,561e419e,f898f772,12eccab6,e6c4ffc2,5daf67b8,47853a6e,8475d19e) -,S(c7474f42,5491fe9d,51a9e00a,a42bc188,50d4fa36,c19d9869,6939962e,61e207b9,8dd394ad,799a69c8,da550741,7352e7a7,92a941d2,10b3f65,f634cdc3,1f42a875) -,S(ac33b339,1bddf66a,6d04c62c,da618bc4,1ad217c9,7d37526a,38d12e28,9fa9dd30,602267b,59fe438f,ac57d14a,8dd3451f,acde0be6,c8984b58,7cfc1b24,34ed9688) -,S(158e2a30,36f71701,2020f476,dd869974,66f157a2,27548e65,688ae79c,3bf8141b,fac16be0,6033e61,d34d1d,1e2c95ca,6109dfa3,64232edc,8f8f62d7,19ce6303) -,S(88384c6,42d1bdcb,af5b472c,2f7a54b2,11ae4947,433d5d35,add21374,33ec4b78,3c3a484d,5b8793ae,203f90bb,476b4d25,773b268a,8e89dfb5,dcb17576,166b3e7c) -,S(21e3c1d6,32299e3b,5da75f6e,7ffa2958,e5d686c2,6322491a,2597dd44,f6973d2,9866fc69,7b9399b7,4307b1ea,e27eda12,590bb138,b22485b9,de6e3cfd,8d23bba6) -,S(abc484c2,6d06ec8,bba4170f,727055de,2611145c,8e4a33ea,56507b60,3477d319,4f92a638,17f6b635,d2d944a6,b9194d40,c4ab7041,2a8ccf05,e2fee038,58d87592) -,S(7a98d6d0,202f4230,a12fe9d2,e321bc55,a3a3b35c,92443731,cc8112f0,579b08fa,bad00e1b,578de9d3,73f0ea77,85502035,c5a04c98,8904923b,f0059a3a,a8ec6285) -,S(282e401f,57ef51d9,f9a10959,d272e0da,e9898f32,d2a3e059,4a65c901,cb1ae10f,6bb8b543,e9461164,a66d55a0,adc51ada,4ac311be,c6625276,5b2c1639,c803037b) -,S(5259a2f8,3dacac1c,18a9a64,d9834c82,e862169c,7a1b9d24,2b521c4a,d7ec4274,196fac52,458c7d1c,3dfae8b8,2ca130ba,99d43a40,8bf41da7,d2e9d040,291f165b) -,S(cbc4fdda,9ed1707b,59db2171,38e9bc1d,eda499c0,78f22c28,4309e184,cf906081,2929df0b,24074d42,75e8a861,8f064466,9ca0dd45,752c7d5c,8cf32661,f8a1ebe8) -,S(96b294a7,ed8d4916,21f10b04,3c2a5ad8,88b92c76,3c93f375,f6d31d99,64b9cef8,f5502e33,f1416c8,77cf06f2,5752998d,a30ed434,365b8239,617ab3e1,65948a96) -,S(287e1f0a,a510c8f6,273362d4,ff8d96f0,dd27113a,b45d0bf0,1af5d5,d24f5038,4b5ddc1d,6c9c4423,1f27ebde,bf4afa29,df337f18,2a2559b0,33de6830,cd7b9e14) -,S(eed0e323,3475ee14,5160d4b7,49210f47,c58d7b26,95dc8036,eae0e6aa,91a545bf,22407aa5,430aa089,3f7218f,2ca23ea0,16eb04b3,3c967e6c,d4c68ad7,16e4378d) -,S(1417cc87,72c932b2,b1116b4d,ab4e86a6,e7d80fc7,b082a6a4,c148c50d,177299a8,66e06245,56f09207,ab2d944d,167590d6,44afa2b7,b598b92b,65706271,d7b50e30) -,S(af6029b8,93c549c7,3544e849,b01ff2d7,b991fb98,2b8a3baa,b9f1b8ed,2b24bc89,dea2973,a97bcb6d,3257121e,9233956d,43ea9155,8105559d,ae17db09,fbc14f2c) -,S(dbb5544d,d28d2510,8a91dfa5,9a3c7538,1b4173c5,eecc8e18,b5065fd8,fa4fa570,4f84feee,755215e9,15abfbb,ff46eb6,9148efbf,39f69261,a9d2a345,3aaf1bd2) -,S(50ee1b42,be9598e6,3fcb0467,18786633,18b550ec,16645f70,869b231b,674a1878,8f4fafc5,fb1e714d,f52c0a10,55016f9f,3ca57c9e,48fca138,68464b8d,70c6b2fe) -,S(77b88613,4bcf9ab7,a1a6e0bc,82137906,d5c24607,a6d4812b,a6d1c8d9,55a5669f,2ffe0de,c5426e8c,92fc247f,a024f1e2,86668e7e,d7a24c33,2c887946,4cbfdfcf) -,S(2bf83837,74a9b9d4,7acfa6cb,6010fd44,620f51c4,e076d5b7,e798edba,21d7fb8c,5f336533,5203a820,a9f75f58,61bf2d0b,fcad07ae,9e297433,79d22b3e,a75f40f7) -,S(207b1218,9a6c2653,69f66738,b2e61d3a,c43cfedc,bd9f94fa,2b883991,ae69e350,c43b15c8,c08b4592,70c887dd,d15cbe95,d627a3e1,4a1c7afe,da2b0c69,549649c2) -,S(5ec76ba9,63dbe3e1,d054ad89,7a00c7af,f60f043,d2472f6,d3369e87,45637cbc,b66d383a,c4ec579b,8350a1b0,b2751fdb,f2ab329f,6ad63cdb,d6d46e35,944009ae) -,S(d010ddeb,3959bd8a,7a7ac178,ca573326,b578e940,b46f5808,12398722,42e13c94,2343d4e2,a380fc9f,617ed8b0,903b722b,a707c53d,a2140021,403ac617,d71fe37) -,S(49157637,c5c47498,5590bdd0,e4a8cdb9,f9bfd422,99812950,9ed25a49,7dad0da4,2564d49e,5c53c818,770c8a36,6e92532b,59fb90ef,e7ff4dba,c6baedc6,b792eefa) -,S(7e39cef2,8285f9ad,1b5ea712,78720954,f4933546,bcd7f9a,b4c7bcc7,54147a9f,6bbe4096,c4c107d1,c361befc,75916c87,6a2a0da5,dde637bf,1f125a21,5408e78c) -,S(45457311,84171f1d,aa931d3c,16b9926,59357877,84a4655c,54822c9c,1685761a,a13710ad,597e7da8,f4b12c17,9afdc5e0,5fc4f05b,e204567,9314149,9c73b421) -,S(c0bbe693,23e256fc,f69f0427,74c59091,287bc0be,82f0b5a5,6ea8f957,6d647d8b,c22981fc,6a015c20,525a0bf7,a9ba8ac6,dab6256d,d763614e,ea250c5f,fb433231) -,S(bb224b39,ff7d27f8,1ba86e92,a6897776,85074fa5,48b5515,987df332,15dca58,73bbcc60,c3adbb94,651cb73b,b311f690,6995d611,8b8238c0,4519de94,1e6bd47a) -,S(94489617,8b4bb641,9cdce312,5d863395,7ea54002,7f759e39,a8846551,ad3a0866,4a16c110,7730cd80,55fb7ddf,93c6deab,e3282da3,8a35d79b,3238e8ee,c8917935) -,S(9ae267ae,a964e8de,68398609,d6351619,4019778b,2341696c,7e44f446,dc8fac38,6d175dce,e589920,851c02cc,3fe3dfee,e9398e53,7742249c,e2745713,fee236c3) -,S(9e237d91,a6ce503a,65dafb47,a9fc5f7f,6dbcf3cb,b026ea73,68403187,d95afd67,64d491e6,df79eadc,74c198f6,fbdc481a,330d030f,851c7fc9,63974047,ddf2d12f) -,S(a5c5e0d4,920f0e3e,6973b71b,90ae2b32,2fa16960,b850eefa,1e516b4c,37252d6c,1aae183c,52ba9f14,f06c57dc,b483ba6f,740d6bfa,7ebb72e8,266895c,e6f6551a) -,S(a6d0cd83,9a198c9f,62bbefc4,b91b696b,57a4f876,6a16fac8,1131a9b1,1b36bc1,97981c96,9f758543,2c810b09,460c07f8,8520e78,3e68529d,7a1d3bbb,e0a86e85) -,S(4a75be64,16d6a87d,49e393c8,a26467b9,4b43887f,a90a25bb,139626e8,58b122b6,ace3e92a,c693f8d4,210932c3,89d4275d,75a46c6f,a9a76358,39c26288,1b8f83ba) -,S(1559a339,7f1e1195,51d8b4c0,fa53b5af,c693ab8f,843e6b00,1a6fc435,5967d7ee,8e450f28,78b2e9ea,829e965f,ae4484be,7e98f39b,a7b0ecaa,b777914b,848f324c) -,S(33565a48,44d9b25c,109eb9f2,9546fd5a,3f30d4a6,157a4e69,6029420a,21f74deb,c8141513,c4e370e2,400b8df6,208e867d,9bcacdd,d87cd975,8f91913,3ba97557) -,S(b49c8814,23db909f,c68c73ee,3995a7db,89e919f2,dc697855,357053a5,7ce26988,65878108,879801bb,ae412aff,72e83051,bb13c415,60499b94,8e0831d3,c2e11fb7) -,S(3a9635b0,b82585d2,37068f72,76291c4f,cd3d211f,80fa7256,58e28dfe,920e3e93,a1711c74,ba4e1a1f,f0a9b6d2,12c8b995,7b6c8c0f,f71da246,154f13f4,719f0713) -,S(ce6dc56e,6f5c496,71a900c1,ae531e3a,a8246877,98044497,fc543013,2572bff8,1af98ef7,3703f8a7,6fc88e9e,c9134aa8,a9e24326,314bf4d8,2a0c85ed,af291f8) -,S(a945a79f,1627e79c,9ce1cc5b,79ad02b7,c07263a9,11f8f78a,ad314049,92bea11f,f41aa315,4049b7c8,c9bef95,f3462336,ccfadf0e,16c1f129,26a5c9e3,7a443bf5) -,S(3debe447,a5f793d4,210e1607,642abdc3,c3a8d446,5a553a45,d73ede0f,20819dae,c0463782,dc5383b4,f7f81557,efddb90d,30138670,858c4197,5a47e6a5,565e339e) -,S(dba32245,a37b5636,9d7120fb,a99880a5,aa590299,601c6cff,d33238a0,395f8d2f,d589ab1f,ff442551,12aa1283,3deb9b43,947059bc,9cb1b32,4d8a29e1,1da82b2e) -,S(9c52bd5d,1fd61e1f,8e75f23f,f6e8baea,a8b7b5e1,5e780870,ea9f8dea,2b75cd56,e6d0a620,c116a7d2,2b2f797c,da7119be,556cd834,caab1007,e9a8ac02,f8945859) -,S(1ec28a0f,24e8910a,85f3c583,415afad6,dc5e10be,cc600749,8cbb40ea,b80fd383,c616ac82,bc6aa8b7,1a3cf89c,b82d7e9d,ddb95761,dd64da13,290f6bd4,a4ff907c) -,S(4fcefc4f,134d223b,994c1274,bd39655,878a35fc,2f50e405,ce11c76,1a6833c6,50c62036,fa49f62f,ab1781da,ec17a13c,4ec82c57,7993fd20,c5c56d70,145c2a54) -,S(85481ce2,90bb32a6,eb0fcfb6,9cb9fdda,580d8808,5b09611d,2d8747f6,ca657e20,ad2f9361,85aea05b,6a0d20db,9b6620ee,ee718c2b,2ae1810,42f6bf1a,2b3a2453) -,S(11aa1424,7760f682,3c11cf4f,12c013f9,7b1c9eaa,5ff0a504,334d2e41,f5daebfe,dda53fb7,b09620c8,fbcdf9b6,605710aa,f807dad5,c7ee4e9f,c7dc9c34,23302646) -,S(908c4f4a,15c58b2c,a0512eb6,b07c67d6,5b08b99c,13d22358,a52bbe24,b3823dc0,5e708db1,d4b37459,e33db06e,21a45fa6,5dd5c959,22ee7b60,7162a77,d89fc674) -,S(d192c334,65630164,2edf01aa,d974fb7d,af13ce8b,2c8975c6,ddde145c,1a2784c9,96bf7877,ced69d6a,a71f0908,86e2dc9c,f6529297,a2f8500d,d683b6a7,ebe4504b) -,S(8fa0f7a1,97138152,75f6c886,245902ef,b6e57515,c28732fe,d49b7f57,c19c6b9b,c09b428a,e54fe6d2,effdb332,4b1fc1e1,11aaf4dc,965b72c5,f97a8a97,18fdb68b) -,S(e53249d5,4d80b59,31d40779,4c550ff5,d6cfc715,13e0f419,4d7b42e0,62e74681,face5c4e,f404cf9a,275846b,11339448,d9133e1b,470489ba,64c190e0,b73735d0) -,S(9a1c943e,7f7178dc,c4453de2,d578c4e6,ab80d538,70c03001,a7a4d5d6,fabca0de,6ae6fb2a,1a7d87c0,99f6eef5,dea6a53b,a296824b,d8ab0848,b44d1216,c2c0789c) -,S(f0d4f862,dd60a74b,e06c9478,1b14b9db,af5847f0,baa00a97,72b61857,bb3d192c,6f48f413,90f9cdb9,edffe12,859b82ff,f8f7b32b,b655f3af,f28175c0,8f1efd8) -,S(1f474fc9,f6ee1699,7a7f37b5,f10f1d02,f2445e12,ae17324e,cd31d2e,c6fb8e1,cbb396e0,4b754b24,3dd587a7,d71eb673,c41b0fb6,329013a6,8ba95dff,c6d0d9c4) -,S(dd871b68,1cf78706,61bd7b4d,1ab259a2,1636cedf,39ac276d,5d36f086,fc9ad4d3,89456fa8,cce6295e,56cd18f5,9d9b83a6,4e4983ca,b55d425d,730726ef,12958dc7) -,S(5223e3b8,3809df92,8db9f4fc,d2b81408,96ed1b89,e6480fe,8a6b815b,bc7a33a5,95b640ed,128da08e,a10148d9,6f53b9ce,e53077e4,64eac3ca,1f604225,75b12182) -,S(65f26a8c,88fed562,12f11676,e2f237d,b4c500e4,a4ee0715,ae2e332d,74c48815,78df921c,545b864d,7ebe6c36,bedd987c,51ac9d73,795b3c8a,2a125d2f,2fb8cbd2) -,S(b62376f4,bd858d69,dc5d2757,b67dfdf7,1d3f770f,e96a0dce,3c61fcad,ed0e2586,c58d5af0,d669832f,4ff38f98,298e9240,c6202343,4e829b0d,145093ac,9ef023f0) -,S(a3297102,6001a6ab,ac0e84c,bfc4c829,4c607d6,c2147833,b1f726,752ddf07,b2c820e9,35502858,eea3b657,c15173fb,d1d45454,3c4fa17a,591a20d1,802d5c65) -,S(3b6e214,94773849,46056d4a,dec9e5c6,86f9873d,76accfa4,b4a377ec,84081339,d7e8ac79,e03d1cd1,7c83ad60,6a140b26,dfe67ed1,254a46e2,9c527cfd,c6afdf96) -,S(ff6aaeab,11cd4c80,ea69c3c,a10f09a4,40b3e51,abf56ee7,2c337414,f3220264,71d8a65d,7a605e01,852f0fcb,1bccfef9,147007f5,7c6b83d0,ef127b0,fe90bdf9) -,S(a0800062,64942e,b9bc70b9,f40bcc7b,52c0d43a,b4d608b4,ff65d73d,75fd4a87,de229122,80c1d66b,364fc250,5b3020dd,1482e43e,c4e67ad2,f2e49ca7,df9659b7) -,S(7c2b8b50,7e2256da,15afa166,84dcb7e7,c437b925,6c042450,6025a551,cafadd5c,747b5b36,e247939,7dd719aa,6ce55c0a,218312b7,26adf84d,eb7e3820,57a0b375) -,S(631c89e9,ee8a3192,c593ef08,baf3fc1e,d30a47e4,6a4ee9b7,e1c6cf5f,d6a0a5e5,8d49bbec,85a5245d,ecf6b084,fc65c697,190f8220,cbb84525,a344263c,ae10e2af) -,S(7ee8cbf4,a0b12cb9,d598835,bcf13fed,72e441e3,bc4b515,4182cf7b,f2818b3c,ea3b208e,70542467,a1e09248,8f34b44c,3821f0dc,169c6037,a7299ecb,25111774) -,S(69c085e5,86fad3f9,7b94d5b4,63b937be,5a95905f,eb33b25e,11ef9e8d,6b5ab3c4,5badd881,779a04f1,3a7333f2,dfcd0fb3,6167d168,b86b6a8,27640559,6e5510c2) -,S(951c09f5,563288a4,e25284a5,a694aebc,1e4b3d45,db0f0ef5,86ce87ed,237aa05f,a0c2704a,fddd2f24,462ac715,cca72894,7de034a9,2c958111,3f55c58d,83911c24) -,S(ba30b632,6ad18aae,6d87a1c4,6af749e4,6d639106,76f25f8a,673d0249,5e813e42,6c174bd6,3def5d0,2ce342b,1d0f895c,ef792f42,a97768b0,d091a92b,14f5192e) -,S(53a1d69b,77ee7d09,f9530860,31e93038,42daf062,c1ec9f19,1328b346,559fea0a,baea6eed,b33605f7,4bdac4e,749650a7,256bf215,737d1081,2c805ed5,298de5b6) -,S(23635f56,f8122da0,91d7e3a0,1125b99,a0f87e98,a717dbe1,f6d9528e,82f9b4ae,1a326517,904ad591,43f0f733,8c98f11c,2ea0fc9b,54e9eeb8,c41e469d,ef0ed297) -,S(c574946f,79574d9a,32c588bb,5cd8fee5,dc60403e,81b11fad,cafc69be,67c0eb67,d2598c1a,8568e4bd,a477d9d9,909b083d,f55a7116,9ccddf5b,666a8b61,96e2f73c) -,S(966bbcbb,4d397eb1,91ea2ecc,871fb24,b0c47469,33df7b03,124408fe,583db143,11741ab6,a38217c,e55bba9f,1c7f41cb,2e69e54a,8a78cf02,60bd3d2b,22789b8f) -,S(6ebbecdf,69e6e137,ad70cfd1,741ed404,4b3620ff,15a07f8a,769edc8f,c1aa1667,2ac87d70,baa106f3,a3490b56,a5960f64,fd80160,d0c14d64,ca1d40c5,f244c57) -,S(815f7f47,8609fee,733b7239,b272afdd,89c2f984,5da8186f,4ee8be2e,2e3e73ce,a972e06b,388be908,86c1e324,e1d2b953,18e99ef3,c0120906,f1508732,f839b930) -,S(24799358,53364be7,4675e3e3,c141e64a,febf3a04,386fa41e,f19696bc,5d3253bb,d6233c69,ec254367,673bedc7,1319641b,f9c029a7,2523f8ba,39dc375a,df245804) -,S(db32eded,dc803ff,d5a1f3e7,8437efbe,8c098fd8,e05f2aaa,c03e0daf,50ba5622,30ceea35,22ba7bbf,2ffe9c1f,bb817fb0,748efb45,65d01eda,9f9cff5c,b5afdad9) -,S(c5fb9cd8,8408cd00,33592de0,e602ad35,74e873be,4442d0bf,fe3bf837,51601689,a604a6eb,85233ccf,ef57fe7f,8a73c430,10e94b8c,4189225b,fe97637f,e7b97935) -,S(7b74932c,71dc26be,429f53eb,efc29905,bdf088a3,f2cf4bb,9828b701,11798163,e07d2133,c628a82e,4a22f58d,710b7d88,892cb999,2f921c28,3772310,c72909ff) -,S(308a025,4f659ac0,7c4e0850,738a2f16,df89ca15,fd64b35f,8f968413,b00b2819,4b4758f4,1eab6491,a8b50fc5,17f7767b,add40ea1,7b1272d4,1b1adf09,5d33c990) -,S(26a78f16,95b595f,63ff1b4c,cd52acca,ae650319,e67554b3,a77f85a3,637fa8ec,3db38db3,ca1e5dec,c73f2192,c4af6ff,66842a38,c76d62c7,c5958fcb,67f38097) -,S(bc440e62,f8524e7b,aef0af7,38e60a61,b213ab6e,713fa9c7,66d28785,891f15ec,175add64,8d472b3f,1547970c,6de2a57b,d2d3833d,2e847810,253b3712,f4d740aa) -,S(f2300d54,ebe04aeb,7a9409c4,3f2bce46,72d9937f,cf7e2a86,c4e8d55a,ef2a4e26,59e0e44b,9e090bfa,5291f436,6a3a5336,a56dbc96,65ae1aeb,e71e8c7d,e2fe77af) -,S(4d34ac85,c64d7d4d,97d40331,3fc19118,ddf31d19,18196594,d2f7a08c,db951c1a,551b6581,e6a1949a,4bbc211f,30fea215,5da8389,a69f6681,96f947e5,f7c8f7f4) -,S(53c3e6f0,fa2795a,adab1a45,a0f30f00,5f0310e,2f989d7f,d1f4504e,d03f2c04,12b382e9,b867a8c8,55461627,b7996676,880784b0,19690280,e709e91d,93048a32) -,S(259b0a65,79eced6b,2dcaa804,ff86122a,24e0d338,165a3013,9ab59f30,343f9ed3,27195af8,5217e109,33e2e1ba,57ebe333,9910c84,9b4e8f6c,af5700bf,93395635) -,S(fe07b39c,f9bd07e7,980b45c2,bd791e14,450eadeb,f6c41206,e73c101d,51093908,a8e47a5e,7a7cd98f,4f5e0afb,b5cccf03,56491271,c85fe0e4,9ae12558,721c66fe) -,S(7f38bd5a,87e2ebd4,526bfa35,5ced4f47,87c404c7,74e7f481,85d40d10,894210a1,4073ed4,cc499ca9,e7f8ff5c,f91f9c4b,782b6e6,f6225edd,d6f69fa8,b0b7fdd2) -,S(8796a424,9a251ecc,c0b3b44a,37edd05b,e34efda1,20926343,3a099e7b,8ae40a82,c02ec680,2860ecd8,f6ac62e2,845e8470,ff60cc55,10bf0179,49f95517,c1dd25d5) -,S(cadcc04b,9d4d8e5,22c153bb,def50fc,941cf94f,bb3b254,61422a4,7e6891b0,4ea1718a,53d64935,ff01f0c3,37ed2b7e,a31f9a15,edbbb60d,bceef362,8a454259) -,S(f2e614fb,346faa61,ec752d79,f9518b1f,e8f535bf,75496cca,513fa961,77f571a,1831227a,b5a35867,82b30fe4,720d2467,68f8c358,8472100e,fea76526,4581fa0) -,S(cb10686b,d361e64e,d82d6aab,5373f62d,b165d3a1,30bc7022,cb3f37ab,d61adff1,d969d37d,9c3db8d4,2c60a24f,44abdf65,b19fc6f7,56a452d6,7ef1b099,613019d2) -,S(6e903855,15042422,cc16d104,962352f0,2e86847c,f816468d,5754c70,fbc6d3cd,cc49058,80b7c15f,6f718ff0,ec2d8544,62e636c4,3e20dbdc,ee318a87,2d52d9fa) -,S(2c0a40ca,38f70b73,ef4da636,185c8260,e50643ff,9b5a83a0,fc0d410f,5526ac12,3f1eda92,8c32cf57,64d768ef,7a6afeb3,89dba8b7,e5bbe5d5,29b50410,5136ab15) -,S(1da89240,4f7ac31,136097f3,ed3055ea,d700aac5,a87ad4c5,49246211,f0ab0d0,e20f1baa,6ca3514e,ed4ceba5,9afe1875,c717597a,b7dd3c37,6d638e,287bd49b) -,S(5113fec4,172e4cf4,4eb27c6e,932e1d93,f16b3ec5,8c791b3c,e22c9bb3,634f76cb,7b129bae,b450023b,ebf81c01,bcd486a9,b494884f,b005b2e9,48eceeae,a6911760) -,S(a8d236b7,bff53a1a,fe23dd5d,63433dd0,a267e05f,31bce172,f80c5d65,c24373c9,698101e4,33e8a6cc,45b07552,7aa4ffae,3714324f,d5da0ff6,4fbc7123,773dde9a) -,S(79b2cfbc,b5a0c79b,d2ba680f,a1b594ef,4b2869da,3baba7b2,81cbf373,9d6f89b6,df45bb38,a21f4838,9e9eec46,f34eb6a9,78967e6c,5d181a92,e989e275,45756aaf) -,S(ba0eca95,4ec16133,1245f4fe,d70b725b,97393053,84fb962b,d1a0a014,cc403bdd,7bb5626d,2ee7d5fb,ad9cb623,7ba48440,26cbc27d,651811f3,92682622,2df76258) -,S(69609368,c01a1920,d3f62310,311cb7d9,cfca4659,1f53fc31,1f0af251,1f99fcc7,73ee24fd,32b08bef,f4254bf4,51614b2b,c0269e59,c6caf25b,bedb4919,76186894) -,S(c0b4d69b,d2344ab6,df9d8427,d480296f,5e0333a6,4a447302,5eac698b,e916f676,817dd44c,49b24aaf,627620c,ff7bb843,a84c7eb3,cc7e77c4,f65ba06a,14abd07a) -,S(80fd0f21,435d42a3,5ba377d4,e2401afc,dec30b21,db770277,fbab9841,3c5d9f9c,502f305a,a3350f4f,50d418d4,9b19768e,4976020d,8e158f2a,6cada628,e79953fe) -,S(7e18fb26,a881189,e3862fe0,9006e1a5,e07aa6b,39a5ef66,4f52547e,1cd7ebcb,dac9006,d99e8a47,d3c5539a,508f3f41,c649d475,4a53fc43,2dace107,1112ca84) -,S(a5b8503e,3f7c067e,628e5f5a,e65a0891,74385de9,69049aaa,26df1906,ed85af56,e9cc7458,fda4c95b,6b502498,95f4bdfa,ad9ed7d,346609ee,6549fa16,6e98dd1d) -,S(d93f866,450f7693,689bc9a4,644b52a9,3d006ced,d284332,4dac7fc0,bc6ff548,94c7526a,14b30b8c,b5a2b33f,c6508dce,fa141bbe,b6aba116,cf3cc169,ca094b08) -,S(424ec330,e4f5dff4,31ce33ed,1ef8293b,b8cdd070,12b5b18a,67b3f4c4,d766bae3,94f29933,fc5ee8a9,27295c4d,8d28b3a3,67c60d6b,13247616,a4dcab96,b58e2dd0) -,S(58805d5b,10cf81e5,b114c372,69dd5dff,cdf7e153,370a8305,bcba9d3b,7ebfe952,15e7b2cc,3ab0ab9e,a36df4bd,ce66bf72,8c45e295,d4a6c94b,e366f86a,ab39df5d) -,S(dab0c80c,a05aa70a,e626f81d,7b85c06f,b418ca69,8067b9fd,83cc6e0d,6a3949e8,4c728c4c,527f9839,498aff2b,91e8a344,aedb11cf,7ab9486c,ab3c7014,3dde8e3) -,S(55b54261,cd493b2d,7dd46f1c,78ad3983,787a37e7,ad8092d8,5cd6a55a,b870e09b,bee36be0,1168a67c,13faf147,6a614b6c,bf7b149b,4600c93e,4ec199e0,9f7fc63a) -,S(ea4f2da7,a5cec770,d986ba06,b1f18ec2,b3907a44,47fa2bef,4c9fbc10,d92afd4e,18f9565a,41583c3b,f7015986,ca7c94c7,4222b81a,9ac26eec,e7954baf,cb470072) -,S(5d835d26,54e489c3,d726f54,bc06ee3f,11390023,fb8d16,61f76b2c,29cfb78e,83091f39,9d1bfaf5,216add5f,dd4d60a3,469aaf82,ca6bf5e4,1070c03f,792dcb2e) -,S(f5efa7d1,484fe717,428e9f54,88c12db1,c775073e,27d028bf,7def8c3f,4f558774,1139d67,793faccc,70c7f48f,c892c314,988d4767,b9d6fa2a,2f2b632f,367453a4) -,S(132950c1,6f24a24f,a907cc59,704692ed,b6a5d254,79dea8d8,38cd71a2,a5d6542,b1e87d14,db8725f4,e2c2522e,c2f3f290,11d664f0,e6e85368,6c142c3,bfefd736) -,S(e479b0c5,478e49b2,c9e211c0,8e610b4c,1f1917fe,5960ba35,9af83c9b,4640d05,66ab2af5,3ffbfca,fdceb064,452c8ab4,b112ed68,8bafed44,1b66ef80,92144364) -,S(41b8288c,19cfecba,562b30e4,93a4c796,dc3adc21,f0c7a9d1,6adf4459,375edc5a,3ae93bec,6f438174,b3956d57,d9dcf29a,d673f6ca,74c96120,c22018dc,fea42398) -,S(56696d31,6d3cb87a,a3eb312e,1cd41768,2d0183f3,b91f605b,c4389d59,d86052e4,5e96c041,e495e90e,2812c09e,81d431c4,eca7274a,2204cb,a3a00a0e,650c6b21) -,S(ea36425,bc35c1f2,f0d96a49,ce4f4446,72848c5b,ec47d7df,6ac5cc30,d3968ebe,b00381cd,a5c19740,a266e63d,d59fea3b,d3d3d3eb,c899bf9b,da8090f8,1eea766b) -,S(84463c57,b01dd5c9,b98e0e4,38e221af,58c0e077,20540b7,da0b4d89,b3c36502,deb3a24f,9a0305e8,812fbaa2,f81e5fea,fd24c375,6a529c3c,c2bf4aa3,8d87b30b) -,S(13a22d5b,d23428f9,912df3be,eb82f4b,411fb39b,1604fa7d,4db63862,293c2310,99a19b77,c6912900,1047d70b,7e84ed80,a8427709,67384cbc,da11a158,6ddfb1db) -,S(de017231,52bdadcd,21b028b,4cee806b,89e98728,f91784d3,a418d7b1,22aaeb57,7ac0a9cf,15ff4a0c,f7d8a0e9,d2fe1469,1a08d526,7e3475a9,381be3bc,64771e65) -,S(1fc63549,9d462327,afc13d0c,eecddb5e,e99bb085,55076d88,7c064e8e,e40396dc,841f309,e47fb335,d2691c43,248a151b,426f1205,ccba170c,7c644615,54258a55) -,S(323e5acb,f821f131,7ff1dddc,822cba0a,b3b2380c,ea2f1b76,903c906d,83491dda,afc25ce3,b13cad24,6f6d9a2f,71e97d1e,e31bd2b5,967a5cc,7ebb1caa,adc7ee) -,S(57b1ec40,5c187317,ff9e70dd,2fd0eca8,cf2b94f0,3d7737ac,dd1468ab,61f56384,247e6f6d,7e2e70ab,a8d50794,36b1f6a0,b27865ac,791d1f08,c334013a,4ed93386) -,S(d6f5f80f,80586e87,5cd322f5,7836327e,225aceb5,6d8a83b1,6cf3bd12,4b581074,e925199,b597c7a0,a179cf34,519ca3a,f35b6d9b,24d76118,ace70f99,f1932979) -,S(2fef6c2f,eaa8c4e7,1cd31179,e0bfaa85,95d26471,fc36be60,1df75cd9,94e73c02,eedc9575,5bbca159,2271bcdf,d9ec8bc3,466e4b77,36d28abd,e6d68ff9,b9820f06) -,S(e488b041,358bf98b,11cd31a7,77a7d93d,e9cb3a61,c49fbafc,4bdabcdd,7b895964,755147d5,ba8f1d44,4ed0eeb3,d072c11d,f448c132,b9e06f4d,66f92ab3,7114a1b5) -,S(ba2591b6,35e7747f,20553589,11e7165e,618b6150,222a70ab,afa66bc9,a931cf35,3c60585,b16b1d07,7bd578f1,85e76bf6,77ff788e,a9b2caee,6c64ef9b,143ef487) -,S(ff4b12b3,cb0ec8d1,750c648d,6ed2695e,a41f8e82,58ba8b16,bf4727ba,6120ccf4,e2cbc52b,f0031efa,74c1fc8d,25466888,41c695d2,393e19e7,287bb34f,afb689ec) -,S(9e42cb1c,aaac0c62,47e4028d,501c84ba,6279b39,dd17424,73c2cd10,9bd36063,c9d0d646,381ca19d,528d2ff2,b04aaefd,9f8095a6,8811f8e3,e85b5ff1,5a5da5f) -,S(610e8f14,eb180ac5,ee435530,812941e3,ed7dad5f,c7bc7924,10f296e2,449fe005,67632a19,b1567d77,b0b5f013,77c6a05e,9261ca50,d010340a,968d8507,877fd4d4) -,S(f4c4230,443f3324,7be7bd5e,5cc12a0,27f0ff23,ede41c44,beacedd0,64789752,55d7b7c6,866f6bfd,29a410e9,8d5d5e21,98719d60,93e2bafa,697a8b5f,734d8bb8) -,S(66221ff,1d344797,1f308b89,a26e993e,c4d1c05,2c2fa436,3729c9aa,8c9dad0d,c0c78a0f,be8ba04a,932a7d6d,604f0fac,4ee01452,fef801d,36d3ca93,c4b7a965) -,S(c3ea4e8d,f8ac15b2,1dd251f9,7ebd19ca,2d91e97e,b13085fa,98294915,6aecfcf3,a7286bd0,3bc8f0bb,a3d28b6f,c513c4d0,472225b7,aab70f62,18c1a735,b31f1547) -,S(762ea616,8b3056b9,da318ef7,53ae0cb4,ff57eb15,8fff58ec,7e4fca2c,b605a49b,195d761e,9caa7603,ff1b5ab9,85d4bdb9,d128ba93,33d6cd94,f00c62f2,9452c8e1) -,S(50cbfa1c,f9a07c2b,42783077,8cae738c,3c3a0d5,617b8c6b,81914720,25712a6a,40a37fbf,97da5646,a653ec25,eeef583e,15cc1db,5bee9ebf,addf9706,cb14e689) -,S(bb8b806c,6798d001,f0d6b31d,1b17cf31,7a5422d4,3a906a79,294e5243,e22ae3ba,46b763df,b7a7a967,75b6b3ac,d21cfa37,a187ab39,99506c99,31623acb,841d4dd3) -,S(5491fa1d,88f0c9f3,6d87e074,331a9a6d,c17a5f63,b1e3326,500a5bba,1f0081d2,6c206f15,7dfb29d0,3b0e5878,57d1abb3,5f18b260,45c58da,87e8c128,7f699a83) -,S(c9d2726f,5ce823a3,ce02ee66,262d0673,f04ee272,dbc16cc0,27068850,cf472435,ff62f77e,60de3ae1,52c7f943,c3eed295,fe6a7aaf,8e6ba0df,bb60a8a2,b6081aef) -,S(a0d934b4,68151a34,cea5ff0b,d002dfb0,ec51df7d,ca5afd35,56acd53e,39515256,2f27f413,ac43711d,fc69e5af,785546f5,8e0da1d0,c9e89271,c8933b21,5998a999) -,S(342b7a8d,a3664884,1d8198dc,5e17b669,f4e602bd,5dfb28f0,95b7751e,4ce8602e,cf36fd4b,24cc36a2,806f8926,db6951a4,4c545076,70ee674e,8e2fefb7,e33f65f0) -,S(1f0993db,1084fdf2,6b2fbcfc,cf0c8a24,124c2474,92acbcb9,6221b788,18542b87,fbf92437,f6feeffa,4e04267a,c8dc57d0,c6d521b0,2631c20f,876fd9f8,b00793a8) -,S(f8f4034b,d7fcc9b4,256433c0,c2b40f9b,2f45a117,3a371707,f6ebec47,e456d9aa,cd895dbe,d97ab95c,b3c98512,c46a538f,385b9b26,5438f7f9,8caa245c,c680f54c) -,S(c80f3bbe,d409d5a8,cc0502ec,d7d95d8b,69067e61,fd2e8f7d,45f06ba6,7db89a33,dc803aae,6b936dc7,27773f6e,17c5d2d,af87a1f9,464320c5,4fd0cdd6,d7ef5c1a) -,S(b19fd3c7,8ee32a3e,dba4d6db,bb1464b8,5b3a5865,7f0c06f8,31af5b39,de2b436e,242c72a1,91f17614,8ee25c12,e0f8d4ad,52837a48,9b94b16c,27c8053,43c8e523) -,S(c88c52f8,a658160c,b10614bf,c744f668,ac46b774,94592a1b,99562a6e,e6482099,5a2f3a43,bfa6873e,7a198ad5,4fc0e3cb,2047f268,6396231a,a158a5eb,f4aa3170) -,S(b5f02d99,8f8f1c5a,8c8995b0,6879c804,1dca6f17,3666613c,efdbb82,820164e0,8e39ef2,207f5d31,2e36ce55,3569d2d7,2204a9f2,500ccff8,50bb67d0,a0802585) -,S(4d4e728b,5da0713c,18fdde5b,290d24ae,f7150d42,f9e5625e,f05bd17b,124f8302,be413caa,b7c77064,91110243,a20545f,8f9e5357,49ce98d5,cdb41384,5471bb5c) -,S(92832d03,32f7ebae,b67701ca,a0a2bfc2,b36b6403,742f4ff5,ff2ae46c,242dd226,cacf8955,92bc2fd2,90dc5b5f,b4185159,3e4a6a0,709a51f7,32e8c554,7cdc4114) -,S(2807a982,b4fc3fc0,8908fc5e,b3734a83,b2e2035d,8c6e3036,b16f9ac2,f4bba58a,ddbb9f8,3a9a6ae0,9945ebfa,9cb7e7a8,49798032,8545379,df582f93,72cea69e) -,S(e755ddd9,139cc4fc,b266477d,645b4efb,b02088da,752d10af,aee5ff8a,45df9659,fa7daf3d,605846c6,35e2534d,746873ab,cd502ee4,27e62c45,ef66401b,c816beae) -,S(93c33dc5,152a9bf8,31c3cf7e,ea833ca0,485f852d,52a255f3,55d7e67a,c1964f63,4a3a36df,13c8cde5,48feb589,dc56eb16,9a874272,c7a0becd,d40554db,cf4d8f63) -,S(70d66e2c,8f934356,d6720d9b,4809b984,6c7ab1c4,f8604990,d2e559b,a59c24c,24e8b668,4ee0062d,7bd79b3a,c96e0316,dcbffe2c,973ff6bf,e99590fa,192603e8) -,S(c165111e,fc2d7105,f6bde2aa,7f682287,2d803fa2,ec904380,27195cc,147904d2,c71184de,f408b79f,32086d4b,2b0e5d95,aed6e0e0,eb99bfb2,7e917abb,8d3a5e74) -,S(12144a63,67cc355e,e75486,357b0c79,ff4fe703,57a2f89f,3e3f7e20,ef860204,f2bb05e6,e55171c,c839fdb1,2b49ba11,dfd53af1,7a5a9602,4327f93,940b8491) -,S(3179dfa8,bd134725,3988033e,70f806de,fde9c6c7,aa4a6d43,a5cf110d,6fda7828,3133a35a,ffd1f24f,579fb314,2e72590e,475e931e,8766d462,842972cd,70e49344) -,S(51fe3e70,e5f21b21,1cae97a9,d0fa49bd,166dac17,5087ac3,a93219bf,d17ee77f,f3309396,5677c691,2a987cc1,5b3f016a,4efc22c7,6f89f562,4830f09,a9fc9bd1) -,S(2d7c98c,a224ebd2,a5167017,88018bf2,1f29444b,6eeead79,dfd9e503,7fe1680e,abae552b,bbeb09d9,dc82af6a,eea16d50,613c9314,be23eb79,d254a16c,decdc02a) -,S(c356823a,37dc335a,918a5553,bb0dfb9c,704ba647,d6cef22c,1e71bc9b,dedaa333,d8715c0c,a0ebf8be,d79ea3d0,85a70d2b,b40efecf,7dded60e,13d0577,cc235e3d) -,S(91af0d4a,56a75616,e9cb1351,4ca27ef1,b7411d9e,5991be14,c1658450,71a2b3f,f6c845a8,76657a63,ed37bd33,46ca60ef,a8fd151c,24a9e35c,5893f969,2580e26) -,S(6a32ae36,93ee1e7b,77fe8418,7266e6c5,cb41c7a7,37351cea,987a4f80,a26cbe00,2816504,dc3efca2,67e4bba2,5d4c9dbb,e8622e99,4a712503,37320925,ed5f64db) -,S(5851d327,5e18fb4d,79292e6e,2bd6bf29,b6301e08,7b418ac1,43afdf70,7d880901,1e17a9c3,dfa8c3e6,c1e9c34a,785321a6,e58d8024,c61cd02a,8b83ad41,a2366211) -,S(233a98a8,9fec3399,f74d99cd,7d5d4894,1be8274d,8f7ecfa1,f4f3693a,fb26a654,e9d5a9ee,fa5e6cbf,9ffe590,bd7db1fb,b9e08125,93f42238,65298e9,eb42d7fd) -,S(8751bf4a,9676e2f9,5036c3ea,97749d8f,f452f67,cd1259c8,4c39e8de,9cf796c9,4f883d63,bfb0a01b,e26b31b,53ed8755,49ed6c1e,4b67a160,7fb68be1,7b845711) -,S(a21126cf,7330697d,714be16f,27986c9d,cca4a0f0,3a12b6a,d54ef31e,d7a3dc23,3b0e984f,565d9825,2c523913,d2d90a26,b47973a4,8d8669f6,8dcb4c62,399b9777) -,S(8123c441,96d17ce1,c6c1a9d6,2aaecfb4,cdde74b9,317599ea,450e62f1,5639c3e4,406c585b,c9aee3ea,dedc117e,d58b1c3f,db5846cb,6eb11592,469bf958,6872b068) -,S(6f8e1a45,c18ebfce,2e2f710,efbd7ffb,4f107a32,fa6a46a4,caaf8ee2,37a22805,b36a7c4d,712315f9,a89b5ac2,8d1a5d55,5ead81,d7c43b8,8155eee2,b3ba8d3b) -,S(51db2e94,7e75c9d5,4ea07ea3,35942071,5987090d,b81c3b99,40b85684,2b0f0bcf,70967acd,454e6ce8,ad015f45,e0578940,c95dd818,70268d0b,9782a595,9a1462d4) -,S(84e0b0fd,b16e03c2,cae53675,4eb3452c,86ef07a1,ba278abc,d5aeed37,f71a3151,5a8e435b,53a4b51e,2ea659b7,1f3371ea,dfb28579,8b062eda,300664b6,d3b204ed) -,S(ced68408,c2b01401,fc039059,5140ab68,14142b7e,d69a64bb,e6ec5d85,be833367,76ce2478,28d2581f,6779f723,327fa83c,8cb10451,fc34625b,d069885,3cfad07c) -,S(8d860f70,a32921af,6376c310,bf5093e0,572e9b3,44e9204d,f5487554,c4f5484c,6dd24078,cb9f8ea0,eeaa4f4,3f3cf99c,890966c,5da8fe0f,9cd70128,88907cfa) -,S(6223ee77,4e56b9e3,da6e008a,eb3ba06a,40bafa1e,84383ff5,65f98286,d9095d37,ebcec7ec,f750cde,9ff7972d,172340c3,c324d843,f31db269,c3f35a62,c5f15f36) -,S(326943a5,5e7b7ca6,951a78dd,afd00e10,c8ca7f6f,3c01a038,ffc4fc7a,20fe2c63,b3bc5a8b,c87ba023,ee22bb4d,3f92cd81,787f2af2,4ecaebe2,67fe0a86,21c5d201) -,S(f69b5d4a,eb0b550f,851f601c,92698789,f9f94821,47a0ade8,c8a19fe0,5742731f,2a74e8bd,94469645,c8a328b4,24975dc4,93adc83e,4baddba,6c41e10,3b58e90c) -,S(f69a5a88,b8f13bef,a987194d,6b00a79b,7e576749,3d180fe0,32a1868a,26d853ba,6eb589cc,9c51900e,a6d99110,206f60dd,cbdc368f,5ae8dd48,cea05218,3415cbfa) -,S(c00ffc9d,8a57cfcf,9624a812,dd2181f7,195f459c,3b858a19,864393bb,1d1a269e,3097e10a,d6abfc0a,3fa039fe,952034e7,6bda4fc5,c5614092,b124ee3b,bf55f87a) -,S(9c021c49,d6671103,cfddcc3d,8e54848a,addfefa1,d6de5455,e5bda021,126dd183,4fa1ad18,81362f4f,f0587b52,a7a1b483,2d14127,434ffc4,c5bb90e4,fce50834) -,S(59aae0a2,923bc36a,1a5bc8cb,ea5bbbc8,b34f1504,4671a046,eb3090ed,3f4b2345,659f89e0,faa1577e,36175240,2cf1736,a18b070e,4d4b0fae,9ed08297,362cb246) -,S(7ba1ee89,479254b1,f32e9e53,517f0961,79d17d81,3ab3666a,75d4bf7a,7113f252,6530b40b,7e66a084,97168778,61cffd96,5eb71e62,e8b0ad7a,7d2851aa,15a26dd8) -,S(4b0e5728,cef356a5,c6d08616,47c268b4,c8a12d8e,89c2da7b,78e9db87,7b606719,235ec085,a1f3651,11b5f03d,7237dcf3,d70e851a,6dab8446,10e45fa,2996e70b) -,S(54285c70,315d9a43,a040bd05,70c35713,68504efb,fd103098,79067d6e,765d4499,de233654,e7c05b5e,f144d25c,6d539157,51e83ce,7f88dedb,7fbef11f,d6acadb6) -,S(ae15f764,d20e4eba,b95c3463,402a2159,fcd21daf,fa831b3c,e47bec08,9bd43da8,474c4cb8,afeba9e9,3f1d0a2d,28911298,939328e,5e364d44,68c64cf4,fec2eb78) -,S(6de8743a,68c42b81,ad069f2b,fc1482c0,204640f7,74515924,441ebd9c,917e3974,7ed602bc,16300648,86ed0369,21936ee,aa5e9764,ffc294e0,bcded12b,bcc86f55) -,S(7e4951,dfae38e6,f9869fd9,6d058847,2a38b0f8,827052f8,46195e21,44213a47,6fa2e60,a3883383,f8efebc,f39329a3,b7aec31,2958510a,dbdd5a72,728035be) -,S(1f7eb5f4,47d53537,3d29770d,5d7ed36c,a2d2a4a5,550d8bc1,849382fe,3847df55,5a351374,da5a804e,3b995d43,49560f7b,aa417dab,936860c5,baa252cd,1753f25f) -,S(dcc1272e,b31560ec,64a4b53d,24727bde,da576493,b571b5b0,aa7bb3ad,e8b2dfb6,567e08e7,bde60e6d,a614f321,a9cdba4,1b860f41,387b3854,603a8740,f93039b2) -,S(3f4e219f,5014414a,3c757cd,28120043,3cc199b,fa843c40,b344b32b,87dc7e7d,dba2099d,839e9c1e,7d7d4c0c,9444e956,168e2bc,4df1dc52,bb5b4da6,3a8283f3) -,S(dac6f264,74fee94e,dfbe9de,cb2fb88e,272ff622,4d7f8b86,3076337d,6d37acec,1bfc6855,5af0f07a,c9329ed7,5549560e,8d3e0c67,753d2673,eb6706b5,27a0de10) -,S(82ac1fb6,5a975de1,4bbd5709,9e2574d5,ebf883c7,7f38a7c6,1408dd3d,5e49b33f,a6d9dde8,b43656b7,9ab5d880,f3af2ca8,b70da7dc,251a7299,cb236b1d,75276c56) -,S(19a59ade,a0da1340,36a533b8,ff202a58,55b9182f,b19e8b79,caea80b0,9e263706,58030bb4,b17da5b,1879a67a,12c1d929,88cee2a5,d8915528,26456762,9a99f256) -,S(27e8a699,eca192b6,7a66b1be,5b290e37,1ff8e912,5afef253,134af2c6,ae709ead,54ae6059,58d036ec,959d789a,5316c70,a09db19b,179e5d4f,effbb057,abd87eeb) -,S(25e6cdbe,5d7e37ea,fe2b51f1,95cac707,a2aaa70,57fd5e78,8fc926cf,76e65466,576b2c22,cb6ba6bd,6acf0eae,79b52ee4,1fdebde,25293347,d624973f,e9b66be1) -,S(a0114d87,cc03bfbf,97e96821,2b69c53f,12910c87,e87e7a79,109f83c1,7042dbb0,869c33a4,cec89d65,633bbe60,a3cf7b70,1e5c83eb,e7c229ea,a4c279a0,4203a9f9) -,S(e8017e4e,806557e4,61ea997,f5f46e72,9fb668d1,e8faacc3,5804c35b,6d5cbad3,eca21b4c,294ed18d,d0df0dbb,771b8bd1,659c2eae,2c843f8b,bfd3aad,f44a4070) -,S(948209cc,528dc6d6,a406c996,7d7c191,19ab5142,679ac9ba,afc5098d,4d7c83e,3cc37cf5,1aecaa1d,ef14a2bd,cb6a1084,f3e60da0,9fdc4fb0,9d9f9fa5,84f14b25) -,S(10f4d6e1,c141dc53,fecfbdb0,b39e3e8a,c7f5279b,dc231fdb,55b25551,df90fca0,4f5e59b0,9c6daad5,80adde67,1583af4d,fae40d52,6017d5b2,9e798bca,6917e735) -,S(66361888,5d081bf3,9e9fc4bf,a0922dbf,dbbe8eae,451c199f,9aa844f0,71a327e4,f31b98f6,48940706,13a086df,12416779,a5c16ad3,7cf885d,5f1fdb37,1be94cce) -,S(6afc24bb,ae6cbfca,b34fd467,f23a31a4,4a0a35f6,203dd7b,a881ee5f,f340db5,7ab76f2f,6bada7ac,1e01c930,90c741fd,90c41fa6,943aa804,ff960b17,3ab28cf8) -,S(3551d572,2eff7d0b,275e310,d1466a70,2b828d8c,fec039aa,ce629aa1,2a9c23a6,b58af71e,1f9a6cce,c48d1fd1,18902a21,7f1e7f35,3ee9d794,8133d41e,2d2d61eb) -,S(e6e8cceb,f6096fcb,8f21cd9e,d428260d,c3867e0d,9c4cacc8,b8900fff,7bd4c1aa,d1b12068,f85e64f,7c9de5ca,f1490bd8,6dabf18b,4b78b5ef,531d9bd4,f64f13a8) -,S(5cd74a22,d46e7769,15b3c84a,492fad11,8790534e,dd8d9bb1,e117a6a4,78f566cf,397b2429,f978404f,ec96a4b5,28db5a,1b0cf9ef,61f2fc7d,470f0554,eed5ee08) -,S(abeeb656,151fc7a0,fdfca1ae,fef91a7,ae156db7,c433178f,be6fd700,991e8b86,e2a10216,3a8bdd0e,8254f459,b573d182,eb55f2b4,969a3f80,267b060,9f208a8c) -,S(3f9702ac,3b96bd4,ac9412cc,8f40d5c,99f4d7b9,d211bd2b,18c6f96a,ebd2f958,e077e28d,8f171626,9488fa5b,67a54800,b0d5a519,4384ca56,f9836b87,68e9821a) -,S(3c8e54a0,d094d63d,60aecab8,675349e9,f229995,587cefde,eaa1f50,cf3032ac,e77aa94a,fd252860,3bff0189,f11d5f93,fb26fe86,dec719b2,f8bbeda1,3cf38ba8) -,S(8e88168f,41689167,ead8ca79,5ef784c9,8e3cdc41,43a0ff8f,2891d476,98387bee,fb4bf21f,343fc6eb,ca6fe337,ccb7a7a6,899bb29f,d2f60480,ffb0a187,e875b00e) -,S(d5c7df6f,31001177,f2e88aa5,43276617,7a598335,cf6ad98a,e55a6d66,1b75c1ec,2edb20b5,47b7c233,23d5c4e3,295921d9,9d98854,e780f4c1,e756021d,79f1b035) -,S(262b9c58,75087b02,490291f3,963160c,c1f5a3a0,fd6a905c,25c98bb9,f7268514,c7e4ec06,b4cc77a4,ee551a5f,6c90ea97,4a0b2193,f1b828c,305a0fc1,b22e5b81) -,S(cc94ea5b,a4fdaa06,93976b76,893dbd92,f602bcce,822ff271,7a13bc2d,6b31e7b1,c81c01ad,f2ff92f,5c2cc42,f3c30091,11e6901d,36c9af9f,9b408df5,c7460932) -,S(b21abb23,4c435197,5b73471e,3b2eebe2,f537b95d,1b19361d,31ca4e63,336b0066,db02da36,73e62e9d,e96e1bc7,b79ef4ed,49449c29,7f4f0330,227dabdd,5b4c3d9e) -,S(ed130512,5af211bb,28118dc7,fc22b8e,8bc2554a,a19a8c7,16f69f11,a03df1dc,fa146b3c,2e0eab2,bba69407,9ee3b6f4,2f64dab3,9c19a1a4,256283f5,bc0886ec) -,S(42b829a,96989e82,37e48200,20eca1d9,61e487d,a9c6f9ee,60586dad,8fcd0e83,c2e164f0,29b6cab0,14fe76ad,82ee7372,78124cf6,5f251c9c,c260e239,50ec4014) -,S(15f09133,fe57a223,e2c9ad79,dadbbc7d,ec85df2c,6af39fd4,a156eb0b,1602a13c,563206ac,b190bc2f,c7b24d2e,ff376cb8,64102efa,12f7be73,84898cc8,76a12b4f) -,S(b8446387,4262c03e,312eb0cb,e562f460,8cd4f65a,75b099d0,b45e0de7,8398f5bd,da730acf,79fa0282,a3a29b99,7a0ea45,ba0896e7,598be8fb,8298aaa6,9b94640d) -,S(6a926c00,ef4c32f2,52d9f336,29fc708b,e21f571f,1f320ae8,6e6c46b8,9511fb95,9106e0c8,2eb9fa36,4a84a2e8,8eadc9aa,9113927d,99adeb61,a2ac5527,5de9a9ba) -,S(fd6cbc21,9ec03dff,8f3d00e6,9de0c64d,30ca5a04,1556d0d5,87339b0a,925d064,742ce8ed,a4b47eeb,29883606,211c453f,fc15ae40,174e1c74,656a78ee,f3a85e8e) -,S(6fd7f1b7,61116218,68e1038f,d5f341,c43b61bc,b6ec53c2,8d84b321,ac664274,f681256b,947a9492,5b8402e4,26ef8d53,20c65a29,3a7758de,6b7e3f45,a9d635d) -,S(c28c2cff,1e418550,f73fb839,58c1ca6d,4c616c3,74a67978,d4dd71c1,99902ac5,537d774,83b1ca9,50174ee,381023de,cc210f91,3a66615c,b242829e,e3285285) -,S(89458f8b,7db2cd74,346b8b74,759088,fbf81591,5fa1e97a,3f34ff90,908cb183,9b5b21fa,378f50f,dff2e276,353179a,c0a6e43b,13373940,c2e73e20,106742bd) -,S(e66ed94e,793b894,552b3893,88a657d8,55ccbb2d,f9ae0061,2cc07244,bfd434a3,8a6a17f5,da95e907,7b03192b,eba324a3,5595b6d0,660851a4,7f9e2259,2f093275) -,S(8c7e4ce,f5dca16e,620d6690,ce3b9337,8000ca08,e73eac21,deb5deae,83359160,29a44639,f9a6b8ef,990b72c1,5ca6f539,31000a2f,394b59c9,36542992,7959c505) -,S(a0d1611a,807750a2,45c68132,2f7adab1,9b81de3,809a9a82,ac038294,b732bdb,c6e35357,246fec0b,ed0c5491,24f13f9a,a01fe39d,e7630357,110a5878,90d9bf95) -,S(c1cc130c,474f5ebf,e4b4e26e,a444d5d,7542609a,2bc65a68,9c6453f7,9dcf6ab5,deaba85c,f0f7f9fa,cac2415d,9f82c62e,9caf457e,fc9149fb,55bd8f2c,32f74ea7) -,S(d6dd2a36,763b77e6,259f1305,43c8262b,784a268e,45adcd26,efbd6d54,afeabd68,2987d048,9549cdd4,c27222a1,9562b005,56dac521,1e67d052,e76266bf,fbab179e) -,S(885cf8e4,ee0498f,29a7f3b6,a2420629,4a941f56,f3d852e1,4641a604,9415c49d,b1002bf3,e34ce44d,54a18be5,3737d98b,28ad0f7f,31d9bc37,ce31279c,fc039b2e) -,S(8f0c57d0,3d85979d,5bec7346,1f0a3b7d,540fd0c3,8d8a6775,fde2ca35,ec8a0d91,86a3f4a2,cc4f934a,8b833cfb,dbb96eaf,159e00ee,caa0871b,235e4f8f,97bf542f) -,S(53456583,d2f4d9fe,1a13883b,7775b363,3993c9ce,6bca547f,d05021a2,d36cd366,92cec0bd,cd83312c,455690fd,d715e41e,c29cc70d,f5eb2e17,7f0b2caa,f3b5214b) -,S(a5ac3a28,fad5cda9,200bef2c,454b73ee,bbc853a3,e8b2ff77,111ea25e,5f3b5359,4951843f,6e23b9ba,60f326b5,d6b13f1f,f49e8b3d,b399be4e,46cb3ab5,7ef10bec) -,S(2ec53b3e,6d91835e,d236898f,8857a64c,4d898098,9af6ba60,392b774,6eb99ad,e21f4abb,cc05952,eec3fe34,f02d64c7,e7a91658,b0b11b14,118c3489,7bb2a2ee) -,S(5863f940,a45c8f5e,a2361500,84c588b8,a7f99d26,84121d59,9073d38a,69494c38,db422c38,41a2bb32,98390c98,e9f4c23c,da27c64e,a5481870,b33a2bc,866852d4) -,S(3492772e,d177b4a2,5f9eed03,7094c52b,aa72dee7,1c5b315b,70948dcf,a1975a64,c5a26844,26418929,b5bd1488,49b3241b,d0eb5243,61106911,1fc32cdb,29087562) -,S(4405762c,ba4f63b4,2401ce63,120c3599,af37ac13,d2de044d,26d830,9e664a4b,3143da5a,8319bf4d,32941d58,e9bda807,74c58380,ad8c3a33,460bfd85,36d9baa2) -,S(4894f457,1324691,8f32111,e1bd94e8,a43f717d,74e8c465,550e864b,9ae2a16e,9c89818e,6f09fdc5,b36c65f7,12f26be6,40598712,fefda799,4b200967,7de01ea) -,S(620abc9d,4efdc1a,55edc41f,29834528,ca87b333,a8678e8c,205d6817,cb7ec3cc,f524cc99,9e911d67,dd0e8bd4,3e003ec1,64af288f,3135a602,4e93856f,8110f867) -,S(d69800fb,9fe61ca8,97f77226,d42749b,1274176e,29bb85a6,226f91e1,e8c62a7b,43baaafa,e10649d3,ff2bb0cf,10c58f8a,f01fd3f4,1a06c245,a4e9c483,8bc9e3f9) -,S(87a12e5e,d002cacf,f55901c0,d374f81c,ab9da24b,80e1fa9b,25f038c9,38344721,36586bc,17aaf4d2,5d02ae3e,e9f98235,f9d605fc,1954be4a,dbbcb917,1f736d72) -,S(a0af0d5c,bfdf4fa8,98a3ea89,867721d6,3178341b,ba30f091,946c72af,bb876624,100f795b,18dd85c0,9af012b2,5d7d5d1d,5118d02d,3837fabc,ceab0b23,99f98e43) -,S(ac94b41,7becf857,1248a94b,a853f4f9,dd47284,157e0b9b,1756c4ca,fb692086,cf94bf3d,d0c7f89f,acf8f678,5508e510,faf27a33,10915d99,80b9fcd9,62f75c92) -,S(649654d2,966fb2df,b917367,e2ea4034,fe886725,3711bc40,8520d5d,579a3481,bf8ac886,a7550c40,29279fe1,c4d330d0,89935427,d6967412,66d79ec1,f1a2780a) -,S(5f7776ad,e73826a7,fd2969a6,1511141f,cbf6fb11,23c8d7e4,3ff93835,ee1860c1,9faebe0,2140468d,4564f7c8,bfe4f097,dd0ba493,8656fb43,ea9f0f8d,22089e5b) -,S(f5dfe7be,f4c42f3c,e91fea18,10402c5a,9072b001,286a7371,35a00fd5,c71e2f17,9787d33f,821a0633,ab1982a4,f9240b53,38a5644a,4d203b1c,6b5cb212,3c837b4e) -,S(d3432817,3f33fa7,e517d6f0,408bfcb4,6a882c0a,6d78feb7,44f731e7,4e1bed23,bc1e6ff7,cbdaca91,edd419f2,e80e617c,506bf8d,8acd4548,8267938b,813a281) -,S(a4420846,95528dde,2c52d5ec,cd67266e,3024865a,c6e812e5,1ef4f780,505f9d2c,4a721caa,63d62b9a,c23ac717,7a27e27d,d54e5ff8,aa204bf7,3e6b3131,3ccc31ac) -,S(b3818c70,ea29c1bf,db63ba44,1e42c842,11f9d2e,4d6b07cc,79938d3b,b294b820,1b2c711,a98418b8,15abf79,44fa75b7,db8965c3,1779d4e6,1967f009,8c005d2a) -,S(3854b55b,def18a47,7e87f62e,d7607c6d,aa2e737d,e0e5015d,de7e90e4,570d43b0,2865de79,552c68ce,4841ad3a,69376a36,9d74d55a,98c35d25,f97656a2,fa22785b) -,S(e2e805af,78bf592,6a37fac8,7429f6ad,88c45522,e58e5c9,2bd2ddcb,e893ff33,c2206185,254ef80d,fcc7365f,1dee9a3a,cdac0ebc,d0ce6a5d,4c9a6875,f07a46f6) -,S(37510b86,df2d8e60,10d40e34,77af6c24,47f2a41a,fa35ed49,224bee62,eb0b77c1,1f30b802,6a3288d9,714b33b3,7a09cf20,cb754f09,730888d2,a09869ac,1e905ff9) -,S(14b2bcad,c5272c56,8930c574,d745fac7,d190558c,121df6e0,c2c9cc1a,f9662fcf,baaf56ed,f70fc0b6,520bea13,a8794d2,d397e935,65841028,6dafdc16,96caaf3b) -,S(2984937c,e3d6a155,7a185609,9e44bfb7,28dc6d0c,bd8c628a,23a383ca,3f38082a,637c5e4,9b0943d8,e09960fd,2375770c,5d4dc4b1,3ea460df,d5ba49ab,fd6339c0) -,S(e64f46da,d9b9e7ee,3d2878b2,f604728b,8203a591,d02e7d23,721fc436,165918c0,f7ec0e4c,9f66adf9,98b8e41a,d43fe3e4,7cb9be23,6356ef3,ef5b9a23,711e1140) -,S(3f587c9f,1b88ca37,d32af584,e510609e,ae113e54,8d07fbb9,a34f6916,908f686e,37712f53,41485518,241835aa,d31c45b6,f5370c6b,238380a4,ddbd0755,17b2b49e) -,S(8218250d,b1ee7484,b8892bdd,53be130b,4b5d3db4,7c3c9e36,5a17baac,5d8654a1,f19955f2,a7f954b9,2050c815,8e801222,8e77405f,c9f0676e,76ec2e4a,f3b93bf) -,S(5ad1a4a2,55a22c56,e8d17acf,786356f1,7ffd6453,262980f7,188879be,9e1eaac5,fec5d2b7,ac26e4f2,d4d7af01,b49295c3,3a969fd5,28e3aeb3,90e86bf9,85093dc4) -,S(1c92ee58,c5226166,c313b491,5c731d34,739068b8,f0241dde,6f0d7151,243304c6,5dff29a6,1197aab4,c1ac8a25,625c4dc1,11729680,15f03488,b8a4baaa,d541bcdc) -,S(fe622f9b,fd9c4ba8,8c80c82d,d1a07bac,c1c9da11,996240cd,50b6a41,f6f8fdc3,666e59ff,e9efb9a9,b7c36539,ac948438,f1de235b,fbed8fe7,3a084076,39f6b901) -,S(b2e8301d,ee34bbc1,d95de73f,b947bbd0,325bb3a5,555738a2,8fbe4e3,601a40d,6953963d,3496413c,53ef500,6def0fda,607d9a9a,319cb93e,22d9bfd,a0c3b807) -,S(1505e140,4644537b,56da7114,5efd34d1,566ee38f,dd4b549a,34ff312d,5cb9bb96,d6440284,c1ba972b,413f8c12,7fc40001,39954fd2,5ee4993b,4dcd5e3d,a2b843a6) -,S(7a524409,67918e47,53b451e5,243c6996,c053fce6,1f492995,8d2bb84,9fd1088d,e089d973,19788a2e,853a3067,c4a98c59,4fce75cc,a9ba908f,37780e1e,567b7284) -,S(69eff8da,8efa75c2,ab052d71,e898a975,c58a074f,c46fc6b3,2b385e41,93ff5a30,30e873ca,f0e7d1d,e58713db,cf7c5c9,6c9f068f,e0e3d1d6,c3863d44,8da1cca4) -,S(64a5649f,2da4eb15,1be3fb68,b1210cca,61b32492,60225ef5,53426992,95e6d6ec,8c53c12e,8fbd7c,811d4a85,95787105,4719c5fc,368845a1,6b8babba,1d92f56f) -,S(ca23d56f,46ce3458,d95a5b24,d998188c,3ed76a22,2034b337,933c4298,8c804fdb,efcbc7c7,d0d11fd3,ef1c0ac1,38d1a2bf,d0e94a85,a0700cb3,630dcaa,426a4c43) -,S(630b2d2e,62bf28a2,ebf80f2c,2bb10cc,82014ee0,c48e15a6,4cd691db,dfe8a55,908eba92,e889f132,4da0f927,9c1bfb74,dcf16786,c9c8a964,79757a79,d4443e9e) -,S(29b5c3d2,57674ebb,1cab5fd0,56534261,5a059eae,c8002aac,c000a857,a7b7c840,e7724381,f3f1cd4d,198a06aa,33b7fb9a,d6acdd57,45f900d7,be34fd6d,4f6dd41) -,S(f4b9c47a,2454985f,e732c151,3216f7aa,f5de769,89344c0a,4b8b46fa,c15508db,9c51095a,c45d901a,75229288,fe5d49c1,1dbab43b,9a030cc7,c6d71bf8,9d097378) -,S(af0dbf55,79f3f1f,91847143,99a09fff,75c8922b,48213c42,1cb17d11,2ab7ac71,56e7f5fe,e96e464d,50cf98b2,90a04917,430bc2c6,72a411a0,842149,8fe23d66) -,S(7ddbb2fb,f5d68e,6acf574f,1fba12e8,323e06d0,b6b80cb,1b9e9368,5543a8e9,888670aa,f057a051,1738d69d,162ac2f4,9074e5ae,d28cd6a3,a30edf9e,e874d7ed) -,S(43612257,2c25dce0,4a0273a8,a83890da,3a27848b,103d5ee9,1f0bb33f,ddf131c8,62cf1a80,7bdfeaf7,7b9d90bb,ec403b7a,b4261e04,62a16c58,5c9e1435,afb177d3) -,S(8691a20c,6df3b947,e173735b,d764ce9a,4a7773b4,4b4276a,873786a8,8e5b0932,974ca0c,6644983f,e4288afa,a80c03de,fa8d9215,c148a63f,1a1d4aef,365d9e81) -,S(7376518a,528c1190,b95cfdb,ef241485,c84f34d9,3690041a,e4d8b0db,295fe87,fcd56fa1,3d5cbebc,ea197636,ad3e7bb,f9faf472,56d44489,e7cbad3b,ca9e01e) -,S(9c5e491d,838b7471,87eeff8,f44ebd70,d6087ba7,fa2b957,8302e46a,3e5113ed,3e312d47,a32d61ee,f88dcb4d,aa38b024,7327ba59,cd377798,75bcd10c,2aa13278) -,S(884a9710,9e6e95f9,9a52d8a3,7b91480,d33a95e2,4f385ecb,d9666bc7,ddad4c63,f39408bf,4f27f2f4,ef65b195,b231edc6,c50aca83,60d23ff3,32b1c3e7,149e8d6a) -,S(f99760ec,771c8f39,d349fa7d,19b0ff65,bfd2ebbb,f2d4707,eff2d646,4beca7fd,d71a5750,a9737ff1,bdd2fbbb,9674905,5508c2eb,ad22aee3,6aff09f0,1fc9d996) -,S(f2cbe279,98214502,77f79ae5,22da1671,452c8e94,27562e3e,5d78fc17,9e758e2f,8334d592,9b50b714,a50ead97,6fcd8b12,f9806edc,5da45d8a,a226e029,282ab52d) -,S(df67bf7b,861d0636,30784bd7,f9a472df,6c2db3a4,7af8d06b,ea3665,cceb76fb,e939458e,513e55b8,7e4b90d4,3f073e47,620dbdec,d7ceb425,1353f4cf,a8d20624) -,S(e3f17365,4bb1e860,d1812852,c67c0095,50f82b34,434c5326,d5864884,bf64fcb3,9f07baf6,ae6b8c28,e8a9d807,22a97f51,bae7c98b,daa09578,5a2d1fae,3f359139) -,S(1cc073f8,ac4fe62f,e311eb31,42bd357e,45ea17,a844528c,7261bfb8,24642103,52303125,ef059a48,142036a1,ab6353cf,90a021d8,30a936ee,9cc4ffc4,91f514b3) -,S(f6b037a4,9394a077,7483c0ef,326e694c,be4b01a0,3accec75,629f7224,7fce7f0,f922659,25e4434c,4054ea7d,d4bdebc4,d3801c39,be53b037,715c6ec2,88b34db3) -,S(74966556,eb8c4cbf,cd364f06,b2bac116,5b914c76,d394dbf6,b5f2f7ca,14e54207,8ef7ffba,85b9eb27,f444de36,86ce67f7,75c8eb30,5bae0c6d,1962c839,a88202df) -,S(44d3ad0a,bd1f2ad,30957e00,594f7738,18777896,9b4237cc,d61931fb,a564ff35,af69cb36,28168fbc,f194f55e,e7691ca1,88178a44,2e6bb250,84c6ea77,a3d41748) -,S(7914f911,b6956f5,cb0fa063,bff4ee00,cb67058,3dd4eeba,daa4e445,97f816a1,a61b333a,e72fef24,a47f48df,90b5384b,b25b5f8d,5530a5e5,117a4f45,43948fc6) -,S(65a31bd4,10c97121,dcf656fb,55a71c94,ac34ba43,c3219b1c,86f19f56,bda94c38,a2e19092,35d8b549,b1926524,132a5220,e26beb5,f9d87ddf,f46aae23,dd8834c7) -,S(eb092b73,5b789bfe,9a466b70,3801b511,aaa33260,407b8750,cad24563,abaafb49,ee29705,18088ea6,132314c,999ee924,5f50346f,c7a9d114,169fc20a,2e6b6a42) -,S(38574e2e,8ff7d427,3870b6ae,d859322b,deac3824,bdc1ec6c,e34d88a,8d92196f,a0a6691b,4d770ffe,e5503d61,bba954d2,f4185860,19aa60f9,303f3e89,9fbbc7d6) -,S(5e555cf3,adf0d5fb,530f87cb,6fa753bd,e2c09d9b,d703a899,f27d2a15,a051a64e,41bba138,c76d1e98,90ce88be,1053bd3d,559e7118,4b900aff,c048a494,24e1768a) -,S(4e8518ed,92b06242,b0f28b2c,e02582db,e5f908ee,fc660c63,964f5e88,95b509c9,9e4fa860,cd07c071,fea0ccdb,f1b9284e,393d9f61,45dc4ddd,5ded2dad,b8897e5d) -,S(507d72be,dc881de7,86103317,77afe208,69619a4c,f6cd3012,e04c8cfd,2029b562,2f2ec47a,963f7c86,de8497cf,fa70846f,22dad843,29643444,706487c7,d9999da6) -,S(c87295fb,299c6f1b,410f1128,a1c88eb3,4467d0b3,df7dfcd2,18fa3819,58df06f6,2977ab13,5abd0c43,ef791c18,5cdd6b59,443ad076,5f190cd4,77620227,dc38c479) -,S(5f9fcb3e,2d7f842e,22ae0d41,48d74b9b,66b8d98f,fb66e4d0,1f279be7,931731ef,523a9ed2,a911ec36,87619cd3,f7ffde07,e11a2b19,e90771b1,8ff86170,a747193) -,S(42d833f2,b9717832,1b9174ee,75127d0f,5a850a63,52452942,56fc4257,f90f74e7,fcb299b0,ed234bb5,4f0c9ad3,e9a87bd3,f4a83bd9,916c9050,6952df68,f39dbda8) -,S(cb173f92,400cf477,47ec4ce9,f9852778,6636247d,55279b52,81388daf,99b77f68,f9d99960,1e669f8a,d8283ced,317eb2bd,5aebe201,ab97a62c,25573a0,65b28e0e) -,S(a73a52d,a2ed0dad,e9943a25,8e6a1f0b,6b2b772,b010d81f,a6eb3bb1,61877d65,71f7bd19,7e9d575e,25a4c592,92061743,2cf69ecd,f33705d0,3429966d,956a2e58) -,S(209411b0,398bdbaa,7412b2b1,49162c31,da88d9c1,5dd4db67,8ab3e19,c90a8415,1392e77d,af6bcf59,3162c8b2,2e8ff0b5,4ecf8e01,4fbdc743,dda8f061,ba8a24dd) -,S(74590b3f,a03daf8d,537d9eaf,410b6c61,780f4146,44e7360f,7d6e2710,3c8a6d9,d40fb53a,1f6768ae,b4918201,54dc85bb,62c5ee68,614f1e3,b6cbbdb8,e182d9f4) -,S(cd77abfc,78148f0e,1acc919d,e3afeee4,2cb6fae7,5f68ce7e,cd31e3a5,adb54544,a46dc809,f9b1d0ee,4ba8872f,95166de3,87b08a0,b68b3622,492841d3,f4c8ee1e) -,S(ad1d5f2f,ef4890e3,5d1916e5,2dc6bac2,612d3b0a,3511ce92,94262b7e,fe2da353,6aff87fe,3778f197,ca8b1a67,9b8f89f9,69fcaaa5,4ef0a629,c0dd311e,ae83e568) -,S(de45c27f,fdb38ff3,a91c0dda,56076875,be8a1369,23ef5a55,26af8829,c9a17705,43564551,83b6ec8c,48c1daf8,d8f0cacc,4b3bd932,5d6e5adb,89368834,2ef5ee90) -,S(deba00f,aa0d172,a6bf1c71,6d280e2c,8c8e35ba,9c15f0cb,ae574940,fb78883f,2b282f66,c9499232,dbe30521,da2298c9,7a0dfc43,562ac5af,74eaac20,1d2dd708) -,S(eb95be9c,eb4d5db2,ae9071,e5dca616,dcdffd15,762dda32,5d13b576,f6532b04,c21f9054,d504aeac,79f98cda,de167ee,60e8cd52,bd44e4e9,3d66e2be,a9867741) -,S(a2849585,a2d9d78b,9da83fa0,cdf7f4b2,62c29e29,876297fe,3ad3bcc3,691acca9,a165f5d5,9ba43cba,816ddc9c,b33c4d14,e4f768e7,96ce32ed,2f711127,7bb8c720) -,S(e5a492b8,cae88b61,c72c8772,eaf6de20,40c89597,a4c4c703,85c28e29,62bdad2d,a0dd4bd,8cc5136a,184fd7e3,aa025c2f,62f85693,163e726f,cffa37e,2be168c) -,S(875a7369,7940cc11,b00b28fd,c72b31f6,19c9018d,5c261af,f1cef7e1,be71b61f,93718642,241a4e8b,22760240,2b4f4e1,fef54882,1af31e69,cd45afb3,427fe8c0) -,S(39a301a4,69836ad3,f98d7086,24b53106,fd9d9aff,c1253059,f45617d6,ad6c0c7b,a7f00229,6ff382a6,4bcb9dd1,fd9afb5,4dfdc2f2,bac962c4,8bb76603,7224a403) -,S(8bc53451,922203aa,caae8513,4deadac8,10c585c9,f9fb44bc,57113a31,9474f090,a4bc9c8e,8ea5d122,54a6cecf,aa46b791,68cf14a2,280c86ca,177871b2,abc65b8e) -,S(796eec76,37c1fc11,3ef31366,dbefc78d,ba5735a9,28505c0c,e2a22ad8,b447b1bc,11e91c1c,f9195b5c,b8948081,7d8ca5e5,f0fa07e0,19ee5566,90da195b,c5eda060) -,S(ac52e134,1b531c25,60efb2eb,1c0c79b0,d1f3cb6f,3bcc4b16,6a7f701d,7d5a60df,4415cb74,b2ca5b76,985a1386,2278f53f,871813e2,905e51a,cad23265,64efe34f) -,S(c231c57a,ed49f271,2d571e10,fea59a11,c4d427c3,4a67b024,b4713af7,d2288d69,bb4ec242,6026ce7b,56471afb,c4ed8772,dada1335,61d07981,907d278e,70ce398c) -,S(1a1b76ef,11f3d64c,5670f06e,7354fc4f,a7c17129,75ed3094,b5a6df78,c8c03034,600c7a61,188e6ea8,76b8bd21,b121ee22,ba9d50a2,d2ce0fc3,d836829d,1f829430) -,S(82b4e49f,2d9d49c0,f409ce6,13b65a5,c031c8fa,adb3ec8b,62885760,c69bc5,67b8cfb9,56b80bee,5e5ec168,6cbad5f5,cddf38ae,3bffcafe,17d242ab,896fca10) -,S(bb3201,8ebb358d,575cf58f,c08426b2,f7116d40,8cd2d779,9acf6c4f,55de461f,8f3205b3,291c8da0,b0ebab8b,ac292913,12ad3a7a,83ac3ff1,6e6f55d0,445f22bf) -,S(fab9cc75,60a02c8a,e916bfe9,b61cce9e,32d37203,8b42b58,150db6a7,cdd40a22,132d8021,8e3b6ced,e6b3060,5812823b,80c7f0ba,f369caab,8b3b7cb3,bbb477d1) -,S(9f96535a,bbd2b21a,bf41bd19,549528fe,1353724e,cfa3870b,3df3256a,661c7e47,b8acdf49,a9783748,40232e1c,9a0f6854,1547b7d6,d1d60bb5,c321a1b6,54fee431) -,S(60d4754a,2faf463d,f7b0cc2b,ff4e6495,ea9fa9a2,e2f1f4e9,d773301b,3d406daa,43d16225,6bddfb93,3588da3e,511ec648,5599ef3f,7db3a1c8,899c21ea,2fc91936) -,S(3850610e,10a40ef1,5aaf4d4d,b11ce214,7c82a449,ea965cb2,5cd9ad46,45ba44d8,c10cdca4,aa919f20,4ab148c7,2eb4e6f3,7939c70e,e134433f,5c70e45c,fc30be3f) -,S(68089586,3a26181,a6966055,1ad8d431,9d325533,70839d17,fbfed5c7,fb84fab4,a0cee277,97d2ff7f,fb7a6805,604eec37,4ef4182f,a163c53,15924f,287bd447) -,S(aee5d57d,17a9167e,9d3ff19e,8eebeb09,7675b709,e3a89ec7,38280b9f,ab9404da,154f14e4,f991644d,aad6d858,940a6126,5a8f1c1e,ef6071db,5e138081,5e2d34c9) -,S(8f3362fa,659c58a8,2376ab88,c921fe2f,2c8a5de,f36c057b,3154800f,bd493950,5f88cf3c,3fc1ccc2,2105f3c7,8ba7b8c5,525a9fa7,7cf76976,8906d0e8,caa64408) -,S(2bfce32a,9d69a14d,324d8f94,15b42f87,25f5befd,ba3cc6ac,2a5c7778,f23187a3,f7e88e0,51ea8e3b,788e18e2,95355b2a,75fc3c3c,e62f7797,d3b02681,d6a3b63c) -,S(62984e62,5d026f0a,c6c82fb0,46dbc152,a05c9a22,3f55663d,5cdd87d1,e094022,1dadce42,d6b68fcb,19439f33,2d2db167,f33861de,28cd303d,c94e3a8b,7b26964e) -,S(15502824,b02a10a1,d7b13137,4175bcb5,6b70f796,fd3d0713,42bdee98,99d8a057,b391d51b,b2b89dae,5b687e16,e2ce1351,2296130b,e86a7d21,c1d3c6b7,b20eca57) -,S(1bd98bca,c0ed80d4,f23422d,c32c5922,1164ce33,55526ea1,61e1d9fe,518c0e11,6b0afff3,b0fa5029,b4e9731a,fe772fca,c0e30c84,e6c652e0,f22dfd41,a9cf0ef1) -,S(4dc9e532,d5543e88,a59872fa,24b99968,e649977f,9ea08bdc,303ca4e,d574bf40,7c05536,d9181687,133dec90,43cae3af,42dbe034,af05a746,b6de1ef8,20276947) -,S(3e92be78,d7c7db61,1049827,42b0d213,672cc543,c27628cb,f5985c19,5685f3a0,171c3afe,c69648e,7bb7912f,fdfecc4a,78cfd246,a4fe1263,e5eeedd5,330f84e4) -,S(57b6c4f4,75bb9ce2,2086a5a,dfd5473b,73b0f6d6,278afc7a,16854e6d,32b2842b,4fb4aff6,738f05ce,31ec7934,3638a717,3806d347,c11afd82,e39d492f,b961ebb) -,S(571ac8b,835c5f4,a7457344,e8572910,309f0d3a,26b849a1,b3bca2a5,28771b59,317ae805,3aa2855d,aaec95e1,72f4005a,6ae09ce7,187590b6,41fc13c4,9bb4cf9f) -,S(534c2141,e38a7880,bf146951,7d4ceaf2,a25bf5d6,a538eb1d,4161461a,ae54c4be,59dc6548,1b056dc8,c3e98364,ce6b76f5,fbc9c501,6ff24e0c,1c7bfffd,306b03e2) -,S(7a761f86,3a224193,157d3d1f,8fff8a05,e5c13366,a7ef7604,2cd3a1ff,f9f936f1,20e86bd4,5e93b784,f433d6a5,8056c6a8,e8d1fdd9,e924fd37,bd5b16fe,fa0ece9) -,S(c1497e7a,b9373d32,4bfe813c,32aa9dae,f1351351,c86ed382,fd3d4c5,6a54f62c,9401bb9,1621a327,2c233004,d6a8093d,f812ee66,604eaa86,32085b3e,482eccf8) -,S(2dd83787,e31e7237,f49a570d,adc675bb,147b91e1,3910f22c,e41bd16f,edf3c0bc,10148349,6883687b,7ee844f6,d60ee90f,1aeb7c0e,c9f83293,be96eb2f,5cd6d46d) -,S(938f1399,18a0fe3,55ddc7ec,d6dacd34,1d9c996f,9ab4f9d6,90b435e1,fbc0a74c,30c71b30,e7a3c244,b8a576be,9e527e6e,60d1834d,17908e6f,a0771daa,92517448) -,S(e71217df,430dc65a,d188f6,861b00ac,c3214125,447d8e26,7dc5473f,9471284,8f27019f,114e542e,96eb5121,b7c3e094,f18f6287,f2cefd9e,6a5290e8,5e1dbac0) -,S(ca2ba87e,4c040efd,c06ca7fa,50cbe414,b66bb2e3,ded2bfdf,7744f81a,91b102fc,24848b82,4019bae7,4cd7604d,101c4819,6e808ecc,79db885d,bed68354,ba3f138) -,S(c267ce5b,633c7f12,1be2b297,45b4dab9,ff488b02,c8f89ba8,706948c7,77167ad7,16184a77,954c3b5,f9e330f8,e8b308de,1489ebe4,bb9ffe59,f3f545da,e7748385) -,S(1eb9af42,96d58c44,bd6fe2ff,db05e0ba,1b5f581a,af842883,5a47a050,468f8b33,f88a1128,95e53e05,4e514117,5a2c54f6,a235cb08,3494a7a,991fba4a,fd0bf1b2) -,S(ba342b95,76bea3ec,15aafca6,2f4f505f,c35bc2ca,64e2f4be,22323b77,1ee39062,91be5746,1fb662f6,cc28e73d,f0dd61e5,20cd3ceb,2d6fb0b3,39a76e5a,39114afb) -,S(f3a8c7f2,86117118,a4714895,eda7f401,dce4be87,dab4d4fe,b55068b4,c948b350,1dd2f669,31f0ec62,74e8bd53,97cb6b50,d97f9238,2603c931,8ff1c6b,18893bf0) -,S(3cc304a4,3aa02bc5,25437a89,977b8ee0,9f5f997c,56c4d317,f531d22e,4a60f55b,9ce121dc,cce749b4,78823adc,c9a613b8,aaf78f5d,c2eac8b5,d5ee6aed,592c7bae) -,S(e5be6c29,b9f12f42,1f499fb1,13e54bf4,4a577fa6,d8d0dcd9,6b509f65,1b4f3587,7755eecc,721bdd9c,c6e8c96a,d398cff3,c03e77c7,9e34dfac,1f51873b,8771d40) -,S(f933bc46,f296b780,4284de6d,5bbeed68,bae90bdc,cd731cb,b9519c05,278c7fda,b6ec0484,faa4c53a,630a8b81,e1d567dd,543a4e55,4e89ba69,d72646c5,7ab3740) -,S(e1d21ebc,297edcc2,b595976b,2f65b2a7,a6797cfa,3e5abd27,34e2a962,dd2f507e,aa31ee8f,4c80a0fb,9e52f32,c7e4a69d,fbe8d297,8dba479e,b0c9f4d0,350012fc) -,S(c3cf0aa1,8e45aa16,343c52ac,41b12278,f9899b46,e17ef9d,d7b67f75,84a1eb72,174cf510,70418a6e,f83b3db4,97102ca9,5bd99985,f2554e5f,c32cdefb,ba47e411) -,S(e6a90aff,6e1f0311,34f93967,538040e4,92120644,8e8e2106,dbba6f5c,701700f8,93895ef2,1d3513e1,19228b95,86289c26,f3efc024,1ac2c963,b394cb87,265638c8) -,S(e2b695fc,8f1856c6,131761e0,9f75a558,94a4a7a9,2837dd29,f8e8a474,7a9b9a91,b580a2e4,240724d,5c5381df,27a17d72,4d0e638d,958c0a27,fcbba34d,da5361d5) -,S(c0660a14,6db599e2,15f813a9,f267d6db,4542a696,9b08334c,6bc80558,ae518063,6a901346,6bee774a,54ec2f97,47d7a8d1,e157a13,fcde8cfc,57e48d84,374f6ee6) -,S(5c41cced,2b091fa7,df1f8e30,3d78b117,842511eb,41717b59,f776e05e,39daacb5,dc4964e4,d91fc985,af5c0f87,f0026a6e,290bb1c0,b181fe2e,195f7001,52509f40) -,S(6abe8574,49cbaffd,d0e5fdf6,450484b5,f8636170,5c8a0a59,a3612dc0,8d0d52a1,c669b059,3a5fadf6,86b9583e,7fecc9f2,c5eae967,9eb5be36,a2018337,64703bdb) -,S(560dc0ec,2d407e81,4b5034cb,8d26c8bc,7c86487c,f74e2fb9,a076b521,f68e22de,faa241bb,ee929015,b4183152,5aff5062,3a270bfd,6026d94e,c3106e3a,e66783da) -,S(f3ef40ed,8d82c02,a141b953,e8593f06,b74b244a,b85edb18,eda3e693,3c8f90a3,aeaa6d25,6db6b12c,d9a6ab5b,d6d0d854,62c0d298,5a772648,db46b614,3050d4a7) -,S(413e0fff,df030385,248b1fe2,1bebedfa,77c1cb86,d665790b,21914da4,58a4479d,6fa9db70,80ab1736,ee7d54dc,e5d1b545,dd17e3f4,45b39038,595fe180,2b34b443) -,S(ed3c5ee2,cf1cc502,37e5c654,d903083c,6fce29e,cda0f427,5a6e1ac,940b8183,fd265e79,3474e60,109cac37,a867bb81,d8ba8b8f,94b13f08,c409ad5,362492c2) -,S(b98e14a2,3f5e5d6a,a99ef39f,18e234d4,42102e72,2e330d2e,e654b328,e2f3bf49,67a60b41,8e820ef9,72ffa57b,1e383b1,35585920,20434df0,e443c318,89734499) -,S(31bb6293,28793b42,dbafdc9e,6a418c51,f0a0cf0b,6da96879,11a6f046,c146e475,1bdb131c,b14a3d85,a532f889,89112231,341a546e,c88e8a25,8bfa341a,7826512) -,S(79b2d26f,f257ac80,ca67a639,9be17ff1,8ea0c10d,739b106a,a9310754,6ba0b252,e09448ea,b102b1cd,654b6e1e,7e4754e1,c63d11c2,46b0ec5d,31df6175,6b99e850) -,S(ab8cbf8b,c3a740d3,c1bfc2e6,efbd7ac,f444795,cf2e311d,edfd5c2d,124d55da,70599847,895f335,a8bd33f1,811201b9,a860555e,8cde2a27,4c348b4c,6ab449a5) -,S(f6b7c2ba,c5468fb1,cfa0785b,f67972b5,36367ef4,d3dc9ef9,25e88085,524e6021,663be56d,c325b2e2,3753bf15,1f6b2ea0,2d6a62b3,a3d5f565,2734401c,9c661a3b) -,S(f5d2e04d,229d784,d7af5af3,ea65a35d,637b404b,c431ca72,1bec7fa4,dee33377,16c90231,e570a434,700fd8e7,cae5f8d,fbfda2e0,e234ef23,a2e82452,a0a953e9) -,S(4df218c9,4277fac3,3ca43921,e29fba57,6f183e74,fa2ea781,88b8245d,eddab853,7828e929,6c589e6b,1d80b036,2c9bb0c9,2c2a79aa,378c597e,8a64b985,d6e4d108) -,S(60e1cbc2,78d4a0bc,b7973b32,964da674,9e2b3448,24075a0d,1db93e51,ee3414c1,cec0aaa2,3db6c3e,6d6c3189,c2dca9de,8ce91791,a721ecbc,1f09c7ad,468ee8c5) -,S(1e7a9c4d,a6cf3251,559d58eb,bafd1a7f,ee686c72,8b1ad271,d9da3b15,6a9f3737,794e3bbb,cdc0df3e,b9669a10,8a32d7b7,f3fb843,388cc55e,aa893f64,ce1b960e) -,S(e8984316,5ee703c2,a413c7,2a5c8ea0,605c0b4b,58cb844c,85df83c3,b4f361b0,69fd6f89,5cac1716,f0bacdd,5a880f12,f964c2cf,1cd402ee,27ccdbcb,5188b64d) -,S(2b95eaae,6078c535,32a23225,eb9821e,c7bf864b,75187df3,2736459,f0797e4e,aa6e1922,b5102e69,77fc23b5,ac2de98c,edcbcc37,54c928b1,7c7d124d,980666fa) -,S(403c1933,59ac9027,7aed0f41,f9ebc507,8ae553a6,ec3b8a4e,4f66a841,19d221a0,edab5156,8667e7b2,c7793e17,839e46e7,85a6c7a0,8af7295,8e25b411,13829ead) -,S(fb182399,c535de2d,556ecded,54e42f29,8c0054a6,1dea2477,9df1c7c3,bb53e1b5,7bed179b,73268027,4fa6b227,d13763d8,4fa62dec,2e351ac2,d3aa59d8,8961123e) -,S(9375a9d3,ecfff9b4,b672d90,45aa4872,f61c3b8e,4cf86a38,7daf74cd,affaa521,41c7bd13,f4e491db,77a42bb8,d65ba77d,f03acc6c,cd789759,37486d08,c3f691d4) -,S(abb9554e,1b68c554,81d8bb12,5b426a4c,433cb110,79254f8a,ddebabd2,9f5be0c7,946d680c,1bee958d,32089353,41ceb7ee,5b4a8168,a6368a92,e1ab1050,5d0e76d4) -,S(56e8aa51,37b38531,1e5e1097,4df857ea,b4f7e53d,11102021,6463c212,ebcb873d,b51e1981,7eee5672,afe7f688,92ada73,abe703ac,4e19770c,97dac300,8d3b1632) -,S(ac487fb0,4b00962b,2b098cfc,4f22eb28,e5007944,d32a136e,5988dd47,d9828f5,bd305529,5f4200e4,c5e6238d,76665bc7,67ad8402,dad13d8,6c6fb316,a214a5c) -,S(1dd7562a,ce273114,660ccde4,5f41d690,11621bce,56cc49c7,2016f19f,d94e9e9f,a8e8861b,ef664d9a,c19391b6,5bb97715,ef677199,a373f255,876aa9ad,d8a93043) -,S(c198019,cda66df3,2bd528db,e3869d6,1d1d7cae,57ced846,eebcf1e2,bcceb8c3,b0a9c52,ae2b2625,7699d3b1,861474,4d66f09f,8b795d81,acd3e5de,902b247a) -,S(950f54ab,3cb421f6,95404b53,9b1f4936,6b43e61c,7bf9879d,168027bd,f58dc386,e14586c,7f005f5f,21e122bb,2a35194,d5d2fcfa,4898c279,cc296b24,9b48b2a0) -,S(5b20af8a,31b69820,a56d0df0,c7374c8a,37805449,81e0c017,83b4ff49,2bd40ed9,7e49b8a1,c5bbcb32,55991da7,99613598,cfab9d8a,82f731d0,dc2f52a1,6ec39c55) -,S(eb8a10cf,3777670f,437f55c0,2ddd8681,63da41ff,5b534c63,ffb23ac9,ecaed755,99c18d8d,df2ba9a0,d46ea92d,8b983f50,c16f14b9,86b955e,a577f332,10533df2) -,S(12977f3f,d75a9c72,81358c91,73664b40,8d8ccc98,45153ede,c62b189d,8da2b176,f24f505a,75761c5d,939ad836,17f0c6,dfd8a2f3,fea04721,9078e2b2,1aa317df) -,S(7a591539,ff4fc3ce,2e2936d3,50d753fb,131ba419,8d034c65,e76d0744,c159096f,c95d8b25,52b3920a,6341ef43,5e3e797a,446565e0,652a562,7e0674c7,ca243425) -,S(993061ac,819fde52,ae500ed7,3277ecb,fd08930f,8adff61d,f5f9c3c6,cca49640,d54444ce,748f6058,10051838,52f0073a,8a5d1477,f14111d8,b623a316,a67ad06a) -,S(cf807c40,c5664fbd,910a31bd,ed3cb7e5,2e54d1ff,ffcb4b43,7a579931,6f803051,a5d21e6,6fa9b5a8,2882b77b,ca66b6e4,163d579a,d245d089,602274f4,55ca9881) -,S(9c0119ba,461d003e,c6fb7a01,2bb32b89,ec819d97,8fd4cfec,ca1c3b2f,1f14f0bd,b41c5fa,ce1e9a54,f1605e84,61b5e6ce,c11590c0,15838059,2c511360,f4b537c4) -,S(56ea3259,5d97b7f,d7f9fe51,b525d73d,3d77d483,f8bf8460,8d874d25,aed3da3c,f764a40,2cc9278a,f1ae6369,e1723bf5,f0a15a47,992f8fe0,ae33752e,473c3058) -,S(2851e3cc,2fa6752b,e0a65326,46aa8445,71736e1,d22a01fa,ab3becd6,50460acd,ad778ace,631584df,da4730a4,20242779,81f9f829,cb18b20f,8ce727b,d62d64b7) -,S(1674559a,528fe0ad,5aef46f4,eeb4e0ba,34b8c2e8,c23d3409,5ec1e164,ef351979,afaef98e,ee2ada75,7be9675f,fee76686,d2350972,a9d1b80d,fbbc0719,efc38b21) -,S(ede70ea,37946f71,848d72fc,7a98102b,f9c167f3,219671ab,1843b5c6,8ba6d7c0,920d6108,6929e5b8,30c4fa,eb155b4c,9d324001,59d748c9,d7e74980,d54be37b) -,S(fd3b1f22,c5037c8e,93f4f9ac,27ea723b,3d3e861e,694ef349,dfe51f83,50ac9fa5,cc02effd,6df18244,fcbd177,a624ff17,b0da8fec,fd60624a,3d066be0,9c466cdd) -,S(72f037df,352a4619,729bc550,e23ad7bb,6f2d7977,7d39ae36,bbc1d45d,d6e864c2,c4bfcde1,2a5cbba3,7e047070,5937c2c9,da702040,bf49cb5,c762d60c,e8fca76b) -,S(f17a9b25,601ec8ef,e320558f,ca832789,d0d8d558,76ff7c53,6af0f84b,ca799a61,c90583c6,2a863567,b0d8c41,e47c3d8e,7e196a1,9269a409,31a1eab8,f1402837) -,S(ea9fdf49,9e201fbb,b0a26a71,1b9be2e,dd17b2d2,b96390c,4aa2dd00,83bf5c86,64322654,c8bb2a83,ab0cb743,eb907234,d8503fe7,381e17be,c17bad5c,d33b4df1) -,S(8d5d6f0a,24aa6e3e,7dff42b9,ab8b22aa,656788b1,1e18ca35,b4ca6f19,1d50de6f,d509a2b5,e9800d5e,a7d1d047,e945e693,2e5c1923,59bb0210,1b2e8956,33e0257e) -,S(25ebcc4e,84a1d22c,f0a8c980,8252d96,7dfd528a,808ea293,ffcae94,50e1fb81,3127af8e,4012c2b5,c92e428,2e455de1,681eb1b2,6e660fcb,4ee8fef,b64c6101) -,S(c55c17a1,dcd8fa41,8a3edb5e,c2da8678,4fed0840,522b24ed,4bcb85c8,cc45c20,7d583091,25261489,44b56fed,17b07906,9d156fa2,e9bdc462,eeddeebe,68f4f463) -,S(f4297f59,21a867ba,1e58b9e1,def633f1,18e058d5,a7889721,f0e4814b,7e63ecce,a39f359e,35a123eb,5fb66d81,f117858f,b0557859,aa2c388,a8298d11,43f137a9) -,S(626b0a,cbcf0e7,daf7d218,74f72be4,8d824883,4428bfee,f82ea516,c2d1b98d,74ae6867,1c27a642,53a36590,5247cbeb,77173b07,2e429de2,3ce09730,8d54ddc4) -,S(8ed35ae3,c02c5db2,acb516f3,2d3b6823,61964f2e,701889ab,26dc9512,ed40172c,aef4c71c,e241be56,63a091d9,e230463d,237e0717,78b7b6ba,a63688c7,6c694334) -,S(5b082ab8,963510de,46c1cc49,4ac6d3c6,dfa25f33,8627a00b,6b98121c,73899ed,cd8b2b84,185718a1,c4686ff0,7cad18ec,fe3d4532,9537910d,31458086,c280bb32) -,S(deaf505d,b08a282,d5274de6,43c5719d,f51827e6,2ed035f1,74279276,7ddc1158,c1067344,5e4c0d47,ad1ca85d,713a5916,1aef6960,9294d738,103b945a,e99ed1c4) -,S(eb62dcb4,d820019c,e865129a,28b98b5,be6c6e16,a80f7c76,db3a15ee,31ba7aea,e78eec22,be4a175d,68b2257f,c5adbe46,fbe31c3d,5eed4736,2304d80,ae4577a7) -,S(6c58cb64,7ef638c2,337cfedc,a9345837,597ac142,577b2230,7d231a3e,5a9173cf,563008a5,7b823427,60bbc400,5f604024,92f0bcf0,2ab2430a,5d7accc5,b62cbcd0) -,S(106d8978,775a41b1,12f07815,7c3bc5db,bb5980d9,c745806a,b5ca5ede,8b468d51,bf960349,6f7d7906,141bc4fd,b1766102,e8dfc49f,decb469f,75dbc54f,21338dab) -,S(cd6124f4,21796b6f,44c34982,8b536ef7,44bf30ec,6ca08142,e959a35e,c0385224,97ccdb9f,2896e815,19bbe9e8,ae491e61,e83417c6,6db8b6a9,bede3aca,f6608ea1) -,S(2918b2d9,b0bd83d0,b8d02815,59219c6,bd708e2f,2139ad0,1815b1ff,ae60e03c,f322596e,c56984f2,e7b2ee90,8a9bb56a,d213f84f,3088aefa,67e372f2,76e2a233) -,S(6d3fe999,acc04d13,2462f14d,680a90c9,89b747f2,3601d779,507c36ce,8c2acc7d,a6c7413c,36b6399e,58a443b4,e4137ea5,551a9fb2,c5397457,9d55b48a,5df0e30b) -,S(bd74ac79,8b320aaa,e3e51123,9354d4e9,280c99c2,809e88be,13980305,62d55d52,73477881,9b9067a0,78b40108,38ae59f4,3f6ef064,ba35209c,46a9f0dc,aaf84597) -,S(303f6cbe,866b4574,9d282217,1f571fb7,8c54dbfe,901f2f43,681ebb0c,76e5700d,b13dea58,d3dfe08,7fd043f5,8e63e565,85230d6c,273d9e3b,22145e39,afd6ea4a) -,S(3bbb0824,16a2e3bd,e328f013,154f18c1,4e840030,707057cc,f4fa0fae,ff56181a,18b214c7,823b0cb1,76375146,7a49bb8c,ddc0047f,782e3802,be12a119,ecf0f480) -,S(ef42fcbc,999a3f80,b4e7319b,1fafc2c6,49f51845,2e423c55,f57e5e1e,f8338adf,786ffec5,60464882,48641155,38aac187,ced4678a,cee2b9ea,eab6ae61,ab2061e2) -,S(afb21e4e,c095bf31,34276f4e,f1a4883a,6038c20b,a7a87ba6,6288bb1a,3bc6f77d,cda832eb,73dc0e9,fb77315f,6cc7a313,2212c7b4,1075a290,d5917033,62363bad) -,S(329c98f5,a40b81bd,7d121b90,78b50bdf,bc16c9bc,47744368,34a5208f,20d39d63,dc14f7d8,4bd2a1e7,22fdab98,1044d6e5,98515df1,7da5536c,7a95866d,8231a) -,S(6929a4df,e15e7ac8,e8a9c5a9,3544af51,aa621dc7,ca04038a,9c9cf603,8e081754,e1333f46,e4d1f151,f2b8c341,d2ff90cf,d36cf73c,6f441b4c,5c0ae272,6a25fbf3) -,S(f40fbdb4,27d2d68e,854cbae0,24ea5980,5948ca40,e3fdfcc3,3efea0a4,57e2bc24,33493d84,41c8945a,9e291b58,5e12789,34990a7f,5fec49db,ea1ff605,4bf8802f) -,S(220417f3,d9fb32c0,1439e473,d638856,9b169c38,1057b780,c9de7d12,e30dd796,4cd93672,5abc4e39,89e64ed1,af9b3d4b,4732ac76,a6c34d6b,23274573,8d765a1a) -,S(dcbe3dcf,2c0120d9,4d6336ae,6158bdf2,859cdb03,8c76ea3c,cad4ed11,13ed216,670823d9,73c74725,ce929318,c2ea650d,5feb7c33,c7831a26,821f2614,7db7d8ee) -,S(34de2319,c535a31a,87fd9b70,33c363e2,8ff754a7,9e0669a6,37230443,228ab3b8,31c65b12,cf6f4a9d,662238b0,c8ab52af,ceb96acc,35b90b2b,81667b8b,dfd9895) -,S(f0fb2bde,a5626729,720ff432,542c5e41,abf0fbc4,772aca7a,75b882ab,2b364acd,114edca0,74520c9e,2f5b8059,59c5273f,25d2e621,d2f55709,b42d187c,932b6bb8) -,S(90477ee6,a00742ef,78662c11,f3725077,dbda7b66,7ba55b55,f9bfea1a,4c5f88f4,467196ec,638d137,33971505,f291dc0b,b9d0f3f8,f284e3ab,9035273e,d9c7279) -,S(ecdef6b7,455a41ff,96cf943d,e489858c,b7abc526,e41d463e,b24a56f9,dd6eeada,1116e7da,9fe72782,e8c656b,9f677c5b,dfb3e46c,98957c30,49efd7b6,dd5d3258) -,S(58d30bd1,d8dbf5d9,885b6e7e,4f28ceb8,381415eb,3851a031,ef04b073,65e16598,9cb96ab0,546246fb,f5cc0878,7b99db0b,26c9bdac,184a0eba,728fbd26,bc880480) -,S(a7587d1b,771b3421,f56e342a,cca98e7d,82c7dc60,765a481,53379da6,fd341c10,9499ba9d,8351d194,213ba35,43d4b563,aa28bba0,9a6d8811,9b55f389,90742929) -,S(8aa99d89,9db3c7e1,c28bfc5e,18abdfbf,d9fff46c,560e4fc0,cff65ce,e18ae6b0,aacbc2e2,bcc4ae58,1e354d29,617afee6,20ced0ff,859c62b6,669cf2e0,565a9bef) -,S(45d81a7a,b4158aa4,2e45fe7f,3966d278,75f8647b,defa0c8d,a761ebef,894ef249,93a76905,d0e785f2,db52e09f,573a461f,183f672f,9f10005a,eeed6e0c,d40d31bb) -,S(de19bc8,6fddeed9,909eff4,80b0760b,66a1a245,82e33be4,55b8061b,225942f9,6eb2c1f6,f604056a,15c4e91f,789e35b6,1a787abe,aded0f30,abd2525f,19486d00) -,S(653f0e92,977b7830,fa546dec,44f05549,80f5a9f6,61f2cecb,7e360efc,41d16380,58ba9f7a,eb7aed3,40b54d7a,6f9ad0aa,ab5eaa2a,7715d8ec,48d52ce3,c3c57128) -,S(c05441fe,2ddce6b6,64270b69,83d44d5c,251efcb8,2bce4665,9388eb3d,537acce,cc82b7bd,3a049b06,98feacc8,11a1c9fa,e95181d2,50c0c62a,55a6d662,c9587d65) -,S(7a569bc6,a089fbd,294dd5d0,b10f3a7a,31b6bf39,42ee97d0,49c9259f,7adf0a7c,2399d17a,f6207b8f,20286fc4,78896af4,5e596b09,7c97f662,9bff0c03,14db53e5) -,S(1c4c7a37,4e14ce88,fd08a1b3,10025711,7d96878a,e173d29e,1ac53a57,1d6ae794,919f9b82,e827cc78,7352f0ab,99770e97,bfe1b600,40cf1034,b7c5178b,3d1104fe) -,S(fd4ef218,a09baf70,57b53f65,2ca1e2e5,8386e867,521dc998,1bd4ffdc,619c31c1,b1d2e716,64fec6d9,3cc8bf17,70ab5f10,a49a0497,ac1586b7,b8299f7a,e92354ce) -,S(f012612c,1f933373,ac30413c,1b2cfb9b,6582957e,b74e4de5,29c0267a,e7552a41,a38b2418,e7ace7bf,3a15035b,a68f82b5,aae49192,5783066e,f0f0263d,6dbc86fa) -,S(8e0d504b,c9598eac,c4bd2726,8b3ad24c,a22b7534,32eb5a31,d7e54948,d57f6f4b,50f59455,ba1ea3a,5a0cc105,a1c40c4b,72637a31,44bf9438,a1e3b52e,7b30911c) -,S(8635604b,89ec22bb,b3b4e266,3e76cb3a,976cc78e,c7db31fa,fc16a7ab,411ed197,8a11d457,6868d117,4f41c40d,4c82d27e,3960d57d,4b1309a4,531c2617,b1d90227) -,S(aba7addf,c234513b,3e861382,654959c9,984628df,72b2a896,6459b3c4,86bdbd2b,ddec8263,bfdb4c38,c9e7fd,e4693b0d,962c6e5f,a4f9eb9b,9561e81a,f04a3a3c) -,S(12aa3b40,44f699c4,8ff6c598,8a7ce56,84f3af85,8cf2ebd3,4d59ca7f,f7501895,76397e3f,3c42935b,6a42222a,525c2166,7662ea00,25decbf7,8a856391,a03956db) -,S(e01136bd,da38f328,af447a50,43a48606,a1ab5a86,b3bca98,b13a53aa,c7061098,76f3fc47,c1aedcc,bf26ec5c,4f6ad56c,fa163212,65844d01,8d2f2b94,184b64df) -,S(639cb266,f0672340,d0a789a9,41eec287,b60c380e,f2f62f96,41b67137,4b286aa6,d381e7bd,5dffffd9,50645e56,63c36d91,83210038,d70df2ca,4bbb837,e8eff508) -,S(eb12f18c,89a6d2e6,5e07d20f,f7acf3c4,b903ce68,5237aca4,5692c0e0,f6a4714e,d26860ab,e6f97745,dfb01cf,f6225c36,bf62e5dd,24088d54,a6d44384,e9eed86a) -,S(8fd06b6d,96f37c6f,8e69187c,c5ace64a,6e36b45e,37de82b4,872731cc,8781e941,e7dc3254,3b40599e,852d4e9b,e35a5438,ff68b063,3b81c8ff,c2f3298e,931e9e98) -,S(d248d914,4ca3f10b,3fb66763,713492ac,93b42781,9119683f,bf0e0f08,1bb6b241,e7a2ca15,f1867e9a,d19ffdc3,f1a20d0f,2469fa6a,e04f94be,a289d019,c405318c) -,S(ba2150dc,15884df0,34a64e20,89023947,687d1322,475dd073,b163a4bf,4eaf0740,af92a566,a320a0a4,34095dc6,f02f765f,4ebdf04e,d81e2c04,a86e6e2e,923f8c94) -,S(fb12f487,225a6843,31e39309,3133f377,a6f841a7,f6f90ccb,18ce3d39,48b56616,e3358a9,406905b7,d6bc0a33,6a89a5ba,e62136a5,4135c3db,bb32f115,4cf92b9b) -,S(bdeb3e38,7c36bb9f,c45a1d62,f7128217,20e6d0a6,55a285dc,da87af3f,f59e0644,b23fb389,3cdb280a,43275691,3c1de5fa,6da12909,c0ebece7,12c9da49,69a3cb29) -,S(32f3ecc5,925ccc13,f753ddc7,d5c0c576,e80402ab,ffc6dc77,6e8bf74d,15735007,f950add3,926bebef,9d8e3a5e,4d0ebbef,24b54dfa,ae7c12d1,32b6e973,dc67c050) -,S(94a725ed,e57e5162,817d95b0,54e2732a,3afe3a6,52ae3e46,ca9de38f,6dd9f0fd,805f6634,f8ba79b8,ecd5f46f,74b741a4,de5f9678,d29b8cba,eec73498,27671f67) -,S(22197e54,d35357fc,ad20f6cc,986216e7,f24e6dc,cfd9bb89,3e5c1ee6,9a99b3a4,b3e7edac,abb1d1c3,d375f361,1f04a927,9d2995c9,3e18e7fc,4b5dca90,a2a3fe17) -,S(a51664bc,5a1edd2a,ee8ea644,7beef61b,419e20ad,ac955847,5e1d666b,1b4dd52d,b8a95fad,e3aeac7,bcd8670c,78dd1b2b,5dcad225,277ca5bd,f24f131d,94405c39) -,S(896a11cf,f9db64a1,aef51088,baec42d0,16dd5a99,98262f71,a005cdc8,ae8cab78,7a7263ea,f64962db,bd09a278,a3958708,e61c4858,1a759726,c225471b,20899077) -,S(fff75552,46da269a,2124d03c,677f59a2,18b995aa,e69c85d4,3b29f81e,5201a757,dbbf1558,6670c191,9da69467,6e8906f3,80eb3f61,34c656b2,a4ccfc71,4b3223f5) -,S(89da8ea8,56f946d6,6e9b07f3,db5b2ca7,49a07e5f,78b59c1b,e52e46b1,3793e198,25889e02,d2013d86,6653cad2,7b3504d1,4e547343,fec74a37,a3ee71a9,646a36b3) -,S(d260dbae,6ac3e8a1,442ca7b9,8f7118c5,7d6cef72,783c0b3b,a4ad7e7c,3a8836fc,e00ee7fc,95131cd3,3a446bf4,c21b85cc,45a8e61d,2d9d6cf0,287996e2,77b7cb6b) -,S(bacf90ec,75ff002b,c1a259f0,3c9debe5,9f5f9dd5,cc0cbff9,e8fd62c,4552a619,82dedfc1,42202786,a7a12a29,22937c0c,23bddd23,4418979e,78723ff2,6a9e5e88) -,S(1ec23fa,995a22ef,53a91dec,a5b2faa9,514b5ef8,faf125ad,da61f84c,5b13a397,1568ab1c,cf75692c,b7d41c53,2dd4427b,ed7043e6,cdfe01a6,2f9bcb47,cb97435d) -,S(48225de5,eb07155b,dd86e759,9e172a3b,b96f69bc,ddcdb051,af2dc769,f4450b1b,856ce939,b81d976c,6a6c249e,c0d087cb,36e28082,ba050de5,4948d92c,6693f4aa) -,S(e9ac9963,16c1ff8e,a7d2bbf4,148c8b3b,a869d4e1,290168f,b3831d6b,3bbd164f,2b1ac664,6bc87e3a,e6914792,d0bda8b8,5cfe1107,3d0447ef,e4a65acc,6eac846d) -,S(8af31ba2,af0b68c9,4290bdf4,b4b80345,5f52ee89,f4ddbc98,1dda1000,9c1a2ec2,a37cbc1,a5efc09c,dc944f42,a66a305a,b302eb17,21ce5088,a7deb46b,5223f0b6) -,S(1d211de7,d75d4389,4cdac235,9b0b9e40,6b71b8a9,8c0583a5,7d7a0056,b3e88779,3ae4bfde,20f83eae,96982e96,62d65443,4359b2bb,df249a85,c7c83b95,56d7679f) -,S(be6beeec,18aa8d77,20100975,3dc7d745,c6d49f9b,ea64ebfe,b8fdafc0,92a192ac,c9e14aa2,4bce41e0,f444030f,ddbf035d,e808bc06,63a70593,454ba287,4ebe50cf) -,S(b126dd86,555491a8,e2ab601b,2f133960,d86a7f9e,bcd2c88a,cbd8764f,1afee3b2,d22ae79f,fbc60439,baaf2c2e,418edb77,70837ebc,a909322d,b5580c30,27c20821) -,S(857b9c62,6350cec4,f928d456,7d30cad8,6f1cfad,142b338d,74a137ec,61212791,9d3dc070,f610ee55,cfb9cfaa,4bffda56,52f7fd18,7f354634,ed4f2dc,d27f9ca9) -,S(bbb7d30,3e242e87,2e94e3b4,27197ebe,5252c363,43ccd8ca,940202ff,fe5775ac,f2b5b210,a40d1fe,140f8638,3a5b0f9c,96885d5,d9857a3d,252523b8,d59d33f5) -,S(3e90a10c,a61bd12a,fe9caabd,e52dafbe,8bcd332c,e0ff8bd,7718b685,89e26447,3a4d342d,fec7d557,7cc52bf9,d7c60537,50150146,8a05baae,7b562dbe,b626a952) -,S(dc1f2531,d5e0d304,66b963fd,7d09524f,c66e6bbb,3855b6d3,141db170,9af05fa4,f1644b11,e8291f92,4884d3ea,cf89d857,fc98c3fc,e49fef96,7986e8e9,d67c9b0e) -,S(2b4714d1,fd0aa7ab,6c103ae9,19493efe,4a503d5f,beba56dd,93a8c9db,485c1dad,d65bb3c,47efcc3f,7484b6c0,9f51605,30542a81,d1192ac7,5d506c43,16f41220) -,S(c9ffd7fa,3b14fce7,c2946111,e940ab3c,8199b7e5,40bface2,5d8e3b0d,d1a15176,3b40f328,a4539bd0,a0b71e5d,91a881c8,87b31e11,453d9f5,82066f44,ead8d5a5) -,S(e019b0e7,6b4221c0,e45d387c,6ee41bdd,ed5e219e,a7069b73,d92b6339,2657c39e,792691b8,4c8748a,cf10475a,955aaf5a,77328c6,f03c2e9,bd1b20be,f363f368) -,S(51e07e1f,e8dc56df,f6394d1d,7f2887a6,9e7959bc,ca10af77,cd54064e,6268929d,c09b86d6,6837e473,574bdf95,f0b99851,b97a821f,6dc622d0,d9c6cfbf,18db5ceb) -,S(c5c19c69,9a9b6908,4625d3b9,5c6598cc,d1bba7a0,6d4e2f91,88f1b77b,4aab720c,af066357,107d856a,51c699a0,259774b3,352f8c12,988201c3,c71bfe3,c5d8280c) -,S(7b51ad32,ec4a6df5,f9c952e1,fcabd8dc,7661ec53,2631331e,5205d231,533f8d77,e1346672,ebbb97d8,569a12ae,fea65246,e1902f0a,9cd91894,a4b8aaad,5a02ad35) -,S(be3059dc,3789e16f,5ca8f6e2,c469f834,bcd3fa73,5d84377f,907cadf9,e7eb895a,5a6fa277,ee5d317e,81819fb1,11f40778,ab437567,48eed726,238ab5c7,f4d6ef06) -,S(cf75a66e,810f3284,52e09fa3,15451289,e1cba33a,ff1013e,4702ff1b,92b6f587,a0658bc5,8c894702,ec5c366c,5a6b18fd,86269d5a,8117dee3,601dc40f,cc93f17b) -,S(6356c70,7d5228e5,253f09b7,7020681a,fa64dfd6,3cabd703,91d7f892,d9822737,3241ba88,cef88e8f,98d19fda,717904fc,737a9c77,45838ba3,97141964,946ac7b5) -,S(90d7f09f,7b8a1232,236b4459,b031b0ff,d5e8c903,36a35f04,94a89615,3baf8554,4a612ce4,b18b7ae0,f3c557e,c4ab51bd,7c32f26b,24d0ca7e,accc748b,3a2db676) -,S(170265f9,5a3f936f,57a39e1f,a748a3cc,902b1b20,4306c49e,f4485b15,555f80af,d2f813a4,b329da9c,68104a55,301eb7cd,3ff6dfe1,c4aab9d9,d2fb03c9,e7ae2bee) -,S(2d6316de,37598fe8,ed6e3e52,ac47d442,636a6553,64274692,5a468f08,54377eea,e064f40,7f0d3b32,74a61d82,d7b75006,6fab6447,e66f2d4b,20439303,cdb3a107) -,S(8c89678e,73f3085a,1a766e14,f566625a,cc29dda6,3eb7bc9,ed1195b8,5fa2092b,12b42d8e,91c9640,b8b2509a,157229bc,a66d28b8,157742fb,a12d7405,eec110f5) -,S(ddeb928,de6424c,f9ea76f0,abc208f1,16731596,29fdb2c5,c8e6ed28,38ab6b11,b1395663,9ac1f06d,74aef36b,61916872,7709eaff,d8b76905,ca404459,325839b6) -,S(485e8e44,35c46bd1,d0c2a4db,19b958fd,4a87511a,ad4aae65,eec4f5ba,6cbb38ee,e621d1d8,736d6df5,df2db5d2,36887c27,a93733b8,d3232dc0,95d0b2b6,d0be516a) -,S(bc527a44,2547aca1,91fd98fb,84ce7b3b,6210378c,46f7bd46,bfd375a8,1b61206f,ff7c1cfb,d3c21616,85d6f405,e6f19e8b,6785e6be,ce374189,4efc149b,b3031707) -,S(9911194a,7a75269d,2fda7214,21e4e2e,3666ad12,3e76004,b5ff9afe,9ea89ca8,b1f350ab,c87d942f,1aea75fe,6c144ea2,fc5cc040,5c38af56,9ee45413,17c7bd4) -,S(93226535,e27a96af,7953597,4db1d4d5,4a65d3e9,331fc3df,7f028fa3,288c3189,98007e66,60fc6673,5e8e864,afc62171,49168a86,27d35eea,2d02d90f,e6f15331) -,S(752d352b,2459fb97,d5a0c46c,3fef99ed,50ebfe74,ceb1c881,b2fa518f,3aa59e72,c6e99a8a,2544731e,d932a164,ca0def49,dbfe4f29,f8894133,ff5eed02,66c4fbcc) -,S(ab37b416,dd06a595,ae6fe33d,717c4ff1,fd1de2ad,6c58e2b3,660e872e,aac7aeb5,182f07fd,61ba43fd,e11ad355,d7027fef,714c9b9c,364c0b72,1838ef7c,f85d9470) -,S(d2fa3ff2,b1cd8909,52a0d380,d43233f4,1eef04da,aeac6ceb,46dd8e6e,572d170a,85f3c854,3eea0e64,b8a9eabf,18057700,6c3a6f70,a790cce6,24a3f6f9,5752c520) -,S(e256c5b7,99ae8dd7,1daf5a7f,3dd94f94,e040d98,291a2d6e,9b398889,addff0c,b4375e5c,82517974,b515ae28,54c83443,e8bf9391,cb975013,727e3bc5,1473b133) -,S(30056648,afaac00,c1d77bd7,e7b5235a,fea2bc8c,58b34a6b,83e630d2,3036db6c,16ca5c30,6882fd6e,f7d82f93,b25ad01c,eb3e9e69,b8280f0e,e3aef2e2,ec204600) -,S(8602fe69,d4b1f32b,e8422928,200c5b5,816f08a1,759faafb,29861e07,c5dccef7,59a5ca0,35490ebe,66409e2a,283f4c9d,f6e0a7c7,9dd1ec82,f31f7e4e,4f23ead0) -,S(53bb9f5,ed205516,36ab170,7afc75b5,6ab3a75a,3d360c15,3b0b74c2,d7d9d64c,77c6c1ec,c7a53dc3,8c6540d4,461757c8,b5f7b66,654fd754,fbfa8f5a,a5318cbf) -,S(badc41b2,86982d76,e5374b3,dcf023e,dbc1e187,70cd0b2e,2916d436,108a4328,b1694651,a69dfad,924fdf5d,526c25cd,e732078f,31128556,3d42ebb1,3329e2fb) -,S(15b43026,f5134b3f,1ad441c9,793b9e57,a318d455,fd6f10df,e4b0bb91,5d36600,43568550,60fb010a,6d5123e8,b446a1e7,cfddb6b4,6e4fb18f,245a4be8,f9975a1a) -,S(fcc64bd,c9df17,4d4e8e18,cad6116,a48780e2,a180f7c7,57f532da,9fdf37e7,ede37062,35eca482,b935410b,6d495f53,12b133cc,238eeb6d,e8e5f593,65601951) -,S(f394fa79,254fbdc2,7a1b31df,1f868c48,9b48b6d5,1afab542,2da5b1f5,6f3edd2,f56d3d7d,e7f8d9c5,fd45d6e2,cc2af300,fdce3293,9be5b975,9d81cead,e2000e7d) -,S(3c7c8c54,6b853a5f,97f92932,5558793a,e1debf3,3f680d5,6a79bdef,d4608d91,575771ed,f26feb38,a728354a,6c4023ce,4b019d65,3f7adfee,3c83cf58,9f2fe4a) -,S(51d61258,43b8d621,6c0880d,f04f34d,9acbb422,d8194a98,dcbf222d,cf27fc4e,2d0bbd0e,ae299afb,93980894,bfbdbdf8,6edf9509,ea408286,ef602cf0,ce3b33a2) -,S(14b17f35,ac7b5914,e08babb5,5aa37cb4,26d3bd34,f2c1e4f,45acb493,8ef51a65,a9090e25,cd8273c3,15d1ac6a,15eab027,7981f6bd,a85fb082,2b24cc88,2918fbc1) -,S(59ceb93d,d78ff6a5,f45c5fcc,7c1ecd72,43f2d8af,e4ba8a3f,fb03053a,586387dc,28f4d0e6,38ac1fc1,98aa3548,56f4f19b,479ff825,5d150f29,871630ae,f82f3777) -,S(273bc0a7,eb63a0df,eea8d7ac,b24a5200,a7086078,388db5bb,37a0a6f6,acf24656,a971405,a287160e,22909b67,357fb63d,10af5ece,f725b1ac,17c7fc73,759936f3) -,S(c9b5b690,3a45e529,3a298219,cca93e0,52a2719c,25cf2f50,c4ff7f04,5f346475,7db09fca,ff1aeae2,dad001ff,1fca6166,a607eaff,bdfc327b,9b63e2a8,e97f665d) -,S(90044bea,c8459e34,edf7c40d,2a101b45,66728d1,cf0055ee,c8ea07ab,e39307f0,19763d08,77d4a896,ca9ecbc0,56d405b,5a6ebcce,1ff6ac26,593be19f,63caf6cf) -,S(6e0898bf,bf6baaef,d085f41,da7e6b93,6b6c9a88,3728dc7,8ce7d71b,fd597b2e,4769146,91587abc,c2f21e05,4542280a,f7260a72,e822edca,1e63c089,3bea3dd9) -,S(e94563b6,e0156145,ca2ef19f,58de9727,7b806969,a249629a,4f024b99,8a023792,c8949547,a4d25901,f3980cf5,333f65f5,8e1797d8,b42ccb0b,dc550e6d,5909927f) -,S(3cd027e4,173c2799,54d06c3c,ec05c0d,161a3b73,348db0d2,8c03d097,8921ad64,f0d1a3e8,ebc3387a,ee88189e,c1fb3f6d,5e73e895,7b7372d9,32b00144,248271ba) -,S(4c96f51,2b4f0758,38335d47,db599db9,a2dfe1d1,6783960c,dedda119,693d5686,4e840262,66897288,9bd54c15,219ae871,e6426b67,afa949c5,e1226bbe,1204dfe1) -,S(8b03ca2e,458873,963ba6b,c9dcd14b,59fb1190,3f2330cb,22997bb4,19002fbd,2b29df15,c6be49d8,27981ffe,aae26930,7a461f84,8285f561,4f910508,eb865781) -,S(f4217bd2,32229dbf,39066a17,c2524838,38098362,f0891b69,275dede1,f8e64f0d,7581350a,957f480c,89246800,86c2803e,99ff5037,938e3e19,22e3f9a6,7098dd96) -,S(247274b3,d5095d63,132673ca,dbf0e418,898468d3,9a30c538,a46a2719,42846bf8,4265a1b7,7d1dbc68,956f2441,9c4d2b70,9e71f6e4,6e24e336,a978285c,22a84f11) -,S(19c25b9b,97f40ddb,23d62bd4,a298ce7d,befdf39d,327aca47,61815c0a,28d4af9a,a9b5d705,94cf4c7e,b7e947e2,101b18bd,fb9f2f20,fc3bf89d,f5a63d7f,61d3b3ce) -,S(fb69718c,baf0c5f8,e20ca98c,2fdb18f5,59df27e5,c2a064fd,ffb2785a,73bf27d6,b612c590,4e0b1c54,7beb4e07,82ad2716,84eb895a,862b59b5,cf6476b8,af52107) -,S(9fe6e793,ed1aed77,d8381352,84890e3c,f817ca60,37ee80df,6646a3ce,9c316a6b,17214a01,99370a88,41717ae5,41d35a4,96f8f041,e9b3fe88,4188f6f4,e30b0657) -,S(c7f7ab4a,394f17c8,47010e9d,f1764fae,6159b140,578f70c9,fe50703b,aaba62cc,9673f262,c875953b,90558dec,8ddd04a2,6d7d3ac1,672e3d10,c1a3c656,b0318c19) -,S(cc2e30bc,2d63d4d2,bd0f5bca,8faac99e,a6add123,82d014c1,d7bf8285,7ede2297,cb87a21c,f1efe789,fe72ca0a,b6acc5be,63e6973,2ca899e6,fb9e05e7,72d4d8ff) -,S(6fe7070d,a78205ea,1f12661b,4538d0fb,60b4bb4,9c1709c9,e53de22e,c3c25d6b,2f6b773d,492a82f7,f9609cbe,e1af3c9b,2940a12f,1e615c1a,801c02b2,19e6b8cb) -,S(1affe9da,ab5da7f7,9b331e9f,91eb7e3a,f4dad51,2317ca45,3ae13528,66013d8f,2706d2aa,d3139097,73a0febc,191c7a0a,df2ef168,c65e759d,7c034bac,49c8a92b) -,S(13566dd2,d0cdb199,20a1f9c,aa1ab581,c3ddf2ad,125c13cf,efe199d5,bc338231,b403ab04,67df46b,2efa5b8a,4cfa8bd,97399c87,12ffc55e,cae8de52,d4f6f28c) -,S(135fae69,9a969720,b1c0d899,790afa99,83074584,da3ee8dc,1e011336,dbc3636e,b4260b88,2dc79423,8cd0fbe6,5242147b,c96690da,c391e3cf,d2c53ecd,2ae9fc60) -,S(1b05d97,744364a0,5432de4a,7d840834,3ffe211f,a543bccf,71a4b210,3bb0489,d61c9d21,671b2481,a4ca0c36,7d4ea919,ae1b331f,a8aedb87,cc6b6c98,85616a9a) -,S(2877f026,83a5cb48,7014da9d,419c8b9c,920f0940,718e2d06,d7252de5,5b46a84d,849f9fb2,88d3fdee,de734aaa,3592ef01,483e02d3,62a5e0ca,2ead6c0b,42628038) -,S(8a7024ce,6348d2fd,84be71ab,b363bdb8,86ec6a2d,29d9cd83,1934270a,27370b78,8f520972,9e4e1325,363a68f4,ad53737b,688c63dd,1cec6cfc,bf9da51a,98b29c0) -,S(5ac77dfb,2309c061,8f68b320,bb6eb76e,4b0f0792,b8235fc1,ed768c57,44fabb1d,fab11baa,beafeab4,43a14a82,f8d70228,57752732,7b016b56,32b924c9,ccbb1db6) -,S(aee4edc,93413d53,45e0df68,99fc2193,be318a8b,f279f0e0,56c0ac42,a60759d2,b6a87499,1dc68ba8,503beb0b,8a6c09df,cb9efb6b,a44aed6a,3cd7befb,506119b9) -,S(b51d3e77,741d0d44,3a67b5d5,67b45aac,2008c25b,5196c71d,c9f910e7,b76dd2d1,431c7ea3,cf4f577f,950d22e2,74b7cfdf,2c2934af,ad0215f9,459a802d,ddee4c21) -,S(803a2ff,c59c2a94,65d8935d,93d47653,86e5beb9,c8e702a,12d7b565,98a09841,d5e02ccc,5d8ccf6e,29a7fb76,5a257dc9,c902c900,a4fe16d1,53e9187e,290efbeb) -,S(22c17725,44eef514,5636a398,23e874df,8c58bc6b,6935598a,440ae9aa,5b738075,a67f431c,688d4426,c519be32,9b1dd50e,2c64648,4d3612f,35d52089,c98dbcfd) -,S(ed67feaa,5aab50a9,ff71c434,855bafb0,5191f036,c691c8c5,563395,d2053b86,b2d13cb6,4ea821df,f8829ee1,57cb5fca,81dcce75,d091719c,73cc7785,c443f0a8) -,S(f8cc5ae2,3b670b9,3c27ab8c,7d8055c8,4654b427,f9e6b733,b083fecc,c7c5d375,7dc996,7bc3a2f2,f516aab3,682f8d6a,32b84173,ecc742d5,c8a15c5c,72eb261b) -,S(838891a1,fa46e300,a20fa3d0,cba3fe09,3326ffd7,bcdd7c73,b6e96da,5d591332,d46717e2,c5fa3d52,a268aa9e,a85922e4,547ea986,3a37b1ae,b77d75b0,d48a8fea) -,S(92caeb7f,400d043,6d36656c,8ffd5d45,6097cb51,cf512c00,1fe613e,8dcd5544,2096bc03,dfd088ca,25cb9aef,29b24b99,2b2aa00b,e3429cad,c0976a3f,162e47e2) -,S(2e6226d,574b687c,20dcd4a9,683697f8,afce56a3,1e11cdef,6f0ba6f0,dceb89b4,d9c4d7a7,a7aa5f8b,f30f0930,d6c3bbdd,b1963b1d,8cf24796,141bddb1,ba8ffcf7) -,S(33aab3f4,17d936de,b8c1f07a,9fd5024f,802fa5b3,a593a6b0,9fd42871,75f4ee7d,4c13dc95,7311dfaf,932eb4cc,68c82550,3b185530,13008dc6,878dd092,50edca9c) -,S(ed74a882,a947da53,fd62a242,b67dcd04,50896a43,e9882c84,ada77f47,691e5fc4,454a18f,a8fc6d8d,e673410b,213875ee,35190221,9f7cf88e,f363be08,571030d8) -,S(b5d3f084,56db930a,7d8b4728,2caaf807,be7bca65,bddf9738,67a56224,39723ebd,a89e0271,28d5872a,f4d6b4d7,c5a7efa3,b0339a32,89a12918,2077c106,b61e1a4a) -,S(5e40e90c,1a01e008,d5fde186,283919ef,eb859921,c3ec07ca,e34eedc2,b0f07967,e4be6ef4,26eb3c94,70ee3084,f431c68d,82b2df48,5286082,82cc1b2,afe77900) -,S(2f4b14a2,674a743a,4aefd302,7fb214f1,a7678336,3c9e7c8f,8ebee72d,c5f29830,11b13461,b6578710,677bc733,3d28e773,c78dec4b,27ca1aac,a17121b0,de9868e6) -,S(71909162,35890bbe,6a8f7a99,5b1cc3c,a68b3ff9,7551d09,59a97835,5b7167c7,f9aa3992,124fa99f,167f1351,865a1456,8ed9eb92,c7cb2050,5082d228,4b1532de) -,S(8df50d7d,d3cf99c7,b0269ae5,e70546dd,bed3f05e,260bd834,575d56e,e65f7f0,835405bf,3c84c4ba,5e253fef,f306bd1c,c1240ef,8c03da98,d7c092db,3a2606ca) -,S(5e0f6a7c,e9bc1e0b,852841ad,52045b02,b4fd545b,f2106c82,17a76bcb,441173ee,ad70f065,4d75c88f,e6654d56,fe65c57b,857d91e8,ad6abff,148f3577,7afa2aa7) -,S(27880a25,21a78fca,cddd0b78,5a3da1f4,2e832641,8f804a2a,42fe3c0e,f69b43b7,ac9f930,12402aad,c55c12bd,e450700,b0208d85,a6784586,d04f1c93,6df8624a) -,S(6578c4a0,dc25e068,97482b12,3f38cef3,39cfd6b2,ec06c89f,6da11449,de5e43a5,8a249d9a,41e6c1a5,a776ddfd,ea93ba78,15f2e908,b8b854c2,3a7e3ff2,cb99bf70) -,S(c66e890a,71beeba3,301bbbef,2bcf4cdd,def8e634,dcf476f4,6907a280,df3dd33e,f3510cb8,9c46f493,c4a70976,34a9c502,11532929,ddc883ab,d43bd360,1b028dff) -,S(393f0dcd,24b47380,81197794,58bf5e48,b2f5479c,8efd8925,a1f78bef,6bd16665,9898d880,e24f840f,f1b4662d,3d444c29,6527cfe8,2b6f1b4f,f0e5928c,bf09de74) -,S(337fc469,43942ce4,f1601877,874366fc,a8726f4a,65a9bb26,c6c2c013,856a3adb,95df242b,2d4446de,b2b792a4,d36ceb2c,add17365,380d78c6,3b23b101,1b3be914) -,S(b7edfbe5,118cfeb1,4c1aa23b,48154dbf,5e9d1057,a2758516,7fb8e030,a457874,bc1e5723,dabdfd76,c98f408d,1d8c13e5,7dee979e,83b3d610,981b9718,f1e61eee) -,S(4dffac46,6a507b9c,2e2ee5b6,ca81d8e4,d4e8aae6,3d73395b,dd29b024,51436e5b,af227fa8,ad0bfc48,eb469596,b9b2759b,f41eb169,1fb8f896,1451489,ebe0d5d7) -,S(553ab99,3448879,b42c72e2,97d597a6,24416a45,f5b35720,c93a303b,c6dd0e88,5ba2d3fb,222a03dd,c5302b25,ffce74cd,58de90a1,c3e41928,19717c28,52ad1b39) -,S(b351ad4e,4c7df853,8f6f71d4,e95554ca,3a07932e,7a812309,b0b0c807,f98cea2a,5ba5141d,b3d4ff44,7efe06c9,c624d447,1aa3c3f3,47af74af,49929de8,d8558c70) -,S(844b9bc0,ae73df50,e5b80fe2,fb24a35c,dbc91c61,2753c2e8,e3765e1e,47d44263,80eeb80c,414c3a08,a42d89b8,87883d48,84b38bd1,40f7bbee,e977ff5b,c4c57b90) -,S(f64b4ef6,8fc11491,38ed4ef8,ab2d6336,3d494b37,b56649d1,5d15777a,8cd315b9,c6f83010,5dcfc707,f435cfa0,b6bc32f3,8ce8afb6,28bf9139,dfc47279,cafa56a5) -,S(969ceb7a,441f8be1,f16c94bd,6065db17,942f88dd,e5506742,7cd30dee,cf9ba5c7,a08ae62c,6e6758f9,724baa45,d35f3e03,9f636265,d841b61a,f1b31d20,bc8d65f8) -,S(e465041b,78c33311,d4397b30,9a8ba4de,6b312d10,ec2ca906,583162ca,1c599102,3f21d5d4,416f1954,7af1ba97,6687dea3,520ac304,43c180ad,3892d46b,86618f55) -,S(87b2e548,b019224f,b1021a06,522073dd,46892847,308fffe9,910ffc28,5b702bd0,6e641d35,9e7ff12b,20123b72,f0e5ef16,338c3418,38c2f4ea,6dab94c,7c3f6940) -,S(f832d7b3,590a59d7,ec2c8a63,7ca0347a,893fe461,4eaba097,8707c353,8296ee14,3fb3e845,4624fe35,326062b4,a6f30c85,f0e7101b,a3532455,7687812e,412233e) -,S(52aff21f,fe1819f3,7f8b5974,ab004393,6e99d8cd,8342b7bb,ad46d333,5e4d6651,66d79c3c,c7d08828,d8646e4a,6a44853b,4a49df0e,85c95e85,d9c995c2,d09b427c) -,S(aae62778,8069bcdb,fc91bdb,946cedab,63896817,575a471b,315a47cc,d567c678,f254c548,832d95f8,4f20215e,ca4805fe,356e806d,9b3b7338,7dd36e85,214b70bf) -,S(fc15d494,b6580e0d,e1c769c3,95c5d047,202e8d07,ba94bd1a,f96064b8,d1a4bfbc,f9327fc8,75319184,c1876748,bdbbdd3c,bfee8baa,bf46844b,af465d4e,ec6be335) -,S(aacec857,fa4bc62c,82790a4a,496206f2,d79a31dd,e17d2db2,d99619d8,c3d880d9,6dd1e4a2,adc502ac,150293d9,42a1cbea,a576da49,f1de7d15,de70bd67,d95c5fb0) -,S(c7ba3155,bf34fb9a,2441832a,27396e1,99836557,9c9cb856,44c3ace2,9ade66bc,afccc814,243a1fa1,345fa46f,ee4b4190,96082bf0,7866fa8a,2a887d84,d24192f4) -,S(cf7a0525,3bee95d7,711d8f7b,7b301f5d,8036a487,a55e3860,900b25b1,c4599115,e8a4a9be,7b9cf99a,5dcb4db9,8249350b,7a71a12f,a9582620,eda5a35,1a8a0484) -,S(a4336248,6b999ad1,623c4c32,c79ebb3,4e8d6f3b,484f808b,9a088ffb,2885a11c,edf8eef9,74d3e5ae,2a991a28,6323597f,5a161f9,2eeb9256,207be548,f9b38d16) -,S(d3cdbd98,8cefc8ac,3a442587,51364a10,649243a8,d4a63927,f4fa3b10,b1a7dcc8,f10e26c8,11f4a219,da4f948c,51e8b81b,d8bb357a,182031cf,40ffb464,d5f7d7c4) -,S(fa038534,28dd093,26977fc,da344269,fe3c61fe,35567eef,909a2309,8e5ceaef,f31c5d30,9e234b3b,44fbb52b,8c973aa2,bd85afac,1f9f0798,788721a9,380d8606) -,S(718c2bc,26dba98f,24f34af5,18e18870,5510c0a7,4e228cd6,9d4e39d8,a00a577f,c41d0d81,8f093246,5675a326,d0615b0,294b8455,909af0c6,e557195e,11225152) -,S(378ade51,463d949,1ed22ab1,834cd7bd,6b99a123,52c65e18,70d5005b,e97e602f,76469796,d7758ba4,b3bed1eb,9f8389a2,2a421f5a,20f8df71,72821a8a,508e4c1) -,S(40bd7df9,1255680b,b50d3d08,fead6815,5f807759,87e9cf80,15e6359c,9f138b8b,ec0417d4,2eb1ab50,a469a853,edc65ca5,2fe00ee7,53b30b9c,56536e3b,36144e8a) -,S(f01b30bb,985dfb53,7bb4cd62,18cb0b00,b5a77215,4d84a802,8a4969,260d963f,3cf483df,d6b58eb8,46e8ba1b,f06c2e9,6784255a,2afbf68,613f39f1,44b82417) -,S(2392d86a,1bf9a636,38eaa5dd,76a7c6c9,eabd50bc,9f2ba568,183c0995,f7195900,806cd3da,ac23f93c,3b11cb5d,a3bc4482,ea49ed2b,444c6e64,dc557e46,3ac5c033) -,S(b0e7747e,c9496fb,aa7798db,e616fa42,5b0b7acb,7409265d,c989b8e9,20087133,32fa615e,d0286b64,b83cbfb1,e8c4b133,85527655,48071401,89f42d93,330491e1) -,S(8d1342f4,2f6dc3cb,9bb741c1,9daa08e2,25fb6352,ffe860e1,76a26fda,a0601624,82d35ed7,57cb6f31,81af31fc,36f53817,191fb9b,c9338a97,3757d0bf,50d79d77) -,S(ad09dcc1,d3ebbbd6,ecd7be45,d7eec5d,ef743851,2ce076e3,cfc4f8b9,449a2ccb,26bde63a,e1f7fbd8,46260a64,372d015a,fd3d5ae6,125dd801,523a94fc,8421d04f) -,S(128f5199,68435c1,a27591a3,2edff533,d12a725c,f0c7e121,260cbb74,925cc292,dd8945f7,42f1d013,92152dbd,1e4dd8e,53277da8,bab68acd,8c7c8d73,f5d7e190) -,S(118c1167,196e8eac,e519d83d,17ae1e30,36ff1fa0,cbd1cc58,41cc3763,d1d8a931,eea348d,54f47b73,d5d8c2b4,7eb7604b,53beb345,c82ceca3,4f8639e1,45b2e3b2) -,S(81ee4bba,6a84edb1,83e1f2b7,5103e453,2ba9613a,b612e0f1,27009ee7,7be3bfb,e58208,d152059b,73b42039,e0a7a489,df067fab,1d1c2c04,9eed00cf,893f4847) -,S(494a821f,6f4b2d75,7e5be34c,fb9949ba,b9271599,3e060005,dd807c83,adf04f2f,8ab15e9f,c37d368,3586a1ed,ef9ddc59,8dae7206,499cf53c,31a8cc4b,d7ba15e0) -,S(3749271a,da87c292,724a3ad7,2861a7df,9757e31,3c3156a1,72cd3735,608c865a,aeffa1c1,aaab4f09,3998b4ef,e046aaf0,f404d590,d6cd762f,1aea5745,1f8aa3f5) -,S(103c8721,321ddfbb,cc3ef6af,1ea8fab1,3de6aca0,294dbc79,3a1e4216,563dc1f5,fe9cca2d,b459596c,462fb268,a8115880,16c2894e,e8839caa,362e4813,e8e827cf) -,S(ddbfc655,6aff403b,10a643fb,f62a60ed,656baa39,b10febe6,92140bf6,7b78f2f9,1cd4169e,cc8ac589,de57b5a6,e02e03df,f3cc7bb3,45993d5c,4ea57e6,852a8417) -,S(d025f583,3e51a9c6,a1c785c5,1c579528,5af0c297,c0fdb82a,f555fd59,88dbb28,5170614c,110f31ce,d88424fc,7d569f4e,e93d5017,a8c676af,c7261ed3,340d22ef) -,S(3f349cbd,8ebac9e,c570b0ca,29fe8ce8,dbd98eba,103f131d,daaf193,4fe78516,ec9641f3,175ed56b,d0c8f26d,188f9fa4,b38d069f,cef8f4cf,71acf66f,1ef7dbc9) -,S(7624599c,61e71532,a177e838,ba92d789,5160e43f,ad798fe2,9170e6d9,bbcc11ce,409e8cbf,6aea70b8,21533902,150148a0,7e45dd61,c9c8d24a,b8cc3da3,f03c49a3) -,S(8a1e1b47,3c699dea,aa418ba2,85cf7467,51af1cb0,8bf78228,932dc6ed,845403f4,1bd300a2,7a9a8da,6ed2bce3,73b9d39e,661d02bd,b4605740,20934bc6,abf3c483) -,S(eeb91c38,d9b834bb,5e3945b0,9655b988,96efff11,1e3dde8c,add6ef2c,7ea51b09,899d841,24f83b43,e2ea82ad,3a6411dc,cf36fa86,17bdab35,d83829d1,456c56be) -,S(46360f69,8c023375,6f050969,60b3defc,2a1897dd,44e0e159,d185ac04,3315ef47,ec02a6d3,828246f0,684d2059,23ba73ee,10cc88c9,575fc005,6271fb8c,67e0a4a0) -,S(16e5cccc,b410c20,e8de1e76,e5b71649,64cabc26,f629f8be,36eff4da,66f875ad,a80de48e,e079d9c,bac312e0,70f10d6f,fb875c90,7dd3ff57,c9bf8b90,57c0fe14) -,S(c315230,c8ee5bd8,429efc06,bd089f49,5f4c5a1e,2fb188bd,81e41bfb,85acc82f,71430e8e,cee9c6f5,eb91eb14,20e07b5d,736217e5,4bc25cac,9767a749,a477599b) -,S(7731eb8c,1684092a,d9d2ec69,b50339d1,19436082,c9116366,8ce2bda7,ee80c0c9,e6636efc,22a4c339,f8100dea,a227a709,42d18222,8cc58d13,ae4d613c,a879de8d) -,S(2c1c200,4a5f04c0,b83d143f,ede81755,67d4d54e,b2dc4ffb,de00b83d,9802f68b,b3e2e434,30d409cd,26490c1c,818b24ed,b10e835b,d6292422,45c529f7,6e299159) -,S(2d984bc6,a2031a3e,1a57d0ae,d13d798d,fab45382,d29e4a7e,8e029fdf,2a9d95c2,b169c34f,9932f02,8320ed87,4a74da8b,5cba81bd,f20a9454,feb315fe,a0926720) -,S(f61abdda,f7673f75,74e966f1,c77096c7,7f6e8659,746e45e7,2c9fbf3d,5e0db5f6,1717dd6f,86edd17a,b242212c,91878ef8,9ff1b865,b32b4e24,cfdab7de,de90937f) -,S(a68f5871,bfbce14a,1097eced,68a9e906,c94599cf,b6dd4176,ef946fa7,e5552c3b,cbc07a08,86faa82e,d231eb0,739a24e3,62a717ed,30b0512b,96ac8dd9,56ab05f2) -,S(52035076,1af3e786,60906105,36a2ced0,6f8209d,a0eb2757,cba705a3,467ccbe2,7a01b944,5f63cf43,cba95191,262b1b53,ae0af9b,4b172b78,3970f84f,f8ace09c) -,S(bc8f1537,9d4b9862,a437065b,10f6c28c,8c3323f4,51f2847c,63251000,c9f144d6,894826ed,61d85e90,58c00e74,cc731dd5,d62684b1,ca996c07,ab176df0,e4b951f7) -,S(536b0cb5,81dbf6,ab3b364,64a397d7,2a513bd8,a7bb8237,70a725d2,2eb12a98,85bc95fe,6e160f2f,9a31b7e2,74c09023,90cb2f4a,22f15ac3,3d0ee72a,b666f5bb) -,S(267840ea,e2f49fe8,9889bac7,40eb797e,ee42f922,c1821a66,163a580a,a0df90d0,2c7fe7f3,4e06f09d,a1a2b1ba,79906a0b,18c3d51b,d9b6011f,688c69e9,1504a00) -,S(d8fd79cf,6beed8c,fa57bedc,ca06e367,e0667e9d,a057222b,81fba682,979808ec,39cab613,9cef186a,248562d4,fa581384,d6c81de5,a0f7fc49,140d0822,f6126034) -,S(601407de,9ecff4d0,836228ae,eeaa612f,2b659706,576e2eca,74bc32a1,d3d14b7b,6cfde694,2f0e4495,1e25ff02,2f2501e6,7101828f,8088c7bc,a8ef2b25,88036ec3) -,S(f518c5c,bc0e8541,48c40253,d500a2d,1ea1d25f,d31dc777,d6365050,d3b26804,8dcc6378,2b1ce6fb,9f15c8fb,70c5fd0e,53e4d80a,cf38261f,49a558e1,de637b6b) -,S(16a9bcff,334e35e2,80258378,b2e25d9a,56ce58c3,b3426bd,da82978f,370ee6f6,c7b6656e,baa3864e,bfbc5294,fe9836a9,9fdc095d,ceac6a32,642e6911,a6f3e933) -,S(9d940fce,5ecdc659,30c945db,7151b823,a9259d0a,2a3991c9,f71e8b00,bbe35d4f,32f533d,d96f2e36,2109a96,48ef55b2,e5887387,80de97ad,c7974227,b23fe647) -,S(19e973f7,69c2d02a,8bed34dd,b7591828,5036e724,22227a81,850f3d31,3128f586,f2f5fab4,fe79c177,752ee60b,cd85e625,e459b50e,de702010,a6fbcbd1,5b31aa6f) -,S(ff07bc26,473271d6,4371a4d2,9b59f858,b1b01e40,472bb4e0,1769ed2b,66bf2097,3eba7660,492ae09a,abd7bb8,c5d80e33,44539ab7,276edfd5,b599b02f,27c60b8a) -,S(175f786c,93d89acb,8959d846,934c21df,5dc4f6ce,a9c1e150,e7da469f,d27e6605,343366e5,7f5b9f7a,407cd566,7ef1f0f2,464a2938,61fd5f2c,b0363a5b,dc9c2f9a) -,S(a9027f8e,b662a7e0,d70aa1ac,d3e0b9ba,d4e0bd8e,8bf8c883,40b0a7f5,cbafa761,2f9dfc2c,57bfd835,271d63ac,e3cecdfe,f6e19e0a,fc19ac0f,71ef9ec2,7fac30e3) -,S(677daf40,728a6c89,6804ed3,1df283e,19b41c2d,36a3a98f,d4b93fa6,6699983,1affbe57,3a561872,37dafd1b,bdcaa594,e499b298,6af58591,c6a2ea3a,2016c039) -,S(1105aff4,d4761b77,68db74ca,d9fc7aa0,14c5417e,de1fe641,ed1dcdb1,9b5a3690,bfabb1aa,76906ada,4a1ea463,f4caff44,a41afa71,b82e2457,d2756ddd,14946ff0) -,S(3221d033,16be670b,e05ecc94,8b537ca7,9318eb65,f93ab3e7,32e7f36c,bd06249e,92f7b5c9,85ba3fd8,7b14a093,74d4ef94,130d3642,517369e8,f9de5fa1,c8ccb803) -,S(ac10037c,ad83fcbe,6aa7acf2,3043ed,831dcdb5,66921f16,246488de,6e012fc8,d530eaa8,ebe1d47c,8e57892d,9301c4a4,29b223b2,7344e433,f2bf77c4,d9a20205) -,S(b3ea670b,f5001657,913d5d49,ee1005ea,65fdd33c,4ad81987,efa0331d,b29a3e53,6d758db6,df4275e3,fc148e91,6536505f,6393daef,c54c3b0,b708e0d0,8de3f1bc) -,S(42762d8,bf60f678,924b7cf5,4e8c513b,fa1223cf,98e124d9,18d88cd9,a54c8d88,96be42a1,f0dadc84,64a3522d,e13f10ad,3272505,f7d4fc54,e6dc1a33,ef6b2eed) -,S(7b9e0117,167c51ed,c3f7d2b9,edb61bde,aa90efd,88349510,c4b1cf1a,43a9ae6e,c43e0d1d,8a673cb,1f0d9d1a,e3a4c985,bd47a068,2528ac36,67976881,1ead7a4) -,S(1e807fdf,c69acac4,ba5be7fc,9c617005,d34ff896,dae25e6c,428abb96,3255239e,7db7d6e8,8bf3b869,fe4f7c11,65d85faf,55bd677f,5670ebdd,89d2f8b9,f56d972c) -,S(9aadd434,75384190,a6289f2,32cc6491,fb7a1d86,b04ae9ea,94dfd2c8,449c3961,fc491907,3ffe94d1,3b945382,eb9c482e,9da5a764,d9aa1d1c,c3d973aa,5edcd3f3) -,S(5012b7eb,481fd85,db13c3fe,2bdd06a,720eb4c9,805193d2,b99b4bf7,39802f26,db8555d7,e2cc1858,21920564,3c288352,22086161,1a611dcb,d1e98518,7c46cd4e) -,S(78f9e5ba,91071270,5160654e,2393cd73,85e4681f,8efb4a45,cdce5ef3,d73cc7b1,24c4512f,911101c9,d3a4fe24,b7468585,36cb8137,e13578e,95cc016b,96d86e20) -,S(91a7d927,4de2c0fe,84a10579,891ea8cd,f87fcf5b,a0939411,4612efd4,6bb9f826,d5a5e511,b85436b,89e46211,ec69dfa8,d0ee87eb,7c0daa31,24d48462,10e6c40) -,S(3940b4e9,4626f86d,4592b96a,4f27f874,c37c6cbf,5940de,37dafc1f,35350b69,ecc6176c,43df3f71,cbf0160b,697afeec,1a9a0d69,5ebdb7bc,34b0efe9,2cc68b39) -,S(76e7ab54,8c63ee6a,30c736ff,11762061,283af0e5,5a7dbbd2,23fe467b,85c95d8b,f266c922,fc5e61f1,65bf521c,33235e05,113140db,6a481b0e,e4f9976d,2696fdce) -,S(ecdc2e5d,b8d5028f,f93de09,c9f5a6b3,c439b14b,3c322c53,94622a13,80f04067,e70df9f2,bf6b0a35,9029f937,5e74aa93,4014e78d,e68e29b0,9d96da05,5ff78112) -,S(ccfe93db,de087d5b,9194b286,99243dc0,91d4dd5d,7189a5e0,d5621311,9dee9a94,2b0a0a20,cfef0c73,addd2dc6,d9b4ba7e,9e44f2c,26d9f376,8ef90241,b2d907da) -,S(4e82a200,e64f5b3b,3e473e50,e437c224,e21bf875,ec8ac364,7e599ba7,84f02574,ff696d9d,2d9cc0be,217394da,85201a1d,208e4309,9b9372a8,19f6d069,88839c0a) -,S(a292e105,6f3f0a1e,e816a49f,51ef4760,91324316,2e3c734e,802550a2,c942c17f,479a2e95,7a05a686,1c08df3b,221ed2c6,5d192181,189269fe,9ef42a8,e71fd6ef) -,S(47279a82,8311aa4c,b6138c9b,ccb2fc6c,c4b9d27e,2e334389,1773fc1,ee09f461,2480a805,496e8bd3,e02b36cf,8081bc5a,254f821e,40c0ef48,291ecbb1,6699a10b) -,S(b903b4f8,2126fe06,44976643,5f0982f4,394db57f,b473401,9536740,595562fc,e8c97572,bfae91fd,61cfee63,3b24bece,e587291,f65a6aff,b71c6a3b,615e1361) -,S(16b9e3eb,eadf469d,368ab368,431afb79,214bc728,5df165e6,c3bf98a4,701b05a5,26e74ff0,64cf5de9,ec3d084f,8d75337d,c04918eb,f783c65e,b50b948,d48eb003) -,S(4927fd2b,c17b92c1,3b3ca52e,759324ca,353e8505,ba81ac24,9003091d,1cebbfa9,95a6c16d,c4c52f20,2883ab4c,a9c050c2,b2849b71,e19e0df0,8ff495cd,f62d73ac) -,S(70c503d,93e47,10262c8b,b1630409,979b673a,79ad08b0,8d855365,f51ffcaa,2ad207aa,5fe05144,95baf3f0,b0807efb,d10265f0,5de63d6b,563e4ac5,e70b89ff) -,S(cf598642,32972f7a,a6cf12ce,dc5aa95d,4bd0f96e,38ed546b,9ba9040a,e25a9e6e,67f2f83a,f5f09b52,caed83e5,1b9d6de0,58a6e9b8,96d1a6ed,d7ab4d40,30332027) -,S(617b9e5a,8d0b8c44,b186aa60,281cee51,dc224e2c,9e1c4f07,c342a180,78b271f0,b64d8d5f,bc2907bf,90b983cb,a6126586,dbb7e7f3,d95993e2,2bc1b8f8,9472d200) -,S(d52e0c90,c69cd94e,3c849ea7,dbba79d8,6aed2a3e,3ca3f106,d2baa2a3,59c50534,36c8390c,fe400769,fd2b2fe1,b6af62d0,7fbd667c,fcd9a132,b6b4f974,a7e454f7) -,S(ea474a01,36d16bc2,fae6f568,9ea3c035,aa6580e6,b238f42f,e2ab19be,81330a46,d09379ce,aa89765e,1164f438,4b0f0ef0,c1e8be86,427c7455,af98e4b5,c9ee8145) -,S(4e5dd22c,b6a4b205,97f71375,cc49ee10,ba6b82cf,b06cf065,a25d6f5d,bef51d70,d4ff2ed0,55279f96,344dc16e,10e3410,40378ff8,b8d912c3,a17cbfb0,70588cf0) -,S(774587f7,f3038136,131fa9eb,f1eb3407,9e473a8b,b9e5acb7,317ff5c9,17447878,9d3779a1,2b067b00,d2a2a3e9,46f8078b,e6279024,d94c83c6,28c0cd48,145f510e) -,S(ab807569,d1a3630c,e5447b36,c205e601,a6a23069,4d2c0786,19d9b97c,e0ba6611,2b9eef15,54f8ee6,e11af6b,6a1d045e,d47b8821,ec84c6da,366afe10,2730e9ea) -,S(91602928,ed3cea8f,4faa254c,28962b68,c4437602,3076a5c1,6bad95ff,3e328049,764faf56,2d8de3c1,89b7fef7,62012be8,112db4,a3201692,95c7e76d,fcbd3be9) -,S(6c1ecc2a,258a44b1,ca1d964b,c86c5600,49fdfd98,b362c35e,3c830647,cf1266d4,1f9d3edf,5e0e8550,e4534c33,5b07d731,19c49c4e,29397f6a,938fc1bc,ebf8fcef) -,S(e176821a,4006b429,999de3a4,ada09166,f6e5deaa,f09fa613,60bd3733,db8f7084,7d07d1a5,390325d0,27b05e18,d90e7659,f5ef4c8c,c7c6dd00,c7a5427,4ec91842) -,S(2ae0b70e,53536893,8a7faee5,da5d8dbe,e5af4873,32caf51d,7bade79f,eea50df2,e70be2e8,c8110c31,c3eb5e36,31dc5a5e,bebeb184,e6b9f081,bb7236dd,cadf903a) -,S(1c686fcb,d7a751b2,d420614b,56d37c8f,81c9a600,335fa911,835dad8a,7c663e24,4fe2eeae,7ea1b639,b893329a,a65bbfcd,b9fd8f07,28614bd8,6a5b0712,76aa576) -,S(b369d7e5,c31c9a56,f480b44b,3354be,84145c3,97dbed68,d87a4c3c,be31dc5c,50800690,17d31473,59bab021,c876d152,c17ea8e8,b5c95762,c749a2d,29adf3cb) -,S(522d3ac3,42a0ff3a,9a8eb5ba,54ed4dad,fbcdb48f,53bc6e1f,2c0c12a5,61cb1e9d,32ed883e,1e1f562a,50063d79,45075ad9,9ab55ba6,fdff0d58,9d2b4a4d,10df82fa) -,S(7d001803,7b722a7a,17d74696,fed9bbb5,f3d5f6f,d8a623b6,9c952a2e,f2be939e,81ee30e6,deb893d6,274c4b46,8533d845,38073ed8,68b101e9,515ebd84,70e368de) -,S(c76b074b,b228dc24,1dc9b704,75fcc52d,a3f3bf0a,5e954910,ca4e6f16,bd298983,4fcc807b,4c1e37cb,6a6c42da,b939a7bb,6f1d5ec2,87320d74,408622fa,ece22266) -,S(8497f267,99c7f525,83c620f6,e284a9a0,35130556,9d7caa1a,f118de41,c51b05e4,3b861f56,16ce6234,c6847273,16bfa629,7cac9d5,ff562f66,24b26146,413960d1) -,S(ddb10ff0,a217ab76,241a587a,8cd46cdf,ce6ff5ae,e39d2d85,7f47eeb7,6d2bd68e,a4110196,fd0813ea,19846dc7,12537cb6,8faf9333,19e7e49b,553e523,f07b004f) -,S(47eb53da,455cbbb9,a8330e12,e0210d80,cc565661,348fec72,529390e2,a75b812e,88e4a8f,91ada187,5734dcf,42b85e2b,a3f5fc53,1f1c1df1,300c3d5f,e811fb70) -,S(eb0a8903,42fb2710,a4c7811e,78384918,dedea7a2,9bb7da46,e49211bd,95da1426,8d69a88b,d85e2edc,d8264cb6,c44d8218,1ce8946a,818c9d4a,6f757bf8,5817ac56) -,S(d400c8ef,655d3879,579ba4c,488c3e55,af5af95c,1701bd15,482b2549,9334906d,e7bafda2,5a9f5934,6bcec6e2,a9408f18,e81b76f9,7a9d721f,496c27f6,42725e5c) -,S(bae81c3d,1772e104,66625f8b,ef08d4a4,5f07892c,72bcee05,fb7e382,2a6261fc,4ce5f14f,74f28b03,34a6cc64,452b9049,8460493f,3b64d9be,2ecf98ef,c0270377) -,S(7f575b9b,46bd0f74,555a363c,d80122c4,232e8c53,a6624d8,e13b5c06,74986961,edc0ffd5,952fd4d3,c752271b,7cdfaf3b,4cefecd8,66d722f0,3da1e97b,49aaa080) -,S(a86871d9,1292f7fa,7249ee8,e77270fe,e7bddafd,3255b4a1,16851ae,411293f3,c21ee1b0,bd897d82,566cf438,b66439dd,3dfab0ec,3c7a4038,ccb86039,3b0b0187) -,S(c320cfdf,9cbc6579,8c8b33c4,d97d690b,64ae90c9,a5070646,8c8791e9,1ee4a18a,8f1a295b,2a3c8c5c,3b5bd8ce,e3380a04,819a8658,7be87d03,73a0194c,fafac74b) -,S(169a1b4,f2eacec2,be263ced,2e0576b4,ae77b863,525b2a9f,f8fc05d2,c07a8fc4,7703f867,d997a2ca,bb697f87,b97ea986,78777183,aea81417,1dd0946,309e77c) -,S(218de686,ed51588b,1307d8b6,54f7f6fc,e673cb37,553d23b7,b8c23367,d6b7ea5f,98325ea9,150a100a,f5d2af49,2fa25b23,40ee9606,1553c3d7,edd4d870,5288b8cf) -,S(c7c2e438,d12ed0ac,6363564,8bf2899c,d1b39b1b,200ffeda,4ef9cae0,5d8381e5,93a36085,fd09ff08,b83d50a8,3b140edd,a63e2442,e4bf4d1c,7ae44963,c1646f41) -,S(12e834e5,605d6e35,8cbe550b,8fe917dc,59194c58,66b265cc,50b00e3c,38fe058,6a44ecf2,17f46865,2e0991b7,df3b3565,444e7e29,3a2d6378,61a8f3c1,5ec1517e) -,S(30f33c39,af77735c,749fd328,e228ed67,bd625fbe,79dc3b06,ab31c173,777308fe,29a00f66,1c998f1d,bd62935e,44794420,7ffd7b1c,24f63806,9206e1c6,5c3d9604) -,S(c5bd81b6,b057e687,19c47964,d55ab996,6c7ea99b,25c1c2cb,50d6fbd9,af492358,5a6b1332,8562599e,e87c475a,1e7da886,c460ec67,ad81372a,7ed39498,41225e5e) -,S(1fd0e769,9d931a80,dbcfaf1,46b5cebe,b9547f8b,b7fa75fd,b2bac9ae,ac0908ab,11770838,88607506,bad87ba6,38c9ae26,d79a9dc6,6746816a,b9f21d64,fea96838) -,S(ac14a06a,4679e9af,b2ea3aea,15f2749,bc9610a3,b576a506,f96fa41a,76df97de,5aafae08,5b8a0a7d,48ebb339,f4dec906,21bf5162,dcb85100,eb7524e3,a65a4921) -,S(ad583074,13a4eba9,ceecba6b,c568bfbb,30566031,c06e8e97,5c5d992b,9ed2bd33,c2bda9bf,d5c87e0f,a663a40,34162dcb,29b61800,c1dcf02a,c11fe615,25af1772) -,S(5a8bd45d,6fd468dd,41ecafd5,aa072227,6d0176be,81b92061,b4277b73,32acfaab,878a8d5f,7903d74f,6abe28f8,d94d4767,3698a7e,6acbc32d,9e92f9d6,bf31c2d5) -,S(6690c9c1,d9666be4,56d3540a,6a2ed706,372256f0,43265478,7b54e56d,f28df74a,7ad591,23772578,999c90c1,24704c13,a7193b62,64240aef,63d12d88,340762a4) -,S(3c051303,c113779a,6137f46d,38d1175d,8778e460,8b1e0abb,f7bc4539,80b64a2f,9d4d04a0,ad1c772b,4a523c13,cc48990,c733eb87,993cdbaf,61dbf75c,4f6a96c2) -,S(1fdff503,66319168,f5dc381e,8085ac92,223b3484,a8b362c2,26d1f00c,976f9f04,5cb328e8,56aaeb05,62017bf8,65da44b2,94ad7404,df11e117,8426b79c,25a49fa6) -,S(ae83da7,52ec2098,a4a593ac,f99dd58f,cd48da14,361feaae,6cd992d3,96b4fd8e,6dc92b41,f1e1474b,a259e96b,ec4f2b36,108745b9,a500ad9a,edd9c828,4c3d129) -,S(c0f86e7a,6c0fee54,a2f73d2b,6b1522e9,fee994cb,d5089886,d98a4748,161811d7,4aea0b92,2441c184,c347243e,5ad5a064,ba00768d,52d7153,a5e0838f,f497d551) -,S(8e5b23f8,85d683a6,a6a657ed,d2d2f403,1320d4c0,83340126,d2958dc2,4c5f5ba2,25c6db80,477f37e0,ed6c6e3c,c96b1c7c,f9a7ca16,8e940e8a,b2946c7,3b02e61f) -,S(6672b4db,bb16c672,2592c239,7d9ea25e,f081d48d,aeb42c89,ae6c42bb,af09b3c5,a3778252,e239ae3a,f64e3b91,7f646181,4f71753d,b4bc958c,b5bcd3ba,4b5b1a4e) -,S(e0af1a1,b894fe1c,1f7de814,1a393a3f,b12b31e3,fcbd8f2a,356e61f4,402d76d0,37913973,b4de9a2d,23f4f795,709fe825,8eee8aee,afec5996,83d924e7,21fb9b0e) -,S(94355dd3,c3d73a1,cabdbe7a,295cb015,335a5a79,dd301718,10c245b3,d0c840ff,31e96abe,22a16033,56681d3e,e5e8330,628d8090,bfdcb925,79074cb6,82845475) -,S(fc340c8d,1e3e2849,1470dfcd,1c2fb445,e807e1a3,9c525ce8,141b292c,596d2e36,738e7213,7580eb3,615b7eed,9b069cd2,b644447,24696a,7cd22257,7a931464) -,S(c0c4e03,61d923fc,4201872a,1ff525c6,1697412a,7bea7a92,596e9204,f1af90c3,25c4c2c6,d6593ef7,ff5f04fa,a5b0b2ca,736ab33f,5c36dc63,433821b5,382fc4b2) -,S(81afd4a8,d666b97f,dcdf0d36,f2dfdf7,bf7c3322,69728b75,26dcb3aa,df51365c,b7fe7653,2c8d48fb,8c3d0382,68d57839,edf80cb5,732ae303,5c1b51c7,cb8d3efc) -,S(140b32fa,62130c2f,1d49e39d,15f9c64,f5cf54af,3a0c65b2,298e91e3,21b9477d,bac2aca4,c96d4363,12107b2d,8996875e,6772eaea,a5070920,39c1171b,9113b516) -,S(17418ab7,46f1eaa,b98725ab,68bca72b,9cc645d9,cbe0835e,4bf91a7b,3939b98,dc964031,b1292c03,117a4ce8,b3341e23,da54a539,fdd31126,41706257,bb9382b6) -,S(8f0222bb,6cbf7491,12b95780,b50077d7,be2a27ec,5bb6dab4,923cf36d,3a12618d,8df2a149,abcd276,31265890,471094cc,fe6bd8ed,b75c2364,6f7dd54e,30c4c6fb) -,S(e3965324,1c543ba1,2d0ca0ad,88c26ace,b265f42a,41d2b7d4,f252ecf0,a48275d0,44467da5,18786654,5722fa15,36c187a6,f67f2e8f,5a424336,b0ce8bbc,a53f9cca) -,S(6a4b614c,41c4a6d4,ba4f8c53,26d08bc4,ecbc72cd,d2415c3,b7caf285,acb07c1d,76dd92d6,3f85e1dd,685faa18,283f8667,2425de4c,95a7985a,cf5f74c2,7b29b576) -,S(afdd252f,82037cb1,928d896,74f3ff64,57b94412,b563a4e0,1a32cf2d,1afde412,d57f319,300a6f93,1155b0b8,3dd83a5e,d2b4a0e0,5d58786a,8024627b,73360609) -,S(65adaf88,4297a087,6ec0d433,ea82bd5b,9e3590c4,921fc2ef,d1fa0b12,cc74808,30e4ac9,77b97c4d,b7516c02,df65de7c,d9e8ae08,6146716c,3da4b26b,eca17033) -,S(eba0dd63,c667395a,9e9eda33,93f5d101,8462b957,1aae6a09,cb723e2d,a45704e7,8314c569,49b7c144,197647da,baf857ca,a164e385,62c1cf46,bb30e7a7,a8dcb680) -,S(d3341d4f,1f967f0f,10932a5,351c6c22,c748af09,1d547cc,2766e6f3,1a9f570c,9694fb83,74177e3d,80775206,f58b2e12,32b87c9a,21f060ec,19152435,45502951) -,S(1596b717,8dceadc1,b5f3a5de,89c089f,62506b6e,2c6e49a7,f1cc4a11,e502079f,97157538,2aba92cd,8f009de0,9dc143c8,51b0f3ea,31067381,48a34858,8c085d49) -,S(138c0bbb,17c63e1a,a3e65b50,3c602d8c,74178847,8dc2bcce,65b84cfc,95f7ec41,bdf88a3e,34f69fc2,415fb95d,a4b6d3b7,f159651f,36a2d4e0,b4063e5a,ee86dafb) -,S(7d99662d,e6274432,65ab2842,a4ed79be,480404b3,1b847c01,c557e277,ee073176,e2ceda2,bada9b63,ff2fc022,44124d3c,b83dd4d1,f3fb74b2,763ecdb6,46e4cbf0) -,S(9e3f4ea0,b1db451b,7d713eae,35802229,fabbbfd,6f6d0ab0,af7483a5,37992e63,a9023199,10301c3d,78933143,b54e87d4,1419524b,16c9c00c,5550fafd,e6be8b65) -,S(108c8cda,d6ffc3d,b0863a66,43f0a4bb,efcdb0c7,202f630f,f971a7ce,dec3ff40,847ab4b9,8fba1fbd,15f6bb2a,4b3d1038,726c2d66,f4c9b8e9,f740af8f,5067d95f) -,S(5258a6a,7c85d4f3,e650f0e5,1e2d8254,8a768c0a,f276da55,27ab0050,6e97e710,e5605a14,31c8941e,4f2aa3c7,9ab94e3f,ffed156e,ba2159a2,7fde377e,e2ea7e26) -,S(c40820e7,f46acad2,5bffcc6d,745aa3e,7036f26a,b6ae85f0,e3cb8f95,29dc3f3,6ddf9217,88249ac7,6ac2c9b0,1dc5e62e,91587d15,c76fe26d,6d7c3b2f,feaf3b12) -,S(c135f50f,160d04e,43148abf,d76509c4,e55aadc7,554e4ea5,823e013e,a0490da7,f9a597a6,b26a1485,a7d5a91d,486d099,93de9a4,6484edc8,72f8f4be,710aae69) -,S(484be5a8,b903230f,991c3118,38d3ebdd,9759f5cb,11a9d0a3,9bb11a03,3924268,18f80a36,a3d70e67,5bd65253,a1ad3e40,a3152d55,c1141315,57f8585e,315ba462) -,S(af67562e,998a4032,77fc5827,cf222258,cb2f23a7,4dcd0d4b,315564c3,eb66da9c,dd5bf89e,c9b2c178,6adea201,d36f3a66,771b3f2a,cfba7acb,c30024fb,fa73ad6f) -,S(38dd6cd,475f2808,938d92be,8ad0c955,f3cf3255,c3602b99,3c177e06,553af411,1abcdd02,d82cc0f,680362bb,f898bf89,304d681b,6bc3afcf,65454ab5,8d44214) -,S(ee37f0ab,3db1f9b3,2da0031d,48f53766,3530b68a,f47bdb87,679426b0,d90fa6d5,6cdb12d8,136fc9c6,2f025cbe,7882ef21,4e7b09dc,9fba4cf9,b021c4d6,610c0397) -,S(670684dd,fcc19f15,ba9201b,ca36d143,47dabf31,bad07e8d,68e6fbd,2630a98e,77bd28ff,a9699737,1304d4f,82d29d1f,a69dc123,6f2ee438,cffe3f2d,358ce706) -,S(1654f447,78026345,64e3608,bb29004a,812ea39a,d96830f6,66a92f5c,54a79359,11d91962,3f81fda0,36d2d021,607d9750,cbd30359,83c4f47a,21fc8116,ca93cbe9) -,S(ccf0a89d,429a0274,7b000326,d62825ec,6978f24e,8f92f490,e8cab1ab,ff90bfa1,5f047694,375222bd,5968dbcf,a331db73,85b4df25,72791c53,42c62467,3d84400d) -,S(45d36700,32ab11c7,897d648,67ed4d03,a9504461,bf28f3df,7e1276fe,4c1de796,67e837fb,37108844,2338086a,d1506453,ed1f37ff,fb14e617,93908c7c,2a8e6fa4) -,S(9af3b6e1,627a2ffb,c18ddf33,b668fece,bbe7ebe0,986df82f,1b2fdfa1,56dbc565,55e9562e,882f6629,1eae4c6b,5a82b0b,b5bc2cb2,b8f884bc,3e45a126,aeee19e0) -,S(ecfe9d5e,d3b9fe15,c320e05c,7e0f3b1a,5fdaa9a4,5e1ff99f,88012642,a5d45b4a,b3cc1fd0,e0117151,f53ec671,e1d207ad,5f2b0755,8956cf28,2be5228d,db5d48bb) -,S(6e482326,6ef64478,dfa30c6c,f3a951f9,fd9d3108,dbe80e5d,3cbf2217,70f5483c,97a3f599,906b1738,372212da,80309562,d3d4179d,d2abc2b6,41ef2f4e,6561095e) -,S(3de89149,f6c939cc,5419e4ba,f0baa93a,390f01a3,4ad0fb7b,3b170e54,60a380c6,e9a07758,1c4617c0,b996ae3f,b250b723,874b66fb,85a6d826,cc5826e5,bb068491) -,S(d4d28193,53ace188,703643d3,84622505,d9020459,a600349e,69016cf4,faed2e25,9a494bcf,e15bcdb0,97513682,ef09890a,424d6bc1,ad1cb73f,123ff5f6,7babb364) -,S(f694a819,fd0f2035,1193eba,c18e2db7,9c219191,2bfcc60b,6af8e067,2281095a,d80d1652,1e43f18a,4b663898,bfce8670,6f53436d,a30b0663,9ee6f99e,ca87e667) -,S(af8595b8,8de7c459,7d1d1614,ac897de0,5dd9ff05,593dd3b6,cbac81ce,d2e1fb5d,e9dcce9c,83ee7217,857d5ca5,a48bb720,69d467b6,897be9ac,658dfbef,3d40e6a6) -,S(df4177f6,a7deccf4,c618b710,b096bb4e,b310e4e2,470b5795,6a633154,8ae8123e,3638e20,5d42ebc6,7184e567,c177f479,18fbf9b1,e4f69435,487b289c,35c7fedf) -,S(ef50482,30344ae2,70ec6d30,f4daea23,ce7b64bd,b101638b,5a52ff3d,6dbe9fd3,a6eec78f,e38a2e6f,a9c062bd,4ce28dde,c5d25fd5,a3204281,ae30d79d,99a2658d) -,S(f89596f3,ddd57abe,3344080c,a6d85d0c,492261ca,7a698aad,ae00dafc,75615954,f8d7d2eb,45dc2b9e,a0979550,8d9da016,20b53a19,b4150ca6,36bf0f86,ab3dc0dc) -,S(a7c2ffd7,50b99bde,92ac1419,57d8df27,56ca49e9,3f4c7434,b24899f1,24fb3cc5,a1672ade,aadad853,47d1440,d573e3dc,91987d6d,ce55c67d,665402d5,f8b0a289) -,S(463f5f25,b5c63801,a6b1accc,6662e6de,5256fce7,37e1c875,2b4a880f,19ceeee9,858e4a68,39eb48a7,f1a7de4a,514fdb46,1f4203c2,65e308d0,3fb9770f,1f8f13e5) -,S(4c99bf38,57073c27,cc92314c,f260dbf9,e0f4bb7d,1a5ffadd,a808783d,3bb602b8,aa107422,ac7dbbbb,f6e8064d,22a5526a,96bcbca9,9dbaac33,c1f35b2f,c6df568f) -,S(f6825035,64438569,aa7a5a4b,e2468453,8d8bfb88,f7e983d5,33ebffd,f8588520,84ff2ce6,9d79938d,fd910bf0,25a2fe8d,e6013c03,74784b73,168049e,c851cf15) -,S(62ea02ca,16b2e528,2f913a,36463494,c00df046,8afbeb34,cc9573,b71577fc,36be98bd,2c83e8cf,e0fc1aad,98ffd9e2,9ccbad8f,a25b9da8,23de20fb,fe91f9b3) -,S(ea34600a,7591c57,d0a7e351,de6e6d0,2c72220,62a980cb,bcca8966,356a2984,25eccb4f,a6102f52,60e4c545,57aa960,b427e372,80c35b8,edad5f52,1bc93aca) -,S(5b76cc79,2e78f177,97b32c46,92f2eca5,1ae1b7be,a753ce98,8e58d116,6c667027,2e01ba25,799e1b9b,3416493e,3fe9fff2,c46e634c,2175a30d,7458429,3ea60b5e) -,S(62a52d8c,d8562624,48ce5315,28213ad0,6fc6044,b6490db7,c27b7662,bb66f07a,e8f5e0aa,aaa65c7c,2b51e665,f3b31157,54ab9fdc,ac492ee5,fbb2a348,d8db5376) -,S(a276992a,5e155e29,d091e05a,5f0513d9,ff2dfbee,6ec1ffd9,a91f55b9,bca641c1,3d480cf4,e3f6efda,6cea9cc9,d769b16c,d1f3d64,23aefe9a,abc82b8a,adb22e48) -,S(bdb5fd64,bc99741f,a2a672d4,a895aacc,98886a9a,d38a486d,ed1915f1,f0b515f,d9744595,ae6e1e64,5a52a094,75ad094e,6af9655f,185ab90c,c03262cd,39794f93) -,S(cd6c6829,9d2b1c60,9b70153a,45259261,91b9b9d0,9fcf0682,d312960c,c3f82c04,2178ce3f,1bc21a2f,7accf32a,b20d625a,182f8733,e460e8b9,e1067dfa,fee6b36e) -,S(ebbfa9e1,8a4107a2,475f99a8,672be581,f32426a2,d774acdb,efe501c0,af97a0f1,1845a5fd,d71baefa,64cdf1f,d1211158,a70752b3,adf2b4d4,b5bf1a9f,7a0abdf2) -,S(bd5af866,4d51256f,455a3190,88b754a5,34223135,1491f763,3e090bd6,27414fa6,f8b5bbf2,2154786a,29f75090,fca2e149,60f84b47,50ea8db,d7c309d2,52233f3c) -,S(34ef0b38,5a8e776f,1c3ff95a,5852027a,ab6d1da6,6201548a,fa181c81,55382b77,958180ce,9afc501f,84d4d3b4,eb556ca2,e6ae8dcf,f949db6d,33cca5e2,9b357280) -,S(4b5f6663,11e6956c,e186fe3,85f00069,c0dfbf67,e4130bda,64e0e89,1abaf471,a6cf3571,2e790d5f,b500324,773281c,43f6d008,f6578ab2,b48fe4de,1ce3b545) -,S(cb22489c,bac94ccc,887a1d7d,8836cacc,c8c2a43a,4e09595c,39cc6064,ca04546c,dced75ef,d7ee6ae0,18ff2690,9abc82ca,da74e823,c62e4268,606334e2,969bf94d) -,S(b069007c,4a50bfdd,38ebcbe4,31a952ae,5356d63a,9f4179b5,e4cda3f,fe478c42,bb90d5c8,e66c6194,ec55acc7,6dae5f0b,dd498746,2d24a265,c314e93d,618a0f41) -,S(18722ce2,9d9cf99a,e52a420e,23fd8e85,e1582d02,c520d4f1,16c2b82d,464091f9,9fe257cb,5cd5f644,183c8461,ac2dde6,94cc84e9,76d9c623,584a9d94,40fea12b) -,S(a1562afa,6420b34f,92a78951,e9ab1bd7,8772a181,636df487,81bf4bc0,b16bd196,ce4435e8,7105d006,9b353734,5a503e0f,a692d3a,8571e8b9,66d9a722,48ecbd1c) -,S(f466db58,b4fae060,b12b780b,df11c7e5,ea8a08cb,cc50e68b,f5d85926,b9f3cd97,c86b4153,45515a2c,9a831ff1,d6377a8c,cae62456,f207df2c,42a1e767,684f79a4) -,S(686a1d05,e2bfaac8,e31def35,21876c81,27be2ad1,34ef3dcf,6de52778,37278176,111404e1,7f2153ab,43597a74,be1c278a,998b3695,5f4d465f,271a6a46,8e9e8986) -,S(d8433d5f,e5ec423c,73bb3ec4,95d06cf5,3a77474c,1e97ff97,f72a0457,9a60926e,3df114d5,a9d63dad,ada0ec4f,f98cb8ce,f1ad419a,e2c23dc2,f24048b4,1879be1c) -,S(3a9a0aed,4581937f,fe49392f,488053df,349f0194,9666418f,16e56fcc,533cb73d,c9db1a90,2d6676da,251b4be9,7a643bdd,d55c2b15,95ce51b3,281cc866,40cb558b) -,S(b35a204a,28884708,3091abf3,34be3696,b1082fc7,5caeb0d5,18387aa2,711a4190,65f951c8,78232345,487e8e,376c22bc,e5d9e8d5,ac04ecbf,24cafef9,4de358f8) -,S(81ff6fec,11f48691,59a2d23b,b2a6a9b5,68c5e6c5,1df9905f,ff73e1cc,a2c505a,c7b794cc,d657519,fc05632e,33e23474,654f1344,6ef1b4aa,1a1da18b,4acc1e49) -,S(3588a9e1,7feaaca1,a62fcdfb,3952beba,43116167,bb238f10,a41fdfa9,bc316d8e,acb24c1a,58ed9a0b,9744fa76,df4742b9,b440347a,4b4446ea,a3e55234,102d4789) -,S(7eb13fdc,9588b724,e7cddaec,498a8b15,d57a49af,529c8c9a,cc8303b5,e81f91c0,89f6ac3f,38351f7d,e4b293e,f61a87a4,2c08a4a3,ae0c160a,563ae5af,dc62dcfd) -,S(2f68c6ef,b363459d,862710a0,a0ae67c4,afc3cc00,85f02e21,ca4d764,3c76e00a,f8be9930,3a3aa7e5,c50d3f53,9b88bfad,60f05fb0,1461d7a8,225bb21e,18616cd7) -,S(b11994c2,5e3e6d0d,917ac215,c5f39606,3b9b764b,5dfc2b75,ab8ef880,3b57d802,4a7ae35e,c525d91a,cfbdea6f,cc9afbc9,b3cc8c80,acb4385e,9bc20158,f9f2b55b) -,S(d8e7881a,e1e4d04,c431c097,25dd4cd9,b4efb4c4,3896256b,7de47fc6,3a3b30bf,ccaf57cc,138f0bbf,5dbde16e,91d14875,c0d5ea,3842e864,be8de17d,875fef67) -,S(88e02abf,a37ffc97,f564cf3d,8a086c8a,62c05720,802319a2,30ab7cfe,b448c478,ec2d3169,15dd0c2d,6f03f851,97a96f9a,6c0772ee,df0c4524,c08f58f2,39c89308) -,S(ad258ffc,b42d127e,a875b181,a8883a5,31d18a64,d75a6dd4,4111d697,90752d1f,acf5ad9d,bfbb14cf,a25748e3,96bf23eb,aefe1bab,6550b234,90ca0278,276e9db4) -,S(a2bfdb6d,38159e5a,604d564e,af29cf09,a0a8ac79,1aef5a63,e1c05da5,fb6a0c39,7a45c5c,a7ee7c0e,74c05914,1e3d898f,ab62a8c7,31ca0a66,a937ef55,51dad999) -,S(7c7bb792,ef21cd53,bcf33a82,6a1ebf93,e9f3357,51131f9b,36f659d9,594f453d,bc98b32e,173d91ca,e9daf137,766c5ca5,6e0434f0,e2eb070e,7fa7f8b2,e7364635) -,S(40a2000c,dc0c1c9e,4c037a3f,3113b48,f26730ce,11e03b1f,d2f07217,7816f8c,1966929f,210afe16,9daee99b,7b48eef7,27e1703c,8bf42006,922c0496,888b690a) -,S(6427d169,cfd7e9fc,1b310f68,e3371720,28c17dd7,c6d5a32f,4ed6d41a,634f3f1a,b1a71fdc,6a030ca3,d7dc2ce9,27f3b9b3,ca7169f5,2fdecba4,bc85e32b,4e52fcff) -,S(723013b4,24fd897a,1e8ab77d,ee0618c9,3c832117,94f8b822,9d7a9e51,1ba8194f,21acfca6,e5e0cc31,479e5a97,17494692,9134f2e6,ebcef2ac,c7779251,77e9aede) -,S(1b18b7a5,43a284b8,3165bfa8,ca947da5,376fc4a0,8f4070e0,a20aa905,fd12acb9,713ab4fd,9e0bab6c,aadd2f63,1c5ef168,7cae85e7,6146319e,94b19a1e,f6a69584) -,S(65e5990a,4700f51c,9d3e61d4,26c92f88,5506817c,d4d60c66,a341cf91,9646ff81,2ebdd818,f69cd135,1405c63a,7160ad4f,17a6a7e2,d4353db4,7b554eab,3e737819) -,S(eb131661,eb78d37f,92a851f4,506c43b5,1f2a155a,dac7eee3,b1dbc29b,a0b1250c,45f2f418,47d2258c,3f78a2d2,794e9aa8,eab23395,8debf0e,b1440d56,dc728334) -,S(f20aaa98,ab7d6f1,d6de080e,ecd0bd28,b14cac9e,7f27c931,5576b039,16777203,4d0dc753,84c942d9,347f007d,543bc399,ee01e84,7625d5c1,a57cdd67,79c4dfba) -,S(9994a963,ef21ca0e,9657cbcb,3da57f3f,e28ce389,60ae5dd2,812b2949,96969047,93d75bb1,35572b75,4801509e,5b64858b,c0a415e0,3968efe4,2e558786,8516362b) -,S(4696ef39,95e5818f,d7894737,2fd68c75,fbb455fa,8477863b,b2687fca,fc2cd7b5,1cdc53f1,c52112c2,f58a6f66,7c1e4e9,110d83f9,d765347e,a724c784,d8e5d5ee) -,S(7b052f1f,e1af9537,ab3bb5b,3e0e510f,7e101cf0,999f85be,c403fd62,53e68d25,69c7f158,4b6c36c,f7d881a0,fe4efa5e,3f879753,641ce0f4,3e73bfe4,77ada27c) -,S(99452d74,3311867d,1d86c1b1,decd1ed4,7192a58b,3ef98cf0,7816823b,1296abc9,ffabb50d,a1a0451d,36b811ab,5e0c55d8,751a1851,3ca8bca4,8d6b3ffc,61ba36e3) -,S(40c6fec6,5ded4688,31f72de9,fb5c7f67,32c0c170,29f19b36,b00b0f85,5a12424,17aa0baa,eb3ba6e4,c5000e96,c3eb620d,ce1dfd81,b35a3e79,b27b8246,97dd5741) -,S(b9bd9e2f,c55ce5dc,2e46e4df,56401c72,e01ac3d5,201a3cbb,a6609fef,ae2e827b,f545efa7,f95e9a60,72cb9750,6f929b4c,e0360c8f,a9f058e6,5b87bd55,a72abdcf) -,S(867c0fa9,f885935,2756e3e4,11666eb2,59a416b4,7c2ff329,e30be462,13178921,6fdda875,4a50ee1b,d229d4f0,fa8876d6,9caf9fb2,a6af19fd,dbbd2a81,5dae486b) -,S(1cbe8374,3decb58f,f2fc9668,7ba45c64,812507ec,c2f71d66,eeea12c2,92fb36cb,799533ce,46d2c091,d0b553b5,18c82317,f516049c,4a4f50be,909c875e,b0bbe21b) -,S(c654f9fd,57426248,fd24097,2595d71d,80cf771f,cabed8d4,63bdda8,340398cd,898e9224,c9e94d14,3f96702d,c296bf50,9b2cee37,da574bdf,b7c09cec,18357a18) -,S(49e8e14f,4a9f09ff,48725eda,85ecae6c,3fe3400b,81012e00,991f6a69,2d75083c,815230c9,284924fa,57d08944,2a30c61b,8ce19644,7a8ede69,fb645864,ef35977f) -,S(43a6ecde,ed83f1fa,8946f584,99e71bd9,978f610,b46d1613,c15fcfc0,f79786af,2995f70c,11eb448e,68eb3d10,c84b36cd,7605e249,1df1fa3,2e9eb57c,c0275482) -,S(96861d91,678e5004,7c491950,5bbfc70a,e342c3d2,361729b0,4d0bcb5f,d93eceb5,6845ec37,9bee6269,464b2e9f,156ada30,c518bb8e,105153e1,c3b3e948,d38078e7) -,S(3c72be53,c9f82add,504a1955,7b9560a1,7716a058,26063408,79aca60,c55f4515,e584b72b,cc4744d9,6a00dc44,b03ba61f,c2269731,a8178755,2a6dce8,25d31b81) -,S(ce4b4d07,deae1fad,33192544,448ac5b2,77ba7f70,27b81a08,d7f84581,4f71787b,2013299b,2c744a5b,da6b243c,d04d95b7,e515848c,dc28eb40,892d40c,210bd1b2) -,S(37984db1,6d288866,78e1804b,9c94ebf8,f3a1aa05,1fefce96,65712f98,198ce116,20a25966,8ed14a5f,fc3aac09,6d2351b3,b6cb19ab,da4c833b,4a2a6c68,55d1ce59) -,S(ac01bcf,b02e627b,2c9c931c,f87beb2f,4ad7328f,9caf627a,2bf695ed,b7353acd,be4eacf4,77c92348,fe0feea9,3075e93b,bb3633c6,6747524a,e387df82,176ea252) -,S(d5d6af83,1a81b72f,efe5618b,ea43335,bf1d81f1,73382fda,860260d8,1a2faa83,865f9ee,4ff0fc6b,fa761709,db4c67ee,a3213d07,21b2facd,fcd8fa57,8945698f) -,S(3c16399c,4de35853,a6dac8c1,8eea4b40,92a22a8d,5e69ed0c,13b9c2a4,3cd5e39c,bffc2dbc,c2ce4b04,6a92b967,d1a04b5a,2fe40be0,fd9930d0,45b51f8a,15b53edf) -,S(f67018d4,23e50a73,68045b0d,ce803e35,a26d9a5c,288a3a7c,c25ebb03,dad28187,ee97afc5,1c73531f,ea8998f5,53086a59,cc67c6db,955baaa2,8f57153c,afc4e772) -,S(de67026,529a32fa,b3ae79f6,ef9ece7a,47008d2,46f89053,e9339c4c,dcb53b30,4daa8700,4b055005,90611f78,43d258b9,516f1fe8,61cf06ca,d466e000,d3a68783) -,S(a133627c,af6e7ed3,1d267608,19b69f45,7e75ecae,2169284a,48b5ee16,b5dc8c10,755ef12a,fb5c071a,36dbe2b7,1f858d87,31c93d81,d271c999,8f632982,d7e97ce6) -,S(d255c1e7,ccc88c4c,33887c9c,b9c15a2b,52b08471,90ad1420,5fb5909e,d36059c7,83e3e1ca,99a386e8,4b119391,2c20593c,f9573996,d42cb7c3,6db24a5f,cb413080) -,S(aca6c69b,9ea17803,4af67422,71b8062f,77e6dbe5,1df2a570,65fb3057,ea185b8c,40cb09f2,adef414c,816b22f8,d7a59f8c,f5197fb9,b31614d9,ac172436,d0f54647) -,S(fbc19c84,3b656fcb,21d99c3,5289d3e3,2bc58fdb,c2404309,a9d8831a,f2365f24,cc22999f,203a4fae,59eac72c,28bed6d9,291f204b,707bffca,ca6d8359,1e403124) -,S(ea308c88,c366677d,5e575457,cd3e6978,5b491a02,c542dcae,5dd5e149,2f839c55,c1916831,2f48555f,b80845fc,ba89eee7,a7967807,d10c6f6e,b516c190,94873ac9) -,S(d911d62a,33fefc48,abfd4409,7ee2d32f,d7e85816,2a8a00d1,342646ac,8dda6cd2,f160f933,41bb32f7,401d153b,4a2decf8,b793fb5b,4d5520c9,6d9cb9e,cba79aa3) -,S(bb75b497,7d698442,7b0ac74b,939ab3d8,fb94304f,602e102,1fdacf22,27022a4e,ee3cc171,8e9190df,9b45d8d3,54eeef9e,11639423,dc091128,ae09e451,fffe3468) -,S(358e7639,b4031852,b983b5c0,a6c0d33e,5edb304a,3f8bd15c,35d35794,e2cf90f0,5da4be1d,2e9bef5a,5da3cc59,d3c4f85a,e6624ee3,17395ded,398147a,12c56c45) -,S(e098fb9c,440a5cdf,bc570270,4b57eeed,f3087b7,e196522e,4b194618,f3c874fe,9a5b80e6,b22dd111,1f824c36,4830e723,18b7825e,2f2a0fe6,ca460d0c,34eb6449) -,S(62d607b2,d1a16e4e,cf60480a,be9416a7,15d70b5c,56734e7d,1498ba03,7632528e,70c5f4d1,4f5c900a,96291a4e,d0f795ff,439d35d5,2c5bddd2,ab10571b,1d7d20c2) -,S(a630c5bd,ec76f869,40842391,cba6cdfb,9109940b,e1034b87,c6a1e5e6,9662857c,8f28f55e,beed2883,3e347b10,92ff8938,133558c3,bfeac1f6,a6b938a4,c783b79f) -,S(e2a164aa,e17cb0c4,8ae1e911,872b0b3a,7c0e29f0,93cd5e18,97145211,d72147b,23ccf99c,afd1bfbf,a7ce1ade,1590d609,9a423b26,381f5761,c19ba373,290e6193) -,S(742526f5,b95051cf,2ee34994,8385fa72,425162e7,e46bba3,febe5ce8,595a8b37,d106a3be,638987e6,870acf8d,26d4f78c,e6aa0e9b,63e4eb19,114fc97a,eee3a12f) -,S(ce7837c2,31c32444,10dcc790,de465c06,75404a1a,68d23fe9,b69d887e,9c554f45,2c0be877,20cfdb11,8c37b2de,a2c355,d12279da,58f75570,7e738867,146257a3) -,S(601167cb,2788b146,998f0b91,d582cbd,27f4b866,40db7ec6,7f26214,f3ab9212,50525e40,1f2da57d,1f605f34,8f11ac23,19ad1827,41d7be11,46538e83,e03bbeeb) -,S(d2f657da,6f7c3c80,9d2e5291,b1161d46,393009ce,e2bd22ae,32b99eed,f76fc728,6df58d32,b795b6de,2a9c3b15,f4f1dc9,4e6e6757,e01891e2,79acde59,d13e3e75) -,S(e9fb6b74,f84973fe,7c7a0924,e0133b92,bb4c22d1,ce9a94e8,433f0c72,2a86e00d,f4df6cd9,df43c150,9d4b9580,eb87298a,551ebec5,2438597c,87dd46d4,3a8ad2c4) -,S(98d46b64,e43f3384,88c63da7,35af1141,e8b41981,b706ac5a,7aa1c0ac,1182afd3,3b2ce203,5bbd2cd7,f3206b3b,6aa3ac68,31e0e2d4,7f9e57f2,3e780fc9,cf865733) -,S(b358a4c6,a7130b1e,a00d8403,7164e68f,c6cf96ea,c6580ee5,b1cc2452,8d2bb5b,3bbb25ab,4645c17a,2a6f7e64,2d3952eb,86462564,5647abd1,2e80d965,be1d3854) -,S(fd8807c6,c456582e,d03114a6,2b42316d,4d0d386a,aee634cb,d33f2f82,c1ad6f05,c67d1611,e45c57d6,1f8d721c,437c0ca2,189488bc,f363aab0,f25314b0,14f896) -,S(cd53fa2a,1f989ceb,cedfb7a5,237addfb,2efe9469,8b6509c9,3081710b,f0db107a,47e61ca6,4d26e617,8192e993,411d0540,bf7c37b5,8c748eb7,6c1c197c,87c3f844) -,S(38cfdfb1,1b60a68,b00a4096,8f2da5e4,4a60868b,de9af728,fcb888b4,9a098c66,65f4f191,92667492,d717cfbe,bafd0076,59c08392,30da216c,315f2cfa,d3725184) -,S(cc179d39,1c6ab4f3,7fae6380,35886e2f,82038bca,768d1396,13fae8df,a167a271,a12fff68,84a967e6,fdd6e14b,4083c0ba,2a2bcf49,f7d6071,d708c70,4722b1f3) -,S(cdd61b33,75fd00cf,430d9d54,202c5c61,465fe7c0,a3f51660,ce74a3bc,58068c,46e5334d,bad31f3f,6c4bccbc,6812cf13,5c039a5d,d51c6516,49564f45,45f13ab) -,S(39ecf8d5,4fa9c3b,fef7d5e6,5ebe0e75,288f17df,4b33036b,d034be2d,fa5bdbbd,21991cec,ef62e421,70da3bf9,8b2f9bd7,790d5b13,25159727,a53a0735,5ab1d956) -,S(7b621836,342994d2,3185da8,67d47e69,a67a184e,925a3,524f5e7b,63639263,b08c269a,1569538e,653f2beb,3e6e348d,c61537e0,7afc5f13,f56d1f74,518b274e) -,S(28e5ec3b,38359a6e,7d3a965a,c5713365,44b91ea5,c9f350bc,d315c153,72133bb4,5bdc5a02,62734535,8621c1f1,492b3434,be731c25,f82c1a32,163ecf09,7f548465) -,S(37ac3ac2,3f6b2a1,a3a5a99c,707a6b8d,5f05e80,133ac522,107ae5ff,414d33c7,460c947e,76eb51c8,42bd0e6,6ccc0937,87f61bc3,554538b4,c2065fdd,533d0b02) -,S(275f5ef2,a4546ba0,9d96d138,e698cd32,78cf27f3,2ee297a,5ff8dd41,f16bea50,ca91a3b8,5b0a493c,a49168b4,c9eff873,66212b9a,c030fe6d,a9be42b7,45d0464a) -,S(6c43669f,a69bd51c,63cacca0,21c69bf7,9a94ef9f,3f0aaa92,3be9380,a6702e34,b416195a,1419771d,82fc2ce0,637cf5a,29823d1a,95614642,c93a979e,5ff3fff6) -,S(606c37c1,271b90f7,482e6ba1,81bd956c,44a44189,346bfa67,539c188,ac0eb61f,f6af64cd,3f04e30a,1b4a7019,c6caa84b,823bd00f,587eb58a,e190ef25,322154b0) -,S(e4136e15,b3fdf609,f779d0c0,70ce8521,2babc592,577361d0,47ada13a,2a83d43b,1af23c84,ad240ac8,50da2ec2,721531e7,18776ddc,5847edd8,b4d79d52,26e53125) -,S(a338d942,6ce420ac,c9fb29b9,cf572af0,72c0d144,46dc2c3c,75b9d5c9,f7fa244d,c88a4399,f6e3ef2c,619cd9d5,215d305d,3715b962,b02b29ca,231446cf,8ea7c40f) -,S(c454d1b2,6f77ad27,a168d032,fc1a73ca,fcc4aac3,ace31f2a,433599fa,7107fd9a,989b6091,ba2ec267,380c5139,47059d4d,2773109c,1afc21a4,3be54ea6,ad8f19ee) -,S(bbd7bd30,5bf1b36c,6cd6c180,2f41525d,75675d76,9352dc60,1a727931,ee6f40c8,3c3263d3,75bd412e,1d7f7d5e,72f73216,6415ef3,52d1fcf0,58e6c046,ceb46abc) -,S(acae6fb0,5d5b503,c2e3d841,19ce3bbe,1380b363,e5d8763d,3c520a3f,df39f7b6,6fab4b7b,daba880c,9167ae8f,5feb9aa4,3ca19f28,77ec5021,df36ac7,db730293) -,S(c9d4ba53,a44403b3,b06915f,6bd9bb43,4716a639,453797e,5b8e1cf5,abc78425,749cca45,6abc2a6a,4e970589,42cefba5,a2f55dc5,39bf4f3e,be5088cf,ae04bf70) -,S(3408e460,99f1a176,fd52f70,3c772f1d,a46d32db,246815d,a21826dc,c5657e61,a93bd344,de7afec8,2ea2842d,40fbcf60,732be8fb,738b8364,aaaab796,1e20974f) -,S(5e061a06,f97f61d1,5f66c3ff,17372621,4ce82af,3e606b4e,9f64fb62,e405376c,609064a0,bde996b2,d909e50f,726ed7be,b4698ec7,5e1c9c45,3ba18815,2915cb1) -,S(b12ca67f,739f4284,3a7adf58,d2a2f3ca,fd245ff4,b766793c,c79cdc31,45579113,b1deaf81,34f017f,b2bc20cd,da75fcb7,d219c353,98ee9887,612781a0,e3f3d1e5) -,S(95a72f2f,c241fa0f,c9500cea,d9cf069d,23820078,f61d4492,508d0fc4,34fc223d,832a3979,1fb9fd9b,79748643,64643bcb,b227c39a,e4cb5051,d136263c,293cd453) -,S(ab8ccb01,4b672660,b867e544,926749bf,7172a0f5,ac6317a1,a18b7d15,f039fc94,28471e3c,a2d6e77c,87700c4c,7e3df1e9,2fe91efc,77724df3,2f20ceba,1ba000fb) -,S(26131926,5261c0d3,ecfa9769,fa987347,1b9d4ebf,dccd830a,96bd160b,61b47278,dc9ab665,485133d2,59d7b604,5e1e4f52,9b099e9d,4db9f680,4935e712,f8402f66) -,S(87a4227d,2303f5c0,acace6e,96586b68,178dc65e,2c99583e,8e427ad7,167c4a65,5bce1d82,216355d6,5bbf33e0,9b3baec4,fb0befff,ebe48b24,cc01d454,7de6db8) -,S(a6576ea2,39af87ba,392a225f,bcec3045,8920b494,68c54ff3,92d2f509,519ce85f,deb950bb,6a767b3f,3603be36,6234480c,1851ae4b,1980f902,f8fec863,dfabde82) -,S(ed41c3a2,48285ad9,1642f6a6,feccdbb1,66298fa6,467b0ec0,ea256570,c8e343a4,dccf3578,aafbc34d,8ca5fb6c,b4482de,4b94dc65,a8d22845,ac800947,dc1042b8) -,S(227756ff,800f7eb5,4493181f,83050c32,9f27a35b,891a3bc1,ea5f0e89,b94e77e7,571c9345,e9e95238,3c7dc62,69aa0fff,46455825,a032f33a,154a89ed,e13a09c3) -,S(6f3b91f1,3f2d6787,454bc7a2,2ee780a2,3c251697,c0da9aa0,a03dcc3f,f03e2b0b,432b396f,c2dcd370,647eadde,ec058a01,53fac955,4b3f400c,435c4755,5e61afe8) -,S(aa79f0aa,767db1c0,3893c9c9,c75a1f8f,457f3f36,72c1d2ae,31e58658,a916fe5,4da2c69c,8033860c,14f8438b,8edf290c,5d02f2e5,153b68ed,fb945043,a6e6a1f0) -,S(48f2a720,df970127,2385a961,5a215d8a,3d41e0b4,ad439c9a,9d0453af,4699e527,11669dc9,26f70e96,e76178c5,7d698d05,b6e7da96,eef4e986,c4f6e6be,216f22ac) -,S(561d8010,a81a1191,3bb2436b,bbe0ce2a,6f1af6c6,fc064d57,59edaf45,c7f9781a,bfb2561,bc311bdd,707aee1f,af3d5c9d,faa9d564,a5121bae,9989665,b074f026) -,S(64d0fc68,6369a225,a15cefec,431fe434,1a424c78,85bdf2,51cccf53,9e266fed,694fdfa8,12f6bffd,b1c75baa,3b843d02,1b69cc8,20f2a8b8,69908a00,ac7050c) -,S(2b80d86d,341d05f6,218eb96c,fb227834,44bdcdf3,65cc3809,1bcba0ff,fa8b3d09,152eb516,2794fd0f,abf030cb,1968faa4,100e803c,e5b8046d,c36e3075,9317a8a5) -,S(62652ecc,daf7ff5,3aa255de,ecbcd653,7840a657,dd53e58a,514ec1bb,98c9b5b9,2a05c8cd,bcc4a512,1d2cafd0,6289fa14,178e91b5,b1fa1190,e4c7c13f,f50cef6c) -,S(f23fe7d7,69cd7bd8,5e0d97c5,4163e596,a0e7dce9,488e8f67,4ca6f3ca,81726ce0,eb1355f6,ecac2b79,dd299fce,c0f273fc,3767a3f3,3ac4777d,cb871a1a,99077e1c) -,S(91d4028d,1ea8e320,5718f427,b427c21f,4780a944,55ec46c4,2fb2a1cf,4772af1e,7a529f92,3756a212,24dcd316,bf9a3f6b,f5bfbc54,3b015c10,54ae51be,5c2e6b2) -,S(7a8fdf03,175969a7,80475dad,c43e5c66,fa75846f,63cfd62c,e82d2153,d185670a,b7b58ebb,fa0b2d3e,ec2a2638,accd965e,c7db6cf1,c847c1b7,9f0714b0,c1cf7dde) -,S(9d72d9af,5e9d7b2,7fb2b867,4aa35438,946c4ca9,eb9ea4be,e20b2eb5,e7cdb89,324214ce,d556acd2,3ac00175,f120d59e,50dc95e,96e6fda6,ff348bde,5ff7e701) -,S(33556ab7,bbf601ba,44dcb33e,aa5efc82,3c70f507,550f3d7c,22f4ba62,cf2d6bcb,a21d830f,233a657f,7857560f,c030f053,656aada8,f7812424,f38a2409,7505dcb7) -,S(e002b33d,93022868,60b39e1c,2820ad06,2063c344,bef98dec,3a9a0428,20e2c507,3133f829,1c81d970,f879d1eb,2128f21d,7540e135,31189576,191ac4bb,d83d99b7) -,S(9eeb1972,ffd49c0c,7982671c,59071b20,422a053e,394db993,8ef7b3d8,98795c5d,ae48763e,5ad78988,7a756827,4a17708f,8afdd8be,bc9c0316,73dd9485,319763c0) -,S(60f821e8,ad12907f,e445f049,141c7718,a495d1ea,3e39edbf,f0a73018,a5cb6854,6dc1b291,62b025ae,2a285e59,a5b406dd,927a743b,483454d1,20426fa7,50adb95d) -,S(5b8bcdc6,40f4a217,6d0661ef,f2ca5d6c,b1aa2069,557274c8,287fba59,dfd65a41,42ab52dc,cad04998,63e634db,ebaae018,c999eee4,c3cf05b9,4f18d218,23f21256) -,S(e764e748,4ec2a2ac,6843df3b,5316f29b,701b5191,778bda16,a23a20c1,69ed0cff,e1007e10,4ae52971,875bf7ea,9e9d9431,94c2e9b5,bc7b2844,7b7acded,de7d633c) -,S(37f0d948,48742a8b,e73ef1ad,495b88f,ea95f7ee,b343152d,85f9e442,771a22b4,bf960e80,467cf81,bc22380b,af2f57f0,d5938ccc,55f3f691,784be72,7fa68bb2) -,S(7ff13c43,7f2189a1,18b2095f,be268dfe,e1375a3d,f71e88b8,4cf5b94d,63b04612,10295e49,1f0a882e,aba663f8,f0202223,21c422d5,f3b453f4,8ab8bf4b,4319930a) -,S(74f6853e,f4a2d018,4cf113d7,62fe2a1c,33ff2729,5414a5bf,3f381989,551ceaa4,629f116d,37c1809,f4e2ecfd,19c2627,6deff6c5,b89249fc,d4f6e82e,58eeea79) -,S(d54d88bd,abdcc56,c1bb8cbf,cdaea6ac,16949256,f78d70f6,7a1416ba,b4cf51ce,996afb9c,5b36f588,812bad4,95c368da,f9e96035,4bb7dd1,3f457a6e,da159b59) -,S(a860ca66,3ecd7482,c862fac6,f6a7b0e5,f5f6bb26,ee950db9,2942fc89,4b6fbacf,3445137d,2047c17d,65b3cb88,8e1b0ba3,619db023,bd989a0d,c585a59d,14da7b9f) -,S(d794dc2,4e0e36fc,6f38fc8e,7a68cdac,8d547d42,b9667241,2dd7e6d2,c40f9aab,22a9a90c,10f1b80,e277be34,3c492125,24ebc477,1f838070,f2be48bf,cec3a7f5) -,S(7e28db65,2115f5a4,575293c3,d792fc97,9ea1adf9,dac468e4,60e5526f,6847657f,8025944c,16a12ac9,25e67f13,3835bcbd,33c338d6,824b1fba,f0ee001b,d79d66e3) -,S(d3f13a27,524f0c87,266f3d46,14d965a1,3865df67,5d20c5aa,99a4411c,dc6322c4,9a1025a3,845a4bc1,9f7cc175,9377c7f,e46ecaf7,53263433,baed836f,77e2e841) -,S(d845636c,db18d557,1759f6e6,bad6a60d,3a67141c,b0bfbbf9,33e628bf,8344c053,40de706,ef833427,80e5120b,ec6e61e4,a8a3726,32818317,729e60e6,3ab7e37) -,S(f40f53fb,c672573b,c020338b,71589d53,3709ac32,b38cb943,ed0ca0ff,e592e552,502145c,5f542a77,652a4ab7,d79791cd,e92f3e72,d9d0190a,2724e114,49b64e0b) -,S(2065a8bb,a0d61dde,921a0741,21ae5678,8766f712,bdb3c4c5,776af9e3,774120be,fd12cac4,a85d5b10,1aec6ee1,4b1301a9,950df948,86427be5,55f52736,3ca29847) -,S(a9b1e8dc,410466c2,df97cc8e,bbcb3af5,f981726c,2daf8803,ef06ef2f,a23e038f,b09dd4e2,77b1d10d,bfdd06e1,a42baf37,a5157017,ba026d98,fee13512,4a1c5419) -,S(c54ce1c,bbfa3808,f24b2661,793c3574,a58aeb0d,128d7e5b,ddcd98a6,d8c9bdbb,c1a2291f,d20e8a23,f4012b54,37a7be7d,5af5f776,bdbb2c53,193e07da,bc1a3212) -,S(41ad2d03,31f57724,6476d0c1,f2c46216,6156296d,8bfd3783,eec40892,835ec421,62777bb0,f8b6ba08,128f1727,9c237286,abc5d2a6,492b9c67,3edc903,7b0e3008) -,S(a8eddde5,eb761183,ef5cce4d,a7958b92,db28bab8,2f695fbb,597f6535,50048a3c,7f60d3aa,95ee5ae5,f4cf10ac,cb5729e2,bf89ba7,6b1070c7,ba385f41,a5912685) -,S(f1db8d40,2cee572f,6eb250bd,ed3d978b,1346ce96,d65291da,977b42cd,36bd073,9bdd0bdb,a546ce4d,774f79fc,3561c0fb,ca11f4fd,b46ab1c2,a7520913,f254f42c) -,S(55cee66c,7ebecc0c,7f22d03f,8f166b99,ec7b5e6a,776bcf60,b5f4d452,c861bfc7,772832cd,55b13c5,890c7ba9,96731ced,5a2e1c05,6ac89469,320c08f4,43159d36) -,S(61427868,7710db98,d4347d4c,aae4c70a,9efbfc7e,bfeffe5d,6f33bddc,4aeddedf,fe8b32bb,d0c7a7d3,b93dcb7a,99a5cc8f,e386bf89,7dcdcd86,ffaac641,6550dd85) -,S(9f3ac763,c117bd99,658f5379,119aa025,cd422ed3,b1ed2cc8,545d6f93,39baf4e4,41b2409d,cec0065e,4026e879,84b99d35,4eed93f4,15e8981,256e8734,a4eebb74) -,S(8510bf74,8f5255a1,8f408565,30f909d5,2bed111d,6347da9d,8da2a97e,751d4a98,2ed99b6,6af7cc01,37329730,1b0b63c9,f8732547,fc632eb7,7357e67e,df5549b4) -,S(d81fc0cf,9646ae0,7dad1a3f,e06adaf,1d3508fb,13af2309,c200c2e1,2228807d,cac833d6,c94e674c,a7aec186,42e4a501,ffbfed92,dfa1015e,c95740e6,57978cd5) -,S(32aa5e70,972a899e,e25e6c6d,e43c32ee,df07ebcf,e5ed13e,5095f7c3,3bb55622,38e82901,990a1e42,38639a42,66a93fb5,4368df0e,befe19a,7f234424,a8b68c0d) -,S(68f7b02a,ea38424f,decbbfc3,498c6193,62c732a3,b048800c,85d042d,b284f7d4,bef680d,90660176,f3d3d009,9f6cf818,a277dc5b,3d765a30,b7a4ee9,cf3bd46e) -,S(9437ace9,6b566bb3,87d9946c,2c32c06,f62f1158,dead214f,2b721c6f,b6e8888d,f8dee3bb,331e1e33,9963b7e2,316a1352,c8748f42,44463ffa,5bf2265a,243941d5) -,S(af40e909,85e5ce8d,dfb6d6d4,222d3c57,2ffae40f,53de2c06,55a74cc,70cd8dc5,2f08f237,3fc922c3,f0ed9d6c,b9538f4b,c661ccac,ea2f4975,50f47ec2,17d8e626) -,S(382e5a07,f1f236d5,ca1a68b8,f0fdb813,29e0393c,c375df88,f87914d,cef93c64,e24ee731,c0a88fa4,8ed3dba,87e97096,e0ec2224,dd657411,a9f1a9e8,2b0a6657) -,S(99fce288,c6ef1d18,ad630097,8ba82dd9,1c779a60,b266109a,288d51c3,978fe565,294c9e53,3cd42a54,c071d5c8,acb7edc9,897db8ac,d25b5f10,9eaf8dac,42a9c1a4) -,S(748326fa,c8dc9394,2de0a000,933dc18c,6ef92cfe,bac46939,f4405d89,627e6727,adf2d561,45581b4f,e706ccd1,8dc82bcc,14d76fa6,94ac8a61,a51d06d2,89e36d2d) -,S(43fef689,67074a2b,7e944b76,8f8b1ca,15aac3ad,c8f5590c,f1f02c3,afa82e90,5313cf6e,8cac44d9,fd548032,dbef3ab2,26e93880,644468bc,799c87d4,c0bc3f99) -,S(404341da,829f537a,c425050c,5ba93ca7,baa8a8b7,dfe51c23,e2ce7c72,43d57659,f91a0d59,bc35db64,b250adca,3cfbbaa2,2a82cfb4,d684e8db,e17484ee,af009f9b) -,S(3af33cb6,b4d553e5,50fd35f1,a0b569e3,eae05737,7b7d735b,545f7f00,d9acae67,42aa2cea,deab8cb3,b1ee9c3f,4b1b06df,e157cbfa,3912035b,585980bb,cf85279c) -,S(2e96133a,1da8a378,c138583e,86ba1de2,3450b285,3559a431,654ec9aa,1f64229f,3bfa5a75,4dbd936d,7a41266c,97472020,6cac86b4,d684bc1a,59dd1f27,fed8e76b) -,S(adc4b672,69fbb719,92bd6e22,3cf9ecb3,c9388b5c,45ffadd6,94c72e2f,b355984a,ed177eea,ac8cbd88,2a368fcc,4908ba4c,8a4054ae,3411d75d,b06939cc,72522a7c) -,S(68ac3244,49eac1e3,df997282,65a0176,bf6c6115,64daf79a,135bc6c2,5578b6e,407a75bd,b1e5e6be,a9b815ce,833c0be5,f5c462c5,c71a086e,59fbe0d2,5e7b1fca) -,S(5176afcc,b4235cc5,ea41eaa7,b657a77,bb383bf,aa71ef8d,d33990b9,9c2acab9,cb363792,9d249fc6,1c0931c,8a27dbfa,c8371574,52c40306,c3291814,ceb57095) -,S(4938cd76,e1aa6b28,2a89e883,8671e4e3,82d7bc76,dc4653c8,46323cd2,51d18542,2bfe67eb,6da39ea8,c8160621,158eac48,550c3730,664590a2,731247a1,399bc42f) -,S(9364dddd,dadbaa52,efc81971,75041c81,e7ebb48a,f20b82a8,125d85fb,a7fea192,ee568f7,53513b91,cf6720,2c45c4f4,181e855,ac0300bf,d7de30e7,317a6ea2) -,S(bdbc0937,243e563,df29781d,3b14d4ac,a664fe5e,70f3d9c1,39ef1b69,57839156,2a84b153,549c6d1b,27dd9ac2,1ab86f34,9ace0619,6f814d08,92a1958e,d137bb1f) -,S(b616b635,adf7b64c,43c4e242,32ffb330,bf28ee8e,48918093,9584c26c,28c82f2c,27fddaab,e5d47957,6344022b,68744822,eec7b937,d29b0631,93c7f6c5,6385cc89) -,S(55a3849a,50606886,abf6f0a6,5a3e657f,46031cd7,4c117365,8f27aa14,326f3cac,4a522c0c,17fcd116,61b11d9b,f88e0ad,c7a5761e,e01db8ff,a7bc3dca,a7976b00) -,S(d53e472b,439dc5dd,c8ff479,ff678dae,95b2e207,c92df108,728c3783,f8818542,3f3f7ecf,df3d9f89,1c723161,75a57931,4ebeadab,3c4dccf,bf2b834,c762d30f) -,S(1e27dd,f6186285,41f5d8a1,6587e2a4,ed38c34d,8393a6c9,fc0a7c07,cef36053,280b223,da8d01c2,12315c1c,ba7dd8d9,96d3202b,91c4eb4b,26c802e5,9494378c) -,S(b6d9d97c,64ba01fb,e8a9d29b,806d8a6,42413bfb,fbb4ae0c,10d8fe52,7ae6415d,894875dc,d912f8fa,845614de,a2b09796,d402c738,ca1f3c9e,c0796681,d715b8e4) -,S(2c97985a,5fd96164,e4c4d9d5,9a9fb52e,b2e6df0c,77ed4745,3dca6eac,7550756a,b3526bbd,de58e408,a4f45dd6,61f5c6fe,2f82d2ca,3e2172e1,c99d1fee,93d44c98) -,S(405deafb,528991e2,ef924f55,b7e4dfd8,185de449,cd6f71d6,53025999,4caae657,e959b7e,59cecac7,f813dc1b,a15bb71b,4a4832ca,54026e18,479d71d9,191c3ad) -,S(4276ecae,a14c0556,b4573b26,dba35226,4fff2c3d,12a3e4a8,4937ae9a,3f687bfa,7611836b,d3b335b,66f92914,6df0de13,d6ecd47e,88369ffb,6c9aa493,e67dfc71) -,S(6fd734de,6d2fadcb,d7b19f56,ae7153d9,1ddb396f,e0c1e51f,ae31fe80,8a35556f,aaa647c6,92865772,f31fdc1a,3b430ffb,e1647e10,3cd5d629,19bcc905,ff7ae633) -,S(4f0a22c,ad6ebf6c,e6b444dd,35a54e38,70017bae,eecc14cc,3f7ca88a,6d4e27c9,1386d40e,680060ca,bb46d678,d2be7209,418d6f72,d3917e20,7b833124,29b43ea1) -,S(873ccb39,5c10f57,6e50093d,44879f2,687d9321,441d8a7c,993c1083,ae7b0570,b261d029,dbe15f4,ff70ee42,36f558de,8984db4a,608d45f,4e28d001,e564c5e2) -,S(75d41857,5be3709c,5c732073,24f36089,b87532b8,e91db4e6,70a89117,9d25e039,47e29f54,fa62ef44,139db763,4b1c8f5c,e027b0d7,e1ec3501,1e8c6dfc,dcd1a105) -,S(b325bb90,cea81ac1,c79df75b,e7615ace,9b2a9d4c,fa1f4504,1a47e0d4,30b64b67,3024fffc,2005699d,5351615f,baee8c49,8a319a19,45ac8132,71c609b4,23e14a07) -,S(436c92bd,a6c7e124,5aaffb22,62036329,ddb8984e,624f2469,b30fab18,1269ee2b,2a9f90d,88c01880,62a152d7,e7ed5acd,33f12e92,4e36fab0,bc0602f8,2c1d3e3) -,S(c0105c64,4e51d333,c7ed28b3,c94292d8,6d9c04f1,89b3827d,f1f22fe2,99bc51cc,d73bc012,1233ba52,ef9727b3,1249babe,bf63cacf,ece0192b,5cbd618c,c48a9d35) -,S(9f2a01b0,46109d49,d11ee109,5e94c281,1cb6f76f,7773141f,632b3a9,2e5f3f7e,1e260290,fda1caa9,ea315380,781f633f,21c90765,2815251a,fa70b169,e4b0da58) -,S(4d805499,23dc1905,7fd35a86,feefb937,f2b621e,48946e53,b8390620,3aef584a,2cd9c060,d66be813,12a3fd9f,ebb9cbdd,4fc23431,c3e0531f,4a026f50,a40dbd30) -,S(76779423,b5e5acad,55137380,276c4033,a865ae5f,9ada0f30,dee6986c,444a1526,9a6fc30b,4f4c5093,b343c8d1,aa204ef3,7c2a6d5c,712ad8d6,39ef545d,1eaa9a57) -,S(1ccc1998,33f8b121,18227adc,2f27c3fe,8d328b26,684b271e,85f8368f,40378881,da21e917,94851bd5,a8859173,830ddd0e,988ffdd7,f7dcb263,f6755eab,e2d73f75) -,S(afeea14,e8306fb8,e69689a3,d12efe72,949b6b03,8c4cdc70,c95bc351,1f999030,cafbd04e,79378032,47c71954,d8c2a11f,d60e53b,35045507,8f6701ed,621e7d53) -,S(cefa268b,e551b02f,8fe50481,44920abc,3d03d97,3f2e9368,d2d2cb42,341c11b3,77440b02,64eb1972,91d2d69,ebdc1de7,66915a09,aa01615,e4001d62,7219d491) -,S(8625c163,58bfd43d,888ef97b,e33d9938,c62f7f2a,9e7b9735,26dd14ca,7c76abda,e1351920,59085272,3ea7b55f,49c4045e,2dda5ceb,c1a31841,1b6cf38b,b97bc1c4) -,S(43b8caf5,d4f72519,19630044,13bd459c,f5913edc,ff303fa6,dceb3412,f8e39c2,7d1df179,13186dc0,d7957f61,a3232180,21a6b50f,61a86f33,72623f5f,d3dc1a11) -,S(163fff8b,cece557b,6fd77b4d,e22e5b55,a6ed51a7,76dfe2b1,362040bc,9e7e4fe0,29204f73,5bc6428,3c510e0e,2192299a,7f6ed56d,1a0cc569,aa37f895,c0c4646a) -,S(fdbfcee1,69aa6724,b5839a55,e1c54856,86503b51,d1320b37,dcd9af73,2bfc4497,d7f75ba3,7af2f969,31bfa612,446c6807,a207af9a,17269199,77b0d71b,16b11a0e) -,S(f1981a9,aa585d6d,102b3a7d,e3509e0f,ed002866,b379b4e2,ba9d175e,4e5879ee,bad6366b,71a7cd67,163b6313,3dcd442d,24f9362e,5d0b9791,2a8dbfb5,74517e1a) -,S(dd3de17f,1cffd240,424096cf,effcaeee,87bf4d30,4a41d5db,6953102e,4b91853d,d136d363,1b9b968b,7c7d1a16,b2302e7a,7770e5ce,afae92a3,8f6e1299,6fb04718) -,S(b1d95fc1,4e35f77f,7e64f62a,36b26218,86397228,35ccadb8,39fa7d7b,834bdae3,75611c0a,920e0251,345b3213,422959c5,ac66c495,14d50c35,de7aa7ff,2a330a6d) -,S(1eeb92e6,75f25a35,9ed16c8b,51a5c130,d2210c35,ce954430,ea2cb3a3,af69187,cdefc1ac,40fac4de,e42ba496,eae80bc7,680e214,4117e6da,c2b3bc12,ce9eec45) -,S(aeef491a,fabae168,9d58c2f3,808b22fd,760e8607,c043c10b,591ed211,6fbb5ce9,b0db916,30810159,7e79aa7,82d8b643,d739bda2,c45ee36c,4f328108,4e55a33c) -,S(c56793cf,822c3da5,300c6c2d,cf06b5ef,413d51af,633ec77b,b9b68b1d,d3079e43,a423e25e,1eb466da,f521c5d1,6395805f,a2da609,fcfcffc1,2728add5,61eb2c0c) -,S(2aa824c3,c8c648eb,8bd0c151,b30452aa,c097bc38,a9f53db5,a8375631,25887e06,20aa4bfa,3bb2c5c2,a113299f,6c61102c,7586deaa,938a33f8,4a517dc,4ba78ada) -,S(4a0bb8dc,1833942d,9ae3428,ed493cb9,5716b50e,c96db120,c18ccac4,f6c3dd9,d0526d5d,c8be139f,53427e50,17cedc51,6b4960ac,bb98d4a4,f07fdf26,640b78b) -,S(2808616a,309b64c1,5d061adf,ae65711a,a561f8b8,345132e1,5b18fdb0,e476240,d2190f22,7320a55e,ad2dc736,671db631,9b18d6cc,b4d2bffc,cb4b692f,74eeaa0c) -,S(3dc4b015,13a95221,32ef431d,33435ba,8cf9e6d7,7e4ac75e,54848916,c23e7959,eaa2516b,9b13bc99,1f4b8ba,fa90a6dc,a007fea4,e26fbe0b,a2c5d1da,326d5420) -,S(473f6157,50af1d8,839ee0d0,eb5dfb8a,c14ce65a,e04e5f03,99fe8666,bd6efe6a,18d204d9,1b27527c,50823d5,222c4e4c,e3e193e5,a282daf2,75d2b43c,ffba8412) -,S(3b87175a,db1a5e49,1cf7565a,28250c51,9fff906b,ef0eecb,e8e50a7d,a190aaaf,fc58f2dd,16f1a5cf,1a728117,dcac3dbf,3a3963f,3859a518,2616b65b,59e96403) -,S(12f1b577,1410d1be,d0c4863,360e37d9,d36643d8,e0cf6fe7,8770478f,504174fa,be29140e,6b5a40a1,40559972,7e0727f8,ca904c3b,813897d2,bea089d9,dc2f17bf) -,S(8658f35b,902afb85,408280f2,3b4d98db,9526b57a,1e6cd0e9,37d8c629,ae174a3c,4060349d,47a69720,7d29e83,d8c82197,d32bb9ae,8c83879,1e09a7b7,1c3e7c28) -,S(530545eb,526d9657,2ce6cfc0,22e1c0a7,b9965c7c,3c2db355,cb5d414a,6c1ac8c7,99243b26,17f8ae2,898b96b4,1c3c65f9,96a9f8f5,83ff341c,671a2d5f,2d04637a) -,S(2e808732,bbab8507,e65936f3,fd1d1662,91ada8c4,c0d865ff,849e0a1a,5f08d265,96dbf7c9,53fd2f61,7e149f06,89b66431,88b091d5,1227a1a6,a0ebb140,18a79fdb) -,S(4272e028,b4b9c90c,44526fe6,b25f5e84,4b8baba6,34ceb2e2,33447413,cd5bb35a,6b4a4076,fc3706a7,50b0c824,93f5e363,f9fcdb64,9d683a1f,fc3bc2af,fc8470cc) -,S(78712f3,449d07ac,7f8171d5,42ee8b40,4761e054,eb0362c8,3b30cd52,6f9ac60,c7ff5ae1,38ca3c13,79457619,dd76061b,7b59778,79db2ca1,5b07ea47,7aa41bf7) -,S(be40166a,60ad9af2,d1bdfc7d,9b0660c1,640d4f1b,640ce485,8fb22eda,65d15a21,78c49afc,1d992bdc,b70bab6d,d3619305,a32fe90a,2f2b1b43,38d77c80,b208cf90) -,S(2fd5831e,6bd5a79b,35bc75f,92e83e4c,9acff5cf,61eaad7e,dacb149f,46d5e6ba,82f38222,4b6be0f2,f52318eb,7fe44a4c,4c0c1b05,8eae3f99,dbdea80f,a70ca3d0) -,S(32fc3fb,4574a651,472e0328,c15a71e3,bf9a12ca,15d341f1,c5102dab,2ee6de37,7e9398a6,760df809,e5eb57df,8fdc3234,eff1aa8,bef57008,c36e7953,c07f25a9) -,S(b9018d98,3452e952,7944f2fb,3354487d,a82f8b90,e52689d4,edb2a91a,a8faa6bf,e9cd0e4e,5c5efcbf,9ca25cf9,f271f9c,a2c46b4a,322cc966,e7789607,324348f8) -,S(a74ba662,32afb3e7,d5c22ad1,c792da33,f1bc88dc,244a8ce5,d4d582bb,b16ced23,444c5512,b49c2c63,4cc0328d,20f7321,a88db1ee,6d525be3,5d2de8df,cc381377) -,S(40f6df83,6d5e8c94,332174e2,2fa43556,d06f48a8,f52cfd69,820c2c46,2185dbfa,852c5b98,15ba4ef0,18f5d231,195fb62d,afafc08d,fbf9159a,eb5f6063,ca353424) -,S(e05800f5,f7890a14,6bbbabb1,27924cc2,e33e3c81,eb88606c,6bca020f,1aa71747,ab905ec6,3af1bc11,897a44e,89c2c2a8,3fb7255,c0e7f76e,8378e59f,1289158f) -,S(7b75dff9,a1afde87,be8528f7,9df63d70,e4df925b,a15f01c5,8e8162f0,89ee735e,bc057ff8,bdc9e37f,554a6ad2,3ebfeb2e,5d64adb7,69fa0082,2b2d4902,ca82712e) -,S(2fb81423,3b01e312,7ceabacd,a9ca518e,b1ab993c,bff855a5,20a96f52,afa9a0cf,a7e4bc57,b53affba,9e2cd875,9665cd9,215fcc,35dfc402,4d1db86b,9605c4b7) -,S(f346a33a,ec17d0e6,a10262f2,fd8185eb,f80a1fbb,f6b06bdd,1c04f18d,75dbaaeb,c09caf81,120586fc,33a6a0bc,97ef5cc7,56d20806,1340a1cc,ba9955ff,4a059e10) -,S(d128544f,a5f5dd38,62a759b8,5d538baa,63d112e2,f8c343a1,1bb3b8bb,ebf548d8,7893faee,b73f0530,bb67e8e0,9c2806d7,e303dd5e,116bc9e5,93e4dcdb,eac031f8) -,S(69046ec4,11c06822,59de20b1,a2a8f84c,58c56765,2ddcae,a26f533a,9c706f43,c17a9640,adc07d61,4a264ffe,272cd686,99b9af9f,6890cdc9,ac02c761,637dda8a) -,S(7b50f61a,9dd7b9ef,7af49c17,6ca5555f,eadf3b67,90998365,29379dd2,a3c85b5b,c08e18cc,bea8a970,7bc34d98,6b36475e,e2e24695,2304df65,bbe0347b,6052416) -,S(794a9728,9db4743e,c91a8560,e430b14,a7d8312,1fbacfbd,ec37a9bd,c749d3f,c57a5b9a,f0cb23a3,5e9b092f,386cda86,bf2f8242,1f74dfa1,837047c3,ae0d2235) -,S(fd8d1485,3d2fa064,c4682ee1,1c319a8a,49fa9b23,2cde9d1a,9a44b2dc,93b2f251,8cc4001d,f0121ce0,ad2119d1,7aaba363,ec45345,87fa10b0,c94a5043,f641b91c) -,S(7b5fbad,8105fe06,6962a72e,39a9a4fb,fac27794,e39a6660,133b9ef4,a6877557,b9b4c9c,1200d879,6013de67,958176c6,dc04ef69,b1021057,de8d3b40,564fbcd3) -,S(2c7ffc8b,40eda03e,20e64678,68959141,c66f01e8,b7cb050d,c60e8a48,6f6e41f9,cd0f3510,39aed3c1,56ae2b0d,1a117f78,c14a704c,992db297,60d22700,2f71ff7a) -,S(79533078,d81a6fe8,446dd750,b59ecdc3,8904f13b,48ca89a6,5644aa8c,9233de64,d7c95bff,77fa9894,74634aab,3b8f86e0,ee0bf92a,3a338fb7,f89881e6,e1fd746) -,S(be96c5e5,d3fb03a1,801a7760,16bf3824,aa16010e,884359b,d5e30658,5f13b214,d156346f,158d0c1a,2ef96a95,86cd8d34,20be21de,6997904,8299744,b40a5d9f) -,S(165c53d1,9ac89139,c063d934,511478aa,bc296cb9,7201dbca,fea4cac2,16a4fa02,4b002644,1e6f1369,d3603780,f33f74e8,42a812d8,b4e7ff7a,4aeea468,35f67348) -,S(508fb72e,dbd27f3c,76569185,a18af8bc,6242462e,cecffffb,3352ce3a,da5ccb5e,e1698f3e,1d53607b,4911423a,f2167466,a473a8f1,e2226849,f4dfe551,dfd14652) -,S(e9be0fb7,8e95dc1c,7b79f4eb,7976367,a85034ce,ea8642cb,19106dad,1d10ab92,b7867a7f,51f89779,a32a7b8e,273f9659,fb84367b,90ca3ff6,afc2cdac,7f596c45) -,S(e6ea5e6f,97116554,2de16c66,1f15d6e1,24aa449e,960b393a,e5337de1,d4c94800,bbd62bdd,1c235fea,60be143a,9155ffa8,204a1b11,3f19f4e,6e683c7d,e234ca7e) -,S(ab3f8a0,5b8f5ff4,149a390b,a858092c,9653d159,6d84bbc5,6e4a7a8b,fd54d7e8,41008916,311de07b,16c1b49,c6aa65ed,8baaebf,7a4e75b1,5aa1bc34,37483e53) -,S(515e02e9,52a347e7,5e0c5eed,a266242b,48bf33d0,70048562,c20feb3f,aecea1e3,797b3ef8,f6c35440,58517c56,ef5c6464,fcb63353,2bd6d2e2,83487a1d,8a403b36) -,S(520cf598,b3552fe0,a42438f8,55aefb81,3a3e10d3,f4985998,492e06a2,42ef46e1,c69de50e,2bf9658a,40567066,3cac0e4,8c8d2920,95ac1df9,9535b7e9,209324ed) -,S(26a8e655,4a2cf338,33bd27fb,d96880bc,bcc1d360,2a76920c,37075790,1c50bb1a,ba5a4560,5ddc5236,2a0d09df,3247a507,9c87e652,c4ad35f2,e19ecc9e,ec1ae4af) -,S(bd06a5a2,362ac91a,759dc578,dff3a3f8,102a67ae,a86ac11,5ddb2e14,bc1bba44,e8751dd7,153537ca,eec17988,98337cd2,abdfa554,52c597c8,61c364dd,78f49de7) -,S(ddbccf92,da0ab07a,e99fda1f,4a03927d,66b0bd21,f1e54fc5,afd4f329,35a0cae7,26fc18c1,52755bc5,d68dc3f2,461d60ee,b4dfc02e,a04b4779,6e7725b1,23acf8dd) -,S(650e1616,2a30c776,b54130c9,9fbbf567,32e2bdde,f667b09b,9b7f25ed,93c0737c,14972f76,429eb04c,1ebb0583,8c54fa0d,309fee09,a55d7eb3,700be0df,5801d56b) -,S(2920d280,41ad7365,cc0e33c8,7a3d6f3c,f9fec9c3,b00e5698,55ae3b83,8cf08973,3821fdd1,fe36668e,16f2cbd0,b2704fbc,24354f08,8ba19a1f,67d1b11a,b70c2d68) -,S(3842fb0f,1b26bfe7,535c9f5b,cee85ba5,6cd491dc,346829a2,a178ce65,c5294302,8e02342a,cb0e1233,9e638018,a125622c,5f66ab52,86a74a6c,28982c25,aa3a0fe2) -,S(9c21d89f,f1142d24,1e62c1df,e0481268,c2273d01,f153af5c,d31b3514,5b9b41ac,f5a924a1,d60e1eb3,72837535,4e252740,593c96f4,87328e9e,2a80cae,15fabdb) -,S(59320ba5,c9088701,f354a3a1,93391880,2829ce91,be9b4c14,c9018fe6,4fcd387a,610e48aa,705e2e7f,86a6a12a,817984a1,7bc60f9b,abc0ba9f,775f3446,8e3f3815) -,S(d800691f,83c2903b,1add209b,35d796e7,15b805a0,9bbe6120,3bf68a08,a13c46e5,21d194ed,bcb8bea0,cc35a9f2,328f1689,cdacc58a,73f65a28,56811e54,d96e5576) -,S(865588f8,66c21986,7b9643d8,7f1215fb,90fe186f,46478e8,522a5da6,724f6e8f,91a6b315,a7ddca8d,b4ecfbc3,9b55eb81,393f4c51,f573fef6,e7ca0c9f,cc551e7d) -,S(9dfe808f,cf7f574a,ddb251c0,4b053d00,8915f8fa,5a975479,d43c719a,b67aa4ad,4d40cc00,ea6720db,ff1f1339,7bb26c0b,281686a8,726fa430,bce0e4e4,ff01b01d) -,S(835f1c87,cf8d4420,72728601,ab6aef63,cd0d73a1,80f81f07,f5d57cc6,bab5ef7d,bac2d1d4,c8541f65,be0644c9,40a18f7f,d2c30360,2083a455,4d70a111,1c5bf07c) -,S(9562dc71,33c48e4,b46d73ac,d42db4c0,b0222c4d,dcd0e76e,b4f84969,348fa46,7cfe0965,96f691de,d358c00e,a292975d,465ef064,e9437556,40bc1d4a,33c3a0ba) -,S(21afe3b9,4237473c,dc032588,c4c1b7ec,853987a6,dcd1fce,2c48bbb6,8d0f3b45,1751c5ef,674cf88d,d5385943,b40a20a4,6d20cbd3,9876adc4,a4a4bba8,477e78a7) -,S(89809c4d,572cc5c1,2241ae09,fe1cee6f,71aaa292,c9ff8d6e,c3eb8a92,8e144ebe,462c023e,1710ed77,bd47d22e,e222598c,68cd7c56,b004369,a9356a47,ed6809d) -,S(b7c6164f,b9e175c1,5724c596,988b496a,b9f5b0d9,dd45d0e6,4a0f08cb,9000e3e9,1a13e8e5,a23b40a0,aba44bad,5cb4d37d,a6061157,aeab7a0d,d327242,ab2ad11f) -,S(62088450,24eef2d5,4fabe8f8,fabf519,72908ac3,23596378,c377c458,9719bba8,26216b3,a353295e,a1877547,b826c240,351f227e,293abcd2,e3967fed,30391f5a) -,S(dcfe82df,4049089,f3f8b275,120ca438,998fb22f,e11d40e0,9d09c4ce,c12ad036,388f9754,39b1c412,10014136,c3b58fe3,30ab524d,d7d3524b,37ce9133,5cb3bf3f) -,S(324ec5b0,12de7919,2f27f5ed,166344e1,934b3527,2b197d28,9a634044,5dd4bce1,99944794,579e12e8,c5c0c11f,a8eae5f1,88cb8cdb,3ce7814c,f89e3f1b,a3d3de0f) -,S(b3a70b0f,af96cb56,7dc4245,13ab7c6c,bbc38634,faa0c286,b81b9754,454a363f,b507745b,97843c90,170f8ffb,f731fee8,4532c1d0,6b2a077c,2aba5d94,189545ed) -,S(c4a6ff4e,cdf1ac83,29a1cdb7,b5165d88,2a1f1823,d1c38006,1b53144f,56187fce,6f7d0fc0,c08a7ba7,386f9a59,330996ef,b13d9d21,eb6d3915,4c8fb919,66159919) -,S(61d9ee96,1ef58634,5c4a73e3,a8c3df82,eac28aa2,6d740cbe,1833dcf6,d5a38811,c9e4a482,1700107,f2d4af3d,fcc74e68,8123b589,4da1c2bb,1fd926e7,11330892) -,S(67ecbd0f,4f4fe300,49390655,5289c9a5,cb6ac090,dff38502,75f7751,a84c6172,e422b1dd,10467cfe,921028f6,71cc75cd,2be5d8a6,75e644e5,d3c40b3a,2836726d) -,S(47f6c669,70898fa8,16dcd4d7,4553c644,2ce5bbe9,cda91324,ee3bba7a,868ff0f7,e56b9590,838bdfaa,1c2be1c3,95f775e,4a0b3982,d0eee531,26ec7ddc,9e3f77a6) -,S(e39ec9af,c8dccd35,4b155dd3,1d1750cb,ab096807,f89c8afc,fe61e6d2,e348cfa3,df3fca08,99158319,b93bac62,88c302f8,a59e175a,cda9fbf7,6f0ad59,8358088) -,S(2d1aae84,500037f9,8e08b64,341eab03,e0f1cdf,5a079b46,738746c2,18b3a0,747c23ac,8173adcc,de767d2e,ac156384,ddf40797,131a6167,c32486aa,12c89e5) -,S(ed1bbf04,d4570df5,8f584158,1fc47665,481ebf59,cb88322e,497d128a,678c2b4a,a40765c4,772da2d0,b3c8f107,22ec3931,ab3fc8cc,c28b003c,bea1a0da,279c8fba) -,S(bcbc3e1f,7bd268,93f377b2,eee4b76d,49a8a603,738de309,5353fde3,deff55f3,fb697a08,2f2570bd,1e9e4ec3,fc7f6c81,2a27a7e6,f7b8a53e,30da80ef,f59ef2cc) -,S(4f98b2d9,2f0b5d57,51ed3784,94cf4de5,65cf632e,982a270b,2746a5a6,3da9333d,43857e7e,437bdc02,6dcdbe68,d056784f,a2cc606d,7ce09a0e,12978a74,5b67e529) -,S(9dbb995d,d0667371,1731bf05,c8029035,2b413411,45318de8,2236df5c,87728582,c0a90e4c,6fbc0665,f8cd9fb6,fd59ea3e,f6ae9a16,9bfb71fc,5fe73e3a,4d665f86) -,S(83692208,1d099344,3d979c51,90940e44,5465624d,3a945c05,7885cd00,5ce6b9e,49be5e40,2e1d05e0,67b16279,855bc1de,6f0d8aad,35d8bc0e,142dbe87,33a14e13) -,S(f713e920,7a699b68,12d7ee9d,1475ba85,a6c56af2,8b73ace7,cf67ed6b,55650e97,a5a2c2a2,45012812,29fc71c8,103db717,48a51f88,61765d31,4b9ec278,3d0aab45) -,S(919f2d21,256ae682,fe514320,9c6551cc,d165de1b,8213fdbc,9c06578d,ef705725,9780da96,eeaac4e8,c96f3d6a,89c222cc,9b16b4c2,e8faad4d,96cc0136,a06021d3) -,S(1738093d,197a5ce3,cedd1fa7,e2a8ff03,959a6c23,6aedf9e8,9dbd74c4,d82b6e48,74363112,d16b829,d371a0c,f1b3bcd1,2000254e,196ea80c,a9d46570,1ee4a1d8) -,S(41242a81,35811b36,d4ffc40d,bbdeaa7c,cce36135,3c4fc9f2,d23191a4,b9c46379,7b894326,789f3071,374983c7,cd2a5ad7,e0ee49c5,e740dd33,817a31ed,97c388ba) -,S(894a6ec9,96eaa8e0,9e077b34,7b4f1e1,a387c930,a526c469,aaefc0c5,402d41a,a080fb43,c8e6bc6,388fa766,2398e096,b65032e8,26c5a9a8,47793924,4dcf5e41) -,S(a71f2131,3599cb7e,8c1058c9,52a5712e,661d01d5,79bc7ee5,1fbadd35,34ca5d5f,afe5b47b,663ebd7c,d788e0f,d3f963c9,ac63ee24,b7495e61,4a5d6553,9ab5f859) -,S(8f330e77,82eb62e4,4ea389f5,7f1c58b3,458c5d39,127d9783,6ddef8c1,27fa390,894e6142,bc359171,999489e1,1ed08224,4a46100,136fba84,e2b8732,e9bb626b) -,S(d2f0700d,6124c46f,a64cb709,1181cea9,34fe0406,21267334,c85ace2,cf05fc6f,8dc30ae9,83a95b74,2d800490,fbd8c290,bda64daf,f82d8fa5,e69243cb,43556cb4) -,S(c2478e89,8c075873,ba6cd5e9,6a730e1c,b6ade2f2,7fc9e7ec,93da9201,63f88c32,c6412063,9921d8c5,77dced53,76907410,82b1b4ff,4434bd,9a55b6c,8591ed5c) -,S(c5bc11a3,4e701898,d22e2920,2806c880,b24efa7a,c6d4ee36,cd440386,e4463a10,2c2b89fc,48feefc8,8bcb4ef5,68d16b44,cd7d8c7,485c9703,91c1c243,bf91003e) -,S(4b3930e8,21827b05,8c487bd2,fefa3458,6d0d3f20,5a2236fe,1b735d63,ac8c62b9,c38a29ad,c9b9941d,dc92a0db,4ce5f312,252c1f66,8a3189c5,595a371,19321c6c) -,S(fc646e3c,eab5a96a,1785da2b,1b50f7db,f0515091,76ade1f5,b057d05f,3aa3b8fe,b2014537,dbf2637d,6f683fb1,6af00d5c,63d4ed59,cdbdd673,f3bfbd48,e9574dd5) -,S(c0ada793,e2d9ed24,8ce307da,a6bebffd,3df2fc27,d2001dd4,5dbfc7be,c5f97a0c,6f3a787e,d40f073b,4965d52c,40700f66,da93f679,9efceafb,4894788f,5c9c7fd7) -,S(b1a45f3d,f2d45a,e21e43af,31ec3159,e8877d91,3efea814,b66f6fa4,a227b157,d988122a,eab167b9,f89db9e2,dd82405b,404f8a9c,a9acfd29,81c8bfa4,273ed248) -,S(4e19b9e2,ad3e421f,1b85a174,89d8841f,65672fad,9a17ad70,ca4fcd12,716d7a68,51412d39,59b158c1,3905c267,f5cf66e2,364aeb8,b66a11fd,ea6f5471,35db6dcd) -,S(533ee2b1,379a6ddd,6e5b3a2a,3a197e7d,eece722d,5c5b9c66,5e1be9dc,f3c09adc,b91b7477,fd0eabdd,bdc4047a,9bcad0cd,9da8496e,bd328fa3,a3ab20a6,3508a6d9) -,S(ccdb933a,816ac55e,c8fb97e1,504fa512,67408fd3,77aeeaf9,565ab66c,a2033b94,20299202,99b57beb,5d3817f5,26aae569,b490b24c,d5834dbe,8b05e8bc,89110de4) -,S(770d7c72,2e9964d6,84dead28,328b1925,287184b4,6e3abbdc,534eb87a,e0ea5873,363c73a7,bbb9b2af,3c0cc91,6f8ffe74,837a99c8,58b5464c,9f253764,e4a78285) -,S(d440dafd,b1d0609f,7c2354d5,74e711cf,852b364,8827fd41,88228ca5,98f71eeb,57d438de,c1aa78b7,c872cae5,c6803a2c,9844809c,7bca1a54,1be6f779,893aae1c) -,S(1602ca76,35ee0795,4fed3cea,d3e54470,41033887,2f060e19,990f3cd3,501b951e,1ea7f857,4b72d3e2,bd45fe36,c828f18a,5810812f,ab6e0936,a7854ed7,c7e32bd6) -,S(9c4d2a24,e4ad8226,bccab8ee,96960b1b,4722d2a1,88a429ad,f9d194ca,6687f7e,e3a4b46f,bf608018,ada2383,5c70fbe,cabbd446,78c9e5c1,35e91138,7d66b01b) -,S(fdf84be7,5be40fa8,db537848,e2fc8ba2,b7c58824,74fea4f4,6e8fcf15,f33d3bb1,2af57dd8,60ba0e6c,dc3606a9,a902420f,9283f721,70ce32d8,39c33673,5da1ff77) -,S(6083a785,fc5aedbf,34615139,e2f97964,ef65d254,a38251ba,203f8ea0,26eea81c,bb4d48bb,894fb656,22cd752f,6e3bc6e7,670a4bd2,64675035,8481561a,2c18439c) -,S(e03ad08e,5b4b9e01,5103e028,668f09a2,7d2f5254,25c6a985,6dfee667,6afffb82,f53acd57,1ab23ddb,d6b104b8,71d957c7,f254bc40,c37017ad,f7350e18,7a24865b) -,S(5a382a4c,88656b6c,4a5c8dcf,4052b1c0,a0bbc0a9,86289ab0,e212fd24,b852d9bc,912caa9a,32a10900,eadd0eec,423f710a,3e0aaba7,93f7b675,912223a2,6ba14f31) -,S(37dd526a,b5392b03,3bd05ff9,3952a31c,7bb0cfe1,f02f4f57,3b8d0ef0,c05d5ec0,7e329228,36595c82,14c8a776,15482931,98966225,4d4315c,c236c156,254e3249) -,S(ed4460f9,cd4bc957,aca653a0,5b6f0935,9dd7e19a,6d65c60,ca585ea3,ee2e1263,733af30e,6edd2b2b,317bba97,d24abd7e,41af6256,e7353f97,58357ff4,1a701829) -,S(eb01d9cd,50ff4778,b29e5096,93388ee1,12cfbc35,2c1b1382,7b3195e7,44a3bc3a,24877b7,99b7a2c9,db23047a,3194e9cb,91e5dd50,d0f1e252,b6f3bfca,f5b4d110) -,S(9fcfa274,b180ce82,14624545,22bb9289,1e0a8fc9,71949bfe,7aa25cde,88dc284e,6787be0a,12a76a23,9de45596,2a11f7f4,4051fbbe,3ba7dfb3,996c60ee,97be2b9) -,S(c8a0d869,87a7a854,99bd5663,30a07d67,70265d8e,cd3286ce,c9be4d02,6145bff,a65c64e4,af865e6a,893e902b,b06c43d6,10bb8181,134a4b71,d136b5fd,f42982a8) -,S(374294c5,932d3f74,a6e74731,6c6a84ca,dfda6d35,5edd914b,70b26161,50628735,ac47d048,8433754e,3deb79c6,7056d828,14d73bdd,703b299a,ca910180,e518672f) -,S(baa9e3a6,2b4bf099,1fde27ad,4b043b50,76a184cb,4f9a6da9,9b56ecd8,a2ab99e5,1e8e836f,f76043c2,c187ee45,7138cf3a,270e2d3f,5bc96979,c12c34cf,9205c63d) -,S(72f85ea,784a5ef1,71516c22,13abca1e,8017db34,4e00b397,4cb509de,a124654d,c78ec627,6cbc5072,fd75b28c,8d395f13,e84731f,7767448d,e06c0ba7,372968bf) -,S(c9173d63,bf5a1301,f0750b1d,e3cb7061,bb9cdd36,296b422e,d23513d1,10b61903,d26a6a0a,ceef78eb,73c6b031,a5455d2c,2a9c4ab2,d916b7cc,7b8e627d,6d581c56) -,S(865ff86a,58fb9853,8bcfe496,26c0bb89,e419083d,f21dbf6a,7b13e041,d5cd3f18,f0bdbabb,8118de57,bce9a90c,83529ec8,abfc2812,ab0088d2,8ade4bde,fe2fa383) -,S(3f14eb28,fd9852c9,bf4d4497,4d794ef1,c30f7748,5c7bb766,6f32fcb5,5ad910ad,e982971b,ec014b05,a9b5657c,a0bf45b7,adfe19d,22726075,80b42eeb,f4dc5217) -,S(61dfae27,c7bb68a1,ede331c,6499a7ed,e242457a,77e5a606,cea82e9f,f450d01,973739f2,c1e4ff77,cae3cf59,b481e730,5ebe8196,c5b62b9d,a96ae224,9b83efa7) -,S(e319690b,e944c297,f7c1bc1f,462ac3b5,a74fb913,9b963384,ac11046f,4343883a,3dadda66,538ea9c8,8fa0c02f,208ede8a,b6ef3480,82af4a32,2ddb5fa7,96d2efeb) -,S(f3db5e84,a9015b39,1617fea6,58143553,baa1975a,ab017012,38dc4243,7d9eaf9b,df55628b,c50cb2b1,be2ef193,a7f90e6a,3bfef4ac,63aaeee7,39907906,547d8b62) -,S(83a7dcd,58742725,8d17657c,ec64b5ed,4807db49,911296e7,10cf349d,c4fc709f,e5201a27,c37cca5f,2f7bf74a,fe000c0f,56643a5b,bafe9f91,de181e74,1d327183) -,S(b95b2363,28f51c80,b376dd90,a0f92d08,1e395132,deaa8f42,c142f642,3d3611ee,c111a08c,a6dbccad,2e784498,22816422,f2200f6b,bb24842a,f96c9502,13479f55) -,S(c3ff0645,921f2b9b,2fe590de,dfbac094,8475bdfc,a6446177,6422cca5,6fb549e6,e07ecccb,4b972834,e2711423,c0fba72f,eb0bb7c0,71a9e206,bf7715f2,62f03e04) -,S(96a37acc,527ee163,51c46241,1df94da3,eb0229b8,6a6e34d0,234bdcb0,5313c10a,46014617,fdd3f8b3,a67269d5,20a49680,9e5fa57e,76da4ef3,59ef862a,c58380c) -,S(b135c091,ec98a07d,b624fe48,4d336b85,62facf81,50346e2d,d0be2cfd,618d1e0e,24456a71,e8f2cc29,19f53594,6d7aaa79,e3d7dcfb,4af2feb5,ea0a2ad3,a23ec070) -,S(71d26219,81730b69,b0411b1c,f553c81,6f35a34,e09d086c,4500ba,94812017,c25357f,8915a2c4,98fe0d60,ca979ecd,8bd7ded3,ad6bc9ad,262db1d2,c3d3e7be) -,S(363cae8,ab2259ee,80283084,d98dc16,60c0934,68e3e854,dd86d9a0,d5e97884,756c60f7,c5e113d8,6e92df38,8fc9a1a2,a4889d86,f7440429,7661365a,ccfd8ce8) -,S(aef32d83,81ba3804,6e5b3305,6764ce3a,726c4e5a,ea61a17,ac114599,63f36247,dea5fc8b,d4ceba19,89640462,a957a8a7,44ca42d6,901716a,734e6f87,9aadb81e) -,S(65980f89,e4d0e342,d4b4fcf5,228692c0,9ebfed11,52d951c7,80963e6f,8c81313e,2d594cdd,a1f0b9db,7b3d8815,f7402a06,acba8e31,b9b0c597,8d2118a2,5dffa75d) -,S(f979280d,7e35cce4,8b9372cd,f73cebe3,6ee08388,e98e6069,fbeeb168,52329433,9181e8aa,bf7d4723,4cb851d5,6b3ca08,8c5f31eb,6b1b8c7,2879cfba,bd3ecaac) -,S(3b9f877e,286a13c8,a8463db3,b306ad62,c152065c,6708bbd5,68931e8a,2deb537f,12436d2a,5269a319,4f605dc1,4a34fcb0,445be9f4,5cc2bdc1,b96d86e8,b9465631) -,S(f2c70f82,1f86e94d,426e3e3c,e31ee519,f5a95b6f,38b663ae,9a6aba4e,f7bdc4e5,dc534655,4ba850bc,fef2485d,51e08c3,ab546119,49fee2ee,4dfc4e09,ff203b44) -,S(e2fb481,da8a356a,ab82098a,f622db2d,6f0a4349,2428dbac,922c1350,65801f15,5f735bb5,bb805980,d85ae242,4855bb2d,5de0c1f5,5018e1a8,e65bc2f4,86b7742d) -,S(d99e2001,33cf632a,f66c382e,d8ef862a,17092764,2c8f1f40,bd3d7bb,f0070324,d00f12db,cdb6e1ed,d190a754,fcbefdec,ee459be4,d5a46d69,afd6cbf8,4a4d30f2) -,S(dd765b6b,cb2dd356,f5965a8d,38108610,688fedc,eb3ce48d,352b095b,aa0daa,636258b3,58171669,f0dc68bd,3dff2a6d,bea6e5ef,20060913,66b12082,e2d7fa0) -,S(f549c14,f099a957,6267ad6c,3adc985b,9d0626b7,3f1f5849,d64ceb1e,266a9965,45a17dc8,30118c3d,28e73a3c,3d026afc,29ecf50d,198afdab,dff3d130,8f32f3d3) -,S(20d80860,90a192a8,51eddb84,f79b2882,ad7ce8a0,9374b365,61e6da34,427e8226,b48b6947,9febc104,880aa8b4,17344206,b19dd720,e5392bac,7e1954d4,a341eec1) -,S(b9f383ff,2545078a,c22cf9cb,83fc9e00,e9d37f30,e03ae03,5694437d,c1de2d7f,14f8b209,d1128a44,20dfb93d,3dc9ccb6,7ed22dd8,ecf5a181,2cd687dd,64a2996b) -,S(2ba0e5b,cec7a4f0,c6edd1c8,2d2f5927,2d97f4dc,3ecf353,8d3854aa,8d6f9739,8b10b217,6e56e5e6,5b99a617,eb71da00,3bee99af,b80e5ef7,3ca8c332,5ca7a75f) -,S(28b45a0f,3c308ecd,c0f7beca,c62d42b,500b704a,9af39931,b8debae8,8cef27e,9a3f95d,a17888ac,19eb4e42,1279c400,a60a0c1f,70a11696,4cf6943,9fc858d8) -,S(d8993bb9,e73af10,26ab41f0,9ec5adf7,437ce08a,4295cccb,283657f0,7a9ca3a5,ad8930d7,817534b1,e8407db9,bb8a608f,538b2bc6,9827a234,743382b,4381ddbd) -,S(77cd88a1,76bfed38,d7dd7152,32e2554a,a644b79,64a85f86,dbd6ffc6,69714e82,4394630a,42436802,1d0a0681,87fcc6a4,dfee0fe3,6db3bf2f,dac6fc58,34faccf5) -,S(d2557185,9c0fd15f,1f3666d3,aba99e38,89419099,ce7be94a,81ca1045,158f2da,90e94d6e,ac00b9d9,19832505,75bb2f,3242e7fb,fb429dc2,a90e3231,d1316cf0) -,S(f4e26c7d,4ccd80e2,7620917a,fdc72ca,94178f54,547eb330,77baa95c,d92a981e,c8ff014d,a388dcc4,c634304b,5973b274,785927e6,190c5557,773b9a0b,ef7d7005) -,S(da3a12a9,50dcd18d,c9e531e9,86f85a53,e7ce5bb8,8f2b5869,9830c44d,8c14cba2,7380a5b8,c01209e9,a1face4d,798f63ad,519a67fe,6bc90511,c763ca19,7e8c6b41) -,S(3565fae0,daf5d9ef,609bede3,6e19417a,45d8c0d2,59163f71,b4d9f54,43756fcc,7b1ef713,a88f9965,be7e6799,4a936960,c44f67ae,d5fa798d,8c0286af,e9da257c) -,S(6683fb20,d435a139,bd08c35f,adcc8aa5,8fbb8f48,7f9576d1,6f41d086,3a4e3de6,6a969f08,566afbc,dc98abfc,9d0d4d54,5076ebaf,efc9b966,957f1dd0,af52209f) -,S(900de92c,cbd4528f,57a72013,77dc1b51,7af67416,1013a20b,30d356bf,e011f508,cb55db4c,8799575d,9dea64f6,9fdf081d,959210eb,32b26bee,b903bf0b,80264c60) -,S(9d84bcf8,1be8a9f5,df2c6e80,d1b5679e,476e39c5,c30351ef,dc6b0b41,61c17613,8aa0cee8,cbc22e60,b71d9066,3533c2cc,a02b8d7f,7df93ce9,897154c6,2fae046d) -,S(6280fba,a3c3c8e4,4fcf0f55,a783eea5,2ebda748,501730de,71781be,abadd211,45b74c18,f0c18d3b,76cc1089,8741246b,202fd272,cdd0e866,5e1f4d86,ee527f5a) -,S(a4237add,7a5ea66e,8a1b48cd,7d5ef195,d90f25e5,6f2f148c,6d4eeff1,805b9024,d512d16e,632bd9ce,6cb1b2d4,c9a41e36,f9a2b83e,73fc8631,1e4dfa1b,b3bf71af) -,S(51effda3,e84027a,47afb48e,dc5c1937,9a685a24,ded2998c,c2b74422,b1e83fe0,346a9d82,cc07ed91,d785c6f0,dc32b62,e3e7877a,892007cf,c015444e,46001f19) -,S(87ac6bee,837ce155,29c005a1,6eca4540,de1480b6,91bc0ed8,90fed51c,de923cf4,9a9aa52f,1be1a33b,7280d0a7,3c19f5c5,b6baf99d,3c9c2d54,4a8d9bf3,a25ceb71) -,S(c8fd7df6,a3b0c0e2,5a931146,72a0af1a,1f995f1a,109e6e83,10b0d433,5dc2666a,3a853149,9b28c2ee,b5baf17d,dba8f57,3cf6e269,f4f21b1e,72bf38c7,79d239c4) -,S(890f9eed,47126c8a,355658f9,296b1845,b142eb17,4c2270d2,46293ba2,997e5a54,f294c38a,1c929ba4,2a9234d3,249690d,10a990cc,137bda3c,ada4b3,6d4e4b79) -,S(9329dbcf,45adc298,65c8defb,ee2ce008,a3474855,39826516,b417b9d3,bd47c86a,469a6cde,e1b0c094,f536fa91,f7617890,1be77c00,896efc5d,94cdd787,3886959f) -,S(6fa5326e,7b161c7c,742188d1,c47263a8,2f1f78e1,df83c664,2546c9ac,70660332,86cfd636,11879179,16d51a4,eac57709,5b8abab2,1024ce5d,35d64b4c,78559375) -,S(ece2e23b,8915d7fd,dab9e58e,8489b053,24eb1485,d18eff66,ee5013ac,3e0556aa,6a94e4cb,8fdf0549,a01621b4,438c2757,fe9753f5,13dcbb35,5655f9b2,ebaaea58) -,S(891b613f,413c155b,c2dedaf9,96d75e1b,54a5b5b0,3705808c,f575cdf,1f697ced,11904787,c1fb6f8f,8856aeb9,f7e05bae,f599b78,d7450bf9,13288e95,ff3f871f) -,S(b7bd8742,d1af6cb2,9b55a307,dd3c0318,6923be55,78ba2797,e38a7154,8d6231c,269e9a33,7a9421b4,cf45938,1961b0a4,3e4a0f6d,f6a0f10,2d7a831a,d7d4cd3f) -,S(7c6f5db3,1620a83f,b4388d45,75d244ca,1f38a0d8,611300b5,d4fdc9c4,34a16432,d5c0c35b,e4a371b0,3b85214e,f5e472de,e6c8175a,b140f05f,6e52b766,aa313f7a) -,S(18d303bb,d2bd6f9b,7f941879,6a23fbea,5ece2078,982064a5,e040c95f,c534ad3b,76eaa3dd,b73af546,7b1862c5,7b4385a0,28b03b7c,66729fce,94885373,1ed2dccc) -,S(31c0daf3,31aa6248,de302243,a768aac0,c8e27da2,c2b8e0a8,7fd74214,b49bb78b,e8e1f975,b77550bc,d404631b,12c72d38,55d3bf5e,5477a588,b11d57e0,e71e1ebe) -,S(940aa62e,e3bff798,327e806,b644a972,fae9eb09,dffb8394,61b080b4,708f715d,2853e12d,56898ea6,8e922497,3660a29b,37ec41c7,339b8059,2075c7a,2836c1b5) -,S(66db37fe,3bcfd7bb,25ca4a1f,b2ee09df,5c748061,1c3a6fb5,d0f079dc,cdbf9b7a,a6d37fd5,5d58ee33,73898711,69794421,9cd7a2f3,3becc8fe,761bcf83,ce603b9a) -,S(fb04bfa,a93a8ed9,3d755351,98895c8f,e90d545f,8eb1d08d,5d7282bc,66026e3f,e77f3c9e,afa2791,b4db2f69,3438d051,47edc983,a8541296,a8cae9a2,174e03b5) -,S(5792afeb,7766365d,e6b36beb,aafde8a1,8e556ac4,207965d7,9e18c1ca,63465c78,95fa5ad4,4b93db96,2c26d740,d2aa582d,da19b761,480ecadc,212452ef,cd885b40) -,S(186c0feb,6298e341,a2440465,547ad137,c56593dd,ed82b608,6824097f,3f83f8eb,b3b58cce,8375d9a1,e63500d,141feec1,38778c46,4be1ad43,7c63256f,33ac3b6c) -,S(d39114b7,c22beefe,6796b6ae,3f740a39,9e3c98bb,58b647b3,5cb23ead,76eae678,1df690f,383db8a3,86284ff8,f914925d,c688aa2a,8ec01a2a,243eb309,e79aa071) -,S(6195550f,8ce49ce2,f762011b,2e8feaca,509a0628,eaa93151,4c779616,721b39b3,ee8208f1,6d86fdbb,c75c265e,88090c85,aec112be,a1d803e1,211151d6,cfbeee2c) -,S(a8429368,37b33a8,2d41a26d,e11a0fd8,7af231bf,30d3eb64,73aa064e,acfd8740,18524c63,c0cf7a0a,b4e0eddd,61717f6c,3221a8f6,3522d35d,4eccee30,b6ed82c9) -,S(bf42ae9e,a64351a6,eb1d2c64,57d23481,f913de5a,d3c00359,5eb8cb5b,228fb202,2d74804a,34413cef,8d2cb488,ea780cf5,15faabd2,36a9db67,91549577,70a09d3) -,S(f1bdfcaa,ba133809,f915e0af,1a08fcbb,dd9cb3d8,b62f545d,6b71b44b,b130daa2,51fba8b2,2c7935ed,4241a87,f19c2b76,bc1a288e,3e53855d,c532f0b8,1ee382c9) -,S(7bf32637,4c6adf01,c7796f59,a11e5c3d,103e3339,a0cfbdc2,dec57f5e,69429bcd,8926e57c,a1fe7442,72d2e89,d037feff,df263831,e40e9ac4,8473336a,269f6b44) -,S(95b652a7,7f58b0d3,4c6d25e1,c294907f,a22a3ee0,f8e8478a,4e8458ef,37791c2f,e7dc4caf,b5bfdaa4,7185f0f3,a98876d,b50bfb35,a77a8b11,b522196,9f255845) -,S(d9f8c6ab,693f8058,8c73e2a,9221b0c4,c8f1d1bb,5e1e58e1,8468a48b,c74f50e1,cb38d48a,89c1ecc0,23e0e248,e1991ac4,3fbddf5a,9beeb53b,4cd9c49d,41f42a9e) -,S(43f62528,287e50,5cbf1a68,18bd99c,9f307e95,84e0d73a,f9fefeb5,b6dff92b,85fbb4ea,b81a0409,ce43ca05,3dfd5a1,9756fb5,f4b964bd,dc409efe,696c2ace) -,S(425a68ad,6d20661c,ca7d688,6bb9c66,f37dbf29,30ccc6da,dc34025a,5ea7a92b,7853cbea,d7816579,fa98ab94,875ebd2e,7ceebf73,20b50b2f,7e67f0f6,dfd2eeee) -,S(929ea74f,9b75c327,a7b26127,8828feca,821e4d8f,c5e308da,f3169a2,bf84bc2,f19e6cfe,d8c966da,bb070d42,3c62289a,5193146e,4297fa35,5908663a,a36b0578) -,S(83da36be,b1bedbd9,4a4ee417,f9faae5c,c20a9763,2c1ab2c8,b997f23c,f6d35c31,a91def1d,7871aa84,eed0bce6,12bf6a82,98d0ebb7,536d8e49,f6757a48,aa7a86ea) -,S(a2e1da8b,4318fad3,52c8c285,46f0a8d7,8fd6cf6a,b506f8ac,2d6746c6,75f2d5b3,584489cc,58b08663,1cdd1b7,3e61cac3,52c16814,493b611e,ffb94a71,2cd85699) -,S(5d7c1af4,4b257440,22b82ca2,9923a180,bb7fc209,1990b111,12061b6e,9eec4d2b,b40ca0f6,a974223,3a7b0253,9f0dbefa,1bf23dfc,cd59c747,c290f525,2e960b02) -,S(e2831933,6cce89c9,993bf230,ae4311ed,48fb0913,b5f35da2,b7531418,b512a75b,660aa9d9,8bfea898,810107e1,711abff0,88881efa,4d9d586d,91381b11,67cc2a21) -,S(722c1e28,498d3c21,66fb0f1b,f44e3ba6,181a962,75efeed6,ac83b36c,12426031,27a135d2,3b70006b,480c3aa3,bd057bfa,200da08f,f9eff741,6bff7885,4a1795be) -,S(f3cd71bd,f93f2100,c534d788,ba607845,cf6049e3,b94f5274,84e8608d,7adb9c99,b8e86285,db09b729,dd789293,7cf5fdc,989e00f4,5dcd4916,a6860bf8,d77cecfe) -,S(36341496,d986b096,5e5ad593,de6f88,67aa6130,889714a3,dc0d58b7,19647318,8cbeb984,a3f4bb5d,75cf77ce,14368b9b,77dfeeeb,7313f16a,8a573953,c7b898a2) -,S(a48443b4,3783c58d,4b7b2f27,17efafc5,e5ffe24c,a7c26bbc,dcbf93,538fbdea,33bd2bf6,9a64a742,c461fc0b,b0ae8770,9ed47a9a,26e7d05c,b71e4e2d,20c894a5) -,S(d4364d96,71f2876e,843dede5,9991ac5a,cf92268a,73212ab0,54b1c196,197dddfa,b30038a0,fd9f7387,fb37754e,9b050e80,e0f28596,d251d627,5149149e,880f6d43) -,S(ce277a60,19ac0b41,16b9d863,5a2555cf,30ef3408,f1a15769,91e48d0f,9465d250,5260ee90,65c89bc,7ef55fa3,d5f5d7ed,594fe592,322b7e97,965a9a3a,5654e710) -,S(587ecb1e,7c08da9d,75ed0249,b1281762,e9c71475,5c3ae35a,f7d66b53,c83117be,c6dda341,cb7d88b,b4a1b13e,313dcca6,1ec58063,376d38f2,cf142b56,87bafcb6) -,S(d87f96bc,69510c4f,19b84e93,cd8dd0b2,eee4fbb6,c5c5074f,ea76a209,e059f41d,a9b83947,b557c4b6,41952117,45ddff77,b5952798,66fb4095,6b5361a1,b463d326) -,S(af9f0d3a,78454c,eb8ca65,c9d7a324,312c01e9,dd8a00ad,e923f2f6,41fb0ead,2d3003ef,29a5ad10,20262c54,936411f0,f8082630,8506fcb1,e1848a7d,5d16482b) -,S(efd0467e,f4791ec9,9380be87,394225ac,637f906f,800abf9b,1ad5b3cd,cf9f017f,a14308d6,b0d16772,f36da4fd,d77945f7,1d82276c,ec4dddc0,de24f760,965c5725) -,S(e892235e,39ac312c,f30dfb97,97e88446,dc1f9a3,ef5cb8eb,d540c64f,d6b6129a,5b291ebe,7c055f52,b9fae6ff,cdcc6dbf,f84cad1e,4d35f495,4dc19b3d,64eb992) -,S(3158351a,542ff38b,12f82b5a,daa6ea3e,6e75caae,600b76a1,16ebe3f8,c9bcd66b,2006c258,a327481c,d324acda,b8ddc331,6a6aca81,44dba340,527babd6,4de975e2) -,S(f17bbac8,c0a7d2da,bbc5a5cd,4b28e96,4ab88639,546b2b22,d40c519d,25dd448d,14f9f488,e76663bc,278961f4,a33e11f6,98d6f5fc,1eaac638,79ccfae,1ab40991) -,S(9aa24eb3,44e010c2,d6fd3efd,fa03cfe6,aff67d25,2f08dda9,3d00332d,3065defb,494cc5bf,e60fff11,f42190dc,e607f067,7e355a9,52ccc682,6845111,322ac050) -,S(3f36168d,77711926,deb0f7ea,b6dad80b,8c755db8,e6705fa5,61285f96,84f1ccc5,486d57cd,b46d998a,5d064f9c,68511657,e53e544a,ee8c5521,87a1cd16,4121c6c2) -,S(fad18e89,219c449,87551525,6150e4a8,1fa2b23a,b6c1d90c,2e2f9152,ee8cd054,b285a7de,4eeff44b,751b4e51,f252f3a0,be7c2223,a715e301,23e9bcea,495ea7d4) -,S(1cb1cf55,9c56951f,58147d84,9482dba7,8dc6050e,2897f389,e30aa87c,519dadb6,b9e54a71,93a8e255,b2cf1fe1,80fe54e4,3e17470,60e9128d,bd527abd,c7ef1f97) -,S(74e68afc,9c8d9e0c,92675d9e,2fc12803,4ce7d22f,e31f5332,d18817a3,bd05efda,1d8442db,d55e8abd,aa1de803,f4fb1295,e9a8710a,3f25a242,7af9a5d0,b5dd786a) -,S(10336317,ec82d4e8,543dea2e,b8cb597d,3aec0e70,fb2971f8,7c5699aa,e4576de2,f2ccc066,5eae8645,54816dfe,c82e1162,226ab207,a17c6085,62925f5a,ffa3e021) -,S(b06a55cf,57668bef,6c51bb66,ac8ba7fc,6714c864,ca788279,2c8b759d,290342b3,7311f47e,5b526dbc,e4bc7833,e4c5b45a,190e3517,8f0f8137,2857e7b0,fb1f0528) -,S(af83a357,81306453,e576c819,d1cdacd2,689b0198,4f108d2b,6d9b8148,50df5523,14f52176,909c7e1b,eda13d20,7567f31e,161a80ac,112e4016,ad7c0bd6,20ec0ce7) -,S(f8f56d54,54faf536,3ea98913,827d57f2,a8983112,aa8809dc,594af919,3ae5c4a5,cc9d4182,bcb00a0d,cb73bfcf,da46ced0,ecee167d,fd7bbfc8,899063e8,d659dd7d) -,S(61aa26b7,415001ae,d6b3afd0,1c690177,879cac31,93a2e410,4148df74,733c4ea1,972510d3,697b93ad,60711b39,f3b3c237,771bfbc0,b7238e78,5a786707,dd179f23) -,S(781f196c,dde0f8e5,10ad45ad,6be062aa,1315c246,85d0ca97,21533c65,627ad492,6f3248fb,e7e61cad,1b01ec2c,fdb4dc4a,b1f4dc25,3666d4ae,27a88d50,c566d18b) -,S(c422d61,7f84ddc6,4483d55e,19228dcb,395f16fc,e85b5c93,2778f62f,ce8917bd,2f3cef48,deefbbe9,9477389b,be898cb3,90499b2a,615899bf,1e910e21,ed337652) -,S(c325955e,b56fe9a6,66555a32,72f637d7,3351b65,da5059f2,17748e68,4da4a4a8,3fa27721,2364140b,5b71526f,ad963d01,16889555,bdd42fda,c2b451c,fb70a3b4) -,S(e393cca1,49142f01,9be9a4a6,e8597354,e34f8d55,b400fa4e,8ac6b4c5,7e50b7a7,e40b69bb,44d6d1e5,22cc30f7,26b7a262,3e5b76e,7b190f07,10325a08,a99fb2ac) -,S(33e3686a,e4e69510,e939e53d,62fd669f,f1a39af5,c6179364,a190ae11,a600cbf1,cfe60b76,1306222e,7052b0f1,f799380,ed564d47,1f6418ac,dfb13d98,47f9154) -,S(1c35b5c8,3072f4d9,b3b294b7,69ff1b8a,ed2954cd,a013c7b3,34b53fec,c783b251,1c691a2e,782ff393,b0ac6c31,94f4cb0,f8dbd5f5,b51654a4,3914a458,6b855318) -,S(147255dd,3af5eb26,119e3d86,b2bed206,43579099,742c4ccd,974f7fb9,83e47fa6,5e0a0a01,7497235b,4766b44e,2fbe8902,aa0e2c2,69e7ceb1,d65c0f34,7a97f7f9) -,S(9524d71,57304a13,71d46aa,bc43986a,5ece70cb,ea008aa2,b8c97070,6436b237,a343af97,db30b94b,3d8d366f,1cd27b11,83c9f44a,75f0aa93,8c4932aa,52f6ea55) -,S(8502e7c6,e498d868,3816188,a99d0f35,79058887,dbeb3c03,676b3b91,be7481a0,28bda608,a9e18df9,c304896f,94efa7d2,46ee528a,6061afd0,322e052b,e7cfb68e) -,S(b89a0d8d,a21903a7,200b196e,46714aa5,ad49c5b0,8fc84de7,8e72ca76,2a3ad3b9,953bac1f,85e4f631,38464a99,e6e3be5c,328b3c10,7523701,c60aad8f,d57e6bee) -,S(49bf791d,67125d38,496d8ae6,ffcc25f8,97114f6f,9fcd5541,9876dca,4bdd7d7,6c2976ec,1b9078a9,a90f55eb,510b1a89,17efca39,d2fda494,b9013d07,7f4e05d8) -,S(c63bdf20,1ff5b07c,14273727,ff174322,422b6497,9ca8427f,5f868eb3,a1fcf05e,c4135e1f,1b5a09b5,d628674c,21ead97a,42957d31,92a44de9,b785986b,3269a782) -,S(58c8c84b,e9f85bd,b26f99b3,cde715b4,4b057d56,d5411c3e,a3000829,27ebe551,15de85b2,1467bee0,d4e0b0c5,114fdafd,410cf720,3ab35f1c,1eb2577e,fc2ec620) -,S(5fc5177f,e0b59e31,e4abef85,31f3fbaa,e3399bb4,126b6119,c7acac83,777cf9b8,adf27f69,b613fa62,3cff72eb,4dd10b4c,4009b73f,2cb885d9,57ab8c78,ca705fe9) -,S(1017a9b8,5116ce3a,498888e5,7a408f36,12a6e8b,b18f6961,d6e1d2e4,38902928,24f7a939,5e0d3c0a,579ae611,b733248a,640db7da,929edb24,b11bd617,3e573658) -,S(d9ea68f4,6af94d9d,232a5deb,c485fed0,d719cdf3,2afe4617,524958ed,751a2c47,e59f2193,db2fe578,642a774f,c4fc8515,f638d1c0,ae8081f,e9d3c0a0,fe20410e) -,S(61d975c7,e4d7e262,5b067179,667325c9,a32ef6de,a0bcbcb4,a825d89f,de6f7aea,b7a00d17,5a2d827d,37de6c8,667bebd9,da92ba42,4efeb706,54092342,e644db9f) -,S(2ff5cd3a,fefe0c25,bbb8245f,c9399409,83194bf8,f4599f3,101e9d79,b7f8d9bf,3c154b7,11964aee,5fe9175d,deacabe2,400350e5,3ea1ba23,20d9e675,5aac8fa9) -,S(cb438486,954c4a00,effd88db,29e0e61c,f9fef94,5b42bbca,8939e0a5,dad9e8a9,920ab096,41789957,6c3a8ab7,249ae2cc,73d1443f,5c650ad3,4da9d473,221de71e) -,S(9aaeefc2,889948cd,f59fa4ac,352204ab,46aa399a,c848041f,446be421,e0e4758d,8e4d2899,2ef8d6d7,3e1e118c,70729e7b,4e0bc28,69d7b5da,72df7b46,38fb3365) -,S(ace47cbf,846e95f2,9387dab7,6ed4e272,e32f6215,1e745738,69f2bfbc,720c78f0,a35997f8,37b8e86c,3b4377d9,71098d88,95d6a008,b9d65552,b1385a4b,49c53d3d) -,S(66610f69,1558942f,8285a9df,3081e431,5c946a5f,df958f03,b2ffde5b,c591850f,be93a2f6,53a8630a,ef037f8a,624e623,8f2ad9d7,3ff4624e,f4240cd8,d3495a98) -,S(db4bc8b3,7a12e950,706e148e,4f07df0d,a24d1de,615f2201,2dc1befe,f1ad95ca,fd55628c,c260a1a2,e56b95ee,ebd6b854,f548dfcf,2c4a6b99,7c4e95a0,a52c4894) -,S(a2a7aebf,58a9a58,24d5a996,da18958a,5fc23d8,452d13b2,b254d4fa,bcba959,d6440764,1642f25c,8b31a117,cd7ed90b,dcdc54f9,e652a818,bfa032cd,18bf085) -,S(2d8846f3,fa8a7a0d,408f8ad,bd76366f,4bf7bade,c255e2fe,595e4e22,cfe86684,2c0a7297,228185cd,3b21c10b,5c7f490c,b01bfe72,9513eb63,f2716d27,f0fbe19) -,S(27ba20c,a44821f,d6ebd41c,8c29e584,6237d8bd,13b3eedb,a82b5aaf,10a6fc59,68d65fe7,b511bde2,f922f119,4bb411a0,c000b4fd,268c2c86,e14279ae,9a63e42) -,S(c2f0b611,3a6bebe9,22ec3e97,a3962280,ab0b6713,76a6778e,5ceb73a7,e2894b13,27b90863,65989917,68a9635a,7f6c674e,71a433fa,ce4f1ec4,cd775277,89d290e8) -,S(8420787c,a0df74fc,5c81d19e,64f7ed56,8bc54a2c,ce1c5714,1706888d,bdf377f8,4a94b5e6,ad402877,dc4c0df,38c7fe41,d9e6e085,e70431e9,99c2b724,e35ae74) -,S(29d08c36,c45715f4,1eb5138f,a5c2f002,b4021f2b,bdc49592,e4242443,1f4d5f0a,903d61f7,2e81352f,582ce3b3,ead7b6f9,e0340c23,6925882a,cdb41285,6181bcab) -,S(ccabdbe,f68b6549,2158d4c8,91dd1d23,efa7a84a,a985252a,3a1e895d,757e5f10,94a0e915,2addabd3,d5adad5e,cbcb38ec,e1a045bb,9d7295a,92aee49c,a6f0bb4b) -,S(5bd30e4,9e2ba9a,745c6ebe,434b8d4f,1d8c34c7,6d478ffb,2871466f,a3ff23e4,1067b3c8,5980ea3a,dd1a4cba,8bb0b96f,ad988cc6,4dd8e206,51eee853,915226ae) -,S(eb233898,8f12eb2b,5369d9f1,56d754dc,8733745b,30967e17,697e69c4,4fa80493,c258bfa5,e993ff4a,4a9eb82f,ce1530ce,25fe74ec,2bbc2639,683464f8,a26b5667) -,S(4b44ca53,f01e1c64,8ff41a97,721e7c3,b0d62b4d,b15c5bd5,d84621c,4dee2ace,d8999254,b359a155,99e59761,f42639ad,27caf87f,ed4ddc57,203fef6c,9abbd922) -,S(ce5ef1f7,6cef6b65,35631e65,d4f47924,df370ac8,ce059a19,5455fb1e,b156f7a1,74c9b95a,a4dc212c,3e127bdd,266aa89c,a4773f27,5607dff1,4438647c,f0e50a60) -,S(563d7e99,40325aee,e66557d0,b14b7e8e,14f86643,de2b3300,1bcfa7f1,ef788bc4,ceebeb99,9878a305,1a8bd9df,bd6cb2f7,3ac18776,ea78df41,30fd22d1,bcdf37da) -,S(ff929868,fb5a1b53,6acca702,f5dc1e83,efe8cb96,f96a3303,d107c6ae,ab5dbee3,82828150,fe8fbb3c,f2bfe03a,3c79fa5e,67c33d97,b12faaaf,572b1455,6ae11969) -,S(1004e4ad,487212a5,8af57ea1,49e0edae,6aac884,2f488bc7,1b75a5bd,4a20204c,88d9a6,164cbc21,52d60ee2,7c8003b6,b39e418,b10c72d0,504a6a7,d7b8b2db) -,S(28dca143,206abca7,1c48137f,8bebd26e,6c79666d,ce164fdd,ef1ca7ac,8e141a25,ec1dea42,575e5cc0,804f6da3,21ee739b,ff244cb,2b299413,4b8539e3,88f7ccf7) -,S(cbb81690,a7e511bf,56a5190,b9366345,7b4fe8f9,64b8fb57,36df2067,28e1ca48,c2d2686a,5405dc79,d6a2deef,95a97813,4a434309,c5303985,f173015c,6571e5e) -,S(3e1e663e,378c44b9,b61d04ca,bfaf65fc,df6b59a2,ae83719,11b11582,978f008f,bbf4b3b8,2010fd76,70d23b07,6018708e,8f78d70a,b2da1efd,be668c9b,d5125d51) -,S(7f742a3b,9edf6aaf,cfbbf368,5a622318,1a6c3b5d,588b74de,c2d2c049,91d97784,238a4f6b,5cd25489,1b8aa5bb,41f253e6,6a59a020,bce98966,ed4c75f6,b7939e32) -,S(f073f95f,f6c809d0,9271eb48,abf35b2d,b760caa6,54b0969c,e327cff,f806f43b,6a7eb8ce,9e297e07,170e9287,7fc737cf,bf923cc1,e72efdbe,5b3b4920,6602746f) -,S(855f6451,5b98ef1,67d3a11a,fec74625,cf3801ab,75df42d2,1b33b1bc,c36d074b,6e8cb794,9990748b,f54a9291,e7ec374f,a31bef56,ed1812a7,7b2ef00,149938fd) -,S(f0164c7,f204384,d3235b4c,cc1bb9ed,bb10cabc,d69c02b5,aed1dfa9,56c74d49,872fc547,78580a6f,38792974,a64399b8,cd674622,659ec31a,91fea06e,77e27118) -,S(16e83238,e95e29f3,ebc297e7,fbbc77eb,53431f3,cc90f809,1e540457,aced09bf,3f3c0ff5,754630bf,88ec765c,a5c04da3,f6ca4ad5,e72d9c0,715cddeb,69c4f8b0) -,S(70d371c8,8b2e47a,47982dfc,bc98ffd8,324b6bcf,2f1aa2a8,f4815f66,dd4949bc,34cc039d,3c69b4d1,833375db,e7315340,bab2452b,2a82163b,dec73702,f4c8da46) -,S(db250b65,6848570b,5a59a2f2,d45e99d2,de1b3813,46fa6ce0,8bca0b34,57c27d10,2859a0e8,fde87061,d7ea8786,f5667aa8,b2633e8c,c52926cc,c5427d64,a7ae6494) -,S(d6ecb3fd,b1ef3350,a2a831e2,321cfe9b,6b22b38d,6a8fa0f,b256f2cd,ac73f949,ad83f35b,c1b5c568,49436cfe,6ff17f5e,8abc6891,e24f4a0c,524d88e0,6c3f1028) -,S(ee2059ff,a2c5bef0,646bf76d,ae2f3bfa,193b8a28,bc74cfbf,a96b48,921ac0d0,3a8f4693,15d6a6e2,2e57edb7,e5897039,153e0283,8d66b1ce,1814ac74,195379e7) -,S(6dd7fa4d,bc12da89,1669cf7f,b1024a8a,551d7281,83fd221a,7a0ca9a0,8c2aa725,67fe6a0d,fca0fc02,1fc89584,d2a5f19e,ce890708,490c79e3,cdbd43ad,ad24493e) -,S(15102e09,b966ca25,1a9b4609,16ca1229,7ab64d60,980582e5,e8bf0e4d,80fd6c35,7ebf61f9,956109c4,3cfb52ad,4e60078c,93ea653f,17c7328f,9120545c,48988be7) -,S(a0697816,4a0511f9,3a48efe1,de74992b,54679aaa,a99e328d,6771386,945e9039,92d24154,971add65,c40e6f32,a5b5fd01,765effb6,c8d64676,c9d97e8b,f857d630) -,S(ac925df1,3a9ce7db,18b9071f,f81880f7,c8ec97be,4b78a31b,27917d71,da0defce,6347aee9,abe9b2bb,1f1e3ab2,2792009e,ee009011,337fb184,d3f637f3,186acba6) -,S(74f3c7b4,e237db77,9229cb2f,1fdba8be,9ba990ed,6dd84976,ff92646e,55e21091,44e9a71e,a07e4254,c4dae620,9c437873,7c56187f,23f42224,3167e45,932055f2) -,S(78f0a024,f6a5bbaa,f3eaf550,92a55bae,73348e82,37dc095c,11ee34fc,3194eb00,54e9b6e7,2f758d54,23d5b9bd,b329262d,6745eb32,c93c2571,f86f40cd,1cfeeef9) -,S(83d3e538,92d722a4,8c006910,a22f32ad,2ff7bdec,d9bd2ea3,a2f315cb,550a1bc3,a4f3c8e1,732b23ae,9f21c03e,7c3711ff,687683c3,13455107,68278332,8d9a25d0) -,S(15deb2e3,f0f0b65,5edbb7d1,8d86cedd,7242a693,a271d853,b468d57a,52cbd647,7cb1ea70,8e12acb,6bbec5ac,26f513cf,51460493,9db6cccb,ba712561,a6f4a80) -,S(6fc5c841,eca2637b,67fcd5f1,3c3dbf40,3b00e4e5,270bccad,617c58af,ac54195,afc3fc7d,92f0f77c,5147ae41,8aae93d3,b5cb7785,d65e623a,391d6a06,1f82d4c4) -,S(154dad09,40e83686,d0942998,e220f8b6,bd106af7,beb9bc66,1f1a4c2e,29300f20,9a47095d,b2a357c7,16d8773f,18c953ff,dc0ed270,1cd881f,f3088176,e61bd7ed) -,S(a498ef6b,89b882d6,81ea0647,f83d53aa,d1fb39e6,6bba74bf,8008a43f,197b301a,cf4d289e,f723ad46,27edc96f,5315bc2c,9ad39c04,4e8e6785,222ca142,3f5c2881) -,S(5c01e4d2,465c3326,1828c45d,bbb2cf69,79cdb746,fb659a6b,44f0f2f1,f388fa3f,315dab9e,5e53f939,610e9729,3e686d33,e46f8262,5ddfb45d,46728b03,927a6837) -,S(d058f58b,255164fe,e6d60472,2b32624b,2eb523b,6c7f1e6a,7ce1c248,fb3fe505,21761abe,1bcb844,39645310,7a3dd2ee,28bb4dc9,93dcd0e9,a09d5176,1a7c6536) -,S(eb89dbf1,67c1352e,5ea2a7fb,206663b1,8c95d962,cec35412,3b9be6b3,51799ca1,9566074f,ec54174,a49a5f84,e4965174,408425f2,22d485ec,b020740c,74b08ef1) -,S(19ddc300,84dda580,db5b1230,b0fe9508,5575eb10,680181ff,ee0d521b,17b39cb8,6af18172,bfb03b77,db456836,b9617f05,bbcbcccf,f6ed2dd9,a9c6e734,c01d188f) -,S(66240aec,7e72f707,69560e0c,f31f2c41,9a8efab5,32f17f59,19bd56e2,93c41e13,16fad661,3600a79d,41eba5b2,d0721dca,afe94372,fe83b20f,7178e29a,e6f3949a) -,S(3c75905b,9e7c7751,9f4617ff,6010c39f,92b852fe,89dca73d,cb3f15b0,23f7a286,799ffb8,94fd4f3e,61dd489f,da746fdb,ae955eb1,3c8dd9eb,e4f73d41,2feccec1) -,S(9719a34,e765cca4,68ab3453,3c6dedd1,6247af51,b73295f6,8b936914,c03f10a,4d4e7f2d,ee3aec6f,71fa8978,f532e995,c0e1533c,5cf0b51d,f35d8f8,29cc10ec) -,S(e32f292e,e5c41e2d,bd262c45,eda0b729,713207c0,17fa5c47,c8bce6,ca550814,105716c5,5995ffa6,998f2209,b9d0b37e,f2bd78be,527f6c12,b707faf1,ef73a82c) -,S(76aa4115,595e7656,c76300d0,a60e3316,fd9c1b60,d41920a6,128e59f0,74a9dde5,f3ca0754,b6daef99,acd6e1e6,fb36d93d,e068c0d2,26b843a6,e7e111e9,9df8efda) -,S(215186c7,ba018fee,747c2030,f57d1105,945b021b,be053da,efb1136b,f0d6f0a9,62994ba3,62d9a8a0,7432690,689a859e,ef498860,3d52352b,e27e0f8f,d02e4de7) -,S(62e16f47,4d3ce3d8,a21f0c8c,875eea7c,111ca0f5,21c03f54,6bcee790,ab0d48bd,e9a8c8ab,99f916e0,4141972c,f60843be,72088d1,e044b27c,6a84b21f,c787abb) -,S(372b5966,8b00faaa,a714e7a8,2462107a,3d1226e4,988faafe,988d06a7,dfb27bd0,c6d349aa,6a53d0bb,185e0f59,a4c137c,8622be1c,5df205f3,4b090080,bf4e4035) -,S(b11cb8c,cd6302bd,e6005ed0,9a1ce2ea,a81fbd9c,748a17e8,fe1c139e,d2d1d725,29ec84f8,e8d627a6,b81a63c,4b13abb,88d7e5d4,9e56e2b9,a3f15f40,60efa38d) -,S(652b5427,f45d07c1,8cd9afb6,7d5743e2,836d78f3,528917fe,2a5c6162,c4a06d81,3e93d9e4,25ce53a4,915bd12d,4327e89b,64a7112c,5ebae53,35c631c9,64b2e5f9) -,S(c0812ee9,89fa0531,56847bb4,edd517a6,7d6d7d0,90ab5955,a59326da,f3833afa,2450338a,cf923109,d67b0501,3557f310,f3b0550a,8f1cd5fc,6eef8a5c,14b46c27) -,S(627c169e,fb0d9937,8ddd0fd5,a73afa16,2a317e56,7d957695,41e52a41,d9344ca1,11dfbcf7,75bafe74,eec503cc,22c8b485,90a17079,580acdd9,c51158f5,efd0cd7b) -,S(69916299,5b83ba3a,6bf16e2,97e8031e,74dc9054,c05ab59a,335a8296,d876a66d,39e45d50,aeceb888,8a1d64ab,9cb3b127,71269b7e,a14ca4eb,2179d762,4ee6d953) -,S(6693adae,579636f3,2332a418,7e49ffc6,921aa51d,852b5136,9a96c8e1,cc268574,ae73a660,580a4005,50865060,dbe9ab43,2f304ca5,506b9f4e,7e17f602,1456bfa2) -,S(ccc178c,7168ac1e,e7bf7579,f75f9645,5ca2b558,e1e709ee,de86df5e,5ebe0789,81c63b04,eddbf33b,432e00c5,9e76d319,fd1ef2f7,d6f31349,1f7a3c10,431a2130) -,S(d80687f6,89f7c28b,d6ef1531,c4e4b283,c6e5dabc,ad7fe5d9,6dc20d30,e1feeea2,71e24cd5,9d2c33ac,2b298946,bc90e0fe,d229720d,539a6f5,e128973a,9bd6c5fb) -,S(c53a6911,88f785f3,efc1fe1a,d142a259,cbda5f76,f3e9de36,895a8963,ffefcb74,7a225bd6,a348728d,951d55bf,257de9e9,d88df32c,ff2c4391,f4ddae8e,ce357cc0) -,S(d512c64d,1932fd1,5636740e,2bbd302c,3d8674e6,52a30d40,ce879145,bed9b7c1,52e336dd,3c7eca6a,469bc97e,a330fa03,1cda3c57,a4354ba2,acffcaa,a1e6b424) -,S(384aed3b,531098a1,99312d65,74b1b1bb,e79a8bf0,ea4f7a86,c5114fda,b32061d6,f2290bbb,2bbe7b53,eb64f87b,17a9e1,49356d9e,de3c0be4,28a4dc7d,709ef731) -,S(6db6c2c1,1fbd5b92,31a4e34f,ca2f9315,dde00dee,909b8d53,d7149c6,6e3cecb7,cb2f0b26,e1bcd464,6e6ee074,8efcd499,f535a8ba,f61a38e7,aaae3511,3c781649) -,S(6bc2f0f2,c0118efd,4fbab4c4,90c56da9,d66c0b1b,ec88e8b1,c8da967a,95d1ae60,a568f40f,24e51e2a,d01c13de,4490f34d,5a5bff13,e005ce77,94a59128,f6d871ae) -,S(12e4e92a,aa40ad9d,281316d2,358bb0d6,c69fac28,24114a9b,a96091d1,64ee29cb,f717cba6,b07eac9c,34b8821c,218519c3,886d5cc7,a22be959,54b3eefa,8819bb51) -,S(6dee0e1c,b887e155,e67996de,92716821,7874f9f0,a14c8673,1eaba91d,272705b3,28d9f2fc,23807874,9dd40ac1,8ace2dce,18ac3980,7c7a5922,43260eb8,ededbc3) -,S(f9d667ac,ec2120aa,50c2b6f0,810b54eb,4928bef4,779e2311,7d12eebf,d093f139,29c9458a,52d4cde7,e32a265b,fb537b3e,5a5fdbe6,ece9be95,b645b960,c160166d) -,S(e026f66,af79f4ea,52955b52,bca16e2f,b2cb05f4,38568c06,ebf1ca25,e6f5be17,6319ae60,3e733681,c8caa501,d7715b98,6244c1df,1c42d391,d8d47e15,a681df15) -,S(1ddd29c9,bbb37823,1185f631,23d5e1fd,39c6b03e,44e2a542,318a6f3e,8325ffb8,22d80158,cee2f596,8da360e5,93a2a86,ce1ed25b,77a4d66,a2e7592d,26c2c715) -,S(138f88f5,f9f46b81,2246373,6034958a,d5476a0f,348ca538,f789e980,9c799f30,adac6393,3e2de680,6fc38d7b,23ec5214,43ab505d,cedde216,6accf786,bd4e4aa5) -,S(b516a9a9,4630ba5e,7469d5e5,ee0f03c2,51bfdf5,a1983506,79baca9a,e6de6f6,9c184956,7ad68859,89a2013a,5a902fea,66d398e4,6c85203e,b7a143b1,90b42587) -,S(bb1a5499,548ee5a6,79500a49,a1466b11,9d56918a,735c3e07,31939ed0,2d47abe7,b946e966,2df43be8,6478e809,ac690d4d,b25398e8,de13731e,89867f80,63f8021e) -,S(394ee032,8be13bc3,ffa069f3,92b72070,36ad018b,503ed70b,9bbf9f7b,458faf36,3a494b0,dd538dc,fa3a10e9,70b83c4a,2169b4ea,255c6423,50f7ee72,40a6910d) -,S(a021889,ce4c941,606c0226,2b423afd,f44d6a75,483dc4cf,797b3512,8131e2ed,d8ae98ca,572b5a38,cd10a763,6638c47f,2867710,373af6a1,bfab6cc9,64b26547) -,S(99e2cf77,a0f389ad,a6c21457,d3e94ee5,95fded19,89c326da,3cef2e49,670f2572,8144a88c,a90a7685,ea3155ea,8fa5cc0c,c282fc25,532aa5da,84494b97,94810a1c) -,S(23c4b50e,80278869,b77c62de,8232a70e,52a4a3c3,4d0d6114,78989746,54e57aca,afba6a63,e35b15f3,1a24e5b5,844b0f3c,b247deee,a764b3c1,1075c3b8,c65bb0b5) -,S(ae0ea240,91b09648,6bd06ec7,ab6dd488,fd6669be,58c2e91d,e8486560,47493d5a,63e13a3,aed0b2f5,a11e914a,3617b1ea,abf62d4d,731eda05,62251d76,939aea63) -,S(d9e9ec51,cea0b150,28199afd,70fa86ef,dfa90e86,b9613831,9cbbeb86,c6573bf2,561519ee,f8dd5ebb,df47d4bb,c24eed76,5ff4342d,6ec6e537,8a2952e7,db51354a) -,S(e674a628,7472d602,8c0b888e,1dc86429,207e38a,af61d3e7,60708721,c1a44613,c145e723,eabf1dc7,f09fcef,1ae24116,1bc0d24e,9c96c83a,3c4e76e4,cdbb9e7f) -,S(19a43fb6,ad571142,42644af6,a3ce367d,329f44e5,bbbd8948,9368620d,944f413f,29a616f2,5f2bf4df,e516574,cbe840de,9ab9ee1d,abc86ca9,6413bfb7,a79a4095) -,S(cf1e1a87,32eb52e1,660186f9,6aaa4cac,9248d8ef,2738a6e7,5e600f3b,658825d,379dd9a1,8355ac8a,94a9614b,e3f51540,c17a76dd,3e3f853f,252f0e75,164dd346) -,S(342147b5,8a1ac1d0,baba5b2d,e924e7a3,b804e385,466f5ae8,29138bc9,5c5b386b,9d8792c5,8917aabb,6a3cbc4c,7f18d2b0,768dc9b9,1871bf48,8ebabc00,f51e2bf0) -,S(1c24e35d,35fda6b1,f6ae6b43,7599ec91,dff1fbb3,b3d26976,783c0539,a8b9af32,58591ff1,68290b12,d729c621,f5da504c,e697ef00,7d922152,9a76ed61,2dbe8608) -,S(d0fa4d47,a29e1101,baa08cca,73e00d6,660e2588,6e1b5cce,ee1c2a5a,9fb806da,918cb1f1,608f9e40,37a59bb7,28c25708,db898d76,a8b2e2b9,d4450c64,3606212) -,S(f3307ffb,7e72413e,2207918d,8a93f183,d5cc93e6,ae07d196,a6d22f1d,253b2499,8a44b83b,feffd6d2,78442d72,51929c0d,42b690a2,d91d99bc,c5dff056,d37e1f27) -,S(77e612a6,9931080c,7d910573,fe55582b,30eb4ca4,c7b7fe1c,9c4eeda9,b296097f,cc85c0f3,6f020bb0,9705f560,15268e36,bf61db2b,814b51b7,c958f1a8,656c26b8) -,S(fe3b3fdb,b8d768aa,8248087b,70e6d0de,592c95e9,b9816996,a3b4c88b,21bb9605,23b44ffb,20e8fc95,ad3c035e,3f52fb53,51291965,95fbda63,8a192cf9,43630e0d) -,S(e664460b,253050fd,8814a2,b2bc0f56,fd8d2f53,94673a67,9a76eee3,f7ae6e80,bf0a7515,a0a6351e,62bdf527,6974f06d,be87345b,438eea33,ddb980fc,788eec9c) -,S(b8ab3266,6cb96b06,a363d87a,a7ee820c,695b7372,b9341b,292dd0f1,d5fc35af,720da144,39ac9d53,c480dc25,5eb45ffa,b9e406c,8eb5bae5,1c145058,8120f900) -,S(38242b07,d1904c72,6da9ca1c,f1acced2,96c1c4a9,b37671c2,e529917d,a651b99,3d47a793,688603a,d6ddfc87,1c85a19f,e21ac51b,d292ff7c,69e219e5,7a0dea85) -,S(ae9a9354,e451abb4,454766fb,7eaac21,5982008e,6cd47d7d,df5a6289,27131913,46d291c0,7f99fbb8,2eea4c66,525602f9,6af5c16b,f4c31ca8,c26a831e,a39985f) -,S(59e59fd6,6a89a538,f5277950,816bf2dc,7070f70e,98d04b95,1b83a80,dab205a9,cec6b519,4d1122d6,dd3e39a6,fb3e80a3,2d829158,3ddf0bb0,3dc3086e,9f247f4d) -,S(59aade5,c117e92a,97ba1785,2e1ef3f6,d000620d,a8f82e2c,1d4272d5,34a8e22a,6a6b6ab1,bd9a69cb,181538fd,eb4a9e8b,eda75811,96ef31ae,deaf516c,e68c1cc3) -,S(f29d02a4,5b464774,fbc1bcd7,7caaf22f,12efcc9b,2a569966,b9adbe8,18a9f075,ba87956,5e0a1c56,fd03175b,a781110,3f34542,ded10367,6d44f706,7b8ab418) -,S(db630bf6,e9ff0092,eebeebb8,a5bc72e8,774c083,cafa0519,2e6d913d,112181a8,6b764e8,2213a7de,79b9abe7,edabf502,d9ac04c8,eb5a4b26,9d22b666,f657685f) -,S(45b9f064,71b848c7,48ff3fc3,34d425d2,57a71abc,27c4d002,dda26c77,1b09d2b8,c2119389,e4cecaa9,c0c72e4e,20c95cf9,1acb1698,c0bcfd42,f8620a9e,d781de57) -,S(d4919e2,3a278aa4,25bb55cd,2fdcde2,eac63058,4cd57f50,390c6a9a,1015ffb4,f8e9f461,950f17fd,8c46f04a,3a6f3c52,5318cb93,a0aa3f3b,bf90c02e,80e1c288) -,S(ea000677,2a76378f,3faa3c1f,c7227cc1,4b11764a,3c9a14c0,4f18f9d0,b55acc46,eafaf0b5,9a308182,8e6d07d7,2e16509f,bbf76fbd,e1473e35,18b795c8,87ff84c6) -,S(70b539a4,4750f763,be1145b5,b433e98,847545a2,8fc72986,2c17045b,f0d6fded,d5438ebf,18eb5feb,fcf6edae,4fcca2af,e0208adb,2f82648,2af428cf,bc761464) -,S(10b4a235,99ce2be7,fdc31f8e,ad91523a,47b8162f,8ed9387b,4c208657,25fa88d3,773ef1b3,a3943b86,729661bb,6ce6f4ae,e8c7165f,97a88fe9,5df9e027,3ccf9e7c) -,S(67d7633,499323f7,cc378c5e,2e62cc6a,5f34ff83,e11e6061,9ec4a404,d63b91b7,cd7616ed,60f0f4fc,1006dcf1,850807d7,e8730954,30db6761,cb7cbbf1,a9c2958b) -,S(5744c77f,8371057,61b1c782,1c9d9c53,14219e1c,5df80ea0,f772f9fe,ff157aa7,578459ee,13ec92b8,b685acda,a153f24,f6c844bb,e195ad58,77364ead,7a9e5fa4) -,S(7c6b254d,39ab709c,cd63c2c2,56c43483,183b1b27,25ca49a3,19753f68,6486ad02,5669fcba,d8662be6,2d12cde6,30102f3,70f7ef0b,5b347fa8,6000ae6f,497fad6a) -,S(8ec715c5,bda8f9ef,3b197ea8,a182a3dd,6cbc3b8a,88227e00,53a2eefb,b2006676,e59ecc81,aea7f2a5,4f659bdf,a317bada,3f8ccb7b,134ae21d,733b9710,335e73c9) -,S(fc7eb1e0,95d0b18,58d22b5,ad36fbac,1b513d86,2bb3c9ef,61b55a5e,985e642,7206dfc3,10056bcc,4071e9f8,13495744,dd903d72,2aa0d6b7,3fb35394,4b66c85d) -,S(4954bd00,308e205b,90c191ab,6262daf2,81939084,668c43dd,1ae998d7,e143f1dc,8efa802f,e67f72c2,5b4fc279,4e23608,7b343d89,255272d6,3c3968c8,7f26237) -,S(f27e6c84,f60858e8,2eb53d39,a6860189,9172da9c,e0d1ea70,9225effe,23de6969,90533e33,321f1f5a,ce37ff79,b4dd3109,a1efd6eb,de502aae,4dbdf58b,1e697c74) -,S(166f3aeb,cd040509,85df120,edf55c1b,f6eed0b5,fb24173d,c7d9125d,d0b2b29a,54b8de8b,c24b1cd7,8f89820f,d4b3ac6a,1588ebce,6de99b9c,81773ba,5fd32e20) -,S(c0797522,8dabaaf2,b46108c4,88ebd104,b0bfafdb,b344b5e0,72f6cb6a,f58f3cdb,bae0280c,704e0d0d,2d421b20,828cd00d,9b388f32,fcadb511,ad5ed4de,281a4a29) -,S(81366739,2085f96c,6a39c9f5,ff60b51c,4991a289,7106619d,1ab0de9b,34de87bc,d7b8599,2464c1e1,9f575cfd,de5bec08,987230b6,20d911d5,d6dd3d2a,8a75e079) -,S(335f446a,f3964e77,8f4985a5,c19e371b,876494b4,467ed700,482558a,9cab3c65,6e8fa42,24cd52c4,b78af9de,b7efa726,c26a94d,85bfeb6,fdb1b97f,674cbe6f) -,S(b6a34b42,bf5e4781,df14fe99,1a14b414,fa488da2,29314366,1ba83ecf,1e80d60c,b633c9f3,cd359dc9,2ce47287,670fe80e,131315c1,6fc17811,f319f1e9,82f88e8b) -,S(95f99013,a9e937e6,ff784b07,23287960,5eb4532,e16b3881,25a18012,17ee3ed9,2d0fa2ee,1aed211d,5b90915f,f3b2116a,28528f19,35b6b534,333b102d,177c08a2) -,S(9c0923b0,d681933,bc8bca36,a6af4058,682c5661,95d3a211,a1ef602f,933f6a45,a72df8d,a9a951e5,a63f0424,4974d74f,fb809cf5,fe7c24da,9c1715a7,2419c7d5) -,S(931cd34d,e32188a8,802b6a73,204eadf2,cae8d8de,52423daf,daf042cb,946657f1,d84b7406,d58c53e2,89ca15bb,4ba78db3,6bd2947,34d0ee9d,6939c15a,9f28b856) -,S(24be4b41,f845c43b,5fc594ac,90e3e4aa,b49cc79c,4b0a8408,1803c27b,ce62fe4,c6651cb0,be54ab0,78940179,6dca2448,3d9349ee,e45e78d4,b786a636,83861bb9) -,S(f19a51c2,ebff1d77,81b0e7f0,a29947fc,3ed9dd26,9f0b9cb9,c27c3f7,500c81eb,8e1cfe92,6128173f,556b3ec4,4c394ba0,201a4f93,e2db054f,63934b2,479a301e) -,S(f6e7e4cb,88ecad49,a1653a6c,5510571a,cec77024,2f490774,a8dd62a7,d6e16363,60842dbb,b8ae082e,9538e725,1a3dd7f9,8edabff3,5444719d,97134a3c,236c97b3) -,S(e7b7bb26,af8cc2ba,6e54e923,6af55e40,7ff704c6,1264cacc,74d96b52,81f2ca00,3abaca16,e20f74d7,6d11a942,415987c7,8da5ed50,3d781f2f,aba6d534,cbc3908c) -,S(c8acf1d3,89a29f6d,e0d03835,80a0a562,aefcaa99,b184f910,f2c8370b,bedc4c16,924e9b2e,2c6463ac,e8eda0b3,feee2f82,73050559,1071bbcd,72f6e323,31617359) -,S(1453b2dc,efe09d16,373ffc2d,42e79805,64ff194c,6b9944dc,b12d3cdb,1d84ae27,2d7faeab,7ca11212,a1aa9d4,a462c04b,8dacd2ec,1f7ee3b8,28fcdfb7,a26c6e17) -,S(ae92e090,b3c6ae15,68a12c6c,882d1b4,345f0a46,b9ad364,bc869243,dd533f4d,3f50449b,a3865900,ff63d944,27a0b967,56c00179,5b5f51cd,5996ca2b,19ad7abf) -,S(3086b503,ad8afe4d,fe2795f7,c972e0c0,8d6f040a,1be88309,606fee4d,b977fd06,b8631fad,80689ce2,7f62db6c,d6a56f3c,d3dc110e,610f3732,fa3f2c10,a4d588d9) -,S(7a17def1,e9c2b175,9944eb35,262908e7,c988f602,2440e151,928dfb44,462e2856,42171a1,f71ae8ea,d437a1d7,e1ec3394,b713044d,6c895930,2535787f,b93fcec3) -,S(97975e9e,b0698b70,995411da,37ce2a87,91198b90,e104476e,b86c4a77,dc5ce9c4,b8999b7,69b36de2,13cfc81c,c2fffc3,65e5dbc2,db1906a0,ec88e931,cd05bd41) -,S(839fa603,a2ec722d,1253328e,15f7d187,55ee80fd,b6bc7b09,bbca59eb,316d1b22,4e43cdca,1b33fa9,cf397ef3,91d40b46,fdcfa770,b2be8e9d,9ee22d61,6e12dfa9) -,S(ccfb8b97,7baefebd,eaf49c7c,1ddada20,861e1c0d,acba4caf,4e30f21b,ca3a05a7,7d9bced6,62579237,a348071,3ea1af91,256e9d62,1265fa27,cc80b5fc,cf75f99f) -,S(8f9f369b,3f325823,e8c9b16f,f2142ebc,3c6f7bfd,dd28c4df,63d1c92b,581cb6a4,114c7d9b,3f54f549,c10d93d4,25843477,9c297e2f,3f07b208,12335fe2,5771b12c) -,S(f0deaa5c,324c5ead,6f6f1cb0,cf1dac32,ef342606,3533435,65ac164a,ac8f0f2f,ef6dd597,e2203c03,f0ce0780,bcc1e963,621c1460,7a4ce616,9ee6624d,11c2eee9) -,S(638362c2,18c9e0e8,72dafa8e,fed86fcf,da5641eb,7cd01725,9a85103,f04fa408,3c224389,bff1fd09,338ea28c,7c9a93cb,32be8749,4a6c629,5c1c3dff,2b582877) -,S(49acbef2,64708117,a53f52e6,84bc15e9,d004baa2,fb3a756a,72d35efb,49871759,b678efb3,fa09158f,d1f9c74a,87a56883,b0a8316c,d4848ef5,1f35dfc0,8c4b5bb) -,S(a79d63c7,b718cd66,b393e70a,f032bc50,a90209b2,5f5b07c0,303eb8d1,1db618ee,ecf7f89d,2f6f9877,9b5e390,ce5837ba,49bc2b3,a7c1047b,7a7c852e,89f1551a) -,S(c922d543,f192f654,3445d3f9,c36a05b8,2ee043e0,92afcae5,a21b9b17,a06d0257,cf77d5eb,9e555f90,34ce1c14,63f7c4b6,a0202d81,deb02ddf,a26113ba,292554e7) -,S(dbb8f077,b411a4dd,faf0d89c,3dc20375,1bb20e16,2052ee46,915528e5,1f461387,a6c0d5df,91cc4ba1,cbba0588,774d47e1,7ef97281,63ca8950,7ff6b779,da12b7e6) -,S(dea21a21,eccb1733,14d76fcf,dc6109c8,88a633d9,645f86e4,e59ee237,cb18110c,a1390d1d,69a304f1,a2792ecc,675f2dae,1ddef908,2f2e3929,6b9a068,3933264b) -,S(f088ed85,750dd58a,cd03b3a9,93d88760,34f50780,985f7552,114f957a,ce8904a1,b810e652,f596cb80,c369f61,f632bc3c,fcfb1fc2,b906acaf,c1f39d02,5e3ae4dd) -,S(b85da431,16b898e8,56fe3c18,b60a48b7,c2ba9f65,ad67c31d,f45ac3b6,608b774c,357d324b,474ae7d8,97398506,c550a1fc,5353a00c,7e6f1245,c0f57683,80ac9e1f) -,S(eaac0d2c,276000ff,899dcb3c,61b41663,70123276,14585bea,7704de95,d164514b,aad696cb,1af2f12,1ba915ec,64afc13d,a689719d,8f188424,25d6068e,9bb06a69) -,S(7a3cfc7e,51fbf61f,ffed3430,eb9ac40,c84164b0,21220837,29f20ed8,eacac977,9015b896,e034d2b6,684f7352,185e959b,5c45406f,6187930f,82f62269,d3ba70a) -,S(5a9def12,e06f0ac4,35b9f853,53db864c,77288050,c349ed7d,a8d8b109,b001a856,b63b74ba,868df816,9dfc30a9,1efbae1e,1617a230,3ed20239,9ecf5798,5ec4bf99) -,S(b937b3d4,287a0f84,5323cc72,95b4a201,ba9d97d3,2d968533,7caccbdc,ce8623ed,6f2ad251,a66e5ff0,77384746,9208db13,2a396dc2,17e781ce,9aa8d556,83fc0adf) -,S(d44f7fc2,97e079f4,ba0689de,dc743d4,964c6ab,8c34bbff,f95bf22e,b7d3c209,b5afe3b6,f6b02542,e6ce811b,f4bb0fce,79e7916f,fed8845c,dd83de07,9320a2d1) -,S(5980fbb1,6be7acd7,b090a2b1,c83dbf80,9148cc99,75fd6834,edf564c5,50fdf2f2,72340269,8d22b946,ae51c9c8,33d5b44d,ee884a02,e12a6d4a,23957483,32abac9) -,S(94733aeb,dce57a89,16961f41,3eb04b5e,71f0a055,29baf93f,c9ff178a,12b70511,e591b62e,5cf92ea4,306e16b5,acc5958d,a5516bf5,7a7dab17,db38cef7,44302c47) -,S(1172b006,3d5ae491,8699e756,75ddfc59,fb5cc8d4,f332ce72,f99fb99e,c9799d96,2845be1b,b97830d3,f9d04a3b,36ae381c,5654bef3,f3fa8516,3a7b9738,ed867ef4) -,S(29afd093,5ca567f7,eb4cc1c2,ebbbe8c3,bc405691,b41a2812,b7c71312,81bbe691,77e9a59d,c0aebd28,9cf2960,ebe7fc19,236c1859,7882df0f,a8e6e0c2,6d92b821) -,S(191c7ed6,72c36def,576f645c,6b475eff,793119e3,ebc3a29b,71eee3c9,cb52a635,642bdce7,90d0f104,54ebe4d6,282be83a,443f8f44,faba4c76,5b1491d8,c7c83210) -,S(237eff13,89c20d30,9902a738,fa4543d4,c2a4a2b5,6731603,500997bb,40d28eda,973d696c,ba9eb05d,73ce7491,5c1cf3d1,5a998608,7ce85854,f7bdd157,3d5c7394) -,S(d4985b52,80673074,53ec0edb,f02b9d4c,b1ce9a0c,af7c675,77789b8d,f3b5ab33,ad8fa145,94c510a7,830f3353,4ac94a98,cdf2fa30,b6a1b572,9222969c,e27eb1ea) -,S(3baed9b6,25f5d0b2,6e0132c6,20a9015,f79bd8d1,8e5ce170,20fed78f,a2238914,6ef88df1,3c7a9023,1180edfd,d041b950,3ad89f22,4ec557b7,2e900bc8,fa820c19) -,S(6e2298a6,102268b1,af97bf67,c0aba783,5463165b,1df8a824,530ee5d7,86d354f6,c3864e52,3bb5cfe0,a64adc7a,9e8926e9,876516a4,c83767d8,5ebfc39a,e125c19c) -,S(f9e87f15,2412598d,775131de,abbd0272,4d658849,cb60aac6,92280e63,8e835e9,e843a3dd,a30f9685,70fcf86e,86206c22,af40ce3a,3beb620c,aa167e63,271d95ac) -,S(f9925b7e,80b8b8b1,b5c56f80,74bd5ee1,9e419678,2c5a33d2,c59f8016,56cfbb0e,3e2fda0b,50aa7671,5810a8d2,2d4778d8,66bd2515,acf87b79,7b2f4875,dee19719) -,S(6fc34efd,5d11ae35,2cca3254,c5f8a040,52b81357,556d4d67,dd02d22b,91f4e49b,f14c656,ec946492,a6af3f2f,56fd7355,71e41b2c,dfeda7bd,ed567658,202f6e61) -,S(ab504458,4b38c846,e282038,1f02f55d,fc6a5648,1b1830c1,e4ee94e3,d11af8d9,4ad3821e,3f5219c,aab31787,2a8fbccf,f0f445d7,da30f05,d9523f55,13eee3cc) -,S(2378d11,716b6d34,85bd5a57,5c5b2c96,1b817abe,e21b7d45,38244933,5ce7e7a5,33682ec0,8c59a158,c4ef12bd,d2a46d31,6abc6dd4,f81a1fef,5be40577,4e03fab) -,S(cfa95425,8608d9b,9c568a1c,fd4b078a,ff49150f,a4681324,ac56b6e9,df569016,e200a3ae,2d82ddc2,a71767e5,842ef30c,86cd9b17,7c5e52ff,ac316e50,1e7e2) -,S(585542d9,a3a582a3,bde74fef,112924c4,e00cafcb,61518d87,f524211d,bdb98993,2035bc19,7a0ea2b6,8d1d1333,b5aadc61,c9dff2c1,e4dea034,1539ff15,9a3d18ae) -,S(fab2433,905e5b46,e47103f2,e353d503,cb141e61,2167cb4d,34946a5c,cd2c06b,7097d735,3f17734f,8eff6993,77916c9,884f67db,42f7a96c,62a3e1d9,9e341547) -,S(b10db548,be55521c,de5edc26,fa39716,154e365d,a1b8b7fd,2265d78b,7edee8cd,389efe1c,7fd8b4a5,4a42e651,b5c06a2a,7c153664,e52ef30d,90eda2d5,9e9690c8) -,S(218a8a36,273fce14,85c0c9f7,1910aff8,64910b00,6254af75,e78a6b5b,3d5c7bad,4a1984e8,e90d4695,b8dcf34a,55eaf568,b0fd34cc,528a147c,bebb052a,8e6e8604) -,S(e120bc22,fe6dc81f,dc3ead1b,a2ca966f,c5702ec,479793b1,5f0ebae3,b6c5ff3,9f92f1d5,e8aa56f6,1ef20685,c8085782,be180658,c7d2b9e1,c020c98e,cd425835) -,S(e83373fa,f80d4560,5ac4da9a,c9cfa220,b2a2c656,26857035,a228c93b,495be15f,8b915652,3c532657,7945021,d6c1b1a6,3b1fd090,ea93cf01,90fdb791,a2397a91) -,S(b7d8a393,a10590ea,91d2a495,eec07262,f2f43e29,74f7b2e5,6ba6ee92,17e3e74b,4ad6671f,58b2c7ba,7a940613,5986b3f3,5a6e13ec,8243b0fa,c8bec130,2afbad0f) -,S(75a5ed46,b2103f5f,ee808803,bf419bbc,232cf5d3,84955e8b,1d4fbaee,5194ca35,51b9670c,4c65e969,a5a56e15,25f33dc9,458c317b,6faf484a,186d52d1,757e4857) -,S(6d8d67cb,c309ecc6,3c1e04d4,aa42683c,775d5f32,51111500,9166c574,b0dd66e4,e127b8c,f431cf09,5939712e,c96d299e,efbdeeec,eeca3d2a,9f6b3d29,fb8f72fd) -,S(51a6d684,463065c8,7d3e0fee,ac72e4f3,1e5187a4,dd14d59e,ef71ee93,85fb229,7fe1069c,b384178c,ae2241fa,6886e1fd,286347f0,d2488dbb,f4d6eaf9,e722a90a) -,S(5140ba9e,81a272eb,30ac5c96,a8b054bf,870b1785,9519cdbe,4f2e6573,2a56e6bc,3b6a2c0e,7421eab3,147b61e6,d8252326,1819bd94,9e3c805f,ca2a12b2,e13599a9) -,S(b94c7812,6c60a3b0,48b28f47,f9d461e,27ffdf7f,93a3ee70,ae38962c,8060166b,bab7aa94,385d224f,f20e7c60,7f7f11db,4ec3526a,c226cc96,16af6a3e,356208f2) -,S(45046678,76689fbc,a94ebd79,ddb5d655,3e97b788,c91cee0,b62ee75c,1fd12ff3,635b3d75,a0621530,d7ff26cf,f1878d52,2864a6ea,e82b220f,d35ae5a5,edea1895) -,S(45f4025d,7b88ddaf,e39566e4,27060b7c,ac59ae7a,526ac3d6,a489424b,d677a54d,d732c322,18307ace,354ade14,21d13438,ac4c7c3,5b5021a6,cea9137f,b47465ac) -,S(c6e8912e,a197f39b,817b743d,deb3320b,558af332,96e0ebb,58c258c4,f1c0d5cc,6e0c8ecc,fd97ccd,deb08f4a,73ca13cf,b48d3633,afb74139,36550e0a,c23f04ea) -,S(6fd13fd,c7d3809d,6a3bf6b1,5208d0ab,5f476e99,57a7fc71,29824154,a05a7dd7,95922641,32be31b4,c34ea614,df6b8c1a,c386dbc2,1318868d,b40869a7,17b862e6) -,S(54fc0732,968b0207,ea2c115f,d11bfb57,b9b28164,4644d82f,45af1100,6b63d0b3,318ef9f3,b2173c45,bba5ffdd,8345a08b,66c8e183,80ef9dbb,b5d80c1f,15f95bfb) -,S(9e6ac718,6e09f698,1f384cdc,b9c48703,a8ee3726,d6d8ee3,a10499f5,e17731e1,95b4c37f,ec98faca,b41c628e,12f606e,79829b17,96ef3dce,c4aba99e,3882bc0a) -,S(85732ae2,eb7944a2,6609aea5,607604c4,c30f25ca,c365fb2,e01c7600,40542ce6,928a62fb,b082f38b,52890540,7b20f9ac,1f4841a7,bde217ab,828780ee,94749fcb) -,S(3ea5ace,80e47aa1,9bf1406d,3559fd50,85d38504,93752563,de66393e,37a652a1,db5fa543,142d36f,fcc1cc8,36b1f4c4,e82d4980,f2b277c7,bec53324,fbdc8e9c) -,S(7d40f7ae,f1866d87,8e42f9c8,d5afff76,2a427567,f6130f73,439d67fe,d14be54d,5bee61f5,31e4ebb5,679c9645,d565cf,f93b391b,f48c5504,a5054e23,47859d2a) -,S(3dc80cd7,478ea38e,1d6e1e41,aca892c4,4e4d8339,acd72fb4,c27861ae,3e7d8664,98412c68,68af56ab,19876499,fa30c8b7,8bfa5d19,b4aea0ec,52787690,49b7e3b5) -,S(2dd92155,81bbbcdb,a1900b90,9018ea30,2e40ec35,cf2b74ca,6065e8d1,f3bcc057,cdb59ee3,b5d42deb,5a4ffe56,46f5dec0,218d0e9d,569cdd3f,b96610ab,2a382fe5) -,S(a245a185,ed85c547,3b78a561,76a32e45,b35efe75,36a1fef4,569f4f70,ba510ae5,93b66fc4,6fde9554,1363bdbd,117073cd,f3f5e406,75fc5710,34bef6bc,47a2519c) -,S(5136c2e4,5004c1fd,615fe81a,e4463153,2753c670,86d1bba0,b3a35bdc,47bbec08,1743f5c5,d0a58608,a66fab55,69f7134d,7fe49fad,2dbee1a6,d01c581d,18f97d85) -,S(b65423af,618b242b,71e258e8,c22f975b,621a8900,9e0a3f12,f9f8314d,7fc6ca54,e3c39b1c,e4159306,e730c2ad,4ecec430,720355a2,815b63a9,720ef623,b91e4230) -,S(d6db49c6,4e68f6b0,59cb5a00,3c826a59,bea1e9fe,7622a2e,6eca605e,fe9a7858,cff0a39d,83e246f1,efad5dad,72c5df0d,62e9cf8f,4da81a5a,68586187,3dfd758f) -,S(ff2f739,8e5aaae1,a589a82f,e8e36315,34ff1081,cb083933,d08473b4,bd16f03,1559e2e8,49dc5aeb,50f3de13,1478fa99,e110627,aa0c4c5d,43ab03ca,dde04cdf) -,S(a7c9398c,5938a3ca,e32d2947,d8e3a58,e42a669f,5cd9b219,d8acf6f5,2cef9bf5,43e2a5a3,dae4bd5e,64a30861,7056fce6,cf86d0b7,41c3b46e,3a3ed90e,98d2d51c) -,S(faa9724a,357b6806,7be30aa6,4fb85879,1969191e,346d5d73,8a85b27c,c6608d72,ea1f8a66,8f4881fc,4ecfc556,f0ca4e12,b93ee6ca,54a0fce,b2fe51ca,174d9713) -,S(28301cf8,328171c0,74cd585f,6e5870ac,815de8d0,9c9f15c5,5540de9a,b29a86df,31910e6f,15585710,74e87f41,e5cc9c73,4ddd15bd,4436ec8f,59806afe,7901c2e4) -,S(fbde2380,ae0cccc4,e044ca59,92be8e11,5fc782eb,c1d49bc2,cbdfd1f5,d7908a09,c1a1d67c,74777fbb,68919bf4,11de555a,6485436f,7e34062b,480b7516,8a03dba3) -,S(59d8ba7b,6c71ba1d,191d4cce,662483cb,9784ede7,d1908e81,815d0a48,4b84bf7d,8a32e968,1ecf963b,3c23a9d2,f382490b,1f229b27,a663f4a6,9819c33b,f9f6149f) -,S(6c3a61d7,1c999ae0,604511ad,23f620ad,dfc7891b,925eeed1,6a5ca37f,b41b47e4,f7115905,c696c2b3,e2b82a30,9728923e,b8eba53c,363f1456,73676b59,9b50b9c0) -,S(8e53027f,8e137bfa,73eb5167,35382ba,ab3468f4,d4227b19,a45c51c2,ef3d8339,2b5ea7b9,542a83ab,a1c402ba,be13437b,c621067,96e83b7a,2cdedc52,2bcff513) -,S(113aa35e,6a5f794b,a56b04a3,d639b1e1,64a790b5,8ff310c,fbeab588,f93be16a,227c17e7,d95583e7,fdcc3ab7,b24182b5,1bb11e91,9f28fd7b,3a2e4a40,4f333962) -,S(16c4c83f,5a06b2de,9d3f39e7,1f0a9de7,af6e8fc7,b0fecaf3,2c82f1aa,fe9a5343,b4cbf71e,c3ad4635,87f8e355,cffe1ea,a19f1dc6,d233d617,776a69a9,ab8dec03) -,S(4d97594c,613de84a,e685199a,ac639a56,e5c15a0e,c00282bd,197cc2ea,90f8fbb0,b9f39a44,24cbb1e2,f77afa90,ec7266ee,64ea987e,80a32b34,483c1f2e,b0c5844a) -,S(b679693a,b3fecff0,819e0598,65406521,1f9aee9c,1ea44417,eba86ebe,32414ac3,7bfe1ba0,ae17291d,71aac3f3,66e5a927,56b53312,a6818d1a,78b7d9ef,a5d01b2f) -,S(a97c2730,a78cf5b7,538b518a,87d8fc55,f95a367d,4e021d23,79f163eb,98b6eb9a,aed1e51c,3ce7e35e,ff69e7d9,3fd3a968,59f0f23a,7bbab9d8,3b60cabd,cebd34f) -,S(7dd4e84f,6547d66b,5e0b204c,ed1d0258,4fe92ed8,6b504ae4,eb1b3d66,d43b8ca4,7956148f,de975510,5e3b5126,f82e77b,89a77b68,ffc9364c,bfb596e8,187ea99b) -,S(5e856d1d,25acc306,e8c1a2b7,a9ccea1,beb3008d,c224b38f,e2f31376,65d07c3f,7dccf6b1,55c12be2,f3da02c9,12fdb666,816558b1,11a2a545,9d88aa28,9d855e6c) -,S(c85ee868,7f507429,e5c26af6,7ef1fe45,e782661c,1fa03aa3,ee9dd9c9,302e5dd6,732de6ad,d071a0b0,b77e47bc,14e176d4,c85b39d0,ac5b4ea,55f0d367,dba5ab5d) -,S(a97ba3a5,cc2d5148,3f65c65b,483b3e4f,3c68e46b,87bcfea1,42aeed8,4c42e42b,f4eb1271,3024d1,b7612c3b,7dc3dff8,ca336f23,5db7daf9,3ca6f7d8,1bdb4a21) -,S(3c0396cf,6ff0150c,5b6bd528,4a05d0a5,3b735c85,125bd49c,f62db5b6,4eaf54a7,6ec02c02,f8d9a61e,6bb38d64,daaf3c7d,5324462e,37e2df8d,4ad12bfa,37fd2cb2) -,S(e36fcebc,e406d2a4,ad42f7dd,cc00e9f3,cf385eeb,58cee004,5aab8174,82d84f94,7c98182f,6edd358e,76d66de0,b45ae9f6,5eb75092,1a25194c,1911bd9f,7e6a1a6b) -,S(171ea2ec,b9641746,7d7edcf,ecd6d85,8577322e,6ebac130,5ab57f33,62eb4e37,9f219970,753a7b9c,e4f0c6ce,5745596a,aca8df7b,a73660c9,10add5a9,d4c533d6) -,S(a81d720a,bf8047e8,ef67bf2,71a13f47,636a5f9e,ec425649,1cbdad65,39652f9e,92b37c88,275c022b,635df6b,9246edf5,5dbd8284,eaa4cd7e,3d3ce6d1,c0ca3794) -,S(fa3b6973,4bd9939c,4b6ecd3b,f0a06327,2dc11345,1bddd717,f17b745f,bc3f99b3,f38a4e1a,bcb35097,7acc8f2e,d7f73f75,d406e7f2,22fdeea,2c12d8b9,e5d2dfa3) -,S(c117681e,b55bff67,feda80a1,ae88b4be,c806860d,91916619,288a7ce0,b31aef86,d94ae124,dca678bc,b69c9421,f295405f,d6dc1fac,de96a2b4,58ba5fd2,72faa032) -,S(5ccc0619,92744a57,683de5e3,7b956fa1,fd7287d,b4516fc9,f8635be3,a0db42a9,af1f73ea,4d2168e1,7550ffc,dcbba288,8397931b,e457ce6f,3f8082f8,cfc5f03) -,S(858b019c,8a93524f,6c86738d,cb10b534,d8caaf86,5c0ce75c,fc9b83b0,7c661a0a,7c59d30,1ffc8ce1,b0767ed7,91f84bc5,60bb8ca,ed3464ba,698a53c,160ec570) -,S(e1e217b8,69da0c77,599dcc38,40fa1d8c,a8d08b1a,4ac9a882,da1476cc,cc76fa56,83f0ef77,905f0801,4bd86e17,63b8c2cf,ab2018a8,9586620a,b49a15,9fc314ca) -,S(15a1ae40,b4fc51dc,554b75d4,db0c2bfd,62dfbbfc,dede18e1,4edbb689,91525cff,4f0453b7,e4e0e99d,9663e5c6,bb018007,b52c8e14,d78a28d,c4a888e4,8c4326c2) -,S(1b9a142f,fc4d03ea,4b079f2d,b05fad98,8ddb2d32,b359967f,c173801f,63320825,59bda7ed,5b691c20,4fc8f8ac,f53be298,ae628954,a8134d0f,dd097e67,be9ff9b6) -#endif -}; -#undef S diff --git a/external/secp256k1/src/precomputed_ecmult.h b/external/secp256k1/src/precomputed_ecmult.h deleted file mode 100644 index 17df102967..0000000000 --- a/external/secp256k1/src/precomputed_ecmult.h +++ /dev/null @@ -1,38 +0,0 @@ -/***************************************************************************************************** - * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *****************************************************************************************************/ - -#ifndef SECP256K1_PRECOMPUTED_ECMULT_H -#define SECP256K1_PRECOMPUTED_ECMULT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ecmult.h" -#include "group.h" -#if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 7 -# define WINDOW_G 3 -# elif EXHAUSTIVE_TEST_ORDER == 13 -# define WINDOW_G 4 -# elif EXHAUSTIVE_TEST_ORDER == 199 -# define WINDOW_G 8 -# else -# error No known generator for the specified exhaustive test group order. -# endif -static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; -#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ -# define WINDOW_G ECMULT_WINDOW_SIZE -extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; -#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_PRECOMPUTED_ECMULT_H */ diff --git a/external/secp256k1/src/precomputed_ecmult_gen.c b/external/secp256k1/src/precomputed_ecmult_gen.c deleted file mode 100644 index 248fb077e5..0000000000 --- a/external/secp256k1/src/precomputed_ecmult_gen.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* This file was automatically generated by precompute_ecmult_gen. */ -/* See ecmult_gen_impl.h for details about the contents of this file. */ -#include "group.h" -#include "ecmult_gen.h" -#include "precomputed_ecmult_gen.h" -#ifdef EXHAUSTIVE_TEST_ORDER -# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode -#endif /* EXHAUSTIVE_TEST_ORDER */ -#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) -const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = { -#if 0 -#elif (COMB_BLOCKS == 2) && (COMB_TEETH == 5) && (COMB_SPACING == 26) -{S(7081b567,8cb87d01,99c9c76e,d1e0a5e0,1d784be9,27f6b135,161e0fd0,3f39b473,ad5222ac,f062cb39,21b234a7,15b626ae,f780b307,9b5122d1,53210f42,d9369242), -S(228af17e,df90d1cc,a40173e9,478fa445,9780dacd,c3f15b90,fda5d00e,1faa1b51,8ff47c4d,a4ba636a,f656da9,12a81f79,6252496d,1e519886,b2c2b073,25be2b4a), -S(b515ebe0,f48fb34e,9e01824c,d90553af,db116579,96667847,5ebaa700,242fd722,4cf08191,510fbf0,51f9e19a,198f11f6,ea31268c,2a6d384c,60557250,f0553c50), -S(c37581f1,35446ff3,e80cde04,ec987f08,5af3af9f,71d87494,99b03ba,dcb8f78c,9e46324a,8d8754fe,fbda7c34,2446cf72,b7472708,25cfb92f,a22a4e73,4f1e9bc7), -S(768392e3,b2ccbbc,21792f2d,6f43c63d,efcc249,bcd549cb,96abd8ef,4ae59e90,5d061a40,ac3f93d1,82f0f7a9,914fff5d,90bbacb9,1965882c,591e89bf,c49da994), -S(a9db5de9,2d96c715,8ce5ee00,3d186cf1,976f6a76,f1be0714,726594fb,6c1ba564,743df2a8,ee73fb4a,47b3d0f,2f2b8cab,5af5227,f232946a,82676e4e,8bb70c8b), -S(58921d8d,3712f640,657e762a,737ccd0a,cece1459,a2ba8323,20b43903,d4953f93,78c26959,7e422c02,c01fcbef,484a9d44,9f635c82,849bc2a3,2a9bf6ef,3e6f1e7e), -S(bae41760,ade541bb,60028015,f6906b78,aa41515a,d995dc40,afa091da,77ae8b9a,716ff74d,ad6dc24c,77ebe31f,abe19792,41d18b0f,43ff7598,c6ea04c6,6899219f), -S(e836ff6c,6f9e02e2,4e6f6bcc,2f2460b4,9de88730,6d69241f,b22fa574,7e100f80,77c41df1,4d87b6d3,de74deca,ad426635,f85daca0,ab966a4,5a26a972,32105c5), -S(c7f17d19,fbbf28e2,543fceb2,4268ff6f,1b85e189,79b09991,7457fca0,9ba1b5a4,23a6d4aa,83ee15bf,f1655575,3e4162c5,8acedadb,4c4abfc2,54b7018,f477514b), -S(79c337ad,8835046e,572eea35,df76276b,84e99172,7bbc68a6,8c0b743,28619a,af6cf2b3,9c6b51c9,f1f92e42,6598dcbe,39da6196,2abae0da,d5fc8d0a,aa16a875), -S(1e77739b,12d20887,2bfe200b,d202972a,544804f5,2b0969c5,c22fbe1c,b8b23837,880c7490,c0455322,a0f1e67d,34b3fd1e,33c1e7da,83b9b047,5aef7bc1,332ccee5), -S(b1d314c1,74d493f6,c36a893a,830d90b,f1e86d0c,6deceee0,edb77ff4,31e9607f,8a4ba010,ec3e47cb,29d8f056,e056eb73,3b6b35f6,4c742d06,9ab832f4,68bcd3be), -S(2498aea6,471f748a,f14e50e6,bc17e0a3,ee09514d,fccbd174,f8a21d02,dd0fae48,55a3949f,2e4188e2,b3d344ce,6f0276b5,99b121bc,358e8fe6,bc4f03f5,a8219d08), -S(42d0778e,27e87710,dd19285e,d531af1e,7064386d,11b1b3c9,fb788bf2,b0c112dc,37888909,d943825a,9610e37a,362549f,547b7c7d,ae64a27e,c34290f0,b4fc5fcc), -S(af09a9f8,3a21b2fd,69ce14c5,495c680e,df18e426,c1ca5a1c,af56246f,d6ea5bbd,8eae43ca,8e591017,62c4cb02,9e5cacd2,58f0fdb1,ddbef7e2,c5765208,107c96af)}, -{S(4a7f72ed,ebd8df1f,13db15be,3ab296a8,d67edee4,37965f03,eb501205,3518ddea,1f8c4dc1,2d0e59e7,7d30a326,fd4ecbf8,aacd5fb6,7dc7169,898a9708,ac46b972), -S(c4d4f8d4,949d1ff6,559925db,f4d34972,af16062b,d59493b8,b1e0d546,c2870874,cd7f93e6,c0ee3fdc,4267625a,a6620540,4f6d80c3,d0f7210a,ce6b52e,c350706e), -S(773627f7,dcc56184,7eabafa3,42fffade,325b8ee2,a96f2f77,cbe675a6,2942277d,fb0ad731,9bff4c9c,270d93d1,89a4c380,218ec9df,1f564228,641ab35c,46526bd6), -S(ff443101,befd0bd9,e1914864,3eceea06,b9cf711b,1405e3d5,3883a29f,906063ed,aa1b7d9f,59cbddf7,bc1ad03c,44c4295e,efb406ca,7960c683,eca508d1,b2a9a2dd), -S(cbfb6813,a6874b65,9234e866,c2875f70,e45f9f76,3d634752,3f86040c,880a2e56,ed85d1a,6620c1a4,85ba3038,d2ee6590,4e27206b,eaa531ec,1eb5b886,8232cbca), -S(4e85c77b,27788563,aaeba139,975f7125,f3c933b4,8d67ba6a,2e964243,bdd7bb51,200a9d9b,3400c87b,1fb98422,3200aeb8,e6a5af1d,58c061f0,d059c0b8,d431c08a), -S(d58178ed,f0ce32e3,39a524f7,ad389f7d,8817f41f,ed782612,45218816,2a67d4f0,4840df81,5dab9596,93f9284c,54bdee72,f4861d39,3944c648,ecd76ec5,6dd3225e), -S(670f8f7,9b66496d,13692558,d56d4cd7,a1eeb0d6,9e5133ab,4f0a064b,7152fce4,1a72206,6f530586,927c2e39,370d11f3,e251bd9e,eee10303,406b7592,716333d6), -S(10b41abd,ed4de2fe,b7a40050,e61e5982,89a8cf3,6eaa608c,f2a82c63,5788f1d0,532d168d,680e9c74,4d5111da,6aab902a,9a0f5283,7836b9d9,585dbc8b,1a407de4), -S(76abd21b,103aea9a,f04b4040,297894ce,a501474d,9d38d30,8ed02cc7,137bc7c9,b5a432ad,9e92935f,7040897e,3b04152f,693c5f2,cc1e1d53,2c33f70d,185318e1), -S(4335e10d,5e4f02e6,f1b58a0d,ffb473ec,15f735a3,bf96c140,50bae78c,37061db2,1301143b,1f29f122,afcd0230,d46b6b38,b154e589,92b7eeb4,16088968,a7d57485), -S(2b3966f0,7e37e771,ac4c68ad,b8eef3c0,977cb895,2f47676b,e658aa86,76057f67,5382a6c5,bcdd1a01,6d79d817,80faf650,c0a486bc,ea8fb592,1cd3492c,42c91c3e), -S(f7738800,b7fdf237,dc7f03fc,43724011,8b53aea4,4d7953d4,276f3b4d,bf5c0ff8,c1de7924,ef8dfeed,c4fb409,f1a15d4c,5e8ab42c,90ea9c92,867b5b5c,f2921605), -S(5cb07874,ac4ffb86,2da619be,4c8fa38b,e8b261ec,3ec73a12,cd4cf8fc,4f8d5dae,549d1896,4931dabf,ba4553a2,461f2660,87733454,ea8eec6b,f671e3de,60c70340), -S(5cc85d41,7b2ae9ac,dedb1b44,ce78d8a7,8f56b878,1a4b3af6,635a55c1,fead3be7,66a48c79,301e57d4,54cc8644,d2e778a8,45d85762,2c10eb98,d77eb873,e58bbeca), -S(f27211c9,a067b01c,7fe7fbf7,7b5d9b0,eb0f2475,9d541457,6eb24ba4,19fd3db8,e26d28eb,89f7b518,e9ae0b88,fadbfb9b,641d3a44,c59c6f93,ec28a541,486e041e)} -#elif (COMB_BLOCKS == 11) && (COMB_TEETH == 6) && (COMB_SPACING == 4) -{S(629bee58,a391595f,eb20c534,4933937a,cdb2eba1,86d49f8b,845c1b5f,4ca87182,8dae4162,73c6c068,2e2aede4,76efa86b,7612c07e,f72070d0,dc4486f1,47e95085), -S(6fd5e13c,a94b874b,28cd574b,726efdbf,143ab108,1089b846,7b5b2ebe,6c6a3c8f,4a4db306,52c9772a,868b2859,57c5a005,d83f6afa,6e65d87c,700da998,ce651396), -S(609b6576,191514f4,83f5b428,500cfbaf,96871b8b,3348fe5c,1a131768,bb266b6f,90abb9c1,1bf184d2,8dbc424a,bbf74eb8,de4e0582,2ea5dd93,7d1e8b30,e5f695e7), -S(b5ec0263,27cfd922,23a46abf,a755e6fc,547806ea,333666cf,a43865a3,f4ae647,143353c,cc733d02,617f7764,7dc29c65,67a2e245,aed27120,e5fc11b3,95ffb9c9), -S(ac1fff6,cd869ed5,ca920544,1ceb990c,ce304998,10e27587,6536dcd8,1d4cd15,67a7a012,3e5ea292,85dedf0a,9f138b80,58a1d23c,2a233c5d,783bec39,b6482126), -S(c1807552,644130a3,f9b8aea0,29fdccdd,59e03e27,ff2cb1f9,9d13cf0d,42da7b13,85e99587,f77a25b0,bc64b882,bd279fa3,5be0262e,c2f5253c,70a43261,bd1fe361), -S(42919187,2b3c6877,c3b91266,79266e49,9fa37a8d,74d094a8,8c4a3638,89c2717c,1e4bd2df,a9757d42,285cca1d,856b49b0,ad481ad,828d826e,8921f744,7e04d6ad), -S(d4b10124,283afe03,4b278e5a,91daf61b,be608417,fc845e1f,9b9f52a5,43659f2,fd070859,75e2bad6,b34e0396,47b81a87,cab9fb,fdba802f,6ae3cc8b,67cc98cb), -S(ec4c2c4c,722a54ae,edc37acd,cb6ac490,3077bdf6,3f2c145c,7eb25e74,87c046aa,327bfe37,d745283b,a385dfd0,8e30b61e,2b4e5499,4432be41,fd3f0d31,c00e9ed7), -S(559e40a7,e151eeeb,46442b86,aaf4922c,12030adf,7279bb2,2bca24c6,67566a05,5483756f,60d26b97,82033592,cec21681,c5b5496a,c47f600,2013e5e5,f2ea82df), -S(c1d2e92,19c0138a,9f0a34fd,acc92f4,eafe13cf,1c004b6a,3175133d,6cc7bf12,8fa653f2,a20c1262,be59c7db,20f12579,b2adb1ff,54d84ebc,e5ad4116,3d2ebc23), -S(1becc6c0,e4861825,576624e4,fa622c01,139d9cb0,50c12062,9b87ae6b,9622245,d8516472,656ea10f,5b23839d,43f64e,85fc727b,faafcb6c,fc9c6e89,bf9c038d), -S(c483c2b3,8ceefd35,a9fa9e7a,da242c,d618cd6c,8b3bcb62,e39d68e,c1effab2,71964aca,9101863a,d7c865f2,41e814ef,3c20face,f46246b6,4a742026,471b2495), -S(3487162e,40c7efa6,92bc827f,9af9121e,af5ac549,b4ab6585,6353d699,a94a3783,f5b29042,28833bd6,e3ce0deb,dc0396ca,42701752,f930f437,d042cab2,8f135c1a), -S(eb3b21fa,f733f15a,b94ee0e4,3378e9b6,47571aff,d69292ad,a1b107c8,ad511d5f,cd95b4ad,b8768858,cb750cbb,4fa64523,6b6fde59,ceb71dd4,73a7fe48,9e5a2304), -S(21c8dd7c,34d3f333,758d1d1b,72748fe0,8695af46,3d0bd9ad,e4a6498d,1d01e9df,634d8671,7b885f36,a54b6691,35c3c026,667f3cb6,f2577701,beb0d3bb,84f07940), -S(608e33b8,14998177,5d78e286,d5c6436f,99623417,4e887da0,a95274a0,d120b57d,5d094ca1,181f8dca,87d1e043,f798bfaa,f1004edf,a470fce0,7ff8b124,328397a5), -S(f77710b4,dbc5f7fb,ac6b015e,956ed26a,6bbfb540,6a931a30,d4215aed,de610c7,7508a762,a7333ca8,ac244d6,47e47647,c62c82d,387d8df6,175fb563,1de83d54), -S(f37040aa,b0347fe,976d5980,cbd83db5,4d8cb90e,7f2d2118,85159911,af769d61,df228dd7,67fa0d5c,d44c3f6d,b09e662b,99faa5c6,688b088d,949ddab1,6f11e42), -S(7bf929f3,25374a1b,a0cbaa50,db47fea2,a5d1e3f9,3c34bddc,ea5c2250,d8252071,8fe2d2bf,b23a6755,50f16760,a6511ae8,4e4d316c,45d7cd62,4411ad3f,c72805c), -S(261bc0f3,a69d636a,b82248,6132bf91,2ab7ca95,e9a4925,b3f68bb4,745ee63a,68f52f7,df1ec349,77856c74,7b280907,cb3d456f,988ff7a7,225c4ace,8457a804), -S(60ef138d,e7086d09,711defff,68dad211,88d7f878,d616efb6,dbd3d498,5b730243,ca7c3297,3c56b178,b0cfb8a,da98748a,c3d06cc0,7fe050d7,3a6a9695,52500f8e), -S(8bfef3d6,4be90cac,8b83bf20,906b4277,75a6d982,23d5141f,b74e3851,50bc5eec,ea8b6b4c,c7c8d9ba,809ca811,3621c72c,b82006d7,81ff5f25,32010fc9,57858324), -S(9ca85f3d,4ba47ab0,e9fc0a28,74cd10a4,a8ba9aeb,ff319405,6140fea9,6e395ff3,41182ce8,96554f45,93768fc3,a656981e,69719f05,5469f9e4,ba79de22,bcfe8a8e), -S(38cd0c79,437b1299,9567999a,f54d4f8e,82a6354c,8a93a5ef,56ca2ff5,8a1ce180,c96f5ed,d78de5,9f560716,82b60b13,f06de5f9,49206258,80544bfc,73dfa76a), -S(be37e05b,9369b159,6b390290,3eb8fa0f,f221f599,1270c5f0,47edf62e,a1d0e6e2,4fc860a7,1fa69a27,fbefd8c0,906fc68f,4713fa2a,b37aaa2a,7edd3c8c,d100963c), -S(aa640e99,b091512f,85faed73,a3ac8ede,ee120513,b661f812,9a046a74,d624aaaf,dfb48ad1,a01fd508,e5652406,b681cc9e,13d0d600,68411dae,72d68061,6f6b94ff), -S(d08bb931,f008a1a7,38a16200,9fbf1ab3,d3d455dd,47f45cd6,617e81,8b8e0245,18d92218,21c9a2ed,bcaa5d26,2b7aba18,1f7f1e,7f2007a9,ec6f7d18,f038d723), -S(4e6ed1f6,c39c894f,eaa53e1c,e115fda,75fecf8a,55794628,d9a2202a,9dd5c719,1bb97d73,2e0e137c,e9c94d4c,763f9a6d,e1496548,904460d,df1c3a2f,73b66c1e), -S(867e83ae,610a24bf,401119d,8e1af6dd,414a7161,52b2ffdc,50f71f77,2fa8409c,d5d21ad5,ef365994,b3ad0533,92df82a5,6f677cb3,8500781b,a769dd50,1f6d235), -S(6031361c,6dffc505,dc7e1887,bc75c1d9,5a9db023,8b7240e4,c254f855,b35686fa,b9a9a979,c6b8c576,11eeb783,8b4ac2ae,66506bb0,a203fdf6,3efa9b59,98c7643d), -S(8502d0f,34684503,68784822,f4510c5c,562ad30f,be29a792,f0667e83,b6f95773,cd0e6511,763674b5,57fac9f1,bb62f9e2,3163a0a4,cf08cd52,a6d10064,d8b02ade)}, -{S(840e41bf,13203a96,f41ea041,1ec034fd,db0dac3d,53b6bbc9,4f8a3a78,d0371235,71b51550,a79af319,56c9b3de,fcb167d0,c3e318eb,a852eedc,78490dc5,fdaaca85), -S(5678a034,a24a1607,d78036b2,23eaa3c3,845c9f9e,7293f656,7390354,2f714d5f,57f624be,ff5d1774,c6962dd4,d14cc565,acae170c,7aaf8c6d,b0552daf,e3bdf48c), -S(722012a5,57ed9c9f,9d737a87,39954469,ca12ab29,9dedbaca,507c1259,7a27c6f1,6c28881e,a0e62453,80d73a7f,499f05a4,d9a9c04f,c2ba11e6,9fdd0b6,7c5d5ee4), -S(70c638d9,3eeab892,8bccf1e4,82368eac,a03ca8f1,b30f7b2d,34258539,8c95c014,f8635082,3dc2a200,67dfb293,891929cf,18a810f2,5c85c169,159a4b44,b190a029), -S(2ce4a530,b5f6c77d,c0c4d891,6e89b24b,c25c04c2,723842d4,29300f82,5e260458,6f306154,4d1195ea,98b972e,91a962e2,95a2a4eb,9be03949,a789b01c,f61dd705), -S(89e71182,851bb441,c0af4e31,cad89dc7,3947369b,fef12eb6,b1dfa71a,72498c51,20b7ffd5,878718c2,2b5bfdc,ac422794,63aac0da,4bcdec2a,8f3b538e,3a9f574d), -S(f01f06b8,da0ba34c,e1045e83,adb95fbe,b76f134b,35235539,6b07f8de,9dd25869,afa0fb5b,45ad1f24,73460f17,5ff4bfd8,f162262,65c423fd,ebd92bc1,72f3aa7b), -S(f0c217c8,1dda2201,1f46648a,e096906d,71fba006,1b4dfdb9,85dfe59c,9d8f1894,d5ddd6b7,bdf2a6f6,cba166ae,4c01c60,b012c9ee,ad954a46,6f631f9f,928b3fc), -S(bd9acff2,87cc2a2b,396aef61,b0937a49,c43a2366,a2c3c461,c1283987,a7b6f53,828de0ad,b9067b2d,8f8fefe6,ce3a5c94,e7d63ea1,7c891d2c,5f266e8c,a5fac116), -S(ee314d97,2b9c10a4,fec9f8d,ccab0015,d4923e52,d915eae8,b319911c,7a8fe379,82057aef,ff05c496,ba8b4753,c4e57832,aba9a724,adf70a9f,1b3765ef,952ab52), -S(d39fa7b,9b87ee2a,aa32454a,13470406,c8024c39,cf387143,3364de62,cb94c103,5cf1309,530f9e09,c9b38ad9,3a778ec5,533f60f6,4a42e31,1cd97c2f,c984b9cc), -S(5ab1a07e,5f6aff68,16780e5a,23c9faff,b29cd7d7,5bfb8984,4834fb6b,c6b34a14,deac47fd,6567023e,b5ec7a94,a0133bbf,158c0425,c0a6d288,23558986,314d54bd), -S(b1a4ecc6,94bb5212,98e80464,cffacd32,331ebc7c,4d545141,a129b522,a4818830,9772044f,3722ec57,d76a049b,2afce2b6,319f0bbc,b17c7f06,175a288f,3ce3534d), -S(56015e42,81aed744,a0859e29,eb913a7c,b44ebd39,2ed8c0b7,1eb42f9c,9c93c8ba,8f973650,45f7d8a9,24a276ac,20056895,fb2b0aaa,4b35468a,a51f41f,722b9d33), -S(7d99a5c5,21543229,c8f9c7b,50dbaa64,b200bf86,47c71b35,a0105dde,2b3a8e0c,eae09ef,3ffdec8b,9a30291c,244c0a72,6466c26d,fe2c8d30,174f57fd,ec6aba60), -S(ab7d21f9,1e7dac68,afd6e4e4,794551d5,55a9f42,59825109,5b25652e,946ebdae,8805a806,710ed7b0,fb99ff30,130c074c,6a0be3d2,abe6e155,f9c07496,f8b92454), -S(b31a5f85,d65e5200,8f5261cd,fd6d36f6,4b2a1f3a,6f08d7b8,defc7e84,21d0f7db,2e6d46c3,3733b3b5,597a133f,7459ee2b,570ba333,4d1e7648,1980dda,1aa8d2d3), -S(30af789e,850c8ef8,9eeb226b,27786679,442a9a0c,35cb7337,98345400,29220fc5,f6651170,c83e24e1,eb6e8da,ffa0b0bb,a6c53676,72558d44,c5b77176,3d9b5d7f), -S(8d87f808,98fb8007,ffd5093a,bc6bad2d,23e09e90,e6967031,48d5418,4c60e0ae,3d14332c,21df527f,a2e98243,d3ed4bd0,6634d799,9f62efd,e8d6c919,8ed716a3), -S(a961c219,eb9ea127,205af30d,909ef732,8cc599a,b2080966,f615796e,1126dd98,3e235ae0,37b10074,32e5cee5,56778856,1d552e3e,bf40bb82,5b527cac,8e1e5b9c), -S(b9c2de21,40cea728,2aec5293,bb77dc7b,550a72c8,84389c05,310651bc,7570f2ea,74171cd9,4a5683b7,5bc7c5d9,b4c8fc10,1fecc3b1,b7349ce,840b6ca4,877fed21), -S(cd041ff2,e8191946,8fd7ef0,c33021d2,9533cd75,64772252,c686f718,7e33166b,3f54a9af,e8597bb,faccbbd2,9280e60,93d31bc5,b366aff2,2c95e21b,fbca6041), -S(adfce0b5,8a9cef85,e690b84a,c7ccc6,8f5aa4de,ada5e265,3720412b,e1f19ae,8ae2dcdb,c6ce83be,825593d6,87f9afbe,a88af079,564c60d5,c9b88898,897515ea), -S(833a50c2,cb5507c6,60bd450e,cde341c9,64f2809a,e400215,c52dfaa0,9825df96,de85e216,493cdb4c,4541f720,201f4c67,1472b6a,d61cf8ea,3cf54ccd,a4584b77), -S(3475027a,628ea423,2d689d70,d45e975d,39d62303,282b16b,1f94a427,3d7ea746,97c3052d,9270df78,6efbd2e7,beaa58cd,f864e28,905e3ab5,507cb9aa,e3c69160), -S(cbda2707,e61d9e40,124668ef,7ed83973,dd293dfd,221396a8,d27e7aa1,392edcb3,fd5023a8,af8eff08,f0e3c8b9,b6a22a99,b3ec3aeb,7e0104dc,1f8409cc,d83d8a02), -S(963722ec,aced2105,2bf447fe,619a8532,dc78816e,2e17a111,3ffc601d,9bec0381,f31feba,259f7d0e,3c326c69,53aae60c,1e0479da,5ca839ea,77c6f1a4,9419172c), -S(fc531e1d,49d2a984,83c861b2,b299b8fd,b26831e0,3bced6da,5c4449b0,18363be7,9f9cc9b0,8d72ced1,998c6329,a17695d9,c94cfc76,ba9f6943,1c5dab83,60f2942), -S(dab255f5,b47d96d8,ec5272b,5cde4ca4,33070920,84aa4866,d53b674a,330aea2,feeda13b,a544f090,b790514a,42064cea,509bb3f3,9dbd4567,6bd75414,37579d7c), -S(ac5b161c,fcc42998,71b49d1f,8cf35bd4,dd6bf98e,5f84f2f6,420bc363,b9cac257,4511d4d3,1fa26d7f,e56f671d,7467bbd0,41358b36,b60775f8,65f7d491,3d17b685), -S(b62fbfcc,2aca0706,b0fe67f4,ed5d96b,4a65b048,f73e8f4c,9782e1ee,36189e31,6549e8c2,f77bc824,4e1a90b4,e42ca64a,5ade1768,a0996d69,8d7b047,7bfbf862), -S(56938443,5e509000,5cf3dd18,ea629078,e15097e9,da7bb5c5,737cfa0a,a40e8818,f86a1815,4f379054,11016994,9b2eba6b,477c32b8,b68091a4,4b14990a,5e8eaf92)}, -{S(7c028bd1,75367939,74871a6b,cc957d95,3813331c,87ae606c,17aecbdf,a704ebb4,4fea040b,a0ef0319,91ff9b8b,7829c0c3,93895439,d506c5c3,1a1a3fd9,e32e7e59), -S(24e966d0,bf1227ca,11eb8fd7,8dc5369d,2bb9b681,927990b6,dd02b948,fc18a169,72b7fa7c,f929a6b1,c556a372,4149a279,8d57f504,4b50a1a7,922cfddc,17308ca7), -S(a2b7db3a,265b30aa,94823577,6d5ea839,c4fe564b,97a5e3da,313f7fc4,5de617c5,5e895546,a2778162,4a91ea4e,c104c911,85f3e954,f8378fc2,bea41a3,f1cc9e15), -S(e365c695,449c9976,cb67ede3,325d9229,ee526349,e6b255f7,f4e72184,6722580b,eff99cdf,a0920505,ac37e46,b812d47b,31a29113,e491208,a19e3edb,557ac2e), -S(c3d90905,297c3a65,2c6c3d5d,915cd9c2,d741f472,4a47c8cf,35e5cf3,cac9dd11,8e9ebbd,34a7dd02,24fa6e33,193cdd72,4906dc81,a5aa41ee,4a34d3d0,4b2ee5b3), -S(6e4e23cd,ee4388d6,e8b61f8a,af7678d1,a62b3e1a,3385d278,895a02a,de4c9f00,f69b843b,ae39cf41,11fe9b99,a0287057,5695421e,e1ea690e,2e76d937,e7e32c01), -S(92eb38a6,3743088a,39b58cad,4eb4a27e,a8b08c27,444d704,6d2aa5f4,89713217,22af8d6c,d3567a6d,cf7403ef,e0afea02,48ea4266,1577005a,9afb5f2a,19611864), -S(b3c84323,e2d022fd,d2a80d07,203f4a26,f5d32dae,62842072,9663a994,3a829d08,9a899de,82329d94,83b88e1e,1bce53ed,8714cad4,c68cd491,1b71bc0a,e3839821), -S(daae5199,57a6002,8958b22e,6dbbee20,c4bbd8e1,7ed589e,b8528f35,7a4dbb40,afec8a03,321586ec,ac38e941,7fa8e342,f0542193,59decf5e,56479a39,c32f92af), -S(7afb9a56,89fd1344,cdbc5c72,62dff7b,718c2e47,a6e19ec,665af795,86ed0161,d1c2c9cb,60a191a9,a3db7e20,2ebc2eff,444bbaa8,d81ba086,6f8825f3,8c765f53), -S(8d0c4a2a,e72b54c6,236d997d,61a2a24f,ddbd39c7,ee16f1e7,d7c45b22,b4bfdac8,15a58f4f,fdad9e3f,b4d33c7e,170747cc,6a5abfdd,bfbe5814,ef0c3611,6a0a9e91), -S(24d8c0ca,53400126,347e67f3,72f19298,595b6d33,76ba2f19,2fba6dd1,7b57bda1,7c01404f,bd316814,f10734a1,559049ca,d6f20e90,d6b13ed5,f9542630,db77f9ec), -S(4c2b7a58,87a49df4,f98cfc72,22fdd832,362b8cc4,c5f4fff4,d0a20674,c9749bde,c2a1cfcd,e8636288,31a5c450,fb5cf552,c76e581f,9274e5d9,888a3a68,c37ca349), -S(2028e381,f42cc2f7,a8829308,bb72881e,94e5b54e,3331d848,898ccabc,bf971cb,16debea0,203f0709,d9b55b0d,2b8651b5,cb085d8c,8f56708d,c1fe4d33,a616dfab), -S(d11e0753,f72b7c4e,641ed50f,84dfa24d,a0baea77,98fcf062,8b2696ba,a7ec2529,55af37fe,88324646,777387e5,a9b18059,ace20e9,becd7488,5e43fee5,fa6809e2), -S(72309865,b8a1a6f3,9d6d561f,43ddf5b7,f2d022ed,95df130b,2563eaff,9008a95,f3fca0be,3ce7d9eb,e1648964,58eba87e,934d000b,a535f223,868dae11,dd5230e), -S(adca4785,cbf38a0f,28de7b36,daccc761,89b8b918,f3fafa7b,abbbd9b1,4ed5485f,880d76a6,fbcce864,657edb9b,349f124d,1b22c7af,2b0ff833,40d7a0c4,84b49de0), -S(bb43e0c0,93d58c6f,3946e58e,4727d7e2,d223c84d,513c4e2,222406bc,aafb03c2,c00f7dc8,fcbd55b3,6a95f2f4,a3a07b7f,9599736f,af099a69,e2fc2630,a2aef1d5), -S(179eb588,d1c7aa5a,24e51f5e,6d86e4ed,2e6f0f98,bf956b71,ec1caca1,b7f775cf,42f461c8,a784f643,d5a8682a,6ec9b470,455f0ab9,f269140,b1ad2376,95f64afd), -S(9144fc75,b00f8608,714f027,16b30575,be19dc01,d3689e8d,2665d967,6a077d11,b168c324,7dc6c31e,8302b6df,a2e7c053,dd849538,f9d45b87,14d889ec,cc789704), -S(d6cd2a7a,b7253b86,34231eb3,2793f062,bdf103b2,4fade912,6206e745,a3b429a7,9903e507,dc5e3a61,d73fc83c,5c4ba476,6ae92655,9b208369,bee55948,4bfe444a), -S(264845ed,623bd3f3,808ca51e,517def45,1fbc237b,e47e3ded,70c3769b,391a9f83,cb5022fe,3d535f4d,192e73d8,5d9ede23,78e0824c,e560a97,d53aabdd,f8717377), -S(2df9621c,cf3e67da,54c47ddf,81e3ba7e,7b50e713,cc7d08ac,d64f47e9,85c4f334,8058f6e8,139d8e87,cce4a389,c470e3d8,45da3537,ccead4f3,abbccf42,a5fcc49f), -S(ccfd6c4,c5966144,32d2efc4,1ccfa0eb,3e0b44ed,a4558128,c3e4d68d,949a5cac,bc77b87b,5f50d3a9,6b28d5cf,fb371b4a,36cc1360,15c548b3,f98d661a,beda8acf), -S(4e2e6052,cd35d585,6531fcf1,73bf124d,3c569bf6,6cc54ed6,9a520d42,cb836296,6381d100,e5d9ae50,f1821122,b8e91a5e,f365edee,556fee1c,2fdb6d17,3fd29c65), -S(6603d715,ed0f8725,7d9c3f29,cf86ad4c,aa0500ca,fa16a708,3168e265,b87d0255,9d2eda4a,6195e2c4,a4576e4d,5d02383,a3a01b2c,f94ab8fd,fef2f338,15807d31), -S(f09ef30d,fade81df,2fcafe31,387ed34,5a8029cb,e93fec3b,eaaeb8ac,8adc9803,f9f3039e,5b73c7cc,cf841eb8,1c15203f,ba192e,9eb39aeb,36f56c29,44b286bb), -S(ebf4611f,cb3a44a9,f9d5b00a,c559dbb5,394840c8,41a06496,bbd2011a,2508cc34,1e183324,9a610584,5d62ef4b,685152e5,c75c7525,c703f81,51bdd87c,6fda0d43), -S(31fc3226,c19aea7b,4845ff2a,ddeca6a9,36505a49,92102cb3,499d66f8,a6e1a3b5,49babd41,b1e8a6c,a728f971,d8d8cb76,47cdb94b,89767a67,fd975ac6,93f144d1), -S(be1e37d9,dadc4b4b,7a5ba74d,fb7eb55c,2b0a4fdd,81564f8d,51038afe,f716e3d2,de6f0c3d,b6efc974,975a7d6d,3c6e9d44,a712879e,4e95c612,164273bc,5de1f4b), -S(f8034e14,2425cdce,31e82b49,cde33ba8,3630d1ae,283b8b47,73960539,c67f1652,a302e3b1,860252a5,e7114568,748746ad,1e02c2e4,280bc913,dd4b4d2f,92a561af), -S(21e709bf,369cdb2d,b7f51b10,f0ff56c1,2c1938d6,18419d00,34e57d94,7b83d5e2,d7e09ab1,2e7d04f5,aab3a75f,8cf75876,ddc3cf0d,cb4b9526,ea7f755a,dfe1e495)}, -{S(638b6618,c1498946,75a1a943,8755a68,30d7dd3c,9d8a9f20,d65a7161,9c8b477f,e4e66035,e947c73a,c34a48b,b43a3762,d1038e6,893dee23,cf658a12,190d2a56), -S(4b6ce93a,acd4954e,cf0febd1,fc9a965e,ae7fbc1e,e24a12d3,a4b86573,62eb255d,8cea4838,1bdf4e5d,79e25ed0,1aab94b3,5f00267b,3ec7eeb6,63833507,583407b3), -S(e2a42110,3e8e2a80,a6451f71,b348434d,7d508023,beeed16a,d87417b8,5c7b7913,5fc15b62,124014e7,fa8f95cf,78ce8415,d46a1f97,d88be55a,76431786,8de3d605), -S(6949956,91582c2c,2e14576f,5ec0dd37,65133237,a4e43369,633edf69,933d1f75,5ca8c2a6,329882f5,2daf48e2,e291c48d,febbbd29,9ccc9ff,3ad54ed,33ccef43), -S(55d836af,2dd4b8a5,7f20eb57,6886790e,a3ccfcf9,2a2940b3,646f263d,685f62cd,7cc1ffe6,37781c72,d3cc26dd,9d4147c2,183c8e0a,95b87742,52ac47ac,19db266), -S(442a3090,46bbf3ef,503a138,b60ddfa0,ea4a5901,ae801003,f3f18ad9,9703a44e,129d9913,eff78c49,16e67c4c,cb658784,fa47da35,92ea1c98,4054b371,a275639b), -S(76981efa,29944c2d,9463fc94,67a92e1f,9403c287,dd595292,4860aee4,b78626ca,c87cb5c9,ce93ff3c,23189404,cabf8e09,996c4cde,e67935d5,874c705d,6a7f95ae), -S(42ad08fc,2a1eafc3,d793f04e,304831e,c1bae89,c7d00b24,7785d870,904bef5c,c3913fd3,6b8c08c2,553b9c48,5b90221e,ecdc8d02,6d558bc2,5fdd6ba3,df78ed63), -S(4d70ffbe,efc6254d,cee74a89,70244bd3,384b3af5,8510ca61,258fcbf8,f0c82575,ba3e19d,b022a75b,c75cbaea,84ff912b,867124d,a20e0d28,a007fb74,9a9d1c7b), -S(4ec8dca8,7079487c,adfd516,da2df139,5477b524,df4aa6d6,4db5e206,cfb14b9f,e88e5bad,c8654d60,fe1f8f6a,73328209,63bb10cd,31aae381,ea1b4d9c,eaf9cb27), -S(2e5a47c9,a47cbbb5,ef701784,34798a6c,48244df9,dab1e5d8,83c7f732,b89c7d79,7c8202dd,cf7fb6ec,471856d5,830d59e6,99c04377,c553d835,f64cb333,cc405c35), -S(3ca98150,bc5f116a,e7034a07,628d698f,67cbb8d3,74869ab1,534464f5,5e8ed24f,fad702ec,c6b738de,5b653f78,f51c98d2,1e4bad57,4db97730,58324d1e,12b89f9), -S(f414495d,9093ad22,11e001f8,b07b38bd,f5430a11,72899bcc,2c553b55,a9d4a225,bc130e93,998db229,6aef128a,5b8e5b9,9cf67eb7,713aa7d9,9fc4c902,af660f4b), -S(44e794c9,5a28ee80,f9b64193,9c626a78,4a851a4f,84f28887,9eaec508,1b60e508,b219e000,1b07a275,f63dfb3b,e977a40a,f505be1e,d3eb8194,b919b9ea,70d7198a), -S(35024622,bc17bec1,9c352280,297ddf7f,41654c08,61c3744b,13c74ed5,6673b98,64aece4c,3ec0b19c,cdbc06b7,4eb15704,50ff689e,6c5bafb7,6ae99396,12f4cca0), -S(45c4f36c,ac4c4738,ab216363,e12b2475,50b8ef09,7a986ce1,60b0462f,f8725a58,fb944806,dee59834,7d256885,3761e3a,9ae666b,9b0ee095,fea33ec7,bbce9a5f), -S(20a0b4f7,cfb58bd8,d09d008d,70e7f807,b4fa61ff,65f2e15,f00bddeb,55df1124,7961d1de,e98ca40f,4d09e5fc,52ae4916,cafdd6e,2bdb9f9d,2776239c,a3480157), -S(fa10af8c,eb2de4c9,3c0c2cb0,95f95911,755b19d9,90f17e33,69930d6,6002fcd3,68a3bfb4,533bb5f0,54fbf91c,b771b08e,e388a61a,9727bb7f,a3a1f67e,60b2eba7), -S(d417d7dd,30ebe9f1,7d52edd6,c82d91f9,25d5987f,a6f53b0e,d769a34f,e557c11e,ea89c810,619e32f2,369258ae,8ad8a456,cc36d87e,b45a42d3,83956039,62e437c8), -S(349b002d,ecee0e4,1788a3c0,cabb9ff7,c17848e2,78ef8905,63924c55,52d59853,47583a2e,7ff61b9,6fa168b5,1191b363,efa3e0a1,ce825a3c,5bb04e5b,e403b4b0), -S(4b8efc8d,7eeb3554,b5128e8d,ce20c29,697f79cb,29f61b4e,a2f7ac28,57910bb,e3cef657,7b5c0d2f,dee52c96,b6353073,b099fc9c,65688969,24cd744b,981c5ff0), -S(f356e8cf,5785b05e,e99a2b4,d202b64,2b1e98c2,57741e60,7241fb9f,d3f5ea2f,9079fd65,59d5a93f,91370d16,20ba487a,a8c6ad3d,e67f2c83,a1c335,fb5398a2), -S(bfb74aa2,15e5ce36,97cb6156,c2666ef7,1b579a50,56ff60ba,d3d5e10a,7eb2d31f,3def8a80,ddc3f407,e30d11fb,232f0e31,191bba1,d51a7eaf,b86d7f97,45d78dce), -S(658748bc,bbc75ba,30c969fa,371fc1d7,76c32a5c,7e632201,264deb36,b296ad2a,c173fe4b,14ead07c,2c6574c,8887500b,53f6c02e,dbd4048b,e69aab41,9267ef9f), -S(f51a5ca6,fd6dde25,447fa46f,c0984d26,66004c02,8d402624,8886d0d4,604f6ad8,fd4290e1,7b2928aa,f2e03b98,97252b82,d481c4c5,ad4edda6,16dc1cd8,e7ee83b2), -S(20ef1ab3,491b8d0d,a1565e2,8dd92dff,efcb88f,e88c6c2f,6b100b30,b58249b6,6814d32,7b5b94c4,12fb770e,2fc4077f,fa9a336c,9e7db2a4,bc7dffa4,286eee0), -S(d98785a,82dfe5de,343bea0,d91cd8c4,93344b86,7fffe1e6,efd7758a,90cdd899,37ad7f7c,5783d262,5204bac3,4405c207,972b7fb4,cccc3585,ee152f0a,48ee16c4), -S(3885e910,18a66e64,2d3f0c76,bca6dc82,a6916cb,1e46a858,7aff5ea2,d9390689,20765590,83ba89c2,14be9178,46e40553,ea195c49,de203c9,d175296e,a4430819), -S(c88cf650,3b50f5eb,7bac15fe,2097ff76,9c57b983,1b5d05c9,fbd8dc58,d4a9a746,b6443b76,64984192,e7056478,e9f372cb,21a0c7c0,cfcb0e84,850443a0,25ff42b6), -S(2831fddb,2ba2d301,2dedd58,a3f47434,3450985e,80e4e4c1,646745cb,1abc69d4,1b04e1b7,db84b6c4,882f264c,7bba91d5,2256dc97,fdd22e58,483dec32,5020a257), -S(5e492bf,c9d19dcb,c3bcb9a8,b7bec84c,23c359de,a78aa0a1,e0522232,df037abc,614fe5b7,cffedd76,35d371b5,2d89baf0,55af687d,e6c12d80,b221d0b3,9d03d0ac), -S(bbc64d06,681957e9,685c9864,c5f9bfda,34b4dd02,6b749399,a12bd8de,87f311e7,3c525096,dd6b7d11,26c6ca50,5064da63,f7f6a203,87594f4f,e4ae0403,fb4d66b6)}, -{S(2b00c7db,16887372,753ab219,17092563,8c603992,f501b07c,9d8442b3,721addf9,8e7c5f66,4c2493ec,77cc74ef,d9221235,f26bd3bd,6f505347,39f0fe19,c41b9fad), -S(56b9a3eb,d9360224,56267f52,21ade9f9,674863ee,4bacb7c9,ef0155ca,b36b336e,2e2b1a4d,f6c150c8,6dcfe9d2,e2836579,f82ac4d4,2f8fa4d5,d814b952,e92da69e), -S(ff52bbc2,83bd15ad,523e6d08,873a8896,9449a1c1,c5ec8570,ed532000,5a92aa3f,dd9c534b,e59d3845,a1943435,1a20513d,1a829424,e65ed8ad,60342b38,6578b21), -S(84f79356,86b0d45a,13a1ce22,7e7c925e,d80be5d9,9fd7e671,270c4c35,7254e9ce,3dfe2058,1e91dc25,12c16951,c667fbe6,83192bf3,3fc0bdec,c760dff6,730f82be), -S(db14da0a,86bcd275,71cb9348,36268bb,85c306c8,9ee1b78b,83c247a1,71c7355d,66ba535e,81e877b4,71b0b75a,6545970d,6e33cbe0,ff011e3f,d653d026,f4fff395), -S(28bfbd9e,44554371,74a4c24a,cc65ef45,5fd4d39e,b466e94,358cef4b,b0eeaa5,5f5ce6de,2925acc9,e503d731,d46601aa,7e668001,669819cf,fa54b3e3,dbb98f32), -S(a7b21a3f,a07b4049,7f9f5087,c763b431,d5f04cd0,e7b7e0dc,f9c6c664,df7c6ac7,daf23f35,b903ecc,af4f50cf,459deac9,85d0d008,3b5afa73,7131a61d,8591bf9c), -S(12fac42a,40935aa,e881894d,245b9691,cd1f6ad0,e0481e1f,444e0ccb,6ee88781,c519e0b9,e3c19fc8,f67c07e4,f357f43d,589ec23c,7714f7a0,4347be96,4ca572fb), -S(5c2e28bc,94f8639e,50133dba,9b6c8a35,348eefdd,2fdbc18f,2abb792,eb8807dd,c546b3c2,5f2809e2,7977a8e2,3a1c3ddf,36229f31,434c90e9,1386ee84,b64e8fdb), -S(e8e73382,fbe8b94e,58bef90b,aeb28305,d27ea48d,9c5f6e08,ef47e4dd,5fad6b78,d3529a2e,86240f06,a63ba03b,ce419c05,24d22622,fab9107d,aaf3016c,6ff7fe3e), -S(26b93629,ebe68d1e,878e94b7,5babd663,6fe1f6f8,659b155a,e10801eb,c2cc51d9,f4630056,b3e532f7,32238911,555c0ffd,f4951c9a,b2f45119,cb12e774,aaa2666), -S(57b3b642,431f793f,24862328,dbd271ae,19d343eb,c3b0ca7c,affe4fcb,319d8d94,1d7ed35a,5abc7e39,1858a9fd,b90f907e,6a065648,c00f94a7,75f06d2b,1cacef1a), -S(c2123794,d98f0311,c1327522,1767236a,6f45cb14,8fcd65d7,e0be8d13,2a650953,d5a382f,fcc2ffba,3917763d,ebe0549d,66f358b,d727c281,288551f8,4ecd193b), -S(16789662,9208b510,7528efd1,36036980,994d6c3e,5b34c69f,ef3b86a4,3db9e8f2,217105f8,39b0ae0e,932b5207,e8e7c190,3ea463c5,40c043aa,e4f8b106,97ccc84b), -S(3a0b8ffc,83a1702e,214adfc3,79bec5a9,753274ef,9e3271ca,8ec5b067,a5f3b6cf,2c3de01b,f27dd574,4496c2a4,75a07e60,71ee60ef,7eaf1c94,c257418b,744d1338), -S(482e5ac2,6477feb7,6c848d58,40173d87,1687c5b7,3b2970ec,b8dd69e9,3393f923,dfb3995a,ca5b54a3,b48e1dc,107023d4,dbd7a918,6adf2af0,61f92160,76e7f78c), -S(3869373d,638a30cb,63177204,bfb194f0,2c6ff503,3cb4ef1f,b146741a,f3b495ed,f2ac9f3a,ca159c7,c2ce9f48,e895c543,d3f19066,74f335b9,efdc4b47,4ccc23c3), -S(98c16ec8,54b34ea2,f08aa4fd,3ce1877d,4a36f2a6,4e673191,17f74e5d,86e57f4e,3448646f,c9aaab0f,4d9ec298,8f7c07ef,448888e7,6318e0ac,552d7cc,b59820a3), -S(1b3a4ebc,8ad1c200,2847e182,de7c9eba,f0f7a408,e2aa172d,484bb9d3,ab897b73,b93decef,69cf2da4,5c3a2373,ac2abd77,311fc1f9,21e7df8,5f5b3504,a5ecbdb4), -S(57b5b2d2,87bec103,e4aa7b96,16129718,64780441,fb5ef847,19f16d,a1c909fe,2c2d983c,d8c37a7d,653716e6,15756121,9e5ad5ab,25664967,67a0fbd8,e8180c71), -S(cd7e277b,ae1498a1,8e7bc00c,2c299a49,69f6862b,bf96e6d9,f5143db8,7b582115,f9548ddf,c27108bb,38f80025,6ffdc25e,28621c17,c370a40e,5009b968,d40660bc), -S(80615f12,82ed7a8f,bdd70890,77c24f18,c03fa395,3cbea7bd,32a26c7c,260102e7,8d54a3a2,83383d6c,a633d17d,e2f4f756,3bcc3826,10cc1012,3f2f192b,e654c2cb), -S(9b16f5dd,c8c8c8d,53786b49,e2d025a6,838f6322,700fe105,7de6d78e,92281a9e,a36aa3c2,f2034285,76f5c570,63bb1bd7,e6e0410,2e1cd2dd,f100a54e,431ca08f), -S(f1d04075,35ffd40f,2a0b59f9,14ecf368,67700c5,b33e15c5,153fa9b1,c724d36c,22a8b48e,4db1d3d1,28cc735f,99db74d9,ba7457cc,67b8fb39,7b38fcbb,153f7c0a), -S(c252ae6b,cb711704,659c37a6,f425b215,1ac8a4c6,63420eba,899127e8,1d8df3b7,8e9a75ab,c5a2cd8c,d44331ea,b07e5d97,a30c6619,8e382261,642c0e10,8f6d46b3), -S(59f6fadb,4a8a3389,999b93d4,cdf1f8f0,4735b397,9fa5397e,64df420b,85876ed5,c6e8baae,fdeb7019,23a68b71,9c88596f,60742a38,db04d7e5,76bd1b8d,1ae25a6b), -S(3c2e03c9,3f610ffd,db519c7,80c201ce,b58ffed8,ee10e21f,d1610e99,33fd08c7,d339d979,38e1c5de,7492e7d2,d64fe34d,ed889d48,54670345,1c51432f,ec6c829), -S(59d16070,f9147ce5,5bac599e,aaace0ef,24c02ea6,85249cc6,ccfbeecb,a4bba83f,8105bf41,47f22f7b,18c73941,3a85ef06,40bf6805,51c68a10,e16be920,193977f), -S(3aca1182,3f31b2b,a12e628b,604b1010,62c45fce,22e15dd0,8b9b5ef9,a53dc02,bdca8ab2,d2dcab6e,3a98e7f8,7e192c19,cae60952,fc6f54bb,d46acb49,60d51c0a), -S(261e9b93,3648c7d8,d5255219,fd0634eb,112e1dd3,fcce0a04,135b2784,e67b5e32,e0eb5ec4,30b1f9ef,2bd10916,b21f4fe1,4cfc80c,2bc179e0,fceb8678,ff933068), -S(75918e0c,a0f03b34,40cd6239,c108bb72,f293a881,a1f2e9a,73c604b8,8c451c39,7f02a925,80e50aa2,5b786d10,422f1d80,2c42cb37,27f09ff1,1f5e0dd9,bf6a6c1c), -S(42025e76,3c05c64c,311a275d,d6f1fb3f,2da2108a,39ed24be,3de83123,b1c1d1e9,dba2eec,7405b67c,a1915b13,45702062,7bfeebb8,6b90dbd4,87849e5a,756921c6)}, -{S(ef2c5fa8,b23285e3,50d7f05d,bd8c96bc,6e662824,5b10e1cb,4b659bc5,ded5836f,1b37679e,1177b653,8975790a,4d5d2abe,3626d636,1d863e0e,1db5881e,8e0c54a8), -S(a1d5a92c,93df3c75,a06f9c2b,a604789d,fd487513,62d957be,68c033e8,3e202fe7,64c1c00a,3964fd5,b35fb52,b423b285,77c8d269,bb1ffd16,325c5e0f,7be08bdb), -S(ef13ec66,d46813ce,68038fcd,541e5e8,bdbc970d,337d7b5b,9099d0e4,3fa4288,7ad7f4f0,c8345229,96341248,b1455ebb,89aaeb6e,1ae9db25,1b86930c,9f779fd9), -S(aea7cf4c,afc1079e,e61396b6,2df9bac3,bf334745,54af4678,8621e337,4c7486c7,c0538605,5911c893,459b98b0,4be449f1,2e9f98cf,ef4cc292,9975d42a,f460d65), -S(8f082b3b,6476b4e9,ffb317e6,1fec0cbe,8e389041,1fdc87d6,8d4d26f5,44c2e6e3,eafc2bd0,d6570a7a,cf8bb5d1,6cdc1020,456473c9,e7fec1b7,fc6217cd,89d0a2a1), -S(e0d6310d,e5e664b3,164faddf,39c93676,4ddd3f0d,f5e007ef,5293ee35,980ae0cc,de093cfa,ca1033bf,47e88723,4978758a,74b93cc5,2cef48a3,daf4dda9,adc79ccb), -S(2518110d,5d064422,5ead0e2a,5ac8b8b6,b1fb7fe1,55e351c5,1d39673d,dab0f6a7,84f0d6e4,b497043a,95b6af9d,e72cd502,a7b6a68d,ecaa01b0,9e0d8ff9,9d8a16c9), -S(6dc820b8,5db42353,c97453eb,d7d768cc,af9732d7,c261bc6f,8399caab,34cf5b93,30b168c0,2509e2f7,2035f60,8be8b89d,577b6e72,540f521,934fe980,7412459c), -S(bddc1c75,5bca9911,3c9ae05d,c14441e,2c707fe5,8a329f8d,feaa36ff,12771376,8c0087ca,b7688dcf,5a3cf1a3,3c27c7b9,cee36007,3aeb9b9f,d7088623,af20f62a), -S(b6e5ef5a,a84c6d2c,a209d50e,8fa8e1d7,93c61ed9,bfbc22d5,2ecf293c,9489ac13,f76e3adc,a89cb983,b6b670f9,5a7e774a,c015de5,1ba56417,40ac1f68,e3df377a), -S(26699dfe,93788eb8,d91cb601,cae628e5,75e8468e,73f6cefe,588755b8,c396071c,e5f9e00f,bcf6f1cc,cd39ab13,41cd06b0,ef2e789a,17d761f6,6a7a83b1,c036791f), -S(72f7e16f,77f0a4f7,92db2cd0,354382af,34282dc0,7b8cb290,a89a5d60,894e8090,54d32ecc,2cd022c6,c03f1379,657450b0,db9f08e9,6e2be5ab,5233dd84,62733cf), -S(f84ae7f8,a03b60,af9cc359,36f0ae78,96935b2c,534f852,8ad159bb,6c0b44e7,68f4dfc6,20a354d9,d6904bae,67792622,337e3180,ab340828,80bf04fd,f47cc23b), -S(5dea33b1,b5207880,6debbcbf,83ca17db,4617488c,ac5c6997,ad4092a9,8a7bff7b,99976fe5,ae88d36f,597e16bc,6dbbd4b4,547f4dcd,7e85786c,d10af30e,1d81bbaa), -S(31be76bd,4f946e41,7de73037,ceaa0dd7,c6eccedd,74399e14,2ae6fb2f,d2b59def,54ad8748,ef129085,dc3172aa,904cc376,e203fa69,38783007,2af33889,52cc6549), -S(b6124d0b,f603a00a,22662897,8dd0da87,fcaca5c4,fb04ebaa,81a7d13b,39f2e307,34ce08c7,4463b06c,afb03c02,583288eb,7bfa6f2d,3eedfed4,91e31781,dcff10da), -S(6aa4bd60,90bee70a,295c451c,c8af72bd,3665680f,545f46c0,bf5af990,aab5f43d,9c2364d8,25406b76,94ec9db,a0ea2f9d,bb36fb2c,5bda62a2,bec941c6,874e68f7), -S(f72faef0,e268a7b0,a9b00a57,3674d846,c1f0dcab,c9a586da,be318b1c,d2874d8b,16b3cfda,65db0f3d,1b5274cd,20b1329e,61ea0404,1f702e71,cd98708e,28c9307), -S(1d26df15,98a6b9a8,7c0a6171,767539e1,86d51d1d,cef130da,1001226f,87872c5c,f227cd82,becf5493,e2fc7635,6a37bb48,3e681a19,ab4d9dc7,92edb114,3a7b072e), -S(28690cb1,db697840,13e9eec4,d9388723,4c28451c,cf9dd51a,746d1274,b13b4610,d9bc39ef,19228981,a1ead1f8,94deb254,162fed5d,cbb58a76,6d361e04,3d8f62ea), -S(4b0b5258,22dbc31b,1966b004,4d39c5de,f2e16d5,1e032045,f9973b1e,fe83ca12,2db33ff4,3631fdc3,b3608b40,7dd494f6,ae730212,9619ae35,f6ea08eb,51aded12), -S(a5b4e205,462ae419,8fffc1e7,393d366f,c5a9eea4,e98c67ee,1684d63f,cc09aa64,d3c11017,de4ad175,17cd076f,cf6c0ce0,4d3108ed,60eabdf0,935499f9,4226078b), -S(d4f1af69,2a3e9fee,1f92d892,b14eef6a,a0ec1f4e,d4d455f3,c70bcb19,52fa9837,115c7ee,73b90adf,f142191b,eca0be01,7d5a651f,93e2e90,5a36646e,21790294), -S(c275c715,9d6e9757,d2adef47,2ee53856,dcf067db,bd4f380e,892c9832,708d46b6,70da1cdd,853a0dc8,a6a9043,3c319371,25590c9,5807284c,ae168f65,62e4465e), -S(d2e38b27,83156e2a,a8e4eac0,149bf2bd,bc2918af,1cfa2a23,d1c7136e,15dca7b,738a0fe,751ecfa3,459e005f,72b7461f,a4b5e1ed,736420d2,22c5428e,2ec1348c), -S(f8f5b3d,b3659174,e0149fc6,fa747c22,9607c434,8f9eab60,900bfe92,b23f9a4d,d89eff33,94a093fb,549fece1,4e11028a,614cdce2,21d5ac26,1bc25f32,dca3919c), -S(5e266403,e49fb860,e6ed0928,45bc0811,a214a0e,dcd6174b,290ecca9,3539d862,ab300acf,5d8b8a14,2fc9e93f,ea995d2c,d7a2bdb8,6a146f65,2b8bd49c,4e8dac1e), -S(8ff869a7,60230ba6,aa5adf91,1ba61702,17cbfdc,5ffa4018,b8a09b9e,4088d634,db5a5aae,bdb946db,80e4c207,22ce38c9,4921bf41,47eea510,70e5aac5,c592f32a), -S(f3d39b65,95bd5ab9,aeedc43f,f49bdb20,73a211f4,5ec2c1b7,72226a97,a31c059b,ea41abf,9322d733,bb5971ac,194da6a0,a6d41c6c,a0d0acaf,a53e17bd,dabcdc68), -S(18ba0c34,10169914,7f7589f9,179b94f9,daed92c9,287f3468,d283bdcc,d71cc637,b3512d25,c199d2a4,c115bd11,eb53d6a1,6ef16c3d,97be6291,5ff76b76,890ba675), -S(2cf3354d,7f96c58f,3c6336a0,6fa30c83,8da767af,48f89fc5,5ced5b40,e0b86cee,403ac306,f6c3ad55,be1ee5bc,29cdd46e,2e3d83ac,71050909,5f117d21,7ef015cf), -S(5d31d140,f754d6c,5943deb7,6aa4d867,cac81abd,9911618b,82327795,da8d085f,c25f99d0,5bc5d583,a3a72b41,4e5eac5f,c14ced01,98247ded,79ba482c,882bec49)}, -{S(e0ad91c6,6ca95326,d440f44,df91c1cd,cd3ec344,e906d0ef,51fd4a48,31ce293d,3559f3c,e349f7b3,cf66c17b,2c3fe7e6,8ba3804e,438c0816,b68ecfe2,30da18d), -S(d8b8c50c,ae9f285f,d6d9282c,373607d8,5fda59dc,71ba0066,148b378b,37440076,ef83dd08,ddc115cc,24948009,f9eb4afe,dcd65c64,b6ef2194,bb4ddd0f,ece180e6), -S(881fbbf1,a9627bd,369abbc2,edda8026,a61b10f,4161e442,530a5e36,447a0290,6a63cb8f,7e5094d3,c8beba5a,2a1d7b54,bc33005c,efdd5a1b,20d51f74,d00c2fcc), -S(36bc0df,fd1441be,1a4efd6a,43ab9d83,243d44bc,a6e108dc,fa9a79fe,23106f0e,eeec58b7,dc37eedb,4432dcff,4de7f88b,2a0e0721,da2c0a72,eadac4dd,71037ed9), -S(7652c155,c2ca8a23,7680f015,a62c7c31,31682752,a99c4329,77ccfb9d,cb58b03e,5339a51b,36ad4548,197d3018,4bde4428,b38ed983,d624bd18,a5f8c4e7,21871c5), -S(904774bb,fb8b0c12,e2b3f91a,e5a2a0c1,a92971f9,86e29fda,9edc609e,e85b222d,ee843f1,8039e251,9c7b23b3,725ca099,114b4f0,26970111,35ded92b,94445e2d), -S(1c7c82cb,fc14b9b2,cdb3c12c,32df33b6,a08e7af9,df62f310,79fa0710,f28f5f95,93471b5a,17c84eea,a45948df,80c0f56,d8684f35,1aa2ce73,ab84b3c,1b8250a4), -S(bb060f5d,971ce062,427a5630,8f114532,40ec54fe,6479d5e7,9ce81444,27f07927,fcbeaa69,8278eff3,d4dad904,836c0233,40a866b2,d8f66774,70d1159e,201501dd), -S(287c5b8b,8dc168ea,197200ea,97c4f63d,db0b620c,7f30d623,7934f856,a558438a,260630e6,ce310eb0,366acd78,bb58f4ef,27fe4836,edc8ff0f,5d5ff987,b659bd20), -S(7d4c5c6a,d6bb0f0a,47b45a35,1264f4e6,a81ee0b1,65a7e665,4b226c95,feb59dbb,e89691f3,ceb4c57f,5aabc1b7,4acd9aef,41531851,b41ec1c6,608f16a2,2243ab5e), -S(ff806f2b,9eaea4f6,47d85077,d8aa5052,9d4b96d2,1e0b31e0,7c86b14b,73b7ab4f,9acc2f77,a994997c,7a2b1aa0,79c0b5d4,c84f6715,e4a50e33,628b871f,8885ef9), -S(3ce795ba,1d91a9bc,b0260654,3450ced8,c94184dc,8a41ac5,e1b84856,e88927de,3492e696,cd1ab2dd,587d4707,ae34fd67,3ab7902c,d0c0972f,ef419795,1ad88a1), -S(299ad528,afa3f36b,c80a757f,f081a8d,c4a6ddc2,d2b57fbe,1e3d361b,ee5a5d8c,9fe823da,74eda2f,266a8e9b,331d511b,623dcd32,ef9ab7a7,f1d1cb4a,7e6fa65c), -S(bc4b0549,16177aa9,b52b29b7,cb91673c,9ffce4c,7d0066b,e4249383,4467e3b9,55bc6436,7db68687,e699cf6c,f2db9dd8,c2b9a438,8202fef5,11acdce0,ab06f969), -S(a8e8b02c,ff5de02a,9e6652cc,6fbe41cf,6e87ae0a,abb14ac5,a178b3d9,e697d0a1,285d4af9,405b03da,c57c993e,4b40df8e,82c6979,f8de57ce,4543b7ef,3381e0a8), -S(e50aa8b6,d7dcc055,4f406959,b056dac5,21a7842c,ffaf09a1,ac24a3d9,8aef5228,46656395,ee84d061,a9f5788a,cb05975d,5ffa5fae,edced564,1f81b5cd,2491c23f), -S(cb516899,98a214c3,c31e4f2,692cd7d,fad6f1aa,eb8afd1f,b29c23ce,429c224b,2292b8a4,5a89eb80,167238ef,2027f975,98a2aea9,a4460c5,3646d088,82403c63), -S(ded04c06,74c6eb16,557b5bed,4b6703d2,cc37c6aa,bae466e,ee7b5665,6693c3c9,4f3ea70f,8e75b02b,76934cc3,645d2af,eee8e9d0,8d100117,40e8a16c,dbf01113), -S(f3d0a253,edb74436,897e6cc6,621c74e1,30457b41,e0690b6f,7b2a203e,8ccf8ac8,89cb07e0,97495bdf,403490fa,d58eefe3,e79ffa33,1deb5cfd,2c548ec0,8771be67), -S(d4c66267,aa73ed55,bd68fee3,2a166a4a,4ec660fc,4cb13e18,fb6ab0fb,19a5f330,7c2efa2e,4509b221,97589483,40b6c74a,8ee2b5b6,5fbb794,7f838c47,ee03e2f0), -S(dbe9a638,f262f9a4,b3a8955f,22293feb,50ef4b32,20df0184,f363a373,d7110981,4c563e83,5e957756,5e6a8996,97510c67,9561972e,5601c1cb,2f2f789a,c1e0b5dc), -S(70c7c07,1b1e6fd0,a97b55cc,5ee34297,166f4d02,417a796b,eadcfd43,96e1b338,b5c49a6e,2ab03e55,f4755f37,e5211d4b,e23339d9,d464fd28,6781bb29,56db23bb), -S(aabc501c,6d52961a,a613fe66,96f0bacf,fad74fcf,8386cbf8,b18704bc,a1392ffc,cb72ba86,70bc3f7c,85a00d3d,76b11596,6cfa0fc7,44b31e01,9129da9,a5b04b77), -S(47f72ec6,e7820788,f0f7814f,aefd6e2e,af5d90f3,f877677d,ae72569f,c6a2e8f5,6709731b,ef2dd880,4696a6,a0661d13,fe579704,5e0a9bc0,e5fdc0af,789c5830), -S(20026251,d9413e42,47a5884c,209b144c,98e36f7d,8ef3f56a,68efd475,8a2ba8c6,9c5531b6,94ba0d24,a943d0c0,94bb623,75c798ca,c9716181,a9d659af,2acb978c), -S(8dfc6293,9b300c9b,fb617d23,6885f652,424b4f12,d04f8bf1,151d1ccf,935e445d,9a519433,18e94107,5472aa9d,6ec3390,59bd3bcb,bbbf6937,c9290e48,9da25f8f), -S(afef3520,3b558495,6fde0eff,5cfab48d,8fb08806,3c1d7cbe,d7e352c2,9d49176f,a764e6e7,bd0c8fa0,8a6f7f30,aa38d7de,fe71773,fb7ea484,68b3fd9a,8adfd650), -S(354c0a98,1628dfff,8be8ede,ed809db4,bc39c686,39a26828,ff28dd47,90801c46,8ff40299,d607036b,acd7c0ab,66a102ab,38f8d3a8,a271e2a5,20b43cbb,687cce6e), -S(da2e7eb1,1a1e66d9,5001ec4,f7b66c1e,d9f7d0ba,ea3bb326,672b9069,5cf4bebb,cbc1c7da,b9bf7e0c,dea9297c,5f45ad0b,9c4fb093,318b55f6,1e4a8951,726c4021), -S(6f780994,d0662667,8fa74156,4232bafb,b3a7f54b,a5b66507,9df32545,c192c3fb,5f11f0f3,af1a763e,4c9fdcb1,1e5e57a5,6dfe0d0f,f27535b4,4343a312,90e375e3), -S(8e28948c,729c1438,5bd09316,31ed3eb8,7acfc5f4,2a9eb4f8,afa50362,33591cec,2c09fa1c,bf0044eb,a78ae81f,bdbd4271,2a89ffdc,f7d476af,881d29fa,2627f250), -S(4011cf05,a85ef14f,1875cf3f,4f78a51,a52a89bd,a8930a4b,8e13802d,b85f319f,35045b10,45c4f71c,c762fa78,5b8d4daf,aa2a1c07,ba37d82d,ee0592ae,ad807810)}, -{S(9089bcb7,1c1559bf,e17f6c0b,91fc098,c63785fa,18a42d69,798b063f,a0930175,de229175,5e4ebf17,1047f79a,37d81b9f,9004a7cf,df747589,7365e174,ae367969), -S(4d1caeb3,41f25459,3b06f715,9e9418df,e29ee076,76c26e6a,51d8add2,5c70a5d1,bf773e4e,4151d17,650aa7ed,1d6a5505,2d622264,75c50f31,3261aea2,cf68dc37), -S(b0760330,517c0d66,2571cfae,830da7fc,a7e0d86c,1ca7f75f,5150f625,db50ad2,d8d10ef3,9c84bc13,32c2cc01,4d4df0fb,45e5c546,1849fb1b,81b7fdd0,7484d35b), -S(3db731e4,273e5b20,2de984c9,74b4112a,d0feebe3,7bb0d2c7,db38c7a,21bd8c67,b425c1d3,46b6a61f,2893a3aa,a243d60f,5563cba2,40018cca,3f80925f,71f4f1b1), -S(3a74a50d,cfbf2ff2,5c99c4d0,1a13a917,9f510c2d,eca1d5a,7ac8fb69,7eb9795,d2b468b6,714681f4,57bc586f,40585c01,e1dc14a1,a42ce887,9ce044d9,ddb92d82), -S(b9139ad5,4f44fed8,4917ad55,c49c23c7,8d62aadc,e83c9ebd,9efde865,cb1eb298,18068856,c80abc3e,2a02a441,bb7a7609,aae8d2d7,8abf4e2e,378fa3d0,a27aa900), -S(bcf5cf94,5887f183,e58a0128,4ed9a4f9,fcf918dd,4e68d70c,5a54eeff,166cb44c,8235f63b,bb06a1a6,d9ad2ae8,47aeb2b3,4838c962,9608943a,93294c6d,e21a3ab9), -S(4b598ce3,a77680c4,c5f66e90,1b76627a,27f35301,9641520f,53ea3894,dcbbd187,357af043,f77cb9fe,c04ce1f4,dd9b610f,9151d15b,3b7383e4,ecc5384a,8ff7c5cd), -S(b588aec9,2dc045e9,a95abd7e,da929837,28b5a7dc,d637001,ce7f0917,1283b16e,e682f53b,5e94fd84,914b7bed,5afc28a,30ae6f53,e12d948b,3c0d88fd,adc5d0e6), -S(eb8f5080,218ac5c3,cd792042,b59e80ed,e3857a75,a81d67e0,7c2221de,d3b7a677,c5f272cc,3734e0f4,6a5cf40,626973ae,1aa76839,1953f211,eb52693d,254a7fc3), -S(87d119ee,65a60dd9,aac3e784,22049cfb,4123d262,ac9e7473,4c9cc418,fb7ce4f0,5185ac,7bcaee8f,f1334eeb,cdf2c39e,83b8b665,1ef9d8f5,48a029c6,464242da), -S(cfd0438b,186d0f5,c64b5f38,a190baf7,35b67512,a439f486,fb79d501,90294683,985edeea,243e9c6b,d9c57cb5,c7372202,7492156f,e10bd2e5,67edd14,8603daf6), -S(52abfb67,5fa8b12f,1b0cf0d,8e85f402,47696662,64c7252f,69562590,839ce4f8,8483ab43,2d4851d7,4f432c0a,8e3863b9,783cff58,3d4c390a,9865d7f7,d1aed67f), -S(52926df,cf12eebd,3008459d,3c91dc1,73532f1d,ce3c5d0a,874ea4c,67331787,18b48fe6,1bd74ac6,4b34f2d0,e7de8920,2c875625,bcad84bd,cb3c81dc,cc86dd87), -S(695e09db,8c4479cf,4c305005,b5737ca0,63f89d02,aced2010,5600d65f,58e26401,32123a91,8bb23fd8,79715cc7,488184b7,53e0eb00,6dbbc95a,ef9d815f,3833c08d), -S(97c35716,e5aac70c,45dcdd45,a5ca0155,5962f09a,cc22c16b,c79ec272,ce1c12d3,93869464,6470f8e3,c0db18b6,2e4378e6,5caa7203,c4d6a079,a10c8182,b8eaec3a), -S(35197cbb,8da9188a,fc60faf9,71cf08fe,73372e15,f857b93b,6afd77e6,bf4db7ed,4e0efeb5,2db601dc,a539c777,14f4aede,c5ff121d,77dbdeee,7f16fb0c,4cfc19af), -S(afb2f842,e0818237,46c294b5,9ae8afd2,279e834f,100f7d1a,58a9551a,98408d49,5bf5ac43,a3609b4f,f058d6dc,6ae09fec,19a19864,6d12096b,6bd3e06d,95d15ae8), -S(a37f6113,882459,b1dc6335,26253a8d,287c9285,b7862721,f9bee74a,d2c4c09b,9ed3252a,303c6d,e01c9985,c5b3edce,1074d478,db56b961,d91fdaf5,1b1d07cd), -S(4579a503,cb12a345,182b28f6,9a3fb98c,4a80579b,2ff592d1,ab18b32d,212098d8,8c61c503,df79dcf2,6083f15b,c3ee1f99,9e1e0960,8bf6af9f,b3175699,cb0e32d5), -S(545031f7,883a2c8e,bd56a405,52719096,4aa1d40d,b22a1730,242f3064,530ce326,ecb024e8,e762b456,f62072e,5f471180,bbc817e7,54e830ee,7757ed7b,df5c9300), -S(b127fb32,bb3e193c,99d232e,d50dcad0,3b45c072,e0d521dd,de72daa9,e20e97b4,b198428,12a344b9,2e8a8d26,f7964c66,82cb3652,66ab3e28,2ba56197,a159f1a), -S(28cb3582,d312cfcc,75ab637d,66c646f7,5157dc74,7a464e9b,933c0820,2326b6cd,a87042b8,510ef9b3,ecf918d,916128e5,f946f43,6f18fd5f,ad62c46c,5882a23c), -S(8a46cb3,27efbeb6,850e3861,c4845ab1,21414f12,9fb27387,4560826d,c9116886,ab09eda1,9156f1f7,194b7b17,fce15268,ba041c96,24765ce,fd964ede,d1f05b3e), -S(b73af914,10ad56f7,d490dc37,1a2584bb,633de0f5,3f00cd0f,6b8a6019,53c7ef16,3dbf4e52,753e5d33,3fd23cc1,c839f278,38eacb3d,5980cba5,bf1be426,b27641a4), -S(b38c1896,427a0108,3f24a917,2a64314c,d9dc1759,60971135,1b2db6f7,d66ab745,d3a71a74,f80d6919,b65629f9,80c7757a,cc49c2aa,78dc67d3,d6f76d06,91a90d85), -S(6f6ac108,aa819a27,6dae862e,276b3ebd,8ed5a3ad,9b0296e0,4f8b65a7,f6a5ac1a,e3048583,7aa2140e,de381363,788d6d95,25a7ee33,9e3a3ed1,2518619b,30d9f71), -S(72f5809c,7c282ab3,4dd81851,33070d85,53999a6f,14fd753f,2ed8deec,ed7adc5b,112bf5fc,8cfd71e1,84ca1967,d05da765,801f12b4,c852768f,60afa7f1,e9576534), -S(4c348833,10f7dd6f,b385ce25,e2d6eef9,8556a59b,5e79a084,ec83425b,37150085,9c4c97e1,be47b073,5209ecf1,5f05cd8a,58ece74c,1b35a92d,96a70287,11d95add), -S(f16e4513,2291b577,ab360b42,c1babcdd,ac61e623,da85819,e9c4c73d,463204b2,5556d7d3,a2d45955,28781d15,16b59aad,941ea356,1b5c88ec,94d09314,555ea64b), -S(3580d3f7,896fb70e,d48d40f8,1b31a72b,51405574,2c2b4369,e3e7dcb,aca4ca22,e38da3af,f409e459,82098305,87aa0eb3,b2339959,75af2e33,501115ce,648360ee), -S(407e63d2,c0cd6d37,84c27734,f7e517fb,4bdf7847,296dc7c,a8714fab,16199828,2dbe5da7,4b29bcc,fe9adabb,69157830,987ac51f,389c6001,2577f298,710025f1)}, -{S(f61f644b,e2414c07,66c6caf7,5d32683d,efafb133,cb4d341d,7eb565e8,9f6e4158,2848548f,15a6e7d7,2b2eefc1,1b76e318,15ebb4b2,1e3bb938,e0c2e9d4,5ad4f7d1), -S(5b891f8,ec902550,429a5ea8,33fc29c0,bfdddf6b,a6f62c19,87a14050,a9689a9e,77901539,1ef92985,6d3e3b35,4e4ba2db,3bad967c,dedf331a,c0bff08e,f25f2e99), -S(d8c5a617,62655ffa,c943ba35,3b595b46,88012282,af068e52,d918bbec,46bec87b,9263db7f,6f74aa,df0dbdaa,7e7ccd76,cb3a498b,44de2bd5,f9b23029,2ebc6009), -S(2e940645,cd189edd,2d6cc2f4,f9b49e4d,305cfe8a,46f2a596,fbb55200,89fa5b21,4c197028,e89ef8a5,b5b6cbb1,3733e90,408877fe,7425d58,1f4bd063,ce286fb2), -S(396c3bd0,9c6af07d,123a8441,c9f79ab3,a783b8f3,fdd69dba,ba61c7ec,f65e3098,534c8657,aeb8cdc6,ea34b372,68f1c70,70881797,46b8e335,477c8525,cd17aa8b), -S(c34e6be,b079f3e8,d1355754,4246d2b7,a82d551b,740b4b59,b9220bbb,768796fe,57806a7,653ff7f9,3d7cb6,b3acf68e,aed049c5,75988fa5,f03b1ab5,1103aee8), -S(5d2d6aa5,252fc9b2,55d89773,e920891e,7021f233,5f7d0ff8,c6bde5eb,b65c5149,1fdbd2c5,6b8bd095,2d16c304,8d9c588b,2a26379a,17f748d,f1345695,1c5959c4), -S(dec812f5,745fcbed,fc36c635,76874bc5,96dde8ef,68a8724c,201b6af3,be7c6e2c,1715328a,f75f9661,d58c667e,5c5514d4,c99dc881,8cfbe702,e0c3c8cf,662e6906), -S(32499061,83487250,f65684b9,9434489d,3a83ec93,61531dfe,48086b2e,b2bd18fa,53217af1,2a25fc6f,45555d93,98fe46df,4247d38d,7b162e34,945f8928,bfe148ba), -S(d3e9381d,83f31116,ee161490,c9b5d1e5,7e086c6c,1552160,2c913315,af033ddb,97ae863d,34271b26,a4d6577a,32028c12,f092a54,8a18ae1b,a83de384,3b8fb84), -S(1347dca6,d097faa5,7c6583c1,c292c6b3,ed87b31e,9f7afe8f,d0d151ee,50ebdeb0,570a9be,e4806ee3,e30696c9,71b5d905,65d09ee6,8b4fa8e2,8acc54c0,7fabb492), -S(691f9995,af2bccbb,f556f624,b28a1da0,67854c15,4f014e92,a56a8cdd,9a43c25c,81babe0,ae44984c,bfdfa958,4dc5c677,881d1b0f,63993075,a3fc462d,e986866a), -S(cbfb62c0,b91cedb2,5a9d4b3,ada43cac,7839dd18,33174711,24688ca5,5f162cb,77c12161,e8199410,b040dd57,4d90c39c,2f1b499e,6b7c17c7,fb21438d,aff4e674), -S(53627516,8de62d6,2c792f64,f87996af,3ed8ec88,653532a8,ad60942e,cae4a339,d8449a0c,c6ae32ff,45a11652,97b3d3a0,57e67c64,42d3bdb1,ea2cbcbc,cf0655cc), -S(2a81679,7505601c,763e6f6d,f7ed5c0c,14ee7fbf,d75b8755,7bd57f3b,e2d3c7c,99f26af2,10540397,b8423da2,c4809942,63734d99,f0d642d8,96b5f216,767b759e), -S(54b2c03b,7a7ea964,220a255b,bb688767,99ff1b83,f0934e4f,fd03c2bb,51490e22,b3cc56a9,ada9240a,a3730828,26733090,ace3d7e3,91200d08,2cbfacfc,bcdb9c08), -S(aac88c8b,7c96e629,6f023e5e,8f260324,9f4e645,bd701705,8f38e9f3,a034eb57,da03ca87,b98ab6fb,e4869756,7c2db04b,7f9948d9,ea65d93f,d222d52f,6d48c552), -S(bfdd8394,fb49f93d,630f6b8d,469da38b,105529d6,70b9a1ab,e3196816,d2a13978,39a97919,4249f78e,c336b00e,475722e8,7ca734d4,3d1e97d4,d2aed074,abfacbe9), -S(5b5dc3d8,66ba3647,d2aab2ac,3338abbe,4d1ca08c,6cc6fb26,4335f40d,4dfb2331,3432ba31,46a0f15a,beca45e4,1ded8729,e6a0a49e,70315745,bfcb3388,4e1b9e64), -S(77057b28,a1d139a1,91e05ad,a8d72f3a,c7bbd198,7647070a,b6a21355,7bc0c73c,46f32321,4519afd2,f830cf7d,567aacc9,47ae6b8f,8c841adf,988e39ad,e7b9757b), -S(f6c8d1da,e28a3d23,2a388998,1b638b23,f381618f,18dc81ed,67bfa696,4cf1626f,2ad8c92d,43378941,8d298dc8,2cbf288e,86d21467,ac73c0e3,383ef3e0,a03142fe), -S(b75b5cc3,77a55310,a3b97067,34f1929,fc0db732,3265e6da,71405f37,729d5a90,be077940,4dc94ea3,3cff505c,e1aef457,bc120359,521eae05,1de1963d,b1948053), -S(a66d54d4,4b4d06ea,f141307e,27e1c225,41274eef,5c0b1743,e6398b22,fbaa4068,51b6b8a8,48e1c27f,107f82cd,d0554643,b9e16611,fa93b789,a2199b3e,3bdce296), -S(56b2f9,ab707dde,3479d0ea,baeb62a7,6cb9bf03,66278eed,559e027e,a1ea6b3b,27c47e9d,646684dd,2a54db0f,c245fcdd,721416f7,22ed568b,736e3e1b,f195b379), -S(a9642a49,83b19c3f,f5f63ea2,9e76afbf,a25dd0c0,221b32b7,6e67373,36e7f5db,8ada3766,9207c6b6,a6b6006b,5240a4d6,cdb8b807,c0c16a56,91289b7d,62b3a051), -S(18eef8d,f9e64c1c,548db40,ad77d92b,11f3ac43,60c63792,5f7d598d,7d8d5155,806db24,eefc3a64,c84da338,937811e1,20c6d0e6,9cde79ee,9957a4fe,c53d0e12), -S(d11359fe,61861a36,8b3809cc,c727320e,42905036,774d0e83,98453ac0,68d404b9,d4182ce7,2500637c,8e14b977,34fcad09,f061838d,57c555fa,420fbd50,9abf6b81), -S(7ea072e8,f60ff273,9cad1d8f,c560f208,b54149a2,5748900b,50830e3f,738b2db2,af09e54b,d44feb44,b39956af,fdca6894,91c7c6fd,f029e71b,e780f8f6,77a48a0f), -S(f53406ab,9fb1317,b038dc28,f0165abc,115b37fa,77d23bc9,e51993a7,8a15ba00,a293f429,f7fb281,9cb60b53,b2e6f07,afb6537a,39a18be,a5ad4cfa,55aea13a), -S(b1674e5f,9f194a16,94fd12d1,4b64ac8,bba69432,241aefd9,9a1c49d,23287635,83cb0060,1f5c33be,9436d946,22c3b3ce,68d20733,ee1e2392,8c3d6c14,a7cde085), -S(22b72e08,66b96344,ee53b898,ea725f7a,b5832c12,7c0881ce,862ea945,5eafee85,b886e8e9,cba29b15,be5c22d6,ada99b02,1098be69,d1c500fe,6fd2ef8b,f1ecae25), -S(9b7151af,698a85d,2246c88e,8ffb14a0,c762c2e2,64ab70b7,e30e2434,9b8370b7,fd9c3d89,46ee9d90,e7fb6d26,796062eb,4cb6c160,76df4834,eecd2748,c8a7bb4b)}, -{S(5ba26c2d,53b04b63,d260c6cf,392786d9,41a1a7c,b88331c1,149cd3b9,9c207f5c,9c7f6303,bd72850e,d4da618,3427e7f3,eee078,6f67cf9,85d483ef,79c2eab7), -S(f7d26944,6d29f81e,39a44a88,49f12184,b9f42eef,16c5d88f,60c96a28,cf0c3e48,e7ec965e,d0a966a7,45087e09,a058421b,852c8a7c,3790a3ef,7abc6ccc,e17c6084), -S(98590b7d,36bd2ef9,37ce788b,22cab951,d921724b,87c3ad83,8263416f,b5a67dc9,b711c21e,5af72a36,5cc1b220,7ed09ebe,be918555,55e9239a,e9b03d75,c0261d5c), -S(92e1cc4e,5f57514e,9ed13535,5f3e2cda,b0b22f8,8f56a972,a657dba4,7263463d,14d296bd,452f2faa,7d6f42e1,550fe35b,3c47eb2e,fe7636c6,2eef90b2,e7822da8), -S(33de9b1b,e153bdd6,efaf9d1a,30aa9b3d,faf26a32,4486b6aa,ecb1f958,f11c4673,7ef29223,4d3a565b,c0f0e295,deffa3c9,a86a6bf1,933a084f,9334b790,51eb0270), -S(f9fad0b7,e1dfd4b2,47cd2cbe,bd863e1,95b3be25,6cf7a707,5d422b9b,f5631ca6,fd5262f9,e6ca0cee,e1c7e531,83d9f3c0,7ac518b,c024681b,56c06a1d,1826f5ef), -S(455ec5ea,f34c02c6,961469ed,27bc7883,c07c9a18,663e22ca,83830a66,569b2b36,4dbf1b57,a7de2fdd,7c0380c2,b38fa5d3,697a5995,8ca0c0f7,6405244d,bff4c9), -S(940fa05,d96fb400,bac8fa39,e696c536,71a490d7,c98b3851,ef76ed35,c62bac19,b6de17b4,1a045978,5755497f,1c2a953f,17554b4,20f2ccaa,9fcfedf3,5afb9b46), -S(16012402,4ded6478,72374af4,6daf9c2d,a9000841,9a7d4672,98b627c2,420981b,7c2607e0,a4b86f7a,d5df7371,60987d21,35d2ce2d,bc422ab9,b643d080,26f84323), -S(caf887e3,339046ff,42c629ff,c954873,2c629ecf,319c44be,6701a9f7,c81bf842,d253a688,3b3d51c5,a914ffb7,46e7ab68,70c2b1ab,5b7e46c1,7a5119e8,4ab6c878), -S(41a5b720,595bfc66,18406547,d59ec09b,4efba0ec,5bbd3191,9e9256ce,f40a7afb,87ee1be5,2233ba8c,82dc06a3,6fd0a1b,4ee8d7d3,ce89cb56,1dc96c19,dad79613), -S(8bdcbe80,fe8533a,174045a8,3cf9d89a,ca438ef0,8f6393cf,6e24d923,edb02586,8d21379f,c053e8dc,c628f0cb,83a7782c,b4e946e3,ca88d467,36232762,fc6f8fdf), -S(409a4482,6b6f0ff6,36178d65,aedd64cd,2d28b39f,3e9cd93d,a0afe712,b75fcd19,25a3bec4,74216dae,d686825b,bee6aac,487a6d07,606e5aed,7c3032df,f4911eba), -S(b7f414a8,4c0af927,64ed5b52,e96dad38,6995771c,2cd90af1,1986bdc3,cbeb61c0,702b0a68,4e93f0a6,26b807d8,8049db6a,3e65001a,d75a476c,e4be230,89574e8e), -S(58b0cdd7,bed4f327,bcecd493,d835c0f0,e45f6fa4,3687d1d2,f19de285,5bcb5c11,21b0a478,2c1d14db,9c67817d,7b23db21,a96e456e,62a85c3f,2a02c76d,78dcad10), -S(c75cbf00,893447ba,5b3f8462,9d6897ff,64be841a,9a6bb714,54adb849,8df03900,15f68903,ae20ae4b,9b3fc7c4,f8135936,c09de15,18317dde,bcf66190,2db79f72), -S(e6258fd4,b63be23f,38361a16,cf3f81cf,f2d7343e,515b2d0c,ea0bfe38,6d4400a9,aedca212,9b73e49b,9757cd7d,a39a1e92,f885b267,a188521b,32089ae7,6d351eb0), -S(7c61b66d,d76f759f,be92708,8b075147,2ba10db2,eee4f0a4,2eac1ad0,d2dac3a6,c2b79de,70372e1a,6c9449af,2612e34a,8e101cc2,81ef378b,97cd77aa,bff004af), -S(29c71194,bbe41f4e,b2f58bf5,799616c3,7b247283,c993bce4,630929d7,55f7c8c4,c0fb083f,d68f63d3,599c2da,9d0c1f03,b6903545,a47581ff,3caecbf4,359e0235), -S(f1cd983,5bd3eb61,f8207495,48da075b,ff4191ff,d5b1521a,a1f4413f,2173a68e,beac8102,13b643a9,4658cdbc,71713894,39b72abc,f8644697,2fe6310b,4ff0233f), -S(94f2137a,ae170855,3af3dd45,8f8fc9d3,c1bf07e4,35a62798,25d5b93a,37380144,e952d6af,b27f9b2b,80ccbe89,59fb8b15,5fe1b2db,f3ffbf14,cf9c1fe9,b8e8209d), -S(f4f0cd2,e28cb8a1,9b469b18,90033912,4a40a39e,67ae1642,a3a677b9,fa1a9a3c,75412f04,5c41770d,73d7cd77,bce0da96,1e6fc69,cfc6cb9,8f691d43,dce1e548), -S(15ba2fd,b652ea98,f2b326ee,e5e1629b,ec8f8e7a,36078d7,cb8a80c8,c943e98a,db416844,cf757376,cfcd5a9a,9a318b51,184f8c89,fcda3d97,e735c120,43d47c35), -S(5754903c,ffa8cb6a,3ffe3488,e484c498,69163b77,7c07183e,8d2da037,78b8da34,508312e,6c2fd008,fac12bd,afdf8e50,1940a81b,d05efd38,5277a85c,ccf125da), -S(3bc76f6b,8abc155a,dbba76a1,9c0fef85,373bb1bc,9775f431,1b3ccb12,9c7fb29c,48036702,aea467ec,daa8b809,97c41c07,9e38c414,f798bdc3,a531b08b,fb4ae303), -S(2992c410,306d3d40,313ef69c,a2e3383,88f592d4,a9c2bd36,ebd9f51e,883aa33,cdecc5df,41cd193a,ecb26700,baa42486,a0506372,d56de3e2,2fa09156,7b525519), -S(baa7d83d,6d70a528,e6392adb,b2af797c,72772b92,ace96a25,90d65c37,b0ff1bc,9943b555,4e44b480,28815d8b,e50189d3,6617e9b6,c8f07393,8309e04c,9978fad7), -S(935488ea,4c88c2e3,cda6c0ab,5b42d519,e7fabe09,fdd3e36a,7c78c9bd,730612fe,705c8f8b,228be0c5,539eae13,1f4f4bdc,2fecf6ce,6cc567c4,dc692af9,7c1d506d), -S(8edeb68d,e63c35e2,5e36bc8,61445a63,8b0637ab,d14557bc,f0b0648b,db43f86a,d20bd0ec,14ef4f35,68954130,6577ef85,baeeeed1,c1004130,80687a5a,94a9e9a3), -S(9a39617a,27c2ff2d,9869acff,b22fad1e,a7d04271,be154547,43234f54,7f21924b,917bf9f3,fe0563a9,8daacf90,dfdcd8eb,e657f023,3fb15711,79bc5ce6,e6f5dd56), -S(41dcb02d,21137ea3,a179b469,199f9ed7,9b831923,68719a4e,5c727ce0,d42e95d,4669d53,82147266,8327cd6b,31c21b80,d3394bf7,fa29a43c,2ed7441,d866f5e1), -S(d4e3e3cc,387e0364,6688a62d,9390d585,a69ff43e,1060811,431dea8,d868355e,3309af2c,b3d7ca6,55334f2e,c53de6aa,debf5d57,1618ecc2,9dc9830f,ec46144a)}, -{S(90edfd0,61871350,b7f1f029,c4114190,b050065b,2030a400,9a8a7a6f,4b92aae8,872d4f07,5f60ae2d,dcec2f12,98a22da2,53d54de4,fde85560,690dde89,1628db56), -S(27e3ce53,b4258f97,a499f408,ecab24f0,60aabae1,dafe992e,5a34952d,5e6e486,d393fad2,9be684f4,7ecec306,332ad969,75b79d29,b5863d98,5f959c4c,b8ffb442), -S(420f1078,27c75c95,d5bc657b,a46cbe2b,415a7d42,ad62cdf1,6c84ee89,22215379,8b257a28,e0b15fcc,ae0b555a,cdadf4a,be93bbb3,a208ee45,77710a9e,d58da7fa), -S(28859abc,b60a95e6,b26c0996,566bf798,60c1a194,2d3342f7,9655f286,32f9d5df,2a770426,5eeca5d8,87840cab,3923d868,aa7b7b18,f9d19941,738ca006,54ccba6b), -S(c33c317b,490e2266,2649a021,e87f6596,3897633c,90be208a,193f1d52,28614059,af850be0,d18708bf,d0e1f523,c1a4fda8,9a6c156a,55f82518,2bd99bb9,b999a358), -S(2333793d,b961d3d6,740fc725,6cf9d833,81b5dc92,85b6d83c,5c343aa8,5baea83b,accc199a,ced3012f,b6db99c4,7a36c30a,f88e7eee,b62c2ed4,1352b488,ba0167bd), -S(4834aa89,caa9c25,a99ee4da,e4a64c15,25a5d74f,9ce573ab,ff44b63f,c3a578aa,fb189539,448a265b,eb87a268,b71a18db,f12fe8ac,e502720,c83ca156,c1cc7a39), -S(432cc05f,c78b0d56,e605391f,e4708bda,a1ff3edc,96a729ca,aad3cb0,300c4d4d,6675d8ee,ece8c078,e1bad373,247ce383,d4c65519,4a6aed20,a7ca5eca,34a89c30), -S(874fda6c,b284ca2d,a216bbda,28249388,88da3968,7f615ab,52c8e61f,b72a1fd,2d7199e2,b0b88f45,18e6eeb1,240b2ffd,a9bfcee4,6f754a4a,3db7959,dfe857e6), -S(7fe21a0f,3ef67d60,1de05f67,2b163285,a5577948,ee78274b,19fc35cf,2d2f6801,62fb2ade,5e2fffe1,28542038,91a6ea73,aabfa35b,1f7fb000,95190adc,de6663f6), -S(cd0540e9,efe497b6,2beb2227,a2da819,a1ac3bed,8eae24c2,6e2991c0,a707dd69,446c3218,7d0c9229,d65dad2,1392e4a1,66445386,4a5c1620,bf768fad,20a45c06), -S(a533c295,74e78024,52218573,66c30001,6159d772,f5bedcff,28d7f7cc,3051457,b61a106e,e0166d54,5e1b945a,f3e4e285,31a34cb8,56a34dd0,cd21184a,9555eeee), -S(5e144f44,ed88845a,c089331c,eb58811e,4c164e02,5d1758ee,51a7a522,c66deb30,ff95cab7,597cf62f,e1aa8df8,a2cd3844,d71ab4dd,4eb02a9e,6175077d,261e2540), -S(97487a40,9562ee2,7620fc2b,c5bd55ac,6509d487,8ab41257,53884b97,7c5a84be,e52a282,1430c540,5f1143d0,62b69faa,16592f02,cb9b8602,d52c9fc3,70769091), -S(906f9ac1,d3db4690,d74771b7,f1940679,b0de7731,a68d7d35,89caae34,c3760eea,6f2be7,2275dd5,1e77a066,b8d3c303,f565cb97,b8fb0dd3,14445d18,876665a6), -S(4c355a31,d17617f3,5d4066c7,a125b2bf,1d6f77e6,27b585ba,2d271a29,a88c81b1,6a686e69,237b75a1,a1ecb86f,b715e858,35aa0686,e2ef10bb,38b762ca,5646e9db), -S(15aac1a8,9b6b7629,57375d4e,aad87c9d,e1fc2617,89e57d29,731fe96c,1380140c,2968c0b2,2c3dd83f,3286d37a,639bcc14,3d89e75f,cac1da56,7e07799a,62af1008), -S(4642f29b,37b87118,65767998,d00b41b9,fca6718d,bfc55785,1c459efc,2ea15037,a1ded31c,be33cc1,425df851,998ddd11,1518ed13,f84756c1,c7cc46cf,3f5e9a72), -S(9554abe,9e092bd2,c4ff46a0,abd0b7c7,fb73d85f,1c01fd96,83146559,306ea727,89e2c07d,db1fe6b0,9872ce91,66ce9ca8,1124986c,c7e48e09,f80aa3cd,70987711), -S(1c0977a,a773c56,2e36dd15,58b95fff,d35b4dea,ac464011,ad7b79cd,26227238,e04ce4c5,b0b165e9,87dfef97,d32094ea,3e86e6dc,33a4c96f,c9470336,34b0db68), -S(71d44171,60361c39,6295e5cf,b1540ef2,1ca046b5,98645a23,e8c9772,ac21be4f,7122d5b,32a654a0,1476a47f,d3317a25,ed51536,4a21253,f4068dc8,14660c55), -S(d906f59b,4d56bc12,f26d60e6,6fc31733,e5450707,89025ea3,8a6193c8,520ddbc7,cd7f414b,c6cc79aa,4c65b943,ff914234,a9d85cf1,9853be59,2a71fe1d,dbb20163), -S(11b7dfb3,17dd5c23,6b8084d4,f3cc157f,c25c0e70,8248b472,240963dd,9a3fbca7,dd2c8caa,2a2d14d7,fbec267c,9fe87ab2,8b1ddd92,dd100449,f75ef1da,97d4e5e), -S(3ef8274a,fca8fbb3,1894d7a2,d1ad59a9,4951b21,328b1e84,ecaa6df9,cc1ef473,2e4f0c04,f5da671d,4a2b641,46ae749,27bc35b5,98a54190,3883469b,3e7874de), -S(a861fc27,f5e6300d,ec0fbf6c,3315d053,98f90b84,2422992,bdfba11b,1c1c7e34,75a7458,5d98bca4,e3517897,afef848,8e524168,a586d8da,18834171,4b51846b), -S(9537019f,57d7869,2a358758,47e885bd,1594a426,4412c595,62eea9ba,4ab34de8,21bfd84e,a66650dd,79cc8c13,7217a351,57b9c046,938f20b7,246362c8,6637d5f4), -S(71c80c38,b1889d4f,507132a1,87af0c91,79994b84,1b816c8a,6d130a,df1b500f,8de1f76c,100e75b5,1572da6,d08c76b2,10cdc447,cf903e0e,2b00e002,5dee0ce2), -S(2fa9ce2f,59865d10,17880d74,d31cd446,5c28ff56,50f29e6b,d74a810,977ef9ec,6c5a2073,55c0dd3a,b994778a,6bd02b87,80ba8e1a,899330ee,cd8781b7,6e15cddc), -S(96ca6bb4,bf74c748,75703386,ae02dc29,13329d9e,a5395892,df1c6f57,4a84fa4a,fcb510b6,dcfe8da5,690f8fc9,4dea8ac0,e42af209,35c33347,b088cc79,52e98b1d), -S(36a066ae,694f2645,25cba884,956ebd46,ae568acf,11664965,63cee00d,a32f2199,5d1e975a,856ebd1a,cb1fe254,101e89ab,ea089e8a,b38bbd0f,1100e914,709fd965), -S(4922879f,800234c9,63f4b572,d236843,4c4da5c8,ff741982,c3d1e341,841d1309,9b259470,24b5f4cb,97c68d18,f7f8dfca,1e57f7de,63208765,2ce15770,98f35494), -S(ee27e2b,acf95f6d,dbb5ebae,bbf181bb,43322a3d,6db87e78,14e57a3d,41b581e0,3d6a18a,daf69ae4,88ecc9d8,7d6b1bf2,c8d65544,3f4b45b4,c5a0ac51,7b1dc3ca)} -#elif (COMB_BLOCKS == 43) && (COMB_TEETH == 6) && (COMB_SPACING == 1) -{S(e3adcb1a,fe947e6e,7cc4f5a2,df78310a,b235e2c3,bcd75eba,1904de80,c8814c50,e0b27ead,c4bbb9d2,37dad580,6e366674,4a9f9c3d,e024f2bd,1edb11d2,fafc0a22), -S(612c2ec6,f0e9c4ec,c2200d23,ddca77eb,d003be35,61e52b1,890bf846,3bb53ea5,9e944d7b,dfc7a952,c1c5ee15,485d7199,dda19551,2d729628,c215a9e0,285f656a), -S(42053dc0,9f90a7f7,86feca60,d68a5c3c,789e44d2,3479aa13,2d1a427c,621373a3,b338f891,f3930ec7,738669bb,3a29ae2d,637be08a,954f2a8c,acb661af,a660bd22), -S(4d227ea1,5194ed57,10f8ea4d,a639be04,fa68ecb4,f3d2d9c9,43ec32f2,80f74051,28a94075,bda4c195,40c20493,b5391df7,166b1264,b957fef9,683cfbec,4c6e6875), -S(8ec4abf4,d4db3b0,2b0712dc,ef54a405,54b6cac9,3f88fa9d,d8cad4c0,9b94eb1e,4e37e159,517346ee,17e948c4,a17912b0,b29c303e,497cfb38,16796752,99aaf9e8), -S(ab186398,117fb83d,db8b9392,cc888fe2,50d2f604,5a0c3f89,92d8a82c,382175c0,79437224,b3b1604c,fae64902,e3030448,51ef17b8,9af02d7c,54a92c34,7fa2abda), -S(2bd09ae7,1e8d85a2,ba550bf2,9c1787a2,3d2c8985,e2ed07bd,1d39e7b9,8ef8135,ddaebb19,195bfd6c,a44ce82f,b7f3c65a,8af935ae,52e2d2fb,33cc231d,c4b16082), -S(e6da6560,c8265e7c,8f62edca,78dc739b,74bd6543,44a939cd,bac0f489,12b920af,147f5ce4,a98377cb,981dfaf0,1a1e4740,238f1c5d,ee69cfff,a54f3aeb,e53980eb), -S(7df5abfa,d6b46a37,30bd5892,69edb6fa,b70a0d31,936c0787,407d5d6,96506263,bc5cbafd,1f5fee67,1aa449ff,bacefc67,cf7c529f,86100d7c,a8160e4c,376c76d4), -S(ad672823,cfe3ac01,50038d30,81a1a109,d8629b4a,a4e26779,373ee0db,44a466d9,c288397c,f91157e6,770c401e,dc84b328,87b22534,d11e11c,c8415a4b,743fef9b), -S(72032cac,3177c280,ceb3076d,7f510405,2413706c,956ecf38,acf410ad,a12473a6,8bbaf50b,95797824,2994e6d0,a4bf6d07,149792bf,f2a74847,1095f845,bb332036), -S(36a1f78c,3bebf8c7,1fae5e29,cf08485d,d9debdae,348a20,ad84ba5d,4308fec9,842f57e2,e900d07b,eefda7e5,9dc40139,c5deefcf,11c07c42,4629c59d,593e01af), -S(5f418454,72e80d51,1c1b8bc2,b6b89224,9119ed43,5b915809,f7b26d01,8427f579,dfc29fdc,f3c65221,a6615262,cebd9a14,acba91ba,cca22ec5,d84303cc,1fe0085e), -S(5577ced2,f6bf41f9,503aa4a7,c0060fae,6d33cda6,e3c8ec55,1eaec315,bb91fedb,858ded64,6c3d6231,87c0967a,84ee5253,2b21c4e5,b329bdbb,76f6a6d4,93cdcb4b), -S(bc74b56a,c94ef36f,2b356bc5,dfd11d2e,7a371087,653ad607,dbfcfeb8,27abc502,d57d74e7,39e758ee,96a422e2,f1fa61f7,4f6308f5,71e6dca6,3b0b0103,e83cf1f3), -S(727ed91f,be4c5086,50a0d365,b28ae4aa,c9434c0,735fce3c,7b3ebb42,f4be911a,8c595547,5e627c22,6bfa855a,22ebbc56,d3d0b331,9120d8e9,13bed868,7d3bf331), -S(6286bb90,71f8887b,c4fbb3f0,a9ecb19e,fcdd2cf1,5e286da7,1bb60c9b,5ff5e644,73731ec5,ea3e537c,c6060ac5,dde716b7,2aef4117,ba747b12,1c26fc9,eddbda74), -S(3905682b,72282a78,2b8d8dba,72cf147a,de0025dc,a21521e1,ea989040,c248852b,5da3bf52,dceaa14a,a3534068,c05bb015,2cf9c722,cc80c56,cf828ace,d96fc390), -S(561a2ccd,ca12b67f,dad28ee2,c3cee78a,cf811766,9e4a2543,c81b1ca6,eb4bd16e,3b386a9d,553c2746,893477f5,17a05e99,bbc8ddf0,896249e3,85e406d6,a57b9ed9), -S(75bdfa06,6a1a42a7,50f283e8,3ec91cc0,a5b68829,6e6aa24a,28a61e33,65f378e5,c73224ec,797d6736,c1a541ab,34523d91,e1ec3754,fe7fed44,474f9cba,29f305e5), -S(e881a840,847aa2e2,2417cd3d,3e798c56,1e630290,5dff6bf7,754d9419,98d401e3,8816d775,f1555452,f624e45,710a240e,90fc5e23,7536d217,cf555349,b5e31bac), -S(1fb527e9,4e9c70e8,657de745,8b81ef9e,e3c2b4e0,128a675b,f7e28980,e18b201e,bab00a09,1145407e,693d5353,7818bd30,49e1f364,757d228,58b8aac5,416e3e78), -S(1c2bd878,b94169da,722a9de0,c4e317ce,a8802aa9,60458301,11a89d1d,9de4270c,95b7d99,bc3df31e,f0dbf17a,a09ef148,71ae6c5d,870ebe75,1f52aaad,a48dfcc5), -S(41f7fa0a,9a59513a,e221e3b8,4b91995f,c9d40eb5,d120a6d8,e663452a,d92099c8,813dbbe,92ec4b62,25d1cc5e,5820ebb7,dbdc2964,d5dd1ab3,deabceb9,5e793d32), -S(e5cbd627,89c6a843,25a24407,89b88dbb,1dc55afb,9e8296e6,bb8af7de,57a50e60,2cf01cea,ae4f4fed,46c4efd7,86ca5e4d,ef5af524,e9393d74,e9dd224c,604b9408), -S(eb3bc68c,623b1f46,ab905412,c7f2d588,fa25abb7,7a7bd782,ba9bb3aa,c05a70ae,df9f46e0,5dc1d126,2f72ef3e,8db01fbc,11915af6,4aee0c51,da1cfa,b4d15ef0), -S(5702fb8a,2602f41f,52699f68,8d4b005a,128762e1,1dfd13fd,22ea751c,cbedb2ef,a77105b3,7af534e6,46f58c3,b02543fd,9e0666c1,58051952,a61f8389,73f5847), -S(66954eca,5434263,4036fc7,fc0fe33,81f5195e,88433bc3,2c5a8a60,341e2859,d8b1b14,40e9f123,f39c8658,f9d64e7d,fe4071f0,ada879ea,42eebad6,4d37f4fc), -S(592152c3,98d6c719,636a03a6,dad64246,a5a6814a,a62c156b,ce5332f,6759b031,8d22d1e2,d93dcccc,889f3b6e,dd5e2098,2f5586d4,bac06842,d689a37b,4b845c12), -S(5699b93f,c6e1bd29,e09a328d,657a607b,4155b61a,6b5fcbed,d7c12df7,c67df8f5,c147ee87,14325497,6b2e534c,e6902748,2a5c33dc,867732a5,8338f05,73368388), -S(c62c910e,502cb615,a27c5851,2b6cc2c9,4f5742f7,6cb3d12e,c993400a,3695d413,e80c2522,898d8a22,2c4dc0b9,8dc9ce88,740fe252,5144656a,c30f978d,dba83c1f), -S(0,0,3b,78ce563f,89a0ed94,14f5aa28,ad0d96d6,795f9c63,3f3979bf,72ae8202,983dc989,aec7f2ff,2ed91bdd,69ce02fc,700ca10,e59ddf3)}, -{S(efbbec14,ff6d7e18,a8015d68,ba3ceb19,d4cbfbb8,a1bbc09c,ce755a23,e9d4b3f4,a76faa08,2b02b8a4,405573c9,5ac067f3,ab936127,24bfc14e,a27f923d,3adf0133), -S(f02f6744,a0ee7b0c,7bf0abb3,c7ec0a5a,3275d109,92be2893,7e9ef649,23fa932d,955f3630,c5621787,13e6d8f,39efee26,d91a0947,8da36db9,4ab4a89f,aaf9019a), -S(1c6f9f0f,d6ecbca1,fbcfbe9d,1f3d2476,dbd3b6ca,ac8e18a5,949b993d,8c0063e5,e3e3770e,33081dc9,5125d69d,c631450e,5494d21b,2ddf48f1,fbc3169f,3cc1eb91), -S(2062725b,739b793d,c9798397,dfc7b1a7,24ebe8f7,5e5654df,536adff1,25970841,22f3e3e5,c0201265,5e6d8e58,b8ba633d,9a9216b5,445a7f78,a2605688,4a5b6092), -S(57ffda66,e0c29448,7a1570f7,e2f5dc58,ecf9b906,5f374046,5bd1734,841785df,22ae8728,a8800436,1264c380,3beddb65,a9dee575,6f0cfa97,c01dc047,3c806def), -S(4b49fa7d,463cbb43,b14928c6,7b3a85a6,8132ad9c,427d3cc3,bba76d1a,7c9a69dc,7e7e3133,3782b30,5c7c3bd6,94e3c306,b3f9829f,86f76f08,d44b1a76,a207f2c5), -S(411a3b18,c9b638fa,38a0e811,ee370f34,5c9476db,61df1843,863d6d7f,4e803ccf,bb306f97,e97e492d,e74afcd0,a771570a,8210b51,9e61df78,4e6e97e0,ac23e109), -S(c8227510,49de1572,37afdf55,d175196d,5d315001,3670b478,a0255a4c,ebe95075,16be5950,a3f12be9,5905fb52,8d5bd93,23eb5908,211d2e8c,26204b32,556c5c45), -S(e46bdb74,8692d0fa,e6fc9f50,6685487,31d61f8a,5717fb88,4e1f7a41,70e4997e,35398e06,48bea42,cc48fa4f,2805efbe,6bead663,c054eb08,2c15ad46,c0611052), -S(d18293cb,d0902dab,e4c014e1,22969601,84aedbbf,a01526a8,6978e144,88ca794f,3a5b423e,32c1d2f4,bf754f42,9da3c9b6,84bb798c,ea73f637,1777ba77,1aae6086), -S(7b9cbbfa,a53923fd,e9f50845,3130101,3b17548a,8097433,79d3a526,d1c90c31,3fd7b71,5b6801cf,30fe22a9,8b7895d8,1b483f6e,9fdefe7e,6c59fec8,fb9786b4), -S(ab6e185c,be9ee393,5ad6278c,167396fa,aa4d936,80524d16,27ca8e93,48fce67c,7154007d,3f96ce60,d09499a5,1262c7bc,3ab5e9aa,929e0594,994a9671,8f912987), -S(56ffb418,8b9c9c13,4a110c03,8df8636a,71141ff9,8448cb79,eb6dece8,a28b65b4,1d728ed5,23ab821,ac0c40e2,b9348e27,191536c6,79a73835,8bd9b3c,b43dcafe), -S(bdba1eff,bf6af786,dca1da26,cc226102,1f95d56f,245298c0,b87a40e1,fa9a0cbc,fa18673b,41f765b8,25d13f2d,7963f1c6,b3308a14,b033fecd,e1d0d597,583440b2), -S(d9a4a7f5,5b3af93b,1c49ffa7,4f8154e8,23aa1477,16b16441,39fbc86b,2d9346ef,19ca90e7,538ac3d8,a28e1aad,5d8b1dcc,756f8a84,240e5769,a0f561d,f53289b), -S(ee5c17b2,74c78b87,9eda9341,256b1506,25582835,60a0bdcc,c8eba320,32d58638,d7d02f4a,b81215b1,7843e3c6,abb63755,c7e05d20,6c61a4f6,bb08d1b0,256409ee), -S(6953ae81,7ec599fa,5f739bef,dc4cd8b,4670eac6,912bd03a,a3fbe91a,5122ba0b,61bca3fe,36245ced,31cae918,fab6d463,50856947,f64a3be,d0eb62d6,f9f16059), -S(3bd721f7,59f7c3a9,93474472,4ffd3e34,503cbe45,fa7fa5ef,40a5a173,b8bebcea,bd7cbfbb,797034c2,d293aa64,1bf175dc,74a44dba,84b8d99b,8182d2be,6512ef2), -S(ab6e36ae,f5b7ff2f,fd2f42f5,8c408b7f,3ac84253,e1d8a43a,55cac222,678dd38e,ff0dc59e,51e504b2,9a0ba824,3ef26eb1,2446f628,78293da2,d924028c,21f57342), -S(bf1a1f6d,7f73b09d,3efbd73,eb9ea2c6,23e17911,9063489b,42fb1303,7b53fce4,236566ae,5371fc97,b5449b9c,2db32175,90e02412,b44539d3,bda7a814,3cd4a634), -S(fa0c6aa3,4c4825de,304cfece,37a20bbb,f72044e3,94cad202,c9e1edc3,b288ed57,df8e64ba,5f5e8381,4b6891b6,14dd4753,fed5f566,956a6dd,95540bdd,25c73995), -S(d2ea634d,ab56961f,52e39ba8,ebc5c150,ba9eeb1c,6178aef9,64fa97d5,e80581c6,2928f71e,a09a35b9,6fc1976c,f6cd3c1c,7d1fcea0,2142eb80,9666917d,c9a0621b), -S(827d6a36,697cb2f1,cf19e27a,ac30c06d,20d818c9,fe869309,6435f1f2,171c9b75,53237d41,3781a1df,d0d977c2,9690d488,b051dc2a,841ba226,c552cc28,12ae7caf), -S(59dafec5,4df05695,e123004d,38d9aa12,6a06c399,e5215245,5392e5e3,f1a47dd6,ff7d173d,ceda39ec,ca8d2c95,ab1658a8,6ad99618,e3fdb7cb,b07b03c5,2f96a86b), -S(5c4f5b9,2acb30ee,8c7ec4b0,ec577f41,a9502af9,a5a384dd,3386f230,3e62a830,8aea5f7,145de3a3,679c86ce,72e8b36,f3d6ac81,bb1d2043,9d719c32,ca2f8b30), -S(38add3d6,209080c8,efb65551,3d9420aa,457f06ac,d3ec84e8,db84e208,a0664ba9,ad95a891,c60f01a1,5fcddf2c,923790e2,d5596334,4d83a21c,dfe5f6bc,4c2b32b3), -S(9038876f,21c3bc14,111d5f6a,4749d07,34e40a53,7d398c68,809355f,764cf1ba,da030216,5e661aff,53367578,4a4d3447,707f14af,cf0d771a,53e8e687,b9dc29e5), -S(b07d3e8,dbbe686e,5e163725,8402cac3,e1e4f29,fdf154f7,bf008c5f,9969da10,c8b668e0,56bf8173,2d9778e2,eaa069d0,cdfbf826,47f615c3,6d0b311a,b2e14922), -S(8bc89c2,f919ed15,8885c356,844d49,890905c7,9b357322,609c4570,6ce6b514,2cec0c32,283233e9,21889013,c4a76d3e,e8d2cfa9,eed8890f,909c0b30,5736aad8), -S(308913a2,7a52d922,2bc77683,8f73f576,a4d04712,2a9b184b,5ec32ad,51b03f6c,b5a4f6a,bc0141a0,6e1cace0,993fc8a2,57ccc015,7d42e0ed,9f54a102,1701afc8), -S(3f0e80e5,74456d8f,8fa64e04,4b2eb72e,a22eb53f,e1efe3a4,43933aca,7f8cb0e3,34992828,d693436e,16f463f7,b7a2fe4c,6afedac5,59a4ac5b,34fd761c,15a0bbe0), -S(d30199d7,4fb5a22d,47b6e054,e2f378ce,dacffcb8,9904a61d,75d0dbd4,7143e65,6afc7262,f51c2a3c,4c292136,167c7f9a,e089f33c,9b127e69,fa4c00df,dbef9176)}, -{S(983e1ca0,5dd64afe,8d39e15e,43c1cf9f,6badf550,12cdea89,5fd85021,b49f173b,18200e81,d75a745,c1ecfe5a,3ead988e,4327693b,7e3c0e04,329b0c80,3d9934ba), -S(4e1200fe,d3e5048f,f6c9fe53,cdff8ef7,5d78e601,4df471fe,369f3d1e,80e46674,a62aca58,4ecf32bd,cc297b38,c1951c71,a66966f,b9ceb2ad,de411da7,d175df94), -S(82f5f27b,83d49042,63e69f48,b676c9a9,2446955,cbc18ec7,fd4346fe,37e0b0a1,e523d039,d0b8ccae,737bfc11,9b83dfd3,d6878403,862618bd,40ddfc89,9a688557), -S(a8c0fd4e,ab1f0e3a,cab37da6,58fbab3d,949ad9a4,31d6461,b2648308,35762d19,950200a9,63c3dc2e,6d2771e2,eff401d1,f9ce037e,75782943,3fd3c560,a169713a), -S(25c1b464,33068900,bff89a4,ee973937,b03c11a,5b33d16c,4f672fd4,bfaa11f9,471f1f8c,df18e73a,e12cae35,43506cf2,c57894a8,f633ad4c,e1c5330f,eae42b43), -S(497e56ce,8793bfec,4dc6f972,dbaf4a72,aa5d8412,3bcac5d4,2aa9baf8,ccfd6723,1d3d028e,b70105b6,eae66785,5dfe7e0b,7c0a6b3a,b069a475,bd913aa9,c29cf426), -S(68a285b0,d30c2dbb,b543e480,f66824b1,69aa339f,7e2282c1,5dc60f50,8e3f2fa6,87529a0e,1d53588d,21064447,99a8fee8,ffc791a7,cacc9e26,f7a7d94b,25e74cdf), -S(721c92ae,931712f6,15f4d7c,498dda23,e1029dbc,944cea16,9442b22e,d755a100,7ef052e6,a0d2646c,a5dff39f,3b2a1019,de43e3b2,5e51913f,d636281d,cee74a85), -S(aae8418f,1b124d79,ad15f773,1bdcea1b,453493ad,4cb0cd6b,ee5c9a8e,34335ba3,c2558bb1,4a7addab,62d1f308,1a9e6fd5,92a06976,3be877d2,af9ae1e8,b510d98c), -S(b6a06052,b492d74,c68640de,8bd3251d,fbaaeb0,ce1eb997,f2127ead,4bd0b81,7bb4269c,4a9ece8b,e8ea2f0f,d663a193,2a571249,2814eb73,4ae1493a,6a97b39a), -S(42fbe048,38761203,11e43178,6af555ed,d7bea551,d4d5aa18,afaa4c05,2c6d0c19,9ba562c0,a4cdc664,87caf55c,291d8246,65c29f32,2a56360e,90138b06,f109d83b), -S(9d6dcb88,b378e7bd,233464e0,25e97bf9,97768e29,6e4aac31,301fa1c8,bfbcc27b,f434ea54,3f7269cb,1ae1279d,4178dd25,bbc337ad,2f0d5141,610dc061,80daa8c0), -S(fa6fa5c8,1e6713d8,90cd6f29,cc8b7d03,c5f8f2d5,88963652,7c199f6e,8f98e060,726194a,2a5da1b5,85eba1a5,5e06ce36,5aebb89d,ba5f7971,db3c1571,c848c5f9), -S(809167d6,85e432c7,372dc111,8573e620,d9ce7e9b,c3ebc15b,ea7e866a,3a8addf4,bf0cb694,f00fd1b4,b62119b3,9dd6c88a,22ef1fed,a94ac0a0,9cf33225,9298b968), -S(99d28ee0,962c1bd2,fa63109d,f5485653,964059df,bd514206,24117eb4,e582ad46,8cbdbb66,4ee209b3,419c0b80,36affa24,85cdfbc6,e6644429,33908490,f6f6353e), -S(559d0617,e0860cd1,87f1c68,e9a9951b,fef7dba,3a67594a,eade6e25,e2df593f,194595af,721e3b26,786fc25a,cf5b2d77,1fe00649,b0cc4938,7168a9ea,1fd2947e), -S(ab9a7228,f0d533a3,4a95af3a,51021b55,bb324229,8d101a66,eb362c97,eac48b02,80a6d111,e451eb09,cbebdd5,a3ce4fdb,42b3665,f8974df8,912221b0,fc7db6af), -S(42c6680d,18b0f528,274c2eb5,422e4731,560ea862,adcc4419,68bb5f3a,5bbfcf16,c8961934,e5bd6e7d,d64d4b1d,f7867c7b,978d182e,48315ae4,3fe2e082,a9455792), -S(e8bc0f9a,c3687bb,69627de1,df71fb34,21e0252a,e33d15da,3039a200,43ec3374,15de9e9e,2ac74839,5116ef76,1267300d,78c2e583,9286e6b6,366c8a6a,540036cf), -S(604ee928,4ea1c8a9,a0a75bf7,be3a5c02,8f52d71,b5fb6340,53401e8d,8f5d3d6,43bc16af,5875b25d,8e2427b3,3913f6e0,bda886a7,52a3b812,f8f191cf,f7bee54b), -S(7f589067,5b771ce,ac754412,a9984352,4f2a4a6b,a5cecae8,5106bb81,f7e4d9dd,a74f2eee,584696c6,88157a3f,fc27085c,6445c7eb,e363c6ed,7a1f5902,63de2024), -S(80aa63b3,1fdd0d2d,ef602bab,dd88a15,71abd052,270988a4,63abe269,fc489fcb,9a145d0f,6dcf0edb,a4873287,a2f221dc,4be613df,f70f7755,f28879a,6e7d9978), -S(ca9793bd,796ae0c1,d778f3,6445bb8b,aa50d859,4be28fe0,ea1e2d16,30972503,7304af4,4c56106e,f0064436,c09b411b,926c4c56,cd82577f,f8c01ab9,9f7c4c6), -S(4cca305c,baf6615e,8cdc8a58,f3a9e52e,97ee20f3,ef080793,ce105a03,a1f1d3d2,637ea84c,9578321b,b5dcc239,7f6206bd,abdfff2a,128d3645,47d474f4,8a8ae493), -S(cb7813b1,a7227a24,cc53b458,1985592a,a9077113,28fb2a05,1d4972a2,3127a913,208b7263,f8f8193b,76dbfb1a,6c4f9264,dd12f63f,e852aa8f,8375fd00,eef83482), -S(d61676be,a11dd1a5,79164cfb,b2488e54,555d7d55,23ddc8a5,454c49e,4a86d8ea,1875b5d5,6db950bc,60b1eeb8,17a94af6,5a19f690,d48aacb0,e483ad52,61995cd9), -S(7142872,6f59c2c8,b398b22f,2ab5c3ca,e803a34c,ab580947,9b7b4d83,1f8e8c0d,3702510e,324c0911,b3154c61,e064ba23,68eff5fe,6f05353a,34980ec1,87ab9ad), -S(72a73d15,9cf7f79b,950971b7,1c66f362,54d13783,c5ef67b8,4da61dcd,4cf432aa,77d711e5,c1793c36,eabf9b86,bf3a692d,234f02db,e4d5854f,5deef926,b9818d2f), -S(ab3b2de,c0a8f23a,a7d3b9d2,88870969,2e45ef47,37a792a5,d65af92b,e58f6347,ac4e4ac9,1bbb57cc,1437e612,e4d4ce37,3d4f0286,5905b621,56826d80,895cb48f), -S(fe5efdb4,32715fed,f9bbb16f,d65ddf6,4ce9bb13,14a491c3,3bfedeba,cb4704ef,e5dc36f5,5fac6974,eaf9d8e4,232a22c3,8aacc6b9,1225a97c,2e695940,ec795c21), -S(5f94851c,a4149e75,e44a0d8,17e81c75,132eb242,c96ae41f,53f30ab9,c8c828a,d9473c47,505e0117,1a0f8682,777d0ca1,7399208a,b03974fb,4014f5bf,c8cbaeaf), -S(5d1bdb4e,a172fa79,fce4cc29,83d8f8d9,fc318b85,f423de0d,edcb6306,9b920471,d7bc7d98,86c861d1,86b4466b,c75dd9a9,8614e166,693a9184,8fccf998,847cb2c)}, -{S(8cf1437b,d87e7faf,550fcbe8,81b0741c,ae0b48e6,e0b3c3d9,9b1b1924,2a925a26,17b40146,c313b1c5,3bdf52e0,efebda45,80d86783,910996fb,8b2d0acf,9bd253a8), -S(fedc65f0,d622743c,53fa6172,e68d983c,2c9b8fbc,58943f48,ad06a852,c98403e1,ca5dcf28,1a2f20d1,5fed06db,89dfd290,8c9d32a,cf40fe6,817e861f,7f168ea9), -S(846c6a48,e771b90,4ae1e8d9,d3daf1ff,d1cb4c88,bbd1de98,454bc817,954654f0,5a4947a5,8a0ab994,3cd0a90,6c1d1f0c,3fb73d2a,49b9c0d1,a9bd35b2,99475dd7), -S(4998795e,a7d80937,e4abee13,6c14585b,40b2dbbb,3fd3c80f,c8c61b45,cd1d59e8,8c817eab,e210398b,59b31660,267c099,baf29e4c,894e09d9,a50894b4,ebbe97f6), -S(76c29921,eb3f3d12,5c11b906,3d1ac276,a205804b,b3e7484b,72ae0483,e4b3c517,48d8a8a5,fe658e1a,4d736bd1,8f07b5ad,28cbb775,d9388e7c,4fecd837,c8eb964e), -S(78de8fb2,b15ff39a,487135a2,636bdcea,57bb3a14,efc329f5,a06bcefa,7ffeaf09,a55c9e98,5e1f529b,ba7ccb6d,3a5c00ce,28cb14f3,e9012d5f,9f66d8cd,5e45113d), -S(71fb3464,b0600c08,7fe70906,2792a676,27830e50,a0bfb473,ec909530,30799282,fe036726,cb928a8a,8affed30,38977377,2a016e7b,1dbde8f3,6db810d7,cd423f36), -S(f1f23de6,bf779cfc,d864dbc7,b46009cd,d2306b1d,cd0de2c3,65f3006e,565d9e21,84f5a011,74ff8e7c,c9a98f52,3f2980eb,4b013695,f6239016,9cc5a1d2,acd8193), -S(f18909a5,a5db0daa,ece22ac7,12ae04ee,53484793,6fd8355f,9ff5ffcc,ab6ca78d,6306f08d,13ce2b0c,b60b3b8a,b0bd5f46,b3ef2a83,7edce51f,2cb5ce41,79f46344), -S(7598d96b,189f476c,bcb1992d,9a38adcf,9d1b6ce9,6c87058e,24584514,a0df4770,7f288be1,b82da02c,a37f655b,d23643ba,bf3d5cff,3b6c2726,9ece7409,ed78bcd6), -S(1e44193e,8223b57d,8fc68641,924cded8,3a04d806,cf9dc18b,7af06010,4e6216eb,45ea3ada,fd726fbe,2b1d6fd1,858ccc2d,57b237bb,bc2965ca,ebcd1b63,53c2f2e1), -S(80954b78,4872286,8fe38891,2d76dfba,d676b4e7,7901e559,dd5983e4,e908f13b,6fe564cd,a0966639,e0237f29,46e92d29,4aee124f,cb33da53,974e8882,b0acf22f), -S(6dd8a9a9,ad7196c1,3c36464a,5cb9fb41,aad8b0cc,423b99fa,a281c5d5,a6ce6ead,79a51469,8767adcf,ed287aa4,914eedc5,8382af71,5485c2aa,c3a77c4,efe2aafe), -S(1895cc13,f99534a1,187a3d65,d1480669,f0d0c0bf,b42b2a9f,1a6392d8,7e1d2c6e,b7905afa,c0eb9b66,51de3583,2cfb9ac7,ae8d2355,1e334d59,32909de9,ed400a0c), -S(f1efcb8a,86f94997,65b38fa5,8edced68,7737b8e9,49dc05f2,190b359d,9ed2c0a9,79b2c874,22de216b,904572b7,a39f320d,f53e392,8dd8e533,a1a28d93,fdd4945e), -S(2944af80,c207d107,ce89fb90,ea6daa2a,c65c1360,503c36c5,ad798333,90432ce4,44b53d27,fd6730f2,33b8c29,f1256136,c637740,86e001a7,60bc1ff0,f8b6211a), -S(938a1dff,117540c8,f6ee7df6,2d3c2cf3,31b38593,131527c3,9804c6d9,874752fb,4683d049,f096bc21,2e0dc20,a8600b8a,a02133d5,d0ae8d6c,b26e4694,ed6f2aa9), -S(b1b3b2c9,54d1fb6e,98fcf939,efc18803,2f693989,81f19c32,f5e55b30,1f59eb16,423a6754,1a29bb01,95adfe15,c1df1c9d,81394e96,2bd1926c,cc789f5b,eef9ec29), -S(52e23f2b,19048d43,b1725695,e3bdfc7a,f4ebd2bf,594f013b,b80d6d0c,ec10632f,258a6236,67090b8a,73881e39,746906f8,eabb6683,4bc3473e,1c6fa8b6,54641cdc), -S(5799a463,cc817bfa,26bcc543,efe0e00b,ca9d2320,1989e854,620fc9b1,ffc14afe,645238d1,8c69338f,9c9395fa,5ef7c9b0,f62b7dc9,c4c6b9e,c545c850,95b6b7ad), -S(1c493b52,3f5a4467,6268220a,58246228,608a603d,f6edb1c9,1a90b060,70b16069,8d311a45,5af92640,e9fe08f0,2981db57,3b22bf4,8fd5e76f,31c175be,23e24fd4), -S(84f5a9c9,cda291c0,71aa9f8d,d7af5a8b,f2ee0dda,fb9139ed,fee08f0f,3f9cec2,df381327,16527be1,d86991a9,bc28966a,c3c6c081,4fc0def8,85e5d160,f59f4458), -S(712c18a0,ae87e7e,87856c8b,ff6e3f6d,996ae157,970e754f,bba80bee,421fcde7,b2788ba,e69d34ba,eb5dfd62,830396df,3b8934a9,551c6070,ae8203c,ccc50ac9), -S(a5104184,ee996a34,7122a460,cd2eba5a,11d04aaa,a47d2ede,25ea13fa,41ee01f4,f4b5f2b3,f7ec9061,7ab5f3cb,763233d0,afc8d4bf,fc535076,5dc5fd41,cc547ffc), -S(79383075,a46a8eb,559ac95e,7dbeb9ee,51b6e906,27e55b9b,922473fd,5f2eb63a,243f56e9,84fd2673,58754a67,2bac56a7,9ae71a5d,68150740,8eaf8c2d,b55ef1a0), -S(2b22635f,b83ab0d4,9b82edfa,a54d6234,8d3bee6f,edbe3315,9470b18a,96f97821,41d9f3a9,52f17182,ccf02725,b58ebd7a,1f37235,1fbb8f2c,15403890,e8b25b82), -S(272fdefe,148ef7e6,957fb8a1,4a07f0ad,b17c27ea,49532547,5114c1f4,76170a0,789b8eb,5846e50b,d489bf66,cebd873f,7cf05619,3674e7d7,147ea691,6a9b8451), -S(2c2da4c0,8a6e73c0,2efd6e7d,13006135,f09990a1,4c0a0eac,1f286108,f4a2a0e0,8011a521,d7fa0ab2,75765bcf,50dba163,9e89c9,300e8a25,31942cc3,fdade63d), -S(19a9e5f,1c4cae30,797a98db,a24051a4,38ea755c,7b062094,a34ed6e8,8a8ff2cf,e199e398,157a50a1,56f9d6d,afed48cf,f3181411,77b792ca,c5881898,24f1b8dd), -S(f7a4be3d,fc6579fb,43c5a960,890893a,f4026165,ed9e3ab2,e6929378,b63968b6,29221093,17dc39ea,de2d6fcf,c735ad2d,668fd047,2eefefa1,b6b225cc,2f3cb3ad), -S(e5380fe8,575f26ad,b7924ae0,d58138d2,68112776,b11bd34b,3eb5e196,33f0e9aa,4680278c,6f784be2,a496ec9c,6db371fe,9046b1a2,b97ce71,3b45bec8,bf7d8a20), -S(4c1b9866,ed9a7e9b,553973c6,c93b02bf,b62fb01,2edfb59d,d2712a5c,af92c541,3e086d2c,df4175f0,804348ac,31a91963,39ad1528,1bc14e52,8d3b0c01,39701c0f)}, -{S(5a13b9b2,5aa6944,1b0b5fb7,f7665dda,95aff48,e3250b4e,34cf8e28,87406c1c,245f250d,78fd66ef,24745e09,f067f16d,d400c387,66d2a1a9,af51e84f,733d0ba2), -S(617b41c6,8534072f,2302290a,4956171e,902634bb,4356bd27,ab83a377,13d8ef6,c867779b,97383817,dfd0971f,64c09c71,7c468a5d,e1bb8ed0,feb98f5a,305d8e6a), -S(ac118ae,ed46b08b,488202f6,96d9469a,e9af3cc7,ddc8eb71,44903a3c,ee43c654,f992fcea,8268ca6b,79f5ce69,c87dcfa8,42ea0345,d7c85a5e,a1b89f1c,9d0217aa), -S(741dc47d,2e0d1424,3f2bd96d,9033d8c2,9008c1e3,66bfb5a1,1434f1cb,3d85310f,c3135d44,e86f574c,266f97d0,f0279dc7,52aee0ab,8e3ed78b,ee0fc646,c133000e), -S(2e973138,f6cea9c0,5adfbb5f,49a7b928,5ae0c15d,120a8b1f,2d0c76ea,1fdcc7e,a05bc93e,68bc82da,7a7c7e38,95a647d8,7f724f20,c5b312b,738c6dee,90de771a), -S(9d938d6a,cf56104b,5522351a,3c424e01,e4d21c33,771ca94c,f55357fc,fe51f91e,881d05fd,4658b08b,edf87396,be3fbb95,ec9f371d,79ff4586,6ddc803b,65ae763f), -S(37a8ed2b,4085961b,84645ad9,8f2c901d,fe9a9a8b,4de8fc89,2cfbca5,c8909835,b1bdacde,94fdc3a8,78cd0eac,f8865d64,77e2cff5,efef834,97b93835,5b7b401a), -S(da1ba954,899cb05,dae6fea2,dc8ddd7c,5ef9e91c,3455838c,a49d2858,ec217d66,14051c3a,12332d70,f8ad8ffa,567765fb,def69640,4291b81e,d3978bf4,51f788a0), -S(92d2ef44,5a10dbc6,73f8c1e6,af093596,13bd1e3,c1b24705,bad2b3de,e8f11b81,adfed916,800d3e94,91a42c59,dd72e3ea,57d47081,b9afe668,f853cec2,c72cbab7), -S(e62208bd,52620df8,91b3ddbf,e6cf0641,6059ce50,be3b00ce,14e7a53,6d1acb07,1fb71455,53b2f4c,431fd86f,c72d51af,5e2edb41,dd3f69a1,9a971371,d9679dc5), -S(191fec47,a48ee268,35ed37ff,6758a80a,532f7011,ab099048,b024efbf,cde1d0ab,47b6389,b3f5534d,a632924d,5b65918d,f65c9c2a,2904ee95,4f24aeb8,c6a02557), -S(60c822fe,a74d52b7,d5203720,b2c2a361,b7628aea,d2a683bd,80655636,bed15714,5d9a9c0,120211b2,e8285b77,8f8d4bc0,b06240d9,22944248,e1cfce73,826bb67d), -S(f602da1c,788ea65b,cc339a38,c353bc08,1c43c2f2,6e05ea6d,ab52648f,890c9101,21468929,89348f8c,67cfdeda,31ef3429,23b5a450,9fbe9a49,f011d42e,57f998e6), -S(756240c0,5274101b,3059d23c,76d9ecdf,33e1312b,7a36af,ea21e6a6,c52cdbb5,ab24e853,900c7ff1,3e4f813d,a2acdd5f,53ce1710,b785ffbd,e74494ab,43e583ee), -S(8e815b45,7adf482e,e30e475a,4949e5ae,c7ff494a,a918f07f,c39441e2,360d112c,a966f04,2dd9edb9,436b0005,7473aa66,dd19b4d2,cbb3bd95,932ba98e,f1a1f406), -S(216d5970,36c661f2,cf6122c0,a136cc33,9660306f,1c190ee5,5f3bf438,e7189261,5bd23797,c6753eee,6fb934bf,dc897ec1,25b31c9b,9e797ef1,56d8cdda,2ec1d128), -S(a30ed06e,ce34d29,a92fdeef,6954b5ed,4065d592,3af09be4,f0ad4a73,e7c24346,f6aea418,6b38c188,b84fb6f4,2b6559be,f52dc13e,b7ddeccb,6e85a76a,8d4efeaa), -S(aa42d20d,8acf7c47,fe40ac15,3fcaf1ac,6c4ecc37,dfa39c39,fe5c7657,c78444d5,bc3becdf,464ce930,e42a05b2,c52d3589,fd45ff37,c7d1767e,f8462811,89634059), -S(7585f8cb,4812e306,de02393c,c06e9871,1953133c,bcb67ec5,c6a79228,69124ff5,c242853d,1a2c1c9,a1cd1b5b,364888fd,28bb23c1,2b0e169,67961b3,e7c8b95b), -S(b096a1aa,fb969483,185ba1fb,a5fa3f3a,d1da87dc,a10344a4,d74ef471,45cc45ce,edbc9490,23801861,44ee39a5,7bdec0a,230df57a,72649e04,c4c99883,a147f0f), -S(7034d8cf,df226df1,6b310628,35dc02c9,f3e3f91a,635ad93c,46be292d,56c0ec2d,f783b6e8,29447cf2,32769a13,7ff33f82,f9fb166a,aec8c3ad,1679c48,c1a913a0), -S(9f88b01b,b936defd,f61156a,b55ca290,cf282a2f,3718b0cc,2d32dd3c,49248b4f,c24ebc35,27052f77,41087cb0,e772ce12,1035042e,603f1301,e19cee0d,30029230), -S(14443190,51f05d23,343367e9,6add133d,fcb63209,2f218847,59ad81ba,c65e7445,745216d2,d11f2556,7e3b224b,6dce478c,bb988b96,a1240093,964e4ba6,f3b15554), -S(54aa2e02,3038fd83,f17a633f,d9ab441f,e039dd0c,57f9368,3da013f1,751c6813,f4d163ac,a9af3e08,c009b44c,b358ebaf,31aacc5e,e0bdb917,d1b4df5,420d2d34), -S(fd44e742,b04ca4df,693e3109,3ec52ad6,1f67264e,100618e5,88d638d6,d96efa41,7ac09cb1,2134a246,b17ce054,b38f3bb7,7d794f9b,2fca3786,a0ba665d,3eb0f14e), -S(f662f214,10cf6e6b,7f79fca8,7ea3925,6760d83,17478419,ff4671f0,2bd2ab6c,be4ad0b7,a56c87a4,8fbc166b,da8473ba,6518385d,bd004b5d,c85126bf,7b9309bb), -S(520e2755,1cd804d2,67f9b4ca,b3986952,612bb099,cbd3f3be,a54f505e,bba4db64,e3c75cd2,c831c539,b095ac18,3bb13a72,ba7cb152,5b9c214c,288509a3,98a9cc3b), -S(4d16fa3,2d74de13,111b3f22,c4133ea5,377921ba,e54af1d,666d6e9f,b01e117d,a63bdf75,78d73f03,75aed657,fbb8675,67230c3f,868f2cf7,b7275ec8,b02ac46f), -S(ab928c61,ad1c2f68,905b9e95,3c2629ad,9bb7c8cf,ad9f5a4b,35b35fad,69a92568,bf39ec2f,6c1ae222,ff383375,6bd83882,c05be6ae,692539a4,5124b972,e72159ee), -S(8731aaa4,93580732,66b96577,7bc24a46,17fb8363,51c5ad8f,c8bc053e,802dd07d,36957f16,1020430f,69a3b1c3,1a6df993,d9ca8e2a,8f487b7f,b2ccd44c,7f528ce9), -S(3514d41e,8b9388e4,33d1155c,c777c398,22ab36c6,3c2aaad7,ce674831,21231d11,7657cdaf,e9fe8147,10bb2ee1,a97c6100,6c7b0ce2,f5086141,ac2904be,1c7a9e3a), -S(9bb8a13,2dcad2f2,c8731a0b,37cbcafd,b3b2dd82,4f23cd3e,7f64eae,9ad1b1f7,6ba44d4d,50111c46,490622d7,b079c17a,f0ab57bf,b8ad2ac,9becf9d7,3c7edfaf)}, -{S(e60e88f1,dc24f079,f835b687,778307af,83446e,71809086,e6dac0db,9f191de4,25a0b86e,ff05c849,d79a176,1a634d82,29d2a759,fbd003c,b6ca4147,85726362), -S(55a5e6cd,c9e11103,749d469,dae84a88,9e744dd5,d9309762,15050a83,fef66fe,31278ace,a971a41,e2f9fb16,8e80ec03,37009cd5,b0a49938,c28c902c,a7c71fd2), -S(5f25326d,e99a7c5a,d81bf2ea,61a9195d,48832bfa,8caa9777,53e483f2,b5a62580,40b69a1b,baa2d0d1,5cb78a3d,3d184c08,5b4c16d2,90751ec9,bf3eb3c1,d3ec2ab5), -S(1a32cc7a,f88976b6,cbc89865,89e685ac,49381a29,1579bd2a,13f9488,c0333d19,4667a3e2,2048f781,11f009ae,5d7b1b97,850a3a5b,86f77880,b128c8c6,a9720acc), -S(1d78e74c,66247be9,352c9797,5fbc1299,743f9c74,68c64d1,f2d8affd,1b098769,37adf553,fa2a11e2,6913ab02,e59c4f2a,48133fe7,d9aa3c24,a76e9af9,48a29d8f), -S(8bb6f83f,6be5c2e2,b2bb265a,9bb3c931,bd5cce6a,48efccdf,daa040da,535dbc86,eb96a982,23278b81,6284fee7,b5b8a121,7350cdba,d56b6078,89602bba,bc003481), -S(a9f19ca8,1d2ebafc,4bb5d881,76bce19a,d2d2564e,185f905b,8f9eeca5,d6b12d6b,ab23a468,3279a9f8,e2e8f880,e0accbba,844bd4e9,4d3e4b43,74db2b55,d998771e), -S(19680305,c887467a,c3bfe44a,dbe65431,7323d8e5,62271e25,1a794b78,618befcc,48e9303a,3d6371f7,cf0a904c,cf16f606,b0007583,87ae0952,c6119521,dde25532), -S(18b3bd03,ed4696c4,7c3f896e,5df7481d,6f19a5ef,53d62ff8,2948f1b2,154175c,85fb04fd,6573a19f,2c136753,a1ca2585,d39dd64e,6e6e3fa5,fba362b4,ae9dad36), -S(38e3bee1,3cc3e18,a57aef97,4ffee58a,a392c311,14ac8baa,1376b56d,f8ac017e,8596c7f9,8abf3e44,4ab5491b,fe659619,f6defb58,f48e2b7b,57842193,cd48fb5c), -S(dba5da08,8cd17c33,3e892bcc,46261694,d2ff3a22,2a26f92c,17c5e1e2,797b235f,ebc15bfc,5729e986,85a19afb,d7f9a219,e60d2784,e9b283cd,3697f782,630fe222), -S(60456426,caea7fc4,48970eea,fab9c632,3e66fcee,50f92630,7b130937,25b85ee8,dd22df89,c5dae339,49459593,1433f2f6,5f719379,68e56f92,a38d1290,17881924), -S(f1ceac82,15670212,279f36e,f0c8ce28,3a192f66,460e4875,d90b2f51,a38f5712,ec11f026,c76c271e,fabd7d55,c8488d99,3298f6ff,c05ad4a1,26be9447,7d878b9e), -S(2c2fb5de,5dea249a,7bf6b196,8bdec8d6,1838da2c,12147045,18d6494,f09e50e,6c0d020a,d6bfd730,5ee73634,e939ac89,ca2b7d4f,dcbe760c,2d14ade2,659a5b8c), -S(2858ea8c,d40ce264,3c9a305,c0e2c758,af5b0b4d,5c57ed21,60cf7ec4,154ffdc2,33586bf,a61a3cde,4f402bea,123c69e2,2410c0e,590a71d8,9a1e8130,85cbb579), -S(2749a250,4e7cefa3,a3647088,6bec22fa,339fec0d,ec63c02,19e6af39,7fdec3e0,d3415104,a9070af8,b61acdf0,77954d37,57fcf742,a006129a,5c0d3529,3aa95407), -S(8edf3ad8,39e661b5,f7f16a85,dce3caf5,d571acf4,d0c6195c,53b618e,5311ac65,fca0efba,35a14d3a,9944367e,db4ac982,7dcb7aa0,12438c5b,aa5627c4,c4a15ed1), -S(dbb92358,8b083294,5d6d3b62,9cced57d,7085d3e2,d0890bde,95d80400,98c22745,42816661,5515429a,aa023737,5fb77804,624546f2,1f0a34ac,1ed4e4ee,dceddccd), -S(aaca9896,6196ce2,e13df3c7,d058a5e5,10566df0,5fefc04e,51f9dd,85a4349d,be389d02,789548e0,aaf67c57,3b91b389,c7e6ed80,ca3e637a,2a147262,80cd5620), -S(104804ab,e621b098,61fc540f,f4d6be9a,750e3cfb,706170db,e34c06ed,e0a431ea,14b700ed,a465915a,eff84ab9,fa568535,f63e4f44,1387ab4b,d841072d,97739071), -S(b2215070,a8ea71f9,b71f1a73,d6ce366,c322b8ac,4d135b3d,ccea68e5,a51f1c0f,9e415cce,3bcc4e62,6f3c8caf,fd632eea,862a046e,bb45e8bc,84fc05a7,a4b87e00), -S(600c6e28,be5ebd28,d83e6c86,bbbd9b0b,aca22006,42234634,6124133f,3348e6f7,822b1816,79e253db,a47ddd76,c0023991,5c0c0206,8f422415,94ac38b8,ff7994fc), -S(f8b9b45f,c6298dc7,13355bf1,3ee33ca9,c4c1aace,c09776e2,56b3746d,ccae0dc,bf4b7f96,1844aa2c,6ed8c8a5,6626386d,174e77fb,98c0c23e,e2b6de90,3f1f79cd), -S(63987b18,67fe5a17,333eef28,5385a0a6,576163e,2c74cd00,ba87b6fc,96a57faa,23ce6655,51d48ca3,c702a5be,87a05d98,b5aa1097,dd5877e8,11e32d76,4873e6cc), -S(2eb06c4f,5ea9ad2b,124a1202,cb13c1ae,aec4394f,4af7c96,d6a9ecba,540ee04d,b96173dc,77b46ef0,6f4141ec,96ce8d1,4adfcfde,f0bd7ea2,479ba6d7,522d037f), -S(5db39904,153002b3,1498bb01,16efd0b5,838e3495,62d9428c,912987f1,3aae5ae,2115b896,479d0d0f,75ffcb54,ff9e3f73,d1356ff1,4b14292c,6bfe8d54,e9e08861), -S(c0f14110,7f324ffc,f3d3e6c,78d5a628,6000d57d,7e85bc7c,fda15f75,79cef3ed,6eb03650,c8142b12,b330b96b,81214a4d,d01b068a,74827611,53d2c52e,e1315ce5), -S(7e3d1510,ed767345,bbb3515b,6f9819bf,33ed9dea,fab35d01,a7284cc2,371b0e66,4c6b3aca,5159023b,d43ec0b2,57e77e87,e5a6b745,178bb017,9960c89,361fd97), -S(f98b5dbc,3e54c227,b002f458,94850ff4,3b15b2d6,1607851c,50d1e4d1,8b20907d,1d2af742,b0b5ec05,bd6c648f,94563361,be03261f,da56f1ca,7caece63,a336d580), -S(188ef3bf,ab103784,37e1859a,7d53e899,6124c395,ca422c05,d6b21b3c,efc76ac1,19036685,fad04566,2ffa04e7,30c671c7,1b299217,c389c78a,cae9fcd4,ad70fb73), -S(b89070ae,96ead4dc,49be16f6,a1a30bc2,41b4e98b,c18d0227,4c9d9d87,dcbf00eb,90db373d,375d2770,b8dd6b1b,3e3b5899,34f274f9,49469598,e480e431,e4f195e1), -S(381c4ad7,a7a97bfd,a61c6031,c118495f,c4ea4bc0,8f6766d6,76bee908,47d297fd,6c950ac4,dc71111b,70c1a058,f66ea133,fbaefcd,246c63ff,6c531ce6,82b6bc6a)}, -{S(704a26e5,19071bb0,24eb2a16,48b66a6e,157b07a5,52fc4258,381f7d02,e8fd9b9e,d169ea55,8650aa3b,ce52c645,278422a3,69326e74,46039381,920f5857,fa3492fa), -S(705063f5,e481735,60afe9dd,5b2beeda,d6e46391,75ad7fb6,f73350df,51edf53c,32290956,61cacec9,472dd014,bda52364,3399d7cd,9ce2bb31,a5b23590,22c6ee5c), -S(972e7585,f8b1725f,4a7d18e7,77939aa6,3600a7b,a07c4d94,5da9511e,889473f5,aae4382a,49b4c97a,bc3edb7d,26ba7bad,16752047,dc99b434,f306c673,2851310b), -S(260530bb,e338f4a9,71930b12,4f18c82d,e33f22d7,32de9375,81e2b0d5,15e59d97,77c66c36,d6b09205,8ade9c0c,a311b60,a705c8c8,73fd2d4,8e6327cb,71eefd4a), -S(15464351,d21d2513,f792ee32,aca3eca7,a52cdaaf,9862172a,e7224a03,804581dd,d9ee19f4,502f1c44,f656ad4e,add6adbb,d8a04f5e,5344b554,894721eb,8e3e2285), -S(4fcc68a3,caf3ff91,dcce9770,11ad5157,6c844132,321791ca,a652593f,6cafcd04,e8db3aea,a35371bf,9700a9bf,b85e90b3,93cc088,9cd655e3,fb18635b,49fb59eb), -S(301c65ad,567952dc,6b39134e,c361030b,3f5203ed,da89784b,225548ec,45c75eee,95e2c0bc,7b4a7cde,8ce3dace,a691bafb,f78fb03f,3170b347,ee807f42,6b947560), -S(96ca5edd,8047ec6f,b5f8c37c,a734533d,13f0e6e7,f55d28,b8b10b5,121f4abe,1a21f1ba,f6a2e336,247f6ee0,88cca9ff,816b0667,3badc241,d9ed00fc,d2070f1f), -S(c94633f5,783c4e68,12143fc4,6e670978,8e8a526,819afea9,404dfa00,df1bd839,874f8760,33dba9,de463f86,b597219a,c1ea37f3,970bdadf,97c96c48,feec4ec5), -S(963146d4,5bdaa05a,b5115ac2,3ee862a0,2305ba9c,75003f4e,ab838f7,e9adcdfa,d75766de,299e5cf3,c8796234,5db9866c,cf011c5c,f108a794,5642a6b9,dd33eb0f), -S(dde8c870,ec4e9890,2a820a7b,c5784034,19ac261e,de5afd0b,82b8c5a0,7c2863df,e7833936,50d4af7,427158e4,6c753ac1,a5143c9b,c09de97b,3b27065,6f622b82), -S(546c6b00,c5e34a8c,4cc7255c,2edea33,d9f77e7a,c67ee629,bbdf1879,4622265e,5ae149da,f65aba8d,e214fa63,be9bbf11,3dd3c220,12d206bd,d56026e7,4a019897), -S(4340c850,d91b63fd,bdaf41bc,f8d8c010,d3f30eb5,79eeefc9,e67c127a,33324071,dd66033e,eb5ae8b3,3c47a940,2482bcdd,4db5c8e,dda3b422,35627434,dc3bad1f), -S(f796431f,679d9cb5,77bce62d,236d1fe9,b5042a83,fdd1cf94,1a2e00c0,5a261d11,718fffe7,68aa2591,d3fb1fd6,1a00537,3b529f9d,f9c27f79,31ad0df9,9aa74859), -S(f3d17ae9,d5b4cf41,27423894,916318bc,adfb5a9a,6c2ca219,1b918e43,eb5ed129,9da6d033,49c64d79,7ad09a33,bf71cf87,8e0ae6a7,9fa7bc3f,1451126,18415960), -S(23899a73,a4b52d27,29ab52a8,370ceef8,4c7684c,cd535f4a,ec360eab,cfa5a787,f1bcde3c,5c4740c7,37b066b3,8a1a88fa,c43357f7,f3fa23a7,b00815a3,85336320), -S(5805914f,5418971b,106305cf,c397dc12,f63a3b2d,8b451e5d,c1b60c2e,3d9e9208,616e2764,67a5f1b6,46279ee9,6e8645f3,76a80192,31e17a5,c92e26ec,1b76e62b), -S(85ffc326,1991848b,5e918c4a,53f291a8,31796b52,d56a5c38,8bebe625,d78cd07e,95fd6f12,7b155e6f,806c089f,3f5abe95,344e9014,e2c72fdb,e720bb8a,93d864a6), -S(6f1a57d0,6566bf81,f4b16329,19f477ef,aab4f829,e29dda4b,27627b96,1cbfe3eb,de1e8359,7ff20c63,3d28b909,caef273a,a57898f1,a797fd91,e00e2e7,da1872f4), -S(3d28eba0,4d0ae2f6,208adc71,cd6af3b0,e208860c,722903ab,e106feb0,af3185e9,cf8bad18,40d3d2b4,abfb5b28,b50702dc,512527d9,5bcd403d,9713ec7b,ef1dda13), -S(46511979,2b845113,1b32663e,baa14c4,20a5408c,1f53afb2,43cd496e,c4b18118,40bd602b,d740096e,842b40fd,8304ee73,842b074e,415d5ac,c5e2243,28b241f9), -S(393a8bb8,7ffe4265,51678524,8ac940c6,4aa70e71,512ebbc2,3485596c,a6d9da5,25773032,d2c1f80b,3954715a,6e4132a1,74b4468e,658f6cc,4d5f5d63,d458980b), -S(aeb37eed,35274696,2b85a21c,86b9fe34,60433606,9ae4ce6e,3a8235a5,e43c48ad,d94165e1,5372330a,7b5507f0,377a966a,541b6fcb,949398c8,dd6d6f52,2411d86d), -S(b0bbb4d3,100ce417,dec58f46,95ed8b30,4306f21f,ee11f899,585fb37e,a9905c59,89141fcc,9344e617,7742e31c,42c565d0,45c7ccb8,6f88df7c,5c36d23e,45e51d75), -S(49694de7,330b4c3,1431d452,f3e9e562,eddfe029,1cce58c,73b69cdc,b89e0f49,4715ea3,b6fdccf8,e224b93a,ffdfd1ac,ad8baf44,c5bce735,e7c9b4ef,3faa2656), -S(9a7720b3,ff0363dd,7263e1ad,83c32526,67b67d3b,72c2c14c,95f0804a,dd20f7a8,815a769c,494824a,a819ea,54b560ed,e1df9bca,d7df2d63,aae69c4,a02f9f20), -S(b89c399f,cdb3aacf,99796fd0,95c17cc9,786d79b4,9a1a255d,5c9ee510,38d3620e,ee3c4936,d4f9d1f9,d2642043,d25b21a1,aa32fa3e,ef44f409,73db47a,96965cdc), -S(add68bac,d7180ac1,4e9bbc5d,1e0c3911,f2202d90,1f9ba649,46b06507,b86ed5e9,fcffc13e,a9be67be,8d090a77,9fd9107b,f62bc785,3f98e97a,c0358b3b,7719944d), -S(9bf62cdc,cdabe928,c1ab44ce,38cd0611,135971ed,81ce6c6f,dfc5eb5b,d9c3996f,885b2381,e0e785d3,cc3f78c7,f9fd54b,ecdd9d9f,c2979e23,f97e9bd2,a4f10d3c), -S(bb223cee,f11450d5,c5e0b75d,20eb44be,9d44dcff,28574117,12fc5875,3b839339,8bb29985,87eb6f5c,c8cb615,285d9e69,71db8e31,8d81fd5d,6318909b,8311a00b), -S(9ed73f09,2263e84c,d022388e,da82361b,445f573d,b646cc62,fa0bf5c5,1d33fd27,49ce7698,144e1115,118a4b0c,bdb98dab,6b57dc1a,4d1bb6cb,a68d4d20,d8e937d7), -S(e747333f,d75d5175,5a0cc9f0,a7287084,65a02c58,7737a7b8,b8fa1b8b,4bb2629a,d5001fe,baf8f3ee,b33bc9fc,7fb3da7e,377c8955,91e56965,607269e4,96b90559)}, -{S(516ea742,3f956765,a15f856,182f1e7c,18d3e548,b9fdca94,ea46024a,1a8fcbc0,cfddd98f,be500604,28beb901,92c01282,aaf9ed93,76f0e26b,e912ac42,a378d542), -S(8ed072cb,13eb90c9,e5c107f6,ba576a87,ac75a431,53025e6a,86addb95,bba7862f,eece8a5a,f28d356b,f1a84c14,2549ae7f,894f7c07,305194f3,18e30e0c,873fb5b0), -S(3e0e488b,1c8acc24,f81bfa1a,f6761afd,b4fa5f5e,6317ba72,bfba2f07,6c2ff593,2c4ec39b,2f37b948,fdbc9e3b,a3fa82c0,dcfde2e2,57830a04,4c178759,ef5bbc8b), -S(f6b3f19f,cd7eac5a,13630ad1,bbf331b9,5608b7a0,ceaa67e2,4a1e830b,5eed9825,a2a64078,19ba0f7e,7a890df9,523c6736,50ad08d5,c2557cd1,53c6ee65,ef493ce5), -S(e2de599a,879285ad,398b1031,8e1a8387,21a5c4f7,1105469e,affc8e37,189548a,dd977e62,3dc05cd6,3155a71d,d87d91d1,d74d6e31,5f73434b,679b605d,9db264df), -S(bc52359,683840a8,59fc2c8e,22d72ec5,da2493a4,bb5073a7,f658517a,de83f867,76a13651,712ff42e,a0c10f09,45c4ce41,2cc8c4f2,ac3ae446,7cb383c8,656d3186), -S(d87e2b08,154e38c0,13847a5a,2f84c276,dc088b6f,c19a9bf3,90a8a433,fa937fda,d91447f,7c9042e4,6f64a9c6,40a5c294,1a6f08f5,d3eed464,b09b2a1,1c402c0c), -S(4359ac5c,5dd70bf1,d4f24f00,1301b9f6,17d9c69b,63350dad,9a8cd192,655ea801,c9e14f94,d8ec39aa,46092657,5d770426,350794a4,b1ef2410,a9b0118c,ac5d55c1), -S(3ab3f503,29e22bf6,8fe9882b,3b4dc989,36dfd840,be6af588,ab6d61de,48094b9e,4a40c435,9f4dd21b,11664095,4b55e6b9,f0308786,eec32fca,6bcdd5d5,8d055ac6), -S(a0f1ac27,d046d987,b9a98bf3,f770205,931fce93,59b75944,6494d221,dc2752b2,bf1bfdc6,47a15997,97b5b6cf,2d8a2a44,e9c36b9a,20b53abe,58ce9e0a,395fab70), -S(a9aa63ed,3b0260d2,b35b030c,7a5511c8,679b6170,b8a4f386,fae0bfa8,92735905,2f654620,4dba9b31,99bd648c,cb1605f7,62f312d1,67123d98,ed66f02e,4d794e90), -S(e51da157,5e566ef3,bad3fa66,e55432e1,29be6c36,32e390c0,f4d76719,bae34b7b,55930b79,2ffc91de,674820b1,eec290d7,74ecd79d,1ca07d6f,5ea2f817,4759984e), -S(8b69a891,b417ea65,7ba52bae,58920eb7,f101bb92,e150dc1b,c961c37e,73cd18b7,5b824edb,f4a68988,39de0d70,ec16ee1c,a01a4692,f29263e1,1069aec8,6b149214), -S(ee5c1186,77462649,6d37fba,e48e797,dc69f31c,d6ad22cc,937c7224,ef7ce8db,13f7987c,f2cc4551,e058d410,3d5c24d5,13c2d602,ddccadae,fddcab82,d14d5310), -S(b961cb45,5de8b5b6,c4c5c2d5,75303c81,35b5d278,503a15d2,371b0551,5b236b,3ed18486,5ca969ba,31c734a,19055129,1cd664be,576925a3,2a142769,4fc40df2), -S(83effa4,c127b5ad,7a0c53df,5be5596b,d4a42987,2eafd8f1,5498a6d2,47b87314,efa99759,c9360b14,7643de2d,64ad07ea,39cfabe0,2bc94e00,dc9b2e70,c2e2c217), -S(f253fc52,4fb0254e,e772f50e,5d6c16d8,48692455,c855d4be,15ea9f9e,9a5411dc,59bd1f8,2cece609,8a63fa1d,48e4166a,d79174ec,5f8216c3,16c48c1f,e5c9a0d7), -S(6b61024e,e6451d97,1446b55,1476c3ec,eb6b19ec,16155acd,317bc2be,11086411,8de5c6e,37b562da,ca5a203e,ea028b76,e6befaff,e54b49d2,6605f169,592242cd), -S(1691a90b,9cf72621,3680a72d,af59ef24,985448ff,5f35372a,ab6e2aef,df8b33e5,83d2032b,6ca761d1,286c1348,31250054,5a230558,cba391e6,f0db9c9f,97c2d618), -S(42a078dd,cf749f25,aec7a1f2,8e976f79,e268c36,a7b5b0cd,6aaee3e0,925746ea,c60f1846,6f025987,e0ea6ca0,3eb98df6,99389753,b57abbf4,f5739509,bfd09d1e), -S(21bfc1a7,16b09543,5142c31e,5038d4ea,4643d9c3,2fd4728d,1374dba8,1ca1f07a,a991d491,2601ca23,8e289e71,e9d743da,4385aed6,c732f808,6dc21406,74540acb), -S(e75223e8,fe247a98,5220cbfe,52151978,c98d1460,746f8de2,8696d235,71f3336b,dbbb8075,ab489582,52472982,c7b0c3bb,d82a0762,36c07c05,44417ff3,883f6f18), -S(7a756a,72fee88c,7a2758a5,3294da85,6b06129c,1978e217,2bc7952c,92b05265,c4ad3a0d,be72fd27,bfa475d0,fbd16a92,5e939362,bc0748c,c39ba9f0,3ad84133), -S(2bc697fa,d947fd62,63bb2841,1a274520,f5d582f6,7f039114,293438fc,9aad7c82,543109b9,82097efc,cb44d854,11fc5230,6c7a219f,2f58b37e,3dd354a8,2ffb28ad), -S(3862db95,1ed8994b,a8cc0178,f6dc97ef,db6e1380,c18719ab,cd24a88c,87039744,af1e8ac9,2b195d3,6fe1b1be,a68e9215,a453e638,67e65d88,64a8baf3,ff5c1267), -S(7b648cfa,40ce7274,59a6fae2,2836ea1d,b18ada4,9b18a61d,748127f7,7ceee771,f2a30c56,42887135,30124a69,da2c0355,8688bac3,dae6d95f,a252855,a85a9b4f), -S(f803d7c6,1820f980,ebe0b297,87aa688c,ddadefca,229b99b3,a6bde5e9,922f94d2,a5f8b450,34dc7de1,461dfb74,e7ed9c49,80407bf0,4b0d9159,af703a9e,1e0f9c61), -S(2247f630,9be2f3aa,e30c5907,c29095d4,b9198d25,1a17bb34,7cf5cb35,a2ecb1f1,82685964,20d87b07,1c5a4044,b79b069f,7fa6ecf2,cfc0f839,b2161475,5728c2f1), -S(1d770ace,ceb2183,fea7c924,a8fba197,579df37a,908992be,d42c8e80,8bd98ee1,d87077fa,b910a21,8769cfc7,49aad579,c809e35b,f1c2a813,6047e85,e2c6fc65), -S(5d134e5c,5da47f7b,a495f216,b4994d90,4a79057a,3d0076be,34f09013,99f1f366,fc4e10b2,c1f7bafb,d241d5b5,1c57d48c,30fd29e9,df5774c6,1d4f2c15,3b66ed03), -S(a49ed10e,aaab9323,3a5f485d,4bd18c06,28ab2629,f0b8c3db,4d05956d,6c953fa9,338d476b,99f0ac67,1fcb893f,5f202204,a5178acb,6971e7e4,984d42dc,b904afbd), -S(4d000b62,1adb87e1,c53261af,9db2e179,141ecae0,b331a187,aa4040a,ee752b08,95f2a470,e71f2daa,34927daa,7d268d33,34820a0e,e638d6c5,c18d7adf,b7cfcf45)}, -{S(44d42980,eb92b3e3,b16816f5,56858355,e031b88c,99117385,def6599e,f274e56f,6e3de5ba,4f693fdc,747caacd,b2cf0107,f29fa7c,9c6a1a09,a527cd16,4c2c1484), -S(9812d508,d6da303,6f08fa7b,54cae319,232f925d,6af91d71,fe6c2fb3,bc86be5,735081a0,35fc17f6,7547b9b8,f0f91ac7,f0ddb965,19f6f398,dea745a9,81441e2c), -S(5a022ba,a90ddc87,42246783,4f692ecf,dd2c2dcf,b054308f,4afeb17a,7ff6ddcf,6fc2a9a5,4c7a130d,fd26ca48,82406fb9,f67db0ab,7e6a6d95,1675fef,2e2d4256), -S(c181ffeb,a8ea7d69,c524cd42,18af3030,1cac8e97,69eaf6f6,ba73027d,30fb7bd6,e88959e5,b07b7d3e,693756a,f94590bf,997763b,afa7d850,a80dd9fb,88e6e904), -S(e29375b8,21c056c,30954b81,4f9ce795,c1493dfb,ebf06f6f,f32c92c8,c74839f1,a9040ad0,95c9d45b,1527c624,bac86841,a1f28b7,ccf8dd37,b7e950b4,858e6e18), -S(69445948,ebec5ae3,9fcb505d,7efb7902,6bc1e8fd,5d3024ac,2b772439,72142d80,5b6c2694,abac3938,db899396,62635c21,e64fe2aa,40d18678,9c246e9,fe3f4be6), -S(a86f3aad,85d0bbb3,8270956f,58c2fd65,f5425428,27d7a658,da1b111f,64c02c36,dec740b0,ee35208c,dbec5b7f,69bb94f0,7fccd075,7868a37,6ecec7b6,dcbe20e0), -S(ba2bf65f,aac92da5,6c252b50,8dd74e3e,99ace1bc,42b9d2db,9d0ead3d,b6820306,37bcd01a,75027b42,eb0d7b85,564bedf9,67153930,6fc97106,ab6623e9,90b031ba), -S(78419e61,4e8b5eb9,d09e0c09,79ce4eaa,26271696,fcc68269,4cddf1d9,6a4c7fa,a32dbb3b,46f9b6b4,9adf4dde,f1986af9,72662a6,2ed6b6a2,f8b920b6,82b32363), -S(71163271,204207c8,a84b5993,88beb505,640898ab,b24c4c10,42195dd8,15d77985,aab43609,9370f246,7035ddc2,e71d73f3,c0f1aa13,148303bd,840459da,ae307e8d), -S(473f52a1,fb7c3920,f09ba6e0,a3c891c3,3f4a13cd,9dbf51f0,f3d39ef2,d6bc07d0,b2c403d2,4aef71eb,1b834df2,8bc08b67,5130897f,a6d9855a,eb21ccf2,780444cc), -S(581e93b2,99b8c50e,e6338c0f,f426502a,d8699563,f17935dd,abe08a73,6932b71f,46e7c7c5,1e076fd8,9b8aa98c,f0b3933b,8ca82cc4,d21783a4,d74ae1b6,ca9896e6), -S(e65d9e24,e7340122,875a9d86,d6071a48,691ed5e5,a94b315c,76f169f7,f3d69c48,73575103,a70b7a59,90d9b880,8698b651,271c8c0c,ac93122a,66873bf1,fa3c6fab), -S(cceab216,41d0597,f9c7ab64,7f99154c,b22d4827,70395d6f,ddd6db5a,dc752825,4084c57d,5aafc328,e7a250d0,a7c3c0a9,627ddd70,c77c2be7,e5a1af34,359b9b86), -S(4222ee66,5baff421,17f47df5,c1c1df5a,dbafb790,d5c75bb7,2646cf85,7ae85923,43088d6c,a029903f,f5a789f8,16730345,5a5cd0af,cab57e15,12781396,fcc9b6da), -S(391c5d0b,17a8c11,3440cd30,83434841,969b0833,71758b30,27e38a25,e778da6a,69f3d295,be55f859,4bbb2fb4,116de5d0,b24b5a80,ed62c1e2,8fca9b8,3f6d7439), -S(803b7149,f87e86c0,13599898,b0c9050c,d4a6e030,e07e8d7c,a49c46a3,8a6ea6a1,6b367fcc,6d5916e,72f670a6,5ada9c39,54800e90,a8830fad,c9ea17c0,494cd9aa), -S(f7aa1c64,f8f92f20,1319f316,353d89bb,eaa4d65a,e148b01f,ab66aff6,c9deb179,e9b407d9,4c2b385a,74f22eba,93dc35e9,bebca7d5,17401b7b,576b7d2b,e13ff0c0), -S(f1c34d52,2b7493ec,cefd49da,99732e00,85ace2c9,fd14e9b0,69b67dcd,5acd5e23,29460fc7,dd77494e,a5a7764c,7ca6db5d,5d7a5e3f,65e865b9,e5f85d58,e77713e9), -S(db19a1f6,38ef7034,5340e3df,8d384944,7500640d,cdbc3be4,df3b191c,edb9db87,baac873,a76e0b91,c4847770,9dbe88e9,6195e9c4,ac4d7749,71ca204d,4a5e748b), -S(4ad12e00,f384c7f6,ea669c71,3649da6,55e0abec,67551a58,224b9f9d,de6bdaf9,2e0314a,8e3f32da,33a22ecf,ccac4965,1f1f6f5,20baeddf,39a02bd8,423cd40c), -S(c9130b88,cd451d4f,6eafffc8,357ba391,ae920c27,69e7c48b,49881070,fd088ad5,aac7c2f,4f2f8b90,bea9267,897e0079,7d6515e1,937fa4fb,1043111,6b5e1de), -S(88260ca,df81b391,be79bde7,b54f8a98,428aeacf,970cd843,d683e6e9,50686db9,3b9b187a,b998a22b,56b2933c,fcd09333,9c23889d,1180e365,10dc086,9869cf2c), -S(3984fce2,ab73c70f,a5538206,c2a61e60,2f160b1d,2eb61980,fe174cbe,fe464dac,b7e65c1a,46b50c72,621e3fc8,4f4c7cf3,6860567f,abf00743,5fd1b13f,7400326a), -S(e6b48495,c8277598,23b73f35,762c55fd,8cd20420,fe5be6ad,f27f12b0,68bdd63c,ccbb7124,3b0300fd,993dc9d3,4b55534a,12515243,e07ab78a,8d8fd528,46e5a69b), -S(6af5144f,342f492f,3f506ee7,fc515d3d,d3c93d02,27ba841d,74bc6548,97d4830e,b195d9e0,8113eeaf,fab92a2,81ddeaa0,95356053,a51cf84a,b5d60fec,5368f98), -S(14439b7f,e40ca407,374da12e,217edd9a,86c84397,e2fcf6fc,965023,ba984a1f,112ad656,47c47c30,f19ae62,e0c06b35,effd49bf,d5e604d,6d621471,9f088fee), -S(d4a7e4b3,863fece9,660baefc,ee57d09f,6f60cd25,f4aa178c,cb6f8a17,5fda9d4f,4985a973,ab0e8627,f6de7ef4,470de4c7,1adecaf9,f3766197,a86f4e40,14ea474c), -S(facc2a9b,9d3ad0e8,9fa479e0,ba777a0c,90a0c229,59d4b719,a9304df5,f1e96ff0,6e12c914,70c78733,3e5a65b9,8c01d342,827810aa,be3e4e33,cba0b7bf,eb283b91), -S(3d1b3f54,2809a7d7,79ca2416,a7b7d007,4a728599,e4f30cc9,14bbbba8,3daa091f,dccd0d01,e56c7e6b,90829ec1,f0fc733c,8f1cbcb8,79916982,3b466448,cc21674e), -S(a8c1ec56,3cf9596,d761e41a,bd6bc960,562eeaf5,b54eb83e,3d7e7259,f69671d5,a03c9fae,e160ba53,8aaf38cd,96ebe3a6,db59a04c,ce7074e7,dc3757f1,ccc244e9), -S(219b4f9c,ef6c6000,7659c79c,45b0533b,3cc9d916,ce29dbff,133b40ca,a2e96db8,db2639fa,26a61015,a5bbe7f,3fc8d591,c6b0753a,c16fa89a,d820fe57,72c49068)}, -{S(b445babc,55be50ee,bedb8c27,dfc6c37b,492649ef,8a65de02,111b9f74,29b8c3af,6f74c5b9,f9a022b1,8d3a706c,5c608b31,9f7ce25d,8424d893,4cbd2f90,84b78bcb), -S(dbed76fb,7e46e1d4,1b507edd,8994fefc,f94bd651,a9720d9f,8d62dc3e,9f329104,c047fc1a,41689ba6,9855f063,c563bfe8,49bd8b5d,37b3836b,d8bc57ca,fd02ef64), -S(844426e0,860ff2db,f012ed29,ad2919d6,f46eb102,68073862,c1792e99,f1b2b33c,243512c9,c6ca739f,fb181482,a901ecc6,a41893f1,371d6b12,31d5427b,fb486394), -S(1df697b5,9a2f9c91,b2c5d4a7,8035ea2a,351dc000,4e1c3bd5,5973020c,24836aa1,e89f949c,f6af652e,d7e79758,74a994ff,46475df5,4f7b17f2,a5c29cd9,7f722831), -S(cf4ffa86,87d9a39,7b4727ba,a033cd02,7d8a5377,46903db3,34c35f1d,855999a1,d1316b65,e027ed02,b4be11bc,4c21c1a8,585bb247,45cdfa67,5fb9cccc,faf0c546), -S(e3eed1d6,1813e3ec,d1b9fcfe,3e8bd700,bf3412ff,78a0a9b9,724d4dde,ddfd98b,dcb09803,b70d4c34,ee2bd7ae,6444724e,9ab27c20,5c3c736b,172af37f,cc673105), -S(3a202c1d,94a94eef,18fa396e,5cb8a867,8c3ae45a,e4ee64b0,822d207e,6c814fe7,147992e5,ab565bc2,ad1b1355,60f37dc6,b5cbee74,fef8e5ca,4e4f418f,811a0482), -S(6ce8f558,a853dacf,205db4a5,80c4cbab,8ef477a6,47bca6cc,9e676cb6,5f3f696a,e88e3934,b2857ec,6edb911f,acd132fa,f0078971,2805aa59,9afb3d80,942dc23c), -S(7fef9aa5,b2df37ac,99ca488a,ba598b4d,eb222149,55e1cb4d,c3ef1e7e,7bd38945,d4b7cb4a,8f9edfd2,3a0efd1,9882baf,98312b6f,7b5775ca,65e9dbf1,f2c32870), -S(6ec1ce91,d1eff7ed,9beba2b8,2f4a526f,736e717d,6442dd29,b55ae2e5,3371e0a2,28240ee,12e2b1ed,b40698e,ba6f087a,145eb772,caece880,b3e94b97,700dbd58), -S(645b9fba,2cb739ee,9b148b29,8fbe9884,f284893d,968c21d9,50696d2f,efbbf0bd,b06977a1,2d19836f,add50b7,b73399bc,698729fb,fd182026,d918a267,eab4b7c6), -S(7b930561,3a4a7cc5,ce1e7f5f,29314e1b,40bc8b93,40604f81,76578c18,69abf6c5,55a7e3e3,3f19805e,b5056d15,deaaa4f7,aea07a46,f9dc6a09,6ce15392,e146fb3c), -S(bbcc74ca,3697ef46,e7415ec6,b31a0808,1e6ade01,c7e2264c,f9d4d94d,d849ccaf,27bf64e,e1005f13,989639a0,8772c42c,b4249ba6,9d90cae,3f542ee1,78929f26), -S(4a45fd82,af96af67,9e640bbf,561cb385,2585a8e6,1b57df7a,e028ed33,a017c680,4ba76ea1,19a0267a,f019b3b9,89cde9ce,7b1c0b6e,da3c773d,ca31e44,61e048ed), -S(c3efb1ce,ddc6a749,a5db9daf,48032a6f,3f1a848b,aef9e44c,ebd76127,a9c90d0e,3de258cf,e593b489,8f92e8ac,50be894c,3636019b,a9f31f70,28468eac,687b8f89), -S(ec71a2a4,6f24acb2,8fda6bbd,ab9326e9,6590a96f,b9b9a4ef,405949a5,e3d2858d,31a91fa1,71207da3,1b0acc25,cace1e7c,5126ca2b,4c8d9733,4c50a7f5,29bc61d2), -S(65dc268e,cfd191fa,f07421f0,dcb16701,f979ad24,81ac5ddb,1f77d3ab,41a773e0,f8c9ac90,255d6460,15ddd1d3,57b92522,53bb55c7,e2f5d843,d7d9a025,2766d2c0), -S(62152eaf,df564900,4379891,4b53ddd7,3b91fb60,f16f2d18,941caa96,18d8ffd3,3a185ef0,a8d8a35d,112f678a,6a04a654,df565a8f,87e99abd,95fb4977,1b278ce1), -S(f68e6fcd,b2c49661,ae59bff1,f24e97e6,fffe7cfd,f185d0b8,133d58e3,bec1c89b,223dee27,5e9cc518,af12be21,ee7ef3a9,ab39c7d4,4f950fdd,9ce5c78e,b50514a2), -S(5d02e9c4,108860e8,2b1ae04a,4afbe1e2,9e0a8444,89876776,7e5b60d9,3fe5c753,25fdcc35,5f1970c1,43dae96c,a1ef0a7c,f95853e4,102548f3,d869d3d5,8bcf962d), -S(f6217e4d,4e6d06d1,27668a01,8225f88f,a1e0fcd8,e8654fd,ab26c8a5,4c6d4751,65a6acbc,19bb2835,13eea5d2,5fae521d,aeed63ca,50f9aed8,edb74dd9,c43d066b), -S(c18bb768,bae77077,35b4d3d0,e82cac24,fe3d7ee8,dcba20b6,a320ba6b,4695a406,b7a7ded3,a589153f,8ee504cf,fb5b45eb,b2d8e121,40f2f475,186153df,1fcf84d6), -S(36fc443c,1350b40b,881e41c4,d3c15952,31f8da9f,cdcac4be,f1d0c5da,ceb9844b,9843bb7b,fd0ebca1,762785cd,55669233,16c36aa2,d2c37b3f,2b196f78,bfa5830a), -S(ba7b8c09,d5293e6b,a2548e6f,ff3c939b,80d2ac54,34903039,dfb8b661,29e19cfc,54fe2a,9353fc1d,a0d34e07,b6d34d1f,f3a1f67d,f4aafa7e,57919142,95c2a5e3), -S(50a8ddf1,17a91c92,37a48fe8,f1a00e72,a5dff682,7398a4c5,d2f78b4d,d49ee339,f91d9b20,da28e51b,99fa102f,13f5e451,ab22e139,80052384,6b9c66bf,b7da1578), -S(642ece53,832d1859,c6543147,56b618f9,520a5888,2549277f,6b27f16,e08e3d1f,d9963beb,2c6da204,339a49c5,f253498c,48cc3e99,b715ea8f,a5eb00cb,1d6cffbb), -S(a68c0d3c,13d764d0,7b513390,5842c9,a7171e4f,755a9737,609db06e,1a44e5e0,a2c3fdd7,b7938a87,86f3756d,dbc66b29,72469e79,839a1448,b367db5a,2bc52c15), -S(5b33d730,288fde53,b123fdee,177758b1,ec113adf,74e79eac,513eadd4,cef377ac,1bbc10e,9d45cb00,db58fceb,bc4bcf4,a0e2bcd2,a7d3ec12,7d87beb7,a134a20b), -S(aa6dc4d3,ce531af3,e68590fc,acbe7816,c8293af0,d77914a3,c7119e23,e50ce56e,14386670,5dbe1ad6,91e09123,a19a199c,3ee67b25,708ef57,4620c5ca,821224f6), -S(180a4ece,d74ceaab,e0f7db3b,b038034e,5e659c61,3c66a534,8d962d14,efa32402,b675b2a8,b845281d,524403d0,db01417a,59fd3a6c,80232e74,cdfc87f1,3b76b0e1), -S(3a55690d,abb5e00d,c2d0d8a4,96d16c44,76ee767c,a9d0d1d3,694c856e,e5b7ad0d,3c1d71e6,8a5f9a84,4de0453,6810660c,fe353475,353cede7,2936786e,4d173828), -S(33b35baa,195e729d,c350f319,996950df,3bc15b8d,3d0389e7,77d2808b,f13f0351,5a75fe7a,9bf54078,6b9bfc9,db72ad43,559a9f10,4377648f,d43afc32,34728817)}, -{S(52f79560,fdfadd45,6165a204,6bf61bbb,726cd726,3a3ed2d2,45f07631,5b0b6ae8,e6c46e55,5b4a0410,bf38965e,5a7ba381,fd259482,2280482f,877a7ec5,84d14012), -S(29eeb07c,7b27f82a,1b031881,11d324a9,4df77713,a8cadb36,2ce4012f,52cafb19,b7538574,28faf258,f240d4a9,f464797c,dffd0a68,f9f978fc,476f9bf0,1a0a2df5), -S(2191ebbd,a95c29f8,e7062f21,a70cb368,ac67ed59,dc44b167,66e52120,cfe8e742,2812f1fe,557496f8,f21b1f11,2df7bd19,db6aad90,59494ad4,eaed4d77,49f66a4c), -S(3c29d849,e25364d7,576779ec,78755ff1,8aa64e2a,65140a2,bbcf22e3,da33a4f3,3658d9ff,e2e283c,f8973cc0,ede5af6b,69ac4970,3c6b1370,f6a2ba4a,78a28a97), -S(37230e16,e11db299,f54ca0f9,f5423ac6,5f05840a,e166175a,ff0732be,c72ba88d,2a26ac2c,e8f9ebdd,20f1f5f0,f628d3d,d0e02745,6132cbf8,78b614b4,51db28f2), -S(8fbb3be7,98e16bfd,b738a512,ceeea92c,1be8eeb8,5374702b,e927c614,ab1f1baa,8280f387,64a48061,26392be0,c95f0c58,3607343f,d0b24b98,afe3605b,8f7e79f4), -S(fb639ee6,29dd1f03,8e12330c,bf40ec7e,129d7da7,655c1c21,86452fe4,9589c89e,171adbae,2efe213c,8d01e273,ed9c5d47,c4e85503,de3849b4,d909823a,bb1da898), -S(2399064b,876b7584,8c977bf8,e35d6b32,2e45d1a0,c4243fe1,2a31a581,d1d5d826,79c1ef29,c1af9497,f3b3db13,17432d42,86fa014e,17e5d780,a0d39df,b61369c1), -S(dd5663da,63acee49,eb7fde29,6ac1215a,772512ee,6a080f3b,1266c7ef,51da5dd2,d19c7348,3754112e,9cb3a4ce,8986f748,3eba26ab,c415abdc,5effc956,27efb7dc), -S(30862c58,43b161ba,c127bea6,7b23d3cc,46b6c42f,8faaa281,6ae47092,8ae47993,44ea1101,26a7c448,dfed4995,46a0fc8a,3658e540,d7d0c2b4,18f8cba0,accf9537), -S(df7ebbdd,4e416e4d,6b1e67aa,34915da2,cc15bf8f,f6d79ebf,273b63a8,32d6610a,d05fddd7,e9618753,21f473b1,bfb5ff48,65b3c4f7,5cf4ae26,549989a9,e13056d8), -S(13adba8d,2485bda5,1ac7994b,c45a7e4a,1b21aa9e,8188e631,59b217a,29d4237c,6256a795,3f24b25a,c1f59384,aac3eabb,4458e504,af3b99c1,99ae614f,8def4ff4), -S(c160f7ac,9a453a1f,8811d031,9849be43,22d8bbe4,89cad7a9,cb815927,d4b54720,7958b41c,751ef3a1,fb985ea9,c7cc85f6,c16282a4,c374fed,5999d8d6,3227b720), -S(c66af931,82a7a9d6,588e9c7b,3eda3b49,40fdcb99,346aa55e,e6549d4f,f9382228,ffe4d0df,43f00af4,fe885b10,92ae38fb,97d21a8d,26aa5f69,9751d52c,a9ccea4b), -S(d3a4f4d7,d208b43e,c4c2fd00,798d882d,922f302d,a199b707,76a70f36,5ff404aa,8df220d9,63faa827,1c4ee360,67a536ab,25813239,82252483,311616d0,1458e1b), -S(47bdd428,d57ed451,cd8754ea,817c5f5f,9658274c,ef6757b8,70527b4e,96f372f9,fbcf0ee,9fb14de6,3c288dbd,b1888fcf,72f0265d,3fe2209e,12c85841,2c375b53), -S(6e6deb95,7f2eea30,5d625288,3cb311c7,f0365a42,480fb807,36315c4c,62495438,ba0fdd63,9b8678f2,ab0fe3e9,a16512e,ffd9ec23,e691cd4f,86146969,534978aa), -S(dcd2775,7cd691e8,28e21987,d6eb6b54,e8def24d,27238cd5,dfb36a3d,d0f05caf,40bf37e7,bd776a62,ab420209,c71df7df,74d185c,f0d6b038,dea9c8e0,c1dad163), -S(eda569f9,9bccdc21,580da94f,92d89312,cef87d13,f08d8ad5,f1574e12,30a64ce6,4e1da1ac,dd274e3,f9d7def7,746f0652,678e549,ad5476d1,410adbbf,aa3c1e42), -S(5d3d4a29,734fb7ad,2846ae12,4c803364,ea3d57bf,e8d77d9e,6a3b3f8c,9cff26b6,d3e598a7,1a469323,a357df08,319dcd1a,d7337a32,c9894b80,6a30c575,b19756b0), -S(10161fa4,61e87595,f269da7a,ae3ccf01,40e910fa,891276c2,df1bd91a,95e4d046,b36eb5f4,b8291a01,18691f1e,50235d8b,f66e14a7,f0641dd6,18ad7ddd,ea150196), -S(7ba1b276,3df207f3,cfd1d58d,5190eb91,99cf82f4,9d2d0927,f5f260f7,2ea0f178,cb9fcac,4be96ef5,3134f513,5509c178,99af24c6,4eabd650,afc599d8,3927969d), -S(4bd6edd3,aaa1802a,b0f46e05,418ada37,e75728e8,6ea4b293,6619c92f,57674dc3,c9e962d3,de71eafc,7fc9a329,3bfd721f,305e876e,a2a4755a,f9567dca,21aa3c0b), -S(95fa0b32,40b24ba,29a484d7,f8f022eb,b3f30349,9d8abc1,9a69b690,3e885b68,dfe6b88e,56d7b923,dcf8bac6,2241d663,3ac2ae55,c3a01fcb,9f966d62,8f3acadd), -S(d0fd4d10,18c37114,2d5f8a86,617c250e,b6c3d5,210ca465,6ec84e87,d0ae42b3,4e3bf443,290404a9,3af38e72,a54fa06c,3b2d6a81,161fc8de,554edd9b,f3399587), -S(992e1183,d4e7afde,166c45e1,37c71c88,d4039709,4262163,b4ae38e,538293f1,c29534fb,55e47a08,ecee311c,8f0ba4c0,39096edf,b2d7ed63,21a2810,32e85900), -S(9c124ecd,4e6ce167,f60dcf38,25976f33,64cc30ff,61f7dde,966f8c23,4c13a4d9,7ad73bdb,e0afe3c2,c89d9135,d445ba4c,796066eb,1909349,9e6ec14a,f74f664c), -S(b09cdc9b,d102f89f,bcca0ed5,888519b,7c5c02b1,64ccbfa0,3d0fe42,b1b113e4,f409865f,6ab4371d,f52790eb,88df67d,84b3b74,f17edbc1,29b802cb,d5e49a59), -S(6b4f628e,beb6d619,1d616e87,3233ae37,ca4cc3f2,ac881e59,9c2c8e3d,295ccdc0,1140b988,60f4ac7b,659eb012,6fdfb796,c0baa652,2202cce0,bf54b3a4,865f171b), -S(a728c830,10169439,3af3f780,b1ceae3a,6ca08ea,4bdc7554,2ae84564,f542c28b,7b68fde9,8c97db32,eb3cdbd7,15816e51,9aa58458,259dc74f,5d722dc,f48f1933), -S(21ce4401,4ce959de,f16b3912,e88ff48b,d44ef79f,5fed2d35,bdd2dc78,de8f7605,cdc598fd,c5d30508,a2690299,e0e25b91,b1ccb69,97b99fd3,eca1baed,76aae6d0), -S(89912259,11b9132d,28f5c6bc,763ceab7,d18c3706,e8bd1d7,ed44db75,60788c1e,2574b267,83365364,d84789ca,a64ec905,c969637b,21061ee,9ca3bddc,7170ed3e)}, -{S(5914f66e,28c1a0a3,47f461d8,1d7f2c55,845e35eb,3dc39945,584b5efa,8d71a215,cd2ac885,3f681e4d,884e308e,ed3ca185,b47e2d63,3fdfff6e,efb6dc67,4d7de056), -S(519834c0,d16c807a,7867b8fe,c99dc93c,3b9ed218,87a9ca17,9343729d,3ba9e294,b867d57e,fe2dd7c7,8586303,152f02fd,f67b5648,78a7727a,190d304e,64f97203), -S(959eda70,cbabcb05,fa8fae96,7227b6be,876db942,ae38bfea,a9c3d359,977e1c52,86373396,9338053b,b00d206c,5d67abd,f95d35e6,992ad69d,8d8a3322,7370fdc), -S(a40279c8,48dc042b,a3ee929c,2910e326,eded6051,9d9eb1a4,98fdd7e1,fc88a6bd,f2c962a9,f2950d2c,acbfcf29,35bad39e,2709c0e7,36378968,fa04d957,1dadc4ee), -S(650b8181,edcfe46c,eea03ec9,f8ee5af2,c288e618,7d634961,6c95554e,25957334,ce140ddc,c2e2b07,a57e5627,62da3eb5,ca1acba5,463e97,fff7eae3,55b954c0), -S(eb04688d,5f4c8d2e,4ccd509a,3d003b30,8c5539b2,dd160a45,cbe71efe,36fd9005,37d80690,2062bde0,b96fc8ba,7a7f751f,9461f774,a1d6f3e8,8999c676,a2ae76b), -S(f79206b6,7813cd64,9f946313,3bac4aca,3762975e,954e0ef5,a876b78e,4b5a5d24,6033d4ee,936e956a,af117dca,6086eb1f,6466ab18,d503503d,4b011315,365242d8), -S(539c99d7,728cf662,13e024c0,9f1226f5,ca5d09cf,67bac12d,47814b2b,b1e7d611,87efd14e,e58fbff,5491bf85,aafd48ae,6680f37,e0d928f0,13fb6cec,6f417f76), -S(2308281d,e761f602,66fb8228,45eec88b,e32f8fdd,4a06b8b9,3dfad9c3,75d64a8e,933f4071,e4f2a9ae,95f4a299,f4267098,94b661de,c96443c5,f03f6cb,f3be87ed), -S(a93d05ae,fa31c0c1,54c02f68,9184c1ff,344c670b,e13eb304,2de517f2,1f6124ed,b7549c5,4651fa60,61f4103e,27d316a5,db531e3e,d7396a46,e360341e,f53ed274), -S(35717dcb,4feada90,b039aa79,10cf064a,c8c998b5,fcbb037c,22bf9e92,eba560d8,b6ff9371,d98bf532,f82d7fdb,24fffa69,2afeb0e6,59ba30da,602b3399,2bbe5a5), -S(941d37ef,1671d5f5,675be9d0,d5cb1f0a,ab6dffdd,2bd342c5,c5b62be9,88d5a0aa,4834d5ee,a8f9ae8e,ba5cc8b,2fb52260,33e35767,d55b6aa6,d204e0e1,a38b42ed), -S(c22cecb,aff78c61,f6e34c9d,9367c4f4,1acc9c35,29e9d894,7989a874,1d70bccf,38a37fb0,5fd9036e,762e2f0c,fef8fcbd,c04a92a5,4cb72ee2,ba08213c,4b58f1e1), -S(7863ac2f,1704fd,5015f0ed,30edf5d4,33c5ea2c,e150833b,a15c1db8,a5e4d2f4,7468fa15,eeab5653,c9f982b4,ad9e4c99,2f44083f,a7a93e9a,25ff70e5,b8742b4d), -S(f702cfa6,f0cfd275,a2c7af50,b53d0c94,bb965063,c433f4f2,cfd13d99,800da48d,3da4a4e1,bc5f2c6d,2f8daec4,599a9704,7c1b930a,b37d6b2c,f8a586cd,ef7dce1), -S(c3a1da3c,6e6b8f2c,2a8eb81a,1875f2b9,1e9cd286,414862d6,57626b47,a413d7dd,983d0892,5983d42e,bdbce2d8,df116bc2,f5cf8c87,aeb833da,e5e7e9ca,f9699798), -S(df0a4106,d61fc3c6,b2a14ecf,ebea3dcf,7e38069b,8faac576,a0b8a1b,7c8e7b5e,dd97a06b,840d64db,1798cee4,9334b033,e8d3f4a,79da565d,c6130da,f0bea75b), -S(ee9901fd,9312a21c,879d4e1b,24d5a299,b8200a15,6e65e147,4a2055c8,a2363423,1bb2933c,8b10f8e8,ab93ecee,16f861ff,a86781ea,59b891b7,740fdc2d,f6c206d), -S(52890b99,c8dc48c4,b6b1e4ae,5b823fca,ad9495b9,8217fa4a,b4f8e960,77cdaf9,6ca2ba73,72606e82,9c3395fb,dd2e4b74,8c771231,e86fade,5e2d728f,e5e7391e), -S(a372b545,bf56b58,b7c4628d,aca9bc14,e8bc634d,d79d139d,8eb7a2d4,13465c3e,afde23df,fad41c68,df94abdf,90a642b,31d62f84,c6254c4b,4cad2934,376372f2), -S(89d02f41,f88b1f7c,90b01078,d7599a70,a1eb9c23,1059e856,4237b0a3,2c18010a,7e8e810b,b063d75b,c224f41,a842972d,6fe065c2,aa6b16e5,7bf224fe,e44b2275), -S(7ef367d7,23fedacf,86425861,f67c5ba2,2deaf04,69e31988,7a3a3a12,2f39576a,4b81e743,e00bfbc,1d98cbc2,5c98c516,55e574,fc7fa1f5,86f15d9b,1b5b7ac1), -S(2eec37a1,5fdd1caf,b4c0855f,e86c5534,1a78cdc,b3944798,311b1cf4,7df768ac,1c18cf5c,1a98fe9,70d1e635,ab133668,4e0d964b,4df0b16d,7c51ea01,c9a63), -S(72208b8c,fd9840d,76dfa6e0,f36cf57e,502f285b,422f0ba1,9b119500,6b2ddd11,fa09196e,a89ce6a,888415ec,a8eb92f4,149bb39a,50174a85,8a29bf63,65b4e577), -S(9f46479a,69411d57,c3c7ea6a,dfa833f9,1fb2109a,fd30c790,2ce323ae,4b14be0c,6cd6d7e0,8494cb95,9e67c258,1be426f6,4eee4514,83e9a9a1,278b073d,758487c3), -S(a9aaf56b,5016db58,5b8116dd,cbad1169,4b16de8d,9db5ea5a,279ccf4d,91b1d7a,218fed41,389a4abc,44fb2a83,7016eb50,99c40e86,bb419265,7f57714e,194a5900), -S(5f950f20,b610c06b,76949dab,52fc6149,97d254be,a1330a0,493f1ea2,1d608864,d9098481,823b3ff9,d1c0b7d0,bce90856,186b45ec,6f20da26,9b158283,8a4c96df), -S(ed621f77,98add722,b0dc5e52,9c6fec6b,dff60827,b0b12c85,18d798dc,761f1075,a8973e79,a9caf1fc,e3165145,df08b7db,6b7187a5,28b12712,6c62bb5d,4f0c46d7), -S(15b8390d,652d7338,e18ee091,97e0e176,74f8c4ba,fa2e7b85,8f5badc9,9c89240f,87930df3,710172f7,c5422833,385a6066,4cfc9854,a3e5ccca,d1d06106,1cd90be5), -S(ac2acb9b,21999a70,540708ab,68338266,aef650ee,d81c5b30,da1e87d8,a8a923b7,897bbd7a,ee3e8db2,e36505f2,ec2614c,9f4f2f40,ed2d85b0,5d23edb4,2832db89), -S(17c072d5,6bdd1382,a782481b,8aa4d223,2db79438,5870bcad,c3063330,a5cd5379,26fe420b,d7c25f9b,1883edb8,50e2fcb0,76a65389,d9a452f2,8351fad,4ef72f0a), -S(8d262002,50cebdae,120ef31b,4c80cd5,d4cddc8,eadbcf29,fc696d32,c0ade462,1412c44b,8ea40bc8,2ce090d2,3c11c945,e2b504b1,8d9874c5,271f5745,f0d9b523)}, -{S(ad9144f1,bdcc3673,26d51685,a047ea9c,3c4feb3c,da4b9b83,80e1ada6,300ba487,68003744,ab5b2c8a,cca5bcfd,e1c4262e,88ffbc0f,b0ad4206,2d57dcf8,62c93c47), -S(f3b90a0d,7a8cbf1d,9b994b19,7ce215f9,b8ed861d,d526228,59fe1811,68727bab,95f48e8b,c05a7bf1,e47fdc86,87513ae,5a56472a,44f384f6,1153a954,2db68b81), -S(24af6d7a,99122466,45b07a1d,29b4bb1,a68b5b0e,f9422065,b5bb0050,61d43cdb,f9dc7725,f628cc4e,d4e5554e,f0166b22,566d59e0,4d55c28,a4d0e975,8306c31a), -S(f704aa4c,2bf19c9b,128311c7,1bab5f8a,f2a3865b,728f4838,b8ccc7d7,82574cdf,ae7c46ce,c44d54a7,2e3f758a,e855710,dee6b189,1223d120,9e059620,38d12453), -S(f701adf5,a1bd988d,d7e1fadd,9903c453,e6798760,252579c8,b90cdce2,a046d9a7,db39a987,48aa20d0,5d8b8538,fc4b7d77,95e2810b,160198c7,ad98305,96407c31), -S(bfe36081,c492ed7e,3b91059d,bb1af376,47dca509,69be6665,50f94903,d948ca7c,a1fc9468,2c3dc954,764ee858,822b8c1a,5d0184e0,93f12bbe,21e9931,18911f03), -S(e707057a,297a3d7d,904a615d,ac1b8e81,78f52481,32fa166e,afb621e3,af3f4f34,9161a930,bfd583c0,bfd3b121,acf574a3,6eb534ab,5198aa84,ef38253d,9ca19bc1), -S(27a6c7a7,970a9e3a,7cd42b6b,4478be62,31f53ff8,481791c,4394e78a,968fdddb,e4bf1b16,6bd56269,9e2c341b,b1a51c8a,c2ac7d28,807899e1,3ab1f726,90f44108), -S(e65f799a,8fb3b6c,ad088351,614db5c3,d64660ef,8c977ec1,2bbe58fa,a53314d6,5897f680,253a948e,fc260fa2,8ac39377,4e6a445d,d2bde00e,4e01ff03,b4398e2), -S(8406a84c,e9e63204,761dd406,9651f20d,6fc3efe3,f98951d0,d0a2db9b,cf86e0a4,ef81aeb3,eac17e5,676f4455,b4372ccc,e405b786,f11a871b,d781e54c,6307d1f2), -S(c012cad9,4742fd49,8daaedfe,5b847f34,7a45c792,53c8a645,2192e905,e256c7a1,c4866f98,48f31660,8a81da9f,da112a71,34232f9c,75e388,7ff987b6,8404cd42), -S(73795313,e9de1efe,3d91ae5,15c620c4,4f9c6bb3,a21e3097,c8794710,b2032683,548ce754,93817f22,cb96c674,5d67708d,c7b9b133,c71cba5f,fede1316,c55245f7), -S(352b89f4,78a47e86,b5575fbe,ee1373bc,e93ca316,1f594564,9efaf048,a60bfebe,d784e6cd,88d7862a,d82747d9,b23340cd,b50235c7,65f30be2,ab5d313b,edb0624d), -S(8a0b3d0a,80d41abc,4b8a028c,6c523923,7b040445,525dc345,d2d8a319,c4708316,7b7a427a,f0e1f902,dd1b9bb4,65b6b376,ee68b9a3,f495cffa,c52fcb9c,705443e9), -S(b4bf6756,61462829,53f9a44a,ee3b5427,2485b45,951013a2,8d59346d,62f65894,85d0c26d,2987dbd9,e26c9673,71ca86af,3b8cfb4f,cbf97404,c99ef900,5379a1c6), -S(bff69744,3ac23a6e,574bd1ac,d0fea305,2f05ea65,14814f1c,65e86e9d,5b46a2a5,36961462,5b998565,9324f5f,c8714d9d,57ff314b,5d5c2cc6,99a4ab39,69add4f4), -S(ecb09f5d,122adf91,e68e98ea,d39e5790,27e7c4ca,405bcaf2,e086d4a3,e68242ed,aa214cca,8a601fa0,a92633cd,a353ca02,7a7dee71,cf335af8,fc75de56,a3405f60), -S(310d957f,10fb34ef,ca3a2a0b,35c901f5,35c0862c,68310134,10982d7d,e74af8ae,289cda3f,29a489a8,86121f4b,4e75a90d,2bc4ff20,e95aa103,4044ea80,cff56378), -S(3a5f1ad7,c59ee6cf,e090f210,7040b419,4ca15fa7,dc8e9f69,20825fc4,e012ac2e,8ac8986b,48d7bd1f,5ae99535,2505b0ad,78f855e,d8411b03,15725571,dc99c920), -S(725f136d,1b426894,c24f8782,43fdc1d3,79636a23,d682f389,dbaf71de,d4672067,db0ffaac,ec5ffadd,f32396be,3f01fe2f,45bb0cbe,eb0d98bc,2390f3ca,c3dfec84), -S(b28e523e,6fc68192,445180d9,5da3e411,2fe0db1a,5b3bd5e8,e00a1090,39c69d53,7c172a4b,31339fb3,47db74a6,beedf59d,c24e6aea,c71e2a0c,434714b4,d61a2f70), -S(b808db0c,e34b5607,8166b308,1dd4b2ca,cf9d2d51,3079648f,fc3c617b,8e45ba09,d69c4ab2,fc7e490f,6887f2c2,49e0b71a,746e3e2b,97a7415f,34475bd6,f6dee79), -S(5e0b091f,3144d7bd,c7e40dbc,98c716cf,d7e64eda,ee9c1fa4,6838bcd9,e0c6878f,1586cf7c,da66b005,8b2d0d49,f588d444,65eecf42,1d94c004,a078dbd,47e0bd20), -S(1c3e88b3,ba46410d,8e08f9fd,5db8b53f,8dff33c6,4f5314f5,e005442d,10cef1f8,ba365020,5f85aa9f,71a42c0,392345b7,4a17a5ab,9ff91109,4d81252c,d8c8f72f), -S(b4926018,fb0e9c,e80c5614,37c3f22c,cc223412,384321e3,6f408e4c,ec0d81ac,55544f6e,cea3575d,e81649b8,4950f225,8a94e78f,13325ffb,16debe1a,8387173d), -S(f4bfac1c,b0834e1a,e332b7b7,1ab84500,b1c8460d,c8c2efad,6a5efbb8,ae78cd1d,5faab691,59ce9d3f,6bdb1818,676684b1,cc2309af,1401b5d5,137e1c61,5fbe287), -S(220ed3d1,fe028d87,b96e8ad9,37ede03e,ed8f262,ce877c0a,42718ab9,cb2ddfb6,5ee2d60d,f96a1b8b,e11c9139,7abf9b4f,a0671966,34bf37a2,8d26864,31933fb6), -S(dca5fad2,d045526,b6a4c309,de1d95b5,23f9a7db,e669b558,edd75ca9,40c85878,f350337e,877c9c61,98fc912b,5d53876c,78ea94cb,bbf3744b,62a52fa5,f5ae4399), -S(486ba509,3272eb1d,16ece443,861eae7b,2d8604f3,37014bc5,11267485,9872642,688d4585,9fa732c4,f582d65c,45930567,8c27dc6e,5525d47c,3908daff,f0a534fe), -S(96bc1bd3,b4840354,14aa92eb,6db81f5,403e2858,c0552d5a,6b21d33e,c468f31a,83027873,f4066b5e,ba6f413d,6a7d4d18,d57f4a62,25cc9289,b514f153,91ede3b9), -S(9f131ffa,b53e20b4,e9cd9e33,793f4614,922c03df,7d11222c,7fffec33,42fddec6,c4deffeb,3f4cd90b,102cb6b,3f713728,2c5cdcab,bc6e7153,91ea890d,76207bdd), -S(c15c8c23,d90c8e35,c1a214dd,e2d4383c,735ae45,bef61f10,aa1a1c25,5984cf74,d456ab27,d7adddca,372390ba,1da02845,b84088d2,af4fea5d,3b5b7326,c6334c2f)}, -{S(e24b71ae,8fdea24b,2d42a2c6,5cb022a8,2aa9e03a,3067a889,e778caf8,34903fa,f87d5757,cae83263,1233b840,296d6066,52cd1ddc,e8334629,25c992db,7e0ee14a), -S(886a7626,6203c559,807acbf6,7e1631ae,1f6bcacf,3fde277b,ddcd795b,292c38f6,b1f590a1,52d3ecc3,2b699c23,a89b2601,de78be2d,fa11b20a,1ef1235d,93ed9e99), -S(3079f709,3d5270f2,95fee75e,a6c5cd3a,5638ee37,aef535b6,523604d2,eed0d57e,492dd2cf,d76705d7,42187f38,f38982d1,85efa30a,fd1639cb,984a8772,3e912a91), -S(7773469e,c557e3e9,4097bd55,33a87583,a79e3eb4,2e421cd6,592363c2,76641966,f827b0dd,46f4b5fb,4a656731,d827cf21,df1ec610,f36dc2d1,215f33fa,20a08020), -S(ebeec367,eb032a6f,7c421ae6,f8fb56f9,3fcdaa68,f6741e46,1992d019,7567336d,6e78af43,e10c742c,35467149,3323f8c4,a6cff91e,7b1f1c2c,65b21fa1,e63f3a6f), -S(b41658a,3683b512,c751d817,f5d92f8e,5d158632,1f2eb836,b446aebf,d276030,9396ba60,ca61b35e,4e52e879,a457ce5b,fee9121a,b2673c19,15e78236,483e069a), -S(2e2ed965,a926700a,1428af7b,68b7dbf7,61d1bf53,6eb9f75e,d56afa0b,63852cd6,8d77656e,d5f11224,3a94e462,3dcfbbdc,61749930,dfcca6cd,c4303cc4,617e9133), -S(4b54bd22,e5604384,9ff2268e,88c695d6,4766e0c8,4f598f5b,634e1dac,d03063ba,176c68e4,a1f25683,37c14fee,dcf9a64b,17cba4f7,283428c,1514990c,98d29d71), -S(b6cf7c38,2d4c63cf,78557116,55b5de99,1fd32da6,8b8d2dd4,cfcd6f5c,59c45251,c4c190ac,2870142f,2a13d7bd,5d6768b8,fb5ccdfa,b99d0e3f,6bda805f,7741ff52), -S(857b6db4,79177eca,82a6c801,bd763647,c1a49021,e5b4f405,ad02e6ec,7ccc3629,586cde8e,cbf7907f,704a6610,f7a8a910,16599e9a,93bc6a6b,1b70d59e,39c0db4b), -S(a18a23b7,6643d92a,9e1bd2c7,7bfee61d,c5171b33,12f64d7f,821fbe05,6a771ee2,321f460b,b9525303,c159fe3a,6762dd97,60432307,919a2f1d,6120c946,47cd8568), -S(19b91028,cc2e5434,b162cee8,c77351d9,d38d9eb6,8ff9b09b,f26cb25f,4b88510e,cbcf2e52,3335ee5c,56ee2a06,7c565627,a5c60f16,808ea8e9,94250c15,e427c883), -S(657e2f30,b1e0241,82c0e57d,996cccf4,7bdf8eec,5a4da875,1638b3f4,9bcdbd2e,8e0a3117,12da36b2,2d0cd048,a9a99b26,5faadec2,14162083,5210f1bc,bb79fe3), -S(576879e4,f4a8e697,45014bee,36ba4267,cf72038a,f5997d38,cf512f08,f0ccf6b0,3f313f,388c011c,18ba0938,51b0e7e,84627277,2e9da999,b839b58,92ede5c0), -S(ed72d681,6516c2f2,7a9e97c7,1a7c99f2,faeb8e31,a5f29260,faa0bbf8,6475117f,331fb25b,e71c24fe,f4d2133b,f1591f3f,e5f8830b,15615134,36fc47fc,522ad4b), -S(e4ed422d,9152f00b,96bce64b,bc3ddaee,6089e1a4,1ffbb58a,109c688e,ba44699f,6dae6420,2dc6cec2,e4a49203,6b16c9f5,9c517436,bf3b9d9b,7e8f458f,7fcba8e9), -S(fc3b8afc,fe39404c,29622db5,b06c989a,8d7a0c4d,85018796,d006bd5e,43dec087,7b77feef,2211c1a5,724af5e9,a841e09c,d7940bc5,43d70c7e,51676689,7682ef15), -S(9c2421ee,e2e7e66b,decbd152,a8839f1e,4cf03808,649399bd,ba55cfbd,9dda6360,8d9477c1,c66a532b,967895ae,66c7585e,608e9653,4f870bd2,c97d7398,74a84700), -S(22040517,334bb5cd,2252d1b9,8a9da91f,a0bd32b5,562c8218,4d991e01,d94e8f13,167d3dd5,738a467e,f8e03064,d6482c2d,64503892,b4f5b9d3,c4b04684,fe2f15c0), -S(b648a617,3c728243,f3c0c7ec,2aadcb13,dfab92fd,77da9aca,1602d47a,80022dd4,7199a3cf,89c596e0,d607d05e,de95c8db,ad763ac0,76fa7ee8,ba7ae6e1,4c14308a), -S(a7d7ab3,6722b9d7,940b2a15,c94bb9fb,41a139d4,26215286,bfff84ec,57386dae,25ea853a,c3e772b6,f400d850,a7cf5760,ed568add,a145ea75,6f20b77a,c32d9f28), -S(9787a21d,ea3dab74,366214b4,933a702c,7a07c4ab,696eddb7,3a84cb5f,80f2ba41,8663b959,2214a018,e373e360,a9e035be,f68d9e01,f6fff1ab,f8ad9b8d,3f6f324), -S(1d2ebbd0,65bd4f50,8dd697db,9c8bafff,b548edef,856fa4e,39f893cd,349ff205,85d0716b,109ab208,a96367e3,bd0a2314,ad2c8586,169096ef,9521d780,61df01a4), -S(d0a506ce,14e88414,46c08a61,98ea0aaf,75b9dfc2,c4d2cc58,1238a597,154981b4,dc8c863c,7c4611a1,85744975,34c8c02d,7cb7504b,dffa91f5,96765a25,98d1f506), -S(b6c4d103,a57d0af,27e93627,f55a34b7,75b2ef48,47d7612a,5fac0748,b41afee9,dc9440a1,596cbfd9,ff87fade,8b426091,4799dad1,ce0f7b60,d032e94b,bbaf53f9), -S(5b5d965c,f2f37462,86f088e8,b58887ab,2182f874,484686dd,43a245e3,dcbc55c7,6718ba28,cf43ba30,eeba6e49,a7234ec8,7f01762,e915ff12,41fb461b,6d87a875), -S(bc85aec9,55e6e99a,c5fa7738,c7972354,57b3935b,bb69e8e1,ddc69d01,d34a47f5,59dd49e8,cb3100a0,9c48ceaa,20cbde82,5072e13a,7af0a44e,601044a,361dd971), -S(66b7ffeb,a34d8cbc,e00b4d1b,a0558741,5123d8b2,89ebdba0,47587d66,b260bc99,43bafb96,c88a5917,c6333dd9,b4a546b5,1c37ab48,3f3873a3,6932ab97,efd79712), -S(3cf9208a,b230b73d,68470411,bf3d4899,e0f19675,f829e32f,cd148d,3c07d7c8,21fc39b3,ea5079a2,ae131935,9a3e98df,62b97b37,2a473a63,f3b56e24,25b30e27), -S(66e3fcef,b7b24cf7,af0f8de2,8e53c2df,2bd1dfb2,c0289b10,31239da0,948e129e,df4074b0,488f3f09,a674a40c,b3207f34,a0282661,2e5ac4ae,8d443c9e,d1184045), -S(28df781d,4ec05680,590f4658,713c8a91,fef23763,87ddb6dd,674a35c8,b0e74459,eb66159,95ecf0e8,34f24e87,6f0dd86b,5c86a45a,fe5190f5,721f833e,10a196c0), -S(85d8da47,48ad1a73,dec8409b,e84f1a13,16e65c51,96aad27e,766746f,3d477c2d,a76b74ac,99a3996f,a794ac9a,ce103843,6b4f5fdf,cc3b2a59,df867e8f,382e1ebf)}, -{S(39ca1e6b,9fd848fb,ac24c444,5a9f398b,8639fa6f,c0c2f2b0,8058d84e,6c0caf1a,8797227c,f956ba7e,5228a452,91cdd51f,8958ab7f,43f6c8b5,e06176b0,dc9048e4), -S(4c87e538,c9eac9ba,d5a2a81e,43a6f1e5,f8403c01,68ad5020,4adef77d,5e3aecde,6ee8b74d,dd0b9bb7,c8b7ed7a,728dd99d,a9fab941,f0132d0e,998e65b9,ffbcb9a), -S(1226617,9f5dabe4,6d963b7,e96247e1,e29f2440,f831c8be,578d628a,78561987,2d3552bf,ddb5ec6e,a7758830,9badce7b,41d71926,857962d3,c3bb28cd,5d68ce7f), -S(866c0a90,893b6b3d,807a96fe,3c67b928,67c1d95,e05146fb,40038476,26981201,8d8f3188,da86e510,b7a7642a,97778201,3926dae6,4ce80663,335bc448,d204413d), -S(8eeb2e94,9a66824,26a6f474,9e7578d3,1b356aa8,d1b42049,5fb83e5f,5d08f723,e439d710,c45063c6,d23aad9e,ac0cae8e,36552ab,ca6f2c02,6eeb03ff,6162a052), -S(ffc93fcd,85fd9502,78369b3d,291f1ffd,5da44964,888d5eba,3c3f60c,95082bfa,9aa66635,a4b0defc,b2514e97,515aa0ec,3f65ce8,6f6962f7,72eaca41,d5ea7983), -S(605ccd66,4f18c83d,edf36f62,e5089f14,4ed23f4,f88635fa,ab161567,fd20c8d5,cfccf020,363a805c,1d614aa5,b9a912ec,99cfea61,5c088789,275ef531,dddf2418), -S(d1e4f37e,7d3902aa,dfdd7254,fc727a44,98eb9303,a12fe71b,4d193be4,8dba6913,bdd29d53,4881cbc6,c2e301fb,7d757bc9,9224f12f,4296e834,9badb88f,84fcc289), -S(f30b6d53,f330e6b6,b23d21df,7b4350a0,c42ad202,4a92751a,5dfed94c,47bbe60f,b5ca6c03,b31d06cb,183b0b18,4432a06d,8143d511,8af4bc01,c364f024,b46e0c38), -S(540944cd,42101851,c2cdb0ad,61264e18,cbf948cf,2090df68,54482628,74271ecf,cd16820b,4ccf9131,476b8778,ba3e83,f5970507,7110686c,653be572,2e99db3f), -S(846e5478,5d9cad5b,5109c7e4,6fd62b04,f686c723,1fc3c0af,66bea20a,d9d60dd0,4b1a28c1,78bd097f,aeee951f,fd4f46a9,4658a76c,268ee7b7,9aea4bcd,e75fc8ff), -S(16e732f4,43b4c616,24a495d5,4497a23c,c95612d0,58df9f81,11d1340c,4b2b8b5f,61ee476f,30ac2be7,e3ff09f3,ebf0b3e,2d76177a,30573465,101f4cc4,ec0585be), -S(4f30ef37,2c730ba,a6a40ff1,94b6b58f,436111d6,848b4e60,10be9b9f,abef17b7,b579a133,7f3247f2,8c6afc05,644778f2,3668e73a,a7c6d14b,649bf948,ef126142), -S(595a0d2f,1668c0b4,9ba0994f,3b681c42,6e3a67be,e957bf52,47acd9c4,7cb7d009,fb10684b,3ef1b0ee,37684ba7,53858b3,3586b837,aba6d82a,958eb947,2eca319e), -S(85dfb59e,d7ef6e0e,355e0ce1,304fe5dc,8bc6a3ad,74de3352,2089f224,8894e0c4,7a9b9ad1,10099903,d0d84a33,6838d422,5f98abde,32d82ab1,a383969c,1fb98bb2), -S(c8e13980,cf58416d,8719bc94,96e21774,c29f2e1c,5a36e760,2ce7783e,2c810fd5,5bdcded7,bb484d46,48bc40e3,ee6a3761,cf995e36,2af21f0,10048a91,6fbd4717), -S(80b98fb8,e48f44e,db69fd8b,18eec95,2404fb59,45c8a35c,bf3616e8,c746aecd,d44010a7,20622d14,6af5319e,155fe4ff,591bb829,f5086c7b,1fc1ed6a,32ccbaa5), -S(17629b1,cf015e58,eccdc7a,de049215,fca806e7,805e0e35,951df2ed,5cb87d38,afd56698,44f6aefb,528dcea4,29438e0c,d10c4b21,23f02444,a950834,97a61f17), -S(592677f8,695479dc,b215af2d,bbc90621,e7f3cba8,650563fe,1b2a8765,6c44107b,3741e4e1,b39b0e2a,58373166,854a1d31,ed062a25,c4e3e1fe,bc82e941,eeaaf50d), -S(98d5f85a,a93c9d87,e34e3bb3,597d9380,f0a7e5c5,b03ec219,4025c89e,42126453,dbe42a83,66753aec,61f7f01d,e5dfde1e,b4b989cf,95bd36bc,a66ddc0e,ffeea196), -S(9187b546,70d2b9a6,b711c88d,353bee60,72a1f5d9,ce75288d,4e6c9111,80dd4126,80e73529,d211ea24,d4bccff2,b9de3e31,c6307ee2,3cd9267e,b2d372ef,78f8d2c0), -S(e38c81ad,8ddfd8ca,4e01f380,78eafecb,f8edba6,8e33e565,309a3ad9,f0abe0eb,9f0ace1,f05f0a85,a1488644,88cce81a,2cf55eb3,a91fc10a,e6b82f47,60dbe618), -S(7ee9955f,99e218e7,dadfed94,dad7054e,3e0b97ba,932338db,69ed056b,6f8adf55,5244e198,524a105e,2b5de11,81d7bfe9,ad56aa0,128a3d87,8cbcc5c0,25b41ca), -S(eb9e5ae8,cdf64b28,76349aab,c3f75c9c,9d95a335,3214d0cd,d43123c,265b08d,858611ee,f67a32b9,7b8a9090,6639e998,a05d9bbf,8ccb7c1b,9e5eb711,4216b877), -S(2aa74ebd,7e8b6b2d,952effaf,e5545eb9,e99b9678,a2515698,975247ac,c83ff081,1ec12cbe,6877aafc,f353f641,1a5edf9f,e4bcc09f,31422df,d076932d,8f0defbf), -S(1b7b8fee,a3ed4af1,cf9b07fe,b435ef76,1d081b1d,f1007697,f78fe5d9,89076aec,b4aa0d8a,efbc71d9,d338e998,197054f0,20c5a2df,7a9504b1,ca7cb603,6641f85d), -S(3f293b75,9f152a4c,b92e319d,e5d02b82,f5dcfbc,2ee7a53d,fdf7ef6c,e2595c32,b67babb8,d1d1963,fd742c22,5ad5bbe4,27e57d6e,b9e17bbb,f91d2c1e,a455c1d0), -S(3eb9968a,c9b01fd0,882ec65a,8f9f5a5a,b0fbec2d,e2dcbf88,cc9a70b7,887ca59a,1a4de130,4a46fcc7,6719c254,dad5e88e,9d6a0839,9a9a28ac,7f171aa5,9624ee2d), -S(a559381a,f41b944f,e2bab9d9,62ec7c53,efb25ce4,1ff1a456,54a99f46,d97ce20c,ebc6f66f,75ad7322,4c1319c6,4268c997,4142,11ca65b4,58c5f79a,be0ba0cd), -S(a8bc942f,c60ff2e1,140f9a97,3d7e0b8b,77698254,57098005,f9186e97,9e430593,2a82070f,25480267,c4fca773,3173b354,fcd5cc1b,ae497af8,58b7d451,8f048c73), -S(2f456ca2,c4f8806b,ce4caf12,32446b07,3405dcab,7b3cdcc0,247dd079,adc7a626,7308e58,5b9bafab,b2dee049,9bbf60ac,fdb37242,3e915156,15314ffe,5ad866fd), -S(b56f4e9f,9e4fd1fc,7d8edde0,98f935f8,4c750d70,5f0c132b,d8c465b6,6a540f17,cd171acb,d63357a9,2c23ee52,fa7d2e2,de2bd69c,343357ab,b95d0350,fdffec02)}, -{S(ec474055,43c52e68,5c9e6c75,97616fbe,edb70df4,fe3c375d,d7d24729,2b120851,22c1c1a7,30066375,5ef8c2fc,86452667,90347223,f11a32d7,9f1c0169,a467530c), -S(3f50e502,c45fd922,94fcc46c,b3118a86,43af00d1,634bd694,dfc0eeb8,be2dd4d5,7cb992e0,f29fbc5f,2887161e,6d1e266d,f11fb723,3b6c020f,26eee393,fe96b526), -S(443007f2,43c3f6f9,76914031,c41e0d49,61337340,9bd4a681,f20e4c79,934fc2de,df67adec,c9ce5f6a,e6c8312,699e0353,68ee87e3,1e96790f,f0bd3408,94af74e2), -S(1e15b9e9,c28f77df,75837a0,cc9504ab,a3a49aef,26a88d99,543fa7d2,a875620b,2a081093,6afbc025,3808ba31,f5597287,e32898ac,77fd0021,9e6fc298,26b0370c), -S(cfff0258,ff6c0d97,99823447,775b75b9,1881e06e,bbd72ba4,28f8248c,5cf2144e,61e63569,5c4a8fb4,f68f974,219bbf4e,e0c277dd,4b74b843,88f99041,f97809e8), -S(2824f4b,f72f9229,2aa04058,7a0c5395,4c87e7dd,bc5dd199,af6918e,6db62f1e,16ab1473,3bf8382c,521af6fd,27f8b2b3,b421dbdd,bcf06c62,3bcd86b6,4bf33274), -S(5dc7571e,27d6b955,6c789b4a,80d49fd3,17416fa4,e04a7eb2,3cdbb88c,9c253a44,b7261e2e,39327d68,a5456abc,9d4600c7,fb6d6e51,a732c7f6,c64cbd0d,56de4a17), -S(e93f3aaa,5d9edc53,6029d332,9ac0bffe,af27d4dd,40f550e5,3df879a2,a5c1d993,25b442d7,f2e2e03e,c7f1588,16a1af43,b5d2870f,e0cdf429,babb19e8,951c0982), -S(8f91f5a5,7aa40d62,ba407d8,6ea5678b,65c84ea8,f241e2aa,dd6df242,52635a86,e9333d7b,d6c319be,3ff4f5b6,f286a8eb,27d5a1bd,29646cdf,77441c40,f716a6f0), -S(77d398e0,228add30,e9e120ea,b16436be,30c254ae,65016672,8bea1198,de1fb17f,749a20c8,ad6f4312,fb6e6fa,c390a4a8,209704be,3355362f,31db9b45,f3876963), -S(96976a85,b6dfc4b6,13dde357,c21c3518,a5f55c7b,a2d22976,592d7632,3b5a8546,96dc660f,8ef3b0b6,adbe77b5,69024fb5,dd713566,617cfc51,c8013f2,5b424e9a), -S(49093c4d,26194278,623c2ff9,6c8e2f11,f9edf3b,13c33099,57b57f1,9db451c6,5d53ff56,50b82edc,9dee9f43,ed6db93b,f6a26233,2dbcd699,130aa9ce,5130384f), -S(49187f03,d5f5f628,b9210b88,8ac4f1b5,2f754015,541e9f38,162e969d,6a99f4f8,276aacaf,d38d0bbb,416bcd0b,8ea590d9,7735a3f2,8de72aaa,76bed0d,6644bd80), -S(7d64e446,65c03917,87fe0b14,16ab1048,3a6025af,b20e8c19,3bbba444,2864c587,2c0da181,6507f8b6,4c9e5684,a4d53d98,d6b88215,772def9f,fa5a7a1b,f2b2ccee), -S(2223484b,9ee12b26,2a21a18d,2682ab01,c291ee1c,fe3b4b9e,2e93fb67,aa08535d,4cd26418,bf0d62fd,b266a768,5f7aaffe,d7bc95e1,be41c6bc,7a0c9076,1ace3974), -S(aac92330,7d6a55d8,552ce6f3,9c531d5e,afdd5313,f801242c,21df07b3,a656c618,93d9be6c,590901a9,1413cc23,94cb426e,e6a61593,93511c,e67e1ffe,68b8f3c4), -S(6ec1a0c7,fe40c40a,f3515ff6,60f0b53b,8fb6be3d,d912f8b2,c7a473d2,3e49d201,b10f000c,191e9423,60fe6b5b,2b6b7b85,73c0c2ee,384dedd6,e3dc04a9,7834f93b), -S(bd982a5d,a4d0291c,38568fae,ebc76df3,f2b0e5b9,1cd0d3b6,d2f32077,6c35c43,48566068,d5142f6a,90b13105,e7841d32,38d869d4,fcc7319,3e3cc9ea,76739c5b), -S(25d54513,b9084ddc,a3f20e18,94382290,115ad5f2,dc72c267,ba845b3c,6ade39f9,e908508,7fc5efab,a6f62c41,ea8fe856,226c8e2f,95dc31fd,2b49a7c3,6aa53b39), -S(29ab6cd5,add595d0,cb64ead9,c3d275a6,ce383f15,9340faf5,118ec2d2,9bb9a62d,54584613,dc27c249,d5d1210e,9e121aa4,7d606fad,1c4621e1,67f67b90,d8f3434c), -S(4cfd960,86f86d5,bd805667,55979c32,d5419dbc,946d63a3,40dcc6f,6d6dcd48,f032b7b5,9d85d0a9,fdc290bd,a1fc703,55b5404c,f70d45c,d15fa9e1,33ee9319), -S(9c786066,b6642e11,139aa303,800314b0,6afd4d97,e8314a1,de9d7002,5b7bbbf4,463a2ded,e2185c8d,944f29f0,140f6b66,9ad6e3aa,8ab6e292,a2af551e,685e58ca), -S(4e98485,f15c506d,6cd29d7c,3f9a59ea,4bfab065,78d86b63,f25e74e3,e7aea96,2baf3fb1,c26f2b0b,1a0725b1,5d1ceeaa,7ccece9,a1dd8f2,7f80d825,d8cf1d71), -S(8412c389,bc88e9bc,b157d835,85af0dfd,48689532,e38044b9,117b8acd,ce3b62cb,17eaa404,ffc1f62a,38f7ce99,6216b1f,40bb62e9,6d1f7a5,8bca370,c0d30b44), -S(31b9b8dd,7d37b38e,892e94c7,a5e817c8,ffaa1c1c,f56979ff,7f25815b,758b6d09,cdb680a,ae795ef1,f94e7e87,50ad9077,7a55eec6,c6f0795a,ef951e3c,ab45d186), -S(2be45d05,e89c58b1,8212890b,b6eaf935,6f03e37a,fd957291,4ab71a97,7af8350d,c3b05f04,c9f7a1db,b6689fe0,6ecf7a80,3ecaa147,8d09a1ec,9a7d71dd,a75406da), -S(5185cfa5,fe6302c,b5573594,61f375dd,c483a66b,c615b5f9,30abbd4a,5c7ae0c,83cc447e,53c91e07,6f44d265,389bef06,549b8d78,9776000b,5c35ce36,5fcff98d), -S(cd42328d,e4a16323,c51ef888,b7e67ba,f9ee1c53,82161b90,65e1db15,bddcffd9,caed06b1,7e86b470,b665de93,74725fdc,94792c57,5509ebfd,f012133e,122302f3), -S(7a1ffea,8fe5114b,8a638306,3b7811c3,25a40c19,42451557,679e75e2,b304ab91,1ef3fbde,4f0283ab,96efbc83,bcbb5a6a,d781a215,e6ff6262,ca50b9c3,986816db), -S(cf0bdf47,a3f15b24,5c7136c2,3a3e38f2,661fa8a9,4df29fbd,8b41ef22,c291dc6e,c73d1fe3,919e0aee,5b3adc4b,1a86e709,4b039302,d44a0d56,638c3eba,24857a99), -S(3a571630,935c1f02,d6fd8744,2c082060,cd5e792a,1c6f92bd,c4eed01,686df50d,7a1ec78c,4a660cd0,ae90c00d,1a8f5f22,1f5507e1,4487e5ee,2dea74d6,17a69494), -S(1c5e5481,32b49a7f,66ae9fed,8323480e,d1ab974,622e7cf0,8993895e,ec87fac,b00309f0,7c80b970,d446a605,e2b3d52c,5c215314,d901cdb3,aaa284c1,a03d2740)}, -{S(2b081f0,268d6ff4,1090561d,79144bb9,554b1f3f,1f0f2cfb,c9344e2,b692157a,597920fb,c528543c,26499af1,8b5e7d7b,5ebf5ada,5df4a46c,edef52f2,1e2fda5e), -S(2ce45dc7,d84d3143,884d6696,73738e55,e30f6045,8bac95cc,c30e86f8,71779827,deb79108,80a1b675,a628fb09,725c9307,d1629b07,8027f566,29f8560c,2ea80458), -S(9dfa0cb6,2a63244a,35ce3a0c,f102e7c7,93a4530e,21c6c03f,15a4fb91,e116c480,b01c1aff,902f0831,bc8cd268,663f0ce3,6d8e22be,86026460,a8950636,ce44626b), -S(61a32d1d,cbd7e887,def51ffc,9c1dfd55,d06d72f6,a73ee2df,f83cfa0f,52d47bb4,69a3b17c,fa91e3d6,faf28d83,2695aa66,c87b14ee,7b2d987c,80242fc,ce2cc42e), -S(8cbbac63,5414c0ac,b6d7f659,5c6eca39,886c3ceb,82549f72,d07a4019,e3076eb8,c838dc49,fd5af1b5,e503a430,71901bcc,90e1ea38,9f735e31,236491ec,43e7b621), -S(d3f77c5f,663c6efa,670b46bf,dfa96af4,fc4720d8,e1df6e8c,1ffc5696,f37cb55,aeea0c3e,50eee6a9,16462a13,90ce5d47,c060efff,1fd3108,1db77513,34300332), -S(6f774118,4a0210a0,79695d20,f93f861b,658137c,3a072076,7d80e5fb,8b1ebdff,c12aecc9,b55bff04,bd6b6e73,870deadc,666973b8,ec498bfd,bcc4c33d,23f5d674), -S(fecfabd4,897a948e,5fab7200,969f9955,9eb1c9dd,2a31325f,34dc4f80,13da72c9,ba70c9bc,c8048aee,6fdaf5f1,8ef638ba,ce739c0c,76ec4c13,fd4dd6c1,1663d02d), -S(d1a1a1d4,24fb5ab1,3e985c86,9bd7c02f,f81b4633,dcd22e96,c3f33489,2e80d543,cd5b79ae,af62769f,dce99530,8b921b5e,39a60fd6,f989dd7e,1d0d7219,e9ee8865), -S(7099682a,c3c083a8,80467746,fb924d4a,56f23d16,a3b57f10,1a824b9e,653d45,6a9c296b,cdd72c93,df840003,24ce78b9,1f9df6b2,bfa33922,ef32733,fe49cb31), -S(1035866a,4e9ff0fe,6b0066c6,3f0a2392,c0b8cd61,36e13ada,21f6dae9,f22c39eb,6390f9ae,ec1989de,2146cd00,a5eee99e,76ea4536,423e9bf2,c778ff29,85538fa8), -S(e18351cf,163e4df7,d31851c0,409b5705,a5ffd472,dbda5dd3,bf05e66b,fae50fec,264c1d26,41f185e2,72b908d4,77222484,c651e8e1,9a9e1fb0,1ec5ed4a,8a4b6c08), -S(dfbee778,ae4bc89,24f32c18,bc0a740f,d01922b1,28e1a595,283bfb4a,fd8f2f76,d11f9b3c,25ae3619,99ec2c9c,2f1a5903,d80eae59,e096c5d,c5e37201,81756acb), -S(842cdb54,414fa977,58ae3fb1,9316ef32,af9c4f0d,649f0abd,cb94267a,124b59fe,a016f899,288f4caf,dcc6edcc,3cbcb561,fdb4047a,f789e1a8,51ad21b3,be62f5c8), -S(3deb5d22,a81540ef,cff29ac5,585a056a,204e4d67,2fb858f3,5c23e939,790c744f,20d73911,5b24b1a0,a4b31302,73321dc5,d8b74398,d6516439,4e1423f8,b4022d6f), -S(3108e61a,1e0f079,f76e3ab0,d69cf068,779674e6,49768aab,718a09b0,640251bc,245a9f2d,141f390c,f1a17bcc,a06c5a66,5cf3a87c,1096f5e9,b04c4fd6,737d9a56), -S(63b9eaa,ce6b32cb,e4cf4a69,6599f8fb,3797bff5,9103ba0,c1351e78,b16cb0fa,938ac414,ef911df6,bda32b5f,1f69cd7a,87a25d82,177763de,568ca95,e846fa5a), -S(f37a5a41,cc96a04c,c882c27e,e362d054,7d6267f1,c91c5403,2daa5c12,1700abda,108bd6ad,27aa72de,48406693,758a74df,53a3ff98,d490e303,54c45ffa,c64638bc), -S(52afb7fd,6a16dc6b,98f9d7d9,555068d2,c2317035,b7492e8a,fbf28aea,3b1fcaf3,548d8ca1,2cf7a11a,b0100455,c7240290,6cb2e92b,101d1e2e,32ab263a,3f3de413), -S(f644fce7,874e9154,8f3fb284,b7d1ba17,fad6eb6e,c581f57d,5aa11804,86de9889,b2acbd8f,5bed4270,ec131ea,1891c99d,ddb46648,60acaf39,d68d2a54,a58b92bc), -S(863cdfdc,66065a4,50c2b7c3,1d694c58,e63ccc09,fccfacdb,4fdf0b1a,b150e937,14d168dc,c84d859b,55a3d5af,9d17ce4e,83bd90ed,55e099f2,50932dad,b5d2693a), -S(9f5569e0,50a26288,5d91f82e,9cacdf9e,f4487676,730f4da1,46ce8769,3d8807ba,cba008af,547e01f,6a9c6c45,8f9d71e1,8ad062c4,4b305b52,3f3a6655,3979a2b9), -S(a0f14b6b,99f0bd74,cf9864bb,17b1c43d,51ade513,6cd72a15,89312dee,706d50c1,e2bd2d82,c549b4da,cebfb888,c1a7c5d2,f0757fe8,53e07fb4,747eb7a1,542137cc), -S(9e7bd727,fbab45a9,db36d17d,5e5437eb,f028a10b,392ea470,d5cff0d3,2e9bb0fc,fb52eb32,e43133db,28125280,e3cc55a6,76877c58,b4051f70,9c031f84,24f12d9f), -S(7d8b1a30,4c0c8931,2d5d712d,ab396efc,7a117483,7f62bb38,62a81a3,660b1068,472a2dbf,ee99c398,94d14c1e,ce87cf17,c8aee10a,4720357c,c5ce79a6,19aafe2b), -S(d5eb073c,a5afa126,70602de8,417fe50d,bd8f0768,d615ef2f,565e421b,4e7842f9,52571e4c,e4f0c424,fd288f3e,8b6c54b7,7481c3a,43230fc7,4c6f48b,d4041089), -S(3c41cd8a,77728b07,ea592254,5ac45462,2c7927fb,6a7aeefd,61635cc4,217acc90,eab0f00e,84099fcc,c2f4d339,77ff7d68,4c035b3f,34c6c4e6,aa812c9f,43af366c), -S(1eeeca5e,cadfae31,188218ae,7beda45,57f85c25,5c99dd64,1d00d8ce,2e6f7809,d7e5c2ff,4ddf421f,cf09b655,113b8cf1,a4c25e90,d02b871,91dbac55,d6606ef1), -S(54c13737,454414e1,76bfaf1e,b4402bf8,678daab1,555412d0,c6d3fd44,653510ae,753f6a,f382d0be,f1dab47c,1b9368f9,57d586c4,acef0d19,dc241ce,f008ea3a), -S(4d608c37,1fd6f635,9ffc57c1,9f1aa5b3,5b0f5702,55851cec,34278d2f,465fc8f4,12d1592d,c2cbccc3,7e5c9fae,4b864e9a,ca6967e,9d4852e,9adc9e31,1000670f), -S(71157d64,8c0a1a33,19b713af,f806cf9b,c91a446e,2ba48ca2,fdd1ed4e,8c43da59,c2ac2aeb,a298fcfa,c0d5eefc,6eae54ec,330f5c0,5b34952a,9821ded3,9b72d383), -S(327f876c,93652555,fa80a054,968b4712,930dc930,12ee6b8d,c10263ed,3b89a762,4d2bfb15,4cadbfd9,4f6696da,a1e66846,8aacaf8f,1428201,636026a5,46dfc92e)}, -{S(4d3b98d0,b5926a8b,3e5622d6,10b30e88,caa6e7ba,eb10bc3c,38aec3c9,c1267578,e84056d8,4726291d,e6880a2f,2d3b0b01,371dfa27,5b8c9cff,4805d18e,a5bdc788), -S(6e463689,111d1a5d,d10b09e1,5d0f438b,1cebdb67,7a6cd230,bf6349c3,70667db9,de10eb3f,5d2f4320,7265952f,b33fc23f,154972fd,d3394cc0,21b66276,1b51db3), -S(48235e7b,76c94c32,b0d21bf1,7fc215ed,df036366,a9ef494,19723485,78db8943,4f5ac8ce,36c77403,b2fa83ba,1fd0e88a,3da4c8cd,3c10ddb,aafe2d0,5da40a2d), -S(668af7c1,4063dfba,1a4187f3,f69cb457,cae4edbf,a3bf9669,4080b6de,bc3e2f0e,ec95f37c,7bac26a0,df23275a,283828a8,5a102d8,f33eef1e,87cb56c1,850740cf), -S(d4426fcd,cbdfd904,725fb501,656b9f2e,2a9f9ee3,c6522064,f078165f,61c31d97,e73f2a38,c56838a7,174ee704,948d28fa,5b5fdc34,7774df9f,72f27834,a85eb4d), -S(d0f49ec3,42076b68,4cd91172,f15584fc,ea38aaf0,a3201063,f854ff1d,f68d4600,28d95ef2,82dd7d6d,72be7854,e8858b1d,a142002b,ad7b7b4d,bd1e582e,94341e16), -S(8a36f3c3,50bc0f1a,1b1687ed,4ff83a68,1578d74c,c28fa875,f6969e52,4887bbb1,15ab9e05,c3ff823d,ba090e21,1033c34c,fa713d39,feec4346,88e3ecba,4b431e10), -S(4d1ef23b,b316e821,7d2cc409,a1baa273,cc06f79,8fdd4d16,5d5b6805,3718e238,fc37e62b,db18154a,2add98b0,ec221e8b,bd1a2096,ac2dd1fb,cf8e2e64,821301fe), -S(eec1f8e5,76e87803,bac48bb4,65ed923a,a68b2965,64365d45,bd1c24c4,cf7041b0,2c6985e4,7cccbc38,3b85be66,ab34a166,c98a8000,aad08f73,616e4d2,2a15a009), -S(9fbc20e4,de372a38,90443786,bd7cfc40,c6195b29,4cf51874,6ccd9ecb,cee223e9,f734bfc8,a6973209,903edaf8,52f63bca,b23fc1a4,879906b9,1c5df169,9d24683a), -S(7984c8ec,a2b02dd4,e8b9c69c,6f803418,48f108fc,b63d7038,de58e567,e64a894,49adeb11,13c705a0,9eb01e50,dea5be48,86e5d424,689282ba,6d64f745,74f45e8c), -S(29a7400b,16f5712a,2324becc,29fc4b98,57fbb926,f8741dcb,324c26d9,6cd178a3,90770be5,5c0a94a8,16bcfa38,aeab11aa,5ec3b7d9,eb4e7d29,1bee1c02,69e87267), -S(8299d2fc,84770bff,a4e630b9,8f2e6744,99b1c7f5,719e907a,d70515f5,140a00c0,c790968f,a3c3d4ee,3e25a1ee,8e1d4923,3c22f034,ba7c172,b5d7d91c,99eabfa8), -S(5cfbd498,5b608db3,5d1a2872,b9cd03fd,d775e498,4629f41,61a2bde4,fb2582f1,8288fa89,81056333,acd1720b,bde757b4,e83d0a49,9c5f2220,521a0bc8,dbe827f8), -S(281f1fb8,e144e39d,9ec2104a,96bf0f1d,494eaff3,57fe084,63825228,ecd286e1,ae40e075,d19ee5f1,1dd7e22b,f1c277ed,9a02abe9,975609c,a7c811f9,7c54e493), -S(51698bc6,73d3289d,6b4882b0,cab14e67,97d31221,e5bc6e53,af061aa1,9f546daf,7b850099,fe977f6c,f50abe00,bb3a0b68,90f47c45,24e9ae02,94304b6b,20bd986c), -S(db701e92,9b696c86,d7fb459c,97af90df,ef847bf5,1d235337,2a2a4792,5fa8ae53,edc7e98f,1a108bc4,8fdbe65c,2904058f,7da5e188,e71d194c,4e9dbfe6,8a55d18), -S(c900f57f,e9a31d4c,9715a822,5a906e90,22d81c12,714006d5,81be0c7b,aeb5a490,8493eb00,90517d9c,b70a4bc,39043ffb,e0863475,17cde2,a9bd0d95,f616bb66), -S(d74e842a,fe2da0df,df6342bb,582fc223,717e0641,f1ce0e14,584c5c63,f379ad72,cefdbd7b,b4ecbdaf,409a0fa3,9a0a305,b1bd986,4913f977,bec6c47d,5d525c10), -S(b00a5f4,f033d126,64366147,a1bbb9b6,ea60a38b,863c5f3a,e323e8e5,1aee200c,11e9f1f7,b7701a4c,26a881ce,30fac1e0,92e157d7,b9c2e4ce,cffeb38a,172ead87), -S(5772b134,68bf9f09,d26074c5,16dd7472,d3a83624,92306cc5,c7544ec0,d73de280,2e2a7931,aefe2a31,6dbad1c,e7f9d42b,7f38197f,43024f16,9e27fbc,7af31d0b), -S(8bf8af02,ccdafb15,598f6725,5f172fb4,ba8960e0,6c81ffa5,b4c1c313,6f95f29b,96041af,1efd128,ef133e5e,b0aa3d9a,6ac3a651,92598b09,ed649847,385a9b2c), -S(292889a2,d8329139,3410385f,cf5bf489,7e1ee23c,e0e3b5ed,82ceb340,d89f87a5,41099fb2,bcec7e07,d4d4ad14,3cf605d1,b0a32487,1736063b,e49b06f6,d648aa69), -S(ad227b2b,737dfd02,665c15d5,9b28c7e8,76413dfa,25c9068b,90efa79,ce83142b,82f1eef1,7e2f6b86,87137302,741f8486,26fad679,9c6a22fb,3a49e341,c7e51e9a), -S(b4245dc5,5df02839,4cff2610,4a4255ef,89f3e708,21541c3a,4631ee4c,145bf85,5a40f72b,7a67540b,6858e5e,b15005c1,3fee862f,3cc54a52,7643204f,d0b8be2f), -S(15aaef61,568537a4,695c1990,c05ecb9,2c605232,f705c3e3,729720de,7e9c2400,e6efd1fb,b74e9e43,ec1244e0,bb4cff2,2a5ede8c,848a4f5f,5eec6f8c,77b6f5af), -S(ade2e63d,4a828328,b4c53763,30790331,734d7f90,37c1a584,59570c8,f31e72d1,c42898ab,3633dc7b,f3a454f9,d5475c4e,fcf1f786,d1f609fa,23616f26,b23a1a97), -S(d8a9043d,297681ea,c5ed63a5,de306500,6b66e4fb,167aa5ec,c76a8e2e,df426e7a,cd3de058,a0a93d7d,7122d777,1446b2b4,d4cf53a7,1759fea3,78adcf03,5093f4f6), -S(30651cb,592d282b,5348f192,5be3f04d,da5033bc,39e2fc7b,1e61500d,9769b57c,dadf77cc,44853f67,53b1dbdc,17a97d3c,e6d5b2e7,8c6087fa,800c5af9,ccdc54c), -S(aa21c60d,6f7d6253,9d42bafe,95c58f30,33c0396c,fa0ceef9,6d2f91ed,d6569044,4d519779,3b19515,92e2d952,2be520b1,11a5453e,ec6d7ccb,3e6db3bd,3d0c84c9), -S(5335cea5,e99eeb23,765b3444,d9bc7be6,1da67d6,91bcc42f,d43ae543,e9c22bc,c4072fdf,8963addb,5f980f7f,f314795,373cf3dc,935e0e64,c3d3d98c,342530cf), -S(708a530e,9e52c73b,ee87c9d8,8161c810,5d5762,2c29ae69,1cf999a8,3a1187a5,6477b7ee,1e065768,569a923,4492c7d7,c13258c3,92cac175,a75b0e63,b8c2426f)}, -{S(3fbd5a4d,ebbeff54,8c2271e5,33dbaed3,fb8ccc23,e3fa2579,4c8f7fd4,47ae186e,fdee4625,45bf75f5,5c29a724,6496d970,4616c54,ba01d0ba,feb9155b,cafdb555), -S(c1483ec1,78ba8414,c371b57c,49c687fa,69669e2,e3e1067,cc6d2a93,b1a9d24e,edf94395,962adfed,c2ebb3bb,29346136,e4dc870c,5c76299e,3b07da35,6bb26bed), -S(26df4b09,693a3905,2cb7a1be,5bc2cc97,222b70e3,3d297a54,43741228,beb77017,a3d6b908,cc6d5f80,aecda93,99e17a8,ce33c423,f00cfc4,dea8354,af502760), -S(b6c265d5,90475506,e15b2388,b894718b,be67aee5,ba40ceca,51876946,e336d903,b451d3f1,2c666c85,bf9486cb,296c39f9,49f9f98e,96d50a19,80f86f85,a1efb999), -S(da6cf69c,feec7b1f,c848639a,7e27932a,f49cd695,a2e56a50,693fa862,6e257c66,4506f44e,e6e0d822,7e67dc4a,9f8e2ec2,d3ec0c3a,c2a70c7d,d25fa9c,34cbe3ae), -S(d57648db,adf18b77,db185ffe,3f86f859,6adeec05,ffb86215,4b894a0,75776eac,a3f2fec7,7186d81e,4228cb1f,691e00e4,82a125a5,bbe9e6ec,45a53604,4932491e), -S(4de6cc4,d64d52c8,49c0e8d2,45409ba0,88248399,1916df3c,238be4de,ee2504d2,b389e7f1,ca72e9e,1cec2ed7,70f21441,590f0bab,1b963f1c,411f9bff,d3df03f0), -S(15f1bb11,78b01439,f26412,1d36a44d,b8333fbc,eabeb471,da2e6c1,1b8b3ee3,bf137117,35e10854,95acf3ad,97fe510b,33d6628f,e67d0067,499169e6,6c12274c), -S(badc76d5,481e77,9df71d6e,223c6965,9e9ecba5,8415a95b,eb7118cc,b1f931a4,475e47ee,115d258,3f0607f1,7542ccde,626e6d57,6ea884f9,61b41354,aef37247), -S(13015ae5,d770f4a9,75825bae,a6cbbece,78536dcb,78d7116e,d304aaca,199add2b,f5e28585,7a99ff0d,a4fd15e,8ac650a,98421629,aa102bca,25df3930,7e5cfcbb), -S(7734d2ac,707b9b53,afbd2a64,50c9b609,1905c391,958d7215,f92353ee,fd3c7be5,751d38f,ef48bfea,8fa5de06,8188a658,ae6c9c75,a359a4ea,efaac5e0,b5e859aa), -S(91814384,7fe2ed34,e9cc9c61,3fc2c67f,2b76a208,561d0e06,271b812f,6c678856,9a97f6e0,9888e076,93c9ebec,b8773485,c3c5d208,c793a77c,6984fb09,cdfd67b2), -S(98c516fa,2a2c8073,70ca9d7c,b4187108,ea345652,c8f814b8,b4a9405f,b48c2469,7b3446f3,2e8c4764,a8eb0846,4be3bc6d,f42b8d14,b7da65a2,ac96a018,d0831c7a), -S(5691d1e3,713302c7,48bf633,189ce032,10832e4a,9af1dbc2,abc3e99b,cb4faa01,d802e21a,fab84c54,5d665ed3,54130d9d,f7f18283,30b3a1fe,e30c2298,8b71654b), -S(1f8cb624,6440b640,aadba62d,c02f4ce7,a0ba9be7,d535987,64072fed,95c0d1a1,647a9dea,abf8247e,f46b60c6,53cdcd5e,cff0d1c6,88b7519b,a778f9ff,c894e1f6), -S(1489af53,94878f07,5cfb2e20,931fa3a4,e585d494,78818e4,f47f05e1,2be54d14,cd5bd721,4e535822,43270bc2,dc692ba4,c57e494c,eba92d4c,dd2e13c8,e24d8550), -S(66159248,2b2229d,ea70ff76,d2a5e70f,ad1905c0,9211e3d6,2d1d652f,ccd709a7,8f5ab85,57948aec,67e7b538,fa9c704b,ae939c22,4041e6e1,65f6045b,a6fd0fdf), -S(bc894efc,d0fb7497,ba70d654,961aa79b,6ac5a795,95537c80,82c525c,2c44c3a1,d5254292,ef0fb6fc,db587393,3b17adfd,87d13320,858ff783,75e356fb,b0d3415e), -S(f117d7f6,85457601,9b559bf5,f5bc150c,13363e7b,72123435,b441d98b,d169dd27,a8f4a23e,dd0d8f2f,8950c124,1abac43e,e629b0e1,8505c3bf,780ea378,20c8623f), -S(2a8d99c2,65a66a51,56b60556,775c61bc,b2a81a62,34896a31,16238c2a,b7716ec3,5e842306,efe11f66,5a049c0b,fe3ac74d,d72c5033,6dbd04bf,2a77b0d2,4d7ea651), -S(ea747597,1a6b6d94,2e368bcd,9979876e,afa4622d,313d819d,5e8291c8,2da95830,41d4a478,e0950bb9,e6595bef,3c197e5,d0f77ae,6340ca8f,2947fec4,70465193), -S(114150c3,fe8853ed,9f3e26f7,bc9f3d6f,aa50ba0e,6ae2d8ff,97924b04,dd9678b4,5530c22f,4ac30716,2b272015,460426ba,9602256c,ab735174,1a2fbbfd,cd71d134), -S(65d96017,c91a746a,656eb595,d39dc9bb,3476dc0b,1a1036f2,df7a4ea8,1846631,de46bfad,6999b108,1f358edd,7809919e,4de768f1,fb21dc09,4b248bbd,56b3dc76), -S(f2aec214,61c040c0,ebd18204,bc277312,732b452,266bfd55,aa071853,e458bea7,52a1b71a,eefe2c48,5ae2918,e236f1d2,1622d37,13b4bc04,36124567,d48cc453), -S(370ef89d,c39e637e,8bf6be31,63a4f76,7cebb202,c868647e,db18f991,977681de,e6d402ba,9769363a,b963729,822bd6aa,9794592f,36e54461,579ae53d,4c8bc4cd), -S(8db6356c,4f31f46f,961e4342,a1ff50a1,8240629c,a0decc36,e1bb24af,f6742e57,8ee033bb,96958466,15626ad6,736e9025,fb76320b,c2d0ceb8,ce3400cd,743f934f), -S(14a1a08,502510e7,1060f291,1316ee01,b1fc2bd3,c88eaa1b,656cba0e,8e3515e4,5a4dc536,b62c349b,c9bfc6d7,fb677231,1368655e,fcb9c89e,572aa58d,a57f08c6), -S(d530fc7c,4d5b4fd1,5f44ba0,c0f08f24,889b278a,93ee30ab,935fc112,5e244a58,39c0ea88,5984c2d1,d5119a28,7cd842ca,d3cb54c8,ab6aa222,c01e7152,98aad10f), -S(50f3c13c,a474f604,ca992658,bca68207,76acff7d,d507d63a,b5e18b28,5c5be81,685e151c,7d8fddee,6c9d8513,dbf167e2,c32dd70f,b6932397,38eb63fb,3e4f7afe), -S(c0a72dda,13174682,726ede1f,7ecbaa68,b4b137f6,d44298d3,4e17b7fc,10e19d4a,1e45ff3e,4a4239ba,4a897489,a265a60d,9a91f3f2,83fe2e75,9e770156,c9ebb3ca), -S(7121e14e,7e2a2c57,76b5702e,c83a845c,28785c79,9099a007,54b50fca,b4d9279c,e6b3ff5,ce62fa35,adf45e69,2ccafb91,b805d7cc,b6eff2e1,38dfd680,d0684401), -S(c0c01f34,ae41b8cf,e466b4c9,c6a5d5f6,14f570d6,fcbef768,a81a6c8f,5ff4adb,f47b0a41,1bca80a3,836c85f4,bf8a4731,3243bc2e,8f2ea47a,3b1008b,53caebca)}, -{S(4f20ce51,84fb2949,443286cd,8ea201eb,15248749,6e15aab6,f3ea2597,d4cbf47c,bf37770,62691c5a,d6c6cb8d,c30fd3b1,73578a3,bcac43c2,c8404b6e,c085c97c), -S(17ceec36,7fad4365,520599d7,62c66c12,5abeff81,ce7242dc,bde4e799,402759c0,91e024e1,e2147fe9,73091001,984dd3c0,9f887257,73bbbedf,47f00c7b,c5c9f626), -S(dcffc4a,5557f2a6,ac7a3527,5a8228ec,325ea0bd,d9bf52c3,8a78217,6bd716,87658163,dcfc39e2,ad08a499,898a1505,988d9b86,72b6d1e9,64e6845b,cb41129e), -S(625fff43,45337aa2,1efa0884,73a6662e,d5340470,a79576a4,362e30dc,bcf762d4,92ad0a66,d0bea2a6,d7eedfe0,e33295b9,3a656e45,9220026a,5ff3be8f,83184187), -S(410b96fe,7db23faa,7d123e97,c1a82a9,7b24a26a,80143e50,dcc6d9a9,1a6e81d2,ca0da356,dce88799,5f8cc790,64d197aa,6532dcf1,20fe93c3,7e2ff4e2,f14394a7), -S(8136e51d,ca68170b,136d40fe,76980b4d,d4f435fd,e38f3017,99de734c,b2491551,823dd1ed,de1d326,676649a3,9d5ba083,7c48e180,ecd0a648,eaffe7c8,2894e819), -S(64a67d9a,a7a31390,3ed9e348,e7300917,6c1d52d0,be63f54b,aa3ee8f3,f1227a52,ef770581,df4aa013,6d191e99,cde7f42,a14fdfbb,11e1b709,bb540100,1dcda1ed), -S(5fcf0465,a905aa8a,a1da5073,d524e8a3,30af663e,f4307359,c03a4c6c,c423dd9a,58641e67,fa821fc1,2307a66e,fe0129e6,4ace7c36,c3f5395c,db87667e,5e742a42), -S(aae6747f,ac3d8c9a,148009ea,c2d25574,39a8b546,455fb3a4,5016891a,f9372dbc,66084f19,b1d97f2c,22e182c,d5450d43,d56636e4,92651cf6,22772a7c,5b46d9), -S(377dc2c8,13e36bb4,642d1e02,cafce754,2ac6d9fd,c2212edb,5432674f,38e242c7,8395dc2a,39d3b1cd,ae9d7d37,d0c4597a,11f931d8,75c8bcf5,8eab03d3,674d5841), -S(35c598c0,7ac5dc3,7afe6895,29d815e9,406e2608,292ffa0e,7b24df65,3278d8ce,e793aaf1,45f538f6,c133309e,53cb5343,dc1dcc74,985c57f,27361c6,aae23e7b), -S(e9666336,6bb286d6,c86f425a,2d5658cc,1d733223,9ec2e9de,c8ab7295,4b329845,908dc533,b6098e9e,9b737e4,b96e7345,e635f591,60bb3df2,75e165bd,d1cc5998), -S(46fab0d4,7fc6586a,31cf861d,ff5e0bb8,cc12b60a,53103007,c8974ab8,204af703,845ab7de,7654fb36,618dbfb1,287534a9,2d43db6f,2a2cdfe4,5365b4b1,893fbe9d), -S(4d80486f,fe748d1e,f88aabff,76bb82c6,a45db736,76ee0ff7,d77cdffa,2c69d07c,2a52044b,d4fc6a59,fd16dabb,df35bb6,8057ad4c,292e87b5,528a3847,c8784638), -S(2c1d108b,f4945c0e,df62cc15,6bf0830f,7a45ca,1baa636e,9f759bb8,bf078a55,81e34495,d269afbc,1be39ce7,5417ebf7,d45decb6,eaddb635,4480a7f7,8d7dd34d), -S(320a08af,eac009eb,7f254b8d,395d836f,ca6ea527,4e2f309d,dfb7f120,2f1b3cdb,75269a2,41199c0e,5f1cd9e2,d102a294,2324a3ea,cfae231f,99ccc5f3,e0af00c2), -S(8b893fcb,9a524af2,6de5aa38,8ac3dc,2159817c,7062e5c9,d5c9e7f7,dd889ad8,cec6a5ba,481f7e3,88c1cab,c11505f2,39afa143,68977ed6,52ea2d6a,19d2cbfd), -S(ea89b95b,36cd5203,22c8e5af,7461f9e1,a054f23d,2720469,fa74cd67,3a52aab5,5325d16c,4b866865,2437b6b8,598b31c4,59e6101,2cc1b147,e0473527,5935ada5), -S(cdfea79a,8c16ce78,75a9fa1c,5b7647fb,ad641ffc,5b73fb31,d9354a1c,3c1cabfc,184c309b,b0f52999,2a3f6b93,77b9e6a7,6da6b943,d8031408,b71223cf,b3ba9100), -S(3daaaf0f,785a6397,c652331,630931ee,a975c522,35899736,1b7e5fcb,409880fa,952efec1,ebd4c107,b26a98f3,c6683903,a498c840,ff4a36c7,ade569e4,c899919b), -S(7cea5226,a56d21cd,45bfdbb0,7fea6670,40247c70,ef43da28,d1f8bbf0,6e4ef2a6,b03edff9,6a5f32c5,6f8f63f6,ba9feb68,f43cca62,391ea587,81396c7,5d963b67), -S(1f5f4c27,847ba921,c63cef52,8b57fef5,5bdb5344,ea67a23,c173828d,c59199e1,d37f6918,e0b774ad,317dbcac,75c82188,c8a421f0,ff5756bd,853a05b0,c95ef089), -S(36cd4da9,2a77613b,6417deac,1d9a0dad,1bf0e506,de26b529,7fffbd03,4a4663f3,ec1dd8f6,6226bf5f,fedb071f,7027f9d8,d931e6af,e378396c,d0d296eb,a63737e3), -S(9835c156,1be21ce5,db788f1,3c0aea13,fde6861e,97cb2cc7,a67fbd37,17eefadc,7fad454b,7372d969,a6e754ef,c73415d7,fcd4d589,c8e255c5,1adf5a9a,82228f42), -S(5e218414,d9c9f0ad,35ded20e,76a484a1,d41b3894,ba9d3be4,bcb4546b,371d0e4d,76966ecf,9c8f1c9a,452cf971,10ca6555,2ca59d31,21092e93,333bbd61,6eb9cfcb), -S(b105f4f4,40e7ea66,e3272da9,d6b2b76e,d00e96a5,6f95224,34ca0df1,5340c585,9e8fea7f,35bc9eec,f82ae118,bcb6dc33,acae587b,f37b149,1f8312e2,4ffc86d8), -S(81d5713e,a732b4d,98d085a9,75cac9b5,3fa65171,e5cf49f4,684a7856,7c24fea9,32480cf7,a0bc0c50,a4de8200,9343b524,4a0f2aa8,ce67b11f,4a5482cc,6fa00bf2), -S(d47b4f1,88f5e7ed,a9eab2e5,8ad2c140,c6278d63,517bfaca,8cfb64aa,cfbcc7ec,524f6580,9d3ee034,afb1e64b,1a0f8ae1,1e464915,3722e345,bfda9671,1b94a5), -S(16e85ad8,6a953564,39b97957,7bedd0e9,6e2eed72,76ba269a,626fbd58,447996c0,8bf74f51,4bdbb6c1,4de81a3,1ff12aa5,de49bd52,63a962ab,b777439a,47eadee7), -S(c299c6b0,6e6c78ae,852bd55c,dea35f99,d264cb5a,e836b77d,ab209ac9,c05201e1,a558c66d,c9ee7fa4,c777b0db,288b328,428b230a,7c53d516,522ccec4,af0ae08c), -S(63c4624,35ef974b,393b05b3,7d1c89d7,b0d8958,ebd541d7,584e2bbc,7235c795,1d806446,ecfc7bfb,bce099f2,6ce37a49,61b53453,5b65642,c0cd23f5,a4eef9d7), -S(6d36d105,ed8cc5ce,53f2cb69,8ab620f9,469a3e5c,b25bf6e6,d413f414,c5af726a,1b45a3cb,1c889961,8d273993,6a3affd6,233a66c9,4bef75ca,3a8fb6e4,ec05ffb2)}, -{S(abdd85c7,a2f8bc31,343382d4,e405978,3874c8d0,1405ef14,85047cf7,f0f71d50,d5a03157,798fe828,a03ab63e,84bb007,b53a5315,1db7af14,e4ab612a,736232d4), -S(31297c6c,f567267b,3c8d65a9,72afc752,e8525eb3,de2958aa,76f72e14,5ad903d7,f4735877,a6c6d89b,d1beb50b,edd1235b,5f5e5d0a,878e4610,e7d756c5,34813389), -S(64706e69,11a7d0a1,2e587c86,91117a27,cbfa64ad,1d5617fc,81e55b8f,64e0da86,59d9af3a,419957d2,b3de7570,15fd8531,a5d07430,5cfd7444,5e7e70b3,57e62772), -S(a4988ed2,89d8397c,f1b897d3,b81d80fa,92658ce,2b935f4e,e2e3f0f9,b193af51,813fb8,73270570,50f23c3,f8082bcb,563ee366,1f6b2af3,f631f5f,916c8478), -S(3c2769bf,af401993,595a01d9,9c72a6f2,699591fe,4b869077,8c6b5ee0,f172a866,f3e0d8b6,cff168c,95873f44,871d27b,df1e79a2,d9e0bd4f,6f90f682,538c1f24), -S(49d93e09,df655edd,19548fbe,affce201,4c6822a7,e196eb98,b9ddfad7,3cb70125,26e6957f,84ced17b,c64f710f,b37656d,31ba088a,98350337,8f7323cf,c57f0eee), -S(53c06842,49997cb2,6e5b4cc,5f166fe7,db0ec0bd,52639a27,d8fedea7,214a78bb,8a8dd3f1,b3081dd4,948255ed,dd178089,a0fa7342,1ea616a5,1f639057,34a489c6), -S(7a8e7d18,3f2aa640,d0e2ea02,4cdca5fa,1767d9f,9ae38805,5d38e8e4,a81d33b7,c2fb92e3,5556fd14,4a894be2,3d97c6d4,30872ccb,25e239c0,d959a24f,aaa77397), -S(a5221a2d,29cf3ef2,f066897e,4ee74ac2,95b34cd7,54390814,297537ae,abdf603f,ec0ff395,8c3a1d1b,5a379417,5a61cd97,782c9683,aa2c7c07,5d147db0,2b134278), -S(3f49da9c,1d62eccc,afc4b88c,814e44dc,8440341d,f347de1,fb60126d,59578dbd,c3cf8e96,2fa9478a,f1be08dc,961734ca,5021a65d,b1b45f80,78fa8e8f,d2813a79), -S(47b16636,f5a64b07,534be14d,6ae37af1,9da79b42,666b201d,d0afda9a,2daeb6b6,f1218111,31ebd87e,e1fd7c9b,d24a0a11,a12e842c,6c00f445,6a342309,9b171f12), -S(a7b5a8ea,1f23ff1e,c1768eaa,2fef0d66,b75744c6,dc925d3f,9068beff,d69b32f4,fe01a23c,b0e5acac,e60058a2,889f9434,9ffce6c,b24f4a3a,662e0079,99bcb690), -S(3e14e2c,e7044716,d42e9b6e,54cb0500,a1e4374e,18917336,e3205e31,4a878b47,18af982d,2c78ac23,818644f1,ec657da8,ad66bdb,3d5a9b84,3f8bb988,4ef8dc3f), -S(71393e6,746d3072,830299c6,c1244303,750742be,361c5f08,6eb314a4,76f1736a,dc30a7ea,9b644339,ce8f1fe4,eeeba07,5bb08934,8135e819,cb061559,aa14e42f), -S(37721b73,e6861f15,7993696d,aded49d3,78994f3d,e2b573a7,defc907e,d6f301f2,ee0e1755,d8efb25a,5cf4d783,ec847425,746fa442,d460cead,56e73a69,42561de1), -S(7803c663,509fc9cc,55b372e1,dc0fa76f,149a0ca6,3db4516c,4abc0ad7,5961e4ac,356c72f7,794a70e4,db3463be,eaa847cb,256c58cd,b6a7d862,fde4feef,d896a46f), -S(32976d3d,a3d033cd,c073b0f,c7d2f445,25646893,fbded1c8,1a0a1761,a8703206,5e6b7900,a069ce4c,65cd84cd,f290f092,2b936bda,af6ea40d,9c36a321,a7c9dcfc), -S(c52c7b18,b5fae5fd,a4e3597f,39c96b8c,6d6c856a,80f1210d,a1ebfc15,34850763,b87e50f6,20b66865,307d0747,a02ba22a,b310712b,cb0bab6b,963c589c,c5a208b1), -S(7de59c8c,3922fd51,68f4151e,cb783775,cd0bc0b,1185ecd3,6ee075e1,14e66cf7,688e2cad,e4d49da7,fe691497,412c9372,c67288e8,ca4b64de,308eabeb,723fda15), -S(ac49d6f3,32cda691,c345f099,667ace08,f6496126,830c39ed,877223a8,cedc8be7,267e6a52,5ddae4f6,7e05f0e8,52b9dfe,5101c491,64d791c9,82249937,c3a7b031), -S(5a92401b,698cc394,c9b714c8,bdcd92d1,20fa72e9,b1311839,1c383024,f469ed22,e29f2926,84c255a9,a739ef0e,5d13cc55,987f5b3a,5c6ed623,29431033,70edb4a2), -S(3609dfba,51616095,ab060e77,d6779025,6456eddb,f4b651c6,442cd673,f893878b,f85fa9b9,442050d8,ad9d9314,9ede8698,91dfc99e,c05a2a48,5854cbeb,55a6c380), -S(332bb85e,92c90a15,3bf602f,45dc33ab,3dea5ef8,7034af81,944113a7,4edc94d9,59b6c879,5f2a824,96d631b5,ceff8708,507db41a,375c7257,7533d8f1,461fbaf1), -S(16e9e054,916b894e,730d7126,27b1bc81,e7689efc,23cfeacb,a423362,df49d87f,303d0428,b701f1e5,fe8ae460,e54adeb2,d4b5aa93,a9c7d7ec,7b903cdb,20e440f3), -S(4e62ab89,1d4c4cf0,2c44915a,4e2fd522,88d75aa8,e22b7463,30dbfbca,97ed9515,a7c21be3,3b5cd522,4de0bd25,faa9c2de,5d6b2f50,b50a6901,b7167b3,c4def4fc), -S(649eedbd,5612c429,2aedbacc,b846e759,4a2b5870,f21452f3,1ac9e697,fc055db9,ca694303,ee206a4a,acfc4cb3,1aa9f117,8fcbe37f,d6bd11a4,669289cc,7c37b0a), -S(e858f72a,5fe2314,951ca096,8ba59760,e3d2a667,e76dcae8,c3ae2d7a,4721afbc,f1c7131d,3e2d0468,ebb89bce,700e0eca,ae83afee,75620938,60e1fc70,cfc7810a), -S(cd351498,29ccb1e6,9b18e35a,72a24b30,e074793d,aab4028b,1c5eefe2,b7b3163d,6bbd52b2,93b43cb3,a19f6291,69ba5b2a,59785099,16842093,1e58dc1,a040c57b), -S(19ffe344,69ba3e43,7d901863,3be7c298,ad8b65a0,49c30dc1,bae30ca5,97ab38fb,c33ca345,efeec662,96802e95,69f0f34d,12ceb64f,30fc704b,b77261f0,ce5c98eb), -S(8a2f772a,a38a5b55,a7081d0a,61bc27d5,89f9832b,1326a230,d81b9f58,4d634293,a4707a0e,a7bf528c,ac62e361,6f09287c,182aa3b6,6862430,dcfef3c2,69d1567), -S(e583bee3,1dbc8f0e,572eb18f,366f88e9,3a7a0484,b4299b9d,335f7836,a222636,8a4fae1b,be122228,be9d8afe,be223c53,dac161ae,ca77ff4f,e14d9c78,894fdfec), -S(8b6e862a,35566848,50b6d4f4,39a25950,47abf695,c08b6414,f95a1335,8dd553fd,15a1f76e,f12ee34b,f2ef43d2,b14605e,db53c3a5,e7cc7c2f,27fc252b,c1641642)}, -{S(1c185b5d,e988ae93,eebe0aa4,a98396aa,fff2671d,8246ce2a,4394db96,7a541ad4,dddf4244,3532024f,d225f86d,133b8156,3ea8c92b,f0ddc354,88e6a04a,d41da5fc), -S(addee173,b29de510,58dc107a,47fad47e,c48bf332,2f7c138d,51060322,571faacd,3890624e,c6920ca8,6a9aadb9,90a15156,799dd771,901823e4,9f3bfcb6,8bf05d5c), -S(9e20bbed,ccdd5c05,d683b2ef,852760b8,e246e5d9,6a8900ea,999ac8bf,5e8f12e3,9f28e5a,b4257f6b,b826d076,ffff259e,1caeda5b,7d34f658,ddfa0401,7cd4768e), -S(dc825d1,5f707c17,46920014,9d7be56,acf2d1d3,c444fa27,cefe5019,6f5b317f,226d4960,2f349d4e,9cd10a57,6bf01681,e4981cb6,4235d347,72a1e5ce,7694a20c), -S(812e2cda,3f473919,1f2ac087,7d70d0e0,2ca0551f,10c96d95,51ba4199,22780f90,c8d05855,6b6364bc,d9aff119,5b9ef26b,85cffa72,1e880b83,eed73cbd,d23b91e1), -S(aebb0870,76f5918e,68194fce,42d0b925,cfd2a506,359af62,146c8ceb,8502231a,c1c19605,e0456cb1,3e57229b,45c83ff7,c3695a2a,31908bc0,31b08140,9c2040fb), -S(af7332f3,3ec274c8,d34f47ac,fcbacf8f,7980cca5,7220012b,8fd5ff94,cbf3d8b,d439f1a2,89799dc8,92b7e53d,a84a9e82,7bf7bdb,7240c34a,caef59a,777188a8), -S(baf71cf,7851a758,12d7e09b,192741f2,1b5d2a36,6e31892e,e54c282c,81163a6b,1ef3bf2c,a81acdfe,17cd6b45,266241a0,22caf299,ed4d87cd,68d3d4d4,526b4d38), -S(615991c5,d250cebf,8c7bd1b2,969213f0,403c7da1,a3ba913,44fd0490,88c2474d,4f014177,12142cca,163f29a1,f5790004,32726712,93c2e87e,f46d2138,c14040b6), -S(b1574b39,26ff27c7,b2dace6,6108b93f,3fc75d48,478567cc,66bba29e,750c0c86,2759967d,8d05be25,3f88a66f,830dfb83,5139e32d,6f42cf3a,43b199ce,ab85b55c), -S(5fe92a7f,d1c407fc,967dbb19,e9fd4d,8361aefc,a3d5a9a4,2f8237a3,458e5e90,9b89ce35,57d469b6,9b9034d6,cee93609,c291d023,d1d9349a,d9bcf47a,aed8b2a9), -S(d65b0a5c,41b2dc6b,e5aa87e4,adfef952,621f9d99,550e424d,176ee180,65f666e,a76fad91,3b80b0cc,3d3ceac3,9a465cb9,4d8c79de,92adf9cd,7a4efae7,c85c30a4), -S(61d7de65,fe34ec4c,f82f67b1,75887263,11683263,145cbeae,18ed192d,14ced48d,effac049,d7e5412c,5052160a,6d1b2230,7157669b,856af0e,e3e46a25,2d2ee19), -S(9a77de66,5165a9be,3dd2758c,39aa7a14,1f052358,fbac634,5ea701c8,c93bc4a9,1044e428,bb381024,70108d56,b8b3e3bc,7512300c,5a6ae44b,93b2098f,a13fc023), -S(4ccb2426,b6eed0f9,651f80d5,72b23e78,d84d6928,57648077,3663216a,bc8a418f,1840c,bf5ccdd7,19f7fa8a,33e7151,aa351d,2f620972,6ec67d1f,fdada8c6), -S(53f96bb7,86516e0f,2ac7611a,1aac61d3,cfbca76a,9609fe,e4cae036,52f68271,97e3acbc,468b777b,bd1c8263,5332dcc4,b08b9fb1,9608fb35,cd51e49b,f09d9087), -S(395253a1,b6a349a6,dfdb0d6e,65695572,2a597411,fdea9294,6e48d107,596d8ac8,c57110d4,dd0d35a7,663fb3aa,e15d8c4,dce5cb67,d3173d91,a6ff7ea2,1bd28107), -S(d7becbeb,c47d0de0,899ffdff,8620124d,b29c8e5a,fd71a0ed,76e0df76,bd4e26e6,d8b52fa3,e16e7f19,e925e769,3b5a731e,18f3163b,1ad4db34,7f878381,da75fc15), -S(fa3afae0,4f8c1fa2,778446af,88e29150,256b0413,d9bfeb44,45288e41,29be15a5,9dc76b39,574453ab,2d46cf23,ce8cdb06,cbe7df15,d03fd390,4470a86a,822028df), -S(da56da00,dfdd788f,90a12219,db03cac1,403efef3,ae706031,e153aa16,b3a52eb3,1012ca8e,ae20efdf,41c77128,93fce97,fc66b187,caec55db,7aaa81ef,cc12838f), -S(f07866f0,cca3474c,40e7fa59,26df41c0,e46fbfce,faab92e8,9ccd1170,3ccf79bf,37ed66d5,5e891f4,e644fa04,182f34b6,1f1aedbc,d2a71aac,dd1523bf,f579dace), -S(853f72d1,edc4d953,348528b8,3656894d,67032333,28a16801,64a84511,15c5e968,197737d0,de83e73b,247d861,510ac76c,3ca214d8,ebbb958a,74ce1c31,5e715e87), -S(7c7eae74,dce7ef76,9ef0ce86,cf6ac861,ffc3d4a9,6313f379,fb2c0325,daa91aba,131e1689,fb017e15,e869d858,2dcfc4f9,153d1e8d,246fd613,b3922302,5b5c3767), -S(56028652,bce9dc6c,c8b4ad5c,f9f222c3,412e5bb7,8d556225,2c06c2e4,25a6e31a,2aa8e093,d8653f6,2153972c,e54806ba,666d49ba,3787934a,a37bd65e,79374ac0), -S(2eb98b01,550a00dc,59d280b0,71e472b5,a65eea89,298fe4b0,9f6f0e07,9315ad7b,74e22fc5,3daecdee,6a0b50be,e17f1d7d,d9481e77,28778957,274c8d29,a0d89fdc), -S(7268b61b,f65d73aa,37766a99,9960d998,18aa4ef2,ae8a97b1,db8476fb,32f891a4,824e99db,3157b706,38573513,618f6901,ce1fcff8,f25019d7,c5c45bb2,f3bb4d47), -S(cdea8771,4a764e3f,a94e7356,879b7d9e,da7c5b6f,28c172a6,1c0ab012,9b9ddd7b,daf49b12,34ce20aa,263b4349,f9f88cc5,1334db26,59b7c587,212f407f,cbb2644b), -S(38831af3,193c8860,690a9d74,cc0079c0,9e3ae0fa,ebe0da02,67ad6e23,99059d19,be188500,5193f11f,e34e70a7,e470cedc,902bee92,e7041403,c2f1ae53,7a8bb077), -S(df3acf55,bc6d97ce,34ebeb46,34fe1010,ed3d6d6,383c11a7,53a93123,e9c8381f,94c22735,ae6f858a,59f663e2,12532e14,4efe6a81,981c7619,e5002968,dcb81df5), -S(a8b08b86,4946ac6d,a101eb85,ee7bdf55,24282ca1,a9956e4a,eeb1afe9,87a43ddc,80ff0174,375c95fe,cea6e00,20f17123,5cda4bba,d4ef893c,78ffe37c,205d5577), -S(fd9941ce,e1c26864,248f7035,352787d1,aba9e93e,f5edd333,d08c89b8,4bb9dc8f,85be138a,42bf190b,921681fa,8777a619,878d4d02,11016c72,8bc151ab,1a687b5a), -S(7e2cd40e,f8c94077,f44b1d15,48425e3d,7e125be6,46707bad,2818b0ed,a7dc0151,6fa48af7,d523054c,7d59e574,cde106a2,776411bf,5111f7d3,65c43ac5,df8ddd68)}, -{S(282c5bc7,5b9c3f76,73e244af,29f22b80,c171bcac,d7e39b4f,ac7ba6cc,656d9010,e8db2eb0,a56699f1,73d5b5f7,99d39e14,dde34648,f159ad0d,c1c7767a,19ae72aa), -S(d5a3eb7,cad9c548,839ceb7f,67145e0e,96c60d8d,68415f76,73b73700,5ce3a8b,34ae4e12,355d1df1,25149efb,1a9050fd,490e251c,4404fb37,31b6dcc9,e233b9f1), -S(68718b29,86197989,3c5f7b1b,48abc254,13bd23c8,96c8828,7000ebe6,6db742a2,bef9d2a1,bb596fdb,3caeef3b,4d950568,8a94b436,4fd85f37,30b20de,b9e9a4fe), -S(a5ed1709,7932011f,9a597511,a526e61d,f22d0bd8,ae3e15ce,655820e6,b1ff1238,dd6dc7d0,81e70b57,4f235c10,c7c3dbed,a57743c1,15e6fe01,a20ac751,34cdace), -S(ec37904d,9662a487,1a471d9f,778bdef3,430df9e2,26fc42e4,7fc4bf5f,80e3a9c4,8413f2f,1ed55d8b,8448e336,ac9d1418,c48846e2,acb43509,f1a3d935,8cd18ed6), -S(b09f9c76,1cbbb685,f695328,61c459a4,d2b16989,3cbbad2f,dd49c87,1d860db4,dbbf9049,31b18454,21c41f2d,2185e3d6,c8f55dad,f1514ab0,655c856e,3391278e), -S(ed1a335,48864e9d,b41abcad,3344f4e7,ebe57841,9371095a,6b95fe4e,ae59edd7,d1146be9,83adc77d,bd9c107f,3092a9c2,9c271248,d78ce913,7831127c,c403f44c), -S(d39507d2,6ba377f5,c7116aca,78df331d,a795cdfb,54e5c912,8558c0e,997b74f3,fa7971d4,32cb5a44,589dc705,de28ad0,382206f1,6e11229f,86ff82a,efef3131), -S(641dc311,baa77b14,35f408e1,528445df,53c5ac5c,32803a3d,84e8fb66,60d71d,2b355a47,76980bfc,8a4e0ac6,a3bd7b02,a6b20ffb,f8650b16,89010456,6953e49c), -S(c3dd73bc,cfb744bc,57bc95f9,3c260df7,7f3b7e74,9e4a5237,f3865f8f,f0c89489,15d58dfb,83654754,80e53bb2,a1ba430a,ce213c38,ea71c7b7,51b4143a,fe2bd124), -S(3f883fa2,e834df1a,6e9b5c46,b663880e,9a0b42f1,891b92c,eb30600d,5641813e,7acff194,a5fb76e5,bd3d8fd4,2c7f07a8,3a991ba6,7f0e4edd,c55e1d8d,3025d590), -S(70c8d4f5,21d808e7,221bd5c6,31f171a9,5e7aa358,4477068c,2549c59e,228688bf,52badf20,6106d5a8,d7bff921,580eb5f5,3a53aeff,e0369f9a,1bcb282d,7b4cc26c), -S(ae08db34,874d39ff,bfb9c92c,5e4253ca,7ed508fd,d12841e9,63600461,b2b3a0e1,dc0504ef,d209be71,381eefd2,91508120,fb6ec1e,df62d24a,cb1d77a9,4eebf1be), -S(627027ad,4aa88477,c6240517,87a25b88,7d5b98f,b968221e,8e45d584,3db6e0bc,34b553a7,c6ac7004,69367afd,17c5eaf8,7605ca18,6a57667b,650fd8c7,18ab76aa), -S(573ef2ae,72ae8fd5,eeb0b720,f8967b44,f7d9d96d,c8a4825c,23a3dbed,fd2bb442,264f508e,efe5e0a2,55e55a54,bbf739b5,757d0a15,994ea9b8,4e139738,7c484786), -S(28907848,cf84eec6,773a384,ce5f4a5a,24c8afc8,606488a2,ccdeff25,6f896dab,ea87d4f,41df8727,2fe84537,d11126d5,62618bee,a51008ca,895a8375,4f05ec5e), -S(163db4c4,536114f0,75521627,c61f62d9,14214d64,ac9e66b0,d85b9991,62c54c5b,7ffc24e1,11c0c845,1c574e9b,e4b56610,696d3667,a6e6abbe,9d1a5ea9,4122aa1f), -S(2ec11f2b,71ffc28c,fb5e779e,7739098e,c969bc78,3cca5a22,77d2bf53,e6574d1c,c5e9fdf2,89a3090d,e24d13a1,bc8377d9,de0bcf4,63482ebd,9620cbdf,8b238fb0), -S(30549ae0,9a46820f,f49423b8,9c6fdd48,703132fd,ac166dc9,90609a32,49039f0a,b8c94b4b,36d39247,732976e,fc16d500,ccdc07f0,d7b97db5,7a1d9fbf,d8cb5d2), -S(98685f94,a043399c,89e74674,240322ac,5a595bf5,41aaa44e,d781781a,10fe9225,4506b1ef,7561b811,53f44e8f,325f9222,e999013,30523885,d8c59864,db13a3ef), -S(9acba196,3014ea9,1baba28c,e273c6e5,b9a2e1a0,98216c3b,194a0b56,dbda7db6,f0a3358e,eec737af,2e313262,b29ddf6,2adb9e97,9f56def2,65102272,6b976290), -S(e81e91a1,7aeec75c,19df0ef7,fd07ce2b,e477c031,179e3f99,4ca13857,e2b5ff93,65236424,aaa8b6cb,fdb2fb20,46ae3c3d,839d97ed,217edc6c,c774f889,d2ce8b45), -S(61e60aeb,821c3f80,b53ca78,2c3b4d21,960eb0d2,c90202f0,a5fba651,1725ddba,b029275f,690d10bc,b52e8bb2,acceb071,f07834fe,64175088,a97e26f9,8ff34432), -S(a931c410,8fcb4346,6802dd4a,8ec2cf62,cf4c5558,8129299c,b3a87e95,6fba2a34,c21a8dd1,43d4a639,339fec49,f56d717c,658a55af,ad72da1,c754fb9a,117cf6e7), -S(fb5c106f,da32fcfe,ffe9b5a2,7ac8cfd8,d9a73da1,5fa6340f,e09d187a,7a83cb88,a3f4c60f,90003375,11c39100,ba4c4721,c6c138c1,cbae09dc,46d1a1d2,5baa95fb), -S(dc25e18a,18f0035c,2a05e80d,d6b38830,7fb3b176,a66ae451,8c5640db,7540dd24,3ba83beb,3e6b29c2,97a0ead6,148f9b93,711556e2,e5fd513e,ee649228,c62d8f3c), -S(ecf7b689,ca03b840,739283e9,c3003a01,65ea3f,3bd17e06,9260c0e9,ad403273,5e0dbad6,47997fca,c0d7ba2a,170a7954,67036ae8,e61dc532,b5fe184a,deb8a7ea), -S(263e593b,10c982d5,1bf89ec9,71f6a3f4,60e53bf4,cb2f6af3,2381214b,2e981bbc,e255bc11,11470eb8,894ead67,c618d7ca,a6b76ae1,a230ef05,3830d028,4a7faf37), -S(f79781e7,a4137ac4,7a9a9d00,9d239b37,6cd0fa3c,b9f5de46,8cba5a11,ffcdd69,d10ba78,896e086d,5e25444,165e79d9,7b3d485,1a448e03,26d8906b,2f27745b), -S(a4d28024,11f577c1,c5d08fbc,457a46bd,428f4d2a,b29475ea,ef622876,593e49f0,e4855491,ac0342b1,dc804bc2,7ae23877,82eeaf22,52874a00,4d4e0d66,b07b434f), -S(87195a80,dc83be4e,cfc9d4b8,29725cbe,11101c26,13c98f2,641753af,1ee840f8,f9fce233,66931c51,4ea09224,b565dec7,22763d8f,6f572057,fdd7d96e,9811289a), -S(210a917a,d9df2779,6746ff30,1ad9ccc8,78f61a5f,1ff4082b,5364dacd,57b4a278,98f1e4ab,af4a1a84,85c6417e,7298c82,c87619e5,500df403,80d8ec01,f384d9fe)}, -{S(6c16768c,433a000b,adc47b10,ba4e132c,f5480e65,ae83d1a6,8aec34d2,c00c76dd,ca1a47dd,66c2d74a,ddb69283,2ea289a6,ae679669,edd80bdd,4ffdab2a,defbb542), -S(f757e860,ed04db61,594bd647,5ae81b7e,d6d2fa58,80cad10a,7756fa26,810b8543,f2aad599,4e491e02,9b1ae256,2c90912a,1c9aa6cd,dfc2331d,a0069a79,861208a), -S(d9f269d2,9aa777c6,9989d706,91403dfd,9025b491,ba03ddf2,dab8c9,af7dc764,1b39b85c,cb4749fb,7f47086a,ce63924f,3ebb4213,af5dfc95,fda796e6,c6b0b8b0), -S(d05e14f6,fe6ca50,a23e9339,e449f771,98e842d4,80a72d5f,8f5e4c06,43547cb9,869e3bea,6b19e0f2,de83fa8a,e932086d,d66e838b,637ea603,5f0fa081,5912c8f1), -S(9f723d81,1818046f,b7512abb,faeb46d3,52d8da9b,3abe819f,3861f9c9,963c583b,37df0657,3f2bb428,6c8b3efe,f6941e2c,4e48d90b,931cd0a5,78a4b52c,6581ee7a), -S(e65f0b42,54ad9df9,681c0db,3428ccaa,11194df3,9e837aab,4564e1fa,254e6f97,43e59d10,54aa35b5,80373e08,cfc02aaa,4f581406,58341e67,7e50977e,5bd893dc), -S(605d61db,589fd91,78a65cb5,99697001,73afca81,23f663ac,5fffd0b9,8f5e7a64,a976a9d,a47745f,447ad4dd,7eb63875,c228b979,a7dda50a,d994df7b,545d0ede), -S(43298aaa,faf20e9d,c2240256,493ef19f,5630db6b,f6376e4a,356bd034,98f1be7e,737551c3,653af1cb,4f8c1e8a,347f50ca,142c03e0,29007f29,c76bb763,b52ed053), -S(8afba782,d6373f0c,54734f1b,4b854e63,bf2a3b4f,23f57a3e,6c2eae86,25c691c6,da3054aa,228b9757,b7321da0,64516249,652fd814,15017584,2c7683ce,1a3638a2), -S(3156d359,e01d64fa,9c8fd8b2,c47c3492,82dd459a,fe89d94f,35906da2,c6d0208,85a23f48,f0a7448f,c57ee545,3978e2cb,6f2bbe54,864477d8,a63775f7,7ff7289f), -S(88e1a44b,1e206eab,49fe97af,30be5e47,25e1011f,312a5222,e9e80819,b3f26357,63dfe52e,10317c4e,227b2a5a,d61b713e,2d93aba7,f0a51e0,b5621191,40c58ded), -S(d10de96b,f2e4a6f8,78e0f37e,15569f3c,b9717a38,7fb98928,6d65d171,4b81b301,2c0a46c9,6a2e3884,e7f3b146,acc170d2,6d12b959,4b75a901,dd535016,f0355ae2), -S(eb36b865,812ae4bd,7893e50,5aef6f14,bfc90c1b,42e75ea5,91615aa,a2101784,1523537b,790b2a61,fb6696d0,a622ff31,efea1255,e1dceb86,763985e2,6c5ca8df), -S(d54be697,e41396c6,3d63f96f,bde9bba2,36ab1649,3c156159,3df81d69,c906fe60,89de1769,433b5678,1f7a2206,ca98258,20d0c7dd,a6d5b672,f77029c2,6bb59f33), -S(d5aa72fc,9063c2f8,bd0fec97,da30dcd2,a5b36aee,7894463a,f7042795,1998c979,ed90095d,bf2d3a67,2d2f1a0f,9737c4d,e8f3e773,c04b77d3,a2345dda,ab662199), -S(ee8cd53e,8ab64281,b5cad323,f03fd06d,7aa166eb,df9185b4,8d0eb0e6,1bd0bc61,4781263d,fc518e4,809e5ea7,7f9df238,1ee7b6ee,ab25c1d9,5cbf3fce,72fdd615), -S(ddc5e95e,2a46736d,9bbeee74,74364bf9,e1d2724f,c43522c,cffa05a8,7d078be9,60908fb,809ae964,98a26cd9,67532df2,409491aa,73c46803,eb58861,7ad86745), -S(ae503a2b,b6250ff6,6ee615d8,41cae4e,751160fe,aef7f33b,dd1feaad,ab236b58,6e53d2a8,8f09f78f,96d49a6,2f98773b,a282b575,ab6e24f8,4d604c3c,8583a66c), -S(8a502d08,bb3cc1da,438c5780,e2120c50,12c1a972,8aaab6bc,5d908b6e,2a83dbdb,fa02e62b,85d7de78,8cf11d9e,ab406523,bba1f912,53006a89,f3a491cc,dd99575c), -S(b52891bf,5acb0019,a8d10b94,87fa47c4,22f83a00,ef539e91,44bd9f7a,d5075716,ae58653a,b167a9e4,b71eecd7,4f4a8786,19c19026,29c0018d,9f082e7d,5920b2f), -S(176170af,b40a3e79,8a88b98f,fb6c578c,d1ab56b5,b7f4142e,b2d84a59,1b009f97,6e1d5682,36176d58,ce5fcac6,4d4d2885,5db107dd,5215c71f,b4076aaf,d31c5d24), -S(27359f7e,8d3e3dcd,ea35f603,d8fb15c0,bd63c08c,3ae4d2fe,8cb6434a,ae2e716d,a0d64207,8fba00dd,4683d597,27f3c67f,3c25075d,802a4ea8,eb08c20b,47a941f9), -S(1e9d955a,2f68478,5227e866,491990a5,62c802ed,1b106bb5,42d02d29,93542067,fbf5f466,57707b3,3f116a23,fe5991a8,90a9583f,fd063943,37a19aa7,e125ccab), -S(b5c4c10b,1b0e0813,37deef6f,c089d2e1,ee14da2d,cbb48e6,74b7dbd4,429e22eb,fdac245,b109947,8f6a53a2,8a1ec4fe,da43b4a9,2ef49e25,8f9296c2,88c48378), -S(bd2f651c,ff6e614b,1d6535cf,c3a2c5d2,da5307b0,1cbd3f48,655623c2,55503916,3715b0bd,bcf29d97,63d7fb35,f9c5b54c,769a863,3517a2d6,8dde74e4,c4277779), -S(c4c2a8e8,f1e257a8,fcd0b11b,30635c5e,782fedcf,f99b0b95,828e1369,3ee0af73,3a08abb4,777a066b,49ec4c01,aa5b0868,f100a473,e555def1,7c5a9d84,b1fd9ae), -S(4aa77ce,15dd97ff,47c1125a,77bcf0e9,d302b79a,e8a919c6,a875e5ed,eab8c2ec,31a09dc4,89a90240,334836f6,302d7e81,57f19762,a9b5f727,6c276e63,560a9d10), -S(3731162e,66a8d2d8,ff4df3e,95950103,f5a03f9a,86bf37e5,605746,cf4be846,e19d7835,10af5daf,724be4b1,932dfac6,23899ccf,7e3e58ab,5bf3265c,667cbf28), -S(6e2114ed,297ba44f,c3926603,bc03a87c,af3e9f2c,8bd84e64,afcd9846,bd9c8f0a,faa6e5f3,3d90f91d,82592af0,7f3a26e2,f6f4138a,2f06a6a1,4286eb71,2e95cf94), -S(50d775b5,f72d186b,266a14e5,254cb5aa,49fd8633,81c36b09,842632d7,ff004130,cbfe11c4,f0b15aa8,3ae8dbcb,9feff9c0,d68a26ba,11095b3c,ba94739a,2091bbc2), -S(8f3ccf31,f8b74b9b,624a5d1b,7cb1096e,202fe5e7,233777aa,859864d3,775732c0,980e32c1,d2c61ace,7610b926,6831ac27,56f19788,ab7a77da,18c421a0,9a46bad4), -S(24cfc017,6da2b46f,a8bb5bf9,636be1ef,fd7e297f,29122fb3,e84c9ab0,c18ada5f,14007044,f8639e59,67978eb2,a21256d8,126a635e,5b07eb0d,97059ec5,6875a3c4)}, -{S(6efcde8b,e99d9ee8,ee0d6b8f,a76584bd,5deb67b1,415e729b,48f3d41a,f1cc1386,4ddcef4a,a6ad5be2,d1e83449,9eca4a8c,73219f80,464a4a9e,ebb7f3f1,b70c9fd2), -S(24fdd052,a1e535e2,4eb79ffd,f03093f8,5778241a,b845b548,31b9a82,730ee3e,c6ff8ebc,7edfd9df,9b7410a,7f54c93d,ff0c682b,152bf4db,1b79c0a6,9889797d), -S(aaaf86ed,31dbf395,687c959,6c445b6c,dcd1fe7e,ba2aa13d,1bf41867,dc87b30b,582b9683,729be5c,85fa83e,2ba2abac,e3037262,2a24aa35,c7753312,1de2fb93), -S(23930d0d,2400db1d,56525bb4,67172fe5,e930bf86,21124fa4,6c5a421e,10b059ea,5e11f202,beca3d5e,dc9b282c,2e86d5d9,30f8f5d,27a5c4d,d2cd6dde,6d1497ef), -S(76ad10d0,bc92ad8f,55b665a1,8ee84e01,2e92dcc9,37e0c604,59bd6fd4,ded2d9d2,d4ca7386,ce0c4c5,fd37da9b,eb8fb040,97d98891,35a5ecc0,320dfffc,95ed3c10), -S(10b324b,e959f0c8,c8a82142,4a8f87c1,fdeb7f88,258e1021,c9cfaa66,b131f3a4,590e672a,daa8d547,161f635f,153fa12,b3500694,677af3f8,90dd4ca6,9620bb56), -S(afdb2acb,ebfdc11b,3577177c,d8bcde00,65151495,79c6ad2b,f7386275,a9314317,87d7786f,5ba775c0,ea47b141,cd0d4274,c7e58634,b64e4c58,f7f0c595,5a307250), -S(574cddbd,59b34df5,30f5dc4,61884ebd,1c867ed5,6cb60832,4a11b1f5,29ebf733,1bfea852,34256807,1fdb4f5c,485caa73,7136e3c3,b4b8a39a,389d7dc8,724f16fa), -S(97ffea2b,5de34e1d,495ce082,d0097b72,e7daddb8,1cb622c,2c14e814,bb0ae278,45fd3d2a,9d1e6530,61b4a356,65aa9e70,43766950,622e1c25,2baab265,6d4ed95f), -S(de627f6a,a7b56d85,535c398,80d0276b,b910ce4a,6066435b,512e5e0,21ef55ef,753033a6,ef89f053,c0e662c8,1557e6cc,d8b4c8d4,5204f5d,e1c8c742,72b96277), -S(b126c35a,d7993bd0,164867c,58c88421,d2cddb6f,d16a5966,7d9683bb,1b428eb5,a9ed1bb9,e9eacf9e,e712bcda,be629143,ad0e7652,82cbfab8,e586cb07,131e5b1d), -S(847b90cb,8837f488,ef027a05,71b2be6c,620cf86f,ead235ad,e76e3408,d0dd1073,9a2667be,6ce36e7b,d76117a9,fdb8f1b8,7c7cb45e,1a03f53e,7b32bc63,6f274b4e), -S(8ea21457,6f1bc2c8,fbee9065,c2cf5c3e,7a3b9fe5,403fb980,96040c2e,c6fe1488,dd75b454,acef4d3b,1b355a63,f0cd17a6,66aa9e65,f1262629,f0c7d1e0,33571b58), -S(9e11bb60,ba4b2d5d,fe53bb9c,598edb16,f3926bea,1cc90eb4,3e05ca34,e83f1896,263d7ea,50d83b8,791fc911,a4f73cac,4d42a09a,85f5ae68,86cb268a,fd562dd0), -S(f741856e,f353a7c7,17db9a13,4ab4aaf9,13c1f7da,cef08bfd,6f81dce5,b1130e20,ee63dd2f,48e15f68,d1acbf49,705fe010,231e26b5,14146c47,1a689960,d568eca4), -S(671ef05a,410b41d9,3b092b04,e523468d,44837d2d,26dba670,27400715,eeefa2b5,686d318b,b49eccbf,40dc18af,f1938fa9,b16d4d2c,c19dd2ac,47c7830f,89b8d55c), -S(59ea10a1,e5bffd6,a34593f4,b986e37b,5294ddbc,60d92906,52c6e9d5,75f88c55,c0a2eb5,6d04ab99,abb5b76f,7b2b55c9,c09d44f3,3785e3d4,64554c3e,dc7a334c), -S(37f2c7c5,69c6fd15,9b721d8b,8d40138e,a8873b6b,452af0a7,89a50551,e9703c1e,d114109f,f9e6d7c0,c51a542f,b2e3ef5b,74654bef,5eb84aef,c87f5096,2a30c078), -S(1d280637,9d77e509,126a440e,b1e56f1a,8723728e,97c92420,5ed13081,98c868b9,85003989,93a4a600,dfd0f092,b13a1186,c1c52dd8,8fc8eace,9bd4f1c1,b47741d8), -S(39aed6e6,a123061c,228d3d1f,857e0c9b,29b70cdc,549b4ea1,9fb6802a,8d8beacf,6bf86967,98e3dbf6,75865a1a,b86d5bbb,10f16e8,4f9104a0,87602c,e6946aec), -S(aa770804,4a996b1d,5bda074c,941b30c1,d1474da6,47d7c4ed,248d3a9f,c3c3c525,10ba5652,b20482f,fc2434ce,ac185d8d,af6cc6e3,61e77d3f,258abc0b,55610879), -S(7626a96,9f9ef188,3ea82737,83e5571e,4054fb73,6190977a,299c2a05,d29f60c7,172d4618,e5f88055,ebfcdf9f,55267ee5,cdf18396,1d5a2a22,55b87ba3,c7d7d2b9), -S(1a550684,d1195da7,c4b09349,f149eae2,5a1ef23,c9a81109,115d93e4,c98cdbda,c31d7dc1,b7efd019,c491010e,30f90ed8,7503c4bb,1b37fbce,3dae199,6609e3b1), -S(8d2306d2,dd8c753f,2b093e62,86fc282,ba3e1dbd,7b4ba101,83d1070e,d2d06e67,97dd14c2,d2c1d147,486a3dfc,d608ba28,d63fc03,251a106c,9811b088,978e3a5e), -S(f31a69ab,97039589,940851f3,cdc98bc5,d400ff93,63794f81,4d88215,4f00db99,56e510be,7f41b009,89792401,13641590,40f5f305,f27fe1e2,db1cd7ae,887ff5e2), -S(ce96b3e9,6eb94b7c,8bdc7b57,efd2186f,62e23e72,f11337ab,be7405d3,43b4d762,cc0dc898,33e7a632,d0fed52d,487f2c60,96c69664,f698a71c,3f7f8a29,4f181add), -S(bed97e25,7d31b5fd,36b41227,462d9122,706da670,d432ceff,5d37d83e,fefda56c,c0cfe30a,2c3b3074,1af492b6,e3797c4f,3b00593c,6806e2e2,f2cff401,6e877ff6), -S(923bc6c9,960f6e4d,ca2a7070,6d160e19,83a16b6c,8535783f,12c5ac69,4aad226a,c47f08b,6b2056d2,8e9f119,9ec6d5ce,b48801b8,7ee56280,d6a48352,b2b42b1), -S(b3cb28fb,7465cdda,85823dcf,819400b,357bce11,23d9229a,eddb8262,53b246c3,cf035ed0,b624dd68,8a31eb5f,3b28e83e,c0bf9453,649dfe4f,44078eac,9345f2a6), -S(c69aa2b9,ab3c5e45,8713a912,e7f95bb,4e5498a6,d4090323,5cfed1c9,c2a60709,2e95e198,85637d55,744e32a7,98c02c7e,b29f3bf5,7cf7c870,7cafdf41,f6710f0c), -S(45996af,5795ea6e,43e0fd29,671e119b,8b8d6ad2,4eac90ec,d27d5db1,b4fb6a39,2c0651f3,1c7d93cc,98d79d7d,f21110fc,8c1dd74b,f1ffefac,a3d52484,f8da40cd), -S(264559d8,7829256b,ed116900,d82d0c37,9f0e4d12,53c68e6f,cf2d41ae,7cddab8b,861a42e6,d92caed3,108439c8,fcbf8d28,8579ce50,c6350e19,3609b4b9,ffe217bc)}, -{S(ac13e0db,846df259,fc38d6,3b0248ec,9fcfa8d4,bcee368b,1f4a66c6,d41f9163,6721b0df,2ed06fda,9b485cc2,aa56f1f3,3a913e99,f6809577,95280451,9ddc96ec), -S(b6b7227f,228da269,a0e5640b,8a2cfa34,555ccdec,2243dd0d,4b2da0a9,b4cb5e4,6afe41f9,dc129d28,4786bb76,17786c8d,42597435,240f998a,f970620,90d32059), -S(460672e4,4f2768b9,842a98a5,ca8b90df,7d9f52bc,3fa2665c,4272d7ad,5f48b992,6d7f8b36,13b38fa5,80ed1d4a,21d196bf,be491b46,49c96da8,342441d3,f4af4ca2), -S(1d3d4ab8,b7c06136,8dfd612a,25f04016,2bd3f6cd,cd9cf58d,c11647a0,d28b629f,434dca08,17bbf964,eb0a316c,b2b0df20,eb2e965d,c4d8d795,1d4a6e66,5ed23d38), -S(9c5d6342,303bc7c,73763cb9,2e3d7069,7d913f6c,1a6e2f47,39470da3,22b7c1b,825c1a54,395b9b41,ccc2e3b5,3fe1092,f04c382f,b2ee3a29,fd59e255,5f22fc15), -S(5c751285,a4b55535,fe24fe27,568868f3,afb43cf,aad1d2b1,c6367daa,ac9493b2,e2388ab4,414c4e4f,e34a4c78,c869dd93,7094ce2d,4f4666a8,2eef8047,3b681fb6), -S(8c1592f3,8d73e277,d3c18d4,ee3eabce,32e86f92,2b27c2f0,1f50509e,74dbc211,399c9507,43cd9e7b,200c255b,bd25670e,cc111462,2d5dfacf,9dbebdb,53ee59ab), -S(85320e36,5f40235e,621171d5,c8008845,890f521b,d7e2cccb,88c7fb7f,a08200c,96bbe8ec,74b5f1b1,2a6ecbee,2aea6f0c,b6d0657,aac3556c,ddc4e46f,17cd31f1), -S(5fc21f20,13403705,687b8ad3,387a725a,f2e6300e,13d28403,569d4cb6,5dda7f34,bb709fbf,be95aeef,c00846b6,a4645b72,dbb4e1ed,866edb57,7bc5d9a8,2b774b0b), -S(fa40e658,588f8a5e,29d380e9,c1a6482c,888f53e5,e331f8ed,9b1273a,56d094e5,5486cff5,3b7baaaa,de8a51a6,1d1a9255,95ecbea3,39955c0e,172de4c3,4762eca1), -S(9f87d04c,5fcc48f,375c40af,3197c28f,c62cf3c5,10fcdbde,5aec79a7,4e6a6bc0,9a6cc172,23a770c7,a03b5333,6922170d,e9409f3b,9846b9f4,41832ae1,f70f5c57), -S(bb66dd5b,2f88786e,736b50,e536a0f0,3d59b86,511e95ca,1bab2cb8,875bb187,f8215527,c76a5af,e5e76a33,eb2622d,5f822ad1,d284c68b,c840f65d,4f731c63), -S(74d223e4,bce2d6b9,b2fa9482,46327e04,18eda6c,cfdd76c7,cda8be62,3f6dd3a9,b7276bb3,817c0e72,e1ab002d,50531065,e1c4ca30,9c6d6f18,bb5796ee,457b4270), -S(80298b62,eb4d3ff2,e10607dd,dbcacda4,3bb30e57,f3c8c7e7,6f9f3968,bf391316,fc72362b,48c8b606,4e428e6d,1ef2ac87,931caf75,e936a33c,228a5caa,c460c5f0), -S(8519f27d,9560acdc,509fddee,9b4a4a7a,8b13496f,14760a08,22609f3b,2ae07963,193aa9db,b98293f8,e70d7253,51d3893,a9f5fc73,6f3c8e65,28a2dfd6,5dedc220), -S(49d734f9,c8eff915,fd66757b,d6484bc9,548f20a,d8c05959,f651eb36,e45cb88,4c594f79,7651b49e,929932a4,59e3bf21,3e74c0b8,acb20907,697a25a7,ed21057b), -S(6a528c6d,19b1e28d,b4d9ec9e,19c4f7be,184ef845,1f41b322,e5932f05,575bcc4a,7350b90b,c22ab41f,40c13a80,18749e8c,275d3e5e,5d687df0,ddd47133,c092eadc), -S(6f3df40f,5647143f,cb93b23,4795d9a7,708db6b8,2e2df53c,f214de4b,61eebaa9,dee10664,54b625ba,34ce4b54,f7285714,7874b5d0,6b38b1dc,37b7471f,9208dcbe), -S(5abfd7eb,c4c5dc14,cbf0e335,f2e87e7a,7db96a2c,b78000aa,64fa8aca,517ee1e5,d65a98d4,20d872e4,4c43997,55cca5c0,bb94ccc0,b25e30fe,8b5a4fcc,7006364f), -S(1bf3714b,da04d769,782e37cb,c4a4b347,f9fc769d,a18e4940,d19a205a,bdd22a23,d0852b21,33b04274,183f4de4,9a20769e,4a08ea16,ca8782bd,84a4da7c,64c928a2), -S(773ab884,a4e90454,ea467caf,f18c3b64,e316468c,b5789fa6,4958f73e,ec3204f1,62213b85,b4838d8a,fa3a14f9,32db7d79,dec538c7,d872d9d2,be1640a2,4e367caa), -S(33a283d9,9b7564ed,6ed10d88,ba26ba,fbf3a375,e00e10d1,577fce27,2c204324,bf84dac3,40736625,cf0e6be6,98072c6c,5fb8bf9d,2850be84,ded3f652,569370d2), -S(62bdb467,596ffefa,22b735fd,d3dfd959,d4a6e187,a19d4c1f,4d647b4e,db380c3b,210a8e93,d1a184d0,a3548be7,6283d180,8e4f32d9,52834c,515953f0,4ecf9acf), -S(ef16d3a3,233f03da,5864801a,c246756b,d1356137,971bc164,b5512067,b369dad2,480e3d32,7f1df8b0,646c3b58,a51126a3,e91522de,ab77d6d2,f2bedadf,1219b877), -S(a6834869,c006d044,a9dcfb9,8a5a14df,86469fd1,fd0cba06,a4e8ec1e,1fba89d6,c1a3e0ff,7abeb1e,8cac11a6,8c1b4c1c,f663e615,9f508c35,f4747f50,84b247e9), -S(203d13c6,53a3c36e,55a836de,b38c7443,681d7b7,c681d71a,38fb0fde,986ce9c3,5d7dba97,573ffd85,b3fd4417,f09192e1,92461c4c,125a9947,ced9c737,ecac65b2), -S(c48819,b8f32966,bd50f162,30f5c0a1,45cb3570,d9c4b104,4c306696,2f4d6667,feb08ff9,1f543c1,35b6e0f0,b21d7624,91ac096a,181bf093,fcf8f4b7,bf6559a2), -S(31441031,ceabfbf8,59bcdd8b,6e177f91,df7bfe08,f9015172,1ead3acd,ab64acff,e36315bf,6f087118,32894704,8d2fd259,6b8beae2,e1917341,d690a1f,786db5f9), -S(e3e4750a,310c48,38920654,b6afa032,79589d52,74e48139,6e22d9cd,3c05fbdd,f05868fe,5452da6f,fadcafb6,69e5edfb,4b9a7840,3a305004,345ddce1,eaca43ac), -S(3659ba70,60d8200c,9512facb,5c730111,4cdc2b9b,aa5bde14,8ad9bf9d,d8f8fb8c,b1185617,f91fe5e8,ec68da07,138b6780,e1ebd12b,1bb44eca,8a1b9472,8337585e), -S(1a46b7e9,fe99a4ea,492fbc90,3281b924,6831fe59,9360af53,bde4ce8b,43ed5996,97c317e1,5c0e23a8,f1c11f7b,5f9c140a,af786b56,10ad8ba3,d11b12ed,17379f81), -S(f16a409c,677a40be,402f8efb,3752373c,aced053c,6f702b82,8bda222c,a412b6fd,d5becee8,ebacd866,285958a5,8b1cf1b1,e9abf9a6,db61435b,d9725187,135fa955)}, -{S(32c932eb,6fa35974,90a408a6,ce962d7a,ef2bd22,72cdaa,cb80f798,9836abc3,3e145848,c2f8197e,f0264d7c,370d1784,7d21a09c,77fd9f7a,73245ce7,2ce5f3f6), -S(49d837bb,63890b4e,8a4a63ea,6d88599a,c9961c20,80dcc955,aca6a101,bc935f16,358a7f6d,b540ac03,78d83bc,304cabf1,84c7580c,46c258ec,58f22254,e3e03aa), -S(23516ddd,40dab9d8,63dcad6c,cd325503,b783379,d870ace0,9a0b238c,d7b6b2bf,b1fb8268,a7814efc,54f3d637,88956b67,a3997a31,10a738a4,94786d95,a5fa1c59), -S(6b4e215e,df56e6ce,6378fa98,5d604f68,e3561275,788283d6,c40cb249,6d16310e,cdf9537e,e6f4304,dbcb9df,f8b97a71,a12f014e,29867e5,6b09b388,78c9ce8d), -S(f4f30433,c933dddb,949ad868,cc0d52e5,247149a,7ec98f12,3e7f63b4,acf6b7b9,949123eb,9fb848fc,d7b94401,a64b21a3,53fde44c,d93dae3e,b7a2d3d4,78055af2), -S(dc3523f4,cd24be1b,30787dd7,5140fff,b66e4487,55e9a3c9,6124fe59,c07faa28,47b945d7,6d37b855,8ede59fe,e297a8e7,81d3ea96,f0a81588,b68db767,9b9641f5), -S(b92cace4,e31dc724,3b3530b1,f90de1c3,47cc39e5,5b247455,a1296912,4e3c2a09,78f89163,c735cb13,b1d8fe7e,547027f,68d8f864,a1f093b,22c0d9cb,95fe28c2), -S(8f7ed1f1,77238a68,bbe32e4d,ae6d67fd,be07c9a2,9fc6b940,6ef81a77,65a8fb75,98e627d8,d32095bd,5913daa5,920c5c60,334691be,537b08d6,da5b8c19,7bf81c8f), -S(47fa27ac,e035176f,34c59581,8d3dca2c,a2b40e53,29756c55,7cf81f75,4f99316a,ddee5921,f381ce26,3634a34d,1b4f9513,4d9f0e50,5e96bb79,b87d98b5,282aee7c), -S(7584cb68,60ae81f2,e0df701c,97d7aa29,8132cb96,fee4ad59,15424bec,2e280dcd,4b76458b,e3926b5b,bf59ad77,da4a96c9,1f9147bd,88a234c0,74b0e09c,a6993228), -S(2cd4c11e,70d432ff,38550aca,481667f4,d09ad11f,9aed62d4,968492d7,5de28dae,82514708,3e5bf46,341177e8,9ad2cfb3,a215578c,52f9436,d3952432,e9acd430), -S(2b524c99,2b18a6e0,30863716,362d236d,e385a10c,3679eec,2774edb7,a1a89be9,1abb3b28,3477769a,5c7b4580,93efb22e,f2e61296,da90d4d3,1d6b2ff9,1766f89d), -S(d642c258,9d0e47ef,f5b2b60d,9321db58,727315ad,522daf58,3bdf35d3,336f1081,1019505a,994030be,484e5340,abea0b7a,51276c99,29cd1f1b,9d19798d,aaacf3d9), -S(3e5e09b,451bcf5d,549f1d66,b96da0ea,25e63270,dae59606,bfc3165b,f89f29fd,2ce591f5,32d57be6,4fc48aa4,ba40231d,9c104615,b76ed6bf,11957694,16d2f0e9), -S(4756965b,82fc23bf,64041d23,a23cba32,cb71d3e7,ef3e6c03,51b20f3f,dec049b6,75f3a293,eae07f4,362c47e9,44a78561,323244ac,bcecef0c,6ba2f5fe,d1933679), -S(f296e9c1,41694ce2,c197ba85,bb9f172,54fc0bc7,f89347,a0e92b8,58491a39,73c7fbdd,91c88ce2,bbcadaae,df8880f6,aff07e8d,3a1ce05,a468e3c2,3008d98d), -S(b437d387,ddae39cf,e26edc85,b0e600bc,2a199b6d,b521f9c9,88d921dd,7e6fc761,ce2111f4,d937905e,2af7f2dc,559f9eb8,bef286dd,909a5965,53c7f61c,f51aed18), -S(bacd4a38,f3e1b7b1,b601fa5a,2a579e87,459fd189,a607314,5a0dcfb6,1ad3c21b,8be8d6b3,9553648f,2a94754f,4c6c14,c4917296,aa9987f0,deeb7e66,d81c3777), -S(d8164748,8ac6bca,945fce70,e8f6a256,90512c8c,dd4c8fbf,b553c131,96f7f607,16b75474,65a80a67,86b5246f,e086d32c,4db03b83,58271938,41877c38,2b5bebed), -S(9c2b0749,cef57b4e,36b31328,e01503dd,ddbd2834,5cd86ca2,5224b967,1b7897d5,f020f978,4eed44cf,cc4aa33f,b2eb4b71,f24b5f3a,a8dc1d72,569bdefb,5f6276fc), -S(ea277814,9f0ab428,63b05bb1,c113ea7b,91afb815,e8f0791,12c11573,eb044e4d,8199dc4f,4e72b691,1c562ded,1220aec3,ab967029,139d30ac,58c753d2,f4548030), -S(4be6fcf8,40673659,5a9e4f2e,877ad7bf,28e25177,63d74238,6e43e6da,1c1c43fd,eb5456f3,d1c40592,2eec37ab,3e0d08da,b7cd257d,9babab02,44e5b2d6,a827a7cb), -S(3f1e9ab5,160733e2,9e7aeb6a,378d169f,9be5c266,a6462e2d,e736be07,f88c1da1,907fa0b9,814da057,9bb11309,aab51902,a0699aad,9422e1f,b8f1a8c4,aa9d4399), -S(eb730dbb,1ba9b2f,50453837,35ec6da2,ac4b5019,86cf03f0,3f5061e2,a28285f9,41dc3a0f,f42fb1b5,d3b464a5,6e305fe5,c60c4561,d6e5a6a7,8cba87ce,15c392fa), -S(aeac891d,f7032059,54d0bab7,41927702,1a595a4c,37bfc34c,5d315876,3e85f3ce,168f8260,1331b5c5,edf941d9,9f1cfe0b,72fd2a1c,3e4bbc2c,c62d47e6,6399105d), -S(667e04e6,daca6315,4888ac26,a268876a,f4b754fb,87687ca7,3c4cff77,d6dac204,1826a26a,cdca828,8e2ac81b,855a4d40,86f3009b,162fba82,83cb1d17,b9f7aa4c), -S(240ec754,24e46326,8e2e4ce0,240f335c,78c46150,1e18cedc,b32e3c51,77ade3e5,be09c744,cf6e9c6a,75976c03,530329af,5e11e5ed,3fb13e8c,af40bc5f,95872645), -S(7b83e4b7,70e7a442,3efbb501,c23881c5,2bbde4b9,d5aacc38,7071decf,79690025,d242ed74,441d1ae6,61b97c83,70be2f52,dcbc2831,1e8707e0,1b44c827,420dcd45), -S(63589c41,fa8975f4,c8738f57,579cc0d8,447218c,69da1a34,ee06af0c,215f6c27,c34f2ede,7589760b,80dbae48,94a3c13c,7351bf5c,33a35351,9988ba67,c2a56d48), -S(db092b0f,4638ee45,190473c7,cb60cfec,45c94d96,99aaf289,82d28af,16ba1c66,8a96ecdf,29ad2fd6,3a85a7fc,b73ab6d7,719bbd6b,98d052b3,3a0cd91,ab924f46), -S(11c4dd8d,3eddc0cd,9a832dd2,dc91c8bd,491fdb51,f5da21c5,732dfb7a,362b8df9,ba4c2789,740b53d5,51bc9fbc,776f049b,e848182d,9d13abb7,e7cd860,96911eff), -S(a65a3a01,df3b5ef2,e620d431,49fbe1,4d71457f,19d1ed35,aea39d57,89303fdd,86715f6b,f300a390,470bc272,6f12d389,7979e2fd,b0512c35,252bb571,fd19752c)}, -{S(d8558716,b7033a9b,29afb346,fd71663a,79b6e86,2719bf12,6e532dc3,f581b7d,a790d460,1e5b2630,1ad6ec43,62f79120,d75449d,8a500e2e,6f17c021,8037a405), -S(842c01b3,54353026,c43dedc7,8829ead1,db35b63d,8c4d0d36,8cd7b661,2eb5e11,f173cab1,a37ee0d0,68e097af,17bf859c,13bb4823,255abddb,f0dbeffc,573e06e7), -S(acac5cae,414c3556,38e293fa,e7cda051,18924e9d,abb81bdd,29123768,c7f21443,5d17b909,5b997254,5f56770c,dcb8af40,e37e1a8b,6e01a989,34ec22fb,f7d04537), -S(c8e73810,c024c6eb,d5398bda,3784261e,542279e5,3438d49e,83b2639f,80889aea,7a2183e7,be4f81,b0337993,935657c4,c55d20df,729d2e8d,b25af238,f3d85f4b), -S(f78c5f53,5e7ccb53,555a6f2c,b1de1c5f,da379360,f6a7fc52,eaf86ecb,dbb3bf90,cf2d33f5,eab2ee1d,5a32eea3,18f9927b,cc982fed,cc9add2e,2461ba14,9def0292), -S(4cd40c43,bdb8a042,2babc95d,eb00a405,59519074,5906a8b7,b5ea00da,b7f995f5,a0bd1c74,79125d2f,5baec520,21fb7c62,415817f7,2afb80,b2315dda,40cf4c4b), -S(647c5950,f8a7fe9,e6945b3d,6da91932,b486a4fb,ed903836,9fbc20f9,a849ac08,d331cf32,d72e148,b47af547,6794a33d,55f49ffb,be47db02,7d2de73c,542bbbc5), -S(97664e78,980a49f0,8269ff19,649e86cd,7da88a76,eb1441d8,a5f3fd2a,6ea335d2,b2898268,9a8cd91b,b1b16be8,ee46b4bc,252f7016,f72432c0,431f1264,8d7450a7), -S(523f68b,b39c2ded,81d22a4e,575483ee,d8748c9f,52c06081,391c27d7,7afe3805,5c331672,4464dc47,cc9cfe32,864b6095,ee8bd6a8,42c1af98,b3e33183,a46e2471), -S(cad866de,5cbf4938,989b835d,5aed958,cd7c316b,980b7c76,2109d688,d7ef5b25,3ae79c30,e77d6d4e,fe404b8f,324179c2,f677f434,8a1c4367,2a0fb5eb,b706607a), -S(ba065cef,b47170a,d6796033,d157fd1c,f22052d0,7b7f9992,6cd58e03,316f95a5,26177c08,bc535702,7f5d03a4,9d982637,d74a6b20,696be76e,742243be,b9ecddca), -S(27ca8178,be756f12,22cebe6c,d05310d8,5a6c4f59,eec71613,7777b625,e6d44c97,de547a17,ddee9fc5,1fecee01,45f9cda1,b65f097,5d1b9544,aa2317f5,102537cb), -S(bfab1d94,d04f4909,dee00998,78f77cc7,d9de94a7,96b5b770,5f3c759d,2ae97ec1,6ec39a8d,9e900a79,b8b88098,d1e5d79d,b75ef91,e442cb2f,27ea531a,2db21bb9), -S(b48a4f25,9d82242,59f08a08,29b05ac8,ae6b97b5,56cccb84,20a479f5,df92701e,beef137f,9f9acdc,8d31a780,2290fe79,9d9470a7,3c8a01a,35abcbee,9730d17a), -S(e3f5d307,ed2f2f13,d23ae5b5,9dd567f0,8161996,776d506f,b53e14f2,70a52370,40ecc697,7da3771f,32a66438,cf70ea9e,550194be,1af85a08,c8a4515d,32365803), -S(818b0462,d5a815b1,57216ab2,4d795886,17cc99bb,7a7abd91,655cacb7,ba99335e,c6ad05a6,7d2a391,a15b6600,7716e02c,9fe40db2,f82283ef,c9c0a7d5,ebe854f4), -S(7e3c52ed,23220b73,ba47613a,bf39a9fb,b3a6bb6e,22c972a9,3ef21a61,50cdf830,b3e4a95b,875719b3,bec1b113,9e29670d,4ba8f39a,2fb76700,f69961fc,bd01fa2c), -S(594e4129,9c1a117e,ce8564bf,ba88ce04,297f2e14,7ecda07c,5f12913c,14d9a5cc,60bd54c8,7395fee2,7fedccfb,ca9524a9,b5750b2d,d712621d,e73e0692,46c2e347), -S(3686bf4c,f387e340,6fc314e,f02c637,ee6f5062,ee9bb567,235b00e6,4d516648,915e5904,b106e057,a0db43,151ac9f8,4871e843,126d5285,337dc3b4,52c67165), -S(338dbd1f,42480753,516d3cb2,c535492b,72849870,a7828b48,643dc143,b966ea61,e51f11ec,86104334,9e9dae17,78116032,949c66c5,3c4d441d,3c88cf4,c7ad61c9), -S(56f935ae,f58bb403,7649198d,1a5da704,26fd944e,c5694c18,38c94287,2130215e,a9c48fd0,3b059474,e528016f,9c998e02,cac7c40b,8c859852,b58b9082,b638222b), -S(1faadcd3,da472591,cc723754,82546c81,c4f53c14,d0d8dc5e,ab95a58f,379e6899,5bdcc45f,42d0ba3f,783a0806,a5d08c74,a1b1b9f5,a559248a,8681b153,74e74958), -S(532d8cd8,fdf838c7,70b87ca1,4703a884,116dd928,74acc660,6ddddd61,8eb053e8,67a31325,853db4d,3e5877b1,c76e7e39,468d2d77,37cb8a6d,af4f16b8,17cd8ad8), -S(8a8cbfd6,d45e5740,aa9f0a21,f40e3671,ef897fe,bf2bf753,ee2d2f75,844ab648,d00eed6,efefa26,46c36895,3a54045d,96da4cce,8ffc554b,9bc989ac,2f62acaf), -S(38ae095a,3c705343,38e542ff,6789902b,cc1b0b5,7763cc43,2f50cd9a,d26d0f1f,100de239,87026f09,e483839c,fe9e1f10,11bcfafa,662a9331,95a8e4ec,e4fc804c), -S(82d9e5a8,385de1f4,fa541796,a00533d9,a3aa4656,74583d07,c4b3c344,b6ff8cb6,70bf2bd3,5765165b,a466171e,f26439e8,f790e178,f67ef5,d2e15e98,435b4261), -S(1843988b,42ddec86,dcc6c9ab,36b381ad,a0ca745e,aba36bf0,237e2830,579aaafb,f1bdc95c,d76337e,cb3cfd65,d9c30b7a,e7c7d667,65c9db5a,6130edf5,e240cec4), -S(a32f7415,9c2743c7,2ef192bf,4a68e838,97a86a0a,3997d1ce,fda3c581,b4fbe683,8862903b,db791be1,dbab5031,ca57f161,b6449bcc,db061438,f45e610d,50ff3bef), -S(b09dcc04,d9c30c35,2bd63880,a766da1,f6314287,dc201bbf,9605516,3db2a09,7580cf9b,7e30dbf2,8f72e9c,a5152ff1,956ae42b,3e952b18,512824c4,7f4e5b9c), -S(ca07cbfb,b24ad1a5,edd9a12a,8ac54157,6f3f2ba1,4b878d82,ab7dc996,bd7e2c95,5123ceef,cd20f120,b575dd98,43ef9936,c53cf90c,c481f340,fa166452,72af1c8d), -S(f8058324,c6b9c2e7,e62147e9,a41ad78d,60e3ecf4,17524c05,80832add,f11349e2,6a39f1a5,f577a932,3217e559,f15eeddc,af6b674a,9d921772,a053b960,a4dfd633), -S(2e3c0532,6255d80f,a42fc69,d5c92aa4,cd326a5,3e8535f0,435efb7b,694a09ec,ffe0076e,9a93904a,42251dbf,47d03e54,1fb75ac3,8f8499ae,dacb797d,7738c9b1)}, -{S(7bd8469f,80f009fa,b4960cdc,bbfbd4ad,d8e37bb,a4b2a34e,d5c95d17,7a94c207,f3062154,c3bcc160,b2aee99,aac98446,516a277d,85b37fe9,34be9359,4af905c6), -S(139b7c10,ce844844,f5d0a9db,bd7e1679,17b37e93,9bb6fd2b,4f19643,f22a6af1,32d4e929,27f5951b,ffa4ddde,4b091ec8,531a6f23,f1772c9d,ada292db,2b88c1da), -S(f49cdd14,14b38e5a,2dd34bff,3d01e1cf,ddefb954,2a641edb,df698d83,774ee70,5c10a6d9,200253e4,a932a42d,2e770f18,69d0336f,3c44f480,ce4a3305,83050c31), -S(ee145304,4771c862,745f03b,4776ade3,104ea0cf,eda8710a,5fa108eb,1e946826,b91f14,b6127808,f1175b72,2c09e02c,66eae622,109f4156,261d65ff,506b88bd), -S(c9ebbdda,867f333d,39142483,2e4150a8,c98090ec,d8ba9c09,3673330a,8777d790,c46d72c6,6028477c,e4754960,d40bd10b,b2defc1a,17dbf018,538b71b2,d208372b), -S(707bf0e3,9f2c8c6c,73a5d0d3,3edb32e3,46e73ac5,dbeef6c,60fb5ebe,b95ece24,adc6edbe,151bcb7c,2ed5fab,1cb9b2de,3ba2f3c5,ca762082,902582cd,e9e27f54), -S(4a002722,9fda7d33,320fc533,27b6c9cb,88a09c2d,e95aad01,65f68f45,1c82e2a9,233416cf,1cc1ee38,90816a09,17c5fd0d,da0bb8f5,d33c709f,6f1b07b9,916282e0), -S(8efefe27,b45a4cc0,3088b6e2,2a0baeb0,3e772763,58af3217,f39c7222,1e20b59a,b9f3fcdf,65771acf,cc7b7486,9b10bc3f,b0e8fb2,960cad82,24ea2430,fdad1634), -S(7bd3815d,6779f321,195047a5,b1772b19,ab29a99f,cc082e93,c442e927,b1ddb235,eeeb4bb7,480f3dd0,92e627a,a042533d,a9eb598a,6cd1ed9,2d75aa89,a592ae8f), -S(883f939b,6bc9169a,3860d36,9894c4b5,2863b5d8,d0348c4c,62368a94,737fc3cb,96e37629,c05b7231,8800ad96,8e922f7e,5b8a2c39,62a25210,9b3e4949,4b24934f), -S(4ad8cfb8,e8ba3265,4d32a656,76822176,95c40b92,e97c6d3b,af26449e,149f4b3c,491d3eda,89930ffe,e401b994,54919947,7ef33a8d,6cfdfb9,eb28295a,c5ce94fa), -S(ff15cd1a,4b185632,c6f11ee7,19319bd3,abce5167,65539608,b1ee3a4e,1671369,24df322b,ab157296,40aeb039,c00ab8,91c96833,4142f87a,1e00d105,b08c63a2), -S(3fc8e63e,995fda97,1d09d96d,4c84e18c,3e0f4d6a,9f8bca41,20c7c832,c4e9d49b,e17b239d,8e6f7fe7,3c4e46d,3aef9040,6bd631f2,da1677c8,db698484,85922ae0), -S(d88b3d3,6bfe995e,45812e9f,63e8b6e7,d5a87562,1c4a23b7,ab46f6ad,2f7d1e81,63079694,7c97b00e,311bfdb6,198c2c4e,eda57d09,b17fd74f,7140b40e,d2842d06), -S(da6971d1,4c0e9c37,e5b1379b,9cedd83e,218ba47,95e4af56,7956922,c64750cc,a14a0bd1,ebd0727a,258c1246,3aaff478,fcb490f0,53d08a40,44cedc97,61be43fa), -S(d098ccf,e2fee442,74377e1c,57d0b924,45f0954f,7af643d8,b7ed5d9e,956fba23,85c99754,17df24ef,2786621b,c0be5069,a9c59da1,61e14759,ee26b524,e9587d18), -S(633f9b18,9dd98f3d,8c4de,528f7170,1c9d5972,cabe3219,cc4e5f0e,e7e094e0,3d69c877,28c859e5,d9e8ea27,3c04ec98,ca084df5,d7c9cb34,9fa537ad,f7da0b5e), -S(2e14be9,af0dda46,8d59df19,9ac9edb0,c875f829,5715cdda,5ba3bed5,d54fcab2,a04688b,64c5d34c,752396d7,f864a9e1,59eea9aa,db8c93c1,5b4d7cd2,539bfa0), -S(adc92567,7678b197,1e45ed31,38a991dd,a4cd3586,a1ce1498,3ea30be0,642a2dbf,70f2c69b,7e47aa55,cab6ab22,e6482571,e8e1ea52,a52df934,d5ab99d9,acce2770), -S(ab89aaff,b04be186,183e8076,46c64111,476c552d,10df84ba,10a1efdb,32c01162,fccc1e20,17ac63a4,b9f78ca5,af245a74,4174c952,cfe29491,11ce1d71,e4be8f87), -S(1195576c,ca3a49b9,4db3f827,1ff2308e,66b66739,a30d73cd,e8acda4,a382002c,6a2be3a1,c6ae9f0d,b314a7d4,728977f2,17e7c7d0,199868fb,c7f79d31,6cd7d32), -S(8a15bed9,bfa215f5,42c62c89,da0adb8,c68cbc33,d9c879d7,a2f2803,b7068556,ef437bc1,1786cd73,6dc321d0,a3360517,3e7572f5,bce04b7a,3c8cdb85,cb56e697), -S(b4521d6d,f9b20080,4d3799ca,4cdc87bc,ea970d60,a3005071,e910210f,5654da88,c4ddf348,2a23e98f,b86ab9e8,4decc6b6,ad18d879,e96435d7,4b944d8c,f7cc1587), -S(4074523e,b75634f7,6442c3bf,ed9a52d4,5f6636f0,77a10e84,5e6ed950,b673a9ea,d8889a02,ec95b511,aa74db1a,10c91547,45b89b57,981011a0,9d4ce57b,e4e1f032), -S(b2e71794,e6ac98d1,ce532974,df79215e,bed8c668,561dc391,505e9e26,8444a858,94d8ff19,b8a74599,fbe5f471,e7f3e1ff,e0238cc9,2504f99a,9c4f5fbc,2e482854), -S(2e672209,8a6b4ca3,905a8910,6d23daf5,aeee63e4,34e7bade,70395df0,e5a1af87,708e9fd2,a3c0a3b1,b0e03f96,c3d477d2,abf6dc0c,bb8a7181,ca4b18db,ed12e3f7), -S(7ec0fbda,63fe7404,438e36,d567d9b0,bdf18b09,d929329b,24a8bc91,816fd433,f80ab84a,99d214fa,5d288e3b,c2b5560f,a1791412,9c3d16ff,cabed23,736e4f85), -S(f166252a,34572146,8bf3a3d7,bdd2c67c,b0d36b02,d7a70033,add26f97,128b1637,134eea4a,42b482c7,ad625407,bb89a615,656e3a2d,232f4bbb,a33660b2,403d6f63), -S(7af860e0,27d3b1df,aa0244e2,51f9459e,488afbce,6a3aa610,e5e223b7,81ba2d93,6ad22116,415c668,7dd3f4f7,b5a00599,bd35705,951e1093,3f85f815,4d0c8af7), -S(e4ad03b7,e01c5d04,7030fe59,6e7e7960,77d9847a,e604d2c1,d801a5eb,e21c0731,c7757ea8,f57af58f,b64f3eb9,c7762bc9,544f28d,a80d760f,c46b0c9,589019e8), -S(ffb2f941,f27aa8ad,6a59ed01,24e83bb,d49f2588,a5602389,15329f6d,f77220dc,6812c00,7dd44185,fc3f0687,6f7a62d0,d31adc40,c0a1a060,c67df13b,e4cd4873), -S(42ca15ab,9f245041,ce991e19,3d696f4f,4c277df9,8cad603,8ad0772c,2da6e03,972d10d9,37e3a836,9b831b2e,347ff11,29917a59,7ef94158,7c977604,73cb849c)}, -{S(576abbcb,8b768480,882aefc,81380709,831625a4,b9de63a7,b9c3390b,9cb4c7fe,b49453e4,6e17bbae,2f1f8f9b,91c3ed04,80d5f194,33917cbb,d28b878,bc6e6c4e), -S(f9d8a157,c151181,3e085c1d,ef2958fb,df2a17b2,6b330a0b,2d512c87,69e5c14,7eacca29,26aa402f,f8b78d57,f5e02add,91087da9,d607bb41,b56a40f8,f7b19b78), -S(d31dff73,7d2d3422,7fe39dee,b2eb4bcf,dc84bd39,d6cfc4ea,ff09812,23400a80,4af55e8a,fe8e8ab1,2e2c4463,d41824df,7b53e44d,efd946ad,b6128214,4244055d), -S(9ff2bce8,a9fe6c7e,e68a8292,f0d2f4c4,8d963c47,63018a55,89a2c130,667bc861,eb138923,94aadfc9,6eca7c5,78c0fcc,bb31a40f,98d02e93,a140abd3,cdf041b3), -S(1397cd8b,aed3c601,b6eee616,243a61dc,fead22fa,da50db4c,1f9e2776,6e5bc9da,534a8e23,59316503,cae233f0,3b6ef0bf,1c7e0105,119d1a49,ee688f04,40695c66), -S(4ee38986,511024ab,5385f710,42bc3778,7cbedd0a,ad13ba24,b77f42c8,2ae935d6,cf87468,24a38404,f313965,a64c927e,4ba0b7e0,140f6b36,47e2049e,35a74e4f), -S(7614cd7f,9b5f1455,74d0d38a,370f69ca,f3050297,10af5242,e5ccf19b,187dd189,b946eded,e4b72db1,6dad876e,396e836a,875d7c9a,28a9c739,f665c741,29ab7648), -S(67fd2372,5bfb445e,5254bc42,f7dbc1a1,65bd4017,cd1019b0,8a3f96cb,7b3c7cec,b556e950,a144febd,a81dd3f2,f729ecb,fe43fc78,8658bb7d,2b9735d7,b06a920a), -S(57572b1f,1f17070e,e9b30b6b,c7168cb2,4741ec5a,b3496b1a,c06ec0f2,5f910fce,8cfe2940,3dc97084,7ab28da7,167e78fe,f2310c83,ca476a97,91ca35a9,610bc560), -S(1f111332,1e31a294,cab4df73,5a0ef333,e753c2f,7c83705c,9a5bf27,1321c4f8,8fed26de,202c92dc,5b51b13b,6e9bae41,3c7c88d7,b858dd72,a11f073b,e2945f9b), -S(23c9e313,b04eebff,15fb0625,43de6975,d19decf6,6416f4d1,855083bb,d738f882,90673370,f380ca49,e876d5f4,b6649de0,24f4454,29cf9d91,96f4f196,8a49ed99), -S(b9251407,6ef7f01e,379aafe8,8f22c156,65a85ead,f671d8c9,89602c5f,804725e7,b3a9409f,7bf973b4,aebe08e1,5ac65562,56983f89,23415e0d,eeda4f4a,c0d7c5f2), -S(1bf9deee,948b3fe1,b4345800,51c67266,8fdb7af2,99275a83,706f9716,7e38e38a,688fc563,771b7d27,f9c09953,c40cf009,a55d7329,5fae0b7d,8fc37710,729a3911), -S(34e20de5,9d00dd45,19a70b3f,2994fc4,588ca9b2,beaf6afe,4a1daae2,10692f33,7804aff0,a43f1ba0,438c05ff,8d013e3b,e5180bb7,3a969825,fc97ef52,6da1b6a8), -S(80fc119e,85e88b0c,8c84d23f,9e44e96,1c7722d8,51d4c9bf,f1824fb3,365823ef,efee941a,a60743a,28b6ffd,39762f9e,437d2b00,206e718,7fc423bf,4eff0caa), -S(89ab0f45,e3860393,f24b1845,7578fe79,b812926a,6bff3788,c8baf283,89fdbf0e,57d4fc21,42bf446f,8e4d9331,659e7673,90391fe6,62e77ee7,f7a4886c,8f440c8d), -S(1f092931,664bb98b,79d8fb4c,efb287a0,f72641fb,1cebe711,820c92e0,42f26437,59f63ca0,b8e2e959,a97b1c1d,1cfa4c02,380dc42f,db7cb5b0,995ceba1,d7e45d94), -S(95ac9f36,f447928f,344eb4e1,9ea806,717600e5,148ad222,fdd52a83,86bc3537,cdef5355,e928b1e8,225b5a53,bb976822,6fb50d1f,6c6cde20,758d5ab0,e9f28543), -S(a9ce5ddd,9941ea69,1343ea71,c85fcd73,6269826d,6eda5008,44cdd1b9,4a66044d,29504563,1fcb7590,27d904c5,4ffc325,2ce3c8a2,169f4649,907db751,2ef3ce43), -S(2edf81,45c4bcf9,62425707,ccb36a3e,7fa1fadb,4062d14d,f78771eb,f3ec15d9,dcfc961c,547548f2,73206d9e,aa0d829,a235f66c,5afbba92,68fdf9e6,abc8260b), -S(fcf5b985,c935e207,92907b93,e9976ceb,ed320a14,3cf286ad,b38540ad,b4077dee,8a0e0b4d,1ab114b1,caf7d0d,f749f219,b75acea5,6a71b3f6,aa18557b,1da85262), -S(2bd4391f,42b70803,2baf4816,54569f48,95f1434e,be6f146d,41447f45,f14581b3,dbc9937a,61f43af7,42635810,5cdfa02c,49a5186,ce67bbbd,7ced2842,19a37506), -S(eb00deae,6cf69ccb,abe6b93e,e5493e05,d22e53c1,b069a6c,4660330a,4e3bc069,18002f2f,61b08dbb,60c784b8,4c6d71d4,6b004e6a,3089a0d5,f853d659,83242d9b), -S(c7c62a5f,ce15326f,25b2fc5b,697cc7f7,26d231e9,e7e9f15f,5998b8b0,10605524,8ad4b370,ea0506f6,f25eb16a,78f87ef2,f408cd17,fa4ec63d,4ee21448,1d5286b7), -S(aa1c2baf,632673de,6f6704aa,5a76c077,be0c24b5,223de654,88d1386f,15a1a002,de4648e4,fda7db79,41efc5e8,6fec516b,c6aef164,62d6dc08,fe93ebc7,a85261f5), -S(11871161,13c3c670,e7f5366,edd22282,1f76ec98,d1a3500d,f0e483d1,e53f2666,d0042c9e,8dc1d72c,f53836f3,2c76b5b6,52fd5ec1,9e8fde42,aed1a7e0,9d242745), -S(e232a92c,9ffdabcf,24422182,34078534,6b6b79f5,983ddd57,2580c3df,e4ee4118,6c1144c7,471342d8,7a784fe1,587ef576,483f8980,bbab12f9,35aa0d84,83c1d76d), -S(1ab6237,3998ded,e50aec45,8043f830,8a7b4564,2dd3c9bb,4804f98e,a7c2e0c9,5528e158,6a23aec9,81f04b51,b90576a9,a9e7feb5,53200e51,e604898f,e55996f3), -S(3bc24bc9,cbc58de3,46644de9,b17ffa7,39a0f7d8,83eb9f52,af19eaf4,d8d52891,f71cf5b,7587c275,8014127b,f404b70b,b257bad7,f5b78d2e,c792e1d6,b2fa4493), -S(a2bf9afe,e6eec182,ef5866a,b4bdfe2e,9d045323,343aa422,8c1a13ae,fee515dd,a5ee438e,3aa35484,c5f5a1d5,43fa15d7,ff0d1c55,6571678b,a3c5694e,f93cfa1d), -S(a0b2b4f,ed0ddd23,8812806c,fccdfa9,7fb3b42a,748721ae,6477dc9b,18953133,325ee7d3,4a540d0,fc3e3935,79ba7372,905c7b17,4f12b456,b43db5c7,cb50ec66), -S(e7b9796b,5ca006d1,632f482d,7f0fe393,2cf16a5a,e104eea7,a7ea1c25,1073e879,ed476773,e6e961d0,20bdefd5,8c833e35,634a40da,1256750c,c718ef75,45575e97)}, -{S(a8565dfb,75f8eea8,ca9ca6e7,c7d18a5,bf3e437,5d1f4e87,68d5f51a,57199ac5,daa7d7c6,cb86b215,a682141f,2308d9b,4c204196,eb779f32,fcddf0a2,da194921), -S(974619cb,86016199,20f507ee,62d10295,44abdd66,456952a0,54e945bd,7890250f,6c8d8bc8,21da8234,1ffd0cf0,548be1dc,a1bb7e1f,47354dc8,3e5d96c8,2c9676f3), -S(24bbdc24,1396b6e1,75f23a6,4bfb41fe,f8329b80,d306586a,ecb69e41,2a2014b8,aa6448ec,f00a0710,27b46f09,d696642b,9274ce3a,11a3e986,e84536e3,7fd7b2f8), -S(eed9a6b4,68004486,e3bd388d,591d3b65,2f35a3f1,9401e5de,81a86f5e,b7cd972c,c81f9aaa,d7300671,b3dbdd73,a095c79a,d73ffbd5,9f845eed,9fe3a57f,a41e9468), -S(5260e0f6,fdc6858a,8d519d3f,6c71929e,36979b65,431a6f3a,a7507797,e54654e2,5af860e5,fbcf9676,bb00c329,d3e2e058,efc860e5,cb9006ad,224caa32,9fd49f07), -S(11e53f67,d844c511,b8118f28,de6ed9b8,66b70bf,214d4d1,ed79adfc,18f7d6bb,20dd984d,7b9eb626,77e411da,2e823045,685a4bc5,2a3f4e5a,3aedea95,1060b330), -S(98c9f3f6,81e220e6,d4bba711,fa8b212a,dcc21bc4,8219b813,eabdfac5,70e6fffe,bd0890be,d9cf4ec9,44f6abb1,56250329,a37d2cc4,64c931ba,8606c2ce,55127aa2), -S(f644f4f0,43d7713,ba4380d8,26ad0f3f,44106352,142fef13,7c6e05ce,5e9f1571,3192280b,f3971223,c00ed336,94779866,536020b6,79ba8cb5,c4f9c515,69d2f97d), -S(334ab869,32c4097c,8d8d8a23,d529b079,6a759d47,a907b047,548e735,5b3b766b,18f11736,d54c9d00,89149b07,35f5a9de,b15d9c,cde4ee06,155a4f3f,de98a7bb), -S(983542dc,61b43ee5,c4a7f36f,22da008e,832d4eac,6791d838,1a095d0e,6d8a14b5,cd225f2c,334d1ba9,94b0a681,d6be7696,16bfb2a2,426e9939,d2238cd4,43bebd02), -S(dbbac008,1b678270,4a0fcef0,73683822,a3d4107,d7f1a71b,41497da2,9cc942a0,cd25ef66,36f21a8b,532371ae,b91b67a,deea5797,983dc36f,54aed202,d9845515), -S(477949e6,9ed28a74,879bc8cc,660696cb,115e6392,5a63817b,60e5187f,1f77f3be,dd8ca490,fb8e3bc1,44f5fe9f,aa41ce73,56a1dce1,cc8e11c3,ca5725e,d1b764ae), -S(7616b9e8,b451d4e2,e4826586,9bfad6c8,ddbf5fd2,2342c6c8,42d6bbe0,398f94a2,4e3bb1a9,76efd345,3c4474ad,e6a494f6,4f97c6dc,c98cf68,72bca24b,dd9e946f), -S(b87fb86f,6ec4ad7d,5bec3bee,e8d68618,c8e4906d,1c584368,ec819f2f,871ca8c3,c64723c0,aa587911,4dda9c75,493f739b,e8c2221b,b2e75ee5,b25def54,a1d40c2f), -S(56ea4572,61a6ccfb,46fced99,1258b31e,8573a488,aa53b7ad,65333452,b06d41c4,d8529601,4145e12e,a72ae4d1,5ae6e5f6,9cc88ba1,4d79467a,3df3bfef,33d84290), -S(e4c6540a,19682e0d,e1f1258a,103037a0,af4df5ad,f27cbb7c,9e3ce67d,e23e13d8,a31e1b08,4bdb5728,36e53d93,1de035,c90b1efe,b5343b23,cac0e7a2,bf5b3868), -S(1902cf3b,90fae93,1855d758,24995b03,e1604861,199853c6,ece84903,c8bd67de,3b3d41e3,a2dd4c28,16d492c3,e6c53c83,e5203c7c,a8100d41,24cbdcd0,e12fe222), -S(6519f4d3,b5d731fe,eada6806,727623a4,daf924d9,b6337a51,56096ec4,16ab42d4,62e2c1ea,afa990bd,6dd91675,e3b2d1e2,acb2fee8,e56ec30b,eb25bdce,2d3ad30e), -S(e1128682,519b965e,a933f197,eb0997a0,16114459,4c0915cc,9c55ea4,a30c1ad1,cb1370ba,f8707c78,84817ee2,8227da3b,7b7c97c8,266af491,e0d52bc4,ea0f9614), -S(4366960c,6ff595d4,143d4cd4,f0f0df2d,3bf864d5,73790abc,23419c7d,6ed9201b,623faab8,2caebb5a,b4c42bf6,b2a686cd,4640cde1,a95a65a1,f8d32836,9e5ee0cb), -S(5acdf691,3c1e283,c1220355,6efd99c5,d347ef69,bda1d040,44cbf0d1,ae41b16a,1bca567a,71698c35,e35e031c,e8a98dd,e34270d1,4e2e2439,9276a7c3,6a1f35df), -S(807ecc04,81aae374,1efec46c,8c6c194b,faa0607c,cf5b7cda,fc270fb5,f5b416bd,cc60be6a,6736dd94,848fbb05,375f6459,d556866d,165a2c16,41984411,dda33fc3), -S(29c470bd,97737284,765adcaa,68a98af7,5e6c275f,fa4fcd5d,6c71d428,bd3bfd79,b19ab40f,33c15201,41fed31f,681f176,4a464373,23283677,a40b4018,99a6eec0), -S(41a6d6f9,40bb8abd,9e8748,dcfd23f0,5333eafc,4ce311a3,161440a6,619efabb,b2a3702e,900788cd,bf35204,27e0facd,b090804,62f65418,89a3c34f,ae2cc008), -S(d5f5096d,776ffdb,f694b9c5,c9a9ae0,ab5897ff,c5ca3320,82cb2a2b,8afcfe89,6461e24e,28560d11,336244da,2038e13,c69ed5,a7a435a6,d07a1d72,be43daa0), -S(f65a00d9,5707ce6c,6bd55e8b,4b0ef381,1eca65b2,9845433,d7b307e,518ea724,7ae079e,9aecabf0,4ec5210a,b85328f7,e60c8ff7,3deb037b,c8e6e1d3,34774734), -S(346cff42,23c9ed2d,a1082d46,eeaff341,f7866e72,d95561b9,678def2d,9f7cd187,f97f85d8,92002750,11efcc9e,f8ff58e4,894f105f,b94e7390,7e185806,575698b3), -S(d0e3cdff,a47417f3,86f64a2,4029e3fd,9bc7a464,6e839bf9,232a0d50,349ecaac,5bdbecfa,2a2b35d3,ce2e9837,222535c1,57ec5bda,5fd70186,1920803d,a279989e), -S(f6bbbd77,b8dba8fd,704a3f02,1bc418c0,f8524c49,ccfcd14d,fcbf7f04,c9a18d,38184001,f39b257b,6755a132,86bdfd92,1a8ff771,fdd5530d,48eb8227,ea70be1), -S(6717bbd0,f019990a,c01a2996,e34f0912,9bf60a3a,71d8124e,fd86c777,9cfad879,9581f790,a16825d8,f44f316f,db3f0bde,108643cc,b390bdc0,75f3dccb,6520029f), -S(417c765,ca91a120,2b07459e,3713d5e1,bbcdfa82,bbc26cc9,279fa2d2,59251fa2,8d281a2a,ed38a80a,cb697989,9839d7c5,265b4e78,8a9e1176,66cfb6fc,4143a935), -S(e2f349b0,f89c69bd,3c8cf2a4,10730dc5,8e0beed4,7048c58c,15f9ffc2,508d2cc2,e014d0d7,f07d8dc8,7e79f513,89fdea45,bdcbb417,1f63424c,81cb8426,1f2b3be0)}, -{S(aceb57c9,187a5202,118c4dbe,573906e1,646b0325,781c1352,574ed15,e02b87b,68ece7f4,4037ff05,d4b89120,d90f08c6,f0499fee,d4e9e02a,a2e68bcc,2d7b70a), -S(365e555e,de9130af,99f996b2,106229c,c36c1ea5,8b065cb5,38af3a5d,2cec1145,81fc523c,b4b97bd3,cccce1e1,d1980769,fbc25a9f,a403adba,8e7e8074,13c87f9c), -S(d0a3812c,b9244d7b,c1f5b652,adbb0df,22d15d41,b1724071,fd297d00,bc8cbb01,f8d7650e,fda2be30,24ded196,eb3baf7f,351d2013,2479640,16ee4c6,b469951), -S(8f4ce1e2,a51c0ebf,f5e34cb1,c6aedd87,85e415dc,e7307119,143bbe9a,3e7fc632,617009a,ee7d4d81,1ba2bf14,d1647911,bf1a3bbe,cba8dfda,9030ead3,803fc217), -S(ea23d837,54cb2e9f,9b884ef,f4d1a708,bc1826c6,59fea53b,f52c51b4,9fe0e21b,7e8c691b,cfc3b7e,56a7699c,4f56a11a,fca5710d,963d602b,b102e1c5,b36dc3f7), -S(e3c970b2,c764c9f4,ad8bdc15,cf995690,807f5d09,4a849787,9d278d18,eed6ceea,aad8c7d7,13ce5439,b9125d9e,c14b5d8a,1c694cfc,f84e6922,b7e58df1,4ab8a34), -S(8ade30a,94b236b9,9597be14,bd421130,b6843895,a85f3613,efcfa0ce,9781a96e,78e4bf57,974cfc0f,c310330e,6aa47de8,2b0f5009,5a703fa,50093d5b,a8e8f0ef), -S(fa5f1cd3,4427d71a,de7e79b2,b0a17ba9,66d05324,1f9996e,be8143c1,9186d24a,3481bd18,2319ddf8,f344e4b0,196b3ddb,10deef4,d8d75c0e,49fc5fe4,cbd6e1fc), -S(8b88b79e,8cd28dc8,58e3f1a6,155146b9,af1e3697,d57b7435,c649f6c3,bf8574ca,e736106c,8ffb9bf4,d83d79f2,4faf8fe2,ba5dc258,e4ae1b1b,b58a1a7e,4922c95b), -S(12078a5,5c46d721,96a148d2,fdf6505b,d059e423,c5d5295e,facc2b82,aec51f5d,66a4332d,cd265085,add9a141,2fae2562,17441d7,dd9596ad,46309a0d,bfb4e55e), -S(841523ef,29f5bffa,b31a526d,bf74b16b,fac3a3aa,391f7404,6675cba8,7808c171,7a3fc3f5,bac300b5,7ef843df,e334c995,cf66de11,2283fdfc,767cb57e,e7e7329c), -S(c8831ece,f4545c2b,387378b4,f88173d3,f1cc7db9,d064774d,60394f0a,ecaf5af6,f32f1a48,bb802757,34e66cbe,58a3ed3f,adf28dd9,374a42a,a824a095,6701322a), -S(30001ff3,7b1b1691,9a135a31,287e3a3d,383ef3ca,94748e33,a52c146,586dc4b9,9d71b25d,6fc35db7,26b58d1f,642dabb,46dfa64d,e0ec2a12,c53c414a,9dd2574b), -S(a17d3621,74d3c789,c4e00888,fd4b0f4e,ea3929cf,afea9e9f,7439901e,d6b0fe44,2bcf09ef,2d374194,510fc057,dc973fe1,bb687428,91e9056d,a5b4df7a,de79bf), -S(4725e2cb,19f95359,2da72565,d8405e09,92a64299,9ad74ed5,b41f5d24,44cb6b0f,be23fa82,7aec3121,7b90028d,b61d1092,764b2824,9f3fa0ef,91929db9,b2e0246b), -S(67c560dd,74c276c4,df3efbe3,b95dca4e,a56c4563,cc7ae225,ebea90e0,f5e212fa,2c9e3120,d52ef31d,7e9e36d6,eafbcdbf,ed8a28c6,7edefb94,1df7f38b,cb05c160), -S(8468da98,7b33b79b,e08da5fd,57cee298,ef86f624,3bb975da,2f4261e8,f7531d92,455d8a8e,b4f45693,2e8b6f77,ddefe070,591dd37f,d6ad3a27,5774055b,8a63e650), -S(3416d4bb,78de7570,b1e9e912,83a3e8fc,be6524d7,4463dee6,82e84e52,72c0953c,94e55458,2c17fffd,321364c9,16658093,986b56,f88b4818,129e19c8,ce685dcc), -S(5c66928c,a39a6e22,672c1dba,8bb6331b,41a7f43c,a72276a6,afd3e209,6416a9c5,181cdfc4,15e7d6a3,c24be94b,7fe328cc,ab624c0d,dfabb1b8,f9a73b56,cdfe1b28), -S(971f7a13,210680a3,ff6a12ad,17481a63,ef624d0c,e4121166,7e63aaf7,9cafce,5de2fd1b,3149e321,2980c7d,88a49018,26f83f18,7438061e,9bdb8d33,6a4b08f6), -S(650277a7,9ae7682d,c5f3526b,8411342e,b48277a4,9876caa7,61ec6815,9a1f13c3,a903255,fcf09808,cd97d92a,26dbd2e4,7a29571f,ae91107a,7cb6f0cc,3aea1985), -S(76a79cc9,7fb80ab3,e8d31e5a,d11f5ce4,74696d23,f1ee7aab,3928848b,556f483e,1779bc5d,c763d1ef,7611b402,4583f07d,c7dc9c96,7afcf83f,e6b6ee42,da75972e), -S(6e0b4015,474fe250,d372400f,13efa0b,70c4e8df,816c0e8b,8d27a7,a8168d54,f01dafc8,8178dcf7,15f8fcc2,e7163137,9e1dd4cb,6c88cfbd,e9a051f,ad204c3f), -S(ee5dd472,b5efeba9,d0e354dc,21228d22,40a69088,842d00dd,6b6358e4,309d1f5b,bce93ac,3fd4a098,9e74448f,5832643a,a2a172f2,eff1e2c6,c61ea99,cc6e7cdc), -S(df99a925,ef2e9f9e,57208fe6,5373ff94,876b1448,368dd453,436c59d0,f2a857e2,88dcfe81,4397f990,56f92a27,143c902a,2a6a66f7,f7e9652e,e0b16f13,33252a1e), -S(9186f095,43dc64db,ad582561,cab96a38,89be54ad,e1cdb27d,674af836,22b5d284,71ae31d5,a73b29f,54af1aa3,2d8e541b,14f7cebc,9279ac26,c846d466,aa975e20), -S(645da454,63357bfb,61b5b932,1897a73b,87af6077,81487bc8,af1a66ba,49bc5e37,4b925aab,aa7bbc19,5963025e,f1896cb5,b6463242,cd8a35f3,b1b404b0,7faf8e94), -S(5cd9a6c4,e9d372db,90a65f11,1f1a1b5,f28bc3b8,3d05f599,39979c91,5277eab1,c147420f,7dfc4ef4,d7d1f08c,1c523771,86a8d7a7,10cd7017,82b97c55,63287aa8), -S(4fd699b1,2c720ccd,7b977e5b,dc622671,18ac3028,bd635b26,fce648cf,335cacbb,3936f10c,aee5f51,26b86240,3249e1d3,5566714d,17ddc19e,cc4d1056,71e523f6), -S(b3fa0545,83510d6b,91226711,4bac7f4,ba4ae5fb,baad7230,3003efcc,4c3c18e1,57a3db8a,6cbf0a94,845e7d67,f9b01902,55aa5b66,ef31abd,34ee0410,ed55d0e0), -S(fd73c052,b194c6c6,dd46aca9,d640981a,ec796009,17a565eb,e77fd534,649a2115,9df8973e,37e877bb,fdf5454f,d9082926,fb09fea9,d162bde0,fb635483,59458f55), -S(2982dbbc,5f366c9f,78e29ebb,ecb1bb22,3deb5c4e,e638b458,3bd3a9af,3149f8ef,59e4a416,5099ddf5,4605acc6,384a4362,f6a2466b,ed1c127b,a918d94e,e93859e7)}, -{S(8aff982a,fbe09f67,6d6e0f49,e2b68f88,8f20dd2e,6387b420,8157ab24,d19027ed,f2350ea9,d00fd861,41259f03,b51b5326,6ce05a34,74508bd4,31ca74e1,366eaf92), -S(27ff285b,1e14961d,a042bd31,56aa44af,5e73717d,fa413a47,b300f358,e1960dd0,8b578851,264a8fea,2e29bbcb,cb9c90e4,93e8c731,983f4bba,65381e88,bc83a8a7), -S(fc6acf61,4a214859,1418ab5e,e0f0274a,309a8248,2cf01f73,db8a9790,825486df,190b9c0d,46953d99,c9de2bdc,bcc15d23,ee90485c,c4c152d8,e28322e5,4c927d54), -S(743bcc6,ac86b0be,a25cce81,1fdcfc13,73f23926,e3116fc8,9415b8c0,4c1983ac,f3df10fd,4afbd3b2,dc0678c9,102150e6,3d005680,6a5e45fe,c95ea495,9f2b8555), -S(bb165428,2c13362b,b1e017e6,6402613e,f82bbe22,9429f29c,6a1a522e,4956d67c,ec542c4f,7fbf3c6c,32e71aaa,86e3e4e7,e52b0d43,98589e15,1f17417a,40b31b07), -S(b3f74ed2,5a7fd474,5820a2f6,221349aa,e41af762,25c2b706,160a463d,1d59e7bc,a9af9d2d,89dcdfe0,21ca46e8,5f09bdb5,197c8f23,bc56d705,851974da,1608dad2), -S(20c0914e,f88902a8,6af0ff68,a08f96ea,25f15ea6,b1128900,120028a1,1049a77a,339567f2,71a1f1c7,16eb1d56,2f009537,68ff4cd3,9a81c6d9,6359d2f5,5d04db9c), -S(a3555aea,2e96f05,d25a145e,4ad0d2f7,fb453974,8c4a3097,a703c0f5,404a0e7a,ee236b76,8fa04380,b0448beb,d2589665,e43299ee,b9fc78fe,5a64db69,ac92b7df), -S(37191a66,1d2a7bd,c96a0767,ce47d97d,7acfb8c0,ce251e9a,1421e2d6,29230c2b,57093393,4783afd7,2df6524e,871c8e67,ff2f48c9,c73e2054,fb219cf,d3c2a68c), -S(1a2f5b6c,5fbe300,8b01407a,b0b28c3d,c823cca9,b4c71a1e,4fc814f1,e186e062,b2f1c632,a9d92a4c,82d31a55,f4fd50bd,d53ee99a,2e1452a4,e43e5ac4,b8cbb7c6), -S(2976575c,c5e70e47,cd9c10e1,32a593dd,12b65215,38613cb7,22390022,73fb41d0,c3f0b08d,a2a3a046,d87dcb13,38c35824,1a8b9959,e2567543,852dcf73,c4f5cba2), -S(bca28e75,5cd6ab74,85884b30,ef399f,44188695,fe9c4143,6016bdec,25d502f7,b67538d4,a571e935,cbefe237,c5a01f77,4ade337c,fec9f95f,3e9cf042,f0dbab6c), -S(3dfe1718,beafee83,b858048d,25d46ee6,7741d3bc,bec1e52d,3ce308cf,738b715,8499a8b3,a0c7c599,f62f056a,a8364494,ec6e0198,2c47bbf8,7e2df591,de0ff537), -S(bde6252e,a9e4823f,36bd1737,ce188fae,be4a271,9984c9e6,76f9f4ff,d070c1c1,2e5db82d,e02a1fe1,39d903,7e7adeef,12d40366,de0eb164,c04b2ef4,b1e849b6), -S(2c74b766,eebac93c,479fc0bd,78a3805,de50be2d,a6ad70c6,9048e43e,c91343af,ab7a929d,588ff993,55094f83,6e7b3b58,c6381bfb,b284f9bf,7dc44cc2,67cc741c), -S(f0e084a7,af9abfaf,b6ebf3c5,b526d545,b8b1cf5e,8e09a06c,3670aa37,6af83a3d,6bb279db,abdb2b2d,fcc97510,2b075dfe,b42d9e6a,5a8af760,f4b63788,c315f8dc), -S(715aa28f,4e52fc26,a2f4b9f,391894b0,6adc3b69,b508827b,4732396f,5eb7edb5,c5d0d68b,3a8c6532,2f6303ab,99b6c48a,88572c4c,56c780d1,d51d2441,86ba110c), -S(8f980e69,3511ec3,cca89b2c,362835bd,24d9c8a6,97deff86,5540f7c2,b0bacf8b,2d5e8470,f2041ca6,f158ac83,e92a2345,4059492f,af27ada2,92bbe51a,d67ee5aa), -S(6823a4e9,d80838b2,750dada3,cc31f59f,3cc9d6c8,3f33aa5,38d949aa,c4d6d657,e087127a,3ddc19cb,e4088a2a,6df61863,e8e81cf5,c5cea4a8,8cd2ab51,bfbcba8d), -S(8c9af14b,11add28a,818f85f3,276d1d7a,1e3478f4,23e74b72,caaf2440,24558538,a7c17174,da1eed2,7eeb7b6,c1d93e4e,9e4515c5,3cd888d5,e4527cdb,94a64fb1), -S(5fadb7c4,74b13592,a1a27f76,b7c2011a,102b66a0,c6ffbc02,a7306e1b,a9ccf49c,7bf61c4f,134f8b4,7a5f90a1,938918a1,4d151f2c,7f1c4bea,cb8c4773,cf11609d), -S(79a21b82,9325fbe5,c01ac979,8b89cc47,379eac4b,682fd747,47e0c04b,879b404d,abfa4d5c,7ff916c4,9f489c12,5235bd9d,a0395b6b,84d6699f,c96f9c0a,5a4cab2b), -S(b213d11d,e4b5601a,5f10827e,d39a7825,adc36bc0,1130a055,cf8b3e8e,fc96d10b,27c0e5b7,a739fcd0,5eb73321,3fd1bbb7,873de0a1,2b92cbc,21de57c6,2bc812b1), -S(299ef8e,e131f523,72949d7e,fc2f0f7f,9965e69b,56725b55,4d513435,ac8b0b3e,8ba93fa0,2a4d97b3,54d47c10,d5d791c5,f724b68,4f501eda,1931e563,2c6faf06), -S(5143ab76,43a21de7,7ffd0f3b,c4746fb0,589be22d,9d9ca2fb,89403a39,86d1cd37,20991000,a7c01e4b,26d9236a,45568bbd,91c968d6,c87dbe05,15063af,d8db5a03), -S(738ce787,49783066,923ceec9,a841d60b,56855e09,93e67cb9,9d52a0ca,7a64b5b2,aba44aa,272945fc,5eee0330,976b659a,a6455dde,feb5c894,cd274414,71610384), -S(6bb9bbe0,4c3dbaf,6c60adcf,5ec5fa59,29cdb04b,14633c10,5dfca2c,183e1d97,b7dac59b,5c35c3cc,15521da5,89c0d333,9dac05c6,614acaf1,d8b9e834,8e02c3c9), -S(f325eeb8,49a32b2a,fb19491d,8c3c112f,a7ca3443,438c8c19,99bdf791,6981472a,169df94,a26f26b1,e5aaf810,7a148faa,17742c3,10cac320,6daa69,f8aad67b), -S(d279bc0c,f7f58a85,b5abbe25,936d5088,4d8ae8a4,b415ea30,2c0f1133,de98603c,1e69875e,2e38f9af,222e03b1,6c833bd1,12bc10f8,1724da7e,bc780e6f,5228fd17), -S(224d079c,750eb1b4,2d70aa25,5fa0c3fd,c2d07c1d,ae4d6cb1,17c1e61c,5ec1c6b3,e54dc4fa,b0e05362,60d27fa7,ba53c37c,a37ce30e,617365dd,1c58a59d,2c93ed00), -S(f4741ca2,b3de5414,49426531,d546272d,ab8fc55d,8f65eb3d,5ea780a,d25cb53b,3b7290bf,dda0d0f,e3704f27,d8537063,f2fe9571,4a0791a3,e1a25865,96a5b0b1), -S(e931258e,8eb5559c,6d697272,8a704c17,b775a26,5b4527d4,a4d4d742,bbfd71fa,4e1ccc9,b3c0211f,17a14be9,636ab4bf,4c6b931e,44a1ca0c,c2642f2b,e8b2c928)}, -{S(fa01dd32,fada2843,c51845e6,3cdc1b76,79dee47b,d2f4b767,5133aa5e,62029057,6ea6596a,b0ea0201,b6c8bbbc,e9d07fd0,8040e1fa,198c8767,67ab6055,34a33), -S(97ec9d33,a9d88115,471619b5,3fc58a08,e6997662,7a28afc0,b75b2f49,55eba300,92ad1d6a,f8a0a100,27d9ba90,4f7fea6a,571f3c32,53393a7c,79abb0cf,9a558390), -S(ef364ba7,626d72a6,87bc9776,3f2c0833,50640bec,6ff4d80,9dabcf2,9ea9145c,7f8d7c48,1bd80ff4,8eccfa9d,2de5eeb9,800cb98,c02da539,3b3d6c83,8fe4a2ff), -S(45961303,a778b47a,89109231,3242304,30a17859,7d940e9f,fc2f25bd,1be61c00,5fa356b6,daad2b1d,7bb19cce,b9148d31,58d2651a,b4b436c0,b99193f6,61cb037d), -S(8aa677f4,d73c0725,e2163e5d,ed3dc312,7ad5ee29,f9bad8b8,5ab8f50d,ec6d77e9,1fcb9da0,d3fb9bc3,3a45bcdc,50aa2ba1,16c2b05e,836b539c,863163c7,2436c334), -S(8c6b2873,33082bf5,a3597a26,7cc14696,2b689f20,59caf1d9,35972c98,9b14c86b,aa86d282,a1107f8e,21307e0,2ad1420a,a4061fea,3e3dd6f5,9b5d6900,6bf4827c), -S(46c963f0,3bdbf433,cbd60858,5a4d659e,9815c286,9f684eaa,cd879d66,ceed05ed,be2a8d60,636c5b80,e443b13a,9e21c91e,90a9e781,1c35101a,dfd61a49,88193e86), -S(cdbe43bc,582f3936,314a88f9,fa21b29d,f4b5acf5,96cdac3,4667e9c4,b02b926b,8f2a5b62,4f20b20d,cce97348,d73d5653,8651dd41,dfedd476,8792fa61,1bac16fa), -S(6f9c5a84,1ffededc,ec45dc63,7ad15aea,207116aa,a3036ea,ddfb0656,1dfd074d,ddf1c22f,9168232d,cf9c36a5,dfb7835e,62d28405,bd32ec15,5e3ddb3e,df834088), -S(42000663,3223b99,e15a2a65,bd95b229,820abee9,5ba5be39,6f8879b7,3f421e7b,9f3f3d66,40de91bf,c6872619,87487226,57e60a4,3ac633cc,48f684c0,cf42696b), -S(f02335b9,9cb524b7,45fa9167,41da4259,f70279d8,efe851ab,f5b0b8a5,32a087ff,e1bc6767,ba068b22,cb7389e1,36805da5,c30ca62a,e59b92f5,48e4dd1d,5327cfbc), -S(5bbda2dc,cf8154e8,28ed49b1,2fdabc3e,eb8c3f9,d0da5878,77611ff4,49d72e7c,312377c3,6277addb,d5b044e,fe136626,d5f7e7e7,a73cfc4b,9751e8ec,e4f77084), -S(5cd5cb83,ba2f225d,1ef4faf6,22e226e1,eaa85a5e,99721d3,82aae23a,f9dff565,254f58ba,9c49244a,4178a067,b0e4bf6f,dd7f3e15,65e21637,bc41f9f3,55045908), -S(3b20ebc6,b453aa16,e5b61381,1d81ca1,f87dce6d,b54ba85b,d8578ee3,23bff228,8c9d3054,56627a,7313505b,4aa5140d,9fc40d83,bcc298a6,43842f04,70a335f4), -S(cd531999,cf33db75,df4430c6,bbcf32d0,642be18,5736d79b,f2947989,e52c8da8,c7e99c34,2a5c1112,400edc69,f58246e3,d3cebbef,2c43ff47,7520b027,e2aa7d78), -S(40b3856b,273bd2a5,145b70f,d16a2972,e488b33a,f3719143,db7bc567,26ff23c4,d8bf895f,71d96e6e,20d523dd,1256bd56,44e11442,c4757d74,f116ae44,69dc9b21), -S(1a0cf029,2d7cce75,32b74bae,acec6864,9e682788,3cef4bbd,c8b24fdb,53e885a5,32c87d92,6f969f69,7989837d,d8ec8ef1,c284d9db,2a86ecd3,5bbb6772,dea06692), -S(7fd5d251,93dd6c17,8d0be92c,342f94a3,c92c061,27998f4d,54f7dfb6,1326fefa,ea7d0755,e0a804bb,8b7ac8f2,dbe1dd7f,9ccd36ca,2fa94365,631ae455,5d080075), -S(51820145,6c07fa3e,70d7b24a,7754b11,e42828e9,c1b96b0f,fd79bead,2f44050e,126f5526,1a55b724,7d08c868,366d697f,a6898c66,d14094f3,44b0a6b3,613d043c), -S(86f2c87d,46038770,3be5ddc6,c2ba1ccc,7dfdd56c,a9986663,882f85da,345886da,ed34fc59,4b66f7e,f06f54de,84f3c7f6,ea1d877b,bbfc4185,3df800f2,fa805027), -S(7f7d8a69,5b86ca13,d6a0ba07,99e60cbe,f5c4e1f4,c74a62bb,93d94d4f,8c1f296e,44a14061,b2c741c4,6a52639e,9bf08776,5db5d496,92bb6d1b,e97f9ced,a89953e7), -S(ec61e956,83714c55,1b72ed5f,c5b09663,6dbdea9a,64d13ef8,c9cf0c55,89da5ae4,39a6e38f,9f7927cf,ffcd0847,df91e856,4188bf58,276bb4df,3721335a,5357c77a), -S(e5906c85,4a75bee9,322d70be,a5d31c76,31a59389,2f479bf,8dc11bef,9ad5101c,125b3a58,8c6c1c5f,288402f4,3ce74ec5,fe9c2dd3,3f3605df,9ab41210,32641524), -S(6c9faca8,b1b435b9,213fde17,ce967f05,46e6f27a,cf0e131,8496bcfd,d856b092,a04ac67d,4bb07624,6b59df97,2fbe2c1f,bb04be99,e269d33f,ccc81f76,3f567577), -S(61031a0c,730cf279,d929b4f,5608f16e,6b1b1440,c04e5a9,fa300ff8,27303def,acc4d732,afb4730e,39a10c0f,5ae2cee9,5099be03,bf5612ac,391900fd,b51238c2), -S(e58fa07f,ebc3aa4c,61ff4fe3,bfc8d04d,48a1e3c9,935317e1,83d537f9,7f35826b,d2402844,7e63c3e0,be630190,8139a75e,2e1a2b22,b05ce52b,e453ccf7,7c35f1fa), -S(4d4d2982,b45a339,1720af,cf6b92df,2c201d38,5b9b6c3a,8fc53b4f,fd3bfdd1,d72650fb,d130482d,116524fa,e2b3dd71,c68b4bbd,54fc55a8,f9824578,cff67503), -S(9adeb6f9,6ffcbb56,f171919c,a8a64c70,9b8ae835,828bd573,b7a1bbc1,3efb0360,6d920a2e,d2e3f41b,4820d838,ca342b66,9af35a7f,7b6d09fd,b1ba4298,9abe027c), -S(64ba9514,d8680f6c,dd66895d,9c5ad45f,6e29,33506f8e,d7be9770,822aa9b8,7ed8c0dd,59bce424,481f88d7,3e641b61,a010e490,97cf84ca,16c2e045,49e9c6ca), -S(9e4ac64d,9ca58a04,46ca18bf,c1700f2c,16937ef9,c82e8b55,9ccbd751,2a0c0222,315ba2e2,601b18b2,cf7f1720,9c4cff2f,e39dfcf0,c2546fb1,e930898b,5b023274), -S(f13a99e5,8dc72fcb,c62a492,d2850704,621ddf48,f1f433e6,9a9814c4,17d4b84a,cc3d3732,f0f4166a,55946e32,e1c01f91,491c82b8,ef0d269d,7a66f039,ac02dfae), -S(fd6451fb,84cfb18d,3ef0acf8,56c4ef4d,553c562,f7ae4d2a,303f2ea3,3e8f62bb,18ba314d,4e78ea87,490185a3,e43cbb33,5d54b6d,2dff17c0,2f526f78,ecd3f31e)}, -{S(f1a749e,6cab100e,2aeef8ee,6a654551,c0ff906e,e7d11d77,f390955e,9d29d783,a60f7295,3c8c3bf7,f1dc1358,e39baf76,3dba22a0,1ce7917e,aeabd996,e21e845b), -S(e8c45020,4c9d9ad,f7878aa4,184a1576,d4c65d5a,c1c4d494,ff427e86,8b42ec1e,aabff02d,8a715c2c,34414b27,808882c3,f656389c,71c26d6b,d7ac8013,83f4c57c), -S(c1febd79,1784fea9,bf378237,a05522de,1081df6c,27d22ea2,aad805dc,7c2f1c4c,c38782e9,fcc1004e,aa677f79,536aa069,7dd9002d,ac16936a,1f0b8736,8734174e), -S(91925564,4d9bdf2d,4522825b,5758b3f0,4d32da73,3a4e772,bfe3eb2c,9909f4ef,2568e18c,1a0448ab,d038ae62,a652d152,4bdec1c1,a0293695,9772bb65,d78450af), -S(25bb4202,9880c39,f5bde432,c1fa357c,7f4867f,6fee48b9,24ecc824,5e1a5253,5d43db2,64c23715,b4b0eeae,63127cf6,9b4bc79e,f96ea8cc,d17cb53c,c3ac0fc5), -S(2597e080,e772d36f,df500782,5f92f797,c61c72c7,8d801dd1,3deb1bfb,9e91b12a,fd5918b8,938ded17,a458d0ae,559c552f,bd45feb2,5b4f59a8,f5b735cb,bdab92c1), -S(70231b28,f578dc12,9f8ac54d,fd4e3577,73d0fcbf,65be0dcd,51132882,5a36e7e1,d12aaf89,4dff3e42,405a4140,58524e30,b7c6c4a1,83763268,6852acff,83d2b7cb), -S(f8ddfd5e,5f3b46a1,ab363169,12b74c97,b0bd654d,87824040,bf6d2cad,b4fcbf95,931fc58f,5b429636,5e080d5a,8fb35ba0,f92104d3,891d6584,8d24c0f7,fc95bda3), -S(a033f432,670a382c,57e2408d,3bdcd2a6,6758e63d,77574598,6b123e4,d927bf10,83b52f69,d79e7445,b6e33545,c23f16fd,52691151,96ee60d6,2ecf6de5,b2961a0c), -S(8e77f9ed,9a643f3c,bf197b09,80f92860,f37d8b83,93633230,6c902c38,3bb7f96d,71b4da9f,f736f9f1,f8c3c099,c34c1bc4,30bb5d26,3c861e2c,726fe891,cdf7d1ce), -S(f34153e2,29934c71,5d895102,778425f5,e92f4ee5,b96d1333,df207e62,6761b328,954584f1,64c8f35f,2c4e0188,76186ceb,3e91523a,5e8ac03,d5998253,49b7b8ac), -S(e133aa94,c0252f05,379b5bd7,75ba3f1f,92de2876,68613613,28946904,11b3ed52,40363801,613423b7,cc6c0cc5,af3641f4,dc2a7ac4,48b178ae,d1393605,103bd6dc), -S(28119c6f,a57d02ac,856edb00,f594c7be,22772b0d,700ad14,713affe5,7e385b5c,969b6cb2,8ef483a0,db4a96bb,92e2d332,6e6d86a1,73bc3d5,831bcbf2,5efc437d), -S(8c728d65,8b78d96,44003708,dadb48b,65dcf6f,6d9412c0,e31cce3d,b5384d00,bb3cf660,9908467d,285f1c7f,40f4f18,ca618093,92633beb,b4ce30c4,72680662), -S(477321b6,1fd5b4ef,3acd1e8d,8432ef5d,e70576ee,6b8490e6,839f1985,dec96490,88008466,2244e3f9,7d2ded5d,2193c70e,2d72c67b,9b7cd70e,9f14cb05,70306bee), -S(ebedd345,ccdd0e04,4bd3d4d7,e1f1cb6b,ec06ad10,5ec2cec8,821580f5,d08a63d4,4278bfb0,88e4ff81,a3fe15bb,e01be36,40450f85,885da0ae,e15c6b9f,e78ad14a), -S(f4795df9,41b315e2,24a98dac,d9149ff2,8b9a7bf,e758a1f3,5cb6336e,8e1f9814,6982bc20,285c27d8,12c5c648,d0635c7,fdab85e6,fc6905d8,65da387e,596da791), -S(65a5964e,ea76e30c,74c472bd,3ddd5169,11dcfb3e,1f2d7ff2,9661e254,4a38ea30,a7c394af,80ebbd32,e442271f,b061bb42,a7b1758f,44d7d952,89152fa2,a88fe3f9), -S(f3d10725,da6b6c76,6da6fb5b,969ba7c6,3e33b4f2,d062a446,4ffb20bc,dea2d376,4d65ff69,64518942,bc3142a6,2148137,7bb609dd,6545bc26,9678ea19,62812ddb), -S(f5fe0f35,cde00589,301584a2,f4f5b1e9,3977082e,9c9bd50d,7c2c672b,ef05cc9f,1b49ac82,486e6344,dea32ca3,c96cd5c1,446ac2fb,2a658a42,50425f32,e8d72e94), -S(fce17cd4,d9519a53,f0a100f,ca54d1f9,fa87eded,98a12654,769c95be,151e33c3,40d342ef,83a4d715,bd13df0,f21197c6,e189681b,efa0d925,248733f,5ee07b8), -S(fd5d90d4,a97c1d1c,4fe18a10,6808f46,f6ea4422,c4408860,c2256b66,618af8e0,7ffc76c3,539bdec8,f59a9a7b,b36fd534,99306cf3,2dd1fe43,a2db5b59,af2f7e3b), -S(1c71f824,1b147abd,9e3c1ca3,fad5146b,e531dae7,c9c0d586,4f2d8bd8,7a6457aa,23e7e758,2cfc92dd,e498c0af,b942182a,92e02bb0,7e95bc1b,763d8030,9ddc9137), -S(dfb018bd,9bc352,f36889b8,2a46512,8850a158,872554cb,3a3dad28,a0496f20,2daa780b,d615d778,3de8f5e8,25cbd934,5c021df1,9ef80a6d,39ff87db,67a1e5ca), -S(bbd320ee,dacc1282,d3fd2109,c26f6bcd,46205ec1,d96b806,dca35dc1,4baa823d,ae7beed,3b5f72bc,ba66c794,89c05666,efa85966,14bacc45,9a99d882,8edbdbfe), -S(c9cd8f21,a068f78b,ce5129c0,9084be52,e48d688b,f474e690,b7720360,e362dfce,a10b9fe2,78c7814e,37851b5a,36aa4246,54c6279e,89df8fc2,ed189ad8,11518f22), -S(ddcf39db,aba52181,72c36a53,50883245,39ccddd8,46ec4258,e72dcd71,40041491,85cadc4a,a569265d,412c8fa9,4872bce1,51a750f7,b43385e2,2db405e3,54428a5b), -S(391562c3,f19436b1,a6e41d06,7435fbe8,27de66b5,555540c5,3ca7a0cc,c7876457,c3a5d917,5b56f67c,66ff269f,72c0a1ac,74503106,9059aaad,f3e66dad,45a80ee0), -S(63d4b224,7b2d441d,680a0437,604533cf,1dc48c9,bdcb9e10,e0249960,f966b2d4,e25cb896,ba165d4,46f73344,61e6856d,4c186736,402dc6a0,d866f97e,bd5cdfff), -S(5fe057df,5d2508c7,611dc21d,412739fe,3e7cf9e9,670812df,cbb00255,4d44cb22,33b88e83,9f22a7bd,17c149bb,65bd4a49,29b2a29e,b975776c,e82189de,80c7d45c), -S(5ac83bf,498f7eb0,79507ac,d5fbc587,f758afa9,b6a1ee51,4c857f8d,608a7b1f,1c866393,8a91904,f0530bdd,ba15390a,4c10fc4c,ef8a2f07,d799c89f,69a33097), -S(b0f9e4b9,b29790b6,33bcc04f,d860cb0f,823d8d1a,4cc1a1c1,413c1606,cc9a8e2c,b617d40e,7bc52192,be344f46,f9021c0f,ccaf33fd,3e8e3118,93df993a,20c2ee7b)}, -{S(eccf169c,9514a854,8f7e1131,a7438469,4df7dc2,fab96462,20e5799d,6d3f672d,452e53a2,aaf17617,37055bb7,24b64f4a,8fef29ed,f8571ff9,a3a6d2c4,6acdb91e), -S(a77bcddd,a0fecd39,a99c6387,57bda1bf,30257248,6a3fa08a,e2d6ff17,e6e4b6ea,debf4c03,b4bb5c7a,8a386a7b,1e459426,6c78eec6,55f01cd9,f137ff18,c5fbdb1d), -S(a77b91ec,6db6a66e,a48de424,65079a2e,ce220fba,da221601,840546ec,2295c2a2,3c721fea,81f5fe05,163562a9,849bdb15,90bc818e,86674ea2,57fe8d0f,4050086c), -S(99a28a1a,3bf2af79,ef2bf134,d31880a,71c2aad3,824fb7df,23fc4fb7,d54b2910,620e2918,df14e3c5,dbfceada,1905941d,32d77592,89ec607a,f9851a6c,5592803d), -S(7eb52616,71402db8,905c7097,2af96b72,2bd77d,f124bbcc,5418f217,f6d8c7be,ce1e663c,8276bf42,99919592,11feb13b,66aefa37,5d6dca15,8b7b66a3,ffc6d7ec), -S(c88b1815,f183e6ea,3ce8469f,ada5b88b,805288d6,828473ba,368d52f,2145e7a4,55e78f2d,3784952e,cb47f6b0,113eb471,8cc58225,85f9d1e,2198dc60,af3f90c9), -S(dd893c5e,a2e4e70a,fcc161ac,47232d3b,77f16c95,54c98770,9a7a6f64,c0cf7ab1,a1a58b41,c7d4d0c5,6d6c908b,32d97467,b8b6ed20,73e6a677,54935665,6a92a480), -S(591b8422,eddbfaf9,d2c27c28,dd84dd30,712a15a0,deb752dd,dee682cc,34722ea7,877b0c99,6a248082,fd442509,b0ce4cc1,b181d4f8,8ff755dd,5f0dba66,ebf95d1f), -S(75f9e3a1,ffdd902,be5d1d2b,3ed18b37,62e42e95,8b024ce8,f892ee13,ab35c674,57fabc84,7c68cfdf,272effee,e7a6ee2c,5fecdeb4,8e4877c,ccf2a8de,2e2264cc), -S(c8a53d5,e1895cdf,db61c1a2,395a866b,ad803773,23ea43ca,775408f7,a4141cc6,ddeff9c9,97a11e4d,d0afab30,f63229f8,1b52ac,c25749ae,2749ddb4,2b201196), -S(8827d23,668f3006,b966cb19,698a066d,aea556b7,4108739d,d6414d8,e8dd78c9,3d009ac7,2baabb53,2e3658e1,8941d4b1,efe512b8,fd7696d5,14b12216,215f10e0), -S(dde6b713,5cf165c6,53c7f5db,542501bc,b0a41e3c,c6779aa6,194ac1d1,8a830b01,25c04b4a,937e16b6,e72616e2,d64a413b,6a7c29ac,71dfcbf6,826261dc,2507c16), -S(8cf6210c,5426b3a5,ed594699,da6cb8b9,8069a3d7,b926cae9,fedb2e96,25d20010,78017fc1,7915e3c8,62557896,acd002fc,7263bd7f,aed38fca,d63ccaa3,57391f30), -S(35772904,91661db6,340e7d1c,a98db8bc,2f50f557,283ccf11,8e446f71,925ade9b,fd8a4a56,b82dff95,a59e29ea,bd5d8e8b,a876bf95,4abf0537,60832d1b,d7edc31c), -S(60e4201c,4dbd9c99,c5eda030,f041f51d,f648f77b,13ec2072,4d89b6be,f249d793,ebd96057,d60b7cae,71349c51,1a3ca99e,847419ff,cdcaa0c8,54d75d40,8263d81b), -S(f39d686,b17ad518,3a7d300f,1bfd015c,57541f08,a96b5943,43d2ef82,bf20bb6e,f1298c9c,633a958a,a0d12b87,8c95836d,f9f93b5f,5e3a6bbd,93a75ba1,1b96d4d0), -S(37ea7dc7,2a3a0b4e,72412814,bc1e1233,17ea3e1c,c4ede35f,cab5d31c,93cc330b,aebaca93,8b14b315,708360e,5662e6a1,af25069b,cc07f581,225dd131,c656c607), -S(ff1f61ed,ba3cfc6f,2fdf3043,37205bab,301c965b,501e4f2f,fcacde00,dd127b25,fb1edca5,90e00f87,eeb56ef9,94e9bb12,b64ad1ea,f5ef0afe,6f0125b4,e100a483), -S(3376e0a5,b93f15b6,c46b92ea,e313ea2d,c5d0b961,a2623487,8919cf5e,25e9ae38,a4cfc1be,fd24647a,20ae014b,2041ab3f,6cb7585d,48a607f8,299e0c10,96bcfdf1), -S(be575f99,842187b,30bcb312,987ea218,3d613442,8878804,b5e7d920,12e58d9c,154e02b0,b573c81b,d2079a4f,4a6efe5f,5f37502b,33225064,4eb38b2c,3f0a1767), -S(5a215836,f1f2997d,9b09d4d0,6473c55c,46cd3006,70d85d6f,6b5531aa,c8da043f,ef5fba1e,b6e1deaf,bd83e480,fcd4984d,cf60f91f,4799e8b4,3f4edd15,f94b6d33), -S(d73fee2,16a503e3,a7d6b0a2,675adb1d,197c3fae,4d43835c,b6b043f5,d44909f5,6f2cc9ee,fbc36b4d,a5b3e704,c13daee9,cb81ce9d,470f1290,8b32f047,ae231053), -S(26fda2e4,d07ec613,ded58e14,ee84e421,ea58e5b9,5beed698,d847f6a6,db185f6,683c0002,bcd6d8b7,1d06e592,db4b961d,f2518fbb,47cb4ad9,96020d84,ed8a5909), -S(cd3d4e87,e433f2b5,5dc55c6,a3f280fc,57f899e1,f8f0777f,32705f3,eb24551c,2315d85b,7521e4e3,8e69f29b,a49a3203,abc7f280,ad49365a,4c78f21c,3ee12542), -S(652476ac,2c9b871c,e108fa13,6a739766,879a76ec,60d787ac,a1b7447a,67f8afd8,b66bf6db,cd3a1393,f70ac7b6,d53069d2,5f084dd7,f05c97a8,76f7f646,c7b67fa8), -S(61ab4f97,61c96446,ea7a75de,7ed36224,7b5ce8b9,e7b442c3,432f9fa0,ec74355e,f391652b,17a910f,6d476c29,89e854f7,d31a5f31,fead5fbd,5013ea56,e44985db), -S(36e4bb36,e62f78a6,a6155351,36a73637,13fe8be8,1c8c3460,a94bb642,4f7c80de,12b38983,c10079f9,b0016df7,fba0685d,5eb87518,234c65c0,7dff006,dbb6a563), -S(f5e4cb89,101e90d4,b2f50097,aa0b22fa,df076932,f4045e9b,7a9ce8d6,ba178780,c12ec4ae,56db7971,3a1bb0f,2559e3a1,de3f8200,650c809,74101940,181eb52b), -S(1138ad12,333790f9,20e979f6,a6471274,2a9bb567,2356e3c,80ffff89,a9de533,4caada48,a78ae26b,790f23c1,606a5820,98642f4,bab5bfff,95748f6a,2ccd6bc), -S(e0346d21,121ff741,fe4eaa23,938a4347,a71df442,9e55359e,aa20d691,c9f40840,c1197c8e,c36676a9,28a92b56,811845d5,d9632c65,9142cc12,3c65e54f,c282dbd), -S(d42011d6,1061388,fec6b7f,3f332b20,24ab318f,2a9ba7ed,23731207,3e32478e,451a2b16,5c82b1f3,e4d2a0a0,bb407b84,904db4d0,caaf733c,e31fa97d,2fb1735b), -S(63964eee,619074e0,780140fe,2e90836,e72328d2,448386d4,59c5be23,187f5048,c49304c5,947630be,5c60064e,3cb40436,c2a7f46c,b221937b,c7c5d7b1,76cf5e37)}, -{S(8f741868,43906722,ab9f5c6e,c796573b,622fa2ae,6d985bfe,ea4d51a1,8f141792,61ecd858,d6992c4a,bdc22472,fb8fd242,929dc5b5,36ea8e35,d1c8c513,bcb9e31e), -S(f2dd67e5,6f75c397,76b29366,149ba4ff,69385651,53afb385,3853acb7,9fc2bd59,3a24641c,d48ca39f,fe992bf1,50291604,79066af4,a0cf364c,9e52a9f,9b51eb66), -S(9386aa5e,c3452728,a8f65141,e2f43a14,c250173,9349c96d,e1968a4e,48cd30,a3a38a85,4f68048,d8f81002,3eef9966,780262cb,aacbe859,a8fc66fc,27c37f32), -S(6c9901ea,920c0f4c,ce51fde7,ab283f98,eebc30dd,c76a3219,1df4c4c9,db467aac,6773f8ae,e601201a,84dd4485,fa560e22,81d5eabb,25a3b3d8,525f4a56,65f79d05), -S(ed1eafec,876154e0,58597caa,8250b0ef,7262ff70,b719ec9b,63c0b2ff,9d167fe3,73505073,2b563f93,89078cc3,93ff9837,227ab8a6,c7d789c,6d2bc835,2018f77b), -S(515806b5,13d4d4bf,83533b56,3b39bf9c,4e808426,f2e4cf16,562e759,cf2d56ab,83c2fb,673a08a6,b8a86b1f,e1ba23d9,3347903a,d6855059,130d8d39,737ddead), -S(30a726d4,d8db1cfa,d59331a0,8f4b5376,36848547,914dcd75,37a80e40,109b8e35,8f628b92,6a11ddc0,dfb1cebb,934aeaa4,3840d442,a61145d1,803f771f,7bf65d7d), -S(116867a8,d72fb00e,80a6f267,e8163770,34affeff,36d667cd,38219f0a,e3c9038d,270f15be,b2a3d50a,4088720a,e9a2c3dd,df00817e,31e1a5b1,d850fe23,dfe51657), -S(abea2899,e4575c6a,201c96fb,a60a24ee,1f1fe0c9,b718b54d,18981938,4f33a1f4,d43d54e3,9e8d433a,ce66ad94,e52662fa,8013e778,f8bc2e3f,31938a6d,5681c660), -S(1fa796d,9f658aa8,6ccd0fb4,6a735651,102e3181,302e371b,8c965dd4,5f078b30,69815d18,43c3b4d9,f7fa4af7,3d2e5dda,390e5372,28608912,79826a53,a437031b), -S(f5022faa,c8caa29f,304ab6c3,d00931c5,e09085e2,73beab04,c1d18f87,1c0fde73,c6abd143,73213fe8,ffa5ec64,8a22dddd,fdf2cb25,e32afd58,4f92dca7,838e8249), -S(8190b10b,97bc72b9,301b1dc,cc60e69e,460e389e,ce7d5d11,4e2284de,853ea02f,f1ffb850,dbff0f06,561b75f6,5d2ae823,cb13881f,d1150eff,274db4cf,112d2253), -S(ea230fbe,c58d7e2f,1a3cea60,f9018562,d2fefb49,8efa312f,4beafcd3,139da094,6045d69d,b27bee6f,3357180c,e92d3866,b480faf4,2debc033,cfa118fb,b89c3bd2), -S(333d063,ccef6aa1,f78c81b3,4a84975c,82bc2cc2,bb897608,f0bed49d,cd08829,90ad105e,f72b7e4f,a927240d,9c69729b,a0aae3a2,3a45342,3be2c385,488840a1), -S(4d95cb48,58d808a3,be82f42c,da4f64a8,c64ae176,3b50257f,2e4ae655,fcc4802,5f6efffc,99bdde54,6d8ffde5,e9a551d0,121a39c3,86db540d,1caf74b4,894c5559), -S(b87b5eca,6e0111bc,5b756816,fa82acf9,77f81376,af796cdd,1e8fcb09,4d363d1,442fa845,9c2a7799,2c09015a,db80f26a,28428851,62432660,56026009,5f2f9d8), -S(34baf43a,a82cce1b,19945590,ef3cb582,2ab03142,6538ea5f,74571582,ee14cf00,9a76705b,c0141e29,75d11543,215377b5,3c051c31,156697cb,e8f56721,da386e2b), -S(f07c5d98,a2579c17,53b3fb58,22a139a1,53e7deeb,ae9304b,114bb188,d61cdd0a,ec18ce0c,1e51b8bc,e12f3d85,23739f8,bc25708f,32deb81d,a780cc4a,1010692d), -S(9a146c80,5ee261ad,3e708885,aa41041a,53bd3758,b3d1ab7a,1a44aa7e,29acca7,fc553e71,4ad8a192,90f94ed7,7c171f9d,9ad9a047,6791f045,4a3ab7d3,f8834f02), -S(c8088409,650feb74,9f9fe21,61772279,128db1d7,58610a9a,8b9fc4b,ef9683b7,692a6be3,132a08d3,82295ee7,1c469465,ae7d63d6,c20c7357,36935003,28799639), -S(53bdc8b2,3edd83b6,b149b79,c88130c6,b207f999,e7045285,7e828f81,b325b9d8,a9a039d1,79486167,8fda727b,1706e9ec,7ec3eba3,26e6a4a7,e27db3f0,8a6ee238), -S(fd08fb47,4af98207,3d8b4ef6,d39012f4,78225f1a,bde3c841,6fe3881b,4fd276c6,d38b53a9,100da1fd,1d2a987e,6907370e,7bca492e,98a22e5d,74a10c9b,93a197e1), -S(5c42ad93,2306363e,a0edf86d,31d14b04,c3f7bc09,c9fe1326,d1ad085d,c84fb7ca,1bdbf812,e9ad6486,ff572d4e,de5be4c9,59de7be3,f21e0dd8,76534091,f13ca3d3), -S(66257876,115e7eef,fc0e6132,9f177d3a,437c81c4,1150f86b,45904f86,30bae971,df830e1e,33aeded,721a0a6a,62a3a402,1d2b7ab7,438b7b3c,d834d67,3a857aed), -S(4feea8d8,2cc6601,c847deff,35581c1d,bf1f4070,402bb948,ce9a41ee,16661627,c09a7686,ad6bcec4,ea9ab0f7,8316adc0,7c7a2899,9332cee7,5d70c50d,249a0007), -S(2d3bb180,73f5345e,cff0c901,9a6f2fb4,e0a237a3,9315fc11,fd53c7d5,aec43670,58a9459c,2710ac75,ff2510ce,4c9c5fb8,b4f739c9,c6611494,daf896db,e43b080), -S(bd539f5f,47b25116,7159153,f402e0af,8650c17a,de7c5dde,2d9d9cc2,d0a3103d,407cab4f,ca581f10,eb386e20,9158541b,8649951e,b2f5e454,2a7032b6,53f0caa), -S(c7a72935,87ba5114,744c3d0,9030be19,9ccea57c,7f80be87,bfb5b79a,8f8e200,7c2a98f8,b4526422,b211bea0,875a81f1,d379012,486db005,e31b9682,404e14a3), -S(cdf20316,f4b63ca4,c472e1cd,b3a938be,291d98b9,3ad8f3f2,4f3e1a4d,f1a6cc80,ab993e8a,68988d4d,2749760f,241399c8,136ee9d2,3d4ae7d1,e6d26df4,6056587b), -S(1d341e6,2eca1f48,165bb2f3,86207da1,f2c7fc86,dff7a75,cb63976e,f21bb074,923b53ed,fe2f5bb5,56aa7cae,2a08ff86,160e3344,c4adc09a,e7aeadfd,f31e2b9c), -S(8704f69d,9d335975,f0e3bb83,5aa3024a,60103d89,e5578253,fbb3d537,1983ce4e,94f4adfa,31dbd13d,95c738b2,8a569453,cba45efd,1cfd20b6,78f6a724,e9a8d025), -S(7175407f,1b58f010,d4cda4c6,2511e59d,b7edcf28,f5476d99,5cf39944,b26b64f1,bc4baabc,bb1c2aaf,c92cbfe,ecb33791,4fe01748,8bb8e2d5,bd918104,4dbdc75a)}, -{S(a16a4734,9afd167f,d5e79d24,9784d87,5121fa24,2c3a54a,88f9b176,72669aa1,4df3fb81,7021efdc,e5296735,3a177b5c,51cc7762,4755ba28,1084db5c,4809e02c), -S(91d1abe3,8d3f9671,54337e03,d27fa6f8,c3007f32,323d15c8,31306b3a,30900328,b1b8c71d,b388009b,98000f9f,291b66e3,f890d42c,a5812f34,5c070f6,e73b89f6), -S(61b64b1c,f2a0e720,e9bb4853,537b9f38,66baff87,388df7f9,f14c06c7,12080b96,44444011,b6ddadc5,7ee00eed,b6af3772,e4116711,c3853f13,7f9c7b00,2bf2a1dc), -S(3b96b2ee,d9cf1ed6,3aaed8e9,aca3a464,d6a6fbf5,e6fd48f0,5aacc318,dfdbc87,51c41c26,506cac9e,bd0c5dbc,8ce8788a,3469e42d,de794707,9e0cd0d9,826e9c58), -S(7bbd147f,77b293ac,ff797b9,a52778de,5874b754,c08df397,72ed8ef7,53242efc,3e843df6,75abef2b,e4d32c83,205322cb,f53bde0,2563eb8e,b5dfbe6f,27d4cada), -S(becb7fc5,de84f994,9f97e55d,bdb6981e,f38c0c45,1e0e454,519c9411,5bae3d7,754145ec,ee6f9c7c,f91963fb,5b0a683a,ef24313f,1125570c,c9b9c7d2,afab99a8), -S(87936626,aa88346d,6d4330d9,3a188ed6,992bdbb8,387b395e,d21dab93,63d833eb,a28c868a,18dbe0e7,12ca5237,53f6a50b,9313e687,85f3b31f,ec778fac,87aa9327), -S(e79d4b2d,e33de1e2,e7eeeb44,d197aec1,f5883ad6,1394dd79,de274ef9,76e3b022,9c73ade7,7c661527,ec2ec6cd,b370c130,380bdd9a,4bcb668a,86e8259a,ca85f293), -S(863f0d65,34de1222,237a07bd,ebb066b5,2c1cdd83,d7a6d3df,278e57c8,bb59b8c7,c546940b,99d04ae2,5cf7c881,28a985cc,9b6223a6,ffc06fe9,8a3e0f68,439b9db6), -S(71e9b0d1,3972d9e0,2225bbda,5a1024e9,c373eeb,f6514eb1,c113ef88,dffdc3a,4436c52e,c58a34c,562638c7,8d76e3fa,29e3586d,fa667577,2fe0b932,c4a1ade2), -S(ef4a500d,c9369125,78fcfcbe,3c313bbf,f0323caa,75750b6b,a317e1e3,dd8054e3,e807e9cf,7911c919,fef82e40,a3ae1b9b,ed8ded38,e74126ed,863199de,c031f2a1), -S(806dd4e0,fbf72904,c7b0080b,4e7526bc,c71fc52d,f143da80,e571041,dd964915,2f4e2e67,3348c32d,6bcc0741,2e76f4fe,944f96bb,d73382c8,c6880cf6,629eac8a), -S(9ea889e8,acf0441d,6e299687,c532ea8f,8b9453ed,5fea0d47,f735056b,1eb3bfa1,e43f79a8,4d302f3c,88698896,5fa7b8f1,a92c620,dfcb3462,c4befe3f,4afbff5e), -S(9a990a22,1d27d8f3,40e79489,58cff3ca,2720dd3d,ac71688d,9c3c9e2f,afeee215,4957ac76,db370918,7992b0b,63370656,7e0f4a0a,9e5f1d9a,be8f7d5e,8a950eef), -S(d3291003,98ad3d92,1d6cbc6e,b37ac3f3,9360cea6,23edd794,64d34a51,fa7adc60,657c110,5bd8df6b,fe52addb,2fdfc41b,810a1ff7,8662021c,7c220b0d,b3509d14), -S(65eac576,e149d97,3cbd772c,60570870,e437e92c,2e5138ac,9c0534df,b7a45582,ebecb6a,edb87cc1,417e066e,fef8e52e,c61eb00c,dfd98205,91d63c08,9dfd5347), -S(b6976b99,c2515be2,2bc901fd,8671255b,f8fd76ca,1f3474cd,5eebe39e,98f6f14f,84ab17d,da67b61c,fd01881e,b1087e69,845aecc9,ce1535fe,1c7245fa,8df98181), -S(c7f5967f,f9910e10,54c93e1e,d0290102,9bf31787,15f53758,f5c53cd3,c79a52bf,bfb01210,5c1ec69c,847ceffc,d1105ac0,528129fe,3b4d3086,2b6e9562,836f5eb2), -S(ffa0da7a,e8984e4,d02a0fe3,acfb4e81,2a63d6b1,682dcd78,fd2635bf,88cfdf1d,49459ee5,3fad1097,2da786fe,45a2d201,e4a52260,7779b1d4,23defafe,29e70098), -S(5a53d683,3bc1740f,d02f278b,2ac15a87,f137f2,c798f157,725a4aac,63f1798d,ac5e7ec5,86d5960f,e25f9e25,7cf9ee05,110d9595,e440d032,c416d444,6242d10), -S(70f67487,9b030a4d,9ccc0bf2,90d5b78,c455f8bd,a1fa2b52,efaf0200,6b70a6cb,10f5b1c5,dc46c0c0,68757804,93805aa7,5a259dbd,95b4bd14,d031daef,a81bf7bb), -S(a4baf0d7,d3a53c29,e78ff81a,52d634a,e009391b,30a9aa91,df8f7bb6,13e3c16,c9f9d001,7f388f09,b6802c45,e1fa036e,99443467,c3847937,8b384a9,dada35cc), -S(351b8e4a,dd336c28,5d140c57,9f2b089d,3c656a05,b1ed6,4cdbaf7e,e5bc671b,b996e61c,cb14553c,b7b79803,c82332b6,704ce97,fb4e19a5,1f70b13d,f8e2732f), -S(d248350,92898c0,5dbb4465,18695efa,e59ac007,d58b5df5,bb3b7038,82f18e61,23455e7f,5104051a,44600be5,2e242a90,95213d25,b4fd65a7,62c3f9fc,9234c2a5), -S(d3fc6d75,10cb0b20,77b52b00,93e84d47,54dd1a28,4f3928f2,a9e3cc02,f1869588,26e86b02,c16171d4,4238aecf,666146f4,9386e0eb,52dfed87,7ac0b409,51ced10b), -S(1c611335,3d115906,182b0e4a,7eb3d39f,552c49f0,c5928aa1,15ae00dd,c23a3b70,1c3e3c4e,ed65ce47,ea82a33f,df8fa6b5,532977d9,53aed38a,f0f4dab3,98477c6b), -S(6487c5c6,abb6e673,821c4b0,2c485f83,3e149af1,83b3f025,71a81fbe,660e98e3,63c4f6b4,7eb37ed6,7668b41,1e83d9c8,9ea323f3,2d9e8918,20b65276,a8a7b7d6), -S(1b0baf63,6daaf2c4,28a62bce,bdd41de2,a4d7cf69,93f0b931,222a40cb,9f5f9a2f,af9a62cd,f91e2c6b,47f308af,e2de8f16,def4972f,24bf4c5b,2b1f92ac,f63a21d2), -S(95bbd974,78e1b8a4,1622e460,8aa82fe9,e77d43e7,492a0d21,1146d987,f9b8f255,412bc52e,d61c3880,210d3df7,f0d2f27,d458d51,388803e,fef1c016,d7c9e7f6), -S(a3466715,5b6ea598,2d3945fb,743a1510,c671b96f,a3494a57,e0349010,55ae087,de35a05a,1a943a42,7210165e,55d5cfae,3ac15490,dc6b0f43,34c0c99b,dd778608), -S(2ed76c11,52ac3600,7aa17c85,a5f902f1,7c845a05,a4e0aaa0,7b05e836,cbcad59,9c60b2bf,bc47a0dd,d3259151,37e89812,a08d39fe,cf5806be,eb538575,3b159531), -S(20e6e2e7,96946bb6,30c7071e,f1b92ea3,d53d280e,e450111,5f5da36f,840dd273,2c528501,b0eaa61b,b5f45e52,6878b9aa,7ee13686,c25796c3,3f8302e9,44b9469c)}, -{S(f040a2fa,b839c753,4e216425,6c2e8dd8,57c52dac,e75cab3d,512a7b1d,562075d2,9e211cf4,bab24e0e,f745e2a0,9b59565b,be7b2449,8123f6b2,ba383b25,29554b36), -S(c66813b,904831cc,12f89e3f,bde93eb3,11ade6dd,f6cfdf72,21cc61a2,ff46bf26,3b60c8c9,9da35a58,7b9650af,f85ca785,ece41146,e7ed8d6d,ef8d26d1,f3d055ce), -S(cd38ece8,7c7a9cbb,e23b58ef,59925633,734de285,f93b3ac4,eb01e03a,adab904b,a5f48fcd,afe414f4,1a44917a,5dcb80b9,30373af9,70e9f22d,c1af80f,a8b06320), -S(72d6f7db,199564a2,6e823a49,eb0171cb,ebb76a2a,add56c7c,6d3102a,9c3ee18c,bd2039ec,c390839f,e2d4451c,9437fef6,3e98dc62,3ab0eea4,c56376f2,e270f626), -S(2ea6c313,1e101867,2454e15c,d34d5fad,13829d5,4ca86062,f074e512,a274167e,67e3d34a,56f12e1b,43687f51,c2d56395,14355d7d,9cc52726,22f62ab8,91c8d5de), -S(d66bdd78,8b20da57,b2485804,a2f6e2ef,78c7ca87,ae1c5c66,fc533533,5b624162,1a8688a1,300e6d39,e130037d,3f074ccc,57addd1b,88977e64,2ab296ac,d6e054c9), -S(6d6458d5,d1683d85,8f9e40,15e5a94a,73868bda,54f6139c,446b5283,6d211542,e44c7ca8,33761e13,ca5458ff,dc682f22,3819411c,a3c5feb6,24f06412,471b9f5a), -S(49f8063,b3d98f6,f159f2e6,65b0e07,8ef8c7df,44da06c3,55b592ac,13402b9d,b0b2d838,4b24ab11,de895013,e897e825,45c3e8dd,6cdb0990,555cd871,5841f8cd), -S(8b2fb6bd,e60449da,2684f8e3,6267fff7,254051ac,faea37cb,102c9bfa,91abb2ca,c82cb9ab,c33c1817,10d3fb19,60f2850b,5072eb47,404266f7,c7964fb,f98027d3), -S(cf90331d,73644476,47c8f86e,eaa6e67b,f3fb4b3c,4c895b82,30ab2f38,80df1e42,9c493d94,3471efd5,ea90f723,db576a35,8cd1ee6,1a119b56,6c65b16,112eb2b4), -S(e70667cd,8d2759e,43f99417,ecc505a7,953d80dd,e7ce2cba,3c8c948b,d43a912a,92a534b3,51449a66,82395a3,b75877ae,851923a2,e791acc3,7293d728,777a2247), -S(4cc07d11,4a715e9f,4b4d0811,f0337c7e,f4bdff74,2fb008d2,1ce8a9ea,50520d47,478b279,613d92d3,dd24ae31,2658eda8,28a7d628,f0346e04,5d5d9dff,7178f093), -S(2a1cee60,4cdd3b2c,1f859bfa,af63d7e3,9aaad910,92c2a38f,a9362798,9753c30d,325c248e,d409e8f3,b96dccab,6fdb62a6,83b7eaf3,36d2864e,b821663d,ed31a6f5), -S(7c18d0bb,9a01969d,302616cb,bad8722e,d00103fa,9985a50b,765f0e2b,9a2ea14c,f6365a6c,b06e4749,c48c212c,63fff571,8f46e0cf,6fdc8c42,34d4db64,ceb72080), -S(a706754,65cde407,e853e882,8fb7a2fe,98638d7e,64b8df0f,b0a7a0b4,e629d0ee,fd694b2c,1354a5e9,415926d0,1590eaac,dbd1b36b,5ecc46b5,72467c3f,e2cc5393), -S(7ff57a63,36ec73da,cc1dc527,928cc6ff,4ec063b1,56b36292,23b8bbb0,a8ba2c7d,4d6dfc43,da0fe33a,1e75dbf5,5e5d669e,be6471d,eb8a4102,6db1a41e,9d5da637), -S(d4b1f7bc,87558c27,7e0fdf91,22bfe488,b3182555,599dd384,5cc039b5,93218e9f,992f79dd,c8f46682,5c44a54d,626b352f,7f59139b,d545f78b,44bd0b10,55c3c1fa), -S(897773f,a9de63a7,46ebf58e,248d0c21,10f90230,a792f0b6,ea5a25a0,9d1940d2,b7c7dd27,d561dde6,ca7588b,8e3a09c7,16297ba3,9d501744,f9639a25,b16b4f64), -S(2f9cb312,b071a600,e5d24cfc,79b0fdbb,f6da1527,10ec395d,53078453,1a3b07e7,49260f95,757b9b66,feeb5c20,16aa051,b444bfc8,836fd8a2,ab913e98,731fa97e), -S(5c53b27c,4c0ae241,8569c806,8dd43a5c,6fa23ac6,74d001b4,eee6a748,d86c9e6d,4e0e720a,f430972f,b0ab89b8,79a56eb4,f0af5161,cae83ca1,964a8099,f9d497c1), -S(2671ef50,5a321387,9560f0d9,e8588707,1c2b87b5,d06bb9d,dec3d179,6275b098,750ea18b,dbdcbd58,be994eb5,cb3539f5,8c3dc630,7d50bbf1,f69050d6,235826be), -S(59baa5ce,9d6e707b,b0738f4f,d37c9890,801ed796,a82afb2a,ecd2c5ba,195be65b,e6b66356,20a8a106,b58dc202,10cccdd1,e0e8c579,c92f3fbf,8b335765,b30d8291), -S(bb422d0,88abedca,e4686479,295aa1a1,77d7e68b,293bcd31,4097ddc1,af764b90,a96d33f6,46d4861d,a471f853,e0c6ae32,b1eea619,a7441504,a773f5e6,fc548805), -S(8d7df8a5,f08ba2b0,923662fc,e594f111,5295cf6e,c5aec9ca,df0f7236,fe51b362,26452215,7d8572d0,f057ec9,6f572f11,ebad3fd0,56032240,26b54df2,991f9046), -S(9e2b1637,352d8988,1e76fdec,c2dc8533,6a71b18b,3c98e59d,397602f5,8b9087d7,b997404f,1c0b1e64,90cff078,fdc47c42,aedf245a,e69d844c,18a146fa,6d8c3d13), -S(972c7bc4,6362bca6,b58f1d0b,87c0b8dc,fe91a217,7f0cd7af,404f6f06,47e09358,cfda778,a59d944b,4ec08bcb,3aabd70a,cd6f29c5,204c9161,fe2e5bd5,71d03f6c), -S(f7dd32ed,89ceaace,52e7f26b,202ea6a5,c7e8ff42,6c7ebc16,12106f7c,6fe51a54,7349c17d,d8ea6ad1,cb346e3d,26989950,3de00c11,4205b3b5,50d27ff7,67efe75d), -S(c9f96f88,3e34aed,97351928,fa77b07a,f4b01bb4,e4515f0,59745ee5,decc9fbc,6fd62453,dd6c9dab,10fb7d79,c15b4822,178eba31,258800e4,519e627e,91ef20c9), -S(9c28cc93,809b35b3,96a4c9cd,d6976391,17402ffb,5588cd76,7c41a92f,e971a9a,ca3b2634,28513516,86a661c4,747aece4,c8130d93,ff4108a6,3365e725,2bbb80ce), -S(263a3fca,437c4dbf,48ca36e6,aa892d61,abf58f6a,d3c82b1f,fe945dc,c45a15f8,604c5bec,69e0f1a7,3e8f8a80,4f762cda,96ba2198,35268887,910c8df0,e83d3044), -S(7fe42dfb,b3466ed4,d7cb8242,5e66b5e1,14a70516,b118911f,9170656a,3dbb04fa,d11385f4,b0a3a0bc,cf09374f,868cb30f,55175d77,2d3e463a,a298b6ed,1e6f6fa6), -S(53f2432b,a8171714,3fa9df3d,ff41ced2,4a29b314,bc5a8c96,f5f6400a,d7c0979,42ad1004,3e0f8648,332b1c1f,6ee4f821,b42a5b0a,361747ba,60816f2,ac84c58d)}, -{S(b8b52efd,bc367a5c,a1534bb2,f339a048,50fc4941,1668780,dcdb8b51,2daa7526,306a2236,856070ea,1e0fd846,cd571889,e20968cf,cd490bc9,facfc4e5,a5970b2a), -S(27e226b6,ed59c89,5bd20232,bc677c35,495d9601,5f37493f,5075718c,2017e42c,a130a5c8,54ed8ab3,ed657e0f,ee4a04cc,1b59a291,6e96465a,74b36144,7cc621f0), -S(1733f1c0,da38fa79,a7b37988,1822ef51,2392d8cb,59d1ad1e,afaf535a,e151fb64,a93ddb00,af779565,eeb230af,815f9434,958ad39b,387d9069,a03cfcb,8563a920), -S(e3f4b777,d06c8839,c63dfb41,73281787,72debac0,ed45b991,724c19bd,85ab3c58,2d6a84ea,745decd9,e6444b7a,dbb59fa3,21957b7c,3f8141e6,fd633d3f,7539dcdb), -S(a2b42fb8,9ac10df9,ebe804b6,c105e855,25cb05eb,7407d383,3031e216,64491ff5,d0973dbd,346a87b4,f4ddfddd,12be3131,e6c6a397,8e17be2c,bda23683,62f80765), -S(66d441a2,6b28378b,cf23d33b,ffac1163,7c23bbb7,7ad352e7,ff5cc09f,41bf6e91,982aa46e,5fa0b19a,28ecfdee,539c0ec,b5f06e2a,217f7687,6c3cbf1d,e92a6068), -S(3721fccc,20338f8a,779aceb8,eae3fc7f,bb0e4040,1de2c8e5,27941ad7,f789d0f7,d9516c54,8f457b6e,d44f6bbb,23f36c7c,e6fdc548,60e5042a,b3dd4f67,ad5ae3ea), -S(959e980,4618bed2,73b5cc48,5565df27,b8e09c9,a128a9e5,ea92e347,66e02015,cee3a227,1bddee01,3582d65d,c3e26c8a,f80a4601,abcff432,b1737127,91ca15a4), -S(f2e81d16,c19466a6,1b56931,935d03e2,aad6b8d0,7f193d97,bacdc29e,13cdcf38,afb8e973,8d563dc4,1e7688f6,c6b43b71,f366b576,9479f093,88fd09e5,faa1063f), -S(98305a48,800f92e0,bd815192,7b8658fc,60a97c64,c9f97383,68812614,3563910e,d32db8e2,6699b969,5b644c08,39f2399,f8ef45ad,a0d857c5,2d0c7c3f,96a62993), -S(8dbd4fba,113c50ba,ff3f251c,96aba9c0,440d8e69,8a1e4ec1,84fba97a,e497c443,f642b1d9,b012eef2,40c6ad38,fe441d11,cfb42ec2,a3c15540,45e64c76,c15be491), -S(deea5bb6,c7eac0a2,93e90817,836a3e55,2a7f1354,395296c8,97964c2a,4527a727,4cbe143c,c9fde617,c6142335,4323b9d8,bba13dd7,fbd46db5,cbf4ce2a,11c9c00), -S(349f46a5,8621034,9f207a07,4558787d,336cb0cf,a56c1e67,8dd3b04a,4d717f4b,a6479d8,f7f017a6,32c369c0,8679fecd,985b3c16,ff444ba0,3fe43575,8b96455a), -S(a6d818c9,dc182fd7,81343bc,b737811f,611c8499,e44a6cdb,33a36beb,7e44b545,1a8ee36e,d6e9b191,b9cbf840,3924e6b8,ac3c3f8a,cbc9a0b5,ff965d6c,734d741d), -S(f9cad333,7b82ea41,b00f3ef1,bba37b8b,fcb24e8a,175fe380,8e399b67,d21837e7,cb206854,4e7f2cda,28c035f1,b8b50009,319797da,bb498b99,d31e24e2,4fa27ca9), -S(25042b59,f9b29a9c,83d04515,c78f1c25,5b72f97f,7b387113,e88c36b9,9da3ebdc,d966ba9e,a7eb9734,e1481cb7,2df63252,7492e1c4,43f1fc9,c0efe0af,442b5a13), -S(e19c4319,b5c9a01e,b588c629,8a7c6b76,1b80bf4b,e39424e0,666ddc45,fd57e0f6,1b0a2c30,4a1bb1b1,9dd0b50d,29df625,bf958a73,46cc6b1d,81a213a3,b6636285), -S(59c26fc1,6d151c0c,7da0edf6,c474463c,587c45cb,7e407589,d15aad89,de223fa0,f7b227b5,4855c1c4,1e576431,8a7106eb,ea214686,ef815b42,db8c18ae,d5c940a5), -S(d967d546,e07ac1c2,31fd50df,a1d25a51,60594d88,3e816f6a,bd62c15c,446aeff6,8eee6c03,6e22a014,5d9cf3af,9b44e005,cd1d36ce,d7c420f5,e2db918b,e4fbf83a), -S(424b149d,9104254e,3f5772b3,7d973cf2,a46bd110,89d8f850,7666f04d,382c972b,7272ad07,54c18fbd,66e2abb3,952c526,d8113d5b,166283a3,9ac8ecb6,2b7a3e46), -S(40b4b2ac,bd299270,e64bc470,8607c586,3bb50913,45e573f3,a5e2461b,47dbc053,d094311e,fd81bb1f,4622d17e,68044107,a2a8ed54,3cd5ff8c,b531b28b,9b8ec99e), -S(79e79ded,6bc0d851,fa769b5e,8d65857c,f3c1c18e,6c990cb6,116fc45b,63e9f924,4fa89e89,ae4214fc,ba2aecdb,41984788,8154eaa6,bcbbe29f,f04a6262,7299f469), -S(a11ad5ea,59c644b2,8dd7402a,5f96a970,68d96e2e,eb77d59a,fe0c2fc,cc6b252f,38e379d5,150109df,36ed7ad3,a2daa41b,4fb9c731,718cf5e3,8f8f8cf7,d1f3d770), -S(b3002b00,ec5be154,cd8e5226,4b97f5c9,f444b305,8f59c4c,bcda5edf,9d10dc88,f7e9ae65,6ad2c823,8e8e0436,e007d821,b17d9405,984eccc4,617e3977,2f25d636), -S(8d1267b1,94da1334,fd20cb8f,77fa01cf,9e9ced90,43107e41,d1ec4057,eb6115a2,a7ba1b9e,2c6f0f19,5ff1f50a,7a8da22f,da3003fa,44b818b9,953b44d3,e6d6a0df), -S(dde6a3a0,87ef41db,2359e4e7,ca7cb064,424301e7,c5cbb5bc,4b6e504a,f3af4837,24175b1c,b4b39b7e,23718e26,be4a22bb,8bf54302,1f156234,e7f18010,d538aeb), -S(79efa584,2fb89f4e,85f556e,c4be170d,5c1ef88a,3f3f75cf,6b20fc1a,96984ad,b0704aaf,e4d8f30f,4f29fa85,6d55da13,91f5f3ce,36cdef6f,25133999,cc8541a), -S(3aa09dc0,5546977f,7369fa0a,7b60c94b,eab86a1,10d85af7,7b826475,7d67eaf5,343b4cf3,aa6c5ebc,ed041d7f,2381be57,f7fd32d0,29a2f42,a7c8821,4f425d8), -S(53fe8af9,8f9419fb,1445bb6a,94750d46,46be9f37,b7155763,88b11064,df2e6ffa,6cd77e81,84aeab9d,e9bf3093,bb9b21a3,a04a0719,fc428f3d,d5e14c8c,9b16cd7a), -S(fc395dc4,a5114dc8,bcb0f7f0,3a4d3e9,38a87a3d,78d33864,d1dc4cba,9e41e20e,c7991f6e,f72f82f6,b3147e56,74224929,fddeb8a5,97a1b1d4,8852733c,1830b941), -S(b1d25d51,b4558f5f,d0ccb868,3af9a9cf,62a169c6,91627fa5,92d80b18,36695f94,8f92258d,fcf16f4e,8415f53,e65457e8,9f090e72,5479c123,5a481464,a11cd4f9), -S(b866d6b1,42df940f,2cf28b54,c92f0c12,94e0b6a2,2a91f2ef,44bcd88c,4384480d,e6eb4f4c,bd95148f,765d8728,15652853,db1add7f,b4e27929,f19a64b7,f3b34c87)}, -{S(d4aaf32e,dd897f48,5ab16466,76d747cd,fec5b7a0,a05c917b,60c07311,45d16f89,4857e649,beff4089,2470f700,cadb73ae,d4866a84,c3f0b975,6fd8570e,df9d29d8), -S(4ebe5b8a,f3b1583c,9f41bd98,afaba549,f45c381e,c93ec9d1,4a543d87,9cefbaf3,63ed1d17,9b215f34,f1f580be,4b3f671f,2fa14689,74cd03d1,19fadae3,c92935ff), -S(20df6160,556dd3c5,a26620a8,70ff5323,cbbab94,be3e3bdd,ad8b936c,554f28f1,7168e7ab,cdbafad,26fbb5be,a09dadde,ed36c20f,c8deafaf,75a480b5,f980e981), -S(86c663f2,cc6f7ee2,50be25fd,fb35fd8e,5873481b,c477bf5b,c0f1bc1e,3f1320f,c13c5795,cce0ad92,e31240da,90a823d0,d2352314,f2852e67,cb62e0c2,8570994a), -S(3fd8085e,57f6870,b25e41d9,7df00126,150f6022,a7ede22f,d27da581,d234ccaa,c6657746,98d6ac03,ed1ea2d7,bd3f70be,86351c5d,407a4d7c,227fd7d0,c330ef04), -S(1510fcf0,b0fb5a23,c15e041,2a7f6d89,9fac4244,8ce316bf,d88fb58b,10e23118,1879dc07,b34d0a62,f0b9517f,3629ae0f,e8aa6d30,5a783f37,69bdf65,3b40408e), -S(67e9982b,c40f427,98df055c,2d8bdcc0,2ea97bad,68d34024,85498e27,d99e19e4,4f087caa,efc5fd7f,b099c134,a273635c,d1d5ace3,26e3103f,9b2fe22c,e95f288e), -S(e8eeab21,6c3395d6,d16338ea,de4108da,1c25e471,67fb13d5,99e8daaf,93e7345f,7fd2ba87,7c7266a5,65a31548,99950ea1,e5e3d73f,612addea,318ad5bc,a965228d), -S(ab20c7c8,9dd74c20,447bc762,e374c548,e7a8ac31,eec11123,1a040cd1,36e9a546,facacfb2,52eb9532,9106a26a,60128a0f,ae1d7e5c,fd39483c,aeb54dd9,231b55ee), -S(a9004211,b7cf5494,1c530a0e,d658fb6e,3b5d2ee1,37b7d7de,45fef6b5,efddbf0f,58cbaf67,5cc5a131,54eef7a1,462b5d1c,408d5d56,3553ca55,45388d77,c6391d4f), -S(8db64274,422ae0f5,6474b83a,89912fa,e3a39b6c,b3fb8370,308a572e,b6b3c020,9b71a72d,431fd44,aa8632ee,23bc678,61d96edd,b7ec72ab,4b1679b8,a4ba73e4), -S(301b330,c478189d,dce4314f,380cb2d8,38bbd416,5dfad8c4,90f2443f,2a56148b,737da0,1c05cf73,db36a1a4,5005f562,1327167f,d3b60ece,3da3705d,131903fe), -S(b9cbc7a3,4a1cbdd1,300e789d,b7ffec1c,dfe1f738,fbe1fe19,67dd7c14,92ee3ba7,5a816a0,9d08c4be,2b8d062f,200fde4c,534fbdbf,854c7e53,64532c08,60c97c01), -S(6a15e51,6f9f0a7c,25f2eac7,649285ea,d86a1e01,5a386dc,c7f94ba8,4782b45b,63eafaf4,660642ef,988aeee7,642e7c4b,71124a1c,2ca2f5c3,d4f2eec9,ea72d70e), -S(f4c696f3,34c56e08,2ab2e627,4d450f34,fa7fbce,29f3e14d,332bcadf,87d5fe0d,6ee44edf,f574d9a8,363f98b6,b863a648,27d3020,1e652935,be12041c,1bbcc7c3), -S(d2f3d5ad,237ba177,ed312bbb,1d02fb2a,e4bda20f,41f5c217,8b70dd9a,c26ee9b0,cc5912d4,2ea1af01,aa914b98,8c42cef8,46a5a059,664c8545,fc00b662,e0327920), -S(5588b0a4,757beb33,e668af5f,adf87fb3,2aed8e16,e6ceabf1,1576ae17,c6a2b843,70d8961b,ac203e89,c437b88b,ce331309,c4f7eca8,d614299c,74aef9b2,17c741de), -S(f993cd07,f6eb75ad,d41426d5,cc653886,18dde1f0,88aaf3cd,b2631eea,158373e0,1e74f804,5f60349e,a85b90e1,206f0ea4,b0cd3740,861186be,648063e8,58c2b395), -S(2cd04170,78291a50,750218b9,44a11a64,1cb75e7d,cd5cc4f9,64f53c8d,a1ef08f4,1f54a70f,f66ce343,c7ed3001,78d7b99e,49129e23,90b5a026,7ba25af5,3467b6d3), -S(52fc09a1,d4f0cc2e,c7ba6cba,1b30e1f0,b9e37f31,3bf59c33,60fc02e3,3b0c15e8,9bd14bcd,a7c7b6ab,dd7e17dd,ab81a1cf,846be336,a76858a1,8e8a0194,776f0a80), -S(90d29aba,764a9b49,1e2878c2,9b964bf6,e510af,3dd5aeb9,3fe29e13,b8f03b23,396b1f6d,e9b8fd1f,463ca064,11b09823,26cb6ab7,4bbbcaef,43031497,f149a620), -S(ce1d6e8e,ddd063f4,316cb006,b4a4213d,9e0952c8,43e6e1e7,570a35e,aad7fa53,a1abcd7,e2c23ad0,895c5aa8,82a805cd,1d7d434c,72f0c528,2ceec0b7,a7016f7c), -S(4df6e1d3,93a4be66,6fd88c75,e1e686a1,e2cb1844,f5f1303e,f7b0a751,99b42bf5,262d8b9,f7e202a3,78a51928,91ee3fc9,f269ef5d,e14dd0ff,f1fec9f4,4cdb9058), -S(f71b9bfa,bcc353a4,11a055eb,a7d6f48f,47c4e437,96382bcc,d5b882cd,a9059638,bfc1c3f8,fea7df8b,d1cd088c,b1f02e47,377d6656,9b3bd8a2,8b457ba5,e6453468), -S(ad5e9212,d3ef76d,8319fd98,72ee753f,ec99fab0,6244f4e2,a9567068,a635eb53,65fb538f,cb570092,7b0f775a,73ffb0c1,4e6c2274,e253f3a6,2dba9caa,27a3e5e4), -S(81a7dfa0,7659fdbd,57e1c8ae,20c14a80,ee8bfc51,46caa8db,b077b653,23bad4a,ac9d2438,3ef0d99f,26744be4,77e69d51,49d44ab9,84801bb,759d3a5b,7fed1e2e), -S(3bf8c1d0,a613316b,e90eab62,6788c8c3,b1641d65,d0e50245,9e5b19c1,ab1eb617,e1edb59a,8594d73,669e6f93,ca10e210,1254946b,8c9e8eac,3fa84a49,e4e2944f), -S(30f9283a,767c551c,e9fe87d9,5730eff6,fc302a4a,1810e4de,11ba62af,fa17eaae,1f383ac5,e714240d,67980617,d96b0c05,76008599,f8e3fa04,d57454e9,927e729b), -S(1c5d4ac6,91d37d0c,9db5e071,c809a59e,99056263,fbd83028,ee9530e9,c2b3f3c9,b98c7be9,7a2fb196,3d3d4a75,4f7fecce,2fbeb8fd,cf23c229,73b6875,86bd276a), -S(3dfe48e5,2f055be1,1db79fa4,501b44d8,f5ae8447,c5a1293a,a79f683f,1e1e9bf,2d7e8303,b988fc17,18c9b64c,1c03373d,27fd0c32,13c26e6c,b684ca94,49f79d5e), -S(adc4251b,c3ef6d5a,a4d6eb22,46ab2787,bc835b65,1d17ceae,489f181d,57d37248,4f0c489d,1c3a1814,a2f9c1c9,d6fe908f,4623aa44,ebaf4143,79fb8352,15234014), -S(edfe16b2,db401803,11f98920,7a2fef7,d05b2a3b,b676899f,9c6e2192,d38f93e0,1196fd0e,35a24c9,6b28b055,b4fa2f2d,a4c2aeff,3b91dd81,c2fe86c1,1d6bf682)}, -{S(b4b57b34,6e1b41b,7394e655,e059cc93,44c5d83e,f0ef17db,2789db5d,13777b78,6fa187a7,4d983b7e,cea6a268,61039430,63e599e7,cba73144,fe3eb23,677c6265), -S(9937238,7300054a,1a8713b7,6942f003,99818b28,6c6fba5d,ca60b9da,1aa7767,6c003e1,848ce30a,65601eb,e7b76acf,b2e122b6,882d7439,f463c042,ef1b31a), -S(ebd177f8,b5757665,58851c7f,a7ada38b,e3596080,f2679181,f994efd3,82714784,d0fe8eb0,97c852f7,b284d5f,bd81f77f,79c35af7,cc30338f,4e63211e,9e20a244), -S(367ef258,b279f923,a18215b7,67d396e4,c6bc874d,2be6b369,b01afffa,2e041741,bd961242,2452eddb,33831dcf,fb3a0273,30ef141f,6db77d91,5bec2ecb,553b6e6c), -S(d89f40c4,f752cff4,5bae5762,37f5096e,f27d46d0,d934d4de,c3011a28,59464e8e,9d32661e,e2319d6,f6427ea,a3014b5,cf98306c,666c4a9e,970dba2e,65e04886), -S(ef6ff862,1d84c5d5,22e490f4,db21181f,a17bafea,3e097868,4f1f0215,759772b9,ae006f11,aa85db2d,3624cf51,ae319ad2,8b4970e7,eac03301,1eb15db8,dc59d62b), -S(8b0a1b1b,d476bbfb,6da1d071,68d3a988,3b49802f,8ffa04a3,bbba1313,17c67a00,d8c74ae5,65c38597,8d9fda2e,dff6b932,1512e40b,ec5b62e2,59d4d81c,9b657b55), -S(9aa9250f,12ffde38,21384434,849d7eb7,bcafbae5,9a3b861f,68a3addb,d75d3715,19b4b1a8,8d8bfeee,38b54564,30d5f73e,ed0365fe,49092d4a,2f52fa12,b65e3ac7), -S(aaccc00f,55e96f0c,e66d9b43,12f9abd2,6772d8b4,30a6c62,edd2aab4,97acbc22,5af203cf,97d11147,82374056,f012f5f9,2825476a,820dce2e,6e1c4b33,cef5337c), -S(43c34546,2836b544,ddd6e432,6aa19b4a,9de7fdfb,86f43cae,ce98ce7c,32b1ccaf,dd518249,f1fbc1c7,1f905860,17a6f60b,15be97d4,18c66d42,f4f9adcd,d722c096), -S(9a38eb25,935441ab,8983097a,d58c821f,d784f091,5f85dc26,3f0c020b,b80c39a0,d8e6dc57,41e4ba5c,576179e8,9a6dcb4a,bd7178c6,13a1100b,e2bd731b,f3e819e2), -S(6b10527,204a4f7c,e8afcacc,fe771634,376f18da,f12774e,50f23a90,9efe0223,b443a451,529b4208,c8c98904,f5eb2ee,2e2ede2d,80ca50c5,aa29b95a,714181a), -S(1a88fecc,71d7550a,abf7faf0,8e884e95,835f6dc8,1815d2d7,7dab66ea,b238d6b2,82cf6711,1dd38ff,d0daebbc,ea2c064b,17b6b21d,34804f93,4a037936,9edec692), -S(a6b1751,f30507fe,5927b6d4,a92ebbbd,77358c02,9b750d05,a56e4d41,efb99144,ccf7c048,a2a0983d,fdcccfd,a071b80,e8035866,c479ea3a,3bbe7c80,12dfd618), -S(e186601e,8b545292,f23ae7fa,4cadc80f,1fcaa1a3,430ddec6,cfd2af47,c835cdf9,fd471f16,7c3683c9,2e5fc0c2,89b646a5,c8ebda6d,5b6da213,d862c3f6,2c292e9c), -S(91b3935,d8ce2b80,c179ee0b,87850140,4c418c7f,7cf94e4a,64b9fc9c,e396a093,45a5043b,8184546c,9083982f,550807d7,d61fe677,ce73ef21,9b3aa573,97c4eca1), -S(3fbe61fd,2a387654,dfc428e7,dac09e91,5e1ae7d6,d3794288,743f2535,20858ef5,206fd9a0,e3265118,e0a6475c,4df87e43,cc7c8898,59d8aa08,23b6dfff,b68b34d7), -S(31a35020,697d9d52,55476289,ce4fcbdc,4e1e0690,c2c36d1b,a4f4640f,e4c5ba18,91f660f9,159d463a,857f08ad,fc3c5ddd,804507c5,92f73de4,2ee44555,da538553), -S(7dc6b83a,10f26e71,e12c0bd,7ebcccc6,61b4394a,68f576fe,bfca1c23,256e8aa2,b4796977,bd386b98,f3e2fa8e,798b6548,fae52a80,40bb12ea,7e6ad675,64fc8736), -S(67a9c3ff,9c7b99b2,5318ff9e,2b85ee23,ec244655,8042ea8b,d880e23e,7d3ce221,a7bcbbbb,895ca7b1,847a43fa,98809ce4,98016123,bbb3c099,7d34debd,cb023f8d), -S(36602997,eba2c6c5,aab4cb65,8d4efd46,65ab3965,f643ff66,831646dc,f6443bf3,c82d0e80,ef775f9c,7ec7862a,e3158556,a57038d,e6850dd1,e349629c,2546239), -S(9eb9244b,299bfd76,f63bb140,ae2f42a1,4af1e072,83f8259f,6478ac03,d411df24,e43f91da,13c2ba21,a9d17d2f,7a8a629d,9051346,93a6552a,538d590,9d2bdd38), -S(ba4450fa,27d57993,3d949a1a,66013906,7d1a9716,6794993d,e45d9426,b4bfc5ed,8e3f3b9b,d8cb8210,7a5ae2af,92b96259,b73633f,6528ac04,20c3e101,6bb6d8a8), -S(e6d5335f,b67abd36,2712c7fe,575ee769,53d488b,236e8589,5664fb04,7f385248,9e255154,e070a5bb,e98e97f6,281fb999,a75e68ea,7681fdf6,fea093bd,919aa5a4), -S(63c099a9,300a331a,3bc4348a,a373e514,c84a810e,1ea8a8d1,4ac8d7cb,818eb534,ed7d4029,3cc4a086,b1d40c24,6086109,a02dbcb5,a864777,27939024,6fd6bf91), -S(7088617f,66cd93f,8130eaeb,874c3f77,3bcb0daa,78923b70,a65512a2,992554dc,5a3ff995,3c712066,291ac4a2,dfc2573e,1d0aed56,75ef526b,b15f61b0,d20f8156), -S(cc354aaf,746d756b,9387730f,2f12b999,4fcd815c,6d25cdab,2e1185aa,4aa639b3,fb1dead9,4fd76859,1aac8d79,5c337924,dc155fbe,5cd5c953,4d55ee31,f6d284a6), -S(e7e47c3a,e2bf4307,7f33ec3d,ac1ae2a7,5c669e61,e248f588,590cfe07,3e2186e0,46e9c4d5,4429fdcf,5efb375e,18f46cc8,3fa7a403,6013777f,e450e228,aebd4cd0), -S(c6ed5e63,28ec31b1,37041108,42d4ac23,fbb883bb,349d88db,1d747cf7,325fe9cc,21b8bfa4,b62807cf,d6cd11ed,a38084d5,7bb068d4,9f0dd30e,f3f431e2,b57022e4), -S(331924c7,50b3417e,48e279ff,6ed7f3dc,ba2e121e,9f69f8fb,e64093b6,c38a8cc6,357086be,e4cc0fe7,d45a49fe,41d004ce,80466165,316164ab,3b171f03,b9a7841f), -S(b4319cc9,f3e0d3b,313626ae,5385796b,c49b300c,88ba4553,dec0aa4a,77829372,b8f82bb6,6590afd4,48501f,63de3a5d,8f84edea,35c1ee44,88d6333e,f522a808), -S(da433d5e,11ceccc0,abc5c762,6ce7bab4,2e89b221,f785c409,282de545,f3fceb19,1b67242c,de57efcf,e214423b,506a1ade,718803d2,6dd84d88,97b18ede,590a2fcb)}, -{S(ebae7464,ece277b8,309d056c,cf3775e2,11a77aa,81c316a4,b6b7b953,6f90f539,62a4d6a2,95fdd811,f2051715,322f17e5,1753c9d0,835ef9a0,3e8dc9f5,c69bda31), -S(5b20700c,1af63394,a3e4cadb,b0ea682e,19cf495a,b908418a,d41f4c6c,ea4477f0,8435d15e,34b03a22,ca89c73d,326c2f88,142d2e23,8964ef6d,99287125,79738f78), -S(b2f25f91,138b974b,561328c0,92f50fdf,8a694004,fd4879d0,12a4a6cc,c8059d1d,d9ec0b2d,b8e81b2,f6feaf55,9776ff78,cda3401b,47826de0,ca06e579,9d866c09), -S(64e79790,7783d6fb,321eb785,acdeb2ff,4628270,fec3342c,527c8db0,a34c516e,c0c4da5d,abf3da9c,a8613f82,ca28e84,a1a18376,c9967c08,aaf70bea,7a2f34c2), -S(a50cae84,a08f4f32,4984853a,d4c6bdaf,77eaa788,9cb8fe95,72fd56e,9078ee73,120ecbf,76e47b38,503067c8,36853003,60ed261a,40fdf440,161ef2cd,19786b93), -S(76ff3ac8,80a451a9,6741fc70,82bc4c82,7bd51c08,95eea8c8,b422b8a9,96ba4794,25555d71,d4313a60,b189a154,58e0a40,c643c204,277334e,966e2abd,3a23f6c3), -S(307e5caa,8b708760,3d9f845b,b78f4f10,72c49c10,9747f91d,192f8d6e,70c0f4be,f5992f76,37167e1d,55cd31a6,1cdb4756,85eb1503,34fb6009,e0240a18,fa8302b8), -S(d8e62e47,b28fd165,4d420137,884dcf21,c10cb159,d9885843,da34b0d9,d09b2758,675c75b4,b903ad28,2055a71b,2c470e2b,1dce69bf,ecf160cf,3a027de2,55b723a9), -S(ec5639c7,73dac23d,3008dabf,732dc005,3154703d,26ee3bbc,7689286e,4a73e39f,aaa5ea4a,2cf5c23d,57cdd0d8,8accbbf9,9fd2c213,97bb45f8,83547876,3aab1248), -S(3d928ee3,2065557a,27722f08,5202f48f,40917ed6,c7ac1963,2a122226,8b0cb9df,ece112a4,e7a05ad6,17c2fd83,76f89102,9eb94eb0,930fb23c,a342d7f1,f021a0c7), -S(616228a5,cc6c3a92,cd694cec,4b2b8574,5dfffa90,b2a36d8f,32eaa6cc,2530de51,50d8d140,4d506a78,700f8e82,967b36a5,1b4de644,a8e22271,d509c8d2,4adf3148), -S(6f85f308,e847b145,c13a07be,bebdd4ba,6c138939,6afd8670,733f44a8,969406d0,864bcde1,be36c9c7,b7e04ef8,cd2366e2,b3c22902,5ee7efce,d005ef5b,ff7dae2b), -S(f3d1ecc3,53a82621,1bd78f0f,aa029076,c6ca779,9bdc54b2,128fa3d2,aec00c6d,75aa0cf9,fd0b7bed,19183e34,58142f66,c94a5aa9,3915435e,ae51c1fe,96625ccd), -S(a5918de3,f18cd8d1,2a234f9f,3a19fcaa,2d83671d,ad566f16,8aea2b1f,b9de41b0,c515dda6,43c0f6c8,d8fea16,5d595917,16b7f521,43d3b941,f28585ed,8a49c06c), -S(3c49e2ef,1d2d3464,81e05fa0,33366609,1615ebcf,535f68,be257f35,7bd91592,57901e0a,c8af3a31,aa404987,72c903fd,175c9b00,5c7458ee,ed667f11,57754132), -S(6c45ff2,c0c30320,83c343e6,dc80b4f7,bb64502a,52f412ff,ada521d4,a544a9f0,e9936037,f1e641eb,1cd6f801,a25271d3,cffe67d,c9bd7162,babf9855,9628a9a8), -S(66df5d95,acdf4260,ee0e465c,e3916d79,395df522,aa086aeb,6c283bb7,18296d46,cb1f3deb,8aea0337,625f46dd,903416d1,5647be91,1633c4c0,cf0e629a,413476fc), -S(428bbba5,ef351762,9eee4059,a3339213,40c7fee2,5ccb051c,88d75e53,ba618858,ef18809c,28227ccc,115876df,b3f378cd,374c0670,2c658501,7990e767,922c3999), -S(e8993820,d782657,ed8badc2,d515e360,df336730,860ef49e,65ca58dd,1a385815,feb41189,16c7e8f6,53c7f5a6,5fd7b6be,7a029814,149c4645,847073be,770959de), -S(2b77e42a,63502244,d6c7d1be,54b7857,9e2742d2,7143d689,fa3f70a3,5986ccf1,721e9da8,bee88ad4,2155dc9a,28be505,86648378,1d6af5b1,382cd47d,771e6428), -S(acffce3a,ed6beea3,2ad71633,21e1ca53,6f69ce76,fb5cd394,9d9dcc14,bbcee96,5384c97d,eac946c0,afc85b54,f3a56b79,fe263bff,63e1894c,6d52ef1b,9b456602), -S(e13d8d4b,25bece8d,90a008e4,c004824e,223b06b,7cf65ebd,1215e910,2e67b639,3e92b1f,14cbee57,9640b377,6ed5938f,9aee0e11,b139a678,3f207cf4,6dd7e20b), -S(d8f356d9,d2498eaa,b3fa12a,cb64562b,dff3e270,c7809a31,25a9ae65,9cb1f3c5,a5403cda,2d499a7c,7402b57c,c9f99e3,64f5085a,91fd8cfd,8a67c7a8,dbce04fb), -S(350062b5,22fb5d0a,8c79a5db,29e92216,79b9fbc6,3e1f95ca,e7d087f3,fedffc49,74cacf57,5e79c85b,d7e77a40,796e8750,a3ca57f2,a47cce8f,3d2de02d,b014df0b), -S(c159e630,9ab23135,58ebfb6b,22edaf93,eac8e16,77cd9f3b,1cd9492,20bf8e54,99244263,53f32608,831c6d74,da51d61,c344defe,f4c1e401,6a3db44b,4c57f4ae), -S(9e568b70,36a2daa2,fe7a3a52,49c56eb8,3fe4afa2,decebd60,c6c3245f,17bc6a13,b6643644,274eab9f,5e83c598,14978681,17c5a078,765156ae,3cb65fd3,830e06ae), -S(9bee7471,6b6c1ff5,62c1bc36,57a65de3,99a91d72,115703f4,4c3819a1,87828478,bb23a3da,ed34028a,7d39a7ed,fe2e23b,73e085a2,d6c2e51a,ef2a2076,a7c902ad), -S(c430c044,91228a7a,ea835698,ecf0f552,9aeef469,a36305cb,52902ccd,1c897473,40d0ee56,61cca82,80d11da,bffe97c4,f10c93aa,5e07224c,154b666e,bcd58c74), -S(2be073f6,b294a01b,eda0b0db,6832e4bc,23ef3889,7a859853,5ee726ef,ae0f15b1,6153f846,349c2a98,26008065,8be2a7d8,311a5e70,cc310ff8,7935a901,8d575813), -S(2934de46,a6d921f8,720567e6,b46e6362,36a7ed53,483b13ed,20958452,3225accd,5979698,26927cd7,abfe4c57,c53fc72a,48b71679,174c749d,aecdb057,e6a2d961), -S(4e9991b,92fa8c4e,4e8efe45,66966073,319e80d3,a54d4b7a,b61cfcc4,7ddaa5d5,9d03ea22,21d4d80e,261952e2,73f6a8cf,c31f6091,e5aa0a8f,2281ffbf,1345df9e), -S(ff3d6136,ffac5b0c,bfc6c5c0,c30dc01a,7ea3d56c,20bd3103,b178e3d3,ae180068,eccdc641,7b1bfff1,bf2fc8d3,2269523e,ab89890d,bffe0a19,8f594490,e7739bb8)} -#else -# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build. -#endif -}; -#undef S diff --git a/external/secp256k1/src/precomputed_ecmult_gen.h b/external/secp256k1/src/precomputed_ecmult_gen.h deleted file mode 100644 index 283738a5ce..0000000000 --- a/external/secp256k1/src/precomputed_ecmult_gen.h +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************************* - * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *********************************************************************************/ - -#ifndef SECP256K1_PRECOMPUTED_ECMULT_GEN_H -#define SECP256K1_PRECOMPUTED_ECMULT_GEN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "group.h" -#include "ecmult_gen.h" -#ifdef EXHAUSTIVE_TEST_ORDER -static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; -#else -extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; -#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_PRECOMPUTED_ECMULT_GEN_H */ diff --git a/external/secp256k1/src/scalar.h b/external/secp256k1/src/scalar.h deleted file mode 100644 index 70f49b1cf2..0000000000 --- a/external/secp256k1/src/scalar.h +++ /dev/null @@ -1,105 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_H -#define SECP256K1_SCALAR_H - -#include "util.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -#include "scalar_low.h" -#elif defined(SECP256K1_WIDEMUL_INT128) -#include "scalar_4x64.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "scalar_8x32.h" -#else -#error "Please select wide multiplication implementation" -#endif - -/** Clear a scalar to prevent the leak of sensitive data. */ -static void secp256k1_scalar_clear(secp256k1_scalar *r); - -/** Access bits (1 < count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ -static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count); - -/** Access bits (1 < count <= 32) from a scalar. offset + count must be < 256. Not constant time in offset and count. */ -static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); - -/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. - * In: bin: pointer to a 32-byte array. - * Out: r: scalar to be set. - * overflow: non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL). - */ -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); - -/** Set a scalar from a big endian byte array and returns 1 if it is a valid - * seckey and 0 otherwise. */ -static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin); - -/** Set a scalar to an unsigned integer. */ -static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); - -/** Convert a scalar to a byte array. */ -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); - -/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); - -/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); - -/** Multiply two scalars (modulo the group order). */ -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); - -/** Compute the inverse of a scalar (modulo the group order). */ -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Compute the complement of a scalar (modulo the group order). */ -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Multiply a scalar with the multiplicative inverse of 2. */ -static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Check whether a scalar equals zero. */ -static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); - -/** Check whether a scalar equals one. */ -static int secp256k1_scalar_is_one(const secp256k1_scalar *a); - -/** Check whether a scalar, considered as an nonnegative integer, is even. */ -static int secp256k1_scalar_is_even(const secp256k1_scalar *a); - -/** Check whether a scalar is higher than the group order divided by 2. */ -static int secp256k1_scalar_is_high(const secp256k1_scalar *a); - -/** Conditionally negate a number, in constant time. - * Returns -1 if the number was negated, 1 otherwise */ -static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); - -/** Compare two scalars. */ -static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); - -/** Find r1 and r2 such that r1+r2*2^128 = k. */ -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); -/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their - * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is - * required that r1, r2, and k all point to different objects. */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k); - -/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag); - -/** Check invariants on a scalar (no-op unless VERIFY is enabled). */ -static void secp256k1_scalar_verify(const secp256k1_scalar *r); -#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r) - -#endif /* SECP256K1_SCALAR_H */ diff --git a/external/secp256k1/src/scalar_4x64.h b/external/secp256k1/src/scalar_4x64.h deleted file mode 100644 index 700964291e..0000000000 --- a/external/secp256k1/src/scalar_4x64.h +++ /dev/null @@ -1,19 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef struct { - uint64_t d[4]; -} secp256k1_scalar; - -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_4x64_impl.h b/external/secp256k1/src/scalar_4x64_impl.h deleted file mode 100644 index 807b9b70ab..0000000000 --- a/external/secp256k1/src/scalar_4x64_impl.h +++ /dev/null @@ -1,1000 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "checkmem.h" -#include "int128.h" -#include "modinv64_impl.h" -#include "util.h" - -/* Limbs of the secp256k1 order. */ -#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) -#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) -#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) -#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) - -/* Limbs of 2^256 minus the secp256k1 order. */ -#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) -#define SECP256K1_N_C_1 (~SECP256K1_N_1) -#define SECP256K1_N_C_2 (1) - -/* Limbs of half the secp256k1 order. */ -#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) -#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) -#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) -#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) - -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - - SECP256K1_SCALAR_VERIFY(r); -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); - - return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK(offset + count <= 256); - - if ((offset + count - 1) >> 6 == offset >> 6) { - return secp256k1_scalar_get_bits_limb32(a, offset, count); - } else { - VERIFY_CHECK((offset >> 6) + 1 < 4); - return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count)); - } -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ - no |= (a->d[2] < SECP256K1_N_2); - yes |= (a->d[2] > SECP256K1_N_2) & ~no; - no |= (a->d[1] < SECP256K1_N_1); - yes |= (a->d[1] > SECP256K1_N_1) & ~no; - yes |= (a->d[0] >= SECP256K1_N_0) & ~no; - return yes; -} - -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { - secp256k1_uint128 t; - VERIFY_CHECK(overflow <= 1); - - secp256k1_u128_from_u64(&t, r->d[0]); - secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); - r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[1]); - secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); - r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[2]); - secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); - r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[3]); - r->d[3] = secp256k1_u128_to_u64(&t); - - SECP256K1_SCALAR_VERIFY(r); - return overflow; -} - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - int overflow; - secp256k1_uint128 t; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - secp256k1_u128_from_u64(&t, a->d[0]); - secp256k1_u128_accum_u64(&t, b->d[0]); - r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, a->d[1]); - secp256k1_u128_accum_u64(&t, b->d[1]); - r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, a->d[2]); - secp256k1_u128_accum_u64(&t, b->d[2]); - r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, a->d[3]); - secp256k1_u128_accum_u64(&t, b->d[3]); - r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); - VERIFY_CHECK(overflow == 0 || overflow == 1); - secp256k1_scalar_reduce(r, overflow); - - SECP256K1_SCALAR_VERIFY(r); - return overflow; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - secp256k1_uint128 t; - volatile int vflag = flag; - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(bit < 256); - - bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ - secp256k1_u128_from_u64(&t, r->d[0]); - secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); - r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[1]); - secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); - r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[2]); - secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); - r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[3]); - secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); - r->d[3] = secp256k1_u128_to_u64(&t); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - int over; - r->d[0] = secp256k1_read_be64(&b32[24]); - r->d[1] = secp256k1_read_be64(&b32[16]); - r->d[2] = secp256k1_read_be64(&b32[8]); - r->d[3] = secp256k1_read_be64(&b32[0]); - over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); - if (overflow) { - *overflow = over; - } - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - SECP256K1_SCALAR_VERIFY(a); - - secp256k1_write_be64(&bin[0], a->d[3]); - secp256k1_write_be64(&bin[8], a->d[2]); - secp256k1_write_be64(&bin[16], a->d[1]); - secp256k1_write_be64(&bin[24], a->d[0]); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); - secp256k1_uint128 t; - SECP256K1_SCALAR_VERIFY(a); - - secp256k1_u128_from_u64(&t, ~a->d[0]); - secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); - r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, ~a->d[1]); - secp256k1_u128_accum_u64(&t, SECP256K1_N_1); - r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, ~a->d[2]); - secp256k1_u128_accum_u64(&t, SECP256K1_N_2); - r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, ~a->d[3]); - secp256k1_u128_accum_u64(&t, SECP256K1_N_3); - r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { - /* Writing `/` for field division and `//` for integer division, we compute - * - * a/2 = (a - (a&1))/2 + (a&1)/2 - * = (a >> 1) + (a&1 ? 1/2 : 0) - * = (a >> 1) + (a&1 ? n//2+1 : 0), - * - * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). - * For n//2, we have the constants SECP256K1_N_H_0, ... - * - * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: - * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 - * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 - * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. - */ - uint64_t mask = -(uint64_t)(a->d[0] & 1U); - secp256k1_uint128 t; - SECP256K1_SCALAR_VERIFY(a); - - secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63)); - secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask); - r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63)); - secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask); - r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63)); - secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask); - r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); - r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask); -#ifdef VERIFY - /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation - * in full 128 bits to make sure the top 64 bits are indeed zero. */ - secp256k1_u128_accum_u64(&t, a->d[3] >> 1); - secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask); - secp256k1_u128_rshift(&t, 64); - VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0); - - SECP256K1_SCALAR_VERIFY(r); -#endif -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - SECP256K1_SCALAR_VERIFY(a); - - no |= (a->d[3] < SECP256K1_N_H_3); - yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; - no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ - no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; - yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; - return yes; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - volatile int vflag = flag; - uint64_t mask = -vflag; - uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; - secp256k1_uint128 t; - SECP256K1_SCALAR_VERIFY(r); - - secp256k1_u128_from_u64(&t, r->d[0] ^ mask); - secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); - r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[1] ^ mask); - secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask); - r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[2] ^ mask); - secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask); - r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); - secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); - secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); - r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; - - SECP256K1_SCALAR_VERIFY(r); - return 2 * (mask == 0) - 1; -} - -/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ - -/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd(a,b) { \ - uint64_t tl, th; \ - { \ - secp256k1_uint128 t; \ - secp256k1_u128_mul(&t, a, b); \ - th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = secp256k1_u128_to_u64(&t); \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ -} - -/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ -#define muladd_fast(a,b) { \ - uint64_t tl, th; \ - { \ - secp256k1_uint128 t; \ - secp256k1_u128_mul(&t, a, b); \ - th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = secp256k1_u128_to_u64(&t); \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK(c1 >= th); \ -} - -/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define sumadd(a) { \ - unsigned int over; \ - c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)); \ - c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over); /* never overflows by contract */ \ -} - -/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ -#define sumadd_fast(a) { \ - c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ - VERIFY_CHECK(c2 == 0); \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ -#define extract(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = c2; \ - c2 = 0; \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ -#define extract_fast(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = 0; \ - VERIFY_CHECK(c2 == 0); \ -} - -static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { -#ifdef USE_ASM_X86_64 - /* Reduce 512 bits into 385. */ - uint64_t m0, m1, m2, m3, m4, m5, m6; - uint64_t p0, p1, p2, p3, p4; - uint64_t c; - - __asm__ __volatile__( - /* Preload. */ - "movq 32(%%rsi), %%r11\n" - "movq 40(%%rsi), %%r12\n" - "movq 48(%%rsi), %%r13\n" - "movq 56(%%rsi), %%r14\n" - /* Initialize r8,r9,r10 */ - "movq 0(%%rsi), %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += n0 * c0 */ - "movq %8, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract m0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += l1 */ - "addq 8(%%rsi), %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += n1 * c0 */ - "movq %8, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n0 * c1 */ - "movq %9, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract m1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += l2 */ - "addq 16(%%rsi), %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n2 * c0 */ - "movq %8, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n1 * c1 */ - "movq %9, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n0 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract m2 */ - "movq %%r10, %q2\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += l3 */ - "addq 24(%%rsi), %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n3 * c0 */ - "movq %8, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n2 * c1 */ - "movq %9, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n1 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* extract m3 */ - "movq %%r8, %q3\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += n3 * c1 */ - "movq %9, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n2 */ - "addq %%r13, %%r9\n" - "adcq $0, %%r10\n" - "adcq $0, %%r8\n" - /* extract m4 */ - "movq %%r9, %q4\n" - /* (r10,r8) += n3 */ - "addq %%r14, %%r10\n" - "adcq $0, %%r8\n" - /* extract m5 */ - "movq %%r10, %q5\n" - /* extract m6 */ - "movq %%r8, %q6\n" - : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) - : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); - - SECP256K1_CHECKMEM_MSAN_DEFINE(&m0, sizeof(m0)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m1, sizeof(m1)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m2, sizeof(m2)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m3, sizeof(m3)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m4, sizeof(m4)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m5, sizeof(m5)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&m6, sizeof(m6)); - - /* Reduce 385 bits into 258. */ - __asm__ __volatile__( - /* Preload */ - "movq %q9, %%r11\n" - "movq %q10, %%r12\n" - "movq %q11, %%r13\n" - /* Initialize (r8,r9,r10) */ - "movq %q5, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += m4 * c0 */ - "movq %12, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract p0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += m1 */ - "addq %q6, %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += m5 * c0 */ - "movq %12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += m4 * c1 */ - "movq %13, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract p1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += m2 */ - "addq %q7, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m6 * c0 */ - "movq %12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m5 * c1 */ - "movq %13, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m4 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract p2 */ - "movq %%r10, %q2\n" - /* (r8,r9) += m3 */ - "addq %q8, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += m6 * c1 */ - "movq %13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* (r8,r9) += m5 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - /* extract p3 */ - "movq %%r8, %q3\n" - /* (r9) += m6 */ - "addq %%r13, %%r9\n" - /* extract p4 */ - "movq %%r9, %q4\n" - : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) - : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); - - SECP256K1_CHECKMEM_MSAN_DEFINE(&p0, sizeof(p0)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&p1, sizeof(p1)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&p2, sizeof(p2)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&p3, sizeof(p3)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&p4, sizeof(p4)); - - /* Reduce 258 bits into 256. */ - __asm__ __volatile__( - /* Preload */ - "movq %q5, %%r10\n" - /* (rax,rdx) = p4 * c0 */ - "movq %7, %%rax\n" - "mulq %%r10\n" - /* (rax,rdx) += p0 */ - "addq %q1, %%rax\n" - "adcq $0, %%rdx\n" - /* extract r0 */ - "movq %%rax, 0(%q6)\n" - /* Move to (r8,r9) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p1 */ - "addq %q2, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += p4 * c1 */ - "movq %8, %%rax\n" - "mulq %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* Extract r1 */ - "movq %%r8, 8(%q6)\n" - "xorq %%r8, %%r8\n" - /* (r9,r8) += p4 */ - "addq %%r10, %%r9\n" - "adcq $0, %%r8\n" - /* (r9,r8) += p2 */ - "addq %q3, %%r9\n" - "adcq $0, %%r8\n" - /* Extract r2 */ - "movq %%r9, 16(%q6)\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p3 */ - "addq %q4, %%r8\n" - "adcq $0, %%r9\n" - /* Extract r3 */ - "movq %%r8, 24(%q6)\n" - /* Extract c */ - "movq %%r9, %q0\n" - : "=g"(c) - : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); - - SECP256K1_CHECKMEM_MSAN_DEFINE(r, sizeof(*r)); - SECP256K1_CHECKMEM_MSAN_DEFINE(&c, sizeof(c)); - -#else - secp256k1_uint128 c128; - uint64_t c, c0, c1, c2; - uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; - uint64_t m0, m1, m2, m3, m4, m5; - uint32_t m6; - uint64_t p0, p1, p2, p3; - uint32_t p4; - - /* Reduce 512 bits into 385. */ - /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ - c0 = l[0]; c1 = 0; c2 = 0; - muladd_fast(n0, SECP256K1_N_C_0); - extract_fast(m0); - sumadd_fast(l[1]); - muladd(n1, SECP256K1_N_C_0); - muladd(n0, SECP256K1_N_C_1); - extract(m1); - sumadd(l[2]); - muladd(n2, SECP256K1_N_C_0); - muladd(n1, SECP256K1_N_C_1); - sumadd(n0); - extract(m2); - sumadd(l[3]); - muladd(n3, SECP256K1_N_C_0); - muladd(n2, SECP256K1_N_C_1); - sumadd(n1); - extract(m3); - muladd(n3, SECP256K1_N_C_1); - sumadd(n2); - extract(m4); - sumadd_fast(n3); - extract_fast(m5); - VERIFY_CHECK(c0 <= 1); - m6 = c0; - - /* Reduce 385 bits into 258. */ - /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ - c0 = m0; c1 = 0; c2 = 0; - muladd_fast(m4, SECP256K1_N_C_0); - extract_fast(p0); - sumadd_fast(m1); - muladd(m5, SECP256K1_N_C_0); - muladd(m4, SECP256K1_N_C_1); - extract(p1); - sumadd(m2); - muladd(m6, SECP256K1_N_C_0); - muladd(m5, SECP256K1_N_C_1); - sumadd(m4); - extract(p2); - sumadd_fast(m3); - muladd_fast(m6, SECP256K1_N_C_1); - sumadd_fast(m5); - extract_fast(p3); - p4 = c0 + m6; - VERIFY_CHECK(p4 <= 2); - - /* Reduce 258 bits into 256. */ - /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - secp256k1_u128_from_u64(&c128, p0); - secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4); - r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); - secp256k1_u128_accum_u64(&c128, p1); - secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4); - r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); - secp256k1_u128_accum_u64(&c128, p2); - secp256k1_u128_accum_u64(&c128, p4); - r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); - secp256k1_u128_accum_u64(&c128, p3); - r->d[3] = secp256k1_u128_to_u64(&c128); - c = secp256k1_u128_hi_u64(&c128); -#endif - - /* Final reduction of r. */ - secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); -} - -static void secp256k1_scalar_mul_512(uint64_t *l8, const secp256k1_scalar *a, const secp256k1_scalar *b) { -#ifdef USE_ASM_X86_64 - const uint64_t *pb = b->d; - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r15\n" - "movq 8(%%rdi), %%rbx\n" - "movq 16(%%rdi), %%rcx\n" - "movq 0(%%rdx), %%r11\n" - "movq 8(%%rdx), %%r12\n" - "movq 16(%%rdx), %%r13\n" - "movq 24(%%rdx), %%r14\n" - /* (rax,rdx) = a0 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - /* Extract l8[0] */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a0 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a1 * b0 */ - "movq %%rbx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l8[1] */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a0 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * b1 */ - "movq %%rbx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a2 * b0 */ - "movq %%rcx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l8[2] */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += a0 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Preload a3 */ - "movq 24(%%rdi), %%r15\n" - /* (r10,r8,r9) += a1 * b2 */ - "movq %%rbx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a2 * b1 */ - "movq %%rcx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a3 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l8[3] */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a1 * b3 */ - "movq %%rbx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * b2 */ - "movq %%rcx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a3 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l8[4] */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a2 * b3 */ - "movq %%rcx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a3 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l8[5] */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l8[6] */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l8[7] */ - "movq %%r8, 56(%%rsi)\n" - : "+d"(pb) - : "S"(l8), "D"(a->d) - : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); - - SECP256K1_CHECKMEM_MSAN_DEFINE(l8, sizeof(*l8) * 8); - -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l8[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], b->d[0]); - extract_fast(l8[0]); - muladd(a->d[0], b->d[1]); - muladd(a->d[1], b->d[0]); - extract(l8[1]); - muladd(a->d[0], b->d[2]); - muladd(a->d[1], b->d[1]); - muladd(a->d[2], b->d[0]); - extract(l8[2]); - muladd(a->d[0], b->d[3]); - muladd(a->d[1], b->d[2]); - muladd(a->d[2], b->d[1]); - muladd(a->d[3], b->d[0]); - extract(l8[3]); - muladd(a->d[1], b->d[3]); - muladd(a->d[2], b->d[2]); - muladd(a->d[3], b->d[1]); - extract(l8[4]); - muladd(a->d[2], b->d[3]); - muladd(a->d[3], b->d[2]); - extract(l8[5]); - muladd_fast(a->d[3], b->d[3]); - extract_fast(l8[6]); - VERIFY_CHECK(c1 == 0); - l8[7] = c0; -#endif -} - -#undef sumadd -#undef sumadd_fast -#undef muladd -#undef muladd_fast -#undef extract -#undef extract_fast - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - uint64_t l[8]; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - secp256k1_scalar_mul_512(l, a, b); - secp256k1_scalar_reduce_512(r, l); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { - SECP256K1_SCALAR_VERIFY(k); - - r1->d[0] = k->d[0]; - r1->d[1] = k->d[1]; - r1->d[2] = 0; - r1->d[3] = 0; - r2->d[0] = k->d[2]; - r2->d[1] = k->d[3]; - r2->d[2] = 0; - r2->d[3] = 0; - - SECP256K1_SCALAR_VERIFY(r1); - SECP256K1_SCALAR_VERIFY(r2); -} - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { - uint64_t l[8]; - unsigned int shiftlimbs; - unsigned int shiftlow; - unsigned int shifthigh; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - VERIFY_CHECK(shift >= 256); - - secp256k1_scalar_mul_512(l, a, b); - shiftlimbs = shift >> 6; - shiftlow = shift & 0x3F; - shifthigh = 64 - shiftlow; - r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); - - SECP256K1_SCALAR_VERIFY(r); -} - -static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { - uint64_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); - - mask0 = vflag + ~((uint64_t)0); - mask1 = ~mask0; - r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); - r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); - r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); - r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) { - const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; - - /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and - * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). - */ - VERIFY_CHECK(a0 >> 62 == 0); - VERIFY_CHECK(a1 >> 62 == 0); - VERIFY_CHECK(a2 >> 62 == 0); - VERIFY_CHECK(a3 >> 62 == 0); - VERIFY_CHECK(a4 >> 8 == 0); - - r->d[0] = a0 | a1 << 62; - r->d[1] = a1 >> 2 | a2 << 60; - r->d[2] = a2 >> 4 | a3 << 58; - r->d[3] = a3 >> 6 | a4 << 56; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) { - const uint64_t M62 = UINT64_MAX >> 2; - const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; - SECP256K1_SCALAR_VERIFY(a); - - r->v[0] = a0 & M62; - r->v[1] = (a0 >> 62 | a1 << 2) & M62; - r->v[2] = (a1 >> 60 | a2 << 4) & M62; - r->v[3] = (a2 >> 58 | a3 << 6) & M62; - r->v[4] = a3 >> 56; -} - -static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_scalar = { - {{0x3FD25E8CD0364141LL, 0x2ABB739ABD2280EELL, -0x15LL, 0, 256}}, - 0x34F20099AA774EC1LL -}; - -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { - secp256k1_modinv64_signed62 s; -#ifdef VERIFY - int zero_in = secp256k1_scalar_is_zero(x); -#endif - SECP256K1_SCALAR_VERIFY(x); - - secp256k1_scalar_to_signed62(&s, x); - secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar); - secp256k1_scalar_from_signed62(r, &s); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -} - -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { - secp256k1_modinv64_signed62 s; -#ifdef VERIFY - int zero_in = secp256k1_scalar_is_zero(x); -#endif - SECP256K1_SCALAR_VERIFY(x); - - secp256k1_scalar_to_signed62(&s, x); - secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar); - secp256k1_scalar_from_signed62(r, &s); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return !(a->d[0] & 1); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_8x32.h b/external/secp256k1/src/scalar_8x32.h deleted file mode 100644 index 17863ef937..0000000000 --- a/external/secp256k1/src/scalar_8x32.h +++ /dev/null @@ -1,19 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef struct { - uint32_t d[8]; -} secp256k1_scalar; - -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_8x32_impl.h b/external/secp256k1/src/scalar_8x32_impl.h deleted file mode 100644 index 2610496052..0000000000 --- a/external/secp256k1/src/scalar_8x32_impl.h +++ /dev/null @@ -1,816 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "checkmem.h" -#include "modinv32_impl.h" -#include "util.h" - -/* Limbs of the secp256k1 order. */ -#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) -#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) -#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) -#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) -#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) -#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) - -/* Limbs of 2^256 minus the secp256k1 order. */ -#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) -#define SECP256K1_N_C_1 (~SECP256K1_N_1) -#define SECP256K1_N_C_2 (~SECP256K1_N_2) -#define SECP256K1_N_C_3 (~SECP256K1_N_3) -#define SECP256K1_N_C_4 (1) - -/* Limbs of half the secp256k1 order. */ -#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) -#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) -#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) -#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) -#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) - -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; - - SECP256K1_SCALAR_VERIFY(r); -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); - - return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count)); -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK(offset + count <= 256); - - if ((offset + count - 1) >> 5 == offset >> 5) { - return secp256k1_scalar_get_bits_limb32(a, offset, count); - } else { - VERIFY_CHECK((offset >> 5) + 1 < 8); - return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & (0xFFFFFFFF >> (32 - count)); - } -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ - no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ - no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ - no |= (a->d[4] < SECP256K1_N_4); - yes |= (a->d[4] > SECP256K1_N_4) & ~no; - no |= (a->d[3] < SECP256K1_N_3) & ~yes; - yes |= (a->d[3] > SECP256K1_N_3) & ~no; - no |= (a->d[2] < SECP256K1_N_2) & ~yes; - yes |= (a->d[2] > SECP256K1_N_2) & ~no; - no |= (a->d[1] < SECP256K1_N_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_1) & ~no; - yes |= (a->d[0] >= SECP256K1_N_0) & ~no; - return yes; -} - -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { - uint64_t t; - VERIFY_CHECK(overflow <= 1); - - t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; - r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; - r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[5]; - r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[6]; - r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[7]; - r->d[7] = t & 0xFFFFFFFFUL; - - SECP256K1_SCALAR_VERIFY(r); - return overflow; -} - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - int overflow; - uint64_t t = (uint64_t)a->d[0] + b->d[0]; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[4] + b->d[4]; - r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[5] + b->d[5]; - r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[6] + b->d[6]; - r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[7] + b->d[7]; - r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; - overflow = t + secp256k1_scalar_check_overflow(r); - VERIFY_CHECK(overflow == 0 || overflow == 1); - secp256k1_scalar_reduce(r, overflow); - - SECP256K1_SCALAR_VERIFY(r); - return overflow; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - uint64_t t; - volatile int vflag = flag; - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(bit < 256); - - bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ - t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); - r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); - r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); - r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); - r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); - r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); - r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); - r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); - r->d[7] = t & 0xFFFFFFFFULL; - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK((t >> 32) == 0); -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - int over; - r->d[0] = secp256k1_read_be32(&b32[28]); - r->d[1] = secp256k1_read_be32(&b32[24]); - r->d[2] = secp256k1_read_be32(&b32[20]); - r->d[3] = secp256k1_read_be32(&b32[16]); - r->d[4] = secp256k1_read_be32(&b32[12]); - r->d[5] = secp256k1_read_be32(&b32[8]); - r->d[6] = secp256k1_read_be32(&b32[4]); - r->d[7] = secp256k1_read_be32(&b32[0]); - over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); - if (overflow) { - *overflow = over; - } - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - SECP256K1_SCALAR_VERIFY(a); - - secp256k1_write_be32(&bin[0], a->d[7]); - secp256k1_write_be32(&bin[4], a->d[6]); - secp256k1_write_be32(&bin[8], a->d[5]); - secp256k1_write_be32(&bin[12], a->d[4]); - secp256k1_write_be32(&bin[16], a->d[3]); - secp256k1_write_be32(&bin[20], a->d[2]); - secp256k1_write_be32(&bin[24], a->d[1]); - secp256k1_write_be32(&bin[28], a->d[0]); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); - uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; - SECP256K1_SCALAR_VERIFY(a); - - r->d[0] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; - r->d[4] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; - r->d[5] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; - r->d[6] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; - r->d[7] = t & nonzero; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { - /* Writing `/` for field division and `//` for integer division, we compute - * - * a/2 = (a - (a&1))/2 + (a&1)/2 - * = (a >> 1) + (a&1 ? 1/2 : 0) - * = (a >> 1) + (a&1 ? n//2+1 : 0), - * - * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). - * For n//2, we have the constants SECP256K1_N_H_0, ... - * - * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: - * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 - * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 - * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. - */ - uint32_t mask = -(uint32_t)(a->d[0] & 1U); - uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31)); - SECP256K1_SCALAR_VERIFY(a); - - t += (SECP256K1_N_H_0 + 1U) & mask; - r->d[0] = t; t >>= 32; - t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31)); - t += SECP256K1_N_H_1 & mask; - r->d[1] = t; t >>= 32; - t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31)); - t += SECP256K1_N_H_2 & mask; - r->d[2] = t; t >>= 32; - t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31)); - t += SECP256K1_N_H_3 & mask; - r->d[3] = t; t >>= 32; - t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31)); - t += SECP256K1_N_H_4 & mask; - r->d[4] = t; t >>= 32; - t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31)); - t += SECP256K1_N_H_5 & mask; - r->d[5] = t; t >>= 32; - t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31)); - t += SECP256K1_N_H_6 & mask; - r->d[6] = t; t >>= 32; - r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask); - - /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation - * in full 64 bits to make sure the top 32 bits are indeed zero. */ - VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0); - - SECP256K1_SCALAR_VERIFY(r); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - SECP256K1_SCALAR_VERIFY(a); - - no |= (a->d[7] < SECP256K1_N_H_7); - yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; - no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ - no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ - no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ - no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; - yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; - no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; - yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; - no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; - yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; - return yes; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - volatile int vflag = flag; - uint32_t mask = -vflag; - uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); - uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - SECP256K1_SCALAR_VERIFY(r); - - r->d[0] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); - r->d[4] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); - r->d[5] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); - r->d[6] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); - r->d[7] = t & nonzero; - - SECP256K1_SCALAR_VERIFY(r); - return 2 * (mask == 0) - 1; -} - - -/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ - -/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd(a,b) { \ - uint32_t tl, th; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFF */ \ - c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ -} - -/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ -#define muladd_fast(a,b) { \ - uint32_t tl, th; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFF */ \ - c1 += th; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK(c1 >= th); \ -} - -/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define sumadd(a) { \ - unsigned int over; \ - c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)); \ - c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over); /* never overflows by contract */ \ -} - -/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ -#define sumadd_fast(a) { \ - c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ - VERIFY_CHECK(c2 == 0); \ -} - -/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ -#define extract(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = c2; \ - c2 = 0; \ -} - -/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ -#define extract_fast(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = 0; \ - VERIFY_CHECK(c2 == 0); \ -} - -static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { - uint64_t c; - uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; - uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; - uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; - - /* 96 bit accumulator. */ - uint32_t c0, c1, c2; - - /* Reduce 512 bits into 385. */ - /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ - c0 = l[0]; c1 = 0; c2 = 0; - muladd_fast(n0, SECP256K1_N_C_0); - extract_fast(m0); - sumadd_fast(l[1]); - muladd(n1, SECP256K1_N_C_0); - muladd(n0, SECP256K1_N_C_1); - extract(m1); - sumadd(l[2]); - muladd(n2, SECP256K1_N_C_0); - muladd(n1, SECP256K1_N_C_1); - muladd(n0, SECP256K1_N_C_2); - extract(m2); - sumadd(l[3]); - muladd(n3, SECP256K1_N_C_0); - muladd(n2, SECP256K1_N_C_1); - muladd(n1, SECP256K1_N_C_2); - muladd(n0, SECP256K1_N_C_3); - extract(m3); - sumadd(l[4]); - muladd(n4, SECP256K1_N_C_0); - muladd(n3, SECP256K1_N_C_1); - muladd(n2, SECP256K1_N_C_2); - muladd(n1, SECP256K1_N_C_3); - sumadd(n0); - extract(m4); - sumadd(l[5]); - muladd(n5, SECP256K1_N_C_0); - muladd(n4, SECP256K1_N_C_1); - muladd(n3, SECP256K1_N_C_2); - muladd(n2, SECP256K1_N_C_3); - sumadd(n1); - extract(m5); - sumadd(l[6]); - muladd(n6, SECP256K1_N_C_0); - muladd(n5, SECP256K1_N_C_1); - muladd(n4, SECP256K1_N_C_2); - muladd(n3, SECP256K1_N_C_3); - sumadd(n2); - extract(m6); - sumadd(l[7]); - muladd(n7, SECP256K1_N_C_0); - muladd(n6, SECP256K1_N_C_1); - muladd(n5, SECP256K1_N_C_2); - muladd(n4, SECP256K1_N_C_3); - sumadd(n3); - extract(m7); - muladd(n7, SECP256K1_N_C_1); - muladd(n6, SECP256K1_N_C_2); - muladd(n5, SECP256K1_N_C_3); - sumadd(n4); - extract(m8); - muladd(n7, SECP256K1_N_C_2); - muladd(n6, SECP256K1_N_C_3); - sumadd(n5); - extract(m9); - muladd(n7, SECP256K1_N_C_3); - sumadd(n6); - extract(m10); - sumadd_fast(n7); - extract_fast(m11); - VERIFY_CHECK(c0 <= 1); - m12 = c0; - - /* Reduce 385 bits into 258. */ - /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ - c0 = m0; c1 = 0; c2 = 0; - muladd_fast(m8, SECP256K1_N_C_0); - extract_fast(p0); - sumadd_fast(m1); - muladd(m9, SECP256K1_N_C_0); - muladd(m8, SECP256K1_N_C_1); - extract(p1); - sumadd(m2); - muladd(m10, SECP256K1_N_C_0); - muladd(m9, SECP256K1_N_C_1); - muladd(m8, SECP256K1_N_C_2); - extract(p2); - sumadd(m3); - muladd(m11, SECP256K1_N_C_0); - muladd(m10, SECP256K1_N_C_1); - muladd(m9, SECP256K1_N_C_2); - muladd(m8, SECP256K1_N_C_3); - extract(p3); - sumadd(m4); - muladd(m12, SECP256K1_N_C_0); - muladd(m11, SECP256K1_N_C_1); - muladd(m10, SECP256K1_N_C_2); - muladd(m9, SECP256K1_N_C_3); - sumadd(m8); - extract(p4); - sumadd(m5); - muladd(m12, SECP256K1_N_C_1); - muladd(m11, SECP256K1_N_C_2); - muladd(m10, SECP256K1_N_C_3); - sumadd(m9); - extract(p5); - sumadd(m6); - muladd(m12, SECP256K1_N_C_2); - muladd(m11, SECP256K1_N_C_3); - sumadd(m10); - extract(p6); - sumadd_fast(m7); - muladd_fast(m12, SECP256K1_N_C_3); - sumadd_fast(m11); - extract_fast(p7); - p8 = c0 + m12; - VERIFY_CHECK(p8 <= 2); - - /* Reduce 258 bits into 256. */ - /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ - c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; - r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; - c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; - r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; - c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; - r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; - c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; - r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; - c += p4 + (uint64_t)p8; - r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; - c += p5; - r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; - c += p6; - r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; - c += p7; - r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; - - /* Final reduction of r. */ - secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); -} - -static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { - /* 96 bit accumulator. */ - uint32_t c0 = 0, c1 = 0, c2 = 0; - - /* l[0..15] = a[0..7] * b[0..7]. */ - muladd_fast(a->d[0], b->d[0]); - extract_fast(l[0]); - muladd(a->d[0], b->d[1]); - muladd(a->d[1], b->d[0]); - extract(l[1]); - muladd(a->d[0], b->d[2]); - muladd(a->d[1], b->d[1]); - muladd(a->d[2], b->d[0]); - extract(l[2]); - muladd(a->d[0], b->d[3]); - muladd(a->d[1], b->d[2]); - muladd(a->d[2], b->d[1]); - muladd(a->d[3], b->d[0]); - extract(l[3]); - muladd(a->d[0], b->d[4]); - muladd(a->d[1], b->d[3]); - muladd(a->d[2], b->d[2]); - muladd(a->d[3], b->d[1]); - muladd(a->d[4], b->d[0]); - extract(l[4]); - muladd(a->d[0], b->d[5]); - muladd(a->d[1], b->d[4]); - muladd(a->d[2], b->d[3]); - muladd(a->d[3], b->d[2]); - muladd(a->d[4], b->d[1]); - muladd(a->d[5], b->d[0]); - extract(l[5]); - muladd(a->d[0], b->d[6]); - muladd(a->d[1], b->d[5]); - muladd(a->d[2], b->d[4]); - muladd(a->d[3], b->d[3]); - muladd(a->d[4], b->d[2]); - muladd(a->d[5], b->d[1]); - muladd(a->d[6], b->d[0]); - extract(l[6]); - muladd(a->d[0], b->d[7]); - muladd(a->d[1], b->d[6]); - muladd(a->d[2], b->d[5]); - muladd(a->d[3], b->d[4]); - muladd(a->d[4], b->d[3]); - muladd(a->d[5], b->d[2]); - muladd(a->d[6], b->d[1]); - muladd(a->d[7], b->d[0]); - extract(l[7]); - muladd(a->d[1], b->d[7]); - muladd(a->d[2], b->d[6]); - muladd(a->d[3], b->d[5]); - muladd(a->d[4], b->d[4]); - muladd(a->d[5], b->d[3]); - muladd(a->d[6], b->d[2]); - muladd(a->d[7], b->d[1]); - extract(l[8]); - muladd(a->d[2], b->d[7]); - muladd(a->d[3], b->d[6]); - muladd(a->d[4], b->d[5]); - muladd(a->d[5], b->d[4]); - muladd(a->d[6], b->d[3]); - muladd(a->d[7], b->d[2]); - extract(l[9]); - muladd(a->d[3], b->d[7]); - muladd(a->d[4], b->d[6]); - muladd(a->d[5], b->d[5]); - muladd(a->d[6], b->d[4]); - muladd(a->d[7], b->d[3]); - extract(l[10]); - muladd(a->d[4], b->d[7]); - muladd(a->d[5], b->d[6]); - muladd(a->d[6], b->d[5]); - muladd(a->d[7], b->d[4]); - extract(l[11]); - muladd(a->d[5], b->d[7]); - muladd(a->d[6], b->d[6]); - muladd(a->d[7], b->d[5]); - extract(l[12]); - muladd(a->d[6], b->d[7]); - muladd(a->d[7], b->d[6]); - extract(l[13]); - muladd_fast(a->d[7], b->d[7]); - extract_fast(l[14]); - VERIFY_CHECK(c1 == 0); - l[15] = c0; -} - -#undef sumadd -#undef sumadd_fast -#undef muladd -#undef muladd_fast -#undef extract -#undef extract_fast - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - uint32_t l[16]; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - secp256k1_scalar_mul_512(l, a, b); - secp256k1_scalar_reduce_512(r, l); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { - SECP256K1_SCALAR_VERIFY(k); - - r1->d[0] = k->d[0]; - r1->d[1] = k->d[1]; - r1->d[2] = k->d[2]; - r1->d[3] = k->d[3]; - r1->d[4] = 0; - r1->d[5] = 0; - r1->d[6] = 0; - r1->d[7] = 0; - r2->d[0] = k->d[4]; - r2->d[1] = k->d[5]; - r2->d[2] = k->d[6]; - r2->d[3] = k->d[7]; - r2->d[4] = 0; - r2->d[5] = 0; - r2->d[6] = 0; - r2->d[7] = 0; - - SECP256K1_SCALAR_VERIFY(r1); - SECP256K1_SCALAR_VERIFY(r2); -} - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { - uint32_t l[16]; - unsigned int shiftlimbs; - unsigned int shiftlow; - unsigned int shifthigh; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - VERIFY_CHECK(shift >= 256); - - secp256k1_scalar_mul_512(l, a, b); - shiftlimbs = shift >> 5; - shiftlow = shift & 0x1F; - shifthigh = 32 - shiftlow; - r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); - - SECP256K1_SCALAR_VERIFY(r); -} - -static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { - uint32_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); - - mask0 = vflag + ~((uint32_t)0); - mask1 = ~mask0; - r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); - r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); - r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); - r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); - r->d[4] = (r->d[4] & mask0) | (a->d[4] & mask1); - r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1); - r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1); - r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) { - const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], - a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; - - /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and - * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). - */ - VERIFY_CHECK(a0 >> 30 == 0); - VERIFY_CHECK(a1 >> 30 == 0); - VERIFY_CHECK(a2 >> 30 == 0); - VERIFY_CHECK(a3 >> 30 == 0); - VERIFY_CHECK(a4 >> 30 == 0); - VERIFY_CHECK(a5 >> 30 == 0); - VERIFY_CHECK(a6 >> 30 == 0); - VERIFY_CHECK(a7 >> 30 == 0); - VERIFY_CHECK(a8 >> 16 == 0); - - r->d[0] = a0 | a1 << 30; - r->d[1] = a1 >> 2 | a2 << 28; - r->d[2] = a2 >> 4 | a3 << 26; - r->d[3] = a3 >> 6 | a4 << 24; - r->d[4] = a4 >> 8 | a5 << 22; - r->d[5] = a5 >> 10 | a6 << 20; - r->d[6] = a6 >> 12 | a7 << 18; - r->d[7] = a7 >> 14 | a8 << 16; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) { - const uint32_t M30 = UINT32_MAX >> 2; - const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3], - a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7]; - SECP256K1_SCALAR_VERIFY(a); - - r->v[0] = a0 & M30; - r->v[1] = (a0 >> 30 | a1 << 2) & M30; - r->v[2] = (a1 >> 28 | a2 << 4) & M30; - r->v[3] = (a2 >> 26 | a3 << 6) & M30; - r->v[4] = (a3 >> 24 | a4 << 8) & M30; - r->v[5] = (a4 >> 22 | a5 << 10) & M30; - r->v[6] = (a5 >> 20 | a6 << 12) & M30; - r->v[7] = (a6 >> 18 | a7 << 14) & M30; - r->v[8] = a7 >> 16; -} - -static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_scalar = { - {{0x10364141L, 0x3F497A33L, 0x348A03BBL, 0x2BB739ABL, -0x146L, 0, 0, 0, 65536}}, - 0x2A774EC1L -}; - -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { - secp256k1_modinv32_signed30 s; -#ifdef VERIFY - int zero_in = secp256k1_scalar_is_zero(x); -#endif - SECP256K1_SCALAR_VERIFY(x); - - secp256k1_scalar_to_signed30(&s, x); - secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar); - secp256k1_scalar_from_signed30(r, &s); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -} - -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { - secp256k1_modinv32_signed30 s; -#ifdef VERIFY - int zero_in = secp256k1_scalar_is_zero(x); -#endif - SECP256K1_SCALAR_VERIFY(x); - - secp256k1_scalar_to_signed30(&s, x); - secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar); - secp256k1_scalar_from_signed30(r, &s); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return !(a->d[0] & 1); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_impl.h b/external/secp256k1/src/scalar_impl.h deleted file mode 100644 index dbb5b0a01c..0000000000 --- a/external/secp256k1/src/scalar_impl.h +++ /dev/null @@ -1,321 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_IMPL_H -#define SECP256K1_SCALAR_IMPL_H - -#ifdef VERIFY -#include -#endif - -#include "scalar.h" -#include "util.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -#include "scalar_low_impl.h" -#elif defined(SECP256K1_WIDEMUL_INT128) -#include "scalar_4x64_impl.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "scalar_8x32_impl.h" -#else -#error "Please select wide multiplication implementation" -#endif - -static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); -static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { - secp256k1_memclear(r, sizeof(secp256k1_scalar)); -} - -static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) { - int overflow; - secp256k1_scalar_set_b32(r, bin, &overflow); - - SECP256K1_SCALAR_VERIFY(r); - return (!overflow) & (!secp256k1_scalar_is_zero(r)); -} - -static void secp256k1_scalar_verify(const secp256k1_scalar *r) { - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); - - (void)r; -} - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ -# if EXHAUSTIVE_TEST_ORDER == 7 -# define EXHAUSTIVE_TEST_LAMBDA 2 -# elif EXHAUSTIVE_TEST_ORDER == 13 -# define EXHAUSTIVE_TEST_LAMBDA 9 -# elif EXHAUSTIVE_TEST_ORDER == 199 -# define EXHAUSTIVE_TEST_LAMBDA 92 -# else -# error No known lambda for the specified exhaustive test group order. -# endif -/* End of section generated by sage/gen_exhaustive_groups.sage. */ - -/** - * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the - * full case we don't bother making r1 and r2 be small, we just want them to be - * nontrivial to get full test coverage for the exhaustive tests. We therefore - * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). - */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { - SECP256K1_SCALAR_VERIFY(k); - VERIFY_CHECK(r1 != k); - VERIFY_CHECK(r2 != k); - VERIFY_CHECK(r1 != r2); - - *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; - *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; - - SECP256K1_SCALAR_VERIFY(r1); - SECP256K1_SCALAR_VERIFY(r2); -} -#else -/** - * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where - * lambda is: */ -static const secp256k1_scalar secp256k1_const_lambda = SECP256K1_SCALAR_CONST( - 0x5363AD4CUL, 0xC05C30E0UL, 0xA5261C02UL, 0x8812645AUL, - 0x122E22EAUL, 0x20816678UL, 0xDF02967CUL, 0x1B23BD72UL -); - -#ifdef VERIFY -static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k); -#endif - -/* - * Both lambda and beta are primitive cube roots of unity. That is lamba^3 == 1 mod n and - * beta^3 == 1 mod p, where n is the curve order and p is the field order. - * - * Furthermore, because (X^3 - 1) = (X - 1)(X^2 + X + 1), the primitive cube roots of unity are - * roots of X^2 + X + 1. Therefore lambda^2 + lamba == -1 mod n and beta^2 + beta == -1 mod p. - * (The other primitive cube roots of unity are lambda^2 and beta^2 respectively.) - * - * Let l = -1/2 + i*sqrt(3)/2, the complex root of X^2 + X + 1. We can define a ring - * homomorphism phi : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. The kernel of phi - * is a lattice over Z[l] (considering Z[l] as a Z-module). This lattice is generated by a - * reduced basis {a1 + b1*l, a2 + b2*l} where - * - * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} - * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} - * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm - * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 - * and k2 are small in absolute value. - * - * The algorithm computes c1 = round(b2 * k / n) and c2 = round((-b1) * k / n), and gives - * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and - * compute r2 = k2 mod n, and r1 = k1 mod n = (k - r2 * lambda) mod n, avoiding the need for - * the constants a1 and a2. - * - * g1, g2 are precomputed constants used to replace division with a rounded multiplication - * when decomposing the scalar for an endomorphism-based point multiplication. - * - * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve - * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. - * - * The derivation is described in the paper "Efficient Software Implementation of Public-Key - * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), - * Section 4.3 (here we use a somewhat higher-precision estimate): - * d = a1*b2 - b1*a2 - * g1 = round(2^384 * b2/d) - * g2 = round(2^384 * (-b1)/d) - * - * (Note that d is also equal to the curve order, n, here because [a1,b1] and [a2,b2] - * can be found as outputs of the Extended Euclidean Algorithm on inputs n and lambda). - * - * The function below splits k into r1 and r2, such that - * - r1 + lambda * r2 == k (mod n) - * - either r1 < 2^128 or -r1 mod n < 2^128 - * - either r2 < 2^128 or -r2 mod n < 2^128 - * - * See proof below. - */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { - secp256k1_scalar c1, c2; - static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, - 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL - ); - static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, - 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL - ); - static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( - 0x3086D221UL, 0xA7D46BCDUL, 0xE86C90E4UL, 0x9284EB15UL, - 0x3DAA8A14UL, 0x71E8CA7FUL, 0xE893209AUL, 0x45DBB031UL - ); - static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( - 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, - 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL - ); - SECP256K1_SCALAR_VERIFY(k); - VERIFY_CHECK(r1 != k); - VERIFY_CHECK(r2 != k); - VERIFY_CHECK(r1 != r2); - - /* these _var calls are constant time since the shift amount is constant */ - secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); - secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); - secp256k1_scalar_mul(&c1, &c1, &minus_b1); - secp256k1_scalar_mul(&c2, &c2, &minus_b2); - secp256k1_scalar_add(r2, &c1, &c2); - secp256k1_scalar_mul(r1, r2, &secp256k1_const_lambda); - secp256k1_scalar_negate(r1, r1); - secp256k1_scalar_add(r1, r1, k); - - SECP256K1_SCALAR_VERIFY(r1); - SECP256K1_SCALAR_VERIFY(r2); -#ifdef VERIFY - secp256k1_scalar_split_lambda_verify(r1, r2, k); -#endif -} - -#ifdef VERIFY -/* - * Proof for secp256k1_scalar_split_lambda's bounds. - * - * Let - * - epsilon1 = 2^256 * |g1/2^384 - b2/d| - * - epsilon2 = 2^256 * |g2/2^384 - (-b1)/d| - * - c1 = round(k*g1/2^384) - * - c2 = round(k*g2/2^384) - * - * Lemma 1: |c1 - k*b2/d| < 2^-1 + epsilon1 - * - * |c1 - k*b2/d| - * = - * |c1 - k*g1/2^384 + k*g1/2^384 - k*b2/d| - * <= {triangle inequality} - * |c1 - k*g1/2^384| + |k*g1/2^384 - k*b2/d| - * = - * |c1 - k*g1/2^384| + k*|g1/2^384 - b2/d| - * < {rounding in c1 and 0 <= k < 2^256} - * 2^-1 + 2^256 * |g1/2^384 - b2/d| - * = {definition of epsilon1} - * 2^-1 + epsilon1 - * - * Lemma 2: |c2 - k*(-b1)/d| < 2^-1 + epsilon2 - * - * |c2 - k*(-b1)/d| - * = - * |c2 - k*g2/2^384 + k*g2/2^384 - k*(-b1)/d| - * <= {triangle inequality} - * |c2 - k*g2/2^384| + |k*g2/2^384 - k*(-b1)/d| - * = - * |c2 - k*g2/2^384| + k*|g2/2^384 - (-b1)/d| - * < {rounding in c2 and 0 <= k < 2^256} - * 2^-1 + 2^256 * |g2/2^384 - (-b1)/d| - * = {definition of epsilon2} - * 2^-1 + epsilon2 - * - * Let - * - k1 = k - c1*a1 - c2*a2 - * - k2 = - c1*b1 - c2*b2 - * - * Lemma 3: |k1| < (a1 + a2 + 1)/2 < 2^128 - * - * |k1| - * = {definition of k1} - * |k - c1*a1 - c2*a2| - * = {(a1*b2 - b1*a2)/n = 1} - * |k*(a1*b2 - b1*a2)/n - c1*a1 - c2*a2| - * = - * |a1*(k*b2/n - c1) + a2*(k*(-b1)/n - c2)| - * <= {triangle inequality} - * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| - * < {Lemma 1 and Lemma 2} - * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2) - * < {rounding up to an integer} - * (a1 + a2 + 1)/2 - * < {rounding up to a power of 2} - * 2^128 - * - * Lemma 4: |k2| < (-b1 + b2)/2 + 1 < 2^128 - * - * |k2| - * = {definition of k2} - * |- c1*a1 - c2*a2| - * = {(b1*b2 - b1*b2)/n = 0} - * |k*(b1*b2 - b1*b2)/n - c1*b1 - c2*b2| - * = - * |b1*(k*b2/n - c1) + b2*(k*(-b1)/n - c2)| - * <= {triangle inequality} - * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| - * < {Lemma 1 and Lemma 2} - * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2) - * < {rounding up to an integer} - * (-b1 + b2)/2 + 1 - * < {rounding up to a power of 2} - * 2^128 - * - * Let - * - r2 = k2 mod n - * - r1 = k - r2*lambda mod n. - * - * Notice that r1 is defined such that r1 + r2 * lambda == k (mod n). - * - * Lemma 5: r1 == k1 mod n. - * - * r1 - * == {definition of r1 and r2} - * k - k2*lambda - * == {definition of k2} - * k - (- c1*b1 - c2*b2)*lambda - * == - * k + c1*b1*lambda + c2*b2*lambda - * == {a1 + b1*lambda == 0 mod n and a2 + b2*lambda == 0 mod n} - * k - c1*a1 - c2*a2 - * == {definition of k1} - * k1 - * - * From Lemma 3, Lemma 4, Lemma 5 and the definition of r2, we can conclude that - * - * - either r1 < 2^128 or -r1 mod n < 2^128 - * - either r2 < 2^128 or -r2 mod n < 2^128. - * - * Q.E.D. - */ -static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k) { - secp256k1_scalar s; - unsigned char buf1[32]; - unsigned char buf2[32]; - - /* (a1 + a2 + 1)/2 is 0xa2a8918ca85bafe22016d0b917e4dd77 */ - static const unsigned char k1_bound[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa2, 0xa8, 0x91, 0x8c, 0xa8, 0x5b, 0xaf, 0xe2, 0x20, 0x16, 0xd0, 0xb9, 0x17, 0xe4, 0xdd, 0x77 - }; - - /* (-b1 + b2)/2 + 1 is 0x8a65287bd47179fb2be08846cea267ed */ - static const unsigned char k2_bound[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x8a, 0x65, 0x28, 0x7b, 0xd4, 0x71, 0x79, 0xfb, 0x2b, 0xe0, 0x88, 0x46, 0xce, 0xa2, 0x67, 0xed - }; - - secp256k1_scalar_mul(&s, &secp256k1_const_lambda, r2); - secp256k1_scalar_add(&s, &s, r1); - VERIFY_CHECK(secp256k1_scalar_eq(&s, k)); - - secp256k1_scalar_negate(&s, r1); - secp256k1_scalar_get_b32(buf1, r1); - secp256k1_scalar_get_b32(buf2, &s); - VERIFY_CHECK(secp256k1_memcmp_var(buf1, k1_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k1_bound, 32) < 0); - - secp256k1_scalar_negate(&s, r2); - secp256k1_scalar_get_b32(buf1, r2); - secp256k1_scalar_get_b32(buf2, &s); - VERIFY_CHECK(secp256k1_memcmp_var(buf1, k2_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k2_bound, 32) < 0); -} -#endif /* VERIFY */ -#endif /* !defined(EXHAUSTIVE_TEST_ORDER) */ - -#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_low.h b/external/secp256k1/src/scalar_low.h deleted file mode 100644 index 2711eb932d..0000000000 --- a/external/secp256k1/src/scalar_low.h +++ /dev/null @@ -1,24 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef uint32_t secp256k1_scalar; - -/* A compile-time constant equal to 2^32 (modulo order). */ -#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U) - -/* Compute a*2^32 + b (modulo order). */ -#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER) - -/* Evaluates to the provided 256-bit constant reduced modulo order. */ -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0)) - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_low_impl.h b/external/secp256k1/src/scalar_low_impl.h deleted file mode 100644 index 84e1a380a3..0000000000 --- a/external/secp256k1/src/scalar_low_impl.h +++ /dev/null @@ -1,206 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "checkmem.h" -#include "scalar.h" -#include "util.h" - -#include - -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return !(*a & 1); -} - -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { - *r = v % EXHAUSTIVE_TEST_ORDER; - - SECP256K1_SCALAR_VERIFY(r); -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - - VERIFY_CHECK(count > 0 && count <= 32); - if (offset < 32) { - return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); - } else { - return 0; - } -} - -SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - SECP256K1_SCALAR_VERIFY(a); - - return secp256k1_scalar_get_bits_limb32(a, offset, count); -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; - - SECP256K1_SCALAR_VERIFY(r); - return *r < *b; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - SECP256K1_SCALAR_VERIFY(r); - - if (flag && bit < 32) - *r += ((uint32_t)1 << bit); - - SECP256K1_SCALAR_VERIFY(r); - VERIFY_CHECK(bit < 32); - /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ - VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - int i; - int over = 0; - *r = 0; - for (i = 0; i < 32; i++) { - *r = (*r * 0x100) + b32[i]; - if (*r >= EXHAUSTIVE_TEST_ORDER) { - over = 1; - *r %= EXHAUSTIVE_TEST_ORDER; - } - } - if (overflow) *overflow = over; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - SECP256K1_SCALAR_VERIFY(a); - - memset(bin, 0, 32); - bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return *a == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - if (*a == 0) { - *r = 0; - } else { - *r = EXHAUSTIVE_TEST_ORDER - *a; - } - - SECP256K1_SCALAR_VERIFY(r); -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return *a == 1; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - return *a > EXHAUSTIVE_TEST_ORDER / 2; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - SECP256K1_SCALAR_VERIFY(r); - - if (flag) secp256k1_scalar_negate(r, r); - - SECP256K1_SCALAR_VERIFY(r); - return flag ? -1 : 1; -} - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - *r1 = *a; - *r2 = 0; - - SECP256K1_SCALAR_VERIFY(r1); - SECP256K1_SCALAR_VERIFY(r2); -} - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_SCALAR_VERIFY(b); - - return *a == *b; -} - -static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { - uint32_t mask0, mask1; - volatile int vflag = flag; - SECP256K1_SCALAR_VERIFY(a); - SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); - - mask0 = vflag + ~((uint32_t)0); - mask1 = ~mask0; - *r = (*r & mask0) | (*a & mask1); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { - int i; - uint32_t res = 0; - SECP256K1_SCALAR_VERIFY(x); - - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) { - res = i; - break; - } - } - - /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus - * have a composite group order; fix it in exhaustive_tests.c). */ - VERIFY_CHECK(res != 0); - *r = res; - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { - SECP256K1_SCALAR_VERIFY(x); - - secp256k1_scalar_inverse(r, x); - - SECP256K1_SCALAR_VERIFY(r); -} - -static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { - SECP256K1_SCALAR_VERIFY(a); - - *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1; - - SECP256K1_SCALAR_VERIFY(r); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scratch.h b/external/secp256k1/src/scratch.h deleted file mode 100644 index 6164330b39..0000000000 --- a/external/secp256k1/src/scratch.h +++ /dev/null @@ -1,44 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2017 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCRATCH_H -#define SECP256K1_SCRATCH_H - -/* The typedef is used internally; the struct name is used in the public API - * (where it is exposed as a different typedef) */ -typedef struct secp256k1_scratch_space_struct { - /** guard against interpreting this object as other types */ - unsigned char magic[8]; - /** actual allocated data */ - void *data; - /** amount that has been allocated (i.e. `data + offset` is the next - * available pointer) */ - size_t alloc_size; - /** maximum size available to allocate */ - size_t max_size; -} secp256k1_scratch; - -typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; - -static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); - -static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); - -/** Returns an opaque object used to "checkpoint" a scratch space. Used - * with `secp256k1_scratch_apply_checkpoint` to undo allocations. */ -static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch); - -/** Applies a check point received from `secp256k1_scratch_checkpoint`, - * undoing all allocations since that point. */ -static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint); - -/** Returns the maximum allocation the scratch space will allow */ -static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects); - -/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ -static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n); - -#endif diff --git a/external/secp256k1/src/scratch_impl.h b/external/secp256k1/src/scratch_impl.h deleted file mode 100644 index f71a20b963..0000000000 --- a/external/secp256k1/src/scratch_impl.h +++ /dev/null @@ -1,99 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2017 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCRATCH_IMPL_H -#define SECP256K1_SCRATCH_IMPL_H - -#include "util.h" -#include "scratch.h" - -static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) { - const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch)); - void *alloc = checked_malloc(error_callback, base_alloc + size); - secp256k1_scratch* ret = (secp256k1_scratch *)alloc; - if (ret != NULL) { - memset(ret, 0, sizeof(*ret)); - memcpy(ret->magic, "scratch", 8); - ret->data = (void *) ((char *) alloc + base_alloc); - ret->max_size = size; - } - return ret; -} - -static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { - if (scratch != NULL) { - if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { - secp256k1_callback_call(error_callback, "invalid scratch space"); - return; - } - VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ - memset(scratch->magic, 0, sizeof(scratch->magic)); - free(scratch); - } -} - -static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { - if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { - secp256k1_callback_call(error_callback, "invalid scratch space"); - return 0; - } - return scratch->alloc_size; -} - -static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) { - if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { - secp256k1_callback_call(error_callback, "invalid scratch space"); - return; - } - if (checkpoint > scratch->alloc_size) { - secp256k1_callback_call(error_callback, "invalid checkpoint"); - return; - } - scratch->alloc_size = checkpoint; -} - -static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) { - if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { - secp256k1_callback_call(error_callback, "invalid scratch space"); - return 0; - } - /* Ensure that multiplication will not wrap around */ - if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) { - return 0; - } - if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) { - return 0; - } - return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1); -} - -static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) { - void *ret; - size_t rounded_size; - - rounded_size = ROUND_TO_ALIGN(size); - /* Check that rounding did not wrap around */ - if (rounded_size < size) { - return NULL; - } - size = rounded_size; - - if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { - secp256k1_callback_call(error_callback, "invalid scratch space"); - return NULL; - } - - if (size > scratch->max_size - scratch->alloc_size) { - return NULL; - } - ret = (void *) ((char *) scratch->data + scratch->alloc_size); - memset(ret, 0, size); - scratch->alloc_size += size; - - return ret; -} - -#endif diff --git a/external/secp256k1/src/secp256k1.c b/external/secp256k1/src/secp256k1.c deleted file mode 100644 index a248519dfd..0000000000 --- a/external/secp256k1/src/secp256k1.c +++ /dev/null @@ -1,831 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/* This is a C project. It should not be compiled with a C++ compiler, - * and we error out if we detect one. - * - * We still want to be able to test the project with a C++ compiler - * because it is still good to know if this will lead to real trouble, so - * there is a possibility to override the check. But be warned that - * compiling with a C++ compiler is not supported. */ -#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) -#error Trying to compile a C project with a C++ compiler. -#endif - -#define SECP256K1_BUILD - -#include "../include/secp256k1.h" -#include "../include/secp256k1_preallocated.h" - -#include "assumptions.h" -#include "checkmem.h" -#include "util.h" - -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "ecmult_impl.h" -#include "ecmult_const_impl.h" -#include "ecmult_gen_impl.h" -#include "ecdsa_impl.h" -#include "eckey_impl.h" -#include "hash_impl.h" -#include "int128_impl.h" -#include "scratch_impl.h" -#include "selftest.h" -#include "hsort_impl.h" - -#ifdef SECP256K1_NO_BUILD -# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" -#endif - -#define ARG_CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - secp256k1_callback_call(&ctx->illegal_callback, #cond); \ - return 0; \ - } \ -} while(0) - -#define ARG_CHECK_VOID(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - secp256k1_callback_call(&ctx->illegal_callback, #cond); \ - return; \ - } \ -} while(0) - -/* Note that whenever you change the context struct, you must also change the - * context_eq function. */ -struct secp256k1_context_struct { - secp256k1_ecmult_gen_context ecmult_gen_ctx; - secp256k1_callback illegal_callback; - secp256k1_callback error_callback; - int declassify; -}; - -static const secp256k1_context secp256k1_context_static_ = { - { 0 }, - { secp256k1_default_illegal_callback_fn, 0 }, - { secp256k1_default_error_callback_fn, 0 }, - 0 -}; -const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; -const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; - -/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. - * - * This is intended for "context" functions such as secp256k1_context_clone. Functions that need specific - * features of a context should still check for these features directly. For example, a function that needs - * ecmult_gen should directly check for the existence of the ecmult_gen context. */ -static int secp256k1_context_is_proper(const secp256k1_context* ctx) { - return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx); -} - -void secp256k1_selftest(void) { - if (!secp256k1_selftest_passes()) { - secp256k1_callback_call(&default_error_callback, "self test failed"); - } -} - -size_t secp256k1_context_preallocated_size(unsigned int flags) { - size_t ret = sizeof(secp256k1_context); - /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ - VERIFY_CHECK(ret != 0); - - if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { - secp256k1_callback_call(&default_illegal_callback, - "Invalid flags"); - return 0; - } - - if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { - secp256k1_callback_call(&default_illegal_callback, - "Declassify flag requires running with memory checking"); - return 0; - } - - return ret; -} - -size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_context_is_proper(ctx)); - return sizeof(secp256k1_context); -} - -secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { - size_t prealloc_size; - secp256k1_context* ret; - - secp256k1_selftest(); - - prealloc_size = secp256k1_context_preallocated_size(flags); - if (prealloc_size == 0) { - return NULL; - } - VERIFY_CHECK(prealloc != NULL); - ret = (secp256k1_context*)prealloc; - ret->illegal_callback = default_illegal_callback; - ret->error_callback = default_error_callback; - - /* Flags have been checked by secp256k1_context_preallocated_size. */ - VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); - ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); - - return ret; -} - -secp256k1_context* secp256k1_context_create(unsigned int flags) { - size_t const prealloc_size = secp256k1_context_preallocated_size(flags); - secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); - if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) { - free(ctx); - return NULL; - } - - return ctx; -} - -secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) { - secp256k1_context* ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(prealloc != NULL); - ARG_CHECK(secp256k1_context_is_proper(ctx)); - - ret = (secp256k1_context*)prealloc; - *ret = *ctx; - return ret; -} - -secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { - secp256k1_context* ret; - size_t prealloc_size; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_context_is_proper(ctx)); - - prealloc_size = secp256k1_context_preallocated_clone_size(ctx); - ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); - ret = secp256k1_context_preallocated_clone(ctx, ret); - return ret; -} - -void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { - ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); - - /* Defined as noop */ - if (ctx == NULL) { - return; - } - - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); -} - -void secp256k1_context_destroy(secp256k1_context* ctx) { - ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); - - /* Defined as noop */ - if (ctx == NULL) { - return; - } - - secp256k1_context_preallocated_destroy(ctx); - free(ctx); -} - -void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - /* We compare pointers instead of checking secp256k1_context_is_proper() here - because setting callbacks is allowed on *copies* of the static context: - it's harmless and makes testing easier. */ - ARG_CHECK_VOID(ctx != secp256k1_context_static); - if (fun == NULL) { - fun = secp256k1_default_illegal_callback_fn; - } - ctx->illegal_callback.fn = fun; - ctx->illegal_callback.data = data; -} - -void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - /* We compare pointers instead of checking secp256k1_context_is_proper() here - because setting callbacks is allowed on *copies* of the static context: - it's harmless and makes testing easier. */ - ARG_CHECK_VOID(ctx != secp256k1_context_static); - if (fun == NULL) { - fun = secp256k1_default_error_callback_fn; - } - ctx->error_callback.fn = fun; - ctx->error_callback.data = data; -} - -static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { - VERIFY_CHECK(ctx != NULL); - return secp256k1_scratch_create(&ctx->error_callback, max_size); -} - -static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { - VERIFY_CHECK(ctx != NULL); - secp256k1_scratch_destroy(&ctx->error_callback, scratch); -} - -/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour - * of the software. - */ -static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) { - if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); -} - -static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - secp256k1_ge_from_bytes(ge, pubkey->data); - ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); - return 1; -} - -static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - secp256k1_ge_to_bytes(pubkey->data, ge); -} - -int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { - secp256k1_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input != NULL); - if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { - return 0; - } - if (!secp256k1_ge_is_in_correct_subgroup(&Q)) { - return 0; - } - secp256k1_pubkey_save(pubkey, &Q); - secp256k1_ge_clear(&Q); - return 1; -} - -int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { - secp256k1_ge Q; - size_t len; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); - len = *outputlen; - *outputlen = 0; - ARG_CHECK(output != NULL); - memset(output, 0, len); - ARG_CHECK(pubkey != NULL); - ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); - if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { - ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); - if (ret) { - *outputlen = len; - } - } - return ret; -} - -int secp256k1_ec_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey0, const secp256k1_pubkey* pubkey1) { - unsigned char out[2][33]; - const secp256k1_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pubkey0; pk[1] = pubkey1; - for (i = 0; i < 2; i++) { - size_t out_size = sizeof(out[i]); - /* If the public key is NULL or invalid, ec_pubkey_serialize will call - * the illegal_callback and return 0. In that case we will serialize the - * key as all zeros which is less than any valid public key. This - * results in consistent comparisons even if NULL or invalid pubkeys are - * involved and prevents edge cases such as sorting algorithms that use - * this function and do not terminate as a result. */ - if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { - /* Note that ec_pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return secp256k1_memcmp_var(out[0], out[1], sizeof(out[0])); -} - -static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) { - return secp256k1_ec_pubkey_cmp((secp256k1_context *)ctx, - *(secp256k1_pubkey **)pk1, - *(secp256k1_pubkey **)pk2); -} - -int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkeys != NULL); - - /* Suppress wrong warning (fixed in MSVC 19.33) */ - #if defined(_MSC_VER) && (_MSC_VER < 1933) - #pragma warning(push) - #pragma warning(disable: 4090) - #endif - - /* Casting away const is fine because neither secp256k1_hsort nor - * secp256k1_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data - * argument. */ - secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_ec_pubkey_sort_cmp, (void *)ctx); - - #if defined(_MSC_VER) && (_MSC_VER < 1933) - #pragma warning(pop) - #endif - - return 1; -} - -static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { - (void)ctx; - if (sizeof(secp256k1_scalar) == 32) { - /* When the secp256k1_scalar type is exactly 32 byte, use its - * representation inside secp256k1_ecdsa_signature, as conversion is very fast. - * Note that secp256k1_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - secp256k1_scalar_set_b32(r, &sig->data[0], NULL); - secp256k1_scalar_set_b32(s, &sig->data[32], NULL); - } -} - -static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { - if (sizeof(secp256k1_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - secp256k1_scalar_get_b32(&sig->data[0], r); - secp256k1_scalar_get_b32(&sig->data[32], s); - } -} - -int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { - secp256k1_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input != NULL); - - if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { - secp256k1_ecdsa_signature_save(sig, &r, &s); - return 1; - } else { - memset(sig, 0, sizeof(*sig)); - return 0; - } -} - -int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { - secp256k1_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - - secp256k1_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - secp256k1_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - secp256k1_ecdsa_signature_save(sig, &r, &s); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { - secp256k1_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(sig != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); -} - -int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { - secp256k1_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - secp256k1_scalar_get_b32(&output64[0], &r); - secp256k1_scalar_get_b32(&output64[32], &s); - return 1; -} - -int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { - secp256k1_scalar r, s; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sigin != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); - ret = secp256k1_scalar_is_high(&s); - if (sigout != NULL) { - if (ret) { - secp256k1_scalar_negate(&s, &s); - } - secp256k1_ecdsa_signature_save(sigout, &r, &s); - } - - return ret; -} - -int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msghash32, const secp256k1_pubkey *pubkey) { - secp256k1_ge q; - secp256k1_scalar r, s; - secp256k1_scalar m; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_scalar_set_b32(&m, msghash32, NULL); - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return (!secp256k1_scalar_is_high(&s) && - secp256k1_pubkey_load(ctx, &q, pubkey) && - secp256k1_ecdsa_sig_verify(&r, &s, &q, &m)); -} - -static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { - memcpy(buf + *offset, data, len); - *offset += len; -} - -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - unsigned char keydata[112]; - unsigned int offset = 0; - secp256k1_rfc6979_hmac_sha256 rng; - unsigned int i; - secp256k1_scalar msg; - unsigned char msgmod32[32]; - secp256k1_scalar_set_b32(&msg, msg32, NULL); - secp256k1_scalar_get_b32(msgmod32, &msg); - /* We feed a byte array to the PRNG as input, consisting of: - * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. - * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. - * - optionally 16 extra bytes with the algorithm name. - * Because the arguments have distinct fixed lengths it is not possible for - * different argument mixtures to emulate each other and result in the same - * nonces. - */ - buffer_append(keydata, &offset, key32, 32); - buffer_append(keydata, &offset, msgmod32, 32); - if (data != NULL) { - buffer_append(keydata, &offset, data, 32); - } - if (algo16 != NULL) { - buffer_append(keydata, &offset, algo16, 16); - } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); - for (i = 0; i <= counter; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - - secp256k1_memclear(keydata, sizeof(keydata)); - secp256k1_rfc6979_hmac_sha256_clear(&rng); - return 1; -} - -const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; -const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; - -static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar sec, non, msg; - int ret = 0; - int is_sec_valid; - unsigned char nonce32[32]; - unsigned int count = 0; - /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ - *r = secp256k1_scalar_zero; - *s = secp256k1_scalar_zero; - if (recid) { - *recid = 0; - } - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - /* Fail if the secret key is invalid. */ - is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey); - secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !is_sec_valid); - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - int is_nonce_valid; - ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32); - /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ - secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); - if (is_nonce_valid) { - ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); - /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ - secp256k1_declassify(ctx, &ret, sizeof(ret)); - if (ret) { - break; - } - } - count++; - } - /* We don't want to declassify is_sec_valid and therefore the range of - * seckey. As a result is_sec_valid is included in ret only after ret was - * used as a branching variable. */ - ret &= is_sec_valid; - secp256k1_memclear(nonce32, sizeof(nonce32)); - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - secp256k1_scalar_cmov(r, &secp256k1_scalar_zero, !ret); - secp256k1_scalar_cmov(s, &secp256k1_scalar_zero, !ret); - if (recid) { - const int zero = 0; - secp256k1_int_cmov(recid, &zero, !ret); - } - return ret; -} - -int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar r, s; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - - ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata); - secp256k1_ecdsa_signature_save(signature, &r, &s); - return ret; -} - -int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { - secp256k1_scalar sec; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); - secp256k1_scalar_clear(&sec); - return ret; -} - -static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) { - secp256k1_gej pj; - int ret; - - ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey); - secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret); - - secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); - secp256k1_ge_set_gej(p, &pj); - secp256k1_gej_clear(&pj); - return ret; -} - -int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { - secp256k1_ge p; - secp256k1_scalar seckey_scalar; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey != NULL); - - ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); - secp256k1_pubkey_save(pubkey, &p); - secp256k1_memczero(pubkey, sizeof(*pubkey), !ret); - - secp256k1_scalar_clear(&seckey_scalar); - return ret; -} - -int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seckey) { - secp256k1_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); - secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); - secp256k1_scalar_negate(&sec, &sec); - secp256k1_scalar_get_b32(seckey, &sec); - - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { - return secp256k1_ec_seckey_negate(ctx, seckey); -} - -int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { - int ret = 0; - secp256k1_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - - ret = secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - secp256k1_ge_neg(&p, &p); - secp256k1_pubkey_save(pubkey, &p); - } - return ret; -} - - -static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak32) { - secp256k1_scalar term; - int overflow = 0; - int ret = 0; - - secp256k1_scalar_set_b32(&term, tweak32, &overflow); - ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term); - secp256k1_scalar_clear(&term); - return ret; -} - -int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - secp256k1_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); - ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak32); - secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); - secp256k1_scalar_get_b32(seckey, &sec); - - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak32); -} - -static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) { - secp256k1_scalar term; - int overflow = 0; - secp256k1_scalar_set_b32(&term, tweak32, &overflow); - return !overflow && secp256k1_eckey_pubkey_tweak_add(p, &term); -} - -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { - secp256k1_ge p; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&p, tweak32); - if (ret) { - secp256k1_pubkey_save(pubkey, &p); - } - - return ret; -} - -int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - secp256k1_scalar factor; - secp256k1_scalar sec; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - secp256k1_scalar_set_b32(&factor, tweak32, &overflow); - ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); - ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor); - secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); - secp256k1_scalar_get_b32(seckey, &sec); - - secp256k1_scalar_clear(&sec); - secp256k1_scalar_clear(&factor); - return ret; -} - -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak32); -} - -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { - secp256k1_ge p; - secp256k1_scalar factor; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - secp256k1_scalar_set_b32(&factor, tweak32, &overflow); - ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - if (secp256k1_eckey_pubkey_tweak_mul(&p, &factor)) { - secp256k1_pubkey_save(pubkey, &p); - } else { - ret = 0; - } - } - - return ret; -} - -int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_context_is_proper(ctx)); - - if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - } - return 1; -} - -int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { - size_t i; - secp256k1_gej Qj; - secp256k1_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(n >= 1); - ARG_CHECK(pubnonces != NULL); - - secp256k1_gej_set_infinity(&Qj); - - for (i = 0; i < n; i++) { - ARG_CHECK(pubnonces[i] != NULL); - secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); - secp256k1_gej_add_ge(&Qj, &Qj, &Q); - } - if (secp256k1_gej_is_infinity(&Qj)) { - return 0; - } - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(pubnonce, &Q); - return 1; -} - -int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { - secp256k1_sha256 sha; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(hash32 != NULL); - ARG_CHECK(tag != NULL); - ARG_CHECK(msg != NULL); - - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, hash32); - secp256k1_sha256_clear(&sha); - return 1; -} - -#ifdef ENABLE_MODULE_ECDH -# include "modules/ecdh/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "modules/recovery/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -# include "modules/extrakeys/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -# include "modules/schnorrsig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -# include "modules/musig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT -# include "modules/ellswift/main_impl.h" -#endif diff --git a/external/secp256k1/src/selftest.h b/external/secp256k1/src/selftest.h deleted file mode 100644 index d083ac9524..0000000000 --- a/external/secp256k1/src/selftest.h +++ /dev/null @@ -1,32 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SELFTEST_H -#define SECP256K1_SELFTEST_H - -#include "hash.h" - -#include - -static int secp256k1_selftest_sha256(void) { - static const char *input63 = "For this sample, this 63-byte string will be used as input data"; - static const unsigned char output32[32] = { - 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, - 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42, - }; - unsigned char out[32]; - secp256k1_sha256 hasher; - secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); - secp256k1_sha256_finalize(&hasher, out); - return secp256k1_memcmp_var(out, output32, 32) == 0; -} - -static int secp256k1_selftest_passes(void) { - return secp256k1_selftest_sha256(); -} - -#endif /* SECP256K1_SELFTEST_H */ diff --git a/external/secp256k1/src/testrand.h b/external/secp256k1/src/testrand.h deleted file mode 100644 index 3c1ed3d45d..0000000000 --- a/external/secp256k1/src/testrand.h +++ /dev/null @@ -1,48 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_TESTRAND_H -#define SECP256K1_TESTRAND_H - -#include "util.h" - -/* A non-cryptographic RNG used only for test infrastructure. */ - -/** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16); - -/** Generate a pseudorandom number in the range [0..2**32-1]. */ -SECP256K1_INLINE static uint32_t testrand32(void); - -/** Generate a pseudorandom number in the range [0..2**64-1]. */ -SECP256K1_INLINE static uint64_t testrand64(void); - -/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or - * more. */ -SECP256K1_INLINE static uint64_t testrand_bits(int bits); - -/** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t testrand_int(uint32_t range); - -/** Generate a pseudorandom 32-byte array. */ -static void testrand256(unsigned char *b32); - -/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void testrand256_test(unsigned char *b32); - -/** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void testrand_bytes_test(unsigned char *bytes, size_t len); - -/** Flip a single random bit in a byte array */ -static void testrand_flip(unsigned char *b, size_t len); - -/** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ -static void testrand_init(const char* hexseed); - -/** Print final test information. */ -static void testrand_finish(void); - -#endif /* SECP256K1_TESTRAND_H */ diff --git a/external/secp256k1/src/testrand_impl.h b/external/secp256k1/src/testrand_impl.h deleted file mode 100644 index b84f5730a9..0000000000 --- a/external/secp256k1/src/testrand_impl.h +++ /dev/null @@ -1,167 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_TESTRAND_IMPL_H -#define SECP256K1_TESTRAND_IMPL_H - -#include -#include -#include - -#include "testrand.h" -#include "hash.h" -#include "util.h" - -static uint64_t secp256k1_test_state[4]; - -SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { - static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'}; - unsigned char out32[32]; - secp256k1_sha256 hash; - int i; - - /* Use SHA256(PREFIX || seed16) as initial state. */ - secp256k1_sha256_initialize(&hash); - secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX)); - secp256k1_sha256_write(&hash, seed16, 16); - secp256k1_sha256_finalize(&hash, out32); - for (i = 0; i < 4; ++i) { - uint64_t s = 0; - int j; - for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; - secp256k1_test_state[i] = s; - } -} - -SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { - return (x << k) | (x >> (64 - k)); -} - -SECP256K1_INLINE static uint64_t testrand64(void) { - /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ - const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0]; - const uint64_t t = secp256k1_test_state[1] << 17; - secp256k1_test_state[2] ^= secp256k1_test_state[0]; - secp256k1_test_state[3] ^= secp256k1_test_state[1]; - secp256k1_test_state[1] ^= secp256k1_test_state[2]; - secp256k1_test_state[0] ^= secp256k1_test_state[3]; - secp256k1_test_state[2] ^= t; - secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45); - return result; -} - -SECP256K1_INLINE static uint64_t testrand_bits(int bits) { - if (bits == 0) return 0; - return testrand64() >> (64 - bits); -} - -SECP256K1_INLINE static uint32_t testrand32(void) { - return testrand64() >> 32; -} - -static uint32_t testrand_int(uint32_t range) { - uint32_t mask = 0; - uint32_t range_copy; - /* Reduce range by 1, changing its meaning to "maximum value". */ - VERIFY_CHECK(range != 0); - range -= 1; - /* Count the number of bits in range. */ - range_copy = range; - while (range_copy) { - mask = (mask << 1) | 1U; - range_copy >>= 1; - } - /* Generation loop. */ - while (1) { - uint32_t val = testrand64() & mask; - if (val <= range) return val; - } -} - -static void testrand256(unsigned char *b32) { - int i; - for (i = 0; i < 4; ++i) { - uint64_t val = testrand64(); - b32[0] = val; - b32[1] = val >> 8; - b32[2] = val >> 16; - b32[3] = val >> 24; - b32[4] = val >> 32; - b32[5] = val >> 40; - b32[6] = val >> 48; - b32[7] = val >> 56; - b32 += 8; - } -} - -static void testrand_bytes_test(unsigned char *bytes, size_t len) { - size_t bits = 0; - memset(bytes, 0, len); - while (bits < len * 8) { - int now; - uint32_t val; - now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31; - val = testrand_bits(1); - while (now > 0 && bits < len * 8) { - bytes[bits / 8] |= val << (bits % 8); - now--; - bits++; - } - } -} - -static void testrand256_test(unsigned char *b32) { - testrand_bytes_test(b32, 32); -} - -static void testrand_flip(unsigned char *b, size_t len) { - b[testrand_int(len)] ^= (1 << testrand_bits(3)); -} - -static void testrand_init(const char* hexseed) { - unsigned char seed16[16] = {0}; - if (hexseed && strlen(hexseed) != 0) { - int pos = 0; - while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { - unsigned short sh; - if ((sscanf(hexseed, "%2hx", &sh)) == 1) { - seed16[pos] = sh; - } else { - break; - } - hexseed += 2; - pos++; - } - } else { - FILE *frand = fopen("/dev/urandom", "rb"); - if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { - uint64_t t = time(NULL) * (uint64_t)1337; - fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); - seed16[0] ^= t; - seed16[1] ^= t >> 8; - seed16[2] ^= t >> 16; - seed16[3] ^= t >> 24; - seed16[4] ^= t >> 32; - seed16[5] ^= t >> 40; - seed16[6] ^= t >> 48; - seed16[7] ^= t >> 56; - } - if (frand) { - fclose(frand); - } - } - - printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); - testrand_seed(seed16); -} - -static void testrand_finish(void) { - unsigned char run32[32]; - testrand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); -} - -#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/external/secp256k1/src/tests.c b/external/secp256k1/src/tests.c deleted file mode 100644 index 78533b11c2..0000000000 --- a/external/secp256k1/src/tests.c +++ /dev/null @@ -1,7841 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include -#include -#include - -#include - -#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS - #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.") - #undef USE_EXTERNAL_DEFAULT_CALLBACKS -#endif -#if defined(VERIFY) && defined(COVERAGE) - #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.") -#endif -#include "secp256k1.c" - -#include "../include/secp256k1.h" -#include "../include/secp256k1_preallocated.h" -#include "testrand_impl.h" -#include "checkmem.h" -#include "testutil.h" -#include "util.h" - -#include "../contrib/lax_der_parsing.c" -#include "../contrib/lax_der_privatekey_parsing.c" - -#include "modinv32_impl.h" -#ifdef SECP256K1_WIDEMUL_INT128 -#include "modinv64_impl.h" -#include "int128_impl.h" -#endif - -#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else - -static int COUNT = 16; -static secp256k1_context *CTX = NULL; -static secp256k1_context *STATIC_CTX = NULL; - -static int all_bytes_equal(const void* s, unsigned char value, size_t n) { - const unsigned char *p = s; - size_t i; - - for (i = 0; i < n; i++) { - if (p[i] != value) { - return 0; - } - } - return 1; -} - -#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \ - int32_t _calls_to_callback = 0; \ - secp256k1_callback _saved_callback = ctx->callback; \ - callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \ - { expr_or_stmt; } \ - ctx->callback = _saved_callback; \ - CHECK(_calls_to_callback == 1); \ -} while(0); - -/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once - * - * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */ -#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \ - CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, secp256k1_context_set_error_callback) -#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \ - CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, secp256k1_context_set_illegal_callback) - -/* CHECK that - * - expr calls the illegal callback of ctx exactly once and, - * - expr == 0 (or equivalently, expr == NULL) - * - * Useful for checking functions that return an integer or a pointer. */ -#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) -#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0)) - -static void counting_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts. */ - int32_t *p; - (void)str; - p = data; - CHECK(*p != INT32_MAX); - (*p)++; -} - -static void uncounting_illegal_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts (backwards). */ - int32_t *p; - (void)str; - p = data; - CHECK(*p != INT32_MIN); - (*p)--; -} - -static void run_xoshiro256pp_tests(void) { - { - size_t i; - /* Sanity check that we run before the actual seeding. */ - for (i = 0; i < sizeof(secp256k1_test_state)/sizeof(secp256k1_test_state[0]); i++) { - CHECK(secp256k1_test_state[i] == 0); - } - } - { - int i; - unsigned char buf32[32]; - unsigned char seed16[16] = { - 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', - 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', - }; - unsigned char buf32_expected[32] = { - 0xAF, 0xCC, 0xA9, 0x16, 0xB5, 0x6C, 0xE3, 0xF0, - 0x44, 0x3F, 0x45, 0xE0, 0x47, 0xA5, 0x08, 0x36, - 0x4C, 0xCC, 0xC1, 0x18, 0xB2, 0xD8, 0x8F, 0xEF, - 0x43, 0x26, 0x15, 0x57, 0x37, 0x00, 0xEF, 0x30, - }; - testrand_seed(seed16); - for (i = 0; i < 17; i++) { - testrand256(buf32); - } - CHECK(secp256k1_memcmp_var(buf32, buf32_expected, sizeof(buf32)) == 0); - } -} - -static void run_selftest_tests(void) { - /* Test public API */ - secp256k1_selftest(); -} - -static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { - return a->built == b->built - && secp256k1_scalar_eq(&a->scalar_offset, &b->scalar_offset) - && secp256k1_ge_eq_var(&a->ge_offset, &b->ge_offset) - && secp256k1_fe_equal(&a->proj_blind, &b->proj_blind); -} - -static int context_eq(const secp256k1_context *a, const secp256k1_context *b) { - return a->declassify == b->declassify - && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) - && a->illegal_callback.fn == b->illegal_callback.fn - && a->illegal_callback.data == b->illegal_callback.data - && a->error_callback.fn == b->error_callback.fn - && a->error_callback.data == b->error_callback.data; -} - -static void run_deprecated_context_flags_test(void) { - /* Check that a context created with any of the flags in the flags array is - * identical to the NONE context. */ - unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, - SECP256K1_CONTEXT_VERIFY, - SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY }; - secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - int i; - for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) { - secp256k1_context *tmp_ctx; - CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i])); - tmp_ctx = secp256k1_context_create(flags[i]); - CHECK(context_eq(none_ctx, tmp_ctx)); - secp256k1_context_destroy(tmp_ctx); - } - secp256k1_context_destroy(none_ctx); -} - -static void run_ec_illegal_argument_tests(void) { - secp256k1_pubkey pubkey; - secp256k1_pubkey zero_pubkey; - secp256k1_ecdsa_signature sig; - unsigned char ctmp[32]; - - /* Setup */ - memset(ctmp, 1, 32); - memset(&zero_pubkey, 0, sizeof(zero_pubkey)); - - /* Verify context-type checking illegal-argument errors. */ - CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL)); - SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); - SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1); - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1); - CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1); - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1); - CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1); - CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_negate(CTX, NULL)); - CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1); -} - -static void run_static_context_tests(int use_prealloc) { - /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ - CHECK(secp256k1_context_no_precomp == secp256k1_context_static); - - { - unsigned char seed[32] = {0x17}; - - /* Randomizing secp256k1_context_static is not supported. */ - CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, seed)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, NULL)); - - /* Destroying or cloning secp256k1_context_static is not supported. */ - if (use_prealloc) { - CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone_size(STATIC_CTX)); - { - secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); - CHECK(my_static_ctx != NULL); - memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx)); - CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); - free(my_static_ctx); - } - CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_preallocated_destroy(STATIC_CTX)); - } else { - CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_clone(STATIC_CTX)); - CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_destroy(STATIC_CTX)); - } - } - - { - /* Verify that setting and resetting illegal callback works */ - int32_t dummy = 0; - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy); - CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn); - CHECK(STATIC_CTX->illegal_callback.data == &dummy); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); - CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); - CHECK(STATIC_CTX->illegal_callback.data == NULL); - } -} - -static void run_proper_context_tests(int use_prealloc) { - int32_t dummy = 0; - secp256k1_context *my_ctx, *my_ctx_fresh; - void *my_ctx_prealloc = NULL; - unsigned char seed[32] = {0x17}; - - secp256k1_gej pubj; - secp256k1_ge pub; - secp256k1_scalar msg, key, nonce; - secp256k1_scalar sigr, sigs; - - /* Fresh reference context for comparison */ - my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - - if (use_prealloc) { - my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - CHECK(my_ctx_prealloc != NULL); - my_ctx = secp256k1_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE); - } else { - my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - } - - /* Randomize and reset randomization */ - CHECK(context_eq(my_ctx, my_ctx_fresh)); - CHECK(secp256k1_context_randomize(my_ctx, seed) == 1); - CHECK(!context_eq(my_ctx, my_ctx_fresh)); - CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1); - CHECK(context_eq(my_ctx, my_ctx_fresh)); - - /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */ - secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL); - CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); - CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); - - /* check if sizes for cloning are consistent */ - CHECK(secp256k1_context_preallocated_clone_size(my_ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - - /*** clone and destroy all of them to make sure cloning was complete ***/ - { - secp256k1_context *ctx_tmp; - - if (use_prealloc) { - /* clone into a non-preallocated context and then again into a new preallocated one. */ - ctx_tmp = my_ctx; - my_ctx = secp256k1_context_clone(my_ctx); - CHECK(context_eq(ctx_tmp, my_ctx)); - secp256k1_context_preallocated_destroy(ctx_tmp); - - free(my_ctx_prealloc); - my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - CHECK(my_ctx_prealloc != NULL); - ctx_tmp = my_ctx; - my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); - CHECK(context_eq(ctx_tmp, my_ctx)); - secp256k1_context_destroy(ctx_tmp); - } else { - /* clone into a preallocated context and then again into a new non-preallocated one. */ - void *prealloc_tmp; - - prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - CHECK(prealloc_tmp != NULL); - ctx_tmp = my_ctx; - my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); - CHECK(context_eq(ctx_tmp, my_ctx)); - secp256k1_context_destroy(ctx_tmp); - - ctx_tmp = my_ctx; - my_ctx = secp256k1_context_clone(my_ctx); - CHECK(context_eq(ctx_tmp, my_ctx)); - secp256k1_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - } - } - - /* Verify that the error callback makes it across the clone. */ - CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); - CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); - /* And that it resets back to default. */ - secp256k1_context_set_error_callback(my_ctx, NULL, NULL); - CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn); - CHECK(context_eq(my_ctx, my_ctx_fresh)); - - /* Verify that setting and resetting illegal callback works */ - secp256k1_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy); - CHECK(my_ctx->illegal_callback.fn == counting_callback_fn); - CHECK(my_ctx->illegal_callback.data == &dummy); - secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); - CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); - CHECK(my_ctx->illegal_callback.data == NULL); - CHECK(context_eq(my_ctx, my_ctx_fresh)); - - /*** attempt to use them ***/ - testutil_random_scalar_order_test(&msg); - testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); - - /* obtain a working nonce */ - do { - testutil_random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - - /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - - /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); - - /* cleanup */ - if (use_prealloc) { - secp256k1_context_preallocated_destroy(my_ctx); - free(my_ctx_prealloc); - } else { - secp256k1_context_destroy(my_ctx); - } - secp256k1_context_destroy(my_ctx_fresh); - - /* Defined as no-op. */ - secp256k1_context_destroy(NULL); - secp256k1_context_preallocated_destroy(NULL); -} - -static void run_scratch_tests(void) { - const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; - - size_t checkpoint; - size_t checkpoint_2; - secp256k1_scratch_space *scratch; - secp256k1_scratch_space local_scratch; - - /* Test public API */ - scratch = secp256k1_scratch_space_create(CTX, 1000); - CHECK(scratch != NULL); - - /* Test internal API */ - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); - CHECK(scratch->alloc_size == 0); - CHECK(scratch->alloc_size % ALIGNMENT == 0); - - /* Allocating 500 bytes succeeds */ - checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); - CHECK(scratch->alloc_size != 0); - CHECK(scratch->alloc_size % ALIGNMENT == 0); - - /* Allocating another 501 bytes fails */ - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 501) == NULL); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); - CHECK(scratch->alloc_size != 0); - CHECK(scratch->alloc_size % ALIGNMENT == 0); - - /* ...but it succeeds once we apply the checkpoint to undo it */ - secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); - CHECK(scratch->alloc_size == 0); - CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); - CHECK(scratch->alloc_size != 0); - - /* try to apply a bad checkpoint */ - checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); - secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); - CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ - CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ - - /* try to use badly initialized scratch space */ - secp256k1_scratch_space_destroy(CTX, scratch); - memset(&local_scratch, 0, sizeof(local_scratch)); - scratch = &local_scratch; - CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); - CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); - CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); - - /* Test that large integers do not wrap around in a bad way */ - scratch = secp256k1_scratch_space_create(CTX, 1000); - /* Try max allocation with a large number of objects. Only makes sense if - * ALIGNMENT is greater than 1 because otherwise the objects take no extra - * space. */ - CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); - /* Try allocating SIZE_MAX to test wrap around which only happens if - * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch - * space is too small. */ - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL); - secp256k1_scratch_space_destroy(CTX, scratch); - - /* cleanup */ - secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ -} - -static void run_ctz_tests(void) { - static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; - static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; - int shift; - unsigned i; - for (i = 0; i < sizeof(b32) / sizeof(b32[0]); ++i) { - for (shift = 0; shift < 32; ++shift) { - CHECK(secp256k1_ctz32_var_debruijn(b32[i] << shift) == shift); - CHECK(secp256k1_ctz32_var(b32[i] << shift) == shift); - } - } - for (i = 0; i < sizeof(b64) / sizeof(b64[0]); ++i) { - for (shift = 0; shift < 64; ++shift) { - CHECK(secp256k1_ctz64_var_debruijn(b64[i] << shift) == shift); - CHECK(secp256k1_ctz64_var(b64[i] << shift) == shift); - } - } -} - -/***** HASH TESTS *****/ - -static void run_sha256_known_output_tests(void) { - static const char *inputs[] = { - "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "For this sample, this 63-byte string will be used as input data", - "This is exactly 64 bytes long, not counting the terminating byte", - "aaaaa", - }; - static const unsigned int repeat[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1000000/5 - }; - static const unsigned char outputs[][32] = { - {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, - {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, - {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, - {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, - {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, - {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, - {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, - {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}, - {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}, - }; - unsigned int i, ninputs; - - /* Skip last input vector for low iteration counts */ - ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1; - CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++; - - for (i = 0; i < ninputs; i++) { - unsigned char out[32]; - secp256k1_sha256 hasher; - unsigned int j; - /* 1. Run: simply write the input bytestrings */ - j = repeat[i]; - secp256k1_sha256_initialize(&hasher); - while (j > 0) { - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - j--; - } - secp256k1_sha256_finalize(&hasher, out); - CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); - /* 2. Run: split the input bytestrings randomly before writing */ - if (strlen(inputs[i]) > 0) { - int split = testrand_int(strlen(inputs[i])); - secp256k1_sha256_initialize(&hasher); - j = repeat[i]; - while (j > 0) { - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - j--; - } - secp256k1_sha256_finalize(&hasher, out); - CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); - } - } -} - -/** SHA256 counter tests - -The tests verify that the SHA256 counter doesn't wrap around at message length -2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the -implementation of the counter and it catches multiple natural 32-bit overflows -(e.g., counting bits, counting bytes, counting blocks, ...). - -The test vectors have been generated using following Python script which relies -on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2). - -``` -from sha256 import sha256 -from copy import copy - -def midstate_c_definition(hasher): - ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n' - ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}' - return ret - -def output_c_literal(hasher): - return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}' - -MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno' -assert(len(MESSAGE) == 64) -BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)] - -midstates = [] -digests = [] -hasher = sha256() -for i in range(BYTE_BOUNDARIES[-1] + 1): - if i in BYTE_BOUNDARIES: - midstates.append(midstate_c_definition(hasher)) - hasher_copy = copy(hasher) - hasher_copy.update(MESSAGE) - digests.append(output_c_literal(hasher_copy)) - hasher.update(MESSAGE) - -for x in midstates: - print(x + ',') - -for x in digests: - print(x + ',') -``` -*/ -static void run_sha256_counter_tests(void) { - static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; - static const secp256k1_sha256 midstates[] = { - {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, - {0x00}, 0xfffc0}, - {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26}, - {0x00}, 0x1fffc0}, - {{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1}, - {0x00}, 0x3fffc0}, - {{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6}, - {0x00}, 0x7fffc0}, - {{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c}, - {0x00}, 0xffffc0}, - {{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2}, - {0x00}, 0x1ffffc0}, - {{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c}, - {0x00}, 0x3ffffc0}, - {{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0}, - {0x00}, 0x7ffffc0}, - {{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad}, - {0x00}, 0xfffffc0}, - {{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023}, - {0x00}, 0x1fffffc0}, - {{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1}, - {0x00}, 0x3fffffc0}, - {{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec}, - {0x00}, 0x7fffffc0}, - {{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162}, - {0x00}, 0xffffffc0}, - {{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a}, - {0x00}, 0x1ffffffc0}, - }; - static const unsigned char outputs[][32] = { - {0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15}, - {0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb}, - {0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e}, - {0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9}, - {0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7}, - {0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07}, - {0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76}, - {0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0}, - {0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8}, - {0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6}, - {0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e}, - {0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b}, - {0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34}, - {0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e}, - }; - unsigned int i; - for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) { - unsigned char out[32]; - secp256k1_sha256 hasher = midstates[i]; - secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); - secp256k1_sha256_finalize(&hasher, out); - CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); - } -} - -/* Tests for the equality of two sha256 structs. This function only produces a - * correct result if an integer multiple of 64 many bytes have been written - * into the hash functions. This function is used by some module tests. */ -static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { - /* Is buffer fully consumed? */ - CHECK((sha1->bytes & 0x3F) == 0); - - CHECK(sha1->bytes == sha2->bytes); - CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); -} - -static void run_hmac_sha256_tests(void) { - static const char *keys[6] = { - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - "\x4a\x65\x66\x65", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - }; - static const char *inputs[6] = { - "\x48\x69\x20\x54\x68\x65\x72\x65", - "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", - "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", - "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", - "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", - "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" - }; - static const unsigned char outputs[6][32] = { - {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, - {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, - {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, - {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, - {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, - {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} - }; - int i; - for (i = 0; i < 6; i++) { - secp256k1_hmac_sha256 hasher; - unsigned char out[32]; - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); - if (strlen(inputs[i]) > 0) { - int split = testrand_int(strlen(inputs[i])); - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); - } - } -} - -static void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; - static const unsigned char out1[3][32] = { - {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, - {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, - {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} - }; - - static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; - static const unsigned char out2[3][32] = { - {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, - {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, - {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} - }; - - secp256k1_rfc6979_hmac_sha256 rng; - unsigned char out[32]; - int i; - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); -} - -static void run_tagged_sha256_tests(void) { - unsigned char tag[32] = { 0 }; - unsigned char msg[32] = { 0 }; - unsigned char hash32[32]; - unsigned char hash_expected[32] = { - 0x04, 0x7A, 0x5E, 0x17, 0xB5, 0x86, 0x47, 0xC1, - 0x3C, 0xC6, 0xEB, 0xC0, 0xAA, 0x58, 0x3B, 0x62, - 0xFB, 0x16, 0x43, 0x32, 0x68, 0x77, 0x40, 0x6C, - 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 - }; - - /* API test */ - CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); - CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg))); - CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg))); - CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0)); - - /* Static test vector */ - memcpy(tag, "tag", 3); - memcpy(msg, "msg", 3); - CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, 3, msg, 3) == 1); - CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); -} - -/***** MODINV TESTS *****/ - -/* Compute the modular inverse of (odd) x mod 2^64. */ -static uint64_t modinv2p64(uint64_t x) { - /* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See - * Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for - * why. Start with L=0, for which it is true for every odd x that - * 1/x=1 mod 2. Iterating 6 times gives us 1/x mod 2^64. */ - int l; - uint64_t w = 1; - CHECK(x & 1); - for (l = 0; l < 6; ++l) w *= (2 - w*x); - return w; -} - - -/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity. - * - * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other - * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ -static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { - uint16_t mul[32]; - uint64_t c = 0; - int i, j; - int m_bitlen = 0; - int mul_bitlen = 0; - - if (b != NULL) { - /* Compute the product of a and b, and put it in mul. */ - for (i = 0; i < 32; ++i) { - for (j = i <= 15 ? 0 : i - 15; j <= i && j <= 15; j++) { - c += (uint64_t)a[j] * b[i - j]; - } - mul[i] = c & 0xFFFF; - c >>= 16; - } - CHECK(c == 0); - - /* compute the highest set bit in mul */ - for (i = 511; i >= 0; --i) { - if ((mul[i >> 4] >> (i & 15)) & 1) { - mul_bitlen = i; - break; - } - } - } else { - /* if b==NULL, set mul=a. */ - memcpy(mul, a, 32); - memset(mul + 16, 0, 32); - /* compute the highest set bit in mul */ - for (i = 255; i >= 0; --i) { - if ((mul[i >> 4] >> (i & 15)) & 1) { - mul_bitlen = i; - break; - } - } - } - - if (m) { - /* Compute the highest set bit in m. */ - for (i = 255; i >= 0; --i) { - if ((m[i >> 4] >> (i & 15)) & 1) { - m_bitlen = i; - break; - } - } - - /* Try do mul -= m<= 0; --i) { - uint16_t mul2[32]; - int64_t cs; - - /* Compute mul2 = mul - m<= 0 && bitpos < 256) { - sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; - } - } - /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ - cs += mul[j]; - cs -= sub; - mul2[j] = (cs & 0xFFFF); - cs >>= 16; - } - /* If remainder of subtraction is 0, set mul = mul2. */ - if (cs == 0) { - memcpy(mul, mul2, sizeof(mul)); - } - } - /* Sanity check: test that all limbs higher than m's highest are zero */ - for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { - CHECK(mul[i] == 0); - } - } - memcpy(out, mul, 32); -} - -/* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */ -static void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { - int i; - memset(out->v, 0, sizeof(out->v)); - for (i = 0; i < 256; ++i) { - out->v[i / 30] |= (int32_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 30); - } -} - -/* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */ -static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { - int i; - memset(out, 0, 32); - for (i = 0; i < 256; ++i) { - out[i >> 4] |= (((in->v[i / 30]) >> (i % 30)) & 1) << (i & 15); - } -} - -/* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */ -static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { - int i; - for (i = 0; i < 16; ++i) { - int pos = testrand_bits(3); - if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) { - x->v[pos] -= 0x40000000; - x->v[pos + 1] += 1; - } else if (x->v[pos] < 0 && x->v[pos + 1] >= 0x3fffffff) { - x->v[pos] += 0x40000000; - x->v[pos + 1] -= 1; - } - } -} - -/* Test secp256k1_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ -static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { - uint16_t tmp[16]; - secp256k1_modinv32_signed30 x; - secp256k1_modinv32_modinfo m; - int i, vartime, nonzero; - - uint16_to_signed30(&x, in); - nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0; - uint16_to_signed30(&m.modulus, mod); - - /* compute 1/modulus mod 2^30 */ - m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff; - CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1); - - /* Test secp256k1_jacobi32_maybe_var. */ - if (nonzero) { - int jac; - uint16_t sqr[16], negone[16]; - mulmod256(sqr, in, in, mod); - uint16_to_signed30(&x, sqr); - /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ - jac = secp256k1_jacobi32_maybe_var(&x, &m); - CHECK(jac == 0 || jac == 1); - /* Then compute the jacobi symbol of -(in^2). x and -x have opposite - * jacobi symbols if and only if (mod % 4) == 3. */ - negone[0] = mod[0] - 1; - for (i = 1; i < 16; ++i) negone[i] = mod[i]; - mulmod256(sqr, sqr, negone, mod); - uint16_to_signed30(&x, sqr); - jac = secp256k1_jacobi32_maybe_var(&x, &m); - CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); - } - - uint16_to_signed30(&x, in); - mutate_sign_signed30(&m.modulus); - for (vartime = 0; vartime < 2; ++vartime) { - /* compute inverse */ - (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); - - /* produce output */ - signed30_to_uint16(out, &x); - - /* check if the inverse times the input is 1 (mod m), unless x is 0. */ - mulmod256(tmp, out, in, mod); - CHECK(tmp[0] == nonzero); - for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); - - /* invert again */ - (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); - - /* check if the result is equal to the input */ - signed30_to_uint16(tmp, &x); - for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); - } -} - -#ifdef SECP256K1_WIDEMUL_INT128 -/* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */ -static void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { - int i; - memset(out->v, 0, sizeof(out->v)); - for (i = 0; i < 256; ++i) { - out->v[i / 62] |= (int64_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 62); - } -} - -/* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */ -static void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { - int i; - memset(out, 0, 32); - for (i = 0; i < 256; ++i) { - out[i >> 4] |= (((in->v[i / 62]) >> (i % 62)) & 1) << (i & 15); - } -} - -/* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */ -static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { - static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - int i; - for (i = 0; i < 8; ++i) { - int pos = testrand_bits(2); - if (x->v[pos] > 0 && x->v[pos + 1] <= M62) { - x->v[pos] -= (M62 + 1); - x->v[pos + 1] += 1; - } else if (x->v[pos] < 0 && x->v[pos + 1] >= -M62) { - x->v[pos] += (M62 + 1); - x->v[pos + 1] -= 1; - } - } -} - -/* Test secp256k1_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ -static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { - static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - uint16_t tmp[16]; - secp256k1_modinv64_signed62 x; - secp256k1_modinv64_modinfo m; - int i, vartime, nonzero; - - uint16_to_signed62(&x, in); - nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0; - uint16_to_signed62(&m.modulus, mod); - - /* compute 1/modulus mod 2^62 */ - m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62; - CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1); - - /* Test secp256k1_jacobi64_maybe_var. */ - if (nonzero) { - int jac; - uint16_t sqr[16], negone[16]; - mulmod256(sqr, in, in, mod); - uint16_to_signed62(&x, sqr); - /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ - jac = secp256k1_jacobi64_maybe_var(&x, &m); - CHECK(jac == 0 || jac == 1); - /* Then compute the jacobi symbol of -(in^2). x and -x have opposite - * jacobi symbols if and only if (mod % 4) == 3. */ - negone[0] = mod[0] - 1; - for (i = 1; i < 16; ++i) negone[i] = mod[i]; - mulmod256(sqr, sqr, negone, mod); - uint16_to_signed62(&x, sqr); - jac = secp256k1_jacobi64_maybe_var(&x, &m); - CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); - } - - uint16_to_signed62(&x, in); - mutate_sign_signed62(&m.modulus); - for (vartime = 0; vartime < 2; ++vartime) { - /* compute inverse */ - (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); - - /* produce output */ - signed62_to_uint16(out, &x); - - /* check if the inverse times the input is 1 (mod m), unless x is 0. */ - mulmod256(tmp, out, in, mod); - CHECK(tmp[0] == nonzero); - for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); - - /* invert again */ - (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); - - /* check if the result is equal to the input */ - signed62_to_uint16(tmp, &x); - for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); - } -} -#endif - -/* test if a and b are coprime */ -static int coprime(const uint16_t* a, const uint16_t* b) { - uint16_t x[16], y[16], t[16]; - int i; - int iszero; - memcpy(x, a, 32); - memcpy(y, b, 32); - - /* simple gcd loop: while x!=0, (x,y)=(y%x,x) */ - while (1) { - iszero = 1; - for (i = 0; i < 16; ++i) { - if (x[i] != 0) { - iszero = 0; - break; - } - } - if (iszero) break; - mulmod256(t, y, NULL, x); - memcpy(y, x, 32); - memcpy(x, t, 32); - } - - /* return whether y=1 */ - if (y[0] != 1) return 0; - for (i = 1; i < 16; ++i) { - if (y[i] != 0) return 0; - } - return 1; -} - -static void run_modinv_tests(void) { - /* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */ - static const uint16_t CASES[][3][16] = { - /* Test cases triggering edge cases in divsteps */ - - /* Test case known to need 713 divsteps */ - {{0x1513, 0x5389, 0x54e9, 0x2798, 0x1957, 0x66a0, 0x8057, 0x3477, - 0x7784, 0x1052, 0x326a, 0x9331, 0x6506, 0xa95c, 0x91f3, 0xfb5e}, - {0x2bdd, 0x8df4, 0xcc61, 0x481f, 0xdae5, 0x5ca7, 0xf43b, 0x7d54, - 0x13d6, 0x469b, 0x2294, 0x20f4, 0xb2a4, 0xa2d1, 0x3ff1, 0xfd4b}, - {0xffd8, 0xd9a0, 0x456e, 0x81bb, 0xbabd, 0x6cea, 0x6dbd, 0x73ab, - 0xbb94, 0x3d3c, 0xdf08, 0x31c4, 0x3e32, 0xc179, 0x2486, 0xb86b}}, - /* Test case known to need 589 divsteps, reaching delta=-140 and - delta=141. */ - {{0x3fb1, 0x903b, 0x4eb7, 0x4813, 0xd863, 0x26bf, 0xd89f, 0xa8a9, - 0x02fe, 0x57c6, 0x554a, 0x4eab, 0x165e, 0x3d61, 0xee1e, 0x456c}, - {0x9295, 0x823b, 0x5c1f, 0x5386, 0x48e0, 0x02ff, 0x4c2a, 0xa2da, - 0xe58f, 0x967c, 0xc97e, 0x3f5a, 0x69fb, 0x52d9, 0x0a86, 0xb4a3}, - {0x3d30, 0xb893, 0xa809, 0xa7a8, 0x26f5, 0x5b42, 0x55be, 0xf4d0, - 0x12c2, 0x7e6a, 0xe41a, 0x90c7, 0xebfa, 0xf920, 0x304e, 0x1419}}, - /* Test case known to need 650 divsteps, and doing 65 consecutive (f,g/2) steps. */ - {{0x8583, 0x5058, 0xbeae, 0xeb69, 0x48bc, 0x52bb, 0x6a9d, 0xcc94, - 0x2a21, 0x87d5, 0x5b0d, 0x42f6, 0x5b8a, 0x2214, 0xe9d6, 0xa040}, - {0x7531, 0x27cb, 0x7e53, 0xb739, 0x6a5f, 0x83f5, 0xa45c, 0xcb1d, - 0x8a87, 0x1c9c, 0x51d7, 0x851c, 0xb9d8, 0x1fbe, 0xc241, 0xd4a3}, - {0xcdb4, 0x275c, 0x7d22, 0xa906, 0x0173, 0xc054, 0x7fdf, 0x5005, - 0x7fb8, 0x9059, 0xdf51, 0x99df, 0x2654, 0x8f6e, 0x070f, 0xb347}}, - /* example needing 713 divsteps; delta=-2..3 */ - {{0xe2e9, 0xee91, 0x4345, 0xe5ad, 0xf3ec, 0x8f42, 0x0364, 0xd5c9, - 0xff49, 0xbef5, 0x4544, 0x4c7c, 0xae4b, 0xfd9d, 0xb35b, 0xda9d}, - {0x36e7, 0x8cca, 0x2ed0, 0x47b3, 0xaca4, 0xb374, 0x7d2a, 0x0772, - 0x6bdb, 0xe0a7, 0x900b, 0xfe10, 0x788c, 0x6f22, 0xd909, 0xf298}, - {0xd8c6, 0xba39, 0x13ed, 0x198c, 0x16c8, 0xb837, 0xa5f2, 0x9797, - 0x0113, 0x882a, 0x15b5, 0x324c, 0xabee, 0xe465, 0x8170, 0x85ac}}, - /* example needing 713 divsteps; delta=-2..3 */ - {{0xd5b7, 0x2966, 0x040e, 0xf59a, 0x0387, 0xd96d, 0xbfbc, 0xd850, - 0x2d96, 0x872a, 0xad81, 0xc03c, 0xbb39, 0xb7fa, 0xd904, 0xef78}, - {0x6279, 0x4314, 0xfdd3, 0x1568, 0x0982, 0x4d13, 0x625f, 0x010c, - 0x22b1, 0x0cc3, 0xf22d, 0x5710, 0x1109, 0x5751, 0x7714, 0xfcf2}, - {0xdb13, 0x5817, 0x232e, 0xe456, 0xbbbc, 0x6fbe, 0x4572, 0xa358, - 0xc76d, 0x928e, 0x0162, 0x5314, 0x8325, 0x5683, 0xe21b, 0xda88}}, - /* example needing 713 divsteps; delta=-2..3 */ - {{0xa06f, 0x71ee, 0x3bac, 0x9ebb, 0xdeaa, 0x09ed, 0x1cf7, 0x9ec9, - 0x7158, 0x8b72, 0x5d53, 0x5479, 0x5c75, 0xbb66, 0x9125, 0xeccc}, - {0x2941, 0xd46c, 0x3cd4, 0x4a9d, 0x5c4a, 0x256b, 0xbd6c, 0x9b8e, - 0x8fe0, 0x8a14, 0xffe8, 0x2496, 0x618d, 0xa9d7, 0x5018, 0xfb29}, - {0x437c, 0xbd60, 0x7590, 0x94bb, 0x0095, 0xd35e, 0xd4fe, 0xd6da, - 0x0d4e, 0x5342, 0x4cd2, 0x169b, 0x661c, 0x1380, 0xed2d, 0x85c1}}, - /* example reaching delta=-64..65; 661 divsteps */ - {{0xfde4, 0x68d6, 0x6c48, 0x7f77, 0x1c78, 0x96de, 0x2fd9, 0xa6c2, - 0xbbb5, 0xd319, 0x69cf, 0xd4b3, 0xa321, 0xcda0, 0x172e, 0xe530}, - {0xd9e3, 0x0f60, 0x3d86, 0xeeab, 0x25ee, 0x9582, 0x2d50, 0xfe16, - 0xd4e2, 0xe3ba, 0x94e2, 0x9833, 0x6c5e, 0x8982, 0x13b6, 0xe598}, - {0xe675, 0xf55a, 0x10f6, 0xabde, 0x5113, 0xecaa, 0x61ae, 0xad9f, - 0x0c27, 0xef33, 0x62e5, 0x211d, 0x08fa, 0xa78d, 0xc675, 0x8bae}}, - /* example reaching delta=-64..65; 661 divsteps */ - {{0x21bf, 0x52d5, 0x8fd4, 0xaa18, 0x156a, 0x7247, 0xebb8, 0x5717, - 0x4eb5, 0x1421, 0xb58f, 0x3b0b, 0x5dff, 0xe533, 0xb369, 0xd28a}, - {0x9f6b, 0xe463, 0x2563, 0xc74d, 0x6d81, 0x636a, 0x8fc8, 0x7a94, - 0x9429, 0x1585, 0xf35e, 0x7ff5, 0xb64f, 0x9720, 0xba74, 0xe108}, - {0xa5ab, 0xea7b, 0xfe5e, 0x8a85, 0x13be, 0x7934, 0xe8a0, 0xa187, - 0x86b5, 0xe477, 0xb9a4, 0x75d7, 0x538f, 0xdd70, 0xc781, 0xb67d}}, - /* example reaching delta=-64..65; 661 divsteps */ - {{0xa41a, 0x3e8d, 0xf1f5, 0x9493, 0x868c, 0x5103, 0x2725, 0x3ceb, - 0x6032, 0x3624, 0xdc6b, 0x9120, 0xbf4c, 0x8821, 0x91ad, 0xb31a}, - {0x5c0b, 0xdda5, 0x20f8, 0x32a1, 0xaf73, 0x6ec5, 0x4779, 0x43d6, - 0xd454, 0x9573, 0xbf84, 0x5a58, 0xe04e, 0x307e, 0xd1d5, 0xe230}, - {0xda15, 0xbcd6, 0x7180, 0xabd3, 0x04e6, 0x6986, 0xc0d7, 0x90bb, - 0x3a4d, 0x7c95, 0xaaab, 0x9ab3, 0xda34, 0xa7f6, 0x9636, 0x6273}}, - /* example doing 123 consecutive (f,g/2) steps; 615 divsteps */ - {{0xb4d6, 0xb38f, 0x00aa, 0xebda, 0xd4c2, 0x70b8, 0x9dad, 0x58ee, - 0x68f8, 0x48d3, 0xb5ff, 0xf422, 0x9e46, 0x2437, 0x18d0, 0xd9cc}, - {0x5c83, 0xfed7, 0x97f5, 0x3f07, 0xcaad, 0x95b1, 0xb4a4, 0xb005, - 0x23af, 0xdd27, 0x6c0d, 0x932c, 0xe2b2, 0xe3ae, 0xfb96, 0xdf67}, - {0x3105, 0x0127, 0xfd48, 0x039b, 0x35f1, 0xbc6f, 0x6c0a, 0xb572, - 0xe4df, 0xebad, 0x8edc, 0xb89d, 0x9555, 0x4c26, 0x1fef, 0x997c}}, - /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ - {{0x5138, 0xd474, 0x385f, 0xc964, 0x00f2, 0x6df7, 0x862d, 0xb185, - 0xb264, 0xe9e1, 0x466c, 0xf39e, 0xafaf, 0x5f41, 0x47e2, 0xc89d}, - {0x8607, 0x9c81, 0x46a2, 0x7dcc, 0xcb0c, 0x9325, 0xe149, 0x2bde, - 0x6632, 0x2869, 0xa261, 0xb163, 0xccee, 0x22ae, 0x91e0, 0xcfd5}, - {0x831c, 0xda22, 0xb080, 0xba7a, 0x26e2, 0x54b0, 0x073b, 0x5ea0, - 0xed4b, 0xcb3d, 0xbba1, 0xbec8, 0xf2ad, 0xae0d, 0x349b, 0x17d1}}, - /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ - {{0xe9a5, 0xb4ad, 0xd995, 0x9953, 0xcdff, 0x50d7, 0xf715, 0x9dc7, - 0x3e28, 0x15a9, 0x95a3, 0x8554, 0x5b5e, 0xad1d, 0x6d57, 0x3d50}, - {0x3ad9, 0xbd60, 0x5cc7, 0x6b91, 0xadeb, 0x71f6, 0x7cc4, 0xa58a, - 0x2cce, 0xf17c, 0x38c9, 0x97ed, 0x65fb, 0x3fa6, 0xa6bc, 0xeb24}, - {0xf96c, 0x1963, 0x8151, 0xa0cc, 0x299b, 0xf277, 0x001a, 0x16bb, - 0xfd2e, 0x532d, 0x0410, 0xe117, 0x6b00, 0x44ec, 0xca6a, 0x1745}}, - /* example doing 446 (f,g/2) steps; 523 divsteps */ - {{0x3758, 0xa56c, 0xe41e, 0x4e47, 0x0975, 0xa82b, 0x107c, 0x89cf, - 0x2093, 0x5a0c, 0xda37, 0xe007, 0x6074, 0x4f68, 0x2f5a, 0xbb8a}, - {0x4beb, 0xa40f, 0x2c42, 0xd9d6, 0x97e8, 0xca7c, 0xd395, 0x894f, - 0x1f50, 0x8067, 0xa233, 0xb850, 0x1746, 0x1706, 0xbcda, 0xdf32}, - {0x762a, 0xceda, 0x4c45, 0x1ca0, 0x8c37, 0xd8c5, 0xef57, 0x7a2c, - 0x6e98, 0xe38a, 0xc50e, 0x2ca9, 0xcb85, 0x24d5, 0xc29c, 0x61f6}}, - /* example doing 446 (f,g/2) steps; 523 divsteps */ - {{0x6f38, 0x74ad, 0x7332, 0x4073, 0x6521, 0xb876, 0xa370, 0xa6bd, - 0xcea5, 0xbd06, 0x969f, 0x77c6, 0x1e69, 0x7c49, 0x7d51, 0xb6e7}, - {0x3f27, 0x4be4, 0xd81e, 0x1396, 0xb21f, 0x92aa, 0x6dc3, 0x6283, - 0x6ada, 0x3ca2, 0xc1e5, 0x8b9b, 0xd705, 0x5598, 0x8ba1, 0xe087}, - {0x6a22, 0xe834, 0xbc8d, 0xcee9, 0x42fc, 0xfc77, 0x9c45, 0x1ca8, - 0xeb66, 0xed74, 0xaaf9, 0xe75f, 0xfe77, 0x46d2, 0x179b, 0xbf3e}}, - /* example doing 336 (f,(f+g)/2) steps; 693 divsteps */ - {{0x7ea7, 0x444e, 0x84ea, 0xc447, 0x7c1f, 0xab97, 0x3de6, 0x5878, - 0x4e8b, 0xc017, 0x03e0, 0xdc40, 0xbbd0, 0x74ce, 0x0169, 0x7ab5}, - {0x4023, 0x154f, 0xfbe4, 0x8195, 0xfda0, 0xef54, 0x9e9a, 0xc703, - 0x2803, 0xf760, 0x6302, 0xed5b, 0x7157, 0x6456, 0xdd7d, 0xf14b}, - {0xb6fb, 0xe3b3, 0x0733, 0xa77e, 0x44c5, 0x3003, 0xc937, 0xdd4d, - 0x5355, 0x14e9, 0x184e, 0xcefe, 0xe6b5, 0xf2e0, 0x0a28, 0x5b74}}, - /* example doing 336 (f,(f+g)/2) steps; 687 divsteps */ - {{0xa893, 0xb5f4, 0x1ede, 0xa316, 0x242c, 0xbdcc, 0xb017, 0x0836, - 0x3a37, 0x27fb, 0xfb85, 0x251e, 0xa189, 0xb15d, 0xa4b8, 0xc24c}, - {0xb0b7, 0x57ba, 0xbb6d, 0x9177, 0xc896, 0xc7f2, 0x43b4, 0x85a6, - 0xe6c4, 0xe50e, 0x3109, 0x7ca5, 0xd73d, 0x13ff, 0x0c3d, 0xcd62}, - {0x48ca, 0xdb34, 0xe347, 0x2cef, 0x4466, 0x10fb, 0x7ee1, 0x6344, - 0x4308, 0x966d, 0xd4d1, 0xb099, 0x994f, 0xd025, 0x2187, 0x5866}}, - /* example doing 267 (g,(g-f)/2) steps; 678 divsteps */ - {{0x0775, 0x1754, 0x01f6, 0xdf37, 0xc0be, 0x8197, 0x072f, 0x6cf5, - 0x8b36, 0x8069, 0x5590, 0xb92d, 0x6084, 0x47a4, 0x23fe, 0xddd5}, - {0x8e1b, 0xda37, 0x27d9, 0x312e, 0x3a2f, 0xef6d, 0xd9eb, 0x8153, - 0xdcba, 0x9fa3, 0x9f80, 0xead5, 0x134d, 0x2ebb, 0x5ec0, 0xe032}, - {0x1cb6, 0x5a61, 0x1bed, 0x77d6, 0xd5d1, 0x7498, 0xef33, 0x2dd2, - 0x1089, 0xedbd, 0x6958, 0x16ae, 0x336c, 0x45e6, 0x4361, 0xbadc}}, - /* example doing 267 (g,(g-f)/2) steps; 676 divsteps */ - {{0x0207, 0xf948, 0xc430, 0xf36b, 0xf0a7, 0x5d36, 0x751f, 0x132c, - 0x6f25, 0xa630, 0xca1f, 0xc967, 0xaf9c, 0x34e7, 0xa38f, 0xbe9f}, - {0x5fb9, 0x7321, 0x6561, 0x5fed, 0x54ec, 0x9c3a, 0xee0e, 0x6717, - 0x49af, 0xb896, 0xf4f5, 0x451c, 0x722a, 0xf116, 0x64a9, 0xcf0b}, - {0xf4d7, 0xdb47, 0xfef2, 0x4806, 0x4cb8, 0x18c7, 0xd9a7, 0x4951, - 0x14d8, 0x5c3a, 0xd22d, 0xd7b2, 0x750c, 0x3de7, 0x8b4a, 0x19aa}}, - - /* Test cases triggering edge cases in divsteps variant starting with delta=1/2 */ - - /* example needing 590 divsteps; delta=-5/2..7/2 */ - {{0x9118, 0xb640, 0x53d7, 0x30ab, 0x2a23, 0xd907, 0x9323, 0x5b3a, - 0xb6d4, 0x538a, 0x7637, 0xfe97, 0xfd05, 0x3cc0, 0x453a, 0xfb7e}, - {0x6983, 0x4f75, 0x4ad1, 0x48ad, 0xb2d9, 0x521d, 0x3dbc, 0x9cc0, - 0x4b60, 0x0ac6, 0xd3be, 0x0fb6, 0xd305, 0x3895, 0x2da5, 0xfdf8}, - {0xcec1, 0x33ac, 0xa801, 0x8194, 0xe36c, 0x65ef, 0x103b, 0xca54, - 0xfa9b, 0xb41d, 0x9b52, 0xb6f7, 0xa611, 0x84aa, 0x3493, 0xbf54}}, - /* example needing 590 divsteps; delta=-3/2..5/2 */ - {{0xb5f2, 0x42d0, 0x35e8, 0x8ca0, 0x4b62, 0x6e1d, 0xbdf3, 0x890e, - 0x8c82, 0x23d8, 0xc79a, 0xc8e8, 0x789e, 0x353d, 0x9766, 0xea9d}, - {0x6fa1, 0xacba, 0x4b7a, 0x5de1, 0x95d0, 0xc845, 0xebbf, 0x6f5a, - 0x30cf, 0x52db, 0x69b7, 0xe278, 0x4b15, 0x8411, 0x2ab2, 0xf3e7}, - {0xf12c, 0x9d6d, 0x95fa, 0x1878, 0x9f13, 0x4fb5, 0x3c8b, 0xa451, - 0x7182, 0xc4b6, 0x7e2a, 0x7bb7, 0x6e0e, 0x5b68, 0xde55, 0x9927}}, - /* example needing 590 divsteps; delta=-3/2..5/2 */ - {{0x229c, 0x4ef8, 0x1e93, 0xe5dc, 0xcde5, 0x6d62, 0x263b, 0xad11, - 0xced0, 0x88ff, 0xae8e, 0x3183, 0x11d2, 0xa50b, 0x350d, 0xeb40}, - {0x3157, 0xe2ea, 0x8a02, 0x0aa3, 0x5ae1, 0xb26c, 0xea27, 0x6805, - 0x87e2, 0x9461, 0x37c1, 0x2f8d, 0x85d2, 0x77a8, 0xf805, 0xeec9}, - {0x6f4e, 0x2748, 0xf7e5, 0xd8d3, 0xabe2, 0x7270, 0xc4e0, 0xedc7, - 0xf196, 0x78ca, 0x9139, 0xd8af, 0x72c6, 0xaf2f, 0x85d2, 0x6cd3}}, - /* example needing 590 divsteps; delta=-5/2..7/2 */ - {{0xdce8, 0xf1fe, 0x6708, 0x021e, 0xf1ca, 0xd609, 0x5443, 0x85ce, - 0x7a05, 0x8f9c, 0x90c3, 0x52e7, 0x8e1d, 0x97b8, 0xc0bf, 0xf2a1}, - {0xbd3d, 0xed11, 0x1625, 0xb4c5, 0x844c, 0xa413, 0x2569, 0xb9ba, - 0xcd35, 0xff84, 0xcd6e, 0x7f0b, 0x7d5d, 0x10df, 0x3efe, 0xfbe5}, - {0xa9dd, 0xafef, 0xb1b7, 0x4c8d, 0x50e4, 0xafbf, 0x2d5a, 0xb27c, - 0x0653, 0x66b6, 0x5d36, 0x4694, 0x7e35, 0xc47c, 0x857f, 0x32c5}}, - /* example needing 590 divsteps; delta=-3/2..5/2 */ - {{0x7902, 0xc9f8, 0x926b, 0xaaeb, 0x90f8, 0x1c89, 0xcce3, 0x96b7, - 0x28b2, 0x87a2, 0x136d, 0x695a, 0xa8df, 0x9061, 0x9e31, 0xee82}, - {0xd3a9, 0x3c02, 0x818c, 0x6b81, 0x34b3, 0xebbb, 0xe2c8, 0x7712, - 0xbfd6, 0x8248, 0xa6f4, 0xba6f, 0x03bb, 0xfb54, 0x7575, 0xfe89}, - {0x8246, 0x0d63, 0x478e, 0xf946, 0xf393, 0x0451, 0x08c2, 0x5919, - 0x5fd6, 0x4c61, 0xbeb7, 0x9a15, 0x30e1, 0x55fc, 0x6a01, 0x3724}}, - /* example reaching delta=-127/2..129/2; 571 divsteps */ - {{0x3eff, 0x926a, 0x77f5, 0x1fff, 0x1a5b, 0xf3ef, 0xf64b, 0x8681, - 0xf800, 0xf9bc, 0x761d, 0xe268, 0x62b0, 0xa032, 0xba9c, 0xbe56}, - {0xb8f9, 0x00e7, 0x47b7, 0xdffc, 0xfd9d, 0x5abb, 0xa19b, 0x1868, - 0x31fd, 0x3b29, 0x3674, 0x5449, 0xf54d, 0x1d19, 0x6ac7, 0xff6f}, - {0xf1d7, 0x3551, 0x5682, 0x9adf, 0xe8aa, 0x19a5, 0x8340, 0x71db, - 0xb7ab, 0x4cfd, 0xf661, 0x632c, 0xc27e, 0xd3c6, 0xdf42, 0xd306}}, - /* example reaching delta=-127/2..129/2; 571 divsteps */ - {{0x0000, 0x0000, 0x0000, 0x0000, 0x3aff, 0x2ed7, 0xf2e0, 0xabc7, - 0x8aee, 0x166e, 0x7ed0, 0x9ac7, 0x714a, 0xb9c5, 0x4d58, 0xad6c}, - {0x9cf9, 0x47e2, 0xa421, 0xb277, 0xffc2, 0x2747, 0x6486, 0x94c1, - 0x1d99, 0xd49b, 0x1096, 0x991a, 0xe986, 0xae02, 0xe89b, 0xea36}, - {0x1fb4, 0x98d8, 0x19b7, 0x80e9, 0xcdac, 0xaa5a, 0xf1e6, 0x0074, - 0xe393, 0xed8b, 0x8d5c, 0xe17d, 0x81b3, 0xc16d, 0x54d3, 0x9be3}}, - /* example reaching delta=-127/2..129/2; 571 divsteps */ - {{0xd047, 0x7e36, 0x3157, 0x7ab6, 0xb4d9, 0x8dae, 0x7534, 0x4f5d, - 0x489e, 0xa8ab, 0x8a3d, 0xd52c, 0x62af, 0xa032, 0xba9c, 0xbe56}, - {0xb1f1, 0x737f, 0x5964, 0x5afb, 0x3712, 0x8ef9, 0x19f7, 0x9669, - 0x664d, 0x03ad, 0xc352, 0xf7a5, 0xf545, 0x1d19, 0x6ac7, 0xff6f}, - {0xa834, 0x5256, 0x27bc, 0x33bd, 0xba11, 0x5a7b, 0x791e, 0xe6c0, - 0x9ac4, 0x9370, 0x1130, 0x28b4, 0x2b2e, 0x231b, 0x082a, 0x796e}}, - /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ - {{0x6ab1, 0x6ea0, 0x1a99, 0xe0c2, 0xdd45, 0x645d, 0x8dbc, 0x466a, - 0xfa64, 0x4289, 0xd3f7, 0xfc8f, 0x2894, 0xe3c5, 0xa008, 0xcc14}, - {0xc75f, 0xc083, 0x4cc2, 0x64f2, 0x2aff, 0x4c12, 0x8461, 0xc4ae, - 0xbbfa, 0xb336, 0xe4b2, 0x3ac5, 0x2c22, 0xf56c, 0x5381, 0xe943}, - {0xcd80, 0x760d, 0x4395, 0xb3a6, 0xd497, 0xf583, 0x82bd, 0x1daa, - 0xbe92, 0x2613, 0xfdfb, 0x869b, 0x0425, 0xa333, 0x7056, 0xc9c5}}, - /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ - {{0x71d4, 0x64df, 0xec4f, 0x74d8, 0x7e0c, 0x40d3, 0x7073, 0x4cc8, - 0x2a2a, 0xb1ff, 0x8518, 0x6513, 0xb0ea, 0x640a, 0x62d9, 0xd5f4}, - {0xdc75, 0xd937, 0x3b13, 0x1d36, 0xdf83, 0xd034, 0x1c1c, 0x4332, - 0x4cc3, 0xeeec, 0x7d94, 0x6771, 0x3384, 0x74b0, 0x947d, 0xf2c4}, - {0x0a82, 0x37a4, 0x12d5, 0xec97, 0x972c, 0xe6bf, 0xc348, 0xa0a9, - 0xc50c, 0xdc7c, 0xae30, 0x19d1, 0x0fca, 0x35e1, 0xd6f6, 0x81ee}}, - /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ - {{0xa6b1, 0xabc5, 0x5bbc, 0x7f65, 0xdd32, 0xaa73, 0xf5a3, 0x1982, - 0xced4, 0xe949, 0x0fd6, 0x2bc4, 0x2bd7, 0xe3c5, 0xa008, 0xcc14}, - {0x4b5f, 0x8f96, 0xa375, 0xfbcf, 0x1c7d, 0xf1ec, 0x03f5, 0xb35d, - 0xb999, 0xdb1f, 0xc9a1, 0xb4c7, 0x1dd5, 0xf56c, 0x5381, 0xe943}, - {0xaa3d, 0x38b9, 0xf17d, 0xeed9, 0x9988, 0x69ee, 0xeb88, 0x1495, - 0x203f, 0x18c8, 0x82b7, 0xdcb2, 0x34a7, 0x6b00, 0x6998, 0x589a}}, - /* example doing 453 (f,g/2) steps; 514 divsteps */ - {{0xa478, 0xe60d, 0x3244, 0x60e6, 0xada3, 0xfe50, 0xb6b1, 0x2eae, - 0xd0ef, 0xa7b1, 0xef63, 0x05c0, 0xe213, 0x443e, 0x4427, 0x2448}, - {0x258f, 0xf9ef, 0xe02b, 0x92dd, 0xd7f3, 0x252b, 0xa503, 0x9089, - 0xedff, 0x96c1, 0xfe3a, 0x3a39, 0x198a, 0x981d, 0x0627, 0xedb7}, - {0x595a, 0x45be, 0x8fb0, 0x2265, 0xc210, 0x02b8, 0xdce9, 0xe241, - 0xcab6, 0xbf0d, 0x0049, 0x8d9a, 0x2f51, 0xae54, 0x5785, 0xb411}}, - /* example doing 453 (f,g/2) steps; 514 divsteps */ - {{0x48f0, 0x7db3, 0xdafe, 0x1c92, 0x5912, 0xe11a, 0xab52, 0xede1, - 0x3182, 0x8980, 0x5d2b, 0x9b5b, 0x8718, 0xda27, 0x1683, 0x1de2}, - {0x168f, 0x6f36, 0xce7a, 0xf435, 0x19d4, 0xda5e, 0x2351, 0x9af5, - 0xb003, 0x0ef5, 0x3b4c, 0xecec, 0xa9f0, 0x78e1, 0xdfef, 0xe823}, - {0x5f55, 0xfdcc, 0xb233, 0x2914, 0x84f0, 0x97d1, 0x9cf4, 0x2159, - 0xbf56, 0xb79c, 0x17a3, 0x7cef, 0xd5de, 0x34f0, 0x5311, 0x4c54}}, - /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ - {{0x2789, 0x2e04, 0x6e0e, 0xb6cd, 0xe4de, 0x4dbf, 0x228d, 0x7877, - 0xc335, 0x806b, 0x38cd, 0x8049, 0xa73b, 0xcfa2, 0x82f7, 0x9e19}, - {0xc08d, 0xb99d, 0xb8f3, 0x663d, 0xbbb3, 0x1284, 0x1485, 0x1d49, - 0xc98f, 0x9e78, 0x1588, 0x11e3, 0xd91a, 0xa2c7, 0xfff1, 0xc7b9}, - {0x1e1f, 0x411d, 0x7c49, 0x0d03, 0xe789, 0x2f8e, 0x5d55, 0xa95e, - 0x826e, 0x8de5, 0x52a0, 0x1abc, 0x4cd7, 0xd13a, 0x4395, 0x63e1}}, - /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ - {{0xd5a1, 0xf786, 0x555c, 0xb14b, 0x44ae, 0x535f, 0x4a49, 0xffc3, - 0xf497, 0x70d1, 0x57c8, 0xa933, 0xc85a, 0x1910, 0x75bf, 0x960b}, - {0xfe53, 0x5058, 0x496d, 0xfdff, 0x6fb8, 0x4100, 0x92bd, 0xe0c4, - 0xda89, 0xe0a4, 0x841b, 0x43d4, 0xa388, 0x957f, 0x99ca, 0x9abf}, - {0xe530, 0x05bc, 0xfeec, 0xfc7e, 0xbcd3, 0x1239, 0x54cb, 0x7042, - 0xbccb, 0x139e, 0x9076, 0x0203, 0x6068, 0x90c7, 0x1ddf, 0x488d}}, - /* example doing 228 (g,(g-f)/2) steps; 538 divsteps */ - {{0x9488, 0xe54b, 0x0e43, 0x81d2, 0x06e7, 0x4b66, 0x36d0, 0x53d6, - 0x2b68, 0x22ec, 0x3fa9, 0xc1a7, 0x9ad2, 0xa596, 0xb3ac, 0xdf42}, - {0xe31f, 0x0b28, 0x5f3b, 0xc1ff, 0x344c, 0xbf5f, 0xd2ec, 0x2936, - 0x9995, 0xdeb2, 0xae6c, 0x2852, 0xa2c6, 0xb306, 0x8120, 0xe305}, - {0xa56e, 0xfb98, 0x1537, 0x4d85, 0x619e, 0x866c, 0x3cd4, 0x779a, - 0xdd66, 0xa80d, 0xdc2f, 0xcae4, 0xc74c, 0x5175, 0xa65d, 0x605e}}, - /* example doing 228 (g,(g-f)/2) steps; 537 divsteps */ - {{0x8cd5, 0x376d, 0xd01b, 0x7176, 0x19ef, 0xcf09, 0x8403, 0x5e52, - 0x83c1, 0x44de, 0xb91e, 0xb33d, 0xe15c, 0x51e7, 0xbad8, 0x6359}, - {0x3b75, 0xf812, 0x5f9e, 0xa04e, 0x92d3, 0x226e, 0x540e, 0x7c9a, - 0x31c6, 0x46d2, 0x0b7b, 0xdb4a, 0xe662, 0x4950, 0x0265, 0xf76f}, - {0x09ed, 0x692f, 0xe8f1, 0x3482, 0xab54, 0x36b4, 0x8442, 0x6ae9, - 0x4329, 0x6505, 0x183b, 0x1c1d, 0x482d, 0x7d63, 0xb44f, 0xcc09}}, - - /* Test cases with the group order as modulus. */ - - /* Test case with the group order as modulus, needing 635 divsteps. */ - {{0x95ed, 0x6c01, 0xd113, 0x5ff1, 0xd7d0, 0x29cc, 0x5817, 0x6120, - 0xca8e, 0xaad1, 0x25ae, 0x8e84, 0x9af6, 0x30bf, 0xf0ed, 0x1686}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x1631, 0xbf4a, 0x286a, 0x2716, 0x469f, 0x2ac8, 0x1312, 0xe9bc, - 0x04f4, 0x304b, 0x9931, 0x113b, 0xd932, 0xc8f4, 0x0d0d, 0x01a1}}, - /* example with group size as modulus needing 631 divsteps */ - {{0x85ed, 0xc284, 0x9608, 0x3c56, 0x19b6, 0xbb5b, 0x2850, 0xdab7, - 0xa7f5, 0xe9ab, 0x06a4, 0x5bbb, 0x1135, 0xa186, 0xc424, 0xc68b}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x8479, 0x450a, 0x8fa3, 0xde05, 0xb2f5, 0x7793, 0x7269, 0xbabb, - 0xc3b3, 0xd49b, 0x3377, 0x03c6, 0xe694, 0xc760, 0xd3cb, 0x2811}}, - /* example with group size as modulus needing 565 divsteps starting at delta=1/2 */ - {{0x8432, 0x5ceb, 0xa847, 0x6f1e, 0x51dd, 0x535a, 0x6ddc, 0x70ce, - 0x6e70, 0xc1f6, 0x18f2, 0x2a7e, 0xc8e7, 0x39f8, 0x7e96, 0xebbf}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x257e, 0x449f, 0x689f, 0x89aa, 0x3989, 0xb661, 0x376c, 0x1e32, - 0x654c, 0xee2e, 0xf4e2, 0x33c8, 0x3f2f, 0x9716, 0x6046, 0xcaa3}}, - /* Test case with the group size as modulus, needing 981 divsteps with - broken eta handling. */ - {{0xfeb9, 0xb877, 0xee41, 0x7fa3, 0x87da, 0x94c4, 0x9d04, 0xc5ae, - 0x5708, 0x0994, 0xfc79, 0x0916, 0xbf32, 0x3ad8, 0xe11c, 0x5ca2}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0f12, 0x075e, 0xce1c, 0x6f92, 0xc80f, 0xca92, 0x9a04, 0x6126, - 0x4b6c, 0x57d6, 0xca31, 0x97f3, 0x1f99, 0xf4fd, 0xda4d, 0x42ce}}, - /* Test case with the group size as modulus, input = 0. */ - {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - /* Test case with the group size as modulus, input = 1. */ - {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - /* Test case with the group size as modulus, input = 2. */ - {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x20a1, 0x681b, 0x2f46, 0xdfe9, 0x501d, 0x57a4, 0x6e73, 0x5d57, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, - /* Test case with the group size as modulus, input = group - 1. */ - {{0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, - 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, - - /* Test cases with the field size as modulus. */ - - /* Test case with the field size as modulus, needing 637 divsteps. */ - {{0x9ec3, 0x1919, 0xca84, 0x7c11, 0xf996, 0x06f3, 0x5408, 0x6688, - 0x1320, 0xdb8a, 0x632a, 0x0dcb, 0x8a84, 0x6bee, 0x9c95, 0xe34e}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x18e5, 0x19b6, 0xdf92, 0x1aaa, 0x09fb, 0x8a3f, 0x52b0, 0x8701, - 0xac0c, 0x2582, 0xda44, 0x9bcc, 0x6828, 0x1c53, 0xbd8f, 0xbd2c}}, - /* example with field size as modulus needing 637 divsteps */ - {{0xaec3, 0xa7cf, 0x2f2d, 0x0693, 0x5ad5, 0xa8ff, 0x7ec7, 0x30ff, - 0x0c8b, 0xc242, 0xcab2, 0x063a, 0xf86e, 0x6057, 0x9cbd, 0xf6d8}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0310, 0x579d, 0xcb38, 0x9030, 0x3ded, 0x9bb9, 0x1234, 0x63ce, - 0x0c63, 0x8e3d, 0xacfe, 0x3c20, 0xdc85, 0xf859, 0x919e, 0x1d45}}, - /* example with field size as modulus needing 564 divsteps starting at delta=1/2 */ - {{0x63ae, 0x8d10, 0x0071, 0xdb5c, 0xb454, 0x78d1, 0x744a, 0x5f8e, - 0xe4d8, 0x87b1, 0x8e62, 0x9590, 0xcede, 0xa070, 0x36b4, 0x7f6f}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0xfdc8, 0xe8d5, 0xbe15, 0x9f86, 0xa5fe, 0xf18e, 0xa7ff, 0xd291, - 0xf4c2, 0x9c87, 0xf150, 0x073e, 0x69b8, 0xf7c4, 0xee4b, 0xc7e6}}, - /* Test case with the field size as modulus, needing 935 divsteps with - broken eta handling. */ - {{0x1b37, 0xbdc3, 0x8bcd, 0x25e3, 0x1eae, 0x567d, 0x30b6, 0xf0d8, - 0x9277, 0x0cf8, 0x9c2e, 0xecd7, 0x631d, 0xe38f, 0xd4f8, 0x5c93}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x1622, 0xe05b, 0xe880, 0x7de9, 0x3e45, 0xb682, 0xee6c, 0x67ed, - 0xa179, 0x15db, 0x6b0d, 0xa656, 0x7ccb, 0x8ef7, 0xa2ff, 0xe279}}, - /* Test case with the field size as modulus, input = 0. */ - {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - /* Test case with the field size as modulus, input = 1. */ - {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - /* Test case with the field size as modulus, input = 2. */ - {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0xfe18, 0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, - /* Test case with the field size as modulus, input = field - 1. */ - {{0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - {0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, - - /* Selected from a large number of random inputs to reach small/large - * d/e values in various configurations. */ - {{0x3a08, 0x23e1, 0x4d8c, 0xe606, 0x3263, 0x67af, 0x9bf1, 0x9d70, - 0xf5fd, 0x12e4, 0x03c8, 0xb9ca, 0xe847, 0x8c5d, 0x6322, 0xbd30}, - {0x8359, 0x59dd, 0x1831, 0x7c1a, 0x1e83, 0xaee1, 0x770d, 0xcea8, - 0xfbb1, 0xeed6, 0x10b5, 0xe2c6, 0x36ea, 0xee17, 0xe32c, 0xffff}, - {0x1727, 0x0f36, 0x6f85, 0x5d0c, 0xca6c, 0x3072, 0x9628, 0x5842, - 0xcb44, 0x7c2b, 0xca4f, 0x62e5, 0x29b1, 0x6ffd, 0x9055, 0xc196}}, - {{0x905d, 0x41c8, 0xa2ff, 0x295b, 0x72bb, 0x4679, 0x6d01, 0x2c98, - 0xb3e0, 0xc537, 0xa310, 0xe07e, 0xe72f, 0x4999, 0x1148, 0xf65e}, - {0x5b41, 0x4239, 0x3c37, 0x5130, 0x30e3, 0xff35, 0xc51f, 0x1a43, - 0xdb23, 0x13cf, 0x9f49, 0xf70c, 0x5e70, 0xd411, 0x3005, 0xf8c6}, - {0xc30e, 0x68f0, 0x201a, 0xe10c, 0x864a, 0x6243, 0xe946, 0x43ae, - 0xf3f1, 0x52dc, 0x1f7f, 0x50d4, 0x2797, 0x064c, 0x5ca4, 0x90e3}}, - {{0xf1b5, 0xc6e5, 0xd2c4, 0xff95, 0x27c5, 0x0c92, 0x5d19, 0x7ae5, - 0x4fbe, 0x5438, 0x99e1, 0x880d, 0xd892, 0xa05c, 0x6ffd, 0x7eac}, - {0x2153, 0xcc9d, 0xfc6c, 0x8358, 0x49a1, 0x01e2, 0xcef0, 0x4969, - 0xd69a, 0x8cef, 0xf5b2, 0xfd95, 0xdcc2, 0x71f4, 0x6ae2, 0xceeb}, - {0x9b2e, 0xcdc6, 0x0a5c, 0x7317, 0x9084, 0xe228, 0x56cf, 0xd512, - 0x628a, 0xce21, 0x3473, 0x4e13, 0x8823, 0x1ed0, 0x34d0, 0xbfa3}}, - {{0x5bae, 0x53e5, 0x5f4d, 0x21ca, 0xb875, 0x8ecf, 0x9aa6, 0xbe3c, - 0x9f96, 0x7b82, 0x375d, 0x4d3e, 0x491c, 0xb1eb, 0x04c9, 0xb6c8}, - {0xfcfd, 0x10b7, 0x73b2, 0xd23b, 0xa357, 0x67da, 0x0d9f, 0x8702, - 0xa037, 0xff8e, 0x0e8b, 0x1801, 0x2c5c, 0x4e6e, 0x4558, 0xfff2}, - {0xc50f, 0x5654, 0x6713, 0x5ef5, 0xa7ce, 0xa647, 0xc832, 0x69ce, - 0x1d5c, 0x4310, 0x0746, 0x5a01, 0x96ea, 0xde4b, 0xa88b, 0x5543}}, - {{0xdc7f, 0x5e8c, 0x89d1, 0xb077, 0xd521, 0xcf90, 0x32fa, 0x5737, - 0x839e, 0x1464, 0x007c, 0x09c6, 0x9371, 0xe8ea, 0xc1cb, 0x75c4}, - {0xe3a3, 0x107f, 0xa82a, 0xa375, 0x4578, 0x60f4, 0x75c9, 0x5ee4, - 0x3fd7, 0x2736, 0x2871, 0xd3d2, 0x5f1d, 0x1abb, 0xa764, 0xffff}, - {0x45c6, 0x1f2e, 0xb14c, 0x84d7, 0x7bb7, 0x5a04, 0x0504, 0x3f33, - 0x5cc1, 0xb07a, 0x6a6c, 0x786f, 0x647f, 0xe1d7, 0x78a2, 0x4cf4}}, - {{0xc006, 0x356f, 0x8cd2, 0x967b, 0xb49e, 0x2d4e, 0x14bf, 0x4bcb, - 0xddab, 0xd3f9, 0xa068, 0x2c1c, 0xd242, 0xa56d, 0xf2c7, 0x5f97}, - {0x465b, 0xb745, 0x0e0d, 0x69a9, 0x987d, 0xcb37, 0xf637, 0xb311, - 0xc4d6, 0x2ddb, 0xf68f, 0x2af9, 0x959d, 0x3f53, 0x98f2, 0xf640}, - {0xc0f2, 0x6bfb, 0xf5c3, 0x91c1, 0x6b05, 0x0825, 0x5ca0, 0x7df7, - 0x9d55, 0x6d9e, 0xfe94, 0x2ad9, 0xd9f0, 0xe68b, 0xa72b, 0xd1b2}}, - {{0x2279, 0x61ba, 0x5bc6, 0x136b, 0xf544, 0x717c, 0xafda, 0x02bd, - 0x79af, 0x1fad, 0xea09, 0x81bb, 0x932b, 0x32c9, 0xdf1d, 0xe576}, - {0x8215, 0x7817, 0xca82, 0x43b0, 0x9b06, 0xea65, 0x1291, 0x0621, - 0x0089, 0x46fe, 0xc5a6, 0xddd7, 0x8065, 0xc6a0, 0x214b, 0xfc64}, - {0x04bf, 0x6f2a, 0x86b2, 0x841a, 0x4a95, 0xc632, 0x97b7, 0x5821, - 0x2b18, 0x1bb0, 0x3e97, 0x935e, 0xcc7d, 0x066b, 0xd513, 0xc251}}, - {{0x76e8, 0x5bc2, 0x3eaa, 0x04fc, 0x9974, 0x92c1, 0x7c15, 0xfa89, - 0x1151, 0x36ee, 0x48b2, 0x049c, 0x5f16, 0xcee4, 0x925b, 0xe98e}, - {0x913f, 0x0a2d, 0xa185, 0x9fea, 0xda5a, 0x4025, 0x40d7, 0x7cfa, - 0x88ca, 0xbbe8, 0xb265, 0xb7e4, 0x6cb1, 0xed64, 0xc6f9, 0xffb5}, - {0x6ab1, 0x1a86, 0x5009, 0x152b, 0x1cc4, 0xe2c8, 0x960b, 0x19d0, - 0x3554, 0xc562, 0xd013, 0xcf91, 0x10e1, 0x7933, 0xe195, 0xcf49}}, - {{0x9cb5, 0xd2d7, 0xc6ed, 0xa818, 0xb495, 0x06ee, 0x0f4a, 0x06e3, - 0x4c5a, 0x80ce, 0xd49a, 0x4cd7, 0x7487, 0x92af, 0xe516, 0x676c}, - {0xd6e9, 0x6b85, 0x619a, 0xb52c, 0x20a0, 0x2f79, 0x3545, 0x1edd, - 0x5a6f, 0x8082, 0x9b80, 0xf8f8, 0xc78a, 0xd0a3, 0xadf4, 0xffff}, - {0x01c2, 0x2118, 0xef5e, 0xa877, 0x046a, 0xd2c2, 0x2ad5, 0x951c, - 0x8900, 0xa5c9, 0x8d0f, 0x6b61, 0x55d3, 0xd572, 0x48de, 0x9219}}, - {{0x5114, 0x0644, 0x23dd, 0x01d3, 0xc101, 0xa659, 0xea17, 0x640f, - 0xf767, 0x2644, 0x9cec, 0xd8ba, 0xd6da, 0x9156, 0x8aeb, 0x875a}, - {0xc1bf, 0xdae9, 0xe96b, 0xce77, 0xf7a1, 0x3e99, 0x5c2e, 0x973b, - 0xd048, 0x5bd0, 0x4e8a, 0xcb85, 0xce39, 0x37f5, 0x815d, 0xffff}, - {0x48cc, 0x35b6, 0x26d4, 0x2ea6, 0x50d6, 0xa2f9, 0x64b6, 0x03bf, - 0xd00c, 0xe057, 0x3343, 0xfb79, 0x3ce5, 0xf717, 0xc5af, 0xe185}}, - {{0x13ff, 0x6c76, 0x2077, 0x16e0, 0xd5ca, 0xf2ad, 0x8dba, 0x8f49, - 0x7887, 0x16f9, 0xb646, 0xfc87, 0xfa31, 0x5096, 0xf08c, 0x3fbe}, - {0x8139, 0x6fd7, 0xf6df, 0xa7bf, 0x6699, 0x5361, 0x6f65, 0x13c8, - 0xf4d1, 0xe28f, 0xc545, 0x0a8c, 0x5274, 0xb0a6, 0xffff, 0xffff}, - {0x22ca, 0x0cd6, 0xc1b5, 0xb064, 0x44a7, 0x297b, 0x495f, 0x34ac, - 0xfa95, 0xec62, 0xf08d, 0x621c, 0x66a6, 0xba94, 0x84c6, 0x8ee0}}, - {{0xaa30, 0x312e, 0x439c, 0x4e88, 0x2e2f, 0x32dc, 0xb880, 0xa28e, - 0xf795, 0xc910, 0xb406, 0x8dd7, 0xb187, 0xa5a5, 0x38f1, 0xe49e}, - {0xfb19, 0xf64a, 0xba6a, 0x8ec2, 0x7255, 0xce89, 0x2cf9, 0x9cba, - 0xe1fe, 0x50da, 0x1705, 0xac52, 0xe3d4, 0x4269, 0x0648, 0xfd77}, - {0xb4c8, 0x6e8a, 0x2b5f, 0x4c2d, 0x5a67, 0xa7bb, 0x7d6d, 0x5569, - 0xa0ea, 0x244a, 0xc0f2, 0xf73d, 0x58cf, 0xac7f, 0xd32b, 0x3018}}, - {{0xc953, 0x1ae1, 0xae46, 0x8709, 0x19c2, 0xa986, 0x9abe, 0x1611, - 0x0395, 0xd5ab, 0xf0f6, 0xb5b0, 0x5b2b, 0x0317, 0x80ba, 0x376d}, - {0xfe77, 0xbc03, 0xac2f, 0x9d00, 0xa175, 0x293d, 0x3b56, 0x0e3a, - 0x0a9c, 0xf40c, 0x690e, 0x1508, 0x95d4, 0xddc4, 0xe805, 0xffff}, - {0xb1ce, 0x0929, 0xa5fe, 0x4b50, 0x9d5d, 0x8187, 0x2557, 0x4376, - 0x11ba, 0xdcef, 0xc1f3, 0xd531, 0x1824, 0x93f6, 0xd81f, 0x8f83}}, - {{0xb8d2, 0xb900, 0x4a0c, 0x7188, 0xa5bf, 0x1b0b, 0x2ae5, 0xa35b, - 0x98e0, 0x610c, 0x86db, 0x2487, 0xa267, 0x002c, 0xebb6, 0xc5f4}, - {0x9cdd, 0x1c1b, 0x2f06, 0x43d1, 0xce47, 0xc334, 0x6e60, 0xc016, - 0x989e, 0x0ab2, 0x0cac, 0x1196, 0xe2d9, 0x2e04, 0xc62b, 0xffff}, - {0xdc36, 0x1f05, 0x6aa9, 0x7a20, 0x944f, 0x2fd3, 0xa553, 0xdb4f, - 0xbd5c, 0x3a75, 0x25d4, 0xe20e, 0xa387, 0x1410, 0xdbb1, 0x1b60}}, - {{0x76b3, 0x2207, 0x4930, 0x5dd7, 0x65a0, 0xd55c, 0xb443, 0x53b7, - 0x5c22, 0x818a, 0xb2e7, 0x9de8, 0x9985, 0xed45, 0x33b1, 0x53e8}, - {0x7913, 0x44e1, 0xf15b, 0x5edd, 0x34f3, 0x4eba, 0x0758, 0x7104, - 0x32d9, 0x28f3, 0x4401, 0x85c5, 0xb695, 0xb899, 0xc0f2, 0xffff}, - {0x7f43, 0xd202, 0x24c9, 0x69f3, 0x74dc, 0x1a69, 0xeaee, 0x5405, - 0x1755, 0x4bb8, 0x04e3, 0x2fd2, 0xada8, 0x39eb, 0x5b4d, 0x96ca}}, - {{0x807b, 0x7112, 0xc088, 0xdafd, 0x02fa, 0x9d95, 0x5e42, 0xc033, - 0xde0a, 0xeecf, 0x8e90, 0x8da1, 0xb17e, 0x9a5b, 0x4c6d, 0x1914}, - {0x4871, 0xd1cb, 0x47d7, 0x327f, 0x09ec, 0x97bb, 0x2fae, 0xd346, - 0x6b78, 0x3707, 0xfeb2, 0xa6ab, 0x13df, 0x76b0, 0x8fb9, 0xffb3}, - {0x179e, 0xb63b, 0x4784, 0x231e, 0x9f42, 0x7f1a, 0xa3fb, 0xdd8c, - 0xd1eb, 0xb4c9, 0x8ca7, 0x018c, 0xf691, 0x576c, 0xa7d6, 0xce27}}, - {{0x5f45, 0x7c64, 0x083d, 0xedd5, 0x08a0, 0x0c64, 0x6c6f, 0xec3c, - 0xe2fb, 0x352c, 0x9303, 0x75e4, 0xb4e0, 0x8b09, 0xaca4, 0x7025}, - {0x1025, 0xb482, 0xfed5, 0xa678, 0x8966, 0x9359, 0x5329, 0x98bb, - 0x85b2, 0x73ba, 0x9982, 0x6fdc, 0xf190, 0xbe8c, 0xdc5c, 0xfd93}, - {0x83a2, 0x87a4, 0xa680, 0x52a1, 0x1ba1, 0x8848, 0x5db7, 0x9744, - 0x409c, 0x0745, 0x0e1e, 0x1cfc, 0x00cd, 0xf573, 0x2071, 0xccaa}}, - {{0xf61f, 0x63d4, 0x536c, 0x9eb9, 0x5ddd, 0xbb11, 0x9014, 0xe904, - 0xfe01, 0x6b45, 0x1858, 0xcb5b, 0x4c38, 0x43e1, 0x381d, 0x7f94}, - {0xf61f, 0x63d4, 0xd810, 0x7ca3, 0x8a04, 0x4b83, 0x11fc, 0xdf94, - 0x4169, 0xbd05, 0x608e, 0x7151, 0x4fbf, 0xb31a, 0x38a7, 0xa29b}, - {0xe621, 0xdfa5, 0x3d06, 0x1d03, 0x81e6, 0x00da, 0x53a6, 0x965e, - 0x93e5, 0x2164, 0x5b61, 0x59b8, 0xa629, 0x8d73, 0x699a, 0x6111}}, - {{0x4cc3, 0xd29e, 0xf4a3, 0x3428, 0x2048, 0xeec9, 0x5f50, 0x99a4, - 0x6de9, 0x05f2, 0x5aa9, 0x5fd2, 0x98b4, 0x1adc, 0x225f, 0x777f}, - {0xe649, 0x37da, 0x5ba6, 0x5765, 0x3f4a, 0x8a1c, 0x2e79, 0xf550, - 0x1a54, 0xcd1e, 0x7218, 0x3c3c, 0x6311, 0xfe28, 0x95fb, 0xed97}, - {0xe9b6, 0x0c47, 0x3f0e, 0x849b, 0x11f8, 0xe599, 0x5e4d, 0xd618, - 0xa06d, 0x33a0, 0x9a3e, 0x44db, 0xded8, 0x10f0, 0x94d2, 0x81fb}}, - {{0x2e59, 0x7025, 0xd413, 0x455a, 0x1ce3, 0xbd45, 0x7263, 0x27f7, - 0x23e3, 0x518e, 0xbe06, 0xc8c4, 0xe332, 0x4276, 0x68b4, 0xb166}, - {0x596f, 0x0cf6, 0xc8ec, 0x787b, 0x04c1, 0x473c, 0xd2b8, 0x8d54, - 0x9cdf, 0x77f2, 0xd3f3, 0x6735, 0x0638, 0xf80e, 0x9467, 0xc6aa}, - {0xc7e7, 0x1822, 0xb62a, 0xec0d, 0x89cd, 0x7846, 0xbfa2, 0x35d5, - 0xfa38, 0x870f, 0x494b, 0x1697, 0x8b17, 0xf904, 0x10b6, 0x9822}}, - {{0x6d5b, 0x1d4f, 0x0aaf, 0x807b, 0x35fb, 0x7ee8, 0x00c6, 0x059a, - 0xddf0, 0x1fb1, 0xc38a, 0xd78e, 0x2aa4, 0x79e7, 0xad28, 0xc3f1}, - {0xe3bb, 0x174e, 0xe0a8, 0x74b6, 0xbd5b, 0x35f6, 0x6d23, 0x6328, - 0xc11f, 0x83e1, 0xf928, 0xa918, 0x838e, 0xbf43, 0xe243, 0xfffb}, - {0x9cf2, 0x6b8b, 0x3476, 0x9d06, 0xdcf2, 0xdb8a, 0x89cd, 0x4857, - 0x75c2, 0xabb8, 0x490b, 0xc9bd, 0x890e, 0xe36e, 0xd552, 0xfffa}}, - {{0x2f09, 0x9d62, 0xa9fc, 0xf090, 0xd6d1, 0x9d1d, 0x1828, 0xe413, - 0xc92b, 0x3d5a, 0x1373, 0x368c, 0xbaf2, 0x2158, 0x71eb, 0x08a3}, - {0x2f09, 0x1d62, 0x4630, 0x0de1, 0x06dc, 0xf7f1, 0xc161, 0x1e92, - 0x7495, 0x97e4, 0x94b6, 0xa39e, 0x4f1b, 0x18f8, 0x7bd4, 0x0c4c}, - {0xeb3d, 0x723d, 0x0907, 0x525b, 0x463a, 0x49a8, 0xc6b8, 0xce7f, - 0x740c, 0x0d7d, 0xa83b, 0x457f, 0xae8e, 0xc6af, 0xd331, 0x0475}}, - {{0x6abd, 0xc7af, 0x3e4e, 0x95fd, 0x8fc4, 0xee25, 0x1f9c, 0x0afe, - 0x291d, 0xcde0, 0x48f4, 0xb2e8, 0xf7af, 0x8f8d, 0x0bd6, 0x078d}, - {0x4037, 0xbf0e, 0x2081, 0xf363, 0x13b2, 0x381e, 0xfb6e, 0x818e, - 0x27e4, 0x5662, 0x18b0, 0x0cd2, 0x81f5, 0x9415, 0x0d6c, 0xf9fb}, - {0xd205, 0x0981, 0x0498, 0x1f08, 0xdb93, 0x1732, 0x0579, 0x1424, - 0xad95, 0x642f, 0x050c, 0x1d6d, 0xfc95, 0xfc4a, 0xd41b, 0x3521}}, - {{0xf23a, 0x4633, 0xaef4, 0x1a92, 0x3c8b, 0x1f09, 0x30f3, 0x4c56, - 0x2a2f, 0x4f62, 0xf5e4, 0x8329, 0x63cc, 0xb593, 0xec6a, 0xc428}, - {0x93a7, 0xfcf6, 0x606d, 0xd4b2, 0x2aad, 0x28b4, 0xc65b, 0x8998, - 0x4e08, 0xd178, 0x0900, 0xc82b, 0x7470, 0xa342, 0x7c0f, 0xffff}, - {0x315f, 0xf304, 0xeb7b, 0xe5c3, 0x1451, 0x6311, 0x8f37, 0x93a8, - 0x4a38, 0xa6c6, 0xe393, 0x1087, 0x6301, 0xd673, 0x4ec4, 0xffff}}, - {{0x892e, 0xeed0, 0x1165, 0xcbc1, 0x5545, 0xa280, 0x7243, 0x10c9, - 0x9536, 0x36af, 0xb3fc, 0x2d7c, 0xe8a5, 0x09d6, 0xe1d4, 0xe85d}, - {0xae09, 0xc28a, 0xd777, 0xbd80, 0x23d6, 0xf980, 0xeb7c, 0x4e0e, - 0xf7dc, 0x6475, 0xf10a, 0x2d33, 0x5dfd, 0x797a, 0x7f1c, 0xf71a}, - {0x4064, 0x8717, 0xd091, 0x80b0, 0x4527, 0x8442, 0xac8b, 0x9614, - 0xc633, 0x35f5, 0x7714, 0x2e83, 0x4aaa, 0xd2e4, 0x1acd, 0x0562}}, - {{0xdb64, 0x0937, 0x308b, 0x53b0, 0x00e8, 0xc77f, 0x2f30, 0x37f7, - 0x79ce, 0xeb7f, 0xde81, 0x9286, 0xafda, 0x0e62, 0xae00, 0x0067}, - {0x2cc7, 0xd362, 0xb161, 0x0557, 0x4ff2, 0xb9c8, 0x06fe, 0x5f2b, - 0xde33, 0x0190, 0x28c6, 0xb886, 0xee2b, 0x5a4e, 0x3289, 0x0185}, - {0x4215, 0x923e, 0xf34f, 0xb362, 0x88f8, 0xceec, 0xafdd, 0x7f42, - 0x0c57, 0x56b2, 0xa366, 0x6a08, 0x0826, 0xfb8f, 0x1b03, 0x0163}}, - {{0xa4ba, 0x8408, 0x810a, 0xdeba, 0x47a3, 0x853a, 0xeb64, 0x2f74, - 0x3039, 0x038c, 0x7fbb, 0x498e, 0xd1e9, 0x46fb, 0x5691, 0x32a4}, - {0xd749, 0xb49d, 0x20b7, 0x2af6, 0xd34a, 0xd2da, 0x0a10, 0xf781, - 0x58c9, 0x171f, 0x3cb6, 0x6337, 0x88cd, 0xcf1e, 0xb246, 0x7351}, - {0xf729, 0xcf0a, 0x96ea, 0x032c, 0x4a8f, 0x42fe, 0xbac8, 0xec65, - 0x1510, 0x0d75, 0x4c17, 0x8d29, 0xa03f, 0x8b7e, 0x2c49, 0x0000}}, - {{0x0fa4, 0x8e1c, 0x3788, 0xba3c, 0x8d52, 0xd89d, 0x12c8, 0xeced, - 0x9fe6, 0x9b88, 0xecf3, 0xe3c8, 0xac48, 0x76ed, 0xf23e, 0xda79}, - {0x1103, 0x227c, 0x5b00, 0x3fcf, 0xc5d0, 0x2d28, 0x8020, 0x4d1c, - 0xc6b9, 0x67f9, 0x6f39, 0x989a, 0xda53, 0x3847, 0xd416, 0xe0d0}, - {0xdd8e, 0xcf31, 0x3710, 0x7e44, 0xa511, 0x933c, 0x0cc3, 0x5145, - 0xf632, 0x5e1d, 0x038f, 0x5ce7, 0x7265, 0xda9d, 0xded6, 0x08f8}}, - {{0xe2c8, 0x91d5, 0xa5f5, 0x735f, 0x6b58, 0x56dc, 0xb39d, 0x5c4a, - 0x57d0, 0xa1c2, 0xd92f, 0x9ad4, 0xf7c4, 0x51dd, 0xaf5c, 0x0096}, - {0x1739, 0x7207, 0x7505, 0xbf35, 0x42de, 0x0a29, 0xa962, 0xdedf, - 0x53e8, 0x12bf, 0xcde7, 0xd8e2, 0x8d4d, 0x2c4b, 0xb1b1, 0x0628}, - {0x992d, 0xe3a7, 0xb422, 0xc198, 0x23ab, 0xa6ef, 0xb45d, 0x50da, - 0xa738, 0x014a, 0x2310, 0x85fb, 0x5fe8, 0x1b18, 0x1774, 0x03a7}}, - {{0x1f16, 0x2b09, 0x0236, 0xee90, 0xccf9, 0x9775, 0x8130, 0x4c91, - 0x9091, 0x310b, 0x6dc4, 0x86f6, 0xc2e8, 0xef60, 0xfc0e, 0xf3a4}, - {0x9f49, 0xac15, 0x02af, 0x110f, 0xc59d, 0x5677, 0xa1a9, 0x38d5, - 0x914f, 0xa909, 0x3a3a, 0x4a39, 0x3703, 0xea30, 0x73da, 0xffad}, - {0x15ed, 0xdd16, 0x83c7, 0x270a, 0x862f, 0xd8ad, 0xcaa1, 0x5f41, - 0x99a9, 0x3fc8, 0x7bb2, 0x360a, 0xb06d, 0xfadc, 0x1b36, 0xffa8}}, - {{0xc4e0, 0xb8fd, 0x5106, 0xe169, 0x754c, 0xa58c, 0xc413, 0x8224, - 0x5483, 0x63ec, 0xd477, 0x8473, 0x4778, 0x9281, 0x0000, 0x0000}, - {0x85e1, 0xff54, 0xb200, 0xe413, 0xf4f4, 0x4c0f, 0xfcec, 0xc183, - 0x60d3, 0x1b0c, 0x3834, 0x601c, 0x943c, 0xbe6e, 0x0002, 0x0000}, - {0xf4f8, 0xfd5e, 0x61ef, 0xece8, 0x9199, 0xe5c4, 0x05a6, 0xe6c3, - 0xc4ae, 0x8b28, 0x66b1, 0x8a95, 0x9ece, 0x8f4a, 0x0001, 0x0000}}, - {{0xeae9, 0xa1b4, 0xc6d8, 0x2411, 0x2b5a, 0x1dd0, 0x2dc9, 0xb57b, - 0x5ccd, 0x4957, 0xaf59, 0xa04b, 0x5f42, 0xab7c, 0x2826, 0x526f}, - {0xf407, 0x165a, 0xb724, 0x2f12, 0x2ea1, 0x470b, 0x4464, 0xbd35, - 0x606f, 0xd73e, 0x50d3, 0x8a7f, 0x8029, 0x7ffc, 0xbe31, 0x6cfb}, - {0x8171, 0x1f4c, 0xced2, 0x9c99, 0x6d7e, 0x5a0f, 0xfefb, 0x59e3, - 0xa0c8, 0xabd9, 0xc4c5, 0x57d3, 0xbfa3, 0x4f11, 0x96a2, 0x5a7d}}, - {{0xe068, 0x4cc0, 0x8bcd, 0xc903, 0x9e52, 0xb3e1, 0xd745, 0x0995, - 0xdd8f, 0xf14b, 0xd2ac, 0xd65a, 0xda1d, 0xa742, 0xbac5, 0x474c}, - {0x7481, 0xf2ad, 0x9757, 0x2d82, 0xb683, 0xb16b, 0x0002, 0x7b60, - 0x8f0c, 0x2594, 0x8f64, 0x3b7a, 0x3552, 0x8d9d, 0xb9d7, 0x67eb}, - {0xcaab, 0xb9a1, 0xf966, 0xe311, 0x5b34, 0x0fa0, 0x6abc, 0x8134, - 0xab3d, 0x90f6, 0x1984, 0x9232, 0xec17, 0x74e5, 0x2ceb, 0x434e}}, - {{0x0fb1, 0x7a55, 0x1a5c, 0x53eb, 0xd7b3, 0x7a01, 0xca32, 0x31f6, - 0x3b74, 0x679e, 0x1501, 0x6c57, 0xdb20, 0x8b7c, 0xd7d0, 0x8097}, - {0xb127, 0xb20c, 0xe3a2, 0x96f3, 0xe0d8, 0xd50c, 0x14b4, 0x0b40, - 0x6eeb, 0xa258, 0x99db, 0x3c8c, 0x0f51, 0x4198, 0x3887, 0xffd0}, - {0x0273, 0x9f8c, 0x9669, 0xbbba, 0x1c49, 0x767c, 0xc2af, 0x59f0, - 0x1366, 0xd397, 0x63ac, 0x6fe8, 0x1a9a, 0x1259, 0x01d0, 0x0016}}, - {{0x7876, 0x2a35, 0xa24a, 0x433e, 0x5501, 0x573c, 0xd76d, 0xcb82, - 0x1334, 0xb4a6, 0xf290, 0xc797, 0xeae9, 0x2b83, 0x1e2b, 0x8b14}, - {0x3885, 0x8aef, 0x9dea, 0x2b8c, 0xdd7c, 0xd7cd, 0xb0cc, 0x05ee, - 0x361b, 0x3800, 0xb0d4, 0x4c23, 0xbd3f, 0x5180, 0x9783, 0xff80}, - {0xab36, 0x3104, 0xdae8, 0x0704, 0x4a28, 0x6714, 0x824b, 0x0051, - 0x8134, 0x1f6a, 0x712d, 0x1f03, 0x03b2, 0xecac, 0x377d, 0xfef9}} - }; - - int i, j, ok; - - /* Test known inputs/outputs */ - for (i = 0; (size_t)i < sizeof(CASES) / sizeof(CASES[0]); ++i) { - uint16_t out[16]; - test_modinv32_uint16(out, CASES[i][0], CASES[i][1]); - for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); -#ifdef SECP256K1_WIDEMUL_INT128 - test_modinv64_uint16(out, CASES[i][0], CASES[i][1]); - for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); -#endif - } - - for (i = 0; i < 100 * COUNT; ++i) { - /* 256-bit numbers in 16-uint16_t's notation */ - static const uint16_t ZERO[16] = {0}; - uint16_t xd[16]; /* the number (in range [0,2^256)) to be inverted */ - uint16_t md[16]; /* the modulus (odd, in range [3,2^256)) */ - uint16_t id[16]; /* the inverse of xd mod md */ - - /* generate random xd and md, so that md is odd, md>1, xd>= 16; - } -} - -/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ -static void neg256(uint16_t* out, const uint16_t* a) { - int i; - uint32_t carry = 1; - for (i = 0; i < 16; ++i) { - carry += (uint16_t)~a[i]; - out[i] = carry; - carry >>= 16; - } -} - -/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ -static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { - uint16_t sign = sign_extend && (a[15] >> 15); - int i, j; - for (i = 15; i >= 0; --i) { - uint16_t v = 0; - for (j = 0; j < 16; ++j) { - int frompos = i*16 + j + n; - if (frompos >= 256) { - v |= sign << j; - } else { - v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j; - } - } - out[i] = v; - } -} - -/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ -static void load256u64(uint16_t* out, uint64_t v, int is_signed) { - int i; - uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; - for (i = 0; i < 4; ++i) { - out[i] = v >> (16 * i); - } - for (i = 4; i < 16; ++i) { - out[i] = sign; - } -} - -/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ -static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { - int i; - uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; - for (i = 0; i < 4; ++i) { - out[i] = lo >> (16 * i); - } - for (i = 4; i < 8; ++i) { - out[i] = hi >> (16 * (i - 4)); - } - for (i = 8; i < 16; ++i) { - out[i] = sign; - } -} - -/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ -static int int256is127(const uint16_t* v) { - int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); - int i; - for (i = 8; i < 16; ++i) { - if (v[i] != 0) all_0 = 0; - if (v[i] != 0xffff) all_1 = 0; - } - return all_0 || all_1; -} - -static void load256u128(uint16_t* out, const secp256k1_uint128* v) { - uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v); - load256two64(out, hi, lo, 0); -} - -static void load256i128(uint16_t* out, const secp256k1_int128* v) { - uint64_t lo; - int64_t hi; - secp256k1_int128 c = *v; - lo = secp256k1_i128_to_u64(&c); - secp256k1_i128_rshift(&c, 64); - hi = secp256k1_i128_to_i64(&c); - load256two64(out, hi, lo, 1); -} - -static void run_int128_test_case(void) { - unsigned char buf[32]; - uint64_t v[4]; - secp256k1_int128 swa, swz; - secp256k1_uint128 uwa, uwz; - uint64_t ub, uc; - int64_t sb, sc; - uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32]; - uint16_t rub[16], ruc[16], rsb[16], rsc[16]; - int i; - - /* Generate 32-byte random value. */ - testrand256_test(buf); - /* Convert into 4 64-bit integers. */ - for (i = 0; i < 4; ++i) { - uint64_t vi = 0; - int j; - for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j]; - v[i] = vi; - } - /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */ - secp256k1_u128_load(&uwa, v[1], v[0]); - secp256k1_i128_load(&swa, v[1], v[0]); - ub = v[2]; - sb = v[2]; - uc = v[3]; - sc = v[3]; - /* Load those also into 16-bit array representations. */ - load256u128(ruwa, &uwa); - load256i128(rswa, &swa); - load256u64(rub, ub, 0); - load256u64(rsb, sb, 1); - load256u64(ruc, uc, 0); - load256u64(rsc, sc, 1); - /* test secp256k1_u128_mul */ - mulmod256(ruwr, rub, ruc, NULL); - secp256k1_u128_mul(&uwz, ub, uc); - load256u128(ruwz, &uwz); - CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); - /* test secp256k1_u128_accum_mul */ - mulmod256(ruwr, rub, ruc, NULL); - add256(ruwr, ruwr, ruwa); - uwz = uwa; - secp256k1_u128_accum_mul(&uwz, ub, uc); - load256u128(ruwz, &uwz); - CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); - /* test secp256k1_u128_accum_u64 */ - add256(ruwr, rub, ruwa); - uwz = uwa; - secp256k1_u128_accum_u64(&uwz, ub); - load256u128(ruwz, &uwz); - CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); - /* test secp256k1_u128_rshift */ - rshift256(ruwr, ruwa, uc % 128, 0); - uwz = uwa; - secp256k1_u128_rshift(&uwz, uc % 128); - load256u128(ruwz, &uwz); - CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); - /* test secp256k1_u128_to_u64 */ - CHECK(secp256k1_u128_to_u64(&uwa) == v[0]); - /* test secp256k1_u128_hi_u64 */ - CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]); - /* test secp256k1_u128_from_u64 */ - secp256k1_u128_from_u64(&uwz, ub); - load256u128(ruwz, &uwz); - CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0); - /* test secp256k1_u128_check_bits */ - { - int uwa_bits = 0; - int j; - for (j = 0; j < 128; ++j) { - if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j; - } - for (j = 0; j < 128; ++j) { - CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j)); - } - } - /* test secp256k1_i128_mul */ - mulmod256(rswr, rsb, rsc, NULL); - secp256k1_i128_mul(&swz, sb, sc); - load256i128(rswz, &swz); - CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); - /* test secp256k1_i128_accum_mul */ - mulmod256(rswr, rsb, rsc, NULL); - add256(rswr, rswr, rswa); - if (int256is127(rswr)) { - swz = swa; - secp256k1_i128_accum_mul(&swz, sb, sc); - load256i128(rswz, &swz); - CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); - } - /* test secp256k1_i128_det */ - { - uint16_t rsd[16], rse[16], rst[32]; - int64_t sd = v[0], se = v[1]; - load256u64(rsd, sd, 1); - load256u64(rse, se, 1); - mulmod256(rst, rsc, rsd, NULL); - neg256(rst, rst); - mulmod256(rswr, rsb, rse, NULL); - add256(rswr, rswr, rst); - secp256k1_i128_det(&swz, sb, sc, sd, se); - load256i128(rswz, &swz); - CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); - } - /* test secp256k1_i128_rshift */ - rshift256(rswr, rswa, uc % 127, 1); - swz = swa; - secp256k1_i128_rshift(&swz, uc % 127); - load256i128(rswz, &swz); - CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); - /* test secp256k1_i128_to_u64 */ - CHECK(secp256k1_i128_to_u64(&swa) == v[0]); - /* test secp256k1_i128_from_i64 */ - secp256k1_i128_from_i64(&swz, sb); - load256i128(rswz, &swz); - CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0); - /* test secp256k1_i128_to_i64 */ - CHECK(secp256k1_i128_to_i64(&swz) == sb); - /* test secp256k1_i128_eq_var */ - { - int expect = (uc & 1); - swz = swa; - if (!expect) { - /* Make sure swz != swa */ - uint64_t v0c = v[0], v1c = v[1]; - if (ub & 64) { - v1c ^= (((uint64_t)1) << (ub & 63)); - } else { - v0c ^= (((uint64_t)1) << (ub & 63)); - } - secp256k1_i128_load(&swz, v1c, v0c); - } - CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); - } - /* test secp256k1_i128_check_pow2 (sign == 1) */ - { - int expect = (uc & 1); - int pos = ub % 127; - if (expect) { - /* If expect==1, set swz to exactly 2^pos. */ - uint64_t hi = 0; - uint64_t lo = 0; - if (pos >= 64) { - hi = (((uint64_t)1) << (pos & 63)); - } else { - lo = (((uint64_t)1) << (pos & 63)); - } - secp256k1_i128_load(&swz, hi, lo); - } else { - /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ - if (pos >= 64) { - if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; - } else { - if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; - } - swz = swa; - } - CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect); - } - /* test secp256k1_i128_check_pow2 (sign == -1) */ - { - int expect = (uc & 1); - int pos = ub % 127; - if (expect) { - /* If expect==1, set swz to exactly -2^pos. */ - uint64_t hi = ~(uint64_t)0; - uint64_t lo = ~(uint64_t)0; - if (pos >= 64) { - hi <<= (pos & 63); - lo = 0; - } else { - lo <<= (pos & 63); - } - secp256k1_i128_load(&swz, hi, lo); - } else { - /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ - if (pos >= 64) { - if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; - } else { - if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; - } - swz = swa; - } - CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect); - } -} - -static void run_int128_tests(void) { - { /* secp256k1_u128_accum_mul */ - secp256k1_uint128 res; - - /* Check secp256k1_u128_accum_mul overflow */ - secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX); - secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX); - CHECK(secp256k1_u128_to_u64(&res) == 2); - CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U); - } - { /* secp256k1_u128_accum_mul */ - secp256k1_int128 res; - - /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */ - secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX); - secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX); - CHECK(secp256k1_i128_to_u64(&res) == 2); - secp256k1_i128_accum_mul(&res, 4, 9223372036854775807); - secp256k1_i128_accum_mul(&res, 1, 1); - CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX); - secp256k1_i128_rshift(&res, 64); - CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX); - - /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */ - secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN); - CHECK(secp256k1_i128_to_u64(&res) == (uint64_t)INT64_MIN); - secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN); - CHECK(secp256k1_i128_to_u64(&res) == 0); - secp256k1_i128_accum_mul(&res, 2, INT64_MIN); - CHECK(secp256k1_i128_to_u64(&res) == 0); - secp256k1_i128_rshift(&res, 64); - CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN); - } - { - /* Randomized tests. */ - int i; - for (i = 0; i < 256 * COUNT; ++i) run_int128_test_case(); - } -} -#endif - -/***** SCALAR TESTS *****/ - -static void scalar_test(void) { - secp256k1_scalar s; - secp256k1_scalar s1; - secp256k1_scalar s2; - unsigned char c[32]; - - /* Set 's' to a random scalar, with value 'snum'. */ - testutil_random_scalar_order_test(&s); - - /* Set 's1' to a random scalar, with value 's1num'. */ - testutil_random_scalar_order_test(&s1); - - /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - testutil_random_scalar_order_test(&s2); - secp256k1_scalar_get_b32(c, &s2); - - { - int i; - /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar n; - secp256k1_scalar_set_int(&n, 0); - for (i = 0; i < 256; i += 4) { - secp256k1_scalar t; - int j; - secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_limb32(&s, 256 - 4 - i, 4)); - for (j = 0; j < 4; j++) { - secp256k1_scalar_add(&n, &n, &n); - } - secp256k1_scalar_add(&n, &n, &t); - } - CHECK(secp256k1_scalar_eq(&n, &s)); - } - - { - /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar n; - int i = 0; - secp256k1_scalar_set_int(&n, 0); - while (i < 256) { - secp256k1_scalar t; - int j; - int now = testrand_int(15) + 1; - if (now + i > 256) { - now = 256 - i; - } - secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); - for (j = 0; j < now; j++) { - secp256k1_scalar_add(&n, &n, &n); - } - secp256k1_scalar_add(&n, &n, &t); - i += now; - } - CHECK(secp256k1_scalar_eq(&n, &s)); - } - - { - /* Test commutativity of add. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_add(&r2, &s2, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - secp256k1_scalar r1, r2; - secp256k1_scalar b; - int i; - /* Test add_bit. */ - int bit = testrand_bits(8); - secp256k1_scalar_set_int(&b, 1); - CHECK(secp256k1_scalar_is_one(&b)); - for (i = 0; i < bit; i++) { - secp256k1_scalar_add(&b, &b, &b); - } - r1 = s1; - r2 = s1; - if (!secp256k1_scalar_add(&r1, &r1, &b)) { - /* No overflow happened. */ - secp256k1_scalar_cadd_bit(&r2, bit, 1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - /* cadd is a noop when flag is zero */ - secp256k1_scalar_cadd_bit(&r2, bit, 0); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - } - - { - /* Test commutativity of mul. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_mul(&r1, &s1, &s2); - secp256k1_scalar_mul(&r2, &s2, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test associativity of add. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_add(&r1, &r1, &s); - secp256k1_scalar_add(&r2, &s2, &s); - secp256k1_scalar_add(&r2, &s1, &r2); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test associativity of mul. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_mul(&r1, &s1, &s2); - secp256k1_scalar_mul(&r1, &r1, &s); - secp256k1_scalar_mul(&r2, &s2, &s); - secp256k1_scalar_mul(&r2, &s1, &r2); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test distributitivity of mul over add. */ - secp256k1_scalar r1, r2, t; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_mul(&r1, &r1, &s); - secp256k1_scalar_mul(&r2, &s1, &s); - secp256k1_scalar_mul(&t, &s2, &s); - secp256k1_scalar_add(&r2, &r2, &t); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test multiplicative identity. */ - secp256k1_scalar r1; - secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_one); - CHECK(secp256k1_scalar_eq(&r1, &s1)); - } - - { - /* Test additive identity. */ - secp256k1_scalar r1; - secp256k1_scalar_add(&r1, &s1, &secp256k1_scalar_zero); - CHECK(secp256k1_scalar_eq(&r1, &s1)); - } - - { - /* Test zero product property. */ - secp256k1_scalar r1; - secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_zero); - CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero)); - } - - { - /* Test halving. */ - secp256k1_scalar r; - secp256k1_scalar_add(&r, &s, &s); - secp256k1_scalar_half(&r, &r); - CHECK(secp256k1_scalar_eq(&r, &s)); - } -} - -static void run_scalar_set_b32_seckey_tests(void) { - unsigned char b32[32]; - secp256k1_scalar s1; - secp256k1_scalar s2; - - /* Usually set_b32 and set_b32_seckey give the same result */ - testutil_random_scalar_order_b32(b32); - secp256k1_scalar_set_b32(&s1, b32, NULL); - CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1); - CHECK(secp256k1_scalar_eq(&s1, &s2) == 1); - - memset(b32, 0, sizeof(b32)); - CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); - memset(b32, 0xFF, sizeof(b32)); - CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); -} - -static void run_scalar_tests(void) { - int i; - for (i = 0; i < 128 * COUNT; i++) { - scalar_test(); - } - for (i = 0; i < COUNT; i++) { - run_scalar_set_b32_seckey_tests(); - } - - { - /* Check that the scalar constants secp256k1_scalar_zero and - secp256k1_scalar_one contain the expected values. */ - secp256k1_scalar zero, one; - - CHECK(secp256k1_scalar_is_zero(&secp256k1_scalar_zero)); - secp256k1_scalar_set_int(&zero, 0); - CHECK(secp256k1_scalar_eq(&zero, &secp256k1_scalar_zero)); - - CHECK(secp256k1_scalar_is_one(&secp256k1_scalar_one)); - secp256k1_scalar_set_int(&one, 1); - CHECK(secp256k1_scalar_eq(&one, &secp256k1_scalar_one)); - } - - { - /* (-1)+1 should be zero. */ - secp256k1_scalar o; - secp256k1_scalar_negate(&o, &secp256k1_scalar_one); - secp256k1_scalar_add(&o, &o, &secp256k1_scalar_one); - CHECK(secp256k1_scalar_is_zero(&o)); - secp256k1_scalar_negate(&o, &o); - CHECK(secp256k1_scalar_is_zero(&o)); - } - - { - /* Test that halving and doubling roundtrips on some fixed values. */ - static const secp256k1_scalar HALF_TESTS[] = { - /* 0 */ - SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), - /* 1 */ - SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), - /* -1 */ - SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul), - /* -2 (largest odd value) */ - SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful), - /* Half the secp256k1 order */ - SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul), - /* Half the secp256k1 order + 1 */ - SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul), - /* 2^255 */ - SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0), - /* 2^255 - 1 */ - SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful), - }; - unsigned n; - for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) { - secp256k1_scalar s; - secp256k1_scalar_half(&s, &HALF_TESTS[n]); - secp256k1_scalar_add(&s, &s, &s); - CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); - secp256k1_scalar_add(&s, &s, &s); - secp256k1_scalar_half(&s, &s); - CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); - } - } - - { - /* Does check_overflow check catch all ones? */ - static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - CHECK(secp256k1_scalar_check_overflow(&overflowed)); - } - - { - /* Static test vectors. - * These were reduced from ~10^12 random vectors based on comparison-decision - * and edge-case coverage on 32-bit and 64-bit implementations. - * The responses were generated with Sage 5.9. - */ - secp256k1_scalar x; - secp256k1_scalar y; - secp256k1_scalar z; - secp256k1_scalar zz; - secp256k1_scalar r1; - secp256k1_scalar r2; - secp256k1_scalar zzv; - int overflow; - unsigned char chal[33][2][32] = { - {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, - {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, - {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, - 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, - 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, - 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, - 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, - {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, - {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, - 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, - 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, - {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, - {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, - {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, - 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, - {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, - {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, - {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, - {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, - {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, - 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, - {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, - 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, - {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, - 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, - {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, - 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, - {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, - 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, - 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, - {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, - 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, - 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} - }; - unsigned char res[33][2][32] = { - {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, - 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, - 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, - 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, - {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, - 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, - 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, - 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, - {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, - 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, - 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, - 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, - {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, - 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, - 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, - 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, - {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, - 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, - 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, - 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, - {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, - 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, - 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, - 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, - {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, - 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, - 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, - 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, - {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, - 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, - 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, - 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, - {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, - 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, - 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, - 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, - {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, - 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, - 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, - 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, - {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, - 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, - 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, - 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, - {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, - 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, - 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, - 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, - {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, - 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, - 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, - 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, - {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, - 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, - 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, - 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, - {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, - 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, - 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, - 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, - {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, - 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, - 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, - 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, - {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, - 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, - 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, - 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, - {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, - 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, - 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, - 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, - {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, - 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, - 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, - 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, - {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, - 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, - 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, - 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, - {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, - 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, - 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, - 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, - {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, - 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, - 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, - 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, - {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, - 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, - 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, - 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, - {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, - 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, - 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, - 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, - {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, - 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, - 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, - 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, - {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, - 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, - 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, - 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, - {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, - 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, - 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, - 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, - {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, - 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, - 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, - 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, - {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, - 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, - 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, - 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, - {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, - 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, - 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, - 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, - {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, - 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, - 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, - 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, - {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, - 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, - 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, - 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, - {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, - 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, - 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, - 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, - {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, - 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, - 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, - 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, - {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, - 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, - 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, - 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, - {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, - 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, - 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, - 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, - {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, - 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, - 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, - 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, - {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, - 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, - 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, - 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, - {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, - 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, - 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, - 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, - {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, - 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, - 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, - 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, - {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, - {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, - 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, - 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, - 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, - {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, - 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, - 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, - 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, - {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, - 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, - 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, - 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, - {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, - 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, - 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, - 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, - {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, - 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, - 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, - 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, - {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, - 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, - 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, - 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, - {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, - 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, - 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, - 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, - {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, - 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, - 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, - 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, - {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, - 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, - 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, - 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, - {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, - 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, - 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, - 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, - {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, - 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, - 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, - 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, - {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, - 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, - 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, - 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, - {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, - 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, - 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, - 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, - {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, - 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, - 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, - 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, - {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, - 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, - 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, - 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, - {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, - 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, - 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, - 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} - }; - for (i = 0; i < 33; i++) { - secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); - CHECK(!overflow); - secp256k1_scalar_mul(&z, &x, &y); - CHECK(secp256k1_scalar_eq(&r1, &z)); - if (!secp256k1_scalar_is_zero(&y)) { - secp256k1_scalar_inverse(&zz, &y); - secp256k1_scalar_inverse_var(&zzv, &y); - CHECK(secp256k1_scalar_eq(&zzv, &zz)); - secp256k1_scalar_mul(&z, &z, &zz); - CHECK(secp256k1_scalar_eq(&x, &z)); - secp256k1_scalar_mul(&zz, &zz, &y); - CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz)); - } - secp256k1_scalar_mul(&z, &x, &x); - CHECK(secp256k1_scalar_eq(&r2, &z)); - } - } -} - -/***** FIELD TESTS *****/ - -static void random_fe_non_square(secp256k1_fe *ns) { - secp256k1_fe r; - testutil_random_fe_non_zero(ns); - if (secp256k1_fe_sqrt(&r, ns)) { - secp256k1_fe_negate(ns, ns, 1); - } -} - -static int fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe an = *a; - secp256k1_fe bn = *b; - secp256k1_fe_normalize_weak(&an); - return secp256k1_fe_equal(&an, &bn); -} - -static void run_field_convert(void) { - static const unsigned char b32[32] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 - }; - static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( - 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, - 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL - ); - static const secp256k1_fe fe = SECP256K1_FE_CONST( - 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, - 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL - ); - secp256k1_fe fe2; - unsigned char b322[32]; - secp256k1_fe_storage fes2; - /* Check conversions to fe. */ - CHECK(secp256k1_fe_set_b32_limit(&fe2, b32)); - CHECK(secp256k1_fe_equal(&fe, &fe2)); - secp256k1_fe_from_storage(&fe2, &fes); - CHECK(secp256k1_fe_equal(&fe, &fe2)); - /* Check conversion from fe. */ - secp256k1_fe_get_b32(b322, &fe); - CHECK(secp256k1_memcmp_var(b322, b32, 32) == 0); - secp256k1_fe_to_storage(&fes2, &fe); - CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); -} - -static void run_field_be32_overflow(void) { - { - static const unsigned char zero_overflow[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, - }; - static const unsigned char zero[32] = { 0x00 }; - unsigned char out[32]; - secp256k1_fe fe; - CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0); - secp256k1_fe_set_b32_mod(&fe, zero_overflow); - CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1); - secp256k1_fe_normalize(&fe); - CHECK(secp256k1_fe_is_zero(&fe) == 1); - secp256k1_fe_get_b32(out, &fe); - CHECK(secp256k1_memcmp_var(out, zero, 32) == 0); - } - { - static const unsigned char one_overflow[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30, - }; - static const unsigned char one[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - unsigned char out[32]; - secp256k1_fe fe; - CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0); - secp256k1_fe_set_b32_mod(&fe, one_overflow); - secp256k1_fe_normalize(&fe); - CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0); - secp256k1_fe_get_b32(out, &fe); - CHECK(secp256k1_memcmp_var(out, one, 32) == 0); - } - { - static const unsigned char ff_overflow[32] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - }; - static const unsigned char ff[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0, - }; - unsigned char out[32]; - secp256k1_fe fe; - const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); - CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0); - secp256k1_fe_set_b32_mod(&fe, ff_overflow); - secp256k1_fe_normalize(&fe); - CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0); - secp256k1_fe_get_b32(out, &fe); - CHECK(secp256k1_memcmp_var(out, ff, 32) == 0); - } -} - -/* Returns true if two field elements have the same representation. */ -static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { - int ret = 1; - /* Compare the struct member that holds the limbs. */ - ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0); - return ret; -} - -static void run_field_half(void) { - secp256k1_fe t, u; - int m; - - /* Check magnitude 0 input */ - secp256k1_fe_get_bounds(&t, 0); - secp256k1_fe_half(&t); -#ifdef VERIFY - CHECK(t.magnitude == 1); - CHECK(t.normalized == 0); -#endif - CHECK(secp256k1_fe_normalizes_to_zero(&t)); - - /* Check non-zero magnitudes in the supported range */ - for (m = 1; m < 32; m++) { - /* Check max-value input */ - secp256k1_fe_get_bounds(&t, m); - - u = t; - secp256k1_fe_half(&u); -#ifdef VERIFY - CHECK(u.magnitude == (m >> 1) + 1); - CHECK(u.normalized == 0); -#endif - secp256k1_fe_normalize_weak(&u); - secp256k1_fe_add(&u, &u); - CHECK(fe_equal(&t, &u)); - - /* Check worst-case input: ensure the LSB is 1 so that P will be added, - * which will also cause all carries to be 1, since all limbs that can - * generate a carry are initially even and all limbs of P are odd in - * every existing field implementation. */ - secp256k1_fe_get_bounds(&t, m); - CHECK(t.n[0] > 0); - CHECK((t.n[0] & 1) == 0); - --t.n[0]; - - u = t; - secp256k1_fe_half(&u); -#ifdef VERIFY - CHECK(u.magnitude == (m >> 1) + 1); - CHECK(u.normalized == 0); -#endif - secp256k1_fe_normalize_weak(&u); - secp256k1_fe_add(&u, &u); - CHECK(fe_equal(&t, &u)); - } -} - -static void run_field_misc(void) { - secp256k1_fe x; - secp256k1_fe y; - secp256k1_fe z; - secp256k1_fe q; - int v; - secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i, j; - for (i = 0; i < 1000 * COUNT; i++) { - secp256k1_fe_storage xs, ys, zs; - if (i & 1) { - testutil_random_fe(&x); - } else { - testutil_random_fe_test(&x); - } - testutil_random_fe_non_zero(&y); - v = testrand_bits(15); - /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ - secp256k1_fe_set_int(&q, v); /* q = v */ - z = x; /* z = x */ - secp256k1_fe_add(&z, &q); /* z = x+v */ - q = x; /* q = x */ - secp256k1_fe_add_int(&q, v); /* q = x+v */ - CHECK(fe_equal(&q, &z)); - /* Test the fe equality and comparison operations. */ - CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); - CHECK(secp256k1_fe_equal(&x, &x)); - z = x; - secp256k1_fe_add(&z,&y); - /* Test fe conditional move; z is not normalized here. */ - q = x; - secp256k1_fe_cmov(&x, &z, 0); -#ifdef VERIFY - CHECK(!x.normalized); - CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude)); - CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude)); -#endif - x = q; - secp256k1_fe_cmov(&x, &x, 1); - CHECK(!fe_identical(&x, &z)); - CHECK(fe_identical(&x, &q)); - secp256k1_fe_cmov(&q, &z, 1); -#ifdef VERIFY - CHECK(!q.normalized); - CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude)); - CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude)); -#endif - CHECK(fe_identical(&q, &z)); - q = z; - secp256k1_fe_normalize_var(&x); - secp256k1_fe_normalize_var(&z); - CHECK(!secp256k1_fe_equal(&x, &z)); - secp256k1_fe_normalize_var(&q); - secp256k1_fe_cmov(&q, &z, (i&1)); -#ifdef VERIFY - CHECK(q.normalized && q.magnitude == 1); -#endif - for (j = 0; j < 6; j++) { - secp256k1_fe_negate_unchecked(&z, &z, j+1); - secp256k1_fe_normalize_var(&q); - secp256k1_fe_cmov(&q, &z, (j&1)); -#ifdef VERIFY - CHECK(!q.normalized && q.magnitude == z.magnitude); -#endif - } - secp256k1_fe_normalize_var(&z); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_to_storage(&xs, &x); - secp256k1_fe_to_storage(&ys, &y); - secp256k1_fe_to_storage(&zs, &z); - secp256k1_fe_storage_cmov(&zs, &xs, 0); - secp256k1_fe_storage_cmov(&zs, &zs, 1); - CHECK(secp256k1_memcmp_var(&xs, &zs, sizeof(xs)) != 0); - secp256k1_fe_storage_cmov(&ys, &xs, 1); - CHECK(secp256k1_memcmp_var(&xs, &ys, sizeof(xs)) == 0); - secp256k1_fe_from_storage(&x, &xs); - secp256k1_fe_from_storage(&y, &ys); - secp256k1_fe_from_storage(&z, &zs); - /* Test that mul_int, mul, and add agree. */ - secp256k1_fe_add(&y, &x); - secp256k1_fe_add(&y, &x); - z = x; - secp256k1_fe_mul_int(&z, 3); - CHECK(fe_equal(&y, &z)); - secp256k1_fe_add(&y, &x); - secp256k1_fe_add(&z, &x); - CHECK(fe_equal(&z, &y)); - z = x; - secp256k1_fe_mul_int(&z, 5); - secp256k1_fe_mul(&q, &x, &fe5); - CHECK(fe_equal(&z, &q)); - secp256k1_fe_negate(&x, &x, 1); - secp256k1_fe_add(&z, &x); - secp256k1_fe_add(&q, &x); - CHECK(fe_equal(&y, &z)); - CHECK(fe_equal(&q, &y)); - /* Check secp256k1_fe_half. */ - z = x; - secp256k1_fe_half(&z); - secp256k1_fe_add(&z, &z); - CHECK(fe_equal(&x, &z)); - secp256k1_fe_add(&z, &z); - secp256k1_fe_half(&z); - CHECK(fe_equal(&x, &z)); - } -} - -static void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) -{ - secp256k1_fe c, an, bn; - /* Variables in BE 32-byte format. */ - unsigned char a32[32], b32[32], c32[32]; - /* Variables in LE 16x uint16_t format. */ - uint16_t a16[16], b16[16], c16[16]; - /* Field modulus in LE 16x uint16_t format. */ - static const uint16_t m16[16] = { - 0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - }; - uint16_t t16[32]; - int i; - - /* Compute C = A * B in fe format. */ - c = *a; - if (use_sqr) { - secp256k1_fe_sqr(&c, &c); - } else { - secp256k1_fe_mul(&c, &c, b); - } - - /* Convert A, B, C into LE 16x uint16_t format. */ - an = *a; - bn = *b; - secp256k1_fe_normalize_var(&c); - secp256k1_fe_normalize_var(&an); - secp256k1_fe_normalize_var(&bn); - secp256k1_fe_get_b32(a32, &an); - secp256k1_fe_get_b32(b32, &bn); - secp256k1_fe_get_b32(c32, &c); - for (i = 0; i < 16; ++i) { - a16[i] = a32[31 - 2*i] + ((uint16_t)a32[30 - 2*i] << 8); - b16[i] = b32[31 - 2*i] + ((uint16_t)b32[30 - 2*i] << 8); - c16[i] = c32[31 - 2*i] + ((uint16_t)c32[30 - 2*i] << 8); - } - /* Compute T = A * B in LE 16x uint16_t format. */ - mulmod256(t16, a16, b16, m16); - /* Compare */ - CHECK(secp256k1_memcmp_var(t16, c16, 32) == 0); -} - -static void run_fe_mul(void) { - int i; - for (i = 0; i < 100 * COUNT; ++i) { - secp256k1_fe a, b, c, d; - testutil_random_fe(&a); - testutil_random_fe_magnitude(&a, 8); - testutil_random_fe(&b); - testutil_random_fe_magnitude(&b, 8); - testutil_random_fe_test(&c); - testutil_random_fe_magnitude(&c, 8); - testutil_random_fe_test(&d); - testutil_random_fe_magnitude(&d, 8); - test_fe_mul(&a, &a, 1); - test_fe_mul(&c, &c, 1); - test_fe_mul(&a, &b, 0); - test_fe_mul(&a, &c, 0); - test_fe_mul(&c, &b, 0); - test_fe_mul(&c, &d, 0); - } -} - -static void run_sqr(void) { - int i; - secp256k1_fe x, y, lhs, rhs, tmp; - - secp256k1_fe_set_int(&x, 1); - secp256k1_fe_negate(&x, &x, 1); - - for (i = 1; i <= 512; ++i) { - secp256k1_fe_mul_int(&x, 2); - secp256k1_fe_normalize(&x); - - /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */ - testutil_random_fe_test(&y); - - lhs = x; - secp256k1_fe_add(&lhs, &y); /* lhs = x+y */ - secp256k1_fe_negate(&tmp, &y, 1); /* tmp = -y */ - secp256k1_fe_add(&tmp, &x); /* tmp = x-y */ - secp256k1_fe_mul(&lhs, &lhs, &tmp); /* lhs = (x+y)*(x-y) */ - - secp256k1_fe_sqr(&rhs, &x); /* rhs = x^2 */ - secp256k1_fe_sqr(&tmp, &y); /* tmp = y^2 */ - secp256k1_fe_negate(&tmp, &tmp, 1); /* tmp = -y^2 */ - secp256k1_fe_add(&rhs, &tmp); /* rhs = x^2 - y^2 */ - - CHECK(fe_equal(&lhs, &rhs)); - } -} - -static void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { - secp256k1_fe r1, r2; - int v = secp256k1_fe_sqrt(&r1, a); - CHECK((v == 0) == (k == NULL)); - - if (k != NULL) { - /* Check that the returned root is +/- the given known answer */ - secp256k1_fe_negate(&r2, &r1, 1); - secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k); - secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2); - CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2)); - } -} - -static void run_sqrt(void) { - secp256k1_fe ns, x, s, t; - int i; - - /* Check sqrt(0) is 0 */ - secp256k1_fe_set_int(&x, 0); - secp256k1_fe_sqr(&s, &x); - test_sqrt(&s, &x); - - /* Check sqrt of small squares (and their negatives) */ - for (i = 1; i <= 100; i++) { - secp256k1_fe_set_int(&x, i); - secp256k1_fe_sqr(&s, &x); - test_sqrt(&s, &x); - secp256k1_fe_negate(&t, &s, 1); - test_sqrt(&t, NULL); - } - - /* Consistency checks for large random values */ - for (i = 0; i < 10; i++) { - int j; - random_fe_non_square(&ns); - for (j = 0; j < COUNT; j++) { - testutil_random_fe(&x); - secp256k1_fe_sqr(&s, &x); - CHECK(secp256k1_fe_is_square_var(&s)); - test_sqrt(&s, &x); - secp256k1_fe_negate(&t, &s, 1); - CHECK(!secp256k1_fe_is_square_var(&t)); - test_sqrt(&t, NULL); - secp256k1_fe_mul(&t, &s, &ns); - test_sqrt(&t, NULL); - } - } -} - -/***** FIELD/SCALAR INVERSE TESTS *****/ - -static const secp256k1_scalar scalar_minus_one = SECP256K1_SCALAR_CONST( - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, - 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364140 -); - -static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST( - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E -); - -/* These tests test the following identities: - * - * for x==0: 1/x == 0 - * for x!=0: x*(1/x) == 1 - * for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1) - */ - -static void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var) -{ - secp256k1_scalar l, r, t; - - (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, x); /* l = 1/x */ - if (out) *out = l; - if (secp256k1_scalar_is_zero(x)) { - CHECK(secp256k1_scalar_is_zero(&l)); - return; - } - secp256k1_scalar_mul(&t, x, &l); /* t = x*(1/x) */ - CHECK(secp256k1_scalar_is_one(&t)); /* x*(1/x) == 1 */ - secp256k1_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */ - if (secp256k1_scalar_is_zero(&r)) return; - (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&r, &r); /* r = 1/(x-1) */ - secp256k1_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */ - (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, &l); /* l = 1/(1/x-1) */ - secp256k1_scalar_add(&l, &l, &secp256k1_scalar_one); /* l = 1/(1/x-1)+1 */ - secp256k1_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */ - CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */ -} - -static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) -{ - secp256k1_fe l, r, t; - - (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, x) ; /* l = 1/x */ - if (out) *out = l; - t = *x; /* t = x */ - if (secp256k1_fe_normalizes_to_zero_var(&t)) { - CHECK(secp256k1_fe_normalizes_to_zero(&l)); - return; - } - secp256k1_fe_mul(&t, x, &l); /* t = x*(1/x) */ - secp256k1_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */ - CHECK(secp256k1_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */ - r = *x; /* r = x */ - secp256k1_fe_add(&r, &fe_minus_one); /* r = x-1 */ - if (secp256k1_fe_normalizes_to_zero_var(&r)) return; - (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */ - secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ - (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ - secp256k1_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */ - secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ - CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */ -} - -static void run_inverse_tests(void) -{ - /* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */ - static const secp256k1_fe fe_cases[][2] = { - /* 0 */ - {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), - SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, - /* 1 */ - {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), - SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, - /* -1 */ - {SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e), - SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e)}, - /* 2 */ - {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2), - SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18)}, - /* 2**128 */ - {SECP256K1_FE_CONST(0, 0, 0, 1, 0, 0, 0, 0), - SECP256K1_FE_CONST(0xbcb223fe, 0xdc24a059, 0xd838091d, 0xd2253530, 0xffffffff, 0xffffffff, 0xffffffff, 0x434dd931)}, - /* Input known to need 637 divsteps */ - {SECP256K1_FE_CONST(0xe34e9c95, 0x6bee8a84, 0x0dcb632a, 0xdb8a1320, 0x66885408, 0x06f3f996, 0x7c11ca84, 0x19199ec3), - SECP256K1_FE_CONST(0xbd2cbd8f, 0x1c536828, 0x9bccda44, 0x2582ac0c, 0x870152b0, 0x8a3f09fb, 0x1aaadf92, 0x19b618e5)}, - /* Input known to need 567 divsteps starting with delta=1/2. */ - {SECP256K1_FE_CONST(0xf6bc3ba3, 0x636451c4, 0x3e46357d, 0x2c21d619, 0x0988e234, 0x15985661, 0x6672982b, 0xa7549bfc), - SECP256K1_FE_CONST(0xb024fdc7, 0x5547451e, 0x426c585f, 0xbd481425, 0x73df6b75, 0xeef6d9d0, 0x389d87d4, 0xfbb440ba)}, - /* Input known to need 566 divsteps starting with delta=1/2. */ - {SECP256K1_FE_CONST(0xb595d81b, 0x2e3c1e2f, 0x482dbc65, 0xe4865af7, 0x9a0a50aa, 0x29f9e618, 0x6f87d7a5, 0x8d1063ae), - SECP256K1_FE_CONST(0xc983337c, 0x5d5c74e1, 0x49918330, 0x0b53afb5, 0xa0428a0b, 0xce6eef86, 0x059bd8ef, 0xe5b908de)}, - /* Set of 10 inputs accessing all 128 entries in the modinv32 divsteps_var table */ - {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0xe0ff1f80, 0x1f000000, 0x00000000, 0x00000000, 0xfeff0100, 0x00000000), - SECP256K1_FE_CONST(0x9faf9316, 0x77e5049d, 0x0b5e7a1b, 0xef70b893, 0x18c9e30c, 0x045e7fd7, 0x29eddf8c, 0xd62e9e3d)}, - {SECP256K1_FE_CONST(0x621a538d, 0x511b2780, 0x35688252, 0x53f889a4, 0x6317c3ac, 0x32ba0a46, 0x6277c0d1, 0xccd31192), - SECP256K1_FE_CONST(0x38513b0c, 0x5eba856f, 0xe29e882e, 0x9b394d8c, 0x34bda011, 0xeaa66943, 0x6a841a4c, 0x6ae8bcff)}, - {SECP256K1_FE_CONST(0x00000200, 0xf0ffff1f, 0x00000000, 0x0000e0ff, 0xffffffff, 0xfffcffff, 0xffffffff, 0xffff0100), - SECP256K1_FE_CONST(0x5da42a52, 0x3640de9e, 0x13e64343, 0x0c7591b7, 0x6c1e3519, 0xf048c5b6, 0x0484217c, 0xedbf8b2f)}, - {SECP256K1_FE_CONST(0xd1343ef9, 0x4b952621, 0x7c52a2ee, 0x4ea1281b, 0x4ab46410, 0x9f26998d, 0xa686a8ff, 0x9f2103e8), - SECP256K1_FE_CONST(0x84044385, 0x9a4619bf, 0x74e35b6d, 0xa47e0c46, 0x6b7fb47d, 0x9ffab128, 0xb0775aa3, 0xcb318bd1)}, - {SECP256K1_FE_CONST(0xb27235d2, 0xc56a52be, 0x210db37a, 0xd50d23a4, 0xbe621bdd, 0x5df22c6a, 0xe926ba62, 0xd2e4e440), - SECP256K1_FE_CONST(0x67a26e54, 0x483a9d3c, 0xa568469e, 0xd258ab3d, 0xb9ec9981, 0xdca9b1bd, 0x8d2775fe, 0x53ae429b)}, - {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00e0ffff, 0xffffff83, 0xffffffff, 0x3f00f00f, 0x000000e0, 0xffffffff), - SECP256K1_FE_CONST(0x310e10f8, 0x23bbfab0, 0xac94907d, 0x076c9a45, 0x8d357d7f, 0xc763bcee, 0x00d0e615, 0x5a6acef6)}, - {SECP256K1_FE_CONST(0xfeff0300, 0x001c0000, 0xf80700c0, 0x0ff0ffff, 0xffffffff, 0x0fffffff, 0xffff0100, 0x7f0000fe), - SECP256K1_FE_CONST(0x28e2fdb4, 0x0709168b, 0x86f598b0, 0x3453a370, 0x530cf21f, 0x32f978d5, 0x1d527a71, 0x59269b0c)}, - {SECP256K1_FE_CONST(0xc2591afa, 0x7bb98ef7, 0x090bb273, 0x85c14f87, 0xbb0b28e0, 0x54d3c453, 0x85c66753, 0xd5574d2f), - SECP256K1_FE_CONST(0xfdca70a2, 0x70ce627c, 0x95e66fae, 0x848a6dbb, 0x07ffb15c, 0x5f63a058, 0xba4140ed, 0x6113b503)}, - {SECP256K1_FE_CONST(0xf5475db3, 0xedc7b5a3, 0x411c047e, 0xeaeb452f, 0xc625828e, 0x1cf5ad27, 0x8eec1060, 0xc7d3e690), - SECP256K1_FE_CONST(0x5eb756c0, 0xf963f4b9, 0xdc6a215e, 0xec8cc2d8, 0x2e9dec01, 0xde5eb88d, 0x6aba7164, 0xaecb2c5a)}, - {SECP256K1_FE_CONST(0x00000000, 0x00f8ffff, 0xffffffff, 0x01000000, 0xe0ff1f00, 0x00000000, 0xffffff7f, 0x00000000), - SECP256K1_FE_CONST(0xe0d2e3d8, 0x49b6157d, 0xe54e88c2, 0x1a7f02ca, 0x7dd28167, 0xf1125d81, 0x7bfa444e, 0xbe110037)}, - /* Selection of randomly generated inputs that reach high/low d/e values in various configurations. */ - {SECP256K1_FE_CONST(0x13cc08a4, 0xd8c41f0f, 0x179c3e67, 0x54c46c67, 0xc4109221, 0x09ab3b13, 0xe24d9be1, 0xffffe950), - SECP256K1_FE_CONST(0xb80c8006, 0xd16abaa7, 0xcabd71e5, 0xcf6714f4, 0x966dd3d0, 0x64767a2d, 0xe92c4441, 0x51008cd1)}, - {SECP256K1_FE_CONST(0xaa6db990, 0x95efbca1, 0x3cc6ff71, 0x0602e24a, 0xf49ff938, 0x99fffc16, 0x46f40993, 0xc6e72057), - SECP256K1_FE_CONST(0xd5d3dd69, 0xb0c195e5, 0x285f1d49, 0xe639e48c, 0x9223f8a9, 0xca1d731d, 0x9ca482f9, 0xa5b93e06)}, - {SECP256K1_FE_CONST(0x1c680eac, 0xaeabffd8, 0x9bdc4aee, 0x1781e3de, 0xa3b08108, 0x0015f2e0, 0x94449e1b, 0x2f67a058), - SECP256K1_FE_CONST(0x7f083f8d, 0x31254f29, 0x6510f475, 0x245c373d, 0xc5622590, 0x4b323393, 0x32ed1719, 0xc127444b)}, - {SECP256K1_FE_CONST(0x147d44b3, 0x012d83f8, 0xc160d386, 0x1a44a870, 0x9ba6be96, 0x8b962707, 0x267cbc1a, 0xb65b2f0a), - SECP256K1_FE_CONST(0x555554ff, 0x170aef1e, 0x50a43002, 0xe51fbd36, 0xafadb458, 0x7a8aded1, 0x0ca6cd33, 0x6ed9087c)}, - {SECP256K1_FE_CONST(0x12423796, 0x22f0fe61, 0xf9ca017c, 0x5384d107, 0xa1fbf3b2, 0x3b018013, 0x916a3c37, 0x4000b98c), - SECP256K1_FE_CONST(0x20257700, 0x08668f94, 0x1177e306, 0x136c01f5, 0x8ed1fbd2, 0x95ec4589, 0xae38edb9, 0xfd19b6d7)}, - {SECP256K1_FE_CONST(0xdcf2d030, 0x9ab42cb4, 0x93ffa181, 0xdcd23619, 0x39699b52, 0x08909a20, 0xb5a17695, 0x3a9dcf21), - SECP256K1_FE_CONST(0x1f701dea, 0xe211fb1f, 0x4f37180d, 0x63a0f51c, 0x29fe1e40, 0xa40b6142, 0x2e7b12eb, 0x982b06b6)}, - {SECP256K1_FE_CONST(0x79a851f6, 0xa6314ed3, 0xb35a55e6, 0xca1c7d7f, 0xe32369ea, 0xf902432e, 0x375308c5, 0xdfd5b600), - SECP256K1_FE_CONST(0xcaae00c5, 0xe6b43851, 0x9dabb737, 0x38cba42c, 0xa02c8549, 0x7895dcbf, 0xbd183d71, 0xafe4476a)}, - {SECP256K1_FE_CONST(0xede78fdd, 0xcfc92bf1, 0x4fec6c6c, 0xdb8d37e2, 0xfb66bc7b, 0x28701870, 0x7fa27c9a, 0x307196ec), - SECP256K1_FE_CONST(0x68193a6c, 0x9a8b87a7, 0x2a760c64, 0x13e473f6, 0x23ae7bed, 0x1de05422, 0x88865427, 0xa3418265)}, - {SECP256K1_FE_CONST(0xa40b2079, 0xb8f88e89, 0xa7617997, 0x89baf5ae, 0x174df343, 0x75138eae, 0x2711595d, 0x3fc3e66c), - SECP256K1_FE_CONST(0x9f99c6a5, 0x6d685267, 0xd4b87c37, 0x9d9c4576, 0x358c692b, 0x6bbae0ed, 0x3389c93d, 0x7fdd2655)}, - {SECP256K1_FE_CONST(0x7c74c6b6, 0xe98d9151, 0x72645cf1, 0x7f06e321, 0xcefee074, 0x15b2113a, 0x10a9be07, 0x08a45696), - SECP256K1_FE_CONST(0x8c919a88, 0x898bc1e0, 0x77f26f97, 0x12e655b7, 0x9ba0ac40, 0xe15bb19e, 0x8364cc3b, 0xe227a8ee)}, - {SECP256K1_FE_CONST(0x109ba1ce, 0xdafa6d4a, 0xa1cec2b2, 0xeb1069f4, 0xb7a79e5b, 0xec6eb99b, 0xaec5f643, 0xee0e723e), - SECP256K1_FE_CONST(0x93d13eb8, 0x4bb0bcf9, 0xe64f5a71, 0xdbe9f359, 0x7191401c, 0x6f057a4a, 0xa407fe1b, 0x7ecb65cc)}, - {SECP256K1_FE_CONST(0x3db076cd, 0xec74a5c9, 0xf61dd138, 0x90e23e06, 0xeeedd2d0, 0x74cbc4e0, 0x3dbe1e91, 0xded36a78), - SECP256K1_FE_CONST(0x3f07f966, 0x8e2a1e09, 0x706c71df, 0x02b5e9d5, 0xcb92ddbf, 0xcdd53010, 0x16545564, 0xe660b107)}, - {SECP256K1_FE_CONST(0xe31c73ed, 0xb4c4b82c, 0x02ae35f7, 0x4cdec153, 0x98b522fd, 0xf7d2460c, 0x6bf7c0f8, 0x4cf67b0d), - SECP256K1_FE_CONST(0x4b8f1faf, 0x94e8b070, 0x19af0ff6, 0xa319cd31, 0xdf0a7ffb, 0xefaba629, 0x59c50666, 0x1fe5b843)}, - {SECP256K1_FE_CONST(0x4c8b0e6e, 0x83392ab6, 0xc0e3e9f1, 0xbbd85497, 0x16698897, 0xf552d50d, 0x79652ddb, 0x12f99870), - SECP256K1_FE_CONST(0x56d5101f, 0xd23b7949, 0x17dc38d6, 0xf24022ef, 0xcf18e70a, 0x5cc34424, 0x438544c3, 0x62da4bca)}, - {SECP256K1_FE_CONST(0xb0e040e2, 0x40cc35da, 0x7dd5c611, 0x7fccb178, 0x28888137, 0xbc930358, 0xea2cbc90, 0x775417dc), - SECP256K1_FE_CONST(0xca37f0d4, 0x016dd7c8, 0xab3ae576, 0x96e08d69, 0x68ed9155, 0xa9b44270, 0x900ae35d, 0x7c7800cd)}, - {SECP256K1_FE_CONST(0x8a32ea49, 0x7fbb0bae, 0x69724a9d, 0x8e2105b2, 0xbdf69178, 0x862577ef, 0x35055590, 0x667ddaef), - SECP256K1_FE_CONST(0xd02d7ead, 0xc5e190f0, 0x559c9d72, 0xdaef1ffc, 0x64f9f425, 0xf43645ea, 0x7341e08d, 0x11768e96)}, - {SECP256K1_FE_CONST(0xa3592d98, 0x9abe289d, 0x579ebea6, 0xbb0857a8, 0xe242ab73, 0x85f9a2ce, 0xb6998f0f, 0xbfffbfc6), - SECP256K1_FE_CONST(0x093c1533, 0x32032efa, 0x6aa46070, 0x0039599e, 0x589c35f4, 0xff525430, 0x7fe3777a, 0x44b43ddc)}, - {SECP256K1_FE_CONST(0x647178a3, 0x229e607b, 0xcc98521a, 0xcce3fdd9, 0x1e1bc9c9, 0x97fb7c6a, 0x61b961e0, 0x99b10709), - SECP256K1_FE_CONST(0x98217c13, 0xd51ddf78, 0x96310e77, 0xdaebd908, 0x602ca683, 0xcb46d07a, 0xa1fcf17e, 0xc8e2feb3)}, - {SECP256K1_FE_CONST(0x7334627c, 0x73f98968, 0x99464b4b, 0xf5964958, 0x1b95870d, 0xc658227e, 0x5e3235d8, 0xdcab5787), - SECP256K1_FE_CONST(0x000006fd, 0xc7e9dd94, 0x40ae367a, 0xe51d495c, 0x07603b9b, 0x2d088418, 0x6cc5c74c, 0x98514307)}, - {SECP256K1_FE_CONST(0x82e83876, 0x96c28938, 0xa50dd1c5, 0x605c3ad1, 0xc048637d, 0x7a50825f, 0x335ed01a, 0x00005760), - SECP256K1_FE_CONST(0xb0393f9f, 0x9f2aa55e, 0xf5607e2e, 0x5287d961, 0x60b3e704, 0xf3e16e80, 0xb4f9a3ea, 0xfec7f02d)}, - {SECP256K1_FE_CONST(0xc97b6cec, 0x3ee6b8dc, 0x98d24b58, 0x3c1970a1, 0xfe06297a, 0xae813529, 0xe76bb6bd, 0x771ae51d), - SECP256K1_FE_CONST(0x0507c702, 0xd407d097, 0x47ddeb06, 0xf6625419, 0x79f48f79, 0x7bf80d0b, 0xfc34b364, 0x253a5db1)}, - {SECP256K1_FE_CONST(0xd559af63, 0x77ea9bc4, 0x3cf1ad14, 0x5c7a4bbb, 0x10e7d18b, 0x7ce0dfac, 0x380bb19d, 0x0bb99bd3), - SECP256K1_FE_CONST(0x00196119, 0xb9b00d92, 0x34edfdb5, 0xbbdc42fc, 0xd2daa33a, 0x163356ca, 0xaa8754c8, 0xb0ec8b0b)}, - {SECP256K1_FE_CONST(0x8ddfa3dc, 0x52918da0, 0x640519dc, 0x0af8512a, 0xca2d33b2, 0xbde52514, 0xda9c0afc, 0xcb29fce4), - SECP256K1_FE_CONST(0xb3e4878d, 0x5cb69148, 0xcd54388b, 0xc23acce0, 0x62518ba8, 0xf09def92, 0x7b31e6aa, 0x6ba35b02)}, - {SECP256K1_FE_CONST(0xf8207492, 0xe3049f0a, 0x65285f2b, 0x0bfff996, 0x00ca112e, 0xc05da837, 0x546d41f9, 0x5194fb91), - SECP256K1_FE_CONST(0x7b7ee50b, 0xa8ed4bbd, 0xf6469930, 0x81419a5c, 0x071441c7, 0x290d046e, 0x3b82ea41, 0x611c5f95)}, - {SECP256K1_FE_CONST(0x050f7c80, 0x5bcd3c6b, 0x823cb724, 0x5ce74db7, 0xa4e39f5c, 0xbd8828d7, 0xfd4d3e07, 0x3ec2926a), - SECP256K1_FE_CONST(0x000d6730, 0xb0171314, 0x4764053d, 0xee157117, 0x48fd61da, 0xdea0b9db, 0x1d5e91c6, 0xbdc3f59e)}, - {SECP256K1_FE_CONST(0x3e3ea8eb, 0x05d760cf, 0x23009263, 0xb3cb3ac9, 0x088f6f0d, 0x3fc182a3, 0xbd57087c, 0xe67c62f9), - SECP256K1_FE_CONST(0xbe988716, 0xa29c1bf6, 0x4456aed6, 0xab1e4720, 0x49929305, 0x51043bf4, 0xebd833dd, 0xdd511e8b)}, - {SECP256K1_FE_CONST(0x6964d2a9, 0xa7fa6501, 0xa5959249, 0x142f4029, 0xea0c1b5f, 0x2f487ef6, 0x301ac80a, 0x768be5cd), - SECP256K1_FE_CONST(0x3918ffe4, 0x07492543, 0xed24d0b7, 0x3df95f8f, 0xaffd7cb4, 0x0de2191c, 0x9ec2f2ad, 0x2c0cb3c6)}, - {SECP256K1_FE_CONST(0x37c93520, 0xf6ddca57, 0x2b42fd5e, 0xb5c7e4de, 0x11b5b81c, 0xb95e91f3, 0x95c4d156, 0x39877ccb), - SECP256K1_FE_CONST(0x9a94b9b5, 0x57eb71ee, 0x4c975b8b, 0xac5262a8, 0x077b0595, 0xe12a6b1f, 0xd728edef, 0x1a6bf956)} - }; - /* Fixed test cases for scalar inverses: pairs of (x, 1/x) mod n. */ - static const secp256k1_scalar scalar_cases[][2] = { - /* 0 */ - {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), - SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, - /* 1 */ - {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), - SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, - /* -1 */ - {SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140), - SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140)}, - /* 2 */ - {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 2), - SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5d576e73, 0x57a4501d, 0xdfe92f46, 0x681b20a1)}, - /* 2**128 */ - {SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0), - SECP256K1_SCALAR_CONST(0x50a51ac8, 0x34b9ec24, 0x4b0dff66, 0x5588b13e, 0x9984d5b3, 0xcf80ef0f, 0xd6a23766, 0xa3ee9f22)}, - /* Input known to need 635 divsteps */ - {SECP256K1_SCALAR_CONST(0xcb9f1d35, 0xdd4416c2, 0xcd71bf3f, 0x6365da66, 0x3c9b3376, 0x8feb7ae9, 0x32a5ef60, 0x19199ec3), - SECP256K1_SCALAR_CONST(0x1d7c7bba, 0xf1893d53, 0xb834bd09, 0x36b411dc, 0x42c2e42f, 0xec72c428, 0x5e189791, 0x8e9bc708)}, - /* Input known to need 566 divsteps starting with delta=1/2. */ - {SECP256K1_SCALAR_CONST(0x7e3c993d, 0xa4272488, 0xbc015b49, 0x2db54174, 0xd382083a, 0xebe6db35, 0x80f82eff, 0xcd132c72), - SECP256K1_SCALAR_CONST(0x086f34a0, 0x3e631f76, 0x77418f28, 0xcc84ac95, 0x6304439d, 0x365db268, 0x312c6ded, 0xd0b934f8)}, - /* Input known to need 565 divsteps starting with delta=1/2. */ - {SECP256K1_SCALAR_CONST(0xbad7e587, 0x3f307859, 0x60d93147, 0x8a18491e, 0xb38a9fd5, 0x254350d3, 0x4b1f0e4b, 0x7dd6edc4), - SECP256K1_SCALAR_CONST(0x89f2df26, 0x39e2b041, 0xf19bd876, 0xd039c8ac, 0xc2223add, 0x29c4943e, 0x6632d908, 0x515f467b)}, - /* Selection of randomly generated inputs that reach low/high d/e values in various configurations. */ - {SECP256K1_SCALAR_CONST(0x1950d757, 0xb37a5809, 0x435059bb, 0x0bb8997e, 0x07e1e3c8, 0x5e5d7d2c, 0x6a0ed8e3, 0xdbde180e), - SECP256K1_SCALAR_CONST(0xbf72af9b, 0x750309e2, 0x8dda230b, 0xfe432b93, 0x7e25e475, 0x4388251e, 0x633d894b, 0x3bcb6f8c)}, - {SECP256K1_SCALAR_CONST(0x9bccf4e7, 0xc5a515e3, 0x50637aa9, 0xbb65a13f, 0x391749a1, 0x62de7d4e, 0xf6d7eabb, 0x3cd10ce0), - SECP256K1_SCALAR_CONST(0xaf2d5623, 0xb6385a33, 0xcd0365be, 0x5e92a70d, 0x7f09179c, 0x3baaf30f, 0x8f9cc83b, 0x20092f67)}, - {SECP256K1_SCALAR_CONST(0x73a57111, 0xb242952a, 0x5c5dee59, 0xf3be2ace, 0xa30a7659, 0xa46e5f47, 0xd21267b1, 0x39e642c9), - SECP256K1_SCALAR_CONST(0xa711df07, 0xcbcf13ef, 0xd61cc6be, 0xbcd058ce, 0xb02cf157, 0x272d4a18, 0x86d0feb3, 0xcd5fa004)}, - {SECP256K1_SCALAR_CONST(0x04884963, 0xce0580b1, 0xba547030, 0x3c691db3, 0x9cd2c84f, 0x24c7cebd, 0x97ebfdba, 0x3e785ec2), - SECP256K1_SCALAR_CONST(0xaaaaaf14, 0xd7c99ba7, 0x517ce2c1, 0x78a28b4c, 0x3769a851, 0xe5c5a03d, 0x4cc28f33, 0x0ec4dc5d)}, - {SECP256K1_SCALAR_CONST(0x1679ed49, 0x21f537b1, 0x815cb8ae, 0x9efc511c, 0x5b9fa037, 0x0b0f275e, 0x6c985281, 0x6c4a9905), - SECP256K1_SCALAR_CONST(0xb14ac3d5, 0x62b52999, 0xef34ead1, 0xffca4998, 0x0294341a, 0x1f8172aa, 0xea1624f9, 0x302eea62)}, - {SECP256K1_SCALAR_CONST(0x626b37c0, 0xf0057c35, 0xee982f83, 0x452a1fd3, 0xea826506, 0x48b08a9d, 0x1d2c4799, 0x4ad5f6ec), - SECP256K1_SCALAR_CONST(0xe38643b7, 0x567bfc2f, 0x5d2f1c15, 0xe327239c, 0x07112443, 0x69509283, 0xfd98e77a, 0xdb71c1e8)}, - {SECP256K1_SCALAR_CONST(0x1850a3a7, 0x759efc56, 0x54f287b2, 0x14d1234b, 0xe263bbc9, 0xcf4d8927, 0xd5f85f27, 0x965bd816), - SECP256K1_SCALAR_CONST(0x3b071831, 0xcac9619a, 0xcceb0596, 0xf614d63b, 0x95d0db2f, 0xc6a00901, 0x8eaa2621, 0xabfa0009)}, - {SECP256K1_SCALAR_CONST(0x94ae5d06, 0xa27dc400, 0x487d72be, 0xaa51ebed, 0xe475b5c0, 0xea675ffc, 0xf4df627a, 0xdca4222f), - SECP256K1_SCALAR_CONST(0x01b412ed, 0xd7830956, 0x1532537e, 0xe5e3dc99, 0x8fd3930a, 0x54f8d067, 0x32ef5760, 0x594438a5)}, - {SECP256K1_SCALAR_CONST(0x1f24278a, 0xb5bfe374, 0xa328dbbc, 0xebe35f48, 0x6620e009, 0xd58bb1b4, 0xb5a6bf84, 0x8815f63a), - SECP256K1_SCALAR_CONST(0xfe928416, 0xca5ba2d3, 0xfde513da, 0x903a60c7, 0x9e58ad8a, 0x8783bee4, 0x083a3843, 0xa608c914)}, - {SECP256K1_SCALAR_CONST(0xdc107d58, 0x274f6330, 0x67dba8bc, 0x26093111, 0x5201dfb8, 0x968ce3f5, 0xf34d1bd4, 0xf2146504), - SECP256K1_SCALAR_CONST(0x660cfa90, 0x13c3d93e, 0x7023b1e5, 0xedd09e71, 0x6d9c9d10, 0x7a3d2cdb, 0xdd08edc3, 0xaa78fcfb)}, - {SECP256K1_SCALAR_CONST(0x7cd1e905, 0xc6f02776, 0x2f551cc7, 0x5da61cff, 0x7da05389, 0x1119d5a4, 0x631c7442, 0x894fd4f7), - SECP256K1_SCALAR_CONST(0xff20862a, 0x9d3b1a37, 0x1628803b, 0x3004ccae, 0xaa23282a, 0xa89a1109, 0xd94ece5e, 0x181bdc46)}, - {SECP256K1_SCALAR_CONST(0x5b9dade8, 0x23d26c58, 0xcd12d818, 0x25b8ae97, 0x3dea04af, 0xf482c96b, 0xa062f254, 0x9e453640), - SECP256K1_SCALAR_CONST(0x50c38800, 0x15fa53f4, 0xbe1e5392, 0x5c9b120a, 0x262c22c7, 0x18fa0816, 0x5f2baab4, 0x8cb5db46)}, - {SECP256K1_SCALAR_CONST(0x11cdaeda, 0x969c464b, 0xef1f4ab0, 0x5b01d22e, 0x656fd098, 0x882bea84, 0x65cdbe7a, 0x0c19ff03), - SECP256K1_SCALAR_CONST(0x1968d0fa, 0xac46f103, 0xb55f1f72, 0xb3820bed, 0xec6b359a, 0x4b1ae0ad, 0x7e38e1fb, 0x295ccdfb)}, - {SECP256K1_SCALAR_CONST(0x2c351aa1, 0x26e91589, 0x194f8a1e, 0x06561f66, 0x0cb97b7f, 0x10914454, 0x134d1c03, 0x157266b4), - SECP256K1_SCALAR_CONST(0xbe49ada6, 0x92bd8711, 0x41b176c4, 0xa478ba95, 0x14883434, 0x9d1cd6f3, 0xcc4b847d, 0x22af80f5)}, - {SECP256K1_SCALAR_CONST(0x6ba07c6e, 0x13a60edb, 0x6247f5c3, 0x84b5fa56, 0x76fe3ec5, 0x80426395, 0xf65ec2ae, 0x623ba730), - SECP256K1_SCALAR_CONST(0x25ac23f7, 0x418cd747, 0x98376f9d, 0x4a11c7bf, 0x24c8ebfe, 0x4c8a8655, 0x345f4f52, 0x1c515595)}, - {SECP256K1_SCALAR_CONST(0x9397a712, 0x8abb6951, 0x2d4a3d54, 0x703b1c2a, 0x0661dca8, 0xd75c9b31, 0xaed4d24b, 0xd2ab2948), - SECP256K1_SCALAR_CONST(0xc52e8bef, 0xd55ce3eb, 0x1c897739, 0xeb9fb606, 0x36b9cd57, 0x18c51cc2, 0x6a87489e, 0xffd0dcf3)}, - {SECP256K1_SCALAR_CONST(0xe6a808cc, 0xeb437888, 0xe97798df, 0x4e224e44, 0x7e3b380a, 0x207c1653, 0x889f3212, 0xc6738b6f), - SECP256K1_SCALAR_CONST(0x31f9ae13, 0xd1e08b20, 0x757a2e5e, 0x5243a0eb, 0x8ae35f73, 0x19bb6122, 0xb910f26b, 0xda70aa55)}, - {SECP256K1_SCALAR_CONST(0xd0320548, 0xab0effe7, 0xa70779e0, 0x61a347a6, 0xb8c1e010, 0x9d5281f8, 0x2ee588a6, 0x80000000), - SECP256K1_SCALAR_CONST(0x1541897e, 0x78195c90, 0x7583dd9e, 0x728b6100, 0xbce8bc6d, 0x7a53b471, 0x5dcd9e45, 0x4425fcaf)}, - {SECP256K1_SCALAR_CONST(0x93d623f1, 0xd45b50b0, 0x796e9186, 0x9eac9407, 0xd30edc20, 0xef6304cf, 0x250494e7, 0xba503de9), - SECP256K1_SCALAR_CONST(0x7026d638, 0x1178b548, 0x92043952, 0x3c7fb47c, 0xcd3ea236, 0x31d82b01, 0x612fc387, 0x80b9b957)}, - {SECP256K1_SCALAR_CONST(0xf860ab39, 0x55f5d412, 0xa4d73bcc, 0x3b48bd90, 0xc248ffd3, 0x13ca10be, 0x8fba84cc, 0xdd28d6a3), - SECP256K1_SCALAR_CONST(0x5c32fc70, 0xe0b15d67, 0x76694700, 0xfe62be4d, 0xeacdb229, 0x7a4433d9, 0x52155cd0, 0x7649ab59)}, - {SECP256K1_SCALAR_CONST(0x4e41311c, 0x0800af58, 0x7a690a8e, 0xe175c9ba, 0x6981ab73, 0xac532ea8, 0x5c1f5e63, 0x6ac1f189), - SECP256K1_SCALAR_CONST(0xfffffff9, 0xd075982c, 0x7fbd3825, 0xc05038a2, 0x4533b91f, 0x94ec5f45, 0xb280b28f, 0x842324dc)}, - {SECP256K1_SCALAR_CONST(0x48e473bf, 0x3555eade, 0xad5d7089, 0x2424c4e4, 0x0a99397c, 0x2dc796d8, 0xb7a43a69, 0xd0364141), - SECP256K1_SCALAR_CONST(0x634976b2, 0xa0e47895, 0x1ec38593, 0x266d6fd0, 0x6f602644, 0x9bb762f1, 0x7180c704, 0xe23a4daa)}, - {SECP256K1_SCALAR_CONST(0xbe83878d, 0x3292fc54, 0x26e71c62, 0x556ccedc, 0x7cbb8810, 0x4032a720, 0x34ead589, 0xe4d6bd13), - SECP256K1_SCALAR_CONST(0x6cd150ad, 0x25e59d0f, 0x74cbae3d, 0x6377534a, 0x1e6562e8, 0xb71b9d18, 0xe1e5d712, 0x8480abb3)}, - {SECP256K1_SCALAR_CONST(0xcdddf2e5, 0xefc15f88, 0xc9ee06de, 0x8a846ca9, 0x28561581, 0x68daa5fb, 0xd1cf3451, 0xeb1782d0), - SECP256K1_SCALAR_CONST(0xffffffd9, 0xed8d2af4, 0x993c865a, 0x23e9681a, 0x3ca3a3dc, 0xe6d5a46e, 0xbd86bd87, 0x61b55c70)}, - {SECP256K1_SCALAR_CONST(0xb6a18f1f, 0x04872df9, 0x08165ec4, 0x319ca19c, 0x6c0359ab, 0x1f7118fb, 0xc2ef8082, 0xca8b7785), - SECP256K1_SCALAR_CONST(0xff55b19b, 0x0f1ac78c, 0x0f0c88c2, 0x2358d5ad, 0x5f455e4e, 0x3330b72f, 0x274dc153, 0xffbf272b)}, - {SECP256K1_SCALAR_CONST(0xea4898e5, 0x30eba3e8, 0xcf0e5c3d, 0x06ec6844, 0x01e26fb6, 0x75636225, 0xc5d08f4c, 0x1decafa0), - SECP256K1_SCALAR_CONST(0xe5a014a8, 0xe3c4ec1e, 0xea4f9b32, 0xcfc7b386, 0x00630806, 0x12c08d02, 0x6407ccc2, 0xb067d90e)}, - {SECP256K1_SCALAR_CONST(0x70e9aea9, 0x7e933af0, 0x8a23bfab, 0x23e4b772, 0xff951863, 0x5ffcf47d, 0x6bebc918, 0x2ca58265), - SECP256K1_SCALAR_CONST(0xf4e00006, 0x81bc6441, 0x4eb6ec02, 0xc194a859, 0x80ad7c48, 0xba4e9afb, 0x8b6bdbe0, 0x989d8f77)}, - {SECP256K1_SCALAR_CONST(0x3c56c774, 0x46efe6f0, 0xe93618b8, 0xf9b5a846, 0xd247df61, 0x83b1e215, 0x06dc8bcc, 0xeefc1bf5), - SECP256K1_SCALAR_CONST(0xfff8937a, 0x2cd9586b, 0x43c25e57, 0xd1cefa7a, 0x9fb91ed3, 0x95b6533d, 0x8ad0de5b, 0xafb93f00)}, - {SECP256K1_SCALAR_CONST(0xfb5c2772, 0x5cb30e83, 0xe38264df, 0xe4e3ebf3, 0x392aa92e, 0xa68756a1, 0x51279ac5, 0xb50711a8), - SECP256K1_SCALAR_CONST(0x000013af, 0x1105bfe7, 0xa6bbd7fb, 0x3d638f99, 0x3b266b02, 0x072fb8bc, 0x39251130, 0x2e0fd0ea)} - }; - int i, var, testrand; - unsigned char b32[32]; - secp256k1_fe x_fe; - secp256k1_scalar x_scalar; - memset(b32, 0, sizeof(b32)); - /* Test fixed test cases through test_inverse_{scalar,field}, both ways. */ - for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) { - for (var = 0; var <= 1; ++var) { - test_inverse_field(&x_fe, &fe_cases[i][0], var); - CHECK(fe_equal(&x_fe, &fe_cases[i][1])); - test_inverse_field(&x_fe, &fe_cases[i][1], var); - CHECK(fe_equal(&x_fe, &fe_cases[i][0])); - } - } - for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) { - for (var = 0; var <= 1; ++var) { - test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var); - CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][1])); - test_inverse_scalar(&x_scalar, &scalar_cases[i][1], var); - CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][0])); - } - } - /* Test inputs 0..999 and their respective negations. */ - for (i = 0; i < 1000; ++i) { - b32[31] = i & 0xff; - b32[30] = (i >> 8) & 0xff; - secp256k1_scalar_set_b32(&x_scalar, b32, NULL); - secp256k1_fe_set_b32_mod(&x_fe, b32); - for (var = 0; var <= 1; ++var) { - test_inverse_scalar(NULL, &x_scalar, var); - test_inverse_field(NULL, &x_fe, var); - } - secp256k1_scalar_negate(&x_scalar, &x_scalar); - secp256k1_fe_negate(&x_fe, &x_fe, 1); - for (var = 0; var <= 1; ++var) { - test_inverse_scalar(NULL, &x_scalar, var); - test_inverse_field(NULL, &x_fe, var); - } - } - /* test 128*count random inputs; half with testrand256_test, half with testrand256 */ - for (testrand = 0; testrand <= 1; ++testrand) { - for (i = 0; i < 64 * COUNT; ++i) { - (testrand ? testrand256_test : testrand256)(b32); - secp256k1_scalar_set_b32(&x_scalar, b32, NULL); - secp256k1_fe_set_b32_mod(&x_fe, b32); - for (var = 0; var <= 1; ++var) { - test_inverse_scalar(NULL, &x_scalar, var); - test_inverse_field(NULL, &x_fe, var); - } - } - } -} - -/***** HSORT TESTS *****/ - -static void test_heap_swap(void) { - unsigned char a[600]; - unsigned char e[sizeof(a)]; - memset(a, 21, 200); - memset(a + 200, 99, 200); - memset(a + 400, 42, 200); - memset(e, 42, 200); - memset(e + 200, 99, 200); - memset(e + 400, 21, 200); - secp256k1_heap_swap(a, 0, 2, 200); - CHECK(secp256k1_memcmp_var(a, e, sizeof(a)) == 0); -} - -static void test_hsort_is_sorted(unsigned char *elements, size_t n, size_t len) { - size_t i; - for (i = 1; i < n; i++) { - CHECK(secp256k1_memcmp_var(&elements[(i-1) * len], &elements[i * len], len) <= 0); - } -} - -struct test_hsort_cmp_data { - size_t counter; - size_t element_len; -}; - - -static int test_hsort_cmp(const void *ele1, const void *ele2, void *data) { - struct test_hsort_cmp_data *d = (struct test_hsort_cmp_data *) data; - d->counter += 1; - return secp256k1_memcmp_var((unsigned char *)ele1, (unsigned char *)ele2, d->element_len); -} - -#define NUM 65 -#define MAX_ELEMENT_LEN 65 -static void test_hsort(size_t element_len) { - unsigned char elements[NUM * MAX_ELEMENT_LEN] = { 0 }; - struct test_hsort_cmp_data data; - int i; - - VERIFY_CHECK(element_len <= MAX_ELEMENT_LEN); - data.counter = 0; - data.element_len = element_len; - - secp256k1_hsort(elements, 0, element_len, test_hsort_cmp, &data); - CHECK(data.counter == 0); - secp256k1_hsort(elements, 1, element_len, test_hsort_cmp, &data); - CHECK(data.counter == 0); - secp256k1_hsort(elements, NUM, element_len, test_hsort_cmp, &data); - CHECK(data.counter >= NUM - 1); - test_hsort_is_sorted(elements, NUM, element_len); - - /* Test hsort with array of random length n */ - for (i = 0; i < COUNT; i++) { - int n = testrand_int(NUM); - testrand_bytes_test(elements, n*element_len); - secp256k1_hsort(elements, n, element_len, test_hsort_cmp, &data); - test_hsort_is_sorted(elements, n, element_len); - } -} -#undef NUM -#undef MAX_ELEMENT_LEN - - -static void run_hsort_tests(void) { - test_heap_swap(); - test_hsort(1); - test_hsort(64); - test_hsort(65); -} - -/***** GROUP TESTS *****/ - -/* This compares jacobian points including their Z, not just their geometric meaning. */ -static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { - secp256k1_gej a2; - secp256k1_gej b2; - int ret = 1; - ret &= a->infinity == b->infinity; - if (ret && !a->infinity) { - a2 = *a; - b2 = *b; - secp256k1_fe_normalize(&a2.x); - secp256k1_fe_normalize(&a2.y); - secp256k1_fe_normalize(&a2.z); - secp256k1_fe_normalize(&b2.x); - secp256k1_fe_normalize(&b2.y); - secp256k1_fe_normalize(&b2.z); - ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; - ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; - ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; - } - return ret; -} - -static void test_ge(void) { - int i, i1; - int runs = 6; - /* 25 points are used: - * - infinity - * - for each of four random points p1 p2 p3 p4, we add the point, its - * negation, and then those two again but with randomized Z coordinate. - * - The same is then done for lambda*p1 and lambda^2*p1. - */ - secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); - secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); - secp256k1_fe zf, r; - secp256k1_fe zfi2, zfi3; - - secp256k1_gej_set_infinity(&gej[0]); - secp256k1_ge_set_infinity(&ge[0]); - for (i = 0; i < runs; i++) { - int j, k; - secp256k1_ge g; - testutil_random_ge_test(&g); - if (i >= runs - 2) { - secp256k1_ge_mul_lambda(&g, &ge[1]); - CHECK(!secp256k1_ge_eq_var(&g, &ge[1])); - } - if (i >= runs - 1) { - secp256k1_ge_mul_lambda(&g, &g); - } - ge[1 + 4 * i] = g; - ge[2 + 4 * i] = g; - secp256k1_ge_neg(&ge[3 + 4 * i], &g); - secp256k1_ge_neg(&ge[4 + 4 * i], &g); - secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); - testutil_random_ge_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); - secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); - testutil_random_ge_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); - for (j = 0; j < 4; j++) { - testutil_random_ge_x_magnitude(&ge[1 + j + 4 * i]); - testutil_random_ge_y_magnitude(&ge[1 + j + 4 * i]); - testutil_random_gej_x_magnitude(&gej[1 + j + 4 * i]); - testutil_random_gej_y_magnitude(&gej[1 + j + 4 * i]); - testutil_random_gej_z_magnitude(&gej[1 + j + 4 * i]); - } - - for (j = 0; j < 4; ++j) { - for (k = 0; k < 4; ++k) { - int expect_equal = (j >> 1) == (k >> 1); - CHECK(secp256k1_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); - CHECK(secp256k1_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal); - CHECK(secp256k1_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); - CHECK(secp256k1_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal); - } - } - } - - /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ - testutil_random_fe_non_zero_test(&zf); - testutil_random_fe_magnitude(&zf, 8); - secp256k1_fe_inv_var(&zfi3, &zf); - secp256k1_fe_sqr(&zfi2, &zfi3); - secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); - - /* Generate random r */ - testutil_random_fe_non_zero_test(&r); - - for (i1 = 0; i1 < 1 + 4 * runs; i1++) { - int i2; - for (i2 = 0; i2 < 1 + 4 * runs; i2++) { - /* Compute reference result using gej + gej (var). */ - secp256k1_gej refj, resj; - secp256k1_ge ref; - secp256k1_fe zr; - secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - /* Check Z ratio. */ - if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { - secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal(&zrz, &refj.z)); - } - secp256k1_ge_set_gej_var(&ref, &refj); - - /* Test gej + ge with Z ratio result (var). */ - secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { - secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal(&zrz, &resj.z)); - } - - /* Test gej + ge (var, with additional Z factor). */ - { - secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ - secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); - secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - testutil_random_ge_x_magnitude(&ge2_zfi); - testutil_random_ge_y_magnitude(&ge2_zfi); - secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - } - - /* Test gej + ge (const). */ - if (i2 != 0) { - /* secp256k1_gej_add_ge does not support its second argument being infinity. */ - secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - } - - /* Test doubling (var). */ - if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - secp256k1_fe zr2; - /* Normal doubling with Z ratio result. */ - secp256k1_gej_double_var(&resj, &gej[i1], &zr2); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - /* Check Z ratio. */ - secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); - CHECK(secp256k1_fe_equal(&zr2, &resj.z)); - /* Normal doubling. */ - secp256k1_gej_double_var(&resj, &gej[i2], NULL); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - /* Constant-time doubling. */ - secp256k1_gej_double(&resj, &gej[i2]); - CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); - } - - /* Test adding opposites. */ - if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { - CHECK(secp256k1_ge_is_infinity(&ref)); - } - - /* Test adding infinity. */ - if (i1 == 0) { - CHECK(secp256k1_ge_is_infinity(&ge[i1])); - CHECK(secp256k1_gej_is_infinity(&gej[i1])); - CHECK(secp256k1_gej_eq_ge_var(&gej[i2], &ref)); - } - if (i2 == 0) { - CHECK(secp256k1_ge_is_infinity(&ge[i2])); - CHECK(secp256k1_gej_is_infinity(&gej[i2])); - CHECK(secp256k1_gej_eq_ge_var(&gej[i1], &ref)); - } - } - } - - /* Test adding all points together in random order equals infinity. */ - { - secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); - for (i = 0; i < 4 * runs + 1; i++) { - gej_shuffled[i] = gej[i]; - } - for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + testrand_int(4 * runs + 1 - i); - if (swap != i) { - secp256k1_gej t = gej_shuffled[i]; - gej_shuffled[i] = gej_shuffled[swap]; - gej_shuffled[swap] = t; - } - } - for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); - } - CHECK(secp256k1_gej_is_infinity(&sum)); - free(gej_shuffled); - } - - /* Test batch gej -> ge conversion without known z ratios. */ - { - secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); - secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); - for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_fe s; - testutil_random_fe_non_zero(&s); - secp256k1_gej_rescale(&gej[i], &s); - CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); - } - free(ge_set_all); - } - - /* Test that all elements have X coordinates on the curve. */ - for (i = 1; i < 4 * runs + 1; i++) { - secp256k1_fe n; - CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x)); - /* And the same holds after random rescaling. */ - secp256k1_fe_mul(&n, &zf, &ge[i].x); - CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf)); - } - - /* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */ - { - secp256k1_fe n; - secp256k1_ge q; - int ret_on_curve, ret_frac_on_curve, ret_set_xo; - secp256k1_fe_mul(&n, &zf, &r); - ret_on_curve = secp256k1_ge_x_on_curve_var(&r); - ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf); - ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0); - CHECK(ret_on_curve == ret_frac_on_curve); - CHECK(ret_on_curve == ret_set_xo); - if (ret_set_xo) CHECK(secp256k1_fe_equal(&r, &q.x)); - } - - /* Test batch gej -> ge conversion with many infinities. */ - for (i = 0; i < 4 * runs + 1; i++) { - int odd; - testutil_random_ge_test(&ge[i]); - odd = secp256k1_fe_is_odd(&ge[i].x); - CHECK(odd == 0 || odd == 1); - /* randomly set half the points to infinity */ - if (odd == i % 2) { - secp256k1_ge_set_infinity(&ge[i]); - } - secp256k1_gej_set_ge(&gej[i], &ge[i]); - } - /* batch convert */ - secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); - /* check result */ - for (i = 0; i < 4 * runs + 1; i++) { - CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge[i])); - } - - /* Test batch gej -> ge conversion with all infinities. */ - for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_gej_set_infinity(&gej[i]); - } - /* batch convert */ - secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); - /* check result */ - for (i = 0; i < 4 * runs + 1; i++) { - CHECK(secp256k1_ge_is_infinity(&ge[i])); - } - - free(ge); - free(gej); -} - -static void test_intialized_inf(void) { - secp256k1_ge p; - secp256k1_gej pj, npj, infj1, infj2, infj3; - secp256k1_fe zinv; - - /* Test that adding P+(-P) results in a fully initialized infinity*/ - testutil_random_ge_test(&p); - secp256k1_gej_set_ge(&pj, &p); - secp256k1_gej_neg(&npj, &pj); - - secp256k1_gej_add_var(&infj1, &pj, &npj, NULL); - CHECK(secp256k1_gej_is_infinity(&infj1)); - CHECK(secp256k1_fe_is_zero(&infj1.x)); - CHECK(secp256k1_fe_is_zero(&infj1.y)); - CHECK(secp256k1_fe_is_zero(&infj1.z)); - - secp256k1_gej_add_ge_var(&infj2, &npj, &p, NULL); - CHECK(secp256k1_gej_is_infinity(&infj2)); - CHECK(secp256k1_fe_is_zero(&infj2.x)); - CHECK(secp256k1_fe_is_zero(&infj2.y)); - CHECK(secp256k1_fe_is_zero(&infj2.z)); - - secp256k1_fe_set_int(&zinv, 1); - secp256k1_gej_add_zinv_var(&infj3, &npj, &p, &zinv); - CHECK(secp256k1_gej_is_infinity(&infj3)); - CHECK(secp256k1_fe_is_zero(&infj3.x)); - CHECK(secp256k1_fe_is_zero(&infj3.y)); - CHECK(secp256k1_fe_is_zero(&infj3.z)); - - -} - -static void test_add_neg_y_diff_x(void) { - /* The point of this test is to check that we can add two points - * whose y-coordinates are negatives of each other but whose x - * coordinates differ. If the x-coordinates were the same, these - * points would be negatives of each other and their sum is - * infinity. This is cool because it "covers up" any degeneracy - * in the addition algorithm that would cause the xy coordinates - * of the sum to be wrong (since infinity has no xy coordinates). - * HOWEVER, if the x-coordinates are different, infinity is the - * wrong answer, and such degeneracies are exposed. This is the - * root of https://github.com/bitcoin-core/secp256k1/issues/257 - * which this test is a regression test for. - * - * These points were generated in sage as - * - * load("secp256k1_params.sage") - * - * # random "bad pair" - * P = C.random_element() - * Q = -int(LAMBDA) * P - * print(" P: %x %x" % P.xy()) - * print(" Q: %x %x" % Q.xy()) - * print("P + Q: %x %x" % (P + Q).xy()) - */ - secp256k1_gej aj = SECP256K1_GEJ_CONST( - 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, - 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, - 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, - 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d - ); - secp256k1_gej bj = SECP256K1_GEJ_CONST( - 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, - 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, - 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, - 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 - ); - secp256k1_gej sumj = SECP256K1_GEJ_CONST( - 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, - 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, - 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, - 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe - ); - secp256k1_ge b; - secp256k1_gej resj; - secp256k1_ge res; - secp256k1_ge_set_gej(&b, &bj); - - secp256k1_gej_add_var(&resj, &aj, &bj, NULL); - secp256k1_ge_set_gej(&res, &resj); - CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); - - secp256k1_gej_add_ge(&resj, &aj, &b); - secp256k1_ge_set_gej(&res, &resj); - CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); - - secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); - secp256k1_ge_set_gej(&res, &resj); - CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); -} - -static void test_ge_bytes(void) { - int i; - - for (i = 0; i < COUNT + 1; i++) { - unsigned char buf[64]; - secp256k1_ge p, q; - - if (i == 0) { - secp256k1_ge_set_infinity(&p); - } else { - testutil_random_ge_test(&p); - } - - if (!secp256k1_ge_is_infinity(&p)) { - secp256k1_ge_to_bytes(buf, &p); - - secp256k1_ge_from_bytes(&q, buf); - CHECK(secp256k1_ge_eq_var(&p, &q)); - - secp256k1_ge_from_bytes_ext(&q, buf); - CHECK(secp256k1_ge_eq_var(&p, &q)); - } - secp256k1_ge_to_bytes_ext(buf, &p); - secp256k1_ge_from_bytes_ext(&q, buf); - CHECK(secp256k1_ge_eq_var(&p, &q)); - } -} - -static void run_ge(void) { - int i; - for (i = 0; i < COUNT * 32; i++) { - test_ge(); - } - test_add_neg_y_diff_x(); - test_intialized_inf(); - test_ge_bytes(); -} - -static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { - secp256k1_gej t = *a; - secp256k1_gej_cmov(&t, b, 0); - CHECK(gej_xyz_equals_gej(&t, a)); - secp256k1_gej_cmov(&t, b, 1); - CHECK(gej_xyz_equals_gej(&t, b)); -} - -static void run_gej(void) { - int i; - secp256k1_gej a, b; - - /* Tests for secp256k1_gej_cmov */ - for (i = 0; i < COUNT; i++) { - secp256k1_gej_set_infinity(&a); - secp256k1_gej_set_infinity(&b); - test_gej_cmov(&a, &b); - - testutil_random_gej_test(&a); - test_gej_cmov(&a, &b); - test_gej_cmov(&b, &a); - - b = a; - test_gej_cmov(&a, &b); - - testutil_random_gej_test(&b); - test_gej_cmov(&a, &b); - test_gej_cmov(&b, &a); - } - - /* Tests for secp256k1_gej_eq_var */ - for (i = 0; i < COUNT; i++) { - secp256k1_fe fe; - testutil_random_gej_test(&a); - testutil_random_gej_test(&b); - CHECK(!secp256k1_gej_eq_var(&a, &b)); - - b = a; - testutil_random_fe_non_zero_test(&fe); - secp256k1_gej_rescale(&a, &fe); - CHECK(secp256k1_gej_eq_var(&a, &b)); - } -} - -static void test_ec_combine(void) { - secp256k1_scalar sum = secp256k1_scalar_zero; - secp256k1_pubkey data[6]; - const secp256k1_pubkey* d[6]; - secp256k1_pubkey sd; - secp256k1_pubkey sd2; - secp256k1_gej Qj; - secp256k1_ge Q; - int i; - for (i = 1; i <= 6; i++) { - secp256k1_scalar s; - testutil_random_scalar_order_test(&s); - secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(&data[i - 1], &Q); - d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(&sd, &Q); - CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); - CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); - } -} - -static void run_ec_combine(void) { - int i; - for (i = 0; i < COUNT * 8; i++) { - test_ec_combine(); - } -} - -static void test_group_decompress(const secp256k1_fe* x) { - /* The input itself, normalized. */ - secp256k1_fe fex = *x; - /* Results of set_xo_var(..., 0), set_xo_var(..., 1). */ - secp256k1_ge ge_even, ge_odd; - /* Return values of the above calls. */ - int res_even, res_odd; - - secp256k1_fe_normalize_var(&fex); - - res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); - res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); - - CHECK(res_even == res_odd); - - if (res_even) { - secp256k1_fe_normalize_var(&ge_odd.x); - secp256k1_fe_normalize_var(&ge_even.x); - secp256k1_fe_normalize_var(&ge_odd.y); - secp256k1_fe_normalize_var(&ge_even.y); - - /* No infinity allowed. */ - CHECK(!ge_even.infinity); - CHECK(!ge_odd.infinity); - - /* Check that the x coordinates check out. */ - CHECK(secp256k1_fe_equal(&ge_even.x, x)); - CHECK(secp256k1_fe_equal(&ge_odd.x, x)); - - /* Check odd/even Y in ge_odd, ge_even. */ - CHECK(secp256k1_fe_is_odd(&ge_odd.y)); - CHECK(!secp256k1_fe_is_odd(&ge_even.y)); - } -} - -static void run_group_decompress(void) { - int i; - for (i = 0; i < COUNT * 4; i++) { - secp256k1_fe fe; - testutil_random_fe_test(&fe); - test_group_decompress(&fe); - } -} - -/***** ECMULT TESTS *****/ - -static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { - /* Tests the pre_g / pre_g_128 tables for consistency. - * For independent verification we take a "geometric" approach to verification. - * We check that every entry is on-curve. - * We check that for consecutive entries p and q, that p + gg - q = 0 by checking - * (1) p, gg, and -q are colinear. - * (2) p, gg, and -q are all distinct. - * where gg is twice the generator, where the generator is the first table entry. - * - * Checking the table's generators are correct is done in run_ecmult_pre_g. - */ - secp256k1_gej g2; - secp256k1_ge p, q, gg; - secp256k1_fe dpx, dpy, dqx, dqy; - size_t i; - - CHECK(0 < n); - - secp256k1_ge_from_storage(&p, &pre_g[0]); - CHECK(secp256k1_ge_is_valid_var(&p)); - - secp256k1_gej_set_ge(&g2, &p); - secp256k1_gej_double_var(&g2, &g2, NULL); - secp256k1_ge_set_gej_var(&gg, &g2); - for (i = 1; i < n; ++i) { - secp256k1_fe_negate(&dpx, &p.x, 1); secp256k1_fe_add(&dpx, &gg.x); secp256k1_fe_normalize_weak(&dpx); - secp256k1_fe_negate(&dpy, &p.y, 1); secp256k1_fe_add(&dpy, &gg.y); secp256k1_fe_normalize_weak(&dpy); - /* Check that p is not equal to gg */ - CHECK(!secp256k1_fe_normalizes_to_zero_var(&dpx) || !secp256k1_fe_normalizes_to_zero_var(&dpy)); - - secp256k1_ge_from_storage(&q, &pre_g[i]); - CHECK(secp256k1_ge_is_valid_var(&q)); - - secp256k1_fe_negate(&dqx, &q.x, 1); secp256k1_fe_add(&dqx, &gg.x); - dqy = q.y; secp256k1_fe_add(&dqy, &gg.y); - /* Check that -q is not equal to gg */ - CHECK(!secp256k1_fe_normalizes_to_zero_var(&dqx) || !secp256k1_fe_normalizes_to_zero_var(&dqy)); - - /* Check that -q is not equal to p */ - CHECK(!secp256k1_fe_equal(&dpx, &dqx) || !secp256k1_fe_equal(&dpy, &dqy)); - - /* Check that p, -q and gg are colinear */ - secp256k1_fe_mul(&dpx, &dpx, &dqy); - secp256k1_fe_mul(&dpy, &dpy, &dqx); - CHECK(secp256k1_fe_equal(&dpx, &dpy)); - - p = q; - } -} - -static void run_ecmult_pre_g(void) { - secp256k1_ge_storage gs; - secp256k1_gej gj; - secp256k1_ge g; - size_t i; - - /* Check that the pre_g and pre_g_128 tables are consistent. */ - test_pre_g_table(secp256k1_pre_g, ECMULT_TABLE_SIZE(WINDOW_G)); - test_pre_g_table(secp256k1_pre_g_128, ECMULT_TABLE_SIZE(WINDOW_G)); - - /* Check the first entry from the pre_g table. */ - secp256k1_ge_to_storage(&gs, &secp256k1_ge_const_g); - CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g[0], sizeof(gs)) == 0); - - /* Check the first entry from the pre_g_128 table. */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - for (i = 0; i < 128; ++i) { - secp256k1_gej_double_var(&gj, &gj, NULL); - } - secp256k1_ge_set_gej(&g, &gj); - secp256k1_ge_to_storage(&gs, &g); - CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g_128[0], sizeof(gs)) == 0); -} - -static void run_ecmult_chain(void) { - /* random starting point A (on the curve) */ - secp256k1_gej a = SECP256K1_GEJ_CONST( - 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, - 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, - 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, - 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f - ); - /* two random initial factors xn and gn */ - secp256k1_scalar xn = SECP256K1_SCALAR_CONST( - 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, - 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 - ); - secp256k1_scalar gn = SECP256K1_SCALAR_CONST( - 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, - 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de - ); - /* two small multipliers to be applied to xn and gn in every iteration: */ - static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); - /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar ae = secp256k1_scalar_one; - secp256k1_scalar ge = secp256k1_scalar_zero; - /* actual points */ - secp256k1_gej x; - secp256k1_gej x2; - int i; - - /* the point being computed */ - x = a; - for (i = 0; i < 200*COUNT; i++) { - /* in each iteration, compute X = xn*X + gn*G; */ - secp256k1_ecmult(&x, &x, &xn, &gn); - /* also compute ae and ge: the actual accumulated factors for A and G */ - /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ - secp256k1_scalar_mul(&ae, &ae, &xn); - secp256k1_scalar_mul(&ge, &ge, &xn); - secp256k1_scalar_add(&ge, &ge, &gn); - /* modify xn and gn */ - secp256k1_scalar_mul(&xn, &xn, &xf); - secp256k1_scalar_mul(&gn, &gn, &gf); - - /* verify */ - if (i == 19999) { - /* expected result after 19999 iterations */ - secp256k1_gej rp = SECP256K1_GEJ_CONST( - 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, - 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, - 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, - 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 - ); - CHECK(secp256k1_gej_eq_var(&rp, &x)); - } - } - /* redo the computation, but directly with the resulting ae and ge coefficients: */ - secp256k1_ecmult(&x2, &a, &ae, &ge); - CHECK(secp256k1_gej_eq_var(&x, &x2)); -} - -static void test_point_times_order(const secp256k1_gej *point) { - /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar x; - secp256k1_scalar nx; - secp256k1_gej res1, res2; - secp256k1_ge res3; - unsigned char pub[65]; - size_t psize = 65; - testutil_random_scalar_order_test(&x); - secp256k1_scalar_negate(&nx, &x); - secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - secp256k1_gej_add_var(&res1, &res1, &res2, NULL); - CHECK(secp256k1_gej_is_infinity(&res1)); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_is_infinity(&res3)); - CHECK(secp256k1_ge_is_valid_var(&res3) == 0); - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); - psize = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); - /* check zero/one edge cases */ - secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_is_infinity(&res3)); - secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_gej_eq_ge_var(point, &res3)); - secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3)); -} - -/* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda. - * - * They are computed as: - * - For a in [-2, -1, 0, 1, 2]: - * - For b in [-3, -1, 1, 3]: - * - Output (a*LAMBDA + (ORDER+b)/2) % ORDER - */ -static const secp256k1_scalar scalars_near_split_bounds[20] = { - SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fc), - SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fd), - SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fe), - SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6ff), - SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632d), - SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632e), - SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632f), - SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf76330), - SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b209f), - SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a0), - SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a1), - SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a2), - SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede11), - SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede12), - SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede13), - SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede14), - SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a42), - SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a43), - SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a44), - SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) -}; - -static void test_ecmult_target(const secp256k1_scalar* target, int mode) { - /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ - secp256k1_scalar n1, n2; - secp256k1_ge p; - secp256k1_gej pj, p1j, p2j, ptj; - - /* Generate random n1,n2 such that n1+n2 = -target. */ - testutil_random_scalar_order_test(&n1); - secp256k1_scalar_add(&n2, &n1, target); - secp256k1_scalar_negate(&n2, &n2); - - /* Generate a random input point. */ - if (mode != 0) { - testutil_random_ge_test(&p); - secp256k1_gej_set_ge(&pj, &p); - } - - /* EC multiplications */ - if (mode == 0) { - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); - } else if (mode == 1) { - secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); - secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); - secp256k1_ecmult(&ptj, &pj, target, &secp256k1_scalar_zero); - } else { - secp256k1_ecmult_const(&p1j, &p, &n1); - secp256k1_ecmult_const(&p2j, &p, &n2); - secp256k1_ecmult_const(&ptj, &p, target); - } - - /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ - secp256k1_gej_add_var(&ptj, &ptj, &p1j, NULL); - secp256k1_gej_add_var(&ptj, &ptj, &p2j, NULL); - CHECK(secp256k1_gej_is_infinity(&ptj)); -} - -static void run_ecmult_near_split_bound(void) { - int i; - unsigned j; - for (i = 0; i < 4*COUNT; ++i) { - for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) { - test_ecmult_target(&scalars_near_split_bounds[j], 0); - test_ecmult_target(&scalars_near_split_bounds[j], 1); - test_ecmult_target(&scalars_near_split_bounds[j], 2); - } - } -} - -static void run_point_times_order(void) { - int i; - secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const secp256k1_fe xr = SECP256K1_FE_CONST( - 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, - 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 - ); - for (i = 0; i < 500; i++) { - secp256k1_ge p; - if (secp256k1_ge_set_xo_var(&p, &x, 1)) { - secp256k1_gej j; - CHECK(secp256k1_ge_is_valid_var(&p)); - secp256k1_gej_set_ge(&j, &p); - test_point_times_order(&j); - } - secp256k1_fe_sqr(&x, &x); - } - secp256k1_fe_normalize_var(&x); - CHECK(secp256k1_fe_equal(&x, &xr)); -} - -static void ecmult_const_random_mult(void) { - /* random starting point A (on the curve) */ - secp256k1_ge a = SECP256K1_GE_CONST( - 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, - 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, - 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, - 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d - ); - /* random initial factor xn */ - secp256k1_scalar xn = SECP256K1_SCALAR_CONST( - 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, - 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b - ); - /* expected xn * A (from sage) */ - secp256k1_ge expected_b = SECP256K1_GE_CONST( - 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, - 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, - 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, - 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 - ); - secp256k1_gej b; - secp256k1_ecmult_const(&b, &a, &xn); - - CHECK(secp256k1_ge_is_valid_var(&a)); - CHECK(secp256k1_gej_eq_ge_var(&b, &expected_b)); -} - -static void ecmult_const_commutativity(void) { - secp256k1_scalar a; - secp256k1_scalar b; - secp256k1_gej res1; - secp256k1_gej res2; - secp256k1_ge mid1; - secp256k1_ge mid2; - testutil_random_scalar_order_test(&a); - testutil_random_scalar_order_test(&b); - - secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); - secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - secp256k1_ecmult_const(&res1, &mid1, &b); - secp256k1_ecmult_const(&res2, &mid2, &a); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - CHECK(secp256k1_ge_eq_var(&mid1, &mid2)); -} - -static void ecmult_const_mult_zero_one(void) { - secp256k1_scalar s; - secp256k1_scalar negone; - secp256k1_gej res1; - secp256k1_ge res2; - secp256k1_ge point; - secp256k1_ge inf; - - testutil_random_scalar_order_test(&s); - secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); - testutil_random_ge_test(&point); - secp256k1_ge_set_infinity(&inf); - - /* 0*point */ - secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero); - CHECK(secp256k1_gej_is_infinity(&res1)); - - /* s*inf */ - secp256k1_ecmult_const(&res1, &inf, &s); - CHECK(secp256k1_gej_is_infinity(&res1)); - - /* 1*point */ - secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one); - secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_eq_var(&res2, &point)); - - /* -1*point */ - secp256k1_ecmult_const(&res1, &point, &negone); - secp256k1_gej_neg(&res1, &res1); - secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_eq_var(&res2, &point)); -} - -static void ecmult_const_check_result(const secp256k1_ge *A, const secp256k1_scalar* q, const secp256k1_gej *res) { - secp256k1_gej pointj, res2j; - secp256k1_ge res2; - secp256k1_gej_set_ge(&pointj, A); - secp256k1_ecmult(&res2j, &pointj, q, &secp256k1_scalar_zero); - secp256k1_ge_set_gej(&res2, &res2j); - CHECK(secp256k1_gej_eq_ge_var(res, &res2)); -} - -static void ecmult_const_edges(void) { - secp256k1_scalar q; - secp256k1_ge point; - secp256k1_gej res; - size_t i; - size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); - - /* We are trying to reach the following edge cases (variables are defined as - * in ecmult_const_impl.h): - * 1. i = 0: s = 0 <=> q = -K - * 2. i > 0: v1, v2 large values - * <=> s1, s2 large values - * <=> s = scalars_near_split_bounds[i] - * <=> q = 2*scalars_near_split_bounds[i] - K - */ - for (i = 0; i < cases; ++i) { - secp256k1_scalar_negate(&q, &secp256k1_ecmult_const_K); - if (i > 0) { - secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); - secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); - } - testutil_random_ge_test(&point); - secp256k1_ecmult_const(&res, &point, &q); - ecmult_const_check_result(&point, &q, &res); - } -} - -static void ecmult_const_mult_xonly(void) { - int i; - - /* Test correspondence between secp256k1_ecmult_const and secp256k1_ecmult_const_xonly. */ - for (i = 0; i < 2*COUNT; ++i) { - secp256k1_ge base; - secp256k1_gej basej, resj; - secp256k1_fe n, d, resx, v; - secp256k1_scalar q; - int res; - /* Random base point. */ - testutil_random_ge_test(&base); - /* Random scalar to multiply it with. */ - testutil_random_scalar_order_test(&q); - /* If i is odd, n=d*base.x for random non-zero d */ - if (i & 1) { - testutil_random_fe_non_zero_test(&d); - secp256k1_fe_mul(&n, &base.x, &d); - } else { - n = base.x; - } - /* Perform x-only multiplication. */ - res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2); - CHECK(res); - /* Perform normal multiplication. */ - secp256k1_gej_set_ge(&basej, &base); - secp256k1_ecmult(&resj, &basej, &q, NULL); - /* Check that resj's X coordinate corresponds with resx. */ - secp256k1_fe_sqr(&v, &resj.z); - secp256k1_fe_mul(&v, &v, &resx); - CHECK(fe_equal(&v, &resj.x)); - } - - /* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */ - for (i = 0; i < 2*COUNT; ++i) { - secp256k1_fe x, n, d, r; - int res; - secp256k1_scalar q; - testutil_random_scalar_order_test(&q); - /* Generate random X coordinate not on the curve. */ - do { - testutil_random_fe_test(&x); - } while (secp256k1_ge_x_on_curve_var(&x)); - /* If i is odd, n=d*x for random non-zero d. */ - if (i & 1) { - testutil_random_fe_non_zero_test(&d); - secp256k1_fe_mul(&n, &x, &d); - } else { - n = x; - } - res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0); - CHECK(res == 0); - } -} - -static void ecmult_const_chain_multiply(void) { - /* Check known result (randomly generated test problem from sage) */ - const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( - 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, - 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b - ); - const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( - 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, - 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, - 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, - 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 - ); - secp256k1_gej point; - secp256k1_ge res; - int i; - - secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); - for (i = 0; i < 100; ++i) { - secp256k1_ge tmp; - secp256k1_ge_set_gej(&tmp, &point); - secp256k1_ecmult_const(&point, &tmp, &scalar); - } - secp256k1_ge_set_gej(&res, &point); - CHECK(secp256k1_gej_eq_ge_var(&expected_point, &res)); -} - -static void run_ecmult_const_tests(void) { - ecmult_const_mult_zero_one(); - ecmult_const_edges(); - ecmult_const_random_mult(); - ecmult_const_commutativity(); - ecmult_const_chain_multiply(); - ecmult_const_mult_xonly(); -} - -typedef struct { - secp256k1_scalar *sc; - secp256k1_ge *pt; -} ecmult_multi_data; - -static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { - ecmult_multi_data *data = (ecmult_multi_data*) cbdata; - *sc = data->sc[idx]; - *pt = data->pt[idx]; - return 1; -} - -static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { - (void)sc; - (void)pt; - (void)idx; - (void)cbdata; - return 0; -} - -static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { - int ncount; - secp256k1_scalar sc[32]; - secp256k1_ge pt[32]; - secp256k1_gej r; - secp256k1_gej r2; - ecmult_multi_data data; - - data.sc = sc; - data.pt = pt; - - /* No points to multiply */ - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); - - /* Check 1- and 2-point multiplies against ecmult */ - for (ncount = 0; ncount < COUNT; ncount++) { - secp256k1_ge ptg; - secp256k1_gej ptgj; - testutil_random_scalar_order(&sc[0]); - testutil_random_scalar_order(&sc[1]); - - testutil_random_ge_test(&ptg); - secp256k1_gej_set_ge(&ptgj, &ptg); - pt[0] = ptg; - pt[1] = secp256k1_ge_const_g; - - /* only G scalar */ - secp256k1_ecmult(&r2, &ptgj, &secp256k1_scalar_zero, &sc[0]); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - - /* 1-point */ - secp256k1_ecmult(&r2, &ptgj, &sc[0], &secp256k1_scalar_zero); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - - /* Try to multiply 1 point, but callback returns false */ - CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_false_callback, &data, 1)); - - /* 2-point */ - secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - - /* 2-point with G scalar */ - secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - } - - /* Check infinite outputs of various forms */ - for (ncount = 0; ncount < COUNT; ncount++) { - secp256k1_ge ptg; - size_t i, j; - size_t sizes[] = { 2, 10, 32 }; - - for (j = 0; j < 3; j++) { - for (i = 0; i < 32; i++) { - testutil_random_scalar_order(&sc[i]); - secp256k1_ge_set_infinity(&pt[i]); - } - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); - CHECK(secp256k1_gej_is_infinity(&r)); - } - - for (j = 0; j < 3; j++) { - for (i = 0; i < 32; i++) { - testutil_random_ge_test(&ptg); - pt[i] = ptg; - secp256k1_scalar_set_int(&sc[i], 0); - } - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); - CHECK(secp256k1_gej_is_infinity(&r)); - } - - for (j = 0; j < 3; j++) { - testutil_random_ge_test(&ptg); - for (i = 0; i < 16; i++) { - testutil_random_scalar_order(&sc[2*i]); - secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]); - pt[2 * i] = ptg; - pt[2 * i + 1] = ptg; - } - - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); - CHECK(secp256k1_gej_is_infinity(&r)); - - testutil_random_scalar_order(&sc[0]); - for (i = 0; i < 16; i++) { - testutil_random_ge_test(&ptg); - - sc[2*i] = sc[0]; - sc[2*i+1] = sc[0]; - pt[2 * i] = ptg; - secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); - } - - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); - CHECK(secp256k1_gej_is_infinity(&r)); - } - - testutil_random_ge_test(&ptg); - secp256k1_scalar_set_int(&sc[0], 0); - pt[0] = ptg; - for (i = 1; i < 32; i++) { - pt[i] = ptg; - - testutil_random_scalar_order(&sc[i]); - secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]); - secp256k1_scalar_negate(&sc[i], &sc[i]); - } - - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 32)); - CHECK(secp256k1_gej_is_infinity(&r)); - } - - /* Check random points, constant scalar */ - for (ncount = 0; ncount < COUNT; ncount++) { - size_t i; - secp256k1_gej_set_infinity(&r); - - testutil_random_scalar_order(&sc[0]); - for (i = 0; i < 20; i++) { - secp256k1_ge ptg; - sc[i] = sc[0]; - testutil_random_ge_test(&ptg); - pt[i] = ptg; - secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL); - } - - secp256k1_ecmult(&r2, &r, &sc[0], &secp256k1_scalar_zero); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - } - - /* Check random scalars, constant point */ - for (ncount = 0; ncount < COUNT; ncount++) { - size_t i; - secp256k1_ge ptg; - secp256k1_gej p0j; - secp256k1_scalar rs; - secp256k1_scalar_set_int(&rs, 0); - - testutil_random_ge_test(&ptg); - for (i = 0; i < 20; i++) { - testutil_random_scalar_order(&sc[i]); - pt[i] = ptg; - secp256k1_scalar_add(&rs, &rs, &sc[i]); - } - - secp256k1_gej_set_ge(&p0j, &pt[0]); - secp256k1_ecmult(&r2, &p0j, &rs, &secp256k1_scalar_zero); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); - CHECK(secp256k1_gej_eq_var(&r, &r2)); - } - - /* Sanity check that zero scalars don't cause problems */ - for (ncount = 0; ncount < 20; ncount++) { - testutil_random_scalar_order(&sc[ncount]); - testutil_random_ge_test(&pt[ncount]); - } - - secp256k1_scalar_set_int(&sc[0], 0); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); - secp256k1_scalar_set_int(&sc[1], 0); - secp256k1_scalar_set_int(&sc[2], 0); - secp256k1_scalar_set_int(&sc[3], 0); - secp256k1_scalar_set_int(&sc[4], 0); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 6)); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5)); - CHECK(secp256k1_gej_is_infinity(&r)); - - /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ - { - const size_t TOP = 8; - size_t s0i, s1i; - size_t t0i, t1i; - secp256k1_ge ptg; - secp256k1_gej ptgj; - - testutil_random_ge_test(&ptg); - secp256k1_gej_set_ge(&ptgj, &ptg); - - for(t0i = 0; t0i < TOP; t0i++) { - for(t1i = 0; t1i < TOP; t1i++) { - secp256k1_gej t0p, t1p; - secp256k1_scalar t0, t1; - - secp256k1_scalar_set_int(&t0, (t0i + 1) / 2); - secp256k1_scalar_cond_negate(&t0, t0i & 1); - secp256k1_scalar_set_int(&t1, (t1i + 1) / 2); - secp256k1_scalar_cond_negate(&t1, t1i & 1); - - secp256k1_ecmult(&t0p, &ptgj, &t0, &secp256k1_scalar_zero); - secp256k1_ecmult(&t1p, &ptgj, &t1, &secp256k1_scalar_zero); - - for(s0i = 0; s0i < TOP; s0i++) { - for(s1i = 0; s1i < TOP; s1i++) { - secp256k1_scalar tmp1, tmp2; - secp256k1_gej expected, actual; - - secp256k1_ge_set_gej(&pt[0], &t0p); - secp256k1_ge_set_gej(&pt[1], &t1p); - - secp256k1_scalar_set_int(&sc[0], (s0i + 1) / 2); - secp256k1_scalar_cond_negate(&sc[0], s0i & 1); - secp256k1_scalar_set_int(&sc[1], (s1i + 1) / 2); - secp256k1_scalar_cond_negate(&sc[1], s1i & 1); - - secp256k1_scalar_mul(&tmp1, &t0, &sc[0]); - secp256k1_scalar_mul(&tmp2, &t1, &sc[1]); - secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); - - secp256k1_ecmult(&expected, &ptgj, &tmp1, &secp256k1_scalar_zero); - CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); - CHECK(secp256k1_gej_eq_var(&actual, &expected)); - } - } - } - } - } -} - -static int test_ecmult_multi_random(secp256k1_scratch *scratch) { - /* Large random test for ecmult_multi_* functions which exercises: - * - Few or many inputs (0 up to 128, roughly exponentially distributed). - * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). - * - Including or excluding an nonzero a*G term (or such a term at all). - * - Final expected result equal to infinity or not (roughly 50%). - * - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch - */ - - /* These 4 variables define the eventual input to the ecmult_multi function. - * g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and - * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points - * which form its normal inputs. */ - int filled = 0; - secp256k1_scalar g_scalar = secp256k1_scalar_zero; - secp256k1_scalar scalars[128]; - secp256k1_gej gejs[128]; - /* The expected result, and the computed result. */ - secp256k1_gej expected, computed; - /* Temporaries. */ - secp256k1_scalar sc_tmp; - secp256k1_ge ge_tmp; - /* Variables needed for the actual input to ecmult_multi. */ - secp256k1_ge ges[128]; - ecmult_multi_data data; - - int i; - /* Which multiplication function to use */ - int fn = testrand_int(3); - secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var : - fn == 1 ? secp256k1_ecmult_strauss_batch_single : - secp256k1_ecmult_pippenger_batch_single; - /* Simulate exponentially distributed num. */ - int num_bits = 2 + testrand_int(6); - /* Number of (scalar, point) inputs (excluding g). */ - int num = testrand_int((1 << num_bits) + 1); - /* Number of those which are nonzero. */ - int num_nonzero = testrand_int(num + 1); - /* Whether we're aiming to create an input with nonzero expected result. */ - int nonzero_result = testrand_bits(1); - /* Whether we will provide nonzero g multiplicand. In some cases our hand - * is forced here based on num_nonzero and nonzero_result. */ - int g_nonzero = num_nonzero == 0 ? nonzero_result : - num_nonzero == 1 && !nonzero_result ? 1 : - (int)testrand_bits(1); - /* Which g_scalar pointer to pass into ecmult_multi(). */ - const secp256k1_scalar* g_scalar_ptr = (g_nonzero || testrand_bits(1)) ? &g_scalar : NULL; - /* How many EC multiplications were performed in this function. */ - int mults = 0; - /* How many randomization steps to apply to the input list. */ - int rands = (int)testrand_bits(3); - if (rands > num_nonzero) rands = num_nonzero; - - secp256k1_gej_set_infinity(&expected); - secp256k1_gej_set_infinity(&gejs[0]); - secp256k1_scalar_set_int(&scalars[0], 0); - - if (g_nonzero) { - /* If g_nonzero, set g_scalar to nonzero value r. */ - testutil_random_scalar_order_test(&g_scalar); - if (!nonzero_result) { - /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */ - CHECK(num_nonzero > filled); - testutil_random_scalar_order_test(&sc_tmp); - secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); - secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); - secp256k1_scalar_negate(&sc_tmp, &sc_tmp); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); - ++filled; - ++mults; - } - } - - if (nonzero_result && filled < num_nonzero) { - /* If a nonzero result is desired, and there is space, add a random nonzero term. */ - testutil_random_scalar_order_test(&scalars[filled]); - testutil_random_ge_test(&ge_tmp); - secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); - ++filled; - } - - if (nonzero_result) { - /* Compute the expected result using normal ecmult. */ - CHECK(filled <= 1); - secp256k1_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar); - mults += filled + g_nonzero; - } - - /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */ - CHECK(filled <= 1 + !nonzero_result); - CHECK(filled <= num_nonzero); - - /* Add entries to scalars,gejs so that there are num of them. All the added entries - * either have scalar=0 or point=infinity, so these do not change the expected result. */ - while (filled < num) { - if (testrand_bits(1)) { - secp256k1_gej_set_infinity(&gejs[filled]); - testutil_random_scalar_order_test(&scalars[filled]); - } else { - secp256k1_scalar_set_int(&scalars[filled], 0); - testutil_random_ge_test(&ge_tmp); - secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); - } - ++filled; - } - - /* Now perform cheapish transformations on gejs and scalars, for indices - * 0..num_nonzero-1, which do not change the expected result, but may - * convert some of them to be both non-0-scalar and non-infinity-point. */ - for (i = 0; i < rands; ++i) { - int j; - secp256k1_scalar v, iv; - /* Shuffle the entries. */ - for (j = 0; j < num_nonzero; ++j) { - int k = testrand_int(num_nonzero - j); - if (k != 0) { - secp256k1_gej gej = gejs[j]; - secp256k1_scalar sc = scalars[j]; - gejs[j] = gejs[j + k]; - scalars[j] = scalars[j + k]; - gejs[j + k] = gej; - scalars[j + k] = sc; - } - } - /* Perturb all consecutive pairs of inputs: - * a*P + b*Q -> (a+b)*P + b*(Q-P). */ - for (j = 0; j + 1 < num_nonzero; j += 2) { - secp256k1_gej gej; - secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]); - secp256k1_gej_neg(&gej, &gejs[j]); - secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL); - } - /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ - CHECK(num_nonzero >= 1); - testutil_random_scalar_order_test(&v); - secp256k1_scalar_inverse(&iv, &v); - secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); - secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); - ++mults; - } - - /* Shuffle all entries (0..num-1). */ - for (i = 0; i < num; ++i) { - int j = testrand_int(num - i); - if (j != 0) { - secp256k1_gej gej = gejs[i]; - secp256k1_scalar sc = scalars[i]; - gejs[i] = gejs[i + j]; - scalars[i] = scalars[i + j]; - gejs[i + j] = gej; - scalars[i + j] = sc; - } - } - - /* Compute affine versions of all inputs. */ - secp256k1_ge_set_all_gej_var(ges, gejs, filled); - /* Invoke ecmult_multi code. */ - data.sc = scalars; - data.pt = ges; - CHECK(ecmult_multi(&CTX->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); - mults += num_nonzero + g_nonzero; - /* Compare with expected result. */ - CHECK(secp256k1_gej_eq_var(&computed, &expected)); - return mults; -} - -static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { - secp256k1_scalar sc; - secp256k1_ge pt; - secp256k1_gej r; - ecmult_multi_data data; - secp256k1_scratch *scratch_empty; - - testutil_random_ge_test(&pt); - testutil_random_scalar_order(&sc); - data.sc = ≻ - data.pt = &pt; - - /* Try to multiply 1 point, but scratch space is empty.*/ - scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0); - CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); - secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty); -} - -static void test_secp256k1_pippenger_bucket_window_inv(void) { - int i; - - CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); - for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { - /* Bucket_window of 8 is not used with endo */ - if (i == 8) { - continue; - } - CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i); - if (i != PIPPENGER_MAX_BUCKET_WINDOW) { - CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i); - } - } -} - -/** - * Probabilistically test the function returning the maximum number of possible points - * for a given scratch space. - */ -static void test_ecmult_multi_pippenger_max_points(void) { - size_t scratch_size = testrand_bits(8); - size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); - secp256k1_scratch *scratch; - size_t n_points_supported; - int bucket_window = 0; - - for(; scratch_size < max_size; scratch_size+=256) { - size_t i; - size_t total_alloc; - size_t checkpoint; - scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size); - CHECK(scratch != NULL); - checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); - n_points_supported = secp256k1_pippenger_max_points(&CTX->error_callback, scratch); - if (n_points_supported == 0) { - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - continue; - } - bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); - /* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */ - total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window); - for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) { - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 1)); - total_alloc--; - } - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, total_alloc)); - secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - } - CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); -} - -static void test_ecmult_multi_batch_size_helper(void) { - size_t n_batches, n_batch_points, max_n_batch_points, n; - - max_n_batch_points = 0; - n = 1; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0); - - max_n_batch_points = 1; - n = 0; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == 0); - CHECK(n_batch_points == 0); - - max_n_batch_points = 2; - n = 5; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == 3); - CHECK(n_batch_points == 2); - - max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; - n = ECMULT_MAX_POINTS_PER_BATCH; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == 1); - CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH); - - max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1; - n = ECMULT_MAX_POINTS_PER_BATCH + 1; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == 2); - CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1); - - max_n_batch_points = 1; - n = SIZE_MAX; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == SIZE_MAX); - CHECK(n_batch_points == 1); - - max_n_batch_points = 2; - n = SIZE_MAX; - CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); - CHECK(n_batches == SIZE_MAX/2 + 1); - CHECK(n_batch_points == 2); -} - -/** - * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to - * 1 <= i <= num points. - */ -static void test_ecmult_multi_batching(void) { - static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; - secp256k1_scalar scG; - secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points); - secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points); - secp256k1_gej r; - secp256k1_gej r2; - ecmult_multi_data data; - int i; - secp256k1_scratch *scratch; - - secp256k1_gej_set_infinity(&r2); - - /* Get random scalars and group elements and compute result */ - testutil_random_scalar_order(&scG); - secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG); - for(i = 0; i < n_points; i++) { - secp256k1_ge ptg; - secp256k1_gej ptgj; - testutil_random_ge_test(&ptg); - secp256k1_gej_set_ge(&ptgj, &ptg); - pt[i] = ptg; - testutil_random_scalar_order(&sc[i]); - secp256k1_ecmult(&ptgj, &ptgj, &sc[i], NULL); - secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL); - } - data.sc = sc; - data.pt = pt; - secp256k1_gej_neg(&r2, &r2); - - /* Test with empty scratch space. It should compute the correct result using - * ecmult_mult_simple algorithm which doesn't require a scratch space. */ - scratch = secp256k1_scratch_create(&CTX->error_callback, 0); - CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - - /* Test with space for 1 point in pippenger. That's not enough because - * ecmult_multi selects strauss which requires more memory. It should - * therefore select the simple algorithm. */ - scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); - CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - - for(i = 1; i <= n_points; i++) { - if (i > ECMULT_PIPPENGER_THRESHOLD) { - int bucket_window = secp256k1_pippenger_bucket_window(i); - size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window); - scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); - } else { - size_t scratch_size = secp256k1_strauss_scratch_size(i); - scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); - } - CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - } - free(sc); - free(pt); -} - -static void run_ecmult_multi_tests(void) { - secp256k1_scratch *scratch; - int64_t todo = (int64_t)320 * COUNT; - - test_secp256k1_pippenger_bucket_window_inv(); - test_ecmult_multi_pippenger_max_points(); - scratch = secp256k1_scratch_create(&CTX->error_callback, 819200); - test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); - test_ecmult_multi(NULL, secp256k1_ecmult_multi_var); - test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); - test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single); - test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); - test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single); - while (todo > 0) { - todo -= test_ecmult_multi_random(scratch); - } - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - - /* Run test_ecmult_multi with space for exactly one point */ - scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); - test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); - secp256k1_scratch_destroy(&CTX->error_callback, scratch); - - test_ecmult_multi_batch_size_helper(); - test_ecmult_multi_batching(); -} - -static void test_wnaf(const secp256k1_scalar *number, int w) { - secp256k1_scalar x, two, t; - int wnaf[256]; - int zeroes = -1; - int i; - int bits; - secp256k1_scalar_set_int(&x, 0); - secp256k1_scalar_set_int(&two, 2); - bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); - CHECK(bits <= 256); - for (i = bits-1; i >= 0; i--) { - int v = wnaf[i]; - secp256k1_scalar_mul(&x, &x, &two); - if (v) { - CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ - zeroes=0; - CHECK((v & 1) == 1); /* check non-zero elements are odd */ - CHECK(v <= (1 << (w-1)) - 1); /* check range below */ - CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ - } else { - CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ - zeroes++; - } - if (v >= 0) { - secp256k1_scalar_set_int(&t, v); - } else { - secp256k1_scalar_set_int(&t, -v); - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_add(&x, &x, &t); - } - CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ -} - -static void test_fixed_wnaf(const secp256k1_scalar *number, int w) { - secp256k1_scalar x, shift; - int wnaf[256] = {0}; - int i; - int skew; - secp256k1_scalar num, unused; - - secp256k1_scalar_set_int(&x, 0); - secp256k1_scalar_set_int(&shift, 1 << w); - /* Make num a 128-bit scalar. */ - secp256k1_scalar_split_128(&num, &unused, number); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - - for (i = WNAF_SIZE(w)-1; i >= 0; --i) { - secp256k1_scalar t; - int v = wnaf[i]; - CHECK(v == 0 || v & 1); /* check parity */ - CHECK(v > -(1 << w)); /* check range above */ - CHECK(v < (1 << w)); /* check range below */ - - secp256k1_scalar_mul(&x, &x, &shift); - if (v >= 0) { - secp256k1_scalar_set_int(&t, v); - } else { - secp256k1_scalar_set_int(&t, -v); - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_add(&x, &x, &t); - } - /* If skew is 1 then add 1 to num */ - secp256k1_scalar_cadd_bit(&num, 0, skew == 1); - CHECK(secp256k1_scalar_eq(&x, &num)); -} - -/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the - * rest is 0.*/ -static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { - int i; - for (i = WNAF_SIZE(w)-1; i >= 8; --i) { - CHECK(wnaf[i] == 0); - } - for (i = 7; i >= 0; --i) { - CHECK(wnaf[i] == wnaf_expected[i]); - } -} - -static void test_fixed_wnaf_small(void) { - int w = 4; - int wnaf[256] = {0}; - int i; - int skew; - secp256k1_scalar num; - - secp256k1_scalar_set_int(&num, 0); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - for (i = WNAF_SIZE(w)-1; i >= 0; --i) { - int v = wnaf[i]; - CHECK(v == 0); - } - CHECK(skew == 0); - - secp256k1_scalar_set_int(&num, 1); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - for (i = WNAF_SIZE(w)-1; i >= 1; --i) { - int v = wnaf[i]; - CHECK(v == 0); - } - CHECK(wnaf[0] == 1); - CHECK(skew == 0); - - { - int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; - secp256k1_scalar_set_int(&num, 0xffffffff); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); - CHECK(skew == 0); - } - { - int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; - secp256k1_scalar_set_int(&num, 0xeeeeeeee); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); - CHECK(skew == 1); - } - { - int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; - secp256k1_scalar_set_int(&num, 0x01010101); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); - CHECK(skew == 0); - } - { - int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; - secp256k1_scalar_set_int(&num, 0x01ef1ef1); - skew = secp256k1_wnaf_fixed(wnaf, &num, w); - test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); - CHECK(skew == 0); - } -} - -static void run_wnaf(void) { - int i; - secp256k1_scalar n; - - /* Test 0 for fixed wnaf */ - test_fixed_wnaf_small(); - /* Random tests */ - for (i = 0; i < COUNT; i++) { - testutil_random_scalar_order(&n); - test_wnaf(&n, 4+(i%10)); - test_fixed_wnaf(&n, 4 + (i % 10)); - } - secp256k1_scalar_set_int(&n, 0); - CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); - CHECK(secp256k1_scalar_is_zero(&n)); - CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); - CHECK(secp256k1_scalar_is_zero(&n)); -} - -static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, size_t idx, void* data) { - const secp256k1_scalar* indata = (const secp256k1_scalar*)data; - *sc = *indata; - *pt = secp256k1_ge_const_g; - CHECK(idx == 0); - return 1; -} - -static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) { - /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */ - secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; - secp256k1_ge r; - unsigned char bytes[65]; - size_t size = 65; - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - secp256k1_gej_set_infinity(&infj); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x); - secp256k1_ecmult(&rj2, &gj, x, &secp256k1_scalar_zero); - secp256k1_ecmult(&rj3, &infj, &secp256k1_scalar_zero, x); - CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj4, x, NULL, NULL, 0)); - CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj5, &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1)); - secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x); - secp256k1_ge_set_gej_var(&r, &rj1); - CHECK(secp256k1_gej_eq_ge_var(&rj2, &r)); - CHECK(secp256k1_gej_eq_ge_var(&rj3, &r)); - CHECK(secp256k1_gej_eq_ge_var(&rj4, &r)); - CHECK(secp256k1_gej_eq_ge_var(&rj5, &r)); - CHECK(secp256k1_gej_eq_ge_var(&rj6, &r)); - if (secp256k1_ge_is_infinity(&r)) { - /* Store infinity as 0x00 */ - const unsigned char zerobyte[1] = {0}; - secp256k1_sha256_write(acc, zerobyte, 1); - } else { - /* Store other points using their uncompressed serialization. */ - secp256k1_eckey_pubkey_serialize(&r, bytes, &size, 0); - CHECK(size == 65); - secp256k1_sha256_write(acc, bytes, size); - } -} - -static void test_ecmult_constants_2bit(void) { - /* Using test_ecmult_accumulate, test ecmult for: - * - For i in 0..36: - * - Key i - * - Key -i - * - For i in 0..255: - * - For j in 1..255 (only odd values): - * - Key (j*2^i) mod order - */ - secp256k1_scalar x; - secp256k1_sha256 acc; - unsigned char b32[32]; - int i, j; - secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); - - /* Expected hash of all the computed points; created with an independent - * implementation. */ - static const unsigned char expected32[32] = { - 0xe4, 0x71, 0x1b, 0x4d, 0x14, 0x1e, 0x68, 0x48, - 0xb7, 0xaf, 0x47, 0x2b, 0x4c, 0xd2, 0x04, 0x14, - 0x3a, 0x75, 0x87, 0x60, 0x1a, 0xf9, 0x63, 0x60, - 0xd0, 0xcb, 0x1f, 0xaa, 0x85, 0x9a, 0xb7, 0xb4 - }; - secp256k1_sha256_initialize(&acc); - for (i = 0; i <= 36; ++i) { - secp256k1_scalar_set_int(&x, i); - test_ecmult_accumulate(&acc, &x, scratch); - secp256k1_scalar_negate(&x, &x); - test_ecmult_accumulate(&acc, &x, scratch); - }; - for (i = 0; i < 256; ++i) { - for (j = 1; j < 256; j += 2) { - int k; - secp256k1_scalar_set_int(&x, j); - for (k = 0; k < i; ++k) secp256k1_scalar_add(&x, &x, &x); - test_ecmult_accumulate(&acc, &x, scratch); - } - } - secp256k1_sha256_finalize(&acc, b32); - CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); - - secp256k1_scratch_space_destroy(CTX, scratch); -} - -static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { - /* Using test_ecmult_accumulate, test ecmult for: - * - Key 0 - * - Key 1 - * - Key -1 - * - For i in range(iter): - * - Key SHA256(LE32(prefix) || LE16(i)) - */ - secp256k1_scalar x; - secp256k1_sha256 acc; - unsigned char b32[32]; - unsigned char inp[6]; - size_t i; - secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); - - inp[0] = prefix & 0xFF; - inp[1] = (prefix >> 8) & 0xFF; - inp[2] = (prefix >> 16) & 0xFF; - inp[3] = (prefix >> 24) & 0xFF; - secp256k1_sha256_initialize(&acc); - secp256k1_scalar_set_int(&x, 0); - test_ecmult_accumulate(&acc, &x, scratch); - secp256k1_scalar_set_int(&x, 1); - test_ecmult_accumulate(&acc, &x, scratch); - secp256k1_scalar_negate(&x, &x); - test_ecmult_accumulate(&acc, &x, scratch); - - for (i = 0; i < iter; ++i) { - secp256k1_sha256 gen; - inp[4] = i & 0xff; - inp[5] = (i >> 8) & 0xff; - secp256k1_sha256_initialize(&gen); - secp256k1_sha256_write(&gen, inp, sizeof(inp)); - secp256k1_sha256_finalize(&gen, b32); - secp256k1_scalar_set_b32(&x, b32, NULL); - test_ecmult_accumulate(&acc, &x, scratch); - } - secp256k1_sha256_finalize(&acc, b32); - CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); - - secp256k1_scratch_space_destroy(CTX, scratch); -} - -static void run_ecmult_constants(void) { - /* Expected hashes of all points in the tests below. Computed using an - * independent implementation. */ - static const unsigned char expected32_6bit20[32] = { - 0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f, - 0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e, - 0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e, - 0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e - }; - static const unsigned char expected32_8bit8[32] = { - 0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95, - 0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec, - 0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12, - 0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6 - }; - /* For every combination of 6 bit positions out of 256, restricted to - * 20-bit windows (i.e., the first and last bit position are no more than - * 19 bits apart), all 64 bit patterns occur in the input scalars used in - * this test. */ - CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") { - test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20); - } - - /* For every combination of 8 consecutive bit positions, all 256 bit - * patterns occur in the input scalars used in this test. */ - CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") { - test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8); - } - - CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") { - test_ecmult_constants_2bit(); - } -} - -static void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ - secp256k1_scalar key; - secp256k1_scalar b; - unsigned char seed32[32]; - secp256k1_gej pgej; - secp256k1_gej pgej2; - secp256k1_ge p; - secp256k1_ge pge; - testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); - testrand256(seed32); - b = CTX->ecmult_gen_ctx.scalar_offset; - p = CTX->ecmult_gen_ctx.ge_offset; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); - CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key); - CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); - CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); - secp256k1_ge_set_gej(&pge, &pgej); - CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge)); -} - -static void test_ecmult_gen_blind_reset(void) { - /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - secp256k1_scalar b; - secp256k1_ge p1, p2; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); - b = CTX->ecmult_gen_ctx.scalar_offset; - p1 = CTX->ecmult_gen_ctx.ge_offset; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); - CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); - p2 = CTX->ecmult_gen_ctx.ge_offset; - CHECK(secp256k1_ge_eq_var(&p1, &p2)); -} - -/* Verify that ecmult_gen for scalars gn for which gn + scalar_offset = {-1,0,1}. */ -static void test_ecmult_gen_edge_cases(void) { - int i; - secp256k1_gej res1, res2, res3; - secp256k1_scalar gn = secp256k1_scalar_one; /* gn = 1 */ - secp256k1_scalar_add(&gn, &gn, &CTX->ecmult_gen_ctx.scalar_offset); /* gn = 1 + scalar_offset */ - secp256k1_scalar_negate(&gn, &gn); /* gn = -1 - scalar_offset */ - - for (i = -1; i < 2; ++i) { - /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); - secp256k1_ecmult(&res2, NULL, &secp256k1_scalar_zero, &gn); - secp256k1_ecmult_const(&res3, &secp256k1_ge_const_g, &gn); - CHECK(secp256k1_gej_eq_var(&res1, &res2)); - CHECK(secp256k1_gej_eq_var(&res1, &res3)); - secp256k1_scalar_add(&gn, &gn, &secp256k1_scalar_one); - } -} - -static void run_ecmult_gen_blind(void) { - int i; - test_ecmult_gen_blind_reset(); - test_ecmult_gen_edge_cases(); - for (i = 0; i < 10; i++) { - test_ecmult_gen_blind(); - } -} - -/***** ENDOMORPHISH TESTS *****/ -static void test_scalar_split(const secp256k1_scalar* full) { - secp256k1_scalar s, s1, slam; - const unsigned char zero[32] = {0}; - unsigned char tmp[32]; - - secp256k1_scalar_split_lambda(&s1, &slam, full); - - /* check slam*lambda + s1 == full */ - secp256k1_scalar_mul(&s, &secp256k1_const_lambda, &slam); - secp256k1_scalar_add(&s, &s, &s1); - CHECK(secp256k1_scalar_eq(&s, full)); - - /* check that both are <= 128 bits in size */ - if (secp256k1_scalar_is_high(&s1)) { - secp256k1_scalar_negate(&s1, &s1); - } - if (secp256k1_scalar_is_high(&slam)) { - secp256k1_scalar_negate(&slam, &slam); - } - - secp256k1_scalar_get_b32(tmp, &s1); - CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); - secp256k1_scalar_get_b32(tmp, &slam); - CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); -} - - -static void run_endomorphism_tests(void) { - unsigned i; - static secp256k1_scalar s; - test_scalar_split(&secp256k1_scalar_zero); - test_scalar_split(&secp256k1_scalar_one); - secp256k1_scalar_negate(&s,&secp256k1_scalar_one); - test_scalar_split(&s); - test_scalar_split(&secp256k1_const_lambda); - secp256k1_scalar_add(&s, &secp256k1_const_lambda, &secp256k1_scalar_one); - test_scalar_split(&s); - - for (i = 0; i < 100U * COUNT; ++i) { - secp256k1_scalar full; - testutil_random_scalar_order_test(&full); - test_scalar_split(&full); - } - for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { - test_scalar_split(&scalars_near_split_bounds[i]); - } -} - -static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { - unsigned char pubkeyc[65]; - secp256k1_pubkey pubkey; - secp256k1_ge ge; - size_t pubkeyclen; - - for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { - /* Smaller sizes are tested exhaustively elsewhere. */ - int32_t i; - memcpy(&pubkeyc[1], input, 64); - SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen); - for (i = 0; i < 256; i++) { - /* Try all type bytes. */ - int xpass; - int ypass; - int ysign; - pubkeyc[0] = i; - /* What sign does this point have? */ - ysign = (input[63] & 1) + 2; - /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ - xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); - /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ - ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && - ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); - if (xpass || ypass) { - /* These cases must parse. */ - unsigned char pubkeyo[65]; - size_t outl; - memset(&pubkey, 0, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - outl = 65; - SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); - CHECK(outl == 33); - CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); - CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); - if (ypass) { - /* This test isn't always done because we decode with alternative signs, so the y won't match. */ - CHECK(pubkeyo[0] == ysign); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - secp256k1_pubkey_save(&pubkey, &ge); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - outl = 65; - SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); - CHECK(outl == 65); - CHECK(pubkeyo[0] == 4); - CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); - } - } else { - /* These cases must fail to parse. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - } - } - } -} - -static void run_ec_pubkey_parse_test(void) { -#define SECP256K1_EC_PARSE_TEST_NVALID (12) - const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { - { - /* Point with leading and trailing zeros in x and y serialization. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, - 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 - }, - { - /* Point with x equal to a 3rd root of unity.*/ - 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, - 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Point with largest x. (1/2) */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, - 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, - 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, - }, - { - /* Point with largest x. (2/2) */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, - 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, - 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, - }, - { - /* Point with smallest x. (1/2) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Point with smallest x. (2/2) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, - 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, - }, - { - /* Point with largest y. (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, - }, - { - /* Point with largest y. (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, - }, - { - /* Point with largest y. (3/3) */ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, - }, - { - /* Point with smallest y. (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Point with smallest y. (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Point with smallest y. (3/3) */ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - } - }; -#define SECP256K1_EC_PARSE_TEST_NXVALID (4) - const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { - { - /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, - }, - { - /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, - }, - { - /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, - }, - { - /* x on curve, y is from y^2 = x^3 + 8. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 - } - }; -#define SECP256K1_EC_PARSE_TEST_NINVALID (7) - const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { - { - /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ - 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, - 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Valid if x overflow ignored (x = 1 mod p). */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Valid if x overflow ignored (x = 1 mod p). */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, - 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, - 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, - }, - { - /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, - 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, - 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, - }, - { - /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, - 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, - 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, - }, - { - /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, - 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, - }, - { - /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, - 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 - } - }; - const unsigned char pubkeyc[66] = { - /* Serialization of G. */ - 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, - 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, - 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, - 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, - 0xB8, 0x00 - }; - unsigned char sout[65]; - unsigned char shortkey[2] = { 0 }; - secp256k1_ge ge; - secp256k1_pubkey pubkey; - size_t len; - int32_t i; - - /* Nothing should be reading this far into pubkeyc. */ - SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); - /* Zero length claimed, fail, zeroize, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - /* Length one claimed, fail, zeroize, no illegal arg error. */ - for (i = 0; i < 256 ; i++) { - memset(&pubkey, 0xfe, sizeof(pubkey)); - shortkey[0] = i; - SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - } - /* Length two claimed, fail, zeroize, no illegal arg error. */ - for (i = 0; i < 65536 ; i++) { - memset(&pubkey, 0xfe, sizeof(pubkey)); - shortkey[0] = i & 255; - shortkey[1] = i >> 8; - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - } - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65)); - /* NULL input string. Illegal arg and zeroize output. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65)); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); - /* Valid parse. */ - memset(&pubkey, 0, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); - CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); - SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); - SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); - SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); - CHECK(secp256k1_ge_eq_var(&ge, &secp256k1_ge_const_g)); - /* secp256k1_ec_pubkey_serialize illegal args. */ - len = 65; - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED)); - CHECK(len == 0); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED)); - len = 65; - SECP256K1_CHECKMEM_UNDEFINE(sout, 65); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED)); - SECP256K1_CHECKMEM_CHECK(sout, 65); - CHECK(len == 0); - len = 65; - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0)); - CHECK(len == 0); - len = 65; - SECP256K1_CHECKMEM_UNDEFINE(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - SECP256K1_CHECKMEM_CHECK(sout, 65); - CHECK(len == 65); - /* Multiple illegal args. Should still set arg error only once. */ - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65)); - /* Try a bunch of prefabbed points with all possible encodings. */ - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { - ec_pubkey_parse_pointtest(valid[i], 1, 1); - } - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { - ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); - } - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { - ec_pubkey_parse_pointtest(invalid[i], 0, 0); - } -} - -static void run_eckey_edge_case_test(void) { - const unsigned char orderc[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 - }; - const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; - unsigned char ctmp[33]; - unsigned char ctmp2[33]; - secp256k1_pubkey pubkey; - secp256k1_pubkey pubkey2; - secp256k1_pubkey pubkey_one; - secp256k1_pubkey pubkey_negone; - const secp256k1_pubkey *pubkeys[3]; - size_t len; - /* Group order is too large, reject. */ - CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, orderc) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* Maximum value is too large, reject. */ - memset(ctmp, 255, 32); - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* Zero is too small, reject. */ - memset(ctmp, 0, 32); - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* One must be accepted. */ - ctmp[31] = 0x01; - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - pubkey_one = pubkey; - /* Group order + 1 is too large, reject. */ - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x42; - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* -1 must be accepted. */ - ctmp[31] = 0x40; - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - pubkey_negone = pubkey; - /* Tweak of zero leaves the value unchanged. */ - memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 1); - CHECK(secp256k1_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); - memcpy(&pubkey2, &pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Multiply tweak of zero zeroizes the output. */ - CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp2) == 0); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing - seckey, the seckey is zeroized. */ - memcpy(ctmp, orderc, 32); - memset(ctmp2, 0, 32); - ctmp2[31] = 0x01; - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp2) == 1); - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); - memcpy(ctmp, orderc, 32); - CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); - /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing - tweak, the seckey is zeroized. */ - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, orderc) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, orderc) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing - tweak, the pubkey is zeroized. */ - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, orderc) == 0); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, orderc) == 0); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* If the resulting key in secp256k1_ec_seckey_tweak_add and - * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter - * case the pubkey is zeroized. */ - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - memset(ctmp2, 0, 32); - ctmp2[31] = 1; - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 0); - CHECK(secp256k1_memcmp_var(zeros, ctmp2, 32) == 0); - ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Tweak computation wraps and results in a key of 1. */ - ctmp2[31] = 2; - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 1); - CHECK(secp256k1_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); - ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); - ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, ctmp2) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Tweak mul * 2 = 1+1. */ - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); - ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Zeroize pubkey on parse error. */ - memset(&pubkey, 0, 32); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - memset(&pubkey2, 0, 32); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2)); - CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); - /* Plain argument errors. */ - CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_verify(CTX, NULL)); - memset(ctmp2, 0, 32); - ctmp2[31] = 4; - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL)); - memset(ctmp2, 0, 32); - ctmp2[31] = 4; - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL)); - memset(ctmp2, 0, 32); - CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2)); - CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL)); - memset(ctmp2, 0, 32); - ctmp2[31] = 1; - CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2)); - CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, NULL, ctmp)); - memset(&pubkey, 1, sizeof(pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* secp256k1_ec_pubkey_combine tests. */ - pubkeys[0] = &pubkey_one; - SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *)); - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0)); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1)); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - pubkeys[0] = &pubkey_negone; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - len = 33; - CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); - /* Result is infinity. */ - pubkeys[0] = &pubkey_one; - pubkeys[1] = &pubkey_negone; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* Passes through infinity but comes out one. */ - pubkeys[2] = &pubkey_one; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - len = 33; - CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); - /* Adds to two. */ - pubkeys[1] = &pubkey_one; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); - SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); -} - -static void run_eckey_negate_test(void) { - unsigned char seckey[32]; - unsigned char seckey_tmp[32]; - - testutil_random_scalar_order_b32(seckey); - memcpy(seckey_tmp, seckey, 32); - - /* Verify negation changes the key and changes it back */ - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) != 0); - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - - /* Check that privkey alias gives same result */ - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); - CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - - /* Negating all 0s fails */ - memset(seckey, 0, 32); - memset(seckey_tmp, 0, 32); - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); - /* Check that seckey is not modified */ - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - - /* Negating an overflowing seckey fails and the seckey is zeroed. In this - * test, the seckey has 16 random bytes to ensure that ec_seckey_negate - * doesn't just set seckey to a constant value in case of failure. */ - testutil_random_scalar_order_b32(seckey); - memset(seckey, 0xFF, 16); - memset(seckey_tmp, 0, 32); - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); -} - -static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { - secp256k1_scalar nonce; - do { - testutil_random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); -} - -static void test_ecdsa_sign_verify(void) { - secp256k1_gej pubj; - secp256k1_ge pub; - secp256k1_scalar one; - secp256k1_scalar msg, key; - secp256k1_scalar sigr, sigs; - int getrec; - int recid; - testutil_random_scalar_order_test(&msg); - testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); - getrec = testrand_bits(1); - /* The specific way in which this conditional is written sidesteps a potential bug in clang. - See the commit messages of the commit that introduced this comment for details. */ - if (getrec) { - random_sign(&sigr, &sigs, &key, &msg, &recid); - CHECK(recid >= 0 && recid < 4); - } else { - random_sign(&sigr, &sigs, &key, &msg, NULL); - } - CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); - secp256k1_scalar_set_int(&one, 1); - secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); -} - -static void run_ecdsa_sign_verify(void) { - int i; - for (i = 0; i < 10*COUNT; i++) { - test_ecdsa_sign_verify(); - } -} - -/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ -static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - (void)msg32; - (void)key32; - (void)algo16; - memcpy(nonce32, data, 32); - return (counter == 0); -} - -static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - /* Dummy nonce generator that has a fatal error on the first counter value. */ - if (counter == 0) { - return 0; - } - return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); -} - -static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ - if (counter < 3) { - memset(nonce32, counter==0 ? 0 : 255, 32); - if (counter == 2) { - nonce32[31]--; - } - return 1; - } - if (counter < 5) { - static const unsigned char order[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 - }; - memcpy(nonce32, order, 32); - if (counter == 4) { - nonce32[31]++; - } - return 1; - } - /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ - /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ - if (counter > 5) { - return 0; - } - return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); -} - -static int is_empty_signature(const secp256k1_ecdsa_signature *sig) { - static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; - return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; -} - -static void test_ecdsa_end_to_end(void) { - unsigned char extra[32] = {0x00}; - unsigned char privkey[32]; - unsigned char message[32]; - unsigned char privkey2[32]; - secp256k1_ecdsa_signature signature[6]; - secp256k1_scalar r, s; - unsigned char sig[74]; - size_t siglen = 74; - unsigned char pubkeyc[65]; - size_t pubkeyclen = 65; - secp256k1_pubkey pubkey; - secp256k1_pubkey pubkey_tmp; - unsigned char seckey[300]; - size_t seckeylen = 300; - - /* Generate a random key and message. */ - { - secp256k1_scalar msg, key; - testutil_random_scalar_order_test(&msg); - testutil_random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_scalar_get_b32(message, &msg); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); - - /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); - memset(&pubkey, 0, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); - - /* Verify negation changes the key and changes it back */ - memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); - CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); - CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); - CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); - - /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, testrand_bits(1) == 1)); - CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1); - CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0); - - /* Optionally tweak the keys using addition. */ - if (testrand_int(3) == 0) { - int ret1; - int ret2; - int ret3; - unsigned char rnd[32]; - unsigned char privkey_tmp[32]; - secp256k1_pubkey pubkey2; - testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); - ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); - CHECK(ret1 == ret2); - CHECK(ret2 == ret3); - if (ret1 == 0) { - return; - } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - } - - /* Optionally tweak the keys using multiplication. */ - if (testrand_int(3) == 0) { - int ret1; - int ret2; - int ret3; - unsigned char rnd[32]; - unsigned char privkey_tmp[32]; - secp256k1_pubkey pubkey2; - testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); - ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); - CHECK(ret1 == ret2); - CHECK(ret2 == ret3); - if (ret1 == 0) { - return; - } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); - CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - } - - /* Sign. */ - CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(CTX, &signature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(CTX, &signature[1], message, privkey, NULL, extra) == 1); - extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(CTX, &signature[2], message, privkey, NULL, extra) == 1); - extra[31] = 0; - extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(CTX, &signature[3], message, privkey, NULL, extra) == 1); - CHECK(secp256k1_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); - CHECK(secp256k1_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); - CHECK(secp256k1_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); - CHECK(secp256k1_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); - CHECK(secp256k1_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); - CHECK(secp256k1_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); - CHECK(secp256k1_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); - /* Verify. */ - CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[1], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[2], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[3], message, &pubkey) == 1); - /* Test lower-S form, malleate, verify and fail, test again, malleate again */ - CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[0])); - secp256k1_ecdsa_signature_load(CTX, &r, &s, &signature[0]); - secp256k1_scalar_negate(&s, &s); - secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 0); - CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); - secp256k1_scalar_negate(&s, &s); - secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); - CHECK(secp256k1_memcmp_var(&signature[5], &signature[0], 64) == 0); - - /* Serialize/parse DER and verify again */ - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); - memset(&signature[0], 0, sizeof(signature[0])); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); - /* Serialize/destroy/parse DER and verify again. */ - siglen = 74; - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); - sig[testrand_int(siglen)] += 1 + testrand_int(255); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 || - secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0); -} - -static void test_random_pubkeys(void) { - secp256k1_ge elem; - secp256k1_ge elem2; - unsigned char in[65]; - /* Generate some randomly sized pubkeys. */ - size_t len = testrand_bits(2) == 0 ? 65 : 33; - if (testrand_bits(2) == 0) { - len = testrand_bits(6); - } - if (len == 65) { - in[0] = testrand_bits(1) ? 4 : (testrand_bits(1) ? 6 : 7); - } else { - in[0] = testrand_bits(1) ? 2 : 3; - } - if (testrand_bits(3) == 0) { - in[0] = testrand_bits(8); - } - if (len > 1) { - testrand256(&in[1]); - } - if (len > 33) { - testrand256(&in[33]); - } - if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { - unsigned char out[65]; - unsigned char firstb; - int res; - size_t size = len; - firstb = in[0]; - /* If the pubkey can be parsed, it should round-trip... */ - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); - CHECK(size == len); - CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0); - /* ... except for the type of hybrid inputs. */ - if ((in[0] != 6) && (in[0] != 7)) { - CHECK(in[0] == out[0]); - } - size = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); - CHECK(size == 65); - CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); - CHECK(secp256k1_ge_eq_var(&elem2, &elem)); - /* Check that the X9.62 hybrid type is checked. */ - in[0] = testrand_bits(1) ? 6 : 7; - res = secp256k1_eckey_pubkey_parse(&elem2, in, size); - if (firstb == 2 || firstb == 3) { - if (in[0] == firstb + 4) { - CHECK(res); - } else { - CHECK(!res); - } - } - if (res) { - CHECK(secp256k1_ge_eq_var(&elem, &elem2)); - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); - CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); - } - } -} - -static void run_pubkey_comparison(void) { - unsigned char pk1_ser[33] = { - 0x02, - 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, - 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 - }; - const unsigned char pk2_ser[33] = { - 0x02, - 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, - 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c - }; - secp256k1_pubkey pk1; - secp256k1_pubkey pk2; - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); - - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0)); - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0)); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0); - { - secp256k1_pubkey pk_tmp; - memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */ - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0)); - { - int32_t ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); - CHECK(ecount == 2); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - } - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0)); - } - - /* Make pk2 the same as pk1 but with 3 rather than 2. Note that in - * an uncompressed encoding, these would have the opposite ordering */ - pk1_ser[0] = 3; - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); -} - -static void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) { - size_t i; - const secp256k1_pubkey *pk_test[5]; - - for (i = 0; i < n_pk; i++) { - pk_test[i] = &pk[pk_order[i]]; - } - secp256k1_ec_pubkey_sort(CTX, pk_test, n_pk); - for (i = 0; i < n_pk; i++) { - CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); - } -} - -static void permute(size_t *arr, size_t n) { - size_t i; - for (i = n - 1; i >= 1; i--) { - size_t tmp, j; - j = testrand_int(i + 1); - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } -} - -static void test_sort_api(void) { - secp256k1_pubkey pks[2]; - const secp256k1_pubkey *pks_ptr[2]; - - pks_ptr[0] = &pks[0]; - pks_ptr[1] = &pks[1]; - - testutil_random_pubkey_test(&pks[0]); - testutil_random_pubkey_test(&pks[1]); - - CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2)); - CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 0) == 1); - /* Test illegal public keys */ - memset(&pks[0], 0, sizeof(pks[0])); - CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1)); - memset(&pks[1], 0, sizeof(pks[1])); - { - int32_t ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); - CHECK(ecount == 2); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - } -} - -static void test_sort(void) { - secp256k1_pubkey pk[5]; - unsigned char pk_ser[5][33] = { - { 0x02, 0x08 }, - { 0x02, 0x0b }, - { 0x02, 0x0c }, - { 0x03, 0x05 }, - { 0x03, 0x0a }, - }; - int i; - size_t pk_order[5] = { 0, 1, 2, 3, 4 }; - - for (i = 0; i < 5; i++) { - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); - } - - permute(pk_order, 1); - test_sort_helper(pk, pk_order, 1); - permute(pk_order, 2); - test_sort_helper(pk, pk_order, 2); - permute(pk_order, 3); - test_sort_helper(pk, pk_order, 3); - for (i = 0; i < COUNT; i++) { - permute(pk_order, 4); - test_sort_helper(pk, pk_order, 4); - } - for (i = 0; i < COUNT; i++) { - permute(pk_order, 5); - test_sort_helper(pk, pk_order, 5); - } - /* Check that sorting also works for random pubkeys */ - for (i = 0; i < COUNT; i++) { - int j; - const secp256k1_pubkey *pk_ptr[5]; - for (j = 0; j < 5; j++) { - testutil_random_pubkey_test(&pk[j]); - pk_ptr[j] = &pk[j]; - } - secp256k1_ec_pubkey_sort(CTX, pk_ptr, 5); - for (j = 1; j < 5; j++) { - CHECK(secp256k1_ec_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], CTX) <= 0); - } - } -} - -/* Test vectors from BIP-MuSig2 */ -static void test_sort_vectors(void) { - enum { N_PUBKEYS = 6 }; - unsigned char pk_ser[N_PUBKEYS][33] = { - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, - { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, - 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, - 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, - 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, - 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, - { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, - 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, - 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } - }; - secp256k1_pubkey pubkeys[N_PUBKEYS]; - secp256k1_pubkey *sorted[N_PUBKEYS]; - const secp256k1_pubkey *pks_ptr[N_PUBKEYS]; - int i; - - sorted[0] = &pubkeys[3]; - sorted[1] = &pubkeys[0]; - sorted[2] = &pubkeys[0]; - sorted[3] = &pubkeys[4]; - sorted[4] = &pubkeys[1]; - sorted[5] = &pubkeys[2]; - - for (i = 0; i < N_PUBKEYS; i++) { - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); - pks_ptr[i] = &pubkeys[i]; - } - CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, N_PUBKEYS) == 1); - for (i = 0; i < N_PUBKEYS; i++) { - CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0); - } -} - -static void run_pubkey_sort(void) { - test_sort_api(); - test_sort(); - test_sort_vectors(); -} - - -static void run_random_pubkeys(void) { - int i; - for (i = 0; i < 10*COUNT; i++) { - test_random_pubkeys(); - } -} - -static void run_ecdsa_end_to_end(void) { - int i; - for (i = 0; i < 64*COUNT; i++) { - test_ecdsa_end_to_end(); - } -} - -static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { - static const unsigned char zeroes[32] = {0}; - - int ret = 0; - - secp256k1_ecdsa_signature sig_der; - unsigned char roundtrip_der[2048]; - unsigned char compact_der[64]; - size_t len_der = 2048; - int parsed_der = 0, valid_der = 0, roundtrips_der = 0; - - secp256k1_ecdsa_signature sig_der_lax; - unsigned char roundtrip_der_lax[2048]; - unsigned char compact_der_lax[64]; - size_t len_der_lax = 2048; - int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; - - parsed_der = secp256k1_ecdsa_signature_parse_der(CTX, &sig_der, sig, siglen); - if (parsed_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der, &sig_der)) << 0; - valid_der = (secp256k1_memcmp_var(compact_der, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der + 32, zeroes, 32) != 0); - } - if (valid_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der, &len_der, &sig_der)) << 1; - roundtrips_der = (len_der == siglen) && secp256k1_memcmp_var(roundtrip_der, sig, siglen) == 0; - } - - parsed_der_lax = ecdsa_signature_parse_der_lax(CTX, &sig_der_lax, sig, siglen); - if (parsed_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der_lax, &sig_der_lax)) << 10; - valid_der_lax = (secp256k1_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); - } - if (valid_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; - roundtrips_der_lax = (len_der_lax == siglen) && secp256k1_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; - } - - if (certainly_der) { - ret |= (!parsed_der) << 2; - } - if (certainly_not_der) { - ret |= (parsed_der) << 17; - } - if (valid_der) { - ret |= (!roundtrips_der) << 3; - } - - if (valid_der) { - ret |= (!roundtrips_der_lax) << 12; - ret |= (len_der != len_der_lax) << 13; - ret |= ((len_der != len_der_lax) || (secp256k1_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; - } - ret |= (roundtrips_der != roundtrips_der_lax) << 15; - if (parsed_der) { - ret |= (!parsed_der_lax) << 16; - } - - return ret; -} - -static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { - size_t i; - for (i = 0; i < ptrlen; i++) { - int shift = ptrlen - 1 - i; - if (shift >= 4) { - ptr[i] = 0; - } else { - ptr[i] = (val >> shift) & 0xFF; - } - } -} - -static void damage_array(unsigned char *sig, size_t *len) { - int pos; - int action = testrand_bits(3); - if (action < 1 && *len > 3) { - /* Delete a byte. */ - pos = testrand_int(*len); - memmove(sig + pos, sig + pos + 1, *len - pos - 1); - (*len)--; - return; - } else if (action < 2 && *len < 2048) { - /* Insert a byte. */ - pos = testrand_int(1 + *len); - memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = testrand_bits(8); - (*len)++; - return; - } else if (action < 4) { - /* Modify a byte. */ - sig[testrand_int(*len)] += 1 + testrand_int(255); - return; - } else { /* action < 8 */ - /* Modify a bit. */ - sig[testrand_int(*len)] ^= 1 << testrand_bits(3); - return; - } -} - -static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { - int der; - int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; - size_t tlen, elen, glen; - int indet; - int n; - - *len = 0; - der = testrand_bits(2) == 0; - *certainly_der = der; - *certainly_not_der = 0; - indet = der ? 0 : testrand_int(10) == 0; - - for (n = 0; n < 2; n++) { - /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (testrand_bits(3) != 0); - /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? testrand_int(33) : 32 + testrand_int(200) * testrand_bits(3) / 8; - CHECK(nlen[n] <= 232); - /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : testrand_bits(1)); - /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + testrand_bits(7) : 1 + testrand_int(127)); - /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? testrand_int(3) : testrand_int(300 - nlen[n]) * testrand_bits(3) / 8); - if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { - *certainly_not_der = 1; - } - CHECK(nlen[n] + nzlen[n] <= 300); - /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ - nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); - if (!der) { - /* nlenlen[n] max 127 bytes */ - int add = testrand_int(127 - nlenlen[n]) * testrand_bits(4) * testrand_bits(4) / 256; - nlenlen[n] += add; - if (add != 0) { - *certainly_not_der = 1; - } - } - CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); - } - - /* The total length of the data to go, so far */ - tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; - CHECK(tlen <= 856); - - /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : testrand_int(980 - tlen) * testrand_bits(3) / 8; - if (elen != 0) { - *certainly_not_der = 1; - } - tlen += elen; - CHECK(tlen <= 980); - - /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : testrand_int(990 - tlen) * testrand_bits(3) / 8; - if (glen != 0) { - *certainly_not_der = 1; - } - CHECK(tlen + glen <= 990); - - /* Write the tuple header. */ - sig[(*len)++] = 0x30; - if (indet) { - /* Indeterminate length */ - sig[(*len)++] = 0x80; - *certainly_not_der = 1; - } else { - int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); - if (!der) { - int add = testrand_int(127 - tlenlen) * testrand_bits(4) * testrand_bits(4) / 256; - tlenlen += add; - if (add != 0) { - *certainly_not_der = 1; - } - } - if (tlenlen == 0) { - /* Short length notation */ - sig[(*len)++] = tlen; - } else { - /* Long length notation */ - sig[(*len)++] = 128 + tlenlen; - assign_big_endian(sig + *len, tlenlen, tlen); - *len += tlenlen; - } - tlen += tlenlen; - } - tlen += 2; - CHECK(tlen + glen <= 1119); - - for (n = 0; n < 2; n++) { - /* Write the integer header. */ - sig[(*len)++] = 0x02; - if (nlenlen[n] == 0) { - /* Short length notation */ - sig[(*len)++] = nlen[n] + nzlen[n]; - } else { - /* Long length notation. */ - sig[(*len)++] = 128 + nlenlen[n]; - assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); - *len += nlenlen[n]; - } - /* Write zero padding */ - while (nzlen[n] > 0) { - sig[(*len)++] = 0x00; - nzlen[n]--; - } - if (nlen[n] == 32 && !nlow[n]) { - /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ - int i; - for (i = 0; i < 16; i++) { - sig[(*len)++] = 0xFF; - } - nlen[n] -= 16; - } - /* Write first byte of number */ - if (nlen[n] > 0) { - sig[(*len)++] = nhbyte[n]; - nlen[n]--; - } - /* Generate remaining random bytes of number */ - testrand_bytes_test(sig + *len, nlen[n]); - *len += nlen[n]; - nlen[n] = 0; - } - - /* Generate random garbage inside tuple. */ - testrand_bytes_test(sig + *len, elen); - *len += elen; - - /* Generate end-of-contents bytes. */ - if (indet) { - sig[(*len)++] = 0; - sig[(*len)++] = 0; - tlen += 2; - } - CHECK(tlen + glen <= 1121); - - /* Generate random garbage outside tuple. */ - testrand_bytes_test(sig + *len, glen); - *len += glen; - tlen += glen; - CHECK(tlen <= 1121); - CHECK(tlen == *len); -} - -static void run_ecdsa_der_parse(void) { - int i,j; - for (i = 0; i < 200 * COUNT; i++) { - unsigned char buffer[2048]; - size_t buflen = 0; - int certainly_der = 0; - int certainly_not_der = 0; - random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); - CHECK(buflen <= 2048); - for (j = 0; j < 16; j++) { - int ret = 0; - if (j > 0) { - damage_array(buffer, &buflen); - /* We don't know anything anymore about the DERness of the result */ - certainly_der = 0; - certainly_not_der = 0; - } - ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); - if (ret != 0) { - size_t k; - fprintf(stderr, "Failure %x on ", ret); - for (k = 0; k < buflen; k++) { - fprintf(stderr, "%02x ", buffer[k]); - } - fprintf(stderr, "\n"); - } - CHECK(ret == 0); - } - } -} - -/* Tests several edge cases. */ -static void test_ecdsa_edge_cases(void) { - int t; - secp256k1_ecdsa_signature sig; - - /* Test the case where ECDSA recomputes a point that is infinity. */ - { - secp256k1_gej keyj; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_negate(&ss, &ss); - secp256k1_scalar_inverse(&ss, &ss); - secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); - secp256k1_ge_set_gej(&key, &keyj); - msg = ss; - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with r of zero fails. */ - { - const unsigned char pubkey_mods_zero[33] = { - 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, - 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, - 0x41 - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 0); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); - CHECK(secp256k1_ecdsa_sig_verify( &sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with s of zero fails. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01 - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 0); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 1); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with message 0 passes. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02 - }; - const unsigned char pubkey2[33] = { - 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, - 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, - 0x43 - }; - secp256k1_ge key; - secp256k1_ge key2; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 2); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 2); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_set_int(&ss, 1); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); - } - - /* Verify signature with message 1 passes. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, - 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, - 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, - 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, - 0x25 - }; - const unsigned char pubkey2[33] = { - 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, - 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, - 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, - 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, - 0x62 - }; - const unsigned char csr[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb - }; - secp256k1_ge key; - secp256k1_ge key2; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 1); - secp256k1_scalar_set_b32(&sr, csr, NULL); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_set_int(&ss, 2); - secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); - } - - /* Verify signature with message -1 passes. */ - { - const unsigned char pubkey[33] = { - 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, - 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, - 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, - 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, - 0xf1 - }; - const unsigned char csr[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 1); - secp256k1_scalar_negate(&msg, &msg); - secp256k1_scalar_set_b32(&sr, csr, NULL); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - secp256k1_scalar_set_int(&ss, 3); - secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - } - - /* Signature where s would be zero. */ - { - secp256k1_pubkey pubkey; - size_t siglen; - unsigned char signature[72]; - static const unsigned char nonce[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - static const unsigned char nonce2[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 - }; - const unsigned char key[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - unsigned char msg[32] = { - 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, - 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, - 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, - 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, - }; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); - msg[31] = 0xaa; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL)); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); - /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey)); - siglen = 72; - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); - siglen = 10; - /* Too little room for a signature does not fail via ARGCHECK. */ - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL)); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); - memset(signature, 255, 64); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); - } - - /* Nonce function corner cases. */ - for (t = 0; t < 2; t++) { - static const unsigned char zero[32] = {0x00}; - int i; - unsigned char key[32]; - unsigned char msg[32]; - secp256k1_ecdsa_signature sig2; - secp256k1_scalar sr[512], ss; - const unsigned char *extra; - extra = t == 0 ? NULL : zero; - memset(msg, 0, 32); - msg[31] = 1; - /* High key results in signature failure. */ - memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* Zero key results in signature failure. */ - memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* Nonce function failure results in signature failure. */ - key[31] = 1; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* The retry loop successfully makes its way to the first good value. */ - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1); - CHECK(!is_empty_signature(&sig)); - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); - /* The default nonce function is deterministic. */ - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); - /* The default nonce function changes output with different messages. */ - for(i = 0; i < 256; i++) { - int j; - msg[0] = i; - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); - for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); - } - } - msg[0] = 0; - msg[31] = 2; - /* The default nonce function changes output with different keys. */ - for(i = 256; i < 512; i++) { - int j; - key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); - for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); - } - } - key[0] = 0; - } - - { - /* Check that optional nonce arguments do not have equivalent effect. */ - const unsigned char zeros[32] = {0}; - unsigned char nonce[32]; - unsigned char nonce2[32]; - unsigned char nonce3[32]; - unsigned char nonce4[32]; - SECP256K1_CHECKMEM_UNDEFINE(nonce,32); - SECP256K1_CHECKMEM_UNDEFINE(nonce2,32); - SECP256K1_CHECKMEM_UNDEFINE(nonce3,32); - SECP256K1_CHECKMEM_UNDEFINE(nonce4,32); - CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); - SECP256K1_CHECKMEM_CHECK(nonce,32); - CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); - SECP256K1_CHECKMEM_CHECK(nonce2,32); - CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); - SECP256K1_CHECKMEM_CHECK(nonce3,32); - CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); - SECP256K1_CHECKMEM_CHECK(nonce4,32); - CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); - CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0); - CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0); - CHECK(secp256k1_memcmp_var(nonce2, nonce3, 32) != 0); - CHECK(secp256k1_memcmp_var(nonce2, nonce4, 32) != 0); - CHECK(secp256k1_memcmp_var(nonce3, nonce4, 32) != 0); - } - - - /* Privkey export where pubkey is the point at infinity. */ - { - unsigned char privkey[300]; - unsigned char seckey[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, - }; - size_t outlen = 300; - CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0)); - outlen = 300; - CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1)); - } -} - -static void run_ecdsa_edge_cases(void) { - test_ecdsa_edge_cases(); -} - -/** Wycheproof tests - -The tests check for known attacks (range checks in (r,s), arithmetic errors, malleability). -*/ -static void test_ecdsa_wycheproof(void) { - #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h" - - int t; - for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { - secp256k1_ecdsa_signature signature; - secp256k1_sha256 hasher; - secp256k1_pubkey pubkey; - const unsigned char *msg, *sig, *pk; - unsigned char out[32] = {0}; - int actual_verify = 0; - - memset(&pubkey, 0, sizeof(pubkey)); - pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset]; - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1); - - secp256k1_sha256_initialize(&hasher); - msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; - secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len); - secp256k1_sha256_finalize(&hasher, out); - - sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset]; - if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) { - actual_verify = secp256k1_ecdsa_verify(CTX, (const secp256k1_ecdsa_signature *)&signature, out, &pubkey); - } - CHECK(testvectors[t].expected_verify == actual_verify); - } -} - -/* Tests cases from Wycheproof test suite. */ -static void run_ecdsa_wycheproof(void) { - test_ecdsa_wycheproof(); -} - -#ifdef ENABLE_MODULE_ECDH -# include "modules/ecdh/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "modules/recovery/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -# include "modules/extrakeys/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -# include "modules/schnorrsig/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -# include "modules/musig/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT -# include "modules/ellswift/tests_impl.h" -#endif - -static void run_secp256k1_memczero_test(void) { - unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; - unsigned char buf2[sizeof(buf1)]; - - /* secp256k1_memczero(..., ..., 0) is a noop. */ - memcpy(buf2, buf1, sizeof(buf1)); - secp256k1_memczero(buf1, sizeof(buf1), 0); - CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); - - /* secp256k1_memczero(..., ..., 1) zeros the buffer. */ - memset(buf2, 0, sizeof(buf2)); - secp256k1_memczero(buf1, sizeof(buf1) , 1); - CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); -} - - -static void run_secp256k1_is_zero_array_test(void) { - unsigned char buf1[3] = {0, 1}; - unsigned char buf2[3] = {1, 0}; - - CHECK(secp256k1_is_zero_array(buf1, 0) == 1); - CHECK(secp256k1_is_zero_array(buf1, 1) == 1); - CHECK(secp256k1_is_zero_array(buf1, 2) == 0); - CHECK(secp256k1_is_zero_array(buf2, 1) == 0); - CHECK(secp256k1_is_zero_array(buf2, 2) == 0); -} - -static void run_secp256k1_byteorder_tests(void) { - { - const uint32_t x = 0xFF03AB45; - const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; - unsigned char buf[4]; - uint32_t x_; - - secp256k1_write_be32(buf, x); - CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); - - x_ = secp256k1_read_be32(buf); - CHECK(x == x_); - } - - { - const uint64_t x = 0xCAFE0123BEEF4567; - const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67}; - unsigned char buf[8]; - uint64_t x_; - - secp256k1_write_be64(buf, x); - CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); - - x_ = secp256k1_read_be64(buf); - CHECK(x == x_); - } -} - -static void int_cmov_test(void) { - int r = INT_MAX; - int a = 0; - - secp256k1_int_cmov(&r, &a, 0); - CHECK(r == INT_MAX); - - r = 0; a = INT_MAX; - secp256k1_int_cmov(&r, &a, 1); - CHECK(r == INT_MAX); - - a = 0; - secp256k1_int_cmov(&r, &a, 1); - CHECK(r == 0); - - a = 1; - secp256k1_int_cmov(&r, &a, 1); - CHECK(r == 1); - - r = 1; a = 0; - secp256k1_int_cmov(&r, &a, 0); - CHECK(r == 1); - -} - -static void fe_cmov_test(void) { - static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - static const secp256k1_fe max = SECP256K1_FE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - secp256k1_fe r = max; - secp256k1_fe a = zero; - - secp256k1_fe_cmov(&r, &a, 0); - CHECK(fe_identical(&r, &max)); - - r = zero; a = max; - secp256k1_fe_cmov(&r, &a, 1); - CHECK(fe_identical(&r, &max)); - - a = zero; - secp256k1_fe_cmov(&r, &a, 1); - CHECK(fe_identical(&r, &zero)); - - a = one; - secp256k1_fe_cmov(&r, &a, 1); - CHECK(fe_identical(&r, &one)); - - r = one; a = zero; - secp256k1_fe_cmov(&r, &a, 0); - CHECK(fe_identical(&r, &one)); -} - -static void fe_storage_cmov_test(void) { - static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - secp256k1_fe_storage r = max; - secp256k1_fe_storage a = zero; - - secp256k1_fe_storage_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - r = zero; a = max; - secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - a = zero; - secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); - - a = one; - secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); - - r = one; a = zero; - secp256k1_fe_storage_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); -} - -static void scalar_cmov_test(void) { - static const secp256k1_scalar max = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, - 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL - ); - secp256k1_scalar r = max; - secp256k1_scalar a = secp256k1_scalar_zero; - - secp256k1_scalar_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - r = secp256k1_scalar_zero; a = max; - secp256k1_scalar_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - a = secp256k1_scalar_zero; - secp256k1_scalar_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_zero, sizeof(r)) == 0); - - a = secp256k1_scalar_one; - secp256k1_scalar_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); - - r = secp256k1_scalar_one; a = secp256k1_scalar_zero; - secp256k1_scalar_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); -} - -static void ge_storage_cmov_test(void) { - static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); - static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - secp256k1_ge_storage r = max; - secp256k1_ge_storage a = zero; - - secp256k1_ge_storage_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - r = zero; a = max; - secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - - a = zero; - secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); - - a = one; - secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); - - r = one; a = zero; - secp256k1_ge_storage_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); -} - -static void run_cmov_tests(void) { - int_cmov_test(); - fe_cmov_test(); - fe_storage_cmov_test(); - scalar_cmov_test(); - ge_storage_cmov_test(); -} - -int main(int argc, char **argv) { - /* Disable buffering for stdout to improve reliability of getting - * diagnostic information. Happens right at the start of main because - * setbuf must be used before any other operation on the stream. */ - setbuf(stdout, NULL); - /* Also disable buffering for stderr because it's not guaranteed that it's - * unbuffered on all systems. */ - setbuf(stderr, NULL); - - /* find iteration count */ - if (argc > 1) { - COUNT = strtol(argv[1], NULL, 0); - } else { - const char* env = getenv("SECP256K1_TEST_ITERS"); - if (env && strlen(env) > 0) { - COUNT = strtol(env, NULL, 0); - } - } - if (COUNT <= 0) { - fputs("An iteration count of 0 or less is not allowed.\n", stderr); - return EXIT_FAILURE; - } - printf("test count = %i\n", COUNT); - - /* run test RNG tests (must run before we really initialize the test RNG) */ - run_xoshiro256pp_tests(); - - /* find random seed */ - testrand_init(argc > 2 ? argv[2] : NULL); - - /*** Setup test environment ***/ - - /* Create a global context available to all tests */ - CTX = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - /* Randomize the context only with probability 15/16 - to make sure we test without context randomization from time to time. - TODO Reconsider this when recalibrating the tests. */ - if (testrand_bits(4)) { - unsigned char rand32[32]; - testrand256(rand32); - CHECK(secp256k1_context_randomize(CTX, rand32)); - } - /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions - that write to the context. The API does not support cloning the static context, so we use - memcpy instead. The user is not supposed to copy a context but we should still ensure that - the API functions handle copies of the static context gracefully. */ - STATIC_CTX = malloc(sizeof(*secp256k1_context_static)); - CHECK(STATIC_CTX != NULL); - memcpy(STATIC_CTX, secp256k1_context_static, sizeof(secp256k1_context)); - CHECK(!secp256k1_context_is_proper(STATIC_CTX)); - - /*** Run actual tests ***/ - - /* selftest tests */ - run_selftest_tests(); - - /* context tests */ - run_proper_context_tests(0); run_proper_context_tests(1); - run_static_context_tests(0); run_static_context_tests(1); - run_deprecated_context_flags_test(); - - /* scratch tests */ - run_scratch_tests(); - - /* integer arithmetic tests */ -#ifdef SECP256K1_WIDEMUL_INT128 - run_int128_tests(); -#endif - run_ctz_tests(); - run_modinv_tests(); - run_inverse_tests(); - - /* sorting tests */ - run_hsort_tests(); - - /* hash tests */ - run_sha256_known_output_tests(); - run_sha256_counter_tests(); - run_hmac_sha256_tests(); - run_rfc6979_hmac_sha256_tests(); - run_tagged_sha256_tests(); - - /* scalar tests */ - run_scalar_tests(); - - /* field tests */ - run_field_half(); - run_field_misc(); - run_field_convert(); - run_field_be32_overflow(); - run_fe_mul(); - run_sqr(); - run_sqrt(); - - /* group tests */ - run_ge(); - run_gej(); - run_group_decompress(); - - /* ecmult tests */ - run_ecmult_pre_g(); - run_wnaf(); - run_point_times_order(); - run_ecmult_near_split_bound(); - run_ecmult_chain(); - run_ecmult_constants(); - run_ecmult_gen_blind(); - run_ecmult_const_tests(); - run_ecmult_multi_tests(); - run_ec_combine(); - - /* endomorphism tests */ - run_endomorphism_tests(); - - /* EC point parser test */ - run_ec_pubkey_parse_test(); - - /* EC key edge cases */ - run_eckey_edge_case_test(); - - /* EC key arithmetic test */ - run_eckey_negate_test(); - -#ifdef ENABLE_MODULE_ECDH - /* ecdh tests */ - run_ecdh_tests(); -#endif - - /* ecdsa tests */ - run_ec_illegal_argument_tests(); - run_pubkey_comparison(); - run_pubkey_sort(); - run_random_pubkeys(); - run_ecdsa_der_parse(); - run_ecdsa_sign_verify(); - run_ecdsa_end_to_end(); - run_ecdsa_edge_cases(); - run_ecdsa_wycheproof(); - -#ifdef ENABLE_MODULE_RECOVERY - /* ECDSA pubkey recovery tests */ - run_recovery_tests(); -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS - run_extrakeys_tests(); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - run_schnorrsig_tests(); -#endif - -#ifdef ENABLE_MODULE_MUSIG - run_musig_tests(); -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT - run_ellswift_tests(); -#endif - - /* util tests */ - run_secp256k1_memczero_test(); - run_secp256k1_is_zero_array_test(); - run_secp256k1_byteorder_tests(); - - run_cmov_tests(); - - /*** Tear down test environment ***/ - free(STATIC_CTX); - secp256k1_context_destroy(CTX); - - testrand_finish(); - - printf("no problems found\n"); - return 0; -} diff --git a/external/secp256k1/src/tests_exhaustive.c b/external/secp256k1/src/tests_exhaustive.c deleted file mode 100644 index 6efa88982e..0000000000 --- a/external/secp256k1/src/tests_exhaustive.c +++ /dev/null @@ -1,466 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include -#include -#include - -#ifndef EXHAUSTIVE_TEST_ORDER -/* see group_impl.h for allowable values */ -#define EXHAUSTIVE_TEST_ORDER 13 -#endif - -/* These values of B are all values in [1, 8] that result in a curve with even order. */ -#define EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER (SECP256K1_B == 1 || SECP256K1_B == 6 || SECP256K1_B == 8) - -#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS - #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.") - #undef USE_EXTERNAL_DEFAULT_CALLBACKS -#endif -#include "secp256k1.c" - -#include "../include/secp256k1.h" -#include "assumptions.h" -#include "group.h" -#include "testrand_impl.h" -#include "ecmult_compute_table_impl.h" -#include "ecmult_gen_compute_table_impl.h" -#include "testutil.h" -#include "util.h" - -static int count = 2; - -static uint32_t num_cores = 1; -static uint32_t this_core = 0; - -SECP256K1_INLINE static int skip_section(uint64_t* iter) { - if (num_cores == 1) return 0; - *iter += 0xe7037ed1a0b428dbULL; - return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; -} - -static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, - const unsigned char *key32, const unsigned char *algo16, - void *data, unsigned int attempt) { - secp256k1_scalar s; - int *idata = data; - (void)msg32; - (void)key32; - (void)algo16; - /* Some nonces cannot be used because they'd cause s and/or r to be zero. - * The signing function has retry logic here that just re-calls the nonce - * function with an increased `attempt`. So if attempt > 0 this means we - * need to change the nonce to avoid an infinite loop. */ - if (attempt > 0) { - *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; - } - secp256k1_scalar_set_int(&s, *idata); - secp256k1_scalar_get_b32(nonce32, &s); - return 1; -} - -static void test_exhaustive_endomorphism(const secp256k1_ge *group) { - int i; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_ge res; - secp256k1_ge_mul_lambda(&res, &group[i]); - CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res)); - } -} - -static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { - int i, j; - uint64_t iter = 0; - - /* Sanity-check (and check infinity functions) */ - CHECK(secp256k1_ge_is_infinity(&group[0])); - CHECK(secp256k1_gej_is_infinity(&groupj[0])); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - CHECK(!secp256k1_ge_is_infinity(&group[i])); - CHECK(!secp256k1_gej_is_infinity(&groupj[i])); - } - - /* Check all addition formulae */ - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - secp256k1_fe fe_inv; - if (skip_section(&iter)) continue; - secp256k1_fe_inv(&fe_inv, &groupj[j].z); - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_ge zless_gej; - secp256k1_gej tmp; - /* add_var */ - secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); - /* add_ge */ - if (j > 0) { - secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); - } - /* add_ge_var */ - secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); - /* add_zinv_var */ - zless_gej.infinity = groupj[j].infinity; - zless_gej.x = groupj[j].x; - zless_gej.y = groupj[j].y; - secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); - } - } - - /* Check doubling */ - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_gej tmp; - secp256k1_gej_double(&tmp, &groupj[i]); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); - secp256k1_gej_double_var(&tmp, &groupj[i], NULL); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); - } - - /* Check negation */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_ge tmp; - secp256k1_gej tmpj; - secp256k1_ge_neg(&tmp, &group[i]); - CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i])); - secp256k1_gej_neg(&tmpj, &groupj[i]); - CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i])); - } -} - -static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { - int i, j, r_log; - uint64_t iter = 0; - for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - if (skip_section(&iter)) continue; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_gej tmp; - secp256k1_scalar na, ng; - secp256k1_scalar_set_int(&na, i); - secp256k1_scalar_set_int(&ng, j); - - secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER])); - } - } - } - - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - int ret; - secp256k1_gej tmp; - secp256k1_fe xn, xd, tmpf; - secp256k1_scalar ng; - - if (skip_section(&iter)) continue; - - secp256k1_scalar_set_int(&ng, j); - - /* Test secp256k1_ecmult_const. */ - secp256k1_ecmult_const(&tmp, &group[i], &ng); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER])); - - if (i != 0 && j != 0) { - /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ - ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); - CHECK(ret); - CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); - - /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ - testutil_random_fe_non_zero(&xd); - secp256k1_fe_mul(&xn, &xd, &group[i].x); - ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); - CHECK(ret); - CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); - } - } - } -} - -typedef struct { - secp256k1_scalar sc[2]; - secp256k1_ge pt[2]; -} ecmult_multi_data; - -static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { - ecmult_multi_data *data = (ecmult_multi_data*) cbdata; - *sc = data->sc[idx]; - *pt = data->pt[idx]; - return 1; -} - -static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { - int i, j, k, x, y; - uint64_t iter = 0; - secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { - if (skip_section(&iter)) continue; - for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { - secp256k1_gej tmp; - secp256k1_scalar g_sc; - ecmult_multi_data data; - - secp256k1_scalar_set_int(&data.sc[0], i); - secp256k1_scalar_set_int(&data.sc[1], j); - secp256k1_scalar_set_int(&g_sc, k); - data.pt[0] = group[x]; - data.pt[1] = group[y]; - - secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); - CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER])); - } - } - } - } - } - secp256k1_scratch_destroy(&ctx->error_callback, scratch); -} - -static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { - secp256k1_fe x; - unsigned char x_bin[32]; - k %= EXHAUSTIVE_TEST_ORDER; - x = group[k].x; - secp256k1_fe_normalize(&x); - secp256k1_fe_get_b32(x_bin, &x); - secp256k1_scalar_set_b32(r, x_bin, overflow); -} - -static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { - int s, r, msg, key; - uint64_t iter = 0; - for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { - for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { - for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { - for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int k, should_verify; - unsigned char msg32[32]; - - if (skip_section(&iter)) continue; - - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k, NULL); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); - - /* Verify by calling verify */ - secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - secp256k1_scalar_get_b32(msg32, &msg_s); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } - } - } - } -} - -static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { - int i, j, k; - uint64_t iter = 0; - - /* Loop */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ - for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ - if (skip_section(&iter)) continue; - for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ - const int starting_k = k; - int ret; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); - - ret = secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); - CHECK(ret == 1); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k, NULL); - CHECK(r == expected_r); - CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); - - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } - } - } - - /* We would like to verify zero-knowledge here by counting how often every - * possible (s, r) tuple appears, but because the group order is larger - * than the field order, when coercing the x-values to scalar values, some - * appear more often than others, so we are actually not zero-knowledge. - * (This effect also appears in the real code, but the difference is on the - * order of 1/2^128th the field order, so the deviation is not useful to a - * computationally bounded attacker.) - */ -} - -#ifdef ENABLE_MODULE_RECOVERY -#include "modules/recovery/tests_exhaustive_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -#include "modules/extrakeys/tests_exhaustive_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "modules/schnorrsig/tests_exhaustive_impl.h" -#endif - -#ifdef ENABLE_MODULE_ELLSWIFT -#include "modules/ellswift/tests_exhaustive_impl.h" -#endif - -int main(int argc, char** argv) { - int i; - secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; - secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; - unsigned char rand32[32]; - secp256k1_context *ctx; - - /* Disable buffering for stdout to improve reliability of getting - * diagnostic information. Happens right at the start of main because - * setbuf must be used before any other operation on the stream. */ - setbuf(stdout, NULL); - /* Also disable buffering for stderr because it's not guaranteed that it's - * unbuffered on all systems. */ - setbuf(stderr, NULL); - - printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); - - /* find iteration count */ - if (argc > 1) { - count = strtol(argv[1], NULL, 0); - } - printf("test count = %i\n", count); - - /* find random seed */ - testrand_init(argc > 2 ? argv[2] : NULL); - - /* set up split processing */ - if (argc > 4) { - num_cores = strtol(argv[3], NULL, 0); - this_core = strtol(argv[4], NULL, 0); - if (num_cores < 1 || this_core >= num_cores) { - fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); - return 1; - } - printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); - } - - /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */ - secp256k1_ecmult_gen_compute_table(&secp256k1_ecmult_gen_prec_table[0][0], &secp256k1_ge_const_g, COMB_BLOCKS, COMB_TEETH, COMB_SPACING); - secp256k1_ecmult_compute_two_tables(secp256k1_pre_g, secp256k1_pre_g_128, WINDOW_G, &secp256k1_ge_const_g); - - while (count--) { - /* Build context */ - ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - testrand256(rand32); - CHECK(secp256k1_context_randomize(ctx, rand32)); - - /* Generate the entire group */ - secp256k1_gej_set_infinity(&groupj[0]); - secp256k1_ge_set_gej(&group[0], &groupj[0]); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); - secp256k1_ge_set_gej(&group[i], &groupj[i]); - if (count != 0) { - /* Set a different random z-value for each Jacobian point, except z=1 - is used in the last iteration. */ - secp256k1_fe z; - testutil_random_fe(&z); - secp256k1_gej_rescale(&groupj[i], &z); - } - - /* Verify against ecmult_gen */ - { - secp256k1_scalar scalar_i; - secp256k1_gej generatedj; - secp256k1_ge generated; - - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); - - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal(&generated.y, &group[i].y)); - } - } - - /* Run the tests */ - test_exhaustive_endomorphism(group); - test_exhaustive_addition(group, groupj); - test_exhaustive_ecmult(group, groupj); - test_exhaustive_ecmult_multi(ctx, group); - test_exhaustive_sign(ctx, group); - test_exhaustive_verify(ctx, group); - -#ifdef ENABLE_MODULE_RECOVERY - test_exhaustive_recovery(ctx, group); -#endif -#ifdef ENABLE_MODULE_EXTRAKEYS - test_exhaustive_extrakeys(ctx, group); -#endif -#ifdef ENABLE_MODULE_SCHNORRSIG - test_exhaustive_schnorrsig(ctx); -#endif -#ifdef ENABLE_MODULE_ELLSWIFT - /* The ellswift algorithm does have additional edge cases when operating on - * curves of even order, which are not included in the code as secp256k1 is - * of odd order. Skip the ellswift tests if the used exhaustive tests curve - * is even-ordered accordingly. */ - #if !EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER - test_exhaustive_ellswift(ctx, group); - #endif -#endif - - secp256k1_context_destroy(ctx); - } - - testrand_finish(); - - printf("no problems found\n"); - return 0; -} diff --git a/external/secp256k1/src/testutil.h b/external/secp256k1/src/testutil.h deleted file mode 100644 index 64b3bb41c0..0000000000 --- a/external/secp256k1/src/testutil.h +++ /dev/null @@ -1,148 +0,0 @@ -/*********************************************************************** - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_TESTUTIL_H -#define SECP256K1_TESTUTIL_H - -#include "field.h" -#include "group.h" -#include "testrand.h" -#include "util.h" - -static void testutil_random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - testrand256(bin); - if (secp256k1_fe_set_b32_limit(x, bin)) { - return; - } - } while(1); -} - -static void testutil_random_fe_non_zero(secp256k1_fe *nz) { - do { - testutil_random_fe(nz); - } while (secp256k1_fe_is_zero(nz)); -} - -static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) { - secp256k1_fe zero; - int n = testrand_int(m + 1); - secp256k1_fe_normalize(fe); - if (n == 0) { - return; - } - secp256k1_fe_set_int(&zero, 0); - secp256k1_fe_negate(&zero, &zero, 0); - secp256k1_fe_mul_int_unchecked(&zero, n - 1); - secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif -} - -static void testutil_random_fe_test(secp256k1_fe *x) { - unsigned char bin[32]; - do { - testrand256_test(bin); - if (secp256k1_fe_set_b32_limit(x, bin)) { - return; - } - } while(1); -} - -static void testutil_random_fe_non_zero_test(secp256k1_fe *fe) { - do { - testutil_random_fe_test(fe); - } while(secp256k1_fe_is_zero(fe)); -} - -static void testutil_random_ge_x_magnitude(secp256k1_ge *ge) { - testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); -} - -static void testutil_random_ge_y_magnitude(secp256k1_ge *ge) { - testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); -} - -static void testutil_random_gej_x_magnitude(secp256k1_gej *gej) { - testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); -} - -static void testutil_random_gej_y_magnitude(secp256k1_gej *gej) { - testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); -} - -static void testutil_random_gej_z_magnitude(secp256k1_gej *gej) { - testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); -} - -static void testutil_random_ge_test(secp256k1_ge *ge) { - secp256k1_fe fe; - do { - testutil_random_fe_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, testrand_bits(1))) { - secp256k1_fe_normalize(&ge->y); - break; - } - } while(1); - ge->infinity = 0; -} - -static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { - secp256k1_fe z2, z3; - testutil_random_fe_non_zero_test(&gej->z); - secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_mul(&z3, &z2, &gej->z); - secp256k1_fe_mul(&gej->x, &ge->x, &z2); - secp256k1_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; -} - -static void testutil_random_gej_test(secp256k1_gej *gej) { - secp256k1_ge ge; - testutil_random_ge_test(&ge); - testutil_random_ge_jacobian_test(gej, &ge); -} - -static void testutil_random_pubkey_test(secp256k1_pubkey *pk) { - secp256k1_ge ge; - testutil_random_ge_test(&ge); - secp256k1_pubkey_save(pk, &ge); -} - -static void testutil_random_scalar_order_test(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - testrand256_test(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -static void testutil_random_scalar_order(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - testrand256(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -static void testutil_random_scalar_order_b32(unsigned char *b32) { - secp256k1_scalar num; - testutil_random_scalar_order(&num); - secp256k1_scalar_get_b32(b32, &num); -} - -#endif /* SECP256K1_TESTUTIL_H */ diff --git a/external/secp256k1/src/util.h b/external/secp256k1/src/util.h deleted file mode 100644 index 88a4149421..0000000000 --- a/external/secp256k1/src/util.h +++ /dev/null @@ -1,451 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_UTIL_H -#define SECP256K1_UTIL_H - -#include "../include/secp256k1.h" -#include "checkmem.h" - -#include -#include -#include -#include -#include -#if defined(_MSC_VER) -/* For SecureZeroMemory */ -#include -#endif - -#define STR_(x) #x -#define STR(x) STR_(x) -#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x -#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) - -/* Debug helper for printing arrays of unsigned char. */ -#define PRINT_BUF(buf, len) do { \ - printf("%s[%lu] = ", #buf, (unsigned long)len); \ - print_buf_plain(buf, len); \ -} while(0) - -static void print_buf_plain(const unsigned char *buf, size_t len) { - size_t i; - printf("{"); - for (i = 0; i < len; i++) { - if (i % 8 == 0) { - printf("\n "); - } else { - printf(" "); - } - printf("0x%02X,", buf[i]); - } - printf("\n}\n"); -} - -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline -# else -# define SECP256K1_INLINE -# endif -# else -# define SECP256K1_INLINE inline -# endif - -/** Assert statically that expr is true. - * - * This is a statement-like macro and can only be used inside functions. - */ -#define STATIC_ASSERT(expr) do { \ - switch(0) { \ - case 0: \ - /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ - case /* ERROR: static assertion failed */ (expr): \ - ; \ - } \ -} while(0) - -/** Assert statically that expr is an integer constant expression, and run stmt. - * - * Useful for example to enforce that magnitude arguments are constant. - */ -#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ - switch(42) { \ - /* C allows only integer constant expressions as case labels. */ \ - case /* ERROR: integer argument is not constant */ (expr): \ - break; \ - default: ; \ - } \ - stmt; \ -} while(0) - -typedef struct { - void (*fn)(const char *text, void* data); - const void* data; -} secp256k1_callback; - -static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { - cb->fn(text, (void*)cb->data); -} - -#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS -static void secp256k1_default_illegal_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); - abort(); -} -static void secp256k1_default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} -#else -void secp256k1_default_illegal_callback_fn(const char* str, void* data); -void secp256k1_default_error_callback_fn(const char* str, void* data); -#endif - -static const secp256k1_callback default_illegal_callback = { - secp256k1_default_illegal_callback_fn, - NULL -}; - -static const secp256k1_callback default_error_callback = { - secp256k1_default_error_callback_fn, - NULL -}; - - -#ifdef DETERMINISTIC -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s\n", msg); \ - abort(); \ -} while(0); -#else -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ - abort(); \ -} while(0) -#endif - -#if SECP256K1_GNUC_PREREQ(3, 0) -#define EXPECT(x,c) __builtin_expect((x),(c)) -#else -#define EXPECT(x,c) (x) -#endif - -#ifdef DETERMINISTIC -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed"); \ - } \ -} while(0) -#else -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed: " #cond); \ - } \ -} while(0) -#endif - -/* Like assert(), but when VERIFY is defined. */ -#if defined(VERIFY) -#define VERIFY_CHECK CHECK -#else -#define VERIFY_CHECK(cond) -#endif - -static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { - void *ret = malloc(size); - if (ret == NULL) { - secp256k1_callback_call(cb, "Out of memory"); - } - return ret; -} - -#if defined(__BIGGEST_ALIGNMENT__) -#define ALIGNMENT __BIGGEST_ALIGNMENT__ -#else -/* Using 16 bytes alignment because common architectures never have alignment - * requirements above 8 for any of the types we care about. In addition we - * leave some room because currently we don't care about a few bytes. */ -#define ALIGNMENT 16 -#endif - -/* ceil(x/y) for integers x > 0 and y > 0. Here, / denotes rational division. */ -#define CEIL_DIV(x, y) (1 + ((x) - 1) / (y)) - -#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT) - -/* Macro for restrict, when available and not in a VERIFY build. */ -#if defined(SECP256K1_BUILD) && defined(VERIFY) -# define SECP256K1_RESTRICT -#else -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(3,0) -# define SECP256K1_RESTRICT __restrict__ -# elif (defined(_MSC_VER) && _MSC_VER >= 1400) -# define SECP256K1_RESTRICT __restrict -# else -# define SECP256K1_RESTRICT -# endif -# else -# define SECP256K1_RESTRICT restrict -# endif -#endif - -#if defined(__GNUC__) -# define SECP256K1_GNUC_EXT __extension__ -#else -# define SECP256K1_GNUC_EXT -#endif - -/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ -static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) { - unsigned char *p = (unsigned char *)s; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - unsigned char mask = -(unsigned char) vflag; - while (len) { - *p &= ~mask; - p++; - len--; - } -} - -/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ -static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) { -#if defined(_MSC_VER) - /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ - SecureZeroMemory(ptr, len); -#elif defined(__GNUC__) - /* We use a memory barrier that scares the compiler away from optimizing out the memset. - * - * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f - * in BoringSSL (ISC License): - * As best as we can tell, this is sufficient to break any optimisations that - * might try to eliminate "superfluous" memsets. - * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it - * is pretty efficient, because the compiler can still implement the memset() efficently, - * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by - * Yang et al. (USENIX Security 2017) for more background. - */ - memset(ptr, 0, len); - __asm__ __volatile__("" : : "r"(ptr) : "memory"); -#else - void *(*volatile const volatile_memset)(void *, int, size_t) = memset; - volatile_memset(ptr, 0, len); -#endif -#ifdef VERIFY - SECP256K1_CHECKMEM_UNDEFINE(ptr, len); -#endif -} - -/** Semantics like memcmp. Variable-time. - * - * We use this to avoid possible compiler bugs with memcmp, e.g. - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 - */ -static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n) { - const unsigned char *p1 = s1, *p2 = s2; - size_t i; - - for (i = 0; i < n; i++) { - int diff = p1[i] - p2[i]; - if (diff != 0) { - return diff; - } - } - return 0; -} - -/* Return 1 if all elements of array s are 0 and otherwise return 0. - * Constant-time. */ -static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size_t len) { - unsigned char acc = 0; - int ret; - size_t i; - - for (i = 0; i < len; i++) { - acc |= s[i]; - } - ret = (acc == 0); - /* acc may contain secret values. Try to explicitly clear it. */ - secp256k1_memclear(&acc, sizeof(acc)); - return ret; -} - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ -static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) { - unsigned int mask0, mask1, r_masked, a_masked; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - - /* Casting a negative int to unsigned and back to int is implementation defined behavior */ - VERIFY_CHECK(*r >= 0 && *a >= 0); - - mask0 = (unsigned int)vflag + ~0u; - mask1 = ~mask0; - r_masked = ((unsigned int)*r & mask0); - a_masked = ((unsigned int)*a & mask1); - - *r = (int)(r_masked | a_masked); -} - -#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) -/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ -# define SECP256K1_WIDEMUL_INT128 1 -# define SECP256K1_INT128_STRUCT 1 -#elif defined(USE_FORCE_WIDEMUL_INT128) -/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ -# define SECP256K1_WIDEMUL_INT128 1 -# define SECP256K1_INT128_NATIVE 1 -#elif defined(USE_FORCE_WIDEMUL_INT64) -/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ -# define SECP256K1_WIDEMUL_INT64 1 -#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) -/* If a native 128-bit integer type exists, use int128. */ -# define SECP256K1_WIDEMUL_INT128 1 -# define SECP256K1_INT128_NATIVE 1 -#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) -/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct - * (which has special logic to implement using intrinsics on those systems). */ -# define SECP256K1_WIDEMUL_INT128 1 -# define SECP256K1_INT128_STRUCT 1 -#elif SIZE_MAX > 0xffffffff -/* Systems with 64-bit pointers (and thus registers) very likely benefit from - * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based - * multiplication logic). */ -# define SECP256K1_WIDEMUL_INT128 1 -# define SECP256K1_INT128_STRUCT 1 -#else -/* Lastly, fall back to int64 based arithmetic. */ -# define SECP256K1_WIDEMUL_INT64 1 -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. - * This function is only intended to be used as fallback for - * secp256k1_ctz32_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) { - static const uint8_t debruijn[32] = { - 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, - 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, - 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B - }; - return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. - * This function is only intended to be used as fallback for - * secp256k1_ctz64_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) { - static const uint8_t debruijn[64] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 - }; - return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ -static SECP256K1_INLINE int secp256k1_ctz32_var(uint32_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ - if (((unsigned)UINT32_MAX) == UINT32_MAX) { - return __builtin_ctz(x); - } -#endif -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ - return __builtin_ctzl(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return secp256k1_ctz32_var_debruijn(x); -#endif -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ -static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ - if (((unsigned long)UINT64_MAX) == UINT64_MAX) { - return __builtin_ctzl(x); - } -#endif -#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ - return __builtin_ctzll(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return secp256k1_ctz64_var_debruijn(x); -#endif -} - -/* Read a uint32_t in big endian */ -SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) { - return (uint32_t)p[0] << 24 | - (uint32_t)p[1] << 16 | - (uint32_t)p[2] << 8 | - (uint32_t)p[3]; -} - -/* Write a uint32_t in big endian */ -SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) { - p[3] = x; - p[2] = x >> 8; - p[1] = x >> 16; - p[0] = x >> 24; -} - -/* Read a uint64_t in big endian */ -SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) { - return (uint64_t)p[0] << 56 | - (uint64_t)p[1] << 48 | - (uint64_t)p[2] << 40 | - (uint64_t)p[3] << 32 | - (uint64_t)p[4] << 24 | - (uint64_t)p[5] << 16 | - (uint64_t)p[6] << 8 | - (uint64_t)p[7]; -} - -/* Write a uint64_t in big endian */ -SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) { - p[7] = x; - p[6] = x >> 8; - p[5] = x >> 16; - p[4] = x >> 24; - p[3] = x >> 32; - p[2] = x >> 40; - p[1] = x >> 48; - p[0] = x >> 56; -} - -/* Rotate a uint32_t to the right. */ -SECP256K1_INLINE static uint32_t secp256k1_rotr32(const uint32_t x, const unsigned int by) { -#if defined(_MSC_VER) - return _rotr(x, by); /* needs */ -#else - /* Reduce rotation amount to avoid UB when shifting. */ - const unsigned int mask = CHAR_BIT * sizeof(x) - 1; - /* Turned into a rot instruction by GCC and clang. */ - return (x >> (by & mask)) | (x << ((-by) & mask)); -#endif -} - -#endif /* SECP256K1_UTIL_H */ diff --git a/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING b/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING deleted file mode 100644 index cddf9d9182..0000000000 --- a/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING +++ /dev/null @@ -1,212 +0,0 @@ -* The file `ecdsa_secp256k1_sha256_bitcoin_test.json` in this directory - comes from Google's project Wycheproof with git commit - `b063b4aedae951c69df014cd25fa6d69ae9e8cb9`, see - https://github.com/google/wycheproof/blob/b063b4aedae951c69df014cd25fa6d69ae9e8cb9/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json - -* The file `ecdsa_secp256k1_sha256_bitcoin_test.h` is generated from - `ecdsa_secp256k1_sha256_bitcoin_test.json` using the script - `tests_wycheproof_generate.py`. - -------------------------------------------------------------------------------- - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h deleted file mode 100644 index 736737fd61..0000000000 --- a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h +++ /dev/null @@ -1,1564 +0,0 @@ -/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */ -#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS (463) - -typedef struct { - size_t pk_offset; - size_t msg_offset; - size_t msg_len; - size_t sig_offset; - size_t sig_len; - int expected_verify; -} wycheproof_ecdsa_testvector; - -static const unsigned char wycheproof_ecdsa_messages[] = { 0x31,0x32,0x33,0x34,0x30,0x30, - 0x32,0x35,0x35,0x38,0x35, - 0x34,0x32,0x36,0x34,0x37,0x39,0x37,0x32,0x34, - 0x37,0x31,0x33,0x38,0x36,0x38,0x34,0x38,0x39,0x31, - 0x31,0x30,0x33,0x35,0x39,0x33,0x33,0x31,0x36,0x36,0x38, - 0x33,0x39,0x34,0x39,0x34,0x30,0x31,0x32,0x31,0x35, - 0x31,0x33,0x34,0x34,0x32,0x39,0x33,0x30,0x37,0x39, - 0x33,0x37,0x30,0x36,0x32,0x31,0x31,0x37,0x31,0x32, - 0x33,0x34,0x33,0x36,0x38,0x38,0x37,0x31,0x32, - 0x31,0x33,0x35,0x31,0x35,0x33,0x30,0x33,0x37,0x30, - 0x36,0x35,0x35,0x33,0x32,0x30,0x33,0x31,0x32,0x36, - 0x31,0x35,0x36,0x34,0x33,0x34,0x36,0x36,0x30,0x33, - 0x34,0x34,0x32,0x39,0x35,0x33,0x39,0x31,0x31,0x37, - 0x31,0x30,0x39,0x35,0x33,0x32,0x36,0x31,0x33,0x35,0x31, - 0x35,0x39,0x38,0x37,0x33,0x35,0x30,0x30,0x34,0x31, - 0x33,0x34,0x36,0x33,0x30,0x30,0x36,0x38,0x37,0x38, - 0x39,0x38,0x31,0x37,0x33,0x32,0x30,0x32,0x38,0x37, - 0x33,0x32,0x32,0x32,0x30,0x34,0x31,0x30,0x34,0x36, - 0x36,0x36,0x36,0x36,0x33,0x30,0x37,0x31,0x30,0x34, - 0x31,0x30,0x33,0x35,0x39,0x35,0x31,0x38,0x39,0x38, - 0x31,0x38,0x34,0x36,0x35,0x39,0x37,0x31,0x39,0x35, - 0x33,0x31,0x33,0x36,0x30,0x34,0x36,0x31,0x38,0x39, - 0x32,0x36,0x36,0x33,0x37,0x38,0x34,0x32,0x35,0x34, - 0x31,0x36,0x35,0x32,0x31,0x30,0x30,0x35,0x32,0x34, - 0x35,0x37,0x34,0x38,0x30,0x38,0x31,0x36,0x39,0x36, - 0x36,0x33,0x34,0x33,0x39,0x31,0x33,0x34,0x36,0x38, - 0x31,0x35,0x34,0x31,0x31,0x30,0x33,0x35,0x39,0x38, - 0x31,0x30,0x34,0x37,0x38,0x35,0x38,0x30,0x31,0x32,0x38, - 0x31,0x30,0x35,0x33,0x36,0x32,0x38,0x35,0x35,0x36,0x38, - 0x39,0x35,0x33,0x39,0x30,0x34,0x31,0x30,0x35, - 0x39,0x37,0x38,0x38,0x34,0x38,0x30,0x33,0x39, - 0x33,0x36,0x31,0x30,0x36,0x37,0x32,0x34,0x34,0x32, - 0x31,0x30,0x35,0x34,0x32,0x34,0x30,0x37,0x30,0x35, - 0x35,0x31,0x37,0x34,0x34,0x34,0x38,0x31,0x39,0x37, - 0x31,0x39,0x36,0x37,0x35,0x36,0x31,0x32,0x35,0x31, - 0x33,0x34,0x34,0x37,0x32,0x35,0x33,0x33,0x34,0x33, - 0x33,0x36,0x38,0x32,0x36,0x34,0x33,0x31,0x38, - 0x33,0x32,0x36,0x31,0x31,0x39,0x38,0x36,0x30,0x38, - 0x39,0x36,0x37,0x38,0x37,0x38,0x31,0x30,0x39,0x34, - 0x34,0x39,0x35,0x38,0x38,0x32,0x33,0x38,0x32,0x33, - 0x38,0x32,0x34,0x36,0x33,0x37,0x38,0x33,0x37, - 0x31,0x31,0x30,0x32,0x30,0x38,0x33,0x33,0x37,0x37,0x36, - 0x31,0x33,0x33,0x38,0x37,0x31,0x36,0x34,0x38, - 0x33,0x32,0x32,0x31,0x34,0x34,0x31,0x36,0x32, - 0x31,0x30,0x36,0x38,0x36,0x36,0x35,0x35,0x35,0x34,0x36, - 0x36,0x32,0x31,0x35,0x35,0x32,0x34,0x36, - 0x37,0x30,0x33,0x30,0x38,0x31,0x38,0x37,0x37,0x34, - 0x35,0x39,0x32,0x34,0x35,0x32,0x33,0x37,0x34,0x34, - 0x31,0x34,0x39,0x35,0x35,0x38,0x36,0x36,0x32,0x31, - 0x34,0x30,0x30,0x35,0x33,0x31,0x34,0x34,0x30,0x36, - 0x33,0x30,0x39,0x36,0x34,0x35,0x37,0x35,0x31,0x32, - 0x32,0x37,0x38,0x34,0x30,0x32,0x35,0x36,0x32,0x30, - 0x32,0x36,0x31,0x38,0x37,0x38,0x37,0x34,0x31,0x38, - 0x31,0x36,0x34,0x32,0x36,0x32,0x35,0x32,0x36,0x32, - 0x36,0x38,0x32,0x34,0x31,0x38,0x39,0x34,0x33,0x36, - 0x34,0x38,0x34,0x32,0x34,0x35,0x34,0x32,0x35, - 0x4d,0x73,0x67, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; - -static const unsigned char wycheproof_ecdsa_public_keys[] = { 0x04,0xb8,0x38,0xff,0x44,0xe5,0xbc,0x17,0x7b,0xf2,0x11,0x89,0xd0,0x76,0x60,0x82,0xfc,0x9d,0x84,0x32,0x26,0x88,0x7f,0xc9,0x76,0x03,0x71,0x10,0x0b,0x7e,0xe2,0x0a,0x6f,0xf0,0xc9,0xd7,0x5b,0xfb,0xa7,0xb3,0x1a,0x6b,0xca,0x19,0x74,0x49,0x6e,0xeb,0x56,0xde,0x35,0x70,0x71,0x95,0x5d,0x83,0xc4,0xb1,0xba,0xda,0xa0,0xb2,0x18,0x32,0xe9, - 0x04,0x07,0x31,0x0f,0x90,0xa9,0xea,0xe1,0x49,0xa0,0x84,0x02,0xf5,0x41,0x94,0xa0,0xf7,0xb4,0xac,0x42,0x7b,0xf8,0xd9,0xbd,0x6c,0x76,0x81,0x07,0x1d,0xc4,0x7d,0xc3,0x62,0x26,0xa6,0xd3,0x7a,0xc4,0x6d,0x61,0xfd,0x60,0x0c,0x0b,0xf1,0xbf,0xf8,0x76,0x89,0xed,0x11,0x7d,0xda,0x6b,0x0e,0x59,0x31,0x8a,0xe0,0x10,0xa1,0x97,0xa2,0x6c,0xa0, - 0x04,0xbc,0x97,0xe7,0x58,0x5e,0xec,0xad,0x48,0xe1,0x66,0x83,0xbc,0x40,0x91,0x70,0x8e,0x1a,0x93,0x0c,0x68,0x3f,0xc4,0x70,0x01,0xd4,0xb3,0x83,0x59,0x4f,0x2c,0x4e,0x22,0x70,0x59,0x89,0xcf,0x69,0xda,0xea,0xdd,0x4e,0x4e,0x4b,0x81,0x51,0xed,0x88,0x8d,0xfe,0xc2,0x0f,0xb0,0x17,0x28,0xd8,0x9d,0x56,0xb3,0xf3,0x8f,0x2a,0xe9,0xc8,0xc5, - 0x04,0x44,0xad,0x33,0x9a,0xfb,0xc2,0x1e,0x9a,0xbf,0x7b,0x60,0x2a,0x5c,0xa5,0x35,0xea,0x37,0x81,0x35,0xb6,0xd1,0x0d,0x81,0x31,0x0b,0xdd,0x82,0x93,0xd1,0xdf,0x32,0x52,0xb6,0x3f,0xf7,0xd0,0x77,0x47,0x70,0xf8,0xfe,0x1d,0x17,0x22,0xfa,0x83,0xac,0xd0,0x2f,0x43,0x4e,0x4f,0xc1,0x10,0xa0,0xcc,0x8f,0x6d,0xdd,0xd3,0x7d,0x56,0xc4,0x63, - 0x04,0x12,0x60,0xc2,0x12,0x2c,0x9e,0x24,0x4e,0x1a,0xf5,0x15,0x1b,0xed,0xe0,0xc3,0xae,0x23,0xb5,0x4d,0x7c,0x59,0x68,0x81,0xd3,0xee,0xba,0xd2,0x1f,0x37,0xdd,0x87,0x8c,0x5c,0x9a,0x0c,0x1a,0x9a,0xde,0x76,0x73,0x7a,0x88,0x11,0xbd,0x6a,0x7f,0x92,0x87,0xc9,0x78,0xee,0x39,0x6a,0xa8,0x9c,0x11,0xe4,0x72,0x29,0xd2,0xcc,0xb5,0x52,0xf0, - 0x04,0x18,0x77,0x04,0x5b,0xe2,0x5d,0x34,0xa1,0xd0,0x60,0x0f,0x9d,0x5c,0x00,0xd0,0x64,0x5a,0x2a,0x54,0x37,0x9b,0x6c,0xee,0xfa,0xd2,0xe6,0xbf,0x5c,0x2a,0x33,0x52,0xce,0x82,0x1a,0x53,0x2c,0xc1,0x75,0x1e,0xe1,0xd3,0x6d,0x41,0xc3,0xd6,0xab,0x4e,0x9b,0x14,0x3e,0x44,0xec,0x46,0xd7,0x34,0x78,0xea,0x6a,0x79,0xa5,0xc0,0xe5,0x41,0x59, - 0x04,0x45,0x54,0x39,0xfc,0xc3,0xd2,0xde,0xec,0xed,0xde,0xae,0xce,0x60,0xe7,0xbd,0x17,0x30,0x4f,0x36,0xeb,0xb6,0x02,0xad,0xf5,0xa2,0x2e,0x0b,0x8f,0x1d,0xb4,0x6a,0x50,0xae,0xc3,0x8f,0xb2,0xba,0xf2,0x21,0xe9,0xa8,0xd1,0x88,0x7c,0x7b,0xf6,0x22,0x2d,0xd1,0x83,0x46,0x34,0xe7,0x72,0x63,0x31,0x5a,0xf6,0xd2,0x36,0x09,0xd0,0x4f,0x77, - 0x04,0x2e,0x1f,0x46,0x6b,0x02,0x4c,0x0c,0x3a,0xce,0x24,0x37,0xde,0x09,0x12,0x7f,0xed,0x04,0xb7,0x06,0xf9,0x4b,0x19,0xa2,0x1b,0xb1,0xc2,0xac,0xf3,0x5c,0xec,0xe7,0x18,0x04,0x49,0xae,0x35,0x23,0xd7,0x25,0x34,0xe9,0x64,0x97,0x2c,0xfd,0x3b,0x38,0xaf,0x0b,0xdd,0xd9,0x61,0x9e,0x5a,0xf2,0x23,0xe4,0xd1,0xa4,0x0f,0x34,0xcf,0x9f,0x1d, - 0x04,0x8e,0x7a,0xbd,0xbb,0xd1,0x8d,0xe7,0x45,0x23,0x74,0xc1,0x87,0x9a,0x1c,0x3b,0x01,0xd1,0x32,0x61,0xe7,0xd4,0x57,0x1c,0x3b,0x47,0xa1,0xc7,0x6c,0x55,0xa2,0x33,0x73,0x26,0xed,0x89,0x7c,0xd5,0x17,0xa4,0xf5,0x34,0x9d,0xb8,0x09,0x78,0x0f,0x6d,0x2f,0x2b,0x9f,0x62,0x99,0xd8,0xb5,0xa8,0x90,0x77,0xf1,0x11,0x9a,0x71,0x8f,0xd7,0xb3, - 0x04,0x7b,0x33,0x3d,0x43,0x40,0xd3,0xd7,0x18,0xdd,0x3e,0x6a,0xff,0x7d,0xe7,0xbb,0xf8,0xb7,0x2b,0xfd,0x61,0x6c,0x84,0x20,0x05,0x60,0x52,0x84,0x23,0x76,0xb9,0xaf,0x19,0x42,0x11,0x7c,0x5a,0xfe,0xac,0x75,0x5d,0x6f,0x37,0x6f,0xc6,0x32,0x9a,0x7d,0x76,0x05,0x1b,0x87,0x12,0x3a,0x4a,0x5d,0x0b,0xc4,0xa5,0x39,0x38,0x0f,0x03,0xde,0x7b, - 0x04,0xd3,0x0c,0xa4,0xa0,0xdd,0xb6,0x61,0x6c,0x85,0x1d,0x30,0xce,0xd6,0x82,0xc4,0x0f,0x83,0xc6,0x27,0x58,0xa1,0xf2,0x75,0x99,0x88,0xd6,0x76,0x3a,0x88,0xf1,0xc0,0xe5,0x03,0xa8,0x0d,0x54,0x15,0x65,0x0d,0x41,0x23,0x97,0x84,0xe8,0xe2,0xfb,0x12,0x35,0xe9,0xfe,0x99,0x1d,0x11,0x2e,0xbb,0x81,0x18,0x6c,0xbf,0x0d,0xa2,0xde,0x3a,0xff, - 0x04,0x48,0x96,0x9b,0x39,0x99,0x12,0x97,0xb3,0x32,0xa6,0x52,0xd3,0xee,0x6e,0x01,0xe9,0x09,0xb3,0x99,0x04,0xe7,0x1f,0xa2,0x35,0x4a,0x78,0x30,0xc7,0x75,0x0b,0xaf,0x24,0xb4,0x01,0x2d,0x1b,0x83,0x0d,0x19,0x9c,0xcb,0x1f,0xc9,0x72,0xb3,0x2b,0xfd,0xed,0x55,0xf0,0x9c,0xd6,0x2d,0x25,0x7e,0x5e,0x84,0x4e,0x27,0xe5,0x7a,0x15,0x94,0xec, - 0x04,0x02,0xef,0x4d,0x6d,0x6c,0xfd,0x5a,0x94,0xf1,0xd7,0x78,0x42,0x26,0xe3,0xe2,0xa6,0xc0,0xa4,0x36,0xc5,0x58,0x39,0x61,0x9f,0x38,0xfb,0x44,0x72,0xb5,0xf9,0xee,0x77,0x7e,0xb4,0xac,0xd4,0xee,0xbd,0xa5,0xcd,0x72,0x87,0x5f,0xfd,0x2a,0x2f,0x26,0x22,0x9c,0x2d,0xc6,0xb4,0x65,0x00,0x91,0x9a,0x43,0x2c,0x86,0x73,0x9f,0x3a,0xe8,0x66, - 0x04,0x46,0x4f,0x4f,0xf7,0x15,0x72,0x9c,0xae,0x50,0x72,0xca,0x3b,0xd8,0x01,0xd3,0x19,0x5b,0x67,0xae,0xc6,0x5e,0x9b,0x01,0xaa,0xd2,0x0a,0x29,0x43,0xdc,0xbc,0xb5,0x84,0xb1,0xaf,0xd2,0x9d,0x31,0xa3,0x9a,0x11,0xd5,0x70,0xaa,0x15,0x97,0x43,0x9b,0x3b,0x2d,0x19,0x71,0xbf,0x2f,0x1a,0xbf,0x15,0x43,0x2d,0x02,0x07,0xb1,0x0d,0x1d,0x08, - 0x04,0x15,0x7f,0x8f,0xdd,0xf3,0x73,0xeb,0x5f,0x49,0xcf,0xcf,0x10,0xd8,0xb8,0x53,0xcf,0x91,0xcb,0xcd,0x7d,0x66,0x5c,0x35,0x22,0xba,0x7d,0xd7,0x38,0xdd,0xb7,0x9a,0x4c,0xde,0xad,0xf1,0xa5,0xc4,0x48,0xea,0x3c,0x9f,0x41,0x91,0xa8,0x99,0x9a,0xbf,0xcc,0x75,0x7a,0xc6,0xd6,0x45,0x67,0xef,0x07,0x2c,0x47,0xfe,0xc6,0x13,0x44,0x3b,0x8f, - 0x04,0x09,0x34,0xa5,0x37,0x46,0x6c,0x07,0x43,0x0e,0x2c,0x48,0xfe,0xb9,0x90,0xbb,0x19,0xfb,0x78,0xce,0xcc,0x9c,0xee,0x42,0x4e,0xa4,0xd1,0x30,0x29,0x1a,0xa2,0x37,0xf0,0xd4,0xf9,0x2d,0x23,0xb4,0x62,0x80,0x4b,0x5b,0x68,0xc5,0x25,0x58,0xc0,0x1c,0x99,0x96,0xdb,0xf7,0x27,0xfc,0xca,0xbb,0xee,0xdb,0x96,0x21,0xa4,0x00,0x53,0x5a,0xfa, - 0x04,0xd6,0xef,0x20,0xbe,0x66,0xc8,0x93,0xf7,0x41,0xa9,0xbf,0x90,0xd9,0xb7,0x46,0x75,0xd1,0xc2,0xa3,0x12,0x96,0x39,0x7a,0xcb,0x3e,0xf1,0x74,0xfd,0x0b,0x30,0x0c,0x65,0x4a,0x0c,0x95,0x47,0x8c,0xa0,0x03,0x99,0x16,0x2d,0x7f,0x0f,0x2d,0xc8,0x9e,0xfd,0xc2,0xb2,0x8a,0x30,0xfb,0xab,0xe2,0x85,0x85,0x72,0x95,0xa4,0xb0,0xc4,0xe2,0x65, - 0x04,0xb7,0x29,0x1d,0x14,0x04,0xe0,0xc0,0xc0,0x7d,0xab,0x93,0x72,0x18,0x9f,0x4b,0xd5,0x8d,0x2c,0xea,0xa8,0xd1,0x5e,0xde,0x54,0x4d,0x95,0x14,0x54,0x5b,0xa9,0xee,0x06,0x29,0xc9,0xa6,0x3d,0x5e,0x30,0x87,0x69,0xcc,0x30,0xec,0x27,0x6a,0x41,0x0e,0x64,0x64,0xa2,0x7e,0xea,0xfd,0x9e,0x59,0x9d,0xb1,0x0f,0x05,0x3a,0x4f,0xe4,0xa8,0x29, - 0x04,0x6e,0x28,0x30,0x33,0x05,0xd6,0x42,0xcc,0xb9,0x23,0xb7,0x22,0xea,0x86,0xb2,0xa0,0xbc,0x8e,0x37,0x35,0xec,0xb2,0x6e,0x84,0x9b,0x19,0xc9,0xf7,0x6b,0x2f,0xdb,0xb8,0x18,0x6e,0x80,0xd6,0x4d,0x8c,0xab,0x16,0x4f,0x52,0x38,0xf5,0x31,0x84,0x61,0xbf,0x89,0xd4,0xd9,0x6e,0xe6,0x54,0x4c,0x81,0x6c,0x75,0x66,0x94,0x77,0x74,0xe0,0xf6, - 0x04,0x37,0x5b,0xda,0x93,0xf6,0xaf,0x92,0xfb,0x5f,0x8f,0x4b,0x1b,0x5f,0x05,0x34,0xe3,0xba,0xfa,0xb3,0x4c,0xb7,0xad,0x9f,0xb9,0xd0,0xb7,0x22,0xe4,0xa5,0xc3,0x02,0xa9,0xa0,0x0b,0x9f,0x38,0x7a,0x5a,0x39,0x60,0x97,0xaa,0x21,0x62,0xfc,0x5b,0xbc,0xf4,0xa5,0x26,0x33,0x72,0xf6,0x81,0xc9,0x4d,0xa5,0x1e,0x97,0x99,0x12,0x09,0x90,0xfd, - 0x04,0xd7,0x5b,0x68,0x21,0x6b,0xab,0xe0,0x3a,0xe2,0x57,0xe9,0x4b,0x4e,0x3b,0xf1,0xc5,0x2f,0x44,0xe3,0xdf,0x26,0x6d,0x15,0x24,0xff,0x8c,0x5e,0xa6,0x9d,0xa7,0x31,0x97,0xda,0x4b,0xff,0x9e,0xd1,0xc5,0x3f,0x44,0x91,0x7a,0x67,0xd7,0xb9,0x78,0x59,0x8e,0x89,0xdf,0x35,0x9e,0x3d,0x59,0x13,0xea,0xea,0x24,0xf3,0xae,0x25,0x9a,0xbc,0x44, - 0x04,0x78,0xbc,0xda,0x14,0x0a,0xed,0x23,0xd4,0x30,0xcb,0x23,0xc3,0xdc,0x0d,0x01,0xf4,0x23,0xdb,0x13,0x4e,0xe9,0x4a,0x3a,0x8c,0xb4,0x83,0xf2,0xde,0xac,0x2a,0xc6,0x53,0x11,0x81,0x14,0xf6,0xf3,0x30,0x45,0xd4,0xe9,0xed,0x91,0x07,0x08,0x50,0x07,0xbf,0xbd,0xdf,0x8f,0x58,0xfe,0x7a,0x1a,0x24,0x45,0xd6,0x6a,0x99,0x00,0x45,0x47,0x6e, - 0x04,0xbb,0x79,0xf6,0x18,0x57,0xf7,0x43,0xbf,0xa1,0xb6,0xe7,0x11,0x1c,0xe4,0x09,0x43,0x77,0x25,0x69,0x69,0xe4,0xe1,0x51,0x59,0x12,0x3d,0x95,0x48,0xac,0xc3,0xbe,0x6c,0x1f,0x9d,0x9f,0x88,0x60,0xdc,0xff,0xd3,0xeb,0x36,0xdd,0x6c,0x31,0xff,0x2e,0x72,0x26,0xc2,0x00,0x9c,0x4c,0x94,0xd8,0xd7,0xd2,0xb5,0x68,0x6b,0xf7,0xab,0xd6,0x77, - 0x04,0x93,0x59,0x18,0x27,0xd9,0xe6,0x71,0x3b,0x4e,0x9f,0xae,0xa6,0x2c,0x72,0xb2,0x8d,0xfe,0xfa,0x68,0xe0,0xc0,0x51,0x60,0xb5,0xd6,0xaa,0xe8,0x8f,0xd2,0xe3,0x6c,0x36,0x07,0x3f,0x55,0x45,0xad,0x5a,0xf4,0x10,0xaf,0x26,0xaf,0xff,0x68,0x65,0x4c,0xf7,0x2d,0x45,0xe4,0x93,0x48,0x93,0x11,0x20,0x32,0x47,0x34,0x7a,0x89,0x0f,0x45,0x18, - 0x04,0x31,0xed,0x30,0x81,0xae,0xfe,0x00,0x1e,0xb6,0x40,0x20,0x69,0xee,0x2c,0xcc,0x18,0x62,0x93,0x7b,0x85,0x99,0x51,0x44,0xdb,0xa9,0x50,0x39,0x43,0x58,0x7b,0xf0,0xda,0xda,0x01,0xb8,0xcc,0x4d,0xf3,0x4f,0x5a,0xb3,0xb1,0xa3,0x59,0x61,0x52,0x08,0x94,0x6e,0x5e,0xe3,0x5f,0x98,0xee,0x77,0x5b,0x8c,0xce,0xcd,0x86,0xcc,0xc1,0x65,0x0f, - 0x04,0x7d,0xff,0x66,0xfa,0x98,0x50,0x9f,0xf3,0xe2,0xe5,0x10,0x45,0xf4,0x39,0x05,0x23,0xdc,0xcd,0xa4,0x3a,0x3b,0xc2,0x88,0x5e,0x58,0xc2,0x48,0x09,0x09,0x90,0xee,0xa8,0x54,0xc7,0x6c,0x2b,0x9a,0xde,0xb6,0xbb,0x57,0x18,0x23,0xe0,0x7f,0xd7,0xc6,0x5c,0x86,0x39,0xcf,0x9d,0x90,0x52,0x60,0x06,0x4c,0x8e,0x76,0x75,0xce,0x6d,0x98,0xb4, - 0x04,0x42,0x80,0x50,0x9a,0xab,0x64,0xed,0xfc,0x0b,0x4a,0x29,0x67,0xe4,0xcb,0xce,0x84,0x9c,0xb5,0x44,0xe4,0xa7,0x73,0x13,0xc8,0xe6,0xec,0xe5,0x79,0xfb,0xd7,0x42,0x0a,0x2e,0x89,0xfe,0x5c,0xc1,0x92,0x7d,0x55,0x4e,0x6a,0x3b,0xb1,0x40,0x33,0xea,0x7c,0x92,0x2c,0xd7,0x5c,0xba,0x2c,0x74,0x15,0xfd,0xab,0x52,0xf2,0x0b,0x18,0x60,0xf1, - 0x04,0x4f,0x8d,0xf1,0x45,0x19,0x4e,0x3c,0x4f,0xc3,0xee,0xa2,0x6d,0x43,0xce,0x75,0xb4,0x02,0xd6,0xb1,0x74,0x72,0xdd,0xcb,0xb2,0x54,0xb8,0xa7,0x9b,0x0b,0xf3,0xd9,0xcb,0x2a,0xa2,0x0d,0x82,0x84,0x4c,0xb2,0x66,0x34,0x4e,0x71,0xca,0x78,0xf2,0xad,0x27,0xa7,0x5a,0x09,0xe5,0xbc,0x0f,0xa5,0x7e,0x4e,0xfd,0x9d,0x46,0x5a,0x08,0x88,0xdb, - 0x04,0x95,0x98,0xa5,0x7d,0xd6,0x7e,0xc3,0xe1,0x6b,0x58,0x7a,0x33,0x8a,0xa3,0xa1,0x0a,0x3a,0x39,0x13,0xb4,0x1a,0x3a,0xf3,0x2e,0x3e,0xd3,0xff,0x01,0x35,0x8c,0x6b,0x14,0x12,0x28,0x19,0xed,0xf8,0x07,0x4b,0xbc,0x52,0x1f,0x7d,0x4c,0xdc,0xe8,0x2f,0xef,0x7a,0x51,0x67,0x06,0xaf,0xfb,0xa1,0xd9,0x3d,0x9d,0xea,0x9c,0xca,0xe1,0xa2,0x07, - 0x04,0x91,0x71,0xfe,0xc3,0xca,0x20,0x80,0x6b,0xc0,0x84,0xf1,0x2f,0x07,0x60,0x91,0x1b,0x60,0x99,0x0b,0xd8,0x0e,0x5b,0x2a,0x71,0xca,0x03,0xa0,0x48,0xb2,0x0f,0x83,0x7e,0x63,0x4f,0xd1,0x78,0x63,0x76,0x1b,0x29,0x58,0xd2,0xbe,0x4e,0x14,0x9f,0x8d,0x3d,0x7a,0xbb,0xdc,0x18,0xbe,0x03,0xf4,0x51,0xab,0x6c,0x17,0xfa,0x0a,0x1f,0x83,0x30, - 0x04,0x77,0x7c,0x89,0x30,0xb6,0xe1,0xd2,0x71,0x10,0x0f,0xe6,0x8c,0xe9,0x3f,0x16,0x3f,0xa3,0x76,0x12,0xc5,0xff,0xf6,0x7f,0x4a,0x62,0xfc,0x3b,0xaf,0xaf,0x3d,0x17,0xa9,0xed,0x73,0xd8,0x6f,0x60,0xa5,0x1b,0x5e,0xd9,0x13,0x53,0xa3,0xb0,0x54,0xed,0xc0,0xaa,0x92,0xc9,0xeb,0xcb,0xd0,0xb7,0x5d,0x18,0x8f,0xdc,0x88,0x27,0x91,0xd6,0x8d, - 0x04,0xea,0xbc,0x24,0x8f,0x62,0x6e,0x0a,0x63,0xe1,0xeb,0x81,0xc4,0x3d,0x46,0x1a,0x39,0xa1,0xdb,0xa8,0x81,0xeb,0x6e,0xe2,0x15,0x2b,0x07,0xc3,0x2d,0x71,0xbc,0xf4,0x70,0x06,0x03,0xca,0xa8,0xb9,0xd3,0x3d,0xb1,0x3a,0xf4,0x4c,0x6e,0xfb,0xec,0x8a,0x19,0x8e,0xd6,0x12,0x4a,0xc9,0xeb,0x17,0xea,0xaf,0xd2,0x82,0x4a,0x54,0x5e,0xc0,0x00, - 0x04,0x9f,0x7a,0x13,0xad,0xa1,0x58,0xa5,0x5f,0x9d,0xdf,0x1a,0x45,0xf0,0x44,0xf0,0x73,0xd9,0xb8,0x00,0x30,0xef,0xdc,0xfc,0x9f,0x9f,0x58,0x41,0x8f,0xbc,0xea,0xf0,0x01,0xf8,0xad,0xa0,0x17,0x50,0x90,0xf8,0x0d,0x47,0x22,0x7d,0x67,0x13,0xb6,0x74,0x0f,0x9a,0x00,0x91,0xd8,0x8a,0x83,0x7d,0x0a,0x1c,0xd7,0x7b,0x58,0xa8,0xf2,0x8d,0x73, - 0x04,0x11,0xc4,0xf3,0xe4,0x61,0xcd,0x01,0x9b,0x5c,0x06,0xea,0x0c,0xea,0x4c,0x40,0x90,0xc3,0xcc,0x3e,0x3c,0x5d,0x9f,0x3c,0x6d,0x65,0xb4,0x36,0x82,0x6d,0xa9,0xb4,0xdb,0xbb,0xeb,0x7a,0x77,0xe4,0xcb,0xfd,0xa2,0x07,0x09,0x7c,0x43,0x42,0x37,0x05,0xf7,0x2c,0x80,0x47,0x6d,0xa3,0xda,0xc4,0x0a,0x48,0x3b,0x0a,0xb0,0xf2,0xea,0xd1,0xcb, - 0x04,0xe2,0xe1,0x86,0x82,0xd5,0x31,0x23,0xaa,0x01,0xa6,0xc5,0xd0,0x0b,0x0c,0x62,0x3d,0x67,0x1b,0x46,0x2e,0xa8,0x0b,0xdd,0xd6,0x52,0x27,0xfd,0x51,0x05,0x98,0x8a,0xa4,0x16,0x19,0x07,0xb3,0xfd,0x25,0x04,0x4a,0x94,0x9e,0xa4,0x1c,0x8e,0x2e,0xa8,0x45,0x9d,0xc6,0xf1,0x65,0x48,0x56,0xb8,0xb6,0x1b,0x31,0x54,0x3b,0xb1,0xb4,0x5b,0xdb, - 0x04,0x90,0xf8,0xd4,0xca,0x73,0xde,0x08,0xa6,0x56,0x4a,0xaf,0x00,0x52,0x47,0xb6,0xf0,0xff,0xe9,0x78,0x50,0x4d,0xce,0x52,0x60,0x5f,0x46,0xb7,0xc3,0xe5,0x61,0x97,0xda,0xfa,0xdb,0xe5,0x28,0xeb,0x70,0xd9,0xee,0x7e,0xa0,0xe7,0x07,0x02,0xdb,0x54,0xf7,0x21,0x51,0x4c,0x7b,0x86,0x04,0xac,0x2c,0xb2,0x14,0xf1,0xde,0xcb,0x7e,0x38,0x3d, - 0x04,0x82,0x4c,0x19,0x5c,0x73,0xcf,0xfd,0xf0,0x38,0xd1,0x01,0xbc,0xe1,0x68,0x7b,0x5c,0x3b,0x61,0x46,0xf3,0x95,0xc8,0x85,0x97,0x6f,0x77,0x53,0xb2,0x37,0x6b,0x94,0x8e,0x3c,0xde,0xfa,0x6f,0xc3,0x47,0xd1,0x3e,0x4d,0xcb,0xc6,0x3a,0x0b,0x03,0xa1,0x65,0x18,0x0c,0xd2,0xbe,0x14,0x31,0xa0,0xcf,0x74,0xce,0x1e,0xa2,0x50,0x82,0xd2,0xbc, - 0x04,0x27,0x88,0xa5,0x2f,0x07,0x8e,0xb3,0xf2,0x02,0xc4,0xfa,0x73,0xe0,0xd3,0x38,0x6f,0xaf,0x3d,0xf6,0xbe,0x85,0x60,0x03,0x63,0x6f,0x59,0x99,0x22,0xd4,0xf5,0x26,0x8f,0x30,0xb4,0xf2,0x07,0xc9,0x19,0xbb,0xdf,0x5e,0x67,0xa8,0xbe,0x42,0x65,0xa8,0x17,0x47,0x54,0xb3,0xab,0xa8,0xf1,0x6e,0x57,0x5b,0x77,0xff,0x4d,0x5a,0x7e,0xb6,0x4f, - 0x04,0xd5,0x33,0xb7,0x89,0xa4,0xaf,0x89,0x0f,0xa7,0xa8,0x2a,0x1f,0xae,0x58,0xc4,0x04,0xf9,0xa6,0x2a,0x50,0xb4,0x9a,0xda,0xfa,0xb3,0x49,0xc5,0x13,0xb4,0x15,0x08,0x74,0x01,0xb4,0x17,0x1b,0x80,0x3e,0x76,0xb3,0x4a,0x98,0x61,0xe1,0x0f,0x7b,0xc2,0x89,0xa0,0x66,0xfd,0x01,0xbd,0x29,0xf8,0x4c,0x98,0x7a,0x10,0xa5,0xfb,0x18,0xc2,0xd4, - 0x04,0x3a,0x31,0x50,0x79,0x8c,0x8a,0xf6,0x9d,0x1e,0x6e,0x98,0x1f,0x3a,0x45,0x40,0x2b,0xa1,0xd7,0x32,0xf4,0xbe,0x83,0x30,0xc5,0x16,0x4f,0x49,0xe1,0x0e,0xc5,0x55,0xb4,0x22,0x1b,0xd8,0x42,0xbc,0x5e,0x4d,0x97,0xef,0xf3,0x71,0x65,0xf6,0x0e,0x39,0x98,0xa4,0x24,0xd7,0x2a,0x45,0x0c,0xf9,0x5e,0xa4,0x77,0xc7,0x82,0x87,0xd0,0x34,0x3a, - 0x04,0x3b,0x37,0xdf,0x5f,0xb3,0x47,0xc6,0x9a,0x0f,0x17,0xd8,0x5c,0x0c,0x7c,0xa8,0x37,0x36,0x88,0x3a,0x82,0x5e,0x13,0x14,0x3d,0x0f,0xcf,0xc8,0x10,0x1e,0x85,0x1e,0x80,0x0d,0xe3,0xc0,0x90,0xb6,0xca,0x21,0xba,0x54,0x35,0x17,0x33,0x0c,0x04,0xb1,0x2f,0x94,0x8c,0x6b,0xad,0xf1,0x4a,0x63,0xab,0xff,0xdf,0x4e,0xf8,0xc7,0x53,0x70,0x26, - 0x04,0xfe,0xb5,0x16,0x3b,0x0e,0xce,0x30,0xff,0x3e,0x03,0xc7,0xd5,0x5c,0x43,0x80,0xfa,0x2f,0xa8,0x1e,0xe2,0xc0,0x35,0x49,0x42,0xff,0x6f,0x08,0xc9,0x9d,0x0c,0xd8,0x2c,0xe8,0x7d,0xe0,0x5e,0xe1,0xbd,0xa0,0x89,0xd3,0xe4,0xe2,0x48,0xfa,0x0f,0x72,0x11,0x02,0xac,0xff,0xfd,0xf5,0x0e,0x65,0x4b,0xe2,0x81,0x43,0x39,0x99,0xdf,0x89,0x7e, - 0x04,0x23,0x8c,0xed,0x00,0x1c,0xf2,0x2b,0x88,0x53,0xe0,0x2e,0xdc,0x89,0xcb,0xec,0xa5,0x05,0x0b,0xa7,0xe0,0x42,0xa7,0xa7,0x7f,0x93,0x82,0xcd,0x41,0x49,0x22,0x89,0x76,0x40,0x68,0x3d,0x30,0x94,0x64,0x38,0x40,0xf2,0x95,0x89,0x0a,0xa4,0xc1,0x8a,0xa3,0x9b,0x41,0xd7,0x7d,0xd0,0xfb,0x3b,0xb2,0x70,0x0e,0x4f,0x9e,0xc2,0x84,0xff,0xc2, - 0x04,0x96,0x1c,0xf6,0x48,0x17,0xc0,0x6c,0x0e,0x51,0xb3,0xc2,0x73,0x6c,0x92,0x2f,0xde,0x18,0xbd,0x8c,0x49,0x06,0xfc,0xd7,0xf5,0xef,0x66,0xc4,0x67,0x85,0x08,0xf3,0x5e,0xd2,0xc5,0xd1,0x81,0x68,0xcf,0xbe,0x70,0xf2,0xf1,0x23,0xbd,0x74,0x19,0x23,0x2b,0xb9,0x2d,0xd6,0x91,0x13,0xe2,0x94,0x10,0x61,0x88,0x94,0x81,0xc5,0xa0,0x27,0xbf, - 0x04,0x13,0x68,0x1e,0xae,0x16,0x8c,0xd4,0xea,0x7c,0xf2,0xe2,0xa4,0x5d,0x05,0x27,0x42,0xd1,0x0a,0x9f,0x64,0xe7,0x96,0x86,0x7d,0xbd,0xcb,0x82,0x9f,0xe0,0xb1,0x02,0x88,0x16,0x52,0x87,0x60,0xd1,0x77,0x37,0x6c,0x09,0xdf,0x79,0xde,0x39,0x55,0x7c,0x32,0x9c,0xc1,0x75,0x35,0x17,0xac,0xff,0xe8,0xfa,0x2e,0xc2,0x98,0x02,0x6b,0x83,0x84, - 0x04,0x5a,0xa7,0xab,0xfd,0xb6,0xb4,0x08,0x6d,0x54,0x33,0x25,0xe5,0xd7,0x9c,0x6e,0x95,0xce,0x42,0xf8,0x66,0xd2,0xbb,0x84,0x90,0x96,0x33,0xa0,0x4b,0xb1,0xaa,0x31,0xc2,0x91,0xc8,0x00,0x88,0x79,0x49,0x05,0xe1,0xda,0x33,0x33,0x6d,0x87,0x4e,0x2f,0x91,0xcc,0xf4,0x5c,0xc5,0x91,0x85,0xbe,0xde,0x5d,0xd6,0xf3,0xf7,0xac,0xaa,0xe1,0x8b, - 0x04,0x00,0x27,0x77,0x91,0xb3,0x05,0xa4,0x5b,0x2b,0x39,0x59,0x0b,0x2f,0x05,0xd3,0x39,0x2a,0x6c,0x81,0x82,0xce,0xf4,0xeb,0x54,0x01,0x20,0xe0,0xf5,0xc2,0x06,0xc3,0xe4,0x64,0x10,0x82,0x33,0xfb,0x0b,0x8c,0x3a,0xc8,0x92,0xd7,0x9e,0xf8,0xe0,0xfb,0xf9,0x2e,0xd1,0x33,0xad,0xdb,0x45,0x54,0x27,0x01,0x32,0x58,0x4d,0xc5,0x2e,0xef,0x41, - 0x04,0x6e,0xfa,0x09,0x2b,0x68,0xde,0x94,0x60,0xf0,0xbc,0xc9,0x19,0x00,0x5a,0x5f,0x6e,0x80,0xe1,0x9d,0xe9,0x89,0x68,0xbe,0x3c,0xd2,0xc7,0x70,0xa9,0x94,0x9b,0xfb,0x1a,0xc7,0x5e,0x6e,0x50,0x87,0xd6,0x55,0x0d,0x5f,0x9b,0xeb,0x1e,0x79,0xe5,0x02,0x93,0x07,0xbc,0x25,0x52,0x35,0xe2,0xd5,0xdc,0x99,0x24,0x1a,0xc3,0xab,0x88,0x6c,0x49, - 0x04,0x72,0xd4,0xa1,0x9c,0x4f,0x9d,0x2c,0xf5,0x84,0x8e,0xa4,0x04,0x45,0xb7,0x0d,0x46,0x96,0xb5,0xf0,0x2d,0x63,0x2c,0x0c,0x65,0x4c,0xc7,0xd7,0xee,0xb0,0xc6,0xd0,0x58,0xe8,0xc4,0xcd,0x99,0x43,0xe4,0x59,0x17,0x4c,0x7a,0xc0,0x1f,0xa7,0x42,0x19,0x8e,0x47,0xe6,0xc1,0x9a,0x6b,0xdb,0x0c,0x4f,0x6c,0x23,0x78,0x31,0xc1,0xb3,0xf9,0x42, - 0x04,0x2a,0x8e,0xa2,0xf5,0x0d,0xcc,0xed,0x0c,0x21,0x75,0x75,0xbd,0xfa,0x7c,0xd4,0x7d,0x1c,0x6f,0x10,0x00,0x41,0xec,0x0e,0x35,0x51,0x27,0x94,0xc1,0xbe,0x7e,0x74,0x02,0x58,0xf8,0xc1,0x71,0x22,0xed,0x30,0x3f,0xda,0x71,0x43,0xeb,0x58,0xbe,0xde,0x70,0x29,0x5b,0x65,0x32,0x66,0x01,0x3b,0x0b,0x0e,0xbd,0x3f,0x05,0x31,0x37,0xf6,0xec, - 0x04,0x88,0xde,0x68,0x9c,0xe9,0xaf,0x1e,0x94,0xbe,0x6a,0x20,0x89,0xc8,0xa8,0xb1,0x25,0x3f,0xfd,0xbb,0x6c,0x8e,0x9c,0x86,0x24,0x9b,0xa2,0x20,0x00,0x1a,0x4a,0xd3,0xb8,0x0c,0x49,0x98,0xe5,0x48,0x42,0xf4,0x13,0xb9,0xed,0xb1,0x82,0x5a,0xcb,0xb6,0x33,0x5e,0x81,0xe4,0xd1,0x84,0xb2,0xb0,0x1c,0x8b,0xeb,0xdc,0x85,0xd1,0xf2,0x89,0x46, - 0x04,0xfe,0xa2,0xd3,0x1f,0x70,0xf9,0x0d,0x5f,0xb3,0xe0,0x0e,0x18,0x6a,0xc4,0x2a,0xb3,0xc1,0x61,0x5c,0xee,0x71,0x4e,0x0b,0x4e,0x11,0x31,0xb3,0xd4,0xd8,0x22,0x5b,0xf7,0xb0,0x37,0xa1,0x8d,0xf2,0xac,0x15,0x34,0x3f,0x30,0xf7,0x40,0x67,0xdd,0xf2,0x9e,0x81,0x7d,0x5f,0x77,0xf8,0xdc,0xe0,0x57,0x14,0xda,0x59,0xc0,0x94,0xf0,0xcd,0xa9, - 0x04,0x72,0x58,0x91,0x1e,0x3d,0x42,0x33,0x49,0x16,0x64,0x79,0xdb,0xe0,0xb8,0x34,0x1a,0xf7,0xfb,0xd0,0x3d,0x0a,0x7e,0x10,0xed,0xcc,0xb3,0x6b,0x6c,0xee,0xa5,0xa3,0xdb,0x17,0xac,0x2b,0x89,0x92,0x79,0x11,0x28,0xfa,0x3b,0x96,0xdc,0x2f,0xbd,0x4c,0xa3,0xbf,0xa7,0x82,0xef,0x28,0x32,0xfc,0x66,0x56,0x94,0x3d,0xb1,0x8e,0x73,0x46,0xb0, - 0x04,0x4f,0x28,0x46,0x1d,0xea,0x64,0x47,0x4d,0x6b,0xb3,0x4d,0x14,0x99,0xc9,0x7d,0x37,0xb9,0xe9,0x56,0x33,0xdf,0x1c,0xee,0xea,0xac,0xd4,0x50,0x16,0xc9,0x8b,0x39,0x14,0xc8,0x81,0x88,0x10,0xb8,0xcc,0x06,0xdd,0xb4,0x0e,0x8a,0x12,0x61,0xc5,0x28,0xfa,0xa5,0x89,0x45,0x5d,0x5a,0x6d,0xf9,0x3b,0x77,0xbc,0x5e,0x0e,0x49,0x3c,0x74,0x70, - 0x04,0x74,0xf2,0xa8,0x14,0xfb,0x5d,0x8e,0xca,0x91,0xa6,0x9b,0x5e,0x60,0x71,0x27,0x32,0xb3,0x93,0x7d,0xe3,0x28,0x29,0xbe,0x97,0x4e,0xd7,0xb6,0x8c,0x5c,0x2f,0x5d,0x66,0xef,0xf0,0xf0,0x7c,0x56,0xf9,0x87,0xa6,0x57,0xf4,0x21,0x96,0x20,0x5f,0x58,0x8c,0x0f,0x1d,0x96,0xfd,0x8a,0x63,0xa5,0xf2,0x38,0xb4,0x8f,0x47,0x87,0x88,0xfe,0x3b, - 0x04,0x19,0x5b,0x51,0xa7,0xcc,0x4a,0x21,0xb8,0x27,0x4a,0x70,0xa9,0x0d,0xe7,0x79,0x81,0x4c,0x3c,0x8c,0xa3,0x58,0x32,0x82,0x08,0xc0,0x9a,0x29,0xf3,0x36,0xb8,0x2d,0x6a,0xb2,0x41,0x6b,0x7c,0x92,0xff,0xfd,0xc2,0x9c,0x3b,0x12,0x82,0xdd,0x2a,0x77,0xa4,0xd0,0x4d,0xf7,0xf7,0x45,0x20,0x47,0x39,0x3d,0x84,0x99,0x89,0xc5,0xce,0xe9,0xad, - 0x04,0x62,0x2f,0xc7,0x47,0x32,0x03,0x4b,0xec,0x2d,0xdf,0x3b,0xc1,0x6d,0x34,0xb3,0xd1,0xf7,0xa3,0x27,0xdd,0x2a,0x8c,0x19,0xba,0xb4,0xbb,0x4f,0xe3,0xa2,0x4b,0x58,0xaa,0x73,0x6b,0x2f,0x2f,0xae,0x76,0xf4,0xdf,0xae,0xcc,0x90,0x96,0x33,0x3b,0x01,0x32,0x8d,0x51,0xeb,0x3f,0xda,0x9c,0x92,0x27,0xe9,0x0d,0x0b,0x44,0x99,0x83,0xc4,0xf0, - 0x04,0x1f,0x7f,0x85,0xca,0xf2,0xd7,0x55,0x0e,0x7a,0xf9,0xb6,0x50,0x23,0xeb,0xb4,0xdc,0xe3,0x45,0x03,0x11,0x69,0x23,0x09,0xdb,0x26,0x99,0x69,0xb8,0x34,0xb6,0x11,0xc7,0x08,0x27,0xf4,0x5b,0x78,0x02,0x0e,0xcb,0xba,0xf4,0x84,0xfd,0xd5,0xbf,0xaa,0xe6,0x87,0x0f,0x11,0x84,0xc2,0x15,0x81,0xba,0xf6,0xef,0x82,0xbd,0x7b,0x53,0x0f,0x93, - 0x04,0x49,0xc1,0x97,0xdc,0x80,0xad,0x1d,0xa4,0x7a,0x43,0x42,0xb9,0x38,0x93,0xe8,0xe1,0xfb,0x0b,0xb9,0x4f,0xc3,0x3a,0x83,0xe7,0x83,0xc0,0x0b,0x24,0xc7,0x81,0x37,0x7a,0xef,0xc2,0x0d,0xa9,0x2b,0xac,0x76,0x29,0x51,0xf7,0x24,0x74,0xbe,0xcc,0x73,0x4d,0x4c,0xc2,0x2b,0xa8,0x1b,0x89,0x5e,0x28,0x2f,0xda,0xc4,0xdf,0x7a,0xf0,0xf3,0x7d, - 0x04,0xd8,0xcb,0x68,0x51,0x7b,0x61,0x6a,0x56,0x40,0x0a,0xa3,0x86,0x86,0x35,0xe5,0x4b,0x6f,0x69,0x95,0x98,0xa2,0xf6,0x16,0x77,0x57,0x65,0x49,0x80,0xba,0xf6,0xac,0xbe,0x7e,0xc8,0xcf,0x44,0x9c,0x84,0x9a,0xa0,0x34,0x61,0xa3,0x0e,0xfa,0xda,0x41,0x45,0x3c,0x57,0xc6,0xe6,0xfb,0xc9,0x3b,0xbc,0x6f,0xa4,0x9a,0xda,0x6d,0xc0,0x55,0x5c, - 0x04,0x03,0x07,0x13,0xfb,0x63,0xf2,0xaa,0x6f,0xe2,0xca,0xdf,0x1b,0x20,0xef,0xc2,0x59,0xc7,0x74,0x45,0xda,0xfa,0x87,0xda,0xc3,0x98,0xb8,0x40,0x65,0xca,0x34,0x7d,0xf3,0xb2,0x27,0x81,0x8d,0xe1,0xa3,0x9b,0x58,0x9c,0xb0,0x71,0xd8,0x3e,0x53,0x17,0xcc,0xcd,0xc2,0x33,0x8e,0x51,0xe3,0x12,0xfe,0x31,0xd8,0xdc,0x34,0xa4,0x80,0x17,0x50, - 0x04,0xba,0xbb,0x36,0x77,0xb0,0x95,0x58,0x02,0xd8,0xe9,0x29,0xa4,0x13,0x55,0x64,0x0e,0xaf,0x1e,0xa1,0x35,0x3f,0x8a,0x77,0x13,0x31,0xc4,0x94,0x6e,0x34,0x80,0xaf,0xa7,0x25,0x2f,0x19,0x6c,0x87,0xed,0x3d,0x2a,0x59,0xd3,0xb1,0xb5,0x59,0x13,0x7f,0xed,0x00,0x13,0xfe,0xce,0xfc,0x19,0xfb,0x5a,0x92,0x68,0x2b,0x9b,0xca,0x51,0xb9,0x50, - 0x04,0x1a,0xab,0x20,0x18,0x79,0x34,0x71,0x11,0x1a,0x8a,0x0e,0x9b,0x14,0x3f,0xde,0x02,0xfc,0x95,0x92,0x07,0x96,0xd3,0xa6,0x3d,0xe3,0x29,0xb4,0x24,0x39,0x6f,0xba,0x60,0xbb,0xe4,0x13,0x07,0x05,0x17,0x47,0x92,0x44,0x1b,0x31,0x8d,0x3a,0xa3,0x1d,0xfe,0x85,0x77,0x82,0x1e,0x9b,0x44,0x6e,0xc5,0x73,0xd2,0x72,0xe0,0x36,0xc4,0xeb,0xe9, - 0x04,0x8c,0xb0,0xb9,0x09,0x49,0x9c,0x83,0xea,0x80,0x6c,0xd8,0x85,0xb1,0xdd,0x46,0x7a,0x01,0x19,0xf0,0x6a,0x88,0xa0,0x27,0x6e,0xb0,0xcf,0xda,0x27,0x45,0x35,0xa8,0xff,0x47,0xb5,0x42,0x88,0x33,0xbc,0x3f,0x2c,0x8b,0xf9,0xd9,0x04,0x11,0x58,0xcf,0x33,0x71,0x8a,0x69,0x96,0x1c,0xd0,0x17,0x29,0xbc,0x00,0x11,0xd1,0xe5,0x86,0xab,0x75, - 0x04,0x8f,0x03,0xcf,0x1a,0x42,0x27,0x2b,0xb1,0x53,0x27,0x23,0x09,0x3f,0x72,0xe6,0xfe,0xea,0xc8,0x5e,0x17,0x00,0xe9,0xfb,0xe9,0xa6,0xa2,0xdd,0x64,0x2d,0x74,0xbf,0x5d,0x3b,0x89,0xa7,0x18,0x9d,0xad,0x8c,0xf7,0x5f,0xc2,0x2f,0x6f,0x15,0x8a,0xa2,0x7f,0x9c,0x2c,0xa0,0x0d,0xac,0xa7,0x85,0xbe,0x33,0x58,0xf2,0xbd,0xa3,0x86,0x2c,0xa0, - 0x04,0x44,0xde,0x3b,0x9c,0x7a,0x57,0xa8,0xc9,0xe8,0x20,0x95,0x27,0x53,0x42,0x1e,0x7d,0x98,0x7b,0xb3,0xd7,0x9f,0x71,0xf0,0x13,0x80,0x5c,0x89,0x7e,0x01,0x8f,0x8a,0xce,0xa2,0x46,0x07,0x58,0xc8,0xf9,0x8d,0x3f,0xdc,0xe1,0x21,0xa9,0x43,0x65,0x9e,0x37,0x2c,0x32,0x6f,0xff,0x2e,0x5f,0xc2,0xae,0x7f,0xa3,0xf7,0x9d,0xaa,0xe1,0x3c,0x12, - 0x04,0x6f,0xb8,0xb2,0xb4,0x8e,0x33,0x03,0x12,0x68,0xad,0x6a,0x51,0x74,0x84,0xdc,0x88,0x39,0xea,0x90,0xf6,0x66,0x9e,0xa0,0xc7,0xac,0x32,0x33,0xe2,0xac,0x31,0x39,0x4a,0x0a,0xc8,0xbb,0xe7,0xf7,0x3c,0x2f,0xf4,0xdf,0x99,0x78,0x72,0x7a,0xc1,0xdf,0xc2,0xfd,0x58,0x64,0x7d,0x20,0xf3,0x1f,0x99,0x10,0x53,0x16,0xb6,0x46,0x71,0xf2,0x04, - 0x04,0xbe,0xa7,0x11,0x22,0xa0,0x48,0x69,0x3e,0x90,0x5f,0xf6,0x02,0xb3,0xcf,0x9d,0xd1,0x8a,0xf6,0x9b,0x9f,0xc9,0xd8,0x43,0x1d,0x2b,0x1d,0xd2,0x6b,0x94,0x2c,0x95,0xe6,0xf4,0x3c,0x7b,0x8b,0x95,0xeb,0x62,0x08,0x2c,0x12,0xdb,0x9d,0xbd,0xa7,0xfe,0x38,0xe4,0x5c,0xbe,0x4a,0x48,0x86,0x90,0x7f,0xb8,0x1b,0xdb,0x0c,0x5e,0xa9,0x24,0x6c, - 0x04,0xda,0x91,0x8c,0x73,0x1b,0xa0,0x6a,0x20,0xcb,0x94,0xef,0x33,0xb7,0x78,0xe9,0x81,0xa4,0x04,0xa3,0x05,0xf1,0x94,0x1f,0xe3,0x36,0x66,0xb4,0x5b,0x03,0x35,0x31,0x56,0xe2,0xbb,0x26,0x94,0xf5,0x75,0xb4,0x51,0x83,0xbe,0x78,0xe5,0xc9,0xb5,0x21,0x0b,0xf3,0xbf,0x48,0x8f,0xd4,0xc8,0x29,0x45,0x16,0xd8,0x95,0x72,0xca,0x4f,0x53,0x91, - 0x04,0x30,0x07,0xe9,0x2c,0x39,0x37,0xda,0xde,0x79,0x64,0xdf,0xa3,0x5b,0x0e,0xff,0x03,0x1f,0x7e,0xb0,0x2a,0xed,0x0a,0x03,0x14,0x41,0x11,0x06,0xcd,0xeb,0x70,0xfe,0x3d,0x5a,0x75,0x46,0xfc,0x05,0x52,0x99,0x7b,0x20,0xe3,0xd6,0xf4,0x13,0xe7,0x5e,0x2c,0xb6,0x6e,0x11,0x63,0x22,0x69,0x71,0x14,0xb7,0x9b,0xac,0x73,0x4b,0xfc,0x4d,0xc5, - 0x04,0x60,0xe7,0x34,0xef,0x56,0x24,0xd3,0xcb,0xf0,0xdd,0xd3,0x75,0x01,0x1b,0xd6,0x63,0xd6,0xd6,0xae,0xbc,0x64,0x4e,0xb5,0x99,0xfd,0xf9,0x8d,0xbd,0xcd,0x18,0xce,0x9b,0xd2,0xd9,0x0b,0x3a,0xc3,0x1f,0x13,0x9a,0xf8,0x32,0xcc,0xcf,0x6c,0xcb,0xbb,0x2c,0x6e,0xa1,0x1f,0xa9,0x73,0x70,0xdc,0x99,0x06,0xda,0x47,0x4d,0x7d,0x8a,0x75,0x67, - 0x04,0x85,0xa9,0x00,0xe9,0x78,0x58,0xf6,0x93,0xc0,0xb7,0xdf,0xa2,0x61,0xe3,0x80,0xda,0xd6,0xea,0x04,0x6d,0x1f,0x65,0xdd,0xee,0xed,0xd5,0xf7,0xd8,0xaf,0x0b,0xa3,0x37,0x69,0x74,0x4d,0x15,0xad,0xd4,0xf6,0xc0,0xbc,0x3b,0x0d,0xa2,0xae,0xc9,0x3b,0x34,0xcb,0x8c,0x65,0xf9,0x34,0x0d,0xdf,0x74,0xe7,0xb0,0x00,0x9e,0xee,0xcc,0xce,0x3c, - 0x04,0x38,0x06,0x6f,0x75,0xd8,0x8e,0xfc,0x4c,0x93,0xde,0x36,0xf4,0x9e,0x03,0x7b,0x23,0x4c,0xc1,0x8b,0x1d,0xe5,0x60,0x87,0x50,0xa6,0x2c,0xab,0x03,0x45,0x40,0x10,0x46,0xa3,0xe8,0x4b,0xed,0x8c,0xfc,0xb8,0x19,0xef,0x4d,0x55,0x04,0x44,0xf2,0xce,0x4b,0x65,0x17,0x66,0xb6,0x9e,0x2e,0x29,0x01,0xf8,0x88,0x36,0xff,0x90,0x03,0x4f,0xed, - 0x04,0x98,0xf6,0x81,0x77,0xdc,0x95,0xc1,0xb4,0xcb,0xfa,0x52,0x45,0x48,0x8c,0xa5,0x23,0xa7,0xd5,0x62,0x94,0x70,0xd0,0x35,0xd6,0x21,0xa4,0x43,0xc7,0x2f,0x39,0xaa,0xbf,0xa3,0x3d,0x29,0x54,0x6f,0xa1,0xc6,0x48,0xf2,0xc7,0xd5,0xcc,0xf7,0x0c,0xf1,0xce,0x4a,0xb7,0x9b,0x5d,0xb1,0xac,0x05,0x9d,0xbe,0xcd,0x06,0x8d,0xbd,0xff,0x1b,0x89, - 0x04,0x5c,0x2b,0xbf,0xa2,0x3c,0x9b,0x9a,0xd0,0x7f,0x03,0x8a,0xa8,0x9b,0x49,0x30,0xbf,0x26,0x7d,0x94,0x01,0xe4,0x25,0x5d,0xe9,0xe8,0xda,0x0a,0x50,0x78,0xec,0x82,0x77,0xe3,0xe8,0x82,0xa3,0x1d,0x5e,0x6a,0x37,0x9e,0x07,0x93,0x98,0x3c,0xcd,0xed,0x39,0xb9,0x5c,0x43,0x53,0xab,0x2f,0xf0,0x1e,0xa5,0x36,0x9b,0xa4,0x7b,0x0c,0x31,0x91, - 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0x35,0x47,0x80,0x82,0x98,0x44,0x8e,0xdb,0x5e,0x70,0x1a,0xde,0x84,0xcd,0x5f,0xb1,0xac,0x95,0x67,0xba,0x5e,0x8f,0xb6,0x8a,0x6b,0x93,0x3e,0xc4,0xb5,0xcc,0x84,0xcc, - 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0xca,0xb8,0x7f,0x7d,0x67,0xbb,0x71,0x24,0xa1,0x8f,0xe5,0x21,0x7b,0x32,0xa0,0x4e,0x53,0x6a,0x98,0x45,0xa1,0x70,0x49,0x75,0x94,0x6c,0xc1,0x3a,0x4a,0x33,0x77,0x63, - 0x04,0x8a,0xa2,0xc6,0x4f,0xa9,0xc6,0x43,0x75,0x63,0xab,0xfb,0xcb,0xd0,0x0b,0x20,0x48,0xd4,0x8c,0x18,0xc1,0x52,0xa2,0xa6,0xf4,0x90,0x36,0xde,0x76,0x47,0xeb,0xe8,0x2e,0x1c,0xe6,0x43,0x87,0x99,0x5c,0x68,0xa0,0x60,0xfa,0x3b,0xc0,0x39,0x9b,0x05,0xcc,0x06,0xee,0xc7,0xd5,0x98,0xf7,0x50,0x41,0xa4,0x91,0x7e,0x69,0x2b,0x7f,0x51,0xff, - 0x04,0x39,0x14,0x27,0xff,0x7e,0xe7,0x80,0x13,0xc1,0x4a,0xec,0x7d,0x96,0xa8,0xa0,0x62,0x20,0x92,0x98,0xa7,0x83,0x83,0x5e,0x94,0xfd,0x65,0x49,0xd5,0x02,0xff,0xf7,0x1f,0xdd,0x66,0x24,0xec,0x34,0x3a,0xd9,0xfc,0xf4,0xd9,0x87,0x21,0x81,0xe5,0x9f,0x84,0x2f,0x9b,0xa4,0xcc,0xca,0xe0,0x9a,0x6c,0x09,0x72,0xfb,0x6a,0xc6,0xb4,0xc6,0xbd, - 0x04,0xe7,0x62,0xb8,0xa2,0x19,0xb4,0xf1,0x80,0x21,0x9c,0xc7,0xa9,0x05,0x92,0x45,0xe4,0x96,0x1b,0xd1,0x91,0xc0,0x38,0x99,0x78,0x9c,0x7a,0x34,0xb8,0x9e,0x8c,0x13,0x8e,0xc1,0x53,0x3e,0xf0,0x41,0x9b,0xb7,0x37,0x6e,0x0b,0xfd,0xe9,0x31,0x9d,0x10,0xa0,0x69,0x68,0x79,0x1d,0x9e,0xa0,0xee,0xd9,0xc1,0xce,0x63,0x45,0xae,0xd9,0x75,0x9e, - 0x04,0x9a,0xed,0xb0,0xd2,0x81,0xdb,0x16,0x4e,0x13,0x00,0x00,0xc5,0x69,0x7f,0xae,0x0f,0x30,0x5e,0xf8,0x48,0xbe,0x6f,0xff,0xb4,0x3a,0xc5,0x93,0xfb,0xb9,0x50,0xe9,0x52,0xfa,0x6f,0x63,0x33,0x59,0xbd,0xcd,0x82,0xb5,0x6b,0x0b,0x9f,0x96,0x5b,0x03,0x77,0x89,0xd4,0x6b,0x9a,0x81,0x41,0xb7,0x91,0xb2,0xae,0xfa,0x71,0x3f,0x96,0xc1,0x75, - 0x04,0x8a,0xd4,0x45,0xdb,0x62,0x81,0x62,0x60,0xe4,0xe6,0x87,0xfd,0x18,0x84,0xe4,0x8b,0x9f,0xc0,0x63,0x6d,0x03,0x15,0x47,0xd6,0x33,0x15,0xe7,0x92,0xe1,0x9b,0xfa,0xee,0x1d,0xe6,0x4f,0x99,0xd5,0xf1,0xcd,0x8b,0x6e,0xc9,0xcb,0x0f,0x78,0x7a,0x65,0x4a,0xe8,0x69,0x93,0xba,0x3d,0xb1,0x00,0x8e,0xf4,0x3c,0xff,0x06,0x84,0xcb,0x22,0xbd, - 0x04,0x1f,0x57,0x99,0xc9,0x5b,0xe8,0x90,0x63,0xb2,0x4f,0x26,0xe4,0x0c,0xb9,0x28,0xc1,0xa8,0x68,0xa7,0x6f,0xb0,0x09,0x46,0x07,0xe8,0x04,0x3d,0xb4,0x09,0xc9,0x1c,0x32,0xe7,0x57,0x24,0xe8,0x13,0xa4,0x19,0x1e,0x3a,0x83,0x90,0x07,0xf0,0x8e,0x2e,0x89,0x73,0x88,0xb0,0x6d,0x4a,0x00,0xde,0x6d,0xe6,0x0e,0x53,0x6d,0x91,0xfa,0xb5,0x66, - 0x04,0xa3,0x33,0x1a,0x4e,0x1b,0x42,0x23,0xec,0x2c,0x02,0x7e,0xdd,0x48,0x2c,0x92,0x8a,0x14,0xed,0x35,0x8d,0x93,0xf1,0xd4,0x21,0x7d,0x39,0xab,0xf6,0x9f,0xcb,0x5c,0xcc,0x28,0xd6,0x84,0xd2,0xaa,0xab,0xcd,0x63,0x83,0x77,0x5c,0xaa,0x62,0x39,0xde,0x26,0xd4,0xc6,0x93,0x7b,0xb6,0x03,0xec,0xb4,0x19,0x60,0x82,0xf4,0xcf,0xfd,0x50,0x9d, - 0x04,0x3f,0x39,0x52,0x19,0x97,0x74,0xc7,0xcf,0x39,0xb3,0x8b,0x66,0xcb,0x10,0x42,0xa6,0x26,0x0d,0x86,0x80,0x80,0x38,0x45,0xe4,0xd4,0x33,0xad,0xba,0x3b,0xb2,0x48,0x18,0x5e,0xa4,0x95,0xb6,0x8c,0xbc,0x7e,0xd4,0x17,0x3e,0xe6,0x3c,0x90,0x42,0xdc,0x50,0x26,0x25,0xc7,0xeb,0x7e,0x21,0xfb,0x02,0xca,0x9a,0x91,0x14,0xe0,0xa3,0xa1,0x8d, - 0x04,0xcd,0xfb,0x8c,0x0f,0x42,0x2e,0x14,0x4e,0x13,0x7c,0x24,0x12,0xc8,0x6c,0x17,0x1f,0x5f,0xe3,0xfa,0x3f,0x5b,0xbb,0x54,0x4e,0x90,0x76,0x28,0x8f,0x3c,0xed,0x78,0x6e,0x05,0x4f,0xd0,0x72,0x1b,0x77,0xc1,0x1c,0x79,0xbe,0xac,0xb3,0xc9,0x42,0x11,0xb0,0xa1,0x9b,0xda,0x08,0x65,0x2e,0xfe,0xaf,0x92,0x51,0x3a,0x3b,0x0a,0x16,0x36,0x98, - 0x04,0x73,0x59,0x8a,0x6a,0x1c,0x68,0x27,0x8f,0xa6,0xbf,0xd0,0xce,0x40,0x64,0xe6,0x82,0x35,0xbc,0x1c,0x0f,0x6b,0x20,0xa9,0x28,0x10,0x8b,0xe3,0x36,0x73,0x0f,0x87,0xe3,0xcb,0xae,0x61,0x25,0x19,0xb5,0x03,0x2e,0xcc,0x85,0xae,0xd8,0x11,0x27,0x1a,0x95,0xfe,0x79,0x39,0xd5,0xd3,0x46,0x01,0x40,0xba,0x31,0x8f,0x4d,0x14,0xab,0xa3,0x1d, - 0x04,0x58,0xde,0xbd,0x9a,0x7e,0xe2,0xc9,0xd5,0x91,0x32,0x47,0x8a,0x54,0x40,0xae,0x4d,0x5d,0x7e,0xd4,0x37,0x30,0x83,0x69,0xf9,0x2e,0xa8,0x6c,0x82,0x18,0x3f,0x10,0xa1,0x67,0x73,0xe7,0x6f,0x5e,0xdb,0xf4,0xda,0x0e,0x4f,0x1b,0xdf,0xfa,0xc0,0xf5,0x72,0x57,0xe1,0xdf,0xa4,0x65,0x84,0x29,0x31,0x30,0x9a,0x24,0x24,0x5f,0xda,0x6a,0x5d, - 0x04,0x8b,0x90,0x4d,0xe4,0x79,0x67,0x34,0x0c,0x5f,0x8c,0x35,0x72,0xa7,0x20,0x92,0x4e,0xf7,0x57,0x86,0x37,0xfe,0xab,0x19,0x49,0xac,0xb2,0x41,0xa5,0xa6,0xac,0x3f,0x5b,0x95,0x09,0x04,0x49,0x6f,0x98,0x24,0xb1,0xd6,0x3f,0x33,0x13,0xba,0xe2,0x1b,0x89,0xfa,0xe8,0x9a,0xfd,0xfc,0x81,0x1b,0x5e,0xce,0x03,0xfd,0x5a,0xa3,0x01,0x86,0x4f, - 0x04,0xf4,0x89,0x2b,0x6d,0x52,0x5c,0x77,0x1e,0x03,0x5f,0x2a,0x25,0x27,0x08,0xf3,0x78,0x4e,0x48,0x23,0x86,0x04,0xb4,0xf9,0x4d,0xc5,0x6e,0xaa,0x1e,0x54,0x6d,0x94,0x1a,0x34,0x6b,0x1a,0xa0,0xbc,0xe6,0x8b,0x1c,0x50,0xe5,0xb5,0x2f,0x50,0x9f,0xb5,0x52,0x2e,0x5c,0x25,0xe0,0x28,0xbc,0x8f,0x86,0x34,0x02,0xed,0xb7,0xbc,0xad,0x8b,0x1b, - 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4,0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,0xd4,0xb8, - 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0xb7,0xc5,0x25,0x88,0xd9,0x5c,0x3b,0x9a,0xa2,0x5b,0x04,0x03,0xf1,0xee,0xf7,0x57,0x02,0xe8,0x4b,0xb7,0x59,0x7a,0xab,0xe6,0x63,0xb8,0x2f,0x6f,0x04,0xef,0x27,0x77, - 0x04,0x78,0x2c,0x8e,0xd1,0x7e,0x3b,0x2a,0x78,0x3b,0x54,0x64,0xf3,0x3b,0x09,0x65,0x2a,0x71,0xc6,0x78,0xe0,0x5e,0xc5,0x1e,0x84,0xe2,0xbc,0xfc,0x66,0x3a,0x3d,0xe9,0x63,0xaf,0x9a,0xcb,0x42,0x80,0xb8,0xc7,0xf7,0xc4,0x2f,0x4e,0xf9,0xab,0xa6,0x24,0x5e,0xc1,0xec,0x17,0x12,0xfd,0x38,0xa0,0xfa,0x96,0x41,0x8d,0x8c,0xd6,0xaa,0x61,0x52, - 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0x00,0x00,0x00,0x01,0x06,0x04,0x92,0xd5,0xa5,0x67,0x3e,0x0f,0x25,0xd8,0xd5,0x0f,0xb7,0xe5,0x8c,0x49,0xd8,0x6d,0x46,0xd4,0x21,0x69,0x55,0xe0,0xaa,0x3d,0x40,0xe1, - 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfb,0x6d,0x2a,0x5a,0x98,0xc1,0xf0,0xda,0x27,0x2a,0xf0,0x48,0x1a,0x73,0xb6,0x27,0x92,0xb9,0x2b,0xde,0x96,0xaa,0x1e,0x55,0xc2,0xbb,0x4e, - 0x04,0x00,0x00,0x00,0x01,0x3f,0xd2,0x22,0x48,0xd6,0x4d,0x95,0xf7,0x3c,0x29,0xb4,0x8a,0xb4,0x86,0x31,0x85,0x0b,0xe5,0x03,0xfd,0x00,0xf8,0x46,0x8b,0x5f,0x0f,0x70,0xe0,0xf6,0xee,0x7a,0xa4,0x3b,0xc2,0xc6,0xfd,0x25,0xb1,0xd8,0x26,0x92,0x41,0xcb,0xdd,0x9d,0xbb,0x0d,0xac,0x96,0xdc,0x96,0x23,0x1f,0x43,0x07,0x05,0xf8,0x38,0x71,0x7d, - 0x04,0x25,0xaf,0xd6,0x89,0xac,0xab,0xae,0xd6,0x7c,0x1f,0x29,0x6d,0xe5,0x94,0x06,0xf8,0xc5,0x50,0xf5,0x71,0x46,0xa0,0xb4,0xec,0x2c,0x97,0x87,0x6d,0xff,0xff,0xff,0xff,0xfa,0x46,0xa7,0x6e,0x52,0x03,0x22,0xdf,0xbc,0x49,0x1e,0xc4,0xf0,0xcc,0x19,0x74,0x20,0xfc,0x4e,0xa5,0x88,0x3d,0x8f,0x6d,0xd5,0x3c,0x35,0x4b,0xc4,0xf6,0x7c,0x35, - 0x04,0xd1,0x2e,0x6c,0x66,0xb6,0x77,0x34,0xc3,0xc8,0x4d,0x26,0x01,0xcf,0x5d,0x35,0xdc,0x09,0x7e,0x27,0x63,0x7f,0x0a,0xca,0x4a,0x4f,0xdb,0x74,0xb6,0xaa,0xdd,0x3b,0xb9,0x3f,0x5b,0xdf,0xf8,0x8b,0xd5,0x73,0x6d,0xf8,0x98,0xe6,0x99,0x00,0x6e,0xd7,0x50,0xf1,0x1c,0xf0,0x7c,0x58,0x66,0xcd,0x7a,0xd7,0x0c,0x71,0x21,0xff,0xff,0xff,0xff, - 0x04,0x6d,0x4a,0x7f,0x60,0xd4,0x77,0x4a,0x4f,0x0a,0xa8,0xbb,0xde,0xdb,0x95,0x3c,0x7e,0xea,0x79,0x09,0x40,0x7e,0x31,0x64,0x75,0x56,0x64,0xbc,0x28,0x00,0x00,0x00,0x00,0xe6,0x59,0xd3,0x4e,0x4d,0xf3,0x8d,0x9e,0x8c,0x9e,0xaa,0xdf,0xba,0x36,0x61,0x2c,0x76,0x91,0x95,0xbe,0x86,0xc7,0x7a,0xac,0x3f,0x36,0xe7,0x8b,0x53,0x86,0x80,0xfb}; - -static const unsigned char wycheproof_ecdsa_signatures[] = { 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x00,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7d,0xb3,0x7c,0x21,0xf4,0xaf,0xd3,0x20,0x3a,0xe8,0xdc,0x4a,0xe7,0x79,0x4b,0x0f,0x87, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x81,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x82,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x85,0x01,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x84,0x7f,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x84,0x80,0x00,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x84,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x85,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x47,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, - 0x30,0x4a,0x49,0x81,0x77,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x25,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, - 0x30,0x4d,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x22,0x29,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x28,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x81, - 0x30,0x4b,0xaa,0x02,0xaa,0xbb,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x80,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x80,0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x05,0x00, - 0x2e,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x2f,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x32,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0xff,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x00, - 0x30,0x49,0x30,0x01,0x02,0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, - 0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x82,0x10,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,0x00,0x00, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x06,0x08,0x11,0x22,0x00,0x00, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0xfe,0x02,0xbe,0xef, - 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x02,0xbe,0xef, - 0x30,0x47,0x30,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x30,0x00, - 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x01,0x00, - 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xbf,0x7f,0x00, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x02,0x05,0x00, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x00, - 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65, - 0x30,0x67,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x64,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xca,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x13,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x08,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x81,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x82,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4a,0x02,0x85,0x01,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4e,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x84,0x7f,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x84,0x80,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x84,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4a,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x80,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x23,0x02,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x24,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02, - 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x23,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4a,0x22,0x26,0x49,0x81,0x77,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x22,0x25,0x25,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x22,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x04,0xde,0xad,0xbe,0xef,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x24,0x02,0x81,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4b,0x22,0x27,0xaa,0x02,0xaa,0xbb,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x22,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x22,0x80,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x24,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x01,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x04,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0xff,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x24,0x02,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x22,0x25,0x02,0x01,0x00,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x02,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0xe5,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x82,0x10,0x48,0x02,0x82,0x10,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x22,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x25,0x09,0x01,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x25,0x02,0x01,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xbb, - 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa4,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf7,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x01,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0x01,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4e,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x7f,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x80,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x80,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, - 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x25,0x49,0x81,0x77,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x25,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, - 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81, - 0x30,0x4b,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x26,0xaa,0x02,0xaa,0xbb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, - 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x01,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x04,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0xff,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x00, - 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x02,0x01,0x6f,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6d,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0x3a, - 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, - 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x82,0x10,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x10,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x09,0x01,0x80, - 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x01,0x00, - 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x83,0xb9,0x0d,0xea,0xbc,0xa4,0xb0,0x5c,0x45,0x74,0xe4,0x9b,0x58,0x99,0xb9,0x64,0xa6,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x86,0x43,0xb0,0x30,0xef,0x46,0x1f,0x1b,0xcd,0xf5,0x3f,0xde,0x3e,0xf9,0x4c,0xe2,0x24,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x22,0x01,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x84,0x3f,0xad,0x3b,0xf4,0x85,0x3e,0x07,0xf7,0xc9,0x87,0x70,0xc9,0x9b,0xff,0xc4,0x64,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0xff,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7b,0x01,0xa0,0xf2,0x2a,0x0a,0x98,0x43,0xf6,0x4a,0xed,0xc3,0x34,0x36,0x7c,0xdc,0x9b,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x20,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x79,0xbc,0x4f,0xcf,0x10,0xb9,0xe0,0xe4,0x32,0x0a,0xc0,0x21,0xc1,0x06,0xb3,0x1d,0xdc,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0xfe,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7c,0x46,0xf2,0x15,0x43,0x5b,0x4f,0xa3,0xba,0x8b,0x1b,0x64,0xa7,0x66,0x46,0x9b,0x5a,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x7f,0xc1,0xe1,0x97,0xd8,0xae,0xbe,0x20,0x3c,0x96,0xc8,0x72,0x32,0x27,0x21,0x72,0xfb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x82,0x4c,0x83,0xde,0x0b,0x50,0x2c,0xdf,0xc5,0x17,0x23,0xb5,0x18,0x86,0xb4,0xf0,0x79,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x46,0x02,0x22,0x01,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9a,0x3b,0xb6,0x0f,0xa1,0xa1,0x48,0x15,0xbb,0xc0,0xa9,0x54,0xa0,0x75,0x8d,0x2c,0x72,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x44,0x02,0x20,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7e,0xf8,0xcd,0x45,0x0e,0x00,0x8a,0x7f,0xff,0x29,0x09,0xec,0x5a,0xa9,0x14,0xce,0x46,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0xfe,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x80,0x3e,0x1e,0x68,0x27,0x51,0x41,0xdf,0xc3,0x69,0x37,0x8d,0xcd,0xd8,0xde,0x8d,0x05,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, - 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x00, - 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x01, - 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0xff, - 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x00, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0xff, - 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x00, - 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x01, - 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0xff, - 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0xff, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0xff, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0xff, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0xff, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0xff, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, - 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, - 0x30,0x08,0x02,0x01,0x00,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x06,0x02,0x01,0x00,0x09,0x01,0x42, - 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x01, - 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x00, - 0x30,0x05,0x02,0x01,0x00,0x05,0x00, - 0x30,0x05,0x02,0x01,0x00,0x0c,0x00, - 0x30,0x06,0x02,0x01,0x00,0x0c,0x01,0x30, - 0x30,0x05,0x02,0x01,0x00,0x30,0x00, - 0x30,0x08,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, - 0x30,0x08,0x02,0x01,0x01,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x06,0x02,0x01,0x01,0x09,0x01,0x42, - 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x01, - 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x00, - 0x30,0x05,0x02,0x01,0x01,0x05,0x00, - 0x30,0x05,0x02,0x01,0x01,0x0c,0x00, - 0x30,0x06,0x02,0x01,0x01,0x0c,0x01,0x30, - 0x30,0x05,0x02,0x01,0x01,0x30,0x00, - 0x30,0x08,0x02,0x01,0x01,0x30,0x03,0x02,0x01,0x00, - 0x30,0x08,0x02,0x01,0xff,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x06,0x02,0x01,0xff,0x09,0x01,0x42, - 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x01, - 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x00, - 0x30,0x05,0x02,0x01,0xff,0x05,0x00, - 0x30,0x05,0x02,0x01,0xff,0x0c,0x00, - 0x30,0x06,0x02,0x01,0xff,0x0c,0x01,0x30, - 0x30,0x05,0x02,0x01,0xff,0x30,0x00, - 0x30,0x08,0x02,0x01,0xff,0x30,0x03,0x02,0x01,0x00, - 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x01,0x42, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x00, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x05,0x00, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x01,0x30, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x00, - 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x03,0x02,0x01,0x00, - 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x01,0x42, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x01, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x00, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x05,0x00, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x00, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x01,0x30, - 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x00, - 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x03,0x02,0x01,0x00, - 0x30,0x0a,0x09,0x03,0x80,0xfe,0x01,0x09,0x03,0x80,0xfe,0x01, - 0x30,0x06,0x09,0x01,0x42,0x09,0x01,0x42, - 0x30,0x06,0x01,0x01,0x01,0x01,0x01,0x01, - 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00, - 0x30,0x04,0x05,0x00,0x05,0x00, - 0x30,0x04,0x0c,0x00,0x0c,0x00, - 0x30,0x06,0x0c,0x01,0x30,0x0c,0x01,0x30, - 0x30,0x04,0x30,0x00,0x30,0x00, - 0x30,0x0a,0x30,0x03,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, - 0x30,0x08,0x09,0x03,0x80,0xfe,0x01,0x02,0x01,0x00, - 0x30,0x06,0x09,0x01,0x42,0x02,0x01,0x00, - 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x00, - 0x30,0x06,0x01,0x01,0x00,0x02,0x01,0x00, - 0x30,0x05,0x05,0x00,0x02,0x01,0x00, - 0x30,0x05,0x0c,0x00,0x02,0x01,0x00, - 0x30,0x06,0x0c,0x01,0x30,0x02,0x01,0x00, - 0x30,0x05,0x30,0x00,0x02,0x01,0x00, - 0x30,0x08,0x30,0x03,0x02,0x01,0x00,0x02,0x01,0x00, - 0x30,0x45,0x02,0x21,0x00,0xdd,0x1b,0x7d,0x09,0xa7,0xbd,0x82,0x18,0x96,0x10,0x34,0xa3,0x9a,0x87,0xfe,0xcf,0x53,0x14,0xf0,0x0c,0x4d,0x25,0xeb,0x58,0xa0,0x7a,0xc8,0x5e,0x85,0xea,0xb5,0x16,0x02,0x20,0x35,0x13,0x8c,0x40,0x1e,0xf8,0xd3,0x49,0x3d,0x65,0xc9,0x00,0x2f,0xe6,0x2b,0x43,0xae,0xe5,0x68,0x73,0x1b,0x74,0x45,0x48,0x35,0x89,0x96,0xd9,0xcc,0x42,0x7e,0x06, - 0x30,0x45,0x02,0x21,0x00,0x95,0xc2,0x92,0x67,0xd9,0x72,0xa0,0x43,0xd9,0x55,0x22,0x45,0x46,0x22,0x2b,0xba,0x34,0x3f,0xc1,0xd4,0xdb,0x0f,0xec,0x26,0x2a,0x33,0xac,0x61,0x30,0x56,0x96,0xae,0x02,0x20,0x6e,0xdf,0xe9,0x67,0x13,0xae,0xd5,0x6f,0x8a,0x28,0xa6,0x65,0x3f,0x57,0xe0,0xb8,0x29,0x71,0x2e,0x5e,0xdd,0xc6,0x7f,0x34,0x68,0x2b,0x24,0xf0,0x67,0x6b,0x26,0x40, - 0x30,0x44,0x02,0x20,0x28,0xf9,0x4a,0x89,0x4e,0x92,0x02,0x46,0x99,0xe3,0x45,0xfe,0x66,0x97,0x1e,0x3e,0xdc,0xd0,0x50,0x02,0x33,0x86,0x13,0x5a,0xb3,0x93,0x9d,0x55,0x08,0x98,0xfb,0x25,0x02,0x20,0x32,0x96,0x3e,0x5b,0xd4,0x1f,0xa5,0x91,0x1e,0xd8,0xf3,0x7d,0xeb,0x86,0xda,0xe0,0xa7,0x62,0xbb,0x61,0x21,0xc8,0x94,0x61,0x50,0x83,0xc5,0xd9,0x5e,0xa0,0x1d,0xb3, - 0x30,0x45,0x02,0x21,0x00,0xbe,0x26,0xb1,0x8f,0x95,0x49,0xf8,0x9f,0x41,0x1a,0x9b,0x52,0x53,0x6b,0x15,0xaa,0x27,0x0b,0x84,0x54,0x8d,0x0e,0x85,0x9a,0x19,0x52,0xa2,0x7a,0xf1,0xa7,0x7a,0xc6,0x02,0x20,0x70,0xc1,0xd4,0xfa,0x9c,0xd0,0x3c,0xc8,0xea,0xa8,0xd5,0x06,0xed,0xb9,0x7e,0xed,0x7b,0x83,0x58,0xb4,0x53,0xc8,0x8a,0xef,0xbb,0x88,0x0a,0x3f,0x0e,0x8d,0x47,0x2f, - 0x30,0x45,0x02,0x21,0x00,0xb1,0xa4,0xb1,0x47,0x8e,0x65,0xcc,0x3e,0xaf,0xdf,0x22,0x5d,0x12,0x98,0xb4,0x3f,0x2d,0xa1,0x9e,0x4b,0xcf,0xf7,0xea,0xcc,0x0a,0x2e,0x98,0xcd,0x4b,0x74,0xb1,0x14,0x02,0x20,0x17,0x9a,0xa3,0x1e,0x30,0x4c,0xc1,0x42,0xcf,0x50,0x73,0x17,0x17,0x51,0xb2,0x8f,0x3f,0x5e,0x0f,0xa8,0x8c,0x99,0x4e,0x7c,0x55,0xf1,0xbc,0x07,0xb8,0xd5,0x6c,0x16, - 0x30,0x44,0x02,0x20,0x32,0x53,0x32,0x02,0x12,0x61,0xf1,0xbd,0x18,0xf2,0x71,0x2a,0xa1,0xe2,0x25,0x2d,0xa2,0x37,0x96,0xda,0x8a,0x4b,0x1f,0xf6,0xea,0x18,0xca,0xfe,0xc7,0xe1,0x71,0xf2,0x02,0x20,0x40,0xb4,0xf5,0xe2,0x87,0xee,0x61,0xfc,0x3c,0x80,0x41,0x86,0x98,0x23,0x60,0x89,0x1e,0xaa,0x35,0xc7,0x5f,0x05,0xa4,0x3e,0xcd,0x48,0xb3,0x5d,0x98,0x4a,0x66,0x48, - 0x30,0x45,0x02,0x21,0x00,0xa2,0x3a,0xd1,0x8d,0x8f,0xc6,0x6d,0x81,0xaf,0x09,0x03,0x89,0x0c,0xbd,0x45,0x3a,0x55,0x4c,0xb0,0x4c,0xdc,0x1a,0x8c,0xa7,0xf7,0xf7,0x8e,0x53,0x67,0xed,0x88,0xa0,0x02,0x20,0x23,0xe3,0xeb,0x2c,0xe1,0xc0,0x4e,0xa7,0x48,0xc3,0x89,0xbd,0x97,0x37,0x4a,0xa9,0x41,0x3b,0x92,0x68,0x85,0x1c,0x04,0xdc,0xd9,0xf8,0x8e,0x78,0x81,0x3f,0xee,0x56, - 0x30,0x44,0x02,0x20,0x2b,0xde,0xa4,0x1c,0xda,0x63,0xa2,0xd1,0x4b,0xf4,0x73,0x53,0xbd,0x20,0x88,0x0a,0x69,0x09,0x01,0xde,0x7c,0xd6,0xe3,0xcc,0x6d,0x8e,0xd5,0xba,0x0c,0xdb,0x10,0x91,0x02,0x20,0x3c,0xea,0x66,0xbc,0xcf,0xc9,0xf9,0xbf,0x8c,0x7c,0xa4,0xe1,0xc1,0x45,0x7c,0xc9,0x14,0x5e,0x13,0xe9,0x36,0xd9,0x0b,0x3d,0x9c,0x77,0x86,0xb8,0xb2,0x6c,0xf4,0xc7, - 0x30,0x45,0x02,0x21,0x00,0xd7,0xcd,0x76,0xec,0x01,0xc1,0xb1,0x07,0x9e,0xba,0x9e,0x2a,0xa2,0xa3,0x97,0x24,0x3c,0x47,0x58,0xc9,0x8a,0x1b,0xa0,0xb7,0x40,0x4a,0x34,0x0b,0x9b,0x00,0xce,0xd6,0x02,0x20,0x35,0x75,0x00,0x1e,0x19,0xd9,0x22,0xe6,0xde,0x8b,0x3d,0x6c,0x84,0xea,0x43,0xb5,0xc3,0x33,0x81,0x06,0xcf,0x29,0x99,0x01,0x34,0xe7,0x66,0x9a,0x82,0x6f,0x78,0xe6, - 0x30,0x45,0x02,0x21,0x00,0xa8,0x72,0xc7,0x44,0xd9,0x36,0xdb,0x21,0xa1,0x0c,0x36,0x1d,0xd5,0xc9,0x06,0x33,0x55,0xf8,0x49,0x02,0x21,0x96,0x52,0xf6,0xfc,0x56,0xdc,0x95,0xa7,0x13,0x9d,0x96,0x02,0x20,0x40,0x0d,0xf7,0x57,0x5d,0x97,0x56,0x21,0x0e,0x9c,0xcc,0x77,0x16,0x2c,0x6b,0x59,0x3c,0x77,0x46,0xcf,0xb4,0x8a,0xc2,0x63,0xc4,0x27,0x50,0xb4,0x21,0xef,0x4b,0xb9, - 0x30,0x45,0x02,0x21,0x00,0x9f,0xa9,0xaf,0xe0,0x77,0x52,0xda,0x10,0xb3,0x6d,0x3a,0xfc,0xd0,0xfe,0x44,0xbf,0xc4,0x02,0x44,0xd7,0x52,0x03,0x59,0x9c,0xf8,0xf5,0x04,0x7f,0xa3,0x45,0x38,0x54,0x02,0x20,0x50,0xe0,0xa7,0xc0,0x13,0xbf,0xbf,0x51,0x81,0x97,0x36,0x97,0x2d,0x44,0xb4,0xb5,0x6b,0xc2,0xa2,0xb2,0xc1,0x80,0xdf,0x6e,0xc6,0x72,0xdf,0x17,0x14,0x10,0xd7,0x7a, - 0x30,0x45,0x02,0x21,0x00,0x88,0x56,0x40,0x38,0x4d,0x0d,0x91,0x0e,0xfb,0x17,0x7b,0x46,0xbe,0x6c,0x3d,0xc5,0xca,0xc8,0x1f,0x0b,0x88,0xc3,0x19,0x0b,0xb6,0xb5,0xf9,0x9c,0x26,0x41,0xf2,0x05,0x02,0x20,0x73,0x8e,0xd9,0xbf,0xf1,0x16,0x30,0x6d,0x9c,0xaa,0x0f,0x8f,0xc6,0x08,0xbe,0x24,0x3e,0x0b,0x56,0x77,0x79,0xd8,0xda,0xb0,0x3e,0x8e,0x19,0xd5,0x53,0xf1,0xdc,0x8e, - 0x30,0x44,0x02,0x20,0x2d,0x05,0x1f,0x91,0xc5,0xa9,0xd4,0x40,0xc5,0x67,0x69,0x85,0x71,0x04,0x83,0xbc,0x4f,0x1a,0x6c,0x61,0x1b,0x10,0xc9,0x5a,0x2f,0xf0,0x36,0x3d,0x90,0xc2,0xa4,0x58,0x02,0x20,0x6d,0xdf,0x94,0xe6,0xfb,0xa5,0xbe,0x58,0x68,0x33,0xd0,0xc5,0x3c,0xf2,0x16,0xad,0x39,0x48,0xf3,0x79,0x53,0xc2,0x6c,0x1c,0xf4,0x96,0x8e,0x9a,0x9e,0x82,0x43,0xdc, - 0x30,0x45,0x02,0x21,0x00,0xf3,0xac,0x25,0x23,0x96,0x74,0x82,0xf5,0x3d,0x50,0x85,0x22,0x71,0x2d,0x58,0x3f,0x43,0x79,0xcd,0x82,0x41,0x01,0xff,0x63,0x5e,0xa0,0x93,0x51,0x17,0xba,0xa5,0x4f,0x02,0x20,0x27,0xf1,0x08,0x12,0x22,0x73,0x97,0xe0,0x2c,0xea,0x96,0xfb,0x0e,0x68,0x07,0x61,0x63,0x6d,0xab,0x2b,0x08,0x0d,0x1f,0xc5,0xd1,0x16,0x85,0xcb,0xe8,0x50,0x0c,0xfe, - 0x30,0x45,0x02,0x21,0x00,0x96,0x44,0x7c,0xf6,0x8c,0x3a,0xb7,0x26,0x6e,0xd7,0x44,0x7d,0xe3,0xac,0x52,0xfe,0xd7,0xcc,0x08,0xcb,0xdf,0xea,0x39,0x1c,0x18,0xa9,0xb8,0xab,0x37,0x0b,0xc9,0x13,0x02,0x20,0x0f,0x5e,0x78,0x74,0xd3,0xac,0x0e,0x91,0x8f,0x01,0xc8,0x85,0xa1,0x63,0x91,0x77,0xc9,0x23,0xf8,0x66,0x0d,0x1c,0xeb,0xa1,0xca,0x1f,0x30,0x1b,0xc6,0x75,0xcd,0xbc, - 0x30,0x44,0x02,0x20,0x53,0x0a,0x08,0x32,0xb6,0x91,0xda,0x0b,0x56,0x19,0xa0,0xb1,0x1d,0xe6,0x87,0x7f,0x3c,0x09,0x71,0xba,0xaa,0x68,0xed,0x12,0x27,0x58,0xc2,0x9c,0xaa,0xf4,0x6b,0x72,0x02,0x20,0x6c,0x89,0xe4,0x4f,0x5e,0xb3,0x30,0x60,0xea,0x4b,0x46,0x31,0x8c,0x39,0x13,0x8e,0xae,0xde,0xc7,0x2d,0xe4,0x2b,0xa5,0x76,0x57,0x9a,0x6a,0x46,0x90,0xe3,0x39,0xf3, - 0x30,0x45,0x02,0x21,0x00,0x9c,0x54,0xc2,0x55,0x00,0xbd,0xe0,0xb9,0x2d,0x72,0xd6,0xec,0x48,0x3d,0xc2,0x48,0x2f,0x36,0x54,0x29,0x4c,0xa7,0x4d,0xe7,0x96,0xb6,0x81,0x25,0x5e,0xd5,0x8a,0x77,0x02,0x20,0x67,0x74,0x53,0xc6,0xb5,0x6f,0x52,0x76,0x31,0xc9,0xf6,0x7b,0x3f,0x3e,0xb6,0x21,0xfd,0x88,0x58,0x2b,0x4a,0xff,0x15,0x6d,0x2f,0x15,0x67,0xd6,0x21,0x1a,0x2a,0x33, - 0x30,0x45,0x02,0x21,0x00,0xe7,0x90,0x9d,0x41,0x43,0x9e,0x2f,0x6a,0xf2,0x91,0x36,0xc7,0x34,0x8c,0xa2,0x64,0x1a,0x2b,0x07,0x0d,0x5b,0x64,0xf9,0x1e,0xa9,0xda,0x70,0x70,0xc7,0xa2,0x61,0x8b,0x02,0x20,0x42,0xd7,0x82,0xf1,0x32,0xfa,0x1d,0x36,0xc2,0xc8,0x8b,0xa2,0x7c,0x3d,0x67,0x8d,0x80,0x18,0x4a,0x5d,0x1e,0xcc,0xac,0x75,0x01,0xf0,0xb4,0x7e,0x3d,0x20,0x50,0x08, - 0x30,0x44,0x02,0x20,0x59,0x24,0x87,0x32,0x09,0x59,0x31,0x35,0xa4,0xc3,0xda,0x7b,0xb3,0x81,0x22,0x7f,0x8a,0x4b,0x6a,0xa9,0xf3,0x4f,0xe5,0xbb,0x7f,0x8f,0xbc,0x13,0x1a,0x03,0x9f,0xfe,0x02,0x20,0x1f,0x1b,0xb1,0x1b,0x44,0x1c,0x8f,0xea,0xa4,0x0f,0x44,0x21,0x3d,0x9a,0x40,0x5e,0xd7,0x92,0xd5,0x9f,0xb4,0x9d,0x5b,0xcd,0xd9,0xa4,0x28,0x5a,0xe5,0x69,0x30,0x22, - 0x30,0x45,0x02,0x21,0x00,0xee,0xb6,0x92,0xc9,0xb2,0x62,0x96,0x9b,0x23,0x1c,0x38,0xb5,0xa7,0xf6,0x06,0x49,0xe0,0xc8,0x75,0xcd,0x64,0xdf,0x88,0xf3,0x3a,0xa5,0x71,0xfa,0x3d,0x29,0xab,0x0e,0x02,0x20,0x21,0x8b,0x3a,0x1e,0xb0,0x63,0x79,0xc2,0xc1,0x8c,0xf5,0x1b,0x06,0x43,0x07,0x86,0xd1,0xc6,0x4c,0xd2,0xd2,0x4c,0x9b,0x23,0x2b,0x23,0xe5,0xba,0xc7,0x98,0x9a,0xcd, - 0x30,0x45,0x02,0x21,0x00,0xa4,0x00,0x34,0x17,0x7f,0x36,0x09,0x1c,0x2b,0x65,0x36,0x84,0xa0,0xe3,0xeb,0x5d,0x4b,0xff,0x18,0xe4,0xd0,0x9f,0x66,0x4c,0x28,0x00,0xe7,0xca,0xfd,0xa1,0xda,0xf8,0x02,0x20,0x3a,0x3e,0xc2,0x98,0x53,0x70,0x4e,0x52,0x03,0x1c,0x58,0x92,0x7a,0x80,0x0a,0x96,0x83,0x53,0xad,0xc3,0xd9,0x73,0xbe,0xba,0x91,0x72,0xcb,0xbe,0xab,0x4d,0xd1,0x49, - 0x30,0x45,0x02,0x21,0x00,0xb5,0xd7,0x95,0xcc,0x75,0xce,0xa5,0xc4,0x34,0xfa,0x41,0x85,0x18,0x0c,0xd6,0xbd,0x21,0x22,0x3f,0x3d,0x5a,0x86,0xda,0x66,0x70,0xd7,0x1d,0x95,0x68,0x0d,0xad,0xbf,0x02,0x20,0x54,0xe4,0xd8,0x81,0x0a,0x00,0x1e,0xcb,0xb9,0xf7,0xca,0x1c,0x2e,0xbf,0xdb,0x9d,0x00,0x9e,0x90,0x31,0xa4,0x31,0xac,0xa3,0xc2,0x0a,0xb4,0xe0,0xd1,0x37,0x4e,0xc1, - 0x30,0x44,0x02,0x20,0x07,0xdc,0x24,0x78,0xd4,0x3c,0x12,0x32,0xa4,0x59,0x56,0x08,0xc6,0x44,0x26,0xc3,0x55,0x10,0x05,0x1a,0x63,0x1a,0xe6,0xa5,0xa6,0xeb,0x11,0x61,0xe5,0x7e,0x42,0xe1,0x02,0x20,0x4a,0x59,0xea,0x0f,0xdb,0x72,0xd1,0x21,0x65,0xce,0xa3,0xbf,0x1c,0xa8,0x6b,0xa9,0x75,0x17,0xbd,0x18,0x8d,0xb3,0xdb,0xd2,0x1a,0x5a,0x15,0x78,0x50,0x02,0x19,0x84, - 0x30,0x45,0x02,0x21,0x00,0xdd,0xd2,0x0c,0x4a,0x05,0x59,0x6c,0xa8,0x68,0xb5,0x58,0x83,0x9f,0xce,0x9f,0x65,0x11,0xdd,0xd8,0x3d,0x1c,0xcb,0x53,0xf8,0x2e,0x52,0x69,0xd5,0x59,0xa0,0x15,0x52,0x02,0x20,0x5b,0x91,0x73,0x47,0x29,0xd9,0x30,0x93,0xff,0x22,0x12,0x3c,0x4a,0x25,0x81,0x9d,0x7f,0xeb,0x66,0xa2,0x50,0x66,0x3f,0xc7,0x80,0xcb,0x66,0xfc,0x7b,0x6e,0x6d,0x17, - 0x30,0x45,0x02,0x21,0x00,0x9c,0xde,0x6e,0x0e,0xde,0x0a,0x00,0x3f,0x02,0xfd,0xa0,0xa0,0x1b,0x59,0xfa,0xcf,0xe5,0xde,0xc0,0x63,0x31,0x8f,0x27,0x9c,0xe2,0xde,0x7a,0x9b,0x10,0x62,0xf7,0xb7,0x02,0x20,0x28,0x86,0xa5,0xb8,0xc6,0x79,0xbd,0xf8,0x22,0x4c,0x66,0xf9,0x08,0xfd,0x62,0x05,0x49,0x2c,0xb7,0x0b,0x00,0x68,0xd4,0x6a,0xe4,0xf3,0x3a,0x41,0x49,0xb1,0x2a,0x52, - 0x30,0x45,0x02,0x21,0x00,0xc5,0x77,0x10,0x16,0xd0,0xdd,0x63,0x57,0x14,0x3c,0x89,0xf6,0x84,0xcd,0x74,0x04,0x23,0x50,0x25,0x54,0xc0,0xc5,0x9a,0xa8,0xc9,0x95,0x84,0xf1,0xff,0x38,0xf6,0x09,0x02,0x20,0x54,0xb4,0x05,0xf4,0x47,0x75,0x46,0x68,0x6e,0x46,0x4c,0x54,0x63,0xb4,0xfd,0x41,0x90,0x57,0x2e,0x58,0xd0,0xf7,0xe7,0x35,0x7f,0x6e,0x61,0x94,0x7d,0x20,0x71,0x5c, - 0x30,0x45,0x02,0x21,0x00,0xa2,0x4e,0xbc,0x0e,0xc2,0x24,0xbd,0x67,0xae,0x39,0x7c,0xbe,0x6f,0xa3,0x7b,0x31,0x25,0xad,0xbd,0x34,0x89,0x1a,0xbe,0x2d,0x7c,0x73,0x56,0x92,0x19,0x16,0xdf,0xe6,0x02,0x20,0x34,0xf6,0xeb,0x63,0x74,0x73,0x1b,0xbb,0xaf,0xc4,0x92,0x4f,0xb8,0xb0,0xbd,0xcd,0xda,0x49,0x45,0x6d,0x72,0x4c,0xda,0xe6,0x17,0x8d,0x87,0x01,0x4c,0xb5,0x3d,0x8c, - 0x30,0x44,0x02,0x20,0x25,0x57,0xd6,0x4a,0x7a,0xee,0x2e,0x09,0x31,0xc0,0x12,0xe4,0xfe,0xa1,0xcd,0x3a,0x2c,0x33,0x4e,0xda,0xe6,0x8c,0xde,0xb7,0x15,0x8c,0xaf,0x21,0xb6,0x8e,0x5a,0x24,0x02,0x20,0x7f,0x06,0xcd,0xbb,0x6a,0x90,0x02,0x3a,0x97,0x38,0x82,0xed,0x97,0xb0,0x80,0xfe,0x6b,0x05,0xaf,0x3e,0xc9,0x3d,0xb6,0xf1,0xa4,0x39,0x9a,0x69,0xed,0xf7,0x67,0x0d, - 0x30,0x45,0x02,0x21,0x00,0xc4,0xf2,0xec,0xcb,0xb6,0xa2,0x43,0x50,0xc8,0x46,0x64,0x50,0xb9,0xd6,0x1b,0x20,0x7e,0xe3,0x59,0xe0,0x37,0xb3,0xdc,0xed,0xb4,0x2a,0x3f,0x2e,0x6d,0xd6,0xae,0xb5,0x02,0x20,0x32,0x63,0xc6,0xb5,0x9a,0x2f,0x55,0xcd,0xd1,0xc6,0xe1,0x48,0x94,0xd5,0xe5,0x96,0x3b,0x28,0xbc,0x3e,0x24,0x69,0xac,0x9b,0xa1,0x19,0x79,0x91,0xca,0x7f,0xf9,0xc7, - 0x30,0x45,0x02,0x21,0x00,0xef,0xf0,0x47,0x81,0xc9,0xcb,0xcd,0x16,0x2d,0x0a,0x25,0xa6,0xe2,0xeb,0xcc,0xa4,0x35,0x06,0xc5,0x23,0x38,0x5c,0xb5,0x15,0xd4,0x9e,0xa3,0x8a,0x1b,0x12,0xfc,0xad,0x02,0x20,0x15,0xac,0xd7,0x31,0x94,0xc9,0x1a,0x95,0x47,0x85,0x34,0xf2,0x30,0x15,0xb6,0x72,0xeb,0xed,0x21,0x3e,0x45,0x42,0x4d,0xd2,0xc8,0xe2,0x6a,0xc8,0xb3,0xeb,0x34,0xa5, - 0x30,0x45,0x02,0x21,0x00,0xf5,0x8b,0x4e,0x31,0x10,0xa6,0x4b,0xf1,0xb5,0xdb,0x97,0x63,0x9e,0xe0,0xe5,0xa9,0xc8,0xdf,0xa4,0x9d,0xc5,0x9b,0x67,0x98,0x91,0xf5,0x20,0xfd,0xf0,0x58,0x4c,0x87,0x02,0x20,0x2c,0xd8,0xfe,0x51,0x88,0x8a,0xee,0x9d,0xb3,0xe0,0x75,0x44,0x0f,0xd4,0xdb,0x73,0xb5,0xc7,0x32,0xfb,0x87,0xb5,0x10,0xe9,0x70,0x93,0xd6,0x64,0x15,0xf6,0x2a,0xf7, - 0x30,0x45,0x02,0x21,0x00,0xf8,0xab,0xec,0xaa,0x4f,0x0c,0x50,0x2d,0xe4,0xbf,0x59,0x03,0xd4,0x84,0x17,0xf7,0x86,0xbf,0x92,0xe8,0xad,0x72,0xfe,0xc0,0xbd,0x7f,0xcb,0x78,0x00,0xc0,0xbb,0xe3,0x02,0x20,0x4c,0x7f,0x9e,0x23,0x10,0x76,0xa3,0x0b,0x7a,0xe3,0x6b,0x0c,0xeb,0xe6,0x9c,0xce,0xf1,0xcd,0x19,0x4f,0x7c,0xce,0x93,0xa5,0x58,0x8f,0xd6,0x81,0x4f,0x43,0x7c,0x0e, - 0x30,0x44,0x02,0x20,0x5d,0x5b,0x38,0xbd,0x37,0xad,0x49,0x8b,0x22,0x27,0xa6,0x33,0x26,0x8a,0x8c,0xca,0x87,0x9a,0x5c,0x7c,0x94,0xa4,0xe4,0x16,0xbd,0x0a,0x61,0x4d,0x09,0xe6,0x06,0xd2,0x02,0x20,0x12,0xb8,0xd6,0x64,0xea,0x99,0x91,0x06,0x2e,0xcb,0xb8,0x34,0xe5,0x84,0x00,0xe2,0x5c,0x46,0x00,0x7a,0xf8,0x4f,0x60,0x07,0xd7,0xf1,0x68,0x54,0x43,0x26,0x9a,0xfe, - 0x30,0x44,0x02,0x20,0x0c,0x1c,0xd9,0xfe,0x40,0x34,0xf0,0x86,0xa2,0xb5,0x2d,0x65,0xb9,0xd3,0x83,0x4d,0x72,0xae,0xbe,0x7f,0x33,0xdf,0xe8,0xf9,0x76,0xda,0x82,0x64,0x81,0x77,0xd8,0xe3,0x02,0x20,0x13,0x10,0x57,0x82,0xe3,0xd0,0xcf,0xe8,0x5c,0x27,0x78,0xde,0xc1,0xa8,0x48,0xb2,0x7a,0xc0,0xae,0x07,0x1a,0xa6,0xda,0x34,0x1a,0x95,0x53,0xa9,0x46,0xb4,0x1e,0x59, - 0x30,0x45,0x02,0x21,0x00,0xae,0x79,0x35,0xfb,0x96,0xff,0x24,0x6b,0x7b,0x5d,0x56,0x62,0x87,0x0d,0x1b,0xa5,0x87,0xb0,0x3d,0x6e,0x13,0x60,0xba,0xf4,0x79,0x88,0xb5,0xc0,0x2c,0xcc,0x1a,0x5b,0x02,0x20,0x5f,0x00,0xc3,0x23,0x27,0x20,0x83,0x78,0x2d,0x4a,0x59,0xf2,0xdf,0xd6,0x5e,0x49,0xde,0x06,0x93,0x62,0x70,0x16,0x90,0x0e,0xf7,0xe6,0x14,0x28,0x05,0x66,0x64,0xb3, - 0x30,0x44,0x02,0x20,0x00,0xa1,0x34,0xb5,0xc6,0xcc,0xbc,0xef,0xd4,0xc8,0x82,0xb9,0x45,0xba,0xeb,0x49,0x33,0x44,0x41,0x72,0x79,0x5f,0xa6,0x79,0x6a,0xae,0x14,0x90,0x67,0x54,0x70,0x98,0x02,0x20,0x56,0x6e,0x46,0x10,0x5d,0x24,0xd8,0x90,0x15,0x1e,0x3e,0xea,0x3e,0xbf,0x88,0xf5,0xb9,0x2b,0x3f,0x5e,0xc9,0x3a,0x21,0x77,0x65,0xa6,0xdc,0xbd,0x94,0xf2,0xc5,0x5b, - 0x30,0x44,0x02,0x20,0x2e,0x47,0x21,0x36,0x3a,0xd3,0x99,0x2c,0x13,0x9e,0x5a,0x1c,0x26,0x39,0x5d,0x2c,0x2d,0x77,0x78,0x24,0xaa,0x24,0xfd,0xe0,0x75,0xe0,0xd7,0x38,0x11,0x71,0x30,0x9d,0x02,0x20,0x74,0x0f,0x7c,0x49,0x44,0x18,0xe1,0x30,0x0d,0xd4,0x51,0x2f,0x78,0x2a,0x58,0x80,0x0b,0xff,0x6a,0x7a,0xbd,0xfd,0xd2,0x0f,0xbb,0xd4,0xf0,0x55,0x15,0xca,0x1a,0x4f, - 0x30,0x44,0x02,0x20,0x68,0x52,0xe9,0xd3,0xcd,0x9f,0xe3,0x73,0xc2,0xd5,0x04,0x87,0x79,0x67,0xd3,0x65,0xab,0x14,0x56,0x70,0x7b,0x68,0x17,0xa0,0x42,0x86,0x46,0x94,0xe1,0x96,0x0c,0xcf,0x02,0x20,0x06,0x4b,0x27,0xea,0x14,0x2b,0x30,0x88,0x7b,0x84,0xc8,0x6a,0xdc,0xcb,0x2f,0xa3,0x9a,0x69,0x11,0xad,0x21,0xfc,0x7e,0x81,0x9f,0x59,0x3b,0xe5,0x2b,0xc4,0xf3,0xbd, - 0x30,0x44,0x02,0x20,0x18,0x8a,0x8c,0x56,0x48,0xdc,0x79,0xea,0xce,0x15,0x8c,0xf8,0x86,0xc6,0x2b,0x54,0x68,0xf0,0x5f,0xd9,0x5f,0x03,0xa7,0x63,0x5c,0x5b,0x4c,0x31,0xf0,0x9a,0xf4,0xc5,0x02,0x20,0x36,0x36,0x1a,0x0b,0x57,0x1a,0x00,0xc6,0xcd,0x5e,0x68,0x6c,0xcb,0xfc,0xfa,0x70,0x3c,0x4f,0x97,0xe4,0x89,0x38,0x34,0x6d,0x0c,0x10,0x3f,0xdc,0x76,0xdc,0x58,0x67, - 0x30,0x45,0x02,0x21,0x00,0xa7,0x4f,0x1f,0xb9,0xa8,0x26,0x3f,0x62,0xfc,0x44,0x16,0xa5,0xb7,0xd5,0x84,0xf4,0x20,0x6f,0x39,0x96,0xbb,0x91,0xf6,0xfc,0x8e,0x73,0xb9,0xe9,0x2b,0xad,0x0e,0x13,0x02,0x20,0x68,0x15,0x03,0x2e,0x8c,0x7d,0x76,0xc3,0xab,0x06,0xa8,0x6f,0x33,0x24,0x9c,0xe9,0x94,0x01,0x48,0xcb,0x36,0xd1,0xf4,0x17,0xc2,0xe9,0x92,0xe8,0x01,0xaf,0xa3,0xfa, - 0x30,0x44,0x02,0x20,0x07,0x24,0x48,0x65,0xb7,0x2f,0xf3,0x7e,0x62,0xe3,0x14,0x6f,0x0d,0xc1,0x46,0x82,0xba,0xdd,0x71,0x97,0x79,0x91,0x35,0xf0,0xb0,0x0a,0xde,0x76,0x71,0x74,0x2b,0xfe,0x02,0x20,0x0d,0x80,0xc2,0x23,0x8e,0xdb,0x4e,0x4a,0x7a,0x86,0xa8,0xc5,0x7c,0xa9,0xaf,0x17,0x11,0xf4,0x06,0xf7,0xf5,0xda,0x02,0x99,0xaa,0x04,0xe2,0x93,0x2d,0x96,0x07,0x54, - 0x30,0x45,0x02,0x21,0x00,0xda,0x7f,0xdd,0x05,0xb5,0xba,0xda,0xbd,0x61,0x9d,0x80,0x5c,0x4e,0xe7,0xd9,0xa8,0x4f,0x84,0xdd,0xd5,0xcf,0x9c,0x5b,0xf4,0xd4,0x33,0x81,0x40,0xd6,0x89,0xef,0x08,0x02,0x20,0x28,0xf1,0xcf,0x4f,0xa1,0xc3,0xc5,0x86,0x2c,0xfa,0x14,0x9c,0x00,0x13,0xcf,0x5f,0xe6,0xcf,0x50,0x76,0xca,0xe0,0x00,0x51,0x10,0x63,0xe7,0xde,0x25,0xbb,0x38,0xe5, - 0x30,0x45,0x02,0x21,0x00,0xd3,0x02,0x7c,0x65,0x6f,0x6d,0x4f,0xdf,0xd8,0xed,0xe2,0x20,0x93,0xe3,0xc3,0x03,0xb0,0x13,0x3c,0x34,0x0d,0x61,0x5e,0x77,0x56,0xf6,0x25,0x3a,0xea,0x92,0x72,0x38,0x02,0x20,0x09,0xae,0xf0,0x60,0xc8,0xe4,0xce,0xf9,0x72,0x97,0x40,0x11,0x55,0x8d,0xf1,0x44,0xfe,0xd2,0x5c,0xa6,0x9a,0xe8,0xd0,0xb2,0xea,0xf1,0xa8,0xfe,0xef,0xbe,0xc4,0x17, - 0x30,0x44,0x02,0x20,0x0b,0xf6,0xc0,0x18,0x8d,0xc9,0x57,0x1c,0xd0,0xe2,0x1e,0xec,0xac,0x5f,0xbb,0x19,0xd2,0x43,0x49,0x88,0xe9,0xcc,0x10,0x24,0x45,0x93,0xef,0x3a,0x98,0x09,0x9f,0x69,0x02,0x20,0x48,0x64,0xa5,0x62,0x66,0x1f,0x92,0x21,0xec,0x88,0xe3,0xdd,0x0b,0xc2,0xf6,0xe2,0x7a,0xc1,0x28,0xc3,0x0c,0xc1,0xa8,0x0f,0x79,0xec,0x67,0x0a,0x22,0xb0,0x42,0xee, - 0x30,0x45,0x02,0x21,0x00,0xae,0x45,0x96,0x40,0xd5,0xd1,0x17,0x9b,0xe4,0x7a,0x47,0xfa,0x53,0x8e,0x16,0xd9,0x4d,0xde,0xa5,0x58,0x5e,0x7a,0x24,0x48,0x04,0xa5,0x17,0x42,0xc6,0x86,0x44,0x3a,0x02,0x20,0x6c,0x8e,0x30,0xe5,0x30,0xa6,0x34,0xfa,0xe8,0x0b,0x3c,0xeb,0x06,0x29,0x78,0xb3,0x9e,0xdb,0xe1,0x97,0x77,0xe0,0xa2,0x45,0x53,0xb6,0x88,0x86,0x18,0x1f,0xd8,0x97, - 0x30,0x44,0x02,0x20,0x1c,0xf3,0x51,0x7b,0xa3,0xbf,0x2a,0xb8,0xb9,0xea,0xd4,0xeb,0xb6,0xe8,0x66,0xcb,0x88,0xa1,0xde,0xac,0xb6,0xa7,0x85,0xd3,0xb6,0x3b,0x48,0x3c,0xa0,0x2a,0xc4,0x95,0x02,0x20,0x24,0x9a,0x79,0x8b,0x73,0x60,0x6f,0x55,0xf5,0xf1,0xc7,0x0d,0xe6,0x7c,0xb1,0xa0,0xcf,0xf9,0x5d,0x7d,0xc5,0x0b,0x3a,0x61,0x7d,0xf8,0x61,0xba,0xd3,0xc6,0xb1,0xc9, - 0x30,0x45,0x02,0x21,0x00,0xe6,0x9b,0x52,0x38,0x26,0x5e,0xa3,0x5d,0x77,0xe4,0xdd,0x17,0x22,0x88,0xd8,0xce,0xa1,0x98,0x10,0xa1,0x02,0x92,0x61,0x7d,0x59,0x76,0x51,0x9d,0xc5,0x75,0x7c,0xb8,0x02,0x20,0x4b,0x03,0xc5,0xbc,0x47,0xe8,0x26,0xbd,0xb2,0x73,0x28,0xab,0xd3,0x8d,0x30,0x56,0xd7,0x74,0x76,0xb2,0x13,0x0f,0x3d,0xf6,0xec,0x48,0x91,0xaf,0x08,0xba,0x1e,0x29, - 0x30,0x44,0x02,0x20,0x5f,0x9d,0x7d,0x7c,0x87,0x0d,0x08,0x5f,0xc1,0xd4,0x9f,0xff,0x69,0xe4,0xa2,0x75,0x81,0x28,0x00,0xd2,0xcf,0x89,0x73,0xe7,0x32,0x58,0x66,0xcb,0x40,0xfa,0x2b,0x6f,0x02,0x20,0x6d,0x1f,0x54,0x91,0xd9,0xf7,0x17,0xa5,0x97,0xa1,0x5f,0xd5,0x40,0x40,0x64,0x86,0xd7,0x6a,0x44,0x69,0x7b,0x3f,0x0d,0x9d,0x6d,0xce,0xf6,0x66,0x9f,0x8a,0x0a,0x56, - 0x30,0x44,0x02,0x20,0x0a,0x7d,0x5b,0x19,0x59,0xf7,0x1d,0xf9,0xf8,0x17,0x14,0x6e,0xe4,0x9b,0xd5,0xc8,0x9b,0x43,0x1e,0x79,0x93,0xe2,0xfd,0xec,0xab,0x68,0x58,0x95,0x7d,0xa6,0x85,0xae,0x02,0x20,0x0f,0x8a,0xad,0x2d,0x25,0x46,0x90,0xbd,0xc1,0x3f,0x34,0xa4,0xfe,0xc4,0x4a,0x02,0xfd,0x74,0x5a,0x42,0x2d,0xf0,0x5c,0xcb,0xb5,0x46,0x35,0xa8,0xb8,0x6b,0x96,0x09, - 0x30,0x44,0x02,0x20,0x79,0xe8,0x8b,0xf5,0x76,0xb7,0x4b,0xc0,0x7c,0xa1,0x42,0x39,0x5f,0xda,0x28,0xf0,0x3d,0x3d,0x5e,0x64,0x0b,0x0b,0x4f,0xf0,0x75,0x2c,0x6d,0x94,0xcd,0x55,0x34,0x08,0x02,0x20,0x32,0xce,0xa0,0x5b,0xd2,0xd7,0x06,0xc8,0xf6,0x03,0x6a,0x50,0x7e,0x2a,0xb7,0x76,0x60,0x04,0xf0,0x90,0x4e,0x2e,0x5c,0x58,0x62,0x74,0x9c,0x00,0x73,0x24,0x5d,0x6a, - 0x30,0x45,0x02,0x21,0x00,0x9d,0x54,0xe0,0x37,0xa0,0x02,0x12,0xb3,0x77,0xbc,0x88,0x74,0x79,0x8b,0x8d,0xa0,0x80,0x56,0x4b,0xbd,0xf7,0xe0,0x75,0x91,0xb8,0x61,0x28,0x58,0x09,0xd0,0x14,0x88,0x02,0x20,0x18,0xb4,0xe5,0x57,0x66,0x7a,0x82,0xbd,0x95,0x96,0x5f,0x07,0x06,0xf8,0x1a,0x29,0x24,0x3f,0xbd,0xd8,0x69,0x68,0xa7,0xeb,0xeb,0x43,0x06,0x9d,0xb3,0xb1,0x8c,0x7f, - 0x30,0x44,0x02,0x20,0x26,0x64,0xf1,0xff,0xa9,0x82,0xfe,0xdb,0xcc,0x7c,0xab,0x1b,0x8b,0xc6,0xe2,0xcb,0x42,0x02,0x18,0xd2,0xa6,0x07,0x7a,0xd0,0x8e,0x59,0x1b,0xa9,0xfe,0xab,0x33,0xbd,0x02,0x20,0x49,0xf5,0xc7,0xcb,0x51,0x5e,0x83,0x87,0x2a,0x3d,0x41,0xb4,0xcd,0xb8,0x5f,0x24,0x2a,0xd9,0xd6,0x1a,0x5b,0xfc,0x01,0xde,0xbf,0xbb,0x52,0xc6,0xc8,0x4b,0xa7,0x28, - 0x30,0x44,0x02,0x20,0x58,0x27,0x51,0x83,0x44,0x84,0x4f,0xd6,0xa7,0xde,0x73,0xcb,0xb0,0xa6,0xbe,0xfd,0xea,0x7b,0x13,0xd2,0xde,0xe4,0x47,0x53,0x17,0xf0,0xf1,0x8f,0xfc,0x81,0x52,0x4b,0x02,0x20,0x4f,0x5c,0xcb,0x4e,0x0b,0x48,0x8b,0x5a,0x5d,0x76,0x0a,0xac,0xdd,0xb2,0xd7,0x91,0x97,0x0f,0xe4,0x3d,0xa6,0x1e,0xb3,0x0e,0x2e,0x90,0x20,0x8a,0x81,0x7e,0x46,0xdb, - 0x30,0x45,0x02,0x21,0x00,0x97,0xab,0x19,0xbd,0x13,0x9c,0xac,0x31,0x93,0x25,0x86,0x92,0x18,0xb1,0xbc,0xe1,0x11,0x87,0x5d,0x63,0xfb,0x12,0x09,0x8a,0x04,0xb0,0xcd,0x59,0xb6,0xfd,0xd3,0xa3,0x02,0x20,0x43,0x1d,0x9c,0xea,0x3a,0x24,0x38,0x47,0x30,0x3c,0xeb,0xda,0x56,0x47,0x64,0x31,0xd0,0x34,0x33,0x9f,0x31,0xd7,0x85,0xee,0x88,0x52,0xdb,0x4f,0x04,0x0d,0x49,0x21, - 0x30,0x44,0x02,0x20,0x52,0xc6,0x83,0x14,0x4e,0x44,0x11,0x9a,0xe2,0x01,0x37,0x49,0xd4,0x96,0x4e,0xf6,0x75,0x09,0x27,0x8f,0x6d,0x38,0xba,0x86,0x9a,0xdc,0xfa,0x69,0x97,0x0e,0x12,0x3d,0x02,0x20,0x34,0x79,0x91,0x01,0x67,0x40,0x8f,0x45,0xbd,0xa4,0x20,0xa6,0x26,0xec,0x9c,0x4e,0xc7,0x11,0xc1,0x27,0x4b,0xe0,0x92,0x19,0x8b,0x41,0x87,0xc0,0x18,0xb5,0x62,0xca, - 0x30,0x16,0x02,0x11,0x01,0x45,0x51,0x23,0x19,0x50,0xb7,0x5f,0xc4,0x40,0x2d,0xa1,0x72,0x2f,0xc9,0xba,0xeb,0x02,0x01,0x03, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2c,0x02,0x01,0x03, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x3f,0x02,0x01,0x03, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x9a,0x75,0x82,0x88,0x60,0x89,0xc6,0x2f,0xb8,0x40,0xcf,0x3b,0x83,0x06,0x1c,0xd1,0xcf,0xf3,0xae,0x43,0x41,0x80,0x8b,0xb5,0xbd,0xee,0x61,0x91,0x17,0x41,0x77, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x24,0x23,0x8e,0x70,0xb4,0x31,0xb1,0xa6,0x4e,0xfd,0xf9,0x03,0x26,0x69,0x93,0x9d,0x4b,0x77,0xf2,0x49,0x50,0x3f,0xc6,0x90,0x5f,0xeb,0x75,0x40,0xde,0xa3,0xe6,0xd2, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x02, - 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x03, - 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x01, - 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x02, - 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x03, - 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x43,0x02,0x01,0x03, - 0x30,0x08,0x02,0x01,0x02,0x02,0x03,0xed,0x29,0x79, - 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0x9f,0x8a,0xb3,0x73,0x2a,0x0a,0x89,0x60,0x4a,0x09,0xbc,0xe5,0xb2,0x91,0x6d,0xa4, - 0x30,0x2b,0x02,0x07,0x2d,0x9b,0x4d,0x34,0x79,0x52,0xcc,0x02,0x20,0x03,0x43,0xae,0xfc,0x2f,0x25,0xd9,0x8b,0x88,0x2e,0x86,0xeb,0x9e,0x30,0xd5,0x5a,0x6e,0xb5,0x08,0xb5,0x16,0x51,0x0b,0x34,0x02,0x4a,0xe4,0xb6,0x36,0x23,0x30,0xb3, - 0x30,0x31,0x02,0x0d,0x10,0x33,0xe6,0x7e,0x37,0xb3,0x2b,0x44,0x55,0x80,0xbf,0x4e,0xfc,0x02,0x20,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x8f,0xe1,0xca,0xb5,0xee,0xfd,0xb2,0x14,0x06,0x1d,0xce,0x3b,0x22,0x78,0x9f,0x1d,0x6f, - 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, - 0x30,0x31,0x02,0x0d,0x06,0x25,0x22,0xbb,0xd3,0xec,0xbe,0x7c,0x39,0xe9,0x3e,0x7c,0x26,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, - 0x30,0x45,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x40,0xc1,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, - 0x30,0x16,0x02,0x09,0x00,0x9c,0x44,0xfe,0xbf,0x31,0xc3,0x59,0x4d,0x02,0x09,0x00,0x83,0x9e,0xd2,0x82,0x47,0xc2,0xb0,0x6b, - 0x30,0x1e,0x02,0x0d,0x09,0xdf,0x8b,0x68,0x24,0x30,0xbe,0xef,0x6f,0x5f,0xd7,0xc7,0xcf,0x02,0x0d,0x0f,0xd0,0xa6,0x2e,0x13,0x77,0x8f,0x42,0x22,0xa0,0xd6,0x1c,0x8a, - 0x30,0x26,0x02,0x11,0x00,0x8a,0x59,0x8e,0x56,0x3a,0x89,0xf5,0x26,0xc3,0x2e,0xbe,0xc8,0xde,0x26,0x36,0x7a,0x02,0x11,0x00,0x84,0xf6,0x33,0xe2,0x04,0x26,0x30,0xe9,0x9d,0xd0,0xf1,0xe1,0x6f,0x7a,0x04,0xbf, - 0x30,0x2e,0x02,0x15,0x00,0xaa,0x6e,0xeb,0x58,0x23,0xf7,0xfa,0x31,0xb4,0x66,0xbb,0x47,0x37,0x97,0xf0,0xd0,0x31,0x4c,0x0b,0xdf,0x02,0x15,0x00,0xe2,0x97,0x7c,0x47,0x9e,0x6d,0x25,0x70,0x3c,0xeb,0xbc,0x6b,0xd5,0x61,0x93,0x8c,0xc9,0xd1,0xbf,0xb9, - 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x01, - 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x00, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x41,0x9d,0x98,0x1c,0x51,0x5a,0xf8,0xcc,0x82,0x54,0x5a,0xac,0x0c,0x85,0xe9,0xe3,0x08,0xfb,0xb2,0xea,0xb6,0xac,0xd7,0xed,0x49,0x7e,0x0b,0x41,0x45,0xa1,0x8f,0xd9, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x1b,0x21,0x71,0x7a,0xd7,0x1d,0x23,0xbb,0xac,0x60,0xa9,0xad,0x0b,0xaf,0x75,0xb0,0x63,0xc9,0xfd,0xf5,0x2a,0x00,0xeb,0xf9,0x9d,0x02,0x21,0x72,0x91,0x09,0x93,0xc9, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x2f,0x58,0x8f,0x66,0x01,0x8f,0x3d,0xd1,0x4d,0xb3,0xe2,0x8e,0x77,0x99,0x64,0x87,0xe3,0x24,0x86,0xb5,0x21,0xed,0x8e,0x5a,0x20,0xf0,0x65,0x91,0x95,0x17,0x77,0xe9, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x09,0x1a,0x08,0x87,0x0f,0xf4,0xda,0xf9,0x12,0x3b,0x30,0xc2,0x0e,0x8c,0x4f,0xc8,0x50,0x57,0x58,0xdc,0xf4,0x07,0x4f,0xca,0xff,0x21,0x70,0xc9,0xbf,0xcf,0x74,0xf4, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7c,0x37,0x0d,0xc0,0xce,0x8c,0x59,0xa8,0xb2,0x73,0xcb,0xa4,0x4a,0x7c,0x11,0x91,0xfc,0x31,0x86,0xdc,0x03,0xca,0xb9,0x6b,0x05,0x67,0x31,0x2d,0xf0,0xd0,0xb2,0x50, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x70,0xb5,0x9a,0x7d,0x1e,0xe7,0x7a,0x2f,0x9e,0x04,0x91,0xc2,0xa7,0xcf,0xcd,0x0e,0xd0,0x4d,0xf4,0xa3,0x51,0x92,0xf6,0x13,0x2d,0xcc,0x66,0x8c,0x79,0xa6,0x16,0x0e, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x27,0x36,0xd7,0x6e,0x41,0x22,0x46,0xe0,0x97,0x14,0x8e,0x2b,0xf6,0x29,0x15,0x61,0x4e,0xb7,0xc4,0x28,0x91,0x3a,0x58,0xeb,0x5e,0x9c,0xd4,0x67,0x4a,0x94,0x23,0xde, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4a,0x1e,0x12,0x83,0x1f,0xbe,0x93,0x62,0x7b,0x02,0xd6,0xe7,0xf2,0x4b,0xcc,0xdd,0x6e,0xf4,0xb2,0xd0,0xf4,0x67,0x39,0xea,0xf3,0xb1,0xea,0xf0,0xca,0x11,0x77,0x70, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x06,0xc7,0x78,0xd4,0xdf,0xff,0x7d,0xee,0x06,0xed,0x88,0xbc,0x4e,0x0e,0xd3,0x4f,0xc5,0x53,0xaa,0xd6,0x7c,0xaf,0x79,0x6f,0x2a,0x1c,0x64,0x87,0xc1,0xb2,0xe8,0x77, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4d,0xe4,0x59,0xef,0x91,0x59,0xaf,0xa0,0x57,0xfe,0xb3,0xec,0x40,0xfe,0xf0,0x1c,0x45,0xb8,0x09,0xf4,0xab,0x29,0x6e,0xa4,0x8c,0x20,0x6d,0x42,0x49,0xa2,0xb4,0x51, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x74,0x5d,0x29,0x49,0x78,0x00,0x73,0x02,0x03,0x35,0x02,0xe1,0xac,0xc4,0x8b,0x63,0xae,0x65,0x00,0xbe,0x43,0xad,0xbe,0xa1,0xb2,0x58,0xd6,0xb4,0x23,0xdb,0xb4,0x16, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7b,0x2a,0x78,0x5e,0x38,0x96,0xf5,0x9b,0x2d,0x69,0xda,0x57,0x64,0x8e,0x80,0xad,0x3c,0x13,0x3a,0x75,0x0a,0x28,0x47,0xfd,0x20,0x98,0xcc,0xd9,0x02,0x04,0x2b,0x6c, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x71,0xae,0x94,0xa7,0x2c,0xa8,0x96,0x87,0x5e,0x7a,0xa4,0xa4,0xc3,0xd2,0x9a,0xfd,0xb4,0xb3,0x5b,0x69,0x96,0x27,0x3e,0x63,0xc4,0x7a,0xc5,0x19,0x25,0x6c,0x5e,0xb1, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x0f,0xa5,0x27,0xfa,0x73,0x43,0xc0,0xbc,0x9e,0xc3,0x5a,0x62,0x78,0xbf,0xbf,0xf4,0xd8,0x33,0x01,0xb1,0x54,0xfc,0x4b,0xd1,0x4a,0xee,0x7e,0xb9,0x34,0x45,0xb5,0xf9, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x65,0x39,0xc0,0xad,0xad,0xd0,0x52,0x5f,0xf4,0x26,0x22,0x16,0x4c,0xe9,0x31,0x43,0x48,0xbd,0x08,0x63,0xb4,0xc8,0x0e,0x93,0x6b,0x23,0xca,0x04,0x14,0x26,0x46,0x71, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa1, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x1c,0x94,0x0f,0x31,0x3f,0x92,0x64,0x7b,0xe2,0x57,0xec,0xcd,0x7e,0xd0,0x8b,0x0b,0xae,0xf3,0xf0,0x47,0x8f,0x25,0x87,0x1b,0x53,0x63,0x53,0x02,0xc5,0xf6,0x31,0x4a, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x15,0xd9,0x4a,0x85,0x07,0x7b,0x49,0x3f,0x91,0xcb,0x71,0x01,0xec,0x63,0xe1,0xb0,0x1b,0xe5,0x8b,0x59,0x4e,0x85,0x5f,0x45,0x05,0x0a,0x8c,0x14,0x06,0x2d,0x68,0x9b, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x1d,0x27,0xa7,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9d,0x9e,0xf3,0xb9,0xfb,0x58,0x38,0x54,0x18,0xd9,0xc9,0x82,0x10,0x50,0x77,0xd1,0xb7, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2d,0x85,0x89,0x6b,0x3e,0xb9,0xdb,0xb5,0xa5,0x2f,0x42,0xf9,0xc9,0x26,0x1e,0xd3,0xfc,0x46,0x64,0x4e,0xc6,0x5f,0x06,0xad,0xe3,0xfd,0x78,0xf2,0x57,0xe4,0x34,0x32, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x0b,0x12,0xd6,0x7d,0x73,0xb7,0x6b,0x4a,0x5e,0x85,0xf3,0x92,0x4c,0x3d,0xa7,0xf8,0x8c,0xc8,0x9d,0x8c,0xbe,0x0d,0x5b,0xc7,0xfa,0xf1,0xe4,0xaf,0xc8,0x68,0x64, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x09,0xe6,0x0e,0x68,0xb9,0x0d,0x0b,0x5e,0x6c,0x5d,0xdd,0xd0,0xcb,0x69,0x4d,0x87,0x99, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3d,0x7f,0x48,0x7c,0x07,0xbf,0xc5,0xf3,0x08,0x46,0x93,0x8a,0x3d,0xce,0xf6,0x96,0x44,0x47,0x07,0xcf,0x96,0x77,0x25,0x4a,0x92,0xb0,0x6c,0x63,0xab,0x86,0x7d,0x22, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6c,0x76,0x48,0xfc,0x0f,0xbf,0x8a,0x06,0xad,0xb8,0xb8,0x39,0xf9,0x7b,0x4f,0xf7,0xa8,0x00,0xf1,0x1b,0x1e,0x37,0xc5,0x93,0xb2,0x61,0x39,0x45,0x99,0x79,0x2b,0xa4, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x1c,0x9c,0x5d,0x79,0x0d,0xc0,0x9c,0xdd,0x3d,0xfa,0xbb,0x62,0xcd,0xf4,0x53,0xe6,0x97,0x47,0xa7,0xe3,0xd7,0xaa,0x1a,0x71,0x41,0x89,0xef,0x53,0x17,0x1a,0x99, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x29,0x79,0x8c,0x5c,0x45,0xbd,0xf5,0x8b,0x4a,0x7b,0x2f,0xdc,0x2c,0x46,0xab,0x4a,0xf1,0x21,0x8c,0x7e,0xeb,0x9f,0x0f,0x27,0xa8,0x8f,0x12,0x67,0x67,0x4d,0xe3,0xb0, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x0b,0x70,0xf2,0x2c,0xa2,0xbb,0x3c,0xef,0xad,0xca,0x1a,0x57,0x11,0xfa,0x3a,0x59,0xf4,0x69,0x53,0x85,0xeb,0x5a,0xed,0xf3,0x49,0x5d,0x0b,0x6d,0x00,0xf8,0xfd,0x85, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x22,0x52,0xd6,0x85,0xe8,0x31,0xb6,0xcf,0x09,0x5e,0x4f,0x05,0x35,0xee,0xaf,0x0d,0xdd,0x3b,0xfa,0x91,0xc2,0x10,0xc9,0xd9,0xdc,0x17,0x22,0x47,0x02,0xea,0xf8,0x8f, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x75,0x13,0x5a,0xbd,0x7c,0x42,0x5b,0x60,0x37,0x1a,0x47,0x7f,0x09,0xce,0x0f,0x27,0x4f,0x64,0xa8,0xc6,0xb0,0x61,0xa0,0x7b,0x5d,0x63,0xe9,0x3c,0x65,0x04,0x6c,0x53, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x88,0x83,0x77,0xac,0x6c,0x71,0xac,0x9d,0xec,0x3f,0xdb,0x9b,0x56,0xc9,0xfe,0xaf,0x0c,0xfa,0xca,0x9f,0x82,0x7f,0xc5,0xeb,0x65,0xfc,0x3e,0xac,0x81,0x12,0x10, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x30,0xbb,0xb7,0x94,0xdb,0x58,0x83,0x63,0xb4,0x06,0x79,0xf6,0xc1,0x82,0xa5,0x0d,0x3c,0xe9,0x67,0x9a,0xcd,0xd3,0xff,0xbe,0x36,0xd7,0x81,0x3d,0xac,0xbd,0xc8,0x18, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2c,0x37,0xfd,0x99,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc7,0xce,0xe7,0x45,0x11,0x0c,0xb4,0x5a,0xb5,0x58,0xed,0x7c,0x90,0xc1,0x5a,0x2f, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x7f,0xd9,0x95,0x62,0x2c,0x4f,0xb7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x88,0x3f,0xfa,0xb5,0xb3,0x26,0x52,0xcc,0xdc,0xaa,0x29,0x0f,0xcc,0xb9,0x7d, - 0x30,0x43,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x1f,0x4c,0xd5,0x3b,0xa7,0x60,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9e,0x5c,0xf1,0x43,0xe2,0x53,0x96,0x26,0x19,0x0a,0x3a,0xb0,0x9c,0xce,0x47, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x92,0x8a,0x8f,0x1c,0x7a,0xc7,0xbe,0xc1,0x80,0x8b,0x9f,0x61,0xc0,0x1e,0xc3,0x27, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x44,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x03,0xb8,0x78,0x53,0xfd,0x3b,0x7d,0x3f,0x8e,0x17,0x51,0x25,0xb4,0x38,0x2f,0x25,0xed, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x27,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x05,0x56,0x02,0x98,0xd1,0xf2,0xf0,0x8d,0xc4,0x19,0xac,0x27,0x3a,0x5b,0x54,0xd9, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x48,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x31,0xc8,0x3a,0xe8,0x2e,0xbe,0x08,0x98,0x77,0x6b,0x4c,0x69,0xd1,0x1f,0x88,0xde, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x06,0xdd,0x3a,0x19,0xb8,0xd5,0xfb,0x87,0x52,0x35,0x96,0x3c,0x59,0x3b,0xd2,0xd3, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x15, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, - 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x18,0x5d,0xdb,0xca,0x6d,0xac,0x41,0xb1,0xda,0x03,0x3c,0xfb,0x60,0xc1,0x52,0x86,0x9e,0x74,0xb3,0xcd,0x66,0xe9,0xff,0xdf,0x1b,0x6b,0xc0,0x9e,0xd6,0x5e,0xe4,0x0c, - 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, - 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, - 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,0x02,0x20,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x32,0xf2,0x22,0xf8,0xfa,0xef,0xdb,0x53,0x3f,0x26,0x5d,0x46,0x1c,0x29,0xa4,0x73,0x73, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, - 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, - 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, - 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, - 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, - 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, - 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, - 0x30,0x45,0x02,0x21,0x00,0xf8,0x0a,0xe4,0xf9,0x6c,0xdb,0xc9,0xd8,0x53,0xf8,0x3d,0x47,0xaa,0xe2,0x25,0xbf,0x40,0x7d,0x51,0xc5,0x6b,0x77,0x76,0xcd,0x67,0xd0,0xdc,0x19,0x5d,0x99,0xa9,0xdc,0x02,0x20,0x4c,0xfc,0x1d,0x94,0x1e,0x08,0xcb,0x9a,0xce,0xad,0xde,0x0f,0x4c,0xce,0xad,0x76,0xb3,0x0d,0x33,0x2f,0xc4,0x42,0x11,0x5d,0x50,0xe6,0x73,0xe2,0x86,0x86,0xb7,0x0b, - 0x30,0x44,0x02,0x20,0x10,0x9c,0xd8,0xae,0x03,0x74,0x35,0x89,0x84,0xa8,0x24,0x9c,0x0a,0x84,0x36,0x28,0xf2,0x83,0x5f,0xfa,0xd1,0xdf,0x1a,0x9a,0x69,0xaa,0x2f,0xe7,0x23,0x55,0x54,0x5c,0x02,0x20,0x53,0x90,0xff,0x25,0x0a,0xc4,0x27,0x4e,0x1c,0xb2,0x5c,0xd6,0xca,0x64,0x91,0xf6,0xb9,0x12,0x81,0xe3,0x2f,0x5b,0x26,0x4d,0x87,0x97,0x7a,0xed,0x4a,0x94,0xe7,0x7b, - 0x30,0x45,0x02,0x21,0x00,0xd0,0x35,0xee,0x1f,0x17,0xfd,0xb0,0xb2,0x68,0x1b,0x16,0x3e,0x33,0xc3,0x59,0x93,0x26,0x59,0x99,0x0a,0xf7,0x7d,0xca,0x63,0x20,0x12,0xb3,0x0b,0x27,0xa0,0x57,0xb3,0x02,0x20,0x19,0x39,0xd9,0xf3,0xb2,0x85,0x8b,0xc1,0x3e,0x34,0x74,0xcb,0x50,0xe6,0xa8,0x2b,0xe4,0x4f,0xaa,0x71,0x94,0x0f,0x87,0x6c,0x1c,0xba,0x4c,0x3e,0x98,0x92,0x02,0xb6, - 0x30,0x44,0x02,0x20,0x4f,0x05,0x3f,0x56,0x3a,0xd3,0x4b,0x74,0xfd,0x8c,0x99,0x34,0xce,0x59,0xe7,0x9c,0x2e,0xb8,0xe6,0xec,0xa0,0xfe,0xf5,0xb3,0x23,0xca,0x67,0xd5,0xac,0x7e,0xd2,0x38,0x02,0x20,0x4d,0x4b,0x05,0xda,0xa0,0x71,0x9e,0x77,0x3d,0x86,0x17,0xdc,0xe5,0x63,0x1c,0x5f,0xd6,0xf5,0x9c,0x9b,0xdc,0x74,0x8e,0x4b,0x55,0xc9,0x70,0x04,0x0a,0xf0,0x1b,0xe5, - 0x30,0x44,0x02,0x20,0x6d,0x6a,0x4f,0x55,0x6c,0xcc,0xe1,0x54,0xe7,0xfb,0x9f,0x19,0xe7,0x6c,0x3d,0xec,0xa1,0x3d,0x59,0xcc,0x2a,0xeb,0x4e,0xca,0xd9,0x68,0xaa,0xb2,0xde,0xd4,0x59,0x65,0x02,0x20,0x53,0xb9,0xfa,0x74,0x80,0x3e,0xde,0x0f,0xc4,0x44,0x1b,0xf6,0x83,0xd5,0x6c,0x56,0x4d,0x3e,0x27,0x4e,0x09,0xcc,0xf4,0x73,0x90,0xba,0xdd,0x14,0x71,0xc0,0x5f,0xb7, - 0x30,0x44,0x02,0x21,0x00,0xaa,0xd5,0x03,0xde,0x9b,0x9f,0xd6,0x6b,0x94,0x8e,0x9a,0xcf,0x59,0x6f,0x0a,0x0e,0x65,0xe7,0x00,0xb2,0x8b,0x26,0xec,0x56,0xe6,0xe4,0x5e,0x84,0x64,0x89,0xb3,0xc4,0x02,0x1f,0x0d,0xdc,0x3a,0x2f,0x89,0xab,0xb8,0x17,0xbb,0x85,0xc0,0x62,0xce,0x02,0xf8,0x23,0xc6,0x3f,0xc2,0x6b,0x26,0x9e,0x0b,0xc9,0xb8,0x4d,0x81,0xa5,0xaa,0x12,0x3d, - 0x30,0x45,0x02,0x21,0x00,0x91,0x82,0xce,0xbd,0x3b,0xb8,0xab,0x57,0x2e,0x16,0x71,0x74,0x39,0x72,0x09,0xef,0x4b,0x1d,0x43,0x9a,0xf3,0xb2,0x00,0xcd,0xf0,0x03,0x62,0x00,0x89,0xe4,0x32,0x25,0x02,0x20,0x54,0x47,0x7c,0x98,0x2e,0xa0,0x19,0xd2,0xe1,0x00,0x04,0x97,0xfc,0x25,0xfc,0xee,0x1b,0xcc,0xae,0x55,0xf2,0xac,0x27,0x53,0x0a,0xe5,0x3b,0x29,0xc4,0xb3,0x56,0xa4, - 0x30,0x44,0x02,0x20,0x38,0x54,0xa3,0x99,0x8a,0xeb,0xdf,0x2d,0xbc,0x28,0xad,0xac,0x41,0x81,0x46,0x2c,0xca,0xc7,0x87,0x39,0x07,0xab,0x7f,0x21,0x2c,0x42,0xdb,0x0e,0x69,0xb5,0x6e,0xd8,0x02,0x20,0x3e,0xd3,0xf6,0xb8,0xa3,0x88,0xd0,0x2f,0x3e,0x4d,0xf9,0xf2,0xae,0x9c,0x1b,0xd2,0xc3,0x91,0x6a,0x68,0x64,0x60,0xdf,0xfc,0xd4,0x29,0x09,0xcd,0x7f,0x82,0x05,0x8e, - 0x30,0x45,0x02,0x21,0x00,0xe9,0x4d,0xbd,0xc3,0x87,0x95,0xfe,0x5c,0x90,0x4d,0x8f,0x16,0xd9,0x69,0xd3,0xb5,0x87,0xf0,0xa2,0x5d,0x2d,0xe9,0x0b,0x6d,0x8c,0x5c,0x53,0xff,0x88,0x7e,0x36,0x07,0x02,0x20,0x7a,0x94,0x73,0x69,0xc1,0x64,0x97,0x25,0x21,0xbb,0x8a,0xf4,0x06,0x81,0x3b,0x2d,0x9f,0x94,0xd2,0xae,0xaa,0x53,0xd4,0xc2,0x15,0xaa,0xa0,0xa2,0x57,0x8a,0x2c,0x5d, - 0x30,0x44,0x02,0x20,0x49,0xfc,0x10,0x2a,0x08,0xca,0x47,0xb6,0x0e,0x08,0x58,0xcd,0x02,0x84,0xd2,0x2c,0xdd,0xd7,0x23,0x3f,0x94,0xaa,0xff,0xbb,0x2d,0xb1,0xdd,0x2c,0xf0,0x84,0x25,0xe1,0x02,0x20,0x5b,0x16,0xfc,0xa5,0xa1,0x2c,0xdb,0x39,0x70,0x16,0x97,0xad,0x8e,0x39,0xff,0xd6,0xbd,0xec,0x00,0x24,0x29,0x8a,0xfa,0xa2,0x32,0x6a,0xea,0x09,0x20,0x0b,0x14,0xd6, - 0x30,0x44,0x02,0x20,0x41,0xef,0xa7,0xd3,0xf0,0x5a,0x00,0x10,0x67,0x5f,0xcb,0x91,0x8a,0x45,0xc6,0x93,0xda,0x4b,0x34,0x8d,0xf2,0x1a,0x59,0xd6,0xf9,0xcd,0x73,0xe0,0xd8,0x31,0xd6,0x7a,0x02,0x20,0x44,0x54,0xad,0xa6,0x93,0xe5,0xe2,0x6b,0x7b,0xd6,0x93,0x23,0x6d,0x34,0x0f,0x80,0x54,0x5c,0x83,0x45,0x77,0xb6,0xf7,0x3d,0x37,0x8c,0x7b,0xcc,0x53,0x42,0x44,0xda, - 0x30,0x45,0x02,0x21,0x00,0xb6,0x15,0x69,0x8c,0x35,0x8b,0x35,0x92,0x0d,0xd8,0x83,0xec,0xa6,0x25,0xa6,0xc5,0xf7,0x56,0x39,0x70,0xcd,0xfc,0x37,0x8f,0x8f,0xe0,0xce,0xe1,0x70,0x92,0x14,0x4c,0x02,0x20,0x25,0xf4,0x7b,0x32,0x6b,0x5b,0xe1,0xfb,0x61,0x0b,0x88,0x51,0x53,0xea,0x84,0xd4,0x1e,0xb4,0x71,0x6b,0xe6,0x6a,0x99,0x4e,0x87,0x79,0x98,0x9d,0xf1,0xc8,0x63,0xd4, - 0x30,0x45,0x02,0x21,0x00,0x87,0xcf,0x8c,0x0e,0xb8,0x2d,0x44,0xf6,0x9c,0x60,0xa2,0xff,0x54,0x57,0xd3,0xaa,0xa3,0x22,0xe7,0xec,0x61,0xae,0x5a,0xec,0xfd,0x67,0x8a,0xe1,0xc1,0x93,0x2b,0x0e,0x02,0x20,0x3a,0xdd,0x3b,0x11,0x58,0x15,0x04,0x7d,0x6e,0xb3,0x40,0xa3,0xe0,0x08,0x98,0x9e,0xaa,0x0f,0x87,0x08,0xd1,0x79,0x48,0x14,0x72,0x90,0x94,0xd0,0x8d,0x24,0x60,0xd3, - 0x30,0x44,0x02,0x20,0x62,0xf4,0x8e,0xf7,0x1a,0xce,0x27,0xbf,0x5a,0x01,0x83,0x4d,0xe1,0xf7,0xe3,0xf9,0x48,0xb9,0xdc,0xe1,0xca,0x1e,0x91,0x1d,0x5e,0x13,0xd3,0xb1,0x04,0x47,0x1d,0x82,0x02,0x20,0x5e,0xa8,0xf3,0x3f,0x0c,0x77,0x89,0x72,0xc4,0x58,0x20,0x80,0xde,0xda,0x9b,0x34,0x18,0x57,0xdd,0x64,0x51,0x4f,0x08,0x49,0xa0,0x5f,0x69,0x64,0xc2,0xe3,0x40,0x22, - 0x30,0x45,0x02,0x21,0x00,0xf6,0xb0,0xe2,0xf6,0xfe,0x02,0x0c,0xf7,0xc0,0xc2,0x01,0x37,0x43,0x43,0x44,0xed,0x7a,0xdd,0x6c,0x4b,0xe5,0x18,0x61,0xe2,0xd1,0x4c,0xbd,0xa4,0x72,0xa6,0xff,0xb4,0x02,0x20,0x64,0x16,0xc8,0xdd,0x3e,0x5c,0x52,0x82,0xb3,0x06,0xe8,0xdc,0x8f,0xf3,0x4a,0xb6,0x4c,0xc9,0x95,0x49,0x23,0x2d,0x67,0x8d,0x71,0x44,0x02,0xeb,0x6c,0xa7,0xaa,0x0f, - 0x30,0x45,0x02,0x21,0x00,0xdb,0x09,0xd8,0x46,0x0f,0x05,0xef,0xf2,0x3b,0xc7,0xe4,0x36,0xb6,0x7d,0xa5,0x63,0xfa,0x4b,0x4e,0xdb,0x58,0xac,0x24,0xce,0x20,0x1f,0xa8,0xa3,0x58,0x12,0x50,0x57,0x02,0x20,0x46,0xda,0x11,0x67,0x54,0x60,0x29,0x40,0xc8,0x99,0x9c,0x8d,0x66,0x5f,0x78,0x6c,0x50,0xf5,0x77,0x2c,0x0a,0x3c,0xdb,0xda,0x07,0x5e,0x77,0xea,0xbc,0x64,0xdf,0x16, - 0x30,0x44,0x02,0x20,0x59,0x2c,0x41,0xe1,0x65,0x17,0xf1,0x2f,0xca,0xbd,0x98,0x26,0x76,0x74,0xf9,0x74,0xb5,0x88,0xe9,0xf3,0x5d,0x35,0x40,0x6c,0x1a,0x7b,0xb2,0xed,0x1d,0x19,0xb7,0xb8,0x02,0x20,0x3e,0x65,0xa0,0x6b,0xd9,0xf8,0x3c,0xaa,0xeb,0x7b,0x00,0xf2,0x36,0x8d,0x7e,0x0d,0xec,0xe6,0xb1,0x22,0x21,0x26,0x9a,0x9b,0x5b,0x76,0x51,0x98,0xf8,0x40,0xa3,0xa1, - 0x30,0x45,0x02,0x21,0x00,0xbe,0x0d,0x70,0x88,0x7d,0x5e,0x40,0x82,0x1a,0x61,0xb6,0x80,0x47,0xde,0x4e,0xa0,0x3d,0xeb,0xfd,0xf5,0x1c,0xdf,0x4d,0x4b,0x19,0x55,0x58,0xb9,0x59,0xa0,0x32,0xb2,0x02,0x20,0x7d,0x99,0x4b,0x2d,0x8f,0x1d,0xbb,0xeb,0x13,0x53,0x4e,0xb3,0xf6,0xe5,0xdc,0xcd,0x85,0xf5,0xc4,0x13,0x3c,0x27,0xd9,0xe6,0x42,0x71,0xb1,0x82,0x6c,0xe1,0xf6,0x7d, - 0x30,0x45,0x02,0x21,0x00,0xfa,0xe9,0x2d,0xfc,0xb2,0xee,0x39,0x2d,0x27,0x0a,0xf3,0xa5,0x73,0x9f,0xaa,0x26,0xd4,0xf9,0x7b,0xfd,0x39,0xed,0x3c,0xbe,0xe4,0xd2,0x9e,0x26,0xaf,0x3b,0x20,0x6a,0x02,0x20,0x6c,0x9b,0xa3,0x7f,0x9f,0xaa,0x6a,0x1f,0xd3,0xf6,0x5f,0x23,0xb4,0xe8,0x53,0xd4,0x69,0x2a,0x72,0x74,0x24,0x0a,0x12,0xdb,0x7b,0xa3,0x88,0x48,0x30,0x63,0x0d,0x16, - 0x30,0x44,0x02,0x20,0x17,0x6a,0x25,0x57,0x56,0x6f,0xfa,0x51,0x8b,0x11,0x22,0x66,0x94,0xeb,0x98,0x02,0xed,0x20,0x98,0xbf,0xe2,0x78,0xe5,0x57,0x0f,0xe1,0xd5,0xd7,0xaf,0x18,0xa9,0x43,0x02,0x20,0x12,0x91,0xdf,0x6a,0x0e,0xd5,0xfc,0x0d,0x15,0x09,0x8e,0x70,0xbc,0xf1,0x3a,0x00,0x92,0x84,0xdf,0xd0,0x68,0x9d,0x3b,0xb4,0xbe,0x6c,0xee,0xb9,0xbe,0x14,0x87,0xc4, - 0x30,0x44,0x02,0x20,0x60,0xbe,0x20,0xc3,0xdb,0xc1,0x62,0xdd,0x34,0xd2,0x67,0x80,0x62,0x1c,0x10,0x4b,0xbe,0x5d,0xac,0xe6,0x30,0x17,0x1b,0x2d,0xae,0xf0,0xd8,0x26,0x40,0x9e,0xe5,0xc2,0x02,0x20,0x42,0x7f,0x7e,0x4d,0x88,0x9d,0x54,0x91,0x70,0xbd,0xa6,0xa9,0x40,0x9f,0xb1,0xcb,0x8b,0x0e,0x76,0x3d,0x13,0xee,0xa7,0xbd,0x97,0xf6,0x4c,0xf4,0x1d,0xc6,0xe4,0x97, - 0x30,0x45,0x02,0x21,0x00,0xed,0xf0,0x3c,0xf6,0x3f,0x65,0x88,0x83,0x28,0x9a,0x1a,0x59,0x3d,0x10,0x07,0x89,0x5b,0x9f,0x23,0x6d,0x27,0xc9,0xc1,0xf1,0x31,0x30,0x89,0xaa,0xed,0x6b,0x16,0xae,0x02,0x20,0x1a,0x4d,0xd6,0xfc,0x08,0x14,0xdc,0x52,0x3d,0x1f,0xef,0xa8,0x1c,0x64,0xfb,0xf5,0xe6,0x18,0xe6,0x51,0xe7,0x09,0x6f,0xcc,0xad,0xbb,0x94,0xcd,0x48,0xe5,0xe0,0xcd}; - -static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = { - /* tcId: 1. Signature malleability */ - {0, 0, 6, 0, 72, 0 }, - /* tcId: 2. valid */ - {0, 0, 6, 72, 71, 1 }, - /* tcId: 3. length of sequence [r, s] uses long form encoding */ - {0, 0, 6, 143, 72, 0 }, - /* tcId: 4. length of sequence [r, s] contains a leading 0 */ - {0, 0, 6, 215, 73, 0 }, - /* tcId: 5. length of sequence [r, s] uses 70 instead of 69 */ - {0, 0, 6, 288, 71, 0 }, - /* tcId: 6. length of sequence [r, s] uses 68 instead of 69 */ - {0, 0, 6, 359, 71, 0 }, - /* tcId: 7. uint32 overflow in length of sequence [r, s] */ - {0, 0, 6, 430, 76, 0 }, - /* tcId: 8. uint64 overflow in length of sequence [r, s] */ - {0, 0, 6, 506, 80, 0 }, - /* tcId: 9. length of sequence [r, s] = 2**31 - 1 */ - {0, 0, 6, 586, 75, 0 }, - /* tcId: 10. length of sequence [r, s] = 2**31 */ - {0, 0, 6, 661, 75, 0 }, - /* tcId: 11. length of sequence [r, s] = 2**32 - 1 */ - {0, 0, 6, 736, 75, 0 }, - /* tcId: 12. length of sequence [r, s] = 2**40 - 1 */ - {0, 0, 6, 811, 76, 0 }, - /* tcId: 13. length of sequence [r, s] = 2**64 - 1 */ - {0, 0, 6, 887, 79, 0 }, - /* tcId: 14. incorrect length of sequence [r, s] */ - {0, 0, 6, 966, 71, 0 }, - /* tcId: 15. replaced sequence [r, s] by an indefinite length tag without termination */ - {0, 0, 6, 1037, 71, 0 }, - /* tcId: 16. removing sequence [r, s] */ - {0, 0, 6, 1108, 0, 0 }, - /* tcId: 17. lonely sequence tag */ - {0, 0, 6, 1108, 1, 0 }, - /* tcId: 18. appending 0's to sequence [r, s] */ - {0, 0, 6, 1109, 73, 0 }, - /* tcId: 19. prepending 0's to sequence [r, s] */ - {0, 0, 6, 1182, 73, 0 }, - /* tcId: 20. appending unused 0's to sequence [r, s] */ - {0, 0, 6, 1255, 73, 0 }, - /* tcId: 21. appending null value to sequence [r, s] */ - {0, 0, 6, 1328, 73, 0 }, - /* tcId: 22. prepending garbage to sequence [r, s] */ - {0, 0, 6, 1401, 76, 0 }, - /* tcId: 23. prepending garbage to sequence [r, s] */ - {0, 0, 6, 1477, 75, 0 }, - /* tcId: 24. appending garbage to sequence [r, s] */ - {0, 0, 6, 1552, 79, 0 }, - /* tcId: 25. including undefined tags */ - {0, 0, 6, 1631, 79, 0 }, - /* tcId: 26. including undefined tags */ - {0, 0, 6, 1710, 79, 0 }, - /* tcId: 27. including undefined tags */ - {0, 0, 6, 1789, 79, 0 }, - /* tcId: 28. truncated length of sequence [r, s] */ - {0, 0, 6, 1868, 2, 0 }, - /* tcId: 29. including undefined tags to sequence [r, s] */ - {0, 0, 6, 1870, 77, 0 }, - /* tcId: 30. using composition with indefinite length for sequence [r, s] */ - {0, 0, 6, 1947, 75, 0 }, - /* tcId: 31. using composition with wrong tag for sequence [r, s] */ - {0, 0, 6, 2022, 75, 0 }, - /* tcId: 32. Replacing sequence [r, s] with NULL */ - {0, 0, 6, 2097, 2, 0 }, - /* tcId: 33. changing tag value of sequence [r, s] */ - {0, 0, 6, 2099, 71, 0 }, - /* tcId: 34. changing tag value of sequence [r, s] */ - {0, 0, 6, 2170, 71, 0 }, - /* tcId: 35. changing tag value of sequence [r, s] */ - {0, 0, 6, 2241, 71, 0 }, - /* tcId: 36. changing tag value of sequence [r, s] */ - {0, 0, 6, 2312, 71, 0 }, - /* tcId: 37. changing tag value of sequence [r, s] */ - {0, 0, 6, 2383, 71, 0 }, - /* tcId: 38. dropping value of sequence [r, s] */ - {0, 0, 6, 2454, 2, 0 }, - /* tcId: 39. using composition for sequence [r, s] */ - {0, 0, 6, 2456, 75, 0 }, - /* tcId: 40. truncated sequence [r, s] */ - {0, 0, 6, 2531, 70, 0 }, - /* tcId: 41. truncated sequence [r, s] */ - {0, 0, 6, 2601, 70, 0 }, - /* tcId: 42. sequence [r, s] of size 4166 to check for overflows */ - {0, 0, 6, 2671, 4170, 0 }, - /* tcId: 43. indefinite length */ - {0, 0, 6, 6841, 73, 0 }, - /* tcId: 44. indefinite length with truncated delimiter */ - {0, 0, 6, 6914, 72, 0 }, - /* tcId: 45. indefinite length with additional element */ - {0, 0, 6, 6986, 75, 0 }, - /* tcId: 46. indefinite length with truncated element */ - {0, 0, 6, 7061, 77, 0 }, - /* tcId: 47. indefinite length with garbage */ - {0, 0, 6, 7138, 77, 0 }, - /* tcId: 48. indefinite length with nonempty EOC */ - {0, 0, 6, 7215, 75, 0 }, - /* tcId: 49. prepend empty sequence */ - {0, 0, 6, 7290, 73, 0 }, - /* tcId: 50. append empty sequence */ - {0, 0, 6, 7363, 73, 0 }, - /* tcId: 51. append zero */ - {0, 0, 6, 7436, 74, 0 }, - /* tcId: 52. append garbage with high tag number */ - {0, 0, 6, 7510, 74, 0 }, - /* tcId: 53. append null with explicit tag */ - {0, 0, 6, 7584, 75, 0 }, - /* tcId: 54. append null with implicit tag */ - {0, 0, 6, 7659, 73, 0 }, - /* tcId: 55. sequence of sequence */ - {0, 0, 6, 7732, 73, 0 }, - /* tcId: 56. truncated sequence: removed last 1 elements */ - {0, 0, 6, 7805, 37, 0 }, - /* tcId: 57. repeating element in sequence */ - {0, 0, 6, 7842, 105, 0 }, - /* tcId: 58. flipped bit 0 in r */ - {0, 0, 6, 7947, 69, 0 }, - /* tcId: 59. flipped bit 32 in r */ - {0, 0, 6, 8016, 69, 0 }, - /* tcId: 60. flipped bit 48 in r */ - {0, 0, 6, 8085, 69, 0 }, - /* tcId: 61. flipped bit 64 in r */ - {0, 0, 6, 8154, 69, 0 }, - /* tcId: 62. length of r uses long form encoding */ - {0, 0, 6, 8223, 72, 0 }, - /* tcId: 63. length of r contains a leading 0 */ - {0, 0, 6, 8295, 73, 0 }, - /* tcId: 64. length of r uses 34 instead of 33 */ - {0, 0, 6, 8368, 71, 0 }, - /* tcId: 65. length of r uses 32 instead of 33 */ - {0, 0, 6, 8439, 71, 0 }, - /* tcId: 66. uint32 overflow in length of r */ - {0, 0, 6, 8510, 76, 0 }, - /* tcId: 67. uint64 overflow in length of r */ - {0, 0, 6, 8586, 80, 0 }, - /* tcId: 68. length of r = 2**31 - 1 */ - {0, 0, 6, 8666, 75, 0 }, - /* tcId: 69. length of r = 2**31 */ - {0, 0, 6, 8741, 75, 0 }, - /* tcId: 70. length of r = 2**32 - 1 */ - {0, 0, 6, 8816, 75, 0 }, - /* tcId: 71. length of r = 2**40 - 1 */ - {0, 0, 6, 8891, 76, 0 }, - /* tcId: 72. length of r = 2**64 - 1 */ - {0, 0, 6, 8967, 79, 0 }, - /* tcId: 73. incorrect length of r */ - {0, 0, 6, 9046, 71, 0 }, - /* tcId: 74. replaced r by an indefinite length tag without termination */ - {0, 0, 6, 9117, 71, 0 }, - /* tcId: 75. removing r */ - {0, 0, 6, 9188, 36, 0 }, - /* tcId: 76. lonely integer tag */ - {0, 0, 6, 9224, 37, 0 }, - /* tcId: 77. lonely integer tag */ - {0, 0, 6, 9261, 38, 0 }, - /* tcId: 78. appending 0's to r */ - {0, 0, 6, 9299, 73, 0 }, - /* tcId: 79. prepending 0's to r */ - {0, 0, 6, 9372, 73, 0 }, - /* tcId: 80. appending unused 0's to r */ - {0, 0, 6, 9445, 73, 0 }, - /* tcId: 81. appending null value to r */ - {0, 0, 6, 9518, 73, 0 }, - /* tcId: 82. prepending garbage to r */ - {0, 0, 6, 9591, 76, 0 }, - /* tcId: 83. prepending garbage to r */ - {0, 0, 6, 9667, 75, 0 }, - /* tcId: 84. appending garbage to r */ - {0, 0, 6, 9742, 79, 0 }, - /* tcId: 85. truncated length of r */ - {0, 0, 6, 9821, 38, 0 }, - /* tcId: 86. including undefined tags to r */ - {0, 0, 6, 9859, 77, 0 }, - /* tcId: 87. using composition with indefinite length for r */ - {0, 0, 6, 9936, 75, 0 }, - /* tcId: 88. using composition with wrong tag for r */ - {0, 0, 6, 10011, 75, 0 }, - /* tcId: 89. Replacing r with NULL */ - {0, 0, 6, 10086, 38, 0 }, - /* tcId: 90. changing tag value of r */ - {0, 0, 6, 10124, 71, 0 }, - /* tcId: 91. changing tag value of r */ - {0, 0, 6, 10195, 71, 0 }, - /* tcId: 92. changing tag value of r */ - {0, 0, 6, 10266, 71, 0 }, - /* tcId: 93. changing tag value of r */ - {0, 0, 6, 10337, 71, 0 }, - /* tcId: 94. changing tag value of r */ - {0, 0, 6, 10408, 71, 0 }, - /* tcId: 95. dropping value of r */ - {0, 0, 6, 10479, 38, 0 }, - /* tcId: 96. using composition for r */ - {0, 0, 6, 10517, 75, 0 }, - /* tcId: 97. modifying first byte of r */ - {0, 0, 6, 10592, 71, 0 }, - /* tcId: 98. modifying last byte of r */ - {0, 0, 6, 10663, 71, 0 }, - /* tcId: 99. truncated r */ - {0, 0, 6, 10734, 70, 0 }, - /* tcId: 100. truncated r */ - {0, 0, 6, 10804, 70, 0 }, - /* tcId: 101. r of size 4130 to check for overflows */ - {0, 0, 6, 10874, 4172, 0 }, - /* tcId: 102. leading ff in r */ - {0, 0, 6, 15046, 72, 0 }, - /* tcId: 103. replaced r by infinity */ - {0, 0, 6, 15118, 39, 0 }, - /* tcId: 104. replacing r with zero */ - {0, 0, 6, 15157, 39, 0 }, - /* tcId: 105. flipped bit 0 in s */ - {0, 0, 6, 15196, 69, 0 }, - /* tcId: 106. flipped bit 32 in s */ - {0, 0, 6, 15265, 69, 0 }, - /* tcId: 107. flipped bit 48 in s */ - {0, 0, 6, 15334, 69, 0 }, - /* tcId: 108. flipped bit 64 in s */ - {0, 0, 6, 15403, 69, 0 }, - /* tcId: 109. length of s uses long form encoding */ - {0, 0, 6, 15472, 72, 0 }, - /* tcId: 110. length of s contains a leading 0 */ - {0, 0, 6, 15544, 73, 0 }, - /* tcId: 111. length of s uses 33 instead of 32 */ - {0, 0, 6, 15617, 71, 0 }, - /* tcId: 112. length of s uses 31 instead of 32 */ - {0, 0, 6, 15688, 71, 0 }, - /* tcId: 113. uint32 overflow in length of s */ - {0, 0, 6, 15759, 76, 0 }, - /* tcId: 114. uint64 overflow in length of s */ - {0, 0, 6, 15835, 80, 0 }, - /* tcId: 115. length of s = 2**31 - 1 */ - {0, 0, 6, 15915, 75, 0 }, - /* tcId: 116. length of s = 2**31 */ - {0, 0, 6, 15990, 75, 0 }, - /* tcId: 117. length of s = 2**32 - 1 */ - {0, 0, 6, 16065, 75, 0 }, - /* tcId: 118. length of s = 2**40 - 1 */ - {0, 0, 6, 16140, 76, 0 }, - /* tcId: 119. length of s = 2**64 - 1 */ - {0, 0, 6, 16216, 79, 0 }, - /* tcId: 120. incorrect length of s */ - {0, 0, 6, 16295, 71, 0 }, - /* tcId: 121. replaced s by an indefinite length tag without termination */ - {0, 0, 6, 16366, 71, 0 }, - /* tcId: 122. appending 0's to s */ - {0, 0, 6, 16437, 73, 0 }, - /* tcId: 123. prepending 0's to s */ - {0, 0, 6, 16510, 73, 0 }, - /* tcId: 124. appending null value to s */ - {0, 0, 6, 16583, 73, 0 }, - /* tcId: 125. prepending garbage to s */ - {0, 0, 6, 16656, 76, 0 }, - /* tcId: 126. prepending garbage to s */ - {0, 0, 6, 16732, 75, 0 }, - /* tcId: 127. appending garbage to s */ - {0, 0, 6, 16807, 79, 0 }, - /* tcId: 128. truncated length of s */ - {0, 0, 6, 16886, 39, 0 }, - /* tcId: 129. including undefined tags to s */ - {0, 0, 6, 16925, 77, 0 }, - /* tcId: 130. using composition with indefinite length for s */ - {0, 0, 6, 17002, 75, 0 }, - /* tcId: 131. using composition with wrong tag for s */ - {0, 0, 6, 17077, 75, 0 }, - /* tcId: 132. Replacing s with NULL */ - {0, 0, 6, 17152, 39, 0 }, - /* tcId: 133. changing tag value of s */ - {0, 0, 6, 17191, 71, 0 }, - /* tcId: 134. changing tag value of s */ - {0, 0, 6, 17262, 71, 0 }, - /* tcId: 135. changing tag value of s */ - {0, 0, 6, 17333, 71, 0 }, - /* tcId: 136. changing tag value of s */ - {0, 0, 6, 17404, 71, 0 }, - /* tcId: 137. changing tag value of s */ - {0, 0, 6, 17475, 71, 0 }, - /* tcId: 138. dropping value of s */ - {0, 0, 6, 17546, 39, 0 }, - /* tcId: 139. using composition for s */ - {0, 0, 6, 17585, 75, 0 }, - /* tcId: 140. modifying first byte of s */ - {0, 0, 6, 17660, 71, 0 }, - /* tcId: 141. modifying last byte of s */ - {0, 0, 6, 17731, 71, 0 }, - /* tcId: 142. truncated s */ - {0, 0, 6, 17802, 70, 0 }, - /* tcId: 143. truncated s */ - {0, 0, 6, 17872, 70, 0 }, - /* tcId: 144. s of size 4129 to check for overflows */ - {0, 0, 6, 17942, 4172, 0 }, - /* tcId: 145. leading ff in s */ - {0, 0, 6, 22114, 72, 0 }, - /* tcId: 146. replaced s by infinity */ - {0, 0, 6, 22186, 40, 0 }, - /* tcId: 147. replacing s with zero */ - {0, 0, 6, 22226, 40, 0 }, - /* tcId: 148. replaced r by r + n */ - {0, 0, 6, 22266, 71, 0 }, - /* tcId: 149. replaced r by r - n */ - {0, 0, 6, 22337, 70, 0 }, - /* tcId: 150. replaced r by r + 256 * n */ - {0, 0, 6, 22407, 72, 0 }, - /* tcId: 151. replaced r by -r */ - {0, 0, 6, 22479, 71, 0 }, - /* tcId: 152. replaced r by n - r */ - {0, 0, 6, 22550, 70, 0 }, - /* tcId: 153. replaced r by -n - r */ - {0, 0, 6, 22620, 71, 0 }, - /* tcId: 154. replaced r by r + 2**256 */ - {0, 0, 6, 22691, 71, 0 }, - /* tcId: 155. replaced r by r + 2**320 */ - {0, 0, 6, 22762, 79, 0 }, - /* tcId: 156. replaced s by s + n */ - {0, 0, 6, 22841, 71, 0 }, - /* tcId: 157. replaced s by s - n */ - {0, 0, 6, 22912, 71, 0 }, - /* tcId: 158. replaced s by s + 256 * n */ - {0, 0, 6, 22983, 72, 0 }, - /* tcId: 159. replaced s by -s */ - {0, 0, 6, 23055, 70, 0 }, - /* tcId: 160. replaced s by -n - s */ - {0, 0, 6, 23125, 71, 0 }, - /* tcId: 161. replaced s by s + 2**256 */ - {0, 0, 6, 23196, 71, 0 }, - /* tcId: 162. replaced s by s - 2**256 */ - {0, 0, 6, 23267, 71, 0 }, - /* tcId: 163. replaced s by s + 2**320 */ - {0, 0, 6, 23338, 79, 0 }, - /* tcId: 164. Signature with special case values r=0 and s=0 */ - {0, 0, 6, 23417, 8, 0 }, - /* tcId: 165. Signature with special case values r=0 and s=1 */ - {0, 0, 6, 23425, 8, 0 }, - /* tcId: 166. Signature with special case values r=0 and s=-1 */ - {0, 0, 6, 23433, 8, 0 }, - /* tcId: 167. Signature with special case values r=0 and s=n */ - {0, 0, 6, 23441, 40, 0 }, - /* tcId: 168. Signature with special case values r=0 and s=n - 1 */ - {0, 0, 6, 23481, 40, 0 }, - /* tcId: 169. Signature with special case values r=0 and s=n + 1 */ - {0, 0, 6, 23521, 40, 0 }, - /* tcId: 170. Signature with special case values r=0 and s=p */ - {0, 0, 6, 23561, 40, 0 }, - /* tcId: 171. Signature with special case values r=0 and s=p + 1 */ - {0, 0, 6, 23601, 40, 0 }, - /* tcId: 172. Signature with special case values r=1 and s=0 */ - {0, 0, 6, 23641, 8, 0 }, - /* tcId: 173. Signature with special case values r=1 and s=1 */ - {0, 0, 6, 23649, 8, 0 }, - /* tcId: 174. Signature with special case values r=1 and s=-1 */ - {0, 0, 6, 23657, 8, 0 }, - /* tcId: 175. Signature with special case values r=1 and s=n */ - {0, 0, 6, 23665, 40, 0 }, - /* tcId: 176. Signature with special case values r=1 and s=n - 1 */ - {0, 0, 6, 23705, 40, 0 }, - /* tcId: 177. Signature with special case values r=1 and s=n + 1 */ - {0, 0, 6, 23745, 40, 0 }, - /* tcId: 178. Signature with special case values r=1 and s=p */ - {0, 0, 6, 23785, 40, 0 }, - /* tcId: 179. Signature with special case values r=1 and s=p + 1 */ - {0, 0, 6, 23825, 40, 0 }, - /* tcId: 180. Signature with special case values r=-1 and s=0 */ - {0, 0, 6, 23865, 8, 0 }, - /* tcId: 181. Signature with special case values r=-1 and s=1 */ - {0, 0, 6, 23873, 8, 0 }, - /* tcId: 182. Signature with special case values r=-1 and s=-1 */ - {0, 0, 6, 23881, 8, 0 }, - /* tcId: 183. Signature with special case values r=-1 and s=n */ - {0, 0, 6, 23889, 40, 0 }, - /* tcId: 184. Signature with special case values r=-1 and s=n - 1 */ - {0, 0, 6, 23929, 40, 0 }, - /* tcId: 185. Signature with special case values r=-1 and s=n + 1 */ - {0, 0, 6, 23969, 40, 0 }, - /* tcId: 186. Signature with special case values r=-1 and s=p */ - {0, 0, 6, 24009, 40, 0 }, - /* tcId: 187. Signature with special case values r=-1 and s=p + 1 */ - {0, 0, 6, 24049, 40, 0 }, - /* tcId: 188. Signature with special case values r=n and s=0 */ - {0, 0, 6, 24089, 40, 0 }, - /* tcId: 189. Signature with special case values r=n and s=1 */ - {0, 0, 6, 24129, 40, 0 }, - /* tcId: 190. Signature with special case values r=n and s=-1 */ - {0, 0, 6, 24169, 40, 0 }, - /* tcId: 191. Signature with special case values r=n and s=n */ - {0, 0, 6, 24209, 72, 0 }, - /* tcId: 192. Signature with special case values r=n and s=n - 1 */ - {0, 0, 6, 24281, 72, 0 }, - /* tcId: 193. Signature with special case values r=n and s=n + 1 */ - {0, 0, 6, 24353, 72, 0 }, - /* tcId: 194. Signature with special case values r=n and s=p */ - {0, 0, 6, 24425, 72, 0 }, - /* tcId: 195. Signature with special case values r=n and s=p + 1 */ - {0, 0, 6, 24497, 72, 0 }, - /* tcId: 196. Signature with special case values r=n - 1 and s=0 */ - {0, 0, 6, 24569, 40, 0 }, - /* tcId: 197. Signature with special case values r=n - 1 and s=1 */ - {0, 0, 6, 24609, 40, 0 }, - /* tcId: 198. Signature with special case values r=n - 1 and s=-1 */ - {0, 0, 6, 24649, 40, 0 }, - /* tcId: 199. Signature with special case values r=n - 1 and s=n */ - {0, 0, 6, 24689, 72, 0 }, - /* tcId: 200. Signature with special case values r=n - 1 and s=n - 1 */ - {0, 0, 6, 24761, 72, 0 }, - /* tcId: 201. Signature with special case values r=n - 1 and s=n + 1 */ - {0, 0, 6, 24833, 72, 0 }, - /* tcId: 202. Signature with special case values r=n - 1 and s=p */ - {0, 0, 6, 24905, 72, 0 }, - /* tcId: 203. Signature with special case values r=n - 1 and s=p + 1 */ - {0, 0, 6, 24977, 72, 0 }, - /* tcId: 204. Signature with special case values r=n + 1 and s=0 */ - {0, 0, 6, 25049, 40, 0 }, - /* tcId: 205. Signature with special case values r=n + 1 and s=1 */ - {0, 0, 6, 25089, 40, 0 }, - /* tcId: 206. Signature with special case values r=n + 1 and s=-1 */ - {0, 0, 6, 25129, 40, 0 }, - /* tcId: 207. Signature with special case values r=n + 1 and s=n */ - {0, 0, 6, 25169, 72, 0 }, - /* tcId: 208. Signature with special case values r=n + 1 and s=n - 1 */ - {0, 0, 6, 25241, 72, 0 }, - /* tcId: 209. Signature with special case values r=n + 1 and s=n + 1 */ - {0, 0, 6, 25313, 72, 0 }, - /* tcId: 210. Signature with special case values r=n + 1 and s=p */ - {0, 0, 6, 25385, 72, 0 }, - /* tcId: 211. Signature with special case values r=n + 1 and s=p + 1 */ - {0, 0, 6, 25457, 72, 0 }, - /* tcId: 212. Signature with special case values r=p and s=0 */ - {0, 0, 6, 25529, 40, 0 }, - /* tcId: 213. Signature with special case values r=p and s=1 */ - {0, 0, 6, 25569, 40, 0 }, - /* tcId: 214. Signature with special case values r=p and s=-1 */ - {0, 0, 6, 25609, 40, 0 }, - /* tcId: 215. Signature with special case values r=p and s=n */ - {0, 0, 6, 25649, 72, 0 }, - /* tcId: 216. Signature with special case values r=p and s=n - 1 */ - {0, 0, 6, 25721, 72, 0 }, - /* tcId: 217. Signature with special case values r=p and s=n + 1 */ - {0, 0, 6, 25793, 72, 0 }, - /* tcId: 218. Signature with special case values r=p and s=p */ - {0, 0, 6, 25865, 72, 0 }, - /* tcId: 219. Signature with special case values r=p and s=p + 1 */ - {0, 0, 6, 25937, 72, 0 }, - /* tcId: 220. Signature with special case values r=p + 1 and s=0 */ - {0, 0, 6, 26009, 40, 0 }, - /* tcId: 221. Signature with special case values r=p + 1 and s=1 */ - {0, 0, 6, 26049, 40, 0 }, - /* tcId: 222. Signature with special case values r=p + 1 and s=-1 */ - {0, 0, 6, 26089, 40, 0 }, - /* tcId: 223. Signature with special case values r=p + 1 and s=n */ - {0, 0, 6, 26129, 72, 0 }, - /* tcId: 224. Signature with special case values r=p + 1 and s=n - 1 */ - {0, 0, 6, 26201, 72, 0 }, - /* tcId: 225. Signature with special case values r=p + 1 and s=n + 1 */ - {0, 0, 6, 26273, 72, 0 }, - /* tcId: 226. Signature with special case values r=p + 1 and s=p */ - {0, 0, 6, 26345, 72, 0 }, - /* tcId: 227. Signature with special case values r=p + 1 and s=p + 1 */ - {0, 0, 6, 26417, 72, 0 }, - /* tcId: 228. Signature encoding contains incorrect types: r=0, s=0.25 */ - {0, 0, 6, 26489, 10, 0 }, - /* tcId: 229. Signature encoding contains incorrect types: r=0, s=nan */ - {0, 0, 6, 26499, 8, 0 }, - /* tcId: 230. Signature encoding contains incorrect types: r=0, s=True */ - {0, 0, 6, 26507, 8, 0 }, - /* tcId: 231. Signature encoding contains incorrect types: r=0, s=False */ - {0, 0, 6, 26515, 8, 0 }, - /* tcId: 232. Signature encoding contains incorrect types: r=0, s=Null */ - {0, 0, 6, 26523, 7, 0 }, - /* tcId: 233. Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string */ - {0, 0, 6, 26530, 7, 0 }, - /* tcId: 234. Signature encoding contains incorrect types: r=0, s="0" */ - {0, 0, 6, 26537, 8, 0 }, - /* tcId: 235. Signature encoding contains incorrect types: r=0, s=empty list */ - {0, 0, 6, 26545, 7, 0 }, - /* tcId: 236. Signature encoding contains incorrect types: r=0, s=list containing 0 */ - {0, 0, 6, 26552, 10, 0 }, - /* tcId: 237. Signature encoding contains incorrect types: r=1, s=0.25 */ - {0, 0, 6, 26562, 10, 0 }, - /* tcId: 238. Signature encoding contains incorrect types: r=1, s=nan */ - {0, 0, 6, 26572, 8, 0 }, - /* tcId: 239. Signature encoding contains incorrect types: r=1, s=True */ - {0, 0, 6, 26580, 8, 0 }, - /* tcId: 240. Signature encoding contains incorrect types: r=1, s=False */ - {0, 0, 6, 26588, 8, 0 }, - /* tcId: 241. Signature encoding contains incorrect types: r=1, s=Null */ - {0, 0, 6, 26596, 7, 0 }, - /* tcId: 242. Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string */ - {0, 0, 6, 26603, 7, 0 }, - /* tcId: 243. Signature encoding contains incorrect types: r=1, s="0" */ - {0, 0, 6, 26610, 8, 0 }, - /* tcId: 244. Signature encoding contains incorrect types: r=1, s=empty list */ - {0, 0, 6, 26618, 7, 0 }, - /* tcId: 245. Signature encoding contains incorrect types: r=1, s=list containing 0 */ - {0, 0, 6, 26625, 10, 0 }, - /* tcId: 246. Signature encoding contains incorrect types: r=-1, s=0.25 */ - {0, 0, 6, 26635, 10, 0 }, - /* tcId: 247. Signature encoding contains incorrect types: r=-1, s=nan */ - {0, 0, 6, 26645, 8, 0 }, - /* tcId: 248. Signature encoding contains incorrect types: r=-1, s=True */ - {0, 0, 6, 26653, 8, 0 }, - /* tcId: 249. Signature encoding contains incorrect types: r=-1, s=False */ - {0, 0, 6, 26661, 8, 0 }, - /* tcId: 250. Signature encoding contains incorrect types: r=-1, s=Null */ - {0, 0, 6, 26669, 7, 0 }, - /* tcId: 251. Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string */ - {0, 0, 6, 26676, 7, 0 }, - /* tcId: 252. Signature encoding contains incorrect types: r=-1, s="0" */ - {0, 0, 6, 26683, 8, 0 }, - /* tcId: 253. Signature encoding contains incorrect types: r=-1, s=empty list */ - {0, 0, 6, 26691, 7, 0 }, - /* tcId: 254. Signature encoding contains incorrect types: r=-1, s=list containing 0 */ - {0, 0, 6, 26698, 10, 0 }, - /* tcId: 255. Signature encoding contains incorrect types: r=n, s=0.25 */ - {0, 0, 6, 26708, 42, 0 }, - /* tcId: 256. Signature encoding contains incorrect types: r=n, s=nan */ - {0, 0, 6, 26750, 40, 0 }, - /* tcId: 257. Signature encoding contains incorrect types: r=n, s=True */ - {0, 0, 6, 26790, 40, 0 }, - /* tcId: 258. Signature encoding contains incorrect types: r=n, s=False */ - {0, 0, 6, 26830, 40, 0 }, - /* tcId: 259. Signature encoding contains incorrect types: r=n, s=Null */ - {0, 0, 6, 26870, 39, 0 }, - /* tcId: 260. Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string */ - {0, 0, 6, 26909, 39, 0 }, - /* tcId: 261. Signature encoding contains incorrect types: r=n, s="0" */ - {0, 0, 6, 26948, 40, 0 }, - /* tcId: 262. Signature encoding contains incorrect types: r=n, s=empty list */ - {0, 0, 6, 26988, 39, 0 }, - /* tcId: 263. Signature encoding contains incorrect types: r=n, s=list containing 0 */ - {0, 0, 6, 27027, 42, 0 }, - /* tcId: 264. Signature encoding contains incorrect types: r=p, s=0.25 */ - {0, 0, 6, 27069, 42, 0 }, - /* tcId: 265. Signature encoding contains incorrect types: r=p, s=nan */ - {0, 0, 6, 27111, 40, 0 }, - /* tcId: 266. Signature encoding contains incorrect types: r=p, s=True */ - {0, 0, 6, 27151, 40, 0 }, - /* tcId: 267. Signature encoding contains incorrect types: r=p, s=False */ - {0, 0, 6, 27191, 40, 0 }, - /* tcId: 268. Signature encoding contains incorrect types: r=p, s=Null */ - {0, 0, 6, 27231, 39, 0 }, - /* tcId: 269. Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string */ - {0, 0, 6, 27270, 39, 0 }, - /* tcId: 270. Signature encoding contains incorrect types: r=p, s="0" */ - {0, 0, 6, 27309, 40, 0 }, - /* tcId: 271. Signature encoding contains incorrect types: r=p, s=empty list */ - {0, 0, 6, 27349, 39, 0 }, - /* tcId: 272. Signature encoding contains incorrect types: r=p, s=list containing 0 */ - {0, 0, 6, 27388, 42, 0 }, - /* tcId: 273. Signature encoding contains incorrect types: r=0.25, s=0.25 */ - {0, 0, 6, 27430, 12, 0 }, - /* tcId: 274. Signature encoding contains incorrect types: r=nan, s=nan */ - {0, 0, 6, 27442, 8, 0 }, - /* tcId: 275. Signature encoding contains incorrect types: r=True, s=True */ - {0, 0, 6, 27450, 8, 0 }, - /* tcId: 276. Signature encoding contains incorrect types: r=False, s=False */ - {0, 0, 6, 27458, 8, 0 }, - /* tcId: 277. Signature encoding contains incorrect types: r=Null, s=Null */ - {0, 0, 6, 27466, 6, 0 }, - /* tcId: 278. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string */ - {0, 0, 6, 27472, 6, 0 }, - /* tcId: 279. Signature encoding contains incorrect types: r="0", s="0" */ - {0, 0, 6, 27478, 8, 0 }, - /* tcId: 280. Signature encoding contains incorrect types: r=empty list, s=empty list */ - {0, 0, 6, 27486, 6, 0 }, - /* tcId: 281. Signature encoding contains incorrect types: r=list containing 0, s=list containing 0 */ - {0, 0, 6, 27492, 12, 0 }, - /* tcId: 282. Signature encoding contains incorrect types: r=0.25, s=0 */ - {0, 0, 6, 27504, 10, 0 }, - /* tcId: 283. Signature encoding contains incorrect types: r=nan, s=0 */ - {0, 0, 6, 27514, 8, 0 }, - /* tcId: 284. Signature encoding contains incorrect types: r=True, s=0 */ - {0, 0, 6, 27522, 8, 0 }, - /* tcId: 285. Signature encoding contains incorrect types: r=False, s=0 */ - {0, 0, 6, 27530, 8, 0 }, - /* tcId: 286. Signature encoding contains incorrect types: r=Null, s=0 */ - {0, 0, 6, 27538, 7, 0 }, - /* tcId: 287. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0 */ - {0, 0, 6, 27545, 7, 0 }, - /* tcId: 288. Signature encoding contains incorrect types: r="0", s=0 */ - {0, 0, 6, 27552, 8, 0 }, - /* tcId: 289. Signature encoding contains incorrect types: r=empty list, s=0 */ - {0, 0, 6, 27560, 7, 0 }, - /* tcId: 290. Signature encoding contains incorrect types: r=list containing 0, s=0 */ - {0, 0, 6, 27567, 10, 0 }, - /* tcId: 291. Edge case for Shamir multiplication */ - {0, 6, 5, 27577, 71, 1 }, - /* tcId: 292. special case hash */ - {0, 11, 9, 27648, 71, 1 }, - /* tcId: 293. special case hash */ - {0, 20, 10, 27719, 70, 1 }, - /* tcId: 294. special case hash */ - {0, 30, 11, 27789, 71, 1 }, - /* tcId: 295. special case hash */ - {0, 41, 10, 27860, 71, 1 }, - /* tcId: 296. special case hash */ - {0, 51, 10, 27931, 70, 1 }, - /* tcId: 297. special case hash */ - {0, 61, 10, 28001, 71, 1 }, - /* tcId: 298. special case hash */ - {0, 71, 9, 28072, 70, 1 }, - /* tcId: 299. special case hash */ - {0, 80, 10, 28142, 71, 1 }, - /* tcId: 300. special case hash */ - {0, 90, 10, 28213, 71, 1 }, - /* tcId: 301. special case hash */ - {0, 100, 10, 28284, 71, 1 }, - /* tcId: 302. special case hash */ - {0, 110, 10, 28355, 71, 1 }, - /* tcId: 303. special case hash */ - {0, 120, 11, 28426, 70, 1 }, - /* tcId: 304. special case hash */ - {0, 131, 10, 28496, 71, 1 }, - /* tcId: 305. special case hash */ - {0, 141, 10, 28567, 71, 1 }, - /* tcId: 306. special case hash */ - {0, 151, 10, 28638, 70, 1 }, - /* tcId: 307. special case hash */ - {0, 161, 10, 28708, 71, 1 }, - /* tcId: 308. special case hash */ - {0, 171, 10, 28779, 71, 1 }, - /* tcId: 309. special case hash */ - {0, 181, 10, 28850, 70, 1 }, - /* tcId: 310. special case hash */ - {0, 191, 10, 28920, 71, 1 }, - /* tcId: 311. special case hash */ - {0, 201, 10, 28991, 71, 1 }, - /* tcId: 312. special case hash */ - {0, 211, 10, 29062, 71, 1 }, - /* tcId: 313. special case hash */ - {0, 221, 10, 29133, 70, 1 }, - /* tcId: 314. special case hash */ - {0, 231, 10, 29203, 71, 1 }, - /* tcId: 315. special case hash */ - {0, 241, 10, 29274, 71, 1 }, - /* tcId: 316. special case hash */ - {0, 251, 10, 29345, 71, 1 }, - /* tcId: 317. special case hash */ - {0, 261, 11, 29416, 71, 1 }, - /* tcId: 318. special case hash */ - {0, 272, 11, 29487, 70, 1 }, - /* tcId: 319. special case hash */ - {0, 283, 9, 29557, 71, 1 }, - /* tcId: 320. special case hash */ - {0, 292, 9, 29628, 71, 1 }, - /* tcId: 321. special case hash */ - {0, 301, 10, 29699, 71, 1 }, - /* tcId: 322. special case hash */ - {0, 311, 10, 29770, 71, 1 }, - /* tcId: 323. special case hash */ - {0, 321, 10, 29841, 70, 1 }, - /* tcId: 324. special case hash */ - {0, 331, 10, 29911, 70, 1 }, - /* tcId: 325. special case hash */ - {0, 341, 10, 29981, 71, 1 }, - /* tcId: 326. special case hash */ - {0, 351, 9, 30052, 70, 1 }, - /* tcId: 327. special case hash */ - {0, 360, 10, 30122, 70, 1 }, - /* tcId: 328. special case hash */ - {0, 370, 10, 30192, 70, 1 }, - /* tcId: 329. special case hash */ - {0, 380, 10, 30262, 70, 1 }, - /* tcId: 330. special case hash */ - {0, 390, 9, 30332, 71, 1 }, - /* tcId: 331. special case hash */ - {0, 399, 11, 30403, 70, 1 }, - /* tcId: 332. special case hash */ - {0, 410, 9, 30473, 71, 1 }, - /* tcId: 333. special case hash */ - {0, 419, 9, 30544, 71, 1 }, - /* tcId: 334. special case hash */ - {0, 428, 11, 30615, 70, 1 }, - /* tcId: 335. special case hash */ - {0, 439, 8, 30685, 71, 1 }, - /* tcId: 336. special case hash */ - {0, 447, 10, 30756, 70, 1 }, - /* tcId: 337. special case hash */ - {0, 457, 10, 30826, 71, 1 }, - /* tcId: 338. special case hash */ - {0, 467, 10, 30897, 70, 1 }, - /* tcId: 339. special case hash */ - {0, 477, 10, 30967, 70, 1 }, - /* tcId: 340. special case hash */ - {0, 487, 10, 31037, 70, 1 }, - /* tcId: 341. special case hash */ - {0, 497, 10, 31107, 71, 1 }, - /* tcId: 342. special case hash */ - {0, 507, 10, 31178, 70, 1 }, - /* tcId: 343. special case hash */ - {0, 517, 10, 31248, 70, 1 }, - /* tcId: 344. special case hash */ - {0, 527, 10, 31318, 71, 1 }, - /* tcId: 345. special case hash */ - {0, 537, 9, 31389, 70, 1 }, - /* tcId: 346. k*G has a large x-coordinate */ - {65, 0, 6, 31459, 24, 1 }, - /* tcId: 347. r too large */ - {65, 0, 6, 31483, 40, 0 }, - /* tcId: 348. r,s are large */ - {130, 0, 6, 31523, 40, 1 }, - /* tcId: 349. r and s^-1 have a large Hamming weight */ - {195, 0, 6, 31563, 70, 1 }, - /* tcId: 350. r and s^-1 have a large Hamming weight */ - {260, 0, 6, 31633, 70, 1 }, - /* tcId: 351. small r and s */ - {325, 0, 6, 31703, 8, 1 }, - /* tcId: 352. small r and s */ - {390, 0, 6, 31711, 8, 1 }, - /* tcId: 353. small r and s */ - {455, 0, 6, 31719, 8, 1 }, - /* tcId: 354. small r and s */ - {520, 0, 6, 31727, 8, 1 }, - /* tcId: 355. small r and s */ - {585, 0, 6, 31735, 8, 1 }, - /* tcId: 356. small r and s */ - {650, 0, 6, 31743, 8, 1 }, - /* tcId: 357. r is larger than n */ - {650, 0, 6, 31751, 40, 0 }, - /* tcId: 358. s is larger than n */ - {715, 0, 6, 31791, 10, 0 }, - /* tcId: 359. small r and s^-1 */ - {780, 0, 6, 31801, 40, 1 }, - /* tcId: 360. smallish r and s^-1 */ - {845, 0, 6, 31841, 45, 1 }, - /* tcId: 361. 100-bit r and small s^-1 */ - {910, 0, 6, 31886, 51, 1 }, - /* tcId: 362. small r and 100 bit s^-1 */ - {975, 0, 6, 31937, 40, 1 }, - /* tcId: 363. 100-bit r and s^-1 */ - {1040, 0, 6, 31977, 51, 1 }, - /* tcId: 364. r and s^-1 are close to n */ - {1105, 0, 6, 32028, 71, 1 }, - /* tcId: 365. r and s are 64-bit integer */ - {1170, 0, 6, 32099, 24, 1 }, - /* tcId: 366. r and s are 100-bit integer */ - {1235, 0, 6, 32123, 32, 1 }, - /* tcId: 367. r and s are 128-bit integer */ - {1300, 0, 6, 32155, 40, 1 }, - /* tcId: 368. r and s are 160-bit integer */ - {1365, 0, 6, 32195, 48, 1 }, - /* tcId: 369. s == 1 */ - {1430, 0, 6, 32243, 39, 1 }, - /* tcId: 370. s == 0 */ - {1430, 0, 6, 32282, 39, 0 }, - /* tcId: 371. edge case modular inverse */ - {1495, 0, 6, 32321, 70, 1 }, - /* tcId: 372. edge case modular inverse */ - {1560, 0, 6, 32391, 70, 1 }, - /* tcId: 373. edge case modular inverse */ - {1625, 0, 6, 32461, 70, 1 }, - /* tcId: 374. edge case modular inverse */ - {1690, 0, 6, 32531, 70, 1 }, - /* tcId: 375. edge case modular inverse */ - {1755, 0, 6, 32601, 70, 1 }, - /* tcId: 376. edge case modular inverse */ - {1820, 0, 6, 32671, 70, 1 }, - /* tcId: 377. edge case modular inverse */ - {1885, 0, 6, 32741, 70, 1 }, - /* tcId: 378. edge case modular inverse */ - {1950, 0, 6, 32811, 70, 1 }, - /* tcId: 379. edge case modular inverse */ - {2015, 0, 6, 32881, 70, 1 }, - /* tcId: 380. edge case modular inverse */ - {2080, 0, 6, 32951, 70, 1 }, - /* tcId: 381. edge case modular inverse */ - {2145, 0, 6, 33021, 70, 1 }, - /* tcId: 382. edge case modular inverse */ - {2210, 0, 6, 33091, 70, 1 }, - /* tcId: 383. edge case modular inverse */ - {2275, 0, 6, 33161, 70, 1 }, - /* tcId: 384. edge case modular inverse */ - {2340, 0, 6, 33231, 70, 1 }, - /* tcId: 385. edge case modular inverse */ - {2405, 0, 6, 33301, 70, 1 }, - /* tcId: 386. point at infinity during verify */ - {2470, 0, 6, 33371, 70, 0 }, - /* tcId: 387. edge case for signature malleability */ - {2535, 0, 6, 33441, 70, 1 }, - /* tcId: 388. edge case for signature malleability */ - {2600, 0, 6, 33511, 70, 0 }, - /* tcId: 389. u1 == 1 */ - {2665, 0, 6, 33581, 70, 1 }, - /* tcId: 390. u1 == n - 1 */ - {2730, 0, 6, 33651, 70, 1 }, - /* tcId: 391. u2 == 1 */ - {2795, 0, 6, 33721, 70, 1 }, - /* tcId: 392. u2 == n - 1 */ - {2860, 0, 6, 33791, 70, 1 }, - /* tcId: 393. edge case for u1 */ - {2925, 0, 6, 33861, 70, 1 }, - /* tcId: 394. edge case for u1 */ - {2990, 0, 6, 33931, 70, 1 }, - /* tcId: 395. edge case for u1 */ - {3055, 0, 6, 34001, 70, 1 }, - /* tcId: 396. edge case for u1 */ - {3120, 0, 6, 34071, 70, 1 }, - /* tcId: 397. edge case for u1 */ - {3185, 0, 6, 34141, 70, 1 }, - /* tcId: 398. edge case for u1 */ - {3250, 0, 6, 34211, 70, 1 }, - /* tcId: 399. edge case for u1 */ - {3315, 0, 6, 34281, 70, 1 }, - /* tcId: 400. edge case for u1 */ - {3380, 0, 6, 34351, 70, 1 }, - /* tcId: 401. edge case for u1 */ - {3445, 0, 6, 34421, 70, 1 }, - /* tcId: 402. edge case for u1 */ - {3510, 0, 6, 34491, 70, 1 }, - /* tcId: 403. edge case for u1 */ - {3575, 0, 6, 34561, 70, 1 }, - /* tcId: 404. edge case for u1 */ - {3640, 0, 6, 34631, 70, 1 }, - /* tcId: 405. edge case for u1 */ - {3705, 0, 6, 34701, 70, 1 }, - /* tcId: 406. edge case for u1 */ - {3770, 0, 6, 34771, 70, 1 }, - /* tcId: 407. edge case for u1 */ - {3835, 0, 6, 34841, 70, 1 }, - /* tcId: 408. edge case for u2 */ - {3900, 0, 6, 34911, 70, 1 }, - /* tcId: 409. edge case for u2 */ - {3965, 0, 6, 34981, 70, 1 }, - /* tcId: 410. edge case for u2 */ - {4030, 0, 6, 35051, 70, 1 }, - /* tcId: 411. edge case for u2 */ - {4095, 0, 6, 35121, 70, 1 }, - /* tcId: 412. edge case for u2 */ - {4160, 0, 6, 35191, 70, 1 }, - /* tcId: 413. edge case for u2 */ - {4225, 0, 6, 35261, 69, 1 }, - /* tcId: 414. edge case for u2 */ - {4290, 0, 6, 35330, 70, 1 }, - /* tcId: 415. edge case for u2 */ - {4355, 0, 6, 35400, 70, 1 }, - /* tcId: 416. edge case for u2 */ - {4420, 0, 6, 35470, 70, 1 }, - /* tcId: 417. edge case for u2 */ - {4485, 0, 6, 35540, 70, 1 }, - /* tcId: 418. edge case for u2 */ - {4550, 0, 6, 35610, 70, 1 }, - /* tcId: 419. edge case for u2 */ - {4615, 0, 6, 35680, 70, 1 }, - /* tcId: 420. edge case for u2 */ - {4680, 0, 6, 35750, 70, 1 }, - /* tcId: 421. edge case for u2 */ - {4745, 0, 6, 35820, 70, 1 }, - /* tcId: 422. edge case for u2 */ - {4810, 0, 6, 35890, 70, 1 }, - /* tcId: 423. point duplication during verification */ - {4875, 0, 6, 35960, 70, 1 }, - /* tcId: 424. duplication bug */ - {4940, 0, 6, 36030, 70, 0 }, - /* tcId: 425. comparison with point at infinity */ - {5005, 0, 6, 36100, 70, 0 }, - /* tcId: 426. extreme value for k and edgecase s */ - {5070, 0, 6, 36170, 71, 1 }, - /* tcId: 427. extreme value for k and s^-1 */ - {5135, 0, 6, 36241, 71, 1 }, - /* tcId: 428. extreme value for k and s^-1 */ - {5200, 0, 6, 36312, 71, 1 }, - /* tcId: 429. extreme value for k and s^-1 */ - {5265, 0, 6, 36383, 71, 1 }, - /* tcId: 430. extreme value for k and s^-1 */ - {5330, 0, 6, 36454, 71, 1 }, - /* tcId: 431. extreme value for k */ - {5395, 0, 6, 36525, 71, 1 }, - /* tcId: 432. extreme value for k and edgecase s */ - {5460, 0, 6, 36596, 70, 1 }, - /* tcId: 433. extreme value for k and s^-1 */ - {5525, 0, 6, 36666, 70, 1 }, - /* tcId: 434. extreme value for k and s^-1 */ - {5590, 0, 6, 36736, 70, 1 }, - /* tcId: 435. extreme value for k and s^-1 */ - {5655, 0, 6, 36806, 70, 1 }, - /* tcId: 436. extreme value for k and s^-1 */ - {5720, 0, 6, 36876, 70, 1 }, - /* tcId: 437. extreme value for k */ - {5785, 0, 6, 36946, 70, 1 }, - /* tcId: 438. public key shares x-coordinate with generator */ - {5850, 0, 6, 37016, 71, 0 }, - /* tcId: 439. public key shares x-coordinate with generator */ - {5850, 0, 6, 37087, 70, 0 }, - /* tcId: 440. public key shares x-coordinate with generator */ - {5915, 0, 6, 37157, 71, 0 }, - /* tcId: 441. public key shares x-coordinate with generator */ - {5915, 0, 6, 37228, 70, 0 }, - /* tcId: 442. pseudorandom signature */ - {5980, 546, 0, 37298, 71, 1 }, - /* tcId: 443. pseudorandom signature */ - {5980, 546, 3, 37369, 70, 1 }, - /* tcId: 444. pseudorandom signature */ - {5980, 0, 6, 37439, 71, 1 }, - /* tcId: 445. pseudorandom signature */ - {5980, 549, 20, 37510, 70, 1 }, - /* tcId: 446. y-coordinate of the public key is small */ - {6045, 569, 7, 37580, 70, 1 }, - /* tcId: 447. y-coordinate of the public key is small */ - {6045, 569, 7, 37650, 70, 1 }, - /* tcId: 448. y-coordinate of the public key is small */ - {6045, 569, 7, 37720, 71, 1 }, - /* tcId: 449. y-coordinate of the public key is large */ - {6110, 569, 7, 37791, 70, 1 }, - /* tcId: 450. y-coordinate of the public key is large */ - {6110, 569, 7, 37861, 71, 1 }, - /* tcId: 451. y-coordinate of the public key is large */ - {6110, 569, 7, 37932, 70, 1 }, - /* tcId: 452. x-coordinate of the public key is small */ - {6175, 569, 7, 38002, 70, 1 }, - /* tcId: 453. x-coordinate of the public key is small */ - {6175, 569, 7, 38072, 71, 1 }, - /* tcId: 454. x-coordinate of the public key is small */ - {6175, 569, 7, 38143, 71, 1 }, - /* tcId: 455. x-coordinate of the public key has many trailing 1's */ - {6240, 569, 7, 38214, 70, 1 }, - /* tcId: 456. x-coordinate of the public key has many trailing 1's */ - {6240, 569, 7, 38284, 71, 1 }, - /* tcId: 457. x-coordinate of the public key has many trailing 1's */ - {6240, 569, 7, 38355, 71, 1 }, - /* tcId: 458. y-coordinate of the public key has many trailing 1's */ - {6305, 569, 7, 38426, 70, 1 }, - /* tcId: 459. y-coordinate of the public key has many trailing 1's */ - {6305, 569, 7, 38496, 71, 1 }, - /* tcId: 460. y-coordinate of the public key has many trailing 1's */ - {6305, 569, 7, 38567, 71, 1 }, - /* tcId: 461. x-coordinate of the public key has many trailing 0's */ - {6370, 569, 7, 38638, 70, 1 }, - /* tcId: 462. x-coordinate of the public key has many trailing 0's */ - {6370, 569, 7, 38708, 70, 1 }, - /* tcId: 463. x-coordinate of the public key has many trailing 0's */ - {6370, 569, 7, 38778, 71, 1 }, - -}; diff --git a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json deleted file mode 100644 index 9c90747993..0000000000 --- a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json +++ /dev/null @@ -1,6360 +0,0 @@ -{ - "algorithm" : "ECDSA", - "schema" : "ecdsa_bitcoin_verify_schema.json", - "generatorVersion" : "0.9rc5", - "numberOfTests" : 463, - "header" : [ - "Test vectors of type EcdsaBitcoinVerify are meant for the verification", - "of a ECDSA variant used for bitcoin, that add signature non-malleability." - ], - "notes" : { - "ArithmeticError" : { - "bugType" : "EDGE_CASE", - "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", - "cves" : [ - "CVE-2017-18146" - ] - }, - "BerEncodedSignature" : { - "bugType" : "BER_ENCODING", - "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", - "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", - "cves" : [ - "CVE-2020-14966", - "CVE-2020-13822", - "CVE-2019-14859", - "CVE-2016-1000342" - ] - }, - "EdgeCasePublicKey" : { - "bugType" : "EDGE_CASE", - "description" : "The test vector uses a special case public key. " - }, - "EdgeCaseShamirMultiplication" : { - "bugType" : "EDGE_CASE", - "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." - }, - "IntegerOverflow" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." - }, - "InvalidEncoding" : { - "bugType" : "CAN_OF_WORMS", - "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." - }, - "InvalidSignature" : { - "bugType" : "AUTH_BYPASS", - "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", - "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", - "cves" : [ - "CVE-2022-21449", - "CVE-2021-43572", - "CVE-2022-24884" - ] - }, - "InvalidTypesInSignature" : { - "bugType" : "AUTH_BYPASS", - "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", - "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", - "cves" : [ - "CVE-2022-21449" - ] - }, - "ModifiedInteger" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." - }, - "ModifiedSignature" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." - }, - "ModularInverse" : { - "bugType" : "EDGE_CASE", - "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", - "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", - "cves" : [ - "CVE-2019-0865" - ] - }, - "PointDuplication" : { - "bugType" : "EDGE_CASE", - "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", - "cves" : [ - "2020-12607", - "CVE-2015-2730" - ] - }, - "RangeCheck" : { - "bugType" : "CAN_OF_WORMS", - "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", - "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." - }, - "SignatureMalleabilityBitcoin" : { - "bugType" : "SIGNATURE_MALLEABILITY", - "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", - "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", - "links" : [ - "https://en.bitcoin.it/wiki/Transaction_malleability", - "https://en.bitcoinwiki.org/wiki/Transaction_Malleability" - ] - }, - "SmallRandS" : { - "bugType" : "EDGE_CASE", - "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", - "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", - "cves" : [ - "2020-13895" - ] - }, - "SpecialCaseHash" : { - "bugType" : "EDGE_CASE", - "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." - }, - "ValidSignature" : { - "bugType" : "BASIC", - "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." - } - }, - "testGroups" : [ - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", - "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", - "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 1, - "comment" : "Signature malleability", - "flags" : [ - "SignatureMalleabilityBitcoin" - ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", - "result" : "invalid" - }, - { - "tcId" : 2, - "comment" : "valid", - "flags" : [ - "ValidSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "valid" - }, - { - "tcId" : 3, - "comment" : "length of sequence [r, s] uses long form encoding", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 4, - "comment" : "length of sequence [r, s] contains a leading 0", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 5, - "comment" : "length of sequence [r, s] uses 70 instead of 69", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 6, - "comment" : "length of sequence [r, s] uses 68 instead of 69", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 7, - "comment" : "uint32 overflow in length of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 8, - "comment" : "uint64 overflow in length of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 9, - "comment" : "length of sequence [r, s] = 2**31 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 10, - "comment" : "length of sequence [r, s] = 2**31", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 11, - "comment" : "length of sequence [r, s] = 2**32 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 12, - "comment" : "length of sequence [r, s] = 2**40 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 13, - "comment" : "length of sequence [r, s] = 2**64 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 14, - "comment" : "incorrect length of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 15, - "comment" : "replaced sequence [r, s] by an indefinite length tag without termination", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 16, - "comment" : "removing sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "", - "result" : "invalid" - }, - { - "tcId" : 17, - "comment" : "lonely sequence tag", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30", - "result" : "invalid" - }, - { - "tcId" : 18, - "comment" : "appending 0's to sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 19, - "comment" : "prepending 0's to sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 20, - "comment" : "appending unused 0's to sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 21, - "comment" : "appending null value to sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", - "result" : "invalid" - }, - { - "tcId" : 22, - "comment" : "prepending garbage to sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 23, - "comment" : "prepending garbage to sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 24, - "comment" : "appending garbage to sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", - "result" : "invalid" - }, - { - "tcId" : 25, - "comment" : "including undefined tags", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 26, - "comment" : "including undefined tags", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 27, - "comment" : "including undefined tags", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 28, - "comment" : "truncated length of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3081", - "result" : "invalid" - }, - { - "tcId" : 29, - "comment" : "including undefined tags to sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 30, - "comment" : "using composition with indefinite length for sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 31, - "comment" : "using composition with wrong tag for sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 32, - "comment" : "Replacing sequence [r, s] with NULL", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "0500", - "result" : "invalid" - }, - { - "tcId" : 33, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 34, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 35, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 36, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 37, - "comment" : "changing tag value of sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 38, - "comment" : "dropping value of sequence [r, s]", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3000", - "result" : "invalid" - }, - { - "tcId" : 39, - "comment" : "using composition for sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 40, - "comment" : "truncated sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", - "result" : "invalid" - }, - { - "tcId" : 41, - "comment" : "truncated sequence [r, s]", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 42, - "comment" : "sequence [r, s] of size 4166 to check for overflows", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid" - }, - { - "tcId" : 43, - "comment" : "indefinite length", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 44, - "comment" : "indefinite length with truncated delimiter", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", - "result" : "invalid" - }, - { - "tcId" : 45, - "comment" : "indefinite length with additional element", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", - "result" : "invalid" - }, - { - "tcId" : 46, - "comment" : "indefinite length with truncated element", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", - "result" : "invalid" - }, - { - "tcId" : 47, - "comment" : "indefinite length with garbage", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", - "result" : "invalid" - }, - { - "tcId" : 48, - "comment" : "indefinite length with nonempty EOC", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", - "result" : "invalid" - }, - { - "tcId" : 49, - "comment" : "prepend empty sequence", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 50, - "comment" : "append empty sequence", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", - "result" : "invalid" - }, - { - "tcId" : 51, - "comment" : "append zero", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", - "result" : "invalid" - }, - { - "tcId" : 52, - "comment" : "append garbage with high tag number", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", - "result" : "invalid" - }, - { - "tcId" : 53, - "comment" : "append null with explicit tag", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", - "result" : "invalid" - }, - { - "tcId" : 54, - "comment" : "append null with implicit tag", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", - "result" : "invalid" - }, - { - "tcId" : 55, - "comment" : "sequence of sequence", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 56, - "comment" : "truncated sequence: removed last 1 elements", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", - "result" : "invalid" - }, - { - "tcId" : 57, - "comment" : "repeating element in sequence", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 58, - "comment" : "flipped bit 0 in r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 59, - "comment" : "flipped bit 32 in r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 60, - "comment" : "flipped bit 48 in r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 61, - "comment" : "flipped bit 64 in r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 62, - "comment" : "length of r uses long form encoding", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 63, - "comment" : "length of r contains a leading 0", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 64, - "comment" : "length of r uses 34 instead of 33", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 65, - "comment" : "length of r uses 32 instead of 33", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 66, - "comment" : "uint32 overflow in length of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 67, - "comment" : "uint64 overflow in length of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 68, - "comment" : "length of r = 2**31 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 69, - "comment" : "length of r = 2**31", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 70, - "comment" : "length of r = 2**32 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 71, - "comment" : "length of r = 2**40 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 72, - "comment" : "length of r = 2**64 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 73, - "comment" : "incorrect length of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 74, - "comment" : "replaced r by an indefinite length tag without termination", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 75, - "comment" : "removing r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 76, - "comment" : "lonely integer tag", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 77, - "comment" : "lonely integer tag", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", - "result" : "invalid" - }, - { - "tcId" : 78, - "comment" : "appending 0's to r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 79, - "comment" : "prepending 0's to r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 80, - "comment" : "appending unused 0's to r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 81, - "comment" : "appending null value to r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 82, - "comment" : "prepending garbage to r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 83, - "comment" : "prepending garbage to r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 84, - "comment" : "appending garbage to r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 85, - "comment" : "truncated length of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 86, - "comment" : "including undefined tags to r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 87, - "comment" : "using composition with indefinite length for r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 88, - "comment" : "using composition with wrong tag for r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 89, - "comment" : "Replacing r with NULL", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 90, - "comment" : "changing tag value of r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 91, - "comment" : "changing tag value of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 92, - "comment" : "changing tag value of r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 93, - "comment" : "changing tag value of r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 94, - "comment" : "changing tag value of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 95, - "comment" : "dropping value of r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 96, - "comment" : "using composition for r", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 97, - "comment" : "modifying first byte of r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 98, - "comment" : "modifying last byte of r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 99, - "comment" : "truncated r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 100, - "comment" : "truncated r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 101, - "comment" : "r of size 4130 to check for overflows", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 102, - "comment" : "leading ff in r", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 103, - "comment" : "replaced r by infinity", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 104, - "comment" : "replacing r with zero", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 105, - "comment" : "flipped bit 0 in s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", - "result" : "invalid" - }, - { - "tcId" : 106, - "comment" : "flipped bit 32 in s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", - "result" : "invalid" - }, - { - "tcId" : 107, - "comment" : "flipped bit 48 in s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 108, - "comment" : "flipped bit 64 in s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 109, - "comment" : "length of s uses long form encoding", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 110, - "comment" : "length of s contains a leading 0", - "flags" : [ - "BerEncodedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 111, - "comment" : "length of s uses 33 instead of 32", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 112, - "comment" : "length of s uses 31 instead of 32", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 113, - "comment" : "uint32 overflow in length of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 114, - "comment" : "uint64 overflow in length of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 115, - "comment" : "length of s = 2**31 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 116, - "comment" : "length of s = 2**31", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 117, - "comment" : "length of s = 2**32 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 118, - "comment" : "length of s = 2**40 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 119, - "comment" : "length of s = 2**64 - 1", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 120, - "comment" : "incorrect length of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 121, - "comment" : "replaced s by an indefinite length tag without termination", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 122, - "comment" : "appending 0's to s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 123, - "comment" : "prepending 0's to s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 124, - "comment" : "appending null value to s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", - "result" : "invalid" - }, - { - "tcId" : 125, - "comment" : "prepending garbage to s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 126, - "comment" : "prepending garbage to s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 127, - "comment" : "appending garbage to s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", - "result" : "invalid" - }, - { - "tcId" : 128, - "comment" : "truncated length of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", - "result" : "invalid" - }, - { - "tcId" : 129, - "comment" : "including undefined tags to s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 130, - "comment" : "using composition with indefinite length for s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 131, - "comment" : "using composition with wrong tag for s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", - "result" : "invalid" - }, - { - "tcId" : 132, - "comment" : "Replacing s with NULL", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", - "result" : "invalid" - }, - { - "tcId" : 133, - "comment" : "changing tag value of s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 134, - "comment" : "changing tag value of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 135, - "comment" : "changing tag value of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 136, - "comment" : "changing tag value of s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 137, - "comment" : "changing tag value of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 138, - "comment" : "dropping value of s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", - "result" : "invalid" - }, - { - "tcId" : 139, - "comment" : "using composition for s", - "flags" : [ - "InvalidEncoding" - ], - "msg" : "313233343030", - "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 140, - "comment" : "modifying first byte of s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 141, - "comment" : "modifying last byte of s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", - "result" : "invalid" - }, - { - "tcId" : 142, - "comment" : "truncated s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", - "result" : "invalid" - }, - { - "tcId" : 143, - "comment" : "truncated s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 144, - "comment" : "s of size 4129 to check for overflows", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "result" : "invalid" - }, - { - "tcId" : 145, - "comment" : "leading ff in s", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 146, - "comment" : "replaced s by infinity", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", - "result" : "invalid" - }, - { - "tcId" : 147, - "comment" : "replacing s with zero", - "flags" : [ - "ModifiedSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", - "result" : "invalid" - }, - { - "tcId" : 148, - "comment" : "replaced r by r + n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 149, - "comment" : "replaced r by r - n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 150, - "comment" : "replaced r by r + 256 * n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 151, - "comment" : "replaced r by -r", - "flags" : [ - "ModifiedInteger" - ], - "msg" : "313233343030", - "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 152, - "comment" : "replaced r by n - r", - "flags" : [ - "ModifiedInteger" - ], - "msg" : "313233343030", - "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 153, - "comment" : "replaced r by -n - r", - "flags" : [ - "ModifiedInteger" - ], - "msg" : "313233343030", - "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 154, - "comment" : "replaced r by r + 2**256", - "flags" : [ - "IntegerOverflow" - ], - "msg" : "313233343030", - "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 155, - "comment" : "replaced r by r + 2**320", - "flags" : [ - "IntegerOverflow" - ], - "msg" : "313233343030", - "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 156, - "comment" : "replaced s by s + n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 157, - "comment" : "replaced s by s - n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 158, - "comment" : "replaced s by s + 256 * n", - "flags" : [ - "RangeCheck" - ], - "msg" : "313233343030", - "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 159, - "comment" : "replaced s by -s", - "flags" : [ - "ModifiedInteger" - ], - "msg" : "313233343030", - "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 160, - "comment" : "replaced s by -n - s", - "flags" : [ - "ModifiedInteger" - ], - "msg" : "313233343030", - "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 161, - "comment" : "replaced s by s + 2**256", - "flags" : [ - "IntegerOverflow" - ], - "msg" : "313233343030", - "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 162, - "comment" : "replaced s by s - 2**256", - "flags" : [ - "IntegerOverflow" - ], - "msg" : "313233343030", - "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 163, - "comment" : "replaced s by s + 2**320", - "flags" : [ - "IntegerOverflow" - ], - "msg" : "313233343030", - "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", - "result" : "invalid" - }, - { - "tcId" : 164, - "comment" : "Signature with special case values r=0 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3006020100020100", - "result" : "invalid" - }, - { - "tcId" : 165, - "comment" : "Signature with special case values r=0 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3006020100020101", - "result" : "invalid" - }, - { - "tcId" : 166, - "comment" : "Signature with special case values r=0 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30060201000201ff", - "result" : "invalid" - }, - { - "tcId" : 167, - "comment" : "Signature with special case values r=0 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 168, - "comment" : "Signature with special case values r=0 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 169, - "comment" : "Signature with special case values r=0 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 170, - "comment" : "Signature with special case values r=0 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 171, - "comment" : "Signature with special case values r=0 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 172, - "comment" : "Signature with special case values r=1 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3006020101020100", - "result" : "invalid" - }, - { - "tcId" : 173, - "comment" : "Signature with special case values r=1 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3006020101020101", - "result" : "invalid" - }, - { - "tcId" : 174, - "comment" : "Signature with special case values r=1 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30060201010201ff", - "result" : "invalid" - }, - { - "tcId" : 175, - "comment" : "Signature with special case values r=1 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 176, - "comment" : "Signature with special case values r=1 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 177, - "comment" : "Signature with special case values r=1 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 178, - "comment" : "Signature with special case values r=1 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 179, - "comment" : "Signature with special case values r=1 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 180, - "comment" : "Signature with special case values r=-1 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff020100", - "result" : "invalid" - }, - { - "tcId" : 181, - "comment" : "Signature with special case values r=-1 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff020101", - "result" : "invalid" - }, - { - "tcId" : 182, - "comment" : "Signature with special case values r=-1 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff0201ff", - "result" : "invalid" - }, - { - "tcId" : 183, - "comment" : "Signature with special case values r=-1 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 184, - "comment" : "Signature with special case values r=-1 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 185, - "comment" : "Signature with special case values r=-1 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 186, - "comment" : "Signature with special case values r=-1 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 187, - "comment" : "Signature with special case values r=-1 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 188, - "comment" : "Signature with special case values r=n and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", - "result" : "invalid" - }, - { - "tcId" : 189, - "comment" : "Signature with special case values r=n and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", - "result" : "invalid" - }, - { - "tcId" : 190, - "comment" : "Signature with special case values r=n and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", - "result" : "invalid" - }, - { - "tcId" : 191, - "comment" : "Signature with special case values r=n and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 192, - "comment" : "Signature with special case values r=n and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 193, - "comment" : "Signature with special case values r=n and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 194, - "comment" : "Signature with special case values r=n and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 195, - "comment" : "Signature with special case values r=n and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 196, - "comment" : "Signature with special case values r=n - 1 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", - "result" : "invalid" - }, - { - "tcId" : 197, - "comment" : "Signature with special case values r=n - 1 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", - "result" : "invalid" - }, - { - "tcId" : 198, - "comment" : "Signature with special case values r=n - 1 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", - "result" : "invalid" - }, - { - "tcId" : 199, - "comment" : "Signature with special case values r=n - 1 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 200, - "comment" : "Signature with special case values r=n - 1 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 201, - "comment" : "Signature with special case values r=n - 1 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 202, - "comment" : "Signature with special case values r=n - 1 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 203, - "comment" : "Signature with special case values r=n - 1 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 204, - "comment" : "Signature with special case values r=n + 1 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", - "result" : "invalid" - }, - { - "tcId" : 205, - "comment" : "Signature with special case values r=n + 1 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", - "result" : "invalid" - }, - { - "tcId" : 206, - "comment" : "Signature with special case values r=n + 1 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", - "result" : "invalid" - }, - { - "tcId" : 207, - "comment" : "Signature with special case values r=n + 1 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 208, - "comment" : "Signature with special case values r=n + 1 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 209, - "comment" : "Signature with special case values r=n + 1 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 210, - "comment" : "Signature with special case values r=n + 1 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 211, - "comment" : "Signature with special case values r=n + 1 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 212, - "comment" : "Signature with special case values r=p and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", - "result" : "invalid" - }, - { - "tcId" : 213, - "comment" : "Signature with special case values r=p and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", - "result" : "invalid" - }, - { - "tcId" : 214, - "comment" : "Signature with special case values r=p and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", - "result" : "invalid" - }, - { - "tcId" : 215, - "comment" : "Signature with special case values r=p and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 216, - "comment" : "Signature with special case values r=p and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 217, - "comment" : "Signature with special case values r=p and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 218, - "comment" : "Signature with special case values r=p and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 219, - "comment" : "Signature with special case values r=p and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 220, - "comment" : "Signature with special case values r=p + 1 and s=0", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", - "result" : "invalid" - }, - { - "tcId" : 221, - "comment" : "Signature with special case values r=p + 1 and s=1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", - "result" : "invalid" - }, - { - "tcId" : 222, - "comment" : "Signature with special case values r=p + 1 and s=-1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", - "result" : "invalid" - }, - { - "tcId" : 223, - "comment" : "Signature with special case values r=p + 1 and s=n", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "result" : "invalid" - }, - { - "tcId" : 224, - "comment" : "Signature with special case values r=p + 1 and s=n - 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "result" : "invalid" - }, - { - "tcId" : 225, - "comment" : "Signature with special case values r=p + 1 and s=n + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", - "result" : "invalid" - }, - { - "tcId" : 226, - "comment" : "Signature with special case values r=p + 1 and s=p", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "result" : "invalid" - }, - { - "tcId" : 227, - "comment" : "Signature with special case values r=p + 1 and s=p + 1", - "flags" : [ - "InvalidSignature" - ], - "msg" : "313233343030", - "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", - "result" : "invalid" - }, - { - "tcId" : 228, - "comment" : "Signature encoding contains incorrect types: r=0, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3008020100090380fe01", - "result" : "invalid" - }, - { - "tcId" : 229, - "comment" : "Signature encoding contains incorrect types: r=0, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020100090142", - "result" : "invalid" - }, - { - "tcId" : 230, - "comment" : "Signature encoding contains incorrect types: r=0, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020100010101", - "result" : "invalid" - }, - { - "tcId" : 231, - "comment" : "Signature encoding contains incorrect types: r=0, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020100010100", - "result" : "invalid" - }, - { - "tcId" : 232, - "comment" : "Signature encoding contains incorrect types: r=0, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201000500", - "result" : "invalid" - }, - { - "tcId" : 233, - "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201000c00", - "result" : "invalid" - }, - { - "tcId" : 234, - "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201000c0130", - "result" : "invalid" - }, - { - "tcId" : 235, - "comment" : "Signature encoding contains incorrect types: r=0, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201003000", - "result" : "invalid" - }, - { - "tcId" : 236, - "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30080201003003020100", - "result" : "invalid" - }, - { - "tcId" : 237, - "comment" : "Signature encoding contains incorrect types: r=1, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3008020101090380fe01", - "result" : "invalid" - }, - { - "tcId" : 238, - "comment" : "Signature encoding contains incorrect types: r=1, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020101090142", - "result" : "invalid" - }, - { - "tcId" : 239, - "comment" : "Signature encoding contains incorrect types: r=1, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020101010101", - "result" : "invalid" - }, - { - "tcId" : 240, - "comment" : "Signature encoding contains incorrect types: r=1, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006020101010100", - "result" : "invalid" - }, - { - "tcId" : 241, - "comment" : "Signature encoding contains incorrect types: r=1, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201010500", - "result" : "invalid" - }, - { - "tcId" : 242, - "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201010c00", - "result" : "invalid" - }, - { - "tcId" : 243, - "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201010c0130", - "result" : "invalid" - }, - { - "tcId" : 244, - "comment" : "Signature encoding contains incorrect types: r=1, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201013000", - "result" : "invalid" - }, - { - "tcId" : 245, - "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30080201013003020100", - "result" : "invalid" - }, - { - "tcId" : 246, - "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30080201ff090380fe01", - "result" : "invalid" - }, - { - "tcId" : 247, - "comment" : "Signature encoding contains incorrect types: r=-1, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff090142", - "result" : "invalid" - }, - { - "tcId" : 248, - "comment" : "Signature encoding contains incorrect types: r=-1, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff010101", - "result" : "invalid" - }, - { - "tcId" : 249, - "comment" : "Signature encoding contains incorrect types: r=-1, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff010100", - "result" : "invalid" - }, - { - "tcId" : 250, - "comment" : "Signature encoding contains incorrect types: r=-1, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201ff0500", - "result" : "invalid" - }, - { - "tcId" : 251, - "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201ff0c00", - "result" : "invalid" - }, - { - "tcId" : 252, - "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060201ff0c0130", - "result" : "invalid" - }, - { - "tcId" : 253, - "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050201ff3000", - "result" : "invalid" - }, - { - "tcId" : 254, - "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30080201ff3003020100", - "result" : "invalid" - }, - { - "tcId" : 255, - "comment" : "Signature encoding contains incorrect types: r=n, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", - "result" : "invalid" - }, - { - "tcId" : 256, - "comment" : "Signature encoding contains incorrect types: r=n, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", - "result" : "invalid" - }, - { - "tcId" : 257, - "comment" : "Signature encoding contains incorrect types: r=n, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", - "result" : "invalid" - }, - { - "tcId" : 258, - "comment" : "Signature encoding contains incorrect types: r=n, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", - "result" : "invalid" - }, - { - "tcId" : 259, - "comment" : "Signature encoding contains incorrect types: r=n, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", - "result" : "invalid" - }, - { - "tcId" : 260, - "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", - "result" : "invalid" - }, - { - "tcId" : 261, - "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", - "result" : "invalid" - }, - { - "tcId" : 262, - "comment" : "Signature encoding contains incorrect types: r=n, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", - "result" : "invalid" - }, - { - "tcId" : 263, - "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", - "result" : "invalid" - }, - { - "tcId" : 264, - "comment" : "Signature encoding contains incorrect types: r=p, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", - "result" : "invalid" - }, - { - "tcId" : 265, - "comment" : "Signature encoding contains incorrect types: r=p, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", - "result" : "invalid" - }, - { - "tcId" : 266, - "comment" : "Signature encoding contains incorrect types: r=p, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", - "result" : "invalid" - }, - { - "tcId" : 267, - "comment" : "Signature encoding contains incorrect types: r=p, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", - "result" : "invalid" - }, - { - "tcId" : 268, - "comment" : "Signature encoding contains incorrect types: r=p, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", - "result" : "invalid" - }, - { - "tcId" : 269, - "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", - "result" : "invalid" - }, - { - "tcId" : 270, - "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", - "result" : "invalid" - }, - { - "tcId" : 271, - "comment" : "Signature encoding contains incorrect types: r=p, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", - "result" : "invalid" - }, - { - "tcId" : 272, - "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", - "result" : "invalid" - }, - { - "tcId" : 273, - "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "300a090380fe01090380fe01", - "result" : "invalid" - }, - { - "tcId" : 274, - "comment" : "Signature encoding contains incorrect types: r=nan, s=nan", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006090142090142", - "result" : "invalid" - }, - { - "tcId" : 275, - "comment" : "Signature encoding contains incorrect types: r=True, s=True", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006010101010101", - "result" : "invalid" - }, - { - "tcId" : 276, - "comment" : "Signature encoding contains incorrect types: r=False, s=False", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006010100010100", - "result" : "invalid" - }, - { - "tcId" : 277, - "comment" : "Signature encoding contains incorrect types: r=Null, s=Null", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "300405000500", - "result" : "invalid" - }, - { - "tcId" : 278, - "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30040c000c00", - "result" : "invalid" - }, - { - "tcId" : 279, - "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060c01300c0130", - "result" : "invalid" - }, - { - "tcId" : 280, - "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "300430003000", - "result" : "invalid" - }, - { - "tcId" : 281, - "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "300a30030201003003020100", - "result" : "invalid" - }, - { - "tcId" : 282, - "comment" : "Signature encoding contains incorrect types: r=0.25, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3008090380fe01020100", - "result" : "invalid" - }, - { - "tcId" : 283, - "comment" : "Signature encoding contains incorrect types: r=nan, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006090142020100", - "result" : "invalid" - }, - { - "tcId" : 284, - "comment" : "Signature encoding contains incorrect types: r=True, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006010101020100", - "result" : "invalid" - }, - { - "tcId" : 285, - "comment" : "Signature encoding contains incorrect types: r=False, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "3006010100020100", - "result" : "invalid" - }, - { - "tcId" : 286, - "comment" : "Signature encoding contains incorrect types: r=Null, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050500020100", - "result" : "invalid" - }, - { - "tcId" : 287, - "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30050c00020100", - "result" : "invalid" - }, - { - "tcId" : 288, - "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30060c0130020100", - "result" : "invalid" - }, - { - "tcId" : 289, - "comment" : "Signature encoding contains incorrect types: r=empty list, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30053000020100", - "result" : "invalid" - }, - { - "tcId" : 290, - "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0", - "flags" : [ - "InvalidTypesInSignature" - ], - "msg" : "313233343030", - "sig" : "30083003020100020100", - "result" : "invalid" - }, - { - "tcId" : 291, - "comment" : "Edge case for Shamir multiplication", - "flags" : [ - "EdgeCaseShamirMultiplication" - ], - "msg" : "3235353835", - "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", - "result" : "valid" - }, - { - "tcId" : 292, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "343236343739373234", - "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", - "result" : "valid" - }, - { - "tcId" : 293, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "37313338363834383931", - "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", - "result" : "valid" - }, - { - "tcId" : 294, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3130333539333331363638", - "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", - "result" : "valid" - }, - { - "tcId" : 295, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33393439343031323135", - "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", - "result" : "valid" - }, - { - "tcId" : 296, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31333434323933303739", - "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", - "result" : "valid" - }, - { - "tcId" : 297, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33373036323131373132", - "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", - "result" : "valid" - }, - { - "tcId" : 298, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "333433363838373132", - "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", - "result" : "valid" - }, - { - "tcId" : 299, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31333531353330333730", - "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", - "result" : "valid" - }, - { - "tcId" : 300, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "36353533323033313236", - "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", - "result" : "valid" - }, - { - "tcId" : 301, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31353634333436363033", - "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", - "result" : "valid" - }, - { - "tcId" : 302, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "34343239353339313137", - "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", - "result" : "valid" - }, - { - "tcId" : 303, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3130393533323631333531", - "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", - "result" : "valid" - }, - { - "tcId" : 304, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "35393837333530303431", - "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", - "result" : "valid" - }, - { - "tcId" : 305, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33343633303036383738", - "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", - "result" : "valid" - }, - { - "tcId" : 306, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "39383137333230323837", - "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", - "result" : "valid" - }, - { - "tcId" : 307, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33323232303431303436", - "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", - "result" : "valid" - }, - { - "tcId" : 308, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "36363636333037313034", - "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", - "result" : "valid" - }, - { - "tcId" : 309, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31303335393531383938", - "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", - "result" : "valid" - }, - { - "tcId" : 310, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31383436353937313935", - "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", - "result" : "valid" - }, - { - "tcId" : 311, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33313336303436313839", - "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", - "result" : "valid" - }, - { - "tcId" : 312, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "32363633373834323534", - "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", - "result" : "valid" - }, - { - "tcId" : 313, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31363532313030353234", - "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", - "result" : "valid" - }, - { - "tcId" : 314, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "35373438303831363936", - "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", - "result" : "valid" - }, - { - "tcId" : 315, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "36333433393133343638", - "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", - "result" : "valid" - }, - { - "tcId" : 316, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31353431313033353938", - "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", - "result" : "valid" - }, - { - "tcId" : 317, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3130343738353830313238", - "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", - "result" : "valid" - }, - { - "tcId" : 318, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3130353336323835353638", - "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", - "result" : "valid" - }, - { - "tcId" : 319, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "393533393034313035", - "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", - "result" : "valid" - }, - { - "tcId" : 320, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "393738383438303339", - "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", - "result" : "valid" - }, - { - "tcId" : 321, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33363130363732343432", - "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", - "result" : "valid" - }, - { - "tcId" : 322, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31303534323430373035", - "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", - "result" : "valid" - }, - { - "tcId" : 323, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "35313734343438313937", - "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", - "result" : "valid" - }, - { - "tcId" : 324, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31393637353631323531", - "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", - "result" : "valid" - }, - { - "tcId" : 325, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33343437323533333433", - "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", - "result" : "valid" - }, - { - "tcId" : 326, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "333638323634333138", - "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", - "result" : "valid" - }, - { - "tcId" : 327, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33323631313938363038", - "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", - "result" : "valid" - }, - { - "tcId" : 328, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "39363738373831303934", - "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", - "result" : "valid" - }, - { - "tcId" : 329, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "34393538383233383233", - "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", - "result" : "valid" - }, - { - "tcId" : 330, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "383234363337383337", - "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", - "result" : "valid" - }, - { - "tcId" : 331, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3131303230383333373736", - "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", - "result" : "valid" - }, - { - "tcId" : 332, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "313333383731363438", - "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", - "result" : "valid" - }, - { - "tcId" : 333, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "333232313434313632", - "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", - "result" : "valid" - }, - { - "tcId" : 334, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3130363836363535353436", - "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", - "result" : "valid" - }, - { - "tcId" : 335, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "3632313535323436", - "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", - "result" : "valid" - }, - { - "tcId" : 336, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "37303330383138373734", - "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", - "result" : "valid" - }, - { - "tcId" : 337, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "35393234353233373434", - "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", - "result" : "valid" - }, - { - "tcId" : 338, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31343935353836363231", - "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", - "result" : "valid" - }, - { - "tcId" : 339, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "34303035333134343036", - "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", - "result" : "valid" - }, - { - "tcId" : 340, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "33303936343537353132", - "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", - "result" : "valid" - }, - { - "tcId" : 341, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "32373834303235363230", - "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", - "result" : "valid" - }, - { - "tcId" : 342, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "32363138373837343138", - "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", - "result" : "valid" - }, - { - "tcId" : 343, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "31363432363235323632", - "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", - "result" : "valid" - }, - { - "tcId" : 344, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "36383234313839343336", - "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", - "result" : "valid" - }, - { - "tcId" : 345, - "comment" : "special case hash", - "flags" : [ - "SpecialCaseHash" - ], - "msg" : "343834323435343235", - "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", - "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", - "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 346, - "comment" : "k*G has a large x-coordinate", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103", - "result" : "valid" - }, - { - "tcId" : 347, - "comment" : "r too large", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", - "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", - "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 348, - "comment" : "r,s are large", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", - "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", - "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 349, - "comment" : "r and s^-1 have a large Hamming weight", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", - "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", - "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 350, - "comment" : "r and s^-1 have a large Hamming weight", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", - "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", - "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 351, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020101020101", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", - "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", - "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 352, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020101020102", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", - "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", - "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 353, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020101020103", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", - "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", - "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 354, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020102020101", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", - "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", - "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 355, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020102020102", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", - "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", - "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 356, - "comment" : "small r and s", - "flags" : [ - "SmallRandS", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3006020102020103", - "result" : "valid" - }, - { - "tcId" : 357, - "comment" : "r is larger than n", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", - "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", - "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 358, - "comment" : "s is larger than n", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "30080201020203ed2979", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", - "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", - "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 359, - "comment" : "small r and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", - "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", - "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 360, - "comment" : "smallish r and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", - "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", - "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 361, - "comment" : "100-bit r and small s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", - "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", - "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 362, - "comment" : "small r and 100 bit s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", - "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", - "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 363, - "comment" : "100-bit r and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", - "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", - "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 364, - "comment" : "r and s^-1 are close to n", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", - "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", - "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 365, - "comment" : "r and s are 64-bit integer", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", - "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", - "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 366, - "comment" : "r and s are 100-bit integer", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", - "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", - "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 367, - "comment" : "r and s are 128-bit integer", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", - "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", - "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 368, - "comment" : "r and s are 160-bit integer", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", - "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", - "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 369, - "comment" : "s == 1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", - "result" : "valid" - }, - { - "tcId" : 370, - "comment" : "s == 0", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", - "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", - "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 371, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", - "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", - "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 372, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", - "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", - "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 373, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", - "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", - "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 374, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", - "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", - "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 375, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", - "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", - "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 376, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", - "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", - "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 377, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", - "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", - "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 378, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", - "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", - "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 379, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", - "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", - "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 380, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", - "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", - "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 381, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", - "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", - "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 382, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", - "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", - "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 383, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", - "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", - "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 384, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", - "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", - "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 385, - "comment" : "edge case modular inverse", - "flags" : [ - "ModularInverse", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", - "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", - "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 386, - "comment" : "point at infinity during verify", - "flags" : [ - "PointDuplication", - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", - "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", - "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 387, - "comment" : "edge case for signature malleability", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", - "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", - "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 388, - "comment" : "edge case for signature malleability", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", - "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", - "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 389, - "comment" : "u1 == 1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", - "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", - "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 390, - "comment" : "u1 == n - 1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", - "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", - "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 391, - "comment" : "u2 == 1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", - "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", - "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 392, - "comment" : "u2 == n - 1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", - "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", - "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 393, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", - "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", - "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 394, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", - "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", - "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 395, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", - "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", - "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 396, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", - "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", - "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 397, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", - "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", - "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 398, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", - "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", - "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 399, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", - "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", - "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 400, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", - "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", - "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 401, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", - "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", - "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 402, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", - "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", - "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 403, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", - "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", - "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 404, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", - "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", - "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 405, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", - "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", - "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 406, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", - "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", - "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 407, - "comment" : "edge case for u1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", - "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", - "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 408, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", - "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", - "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 409, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", - "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", - "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 410, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", - "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", - "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 411, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", - "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", - "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 412, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", - "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", - "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 413, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", - "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", - "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 414, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", - "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", - "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 415, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", - "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", - "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 416, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", - "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", - "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 417, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", - "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", - "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 418, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", - "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", - "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 419, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", - "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", - "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 420, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", - "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", - "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 421, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", - "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", - "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 422, - "comment" : "edge case for u2", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", - "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", - "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 423, - "comment" : "point duplication during verification", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", - "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", - "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 424, - "comment" : "duplication bug", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", - "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", - "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 425, - "comment" : "comparison with point at infinity ", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", - "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", - "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 426, - "comment" : "extreme value for k and edgecase s", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", - "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", - "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 427, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", - "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", - "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 428, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", - "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", - "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 429, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", - "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", - "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 430, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", - "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", - "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 431, - "comment" : "extreme value for k", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", - "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", - "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 432, - "comment" : "extreme value for k and edgecase s", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", - "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", - "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 433, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", - "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", - "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 434, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", - "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", - "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 435, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", - "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", - "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 436, - "comment" : "extreme value for k and s^-1", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", - "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", - "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 437, - "comment" : "extreme value for k", - "flags" : [ - "ArithmeticError" - ], - "msg" : "313233343030", - "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 438, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" - }, - { - "tcId" : 439, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", - "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 440, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" - }, - { - "tcId" : 441, - "comment" : "public key shares x-coordinate with generator", - "flags" : [ - "PointDuplication" - ], - "msg" : "313233343030", - "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", - "result" : "invalid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", - "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", - "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 442, - "comment" : "pseudorandom signature", - "flags" : [ - "ValidSignature" - ], - "msg" : "", - "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", - "result" : "valid" - }, - { - "tcId" : 443, - "comment" : "pseudorandom signature", - "flags" : [ - "ValidSignature" - ], - "msg" : "4d7367", - "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", - "result" : "valid" - }, - { - "tcId" : 444, - "comment" : "pseudorandom signature", - "flags" : [ - "ValidSignature" - ], - "msg" : "313233343030", - "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", - "result" : "valid" - }, - { - "tcId" : 445, - "comment" : "pseudorandom signature", - "flags" : [ - "ValidSignature" - ], - "msg" : "0000000000000000000000000000000000000000", - "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", - "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", - "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 446, - "comment" : "y-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", - "result" : "valid" - }, - { - "tcId" : 447, - "comment" : "y-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", - "result" : "valid" - }, - { - "tcId" : 448, - "comment" : "y-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", - "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", - "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 449, - "comment" : "y-coordinate of the public key is large", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", - "result" : "valid" - }, - { - "tcId" : 450, - "comment" : "y-coordinate of the public key is large", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", - "result" : "valid" - }, - { - "tcId" : 451, - "comment" : "y-coordinate of the public key is large", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", - "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", - "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 452, - "comment" : "x-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", - "result" : "valid" - }, - { - "tcId" : 453, - "comment" : "x-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", - "result" : "valid" - }, - { - "tcId" : 454, - "comment" : "x-coordinate of the public key is small", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", - "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", - "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 455, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", - "result" : "valid" - }, - { - "tcId" : 456, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", - "result" : "valid" - }, - { - "tcId" : 457, - "comment" : "x-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", - "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", - "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 458, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", - "result" : "valid" - }, - { - "tcId" : 459, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", - "result" : "valid" - }, - { - "tcId" : 460, - "comment" : "y-coordinate of the public key has many trailing 1's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", - "result" : "valid" - } - ] - }, - { - "type" : "EcdsaBitcoinVerify", - "publicKey" : { - "type" : "EcPublicKey", - "curve" : "secp256k1", - "keySize" : 256, - "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", - "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", - "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" - }, - "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", - "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", - "sha" : "SHA-256", - "tests" : [ - { - "tcId" : 461, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", - "result" : "valid" - }, - { - "tcId" : 462, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", - "result" : "valid" - }, - { - "tcId" : 463, - "comment" : "x-coordinate of the public key has many trailing 0's", - "flags" : [ - "EdgeCasePublicKey" - ], - "msg" : "4d657373616765", - "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", - "result" : "valid" - } - ] - } - ] -} diff --git a/external/secp256k1/tools/check-abi.sh b/external/secp256k1/tools/check-abi.sh deleted file mode 100755 index 601a64ba96..0000000000 --- a/external/secp256k1/tools/check-abi.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh - -set -eu - -default_base_version="$(git describe --match "v*.*.*" --abbrev=0)" -default_new_version="HEAD" - -display_help_and_exit() { - echo "Usage: $0 [ []]" - echo "" - echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI" - echo " of a new version of libsecp256k1 has changed in a backward-incompatible way." - echo "" - echo "Options:" - echo " base_ver Specify the base version as a git commit-ish" - echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")" - echo " new_ver Specify the new version as a git commit-ish" - echo " (default: $default_new_version)" - echo " -h, --help Display this help message" - exit 0 -} - -if [ "$#" -eq 0 ]; then - base_version="$default_base_version" - new_version="$default_new_version" -elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then - display_help_and_exit -elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then - base_version="$1" - if [ "$#" -eq 2 ]; then - new_version="$2" - fi -else - echo "Invalid usage. See help:" - echo "" - display_help_and_exit -fi - -checkout_and_build() { - _orig_dir="$(pwd)" - git worktree add --detach "$1" "$2" - cd "$1" - mkdir build && cd build - cmake -S .. --preset dev-mode \ - -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \ - -DSECP256K1_BUILD_BENCHMARK=OFF \ - -DSECP256K1_BUILD_TESTS=OFF \ - -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ - -DSECP256K1_BUILD_CTIME_TESTS=OFF \ - -DSECP256K1_BUILD_EXAMPLES=OFF - cmake --build . -j "$(nproc)" - # FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is - # released. - if [ -f "src/libsecp256k1.so" ]; then - LIBPATH="src/libsecp256k1.so" - else - LIBPATH="lib/libsecp256k1.so" - fi - abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/ - cd "$_orig_dir" -} - -echo "Comparing $base_version (base version) to $new_version (new version)" -echo - -base_source_dir="$(mktemp -d)" -checkout_and_build "$base_source_dir" "$base_version" - -new_source_dir="$(mktemp -d)" -checkout_and_build "$new_source_dir" "$new_version" - -abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump" -git worktree remove "$base_source_dir" -git worktree remove "$new_source_dir" diff --git a/external/secp256k1/tools/test_vectors_musig2_generate.py b/external/secp256k1/tools/test_vectors_musig2_generate.py deleted file mode 100755 index 97424419f3..0000000000 --- a/external/secp256k1/tools/test_vectors_musig2_generate.py +++ /dev/null @@ -1,656 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import json -import textwrap - -max_pubkeys = 0 - -if len(sys.argv) < 2: - print( - "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework." - ) - print("Usage: %s " % sys.argv[0]) - sys.exit(1) - - -def hexstr_to_intarray(str): - return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)]) - - -def create_init(name): - return """ -static const struct musig_%s_vector musig_%s_vector = { -""" % ( - name, - name, - ) - - -def init_array(key): - return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ") - - -def init_arrays(key): - s = textwrap.indent("{\n", 4 * " ") - s += textwrap.indent( - ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " " - ) - s += textwrap.indent("\n},\n", 4 * " ") - return s - - -def init_indices(array): - return " %d, { %s }" % ( - len(array), - ", ".join(map(str, array) if len(array) > 0 else "0"), - ) - - -def init_is_xonly(case): - if len(case["tweak_indices"]) > 0: - return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"])) - return "0" - - -def init_optional_expected(case): - return hexstr_to_intarray(case["expected"]) if "expected" in case else 0 - - -def init_cases(cases, f): - s = textwrap.indent("{\n", 4 * " ") - for (i, case) in enumerate(cases): - s += textwrap.indent("%s\n" % f(case), 8 * " ") - s += textwrap.indent("},\n", 4 * " ") - return s - - -def finish_init(): - return "};\n" - - -s = ( - """/** - * Automatically generated by %s. - * - * The test vectors for the KeySort function are included in this file. They can - * be found in src/modules/extrakeys/tests_impl.h. */ -""" - % sys.argv[0] -) - - -s += """ -enum MUSIG_ERROR { - MUSIG_PUBKEY, - MUSIG_TWEAK, - MUSIG_PUBNONCE, - MUSIG_AGGNONCE, - MUSIG_SECNONCE, - MUSIG_SIG, - MUSIG_SIG_VERIFY, - MUSIG_OTHER -}; -""" - -# key agg vectors -with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f: - data = json.load(f) - - max_key_indices = max( - len(test_case["key_indices"]) for test_case in data["valid_test_cases"] - ) - max_tweak_indices = max( - len(test_case["tweak_indices"]) for test_case in data["error_test_cases"] - ) - num_pubkeys = len(data["pubkeys"]) - max_pubkeys = max(num_pubkeys, max_pubkeys) - num_tweaks = len(data["tweaks"]) - num_valid_cases = len(data["valid_test_cases"]) - num_error_cases = len(data["error_test_cases"]) - - # Add structures for valid and error cases - s += ( - """ -struct musig_key_agg_valid_test_case { - size_t key_indices_len; - size_t key_indices[%d]; - unsigned char expected[32]; -}; -""" - % max_key_indices - ) - s += """ -struct musig_key_agg_error_test_case { - size_t key_indices_len; - size_t key_indices[%d]; - size_t tweak_indices_len; - size_t tweak_indices[%d]; - int is_xonly[%d]; - enum MUSIG_ERROR error; -}; -""" % ( - max_key_indices, - max_tweak_indices, - max_tweak_indices, - ) - - # Add structure for entire vector - s += """ -struct musig_key_agg_vector { - unsigned char pubkeys[%d][33]; - unsigned char tweaks[%d][32]; - struct musig_key_agg_valid_test_case valid_case[%d]; - struct musig_key_agg_error_test_case error_case[%d]; -}; -""" % ( - num_pubkeys, - num_tweaks, - num_valid_cases, - num_error_cases, - ) - - s += create_init("key_agg") - # Add pubkeys and tweaks to the vector - s += init_arrays("pubkeys") - s += init_arrays("tweaks") - - # Add valid cases to the vector - s += init_cases( - data["valid_test_cases"], - lambda case: "{ %s, { %s }}," - % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])), - ) - - def comment_to_error(case): - comment = case["comment"] - if "public key" in comment.lower(): - return "MUSIG_PUBKEY" - elif "tweak" in comment.lower(): - return "MUSIG_TWEAK" - else: - sys.exit("Unknown error") - - # Add error cases to the vector - s += init_cases( - data["error_test_cases"], - lambda case: "{ %s, %s, { %s }, %s }," - % ( - init_indices(case["key_indices"]), - init_indices(case["tweak_indices"]), - init_is_xonly(case), - comment_to_error(case), - ), - ) - - s += finish_init() - -# nonce gen vectors -with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f: - data = json.load(f) - - # The MuSig2 implementation only allows messages of length 32 - data["test_cases"] = list( - filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"]) - ) - - num_tests = len(data["test_cases"]) - - s += """ -struct musig_nonce_gen_test_case { - unsigned char rand_[32]; - int has_sk; - unsigned char sk[32]; - unsigned char pk[33]; - int has_aggpk; - unsigned char aggpk[32]; - int has_msg; - unsigned char msg[32]; - int has_extra_in; - unsigned char extra_in[32]; - unsigned char expected_secnonce[97]; - unsigned char expected_pubnonce[66]; -}; -""" - - s += ( - """ -struct musig_nonce_gen_vector { - struct musig_nonce_gen_test_case test_case[%d]; -}; -""" - % num_tests - ) - - s += create_init("nonce_gen") - - def init_array_maybe(array): - return "%d , { %s }" % ( - 0 if array is None else 1, - hexstr_to_intarray(array) if array is not None else 0, - ) - - s += init_cases( - data["test_cases"], - lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } }," - % ( - hexstr_to_intarray(case["rand_"]), - init_array_maybe(case["sk"]), - hexstr_to_intarray(case["pk"]), - init_array_maybe(case["aggpk"]), - init_array_maybe(case["msg"]), - init_array_maybe(case["extra_in"]), - hexstr_to_intarray(case["expected_secnonce"]), - hexstr_to_intarray(case["expected_pubnonce"]), - ), - ) - - s += finish_init() - -# nonce agg vectors -with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f: - data = json.load(f) - - num_pnonces = len(data["pnonces"]) - num_valid_cases = len(data["valid_test_cases"]) - num_error_cases = len(data["error_test_cases"]) - - pnonce_indices_len = 2 - for case in data["valid_test_cases"] + data["error_test_cases"]: - assert len(case["pnonce_indices"]) == pnonce_indices_len - - # Add structures for valid and error cases - s += """ -struct musig_nonce_agg_test_case { - size_t pnonce_indices[2]; - /* if valid case */ - unsigned char expected[66]; - /* if error case */ - int invalid_nonce_idx; -}; -""" - # Add structure for entire vector - s += """ -struct musig_nonce_agg_vector { - unsigned char pnonces[%d][66]; - struct musig_nonce_agg_test_case valid_case[%d]; - struct musig_nonce_agg_test_case error_case[%d]; -}; -""" % ( - num_pnonces, - num_valid_cases, - num_error_cases, - ) - - s += create_init("nonce_agg") - s += init_arrays("pnonces") - - for cases in (data["valid_test_cases"], data["error_test_cases"]): - s += init_cases( - cases, - lambda case: "{ { %s }, { %s }, %d }," - % ( - ", ".join(map(str, case["pnonce_indices"])), - init_optional_expected(case), - case["error"]["signer"] if "error" in case else 0, - ), - ) - s += finish_init() - -# sign/verify vectors -with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f: - data = json.load(f) - - # The MuSig2 implementation only allows messages of length 32 - assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0] - data["msgs"] = [data["msgs"][0]] - - def filter_msg32(k): - return list(filter(lambda x: x["msg_index"] == 0, data[k])) - - data["valid_test_cases"] = filter_msg32("valid_test_cases") - data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases") - data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases") - data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases") - - num_pubkeys = len(data["pubkeys"]) - max_pubkeys = max(num_pubkeys, max_pubkeys) - num_secnonces = len(data["secnonces"]) - num_pubnonces = len(data["pnonces"]) - num_aggnonces = len(data["aggnonces"]) - num_msgs = len(data["msgs"]) - num_valid_cases = len(data["valid_test_cases"]) - num_sign_error_cases = len(data["sign_error_test_cases"]) - num_verify_fail_cases = len(data["verify_fail_test_cases"]) - num_verify_error_cases = len(data["verify_error_test_cases"]) - - all_cases = ( - data["valid_test_cases"] - + data["sign_error_test_cases"] - + data["verify_error_test_cases"] - + data["verify_fail_test_cases"] - ) - max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) - max_nonce_indices = max( - len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0 - for test_case in all_cases - ) - # Add structures for valid and error cases - s += ( - """ -/* Omit pubnonces in the test vectors because our partial signature verification - * implementation is able to accept the aggnonce directly. */ -struct musig_valid_case { - size_t key_indices_len; - size_t key_indices[%d]; - size_t aggnonce_index; - size_t msg_index; - size_t signer_index; - unsigned char expected[32]; -}; -""" - % max_key_indices - ) - - s += ( - """ -struct musig_sign_error_case { - size_t key_indices_len; - size_t key_indices[%d]; - size_t aggnonce_index; - size_t msg_index; - size_t secnonce_index; - enum MUSIG_ERROR error; -}; -""" - % max_key_indices - ) - - s += """ -struct musig_verify_fail_error_case { - unsigned char sig[32]; - size_t key_indices_len; - size_t key_indices[%d]; - size_t nonce_indices_len; - size_t nonce_indices[%d]; - size_t msg_index; - size_t signer_index; - enum MUSIG_ERROR error; -}; -""" % ( - max_key_indices, - max_nonce_indices, - ) - - # Add structure for entire vector - s += """ -struct musig_sign_verify_vector { - unsigned char sk[32]; - unsigned char pubkeys[%d][33]; - unsigned char secnonces[%d][194]; - unsigned char pubnonces[%d][194]; - unsigned char aggnonces[%d][66]; - unsigned char msgs[%d][32]; - struct musig_valid_case valid_case[%d]; - struct musig_sign_error_case sign_error_case[%d]; - struct musig_verify_fail_error_case verify_fail_case[%d]; - struct musig_verify_fail_error_case verify_error_case[%d]; -}; -""" % ( - num_pubkeys, - num_secnonces, - num_pubnonces, - num_aggnonces, - num_msgs, - num_valid_cases, - num_sign_error_cases, - num_verify_fail_cases, - num_verify_error_cases, - ) - - s += create_init("sign_verify") - s += init_array("sk") - s += init_arrays("pubkeys") - s += init_arrays("secnonces") - s += init_arrays("pnonces") - s += init_arrays("aggnonces") - s += init_arrays("msgs") - - s += init_cases( - data["valid_test_cases"], - lambda case: "{ %s, %d, %d, %d, { %s }}," - % ( - init_indices(case["key_indices"]), - case["aggnonce_index"], - case["msg_index"], - case["signer_index"], - init_optional_expected(case), - ), - ) - - def sign_error(case): - comment = case["comment"] - if "pubkey" in comment or "public key" in comment: - return "MUSIG_PUBKEY" - elif "Aggregate nonce" in comment: - return "MUSIG_AGGNONCE" - elif "Secnonce" in comment: - return "MUSIG_SECNONCE" - else: - sys.exit("Unknown sign error") - - s += init_cases( - data["sign_error_test_cases"], - lambda case: "{ %s, %d, %d, %d, %s }," - % ( - init_indices(case["key_indices"]), - case["aggnonce_index"], - case["msg_index"], - case["secnonce_index"], - sign_error(case), - ), - ) - - def verify_error(case): - comment = case["comment"] - if "exceeds" in comment: - return "MUSIG_SIG" - elif "Wrong signer" in comment or "Wrong signature" in comment: - return "MUSIG_SIG_VERIFY" - elif "pubnonce" in comment: - return "MUSIG_PUBNONCE" - elif "pubkey" in comment: - return "MUSIG_PUBKEY" - else: - sys.exit("Unknown verify error") - - for cases in ("verify_fail_test_cases", "verify_error_test_cases"): - s += init_cases( - data[cases], - lambda case: "{ { %s }, %s, %s, %d, %d, %s }," - % ( - hexstr_to_intarray(case["sig"]), - init_indices(case["key_indices"]), - init_indices(case["nonce_indices"]), - case["msg_index"], - case["signer_index"], - verify_error(case), - ), - ) - - s += finish_init() - -# tweak vectors -with open(sys.argv[1] + "/tweak_vectors.json", "r") as f: - data = json.load(f) - - num_pubkeys = len(data["pubkeys"]) - max_pubkeys = max(num_pubkeys, max_pubkeys) - num_pubnonces = len(data["pnonces"]) - num_tweaks = len(data["tweaks"]) - num_valid_cases = len(data["valid_test_cases"]) - num_error_cases = len(data["error_test_cases"]) - - all_cases = data["valid_test_cases"] + data["error_test_cases"] - max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) - max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) - max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases) - # Add structures for valid and error cases - s += """ -struct musig_tweak_case { - size_t key_indices_len; - size_t key_indices[%d]; - size_t nonce_indices_len; - size_t nonce_indices[%d]; - size_t tweak_indices_len; - size_t tweak_indices[%d]; - int is_xonly[%d]; - size_t signer_index; - unsigned char expected[32]; -}; -""" % ( - max_key_indices, - max_nonce_indices, - max_tweak_indices, - max_tweak_indices, - ) - - # Add structure for entire vector - s += """ -struct musig_tweak_vector { - unsigned char sk[32]; - unsigned char secnonce[97]; - unsigned char aggnonce[66]; - unsigned char msg[32]; - unsigned char pubkeys[%d][33]; - unsigned char pubnonces[%d][194]; - unsigned char tweaks[%d][32]; - struct musig_tweak_case valid_case[%d]; - struct musig_tweak_case error_case[%d]; -}; -""" % ( - num_pubkeys, - num_pubnonces, - num_tweaks, - num_valid_cases, - num_error_cases, - ) - s += create_init("tweak") - s += init_array("sk") - s += init_array("secnonce") - s += init_array("aggnonce") - s += init_array("msg") - s += init_arrays("pubkeys") - s += init_arrays("pnonces") - s += init_arrays("tweaks") - - s += init_cases( - data["valid_test_cases"], - lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," - % ( - init_indices(case["key_indices"]), - init_indices(case["nonce_indices"]), - init_indices(case["tweak_indices"]), - init_is_xonly(case), - case["signer_index"], - init_optional_expected(case), - ), - ) - - s += init_cases( - data["error_test_cases"], - lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," - % ( - init_indices(case["key_indices"]), - init_indices(case["nonce_indices"]), - init_indices(case["tweak_indices"]), - init_is_xonly(case), - case["signer_index"], - init_optional_expected(case), - ), - ) - - s += finish_init() - -# sigagg vectors -with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f: - data = json.load(f) - - num_pubkeys = len(data["pubkeys"]) - max_pubkeys = max(num_pubkeys, max_pubkeys) - num_tweaks = len(data["tweaks"]) - num_psigs = len(data["psigs"]) - num_valid_cases = len(data["valid_test_cases"]) - num_error_cases = len(data["error_test_cases"]) - - all_cases = data["valid_test_cases"] + data["error_test_cases"] - max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) - max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) - max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases) - - # Add structures for valid and error cases - s += """ -/* Omit pubnonces in the test vectors because they're only needed for - * implementations that do not directly accept an aggnonce. */ -struct musig_sig_agg_case { - size_t key_indices_len; - size_t key_indices[%d]; - size_t tweak_indices_len; - size_t tweak_indices[%d]; - int is_xonly[%d]; - unsigned char aggnonce[66]; - size_t psig_indices_len; - size_t psig_indices[%d]; - /* if valid case */ - unsigned char expected[64]; - /* if error case */ - int invalid_sig_idx; -}; -""" % ( - max_key_indices, - max_tweak_indices, - max_tweak_indices, - max_psig_indices, - ) - - # Add structure for entire vector - s += """ -struct musig_sig_agg_vector { - unsigned char pubkeys[%d][33]; - unsigned char tweaks[%d][32]; - unsigned char psigs[%d][32]; - unsigned char msg[32]; - struct musig_sig_agg_case valid_case[%d]; - struct musig_sig_agg_case error_case[%d]; -}; -""" % ( - num_pubkeys, - num_tweaks, - num_psigs, - num_valid_cases, - num_error_cases, - ) - - s += create_init("sig_agg") - s += init_arrays("pubkeys") - s += init_arrays("tweaks") - s += init_arrays("psigs") - s += init_array("msg") - - for cases in (data["valid_test_cases"], data["error_test_cases"]): - s += init_cases( - cases, - lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d }," - % ( - init_indices(case["key_indices"]), - init_indices(case["tweak_indices"]), - init_is_xonly(case), - hexstr_to_intarray(case["aggnonce"]), - init_indices(case["psig_indices"]), - init_optional_expected(case), - case["error"]["signer"] if "error" in case else 0, - ), - ) - s += finish_init() -s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys -print(s) diff --git a/external/secp256k1/tools/tests_wycheproof_generate.py b/external/secp256k1/tools/tests_wycheproof_generate.py deleted file mode 100755 index b26dfa89d6..0000000000 --- a/external/secp256k1/tools/tests_wycheproof_generate.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen -# Distributed under the MIT software license, see the accompanying -# file COPYING or https://www.opensource.org/licenses/mit-license.php. -''' -Generate a C file with ECDSA testvectors from the Wycheproof project. -''' - -import json -import sys - -filename_input = sys.argv[1] - -with open(filename_input) as f: - doc = json.load(f) - -num_groups = len(doc['testGroups']) - -def to_c_array(x): - if x == "": - return "" - s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2])) - return "0x" + s - - -num_vectors = 0 -offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0 -out = "" -messages = "" -signatures = "" -public_keys = "" -cache_msgs = {} -cache_public_keys = {} - -for i in range(num_groups): - group = doc['testGroups'][i] - num_tests = len(group['tests']) - public_key = group['publicKey'] - for j in range(num_tests): - test_vector = group['tests'][j] - # // 2 to convert hex to byte length - sig_size = len(test_vector['sig']) // 2 - msg_size = len(test_vector['msg']) // 2 - - if test_vector['result'] == "invalid": - expected_verify = 0 - elif test_vector['result'] == "valid": - expected_verify = 1 - else: - raise ValueError("invalid result field") - - if num_vectors != 0 and sig_size != 0: - signatures += ",\n " - - new_msg = False - msg = to_c_array(test_vector['msg']) - msg_offset = offset_msg_running - # check for repeated msg - if msg not in cache_msgs: - if num_vectors != 0 and msg_size != 0: - messages += ",\n " - cache_msgs[msg] = offset_msg_running - messages += msg - new_msg = True - else: - msg_offset = cache_msgs[msg] - - new_pk = False - pk = to_c_array(public_key['uncompressed']) - pk_offset = offset_pk_running - # check for repeated pk - if pk not in cache_public_keys: - if num_vectors != 0: - public_keys += ",\n " - cache_public_keys[pk] = offset_pk_running - public_keys += pk - new_pk = True - else: - pk_offset = cache_public_keys[pk] - - signatures += to_c_array(test_vector['sig']) - - out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n" - out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n" - if new_msg: - offset_msg_running += msg_size - if new_pk: - offset_pk_running += 65 - offset_sig += sig_size - num_vectors += 1 - -struct_definition = """ -typedef struct { - size_t pk_offset; - size_t msg_offset; - size_t msg_len; - size_t sig_offset; - size_t sig_len; - int expected_verify; -} wycheproof_ecdsa_testvector; -""" - - -print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */") -print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})") - -print(struct_definition) - -print("static const unsigned char wycheproof_ecdsa_messages[] = { " + messages + "};\n") -print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n") -print("static const unsigned char wycheproof_ecdsa_signatures[] = { " + signatures + "};\n") - -print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {") -print(out) -print("};") diff --git a/include/xrpl/basics/Archive.h b/include/xrpl/basics/Archive.h index 7ae6950f46..58e12bbb71 100644 --- a/include/xrpl/basics/Archive.h +++ b/include/xrpl/basics/Archive.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_ARCHIVE_H_INCLUDED -#define RIPPLE_BASICS_ARCHIVE_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Extract a tar archive compressed with lz4 @@ -32,10 +12,6 @@ namespace ripple { @throws runtime_error */ void -extractTarLz4( - boost::filesystem::path const& src, - boost::filesystem::path const& dst); +extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/BasicConfig.h b/include/xrpl/basics/BasicConfig.h index dcd96e7738..d18019fa9f 100644 --- a/include/xrpl/basics/BasicConfig.h +++ b/include/xrpl/basics/BasicConfig.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_BASICCONFIG_H_INCLUDED -#define RIPPLE_BASICS_BASICCONFIG_H_INCLUDED +#pragma once #include @@ -31,10 +11,9 @@ #include #include -namespace ripple { +namespace xrpl { -using IniFileSections = - std::unordered_map>; +using IniFileSections = std::unordered_map>; //------------------------------------------------------------------------------ @@ -105,8 +84,7 @@ public: if (lines_.empty()) return ""; if (lines_.size() > 1) - Throw( - "A legacy value must have exactly one line. Section: " + name_); + Throw("A legacy value must have exactly one line. Section: " + name_); return lines_[0]; } @@ -252,10 +230,7 @@ public: The previous value, if any, is overwritten. */ void - overwrite( - std::string const& section, - std::string const& key, - std::string const& value); + overwrite(std::string const& section, std::string const& key, std::string const& value); /** Remove all the key/value pairs from the section. */ @@ -293,9 +268,7 @@ public: bool had_trailing_comments() const { - return std::any_of(map_.cbegin(), map_.cend(), [](auto s) { - return s.second.had_trailing_comments(); - }); + return std::any_of(map_.cbegin(), map_.cend(), [](auto s) { return s.second.had_trailing_comments(); }); } protected: @@ -334,10 +307,7 @@ set(T& target, std::string const& name, Section const& section) */ template bool -set(T& target, - T const& defaultValue, - std::string const& name, - Section const& section) +set(T& target, T const& defaultValue, std::string const& name, Section const& section) { bool found_and_valid = set(target, name, section); if (!found_and_valid) @@ -352,9 +322,7 @@ set(T& target, // NOTE This routine might be more clumsy than the previous two template T -get(Section const& section, - std::string const& name, - T const& defaultValue = T{}) +get(Section const& section, std::string const& name, T const& defaultValue = T{}) { try { @@ -399,6 +367,4 @@ get_if_exists(Section const& section, std::string const& name, bool& v) return stat; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Blob.h b/include/xrpl/basics/Blob.h index 9949cbd040..ee0d6cf3b5 100644 --- a/include/xrpl/basics/Blob.h +++ b/include/xrpl/basics/Blob.h @@ -1,34 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_BLOB_H_INCLUDED -#define RIPPLE_BASICS_BLOB_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Storage for linear binary data. Blocks of binary data appear often in various idioms and structures. */ using Blob = std::vector; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index 3379a923f0..5192daf632 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_BUFFER_H_INCLUDED -#define RIPPLE_BASICS_BUFFER_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Like std::vector but better. Meets the requirements of BufferFactory. @@ -44,8 +24,7 @@ public: Buffer() = default; /** Create an uninitialized buffer with the given size. */ - explicit Buffer(std::size_t size) - : p_(size ? new std::uint8_t[size] : nullptr), size_(size) + explicit Buffer(std::size_t size) : p_(size ? new std::uint8_t[size] : nullptr), size_(size) { } @@ -81,8 +60,7 @@ public: /** Move-construct. The other buffer is reset. */ - Buffer(Buffer&& other) noexcept - : p_(std::move(other.p_)), size_(other.size_) + Buffer(Buffer&& other) noexcept : p_(std::move(other.p_)), size_(other.size_) { other.size_ = 0; } @@ -113,9 +91,8 @@ public: { // Ensure the slice isn't a subset of the buffer. XRPL_ASSERT( - s.size() == 0 || size_ == 0 || s.data() < p_.get() || - s.data() >= p_.get() + size_, - "ripple::Buffer::operator=(Slice) : input not a subset"); + s.size() == 0 || size_ == 0 || s.data() < p_.get() || s.data() >= p_.get() + size_, + "xrpl::Buffer::operator=(Slice) : input not a subset"); if (auto p = alloc(s.size())) std::memcpy(p, s.data(), s.size()); @@ -234,6 +211,4 @@ operator!=(Buffer const& lhs, Buffer const& rhs) noexcept return !(lhs == rhs); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/ByteUtilities.h b/include/xrpl/basics/ByteUtilities.h index 8013398eba..cd10611a50 100644 --- a/include/xrpl/basics/ByteUtilities.h +++ b/include/xrpl/basics/ByteUtilities.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_BYTEUTILITIES_H_INCLUDED -#define RIPPLE_BASICS_BYTEUTILITIES_H_INCLUDED - -namespace ripple { +namespace xrpl { template constexpr auto @@ -38,6 +18,4 @@ megabytes(T value) noexcept static_assert(kilobytes(2) == 2048, "kilobytes(2) == 2048"); static_assert(megabytes(3) == 3145728, "megabytes(3) == 3145728"); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/CompressionAlgorithms.h b/include/xrpl/basics/CompressionAlgorithms.h index 4d6cf21cd8..b8fe4c8018 100644 --- a/include/xrpl/basics/CompressionAlgorithms.h +++ b/include/xrpl/basics/CompressionAlgorithms.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED -#define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace compression_algorithms { @@ -55,10 +35,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf) auto compressed = bf(outCapacity); auto compressedSize = LZ4_compress_default( - reinterpret_cast(in), - reinterpret_cast(compressed), - inSize, - outCapacity); + reinterpret_cast(in), reinterpret_cast(compressed), inSize, outCapacity); if (compressedSize == 0) Throw("lz4 compress: failed"); @@ -89,10 +66,8 @@ lz4Decompress( Throw("lz4Decompress: integer overflow (output)"); if (LZ4_decompress_safe( - reinterpret_cast(in), - reinterpret_cast(decompressed), - inSize, - decompressedSize) != decompressedSize) + reinterpret_cast(in), reinterpret_cast(decompressed), inSize, decompressedSize) != + decompressedSize) Throw("lz4Decompress: failed"); return decompressedSize; @@ -108,11 +83,7 @@ lz4Decompress( */ template std::size_t -lz4Decompress( - InputStream& in, - std::size_t inSize, - std::uint8_t* decompressed, - std::size_t decompressedSize) +lz4Decompress(InputStream& in, std::size_t inSize, std::uint8_t* decompressed, std::size_t decompressedSize) { std::vector compressed; std::uint8_t const* chunk = nullptr; @@ -135,9 +106,7 @@ lz4Decompress( compressed.resize(inSize); } - chunkSize = chunkSize < (inSize - copiedInSize) - ? chunkSize - : (inSize - copiedInSize); + chunkSize = chunkSize < (inSize - copiedInSize) ? chunkSize : (inSize - copiedInSize); std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize); @@ -154,8 +123,7 @@ lz4Decompress( if (in.ByteCount() > (currentBytes + copiedInSize)) in.BackUp(in.ByteCount() - currentBytes - copiedInSize); - if ((copiedInSize == 0 && chunkSize < inSize) || - (copiedInSize > 0 && copiedInSize != inSize)) + if ((copiedInSize == 0 && chunkSize < inSize) || (copiedInSize > 0 && copiedInSize != inSize)) Throw("lz4 decompress: insufficient input size"); return lz4Decompress(chunk, inSize, decompressed, decompressedSize); @@ -163,6 +131,4 @@ lz4Decompress( } // namespace compression_algorithms -} // namespace ripple - -#endif // RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/basics/CountedObject.h b/include/xrpl/basics/CountedObject.h index ef4b6544d2..55a895dbb1 100644 --- a/include/xrpl/basics/CountedObject.h +++ b/include/xrpl/basics/CountedObject.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED -#define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Manages all counted object types. */ class CountedObjects @@ -152,6 +132,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/DecayingSample.h b/include/xrpl/basics/DecayingSample.h index 20a02572db..e4c9ad5d7a 100644 --- a/include/xrpl/basics/DecayingSample.h +++ b/include/xrpl/basics/DecayingSample.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_DECAYINGSAMPLE_H_INCLUDED -#define RIPPLE_BASICS_DECAYINGSAMPLE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Sampling function using exponential decay to provide a continuous value. @tparam The number of seconds in the decay window. @@ -75,9 +55,7 @@ private: if (m_value != value_type()) { - std::size_t elapsed = - std::chrono::duration_cast(now - m_when) - .count(); + std::size_t elapsed = std::chrono::duration_cast(now - m_when).count(); // A span larger than four times the window decays the // value to an insignificant amount so just reset it. @@ -150,6 +128,4 @@ private: time_point when_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h index 9afb160d9d..7c98e72107 100644 --- a/include/xrpl/basics/Expected.h +++ b/include/xrpl/basics/Expected.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_EXPECTED_H_INCLUDED -#define RIPPLE_BASICS_EXPECTED_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { /** Expected is an approximation of std::expected (hoped for in C++23) @@ -127,23 +107,20 @@ Unexpected(E (&)[N]) -> Unexpected; // Definition of Expected. All of the machinery comes from boost::result. template -class [[nodiscard]] Expected - : private boost::outcome_v2::result +class [[nodiscard]] Expected : private boost::outcome_v2::result { using Base = boost::outcome_v2::result; public: template requires std::convertible_to - constexpr Expected(U&& r) - : Base(boost::outcome_v2::in_place_type_t{}, std::forward(r)) + constexpr Expected(U&& r) : Base(boost::outcome_v2::in_place_type_t{}, std::forward(r)) { } template requires std::convertible_to && (!std::is_reference_v) - constexpr Expected(Unexpected e) - : Base(boost::outcome_v2::in_place_type_t{}, std::move(e.value())) + constexpr Expected(Unexpected e) : Base(boost::outcome_v2::in_place_type_t{}, std::move(e.value())) { } @@ -214,8 +191,7 @@ public: // Specialization of Expected. Allows returning either success // (without a value) or the reason for the failure. template -class [[nodiscard]] Expected - : private boost::outcome_v2::result +class [[nodiscard]] Expected : private boost::outcome_v2::result { using Base = boost::outcome_v2::result; @@ -251,6 +227,4 @@ public: } }; -} // namespace ripple - -#endif // RIPPLE_BASICS_EXPECTED_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/basics/FileUtilities.h b/include/xrpl/basics/FileUtilities.h index 49138c83c9..299269703a 100644 --- a/include/xrpl/basics/FileUtilities.h +++ b/include/xrpl/basics/FileUtilities.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED -#define RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { std::string getFileContents( @@ -34,11 +14,6 @@ getFileContents( std::optional maxSize = std::nullopt); void -writeFileContents( - boost::system::error_code& ec, - boost::filesystem::path const& destPath, - std::string const& contents); +writeFileContents(boost::system::error_code& ec, boost::filesystem::path const& destPath, std::string const& contents); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/IntrusivePointer.h b/include/xrpl/basics/IntrusivePointer.h index b28ea4e6b8..4464c37dc5 100644 --- a/include/xrpl/basics/IntrusivePointer.h +++ b/include/xrpl/basics/IntrusivePointer.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED -#define RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { //------------------------------------------------------------------------------ @@ -64,8 +44,8 @@ struct SharedIntrusiveAdoptNoIncrementTag // template -concept CAdoptTag = std::is_same_v || - std::is_same_v; +concept CAdoptTag = + std::is_same_v || std::is_same_v; //------------------------------------------------------------------------------ @@ -77,7 +57,7 @@ concept CAdoptTag = std::is_same_v || When the strong pointer count goes to zero, the "partialDestructor" is called. This can be used to destroy as much of the object as possible while still retaining the reference counts. For example, for SHAMapInnerNodes the - children may be reset in that function. Note that std::shared_poiner WILL + children may be reset in that function. Note that std::shared_pointer WILL run the destructor when the strong count reaches zero, but may not free the memory used by the object until the weak count reaches zero. In rippled, we typically allocate shared pointers with the `make_shared` function. When @@ -141,9 +121,7 @@ public: controlled by the rhs param. */ template - SharedIntrusive( - StaticCastTagSharedIntrusive, - SharedIntrusive const& rhs); + SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive const& rhs); /** Create a new SharedIntrusive by statically casting the pointer controlled by the rhs param. @@ -155,9 +133,7 @@ public: controlled by the rhs param. */ template - SharedIntrusive( - DynamicCastTagSharedIntrusive, - SharedIntrusive const& rhs); + SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive const& rhs); /** Create a new SharedIntrusive by dynamically casting the pointer controlled by the rhs param. @@ -323,9 +299,7 @@ class SharedWeakUnion // Tagged pointer. Low bit determines if this is a strong or a weak // pointer. The low bit must be masked to zero when converting back to a // pointer. If the low bit is '1', this is a weak pointer. - static_assert( - alignof(T) >= 2, - "Bad alignment: Combo pointer requires low bit to be zero"); + static_assert(alignof(T) >= 2, "Bad alignment: Combo pointer requires low bit to be zero"); public: SharedWeakUnion() = default; @@ -469,9 +443,7 @@ make_SharedIntrusive(Args&&... args) auto p = new TT(std::forward(args)...); static_assert( - noexcept(SharedIntrusive( - std::declval(), - std::declval())), + noexcept(SharedIntrusive(std::declval(), std::declval())), "SharedIntrusive constructor should not throw or this can leak " "memory"); @@ -511,5 +483,4 @@ dynamic_pointer_cast(TT const& v) return SharedPtr(DynamicCastTagSharedIntrusive{}, v); } } // namespace intr_ptr -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/IntrusivePointer.ipp b/include/xrpl/basics/IntrusivePointer.ipp index 4d037bc329..d52aa6299f 100644 --- a/include/xrpl/basics/IntrusivePointer.ipp +++ b/include/xrpl/basics/IntrusivePointer.ipp @@ -1,39 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED -#define RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { template template SharedIntrusive::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p} { - if constexpr (std::is_same_v< - TAdoptTag, - SharedIntrusiveAdoptIncrementStrongTag>) + if constexpr (std::is_same_v) { if (p) p->addStrongRef(); @@ -65,16 +43,14 @@ SharedIntrusive::SharedIntrusive(SharedIntrusive const& rhs) } template -SharedIntrusive::SharedIntrusive(SharedIntrusive&& rhs) - : ptr_{rhs.unsafeExchange(nullptr)} +SharedIntrusive::SharedIntrusive(SharedIntrusive&& rhs) : ptr_{rhs.unsafeExchange(nullptr)} { } template template requires std::convertible_to -SharedIntrusive::SharedIntrusive(SharedIntrusive&& rhs) - : ptr_{rhs.unsafeExchange(nullptr)} +SharedIntrusive::SharedIntrusive(SharedIntrusive&& rhs) : ptr_{rhs.unsafeExchange(nullptr)} { } template @@ -131,9 +107,7 @@ requires std::convertible_to SharedIntrusive& SharedIntrusive::operator=(SharedIntrusive&& rhs) { - static_assert( - !std::is_same_v, - "This overload should not be instantiated for T == TT"); + static_assert(!std::is_same_v, "This overload should not be instantiated for T == TT"); unsafeReleaseAndStore(rhs.unsafeExchange(nullptr)); return *this; @@ -158,9 +132,7 @@ template void SharedIntrusive::adopt(T* p) { - if constexpr (std::is_same_v< - TAdoptTag, - SharedIntrusiveAdoptIncrementStrongTag>) + if constexpr (std::is_same_v) { if (p) p->addStrongRef(); @@ -176,9 +148,7 @@ SharedIntrusive::~SharedIntrusive() template template -SharedIntrusive::SharedIntrusive( - StaticCastTagSharedIntrusive, - SharedIntrusive const& rhs) +SharedIntrusive::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive const& rhs) : ptr_{[&] { auto p = static_cast(rhs.unsafeGetRawPtr()); if (p) @@ -190,18 +160,14 @@ SharedIntrusive::SharedIntrusive( template template -SharedIntrusive::SharedIntrusive( - StaticCastTagSharedIntrusive, - SharedIntrusive&& rhs) +SharedIntrusive::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive&& rhs) : ptr_{static_cast(rhs.unsafeExchange(nullptr))} { } template template -SharedIntrusive::SharedIntrusive( - DynamicCastTagSharedIntrusive, - SharedIntrusive const& rhs) +SharedIntrusive::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive const& rhs) : ptr_{[&] { auto p = dynamic_cast(rhs.unsafeGetRawPtr()); if (p) @@ -213,9 +179,7 @@ SharedIntrusive::SharedIntrusive( template template -SharedIntrusive::SharedIntrusive( - DynamicCastTagSharedIntrusive, - SharedIntrusive&& rhs) +SharedIntrusive::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive&& rhs) { // This can be simplified without the `exchange`, but the `exchange` is kept // in anticipation of supporting atomic operations. @@ -334,8 +298,7 @@ WeakIntrusive::WeakIntrusive(WeakIntrusive&& rhs) : ptr_{rhs.ptr_} } template -WeakIntrusive::WeakIntrusive(SharedIntrusive const& rhs) - : ptr_{rhs.unsafeGetRawPtr()} +WeakIntrusive::WeakIntrusive(SharedIntrusive const& rhs) : ptr_{rhs.unsafeGetRawPtr()} { if (ptr_) ptr_->addWeakRef(); @@ -627,7 +590,7 @@ SharedWeakUnion::convertToStrong() [[maybe_unused]] auto action = p->releaseWeakRef(); XRPL_ASSERT( (action == ReleaseWeakRefAction::noop), - "ripple::SharedWeakUnion::convertToStrong : " + "xrpl::SharedWeakUnion::convertToStrong : " "action is noop"); unsafeSetRawPtr(p, RefStrength::strong); return true; @@ -656,7 +619,7 @@ SharedWeakUnion::convertToWeak() // We just added a weak ref. How could we destroy? // LCOV_EXCL_START UNREACHABLE( - "ripple::SharedWeakUnion::convertToWeak : destroying freshly " + "xrpl::SharedWeakUnion::convertToWeak : destroying freshly " "added ref"); delete p; unsafeSetRawPtr(nullptr); @@ -738,5 +701,4 @@ SharedWeakUnion::unsafeReleaseNoStore() } } -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/IntrusiveRefCounts.h b/include/xrpl/basics/IntrusiveRefCounts.h index 750b945803..0273ed4647 100644 --- a/include/xrpl/basics/IntrusiveRefCounts.h +++ b/include/xrpl/basics/IntrusiveRefCounts.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED -#define RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Action to perform when releasing a strong pointer. @@ -53,7 +33,7 @@ enum class ReleaseWeakRefAction { noop, destroy }; /** Implement the strong count, weak count, and bit flags for an intrusive pointer. - A class can satisfy the requirements of a ripple::IntrusivePointer by + A class can satisfy the requirements of a xrpl::IntrusivePointer by inheriting from this class. */ struct IntrusiveRefCounts @@ -179,22 +159,19 @@ private: See description of the `refCounts` field for a fuller description of this field. */ - static constexpr FieldType partialDestroyStartedMask = - (one << (FieldTypeBits - 1)); + static constexpr FieldType partialDestroyStartedMask = (one << (FieldTypeBits - 1)); /** Flag that is set when the partialDestroy function has finished running See description of the `refCounts` field for a fuller description of this field. */ - static constexpr FieldType partialDestroyFinishedMask = - (one << (FieldTypeBits - 2)); + static constexpr FieldType partialDestroyFinishedMask = (one << (FieldTypeBits - 2)); /** Mask that will zero out all the `count` bits and leave the tag bits unchanged. */ - static constexpr FieldType tagMask = - partialDestroyStartedMask | partialDestroyFinishedMask; + static constexpr FieldType tagMask = partialDestroyStartedMask | partialDestroyFinishedMask; /** Mask that will zero out the `tag` bits and leave the count bits unchanged. @@ -203,13 +180,11 @@ private: /** Mask that will zero out everything except the strong count. */ - static constexpr FieldType strongMask = - ((one << StrongCountNumBits) - 1) & valueMask; + static constexpr FieldType strongMask = ((one << StrongCountNumBits) - 1) & valueMask; /** Mask that will zero out everything except the weak count. */ - static constexpr FieldType weakMask = - (((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask; + static constexpr FieldType weakMask = (((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask; /** Unpack the count and tag fields from the packed atomic integer form. */ struct RefCountPair @@ -234,10 +209,8 @@ private: FieldType combinedValue() const noexcept; - static constexpr CountType maxStrongValue = - static_cast((one << StrongCountNumBits) - 1); - static constexpr CountType maxWeakValue = - static_cast((one << WeakCountNumBits) - 1); + static constexpr CountType maxStrongValue = static_cast((one << StrongCountNumBits) - 1); + static constexpr CountType maxWeakValue = static_cast((one << WeakCountNumBits) - 1); /** Put an extra margin to detect when running up against limits. This is only used in debug code, and is useful if we reduce the number of bits in the strong and weak counts (to 16 and 14 bits). @@ -276,7 +249,7 @@ IntrusiveRefCounts::releaseStrongRef() const RefCountPair const prevVal{prevIntVal}; XRPL_ASSERT( (prevVal.strong >= strongDelta), - "ripple::IntrusiveRefCounts::releaseStrongRef : previous ref " + "xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref " "higher than new"); auto nextIntVal = prevIntVal - strongDelta; ReleaseStrongRefAction action = noop; @@ -293,15 +266,14 @@ IntrusiveRefCounts::releaseStrongRef() const } } - if (refCounts.compare_exchange_weak( - prevIntVal, nextIntVal, std::memory_order_acq_rel)) + if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel)) { // Can't be in partial destroy because only decrementing the strong // count to zero can start a partial destroy, and that can't happen // twice. XRPL_ASSERT( (action == noop) || !(prevIntVal & partialDestroyStartedMask), - "ripple::IntrusiveRefCounts::releaseStrongRef : not in partial " + "xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial " "destroy"); return action; } @@ -320,7 +292,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const // change the counts and flags (the count could be atomically changed, but // the flags depend on the current value of the counts). // - // Note: If this becomes a perf bottleneck, the `partialDestoryStartedMask` + // Note: If this becomes a perf bottleneck, the `partialDestroyStartedMask` // may be able to be set non-atomically. But it is easier to reason about // the code if the flag is set atomically. while (1) @@ -333,7 +305,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const // can't happen twice. XRPL_ASSERT( (!prevVal.partialDestroyStartedBit), - "ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not in " + "xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in " "partial destroy"); auto nextIntVal = prevIntVal + delta; @@ -350,12 +322,11 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const action = partialDestroy; } } - if (refCounts.compare_exchange_weak( - prevIntVal, nextIntVal, std::memory_order_acq_rel)) + if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel)) { XRPL_ASSERT( (!(prevIntVal & partialDestroyStartedMask)), - "ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not " + "xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not " "started partial destroy"); return action; } @@ -395,8 +366,7 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept auto curValue = RefCountPair{1, 1}.combinedValue(); auto desiredValue = RefCountPair{2, 1}.combinedValue(); - while (!refCounts.compare_exchange_weak( - curValue, desiredValue, std::memory_order_acq_rel)) + while (!refCounts.compare_exchange_weak(curValue, desiredValue, std::memory_order_acq_rel)) { RefCountPair const prev{curValue}; if (!prev.strong) @@ -425,20 +395,15 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept { #ifndef NDEBUG auto v = refCounts.load(std::memory_order_acquire); - XRPL_ASSERT( - (!(v & valueMask)), - "ripple::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero"); + XRPL_ASSERT((!(v & valueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero"); auto t = v & tagMask; - XRPL_ASSERT( - (!t || t == tagMask), - "ripple::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag"); + XRPL_ASSERT((!t || t == tagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag"); #endif } //------------------------------------------------------------------------------ -inline IntrusiveRefCounts::RefCountPair::RefCountPair( - IntrusiveRefCounts::FieldType v) noexcept +inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept : strong{static_cast(v & strongMask)} , weak{static_cast((v & weakMask) >> StrongCountNumBits)} , partialDestroyStartedBit{v & partialDestroyStartedMask} @@ -446,7 +411,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair( { XRPL_ASSERT( (strong < checkStrongMaxValue && weak < checkWeakMaxValue), - "ripple::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside " + "xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside " "range"); } @@ -457,7 +422,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair( { XRPL_ASSERT( (strong < checkStrongMaxValue && weak < checkWeakMaxValue), - "ripple::IntrusiveRefCounts::RefCountPair(CountType, CountType) : " + "xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : " "inputs inside range"); } @@ -466,12 +431,10 @@ IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept { XRPL_ASSERT( (strong < checkStrongMaxValue && weak < checkWeakMaxValue), - "ripple::IntrusiveRefCounts::RefCountPair::combinedValue : inputs " + "xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs " "inside range"); - return (static_cast(weak) - << IntrusiveRefCounts::StrongCountNumBits) | - static_cast(strong) | - partialDestroyStartedBit | partialDestroyFinishedBit; + return (static_cast(weak) << IntrusiveRefCounts::StrongCountNumBits) | + static_cast(strong) | partialDestroyStartedBit | partialDestroyFinishedBit; } template @@ -479,12 +442,10 @@ inline void partialDestructorFinished(T** o) { T& self = **o; - IntrusiveRefCounts::RefCountPair p = - self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask); + IntrusiveRefCounts::RefCountPair p = self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask); XRPL_ASSERT( - (!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && - !p.strong), - "ripple::partialDestructorFinished : not a weak ref"); + (!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong), + "xrpl::partialDestructorFinished : not a weak ref"); if (!p.weak) { // There was a weak count before the partial destructor ran (or we would @@ -498,5 +459,4 @@ partialDestructorFinished(T** o) } //------------------------------------------------------------------------------ -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/KeyCache.h b/include/xrpl/basics/KeyCache.h index 1439a8b334..4f2ca20cca 100644 --- a/include/xrpl/basics/KeyCache.h +++ b/include/xrpl/basics/KeyCache.h @@ -1,32 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_KEYCACHE_H -#define RIPPLE_BASICS_KEYCACHE_H +#pragma once #include #include -namespace ripple { +namespace xrpl { using KeyCache = TaggedCache; -} // namespace ripple - -#endif // RIPPLE_BASICS_KEYCACHE_H +} // namespace xrpl diff --git a/include/xrpl/basics/LocalValue.h b/include/xrpl/basics/LocalValue.h index 1f53fab246..94af41a41d 100644 --- a/include/xrpl/basics/LocalValue.h +++ b/include/xrpl/basics/LocalValue.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_LOCALVALUE_H_INCLUDED -#define RIPPLE_BASICS_LOCALVALUE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -74,8 +54,7 @@ template boost::thread_specific_ptr& getLocalValues() { - static boost::thread_specific_ptr tsp( - &detail::LocalValues::cleanup); + static boost::thread_specific_ptr tsp(&detail::LocalValues::cleanup); return tsp; } @@ -124,10 +103,6 @@ LocalValue::operator*() } return *reinterpret_cast( - lvs->values - .emplace(this, std::make_unique>(t_)) - .first->second->get()); + lvs->values.emplace(this, std::make_unique>(t_)).first->second->get()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h index 833907eb9c..786fbc5da2 100644 --- a/include/xrpl/basics/Log.h +++ b/include/xrpl/basics/Log.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_LOG_H_INCLUDED -#define RIPPLE_BASICS_LOG_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { // DEPRECATED use beast::severities::Severity instead enum LogSeverity { @@ -58,22 +38,17 @@ private: std::string partition_; public: - Sink( - std::string const& partition, - beast::severities::Severity thresh, - Logs& logs); + Sink(std::string const& partition, beast::severities::Severity thresh, Logs& logs); Sink(Sink const&) = delete; Sink& operator=(Sink const&) = delete; void - write(beast::severities::Severity level, std::string const& text) - override; + write(beast::severities::Severity level, std::string const& text) override; void - writeAlways(beast::severities::Severity level, std::string const& text) - override; + writeAlways(beast::severities::Severity level, std::string const& text) override; }; /** Manages a system file containing logged output. @@ -159,11 +134,7 @@ private: }; std::mutex mutable mutex_; - std::map< - std::string, - std::unique_ptr, - boost::beast::iless> - sinks_; + std::map, boost::beast::iless> sinks_; beast::severities::Severity thresh_; File file_; bool silent_ = false; @@ -199,11 +170,7 @@ public: partition_severities() const; void - write( - beast::severities::Severity level, - std::string const& partition, - std::string const& text, - bool console); + write(beast::severities::Severity level, std::string const& partition, std::string const& text, bool console); std::string rotate(); @@ -220,9 +187,7 @@ public: } virtual std::unique_ptr - makeSink( - std::string const& partition, - beast::severities::Severity startingLevel); + makeSink(std::string const& partition, beast::severities::Severity startingLevel); public: static LogSeverity @@ -240,7 +205,8 @@ public: private: enum { // Maximum line length for log messages. - // If the message exceeds this length it will be truncated with elipses. + // If the message exceeds this length it will be truncated with + // ellipses. maximumMessageCharacters = 12 * 1024 }; @@ -290,6 +256,4 @@ setDebugLogSink(std::unique_ptr sink); beast::Journal debugLog(); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h index 516c07f377..4552b335e1 100644 --- a/include/xrpl/basics/MathUtilities.h +++ b/include/xrpl/basics/MathUtilities.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED -#define RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Calculate one number divided by another number in percentage. * The result is rounded up to the next integer, and capped in the range [0,100] @@ -63,6 +43,4 @@ static_assert(calculatePercent(50'000'000, 100'000'000) == 50); static_assert(calculatePercent(50'000'001, 100'000'000) == 51); static_assert(calculatePercent(99'999'999, 100'000'000) == 100); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 41c60d30a1..c269d27781 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -1,62 +1,252 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED -#define RIPPLE_BASICS_NUMBER_H_INCLUDED +#include #include +#include #include +#include #include #include -namespace ripple { +namespace xrpl { class Number; std::string to_string(Number const& amount); +template +constexpr std::optional +logTen(T value) +{ + int log = 0; + while (value >= 10 && value % 10 == 0) + { + value /= 10; + ++log; + } + if (value == 1) + return log; + return std::nullopt; +} + +template +constexpr bool +isPowerOfTen(T value) +{ + return logTen(value).has_value(); +} + +/** MantissaRange defines a range for the mantissa of a normalized Number. + * + * The mantissa is in the range [min, max], where + * * min is a power of 10, and + * * max = min * 10 - 1. + * + * The mantissa_scale enum indicates whether the range is "small" or "large". + * This intentionally restricts the number of MantissaRanges that can be + * instantiated to two: one for each scale. + * + * The "small" scale is based on the behavior of STAmount for IOUs. It has a min + * value of 10^15, and a max value of 10^16-1. This was sufficient for + * uses before Lending Protocol was implemented, mostly related to AMM. + * + * However, it does not have sufficient precision to represent the full integer + * range of int64_t values (-2^63 to 2^63-1), which are needed for XRP and MPT + * values. The implementation of SingleAssetVault, and LendingProtocol need to + * represent those integer values accurately and precisely, both for the + * STNumber field type, and for internal calculations. That necessitated the + * "large" scale. + * + * The "large" scale is intended to represent all values that can be represented + * by an STAmount - IOUs, XRP, and MPTs. It has a min value of 10^18, and a max + * value of 10^19-1. + * + * Note that if the mentioned amendments are eventually retired, this class + * should be left in place, but the "small" scale option should be removed. This + * will allow for future expansion beyond 64-bits if it is ever needed. + */ +struct MantissaRange +{ + using rep = std::uint64_t; + enum mantissa_scale { small, large }; + + explicit constexpr MantissaRange(mantissa_scale scale_) + : min(getMin(scale_)), max(min * 10 - 1), log(logTen(min).value_or(-1)), scale(scale_) + { + } + + rep min; + rep max; + int log; + mantissa_scale scale; + +private: + static constexpr rep + getMin(mantissa_scale scale_) + { + switch (scale_) + { + case small: + return 1'000'000'000'000'000ULL; + case large: + return 1'000'000'000'000'000'000ULL; + default: + // Since this can never be called outside a non-constexpr + // context, this throw assures that the build fails if an + // invalid scale is used. + throw std::runtime_error("Unknown mantissa scale"); + } + } +}; + +// Like std::integral, but only 64-bit integral types. +template +concept Integral64 = std::is_same_v || std::is_same_v; + +/** Number is a floating point type that can represent a wide range of values. + * + * It can represent all values that can be represented by an STAmount - + * regardless of asset type - XRPAmount, MPTAmount, and IOUAmount, with at least + * as much precision as those types require. + * + * ---- Internal Representation ---- + * + * Internally, Number is represented with three values: + * 1. a bool sign flag, + * 2. a std::uint64_t mantissa, + * 3. an int exponent. + * + * The internal mantissa is an unsigned integer in the range defined by the + * current MantissaRange. The exponent is an integer in the range + * [minExponent, maxExponent]. + * + * See the description of MantissaRange for more details on the ranges. + * + * A non-zero mantissa is (almost) always normalized, meaning it and the + * exponent are grown or shrunk until the mantissa is in the range + * [MantissaRange.min, MantissaRange.max]. + * + * Note: + * 1. Normalization can be disabled by using the "unchecked" ctor tag. This + * should only be used at specific conversion points, some constexpr + * values, and in unit tests. + * 2. The max of the "large" range, 10^19-1, is the largest 10^X-1 value that + * fits in an unsigned 64-bit number. (10^19-1 < 2^64-1 and + * 10^20-1 > 2^64-1). This avoids under- and overflows. + * + * ---- External Interface ---- + * + * The external interface of Number consists of a std::int64_t mantissa, which + * is restricted to 63-bits, and an int exponent, which must be in the range + * [minExponent, maxExponent]. The range of the mantissa depends on which + * MantissaRange is currently active. For the "short" range, the mantissa will + * be between 10^15 and 10^16-1. For the "large" range, the mantissa will be + * between -(2^63-1) and 2^63-1. As noted above, the "large" range is needed to + * represent the full range of valid XRP and MPT integer values accurately. + * + * Note: + * 1. 2^63-1 is between 10^18 and 10^19-1, which are the limits of the "large" + * mantissa range. + * 2. The functions mantissa() and exponent() return the external view of the + * Number value, specifically using a signed 63-bit mantissa. This may + * require altering the internal representation to fit into that range + * before the value is returned. The interface guarantees consistency of + * the two values. + * 3. Number cannot represent -2^63 (std::numeric_limits::min()) + * as an exact integer, but it doesn't need to, because all asset values + * on-ledger are non-negative. This is due to implementation details of + * several operations which use unsigned arithmetic internally. This is + * sufficient to represent all valid XRP values (where the absolute value + * can not exceed INITIAL_XRP: 10^17), and MPT values (where the absolute + * value can not exceed maxMPTokenAmount: 2^63-1). + * + * ---- Mantissa Range Switching ---- + * + * The mantissa range may be changed at runtime via setMantissaScale(). The + * default mantissa range is "large". The range is updated whenever transaction + * processing begins, based on whether SingleAssetVault or LendingProtocol are + * enabled. If either is enabled, the mantissa range is set to "large". If not, + * it is set to "small", preserving backward compatibility and correct + * "amendment-gating". + * + * It is extremely unlikely that any more calls to setMantissaScale() will be + * needed outside of unit tests. + * + * ---- Usage With Different Ranges ---- + * + * Outside of unit tests, and existing checks, code that uses Number should not + * know or care which mantissa range is active. + * + * The results of computations using Numbers with a small mantissa may differ + * from computations using Numbers with a large mantissa, specifically as it + * effects the results after rounding. That is why the large mantissa range is + * amendment gated in transaction processing. + * + * It is extremely unlikely that any more calls to getMantissaScale() will be + * needed outside of unit tests. + * + * Code that uses Number should not assume or check anything about the + * mantissa() or exponent() except that they fit into the "large" range + * specified in the "External Interface" section. + * + * ----- Unit Tests ----- + * + * Within unit tests, it may be useful to explicitly switch between the two + * ranges, or to check which range is active when checking the results of + * computations. If the test is doing the math directly, the + * set/getMantissaScale() functions may be most appropriate. However, if the + * test has anything to do with transaction processing, it should enable or + * disable the amendments that control the mantissa range choice + * (SingleAssetVault and LendingProtocol), and/or check if either of those + * amendments are enabled to determine which result to expect. + * + */ class Number { using rep = std::int64_t; - rep mantissa_{0}; + using internalrep = MantissaRange::rep; + + bool negative_{false}; + internalrep mantissa_{0}; int exponent_{std::numeric_limits::lowest()}; public: - // The range for the mantissa when normalized - constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; - constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; - // The range for the exponent when normalized constexpr static int minExponent = -32768; constexpr static int maxExponent = 32768; + constexpr static internalrep maxRep = std::numeric_limits::max(); + static_assert(maxRep == 9'223'372'036'854'775'807); + static_assert(-maxRep == std::numeric_limits::min() + 1); + + // May need to make unchecked private struct unchecked { explicit unchecked() = default; }; + // Like unchecked, normalized is used with the ctors that take an + // internalrep mantissa. Unlike unchecked, those ctors will normalize the + // value. + // Only unit tests are expected to use this class + struct normalized + { + explicit normalized() = default; + }; + explicit constexpr Number() = default; Number(rep mantissa); explicit Number(rep mantissa, int exponent); - explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; + explicit constexpr Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept; + // Assume unsigned values are... unsigned. i.e. positive + explicit constexpr Number(internalrep mantissa, int exponent, unchecked) noexcept; + // Only unit tests are expected to use this ctor + explicit Number(bool negative, internalrep mantissa, int exponent, normalized); + // Assume unsigned values are... unsigned. i.e. positive + explicit Number(internalrep mantissa, int exponent, normalized); constexpr rep mantissa() const noexcept; @@ -86,11 +276,11 @@ public: Number& operator/=(Number const& x); - static constexpr Number + static Number min() noexcept; - static constexpr Number + static Number max() noexcept; - static constexpr Number + static Number lowest() noexcept; /** Conversions to Number are implicit and conversions away from Number @@ -104,7 +294,7 @@ public: friend constexpr bool operator==(Number const& x, Number const& y) noexcept { - return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; + return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; } friend constexpr bool @@ -118,8 +308,8 @@ public: { // If the two amounts have different signs (zero is treated as positive) // then the comparison is true iff the left is negative. - bool const lneg = x.mantissa_ < 0; - bool const rneg = y.mantissa_ < 0; + bool const lneg = x.negative_; + bool const rneg = y.negative_; if (lneg != rneg) return lneg; @@ -147,26 +337,11 @@ public: constexpr int signum() const noexcept { - return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0); + return negative_ ? -1 : (mantissa_ ? 1 : 0); } Number - truncate() const noexcept - { - if (exponent_ >= 0 || mantissa_ == 0) - return *this; - - Number ret = *this; - while (ret.exponent_ < 0 && ret.mantissa_ != 0) - { - ret.exponent_ += 1; - ret.mantissa_ /= rep(10); - } - // We are guaranteed that normalize() will never throw an exception - // because exponent is either negative or zero at this point. - ret.normalize(); - return ret; - } + truncate() const noexcept; friend constexpr bool operator>(Number const& x, Number const& y) noexcept @@ -192,6 +367,15 @@ public: return os << to_string(x); } + friend std::string + to_string(Number const& amount); + + friend Number + root(Number f, unsigned d); + + friend Number + root2(Number f); + // Thread local rounding control. Default is to_nearest enum rounding_mode { to_nearest, towards_zero, downward, upward }; static rounding_mode @@ -200,42 +384,194 @@ public: static rounding_mode setround(rounding_mode mode); + /** Returns which mantissa scale is currently in use for normalization. + * + * If you think you need to call this outside of unit tests, no you don't. + */ + static MantissaRange::mantissa_scale + getMantissaScale(); + /** Changes which mantissa scale is used for normalization. + * + * If you think you need to call this outside of unit tests, no you don't. + */ + static void + setMantissaScale(MantissaRange::mantissa_scale scale); + + inline static internalrep + minMantissa() + { + return range_.get().min; + } + + inline static internalrep + maxMantissa() + { + return range_.get().max; + } + + inline static int + mantissaLog() + { + return range_.get().log; + } + + /// oneSmall is needed because the ranges are private + constexpr static Number + oneSmall(); + /// oneLarge is needed because the ranges are private + constexpr static Number + oneLarge(); + + // And one is needed because it needs to choose between oneSmall and + // oneLarge based on the current range + static Number + one(); + + template + [[nodiscard]] + std::pair + normalizeToRange(T minMantissa, T maxMantissa) const; + private: static thread_local rounding_mode mode_; + // The available ranges for mantissa + + constexpr static MantissaRange smallRange{MantissaRange::small}; + static_assert(isPowerOfTen(smallRange.min)); + static_assert(smallRange.min == 1'000'000'000'000'000LL); + static_assert(smallRange.max == 9'999'999'999'999'999LL); + static_assert(smallRange.log == 15); + static_assert(smallRange.min < maxRep); + static_assert(smallRange.max < maxRep); + constexpr static MantissaRange largeRange{MantissaRange::large}; + static_assert(isPowerOfTen(largeRange.min)); + static_assert(largeRange.min == 1'000'000'000'000'000'000ULL); + static_assert(largeRange.max == internalrep(9'999'999'999'999'999'999ULL)); + static_assert(largeRange.log == 18); + static_assert(largeRange.min < maxRep); + static_assert(largeRange.max > maxRep); + + // The range for the mantissa when normalized. + // Use reference_wrapper to avoid making copies, and prevent accidentally + // changing the values inside the range. + static thread_local std::reference_wrapper range_; void normalize(); - constexpr bool + + /** Normalize Number components to an arbitrary range. + * + * min/maxMantissa are parameters because this function is used by both + * normalize(), which reads from range_, and by normalizeToRange, + * which is public and can accept an arbitrary range from the caller. + */ + template + static void + normalize( + bool& negative, + T& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa); + + template + friend void + doNormalize( + bool& negative, + T& mantissa_, + int& exponent_, + MantissaRange::rep const& minMantissa, + MantissaRange::rep const& maxMantissa); + + bool isnormal() const noexcept; + // Copy the number, but modify the exponent by "exponentDelta". Because the + // mantissa doesn't change, the result will be "mostly" normalized, but the + // exponent could go out of range, so it will be checked. + Number + shiftExponent(int exponentDelta) const; + + // Safely convert rep (int64) mantissa to internalrep (uint64). If the rep + // is negative, returns the positive value. This takes a little extra work + // because converting std::numeric_limits::min() flirts with + // UB, and can vary across compilers. + static internalrep + externalToInternal(rep mantissa); + class Guard; }; -inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept - : mantissa_{mantissa}, exponent_{exponent} +inline constexpr Number::Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept + : negative_(negative), mantissa_{mantissa}, exponent_{exponent} +{ +} + +inline constexpr Number::Number(internalrep mantissa, int exponent, unchecked) noexcept + : Number(false, mantissa, exponent, unchecked{}) +{ +} + +constexpr static Number numZero{}; + +inline Number::Number(bool negative, internalrep mantissa, int exponent, normalized) + : Number(negative, mantissa, exponent, unchecked{}) +{ + normalize(); +} + +inline Number::Number(internalrep mantissa, int exponent, normalized) : Number(false, mantissa, exponent, normalized{}) { } inline Number::Number(rep mantissa, int exponent) - : mantissa_{mantissa}, exponent_{exponent} + : Number(mantissa < 0, externalToInternal(mantissa), exponent, normalized{}) { - normalize(); } inline Number::Number(rep mantissa) : Number{mantissa, 0} { } +/** Returns the mantissa of the external view of the Number. + * + * Please see the "---- External Interface ----" section of the class + * documentation for an explanation of why the internal value may be modified. + */ inline constexpr Number::rep Number::mantissa() const noexcept { - return mantissa_; + auto m = mantissa_; + if (m > maxRep) + { + XRPL_ASSERT_PARTS( + !isnormal() || (m % 10 == 0 && m / 10 <= maxRep), + "xrpl::Number::mantissa", + "large normalized mantissa has no remainder"); + m /= 10; + } + auto const sign = negative_ ? -1 : 1; + return sign * static_cast(m); } +/** Returns the exponent of the external view of the Number. + * + * Please see the "---- External Interface ----" section of the class + * documentation for an explanation of why the internal value may be modified. + */ inline constexpr int Number::exponent() const noexcept { - return exponent_; + auto e = exponent_; + if (mantissa_ > maxRep) + { + XRPL_ASSERT_PARTS( + !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= maxRep), + "xrpl::Number::exponent", + "large normalized mantissa has no remainder"); + ++e; + } + return e; } inline constexpr Number @@ -247,15 +583,17 @@ Number::operator+() const noexcept inline constexpr Number Number::operator-() const noexcept { + if (mantissa_ == 0) + return Number{}; auto x = *this; - x.mantissa_ = -x.mantissa_; + x.negative_ = !x.negative_; return x; } inline Number& Number::operator++() { - *this += Number{1000000000000000, -15, unchecked{}}; + *this += one(); return *this; } @@ -270,7 +608,7 @@ Number::operator++(int) inline Number& Number::operator--() { - *this -= Number{1000000000000000, -15, unchecked{}}; + *this -= one(); return *this; } @@ -320,30 +658,48 @@ operator/(Number const& x, Number const& y) return z; } -inline constexpr Number +inline Number Number::min() noexcept { - return Number{minMantissa, minExponent, unchecked{}}; + return Number{false, range_.get().min, minExponent, unchecked{}}; } -inline constexpr Number +inline Number Number::max() noexcept { - return Number{maxMantissa, maxExponent, unchecked{}}; + return Number{false, std::min(range_.get().max, maxRep), maxExponent, unchecked{}}; } -inline constexpr Number +inline Number Number::lowest() noexcept { - return -Number{maxMantissa, maxExponent, unchecked{}}; + return Number{true, std::min(range_.get().max, maxRep), maxExponent, unchecked{}}; } -inline constexpr bool +inline bool Number::isnormal() const noexcept { - auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_; - return minMantissa <= abs_m && abs_m <= maxMantissa && - minExponent <= exponent_ && exponent_ <= maxExponent; + MantissaRange const& range = range_; + auto const abs_m = mantissa_; + return *this == Number{} || + (range.min <= abs_m && abs_m <= range.max && (abs_m <= maxRep || abs_m % 10 == 0) && minExponent <= exponent_ && + exponent_ <= maxExponent); +} + +template +std::pair +Number::normalizeToRange(T minMantissa, T maxMantissa) const +{ + bool negative = negative_; + internalrep mantissa = mantissa_; + int exponent = exponent_; + + if constexpr (std::is_unsigned_v) + XRPL_ASSERT_PARTS(!negative, "xrpl::Number::normalizeToRange", "Number is non-negative for unsigned range."); + Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa); + + auto const sign = negative ? -1 : 1; + return std::make_pair(static_cast(sign * mantissa), exponent); } inline constexpr Number @@ -385,6 +741,20 @@ squelch(Number const& x, Number const& limit) noexcept return x; } +inline std::string +to_string(MantissaRange::mantissa_scale const& scale) +{ + switch (scale) + { + case MantissaRange::small: + return "small"; + case MantissaRange::large: + return "large"; + default: + throw std::runtime_error("Bad scale"); + } +} + class saveNumberRoundMode { Number::rounding_mode mode_; @@ -394,8 +764,7 @@ public: { Number::setround(mode_); } - explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept - : mode_{mode} + explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept : mode_{mode} { } saveNumberRoundMode(saveNumberRoundMode const&) = delete; @@ -412,8 +781,7 @@ class NumberRoundModeGuard saveNumberRoundMode saved_; public: - explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept - : saved_{Number::setround(mode)} + explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept : saved_{Number::setround(mode)} { } @@ -423,6 +791,30 @@ public: operator=(NumberRoundModeGuard const&) = delete; }; -} // namespace ripple +/** Sets the new scale and restores the old scale when it leaves scope. + * + * If you think you need to use this class outside of unit tests, no you don't. + * + */ +class NumberMantissaScaleGuard +{ + MantissaRange::mantissa_scale const saved_; -#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED +public: + explicit NumberMantissaScaleGuard(MantissaRange::mantissa_scale scale) noexcept : saved_{Number::getMantissaScale()} + { + Number::setMantissaScale(scale); + } + + ~NumberMantissaScaleGuard() + { + Number::setMantissaScale(saved_); + } + + NumberMantissaScaleGuard(NumberMantissaScaleGuard const&) = delete; + + NumberMantissaScaleGuard& + operator=(NumberMantissaScaleGuard const&) = delete; +}; + +} // namespace xrpl diff --git a/include/xrpl/basics/README.md b/include/xrpl/basics/README.md index 290bb7ad0c..f8b19522cd 100644 --- a/include/xrpl/basics/README.md +++ b/include/xrpl/basics/README.md @@ -21,11 +21,11 @@ ripple/basic should contain no dependencies on other modules. - `std::set` - For sorted containers. -- `ripple::hash_set` +- `xrpl::hash_set` - Where inserts and contains need to be O(1). - For "small" sets, `std::set` might be faster and smaller. -- `ripple::hardened_hash_set` +- `xrpl::hardened_hash_set` - For data sets where the key could be manipulated by an attacker in an attempt to mount an algorithmic complexity attack: see http://en.wikipedia.org/wiki/Algorithmic_complexity_attack @@ -33,5 +33,5 @@ ripple/basic should contain no dependencies on other modules. The following container is deprecated - `std::unordered_set` -- Use `ripple::hash_set` instead, which uses a better hashing algorithm. -- Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks. +- Use `xrpl::hash_set` instead, which uses a better hashing algorithm. +- Or use `xrpl::hardened_hash_set` to prevent algorithmic complexity attacks. diff --git a/include/xrpl/basics/RangeSet.h b/include/xrpl/basics/RangeSet.h index 0ffed2db1e..f6e03cac79 100644 --- a/include/xrpl/basics/RangeSet.h +++ b/include/xrpl/basics/RangeSet.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_RANGESET_H_INCLUDED -#define RIPPLE_BASICS_RANGESET_H_INCLUDED +#pragma once #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { /** A closed interval over the domain T. @@ -104,7 +84,7 @@ to_string(RangeSet const& rs) std::string s; for (auto const& interval : rs) - s += ripple::to_string(interval) + ","; + s += xrpl::to_string(interval) + ","; s.pop_back(); return s; @@ -191,6 +171,4 @@ prevMissing(RangeSet const& rs, T t, T minVal = 0) return boost::icl::last(tgt); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/Resolver.h b/include/xrpl/basics/Resolver.h index 2ed32f39bd..5bfa6796d2 100644 --- a/include/xrpl/basics/Resolver.h +++ b/include/xrpl/basics/Resolver.h @@ -1,37 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_RESOLVER_H_INCLUDED -#define RIPPLE_BASICS_RESOLVER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class Resolver { public: - using HandlerType = - std::function)>; + using HandlerType = std::function)>; virtual ~Resolver() = 0; @@ -60,12 +39,8 @@ public: } virtual void - resolve( - std::vector const& names, - HandlerType const& handler) = 0; + resolve(std::vector const& names, HandlerType const& handler) = 0; /** @} */ }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/ResolverAsio.h b/include/xrpl/basics/ResolverAsio.h index 94688de650..d0dcc9f185 100644 --- a/include/xrpl/basics/ResolverAsio.h +++ b/include/xrpl/basics/ResolverAsio.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED -#define RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class ResolverAsio : public Resolver { @@ -36,6 +16,4 @@ public: New(boost::asio::io_context&, beast::Journal); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h index 2d2dcdc3ef..22f8505912 100644 --- a/include/xrpl/basics/SHAMapHash.h +++ b/include/xrpl/basics/SHAMapHash.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED -#define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // A SHAMapHash is the hash of a node in a SHAMap, and also the // type of the hash of the entire SHAMap. @@ -116,6 +96,4 @@ extract(SHAMapHash const& key) return *reinterpret_cast(key.as_uint256().data()); } -} // namespace ripple - -#endif // RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/basics/SharedWeakCachePointer.h b/include/xrpl/basics/SharedWeakCachePointer.h index 78e25b4485..afc701ed5a 100644 --- a/include/xrpl/basics/SharedWeakCachePointer.h +++ b/include/xrpl/basics/SharedWeakCachePointer.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED -#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** A combination of a std::shared_ptr and a std::weak_pointer. @@ -131,5 +111,4 @@ public: private: std::variant, std::weak_ptr> combo_; }; -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/SharedWeakCachePointer.ipp b/include/xrpl/basics/SharedWeakCachePointer.ipp index 5a3b6e72a1..6e7514ffae 100644 --- a/include/xrpl/basics/SharedWeakCachePointer.ipp +++ b/include/xrpl/basics/SharedWeakCachePointer.ipp @@ -1,57 +1,31 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED -#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { template -SharedWeakCachePointer::SharedWeakCachePointer( - SharedWeakCachePointer const& rhs) = default; +SharedWeakCachePointer::SharedWeakCachePointer(SharedWeakCachePointer const& rhs) = default; template template requires std::convertible_to -SharedWeakCachePointer::SharedWeakCachePointer( - std::shared_ptr const& rhs) - : combo_{rhs} +SharedWeakCachePointer::SharedWeakCachePointer(std::shared_ptr const& rhs) : combo_{rhs} { } template -SharedWeakCachePointer::SharedWeakCachePointer( - SharedWeakCachePointer&& rhs) = default; +SharedWeakCachePointer::SharedWeakCachePointer(SharedWeakCachePointer&& rhs) = default; template template requires std::convertible_to -SharedWeakCachePointer::SharedWeakCachePointer(std::shared_ptr&& rhs) - : combo_{std::move(rhs)} +SharedWeakCachePointer::SharedWeakCachePointer(std::shared_ptr&& rhs) : combo_{std::move(rhs)} { } template SharedWeakCachePointer& -SharedWeakCachePointer::operator=(SharedWeakCachePointer const& rhs) = - default; +SharedWeakCachePointer::operator=(SharedWeakCachePointer const& rhs) = default; template template @@ -188,5 +162,4 @@ SharedWeakCachePointer::convertToWeak() return false; } -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h index 5e3a2b5138..2578afdc5a 100644 --- a/include/xrpl/basics/SlabAllocator.h +++ b/include/xrpl/basics/SlabAllocator.h @@ -1,24 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2022, Nikolaos D. Bougalis +// Copyright (c) 2022, Nikolaos D. Bougalis - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED -#define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED +#pragma once #include #include @@ -39,7 +21,7 @@ #include #endif -namespace ripple { +namespace xrpl { template class SlabAllocator @@ -68,11 +50,7 @@ class SlabAllocator // The extent of the underlying memory block: std::size_t const size_; - SlabBlock( - SlabBlock* next, - std::uint8_t* data, - std::size_t size, - std::size_t item) + SlabBlock(SlabBlock* next, std::uint8_t* data, std::size_t size, std::size_t item) : next_(next), p_(data), size_(size) { // We don't need to grab the mutex here, since we're the only @@ -143,9 +121,7 @@ class SlabAllocator void deallocate(std::uint8_t* ptr) noexcept { - XRPL_ASSERT( - own(ptr), - "ripple::SlabAllocator::SlabBlock::deallocate : own input"); + XRPL_ASSERT(own(ptr), "xrpl::SlabAllocator::SlabBlock::deallocate : own input"); std::lock_guard l(m_); @@ -176,21 +152,16 @@ public: @param count the number of items the slab allocator can allocate; note that a count of 0 is valid and means that the allocator is, effectively, disabled. This can be very useful in some - contexts (e.g. when mimimal memory usage is needed) and + contexts (e.g. when minimal memory usage is needed) and allows for graceful failure. */ - constexpr explicit SlabAllocator( - std::size_t extra, - std::size_t alloc = 0, - std::size_t align = 0) + constexpr explicit SlabAllocator(std::size_t extra, std::size_t alloc = 0, std::size_t align = 0) : itemAlignment_(align ? align : alignof(Type)) - , itemSize_( - boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_)) + , itemSize_(boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_)) , slabSize_(alloc) { XRPL_ASSERT( - (itemAlignment_ & (itemAlignment_ - 1)) == 0, - "ripple::SlabAllocator::SlabAllocator : valid alignment"); + (itemAlignment_ & (itemAlignment_ - 1)) == 0, "xrpl::SlabAllocator::SlabAllocator : valid alignment"); } SlabAllocator(SlabAllocator const& other) = delete; @@ -239,8 +210,7 @@ public: // We want to allocate the memory at a 2 MiB boundary, to make it // possible to use hugepage mappings on Linux: - auto buf = - boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size); + auto buf = boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size); // clang-format off if (!buf) [[unlikely]] @@ -258,31 +228,21 @@ public: // We need to carve out a bit of memory for the slab header // and then align the rest appropriately: - auto slabData = reinterpret_cast( - reinterpret_cast(buf) + sizeof(SlabBlock)); + auto slabData = reinterpret_cast(reinterpret_cast(buf) + sizeof(SlabBlock)); auto slabSize = size - sizeof(SlabBlock); // This operation is essentially guaranteed not to fail but // let's be careful anyways. - if (!boost::alignment::align( - itemAlignment_, itemSize_, slabData, slabSize)) + if (!boost::alignment::align(itemAlignment_, itemSize_, slabData, slabSize)) { boost::alignment::aligned_free(buf); return nullptr; } - slab = new (buf) SlabBlock( - slabs_.load(), - reinterpret_cast(slabData), - slabSize, - itemSize_); + slab = new (buf) SlabBlock(slabs_.load(), reinterpret_cast(slabData), slabSize, itemSize_); // Link the new slab - while (!slabs_.compare_exchange_weak( - slab->next_, - slab, - std::memory_order_release, - std::memory_order_relaxed)) + while (!slabs_.compare_exchange_weak(slab->next_, slab, std::memory_order_release, std::memory_order_relaxed)) { ; // Nothing to do } @@ -302,7 +262,7 @@ public: { XRPL_ASSERT( ptr, - "ripple::SlabAllocator::SlabAllocator::deallocate : non-null " + "xrpl::SlabAllocator::SlabAllocator::deallocate : non-null " "input"); for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_) @@ -339,10 +299,7 @@ public: std::size_t align; public: - constexpr SlabConfig( - std::size_t extra_, - std::size_t alloc_ = 0, - std::size_t align_ = alignof(Type)) + constexpr SlabConfig(std::size_t extra_, std::size_t alloc_ = 0, std::size_t align_ = alignof(Type)) : extra(extra_), alloc(alloc_), align(align_) { } @@ -353,23 +310,14 @@ public: // Ensure that the specified allocators are sorted from smallest to // largest by size: std::sort( - std::begin(cfg), - std::end(cfg), - [](SlabConfig const& a, SlabConfig const& b) { - return a.extra < b.extra; - }); + std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) { return a.extra < b.extra; }); // We should never have two slabs of the same size - if (std::adjacent_find( - std::begin(cfg), - std::end(cfg), - [](SlabConfig const& a, SlabConfig const& b) { - return a.extra == b.extra; - }) != cfg.end()) + if (std::adjacent_find(std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) { + return a.extra == b.extra; + }) != cfg.end()) { - throw std::runtime_error( - "SlabAllocatorSet<" + beast::type_name() + - ">: duplicate slab size"); + throw std::runtime_error("SlabAllocatorSet<" + beast::type_name() + ">: duplicate slab size"); } for (auto const& c : cfg) @@ -436,6 +384,4 @@ public: } }; -} // namespace ripple - -#endif // RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h index 65d7acfd94..2f6081760f 100644 --- a/include/xrpl/basics/Slice.h +++ b/include/xrpl/basics/Slice.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SLICE_H_INCLUDED -#define RIPPLE_BASICS_SLICE_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { /** An immutable linear range of bytes. @@ -60,8 +40,7 @@ public: operator=(Slice const&) noexcept = default; /** Create a slice pointing to existing memory. */ - Slice(void const* data, std::size_t size) noexcept - : data_(reinterpret_cast(data)), size_(size) + Slice(void const* data, std::size_t size) noexcept : data_(reinterpret_cast(data)), size_(size) { } @@ -104,9 +83,7 @@ public: std::uint8_t operator[](std::size_t i) const noexcept { - XRPL_ASSERT( - i < size_, - "ripple::Slice::operator[](std::size_t) const : valid input"); + XRPL_ASSERT(i < size_, "xrpl::Slice::operator[](std::size_t) const : valid input"); return data_[i]; } @@ -171,8 +148,8 @@ public: /** Return a "sub slice" of given length starting at the given position - Note that the subslice encompasses the range [pos, pos + rcount), - where rcount is the smaller of count and size() - pos. + Note that the subslice encompasses the range [pos, pos + rCount), + where rCount is the smaller of count and size() - pos. @param pos position of the first character @count requested length @@ -181,9 +158,7 @@ public: @throws std::out_of_range if pos > size() */ Slice - substr( - std::size_t pos, - std::size_t count = std::numeric_limits::max()) const + substr(std::size_t pos, std::size_t count = std::numeric_limits::max()) const { if (pos > size()) throw std::out_of_range("Requested sub-slice is out of bounds"); @@ -222,11 +197,7 @@ operator!=(Slice const& lhs, Slice const& rhs) noexcept inline bool operator<(Slice const& lhs, Slice const& rhs) noexcept { - return std::lexicographical_compare( - lhs.data(), - lhs.data() + lhs.size(), - rhs.data(), - rhs.data() + rhs.size()); + return std::lexicographical_compare(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size()); } template @@ -238,18 +209,14 @@ operator<<(Stream& s, Slice const& v) } template -std::enable_if_t< - std::is_same::value || std::is_same::value, - Slice> +std::enable_if_t::value || std::is_same::value, Slice> makeSlice(std::array const& a) { return Slice(a.data(), a.size()); } template -std::enable_if_t< - std::is_same::value || std::is_same::value, - Slice> +std::enable_if_t::value || std::is_same::value, Slice> makeSlice(std::vector const& v) { return Slice(v.data(), v.size()); @@ -262,6 +229,4 @@ makeSlice(std::basic_string const& s) return Slice(s.data(), s.size()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h index 5f905638cb..9b1cf4892d 100644 --- a/include/xrpl/basics/StringUtilities.h +++ b/include/xrpl/basics/StringUtilities.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED -#define RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Format arbitrary binary data as an SQLite "blob literal". @@ -50,7 +30,7 @@ template std::optional strUnHex(std::size_t strSize, Iterator begin, Iterator end) { - static constexpr std::array const unxtab = []() { + static constexpr std::array const digitLookupTable = []() { std::array t{}; for (auto& x : t) @@ -76,7 +56,7 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end) if (strSize & 1) { - int c = unxtab[*iter++]; + int c = digitLookupTable[*iter++]; if (c < 0) return {}; @@ -86,12 +66,12 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end) while (iter != end) { - int cHigh = unxtab[*iter++]; + int cHigh = digitLookupTable[*iter++]; if (cHigh < 0) return {}; - int cLow = unxtab[*iter++]; + int cLow = digitLookupTable[*iter++]; if (cLow < 0) return {}; @@ -128,8 +108,7 @@ struct parsedURL bool operator==(parsedURL const& other) const { - return scheme == other.scheme && domain == other.domain && - port == other.port && path == other.path; + return scheme == other.scheme && domain == other.domain && port == other.port && path == other.path; } }; @@ -151,6 +130,4 @@ to_uint64(std::string const& s); bool isProperlyFormedTomlDomain(std::string_view domain); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h index 99c91fe393..78c4ea7aeb 100644 --- a/include/xrpl/basics/TaggedCache.h +++ b/include/xrpl/basics/TaggedCache.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED -#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED +#pragma once #include #include @@ -35,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Map/cache combination. This class implements a cache and a map. The cache keeps objects alive @@ -75,8 +55,7 @@ public: clock_type::duration expiration, clock_type& clock, beast::Journal journal, - beast::insight::Collector::ptr const& collector = - beast::insight::NullCollector::New()); + beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New()); public: /** Return the clock associated with the cache. */ @@ -133,15 +112,10 @@ public: */ template bool - canonicalize( - key_type const& key, - SharedPointerType& data, - R&& replaceCallback); + canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback); bool - canonicalize_replace_cache( - key_type const& key, - SharedPointerType const& data); + canonicalize_replace_cache(key_type const& key, SharedPointerType const& data); bool canonicalize_replace_client(key_type const& key, SharedPointerType& data); @@ -155,8 +129,7 @@ public: */ template auto - insert(key_type const& key, T const& value) - -> std::enable_if_t; + insert(key_type const& key, T const& value) -> std::enable_if_t; template auto @@ -202,10 +175,7 @@ private: struct Stats { template - Stats( - std::string const& prefix, - Handler const& handler, - beast::insight::Collector::ptr const& collector) + Stats(std::string const& prefix, Handler const& handler, beast::insight::Collector::ptr const& collector) : hook(collector->make_hook(handler)) , size(collector->make_gauge(prefix, "size")) , hit_rate(collector->make_gauge(prefix, "hit_rate")) @@ -227,8 +197,7 @@ private: public: clock_type::time_point last_access; - explicit KeyOnlyEntry(clock_type::time_point const& last_access_) - : last_access(last_access_) + explicit KeyOnlyEntry(clock_type::time_point const& last_access_) : last_access(last_access_) { } @@ -245,9 +214,7 @@ private: shared_weak_combo_pointer_type ptr; clock_type::time_point last_access; - ValueEntry( - clock_type::time_point const& last_access_, - shared_pointer_type const& ptr_) + ValueEntry(clock_type::time_point const& last_access_, shared_pointer_type const& ptr_) : ptr(ptr_), last_access(last_access_) { } @@ -281,18 +248,13 @@ private: } }; - typedef - typename std::conditional::type - Entry; + typedef typename std::conditional::type Entry; - using KeyOnlyCacheType = - hardened_partitioned_hash_map; + using KeyOnlyCacheType = hardened_partitioned_hash_map; - using KeyValueCacheType = - hardened_partitioned_hash_map; + using KeyValueCacheType = hardened_partitioned_hash_map; - using cache_type = - hardened_partitioned_hash_map; + using cache_type = hardened_partitioned_hash_map; [[nodiscard]] std::thread sweepHelper( @@ -334,6 +296,4 @@ private: std::uint64_t m_misses; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/TaggedCache.ipp b/include/xrpl/basics/TaggedCache.ipp index 16a3f7587a..3d0c0342cc 100644 --- a/include/xrpl/basics/TaggedCache.ipp +++ b/include/xrpl/basics/TaggedCache.ipp @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_TAGGEDCACHE_IPP_INCLUDED -#define RIPPLE_BASICS_TAGGEDCACHE_IPP_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { template < class Key, @@ -34,22 +14,13 @@ template < class Hash, class KeyEqual, class Mutex> -inline TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - TaggedCache( - std::string const& name, - int size, - clock_type::duration expiration, - clock_type& clock, - beast::Journal journal, - beast::insight::Collector::ptr const& collector) +inline TaggedCache::TaggedCache( + std::string const& name, + int size, + clock_type::duration expiration, + clock_type& clock, + beast::Journal journal, + beast::insight::Collector::ptr const& collector) : m_journal(journal) , m_clock(clock) , m_stats(name, std::bind(&TaggedCache::collect_metrics, this), collector) @@ -72,15 +43,8 @@ template < class KeyEqual, class Mutex> inline auto -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::clock() -> clock_type& +TaggedCache::clock() + -> clock_type& { return m_clock; } @@ -95,15 +59,7 @@ template < class KeyEqual, class Mutex> inline std::size_t -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::size() const +TaggedCache::size() const { std::lock_guard lock(m_mutex); return m_cache.size(); @@ -119,15 +75,7 @@ template < class KeyEqual, class Mutex> inline int -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::getCacheSize() const +TaggedCache::getCacheSize() const { std::lock_guard lock(m_mutex); return m_cache_count; @@ -143,15 +91,7 @@ template < class KeyEqual, class Mutex> inline int -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::getTrackSize() const +TaggedCache::getTrackSize() const { std::lock_guard lock(m_mutex); return m_cache.size(); @@ -167,15 +107,7 @@ template < class KeyEqual, class Mutex> inline float -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::getHitRate() +TaggedCache::getHitRate() { std::lock_guard lock(m_mutex); auto const total = static_cast(m_hits + m_misses); @@ -192,15 +124,7 @@ template < class KeyEqual, class Mutex> inline void -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::clear() +TaggedCache::clear() { std::lock_guard lock(m_mutex); m_cache.clear(); @@ -217,15 +141,7 @@ template < class KeyEqual, class Mutex> inline void -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::reset() +TaggedCache::reset() { std::lock_guard lock(m_mutex); m_cache.clear(); @@ -245,15 +161,8 @@ template < class Mutex> template inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::touch_if_exists(KeyComparable const& key) +TaggedCache::touch_if_exists( + KeyComparable const& key) { std::lock_guard lock(m_mutex); auto const iter(m_cache.find(key)); @@ -277,15 +186,7 @@ template < class KeyEqual, class Mutex> inline void -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::sweep() +TaggedCache::sweep() { // Keep references to all the stuff we sweep // For performance, each worker thread should exit before the swept data @@ -299,8 +200,7 @@ TaggedCache< { std::lock_guard lock(m_mutex); - if (m_target_size == 0 || - (static_cast(m_cache.size()) <= m_target_size)) + if (m_target_size == 0 || (static_cast(m_cache.size()) <= m_target_size)) { when_expire = now - m_target_age; } @@ -312,10 +212,8 @@ TaggedCache< if (when_expire > (now - minimumAge)) when_expire = now - minimumAge; - JLOG(m_journal.trace()) - << m_name << " is growing fast " << m_cache.size() << " of " - << m_target_size << " aging at " << (now - when_expire).count() - << " of " << m_target_age.count(); + JLOG(m_journal.trace()) << m_name << " is growing fast " << m_cache.size() << " of " << m_target_size + << " aging at " << (now - when_expire).count() << " of " << m_target_age.count(); } std::vector workers; @@ -324,13 +222,7 @@ TaggedCache< for (std::size_t p = 0; p < m_cache.partitions(); ++p) { - workers.push_back(sweepHelper( - when_expire, - now, - m_cache.map()[p], - allStuffToSweep[p], - allRemovals, - lock)); + workers.push_back(sweepHelper(when_expire, now, m_cache.map()[p], allStuffToSweep[p], allRemovals, lock)); } for (std::thread& worker : workers) worker.join(); @@ -341,9 +233,7 @@ TaggedCache< // and decrement the reference count on each strong pointer. JLOG(m_journal.debug()) << m_name << " TaggedCache sweep lock duration " - << std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count() + << std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() << "ms"; } @@ -357,15 +247,9 @@ template < class KeyEqual, class Mutex> inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::del(key_type const& key, bool valid) +TaggedCache::del( + key_type const& key, + bool valid) { // Remove from cache, if !valid, remove from map too. Returns true if // removed from cache @@ -404,19 +288,10 @@ template < class Mutex> template inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - canonicalize( - key_type const& key, - SharedPointerType& data, - R&& replaceCallback) +TaggedCache::canonicalize( + key_type const& key, + SharedPointerType& data, + R&& replaceCallback) { // Return canonical value, store if needed, refresh in cache // Return values: true=we had the data already @@ -427,9 +302,7 @@ TaggedCache< if (cit == m_cache.end()) { m_cache.emplace( - std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple(m_clock.now(), data)); + std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(m_clock.now(), data)); ++m_cache_count; return false; } @@ -499,21 +372,10 @@ template < class KeyEqual, class Mutex> inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - canonicalize_replace_cache( - key_type const& key, - SharedPointerType const& data) +TaggedCache:: + canonicalize_replace_cache(key_type const& key, SharedPointerType const& data) { - return canonicalize( - key, const_cast(data), []() { return true; }); + return canonicalize(key, const_cast(data), []() { return true; }); } template < @@ -526,15 +388,7 @@ template < class KeyEqual, class Mutex> inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: +TaggedCache:: canonicalize_replace_client(key_type const& key, SharedPointerType& data) { return canonicalize(key, data, []() { return false; }); @@ -550,15 +404,8 @@ template < class KeyEqual, class Mutex> inline SharedPointerType -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::fetch(key_type const& key) +TaggedCache::fetch( + key_type const& key) { std::lock_guard l(m_mutex); auto ret = initialFetch(key, l); @@ -578,16 +425,9 @@ template < class Mutex> template inline auto -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::insert(key_type const& key, T const& value) - -> std::enable_if_t +TaggedCache::insert( + key_type const& key, + T const& value) -> std::enable_if_t { static_assert( std::is_same_v, SharedPointerType> || @@ -616,23 +456,13 @@ template < class Mutex> template inline auto -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::insert(key_type const& key) - -> std::enable_if_t +TaggedCache::insert( + key_type const& key) -> std::enable_if_t { std::lock_guard lock(m_mutex); clock_type::time_point const now(m_clock.now()); - auto [it, inserted] = m_cache.emplace( - std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple(now)); + auto [it, inserted] = + m_cache.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now)); if (!inserted) it->second.last_access = now; return inserted; @@ -648,15 +478,9 @@ template < class KeyEqual, class Mutex> inline bool -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::retrieve(key_type const& key, T& data) +TaggedCache::retrieve( + key_type const& key, + T& data) { // retrieve the value of the stored data auto entry = fetch(key); @@ -678,15 +502,8 @@ template < class KeyEqual, class Mutex> inline auto -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::peekMutex() -> mutex_type& +TaggedCache::peekMutex() + -> mutex_type& { return m_mutex; } @@ -701,15 +518,8 @@ template < class KeyEqual, class Mutex> inline auto -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::getKeys() const -> std::vector +TaggedCache::getKeys() const + -> std::vector { std::vector v; @@ -733,15 +543,7 @@ template < class KeyEqual, class Mutex> inline double -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::rate() const +TaggedCache::rate() const { std::lock_guard lock(m_mutex); auto const tot = m_hits + m_misses; @@ -761,15 +563,9 @@ template < class Mutex> template inline SharedPointerType -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::fetch(key_type const& digest, Handler const& h) +TaggedCache::fetch( + key_type const& digest, + Handler const& h) { { std::lock_guard l(m_mutex); @@ -783,8 +579,7 @@ TaggedCache< std::lock_guard l(m_mutex); ++m_misses; - auto const [it, inserted] = - m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle))); + auto const [it, inserted] = m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle))); if (!inserted) it->second.touch(m_clock.now()); return it->second.ptr.getStrong(); @@ -801,16 +596,9 @@ template < class KeyEqual, class Mutex> inline SharedPointerType -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - initialFetch(key_type const& key, std::lock_guard const& l) +TaggedCache::initialFetch( + key_type const& key, + std::lock_guard const& l) { auto cit = m_cache.find(key); if (cit == m_cache.end()) @@ -846,15 +634,7 @@ template < class KeyEqual, class Mutex> inline void -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>::collect_metrics() +TaggedCache::collect_metrics() { m_stats.size.set(getCacheSize()); @@ -880,22 +660,13 @@ template < class KeyEqual, class Mutex> inline std::thread -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - sweepHelper( - clock_type::time_point const& when_expire, - [[maybe_unused]] clock_type::time_point const& now, - typename KeyValueCacheType::map_type& partition, - SweptPointersVector& stuffToSweep, - std::atomic& allRemovals, - std::lock_guard const&) +TaggedCache::sweepHelper( + clock_type::time_point const& when_expire, + [[maybe_unused]] clock_type::time_point const& now, + typename KeyValueCacheType::map_type& partition, + SweptPointersVector& stuffToSweep, + std::atomic& allRemovals, + std::lock_guard const&) { return std::thread([&, this]() { int cacheRemovals = 0; @@ -949,10 +720,8 @@ TaggedCache< if (mapRemovals || cacheRemovals) { - JLOG(m_journal.debug()) - << "TaggedCache partition sweep " << m_name - << ": cache = " << partition.size() << "-" << cacheRemovals - << ", map-=" << mapRemovals; + JLOG(m_journal.debug()) << "TaggedCache partition sweep " << m_name << ": cache = " << partition.size() + << "-" << cacheRemovals << ", map-=" << mapRemovals; } allRemovals += cacheRemovals; @@ -969,22 +738,13 @@ template < class KeyEqual, class Mutex> inline std::thread -TaggedCache< - Key, - T, - IsKeyCache, - SharedWeakUnionPointer, - SharedPointerType, - Hash, - KeyEqual, - Mutex>:: - sweepHelper( - clock_type::time_point const& when_expire, - clock_type::time_point const& now, - typename KeyOnlyCacheType::map_type& partition, - SweptPointersVector&, - std::atomic& allRemovals, - std::lock_guard const&) +TaggedCache::sweepHelper( + clock_type::time_point const& when_expire, + clock_type::time_point const& now, + typename KeyOnlyCacheType::map_type& partition, + SweptPointersVector&, + std::atomic& allRemovals, + std::lock_guard const&) { return std::thread([&, this]() { int cacheRemovals = 0; @@ -1014,16 +774,12 @@ TaggedCache< if (mapRemovals || cacheRemovals) { - JLOG(m_journal.debug()) - << "TaggedCache partition sweep " << m_name - << ": cache = " << partition.size() << "-" << cacheRemovals - << ", map-=" << mapRemovals; + JLOG(m_journal.debug()) << "TaggedCache partition sweep " << m_name << ": cache = " << partition.size() + << "-" << cacheRemovals << ", map-=" << mapRemovals; } allRemovals += cacheRemovals; }); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/ToString.h b/include/xrpl/basics/ToString.h index 93cb0ff335..a6254a1880 100644 --- a/include/xrpl/basics/ToString.h +++ b/include/xrpl/basics/ToString.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_TOSTRING_H_INCLUDED -#define RIPPLE_BASICS_TOSTRING_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** to_string() generalizes std::to_string to handle bools, chars, and strings. @@ -62,6 +42,4 @@ to_string(char const* s) return s; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/UnorderedContainers.h b/include/xrpl/basics/UnorderedContainers.h index 4f6e1093b1..c614f9ea80 100644 --- a/include/xrpl/basics/UnorderedContainers.h +++ b/include/xrpl/basics/UnorderedContainers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED -#define RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED +#pragma once #include #include @@ -41,7 +21,7 @@ * what container it is. */ -namespace ripple { +namespace xrpl { // hash containers @@ -59,8 +39,7 @@ template < class Hash = beast::uhash<>, class Pred = std::equal_to, class Allocator = std::allocator>> -using hash_multimap = - std::unordered_multimap; +using hash_multimap = std::unordered_multimap; template < class Value, @@ -94,8 +73,7 @@ template < class Hash = hardened_hash, class Pred = std::equal_to, class Allocator = std::allocator>> -using hardened_partitioned_hash_map = - partitioned_unordered_map; +using hardened_partitioned_hash_map = partitioned_unordered_map; template < class Key, @@ -103,8 +81,7 @@ template < class Hash = hardened_hash, class Pred = std::equal_to, class Allocator = std::allocator>> -using hardened_hash_multimap = - std::unordered_multimap; +using hardened_hash_multimap = std::unordered_multimap; template < class Value, @@ -118,9 +95,6 @@ template < class Hash = hardened_hash, class Pred = std::equal_to, class Allocator = std::allocator> -using hardened_hash_multiset = - std::unordered_multiset; +using hardened_hash_multiset = std::unordered_multiset; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/UptimeClock.h b/include/xrpl/basics/UptimeClock.h index 7cafb94b53..4edd38d274 100644 --- a/include/xrpl/basics/UptimeClock.h +++ b/include/xrpl/basics/UptimeClock.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED -#define RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { /** Tracks program uptime to seconds precision. @@ -64,6 +44,4 @@ private: start_clock(); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/algorithm.h b/include/xrpl/basics/algorithm.h index 673d5e955b..2378c695df 100644 --- a/include/xrpl/basics/algorithm.h +++ b/include/xrpl/basics/algorithm.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_ALGORITHM_H_INCLUDED -#define RIPPLE_ALGORITHM_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { // Requires: [first1, last1) and [first2, last2) are ordered ranges according to // comp. @@ -71,13 +51,7 @@ generalized_set_intersection( // std::set_intersection. template FwdIter1 -remove_if_intersect_or_match( - FwdIter1 first1, - FwdIter1 last1, - InputIter2 first2, - InputIter2 last2, - Pred pred, - Comp comp) +remove_if_intersect_or_match(FwdIter1 first1, FwdIter1 last1, InputIter2 first2, InputIter2 last2, Pred pred, Comp comp) { // [original-first1, current-first1) is the set of elements to be preserved. // [current-first1, i) is the set of elements that have been removed. @@ -114,6 +88,4 @@ remove_if_intersect_or_match( return first1; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/base64.h b/include/xrpl/basics/base64.h index 515a7584e5..1725ee42f6 100644 --- a/include/xrpl/basics/base64.h +++ b/include/xrpl/basics/base64.h @@ -1,25 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -54,13 +32,12 @@ */ -#ifndef RIPPLE_BASICS_BASE64_H_INCLUDED -#define RIPPLE_BASICS_BASE64_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { std::string base64_encode(std::uint8_t const* data, std::size_t len); @@ -68,13 +45,10 @@ base64_encode(std::uint8_t const* data, std::size_t len); inline std::string base64_encode(std::string const& s) { - return base64_encode( - reinterpret_cast(s.data()), s.size()); + return base64_encode(reinterpret_cast(s.data()), s.size()); } std::string base64_decode(std::string_view data); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index b1a4622cc4..745cb7ab40 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED -#define RIPPLE_BASICS_BASE_UINT_H_INCLUDED +#pragma once #include #include @@ -42,7 +22,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -84,13 +64,9 @@ struct is_contiguous_container : std::true_type template class base_uint { - static_assert( - (Bits % 32) == 0, - "The length of a base_uint in bits must be a multiple of 32."); + static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32."); - static_assert( - Bits >= 64, - "The length of a base_uint in bits must be at least 64."); + static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64."); static constexpr std::size_t WIDTH = Bits / 32; @@ -201,9 +177,7 @@ private: { // Local lambda that converts a single hex char to four bits and // ORs those bits into a uint32_t. - auto hexCharToUInt = [](char c, - std::uint32_t shift, - std::uint32_t& accum) -> ParseResult { + auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult { std::uint32_t nibble = 0xFFu; if (c < '0' || c > 'f') return ParseResult::badChar; @@ -240,8 +214,7 @@ private: std::uint32_t accum = {}; for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u}) { - if (auto const result = hexCharToUInt(*in++, shift, accum); - result != ParseResult::okay) + if (auto const result = hexCharToUInt(*in++, shift, accum); result != ParseResult::okay) return Unexpected(result); } ret[i++] = accum; @@ -280,8 +253,7 @@ public: // This constructor is intended to be used at compile time since it might // throw at runtime. Consider declaring this constructor consteval once // we get to C++23. - explicit constexpr base_uint(std::string_view sv) noexcept(false) - : data_(parseFromStringViewThrows(sv)) + explicit constexpr base_uint(std::string_view sv) noexcept(false) : data_(parseFromStringViewThrows(sv)) { } @@ -294,7 +266,7 @@ public: { XRPL_ASSERT( c.size() * sizeof(typename Container::value_type) == size(), - "ripple::base_uint::base_uint(Container auto) : input size match"); + "xrpl::base_uint::base_uint(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); } @@ -307,7 +279,7 @@ public: { XRPL_ASSERT( c.size() * sizeof(typename Container::value_type) == size(), - "ripple::base_uint::operator=(Container auto) : input size match"); + "xrpl::base_uint::operator=(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); return *this; } @@ -406,8 +378,7 @@ public: // prefix operator for (int i = WIDTH - 1; i >= 0; --i) { - data_[i] = boost::endian::native_to_big( - boost::endian::big_to_native(data_[i]) + 1); + data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1); if (data_[i] != 0) break; } @@ -431,8 +402,7 @@ public: for (int i = WIDTH - 1; i >= 0; --i) { auto prev = data_[i]; - data_[i] = boost::endian::native_to_big( - boost::endian::big_to_native(data_[i]) - 1); + data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1); if (prev != 0) break; @@ -472,11 +442,9 @@ public: for (int i = WIDTH; i--;) { - std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) + - boost::endian::big_to_native(b.data_[i]); + std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) + boost::endian::big_to_native(b.data_[i]); - data_[i] = - boost::endian::native_to_big(static_cast(n)); + data_[i] = boost::endian::native_to_big(static_cast(n)); carry = n >> 32; } @@ -565,7 +533,7 @@ operator<=>(base_uint const& lhs, base_uint const& rhs) // This comparison might seem wrong on a casual inspection because it // compares data internally stored as std::uint32_t byte-by-byte. But // note that the underlying data is stored in big endian, even if the - // plaform is little endian. This makes the comparison correct. + // platform is little endian. This makes the comparison correct. // // FIXME: use std::lexicographical_compare_three_way once support is // added to MacOS. @@ -576,8 +544,7 @@ operator<=>(base_uint const& lhs, base_uint const& rhs) if (ret.first == lhs.cend()) return std::strong_ordering::equivalent; - return (*ret.first > *ret.second) ? std::strong_ordering::greater - : std::strong_ordering::less; + return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less; } template @@ -636,9 +603,7 @@ template inline std::string to_short_string(base_uint const& a) { - static_assert( - base_uint::bytes > 4, - "For 4 bytes or less, use a native type"); + static_assert(base_uint::bytes > 4, "For 4 bytes or less, use a native type"); return strHex(a.cbegin(), a.cbegin() + 4) + "..."; } @@ -667,17 +632,14 @@ static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes"); static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes"); #endif -} // namespace ripple +} // namespace xrpl namespace beast { template -struct is_uniquely_represented> - : public std::true_type +struct is_uniquely_represented> : public std::true_type { explicit is_uniquely_represented() = default; }; } // namespace beast - -#endif diff --git a/include/xrpl/basics/chrono.h b/include/xrpl/basics/chrono.h index 2ed1a96047..bcf988b45e 100644 --- a/include/xrpl/basics/chrono.h +++ b/include/xrpl/basics/chrono.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_CHRONO_H_INCLUDED -#define RIPPLE_BASICS_CHRONO_H_INCLUDED +#pragma once #include #include @@ -31,16 +11,13 @@ #include #include -namespace ripple { +namespace xrpl { // A few handy aliases -using days = std::chrono::duration< - int, - std::ratio_multiply>>; +using days = std::chrono::duration>>; -using weeks = std::chrono:: - duration>>; +using weeks = std::chrono::duration>>; /** Clock for measuring the network time. @@ -53,8 +30,7 @@ using weeks = std::chrono:: */ constexpr static std::chrono::seconds epoch_offset = - date::sys_days{date::year{2000} / 1 / 1} - - date::sys_days{date::year{1970} / 1 / 1}; + date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1}; static_assert(epoch_offset.count() == 946684800); @@ -83,8 +59,7 @@ to_string(NetClock::time_point tp) { // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC using namespace std::chrono; - return to_string( - system_clock::time_point{tp.time_since_epoch() + epoch_offset}); + return to_string(system_clock::time_point{tp.time_since_epoch() + epoch_offset}); } template @@ -101,8 +76,7 @@ to_string_iso(NetClock::time_point tp) // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC // Note, NetClock::duration is seconds, as checked by static_assert static_assert(std::is_same_v>); - return to_string_iso(date::sys_time{ - tp.time_since_epoch() + epoch_offset}); + return to_string_iso(date::sys_time{tp.time_since_epoch() + epoch_offset}); } /** A clock for measuring elapsed time. @@ -123,6 +97,4 @@ stopwatch() return beast::get_abstract_clock(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/comparators.h b/include/xrpl/basics/comparators.h index 0e5f11e9e5..0e21d38d6b 100644 --- a/include/xrpl/basics/comparators.h +++ b/include/xrpl/basics/comparators.h @@ -1,34 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_COMPARATORS_H_INCLUDED -#define RIPPLE_BASICS_COMPARATORS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { #ifdef _MSC_VER /* * MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison - * operator() functions. boost::bimap checks that the comparitor is a + * operator() functions. boost::bimap checks that the comparator is a * BinaryFunction, in part by calling the function and ignoring the value. * These two things don't play well together. These wrapper classes simply * strip [[nodiscard]] from operator() for use in boost::bimap. @@ -71,6 +51,4 @@ using equal_to = std::equal_to; #endif -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/contract.h b/include/xrpl/basics/contract.h index bf98964b9e..8be257bb02 100644 --- a/include/xrpl/basics/contract.h +++ b/include/xrpl/basics/contract.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_CONTRACT_H_INCLUDED -#define RIPPLE_BASICS_CONTRACT_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { /* Programming By Contract @@ -55,15 +35,10 @@ template [[noreturn]] inline void Throw(Args&&... args) { - static_assert( - std::is_convertible::value, - "Exception must derive from std::exception."); + static_assert(std::is_convertible::value, "Exception must derive from std::exception."); E e(std::forward(args)...); - LogThrow( - std::string( - "Throwing exception of type " + beast::type_name() + ": ") + - e.what()); + LogThrow(std::string("Throwing exception of type " + beast::type_name() + ": ") + e.what()); throw e; } @@ -71,6 +46,4 @@ Throw(Args&&... args) [[noreturn]] void LogicError(std::string const& how) noexcept; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h index aae6c55dff..b05ecda7a6 100644 --- a/include/xrpl/basics/hardened_hash.h +++ b/include/xrpl/basics/hardened_hash.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED -#define RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -111,6 +91,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/join.h b/include/xrpl/basics/join.h index dde52bc9e6..16fae4ff87 100644 --- a/include/xrpl/basics/join.h +++ b/include/xrpl/basics/join.h @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2022 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef JOIN_H_INCLUDED -#define JOIN_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { template Stream& @@ -42,8 +23,7 @@ public: Collection const& collection; std::string const delimiter; - explicit CollectionAndDelimiter(Collection const& c, std::string delim) - : collection(c), delimiter(std::move(delim)) + explicit CollectionAndDelimiter(Collection const& c, std::string delim) : collection(c), delimiter(std::move(delim)) { } @@ -51,11 +31,7 @@ public: friend Stream& operator<<(Stream& s, CollectionAndDelimiter const& cd) { - return join( - s, - std::begin(cd.collection), - std::end(cd.collection), - cd.delimiter); + return join(s, std::begin(cd.collection), std::end(cd.collection), cd.delimiter); } }; @@ -87,8 +63,7 @@ public: char const* collection; std::string const delimiter; - explicit CollectionAndDelimiter(char const c[N], std::string delim) - : collection(c), delimiter(std::move(delim)) + explicit CollectionAndDelimiter(char const c[N], std::string delim) : collection(c), delimiter(std::move(delim)) { } @@ -103,6 +78,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/make_SSLContext.h b/include/xrpl/basics/make_SSLContext.h index aba797ce31..1714d3e58c 100644 --- a/include/xrpl/basics/make_SSLContext.h +++ b/include/xrpl/basics/make_SSLContext.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED -#define RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Create a self-signed SSL context that allows anonymous Diffie Hellman. */ std::shared_ptr @@ -38,6 +18,4 @@ make_SSLContextAuthed( std::string const& chainFile, std::string const& cipherList); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/mulDiv.h b/include/xrpl/basics/mulDiv.h index 96d466f6c7..2495f07728 100644 --- a/include/xrpl/basics/mulDiv.h +++ b/include/xrpl/basics/mulDiv.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_MULDIV_H_INCLUDED -#define RIPPLE_BASICS_MULDIV_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { auto constexpr muldiv_max = std::numeric_limits::max(); /** Return value*mul/div accurately. @@ -40,6 +20,4 @@ auto constexpr muldiv_max = std::numeric_limits::max(); std::optional mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h index 4e503ad0fa..181597ca69 100644 --- a/include/xrpl/basics/partitioned_unordered_map.h +++ b/include/xrpl/basics/partitioned_unordered_map.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H -#define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { template static std::size_t @@ -70,8 +50,7 @@ public: using const_reference = value_type const&; using pointer = value_type*; using const_pointer = value_type const*; - using map_type = std:: - unordered_map; + using map_type = std::unordered_map; using partition_map_type = std::vector; struct iterator @@ -132,8 +111,7 @@ public: friend bool operator==(iterator const& lhs, iterator const& rhs) { - return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && - lhs.mit_ == rhs.mit_; + return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_; } friend bool @@ -209,8 +187,7 @@ public: friend bool operator==(const_iterator const& lhs, const_iterator const& rhs) { - return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && - lhs.mit_ == rhs.mit_; + return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_; } friend bool @@ -250,18 +227,15 @@ private: } public: - partitioned_unordered_map( - std::optional partitions = std::nullopt) + partitioned_unordered_map(std::optional partitions = std::nullopt) { // Set partitions to the number of hardware threads if the parameter // is either empty or set to 0. - partitions_ = partitions && *partitions - ? *partitions - : std::thread::hardware_concurrency(); + partitions_ = partitions && *partitions ? *partitions : std::thread::hardware_concurrency(); map_.resize(partitions_); XRPL_ASSERT( partitions_, - "ripple::partitioned_unordered_map::partitioned_unordered_map : " + "xrpl::partitioned_unordered_map::partitioned_unordered_map : " "nonzero partitions"); } @@ -356,10 +330,8 @@ public: auto const& key = std::get<0>(keyTuple); iterator it(&map_); it.ait_ = it.map_->begin() + partitioner(key); - auto [eit, inserted] = it.ait_->emplace( - std::piecewise_construct, - std::forward(keyTuple), - std::forward(valueTuple)); + auto [eit, inserted] = + it.ait_->emplace(std::piecewise_construct, std::forward(keyTuple), std::forward(valueTuple)); it.mit_ = eit; return {it, inserted}; } @@ -370,8 +342,7 @@ public: { iterator it(&map_); it.ait_ = it.map_->begin() + partitioner(key); - auto [eit, inserted] = - it.ait_->emplace(std::forward(key), std::forward(val)); + auto [eit, inserted] = it.ait_->emplace(std::forward(key), std::forward(val)); it.mit_ = eit; return {it, inserted}; } @@ -420,6 +391,4 @@ private: mutable partition_map_type map_{}; }; -} // namespace ripple - -#endif // RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H +} // namespace xrpl diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h index 4b8bc81759..34e460fd8a 100644 --- a/include/xrpl/basics/random.h +++ b/include/xrpl/basics/random.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED -#define RIPPLE_BASICS_RANDOM_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { #ifndef __INTELLISENSE__ static_assert( @@ -39,8 +19,7 @@ static_assert( "The Ripple default PRNG engine must return an unsigned integral type."); static_assert( - std::numeric_limits::max() >= - std::numeric_limits::max(), + std::numeric_limits::max() >= std::numeric_limits::max(), "The Ripple default PRNG engine return must be at least 64 bits wide."); #endif @@ -109,12 +88,10 @@ default_prng() */ /** @{ */ template -std::enable_if_t< - std::is_integral::value && detail::is_engine::value, - Integral> +std::enable_if_t::value && detail::is_engine::value, Integral> rand_int(Engine& engine, Integral min, Integral max) { - XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs"); + XRPL_ASSERT(max > min, "xrpl::rand_int : max over min inputs"); // This should have no state and constructing it should // be very cheap. If that turns out not to be the case @@ -130,9 +107,7 @@ rand_int(Integral min, Integral max) } template -std::enable_if_t< - std::is_integral::value && detail::is_engine::value, - Integral> +std::enable_if_t::value && detail::is_engine::value, Integral> rand_int(Engine& engine, Integral max) { return rand_int(engine, Integral(0), max); @@ -146,9 +121,7 @@ rand_int(Integral max) } template -std::enable_if_t< - std::is_integral::value && detail::is_engine::value, - Integral> +std::enable_if_t::value && detail::is_engine::value, Integral> rand_int(Engine& engine) { return rand_int(engine, std::numeric_limits::max()); @@ -166,23 +139,17 @@ rand_int() /** @{ */ template std::enable_if_t< - (std::is_same::value || - std::is_same::value) && + (std::is_same::value || std::is_same::value) && detail::is_engine::value, Byte> rand_byte(Engine& engine) { - return static_cast(rand_int( - engine, - std::numeric_limits::min(), - std::numeric_limits::max())); + return static_cast( + rand_int(engine, std::numeric_limits::min(), std::numeric_limits::max())); } template -std::enable_if_t< - (std::is_same::value || - std::is_same::value), - Byte> +std::enable_if_t<(std::is_same::value || std::is_same::value), Byte> rand_byte() { return rand_byte(default_prng()); @@ -205,6 +172,4 @@ rand_bool() } /** @} */ -} // namespace ripple - -#endif // RIPPLE_BASICS_RANDOM_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/basics/rocksdb.h b/include/xrpl/basics/rocksdb.h index 4a71dc4b57..3d468b0f1b 100644 --- a/include/xrpl/basics/rocksdb.h +++ b/include/xrpl/basics/rocksdb.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_UNITY_ROCKSDB_H_INCLUDED -#define RIPPLE_UNITY_ROCKSDB_H_INCLUDED - -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE // #include #include #include @@ -47,5 +27,3 @@ #include #endif - -#endif diff --git a/include/xrpl/basics/safe_cast.h b/include/xrpl/basics/safe_cast.h index a750a3b6fc..285d76782a 100644 --- a/include/xrpl/basics/safe_cast.h +++ b/include/xrpl/basics/safe_cast.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SAFE_CAST_H_INCLUDED -#define RIPPLE_BASICS_SAFE_CAST_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { // safe_cast adds compile-time checks to a static_cast to ensure that // the destination can hold all values of the source. This is particularly @@ -31,38 +11,29 @@ namespace ripple { template concept SafeToCast = (std::is_integral_v && std::is_integral_v) && (std::is_signed::value || std::is_unsigned::value) && - (std::is_signed::value != std::is_signed::value - ? sizeof(Dest) > sizeof(Src) - : sizeof(Dest) >= sizeof(Src)); + (std::is_signed::value != std::is_signed::value ? sizeof(Dest) > sizeof(Src) + : sizeof(Dest) >= sizeof(Src)); template -inline constexpr std:: - enable_if_t && std::is_integral_v, Dest> - safe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_integral_v, Dest> +safe_cast(Src s) noexcept { - static_assert( - std::is_signed_v || std::is_unsigned_v, - "Cannot cast signed to unsigned"); - constexpr unsigned not_same = - std::is_signed_v != std::is_signed_v; - static_assert( - sizeof(Dest) >= sizeof(Src) + not_same, - "Destination is too small to hold all values of source"); + static_assert(std::is_signed_v || std::is_unsigned_v, "Cannot cast signed to unsigned"); + constexpr unsigned not_same = std::is_signed_v != std::is_signed_v; + static_assert(sizeof(Dest) >= sizeof(Src) + not_same, "Destination is too small to hold all values of source"); return static_cast(s); } template -inline constexpr std:: - enable_if_t && std::is_integral_v, Dest> - safe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_integral_v, Dest> +safe_cast(Src s) noexcept { return static_cast(safe_cast>(s)); } template -inline constexpr std:: - enable_if_t && std::is_enum_v, Dest> - safe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_enum_v, Dest> +safe_cast(Src s) noexcept { return safe_cast(static_cast>(s)); } @@ -72,9 +43,8 @@ inline constexpr std:: // underlying types become safe, it can be converted to a safe_cast. template -inline constexpr std:: - enable_if_t && std::is_integral_v, Dest> - unsafe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_integral_v, Dest> +unsafe_cast(Src s) noexcept { static_assert( !SafeToCast, @@ -84,21 +54,17 @@ inline constexpr std:: } template -inline constexpr std:: - enable_if_t && std::is_integral_v, Dest> - unsafe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_integral_v, Dest> +unsafe_cast(Src s) noexcept { return static_cast(unsafe_cast>(s)); } template -inline constexpr std:: - enable_if_t && std::is_enum_v, Dest> - unsafe_cast(Src s) noexcept +inline constexpr std::enable_if_t && std::is_enum_v, Dest> +unsafe_cast(Src s) noexcept { return unsafe_cast(static_cast>(s)); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h index 954edcc2a1..797a7d3fdc 100644 --- a/include/xrpl/basics/scope.h +++ b/include/xrpl/basics/scope.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_SCOPE_H_INCLUDED -#define RIPPLE_BASICS_SCOPE_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { // RAII scope helpers. As specified in Library Fundamental, Version 3 // Basic design of idea: https://www.youtube.com/watch?v=WjTrfoiB0MQ @@ -55,10 +35,8 @@ public: } scope_exit(scope_exit&& rhs) noexcept( - std::is_nothrow_move_constructible_v || - std::is_nothrow_copy_constructible_v) - : exit_function_{std::forward(rhs.exit_function_)} - , execute_on_destruction_{rhs.execute_on_destruction_} + std::is_nothrow_move_constructible_v || std::is_nothrow_copy_constructible_v) + : exit_function_{std::forward(rhs.exit_function_)}, execute_on_destruction_{rhs.execute_on_destruction_} { rhs.release(); } @@ -69,14 +47,11 @@ public: template explicit scope_exit( EFP&& f, - std::enable_if_t< - !std::is_same_v, scope_exit> && - std::is_constructible_v>* = 0) noexcept + std::enable_if_t, scope_exit> && std::is_constructible_v>* = + 0) noexcept : exit_function_{std::forward(f)} { - static_assert( - std:: - is_nothrow_constructible_v(f))>); + static_assert(std::is_nothrow_constructible_v(f))>); } void @@ -99,14 +74,12 @@ class scope_fail public: ~scope_fail() { - if (execute_on_destruction_ && - std::uncaught_exceptions() > uncaught_on_creation_) + if (execute_on_destruction_ && std::uncaught_exceptions() > uncaught_on_creation_) exit_function_(); } scope_fail(scope_fail&& rhs) noexcept( - std::is_nothrow_move_constructible_v || - std::is_nothrow_copy_constructible_v) + std::is_nothrow_move_constructible_v || std::is_nothrow_copy_constructible_v) : exit_function_{std::forward(rhs.exit_function_)} , execute_on_destruction_{rhs.execute_on_destruction_} , uncaught_on_creation_{rhs.uncaught_on_creation_} @@ -120,14 +93,11 @@ public: template explicit scope_fail( EFP&& f, - std::enable_if_t< - !std::is_same_v, scope_fail> && - std::is_constructible_v>* = 0) noexcept + std::enable_if_t, scope_fail> && std::is_constructible_v>* = + 0) noexcept : exit_function_{std::forward(f)} { - static_assert( - std:: - is_nothrow_constructible_v(f))>); + static_assert(std::is_nothrow_constructible_v(f))>); } void @@ -150,14 +120,12 @@ class scope_success public: ~scope_success() noexcept(noexcept(exit_function_())) { - if (execute_on_destruction_ && - std::uncaught_exceptions() <= uncaught_on_creation_) + if (execute_on_destruction_ && std::uncaught_exceptions() <= uncaught_on_creation_) exit_function_(); } scope_success(scope_success&& rhs) noexcept( - std::is_nothrow_move_constructible_v || - std::is_nothrow_copy_constructible_v) + std::is_nothrow_move_constructible_v || std::is_nothrow_copy_constructible_v) : exit_function_{std::forward(rhs.exit_function_)} , execute_on_destruction_{rhs.execute_on_destruction_} , uncaught_on_creation_{rhs.uncaught_on_creation_} @@ -171,9 +139,7 @@ public: template explicit scope_success( EFP&& f, - std::enable_if_t< - !std::is_same_v, scope_success> && - std::is_constructible_v>* = + std::enable_if_t, scope_success> && std::is_constructible_v>* = 0) noexcept(std::is_nothrow_constructible_v || std::is_nothrow_constructible_v) : exit_function_{std::forward(f)} { @@ -232,12 +198,9 @@ class scope_unlock std::unique_lock* plock; public: - explicit scope_unlock(std::unique_lock& lock) noexcept(true) - : plock(&lock) + explicit scope_unlock(std::unique_lock& lock) noexcept(true) : plock(&lock) { - XRPL_ASSERT( - plock->owns_lock(), - "ripple::scope_unlock::scope_unlock : mutex must be locked"); + XRPL_ASSERT(plock->owns_lock(), "xrpl::scope_unlock::scope_unlock : mutex must be locked"); plock->unlock(); } @@ -255,6 +218,4 @@ public: template scope_unlock(std::unique_lock&) -> scope_unlock; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/spinlock.h b/include/xrpl/basics/spinlock.h index 5d5097bd2d..7b05b7c339 100644 --- a/include/xrpl/basics/spinlock.h +++ b/include/xrpl/basics/spinlock.h @@ -1,22 +1,6 @@ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2022, Nikolaos D. Bougalis +// Copyright (c) 2022, Nikolaos D. Bougalis - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef RIPPLE_BASICS_SPINLOCK_H_INCLUDED -#define RIPPLE_BASICS_SPINLOCK_H_INCLUDED +#pragma once #include @@ -28,7 +12,7 @@ #include #endif -namespace ripple { +namespace xrpl { namespace detail { /** Inform the processor that we are in a tight spin-wait loop. @@ -115,12 +99,9 @@ public: @note For performance reasons, you should strive to have `lock` be on a cacheline by itself. */ - packed_spinlock(std::atomic& lock, int index) - : bits_(lock), mask_(static_cast(1) << index) + packed_spinlock(std::atomic& lock, int index) : bits_(lock), mask_(static_cast(1) << index) { - XRPL_ASSERT( - index >= 0 && (mask_ != 0), - "ripple::packed_spinlock::packed_spinlock : valid index and mask"); + XRPL_ASSERT(index >= 0 && (mask_ != 0), "xrpl::packed_spinlock::packed_spinlock : valid index and mask"); } [[nodiscard]] bool @@ -193,10 +174,7 @@ public: T expected = 0; return lock_.compare_exchange_weak( - expected, - std::numeric_limits::max(), - std::memory_order_acquire, - std::memory_order_relaxed); + expected, std::numeric_limits::max(), std::memory_order_acquire, std::memory_order_relaxed); } void @@ -221,6 +199,4 @@ public: }; /** @} */ -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/strHex.h b/include/xrpl/basics/strHex.h index 257fb540b3..76a3d86ff3 100644 --- a/include/xrpl/basics/strHex.h +++ b/include/xrpl/basics/strHex.h @@ -1,38 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_STRHEX_H_INCLUDED -#define RIPPLE_BASICS_STRHEX_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { template std::string strHex(FwdIt begin, FwdIt end) { static_assert( - std::is_convertible< - typename std::iterator_traits::iterator_category, - std::forward_iterator_tag>::value, + std::is_convertible::iterator_category, std::forward_iterator_tag>::value, "FwdIt must be a forward iterator"); std::string result; result.reserve(2 * std::distance(begin, end)); @@ -47,6 +25,4 @@ strHex(T const& from) return strHex(from.begin(), from.end()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h index ed30b6f120..439cc537e2 100644 --- a/include/xrpl/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -1,24 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2014, Nikolaos D. Bougalis +// Copyright (c) 2014, Nikolaos D. Bougalis - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED -#define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED +#pragma once #include @@ -27,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** A type-safe wrap around standard integral types @@ -48,9 +30,7 @@ class tagged_integer tagged_integer, boost::bitwise< tagged_integer, - boost::unit_steppable< - tagged_integer, - boost::shiftable>>>>> + boost::unit_steppable, boost::shiftable>>>>> { private: Int m_value; @@ -63,14 +43,10 @@ public: template < class OtherInt, - class = typename std::enable_if< - std::is_integral::value && - sizeof(OtherInt) <= sizeof(Int)>::type> + class = typename std::enable_if::value && sizeof(OtherInt) <= sizeof(Int)>::type> explicit constexpr tagged_integer(OtherInt value) noexcept : m_value(value) { - static_assert( - sizeof(tagged_integer) == sizeof(Int), - "tagged_integer is adding padding"); + static_assert(sizeof(tagged_integer) == sizeof(Int), "tagged_integer is adding padding"); } bool @@ -214,15 +190,14 @@ public: } }; -} // namespace ripple +} // namespace xrpl namespace beast { template -struct is_contiguously_hashable, HashAlgorithm> +struct is_contiguously_hashable, HashAlgorithm> : public is_contiguously_hashable { explicit is_contiguously_hashable() = default; }; } // namespace beast -#endif diff --git a/include/xrpl/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h index 37f75cf649..347203acb3 100644 --- a/include/xrpl/beast/asio/io_latency_probe.h +++ b/include/xrpl/beast/asio/io_latency_probe.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED -#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED +#pragma once #include @@ -51,11 +31,7 @@ private: public: io_latency_probe(duration const& period, boost::asio::io_context& ios) - : m_count(1) - , m_period(period) - , m_ios(ios) - , m_timer(m_ios) - , m_cancel(false) + : m_count(1), m_period(period), m_ios(ios), m_timer(m_ios), m_cancel(false) { } @@ -110,10 +86,7 @@ public: std::lock_guard lock(m_mutex); if (m_cancel) throw std::logic_error("io_latency_probe is canceled"); - boost::asio::post( - m_ios, - sample_op( - std::forward(handler), Clock::now(), false, this)); + boost::asio::post(m_ios, sample_op(std::forward(handler), Clock::now(), false, this)); } /** Initiate continuous i/o latency sampling. @@ -127,10 +100,7 @@ public: std::lock_guard lock(m_mutex); if (m_cancel) throw std::logic_error("io_latency_probe is canceled"); - boost::asio::post( - m_ios, - sample_op( - std::forward(handler), Clock::now(), true, this)); + boost::asio::post(m_ios, sample_op(std::forward(handler), Clock::now(), true, this)); } private: @@ -170,15 +140,8 @@ private: bool m_repeat; io_latency_probe* m_probe; - sample_op( - Handler const& handler, - time_point const& start, - bool repeat, - io_latency_probe* probe) - : m_handler(handler) - , m_start(start) - , m_repeat(repeat) - , m_probe(probe) + sample_op(Handler const& handler, time_point const& start, bool repeat, io_latency_probe* probe) + : m_handler(handler), m_start(start), m_repeat(repeat), m_probe(probe) { XRPL_ASSERT( m_probe, @@ -233,23 +196,19 @@ private: // Calculate when we want to sample again, and // adjust for the expected latency. // - typename Clock::time_point const when( - now + m_probe->m_period - 2 * elapsed); + typename Clock::time_point const when(now + m_probe->m_period - 2 * elapsed); if (when <= now) { // The latency is too high to maintain the desired // period so don't bother with a timer. // - boost::asio::post( - m_probe->m_ios, - sample_op(m_handler, now, m_repeat, m_probe)); + boost::asio::post(m_probe->m_ios, sample_op(m_handler, now, m_repeat, m_probe)); } else { m_probe->m_timer.expires_after(when - now); - m_probe->m_timer.async_wait( - sample_op(m_handler, now, m_repeat, m_probe)); + m_probe->m_timer.async_wait(sample_op(m_handler, now, m_repeat, m_probe)); } } } @@ -260,13 +219,9 @@ private: if (!m_probe) return; typename Clock::time_point const now(Clock::now()); - boost::asio::post( - m_probe->m_ios, - sample_op(m_handler, now, m_repeat, m_probe)); + boost::asio::post(m_probe->m_ios, sample_op(m_handler, now, m_repeat, m_probe)); } }; }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/clock/abstract_clock.h b/include/xrpl/beast/clock/abstract_clock.h index 7b0f04225f..41b57fdd2c 100644 --- a/include/xrpl/beast/clock/abstract_clock.h +++ b/include/xrpl/beast/clock/abstract_clock.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED -#define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED +#pragma once namespace beast { @@ -108,5 +88,3 @@ get_abstract_clock() } } // namespace beast - -#endif diff --git a/include/xrpl/beast/clock/basic_seconds_clock.h b/include/xrpl/beast/clock/basic_seconds_clock.h index 4e444fefee..5205d92fef 100644 --- a/include/xrpl/beast/clock/basic_seconds_clock.h +++ b/include/xrpl/beast/clock/basic_seconds_clock.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED -#define BEAST_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED +#pragma once #include @@ -52,5 +32,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index a0e82b7014..a301b4e1fe 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED -#define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED +#pragma once #include #include @@ -48,8 +28,7 @@ private: time_point now_; public: - explicit manual_clock(time_point const& now = time_point(duration(0))) - : now_(now) + explicit manual_clock(time_point const& now = time_point(duration(0))) : now_(now) { } @@ -63,9 +42,7 @@ public: void set(time_point const& when) { - XRPL_ASSERT( - !Clock::is_steady || when >= now_, - "beast::manual_clock::set(time_point) : forward input"); + XRPL_ASSERT(!Clock::is_steady || when >= now_, "beast::manual_clock::set(time_point) : forward input"); now_ = when; } @@ -83,8 +60,7 @@ public: advance(std::chrono::duration const& elapsed) { XRPL_ASSERT( - !Clock::is_steady || (now_ + elapsed) >= now_, - "beast::manual_clock::advance(duration) : forward input"); + !Clock::is_steady || (now_ + elapsed) >= now_, "beast::manual_clock::advance(duration) : forward input"); now_ += elapsed; } @@ -98,5 +74,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/aged_container.h b/include/xrpl/beast/container/aged_container.h index 38a50b4e84..dd622fcd9a 100644 --- a/include/xrpl/beast/container/aged_container.h +++ b/include/xrpl/beast/container/aged_container.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_CONTAINER_H_INCLUDED -#define BEAST_CONTAINER_AGED_CONTAINER_H_INCLUDED +#pragma once #include @@ -31,5 +11,3 @@ struct is_aged_container : std::false_type }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h index d315f05346..fd5d481aa5 100644 --- a/include/xrpl/beast/container/aged_container_utility.h +++ b/include/xrpl/beast/container/aged_container_utility.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED -#define BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED +#pragma once #include @@ -29,14 +9,12 @@ namespace beast { /** Expire aged container items past the specified age. */ template -typename std::enable_if::value, std::size_t>:: - type - expire(AgedContainer& c, std::chrono::duration const& age) +typename std::enable_if::value, std::size_t>::type +expire(AgedContainer& c, std::chrono::duration const& age) { std::size_t n(0); auto const expired(c.clock().now() - age); - for (auto iter(c.chronological.cbegin()); - iter != c.chronological.cend() && iter.when() <= expired;) + for (auto iter(c.chronological.cbegin()); iter != c.chronological.cend() && iter.when() <= expired;) { iter = c.erase(iter); ++n; @@ -45,5 +23,3 @@ typename std::enable_if::value, std::size_t>:: } } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/aged_map.h b/include/xrpl/beast/container/aged_map.h index 5b56cde962..e9505f2763 100644 --- a/include/xrpl/beast/container/aged_map.h +++ b/include/xrpl/beast/container/aged_map.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_MAP_H_INCLUDED -#define BEAST_CONTAINER_AGED_MAP_H_INCLUDED +#pragma once #include @@ -34,9 +14,6 @@ template < class Clock = std::chrono::steady_clock, class Compare = std::less, class Allocator = std::allocator>> -using aged_map = detail:: - aged_ordered_container; +using aged_map = detail::aged_ordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_multimap.h b/include/xrpl/beast/container/aged_multimap.h index aa6c01f5b3..7625694f66 100644 --- a/include/xrpl/beast/container/aged_multimap.h +++ b/include/xrpl/beast/container/aged_multimap.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED -#define BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED +#pragma once #include @@ -34,9 +14,6 @@ template < class Clock = std::chrono::steady_clock, class Compare = std::less, class Allocator = std::allocator>> -using aged_multimap = detail:: - aged_ordered_container; +using aged_multimap = detail::aged_ordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_multiset.h b/include/xrpl/beast/container/aged_multiset.h index d43cc8d5a7..2ad09344e5 100644 --- a/include/xrpl/beast/container/aged_multiset.h +++ b/include/xrpl/beast/container/aged_multiset.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED -#define BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED +#pragma once #include @@ -33,9 +13,6 @@ template < class Clock = std::chrono::steady_clock, class Compare = std::less, class Allocator = std::allocator> -using aged_multiset = detail:: - aged_ordered_container; +using aged_multiset = detail::aged_ordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_set.h b/include/xrpl/beast/container/aged_set.h index aa31a47af4..2c601f5f41 100644 --- a/include/xrpl/beast/container/aged_set.h +++ b/include/xrpl/beast/container/aged_set.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_SET_H_INCLUDED -#define BEAST_CONTAINER_AGED_SET_H_INCLUDED +#pragma once #include @@ -33,9 +13,6 @@ template < class Clock = std::chrono::steady_clock, class Compare = std::less, class Allocator = std::allocator> -using aged_set = detail:: - aged_ordered_container; +using aged_set = detail::aged_ordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_unordered_map.h b/include/xrpl/beast/container/aged_unordered_map.h index b466c87b3f..116d5669a1 100644 --- a/include/xrpl/beast/container/aged_unordered_map.h +++ b/include/xrpl/beast/container/aged_unordered_map.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED -#define BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED +#pragma once #include @@ -35,16 +15,6 @@ template < class Hash = std::hash, class KeyEqual = std::equal_to, class Allocator = std::allocator>> -using aged_unordered_map = detail::aged_unordered_container< - false, - true, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>; +using aged_unordered_map = detail::aged_unordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_unordered_multimap.h b/include/xrpl/beast/container/aged_unordered_multimap.h index e64c8415c6..4c3333a099 100644 --- a/include/xrpl/beast/container/aged_unordered_multimap.h +++ b/include/xrpl/beast/container/aged_unordered_multimap.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED -#define BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED +#pragma once #include @@ -35,16 +15,6 @@ template < class Hash = std::hash, class KeyEqual = std::equal_to, class Allocator = std::allocator>> -using aged_unordered_multimap = detail::aged_unordered_container< - true, - true, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>; +using aged_unordered_multimap = detail::aged_unordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_unordered_multiset.h b/include/xrpl/beast/container/aged_unordered_multiset.h index 499dc7d678..b251f20077 100644 --- a/include/xrpl/beast/container/aged_unordered_multiset.h +++ b/include/xrpl/beast/container/aged_unordered_multiset.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED -#define BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED +#pragma once #include @@ -34,16 +14,7 @@ template < class Hash = std::hash, class KeyEqual = std::equal_to, class Allocator = std::allocator> -using aged_unordered_multiset = detail::aged_unordered_container< - true, - false, - Key, - void, - Clock, - Hash, - KeyEqual, - Allocator>; +using aged_unordered_multiset = + detail::aged_unordered_container; } - -#endif diff --git a/include/xrpl/beast/container/aged_unordered_set.h b/include/xrpl/beast/container/aged_unordered_set.h index 45fc6cd0ed..a8ee61f1f5 100644 --- a/include/xrpl/beast/container/aged_unordered_set.h +++ b/include/xrpl/beast/container/aged_unordered_set.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED -#define BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED +#pragma once #include @@ -34,16 +14,6 @@ template < class Hash = std::hash, class KeyEqual = std::equal_to, class Allocator = std::allocator> -using aged_unordered_set = detail::aged_unordered_container< - false, - false, - Key, - void, - Clock, - Hash, - KeyEqual, - Allocator>; +using aged_unordered_set = detail::aged_unordered_container; } - -#endif diff --git a/include/xrpl/beast/container/detail/aged_associative_container.h b/include/xrpl/beast/container/detail/aged_associative_container.h index 678fbe4e17..34e9560cbb 100644 --- a/include/xrpl/beast/container/detail/aged_associative_container.h +++ b/include/xrpl/beast/container/detail/aged_associative_container.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED -#define BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED +#pragma once namespace beast { namespace detail { @@ -52,5 +32,3 @@ struct aged_associative_container_extract_t } // namespace detail } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/detail/aged_container_iterator.h b/include/xrpl/beast/container/detail/aged_container_iterator.h index 7467ad33c7..12cd15f677 100644 --- a/include/xrpl/beast/container/detail/aged_container_iterator.h +++ b/include/xrpl/beast/container/detail/aged_container_iterator.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED -#define BEAST_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED +#pragma once #include #include @@ -35,14 +15,12 @@ template class aged_container_iterator { public: - using iterator_category = - typename std::iterator_traits::iterator_category; + using iterator_category = typename std::iterator_traits::iterator_category; using value_type = typename std::conditional< is_const, typename Iterator::value_type::stashed::value_type const, typename Iterator::value_type::stashed::value_type>::type; - using difference_type = - typename std::iterator_traits::difference_type; + using difference_type = typename std::iterator_traits::difference_type; using pointer = value_type*; using reference = value_type&; using time_point = typename Iterator::value_type::stashed::time_point; @@ -57,31 +35,22 @@ public: class = typename std::enable_if< (other_is_const == false || is_const == true) && std::is_same::value == false>::type> - explicit aged_container_iterator( - aged_container_iterator const& other) + explicit aged_container_iterator(aged_container_iterator const& other) : m_iter(other.m_iter) { } // Disable constructing a const_iterator from a non-const_iterator. - template < - bool other_is_const, - class = typename std::enable_if< - other_is_const == false || is_const == true>::type> - aged_container_iterator( - aged_container_iterator const& other) - : m_iter(other.m_iter) + template ::type> + aged_container_iterator(aged_container_iterator const& other) : m_iter(other.m_iter) { } // Disable assigning a const_iterator to a non-const iterator template auto - operator=( - aged_container_iterator const& other) -> - typename std::enable_if< - other_is_const == false || is_const == true, - aged_container_iterator&>::type + operator=(aged_container_iterator const& other) -> + typename std::enable_if::type { m_iter = other.m_iter; return *this; @@ -89,16 +58,14 @@ public: template bool - operator==(aged_container_iterator const& - other) const + operator==(aged_container_iterator const& other) const { return m_iter == other.m_iter; } template bool - operator!=(aged_container_iterator const& - other) const + operator!=(aged_container_iterator const& other) const { return m_iter != other.m_iter; } @@ -178,5 +145,3 @@ private: } // namespace detail } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h index ef3e1b5ea1..2f3d8973e9 100644 --- a/include/xrpl/beast/container/detail/aged_ordered_container.h +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED -#define BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED +#pragma once #include #include @@ -49,8 +29,7 @@ struct is_boost_reverse_iterator : std::false_type }; template -struct is_boost_reverse_iterator> - : std::true_type +struct is_boost_reverse_iterator> : std::true_type { explicit is_boost_reverse_iterator() = default; }; @@ -78,8 +57,7 @@ template < class T, class Clock = std::chrono::steady_clock, class Compare = std::less, - class Allocator = std::allocator< - typename std::conditional, Key>::type>> + class Allocator = std::allocator, Key>::type>> class aged_ordered_container { public: @@ -88,8 +66,7 @@ public: using duration = typename clock_type::duration; using key_type = Key; using mapped_type = T; - using value_type = - typename std::conditional, Key>::type; + using value_type = typename std::conditional, Key>::type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; @@ -106,11 +83,8 @@ private: } // VFALCO TODO hoist to remove template argument dependencies - struct element - : boost::intrusive::set_base_hook< - boost::intrusive::link_mode>, - boost::intrusive::list_base_hook< - boost::intrusive::link_mode> + struct element : boost::intrusive::set_base_hook>, + boost::intrusive::list_base_hook> { // Stash types here so the iterator doesn't // need to see the container declaration. @@ -122,22 +96,18 @@ private: using time_point = typename aged_ordered_container::time_point; }; - element(time_point const& when_, value_type const& value_) - : value(value_), when(when_) + element(time_point const& when_, value_type const& value_) : value(value_), when(when_) { } - element(time_point const& when_, value_type&& value_) - : value(std::move(value_)), when(when_) + element(time_point const& when_, value_type&& value_) : value(std::move(value_)), when(when_) { } template < class... Args, - class = typename std::enable_if< - std::is_constructible::value>::type> - element(time_point const& when_, Args&&... args) - : value(std::forward(args)...), when(when_) + class = typename std::enable_if::value>::type> + element(time_point const& when_, Args&&... args) : value(std::forward(args)...), when(when_) { } @@ -221,8 +191,7 @@ private: } }; - using list_type = typename boost::intrusive:: - make_list>::type; + using list_type = typename boost::intrusive::make_list>::type; using cont_type = typename std::conditional< IsMulti, @@ -230,51 +199,39 @@ private: element, boost::intrusive::constant_time_size, boost::intrusive::compare>::type, - typename boost::intrusive::make_set< - element, - boost::intrusive::constant_time_size, - boost::intrusive::compare>::type>::type; + typename boost::intrusive:: + make_set, boost::intrusive::compare>:: + type>::type; - using ElementAllocator = typename std::allocator_traits< - Allocator>::template rebind_alloc; + using ElementAllocator = typename std::allocator_traits::template rebind_alloc; using ElementAllocatorTraits = std::allocator_traits; - class config_t - : private KeyValueCompare, - public beast::detail::empty_base_optimization + class config_t : private KeyValueCompare, public beast::detail::empty_base_optimization { public: explicit config_t(clock_type& clock_) : clock(clock_) { } - config_t(clock_type& clock_, Compare const& comp) - : KeyValueCompare(comp), clock(clock_) + config_t(clock_type& clock_, Compare const& comp) : KeyValueCompare(comp), clock(clock_) { } config_t(clock_type& clock_, Allocator const& alloc_) - : beast::detail::empty_base_optimization(alloc_) - , clock(clock_) + : beast::detail::empty_base_optimization(alloc_), clock(clock_) { } - config_t( - clock_type& clock_, - Compare const& comp, - Allocator const& alloc_) - : KeyValueCompare(comp) - , beast::detail::empty_base_optimization(alloc_) - , clock(clock_) + config_t(clock_type& clock_, Compare const& comp, Allocator const& alloc_) + : KeyValueCompare(comp), beast::detail::empty_base_optimization(alloc_), clock(clock_) { } config_t(config_t const& other) : KeyValueCompare(other.key_compare()) , beast::detail::empty_base_optimization( - ElementAllocatorTraits::select_on_container_copy_construction( - other.alloc())) + ElementAllocatorTraits::select_on_container_copy_construction(other.alloc())) , clock(other.clock) { } @@ -288,8 +245,7 @@ private: config_t(config_t&& other) : KeyValueCompare(std::move(other.key_compare())) - , beast::detail::empty_base_optimization( - std::move(other)) + , beast::detail::empty_base_optimization(std::move(other)) , clock(other.clock) { } @@ -349,15 +305,13 @@ private: ElementAllocator& alloc() { - return beast::detail::empty_base_optimization< - ElementAllocator>::member(); + return beast::detail::empty_base_optimization::member(); } ElementAllocator const& alloc() const { - return beast::detail::empty_base_optimization< - ElementAllocator>::member(); + return beast::detail::empty_base_optimization::member(); } std::reference_wrapper clock; @@ -382,13 +336,8 @@ private: }; std::unique_ptr p( - ElementAllocatorTraits::allocate(m_config.alloc(), 1), - Deleter(m_config.alloc())); - ElementAllocatorTraits::construct( - m_config.alloc(), - p.get(), - clock().now(), - std::forward(args)...); + ElementAllocatorTraits::allocate(m_config.alloc(), 1), Deleter(m_config.alloc())); + ElementAllocatorTraits::construct(m_config.alloc(), p.get(), clock().now(), std::forward(args)...); return p.release(); } @@ -396,8 +345,7 @@ private: delete_element(element const* p) { ElementAllocatorTraits::destroy(m_config.alloc(), p); - ElementAllocatorTraits::deallocate( - m_config.alloc(), const_cast(p), 1); + ElementAllocatorTraits::deallocate(m_config.alloc(), const_cast(p), 1); } void @@ -410,25 +358,19 @@ private: public: using key_compare = Compare; - using value_compare = - typename std::conditional::type; + using value_compare = typename std::conditional::type; using allocator_type = Allocator; using reference = value_type&; using const_reference = value_type const&; using pointer = typename std::allocator_traits::pointer; - using const_pointer = - typename std::allocator_traits::const_pointer; + using const_pointer = typename std::allocator_traits::const_pointer; // A set iterator (IsMap==false) is always const // because the elements of a set are immutable. - using iterator = beast::detail:: - aged_container_iterator; - using const_iterator = beast::detail:: - aged_container_iterator; - using reverse_iterator = beast::detail:: - aged_container_iterator; - using const_reverse_iterator = beast::detail:: - aged_container_iterator; + using iterator = beast::detail::aged_container_iterator; + using const_iterator = beast::detail::aged_container_iterator; + using reverse_iterator = beast::detail::aged_container_iterator; + using const_reverse_iterator = beast::detail::aged_container_iterator; //-------------------------------------------------------------------------- // @@ -444,15 +386,11 @@ public: public: // A set iterator (IsMap==false) is always const // because the elements of a set are immutable. - using iterator = beast::detail:: - aged_container_iterator; - using const_iterator = beast::detail:: - aged_container_iterator; - using reverse_iterator = beast::detail::aged_container_iterator< - !IsMap, - typename list_type::reverse_iterator>; - using const_reverse_iterator = beast::detail:: - aged_container_iterator; + using iterator = beast::detail::aged_container_iterator; + using const_iterator = beast::detail::aged_container_iterator; + using reverse_iterator = beast::detail::aged_container_iterator; + using const_reverse_iterator = + beast::detail::aged_container_iterator; iterator begin() @@ -529,23 +467,17 @@ public: iterator iterator_to(value_type& value) { - static_assert( - std::is_standard_layout::value, - "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return list.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } const_iterator iterator_to(value_type const& value) const { - static_assert( - std::is_standard_layout::value, - "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return list.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } private: @@ -574,61 +506,33 @@ public: aged_ordered_container(clock_type& clock, Allocator const& alloc); - aged_ordered_container( - clock_type& clock, - Compare const& comp, - Allocator const& alloc); + aged_ordered_container(clock_type& clock, Compare const& comp, Allocator const& alloc); template aged_ordered_container(InputIt first, InputIt last, clock_type& clock); template - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Compare const& comp); + aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Compare const& comp); template - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Allocator const& alloc); + aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc); template - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Compare const& comp, - Allocator const& alloc); + aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Compare const& comp, Allocator const& alloc); aged_ordered_container(aged_ordered_container const& other); - aged_ordered_container( - aged_ordered_container const& other, - Allocator const& alloc); + aged_ordered_container(aged_ordered_container const& other, Allocator const& alloc); aged_ordered_container(aged_ordered_container&& other); - aged_ordered_container( - aged_ordered_container&& other, - Allocator const& alloc); + aged_ordered_container(aged_ordered_container&& other, Allocator const& alloc); - aged_ordered_container( - std::initializer_list init, - clock_type& clock); + aged_ordered_container(std::initializer_list init, clock_type& clock); - aged_ordered_container( - std::initializer_list init, - clock_type& clock, - Compare const& comp); + aged_ordered_container(std::initializer_list init, clock_type& clock, Compare const& comp); - aged_ordered_container( - std::initializer_list init, - clock_type& clock, - Allocator const& alloc); + aged_ordered_container(std::initializer_list init, clock_type& clock, Allocator const& alloc); aged_ordered_container( std::initializer_list init, @@ -782,21 +686,17 @@ public: iterator iterator_to(value_type& value) { - static_assert( - std::is_standard_layout::value, "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return m_cont.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } const_iterator iterator_to(value_type const& value) const { - static_assert( - std::is_standard_layout::value, "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return m_cont.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } //-------------------------------------------------------------------------- @@ -835,35 +735,29 @@ public: // map, set template auto - insert(value_type const& value) -> - typename std::enable_if>::type; + insert(value_type const& value) -> typename std::enable_if>::type; // multimap, multiset template auto - insert(value_type const& value) -> - typename std::enable_if::type; + insert(value_type const& value) -> typename std::enable_if::type; // set template auto - insert(value_type&& value) -> typename std::enable_if< - !maybe_multi && !maybe_map, - std::pair>::type; + insert(value_type&& value) -> typename std::enable_if>::type; // multiset template auto - insert(value_type&& value) -> - typename std::enable_if::type; + insert(value_type&& value) -> typename std::enable_if::type; //--- // map, set template auto - insert(const_iterator hint, value_type const& value) -> - typename std::enable_if::type; + insert(const_iterator hint, value_type const& value) -> typename std::enable_if::type; // multimap, multiset template @@ -877,8 +771,7 @@ public: // map, set template auto - insert(const_iterator hint, value_type&& value) -> - typename std::enable_if::type; + insert(const_iterator hint, value_type&& value) -> typename std::enable_if::type; // multimap, multiset template @@ -893,10 +786,8 @@ public: template typename std::enable_if< maybe_map && std::is_constructible::value, - typename std:: - conditional>::type>:: - type - insert(P&& value) + typename std::conditional>::type>::type + insert(P&& value) { return emplace(std::forward

(value)); } @@ -905,10 +796,8 @@ public: template typename std::enable_if< maybe_map && std::is_constructible::value, - typename std:: - conditional>::type>:: - type - insert(const_iterator hint, P&& value) + typename std::conditional>::type>::type + insert(const_iterator hint, P&& value) { return emplace_hint(hint, std::forward

(value)); } @@ -930,14 +819,12 @@ public: // map, set template auto - emplace(Args&&... args) -> - typename std::enable_if>::type; + emplace(Args&&... args) -> typename std::enable_if>::type; // multiset, multimap template auto - emplace(Args&&... args) -> - typename std::enable_if::type; + emplace(Args&&... args) -> typename std::enable_if::type; // map, set template @@ -955,19 +842,13 @@ public: } // enable_if prevents erase (reverse_iterator pos) from compiling - template < - bool is_const, - class Iterator, - class = std::enable_if_t::value>> + template ::value>> beast::detail::aged_container_iterator erase(beast::detail::aged_container_iterator pos); // enable_if prevents erase (reverse_iterator first, reverse_iterator last) // from compiling - template < - bool is_const, - class Iterator, - class = std::enable_if_t::value>> + template ::value>> beast::detail::aged_container_iterator erase( beast::detail::aged_container_iterator first, @@ -983,10 +864,7 @@ public: //-------------------------------------------------------------------------- // enable_if prevents touch (reverse_iterator pos) from compiling - template < - bool is_const, - class Iterator, - class = std::enable_if_t::value>> + template ::value>> void touch(beast::detail::aged_container_iterator pos) { @@ -1024,8 +902,7 @@ public: const_iterator find(K const& k) const { - return const_iterator( - m_cont.find(k, std::cref(m_config.key_compare()))); + return const_iterator(m_cont.find(k, std::cref(m_config.key_compare()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1043,8 +920,7 @@ public: equal_range(K const& k) const { auto const r(m_cont.equal_range(k, std::cref(m_config.key_compare()))); - return std::make_pair( - const_iterator(r.first), const_iterator(r.second)); + return std::make_pair(const_iterator(r.first), const_iterator(r.second)); } // VFALCO TODO Respect is_transparent (c++14) @@ -1052,8 +928,7 @@ public: iterator lower_bound(K const& k) { - return iterator( - m_cont.lower_bound(k, std::cref(m_config.key_compare()))); + return iterator(m_cont.lower_bound(k, std::cref(m_config.key_compare()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1061,8 +936,7 @@ public: const_iterator lower_bound(K const& k) const { - return const_iterator( - m_cont.lower_bound(k, std::cref(m_config.key_compare()))); + return const_iterator(m_cont.lower_bound(k, std::cref(m_config.key_compare()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1070,8 +944,7 @@ public: iterator upper_bound(K const& k) { - return iterator( - m_cont.upper_bound(k, std::cref(m_config.key_compare()))); + return iterator(m_cont.upper_bound(k, std::cref(m_config.key_compare()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1079,8 +952,7 @@ public: const_iterator upper_bound(K const& k) const { - return const_iterator( - m_cont.upper_bound(k, std::cref(m_config.key_compare()))); + return const_iterator(m_cont.upper_bound(k, std::cref(m_config.key_compare()))); } //-------------------------------------------------------------------------- @@ -1112,139 +984,69 @@ public: // is only done on the key portion of the value type, ignoring // the mapped type. // - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator==(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const; + operator==( + aged_ordered_container const& + other) const; - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator!=(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const + operator!=( + aged_ordered_container const& + other) const { return !(this->operator==(other)); } - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator<(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const + operator<( + aged_ordered_container const& + other) const { value_compare const comp(value_comp()); - return std::lexicographical_compare( - cbegin(), cend(), other.cbegin(), other.cend(), comp); + return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend(), comp); } - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator<=(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const + operator<=( + aged_ordered_container const& + other) const { return !(other < *this); } - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator>(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const + operator>( + aged_ordered_container const& + other) const { return other < *this; } - template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> + template bool - operator>=(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const + operator>=( + aged_ordered_container const& + other) const { return !(*this < other); } private: // enable_if prevents erase (reverse_iterator pos, now) from compiling - template < - bool is_const, - class Iterator, - class = std::enable_if_t::value>> + template ::value>> void - touch( - beast::detail::aged_container_iterator pos, - typename clock_type::time_point const& now); + touch(beast::detail::aged_container_iterator pos, typename clock_type::time_point const& now); - template < - bool maybe_propagate = std::allocator_traits< - Allocator>::propagate_on_container_swap::value> + template ::propagate_on_container_swap::value> typename std::enable_if::type swap_data(aged_ordered_container& other) noexcept; - template < - bool maybe_propagate = std::allocator_traits< - Allocator>::propagate_on_container_swap::value> + template ::propagate_on_container_swap::value> typename std::enable_if::type swap_data(aged_ordered_container& other) noexcept; @@ -1255,152 +1057,88 @@ private: //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container(clock_type& clock) +template +aged_ordered_container::aged_ordered_container(clock_type& clock) : m_config(clock) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container(clock_type& clock, Compare const& comp) +template +aged_ordered_container::aged_ordered_container( + clock_type& clock, + Compare const& comp) : m_config(clock, comp), m_cont(comp) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container(clock_type& clock, Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - clock_type& clock, - Compare const& comp, - Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + clock_type& clock, + Compare const& comp, + Allocator const& alloc) : m_config(clock, comp, alloc), m_cont(comp) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template -aged_ordered_container:: - aged_ordered_container(InputIt first, InputIt last, clock_type& clock) +aged_ordered_container::aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock) : m_config(clock) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template -aged_ordered_container:: - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Compare const& comp) +aged_ordered_container::aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp) : m_config(clock, comp), m_cont(comp) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template -aged_ordered_container:: - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Allocator const& alloc) +aged_ordered_container::aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template -aged_ordered_container:: - aged_ordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Compare const& comp, - Allocator const& alloc) +aged_ordered_container::aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) : m_config(clock, comp, alloc), m_cont(comp) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container(aged_ordered_container const& other) +template +aged_ordered_container::aged_ordered_container( + aged_ordered_container const& other) : m_config(other.m_config) #if BOOST_VERSION >= 108000 , m_cont(other.m_cont.get_comp()) @@ -1411,18 +1149,10 @@ aged_ordered_container:: insert(other.cbegin(), other.cend()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - aged_ordered_container const& other, - Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + aged_ordered_container const& other, + Allocator const& alloc) : m_config(other.m_config, alloc) #if BOOST_VERSION >= 108000 , m_cont(other.m_cont.get_comp()) @@ -1433,33 +1163,18 @@ aged_ordered_container:: insert(other.cbegin(), other.cend()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container(aged_ordered_container&& other) +template +aged_ordered_container::aged_ordered_container( + aged_ordered_container&& other) : m_config(std::move(other.m_config)), m_cont(std::move(other.m_cont)) { chronological.list = std::move(other.chronological.list); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - aged_ordered_container&& other, - Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + aged_ordered_container&& other, + Allocator const& alloc) : m_config(std::move(other.m_config), alloc) #if BOOST_VERSION >= 108000 , m_cont(std::move(other.m_cont.get_comp())) @@ -1472,103 +1187,56 @@ aged_ordered_container:: other.clear(); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - std::initializer_list init, - clock_type& clock) +template +aged_ordered_container::aged_ordered_container( + std::initializer_list init, + clock_type& clock) : m_config(clock) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - std::initializer_list init, - clock_type& clock, - Compare const& comp) +template +aged_ordered_container::aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp) : m_config(clock, comp), m_cont(comp) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - std::initializer_list init, - clock_type& clock, - Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - aged_ordered_container( - std::initializer_list init, - clock_type& clock, - Compare const& comp, - Allocator const& alloc) +template +aged_ordered_container::aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) : m_config(clock, comp, alloc), m_cont(comp) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -aged_ordered_container:: - ~aged_ordered_container() +template +aged_ordered_container::~aged_ordered_container() { clear(); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template auto -aged_ordered_container:: -operator=(aged_ordered_container const& other) -> aged_ordered_container& +aged_ordered_container::operator=( + aged_ordered_container const& other) -> aged_ordered_container& { if (this != &other) { @@ -1579,17 +1247,10 @@ operator=(aged_ordered_container const& other) -> aged_ordered_container& return *this; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template auto -aged_ordered_container:: -operator=(aged_ordered_container&& other) -> aged_ordered_container& +aged_ordered_container::operator=(aged_ordered_container&& other) + -> aged_ordered_container& { clear(); this->m_config = std::move(other.m_config); @@ -1598,17 +1259,10 @@ operator=(aged_ordered_container&& other) -> aged_ordered_container& return *this; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template auto -aged_ordered_container:: -operator=(std::initializer_list init) -> aged_ordered_container& +aged_ordered_container::operator=( + std::initializer_list init) -> aged_ordered_container& { clear(); insert(init); @@ -1617,18 +1271,10 @@ operator=(std::initializer_list init) -> aged_ordered_container& //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::conditional::type& -aged_ordered_container::at( - K const& k) +aged_ordered_container::at(K const& k) { auto const iter(m_cont.find(k, std::cref(m_config.key_compare()))); if (iter == m_cont.end()) @@ -1636,18 +1282,10 @@ aged_ordered_container::at( return iter->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::conditional::type const& -aged_ordered_container::at( - K const& k) const +aged_ordered_container::at(K const& k) const { auto const iter(m_cont.find(k, std::cref(m_config.key_compare()))); if (iter == m_cont.end()) @@ -1655,28 +1293,16 @@ aged_ordered_container::at( return iter->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::conditional::type& -aged_ordered_container:: -operator[](Key const& key) +aged_ordered_container::operator[](Key const& key) { typename cont_type::insert_commit_data d; - auto const result( - m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); if (result.second) { - element* const p(new_element( - std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple())); + element* const p(new_element(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple())); m_cont.insert_commit(*p, d); chronological.list.push_back(*p); return p->value.second; @@ -1684,28 +1310,17 @@ operator[](Key const& key) return result.first->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::conditional::type& -aged_ordered_container:: -operator[](Key&& key) +aged_ordered_container::operator[](Key&& key) { typename cont_type::insert_commit_data d; - auto const result( - m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); if (result.second) { - element* const p(new_element( - std::piecewise_construct, - std::forward_as_tuple(std::move(key)), - std::forward_as_tuple())); + element* const p( + new_element(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::forward_as_tuple())); m_cont.insert_commit(*p, d); chronological.list.push_back(*p); return p->value.second; @@ -1715,43 +1330,25 @@ operator[](Key&& key) //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template void -aged_ordered_container:: - clear() +aged_ordered_container::clear() { - for (auto iter(chronological.list.begin()); - iter != chronological.list.end();) + for (auto iter(chronological.list.begin()); iter != chronological.list.end();) delete_element(&*iter++); chronological.list.clear(); m_cont.clear(); } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(value_type const& value) -> +aged_ordered_container::insert(value_type const& value) -> typename std::enable_if>::type { typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - extract(value), std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(extract(value), std::cref(m_config.key_compare()), d)); if (result.second) { element* const p(new_element(value)); @@ -1763,22 +1360,13 @@ aged_ordered_container:: } // multimap, multiset -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(value_type const& value) -> +aged_ordered_container::insert(value_type const& value) -> typename std::enable_if::type { - auto const before( - m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); + auto const before(m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); element* const p(new_element(value)); chronological.list.push_back(*p); auto const iter(m_cont.insert_before(before, *p)); @@ -1786,24 +1374,14 @@ aged_ordered_container:: } // set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(value_type&& value) -> - typename std:: - enable_if>::type +aged_ordered_container::insert(value_type&& value) -> + typename std::enable_if>::type { typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - extract(value), std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(extract(value), std::cref(m_config.key_compare()), d)); if (result.second) { element* const p(new_element(std::move(value))); @@ -1815,22 +1393,13 @@ aged_ordered_container:: } // multiset -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(value_type&& value) -> +aged_ordered_container::insert(value_type&& value) -> typename std::enable_if::type { - auto const before( - m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); + auto const before(m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); element* const p(new_element(std::move(value))); chronological.list.push_back(*p); auto const iter(m_cont.insert_before(before, *p)); @@ -1840,23 +1409,15 @@ aged_ordered_container:: //--- // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(const_iterator hint, value_type const& value) -> - typename std::enable_if::type +aged_ordered_container::insert( + const_iterator hint, + value_type const& value) -> typename std::enable_if::type { typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); if (result.second) { element* const p(new_element(value)); @@ -1868,23 +1429,15 @@ aged_ordered_container:: } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - insert(const_iterator hint, value_type&& value) -> - typename std::enable_if::type +aged_ordered_container::insert( + const_iterator hint, + value_type&& value) -> typename std::enable_if::type { typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); if (result.second) { element* const p(new_element(std::move(value))); @@ -1896,26 +1449,17 @@ aged_ordered_container:: } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - emplace(Args&&... args) -> +aged_ordered_container::emplace(Args&&... args) -> typename std::enable_if>::type { // VFALCO NOTE Its unfortunate that we need to // construct element here element* const p(new_element(std::forward(args)...)); typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - extract(p->value), std::cref(m_config.key_compare()), d)); + auto const result(m_cont.insert_check(extract(p->value), std::cref(m_config.key_compare()), d)); if (result.second) { auto const iter(m_cont.insert_commit(*p, d)); @@ -1927,52 +1471,32 @@ aged_ordered_container:: } // multiset, multimap -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - emplace(Args&&... args) -> +aged_ordered_container::emplace(Args&&... args) -> typename std::enable_if::type { element* const p(new_element(std::forward(args)...)); - auto const before(m_cont.upper_bound( - extract(p->value), std::cref(m_config.key_compare()))); + auto const before(m_cont.upper_bound(extract(p->value), std::cref(m_config.key_compare()))); chronological.list.push_back(*p); auto const iter(m_cont.insert_before(before, *p)); return iterator(iter); } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - emplace_hint(const_iterator hint, Args&&... args) -> - typename std::enable_if>::type +aged_ordered_container::emplace_hint( + const_iterator hint, + Args&&... args) -> typename std::enable_if>::type { // VFALCO NOTE Its unfortunate that we need to // construct element here element* const p(new_element(std::forward(args)...)); typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - hint.iterator(), - extract(p->value), - std::cref(m_config.key_compare()), - d)); + auto const result(m_cont.insert_check(hint.iterator(), extract(p->value), std::cref(m_config.key_compare()), d)); if (result.second) { auto const iter(m_cont.insert_commit(*p, d)); @@ -1983,58 +1507,33 @@ aged_ordered_container:: return std::make_pair(iterator(result.first), false); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template beast::detail::aged_container_iterator -aged_ordered_container:: - erase(beast::detail::aged_container_iterator pos) +aged_ordered_container::erase( + beast::detail::aged_container_iterator pos) { unlink_and_delete_element(&*((pos++).iterator())); - return beast::detail::aged_container_iterator( - pos.iterator()); + return beast::detail::aged_container_iterator(pos.iterator()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template beast::detail::aged_container_iterator -aged_ordered_container:: - erase( - beast::detail::aged_container_iterator first, - beast::detail::aged_container_iterator last) +aged_ordered_container::erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last) { for (; first != last;) unlink_and_delete_element(&*((first++).iterator())); - return beast::detail::aged_container_iterator( - first.iterator()); + return beast::detail::aged_container_iterator(first.iterator()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - erase(K const& k) -> size_type +aged_ordered_container::erase(K const& k) -> size_type { auto iter(m_cont.find(k, std::cref(m_config.key_compare()))); if (iter == m_cont.end()) @@ -2052,17 +1551,9 @@ aged_ordered_container:: return n; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template void -aged_ordered_container::swap( - aged_ordered_container& other) noexcept +aged_ordered_container::swap(aged_ordered_container& other) noexcept { swap_data(other); std::swap(chronological, other.chronological); @@ -2071,18 +1562,10 @@ aged_ordered_container::swap( //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template auto -aged_ordered_container:: - touch(K const& k) -> size_type +aged_ordered_container::touch(K const& k) -> size_type { auto const now(clock().now()); size_type n(0); @@ -2097,39 +1580,14 @@ aged_ordered_container:: //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -template < - bool OtherIsMulti, - bool OtherIsMap, - class OtherT, - class OtherDuration, - class OtherAllocator> +template +template bool -aged_ordered_container:: -operator==(aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator> const& other) const +aged_ordered_container::operator==( + aged_ordered_container const& other) + const { - using Other = aged_ordered_container< - OtherIsMulti, - OtherIsMap, - Key, - OtherT, - OtherDuration, - Compare, - OtherAllocator>; + using Other = aged_ordered_container; if (size() != other.size()) return false; std::equal_to eq; @@ -2138,28 +1596,19 @@ operator==(aged_ordered_container< cend(), other.cbegin(), other.cend(), - [&eq, &other]( - value_type const& lhs, typename Other::value_type const& rhs) { + [&eq, &other](value_type const& lhs, typename Other::value_type const& rhs) { return eq(extract(lhs), other.extract(rhs)); }); } //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template void -aged_ordered_container:: - touch( - beast::detail::aged_container_iterator pos, - typename clock_type::time_point const& now) +aged_ordered_container::touch( + beast::detail::aged_container_iterator pos, + typename clock_type::time_point const& now) { auto& e(*pos.iterator()); e.when = now; @@ -2167,36 +1616,22 @@ aged_ordered_container:: chronological.list.push_back(e); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::enable_if::type -aged_ordered_container:: - swap_data(aged_ordered_container& other) noexcept +aged_ordered_container::swap_data( + aged_ordered_container& other) noexcept { std::swap(m_config.key_compare(), other.m_config.key_compare()); std::swap(m_config.alloc(), other.m_config.alloc()); std::swap(m_config.clock, other.m_config.clock); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template template typename std::enable_if::type -aged_ordered_container:: - swap_data(aged_ordered_container& other) noexcept +aged_ordered_container::swap_data( + aged_ordered_container& other) noexcept { std::swap(m_config.key_compare(), other.m_config.key_compare()); std::swap(m_config.clock, other.m_config.clock); @@ -2206,54 +1641,20 @@ aged_ordered_container:: //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> -struct is_aged_container> : std::true_type +template +struct is_aged_container> + : std::true_type { explicit is_aged_container() = default; }; // Free functions -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Compare, - class Allocator> +template void swap( - beast::detail::aged_ordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Compare, - Allocator>& lhs, - beast::detail::aged_ordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Compare, - Allocator>& rhs) noexcept + beast::detail::aged_ordered_container& lhs, + beast::detail::aged_ordered_container& rhs) noexcept { lhs.swap(rhs); } @@ -2271,20 +1672,12 @@ template < class Period> std::size_t expire( - detail::aged_ordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Compare, - Allocator>& c, + detail::aged_ordered_container& c, std::chrono::duration const& age) { std::size_t n(0); auto const expired(c.clock().now() - age); - for (auto iter(c.chronological.cbegin()); - iter != c.chronological.cend() && iter.when() <= expired;) + for (auto iter(c.chronological.cbegin()); iter != c.chronological.cend() && iter.when() <= expired;) { iter = c.erase(iter); ++n; @@ -2293,5 +1686,3 @@ expire( } } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 23200ae007..a73ec107a7 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED -#define BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED +#pragma once #include #include @@ -82,8 +62,7 @@ template < class Clock = std::chrono::steady_clock, class Hash = std::hash, class KeyEqual = std::equal_to, - class Allocator = std::allocator< - typename std::conditional, Key>::type>> + class Allocator = std::allocator, Key>::type>> class aged_unordered_container { public: @@ -92,8 +71,7 @@ public: using duration = typename clock_type::duration; using key_type = Key; using mapped_type = T; - using value_type = - typename std::conditional, Key>::type; + using value_type = typename std::conditional, Key>::type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; @@ -111,10 +89,8 @@ private: // VFALCO TODO hoist to remove template argument dependencies struct element - : boost::intrusive::unordered_set_base_hook< - boost::intrusive::link_mode>, - boost::intrusive::list_base_hook< - boost::intrusive::link_mode> + : boost::intrusive::unordered_set_base_hook>, + boost::intrusive::list_base_hook> { // Stash types here so the iterator doesn't // need to see the container declaration. @@ -126,22 +102,18 @@ private: using time_point = typename aged_unordered_container::time_point; }; - element(time_point const& when_, value_type const& value_) - : value(value_), when(when_) + element(time_point const& when_, value_type const& value_) : value(value_), when(when_) { } - element(time_point const& when_, value_type&& value_) - : value(std::move(value_)), when(when_) + element(time_point const& when_, value_type&& value_) : value(std::move(value_)), when(when_) { } template < class... Args, - class = typename std::enable_if< - std::is_constructible::value>::type> - element(time_point const& when_, Args&&... args) - : value(std::forward(args)...), when(when_) + class = typename std::enable_if::value>::type> + element(time_point const& when_, Args&&... args) : value(std::forward(args)...), when(when_) { } @@ -231,8 +203,7 @@ private: } }; - using list_type = typename boost::intrusive:: - make_list>::type; + using list_type = typename boost::intrusive::make_list>::type; using cont_type = typename std::conditional< IsMulti, @@ -252,39 +223,33 @@ private: using bucket_type = typename cont_type::bucket_type; using bucket_traits = typename cont_type::bucket_traits; - using ElementAllocator = typename std::allocator_traits< - Allocator>::template rebind_alloc; + using ElementAllocator = typename std::allocator_traits::template rebind_alloc; using ElementAllocatorTraits = std::allocator_traits; - using BucketAllocator = typename std::allocator_traits< - Allocator>::template rebind_alloc; + using BucketAllocator = typename std::allocator_traits::template rebind_alloc; using BucketAllocatorTraits = std::allocator_traits; - class config_t - : private ValueHash, - private KeyValueEqual, - private beast::detail::empty_base_optimization + class config_t : private ValueHash, + private KeyValueEqual, + private beast::detail::empty_base_optimization { public: explicit config_t(clock_type& clock_) : clock(clock_) { } - config_t(clock_type& clock_, Hash const& hash) - : ValueHash(hash), clock(clock_) + config_t(clock_type& clock_, Hash const& hash) : ValueHash(hash), clock(clock_) { } - config_t(clock_type& clock_, KeyEqual const& keyEqual) - : KeyValueEqual(keyEqual), clock(clock_) + config_t(clock_type& clock_, KeyEqual const& keyEqual) : KeyValueEqual(keyEqual), clock(clock_) { } config_t(clock_type& clock_, Allocator const& alloc_) - : beast::detail::empty_base_optimization(alloc_) - , clock(clock_) + : beast::detail::empty_base_optimization(alloc_), clock(clock_) { } @@ -294,27 +259,16 @@ private: } config_t(clock_type& clock_, Hash const& hash, Allocator const& alloc_) - : ValueHash(hash) - , beast::detail::empty_base_optimization(alloc_) - , clock(clock_) + : ValueHash(hash), beast::detail::empty_base_optimization(alloc_), clock(clock_) { } - config_t( - clock_type& clock_, - KeyEqual const& keyEqual, - Allocator const& alloc_) - : KeyValueEqual(keyEqual) - , beast::detail::empty_base_optimization(alloc_) - , clock(clock_) + config_t(clock_type& clock_, KeyEqual const& keyEqual, Allocator const& alloc_) + : KeyValueEqual(keyEqual), beast::detail::empty_base_optimization(alloc_), clock(clock_) { } - config_t( - clock_type& clock_, - Hash const& hash, - KeyEqual const& keyEqual, - Allocator const& alloc_) + config_t(clock_type& clock_, Hash const& hash, KeyEqual const& keyEqual, Allocator const& alloc_) : ValueHash(hash) , KeyValueEqual(keyEqual) , beast::detail::empty_base_optimization(alloc_) @@ -326,8 +280,7 @@ private: : ValueHash(other.hash_function()) , KeyValueEqual(other.key_eq()) , beast::detail::empty_base_optimization( - ElementAllocatorTraits::select_on_container_copy_construction( - other.alloc())) + ElementAllocatorTraits::select_on_container_copy_construction(other.alloc())) , clock(other.clock) { } @@ -343,8 +296,7 @@ private: config_t(config_t&& other) : ValueHash(std::move(other.hash_function())) , KeyValueEqual(std::move(other.key_eq())) - , beast::detail::empty_base_optimization( - std::move(other.alloc())) + , beast::detail::empty_base_optimization(std::move(other.alloc())) , clock(other.clock) { } @@ -428,15 +380,13 @@ private: ElementAllocator& alloc() { - return beast::detail::empty_base_optimization< - ElementAllocator>::member(); + return beast::detail::empty_base_optimization::member(); } ElementAllocator const& alloc() const { - return beast::detail::empty_base_optimization< - ElementAllocator>::member(); + return beast::detail::empty_base_optimization::member(); } std::reference_wrapper clock; @@ -445,10 +395,8 @@ private: class Buckets { public: - using vec_type = std::vector< - bucket_type, - typename std::allocator_traits::template rebind_alloc< - bucket_type>>; + using vec_type = + std::vector::template rebind_alloc>; Buckets() : m_max_load_factor(1.f), m_vec() { @@ -527,8 +475,7 @@ private: void resize(size_type n, Container& c) { - size_type const suggested( - cont_type::suggested_upper_bucket_count(n)); + size_type const suggested(cont_type::suggested_upper_bucket_count(n)); rehash(suggested, c); } @@ -556,13 +503,8 @@ private: }; std::unique_ptr p( - ElementAllocatorTraits::allocate(m_config.alloc(), 1), - Deleter(m_config.alloc())); - ElementAllocatorTraits::construct( - m_config.alloc(), - p.get(), - clock().now(), - std::forward(args)...); + ElementAllocatorTraits::allocate(m_config.alloc(), 1), Deleter(m_config.alloc())); + ElementAllocatorTraits::construct(m_config.alloc(), p.get(), clock().now(), std::forward(args)...); return p.release(); } @@ -570,8 +512,7 @@ private: delete_element(element const* p) { ElementAllocatorTraits::destroy(m_config.alloc(), p); - ElementAllocatorTraits::deallocate( - m_config.alloc(), const_cast(p), 1); + ElementAllocatorTraits::deallocate(m_config.alloc(), const_cast(p), 1); } void @@ -589,20 +530,15 @@ public: using reference = value_type&; using const_reference = value_type const&; using pointer = typename std::allocator_traits::pointer; - using const_pointer = - typename std::allocator_traits::const_pointer; + using const_pointer = typename std::allocator_traits::const_pointer; // A set iterator (IsMap==false) is always const // because the elements of a set are immutable. - using iterator = beast::detail:: - aged_container_iterator; - using const_iterator = beast::detail:: - aged_container_iterator; + using iterator = beast::detail::aged_container_iterator; + using const_iterator = beast::detail::aged_container_iterator; - using local_iterator = beast::detail:: - aged_container_iterator; - using const_local_iterator = beast::detail:: - aged_container_iterator; + using local_iterator = beast::detail::aged_container_iterator; + using const_local_iterator = beast::detail::aged_container_iterator; //-------------------------------------------------------------------------- // @@ -618,15 +554,11 @@ public: public: // A set iterator (IsMap==false) is always const // because the elements of a set are immutable. - using iterator = beast::detail:: - aged_container_iterator; - using const_iterator = beast::detail:: - aged_container_iterator; - using reverse_iterator = beast::detail::aged_container_iterator< - !IsMap, - typename list_type::reverse_iterator>; - using const_reverse_iterator = beast::detail:: - aged_container_iterator; + using iterator = beast::detail::aged_container_iterator; + using const_iterator = beast::detail::aged_container_iterator; + using reverse_iterator = beast::detail::aged_container_iterator; + using const_reverse_iterator = + beast::detail::aged_container_iterator; iterator begin() @@ -703,23 +635,17 @@ public: iterator iterator_to(value_type& value) { - static_assert( - std::is_standard_layout::value, - "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return list.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } const_iterator iterator_to(value_type const& value) const { - static_assert( - std::is_standard_layout::value, - "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return list.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } private: @@ -750,66 +676,31 @@ public: aged_unordered_container(clock_type& clock, Allocator const& alloc); - aged_unordered_container( - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq); + aged_unordered_container(clock_type& clock, Hash const& hash, KeyEqual const& key_eq); - aged_unordered_container( - clock_type& clock, - Hash const& hash, - Allocator const& alloc); + aged_unordered_container(clock_type& clock, Hash const& hash, Allocator const& alloc); - aged_unordered_container( - clock_type& clock, - KeyEqual const& key_eq, - Allocator const& alloc); + aged_unordered_container(clock_type& clock, KeyEqual const& key_eq, Allocator const& alloc); - aged_unordered_container( - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq, - Allocator const& alloc); + aged_unordered_container(clock_type& clock, Hash const& hash, KeyEqual const& key_eq, Allocator const& alloc); template aged_unordered_container(InputIt first, InputIt last, clock_type& clock); template - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash); + aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Hash const& hash); template - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - KeyEqual const& key_eq); + aged_unordered_container(InputIt first, InputIt last, clock_type& clock, KeyEqual const& key_eq); template - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Allocator const& alloc); + aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc); template - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq); + aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Hash const& hash, KeyEqual const& key_eq); template - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash, - Allocator const& alloc); + aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Hash const& hash, Allocator const& alloc); template aged_unordered_container( @@ -830,34 +721,19 @@ public: aged_unordered_container(aged_unordered_container const& other); - aged_unordered_container( - aged_unordered_container const& other, - Allocator const& alloc); + aged_unordered_container(aged_unordered_container const& other, Allocator const& alloc); aged_unordered_container(aged_unordered_container&& other); - aged_unordered_container( - aged_unordered_container&& other, - Allocator const& alloc); + aged_unordered_container(aged_unordered_container&& other, Allocator const& alloc); - aged_unordered_container( - std::initializer_list init, - clock_type& clock); + aged_unordered_container(std::initializer_list init, clock_type& clock); - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Hash const& hash); + aged_unordered_container(std::initializer_list init, clock_type& clock, Hash const& hash); - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - KeyEqual const& key_eq); + aged_unordered_container(std::initializer_list init, clock_type& clock, KeyEqual const& key_eq); - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Allocator const& alloc); + aged_unordered_container(std::initializer_list init, clock_type& clock, Allocator const& alloc); aged_unordered_container( std::initializer_list init, @@ -994,21 +870,17 @@ public: iterator iterator_to(value_type& value) { - static_assert( - std::is_standard_layout::value, "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return m_cont.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } const_iterator iterator_to(value_type const& value) const { - static_assert( - std::is_standard_layout::value, "must be standard layout"); + static_assert(std::is_standard_layout::value, "must be standard layout"); return m_cont.iterator_to(*reinterpret_cast( - reinterpret_cast(&value) - - ((std::size_t)std::addressof(((element*)0)->member)))); + reinterpret_cast(&value) - ((std::size_t)std::addressof(((element*)0)->member)))); } //-------------------------------------------------------------------------- @@ -1047,27 +919,22 @@ public: // map, set template auto - insert(value_type const& value) -> - typename std::enable_if>::type; + insert(value_type const& value) -> typename std::enable_if>::type; // multimap, multiset template auto - insert(value_type const& value) -> - typename std::enable_if::type; + insert(value_type const& value) -> typename std::enable_if::type; // map, set template auto - insert(value_type&& value) -> typename std::enable_if< - !maybe_multi && !maybe_map, - std::pair>::type; + insert(value_type&& value) -> typename std::enable_if>::type; // multimap, multiset template auto - insert(value_type&& value) -> - typename std::enable_if::type; + insert(value_type&& value) -> typename std::enable_if::type; // map, set template @@ -1113,10 +980,8 @@ public: template typename std::enable_if< maybe_map && std::is_constructible::value, - typename std:: - conditional>::type>:: - type - insert(P&& value) + typename std::conditional>::type>::type + insert(P&& value) { return emplace(std::forward

(value)); } @@ -1125,10 +990,8 @@ public: template typename std::enable_if< maybe_map && std::is_constructible::value, - typename std:: - conditional>::type>:: - type - insert(const_iterator hint, P&& value) + typename std::conditional>::type>::type + insert(const_iterator hint, P&& value) { return emplace_hint(hint, std::forward

(value)); } @@ -1137,10 +1000,7 @@ public: void insert(InputIt first, InputIt last) { - insert( - first, - last, - typename std::iterator_traits::iterator_category()); + insert(first, last, typename std::iterator_traits::iterator_category()); } void @@ -1152,14 +1012,12 @@ public: // set, map template auto - emplace(Args&&... args) -> - typename std::enable_if>::type; + emplace(Args&&... args) -> typename std::enable_if>::type; // multiset, multimap template auto - emplace(Args&&... args) -> - typename std::enable_if::type; + emplace(Args&&... args) -> typename std::enable_if::type; // set, map template @@ -1216,10 +1074,7 @@ public: size_type count(K const& k) const { - return m_cont.count( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal())); + return m_cont.count(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal())); } // VFALCO TODO Respect is_transparent (c++14) @@ -1227,10 +1082,7 @@ public: iterator find(K const& k) { - return iterator(m_cont.find( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + return iterator(m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1238,10 +1090,8 @@ public: const_iterator find(K const& k) const { - return const_iterator(m_cont.find( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + return const_iterator( + m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); } // VFALCO TODO Respect is_transparent (c++14) @@ -1249,10 +1099,7 @@ public: std::pair equal_range(K const& k) { - auto const r(m_cont.equal_range( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + auto const r(m_cont.equal_range(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); return std::make_pair(iterator(r.first), iterator(r.second)); } @@ -1261,12 +1108,8 @@ public: std::pair equal_range(K const& k) const { - auto const r(m_cont.equal_range( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); - return std::make_pair( - const_iterator(r.first), const_iterator(r.second)); + auto const r(m_cont.equal_range(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); + return std::make_pair(const_iterator(r.first), const_iterator(r.second)); } //-------------------------------------------------------------------------- @@ -1485,14 +1328,12 @@ private: // map, set template auto - insert_unchecked(value_type const& value) -> - typename std::enable_if>::type; + insert_unchecked(value_type const& value) -> typename std::enable_if>::type; // multimap, multiset template auto - insert_unchecked(value_type const& value) -> - typename std::enable_if::type; + insert_unchecked(value_type const& value) -> typename std::enable_if::type; template void @@ -1521,9 +1362,7 @@ private: template void - touch( - beast::detail::aged_container_iterator pos, - typename clock_type::time_point const& now) + touch(beast::detail::aged_container_iterator pos, typename clock_type::time_point const& now) { auto& e(*pos.iterator()); e.when = now; @@ -1531,9 +1370,7 @@ private: chronological.list.push_back(e); } - template < - bool maybe_propagate = std::allocator_traits< - Allocator>::propagate_on_container_swap::value> + template ::propagate_on_container_swap::value> typename std::enable_if::type swap_data(aged_unordered_container& other) noexcept { @@ -1542,9 +1379,7 @@ private: std::swap(m_config.clock, other.m_config.clock); } - template < - bool maybe_propagate = std::allocator_traits< - Allocator>::propagate_on_container_swap::value> + template ::propagate_on_container_swap::value> typename std::enable_if::type swap_data(aged_unordered_container& other) noexcept { @@ -1560,920 +1395,336 @@ private: //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::aged_unordered_container(clock_type& clock) - : m_config(clock) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock) + : m_config(clock), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::aged_unordered_container(clock_type& clock, Hash const& hash) - : m_config(clock, hash) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + Hash const& hash) + : m_config(clock, hash), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container(clock_type& clock, KeyEqual const& key_eq) - : m_config(clock, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + KeyEqual const& key_eq) + : m_config(clock, key_eq), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container(clock_type& clock, Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) : m_config(clock, hash, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - clock_type& clock, - Hash const& hash, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + Hash const& hash, + Allocator const& alloc) : m_config(clock, hash, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - clock_type& clock, - KeyEqual const& key_eq, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, hash, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container(InputIt first, InputIt last, clock_type& clock) - : m_config(clock) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock) + : m_config(clock), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash) - : m_config(clock, hash) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash) + : m_config(clock, hash), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - KeyEqual const& key_eq) - : m_config(clock, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq) + : m_config(clock, key_eq), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Allocator const& alloc) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) : m_config(clock, hash, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash, - Allocator const& alloc) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) : m_config(clock, hash, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - KeyEqual const& key_eq, - Allocator const& alloc) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - InputIt first, - InputIt last, - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq, - Allocator const& alloc) +aged_unordered_container::aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, hash, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(first, last); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::aged_unordered_container(aged_unordered_container const& other) +template +aged_unordered_container::aged_unordered_container( + aged_unordered_container const& other) : m_config(other.m_config) , m_buck(m_config.alloc()) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(other.cbegin(), other.cend()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - aged_unordered_container const& other, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + aged_unordered_container const& other, + Allocator const& alloc) : m_config(other.m_config, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(other.cbegin(), other.cend()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::aged_unordered_container(aged_unordered_container&& other) - : m_config(std::move(other.m_config)) - , m_buck(std::move(other.m_buck)) - , m_cont(std::move(other.m_cont)) +template +aged_unordered_container::aged_unordered_container( + aged_unordered_container&& other) + : m_config(std::move(other.m_config)), m_buck(std::move(other.m_buck)), m_cont(std::move(other.m_cont)) { chronological.list = std::move(other.chronological.list); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - aged_unordered_container&& other, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + aged_unordered_container&& other, + Allocator const& alloc) : m_config(std::move(other.m_config), alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(other.cbegin(), other.cend()); other.clear(); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock) - : m_config(clock) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock) + : m_config(clock), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Hash const& hash) - : m_config(clock, hash) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash) + : m_config(clock, hash), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - KeyEqual const& key_eq) - : m_config(clock, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq) + : m_config(clock, key_eq), m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc) : m_config(clock, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) : m_config(clock, hash, key_eq) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Hash const& hash, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) : m_config(clock, hash, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - KeyEqual const& key_eq, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - aged_unordered_container( - std::initializer_list init, - clock_type& clock, - Hash const& hash, - KeyEqual const& key_eq, - Allocator const& alloc) +template +aged_unordered_container::aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) : m_config(clock, hash, key_eq, alloc) , m_buck(alloc) - , m_cont( - m_buck, - std::cref(m_config.value_hash()), - std::cref(m_config.key_value_equal())) + , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal())) { insert(init.begin(), init.end()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::~aged_unordered_container() +template +aged_unordered_container::~aged_unordered_container() { clear(); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::operator=(aged_unordered_container const& other) - -> aged_unordered_container& +aged_unordered_container::operator=( + aged_unordered_container const& other) -> aged_unordered_container& { if (this != &other) { @@ -2487,26 +1738,10 @@ aged_unordered_container< return *this; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::operator=(aged_unordered_container&& other) - -> aged_unordered_container& +aged_unordered_container::operator=( + aged_unordered_container&& other) -> aged_unordered_container& { size_type const n(other.size()); clear(); @@ -2518,26 +1753,10 @@ aged_unordered_container< return *this; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::operator=(std::initializer_list init) - -> aged_unordered_container& +aged_unordered_container::operator=( + std::initializer_list init) -> aged_unordered_container& { clear(); insert(init); @@ -2546,100 +1765,40 @@ aged_unordered_container< //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template typename std::conditional::type& -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::at(K const& k) +aged_unordered_container::at(K const& k) { - auto const iter(m_cont.find( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + auto const iter(m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); if (iter == m_cont.end()) throw std::out_of_range("key not found"); return iter->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template typename std::conditional::type const& -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::at(K const& k) const +aged_unordered_container::at(K const& k) const { - auto const iter(m_cont.find( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + auto const iter(m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); if (iter == m_cont.end()) throw std::out_of_range("key not found"); return iter->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template typename std::conditional::type& -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::operator[](Key const& key) +aged_unordered_container::operator[](Key const& key) { maybe_rehash(1); typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - key, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + auto const result( + m_cont.insert_check(key, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { - element* const p(new_element( - std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple())); + element* const p(new_element(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple())); m_cont.insert_commit(*p, d); chronological.list.push_back(*p); return p->value.second; @@ -2647,40 +1806,19 @@ aged_unordered_container< return result.first->value.second; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template typename std::conditional::type& -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::operator[](Key&& key) +aged_unordered_container::operator[](Key&& key) { maybe_rehash(1); typename cont_type::insert_commit_data d; - auto const result(m_cont.insert_check( - key, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + auto const result( + m_cont.insert_check(key, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { - element* const p(new_element( - std::piecewise_construct, - std::forward_as_tuple(std::move(key)), - std::forward_as_tuple())); + element* const p( + new_element(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::forward_as_tuple())); m_cont.insert_commit(*p, d); chronological.list.push_back(*p); return p->value.second; @@ -2690,28 +1828,11 @@ aged_unordered_container< //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template void -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::clear() +aged_unordered_container::clear() { - for (auto iter(chronological.list.begin()); - iter != chronological.list.end();) + for (auto iter(chronological.list.begin()); iter != chronological.list.end();) unlink_and_delete_element(&*iter++); chronological.list.clear(); m_cont.clear(); @@ -2719,35 +1840,16 @@ aged_unordered_container< } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert(value_type const& value) -> +aged_unordered_container::insert(value_type const& value) -> typename std::enable_if>::type { maybe_rehash(1); typename cont_type::insert_commit_data d; auto const result(m_cont.insert_check( - extract(value), - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + extract(value), std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { element* const p(new_element(value)); @@ -2759,26 +1861,10 @@ aged_unordered_container< } // multimap, multiset -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert(value_type const& value) -> +aged_unordered_container::insert(value_type const& value) -> typename std::enable_if::type { maybe_rehash(1); @@ -2789,36 +1875,16 @@ aged_unordered_container< } // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert(value_type&& value) -> - typename std:: - enable_if>::type +aged_unordered_container::insert(value_type&& value) -> + typename std::enable_if>::type { maybe_rehash(1); typename cont_type::insert_commit_data d; auto const result(m_cont.insert_check( - extract(value), - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + extract(value), std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { element* const p(new_element(std::move(value))); @@ -2830,26 +1896,10 @@ aged_unordered_container< } // multimap, multiset -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert(value_type&& value) -> +aged_unordered_container::insert(value_type&& value) -> typename std::enable_if::type { maybe_rehash(1); @@ -2861,26 +1911,10 @@ aged_unordered_container< #if 1 // Use insert() instead of insert_check() insert_commit() // set, map -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::emplace(Args&&... args) -> +aged_unordered_container::emplace(Args&&... args) -> typename std::enable_if>::type { maybe_rehash(1); @@ -2898,26 +1932,10 @@ aged_unordered_container< } #else // As original, use insert_check() / insert_commit () pair. // set, map -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::emplace(Args&&... args) -> +aged_unordered_container::emplace(Args&&... args) -> typename std::enable_if>::type { maybe_rehash(1); @@ -2926,10 +1944,7 @@ aged_unordered_container< element* const p(new_element(std::forward(args)...)); typename cont_type::insert_commit_data d; auto const result(m_cont.insert_check( - extract(p->value), - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + extract(p->value), std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { auto const iter(m_cont.insert_commit(*p, d)); @@ -2942,26 +1957,10 @@ aged_unordered_container< #endif // 0 // multiset, multimap -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::emplace(Args&&... args) -> +aged_unordered_container::emplace(Args&&... args) -> typename std::enable_if::type { maybe_rehash(1); @@ -2972,27 +1971,12 @@ aged_unordered_container< } // set, map -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::emplace_hint(const_iterator /*hint*/, Args&&... args) -> - typename std::enable_if>::type +aged_unordered_container::emplace_hint( + const_iterator /*hint*/, + Args&&... args) -> typename std::enable_if>::type { maybe_rehash(1); // VFALCO NOTE Its unfortunate that we need to @@ -3000,10 +1984,7 @@ aged_unordered_container< element* const p(new_element(std::forward(args)...)); typename cont_type::insert_commit_data d; auto const result(m_cont.insert_check( - extract(p->value), - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + extract(p->value), std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { auto const iter(m_cont.insert_commit(*p, d)); @@ -3014,89 +1995,35 @@ aged_unordered_container< return std::make_pair(iterator(result.first), false); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template beast::detail::aged_container_iterator -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::erase(beast::detail::aged_container_iterator - pos) +aged_unordered_container::erase( + beast::detail::aged_container_iterator pos) { unlink_and_delete_element(&*((pos++).iterator())); - return beast::detail::aged_container_iterator( - pos.iterator()); + return beast::detail::aged_container_iterator(pos.iterator()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template beast::detail::aged_container_iterator -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: - erase( - beast::detail::aged_container_iterator first, - beast::detail::aged_container_iterator last) +aged_unordered_container::erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last) { for (; first != last;) unlink_and_delete_element(&*((first++).iterator())); - return beast::detail::aged_container_iterator( - first.iterator()); + return beast::detail::aged_container_iterator(first.iterator()); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::erase(K const& k) -> size_type +aged_unordered_container::erase(K const& k) -> size_type { - auto iter(m_cont.find( - k, - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()))); + auto iter(m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()))); if (iter == m_cont.end()) return 0; size_type n(0); @@ -3112,51 +2039,20 @@ aged_unordered_container< return n; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template void -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::swap(aged_unordered_container& other) noexcept +aged_unordered_container::swap( + aged_unordered_container& other) noexcept { swap_data(other); std::swap(chronological, other.chronological); std::swap(m_cont, other.m_cont); } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::touch(K const& k) -> size_type +aged_unordered_container::touch(K const& k) -> size_type { auto const now(clock().now()); size_type n(0); @@ -3169,15 +2065,7 @@ aged_unordered_container< return n; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template < bool OtherIsMap, class OtherKey, @@ -3187,46 +2075,29 @@ template < class OtherAllocator, bool maybe_multi> typename std::enable_if::type -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: -operator==(aged_unordered_container< - false, - OtherIsMap, - OtherKey, - OtherT, - OtherDuration, - OtherHash, - KeyEqual, - OtherAllocator> const& other) const +aged_unordered_container::operator==( + aged_unordered_container< + false, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const { if (size() != other.size()) return false; - for (auto iter(cbegin()), last(cend()), olast(other.cend()); iter != last; - ++iter) + for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter) { - auto oiter(other.find(extract(*iter))); - if (oiter == olast) + auto otherIter(other.find(extract(*iter))); + if (otherIter == otherLast) return false; } return true; } -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template < bool OtherIsMap, class OtherKey, @@ -3236,24 +2107,16 @@ template < class OtherAllocator, bool maybe_multi> typename std::enable_if::type -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>:: -operator==(aged_unordered_container< - true, - OtherIsMap, - OtherKey, - OtherT, - OtherDuration, - OtherHash, - KeyEqual, - OtherAllocator> const& other) const +aged_unordered_container::operator==( + aged_unordered_container< + true, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const { if (size() != other.size()) return false; @@ -3263,8 +2126,7 @@ operator==(aged_unordered_container< auto const eq(equal_range(k)); auto const oeq(other.equal_range(k)); #if BEAST_NO_CXX14_IS_PERMUTATION - if (std::distance(eq.first, eq.second) != - std::distance(oeq.first, oeq.second) || + if (std::distance(eq.first, eq.second) != std::distance(oeq.first, oeq.second) || !std::is_permutation(eq.first, eq.second, oeq.first)) return false; #else @@ -3279,34 +2141,15 @@ operator==(aged_unordered_container< //------------------------------------------------------------------------------ // map, set -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert_unchecked(value_type const& value) -> - typename std::enable_if>::type +aged_unordered_container::insert_unchecked( + value_type const& value) -> typename std::enable_if>::type { typename cont_type::insert_commit_data d; auto const result(m_cont.insert_check( - extract(value), - std::cref(m_config.hash_function()), - std::cref(m_config.key_value_equal()), - d)); + extract(value), std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d)); if (result.second) { element* const p(new_element(value)); @@ -3318,27 +2161,11 @@ aged_unordered_container< } // multimap, multiset -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template template auto -aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>::insert_unchecked(value_type const& value) -> - typename std::enable_if::type +aged_unordered_container::insert_unchecked( + value_type const& value) -> typename std::enable_if::type { element* const p(new_element(value)); chronological.list.push_back(*p); @@ -3352,59 +2179,20 @@ aged_unordered_container< //------------------------------------------------------------------------------ -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> -struct is_aged_container> : std::true_type +template +struct is_aged_container< + beast::detail::aged_unordered_container> : std::true_type { explicit is_aged_container() = default; }; // Free functions -template < - bool IsMulti, - bool IsMap, - class Key, - class T, - class Clock, - class Hash, - class KeyEqual, - class Allocator> +template void swap( - beast::detail::aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>& lhs, - beast::detail::aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>& rhs) noexcept + beast::detail::aged_unordered_container& lhs, + beast::detail::aged_unordered_container& rhs) noexcept { lhs.swap(rhs); } @@ -3423,21 +2211,12 @@ template < class Period> std::size_t expire( - beast::detail::aged_unordered_container< - IsMulti, - IsMap, - Key, - T, - Clock, - Hash, - KeyEqual, - Allocator>& c, + beast::detail::aged_unordered_container& c, std::chrono::duration const& age) noexcept { std::size_t n(0); auto const expired(c.clock().now() - age); - for (auto iter(c.chronological.cbegin()); - iter != c.chronological.cend() && iter.when() <= expired;) + for (auto iter(c.chronological.cbegin()); iter != c.chronological.cend() && iter.when() <= expired;) { iter = c.erase(iter); ++n; @@ -3446,5 +2225,3 @@ expire( } } // namespace beast - -#endif diff --git a/include/xrpl/beast/container/detail/empty_base_optimization.h b/include/xrpl/beast/container/detail/empty_base_optimization.h index 350046d594..21a9d13ce8 100644 --- a/include/xrpl/beast/container/detail/empty_base_optimization.h +++ b/include/xrpl/beast/container/detail/empty_base_optimization.h @@ -1,14 +1,10 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // -#ifndef BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED -#define BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED +#pragma once #include @@ -20,16 +16,11 @@ namespace detail { template struct is_empty_base_optimization_derived - : std::integral_constant< - bool, - std::is_empty::value && !boost::is_final::value> + : std::integral_constant::value && !boost::is_final::value> { }; -template < - class T, - int UniqueID = 0, - bool isDerived = is_empty_base_optimization_derived::value> +template ::value> class empty_base_optimization : private T { public: @@ -97,5 +88,3 @@ public: } // namespace detail } // namespace beast - -#endif diff --git a/include/xrpl/beast/core/CurrentThreadName.h b/include/xrpl/beast/core/CurrentThreadName.h index 5adbb21088..8e99ee90da 100644 --- a/include/xrpl/beast/core/CurrentThreadName.h +++ b/include/xrpl/beast/core/CurrentThreadName.h @@ -1,28 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco +// Portions of this file are from JUCE (http://www.juce.com). +// Copyright (c) 2013 - Raw Material Software Ltd. +// Please visit http://www.juce.com - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED -#define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED +#include #include #include @@ -35,6 +17,29 @@ namespace beast { void setCurrentThreadName(std::string_view newThreadName); +#if BOOST_OS_LINUX + +// On Linux, thread names are limited to 16 bytes including the null terminator. +// Maximum number of characters is therefore 15. +constexpr std::size_t maxThreadNameLength = 15; + +/** Sets the name of the caller thread with compile-time size checking. + @tparam N The size of the string literal including null terminator + @param newThreadName A string literal to set as the thread name + + This template overload enforces that thread names are at most 16 characters + (including null terminator) at compile time, matching Linux's limit. +*/ +template +void +setCurrentThreadName(char const (&newThreadName)[N]) +{ + static_assert(N <= maxThreadNameLength + 1, "Thread name cannot exceed 15 characters"); + + setCurrentThreadName(std::string_view(newThreadName, N - 1)); +} +#endif + /** Returns the name of the caller thread. The name returned is the name as set by a call to setCurrentThreadName(). @@ -47,5 +52,3 @@ std::string getCurrentThreadName(); } // namespace beast - -#endif diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h index 5551e1f2dc..a7c135f23f 100644 --- a/include/xrpl/beast/core/LexicalCast.h +++ b/include/xrpl/beast/core/LexicalCast.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED -#define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED +#pragma once #include @@ -37,7 +17,7 @@ namespace beast { namespace detail { -// These specializatons get called by the non-member functions to do the work +// These specializations get called by the non-member functions to do the work template struct LexicalCast; @@ -59,8 +39,7 @@ struct LexicalCast std::enable_if_t, bool> operator()(std::string& out, Enumeration in) { - out = std::to_string( - static_cast>(in)); + out = std::to_string(static_cast>(in)); return true; } }; @@ -71,14 +50,10 @@ struct LexicalCast { explicit LexicalCast() = default; - static_assert( - std::is_integral_v, - "beast::LexicalCast can only be used with integral types"); + static_assert(std::is_integral_v, "beast::LexicalCast can only be used with integral types"); template - std::enable_if_t< - std::is_integral_v && !std::is_same_v, - bool> + std::enable_if_t && !std::is_same_v, bool> operator()(Integral& out, std::string_view in) const { auto first = in.data(); @@ -98,10 +73,9 @@ struct LexicalCast std::string result; // Convert the input to lowercase - std::transform( - in.begin(), in.end(), std::back_inserter(result), [](auto c) { - return std::tolower(static_cast(c)); - }); + std::transform(in.begin(), in.end(), std::back_inserter(result), [](auto c) { + return std::tolower(static_cast(c)); + }); if (result == "1" || result == "true") { @@ -159,8 +133,7 @@ struct LexicalCast bool operator()(Out& out, char const* in) const { - XRPL_ASSERT( - in, "beast::detail::LexicalCast(char const*) : non-null input"); + XRPL_ASSERT(in, "beast::detail::LexicalCast(char const*) : non-null input"); return LexicalCast()(out, in); } }; @@ -234,5 +207,3 @@ lexicalCast(In in, Out defaultValue = Out()) } } // namespace beast - -#endif diff --git a/include/xrpl/beast/core/List.h b/include/xrpl/beast/core/List.h index d95f92d1c8..75c981ea1b 100644 --- a/include/xrpl/beast/core/List.h +++ b/include/xrpl/beast/core/List.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INTRUSIVE_LIST_H_INCLUDED -#define BEAST_INTRUSIVE_LIST_H_INCLUDED +#pragma once #include @@ -74,8 +54,7 @@ class ListIterator { public: using iterator_category = std::bidirectional_iterator_tag; - using value_type = - typename beast::detail::CopyConst::type; + using value_type = typename beast::detail::CopyConst::type; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; @@ -594,5 +573,3 @@ private: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/core/LockFreeStack.h b/include/xrpl/beast/core/LockFreeStack.h index 107564415c..bb32698dd8 100644 --- a/include/xrpl/beast/core/LockFreeStack.h +++ b/include/xrpl/beast/core/LockFreeStack.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INTRUSIVE_LOCKFREESTACK_H_INCLUDED -#define BEAST_INTRUSIVE_LOCKFREESTACK_H_INCLUDED +#pragma once #include #include @@ -33,21 +13,16 @@ class LockFreeStackIterator { protected: using Node = typename Container::Node; - using NodePtr = - typename std::conditional::type; + using NodePtr = typename std::conditional::type; public: using iterator_category = std::forward_iterator_tag; using value_type = typename Container::value_type; using difference_type = typename Container::difference_type; - using pointer = typename std::conditional< - IsConst, - typename Container::const_pointer, - typename Container::pointer>::type; - using reference = typename std::conditional< - IsConst, - typename Container::const_reference, - typename Container::reference>::type; + using pointer = + typename std::conditional::type; + using reference = + typename std::conditional::type; LockFreeStackIterator() : m_node() { @@ -58,9 +33,7 @@ public: } template - explicit LockFreeStackIterator( - LockFreeStackIterator const& other) - : m_node(other.m_node) + explicit LockFreeStackIterator(LockFreeStackIterator const& other) : m_node(other.m_node) { } @@ -179,8 +152,7 @@ public: using size_type = std::size_t; using difference_type = std::ptrdiff_t; using iterator = LockFreeStackIterator, false>; - using const_iterator = - LockFreeStackIterator, true>; + using const_iterator = LockFreeStackIterator, true>; LockFreeStack() : m_end(nullptr), m_head(&m_end) { @@ -218,11 +190,7 @@ public: { first = (old_head == &m_end); node->m_next = old_head; - } while (!m_head.compare_exchange_strong( - old_head, - node, - std::memory_order_release, - std::memory_order_relaxed)); + } while (!m_head.compare_exchange_strong(old_head, node, std::memory_order_release, std::memory_order_relaxed)); return first; } @@ -245,11 +213,7 @@ public: if (node == &m_end) return nullptr; new_head = node->m_next.load(); - } while (!m_head.compare_exchange_strong( - node, - new_head, - std::memory_order_release, - std::memory_order_relaxed)); + } while (!m_head.compare_exchange_strong(node, new_head, std::memory_order_release, std::memory_order_relaxed)); return static_cast(node); } @@ -303,5 +267,3 @@ private: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/core/SemanticVersion.h b/include/xrpl/beast/core/SemanticVersion.h index 5fe216f1ab..1d3525de25 100644 --- a/include/xrpl/beast/core/SemanticVersion.h +++ b/include/xrpl/beast/core/SemanticVersion.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED -#define BEAST_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED +#pragma once #include #include @@ -114,5 +94,3 @@ operator<(SemanticVersion const& lhs, SemanticVersion const& rhs) } } // namespace beast - -#endif diff --git a/include/xrpl/beast/hash/hash_append.h b/include/xrpl/beast/hash/hash_append.h index a4ffeaf30c..e4d646e532 100644 --- a/include/xrpl/beast/hash/hash_append.h +++ b/include/xrpl/beast/hash/hash_append.h @@ -1,25 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Howard Hinnant , - Vinnie Falco #include @@ -47,8 +26,7 @@ template inline void reverse_bytes(T& t) { - unsigned char* bytes = static_cast( - std::memmove(std::addressof(t), std::addressof(t), sizeof(T))); + unsigned char* bytes = static_cast(std::memmove(std::addressof(t), std::addressof(t), sizeof(T))); for (unsigned i = 0; i < sizeof(T) / 2; ++i) std::swap(bytes[i], bytes[sizeof(T) - 1 - i]); } @@ -73,11 +51,7 @@ template inline void maybe_reverse_bytes(T& t, Hasher&) { - maybe_reverse_bytes( - t, - std::integral_constant< - bool, - Hasher::endian != boost::endian::order::native>{}); + maybe_reverse_bytes(t, std::integral_constant{}); } } // namespace detail @@ -91,10 +65,8 @@ maybe_reverse_bytes(T& t, Hasher&) template struct is_uniquely_represented - : public std::integral_constant< - bool, - std::is_integral::value || std::is_enum::value || - std::is_pointer::value> + : public std:: + integral_constant::value || std::is_enum::value || std::is_pointer::value> { explicit is_uniquely_represented() = default; }; @@ -112,8 +84,7 @@ struct is_uniquely_represented : public is_uniquely_represented }; template -struct is_uniquely_represented - : public is_uniquely_represented +struct is_uniquely_represented : public is_uniquely_represented { explicit is_uniquely_represented() = default; }; @@ -124,8 +95,7 @@ template struct is_uniquely_represented> : public std::integral_constant< bool, - is_uniquely_represented::value && - is_uniquely_represented::value && + is_uniquely_represented::value && is_uniquely_represented::value && sizeof(T) + sizeof(U) == sizeof(std::pair)> { explicit is_uniquely_represented() = default; @@ -137,8 +107,7 @@ template struct is_uniquely_represented> : public std::integral_constant< bool, - std::conjunction_v...> && - sizeof(std::tuple) == (sizeof(T) + ...)> + std::conjunction_v...> && sizeof(std::tuple) == (sizeof(T) + ...)> { explicit is_uniquely_represented() = default; }; @@ -155,10 +124,8 @@ struct is_uniquely_represented : public is_uniquely_represented template struct is_uniquely_represented> - : public std::integral_constant< - bool, - is_uniquely_represented::value && - sizeof(T) * N == sizeof(std::array)> + : public std:: + integral_constant::value && sizeof(T) * N == sizeof(std::array)> { explicit is_uniquely_represented() = default; }; @@ -178,12 +145,10 @@ struct is_uniquely_represented> */ /** @{ */ template -struct is_contiguously_hashable - : public std::integral_constant< - bool, - is_uniquely_represented::value && - (sizeof(T) == 1 || - HashAlgorithm::endian == boost::endian::order::native)> +struct is_contiguously_hashable : public std::integral_constant< + bool, + is_uniquely_represented::value && + (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)> { explicit is_contiguously_hashable() = default; }; @@ -193,8 +158,7 @@ struct is_contiguously_hashable : public std::integral_constant< bool, is_uniquely_represented::value && - (sizeof(T) == 1 || - HashAlgorithm::endian == boost::endian::order::native)> + (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)> { explicit is_contiguously_hashable() = default; }; @@ -223,7 +187,7 @@ struct is_contiguously_hashable Throws: Never Effect: - Returns the reslting hash of all the input data. + Returns the resulting hash of all the input data. */ /** @{ */ @@ -239,8 +203,7 @@ hash_append(Hasher& h, T const& t) noexcept template inline std::enable_if_t< !is_contiguously_hashable::value && - (std::is_integral::value || std::is_pointer::value || - std::is_enum::value)> + (std::is_integral::value || std::is_pointer::value || std::is_enum::value)> hash_append(Hasher& h, T t) noexcept { detail::reverse_bytes(t); @@ -274,15 +237,11 @@ hash_append(Hasher& h, T (&a)[N]) noexcept; template std::enable_if_t::value> -hash_append( - Hasher& h, - std::basic_string const& s) noexcept; +hash_append(Hasher& h, std::basic_string const& s) noexcept; template std::enable_if_t::value> -hash_append( - Hasher& h, - std::basic_string const& s) noexcept; +hash_append(Hasher& h, std::basic_string const& s) noexcept; template std::enable_if_t, Hasher>::value> @@ -314,14 +273,10 @@ hash_append(Hasher& h, std::unordered_set const& s); template std::enable_if_t::value> -hash_append( - Hasher& h, - boost::container::flat_set const& v) noexcept; +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept; template std::enable_if_t::value> -hash_append( - Hasher& h, - boost::container::flat_set const& v) noexcept; +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept; template void hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept; @@ -340,9 +295,7 @@ hash_append(Hasher& h, T (&a)[N]) noexcept template inline std::enable_if_t::value> -hash_append( - Hasher& h, - std::basic_string const& s) noexcept +hash_append(Hasher& h, std::basic_string const& s) noexcept { for (auto c : s) hash_append(h, c); @@ -351,9 +304,7 @@ hash_append( template inline std::enable_if_t::value> -hash_append( - Hasher& h, - std::basic_string const& s) noexcept +hash_append(Hasher& h, std::basic_string const& s) noexcept { h(s.data(), s.size() * sizeof(CharT)); hash_append(h, s.size()); @@ -362,8 +313,7 @@ hash_append( // pair template -inline std::enable_if_t< - !is_contiguously_hashable, Hasher>::value> +inline std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::pair const& p) noexcept { hash_append(h, p.first, p.second); @@ -400,18 +350,14 @@ hash_append(Hasher& h, std::array const& a) noexcept template std::enable_if_t::value> -hash_append( - Hasher& h, - boost::container::flat_set const& v) noexcept +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept { for (auto const& t : v) hash_append(h, t); } template std::enable_if_t::value> -hash_append( - Hasher& h, - boost::container::flat_set const& v) noexcept +hash_append(Hasher& h, boost::container::flat_set const& v) noexcept { h(&(v.begin()), v.size() * sizeof(Key)); } @@ -434,10 +380,7 @@ hash_one(Hasher& h, T const& t) noexcept template inline void -tuple_hash( - Hasher& h, - std::tuple const& t, - std::index_sequence) noexcept +tuple_hash(Hasher& h, std::tuple const& t, std::index_sequence) noexcept { for_each_item(hash_one(h, std::get(t))...); } @@ -445,8 +388,7 @@ tuple_hash( } // namespace detail template -inline std::enable_if_t< - !is_contiguously_hashable, Hasher>::value> +inline std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::tuple const& t) noexcept { detail::tuple_hash(h, t, std::index_sequence_for{}); @@ -472,9 +414,7 @@ hash_append(Hasher& h, std::chrono::duration const& d) noexcept template inline void -hash_append( - Hasher& h, - std::chrono::time_point const& tp) noexcept +hash_append(Hasher& h, std::chrono::time_point const& tp) noexcept { hash_append(h, tp.time_since_epoch()); } @@ -499,5 +439,3 @@ hash_append(HashAlgorithm& h, std::error_code const& ec) } } // namespace beast - -#endif diff --git a/include/xrpl/beast/hash/uhash.h b/include/xrpl/beast/hash/uhash.h index ac4ba7256d..4f66f058a8 100644 --- a/include/xrpl/beast/hash/uhash.h +++ b/include/xrpl/beast/hash/uhash.h @@ -1,25 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Howard Hinnant , - Vinnie Falco #include @@ -45,5 +24,3 @@ struct uhash }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h index 9cd343f544..473907ea89 100644 --- a/include/xrpl/beast/hash/xxhasher.h +++ b/include/xrpl/beast/hash/xxhasher.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_HASH_XXHASHER_H_INCLUDED -#define BEAST_HASH_XXHASHER_H_INCLUDED +#pragma once #include @@ -68,8 +48,7 @@ private: { std::memcpy(writeBuffer_.data(), data, len); writeBuffer_ = writeBuffer_.subspan(len); - readBuffer_ = std::span{ - std::begin(buffer_), buffer_.size() - writeBuffer_.size()}; + readBuffer_ = std::span{std::begin(buffer_), buffer_.size() - writeBuffer_.size()}; } } @@ -117,8 +96,7 @@ private: { if (seed_.has_value()) { - return XXH3_64bits_withSeed( - readBuffer_.data(), readBuffer_.size(), *seed_); + return XXH3_64bits_withSeed(readBuffer_.data(), readBuffer_.size(), *seed_); } else { @@ -147,17 +125,13 @@ public: } } - template < - class Seed, - std::enable_if_t::value>* = nullptr> + template ::value>* = nullptr> explicit xxhasher(Seed seed) : seed_(seed) { resetBuffers(); } - template < - class Seed, - std::enable_if_t::value>* = nullptr> + template ::value>* = nullptr> xxhasher(Seed seed, Seed) : seed_(seed) { resetBuffers(); @@ -177,5 +151,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Collector.h b/include/xrpl/beast/insight/Collector.h index eab2bd7d70..89aa8c1cb5 100644 --- a/include/xrpl/beast/insight/Collector.h +++ b/include/xrpl/beast/insight/Collector.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_COLLECTOR_H_INCLUDED -#define BEAST_INSIGHT_COLLECTOR_H_INCLUDED +#pragma once #include #include @@ -139,5 +119,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Counter.h b/include/xrpl/beast/insight/Counter.h index 3f3a251de8..f6722c4e03 100644 --- a/include/xrpl/beast/insight/Counter.h +++ b/include/xrpl/beast/insight/Counter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_COUNTER_H_INCLUDED -#define BEAST_INSIGHT_COUNTER_H_INCLUDED +#pragma once #include @@ -113,5 +93,3 @@ private: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/CounterImpl.h b/include/xrpl/beast/insight/CounterImpl.h index f369b32f77..199315dcb8 100644 --- a/include/xrpl/beast/insight/CounterImpl.h +++ b/include/xrpl/beast/insight/CounterImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_COUNTERIMPL_H_INCLUDED -#define BEAST_INSIGHT_COUNTERIMPL_H_INCLUDED +#pragma once #include #include @@ -40,5 +20,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Event.h b/include/xrpl/beast/insight/Event.h index 407dd233e9..bc0c0dd403 100644 --- a/include/xrpl/beast/insight/Event.h +++ b/include/xrpl/beast/insight/Event.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_EVENT_H_INCLUDED -#define BEAST_INSIGHT_EVENT_H_INCLUDED +#pragma once #include @@ -80,5 +60,3 @@ private: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/EventImpl.h b/include/xrpl/beast/insight/EventImpl.h index 5104d05c46..abd9741511 100644 --- a/include/xrpl/beast/insight/EventImpl.h +++ b/include/xrpl/beast/insight/EventImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_EVENTIMPL_H_INCLUDED -#define BEAST_INSIGHT_EVENTIMPL_H_INCLUDED +#pragma once #include #include @@ -40,5 +20,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Gauge.h b/include/xrpl/beast/insight/Gauge.h index b1e8bedfac..f2a88deda2 100644 --- a/include/xrpl/beast/insight/Gauge.h +++ b/include/xrpl/beast/insight/Gauge.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_GAUGE_H_INCLUDED -#define BEAST_INSIGHT_GAUGE_H_INCLUDED +#pragma once #include @@ -143,5 +123,3 @@ private: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/GaugeImpl.h b/include/xrpl/beast/insight/GaugeImpl.h index 78609fd432..29afbe6a4d 100644 --- a/include/xrpl/beast/insight/GaugeImpl.h +++ b/include/xrpl/beast/insight/GaugeImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_GAUGEIMPL_H_INCLUDED -#define BEAST_INSIGHT_GAUGEIMPL_H_INCLUDED +#pragma once #include #include @@ -43,5 +23,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Group.h b/include/xrpl/beast/insight/Group.h index f11b1397c8..c85fd1bfb6 100644 --- a/include/xrpl/beast/insight/Group.h +++ b/include/xrpl/beast/insight/Group.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_GROUP_H_INCLUDED -#define BEAST_INSIGHT_GROUP_H_INCLUDED +#pragma once #include @@ -41,5 +21,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Groups.h b/include/xrpl/beast/insight/Groups.h index 456deb7907..8ac93454d3 100644 --- a/include/xrpl/beast/insight/Groups.h +++ b/include/xrpl/beast/insight/Groups.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_GROUPS_H_INCLUDED -#define BEAST_INSIGHT_GROUPS_H_INCLUDED +#pragma once #include #include @@ -54,5 +34,3 @@ make_Groups(Collector::ptr const& collector); } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Hook.h b/include/xrpl/beast/insight/Hook.h index affa42bb82..ea511862d9 100644 --- a/include/xrpl/beast/insight/Hook.h +++ b/include/xrpl/beast/insight/Hook.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_HOOK_H_INCLUDED -#define BEAST_INSIGHT_HOOK_H_INCLUDED +#pragma once #include @@ -59,5 +39,3 @@ private: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/HookImpl.h b/include/xrpl/beast/insight/HookImpl.h index aca1f847fa..18208b554a 100644 --- a/include/xrpl/beast/insight/HookImpl.h +++ b/include/xrpl/beast/insight/HookImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_HOOKIMPL_H_INCLUDED -#define BEAST_INSIGHT_HOOKIMPL_H_INCLUDED +#pragma once #include #include @@ -36,5 +16,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/Insight.h b/include/xrpl/beast/insight/Insight.h index 1c2c1375a2..bf3743cfd8 100644 --- a/include/xrpl/beast/insight/Insight.h +++ b/include/xrpl/beast/insight/Insight.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_H_INCLUDED -#define BEAST_INSIGHT_H_INCLUDED +#pragma once #include #include @@ -33,5 +13,3 @@ #include #include #include - -#endif diff --git a/include/xrpl/beast/insight/Meter.h b/include/xrpl/beast/insight/Meter.h index 7ef71988a1..193a1f1003 100644 --- a/include/xrpl/beast/insight/Meter.h +++ b/include/xrpl/beast/insight/Meter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_METER_H_INCLUDED -#define BEAST_INSIGHT_METER_H_INCLUDED +#pragma once #include @@ -98,5 +78,3 @@ private: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/MeterImpl.h b/include/xrpl/beast/insight/MeterImpl.h index 846dbe19a8..22efdbe647 100644 --- a/include/xrpl/beast/insight/MeterImpl.h +++ b/include/xrpl/beast/insight/MeterImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_METERIMPL_H_INCLUDED -#define BEAST_INSIGHT_METERIMPL_H_INCLUDED +#pragma once #include #include @@ -40,5 +20,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/NullCollector.h b/include/xrpl/beast/insight/NullCollector.h index 4379c3ceb9..1d16a11e17 100644 --- a/include/xrpl/beast/insight/NullCollector.h +++ b/include/xrpl/beast/insight/NullCollector.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED -#define BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED +#pragma once #include @@ -37,5 +17,3 @@ public: } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/insight/StatsDCollector.h b/include/xrpl/beast/insight/StatsDCollector.h index fb47eeb7fc..ab09967483 100644 --- a/include/xrpl/beast/insight/StatsDCollector.h +++ b/include/xrpl/beast/insight/StatsDCollector.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED -#define BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED +#pragma once #include #include @@ -42,12 +22,8 @@ public: @param journal Destination for logging output. */ static std::shared_ptr - New(IP::Endpoint const& address, - std::string const& prefix, - Journal journal); + New(IP::Endpoint const& address, std::string const& prefix, Journal journal); }; } // namespace insight } // namespace beast - -#endif diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index f3c7387bb8..2ac4c3bc43 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_IPADDRESS_H_INCLUDED -#define BEAST_NET_IPADDRESS_H_INCLUDED +#pragma once #include #include @@ -115,5 +95,3 @@ struct hash<::beast::IP::Address> } }; } // namespace boost - -#endif diff --git a/include/xrpl/beast/net/IPAddressConversion.h b/include/xrpl/beast/net/IPAddressConversion.h index 0dfbe3197d..2ebd0a6eef 100644 --- a/include/xrpl/beast/net/IPAddressConversion.h +++ b/include/xrpl/beast/net/IPAddressConversion.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED -#define BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED +#pragma once #include @@ -80,5 +60,3 @@ struct IPAddressConversion }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h index c65adae05b..0d586716d8 100644 --- a/include/xrpl/beast/net/IPAddressV4.h +++ b/include/xrpl/beast/net/IPAddressV4.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_IPADDRESSV4_H_INCLUDED -#define BEAST_NET_IPADDRESSV4_H_INCLUDED +#pragma once #include @@ -45,5 +25,3 @@ get_class(AddressV4 const& address); } // namespace IP } // namespace beast - -#endif diff --git a/include/xrpl/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h index 9e24b228e5..2f9dedb748 100644 --- a/include/xrpl/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_IPADDRESSV6_H_INCLUDED -#define BEAST_NET_IPADDRESSV6_H_INCLUDED +#pragma once #include @@ -39,5 +19,3 @@ is_public(AddressV6 const& addr); } // namespace IP } // namespace beast - -#endif diff --git a/include/xrpl/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h index 8d43eb0ba9..7a0394cbd1 100644 --- a/include/xrpl/beast/net/IPEndpoint.h +++ b/include/xrpl/beast/net/IPEndpoint.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_IPENDPOINT_H_INCLUDED -#define BEAST_NET_IPENDPOINT_H_INCLUDED +#pragma once #include #include @@ -238,5 +218,3 @@ struct hash<::beast::IP::Endpoint> } }; } // namespace boost - -#endif diff --git a/include/xrpl/beast/rfc2616.h b/include/xrpl/beast/rfc2616.h index d6b3fa3cda..2ff770c011 100644 --- a/include/xrpl/beast/rfc2616.h +++ b/include/xrpl/beast/rfc2616.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_RFC2616_HPP -#define BEAST_RFC2616_HPP +#pragma once #include #include @@ -45,8 +25,7 @@ struct ci_equal_pred operator()(char c1, char c2) { // VFALCO TODO Use a table lookup here - return std::tolower(static_cast(c1)) == - std::tolower(static_cast(c2)); + return std::tolower(static_cast(c1)) == std::tolower(static_cast(c2)); } }; @@ -116,8 +95,7 @@ trim_right(String const& s) */ template < class FwdIt, - class Result = std::vector< - std::basic_string::value_type>>, + class Result = std::vector::value_type>>, class Char> Result split(FwdIt first, FwdIt last, Char delim) @@ -191,10 +169,7 @@ split(FwdIt first, FwdIt last, Char delim) return result; } -template < - class FwdIt, - class Result = std::vector< - std::basic_string::value_type>>> +template ::value_type>>> Result split_commas(FwdIt first, FwdIt last) { @@ -242,8 +217,7 @@ public: bool operator==(list_iterator const& other) const { - return other.it_ == it_ && other.end_ == end_ && - other.value_.size() == value_.size(); + return other.it_ == it_ && other.end_ == end_ && other.value_.size() == value_.size(); } bool @@ -307,14 +281,12 @@ list_iterator::increment() ++it_; if (it_ == end_) { - value_ = boost::string_ref( - &*start, std::distance(start, it_)); + value_ = boost::string_ref(&*start, std::distance(start, it_)); return; } if (*it_ == '"') { - value_ = boost::string_ref( - &*start, std::distance(start, it_)); + value_ = boost::string_ref(&*start, std::distance(start, it_)); ++it_; return; } @@ -340,8 +312,7 @@ list_iterator::increment() ++it_; if (it_ == end_ || *it_ == ',' || is_lws(*it_)) { - value_ = - boost::string_ref(&*start, std::distance(start, it_)); + value_ = boost::string_ref(&*start, std::distance(start, it_)); return; } } @@ -363,8 +334,7 @@ inline boost::iterator_range make_list(boost::string_ref const& field) { return boost::iterator_range{ - list_iterator{field.begin(), field.end()}, - list_iterator{field.end(), field.end()}}; + list_iterator{field.begin(), field.end()}, list_iterator{field.end(), field.end()}}; } /** Returns true if the specified token exists in the list. @@ -386,15 +356,9 @@ bool is_keep_alive(boost::beast::http::message const& m) { if (m.version() <= 10) - return boost::beast::http::token_list{ - m[boost::beast::http::field::connection]} - .exists("keep-alive"); - return !boost::beast::http::token_list{ - m[boost::beast::http::field::connection]} - .exists("close"); + return boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists("keep-alive"); + return !boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists("close"); } } // namespace rfc2616 } // namespace beast - -#endif diff --git a/include/xrpl/beast/test/yield_to.h b/include/xrpl/beast/test/yield_to.h index a222e8627e..b10530c0d3 100644 --- a/include/xrpl/beast/test/yield_to.h +++ b/include/xrpl/beast/test/yield_to.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_TEST_YIELD_TO_HPP -#define BEAST_TEST_YIELD_TO_HPP +#pragma once #include #include @@ -34,9 +30,7 @@ protected: boost::asio::io_context ios_; private: - boost::optional> - work_; + boost::optional> work_; std::vector threads_; std::mutex m_; std::condition_variable cv_; @@ -46,8 +40,7 @@ public: /// The type of yield context passed to functions. using yield_context = boost::asio::yield_context; - explicit enable_yield_to(std::size_t concurrency = 1) - : work_(boost::asio::make_work_guard(ios_)) + explicit enable_yield_to(std::size_t concurrency = 1) : work_(boost::asio::make_work_guard(ios_)) { threads_.reserve(concurrency); while (concurrency--) @@ -133,5 +126,3 @@ enable_yield_to::spawn(F0&& f, FN&&... fn) } // namespace test } // namespace beast - -#endif diff --git a/include/xrpl/beast/type_name.h b/include/xrpl/beast/type_name.h index 12281cdfe1..99b90d1757 100644 --- a/include/xrpl/beast/type_name.h +++ b/include/xrpl/beast/type_name.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Howard Hinnant - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_TYPE_NAME_H_INCLUDED -#define BEAST_TYPE_NAME_H_INCLUDED +#pragma once #include #include @@ -60,5 +40,3 @@ type_name() } } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test.h b/include/xrpl/beast/unit_test.h index bf33b205e6..51ac96cacb 100644 --- a/include/xrpl/beast/unit_test.h +++ b/include/xrpl/beast/unit_test.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UNIT_TEST_H_INCLUDED -#define BEAST_UNIT_TEST_H_INCLUDED +#pragma once #include #include @@ -38,5 +18,3 @@ //__LINE__);}while(false){} #define BEAST_EXPECT(cond) expect(cond, __FILE__ ":" BEAST_EXPECT_S2(__LINE__)) #endif - -#endif diff --git a/include/xrpl/beast/unit_test/amount.h b/include/xrpl/beast/unit_test/amount.h index 6f2182f599..aedced15a7 100644 --- a/include/xrpl/beast/unit_test/amount.h +++ b/include/xrpl/beast/unit_test/amount.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_AMOUNT_HPP -#define BEAST_UNIT_TEST_AMOUNT_HPP +#pragma once #include #include @@ -48,5 +44,3 @@ operator<<(std::ostream& s, amount const& t) } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/detail/const_container.h b/include/xrpl/beast/unit_test/detail/const_container.h index b1f089feed..7c52e0e1ec 100644 --- a/include/xrpl/beast/unit_test/detail/const_container.h +++ b/include/xrpl/beast/unit_test/detail/const_container.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_DETAIL_CONST_CONTAINER_HPP -#define BEAST_UNIT_TEST_DETAIL_CONST_CONTAINER_HPP +#pragma once namespace beast { namespace unit_test { @@ -89,5 +85,3 @@ public: } // namespace detail } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/global_suites.h b/include/xrpl/beast/unit_test/global_suites.h index 64bbbc7a26..68b4e2ced8 100644 --- a/include/xrpl/beast/unit_test/global_suites.h +++ b/include/xrpl/beast/unit_test/global_suites.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_GLOBAL_SUITES_HPP -#define BEAST_UNIT_TEST_GLOBAL_SUITES_HPP +#pragma once #include @@ -26,12 +22,7 @@ global_suites() template struct insert_suite { - insert_suite( - char const* name, - char const* module, - char const* library, - bool manual, - int priority) + insert_suite(char const* name, char const* module, char const* library, bool manual, int priority) { global_suites().insert(name, module, library, manual, priority); } @@ -48,5 +39,3 @@ global_suites() } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/match.h b/include/xrpl/beast/unit_test/match.h index 641787e814..38816bb5c7 100644 --- a/include/xrpl/beast/unit_test/match.h +++ b/include/xrpl/beast/unit_test/match.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_MATCH_HPP -#define BEAST_UNIT_TEST_MATCH_HPP +#pragma once #include @@ -56,8 +52,7 @@ public: //------------------------------------------------------------------------------ template -selector::selector(mode_t mode, std::string const& pattern) - : mode_(mode), pat_(pattern) +selector::selector(mode_t mode, std::string const& pattern) : mode_(mode), pat_(pattern) { if (mode_ == automatch && pattern.empty()) mode_ = all; @@ -170,5 +165,3 @@ match_library(std::string const& name) } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/recorder.h b/include/xrpl/beast/unit_test/recorder.h index fbe6ab6c10..8f956fda88 100644 --- a/include/xrpl/beast/unit_test/recorder.h +++ b/include/xrpl/beast/unit_test/recorder.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_RECORDER_HPP -#define BEAST_UNIT_TEST_RECORDER_HPP +#pragma once #include #include @@ -79,5 +75,3 @@ private: } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h index 0054daab98..ee7168d039 100644 --- a/include/xrpl/beast/unit_test/reporter.h +++ b/include/xrpl/beast/unit_test/reporter.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_REPORTER_HPP -#define BEAST_UNIT_TEST_REPORTER_HPP +#pragma once #include #include @@ -143,10 +139,7 @@ reporter<_>::results::add(suite_results const& r) if (elapsed >= std::chrono::seconds{1}) { auto const iter = std::lower_bound( - top.begin(), - top.end(), - elapsed, - [](run_time const& t1, typename clock_type::duration const& t2) { + top.begin(), top.end(), elapsed, [](run_time const& t1, typename clock_type::duration const& t2) { return t1.second > t2; }); if (iter != top.end()) @@ -179,10 +172,8 @@ reporter<_>::~reporter() os_ << std::setw(8) << fmtdur(i.second) << " " << i.first << '\n'; } auto const elapsed = clock_type::now() - results_.start; - os_ << fmtdur(elapsed) << ", " << amount{results_.suites, "suite"} << ", " - << amount{results_.cases, "case"} << ", " - << amount{results_.total, "test"} << " total, " - << amount{results_.failed, "failure"} << std::endl; + os_ << fmtdur(elapsed) << ", " << amount{results_.suites, "suite"} << ", " << amount{results_.cases, "case"} << ", " + << amount{results_.total, "test"} << " total, " << amount{results_.failed, "failure"} << std::endl; } template @@ -217,9 +208,7 @@ void reporter<_>::on_case_begin(std::string const& name) { case_results_ = case_results(name); - os_ << suite_results_.name - << (case_results_.name.empty() ? "" : (" " + case_results_.name)) - << std::endl; + os_ << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name)) << std::endl; } template @@ -242,8 +231,7 @@ reporter<_>::on_fail(std::string const& reason) { ++case_results_.failed; ++case_results_.total; - os_ << "#" << case_results_.total << " failed" - << (reason.empty() ? "" : ": ") << reason << std::endl; + os_ << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason << std::endl; } template @@ -259,5 +247,3 @@ using reporter = detail::reporter<>; } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/results.h b/include/xrpl/beast/unit_test/results.h index 96fedc9b75..cbd0a71057 100644 --- a/include/xrpl/beast/unit_test/results.h +++ b/include/xrpl/beast/unit_test/results.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_RESULTS_HPP -#define BEAST_UNIT_TEST_RESULTS_HPP +#pragma once #include @@ -27,8 +23,7 @@ public: { } - test(bool pass_, std::string const& reason_) - : pass(pass_), reason(reason_) + test(bool pass_, std::string const& reason_) : pass(pass_), reason(reason_) { } @@ -226,5 +221,3 @@ public: } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h index 977cc45035..90d8a2f4b5 100644 --- a/include/xrpl/beast/unit_test/runner.h +++ b/include/xrpl/beast/unit_test/runner.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_RUNNER_H_INCLUDED -#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED +#pragma once #include @@ -42,7 +38,7 @@ public: The argument string is available to suites and allows for customization of the test. Each suite - defines its own syntax for the argumnet string. + defines its own syntax for the argument string. The same argument is passed to all suites. */ void @@ -279,5 +275,3 @@ runner::log(std::string const& s) } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h index 51cd3e17ea..0e6b592a87 100644 --- a/include/xrpl/beast/unit_test/suite.h +++ b/include/xrpl/beast/unit_test/suite.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_SUITE_HPP -#define BEAST_UNIT_TEST_SUITE_HPP +#pragma once #include @@ -95,17 +91,13 @@ private: } }; - template < - class CharT, - class Traits = std::char_traits, - class Allocator = std::allocator> + template , class Allocator = std::allocator> class log_os : public std::basic_ostream { log_buf buf_; public: - explicit log_os(suite& self) - : std::basic_ostream(&buf_), buf_(self) + explicit log_os(suite& self) : std::basic_ostream(&buf_), buf_(self) { } }; @@ -244,11 +236,7 @@ public: template bool - expect( - Condition const& shouldBeTrue, - String const& reason, - char const* file, - int line); + expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line); /** @} */ // @@ -352,8 +340,7 @@ public: } template - scoped_testcase(suite& self, std::stringstream& ss, T const& t) - : suite_(self), ss_(ss) + scoped_testcase(suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss) { ss_.clear(); ss_.str({}); @@ -426,11 +413,7 @@ suite::expect(Condition const& shouldBeTrue, String const& reason) template bool -suite::expect( - Condition const& shouldBeTrue, - String const& reason, - char const* file, - int line) +suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line) { if (shouldBeTrue) { @@ -579,8 +562,7 @@ suite::run(runner& r) If the condition is false, the file and line number are reported. */ -#define BEAST_EXPECTS(cond, reason) \ - ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false)) +#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false)) #endif } // namespace unit_test @@ -590,11 +572,9 @@ suite::run(runner& r) // detail: // This inserts the suite with the given manual flag -#define BEAST_DEFINE_TESTSUITE_INSERT( \ - Class, Module, Library, manual, priority) \ - static beast::unit_test::detail::insert_suite \ - Library##Module##Class##_test_instance( \ - #Class, #Module, #Library, manual, priority) +#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \ + static beast::unit_test::detail::insert_suite Library##Module##Class##_test_instance( \ + #Class, #Module, #Library, manual, priority) //------------------------------------------------------------------------------ @@ -649,8 +629,7 @@ suite::run(runner& r) #else #include -#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \ - BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0) +#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0) #define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \ BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0) #define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \ @@ -662,5 +641,3 @@ suite::run(runner& r) #endif //------------------------------------------------------------------------------ - -#endif diff --git a/include/xrpl/beast/unit_test/suite_info.h b/include/xrpl/beast/unit_test/suite_info.h index a7e63d606c..019251b0c4 100644 --- a/include/xrpl/beast/unit_test/suite_info.h +++ b/include/xrpl/beast/unit_test/suite_info.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP -#define BEAST_UNIT_TEST_SUITE_INFO_HPP +#pragma once #include #include @@ -31,13 +27,7 @@ class suite_info run_type run_; public: - suite_info( - std::string name, - std::string module, - std::string library, - bool manual, - int priority, - run_type run) + suite_info(std::string name, std::string module, std::string library, bool manual, int priority, run_type run) : name_(std::move(name)) , module_(std::move(module)) , library_(std::move(library)) @@ -91,10 +81,8 @@ public: { // we want higher priority suites sorted first, thus the negation // of priority value here - return std::forward_as_tuple( - -lhs.priority_, lhs.library_, lhs.module_, lhs.name_) < - std::forward_as_tuple( - -rhs.priority_, rhs.library_, rhs.module_, rhs.name_); + return std::forward_as_tuple(-lhs.priority_, lhs.library_, lhs.module_, lhs.name_) < + std::forward_as_tuple(-rhs.priority_, rhs.library_, rhs.module_, rhs.name_); } }; @@ -103,23 +91,11 @@ public: /// Convenience for producing suite_info for a given test type. template suite_info -make_suite_info( - std::string name, - std::string module, - std::string library, - bool manual, - int priority) +make_suite_info(std::string name, std::string module, std::string library, bool manual, int priority) { return suite_info( - std::move(name), - std::move(module), - std::move(library), - manual, - priority, - [](runner& r) { Suite{}(r); }); + std::move(name), std::move(module), std::move(library), manual, priority, [](runner& r) { Suite{}(r); }); } } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/suite_list.h b/include/xrpl/beast/unit_test/suite_list.h index 0095290eac..4412883e31 100644 --- a/include/xrpl/beast/unit_test/suite_list.h +++ b/include/xrpl/beast/unit_test/suite_list.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_SUITE_LIST_HPP -#define BEAST_UNIT_TEST_SUITE_LIST_HPP +#pragma once #include #include @@ -36,24 +32,14 @@ public: */ template void - insert( - char const* name, - char const* module, - char const* library, - bool manual, - int priority); + insert(char const* name, char const* module, char const* library, bool manual, int priority); }; //------------------------------------------------------------------------------ template void -suite_list::insert( - char const* name, - char const* module, - char const* library, - bool manual, - int priority) +suite_list::insert(char const* name, char const* module, char const* library, bool manual, int priority) { #ifndef NDEBUG { @@ -68,11 +54,8 @@ suite_list::insert( BOOST_ASSERT(result.second); // Duplicate type } #endif - cont().emplace( - make_suite_info(name, module, library, manual, priority)); + cont().emplace(make_suite_info(name, module, library, manual, priority)); } } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/thread.h b/include/xrpl/beast/unit_test/thread.h index 99572a549d..b49f8ed36e 100644 --- a/include/xrpl/beast/unit_test/thread.h +++ b/include/xrpl/beast/unit_test/thread.h @@ -1,12 +1,8 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_UNIT_TEST_THREAD_HPP -#define BEAST_UNIT_TEST_THREAD_HPP +#pragma once #include @@ -48,8 +44,7 @@ public: template explicit thread(suite& s, F&& f, Args&&... args) : s_(&s) { - std::function b = - std::bind(std::forward(f), std::forward(args)...); + std::function b = std::bind(std::forward(f), std::forward(args)...); t_ = std::thread(&thread::run, this, std::move(b)); } @@ -115,5 +110,3 @@ private: } // namespace unit_test } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 91ddf33d27..dff88826ce 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED -#define BEAST_UTILITY_JOURNAL_H_INCLUDED +#pragma once #include @@ -149,8 +129,7 @@ public: class ScopedStream { public: - ScopedStream(ScopedStream const& other) - : ScopedStream(other.m_sink, other.m_level) + ScopedStream(ScopedStream const& other) : ScopedStream(other.m_sink, other.m_level) { } @@ -186,16 +165,12 @@ public: }; #ifndef __INTELLISENSE__ - static_assert( - std::is_default_constructible::value == false, - ""); + static_assert(std::is_default_constructible::value == false, ""); static_assert(std::is_copy_constructible::value == true, ""); static_assert(std::is_move_constructible::value == true, ""); static_assert(std::is_copy_assignable::value == false, ""); static_assert(std::is_move_assignable::value == false, ""); - static_assert( - std::is_nothrow_destructible::value == true, - ""); + static_assert(std::is_nothrow_destructible::value == true, ""); #endif //-------------------------------------------------------------------------- @@ -205,8 +180,7 @@ public: { public: /** Create a stream which produces no output. */ - explicit Stream() - : m_sink(getNullSink()), m_level(severities::kDisabled) + explicit Stream() : m_sink(getNullSink()), m_level(severities::kDisabled) { } @@ -216,9 +190,7 @@ public: */ Stream(Sink& sink, Severity level) : m_sink(sink), m_level(level) { - XRPL_ASSERT( - m_level < severities::kDisabled, - "beast::Journal::Stream::Stream : maximum level"); + XRPL_ASSERT(m_level < severities::kDisabled, "beast::Journal::Stream::Stream : maximum level"); } /** Construct or copy another Stream. */ @@ -449,8 +421,7 @@ class basic_logstream : public std::basic_ostream detail::logstream_buf buf_; public: - explicit basic_logstream(beast::Journal::Stream const& strm) - : std::basic_ostream(&buf_), buf_(strm) + explicit basic_logstream(beast::Journal::Stream const& strm) : std::basic_ostream(&buf_), buf_(strm) { } }; @@ -459,5 +430,3 @@ using logstream = basic_logstream; using logwstream = basic_logstream; } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/PropertyStream.h b/include/xrpl/beast/utility/PropertyStream.h index 18895e2410..3d29138a12 100644 --- a/include/xrpl/beast/utility/PropertyStream.h +++ b/include/xrpl/beast/utility/PropertyStream.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED -#define BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED +#pragma once #include @@ -395,7 +375,7 @@ public: print statement examples "parent.child" prints child and all of its children "parent.child." start at the parent and print down to child - "parent.grandchild" prints nothing- grandchild not direct discendent + "parent.grandchild" prints nothing- grandchild not direct descendent "parent.grandchild." starts at the parent and prints down to grandchild "parent.grandchild.*" starts at parent, print through grandchild children @@ -427,5 +407,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h index 72dcf4e8f5..bb8a1a6994 100644 --- a/include/xrpl/beast/utility/WrappedSink.h +++ b/include/xrpl/beast/utility/WrappedSink.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED -#define BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED +#pragma once #include @@ -37,16 +17,12 @@ private: std::string prefix_; public: - explicit WrappedSink( - beast::Journal::Sink& sink, - std::string const& prefix = "") + explicit WrappedSink(beast::Journal::Sink& sink, std::string const& prefix = "") : Sink(sink), sink_(sink), prefix_(prefix) { } - explicit WrappedSink( - beast::Journal const& journal, - std::string const& prefix = "") + explicit WrappedSink(beast::Journal const& journal, std::string const& prefix = "") : WrappedSink(journal.sink(), prefix) { } @@ -103,5 +79,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/Zero.h b/include/xrpl/beast/utility/Zero.h index efd4d6d667..00e91a1a47 100644 --- a/include/xrpl/beast/utility/Zero.h +++ b/include/xrpl/beast/utility/Zero.h @@ -1,24 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Tom Ritchford +// Copyright (c) 2014, Tom Ritchford - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_ZERO_H_INCLUDED -#define BEAST_UTILITY_ZERO_H_INCLUDED +#pragma once namespace beast { @@ -161,5 +143,3 @@ operator<=(Zero, T const& t) } } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/instrumentation.h b/include/xrpl/beast/utility/instrumentation.h index 3594855eef..0d0b2ce415 100644 --- a/include/xrpl/beast/utility/instrumentation.h +++ b/include/xrpl/beast/utility/instrumentation.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2024 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED -#define BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED +#pragma once #include @@ -32,15 +12,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // The duplication is because Visual Studio 2019 cannot compile that header // even with the option -Zc:__cplusplus added. #define ALWAYS(cond, message, ...) assert((message) && (cond)) -#define ALWAYS_OR_UNREACHABLE(cond, message, ...) assert((message) && (cond)) +#define ALWAYS_OR_UNREACHABLE(cond, message) assert((message) && (cond)) #define SOMETIMES(cond, message, ...) #define REACHABLE(message, ...) #define UNREACHABLE(message, ...) assert((message) && false) #endif #define XRPL_ASSERT ALWAYS_OR_UNREACHABLE -#define XRPL_ASSERT_PARTS(cond, function, description, ...) \ - XRPL_ASSERT(cond, function " : " description) +#define XRPL_ASSERT_PARTS(cond, function, description, ...) XRPL_ASSERT(cond, function " : " description) // How to use the instrumentation macros: // @@ -71,5 +50,3 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // instrumentation macros - its name describes the condition which was _not_ // meant to happen, while name in other macros describes the condition that is // meant to happen (e.g. as in "assert that this happens"). - -#endif diff --git a/include/xrpl/beast/utility/maybe_const.h b/include/xrpl/beast/utility/maybe_const.h index c1c01490c9..4aac7f018e 100644 --- a/include/xrpl/beast/utility/maybe_const.h +++ b/include/xrpl/beast/utility/maybe_const.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_MAYBE_CONST_H_INCLUDED -#define BEAST_UTILITY_MAYBE_CONST_H_INCLUDED +#pragma once #include @@ -29,10 +9,8 @@ template struct maybe_const { explicit maybe_const() = default; - using type = typename std::conditional< - IsConst, - typename std::remove_const::type const, - typename std::remove_const::type>::type; + using type = typename std:: + conditional::type const, typename std::remove_const::type>::type; }; /** Alias for omitting `typename`. */ @@ -40,5 +18,3 @@ template using maybe_const_t = typename maybe_const::type; } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h index e1b47618ba..7c694aac4f 100644 --- a/include/xrpl/beast/utility/rngfill.h +++ b/include/xrpl/beast/utility/rngfill.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_RANDOM_RNGFILL_H_INCLUDED -#define BEAST_RANDOM_RNGFILL_H_INCLUDED +#pragma once #include @@ -55,10 +35,7 @@ rngfill(void* const buffer, std::size_t const bytes, Generator& g) } } -template < - class Generator, - std::size_t N, - class = std::enable_if_t> +template > void rngfill(std::array& a, Generator& g) { @@ -70,5 +47,3 @@ rngfill(std::array& a, Generator& g) } } // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/temp_dir.h b/include/xrpl/beast/utility/temp_dir.h index 074b7461a4..5aa7b28ac2 100644 --- a/include/xrpl/beast/utility/temp_dir.h +++ b/include/xrpl/beast/utility/temp_dir.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_UTILITY_TEMP_DIR_H_INCLUDED -#define BEAST_UTILITY_TEMP_DIR_H_INCLUDED +#pragma once #include @@ -81,5 +61,3 @@ public: }; } // namespace beast - -#endif diff --git a/include/xrpl/beast/xor_shift_engine.h b/include/xrpl/beast/xor_shift_engine.h index 77012980c8..d49cb08fc0 100644 --- a/include/xrpl/beast/xor_shift_engine.h +++ b/include/xrpl/beast/xor_shift_engine.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_RANDOM_XOR_SHIFT_ENGINE_H_INCLUDED -#define BEAST_RANDOM_XOR_SHIFT_ENGINE_H_INCLUDED +#pragma once #include #include @@ -114,5 +94,3 @@ xor_shift_engine<_>::murmurhash3(result_type x) -> result_type using xor_shift_engine = detail::xor_shift_engine<>; } // namespace beast - -#endif diff --git a/src/xrpld/core/ClosureCounter.h b/include/xrpl/core/ClosureCounter.h similarity index 77% rename from src/xrpld/core/ClosureCounter.h rename to include/xrpl/core/ClosureCounter.h index 92117a91c4..6802a03f3d 100644 --- a/src/xrpld/core/ClosureCounter.h +++ b/include/xrpl/core/ClosureCounter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_CLOSURE_COUNTER_H_INCLUDED -#define RIPPLE_CORE_CLOSURE_COUNTER_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** * The role of a `ClosureCounter` is to assist in shutdown by letting callers @@ -95,21 +75,18 @@ private: std::remove_reference_t closure_; static_assert( - std::is_same()...)), Ret_t>:: - value, + std::is_same()...)), Ret_t>::value, "Closure arguments don't match ClosureCounter Ret_t or Args_t"); public: Substitute() = delete; - Substitute(Substitute const& rhs) - : counter_(rhs.counter_), closure_(rhs.closure_) + Substitute(Substitute const& rhs) : counter_(rhs.counter_), closure_(rhs.closure_) { ++counter_; } - Substitute(Substitute&& rhs) noexcept( - std::is_nothrow_move_constructible::value) + Substitute(Substitute&& rhs) noexcept(std::is_nothrow_move_constructible::value) : counter_(rhs.counter_), closure_(std::move(rhs.closure_)) { ++counter_; @@ -169,13 +146,11 @@ public: waitForClosures_ = true; if (closureCount_ > 0) { - if (!allClosuresDoneCond_.wait_for( - lock, wait, [this] { return closureCount_ == 0; })) + if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; })) { if (auto stream = j.error()) stream << name << " waiting for ClosureCounter::join()."; - allClosuresDoneCond_.wait( - lock, [this] { return closureCount_ == 0; }); + allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; }); } } } @@ -221,6 +196,4 @@ public: } }; -} // namespace ripple - -#endif // RIPPLE_CORE_CLOSURE_COUNTER_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/core/Coro.ipp b/include/xrpl/core/Coro.ipp similarity index 56% rename from src/xrpld/core/Coro.ipp rename to include/xrpl/core/Coro.ipp index 5901e07c68..2853adf0de 100644 --- a/src/xrpld/core/Coro.ipp +++ b/include/xrpl/core/Coro.ipp @@ -1,44 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_COROINL_H_INCLUDED -#define RIPPLE_CORE_COROINL_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { template -JobQueue::Coro::Coro( - Coro_create_t, - JobQueue& jq, - JobType type, - std::string const& name, - F&& f) +JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string const& name, F&& f) : jq_(jq) , type_(type) , name_(name) , running_(false) , coro_( - [this, fn = std::forward(f)]( - boost::coroutines::asymmetric_coroutine::push_type& - do_yield) { + [this, fn = std::forward(f)](boost::coroutines::asymmetric_coroutine::push_type& do_yield) { yield_ = &do_yield; yield(); fn(shared_from_this()); @@ -53,7 +26,7 @@ JobQueue::Coro::Coro( inline JobQueue::Coro::~Coro() { #ifndef NDEBUG - XRPL_ASSERT(finished_, "ripple::JobQueue::Coro::~Coro : is finished"); + XRPL_ASSERT(finished_, "xrpl::JobQueue::Coro::~Coro : is finished"); #endif } @@ -76,8 +49,7 @@ JobQueue::Coro::post() } // sp keeps 'this' alive - if (jq_.addJob( - type_, name_, [this, sp = shared_from_this()]() { resume(); })) + if (jq_.addJob(type_, name_, [this, sp = shared_from_this()]() { resume(); })) { return true; } @@ -103,9 +75,7 @@ JobQueue::Coro::resume() auto saved = detail::getLocalValues().release(); detail::getLocalValues().reset(&lvs_); std::lock_guard lock(mutex_); - XRPL_ASSERT( - static_cast(coro_), - "ripple::JobQueue::Coro::resume : is runnable"); + XRPL_ASSERT(static_cast(coro_), "xrpl::JobQueue::Coro::resume : is runnable"); coro_(); detail::getLocalValues().release(); detail::getLocalValues().reset(saved); @@ -148,6 +118,4 @@ JobQueue::Coro::join() cv_.wait(lk, [this]() { return running_ == false; }); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/core/Job.h b/include/xrpl/core/Job.h similarity index 75% rename from src/xrpld/core/Job.h rename to include/xrpl/core/Job.h index 11b0b9b72b..61651fd673 100644 --- a/src/xrpld/core/Job.h +++ b/include/xrpl/core/Job.h @@ -1,33 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_JOB_H_INCLUDED -#define RIPPLE_CORE_JOB_H_INCLUDED - -#include -#include +#pragma once #include +#include +#include #include -namespace ripple { +namespace xrpl { // Note that this queue should only be used for CPU-bound jobs // It is primarily intended for signature checking @@ -113,11 +92,7 @@ public: Job(JobType type, std::uint64_t index); // VFALCO TODO try to remove the dependency on LoadMonitor. - Job(JobType type, - std::string const& name, - std::uint64_t index, - LoadMonitor& lm, - std::function const& job); + Job(JobType type, std::string const& name, std::uint64_t index, LoadMonitor& lm, std::function const& job); JobType getType() const; @@ -151,6 +126,4 @@ private: using JobCounter = ClosureCounter; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/core/JobQueue.h b/include/xrpl/core/JobQueue.h similarity index 86% rename from src/xrpld/core/JobQueue.h rename to include/xrpl/core/JobQueue.h index eda956c019..b410e200e1 100644 --- a/src/xrpld/core/JobQueue.h +++ b/include/xrpl/core/JobQueue.h @@ -1,38 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_JOBQUEUE_H_INCLUDED -#define RIPPLE_CORE_JOBQUEUE_H_INCLUDED - -#include -#include -#include -#include +#pragma once #include +#include +#include +#include +#include #include #include #include -namespace ripple { +namespace xrpl { namespace perf { class PerfLog; @@ -161,14 +140,11 @@ public: */ template < typename JobHandler, - typename = std::enable_if_t()()), - void>::value>> + typename = std::enable_if_t()()), void>::value>> bool addJob(JobType type, std::string const& name, JobHandler&& jobHandler) { - if (auto optionalCountedJob = - jobCounter_.wrap(std::forward(jobHandler))) + if (auto optionalCountedJob = jobCounter_.wrap(std::forward(jobHandler))) { return addRefCountedJob(type, name, std::move(*optionalCountedJob)); } @@ -284,10 +260,7 @@ private: // // return true if func added to queue. bool - addRefCountedJob( - JobType type, - std::string const& name, - JobFunction const& func); + addRefCountedJob(JobType type, std::string const& name, JobFunction const& func); // Returns the next Job we should run now. // @@ -402,11 +375,11 @@ private: lock is released which only happens after the coroutine completes. */ -} // namespace ripple +} // namespace xrpl -#include +#include -namespace ripple { +namespace xrpl { template std::shared_ptr @@ -416,8 +389,7 @@ JobQueue::postCoro(JobType t, std::string const& name, F&& f) Last param is the function the coroutine runs. Signature of void(std::shared_ptr). */ - auto coro = std::make_shared( - Coro_create_t{}, *this, t, name, std::forward(f)); + auto coro = std::make_shared(Coro_create_t{}, *this, t, name, std::forward(f)); if (!coro->post()) { // The Coro was not successfully posted. Disable it so it's destructor @@ -428,6 +400,4 @@ JobQueue::postCoro(JobType t, std::string const& name, F&& f) return coro; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/core/JobTypeData.h b/include/xrpl/core/JobTypeData.h new file mode 100644 index 0000000000..cdcb19c316 --- /dev/null +++ b/include/xrpl/core/JobTypeData.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +namespace xrpl { + +struct JobTypeData +{ +private: + LoadMonitor m_load; + + /* Support for insight */ + beast::insight::Collector::ptr m_collector; + +public: + /* The job category which we represent */ + JobTypeInfo const& info; + + /* The number of jobs waiting */ + int waiting; + + /* The number presently running */ + int running; + + /* And the number we deferred executing because of job limits */ + int deferred; + + /* Notification callbacks */ + beast::insight::Event dequeue; + beast::insight::Event execute; + + JobTypeData(JobTypeInfo const& info_, beast::insight::Collector::ptr const& collector, Logs& logs) noexcept + : m_load(logs.journal("LoadMonitor")), m_collector(collector), info(info_), waiting(0), running(0), deferred(0) + { + m_load.setTargetLatency(info.getAverageLatency(), info.getPeakLatency()); + + if (!info.special()) + { + dequeue = m_collector->make_event(info.name() + "_q"); + execute = m_collector->make_event(info.name()); + } + } + + /* Not copy-constructible or assignable */ + JobTypeData(JobTypeData const& other) = delete; + JobTypeData& + operator=(JobTypeData const& other) = delete; + + std::string + name() const + { + return info.name(); + } + + JobType + type() const + { + return info.type(); + } + + LoadMonitor& + load() + { + return m_load; + } + + LoadMonitor::Stats + stats() + { + return m_load.getStats(); + } +}; + +} // namespace xrpl diff --git a/include/xrpl/core/JobTypeInfo.h b/include/xrpl/core/JobTypeInfo.h new file mode 100644 index 0000000000..d4daa1ec68 --- /dev/null +++ b/include/xrpl/core/JobTypeInfo.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +namespace xrpl { + +/** Holds all the 'static' information about a job, which does not change */ +class JobTypeInfo +{ +private: + JobType const m_type; + std::string const m_name; + + /** The limit on the number of running jobs for this job type. + + A limit of 0 marks this as a "special job" which is not + dispatched via the job queue. + */ + int const m_limit; + + /** Average and peak latencies for this job type. 0 is none specified */ + std::chrono::milliseconds const m_avgLatency; + std::chrono::milliseconds const m_peakLatency; + +public: + // Not default constructible + JobTypeInfo() = delete; + + JobTypeInfo( + JobType type, + std::string name, + int limit, + std::chrono::milliseconds avgLatency, + std::chrono::milliseconds peakLatency) + : m_type(type), m_name(std::move(name)), m_limit(limit), m_avgLatency(avgLatency), m_peakLatency(peakLatency) + { + } + + JobType + type() const + { + return m_type; + } + + std::string const& + name() const + { + return m_name; + } + + int + limit() const + { + return m_limit; + } + + bool + special() const + { + return m_limit == 0; + } + + std::chrono::milliseconds + getAverageLatency() const + { + return m_avgLatency; + } + + std::chrono::milliseconds + getPeakLatency() const + { + return m_peakLatency; + } +}; + +} // namespace xrpl diff --git a/src/xrpld/core/JobTypes.h b/include/xrpl/core/JobTypes.h similarity index 75% rename from src/xrpld/core/JobTypes.h rename to include/xrpl/core/JobTypes.h index 29863893d9..88f98aad66 100644 --- a/src/xrpld/core/JobTypes.h +++ b/include/xrpl/core/JobTypes.h @@ -1,32 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_JOBTYPES_H_INCLUDED -#define RIPPLE_CORE_JOBTYPES_H_INCLUDED - -#include -#include +#include +#include #include #include -namespace ripple { +namespace xrpl { class JobTypes { @@ -35,13 +15,7 @@ public: using const_iterator = Map::const_iterator; private: - JobTypes() - : m_unknown( - jtINVALID, - "invalid", - 0, - std::chrono::milliseconds{0}, - std::chrono::milliseconds{0}) + JobTypes() : m_unknown(jtINVALID, "invalid", 0, std::chrono::milliseconds{0}, std::chrono::milliseconds{0}) { using namespace std::chrono_literals; int maxLimit = std::numeric_limits::max(); @@ -52,22 +26,17 @@ private: int limit, std::chrono::milliseconds avgLatency, std::chrono::milliseconds peakLatency) { - XRPL_ASSERT( - m_map.find(jt) == m_map.end(), - "ripple::JobTypes::JobTypes::add : unique job type input"); + XRPL_ASSERT(m_map.find(jt) == m_map.end(), "xrpl::JobTypes::JobTypes::add : unique job type input"); [[maybe_unused]] auto const inserted = m_map .emplace( std::piecewise_construct, std::forward_as_tuple(jt), - std::forward_as_tuple( - jt, name, limit, avgLatency, peakLatency)) + std::forward_as_tuple(jt, name, limit, avgLatency, peakLatency)) .second; - XRPL_ASSERT( - inserted == true, - "ripple::JobTypes::JobTypes::add : input is inserted"); + XRPL_ASSERT(inserted == true, "xrpl::JobTypes::JobTypes::add : input is inserted"); }; // clang-format off @@ -141,7 +110,7 @@ public: get(JobType jt) const { Map::const_iterator const iter(m_map.find(jt)); - XRPL_ASSERT(iter != m_map.end(), "ripple::JobTypes::get : valid input"); + XRPL_ASSERT(iter != m_map.end(), "xrpl::JobTypes::get : valid input"); if (iter != m_map.end()) return iter->second; @@ -189,6 +158,4 @@ public: Map m_map; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/core/LoadEvent.h b/include/xrpl/core/LoadEvent.h similarity index 56% rename from src/xrpld/core/LoadEvent.h rename to include/xrpl/core/LoadEvent.h index 3b5f69194f..f94e1020bf 100644 --- a/src/xrpld/core/LoadEvent.h +++ b/include/xrpl/core/LoadEvent.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_LOADEVENT_H_INCLUDED -#define RIPPLE_CORE_LOADEVENT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class LoadMonitor; @@ -84,6 +64,4 @@ private: std::chrono::steady_clock::duration timeRunning_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/core/LoadMonitor.h b/include/xrpl/core/LoadMonitor.h new file mode 100644 index 0000000000..71fbf75d68 --- /dev/null +++ b/include/xrpl/core/LoadMonitor.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace xrpl { + +// Monitors load levels and response times + +// VFALCO TODO Rename this. Having both LoadManager and LoadMonitor is +// confusing. +// +class LoadMonitor +{ +public: + explicit LoadMonitor(beast::Journal j); + + void + addLoadSample(LoadEvent const& sample); + + void + addSamples(int count, std::chrono::milliseconds latency); + + void + setTargetLatency(std::chrono::milliseconds avg, std::chrono::milliseconds pk); + + bool + isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak); + + // VFALCO TODO make this return the values in a struct. + struct Stats + { + Stats(); + + std::uint64_t count; + std::chrono::milliseconds latencyAvg; + std::chrono::milliseconds latencyPeak; + bool isOverloaded; + }; + + Stats + getStats(); + + bool + isOver(); + +private: + void + update(); + + std::mutex mutex_; + + std::uint64_t mCounts; + int mLatencyEvents; + std::chrono::milliseconds mLatencyMSAvg; + std::chrono::milliseconds mLatencyMSPeak; + std::chrono::milliseconds mTargetLatencyAvg; + std::chrono::milliseconds mTargetLatencyPk; + UptimeClock::time_point mLastUpdate; + beast::Journal const j_; +}; + +} // namespace xrpl diff --git a/src/xrpld/overlay/PeerReservationTable.h b/include/xrpl/core/PeerReservationTable.h similarity index 61% rename from src/xrpld/overlay/PeerReservationTable.h rename to include/xrpl/core/PeerReservationTable.h index ddd6526161..8f187bf324 100644 --- a/src/xrpld/overlay/PeerReservationTable.h +++ b/include/xrpl/core/PeerReservationTable.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_OVERLAY_PEER_RESERVATION_TABLE_H_INCLUDED -#define RIPPLE_OVERLAY_PEER_RESERVATION_TABLE_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { class DatabaseCon; @@ -75,8 +55,7 @@ struct KeyEqual final class PeerReservationTable final { public: - explicit PeerReservationTable( - beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) + explicit PeerReservationTable(beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) : journal_(journal) { } @@ -116,6 +95,4 @@ private: std::unordered_set, KeyEqual> table_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/perflog/PerfLog.h b/include/xrpl/core/PerfLog.h similarity index 69% rename from src/xrpld/perflog/PerfLog.h rename to include/xrpl/core/PerfLog.h index 5212752ec7..eebd41ae09 100644 --- a/src/xrpld/perflog/PerfLog.h +++ b/include/xrpl/core/PerfLog.h @@ -1,28 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_PERFLOG_H -#define RIPPLE_BASICS_PERFLOG_H - -#include -#include +#pragma once +#include +#include #include #include @@ -37,7 +16,7 @@ namespace beast { class Journal; } -namespace ripple { +namespace xrpl { class Application; namespace perf { @@ -60,7 +39,7 @@ public: using microseconds = std::chrono::microseconds; /** - * Configuration from [perf] section of rippled.cfg. + * Configuration from [perf] section of xrpld.cfg. */ struct Setup { @@ -125,11 +104,7 @@ public: * @param instance JobQueue worker thread instance */ virtual void - jobStart( - JobType const type, - microseconds dur, - steady_time_point startTime, - int instance) = 0; + jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) = 0; /** * Log job finishing @@ -176,11 +151,7 @@ PerfLog::Setup setup_PerfLog(Section const& section, boost::filesystem::path const& configDir); std::unique_ptr -make_PerfLog( - PerfLog::Setup const& setup, - Application& app, - beast::Journal journal, - std::function&& signalStop); +make_PerfLog(PerfLog::Setup const& setup, Application& app, beast::Journal journal, std::function&& signalStop); template auto @@ -195,18 +166,14 @@ measureDurationAndLog( auto result = func(); auto end_time = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast( - end_time - start_time); + auto duration = std::chrono::duration_cast(end_time - start_time); if (duration > maxDelay) { - JLOG(journal.warn()) - << actionDescription << " took " << duration.count() << " ms"; + JLOG(journal.warn()) << actionDescription << " took " << duration.count() << " ms"; } return result; } } // namespace perf -} // namespace ripple - -#endif // RIPPLE_BASICS_PERFLOG_H +} // namespace xrpl diff --git a/include/xrpl/core/ServiceRegistry.h b/include/xrpl/core/ServiceRegistry.h new file mode 100644 index 0000000000..86591a815f --- /dev/null +++ b/include/xrpl/core/ServiceRegistry.h @@ -0,0 +1,223 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace xrpl { + +// Forward declarations +namespace NodeStore { +class Database; +} +namespace Resource { +class Manager; +} +namespace perf { +class PerfLog; +} + +// This is temporary until we migrate all code to use ServiceRegistry. +class Application; + +// Forward declarations +class AcceptedLedger; +class AmendmentTable; +class Cluster; +class CollectorManager; +class DatabaseCon; +class Family; +class HashRouter; +class InboundLedgers; +class InboundTransactions; +class JobQueue; +class LedgerCleaner; +class LedgerMaster; +class LedgerReplayer; +class LoadFeeTrack; +class LoadManager; +class ManifestCache; +class NetworkOPs; +class OpenLedger; +class OrderBookDB; +class Overlay; +class PathRequests; +class PeerReservationTable; +class PendingSaves; +class RelationalDatabase; +class ServerHandler; +class SHAMapStore; +class TimeKeeper; +class TransactionMaster; +class TxQ; +class ValidatorList; +class ValidatorSite; + +template +class Validations; +class RCLValidationsAdaptor; +using RCLValidations = Validations; + +using NodeCache = TaggedCache; + +/** Service registry for dependency injection. + + This abstract interface provides access to various services and components + used throughout the application. It separates the service locator pattern + from the Application lifecycle management. + + Components that need access to services can hold a reference to + ServiceRegistry rather than Application when they only need service + access and not lifecycle management. + +*/ +class ServiceRegistry +{ +public: + ServiceRegistry() = default; + virtual ~ServiceRegistry() = default; + + // Core infrastructure services + virtual CollectorManager& + getCollectorManager() = 0; + + virtual Family& + getNodeFamily() = 0; + + virtual TimeKeeper& + timeKeeper() = 0; + + virtual JobQueue& + getJobQueue() = 0; + + virtual NodeCache& + getTempNodeCache() = 0; + + virtual CachedSLEs& + cachedSLEs() = 0; + + // Protocol and validation services + virtual AmendmentTable& + getAmendmentTable() = 0; + + virtual HashRouter& + getHashRouter() = 0; + + virtual LoadFeeTrack& + getFeeTrack() = 0; + + virtual LoadManager& + getLoadManager() = 0; + + virtual RCLValidations& + getValidations() = 0; + + virtual ValidatorList& + validators() = 0; + + virtual ValidatorSite& + validatorSites() = 0; + + virtual ManifestCache& + validatorManifests() = 0; + + virtual ManifestCache& + publisherManifests() = 0; + + // Network services + virtual Overlay& + overlay() = 0; + + virtual Cluster& + cluster() = 0; + + virtual PeerReservationTable& + peerReservations() = 0; + + virtual Resource::Manager& + getResourceManager() = 0; + + // Storage services + virtual NodeStore::Database& + getNodeStore() = 0; + + virtual SHAMapStore& + getSHAMapStore() = 0; + + virtual RelationalDatabase& + getRelationalDatabase() = 0; + + // Ledger services + virtual InboundLedgers& + getInboundLedgers() = 0; + + virtual InboundTransactions& + getInboundTransactions() = 0; + + virtual TaggedCache& + getAcceptedLedgerCache() = 0; + + virtual LedgerMaster& + getLedgerMaster() = 0; + + virtual LedgerCleaner& + getLedgerCleaner() = 0; + + virtual LedgerReplayer& + getLedgerReplayer() = 0; + + virtual PendingSaves& + pendingSaves() = 0; + + virtual OpenLedger& + openLedger() = 0; + + virtual OpenLedger const& + openLedger() const = 0; + + // Transaction and operation services + virtual NetworkOPs& + getOPs() = 0; + + virtual OrderBookDB& + getOrderBookDB() = 0; + + virtual TransactionMaster& + getMasterTransaction() = 0; + + virtual TxQ& + getTxQ() = 0; + + virtual PathRequests& + getPathRequests() = 0; + + // Server services + virtual ServerHandler& + getServerHandler() = 0; + + virtual perf::PerfLog& + getPerfLog() = 0; + + // Configuration and state + virtual bool + isStopping() const = 0; + + virtual beast::Journal + journal(std::string const& name) = 0; + + virtual boost::asio::io_context& + getIOContext() = 0; + + virtual Logs& + logs() = 0; + + // Temporary: Get the underlying Application for functions that haven't + // been migrated yet. This should be removed once all code is migrated. + virtual Application& + app() = 0; +}; + +} // namespace xrpl diff --git a/include/xrpl/core/StartUpType.h b/include/xrpl/core/StartUpType.h new file mode 100644 index 0000000000..74a1898806 --- /dev/null +++ b/include/xrpl/core/StartUpType.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace xrpl { + +enum class StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK }; + +inline std::ostream& +operator<<(std::ostream& os, StartUpType const& type) +{ + return os << static_cast>(type); +} + +} // namespace xrpl diff --git a/src/xrpld/core/detail/Workers.h b/include/xrpl/core/detail/Workers.h similarity index 74% rename from src/xrpld/core/detail/Workers.h rename to include/xrpl/core/detail/Workers.h index 3f41e382b0..c5df622fa1 100644 --- a/src/xrpld/core/detail/Workers.h +++ b/include/xrpl/core/detail/Workers.h @@ -1,28 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_WORKERS_H_INCLUDED -#define RIPPLE_CORE_WORKERS_H_INCLUDED - -#include +#pragma once #include +#include #include #include @@ -30,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace perf { class PerfLog; @@ -115,8 +94,7 @@ public: Callback& callback, perf::PerfLog* perfLog, std::string const& threadNames = "Worker", - int numberOfThreads = - static_cast(std::thread::hardware_concurrency())); + int numberOfThreads = static_cast(std::thread::hardware_concurrency())); ~Workers(); @@ -182,14 +160,10 @@ private: Idle: Active, but blocked on waiting for a task. Paused: Blocked waiting to exit or become active. */ - class Worker : public beast::LockFreeStack::Node, - public beast::LockFreeStack::Node + class Worker : public beast::LockFreeStack::Node, public beast::LockFreeStack::Node { public: - Worker( - Workers& workers, - std::string const& threadName, - int const instance); + Worker(Workers& workers, std::string const& threadName, int const instance); ~Worker(); @@ -223,17 +197,13 @@ private: std::condition_variable m_cv; // signaled when all threads paused std::mutex m_mut; bool m_allPaused; - semaphore m_semaphore; // each pending task is 1 resource - int m_numberOfThreads; // how many we want active now - std::atomic m_activeCount; // to know when all are paused - std::atomic m_pauseCount; // how many threads need to pause now - std::atomic - m_runningTaskCount; // how many calls to processTask() active - beast::LockFreeStack m_everyone; // holds all created workers - beast::LockFreeStack - m_paused; // holds just paused workers + semaphore m_semaphore; // each pending task is 1 resource + int m_numberOfThreads; // how many we want active now + std::atomic m_activeCount; // to know when all are paused + std::atomic m_pauseCount; // how many threads need to pause now + std::atomic m_runningTaskCount; // how many calls to processTask() active + beast::LockFreeStack m_everyone; // holds all created workers + beast::LockFreeStack m_paused; // holds just paused workers }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/core/detail/semaphore.h b/include/xrpl/core/detail/semaphore.h similarity index 62% rename from src/xrpld/core/detail/semaphore.h rename to include/xrpl/core/detail/semaphore.h index fbeb79c66a..fad3bf5e29 100644 --- a/src/xrpld/core/detail/semaphore.h +++ b/include/xrpl/core/detail/semaphore.h @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - /** * - * TODO: Remove ripple::basic_semaphore (and this file) and use + * TODO: Remove xrpl::basic_semaphore (and this file) and use * std::counting_semaphore. * * Background: @@ -45,13 +26,12 @@ * version is updated. */ -#ifndef RIPPLE_CORE_SEMAPHORE_H_INCLUDED -#define RIPPLE_CORE_SEMAPHORE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { template class basic_semaphore @@ -106,6 +86,4 @@ public: using semaphore = basic_semaphore; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/crypto/RFC1751.h b/include/xrpl/crypto/RFC1751.h index fa70830b79..64b3e08813 100644 --- a/include/xrpl/crypto/RFC1751.h +++ b/include/xrpl/crypto/RFC1751.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CRYPTO_RFC1751_H_INCLUDED -#define RIPPLE_CRYPTO_RFC1751_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class RFC1751 { @@ -61,6 +41,4 @@ private: static char const* s_dictionary[]; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/crypto/csprng.h b/include/xrpl/crypto/csprng.h index 9a4e933a2e..e5135c96d7 100644 --- a/include/xrpl/crypto/csprng.h +++ b/include/xrpl/crypto/csprng.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CRYPTO_RANDOM_H_INCLUDED -#define RIPPLE_CRYPTO_RANDOM_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** A cryptographically secure random number engine @@ -89,6 +69,4 @@ public: csprng_engine& crypto_prng(); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/crypto/secure_erase.h b/include/xrpl/crypto/secure_erase.h index d7eceab87a..2815a8531a 100644 --- a/include/xrpl/crypto/secure_erase.h +++ b/include/xrpl/crypto/secure_erase.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CRYPTO_SECURE_ERASE_H_INCLUDED -#define RIPPLE_CRYPTO_SECURE_ERASE_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Attempts to clear the given blob of memory. @@ -41,6 +21,4 @@ namespace ripple { void secure_erase(void* dest, std::size_t bytes); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/json/JsonPropertyStream.h b/include/xrpl/json/JsonPropertyStream.h index fdc2197197..510ed72950 100644 --- a/include/xrpl/json/JsonPropertyStream.h +++ b/include/xrpl/json/JsonPropertyStream.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED -#define RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** A PropertyStream::Sink which produces a Json::Value of type objectValue. */ class JsonPropertyStream : public beast::PropertyStream @@ -85,6 +65,4 @@ protected: add(std::string const& v) override; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/json/Object.h b/include/xrpl/json/Object.h deleted file mode 100644 index 87ef8ea4f2..0000000000 --- a/include/xrpl/json/Object.h +++ /dev/null @@ -1,464 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_OBJECT_H_INCLUDED -#define RIPPLE_JSON_OBJECT_H_INCLUDED - -#include - -#include - -namespace Json { - -/** - Collection is a base class for Array and Object, classes which provide the - facade of JSON collections for the O(1) JSON writer, while still using no - heap memory and only a very small amount of stack. - - From http://json.org, JSON has two types of collection: array, and object. - Everything else is a *scalar* - a number, a string, a boolean, the special - value null, or a legacy Json::Value. - - Collections must write JSON "as-it-goes" in order to get the strong - performance guarantees. This puts restrictions upon API users: - - 1. Only one collection can be open for change at any one time. - - This condition is enforced automatically and a std::logic_error thrown if - it is violated. - - 2. A tag may only be used once in an Object. - - Some objects have many tags, so this condition might be a little - expensive. Enforcement of this condition is turned on in debug builds and - a std::logic_error is thrown when the tag is added for a second time. - - Code samples: - - Writer writer; - - // An empty object. - { - Object::Root (writer); - } - // Outputs {} - - // An object with one scalar value. - { - Object::Root root (writer); - write["hello"] = "world"; - } - // Outputs {"hello":"world"} - - // Same, using chaining. - { - Object::Root (writer)["hello"] = "world"; - } - // Output is the same. - - // Add several scalars, with chaining. - { - Object::Root (writer) - .set ("hello", "world") - .set ("flag", false) - .set ("x", 42); - } - // Outputs {"hello":"world","flag":false,"x":42} - - // Add an array. - { - Object::Root root (writer); - { - auto array = root.setArray ("hands"); - array.append ("left"); - array.append ("right"); - } - } - // Outputs {"hands":["left", "right"]} - - // Same, using chaining. - { - Object::Root (writer) - .setArray ("hands") - .append ("left") - .append ("right"); - } - // Output is the same. - - // Add an object. - { - Object::Root root (writer); - { - auto object = root.setObject ("hands"); - object["left"] = false; - object["right"] = true; - } - } - // Outputs {"hands":{"left":false,"right":true}} - - // Same, using chaining. - { - Object::Root (writer) - .setObject ("hands") - .set ("left", false) - .set ("right", true); - } - } - // Outputs {"hands":{"left":false,"right":true}} - - - Typical ways to make mistakes and get a std::logic_error: - - Writer writer; - Object::Root root (writer); - - // Repeat a tag. - { - root ["hello"] = "world"; - root ["hello"] = "there"; // THROWS! in a debug build. - } - - // Open a subcollection, then set something else. - { - auto object = root.setObject ("foo"); - root ["hello"] = "world"; // THROWS! - } - - // Open two subcollections at a time. - { - auto object = root.setObject ("foo"); - auto array = root.setArray ("bar"); // THROWS!! - } - - For more examples, check the unit tests. - */ - -class Collection -{ -public: - Collection(Collection&& c) noexcept; - Collection& - operator=(Collection&& c) noexcept; - Collection() = delete; - - ~Collection(); - -protected: - // A null parent means "no parent at all". - // Writers cannot be null. - Collection(Collection* parent, Writer*); - void - checkWritable(std::string const& label); - - Collection* parent_; - Writer* writer_; - bool enabled_; -}; - -class Array; - -//------------------------------------------------------------------------------ - -/** Represents a JSON object being written to a Writer. */ -class Object : protected Collection -{ -public: - /** Object::Root is the only Collection that has a public constructor. */ - class Root; - - /** Set a scalar value in the Object for a key. - - A JSON scalar is a single value - a number, string, boolean, nullptr or - a Json::Value. - - `set()` throws an exception if this object is disabled (which means that - one of its children is enabled). - - In a debug build, `set()` also throws an exception if the key has - already been set() before. - - An operator[] is provided to allow writing `object["key"] = scalar;`. - */ - template - void - set(std::string const& key, Scalar const&); - - void - set(std::string const& key, Json::Value const&); - - // Detail class and method used to implement operator[]. - class Proxy; - - Proxy - operator[](std::string const& key); - Proxy - operator[](Json::StaticString const& key); - - /** Make a new Object at a key and return it. - - This Object is disabled until that sub-object is destroyed. - Throws an exception if this Object was already disabled. - */ - Object - setObject(std::string const& key); - - /** Make a new Array at a key and return it. - - This Object is disabled until that sub-array is destroyed. - Throws an exception if this Object was already disabled. - */ - Array - setArray(std::string const& key); - -protected: - friend class Array; - Object(Collection* parent, Writer* w) : Collection(parent, w) - { - } -}; - -class Object::Root : public Object -{ -public: - /** Each Object::Root must be constructed with its own unique Writer. */ - Root(Writer&); -}; - -//------------------------------------------------------------------------------ - -/** Represents a JSON array being written to a Writer. */ -class Array : private Collection -{ -public: - /** Append a scalar to the Arrary. - - Throws an exception if this array is disabled (which means that one of - its sub-collections is enabled). - */ - template - void - append(Scalar const&); - - /** - Appends a Json::Value to an array. - Throws an exception if this Array was disabled. - */ - void - append(Json::Value const&); - - /** Append a new Object and return it. - - This Array is disabled until that sub-object is destroyed. - Throws an exception if this Array was disabled. - */ - Object - appendObject(); - - /** Append a new Array and return it. - - This Array is disabled until that sub-array is destroyed. - Throws an exception if this Array was already disabled. - */ - Array - appendArray(); - -protected: - friend class Object; - Array(Collection* parent, Writer* w) : Collection(parent, w) - { - } -}; - -//------------------------------------------------------------------------------ - -// Generic accessor functions to allow Json::Value and Collection to -// interoperate. - -/** Add a new subarray at a named key in a Json object. */ -Json::Value& -setArray(Json::Value&, Json::StaticString const& key); - -/** Add a new subarray at a named key in a Json object. */ -Array -setArray(Object&, Json::StaticString const& key); - -/** Add a new subobject at a named key in a Json object. */ -Json::Value& -addObject(Json::Value&, Json::StaticString const& key); - -/** Add a new subobject at a named key in a Json object. */ -Object -addObject(Object&, Json::StaticString const& key); - -/** Append a new subarray to a Json array. */ -Json::Value& -appendArray(Json::Value&); - -/** Append a new subarray to a Json array. */ -Array -appendArray(Array&); - -/** Append a new subobject to a Json object. */ -Json::Value& -appendObject(Json::Value&); - -/** Append a new subobject to a Json object. */ -Object -appendObject(Array&); - -/** Copy all the keys and values from one object into another. */ -void -copyFrom(Json::Value& to, Json::Value const& from); - -/** Copy all the keys and values from one object into another. */ -void -copyFrom(Object& to, Json::Value const& from); - -/** An Object that contains its own Writer. */ -class WriterObject -{ -public: - WriterObject(Output const& output) - : writer_(std::make_unique(output)) - , object_(std::make_unique(*writer_)) - { - } - - WriterObject(WriterObject&& other) = default; - - Object* - operator->() - { - return object_.get(); - } - - Object& - operator*() - { - return *object_; - } - -private: - std::unique_ptr writer_; - std::unique_ptr object_; -}; - -WriterObject -stringWriterObject(std::string&); - -//------------------------------------------------------------------------------ -// Implementation details. - -// Detail class for Object::operator[]. -class Object::Proxy -{ -private: - Object& object_; - std::string const key_; - -public: - Proxy(Object& object, std::string const& key); - - template - void - operator=(T const& t) - { - object_.set(key_, t); - // Note: This function shouldn't return *this, because it's a trap. - // - // In Json::Value, foo[jss::key] returns a reference to a - // mutable Json::Value contained _inside_ foo. But in the case of - // Json::Object, where we write once only, there isn't any such - // reference that can be returned. Returning *this would return an - // object "a level higher" than in Json::Value, leading to obscure bugs, - // particularly in generic code. - } -}; - -//------------------------------------------------------------------------------ - -template -void -Array::append(Scalar const& value) -{ - checkWritable("append"); - if (writer_) - writer_->append(value); -} - -template -void -Object::set(std::string const& key, Scalar const& value) -{ - checkWritable("set"); - if (writer_) - writer_->set(key, value); -} - -inline Json::Value& -setArray(Json::Value& json, Json::StaticString const& key) -{ - return (json[key] = Json::arrayValue); -} - -inline Array -setArray(Object& json, Json::StaticString const& key) -{ - return json.setArray(std::string(key)); -} - -inline Json::Value& -addObject(Json::Value& json, Json::StaticString const& key) -{ - return (json[key] = Json::objectValue); -} - -inline Object -addObject(Object& object, Json::StaticString const& key) -{ - return object.setObject(std::string(key)); -} - -inline Json::Value& -appendArray(Json::Value& json) -{ - return json.append(Json::arrayValue); -} - -inline Array -appendArray(Array& json) -{ - return json.appendArray(); -} - -inline Json::Value& -appendObject(Json::Value& json) -{ - return json.append(Json::objectValue); -} - -inline Object -appendObject(Array& json) -{ - return json.appendObject(); -} - -} // namespace Json - -#endif diff --git a/include/xrpl/json/Output.h b/include/xrpl/json/Output.h index ef5f68e518..b0ba3fa6d4 100644 --- a/include/xrpl/json/Output.h +++ b/include/xrpl/json/Output.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_OUTPUT_H_INCLUDED -#define RIPPLE_JSON_OUTPUT_H_INCLUDED +#pragma once #include @@ -34,9 +14,7 @@ using Output = std::function; inline Output stringOutput(std::string& s) { - return [&](boost::beast::string_view const& b) { - s.append(b.data(), b.size()); - }; + return [&](boost::beast::string_view const& b) { s.append(b.data(), b.size()); }; } /** Writes a minimal representation of a Json value to an Output in O(n) time. @@ -56,5 +34,3 @@ std::string jsonAsString(Json::Value const&); } // namespace Json - -#endif diff --git a/include/xrpl/json/Writer.h b/include/xrpl/json/Writer.h index f4c37c3316..e348e57825 100644 --- a/include/xrpl/json/Writer.h +++ b/include/xrpl/json/Writer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_WRITER_H_INCLUDED -#define RIPPLE_JSON_WRITER_H_INCLUDED +#pragma once #include #include @@ -253,9 +233,7 @@ inline void check(bool condition, std::string const& message) { if (!condition) - ripple::Throw(message); + xrpl::Throw(message); } } // namespace Json - -#endif diff --git a/include/xrpl/json/detail/json_assert.h b/include/xrpl/json/detail/json_assert.h index 5d680e6e34..e9a66ccef1 100644 --- a/include/xrpl/json/detail/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -1,30 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_ASSERT_H_INCLUDED -#define RIPPLE_JSON_JSON_ASSERT_H_INCLUDED +#pragma once #include #include #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) \ - ripple::Throw(message); - -#endif + xrpl::Throw(message); diff --git a/include/xrpl/json/json_errors.h b/include/xrpl/json/json_errors.h index 4bed420409..5cbf3bd2a5 100644 --- a/include/xrpl/json/json_errors.h +++ b/include/xrpl/json/json_errors.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_ERRORS_H_INCLUDED -#define RIPPLE_JSON_JSON_ERRORS_H_INCLUDED +#pragma once #include @@ -30,5 +10,3 @@ struct error : std::runtime_error }; } // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED diff --git a/include/xrpl/json/json_forwards.h b/include/xrpl/json/json_forwards.h index e77ea58169..612648a5f4 100644 --- a/include/xrpl/json/json_forwards.h +++ b/include/xrpl/json/json_forwards.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED -#define RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED +#pragma once namespace Json { @@ -32,5 +12,3 @@ class ValueIterator; class ValueConstIterator; } // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED diff --git a/include/xrpl/json/json_reader.h b/include/xrpl/json/json_reader.h index 8eceee1f1c..3a1bc38929 100644 --- a/include/xrpl/json/json_reader.h +++ b/include/xrpl/json/json_reader.h @@ -1,26 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_READER_H_INCLUDED -#define RIPPLE_JSON_JSON_READER_H_INCLUDED - -#define CPPTL_JSON_READER_H_INCLUDED +#pragma once #include #include @@ -87,7 +65,7 @@ public: * error occurred during parsing. */ std::string - getFormatedErrorMessages() const; + getFormattedErrorMessages() const; static constexpr unsigned nest_limit{25}; @@ -165,26 +143,15 @@ private: bool decodeDouble(Token& token); bool - decodeUnicodeCodePoint( - Token& token, - Location& current, - Location end, - unsigned int& unicode); + decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode); bool - decodeUnicodeEscapeSequence( - Token& token, - Location& current, - Location end, - unsigned int& unicode); + decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode); bool addError(std::string const& message, Token& token, Location extra = 0); bool recoverFromError(TokenType skipUntilToken); bool - addErrorAndRecover( - std::string const& message, - Token& token, - TokenType skipUntilToken); + addErrorAndRecover(std::string const& message, Token& token, TokenType skipUntilToken); void skipUntilSpace(); Value& @@ -249,5 +216,3 @@ std::istream& operator>>(std::istream&, Value&); } // namespace Json - -#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h index 272d12d680..5895c94065 100644 --- a/include/xrpl/json/json_value.h +++ b/include/xrpl/json/json_value.h @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED -#define RIPPLE_JSON_JSON_VALUE_H_INCLUDED +#pragma once #include #include #include +#include #include #include #include @@ -62,7 +43,7 @@ enum ValueType { class StaticString { public: - constexpr explicit StaticString(char const* czstring) : str_(czstring) + constexpr explicit StaticString(char const* czString) : str_(czString) { } @@ -158,19 +139,15 @@ public: using ArrayIndex = UInt; static Value const null; - static Int const minInt; - static Int const maxInt; - static UInt const maxUInt; + static constexpr Int minInt = std::numeric_limits::min(); + static constexpr Int maxInt = std::numeric_limits::max(); + static constexpr UInt maxUInt = std::numeric_limits::max(); private: class CZString { public: - enum DuplicationPolicy { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; CZString(int index); CZString(char const* cstr, DuplicationPolicy allocate); CZString(CZString const& other); @@ -217,7 +194,7 @@ public: Value(UInt value); Value(double value); Value(char const* value); - Value(ripple::Number const& value); + Value(xrpl::Number const& value); /** \brief Constructs a value from a static string. * Like other value string constructor but do not duplicate the string for @@ -263,6 +240,10 @@ public: bool asBool() const; + /** Correct absolute value from int or unsigned int */ + UInt + asAbsUInt() const; + // TODO: What is the "empty()" method this docstring mentions? /** isNull() tests to see if this field is null. Don't use this method to test for emptiness: use empty(). */ @@ -395,6 +376,9 @@ public: /// Return true if the object has a member named key. bool isMember(std::string const& key) const; + /// Return true if the object has a member named key. + bool + isMember(StaticString const& key) const; /// \brief Return a list of the member names. /// @@ -441,7 +425,7 @@ private: }; inline Value -to_json(ripple::Number const& number) +to_json(xrpl::Number const& number) { return to_string(number); } @@ -692,5 +676,3 @@ public: }; } // namespace Json - -#endif // CPPTL_JSON_H_INCLUDED diff --git a/include/xrpl/json/json_writer.h b/include/xrpl/json/json_writer.h index ba3a51013f..9455d4abd9 100644 --- a/include/xrpl/json/json_writer.h +++ b/include/xrpl/json/json_writer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_JSON_WRITER_H_INCLUDED -#define RIPPLE_JSON_JSON_WRITER_H_INCLUDED +#pragma once #include #include @@ -109,7 +89,7 @@ private: void writeArrayValue(Value const& value); bool - isMultineArray(Value const& value); + isMultilineArray(Value const& value); void pushValue(std::string const& value); void @@ -176,7 +156,7 @@ private: void writeArrayValue(Value const& value); bool - isMultineArray(Value const& value); + isMultilineArray(Value const& value); void pushValue(std::string const& value); void @@ -335,14 +315,9 @@ public: operator<<(std::ostream& o, Compact const& cJv) { detail::write_value( - [&o](void const* data, std::size_t n) { - o.write(static_cast(data), n); - }, - cJv.jv_); + [&o](void const* data, std::size_t n) { o.write(static_cast(data), n); }, cJv.jv_); return o; } }; } // namespace Json - -#endif // JSON_WRITER_H_INCLUDED diff --git a/include/xrpl/json/to_string.h b/include/xrpl/json/to_string.h index 5b20293f06..fb379f5759 100644 --- a/include/xrpl/json/to_string.h +++ b/include/xrpl/json/to_string.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_TO_STRING_H_INCLUDED -#define RIPPLE_JSON_TO_STRING_H_INCLUDED +#pragma once #include #include @@ -40,5 +20,3 @@ std::ostream& operator<<(std::ostream&, Value const& root); } // namespace Json - -#endif // JSON_TO_STRING_H_INCLUDED diff --git a/include/xrpl/ledger/ApplyView.h b/include/xrpl/ledger/ApplyView.h index f90033966a..2de5f79452 100644 --- a/include/xrpl/ledger/ApplyView.h +++ b/include/xrpl/ledger/ApplyView.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED -#define RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { enum ApplyFlags : std::uint32_t { tapNONE = 0x00, @@ -53,23 +33,17 @@ constexpr ApplyFlags operator|(ApplyFlags const& lhs, ApplyFlags const& rhs) { return safe_cast( - safe_cast>(lhs) | - safe_cast>(rhs)); + safe_cast>(lhs) | safe_cast>(rhs)); } -static_assert( - (tapFAIL_HARD | tapRETRY) == safe_cast(0x30u), - "ApplyFlags operator |"); -static_assert( - (tapRETRY | tapFAIL_HARD) == safe_cast(0x30u), - "ApplyFlags operator |"); +static_assert((tapFAIL_HARD | tapRETRY) == safe_cast(0x30u), "ApplyFlags operator |"); +static_assert((tapRETRY | tapFAIL_HARD) == safe_cast(0x30u), "ApplyFlags operator |"); constexpr ApplyFlags operator&(ApplyFlags const& lhs, ApplyFlags const& rhs) { return safe_cast( - safe_cast>(lhs) & - safe_cast>(rhs)); + safe_cast>(lhs) & safe_cast>(rhs)); } static_assert((tapFAIL_HARD & tapRETRY) == tapNONE, "ApplyFlags operator &"); @@ -78,13 +52,10 @@ static_assert((tapRETRY & tapFAIL_HARD) == tapNONE, "ApplyFlags operator &"); constexpr ApplyFlags operator~(ApplyFlags const& flags) { - return safe_cast( - ~safe_cast>(flags)); + return safe_cast(~safe_cast>(flags)); } -static_assert( - ~tapRETRY == safe_cast(0xFFFFFFDFu), - "ApplyFlags operator ~"); +static_assert(~tapRETRY == safe_cast(0xFFFFFFDFu), "ApplyFlags operator ~"); inline ApplyFlags operator|=(ApplyFlags& lhs, ApplyFlags const& rhs) @@ -240,21 +211,14 @@ public: // Called when a credit is made to an account // This is required to support PaymentSandbox virtual void - creditHook( - AccountID const& from, - AccountID const& to, - STAmount const& amount, - STAmount const& preCreditBalance) + creditHook(AccountID const& from, AccountID const& to, STAmount const& amount, STAmount const& preCreditBalance) { } // Called when the owner count changes // This is required to support PaymentSandbox virtual void - adjustOwnerCountHook( - AccountID const& account, - std::uint32_t cur, - std::uint32_t next) + adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) { } @@ -286,7 +250,7 @@ public: { // LCOV_EXCL_START UNREACHABLE( - "ripple::ApplyView::dirAppend : only Offers are appended to " + "xrpl::ApplyView::dirAppend : only Offers are appended to " "book directories"); // Only Offers are appended to book directories. Call dirInsert() // instead @@ -351,18 +315,10 @@ public: */ /** @{ */ bool - dirRemove( - Keylet const& directory, - std::uint64_t page, - uint256 const& key, - bool keepRoot); + dirRemove(Keylet const& directory, std::uint64_t page, uint256 const& key, bool keepRoot); bool - dirRemove( - Keylet const& directory, - std::uint64_t page, - Keylet const& key, - bool keepRoot) + dirRemove(Keylet const& directory, std::uint64_t page, Keylet const& key, bool keepRoot) { return dirRemove(directory, page, key.key, keepRoot); } @@ -370,9 +326,7 @@ public: /** Remove the specified directory, invoking the callback for every node. */ bool - dirDelete( - Keylet const& directory, - std::function const&); + dirDelete(Keylet const& directory, std::function const&); /** Remove the specified directory, if it is empty. @@ -387,6 +341,43 @@ public: emptyDirDelete(Keylet const& directory); }; -} // namespace ripple +namespace directory { +/** Helper functions for managing low-level directory operations. + These are not part of the ApplyView interface. -#endif + Don't use them unless you really, really know what you're doing. + Instead use dirAdd, dirInsert, etc. + */ + +std::uint64_t +createRoot( + ApplyView& view, + Keylet const& directory, + uint256 const& key, + std::function const&)> const& describe); + +auto +findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start); + +std::uint64_t +insertKey( + ApplyView& view, + SLE::ref node, + std::uint64_t page, + bool preserveOrder, + STVector256& indexes, + uint256 const& key); + +std::optional +insertPage( + ApplyView& view, + std::uint64_t page, + SLE::pointer node, + std::uint64_t nextPage, + SLE::ref next, + uint256 const& key, + Keylet const& directory, + std::function const&)> const& describe); + +} // namespace directory +} // namespace xrpl diff --git a/include/xrpl/ledger/ApplyViewImpl.h b/include/xrpl/ledger/ApplyViewImpl.h index eadcd8acb5..f6c83462f2 100644 --- a/include/xrpl/ledger/ApplyViewImpl.h +++ b/include/xrpl/ledger/ApplyViewImpl.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED -#define RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { /** Editable, discardable view that can build metadata for one tx. @@ -53,13 +33,7 @@ public: destructor. */ std::optional - apply( - OpenView& to, - STTx const& tx, - TER ter, - std::optional parentBatchId, - bool isDryRun, - beast::Journal j); + apply(OpenView& to, STTx const& tx, TER ter, std::optional parentBatchId, bool isDryRun, beast::Journal j); /** Set the amount of currency delivered. @@ -94,6 +68,4 @@ private: std::optional deliver_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/BookDirs.h b/include/xrpl/ledger/BookDirs.h index 95cd41e044..eb1cbcbfa7 100644 --- a/include/xrpl/ledger/BookDirs.h +++ b/include/xrpl/ledger/BookDirs.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED -#define RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class BookDirs { @@ -87,10 +67,7 @@ public: private: friend class BookDirs; - const_iterator( - ReadView const& view, - uint256 const& root, - uint256 const& dir_key) + const_iterator(ReadView const& view, uint256 const& root, uint256 const& dir_key) : view_(&view), root_(root), key_(dir_key), cur_key_(dir_key) { } @@ -108,6 +85,4 @@ private: static beast::Journal j_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/CachedSLEs.h b/include/xrpl/ledger/CachedSLEs.h index bc94092e20..2909501b1d 100644 --- a/include/xrpl/ledger/CachedSLEs.h +++ b/include/xrpl/ledger/CachedSLEs.h @@ -1,31 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED -#define RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { using CachedSLEs = TaggedCache; } - -#endif // RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED diff --git a/include/xrpl/ledger/CachedView.h b/include/xrpl/ledger/CachedView.h index 3e1fb9cc72..7cab1dc1b3 100644 --- a/include/xrpl/ledger/CachedView.h +++ b/include/xrpl/ledger/CachedView.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED -#define RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -45,8 +25,7 @@ public: CachedViewImpl& operator=(CachedViewImpl const&) = delete; - CachedViewImpl(DigestAwareReadView const* base, CachedSLEs& cache) - : base_(*base), cache_(cache) + CachedViewImpl(DigestAwareReadView const* base, CachedSLEs& cache) : base_(*base), cache_(cache) { } @@ -66,10 +45,10 @@ public: return base_.open(); } - LedgerInfo const& - info() const override + LedgerHeader const& + header() const override { - return base_.info(); + return base_.header(); } Fees const& @@ -85,9 +64,7 @@ public: } std::optional - succ( - key_type const& key, - std::optional const& last = std::nullopt) const override + succ(key_type const& key, std::optional const& last = std::nullopt) const override { return base_.succ(key, last); } @@ -183,6 +160,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/CredentialHelpers.h b/include/xrpl/ledger/CredentialHelpers.h index cb6b3c98ee..3744ff47eb 100644 --- a/include/xrpl/ledger/CredentialHelpers.h +++ b/include/xrpl/ledger/CredentialHelpers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED -#define RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED +#pragma once #include #include @@ -30,18 +10,16 @@ #include #include -namespace ripple { +namespace xrpl { namespace credentials { // These function will be used by the code that use DepositPreauth / Credentials -// (and any future preauthorization modes) as part of authorization (all the +// (and any future pre-authorization modes) as part of authorization (all the // transfer funds transactions) // Check if credential sfExpiration field has passed ledger's parentCloseTime bool -checkExpired( - std::shared_ptr const& sleCredential, - NetClock::time_point const& closed); +checkExpired(std::shared_ptr const& sleCredential, NetClock::time_point const& closed); // Return true if any expired credential was found in arr (and deleted) bool @@ -49,10 +27,7 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j); // Actually remove a credentials object from the ledger TER -deleteSLE( - ApplyView& view, - std::shared_ptr const& sleCredential, - beast::Journal j); +deleteSLE(ApplyView& view, std::shared_ptr const& sleCredential, beast::Journal j); // Amendment and parameters checks for sfCredentialIDs field NotTEC @@ -60,13 +35,10 @@ checkFields(STTx const& tx, beast::Journal j); // Accessing the ledger to check if provided credentials are valid. Do not use // in doApply (only in preclaim) since it does not remove expired credentials. -// If you call it in prelaim, you also must call verifyDepositPreauth in doApply +// If you call it in preclaim, you also must call verifyDepositPreauth in +// doApply TER -valid( - STTx const& tx, - ReadView const& view, - AccountID const& src, - beast::Journal j); +valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal j); // Check if subject has any credential maching the given domain. If you call it // in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in @@ -77,10 +49,7 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject); // This function is only called when we about to return tecNO_PERMISSION // because all the checks for the DepositPreauth authorization failed. TER -authorizedDepositPreauth( - ApplyView const& view, - STVector256 const& ctx, - AccountID const& dst); +authorizedDepositPreauth(ApplyView const& view, STVector256 const& ctx, AccountID const& dst); // Sort credentials array, return empty set if there are duplicates std::set> @@ -96,11 +65,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j); // Check expired credentials and for credentials maching DomainID of the ledger // object TER -verifyValidDomain( - ApplyView& view, - AccountID const& account, - uint256 domainID, - beast::Journal j); +verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j); // Check expired credentials and for existing DepositPreauth ledger object TER @@ -112,6 +77,4 @@ verifyDepositPreauth( std::shared_ptr const& sleDst, beast::Journal j); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/Credit.h b/include/xrpl/ledger/Credit.h new file mode 100644 index 0000000000..58ec23a86a --- /dev/null +++ b/include/xrpl/ledger/Credit.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +namespace xrpl { + +/** Calculate the maximum amount of IOUs that an account can hold + @param ledger the ledger to check against. + @param account the account of interest. + @param issuer the issuer of the IOU. + @param currency the IOU to check. + @return The maximum amount that can be held. +*/ +/** @{ */ +STAmount +creditLimit(ReadView const& view, AccountID const& account, AccountID const& issuer, Currency const& currency); + +IOUAmount +creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur); +/** @} */ + +/** Returns the amount of IOUs issued by issuer that are held by an account + @param ledger the ledger to check against. + @param account the account of interest. + @param issuer the issuer of the IOU. + @param currency the IOU to check. +*/ +/** @{ */ +STAmount +creditBalance(ReadView const& view, AccountID const& account, AccountID const& issuer, Currency const& currency); +/** @} */ + +} // namespace xrpl diff --git a/include/xrpl/ledger/Dir.h b/include/xrpl/ledger/Dir.h index 0e9e5e998f..0c2f1e3765 100644 --- a/include/xrpl/ledger/Dir.h +++ b/include/xrpl/ledger/Dir.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_DIR_H_INCLUDED -#define RIPPLE_LEDGER_DIR_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** A class that simplifies iterating ledger directory pages @@ -127,6 +107,4 @@ private: std::vector::const_iterator it_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/OpenView.h b/include/xrpl/ledger/OpenView.h index e856e03764..42f62d5bca 100644 --- a/include/xrpl/ledger/OpenView.h +++ b/include/xrpl/ledger/OpenView.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_OPENVIEW_H_INCLUDED -#define RIPPLE_LEDGER_OPENVIEW_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Open ledger construction tag. @@ -77,9 +57,7 @@ private: std::shared_ptr meta; // Constructor needed for emplacement in std::map - txData( - std::shared_ptr const& txn_, - std::shared_ptr const& meta_) + txData(std::shared_ptr const& txn_, std::shared_ptr const& meta_) : txn(txn_), meta(meta_) { } @@ -92,16 +70,14 @@ private: key_type, txData, std::less, - boost::container::pmr::polymorphic_allocator< - std::pair>>; + boost::container::pmr::polymorphic_allocator>>; // monotonic_resource_ must outlive `items_`. Make a pointer so it may be // easily moved. - std::unique_ptr - monotonic_resource_; + std::unique_ptr monotonic_resource_; txs_map txs_; Rules rules_; - LedgerInfo info_; + LedgerHeader header_; ReadView const* base_; detail::RawStateTable items_; std::shared_ptr hold_; @@ -154,16 +130,9 @@ public: The tx list starts empty and will contain all newly inserted tx. */ - OpenView( - open_ledger_t, - ReadView const* base, - Rules const& rules, - std::shared_ptr hold = nullptr); + OpenView(open_ledger_t, ReadView const* base, Rules const& rules, std::shared_ptr hold = nullptr); - OpenView( - open_ledger_t, - Rules const& rules, - std::shared_ptr const& base) + OpenView(open_ledger_t, Rules const& rules, std::shared_ptr const& base) : OpenView(open_ledger, &*base, rules, base) { } @@ -177,7 +146,7 @@ public: Effects: - The LedgerInfo is copied from the base. + The LedgerHeader is copied from the base. The rules are inherited from the base. @@ -207,8 +176,8 @@ public: // ReadView - LedgerInfo const& - info() const override; + LedgerHeader const& + header() const override; Fees const& fees() const override; @@ -220,9 +189,7 @@ public: exists(Keylet const& k) const override; std::optional - succ( - key_type const& key, - std::optional const& last = std::nullopt) const override; + succ(key_type const& key, std::optional const& last = std::nullopt) const override; std::shared_ptr read(Keylet const& k) const override; @@ -271,6 +238,4 @@ public: std::shared_ptr const& metaData) override; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/PaymentSandbox.h b/include/xrpl/ledger/PaymentSandbox.h index c5bf28d1f9..fe62d753ec 100644 --- a/include/xrpl/ledger/PaymentSandbox.h +++ b/include/xrpl/ledger/PaymentSandbox.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED -#define RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { namespace detail { @@ -38,8 +18,7 @@ class DeferredCredits public: struct Adjustment { - Adjustment(STAmount const& d, STAmount const& c, STAmount const& b) - : debits(d), credits(c), origBalance(b) + Adjustment(STAmount const& d, STAmount const& c, STAmount const& b) : debits(d), credits(c), origBalance(b) { } STAmount debits; @@ -50,10 +29,7 @@ public: // Get the adjustments for the balance between main and other. // Returns the debits, credits and the original balance std::optional - adjustments( - AccountID const& main, - AccountID const& other, - Currency const& currency) const; + adjustments(AccountID const& main, AccountID const& other, Currency const& currency) const; void credit( @@ -121,8 +97,7 @@ public: PaymentSandbox(PaymentSandbox&&) = default; - PaymentSandbox(ReadView const* base, ApplyFlags flags) - : ApplyViewBase(base, flags) + PaymentSandbox(ReadView const* base, ApplyFlags flags) : ApplyViewBase(base, flags) { } @@ -144,39 +119,27 @@ public: // or a PaymentSandbox-derived class, we MUST go through // one of these constructors or invariants will be broken. /** @{ */ - explicit PaymentSandbox(PaymentSandbox const* base) - : ApplyViewBase(base, base->flags()), ps_(base) + explicit PaymentSandbox(PaymentSandbox const* base) : ApplyViewBase(base, base->flags()), ps_(base) { } - explicit PaymentSandbox(PaymentSandbox* base) - : ApplyViewBase(base, base->flags()), ps_(base) + explicit PaymentSandbox(PaymentSandbox* base) : ApplyViewBase(base, base->flags()), ps_(base) { } /** @} */ STAmount - balanceHook( - AccountID const& account, - AccountID const& issuer, - STAmount const& amount) const override; + balanceHook(AccountID const& account, AccountID const& issuer, STAmount const& amount) const override; void - creditHook( - AccountID const& from, - AccountID const& to, - STAmount const& amount, - STAmount const& preCreditBalance) override; + creditHook(AccountID const& from, AccountID const& to, STAmount const& amount, STAmount const& preCreditBalance) + override; void - adjustOwnerCountHook( - AccountID const& account, - std::uint32_t cur, - std::uint32_t next) override; + adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) override; std::uint32_t - ownerCountHook(AccountID const& account, std::uint32_t count) - const override; + ownerCountHook(AccountID const& account, std::uint32_t count) const override; /** Apply changes to base view. @@ -207,6 +170,4 @@ private: PaymentSandbox const* ps_ = nullptr; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/RawView.h b/include/xrpl/ledger/RawView.h index c22fd40132..cfcf807e13 100644 --- a/include/xrpl/ledger/RawView.h +++ b/include/xrpl/ledger/RawView.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_RAWVIEW_H_INCLUDED -#define RIPPLE_LEDGER_RAWVIEW_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Interface for ledger entry changes. @@ -106,6 +86,4 @@ public: std::shared_ptr const& metaData) = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/ReadView.h b/include/xrpl/ledger/ReadView.h index 2c87dbbf6a..faec10993a 100644 --- a/include/xrpl/ledger/ReadView.h +++ b/include/xrpl/ledger/ReadView.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_READVIEW_H_INCLUDED -#define RIPPLE_LEDGER_READVIEW_H_INCLUDED +#pragma once #include #include @@ -37,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { //------------------------------------------------------------------------------ @@ -50,8 +30,7 @@ namespace ripple { class ReadView { public: - using tx_type = - std::pair, std::shared_ptr>; + using tx_type = std::pair, std::shared_ptr>; using key_type = uint256; @@ -99,8 +78,8 @@ public: } /** Returns information about the ledger. */ - virtual LedgerInfo const& - info() const = 0; + virtual LedgerHeader const& + header() const = 0; /** Returns true if this reflects an open ledger. */ virtual bool @@ -110,14 +89,14 @@ public: NetClock::time_point parentCloseTime() const { - return info().parentCloseTime; + return header().parentCloseTime; } /** Returns the sequence number of the base ledger. */ LedgerIndex seq() const { - return info().seq; + return header().seq; } /** Returns the fees for the base ledger. */ @@ -149,9 +128,7 @@ public: interval (key, last). */ virtual std::optional - succ( - key_type const& key, - std::optional const& last = std::nullopt) const = 0; + succ(key_type const& key, std::optional const& last = std::nullopt) const = 0; /** Return the state item associated with a key. @@ -175,10 +152,7 @@ public: // balances so newly acquired assets are not counted toward the balance. // This is required to support PaymentSandbox. virtual STAmount - balanceHook( - AccountID const& account, - AccountID const& issuer, - STAmount const& amount) const + balanceHook(AccountID const& account, AccountID const& issuer, STAmount const& amount) const { return amount; } @@ -273,12 +247,8 @@ Rules makeRulesGivenLedger(DigestAwareReadView const& ledger, Rules const& current); Rules -makeRulesGivenLedger( - DigestAwareReadView const& ledger, - std::unordered_set> const& presets); +makeRulesGivenLedger(DigestAwareReadView const& ledger, std::unordered_set> const& presets); -} // namespace ripple +} // namespace xrpl #include - -#endif diff --git a/include/xrpl/ledger/Sandbox.h b/include/xrpl/ledger/Sandbox.h index 495da120c6..dc80df5ba2 100644 --- a/include/xrpl/ledger/Sandbox.h +++ b/include/xrpl/ledger/Sandbox.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_SANDBOX_H_INCLUDED -#define RIPPLE_LEDGER_SANDBOX_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Discardable, editable view to a ledger. @@ -58,6 +38,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/View.h b/include/xrpl/ledger/View.h index 9698b4fda3..fa16e16006 100644 --- a/include/xrpl/ledger/View.h +++ b/include/xrpl/ledger/View.h @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_VIEW_H_INCLUDED -#define RIPPLE_LEDGER_VIEW_H_INCLUDED +#pragma once #include #include #include #include +#include #include #include #include @@ -38,7 +19,7 @@ #include #include -namespace ripple { +namespace xrpl { enum class WaiveTransferFee : bool { No = false, Yes }; enum class SkipEntry : bool { No = false, Yes }; @@ -79,6 +60,9 @@ enum FreezeHandling { fhIGNORE_FREEZE, fhZERO_IF_FROZEN }; /** Controls the treatment of unauthorized MPT balances */ enum AuthHandling { ahIGNORE_AUTH, ahZERO_IF_UNAUTHORIZED }; +/** Controls whether to include the account's full spendable balance */ +enum SpendableHandling { shSIMPLE_BALANCE, shFULL_BALANCE }; + [[nodiscard]] bool isGlobalFrozen(ReadView const& view, AccountID const& issuer); @@ -90,70 +74,37 @@ isGlobalFrozen(ReadView const& view, Asset const& asset); // Note, depth parameter is used to limit the recursion depth [[nodiscard]] bool -isVaultPseudoAccountFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptShare, - int depth); +isVaultPseudoAccountFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptShare, int depth); [[nodiscard]] bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); +isIndividualFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer); [[nodiscard]] inline bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Issue const& issue) +isIndividualFrozen(ReadView const& view, AccountID const& account, Issue const& issue) { return isIndividualFrozen(view, account, issue.currency, issue.account); } [[nodiscard]] bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue); +isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); [[nodiscard]] inline bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Asset const& asset) +isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset) { - return std::visit( - [&](auto const& issue) { - return isIndividualFrozen(view, account, issue); - }, - asset.value()); + return std::visit([&](auto const& issue) { return isIndividualFrozen(view, account, issue); }, asset.value()); } [[nodiscard]] bool -isFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); +isFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer); [[nodiscard]] inline bool -isFrozen( - ReadView const& view, - AccountID const& account, - Issue const& issue, - int = 0 /*ignored*/) +isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int = 0 /*ignored*/) { return isFrozen(view, account, issue.currency, issue.account); } [[nodiscard]] bool -isFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue, - int depth = 0); +isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0); /** * isFrozen check is recursive for MPT shares in a vault, descending to @@ -161,17 +112,9 @@ isFrozen( * purely defensive, as we currently do not allow such vaults to be created. */ [[nodiscard]] inline bool -isFrozen( - ReadView const& view, - AccountID const& account, - Asset const& asset, - int depth = 0) +isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0) { - return std::visit( - [&](auto const& issue) { - return isFrozen(view, account, issue, depth); - }, - asset.value()); + return std::visit([&](auto const& issue) { return isFrozen(view, account, issue, depth); }, asset.value()); } [[nodiscard]] inline TER @@ -181,10 +124,7 @@ checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue) } [[nodiscard]] inline TER -checkFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue) +checkFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) { return isFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; } @@ -192,9 +132,7 @@ checkFrozen( [[nodiscard]] inline TER checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset) { - return std::visit( - [&](auto const& issue) { return checkFrozen(view, account, issue); }, - asset.value()); + return std::visit([&](auto const& issue) { return checkFrozen(view, account, issue); }, asset.value()); } [[nodiscard]] bool @@ -205,10 +143,7 @@ isAnyFrozen( int depth = 0); [[nodiscard]] inline bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - Issue const& issue) +isAnyFrozen(ReadView const& view, std::initializer_list const& accounts, Issue const& issue) { for (auto const& account : accounts) { @@ -219,11 +154,7 @@ isAnyFrozen( } [[nodiscard]] inline bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - Asset const& asset, - int depth = 0) +isAnyFrozen(ReadView const& view, std::initializer_list const& accounts, Asset const& asset, int depth = 0) { return std::visit( [&](TIss const& issue) { @@ -236,20 +167,65 @@ isAnyFrozen( } [[nodiscard]] bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); +isDeepFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer); + +[[nodiscard]] inline bool +isDeepFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int = 0 /*ignored*/) +{ + return isDeepFrozen(view, account, issue.currency, issue.account); +} + +[[nodiscard]] inline bool +isDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0) +{ + // Unlike IOUs, frozen / locked MPTs are not allowed to send or receive + // funds, so checking "deep frozen" is the same as checking "frozen". + return isFrozen(view, account, mptIssue, depth); +} + +/** + * isFrozen check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. + */ +[[nodiscard]] inline bool +isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0) +{ + return std::visit([&](auto const& issue) { return isDeepFrozen(view, account, issue, depth); }, asset.value()); +} + +[[nodiscard]] inline TER +checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; +} + +[[nodiscard]] inline TER +checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) +{ + return isDeepFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; +} + +[[nodiscard]] inline TER +checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit([&](auto const& issue) { return checkDeepFrozen(view, account, issue); }, asset.value()); +} [[nodiscard]] bool -isLPTokenFrozen( - ReadView const& view, - AccountID const& account, - Issue const& asset, - Issue const& asset2); +isLPTokenFrozen(ReadView const& view, AccountID const& account, Issue const& asset, Issue const& asset2); -// Returns the amount an account can spend without going into debt. +// Returns the amount an account can spend. +// +// If shSIMPLE_BALANCE is specified, this is the amount the account can spend +// without going into debt. +// +// If shFULL_BALANCE is specified, this is the amount the account can spend +// total. Specifically: +// * The account can go into debt if using a trust line, and the other side has +// a non-zero limit. +// * If the account is the asset issuer the limit is defined by the asset / +// issuance. // // <-- saAmount: amount of currency held by account. May be negative. [[nodiscard]] STAmount @@ -259,7 +235,8 @@ accountHolds( Currency const& currency, AccountID const& issuer, FreezeHandling zeroIfFrozen, - beast::Journal j); + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); [[nodiscard]] STAmount accountHolds( @@ -267,7 +244,8 @@ accountHolds( AccountID const& account, Issue const& issue, FreezeHandling zeroIfFrozen, - beast::Journal j); + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); [[nodiscard]] STAmount accountHolds( @@ -276,7 +254,8 @@ accountHolds( MPTIssue const& mptIssue, FreezeHandling zeroIfFrozen, AuthHandling zeroIfUnauthorized, - beast::Journal j); + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); [[nodiscard]] STAmount accountHolds( @@ -285,7 +264,8 @@ accountHolds( Asset const& asset, FreezeHandling zeroIfFrozen, AuthHandling zeroIfUnauthorized, - beast::Journal j); + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); // Returns the amount an account can spend of the currency type saDefault, or // returns saDefault if this account is the issuer of the currency in @@ -307,18 +287,11 @@ accountFunds( // // @param ownerCountAdj positive to add to count, negative to reduce count. [[nodiscard]] XRPAmount -xrpLiquid( - ReadView const& view, - AccountID const& id, - std::int32_t ownerCountAdj, - beast::Journal j); +xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j); /** Iterate all items in the given directory. */ void -forEachItem( - ReadView const& view, - Keylet const& root, - std::function const&)> const& f); +forEachItem(ReadView const& view, Keylet const& root, std::function const&)> const& f); /** Iterate all items after an item in the given directory. @param after The key of the item to start after @@ -337,10 +310,7 @@ forEachItemAfter( /** Iterate all items in an account's owner directory. */ inline void -forEachItem( - ReadView const& view, - AccountID const& id, - std::function const&)> const& f) +forEachItem(ReadView const& view, AccountID const& id, std::function const&)> const& f) { return forEachItem(view, keylet::ownerDir(id), f); } @@ -437,11 +407,7 @@ getCandidateLedger(LedgerIndex requested) use the second form if you have not acquired the valid ledger yet */ [[nodiscard]] bool -areCompatible( - ReadView const& validLedger, - ReadView const& testLedger, - beast::Journal::Stream& s, - char const* reason); +areCompatible(ReadView const& validLedger, ReadView const& testLedger, beast::Journal::Stream& s, char const* reason); [[nodiscard]] bool areCompatible( @@ -459,11 +425,7 @@ areCompatible( /** Adjust the owner count up or down. */ void -adjustOwnerCount( - ApplyView& view, - std::shared_ptr const& sle, - std::int32_t amount, - beast::Journal j); +adjustOwnerCount(ApplyView& view, std::shared_ptr const& sle, std::int32_t amount, beast::Journal j); /** @{ */ /** Returns the first entry in the directory, advancing the index @@ -489,12 +451,7 @@ cdirFirst( uint256& entry); bool -dirFirst( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); +dirFirst(ApplyView& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry); /** @} */ /** @{ */ @@ -521,19 +478,14 @@ cdirNext( uint256& entry); bool -dirNext( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); +dirNext(ApplyView& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry); /** @} */ [[nodiscard]] std::function describeOwnerDir(AccountID const& account); [[nodiscard]] TER -dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr& object); +dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr& object, SF_UINT64 const& node = sfOwnerNode); AccountID pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); @@ -547,19 +499,17 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); * field. The amendment check is **not** performed in createPseudoAccount. */ [[nodiscard]] Expected, TER> -createPseudoAccount( - ApplyView& view, - uint256 const& pseudoOwnerKey, - SField const& ownerField); +createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField); -// Returns true iff sleAcct is a pseudo-account. +// Returns true if and only if sleAcct is a pseudo-account or specific +// pseudo-accounts in pseudoFieldFilter. // // Returns false if sleAcct is // * NOT a pseudo-account OR // * NOT a ltACCOUNT_ROOT OR // * null pointer [[nodiscard]] bool -isPseudoAccount(std::shared_ptr sleAcct); +isPseudoAccount(std::shared_ptr sleAcct, std::set const& pseudoFieldFilter = {}); // Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if // set @@ -573,14 +523,95 @@ isPseudoAccount(std::shared_ptr sleAcct); getPseudoAccountFields(); [[nodiscard]] inline bool -isPseudoAccount(ReadView const& view, AccountID accountId) +isPseudoAccount(ReadView const& view, AccountID const& accountId, std::set const& pseudoFieldFilter = {}) { - return isPseudoAccount(view.read(keylet::account(accountId))); + return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter); } [[nodiscard]] TER canAddHolding(ReadView const& view, Asset const& asset); +/** Validates that the destination SLE and tag are valid + + - Checks that the SLE is not null. + - If the SLE requires a destination tag, checks that there is a tag. +*/ +[[nodiscard]] TER +checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag); + +/** Checks that can withdraw funds from an object to itself or a destination. + * + * The receiver may be either the submitting account (sfAccount) or a different + * destination account (sfDestination). + * + * - Checks that the receiver account exists. + * - If the receiver requires a destination tag, check that one exists, even + * if withdrawing to self. + * - If withdrawing to self, succeed. + * - If not, checks if the receiver requires deposit authorization, and if + * the sender has it. + * - Checks that the receiver will not exceed the limit (IOU trustline limit + * or MPT MaximumAmount). + */ +[[nodiscard]] TER +canWithdraw( + ReadView const& view, + AccountID const& from, + AccountID const& to, + SLE::const_ref toSle, + STAmount const& amount, + bool hasDestinationTag); + +/** Checks that can withdraw funds from an object to itself or a destination. + * + * The receiver may be either the submitting account (sfAccount) or a different + * destination account (sfDestination). + * + * - Checks that the receiver account exists. + * - If the receiver requires a destination tag, check that one exists, even + * if withdrawing to self. + * - If withdrawing to self, succeed. + * - If not, checks if the receiver requires deposit authorization, and if + * the sender has it. + * - Checks that the receiver will not exceed the limit (IOU trustline limit + * or MPT MaximumAmount). + */ +[[nodiscard]] TER +canWithdraw( + ReadView const& view, + AccountID const& from, + AccountID const& to, + STAmount const& amount, + bool hasDestinationTag); + +/** Checks that can withdraw funds from an object to itself or a destination. + * + * The receiver may be either the submitting account (sfAccount) or a different + * destination account (sfDestination). + * + * - Checks that the receiver account exists. + * - If the receiver requires a destination tag, check that one exists, even + * if withdrawing to self. + * - If withdrawing to self, succeed. + * - If not, checks if the receiver requires deposit authorization, and if + * the sender has it. + * - Checks that the receiver will not exceed the limit (IOU trustline limit + * or MPT MaximumAmount). + */ +[[nodiscard]] TER +canWithdraw(ReadView const& view, STTx const& tx); + +[[nodiscard]] TER +doWithdraw( + ApplyView& view, + STTx const& tx, + AccountID const& senderAcct, + AccountID const& dstAcct, + AccountID const& sourceAcct, + XRPAmount priorBalance, + STAmount const& amount, + beast::Journal j); + /// Any transactors that call addEmptyHolding() in doApply must call /// canAddHolding() in preflight with the same View and Asset [[nodiscard]] TER @@ -609,8 +640,7 @@ addEmptyHolding( { return std::visit( [&](TIss const& issue) -> TER { - return addEmptyHolding( - view, accountID, priorBalance, issue, journal); + return addEmptyHolding(view, accountID, priorBalance, issue, journal); }, asset.value()); } @@ -653,25 +683,13 @@ trustCreate( beast::Journal j); [[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Issue const& issue, - beast::Journal journal); +removeEmptyHolding(ApplyView& view, AccountID const& accountID, Issue const& issue, beast::Journal journal); [[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - MPTIssue const& mptIssue, - beast::Journal journal); +removeEmptyHolding(ApplyView& view, AccountID const& accountID, MPTIssue const& mptIssue, beast::Journal journal); [[nodiscard]] inline TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Asset const& asset, - beast::Journal journal) +removeEmptyHolding(ApplyView& view, AccountID const& accountID, Asset const& asset, beast::Journal journal) { return std::visit( [&](TIss const& issue) -> TER { @@ -723,11 +741,7 @@ rippleCredit( beast::Journal j); TER -rippleLockEscrowMPT( - ApplyView& view, - AccountID const& uGrantorID, - STAmount const& saAmount, - beast::Journal j); +rippleLockEscrowMPT(ApplyView& view, AccountID const& uGrantorID, STAmount const& saAmount, beast::Journal j); TER rippleUnlockEscrowMPT( @@ -750,29 +764,30 @@ accountSend( beast::Journal j, WaiveTransferFee waiveFee = WaiveTransferFee::No); +using MultiplePaymentDestinations = std::vector>; +/** Like accountSend, except one account is sending multiple payments (with the + * same asset!) simultaneously + * + * Calls static accountSendMultiIOU if saAmount represents Issue. + * Calls static accountSendMultiMPT if saAmount represents MPTIssue. + */ [[nodiscard]] TER -issueIOU( +accountSendMulti( ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j); + AccountID const& senderID, + Asset const& asset, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee = WaiveTransferFee::No); [[nodiscard]] TER -redeemIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j); +issueIOU(ApplyView& view, AccountID const& account, STAmount const& amount, Issue const& issue, beast::Journal j); [[nodiscard]] TER -transferXRP( - ApplyView& view, - AccountID const& from, - AccountID const& to, - STAmount const& amount, - beast::Journal j); +redeemIOU(ApplyView& view, AccountID const& account, STAmount const& amount, Issue const& issue, beast::Journal j); + +[[nodiscard]] TER +transferXRP(ApplyView& view, AccountID const& from, AccountID const& to, STAmount const& amount, beast::Journal j); /* Check if MPToken (for MPT) or trust line (for IOU) exists: * - StrongAuth - before checking if authorization is required @@ -803,11 +818,7 @@ enum class AuthType { StrongAuth, WeakAuth, Legacy }; * The default "Legacy" auth type is equivalent to WeakAuth. */ [[nodiscard]] TER -requireAuth( - ReadView const& view, - Issue const& issue, - AccountID const& account, - AuthType authType = AuthType::Legacy); +requireAuth(ReadView const& view, Issue const& issue, AccountID const& account, AuthType authType = AuthType::Legacy); /** Check if the account lacks required authorization. * @@ -821,7 +832,8 @@ requireAuth( * purely defensive, as we currently do not allow such vaults to be created. * * If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or - * lsfMPTRequireAuth is set and MPToken is not authorized. + * lsfMPTRequireAuth is set and MPToken is not authorized. Vault and LoanBroker + * pseudo-accounts are implicitly authorized. * * If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken * doesn't exist or is not authorized (explicitly or via credentials, if @@ -846,9 +858,7 @@ requireAuth( AuthType authType = AuthType::Legacy) { return std::visit( - [&](TIss const& issue_) { - return requireAuth(view, issue_, account, authType); - }, + [&](TIss const& issue_) { return requireAuth(view, issue_, account, authType); }, asset.value()); } @@ -888,20 +898,27 @@ enforceMPTokenAuthorization( * and tesSUCCESS otherwise. */ [[nodiscard]] TER -canTransfer( +canTransfer(ReadView const& view, MPTIssue const& mptIssue, AccountID const& from, AccountID const& to); + +[[nodiscard]] TER +canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to); + +[[nodiscard]] TER inline canTransfer( ReadView const& view, - MPTIssue const& mptIssue, + Asset const& asset, AccountID const& from, - AccountID const& to); + AccountID const& to) +{ + return std::visit( + [&](TIss const& issue) -> TER { return canTransfer(view, issue, from, to); }, + asset.value()); +} /** Deleter function prototype. Returns the status of the entry deletion * (if should not be skipped) and if the entry should be skipped. The status * is always tesSUCCESS if the entry should be skipped. */ -using EntryDeleter = std::function( - LedgerEntryType, - uint256 const&, - std::shared_ptr&)>; +using EntryDeleter = std::function(LedgerEntryType, uint256 const&, std::shared_ptr&)>; /** Cleanup owner directory entries on account delete. * Used for a regular and AMM accounts deletion. The caller * has to provide the deleter function, which handles details of @@ -977,6 +994,4 @@ sharesToAssetsWithdraw( bool after(NetClock::time_point now, std::uint32_t mark); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/detail/ApplyStateTable.h b/include/xrpl/ledger/detail/ApplyStateTable.h index 01ab1e07ab..07af5247f6 100644 --- a/include/xrpl/ledger/detail/ApplyStateTable.h +++ b/include/xrpl/ledger/detail/ApplyStateTable.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED -#define RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include -namespace ripple { +namespace xrpl { namespace detail { // Helper class that buffers modifications @@ -79,10 +59,7 @@ public: exists(ReadView const& base, Keylet const& k) const; std::optional - succ( - ReadView const& base, - key_type const& key, - std::optional const& last) const; + succ(ReadView const& base, key_type const& key, std::optional const& last) const; std::shared_ptr read(ReadView const& base, Keylet const& k) const; @@ -134,19 +111,10 @@ private: threadItem(TxMeta& meta, std::shared_ptr const& to); std::shared_ptr - getForMod( - ReadView const& base, - key_type const& key, - Mods& mods, - beast::Journal j); + getForMod(ReadView const& base, key_type const& key, Mods& mods, beast::Journal j); void - threadTx( - ReadView const& base, - TxMeta& meta, - AccountID const& to, - Mods& mods, - beast::Journal j); + threadTx(ReadView const& base, TxMeta& meta, AccountID const& to, Mods& mods, beast::Journal j); void threadOwners( @@ -158,6 +126,4 @@ private: }; } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/detail/ApplyViewBase.h b/include/xrpl/ledger/detail/ApplyViewBase.h index af86fc23b4..b3ec3c0fea 100644 --- a/include/xrpl/ledger/detail/ApplyViewBase.h +++ b/include/xrpl/ledger/detail/ApplyViewBase.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED -#define RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { namespace detail { class ApplyViewBase : public ApplyView, public RawView @@ -46,8 +26,8 @@ public: bool open() const override; - LedgerInfo const& - info() const override; + LedgerHeader const& + header() const override; Fees const& fees() const override; @@ -59,9 +39,7 @@ public: exists(Keylet const& k) const override; std::optional - succ( - key_type const& key, - std::optional const& last = std::nullopt) const override; + succ(key_type const& key, std::optional const& last = std::nullopt) const override; std::shared_ptr read(Keylet const& k) const override; @@ -125,6 +103,4 @@ protected: }; } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/detail/RawStateTable.h b/include/xrpl/ledger/detail/RawStateTable.h index 53a6f52208..e09f2f0e44 100644 --- a/include/xrpl/ledger/detail/RawStateTable.h +++ b/include/xrpl/ledger/detail/RawStateTable.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED -#define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { // Helper class that buffers raw modifications @@ -43,15 +23,11 @@ public: static constexpr size_t initialBufferSize = kilobytes(256); RawStateTable() - : monotonic_resource_{std::make_unique< - boost::container::pmr::monotonic_buffer_resource>( - initialBufferSize)} + : monotonic_resource_{std::make_unique(initialBufferSize)} , items_{monotonic_resource_.get()} {}; RawStateTable(RawStateTable const& rhs) - : monotonic_resource_{std::make_unique< - boost::container::pmr::monotonic_buffer_resource>( - initialBufferSize)} + : monotonic_resource_{std::make_unique(initialBufferSize)} , items_{rhs.items_, monotonic_resource_.get()} , dropsDestroyed_{rhs.dropsDestroyed_} {}; @@ -69,10 +45,7 @@ public: exists(ReadView const& base, Keylet const& k) const; std::optional - succ( - ReadView const& base, - key_type const& key, - std::optional const& last) const; + succ(ReadView const& base, key_type const& key, std::optional const& last) const; void erase(std::shared_ptr const& sle); @@ -113,8 +86,7 @@ private: std::shared_ptr sle; // Constructor needed for emplacement in std::map - sleAction(Action action_, std::shared_ptr const& sle_) - : action(action_), sle(sle_) + sleAction(Action action_, std::shared_ptr const& sle_) : action(action_), sle(sle_) { } }; @@ -125,18 +97,14 @@ private: key_type, sleAction, std::less, - boost::container::pmr::polymorphic_allocator< - std::pair>>; + boost::container::pmr::polymorphic_allocator>>; // monotonic_resource_ must outlive `items_`. Make a pointer so it may be // easily moved. - std::unique_ptr - monotonic_resource_; + std::unique_ptr monotonic_resource_; items_t items_; XRPAmount dropsDestroyed_{0}; }; } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/detail/ReadViewFwdRange.h b/include/xrpl/ledger/detail/ReadViewFwdRange.h index 0dab5e9464..bf40b04a6a 100644 --- a/include/xrpl/ledger/detail/ReadViewFwdRange.h +++ b/include/xrpl/ledger/detail/ReadViewFwdRange.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_READVIEWFWDRANGE_H_INCLUDED -#define RIPPLE_LEDGER_READVIEWFWDRANGE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class ReadView; @@ -92,9 +72,7 @@ public: iterator(iterator&& other) noexcept; // Used by the implementation - explicit iterator( - ReadView const* view, - std::unique_ptr impl); + explicit iterator(ReadView const* view, std::unique_ptr impl); iterator& operator=(iterator const& other); @@ -149,6 +127,4 @@ protected: }; } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/ledger/detail/ReadViewFwdRange.ipp b/include/xrpl/ledger/detail/ReadViewFwdRange.ipp index 86c1eedfdd..212be52432 100644 --- a/include/xrpl/ledger/detail/ReadViewFwdRange.ipp +++ b/include/xrpl/ledger/detail/ReadViewFwdRange.ipp @@ -1,56 +1,29 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED -#define RIPPLE_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace detail { template ReadViewFwdRange::iterator::iterator(iterator const& other) - : view_(other.view_) - , impl_(other.impl_ ? other.impl_->copy() : nullptr) - , cache_(other.cache_) + : view_(other.view_), impl_(other.impl_ ? other.impl_->copy() : nullptr), cache_(other.cache_) { } template ReadViewFwdRange::iterator::iterator(iterator&& other) noexcept - : view_(other.view_) - , impl_(std::move(other.impl_)) - , cache_(std::move(other.cache_)) + : view_(other.view_), impl_(std::move(other.impl_)), cache_(std::move(other.cache_)) { } template -ReadViewFwdRange::iterator::iterator( - ReadView const* view, - std::unique_ptr impl) +ReadViewFwdRange::iterator::iterator(ReadView const* view, std::unique_ptr impl) : view_(view), impl_(std::move(impl)) { } template auto -ReadViewFwdRange::iterator::operator=(iterator const& other) - -> iterator& +ReadViewFwdRange::iterator::operator=(iterator const& other) -> iterator& { if (this != &other) { @@ -63,8 +36,7 @@ ReadViewFwdRange::iterator::operator=(iterator const& other) template auto -ReadViewFwdRange::iterator::operator=(iterator&& other) noexcept - -> iterator& +ReadViewFwdRange::iterator::operator=(iterator&& other) noexcept -> iterator& { if (this != &other) { @@ -82,7 +54,7 @@ ReadViewFwdRange::iterator::operator==(iterator const& other) const { XRPL_ASSERT( view_ == other.view_, - "ripple::detail::ReadViewFwdRange::iterator::operator==(iterator) " + "xrpl::detail::ReadViewFwdRange::iterator::operator==(iterator) " "const : input view match"); if (impl_ != nullptr && other.impl_ != nullptr) @@ -134,6 +106,4 @@ ReadViewFwdRange::iterator::operator++(int) -> iterator } } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/net/AutoSocket.h b/include/xrpl/net/AutoSocket.h index 5f82854039..85a3adb456 100644 --- a/include/xrpl/net/AutoSocket.h +++ b/include/xrpl/net/AutoSocket.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED -#define RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED +#pragma once #include #include @@ -46,20 +26,13 @@ public: using callback = std::function; public: - AutoSocket( - boost::asio::io_context& s, - boost::asio::ssl::context& c, - bool secureOnly, - bool plainOnly) - : mSecure(secureOnly) - , mBuffer((plainOnly || secureOnly) ? 0 : 4) - , j_{beast::Journal::getNullSink()} + AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c, bool secureOnly, bool plainOnly) + : mSecure(secureOnly), mBuffer((plainOnly || secureOnly) ? 0 : 4), j_{beast::Journal::getNullSink()} { mSocket = std::make_unique(s, c); } - AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c) - : AutoSocket(s, c, false, false) + AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c) : AutoSocket(s, c, false, false) { } @@ -124,9 +97,7 @@ public: { // must be plain mSecure = false; - post( - mSocket->get_executor(), - boost::beast::bind_handler(cbFunc, error_code())); + post(mSocket->get_executor(), boost::beast::bind_handler(cbFunc, error_code())); } else { @@ -134,12 +105,7 @@ public: mSocket->next_layer().async_receive( boost::asio::buffer(mBuffer), boost::asio::socket_base::message_peek, - std::bind( - &AutoSocket::handle_autodetect, - this, - cbFunc, - std::placeholders::_1, - std::placeholders::_2)); + std::bind(&AutoSocket::handle_autodetect, this, cbFunc, std::placeholders::_1, std::placeholders::_2)); } } @@ -160,9 +126,7 @@ public: { ec = e.code(); } - post( - mSocket->get_executor(), - boost::beast::bind_handler(handler, ec)); + post(mSocket->get_executor(), boost::beast::bind_handler(handler, ec)); } } @@ -181,39 +145,29 @@ public: async_read_until(Seq const& buffers, Condition condition, Handler handler) { if (isSecure()) - boost::asio::async_read_until( - *mSocket, buffers, condition, handler); + boost::asio::async_read_until(*mSocket, buffers, condition, handler); else - boost::asio::async_read_until( - PlainSocket(), buffers, condition, handler); + boost::asio::async_read_until(PlainSocket(), buffers, condition, handler); } template void - async_read_until( - boost::asio::basic_streambuf& buffers, - std::string const& delim, - Handler handler) + async_read_until(boost::asio::basic_streambuf& buffers, std::string const& delim, Handler handler) { if (isSecure()) boost::asio::async_read_until(*mSocket, buffers, delim, handler); else - boost::asio::async_read_until( - PlainSocket(), buffers, delim, handler); + boost::asio::async_read_until(PlainSocket(), buffers, delim, handler); } template void - async_read_until( - boost::asio::basic_streambuf& buffers, - MatchCondition cond, - Handler handler) + async_read_until(boost::asio::basic_streambuf& buffers, MatchCondition cond, Handler handler) { if (isSecure()) boost::asio::async_read_until(*mSocket, buffers, cond, handler); else - boost::asio::async_read_until( - PlainSocket(), buffers, cond, handler); + boost::asio::async_read_until(PlainSocket(), buffers, cond, handler); } template @@ -228,9 +182,7 @@ public: template void - async_write( - boost::asio::basic_streambuf& buffers, - Handler handler) + async_write(boost::asio::basic_streambuf& buffers, Handler handler) { if (isSecure()) boost::asio::async_write(*mSocket, buffers, handler); @@ -250,10 +202,7 @@ public: template void - async_read( - boost::asio::basic_streambuf& buffers, - Condition cond, - Handler handler) + async_read(boost::asio::basic_streambuf& buffers, Condition cond, Handler handler) { if (isSecure()) boost::asio::async_read(*mSocket, buffers, cond, handler); @@ -283,12 +232,9 @@ public: protected: void - handle_autodetect( - callback cbFunc, - error_code const& ec, - size_t bytesTransferred) + handle_autodetect(callback cbFunc, error_code const& ec, size_t bytesTransferred) { - using namespace ripple; + using namespace xrpl; if (ec) { @@ -297,12 +243,9 @@ protected: } else if ( (mBuffer[0] < 127) && (mBuffer[0] > 31) && - ((bytesTransferred < 2) || - ((mBuffer[1] < 127) && (mBuffer[1] > 31))) && - ((bytesTransferred < 3) || - ((mBuffer[2] < 127) && (mBuffer[2] > 31))) && - ((bytesTransferred < 4) || - ((mBuffer[3] < 127) && (mBuffer[3] > 31)))) + ((bytesTransferred < 2) || ((mBuffer[1] < 127) && (mBuffer[1] > 31))) && + ((bytesTransferred < 3) || ((mBuffer[2] < 127) && (mBuffer[2] > 31))) && + ((bytesTransferred < 4) || ((mBuffer[3] < 127) && (mBuffer[3] > 31)))) { // not ssl JLOG(j_.trace()) << "non-SSL"; @@ -324,5 +267,3 @@ private: std::vector mBuffer; beast::Journal j_; }; - -#endif diff --git a/include/xrpl/net/HTTPClient.h b/include/xrpl/net/HTTPClient.h index b5043cd024..289ce8f6e3 100644 --- a/include/xrpl/net/HTTPClient.h +++ b/include/xrpl/net/HTTPClient.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NET_HTTPCLIENT_H_INCLUDED -#define RIPPLE_NET_HTTPCLIENT_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Provides an asynchronous HTTP client implementation with optional SSL. */ @@ -57,10 +37,8 @@ public: std::string const& strPath, std::size_t responseMax, // if no Content-Length header std::chrono::seconds timeout, - std::function complete, + std::function + complete, beast::Journal& j); static void @@ -71,10 +49,8 @@ public: std::string const& strPath, std::size_t responseMax, // if no Content-Length header std::chrono::seconds timeout, - std::function complete, + std::function + complete, beast::Journal& j); static void @@ -83,17 +59,12 @@ public: boost::asio::io_context& io_context, std::string strSite, unsigned short const port, - std::function< - void(boost::asio::streambuf& sb, std::string const& strHost)> build, + std::function build, std::size_t responseMax, // if no Content-Length header std::chrono::seconds timeout, - std::function complete, + std::function + complete, beast::Journal& j); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/net/HTTPClientSSLContext.h b/include/xrpl/net/HTTPClientSSLContext.h index f5dd1e54c6..1033b9a22b 100644 --- a/include/xrpl/net/HTTPClientSSLContext.h +++ b/include/xrpl/net/HTTPClientSSLContext.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED -#define RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { class HTTPClientSSLContext { @@ -40,8 +20,7 @@ public: std::string const& sslVerifyFile, bool sslVerify, beast::Journal j, - boost::asio::ssl::context_base::method method = - boost::asio::ssl::context::sslv23) + boost::asio::ssl::context_base::method method = boost::asio::ssl::context::sslv23) : ssl_context_{method}, j_(j), verify_{sslVerify} { boost::system::error_code ec; @@ -51,9 +30,8 @@ public: registerSSLCerts(ssl_context_, ec, j_); if (ec && sslVerifyDir.empty()) - Throw(boost::str( - boost::format("Failed to set_default_verify_paths: %s") % - ec.message())); + Throw( + boost::str(boost::format("Failed to set_default_verify_paths: %s") % ec.message())); } else { @@ -65,9 +43,7 @@ public: ssl_context_.add_verify_path(sslVerifyDir, ec); if (ec) - Throw(boost::str( - boost::format("Failed to add verify path: %s") % - ec.message())); + Throw(boost::str(boost::format("Failed to add verify path: %s") % ec.message())); } } @@ -98,23 +74,15 @@ public: template < class T, class = std::enable_if_t< - std::is_same< - T, - boost::asio::ssl::stream>:: - value || - std::is_same< - T, - boost::asio::ssl::stream>:: - value>> + std::is_same>::value || + std::is_same>::value>> boost::system::error_code preConnectVerify(T& strm, std::string const& host) { boost::system::error_code ec; if (!SSL_set_tlsext_host_name(strm.native_handle(), host.c_str())) { - ec.assign( - static_cast(::ERR_get_error()), - boost::asio::error::get_ssl_category()); + ec.assign(static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category()); } else if (!sslVerify()) { @@ -126,14 +94,8 @@ public: template < class T, class = std::enable_if_t< - std::is_same< - T, - boost::asio::ssl::stream>:: - value || - std::is_same< - T, - boost::asio::ssl::stream>:: - value>> + std::is_same>::value || + std::is_same>::value>> /** * @brief invoked after connect/async_connect but before sending data * on an ssl stream - to setup name verification. @@ -152,13 +114,7 @@ public: if (!ec) { strm.set_verify_callback( - std::bind( - &rfc6125_verify, - host, - std::placeholders::_1, - std::placeholders::_2, - j_), - ec); + std::bind(&rfc6125_verify, host, std::placeholders::_1, std::placeholders::_2, j_), ec); } } @@ -175,17 +131,12 @@ public: * @param j journal for logging */ static bool - rfc6125_verify( - std::string const& domain, - bool preverified, - boost::asio::ssl::verify_context& ctx, - beast::Journal j) + rfc6125_verify(std::string const& domain, bool preverified, boost::asio::ssl::verify_context& ctx, beast::Journal j) { if (boost::asio::ssl::host_name_verification(domain)(preverified, ctx)) return true; - JLOG(j.warn()) << "Outbound SSL connection to " << domain - << " fails certificate verification"; + JLOG(j.warn()) << "Outbound SSL connection to " << domain << " fails certificate verification"; return false; } @@ -195,6 +146,4 @@ private: bool const verify_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/net/RegisterSSLCerts.h b/include/xrpl/net/RegisterSSLCerts.h index 58c8c6c82d..e313b1cb06 100644 --- a/include/xrpl/net/RegisterSSLCerts.h +++ b/include/xrpl/net/RegisterSSLCerts.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NET_REGISTER_SSL_CERTS_H_INCLUDED -#define RIPPLE_NET_REGISTER_SSL_CERTS_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Register default SSL certificates. Register the system default SSL root certificates. On linux/mac, @@ -33,11 +13,6 @@ namespace ripple { store accessible via CryptoAPI. */ void -registerSSLCerts( - boost::asio::ssl::context&, - boost::system::error_code&, - beast::Journal j); +registerSSLCerts(boost::asio::ssl::context&, boost::system::error_code&, beast::Journal j); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Backend.h b/include/xrpl/nodestore/Backend.h index 23c0285a1d..6af292d5b3 100644 --- a/include/xrpl/nodestore/Backend.h +++ b/include/xrpl/nodestore/Backend.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_BACKEND_H_INCLUDED -#define RIPPLE_NODESTORE_BACKEND_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { /** A backend used for the NodeStore. @@ -83,9 +63,7 @@ public: virtual void open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) { - Throw( - "Deterministic appType/uid/salt not supported by backend " + - getName()); + Throw("Deterministic appType/uid/salt not supported by backend " + getName()); } /** Close the backend. @@ -162,6 +140,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Database.h b/include/xrpl/nodestore/Database.h index 165d1f74c9..d1f5b1bda2 100644 --- a/include/xrpl/nodestore/Database.h +++ b/include/xrpl/nodestore/Database.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DATABASE_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASE_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -59,11 +39,7 @@ public: @param config The configuration settings @param journal Destination for logging output. */ - Database( - Scheduler& scheduler, - int readThreads, - Section const& config, - beast::Journal j); + Database(Scheduler& scheduler, int readThreads, Section const& config, beast::Journal j); /** Destroy the node store. All pending operations are completed, pending writes flushed, @@ -101,11 +77,7 @@ public: @return `true` if the object was stored? */ virtual void - store( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - std::uint32_t ledgerSeq) = 0; + store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t ledgerSeq) = 0; /* Check if two ledgers are in the same database @@ -161,10 +133,6 @@ public: std::uint32_t ledgerSeq, std::function const&)>&& callback); - /** Remove expired entries from the positive and negative caches. */ - virtual void - sweep() = 0; - /** Gather statistics pertaining to read and write activities. * * @param obj Json object reference into which to place counters. @@ -247,9 +215,7 @@ protected: void storeStats(std::uint64_t count, std::uint64_t sz) { - XRPL_ASSERT( - count <= sz, - "ripple::NodeStore::Database::storeStats : valid inputs"); + XRPL_ASSERT(count <= sz, "xrpl::NodeStore::Database::storeStats : valid inputs"); storeCount_ += count; storeSz_ += sz; } @@ -277,11 +243,7 @@ private: std::condition_variable readCondVar_; // reads to do - std::map< - uint256, - std::vector const&)>>>> + std::map const&)>>>> read_; std::atomic readStopping_ = false; @@ -289,11 +251,7 @@ private: std::atomic runningThreads_ = 0; virtual std::shared_ptr - fetchNodeObject( - uint256 const& hash, - std::uint32_t ledgerSeq, - FetchReport& fetchReport, - bool duplicate) = 0; + fetchNodeObject(uint256 const& hash, std::uint32_t ledgerSeq, FetchReport& fetchReport, bool duplicate) = 0; /** Visit every object in the database This is usually called during import. @@ -310,6 +268,4 @@ private: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/DatabaseRotating.h b/include/xrpl/nodestore/DatabaseRotating.h index f63e99401d..e20b49805c 100644 --- a/include/xrpl/nodestore/DatabaseRotating.h +++ b/include/xrpl/nodestore/DatabaseRotating.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace NodeStore { /* This class has two key-value store Backend objects for persisting SHAMap @@ -33,11 +13,7 @@ namespace NodeStore { class DatabaseRotating : public Database { public: - DatabaseRotating( - Scheduler& scheduler, - int readThreads, - Section const& config, - beast::Journal journal) + DatabaseRotating(Scheduler& scheduler, int readThreads, Section const& config, beast::Journal journal) : Database(scheduler, readThreads, config, journal) { } @@ -52,12 +28,8 @@ public: virtual void rotate( std::unique_ptr&& newBackend, - std::function const& f) = 0; + std::function const& f) = 0; }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/DummyScheduler.h b/include/xrpl/nodestore/DummyScheduler.h index 0e9815f309..9fce4a6100 100644 --- a/include/xrpl/nodestore/DummyScheduler.h +++ b/include/xrpl/nodestore/DummyScheduler.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED -#define RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace NodeStore { -/** Simple NodeStore Scheduler that just peforms the tasks synchronously. */ +/** Simple NodeStore Scheduler that just performs the tasks synchronously. */ class DummyScheduler : public Scheduler { public: @@ -40,6 +20,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Factory.h b/include/xrpl/nodestore/Factory.h index a7ea4310fa..e01bdfabf2 100644 --- a/include/xrpl/nodestore/Factory.h +++ b/include/xrpl/nodestore/Factory.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_FACTORY_H_INCLUDED -#define RIPPLE_NODESTORE_FACTORY_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -80,6 +60,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Manager.h b/include/xrpl/nodestore/Manager.h index bf5213a508..9553407881 100644 --- a/include/xrpl/nodestore/Manager.h +++ b/include/xrpl/nodestore/Manager.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_MANAGER_H_INCLUDED -#define RIPPLE_NODESTORE_MANAGER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -58,11 +38,7 @@ public: /** Create a backend. */ virtual std::unique_ptr - make_Backend( - Section const& parameters, - std::size_t burstSize, - Scheduler& scheduler, - beast::Journal journal) = 0; + make_Backend(Section const& parameters, std::size_t burstSize, Scheduler& scheduler, beast::Journal journal) = 0; /** Construct a NodeStore database. @@ -74,7 +50,7 @@ public: HyperLevelDB, LevelDBFactory, SQLite, MDB If the fastBackendParameter is omitted or empty, no ephemeral database - is used. If the scheduler parameter is omited or unspecified, a + is used. If the scheduler parameter is omitted or unspecified, a synchronous scheduler is used which performs all tasks immediately on the caller's thread. @@ -102,6 +78,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/NodeObject.h b/include/xrpl/nodestore/NodeObject.h index dd7f4c4dc7..2274fc8c38 100644 --- a/include/xrpl/nodestore/NodeObject.h +++ b/include/xrpl/nodestore/NodeObject.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_NODEOBJECT_H_INCLUDED -#define RIPPLE_NODESTORE_NODEOBJECT_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ // VFALCO NOTE Intentionally not in the NodeStore namespace -namespace ripple { +namespace xrpl { /** The types of node objects. */ enum NodeObjectType : std::uint32_t { @@ -62,11 +42,7 @@ private: public: // This constructor is private, use createObject instead. - NodeObject( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - PrivateAccess); + NodeObject(NodeObjectType type, Blob&& data, uint256 const& hash, PrivateAccess); /** Create an object from fields. @@ -100,6 +76,4 @@ private: Blob const mData; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/README.md b/include/xrpl/nodestore/README.md index a5d1128d17..4b228bfc9a 100644 --- a/include/xrpl/nodestore/README.md +++ b/include/xrpl/nodestore/README.md @@ -96,7 +96,7 @@ Facebook's RocksDB database, builds on LevelDB. Use SQLite. -'path' speficies where the backend will store its data files. +'path' specifies where the backend will store its data files. Choices for 'compression' @@ -130,7 +130,7 @@ newer versions of RocksDB (TBD). ## Discussion RocksDBQuickFactory is intended to provide a testbed for comparing potential -rocksdb performance with the existing recommended configuration in rippled.cfg. +rocksdb performance with the existing recommended configuration in xrpld.cfg. Through various executions and profiling some conclusions are presented below. - If the write ahead log is enabled, insert speed soon clogs up under load. The @@ -161,7 +161,7 @@ Through various executions and profiling some conclusions are presented below. - Multiple runs of the benchmarks can yield surprisingly different results. This can perhaps be attributed to the asynchronous nature of rocksdb's compaction - process. The benchmarks are artifical and create highly unlikely write load to + process. The benchmarks are artificial and create highly unlikely write load to create the dataset to measure different read access patterns. Therefore multiple runs of the benchmarks are required to get a feel for the effectiveness of the changes. This contrasts sharply with the keyvadb benchmarking were highly diff --git a/include/xrpl/nodestore/Scheduler.h b/include/xrpl/nodestore/Scheduler.h index fb4aa6bdfc..6e01533930 100644 --- a/include/xrpl/nodestore/Scheduler.h +++ b/include/xrpl/nodestore/Scheduler.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED -#define RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { enum class FetchType { synchronous, async }; @@ -85,6 +65,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Task.h b/include/xrpl/nodestore/Task.h index 290d83588a..4bfc88bd13 100644 --- a/include/xrpl/nodestore/Task.h +++ b/include/xrpl/nodestore/Task.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_TASK_H_INCLUDED -#define RIPPLE_NODESTORE_TASK_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace NodeStore { /** Derived classes perform scheduled tasks. */ @@ -36,6 +16,4 @@ struct Task }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/Types.h b/include/xrpl/nodestore/Types.h index ea17a8f1ae..5adbc40f70 100644 --- a/include/xrpl/nodestore/Types.h +++ b/include/xrpl/nodestore/Types.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_TYPES_H_INCLUDED -#define RIPPLE_NODESTORE_TYPES_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { enum { @@ -56,6 +36,4 @@ using Batch = std::vector>; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/BatchWriter.h b/include/xrpl/nodestore/detail/BatchWriter.h index 941ecdfe18..1820435133 100644 --- a/include/xrpl/nodestore/detail/BatchWriter.h +++ b/include/xrpl/nodestore/detail/BatchWriter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED -#define RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { /** Batch-writing assist logic. @@ -97,6 +77,4 @@ private: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/DatabaseNodeImp.h b/include/xrpl/nodestore/detail/DatabaseNodeImp.h index ff43bd253e..94859c4d22 100644 --- a/include/xrpl/nodestore/detail/DatabaseNodeImp.h +++ b/include/xrpl/nodestore/detail/DatabaseNodeImp.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class DatabaseNodeImp : public Database @@ -41,44 +21,11 @@ public: std::shared_ptr backend, Section const& config, beast::Journal j) - : Database(scheduler, readThreads, config, j) - , backend_(std::move(backend)) + : Database(scheduler, readThreads, config, j), backend_(std::move(backend)) { - std::optional cacheSize, cacheAge; - - if (config.exists("cache_size")) - { - cacheSize = get(config, "cache_size"); - if (cacheSize.value() < 0) - { - Throw( - "Specified negative value for cache_size"); - } - } - - if (config.exists("cache_age")) - { - cacheAge = get(config, "cache_age"); - if (cacheAge.value() < 0) - { - Throw( - "Specified negative value for cache_age"); - } - } - - if (cacheSize != 0 || cacheAge != 0) - { - cache_ = std::make_shared>( - "DatabaseNodeImp", - cacheSize.value_or(0), - std::chrono::minutes(cacheAge.value_or(0)), - stopwatch(), - j); - } - XRPL_ASSERT( backend_, - "ripple::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null " + "xrpl::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null " "backend"); } @@ -106,8 +53,7 @@ public: } void - store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) - override; + store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) override; bool isSameDB(std::uint32_t, std::uint32_t) override @@ -129,25 +75,14 @@ public: asyncFetch( uint256 const& hash, std::uint32_t ledgerSeq, - std::function const&)>&& callback) - override; - - void - sweep() override; + std::function const&)>&& callback) override; private: - // Cache for database objects. This cache is not always initialized. Check - // for null before using. - std::shared_ptr> cache_; // Persistent key/value storage std::shared_ptr backend_; std::shared_ptr - fetchNodeObject( - uint256 const& hash, - std::uint32_t, - FetchReport& fetchReport, - bool duplicate) override; + fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate) override; void for_each(std::function)> f) override @@ -157,6 +92,4 @@ private: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/DatabaseRotatingImp.h b/include/xrpl/nodestore/detail/DatabaseRotatingImp.h index 0f81ac873c..1a378c54c7 100644 --- a/include/xrpl/nodestore/detail/DatabaseRotatingImp.h +++ b/include/xrpl/nodestore/detail/DatabaseRotatingImp.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class DatabaseRotatingImp : public DatabaseRotating @@ -51,9 +31,7 @@ public: void rotate( std::unique_ptr&& newBackend, - std::function const& f) override; + std::function const& f) override; std::string getName() const override; @@ -72,32 +50,22 @@ public: } void - store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) - override; + store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) override; void sync() override; - void - sweep() override; - private: std::shared_ptr writableBackend_; std::shared_ptr archiveBackend_; mutable std::mutex mutex_; std::shared_ptr - fetchNodeObject( - uint256 const& hash, - std::uint32_t, - FetchReport& fetchReport, - bool duplicate) override; + fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate) override; void for_each(std::function)> f) override; }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/DecodedBlob.h b/include/xrpl/nodestore/detail/DecodedBlob.h index 635f2a196b..dc6704a08d 100644 --- a/include/xrpl/nodestore/detail/DecodedBlob.h +++ b/include/xrpl/nodestore/detail/DecodedBlob.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED -#define RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace NodeStore { /** Parsed key/value blob into NodeObject components. @@ -62,6 +42,4 @@ private: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/EncodedBlob.h b/include/xrpl/nodestore/detail/EncodedBlob.h index d1f465d0cd..78e7153f73 100644 --- a/include/xrpl/nodestore/detail/EncodedBlob.h +++ b/include/xrpl/nodestore/detail/EncodedBlob.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED -#define RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { /** Convert a NodeObject from in-memory to database format. @@ -63,10 +43,7 @@ class EncodedBlob 1024 more bytes. The precise size is calculated automatically at compile time so as to avoid wasting space on padding bytes. */ - std::array< - std::uint8_t, - boost::alignment::align_up(9 + 1024, alignof(std::uint32_t))> - payload_; + std::array payload_; /** The size of the serialized data. */ std::uint32_t size_; @@ -81,19 +58,14 @@ class EncodedBlob public: explicit EncodedBlob(std::shared_ptr const& obj) : size_([&obj]() { - XRPL_ASSERT( - obj, - "ripple::NodeStore::EncodedBlob::EncodedBlob : non-null input"); + XRPL_ASSERT(obj, "xrpl::NodeStore::EncodedBlob::EncodedBlob : non-null input"); if (!obj) - throw std::runtime_error( - "EncodedBlob: unseated std::shared_ptr used."); + throw std::runtime_error("EncodedBlob: unseated std::shared_ptr used."); return obj->getData().size() + 9; }()) - , ptr_( - (size_ <= payload_.size()) ? payload_.data() - : new std::uint8_t[size_]) + , ptr_((size_ <= payload_.size()) ? payload_.data() : new std::uint8_t[size_]) { std::fill_n(ptr_, 8, std::uint8_t{0}); ptr_[8] = static_cast(obj->getType()); @@ -106,7 +78,7 @@ public: XRPL_ASSERT( ((ptr_ == payload_.data()) && (size_ <= payload_.size())) || ((ptr_ != payload_.data()) && (size_ > payload_.size())), - "ripple::NodeStore::EncodedBlob::~EncodedBlob : valid payload " + "xrpl::NodeStore::EncodedBlob::~EncodedBlob : valid payload " "pointer"); if (ptr_ != payload_.data()) @@ -133,6 +105,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/ManagerImp.h b/include/xrpl/nodestore/detail/ManagerImp.h index e8ebbc3e11..f46a7d56d0 100644 --- a/include/xrpl/nodestore/detail/ManagerImp.h +++ b/include/xrpl/nodestore/detail/ManagerImp.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED -#define RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -53,11 +33,8 @@ public: erase(Factory& factory) override; std::unique_ptr - make_Backend( - Section const& parameters, - std::size_t burstSize, - Scheduler& scheduler, - beast::Journal journal) override; + make_Backend(Section const& parameters, std::size_t burstSize, Scheduler& scheduler, beast::Journal journal) + override; std::unique_ptr make_Database( @@ -69,6 +46,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/codec.h b/include/xrpl/nodestore/detail/codec.h index 9c115277f8..1d08beff59 100644 --- a/include/xrpl/nodestore/detail/codec.h +++ b/include/xrpl/nodestore/detail/codec.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_CODEC_H_INCLUDED -#define RIPPLE_NODESTORE_CODEC_H_INCLUDED +#pragma once // Disable lz4 deprecation warning due to incompatibility with clang attributes #define LZ4_DISABLE_DEPRECATE_WARNINGS @@ -37,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { template @@ -49,8 +29,7 @@ lz4_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) std::size_t outSize = 0; - auto const n = read_varint( - reinterpret_cast(in), in_size, outSize); + auto const n = read_varint(reinterpret_cast(in), in_size, outSize); if (n == 0 || n >= in_size) Throw("lz4_decompress: invalid blob"); @@ -83,11 +62,8 @@ lz4_compress(void const* in, std::size_t in_size, BufferFactory&& bf) std::uint8_t* out = reinterpret_cast(bf(n + out_max)); result.first = out; std::memcpy(out, vi.data(), n); - auto const out_size = LZ4_compress_default( - reinterpret_cast(in), - reinterpret_cast(out + n), - in_size, - out_max); + auto const out_size = + LZ4_compress_default(reinterpret_cast(in), reinterpret_cast(out + n), in_size, out_max); if (out_size == 0) Throw("lz4 compress"); result.second = n + out_size; @@ -138,9 +114,8 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) auto const hs = field::size; // Mask if (in_size < hs + 32) Throw( - "nodeobject codec v1: short inner node size: " + - std::string("in_size = ") + std::to_string(in_size) + - " hs = " + std::to_string(hs)); + "nodeobject codec v1: short inner node size: " + std::string("in_size = ") + + std::to_string(in_size) + " hs = " + std::to_string(hs)); istream is(p, in_size); std::uint16_t mask; read(is, mask); // Mask @@ -152,11 +127,9 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) write(os, 0); write(os, 0); write(os, hotUNKNOWN); - write( - os, static_cast(HashPrefix::innerNode)); + write(os, static_cast(HashPrefix::innerNode)); if (mask == 0) - Throw( - "nodeobject codec v1: empty inner node"); + Throw("nodeobject codec v1: empty inner node"); std::uint16_t bit = 0x8000; for (int i = 16; i--; bit >>= 1) { @@ -164,10 +137,8 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) { if (in_size < 32) Throw( - "nodeobject codec v1: short inner node subsize: " + - std::string("in_size = ") + - std::to_string(in_size) + - " i = " + std::to_string(i)); + "nodeobject codec v1: short inner node subsize: " + std::string("in_size = ") + + std::to_string(in_size) + " i = " + std::to_string(i)); std::memcpy(os.data(32), is(32), 32); in_size -= 32; } @@ -177,17 +148,14 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) } } if (in_size > 0) - Throw( - "nodeobject codec v1: long inner node, in_size = " + - std::to_string(in_size)); + Throw("nodeobject codec v1: long inner node, in_size = " + std::to_string(in_size)); break; } case 3: // full v1 inner node { if (in_size != 16 * 32) // hashes Throw( - "nodeobject codec v1: short full inner node, in_size = " + - std::to_string(in_size)); + "nodeobject codec v1: short full inner node, in_size = " + std::to_string(in_size)); istream is(p, in_size); result.second = 525; void* const out = bf(result.second); @@ -196,14 +164,12 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf) write(os, 0); write(os, 0); write(os, hotUNKNOWN); - write( - os, static_cast(HashPrefix::innerNode)); + write(os, static_cast(HashPrefix::innerNode)); write(os, is(512), 512); break; } default: - Throw( - "nodeobject codec: bad type=" + std::to_string(type)); + Throw("nodeobject codec: bad type=" + std::to_string(type)); }; return result; } @@ -257,8 +223,7 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf) auto const vs = size_varint(type); result.second = vs + field::size + // mask n * 32; // hashes - std::uint8_t* out = - reinterpret_cast(bf(result.second)); + std::uint8_t* out = reinterpret_cast(bf(result.second)); result.first = out; ostream os(out, result.second); write(os, type); @@ -270,8 +235,7 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf) auto const type = 3U; auto const vs = size_varint(type); result.second = vs + n * 32; // hashes - std::uint8_t* out = - reinterpret_cast(bf(result.second)); + std::uint8_t* out = reinterpret_cast(bf(result.second)); result.first = out; ostream os(out, result.second); write(os, type); @@ -291,19 +255,17 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf) case 1: // lz4 { std::uint8_t* p; - auto const lzr = NodeStore::lz4_compress( - in, in_size, [&p, &vn, &bf](std::size_t n) { - p = reinterpret_cast(bf(vn + n)); - return p + vn; - }); + auto const lzr = NodeStore::lz4_compress(in, in_size, [&p, &vn, &bf](std::size_t n) { + p = reinterpret_cast(bf(vn + n)); + return p + vn; + }); std::memcpy(p, vi.data(), vn); result.first = p; result.second = vn + lzr.second; break; } default: - Throw( - "nodeobject codec: unknown=" + std::to_string(codecType)); + Throw("nodeobject codec: unknown=" + std::to_string(codecType)); }; return result; } @@ -341,6 +303,4 @@ filter_inner(void* in, std::size_t in_size) } } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/nodestore/detail/varint.h b/include/xrpl/nodestore/detail/varint.h index 6ccbe68b87..98f8d8ff08 100644 --- a/include/xrpl/nodestore/detail/varint.h +++ b/include/xrpl/nodestore/detail/varint.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NUDB_VARINT_H_INCLUDED -#define BEAST_NUDB_VARINT_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { // This is a variant of the base128 varint format from @@ -137,6 +117,4 @@ write(nudb::detail::ostream& os, std::size_t t) } } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto index 2b8dc471ce..942a4a2135 100644 --- a/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto +++ b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto @@ -9,7 +9,7 @@ import "org/xrpl/rpc/v1/get_ledger_entry.proto"; import "org/xrpl/rpc/v1/get_ledger_data.proto"; import "org/xrpl/rpc/v1/get_ledger_diff.proto"; -// These methods are binary only methods for retrieiving arbitrary ledger state +// These methods are binary only methods for retrieving arbitrary ledger state // via gRPC. These methods are used by clio, but can also be // used by any client that wants to extract ledger state in an efficient manner. // They do not directly mimic the JSON equivalent methods. diff --git a/include/xrpl/proto/ripple.proto b/include/xrpl/proto/xrpl.proto similarity index 97% rename from include/xrpl/proto/ripple.proto rename to include/xrpl/proto/xrpl.proto index f93ebbc72c..0af7deb35d 100644 --- a/include/xrpl/proto/ripple.proto +++ b/include/xrpl/proto/xrpl.proto @@ -17,9 +17,9 @@ enum MessageType { mtHAVE_SET = 35; mtVALIDATION = 41; mtGET_OBJECTS = 42; - mtVALIDATORLIST = 54; + mtVALIDATOR_LIST = 54; mtSQUELCH = 55; - mtVALIDATORLISTCOLLECTION = 56; + mtVALIDATOR_LIST_COLLECTION = 56; mtPROOF_PATH_REQ = 57; mtPROOF_PATH_RESPONSE = 58; mtREPLAY_DELTA_REQ = 59; @@ -86,9 +86,9 @@ message TMPublicKey { // you must first combine coins from one address to another. enum TransactionStatus { - tsNEW = 1; // origin node did/could not validate - tsCURRENT = 2; // scheduled to go in this ledger - tsCOMMITED = 3; // in a closed ledger + tsNEW = 1; // origin node did/could not validate + tsCURRENT = 2; // scheduled to go in this ledger + tsCOMMITTED = 3; // in a closed ledger tsREJECT_CONFLICT = 4; tsREJECT_INVALID = 5; tsREJECT_FUNDS = 6; @@ -308,7 +308,7 @@ message TMSquelch { } enum TMLedgerMapType { - lmTRANASCTION = 1; // transaction map + lmTRANSACTION = 1; // transaction map lmACCOUNT_STATE = 2; // account state map } diff --git a/include/xrpl/protocol/AMMCore.h b/include/xrpl/protocol/AMMCore.h index 442f24d878..a2c531f361 100644 --- a/include/xrpl/protocol/AMMCore.h +++ b/include/xrpl/protocol/AMMCore.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED -#define RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { std::uint16_t constexpr TRADING_FEE_THRESHOLD = 1000; // 1% @@ -37,8 +17,7 @@ std::uint16_t constexpr AUCTION_SLOT_MAX_AUTH_ACCOUNTS = 4; std::uint32_t constexpr AUCTION_SLOT_FEE_SCALE_FACTOR = 100000; std::uint32_t constexpr AUCTION_SLOT_DISCOUNTED_FEE_FRACTION = 10; std::uint32_t constexpr AUCTION_SLOT_MIN_FEE_FRACTION = 25; -std::uint32_t constexpr AUCTION_SLOT_INTERVAL_DURATION = - TOTAL_TIME_SLOT_SECS / AUCTION_SLOT_TIME_INTERVALS; +std::uint32_t constexpr AUCTION_SLOT_INTERVAL_DURATION = TOTAL_TIME_SLOT_SECS / AUCTION_SLOT_TIME_INTERVALS; // Votes std::uint16_t constexpr VOTE_MAX_SLOTS = 8; @@ -56,10 +35,7 @@ ammLPTCurrency(Currency const& cur1, Currency const& cur2); /** Calculate LPT Issue from AMM asset pair. */ Issue -ammLPTIssue( - Currency const& cur1, - Currency const& cur2, - AccountID const& ammAccountID); +ammLPTIssue(Currency const& cur1, Currency const& cur2, AccountID const& ammAccountID); /** Validate the amount. * If validZero is false and amount is beast::zero then invalid amount. @@ -73,9 +49,7 @@ invalidAMMAmount( bool validZero = false); NotTEC -invalidAMMAsset( - Issue const& issue, - std::optional> const& pair = std::nullopt); +invalidAMMAsset(Issue const& issue, std::optional> const& pair = std::nullopt); NotTEC invalidAMMAssetPair( @@ -121,6 +95,4 @@ feeMultHalf(std::uint16_t tfee) return 1 - getFee(tfee) / 2; } -} // namespace ripple - -#endif // RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h index d546346bb4..bc57058d9e 100644 --- a/include/xrpl/protocol/AccountID.h +++ b/include/xrpl/protocol/AccountID.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED -#define RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED +#pragma once #include // VFALCO Uncomment when the header issues are resolved @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -122,15 +102,15 @@ operator<<(std::ostream& os, AccountID const& x) void initAccountIdCache(std::size_t count); -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ namespace Json { template <> -inline ripple::AccountID -getOrThrow(Json::Value const& v, ripple::SField const& field) +inline xrpl::AccountID +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; std::string const b58 = getOrThrow(v, field); if (auto const r = parseBase58(b58)) @@ -146,11 +126,9 @@ namespace std { // DEPRECATED // VFALCO Use beast::uhash or a hardened container template <> -struct hash : ripple::AccountID::hasher +struct hash : xrpl::AccountID::hasher { hash() = default; }; } // namespace std - -#endif diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index a65f7fcad8..0807e96c49 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED -#define RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { inline STAmount toSTAmount(IOUAmount const& iou, Issue const& iss) @@ -53,9 +33,7 @@ toSTAmount(XRPAmount const& xrp) inline STAmount toSTAmount(XRPAmount const& xrp, Issue const& iss) { - XRPL_ASSERT( - isXRP(iss.account) && isXRP(iss.currency), - "ripple::toSTAmount : is XRP"); + XRPL_ASSERT(isXRP(iss.account) && isXRP(iss.currency), "xrpl::toSTAmount : is XRP"); return toSTAmount(xrp); } @@ -75,13 +53,11 @@ inline IOUAmount toAmount(STAmount const& amt) { XRPL_ASSERT( - amt.mantissa() < std::numeric_limits::max(), - "ripple::toAmount : maximum mantissa"); + amt.mantissa() < std::numeric_limits::max(), "xrpl::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); - std::int64_t const sMant = - isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); + std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - XRPL_ASSERT(!isXRP(amt), "ripple::toAmount : is not XRP"); + XRPL_ASSERT(!isXRP(amt), "xrpl::toAmount : is not XRP"); return IOUAmount(sMant, amt.exponent()); } @@ -90,13 +66,11 @@ inline XRPAmount toAmount(STAmount const& amt) { XRPL_ASSERT( - amt.mantissa() < std::numeric_limits::max(), - "ripple::toAmount : maximum mantissa"); + amt.mantissa() < std::numeric_limits::max(), "xrpl::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); - std::int64_t const sMant = - isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); + std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - XRPL_ASSERT(isXRP(amt), "ripple::toAmount : is XRP"); + XRPL_ASSERT(isXRP(amt), "xrpl::toAmount : is XRP"); return XRPAmount(sMant); } @@ -124,10 +98,7 @@ toAmount(XRPAmount const& amt) template T -toAmount( - Issue const& issue, - Number const& n, - Number::rounding_mode mode = Number::getround()) +toAmount(Issue const& issue, Number const& n, Number::rounding_mode mode = Number::getround()) { saveNumberRoundMode rm(Number::getround()); if (isXRP(issue)) @@ -141,7 +112,7 @@ toAmount( { if (isXRP(issue)) return STAmount(issue, static_cast(n)); - return STAmount(issue, n.mantissa(), n.exponent()); + return STAmount(issue, n); } else { @@ -161,8 +132,7 @@ toMaxAmount(Issue const& issue) else if constexpr (std::is_same_v) { if (isXRP(issue)) - return STAmount( - issue, static_cast(STAmount::cMaxNativeN)); + return STAmount(issue, static_cast(STAmount::cMaxNativeN)); return STAmount(issue, STAmount::cMaxValue, STAmount::cMaxOffset); } else @@ -173,10 +143,7 @@ toMaxAmount(Issue const& issue) } inline STAmount -toSTAmount( - Issue const& issue, - Number const& n, - Number::rounding_mode mode = Number::getround()) +toSTAmount(Issue const& issue, Number const& n, Number::rounding_mode mode = Number::getround()) { return toAmount(issue, n, mode); } @@ -215,6 +182,4 @@ get(STAmount const& a) } } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h index c836fbb5b4..756a41d25e 100644 --- a/include/xrpl/protocol/ApiVersion.h +++ b/include/xrpl/protocol/ApiVersion.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED -#define RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { /** * API version numbers used in later API versions @@ -61,30 +41,25 @@ constexpr static auto apiInvalidVersion = apiVersion<0>; constexpr static auto apiMinimumSupportedVersion = apiVersion<1>; constexpr static auto apiMaximumSupportedVersion = apiVersion<2>; constexpr static auto apiVersionIfUnspecified = apiVersion<1>; -constexpr static auto apiCommandLineVersion = - apiVersion<1>; // TODO Bump to 2 later +constexpr static auto apiCommandLineVersion = apiVersion<1>; // TODO Bump to 2 later constexpr static auto apiBetaVersion = apiVersion<3>; constexpr static auto apiMaximumValidVersion = apiBetaVersion; static_assert(apiInvalidVersion < apiMinimumSupportedVersion); static_assert( - apiVersionIfUnspecified >= apiMinimumSupportedVersion && - apiVersionIfUnspecified <= apiMaximumSupportedVersion); + apiVersionIfUnspecified >= apiMinimumSupportedVersion && apiVersionIfUnspecified <= apiMaximumSupportedVersion); static_assert( - apiCommandLineVersion >= apiMinimumSupportedVersion && - apiCommandLineVersion <= apiMaximumSupportedVersion); + apiCommandLineVersion >= apiMinimumSupportedVersion && apiCommandLineVersion <= apiMaximumSupportedVersion); static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion); static_assert(apiBetaVersion >= apiMaximumSupportedVersion); static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion); -template -void -setVersion(JsonObject& parent, unsigned int apiVersion, bool betaEnabled) +inline void +setVersion(Json::Value& parent, unsigned int apiVersion, bool betaEnabled) { - XRPL_ASSERT( - apiVersion != apiInvalidVersion, - "ripple::RPC::setVersion : input is valid"); - auto& retObj = addObject(parent, jss::version); + XRPL_ASSERT(apiVersion != apiInvalidVersion, "xrpl::RPC::setVersion : input is valid"); + + auto& retObj = parent[jss::version] = Json::objectValue; if (apiVersion == apiVersionIfUnspecified) { @@ -100,8 +75,7 @@ setVersion(JsonObject& parent, unsigned int apiVersion, bool betaEnabled) else { retObj[jss::first] = apiMinimumSupportedVersion.value; - retObj[jss::last] = - betaEnabled ? apiBetaVersion : apiMaximumSupportedVersion; + retObj[jss::last] = betaEnabled ? apiBetaVersion : apiMaximumSupportedVersion; } } @@ -114,7 +88,7 @@ setVersion(JsonObject& parent, unsigned int apiVersion, bool betaEnabled) * 3) the version number is unspecified and * APIVersionIfUnspecified is out of the supported range * - * @param jv a Json value that may or may not specifies + * @param jv a Json value that may or may not specify * the api version number * @param betaEnabled if the beta API version is enabled * @return the api version number @@ -123,8 +97,7 @@ inline unsigned int getAPIVersionNumber(Json::Value const& jv, bool betaEnabled) { static Json::Value const minVersion(RPC::apiMinimumSupportedVersion); - Json::Value const maxVersion( - betaEnabled ? RPC::apiBetaVersion : RPC::apiMaximumSupportedVersion); + Json::Value const maxVersion(betaEnabled ? RPC::apiBetaVersion : RPC::apiMaximumSupportedVersion); if (jv.isObject()) { @@ -136,8 +109,7 @@ getAPIVersionNumber(Json::Value const& jv, bool betaEnabled) return RPC::apiInvalidVersion; } auto const specifiedVersionInt = specifiedVersion.asInt(); - if (specifiedVersionInt < minVersion || - specifiedVersionInt > maxVersion) + if (specifiedVersionInt < minVersion || specifiedVersionInt > maxVersion) { return RPC::apiInvalidVersion; } @@ -157,18 +129,13 @@ forApiVersions(Fn const& fn, Args&&... args) (maxVer >= minVer) && // (minVer >= RPC::apiMinimumSupportedVersion) && // (RPC::apiMaximumValidVersion >= maxVer) && requires { - fn(std::integral_constant{}, - std::forward(args)...); - fn(std::integral_constant{}, - std::forward(args)...); + fn(std::integral_constant{}, std::forward(args)...); + fn(std::integral_constant{}, std::forward(args)...); } { constexpr auto size = maxVer + 1 - minVer; [&](std::index_sequence) { - (((void)fn( - std::integral_constant{}, - std::forward(args)...)), - ...); + (((void)fn(std::integral_constant{}, std::forward(args)...)), ...); }(std::make_index_sequence{}); } @@ -176,16 +143,10 @@ template void forAllApiVersions(Fn const& fn, Args&&... args) requires requires { - forApiVersions< - RPC::apiMinimumSupportedVersion, - RPC::apiMaximumValidVersion>(fn, std::forward(args)...); + forApiVersions(fn, std::forward(args)...); } { - forApiVersions< - RPC::apiMinimumSupportedVersion, - RPC::apiMaximumValidVersion>(fn, std::forward(args)...); + forApiVersions(fn, std::forward(args)...); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h index 4438106738..d48bc94b50 100644 --- a/include/xrpl/protocol/Asset.h +++ b/include/xrpl/protocol/Asset.h @@ -1,42 +1,20 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_ASSET_H_INCLUDED -#define RIPPLE_PROTOCOL_ASSET_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { class Asset; class STAmount; template -concept ValidIssueType = - std::is_same_v || std::is_same_v; +concept ValidIssueType = std::is_same_v || std::is_same_v; template -concept AssetType = - std::is_convertible_v || std::is_convertible_v || +concept AssetType = std::is_convertible_v || std::is_convertible_v || std::is_convertible_v || std::is_convertible_v; /* Asset is an abstraction of three different issue types: XRP, IOU, MPT. @@ -100,7 +78,27 @@ public: bool native() const { - return holds() && get().native(); + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + return issue.native(); + if constexpr (std::is_same_v) + return false; + }, + issue_); + } + + bool + integral() const + { + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + return issue.native(); + if constexpr (std::is_same_v) + return true; + }, + issue_); } friend constexpr bool @@ -162,8 +160,7 @@ constexpr bool operator==(Asset const& lhs, Asset const& rhs) { return std::visit( - [&]( - TLhs const& issLhs, TRhs const& issRhs) { + [&](TLhs const& issLhs, TRhs const& issRhs) { if constexpr (std::is_same_v) return issLhs == issRhs; else @@ -177,12 +174,10 @@ constexpr std::weak_ordering operator<=>(Asset const& lhs, Asset const& rhs) { return std::visit( - []( - TLhs const& lhs_, TRhs const& rhs_) { + [](TLhs const& lhs_, TRhs const& rhs_) { if constexpr (std::is_same_v) return std::weak_ordering(lhs_ <=> rhs_); - else if constexpr ( - std::is_same_v && std::is_same_v) + else if constexpr (std::is_same_v && std::is_same_v) return std::weak_ordering::greater; else return std::weak_ordering::less; @@ -201,14 +196,10 @@ constexpr bool equalTokens(Asset const& lhs, Asset const& rhs) { return std::visit( - [&]( - TLhs const& issLhs, TRhs const& issRhs) { - if constexpr ( - std::is_same_v && std::is_same_v) + [&](TLhs const& issLhs, TRhs const& issRhs) { + if constexpr (std::is_same_v && std::is_same_v) return issLhs.currency == issRhs.currency; - else if constexpr ( - std::is_same_v && - std::is_same_v) + else if constexpr (std::is_same_v && std::is_same_v) return issLhs.getMptID() == issRhs.getMptID(); else return false; @@ -232,6 +223,4 @@ validJSONAsset(Json::Value const& jv); Asset assetFromJson(Json::Value const& jv); -} // namespace ripple - -#endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/Batch.h b/include/xrpl/protocol/Batch.h index 1307ea0978..91fb8e5a9d 100644 --- a/include/xrpl/protocol/Batch.h +++ b/include/xrpl/protocol/Batch.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { inline void -serializeBatch( - Serializer& msg, - std::uint32_t const& flags, - std::vector const& txids) +serializeBatch(Serializer& msg, std::uint32_t const& flags, std::vector const& txids) { msg.add32(HashPrefix::batch); msg.add32(flags); @@ -34,4 +14,4 @@ serializeBatch( msg.addBitString(txid); } -} // namespace ripple +} // namespace xrpl diff --git a/include/xrpl/protocol/Book.h b/include/xrpl/protocol/Book.h index a8b9afacac..83965cf701 100644 --- a/include/xrpl/protocol/Book.h +++ b/include/xrpl/protocol/Book.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_BOOK_H_INCLUDED -#define RIPPLE_PROTOCOL_BOOK_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { /** Specifies an order book. The order book is a pair of Issues called in and out. @@ -43,10 +23,7 @@ public: { } - Book( - Issue const& in_, - Issue const& out_, - std::optional const& domain_) + Book(Issue const& in_, Issue const& out_, std::optional const& domain_) : in(in_), out(out_), domain(domain_) { } @@ -79,8 +56,7 @@ reversed(Book const& book); [[nodiscard]] inline constexpr bool operator==(Book const& lhs, Book const& rhs) { - return (lhs.in == rhs.in) && (lhs.out == rhs.out) && - (lhs.domain == rhs.domain); + return (lhs.in == rhs.in) && (lhs.out == rhs.out) && (lhs.domain == rhs.domain); } /** @} */ @@ -106,36 +82,32 @@ operator<=>(Book const& lhs, Book const& rhs) } /** @} */ -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ namespace std { template <> -struct hash - : private boost::base_from_member, 0>, - private boost::base_from_member, 1> +struct hash : private boost::base_from_member, 0>, + private boost::base_from_member, 1> { private: - using currency_hash_type = - boost::base_from_member, 0>; - using issuer_hash_type = - boost::base_from_member, 1>; + using currency_hash_type = boost::base_from_member, 0>; + using issuer_hash_type = boost::base_from_member, 1>; public: hash() = default; using value_type = std::size_t; - using argument_type = ripple::Issue; + using argument_type = xrpl::Issue; value_type operator()(argument_type const& value) const { value_type result(currency_hash_type::member(value.currency)); if (!isXRP(value.currency)) - boost::hash_combine( - result, issuer_hash_type::member(value.account)); + boost::hash_combine(result, issuer_hash_type::member(value.account)); return result; } }; @@ -143,11 +115,11 @@ public: //------------------------------------------------------------------------------ template <> -struct hash +struct hash { private: - using issue_hasher = std::hash; - using uint256_hasher = ripple::uint256::hasher; + using issue_hasher = std::hash; + using uint256_hasher = xrpl::uint256::hasher; issue_hasher m_issue_hasher; uint256_hasher m_uint256_hasher; @@ -156,7 +128,7 @@ public: hash() = default; using value_type = std::size_t; - using argument_type = ripple::Book; + using argument_type = xrpl::Book; value_type operator()(argument_type const& value) const @@ -178,25 +150,23 @@ public: namespace boost { template <> -struct hash : std::hash +struct hash : std::hash { hash() = default; - using Base = std::hash; + using Base = std::hash; // VFALCO NOTE broken in vs2012 // using Base::Base; // inherit ctors }; template <> -struct hash : std::hash +struct hash : std::hash { hash() = default; - using Base = std::hash; + using Base = std::hash; // VFALCO NOTE broken in vs2012 // using Base::Base; // inherit ctors }; } // namespace boost - -#endif diff --git a/include/xrpl/protocol/BuildInfo.h b/include/xrpl/protocol/BuildInfo.h index cfe35d3383..3c42a4323f 100644 --- a/include/xrpl/protocol/BuildInfo.h +++ b/include/xrpl/protocol/BuildInfo.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_BUILDINFO_H_INCLUDED -#define RIPPLE_PROTOCOL_BUILDINFO_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Versioning information for this build. */ // VFALCO The namespace is deprecated @@ -98,6 +78,4 @@ isNewerVersion(std::uint64_t version); } // namespace BuildInfo -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/ConfidentialTransfer.h b/include/xrpl/protocol/ConfidentialTransfer.h index 5283a08733..a7f59773f4 100644 --- a/include/xrpl/protocol/ConfidentialTransfer.h +++ b/include/xrpl/protocol/ConfidentialTransfer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_CONFIDENTIALTRANSFER_H_INCLUDED -#define RIPPLE_PROTOCOL_CONFIDENTIALTRANSFER_H_INCLUDED +#pragma once #include #include @@ -29,152 +9,495 @@ #include #include #include +#include #include -#include +#include -namespace ripple { +namespace xrpl { /** - * @brief Generates a new secp256k1 key pair. - */ -SECP256K1_API int -secp256k1_elgamal_generate_keypair( - secp256k1_context const* ctx, - unsigned char* privkey, - secp256k1_pubkey* pubkey); - -/** - * @brief Encrypts a 64-bit amount using ElGamal. - */ -SECP256K1_API int -secp256k1_elgamal_encrypt( - secp256k1_context const* ctx, - secp256k1_pubkey* c1, - secp256k1_pubkey* c2, - secp256k1_pubkey const* pubkey_Q, - uint64_t amount, - unsigned char const* blinding_factor); - -/** - * @brief Decrypts an ElGamal ciphertext to recover the amount. - */ -SECP256K1_API int -secp256k1_elgamal_decrypt( - secp256k1_context const* ctx, - uint64_t* amount, - secp256k1_pubkey const* c1, - secp256k1_pubkey const* c2, - unsigned char const* privkey); - -/** - * @brief Homomorphically adds two ElGamal ciphertexts. - */ -SECP256K1_API int -secp256k1_elgamal_add( - secp256k1_context const* ctx, - secp256k1_pubkey* sum_c1, - secp256k1_pubkey* sum_c2, - secp256k1_pubkey const* a_c1, - secp256k1_pubkey const* a_c2, - secp256k1_pubkey const* b_c1, - secp256k1_pubkey const* b_c2); - -/** - * @brief Homomorphically subtracts two ElGamal ciphertexts. - */ -SECP256K1_API int -secp256k1_elgamal_subtract( - secp256k1_context const* ctx, - secp256k1_pubkey* diff_c1, - secp256k1_pubkey* diff_c2, - secp256k1_pubkey const* a_c1, - secp256k1_pubkey const* a_c2, - secp256k1_pubkey const* b_c1, - secp256k1_pubkey const* b_c2); - -/** - * @brief Generates the canonical encrypted zero for a given MPT token instance. + * @brief Bundles an ElGamal public key with its associated encrypted amount. * - * This ciphertext represents a zero balance for a specific account's holding - * of a token defined by its MPTokenIssuanceID. - * - * @param[in] ctx A pointer to a valid secp256k1 context. - * @param[out] enc_zero_c1 The C1 component of the canonical ciphertext. - * @param[out] enc_zero_c2 The C2 component of the canonical ciphertext. - * @param[in] pubkey The ElGamal public key of the account holder. - * @param[in] account_id A pointer to the 20-byte AccountID. - * @param[in] mpt_issuance_id A pointer to the 24-byte MPTokenIssuanceID. - * - * @return 1 on success, 0 on failure. + * Used to represent a recipient in confidential transfers, containing both + * the recipient's ElGamal public key and the ciphertext encrypting the + * transfer amount under that key. */ -SECP256K1_API int -generate_canonical_encrypted_zero( - secp256k1_context const* ctx, - secp256k1_pubkey* enc_zero_c1, - secp256k1_pubkey* enc_zero_c2, - secp256k1_pubkey const* pubkey, - unsigned char const* account_id, // 20 bytes - unsigned char const* mpt_issuance_id // 24 bytes -); +struct ConfidentialRecipient +{ + Slice const publicKey; ///< The recipient's ElGamal public key (64 bytes). + Slice const encryptedAmount; ///< The encrypted amount ciphertext (128 bytes). +}; -// breaks a 66-byte encrypted amount into two 33-byte components -// then parses each 33-byte component into 64-byte secp256k1_pubkey format +/** + * @brief Increments the confidential balance version counter on an MPToken. + * + * The version counter is used to prevent replay attacks by binding proofs + * to a specific state of the account's confidential balance. Wraps to 0 + * on overflow (defined behavior for unsigned integers). + * + * @param mptoken The MPToken ledger entry to update. + */ +inline void +incrementConfidentialVersion(STObject& mptoken) +{ + // Retrieve current version and increment. + // Unsigned integer overflow is defined behavior in C++ (wraps to 0), + // which is acceptable here. + mptoken[sfConfidentialBalanceVersion] = mptoken[~sfConfidentialBalanceVersion].value_or(0u) + 1u; +} + +/** + * @brief Adds common fields to a serializer for ZKP context hash generation. + * + * Serializes the transaction type, account, sequence number, and issuance ID + * into the provided serializer. These fields form the base of all context + * hashes used in zero-knowledge proofs. + * + * @param s The serializer to append fields to. + * @param txType The transaction type identifier. + * @param account The account ID of the transaction sender. + * @param sequence The transaction sequence number. + * @param issuanceID The MPToken Issuance ID. + */ +void +addCommonZKPFields( + Serializer& s, + std::uint16_t txType, + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID); + +/** + * @brief Generates the context hash for ConfidentialMPTSend transactions. + * + * Creates a unique 256-bit hash that binds the zero-knowledge proofs to + * this specific send transaction, preventing proof reuse across transactions. + * + * @param account The sender's account ID. + * @param sequence The transaction sequence number. + * @param issuanceID The MPToken Issuance ID. + * @param destination The destination account ID. + * @param version The sender's confidential balance version. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getSendContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + AccountID const& destination, + std::uint32_t version); + +/** + * @brief Generates the context hash for ConfidentialMPTClawback transactions. + * + * Creates a unique 256-bit hash that binds the equality proof to this + * specific clawback transaction. + * + * @param account The issuer's account ID. + * @param sequence The transaction sequence number. + * @param issuanceID The MPToken Issuance ID. + * @param amount The amount being clawed back. + * @param holder The holder's account ID being clawed back from. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getClawbackContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + std::uint64_t amount, + AccountID const& holder); + +/** + * @brief Generates the context hash for ConfidentialMPTConvert transactions. + * + * Creates a unique 256-bit hash that binds the Schnorr proof (for key + * registration) to this specific convert transaction. + * + * @param account The holder's account ID. + * @param sequence The transaction sequence number. + * @param issuanceID The MPToken Issuance ID. + * @param amount The amount being converted to confidential. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getConvertContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + std::uint64_t amount); + +/** + * @brief Generates the context hash for ConfidentialMPTConvertBack transactions. + * + * Creates a unique 256-bit hash that binds the zero-knowledge proofs to + * this specific convert-back transaction. + * + * @param account The holder's account ID. + * @param sequence The transaction sequence number. + * @param issuanceID The MPToken Issuance ID. + * @param amount The amount being converted back to public. + * @param version The holder's confidential balance version. + * @return A 256-bit context hash unique to this transaction. + */ +uint256 +getConvertBackContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + std::uint64_t amount, + std::uint32_t version); + +/** + * @brief Parses an ElGamal ciphertext into two secp256k1 public key components. + * + * Breaks a 66-byte encrypted amount (two 33-byte compressed EC points) into + * two secp256k1_pubkey structures (C1, C2) for use in cryptographic operations. + * + * @param buffer The 66-byte buffer containing the compressed ciphertext. + * @param out1 Output: The C1 component of the ElGamal ciphertext. + * @param out2 Output: The C2 component of the ElGamal ciphertext. + * @return true if parsing succeeds, false if the buffer is invalid. + */ bool makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2); -// serialize two secp256k1_pubkey components back into compressed 66-byte form +/** + * @brief Serializes two secp256k1 public key components into compressed form. + * + * Converts two secp256k1_pubkey structures (C1, C2) back into a 66-byte + * buffer containing two 33-byte compressed EC points. + * + * @param in1 The C1 component to serialize. + * @param in2 The C2 component to serialize. + * @param buffer Output: The 66-byte buffer to write the compressed ciphertext. + * @return true if serialization succeeds, false otherwise. + */ bool -serializeEcPair( - secp256k1_pubkey const& in1, - secp256k1_pubkey const& in2, - Buffer& buffer); +serializeEcPair(secp256k1_pubkey const& in1, secp256k1_pubkey const& in2, Buffer& buffer); /** * @brief Verifies that a buffer contains two valid, parsable EC public keys. + * * @param buffer The input buffer containing two concatenated components. * @return true if both components can be parsed successfully, false otherwise. */ bool isValidCiphertext(Slice const& buffer); +/** + * @brief Verifies that a buffer contains a valid, parsable compressed EC point. + * + * Can be used to validate both compressed public keys and Pedersen commitments. + * Fails early if the prefix byte is not 0x02 or 0x03. + * + * @param buffer The input buffer containing a compressed EC point (33 bytes). + * @return true if the point can be parsed successfully, false otherwise. + */ +bool +isValidCompressedECPoint(Slice const& buffer); + +/** + * @brief Homomorphically adds two ElGamal ciphertexts. + * + * Uses the additive homomorphic property of ElGamal encryption to compute + * Enc(a + b) from Enc(a) and Enc(b) without decryption. + * + * @param a The first ciphertext (66 bytes). + * @param b The second ciphertext (66 bytes). + * @param out Output: The resulting ciphertext Enc(a + b). + * @return tesSUCCESS on success, or an error code if parsing fails. + */ TER homomorphicAdd(Slice const& a, Slice const& b, Buffer& out); +/** + * @brief Homomorphically subtracts two ElGamal ciphertexts. + * + * Uses the additive homomorphic property of ElGamal encryption to compute + * Enc(a - b) from Enc(a) and Enc(b) without decryption. + * + * @param a The minuend ciphertext (66 bytes). + * @param b The subtrahend ciphertext (66 bytes). + * @param out Output: The resulting ciphertext Enc(a - b). + * @return tesSUCCESS on success, or an error code if parsing fails. + */ TER homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out); +/** + * @brief Encrypts an amount using ElGamal encryption. + * + * Produces a ciphertext C = (C1, C2) where C1 = r*G and C2 = m*G + r*Pk, + * using the provided blinding factor r. + * + * @param amt The plaintext amount to encrypt. + * @param pubKeySlice The recipient's ElGamal public key (64 bytes). + * @param blindingFactor The 32-byte randomness used as blinding factor r. + * @return The 66-byte ciphertext, or std::nullopt on failure. + */ +std::optional +encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor); + +/** + * @brief Generates the canonical zero encryption for a specific MPToken. + * + * Creates a deterministic encryption of zero that is unique to the account + * and MPT issuance. Used to initialize confidential balance fields. + * + * @param pubKeySlice The holder's ElGamal public key (64 bytes). + * @param account The account ID of the token holder. + * @param mptId The MPToken Issuance ID. + * @return The 66-byte canonical zero ciphertext, or std::nullopt on failure. + */ +std::optional +encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId); + +/** + * @brief Verifies a Schnorr proof of knowledge of an ElGamal private key. + * + * Proves that the submitter knows the secret key corresponding to the + * provided public key, without revealing the secret key itself. + * + * @param pubKeySlice The ElGamal public key (64 bytes). + * @param proofSlice The Schnorr proof (65 bytes). + * @param contextHash The 256-bit context hash binding the proof. + * @return tesSUCCESS if valid, or an error code otherwise. + */ TER -proveEquality( - Slice const& proof, - Slice const& encAmt, // encrypted amount - Slice const& pubkey, - uint64_t const amount, - uint256 const& txHash, // Transaction context data - std::uint32_t const spendVersion); +verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash); -Buffer -encryptAmount(uint64_t amt, Slice const& pubKeySlice); - -Buffer -encryptCanonicalZeroAmount( +/** + * @brief Verifies that a ciphertext correctly encrypts a revealed amount. + * + * Given the plaintext amount and blinding factor, verifies that the + * ciphertext was correctly constructed using ElGamal encryption. + * + * @param amount The revealed plaintext amount. + * @param blindingFactor The 32-byte blinding factor used in encryption. + * @param pubKeySlice The recipient's ElGamal public key (64 bytes). + * @param ciphertext The ciphertext to verify (66 bytes). + * @return tesSUCCESS if the encryption is valid, or an error code otherwise. + */ +TER +verifyElGamalEncryption( + std::uint64_t const amount, + Slice const& blindingFactor, Slice const& pubKeySlice, - AccountID const& account, - MPTID const& mptId); + Slice const& ciphertext); +/** + * @brief Validates the format of encrypted amount fields in a transaction. + * + * Checks that all ciphertext fields in the transaction object have the + * correct length and contain valid EC points. This function is only used + * by ConfidentialMPTConvert and ConfidentialMPTConvertBack transactions. + * + * @param object The transaction object containing encrypted amount fields. + * @return tesSUCCESS if all formats are valid, temMALFORMED if required fields + * are missing, or temBAD_CIPHERTEXT if format validation fails. + */ +NotTEC +checkEncryptedAmountFormat(STObject const& object); + +/** + * @brief Verifies revealed amount encryptions for all recipients. + * + * Validates that the same amount was correctly encrypted for the holder, + * issuer, and optionally the auditor using their respective public keys. + * + * @param amount The revealed plaintext amount. + * @param blindingFactor The 32-byte blinding factor used in all encryptions. + * @param holder The holder's public key and encrypted amount. + * @param issuer The issuer's public key and encrypted amount. + * @param auditor Optional auditor's public key and encrypted amount. + * @return tesSUCCESS if all encryptions are valid, or an error code otherwise. + */ TER -verifyConfidentialSendProof( +verifyRevealedAmount( + std::uint64_t const amount, + Slice const& blindingFactor, + ConfidentialRecipient const& holder, + ConfidentialRecipient const& issuer, + std::optional const& auditor); + +/** + * @brief Returns the number of recipients in a confidential transfer. + * + * Returns 4 if an auditor is present (sender, destination, issuer, auditor), + * or 3 if no auditor (sender, destination, issuer). + * + * @param hasAuditor Whether the issuance has an auditor configured. + * @return The number of recipients (3 or 4). + */ +constexpr std::size_t +getConfidentialRecipientCount(bool hasAuditor) +{ + return hasAuditor ? 4 : 3; +} + +/** + * @brief Calculates the size of a multi-ciphertext equality proof. + * + * The proof size varies based on the number of recipients because each + * additional recipient requires additional proof components. + * + * @param nRecipients The number of recipients in the transfer. + * @return The size in bytes of the equality proof. + */ +std::size_t +getMultiCiphertextEqualityProofSize(std::size_t nRecipients); + +/** + * @brief Verifies a multi-ciphertext equality proof. + * + * Proves that all ciphertexts in the recipients vector encrypt the same + * plaintext amount, without revealing the amount itself. + * + * @param proof The zero-knowledge proof bytes. + * @param recipients Vector of recipients with their public keys and ciphertexts. + * @param nRecipients The number of recipients (must match recipients.size()). + * @param contextHash The 256-bit context hash binding the proof. + * @return tesSUCCESS if the proof is valid, or an error code otherwise. + */ +TER +verifyMultiCiphertextEqualityProof( Slice const& proof, - Slice const& encSenderBalance, - Slice const& encSenderAmt, - Slice const& encDestAmt, - Slice const& encIssuerAmt, - Slice const& senderPubKey, - Slice const& destPubKey, - Slice const& issuerPubKey, - std::uint32_t const version, - uint256 const& txHash); + std::vector const& recipients, + std::size_t const nRecipients, + uint256 const& contextHash); -} // namespace ripple +/** + * @brief Verifies a clawback equality proof. + * + * Proves that the issuer knows the exact amount encrypted in the holder's + * balance ciphertext. Used in ConfidentialMPTClawback to verify the issuer + * can decrypt the balance using their private key. + * + * @param amount The revealed plaintext amount. + * @param proof The zero-knowledge proof bytes. + * @param pubKeySlice The issuer's ElGamal public key (64 bytes). + * @param ciphertext The issuer's encrypted balance on the holder's account (66 bytes). + * @param contextHash The 256-bit context hash binding the proof. + * @return tesSUCCESS if the proof is valid, or an error code otherwise. + */ +TER +verifyClawbackEqualityProof( + uint64_t const amount, + Slice const& proof, + Slice const& pubKeySlice, + Slice const& ciphertext, + uint256 const& contextHash); -#endif +/** + * @brief Generates a cryptographically secure 32-byte blinding factor. + * + * Produces random bytes suitable for use as an ElGamal blinding factor + * or Pedersen commitment randomness. + * + * @return A 32-byte buffer containing the random blinding factor. + */ +Buffer +generateBlindingFactor(); + +/** + * @brief Verifies the cryptographic link between an ElGamal Ciphertext and a + * Pedersen Commitment for a transaction Amount. + * + * It proves that the ElGamal ciphertext `encAmt` encrypts the same value `m` + * as the Pedersen Commitment `pcmSlice`, using the randomness `r`. + * Proves Enc(m) <-> Pcm(m) + * + * @param proof The Zero Knowledge Proof bytes. + * @param encAmt The ElGamal ciphertext of the amount (C1, C2). + * @param pubKeySlice The sender's public key. + * @param pcmSlice The Pedersen Commitment to the amount. + * @param contextHash The unique context hash for this transaction. + * @return tesSUCCESS if the proof is valid, or an error code otherwise. + */ +TER +verifyAmountPcmLinkage( + Slice const& proof, + Slice const& encAmt, + Slice const& pubKeySlice, + Slice const& pcmSlice, + uint256 const& contextHash); + +/** + * @brief Verifies the cryptographic link between an ElGamal Ciphertext and a + * Pedersen Commitment for an account Balance. + * + * It proves that the ElGamal ciphertext `encAmt` encrypts the same value `b` + * as the Pedersen Commitment `pcmSlice`, using the secret key `s`. + * Proves Enc(b) <-> Pcm(b) + * + * Note: Swaps arguments (Pk <-> C1) to accommodate the different algebraic + * structure. + * + * @param proof The Zero Knowledge Proof bytes. + * @param encAmt The ElGamal ciphertext of the balance (C1, C2). + * @param pubKeySlice The sender's public key. + * @param pcmSlice The Pedersen Commitment to the balance. + * @param contextHash The unique context hash for this transaction. + * @return tesSUCCESS if the proof is valid, or an error code otherwise. + */ +TER +verifyBalancePcmLinkage( + Slice const& proof, + Slice const& encAmt, + Slice const& pubKeySlice, + Slice const& pcmSlice, + uint256 const& contextHash); + +/** + * @brief Verifies an aggregated Bulletproof range proof. + * + * This function verifies that all commitments in commitment_C_vec commit + * to values within the valid 64-bit range [0, 2^64 - 1]. + * + * @param proof The serialized Bulletproof proof. + * @param compressedCommitments Vector of compressed Pedersen commitments (each 33 bytes). + * @param contextHash The unique context hash for this transaction. + * @return tesSUCCESS if the proof is valid, tecBAD_PROOF if verification + * fails, or tecINTERNAL for internal errors. + */ +TER +verifyAggregatedBulletproof( + Slice const& proof, + std::vector const& compressedCommitments, + uint256 const& contextHash); + +/** + * @brief Computes the remainder commitment for ConfidentialMPTSend. + * + * Given a balance commitment PC_bal = m_bal*G + rho_bal*H and an amount + * commitment PC_amt = m_amt*G + rho_amt*H, this function computes: + * PC_rem = PC_bal - PC_amt = (m_bal - m_amt)*G + (rho_bal - rho_amt)*H + * + * This derived commitment is used in an aggregated range proof to ensure + * the sender maintains a non-negative balance (m_bal - m_amt >= 0). + * + * @param balanceCommitment The compressed Pedersen commitment to the balance (33 bytes). + * @param amountCommitment The compressed Pedersen commitment to the amount (33 bytes). + * @param out Output buffer for the resulting remainder commitment (33 bytes). + * @return tesSUCCESS on success, tecINTERNAL on failure. + */ +TER +computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitment, Buffer& out); + +/** + * @brief Computes the remainder commitment for ConvertBack. + * + * Given a Pedersen commitment PC = m*G + rho*H, this function computes + * PC_rem = PC - amount*G = (m - amount)*G + rho*H + * + * @param commitment The compressed Pedersen commitment (33 bytes). + * @param amount The amount to subtract (must be non-zero). + * @param out Output buffer for the resulting commitment (33 bytes). + * @return tesSUCCESS on success, tecINTERNAL on failure or if amount is 0. + */ +TER +computeConvertBackRemainder(Slice const& commitment, std::uint64_t amount, Buffer& out); +} // namespace xrpl diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index 5da3ad0b33..08c034e38f 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 - 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED -#define RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { // VFALCO NOTE These are outside the RPC namespace @@ -161,8 +141,7 @@ enum error_code_i { rpcENTRY_NOT_FOUND = 98, rpcUNEXPECTED_LEDGER_TYPE = 99, - rpcLAST = - rpcUNEXPECTED_LEDGER_TYPE // rpcLAST should always equal the last code. + rpcLAST = rpcUNEXPECTED_LEDGER_TYPE // rpcLAST should always equal the last code. }; /** Codes returned in the `warnings` array of certain RPC commands. @@ -188,31 +167,17 @@ namespace RPC { struct ErrorInfo { // Default ctor needed to produce an empty std::array during constexpr eval. - constexpr ErrorInfo() - : code(rpcUNKNOWN) - , token("unknown") - , message("An unknown error code.") - , http_status(200) + constexpr ErrorInfo() : code(rpcUNKNOWN), token("unknown"), message("An unknown error code."), http_status(200) { } - constexpr ErrorInfo( - error_code_i code_, - char const* token_, - char const* message_) + constexpr ErrorInfo(error_code_i code_, char const* token_, char const* message_) : code(code_), token(token_), message(message_), http_status(200) { } - constexpr ErrorInfo( - error_code_i code_, - char const* token_, - char const* message_, - int http_status_) - : code(code_) - , token(token_) - , message(message_) - , http_status(http_status_) + constexpr ErrorInfo(error_code_i code_, char const* token_, char const* message_, int http_status_) + : code(code_), token(token_), message(message_), http_status(http_status_) { } @@ -228,33 +193,11 @@ get_error_info(error_code_i code); /** Add or update the json update to reflect the error code. */ /** @{ */ -template void -inject_error(error_code_i code, JsonValue& json) -{ - ErrorInfo const& info(get_error_info(code)); - json[jss::error] = info.token; - json[jss::error_code] = info.code; - json[jss::error_message] = info.message; -} +inject_error(error_code_i code, Json::Value& json); -template void -inject_error(int code, JsonValue& json) -{ - inject_error(error_code_i(code), json); -} - -template -void -inject_error(error_code_i code, std::string const& message, JsonValue& json) -{ - ErrorInfo const& info(get_error_info(code)); - json[jss::error] = info.token; - json[jss::error_code] = info.code; - json[jss::error_message] = message; -} - +inject_error(error_code_i code, std::string const& message, Json::Value& json); /** @} */ /** Returns a new json object that reflects the error code. */ @@ -379,6 +322,4 @@ error_code_http_status(error_code_i code); std::string rpcErrorString(Json::Value const& jv); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 5844a70eb0..6d674fbef2 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_FEATURE_H_INCLUDED -#define RIPPLE_PROTOCOL_FEATURE_H_INCLUDED +#pragma once #include @@ -82,7 +62,7 @@ * */ -namespace ripple { +namespace xrpl { enum class VoteBehavior : int { Obsolete = -1, DefaultNo = 0, DefaultYes }; enum class AmendmentSupport : int { Retired = -1, Supported = 0, Unsupported }; @@ -97,12 +77,15 @@ namespace detail { #undef XRPL_FEATURE #pragma push_macro("XRPL_FIX") #undef XRPL_FIX -#pragma push_macro("XRPL_RETIRE") -#undef XRPL_RETIRE +#pragma push_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FEATURE +#pragma push_macro("XRPL_RETIRE_FIX") +#undef XRPL_RETIRE_FIX #define XRPL_FEATURE(name, supported, vote) +1 #define XRPL_FIX(name, supported, vote) +1 -#define XRPL_RETIRE(name) +1 +#define XRPL_RETIRE_FEATURE(name) +1 +#define XRPL_RETIRE_FIX(name) +1 // This value SHOULD be equal to the number of amendments registered in // Feature.cpp. Because it's only used to reserve storage, and determine how @@ -113,8 +96,10 @@ static constexpr std::size_t numFeatures = #include ); -#undef XRPL_RETIRE -#pragma pop_macro("XRPL_RETIRE") +#undef XRPL_RETIRE_FEATURE +#pragma pop_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FIX +#pragma pop_macro("XRPL_RETIRE_FIX") #undef XRPL_FIX #pragma pop_macro("XRPL_FIX") #undef XRPL_FEATURE @@ -189,9 +174,7 @@ public: explicit FeatureBitset(base const& b) : base(b) { - XRPL_ASSERT( - b.count() == count(), - "ripple::FeatureBitset::FeatureBitset(base) : count match"); + XRPL_ASSERT(b.count() == count(), "xrpl::FeatureBitset::FeatureBitset(base) : count match"); } template @@ -200,7 +183,7 @@ public: initFromFeatures(f, std::forward(fs)...); XRPL_ASSERT( count() == (sizeof...(fs) + 1), - "ripple::FeatureBitset::FeatureBitset(uint256) : count and " + "xrpl::FeatureBitset::FeatureBitset(uint256) : count and " "sizeof... do match"); } @@ -211,7 +194,7 @@ public: set(featureToBitsetIndex(f)); XRPL_ASSERT( fs.size() == count(), - "ripple::FeatureBitset::FeatureBitset(Container auto) : count and " + "xrpl::FeatureBitset::FeatureBitset(Container auto) : count and " "size do match"); } @@ -271,8 +254,7 @@ public: friend FeatureBitset operator&(FeatureBitset const& lhs, FeatureBitset const& rhs) { - return FeatureBitset{ - static_cast(lhs) & static_cast(rhs)}; + return FeatureBitset{static_cast(lhs) & static_cast(rhs)}; } friend FeatureBitset @@ -290,8 +272,7 @@ public: friend FeatureBitset operator|(FeatureBitset const& lhs, FeatureBitset const& rhs) { - return FeatureBitset{ - static_cast(lhs) | static_cast(rhs)}; + return FeatureBitset{static_cast(lhs) | static_cast(rhs)}; } friend FeatureBitset @@ -309,8 +290,7 @@ public: friend FeatureBitset operator^(FeatureBitset const& lhs, FeatureBitset const& rhs) { - return FeatureBitset{ - static_cast(lhs) ^ static_cast(rhs)}; + return FeatureBitset{static_cast(lhs) ^ static_cast(rhs)}; } friend FeatureBitset @@ -358,22 +338,25 @@ foreachFeature(FeatureBitset bs, F&& f) #undef XRPL_FEATURE #pragma push_macro("XRPL_FIX") #undef XRPL_FIX -#pragma push_macro("XRPL_RETIRE") -#undef XRPL_RETIRE +#pragma push_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FEATURE +#pragma push_macro("XRPL_RETIRE_FIX") +#undef XRPL_RETIRE_FIX #define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name; #define XRPL_FIX(name, supported, vote) extern uint256 const fix##name; -#define XRPL_RETIRE(name) +#define XRPL_RETIRE_FEATURE(name) +#define XRPL_RETIRE_FIX(name) #include -#undef XRPL_RETIRE -#pragma pop_macro("XRPL_RETIRE") +#undef XRPL_RETIRE_FEATURE +#pragma pop_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FIX +#pragma pop_macro("XRPL_RETIRE_FIX") #undef XRPL_FIX #pragma pop_macro("XRPL_FIX") #undef XRPL_FEATURE #pragma pop_macro("XRPL_FEATURE") -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h index 4393f1a1d9..84c8ffe81f 100644 --- a/include/xrpl/protocol/Fees.h +++ b/include/xrpl/protocol/Fees.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_FEES_H_INCLUDED -#define RIPPLE_PROTOCOL_FEES_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Reflects the fee settings for a particular ledger. @@ -52,6 +32,4 @@ struct Fees } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h index 7e486af4c0..305b4bfd49 100644 --- a/include/xrpl/protocol/HashPrefix.h +++ b/include/xrpl/protocol/HashPrefix.h @@ -1,38 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED -#define RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace detail { constexpr std::uint32_t make_hash_prefix(char a, char b, char c) { - return (static_cast(a) << 24) + - (static_cast(b) << 16) + + return (static_cast(a) << 24) + (static_cast(b) << 16) + (static_cast(c) << 8); } @@ -86,9 +65,6 @@ enum class HashPrefix : std::uint32_t { /** Payment Channel Claim */ paymentChannelClaim = detail::make_hash_prefix('C', 'L', 'M'), - /** Credentials signature */ - credential = detail::make_hash_prefix('C', 'R', 'D'), - /** Batch */ batch = detail::make_hash_prefix('B', 'C', 'H'), }; @@ -101,6 +77,4 @@ hash_append(Hasher& h, HashPrefix const& hp) noexcept hash_append(h, static_cast(hp)); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h index 93fba4150d..52c2272da0 100644 --- a/include/xrpl/protocol/IOUAmount.h +++ b/include/xrpl/protocol/IOUAmount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED -#define RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Floating point representation of amounts with high dynamic range @@ -39,14 +19,15 @@ namespace ripple { Arithmetic operations can throw std::overflow_error during normalization if the amount exceeds the largest representable amount, but underflows - will silently trunctate to zero. + will silently truncate to zero. */ -class IOUAmount : private boost::totally_ordered, - private boost::additive +class IOUAmount : private boost::totally_ordered, private boost::additive { private: - std::int64_t mantissa_; - int exponent_; + using mantissa_type = std::int64_t; + using exponent_type = int; + mantissa_type mantissa_; + exponent_type exponent_; /** Adjusts the mantissa and exponent to the proper range. @@ -57,11 +38,14 @@ private: void normalize(); + static IOUAmount + fromNumber(Number const& number); + public: IOUAmount() = default; explicit IOUAmount(Number const& other); IOUAmount(beast::Zero); - IOUAmount(std::int64_t mantissa, int exponent); + IOUAmount(mantissa_type mantissa, exponent_type exponent); IOUAmount& operator=(beast::Zero); @@ -90,10 +74,10 @@ public: int signum() const noexcept; - int + exponent_type exponent() const noexcept; - std::int64_t + mantissa_type mantissa() const noexcept; static IOUAmount @@ -111,8 +95,7 @@ inline IOUAmount::IOUAmount(beast::Zero) *this = beast::zero; } -inline IOUAmount::IOUAmount(std::int64_t mantissa, int exponent) - : mantissa_(mantissa), exponent_(exponent) +inline IOUAmount::IOUAmount(mantissa_type mantissa, exponent_type exponent) : mantissa_(mantissa), exponent_(exponent) { normalize(); } @@ -168,13 +151,13 @@ IOUAmount::signum() const noexcept return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0); } -inline int +inline IOUAmount::exponent_type IOUAmount::exponent() const noexcept { return exponent_; } -inline std::int64_t +inline IOUAmount::mantissa_type IOUAmount::mantissa() const noexcept { return mantissa_; @@ -189,11 +172,7 @@ to_string(IOUAmount const& amount); dividing by den. */ IOUAmount -mulRatio( - IOUAmount const& amt, - std::uint32_t num, - std::uint32_t den, - bool roundUp); +mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp); // Since many uses of the number class do not have access to a ledger, // getSTNumberSwitchover needs to be globally accessible. @@ -227,6 +206,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 79be15d906..f1e0b1655a 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_INDEXES_H_INCLUDED -#define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED +#pragma once #include #include @@ -34,10 +14,10 @@ #include #include -namespace ripple { +namespace xrpl { class SeqProxy; -/** Keylet computation funclets. +/** Keylet computation functions. Entries in the ledger are located using 256-bit locators. The locators are calculated using a wide range of parameters specific to the entry whose @@ -113,10 +93,7 @@ static book_t const book{}; */ /** @{ */ Keylet -line( - AccountID const& id0, - AccountID const& id1, - Currency const& currency) noexcept; +line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept; inline Keylet line(AccountID const& id, Issue const& issue) noexcept @@ -192,9 +169,7 @@ Keylet depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept; Keylet -depositPreauth( - AccountID const& owner, - std::set> const& authCreds) noexcept; +depositPreauth(AccountID const& owner, std::set> const& authCreds) noexcept; inline Keylet depositPreauth(uint256 const& key) noexcept @@ -221,8 +196,7 @@ page(uint256 const& root, std::uint64_t index = 0) noexcept; inline Keylet page(Keylet const& root, std::uint64_t index = 0) noexcept { - XRPL_ASSERT( - root.type == ltDIR_NODE, "ripple::keylet::page : valid root type"); + XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::keylet::page : valid root type"); return page(root.key, index); } /** @} */ @@ -302,10 +276,7 @@ Keylet oracle(AccountID const& account, std::uint32_t const& documentID) noexcept; Keylet -credential( - AccountID const& subject, - AccountID const& issuer, - Slice const& credType) noexcept; +credential(AccountID const& subject, AccountID const& issuer, Slice const& credType) noexcept; inline Keylet credential(uint256 const& key) noexcept @@ -346,6 +317,24 @@ vault(uint256 const& vaultKey) return {ltVAULT, vaultKey}; } +Keylet +loanbroker(AccountID const& owner, std::uint32_t seq) noexcept; + +inline Keylet +loanbroker(uint256 const& key) +{ + return {ltLOAN_BROKER, key}; +} + +Keylet +loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept; + +inline Keylet +loan(uint256 const& key) +{ + return {ltLOAN, key}; +} + Keylet permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept; @@ -394,6 +383,4 @@ std::array, 6> const directAccountKeylets{ MPTID makeMptID(std::uint32_t sequence, AccountID const& account); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/InnerObjectFormats.h b/include/xrpl/protocol/InnerObjectFormats.h index 06ca5af385..a00e6e120b 100644 --- a/include/xrpl/protocol/InnerObjectFormats.h +++ b/include/xrpl/protocol/InnerObjectFormats.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED -#define RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Manages the list of known inner object formats. */ @@ -42,6 +22,4 @@ public: findSOTemplateBySField(SField const& sField) const; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index eb4861f59b..c8e598a540 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED -#define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** A currency issued by an account. @see Currency, AccountID, Issue, Book @@ -56,6 +36,9 @@ public: bool native() const; + bool + integral() const; + friend constexpr std::weak_ordering operator<=>(Issue const& lhs, Issue const& rhs); }; @@ -88,8 +71,7 @@ hash_append(Hasher& h, Issue const& r) [[nodiscard]] inline constexpr bool operator==(Issue const& lhs, Issue const& rhs) { - return (lhs.currency == rhs.currency) && - (isXRP(lhs.currency) || lhs.account == rhs.account); + return (lhs.currency == rhs.currency) && (isXRP(lhs.currency) || lhs.account == rhs.account); } /** @} */ @@ -132,6 +114,4 @@ isXRP(Issue const& issue) return issue.native(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/KeyType.h b/include/xrpl/protocol/KeyType.h index 810e3e6fdf..d05e421e4b 100644 --- a/include/xrpl/protocol/KeyType.h +++ b/include/xrpl/protocol/KeyType.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_KEYTYPE_H_INCLUDED -#define RIPPLE_PROTOCOL_KEYTYPE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { enum class KeyType { secp256k1 = 0, @@ -61,6 +41,4 @@ operator<<(Stream& s, KeyType type) return s << to_string(type); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Keylet.h b/include/xrpl/protocol/Keylet.h index d3bda10331..2931486ac0 100644 --- a/include/xrpl/protocol/Keylet.h +++ b/include/xrpl/protocol/Keylet.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_KEYLET_H_INCLUDED -#define RIPPLE_PROTOCOL_KEYLET_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class STLedgerEntry; @@ -49,6 +29,4 @@ struct Keylet check(STLedgerEntry const&) const; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/KnownFormats.h b/include/xrpl/protocol/KnownFormats.h index db2042eade..67701c91ca 100644 --- a/include/xrpl/protocol/KnownFormats.h +++ b/include/xrpl/protocol/KnownFormats.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED -#define RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Manages a list of known formats. @@ -56,8 +36,7 @@ public: { // Verify that KeyType is appropriate. static_assert( - std::is_enum::value || - std::is_integral::value, + std::is_enum::value || std::is_integral::value, "KnownFormats KeyType must be integral or enum."); } @@ -119,8 +98,7 @@ public: if (auto const result = findByName(name)) return result->getType(); Throw( - name_ + ": Unknown format name '" + - name.substr(0, std::min(name.size(), std::size_t(32))) + "'"); + name_ + ": Unknown format name '" + name.substr(0, std::min(name.size(), std::size_t(32))) + "'"); } /** Retrieve a format based on its type. @@ -176,9 +154,7 @@ protected: { if (auto const item = findByType(type)) { - LogicError( - std::string("Duplicate key for item '") + name + - "': already maps to " + item->getName()); + LogicError(std::string("Duplicate key for item '") + name + "': already maps to " + item->getName()); } formats_.emplace_front(name, type, uniqueFields, commonFields); @@ -202,6 +178,4 @@ private: boost::container::flat_map types_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 5ea470269a..2ce894c183 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED -#define RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Identifiers for on-ledger objects. @@ -187,8 +167,10 @@ enum LedgerSpecificFlags { lsfMPTCanTrade = 0x00000010, lsfMPTCanTransfer = 0x00000020, lsfMPTCanClawback = 0x00000040, - lsfMPTNoConfidentialTransfer = 0x00000080, + lsfMPTCanPrivacy = 0x00000080, + // Mutable flags (lsmf prefix) control whether the issuer can change + // corresponding feature flags after issuance via MPTokenIssuanceSet. lsmfMPTCanMutateCanLock = 0x00000002, lsmfMPTCanMutateRequireAuth = 0x00000004, lsmfMPTCanMutateCanEscrow = 0x00000008, @@ -197,6 +179,12 @@ enum LedgerSpecificFlags { lsmfMPTCanMutateCanClawback = 0x00000040, lsmfMPTCanMutateMetadata = 0x00010000, lsmfMPTCanMutateTransferFee = 0x00020000, + // Controls mutability of lsfMPTCanPrivacy. Note the inverted naming: + // - Other mutable flags: "CanMutate" means issuer CAN change the setting + // - This flag: "CannotMutate" means issuer CANNOT change the setting + // By default (flag not set), issuer can toggle lsfMPTCanPrivacy on/off. + // If set, lsfMPTCanPrivacy is permanently locked to its creation value. + lsmfMPTCannotMutatePrivacy = 0x00040000, // ltMPTOKEN lsfMPTAuthorized = 0x00000002, @@ -206,6 +194,11 @@ enum LedgerSpecificFlags { // ltVAULT lsfVaultPrivate = 0x00010000, + + // ltLOAN + lsfLoanDefault = 0x00010000, + lsfLoanImpaired = 0x00020000, + lsfLoanOverpayment = 0x00040000, // True, loan allows overpayments }; //------------------------------------------------------------------------------ @@ -225,6 +218,4 @@ public: getInstance(); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h index 0b35979971..1dc67cada5 100644 --- a/include/xrpl/protocol/LedgerHeader.h +++ b/include/xrpl/protocol/LedgerHeader.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED -#define RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Information about the notional ledger backing the view. */ struct LedgerHeader @@ -72,12 +52,6 @@ struct LedgerHeader NetClock::time_point closeTime = {}; }; -// We call them "headers" in conversation -// but "info" in code. Unintuitive. -// This alias lets us give the "correct" name to the class -// without yet disturbing existing uses. -using LedgerInfo = LedgerHeader; - // ledger close flags static std::uint32_t const sLCF_NoConsensusTime = 0x01; @@ -98,6 +72,4 @@ deserializeHeader(Slice data, bool hasHash = false); LedgerHeader deserializePrefixedHeader(Slice data, bool hasHash = false); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/LedgerShortcut.h b/include/xrpl/protocol/LedgerShortcut.h new file mode 100644 index 0000000000..68c31c4c3c --- /dev/null +++ b/include/xrpl/protocol/LedgerShortcut.h @@ -0,0 +1,22 @@ +#pragma once + +namespace xrpl { + +/** + * @brief Enumeration of ledger shortcuts for specifying which ledger to use. + * + * These shortcuts provide a convenient way to reference commonly used ledgers + * without needing to specify their exact hash or sequence number. + */ +enum class LedgerShortcut { + /** The current working ledger (open, not yet closed) */ + Current, + + /** The most recently closed ledger (may not be validated) */ + Closed, + + /** The most recently validated ledger */ + Validated +}; + +} // namespace xrpl diff --git a/include/xrpl/protocol/MPTAmount.h b/include/xrpl/protocol/MPTAmount.h index 419450eeb9..66027185b3 100644 --- a/include/xrpl/protocol/MPTAmount.h +++ b/include/xrpl/protocol/MPTAmount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED -#define RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { class MPTAmount : private boost::totally_ordered, private boost::additive, @@ -142,11 +122,7 @@ to_string(MPTAmount const& amount) } inline MPTAmount -mulRatio( - MPTAmount const& amt, - std::uint32_t num, - std::uint32_t den, - bool roundUp) +mulRatio(MPTAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp) { using namespace boost::multiprecision; @@ -169,6 +145,4 @@ mulRatio( return MPTAmount(r.convert_to()); } -} // namespace ripple - -#endif // RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/MPTIssue.h b/include/xrpl/protocol/MPTIssue.h index d1c757337e..d84a610418 100644 --- a/include/xrpl/protocol/MPTIssue.h +++ b/include/xrpl/protocol/MPTIssue.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED -#define RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /* Adapt MPTID to provide the same interface as Issue. Enables using static * polymorphism by Asset and other classes. MPTID is a 192-bit concatenation @@ -65,6 +45,12 @@ public: { return false; } + + bool + integral() const + { + return true; + } }; constexpr bool @@ -96,6 +82,4 @@ to_string(MPTIssue const& mptIssue); MPTIssue mptIssueFromJson(Json::Value const& jv); -} // namespace ripple - -#endif // RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index 4a3d0115de..ad7a6b8f0d 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED -#define RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { template @@ -103,84 +83,52 @@ struct MultiApiJson static constexpr struct visitor_t final { // integral_constant version, extra arguments - template < - typename Json, - unsigned int Version, - typename... Args, - typename Fn> + template requires std::same_as, MultiApiJson> auto - operator()( - Json& json, - std::integral_constant const version, - Fn fn, - Args&&... args) const - -> std::invoke_result_t< - Fn, - decltype(json.val[0]), - std::integral_constant, - Args&&...> + operator()(Json& json, std::integral_constant const version, Fn fn, Args&&... args) const + -> std::invoke_result_t, Args&&...> { - static_assert( - valid(Version) && index(Version) >= 0 && index(Version) < size); - return std::invoke( - fn, - json.val[index(Version)], - version, - std::forward(args)...); + static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size); + return std::invoke(fn, json.val[index(Version)], version, std::forward(args)...); } // integral_constant version, Json only template requires std::same_as, MultiApiJson> auto - operator()( - Json& json, - std::integral_constant const, - Fn fn) const -> std::invoke_result_t + operator()(Json& json, std::integral_constant const, Fn fn) const + -> std::invoke_result_t { - static_assert( - valid(Version) && index(Version) >= 0 && index(Version) < size); + static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size); return std::invoke(fn, json.val[index(Version)]); } // unsigned int version, extra arguments - template < - typename Json, - typename Version, - typename... Args, - typename Fn> - requires(!some_integral_constant) && - std::convertible_to && + template + requires(!some_integral_constant) && std::convertible_to && std::same_as, MultiApiJson> auto operator()(Json& json, Version version, Fn fn, Args&&... args) const - -> std:: - invoke_result_t + -> std::invoke_result_t { XRPL_ASSERT( valid(version) && index(version) >= 0 && index(version) < size, - "ripple::detail::MultiApiJson::operator() : valid " + "xrpl::detail::MultiApiJson::operator() : valid " "version"); - return std::invoke( - fn, - json.val[index(version)], - version, - std::forward(args)...); + return std::invoke(fn, json.val[index(version)], version, std::forward(args)...); } // unsigned int version, Json only template - requires(!some_integral_constant) && - std::convertible_to && + requires(!some_integral_constant) && std::convertible_to && std::same_as, MultiApiJson> auto - operator()(Json& json, Version version, Fn fn) const - -> std::invoke_result_t + operator()(Json& json, Version version, Fn fn) const -> std::invoke_result_t { XRPL_ASSERT( valid(version) && index(version) >= 0 && index(version) < size, - "ripple::detail::MultiApiJson::operator() : valid version"); + "xrpl::detail::MultiApiJson::operator() : valid version"); return std::invoke(fn, json.val[index(version)]); } } visitor = {}; @@ -189,11 +137,7 @@ struct MultiApiJson visit() { return [self = this](auto... args) - requires requires { - visitor( - std::declval(), - std::declval()...); - } + requires requires { visitor(std::declval(), std::declval()...); } { return visitor(*self, std::forward(args)...); }; } @@ -201,30 +145,22 @@ struct MultiApiJson visit() const { return [self = this](auto... args) - requires requires { - visitor( - std::declval(), - std::declval()...); - } + requires requires { visitor(std::declval(), std::declval()...); } { return visitor(*self, std::forward(args)...); }; } template auto - visit(Args... args) - -> std::invoke_result_t - requires(sizeof...(args) > 0) && - requires { visitor(*this, std::forward(args)...); } + visit(Args... args) -> std::invoke_result_t + requires(sizeof...(args) > 0) && requires { visitor(*this, std::forward(args)...); } { return visitor(*this, std::forward(args)...); } template auto - visit(Args... args) const - -> std::invoke_result_t - requires(sizeof...(args) > 0) && - requires { visitor(*this, std::forward(args)...); } + visit(Args... args) const -> std::invoke_result_t + requires(sizeof...(args) > 0) && requires { visitor(*this, std::forward(args)...); } { return visitor(*this, std::forward(args)...); } @@ -233,9 +169,6 @@ struct MultiApiJson } // namespace detail // Wrapper for Json for all supported API versions. -using MultiApiJson = detail:: - MultiApiJson; +using MultiApiJson = detail::MultiApiJson; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h index cb33744485..c33a6edc7d 100644 --- a/include/xrpl/protocol/NFTSyntheticSerializer.h +++ b/include/xrpl/protocol/NFTSyntheticSerializer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED -#define RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace RPC { @@ -36,13 +16,8 @@ namespace RPC { @{ */ void -insertNFTSyntheticInJson( - Json::Value&, - std::shared_ptr const&, - TxMeta const&); +insertNFTSyntheticInJson(Json::Value&, std::shared_ptr const&, TxMeta const&); /** @} */ } // namespace RPC -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/NFTokenID.h b/include/xrpl/protocol/NFTokenID.h index b9ea75d203..f3635d6fac 100644 --- a/include/xrpl/protocol/NFTokenID.h +++ b/include/xrpl/protocol/NFTokenID.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED -#define RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Add a `nftoken_ids` field to the `meta` output parameter. @@ -40,9 +20,7 @@ namespace ripple { @{ */ bool -canHaveNFTokenID( - std::shared_ptr const& serializedTx, - TxMeta const& transactionMeta); +canHaveNFTokenID(std::shared_ptr const& serializedTx, TxMeta const& transactionMeta); std::optional getNFTokenIDFromPage(TxMeta const& transactionMeta); @@ -51,12 +29,7 @@ std::vector getNFTokenIDFromDeletedOffer(TxMeta const& transactionMeta); void -insertNFTokenID( - Json::Value& response, - std::shared_ptr const& transaction, - TxMeta const& transactionMeta); +insertNFTokenID(Json::Value& response, std::shared_ptr const& transaction, TxMeta const& transactionMeta); /** @} */ -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/NFTokenOfferID.h b/include/xrpl/protocol/NFTokenOfferID.h index 9645b0b34d..c3117db197 100644 --- a/include/xrpl/protocol/NFTokenOfferID.h +++ b/include/xrpl/protocol/NFTokenOfferID.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED -#define RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Add an `offer_id` field to the `meta` output parameter. @@ -38,9 +18,7 @@ namespace ripple { @{ */ bool -canHaveNFTokenOfferID( - std::shared_ptr const& serializedTx, - TxMeta const& transactionMeta); +canHaveNFTokenOfferID(std::shared_ptr const& serializedTx, TxMeta const& transactionMeta); std::optional getOfferIDFromCreatedOffer(TxMeta const& transactionMeta); @@ -52,6 +30,4 @@ insertNFTokenOfferID( TxMeta const& transactionMeta); /** @} */ -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/PayChan.h b/include/xrpl/protocol/PayChan.h index b552b591af..0a1496ca8e 100644 --- a/include/xrpl/protocol/PayChan.h +++ b/include/xrpl/protocol/PayChan.h @@ -1,43 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED -#define RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { inline void -serializePayChanAuthorization( - Serializer& msg, - uint256 const& key, - XRPAmount const& amt) +serializePayChanAuthorization(Serializer& msg, uint256 const& key, XRPAmount const& amt) { msg.add32(HashPrefix::paymentChannelClaim); msg.addBitString(key); msg.add64(amt.drops()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h index d3f5253cd0..e8800a41d2 100644 --- a/include/xrpl/protocol/Permissions.h +++ b/include/xrpl/protocol/Permissions.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED -#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { /** * We have both transaction type permissions and granular type permissions. * Since we will reuse the TransactionFormats to parse the Transaction @@ -48,7 +28,7 @@ enum GranularPermissionType : std::uint32_t { #pragma pop_macro("PERMISSION") }; -enum Delegation { delegatable, notDelegatable }; +enum Delegation { delegable, notDelegable }; class Permission { @@ -57,10 +37,9 @@ private: std::unordered_map txFeatureMap_; - std::unordered_map delegatableTx_; + std::unordered_map delegableTx_; - std::unordered_map - granularPermissionMap_; + std::unordered_map granularPermissionMap_; std::unordered_map granularNameMap_; @@ -90,8 +69,7 @@ public: getTxFeature(TxType txType) const; bool - isDelegatable(std::uint32_t const& permissionValue, Rules const& rules) - const; + isDelegable(std::uint32_t const& permissionValue, Rules const& rules) const; // for tx level permission, permission value is equal to tx type plus one uint32_t @@ -102,6 +80,4 @@ public: permissionToTxType(uint32_t const& value) const; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index bdbdbda916..1c779a36ec 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -1,31 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED -#define RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED +#pragma once #include #include +#include #include -namespace ripple { +namespace xrpl { /** Protocol specific constants. @@ -84,6 +65,139 @@ std::size_t constexpr maxDeletableTokenOfferEntries = 500; */ std::uint16_t constexpr maxTransferFee = 50000; +/** There are 10,000 basis points (bips) in 100%. + * + * Basis points represent 0.01%. + * + * Given a value X, to find the amount for B bps, + * use X * B / bipsPerUnity + * + * Example: If a loan broker has 999 XRP of debt, and must maintain 1,000 bps of + * that debt as cover (10%), then the minimum cover amount is 999,000,000 drops + * * 1000 / bipsPerUnity = 99,900,00 drops or 99.9 XRP. + * + * Given a percentage P, to find the number of bps that percentage represents, + * use P * bipsPerUnity. + * + * Example: 50% is 0.50 * bipsPerUnity = 5,000 bps. + */ +Bips32 constexpr bipsPerUnity(100 * 100); +static_assert(bipsPerUnity == Bips32{10'000}); +TenthBips32 constexpr tenthBipsPerUnity(bipsPerUnity.value() * 10); +static_assert(tenthBipsPerUnity == TenthBips32(100'000)); + +constexpr Bips32 +percentageToBips(std::uint32_t percentage) +{ + return Bips32(percentage * bipsPerUnity.value() / 100); +} +constexpr TenthBips32 +percentageToTenthBips(std::uint32_t percentage) +{ + return TenthBips32(percentage * tenthBipsPerUnity.value() / 100); +} +template +constexpr T +bipsOfValue(T value, Bips bips) +{ + return value * bips.value() / bipsPerUnity.value(); +} +template +constexpr T +tenthBipsOfValue(T value, TenthBips bips) +{ + return value * bips.value() / tenthBipsPerUnity.value(); +} + +namespace Lending { +/** The maximum management fee rate allowed by a loan broker in 1/10 bips. + + Valid values are between 0 and 10% inclusive. +*/ +TenthBips16 constexpr maxManagementFeeRate(unsafe_cast(percentageToTenthBips(10).value())); +static_assert(maxManagementFeeRate == TenthBips16(std::uint16_t(10'000u))); + +/** The maximum coverage rate required of a loan broker in 1/10 bips. + + Valid values are between 0 and 100% inclusive. +*/ +TenthBips32 constexpr maxCoverRate = percentageToTenthBips(100); +static_assert(maxCoverRate == TenthBips32(100'000u)); + +/** The maximum overpayment fee on a loan in 1/10 bips. +* + Valid values are between 0 and 100% inclusive. +*/ +TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100); +static_assert(maxOverpaymentFee == TenthBips32(100'000u)); + +/** Annualized interest rate of the Loan in 1/10 bips. + * + * Valid values are between 0 and 100% inclusive. + */ +TenthBips32 constexpr maxInterestRate = percentageToTenthBips(100); +static_assert(maxInterestRate == TenthBips32(100'000u)); + +/** The maximum premium added to the interest rate for late payments on a loan + * in 1/10 bips. + * + * Valid values are between 0 and 100% inclusive. + */ +TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100); +static_assert(maxLateInterestRate == TenthBips32(100'000u)); + +/** The maximum close interest rate charged for repaying a loan early in 1/10 + * bips. + * + * Valid values are between 0 and 100% inclusive. + */ +TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100); +static_assert(maxCloseInterestRate == TenthBips32(100'000u)); + +/** The maximum overpayment interest rate charged on loan overpayments in 1/10 + * bips. + * + * Valid values are between 0 and 100% inclusive. + */ +TenthBips32 constexpr maxOverpaymentInterestRate = percentageToTenthBips(100); +static_assert(maxOverpaymentInterestRate == TenthBips32(100'000u)); + +/** LoanPay transaction cost will be one base fee per X combined payments + * + * The number of payments is estimated based on the Amount paid and the Loan's + * Fixed Payment size. Overpayments (indicated with the tfLoanOverpayment flag) + * count as one more payment. + * + * This number was chosen arbitrarily, but should not be changed once released + * without an amendment + */ +static constexpr int loanPaymentsPerFeeIncrement = 5; + +/** Maximum number of combined payments that a LoanPay transaction will process + * + * This limit is enforced during the loan payment process, and thus is not + * estimated. If the limit is hit, no further payments or overpayments will be + * processed, no matter how much of the transaction Amount is left, but the + * transaction will succeed with the payments that have been processed up to + * that point. + * + * This limit is independent of loanPaymentsPerFeeIncrement, so a transaction + * could potentially be charged for many more payments than actually get + * processed. Users should take care not to submit a transaction paying more + * than loanMaximumPaymentsPerTransaction * Loan.PeriodicPayment. Because + * overpayments are charged as a payment, if submitting + * loanMaximumPaymentsPerTransaction * Loan.PeriodicPayment, users should not + * set the tfLoanOverpayment flag. + * + * Even though they're independent, loanMaximumPaymentsPerTransaction should be + * a multiple of loanPaymentsPerFeeIncrement. + * + * This number was chosen arbitrarily, but should not be changed once released + * without an amendment + */ +static constexpr int loanMaximumPaymentsPerTransaction = 100; +} // namespace Lending + /** The maximum length of a URI inside an NFT */ std::size_t constexpr maxTokenURILength = 256; @@ -117,6 +231,7 @@ std::size_t constexpr maxMPTokenMetadataLength = 1024; /** The maximum amount of MPTokenIssuance */ std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull; +static_assert(Number::maxRep >= maxMPTokenAmount); /** The maximum length of Data payload */ std::size_t constexpr maxDataPayloadLength = 256; @@ -187,14 +302,37 @@ std::size_t constexpr ecGamalEncryptedLength = 33; /** EC ElGamal ciphertext length: two 33-byte components concatenated */ std::size_t constexpr ecGamalEncryptedTotalLength = 66; -/** Length of equality ZKProof */ +/** Length of equality ZKProof in bytes */ std::size_t constexpr ecEqualityProofLength = 98; -/** Length of EC public key */ -std::size_t constexpr ecPubKeyLength = 64; +/** Length of EC point (compressed) */ +std::size_t constexpr compressedECPointLength = 33; -/** Length of EC private key */ +/** Length of EC public key (compressed) */ +std::size_t constexpr ecPubKeyLength = compressedECPointLength; + +/** Length of EC private key in bytes */ std::size_t constexpr ecPrivKeyLength = 32; -} // namespace ripple -#endif +/** Length of the EC blinding factor in bytes */ +std::size_t constexpr ecBlindingFactorLength = 32; + +/** Length of Schnorr ZKProof for public key registration in bytes */ +std::size_t constexpr ecSchnorrProofLength = 65; + +/** Length of ElGamal ciphertext equality proof in bytes */ +std::size_t constexpr ecCiphertextEqualityProofLength = 261; + +/** Length of ElGamal Pedersen linkage proof in bytes */ +std::size_t constexpr ecPedersenProofLength = 195; + +/** Length of Pedersen Commitment (compressed) */ +std::size_t constexpr ecPedersenCommitmentLength = compressedECPointLength; + +/** Length of single bulletproof (range proof for 1 commitment) in bytes */ +std::size_t constexpr ecSingleBulletproofLength = 688; + +/** Length of double bulletproof (range proof for 2 commitments) in bytes */ +std::size_t constexpr ecDoubleBulletproofLength = 754; + +} // namespace xrpl diff --git a/include/xrpl/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h index a54f593fee..eff2af6839 100644 --- a/include/xrpl/protocol/PublicKey.h +++ b/include/xrpl/protocol/PublicKey.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED -#define RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { /** A public key. @@ -145,11 +125,7 @@ operator==(PublicKey const& lhs, PublicKey const& rhs) inline bool operator<(PublicKey const& lhs, PublicKey const& rhs) { - return std::lexicographical_compare( - lhs.data(), - lhs.data() + lhs.size(), - rhs.data(), - rhs.data() + rhs.size()); + return std::lexicographical_compare(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size()); } template @@ -250,11 +226,7 @@ verifyDigest( SHA512-Half, and the resulting digest is signed. */ [[nodiscard]] bool -verify( - PublicKey const& publicKey, - Slice const& m, - Slice const& sig, - bool mustBeFullyCanonical = true) noexcept; +verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept; /** Calculate the 160-bit node ID from a node public key. */ NodeID @@ -283,23 +255,22 @@ getFingerprint( } return ss.str(); } -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ namespace Json { template <> -inline ripple::PublicKey -getOrThrow(Json::Value const& v, ripple::SField const& field) +inline xrpl::PublicKey +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; std::string const b58 = getOrThrow(v, field); if (auto pubKeyBlob = strUnHex(b58); publicKeyType(makeSlice(*pubKeyBlob))) { return PublicKey{makeSlice(*pubKeyBlob)}; } - for (auto const tokenType : - {TokenType::NodePublic, TokenType::AccountPublic}) + for (auto const tokenType : {TokenType::NodePublic, TokenType::AccountPublic}) { if (auto const pk = parseBase58(tokenType, b58)) return *pk; @@ -307,5 +278,3 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) Throw(field.getJsonName(), "PublicKey"); } } // namespace Json - -#endif diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h index f1a3a58224..4d3fcbfcc0 100644 --- a/include/xrpl/protocol/Quality.h +++ b/include/xrpl/protocol/Quality.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED -#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Represents a pair of input and output currencies. @@ -134,15 +114,13 @@ public: /** Create a quality from the ratio of two amounts. */ template - explicit Quality(TAmounts const& amount) - : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out))) + explicit Quality(TAmounts const& amount) : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out))) { } /** Create a quality from the ratio of two amounts. */ template - Quality(Out const& out, In const& in) - : Quality(Amounts(toSTAmount(in), toSTAmount(out))) + Quality(Out const& out, In const& in) : Quality(Amounts(toSTAmount(in), toSTAmount(out))) { } @@ -192,15 +170,11 @@ public: // low order bits that could influence rounding decisions. This "strict" // method uses underlying functions that pay attention to all the bits. [[nodiscard]] Amounts - ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) - const; + ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const; template [[nodiscard]] TAmounts - ceil_in_strict( - TAmounts const& amount, - In const& limit, - bool roundUp) const; + ceil_in_strict(TAmounts const& amount, In const& limit, bool roundUp) const; /** Returns the scaled amount with out capped. Math is avoided if the result is exact. The input is clamped @@ -217,26 +191,17 @@ public: // low order bits that could influence rounding decisions. This "strict" // method uses underlying functions that pay attention to all the bits. [[nodiscard]] Amounts - ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) - const; + ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const; template [[nodiscard]] TAmounts - ceil_out_strict( - TAmounts const& amount, - Out const& limit, - bool roundUp) const; + ceil_out_strict(TAmounts const& amount, Out const& limit, bool roundUp) const; private: // The ceil_in and ceil_out methods that deal in TAmount all convert - // their arguments to STAoumout and convert the result back to TAmount. + // their arguments to STAmount and convert the result back to TAmount. // This helper function takes care of all the conversion operations. - template < - class In, - class Out, - class Lim, - typename FnPtr, - std::same_as... Round> + template ... Round> [[nodiscard]] TAmounts ceil_TAmounts_helper( TAmounts const& amount, @@ -298,29 +263,22 @@ public: friend double relativeDistance(Quality const& q1, Quality const& q2) { - XRPL_ASSERT( - q1.m_value > 0 && q2.m_value > 0, - "ripple::Quality::relativeDistance : minimum inputs"); + XRPL_ASSERT(q1.m_value > 0 && q2.m_value > 0, "xrpl::Quality::relativeDistance : minimum inputs"); if (q1.m_value == q2.m_value) // make expected common case fast return 0; auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value); - auto mantissa = [](std::uint64_t rate) { - return rate & ~(255ull << (64 - 8)); - }; - auto exponent = [](std::uint64_t rate) { - return static_cast(rate >> (64 - 8)) - 100; - }; + auto mantissa = [](std::uint64_t rate) { return rate & ~(255ull << (64 - 8)); }; + auto exponent = [](std::uint64_t rate) { return static_cast(rate >> (64 - 8)) - 100; }; auto const minVMantissa = mantissa(minV); auto const maxVMantissa = mantissa(maxV); auto const expDiff = exponent(maxV) - exponent(minV); double const minVD = static_cast(minVMantissa); - double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff) - : static_cast(maxVMantissa); + double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff) : static_cast(maxVMantissa); // maxVD and minVD are scaled so they have the same exponents. Dividing // cancels out the exponents, so we only need to deal with the (scaled) @@ -329,12 +287,7 @@ public: } }; -template < - class In, - class Out, - class Lim, - typename FnPtr, - std::same_as... Round> +template ... Round> TAmounts Quality::ceil_TAmounts_helper( TAmounts const& amount, @@ -359,25 +312,20 @@ TAmounts Quality::ceil_in(TAmounts const& amount, In const& limit) const { // Construct a function pointer to the function we want to call. - static constexpr Amounts (Quality::*ceil_in_fn_ptr)( - Amounts const&, STAmount const&) const = &Quality::ceil_in; + static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&) const = &Quality::ceil_in; return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr); } template TAmounts -Quality::ceil_in_strict( - TAmounts const& amount, - In const& limit, - bool roundUp) const +Quality::ceil_in_strict(TAmounts const& amount, In const& limit, bool roundUp) const { // Construct a function pointer to the function we want to call. - static constexpr Amounts (Quality::*ceil_in_fn_ptr)( - Amounts const&, STAmount const&, bool) const = &Quality::ceil_in_strict; + static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&, bool) const = + &Quality::ceil_in_strict; - return ceil_TAmounts_helper( - amount, limit, amount.in, ceil_in_fn_ptr, roundUp); + return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr, roundUp); } template @@ -385,26 +333,20 @@ TAmounts Quality::ceil_out(TAmounts const& amount, Out const& limit) const { // Construct a function pointer to the function we want to call. - static constexpr Amounts (Quality::*ceil_out_fn_ptr)( - Amounts const&, STAmount const&) const = &Quality::ceil_out; + static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&) const = &Quality::ceil_out; return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr); } template TAmounts -Quality::ceil_out_strict( - TAmounts const& amount, - Out const& limit, - bool roundUp) const +Quality::ceil_out_strict(TAmounts const& amount, Out const& limit, bool roundUp) const { // Construct a function pointer to the function we want to call. - static constexpr Amounts (Quality::*ceil_out_fn_ptr)( - Amounts const&, STAmount const&, bool) const = + static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&, bool) const = &Quality::ceil_out_strict; - return ceil_TAmounts_helper( - amount, limit, amount.out, ceil_out_fn_ptr, roundUp); + return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr, roundUp); } /** Calculate the quality of a two-hop path given the two hops. @@ -414,6 +356,4 @@ Quality::ceil_out_strict( Quality composed_quality(Quality const& lhs, Quality const& rhs); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/QualityFunction.h b/include/xrpl/protocol/QualityFunction.h index f718488148..4f76f4df0a 100644 --- a/include/xrpl/protocol/QualityFunction.h +++ b/include/xrpl/protocol/QualityFunction.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED -#define RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Average quality of a path as a function of `out`: q(out) = m * out + b, * where m = -1 / poolGets, b = poolPays / poolGets. If CLOB offer then @@ -57,10 +37,7 @@ public: }; QualityFunction(Quality const& quality, CLOBLikeTag); template - QualityFunction( - TAmounts const& amounts, - std::uint32_t tfee, - AMMTag); + QualityFunction(TAmounts const& amounts, std::uint32_t tfee, AMMTag); /** Combines QF with the next step QF */ @@ -90,10 +67,7 @@ public: }; template -QualityFunction::QualityFunction( - TAmounts const& amounts, - std::uint32_t tfee, - QualityFunction::AMMTag) +QualityFunction::QualityFunction(TAmounts const& amounts, std::uint32_t tfee, QualityFunction::AMMTag) { if (amounts.in <= beast::zero || amounts.out <= beast::zero) Throw("QualityFunction amounts are 0."); @@ -102,6 +76,4 @@ QualityFunction::QualityFunction( b_ = amounts.out * cfee / amounts.in; } -} // namespace ripple - -#endif // RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/RPCErr.h b/include/xrpl/protocol/RPCErr.h index cb106b2f0d..34c4bf8f99 100644 --- a/include/xrpl/protocol/RPCErr.h +++ b/include/xrpl/protocol/RPCErr.h @@ -1,35 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NET_RPCERR_H_INCLUDED -#define RIPPLE_NET_RPCERR_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { // VFALCO NOTE these are deprecated bool isRpcError(Json::Value jvResult); Json::Value -rpcError(int iError); +rpcError(error_code_i iError); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index 548a7af6f9..e57d7e3a99 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED -#define RIPPLE_PROTOCOL_RATE_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Represents a transfer rate @@ -73,11 +53,7 @@ STAmount multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp); STAmount -multiplyRound( - STAmount const& amount, - Rate const& rate, - Asset const& asset, - bool roundUp); +multiplyRound(STAmount const& amount, Rate const& rate, Asset const& asset, bool roundUp); STAmount divide(STAmount const& amount, Rate const& rate); @@ -86,11 +62,7 @@ STAmount divideRound(STAmount const& amount, Rate const& rate, bool roundUp); STAmount -divideRound( - STAmount const& amount, - Rate const& rate, - Asset const& asset, - bool roundUp); +divideRound(STAmount const& amount, Rate const& rate, Asset const& asset, bool roundUp); namespace nft { /** Given a transfer fee (in basis points) convert it to a transfer rate. */ @@ -102,6 +74,4 @@ transferFeeAsRate(std::uint16_t fee); /** A transfer rate signifying a 1:1 exchange */ extern Rate const parityRate; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/RippleLedgerHash.h b/include/xrpl/protocol/RippleLedgerHash.h index 19ba803b82..2a51298d3d 100644 --- a/include/xrpl/protocol/RippleLedgerHash.h +++ b/include/xrpl/protocol/RippleLedgerHash.h @@ -1,31 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED -#define RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { using LedgerHash = uint256; } - -#endif diff --git a/include/xrpl/protocol/Rules.h b/include/xrpl/protocol/Rules.h index efdaf803fd..7d4a458fce 100644 --- a/include/xrpl/protocol/Rules.h +++ b/include/xrpl/protocol/Rules.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_RULES_H_INCLUDED -#define RIPPLE_LEDGER_RULES_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { bool isFeatureEnabled(uint256 const& feature); @@ -66,14 +46,10 @@ public: private: // Allow a friend function to construct Rules. friend Rules - makeRulesGivenLedger( - DigestAwareReadView const& ledger, - Rules const& current); + makeRulesGivenLedger(DigestAwareReadView const& ledger, Rules const& current); friend Rules - makeRulesGivenLedger( - DigestAwareReadView const& ledger, - std::unordered_set> const& presets); + makeRulesGivenLedger(DigestAwareReadView const& ledger, std::unordered_set> const& presets); Rules( std::unordered_set> const& presets, @@ -110,8 +86,7 @@ setCurrentTransactionRules(std::optional r); class CurrentTransactionRulesGuard { public: - explicit CurrentTransactionRulesGuard(Rules r) - : saved_(getCurrentTransactionRules()) + explicit CurrentTransactionRulesGuard(Rules r) : saved_(getCurrentTransactionRules()) { setCurrentTransactionRules(std::move(r)); } @@ -130,5 +105,4 @@ private: std::optional saved_; }; -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index b6ae98b48f..7a864b1b58 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SFIELD_H_INCLUDED -#define RIPPLE_PROTOCOL_SFIELD_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /* @@ -139,24 +119,26 @@ field_code(int id, int index) SFields are created at compile time. Each SField, once constructed, lives until program termination, and there - is only one instance per fieldType/fieldValue pair which serves the entire - application. + is only one instance per fieldType/fieldValue pair which serves the + entire application. */ class SField { public: enum { sMD_Never = 0x00, - sMD_ChangeOrig = 0x01, // original value when it changes - sMD_ChangeNew = 0x02, // new value when it changes - sMD_DeleteFinal = 0x04, // final value when it is deleted - sMD_Create = 0x08, // value when it's created - sMD_Always = 0x10, // value when node containing it is affected at all - sMD_BaseTen = 0x20, // value is treated as base 10, overriding behavior + sMD_ChangeOrig = 0x01, // original value when it changes + sMD_ChangeNew = 0x02, // new value when it changes + sMD_DeleteFinal = 0x04, // final value when it is deleted + sMD_Create = 0x08, // value when it's created + sMD_Always = 0x10, // value when node containing it is affected at all + sMD_BaseTen = 0x20, // value is treated as base 10, overriding behavior sMD_PseudoAccount = 0x40, // if this field is set in an ACCOUNT_ROOT - // _only_, then it is a pseudo-account - sMD_Default = - sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create + // _only_, then it is a pseudo-account + sMD_NeedsAsset = 0x80, // This field needs to be associated with an + // asset before it is serialized as a ledger + // object. Intended for STNumber. + sMD_Default = sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create }; enum class IsSigning : unsigned char { no, yes }; @@ -283,8 +265,7 @@ public: bool shouldInclude(bool withSigningField) const { - return (fieldValue < 256) && - (withSigningField || (signingField == IsSigning::yes)); + return (fieldValue < 256) && (withSigningField || (signingField == IsSigning::yes)); } bool @@ -378,10 +359,8 @@ using SF_XCHAIN_BRIDGE = TypedField; #pragma push_macro("TYPED_SFIELD") #undef TYPED_SFIELD -#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ - extern SField const sfName; -#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ - extern SF_##stiSuffix const sfName; +#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SField const sfName; +#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) extern SF_##stiSuffix const sfName; extern SField const sfInvalid; extern SField const sfGeneric; @@ -393,6 +372,4 @@ extern SField const sfGeneric; #undef UNTYPED_SFIELD #pragma pop_macro("UNTYPED_SFIELD") -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 14497b4222..794fc86c11 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED -#define RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Kind of element in each entry of an SOTemplate. */ enum SOEStyle { @@ -61,24 +41,19 @@ private: auto nm = std::to_string(fieldName.getCode()); if (fieldName.hasName()) nm += ": '" + fieldName.getName() + "'"; - Throw( - "SField (" + nm + ") in SOElement must be useful."); + Throw("SField (" + nm + ") in SOElement must be useful."); } } public: - SOElement(SField const& fieldName, SOEStyle style) - : sField_(fieldName), style_(style) + SOElement(SField const& fieldName, SOEStyle style) : sField_(fieldName), style_(style) { init(fieldName); } template requires(std::is_same_v || std::is_same_v) - SOElement( - TypedField const& fieldName, - SOEStyle style, - SOETxMPTIssue supportMpt = soeMPTNotSupported) + SOElement(TypedField const& fieldName, SOEStyle style, SOETxMPTIssue supportMpt = soeMPTNotSupported) : sField_(fieldName), style_(style), supportMpt_(supportMpt) { init(fieldName); @@ -122,9 +97,7 @@ public: After creating the template fields cannot be added, modified, or removed. */ - SOTemplate( - std::initializer_list uniqueFields, - std::initializer_list commonFields = {}); + SOTemplate(std::initializer_list uniqueFields, std::initializer_list commonFields = {}); /* Provide for the enumeration of fields */ std::vector::const_iterator @@ -173,6 +146,4 @@ private: std::vector indices_; // field num -> index }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STAccount.h b/include/xrpl/protocol/STAccount.h index 422a01defa..3fdb2e015e 100644 --- a/include/xrpl/protocol/STAccount.h +++ b/include/xrpl/protocol/STAccount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED -#define RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED +#pragma once #include #include @@ -26,14 +6,14 @@ #include -namespace ripple { +namespace xrpl { class STAccount final : public STBase, public CountedObject { private: // The original implementation of STAccount kept the value in an STBlob. // But an STAccount is always 160 bits, so we can store it with less - // overhead in a ripple::uint160. However, so the serialized format of the + // overhead in a xrpl::uint160. However, so the serialized format of the // STAccount stays unchanged, we serialize and deserialize like an STBlob. AccountID value_; bool default_; @@ -131,6 +111,4 @@ operator<(AccountID const& lhs, STAccount const& rhs) return lhs < rhs.value(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index ee68e33000..df2b1c19a0 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED -#define RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { // Internal form: // 1: If amount is zero, then value is zero and offset is -100 @@ -66,16 +46,18 @@ public: static int const cMaxOffset = 80; // Maximum native value supported by the code - static std::uint64_t const cMinValue = 1000000000000000ull; - static std::uint64_t const cMaxValue = 9999999999999999ull; - static std::uint64_t const cMaxNative = 9000000000000000000ull; + constexpr static std::uint64_t cMinValue = 1'000'000'000'000'000ull; + static_assert(isPowerOfTen(cMinValue)); + constexpr static std::uint64_t cMaxValue = cMinValue * 10 - 1; + static_assert(cMaxValue == 9'999'999'999'999'999ull); + constexpr static std::uint64_t cMaxNative = 9'000'000'000'000'000'000ull; // Max native value on network. - static std::uint64_t const cMaxNativeN = 100000000000000000ull; - static std::uint64_t const cIssuedCurrency = 0x8000000000000000ull; - static std::uint64_t const cPositive = 0x4000000000000000ull; - static std::uint64_t const cMPToken = 0x2000000000000000ull; - static std::uint64_t const cValueMask = ~(cPositive | cMPToken); + constexpr static std::uint64_t cMaxNativeN = 100'000'000'000'000'000ull; + constexpr static std::uint64_t cIssuedCurrency = 0x8'000'000'000'000'000ull; + constexpr static std::uint64_t cPositive = 0x4'000'000'000'000'000ull; + constexpr static std::uint64_t cMPToken = 0x2'000'000'000'000'000ull; + constexpr static std::uint64_t cValueMask = ~(cPositive | cMPToken); static std::uint64_t const uRateOne; @@ -98,12 +80,7 @@ public: unchecked); template - STAmount( - A const& asset, - mantissa_type mantissa, - exponent_type exponent, - bool negative, - unchecked); + STAmount(A const& asset, mantissa_type mantissa, exponent_type exponent, bool negative, unchecked); // Call canonicalize template @@ -116,36 +93,22 @@ public: STAmount(SField const& name, std::int64_t mantissa); - STAmount( - SField const& name, - std::uint64_t mantissa = 0, - bool negative = false); + STAmount(SField const& name, std::uint64_t mantissa = 0, bool negative = false); explicit STAmount(std::uint64_t mantissa = 0, bool negative = false); explicit STAmount(SField const& name, STAmount const& amt); template - STAmount( - A const& asset, - std::uint64_t mantissa = 0, - int exponent = 0, - bool negative = false) - : mAsset(asset) - , mValue(mantissa) - , mOffset(exponent) - , mIsNegative(negative) + STAmount(A const& asset, std::uint64_t mantissa = 0, int exponent = 0, bool negative = false) + : mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) { canonicalize(); } // VFALCO Is this needed when we have the previous signature? template - STAmount( - A const& asset, - std::uint32_t mantissa, - int exponent = 0, - bool negative = false); + STAmount(A const& asset, std::uint32_t mantissa, int exponent = 0, bool negative = false); template STAmount(A const& asset, std::int64_t mantissa, int exponent = 0); @@ -154,8 +117,7 @@ public: STAmount(A const& asset, int mantissa, int exponent = 0); template - STAmount(A const& asset, Number const& number) - : STAmount(asset, number.mantissa(), number.exponent()) + STAmount(A const& asset, Number const& number) : STAmount(fromNumber(asset, number)) { } @@ -174,6 +136,9 @@ public: int exponent() const noexcept; + bool + integral() const noexcept; + bool native() const noexcept; @@ -296,6 +261,10 @@ public: mpt() const; private: + template + static STAmount + fromNumber(A const& asset, Number const& number); + static std::unique_ptr construct(SerialIter&, SField const& name); @@ -326,60 +295,45 @@ STAmount::STAmount( exponent_type exponent, bool negative, unchecked) - : STBase(name) - , mAsset(asset) - , mValue(mantissa) - , mOffset(exponent) - , mIsNegative(negative) + : STBase(name), mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) { } template -STAmount::STAmount( - A const& asset, - mantissa_type mantissa, - exponent_type exponent, - bool negative, - unchecked) +STAmount::STAmount(A const& asset, mantissa_type mantissa, exponent_type exponent, bool negative, unchecked) : mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) { } template -STAmount::STAmount( - SField const& name, - A const& asset, - std::uint64_t mantissa, - int exponent, - bool negative) - : STBase(name) - , mAsset(asset) - , mValue(mantissa) - , mOffset(exponent) - , mIsNegative(negative) +STAmount::STAmount(SField const& name, A const& asset, std::uint64_t mantissa, int exponent, bool negative) + : STBase(name), mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) { // mValue is uint64, but needs to fit in the range of int64 - XRPL_ASSERT( - mValue <= std::numeric_limits::max(), - "ripple::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : " - "maximum mantissa input"); + if (Number::getMantissaScale() == MantissaRange::small) + { + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "xrpl::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : " + "maximum mantissa input"); + } + else + { + if (integral() && mValue > std::numeric_limits::max()) + throw std::overflow_error("STAmount mantissa is too large " + std::to_string(mantissa)); + } canonicalize(); } template -STAmount::STAmount(A const& asset, std::int64_t mantissa, int exponent) - : mAsset(asset), mOffset(exponent) +STAmount::STAmount(A const& asset, std::int64_t mantissa, int exponent) : mAsset(asset), mOffset(exponent) { set(mantissa); canonicalize(); } template -STAmount::STAmount( - A const& asset, - std::uint32_t mantissa, - int exponent, - bool negative) +STAmount::STAmount(A const& asset, std::uint32_t mantissa, int exponent, bool negative) : STAmount(asset, safe_cast(mantissa), exponent, negative) { } @@ -392,9 +346,7 @@ STAmount::STAmount(A const& asset, int mantissa, int exponent) // Legacy support for new-style amounts inline STAmount::STAmount(IOUAmount const& amount, Issue const& issue) - : mAsset(issue) - , mOffset(amount.exponent()) - , mIsNegative(amount < beast::zero) + : mAsset(issue), mOffset(amount.exponent()), mIsNegative(amount < beast::zero) { if (mIsNegative) mValue = unsafe_cast(-amount.mantissa()); @@ -454,6 +406,12 @@ STAmount::exponent() const noexcept return mOffset; } +inline bool +STAmount::integral() const noexcept +{ + return mAsset.integral(); +} + inline bool STAmount::native() const noexcept { @@ -550,14 +508,22 @@ STAmount::operator=(XRPAmount const& amount) return *this; } -inline STAmount& -STAmount::operator=(Number const& number) +template +inline STAmount +STAmount::fromNumber(A const& a, Number const& number) { - mIsNegative = number.mantissa() < 0; - mValue = mIsNegative ? -number.mantissa() : number.mantissa(); - mOffset = number.exponent(); - canonicalize(); - return *this; + bool const negative = number.mantissa() < 0; + Number const working{negative ? -number : number}; + Asset asset{a}; + if (asset.integral()) + { + std::uint64_t const intValue = static_cast(working); + return STAmount{asset, intValue, 0, negative}; + } + + auto const [mantissa, exponent] = working.normalizeToRange(cMinValue, cMaxValue); + + return STAmount{asset, mantissa, exponent, negative}; } inline void @@ -572,7 +538,7 @@ STAmount::clear() { // The -100 is used to allow 0 to sort less than a small positive values // which have a negative exponent. - mOffset = native() ? 0 : -100; + mOffset = integral() ? 0 : -100; mValue = 0; mIsNegative = false; } @@ -659,35 +625,19 @@ multiply(STAmount const& v1, STAmount const& v2, Asset const& asset); // multiply rounding result in specified direction STAmount -mulRound( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp); +mulRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp); // multiply following the rounding directions more precisely. STAmount -mulRoundStrict( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp); +mulRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp); // divide rounding result in specified direction STAmount -divRound( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp); +divRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp); // divide following the rounding directions more precisely. STAmount -divRoundStrict( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp); +divRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp); // Someone is offering X for Y, what is the rate? // Rate: smaller is better, the taker wants the most out: in/out @@ -695,6 +645,65 @@ divRoundStrict( std::uint64_t getRate(STAmount const& offerOut, STAmount const& offerIn); +/** Round an arbitrary precision Amount to the precision of an STAmount that has + * a given exponent. + * + * This is used to ensure that calculations involving IOU amounts do not collect + * dust beyond the precision of the reference value. + * + * @param value The value to be rounded + * @param scale An exponent value to establish the precision limit of + * `value`. Should be larger than `value.exponent()`. + * @param rounding Optional Number rounding mode + * + */ +[[nodiscard]] STAmount +roundToScale(STAmount const& value, std::int32_t scale, Number::rounding_mode rounding = Number::getround()); + +/** Round an arbitrary precision Number IN PLACE to the precision of a given + * Asset. + * + * This is used to ensure that calculations do not collect dust for IOUs, or + * fractional amounts for the integral types XRP and MPT. + * + * @param asset The relevant asset + * @param value The lvalue to be rounded + */ +template +void +roundToAsset(A const& asset, Number& value) +{ + value = STAmount{asset, value}; +} + +/** Round an arbitrary precision Number to the precision of a given Asset. + * + * This is used to ensure that calculations do not collect dust beyond specified + * scale for IOUs, or fractional amounts for the integral types XRP and MPT. + * + * @param asset The relevant asset + * @param value The value to be rounded + * @param scale Only relevant to IOU assets. An exponent value to establish the + * precision limit of `value`. Should be larger than `value.exponent()`. + * @param rounding Optional Number rounding mode + */ +template +[[nodiscard]] Number +roundToAsset( + A const& asset, + Number const& value, + std::int32_t scale, + Number::rounding_mode rounding = Number::getround()) +{ + NumberRoundModeGuard mg(rounding); + STAmount const ret{asset, value}; + if (ret.integral()) + return ret; + // Note that the ctor will round integral types (XRP, MPT) via canonicalize, + // so no extra work is needed for those. + return roundToScale(ret, scale); +} + //------------------------------------------------------------------------------ inline bool @@ -709,15 +718,15 @@ canAdd(STAmount const& amt1, STAmount const& amt2); bool canSubtract(STAmount const& amt1, STAmount const& amt2); -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ namespace Json { template <> -inline ripple::STAmount -getOrThrow(Json::Value const& v, ripple::SField const& field) +inline xrpl::STAmount +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; Json::StaticString const& key = field.getJsonName(); if (!v.isMember(key)) Throw(key); @@ -725,4 +734,3 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) return amountFromJson(field, inner); } } // namespace Json -#endif diff --git a/include/xrpl/protocol/STArray.h b/include/xrpl/protocol/STArray.h index 8f1e2dd0ee..d9c5306d14 100644 --- a/include/xrpl/protocol/STArray.h +++ b/include/xrpl/protocol/STArray.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STARRAY_H_INCLUDED -#define RIPPLE_PROTOCOL_STARRAY_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class STArray final : public STBase, public CountedObject { @@ -43,16 +23,12 @@ public: template < class Iter, - class = std::enable_if_t::reference, - STObject>>> + class = std::enable_if_t::reference, STObject>>> explicit STArray(Iter first, Iter last); template < class Iter, - class = std::enable_if_t::reference, - STObject>>> + class = std::enable_if_t::reference, STObject>>> STArray(SField const& f, Iter first, Iter last); STArray& @@ -172,8 +148,7 @@ STArray::STArray(Iter first, Iter last) : v_(first, last) } template -STArray::STArray(SField const& f, Iter first, Iter last) - : STBase(f), v_(first, last) +STArray::STArray(SField const& f, Iter first, Iter last) : STBase(f), v_(first, last) { } @@ -310,6 +285,4 @@ STArray::erase(const_iterator first, const_iterator last) return v_.erase(first, last); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h index 3f5a3b57ab..7f06b01ca4 100644 --- a/include/xrpl/protocol/STBase.h +++ b/include/xrpl/protocol/STBase.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STBASE_H_INCLUDED -#define RIPPLE_PROTOCOL_STBASE_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { /// Note, should be treated as flags that can be | and & struct JsonOptions @@ -238,6 +218,4 @@ STBase::emplace(std::size_t n, void* buf, T&& val) return new (buf) U(std::forward(val)); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index 7d41637c89..e8b6e7282b 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED -#define RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // The template parameter could be an unsigned type, however there's a bug in // gdb (last checked in gdb 12.1) that prevents gdb from finding the RTTI @@ -98,14 +78,12 @@ inline STBitString::STBitString(value_type const& v) : value_(v) } template -inline STBitString::STBitString(SField const& n, value_type const& v) - : STBase(n), value_(v) +inline STBitString::STBitString(SField const& n, value_type const& v) : STBase(n), value_(v) { } template -inline STBitString::STBitString(SerialIter& sit, SField const& name) - : STBitString(name, sit.getBitString()) +inline STBitString::STBitString(SerialIter& sit, SField const& name) : STBitString(name, sit.getBitString()) { } @@ -170,11 +148,8 @@ template void STBitString::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STBitString::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == getSType(), - "ripple::STBitString::add : field type match"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STBitString::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STBitString::add : field type match"); s.addBitString(value_); } @@ -206,6 +181,4 @@ STBitString::isDefault() const return value_ == beast::zero; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index 374abd2a7c..15a9bd5f78 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STBLOB_H_INCLUDED -#define RIPPLE_PROTOCOL_STBLOB_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { // variable length byte string class STBlob : public STBase, public CountedObject @@ -88,18 +68,15 @@ private: friend class detail::STVar; }; -inline STBlob::STBlob(STBlob const& rhs) - : STBase(rhs), CountedObject(rhs), value_(rhs.data(), rhs.size()) +inline STBlob::STBlob(STBlob const& rhs) : STBase(rhs), CountedObject(rhs), value_(rhs.data(), rhs.size()) { } -inline STBlob::STBlob(SField const& f, void const* data, std::size_t size) - : STBase(f), value_(data, size) +inline STBlob::STBlob(SField const& f, void const* data, std::size_t size) : STBase(f), value_(data, size) { } -inline STBlob::STBlob(SField const& f, Buffer&& b) - : STBase(f), value_(std::move(b)) +inline STBlob::STBlob(SField const& f, Buffer&& b) : STBase(f), value_(std::move(b)) { } @@ -145,6 +122,4 @@ STBlob::setValue(Buffer&& b) value_ = std::move(b); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STCurrency.h b/include/xrpl/protocol/STCurrency.h index 90a6589048..dc5b079c6d 100644 --- a/include/xrpl/protocol/STCurrency.h +++ b/include/xrpl/protocol/STCurrency.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED -#define RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { class STCurrency final : public STBase { @@ -133,6 +113,4 @@ operator<(STCurrency const& lhs, Currency const& rhs) return lhs.currency() < rhs; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STExchange.h b/include/xrpl/protocol/STExchange.h index dd7c4834a6..4b576991b7 100644 --- a/include/xrpl/protocol/STExchange.h +++ b/include/xrpl/protocol/STExchange.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED -#define RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED +#pragma once #include #include @@ -35,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Convert between serialized type U and C++ type T. */ template @@ -143,8 +123,7 @@ template void set(STObject& st, TypedField const& f, T&& t) { - st.set(STExchange::type>::set( - f, std::forward(t))); + st.set(STExchange::type>::set(f, std::forward(t))); } /** Set a blob field using an init function. */ @@ -158,10 +137,7 @@ set(STObject& st, TypedField const& f, std::size_t size, Init&& init) /** Set a blob field from data. */ template void -set(STObject& st, - TypedField const& f, - void const* data, - std::size_t size) +set(STObject& st, TypedField const& f, void const* data, std::size_t size) { st.set(std::make_unique(f, data, size)); } @@ -174,6 +150,4 @@ erase(STObject& st, TypedField const& f) st.makeFieldAbsent(f); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h index 154ee7f203..b5c4dbf6cf 100644 --- a/include/xrpl/protocol/STInteger.h +++ b/include/xrpl/protocol/STInteger.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED -#define RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { template class STInteger : public STBase, public CountedObject> @@ -73,7 +53,7 @@ private: STBase* move(std::size_t n, void* buf) override; - friend class ripple::detail::STVar; + friend class xrpl::detail::STVar; }; using STUInt8 = STInteger; @@ -89,8 +69,7 @@ inline STInteger::STInteger(Integer v) : value_(v) } template -inline STInteger::STInteger(SField const& n, Integer v) - : STBase(n), value_(v) +inline STInteger::STInteger(SField const& n, Integer v) : STBase(n), value_(v) { } @@ -112,11 +91,8 @@ template inline void STInteger::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STInteger::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == getSType(), - "ripple::STInteger::add : field type match"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STInteger::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STInteger::add : field type match"); s.addInteger(value_); } @@ -163,6 +139,4 @@ inline STInteger::operator Integer() const return value_; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h index 9fe61f32cd..7491e3b3ff 100644 --- a/include/xrpl/protocol/STIssue.h +++ b/include/xrpl/protocol/STIssue.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STISSUE_H_INCLUDED -#define RIPPLE_PROTOCOL_STISSUE_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { class STIssue final : public STBase, CountedObject { @@ -102,12 +82,10 @@ private: }; template -STIssue::STIssue(SField const& name, A const& asset) - : STBase{name}, asset_{asset} +STIssue::STIssue(SField const& name, A const& asset) : STBase{name}, asset_{asset} { if (holds() && !isConsistent(asset_.get())) - Throw( - "Invalid asset: currency and account native mismatch"); + Throw("Invalid asset: currency and account native mismatch"); } STIssue @@ -139,8 +117,7 @@ inline void STIssue::setIssue(Asset const& asset) { if (holds() && !isConsistent(asset_.get())) - Throw( - "Invalid asset: currency and account native mismatch"); + Throw("Invalid asset: currency and account native mismatch"); asset_ = asset; } @@ -169,6 +146,4 @@ operator<=>(STIssue const& lhs, Asset const& rhs) return lhs.asset_ <=> rhs; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STLedgerEntry.h b/include/xrpl/protocol/STLedgerEntry.h index 571c7af5fe..6ba3b36c6b 100644 --- a/include/xrpl/protocol/STLedgerEntry.h +++ b/include/xrpl/protocol/STLedgerEntry.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED -#define RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class Rules; namespace test { @@ -75,11 +55,7 @@ public: isThreadedType(Rules const& rules) const; bool - thread( - uint256 const& txID, - std::uint32_t ledgerSeq, - uint256& prevTxID, - std::uint32_t& prevLedgerID); + thread(uint256 const& txID, std::uint32_t ledgerSeq, uint256& prevTxID, std::uint32_t& prevLedgerID); private: /* Make STObject comply with the template for this SLE type @@ -101,13 +77,11 @@ private: using SLE = STLedgerEntry; -inline STLedgerEntry::STLedgerEntry(LedgerEntryType type, uint256 const& key) - : STLedgerEntry(Keylet(type, key)) +inline STLedgerEntry::STLedgerEntry(LedgerEntryType type, uint256 const& key) : STLedgerEntry(Keylet(type, key)) { } -inline STLedgerEntry::STLedgerEntry(SerialIter&& sit, uint256 const& index) - : STLedgerEntry(sit, index) +inline STLedgerEntry::STLedgerEntry(SerialIter&& sit, uint256 const& index) : STLedgerEntry(sit, index) { } @@ -127,6 +101,4 @@ STLedgerEntry::getType() const return type_; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STNumber.h b/include/xrpl/protocol/STNumber.h index 3c1f73e4e6..137016dfe7 100644 --- a/include/xrpl/protocol/STNumber.h +++ b/include/xrpl/protocol/STNumber.h @@ -1,32 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef XRPL_PROTOCOL_STNUMBER_H_INCLUDED -#define XRPL_PROTOCOL_STNUMBER_H_INCLUDED +#pragma once #include #include #include +#include #include -namespace ripple { +namespace xrpl { /** * A serializable number. @@ -38,8 +19,19 @@ namespace ripple { * it can represent a value of any token type (XRP, IOU, or MPT) * without paying the storage cost of duplicating asset information * that may be deduced from the context. + * + * STNumber derives from STTakesAsset, so that it can be associated with the + * related Asset during transaction processing. Which asset is relevant depends + * on the object and transaction. As of this writing, only Vault, LoanBroker, + * and Loan objects use STNumber fields. All of those fields represent amounts + * of the Vault's Asset, so they should be associated with the Vault's Asset. + * + * e.g. + * associateAsset(*loanSle, asset); + * associateAsset(*brokerSle, asset); + * associateAsset(*vaultSle, asset); */ -class STNumber : public STBase, public CountedObject +class STNumber : public STTakesAsset, public CountedObject { private: Number value_; @@ -75,6 +67,9 @@ public: bool isDefault() const override; + void + associateAsset(Asset const& a) override; + operator Number() const { return value_; @@ -103,6 +98,4 @@ partsFromString(std::string const& number); STNumber numberFromJson(SField const& field, Json::Value const& value); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 84706c5833..5d5d829c99 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED -#define RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED +#pragma once #include #include @@ -43,7 +23,7 @@ #include #include -namespace ripple { +namespace xrpl { class STArray; @@ -80,15 +60,13 @@ class STObject : public STBase, public CountedObject SOTemplate const* mType; public: - using iterator = boost:: - transform_iterator; + using iterator = boost::transform_iterator; virtual ~STObject() = default; STObject(STObject const&) = default; template - STObject(SOTemplate const& type, SField const& name, F&& f) - : STObject(type, name) + STObject(SOTemplate const& type, SField const& name, F&& f) : STObject(type, name) { f(*this); } @@ -416,6 +394,9 @@ public: void delField(int index); + SOEStyle + getStyle(SField const& field) const; + bool hasMatchingEntry(STBase const&); @@ -450,8 +431,8 @@ private: // by value. template < typename T, - typename V = typename std::remove_cv().value())>::type>::type> + typename V = + typename std::remove_cv().value())>::type>::type> V getFieldByValue(SField const& field) const; @@ -501,6 +482,8 @@ public: value_type operator*() const; + /// Do not use operator->() unless the field is required, or you've checked + /// that it's set. T const* operator->() const; @@ -524,7 +507,19 @@ protected: // Constraint += and -= ValueProxy operators // to value types that support arithmetic operations template -concept IsArithmetic = std::is_arithmetic_v || std::is_same_v; +concept IsArithmeticNumber = std::is_arithmetic_v || std::is_same_v || std::is_same_v; +template +concept IsArithmeticValueUnit = + std::is_same_v> && IsArithmeticNumber && std::is_class_v; +template +concept IsArithmeticST = !IsArithmeticValueUnit && IsArithmeticNumber; +template +concept IsArithmetic = IsArithmeticNumber || IsArithmeticST || IsArithmeticValueUnit; + +template +concept Addable = requires(T t, U u) { t = t + u; }; +template +concept IsArithmeticCompatible = IsArithmetic && Addable; template class STObject::ValueProxy : public Proxy @@ -544,10 +539,12 @@ public: // Convenience operators for value types supporting // arithmetic operations template + requires IsArithmeticCompatible ValueProxy& operator+=(U const& u); template + requires IsArithmeticCompatible ValueProxy& operator-=(U const& u); @@ -701,8 +698,7 @@ STObject::Proxy::Proxy(STObject* st, TypedField const* f) : st_(st), f_(f) { // STObject has associated template if (!st_->peekAtPField(*f_)) - Throw( - "Template field error '" + this->f_->getName() + "'"); + Throw("Template field error '" + this->f_->getName() + "'"); style_ = st_->mType->style(*f_); } else @@ -724,8 +720,7 @@ STObject::Proxy::value() const -> value_type } if (style_ != soeDEFAULT) { - Throw( - "Missing field '" + this->f_->getName() + "'"); + Throw("Missing field '" + this->f_->getName() + "'"); } return value_type{}; } @@ -737,6 +732,8 @@ STObject::Proxy::operator*() const -> value_type return this->value(); } +/// Do not use operator->() unless the field is required, or you've checked that +/// it's set. template T const* STObject::Proxy::operator->() const @@ -766,7 +763,7 @@ STObject::Proxy::assign(U&& u) t = dynamic_cast(st_->getPField(*f_, true)); else t = dynamic_cast(st_->makeFieldPresent(*f_)); - XRPL_ASSERT(t, "ripple::STObject::Proxy::assign : type cast succeeded"); + XRPL_ASSERT(t, "xrpl::STObject::Proxy::assign : type cast succeeded"); *t = std::forward(u); } @@ -783,6 +780,7 @@ STObject::ValueProxy::operator=(U&& u) template template + requires IsArithmeticCompatible STObject::ValueProxy& STObject::ValueProxy::operator+=(U const& u) { @@ -792,6 +790,7 @@ STObject::ValueProxy::operator+=(U const& u) template template + requires IsArithmeticCompatible STObject::ValueProxy& STObject::ValueProxy::operator-=(U const& u) { @@ -806,8 +805,7 @@ STObject::ValueProxy::operator value_type() const } template -STObject::ValueProxy::ValueProxy(STObject* st, TypedField const* f) - : Proxy(st, f) +STObject::ValueProxy::ValueProxy(STObject* st, TypedField const* f) : Proxy(st, f) { } @@ -820,8 +818,7 @@ STObject::OptionalProxy::operator bool() const noexcept } template -STObject::OptionalProxy::operator typename STObject::OptionalProxy< - T>::optional_type() const +STObject::OptionalProxy::operator typename STObject::OptionalProxy::optional_type() const { return optional_value(); } @@ -873,8 +870,7 @@ STObject::OptionalProxy::operator=(U&& u) } template -STObject::OptionalProxy::OptionalProxy(STObject* st, TypedField const* f) - : Proxy(st, f) +STObject::OptionalProxy::OptionalProxy(STObject* st, TypedField const* f) : Proxy(st, f) { } @@ -890,8 +886,7 @@ void STObject::OptionalProxy::disengage() { if (this->style_ == soeREQUIRED || this->style_ == soeDEFAULT) - Throw( - "Template field error '" + this->f_->getName() + "'"); + Throw("Template field error '" + this->f_->getName() + "'"); if (this->style_ == soeINVALID) this->st_->delField(*this->f_); else @@ -924,8 +919,7 @@ STObject::Transform::operator()(detail::STVar const& e) const //------------------------------------------------------------------------------ -inline STObject::STObject(SerialIter&& sit, SField const& name) - : STObject(sit, name) +inline STObject::STObject(SerialIter&& sit, SField const& name) : STObject(sit, name) { } @@ -1055,19 +1049,13 @@ STObject::at(TypedField const& f) const if (auto const u = dynamic_cast(b)) return u->value(); - XRPL_ASSERT( - mType, - "ripple::STObject::at(TypedField auto) : field template non-null"); - XRPL_ASSERT( - b->getSType() == STI_NOTPRESENT, - "ripple::STObject::at(TypedField auto) : type not present"); + XRPL_ASSERT(mType, "xrpl::STObject::at(TypedField auto) : field template non-null"); + XRPL_ASSERT(b->getSType() == STI_NOTPRESENT, "xrpl::STObject::at(TypedField auto) : type not present"); if (mType->style(f) == soeOPTIONAL) Throw("Missing optional field: " + f.getName()); - XRPL_ASSERT( - mType->style(f) == soeDEFAULT, - "ripple::STObject::at(TypedField auto) : template style is default"); + XRPL_ASSERT(mType->style(f) == soeDEFAULT, "xrpl::STObject::at(TypedField auto) : template style is default"); // Used to help handle the case where value_type is a const reference, // otherwise we would return the address of a temporary. @@ -1087,16 +1075,14 @@ STObject::at(OptionaledField const& of) const { XRPL_ASSERT( mType, - "ripple::STObject::at(OptionaledField auto) : field template " + "xrpl::STObject::at(OptionaledField auto) : field template " "non-null"); - XRPL_ASSERT( - b->getSType() == STI_NOTPRESENT, - "ripple::STObject::at(OptionaledField auto) : type not present"); + XRPL_ASSERT(b->getSType() == STI_NOTPRESENT, "xrpl::STObject::at(OptionaledField auto) : type not present"); if (mType->style(*of.f) == soeOPTIONAL) return std::nullopt; XRPL_ASSERT( mType->style(*of.f) == soeDEFAULT, - "ripple::STObject::at(OptionaledField auto) : template style is " + "xrpl::STObject::at(OptionaledField auto) : template style is " "default"); return typename T::value_type{}; } @@ -1256,6 +1242,4 @@ STObject::peekField(SField const& field) return *cf; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STParsedJSON.h b/include/xrpl/protocol/STParsedJSON.h index 9c770fe94d..772785fd70 100644 --- a/include/xrpl/protocol/STParsedJSON.h +++ b/include/xrpl/protocol/STParsedJSON.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED -#define RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Holds the serialized result of parsing an input JSON object. This does validation and checking on the provided JSON. @@ -54,6 +34,4 @@ public: Json::Value error; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index c56dd43e7f..1bab654d3f 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED -#define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { class STPathElement final : public CountedObject { @@ -45,8 +25,7 @@ class STPathElement final : public CountedObject public: enum Type { typeNone = 0x00, - typeAccount = - 0x01, // Rippling through an account (vs taking an offer). + typeAccount = 0x01, // Rippling through an account (vs taking an offer). typeCurrency = 0x10, // Currency follows. typeIssuer = 0x20, // Issuer follows. typeBoundary = 0xFF, // Boundary between alternate paths. @@ -70,11 +49,7 @@ public: AccountID const& issuer, bool forceCurrency = false); - STPathElement( - unsigned int uType, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); + STPathElement(unsigned int uType, AccountID const& account, Currency const& currency, AccountID const& issuer); auto getNodeType() const; @@ -139,10 +114,7 @@ public: emplace_back(Args&&... args); bool - hasSeen( - AccountID const& account, - Currency const& currency, - AccountID const& issuer) const; + hasSeen(AccountID const& account, Currency const& currency, AccountID const& issuer) const; Json::Value getJson(JsonOptions) const; @@ -258,9 +230,7 @@ inline STPathElement::STPathElement( is_offer_ = false; mAccountID = *account; mType |= typeAccount; - XRPL_ASSERT( - mAccountID != noAccount(), - "ripple::STPathElement::STPathElement : account is set"); + XRPL_ASSERT(mAccountID != noAccount(), "xrpl::STPathElement::STPathElement : account is set"); } if (currency) @@ -273,9 +243,7 @@ inline STPathElement::STPathElement( { mIssuerID = *issuer; mType |= typeIssuer; - XRPL_ASSERT( - mIssuerID != noAccount(), - "ripple::STPathElement::STPathElement : issuer is set"); + XRPL_ASSERT(mIssuerID != noAccount(), "xrpl::STPathElement::STPathElement : issuer is set"); } hash_value_ = get_hash(*this); @@ -286,11 +254,7 @@ inline STPathElement::STPathElement( Currency const& currency, AccountID const& issuer, bool forceCurrency) - : mType(typeNone) - , mAccountID(account) - , mCurrencyID(currency) - , mIssuerID(issuer) - , is_offer_(isXRP(mAccountID)) + : mType(typeNone), mAccountID(account), mCurrencyID(currency), mIssuerID(issuer), is_offer_(isXRP(mAccountID)) { if (!is_offer_) mType |= typeAccount; @@ -309,11 +273,7 @@ inline STPathElement::STPathElement( AccountID const& account, Currency const& currency, AccountID const& issuer) - : mType(uType) - , mAccountID(account) - , mCurrencyID(currency) - , mIssuerID(issuer) - , is_offer_(isXRP(mAccountID)) + : mType(uType), mAccountID(account), mCurrencyID(currency), mIssuerID(issuer), is_offer_(isXRP(mAccountID)) { hash_value_ = get_hash(*this); } @@ -377,9 +337,8 @@ STPathElement::getIssuerID() const inline bool STPathElement::operator==(STPathElement const& t) const { - return (mType & typeAccount) == (t.mType & typeAccount) && - hash_value_ == t.hash_value_ && mAccountID == t.mAccountID && - mCurrencyID == t.mCurrencyID && mIssuerID == t.mIssuerID; + return (mType & typeAccount) == (t.mType & typeAccount) && hash_value_ == t.hash_value_ && + mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID && mIssuerID == t.mIssuerID; } inline bool @@ -523,6 +482,4 @@ STPathSet::emplace_back(Args&&... args) value.emplace_back(std::forward(args)...); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STTakesAsset.h b/include/xrpl/protocol/STTakesAsset.h new file mode 100644 index 0000000000..bf75ffccf7 --- /dev/null +++ b/include/xrpl/protocol/STTakesAsset.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +namespace xrpl { + +/** Intermediate class for any STBase-derived class to store an Asset. + * + * In the class definition, this class should be specified as a base class + * _instead_ of STBase. + * + * Specifically, the Asset is only stored and used at runtime. It should not be + * serialized to the ledger. + * + * The derived class decides what to do with the Asset, and when. It will not + * necessarily be set at any given time. As of this writing, only STNumber uses + * it to round the stored Number to the Asset's precision both when associated, + * and when serializing the Number. + */ +class STTakesAsset : public STBase +{ +protected: + std::optional asset_; + +public: + using STBase::STBase; + using STBase::operator=; + + virtual void + associateAsset(Asset const& a); +}; + +inline void +STTakesAsset::associateAsset(Asset const& a) +{ + asset_.emplace(a); +} + +class STLedgerEntry; + +/** Associate an Asset with all sMD_NeedsAsset fields in a ledger entry. + * + * This function iterates over all fields in the given ledger entry. For each + * field that is set and has the SField::sMD_NeedsAsset metadata flag, it calls + * `associateAsset` on that field with the given Asset. Such field must be + * derived from STTakesAsset - if it is not, the conversion will throw. + * + * Typically, associateAsset should be called near the end of doApply() of any + * Transactor classes on the SLEs of any new or modified ledger entries + * containing STNumber fields, after doing all of the modifications t the SLEs. + * + * @param sle The ledger entry whose fields will be updated. + * @param asset The Asset to associate with the relevant fields. + * + */ +void +associateAsset(STLedgerEntry& sle, Asset const& asset); + +} // namespace xrpl diff --git a/include/xrpl/protocol/STTx.h b/include/xrpl/protocol/STTx.h index ac0223ee77..a12c658dc2 100644 --- a/include/xrpl/protocol/STTx.h +++ b/include/xrpl/protocol/STTx.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STTX_H_INCLUDED -#define RIPPLE_PROTOCOL_STTX_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include -namespace ripple { +namespace xrpl { enum TxnSql : char { txnSqlNew = 'N', @@ -50,17 +30,8 @@ class STTx final : public STObject, public CountedObject TxType tx_type_; public: - static std::size_t const minMultiSigners = 1; - - // if rules are not supplied then the largest possible value is returned - static std::size_t - maxMultiSigners(Rules const* rules = 0) - { - if (rules && !rules->enabled(featureExpandedSignerList)) - return 8; - - return 32; - } + static constexpr std::size_t minMultiSigners = 1; + static constexpr std::size_t maxMultiSigners = 32; STTx() = delete; STTx(STTx const& other) = default; @@ -128,80 +99,52 @@ public: sign( PublicKey const& publicKey, SecretKey const& secretKey, - std::optional> signatureTarget = - {}); - - enum class RequireFullyCanonicalSig : bool { no, yes }; + std::optional> signatureTarget = {}); /** Check the signature. - @param requireCanonicalSig If `true`, check that the signature is fully - canonical. If `false`, only check that the signature is valid. @param rules The current ledger rules. @return `true` if valid signature. If invalid, the error message string. */ Expected - checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules) - const; + checkSign(Rules const& rules) const; Expected - checkBatchSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules) const; + checkBatchSign(Rules const& rules) const; // SQL Functions with metadata. static std::string const& getMetaSQLInsertReplaceHeader(); std::string - getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) - const; + getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const; std::string - getMetaSQL( - Serializer rawTxn, - std::uint32_t inLedger, - char status, - std::string const& escapedMetaData) const; + getMetaSQL(Serializer rawTxn, std::uint32_t inLedger, char status, std::string const& escapedMetaData) const; std::vector const& getBatchTransactionIDs() const; private: /** Check the signature. - @param requireCanonicalSig If `true`, check that the signature is fully - canonical. If `false`, only check that the signature is valid. @param rules The current ledger rules. @param sigObject Reference to object that contains the signature fields. Will be *this more often than not. @return `true` if valid signature. If invalid, the error message string. */ Expected - checkSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules, - STObject const& sigObject) const; + checkSign(Rules const& rules, STObject const& sigObject) const; Expected - checkSingleSign( - RequireFullyCanonicalSig requireCanonicalSig, - STObject const& sigObject) const; + checkSingleSign(STObject const& sigObject) const; Expected - checkMultiSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules, - STObject const& sigObject) const; + checkMultiSign(Rules const& rules, STObject const& sigObject) const; Expected - checkBatchSingleSign( - STObject const& batchSigner, - RequireFullyCanonicalSig requireCanonicalSig) const; + checkBatchSingleSign(STObject const& batchSigner) const; Expected - checkBatchMultiSign( - STObject const& batchSigner, - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules) const; + checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const; STBase* copy(std::size_t n, void* buf) const override; @@ -251,6 +194,4 @@ STTx::getTransactionID() const return tid_; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index 991922514d..aa48161f68 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED -#define RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { // Validation flags @@ -73,10 +53,7 @@ public: @note Throws if the object is not valid */ template - STValidation( - SerialIter& sit, - LookupNodeID&& lookupNodeID, - bool checkSignature); + STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool checkSignature); /** Construct, sign and trust a new STValidation issued by this node. @@ -87,12 +64,7 @@ public: @param f callback function to "fill" the validation with necessary data */ template - STValidation( - NetClock::time_point signTime, - PublicKey const& pk, - SecretKey const& sk, - NodeID const& nodeID, - F&& f); + STValidation(NetClock::time_point signTime, PublicKey const& pk, SecretKey const& sk, NodeID const& nodeID, F&& f); // Hash of the validated ledger uint256 @@ -145,14 +117,10 @@ public: render() const { std::stringstream ss; - ss << "validation: " << " ledger_hash: " << getLedgerHash() - << " consensus_hash: " << getConsensusHash() - << " sign_time: " << to_string(getSignTime()) - << " seen_time: " << to_string(getSeenTime()) - << " signer_public_key: " << getSignerPublic() - << " node_id: " << getNodeID() << " is_valid: " << isValid() - << " is_full: " << isFull() << " is_trusted: " << isTrusted() - << " signing_hash: " << getSigningHash() + ss << "validation: " << " ledger_hash: " << getLedgerHash() << " consensus_hash: " << getConsensusHash() + << " sign_time: " << to_string(getSignTime()) << " seen_time: " << to_string(getSeenTime()) + << " signer_public_key: " << getSignerPublic() << " node_id: " << getNodeID() << " is_valid: " << isValid() + << " is_full: " << isFull() << " is_trusted: " << isTrusted() << " signing_hash: " << getSigningHash() << " base58: " << toBase58(TokenType::NodePublic, getSignerPublic()); return ss.str(); } @@ -170,10 +138,7 @@ private: }; template -STValidation::STValidation( - SerialIter& sit, - LookupNodeID&& lookupNodeID, - bool checkSignature) +STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, bool checkSignature) : STObject(validationFormat(), sit, sfValidation) , signingPubKey_([this]() { auto const spk = getFieldVL(sfSigningPubKey); @@ -187,14 +152,11 @@ STValidation::STValidation( { if (checkSignature && !isValid()) { - JLOG(debugLog().error()) << "Invalid signature in validation: " - << getJson(JsonOptions::none); + JLOG(debugLog().error()) << "Invalid signature in validation: " << getJson(JsonOptions::none); Throw("Invalid signature in validation"); } - XRPL_ASSERT( - nodeID_.isNonZero(), - "ripple::STValidation::STValidation(SerialIter) : nonzero node"); + XRPL_ASSERT(nodeID_.isNonZero(), "xrpl::STValidation::STValidation(SerialIter) : nonzero node"); } /** Construct, sign and trust a new STValidation issued by this node. @@ -212,14 +174,11 @@ STValidation::STValidation( SecretKey const& sk, NodeID const& nodeID, F&& f) - : STObject(validationFormat(), sfValidation) - , signingPubKey_(pk) - , nodeID_(nodeID) - , seenTime_(signTime) + : STObject(validationFormat(), sfValidation), signingPubKey_(pk), nodeID_(nodeID), seenTime_(signTime) { XRPL_ASSERT( nodeID_.isNonZero(), - "ripple::STValidation::STValidation(PublicKey, SecretKey) : nonzero " + "xrpl::STValidation::STValidation(PublicKey, SecretKey) : nonzero " "node"); // First, set our own public key: @@ -241,9 +200,7 @@ STValidation::STValidation( for (auto const& e : validationFormat()) { if (e.style() == soeREQUIRED && !isFieldPresent(e.sField())) - LogicError( - "Required field '" + e.sField().getName() + - "' missing from validation."); + LogicError("Required field '" + e.sField().getName() + "' missing from validation."); } // We just signed this, so it should be valid. @@ -286,6 +243,4 @@ STValidation::setSeen(NetClock::time_point s) seenTime_ = s; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h index bc22ebdc7f..c83d981bfc 100644 --- a/include/xrpl/protocol/STVector256.h +++ b/include/xrpl/protocol/STVector256.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED -#define RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { class STVector256 : public STBase, public CountedObject { @@ -126,15 +106,11 @@ inline STVector256::STVector256(SField const& n) : STBase(n) { } -inline STVector256::STVector256(std::vector const& vector) - : mValue(vector) +inline STVector256::STVector256(std::vector const& vector) : mValue(vector) { } -inline STVector256::STVector256( - SField const& n, - std::vector const& vector) - : STBase(n), mValue(vector) +inline STVector256::STVector256(SField const& n, std::vector const& vector) : STBase(n), mValue(vector) { } @@ -201,9 +177,7 @@ STVector256::value() const } inline std::vector::iterator -STVector256::insert( - std::vector::const_iterator pos, - uint256 const& value) +STVector256::insert(std::vector::const_iterator pos, uint256 const& value) { return mValue.insert(pos, value); } @@ -256,6 +230,4 @@ STVector256::clear() noexcept return mValue.clear(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h index 4435857a51..709d3886b7 100644 --- a/include/xrpl/protocol/STXChainBridge.h +++ b/include/xrpl/protocol/STXChainBridge.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED -#define RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { class Serializer; class STObject; @@ -134,31 +114,15 @@ private: inline bool operator==(STXChainBridge const& lhs, STXChainBridge const& rhs) { - return std::tie( - lhs.lockingChainDoor_, - lhs.lockingChainIssue_, - lhs.issuingChainDoor_, - lhs.issuingChainIssue_) == - std::tie( - rhs.lockingChainDoor_, - rhs.lockingChainIssue_, - rhs.issuingChainDoor_, - rhs.issuingChainIssue_); + return std::tie(lhs.lockingChainDoor_, lhs.lockingChainIssue_, lhs.issuingChainDoor_, lhs.issuingChainIssue_) == + std::tie(rhs.lockingChainDoor_, rhs.lockingChainIssue_, rhs.issuingChainDoor_, rhs.issuingChainIssue_); } inline bool operator<(STXChainBridge const& lhs, STXChainBridge const& rhs) { - return std::tie( - lhs.lockingChainDoor_, - lhs.lockingChainIssue_, - lhs.issuingChainDoor_, - lhs.issuingChainIssue_) < - std::tie( - rhs.lockingChainDoor_, - rhs.lockingChainIssue_, - rhs.issuingChainDoor_, - rhs.issuingChainIssue_); + return std::tie(lhs.lockingChainDoor_, lhs.lockingChainIssue_, lhs.issuingChainDoor_, lhs.issuingChainIssue_) < + std::tie(rhs.lockingChainDoor_, rhs.lockingChainIssue_, rhs.issuingChainDoor_, rhs.issuingChainIssue_); } inline AccountID const& @@ -231,6 +195,4 @@ STXChainBridge::dstChain(bool wasLockingChainSend) return ChainType::locking; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/SecretKey.h b/include/xrpl/protocol/SecretKey.h index 1a13cd17c9..a59b1150c1 100644 --- a/include/xrpl/protocol/SecretKey.h +++ b/include/xrpl/protocol/SecretKey.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED -#define RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { /** A secret key. */ class SecretKey @@ -100,8 +80,7 @@ public: inline bool operator==(SecretKey const& lhs, SecretKey const& rhs) { - return lhs.size() == rhs.size() && - std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0; + return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0; } inline bool @@ -181,6 +160,4 @@ sign(KeyType type, SecretKey const& sk, Slice const& message) } /** @} */ -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Seed.h b/include/xrpl/protocol/Seed.h index 8a43d597a5..1fad94e2bd 100644 --- a/include/xrpl/protocol/Seed.h +++ b/include/xrpl/protocol/Seed.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SEED_H_INCLUDED -#define RIPPLE_PROTOCOL_SEED_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Seeds are used to generate deterministic secret keys. */ class Seed @@ -136,6 +116,4 @@ toBase58(Seed const& seed) return encodeBase58Token(TokenType::FamilySeed, seed.data(), seed.size()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/SeqProxy.h b/include/xrpl/protocol/SeqProxy.h index e7a89561c3..563292f8b3 100644 --- a/include/xrpl/protocol/SeqProxy.h +++ b/include/xrpl/protocol/SeqProxy.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED -#define RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** A type that represents either a sequence value or a ticket value. @@ -165,6 +145,4 @@ public: return os; } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index 5ea4d3ca96..98cefb4d08 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED -#define RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED +#pragma once #include #include @@ -35,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { class Serializer { @@ -55,9 +35,7 @@ public: if (size) { - XRPL_ASSERT( - data, - "ripple::Serializer::Serializer(void const*) : non-null input"); + XRPL_ASSERT(data, "xrpl::Serializer::Serializer(void const*) : non-null input"); std::memcpy(mData.data(), data, size); } } @@ -87,9 +65,7 @@ public: add16(std::uint16_t i); template - requires(std::is_same_v< - std::make_unsigned_t>, - std::uint32_t>) + requires(std::is_same_v>, std::uint32_t>) int add32(T i) { @@ -105,9 +81,7 @@ public: add32(HashPrefix p); template - requires(std::is_same_v< - std::make_unsigned_t>, - std::uint64_t>) + requires(std::is_same_v>, std::uint64_t>) int add64(T i) { @@ -333,8 +307,7 @@ Serializer::addVL(Iter begin, Iter end, int len) len -= begin->size(); #endif } - XRPL_ASSERT( - len == 0, "ripple::Serializer::addVL : length matches distance"); + XRPL_ASSERT(len == 0, "xrpl::Serializer::addVL : length matches distance"); return ret; } @@ -472,6 +445,4 @@ SerialIter::getBitString() return base_uint::fromVoid(x); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/Sign.h b/include/xrpl/protocol/Sign.h index 5aa9fabddc..9f0bf2f1ca 100644 --- a/include/xrpl/protocol/Sign.h +++ b/include/xrpl/protocol/Sign.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SIGN_H_INCLUDED -#define RIPPLE_PROTOCOL_SIGN_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { /** Sign an STObject @@ -39,12 +19,7 @@ namespace ripple { @note If a signature already exists, it is overwritten. */ void -sign( - STObject& st, - HashPrefix const& prefix, - KeyType type, - SecretKey const& sk, - SF_VL const& sigField = sfSignature); +sign(STObject& st, HashPrefix const& prefix, KeyType type, SecretKey const& sk, SF_VL const& sigField = sfSignature); /** Returns `true` if STObject contains valid signature @@ -55,11 +30,7 @@ sign( If not specified the value defaults to `sfSignature`. */ bool -verify( - STObject const& st, - HashPrefix const& prefix, - PublicKey const& pk, - SF_VL const& sigField = sfSignature); +verify(STObject const& st, HashPrefix const& prefix, PublicKey const& pk, SF_VL const& sigField = sfSignature); /** Return a Serializer suitable for computing a multisigning TxnSignature. */ Serializer @@ -86,6 +57,4 @@ finishMultiSigningData(AccountID const& signingID, Serializer& s) s.addBitString(signingID); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h index 5aa21827fc..70ab67c56f 100644 --- a/include/xrpl/protocol/SystemParameters.h +++ b/include/xrpl/protocol/SystemParameters.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED -#define RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { // Various protocol and system specific constant globals. @@ -42,6 +22,8 @@ systemName() /** Number of drops in the genesis account. */ constexpr XRPAmount INITIAL_XRP{100'000'000'000 * DROPS_PER_XRP}; +static_assert(INITIAL_XRP.drops() == 100'000'000'000'000'000); +static_assert(Number::maxRep >= INITIAL_XRP.drops()); /** Returns true if the amount does not exceed the initial XRP in existence. */ inline bool @@ -79,9 +61,7 @@ constexpr std::ratio<80, 100> amendmentMajorityCalcThreshold; /** The minimum amount of time an amendment must hold a majority */ constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2}; -} // namespace ripple +} // namespace xrpl /** Default peer port (IANA registered) */ inline std::uint16_t constexpr DEFAULT_PEER_PORT{2459}; - -#endif diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 544ab68082..2e408f8df7 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 - 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_TER_H_INCLUDED -#define RIPPLE_PROTOCOL_TER_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { // See https://xrpl.org/transaction-results.html // @@ -213,19 +193,19 @@ enum TERcodes : TERUnderlyingType { // - Hold // - Makes hole in sequence which jams transactions. terRETRY = -99, - terFUNDS_SPENT, // DEPRECATED. - terINSUF_FEE_B, // Can't pay fee, therefore don't burden network. - terNO_ACCOUNT, // Can't pay fee, therefore don't burden network. - terNO_AUTH, // Not authorized to hold IOUs. - terNO_LINE, // Internal flag. - terOWNERS, // Can't succeed with non-zero owner count. - terPRE_SEQ, // Can't pay fee, no point in forwarding, so don't - // burden network. - terLAST, // DEPRECATED. - terNO_RIPPLE, // Rippling not allowed - terQUEUED, // Transaction is being held in TxQ until fee drops - terPRE_TICKET, // Ticket is not yet in ledger but might be on its way - terNO_AMM, // AMM doesn't exist for the asset pair + terFUNDS_SPENT, // DEPRECATED. + terINSUF_FEE_B, // Can't pay fee, therefore don't burden network. + terNO_ACCOUNT, // Can't pay fee, therefore don't burden network. + terNO_AUTH, // Not authorized to hold IOUs. + terNO_LINE, // Internal flag. + terOWNERS, // Can't succeed with non-zero owner count. + terPRE_SEQ, // Can't pay fee, no point in forwarding, so don't + // burden network. + terLAST, // DEPRECATED. + terNO_RIPPLE, // Rippling not allowed + terQUEUED, // Transaction is being held in TxQ until fee drops + terPRE_TICKET, // Ticket is not yet in ledger but might be on its way + terNO_AMM, // AMM doesn't exist for the asset pair terADDRESS_COLLISION, // Failed to allocate AccountID when trying to // create a pseudo-account terNO_DELEGATE_PERMISSION, // Delegate does not have permission @@ -438,10 +418,7 @@ public: } // Trait tells enable_if which types are allowed for construction. - template < - typename T, - typename = std::enable_if_t< - Trait>>::value>> + template >>::value>> constexpr TERSubset(T rhs) : code_(TERtoInt(rhs)) { } @@ -511,8 +488,7 @@ template constexpr auto operator==(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) == TERtoInt(rhs); @@ -522,8 +498,7 @@ template constexpr auto operator!=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) != TERtoInt(rhs); @@ -533,8 +508,7 @@ template constexpr auto operator<(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) < TERtoInt(rhs); @@ -544,8 +518,7 @@ template constexpr auto operator<=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) <= TERtoInt(rhs); @@ -555,8 +528,7 @@ template constexpr auto operator>(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) > TERtoInt(rhs); @@ -566,8 +538,7 @@ template constexpr auto operator>=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, + std::is_same::value && std::is_same::value, bool> { return TERtoInt(lhs) >= TERtoInt(rhs); @@ -689,9 +660,7 @@ isTecClaim(TER x) noexcept return ((x) >= tecCLAIM); } -std::unordered_map< - TERUnderlyingType, - std::pair> const& +std::unordered_map> const& transResults(); bool @@ -706,6 +675,4 @@ transHuman(TER code); std::optional transCode(std::string const& token); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index e71b8f0565..8f06d3f519 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_TXFLAGS_H_INCLUDED -#define RIPPLE_PROTOCOL_TXFLAGS_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Transaction flags. @@ -151,9 +131,9 @@ constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow; constexpr std::uint32_t const tfMPTCanTrade = lsfMPTCanTrade; constexpr std::uint32_t const tfMPTCanTransfer = lsfMPTCanTransfer; constexpr std::uint32_t const tfMPTCanClawback = lsfMPTCanClawback; -constexpr std::uint32_t const tfMPTNoConfidentialTransfer = lsfMPTNoConfidentialTransfer; +constexpr std::uint32_t const tfMPTCanPrivacy = lsfMPTCanPrivacy; constexpr std::uint32_t const tfMPTokenIssuanceCreateMask = - ~(tfUniversal | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback | tfMPTNoConfidentialTransfer); + ~(tfUniversal | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanPrivacy); // MPTokenIssuanceCreate MutableFlags: // Indicating specific fields or flags may be changed after issuance. @@ -165,9 +145,13 @@ constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTr constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback; constexpr std::uint32_t const tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata; constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee; + +// Issuer can mutate lsfMPTPrivacy by default unless lsmfMPTCannotMutatePrivacy is set. +constexpr std::uint32_t const tmfMPTCannotMutatePrivacy = lsmfMPTCannotMutatePrivacy; constexpr std::uint32_t const tmfMPTokenIssuanceCreateMutableMask = ~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow | tmfMPTCanMutateCanTrade - | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee); + | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee + | tmfMPTCannotMutatePrivacy); // MPTokenAuthorize flags: constexpr std::uint32_t const tfMPTUnauthorize = 0x00000001; @@ -193,10 +177,12 @@ constexpr std::uint32_t const tmfMPTSetCanTransfer = 0x00000100; constexpr std::uint32_t const tmfMPTClearCanTransfer = 0x00000200; constexpr std::uint32_t const tmfMPTSetCanClawback = 0x00000400; constexpr std::uint32_t const tmfMPTClearCanClawback = 0x00000800; +constexpr std::uint32_t const tmfMPTSetPrivacy = 0x00001000; +constexpr std::uint32_t const tmfMPTClearPrivacy = 0x00002000; constexpr std::uint32_t const tmfMPTokenIssuanceSetMutableMask = ~(tmfMPTSetCanLock | tmfMPTClearCanLock | tmfMPTSetRequireAuth | tmfMPTClearRequireAuth | tmfMPTSetCanEscrow | tmfMPTClearCanEscrow | tmfMPTSetCanTrade | tmfMPTClearCanTrade | tmfMPTSetCanTransfer | tmfMPTClearCanTransfer | - tmfMPTSetCanClawback | tmfMPTClearCanClawback); + tmfMPTSetCanClawback | tmfMPTClearCanClawback | tmfMPTSetPrivacy | tmfMPTClearPrivacy); // MPTokenIssuanceDestroy flags: constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal; @@ -286,8 +272,32 @@ constexpr std::uint32_t tfIndependent = 0x00080000; constexpr std::uint32_t const tfBatchMask = ~(tfUniversal | tfAllOrNothing | tfOnlyOne | tfUntilFailure | tfIndependent) | tfInnerBatchTxn; +// LoanSet and LoanPay flags: +// LoanSet: True, indicates the loan supports overpayments +// LoanPay: True, indicates any excess in this payment can be used +// as an overpayment. False, no overpayments will be taken. +constexpr std::uint32_t const tfLoanOverpayment = 0x00010000; +// LoanPay exclusive flags: +// tfLoanFullPayment: True, indicates that the payment is an early +// full payment. It must pay the entire loan including close +// interest and fees, or it will fail. False: Not a full payment. +constexpr std::uint32_t const tfLoanFullPayment = 0x00020000; +// tfLoanLatePayment: True, indicates that the payment is late, +// and includes late interest and fees. If the loan is not late, +// it will fail. False: not a late payment. If the current payment +// is overdue, the transaction will fail. +constexpr std::uint32_t const tfLoanLatePayment = 0x00040000; +constexpr std::uint32_t const tfLoanSetMask = ~(tfUniversal | + tfLoanOverpayment); +constexpr std::uint32_t const tfLoanPayMask = ~(tfUniversal | + tfLoanOverpayment | tfLoanFullPayment | tfLoanLatePayment); + +// LoanManage flags: +constexpr std::uint32_t const tfLoanDefault = 0x00010000; +constexpr std::uint32_t const tfLoanImpair = 0x00020000; +constexpr std::uint32_t const tfLoanUnimpair = 0x00040000; +constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair); + // clang-format on -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/TxFormats.h b/include/xrpl/protocol/TxFormats.h index d17eea7644..b76eef7585 100644 --- a/include/xrpl/protocol/TxFormats.h +++ b/include/xrpl/protocol/TxFormats.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_TXFORMATS_H_INCLUDED -#define RIPPLE_PROTOCOL_TXFORMATS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Transaction type identifiers. @@ -95,6 +75,4 @@ public: getInstance(); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/TxMeta.h b/include/xrpl/protocol/TxMeta.h index 975ade355f..a295eb4569 100644 --- a/include/xrpl/protocol/TxMeta.h +++ b/include/xrpl/protocol/TxMeta.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_TX_TRANSACTIONMETA_H_INCLUDED -#define RIPPLE_APP_TX_TRANSACTIONMETA_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { class TxMeta { @@ -136,6 +116,4 @@ private: STArray nodes_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/TxSearched.h b/include/xrpl/protocol/TxSearched.h new file mode 100644 index 0000000000..e085bff315 --- /dev/null +++ b/include/xrpl/protocol/TxSearched.h @@ -0,0 +1,7 @@ +#pragma once + +namespace xrpl { + +enum class TxSearched { all, some, unknown }; + +} diff --git a/include/xrpl/protocol/UintTypes.h b/include/xrpl/protocol/UintTypes.h index 1d6b3e23dc..fd48244d89 100644 --- a/include/xrpl/protocol/UintTypes.h +++ b/include/xrpl/protocol/UintTypes.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_UINTTYPES_H_INCLUDED -#define RIPPLE_PROTOCOL_UINTTYPES_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { namespace detail { class CurrencyTag @@ -115,34 +95,32 @@ operator<<(std::ostream& os, Currency const& x) return os; } -} // namespace ripple +} // namespace xrpl namespace std { template <> -struct hash : ripple::Currency::hasher +struct hash : xrpl::Currency::hasher { hash() = default; }; template <> -struct hash : ripple::NodeID::hasher +struct hash : xrpl::NodeID::hasher { hash() = default; }; template <> -struct hash : ripple::Directory::hasher +struct hash : xrpl::Directory::hasher { hash() = default; }; template <> -struct hash : ripple::uint256::hasher +struct hash : xrpl::uint256::hasher { hash() = default; }; } // namespace std - -#endif diff --git a/include/xrpl/protocol/Units.h b/include/xrpl/protocol/Units.h index 6b2ae67059..ecf0bf7798 100644 --- a/include/xrpl/protocol/Units.h +++ b/include/xrpl/protocol/Units.h @@ -1,23 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PROTOCOL_UNITS_H_INCLUDED -#define PROTOCOL_UNITS_H_INCLUDED +#pragma once #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace unit { @@ -54,8 +35,8 @@ class TenthBipsTag; // namespace. template -concept Valid = std::is_class_v && std::is_object_v && - std::is_object_v; +concept Valid = + std::is_class_v && std::is_object_v && std::is_object_v; /** `Usable` is checked to ensure that only values with known valid type tags can be used (sometimes transparently) in @@ -66,15 +47,12 @@ concept Valid = std::is_class_v && std::is_object_v && */ template concept Usable = Valid && - (std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || + (std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v); template -concept Compatible = Valid && std::is_arithmetic_v && - std::is_arithmetic_v && +concept Compatible = Valid && std::is_arithmetic_v && std::is_arithmetic_v && std::is_convertible_v; template @@ -84,8 +62,8 @@ template concept IntegralValue = Integral; template -concept CastableValue = IntegralValue && IntegralValue && - std::is_same_v; +concept CastableValue = + IntegralValue && IntegralValue && std::is_same_v; template class ValueUnit : private boost::totally_ordered>, @@ -239,8 +217,7 @@ public: ValueUnit operator-() const { - static_assert( - std::is_signed_v, "- operator illegal on unsigned value types"); + static_assert(std::is_signed_v, "- operator illegal on unsigned value types"); return ValueUnit{-value_}; } @@ -315,10 +292,7 @@ public: { if constexpr (std::is_integral_v) { - using jsontype = std::conditional_t< - std::is_signed_v, - Json::Int, - Json::UInt>; + using jsontype = std::conditional_t, Json::Int, Json::UInt>; constexpr auto min = std::numeric_limits::min(); constexpr auto max = std::numeric_limits::max(); @@ -369,8 +343,7 @@ to_string(ValueUnit const& amount) } template -concept muldivSource = Valid && - std::is_convertible_v; +concept muldivSource = Valid && std::is_convertible_v; template concept muldivDest = muldivSource && // Dest is also a source @@ -386,8 +359,8 @@ concept muldivable = muldivSources && muldivDest; // Source and Dest can be the same by default template -concept muldivCommutable = muldivable && - !std::is_same_v; +concept muldivCommutable = + muldivable && !std::is_same_v; template ValueUnit @@ -405,12 +378,9 @@ mulDivU(Source1 value, Dest mul, Source2 div) { // split the asserts so if one hits, the user can tell which // without a debugger. - XRPL_ASSERT( - value.value() >= 0, "ripple::unit::mulDivU : minimum value input"); - XRPL_ASSERT( - mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input"); - XRPL_ASSERT( - div.value() > 0, "ripple::unit::mulDivU : minimum div input"); + XRPL_ASSERT(value.value() >= 0, "xrpl::unit::mulDivU : minimum value input"); + XRPL_ASSERT(mul.value() >= 0, "xrpl::unit::mulDivU : minimum mul input"); + XRPL_ASSERT(div.value() > 0, "xrpl::unit::mulDivU : minimum div input"); return std::nullopt; } @@ -430,10 +400,7 @@ mulDivU(Source1 value, Dest mul, Source2 div) using namespace boost::multiprecision; uint128_t product; - product = multiply( - product, - static_cast(value.value()), - static_cast(mul.value())); + product = multiply(product, static_cast(value.value()), static_cast(mul.value())); auto quotient = product / div.value(); @@ -468,10 +435,7 @@ mulDiv(Source1 value, Dest mul, Source2 div) return unit::mulDivU(value, mul, div); } -template < - class Source1, - class Source2, - unit::muldivCommutable Dest> +template Dest> std::optional mulDiv(Dest value, Source1 mul, Source2 div) { @@ -550,6 +514,4 @@ unsafe_cast(Src s) noexcept return Dest{unsafe_cast(s)}; } -} // namespace ripple - -#endif // PROTOCOL_UNITS_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/XChainAttestations.h b/include/xrpl/protocol/XChainAttestations.h index 92fd04731d..fc3c464b92 100644 --- a/include/xrpl/protocol/XChainAttestations.h +++ b/include/xrpl/protocol/XChainAttestations.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED -#define RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED +#pragma once #include #include @@ -37,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace Attestations { @@ -52,12 +32,12 @@ struct AttestationBase // Account on the sending chain that triggered the event (sent the // transaction) AccountID sendingAccount; - // Amount transfered on the sending chain + // Amount transferred on the sending chain STAmount sendingAmount; // Account on the destination chain that collects a share of the attestation // reward AccountID rewardAccount; - // Amount was transfered on the locking chain + // Amount was transferred on the locking chain bool wasLockingChainSend; explicit AttestationBase( @@ -216,9 +196,7 @@ struct AttestationCreateAccount : AttestationBase sameEvent(AttestationCreateAccount const& rhs) const; friend bool - operator==( - AttestationCreateAccount const& lhs, - AttestationCreateAccount const& rhs); + operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs); [[nodiscard]] static std::vector message( @@ -242,9 +220,7 @@ private: struct CmpByCreateCount { bool - operator()( - AttestationCreateAccount const& lhs, - AttestationCreateAccount const& rhs) const + operator()(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) const { return lhs.createCount < rhs.createCount; } @@ -280,10 +256,7 @@ struct XChainClaimAttestation bool wasLockingChainSend; std::optional dst; MatchFields(TSignedAttestation const& att); - MatchFields( - STAmount const& a, - bool b, - std::optional const& d) + MatchFields(STAmount const& a, bool b, std::optional const& d) : amount{a}, wasLockingChainSend{b}, dst{d} { } @@ -318,9 +291,7 @@ struct XChainClaimAttestation toSTObject() const; friend bool - operator==( - XChainClaimAttestation const& lhs, - XChainClaimAttestation const& rhs); + operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs); }; struct XChainCreateAccountAttestation @@ -368,12 +339,10 @@ struct XChainCreateAccountAttestation match(MatchFields const& rhs) const; friend bool - operator==( - XChainCreateAccountAttestation const& lhs, - XChainCreateAccountAttestation const& rhs); + operator==(XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs); }; -// Attestations from witness servers for a particular claimid and bridge. +// Attestations from witness servers for a particular claim ID and bridge. // Only one attestation per signature is allowed. template class XChainAttestationsBase @@ -439,9 +408,7 @@ public: template [[nodiscard]] inline bool -operator==( - XChainAttestationsBase const& lhs, - XChainAttestationsBase const& rhs) +operator==(XChainAttestationsBase const& lhs, XChainAttestationsBase const& rhs) { return lhs.attestations() == rhs.attestations(); } @@ -483,20 +450,16 @@ XChainAttestationsBase::empty() const return attestations_.empty(); } -class XChainClaimAttestations final - : public XChainAttestationsBase +class XChainClaimAttestations final : public XChainAttestationsBase { using TBase = XChainAttestationsBase; using TBase::TBase; }; -class XChainCreateAccountAttestations final - : public XChainAttestationsBase +class XChainCreateAccountAttestations final : public XChainAttestationsBase { using TBase = XChainAttestationsBase; using TBase::TBase; }; -} // namespace ripple - -#endif // STXCHAINATTESTATIONS_H_ +} // namespace xrpl diff --git a/include/xrpl/protocol/XRPAmount.h b/include/xrpl/protocol/XRPAmount.h index a7a013d625..c1af338e4b 100644 --- a/include/xrpl/protocol/XRPAmount.h +++ b/include/xrpl/protocol/XRPAmount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED -#define RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { class XRPAmount : private boost::totally_ordered, private boost::additive, @@ -186,10 +166,8 @@ public: std::optional dropsAs() const { - if ((drops_ > std::numeric_limits::max()) || - (!std::numeric_limits::is_signed && drops_ < 0) || - (std::numeric_limits::is_signed && - drops_ < std::numeric_limits::lowest())) + if ((drops_ > std::numeric_limits::max()) || (!std::numeric_limits::is_signed && drops_ < 0) || + (std::numeric_limits::is_signed && drops_ < std::numeric_limits::lowest())) { return std::nullopt; } @@ -279,11 +257,7 @@ to_string(XRPAmount const& amount) } inline XRPAmount -mulRatio( - XRPAmount const& amt, - std::uint32_t num, - std::uint32_t den, - bool roundUp) +mulRatio(XRPAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp) { using namespace boost::multiprecision; @@ -306,6 +280,4 @@ mulRatio( return XRPAmount(r.convert_to()); } -} // namespace ripple - -#endif // RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/detail/STVar.h b/include/xrpl/protocol/detail/STVar.h index 6ff7e5ebc1..b5373d1a4a 100644 --- a/include/xrpl/protocol/detail/STVar.h +++ b/include/xrpl/protocol/detail/STVar.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_STVAR_H_INCLUDED -#define RIPPLE_PROTOCOL_STVAR_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { struct defaultObject_t @@ -61,7 +41,7 @@ concept ValidConstructSTArgs = class STVar { private: - // The largest "small object" we can accomodate + // The largest "small object" we can accommodate static std::size_t constexpr max_size = 72; std::aligned_storage::type d_; @@ -181,6 +161,4 @@ operator!=(STVar const& lhs, STVar const& rhs) } } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index 3908822661..a34104555e 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED -#define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { template using Result = boost::outcome_v2::result; @@ -131,39 +111,35 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) // the a null set of numbers to be zero, so the remainder is also zero. // LCOV_EXCL_START UNREACHABLE( - "ripple::b58_fast::detail::inplace_bigint_div_rem : empty " + "xrpl::b58_fast::detail::inplace_bigint_div_rem : empty " "numerator"); return 0; // LCOV_EXCL_STOP } - auto to_u128 = [](std::uint64_t high, - std::uint64_t low) -> unsigned __int128 { + auto to_u128 = [](std::uint64_t high, std::uint64_t low) -> unsigned __int128 { unsigned __int128 const high128 = high; unsigned __int128 const low128 = low; return ((high128 << 64) | low128); }; - auto div_rem_64 = - [](unsigned __int128 num, - std::uint64_t denom) -> std::tuple { + auto div_rem_64 = [](unsigned __int128 num, std::uint64_t denom) -> std::tuple { unsigned __int128 const denom128 = denom; unsigned __int128 const d = num / denom128; unsigned __int128 const r = num - (denom128 * d); XRPL_ASSERT( d >> 64 == 0, - "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "xrpl::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " "valid division result"); XRPL_ASSERT( r >> 64 == 0, - "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "xrpl::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " "valid remainder"); return {static_cast(d), static_cast(r)}; }; std::uint64_t prev_rem = 0; int const last_index = numerator.size() - 1; - std::tie(numerator[last_index], prev_rem) = - div_rem(numerator[last_index], divisor); + std::tie(numerator[last_index], prev_rem) = div_rem(numerator[last_index], divisor); for (int i = last_index - 1; i >= 0; --i) { unsigned __int128 const cur_num = to_u128(prev_rem, numerator[i]); @@ -178,11 +154,8 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) [[nodiscard]] inline std::array b58_10_to_b58_be(std::uint64_t input) { - [[maybe_unused]] static constexpr std::uint64_t B_58_10 = - 430804206899405824; // 58^10; - XRPL_ASSERT( - input < B_58_10, - "ripple::b58_fast::detail::b58_10_to_b58_be : valid input"); + [[maybe_unused]] static constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; + XRPL_ASSERT(input < B_58_10, "xrpl::b58_fast::detail::b58_10_to_b58_be : valid input"); constexpr std::size_t resultSize = 10; std::array result{}; int i = 0; @@ -200,5 +173,4 @@ b58_10_to_b58_be(std::uint64_t input) } // namespace b58_fast #endif -} // namespace ripple -#endif // RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED +} // namespace xrpl diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 4504df6ed1..bb518c9fda 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -1,36 +1,25 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if !defined(XRPL_FEATURE) #error "undefined macro: XRPL_FEATURE" #endif #if !defined(XRPL_FIX) #error "undefined macro: XRPL_FIX" #endif -#if !defined(XRPL_RETIRE) -#error "undefined macro: XRPL_RETIRE" +#if !defined(XRPL_RETIRE_FEATURE) +#error "undefined macro: XRPL_RETIRE_FEATURE" #endif +#if !defined(XRPL_RETIRE_FIX) +#error "undefined macro: XRPL_RETIRE_FIX" +#endif + +// clang-format off // Add new amendments to the top of this list. // Keep it sorted in reverse chronological order. - -XRPL_FEATURE(ConfidentialTransfer, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(ConfidentialTransfer, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (PermissionedDomainInvariant, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (ExpiredNFTokenOfferRemoval, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (BatchInnerSigs, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(LendingProtocol, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo) @@ -44,7 +33,7 @@ XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo) +XRPL_FEATURE(SingleAssetVault, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) // Check flags in Credential transactions XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo) @@ -80,23 +69,7 @@ XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FIX (TrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes) -XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. @@ -108,47 +81,67 @@ XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYe // enabled (added to the ledger). // // If a feature remains obsolete for long enough that no clients are able -// to vote for it, the feature can be removed (entirely?) from the code. -XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete) - +// to vote for it, the feature can be removed entirely from the code. Until +// then the feature needs to be marked explicitly as obsolete, e.g. +// XRPL_FEATURE(Example, Supported::yes, VoteBehavior::Obsolete) // The following amendments have been active for at least two years. Their // pre-amendment code has been removed and the identifiers are deprecated. // All known amendments and amendments that may appear in a validated ledger // must be registered either here or above with the "active" amendments // -// Please keep this list sorted alphabetically for convenience. -XRPL_RETIRE(fix1201) -XRPL_RETIRE(fix1368) -XRPL_RETIRE(fix1373) -XRPL_RETIRE(fix1512) -XRPL_RETIRE(fix1513) -XRPL_RETIRE(fix1515) -XRPL_RETIRE(fix1523) -XRPL_RETIRE(fix1528) -XRPL_RETIRE(fix1543) -XRPL_RETIRE(fix1571) -XRPL_RETIRE(fix1578) -XRPL_RETIRE(fix1623) -XRPL_RETIRE(fix1781) -XRPL_RETIRE(fixAmendmentMajorityCalc) -XRPL_RETIRE(fixCheckThreading) -XRPL_RETIRE(fixNonFungibleTokensV1_2) -XRPL_RETIRE(fixNFTokenRemint) -XRPL_RETIRE(fixMasterKeyAsRegularKey) -XRPL_RETIRE(fixQualityUpperBound) -XRPL_RETIRE(fixReducedOffersV1) -XRPL_RETIRE(fixRmSmallIncreasedQOffers) -XRPL_RETIRE(fixSTAmountCanonicalize) -XRPL_RETIRE(fixTakerDryOfferRemoval) -XRPL_RETIRE(CryptoConditions) -XRPL_RETIRE(Escrow) -XRPL_RETIRE(EnforceInvariants) -XRPL_RETIRE(FeeEscalation) -XRPL_RETIRE(FlowCross) -XRPL_RETIRE(ImmediateOfferKilled) -XRPL_RETIRE(MultiSign) -XRPL_RETIRE(NonFungibleTokensV1_1) -XRPL_RETIRE(PayChan) -XRPL_RETIRE(SortedDirectories) -XRPL_RETIRE(TickSize) -XRPL_RETIRE(TrustSetAuth) +// Please keep both lists sorted alphabetically for convenience. +XRPL_RETIRE_FIX(1201) +XRPL_RETIRE_FIX(1368) +XRPL_RETIRE_FIX(1373) +XRPL_RETIRE_FIX(1512) +XRPL_RETIRE_FIX(1513) +XRPL_RETIRE_FIX(1515) +XRPL_RETIRE_FIX(1523) +XRPL_RETIRE_FIX(1528) +XRPL_RETIRE_FIX(1543) +XRPL_RETIRE_FIX(1571) +XRPL_RETIRE_FIX(1578) +XRPL_RETIRE_FIX(1623) +XRPL_RETIRE_FIX(1781) +XRPL_RETIRE_FIX(AmendmentMajorityCalc) +XRPL_RETIRE_FIX(CheckThreading) +XRPL_RETIRE_FIX(MasterKeyAsRegularKey) +XRPL_RETIRE_FIX(NonFungibleTokensV1_2) +XRPL_RETIRE_FIX(NFTokenRemint) +XRPL_RETIRE_FIX(PayChanRecipientOwnerDir) +XRPL_RETIRE_FIX(QualityUpperBound) +XRPL_RETIRE_FIX(ReducedOffersV1) +XRPL_RETIRE_FIX(RmSmallIncreasedQOffers) +XRPL_RETIRE_FIX(STAmountCanonicalize) +XRPL_RETIRE_FIX(TakerDryOfferRemoval) +XRPL_RETIRE_FIX(TrustLinesToSelf) + +XRPL_RETIRE_FEATURE(Checks) +XRPL_RETIRE_FEATURE(CheckCashMakesTrustLine) +XRPL_RETIRE_FEATURE(CryptoConditions) +XRPL_RETIRE_FEATURE(CryptoConditionsSuite) +XRPL_RETIRE_FEATURE(DeletableAccounts) +XRPL_RETIRE_FEATURE(DepositAuth) +XRPL_RETIRE_FEATURE(DepositPreauth) +XRPL_RETIRE_FEATURE(DisallowIncoming) +XRPL_RETIRE_FEATURE(Escrow) +XRPL_RETIRE_FEATURE(EnforceInvariants) +XRPL_RETIRE_FEATURE(ExpandedSignerList) +XRPL_RETIRE_FEATURE(FeeEscalation) +XRPL_RETIRE_FEATURE(Flow) +XRPL_RETIRE_FEATURE(FlowCross) +XRPL_RETIRE_FEATURE(FlowSortStrands) +XRPL_RETIRE_FEATURE(HardenedValidations) +XRPL_RETIRE_FEATURE(ImmediateOfferKilled) +XRPL_RETIRE_FEATURE(MultiSign) +XRPL_RETIRE_FEATURE(MultiSignReserve) +XRPL_RETIRE_FEATURE(NegativeUNL) +XRPL_RETIRE_FEATURE(NonFungibleTokensV1_1) +XRPL_RETIRE_FEATURE(PayChan) +XRPL_RETIRE_FEATURE(RequireFullyCanonicalSig) +XRPL_RETIRE_FEATURE(SortedDirectories) +XRPL_RETIRE_FEATURE(TicketBatch) +XRPL_RETIRE_FEATURE(TickSize) +XRPL_RETIRE_FEATURE(TrustSetAuth) + +// clang-format on diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index f58a2a1998..87ac3dc5f5 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if !defined(LEDGER_ENTRY) #error "undefined macro: LEDGER_ENTRY" #endif @@ -168,6 +149,7 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({ {sfFirstNFTokenSequence, soeOPTIONAL}, {sfAMMID, soeOPTIONAL}, // pseudo-account designator {sfVaultID, soeOPTIONAL}, // pseudo-account designator + {sfLoanBrokerID, soeOPTIONAL}, // pseudo-account designator })) /** A ledger object which contains a list of object identifiers. @@ -255,7 +237,7 @@ LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, ({ {sfAdditionalBooks, soeOPTIONAL}, })) -/** A ledger object which describes a deposit preauthorization. +/** A ledger object which describes a deposit pre-authorization. \sa keylet::depositPreauth */ @@ -417,6 +399,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({ {sfDomainID, soeOPTIONAL}, {sfMutableFlags, soeDEFAULT}, {sfIssuerElGamalPublicKey, soeOPTIONAL}, + {sfAuditorElGamalPublicKey, soeOPTIONAL}, {sfConfidentialOutstandingAmount, soeDEFAULT}, })) @@ -435,6 +418,7 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({ {sfConfidentialBalanceSpending, soeOPTIONAL}, {sfConfidentialBalanceVersion, soeDEFAULT}, {sfIssuerEncryptedBalance, soeOPTIONAL}, + {sfAuditorEncryptedBalance, soeOPTIONAL}, {sfHolderElGamalPublicKey, soeOPTIONAL}, })) @@ -505,10 +489,10 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({ {sfAccount, soeREQUIRED}, {sfData, soeOPTIONAL}, {sfAsset, soeREQUIRED}, - {sfAssetsTotal, soeREQUIRED}, - {sfAssetsAvailable, soeREQUIRED}, + {sfAssetsTotal, soeDEFAULT}, + {sfAssetsAvailable, soeDEFAULT}, {sfAssetsMaximum, soeDEFAULT}, - {sfLossUnrealized, soeREQUIRED}, + {sfLossUnrealized, soeDEFAULT}, {sfShareMPTID, soeREQUIRED}, {sfWithdrawalPolicy, soeREQUIRED}, {sfScale, soeDEFAULT}, @@ -516,5 +500,117 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({ // no PermissionedDomainID ever (use MPTIssuance.sfDomainID) })) +/** Reserve 0x0084-0x0087 for future Vault-related objects. */ + +/** A ledger object representing a loan broker + + \sa keylet::loanbroker + */ +LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({ + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfSequence, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfVaultNode, soeREQUIRED}, + {sfVaultID, soeREQUIRED}, + {sfAccount, soeREQUIRED}, + {sfOwner, soeREQUIRED}, + {sfLoanSequence, soeREQUIRED}, + {sfData, soeDEFAULT}, + {sfManagementFeeRate, soeDEFAULT}, + {sfOwnerCount, soeDEFAULT}, + {sfDebtTotal, soeDEFAULT}, + {sfDebtMaximum, soeDEFAULT}, + {sfCoverAvailable, soeDEFAULT}, + {sfCoverRateMinimum, soeDEFAULT}, + {sfCoverRateLiquidation, soeDEFAULT}, +})) + +/** A ledger object representing a loan between a Borrower and a Loan Broker + + \sa keylet::loan + */ +LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({ + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfLoanBrokerNode, soeREQUIRED}, + {sfLoanBrokerID, soeREQUIRED}, + {sfLoanSequence, soeREQUIRED}, + {sfBorrower, soeREQUIRED}, + {sfLoanOriginationFee, soeDEFAULT}, + {sfLoanServiceFee, soeDEFAULT}, + {sfLatePaymentFee, soeDEFAULT}, + {sfClosePaymentFee, soeDEFAULT}, + {sfOverpaymentFee, soeDEFAULT}, + {sfInterestRate, soeDEFAULT}, + {sfLateInterestRate, soeDEFAULT}, + {sfCloseInterestRate, soeDEFAULT}, + {sfOverpaymentInterestRate, soeDEFAULT}, + {sfStartDate, soeREQUIRED}, + {sfPaymentInterval, soeREQUIRED}, + {sfGracePeriod, soeDEFAULT}, + {sfPreviousPaymentDueDate, soeDEFAULT}, + {sfNextPaymentDueDate, soeDEFAULT}, + // The loan object tracks these values: + // + // - PaymentRemaining: The number of payments left in the loan. When it + // reaches 0, the loan is paid off, and all other relevant values + // must also be 0. + // + // - PeriodicPayment: The fixed, unrounded amount to be paid each + // interval. Stored with as much precision as possible. + // Payment transactions must round this value *UP*. + // + // - TotalValueOutstanding: The rounded total amount owed by the + // borrower to the lender / vault. + // + // - PrincipalOutstanding: The rounded portion of the + // TotalValueOutstanding that is from the principal borrowed. + // + // - ManagementFeeOutstanding: The rounded portion of the + // TotalValueOutstanding that represents management fees + // specifically owed to the broker based on the initial + // loan parameters. + // + // There are additional values that can be computed from these: + // + // - InterestOutstanding = TotalValueOutstanding - PrincipalOutstanding + // The total amount of interest still pending on the loan, + // independent of management fees. + // + // - InterestOwedToVault = InterestOutstanding - ManagementFeeOutstanding + // The amount of the total interest that is owed to the vault, and + // will be sent to it as part of a payment. + // + // - TrueTotalLoanValue = PaymentRemaining * PeriodicPayment + // The unrounded true total value of the loan. + // + // - TrueTotalPrincipalOutstanding can be computed using the algorithm + // in the ripple::detail::loanPrincipalFromPeriodicPayment function. + // + // - TrueTotalInterestOutstanding = TrueTotalLoanValue - + // TrueTotalPrincipalOutstanding + // The unrounded true total interest remaining. + // + // - TrueTotalManagementFeeOutstanding = TrueTotalInterestOutstanding * + // LoanBroker.ManagementFeeRate + // The unrounded true total fee still owed to the broker. + // + // Note the the "True" values may differ significantly from the tracked + // rounded values. + {sfPaymentRemaining, soeDEFAULT}, + {sfPeriodicPayment, soeREQUIRED}, + {sfPrincipalOutstanding, soeDEFAULT}, + {sfTotalValueOutstanding, soeDEFAULT}, + {sfManagementFeeOutstanding, soeDEFAULT}, + // Based on the computed total value at creation, used for + // rounding calculated values so they are all on a + // consistent scale - that is, they all have the same + // number of digits after the decimal point (excluding + // trailing zeros). + {sfLoanScale, soeDEFAULT}, +})) + #undef EXPAND #undef LEDGER_ENTRY_DUPLICATE diff --git a/include/xrpl/protocol/detail/permissions.macro b/include/xrpl/protocol/detail/permissions.macro index ec19c5767f..729861a013 100644 --- a/include/xrpl/protocol/detail/permissions.macro +++ b/include/xrpl/protocol/detail/permissions.macro @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if !defined(PERMISSION) #error "undefined macro: PERMISSION" #endif diff --git a/include/xrpl/protocol/detail/secp256k1.h b/include/xrpl/protocol/detail/secp256k1.h index 36f4d39a13..0ac810fd80 100644 --- a/include/xrpl/protocol/detail/secp256k1.h +++ b/include/xrpl/protocol/detail/secp256k1.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SECP256K1_H_INCLUDED -#define RIPPLE_PROTOCOL_SECP256K1_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { template secp256k1_context const* @@ -31,9 +11,7 @@ secp256k1Context() struct holder { secp256k1_context* impl; - holder() - : impl(secp256k1_context_create( - SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN)) + holder() : impl(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN)) { } @@ -46,6 +24,4 @@ secp256k1Context() return h.impl; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index 0c127e21a9..86c20efd34 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if !defined(UNTYPED_SFIELD) #error "undefined macro: UNTYPED_SFIELD" #endif @@ -24,6 +5,8 @@ #error "undefined macro: TYPED_SFIELD" #endif +// clang-format off + // untyped UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257) UNTYPED_SFIELD(sfTransaction, TRANSACTION, 257) @@ -59,6 +42,7 @@ TYPED_SFIELD(sfHookEmitCount, UINT16, 18) TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19) TYPED_SFIELD(sfHookApiVersion, UINT16, 20) TYPED_SFIELD(sfLedgerFixType, UINT16, 21) +TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips) // 32-bit integers (common) TYPED_SFIELD(sfNetworkID, UINT32, 1) @@ -115,7 +99,22 @@ TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50) TYPED_SFIELD(sfOracleDocumentID, UINT32, 51) TYPED_SFIELD(sfPermissionValue, UINT32, 52) TYPED_SFIELD(sfMutableFlags, UINT32, 53) -TYPED_SFIELD(sfConfidentialBalanceVersion, UINT32, 54) +TYPED_SFIELD(sfStartDate, UINT32, 54) +TYPED_SFIELD(sfPaymentInterval, UINT32, 55) +TYPED_SFIELD(sfGracePeriod, UINT32, 56) +TYPED_SFIELD(sfPreviousPaymentDueDate, UINT32, 57) +TYPED_SFIELD(sfNextPaymentDueDate, UINT32, 58) +TYPED_SFIELD(sfPaymentRemaining, UINT32, 59) +TYPED_SFIELD(sfPaymentTotal, UINT32, 60) +TYPED_SFIELD(sfLoanSequence, UINT32, 61) +TYPED_SFIELD(sfCoverRateMinimum, UINT32, 62) // 1/10 basis points (bips) +TYPED_SFIELD(sfCoverRateLiquidation, UINT32, 63) // 1/10 basis points (bips) +TYPED_SFIELD(sfOverpaymentFee, UINT32, 64) // 1/10 basis points (bips) +TYPED_SFIELD(sfInterestRate, UINT32, 65) // 1/10 basis points (bips) +TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bips) +TYPED_SFIELD(sfCloseInterestRate, UINT32, 67) // 1/10 basis points (bips) +TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 68) // 1/10 basis points (bips) +TYPED_SFIELD(sfConfidentialBalanceVersion, UINT32, 69) // 64-bit integers (common) TYPED_SFIELD(sfIndexNext, UINT64, 1) @@ -147,7 +146,9 @@ TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SFie TYPED_SFIELD(sfIssuerNode, UINT64, 27) TYPED_SFIELD(sfSubjectNode, UINT64, 28) TYPED_SFIELD(sfLockedAmount, UINT64, 29, SField::sMD_BaseTen|SField::sMD_Default) -TYPED_SFIELD(sfConfidentialOutstandingAmount, UINT64, 30, SField::sMD_BaseTen|SField::sMD_Default) +TYPED_SFIELD(sfVaultNode, UINT64, 30) +TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31) +TYPED_SFIELD(sfConfidentialOutstandingAmount, UINT64, 32, SField::sMD_BaseTen|SField::sMD_Default) // 128-bit TYPED_SFIELD(sfEmailHash, UINT128, 1) @@ -202,19 +203,31 @@ TYPED_SFIELD(sfDomainID, UINT256, 34) TYPED_SFIELD(sfVaultID, UINT256, 35, SField::sMD_PseudoAccount | SField::sMD_Default) TYPED_SFIELD(sfParentBatchID, UINT256, 36) +TYPED_SFIELD(sfLoanBrokerID, UINT256, 37, + SField::sMD_PseudoAccount | SField::sMD_Default) +TYPED_SFIELD(sfLoanID, UINT256, 38) // number (common) TYPED_SFIELD(sfNumber, NUMBER, 1) -TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2) -TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3) -TYPED_SFIELD(sfAssetsTotal, NUMBER, 4) -TYPED_SFIELD(sfLossUnrealized, NUMBER, 5) +TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfAssetsTotal, NUMBER, 4, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfLossUnrealized, NUMBER, 5, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfDebtTotal, NUMBER, 6, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfDebtMaximum, NUMBER, 7, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfCoverAvailable, NUMBER, 8, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfLoanOriginationFee, NUMBER, 9) +TYPED_SFIELD(sfLoanServiceFee, NUMBER, 10) +TYPED_SFIELD(sfLatePaymentFee, NUMBER, 11) +TYPED_SFIELD(sfClosePaymentFee, NUMBER, 12) +TYPED_SFIELD(sfPrincipalOutstanding, NUMBER, 13, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfPrincipalRequested, NUMBER, 14) +TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15, SField::sMD_NeedsAsset | SField::sMD_Default) +TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16) +TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::sMD_NeedsAsset | SField::sMD_Default) // int32 -// NOTE: Do not use `sfDummyInt32`. It's so far the only use of INT32 -// in this file and has been defined here for test only. -// TODO: Replace `sfDummyInt32` with actually useful field. -TYPED_SFIELD(sfDummyInt32, INT32, 1) // for tests only +TYPED_SFIELD(sfLoanScale, INT32, 1) // currency amount (common) TYPED_SFIELD(sfAmount, AMOUNT, 1) @@ -296,6 +309,12 @@ TYPED_SFIELD(sfHolderEncryptedAmount, VL, 38) TYPED_SFIELD(sfIssuerEncryptedAmount, VL, 39) TYPED_SFIELD(sfSenderEncryptedAmount, VL, 40) TYPED_SFIELD(sfDestinationEncryptedAmount, VL, 41) +TYPED_SFIELD(sfAuditorEncryptedBalance, VL, 42) +TYPED_SFIELD(sfAuditorEncryptedAmount, VL, 43) +TYPED_SFIELD(sfAuditorElGamalPublicKey, VL, 44) +TYPED_SFIELD(sfBlindingFactor, VL, 45) +TYPED_SFIELD(sfAmountCommitment, VL, 46) +TYPED_SFIELD(sfBalanceCommitment, VL, 47) // account (common) TYPED_SFIELD(sfAccount, ACCOUNT, 1) @@ -320,6 +339,8 @@ TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21) TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22) TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23) TYPED_SFIELD(sfSubject, ACCOUNT, 24) +TYPED_SFIELD(sfBorrower, ACCOUNT, 25) +TYPED_SFIELD(sfCounterparty, ACCOUNT, 26) // vector of 256-bit TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never) @@ -383,6 +404,7 @@ UNTYPED_SFIELD(sfCredential, OBJECT, 33) UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34) UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35) UNTYPED_SFIELD(sfBook, OBJECT, 36) +UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::sMD_Default, SField::notSigning) // array of objects (common) // ARRAY/1 is reserved for end of array @@ -417,3 +439,5 @@ UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28) UNTYPED_SFIELD(sfPermissions, ARRAY, 29) UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30) UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::sMD_Default, SField::notSigning) + +// clang-format on diff --git a/include/xrpl/protocol/detail/token_errors.h b/include/xrpl/protocol/detail/token_errors.h index 0ae2728024..686851f508 100644 --- a/include/xrpl/protocol/detail/token_errors.h +++ b/include/xrpl/protocol/detail/token_errors.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_TOKEN_ERRORS_H_INCLUDED -#define RIPPLE_PROTOCOL_TOKEN_ERRORS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { enum class TokenCodecErrc { success = 0, inputTooLarge, @@ -39,12 +19,12 @@ enum class TokenCodecErrc { namespace std { template <> -struct is_error_code_enum : true_type +struct is_error_code_enum : true_type { }; } // namespace std -namespace ripple { +namespace xrpl { namespace detail { class TokenCodecErrcCategory : public std::error_category { @@ -86,17 +66,16 @@ public: }; } // namespace detail -inline ripple::detail::TokenCodecErrcCategory const& +inline xrpl::detail::TokenCodecErrcCategory const& TokenCodecErrcCategory() { - static ripple::detail::TokenCodecErrcCategory c; + static xrpl::detail::TokenCodecErrcCategory c; return c; } inline std::error_code -make_error_code(ripple::TokenCodecErrc e) +make_error_code(xrpl::TokenCodecErrc e) { return {static_cast(e), TokenCodecErrcCategory()}; } -} // namespace ripple -#endif // TOKEN_ERRORS_H_ +} // namespace xrpl diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 982c8ae96b..49ee7f2265 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if !defined(TRANSACTION) #error "undefined macro: TRANSACTION" #endif /** - * TRANSACTION(tag, value, name, delegatable, amendments, privileges, fields) + * TRANSACTION(tag, value, name, delegable, amendments, privileges, fields) * * To ease maintenance, you may replace any unneeded values with "..." * e.g. #define TRANSACTION(tag, value, name, ...) @@ -44,7 +25,7 @@ # include #endif TRANSACTION(ttPAYMENT, 0, Payment, - Delegation::delegatable, + Delegation::delegable, uint256{}, createAcct, ({ @@ -64,7 +45,7 @@ TRANSACTION(ttPAYMENT, 0, Payment, # include #endif TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -78,7 +59,7 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, /** This transaction type completes an existing escrow. */ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -95,7 +76,7 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, # include #endif TRANSACTION(ttACCOUNT_SET, 3, AccountSet, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ @@ -116,7 +97,7 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet, # include #endif TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -129,7 +110,7 @@ TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, # include #endif TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ @@ -143,7 +124,7 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, # include #endif TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -159,7 +140,7 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, # include #endif TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -173,8 +154,8 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, # include #endif TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, - Delegation::delegatable, - featureTicketBatch, + Delegation::delegable, + uint256{}, noPriv, ({ {sfTicketCount, soeREQUIRED}, @@ -189,7 +170,7 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, # include #endif TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ @@ -202,7 +183,7 @@ TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, # include #endif TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -216,7 +197,7 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, /** This transaction type funds an existing unidirectional XRP payment channel. */ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -227,7 +208,7 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, /** This transaction type submits a claim against an existing unidirectional payment channel. */ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -244,8 +225,8 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, # include #endif TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, - Delegation::delegatable, - featureChecks, + Delegation::delegable, + uint256{}, noPriv, ({ {sfDestination, soeREQUIRED}, @@ -260,8 +241,8 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, # include #endif TRANSACTION(ttCHECK_CASH, 17, CheckCash, - Delegation::delegatable, - featureChecks, + Delegation::delegable, + uint256{}, noPriv, ({ {sfCheckID, soeREQUIRED}, @@ -274,8 +255,8 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash, # include #endif TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, - Delegation::delegatable, - featureChecks, + Delegation::delegable, + uint256{}, noPriv, ({ {sfCheckID, soeREQUIRED}, @@ -286,8 +267,8 @@ TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, # include #endif TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, - Delegation::delegatable, - featureDepositPreauth, + Delegation::delegable, + uint256{}, noPriv, ({ {sfAuthorize, soeOPTIONAL}, @@ -301,7 +282,7 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, # include #endif TRANSACTION(ttTRUST_SET, 20, TrustSet, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -315,8 +296,8 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet, # include #endif TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, - Delegation::notDelegatable, - featureDeletableAccounts, + Delegation::notDelegable, + uint256{}, mustDeleteAcct, ({ {sfDestination, soeREQUIRED}, @@ -331,7 +312,7 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, # include #endif TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, - Delegation::delegatable, + Delegation::delegable, uint256{}, changeNFTCounts, ({ @@ -349,7 +330,7 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, # include #endif TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, - Delegation::delegatable, + Delegation::delegable, uint256{}, changeNFTCounts, ({ @@ -362,7 +343,7 @@ TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, # include #endif TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -378,7 +359,7 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, # include #endif TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -390,7 +371,7 @@ TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, # include #endif TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, - Delegation::delegatable, + Delegation::delegable, uint256{}, noPriv, ({ @@ -404,7 +385,7 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, # include #endif TRANSACTION(ttCLAWBACK, 30, Clawback, - Delegation::delegatable, + Delegation::delegable, featureClawback, noPriv, ({ @@ -417,7 +398,7 @@ TRANSACTION(ttCLAWBACK, 30, Clawback, # include #endif TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, - Delegation::delegatable, + Delegation::delegable, featureAMMClawback, mayDeleteAcct | overrideFreeze, ({ @@ -432,7 +413,7 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, # include #endif TRANSACTION(ttAMM_CREATE, 35, AMMCreate, - Delegation::delegatable, + Delegation::delegable, featureAMM, createPseudoAcct, ({ @@ -446,7 +427,7 @@ TRANSACTION(ttAMM_CREATE, 35, AMMCreate, # include #endif TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, - Delegation::delegatable, + Delegation::delegable, featureAMM, noPriv, ({ @@ -464,7 +445,7 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, # include #endif TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, - Delegation::delegatable, + Delegation::delegable, featureAMM, mayDeleteAcct, ({ @@ -481,7 +462,7 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, # include #endif TRANSACTION(ttAMM_VOTE, 38, AMMVote, - Delegation::delegatable, + Delegation::delegable, featureAMM, noPriv, ({ @@ -495,7 +476,7 @@ TRANSACTION(ttAMM_VOTE, 38, AMMVote, # include #endif TRANSACTION(ttAMM_BID, 39, AMMBid, - Delegation::delegatable, + Delegation::delegable, featureAMM, noPriv, ({ @@ -511,7 +492,7 @@ TRANSACTION(ttAMM_BID, 39, AMMBid, # include #endif TRANSACTION(ttAMM_DELETE, 40, AMMDelete, - Delegation::delegatable, + Delegation::delegable, featureAMM, mustDeleteAcct, ({ @@ -524,7 +505,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete, # include #endif TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -535,7 +516,7 @@ TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, /** This transactions initiates a crosschain transaction */ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -547,7 +528,7 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, /** This transaction completes a crosschain transaction */ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -560,7 +541,7 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, /** This transaction initiates a crosschain account create transaction */ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -572,7 +553,7 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, /** This transaction adds an attestation to a claim */ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, createAcct, ({ @@ -593,7 +574,7 @@ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, /** This transaction adds an attestation to an account */ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, createAcct, ({ @@ -614,7 +595,7 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, /** This transaction modifies a sidechain */ TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -625,7 +606,7 @@ TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, /** This transactions creates a sidechain */ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, - Delegation::delegatable, + Delegation::delegable, featureXChainBridge, noPriv, ({ @@ -639,7 +620,7 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, # include #endif TRANSACTION(ttDID_SET, 49, DIDSet, - Delegation::delegatable, + Delegation::delegable, featureDID, noPriv, ({ @@ -650,7 +631,7 @@ TRANSACTION(ttDID_SET, 49, DIDSet, /** This transaction type deletes a DID */ TRANSACTION(ttDID_DELETE, 50, DIDDelete, - Delegation::delegatable, + Delegation::delegable, featureDID, noPriv, ({})) @@ -660,7 +641,7 @@ TRANSACTION(ttDID_DELETE, 50, DIDDelete, # include #endif TRANSACTION(ttORACLE_SET, 51, OracleSet, - Delegation::delegatable, + Delegation::delegable, featurePriceOracle, noPriv, ({ @@ -677,7 +658,7 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet, # include #endif TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, - Delegation::delegatable, + Delegation::delegable, featurePriceOracle, noPriv, ({ @@ -689,7 +670,7 @@ TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, # include #endif TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, - Delegation::delegatable, + Delegation::delegable, fixNFTokenPageLinks, noPriv, ({ @@ -702,7 +683,7 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, # include #endif TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, - Delegation::delegatable, + Delegation::delegable, featureMPTokensV1, createMPTIssuance, ({ @@ -719,7 +700,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, # include #endif TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, - Delegation::delegatable, + Delegation::delegable, featureMPTokensV1, destroyMPTIssuance, ({ @@ -731,7 +712,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, # include #endif TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, - Delegation::delegatable, + Delegation::delegable, featureMPTokensV1, noPriv, ({ @@ -742,6 +723,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, {sfTransferFee, soeOPTIONAL}, {sfMutableFlags, soeOPTIONAL}, {sfIssuerElGamalPublicKey, soeOPTIONAL}, + {sfAuditorElGamalPublicKey, soeOPTIONAL}, })) /** This transaction type authorizes a MPToken instance */ @@ -749,7 +731,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, # include #endif TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, - Delegation::delegatable, + Delegation::delegable, featureMPTokensV1, mustAuthorizeMPT, ({ @@ -762,7 +744,7 @@ TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, # include #endif TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, - Delegation::delegatable, + Delegation::delegable, featureCredentials, noPriv, ({ @@ -774,7 +756,7 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, /** This transaction type accept an Credential object */ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept, - Delegation::delegatable, + Delegation::delegable, featureCredentials, noPriv, ({ @@ -784,7 +766,7 @@ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept, /** This transaction type delete an Credential object */ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, - Delegation::delegatable, + Delegation::delegable, featureCredentials, noPriv, ({ @@ -798,7 +780,7 @@ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, # include #endif TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify, - Delegation::delegatable, + Delegation::delegable, featureDynamicNFT, noPriv, ({ @@ -812,7 +794,7 @@ TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify, # include #endif TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet, - Delegation::delegatable, + Delegation::delegable, featurePermissionedDomains, noPriv, ({ @@ -825,7 +807,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet, # include #endif TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete, - Delegation::delegatable, + Delegation::delegable, featurePermissionedDomains, noPriv, ({ @@ -837,7 +819,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete, # include #endif TRANSACTION(ttDELEGATE_SET, 64, DelegateSet, - Delegation::notDelegatable, + Delegation::notDelegable, featurePermissionDelegationV1_1, noPriv, ({ @@ -850,7 +832,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet, # include #endif TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, createPseudoAcct | createMPTIssuance | mustModifyVault, ({ @@ -868,7 +850,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, # include #endif TRANSACTION(ttVAULT_SET, 66, VaultSet, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, mustModifyVault, ({ @@ -883,7 +865,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet, # include #endif TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, mustDeleteAcct | destroyMPTIssuance | mustModifyVault, ({ @@ -895,7 +877,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, # include #endif TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, mayAuthorizeMPT | mustModifyVault, ({ @@ -908,7 +890,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, # include #endif TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, mayDeleteMPT | mayAuthorizeMPT | mustModifyVault, ({ @@ -923,7 +905,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, # include #endif TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback, - Delegation::delegatable, + Delegation::delegable, featureSingleAssetVault, mayDeleteMPT | mustModifyVault, ({ @@ -937,7 +919,7 @@ TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback, # include #endif TRANSACTION(ttBATCH, 71, Batch, - Delegation::notDelegatable, + Delegation::notDelegable, featureBatch, noPriv, ({ @@ -945,12 +927,145 @@ TRANSACTION(ttBATCH, 71, Batch, {sfBatchSigners, soeOPTIONAL}, })) +/** Reserve 72-73 for future Vault-related transactions */ + +/** This transaction creates and updates a Loan Broker */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet, + Delegation::delegable, + featureLendingProtocol, + createPseudoAcct | mayAuthorizeMPT, ({ + {sfVaultID, soeREQUIRED}, + {sfLoanBrokerID, soeOPTIONAL}, + {sfData, soeOPTIONAL}, + {sfManagementFeeRate, soeOPTIONAL}, + {sfDebtMaximum, soeOPTIONAL}, + {sfCoverRateMinimum, soeOPTIONAL}, + {sfCoverRateLiquidation, soeOPTIONAL}, +})) + +/** This transaction deletes a Loan Broker */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete, + Delegation::delegable, + featureLendingProtocol, + mustDeleteAcct | mayAuthorizeMPT, ({ + {sfLoanBrokerID, soeREQUIRED}, +})) + +/** This transaction deposits First Loss Capital into a Loan Broker */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit, + Delegation::delegable, + featureLendingProtocol, + noPriv, ({ + {sfLoanBrokerID, soeREQUIRED}, + {sfAmount, soeREQUIRED, soeMPTSupported}, +})) + +/** This transaction withdraws First Loss Capital from a Loan Broker */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw, + Delegation::delegable, + featureLendingProtocol, + mayAuthorizeMPT, ({ + {sfLoanBrokerID, soeREQUIRED}, + {sfAmount, soeREQUIRED, soeMPTSupported}, + {sfDestination, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, +})) + +/** This transaction claws back First Loss Capital from a Loan Broker to + the issuer of the capital */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback, + Delegation::delegable, + featureLendingProtocol, + noPriv, ({ + {sfLoanBrokerID, soeOPTIONAL}, + {sfAmount, soeOPTIONAL, soeMPTSupported}, +})) + +/** This transaction creates a Loan */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_SET, 80, LoanSet, + Delegation::delegable, + featureLendingProtocol, + mayAuthorizeMPT | mustModifyVault, ({ + {sfLoanBrokerID, soeREQUIRED}, + {sfData, soeOPTIONAL}, + {sfCounterparty, soeOPTIONAL}, + {sfCounterpartySignature, soeOPTIONAL}, + {sfLoanOriginationFee, soeOPTIONAL}, + {sfLoanServiceFee, soeOPTIONAL}, + {sfLatePaymentFee, soeOPTIONAL}, + {sfClosePaymentFee, soeOPTIONAL}, + {sfOverpaymentFee, soeOPTIONAL}, + {sfInterestRate, soeOPTIONAL}, + {sfLateInterestRate, soeOPTIONAL}, + {sfCloseInterestRate, soeOPTIONAL}, + {sfOverpaymentInterestRate, soeOPTIONAL}, + {sfPrincipalRequested, soeREQUIRED}, + {sfPaymentTotal, soeOPTIONAL}, + {sfPaymentInterval, soeOPTIONAL}, + {sfGracePeriod, soeOPTIONAL}, +})) + +/** This transaction deletes an existing Loan */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_DELETE, 81, LoanDelete, + Delegation::delegable, + featureLendingProtocol, + noPriv, ({ + {sfLoanID, soeREQUIRED}, +})) + +/** This transaction is used to change the delinquency status of an existing Loan */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_MANAGE, 82, LoanManage, + Delegation::delegable, + featureLendingProtocol, + // All of the LoanManage options will modify the vault, but the + // transaction can succeed without options, essentially making it + // a noop. + mayModifyVault, ({ + {sfLoanID, soeREQUIRED}, +})) + +/** The Borrower uses this transaction to make a Payment on the Loan. */ +#if TRANSACTION_INCLUDE +# include +#endif +TRANSACTION(ttLOAN_PAY, 84, LoanPay, + Delegation::delegable, + featureLendingProtocol, + mayAuthorizeMPT | mustModifyVault, ({ + {sfLoanID, soeREQUIRED}, + {sfAmount, soeREQUIRED, soeMPTSupported}, +})) + /** This transaction type converts into confidential MPT balance. */ #if TRANSACTION_INCLUDE -#include +#include #endif -TRANSACTION(ttCONFIDENTIAL_CONVERT, 72, ConfidentialConvert, - Delegation::delegatable, +TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT, 85, ConfidentialMPTConvert, + Delegation::delegable, featureConfidentialTransfer, noPriv, ({ @@ -959,15 +1074,17 @@ TRANSACTION(ttCONFIDENTIAL_CONVERT, 72, ConfidentialConvert, {sfHolderElGamalPublicKey, soeOPTIONAL}, {sfHolderEncryptedAmount, soeREQUIRED}, {sfIssuerEncryptedAmount, soeREQUIRED}, - {sfZKProof, soeREQUIRED}, + {sfAuditorEncryptedAmount, soeOPTIONAL}, + {sfBlindingFactor, soeREQUIRED}, + {sfZKProof, soeOPTIONAL}, })) /** This transaction type merges MPT inbox. */ #if TRANSACTION_INCLUDE -#include +#include #endif -TRANSACTION(ttCONFIDENTIAL_MERGE_INBOX, 73, ConfidentialMergeInbox, - Delegation::delegatable, +TRANSACTION(ttCONFIDENTIAL_MPT_MERGE_INBOX, 86, ConfidentialMPTMergeInbox, + Delegation::delegable, featureConfidentialTransfer, noPriv, ({ @@ -976,10 +1093,10 @@ TRANSACTION(ttCONFIDENTIAL_MERGE_INBOX, 73, ConfidentialMergeInbox, /** This transaction type converts back into public MPT balance. */ #if TRANSACTION_INCLUDE -#include +#include #endif -TRANSACTION(ttCONFIDENTIAL_CONVERT_BACK, 74, ConfidentialConvertBack, - Delegation::delegatable, +TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT_BACK, 87, ConfidentialMPTConvertBack, + Delegation::delegable, featureConfidentialTransfer, noPriv, ({ @@ -987,14 +1104,17 @@ TRANSACTION(ttCONFIDENTIAL_CONVERT_BACK, 74, ConfidentialConvertBack, {sfMPTAmount, soeREQUIRED}, {sfHolderEncryptedAmount, soeREQUIRED}, {sfIssuerEncryptedAmount, soeREQUIRED}, + {sfAuditorEncryptedAmount, soeOPTIONAL}, + {sfBlindingFactor, soeREQUIRED}, {sfZKProof, soeREQUIRED}, + {sfBalanceCommitment, soeREQUIRED}, })) #if TRANSACTION_INCLUDE -#include +#include #endif -TRANSACTION(ttCONFIDENTIAL_SEND, 75, ConfidentialSend, - Delegation::delegatable, +TRANSACTION(ttCONFIDENTIAL_MPT_SEND, 88, ConfidentialMPTSend, + Delegation::delegable, featureConfidentialTransfer, noPriv, ({ @@ -1003,15 +1123,18 @@ TRANSACTION(ttCONFIDENTIAL_SEND, 75, ConfidentialSend, {sfSenderEncryptedAmount, soeREQUIRED}, {sfDestinationEncryptedAmount, soeREQUIRED}, {sfIssuerEncryptedAmount, soeREQUIRED}, + {sfAuditorEncryptedAmount, soeOPTIONAL}, {sfZKProof, soeREQUIRED}, + {sfAmountCommitment, soeREQUIRED}, + {sfBalanceCommitment, soeREQUIRED}, {sfCredentialIDs, soeOPTIONAL}, })) #if TRANSACTION_INCLUDE -#include +#include #endif -TRANSACTION(ttCONFIDENTIAL_CLAWBACK, 76, ConfidentialClawback, - Delegation::delegatable, +TRANSACTION(ttCONFIDENTIAL_MPT_CLAWBACK, 89, ConfidentialMPTClawback, + Delegation::delegable, featureConfidentialTransfer, noPriv, ({ @@ -1029,7 +1152,7 @@ TRANSACTION(ttCONFIDENTIAL_CLAWBACK, 76, ConfidentialClawback, # include #endif TRANSACTION(ttAMENDMENT, 100, EnableAmendment, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ @@ -1041,7 +1164,7 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment, For details, see: https://xrpl.org/fee-voting.html */ TRANSACTION(ttFEE, 101, SetFee, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ @@ -1062,7 +1185,7 @@ TRANSACTION(ttFEE, 101, SetFee, For details, see: https://xrpl.org/negative-unl.html */ TRANSACTION(ttUNL_MODIFY, 102, UNLModify, - Delegation::notDelegatable, + Delegation::notDelegable, uint256{}, noPriv, ({ diff --git a/include/xrpl/protocol/digest.h b/include/xrpl/protocol/digest.h index 303fbafe4f..b5ec277e7b 100644 --- a/include/xrpl/protocol/digest.h +++ b/include/xrpl/protocol/digest.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_DIGEST_H_INCLUDED -#define RIPPLE_PROTOCOL_DIGEST_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { /** Message digest functions used in the codebase @@ -245,6 +225,4 @@ sha512Half_s(Args const&... args) return static_cast(h); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/json_get_or_throw.h b/include/xrpl/protocol/json_get_or_throw.h index 74d1779339..7cdf481ad3 100644 --- a/include/xrpl/protocol/json_get_or_throw.h +++ b/include/xrpl/protocol/json_get_or_throw.h @@ -1,5 +1,4 @@ -#ifndef PROTOCOL_GET_OR_THROW_H_ -#define PROTOCOL_GET_OR_THROW_H_ +#pragma once #include #include @@ -35,8 +34,7 @@ struct JsonTypeMismatchError : std::exception char const* const key; std::string const expectedType; mutable std::string msg; - JsonTypeMismatchError(Json::StaticString const& k, std::string et) - : key{k.c_str()}, expectedType{std::move(et)} + JsonTypeMismatchError(Json::StaticString const& k, std::string et) : key{k.c_str()}, expectedType{std::move(et)} { } char const* @@ -44,8 +42,7 @@ struct JsonTypeMismatchError : std::exception { if (msg.empty()) { - msg = std::string("Type mismatch on json key: ") + key + - "; expected type: " + expectedType; + msg = std::string("Type mismatch on json key: ") + key + "; expected type: " + expectedType; } return msg.c_str(); } @@ -53,16 +50,16 @@ struct JsonTypeMismatchError : std::exception template T -getOrThrow(Json::Value const& v, ripple::SField const& field) +getOrThrow(Json::Value const& v, xrpl::SField const& field) { static_assert(sizeof(T) == -1, "This function must be specialized"); } template <> inline std::string -getOrThrow(Json::Value const& v, ripple::SField const& field) +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; Json::StaticString const& key = field.getJsonName(); if (!v.isMember(key)) Throw(key); @@ -76,9 +73,9 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) // Note, this allows integer numeric fields to act as bools template <> inline bool -getOrThrow(Json::Value const& v, ripple::SField const& field) +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; Json::StaticString const& key = field.getJsonName(); if (!v.isMember(key)) Throw(key); @@ -93,9 +90,9 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) template <> inline std::uint64_t -getOrThrow(Json::Value const& v, ripple::SField const& field) +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; Json::StaticString const& key = field.getJsonName(); if (!v.isMember(key)) Throw(key); @@ -125,10 +122,10 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) } template <> -inline ripple::Buffer -getOrThrow(Json::Value const& v, ripple::SField const& field) +inline xrpl::Buffer +getOrThrow(Json::Value const& v, xrpl::SField const& field) { - using namespace ripple; + using namespace xrpl; std::string const hex = getOrThrow(v, field); if (auto const r = strUnHex(hex)) { @@ -141,7 +138,7 @@ getOrThrow(Json::Value const& v, ripple::SField const& field) // This function may be used by external projects (like the witness server). template std::optional -getOptional(Json::Value const& v, ripple::SField const& field) +getOptional(Json::Value const& v, xrpl::SField const& field) { try { @@ -154,5 +151,3 @@ getOptional(Json::Value const& v, ripple::SField const& field) } } // namespace Json - -#endif // PROTOCOL_GET_OR_THROW_H_ diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index bb5af1fc4d..0264f625eb 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_JSONFIELDS_H_INCLUDED -#define RIPPLE_PROTOCOL_JSONFIELDS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace jss { // JSON static strings @@ -59,6 +39,8 @@ JSS(BaseAsset); // in: Oracle JSS(BidMax); // in: AMM Bid JSS(BidMin); // in: AMM Bid JSS(ClearFlag); // field. +JSS(Counterparty); // field. +JSS(CounterpartySignature);// field. JSS(DeliverMax); // out: alias to Amount JSS(DeliverMin); // in: TransactionSign JSS(Destination); // in: TransactionSign; field. @@ -392,6 +374,8 @@ JSS(load_factor_local); // out: NetworkOPs JSS(load_factor_net); // out: NetworkOPs JSS(load_factor_server); // out: NetworkOPs JSS(load_fee); // out: LoadFeeTrackImp, NetworkOPs +JSS(loan_broker_id); // in: LedgerEntry +JSS(loan_seq); // in: LedgerEntry JSS(local); // out: resource/Logic.h JSS(local_txs); // out: GetCounts JSS(local_static_keys); // out: ValidatorList @@ -504,6 +488,7 @@ JSS(propose_seq); // out: LedgerPropose JSS(proposers); // out: NetworkOPs, LedgerConsensus JSS(protocol); // out: NetworkOPs, PeerImp JSS(proxied); // out: RPC ping +JSS(pseudo_account); // out: AccountInfo JSS(pubkey_node); // out: NetworkOPs JSS(pubkey_publisher); // out: ValidatorList JSS(pubkey_validator); // out: NetworkOPs, ValidatorList @@ -739,6 +724,4 @@ JSS(write_load); // out: GetCounts #undef JSS } // namespace jss -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/messages.h b/include/xrpl/protocol/messages.h index 640305185a..e6654cc183 100644 --- a/include/xrpl/protocol/messages.h +++ b/include/xrpl/protocol/messages.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_MESSAGES_H_INCLUDED -#define RIPPLE_PROTOCOL_MESSAGES_H_INCLUDED +#pragma once // Some versions of protobuf generate code that will produce errors during // compilation. See https://github.com/google/protobuf/issues/549 for more @@ -31,6 +11,4 @@ #undef TYPE_BOOL #endif -#include - -#endif +#include diff --git a/include/xrpl/protocol/nft.h b/include/xrpl/protocol/nft.h index 97c004ae3a..4be58c381c 100644 --- a/include/xrpl/protocol/nft.h +++ b/include/xrpl/protocol/nft.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_NFT_H_INCLUDED -#define RIPPLE_PROTOCOL_NFT_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace nft { // Separate taxons from regular integers. @@ -123,6 +103,4 @@ getIssuer(uint256 const& id) } } // namespace nft -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/nftPageMask.h b/include/xrpl/protocol/nftPageMask.h index 90fff10d95..05a42ce294 100644 --- a/include/xrpl/protocol/nftPageMask.h +++ b/include/xrpl/protocol/nftPageMask.h @@ -1,38 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_NFT_PAGE_MASK_H_INCLUDED -#define RIPPLE_PROTOCOL_NFT_PAGE_MASK_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace nft { // NFT directory pages order their contents based only on the low 96 bits of // the NFToken value. This mask provides easy access to the necessary mask. -uint256 constexpr pageMask(std::string_view( - "0000000000000000000000000000000000000000ffffffffffffffffffffffff")); +uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff")); } // namespace nft -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/serialize.h b/include/xrpl/protocol/serialize.h index 6d171c5e86..5b84a28b5d 100644 --- a/include/xrpl/protocol/serialize.h +++ b/include/xrpl/protocol/serialize.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_SERIALIZE_H_INCLUDED -#define RIPPLE_PROTOCOL_SERIALIZE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Serialize an object to a blob. */ template @@ -43,6 +23,4 @@ serializeHex(STObject const& o) return strHex(serializeBlob(o)); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/protocol/st.h b/include/xrpl/protocol/st.h index 0035deaa1b..61571196f2 100644 --- a/include/xrpl/protocol/st.h +++ b/include/xrpl/protocol/st.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_ST_H_INCLUDED -#define RIPPLE_PROTOCOL_ST_H_INCLUDED +#pragma once #include #include @@ -36,5 +16,3 @@ #include #include #include - -#endif diff --git a/include/xrpl/protocol/tokens.h b/include/xrpl/protocol/tokens.h index f0c4e79d43..8cda8efc86 100644 --- a/include/xrpl/protocol/tokens.h +++ b/include/xrpl/protocol/tokens.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PROTOCOL_TOKENS_H_INCLUDED -#define RIPPLE_PROTOCOL_TOKENS_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { template using B58Result = Expected; @@ -82,11 +62,7 @@ decodeBase58Token(std::string const& s, TokenType type); namespace detail { // Expose detail functions for unit tests only std::string -encodeBase58( - void const* message, - std::size_t size, - void* temp, - std::size_t temp_size); +encodeBase58(void const* message, std::size_t size, void* temp, std::size_t temp_size); std::string decodeBase58(std::string const& s); @@ -98,16 +74,10 @@ namespace b58_fast { // Use the fast version (10-15x faster) is using gcc extensions (int128 in // particular) [[nodiscard]] B58Result> -encodeBase58Token( - TokenType token_type, - std::span input, - std::span out); +encodeBase58Token(TokenType token_type, std::span input, std::span out); [[nodiscard]] B58Result> -decodeBase58Token( - TokenType type, - std::string_view s, - std::span outBuf); +decodeBase58Token(TokenType type, std::string_view s, std::span outBuf); // This interface matches the old interface, but requires additional allocation [[nodiscard]] std::string @@ -120,9 +90,7 @@ decodeBase58Token(std::string const& s, TokenType type); namespace detail { // Expose detail functions for unit tests only B58Result> -b256_to_b58_be( - std::span input, - std::span out); +b256_to_b58_be(std::span input, std::span out); B58Result> b58_to_b256_be(std::string_view input, std::span out); @@ -130,6 +98,4 @@ b58_to_b256_be(std::string_view input, std::span out); } // namespace b58_fast #endif // _MSC_VER -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/DBInit.h b/include/xrpl/rdb/DBInit.h similarity index 79% rename from src/xrpld/app/main/DBInit.h rename to include/xrpl/rdb/DBInit.h index 192b1bedae..56bc752343 100644 --- a/src/xrpld/app/main/DBInit.h +++ b/include/xrpl/rdb/DBInit.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_DATA_DBINIT_H_INCLUDED -#define RIPPLE_APP_DATA_DBINIT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { //////////////////////////////////////////////////////////////////////////////// @@ -135,6 +115,4 @@ inline constexpr std::array WalletDBInit{ "END TRANSACTION;"}}; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/core/DatabaseCon.h b/include/xrpl/rdb/DatabaseCon.h similarity index 72% rename from src/xrpld/core/DatabaseCon.h rename to include/xrpl/rdb/DatabaseCon.h index 299861e1b0..37a53044e4 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/include/xrpl/rdb/DatabaseCon.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_DATA_DATABASECON_H_INCLUDED -#define RIPPLE_APP_DATA_DATABASECON_H_INCLUDED - -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -35,7 +15,7 @@ namespace soci { class session; } -namespace ripple { +namespace xrpl { class LockedSociSession { @@ -47,12 +27,10 @@ private: std::unique_lock lock_; public: - LockedSociSession(std::shared_ptr it, mutex& m) - : session_(std::move(it)), lock_(m) + LockedSociSession(std::shared_ptr it, mutex& m) : session_(std::move(it)), lock_(m) { } - LockedSociSession(LockedSociSession&& rhs) noexcept - : session_(std::move(rhs.session_)), lock_(std::move(rhs.lock_)) + LockedSociSession(LockedSociSession&& rhs) noexcept : session_(std::move(rhs.session_)), lock_(std::move(rhs.lock_)) { } LockedSociSession() = delete; @@ -89,7 +67,7 @@ public: { explicit Setup() = default; - Config::StartUpType startUp = Config::NORMAL; + StartUpType startUp = StartUpType::NORMAL; bool standAlone = false; boost::filesystem::path dataDir; // Indicates whether or not to return the `globalPragma` @@ -101,10 +79,9 @@ public: { XRPL_ASSERT( !useGlobalPragma || globalPragma, - "ripple::DatabaseCon::Setup::commonPragma : consistent global " + "xrpl::DatabaseCon::Setup::commonPragma : consistent global " "pragma"); - return useGlobalPragma && globalPragma ? globalPragma.get() - : nullptr; + return useGlobalPragma && globalPragma ? globalPragma.get() : nullptr; } static std::unique_ptr const> globalPragma; @@ -127,9 +104,8 @@ public: beast::Journal journal) // Use temporary files or regular DB files? : DatabaseCon( - setup.standAlone && setup.startUp != Config::LOAD && - setup.startUp != Config::LOAD_FILE && - setup.startUp != Config::REPLAY + setup.standAlone && setup.startUp != StartUpType::LOAD && setup.startUp != StartUpType::LOAD_FILE && + setup.startUp != StartUpType::REPLAY ? "" : (setup.dataDir / dbName), setup.commonPragma(), @@ -190,11 +166,8 @@ public: checkoutDb() { using namespace std::chrono_literals; - LockedSociSession session = perf::measureDurationAndLog( - [&]() { return LockedSociSession(session_, lock_); }, - "checkoutDb", - 10ms, - j_); + LockedSociSession session = + perf::measureDurationAndLog([&]() { return LockedSociSession(session_, lock_); }, "checkoutDb", 10ms, j_); return session; } @@ -255,11 +228,4 @@ private: std::shared_ptr checkpointerFromId(std::uintptr_t id); -DatabaseCon::Setup -setup_DatabaseCon( - Config const& c, - std::optional j = std::nullopt); - -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/rdb/RelationalDatabase.h b/include/xrpl/rdb/RelationalDatabase.h new file mode 100644 index 0000000000..b80c6c8331 --- /dev/null +++ b/include/xrpl/rdb/RelationalDatabase.h @@ -0,0 +1,475 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl { + +class Transaction; +class Ledger; + +struct LedgerHashPair +{ + uint256 ledgerHash; + uint256 parentHash; +}; + +struct LedgerRange +{ + uint32_t min; + uint32_t max; +}; + +class RelationalDatabase +{ +public: + struct CountMinMax + { + std::size_t numberOfRows; + LedgerIndex minLedgerSequence; + LedgerIndex maxLedgerSequence; + }; + + struct AccountTxMarker + { + std::uint32_t ledgerSeq = 0; + std::uint32_t txnSeq = 0; + }; + + struct AccountTxOptions + { + AccountID const& account; + std::uint32_t minLedger; + std::uint32_t maxLedger; + std::uint32_t offset; + std::uint32_t limit; + bool bUnlimited; + }; + + struct AccountTxPageOptions + { + AccountID const& account; + std::uint32_t minLedger; + std::uint32_t maxLedger; + std::optional marker; + std::uint32_t limit; + bool bAdmin; + }; + + using AccountTx = std::pair, std::shared_ptr>; + using AccountTxs = std::vector; + using txnMetaLedgerType = std::tuple; + using MetaTxsList = std::vector; + + using LedgerSequence = uint32_t; + using LedgerHash = uint256; + using LedgerSpecifier = std::variant; + + struct AccountTxArgs + { + AccountID account; + std::optional ledger; + bool binary = false; + bool forward = false; + uint32_t limit = 0; + std::optional marker; + }; + + struct AccountTxResult + { + std::variant transactions; + LedgerRange ledgerRange; + uint32_t limit; + std::optional marker; + }; + + virtual ~RelationalDatabase() = default; + + /** + * @brief getMinLedgerSeq Returns the minimum ledger sequence in the Ledgers + * table. + * @return Ledger sequence or no value if no ledgers exist. + */ + virtual std::optional + getMinLedgerSeq() = 0; + + /** + * @brief getMaxLedgerSeq Returns the maximum ledger sequence in the Ledgers + * table. + * @return Ledger sequence or none if no ledgers exist. + */ + virtual std::optional + getMaxLedgerSeq() = 0; + + /** + * @brief getLedgerInfoByIndex Returns a ledger by its sequence. + * @param ledgerSeq Ledger sequence. + * @return The ledger if found, otherwise no value. + */ + virtual std::optional + getLedgerInfoByIndex(LedgerIndex ledgerSeq) = 0; + + /** + * @brief getNewestLedgerInfo Returns the info of the newest saved ledger. + * @return Ledger info if found, otherwise no value. + */ + virtual std::optional + getNewestLedgerInfo() = 0; + + /** + * @brief getLedgerInfoByHash Returns the info of the ledger with given + * hash. + * @param ledgerHash Hash of the ledger. + * @return Ledger if found, otherwise no value. + */ + virtual std::optional + getLedgerInfoByHash(uint256 const& ledgerHash) = 0; + + /** + * @brief getHashByIndex Returns the hash of the ledger with the given + * sequence. + * @param ledgerIndex Ledger sequence. + * @return Hash of the ledger. + */ + virtual uint256 + getHashByIndex(LedgerIndex ledgerIndex) = 0; + + /** + * @brief getHashesByIndex Returns the hashes of the ledger and its parent + * as specified by the ledgerIndex. + * @param ledgerIndex Ledger sequence. + * @return Struct LedgerHashPair which contains hashes of the ledger and + * its parent. + */ + virtual std::optional + getHashesByIndex(LedgerIndex ledgerIndex) = 0; + + /** + * @brief getHashesByIndex Returns hashes of each ledger and its parent for + * all ledgers within the provided range. + * @param minSeq Minimum ledger sequence. + * @param maxSeq Maximum ledger sequence. + * @return Container that maps the sequence number of a found ledger to the + * struct LedgerHashPair which contains the hashes of the ledger and + * its parent. + */ + virtual std::map + getHashesByIndex(LedgerIndex minSeq, LedgerIndex maxSeq) = 0; + + /** + * @brief getTxHistory Returns the 20 most recent transactions starting from + * the given number. + * @param startIndex First number of returned entry. + * @return Vector of shared pointers to transactions sorted in + * descending order by ledger sequence. + */ + virtual std::vector> + getTxHistory(LedgerIndex startIndex) = 0; + + /** + * @brief getTransactionsMinLedgerSeq Returns the minimum ledger sequence + * stored in the Transactions table. + * @return Ledger sequence or no value if no ledgers exist. + */ + virtual std::optional + getTransactionsMinLedgerSeq() = 0; + + /** + * @brief getAccountTransactionsMinLedgerSeq Returns the minimum ledger + * sequence stored in the AccountTransactions table. + * @return Ledger sequence or no value if no ledgers exist. + */ + virtual std::optional + getAccountTransactionsMinLedgerSeq() = 0; + + /** + * @brief deleteTransactionByLedgerSeq Deletes transactions from the ledger + * with the given sequence. + * @param ledgerSeq Ledger sequence. + */ + virtual void + deleteTransactionByLedgerSeq(LedgerIndex ledgerSeq) = 0; + + /** + * @brief deleteBeforeLedgerSeq Deletes all ledgers with a sequence number + * less than or equal to the given ledger sequence. + * @param ledgerSeq Ledger sequence. + */ + virtual void + deleteBeforeLedgerSeq(LedgerIndex ledgerSeq) = 0; + + /** + * @brief deleteTransactionsBeforeLedgerSeq Deletes all transactions with + * a sequence number less than or equal to the given ledger + * sequence. + * @param ledgerSeq Ledger sequence. + */ + virtual void + deleteTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) = 0; + + /** + * @brief deleteAccountTransactionsBeforeLedgerSeq Deletes all account + * transactions with a sequence number less than or equal to the + * given ledger sequence. + * @param ledgerSeq Ledger sequence. + */ + virtual void + deleteAccountTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) = 0; + + /** + * @brief getTransactionCount Returns the number of transactions. + * @return Number of transactions. + */ + virtual std::size_t + getTransactionCount() = 0; + + /** + * @brief getAccountTransactionCount Returns the number of account + * transactions. + * @return Number of account transactions. + */ + virtual std::size_t + getAccountTransactionCount() = 0; + + /** + * @brief getLedgerCountMinMax Returns the minimum ledger sequence, + * maximum ledger sequence and total number of saved ledgers. + * @return Struct CountMinMax which contains the minimum sequence, + * maximum sequence and number of ledgers. + */ + virtual struct CountMinMax + getLedgerCountMinMax() = 0; + + /** + * @brief saveValidatedLedger Saves a ledger into the database. + * @param ledger The ledger. + * @param current True if the ledger is current. + * @return True if saving was successful. + */ + virtual bool + saveValidatedLedger(std::shared_ptr const& ledger, bool current) = 0; + + /** + * @brief getLimitedOldestLedgerInfo Returns the info of the oldest ledger + * whose sequence number is greater than or equal to the given + * sequence number. + * @param ledgerFirstIndex Minimum ledger sequence. + * @return Ledger info if found, otherwise no value. + */ + virtual std::optional + getLimitedOldestLedgerInfo(LedgerIndex ledgerFirstIndex) = 0; + + /** + * @brief getLimitedNewestLedgerInfo Returns the info of the newest ledger + * whose sequence number is greater than or equal to the given + * sequence number. + * @param ledgerFirstIndex Minimum ledger sequence. + * @return Ledger info if found, otherwise no value. + */ + virtual std::optional + getLimitedNewestLedgerInfo(LedgerIndex ledgerFirstIndex) = 0; + + /** + * @brief getOldestAccountTxs Returns the oldest transactions for the + * account that matches the given criteria starting from the provided + * offset. + * @param options Struct AccountTxOptions which contains the criteria to + * match: the account, ledger search range, the offset of the first + * entry to return, the number of transactions to return, a flag if + * this number is unlimited. + * @return Vector of pairs of found transactions and their metadata + * sorted in ascending order by account sequence. + */ + virtual AccountTxs + getOldestAccountTxs(AccountTxOptions const& options) = 0; + + /** + * @brief getNewestAccountTxs Returns the newest transactions for the + * account that matches the given criteria starting from the provided + * offset. + * @param options Struct AccountTxOptions which contains the criteria to + * match: the account, the ledger search range, the offset of the + * first entry to return, the number of transactions to return, a + * flag if this number unlimited. + * @return Vector of pairs of found transactions and their metadata + * sorted in descending order by account sequence. + */ + virtual AccountTxs + getNewestAccountTxs(AccountTxOptions const& options) = 0; + + /** + * @brief getOldestAccountTxsB Returns the oldest transactions in binary + * form for the account that matches the given criteria starting from + * the provided offset. + * @param options Struct AccountTxOptions which contains the criteria to + * match: the account, the ledger search range, the offset of the + * first entry to return, the number of transactions to return, a + * flag if this number unlimited. + * @return Vector of tuples of found transactions, their metadata and + * account sequences sorted in ascending order by account sequence. + */ + virtual MetaTxsList + getOldestAccountTxsB(AccountTxOptions const& options) = 0; + + /** + * @brief getNewestAccountTxsB Returns the newest transactions in binary + * form for the account that matches the given criteria starting from + * the provided offset. + * @param options Struct AccountTxOptions which contains the criteria to + * match: the account, the ledger search range, the offset of the + * first entry to return, the number of transactions to return, a + * flag if this number is unlimited. + * @return Vector of tuples of found transactions, their metadata and + * account sequences sorted in descending order by account + * sequence. + */ + virtual MetaTxsList + getNewestAccountTxsB(AccountTxOptions const& options) = 0; + + /** + * @brief oldestAccountTxPage Returns the oldest transactions for the + * account that matches the given criteria starting from the + * provided marker. + * @param options Struct AccountTxPageOptions which contains the criteria to + * match: the account, the ledger search range, the marker of first + * returned entry, the number of transactions to return, a flag if + * this number is unlimited. + * @return Vector of pairs of found transactions and their metadata + * sorted in ascending order by account sequence and a marker + * for the next search if the search was not finished. + */ + virtual std::pair> + oldestAccountTxPage(AccountTxPageOptions const& options) = 0; + + /** + * @brief newestAccountTxPage Returns the newest transactions for the + * account that matches the given criteria starting from the provided + * marker. + * @param options Struct AccountTxPageOptions which contains the criteria to + * match: the account, the ledger search range, the marker of the + * first returned entry, the number of transactions to return, a flag + * if this number unlimited. + * @return Vector of pairs of found transactions and their metadata + * sorted in descending order by account sequence and a marker + * for the next search if the search was not finished. + */ + virtual std::pair> + newestAccountTxPage(AccountTxPageOptions const& options) = 0; + + /** + * @brief oldestAccountTxPageB Returns the oldest transactions in binary + * form for the account that matches the given criteria starting from + * the provided marker. + * @param options Struct AccountTxPageOptions which contains criteria to + * match: the account, the ledger search range, the marker of the + * first returned entry, the number of transactions to return, a flag + * if this number unlimited. + * @return Vector of tuples of found transactions, their metadata and + * account sequences sorted in ascending order by account + * sequence and a marker for the next search if the search was not + * finished. + */ + virtual std::pair> + oldestAccountTxPageB(AccountTxPageOptions const& options) = 0; + + /** + * @brief newestAccountTxPageB Returns the newest transactions in binary + * form for the account that matches the given criteria starting from + * the provided marker. + * @param options Struct AccountTxPageOptions which contains the criteria to + * match: the account, the ledger search range, the marker of the + * first returned entry, the number of transactions to return, a flag + * if this number is unlimited. + * @return Vector of tuples of found transactions, their metadata and + * account sequences sorted in descending order by account + * sequence and a marker for the next search if the search was not + * finished. + */ + virtual std::pair> + newestAccountTxPageB(AccountTxPageOptions const& options) = 0; + + /** + * @brief getTransaction Returns the transaction with the given hash. If a + * range is provided but the transaction is not found, then check if + * all ledgers in the range are present in the database. + * @param id Hash of the transaction. + * @param range Range of ledgers to check, if present. + * @param ec Default error code value. + * @return Transaction and its metadata if found, otherwise TxSearched::all + * if a range is provided and all ledgers from the range are present + * in the database, TxSearched::some if a range is provided and not + * all ledgers are present, TxSearched::unknown if the range is not + * provided or a deserializing error occurred. In the last case the + * error code is returned via the ec parameter, in other cases the + * default error code is not changed. + */ + virtual std::variant + getTransaction(uint256 const& id, std::optional> const& range, error_code_i& ec) = 0; + + /** + * @brief getKBUsedAll Returns the amount of space used by all databases. + * @return Space in kilobytes. + */ + virtual uint32_t + getKBUsedAll() = 0; + + /** + * @brief getKBUsedLedger Returns the amount of space space used by the + * ledger database. + * @return Space in kilobytes. + */ + virtual uint32_t + getKBUsedLedger() = 0; + + /** + * @brief getKBUsedTransaction Returns the amount of space used by the + * transaction database. + * @return Space in kilobytes. + */ + virtual uint32_t + getKBUsedTransaction() = 0; + + /** + * @brief Closes the ledger database + */ + virtual void + closeLedgerDB() = 0; + + /** + * @brief Closes the transaction database + */ + virtual void + closeTransactionDB() = 0; +}; + +template +T +rangeCheckedCast(C c) +{ + if ((c > std::numeric_limits::max()) || (!std::numeric_limits::is_signed && c < 0) || + (std::numeric_limits::is_signed && std::numeric_limits::is_signed && + c < std::numeric_limits::lowest())) + { + // This should never happen + // LCOV_EXCL_START + UNREACHABLE("xrpl::rangeCheckedCast : domain error"); + JLOG(debugLog().error()) << "rangeCheckedCast domain error:" + << " value = " << c << " min = " << std::numeric_limits::lowest() + << " max: " << std::numeric_limits::max(); + // LCOV_EXCL_STOP + } + + return static_cast(c); +} + +} // namespace xrpl diff --git a/src/xrpld/core/SociDB.h b/include/xrpl/rdb/SociDB.h similarity index 65% rename from src/xrpld/core/SociDB.h rename to include/xrpl/rdb/SociDB.h index a741504e97..acfc183076 100644 --- a/src/xrpld/core/SociDB.h +++ b/include/xrpl/rdb/SociDB.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SOCIDB_H_INCLUDED -#define RIPPLE_SOCIDB_H_INCLUDED +#pragma once /** An embedded database wrapper with an intuitive, type-safe interface. @@ -33,9 +13,8 @@ #pragma clang diagnostic ignored "-Wdeprecated" #endif -#include - #include +#include #define SOCI_USE_BOOST #include @@ -48,7 +27,7 @@ namespace sqlite_api { struct sqlite3; } -namespace ripple { +namespace xrpl { class BasicConfig; @@ -95,10 +74,7 @@ open(soci::session& s, BasicConfig const& config, std::string const& dbName); * */ void -open( - soci::session& s, - std::string const& beName, - std::string const& connectionString); +open(soci::session& s, std::string const& beName, std::string const& connectionString); std::uint32_t getKBUsedAll(soci::session& s); @@ -135,16 +111,10 @@ public: and so must outlive them both. */ std::shared_ptr -makeCheckpointer( - std::uintptr_t id, - std::weak_ptr, - JobQueue&, - Logs&); +makeCheckpointer(std::uintptr_t id, std::weak_ptr, JobQueue&, Logs&); -} // namespace ripple +} // namespace xrpl #if defined(__clang__) #pragma clang diagnostic pop #endif - -#endif diff --git a/include/xrpl/resource/Charge.h b/include/xrpl/resource/Charge.h index ead46ca31f..55b13731b9 100644 --- a/include/xrpl/resource/Charge.h +++ b/include/xrpl/resource/Charge.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_CHARGE_H_INCLUDED -#define RIPPLE_RESOURCE_CHARGE_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace Resource { /** A consumption charge. */ @@ -68,6 +48,4 @@ std::ostream& operator<<(std::ostream& os, Charge const& v); } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/Consumer.h b/include/xrpl/resource/Consumer.h index cf6c25a205..45cc221212 100644 --- a/include/xrpl/resource/Consumer.h +++ b/include/xrpl/resource/Consumer.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_CONSUMER_H_INCLUDED -#define RIPPLE_RESOURCE_CONSUMER_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { namespace Resource { struct Entry; @@ -100,6 +80,4 @@ std::ostream& operator<<(std::ostream& os, Consumer const& v); } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/Disposition.h b/include/xrpl/resource/Disposition.h index 4b3c596986..096afb6a6f 100644 --- a/include/xrpl/resource/Disposition.h +++ b/include/xrpl/resource/Disposition.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED -#define RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace Resource { /** The disposition of a consumer after applying a load charge. */ @@ -38,6 +18,4 @@ enum Disposition { }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/Fees.h b/include/xrpl/resource/Fees.h index f85e7c8cd2..0ba083d4fe 100644 --- a/include/xrpl/resource/Fees.h +++ b/include/xrpl/resource/Fees.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_FEES_H_INCLUDED -#define RIPPLE_RESOURCE_FEES_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace Resource { // clang-format off @@ -59,6 +39,4 @@ extern Charge const feeDrop; // The cost of being dropped for // clang-format on } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/Gossip.h b/include/xrpl/resource/Gossip.h index 3495de5b95..e581145149 100644 --- a/include/xrpl/resource/Gossip.h +++ b/include/xrpl/resource/Gossip.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_GOSSIP_H_INCLUDED -#define RIPPLE_RESOURCE_GOSSIP_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace Resource { /** Data format for exchanging consumption information across peers. */ @@ -45,6 +25,4 @@ struct Gossip }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/README.md b/include/xrpl/resource/README.md index 253e3c7625..e525ce83e3 100644 --- a/include/xrpl/resource/README.md +++ b/include/xrpl/resource/README.md @@ -66,7 +66,7 @@ values over time: this is implemented by the DecayingSample class. Each server in a cluster creates a list of IP addresses of end points that are imposing a significant load. This list is called Gossip, which is passed to other nodes in that cluster. Gossip helps individual -servers in the cluster identify IP addreses that might be unduly loading +servers in the cluster identify IP addresses that might be unduly loading the entire cluster. Again the recourse of the individual servers is to drop connections to those IP addresses that occur commonly in the gossip. diff --git a/include/xrpl/resource/ResourceManager.h b/include/xrpl/resource/ResourceManager.h index 22697d12eb..c04e7bb79b 100644 --- a/include/xrpl/resource/ResourceManager.h +++ b/include/xrpl/resource/ResourceManager.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_MANAGER_H_INCLUDED -#define RIPPLE_RESOURCE_MANAGER_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include -namespace ripple { +namespace xrpl { namespace Resource { /** Tracks load and resource consumption. */ @@ -47,10 +27,7 @@ public: virtual Consumer newInboundEndpoint(beast::IP::Endpoint const& address) = 0; virtual Consumer - newInboundEndpoint( - beast::IP::Endpoint const& address, - bool const proxy, - std::string_view forwardedFor) = 0; + newInboundEndpoint(beast::IP::Endpoint const& address, bool const proxy, std::string_view forwardedFor) = 0; /** Create a new endpoint keyed by outbound IP address and port. */ virtual Consumer @@ -80,11 +57,7 @@ public: //------------------------------------------------------------------------------ std::unique_ptr -make_Manager( - beast::insight::Collector::ptr const& collector, - beast::Journal journal); +make_Manager(beast::insight::Collector::ptr const& collector, beast::Journal journal); } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/Types.h b/include/xrpl/resource/Types.h index c2061007a4..fb71cffe37 100644 --- a/include/xrpl/resource/Types.h +++ b/include/xrpl/resource/Types.h @@ -1,32 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_TYPES_H_INCLUDED -#define RIPPLE_RESOURCE_TYPES_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace Resource { struct Key; struct Entry; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Entry.h b/include/xrpl/resource/detail/Entry.h index a8002611ce..ecff8828af 100644 --- a/include/xrpl/resource/detail/Entry.h +++ b/include/xrpl/resource/detail/Entry.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_ENTRY_H_INCLUDED -#define RIPPLE_RESOURCE_ENTRY_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace Resource { using clock_type = beast::abstract_clock; @@ -42,11 +22,7 @@ struct Entry : public beast::List::Node @param now Construction time of Entry. */ explicit Entry(clock_type::time_point const now) - : refcount(0) - , local_balance(now) - , remote_balance(0) - , lastWarningTime() - , whenExpires() + : refcount(0), local_balance(now), remote_balance(0), lastWarningTime(), whenExpires() { } @@ -112,6 +88,4 @@ operator<<(std::ostream& os, Entry const& v) } } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Import.h b/include/xrpl/resource/detail/Import.h index 5231564496..790fc0596a 100644 --- a/include/xrpl/resource/detail/Import.h +++ b/include/xrpl/resource/detail/Import.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_IMPORT_H_INCLUDED -#define RIPPLE_RESOURCE_IMPORT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace Resource { /** A set of imported consumer data from a gossip origin. */ @@ -50,6 +30,4 @@ struct Import }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Key.h b/include/xrpl/resource/detail/Key.h index 188ee142da..0c5164a7d8 100644 --- a/include/xrpl/resource/detail/Key.h +++ b/include/xrpl/resource/detail/Key.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_KEY_H_INCLUDED -#define RIPPLE_RESOURCE_KEY_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace Resource { // The consumer key @@ -66,6 +46,4 @@ struct Key }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Kind.h b/include/xrpl/resource/detail/Kind.h index e9b819c3b5..fbb6b65e25 100644 --- a/include/xrpl/resource/detail/Kind.h +++ b/include/xrpl/resource/detail/Kind.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_KIND_H_INCLUDED -#define RIPPLE_RESOURCE_KIND_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace Resource { /** @@ -34,6 +14,4 @@ namespace Resource { enum Kind { kindInbound, kindOutbound, kindUnlimited }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Logic.h b/include/xrpl/resource/detail/Logic.h index 0fc5a9035a..066e416550 100644 --- a/include/xrpl/resource/detail/Logic.h +++ b/include/xrpl/resource/detail/Logic.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_LOGIC_H_INCLUDED -#define RIPPLE_RESOURCE_LOGIC_H_INCLUDED +#pragma once #include #include @@ -35,7 +15,7 @@ #include -namespace ripple { +namespace xrpl { namespace Resource { class Logic @@ -80,7 +60,7 @@ private: // List of all active admin entries EntryIntrusiveList admin_; - // List of all inactve entries + // List of all inactive entries EntryIntrusiveList inactive_; // All imported gossip data @@ -88,10 +68,7 @@ private: //-------------------------------------------------------------------------- public: - Logic( - beast::insight::Collector::ptr const& collector, - clock_type& clock, - beast::Journal journal) + Logic(beast::insight::Collector::ptr const& collector, clock_type& clock, beast::Journal journal) : m_stats(collector), m_clock(clock), m_journal(journal) { } @@ -218,8 +195,7 @@ public: int localBalance = inboundEntry.local_balance.value(now); if ((localBalance + inboundEntry.remote_balance) >= threshold) { - Json::Value& entry = - (ret[inboundEntry.to_string()] = Json::objectValue); + Json::Value& entry = (ret[inboundEntry.to_string()] = Json::objectValue); entry[jss::local] = localBalance; entry[jss::remote] = inboundEntry.remote_balance; entry[jss::type] = "inbound"; @@ -230,8 +206,7 @@ public: int localBalance = outboundEntry.local_balance.value(now); if ((localBalance + outboundEntry.remote_balance) >= threshold) { - Json::Value& entry = - (ret[outboundEntry.to_string()] = Json::objectValue); + Json::Value& entry = (ret[outboundEntry.to_string()] = Json::objectValue); entry[jss::local] = localBalance; entry[jss::remote] = outboundEntry.remote_balance; entry[jss::type] = "outbound"; @@ -242,8 +217,7 @@ public: int localBalance = adminEntry.local_balance.value(now); if ((localBalance + adminEntry.remote_balance) >= threshold) { - Json::Value& entry = - (ret[adminEntry.to_string()] = Json::objectValue); + Json::Value& entry = (ret[adminEntry.to_string()] = Json::objectValue); entry[jss::local] = localBalance; entry[jss::remote] = adminEntry.remote_balance; entry[jss::type] = "admin"; @@ -287,9 +261,8 @@ public: std::lock_guard _(lock_); auto [resultIt, resultInserted] = importTable_.emplace( std::piecewise_construct, - std::make_tuple(origin), // Key - std::make_tuple( - m_clock.now().time_since_epoch().count())); // Import + std::make_tuple(origin), // Key + std::make_tuple(m_clock.now().time_since_epoch().count())); // Import if (resultInserted) { @@ -367,12 +340,9 @@ public: Import& import(iter->second); if (iter->second.whenExpires <= elapsed) { - for (auto item_iter(import.items.begin()); - item_iter != import.items.end(); - ++item_iter) + for (auto item_iter(import.items.begin()); item_iter != import.items.end(); ++item_iter) { - item_iter->consumer.entry().remote_balance -= - item_iter->balance; + item_iter->consumer.entry().remote_balance -= item_iter->balance; } iter = importTable_.erase(iter); @@ -402,9 +372,7 @@ public: { std::lock_guard _(lock_); Entry& entry(iter->second); - XRPL_ASSERT( - entry.refcount == 0, - "ripple::Resource::Logic::erase : entry not used"); + XRPL_ASSERT(entry.refcount == 0, "xrpl::Resource::Logic::erase : entry not used"); inactive_.erase(inactive_.iterator_to(entry)); table_.erase(iter); } @@ -438,7 +406,7 @@ public: default: // LCOV_EXCL_START UNREACHABLE( - "ripple::Resource::Logic::release : invalid entry " + "xrpl::Resource::Logic::release : invalid entry " "kind"); break; // LCOV_EXCL_STOP @@ -454,12 +422,9 @@ public: static constexpr Charge::value_type feeLogAsWarn = 3000; static constexpr Charge::value_type feeLogAsInfo = 1000; static constexpr Charge::value_type feeLogAsDebug = 100; - static_assert( - feeLogAsWarn > feeLogAsInfo && feeLogAsInfo > feeLogAsDebug && - feeLogAsDebug > 10); + static_assert(feeLogAsWarn > feeLogAsInfo && feeLogAsInfo > feeLogAsDebug && feeLogAsDebug > 10); - static auto getStream = [](Resource::Charge::value_type cost, - beast::Journal& journal) { + static auto getStream = [](Resource::Charge::value_type cost, beast::Journal& journal) { if (cost >= feeLogAsWarn) return journal.warn(); if (cost >= feeLogAsInfo) @@ -475,8 +440,7 @@ public: std::lock_guard _(lock_); clock_type::time_point const now(m_clock.now()); int const balance(entry.add(fee.cost(), now)); - JLOG(getStream(fee.cost(), m_journal)) - << "Charging " << entry << " for " << fee << context; + JLOG(getStream(fee.cost(), m_journal)) << "Charging " << entry << " for " << fee << context; return disposition(balance); } @@ -489,8 +453,7 @@ public: std::lock_guard _(lock_); bool notify(false); auto const elapsed = m_clock.now(); - if (entry.balance(m_clock.now()) >= warningThreshold && - elapsed != entry.lastWarningTime) + if (entry.balance(m_clock.now()) >= warningThreshold && elapsed != entry.lastWarningTime) { charge(entry, feeWarning); notify = true; @@ -516,9 +479,8 @@ public: int const balance(entry.balance(now)); if (balance >= dropThreshold) { - JLOG(m_journal.warn()) - << "Consumer entry " << entry << " dropped with balance " - << balance << " at or above drop threshold " << dropThreshold; + JLOG(m_journal.warn()) << "Consumer entry " << entry << " dropped with balance " << balance + << " at or above drop threshold " << dropThreshold; // Adding feeDrop at this point keeps the dropped connection // from re-connecting for at least a little while after it is @@ -540,10 +502,7 @@ public: //-------------------------------------------------------------------------- void - writeList( - clock_type::time_point const now, - beast::PropertyStream::Set& items, - EntryIntrusiveList& list) + writeList(clock_type::time_point const now, beast::PropertyStream::Set& items, EntryIntrusiveList& list) { for (auto& entry : list) { @@ -587,6 +546,4 @@ public: }; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/resource/detail/Tuning.h b/include/xrpl/resource/detail/Tuning.h index 62234c3569..d5be5cf0b6 100644 --- a/include/xrpl/resource/detail/Tuning.h +++ b/include/xrpl/resource/detail/Tuning.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_TUNING_H_INCLUDED -#define RIPPLE_RESOURCE_TUNING_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace Resource { /** Tunable constants. */ @@ -51,6 +31,4 @@ std::chrono::seconds constexpr secondsUntilExpiration{300}; std::chrono::seconds constexpr gossipExpirationSeconds{30}; } // namespace Resource -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Handoff.h b/include/xrpl/server/Handoff.h index d33e8a7edd..60ed16def4 100644 --- a/include/xrpl/server/Handoff.h +++ b/include/xrpl/server/Handoff.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_HANDOFF_H_INCLUDED -#define RIPPLE_SERVER_HANDOFF_H_INCLUDED +#pragma once #include @@ -27,13 +7,11 @@ #include -namespace ripple { +namespace xrpl { -using http_request_type = - boost::beast::http::request; +using http_request_type = boost::beast::http::request; -using http_response_type = - boost::beast::http::response; +using http_response_type = boost::beast::http::response; /** Used to indicate the result of a server connection handoff. */ struct Handoff @@ -55,6 +33,4 @@ struct Handoff } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/Manifest.h b/include/xrpl/server/Manifest.h similarity index 84% rename from src/xrpld/app/misc/Manifest.h rename to include/xrpl/server/Manifest.h index 1b53fda77b..79426a1a46 100644 --- a/src/xrpld/app/misc/Manifest.h +++ b/include/xrpl/server/Manifest.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_MANIFEST_H_INCLUDED -#define RIPPLE_APP_MISC_MANIFEST_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /* Validator key manifests @@ -105,11 +85,7 @@ struct Manifest std::optional const& signingKey_, std::uint32_t seq, std::string const& domain_) - : serialized(serialized_) - , masterKey(masterKey_) - , signingKey(signingKey_) - , sequence(seq) - , domain(domain_) + : serialized(serialized_), masterKey(masterKey_), signingKey(signingKey_), sequence(seq), domain(domain_) { } @@ -165,21 +141,14 @@ std::optional deserializeManifest(Slice s, beast::Journal journal); inline std::optional -deserializeManifest( - std::string const& s, - beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) +deserializeManifest(std::string const& s, beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) { return deserializeManifest(makeSlice(s), journal); } -template < - class T, - class = std::enable_if_t< - std::is_same::value || std::is_same::value>> +template ::value || std::is_same::value>> std::optional -deserializeManifest( - std::vector const& v, - beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) +deserializeManifest(std::vector const& v, beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) { return deserializeManifest(makeSlice(v), journal); } @@ -190,9 +159,8 @@ operator==(Manifest const& lhs, Manifest const& rhs) { // In theory, comparing the two serialized strings should be // sufficient. - return lhs.sequence == rhs.sequence && lhs.masterKey == rhs.masterKey && - lhs.signingKey == rhs.signingKey && lhs.domain == rhs.domain && - lhs.serialized == rhs.serialized; + return lhs.sequence == rhs.sequence && lhs.masterKey == rhs.masterKey && lhs.signingKey == rhs.signingKey && + lhs.domain == rhs.domain && lhs.serialized == rhs.serialized; } inline bool @@ -267,9 +235,7 @@ private: std::atomic seq_{0}; public: - explicit ManifestCache( - beast::Journal j = beast::Journal(beast::Journal::getNullSink())) - : j_(j) + explicit ManifestCache(beast::Journal j = beast::Journal(beast::Journal::getNullSink())) : j_(j) { } @@ -322,7 +288,7 @@ public: std::optional getDomain(PublicKey const& pk) const; - /** Returns mainfest corresponding to a given public key + /** Returns manifest corresponding to a given public key @return manifest corresponding to Master public key if present, otherwise std::nullopt @@ -402,10 +368,7 @@ public: May be called concurrently */ void - save( - DatabaseCon& dbCon, - std::string const& dbTable, - std::function const& isTrusted); + save(DatabaseCon& dbCon, std::string const& dbTable, std::function const& isTrusted); /** Invokes the callback once for every populated manifest. @@ -462,6 +425,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Port.h b/include/xrpl/server/Port.h index 88f824d19f..1dfa93b0a7 100644 --- a/include/xrpl/server/Port.h +++ b/include/xrpl/server/Port.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_PORT_H_INCLUDED -#define RIPPLE_SERVER_PORT_H_INCLUDED +#pragma once #include #include @@ -43,7 +23,7 @@ class context; } // namespace asio } // namespace boost -namespace ripple { +namespace xrpl { /** Configuration information for a Server listening port. */ struct Port @@ -123,6 +103,4 @@ struct ParsedPort void parse_Port(ParsedPort& port, Section const& section, std::ostream& log); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Server.h b/include/xrpl/server/Server.h index a8f9c7f8af..52340ac900 100644 --- a/include/xrpl/server/Server.h +++ b/include/xrpl/server/Server.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SERVER_H_INCLUDED -#define RIPPLE_SERVER_SERVER_H_INCLUDED +#pragma once #include #include @@ -27,19 +7,14 @@ #include -namespace ripple { +namespace xrpl { /** Create the HTTP server using the specified handler. */ template std::unique_ptr -make_Server( - Handler& handler, - boost::asio::io_context& io_context, - beast::Journal journal) +make_Server(Handler& handler, boost::asio::io_context& io_context, beast::Journal journal) { return std::make_unique>(handler, io_context, journal); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Session.h b/include/xrpl/server/Session.h index 586172a5da..37cbf59775 100644 --- a/include/xrpl/server/Session.h +++ b/include/xrpl/server/Session.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SESSION_H_INCLUDED -#define RIPPLE_SERVER_SESSION_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Persistent state information for a connection session. These values are preserved between calls for efficiency. @@ -83,9 +63,7 @@ public: void write(BufferSequence const& buffers) { - for (typename BufferSequence::const_iterator iter(buffers.begin()); - iter != buffers.end(); - ++iter) + for (typename BufferSequence::const_iterator iter(buffers.begin()); iter != buffers.end(); ++iter) { typename BufferSequence::value_type const& buffer(*iter); write(buffer.data(), boost::asio::buffer_size(buffer)); @@ -130,6 +108,4 @@ public: websocketUpgrade() = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/SimpleWriter.h b/include/xrpl/server/SimpleWriter.h index 371d6cbf97..87b94507a4 100644 --- a/include/xrpl/server/SimpleWriter.h +++ b/include/xrpl/server/SimpleWriter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SIMPLEWRITER_H_INCLUDED -#define RIPPLE_SERVER_SIMPLEWRITER_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { /// Deprecated: Writer that serializes a HTTP/1 message class SimpleWriter : public Writer @@ -38,8 +18,7 @@ class SimpleWriter : public Writer public: template - explicit SimpleWriter( - boost::beast::http::message const& msg) + explicit SimpleWriter(boost::beast::http::message const& msg) { boost::beast::ostream(sb_) << msg; } @@ -74,6 +53,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/rdb/State.h b/include/xrpl/server/State.h similarity index 55% rename from src/xrpld/app/rdb/State.h rename to include/xrpl/server/State.h index 595e749f18..48e11869f4 100644 --- a/src/xrpld/app/rdb/State.h +++ b/include/xrpl/server/State.h @@ -1,34 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_RDB_STATE_H_INCLUDED -#define RIPPLE_APP_RDB_STATE_H_INCLUDED - -#include -#include -#include -#include -#include +#include +#include +#include #include -namespace ripple { +namespace xrpl { struct SavedState { @@ -44,10 +22,7 @@ struct SavedState * @param dbName Name of the database. */ void -initStateDB( - soci::session& session, - BasicConfig const& config, - std::string const& dbName); +initStateDB(soci::session& session, BasicConfig const& config, std::string const& dbName); /** * @brief getCanDelete Returns the ledger sequence which can be deleted. @@ -93,6 +68,4 @@ setSavedState(soci::session& session, SavedState const& state); void setLastRotated(soci::session& session, LedgerIndex seq); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Vacuum.h b/include/xrpl/server/Vacuum.h new file mode 100644 index 0000000000..5f80eced87 --- /dev/null +++ b/include/xrpl/server/Vacuum.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace xrpl { + +/** + * @brief doVacuumDB Creates, initialises, and performs cleanup on a database. + * @param setup Path to the database and other opening parameters. + * @param j Journal. + * @return True if the vacuum process completed successfully. + */ +bool +doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j); + +} // namespace xrpl diff --git a/include/xrpl/server/WSSession.h b/include/xrpl/server/WSSession.h index d739afcefb..56105739e9 100644 --- a/include/xrpl/server/WSSession.h +++ b/include/xrpl/server/WSSession.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_WSSESSION_H_INCLUDED -#define RIPPLE_SERVER_WSSESSION_H_INCLUDED +#pragma once #include #include @@ -36,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { class WSMsg { @@ -97,8 +77,7 @@ public: done = true; } auto const pb = boost::beast::buffers_prefix(n_, sb_.data()); - std::vector vb( - std::distance(pb.begin(), pb.end())); + std::vector vb(std::distance(pb.begin(), pb.end())); std::copy(pb.begin(), pb.end(), std::back_inserter(vb)); return {done, vb}; } @@ -144,6 +123,4 @@ struct WSSession complete() = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/rdb/Wallet.h b/include/xrpl/server/Wallet.h similarity index 70% rename from src/xrpld/app/rdb/Wallet.h rename to include/xrpl/server/Wallet.h index 5cbb356520..dcfbada8eb 100644 --- a/src/xrpld/app/rdb/Wallet.h +++ b/include/xrpl/server/Wallet.h @@ -1,31 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. +#include +#include +#include - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_RDB_WALLET_H_INCLUDED -#define RIPPLE_APP_RDB_WALLET_H_INCLUDED - -#include -#include -#include -#include - -namespace ripple { +namespace xrpl { /** * @brief makeWalletDB Opens the wallet database and returns it. @@ -44,10 +23,7 @@ makeWalletDB(DatabaseCon::Setup const& setup, beast::Journal j); * @return Unique pointer to the database descriptor. */ std::unique_ptr -makeTestWalletDB( - DatabaseCon::Setup const& setup, - std::string const& dbname, - beast::Journal j); +makeTestWalletDB(DatabaseCon::Setup const& setup, std::string const& dbname, beast::Journal j); /** * @brief getManifests Loads a manifest from the wallet database and stores it @@ -59,11 +35,7 @@ makeTestWalletDB( * @param j Journal. */ void -getManifests( - soci::session& session, - std::string const& dbTable, - ManifestCache& mCache, - beast::Journal j); +getManifests(soci::session& session, std::string const& dbTable, ManifestCache& mCache, beast::Journal j); /** * @brief saveManifests Saves all given manifests to the database. @@ -123,10 +95,7 @@ getPeerReservationTable(soci::session& session, beast::Journal j); * @param description Description of the node. */ void -insertPeerReservation( - soci::session& session, - PublicKey const& nodeId, - std::string const& description); +insertPeerReservation(soci::session& session, PublicKey const& nodeId, std::string const& description); /** * @brief deletePeerReservation Deletes an entry from the peer reservation @@ -171,12 +140,6 @@ readAmendments( * @param vote Whether to vote in favor of this amendment. */ void -voteAmendment( - soci::session& session, - uint256 const& amendment, - std::string const& name, - AmendmentVote vote); +voteAmendment(soci::session& session, uint256 const& amendment, std::string const& name, AmendmentVote vote); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/Writer.h b/include/xrpl/server/Writer.h index b63a1e89e4..05fea863be 100644 --- a/include/xrpl/server/Writer.h +++ b/include/xrpl/server/Writer.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_WRITER_H_INCLUDED -#define RIPPLE_SERVER_WRITER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class Writer { @@ -56,6 +36,4 @@ public: data() = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index b7f471bdee..ab85cb7c89 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright(c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_BASEHTTPPEER_H_INCLUDED -#define RIPPLE_SERVER_BASEHTTPPEER_H_INCLUDED +#pragma once #include #include @@ -45,7 +25,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Represents an active connection. */ template @@ -68,8 +48,7 @@ protected: struct buffer { - buffer(void const* ptr, std::size_t len) - : data(new char[len]), bytes(len), used(0) + buffer(void const* ptr, std::size_t len) : data(new char[len]), bytes(len), used(0) { memcpy(data.get(), ptr, len); } @@ -151,10 +130,7 @@ protected: on_write(error_code const& ec, std::size_t bytes_transferred); void - do_writer( - std::shared_ptr const& writer, - bool keep_alive, - yield_context do_yield); + do_writer(std::shared_ptr const& writer, bool keep_alive, yield_context do_yield); virtual void do_request() = 0; @@ -222,8 +198,7 @@ BaseHTTPPeer::BaseHTTPPeer( , remote_address_(remote_address) , journal_(journal) { - read_buf_.commit(boost::asio::buffer_copy( - read_buf_.prepare(boost::asio::buffer_size(buffers)), buffers)); + read_buf_.commit(boost::asio::buffer_copy(read_buf_.prepare(boost::asio::buffer_size(buffers)), buffers)); static std::atomic sid; nid_ = ++sid; id_ = std::string("#") + std::to_string(nid_) + " "; @@ -235,8 +210,7 @@ BaseHTTPPeer::~BaseHTTPPeer() { handler_.onClose(session(), ec_); JLOG(journal_.trace()) << id_ << "destroyed: " << request_count_ - << ((request_count_ == 1) ? " request" - : " requests"); + << ((request_count_ == 1) ? " request" : " requests"); } template @@ -244,11 +218,7 @@ void BaseHTTPPeer::close() { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind( - (void(BaseHTTPPeer::*)(void)) & BaseHTTPPeer::close, - impl().shared_from_this())); + return post(strand_, std::bind((void(BaseHTTPPeer::*)(void)) & BaseHTTPPeer::close, impl().shared_from_this())); boost::beast::get_lowest_layer(impl().stream_).close(); } @@ -261,8 +231,7 @@ BaseHTTPPeer::fail(error_code ec, char const* what) if (!ec_ && ec != boost::asio::error::operation_aborted) { ec_ = ec; - JLOG(journal_.trace()) - << id_ << std::string(what) << ": " << ec.message(); + JLOG(journal_.trace()) << id_ << std::string(what) << ": " << ec.message(); boost::beast::get_lowest_layer(impl().stream_).close(); } } @@ -272,9 +241,8 @@ void BaseHTTPPeer::start_timer() { boost::beast::get_lowest_layer(impl().stream_) - .expires_after(std::chrono::seconds( - remote_address_.address().is_loopback() ? timeoutSecondsLocal - : timeoutSeconds)); + .expires_after( + std::chrono::seconds(remote_address_.address().is_loopback() ? timeoutSecondsLocal : timeoutSeconds)); } // Convenience for discarding the error code @@ -290,8 +258,7 @@ template void BaseHTTPPeer::on_timer() { - auto ec = - boost::system::errc::make_error_code(boost::system::errc::timed_out); + auto ec = boost::system::errc::make_error_code(boost::system::errc::timed_out); fail(ec, "timer"); } @@ -304,8 +271,7 @@ BaseHTTPPeer::do_read(yield_context do_yield) complete_ = false; error_code ec; start_timer(); - boost::beast::http::async_read( - impl().stream_, read_buf_, message_, do_yield[ec]); + boost::beast::http::async_read(impl().stream_, read_buf_, message_, do_yield[ec]); cancel_timer(); if (ec == boost::beast::http::error::end_of_stream) return do_close(); @@ -320,9 +286,7 @@ BaseHTTPPeer::do_read(yield_context do_yield) // The write queue must not be empty upon entry. template void -BaseHTTPPeer::on_write( - error_code const& ec, - std::size_t bytes_transferred) +BaseHTTPPeer::on_write(error_code const& ec, std::size_t bytes_transferred) { cancel_timer(); if (ec == boost::beast::error::timeout) @@ -349,29 +313,19 @@ BaseHTTPPeer::on_write( bind_executor( strand_, std::bind( - &BaseHTTPPeer::on_write, - impl().shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + &BaseHTTPPeer::on_write, impl().shared_from_this(), std::placeholders::_1, std::placeholders::_2))); } if (!complete_) return; if (graceful_) return do_close(); util::spawn( - strand_, - std::bind( - &BaseHTTPPeer::do_read, - impl().shared_from_this(), - std::placeholders::_1)); + strand_, std::bind(&BaseHTTPPeer::do_read, impl().shared_from_this(), std::placeholders::_1)); } template void -BaseHTTPPeer::do_writer( - std::shared_ptr const& writer, - bool keep_alive, - yield_context do_yield) +BaseHTTPPeer::do_writer(std::shared_ptr const& writer, bool keep_alive, yield_context do_yield) { std::function resume; { @@ -379,12 +333,7 @@ BaseHTTPPeer::do_writer( resume = std::function([this, p, writer, keep_alive]() { util::spawn( strand_, - std::bind( - &BaseHTTPPeer::do_writer, - p, - writer, - keep_alive, - std::placeholders::_1)); + std::bind(&BaseHTTPPeer::do_writer, p, writer, keep_alive, std::placeholders::_1)); }); } @@ -393,11 +342,8 @@ BaseHTTPPeer::do_writer( if (!writer->prepare(bufferSize, resume)) return; error_code ec; - auto const bytes_transferred = boost::asio::async_write( - impl().stream_, - writer->data(), - boost::asio::transfer_at_least(1), - do_yield[ec]); + auto const bytes_transferred = + boost::asio::async_write(impl().stream_, writer->data(), boost::asio::transfer_at_least(1), do_yield[ec]); if (ec) return fail(ec, "writer"); writer->consume(bytes_transferred); @@ -409,11 +355,7 @@ BaseHTTPPeer::do_writer( return do_close(); util::spawn( - strand_, - std::bind( - &BaseHTTPPeer::do_read, - impl().shared_from_this(), - std::placeholders::_1)); + strand_, std::bind(&BaseHTTPPeer::do_read, impl().shared_from_this(), std::placeholders::_1)); } //------------------------------------------------------------------------------ @@ -432,13 +374,7 @@ BaseHTTPPeer::write(void const* buf, std::size_t bytes) }()) { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind( - &BaseHTTPPeer::on_write, - impl().shared_from_this(), - error_code{}, - 0)); + return post(strand_, std::bind(&BaseHTTPPeer::on_write, impl().shared_from_this(), error_code{}, 0)); else return on_write(error_code{}, 0); } @@ -446,9 +382,7 @@ BaseHTTPPeer::write(void const* buf, std::size_t bytes) template void -BaseHTTPPeer::write( - std::shared_ptr const& writer, - bool keep_alive) +BaseHTTPPeer::write(std::shared_ptr const& writer, bool keep_alive) { util::spawn( strand_, @@ -476,11 +410,7 @@ void BaseHTTPPeer::complete() { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind( - &BaseHTTPPeer::complete, - impl().shared_from_this())); + return post(strand_, std::bind(&BaseHTTPPeer::complete, impl().shared_from_this())); message_ = {}; complete_ = true; @@ -493,11 +423,7 @@ BaseHTTPPeer::complete() // keep-alive util::spawn( - strand_, - std::bind( - &BaseHTTPPeer::do_read, - impl().shared_from_this(), - std::placeholders::_1)); + strand_, std::bind(&BaseHTTPPeer::do_read, impl().shared_from_this(), std::placeholders::_1)); } // DEPRECATED @@ -510,8 +436,7 @@ BaseHTTPPeer::close(bool graceful) return post( strand_, std::bind( - (void(BaseHTTPPeer::*)(bool)) & - BaseHTTPPeer::close, + (void(BaseHTTPPeer::*)(bool)) & BaseHTTPPeer::close, impl().shared_from_this(), graceful)); @@ -530,6 +455,4 @@ BaseHTTPPeer::close(bool graceful) boost::beast::get_lowest_layer(impl().stream_).close(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/BasePeer.h b/include/xrpl/server/detail/BasePeer.h index 30de63e6ff..afa1ceb993 100644 --- a/include/xrpl/server/detail/BasePeer.h +++ b/include/xrpl/server/detail/BasePeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_BASEPEER_H_INCLUDED -#define RIPPLE_SERVER_BASEPEER_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { // Common part of all peers template @@ -101,12 +81,9 @@ void BasePeer::close() { if (!strand_.running_in_this_thread()) - return post( - strand_, std::bind(&BasePeer::close, impl().shared_from_this())); + return post(strand_, std::bind(&BasePeer::close, impl().shared_from_this())); error_code ec; - ripple::get_lowest_layer(impl().ws_).socket().close(ec); + xrpl::get_lowest_layer(impl().ws_).socket().close(ec); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/BaseWSPeer.h b/include/xrpl/server/detail/BaseWSPeer.h index 391c5c337e..ab985dfac5 100644 --- a/include/xrpl/server/detail/BaseWSPeer.h +++ b/include/xrpl/server/detail/BaseWSPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright(c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_BASEWSPEER_H_INCLUDED -#define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED +#pragma once #include #include @@ -38,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Represents an active WebSocket connection. */ template @@ -68,9 +48,7 @@ private: bool ping_active_ = false; boost::beast::websocket::ping_data payload_; error_code ec_; - std::function< - void(boost::beast::websocket::frame_type, boost::beast::string_view)> - control_callback_; + std::function control_callback_; public: template @@ -158,9 +136,7 @@ protected: on_ping(error_code const& ec); void - on_ping_pong( - boost::beast::websocket::frame_type kind, - boost::beast::string_view payload); + on_ping_pong(boost::beast::websocket::frame_type kind, boost::beast::string_view payload); void on_timer(error_code ec); @@ -194,33 +170,20 @@ void BaseWSPeer::run() { if (!strand_.running_in_this_thread()) - return post( - strand_, std::bind(&BaseWSPeer::run, impl().shared_from_this())); + return post(strand_, std::bind(&BaseWSPeer::run, impl().shared_from_this())); impl().ws_.set_option(port().pmd_options); // Must manage the control callback memory outside of the `control_callback` // function - control_callback_ = std::bind( - &BaseWSPeer::on_ping_pong, - this, - std::placeholders::_1, - std::placeholders::_2); + control_callback_ = std::bind(&BaseWSPeer::on_ping_pong, this, std::placeholders::_1, std::placeholders::_2); impl().ws_.control_callback(control_callback_); start_timer(); close_on_timer_ = true; - impl().ws_.set_option( - boost::beast::websocket::stream_base::decorator([](auto& res) { - res.set( - boost::beast::http::field::server, - BuildInfo::getFullVersionString()); - })); + impl().ws_.set_option(boost::beast::websocket::stream_base::decorator( + [](auto& res) { res.set(boost::beast::http::field::server, BuildInfo::getFullVersionString()); })); impl().ws_.async_accept( request_, bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_ws_handshake, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&BaseWSPeer::on_ws_handshake, impl().shared_from_this(), std::placeholders::_1))); } template @@ -228,16 +191,12 @@ void BaseWSPeer::send(std::shared_ptr w) { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind( - &BaseWSPeer::send, impl().shared_from_this(), std::move(w))); + return post(strand_, std::bind(&BaseWSPeer::send, impl().shared_from_this(), std::move(w))); if (do_close_) return; if (wq_.size() > port().ws_queue_limit) { - cr_.code = safe_cast( - boost::beast::websocket::close_code::policy_error); + cr_.code = safe_cast(boost::beast::websocket::close_code::policy_error); cr_.reason = "Policy error: client is too slow."; JLOG(this->j_.info()) << cr_.reason; wq_.erase(std::next(wq_.begin()), wq_.end()); @@ -258,26 +217,19 @@ BaseWSPeer::close() template void -BaseWSPeer::close( - boost::beast::websocket::close_reason const& reason) +BaseWSPeer::close(boost::beast::websocket::close_reason const& reason) { if (!strand_.running_in_this_thread()) - return post(strand_, [self = impl().shared_from_this(), reason] { - self->close(reason); - }); + return post(strand_, [self = impl().shared_from_this(), reason] { self->close(reason); }); if (do_close_) return; do_close_ = true; if (wq_.empty()) { impl().ws_.async_close( - reason, - bind_executor( - strand_, - [self = impl().shared_from_this()]( - boost::beast::error_code const& ec) { - self->on_close(ec); - })); + reason, bind_executor(strand_, [self = impl().shared_from_this()](boost::beast::error_code const& ec) { + self->on_close(ec); + })); } else { @@ -290,9 +242,7 @@ void BaseWSPeer::complete() { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&BaseWSPeer::complete, impl().shared_from_this())); + return post(strand_, std::bind(&BaseWSPeer::complete, impl().shared_from_this())); do_read(); } @@ -311,9 +261,7 @@ void BaseWSPeer::do_write() { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&BaseWSPeer::do_write, impl().shared_from_this())); + return post(strand_, std::bind(&BaseWSPeer::do_write, impl().shared_from_this())); on_write({}); } @@ -324,8 +272,7 @@ BaseWSPeer::on_write(error_code const& ec) if (ec) return fail(ec, "write"); auto& w = *wq_.front(); - auto const result = w.prepare( - 65536, std::bind(&BaseWSPeer::do_write, impl().shared_from_this())); + auto const result = w.prepare(65536, std::bind(&BaseWSPeer::do_write, impl().shared_from_this())); if (boost::indeterminate(result.first)) return; start_timer(); @@ -333,22 +280,13 @@ BaseWSPeer::on_write(error_code const& ec) impl().ws_.async_write_some( static_cast(result.first), result.second, - bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_write, - impl().shared_from_this(), - std::placeholders::_1))); + bind_executor(strand_, std::bind(&BaseWSPeer::on_write, impl().shared_from_this(), std::placeholders::_1))); else impl().ws_.async_write_some( static_cast(result.first), result.second, bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_write_fin, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&BaseWSPeer::on_write_fin, impl().shared_from_this(), std::placeholders::_1))); } template @@ -362,12 +300,7 @@ BaseWSPeer::on_write_fin(error_code const& ec) { impl().ws_.async_close( cr_, - bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_close, - impl().shared_from_this(), - std::placeholders::_1))); + bind_executor(strand_, std::bind(&BaseWSPeer::on_close, impl().shared_from_this(), std::placeholders::_1))); } else if (!wq_.empty()) on_write({}); @@ -378,17 +311,9 @@ void BaseWSPeer::do_read() { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&BaseWSPeer::do_read, impl().shared_from_this())); + return post(strand_, std::bind(&BaseWSPeer::do_read, impl().shared_from_this())); impl().ws_.async_read( - rb_, - bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_read, - impl().shared_from_this(), - std::placeholders::_1))); + rb_, bind_executor(strand_, std::bind(&BaseWSPeer::on_read, impl().shared_from_this(), std::placeholders::_1))); } template @@ -424,8 +349,7 @@ BaseWSPeer::start_timer() try { - timer_.expires_after( - remote_endpoint().address().is_loopback() ? timeoutLocal : timeout); + timer_.expires_after(remote_endpoint().address().is_loopback() ? timeoutLocal : timeout); } catch (boost::system::system_error const& e) { @@ -433,11 +357,7 @@ BaseWSPeer::start_timer() } timer_.async_wait(bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_timer, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&BaseWSPeer::on_timer, impl().shared_from_this(), std::placeholders::_1))); } // Convenience for discarding the error code @@ -469,9 +389,7 @@ BaseWSPeer::on_ping(error_code const& ec) template void -BaseWSPeer::on_ping_pong( - boost::beast::websocket::frame_type kind, - boost::beast::string_view payload) +BaseWSPeer::on_ping_pong(boost::beast::websocket::frame_type kind, boost::beast::string_view payload) { if (kind == boost::beast::websocket::frame_type::pong) { @@ -506,16 +424,11 @@ BaseWSPeer::on_timer(error_code ec) impl().ws_.async_ping( payload_, bind_executor( - strand_, - std::bind( - &BaseWSPeer::on_ping, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&BaseWSPeer::on_ping, impl().shared_from_this(), std::placeholders::_1))); JLOG(this->j_.trace()) << "sent ping"; return; } - ec = boost::system::errc::make_error_code( - boost::system::errc::timed_out); + ec = boost::system::errc::make_error_code(boost::system::errc::timed_out); } fail(ec, "timer"); } @@ -525,19 +438,15 @@ template void BaseWSPeer::fail(error_code ec, String const& what) { - XRPL_ASSERT( - strand_.running_in_this_thread(), - "ripple::BaseWSPeer::fail : strand in this thread"); + XRPL_ASSERT(strand_.running_in_this_thread(), "xrpl::BaseWSPeer::fail : strand in this thread"); cancel_timer(); if (!ec_ && ec != boost::asio::error::operation_aborted) { ec_ = ec; JLOG(this->j_.trace()) << what << ": " << ec.message(); - ripple::get_lowest_layer(impl().ws_).socket().close(ec); + xrpl::get_lowest_layer(impl().ws_).socket().close(ec); } } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/Door.h b/include/xrpl/server/detail/Door.h index 65bc310d4c..e41049f203 100644 --- a/include/xrpl/server/detail/Door.h +++ b/include/xrpl/server/detail/Door.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_DOOR_H_INCLUDED -#define RIPPLE_SERVER_DOOR_H_INCLUDED +#pragma once #include #include @@ -54,12 +34,11 @@ #include #include -namespace ripple { +namespace xrpl { /** A listening socket. */ template -class Door : public io_list::work, - public std::enable_shared_from_this> +class Door : public io_list::work, public std::enable_shared_from_this> { private: using clock_type = std::chrono::steady_clock; @@ -73,8 +52,7 @@ private: using stream_type = boost::beast::tcp_stream; // Detects SSL on a socket - class Detector : public io_list::work, - public std::enable_shared_from_this + class Detector : public io_list::work, public std::enable_shared_from_this { private: Port const& port_; @@ -134,11 +112,7 @@ private: should_throttle_for_fds(); public: - Door( - Handler& handler, - boost::asio::io_context& io_context, - Port const& port, - beast::Journal j); + Door(Handler& handler, boost::asio::io_context& io_context, Port const& port, beast::Journal j); // Work-around because we can't call shared_from_this in ctor void @@ -162,11 +136,7 @@ public: private: template void - create( - bool ssl, - ConstBufferSequence const& buffers, - stream_type&& stream, - endpoint_type remote_address); + create(bool ssl, ConstBufferSequence const& buffers, stream_type&& stream, endpoint_type remote_address); void do_accept(yield_context yield); @@ -195,12 +165,7 @@ template void Door::Detector::run() { - util::spawn( - strand_, - std::bind( - &Detector::do_detect, - this->shared_from_this(), - std::placeholders::_1)); + util::spawn(strand_, std::bind(&Detector::do_detect, this->shared_from_this(), std::placeholders::_1)); } template @@ -224,31 +189,18 @@ Door::Detector::do_detect(boost::asio::yield_context do_yield) if (ssl) { if (auto sp = ios().template emplace>( - port_, - handler_, - ioc_, - j_, - remote_address_, - buf.data(), - std::move(stream_))) + port_, handler_, ioc_, j_, remote_address_, buf.data(), std::move(stream_))) sp->run(); return; } if (auto sp = ios().template emplace>( - port_, - handler_, - ioc_, - j_, - remote_address_, - buf.data(), - std::move(stream_))) + port_, handler_, ioc_, j_, remote_address_, buf.data(), std::move(stream_))) sp->run(); return; } if (ec != boost::asio::error::operation_aborted) { - JLOG(j_.trace()) << "Error detecting ssl: " << ec.message() << " from " - << remote_address_; + JLOG(j_.trace()) << "Error detecting ssl: " << ec.message() << " from " << remote_address_; } } @@ -266,8 +218,7 @@ Door::reOpen() if (ec) { std::stringstream ss; - ss << "Can't close acceptor: " << port_.name << ", " - << ec.message(); + ss << "Can't close acceptor: " << port_.name << ", " << ec.message(); JLOG(j_.error()) << ss.str(); Throw(ss.str()); } @@ -278,33 +229,28 @@ Door::reOpen() acceptor_.open(local_address.protocol(), ec); if (ec) { - JLOG(j_.error()) << "Open port '" << port_.name - << "' failed:" << ec.message(); + JLOG(j_.error()) << "Open port '" << port_.name << "' failed:" << ec.message(); Throw(); } - acceptor_.set_option( - boost::asio::ip::tcp::acceptor::reuse_address(true), ec); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), ec); if (ec) { - JLOG(j_.error()) << "Option for port '" << port_.name - << "' failed:" << ec.message(); + JLOG(j_.error()) << "Option for port '" << port_.name << "' failed:" << ec.message(); Throw(); } acceptor_.bind(local_address, ec); if (ec) { - JLOG(j_.error()) << "Bind port '" << port_.name - << "' failed:" << ec.message(); + JLOG(j_.error()) << "Bind port '" << port_.name << "' failed:" << ec.message(); Throw(); } acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec); if (ec) { - JLOG(j_.error()) << "Listen on port '" << port_.name - << "' failed:" << ec.message(); + JLOG(j_.error()) << "Listen on port '" << port_.name << "' failed:" << ec.message(); Throw(); } @@ -312,11 +258,7 @@ Door::reOpen() } template -Door::Door( - Handler& handler, - boost::asio::io_context& io_context, - Port const& port, - beast::Journal j) +Door::Door(Handler& handler, boost::asio::io_context& io_context, Port const& port, beast::Journal j) : j_(j) , port_(port) , handler_(handler) @@ -324,12 +266,9 @@ Door::Door( , acceptor_(io_context) , strand_(boost::asio::make_strand(io_context)) , ssl_( - port_.protocol.count("https") > 0 || - port_.protocol.count("wss") > 0 || port_.protocol.count("wss2") > 0 || + port_.protocol.count("https") > 0 || port_.protocol.count("wss") > 0 || port_.protocol.count("wss2") > 0 || port_.protocol.count("peer") > 0) - , plain_( - port_.protocol.count("http") > 0 || port_.protocol.count("ws") > 0 || - port_.protocol.count("ws2")) + , plain_(port_.protocol.count("http") > 0 || port_.protocol.count("ws") > 0 || port_.protocol.count("ws2")) , backoff_timer_(io_context) { reOpen(); @@ -339,12 +278,7 @@ template void Door::run() { - util::spawn( - strand_, - std::bind( - &Door::do_accept, - this->shared_from_this(), - std::placeholders::_1)); + util::spawn(strand_, std::bind(&Door::do_accept, this->shared_from_this(), std::placeholders::_1)); } template @@ -352,9 +286,7 @@ void Door::close() { if (!strand_.running_in_this_thread()) - return boost::asio::post( - strand_, - std::bind(&Door::close, this->shared_from_this())); + return boost::asio::post(strand_, std::bind(&Door::close, this->shared_from_this())); backoff_timer_.cancel(); error_code ec; acceptor_.close(ec); @@ -365,33 +297,17 @@ Door::close() template template void -Door::create( - bool ssl, - ConstBufferSequence const& buffers, - stream_type&& stream, - endpoint_type remote_address) +Door::create(bool ssl, ConstBufferSequence const& buffers, stream_type&& stream, endpoint_type remote_address) { if (ssl) { if (auto sp = ios().template emplace>( - port_, - handler_, - ioc_, - j_, - remote_address, - buffers, - std::move(stream))) + port_, handler_, ioc_, j_, remote_address, buffers, std::move(stream))) sp->run(); return; } if (auto sp = ios().template emplace>( - port_, - handler_, - ioc_, - j_, - remote_address, - buffers, - std::move(stream))) + port_, handler_, ioc_, j_, remote_address, buffers, std::move(stream))) sp->run(); } @@ -407,8 +323,7 @@ Door::do_accept(boost::asio::yield_context do_yield) boost::system::error_code tec; backoff_timer_.async_wait(do_yield[tec]); accept_delay_ = std::min(accept_delay_ * 2, MAX_ACCEPT_DELAY); - JLOG(j_.warn()) << "Throttling do_accept for " - << accept_delay_.count() << "ms."; + JLOG(j_.warn()) << "Throttling do_accept for " << accept_delay_.count() << "ms."; continue; } @@ -422,11 +337,9 @@ Door::do_accept(boost::asio::yield_context do_yield) if (ec == boost::asio::error::operation_aborted) break; - if (ec == boost::asio::error::no_descriptors || - ec == boost::asio::error::no_buffer_space) + if (ec == boost::asio::error::no_descriptors || ec == boost::asio::error::no_buffer_space) { - JLOG(j_.warn()) << "accept: Too many open files. Pausing for " - << accept_delay_.count() << "ms."; + JLOG(j_.warn()) << "accept: Too many open files. Pausing for " << accept_delay_.count() << "ms."; backoff_timer_.expires_after(accept_delay_); boost::system::error_code tec; @@ -445,22 +358,13 @@ Door::do_accept(boost::asio::yield_context do_yield) if (ssl_ && plain_) { - if (auto sp = ios().template emplace( - port_, - handler_, - ioc_, - std::move(stream), - remote_address, - j_)) + if (auto sp = + ios().template emplace(port_, handler_, ioc_, std::move(stream), remote_address, j_)) sp->run(); } else if (ssl_ || plain_) { - create( - ssl_, - boost::asio::null_buffers{}, - std::move(stream), - remote_address); + create(ssl_, boost::asio::null_buffers{}, std::move(stream), remote_address); } } } @@ -509,8 +413,7 @@ Door::should_throttle_for_fds() auto const& s = *stats; auto const free = (s.limit > s.used) ? (s.limit - s.used) : 0ull; - double const free_ratio = - static_cast(free) / static_cast(s.limit); + double const free_ratio = static_cast(free) / static_cast(s.limit); if (free_ratio < FREE_FD_THRESHOLD) { return true; @@ -519,6 +422,4 @@ Door::should_throttle_for_fds() #endif } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/JSONRPCUtil.h b/include/xrpl/server/detail/JSONRPCUtil.h index 88efc077d8..934085f8e6 100644 --- a/include/xrpl/server/detail/JSONRPCUtil.h +++ b/include/xrpl/server/detail/JSONRPCUtil.h @@ -1,38 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_JSONRPCUTIL_H_INCLUDED -#define RIPPLE_SERVER_JSONRPCUTIL_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { void -HTTPReply( - int nStatus, - std::string const& strMsg, - Json::Output const&, - beast::Journal j); +HTTPReply(int nStatus, std::string const& strMsg, Json::Output const&, beast::Journal j); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/LowestLayer.h b/include/xrpl/server/detail/LowestLayer.h index abc6904179..b8b0d46180 100644 --- a/include/xrpl/server/detail/LowestLayer.h +++ b/include/xrpl/server/detail/LowestLayer.h @@ -1,25 +1,4 @@ - -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_LOWESTLAYER_H_INCLUDED -#define RIPPLE_SERVER_LOWESTLAYER_H_INCLUDED +#pragma once #if BOOST_VERSION >= 107000 #include @@ -27,9 +6,9 @@ #include #endif -namespace ripple { +namespace xrpl { -// Before boost 1.70, get_lowest_layer required an explicit templat parameter +// Before boost 1.70, get_lowest_layer required an explicit template parameter template decltype(auto) get_lowest_layer(T& t) noexcept @@ -41,6 +20,4 @@ get_lowest_layer(T& t) noexcept #endif } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/PlainHTTPPeer.h b/include/xrpl/server/detail/PlainHTTPPeer.h index f6f8e5b010..94c84336f9 100644 --- a/include/xrpl/server/detail/PlainHTTPPeer.h +++ b/include/xrpl/server/detail/PlainHTTPPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_PLAINHTTPPEER_H_INCLUDED -#define RIPPLE_SERVER_PLAINHTTPPEER_H_INCLUDED +#pragma once #include #include @@ -28,12 +8,11 @@ #include -namespace ripple { +namespace xrpl { template -class PlainHTTPPeer - : public BaseHTTPPeer>, - public std::enable_shared_from_this> +class PlainHTTPPeer : public BaseHTTPPeer>, + public std::enable_shared_from_this> { private: friend class BaseHTTPPeer; @@ -81,13 +60,7 @@ PlainHTTPPeer::PlainHTTPPeer( endpoint_type remote_endpoint, ConstBufferSequence const& buffers, stream_type&& stream) - : BaseHTTPPeer( - port, - handler, - ioc.get_executor(), - journal, - remote_endpoint, - buffers) + : BaseHTTPPeer(port, handler, ioc.get_executor(), journal, remote_endpoint, buffers) , stream_(std::move(stream)) , socket_(stream_.socket()) { @@ -105,21 +78,14 @@ PlainHTTPPeer::run() { if (!this->handler_.onAccept(this->session(), this->remote_address_)) { - util::spawn( - this->strand_, - std::bind(&PlainHTTPPeer::do_close, this->shared_from_this())); + util::spawn(this->strand_, std::bind(&PlainHTTPPeer::do_close, this->shared_from_this())); return; } if (!socket_.is_open()) return; - util::spawn( - this->strand_, - std::bind( - &PlainHTTPPeer::do_read, - this->shared_from_this(), - std::placeholders::_1)); + util::spawn(this->strand_, std::bind(&PlainHTTPPeer::do_read, this->shared_from_this(), std::placeholders::_1)); } template @@ -141,8 +107,7 @@ void PlainHTTPPeer::do_request() { ++this->request_count_; - auto const what = this->handler_.onHandoff( - this->session(), std::move(this->message_), this->remote_address_); + auto const what = this->handler_.onHandoff(this->session(), std::move(this->message_), this->remote_address_); if (what.moved) return; boost::system::error_code ec; @@ -173,6 +138,4 @@ PlainHTTPPeer::do_close() socket_.shutdown(socket_type::shutdown_send, ec); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/PlainWSPeer.h b/include/xrpl/server/detail/PlainWSPeer.h index 4fdc1f6f49..9196d5ea49 100644 --- a/include/xrpl/server/detail/PlainWSPeer.h +++ b/include/xrpl/server/detail/PlainWSPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_PLAINWSPEER_H_INCLUDED -#define RIPPLE_SERVER_PLAINWSPEER_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { template class PlainWSPeer : public BaseWSPeer>, @@ -77,6 +57,4 @@ PlainWSPeer::PlainWSPeer( { } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/SSLHTTPPeer.h b/include/xrpl/server/detail/SSLHTTPPeer.h index 8564263114..138145544e 100644 --- a/include/xrpl/server/detail/SSLHTTPPeer.h +++ b/include/xrpl/server/detail/SSLHTTPPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SSLHTTPPEER_H_INCLUDED -#define RIPPLE_SERVER_SSLHTTPPEER_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include -namespace ripple { +namespace xrpl { template class SSLHTTPPeer : public BaseHTTPPeer>, @@ -93,16 +73,8 @@ SSLHTTPPeer::SSLHTTPPeer( endpoint_type remote_address, ConstBufferSequence const& buffers, middle_type&& stream) - : BaseHTTPPeer( - port, - handler, - ioc.get_executor(), - journal, - remote_address, - buffers) - , stream_ptr_(std::make_unique( - middle_type(std::move(stream)), - *port.context)) + : BaseHTTPPeer(port, handler, ioc.get_executor(), journal, remote_address, buffers) + , stream_ptr_(std::make_unique(middle_type(std::move(stream)), *port.context)) , stream_(*stream_ptr_) , socket_(stream_.next_layer().socket()) { @@ -115,19 +87,12 @@ SSLHTTPPeer::run() { if (!this->handler_.onAccept(this->session(), this->remote_address_)) { - util::spawn( - this->strand_, - std::bind(&SSLHTTPPeer::do_close, this->shared_from_this())); + util::spawn(this->strand_, std::bind(&SSLHTTPPeer::do_close, this->shared_from_this())); return; } if (!socket_.is_open()) return; - util::spawn( - this->strand_, - std::bind( - &SSLHTTPPeer::do_handshake, - this->shared_from_this(), - std::placeholders::_1)); + util::spawn(this->strand_, std::bind(&SSLHTTPPeer::do_handshake, this->shared_from_this(), std::placeholders::_1)); } template @@ -151,25 +116,17 @@ SSLHTTPPeer::do_handshake(yield_context do_yield) boost::system::error_code ec; stream_.set_verify_mode(boost::asio::ssl::verify_none); this->start_timer(); - this->read_buf_.consume(stream_.async_handshake( - stream_type::server, this->read_buf_.data(), do_yield[ec])); + this->read_buf_.consume(stream_.async_handshake(stream_type::server, this->read_buf_.data(), do_yield[ec])); this->cancel_timer(); if (ec == boost::beast::error::timeout) return this->on_timer(); if (ec) return this->fail(ec, "handshake"); - bool const http = this->port().protocol.count("peer") > 0 || - this->port().protocol.count("wss") > 0 || - this->port().protocol.count("wss2") > 0 || - this->port().protocol.count("https") > 0; + bool const http = this->port().protocol.count("peer") > 0 || this->port().protocol.count("wss") > 0 || + this->port().protocol.count("wss2") > 0 || this->port().protocol.count("https") > 0; if (http) { - util::spawn( - this->strand_, - std::bind( - &SSLHTTPPeer::do_read, - this->shared_from_this(), - std::placeholders::_1)); + util::spawn(this->strand_, std::bind(&SSLHTTPPeer::do_read, this->shared_from_this(), std::placeholders::_1)); return; } // `this` will be destroyed @@ -181,10 +138,7 @@ SSLHTTPPeer::do_request() { ++this->request_count_; auto const what = this->handler_.onHandoff( - this->session(), - std::move(stream_ptr_), - std::move(this->message_), - this->remote_address_); + this->session(), std::move(stream_ptr_), std::move(this->message_), this->remote_address_); if (what.moved) return; if (what.response) @@ -199,11 +153,7 @@ SSLHTTPPeer::do_close() { this->start_timer(); stream_.async_shutdown(bind_executor( - this->strand_, - std::bind( - &SSLHTTPPeer::on_shutdown, - this->shared_from_this(), - std::placeholders::_1))); + this->strand_, std::bind(&SSLHTTPPeer::on_shutdown, this->shared_from_this(), std::placeholders::_1))); } template @@ -223,6 +173,4 @@ SSLHTTPPeer::on_shutdown(error_code ec) stream_.next_layer().close(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/SSLWSPeer.h b/include/xrpl/server/detail/SSLWSPeer.h index d7cc0395c7..b80312e55f 100644 --- a/include/xrpl/server/detail/SSLWSPeer.h +++ b/include/xrpl/server/detail/SSLWSPeer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SSLWSPEER_H_INCLUDED -#define RIPPLE_SERVER_SSLWSPEER_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include -namespace ripple { +namespace xrpl { template class SSLWSPeer : public BaseWSPeer>, @@ -86,6 +66,4 @@ SSLWSPeer::SSLWSPeer( { } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/ServerImpl.h b/include/xrpl/server/detail/ServerImpl.h index 4090aa0a6b..e836b964d2 100644 --- a/include/xrpl/server/detail/ServerImpl.h +++ b/include/xrpl/server/detail/ServerImpl.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SERVERIMPL_H_INCLUDED -#define RIPPLE_SERVER_SERVERIMPL_H_INCLUDED +#pragma once #include #include @@ -35,10 +15,9 @@ #include #include -namespace ripple { +namespace xrpl { -using Endpoints = - std::unordered_map; +using Endpoints = std::unordered_map; /** A multi-protocol server. @@ -89,9 +68,7 @@ private: beast::Journal const j_; boost::asio::io_context& io_context_; boost::asio::strand strand_; - std::optional> - work_; + std::optional> work_; std::mutex m_; std::vector ports_; @@ -102,10 +79,7 @@ private: io_list ios_; public: - ServerImpl( - Handler& handler, - boost::asio::io_context& io_context, - beast::Journal journal); + ServerImpl(Handler& handler, boost::asio::io_context& io_context, beast::Journal journal); ~ServerImpl(); @@ -142,10 +116,7 @@ private: }; template -ServerImpl::ServerImpl( - Handler& handler, - boost::asio::io_context& io_context, - beast::Journal journal) +ServerImpl::ServerImpl(Handler& handler, boost::asio::io_context& io_context, beast::Journal journal) : handler_(handler) , j_(journal) , io_context_(io_context) @@ -176,8 +147,7 @@ ServerImpl::ports(std::vector const& ports) { ports_.push_back(port); auto& internalPort = ports_.back(); - if (auto sp = ios_.emplace>( - handler_, io_context_, internalPort, j_)) + if (auto sp = ios_.emplace>(handler_, io_context_, internalPort, j_)) { list_.push_back(sp); @@ -208,6 +178,4 @@ ServerImpl::closed() { return ios_.closed(); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/server/detail/Spawn.h b/include/xrpl/server/detail/Spawn.h index 56f173dec3..d94fb4fa05 100644 --- a/include/xrpl/server/detail/Spawn.h +++ b/include/xrpl/server/detail/Spawn.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright(c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_SPAWN_H_INCLUDED -#define RIPPLE_SERVER_SPAWN_H_INCLUDED +#pragma once #include @@ -28,13 +8,11 @@ #include #include -namespace ripple::util { +namespace xrpl::util { namespace impl { template -concept IsStrand = std::same_as< - std::decay_t, - boost::asio::strand::inner_executor_type>>; +concept IsStrand = std::same_as, boost::asio::strand::inner_executor_type>>; /** * @brief A completion handler that restores `boost::asio::spawn`'s behaviour @@ -88,21 +66,15 @@ spawn(Ctx&& ctx, F&& func) { if constexpr (impl::IsStrand) { - boost::asio::spawn( - std::forward(ctx), - std::forward(func), - impl::kPROPAGATE_EXCEPTIONS); + boost::asio::spawn(std::forward(ctx), std::forward(func), impl::kPROPAGATE_EXCEPTIONS); } else { boost::asio::spawn( - boost::asio::make_strand( - boost::asio::get_associated_executor(std::forward(ctx))), + boost::asio::make_strand(boost::asio::get_associated_executor(std::forward(ctx))), std::forward(func), impl::kPROPAGATE_EXCEPTIONS); } } -} // namespace ripple::util - -#endif +} // namespace xrpl::util diff --git a/include/xrpl/server/detail/io_list.h b/include/xrpl/server/detail/io_list.h index 6292794864..5b1a02e039 100644 --- a/include/xrpl/server/detail/io_list.h +++ b/include/xrpl/server/detail/io_list.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SERVER_IO_LIST_H_INCLUDED -#define RIPPLE_SERVER_IO_LIST_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Manages a set of objects performing asynchronous I/O. */ class io_list final @@ -209,8 +189,7 @@ template std::shared_ptr io_list::emplace(Args&&... args) { - static_assert( - std::is_base_of::value, "T must derive from io_list::work"); + static_assert(std::is_base_of::value, "T must derive from io_list::work"); if (closed_) return nullptr; auto sp = std::make_shared(std::forward(args)...); @@ -262,6 +241,4 @@ io_list::join() cv_.wait(lock, [&] { return closed_ && n_ == 0; }); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/Family.h b/include/xrpl/shamap/Family.h index 5975321873..73887fb2dc 100644 --- a/include/xrpl/shamap/Family.h +++ b/include/xrpl/shamap/Family.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_FAMILY_H_INCLUDED -#define RIPPLE_SHAMAP_FAMILY_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class Family { @@ -84,6 +64,4 @@ public: reset() = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/FullBelowCache.h b/include/xrpl/shamap/FullBelowCache.h index f792b9035f..6a6da1463a 100644 --- a/include/xrpl/shamap/FullBelowCache.h +++ b/include/xrpl/shamap/FullBelowCache.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_FULLBELOWCACHE_H_INCLUDED -#define RIPPLE_SHAMAP_FULLBELOWCACHE_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -58,8 +38,7 @@ public: std::string const& name, clock_type& clock, beast::Journal j, - beast::insight::Collector::ptr const& collector = - beast::insight::NullCollector::New(), + beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New(), std::size_t target_size = defaultCacheTargetSize, std::chrono::seconds expiration = std::chrono::minutes{2}) : m_cache(name, target_size, expiration, clock, j, collector), m_gen(1) @@ -148,6 +127,4 @@ private: using FullBelowCache = detail::BasicFullBelowCache; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/README.md b/include/xrpl/shamap/README.md index 3bff74e67b..419918c0cb 100644 --- a/include/xrpl/shamap/README.md +++ b/include/xrpl/shamap/README.md @@ -226,7 +226,7 @@ The `fetchNodeNT()` method goes through three phases: Any SHAMapLeafNode that is immutable has a sequence number of zero (sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are - given non-zero sequence numbers (unsharable). But all nodes in the + given non-zero sequence numbers (unshareable). But all nodes in the TreeNodeCache are immutable, so if one is found here, its sequence number will be 0. diff --git a/include/xrpl/shamap/SHAMap.h b/include/xrpl/shamap/SHAMap.h index 2bc003cd82..cd084ab48b 100644 --- a/include/xrpl/shamap/SHAMap.h +++ b/include/xrpl/shamap/SHAMap.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAP_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAP_H_INCLUDED +#pragma once #include #include @@ -38,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { class SHAMapNodeID; class SHAMapSyncFilter; @@ -114,15 +94,12 @@ private: public: /** Number of children each non-leaf node has (the 'radix tree' part of the * map) */ - static inline constexpr unsigned int branchFactor = - SHAMapInnerNode::branchFactor; + static inline constexpr unsigned int branchFactor = SHAMapInnerNode::branchFactor; /** The depth of the hash map: data is only present in the leaves */ static inline constexpr unsigned int leafDepth = 64; - using DeltaItem = std::pair< - boost::intrusive_ptr, - boost::intrusive_ptr>; + using DeltaItem = std::pair, boost::intrusive_ptr>; using Delta = std::map; SHAMap() = delete; @@ -202,14 +179,10 @@ public: // save a copy if you have a temporary anyway bool - updateGiveItem( - SHAMapNodeType type, - boost::intrusive_ptr item); + updateGiveItem(SHAMapNodeType type, boost::intrusive_ptr item); bool - addGiveItem( - SHAMapNodeType type, - boost::intrusive_ptr item); + addGiveItem(SHAMapNodeType type, boost::intrusive_ptr item); // Save a copy if you need to extend the life // of the SHAMapItem beyond this SHAMap @@ -252,18 +225,14 @@ public: If function returns false, visitDifferences exits. */ void - visitDifferences( - SHAMap const* have, - std::function const&) const; + visitDifferences(SHAMap const* have, std::function const&) const; /** Visit every leaf node in this SHAMap @param function called with every non inner node visited. */ void - visitLeaves( - std::function< - void(boost::intrusive_ptr const&)> const&) const; + visitLeaves(std::function const&)> const&) const; // comparison/sync functions @@ -304,25 +273,16 @@ public: * @return true if verified successfully */ static bool - verifyProofPath( - uint256 const& rootHash, - uint256 const& key, - std::vector const& path); + verifyProofPath(uint256 const& rootHash, uint256 const& key, std::vector const& path); /** Serializes the root in a format appropriate for sending over the wire */ void serializeRoot(Serializer& s) const; SHAMapAddNode - addRootNode( - SHAMapHash const& hash, - Slice const& rootNode, - SHAMapSyncFilter* filter); + addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter* filter); SHAMapAddNode - addKnownNode( - SHAMapNodeID const& nodeID, - Slice const& rawNode, - SHAMapSyncFilter* filter); + addKnownNode(SHAMapNodeID const& nodeID, Slice const& rawNode, SHAMapSyncFilter* filter); // status functions void @@ -352,9 +312,7 @@ public: void walkMap(std::vector& missingNodes, int maxMissing) const; bool - walkMapParallel( - std::vector& missingNodes, - int maxMissing) const; + walkMapParallel(std::vector& missingNodes, int maxMissing) const; bool deepCompare(SHAMap& other) const; // Intended for debug/test only @@ -367,19 +325,15 @@ public: invariants() const; private: - using SharedPtrNodeStack = std::stack< - std::pair, SHAMapNodeID>>; - using DeltaRef = std::pair< - boost::intrusive_ptr, - boost::intrusive_ptr>; + using SharedPtrNodeStack = std::stack, SHAMapNodeID>>; + using DeltaRef = std::pair, boost::intrusive_ptr>; // tree node cache operations intr_ptr::SharedPtr cacheLookup(SHAMapHash const& hash) const; void - canonicalize(SHAMapHash const& hash, intr_ptr::SharedPtr&) - const; + canonicalize(SHAMapHash const& hash, intr_ptr::SharedPtr&) const; // database operations intr_ptr::SharedPtr @@ -395,17 +349,13 @@ private: /** Update hashes up to the root */ void - dirtyUp( - SharedPtrNodeStack& stack, - uint256 const& target, - intr_ptr::SharedPtr terminal); + dirtyUp(SharedPtrNodeStack& stack, uint256 const& target, intr_ptr::SharedPtr terminal); /** Walk towards the specified id, returning the node. Caller must check if the return is nullptr, and if not, if the node->peekItem()->key() == id */ SHAMapLeafNode* - walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack = nullptr) - const; + walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack = nullptr) const; /** Return nullptr if key not found */ SHAMapLeafNode* findKey(uint256 const& id) const; @@ -426,17 +376,11 @@ private: // returns the first item at or below this node SHAMapLeafNode* - firstBelow( - intr_ptr::SharedPtr, - SharedPtrNodeStack& stack, - int branch = 0) const; + firstBelow(intr_ptr::SharedPtr, SharedPtrNodeStack& stack, int branch = 0) const; // returns the last item at or below this node SHAMapLeafNode* - lastBelow( - intr_ptr::SharedPtr node, - SharedPtrNodeStack& stack, - int branch = branchFactor) const; + lastBelow(intr_ptr::SharedPtr node, SharedPtrNodeStack& stack, int branch = branchFactor) const; // helper function for firstBelow and lastBelow SHAMapLeafNode* @@ -444,10 +388,7 @@ private: intr_ptr::SharedPtr node, SharedPtrNodeStack& stack, int branch, - std::tuple< - int, - std::function, - std::function> const& loopParams) const; + std::tuple, std::function> const& loopParams) const; // Simple descent // Get a child of the specified node @@ -462,22 +403,12 @@ private: // Descend with filter // If pending, callback is called as if it called fetchNodeNT - using descendCallback = std::function< - void(intr_ptr::SharedPtr, SHAMapHash const&)>; + using descendCallback = std::function, SHAMapHash const&)>; SHAMapTreeNode* - descendAsync( - SHAMapInnerNode* parent, - int branch, - SHAMapSyncFilter* filter, - bool& pending, - descendCallback&&) const; + descendAsync(SHAMapInnerNode* parent, int branch, SHAMapSyncFilter* filter, bool& pending, descendCallback&&) const; std::pair - descend( - SHAMapInnerNode* parent, - SHAMapNodeID const& parentID, - int branch, - SHAMapSyncFilter* filter) const; + descend(SHAMapInnerNode* parent, SHAMapNodeID const& parentID, int branch, SHAMapSyncFilter* filter) const; // Non-storing // Does not hook the returned node to its parent @@ -557,16 +488,8 @@ private: // reads std::map resumes_; - MissingNodes( - int max, - SHAMapSyncFilter* filter, - int maxDefer, - std::uint32_t generation) - : max_(max) - , filter_(filter) - , maxDefer_(maxDefer) - , generation_(generation) - , deferred_(0) + MissingNodes(int max, SHAMapSyncFilter* filter, int maxDefer, std::uint32_t generation) + : max_(max), filter_(filter), maxDefer_(maxDefer), generation_(generation), deferred_(0) { missingNodes_.reserve(max); finishedReads_.reserve(maxDefer); @@ -581,9 +504,7 @@ private: // fetch from DB helper function intr_ptr::SharedPtr - finishFetch( - SHAMapHash const& hash, - std::shared_ptr const& object) const; + finishFetch(SHAMapHash const& hash, std::shared_ptr const& object) const; }; inline void @@ -601,9 +522,7 @@ SHAMap::setLedgerSeq(std::uint32_t lseq) inline void SHAMap::setImmutable() { - XRPL_ASSERT( - state_ != SHAMapState::Invalid, - "ripple::SHAMap::setImmutable : state is valid"); + XRPL_ASSERT(state_ != SHAMapState::Invalid, "xrpl::SHAMap::setImmutable : state is valid"); state_ = SHAMapState::Immutable; } @@ -684,23 +603,17 @@ private: inline SHAMap::const_iterator::const_iterator(SHAMap const* map) : map_(map) { - XRPL_ASSERT( - map_, - "ripple::SHAMap::const_iterator::const_iterator : non-null input"); + XRPL_ASSERT(map_, "xrpl::SHAMap::const_iterator::const_iterator : non-null input"); if (auto temp = map_->peekFirstItem(stack_)) item_ = temp->peekItem().get(); } -inline SHAMap::const_iterator::const_iterator(SHAMap const* map, std::nullptr_t) - : map_(map) +inline SHAMap::const_iterator::const_iterator(SHAMap const* map, std::nullptr_t) : map_(map) { } -inline SHAMap::const_iterator::const_iterator( - SHAMap const* map, - pointer item, - SharedPtrNodeStack&& stack) +inline SHAMap::const_iterator::const_iterator(SHAMap const* map, pointer item, SharedPtrNodeStack&& stack) : stack_(std::move(stack)), map_(map), item_(item) { } @@ -740,7 +653,7 @@ operator==(SHAMap::const_iterator const& x, SHAMap::const_iterator const& y) { XRPL_ASSERT( x.map_ == y.map_, - "ripple::operator==(SHAMap::const_iterator, SHAMap::const_iterator) : " + "xrpl::operator==(SHAMap::const_iterator, SHAMap::const_iterator) : " "inputs map do match"); return x.item_ == y.item_; } @@ -763,6 +676,4 @@ SHAMap::end() const return const_iterator(this, nullptr); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapAccountStateLeafNode.h b/include/xrpl/shamap/SHAMapAccountStateLeafNode.h index a600ea222b..552d2b4692 100644 --- a/include/xrpl/shamap/SHAMapAccountStateLeafNode.h +++ b/include/xrpl/shamap/SHAMapAccountStateLeafNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED +#pragma once #include #include @@ -26,26 +6,19 @@ #include #include -namespace ripple { +namespace xrpl { /** A leaf node for a state object. */ -class SHAMapAccountStateLeafNode final - : public SHAMapLeafNode, - public CountedObject +class SHAMapAccountStateLeafNode final : public SHAMapLeafNode, public CountedObject { public: - SHAMapAccountStateLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid) + SHAMapAccountStateLeafNode(boost::intrusive_ptr item, std::uint32_t cowid) : SHAMapLeafNode(std::move(item), cowid) { updateHash(); } - SHAMapAccountStateLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid, - SHAMapHash const& hash) + SHAMapAccountStateLeafNode(boost::intrusive_ptr item, std::uint32_t cowid, SHAMapHash const& hash) : SHAMapLeafNode(std::move(item), cowid, hash) { } @@ -53,8 +26,7 @@ public: intr_ptr::SharedPtr clone(std::uint32_t cowid) const final override { - return intr_ptr::make_shared( - item_, cowid, hash_); + return intr_ptr::make_shared(item_, cowid, hash_); } SHAMapNodeType @@ -66,8 +38,7 @@ public: void updateHash() final override { - hash_ = SHAMapHash{ - sha512Half(HashPrefix::leafNode, item_->slice(), item_->key())}; + hash_ = SHAMapHash{sha512Half(HashPrefix::leafNode, item_->slice(), item_->key())}; } void @@ -87,6 +58,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapAddNode.h b/include/xrpl/shamap/SHAMapAddNode.h index 898a3cb99e..7d0aaf3be4 100644 --- a/include/xrpl/shamap/SHAMapAddNode.h +++ b/include/xrpl/shamap/SHAMapAddNode.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPADDNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPADDNODE_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { // results of adding nodes class SHAMapAddNode @@ -71,8 +51,7 @@ inline SHAMapAddNode::SHAMapAddNode() : mGood(0), mBad(0), mDuplicate(0) { } -inline SHAMapAddNode::SHAMapAddNode(int good, int bad, int duplicate) - : mGood(good), mBad(bad), mDuplicate(duplicate) +inline SHAMapAddNode::SHAMapAddNode(int good, int bad, int duplicate) : mGood(good), mBad(bad), mDuplicate(duplicate) { } @@ -180,6 +159,4 @@ SHAMapAddNode::get() const return ret; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapInnerNode.h b/include/xrpl/shamap/SHAMapInnerNode.h index 58d7392cf4..73d59cc1fe 100644 --- a/include/xrpl/shamap/SHAMapInnerNode.h +++ b/include/xrpl/shamap/SHAMapInnerNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED +#pragma once #include #include @@ -29,10 +9,9 @@ #include #include -namespace ripple { +namespace xrpl { -class SHAMapInnerNode final : public SHAMapTreeNode, - public CountedObject +class SHAMapInnerNode final : public SHAMapTreeNode, public CountedObject { public: /** Each inner node has 16 children (the 'radix tree' part of the map) */ @@ -97,9 +76,7 @@ private: iterNonEmptyChildIndexes(F&& f) const; public: - explicit SHAMapInnerNode( - std::uint32_t cowid, - std::uint8_t numAllocatedChildren = 2); + explicit SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren = 2); SHAMapInnerNode(SHAMapInnerNode const&) = delete; SHAMapInnerNode& @@ -221,5 +198,4 @@ SHAMapInnerNode::setFullBelowGen(std::uint32_t gen) fullBelowGen_ = gen; } -} // namespace ripple -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapItem.h b/include/xrpl/shamap/SHAMapItem.h index 4c9ce65469..ab9cf74dc8 100644 --- a/include/xrpl/shamap/SHAMapItem.h +++ b/include/xrpl/shamap/SHAMapItem.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { // an item stored in a SHAMap class SHAMapItem : public CountedObject @@ -62,13 +42,9 @@ private: // the only way to properly create one is to first allocate enough memory // so we limit this constructor to codepaths that do this right and limit // arbitrary construction. - SHAMapItem(uint256 const& tag, Slice data) - : tag_(tag), size_(static_cast(data.size())) + SHAMapItem(uint256 const& tag, Slice data) : tag_(tag), size_(static_cast(data.size())) { - std::memcpy( - reinterpret_cast(this) + sizeof(*this), - data.data(), - data.size()); + std::memcpy(reinterpret_cast(this) + sizeof(*this), data.data(), data.size()); } public: @@ -144,13 +120,13 @@ intrusive_ptr_release(SHAMapItem const* x) { auto p = reinterpret_cast(x); - // The SHAMapItem constuctor isn't trivial (because the destructor + // The SHAMapItem constructor isn't trivial (because the destructor // for CountedObject isn't) so we can't avoid calling it here, but // plan for a future where we might not need to. if constexpr (!std::is_trivially_destructible_v) std::destroy_at(x); - // If the slabber doens't claim this pointer, it was allocated + // If the slabber doesn't claim this pointer, it was allocated // manually, so we free it manually. if (!detail::slabber.deallocate(const_cast(p))) delete[] p; @@ -160,9 +136,7 @@ intrusive_ptr_release(SHAMapItem const* x) inline boost::intrusive_ptr make_shamapitem(uint256 const& tag, Slice data) { - XRPL_ASSERT( - data.size() <= megabytes(16), - "ripple::make_shamapitem : maximum input size"); + XRPL_ASSERT(data.size() <= megabytes(16), "xrpl::make_shamapitem : maximum input size"); std::uint8_t* raw = detail::slabber.allocate(data.size()); @@ -187,6 +161,4 @@ make_shamapitem(SHAMapItem const& other) return make_shamapitem(other.key(), other.slice()); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapLeafNode.h b/include/xrpl/shamap/SHAMapLeafNode.h index 5c853d6127..aedcb3b79c 100644 --- a/include/xrpl/shamap/SHAMapLeafNode.h +++ b/include/xrpl/shamap/SHAMapLeafNode.h @@ -1,45 +1,20 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class SHAMapLeafNode : public SHAMapTreeNode { protected: boost::intrusive_ptr item_; - SHAMapLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid); + SHAMapLeafNode(boost::intrusive_ptr item, std::uint32_t cowid); - SHAMapLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid, - SHAMapHash const& hash); + SHAMapLeafNode(boost::intrusive_ptr item, std::uint32_t cowid, SHAMapHash const& hash); public: SHAMapLeafNode(SHAMapLeafNode const&) = delete; @@ -78,6 +53,4 @@ public: getString(SHAMapNodeID const&) const final override; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapMissingNode.h b/include/xrpl/shamap/SHAMapMissingNode.h index c41e6f2602..f1670587eb 100644 --- a/include/xrpl/shamap/SHAMapMissingNode.h +++ b/include/xrpl/shamap/SHAMapMissingNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { enum class SHAMapType { TRANSACTION = 1, // A tree of transactions @@ -48,8 +28,7 @@ to_string(SHAMapType t) case SHAMapType::FREE: return "Free Tree"; default: - return std::to_string( - safe_cast>(t)); + return std::to_string(safe_cast>(t)); } } @@ -57,18 +36,14 @@ class SHAMapMissingNode : public std::runtime_error { public: SHAMapMissingNode(SHAMapType t, SHAMapHash const& hash) - : std::runtime_error( - "Missing Node: " + to_string(t) + ": hash " + to_string(hash)) + : std::runtime_error("Missing Node: " + to_string(t) + ": hash " + to_string(hash)) { } SHAMapMissingNode(SHAMapType t, uint256 const& id) - : std::runtime_error( - "Missing Node: " + to_string(t) + ": id " + to_string(id)) + : std::runtime_error("Missing Node: " + to_string(t) + ": id " + to_string(id)) { } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapNodeID.h b/include/xrpl/shamap/SHAMapNodeID.h index abdca3a55a..3517246f90 100644 --- a/include/xrpl/shamap/SHAMapNodeID.h +++ b/include/xrpl/shamap/SHAMapNodeID.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPNODEID_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPNODEID_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Identifies a node inside a SHAMap */ class SHAMapNodeID : public CountedObject @@ -125,8 +105,7 @@ to_string(SHAMapNodeID const& node) if (node.isRoot()) return "NodeID(root)"; - return "NodeID(" + std::to_string(node.getDepth()) + "," + - to_string(node.getNodeID()) + ")"; + return "NodeID(" + std::to_string(node.getDepth()) + "," + to_string(node.getNodeID()) + ")"; } inline std::ostream& @@ -158,6 +137,4 @@ deserializeSHAMapNodeID(std::string const& s) [[nodiscard]] unsigned int selectBranch(SHAMapNodeID const& id, uint256 const& hash); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapSyncFilter.h b/include/xrpl/shamap/SHAMapSyncFilter.h index 43d5941466..219f9ac558 100644 --- a/include/xrpl/shamap/SHAMapSyncFilter.h +++ b/include/xrpl/shamap/SHAMapSyncFilter.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED +#pragma once #include #include /** Callback for filtering SHAMap during sync. */ -namespace ripple { +namespace xrpl { class SHAMapSyncFilter { @@ -38,17 +18,11 @@ public: // Note that the nodeData is overwritten by this call virtual void - gotNode( - bool fromFilter, - SHAMapHash const& nodeHash, - std::uint32_t ledgerSeq, - Blob&& nodeData, - SHAMapNodeType type) const = 0; + gotNode(bool fromFilter, SHAMapHash const& nodeHash, std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapNodeType type) + const = 0; virtual std::optional getNode(SHAMapHash const& nodeHash) const = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapTreeNode.h b/include/xrpl/shamap/SHAMapTreeNode.h index c1351112c2..668f658754 100644 --- a/include/xrpl/shamap/SHAMapTreeNode.h +++ b/include/xrpl/shamap/SHAMapTreeNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { // These are wire-protocol identifiers used during serialization to encode the // type of a node. They should not be arbitrarily be changed. @@ -75,10 +55,7 @@ protected: { } - explicit SHAMapTreeNode( - std::uint32_t cowid, - SHAMapHash const& hash) noexcept - : hash_(hash), cowid_(cowid) + explicit SHAMapTreeNode(std::uint32_t cowid, SHAMapHash const& hash) noexcept : hash_(hash), cowid_(cowid) { } /** @} */ @@ -189,6 +166,4 @@ private: makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool hashValid); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapTxLeafNode.h b/include/xrpl/shamap/SHAMapTxLeafNode.h index f5b406d1de..0a44380b9b 100644 --- a/include/xrpl/shamap/SHAMapTxLeafNode.h +++ b/include/xrpl/shamap/SHAMapTxLeafNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED +#pragma once #include #include @@ -26,25 +6,19 @@ #include #include -namespace ripple { +namespace xrpl { /** A leaf node for a transaction. No metadata is included. */ -class SHAMapTxLeafNode final : public SHAMapLeafNode, - public CountedObject +class SHAMapTxLeafNode final : public SHAMapLeafNode, public CountedObject { public: - SHAMapTxLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid) + SHAMapTxLeafNode(boost::intrusive_ptr item, std::uint32_t cowid) : SHAMapLeafNode(std::move(item), cowid) { updateHash(); } - SHAMapTxLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid, - SHAMapHash const& hash) + SHAMapTxLeafNode(boost::intrusive_ptr item, std::uint32_t cowid, SHAMapHash const& hash) : SHAMapLeafNode(std::move(item), cowid, hash) { } @@ -64,8 +38,7 @@ public: void updateHash() final override { - hash_ = - SHAMapHash{sha512Half(HashPrefix::transactionID, item_->slice())}; + hash_ = SHAMapHash{sha512Half(HashPrefix::transactionID, item_->slice())}; } void @@ -83,6 +56,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/SHAMapTxPlusMetaLeafNode.h b/include/xrpl/shamap/SHAMapTxPlusMetaLeafNode.h index f14726b0f2..d11cc87ff7 100644 --- a/include/xrpl/shamap/SHAMapTxPlusMetaLeafNode.h +++ b/include/xrpl/shamap/SHAMapTxPlusMetaLeafNode.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED -#define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED +#pragma once #include #include @@ -26,26 +6,19 @@ #include #include -namespace ripple { +namespace xrpl { /** A leaf node for a transaction and its associated metadata. */ -class SHAMapTxPlusMetaLeafNode final - : public SHAMapLeafNode, - public CountedObject +class SHAMapTxPlusMetaLeafNode final : public SHAMapLeafNode, public CountedObject { public: - SHAMapTxPlusMetaLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid) + SHAMapTxPlusMetaLeafNode(boost::intrusive_ptr item, std::uint32_t cowid) : SHAMapLeafNode(std::move(item), cowid) { updateHash(); } - SHAMapTxPlusMetaLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid, - SHAMapHash const& hash) + SHAMapTxPlusMetaLeafNode(boost::intrusive_ptr item, std::uint32_t cowid, SHAMapHash const& hash) : SHAMapLeafNode(std::move(item), cowid, hash) { } @@ -53,8 +26,7 @@ public: intr_ptr::SharedPtr clone(std::uint32_t cowid) const override { - return intr_ptr::make_shared( - item_, cowid, hash_); + return intr_ptr::make_shared(item_, cowid, hash_); } SHAMapNodeType @@ -66,8 +38,7 @@ public: void updateHash() final override { - hash_ = SHAMapHash{ - sha512Half(HashPrefix::txNode, item_->slice(), item_->key())}; + hash_ = SHAMapHash{sha512Half(HashPrefix::txNode, item_->slice(), item_->key())}; } void @@ -87,6 +58,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/TreeNodeCache.h b/include/xrpl/shamap/TreeNodeCache.h index e1c612586e..4edb6348ec 100644 --- a/include/xrpl/shamap/TreeNodeCache.h +++ b/include/xrpl/shamap/TreeNodeCache.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED -#define RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { using TreeNodeCache = TaggedCache< uint256, @@ -32,6 +12,4 @@ using TreeNodeCache = TaggedCache< /*IsKeyCache*/ false, intr_ptr::SharedWeakUnionPtr, intr_ptr::SharedPtr>; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/detail/TaggedPointer.h b/include/xrpl/shamap/detail/TaggedPointer.h index 54aef85fa6..217cd93d0a 100644 --- a/include/xrpl/shamap/detail/TaggedPointer.h +++ b/include/xrpl/shamap/detail/TaggedPointer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED -#define RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** TaggedPointer is a combination of a pointer and a mask stored in the lowest two bits. @@ -59,9 +39,7 @@ namespace ripple { class TaggedPointer { private: - static_assert( - alignof(SHAMapHash) >= 4, - "Bad alignment: Tag pointer requires low two bits to be zero."); + static_assert(alignof(SHAMapHash) >= 4, "Bad alignment: Tag pointer requires low two bits to be zero."); /** Upper bits are the pointer, lowest two bits are the tag A moved-from object will have a tp_ of zero. */ @@ -111,10 +89,7 @@ public: @param toAllocate allocate space for at least this number of children (must be <= branchFactor) */ - explicit TaggedPointer( - TaggedPointer&& other, - std::uint16_t isBranch, - std::uint8_t toAllocate); + explicit TaggedPointer(TaggedPointer&& other, std::uint16_t isBranch, std::uint8_t toAllocate); /** Given `other` with the specified children in `srcBranches`, create a new TaggedPointer with the allocated number of children and the @@ -171,9 +146,8 @@ public: /** Get the number of elements in each array and a pointer to the start of each array. */ - [[nodiscard]] std:: - tuple*> - getHashesAndChildren() const; + [[nodiscard]] std::tuple*> + getHashesAndChildren() const; /** Get the `hashes` array */ [[nodiscard]] SHAMapHash* @@ -245,6 +219,4 @@ popcnt16(std::uint16_t a) #endif } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/include/xrpl/shamap/detail/TaggedPointer.ipp b/include/xrpl/shamap/detail/TaggedPointer.ipp index 3efcfb6ffe..bedb33a733 100644 --- a/include/xrpl/shamap/detail/TaggedPointer.ipp +++ b/include/xrpl/shamap/detail/TaggedPointer.ipp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,18 +6,14 @@ #include -namespace ripple { +namespace xrpl { namespace { // Sparse array size boundaries. // Given n children, an array of size `*std::lower_bound(boundaries.begin(), // boundaries.end(), n);` is used to store the children. Note that the last // element must be the number of children in a dense array. -constexpr std::array boundaries{ - 2, - 4, - 6, - SHAMapInnerNode::branchFactor}; +constexpr std::array boundaries{2, 4, 6, SHAMapInnerNode::branchFactor}; static_assert( boundaries.size() <= 4, "The hashesAndChildren member uses a tagged array format with two bits " @@ -48,8 +25,7 @@ static_assert( // Terminology: A chunk is the memory being allocated from a block. A block // contains multiple chunks. This is the terminology the boost documentation // uses. Pools use "Simple Segregated Storage" as their storage format. -constexpr size_t elementSizeBytes = - (sizeof(SHAMapHash) + sizeof(intr_ptr::SharedPtr)); +constexpr size_t elementSizeBytes = (sizeof(SHAMapHash) + sizeof(intr_ptr::SharedPtr)); constexpr size_t blockSizeBytes = kilobytes(512); @@ -61,8 +37,7 @@ initArrayChunkSizeBytes(std::index_sequence) boundaries[I] * elementSizeBytes..., }; } -constexpr auto arrayChunkSizeBytes = - initArrayChunkSizeBytes(std::make_index_sequence{}); +constexpr auto arrayChunkSizeBytes = initArrayChunkSizeBytes(std::make_index_sequence{}); template constexpr std::array @@ -72,27 +47,20 @@ initArrayChunksPerBlock(std::index_sequence) blockSizeBytes / arrayChunkSizeBytes[I]..., }; } -constexpr auto chunksPerBlock = - initArrayChunksPerBlock(std::make_index_sequence{}); +constexpr auto chunksPerBlock = initArrayChunksPerBlock(std::make_index_sequence{}); [[nodiscard]] inline std::uint8_t numAllocatedChildren(std::uint8_t n) { - XRPL_ASSERT( - n <= SHAMapInnerNode::branchFactor, - "ripple::numAllocatedChildren : valid input"); + XRPL_ASSERT(n <= SHAMapInnerNode::branchFactor, "xrpl::numAllocatedChildren : valid input"); return *std::lower_bound(boundaries.begin(), boundaries.end(), n); } [[nodiscard]] inline std::size_t boundariesIndex(std::uint8_t numChildren) { - XRPL_ASSERT( - numChildren <= SHAMapInnerNode::branchFactor, - "ripple::boundariesIndex : valid input"); - return std::distance( - boundaries.begin(), - std::lower_bound(boundaries.begin(), boundaries.end(), numChildren)); + XRPL_ASSERT(numChildren <= SHAMapInnerNode::branchFactor, "xrpl::boundariesIndex : valid input"); + return std::distance(boundaries.begin(), std::lower_bound(boundaries.begin(), boundaries.end(), numChildren)); } template @@ -143,9 +111,8 @@ initIsFromArrayFuns(std::index_sequence) chunksPerBlock[I]>::is_from..., }; } -std::array, boundaries.size()> const - isFromArrayFuns = - initIsFromArrayFuns(std::make_index_sequence{}); +std::array, boundaries.size()> const isFromArrayFuns = + initIsFromArrayFuns(std::make_index_sequence{}); // This function returns an untagged pointer [[nodiscard]] inline std::pair @@ -159,9 +126,7 @@ allocateArrays(std::uint8_t numChildren) inline void deallocateArrays(std::uint8_t boundaryIndex, void* p) { - XRPL_ASSERT( - isFromArrayFuns[boundaryIndex](p), - "ripple::deallocateArrays : valid inputs"); + XRPL_ASSERT(isFromArrayFuns[boundaryIndex](p), "xrpl::deallocateArrays : valid inputs"); freeArrayFuns[boundaryIndex](p); } @@ -277,12 +242,11 @@ inline TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t numChildren) auto [tag, p] = allocateArrays(numChildren); XRPL_ASSERT( tag < boundaries.size(), - "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + "xrpl::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " "maximum tag"); XRPL_ASSERT( - (reinterpret_cast(p) & ptrMask) == - reinterpret_cast(p), - "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + (reinterpret_cast(p) & ptrMask) == reinterpret_cast(p), + "xrpl::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " "valid pointer"); tp_ = reinterpret_cast(p) + tag; } @@ -295,15 +259,14 @@ inline TaggedPointer::TaggedPointer( { XRPL_ASSERT( toAllocate >= popcnt16(dstBranches), - "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : minimum " + "xrpl::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : minimum " "toAllocate input"); if (other.capacity() == numAllocatedChildren(toAllocate)) { // in place *this = std::move(other); - auto [srcDstNumAllocated, srcDstHashes, srcDstChildren] = - getHashesAndChildren(); + auto [srcDstNumAllocated, srcDstHashes, srcDstChildren] = getHashesAndChildren(); bool const srcDstIsDense = isDense(); int srcDstIndex = 0; for (int i = 0; i < SHAMapInnerNode::branchFactor; ++i) @@ -377,13 +340,11 @@ inline TaggedPointer::TaggedPointer( { // not in place TaggedPointer dst{RawAllocateTag{}, toAllocate}; - auto [dstNumAllocated, dstHashes, dstChildren] = - dst.getHashesAndChildren(); + auto [dstNumAllocated, dstHashes, dstChildren] = dst.getHashesAndChildren(); // Move `other` into a local var so it's not in a partially moved from // state after this function runs TaggedPointer src(std::move(other)); - auto [srcNumAllocated, srcHashes, srcChildren] = - src.getHashesAndChildren(); + auto [srcNumAllocated, srcHashes, srcChildren] = src.getHashesAndChildren(); bool const srcIsDense = src.isDense(); bool const dstIsDense = dst.isDense(); int srcIndex = 0, dstIndex = 0; @@ -397,9 +358,7 @@ inline TaggedPointer::TaggedPointer( // keep new (&dstHashes[dstIndex]) SHAMapHash{srcHashes[srcIndex]}; - new (&dstChildren[dstIndex]) - intr_ptr::SharedPtr{ - std::move(srcChildren[srcIndex])}; + new (&dstChildren[dstIndex]) intr_ptr::SharedPtr{std::move(srcChildren[srcIndex])}; ++dstIndex; ++srcIndex; } @@ -410,8 +369,7 @@ inline TaggedPointer::TaggedPointer( if (dstIsDense) { new (&dstHashes[dstIndex]) SHAMapHash{}; - new (&dstChildren[dstIndex]) - intr_ptr::SharedPtr{}; + new (&dstChildren[dstIndex]) intr_ptr::SharedPtr{}; ++dstIndex; } } @@ -419,8 +377,7 @@ inline TaggedPointer::TaggedPointer( { // add new (&dstHashes[dstIndex]) SHAMapHash{}; - new (&dstChildren[dstIndex]) - intr_ptr::SharedPtr{}; + new (&dstChildren[dstIndex]) intr_ptr::SharedPtr{}; ++dstIndex; if (srcIsDense) { @@ -433,8 +390,7 @@ inline TaggedPointer::TaggedPointer( if (dstIsDense) { new (&dstHashes[dstIndex]) SHAMapHash{}; - new (&dstChildren[dstIndex]) - intr_ptr::SharedPtr{}; + new (&dstChildren[dstIndex]) intr_ptr::SharedPtr{}; ++dstIndex; } if (srcIsDense) @@ -446,7 +402,7 @@ inline TaggedPointer::TaggedPointer( // If sparse, may need to run additional constructors XRPL_ASSERT( !dstIsDense || dstIndex == dstNumAllocated, - "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : " + "xrpl::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : " "non-sparse or valid sparse"); for (int i = dstIndex; i < dstNumAllocated; ++i) { @@ -457,10 +413,7 @@ inline TaggedPointer::TaggedPointer( } } -inline TaggedPointer::TaggedPointer( - TaggedPointer&& other, - std::uint16_t isBranch, - std::uint8_t toAllocate) +inline TaggedPointer::TaggedPointer(TaggedPointer&& other, std::uint16_t isBranch, std::uint8_t toAllocate) : TaggedPointer(std::move(other)) { auto const oldNumAllocated = capacity(); @@ -474,8 +427,7 @@ inline TaggedPointer::TaggedPointer( intr_ptr::SharedPtr*newChildren, *oldChildren; std::uint8_t newNumAllocated; // structured bindings can't be captured in c++ 17; use tie instead - std::tie(newNumAllocated, newHashes, newChildren) = - newHashesAndChildren.getHashesAndChildren(); + std::tie(newNumAllocated, newHashes, newChildren) = newHashesAndChildren.getHashesAndChildren(); std::tie(std::ignore, oldHashes, oldChildren) = getHashesAndChildren(); if (newNumAllocated == SHAMapInnerNode::branchFactor) @@ -483,8 +435,7 @@ inline TaggedPointer::TaggedPointer( // new arrays are dense, old arrays are sparse iterNonEmptyChildIndexes(isBranch, [&](auto branchNum, auto indexNum) { new (&newHashes[branchNum]) SHAMapHash{oldHashes[indexNum]}; - new (&newChildren[branchNum]) intr_ptr::SharedPtr{ - std::move(oldChildren[indexNum])}; + new (&newChildren[branchNum]) intr_ptr::SharedPtr{std::move(oldChildren[indexNum])}; }); // Run the constructors for the remaining elements for (int i = 0; i < SHAMapInnerNode::branchFactor; ++i) @@ -500,11 +451,9 @@ inline TaggedPointer::TaggedPointer( // new arrays are sparse, old arrays may be sparse or dense int curCompressedIndex = 0; iterNonEmptyChildIndexes(isBranch, [&](auto branchNum, auto indexNum) { - new (&newHashes[curCompressedIndex]) - SHAMapHash{oldHashes[indexNum]}; + new (&newHashes[curCompressedIndex]) SHAMapHash{oldHashes[indexNum]}; new (&newChildren[curCompressedIndex]) - intr_ptr::SharedPtr{ - std::move(oldChildren[indexNum])}; + intr_ptr::SharedPtr{std::move(oldChildren[indexNum])}; ++curCompressedIndex; }); // Run the constructors for the remaining elements @@ -563,16 +512,13 @@ TaggedPointer::isDense() const return (tp_ & tagMask) == boundaries.size() - 1; } -[[nodiscard]] inline std:: - tuple*> - TaggedPointer::getHashesAndChildren() const +[[nodiscard]] inline std::tuple*> +TaggedPointer::getHashesAndChildren() const { auto const [tag, ptr] = decode(); auto const hashes = reinterpret_cast(ptr); std::uint8_t numAllocated = boundaries[tag]; - auto const children = - reinterpret_cast*>( - hashes + numAllocated); + auto const children = reinterpret_cast*>(hashes + numAllocated); return {numAllocated, hashes, children}; }; @@ -594,4 +540,4 @@ inline TaggedPointer::~TaggedPointer() destroyHashesAndChildren(); } -} // namespace ripple +} // namespace xrpl diff --git a/sanitizers/suppressions/asan.supp b/sanitizers/suppressions/asan.supp new file mode 100644 index 0000000000..7ba98766bd --- /dev/null +++ b/sanitizers/suppressions/asan.supp @@ -0,0 +1,29 @@ +# The idea is to empty this file gradually by fixing the underlying issues and removing suppressions. +# +# ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0" +# +# The detect_container_overflow=0 option disables false positives from: +# - Boost intrusive containers (slist_iterator.hpp, hashtable.hpp, aged_unordered_container.h) +# - Boost context/coroutine stack switching (Workers.cpp, thread.h) +# +# See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow + +# Boost +interceptor_name:boost/asio + +# Leaks in Doctest tests: xrpl.test.* +interceptor_name:src/libxrpl/net/HTTPClient.cpp +interceptor_name:src/libxrpl/net/RegisterSSLCerts.cpp +interceptor_name:src/tests/libxrpl/net/HTTPClient.cpp +interceptor_name:xrpl/net/AutoSocket.h +interceptor_name:xrpl/net/HTTPClient.h +interceptor_name:xrpl/net/HTTPClientSSLContext.h +interceptor_name:xrpl/net/RegisterSSLCerts.h + +# Suppress false positive stack-buffer errors in thread stack allocation +# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189) +# These occur during multi-threaded test initialization on macOS +interceptor_name:memcpy +interceptor_name:__bzero +interceptor_name:__asan_memset +interceptor_name:__asan_memcpy diff --git a/sanitizers/suppressions/lsan.supp b/sanitizers/suppressions/lsan.supp new file mode 100644 index 0000000000..a81d7d89fa --- /dev/null +++ b/sanitizers/suppressions/lsan.supp @@ -0,0 +1,16 @@ +# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions. + +# Suppress leaks detected by asan in rippled code. +leak:src/libxrpl/net/HTTPClient.cpp +leak:src/libxrpl/net/RegisterSSLCerts.cpp +leak:src/tests/libxrpl/net/HTTPClient.cpp +leak:xrpl/net/AutoSocket.h +leak:xrpl/net/HTTPClient.h +leak:xrpl/net/HTTPClientSSLContext.h +leak:xrpl/net/RegisterSSLCerts.h +leak:ripple::HTTPClient +leak:ripple::HTTPClientImp + +# Suppress leaks detected by asan in boost code. +leak:boost::asio +leak:boost/asio diff --git a/sanitizers/suppressions/sanitizer-ignorelist.txt b/sanitizers/suppressions/sanitizer-ignorelist.txt new file mode 100644 index 0000000000..5dbead48a2 --- /dev/null +++ b/sanitizers/suppressions/sanitizer-ignorelist.txt @@ -0,0 +1,29 @@ +# We were seeing some false positives and some repeated errors(since these are library files) in following files. +# Clang will skip instrumenting the files added here. +# We should fix the underlying issues(if any) and remove these entries. + +deadlock:libxrpl/beast/utility/beast_Journal.cpp +deadlock:libxrpl/beast/utility/beast_PropertyStream.cpp +deadlock:test/beast/beast_PropertyStream_test.cpp +deadlock:xrpld/core/detail/Workers.cpp +deadlock:xrpld/core/JobQueue.cpp + +race:libxrpl/beast/utility/beast_Journal.cpp +race:libxrpl/beast/utility/beast_PropertyStream.cpp +race:test/beast/beast_PropertyStream_test.cpp +race:xrpld/core/detail/Workers.cpp +race:xrpld/core/JobQueue.cpp + +signal:libxrpl/beast/utility/beast_Journal.cpp +signal:libxrpl/beast/utility/beast_PropertyStream.cpp +signal:test/beast/beast_PropertyStream_test.cpp +signal:xrpld/core/detail/Workers.cpp +signal:xrpld/core/JobQueue.cpp + +src:beast/utility/beast_Journal.cpp +src:beast/utility/beast_PropertyStream.cpp +src:core/detail/Workers.cpp +src:core/JobQueue.cpp +src:libxrpl/beast/utility/beast_Journal.cpp +src:test/beast/beast_PropertyStream_test.cpp +src:src/test/app/Invariants_test.cpp diff --git a/sanitizers/suppressions/tsan.supp b/sanitizers/suppressions/tsan.supp new file mode 100644 index 0000000000..74f3371e68 --- /dev/null +++ b/sanitizers/suppressions/tsan.supp @@ -0,0 +1,102 @@ +# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions. + +# Suppress race in Boost ASIO scheduler detected by GCC-15 +# This is a false positive in Boost's internal pipe() synchronization +race:boost/asio/ +race:boost/context/ +race:boost/asio/executor.hpp +race:boost::asio + +# Suppress tsan related issues in rippled code. +race:src/libxrpl/basics/make_SSLContext.cpp +race:src/libxrpl/basics/Number.cpp +race:src/libxrpl/json/json_value.cpp +race:src/libxrpl/json/to_string.cpp +race:src/libxrpl/ledger/OpenView.cpp +race:src/libxrpl/net/HTTPClient.cpp +race:src/libxrpl/nodestore/backend/NuDBFactory.cpp +race:src/libxrpl/protocol/InnerObjectFormats.cpp +race:src/libxrpl/protocol/STParsedJSON.cpp +race:src/libxrpl/resource/ResourceManager.cpp +race:src/test/app/Flow_test.cpp +race:src/test/app/LedgerReplay_test.cpp +race:src/test/app/NFToken_test.cpp +race:src/test/app/Offer_test.cpp +race:src/test/app/ValidatorSite_test.cpp +race:src/test/consensus/NegativeUNL_test.cpp +race:src/test/jtx/impl/Env.cpp +race:src/test/jtx/impl/JSONRPCClient.cpp +race:src/test/jtx/impl/pay.cpp +race:src/test/jtx/impl/token.cpp +race:src/test/rpc/Book_test.cpp +race:src/xrpld/app/ledger/detail/InboundTransactions.cpp +race:src/xrpld/app/main/Application.cpp +race:src/xrpld/app/main/BasicApp.cpp +race:src/xrpld/app/main/GRPCServer.cpp +race:src/xrpld/app/misc/detail/AmendmentTable.cpp +race:src/xrpld/app/misc/FeeVoteImpl.cpp +race:src/xrpld/app/rdb/detail/Wallet.cpp +race:src/xrpld/overlay/detail/OverlayImpl.cpp +race:src/xrpld/peerfinder/detail/PeerfinderManager.cpp +race:src/xrpld/peerfinder/detail/SourceStrings.cpp +race:src/xrpld/rpc/detail/ServerHandler.cpp +race:xrpl/server/detail/Door.h +race:xrpl/server/detail/Spawn.h +race:xrpl/server/detail/ServerImpl.h +race:xrpl/nodestore/detail/DatabaseNodeImp.h +race:src/libxrpl/beast/utility/beast_Journal.cpp +race:src/test/beast/LexicalCast_test.cpp +race:ripple::ServerHandler + +# More suppressions in external library code. +race:crtstuff.c +race:pipe + +# Deadlock / lock-order-inversion suppressions +# Note: GCC's TSAN may not fully support all deadlock suppression patterns +deadlock:src/libxrpl/beast/utility/beast_Journal.cpp +deadlock:src/libxrpl/beast/utility/beast_PropertyStream.cpp +deadlock:src/test/beast/beast_PropertyStream_test.cpp +deadlock:src/xrpld/core/detail/Workers.cpp +deadlock:src/xrpld/app/misc/detail/Manifest.cpp +deadlock:src/xrpld/app/misc/detail/ValidatorList.cpp +deadlock:src/xrpld/app/misc/detail/ValidatorSite.cpp + +signal:src/libxrpl/beast/utility/beast_Journal.cpp +signal:src/xrpld/core/detail/Workers.cpp +signal:src/xrpld/core/JobQueue.cpp +signal:ripple::Workers::Worker + +# Aggressive suppressing of deadlock tsan errors +deadlock:pthread_create +deadlock:pthread_rwlock_rdlock +deadlock:boost::asio + +# Suppress SEGV crashes in TSAN itself during stringbuf operations +# This appears to be a GCC-15 TSAN instrumentation issue with basic_stringbuf::str() +# Commonly triggered in beast::Journal::ScopedStream destructor +signal:std::__cxx11::basic_stringbuf +signal:basic_stringbuf +signal:basic_ostringstream + +called_from_lib:libclang_rt +race:ostreambuf_iterator +race:basic_ostream + +# Suppress SEGV in Boost ASIO memory allocation with GCC-15 TSAN +signal:boost::asio::aligned_new +signal:boost::asio::detail::memory + +# Suppress SEGV in execute_native_thread_routine +signal:execute_native_thread_routine + +# Suppress data race in Boost Context fiber management +# This is a false positive in Boost's exception state management during fiber context switching +race:__cxxabiv1::manage_exception_state +race:boost::context::fiber::resume +race:boost::asio::detail::spawned_fiber_thread +race:boost::asio::detail::spawned_fiber_thread::suspend_with +race:boost::asio::detail::spawned_fiber_thread::destroy + +# Suppress data race in __tsan_memcpy called from Boost fiber operations +race:__tsan_memcpy diff --git a/sanitizers/suppressions/ubsan.supp b/sanitizers/suppressions/ubsan.supp new file mode 100644 index 0000000000..1504ef685f --- /dev/null +++ b/sanitizers/suppressions/ubsan.supp @@ -0,0 +1,237 @@ +# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions. + +# Suppress UBSan errors in external code by source file path +# This matches any source file under the external/ directory +alignment:external +bool:external +bounds:external +cfi:external +enum:external +float-cast-overflow:external +float-divide-by-zero:external +function:external +implicit-integer-sign-change:external +implicit-signed-integer-truncation::external +implicit-signed-integer-truncation:external +implicit-unsigned-integer-truncation:external +integer-divide-by-zero:external +invalid-builtin-use:external +invalid-objc-cast:external +nonnull-attribute:external +null:external +nullability-arg:external +nullability-assign:external +nullability-return:external +object-size:external +pointer-overflow:external +return:external +returns-nonnull-attribute:external +shift-base:external +shift-exponent:external +signed-integer-overflow:external +undefined:external +unreachable:external +unsigned-integer-overflow:external +vla-bound:external +vptr_check:external +vptr:external + +# Suppress all UBSan errors in Boost libraries +# This matches any files containing "boost" in its path or name +alignment:boost +bool:boost +bounds:boost +cfi:boost +enum:boost +float-cast-overflow:boost +float-divide-by-zero:boost +function:boost +implicit-integer-sign-change:boost +implicit-signed-integer-truncation:boost +implicit-unsigned-integer-truncation:boost +integer-divide-by-zero:boost +invalid-builtin-use:boost +invalid-objc-cast:boost +nonnull-attribute:boost +null:boost +nullability-arg:boost +nullability-assign:boost +nullability-return:boost +object-size:boost +pointer-overflow:boost +return:boost +returns-nonnull-attribute:boost +shift-base:boost +shift-exponent:boost +signed-integer-overflow:boost +undefined:boost +unreachable:boost +unsigned-integer-overflow:boost +vla-bound:boost +vptr_check:boost +vptr:boost + +# Google protobuf +undefined:protobuf + +# Suppress UBSan errors in rippled code by source file path +undefined:src/libxrpl/basics/base64.cpp +undefined:src/libxrpl/basics/Number.cpp +undefined:src/libxrpl/beast/utility/beast_Journal.cpp +undefined:src/libxrpl/crypto/RFC1751.cpp +undefined:src/libxrpl/ledger/ApplyView.cpp +undefined:src/libxrpl/ledger/View.cpp +undefined:src/libxrpl/protocol/Permissions.cpp +undefined:src/libxrpl/protocol/STAmount.cpp +undefined:src/libxrpl/protocol/STPathSet.cpp +undefined:src/libxrpl/protocol/tokens.cpp +undefined:src/libxrpl/shamap/SHAMap.cpp +undefined:src/test/app/Batch_test.cpp +undefined:src/test/app/Invariants_test.cpp +undefined:src/test/app/NFToken_test.cpp +undefined:src/test/app/Offer_test.cpp +undefined:src/test/app/Path_test.cpp +undefined:src/test/basics/XRPAmount_test.cpp +undefined:src/test/beast/LexicalCast_test.cpp +undefined:src/test/jtx/impl/acctdelete.cpp +undefined:src/test/ledger/SkipList_test.cpp +undefined:src/test/rpc/Subscribe_test.cpp +undefined:src/tests/libxrpl/basics/RangeSet.cpp +undefined:src/xrpld/app/main/BasicApp.cpp +undefined:src/xrpld/app/main/BasicApp.cpp +undefined:src/xrpld/app/misc/detail/AmendmentTable.cpp +undefined:src/xrpld/app/misc/NetworkOPs.cpp +undefined:src/libxrpl/json/json_value.cpp +undefined:src/xrpld/app/paths/detail/StrandFlow.h +undefined:src/xrpld/app/tx/detail/NFTokenMint.cpp +undefined:src/xrpld/app/tx/detail/SetOracle.cpp +undefined:src/xrpld/core/detail/JobQueue.cpp +undefined:src/xrpld/core/detail/Workers.cpp +undefined:src/xrpld/rpc/detail/Role.cpp +undefined:src/xrpld/rpc/handlers/GetAggregatePrice.cpp +undefined:xrpl/basics/base_uint.h +undefined:xrpl/basics/DecayingSample.h +undefined:xrpl/beast/test/yield_to.h +undefined:xrpl/beast/xor_shift_engine.h +undefined:xrpl/nodestore/detail/varint.h +undefined:xrpl/peerfinder/detail/Counts.h +undefined:xrpl/protocol/nft.h + +# basic_string.h:483:51: runtime error: unsigned integer overflow +unsigned-integer-overflow:basic_string.h +unsigned-integer-overflow:bits/chrono.h +unsigned-integer-overflow:bits/random.h +unsigned-integer-overflow:bits/random.tcc +unsigned-integer-overflow:bits/stl_algobase.h +unsigned-integer-overflow:bits/uniform_int_dist.h +unsigned-integer-overflow:string_view + +# runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'std::size_t' (aka 'unsigned long') +unsigned-integer-overflow:src/libxrpl/basics/base64.cpp +unsigned-integer-overflow:src/libxrpl/basics/Number.cpp +unsigned-integer-overflow:src/libxrpl/crypto/RFC1751.cpp +unsigned-integer-overflow:rc/libxrpl/json/json_value.cpp +unsigned-integer-overflow:src/libxrpl/ledger/ApplyView.cpp +unsigned-integer-overflow:src/libxrpl/ledger/View.cpp +unsigned-integer-overflow:src/libxrpl/protocol/Permissions.cpp +unsigned-integer-overflow:src/libxrpl/protocol/STAmount.cpp +unsigned-integer-overflow:src/libxrpl/protocol/STPathSet.cpp +unsigned-integer-overflow:src/libxrpl/protocol/tokens.cpp +unsigned-integer-overflow:src/libxrpl/shamap/SHAMap.cpp +unsigned-integer-overflow:src/test/app/Batch_test.cpp +unsigned-integer-overflow:src/test/app/Invariants_test.cpp +unsigned-integer-overflow:src/test/app/NFToken_test.cpp +unsigned-integer-overflow:src/test/app/Offer_test.cpp +unsigned-integer-overflow:src/test/app/Path_test.cpp +unsigned-integer-overflow:src/test/basics/XRPAmount_test.cpp +unsigned-integer-overflow:src/test/beast/LexicalCast_test.cpp +unsigned-integer-overflow:src/test/jtx/impl/acctdelete.cpp +unsigned-integer-overflow:src/test/ledger/SkipList_test.cpp +unsigned-integer-overflow:src/test/rpc/Subscribe_test.cpp +unsigned-integer-overflow:src/tests/libxrpl/basics/RangeSet.cpp +unsigned-integer-overflow:src/xrpld/app/main/BasicApp.cpp +unsigned-integer-overflow:src/xrpld/app/misc/detail/AmendmentTable.cpp +unsigned-integer-overflow:src/xrpld/app/misc/NetworkOPs.cpp +unsigned-integer-overflow:src/xrpld/app/paths/detail/StrandFlow.h +unsigned-integer-overflow:src/xrpld/app/tx/detail/NFTokenMint.cpp +unsigned-integer-overflow:src/xrpld/app/tx/detail/SetOracle.cpp +unsigned-integer-overflow:src/xrpld/rpc/detail/Role.cpp +unsigned-integer-overflow:src/xrpld/rpc/handlers/GetAggregatePrice.cpp +unsigned-integer-overflow:xrpl/basics/base_uint.h +unsigned-integer-overflow:xrpl/basics/DecayingSample.h +unsigned-integer-overflow:xrpl/beast/test/yield_to.h +unsigned-integer-overflow:xrpl/beast/xor_shift_engine.h +unsigned-integer-overflow:xrpl/nodestore/detail/varint.h +unsigned-integer-overflow:xrpl/peerfinder/detail/Counts.h +unsigned-integer-overflow:xrpl/protocol/nft.h + +# Rippled intentional overflows and operations +# STAmount uses intentional negation of INT64_MIN and overflow in arithmetic +signed-integer-overflow:src/libxrpl/protocol/STAmount.cpp +unsigned-integer-overflow:src/libxrpl/protocol/STAmount.cpp + +# XRPAmount test intentional overflows +signed-integer-overflow:src/test/basics/XRPAmount_test.cpp + +# Peerfinder intentional overflow in counter arithmetic +unsigned-integer-overflow:src/xrpld/peerfinder/detail/Counts.h + +# Signed integer overflow suppressions +signed-integer-overflow:src/test/beast/LexicalCast_test.cpp + +# External library suppressions +unsigned-integer-overflow:nudb/detail/xxhash.hpp + +# Protobuf intentional overflows in hash functions +# Protobuf uses intentional unsigned overflow for hash computation (stringpiece.h:393) +unsigned-integer-overflow:google/protobuf/stubs/stringpiece.h + +# gRPC intentional overflows +# gRPC uses intentional overflow in timer calculations +unsigned-integer-overflow:grpc +unsigned-integer-overflow:timer_manager.cc + +# Standard library intentional overflows +# These are intentional overflows in random number generation and character conversion +unsigned-integer-overflow:__random/seed_seq.h +unsigned-integer-overflow:__charconv/traits.h + + +# Suppress errors in RocksDB +# RocksDB uses intentional unsigned integer overflows in hash functions and CRC calculations +unsigned-integer-overflow:rocks*/*/util/xxhash.h +unsigned-integer-overflow:rocks*/*/util/xxph3.h +unsigned-integer-overflow:rocks*/*/util/hash.cc +unsigned-integer-overflow:rocks*/*/util/crc32c.cc +unsigned-integer-overflow:rocks*/*/util/crc32c.h +unsigned-integer-overflow:rocks*/*/include/rocksdb/utilities/options_type.h +unsigned-integer-overflow:rocks*/*/table/format.h +unsigned-integer-overflow:rocks*/*/table/format.cc +unsigned-integer-overflow:rocks*/*/table/block_based/block_based_table_builder.cc +unsigned-integer-overflow:rocks*/*/table/block_based/reader_common.cc +unsigned-integer-overflow:rocks*/*/db/version_set.cc + +# RocksDB misaligned loads (intentional for performance on ARM64) +alignment:rocks*/*/util/crc32c_arm64.cc + +# nudb intentional overflows in hash functions +unsigned-integer-overflow:nudb/detail/xxhash.hpp +alignment:nudb/detail/xxhash.hpp + +# Snappy compression library intentional overflows +unsigned-integer-overflow:snappy.cc + +# Abseil intentional overflows +unsigned-integer-overflow:absl/strings/numbers.cc +unsigned-integer-overflow:absl/strings/internal/cord_rep_flat.h +unsigned-integer-overflow:absl/base/internal/low_level_alloc.cc +unsigned-integer-overflow:absl/hash/internal/hash.h +unsigned-integer-overflow:absl/container/internal/raw_hash_set.h + +# Standard library intentional overflows in chrono duration arithmetic +unsigned-integer-overflow:__chrono/duration.h + +# Suppress undefined errors in RocksDB and nudb +undefined:rocks.*/*/util/crc32c_arm64.cc +undefined:rocks.*/*/util/xxhash.h +undefined:nudb diff --git a/src/libxrpl/basics/Archive.cpp b/src/libxrpl/basics/Archive.cpp index e60b2f12cf..a4100e8196 100644 --- a/src/libxrpl/basics/Archive.cpp +++ b/src/libxrpl/basics/Archive.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,20 +11,16 @@ #include #include -namespace ripple { +namespace xrpl { void -extractTarLz4( - boost::filesystem::path const& src, - boost::filesystem::path const& dst) +extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst) { if (!is_regular_file(src)) Throw("Invalid source file"); - using archive_ptr = - std::unique_ptr; - archive_ptr ar{ - archive_read_new(), [](struct archive* a) { archive_read_free(a); }}; + using archive_ptr = std::unique_ptr; + archive_ptr ar{archive_read_new(), [](struct archive* a) { archive_read_free(a); }}; if (!ar) Throw("Failed to allocate archive"); @@ -54,22 +31,18 @@ extractTarLz4( Throw(archive_error_string(ar.get())); // Examples suggest this block size - if (archive_read_open_filename(ar.get(), src.string().c_str(), 10240) < - ARCHIVE_OK) + if (archive_read_open_filename(ar.get(), src.string().c_str(), 10240) < ARCHIVE_OK) { Throw(archive_error_string(ar.get())); } - archive_ptr aw{archive_write_disk_new(), [](struct archive* a) { - archive_write_free(a); - }}; + archive_ptr aw{archive_write_disk_new(), [](struct archive* a) { archive_write_free(a); }}; if (!aw) Throw("Failed to allocate archive"); if (archive_write_disk_set_options( - aw.get(), - ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | - ARCHIVE_EXTRACT_FFLAGS) < ARCHIVE_OK) + aw.get(), ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS) < + ARCHIVE_OK) { Throw(archive_error_string(aw.get())); } @@ -87,8 +60,7 @@ extractTarLz4( if (result < ARCHIVE_OK) Throw(archive_error_string(ar.get())); - archive_entry_set_pathname( - entry, (dst / archive_entry_pathname(entry)).string().c_str()); + archive_entry_set_pathname(entry, (dst / archive_entry_pathname(entry)).string().c_str()); if (archive_write_header(aw.get(), entry) < ARCHIVE_OK) Throw(archive_error_string(aw.get())); @@ -105,8 +77,7 @@ extractTarLz4( if (result < ARCHIVE_OK) Throw(archive_error_string(ar.get())); - if (archive_write_data_block(aw.get(), buf, sz, offset) < - ARCHIVE_OK) + if (archive_write_data_block(aw.get(), buf, sz, offset) < ARCHIVE_OK) { Throw(archive_error_string(aw.get())); } @@ -118,4 +89,4 @@ extractTarLz4( } } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/BasicConfig.cpp b/src/libxrpl/basics/BasicConfig.cpp index 7d6f09b391..64e80c63ec 100644 --- a/src/libxrpl/basics/BasicConfig.cpp +++ b/src/libxrpl/basics/BasicConfig.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { Section::Section(std::string const& name) : name_(name) { @@ -49,7 +30,7 @@ Section::append(std::vector const& lines) // '=' static boost::regex const re1( "^" // start of line - "(?:\\s*)" // whitespace (optonal) + "(?:\\s*)" // whitespace (optional) "([a-zA-Z][_a-zA-Z0-9]*)" // "(?:\\s*)" // whitespace (optional) "(?:=)" // '=' @@ -149,15 +130,9 @@ BasicConfig::section(std::string const& name) const } void -BasicConfig::overwrite( - std::string const& section, - std::string const& key, - std::string const& value) +BasicConfig::overwrite(std::string const& section, std::string const& key, std::string const& value) { - auto const result = map_.emplace( - std::piecewise_construct, - std::make_tuple(section), - std::make_tuple(section)); + auto const result = map_.emplace(std::piecewise_construct, std::make_tuple(section), std::make_tuple(section)); result.first->second.set(key, value); } @@ -186,10 +161,8 @@ BasicConfig::build(IniFileSections const& ifs) { for (auto const& entry : ifs) { - auto const result = map_.emplace( - std::piecewise_construct, - std::make_tuple(entry.first), - std::make_tuple(entry.first)); + auto const result = + map_.emplace(std::piecewise_construct, std::make_tuple(entry.first), std::make_tuple(entry.first)); result.first->second.append(entry.second); } } @@ -202,4 +175,4 @@ operator<<(std::ostream& ss, BasicConfig const& c) return ss; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/CountedObject.cpp b/src/libxrpl/basics/CountedObject.cpp index d3b9455480..bcdca9dfa4 100644 --- a/src/libxrpl/basics/CountedObject.cpp +++ b/src/libxrpl/basics/CountedObject.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { CountedObjects& CountedObjects::getInstance() noexcept @@ -55,4 +36,4 @@ CountedObjects::getCounts(int minimumThreshold) const return counts; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/FileUtilities.cpp b/src/libxrpl/basics/FileUtilities.cpp index ffb9792614..35cc4350ef 100644 --- a/src/libxrpl/basics/FileUtilities.cpp +++ b/src/libxrpl/basics/FileUtilities.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -34,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { std::string getFileContents( @@ -64,9 +45,7 @@ getFileContents( return {}; } - std::string const result{ - std::istreambuf_iterator{fileStream}, - std::istreambuf_iterator{}}; + std::string const result{std::istreambuf_iterator{fileStream}, std::istreambuf_iterator{}}; if (fileStream.bad()) { @@ -78,16 +57,12 @@ getFileContents( } void -writeFileContents( - boost::system::error_code& ec, - boost::filesystem::path const& destPath, - std::string const& contents) +writeFileContents(boost::system::error_code& ec, boost::filesystem::path const& destPath, std::string const& contents) { using namespace boost::filesystem; using namespace boost::system::errc; - std::ofstream fileStream( - destPath.string(), std::ios::out | std::ios::trunc); + std::ofstream fileStream(destPath.string(), std::ios::out | std::ios::trunc); if (!fileStream) { @@ -104,4 +79,4 @@ writeFileContents( } } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 95419dda20..fc5100a152 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,12 +17,9 @@ #include #include -namespace ripple { +namespace xrpl { -Logs::Sink::Sink( - std::string const& partition, - beast::severities::Severity thresh, - Logs& logs) +Logs::Sink::Sink(std::string const& partition, beast::severities::Severity thresh, Logs& logs) : beast::Journal::Sink(thresh, false), logs_(logs), partition_(partition) { } @@ -56,9 +34,7 @@ Logs::Sink::write(beast::severities::Severity level, std::string const& text) } void -Logs::Sink::writeAlways( - beast::severities::Severity level, - std::string const& text) +Logs::Sink::writeAlways(beast::severities::Severity level, std::string const& text) { logs_.write(level, partition_, text, console()); } @@ -83,8 +59,7 @@ Logs::File::open(boost::filesystem::path const& path) bool wasOpened = false; // VFALCO TODO Make this work with Unicode file paths - std::unique_ptr stream( - new std::ofstream(path.c_str(), std::fstream::app)); + std::unique_ptr stream(new std::ofstream(path.c_str(), std::fstream::app)); if (stream->good()) { @@ -131,8 +106,7 @@ Logs::File::writeln(char const* text) //------------------------------------------------------------------------------ -Logs::Logs(beast::severities::Severity thresh) - : thresh_(thresh) // default severity +Logs::Logs(beast::severities::Severity thresh) : thresh_(thresh) // default severity { } @@ -189,11 +163,7 @@ Logs::partition_severities() const } void -Logs::write( - beast::severities::Severity level, - std::string const& partition, - std::string const& text, - bool console) +Logs::write(beast::severities::Severity level, std::string const& partition, std::string const& text, bool console) { std::string s; format(s, text, level, partition); @@ -241,7 +211,7 @@ Logs::fromSeverity(beast::severities::Severity level) // LCOV_EXCL_START default: - UNREACHABLE("ripple::Logs::fromSeverity : invalid severity"); + UNREACHABLE("xrpl::Logs::fromSeverity : invalid severity"); [[fallthrough]]; // LCOV_EXCL_STOP case kFatal: @@ -269,7 +239,7 @@ Logs::toSeverity(LogSeverity level) return kError; // LCOV_EXCL_START default: - UNREACHABLE("ripple::Logs::toSeverity : invalid severity"); + UNREACHABLE("xrpl::Logs::toSeverity : invalid severity"); [[fallthrough]]; // LCOV_EXCL_STOP case lsFATAL: @@ -298,7 +268,7 @@ Logs::toString(LogSeverity s) return "Fatal"; // LCOV_EXCL_START default: - UNREACHABLE("ripple::Logs::toString : invalid severity"); + UNREACHABLE("xrpl::Logs::toString : invalid severity"); return "Unknown"; // LCOV_EXCL_STOP } @@ -316,8 +286,7 @@ Logs::fromString(std::string const& s) if (boost::iequals(s, "info") || boost::iequals(s, "information")) return lsINFO; - if (boost::iequals(s, "warn") || boost::iequals(s, "warning") || - boost::iequals(s, "warnings")) + if (boost::iequals(s, "warn") || boost::iequals(s, "warning") || boost::iequals(s, "warnings")) return lsWARNING; if (boost::iequals(s, "error") || boost::iequals(s, "errors")) @@ -364,7 +333,7 @@ Logs::format( break; // LCOV_EXCL_START default: - UNREACHABLE("ripple::Logs::format : invalid severity"); + UNREACHABLE("xrpl::Logs::format : invalid severity"); [[fallthrough]]; // LCOV_EXCL_STOP case kFatal: @@ -478,4 +447,4 @@ debugLog() return beast::Journal(debugSink().get()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index f43288b57b..1651e8aba2 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -1,23 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include +// Keep Number.h first to ensure it can build without hidden dependencies +#include #include #include @@ -32,16 +15,19 @@ #include #ifdef _MSC_VER -#pragma message("Using boost::multiprecision::uint128_t") +#pragma message("Using boost::multiprecision::uint128_t and int128_t") #include using uint128_t = boost::multiprecision::uint128_t; +using int128_t = boost::multiprecision::int128_t; #else // !defined(_MSC_VER) using uint128_t = __uint128_t; +using int128_t = __int128_t; #endif // !defined(_MSC_VER) -namespace ripple { +namespace xrpl { thread_local Number::rounding_mode Number::mode_ = Number::to_nearest; +thread_local std::reference_wrapper Number::range_ = largeRange; Number::rounding_mode Number::getround() @@ -55,12 +41,29 @@ Number::setround(rounding_mode mode) return std::exchange(mode_, mode); } +MantissaRange::mantissa_scale +Number::getMantissaScale() +{ + return range_.get().scale; +} + +void +Number::setMantissaScale(MantissaRange::mantissa_scale scale) +{ + if (scale != MantissaRange::small && scale != MantissaRange::large) + LogicError("Unknown mantissa scale"); + range_ = scale == MantissaRange::small ? smallRange : largeRange; +} + // Guard -// The Guard class is used to tempoarily add extra digits of -// preicision to an operation. This enables the final result +// The Guard class is used to temporarily add extra digits of +// precision to an operation. This enables the final result // to be correctly rounded to the internal precision of Number. +template +concept UnsignedMantissa = std::is_unsigned_v || std::is_same_v; + class Number::Guard { std::uint64_t digits_; // 16 decimal guard digits @@ -81,8 +84,9 @@ public: is_negative() const noexcept; // add a digit + template void - push(unsigned d) noexcept; + push(T d) noexcept; // recover a digit unsigned @@ -93,6 +97,34 @@ public: // tie, round towards even. int round() noexcept; + + // Modify the result to the correctly rounded value + template + void + doRoundUp( + bool& negative, + T& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa, + std::string location); + + // Modify the result to the correctly rounded value + template + void + doRoundDown(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa); + + // Modify the result to the correctly rounded value + void + doRound(rep& drops, std::string location); + +private: + void + doPush(unsigned d) noexcept; + + template + void + bringIntoRange(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa); }; inline void @@ -114,13 +146,20 @@ Number::Guard::is_negative() const noexcept } inline void -Number::Guard::push(unsigned d) noexcept +Number::Guard::doPush(unsigned d) noexcept { - xbit_ = xbit_ || (digits_ & 0x0000'0000'0000'000F) != 0; + xbit_ = xbit_ || ((digits_ & 0x0000'0000'0000'000F) != 0); digits_ >>= 4; digits_ |= (d & 0x0000'0000'0000'000FULL) << 60; } +template +inline void +Number::Guard::push(T d) noexcept +{ + doPush(static_cast(d)); +} + inline unsigned Number::Guard::pop() noexcept { @@ -170,22 +209,171 @@ Number::Guard::round() noexcept return 0; } +template +void +Number::Guard::bringIntoRange(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa) +{ + // Bring mantissa back into the minMantissa / maxMantissa range AFTER + // rounding + if (mantissa < minMantissa) + { + mantissa *= 10; + --exponent; + } + if (exponent < minExponent) + { + constexpr Number zero = Number{}; + + negative = zero.negative_; + mantissa = zero.mantissa_; + exponent = zero.exponent_; + } +} + +template +void +Number::Guard::doRoundUp( + bool& negative, + T& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa, + std::string location) +{ + auto r = round(); + if (r == 1 || (r == 0 && (mantissa & 1) == 1)) + { + ++mantissa; + // Ensure mantissa after incrementing fits within both the + // min/maxMantissa range and is a valid "rep". + if (mantissa > maxMantissa || mantissa > maxRep) + { + mantissa /= 10; + ++exponent; + } + } + bringIntoRange(negative, mantissa, exponent, minMantissa); + if (exponent > maxExponent) + throw std::overflow_error(location); +} + +template +void +Number::Guard::doRoundDown(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa) +{ + auto r = round(); + if (r == 1 || (r == 0 && (mantissa & 1) == 1)) + { + --mantissa; + if (mantissa < minMantissa) + { + mantissa *= 10; + --exponent; + } + } + bringIntoRange(negative, mantissa, exponent, minMantissa); +} + +// Modify the result to the correctly rounded value +void +Number::Guard::doRound(rep& drops, std::string location) +{ + auto r = round(); + if (r == 1 || (r == 0 && (drops & 1) == 1)) + { + if (drops >= maxRep) + { + static_assert(sizeof(internalrep) == sizeof(rep)); + // This should be impossible, because it's impossible to represent + // "maxRep + 0.6" in Number, regardless of the scale. There aren't + // enough digits available. You'd either get a mantissa of "maxRep" + // or "(maxRep + 1) / 10", neither of which will round up when + // converting to rep, though the latter might overflow _before_ + // rounding. + throw std::overflow_error(location); // LCOV_EXCL_LINE + } + ++drops; + } + if (is_negative()) + drops = -drops; +} + // Number -constexpr Number one{1000000000000000, -15, Number::unchecked{}}; - -void -Number::normalize() +// Safely convert rep (int64) mantissa to internalrep (uint64). If the rep is +// negative, returns the positive value. This takes a little extra work because +// converting std::numeric_limits::min() flirts with UB, and can +// vary across compilers. +Number::internalrep +Number::externalToInternal(rep mantissa) { + // If the mantissa is already positive, just return it + if (mantissa >= 0) + return mantissa; + // If the mantissa is negative, but fits within the positive range of rep, + // return it negated + if (mantissa >= -std::numeric_limits::max()) + return -mantissa; + + // If the mantissa doesn't fit within the positive range, convert to + // int128_t, negate that, and cast it back down to the internalrep + // In practice, this is only going to cover the case of + // std::numeric_limits::min(). + int128_t temp = mantissa; + return static_cast(-temp); +} + +constexpr Number +Number::oneSmall() +{ + return Number{false, Number::smallRange.min, -Number::smallRange.log, Number::unchecked{}}; +}; + +constexpr Number oneSml = Number::oneSmall(); + +constexpr Number +Number::oneLarge() +{ + return Number{false, Number::largeRange.min, -Number::largeRange.log, Number::unchecked{}}; +}; + +constexpr Number oneLrg = Number::oneLarge(); + +Number +Number::one() +{ + if (&range_.get() == &smallRange) + return oneSml; + XRPL_ASSERT(&range_.get() == &largeRange, "Number::one() : valid range_"); + return oneLrg; +} + +// Use the member names in this static function for now so the diff is cleaner +// TODO: Rename the function parameters to get rid of the "_" suffix +template +void +doNormalize( + bool& negative, + T& mantissa_, + int& exponent_, + MantissaRange::rep const& minMantissa, + MantissaRange::rep const& maxMantissa) +{ + auto constexpr minExponent = Number::minExponent; + auto constexpr maxExponent = Number::maxExponent; + auto constexpr maxRep = Number::maxRep; + + using Guard = Number::Guard; + + constexpr Number zero = Number{}; if (mantissa_ == 0) { - *this = Number{}; + mantissa_ = zero.mantissa_; + exponent_ = zero.exponent_; + negative = zero.negative_; return; } - bool const negative = (mantissa_ < 0); - auto m = static_cast>(mantissa_); - if (negative) - m = -m; + auto m = mantissa_; while ((m < minMantissa) && (exponent_ > minExponent)) { m *= 10; @@ -202,68 +390,145 @@ Number::normalize() m /= 10; ++exponent_; } - mantissa_ = m; - if ((exponent_ < minExponent) || (mantissa_ < minMantissa)) + if ((exponent_ < minExponent) || (m < minMantissa)) { - *this = Number{}; + mantissa_ = zero.mantissa_; + exponent_ = zero.exponent_; + negative = zero.negative_; return; } - auto r = g.round(); - if (r == 1 || (r == 0 && (mantissa_ & 1) == 1)) + // When using the largeRange, "m" needs fit within an int64, even if + // the final mantissa_ is going to end up larger to fit within the + // MantissaRange. Cut it down here so that the rounding will be done while + // it's smaller. + // + // Example: 9,900,000,000,000,123,456 > 9,223,372,036,854,775,807, + // so "m" will be modified to 990,000,000,000,012,345. Then that value + // will be rounded to 990,000,000,000,012,345 or + // 990,000,000,000,012,346, depending on the rounding mode. Finally, + // mantissa_ will be "m*10" so it fits within the range, and end up as + // 9,900,000,000,000,123,450 or 9,900,000,000,000,123,460. + // mantissa() will return mantissa_ / 10, and exponent() will return + // exponent_ + 1. + if (m > maxRep) { - ++mantissa_; - if (mantissa_ > maxMantissa) - { - mantissa_ /= 10; - ++exponent_; - } + if (exponent_ >= maxExponent) + throw std::overflow_error("Number::normalize 1.5"); + g.push(m % 10); + m /= 10; + ++exponent_; } - if (exponent_ > maxExponent) - throw std::overflow_error("Number::normalize 2"); + // Before modification, m should be within the min/max range. After + // modification, it must be less than maxRep. In other words, the original + // value should have been no more than maxRep * 10. + // (maxRep * 10 > maxMantissa) + XRPL_ASSERT_PARTS(m <= maxRep, "xrpl::doNormalize", "intermediate mantissa fits in int64"); + mantissa_ = m; - if (negative) - mantissa_ = -mantissa_; + g.doRoundUp(negative, mantissa_, exponent_, minMantissa, maxMantissa, "Number::normalize 2"); + XRPL_ASSERT_PARTS( + mantissa_ >= minMantissa && mantissa_ <= maxMantissa, "xrpl::doNormalize", "final mantissa fits in range"); +} + +template <> +void +Number::normalize( + bool& negative, + uint128_t& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa) +{ + doNormalize(negative, mantissa, exponent, minMantissa, maxMantissa); +} + +template <> +void +Number::normalize( + bool& negative, + unsigned long long& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa) +{ + doNormalize(negative, mantissa, exponent, minMantissa, maxMantissa); +} + +template <> +void +Number::normalize( + bool& negative, + unsigned long& mantissa, + int& exponent, + internalrep const& minMantissa, + internalrep const& maxMantissa) +{ + doNormalize(negative, mantissa, exponent, minMantissa, maxMantissa); +} + +void +Number::normalize() +{ + auto const& range = range_.get(); + normalize(negative_, mantissa_, exponent_, range.min, range.max); +} + +// Copy the number, but set a new exponent. Because the mantissa doesn't change, +// the result will be "mostly" normalized, but the exponent could go out of +// range. +Number +Number::shiftExponent(int exponentDelta) const +{ + XRPL_ASSERT_PARTS(isnormal(), "xrpl::Number::shiftExponent", "normalized"); + auto const newExponent = exponent_ + exponentDelta; + if (newExponent >= maxExponent) + throw std::overflow_error("Number::shiftExponent"); + if (newExponent < minExponent) + { + return Number{}; + } + Number const result{negative_, mantissa_, newExponent, unchecked{}}; + XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::Number::shiftExponent", "result is normalized"); + return result; } Number& Number::operator+=(Number const& y) { - if (y == Number{}) + constexpr Number zero = Number{}; + if (y == zero) return *this; - if (*this == Number{}) + if (*this == zero) { *this = y; return *this; } if (*this == -y) { - *this = Number{}; + *this = zero; return *this; } - XRPL_ASSERT( - isnormal() && y.isnormal(), - "ripple::Number::operator+=(Number) : is normal"); - auto xm = mantissa(); - auto xe = exponent(); - int xn = 1; - if (xm < 0) - { - xm = -xm; - xn = -1; - } - auto ym = y.mantissa(); - auto ye = y.exponent(); - int yn = 1; - if (ym < 0) - { - ym = -ym; - yn = -1; - } + + XRPL_ASSERT(isnormal() && y.isnormal(), "xrpl::Number::operator+=(Number) : is normal"); + // *n = negative + // *s = sign + // *m = mantissa + // *e = exponent + + // Need to use uint128_t, because large mantissas can overflow when added + // together. + bool xn = negative_; + uint128_t xm = mantissa_; + auto xe = exponent_; + + bool yn = y.negative_; + uint128_t ym = y.mantissa_; + auto ye = y.exponent_; Guard g; if (xe < ye) { - if (xn == -1) + if (xn) g.set_negative(); do { @@ -274,7 +539,7 @@ Number::operator+=(Number const& y) } else if (xe > ye) { - if (yn == -1) + if (yn) g.set_negative(); do { @@ -283,27 +548,21 @@ Number::operator+=(Number const& y) ++ye; } while (xe > ye); } + + auto const& range = range_.get(); + auto const& minMantissa = range.min; + auto const& maxMantissa = range.max; + if (xn == yn) { xm += ym; - if (xm > maxMantissa) + if (xm > maxMantissa || xm > maxRep) { g.push(xm % 10); xm /= 10; ++xe; } - auto r = g.round(); - if (r == 1 || (r == 0 && (xm & 1) == 1)) - { - ++xm; - if (xm > maxMantissa) - { - xm /= 10; - ++xe; - } - } - if (xe > maxExponent) - throw std::overflow_error("Number::addition overflow"); + g.doRoundUp(xn, xm, xe, minMantissa, maxMantissa, "Number::addition overflow"); } else { @@ -317,30 +576,19 @@ Number::operator+=(Number const& y) xe = ye; xn = yn; } - while (xm < minMantissa) + while (xm < minMantissa && xm * 10 <= maxRep) { xm *= 10; xm -= g.pop(); --xe; } - auto r = g.round(); - if (r == 1 || (r == 0 && (xm & 1) == 1)) - { - --xm; - if (xm < minMantissa) - { - xm *= 10; - --xe; - } - } - if (xe < minExponent) - { - xm = 0; - xe = Number{}.exponent_; - } + g.doRoundDown(xn, xm, xe, minMantissa); } - mantissa_ = xm * xn; + + negative_ = xn; + mantissa_ = static_cast(xm); exponent_ = xe; + normalize(); return *this; } @@ -375,39 +623,42 @@ divu10(uint128_t& u) Number& Number::operator*=(Number const& y) { - if (*this == Number{}) + constexpr Number zero = Number{}; + if (*this == zero) return *this; - if (y == Number{}) + if (y == zero) { *this = y; return *this; } - XRPL_ASSERT( - isnormal() && y.isnormal(), - "ripple::Number::operator*=(Number) : is normal"); - auto xm = mantissa(); - auto xe = exponent(); - int xn = 1; - if (xm < 0) - { - xm = -xm; - xn = -1; - } - auto ym = y.mantissa(); - auto ye = y.exponent(); - int yn = 1; - if (ym < 0) - { - ym = -ym; - yn = -1; - } + // *n = negative + // *s = sign + // *m = mantissa + // *e = exponent + + bool xn = negative_; + int xs = xn ? -1 : 1; + internalrep xm = mantissa_; + auto xe = exponent_; + + bool yn = y.negative_; + int ys = yn ? -1 : 1; + internalrep ym = y.mantissa_; + auto ye = y.exponent_; + auto zm = uint128_t(xm) * uint128_t(ym); auto ze = xe + ye; - auto zn = xn * yn; + auto zs = xs * ys; + bool zn = (zs == -1); Guard g; - if (zn == -1) + if (zn) g.set_negative(); - while (zm > maxMantissa) + + auto const& range = range_.get(); + auto const& minMantissa = range.min; + auto const& maxMantissa = range.max; + + while (zm > maxMantissa || zm > maxRep) { // The following is optimization for: // g.push(static_cast(zm % 10)); @@ -415,76 +666,121 @@ Number::operator*=(Number const& y) g.push(divu10(zm)); ++ze; } - xm = static_cast(zm); + xm = static_cast(zm); xe = ze; - auto r = g.round(); - if (r == 1 || (r == 0 && (xm & 1) == 1)) - { - ++xm; - if (xm > maxMantissa) - { - xm /= 10; - ++xe; - } - } - if (xe < minExponent) - { - xm = 0; - xe = Number{}.exponent_; - } - if (xe > maxExponent) - throw std::overflow_error( - "Number::multiplication overflow : exponent is " + - std::to_string(xe)); - mantissa_ = xm * zn; + g.doRoundUp( + zn, xm, xe, minMantissa, maxMantissa, "Number::multiplication overflow : exponent is " + std::to_string(xe)); + negative_ = zn; + mantissa_ = xm; exponent_ = xe; - XRPL_ASSERT( - isnormal() || *this == Number{}, - "ripple::Number::operator*=(Number) : result is normal"); + + normalize(); return *this; } Number& Number::operator/=(Number const& y) { - if (y == Number{}) + constexpr Number zero = Number{}; + if (y == zero) throw std::overflow_error("Number: divide by 0"); - if (*this == Number{}) + if (*this == zero) return *this; - int np = 1; - auto nm = mantissa(); - auto ne = exponent(); - if (nm < 0) + // n* = numerator + // d* = denominator + // *p = negative (positive?) + // *s = sign + // *m = mantissa + // *e = exponent + + bool np = negative_; + int ns = (np ? -1 : 1); + auto nm = mantissa_; + auto ne = exponent_; + + bool dp = y.negative_; + int ds = (dp ? -1 : 1); + auto dm = y.mantissa_; + auto de = y.exponent_; + + auto const& range = range_.get(); + auto const& minMantissa = range.min; + auto const& maxMantissa = range.max; + + // Shift by 10^17 gives greatest precision while not overflowing + // uint128_t or the cast back to int64_t + // TODO: Can/should this be made bigger for largeRange? + // log(2^128,10) ~ 38.5 + // largeRange.log = 18, fits in 10^19 + // f can be up to 10^(38-19) = 10^19 safely + static_assert(smallRange.log == 15); + static_assert(largeRange.log == 18); + bool small = Number::getMantissaScale() == MantissaRange::small; + uint128_t const f = small ? 100'000'000'000'000'000 : 10'000'000'000'000'000'000ULL; + XRPL_ASSERT_PARTS(f >= minMantissa * 10, "Number::operator/=", "factor expected size"); + + // unsigned denominator + auto const dmu = static_cast(dm); + // correctionFactor can be anything between 10 and f, depending on how much + // extra precision we want to only use for rounding with the + // largeRange. Three digits seems like plenty, and is more than + // the smallRange uses. + uint128_t const correctionFactor = 1'000; + + auto const numerator = uint128_t(nm) * f; + + auto zm = numerator / dmu; + auto ze = ne - de - (small ? 17 : 19); + bool zn = (ns * ds) < 0; + if (!small) { - nm = -nm; - np = -1; + // Virtually multiply numerator by correctionFactor. Since that would + // overflow in the existing uint128_t, we'll do that part separately. + // The math for this would work for small mantissas, but we need to + // preserve existing behavior. + // + // Consider: + // ((numerator * correctionFactor) / dmu) / correctionFactor + // = ((numerator / dmu) * correctionFactor) / correctionFactor) + // + // But that assumes infinite precision. With integer math, this is + // equivalent to + // + // = ((numerator / dmu * correctionFactor) + // + ((numerator % dmu) * correctionFactor) / dmu) / correctionFactor + // + // We have already set `mantissa_ = numerator / dmu`. Now we + // compute `remainder = numerator % dmu`, and if it is + // nonzero, we do the rest of the arithmetic. If it's zero, we can skip + // it. + auto const remainder = (numerator % dmu); + if (remainder != 0) + { + zm *= correctionFactor; + auto const correction = remainder * correctionFactor / dmu; + zm += correction; + // divide by 1000 by moving the exponent, so we don't lose the + // integer value we just computed + ze -= 3; + } } - int dp = 1; - auto dm = y.mantissa(); - auto de = y.exponent(); - if (dm < 0) - { - dm = -dm; - dp = -1; - } - // Shift by 10^17 gives greatest precision while not overflowing uint128_t - // or the cast back to int64_t - uint128_t const f = 100'000'000'000'000'000; - mantissa_ = static_cast(uint128_t(nm) * f / uint128_t(dm)); - exponent_ = ne - de - 17; - mantissa_ *= np * dp; - normalize(); + normalize(zn, zm, ze, minMantissa, maxMantissa); + negative_ = zn; + mantissa_ = static_cast(zm); + exponent_ = ze; + XRPL_ASSERT_PARTS(isnormal(), "xrpl::Number::operator/=", "result is normalized"); + return *this; } Number::operator rep() const { - rep drops = mantissa_; - int offset = exponent_; + rep drops = mantissa(); + int offset = exponent(); Guard g; if (drops != 0) { - if (drops < 0) + if (negative_) { g.set_negative(); drops = -drops; @@ -496,53 +792,65 @@ Number::operator rep() const } for (; offset > 0; --offset) { - if (drops > std::numeric_limits::max() / 10) + if (drops > maxRep / 10) throw std::overflow_error("Number::operator rep() overflow"); drops *= 10; } - auto r = g.round(); - if (r == 1 || (r == 0 && (drops & 1) == 1)) - { - ++drops; - } - if (g.is_negative()) - drops = -drops; + g.doRound(drops, "Number::operator rep() rounding overflow"); } return drops; } +Number +Number::truncate() const noexcept +{ + if (exponent_ >= 0 || mantissa_ == 0) + return *this; + + Number ret = *this; + while (ret.exponent_ < 0 && ret.mantissa_ != 0) + { + ret.exponent_ += 1; + ret.mantissa_ /= rep(10); + } + // We are guaranteed that normalize() will never throw an exception + // because exponent is either negative or zero at this point. + ret.normalize(); + return ret; +} + std::string to_string(Number const& amount) { // keep full internal accuracy, but make more human friendly if possible - if (amount == Number{}) + constexpr Number zero = Number{}; + if (amount == zero) return "0"; - auto const exponent = amount.exponent(); - auto mantissa = amount.mantissa(); + auto exponent = amount.exponent_; + auto mantissa = amount.mantissa_; + bool const negative = amount.negative_; // Use scientific notation for exponents that are too small or too large - if (((exponent != 0) && ((exponent < -25) || (exponent > -5)))) + auto const rangeLog = Number::mantissaLog(); + if (((exponent != 0) && ((exponent < -(rangeLog + 10)) || (exponent > -(rangeLog - 10))))) { - std::string ret = std::to_string(mantissa); + while (mantissa != 0 && mantissa % 10 == 0 && exponent < Number::maxExponent) + { + mantissa /= 10; + ++exponent; + } + std::string ret = negative ? "-" : ""; + ret.append(std::to_string(mantissa)); ret.append(1, 'e'); ret.append(std::to_string(exponent)); return ret; } - bool negative = false; + XRPL_ASSERT(exponent + 43 > 0, "xrpl::to_string(Number) : minimum exponent"); - if (mantissa < 0) - { - mantissa = -mantissa; - negative = true; - } - - XRPL_ASSERT( - exponent + 43 > 0, "ripple::to_string(Number) : minimum exponent"); - - ptrdiff_t const pad_prefix = 27; - ptrdiff_t const pad_suffix = 23; + ptrdiff_t const pad_prefix = rangeLog + 12; + ptrdiff_t const pad_suffix = rangeLog + 8; std::string const raw_value(std::to_string(mantissa)); std::string val; @@ -552,7 +860,7 @@ to_string(Number const& amount) val.append(raw_value); val.append(pad_suffix, '0'); - ptrdiff_t const offset(exponent + 43); + ptrdiff_t const offset(exponent + pad_prefix + rangeLog + 1); auto pre_from(val.begin()); auto const pre_to(val.begin() + offset); @@ -565,9 +873,7 @@ to_string(Number const& amount) if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - XRPL_ASSERT( - post_to >= post_from, - "ripple::to_string(Number) : first distance check"); + XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -576,15 +882,11 @@ to_string(Number const& amount) if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - XRPL_ASSERT( - post_to >= post_from, - "ripple::to_string(Number) : second distance check"); + XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : second distance check"); - post_to = std::find_if( - std::make_reverse_iterator(post_to), - std::make_reverse_iterator(post_from), - [](char c) { return c != '0'; }) - .base(); + post_to = std::find_if(std::make_reverse_iterator(post_to), std::make_reverse_iterator(post_from), [](char c) { + return c != '0'; + }).base(); std::string ret; @@ -613,7 +915,7 @@ Number power(Number const& f, unsigned n) { if (n == 0) - return one; + return Number::one(); if (n == 1) return f; auto r = power(f, n / 2); @@ -635,6 +937,9 @@ power(Number const& f, unsigned n) Number root(Number f, unsigned d) { + constexpr Number zero = Number{}; + auto const one = Number::one(); + if (f == one || d == 1) return f; if (d == 0) @@ -642,16 +947,16 @@ root(Number f, unsigned d) if (f == -one) return one; if (abs(f) < one) - return Number{}; + return zero; throw std::overflow_error("Number::root infinity"); } - if (f < Number{} && d % 2 == 0) + if (f < zero && d % 2 == 0) throw std::overflow_error("Number::root nan"); - if (f == Number{}) + if (f == zero) return f; // Scale f into the range (0, 1) such that f's exponent is a multiple of d - auto e = f.exponent() + 16; + auto e = f.exponent_ + Number::mantissaLog() + 1; auto const di = static_cast(d); auto ex = [e = e, di = di]() // Euclidean remainder of e/d { @@ -662,9 +967,11 @@ root(Number f, unsigned d) return di - k2; }(); e += ex; - f = Number{f.mantissa(), f.exponent() - e}; // f /= 10^e; + f = f.shiftExponent(-e); // f /= 10^e; + + XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root(Number, unsigned)", "f is normalized"); bool neg = false; - if (f < Number{}) + if (f < zero) { neg = true; f = -f; @@ -694,24 +1001,30 @@ root(Number f, unsigned d) } while (r != rm1 && r != rm2); // return r * 10^(e/d) to reverse scaling - return Number{r.mantissa(), r.exponent() + e / di}; + auto const result = r.shiftExponent(e / di); + XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root(Number, unsigned)", "result is normalized"); + return result; } Number root2(Number f) { + constexpr Number zero = Number{}; + auto const one = Number::one(); + if (f == one) return f; - if (f < Number{}) + if (f < zero) throw std::overflow_error("Number::root nan"); - if (f == Number{}) + if (f == zero) return f; // Scale f into the range (0, 1) such that f's exponent is a multiple of d - auto e = f.exponent() + 16; + auto e = f.exponent_ + Number::mantissaLog() + 1; if (e % 2 != 0) ++e; - f = Number{f.mantissa(), f.exponent() - e}; // f /= 10^e; + f = f.shiftExponent(-e); // f /= 10^e; + XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root2(Number)", "f is normalized"); // Quadratic least squares curve fit of f^(1/d) in the range [0, 1] auto const D = 105; @@ -732,7 +1045,10 @@ root2(Number f) } while (r != rm1 && r != rm2); // return r * 10^(e/2) to reverse scaling - return Number{r.mantissa(), r.exponent() + e / 2}; + auto const result = r.shiftExponent(e / 2); + XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root2(Number)", "result is normalized"); + + return result; } // Returns f^(n/d) @@ -740,6 +1056,9 @@ root2(Number f) Number power(Number const& f, unsigned n, unsigned d) { + constexpr Number zero = Number{}; + auto const one = Number::one(); + if (f == one) return f; auto g = std::gcd(n, d); @@ -750,7 +1069,7 @@ power(Number const& f, unsigned n, unsigned d) if (f == -one) return one; if (abs(f) < one) - return Number{}; + return zero; // abs(f) > one throw std::overflow_error("Number::power infinity"); } @@ -758,9 +1077,9 @@ power(Number const& f, unsigned n, unsigned d) return one; n /= g; d /= g; - if ((n % 2) == 1 && (d % 2) == 0 && f < Number{}) + if ((n % 2) == 1 && (d % 2) == 0 && f < zero) throw std::overflow_error("Number::power nan"); return root(power(f, n), d); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index 1b52465a80..78346870a7 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -45,7 +26,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Mix-in to track when all pending I/O is complete. Derived classes must be callable with this signature: @@ -63,9 +44,7 @@ public: ~AsyncObject() { // Destroying the object with I/O pending? Not a clean exit! - XRPL_ASSERT( - m_pending.load() == 0, - "ripple::AsyncObject::~AsyncObject : nothing pending"); + XRPL_ASSERT(m_pending.load() == 0, "xrpl::AsyncObject::~AsyncObject : nothing pending"); } /** RAII container that maintains the count of pending I/O. @@ -80,8 +59,7 @@ public: ++m_owner->m_pending; } - CompletionCounter(CompletionCounter const& other) - : m_owner(other.m_owner) + CompletionCounter(CompletionCounter const& other) : m_owner(other.m_owner) { ++m_owner->m_pending; } @@ -117,8 +95,7 @@ private: std::atomic m_pending; }; -class ResolverAsioImpl : public ResolverAsio, - public AsyncObject +class ResolverAsioImpl : public ResolverAsio, public AsyncObject { public: using HostAndPort = std::pair; @@ -143,21 +120,17 @@ public: HandlerType handler; template - Work(StringSequence const& names_, HandlerType const& handler_) - : handler(handler_) + Work(StringSequence const& names_, HandlerType const& handler_) : handler(handler_) { names.reserve(names_.size()); - std::reverse_copy( - names_.begin(), names_.end(), std::back_inserter(names)); + std::reverse_copy(names_.begin(), names_.end(), std::back_inserter(names)); } }; std::deque m_work; - ResolverAsioImpl( - boost::asio::io_context& io_context, - beast::Journal journal) + ResolverAsioImpl(boost::asio::io_context& io_context, beast::Journal journal) : m_journal(journal) , m_io_context(io_context) , m_strand(boost::asio::make_strand(io_context)) @@ -170,11 +143,8 @@ public: ~ResolverAsioImpl() override { - XRPL_ASSERT( - m_work.empty(), - "ripple::ResolverAsioImpl::~ResolverAsioImpl : no pending work"); - XRPL_ASSERT( - m_stopped, "ripple::ResolverAsioImpl::~ResolverAsioImpl : stopped"); + XRPL_ASSERT(m_work.empty(), "xrpl::ResolverAsioImpl::~ResolverAsioImpl : no pending work"); + XRPL_ASSERT(m_stopped, "xrpl::ResolverAsioImpl::~ResolverAsioImpl : stopped"); } //------------------------------------------------------------------------- @@ -196,11 +166,8 @@ public: void start() override { - XRPL_ASSERT( - m_stopped == true, "ripple::ResolverAsioImpl::start : stopped"); - XRPL_ASSERT( - m_stop_called == false, - "ripple::ResolverAsioImpl::start : not stopping"); + XRPL_ASSERT(m_stopped == true, "xrpl::ResolverAsioImpl::start : stopped"); + XRPL_ASSERT(m_stop_called == false, "xrpl::ResolverAsioImpl::start : not stopping"); if (m_stopped.exchange(false) == true) { @@ -220,11 +187,7 @@ public: boost::asio::dispatch( m_io_context, boost::asio::bind_executor( - m_strand, - std::bind( - &ResolverAsioImpl::do_stop, - this, - CompletionCounter(this)))); + m_strand, std::bind(&ResolverAsioImpl::do_stop, this, CompletionCounter(this)))); JLOG(m_journal.debug()) << "Queued a stop request"; } @@ -243,28 +206,17 @@ public: } void - resolve(std::vector const& names, HandlerType const& handler) - override + resolve(std::vector const& names, HandlerType const& handler) override { - XRPL_ASSERT( - m_stop_called == false, - "ripple::ResolverAsioImpl::resolve : not stopping"); - XRPL_ASSERT( - !names.empty(), - "ripple::ResolverAsioImpl::resolve : names non-empty"); + XRPL_ASSERT(m_stop_called == false, "xrpl::ResolverAsioImpl::resolve : not stopping"); + XRPL_ASSERT(!names.empty(), "xrpl::ResolverAsioImpl::resolve : names non-empty"); // TODO NIKB use rvalue references to construct and move // reducing cost. boost::asio::dispatch( m_io_context, boost::asio::bind_executor( - m_strand, - std::bind( - &ResolverAsioImpl::do_resolve, - this, - names, - handler, - CompletionCounter(this)))); + m_strand, std::bind(&ResolverAsioImpl::do_resolve, this, names, handler, CompletionCounter(this)))); } //------------------------------------------------------------------------- @@ -272,9 +224,7 @@ public: void do_stop(CompletionCounter) { - XRPL_ASSERT( - m_stop_called == true, - "ripple::ResolverAsioImpl::do_stop : stopping"); + XRPL_ASSERT(m_stop_called == true, "xrpl::ResolverAsioImpl::do_stop : stopping"); if (m_stopped.exchange(true) == false) { @@ -305,8 +255,7 @@ public: { while (iter != results.end()) { - addresses.push_back( - beast::IPAddressConversion::from_asio(*iter)); + addresses.push_back(beast::IPAddressConversion::from_asio(*iter)); ++iter; } } @@ -315,12 +264,7 @@ public: boost::asio::post( m_io_context, - boost::asio::bind_executor( - m_strand, - std::bind( - &ResolverAsioImpl::do_work, - this, - CompletionCounter(this)))); + boost::asio::bind_executor(m_strand, std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this)))); } HostAndPort @@ -331,8 +275,7 @@ public: if (auto const result = beast::IP::Endpoint::from_string_checked(str)) { - return make_pair( - result->address().to_string(), std::to_string(result->port())); + return make_pair(result->address().to_string(), std::to_string(result->port())); } // generic name/port parsing, which doesn't work for @@ -340,16 +283,12 @@ public: // a port separator // Attempt to find the first and last non-whitespace - auto const find_whitespace = std::bind( - &std::isspace, - std::placeholders::_1, - std::locale()); + auto const find_whitespace = + std::bind(&std::isspace, std::placeholders::_1, std::locale()); - auto host_first = - std::find_if_not(str.begin(), str.end(), find_whitespace); + auto host_first = std::find_if_not(str.begin(), str.end(), find_whitespace); - auto port_last = - std::find_if_not(str.rbegin(), str.rend(), find_whitespace).base(); + auto port_last = std::find_if_not(str.rbegin(), str.rend(), find_whitespace).base(); // This should only happen for all-whitespace strings if (host_first >= port_last) @@ -366,15 +305,11 @@ public: return false; }; - auto host_last = - std::find_if(host_first, port_last, find_port_separator); + auto host_last = std::find_if(host_first, port_last, find_port_separator); - auto port_first = - std::find_if_not(host_last, port_last, find_port_separator); + auto port_first = std::find_if_not(host_last, port_last, find_port_separator); - return make_pair( - std::string(host_first, host_last), - std::string(port_first, port_last)); + return make_pair(std::string(host_first, host_last), std::string(port_first, port_last)); } void @@ -404,11 +339,7 @@ public: boost::asio::post( m_io_context, boost::asio::bind_executor( - m_strand, - std::bind( - &ResolverAsioImpl::do_work, - this, - CompletionCounter(this)))); + m_strand, std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this)))); return; } @@ -427,33 +358,23 @@ public: } void - do_resolve( - std::vector const& names, - HandlerType const& handler, - CompletionCounter) + do_resolve(std::vector const& names, HandlerType const& handler, CompletionCounter) { - XRPL_ASSERT( - !names.empty(), - "ripple::ResolverAsioImpl::do_resolve : names non-empty"); + XRPL_ASSERT(!names.empty(), "xrpl::ResolverAsioImpl::do_resolve : names non-empty"); if (m_stop_called == false) { m_work.emplace_back(names, handler); - JLOG(m_journal.debug()) - << "Queued new job with " << names.size() << " tasks. " - << m_work.size() << " jobs outstanding."; + JLOG(m_journal.debug()) << "Queued new job with " << names.size() << " tasks. " << m_work.size() + << " jobs outstanding."; if (m_work.size() > 0) { boost::asio::post( m_io_context, boost::asio::bind_executor( - m_strand, - std::bind( - &ResolverAsioImpl::do_work, - this, - CompletionCounter(this)))); + m_strand, std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this)))); } } } @@ -469,4 +390,4 @@ ResolverAsio::New(boost::asio::io_context& io_context, beast::Journal journal) //----------------------------------------------------------------------------- Resolver::~Resolver() = default; -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/StringUtilities.cpp b/src/libxrpl/basics/StringUtilities.cpp index 3cf3df209e..96b5cfdb9b 100644 --- a/src/libxrpl/basics/StringUtilities.cpp +++ b/src/libxrpl/basics/StringUtilities.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { std::string sqlBlobLiteral(Blob const& blob) @@ -155,4 +136,4 @@ isProperlyFormedTomlDomain(std::string_view domain) return boost::regex_match(domain.begin(), domain.end(), re); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/UptimeClock.cpp b/src/libxrpl/basics/UptimeClock.cpp index 7b61a5397e..521a6a1313 100644 --- a/src/libxrpl/basics/UptimeClock.cpp +++ b/src/libxrpl/basics/UptimeClock.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { std::atomic UptimeClock::now_{0}; // seconds since start std::atomic UptimeClock::stop_{false}; // stop update thread @@ -73,4 +54,4 @@ UptimeClock::now() return time_point{duration{now_}}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/base64.cpp b/src/libxrpl/basics/base64.cpp index 741d978aa0..3b692bc743 100644 --- a/src/libxrpl/basics/base64.cpp +++ b/src/libxrpl/basics/base64.cpp @@ -1,25 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -62,15 +40,14 @@ #include #include -namespace ripple { +namespace xrpl { namespace base64 { inline char const* get_alphabet() { - static char constexpr tab[] = { - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; + static char constexpr tab[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; return &tab[0]; } @@ -78,38 +55,22 @@ inline signed char const* get_inverse() { static signed char constexpr tab[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 0-15 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 16-31 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, // 32-47 - 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, -1, -1, -1, -1, -1, -1, // 48-63 - -1, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 - 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, -1, -1, -1, -1, -1, // 80-95 - -1, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 - 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, -1, -1, -1, -1, -1, // 112-127 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 128-143 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 144-159 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 160-175 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 176-191 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 192-207 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 208-223 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, // 224-239 - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 // 240-255 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63 + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95 + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255 }; return &tab[0]; } @@ -228,9 +189,7 @@ decode(void* dest, char const* src, std::size_t len) *out++ = c3[j]; } - return { - out - static_cast(dest), - in - reinterpret_cast(src)}; + return {out - static_cast(dest), in - reinterpret_cast(src)}; } } // namespace base64 @@ -254,4 +213,4 @@ base64_decode(std::string_view data) return dest; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/contract.cpp b/src/libxrpl/basics/contract.cpp index ea75929be0..562d3a0944 100644 --- a/src/libxrpl/basics/contract.cpp +++ b/src/libxrpl/basics/contract.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { void LogThrow(std::string const& title) @@ -49,4 +30,4 @@ LogicError(std::string const& s) noexcept // LCOV_EXCL_STOP } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/make_SSLContext.cpp b/src/libxrpl/basics/make_SSLContext.cpp index 980f2d48a6..57cbf7a24a 100644 --- a/src/libxrpl/basics/make_SSLContext.cpp +++ b/src/libxrpl/basics/make_SSLContext.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -43,11 +24,11 @@ #include #include -namespace ripple { +namespace xrpl { namespace openssl { namespace detail { -/** The default strength of self-signed RSA certifices. +/** The default strength of self-signed RSA certificates. Per NIST Special Publication 800-57 Part 3, 2048-bit RSA is still considered acceptably secure. Generally, we would want to go above @@ -134,8 +115,7 @@ initAnonymous(boost::asio::ssl::context& context) // We need to up the reference count of here, since we are retaining a // copy of the key for (potential) reuse. if (RSA_up_ref(defaultRSA) != 1) - LogicError( - "EVP_PKEY_assign_RSA: incrementing reference count failed"); + LogicError("EVP_PKEY_assign_RSA: incrementing reference count failed"); if (!EVP_PKEY_assign_RSA(pkey, defaultRSA)) LogicError("EVP_PKEY_assign_RSA failed"); @@ -150,7 +130,7 @@ initAnonymous(boost::asio::ssl::context& context) LogicError("X509_new failed"); // According to the standards (X.509 et al), the value should be one - // less than the actualy certificate version we want. Since we want + // less than the actually certificate version we want. Since we want // version 3, we must use a 2. X509_set_version(x509, 2); @@ -160,8 +140,7 @@ initAnonymous(boost::asio::ssl::context& context) auto const ts = std::time(nullptr) - (25 * 60 * 60); - int ret = std::strftime( - buf, sizeof(buf) - 1, "%y%m%d000000Z", std::gmtime(&ts)); + int ret = std::strftime(buf, sizeof(buf) - 1, "%y%m%d000000Z", std::gmtime(&ts)); buf[ret] = 0; @@ -195,32 +174,25 @@ initAnonymous(boost::asio::ssl::context& context) X509V3_set_ctx_nodb(&ctx); X509V3_set_ctx(&ctx, x509, x509, nullptr, nullptr, 0); - if (auto ext = X509V3_EXT_conf_nid( - nullptr, &ctx, NID_basic_constraints, "critical,CA:FALSE")) + if (auto ext = X509V3_EXT_conf_nid(nullptr, &ctx, NID_basic_constraints, "critical,CA:FALSE")) { X509_add_ext(x509, ext, -1); X509_EXTENSION_free(ext); } - if (auto ext = X509V3_EXT_conf_nid( - nullptr, - &ctx, - NID_ext_key_usage, - "critical,serverAuth,clientAuth")) + if (auto ext = X509V3_EXT_conf_nid(nullptr, &ctx, NID_ext_key_usage, "critical,serverAuth,clientAuth")) { X509_add_ext(x509, ext, -1); X509_EXTENSION_free(ext); } - if (auto ext = X509V3_EXT_conf_nid( - nullptr, &ctx, NID_key_usage, "critical,digitalSignature")) + if (auto ext = X509V3_EXT_conf_nid(nullptr, &ctx, NID_key_usage, "critical,digitalSignature")) { X509_add_ext(x509, ext, -1); X509_EXTENSION_free(ext); } - if (auto ext = X509V3_EXT_conf_nid( - nullptr, &ctx, NID_subject_key_identifier, "hash")) + if (auto ext = X509V3_EXT_conf_nid(nullptr, &ctx, NID_subject_key_identifier, "hash")) { X509_add_ext(x509, ext, -1); X509_EXTENSION_free(ext); @@ -264,8 +236,7 @@ initAuthenticated( { boost::system::error_code ec; - context.use_certificate_file( - cert_file, boost::asio::ssl::context::pem, ec); + context.use_certificate_file(cert_file, boost::asio::ssl::context::pem, ec); if (ec) LogicError("Problem with SSL certificate file" + fmt_error(ec)); @@ -282,8 +253,7 @@ initAuthenticated( { LogicError( "Problem opening SSL chain file" + - fmt_error(boost::system::error_code( - errno, boost::system::generic_category()))); + fmt_error(boost::system::error_code(errno, boost::system::generic_category()))); } try @@ -316,10 +286,7 @@ initAuthenticated( catch (std::exception const& ex) { fclose(f); - LogicError( - std::string( - "Reading the SSL chain file generated an exception: ") + - ex.what()); + LogicError(std::string("Reading the SSL chain file generated an exception: ") + ex.what()); } } @@ -327,13 +294,11 @@ initAuthenticated( { boost::system::error_code ec; - context.use_private_key_file( - key_file, boost::asio::ssl::context::pem, ec); + context.use_private_key_file(key_file, boost::asio::ssl::context::pem, ec); if (ec) { - LogicError( - "Problem using the SSL private key file" + fmt_error(ec)); + LogicError("Problem using the SSL private key file" + fmt_error(ec)); } } @@ -346,24 +311,18 @@ initAuthenticated( std::shared_ptr get_context(std::string cipherList) { - auto c = std::make_shared( - boost::asio::ssl::context::sslv23); + auto c = std::make_shared(boost::asio::ssl::context::sslv23); c->set_options( - boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::no_sslv3 | - boost::asio::ssl::context::no_tlsv1 | - boost::asio::ssl::context::no_tlsv1_1 | - boost::asio::ssl::context::single_dh_use | + boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::no_tlsv1 | + boost::asio::ssl::context::no_tlsv1_1 | boost::asio::ssl::context::single_dh_use | boost::asio::ssl::context::no_compression); if (cipherList.empty()) cipherList = defaultCipherList; - if (auto result = - SSL_CTX_set_cipher_list(c->native_handle(), cipherList.c_str()); - result != 1) + if (auto result = SSL_CTX_set_cipher_list(c->native_handle(), cipherList.c_str()); result != 1) LogicError("SSL_CTX_set_cipher_list failed"); c->use_tmp_dh({std::addressof(detail::defaultDH), sizeof(defaultDH)}); @@ -404,4 +363,4 @@ make_SSLContextAuthed( return context; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/basics/mulDiv.cpp b/src/libxrpl/basics/mulDiv.cpp index 57c3dd81cd..d8988b474e 100644 --- a/src/libxrpl/basics/mulDiv.cpp +++ b/src/libxrpl/basics/mulDiv.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { std::optional mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div) @@ -36,10 +17,10 @@ mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div) result /= div; - if (result > ripple::muldiv_max) + if (result > xrpl::muldiv_max) return std::nullopt; return static_cast(result); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/beast/clock/basic_seconds_clock.cpp b/src/libxrpl/beast/clock/basic_seconds_clock.cpp index 1407b67de9..27fb7b78c9 100644 --- a/src/libxrpl/beast/clock/basic_seconds_clock.cpp +++ b/src/libxrpl/beast/clock/basic_seconds_clock.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2021, Howard Hinnant - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -57,9 +38,7 @@ static_assert(std::atomic::is_always_lock_free); seconds_clock_thread::~seconds_clock_thread() { - XRPL_ASSERT( - thread_.joinable(), - "beast::seconds_clock_thread::~seconds_clock_thread : thread joinable"); + XRPL_ASSERT(thread_.joinable(), "beast::seconds_clock_thread::~seconds_clock_thread : thread joinable"); { std::lock_guard lock(mut_); stop_ = true; @@ -68,8 +47,7 @@ seconds_clock_thread::~seconds_clock_thread() thread_.join(); } -seconds_clock_thread::seconds_clock_thread() - : stop_{false}, tp_{Clock::now().time_since_epoch().count()} +seconds_clock_thread::seconds_clock_thread() : stop_{false}, tp_{Clock::now().time_since_epoch().count()} { thread_ = std::thread(&seconds_clock_thread::run, this); } diff --git a/src/libxrpl/beast/core/CurrentThreadName.cpp b/src/libxrpl/beast/core/CurrentThreadName.cpp index b393844972..9d8d4e4bf2 100644 --- a/src/libxrpl/beast/core/CurrentThreadName.cpp +++ b/src/libxrpl/beast/core/CurrentThreadName.cpp @@ -1,29 +1,5 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include - -#include +#include #include #include @@ -66,8 +42,7 @@ setCurrentThreadNameImpl(std::string_view name) #pragma warning(disable : 6320 6322) __try { - RaiseException( - 0x406d1388, 0, sizeof(ni) / sizeof(ULONG_PTR), (ULONG_PTR*)&ni); + RaiseException(0x406d1388, 0, sizeof(ni) / sizeof(ULONG_PTR), (ULONG_PTR*)&ni); } __except (EXCEPTION_CONTINUE_EXECUTION) { @@ -96,12 +71,31 @@ setCurrentThreadNameImpl(std::string_view name) #if BOOST_OS_LINUX #include +#include + namespace beast::detail { inline void setCurrentThreadNameImpl(std::string_view name) { - pthread_setname_np(pthread_self(), name.data()); + // truncate and set the thread name. + char boundedName[maxThreadNameLength + 1]; + std::snprintf(boundedName, sizeof(boundedName), "%.*s", static_cast(maxThreadNameLength), name.data()); + + pthread_setname_np(pthread_self(), boundedName); + +#ifdef TRUNCATED_THREAD_NAME_LOGS + if (name.size() > maxThreadNameLength) + { + std::cerr << "WARNING: Thread name \"" << name << "\" (length " << name.size() << ") exceeds maximum of " + << maxThreadNameLength << " characters on Linux.\n"; + + XRPL_ASSERT( + false, + "beast::detail::setCurrentThreadNameImpl : Thread name exceeds " + "maximum length for Linux"); + } +#endif } } // namespace beast::detail diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index e659d63570..d22211cc7d 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -78,9 +59,7 @@ chopUInt(int& value, int limit, std::string& input) return false; auto left_iter = std::find_if_not( - input.begin(), input.end(), [](std::string::value_type c) { - return std::isdigit(c, std::locale::classic()); - }); + input.begin(), input.end(), [](std::string::value_type c) { return std::isdigit(c, std::locale::classic()); }); std::string item(input.begin(), left_iter); @@ -109,10 +88,7 @@ chopUInt(int& value, int limit, std::string& input) } bool -extract_identifier( - std::string& value, - bool allowLeadingZeroes, - std::string& input) +extract_identifier(std::string& value, bool allowLeadingZeroes, std::string& input) { // Must not be empty if (input.empty()) @@ -122,8 +98,7 @@ extract_identifier( if (!allowLeadingZeroes && input[0] == '0') return false; - auto last = input.find_first_not_of( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"); + auto last = input.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"); // Must not be empty if (last == 0) @@ -135,10 +110,7 @@ extract_identifier( } bool -extract_identifiers( - SemanticVersion::identifier_list& identifiers, - bool allowLeadingZeroes, - std::string& input) +extract_identifiers(SemanticVersion::identifier_list& identifiers, bool allowLeadingZeroes, std::string& input) { if (input.empty()) return false; @@ -157,8 +129,7 @@ extract_identifiers( //------------------------------------------------------------------------------ -SemanticVersion::SemanticVersion() - : majorVersion(0), minorVersion(0), patchVersion(0) +SemanticVersion::SemanticVersion() : majorVersion(0), minorVersion(0), patchVersion(0) { } @@ -173,17 +144,11 @@ SemanticVersion::parse(std::string const& input) { // May not have leading or trailing whitespace auto left_iter = std::find_if_not( - input.begin(), input.end(), [](std::string::value_type c) { - return std::isspace(c, std::locale::classic()); - }); + input.begin(), input.end(), [](std::string::value_type c) { return std::isspace(c, std::locale::classic()); }); - auto right_iter = std::find_if_not( - input.rbegin(), - input.rend(), - [](std::string::value_type c) { - return std::isspace(c, std::locale::classic()); - }) - .base(); + auto right_iter = std::find_if_not(input.rbegin(), input.rend(), [](std::string::value_type c) { + return std::isspace(c, std::locale::classic()); + }).base(); // Must not be empty! if (left_iter >= right_iter) @@ -241,8 +206,7 @@ SemanticVersion::print() const { std::string s; - s = std::to_string(majorVersion) + "." + std::to_string(minorVersion) + - "." + std::to_string(patchVersion); + s = std::to_string(majorVersion) + "." + std::to_string(minorVersion) + "." + std::to_string(patchVersion); if (!preReleaseIdentifiers.empty()) { @@ -286,10 +250,7 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) return -1; // Compare pre-release identifiers - for (int i = 0; i < - std::max(lhs.preReleaseIdentifiers.size(), - rhs.preReleaseIdentifiers.size()); - ++i) + for (int i = 0; i < std::max(lhs.preReleaseIdentifiers.size(), rhs.preReleaseIdentifiers.size()); ++i) { // A larger list of identifiers has a higher precedence if (i >= rhs.preReleaseIdentifiers.size()) @@ -308,8 +269,7 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) if (isNumeric(left)) { - XRPL_ASSERT( - isNumeric(right), "beast::compare : both inputs numeric"); + XRPL_ASSERT(isNumeric(right), "beast::compare : both inputs numeric"); int const iLeft(lexicalCastThrow(left)); int const iRight(lexicalCastThrow(right)); @@ -321,9 +281,7 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) } else { - XRPL_ASSERT( - !isNumeric(right), - "beast::compare : both inputs non-numeric"); + XRPL_ASSERT(!isNumeric(right), "beast::compare : both inputs non-numeric"); int result = left.compare(right); diff --git a/src/libxrpl/beast/insight/Collector.cpp b/src/libxrpl/beast/insight/Collector.cpp index 4fdf6de984..37b199fa7f 100644 --- a/src/libxrpl/beast/insight/Collector.cpp +++ b/src/libxrpl/beast/insight/Collector.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include namespace beast { diff --git a/src/libxrpl/beast/insight/Groups.cpp b/src/libxrpl/beast/insight/Groups.cpp index c846ceff3b..1ff8dbc4c1 100644 --- a/src/libxrpl/beast/insight/Groups.cpp +++ b/src/libxrpl/beast/insight/Groups.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -44,8 +25,7 @@ public: std::string const m_name; Collector::ptr m_collector; - GroupImp(std::string const& name_, Collector::ptr const& collector) - : m_name(name_), m_collector(collector) + GroupImp(std::string const& name_, Collector::ptr const& collector) : m_name(name_), m_collector(collector) { } @@ -103,8 +83,7 @@ private: class GroupsImp : public Groups { public: - using Items = - std::unordered_map, uhash<>>; + using Items = std::unordered_map, uhash<>>; Collector::ptr m_collector; Items m_items; @@ -118,8 +97,7 @@ public: Group::ptr const& get(std::string const& name) override { - std::pair result( - m_items.emplace(name, Group::ptr())); + std::pair result(m_items.emplace(name, Group::ptr())); Group::ptr& group(result.first->second); if (result.second) group = std::make_shared(name, m_collector); diff --git a/src/libxrpl/beast/insight/Hook.cpp b/src/libxrpl/beast/insight/Hook.cpp index d15e001ace..d5e0a3439f 100644 --- a/src/libxrpl/beast/insight/Hook.cpp +++ b/src/libxrpl/beast/insight/Hook.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/libxrpl/beast/insight/Metric.cpp b/src/libxrpl/beast/insight/Metric.cpp index 64a4082fce..fcad390576 100644 --- a/src/libxrpl/beast/insight/Metric.cpp +++ b/src/libxrpl/beast/insight/Metric.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include diff --git a/src/libxrpl/beast/insight/NullCollector.cpp b/src/libxrpl/beast/insight/NullCollector.cpp index 4801bcecab..d8ba67a8e7 100644 --- a/src/libxrpl/beast/insight/NullCollector.cpp +++ b/src/libxrpl/beast/insight/NullCollector.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include diff --git a/src/libxrpl/beast/insight/StatsDCollector.cpp b/src/libxrpl/beast/insight/StatsDCollector.cpp index 7a3929e0d5..e005a0b177 100644 --- a/src/libxrpl/beast/insight/StatsDCollector.cpp +++ b/src/libxrpl/beast/insight/StatsDCollector.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -83,9 +64,7 @@ public: class StatsDHookImpl : public HookImpl, public StatsDMetricBase { public: - StatsDHookImpl( - HandlerType const& handler, - std::shared_ptr const& impl); + StatsDHookImpl(HandlerType const& handler, std::shared_ptr const& impl); ~StatsDHookImpl() override; @@ -105,9 +84,7 @@ private: class StatsDCounterImpl : public CounterImpl, public StatsDMetricBase { public: - StatsDCounterImpl( - std::string const& name, - std::shared_ptr const& impl); + StatsDCounterImpl(std::string const& name, std::shared_ptr const& impl); ~StatsDCounterImpl() override; @@ -136,9 +113,7 @@ private: class StatsDEventImpl : public EventImpl { public: - StatsDEventImpl( - std::string const& name, - std::shared_ptr const& impl); + StatsDEventImpl(std::string const& name, std::shared_ptr const& impl); ~StatsDEventImpl() = default; @@ -163,9 +138,7 @@ private: class StatsDGaugeImpl : public GaugeImpl, public StatsDMetricBase { public: - StatsDGaugeImpl( - std::string const& name, - std::shared_ptr const& impl); + StatsDGaugeImpl(std::string const& name, std::shared_ptr const& impl); ~StatsDGaugeImpl() override; @@ -199,9 +172,7 @@ private: class StatsDMeterImpl : public MeterImpl, public StatsDMetricBase { public: - explicit StatsDMeterImpl( - std::string const& name, - std::shared_ptr const& impl); + explicit StatsDMeterImpl(std::string const& name, std::shared_ptr const& impl); ~StatsDMeterImpl() override; @@ -227,9 +198,7 @@ private: //------------------------------------------------------------------------------ -class StatsDCollectorImp - : public StatsDCollector, - public std::enable_shared_from_this +class StatsDCollectorImp : public StatsDCollector, public std::enable_shared_from_this { private: enum { @@ -241,9 +210,7 @@ private: IP::Endpoint m_address; std::string m_prefix; boost::asio::io_context m_io_context; - std::optional> - m_work; + std::optional> m_work; boost::asio::strand m_strand; boost::asio::basic_waitable_timer m_timer; boost::asio::ip::udp::socket m_socket; @@ -261,10 +228,7 @@ private: } public: - StatsDCollectorImp( - IP::Endpoint const& address, - std::string const& prefix, - Journal journal) + StatsDCollectorImp(IP::Endpoint const& address, std::string const& prefix, Journal journal) : m_journal(journal) , m_address(address) , m_prefix(prefix) @@ -294,36 +258,31 @@ public: Hook make_hook(HookImpl::HandlerType const& handler) override { - return Hook(std::make_shared( - handler, shared_from_this())); + return Hook(std::make_shared(handler, shared_from_this())); } Counter make_counter(std::string const& name) override { - return Counter(std::make_shared( - name, shared_from_this())); + return Counter(std::make_shared(name, shared_from_this())); } Event make_event(std::string const& name) override { - return Event(std::make_shared( - name, shared_from_this())); + return Event(std::make_shared(name, shared_from_this())); } Gauge make_gauge(std::string const& name) override { - return Gauge(std::make_shared( - name, shared_from_this())); + return Gauge(std::make_shared(name, shared_from_this())); } Meter make_meter(std::string const& name) override { - return Meter(std::make_shared( - name, shared_from_this())); + return Meter(std::make_shared(name, shared_from_this())); } //-------------------------------------------------------------------------- @@ -368,20 +327,13 @@ public: boost::asio::dispatch( m_io_context, boost::asio::bind_executor( - m_strand, - std::bind( - &StatsDCollectorImp::do_post_buffer, - this, - std::move(buffer)))); + m_strand, std::bind(&StatsDCollectorImp::do_post_buffer, this, std::move(buffer)))); } // The keepAlive parameter makes sure the buffers sent to // boost::asio::async_send do not go away until the call is finished void - on_send( - std::shared_ptr> /*keepAlive*/, - boost::system::error_code ec, - std::size_t) + on_send(std::shared_ptr> /*keepAlive*/, boost::system::error_code ec, std::size_t) { if (ec == boost::asio::error::operation_aborted) return; @@ -401,8 +353,7 @@ public: #if BEAST_STATSDCOLLECTOR_TRACING_ENABLED for (auto const& buffer : buffers) { - std::string const s( - buffer.data(), boost::asio::buffer_size(buffer)); + std::string const s(buffer.data(), boost::asio::buffer_size(buffer)); std::cerr << s; } std::cerr << '\n'; @@ -423,8 +374,7 @@ public: buffers.reserve(m_data.size()); std::size_t size(0); - auto keepAlive = - std::make_shared>(std::move(m_data)); + auto keepAlive = std::make_shared>(std::move(m_data)); m_data.clear(); for (auto const& s : *keepAlive) @@ -440,11 +390,7 @@ public: m_socket.async_send( buffers, std::bind( - &StatsDCollectorImp::on_send, - this, - keepAlive, - std::placeholders::_1, - std::placeholders::_2)); + &StatsDCollectorImp::on_send, this, keepAlive, std::placeholders::_1, std::placeholders::_2)); buffers.clear(); size = 0; } @@ -458,12 +404,7 @@ public: log(buffers); m_socket.async_send( buffers, - std::bind( - &StatsDCollectorImp::on_send, - this, - keepAlive, - std::placeholders::_1, - std::placeholders::_2)); + std::bind(&StatsDCollectorImp::on_send, this, keepAlive, std::placeholders::_1, std::placeholders::_2)); } } @@ -472,8 +413,7 @@ public: { using namespace std::chrono_literals; m_timer.expires_after(1s); - m_timer.async_wait(std::bind( - &StatsDCollectorImp::on_timer, this, std::placeholders::_1)); + m_timer.async_wait(std::bind(&StatsDCollectorImp::on_timer, this, std::placeholders::_1)); } void @@ -525,9 +465,7 @@ public: //------------------------------------------------------------------------------ -StatsDHookImpl::StatsDHookImpl( - HandlerType const& handler, - std::shared_ptr const& impl) +StatsDHookImpl::StatsDHookImpl(HandlerType const& handler, std::shared_ptr const& impl) : m_impl(impl), m_handler(handler) { m_impl->add(*this); @@ -546,9 +484,7 @@ StatsDHookImpl::do_process() //------------------------------------------------------------------------------ -StatsDCounterImpl::StatsDCounterImpl( - std::string const& name, - std::shared_ptr const& impl) +StatsDCounterImpl::StatsDCounterImpl(std::string const& name, std::shared_ptr const& impl) : m_impl(impl), m_name(name), m_value(0), m_dirty(false) { m_impl->add(*this); @@ -565,9 +501,7 @@ StatsDCounterImpl::increment(CounterImpl::value_type amount) boost::asio::dispatch( m_impl->get_io_context(), std::bind( - &StatsDCounterImpl::do_increment, - std::static_pointer_cast(shared_from_this()), - amount)); + &StatsDCounterImpl::do_increment, std::static_pointer_cast(shared_from_this()), amount)); } void @@ -599,9 +533,7 @@ StatsDCounterImpl::do_process() //------------------------------------------------------------------------------ -StatsDEventImpl::StatsDEventImpl( - std::string const& name, - std::shared_ptr const& impl) +StatsDEventImpl::StatsDEventImpl(std::string const& name, std::shared_ptr const& impl) : m_impl(impl), m_name(name) { } @@ -611,10 +543,7 @@ StatsDEventImpl::notify(EventImpl::value_type const& value) { boost::asio::dispatch( m_impl->get_io_context(), - std::bind( - &StatsDEventImpl::do_notify, - std::static_pointer_cast(shared_from_this()), - value)); + std::bind(&StatsDEventImpl::do_notify, std::static_pointer_cast(shared_from_this()), value)); } void @@ -628,9 +557,7 @@ StatsDEventImpl::do_notify(EventImpl::value_type const& value) //------------------------------------------------------------------------------ -StatsDGaugeImpl::StatsDGaugeImpl( - std::string const& name, - std::shared_ptr const& impl) +StatsDGaugeImpl::StatsDGaugeImpl(std::string const& name, std::shared_ptr const& impl) : m_impl(impl), m_name(name), m_last_value(0), m_value(0), m_dirty(false) { m_impl->add(*this); @@ -646,10 +573,7 @@ StatsDGaugeImpl::set(GaugeImpl::value_type value) { boost::asio::dispatch( m_impl->get_io_context(), - std::bind( - &StatsDGaugeImpl::do_set, - std::static_pointer_cast(shared_from_this()), - value)); + std::bind(&StatsDGaugeImpl::do_set, std::static_pointer_cast(shared_from_this()), value)); } void @@ -658,9 +582,7 @@ StatsDGaugeImpl::increment(GaugeImpl::difference_type amount) boost::asio::dispatch( m_impl->get_io_context(), std::bind( - &StatsDGaugeImpl::do_increment, - std::static_pointer_cast(shared_from_this()), - amount)); + &StatsDGaugeImpl::do_increment, std::static_pointer_cast(shared_from_this()), amount)); } void @@ -695,17 +617,14 @@ StatsDGaugeImpl::do_increment(GaugeImpl::difference_type amount) if (amount > 0) { - GaugeImpl::value_type const d( - static_cast(amount)); - value += - (d >= std::numeric_limits::max() - m_value) + GaugeImpl::value_type const d(static_cast(amount)); + value += (d >= std::numeric_limits::max() - m_value) ? std::numeric_limits::max() - m_value : d; } else if (amount < 0) { - GaugeImpl::value_type const d( - static_cast(-amount)); + GaugeImpl::value_type const d(static_cast(-amount)); value = (d >= value) ? 0 : value - d; } @@ -720,9 +639,7 @@ StatsDGaugeImpl::do_process() //------------------------------------------------------------------------------ -StatsDMeterImpl::StatsDMeterImpl( - std::string const& name, - std::shared_ptr const& impl) +StatsDMeterImpl::StatsDMeterImpl(std::string const& name, std::shared_ptr const& impl) : m_impl(impl), m_name(name), m_value(0), m_dirty(false) { m_impl->add(*this); @@ -739,9 +656,7 @@ StatsDMeterImpl::increment(MeterImpl::value_type amount) boost::asio::dispatch( m_impl->get_io_context(), std::bind( - &StatsDMeterImpl::do_increment, - std::static_pointer_cast(shared_from_this()), - amount)); + &StatsDMeterImpl::do_increment, std::static_pointer_cast(shared_from_this()), amount)); } void @@ -776,13 +691,9 @@ StatsDMeterImpl::do_process() //------------------------------------------------------------------------------ std::shared_ptr -StatsDCollector::New( - IP::Endpoint const& address, - std::string const& prefix, - Journal journal) +StatsDCollector::New(IP::Endpoint const& address, std::string const& prefix, Journal journal) { - return std::make_shared( - address, prefix, journal); + return std::make_shared(address, prefix, journal); } } // namespace insight diff --git a/src/libxrpl/beast/net/IPAddressConversion.cpp b/src/libxrpl/beast/net/IPAddressConversion.cpp index abaf1bb7b8..d34a973d8e 100644 --- a/src/libxrpl/beast/net/IPAddressConversion.cpp +++ b/src/libxrpl/beast/net/IPAddressConversion.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/libxrpl/beast/net/IPAddressV4.cpp b/src/libxrpl/beast/net/IPAddressV4.cpp index 22162c2bbe..021b7588d9 100644 --- a/src/libxrpl/beast/net/IPAddressV4.cpp +++ b/src/libxrpl/beast/net/IPAddressV4.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include namespace beast { @@ -25,12 +6,9 @@ namespace IP { bool is_private(AddressV4 const& addr) { - return ((addr.to_uint() & 0xff000000) == - 0x0a000000) || // Prefix /8, 10. #.#.# - ((addr.to_uint() & 0xfff00000) == - 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.# - ((addr.to_uint() & 0xffff0000) == - 0xc0a80000) || // Prefix /16 192.168.#.# + return ((addr.to_uint() & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.# + ((addr.to_uint() & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.# + ((addr.to_uint() & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.# addr.is_loopback(); } @@ -43,7 +21,7 @@ is_public(AddressV4 const& addr) char get_class(AddressV4 const& addr) { - static char const* table = "AAAABBCD"; + static char const* table = "AAAABBCD"; // cspell:disable-line return table[(addr.to_uint() & 0xE0000000) >> 29]; } diff --git a/src/libxrpl/beast/net/IPAddressV6.cpp b/src/libxrpl/beast/net/IPAddressV6.cpp index d1b86ba9bd..b1db5ae09c 100644 --- a/src/libxrpl/beast/net/IPAddressV6.cpp +++ b/src/libxrpl/beast/net/IPAddressV6.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,9 +11,7 @@ is_private(AddressV6 const& addr) { return ( (addr.to_bytes()[0] & 0xfd) || // TODO fc00::/8 too ? - (addr.is_v4_mapped() && - is_private(boost::asio::ip::make_address_v4( - boost::asio::ip::v4_mapped, addr)))); + (addr.is_v4_mapped() && is_private(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr)))); } bool diff --git a/src/libxrpl/beast/net/IPEndpoint.cpp b/src/libxrpl/beast/net/IPEndpoint.cpp index f1ffc23e82..a79b0d750c 100644 --- a/src/libxrpl/beast/net/IPEndpoint.cpp +++ b/src/libxrpl/beast/net/IPEndpoint.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -69,9 +50,7 @@ std::string Endpoint::to_string() const { std::string s; - s.reserve( - (address().is_v6() ? INET6_ADDRSTRLEN - 1 : 15) + - (port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0))); + s.reserve((address().is_v6() ? INET6_ADDRSTRLEN - 1 : 15) + (port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0))); if (port() != 0 && address().is_v6()) s += '['; @@ -129,14 +108,12 @@ operator>>(std::istream& is, Endpoint& endpoint) if (isspace(static_cast(i)) || (readTo && i == readTo)) break; - if ((i == '.') || (i >= '0' && i <= ':') || (i >= 'a' && i <= 'f') || - (i >= 'A' && i <= 'F')) + if ((i == '.') || (i >= '0' && i <= ':') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) { addrStr += i; // don't exceed a reasonable length... - if (addrStr.size() == INET6_ADDRSTRLEN || - (readTo && readTo == ':' && addrStr.size() > 15)) + if (addrStr.size() == INET6_ADDRSTRLEN || (readTo && readTo == ':' && addrStr.size() > 15)) { is.setstate(std::ios_base::failbit); return is; diff --git a/src/libxrpl/beast/utility/beast_Journal.cpp b/src/libxrpl/beast/utility/beast_Journal.cpp index 828f2fa619..f9ee0cdb73 100644 --- a/src/libxrpl/beast/utility/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/beast_Journal.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -87,8 +68,7 @@ Journal::getNullSink() //------------------------------------------------------------------------------ -Journal::Sink::Sink(Severity thresh, bool console) - : thresh_(thresh), m_console(console) +Journal::Sink::Sink(Severity thresh, bool console) : thresh_(thresh), m_console(console) { } @@ -126,16 +106,13 @@ Journal::Sink::threshold(Severity thresh) //------------------------------------------------------------------------------ -Journal::ScopedStream::ScopedStream(Sink& sink, Severity level) - : m_sink(sink), m_level(level) +Journal::ScopedStream::ScopedStream(Sink& sink, Severity level) : m_sink(sink), m_level(level) { // Modifiers applied from all ctors m_ostream << std::boolalpha << std::showbase; } -Journal::ScopedStream::ScopedStream( - Stream const& stream, - std::ostream& manip(std::ostream&)) +Journal::ScopedStream::ScopedStream(Stream const& stream, std::ostream& manip(std::ostream&)) : ScopedStream(stream.sink(), stream.level()) { m_ostream << manip; diff --git a/src/libxrpl/beast/utility/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/beast_PropertyStream.cpp index 22d1f898d6..daf6bc4526 100644 --- a/src/libxrpl/beast/utility/beast_PropertyStream.cpp +++ b/src/libxrpl/beast/utility/beast_PropertyStream.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -62,13 +43,11 @@ PropertyStream::Item::operator*() const // //------------------------------------------------------------------------------ -PropertyStream::Proxy::Proxy(Map const& map, std::string const& key) - : m_map(&map), m_key(key) +PropertyStream::Proxy::Proxy(Map const& map, std::string const& key) : m_map(&map), m_key(key) { } -PropertyStream::Proxy::Proxy(Proxy const& other) - : m_map(other.m_map), m_key(other.m_key) +PropertyStream::Proxy::Proxy(Proxy const& other) : m_map(other.m_map), m_key(other.m_key) { } @@ -100,14 +79,12 @@ PropertyStream::Map::Map(Set& parent) : m_stream(parent.stream()) m_stream.map_begin(); } -PropertyStream::Map::Map(std::string const& key, Map& map) - : m_stream(map.stream()) +PropertyStream::Map::Map(std::string const& key, Map& map) : m_stream(map.stream()) { m_stream.map_begin(key); } -PropertyStream::Map::Map(std::string const& key, PropertyStream& stream) - : m_stream(stream) +PropertyStream::Map::Map(std::string const& key, PropertyStream& stream) : m_stream(stream) { m_stream.map_begin(key); } @@ -141,14 +118,12 @@ PropertyStream::Map::operator[](std::string const& key) // //------------------------------------------------------------------------------ -PropertyStream::Set::Set(std::string const& key, Map& map) - : m_stream(map.stream()) +PropertyStream::Set::Set(std::string const& key, Map& map) : m_stream(map.stream()) { m_stream.array_begin(key); } -PropertyStream::Set::Set(std::string const& key, PropertyStream& stream) - : m_stream(stream) +PropertyStream::Set::Set(std::string const& key, PropertyStream& stream) : m_stream(stream) { m_stream.array_begin(key); } @@ -176,8 +151,7 @@ PropertyStream::Set::stream() const // //------------------------------------------------------------------------------ -PropertyStream::Source::Source(std::string const& name) - : m_name(name), item_(this), parent_(nullptr) +PropertyStream::Source::Source(std::string const& name) : m_name(name), item_(this), parent_(nullptr) { } @@ -202,9 +176,7 @@ PropertyStream::Source::add(Source& source) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(source.lock_, std::adopt_lock); - XRPL_ASSERT( - source.parent_ == nullptr, - "beast::PropertyStream::Source::add : null source parent"); + XRPL_ASSERT(source.parent_ == nullptr, "beast::PropertyStream::Source::add : null source parent"); children_.push_back(source.item_); source.parent_ = this; } @@ -216,9 +188,7 @@ PropertyStream::Source::remove(Source& child) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(child.lock_, std::adopt_lock); - XRPL_ASSERT( - child.parent_ == this, - "beast::PropertyStream::Source::remove : child parent match"); + XRPL_ASSERT(child.parent_ == this, "beast::PropertyStream::Source::remove : child parent match"); children_.erase(children_.iterator_to(child.item_)); child.parent_ = nullptr; } diff --git a/src/libxrpl/core/detail/Job.cpp b/src/libxrpl/core/detail/Job.cpp new file mode 100644 index 0000000000..4e957b9619 --- /dev/null +++ b/src/libxrpl/core/detail/Job.cpp @@ -0,0 +1,94 @@ +#include +#include + +namespace xrpl { + +Job::Job() : mType(jtINVALID), mJobIndex(0) +{ +} + +Job::Job(JobType type, std::uint64_t index) : mType(type), mJobIndex(index) +{ +} + +Job::Job(JobType type, std::string const& name, std::uint64_t index, LoadMonitor& lm, std::function const& job) + : mType(type), mJobIndex(index), mJob(job), mName(name), m_queue_time(clock_type::now()) +{ + m_loadEvent = std::make_shared(std::ref(lm), name, false); +} + +JobType +Job::getType() const +{ + return mType; +} + +Job::clock_type::time_point const& +Job::queue_time() const +{ + return m_queue_time; +} + +void +Job::doJob() +{ + beast::setCurrentThreadName("j:" + mName); + m_loadEvent->start(); + m_loadEvent->setName(mName); + + mJob(); + + // Destroy the lambda, otherwise we won't include + // its duration in the time measurement + mJob = nullptr; +} + +bool +Job::operator>(Job const& j) const +{ + if (mType < j.mType) + return true; + + if (mType > j.mType) + return false; + + return mJobIndex > j.mJobIndex; +} + +bool +Job::operator>=(Job const& j) const +{ + if (mType < j.mType) + return true; + + if (mType > j.mType) + return false; + + return mJobIndex >= j.mJobIndex; +} + +bool +Job::operator<(Job const& j) const +{ + if (mType < j.mType) + return false; + + if (mType > j.mType) + return true; + + return mJobIndex < j.mJobIndex; +} + +bool +Job::operator<=(Job const& j) const +{ + if (mType < j.mType) + return false; + + if (mType > j.mType) + return true; + + return mJobIndex <= j.mJobIndex; +} + +} // namespace xrpl diff --git a/src/xrpld/core/detail/JobQueue.cpp b/src/libxrpl/core/detail/JobQueue.cpp similarity index 65% rename from src/xrpld/core/detail/JobQueue.cpp rename to src/libxrpl/core/detail/JobQueue.cpp index 1ea1df51ab..37e5402946 100644 --- a/src/xrpld/core/detail/JobQueue.cpp +++ b/src/libxrpl/core/detail/JobQueue.cpp @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - #include +#include +#include #include -namespace ripple { +namespace xrpl { JobQueue::JobQueue( int threadCount, @@ -57,9 +37,7 @@ JobQueue::JobQueue( std::piecewise_construct, std::forward_as_tuple(jt.type()), std::forward_as_tuple(jt, m_collector, logs))); - XRPL_ASSERT( - result.second == true, - "ripple::JobQueue::JobQueue : jobs added"); + XRPL_ASSERT(result.second == true, "xrpl::JobQueue::JobQueue : jobs added"); (void)result.second; } } @@ -79,47 +57,33 @@ JobQueue::collect() } bool -JobQueue::addRefCountedJob( - JobType type, - std::string const& name, - JobFunction const& func) +JobQueue::addRefCountedJob(JobType type, std::string const& name, JobFunction const& func) { - XRPL_ASSERT( - type != jtINVALID, - "ripple::JobQueue::addRefCountedJob : valid input job type"); + XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::addRefCountedJob : valid input job type"); auto iter(m_jobData.find(type)); - XRPL_ASSERT( - iter != m_jobData.end(), - "ripple::JobQueue::addRefCountedJob : job type found in jobs"); + XRPL_ASSERT(iter != m_jobData.end(), "xrpl::JobQueue::addRefCountedJob : job type found in jobs"); if (iter == m_jobData.end()) return false; - JLOG(m_journal.debug()) - << __func__ << " : Adding job : " << name << " : " << type; + JLOG(m_journal.debug()) << __func__ << " : Adding job : " << name << " : " << type; JobTypeData& data(iter->second); // FIXME: Workaround incorrect client shutdown ordering // do not add jobs to a queue with no threads XRPL_ASSERT( - (type >= jtCLIENT && type <= jtCLIENT_WEBSOCKET) || - m_workers.getNumberOfThreads() > 0, - "ripple::JobQueue::addRefCountedJob : threads available or job " + (type >= jtCLIENT && type <= jtCLIENT_WEBSOCKET) || m_workers.getNumberOfThreads() > 0, + "xrpl::JobQueue::addRefCountedJob : threads available or job " "requires no threads"); { std::lock_guard lock(m_mutex); - auto result = - m_jobSet.emplace(type, name, ++m_lastJob, data.load(), func); + auto result = m_jobSet.emplace(type, name, ++m_lastJob, data.load(), func); auto const& job = *result.first; JobType const type(job.getType()); - XRPL_ASSERT( - type != jtINVALID, - "ripple::JobQueue::addRefCountedJob : has valid job type"); - XRPL_ASSERT( - m_jobSet.find(job) != m_jobSet.end(), - "ripple::JobQueue::addRefCountedJob : job found"); + XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::addRefCountedJob : has valid job type"); + XRPL_ASSERT(m_jobSet.find(job) != m_jobSet.end(), "xrpl::JobQueue::addRefCountedJob : job found"); perfLog_.jobQueue(type); JobTypeData& data(getJobTypeData(type)); @@ -179,9 +143,7 @@ std::unique_ptr JobQueue::makeLoadEvent(JobType t, std::string const& name) { JobDataMap::iterator iter(m_jobData.find(t)); - XRPL_ASSERT( - iter != m_jobData.end(), - "ripple::JobQueue::makeLoadEvent : valid job type input"); + XRPL_ASSERT(iter != m_jobData.end(), "xrpl::JobQueue::makeLoadEvent : valid job type input"); if (iter == m_jobData.end()) return {}; @@ -196,18 +158,14 @@ JobQueue::addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed) LogicError("JobQueue::addLoadEvents() called after JobQueue stopped"); JobDataMap::iterator iter(m_jobData.find(t)); - XRPL_ASSERT( - iter != m_jobData.end(), - "ripple::JobQueue::addLoadEvents : valid job type input"); + XRPL_ASSERT(iter != m_jobData.end(), "xrpl::JobQueue::addLoadEvents : valid job type input"); iter->second.load().addSamples(count, elapsed); } bool JobQueue::isOverloaded() { - return std::any_of(m_jobData.begin(), m_jobData.end(), [](auto& entry) { - return entry.second.load().isOver(); - }); + return std::any_of(m_jobData.begin(), m_jobData.end(), [](auto& entry) { return entry.second.load().isOver(); }); } Json::Value @@ -224,8 +182,7 @@ JobQueue::getJson(int c) for (auto& x : m_jobData) { - XRPL_ASSERT( - x.first != jtINVALID, "ripple::JobQueue::getJson : valid job type"); + XRPL_ASSERT(x.first != jtINVALID, "xrpl::JobQueue::getJson : valid job type"); if (x.first == jtGENERIC) continue; @@ -237,8 +194,7 @@ JobQueue::getJson(int c) int waiting(data.waiting); int running(data.running); - if ((stats.count != 0) || (waiting != 0) || - (stats.latencyPeak != 0ms) || (running != 0)) + if ((stats.count != 0) || (waiting != 0) || (stats.latencyPeak != 0ms) || (running != 0)) { Json::Value& pri = priorities.append(Json::objectValue); @@ -280,9 +236,7 @@ JobTypeData& JobQueue::getJobTypeData(JobType type) { JobDataMap::iterator c(m_jobData.find(type)); - XRPL_ASSERT( - c != m_jobData.end(), - "ripple::JobQueue::getJobTypeData : valid job type input"); + XRPL_ASSERT(c != m_jobData.end(), "xrpl::JobQueue::getJobTypeData : valid job type input"); // NIKB: This is ugly and I hate it. We must remove jtINVALID completely // and use something sane. @@ -305,15 +259,10 @@ JobQueue::stop() // `Job::doJob` and the return of `JobQueue::processTask`. That is why // we must wait on the condition variable to make these assertions. std::unique_lock lock(m_mutex); - cv_.wait( - lock, [this] { return m_processCount == 0 && m_jobSet.empty(); }); - XRPL_ASSERT( - m_processCount == 0, - "ripple::JobQueue::stop : all processes completed"); - XRPL_ASSERT( - m_jobSet.empty(), "ripple::JobQueue::stop : all jobs completed"); - XRPL_ASSERT( - nSuspend_ == 0, "ripple::JobQueue::stop : no coros suspended"); + cv_.wait(lock, [this] { return m_processCount == 0 && m_jobSet.empty(); }); + XRPL_ASSERT(m_processCount == 0, "xrpl::JobQueue::stop : all processes completed"); + XRPL_ASSERT(m_jobSet.empty(), "xrpl::JobQueue::stop : all jobs completed"); + XRPL_ASSERT(nSuspend_ == 0, "xrpl::JobQueue::stop : no coros suspended"); stopped_ = true; } } @@ -327,36 +276,28 @@ JobQueue::isStopped() const void JobQueue::getNextJob(Job& job) { - XRPL_ASSERT( - !m_jobSet.empty(), "ripple::JobQueue::getNextJob : non-empty jobs"); + XRPL_ASSERT(!m_jobSet.empty(), "xrpl::JobQueue::getNextJob : non-empty jobs"); std::set::const_iterator iter; for (iter = m_jobSet.begin(); iter != m_jobSet.end(); ++iter) { JobType const type = iter->getType(); - XRPL_ASSERT( - type != jtINVALID, "ripple::JobQueue::getNextJob : valid job type"); + XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::getNextJob : valid job type"); JobTypeData& data(getJobTypeData(type)); - XRPL_ASSERT( - data.running <= getJobLimit(type), - "ripple::JobQueue::getNextJob : maximum jobs running"); + XRPL_ASSERT(data.running <= getJobLimit(type), "xrpl::JobQueue::getNextJob : maximum jobs running"); // Run this job if we're running below the limit. if (data.running < getJobLimit(data.type())) { - XRPL_ASSERT( - data.waiting > 0, - "ripple::JobQueue::getNextJob : positive data waiting"); + XRPL_ASSERT(data.waiting > 0, "xrpl::JobQueue::getNextJob : positive data waiting"); --data.waiting; ++data.running; break; } } - XRPL_ASSERT( - iter != m_jobSet.end(), - "ripple::JobQueue::getNextJob : found next job"); + XRPL_ASSERT(iter != m_jobSet.end(), "xrpl::JobQueue::getNextJob : found next job"); job = *iter; m_jobSet.erase(iter); } @@ -364,18 +305,14 @@ JobQueue::getNextJob(Job& job) void JobQueue::finishJob(JobType type) { - XRPL_ASSERT( - type != jtINVALID, - "ripple::JobQueue::finishJob : valid input job type"); + XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::finishJob : valid input job type"); JobTypeData& data = getJobTypeData(type); // Queue a deferred task if possible if (data.deferred > 0) { - XRPL_ASSERT( - data.running + data.waiting >= getJobLimit(type), - "ripple::JobQueue::finishJob : job limit"); + XRPL_ASSERT(data.running + data.waiting >= getJobLimit(type), "xrpl::JobQueue::finishJob : job limit"); --data.deferred; m_workers.addTask(); @@ -404,15 +341,13 @@ JobQueue::processTask(int instance) JLOG(m_journal.trace()) << "Doing " << data.name() << "job"; // The amount of time that the job was in the queue - auto const q_time = - ceil(start_time - job.queue_time()); + auto const q_time = ceil(start_time - job.queue_time()); perfLog_.jobStart(type, q_time, start_time, instance); job.doJob(); // The amount of time it took to execute the job - auto const x_time = - ceil(Job::clock_type::now() - start_time); + auto const x_time = ceil(Job::clock_type::now() - start_time); if (x_time >= 10ms || q_time >= 10ms) { @@ -441,11 +376,9 @@ int JobQueue::getJobLimit(JobType type) { JobTypeInfo const& j(JobTypes::instance().get(type)); - XRPL_ASSERT( - j.type() != jtINVALID, - "ripple::JobQueue::getJobLimit : valid job type"); + XRPL_ASSERT(j.type() != jtINVALID, "xrpl::JobQueue::getJobLimit : valid job type"); return j.limit(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/core/detail/LoadEvent.cpp b/src/libxrpl/core/detail/LoadEvent.cpp new file mode 100644 index 0000000000..1370e9089f --- /dev/null +++ b/src/libxrpl/core/detail/LoadEvent.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +namespace xrpl { + +LoadEvent::LoadEvent(LoadMonitor& monitor, std::string const& name, bool shouldStart) + : monitor_(monitor) + , running_(shouldStart) + , name_(name) + , mark_{std::chrono::steady_clock::now()} + , timeWaiting_{} + , timeRunning_{} +{ +} + +LoadEvent::~LoadEvent() +{ + if (running_) + stop(); +} + +std::string const& +LoadEvent::name() const +{ + return name_; +} + +std::chrono::steady_clock::duration +LoadEvent::waitTime() const +{ + return timeWaiting_; +} + +std::chrono::steady_clock::duration +LoadEvent::runTime() const +{ + return timeRunning_; +} + +void +LoadEvent::setName(std::string const& name) +{ + name_ = name; +} + +void +LoadEvent::start() +{ + auto const now = std::chrono::steady_clock::now(); + + // If we had already called start, this call will + // replace the previous one. Any time accumulated will + // be counted as "waiting". + timeWaiting_ += now - mark_; + mark_ = now; + running_ = true; +} + +void +LoadEvent::stop() +{ + XRPL_ASSERT(running_, "xrpl::LoadEvent::stop : is running"); + + auto const now = std::chrono::steady_clock::now(); + + timeRunning_ += now - mark_; + mark_ = now; + running_ = false; + + monitor_.addLoadSample(*this); +} + +} // namespace xrpl diff --git a/src/xrpld/core/detail/LoadMonitor.cpp b/src/libxrpl/core/detail/LoadMonitor.cpp similarity index 67% rename from src/xrpld/core/detail/LoadMonitor.cpp rename to src/libxrpl/core/detail/LoadMonitor.cpp index 98fa959d6c..376b25c178 100644 --- a/src/xrpld/core/detail/LoadMonitor.cpp +++ b/src/libxrpl/core/detail/LoadMonitor.cpp @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - #include #include +#include -namespace ripple { +namespace xrpl { /* @@ -35,8 +15,7 @@ TODO //------------------------------------------------------------------------------ -LoadMonitor::Stats::Stats() - : count(0), latencyAvg(0), latencyPeak(0), isOverloaded(false) +LoadMonitor::Stats::Stats() : count(0), latencyAvg(0), latencyPeak(0), isOverloaded(false) { } @@ -86,7 +65,7 @@ LoadMonitor::update() "Imagine if you add 10 to something every second. And you also reduce it by 1/4 every second. It will "idle" at 40, - correponding to 10 counts per second." + corresponding to 10 counts per second." */ do { @@ -110,10 +89,8 @@ LoadMonitor::addLoadSample(LoadEvent const& s) if (latency > 500ms) { auto mj = (latency > 1s) ? j_.warn() : j_.info(); - JLOG(mj) << "Job: " << s.name() - << " run: " << round(s.runTime()).count() << "ms" - << " wait: " << round(s.waitTime()).count() - << "ms"; + JLOG(mj) << "Job: " << s.name() << " run: " << round(s.runTime()).count() << "ms" + << " wait: " << round(s.waitTime()).count() << "ms"; } addSamples(1, latency); @@ -141,18 +118,14 @@ LoadMonitor::addSamples(int count, std::chrono::milliseconds latency) } void -LoadMonitor::setTargetLatency( - std::chrono::milliseconds avg, - std::chrono::milliseconds pk) +LoadMonitor::setTargetLatency(std::chrono::milliseconds avg, std::chrono::milliseconds pk) { mTargetLatencyAvg = avg; mTargetLatencyPk = pk; } bool -LoadMonitor::isOverTarget( - std::chrono::milliseconds avg, - std::chrono::milliseconds peak) +LoadMonitor::isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak) { using namespace std::chrono_literals; return (mTargetLatencyPk > 0ms && (peak > mTargetLatencyPk)) || @@ -169,9 +142,7 @@ LoadMonitor::isOver() if (mLatencyEvents == 0) return 0; - return isOverTarget( - mLatencyMSAvg / (mLatencyEvents * 4), - mLatencyMSPeak / (mLatencyEvents * 4)); + return isOverTarget(mLatencyMSAvg / (mLatencyEvents * 4), mLatencyMSPeak / (mLatencyEvents * 4)); } LoadMonitor::Stats @@ -202,4 +173,4 @@ LoadMonitor::getStats() return stats; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/core/detail/Workers.cpp b/src/libxrpl/core/detail/Workers.cpp similarity index 77% rename from src/xrpld/core/detail/Workers.cpp rename to src/libxrpl/core/detail/Workers.cpp index 53b5944ac0..27103d765d 100644 --- a/src/xrpld/core/detail/Workers.cpp +++ b/src/libxrpl/core/detail/Workers.cpp @@ -1,35 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - #include #include +#include +#include -namespace ripple { +namespace xrpl { -Workers::Workers( - Callback& callback, - perf::PerfLog* perfLog, - std::string const& threadNames, - int numberOfThreads) +Workers::Workers(Callback& callback, perf::PerfLog* perfLog, std::string const& threadNames, int numberOfThreads) : m_callback(callback) , perfLog_(perfLog) , m_threadNames(threadNames) @@ -120,9 +96,7 @@ Workers::stop() m_cv.wait(lk, [this] { return m_allPaused; }); lk.unlock(); - XRPL_ASSERT( - numberOfCurrentlyRunningTasks() == 0, - "ripple::Workers::stop : zero running tasks"); + XRPL_ASSERT(numberOfCurrentlyRunningTasks() == 0, "xrpl::Workers::stop : zero running tasks"); } void @@ -158,15 +132,8 @@ Workers::deleteWorkers(beast::LockFreeStack& stack) //------------------------------------------------------------------------------ -Workers::Worker::Worker( - Workers& workers, - std::string const& threadName, - int const instance) - : m_workers{workers} - , threadName_{threadName} - , instance_{instance} - , wakeCount_{0} - , shouldExit_{false} +Workers::Worker::Worker(Workers& workers, std::string const& threadName, int const instance) + : m_workers{workers}, threadName_{threadName}, instance_{instance}, wakeCount_{0}, shouldExit_{false} { thread_ = std::thread{&Workers::Worker::run, this}; } @@ -280,4 +247,4 @@ Workers::Worker::run() } while (!shouldExit); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/crypto/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp index 48bd8dc0f8..dc841fca83 100644 --- a/src/libxrpl/crypto/RFC1751.cpp +++ b/src/libxrpl/crypto/RFC1751.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -33,241 +14,160 @@ #include #include -namespace ripple { +namespace xrpl { // // RFC 1751 code converted to C++/Boost. // char const* RFC1751::s_dictionary[2048] = { - "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", "AGO", "AID", - "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA", "AND", - "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", - "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", - "AVE", "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", - "BAH", "BAM", "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", - "BEG", "BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", - "BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB", "BUD", - "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", "BYE", "CAB", - "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", "CAW", "COD", "COG", - "COL", "CON", "COO", "COP", "COT", "COW", "COY", "CRY", "CUB", - "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", "DAR", - "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG", - "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", - "DUB", "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", - "EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", - "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", - "FAY", "FED", "FEE", "FEW", "FIB", "FIG", "FIN", "FIR", "FIT", - "FLO", "FLY", "FOE", "FOG", "FOR", "FRY", "FUM", "FUN", "FUR", - "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", "GAS", "GAY", "GEE", - "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO", "GOT", "GUM", - "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", - "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", - "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", - "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", - "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", - "IF", "IKE", "ILL", "INK", "INN", "IO", "ION", "IQ", "IRA", - "IRE", "IRK", "IS", "IT", "ITS", "IVY", "JAB", "JAG", "JAM", - "JAN", "JAR", "JAW", "JAY", "JET", "JIG", "JIM", "JO", "JOB", - "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", - "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", - "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG", - "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", - "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", - "LUG", "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", - "MAT", "MAW", "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", - "MID", "MIN", "MIT", "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", - "MOT", "MOW", "MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", - "NAP", "NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB", - "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", "NOT", - "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", "OAK", "OAR", - "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", "OK", - "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", - "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", - "PAD", "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", - "PEA", "PEG", "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", - "PIE", "PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT", - "POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", "QUO", - "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY", "REB", "RED", - "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO", "RIP", "ROB", - "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", "RUE", "RUG", - "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", "SAN", - "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", - "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", - "SKY", "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", - "SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", - "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", "TEE", "TEN", - "THE", "THY", "TIC", "TIE", "TIM", "TIN", "TIP", "TO", "TOE", - "TOG", "TOM", "TON", "TOO", "TOP", "TOW", "TOY", "TRY", "TUB", - "TUG", "TUM", "TUN", "TWO", "UN", "UP", "US", "USE", "VAN", - "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", "WAY", "WE", - "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", - "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", - "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", - "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", "ADEN", - "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", - "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", "ALOE", - "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID", "AMMO", "AMOK", - "AMOS", "AMRA", "ANDY", "ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", - "ARAB", "ARCH", "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", - "ASKS", "ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", - "AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", - "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", "BAND", - "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR", - "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", "BAWD", "BAWL", "BEAD", - "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", "BEAU", "BECK", "BEEF", "BEEN", - "BEER", "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", - "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", - "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", - "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", - "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", "BOHR", - "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND", "BONE", "BONG", - "BONN", "BONY", "BOOK", "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", - "BOSE", "BOSS", "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", - "BRAN", "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", - "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", - "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", - "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME", - "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART", "CASE", "CASH", - "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT", "CERN", "CHAD", "CHAR", - "CHAT", "CHAW", "CHEF", "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", - "CHUB", "CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", - "CLAY", "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", - "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", - "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", - "COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", "CRAB", - "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", "CUBA", "CUBE", - "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", - "CUTS", "DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", - "DARK", "DARN", "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", - "DAYS", "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", - "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", - "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", - "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", "DOLT", - "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", - "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", "DRUB", "DRUG", - "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", - "DUNE", "DUNK", "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", - "EAST", "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", - "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", - "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", - "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", - "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET", "FELL", - "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF", "FIGS", "FILE", "FILL", - "FILM", "FIND", "FINE", "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", - "FITS", "FIVE", "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", - "FLEW", "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", - "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", - "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", - "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", "FUEL", - "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", "GAFF", "GAGE", - "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL", "GALT", "GAME", "GANG", - "GARB", "GARY", "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", - "GELD", "GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", - "GILT", "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", - "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", - "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", - "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", "GREG", - "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", "GRUB", "GULF", - "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS", - "HACK", "HAIL", "HAIR", "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", - "HANG", "HANK", "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", - "HATE", "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", - "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", - "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", - "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", "HIVE", - "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", "HONE", - "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE", "HOST", "HOUR", - "HOVE", "HOWE", "HOWL", "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", - "HUGO", "HULK", "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", - "HYDE", "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", - "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", - "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", - "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN", - "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", "JOLT", "JOVE", - "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE", "JULY", "JUNE", "JUNK", - "JUNO", "JURY", "JUST", "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", - "KATE", "KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", - "KILL", "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", - "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", - "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", - "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", "LAST", - "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", "LEAF", "LEAK", - "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", - "LESK", "LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", - "LIES", "LIEU", "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", - "LIMB", "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", - "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", - "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", - "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", "LUKE", - "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", - "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", "MAIL", "MAIN", - "MAKE", "MALE", "MALI", "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", - "MARE", "MARK", "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", - "MATE", "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", - "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", - "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", - "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", - "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT", "MONA", - "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT", "MORE", "MORN", "MORT", - "MOSS", "MOST", "MOTH", "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", - "MULL", "MURK", "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", - "NAIL", "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", - "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", - "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", - "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", "NOTE", - "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", "OBOE", "ODIN", - "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", - "OMEN", "OMIT", "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", - "OSLO", "OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", - "OWLY", "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", - "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", - "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", - "REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", "REST", - "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", "RING", "RINK", - "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE", - "ROIL", "ROLL", "ROME", "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", - "ROSE", "ROSS", "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", - "RUBY", "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", - "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", - "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", - "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", - "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", "SELF", - "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", - "SHED", "SHIM", "SHIN", "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", - "SICK", "SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", - "SINE", "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", - "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", - "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", - "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG", - "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", "SOLD", "SOME", - "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL", "SOUR", "SOWN", "STAB", - "STAG", "STAN", "STAR", "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", - "STUN", "SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", - "SURF", "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", - "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", - "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", - "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", "THAT", - "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD", "THUG", "TICK", - "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", - "TINE", "TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", - "TONE", "TONG", "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", - "TOUR", "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", - "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", - "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", - "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", "VAIL", - "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", - "VEND", "VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", "VINE", "VISE", - "VOID", "VOLT", "VOTE", "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", - "WALE", "WALK", "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", - "WARM", "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", - "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", - "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", - "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", - "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH", "WOLF", - "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK", "WORM", "WORN", "WOVE", - "WRIT", "WYNN", "YALE", "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", - "YEAH", "YEAR", "YELL", "YOGA", "YOKE"}; + "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", + "AMY", "AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", "ARM", + "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK", "AWL", "AWN", "AX", + "AYE", "BAD", "BAG", "BAH", "BAM", "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", + "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", + "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", + "CAP", "CAR", "CAT", "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY", "CRY", + "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL", "DEN", + "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", + "DUB", "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO", "ELI", "ELK", "ELM", + "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", + "FED", "FEE", "FEW", "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", "FRY", + "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", + "GET", "GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", + "HAD", "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", "HEN", "HER", "HEW", + "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", + "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", + "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", "ITS", "IVY", "JAB", "JAG", "JAM", + "JAN", "JAR", "JAW", "JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", + "JUT", "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", "LAG", + "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", + "LIN", "LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", "LYE", + "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME", "MEG", "MEL", "MEN", + "MET", "MEW", "MID", "MIN", "MIT", "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", + "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", + "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", + "NUT", "O", "OAF", "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", "OK", + "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW", "OWE", + "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", + "PEG", "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", "PLY", "PO", "POD", + "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", + "RAN", "RAP", "RAT", "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO", + "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", + "SAC", "SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", + "SET", "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", "SLY", "SO", "SOB", + "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", + "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", + "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", "TOW", "TOY", "TRY", "TUB", "TUG", + "TUM", "TUN", "TWO", "UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", + "WAS", "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON", "WOO", + "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", + "ABLE", "ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", "ADEN", "AFAR", "AFRO", "AGEE", + "AHEM", "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", + "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", + "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", + "ASKS", "ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW", "AWAY", "AWRY", "BABE", "BABY", + "BACH", "BACK", "BADE", "BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", "BAND", "BANE", + "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", + "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", + "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", + "BIDE", "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", "BLAT", "BLED", "BLEW", + "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", + "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", + "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", + "BRAN", "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB", "BULK", "BULL", "BUNK", + "BUNT", "BUOY", "BURG", "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", "CADY", + "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", + "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", + "CHEF", "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", + "CLAN", "CLAW", "CLAY", "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO", "CODA", + "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", + "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", + "CRIB", "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", + "CUTS", "DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH", "DATA", + "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", + "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", + "DINT", "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", "DOLT", "DOME", "DONE", + "DOOM", "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", + "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", + "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", + "EDIT", "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS", "ERIC", "EROS", "EVEN", + "EVER", "EVIL", "EYED", "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", + "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", + "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", + "FIVE", "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", + "FLUE", "FOAL", "FOAM", "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD", "FORE", + "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", + "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", + "GALA", "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", + "GEAR", "GELD", "GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD", "GIRL", + "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", + "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", + "GRAB", "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", "GRUB", "GULF", "GULL", + "GUNK", "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF", "HALL", + "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", + "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", + "HELL", "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", "HIGH", "HIKE", "HILL", + "HILT", "HIND", "HINT", "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", + "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", + "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", + "HYDE", "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS", "IOTA", "IOWA", "IRIS", + "IRMA", "IRON", "ISLE", "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", "JEFF", + "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", + "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", + "JUST", "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", + "KEYS", "KICK", "KILL", "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB", "KNOT", + "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", + "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", + "LAWS", "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", + "LESK", "LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT", "LIKE", + "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", + "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", + "LORD", "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", "LUKE", "LULU", "LUND", + "LUNG", "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", + "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", + "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", + "MEEK", "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE", "MIKE", "MILD", "MILE", + "MILK", "MILL", "MILT", "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", + "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", + "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", + "MURK", "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME", "NARY", "NASH", "NAVE", + "NAVY", "NEAL", "NEAR", "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS", "NEWT", + "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", + "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", + "OKAY", "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", + "ORGY", "OSLO", "OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD", "QUIT", + "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", + "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", + "RENA", "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", "RING", "RINK", "RISE", + "RISK", "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF", "ROOK", + "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", + "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", + "SAGE", "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", "SARA", "SAUL", "SAVE", + "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", + "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", + "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", + "SINE", "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM", "SKIN", "SKIT", "SLAB", + "SLAM", "SLAT", "SLAY", "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", "SLUM", + "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", + "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", + "STAR", "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", + "SUNK", "SURE", "SURF", "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT", "TAIL", + "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", + "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", + "THIN", "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", + "TINE", "TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK", "TOOL", + "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", + "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", + "TUSK", "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", "VAIL", "VAIN", "VALE", + "VARY", "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", + "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", + "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", + "WAVY", "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL", "WELT", "WENT", "WERE", + "WERT", "WEST", "WHAM", "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", + "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", + "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", + "YEAR", "YELL", "YOGA", "YOKE"}; /* Extract 'length' bits from the char array 's' starting with bit 'start' */ @@ -279,12 +179,10 @@ RFC1751::extract(char const* s, int start, int length) unsigned char cr; unsigned long x; - XRPL_ASSERT(length <= 11, "ripple::RFC1751::extract : maximum length"); - XRPL_ASSERT(start >= 0, "ripple::RFC1751::extract : minimum start"); - XRPL_ASSERT(length >= 0, "ripple::RFC1751::extract : minimum length"); - XRPL_ASSERT( - start + length <= 66, - "ripple::RFC1751::extract : maximum start + length"); + XRPL_ASSERT(length <= 11, "xrpl::RFC1751::extract : maximum length"); + XRPL_ASSERT(start >= 0, "xrpl::RFC1751::extract : minimum start"); + XRPL_ASSERT(length >= 0, "xrpl::RFC1751::extract : minimum length"); + XRPL_ASSERT(start + length <= 66, "xrpl::RFC1751::extract : maximum start + length"); int const shiftR = 24 - (length + (start % 8)); cl = s[start / 8]; // get components @@ -314,12 +212,9 @@ RFC1751::btoe(std::string& strHuman, std::string const& strData) caBuffer[8] = char(p) << 6; - strHuman = std::string() + s_dictionary[extract(caBuffer, 0, 11)] + " " + - s_dictionary[extract(caBuffer, 11, 11)] + " " + - s_dictionary[extract(caBuffer, 22, 11)] + " " + - s_dictionary[extract(caBuffer, 33, 11)] + " " + - s_dictionary[extract(caBuffer, 44, 11)] + " " + - s_dictionary[extract(caBuffer, 55, 11)]; + strHuman = std::string() + s_dictionary[extract(caBuffer, 0, 11)] + " " + s_dictionary[extract(caBuffer, 11, 11)] + + " " + s_dictionary[extract(caBuffer, 22, 11)] + " " + s_dictionary[extract(caBuffer, 33, 11)] + " " + + s_dictionary[extract(caBuffer, 44, 11)] + " " + s_dictionary[extract(caBuffer, 55, 11)]; } void @@ -331,12 +226,10 @@ RFC1751::insert(char* s, int x, int start, int length) unsigned long y; int shift; - XRPL_ASSERT(length <= 11, "ripple::RFC1751::insert : maximum length"); - XRPL_ASSERT(start >= 0, "ripple::RFC1751::insert : minimum start"); - XRPL_ASSERT(length >= 0, "ripple::RFC1751::insert : minimum length"); - XRPL_ASSERT( - start + length <= 66, - "ripple::RFC1751::insert : maximum start + length"); + XRPL_ASSERT(length <= 11, "xrpl::RFC1751::insert : maximum length"); + XRPL_ASSERT(start >= 0, "xrpl::RFC1751::insert : minimum start"); + XRPL_ASSERT(length >= 0, "xrpl::RFC1751::insert : minimum length"); + XRPL_ASSERT(start + length <= 66, "xrpl::RFC1751::insert : maximum start + length"); shift = ((8 - ((start + length) % 8)) % 8); y = (long)x << shift; @@ -470,11 +363,7 @@ RFC1751::getKeyFromEnglish(std::string& strKey, std::string const& strHuman) boost::algorithm::trim(strTrimmed); - boost::algorithm::split( - vWords, - strTrimmed, - boost::algorithm::is_space(), - boost::algorithm::token_compress_on); + boost::algorithm::split(vWords, strTrimmed, boost::algorithm::is_space(), boost::algorithm::token_compress_on); rc = 12 == vWords.size() ? 1 : -1; @@ -523,8 +412,7 @@ RFC1751::getWordFromBlob(void const* blob, size_t bytes) hash ^= (hash >> 11); hash += (hash << 15); - return s_dictionary - [hash % (sizeof(s_dictionary) / sizeof(s_dictionary[0]))]; + return s_dictionary[hash % (sizeof(s_dictionary) / sizeof(s_dictionary[0]))]; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/crypto/csprng.cpp b/src/libxrpl/crypto/csprng.cpp index 986c30d8fd..7858d4089c 100644 --- a/src/libxrpl/crypto/csprng.cpp +++ b/src/libxrpl/crypto/csprng.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { csprng_engine::csprng_engine() { @@ -65,10 +46,7 @@ csprng_engine::mix_entropy(void* buffer, std::size_t count) // We add data to the pool, but we conservatively assume that // it contributes no actual entropy. - RAND_add( - entropy.data(), - entropy.size() * sizeof(std::random_device::result_type), - 0); + RAND_add(entropy.data(), entropy.size() * sizeof(std::random_device::result_type), 0); if (buffer != nullptr && count != 0) RAND_add(buffer, count, 0); @@ -84,8 +62,7 @@ csprng_engine::operator()(void* ptr, std::size_t count) std::lock_guard lock(mutex_); #endif - auto const result = - RAND_bytes(reinterpret_cast(ptr), count); + auto const result = RAND_bytes(reinterpret_cast(ptr), count); if (result != 1) Throw("CSPRNG: Insufficient entropy"); @@ -106,4 +83,4 @@ crypto_prng() return engine; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/crypto/secure_erase.cpp b/src/libxrpl/crypto/secure_erase.cpp index d5f2e25059..5b65b342ec 100644 --- a/src/libxrpl/crypto/secure_erase.cpp +++ b/src/libxrpl/crypto/secure_erase.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { void secure_erase(void* dest, std::size_t bytes) @@ -31,4 +12,4 @@ secure_erase(void* dest, std::size_t bytes) OPENSSL_cleanse(dest, bytes); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/json/JsonPropertyStream.cpp b/src/libxrpl/json/JsonPropertyStream.cpp index a8441f39ec..fb5a7b32a4 100644 --- a/src/libxrpl/json/JsonPropertyStream.cpp +++ b/src/libxrpl/json/JsonPropertyStream.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { JsonPropertyStream::JsonPropertyStream() : m_top(Json::objectValue) { @@ -180,4 +161,4 @@ JsonPropertyStream::add(std::string const& v) m_stack.back()->append(v); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/json/Object.cpp b/src/libxrpl/json/Object.cpp deleted file mode 100644 index 55e573c0db..0000000000 --- a/src/libxrpl/json/Object.cpp +++ /dev/null @@ -1,252 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace Json { - -Collection::Collection(Collection* parent, Writer* writer) - : parent_(parent), writer_(writer), enabled_(true) -{ - checkWritable("Collection::Collection()"); - if (parent_) - { - check(parent_->enabled_, "Parent not enabled in constructor"); - parent_->enabled_ = false; - } -} - -Collection::~Collection() -{ - if (writer_) - writer_->finish(); - if (parent_) - parent_->enabled_ = true; -} - -Collection& -Collection::operator=(Collection&& that) noexcept -{ - parent_ = that.parent_; - writer_ = that.writer_; - enabled_ = that.enabled_; - - that.parent_ = nullptr; - that.writer_ = nullptr; - that.enabled_ = false; - - return *this; -} - -Collection::Collection(Collection&& that) noexcept -{ - *this = std::move(that); -} - -void -Collection::checkWritable(std::string const& label) -{ - if (!enabled_) - ripple::Throw(label + ": not enabled"); - if (!writer_) - ripple::Throw(label + ": not writable"); -} - -//------------------------------------------------------------------------------ - -Object::Root::Root(Writer& w) : Object(nullptr, &w) -{ - writer_->startRoot(Writer::object); -} - -Object -Object::setObject(std::string const& key) -{ - checkWritable("Object::setObject"); - if (writer_) - writer_->startSet(Writer::object, key); - return Object(this, writer_); -} - -Array -Object::setArray(std::string const& key) -{ - checkWritable("Object::setArray"); - if (writer_) - writer_->startSet(Writer::array, key); - return Array(this, writer_); -} - -//------------------------------------------------------------------------------ - -Object -Array::appendObject() -{ - checkWritable("Array::appendObject"); - if (writer_) - writer_->startAppend(Writer::object); - return Object(this, writer_); -} - -Array -Array::appendArray() -{ - checkWritable("Array::makeArray"); - if (writer_) - writer_->startAppend(Writer::array); - return Array(this, writer_); -} - -//------------------------------------------------------------------------------ - -Object::Proxy::Proxy(Object& object, std::string const& key) - : object_(object), key_(key) -{ -} - -Object::Proxy -Object::operator[](std::string const& key) -{ - return Proxy(*this, key); -} - -Object::Proxy -Object::operator[](Json::StaticString const& key) -{ - return Proxy(*this, std::string(key)); -} - -//------------------------------------------------------------------------------ - -void -Array::append(Json::Value const& v) -{ - auto t = v.type(); - switch (t) - { - case Json::nullValue: - return append(nullptr); - case Json::intValue: - return append(v.asInt()); - case Json::uintValue: - return append(v.asUInt()); - case Json::realValue: - return append(v.asDouble()); - case Json::stringValue: - return append(v.asString()); - case Json::booleanValue: - return append(v.asBool()); - - case Json::objectValue: { - auto object = appendObject(); - copyFrom(object, v); - return; - } - - case Json::arrayValue: { - auto array = appendArray(); - for (auto& item : v) - array.append(item); - return; - } - } - UNREACHABLE("Json::Array::append : invalid type"); // LCOV_EXCL_LINE -} - -void -Object::set(std::string const& k, Json::Value const& v) -{ - auto t = v.type(); - switch (t) - { - case Json::nullValue: - return set(k, nullptr); - case Json::intValue: - return set(k, v.asInt()); - case Json::uintValue: - return set(k, v.asUInt()); - case Json::realValue: - return set(k, v.asDouble()); - case Json::stringValue: - return set(k, v.asString()); - case Json::booleanValue: - return set(k, v.asBool()); - - case Json::objectValue: { - auto object = setObject(k); - copyFrom(object, v); - return; - } - - case Json::arrayValue: { - auto array = setArray(k); - for (auto& item : v) - array.append(item); - return; - } - } - UNREACHABLE("Json::Object::set : invalid type"); // LCOV_EXCL_LINE -} - -//------------------------------------------------------------------------------ - -namespace { - -template -void -doCopyFrom(Object& to, Json::Value const& from) -{ - XRPL_ASSERT(from.isObjectOrNull(), "Json::doCopyFrom : valid input type"); - auto members = from.getMemberNames(); - for (auto& m : members) - to[m] = from[m]; -} - -} // namespace - -void -copyFrom(Json::Value& to, Json::Value const& from) -{ - if (!to) // Short circuit this very common case. - to = from; - else - doCopyFrom(to, from); -} - -void -copyFrom(Object& to, Json::Value const& from) -{ - doCopyFrom(to, from); -} - -WriterObject -stringWriterObject(std::string& s) -{ - return WriterObject(stringOutput(s)); -} - -} // namespace Json diff --git a/src/libxrpl/json/Output.cpp b/src/libxrpl/json/Output.cpp index 84388884da..626dbeb4b8 100644 --- a/src/libxrpl/json/Output.cpp +++ b/src/libxrpl/json/Output.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include diff --git a/src/libxrpl/json/Writer.cpp b/src/libxrpl/json/Writer.cpp index 369763da09..be9595b088 100644 --- a/src/libxrpl/json/Writer.cpp +++ b/src/libxrpl/json/Writer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -153,10 +134,7 @@ public: auto t = stack_.top().type; if (t != type) { - check( - false, - "Not an " + - ((type == array ? "array: " : "object: ") + message)); + check(false, "Not an " + ((type == array ? "array: " : "object: ") + message)); } if (stack_.top().isFirst) stack_.top().isFirst = false; @@ -212,7 +190,7 @@ public: } private: - // JSON collections are either arrrays, or objects. + // JSON collections are either arrays, or objects. struct Collection { explicit Collection() = default; @@ -282,14 +260,14 @@ Writer::output(Json::Value const& value) void Writer::output(float f) { - auto s = ripple::to_string(f); + auto s = xrpl::to_string(f); impl_->output({s.data(), lengthWithoutTrailingZeros(s)}); } void Writer::output(double f) { - auto s = ripple::to_string(f); + auto s = xrpl::to_string(f); impl_->output({s.data(), lengthWithoutTrailingZeros(s)}); } diff --git a/src/libxrpl/json/json_reader.cpp b/src/libxrpl/json/json_reader.cpp index 9bad898bee..22df530b7e 100644 --- a/src/libxrpl/json/json_reader.cpp +++ b/src/libxrpl/json/json_reader.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -123,9 +104,7 @@ Reader::parse(char const* beginDoc, char const* endDoc, Value& root) token.type_ = tokenError; token.start_ = beginDoc; token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); + addError("A valid JSON document must be either an array or an object value.", token); return false; } @@ -176,8 +155,7 @@ Reader::readValue(unsigned depth) break; default: - return addError( - "Syntax error: value, object or array expected.", token); + return addError("Syntax error: value, object or array expected.", token); } return successful; @@ -260,7 +238,7 @@ Reader::readToken(Token& token) case 'f': token.type_ = tokenFalse; - ok = match("alse", 4); + ok = match("alse", 4); // cspell:disable-line break; case 'n': @@ -380,10 +358,7 @@ Reader::readNumber() { if (!std::isdigit(static_cast(*current_))) { - auto ret = std::find( - std::begin(extended_tokens), - std::end(extended_tokens), - *current_); + auto ret = std::find(std::begin(extended_tokens), std::end(extended_tokens), *current_); if (ret == std::end(extended_tokens)) break; @@ -448,8 +423,7 @@ Reader::readObject(Token& tokenStart, unsigned depth) if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); + return addErrorAndRecover("Missing ':' after object member name", colon, tokenObjectEnd); } // Reject duplicate names @@ -467,13 +441,9 @@ Reader::readObject(Token& tokenStart, unsigned depth) Token comma; if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd); + return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd); } bool finalizeTokenOk = true; @@ -485,8 +455,7 @@ Reader::readObject(Token& tokenStart, unsigned depth) return true; } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd); } bool @@ -523,16 +492,11 @@ Reader::readArray(Token& tokenStart, unsigned depth) ok = readToken(token); } - bool badTokenType = - (token.type_ != tokenArraySeparator && - token.type_ != tokenArrayEnd); + bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", - token, - tokenArrayEnd); + return addErrorAndRecover("Missing ',' or ']' in array declaration", token, tokenArrayEnd); } if (token.type_ == tokenArrayEnd) @@ -553,19 +517,14 @@ Reader::decodeNumber(Token& token) if (current == token.end_) { - return addError( - "'" + std::string(token.start_, token.end_) + - "' is not a valid number.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' is not a valid number.", token); } // The existing Json integers are 32-bit so using a 64-bit value here avoids // overflows in the conversion code below. std::int64_t value = 0; - static_assert( - sizeof(value) > sizeof(Value::maxUInt), - "The JSON integer overflow logic will need to be reworked."); + static_assert(sizeof(value) > sizeof(Value::maxUInt), "The JSON integer overflow logic will need to be reworked."); while (current < token.end_ && (value <= Value::maxUInt)) { @@ -573,10 +532,7 @@ Reader::decodeNumber(Token& token) if (c < '0' || c > '9') { - return addError( - "'" + std::string(token.start_, token.end_) + - "' is not a number.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); } value = (value * 10) + (c - '0'); @@ -585,10 +541,7 @@ Reader::decodeNumber(Token& token) // More tokens left -> input is larger than largest possible return value if (current != token.end_) { - return addError( - "'" + std::string(token.start_, token.end_) + - "' exceeds the allowable range.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.", token); } if (isNegative) @@ -597,10 +550,7 @@ Reader::decodeNumber(Token& token) if (value < Value::minInt || value > Value::maxInt) { - return addError( - "'" + std::string(token.start_, token.end_) + - "' exceeds the allowable range.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.", token); } currentValue() = static_cast(value); @@ -609,10 +559,7 @@ Reader::decodeNumber(Token& token) { if (value > Value::maxUInt) { - return addError( - "'" + std::string(token.start_, token.end_) + - "' exceeds the allowable range.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.", token); } // If it's representable as a signed integer, construct it as one. @@ -656,9 +603,7 @@ Reader::decodeDouble(Token& token) count = sscanf(buffer.c_str(), format, &value); } if (count != 1) - return addError( - "'" + std::string(token.start_, token.end_) + "' is not a number.", - token); + return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); currentValue() = value; return true; } @@ -691,8 +636,7 @@ Reader::decodeString(Token& token, std::string& decoded) else if (c == '\\') { if (current == end) - return addError( - "Empty escape sequence in string", token, current); + return addError("Empty escape sequence in string", token, current); Char escape = *current++; @@ -741,8 +685,7 @@ Reader::decodeString(Token& token, std::string& decoded) break; default: - return addError( - "Bad escape sequence in string", token, current); + return addError("Bad escape sequence in string", token, current); } } else @@ -755,11 +698,7 @@ Reader::decodeString(Token& token, std::string& decoded) } bool -Reader::decodeUnicodeCodePoint( - Token& token, - Location& current, - Location end, - unsigned int& unicode) +Reader::decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode) { if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) return false; @@ -780,8 +719,7 @@ Reader::decodeUnicodeCodePoint( { if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + - (surrogatePair & 0x3FF); + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); } else return false; @@ -798,17 +736,10 @@ Reader::decodeUnicodeCodePoint( } bool -Reader::decodeUnicodeEscapeSequence( - Token& token, - Location& current, - Location end, - unsigned int& unicode) +Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode) { if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); + return addError("Bad unicode escape sequence in string: four digits expected.", token, current); unicode = 0; @@ -865,10 +796,7 @@ Reader::recoverFromError(TokenType skipUntilToken) } bool -Reader::addErrorAndRecover( - std::string const& message, - Token& token, - TokenType skipUntilToken) +Reader::addErrorAndRecover(std::string const& message, Token& token, TokenType skipUntilToken) { addError(message, token); return recoverFromError(skipUntilToken); @@ -890,8 +818,7 @@ Reader::getNextChar() } void -Reader::getLocationLineAndColumn(Location location, int& line, int& column) - const +Reader::getLocationLineAndColumn(Location location, int& line, int& column) const { Location current = begin_; Location lastLineStart = current; @@ -926,27 +853,22 @@ Reader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); - return "Line " + std::to_string(line) + ", Column " + - std::to_string(column); + return "Line " + std::to_string(line) + ", Column " + std::to_string(column); } std::string -Reader::getFormatedErrorMessages() const +Reader::getFormattedErrorMessages() const { std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) + for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { ErrorInfo const& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; if (error.extra_) - formattedMessage += "See " + - getLocationLineAndColumn(error.extra_) + " for detail.\n"; + formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; } return formattedMessage; @@ -960,7 +882,7 @@ operator>>(std::istream& sin, Value& root) // XRPL_ASSERT(ok, "Json::operator>>() : parse succeeded"); if (!ok) - ripple::Throw(reader.getFormatedErrorMessages()); + xrpl::Throw(reader.getFormattedErrorMessages()); return sin; } diff --git a/src/libxrpl/json/json_value.cpp b/src/libxrpl/json/json_value.cpp index 7e4d8b6d81..edbbafc1eb 100644 --- a/src/libxrpl/json/json_value.cpp +++ b/src/libxrpl/json/json_value.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,9 +14,6 @@ namespace Json { Value const Value::null; -Int const Value::minInt = Int(~(UInt(-1) / 2)); -Int const Value::maxInt = Int(UInt(-1) / 2); -UInt const Value::maxUInt = UInt(-1); class DefaultValueAllocator : public ValueAllocator { @@ -55,8 +33,7 @@ public: } char* - duplicateStringValue(char const* value, unsigned int length = unknown) - override + duplicateStringValue(char const* value, unsigned int length = unknown) override { //@todo investigate this old optimization // if ( !value || value[0] == 0 ) @@ -112,21 +89,15 @@ Value::CZString::CZString(int index) : cstr_(0), index_(index) } Value::CZString::CZString(char const* cstr, DuplicationPolicy allocate) - : cstr_( - allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr) - , index_(allocate) + : cstr_(allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr), index_(allocate) { } Value::CZString::CZString(CZString const& other) : cstr_( - other.index_ != noDuplication && other.cstr_ != 0 - ? valueAllocator()->makeMemberName(other.cstr_) - : other.cstr_) - , index_( - other.cstr_ - ? (other.index_ == noDuplication ? noDuplication : duplicate) - : other.index_) + other.index_ != noDuplication && other.cstr_ != 0 ? valueAllocator()->makeMemberName(other.cstr_) + : other.cstr_) + , index_(other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) { } @@ -240,17 +211,15 @@ Value::Value(char const* value) : type_(stringValue), allocated_(true) value_.string_ = valueAllocator()->duplicateStringValue(value); } -Value::Value(ripple::Number const& value) : type_(stringValue), allocated_(true) +Value::Value(xrpl::Number const& value) : type_(stringValue), allocated_(true) { auto const tmp = to_string(value); - value_.string_ = - valueAllocator()->duplicateStringValue(tmp.c_str(), tmp.length()); + value_.string_ = valueAllocator()->duplicateStringValue(tmp.c_str(), tmp.length()); } Value::Value(std::string const& value) : type_(stringValue), allocated_(true) { - value_.string_ = valueAllocator()->duplicateStringValue( - value.c_str(), (unsigned int)value.length()); + value_.string_ = valueAllocator()->duplicateStringValue(value.c_str(), (unsigned int)value.length()); } Value::Value(StaticString const& value) : type_(stringValue), allocated_(false) @@ -278,8 +247,7 @@ Value::Value(Value const& other) : type_(other.type_) case stringValue: if (other.value_.string_) { - value_.string_ = valueAllocator()->duplicateStringValue( - other.value_.string_); + value_.string_ = valueAllocator()->duplicateStringValue(other.value_.string_); allocated_ = true; } else @@ -337,8 +305,7 @@ Value::operator=(Value const& other) return *this; } -Value::Value(Value&& other) noexcept - : value_(other.value_), type_(other.type_), allocated_(other.allocated_) +Value::Value(Value&& other) noexcept : value_(other.value_), type_(other.type_), allocated_(other.allocated_) { other.type_ = nullValue; other.allocated_ = 0; @@ -414,8 +381,7 @@ operator<(Value const& x, Value const& y) case stringValue: return (x.value_.string_ == 0 && y.value_.string_) || - (y.value_.string_ && x.value_.string_ && - strcmp(x.value_.string_, y.value_.string_) < 0); + (y.value_.string_ && x.value_.string_ && strcmp(x.value_.string_, y.value_.string_) < 0); case arrayValue: case objectValue: { @@ -465,13 +431,11 @@ operator==(Value const& x, Value const& y) case stringValue: return x.value_.string_ == y.value_.string_ || - (y.value_.string_ && x.value_.string_ && - !strcmp(x.value_.string_, y.value_.string_)); + (y.value_.string_ && x.value_.string_ && !strcmp(x.value_.string_, y.value_.string_)); case arrayValue: case objectValue: - return x.value_.map_->size() == y.value_.map_->size() && - *x.value_.map_ == *y.value_.map_; + return x.value_.map_->size() == y.value_.map_->size() && *x.value_.map_ == *y.value_.map_; // LCOV_EXCL_START default: @@ -537,15 +501,11 @@ Value::asInt() const return value_.int_; case uintValue: - JSON_ASSERT_MESSAGE( - value_.uint_ < (unsigned)maxInt, - "integer out of signed integer range"); + JSON_ASSERT_MESSAGE(value_.uint_ < (unsigned)maxInt, "integer out of signed integer range"); return value_.uint_; case realValue: - JSON_ASSERT_MESSAGE( - value_.real_ >= minInt && value_.real_ <= maxInt, - "Real out of signed integer range"); + JSON_ASSERT_MESSAGE(value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range"); return Int(value_.real_); case booleanValue: @@ -569,6 +529,63 @@ Value::asInt() const return 0; // unreachable; } +UInt +Value::asAbsUInt() const +{ + switch (type_) + { + case nullValue: + return 0; + + case intValue: { + // Doing this conversion through int64 avoids overflow error for + // value_.int_ = -1 * 2^31 i.e. numeric_limits::min(). + if (value_.int_ < 0) + return static_cast(value_.int_) * -1; + return value_.int_; + } + + case uintValue: + return value_.uint_; + + case realValue: { + if (value_.real_ < 0) + { + JSON_ASSERT_MESSAGE(-1 * value_.real_ <= maxUInt, "Real out of unsigned integer range"); + return UInt(-1 * value_.real_); + } + JSON_ASSERT_MESSAGE(value_.real_ <= maxUInt, "Real out of unsigned integer range"); + return UInt(value_.real_); + } + + case booleanValue: + return value_.bool_ ? 1 : 0; + + case stringValue: { + char const* const str{value_.string_ ? value_.string_ : ""}; + auto const temp = beast::lexicalCastThrow(str); + if (temp < 0) + { + JSON_ASSERT_MESSAGE(-1 * temp <= maxUInt, "String out of unsigned integer range"); + return -1 * temp; + } + JSON_ASSERT_MESSAGE(temp <= maxUInt, "String out of unsigned integer range"); + return temp; + } + + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE(false, "Type is not convertible to int"); + + // LCOV_EXCL_START + default: + UNREACHABLE("Json::Value::asAbsInt : invalid type"); + // LCOV_EXCL_STOP + } + + return 0; // unreachable; +} + Value::UInt Value::asUInt() const { @@ -578,18 +595,14 @@ Value::asUInt() const return 0; case intValue: - JSON_ASSERT_MESSAGE( - value_.int_ >= 0, - "Negative integer can not be converted to unsigned integer"); + JSON_ASSERT_MESSAGE(value_.int_ >= 0, "Negative integer can not be converted to unsigned integer"); return value_.int_; case uintValue: return value_.uint_; case realValue: - JSON_ASSERT_MESSAGE( - value_.real_ >= 0 && value_.real_ <= maxUInt, - "Real out of unsigned integer range"); + JSON_ASSERT_MESSAGE(value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range"); return UInt(value_.real_); case booleanValue: @@ -690,45 +703,34 @@ Value::isConvertibleTo(ValueType other) const return true; case intValue: - return (other == nullValue && value_.int_ == 0) || - other == intValue || (other == uintValue && value_.int_ >= 0) || - other == realValue || other == stringValue || + return (other == nullValue && value_.int_ == 0) || other == intValue || + (other == uintValue && value_.int_ >= 0) || other == realValue || other == stringValue || other == booleanValue; case uintValue: return (other == nullValue && value_.uint_ == 0) || - (other == intValue && value_.uint_ <= (unsigned)maxInt) || - other == uintValue || other == realValue || + (other == intValue && value_.uint_ <= (unsigned)maxInt) || other == uintValue || other == realValue || other == stringValue || other == booleanValue; case realValue: return (other == nullValue && value_.real_ == 0.0) || - (other == intValue && value_.real_ >= minInt && - value_.real_ <= maxInt) || - (other == uintValue && value_.real_ >= 0 && - value_.real_ <= maxUInt && - std::fabs(round(value_.real_) - value_.real_) < - std::numeric_limits::epsilon()) || - other == realValue || other == stringValue || - other == booleanValue; + (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt) || + (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt && + std::fabs(round(value_.real_) - value_.real_) < std::numeric_limits::epsilon()) || + other == realValue || other == stringValue || other == booleanValue; case booleanValue: - return (other == nullValue && value_.bool_ == false) || - other == intValue || other == uintValue || other == realValue || - other == stringValue || other == booleanValue; + return (other == nullValue && value_.bool_ == false) || other == intValue || other == uintValue || + other == realValue || other == stringValue || other == booleanValue; case stringValue: - return other == stringValue || - (other == nullValue && - (!value_.string_ || value_.string_[0] == 0)); + return other == stringValue || (other == nullValue && (!value_.string_ || value_.string_[0] == 0)); case arrayValue: - return other == arrayValue || - (other == nullValue && value_.map_->size() == 0); + return other == arrayValue || (other == nullValue && value_.map_->size() == 0); case objectValue: - return other == objectValue || - (other == nullValue && value_.map_->size() == 0); + return other == objectValue || (other == nullValue && value_.map_->size() == 0); // LCOV_EXCL_START default: @@ -792,9 +794,7 @@ Value::operator bool() const void Value::clear() { - XRPL_ASSERT( - type_ == nullValue || type_ == arrayValue || type_ == objectValue, - "Json::Value::clear : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "Json::Value::clear : valid type"); switch (type_) { @@ -811,9 +811,7 @@ Value::clear() Value& Value::operator[](UInt index) { - XRPL_ASSERT( - type_ == nullValue || type_ == arrayValue, - "Json::Value::operator[](UInt) : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == arrayValue, "Json::Value::operator[](UInt) : valid type"); if (type_ == nullValue) *this = Value(arrayValue); @@ -832,9 +830,7 @@ Value::operator[](UInt index) Value const& Value::operator[](UInt index) const { - XRPL_ASSERT( - type_ == nullValue || type_ == arrayValue, - "Json::Value::operator[](UInt) const : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == arrayValue, "Json::Value::operator[](UInt) const : valid type"); if (type_ == nullValue) return null; @@ -857,15 +853,12 @@ Value::operator[](char const* key) Value& Value::resolveReference(char const* key, bool isStatic) { - XRPL_ASSERT( - type_ == nullValue || type_ == objectValue, - "Json::Value::resolveReference : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == objectValue, "Json::Value::resolveReference : valid type"); if (type_ == nullValue) *this = Value(objectValue); - CZString actualKey( - key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); + CZString actualKey(key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) @@ -893,9 +886,7 @@ Value::isValidIndex(UInt index) const Value const& Value::operator[](char const* key) const { - XRPL_ASSERT( - type_ == nullValue || type_ == objectValue, - "Json::Value::operator[](const char*) const : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == objectValue, "Json::Value::operator[](const char*) const : valid type"); if (type_ == nullValue) return null; @@ -961,9 +952,7 @@ Value::get(std::string const& key, Value const& defaultValue) const Value Value::removeMember(char const* key) { - XRPL_ASSERT( - type_ == nullValue || type_ == objectValue, - "Json::Value::removeMember : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == objectValue, "Json::Value::removeMember : valid type"); if (type_ == nullValue) return null; @@ -1001,12 +990,16 @@ Value::isMember(std::string const& key) const return isMember(key.c_str()); } +bool +Value::isMember(StaticString const& key) const +{ + return isMember(key.c_str()); +} + Value::Members Value::getMemberNames() const { - XRPL_ASSERT( - type_ == nullValue || type_ == objectValue, - "Json::Value::getMemberNames : valid type"); + XRPL_ASSERT(type_ == nullValue || type_ == objectValue, "Json::Value::getMemberNames : valid type"); if (type_ == nullValue) return Value::Members(); diff --git a/src/libxrpl/json/json_valueiterator.cpp b/src/libxrpl/json/json_valueiterator.cpp index 9f65a48a0d..90a1ebe44b 100644 --- a/src/libxrpl/json/json_valueiterator.cpp +++ b/src/libxrpl/json/json_valueiterator.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - // included by json_value.cpp #include @@ -36,9 +17,7 @@ ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) { } -ValueIteratorBase::ValueIteratorBase( - Value::ObjectValues::iterator const& current) - : current_(current), isNull_(false) +ValueIteratorBase::ValueIteratorBase(Value::ObjectValues::iterator const& current) : current_(current), isNull_(false) { } @@ -79,8 +58,7 @@ ValueIteratorBase::computeDistance(SelfType const& other) const // return difference_type( std::distance( current_, other.current_ ) ); difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) + for (Value::ObjectValues::iterator it = current_; it != other.current_; ++it) { ++myDistance; } @@ -108,26 +86,26 @@ ValueIteratorBase::copy(SelfType const& other) Value ValueIteratorBase::key() const { - Value::CZString const czstring = (*current_).first; + Value::CZString const czString = (*current_).first; - if (czstring.c_str()) + if (czString.c_str()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.c_str())); + if (czString.isStaticString()) + return Value(StaticString(czString.c_str())); - return Value(czstring.c_str()); + return Value(czString.c_str()); } - return Value(czstring.index()); + return Value(czString.index()); } UInt ValueIteratorBase::index() const { - Value::CZString const czstring = (*current_).first; + Value::CZString const czString = (*current_).first; - if (!czstring.c_str()) - return czstring.index(); + if (!czString.c_str()) + return czString.index(); return Value::UInt(-1); } @@ -147,9 +125,7 @@ ValueIteratorBase::memberName() const // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueConstIterator::ValueConstIterator( - Value::ObjectValues::iterator const& current) - : ValueIteratorBase(current) +ValueConstIterator::ValueConstIterator(Value::ObjectValues::iterator const& current) : ValueIteratorBase(current) { } @@ -168,18 +144,15 @@ ValueConstIterator::operator=(ValueIteratorBase const& other) // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueIterator::ValueIterator(Value::ObjectValues::iterator const& current) - : ValueIteratorBase(current) +ValueIterator::ValueIterator(Value::ObjectValues::iterator const& current) : ValueIteratorBase(current) { } -ValueIterator::ValueIterator(ValueConstIterator const& other) - : ValueIteratorBase(other) +ValueIterator::ValueIterator(ValueConstIterator const& other) : ValueIteratorBase(other) { } -ValueIterator::ValueIterator(ValueIterator const& other) - : ValueIteratorBase(other) +ValueIterator::ValueIterator(ValueIterator const& other) : ValueIteratorBase(other) { } diff --git a/src/libxrpl/json/json_writer.cpp b/src/libxrpl/json/json_writer.cpp index fabc697358..e36cf72b1c 100644 --- a/src/libxrpl/json/json_writer.cpp +++ b/src/libxrpl/json/json_writer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -98,11 +79,10 @@ valueToString(double value) // of precision requested below. char buffer[32]; // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distingish the + // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. -#if defined(_MSC_VER) && \ - defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 - // to avoid warning. +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 + // to avoid warning. sprintf_s(buffer, sizeof(buffer), "%.16g", value); #else snprintf(buffer, sizeof(buffer), "%.16g", value); @@ -120,14 +100,13 @@ std::string valueToQuotedString(char const* value) { // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr && - !containsControlCharacter(value)) + if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr && !containsControlCharacter(value)) return std::string("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to std::string is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - unsigned maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL + unsigned maxsize = strlen(value) * 2 + 3; // all-escaped+quotes+NULL std::string result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; @@ -175,8 +154,7 @@ valueToQuotedString(char const* value) if (isControlCharacter(*c)) { std::ostringstream oss; - oss << "\\u" << std::hex << std::uppercase - << std::setfill('0') << std::setw(4) + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*c); result += oss.str(); } @@ -253,9 +231,7 @@ FastWriter::writeValue(Value const& value) Value::Members members(value.getMemberNames()); document_ += "{"; - for (Value::Members::iterator it = members.begin(); - it != members.end(); - ++it) + for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { std::string const& name = *it; @@ -366,7 +342,7 @@ StyledWriter::writeArrayValue(Value const& value) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { @@ -398,9 +374,7 @@ StyledWriter::writeArrayValue(Value const& value) } else // output on a single line { - XRPL_ASSERT( - childValues_.size() == size, - "Json::StyledWriter::writeArrayValue : child size match"); + XRPL_ASSERT(childValues_.size() == size, "Json::StyledWriter::writeArrayValue : child size match"); document_ += "[ "; for (unsigned index = 0; index < size; ++index) @@ -417,7 +391,7 @@ StyledWriter::writeArrayValue(Value const& value) } bool -StyledWriter::isMultineArray(Value const& value) +StyledWriter::isMultilineArray(Value const& value) { int size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; @@ -426,9 +400,7 @@ StyledWriter::isMultineArray(Value const& value) for (int index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; - isMultiLine = isMultiLine || - ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length @@ -492,9 +464,7 @@ StyledWriter::indent() void StyledWriter::unindent() { - XRPL_ASSERT( - int(indentString_.size()) >= indentSize_, - "Json::StyledWriter::unindent : maximum indent size"); + XRPL_ASSERT(int(indentString_.size()) >= indentSize_, "Json::StyledWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentSize_); } @@ -592,7 +562,7 @@ StyledStreamWriter::writeArrayValue(Value const& value) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { @@ -624,9 +594,7 @@ StyledStreamWriter::writeArrayValue(Value const& value) } else // output on a single line { - XRPL_ASSERT( - childValues_.size() == size, - "Json::StyledStreamWriter::writeArrayValue : child size match"); + XRPL_ASSERT(childValues_.size() == size, "Json::StyledStreamWriter::writeArrayValue : child size match"); *document_ << "[ "; for (unsigned index = 0; index < size; ++index) @@ -643,7 +611,7 @@ StyledStreamWriter::writeArrayValue(Value const& value) } bool -StyledStreamWriter::isMultineArray(Value const& value) +StyledStreamWriter::isMultilineArray(Value const& value) { int size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; @@ -652,9 +620,7 @@ StyledStreamWriter::isMultineArray(Value const& value) for (int index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; - isMultiLine = isMultiLine || - ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length @@ -720,8 +686,7 @@ void StyledStreamWriter::unindent() { XRPL_ASSERT( - indentString_.size() >= indentation_.size(), - "Json::StyledStreamWriter::unindent : maximum indent size"); + indentString_.size() >= indentation_.size(), "Json::StyledStreamWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentation_.size()); } diff --git a/src/libxrpl/json/to_string.cpp b/src/libxrpl/json/to_string.cpp index f6fb65d10a..d3b35308a0 100644 --- a/src/libxrpl/json/to_string.cpp +++ b/src/libxrpl/json/to_string.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/libxrpl/ledger/ApplyStateTable.cpp b/src/libxrpl/ledger/ApplyStateTable.cpp index 11126d5242..9892951e15 100644 --- a/src/libxrpl/ledger/ApplyStateTable.cpp +++ b/src/libxrpl/ledger/ApplyStateTable.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { void @@ -84,11 +65,7 @@ ApplyStateTable::visit( switch (item.second.first) { case Action::erase: - func( - item.first, - true, - to.read(keylet::unchecked(item.first)), - item.second.second); + func(item.first, true, to.read(keylet::unchecked(item.first)), item.second.second); break; case Action::insert: @@ -96,11 +73,7 @@ ApplyStateTable::visit( break; case Action::modify: - func( - item.first, - false, - to.read(keylet::unchecked(item.first)), - item.second.second); + func(item.first, false, to.read(keylet::unchecked(item.first)), item.second.second); break; default: @@ -154,15 +127,14 @@ ApplyStateTable::apply( auto curNode = item.second.second; if ((type == &sfModifiedNode) && (*curNode == *origNode)) continue; - std::uint16_t nodeType = curNode - ? curNode->getFieldU16(sfLedgerEntryType) - : origNode->getFieldU16(sfLedgerEntryType); + std::uint16_t nodeType = + curNode ? curNode->getFieldU16(sfLedgerEntryType) : origNode->getFieldU16(sfLedgerEntryType); meta.setAffectedNode(item.first, *type, nodeType); if (type == &sfDeletedNode) { XRPL_ASSERT( origNode && curNode, - "ripple::detail::ApplyStateTable::apply : valid nodes for " + "xrpl::detail::ApplyStateTable::apply : valid nodes for " "deletion"); threadOwners(to, meta, origNode, newMod, j); @@ -171,97 +143,84 @@ ApplyStateTable::apply( { // go through the original node for // modified fields saved on modification - if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) && - !curNode->hasMatchingEntry(obj)) + if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) && !curNode->hasMatchingEntry(obj)) prevs.emplace_back(obj); } if (!prevs.empty()) - meta.getAffectedNode(item.first) - .emplace_back(std::move(prevs)); + meta.getAffectedNode(item.first).emplace_back(std::move(prevs)); STObject finals(sfFinalFields); for (auto const& obj : *curNode) { // go through the final node for final fields - if (obj.getFName().shouldMeta( - SField::sMD_Always | SField::sMD_DeleteFinal)) + if (obj.getFName().shouldMeta(SField::sMD_Always | SField::sMD_DeleteFinal)) finals.emplace_back(obj); } if (!finals.empty()) - meta.getAffectedNode(item.first) - .emplace_back(std::move(finals)); + meta.getAffectedNode(item.first).emplace_back(std::move(finals)); } else if (type == &sfModifiedNode) { XRPL_ASSERT( curNode && origNode, - "ripple::detail::ApplyStateTable::apply : valid nodes for " + "xrpl::detail::ApplyStateTable::apply : valid nodes for " "modification"); - if (curNode->isThreadedType( - to.rules())) // thread transaction to node - // item modified + if (curNode->isThreadedType(to.rules())) // thread transaction to node + // item modified threadItem(meta, curNode); STObject prevs(sfPreviousFields); for (auto const& obj : *origNode) { // search the original node for values saved on modify - if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) && - !curNode->hasMatchingEntry(obj)) + if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) && !curNode->hasMatchingEntry(obj)) prevs.emplace_back(obj); } if (!prevs.empty()) - meta.getAffectedNode(item.first) - .emplace_back(std::move(prevs)); + meta.getAffectedNode(item.first).emplace_back(std::move(prevs)); STObject finals(sfFinalFields); for (auto const& obj : *curNode) { // search the final node for values saved always - if (obj.getFName().shouldMeta( - SField::sMD_Always | SField::sMD_ChangeNew)) + if (obj.getFName().shouldMeta(SField::sMD_Always | SField::sMD_ChangeNew)) finals.emplace_back(obj); } if (!finals.empty()) - meta.getAffectedNode(item.first) - .emplace_back(std::move(finals)); + meta.getAffectedNode(item.first).emplace_back(std::move(finals)); } else if (type == &sfCreatedNode) // if created, thread to owner(s) { XRPL_ASSERT( curNode && !origNode, - "ripple::detail::ApplyStateTable::apply : valid nodes for " + "xrpl::detail::ApplyStateTable::apply : valid nodes for " "creation"); threadOwners(to, meta, curNode, newMod, j); - if (curNode->isThreadedType( - to.rules())) // always thread to self + if (curNode->isThreadedType(to.rules())) // always thread to self threadItem(meta, curNode); STObject news(sfNewFields); for (auto const& obj : *curNode) { // save non-default values - if (!obj.isDefault() && - obj.getFName().shouldMeta( - SField::sMD_Create | SField::sMD_Always)) + if (!obj.isDefault() && obj.getFName().shouldMeta(SField::sMD_Create | SField::sMD_Always)) news.emplace_back(obj); } if (!news.empty()) - meta.getAffectedNode(item.first) - .emplace_back(std::move(news)); + meta.getAffectedNode(item.first).emplace_back(std::move(news)); } else { // LCOV_EXCL_START UNREACHABLE( - "ripple::detail::ApplyStateTable::apply : unsupported " + "xrpl::detail::ApplyStateTable::apply : unsupported " "operation type"); // LCOV_EXCL_STOP } @@ -317,10 +276,8 @@ ApplyStateTable::exists(ReadView const& base, Keylet const& k) const } auto -ApplyStateTable::succ( - ReadView const& base, - key_type const& key, - std::optional const& last) const -> std::optional +ApplyStateTable::succ(ReadView const& base, key_type const& key, std::optional const& last) const + -> std::optional { std::optional next = key; items_t::const_iterator iter; @@ -435,10 +392,8 @@ void ApplyStateTable::rawErase(ReadView const& base, std::shared_ptr const& sle) { using namespace std; - auto const result = items_.emplace( - piecewise_construct, - forward_as_tuple(sle->key()), - forward_as_tuple(Action::erase, sle)); + auto const result = + items_.emplace(piecewise_construct, forward_as_tuple(sle->key()), forward_as_tuple(Action::erase, sle)); if (result.second) return; auto& item = result.first->second; @@ -466,10 +421,7 @@ ApplyStateTable::insert(ReadView const& base, std::shared_ptr const& sle) { using namespace std; items_.emplace_hint( - iter, - piecewise_construct, - forward_as_tuple(sle->key()), - forward_as_tuple(Action::insert, sle)); + iter, piecewise_construct, forward_as_tuple(sle->key()), forward_as_tuple(Action::insert, sle)); return; } auto& item = iter->second; @@ -496,10 +448,7 @@ ApplyStateTable::replace(ReadView const& base, std::shared_ptr const& sle) { using namespace std; items_.emplace_hint( - iter, - piecewise_construct, - forward_as_tuple(sle->key()), - forward_as_tuple(Action::modify, sle)); + iter, piecewise_construct, forward_as_tuple(sle->key()), forward_as_tuple(Action::modify, sle)); return; } auto& item = iter->second; @@ -566,7 +515,7 @@ ApplyStateTable::threadItem(TxMeta& meta, std::shared_ptr const& sle) { XRPL_ASSERT( node.getFieldIndex(sfPreviousTxnLgrSeq) == -1, - "ripple::ApplyStateTable::threadItem : previous ledger is not " + "xrpl::ApplyStateTable::threadItem : previous ledger is not " "set"); node.setFieldH256(sfPreviousTxnID, prevTxID); node.setFieldU32(sfPreviousTxnLgrSeq, prevLgrID); @@ -574,28 +523,22 @@ ApplyStateTable::threadItem(TxMeta& meta, std::shared_ptr const& sle) XRPL_ASSERT( node.getFieldH256(sfPreviousTxnID) == prevTxID, - "ripple::ApplyStateTable::threadItem : previous transaction is a " + "xrpl::ApplyStateTable::threadItem : previous transaction is a " "match"); XRPL_ASSERT( node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID, - "ripple::ApplyStateTable::threadItem : previous ledger is a match"); + "xrpl::ApplyStateTable::threadItem : previous ledger is a match"); } } std::shared_ptr -ApplyStateTable::getForMod( - ReadView const& base, - key_type const& key, - Mods& mods, - beast::Journal j) +ApplyStateTable::getForMod(ReadView const& base, key_type const& key, Mods& mods, beast::Journal j) { { auto miter = mods.find(key); if (miter != mods.end()) { - XRPL_ASSERT( - miter->second, - "ripple::ApplyStateTable::getForMod : non-null result"); + XRPL_ASSERT(miter->second, "xrpl::ApplyStateTable::getForMod : non-null result"); return miter->second; } } @@ -634,12 +577,7 @@ ApplyStateTable::getForMod( } void -ApplyStateTable::threadTx( - ReadView const& base, - TxMeta& meta, - AccountID const& to, - Mods& mods, - beast::Journal j) +ApplyStateTable::threadTx(ReadView const& base, TxMeta& meta, AccountID const& to, Mods& mods, beast::Journal j) { auto const sle = getForMod(base, keylet::account(to).key, mods, j); if (!sle) @@ -651,9 +589,7 @@ ApplyStateTable::threadTx( return; } // threadItem only applied to AccountRoot - XRPL_ASSERT( - sle->isThreadedType(base.rules()), - "ripple::ApplyStateTable::threadTx : SLE is threaded"); + XRPL_ASSERT(sle->isThreadedType(base.rules()), "xrpl::ApplyStateTable::threadTx : SLE is threaded"); threadItem(meta, sle); } @@ -690,4 +626,4 @@ ApplyStateTable::threadOwners( } } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/ApplyView.cpp b/src/libxrpl/ledger/ApplyView.cpp index bbc8f317ce..fc35ff5119 100644 --- a/src/libxrpl/ledger/ApplyView.cpp +++ b/src/libxrpl/ledger/ApplyView.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,75 +6,97 @@ #include #include -namespace ripple { +namespace xrpl { -std::optional -ApplyView::dirAdd( - bool preserveOrder, +namespace directory { + +std::uint64_t +createRoot( + ApplyView& view, Keylet const& directory, uint256 const& key, std::function const&)> const& describe) { - auto root = peek(directory); + auto newRoot = std::make_shared(directory); + newRoot->setFieldH256(sfRootIndex, directory.key); + describe(newRoot); - if (!root) - { - // No root, make it. - root = std::make_shared(directory); - root->setFieldH256(sfRootIndex, directory.key); - describe(root); + STVector256 v; + v.push_back(key); + newRoot->setFieldV256(sfIndexes, v); - STVector256 v; - v.push_back(key); - root->setFieldV256(sfIndexes, v); + view.insert(newRoot); + return std::uint64_t{0}; +} - insert(root); - return std::uint64_t{0}; - } +auto +findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start) +{ + std::uint64_t page = start->getFieldU64(sfIndexPrevious); - std::uint64_t page = root->getFieldU64(sfIndexPrevious); - - auto node = root; + auto node = start; if (page) { - node = peek(keylet::page(directory, page)); + node = view.peek(keylet::page(directory, page)); if (!node) + { // LCOV_EXCL_START LogicError("Directory chain: root back-pointer broken."); + // LCOV_EXCL_STOP + } } auto indexes = node->getFieldV256(sfIndexes); + return std::make_tuple(page, node, indexes); +} - // If there's space, we use it: - if (indexes.size() < dirNodeMaxEntries) +std::uint64_t +insertKey( + ApplyView& view, + SLE::ref node, + std::uint64_t page, + bool preserveOrder, + STVector256& indexes, + uint256 const& key) +{ + if (preserveOrder) { - if (preserveOrder) - { - if (std::find(indexes.begin(), indexes.end(), key) != indexes.end()) - LogicError("dirInsert: double insertion"); + if (std::find(indexes.begin(), indexes.end(), key) != indexes.end()) + LogicError("dirInsert: double insertion"); // LCOV_EXCL_LINE - indexes.push_back(key); - } - else - { - // We can't be sure if this page is already sorted because - // it may be a legacy page we haven't yet touched. Take - // the time to sort it. - std::sort(indexes.begin(), indexes.end()); + indexes.push_back(key); + } + else + { + // We can't be sure if this page is already sorted because + // it may be a legacy page we haven't yet touched. Take + // the time to sort it. + std::sort(indexes.begin(), indexes.end()); - auto pos = std::lower_bound(indexes.begin(), indexes.end(), key); + auto pos = std::lower_bound(indexes.begin(), indexes.end(), key); - if (pos != indexes.end() && key == *pos) - LogicError("dirInsert: double insertion"); + if (pos != indexes.end() && key == *pos) + LogicError("dirInsert: double insertion"); // LCOV_EXCL_LINE - indexes.insert(pos, key); - } - - node->setFieldV256(sfIndexes, indexes); - update(node); - return page; + indexes.insert(pos, key); } + node->setFieldV256(sfIndexes, indexes); + view.update(node); + return page; +} + +std::optional +insertPage( + ApplyView& view, + std::uint64_t page, + SLE::pointer node, + std::uint64_t nextPage, + SLE::ref next, + uint256 const& key, + Keylet const& directory, + std::function const&)> const& describe) +{ // We rely on modulo arithmetic of unsigned integers (guaranteed in // [basic.fundamental] paragraph 2) to detect page representation overflow. // For signed integers this would be UB, hence static_assert here. @@ -107,20 +110,19 @@ ApplyView::dirAdd( // Check whether we're out of pages. if (page == 0) return std::nullopt; - if (!rules().enabled(fixDirectoryLimit) && - page >= dirNodeMaxPages) // Old pages limit + if (!view.rules().enabled(fixDirectoryLimit) && page >= dirNodeMaxPages) // Old pages limit return std::nullopt; // We are about to create a new node; we'll link it to // the chain first: node->setFieldU64(sfIndexNext, page); - update(node); + view.update(node); - root->setFieldU64(sfIndexPrevious, page); - update(root); + next->setFieldU64(sfIndexPrevious, page); + view.update(next); // Insert the new key: - indexes.clear(); + STVector256 indexes; indexes.push_back(key); node = std::make_shared(keylet::page(directory, page)); @@ -131,12 +133,46 @@ ApplyView::dirAdd( // it's the default. if (page != 1) node->setFieldU64(sfIndexPrevious, page - 1); + XRPL_ASSERT_PARTS(!nextPage, "xrpl::directory::insertPage", "nextPage has default value"); + /* Reserved for future use when directory pages may be inserted in + * between two other pages instead of only at the end of the chain. + if (nextPage) + node->setFieldU64(sfIndexNext, nextPage); + */ describe(node); - insert(node); + view.insert(node); return page; } +} // namespace directory + +std::optional +ApplyView::dirAdd( + bool preserveOrder, + Keylet const& directory, + uint256 const& key, + std::function const&)> const& describe) +{ + auto root = peek(directory); + + if (!root) + { + // No root, make it. + return directory::createRoot(*this, directory, key, describe); + } + + auto [page, node, indexes] = directory::findPreviousPage(*this, directory, root); + + // If there's space, we use it: + if (indexes.size() < dirNodeMaxEntries) + { + return directory::insertKey(*this, node, page, preserveOrder, indexes, key); + } + + return directory::insertPage(*this, page, node, 0, root, key, directory, describe); +} + bool ApplyView::emptyDirDelete(Keylet const& directory) { @@ -146,11 +182,10 @@ ApplyView::emptyDirDelete(Keylet const& directory) return false; // Verify that the passed directory node is the directory root. - if (directory.type != ltDIR_NODE || - node->getFieldH256(sfRootIndex) != directory.key) + if (directory.type != ltDIR_NODE || node->getFieldH256(sfRootIndex) != directory.key) { // LCOV_EXCL_START - UNREACHABLE("ripple::ApplyView::emptyDirDelete : invalid node type"); + UNREACHABLE("xrpl::ApplyView::emptyDirDelete : invalid node type"); return false; // LCOV_EXCL_STOP } @@ -164,10 +199,10 @@ ApplyView::emptyDirDelete(Keylet const& directory) auto nextPage = node->getFieldU64(sfIndexNext); if (nextPage == rootPage && prevPage != rootPage) - LogicError("Directory chain: fwd link broken"); + LogicError("Directory chain: fwd link broken"); // LCOV_EXCL_LINE if (prevPage == rootPage && nextPage != rootPage) - LogicError("Directory chain: rev link broken"); + LogicError("Directory chain: rev link broken"); // LCOV_EXCL_LINE // Older versions of the code would, in some cases, allow the last // page to be empty. Remove such pages: @@ -176,7 +211,10 @@ ApplyView::emptyDirDelete(Keylet const& directory) auto last = peek(keylet::page(directory, nextPage)); if (!last) + { // LCOV_EXCL_START LogicError("Directory chain: fwd link broken."); + // LCOV_EXCL_STOP + } if (!last->getFieldV256(sfIndexes).empty()) return false; @@ -204,11 +242,7 @@ ApplyView::emptyDirDelete(Keylet const& directory) } bool -ApplyView::dirRemove( - Keylet const& directory, - std::uint64_t page, - uint256 const& key, - bool keepRoot) +ApplyView::dirRemove(Keylet const& directory, std::uint64_t page, uint256 const& key, bool keepRoot) { auto node = peek(keylet::page(directory, page)); @@ -248,10 +282,16 @@ ApplyView::dirRemove( if (page == rootPage) { if (nextPage == page && prevPage != page) + { // LCOV_EXCL_START LogicError("Directory chain: fwd link broken"); + // LCOV_EXCL_STOP + } if (prevPage == page && nextPage != page) + { // LCOV_EXCL_START LogicError("Directory chain: rev link broken"); + // LCOV_EXCL_STOP + } // Older versions of the code would, in some cases, // allow the last page to be empty. Remove such @@ -260,7 +300,10 @@ ApplyView::dirRemove( { auto last = peek(keylet::page(directory, nextPage)); if (!last) + { // LCOV_EXCL_START LogicError("Directory chain: fwd link broken."); + // LCOV_EXCL_STOP + } if (last->getFieldV256(sfIndexes).empty()) { @@ -292,10 +335,10 @@ ApplyView::dirRemove( // This can never happen for nodes other than the root: if (nextPage == page) - LogicError("Directory chain: fwd link broken"); + LogicError("Directory chain: fwd link broken"); // LCOV_EXCL_LINE if (prevPage == page) - LogicError("Directory chain: rev link broken"); + LogicError("Directory chain: rev link broken"); // LCOV_EXCL_LINE // This node isn't the root, so it can either be in the // middle of the list, or at the end. Unlink it first @@ -303,14 +346,14 @@ ApplyView::dirRemove( // root: auto prev = peek(keylet::page(directory, prevPage)); if (!prev) - LogicError("Directory chain: fwd link broken."); + LogicError("Directory chain: fwd link broken."); // LCOV_EXCL_LINE // Fix previous to point to its new next. prev->setFieldU64(sfIndexNext, nextPage); update(prev); auto next = peek(keylet::page(directory, nextPage)); if (!next) - LogicError("Directory chain: rev link broken."); + LogicError("Directory chain: rev link broken."); // LCOV_EXCL_LINE // Fix next to point to its new previous. next->setFieldU64(sfIndexPrevious, prevPage); update(next); @@ -320,8 +363,7 @@ ApplyView::dirRemove( // Check whether the next page is the last page and, if // so, whether it's empty. If it is, delete it. - if (nextPage != rootPage && next->getFieldU64(sfIndexNext) == rootPage && - next->getFieldV256(sfIndexes).empty()) + if (nextPage != rootPage && next->getFieldU64(sfIndexNext) == rootPage && next->getFieldV256(sfIndexes).empty()) { // Since next doesn't point to the root, it // can't be pointing to prev. @@ -334,7 +376,10 @@ ApplyView::dirRemove( // And the root points to the last page: auto root = peek(keylet::page(directory, rootPage)); if (!root) + { // LCOV_EXCL_START LogicError("Directory chain: root link broken."); + // LCOV_EXCL_STOP + } root->setFieldU64(sfIndexPrevious, prevPage); update(root); @@ -353,9 +398,7 @@ ApplyView::dirRemove( } bool -ApplyView::dirDelete( - Keylet const& directory, - std::function const& callback) +ApplyView::dirDelete(Keylet const& directory, std::function const& callback) { std::optional pi; @@ -377,4 +420,4 @@ ApplyView::dirDelete( return true; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/ApplyViewBase.cpp b/src/libxrpl/ledger/ApplyViewBase.cpp index dd0e043474..ecb5180557 100644 --- a/src/libxrpl/ledger/ApplyViewBase.cpp +++ b/src/libxrpl/ledger/ApplyViewBase.cpp @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace detail { -ApplyViewBase::ApplyViewBase(ReadView const* base, ApplyFlags flags) - : flags_(flags), base_(base) +ApplyViewBase::ApplyViewBase(ReadView const* base, ApplyFlags flags) : flags_(flags), base_(base) { } @@ -35,10 +15,10 @@ ApplyViewBase::open() const return base_->open(); } -LedgerInfo const& -ApplyViewBase::info() const +LedgerHeader const& +ApplyViewBase::header() const { - return base_->info(); + return base_->header(); } Fees const& @@ -60,8 +40,7 @@ ApplyViewBase::exists(Keylet const& k) const } auto -ApplyViewBase::succ(key_type const& key, std::optional const& last) - const -> std::optional +ApplyViewBase::succ(key_type const& key, std::optional const& last) const -> std::optional { return items_.succ(*base_, key, last); } @@ -85,8 +64,7 @@ ApplyViewBase::slesEnd() const -> std::unique_ptr } auto -ApplyViewBase::slesUpperBound(uint256 const& key) const - -> std::unique_ptr +ApplyViewBase::slesUpperBound(uint256 const& key) const -> std::unique_ptr { return base_->slesUpperBound(key); } @@ -174,4 +152,4 @@ ApplyViewBase::rawDestroyXRP(XRPAmount const& fee) } } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/ApplyViewImpl.cpp b/src/libxrpl/ledger/ApplyViewImpl.cpp index 9429bcee6e..eca9043db8 100644 --- a/src/libxrpl/ledger/ApplyViewImpl.cpp +++ b/src/libxrpl/ledger/ApplyViewImpl.cpp @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { -ApplyViewImpl::ApplyViewImpl(ReadView const* base, ApplyFlags flags) - : ApplyViewBase(base, flags) +ApplyViewImpl::ApplyViewImpl(ReadView const* base, ApplyFlags flags) : ApplyViewBase(base, flags) { } @@ -56,4 +36,4 @@ ApplyViewImpl::visit( items_.visit(to, func); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/BookDirs.cpp b/src/libxrpl/ledger/BookDirs.cpp index 61ec160b1b..03dd0b0e13 100644 --- a/src/libxrpl/ledger/BookDirs.cpp +++ b/src/libxrpl/ledger/BookDirs.cpp @@ -1,28 +1,8 @@ -//------------ -//------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { BookDirs::BookDirs(ReadView const& view, Book const& book) : view_(&view) @@ -30,14 +10,13 @@ BookDirs::BookDirs(ReadView const& view, Book const& book) , next_quality_(getQualityNext(root_)) , key_(view_->succ(root_, next_quality_).value_or(beast::zero)) { - XRPL_ASSERT( - root_ != beast::zero, "ripple::BookDirs::BookDirs : nonzero root"); + XRPL_ASSERT(root_ != beast::zero, "xrpl::BookDirs::BookDirs : nonzero root"); if (key_ != beast::zero) { if (!cdirFirst(*view_, key_, sle_, entry_, index_)) { // LCOV_EXCL_START - UNREACHABLE("ripple::BookDirs::BookDirs : directory is empty"); + UNREACHABLE("xrpl::BookDirs::BookDirs : directory is empty"); // LCOV_EXCL_STOP } } @@ -63,30 +42,25 @@ BookDirs::end() const -> BookDirs::const_iterator return BookDirs::const_iterator(*view_, root_, key_); } -beast::Journal BookDirs::const_iterator::j_ = - beast::Journal{beast::Journal::getNullSink()}; +beast::Journal BookDirs::const_iterator::j_ = beast::Journal{beast::Journal::getNullSink()}; bool -BookDirs::const_iterator::operator==( - BookDirs::const_iterator const& other) const +BookDirs::const_iterator::operator==(BookDirs::const_iterator const& other) const { if (view_ == nullptr || other.view_ == nullptr) return false; XRPL_ASSERT( view_ == other.view_ && root_ == other.root_, - "ripple::BookDirs::const_iterator::operator== : views and roots are " + "xrpl::BookDirs::const_iterator::operator== : views and roots are " "matching"); - return entry_ == other.entry_ && cur_key_ == other.cur_key_ && - index_ == other.index_; + return entry_ == other.entry_ && cur_key_ == other.cur_key_ && index_ == other.index_; } BookDirs::const_iterator::reference BookDirs::const_iterator::operator*() const { - XRPL_ASSERT( - index_ != beast::zero, - "ripple::BookDirs::const_iterator::operator* : nonzero index"); + XRPL_ASSERT(index_ != beast::zero, "xrpl::BookDirs::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::offer(index_)); return *cache_; @@ -97,14 +71,10 @@ BookDirs::const_iterator::operator++() { using beast::zero; - XRPL_ASSERT( - index_ != zero, - "ripple::BookDirs::const_iterator::operator++ : nonzero index"); + XRPL_ASSERT(index_ != zero, "xrpl::BookDirs::const_iterator::operator++ : nonzero index"); if (!cdirNext(*view_, cur_key_, sle_, entry_, index_)) { - if (index_ != 0 || - (cur_key_ = - view_->succ(++cur_key_, next_quality_).value_or(zero)) == zero) + if (index_ != 0 || (cur_key_ = view_->succ(++cur_key_, next_quality_).value_or(zero)) == zero) { cur_key_ = key_; entry_ = 0; @@ -114,7 +84,7 @@ BookDirs::const_iterator::operator++() { // LCOV_EXCL_START UNREACHABLE( - "ripple::BookDirs::const_iterator::operator++ : directory is " + "xrpl::BookDirs::const_iterator::operator++ : directory is " "empty"); // LCOV_EXCL_STOP } @@ -127,12 +97,10 @@ BookDirs::const_iterator::operator++() BookDirs::const_iterator BookDirs::const_iterator::operator++(int) { - XRPL_ASSERT( - index_ != beast::zero, - "ripple::BookDirs::const_iterator::operator++(int) : nonzero index"); + XRPL_ASSERT(index_ != beast::zero, "xrpl::BookDirs::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/CachedView.cpp b/src/libxrpl/ledger/CachedView.cpp index 0bec9094d2..12704d227e 100644 --- a/src/libxrpl/ledger/CachedView.cpp +++ b/src/libxrpl/ledger/CachedView.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace detail { bool @@ -57,9 +38,7 @@ CachedViewImpl::read(Keylet const& k) const return base_.read(k); }); // If the sle is null, then a failure must have occurred in base_.read() - XRPL_ASSERT( - sle || baseRead, - "ripple::CachedView::read : null SLE result from base"); + XRPL_ASSERT(sle || baseRead, "xrpl::CachedView::read : null SLE result from base"); if (cacheHit && baseRead) hitsexpired.increment(); else if (cacheHit) @@ -81,4 +60,4 @@ CachedViewImpl::read(Keylet const& k) const } } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/CredentialHelpers.cpp b/src/libxrpl/ledger/CredentialHelpers.cpp index 4c625f5eee..c737d42f07 100644 --- a/src/libxrpl/ledger/CredentialHelpers.cpp +++ b/src/libxrpl/ledger/CredentialHelpers.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,16 +5,13 @@ #include -namespace ripple { +namespace xrpl { namespace credentials { bool -checkExpired( - std::shared_ptr const& sleCredential, - NetClock::time_point const& closed) +checkExpired(std::shared_ptr const& sleCredential, NetClock::time_point const& closed) { - std::uint32_t const exp = (*sleCredential)[~sfExpiration].value_or( - std::numeric_limits::max()); + std::uint32_t const exp = (*sleCredential)[~sfExpiration].value_or(std::numeric_limits::max()); std::uint32_t const now = closed.time_since_epoch().count(); return now > exp; } @@ -41,7 +19,7 @@ checkExpired( bool removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j) { - auto const closeTime = view.info().parentCloseTime; + auto const closeTime = view.header().parentCloseTime; bool foundExpired = false; for (auto const& h : arr) @@ -52,8 +30,7 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j) if (sleCred && checkExpired(sleCred, closeTime)) { - JLOG(j.trace()) - << "Credentials are expired. Cred: " << sleCred->getText(); + JLOG(j.trace()) << "Credentials are expired. Cred: " << sleCred->getText(); // delete expired credentials even if the transaction failed deleteSLE(view, sleCred, j); foundExpired = true; @@ -64,17 +41,12 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j) } TER -deleteSLE( - ApplyView& view, - std::shared_ptr const& sleCredential, - beast::Journal j) +deleteSLE(ApplyView& view, std::shared_ptr const& sleCredential, beast::Journal j) { if (!sleCredential) return tecNO_ENTRY; - auto delSLE = - [&view, &sleCredential, j]( - AccountID const& account, SField const& node, bool isOwner) -> TER { + auto delSLE = [&view, &sleCredential, j](AccountID const& account, SField const& node, bool isOwner) -> TER { auto const sleAccount = view.peek(keylet::account(account)); if (!sleAccount) { @@ -86,8 +58,7 @@ deleteSLE( // Remove object from owner directory std::uint64_t const page = sleCredential->getFieldU64(node); - if (!view.dirRemove( - keylet::ownerDir(account), page, sleCredential->key(), false)) + if (!view.dirRemove(keylet::ownerDir(account), page, sleCredential->key(), false)) { // LCOV_EXCL_START JLOG(j.fatal()) << "Unable to delete Credential from owner."; @@ -131,9 +102,7 @@ checkFields(STTx const& tx, beast::Journal j) auto const& credentials = tx.getFieldV256(sfCredentialIDs); if (credentials.empty() || (credentials.size() > maxCredentialsArraySize)) { - JLOG(j.trace()) - << "Malformed transaction: Credentials array size is invalid: " - << credentials.size(); + JLOG(j.trace()) << "Malformed transaction: Credentials array size is invalid: " << credentials.size(); return temMALFORMED; } @@ -143,8 +112,7 @@ checkFields(STTx const& tx, beast::Journal j) auto [it, ins] = duplicates.insert(cred); if (!ins) { - JLOG(j.trace()) - << "Malformed transaction: duplicates in credentials."; + JLOG(j.trace()) << "Malformed transaction: duplicates in credentials."; return temMALFORMED; } } @@ -153,11 +121,7 @@ checkFields(STTx const& tx, beast::Journal j) } TER -valid( - STTx const& tx, - ReadView const& view, - AccountID const& src, - beast::Journal j) +valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal j) { if (!tx.isFieldPresent(sfCredentialIDs)) return tesSUCCESS; @@ -174,9 +138,7 @@ valid( if (sleCred->getAccountID(sfSubject) != src) { - JLOG(j.trace()) - << "Credential doesn't belong to the source account. Cred: " - << h; + JLOG(j.trace()) << "Credential doesn't belong to the source account. Cred: " << h; return tecBAD_CREDENTIALS; } @@ -200,14 +162,13 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject) if (!slePD) return tecOBJECT_NOT_FOUND; - auto const closeTime = view.info().parentCloseTime; + auto const closeTime = view.header().parentCloseTime; bool foundExpired = false; for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials)) { auto const issuer = h.getAccountID(sfIssuer); auto const type = h.getFieldVL(sfCredentialType); - auto const keyletCredential = - keylet::credential(subject, issuer, makeSlice(type)); + auto const keyletCredential = keylet::credential(subject, issuer, makeSlice(type)); auto const sleCredential = view.read(keyletCredential); // We cannot delete expired credentials, that would require ApplyView& @@ -233,10 +194,7 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject) } TER -authorizedDepositPreauth( - ApplyView const& view, - STVector256 const& credIDs, - AccountID const& dst) +authorizedDepositPreauth(ApplyView const& view, STVector256 const& credIDs, AccountID const& dst) { std::set> sorted; std::vector> lifeExtender; @@ -247,8 +205,7 @@ authorizedDepositPreauth( if (!sleCred) // already checked in preclaim return tefINTERNAL; // LCOV_EXCL_LINE - auto [it, ins] = - sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]); + auto [it, ins] = sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]); if (!ins) return tefINTERNAL; // LCOV_EXCL_LINE lifeExtender.push_back(std::move(sleCred)); @@ -309,7 +266,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j) if (!ins) { JLOG(j.trace()) << "Malformed transaction: " - "duplicates in credenentials."; + "duplicates in credentials."; return temMALFORMED; } } @@ -320,11 +277,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j) } // namespace credentials TER -verifyValidDomain( - ApplyView& view, - AccountID const& account, - uint256 domainID, - beast::Journal j) +verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j) { auto const slePD = view.read(keylet::permissionedDomain(domainID)); if (!slePD) @@ -337,8 +290,7 @@ verifyValidDomain( { auto const issuer = h.getAccountID(sfIssuer); auto const type = h.getFieldVL(sfCredentialType); - auto const keyletCredential = - keylet::credential(account, issuer, makeSlice(type)); + auto const keyletCredential = keylet::credential(account, issuer, makeSlice(type)); if (view.exists(keyletCredential)) credentials.push_back(keyletCredential.key); } @@ -374,8 +326,7 @@ verifyDepositPreauth( bool const credentialsPresent = tx.isFieldPresent(sfCredentialIDs); - if (credentialsPresent && - credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j)) + if (credentialsPresent && credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j)) return tecEXPIRED; if (sleDst && (sleDst->getFlags() & lsfDepositAuth)) @@ -385,12 +336,11 @@ verifyDepositPreauth( if (!view.exists(keylet::depositPreauth(dst, src))) return !credentialsPresent ? tecNO_PERMISSION - : credentials::authorizedDepositPreauth( - view, tx.getFieldV256(sfCredentialIDs), dst); + : credentials::authorizedDepositPreauth(view, tx.getFieldV256(sfCredentialIDs), dst); } } return tesSUCCESS; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/Credit.cpp b/src/libxrpl/ledger/Credit.cpp new file mode 100644 index 0000000000..064fcdaf3b --- /dev/null +++ b/src/libxrpl/ledger/Credit.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +namespace xrpl { + +STAmount +creditLimit(ReadView const& view, AccountID const& account, AccountID const& issuer, Currency const& currency) +{ + STAmount result(Issue{currency, account}); + + auto sleRippleState = view.read(keylet::line(account, issuer, currency)); + + if (sleRippleState) + { + result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit); + result.setIssuer(account); + } + + XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditLimit : result issuer match"); + XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditLimit : result currency match"); + return result; +} + +IOUAmount +creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur) +{ + return toAmount(creditLimit(v, acc, iss, cur)); +} + +STAmount +creditBalance(ReadView const& view, AccountID const& account, AccountID const& issuer, Currency const& currency) +{ + STAmount result(Issue{currency, account}); + + auto sleRippleState = view.read(keylet::line(account, issuer, currency)); + + if (sleRippleState) + { + result = sleRippleState->getFieldAmount(sfBalance); + if (account < issuer) + result.negate(); + result.setIssuer(account); + } + + XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditBalance : result issuer match"); + XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditBalance : result currency match"); + return result; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/Dir.cpp b/src/libxrpl/ledger/Dir.cpp index ea57369495..cf0b01aa7f 100644 --- a/src/libxrpl/ledger/Dir.cpp +++ b/src/libxrpl/ledger/Dir.cpp @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { using const_iterator = Dir::const_iterator; -Dir::Dir(ReadView const& view, Keylet const& key) - : view_(&view), root_(key), sle_(view_->read(root_)) +Dir::Dir(ReadView const& view, Keylet const& key) : view_(&view), root_(key), sle_(view_->read(root_)) { if (sle_ != nullptr) indexes_ = &sle_->getFieldV256(sfIndexes); @@ -62,16 +42,14 @@ const_iterator::operator==(const_iterator const& other) const XRPL_ASSERT( view_ == other.view_ && root_.key == other.root_.key, - "ripple::const_iterator::operator== : views and roots are matching"); + "xrpl::const_iterator::operator== : views and roots are matching"); return page_.key == other.page_.key && index_ == other.index_; } const_iterator::reference const_iterator::operator*() const { - XRPL_ASSERT( - index_ != beast::zero, - "ripple::const_iterator::operator* : nonzero index"); + XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::child(index_)); return *cache_; @@ -80,9 +58,7 @@ const_iterator::operator*() const const_iterator& const_iterator::operator++() { - XRPL_ASSERT( - index_ != beast::zero, - "ripple::const_iterator::operator++ : nonzero index"); + XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator++ : nonzero index"); if (++it_ != std::end(*indexes_)) { index_ = *it_; @@ -96,9 +72,7 @@ const_iterator::operator++() const_iterator const_iterator::operator++(int) { - XRPL_ASSERT( - index_ != beast::zero, - "ripple::const_iterator::operator++(int) : nonzero index"); + XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; @@ -117,7 +91,7 @@ const_iterator::next_page() { page_ = keylet::page(root_, next); sle_ = view_->read(page_); - XRPL_ASSERT(sle_, "ripple::const_iterator::next_page : non-null SLE"); + XRPL_ASSERT(sle_, "xrpl::const_iterator::next_page : non-null SLE"); indexes_ = &sle_->getFieldV256(sfIndexes); if (indexes_->empty()) { @@ -139,4 +113,4 @@ const_iterator::page_size() return indexes_->size(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/OpenView.cpp b/src/libxrpl/ledger/OpenView.cpp index c40434b38d..73bd3e16ea 100644 --- a/src/libxrpl/ledger/OpenView.cpp +++ b/src/libxrpl/ledger/OpenView.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class OpenView::txs_iter_impl : public txs_type::iter_base { @@ -29,8 +10,7 @@ private: txs_map::const_iterator iter_; public: - explicit txs_iter_impl(bool metadata, txs_map::const_iterator iter) - : metadata_(metadata), iter_(iter) + explicit txs_iter_impl(bool metadata, txs_map::const_iterator iter) : metadata_(metadata), iter_(iter) { } @@ -76,42 +56,35 @@ public: OpenView::OpenView(OpenView const& rhs) : ReadView(rhs) , TxsRawView(rhs) - , monotonic_resource_{std::make_unique< - boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)} + , monotonic_resource_{std::make_unique(initialBufferSize)} , txs_{rhs.txs_, monotonic_resource_.get()} , rules_{rhs.rules_} - , info_{rhs.info_} + , header_{rhs.header_} , base_{rhs.base_} , items_{rhs.items_} , hold_{rhs.hold_} , open_{rhs.open_} {}; -OpenView::OpenView( - open_ledger_t, - ReadView const* base, - Rules const& rules, - std::shared_ptr hold) - : monotonic_resource_{std::make_unique< - boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)} +OpenView::OpenView(open_ledger_t, ReadView const* base, Rules const& rules, std::shared_ptr hold) + : monotonic_resource_{std::make_unique(initialBufferSize)} , txs_{monotonic_resource_.get()} , rules_(rules) - , info_(base->info()) + , header_(base->header()) , base_(base) , hold_(std::move(hold)) { - info_.validated = false; - info_.accepted = false; - info_.seq = base_->info().seq + 1; - info_.parentCloseTime = base_->info().closeTime; - info_.parentHash = base_->info().hash; + header_.validated = false; + header_.accepted = false; + header_.seq = base_->header().seq + 1; + header_.parentCloseTime = base_->header().closeTime; + header_.parentHash = base_->header().hash; } OpenView::OpenView(ReadView const* base, std::shared_ptr hold) - : monotonic_resource_{std::make_unique< - boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)} + : monotonic_resource_{std::make_unique(initialBufferSize)} , txs_{monotonic_resource_.get()} , rules_(base->rules()) - , info_(base->info()) + , header_(base->header()) , base_(base) , hold_(std::move(hold)) , open_(base->open()) @@ -134,10 +107,10 @@ OpenView::apply(TxsRawView& to) const //--- -LedgerInfo const& -OpenView::info() const +LedgerHeader const& +OpenView::header() const { - return info_; + return header_; } Fees const& @@ -159,8 +132,7 @@ OpenView::exists(Keylet const& k) const } auto -OpenView::succ(key_type const& key, std::optional const& last) const - -> std::optional +OpenView::succ(key_type const& key, std::optional const& last) const -> std::optional { return items_.succ(*base_, key, last); } @@ -184,8 +156,7 @@ OpenView::slesEnd() const -> std::unique_ptr } auto -OpenView::slesUpperBound(uint256 const& key) const - -> std::unique_ptr +OpenView::slesUpperBound(uint256 const& key) const -> std::unique_ptr { return items_.slesUpperBound(*base_, key); } @@ -218,8 +189,7 @@ OpenView::txRead(key_type const& key) const -> tx_type auto stx = std::make_shared(SerialIter{item.txn->slice()}); decltype(tx_type::second) sto; if (item.meta) - sto = std::make_shared( - SerialIter{item.meta->slice()}, sfMetadata); + sto = std::make_shared(SerialIter{item.meta->slice()}, sfMetadata); else sto = nullptr; return {std::move(stx), std::move(sto)}; @@ -249,7 +219,7 @@ void OpenView::rawDestroyXRP(XRPAmount const& fee) { items_.destroyXRP(fee); - // VFALCO Deduct from info_.totalDrops ? + // VFALCO Deduct from header_.totalDrops ? // What about child views? } @@ -261,12 +231,10 @@ OpenView::rawTxInsert( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - auto const result = txs_.emplace( - std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple(txn, metaData)); + auto const result = + txs_.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(txn, metaData)); if (!result.second) LogicError("rawTxInsert: duplicate TX id: " + to_string(key)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/PaymentSandbox.cpp b/src/libxrpl/ledger/PaymentSandbox.cpp index ba59b573fa..67492142da 100644 --- a/src/libxrpl/ledger/PaymentSandbox.cpp +++ b/src/libxrpl/ledger/PaymentSandbox.cpp @@ -1,36 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace detail { auto -DeferredCredits::makeKey( - AccountID const& a1, - AccountID const& a2, - Currency const& c) -> Key +DeferredCredits::makeKey(AccountID const& a1, AccountID const& a2, Currency const& c) -> Key { if (a1 < a2) return std::make_tuple(a1, a2, c); @@ -45,12 +23,8 @@ DeferredCredits::credit( STAmount const& amount, STAmount const& preCreditSenderBalance) { - XRPL_ASSERT( - sender != receiver, - "ripple::detail::DeferredCredits::credit : sender is not receiver"); - XRPL_ASSERT( - !amount.negative(), - "ripple::detail::DeferredCredits::credit : positive amount"); + XRPL_ASSERT(sender != receiver, "xrpl::detail::DeferredCredits::credit : sender is not receiver"); + XRPL_ASSERT(!amount.negative(), "xrpl::detail::DeferredCredits::credit : positive amount"); auto const k = makeKey(sender, receiver, amount.getCurrency()); auto i = credits_.find(k); @@ -85,10 +59,7 @@ DeferredCredits::credit( } void -DeferredCredits::ownerCount( - AccountID const& id, - std::uint32_t cur, - std::uint32_t next) +DeferredCredits::ownerCount(AccountID const& id, std::uint32_t cur, std::uint32_t next) { auto const v = std::max(cur, next); auto r = ownerCounts_.emplace(std::make_pair(id, v)); @@ -110,10 +81,8 @@ DeferredCredits::ownerCount(AccountID const& id) const // Get the adjustments for the balance between main and other. auto -DeferredCredits::adjustments( - AccountID const& main, - AccountID const& other, - Currency const& currency) const -> std::optional +DeferredCredits::adjustments(AccountID const& main, AccountID const& other, Currency const& currency) const + -> std::optional { std::optional result; @@ -126,14 +95,12 @@ DeferredCredits::adjustments( if (main < other) { - result.emplace( - v.highAcctCredits, v.lowAcctCredits, v.lowAcctOrigBalance); + result.emplace(v.highAcctCredits, v.lowAcctCredits, v.lowAcctOrigBalance); return result; } else { - result.emplace( - v.lowAcctCredits, v.highAcctCredits, -v.lowAcctOrigBalance); + result.emplace(v.lowAcctCredits, v.highAcctCredits, -v.lowAcctOrigBalance); return result; } } @@ -169,10 +136,7 @@ DeferredCredits::apply(DeferredCredits& to) } // namespace detail STAmount -PaymentSandbox::balanceHook( - AccountID const& account, - AccountID const& issuer, - STAmount const& amount) const +PaymentSandbox::balanceHook(AccountID const& account, AccountID const& issuer, STAmount const& amount) const { /* There are two algorithms here. The pre-switchover algorithm takes the @@ -219,8 +183,7 @@ PaymentSandbox::balanceHook( } std::uint32_t -PaymentSandbox::ownerCountHook(AccountID const& account, std::uint32_t count) - const +PaymentSandbox::ownerCountHook(AccountID const& account, std::uint32_t count) const { std::uint32_t result = count; for (auto curSB = this; curSB; curSB = curSB->ps_) @@ -242,10 +205,7 @@ PaymentSandbox::creditHook( } void -PaymentSandbox::adjustOwnerCountHook( - AccountID const& account, - std::uint32_t cur, - std::uint32_t next) +PaymentSandbox::adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) { tab_.ownerCount(account, cur, next); } @@ -253,14 +213,14 @@ PaymentSandbox::adjustOwnerCountHook( void PaymentSandbox::apply(RawView& to) { - XRPL_ASSERT(!ps_, "ripple::PaymentSandbox::apply : non-null sandbox"); + XRPL_ASSERT(!ps_, "xrpl::PaymentSandbox::apply : non-null sandbox"); items_.apply(to); } void PaymentSandbox::apply(PaymentSandbox& to) { - XRPL_ASSERT(ps_ == &to, "ripple::PaymentSandbox::apply : matching sandbox"); + XRPL_ASSERT(ps_ == &to, "xrpl::PaymentSandbox::apply : matching sandbox"); items_.apply(to); tab_.apply(to.tab_); } @@ -346,7 +306,7 @@ PaymentSandbox::balanceChanges(ReadView const& view) const auto const at = after->getType(); XRPL_ASSERT( at == before->getType(), - "ripple::PaymentSandbox::balanceChanges : after and before " + "xrpl::PaymentSandbox::balanceChanges : after and before " "types matching"); switch (at) { @@ -396,4 +356,4 @@ PaymentSandbox::xrpDestroyed() const return items_.dropsDestroyed(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/RawStateTable.cpp b/src/libxrpl/ledger/RawStateTable.cpp index e6b1467581..4b5f6837b2 100644 --- a/src/libxrpl/ledger/RawStateTable.cpp +++ b/src/libxrpl/ledger/RawStateTable.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace detail { class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base @@ -65,7 +46,7 @@ public: { XRPL_ASSERT( end1_ == p->end1_ && end0_ == p->end0_, - "ripple::detail::RawStateTable::equal : matching end " + "xrpl::detail::RawStateTable::equal : matching end " "iterators"); return iter1_ == p->iter1_ && iter0_ == p->iter0_; } @@ -78,7 +59,7 @@ public: { XRPL_ASSERT( sle1_ || sle0_, - "ripple::detail::RawStateTable::increment : either SLE is " + "xrpl::detail::RawStateTable::increment : either SLE is " "non-null"); if (sle1_ && !sle0_) @@ -145,8 +126,7 @@ private: void skip() { - while (iter1_ != end1_ && iter1_->second.action == Action::erase && - sle0_->key() == sle1_->key()) + while (iter1_ != end1_ && iter1_->second.action == Action::erase && sle0_->key() == sle1_->key()) { inc1(); inc0(); @@ -185,9 +165,7 @@ RawStateTable::apply(RawView& to) const bool RawStateTable::exists(ReadView const& base, Keylet const& k) const { - XRPL_ASSERT( - k.key.isNonZero(), - "ripple::detail::RawStateTable::exists : nonzero key"); + XRPL_ASSERT(k.key.isNonZero(), "xrpl::detail::RawStateTable::exists : nonzero key"); auto const iter = items_.find(k.key); if (iter == items_.end()) return base.exists(k); @@ -204,10 +182,8 @@ RawStateTable::exists(ReadView const& base, Keylet const& k) const the lower of the two. */ auto -RawStateTable::succ( - ReadView const& base, - key_type const& key, - std::optional const& last) const -> std::optional +RawStateTable::succ(ReadView const& base, key_type const& key, std::optional const& last) const + -> std::optional { std::optional next = key; items_t::const_iterator iter; @@ -243,9 +219,7 @@ RawStateTable::erase(std::shared_ptr const& sle) { // The base invariant is checked during apply auto const result = items_.emplace( - std::piecewise_construct, - std::forward_as_tuple(sle->key()), - std::forward_as_tuple(Action::erase, sle)); + std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::erase, sle)); if (result.second) return; auto& item = result.first->second; @@ -268,9 +242,7 @@ void RawStateTable::insert(std::shared_ptr const& sle) { auto const result = items_.emplace( - std::piecewise_construct, - std::forward_as_tuple(sle->key()), - std::forward_as_tuple(Action::insert, sle)); + std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::insert, sle)); if (result.second) return; auto& item = result.first->second; @@ -293,9 +265,7 @@ void RawStateTable::replace(std::shared_ptr const& sle) { auto const result = items_.emplace( - std::piecewise_construct, - std::forward_as_tuple(sle->key()), - std::forward_as_tuple(Action::replace, sle)); + std::piecewise_construct, std::forward_as_tuple(sle->key()), std::forward_as_tuple(Action::replace, sle)); if (result.second) return; auto& item = result.first->second; @@ -336,26 +306,21 @@ RawStateTable::destroyXRP(XRPAmount const& fee) std::unique_ptr RawStateTable::slesBegin(ReadView const& base) const { - return std::make_unique( - items_.begin(), items_.end(), base.sles.begin(), base.sles.end()); + return std::make_unique(items_.begin(), items_.end(), base.sles.begin(), base.sles.end()); } std::unique_ptr RawStateTable::slesEnd(ReadView const& base) const { - return std::make_unique( - items_.end(), items_.end(), base.sles.end(), base.sles.end()); + return std::make_unique(items_.end(), items_.end(), base.sles.end(), base.sles.end()); } std::unique_ptr RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const { return std::make_unique( - items_.upper_bound(key), - items_.end(), - base.sles.upper_bound(key), - base.sles.end()); + items_.upper_bound(key), items_.end(), base.sles.upper_bound(key), base.sles.end()); } } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/ReadView.cpp b/src/libxrpl/ledger/ReadView.cpp index 449a5a9cec..d6674ba0da 100644 --- a/src/libxrpl/ledger/ReadView.cpp +++ b/src/libxrpl/ledger/ReadView.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { ReadView::sles_type::sles_type(ReadView const& view) : ReadViewFwdRange(view) { @@ -72,9 +53,7 @@ makeRulesGivenLedger(DigestAwareReadView const& ledger, Rules const& current) } Rules -makeRulesGivenLedger( - DigestAwareReadView const& ledger, - std::unordered_set> const& presets) +makeRulesGivenLedger(DigestAwareReadView const& ledger, std::unordered_set> const& presets) { Keylet const k = keylet::amendments(); std::optional digest = ledger.digest(k.key); @@ -87,4 +66,4 @@ makeRulesGivenLedger( return Rules(presets); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index cd04b8a94e..e5f389af73 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -1,27 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include +#include #include #include #include @@ -38,28 +20,19 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { template < class V, class N, - class = std::enable_if_t< - std::is_same_v, SLE> && - std::is_base_of_v>> + class = std::enable_if_t, SLE> && std::is_base_of_v>> bool -internalDirNext( - V& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) +internalDirNext(V& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry) { auto const& svIndexes = page->getFieldV256(sfIndexes); - XRPL_ASSERT( - index <= svIndexes.size(), - "ripple::detail::internalDirNext : index inside range"); + XRPL_ASSERT(index <= svIndexes.size(), "xrpl::detail::internalDirNext : index inside range"); if (index >= svIndexes.size()) { @@ -76,7 +49,7 @@ internalDirNext( else page = view.peek(keylet::page(root, next)); - XRPL_ASSERT(page, "ripple::detail::internalDirNext : non-null root"); + XRPL_ASSERT(page, "xrpl::detail::internalDirNext : non-null root"); if (!page) return false; @@ -93,16 +66,9 @@ internalDirNext( template < class V, class N, - class = std::enable_if_t< - std::is_same_v, SLE> && - std::is_base_of_v>> + class = std::enable_if_t, SLE> && std::is_base_of_v>> bool -internalDirFirst( - V& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) +internalDirFirst(V& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry) { if constexpr (std::is_const_v) page = view.read(keylet::page(root)); @@ -120,23 +86,13 @@ internalDirFirst( } // namespace detail bool -dirFirst( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) +dirFirst(ApplyView& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry) { return detail::internalDirFirst(view, root, page, index, entry); } bool -dirNext( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) +dirNext(ApplyView& view, uint256 const& root, std::shared_ptr& page, unsigned int& index, uint256& entry) { return detail::internalDirNext(view, root, page, index, entry); } @@ -210,11 +166,7 @@ isGlobalFrozen(ReadView const& view, Asset const& asset) } bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) +isIndividualFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer) { if (isXRP(currency)) return false; @@ -222,21 +174,16 @@ isIndividualFrozen( { // Check if the issuer froze the line auto const sle = view.read(keylet::line(account, issuer, currency)); - if (sle && - sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) + if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) return true; } return false; } bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue) +isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) { - if (auto const sle = - view.read(keylet::mptoken(mptIssue.getMptID(), account))) + if (auto const sle = view.read(keylet::mptoken(mptIssue.getMptID(), account))) return sle->isFlag(lsfMPTLocked); return false; } @@ -244,11 +191,7 @@ isIndividualFrozen( // Can the specified account spend the specified currency issued by // the specified issuer or does the freeze flag prohibit it? bool -isFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) +isFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer) { if (isXRP(currency)) return false; @@ -259,31 +202,21 @@ isFrozen( { // Check if the issuer froze the line sle = view.read(keylet::line(account, issuer, currency)); - if (sle && - sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) + if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) return true; } return false; } bool -isFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue, - int depth) +isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth) { - return isGlobalFrozen(view, mptIssue) || - isIndividualFrozen(view, account, mptIssue) || + return isGlobalFrozen(view, mptIssue) || isIndividualFrozen(view, account, mptIssue) || isVaultPseudoAccountFrozen(view, account, mptIssue, depth); } [[nodiscard]] bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - MPTIssue const& mptIssue, - int depth) +isAnyFrozen(ReadView const& view, std::initializer_list const& accounts, MPTIssue const& mptIssue, int depth) { if (isGlobalFrozen(view, mptIssue)) return true; @@ -304,11 +237,7 @@ isAnyFrozen( } bool -isVaultPseudoAccountFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptShare, - int depth) +isVaultPseudoAccountFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptShare, int depth) { if (!view.rules().enabled(featureSingleAssetVault)) return false; @@ -316,8 +245,7 @@ isVaultPseudoAccountFrozen( if (depth >= maxAssetCheckDepth) return true; // LCOV_EXCL_LINE - auto const mptIssuance = - view.read(keylet::mptIssuance(mptShare.getMptID())); + auto const mptIssuance = view.read(keylet::mptIssuance(mptShare.getMptID())); if (mptIssuance == nullptr) return false; // zero MPToken won't block deletion of MPTokenIssuance @@ -326,7 +254,7 @@ isVaultPseudoAccountFrozen( if (mptIssuer == nullptr) { // LCOV_EXCL_START - UNREACHABLE("ripple::isVaultPseudoAccountFrozen : null MPToken issuer"); + UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null MPToken issuer"); return false; // LCOV_EXCL_STOP } @@ -334,11 +262,10 @@ isVaultPseudoAccountFrozen( if (!mptIssuer->isFieldPresent(sfVaultID)) return false; // not a Vault pseudo-account, common case - auto const vault = - view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID))); + auto const vault = view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID))); if (vault == nullptr) { // LCOV_EXCL_START - UNREACHABLE("ripple::isVaultPseudoAccountFrozen : null vault"); + UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null vault"); return false; // LCOV_EXCL_STOP } @@ -347,11 +274,7 @@ isVaultPseudoAccountFrozen( } bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) +isDeepFrozen(ReadView const& view, AccountID const& account, Currency const& currency, AccountID const& issuer) { if (isXRP(currency)) { @@ -373,18 +296,14 @@ isDeepFrozen( } bool -isLPTokenFrozen( - ReadView const& view, - AccountID const& account, - Issue const& asset, - Issue const& asset2) +isLPTokenFrozen(ReadView const& view, AccountID const& account, Issue const& asset, Issue const& asset2) { return isFrozen(view, account, asset.currency, asset.account) || isFrozen(view, account, asset2.currency, asset2.account); } -STAmount -accountHolds( +static SLE::const_pointer +getLineIfUsable( ReadView const& view, AccountID const& account, Currency const& currency, @@ -392,66 +311,70 @@ accountHolds( FreezeHandling zeroIfFrozen, beast::Journal j) { - STAmount amount; - if (isXRP(currency)) + auto const sle = view.read(keylet::line(account, issuer, currency)); + + if (!sle) { - return {xrpLiquid(view, account, 0, j)}; + return nullptr; } - // IOU: Return balance on trust line modulo freeze - auto const sle = view.read(keylet::line(account, issuer, currency)); - auto const allowBalance = [&]() { - if (!sle) + if (zeroIfFrozen == fhZERO_IF_FROZEN) + { + if (isFrozen(view, account, currency, issuer) || isDeepFrozen(view, account, currency, issuer)) { - return false; + return nullptr; } - if (zeroIfFrozen == fhZERO_IF_FROZEN) + // when fixFrozenLPTokenTransfer is enabled, if currency is lptoken, + // we need to check if the associated assets have been frozen + if (view.rules().enabled(fixFrozenLPTokenTransfer)) { - if (isFrozen(view, account, currency, issuer) || - isDeepFrozen(view, account, currency, issuer)) + auto const sleIssuer = view.read(keylet::account(issuer)); + if (!sleIssuer) { - return false; + return nullptr; // LCOV_EXCL_LINE } - - // when fixFrozenLPTokenTransfer is enabled, if currency is lptoken, - // we need to check if the associated assets have been frozen - if (view.rules().enabled(fixFrozenLPTokenTransfer)) + else if (sleIssuer->isFieldPresent(sfAMMID)) { - auto const sleIssuer = view.read(keylet::account(issuer)); - if (!sleIssuer) - { - return false; // LCOV_EXCL_LINE - } - else if (sleIssuer->isFieldPresent(sfAMMID)) - { - auto const sleAmm = - view.read(keylet::amm((*sleIssuer)[sfAMMID])); + auto const sleAmm = view.read(keylet::amm((*sleIssuer)[sfAMMID])); - if (!sleAmm || - isLPTokenFrozen( - view, - account, - (*sleAmm)[sfAsset].get(), - (*sleAmm)[sfAsset2].get())) - { - return false; - } + if (!sleAmm || + isLPTokenFrozen(view, account, (*sleAmm)[sfAsset].get(), (*sleAmm)[sfAsset2].get())) + { + return nullptr; } } } + } - return true; - }(); + return sle; +} - if (allowBalance) +static STAmount +getTrustLineBalance( + ReadView const& view, + SLE::const_ref sle, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + bool includeOppositeLimit, + beast::Journal j) +{ + STAmount amount; + if (sle) { amount = sle->getFieldAmount(sfBalance); - if (account > issuer) + bool const accountHigh = account > issuer; + auto const& oppositeField = accountHigh ? sfLowLimit : sfHighLimit; + if (accountHigh) { // Put balance in account terms. amount.negate(); } + if (includeOppositeLimit) + { + amount += sle->getFieldAmount(oppositeField); + } amount.setIssuer(issuer); } else @@ -459,23 +382,50 @@ accountHolds( amount.clear(Issue{currency, issuer}); } - JLOG(j.trace()) << "accountHolds:" - << " account=" << to_string(account) + JLOG(j.trace()) << "getTrustLineBalance:" << " account=" << to_string(account) << " amount=" << amount.getFullText(); return view.balanceHook(account, issuer, amount); } +STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + FreezeHandling zeroIfFrozen, + beast::Journal j, + SpendableHandling includeFullBalance) +{ + STAmount amount; + if (isXRP(currency)) + { + return {xrpLiquid(view, account, 0, j)}; + } + + bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); + if (returnSpendable && account == issuer) + // If the account is the issuer, then their limit is effectively + // infinite + return STAmount{Issue{currency, issuer}, STAmount::cMaxValue, STAmount::cMaxOffset}; + + // IOU: Return balance on trust line modulo freeze + SLE::const_pointer const sle = getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j); + + return getTrustLineBalance(view, sle, account, currency, issuer, returnSpendable, j); +} + STAmount accountHolds( ReadView const& view, AccountID const& account, Issue const& issue, FreezeHandling zeroIfFrozen, - beast::Journal j) + beast::Journal j, + SpendableHandling includeFullBalance) { - return accountHolds( - view, account, issue.currency, issue.account, zeroIfFrozen, j); + return accountHolds(view, account, issue.currency, issue.account, zeroIfFrozen, j, includeFullBalance); } STAmount @@ -485,17 +435,32 @@ accountHolds( MPTIssue const& mptIssue, FreezeHandling zeroIfFrozen, AuthHandling zeroIfUnauthorized, - beast::Journal j) + beast::Journal j, + SpendableHandling includeFullBalance) { + bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); + + if (returnSpendable && account == mptIssue.getIssuer()) + { + // if the account is the issuer, and the issuance exists, their limit is + // the issuance limit minus the outstanding value + auto const issuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); + + if (!issuance) + { + return STAmount{mptIssue}; + } + return STAmount{ + mptIssue, issuance->at(~sfMaximumAmount).value_or(maxMPTokenAmount) - issuance->at(sfOutstandingAmount)}; + } + STAmount amount; - auto const sleMpt = - view.read(keylet::mptoken(mptIssue.getMptID(), account)); + auto const sleMpt = view.read(keylet::mptoken(mptIssue.getMptID(), account)); if (!sleMpt) amount.clear(mptIssue); - else if ( - zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue)) + else if (zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue)) amount.clear(mptIssue); else { @@ -504,23 +469,18 @@ accountHolds( // Only if auth check is needed, as it needs to do an additional read // operation. Note featureSingleAssetVault will affect error codes. if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED && - (view.rules().enabled(featureSingleAssetVault) || - view.rules().enabled(featureConfidentialTransfer))) + (view.rules().enabled(featureSingleAssetVault) || view.rules().enabled(featureConfidentialTransfer))) { - if (auto const err = - requireAuth(view, mptIssue, account, AuthType::StrongAuth); - !isTesSuccess(err)) + if (auto const err = requireAuth(view, mptIssue, account, AuthType::StrongAuth); !isTesSuccess(err)) amount.clear(mptIssue); } else if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED) { - auto const sleIssuance = - view.read(keylet::mptIssuance(mptIssue.getMptID())); + auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); // if auth is enabled on the issuance and mpt is not authorized, // clear amount - if (sleIssuance && sleIssuance->isFlag(lsfMPTRequireAuth) && - !sleMpt->isFlag(lsfMPTAuthorized)) + if (sleIssuance && sleIssuance->isFlag(lsfMPTRequireAuth) && !sleMpt->isFlag(lsfMPTAuthorized)) amount.clear(mptIssue); } } @@ -535,18 +495,19 @@ accountHolds( Asset const& asset, FreezeHandling zeroIfFrozen, AuthHandling zeroIfUnauthorized, - beast::Journal j) + beast::Journal j, + SpendableHandling includeFullBalance) { return std::visit( - [&](auto const& value) { - if constexpr (std::is_same_v< - std::remove_cvref_t, - Issue>) + [&](TIss const& value) { + if constexpr (std::is_same_v) { - return accountHolds(view, account, value, zeroIfFrozen, j); + return accountHolds(view, account, value, zeroIfFrozen, j, includeFullBalance); + } + else if constexpr (std::is_same_v) + { + return accountHolds(view, account, value, zeroIfFrozen, zeroIfUnauthorized, j, includeFullBalance); } - return accountHolds( - view, account, value, zeroIfFrozen, zeroIfUnauthorized, j); }, asset.value()); } @@ -562,13 +523,7 @@ accountFunds( if (!saDefault.native() && saDefault.getIssuer() == id) return saDefault; - return accountHolds( - view, - id, - saDefault.getCurrency(), - saDefault.getIssuer(), - freezeHandling, - j); + return accountHolds(view, id, saDefault.getCurrency(), saDefault.getIssuer(), freezeHandling, j); } // Prevent ownerCount from wrapping under error conditions. @@ -592,8 +547,7 @@ confineOwnerCount( { if (id) { - JLOG(j.fatal()) - << "Account " << *id << " owner count exceeds max!"; + JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!"; } adjusted = std::numeric_limits::max(); } @@ -605,62 +559,46 @@ confineOwnerCount( { if (id) { - JLOG(j.fatal()) - << "Account " << *id << " owner count set below 0!"; + JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; } adjusted = 0; - XRPL_ASSERT(!id, "ripple::confineOwnerCount : id is not set"); + XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); } } return adjusted; } XRPAmount -xrpLiquid( - ReadView const& view, - AccountID const& id, - std::int32_t ownerCountAdj, - beast::Journal j) +xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j) { auto const sle = view.read(keylet::account(id)); if (sle == nullptr) return beast::zero; // Return balance minus reserve - std::uint32_t const ownerCount = confineOwnerCount( - view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj); + std::uint32_t const ownerCount = + confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj); // Pseudo-accounts have no reserve requirement - auto const reserve = isPseudoAccount(sle) - ? XRPAmount{0} - : view.fees().accountReserve(ownerCount); + auto const reserve = isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount); auto const fullBalance = sle->getFieldAmount(sfBalance); auto const balance = view.balanceHook(id, xrpAccount(), fullBalance); - STAmount const amount = - (balance < reserve) ? STAmount{0} : balance - reserve; + STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve; - JLOG(j.trace()) << "accountHolds:" - << " account=" << to_string(id) - << " amount=" << amount.getFullText() - << " fullBalance=" << fullBalance.getFullText() - << " balance=" << balance.getFullText() - << " reserve=" << reserve << " ownerCount=" << ownerCount - << " ownerCountAdj=" << ownerCountAdj; + JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id) << " amount=" << amount.getFullText() + << " fullBalance=" << fullBalance.getFullText() << " balance=" << balance.getFullText() + << " reserve=" << reserve << " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj; return amount.xrp(); } void -forEachItem( - ReadView const& view, - Keylet const& root, - std::function const&)> const& f) +forEachItem(ReadView const& view, Keylet const& root, std::function const&)> const& f) { - XRPL_ASSERT( - root.type == ltDIR_NODE, "ripple::forEachItem : valid root type"); + XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItem : valid root type"); if (root.type != ltDIR_NODE) return; @@ -690,8 +628,7 @@ forEachItemAfter( unsigned int limit, std::function const&)> const& f) { - XRPL_ASSERT( - root.type == ltDIR_NODE, "ripple::forEachItemAfter : valid root type"); + XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItemAfter : valid root type"); if (root.type != ltDIR_NODE) return false; @@ -776,8 +713,7 @@ transferRate(ReadView const& view, MPTID const& issuanceID) // fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000 // For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000 // which represents 50% of 1,000,000,000 - if (auto const sle = view.read(keylet::mptIssuance(issuanceID)); - sle && sle->isFieldPresent(sfTransferFee)) + if (auto const sle = view.read(keylet::mptIssuance(issuanceID)); sle && sle->isFieldPresent(sfTransferFee)) return Rate{1'000'000'000u + 10'000 * sle->getFieldU16(sfTransferFee)}; return parityRate; @@ -797,22 +733,15 @@ transferRate(ReadView const& view, STAmount const& amount) } bool -areCompatible( - ReadView const& validLedger, - ReadView const& testLedger, - beast::Journal::Stream& s, - char const* reason) +areCompatible(ReadView const& validLedger, ReadView const& testLedger, beast::Journal::Stream& s, char const* reason) { bool ret = true; - if (validLedger.info().seq < testLedger.info().seq) + if (validLedger.header().seq < testLedger.header().seq) { // valid -> ... -> test - auto hash = hashOfSeq( - testLedger, - validLedger.info().seq, - beast::Journal{beast::Journal::getNullSink()}); - if (hash && (*hash != validLedger.info().hash)) + auto hash = hashOfSeq(testLedger, validLedger.header().seq, beast::Journal{beast::Journal::getNullSink()}); + if (hash && (*hash != validLedger.header().hash)) { JLOG(s) << reason << " incompatible with valid ledger"; @@ -821,14 +750,11 @@ areCompatible( ret = false; } } - else if (validLedger.info().seq > testLedger.info().seq) + else if (validLedger.header().seq > testLedger.header().seq) { // test -> ... -> valid - auto hash = hashOfSeq( - validLedger, - testLedger.info().seq, - beast::Journal{beast::Journal::getNullSink()}); - if (hash && (*hash != testLedger.info().hash)) + auto hash = hashOfSeq(validLedger, testLedger.header().seq, beast::Journal{beast::Journal::getNullSink()}); + if (hash && (*hash != testLedger.header().hash)) { JLOG(s) << reason << " incompatible preceding ledger"; @@ -838,8 +764,8 @@ areCompatible( } } else if ( - (validLedger.info().seq == testLedger.info().seq) && - (validLedger.info().hash != testLedger.info().hash)) + (validLedger.header().seq == testLedger.header().seq) && + (validLedger.header().hash != testLedger.header().hash)) { // Same sequence number, different hash JLOG(s) << reason << " incompatible ledger"; @@ -849,11 +775,9 @@ areCompatible( if (!ret) { - JLOG(s) << "Val: " << validLedger.info().seq << " " - << to_string(validLedger.info().hash); + JLOG(s) << "Val: " << validLedger.header().seq << " " << to_string(validLedger.header().hash); - JLOG(s) << "New: " << testLedger.info().seq << " " - << to_string(testLedger.info().hash); + JLOG(s) << "New: " << testLedger.header().seq << " " << to_string(testLedger.header().hash); } return ret; @@ -869,13 +793,10 @@ areCompatible( { bool ret = true; - if (testLedger.info().seq > validIndex) + if (testLedger.header().seq > validIndex) { // Ledger we are testing follows last valid ledger - auto hash = hashOfSeq( - testLedger, - validIndex, - beast::Journal{beast::Journal::getNullSink()}); + auto hash = hashOfSeq(testLedger, validIndex, beast::Journal{beast::Journal::getNullSink()}); if (hash && (*hash != validHash)) { JLOG(s) << reason << " incompatible following ledger"; @@ -884,9 +805,7 @@ areCompatible( ret = false; } } - else if ( - (validIndex == testLedger.info().seq) && - (testLedger.info().hash != validHash)) + else if ((validIndex == testLedger.header().seq) && (testLedger.header().hash != validHash)) { JLOG(s) << reason << " incompatible ledger"; @@ -897,8 +816,7 @@ areCompatible( { JLOG(s) << "Val: " << validIndex << " " << to_string(validHash); - JLOG(s) << "New: " << testLedger.info().seq << " " - << to_string(testLedger.info().hash); + JLOG(s) << "New: " << testLedger.header().seq << " " << to_string(testLedger.header().hash); } return ret; @@ -950,8 +868,7 @@ getMajorityAmendments(ReadView const& view) auto const majorities = sle->getFieldArray(sfMajorities); for (auto const& m : majorities) - ret[m.getFieldH256(sfAmendment)] = - tp(d(m.getFieldU32(sfCloseTime))); + ret[m.getFieldH256(sfAmendment)] = tp(d(m.getFieldU32(sfCloseTime))); } } @@ -964,14 +881,13 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) // Easy cases... if (seq > ledger.seq()) { - JLOG(journal.warn()) - << "Can't get seq " << seq << " from " << ledger.seq() << " future"; + JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() << " future"; return std::nullopt; } if (seq == ledger.seq()) - return ledger.info().hash; + return ledger.header().hash; if (seq == (ledger.seq() - 1)) - return ledger.info().parentHash; + return ledger.header().parentHash; if (int diff = ledger.seq() - seq; diff <= 256) { @@ -980,28 +896,23 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) if (hashIndex) { XRPL_ASSERT( - hashIndex->getFieldU32(sfLastLedgerSequence) == - (ledger.seq() - 1), - "ripple::hashOfSeq : matching ledger sequence"); + hashIndex->getFieldU32(sfLastLedgerSequence) == (ledger.seq() - 1), + "xrpl::hashOfSeq : matching ledger sequence"); STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() >= diff) return vec[vec.size() - diff]; - JLOG(journal.warn()) - << "Ledger " << ledger.seq() << " missing hash for " << seq - << " (" << vec.size() << "," << diff << ")"; + JLOG(journal.warn()) << "Ledger " << ledger.seq() << " missing hash for " << seq << " (" << vec.size() + << "," << diff << ")"; } else { - JLOG(journal.warn()) - << "Ledger " << ledger.seq() << ":" << ledger.info().hash - << " missing normal list"; + JLOG(journal.warn()) << "Ledger " << ledger.seq() << ":" << ledger.header().hash << " missing normal list"; } } if ((seq & 0xff) != 0) { - JLOG(journal.debug()) - << "Can't get seq " << seq << " from " << ledger.seq() << " past"; + JLOG(journal.debug()) << "Can't get seq " << seq << " from " << ledger.seq() << " past"; return std::nullopt; } @@ -1010,16 +921,14 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) if (hashIndex) { auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence); - XRPL_ASSERT(lastSeq >= seq, "ripple::hashOfSeq : minimum last ledger"); - XRPL_ASSERT( - (lastSeq & 0xff) == 0, "ripple::hashOfSeq : valid last ledger"); + XRPL_ASSERT(lastSeq >= seq, "xrpl::hashOfSeq : minimum last ledger"); + XRPL_ASSERT((lastSeq & 0xff) == 0, "xrpl::hashOfSeq : valid last ledger"); auto const diff = (lastSeq - seq) >> 8; STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() > diff) return vec[vec.size() - diff - 1]; } - JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() - << " error"; + JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() << " error"; return std::nullopt; } @@ -1030,15 +939,11 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) //------------------------------------------------------------------------------ void -adjustOwnerCount( - ApplyView& view, - std::shared_ptr const& sle, - std::int32_t amount, - beast::Journal j) +adjustOwnerCount(ApplyView& view, std::shared_ptr const& sle, std::int32_t amount, beast::Journal j) { if (!sle) return; - XRPL_ASSERT(amount, "ripple::adjustOwnerCount : nonzero amount input"); + XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input"); std::uint32_t const current{sle->getFieldU32(sfOwnerCount)}; AccountID const id = (*sle)[sfAccount]; std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j); @@ -1050,19 +955,16 @@ adjustOwnerCount( std::function describeOwnerDir(AccountID const& account) { - return [&account](std::shared_ptr const& sle) { - (*sle)[sfOwner] = account; - }; + return [account](std::shared_ptr const& sle) { (*sle)[sfOwner] = account; }; } TER -dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr& object) +dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr& object, SF_UINT64 const& node) { - auto const page = view.dirInsert( - keylet::ownerDir(owner), object->key(), describeOwnerDir(owner)); + auto const page = view.dirInsert(keylet::ownerDir(owner), object->key(), describeOwnerDir(owner)); if (!page) return tecDIR_FULL; // LCOV_EXCL_LINE - object->setFieldU64(sfOwnerNode, *page); + object->setFieldU64(node, *page); return tesSUCCESS; } @@ -1074,7 +976,7 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey) for (std::uint16_t i = 0; i < maxAccountAttempts; ++i) { ripesha_hasher rsh; - auto const hash = sha512Half(i, view.info().parentHash, pseudoOwnerKey); + auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey); rsh(hash.data(), hash.size()); AccountID const ret{static_cast(rsh)}; if (!view.read(keylet::account(ret))) @@ -1098,8 +1000,8 @@ getPseudoAccountFields() { // LCOV_EXCL_START LogicError( - "ripple::isPseudoAccount : unable to find account root ledger " - "format"); + "xrpl::getPseudoAccountFields : unable to find account root " + "ledger format"); // LCOV_EXCL_STOP } auto const& soTemplate = ar->getSOTemplate(); @@ -1116,34 +1018,27 @@ getPseudoAccountFields() } [[nodiscard]] bool -isPseudoAccount(std::shared_ptr sleAcct) +isPseudoAccount(std::shared_ptr sleAcct, std::set const& pseudoFieldFilter) { auto const& fields = getPseudoAccountFields(); // Intentionally use defensive coding here because it's cheap and makes the // semantics of true return value clean. return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT && - std::count_if( - fields.begin(), fields.end(), [&sleAcct](SField const* sf) -> bool { - return sleAcct->isFieldPresent(*sf); - }) > 0; + std::count_if(fields.begin(), fields.end(), [&sleAcct, &pseudoFieldFilter](SField const* sf) -> bool { + return sleAcct->isFieldPresent(*sf) && (pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf)); + }) > 0; } Expected, TER> -createPseudoAccount( - ApplyView& view, - uint256 const& pseudoOwnerKey, - SField const& ownerField) +createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField) { - [[maybe_unused]] auto const& fields = getPseudoAccountFields(); + [[maybe_unused]] + auto const& fields = getPseudoAccountFields(); XRPL_ASSERT( std::count_if( - fields.begin(), - fields.end(), - [&ownerField](SField const* sf) -> bool { - return *sf == ownerField; - }) == 1, - "ripple::createPseudoAccount : valid owner field"); + fields.begin(), fields.end(), [&ownerField](SField const* sf) -> bool { return *sf == ownerField; }) == 1, + "xrpl::createPseudoAccount : valid owner field"); auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey); if (accountId == beast::zero) @@ -1157,16 +1052,16 @@ createPseudoAccount( // Pseudo-accounts can't submit transactions, so set the sequence number // to 0 to make them easier to spot and verify, and add an extra level // of protection. - std::uint32_t const seqno = // - view.rules().enabled(featureSingleAssetVault) // - ? 0 // + std::uint32_t const seqno = // + view.rules().enabled(featureSingleAssetVault) || // + view.rules().enabled(featureLendingProtocol) // + ? 0 // : view.seq(); account->setFieldU32(sfSequence, seqno); // Ignore reserves requirement, disable the master key, allow default // rippling, and enable deposit authorization to prevent payments into // pseudo-account. - account->setFieldU32( - sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); + account->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); // Link the pseudo-account with its owner object. account->setFieldH256(ownerField, pseudoOwnerKey); @@ -1206,11 +1101,150 @@ canAddHolding(ReadView const& view, MPTIssue const& mptIssue) [[nodiscard]] TER canAddHolding(ReadView const& view, Asset const& asset) { + return std::visit( + [&](TIss const& issue) -> TER { return canAddHolding(view, issue); }, asset.value()); +} + +[[nodiscard]] TER +checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag) +{ + if (toSle == nullptr) + return tecNO_DST; + + // The tag is basically account-specific information we don't + // understand, but we can require someone to fill it in. + if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag) + return tecDST_TAG_NEEDED; // Cannot send without a tag + + return tesSUCCESS; +} + +/* + * Checks if a withdrawal amount into the destination account exceeds + * any applicable receiving limit. + * Called by VaultWithdraw and LoanBrokerCoverWithdraw. + * + * IOU : Performs the trustline check against the destination account's + * credit limit to ensure the account's trust maximum is not exceeded. + * + * MPT: The limit check is effectively skipped (returns true). This is + * because MPT MaximumAmount relates to token supply, and withdrawal does not + * involve minting new tokens that could exceed the global cap. + * On withdrawal, tokens are simply transferred from the vault's pseudo-account + * to the destination account. Since no new MPT tokens are minted during this + * transfer, the withdrawal cannot violate the MPT MaximumAmount/supply cap + * even if `from` is the issuer. + */ +static TER +withdrawToDestExceedsLimit(ReadView const& view, AccountID const& from, AccountID const& to, STAmount const& amount) +{ + auto const& issuer = amount.getIssuer(); + if (from == to || to == issuer || isXRP(issuer)) + return tesSUCCESS; + return std::visit( [&](TIss const& issue) -> TER { - return canAddHolding(view, issue); + if constexpr (std::is_same_v) + { + auto const& currency = issue.currency; + auto const owed = creditBalance(view, to, issuer, currency); + if (owed <= beast::zero) + { + auto const limit = creditLimit(view, to, issuer, currency); + if (-owed >= limit || amount > (limit + owed)) + return tecNO_LINE; + } + } + return tesSUCCESS; }, - asset.value()); + amount.asset().value()); +} + +[[nodiscard]] TER +canWithdraw( + ReadView const& view, + AccountID const& from, + AccountID const& to, + SLE::const_ref toSle, + STAmount const& amount, + bool hasDestinationTag) +{ + if (auto const ret = checkDestinationAndTag(toSle, hasDestinationTag)) + return ret; + + if (from == to) + return tesSUCCESS; + + if (toSle->isFlag(lsfDepositAuth)) + { + if (!view.exists(keylet::depositPreauth(to, from))) + return tecNO_PERMISSION; + } + + return withdrawToDestExceedsLimit(view, from, to, amount); +} + +[[nodiscard]] TER +canWithdraw( + ReadView const& view, + AccountID const& from, + AccountID const& to, + STAmount const& amount, + bool hasDestinationTag) +{ + auto const toSle = view.read(keylet::account(to)); + + return canWithdraw(view, from, to, toSle, amount, hasDestinationTag); +} + +[[nodiscard]] TER +canWithdraw(ReadView const& view, STTx const& tx) +{ + auto const from = tx[sfAccount]; + auto const to = tx[~sfDestination].value_or(from); + + return canWithdraw(view, from, to, tx[sfAmount], tx.isFieldPresent(sfDestinationTag)); +} + +TER +doWithdraw( + ApplyView& view, + STTx const& tx, + AccountID const& senderAcct, + AccountID const& dstAcct, + AccountID const& sourceAcct, + XRPAmount priorBalance, + STAmount const& amount, + beast::Journal j) +{ + // Create trust line or MPToken for the receiving account + if (dstAcct == senderAcct) + { + if (auto const ter = addEmptyHolding(view, senderAcct, priorBalance, amount.asset(), j); + !isTesSuccess(ter) && ter != tecDUPLICATE) + return ter; + } + else + { + auto dstSle = view.peek(keylet::account(dstAcct)); + if (auto err = verifyDepositPreauth(tx, view, senderAcct, dstAcct, dstSle, j)) + return err; + } + + // Sanity check + if (accountHolds( + view, sourceAcct, amount.asset(), FreezeHandling::fhIGNORE_FREEZE, AuthHandling::ahIGNORE_AUTH, j) < amount) + { + // LCOV_EXCL_START + JLOG(j.error()) << "LoanBrokerCoverWithdraw: negative balance of " + "broker cover assets."; + return tefINTERNAL; + // LCOV_EXCL_STOP + } + + // Move the funds directly from the broker's pseudo-account to the + // dstAcct + return accountSend(view, sourceAcct, dstAcct, amount, j, WaiveTransferFee::Yes); } [[nodiscard]] TER @@ -1221,8 +1255,8 @@ addEmptyHolding( Issue const& issue, beast::Journal journal) { - // Every account can hold XRP. - if (issue.native()) + // Every account can hold XRP. An issuer can issue directly. + if (issue.native() || accountID == issue.getIssuer()) return tesSUCCESS; auto const& issuerId = issue.getIssuer(); @@ -1283,6 +1317,8 @@ addEmptyHolding( return tefINTERNAL; // LCOV_EXCL_LINE if (view.peek(keylet::mptoken(mptID, accountID))) return tecDUPLICATE; + if (accountID == mptIssue.getIssuer()) + return tesSUCCESS; return authorizeMPToken(view, priorBalance, mptID, accountID, journal); } @@ -1316,11 +1352,7 @@ authorizeMPToken( if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) return tecINTERNAL; // LCOV_EXCL_LINE - if (!view.dirRemove( - keylet::ownerDir(account), - (*sleMpt)[sfOwnerNode], - sleMpt->key(), - false)) + if (!view.dirRemove(keylet::ownerDir(account), (*sleMpt)[sfOwnerNode], sleMpt->key(), false)) return tecINTERNAL; // LCOV_EXCL_LINE adjustOwnerCount(view, sleAcct, -1, journal); @@ -1340,12 +1372,22 @@ authorizeMPToken( // items. This is similar to the reserve requirements of trust lines. std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount); XRPAmount const reserveCreate( - (uOwnerCount < 2) ? XRPAmount(beast::zero) - : view.fees().accountReserve(uOwnerCount + 1)); + (uOwnerCount < 2) ? XRPAmount(beast::zero) : view.fees().accountReserve(uOwnerCount + 1)); if (priorBalance < reserveCreate) return tecINSUFFICIENT_RESERVE; + // Defensive check before we attempt to create MPToken for the issuer + auto const mpt = view.read(keylet::mptIssuance(mptIssuanceID)); + if (!mpt || mpt->getAccountID(sfIssuer) == account) + { + // LCOV_EXCL_START + UNREACHABLE("xrpl::authorizeMPToken : invalid issuance or issuers token"); + if (view.rules().enabled(featureLendingProtocol)) + return tecINTERNAL; + // LCOV_EXCL_STOP + } + auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); auto mptoken = std::make_shared(mptokenKey); if (auto ter = dirLink(view, account, mptoken)) @@ -1415,28 +1457,31 @@ trustCreate( std::uint32_t uQualityOut, beast::Journal j) { - JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", " - << to_string(uDstAccountID) << ", " + JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", " << to_string(uDstAccountID) << ", " << saBalance.getFullText(); auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID; auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID; + if (uLowAccountID == uHighAccountID) + { + // LCOV_EXCL_START + UNREACHABLE("xrpl::trustCreate : trust line to self"); + if (view.rules().enabled(featureLendingProtocol)) + return tecINTERNAL; + // LCOV_EXCL_STOP + } auto const sleRippleState = std::make_shared(ltRIPPLE_STATE, uIndex); view.insert(sleRippleState); - auto lowNode = view.dirInsert( - keylet::ownerDir(uLowAccountID), - sleRippleState->key(), - describeOwnerDir(uLowAccountID)); + auto lowNode = + view.dirInsert(keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID)); if (!lowNode) return tecDIR_FULL; // LCOV_EXCL_LINE - auto highNode = view.dirInsert( - keylet::ownerDir(uHighAccountID), - sleRippleState->key(), - describeOwnerDir(uHighAccountID)); + auto highNode = + view.dirInsert(keylet::ownerDir(uHighAccountID), sleRippleState->key(), describeOwnerDir(uHighAccountID)); if (!highNode) return tecDIR_FULL; // LCOV_EXCL_LINE @@ -1444,16 +1489,14 @@ trustCreate( bool const bSetDst = saLimit.getIssuer() == uDstAccountID; bool const bSetHigh = bSrcHigh ^ bSetDst; - XRPL_ASSERT(sleAccount, "ripple::trustCreate : non-null SLE"); + XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE"); if (!sleAccount) return tefINTERNAL; // LCOV_EXCL_LINE XRPL_ASSERT( - sleAccount->getAccountID(sfAccount) == - (bSetHigh ? uHighAccountID : uLowAccountID), - "ripple::trustCreate : matching account ID"); - auto const slePeer = - view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); + sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID), + "xrpl::trustCreate : matching account ID"); + auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); if (!slePeer) return tecNO_TARGET; @@ -1461,20 +1504,16 @@ trustCreate( sleRippleState->setFieldU64(sfLowNode, *lowNode); sleRippleState->setFieldU64(sfHighNode, *highNode); - sleRippleState->setFieldAmount( - bSetHigh ? sfHighLimit : sfLowLimit, saLimit); + sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit); sleRippleState->setFieldAmount( bSetHigh ? sfLowLimit : sfHighLimit, - STAmount(Issue{ - saBalance.getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID})); + STAmount(Issue{saBalance.getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID})); if (uQualityIn) - sleRippleState->setFieldU32( - bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn); + sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn); if (uQualityOut) - sleRippleState->setFieldU32( - bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut); + sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut); std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve; @@ -1505,21 +1544,15 @@ trustCreate( adjustOwnerCount(view, sleAccount, 1, j); // ONLY: Create ripple balance. - sleRippleState->setFieldAmount( - sfBalance, bSetHigh ? -saBalance : saBalance); + sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance); - view.creditHook( - uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed()); + view.creditHook(uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed()); return tesSUCCESS; } [[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Issue const& issue, - beast::Journal journal) +removeEmptyHolding(ApplyView& view, AccountID const& accountID, Issue const& issue, beast::Journal journal) { if (issue.native()) { @@ -1535,18 +1568,20 @@ removeEmptyHolding( } // `asset` is an IOU. + // If the account is the issuer, then no line should exist. Check anyway. If + // a line does exist, it will get deleted. If not, return success. + bool const accountIsIssuer = accountID == issue.account; auto const line = view.peek(keylet::line(accountID, issue)); if (!line) - return tecOBJECT_NOT_FOUND; - if (line->at(sfBalance)->iou() != beast::zero) + return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND; + if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::zero) return tecHAS_OBLIGATIONS; // Adjust the owner count(s) if (line->isFlag(lsfLowReserve)) { // Clear reserve for low account. - auto sleLowAccount = - view.peek(keylet::account(line->at(sfLowLimit)->getIssuer())); + auto sleLowAccount = view.peek(keylet::account(line->at(sfLowLimit)->getIssuer())); if (!sleLowAccount) return tecINTERNAL; // LCOV_EXCL_LINE @@ -1560,8 +1595,7 @@ removeEmptyHolding( if (line->isFlag(lsfHighReserve)) { // Clear reserve for high account. - auto sleHighAccount = - view.peek(keylet::account(line->at(sfHighLimit)->getIssuer())); + auto sleHighAccount = view.peek(keylet::account(line->at(sfHighLimit)->getIssuer())); if (!sleHighAccount) return tecINTERNAL; // LCOV_EXCL_LINE @@ -1572,25 +1606,24 @@ removeEmptyHolding( line->clearFlag(lsfHighReserve); } - return trustDelete( - view, - line, - line->at(sfLowLimit)->getIssuer(), - line->at(sfHighLimit)->getIssuer(), - journal); + return trustDelete(view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal); } [[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - MPTIssue const& mptIssue, - beast::Journal journal) +removeEmptyHolding(ApplyView& view, AccountID const& accountID, MPTIssue const& mptIssue, beast::Journal journal) { + // If the account is the issuer, then no token should exist. MPTs do not + // have the legacy ability to create such a situation, but check anyway. If + // a token does exist, it will get deleted. If not, return success. + bool const accountIsIssuer = accountID == mptIssue.getIssuer(); auto const& mptID = mptIssue.getMptID(); auto const mptoken = view.peek(keylet::mptoken(mptID, accountID)); if (!mptoken) - return tecOBJECT_NOT_FOUND; + return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND; + // Unlike a trust line, if the account is the issuer, and the token has a + // balance, it can not just be deleted, because that will throw the issuance + // accounting out of balance, so fail. Since this should be impossible + // anyway, I'm not going to put any effort into it. if (mptoken->at(sfMPTAmount) != 0) return tecHAS_OBLIGATIONS; @@ -1618,22 +1651,14 @@ trustDelete( JLOG(j.trace()) << "trustDelete: Deleting ripple line: low"; - if (!view.dirRemove( - keylet::ownerDir(uLowAccountID), - uLowNode, - sleRippleState->key(), - false)) + if (!view.dirRemove(keylet::ownerDir(uLowAccountID), uLowNode, sleRippleState->key(), false)) { return tefBAD_LEDGER; // LCOV_EXCL_LINE } JLOG(j.trace()) << "trustDelete: Deleting ripple line: high"; - if (!view.dirRemove( - keylet::ownerDir(uHighAccountID), - uHighNode, - sleRippleState->key(), - false)) + if (!view.dirRemove(keylet::ownerDir(uHighAccountID), uHighNode, sleRippleState->key(), false)) { return tefBAD_LEDGER; // LCOV_EXCL_LINE } @@ -1655,20 +1680,12 @@ offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) // Detect legacy directories. uint256 uDirectory = sle->getFieldH256(sfBookDirectory); - if (!view.dirRemove( - keylet::ownerDir(owner), - sle->getFieldU64(sfOwnerNode), - offerIndex, - false)) + if (!view.dirRemove(keylet::ownerDir(owner), sle->getFieldU64(sfOwnerNode), offerIndex, false)) { return tefBAD_LEDGER; // LCOV_EXCL_LINE } - if (!view.dirRemove( - keylet::page(uDirectory), - sle->getFieldU64(sfBookNode), - offerIndex, - false)) + if (!view.dirRemove(keylet::page(uDirectory), sle->getFieldU64(sfBookNode), offerIndex, false)) { return tefBAD_LEDGER; // LCOV_EXCL_LINE } @@ -1677,7 +1694,7 @@ offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) { XRPL_ASSERT( sle->isFlag(lsfHybrid) && sle->isFieldPresent(sfDomainID), - "ripple::offerDelete : should be a hybrid domain offer"); + "xrpl::offerDelete : should be a hybrid domain offer"); auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks); @@ -1686,8 +1703,7 @@ offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory); auto const& dirNode = bookDir.getFieldU64(sfBookNode); - if (!view.dirRemove( - keylet::page(dirIndex), dirNode, offerIndex, false)) + if (!view.dirRemove(keylet::page(dirIndex), dirNode, offerIndex, false)) { return tefBAD_LEDGER; // LCOV_EXCL_LINE } @@ -1720,23 +1736,17 @@ rippleCreditIOU( // Make sure issuer is involved. XRPL_ASSERT( !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer, - "ripple::rippleCreditIOU : matching issuer or don't care"); + "xrpl::rippleCreditIOU : matching issuer or don't care"); (void)issuer; // Disallow sending to self. - XRPL_ASSERT( - uSenderID != uReceiverID, - "ripple::rippleCreditIOU : sender is not receiver"); + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleCreditIOU : sender is not receiver"); bool const bSenderHigh = uSenderID > uReceiverID; auto const index = keylet::line(uSenderID, uReceiverID, currency); - XRPL_ASSERT( - !isXRP(uSenderID) && uSenderID != noAccount(), - "ripple::rippleCreditIOU : sender is not XRP"); - XRPL_ASSERT( - !isXRP(uReceiverID) && uReceiverID != noAccount(), - "ripple::rippleCreditIOU : receiver is not XRP"); + XRPL_ASSERT(!isXRP(uSenderID) && uSenderID != noAccount(), "xrpl::rippleCreditIOU : sender is not XRP"); + XRPL_ASSERT(!isXRP(uReceiverID) && uReceiverID != noAccount(), "xrpl::rippleCreditIOU : receiver is not XRP"); // If the line exists, modify it accordingly. if (auto const sleRippleState = view.peek(index)) @@ -1752,10 +1762,8 @@ rippleCreditIOU( saBalance -= saAmount; - JLOG(j.trace()) << "rippleCreditIOU: " << to_string(uSenderID) << " -> " - << to_string(uReceiverID) - << " : before=" << saBefore.getFullText() - << " amount=" << saAmount.getFullText() + JLOG(j.trace()) << "rippleCreditIOU: " << to_string(uSenderID) << " -> " << to_string(uReceiverID) + << " : before=" << saBefore.getFullText() << " amount=" << saAmount.getFullText() << " after=" << saBalance.getFullText(); std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags)); @@ -1769,31 +1777,21 @@ rippleCreditIOU( // Sender is zero or negative. && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) // Sender reserve is set. - && - static_cast( - uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != - static_cast( - view.read(keylet::account(uSenderID))->getFlags() & - lsfDefaultRipple) && + && static_cast(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != + static_cast(view.read(keylet::account(uSenderID))->getFlags() & lsfDefaultRipple) && !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && - !sleRippleState->getFieldAmount( - !bSenderHigh ? sfLowLimit : sfHighLimit) + !sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) // Sender trust limit is 0. - && !sleRippleState->getFieldU32( - !bSenderHigh ? sfLowQualityIn : sfHighQualityIn) + && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) // Sender quality in is 0. - && !sleRippleState->getFieldU32( - !bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) + && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) // Sender quality out is 0. { // Clear the reserve of the sender, possibly delete the line! - adjustOwnerCount( - view, view.peek(keylet::account(uSenderID)), -1, j); + adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j); // Clear reserve flag. - sleRippleState->setFieldU32( - sfFlags, - uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); + sleRippleState->setFieldU32(sfFlags, uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); // Balance is zero, receiver reserve is clear. bDelete = !saBalance // Balance is zero. @@ -1811,11 +1809,7 @@ rippleCreditIOU( if (bDelete) { return trustDelete( - view, - sleRippleState, - bSenderHigh ? uReceiverID : uSenderID, - !bSenderHigh ? uReceiverID : uSenderID, - j); + view, sleRippleState, bSenderHigh ? uReceiverID : uSenderID, !bSenderHigh ? uReceiverID : uSenderID, j); } view.update(sleRippleState); @@ -1829,8 +1823,7 @@ rippleCreditIOU( JLOG(j.debug()) << "rippleCreditIOU: " "create line: " - << to_string(uSenderID) << " -> " << to_string(uReceiverID) - << " : " << saAmount.getFullText(); + << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " << saAmount.getFullText(); auto const sleAccount = view.peek(keylet::account(uReceiverID)); if (!sleAccount) @@ -1869,21 +1862,16 @@ rippleSendIOU( beast::Journal j, WaiveTransferFee waiveFee) { - auto const issuer = saAmount.getIssuer(); + auto const& issuer = saAmount.getIssuer(); - XRPL_ASSERT( - !isXRP(uSenderID) && !isXRP(uReceiverID), - "ripple::rippleSendIOU : neither sender nor receiver is XRP"); - XRPL_ASSERT( - uSenderID != uReceiverID, - "ripple::rippleSendIOU : sender is not receiver"); + XRPL_ASSERT(!isXRP(uSenderID) && !isXRP(uReceiverID), "xrpl::rippleSendIOU : neither sender nor receiver is XRP"); + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendIOU : sender is not receiver"); if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount()) { // Direct send: redeeming IOUs and/or sending own IOUs. - auto const ter = - rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, false, j); - if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS) + auto const ter = rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, false, j); + if (ter != tesSUCCESS) return ter; saActual = saAmount; return tesSUCCESS; @@ -1893,17 +1881,12 @@ rippleSendIOU( // Calculate the amount to transfer accounting // for any transfer fees if the fee is not waived: - saActual = (waiveFee == WaiveTransferFee::Yes) - ? saAmount - : multiply(saAmount, transferRate(view, issuer)); + saActual = (waiveFee == WaiveTransferFee::Yes) ? saAmount : multiply(saAmount, transferRate(view, issuer)); - JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > " - << to_string(uReceiverID) - << " : deliver=" << saAmount.getFullText() - << " cost=" << saActual.getFullText(); + JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > " << to_string(uReceiverID) + << " : deliver=" << saAmount.getFullText() << " cost=" << saActual.getFullText(); - TER terResult = - rippleCreditIOU(view, issuer, uReceiverID, saAmount, true, j); + TER terResult = rippleCreditIOU(view, issuer, uReceiverID, saAmount, true, j); if (tesSUCCESS == terResult) terResult = rippleCreditIOU(view, uSenderID, issuer, saActual, true, j); @@ -1911,6 +1894,78 @@ rippleSendIOU( return terResult; } +// Send regardless of limits. +// --> receivers: Amount/currency/issuer to deliver to receivers. +// <-- saActual: Amount actually cost to sender. Sender pays fees. +static TER +rippleSendMultiIOU( + ApplyView& view, + AccountID const& senderID, + Issue const& issue, + MultiplePaymentDestinations const& receivers, + STAmount& actual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + auto const& issuer = issue.getIssuer(); + + XRPL_ASSERT(!isXRP(senderID), "xrpl::rippleSendMultiIOU : sender is not XRP"); + + // These may diverge + STAmount takeFromSender{issue}; + actual = takeFromSender; + + // Failures return immediately. + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{issue, r.second}; + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + XRPL_ASSERT(!isXRP(receiverID), "xrpl::rippleSendMultiIOU : receiver is not XRP"); + + if (senderID == issuer || receiverID == issuer || issuer == noAccount()) + { + // Direct send: redeeming IOUs and/or sending own IOUs. + if (auto const ter = rippleCreditIOU(view, senderID, receiverID, amount, false, j)) + return ter; + actual += amount; + // Do not add amount to takeFromSender, because rippleCreditIOU took + // it. + + continue; + } + + // Sending 3rd party IOUs: transit. + + // Calculate the amount to transfer accounting + // for any transfer fees if the fee is not waived: + STAmount actualSend = + (waiveFee == WaiveTransferFee::Yes) ? amount : multiply(amount, transferRate(view, issuer)); + actual += actualSend; + takeFromSender += actualSend; + + JLOG(j.debug()) << "rippleSendMultiIOU> " << to_string(senderID) << " - > " << to_string(receiverID) + << " : deliver=" << amount.getFullText() << " cost=" << actual.getFullText(); + + if (TER const terResult = rippleCreditIOU(view, issuer, receiverID, amount, true, j)) + return terResult; + } + + if (senderID != issuer && takeFromSender) + { + if (TER const terResult = rippleCreditIOU(view, senderID, issuer, takeFromSender, true, j)) + return terResult; + } + + return tesSUCCESS; +} + static TER accountSendIOU( ApplyView& view, @@ -1932,7 +1987,7 @@ accountSendIOU( // LCOV_EXCL_START XRPL_ASSERT( saAmount >= beast::zero && !saAmount.holds(), - "ripple::accountSendIOU : minimum amount and not MPT"); + "xrpl::accountSendIOU : minimum amount and not MPT"); // LCOV_EXCL_STOP } @@ -1946,12 +2001,10 @@ accountSendIOU( { STAmount saActual; - JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> " - << to_string(uReceiverID) << " : " + JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " << saAmount.getFullText(); - return rippleSendIOU( - view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); + return rippleSendIOU(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); } /* XRP send which does not check reserve and can do pure adjustment. @@ -1961,12 +2014,8 @@ accountSendIOU( */ TER terResult(tesSUCCESS); - SLE::pointer sender = uSenderID != beast::zero - ? view.peek(keylet::account(uSenderID)) - : SLE::pointer(); - SLE::pointer receiver = uReceiverID != beast::zero - ? view.peek(keylet::account(uReceiverID)) - : SLE::pointer(); + SLE::pointer sender = uSenderID != beast::zero ? view.peek(keylet::account(uSenderID)) : SLE::pointer(); + SLE::pointer receiver = uReceiverID != beast::zero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer(); if (auto stream = j.trace()) { @@ -1979,9 +2028,8 @@ accountSendIOU( if (receiver) receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - stream << "accountSendIOU> " << to_string(uSenderID) << " (" - << sender_bal << ") -> " << to_string(uReceiverID) << " (" - << receiver_bal << ") : " << saAmount.getFullText(); + stream << "accountSendIOU> " << to_string(uSenderID) << " (" << sender_bal << ") -> " << to_string(uReceiverID) + << " (" << receiver_bal << ") : " << saAmount.getFullText(); } if (sender) @@ -1991,8 +2039,7 @@ accountSendIOU( // VFALCO Its laborious to have to mutate the // TER based on params everywhere // LCOV_EXCL_START - terResult = view.open() ? TER{telFAILED_PROCESSING} - : TER{tecFAILED_PROCESSING}; + terResult = view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; // LCOV_EXCL_STOP } else @@ -2027,14 +2074,138 @@ accountSendIOU( if (receiver) receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - stream << "accountSendIOU< " << to_string(uSenderID) << " (" - << sender_bal << ") -> " << to_string(uReceiverID) << " (" - << receiver_bal << ") : " << saAmount.getFullText(); + stream << "accountSendIOU< " << to_string(uSenderID) << " (" << sender_bal << ") -> " << to_string(uReceiverID) + << " (" << receiver_bal << ") : " << saAmount.getFullText(); } return terResult; } +static TER +accountSendMultiIOU( + ApplyView& view, + AccountID const& senderID, + Issue const& issue, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT_PARTS(receivers.size() > 1, "xrpl::accountSendMultiIOU", "multiple recipients provided"); + + if (!issue.native()) + { + STAmount actual; + JLOG(j.trace()) << "accountSendMultiIOU: " << to_string(senderID) << " sending " << receivers.size() << " IOUs"; + + return rippleSendMultiIOU(view, senderID, issue, receivers, actual, j, waiveFee); + } + + /* XRP send which does not check reserve and can do pure adjustment. + * Note that sender or receiver may be null and this not a mistake; this + * setup could be used during pathfinding and it is carefully controlled to + * ensure that transfers are balanced. + */ + + SLE::pointer sender = senderID != beast::zero ? view.peek(keylet::account(senderID)) : SLE::pointer(); + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU> " << to_string(senderID) << " (" << sender_bal << ") -> " << receivers.size() + << " receivers."; + } + + // Failures return immediately. + STAmount takeFromSender{issue}; + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{issue, r.second}; + + if (amount < beast::zero) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + SLE::pointer receiver = receiverID != beast::zero ? view.peek(keylet::account(receiverID)) : SLE::pointer(); + + if (auto stream = j.trace()) + { + std::string receiver_bal("-"); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU> " << to_string(senderID) << " -> " << to_string(receiverID) << " (" + << receiver_bal << ") : " << amount.getFullText(); + } + + if (receiver) + { + // Increment XRP balance. + auto const rcvBal = receiver->getFieldAmount(sfBalance); + receiver->setFieldAmount(sfBalance, rcvBal + amount); + view.creditHook(xrpAccount(), receiverID, amount, -rcvBal); + + view.update(receiver); + + // Take what is actually sent + takeFromSender += amount; + } + + if (auto stream = j.trace()) + { + std::string receiver_bal("-"); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU< " << to_string(senderID) << " -> " << to_string(receiverID) << " (" + << receiver_bal << ") : " << amount.getFullText(); + } + } + + if (sender) + { + if (sender->getFieldAmount(sfBalance) < takeFromSender) + { + return TER{tecFAILED_PROCESSING}; + } + else + { + auto const sndBal = sender->getFieldAmount(sfBalance); + view.creditHook(senderID, xrpAccount(), takeFromSender, sndBal); + + // Decrement XRP balance. + sender->setFieldAmount(sfBalance, sndBal - takeFromSender); + view.update(sender); + } + } + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + std::string receiver_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU< " << to_string(senderID) << " (" << sender_bal << ") -> " << receivers.size() + << " receivers."; + } + return tesSUCCESS; +} + static TER rippleCreditMPT( ApplyView& view, @@ -2045,7 +2216,7 @@ rippleCreditMPT( { // Do not check MPT authorization here - it must have been checked earlier auto const mptID = keylet::mptIssuance(saAmount.get().getMptID()); - auto const issuer = saAmount.getIssuer(); + auto const& issuer = saAmount.getIssuer(); auto sleIssuance = view.peek(mptID); if (!sleIssuance) return tecOBJECT_NOT_FOUND; @@ -2107,15 +2278,12 @@ rippleSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - XRPL_ASSERT( - uSenderID != uReceiverID, - "ripple::rippleSendMPT : sender is not receiver"); + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendMPT : sender is not receiver"); // Safe to get MPT since rippleSendMPT is only called by accountSendMPT - auto const issuer = saAmount.getIssuer(); + auto const& issuer = saAmount.getIssuer(); - auto const sle = - view.read(keylet::mptIssuance(saAmount.get().getMptID())); + auto const sle = view.read(keylet::mptIssuance(saAmount.get().getMptID())); if (!sle) return tecOBJECT_NOT_FOUND; @@ -2126,17 +2294,13 @@ rippleSendMPT( if (uSenderID == issuer) { auto const sendAmount = saAmount.mpt().value(); - auto const maximumAmount = - sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); - if (sendAmount > maximumAmount || - sle->getFieldU64(sfOutstandingAmount) > - maximumAmount - sendAmount) + auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); + if (sendAmount > maximumAmount || sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) return tecPATH_DRY; } // Direct send: redeeming MPTs and/or sending own MPTs. - auto const ter = - rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); + auto const ter = rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); if (ter != tesSUCCESS) return ter; saActual = saAmount; @@ -2146,23 +2310,103 @@ rippleSendMPT( // Sending 3rd party MPTs: transit. saActual = (waiveFee == WaiveTransferFee::Yes) ? saAmount - : multiply( - saAmount, - transferRate(view, saAmount.get().getMptID())); + : multiply(saAmount, transferRate(view, saAmount.get().getMptID())); - JLOG(j.debug()) << "rippleSendMPT> " << to_string(uSenderID) << " - > " - << to_string(uReceiverID) - << " : deliver=" << saAmount.getFullText() - << " cost=" << saActual.getFullText(); + JLOG(j.debug()) << "rippleSendMPT> " << to_string(uSenderID) << " - > " << to_string(uReceiverID) + << " : deliver=" << saAmount.getFullText() << " cost=" << saActual.getFullText(); - if (auto const terResult = - rippleCreditMPT(view, issuer, uReceiverID, saAmount, j); - terResult != tesSUCCESS) + if (auto const terResult = rippleCreditMPT(view, issuer, uReceiverID, saAmount, j); terResult != tesSUCCESS) return terResult; return rippleCreditMPT(view, uSenderID, issuer, saActual, j); } +static TER +rippleSendMultiMPT( + ApplyView& view, + AccountID const& senderID, + MPTIssue const& mptIssue, + MultiplePaymentDestinations const& receivers, + STAmount& actual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + // Safe to get MPT since rippleSendMultiMPT is only called by + // accountSendMultiMPT + auto const& issuer = mptIssue.getIssuer(); + + auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID())); + if (!sle) + return tecOBJECT_NOT_FOUND; + + // These may diverge + STAmount takeFromSender{mptIssue}; + actual = takeFromSender; + + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{mptIssue, r.second}; + + if (amount < beast::zero) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + if (senderID == issuer || receiverID == issuer) + { + // if sender is issuer, check that the new OutstandingAmount will + // not exceed MaximumAmount + if (senderID == issuer) + { + XRPL_ASSERT_PARTS( + takeFromSender == beast::zero, + "rippler::rippleSendMultiMPT", + "sender == issuer, takeFromSender == zero"); + auto const sendAmount = amount.mpt().value(); + auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); + if (sendAmount > maximumAmount || sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) + return tecPATH_DRY; + } + + // Direct send: redeeming MPTs and/or sending own MPTs. + if (auto const ter = rippleCreditMPT(view, senderID, receiverID, amount, j)) + return ter; + actual += amount; + // Do not add amount to takeFromSender, because rippleCreditMPT took + // it + + continue; + } + + // Sending 3rd party MPTs: transit. + STAmount actualSend = (waiveFee == WaiveTransferFee::Yes) + ? amount + : multiply(amount, transferRate(view, amount.get().getMptID())); + actual += actualSend; + takeFromSender += actualSend; + + JLOG(j.debug()) << "rippleSendMultiMPT> " << to_string(senderID) << " - > " << to_string(receiverID) + << " : deliver=" << amount.getFullText() << " cost=" << actualSend.getFullText(); + + if (auto const terResult = rippleCreditMPT(view, issuer, receiverID, amount, j)) + return terResult; + } + if (senderID != issuer && takeFromSender) + { + if (TER const terResult = rippleCreditMPT(view, senderID, issuer, takeFromSender, j)) + return terResult; + } + + return tesSUCCESS; +} + static TER accountSendMPT( ApplyView& view, @@ -2172,9 +2416,7 @@ accountSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - XRPL_ASSERT( - saAmount >= beast::zero && saAmount.holds(), - "ripple::accountSendMPT : minimum amount and MPT"); + XRPL_ASSERT(saAmount >= beast::zero && saAmount.holds(), "xrpl::accountSendMPT : minimum amount and MPT"); /* If we aren't sending anything or if the sender is the same as the * receiver then we don't need to do anything. @@ -2184,8 +2426,21 @@ accountSendMPT( STAmount saActual{saAmount.asset()}; - return rippleSendMPT( - view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); + return rippleSendMPT(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); +} + +static TER +accountSendMultiMPT( + ApplyView& view, + AccountID const& senderID, + MPTIssue const& mptIssue, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + STAmount actual; + + return rippleSendMultiMPT(view, senderID, mptIssue, receivers, actual, j, waiveFee); } TER @@ -2200,15 +2455,33 @@ accountSend( return std::visit( [&](TIss const& issue) { if constexpr (std::is_same_v) - return accountSendIOU( - view, uSenderID, uReceiverID, saAmount, j, waiveFee); + return accountSendIOU(view, uSenderID, uReceiverID, saAmount, j, waiveFee); else - return accountSendMPT( - view, uSenderID, uReceiverID, saAmount, j, waiveFee); + return accountSendMPT(view, uSenderID, uReceiverID, saAmount, j, waiveFee); }, saAmount.asset().value()); } +TER +accountSendMulti( + ApplyView& view, + AccountID const& senderID, + Asset const& asset, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT_PARTS(receivers.size() > 1, "xrpl::accountSendMulti", "multiple recipients provided"); + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + return accountSendMultiIOU(view, senderID, issue, receivers, j, waiveFee); + else + return accountSendMultiMPT(view, senderID, issue, receivers, j, waiveFee); + }, + asset.value()); +} + static bool updateTrustLine( ApplyView& view, @@ -2234,16 +2507,14 @@ updateTrustLine( // Sender is zero or negative. && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) // Sender reserve is set. - && static_cast( - flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != + && static_cast(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != static_cast(sle->getFlags() & lsfDefaultRipple) && !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) // Sender trust limit is 0. && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) // Sender quality in is 0. - && - !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) + && !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) // Sender quality out is 0. { // VFALCO Where is the line being deleted? @@ -2251,8 +2522,7 @@ updateTrustLine( adjustOwnerCount(view, sle, -1, j); // Clear reserve flag. - state->setFieldU32( - sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); + state->setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); // Balance is zero, receiver reserve is clear. if (!after // Balance is zero. @@ -2263,26 +2533,17 @@ updateTrustLine( } TER -issueIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j) +issueIOU(ApplyView& view, AccountID const& account, STAmount const& amount, Issue const& issue, beast::Journal j) { - XRPL_ASSERT( - !isXRP(account) && !isXRP(issue.account), - "ripple::issueIOU : neither account nor issuer is XRP"); + XRPL_ASSERT(!isXRP(account) && !isXRP(issue.account), "xrpl::issueIOU : neither account nor issuer is XRP"); // Consistency check - XRPL_ASSERT(issue == amount.issue(), "ripple::issueIOU : matching issue"); + XRPL_ASSERT(issue == amount.issue(), "xrpl::issueIOU : matching issue"); // Can't send to self! - XRPL_ASSERT( - issue.account != account, "ripple::issueIOU : not issuer account"); + XRPL_ASSERT(issue.account != account, "xrpl::issueIOU : not issuer account"); - JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " - << amount.getFullText(); + JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " << amount.getFullText(); bool bSenderHigh = issue.account > account; @@ -2299,14 +2560,8 @@ issueIOU( final_balance -= amount; - auto const must_delete = updateTrustLine( - view, - state, - bSenderHigh, - issue.account, - start_balance, - final_balance, - j); + auto const must_delete = + updateTrustLine(view, state, bSenderHigh, issue.account, start_balance, final_balance, j); view.creditHook(issue.account, account, amount, start_balance); @@ -2319,11 +2574,7 @@ issueIOU( state->setFieldAmount(sfBalance, final_balance); if (must_delete) return trustDelete( - view, - state, - bSenderHigh ? account : issue.account, - bSenderHigh ? issue.account : account, - j); + view, state, bSenderHigh ? account : issue.account, bSenderHigh ? issue.account : account, j); view.update(state); @@ -2363,31 +2614,21 @@ issueIOU( } TER -redeemIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j) +redeemIOU(ApplyView& view, AccountID const& account, STAmount const& amount, Issue const& issue, beast::Journal j) { - XRPL_ASSERT( - !isXRP(account) && !isXRP(issue.account), - "ripple::redeemIOU : neither account nor issuer is XRP"); + XRPL_ASSERT(!isXRP(account) && !isXRP(issue.account), "xrpl::redeemIOU : neither account nor issuer is XRP"); // Consistency check - XRPL_ASSERT(issue == amount.issue(), "ripple::redeemIOU : matching issue"); + XRPL_ASSERT(issue == amount.issue(), "xrpl::redeemIOU : matching issue"); // Can't send to self! - XRPL_ASSERT( - issue.account != account, "ripple::redeemIOU : not issuer account"); + XRPL_ASSERT(issue.account != account, "xrpl::redeemIOU : not issuer account"); - JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " - << amount.getFullText(); + JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " << amount.getFullText(); bool bSenderHigh = account > issue.account; - if (auto state = - view.peek(keylet::line(account, issue.account, issue.currency))) + if (auto state = view.peek(keylet::line(account, issue.account, issue.currency))) { STAmount final_balance = state->getFieldAmount(sfBalance); @@ -2398,8 +2639,7 @@ redeemIOU( final_balance -= amount; - auto const must_delete = updateTrustLine( - view, state, bSenderHigh, account, start_balance, final_balance, j); + auto const must_delete = updateTrustLine(view, state, bSenderHigh, account, start_balance, final_balance, j); view.creditHook(account, issue.account, amount, start_balance); @@ -2414,11 +2654,7 @@ redeemIOU( if (must_delete) { return trustDelete( - view, - state, - bSenderHigh ? issue.account : account, - bSenderHigh ? account : issue.account, - j); + view, state, bSenderHigh ? issue.account : account, bSenderHigh ? account : issue.account, j); } view.update(state); @@ -2429,8 +2665,7 @@ redeemIOU( // balance. If it doesn't, then something is very wrong. Don't try // to continue. // LCOV_EXCL_START - JLOG(j.fatal()) << "redeemIOU: " << to_string(account) - << " attempts to redeem " << amount.getFullText() + JLOG(j.fatal()) << "redeemIOU: " << to_string(account) << " attempts to redeem " << amount.getFullText() << " but no trust line exists!"; return tefINTERNAL; @@ -2438,26 +2673,19 @@ redeemIOU( } TER -transferXRP( - ApplyView& view, - AccountID const& from, - AccountID const& to, - STAmount const& amount, - beast::Journal j) +transferXRP(ApplyView& view, AccountID const& from, AccountID const& to, STAmount const& amount, beast::Journal j) { - XRPL_ASSERT( - from != beast::zero, "ripple::transferXRP : nonzero from account"); - XRPL_ASSERT(to != beast::zero, "ripple::transferXRP : nonzero to account"); - XRPL_ASSERT(from != to, "ripple::transferXRP : sender is not receiver"); - XRPL_ASSERT(amount.native(), "ripple::transferXRP : amount is XRP"); + XRPL_ASSERT(from != beast::zero, "xrpl::transferXRP : nonzero from account"); + XRPL_ASSERT(to != beast::zero, "xrpl::transferXRP : nonzero to account"); + XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver"); + XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP"); SLE::pointer const sender = view.peek(keylet::account(from)); SLE::pointer const receiver = view.peek(keylet::account(to)); if (!sender || !receiver) return tefINTERNAL; // LCOV_EXCL_LINE - JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> " - << to_string(to) << ") : " << amount.getFullText(); + JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> " << to_string(to) << ") : " << amount.getFullText(); if (sender->getFieldAmount(sfBalance) < amount) { @@ -2465,35 +2693,27 @@ transferXRP( // mutating these TER everywhere // FIXME: this logic should be moved to callers maybe? // LCOV_EXCL_START - return view.open() ? TER{telFAILED_PROCESSING} - : TER{tecFAILED_PROCESSING}; + return view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; // LCOV_EXCL_STOP } // Decrement XRP balance. - sender->setFieldAmount( - sfBalance, sender->getFieldAmount(sfBalance) - amount); + sender->setFieldAmount(sfBalance, sender->getFieldAmount(sfBalance) - amount); view.update(sender); - receiver->setFieldAmount( - sfBalance, receiver->getFieldAmount(sfBalance) + amount); + receiver->setFieldAmount(sfBalance, receiver->getFieldAmount(sfBalance) + amount); view.update(receiver); return tesSUCCESS; } TER -requireAuth( - ReadView const& view, - Issue const& issue, - AccountID const& account, - AuthType authType) +requireAuth(ReadView const& view, Issue const& issue, AccountID const& account, AuthType authType) { if (isXRP(issue) || issue.account == account) return tesSUCCESS; - auto const trustLine = - view.read(keylet::line(account, issue.account, issue.currency)); + auto const trustLine = view.read(keylet::line(account, issue.account, issue.currency)); // If account has no line, and this is a strong check, fail if (!trustLine && authType == AuthType::StrongAuth) return tecNO_LINE; @@ -2504,10 +2724,8 @@ requireAuth( issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth) { if (trustLine) - return ((*trustLine)[sfFlags] & - ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) - ? tesSUCCESS - : TER{tecNO_AUTH}; + return ((*trustLine)[sfFlags] & ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) ? tesSUCCESS + : TER{tecNO_AUTH}; return TER{tecNO_LINE}; } @@ -2515,12 +2733,7 @@ requireAuth( } TER -requireAuth( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& account, - AuthType authType, - int depth) +requireAuth(ReadView const& view, MPTIssue const& mptIssue, AccountID const& account, AuthType authType, int depth) { auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); auto const sleIssuance = view.read(mptID); @@ -2533,7 +2746,9 @@ requireAuth( if (mptIssuer == account) // Issuer won't have MPToken return tesSUCCESS; - if (view.rules().enabled(featureSingleAssetVault)) + bool const featureSAVEnabled = view.rules().enabled(featureSingleAssetVault); + + if (featureSAVEnabled) { if (depth >= maxAssetCheckDepth) return tecINTERNAL; // LCOV_EXCL_LINE @@ -2545,8 +2760,7 @@ requireAuth( if (sleIssuer->isFieldPresent(sfVaultID)) { - auto const sleVault = - view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID))); + auto const sleVault = view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID))); if (!sleVault) return tefINTERNAL; // LCOV_EXCL_LINE @@ -2556,8 +2770,7 @@ requireAuth( if constexpr (std::is_same_v) return requireAuth(view, issue, account, authType); else - return requireAuth( - view, issue, account, authType, depth + 1); + return requireAuth(view, issue, account, authType, depth + 1); }, asset.value()); !isTesSuccess(err)) @@ -2569,8 +2782,7 @@ requireAuth( auto const sleToken = view.read(mptokenID); // if account has no MPToken, fail - if (!sleToken && - (authType == AuthType::StrongAuth || authType == AuthType::Legacy)) + if (!sleToken && (authType == AuthType::StrongAuth || authType == AuthType::Legacy)) return tecNO_AUTH; // Note, this check is not amendment-gated because DomainID will be always @@ -2580,11 +2792,9 @@ requireAuth( { XRPL_ASSERT( sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth, - "ripple::requireAuth : issuance requires authorization"); + "xrpl::requireAuth : issuance requires authorization"); // ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED - if (auto const ter = - credentials::validDomain(view, *maybeDomainID, account); - isTesSuccess(ter)) + if (auto const ter = credentials::validDomain(view, *maybeDomainID, account); isTesSuccess(ter)) return ter; // Note: sleToken might be null else if (!sleToken) return ter; @@ -2592,9 +2802,15 @@ requireAuth( // belong to someone who is explicitly authorized e.g. a vault owner. } + if (featureSAVEnabled) + { + // Implicitly authorize Vault and LoanBroker pseudo-accounts + if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID})) + return tesSUCCESS; + } + // mptoken must be authorized if issuance enabled requireAuth - if (sleIssuance->isFlag(lsfMPTRequireAuth) && - (!sleToken || !sleToken->isFlag(lsfMPTAuthorized))) + if (sleIssuance->isFlag(lsfMPTRequireAuth) && (!sleToken || !sleToken->isFlag(lsfMPTAuthorized))) return tecNO_AUTH; return tesSUCCESS; // Note: sleToken might be null @@ -2612,9 +2828,7 @@ enforceMPTokenAuthorization( if (!sleIssuance) return tefINTERNAL; // LCOV_EXCL_LINE - XRPL_ASSERT( - sleIssuance->isFlag(lsfMPTRequireAuth), - "ripple::enforceMPTokenAuthorization : authorization required"); + XRPL_ASSERT(sleIssuance->isFlag(lsfMPTRequireAuth), "xrpl::enforceMPTokenAuthorization : authorization required"); if (account == sleIssuance->at(sfIssuer)) return tefINTERNAL; // LCOV_EXCL_LINE @@ -2624,7 +2838,7 @@ enforceMPTokenAuthorization( auto const maybeDomainID = sleIssuance->at(~sfDomainID); bool expired = false; bool const authorizedByDomain = [&]() -> bool { - // NOTE: defensive here, shuld be checked in preclaim + // NOTE: defensive here, should be checked in preclaim if (!maybeDomainID.has_value()) return false; // LCOV_EXCL_LINE @@ -2659,8 +2873,7 @@ enforceMPTokenAuthorization( // We found an MPToken, but sfDomainID is not set, so this is a classic // MPToken which requires authorization by the token issuer. XRPL_ASSERT( - sleToken != nullptr && !maybeDomainID.has_value(), - "ripple::enforceMPTokenAuthorization : found MPToken"); + sleToken != nullptr && !maybeDomainID.has_value(), "xrpl::enforceMPTokenAuthorization : found MPToken"); if (sleToken->isFlag(lsfMPTAuthorized)) return tesSUCCESS; @@ -2670,9 +2883,7 @@ enforceMPTokenAuthorization( { // Found an MPToken, authorized by the domain. Ignore authorization flag // lsfMPTAuthorized because it is meaningless. Return tesSUCCESS - XRPL_ASSERT( - maybeDomainID.has_value(), - "ripple::enforceMPTokenAuthorization : found MPToken for domain"); + XRPL_ASSERT(maybeDomainID.has_value(), "xrpl::enforceMPTokenAuthorization : found MPToken for domain"); return tesSUCCESS; } else if (authorizedByDomain) @@ -2681,7 +2892,7 @@ enforceMPTokenAuthorization( // authorized by domain. Proceed to create it, then return tesSUCCESS XRPL_ASSERT( maybeDomainID.has_value() && sleToken == nullptr, - "ripple::enforceMPTokenAuthorization : new MPToken for domain"); + "xrpl::enforceMPTokenAuthorization : new MPToken for domain"); if (auto const err = authorizeMPToken( view, priorBalance, // priorBalance @@ -2695,18 +2906,13 @@ enforceMPTokenAuthorization( } // LCOV_EXCL_START - UNREACHABLE( - "ripple::enforceMPTokenAuthorization : condition list is incomplete"); + UNREACHABLE("xrpl::enforceMPTokenAuthorization : condition list is incomplete"); return tefINTERNAL; // LCOV_EXCL_STOP } TER -canTransfer( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& from, - AccountID const& to) +canTransfer(ReadView const& view, MPTIssue const& mptIssue, AccountID const& from, AccountID const& to) { auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); auto const sleIssuance = view.read(mptID); @@ -2721,6 +2927,38 @@ canTransfer( return tesSUCCESS; } +[[nodiscard]] TER +canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to) +{ + if (issue.native()) + return tesSUCCESS; + + auto const& issuerId = issue.getIssuer(); + if (issuerId == from || issuerId == to) + return tesSUCCESS; + auto const sleIssuer = view.read(keylet::account(issuerId)); + if (sleIssuer == nullptr) + return tefINTERNAL; // LCOV_EXCL_LINE + + auto const isRippleDisabled = [&](AccountID account) -> bool { + // Line might not exist, but some transfers can create it. If this + // is the case, just check the default ripple on the issuer account. + auto const line = view.read(keylet::line(account, issue)); + if (line) + { + bool const issuerHigh = issuerId > account; + return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple); + } + return sleIssuer->isFlag(lsfDefaultRipple) == false; + }; + + // Fail if rippling disabled on both trust lines + if (isRippleDisabled(from) && isRippleDisabled(to)) + return terNO_RIPPLE; + + return tesSUCCESS; +} + TER cleanupOnAccountDelete( ApplyView& view, @@ -2735,8 +2973,7 @@ cleanupOnAccountDelete( uint256 dirEntry{beast::zero}; std::uint32_t deleted = 0; - if (view.exists(ownerDirKeylet) && - dirFirst(view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry)) + if (view.exists(ownerDirKeylet) && dirFirst(view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry)) { do { @@ -2749,16 +2986,13 @@ cleanupOnAccountDelete( { // Directory node has an invalid index. Bail out. // LCOV_EXCL_START - JLOG(j.fatal()) - << "DeleteAccount: Directory node in ledger " << view.seq() - << " has index to object that is missing: " - << to_string(dirEntry); + JLOG(j.fatal()) << "DeleteAccount: Directory node in ledger " << view.seq() + << " has index to object that is missing: " << to_string(dirEntry); return tefBAD_LEDGER; // LCOV_EXCL_STOP } - LedgerEntryType const nodeType{safe_cast( - sleItem->getFieldU16(sfLedgerEntryType))}; + LedgerEntryType const nodeType{safe_cast(sleItem->getFieldU16(sfLedgerEntryType))}; // Deleter handles the details of specific account-owned object // deletion @@ -2782,22 +3016,18 @@ cleanupOnAccountDelete( // // 3. So we verify that uDirEntry is indeed 'it'+1. Then we jam it // back to 'it' to "un-invalidate" the iterator. - XRPL_ASSERT( - uDirEntry >= 1, - "ripple::cleanupOnAccountDelete : minimum dir entries"); + XRPL_ASSERT(uDirEntry >= 1, "xrpl::cleanupOnAccountDelete : minimum dir entries"); if (uDirEntry == 0) { // LCOV_EXCL_START - JLOG(j.error()) - << "DeleteAccount iterator re-validation failed."; + JLOG(j.error()) << "DeleteAccount iterator re-validation failed."; return tefBAD_LEDGER; // LCOV_EXCL_STOP } if (skipEntry == SkipEntry::No) uDirEntry--; - } while ( - dirNext(view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry)); + } while (dirNext(view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry)); } return tesSUCCESS; @@ -2814,8 +3044,7 @@ deleteAMMTrustLine( return tecINTERNAL; // LCOV_EXCL_LINE auto const& [low, high] = std::minmax( - sleState->getFieldAmount(sfLowLimit).getIssuer(), - sleState->getFieldAmount(sfHighLimit).getIssuer()); + sleState->getFieldAmount(sfLowLimit).getIssuer(), sleState->getFieldAmount(sfHighLimit).getIssuer()); auto sleLow = view.peek(keylet::account(low)); auto sleHigh = view.peek(keylet::account(high)); if (!sleLow || !sleHigh) @@ -2836,11 +3065,9 @@ deleteAMMTrustLine( if (ammAccountID && (low != *ammAccountID && high != *ammAccountID)) return terNO_AMM; - if (auto const ter = trustDelete(view, sleState, low, high, j); - ter != tesSUCCESS) + if (auto const ter = trustDelete(view, sleState, low, high, j); ter != tesSUCCESS) { - JLOG(j.error()) - << "deleteAMMTrustLine: failed to delete the trustline."; + JLOG(j.error()) << "deleteAMMTrustLine: failed to delete the trustline."; return ter; } @@ -2866,16 +3093,12 @@ rippleCredit( [&](TIss const& issue) { if constexpr (std::is_same_v) { - return rippleCreditIOU( - view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j); + return rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j); } else { - XRPL_ASSERT( - !bCheckIssuer, - "ripple::rippleCredit : not checking issuer"); - return rippleCreditMPT( - view, uSenderID, uReceiverID, saAmount, j); + XRPL_ASSERT(!bCheckIssuer, "xrpl::rippleCredit : not checking issuer"); + return rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); } }, saAmount.asset().value()); @@ -2887,25 +3110,18 @@ assetsToSharesDeposit( std::shared_ptr const& issuance, STAmount const& assets) { - XRPL_ASSERT( - !assets.negative(), - "ripple::assetsToSharesDeposit : non-negative assets"); - XRPL_ASSERT( - assets.asset() == vault->at(sfAsset), - "ripple::assetsToSharesDeposit : assets and vault match"); + XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets"); + XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesDeposit : assets and vault match"); if (assets.negative() || assets.asset() != vault->at(sfAsset)) return std::nullopt; // LCOV_EXCL_LINE Number const assetTotal = vault->at(sfAssetsTotal); STAmount shares{vault->at(sfShareMPTID)}; if (assetTotal == 0) - return STAmount{ - shares.asset(), - Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)) - .truncate()}; + return STAmount{shares.asset(), Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()}; Number const shareTotal = issuance->at(sfOutstandingAmount); - shares = (shareTotal * (assets / assetTotal)).truncate(); + shares = ((shareTotal * assets) / assetTotal).truncate(); return shares; } @@ -2915,26 +3131,18 @@ sharesToAssetsDeposit( std::shared_ptr const& issuance, STAmount const& shares) { - XRPL_ASSERT( - !shares.negative(), - "ripple::sharesToAssetsDeposit : non-negative shares"); - XRPL_ASSERT( - shares.asset() == vault->at(sfShareMPTID), - "ripple::sharesToAssetsDeposit : shares and vault match"); + XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); + XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsDeposit : shares and vault match"); if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) return std::nullopt; // LCOV_EXCL_LINE Number const assetTotal = vault->at(sfAssetsTotal); STAmount assets{vault->at(sfAsset)}; if (assetTotal == 0) - return STAmount{ - assets.asset(), - shares.mantissa(), - shares.exponent() - vault->at(sfScale), - false}; + return STAmount{assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false}; Number const shareTotal = issuance->at(sfOutstandingAmount); - assets = assetTotal * (shares / shareTotal); + assets = (assetTotal * shares) / shareTotal; return assets; } @@ -2945,12 +3153,8 @@ assetsToSharesWithdraw( STAmount const& assets, TruncateShares truncate) { - XRPL_ASSERT( - !assets.negative(), - "ripple::assetsToSharesDeposit : non-negative assets"); - XRPL_ASSERT( - assets.asset() == vault->at(sfAsset), - "ripple::assetsToSharesWithdraw : assets and vault match"); + XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets"); + XRPL_ASSERT(assets.asset() == vault->at(sfAsset), "xrpl::assetsToSharesWithdraw : assets and vault match"); if (assets.negative() || assets.asset() != vault->at(sfAsset)) return std::nullopt; // LCOV_EXCL_LINE @@ -2960,7 +3164,7 @@ assetsToSharesWithdraw( if (assetTotal == 0) return shares; Number const shareTotal = issuance->at(sfOutstandingAmount); - Number result = shareTotal * (assets / assetTotal); + Number result = (shareTotal * assets) / assetTotal; if (truncate == TruncateShares::yes) result = result.truncate(); shares = result; @@ -2973,12 +3177,8 @@ sharesToAssetsWithdraw( std::shared_ptr const& issuance, STAmount const& shares) { - XRPL_ASSERT( - !shares.negative(), - "ripple::sharesToAssetsDeposit : non-negative shares"); - XRPL_ASSERT( - shares.asset() == vault->at(sfShareMPTID), - "ripple::sharesToAssetsWithdraw : shares and vault match"); + XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); + XRPL_ASSERT(shares.asset() == vault->at(sfShareMPTID), "xrpl::sharesToAssetsWithdraw : shares and vault match"); if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) return std::nullopt; // LCOV_EXCL_LINE @@ -2988,31 +3188,25 @@ sharesToAssetsWithdraw( if (assetTotal == 0) return assets; Number const shareTotal = issuance->at(sfOutstandingAmount); - assets = assetTotal * (shares / shareTotal); + assets = (assetTotal * shares) / shareTotal; return assets; } TER -rippleLockEscrowMPT( - ApplyView& view, - AccountID const& sender, - STAmount const& amount, - beast::Journal j) +rippleLockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount, beast::Journal j) { auto const mptIssue = amount.get(); auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); auto sleIssuance = view.peek(mptID); if (!sleIssuance) { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: MPT issuance not found for " - << mptIssue.getMptID(); + JLOG(j.error()) << "rippleLockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID(); return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP if (amount.getIssuer() == sender) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs."; + JLOG(j.error()) << "rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs."; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3023,8 +3217,7 @@ rippleLockEscrowMPT( auto sle = view.peek(mptokenID); if (!sle) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleLockEscrowMPT: MPToken not found for " << sender; + JLOG(j.error()) << "rippleLockEscrowMPT: MPToken not found for " << sender; return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP @@ -3034,9 +3227,8 @@ rippleLockEscrowMPT( // Underflow check for subtraction if (!canSubtract(STAmount(mptIssue, amt), STAmount(mptIssue, pay))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleLockEscrowMPT: insufficient MPTAmount for " - << to_string(sender) << ": " << amt << " < " << pay; + JLOG(j.error()) << "rippleLockEscrowMPT: insufficient MPTAmount for " << to_string(sender) << ": " << amt + << " < " << pay; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3047,9 +3239,8 @@ rippleLockEscrowMPT( if (!canAdd(STAmount(mptIssue, locked), STAmount(mptIssue, pay))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleLockEscrowMPT: overflow on locked amount for " - << to_string(sender) << ": " << locked << " + " << pay; + JLOG(j.error()) << "rippleLockEscrowMPT: overflow on locked amount for " << to_string(sender) << ": " + << locked << " + " << pay; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3064,18 +3255,15 @@ rippleLockEscrowMPT( // 1. Increase the Issuance EscrowedAmount // 2. DO NOT change the Issuance OutstandingAmount { - uint64_t const issuanceEscrowed = - (*sleIssuance)[~sfLockedAmount].value_or(0); + uint64_t const issuanceEscrowed = (*sleIssuance)[~sfLockedAmount].value_or(0); auto const pay = amount.mpt().value(); // Overflow check for addition - if (!canAdd( - STAmount(mptIssue, issuanceEscrowed), STAmount(mptIssue, pay))) + if (!canAdd(STAmount(mptIssue, issuanceEscrowed), STAmount(mptIssue, pay))) { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: overflow on issuance " "locked amount for " - << mptIssue.getMptID() << ": " << issuanceEscrowed - << " + " << pay; + << mptIssue.getMptID() << ": " << issuanceEscrowed << " + " << pay; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3099,9 +3287,7 @@ rippleUnlockEscrowMPT( beast::Journal j) { if (!view.rules().enabled(fixTokenEscrowV1)) - XRPL_ASSERT( - netAmount == grossAmount, - "ripple::rippleUnlockEscrowMPT : netAmount == grossAmount"); + XRPL_ASSERT(netAmount == grossAmount, "xrpl::rippleUnlockEscrowMPT : netAmount == grossAmount"); auto const& issuer = netAmount.getIssuer(); auto const& mptIssue = netAmount.get(); @@ -3109,8 +3295,7 @@ rippleUnlockEscrowMPT( auto sleIssuance = view.peek(mptID); if (!sleIssuance) { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: MPT issuance not found for " - << mptIssue.getMptID(); + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID(); return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP @@ -3118,9 +3303,7 @@ rippleUnlockEscrowMPT( { if (!sleIssuance->isFieldPresent(sfLockedAmount)) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: no locked amount in issuance for " - << mptIssue.getMptID(); + JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in issuance for " << mptIssue.getMptID(); return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3128,12 +3311,10 @@ rippleUnlockEscrowMPT( auto const redeem = grossAmount.mpt().value(); // Underflow check for subtraction - if (!canSubtract( - STAmount(mptIssue, locked), STAmount(mptIssue, redeem))) + if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, redeem))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: insufficient locked amount for " - << mptIssue.getMptID() << ": " << locked << " < " << redeem; + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " << mptIssue.getMptID() << ": " + << locked << " < " << redeem; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3152,8 +3333,7 @@ rippleUnlockEscrowMPT( auto sle = view.peek(mptokenID); if (!sle) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP @@ -3163,9 +3343,8 @@ rippleUnlockEscrowMPT( // Overflow check for addition if (!canAdd(STAmount(mptIssue, current), STAmount(mptIssue, delta))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: overflow on MPTAmount for " - << to_string(receiver) << ": " << current << " + " << delta; + JLOG(j.error()) << "rippleUnlockEscrowMPT: overflow on MPTAmount for " << to_string(receiver) << ": " + << current << " + " << delta; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3179,13 +3358,10 @@ rippleUnlockEscrowMPT( auto const redeem = netAmount.mpt().value(); // Underflow check for subtraction - if (!canSubtract( - STAmount(mptIssue, outstanding), STAmount(mptIssue, redeem))) + if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, redeem))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: insufficient outstanding amount for " - << mptIssue.getMptID() << ": " << outstanding << " < " - << redeem; + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " << mptIssue.getMptID() + << ": " << outstanding << " < " << redeem; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3206,16 +3382,13 @@ rippleUnlockEscrowMPT( auto sle = view.peek(mptokenID); if (!sle) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: MPToken not found for " << sender; + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << sender; return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP if (!sle->isFieldPresent(sfLockedAmount)) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: no locked amount in MPToken for " - << to_string(sender); + JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in MPToken for " << to_string(sender); return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3225,9 +3398,8 @@ rippleUnlockEscrowMPT( // Underflow check for subtraction if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, delta))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: insufficient locked amount for " - << to_string(sender) << ": " << locked << " < " << delta; + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " << to_string(sender) << ": " + << locked << " < " << delta; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3248,12 +3420,10 @@ rippleUnlockEscrowMPT( { auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); // Underflow check for subtraction - if (!canSubtract( - STAmount(mptIssue, outstanding), STAmount(mptIssue, diff))) + if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, diff))) { // LCOV_EXCL_START - JLOG(j.error()) - << "rippleUnlockEscrowMPT: insufficient outstanding amount for " - << mptIssue.getMptID() << ": " << outstanding << " < " << diff; + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " << mptIssue.getMptID() + << ": " << outstanding << " < " << diff; return tecINTERNAL; } // LCOV_EXCL_STOP @@ -3269,4 +3439,4 @@ after(NetClock::time_point now, std::uint32_t mark) return now.time_since_epoch().count() > mark; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/net/HTTPClient.cpp b/src/libxrpl/net/HTTPClient.cpp index 74b8b61ca6..e5a1196cb0 100644 --- a/src/libxrpl/net/HTTPClient.cpp +++ b/src/libxrpl/net/HTTPClient.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,7 +12,7 @@ #include -namespace ripple { +namespace xrpl { static std::optional httpClientSSLContext; @@ -51,8 +32,7 @@ HTTPClient::initializeSSLContext( // //------------------------------------------------------------------------------ -class HTTPClientImp : public std::enable_shared_from_this, - public HTTPClient +class HTTPClientImp : public std::enable_shared_from_this, public HTTPClient { public: HTTPClientImp( @@ -73,10 +53,7 @@ public: //-------------------------------------------------------------------------- void - makeGet( - std::string const& strPath, - boost::asio::streambuf& sb, - std::string const& strHost) + makeGet(std::string const& strPath, boost::asio::streambuf& sb, std::string const& strHost) { std::ostream osRequest(&sb); @@ -95,13 +72,10 @@ public: request( bool bSSL, std::deque deqSites, - std::function< - void(boost::asio::streambuf& sb, std::string const& strHost)> build, + std::function build, std::chrono::seconds timeout, - std::function complete) + std::function + complete) { mSSL = bSSL; mDeqSites = deqSites; @@ -119,10 +93,8 @@ public: std::deque deqSites, std::string const& strPath, std::chrono::seconds timeout, - std::function complete) + std::function + complete) { mComplete = complete; mTimeout = timeout; @@ -131,11 +103,7 @@ public: bSSL, deqSites, std::bind( - &HTTPClientImp::makeGet, - shared_from_this(), - strPath, - std::placeholders::_1, - std::placeholders::_2), + &HTTPClientImp::makeGet, shared_from_this(), strPath, std::placeholders::_1, std::placeholders::_2), timeout, complete); } @@ -148,9 +116,7 @@ public: JLOG(j_.trace()) << "Fetch: " << mDeqSites[0]; auto query = std::make_shared( - mDeqSites[0], - std::to_string(mPort), - boost::asio::ip::resolver_query_base::numeric_service); + mDeqSites[0], std::to_string(mPort), boost::asio::ip::resolver_query_base::numeric_service); mQuery = query; try @@ -162,10 +128,7 @@ public: mShutdown = e.code(); JLOG(j_.trace()) << "expires_after: " << mShutdown.message(); - mDeadline.async_wait(std::bind( - &HTTPClientImp::handleDeadline, - shared_from_this(), - std::placeholders::_1)); + mDeadline.async_wait(std::bind(&HTTPClientImp::handleDeadline, shared_from_this(), std::placeholders::_1)); } if (!mShutdown) @@ -177,10 +140,7 @@ public: mQuery->port, mQuery->flags, std::bind( - &HTTPClientImp::handleResolve, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); + &HTTPClientImp::handleResolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } if (mShutdown) @@ -199,8 +159,7 @@ public: } else if (ecResult) { - JLOG(j_.trace()) << "Deadline error: " << mDeqSites[0] << ": " - << ecResult.message(); + JLOG(j_.trace()) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message(); // Can't do anything sound. abort(); @@ -211,18 +170,14 @@ public: // Mark us as shutting down. // XXX Use our own error code. - mShutdown = boost::system::error_code{ - boost::system::errc::bad_address, - boost::system::system_category()}; + mShutdown = boost::system::error_code{boost::system::errc::bad_address, boost::system::system_category()}; // Cancel any resolving. mResolver.cancel(); // Stop the transaction. - mSocket.async_shutdown(std::bind( - &HTTPClientImp::handleShutdown, - shared_from_this(), - std::placeholders::_1)); + mSocket.async_shutdown( + std::bind(&HTTPClientImp::handleShutdown, shared_from_this(), std::placeholders::_1)); } } @@ -231,27 +186,21 @@ public: { if (ecResult) { - JLOG(j_.trace()) << "Shutdown error: " << mDeqSites[0] << ": " - << ecResult.message(); + JLOG(j_.trace()) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message(); } } void - handleResolve( - boost::system::error_code const& ecResult, - boost::asio::ip::tcp::resolver::results_type result) + handleResolve(boost::system::error_code const& ecResult, boost::asio::ip::tcp::resolver::results_type result) { if (!mShutdown) { - mShutdown = ecResult ? ecResult - : httpClientSSLContext->preConnectVerify( - mSocket.SSLSocket(), mDeqSites[0]); + mShutdown = ecResult ? ecResult : httpClientSSLContext->preConnectVerify(mSocket.SSLSocket(), mDeqSites[0]); } if (mShutdown) { - JLOG(j_.trace()) << "Resolve error: " << mDeqSites[0] << ": " - << mShutdown.message(); + JLOG(j_.trace()) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message(); invokeComplete(mShutdown); } @@ -262,10 +211,7 @@ public: boost::asio::async_connect( mSocket.lowest_layer(), result, - std::bind( - &HTTPClientImp::handleConnect, - shared_from_this(), - std::placeholders::_1)); + std::bind(&HTTPClientImp::handleConnect, shared_from_this(), std::placeholders::_1)); } } @@ -284,13 +230,11 @@ public: { JLOG(j_.trace()) << "Connected."; - mShutdown = httpClientSSLContext->postConnectVerify( - mSocket.SSLSocket(), mDeqSites[0]); + mShutdown = httpClientSSLContext->postConnectVerify(mSocket.SSLSocket(), mDeqSites[0]); if (mShutdown) { - JLOG(j_.trace()) << "postConnectVerify: " << mDeqSites[0] - << ": " << mShutdown.message(); + JLOG(j_.trace()) << "postConnectVerify: " << mDeqSites[0] << ": " << mShutdown.message(); } } @@ -302,10 +246,7 @@ public: { mSocket.async_handshake( AutoSocket::ssl_socket::client, - std::bind( - &HTTPClientImp::handleRequest, - shared_from_this(), - std::placeholders::_1)); + std::bind(&HTTPClientImp::handleRequest, shared_from_this(), std::placeholders::_1)); } else { @@ -334,17 +275,12 @@ public: mSocket.async_write( mRequest, std::bind( - &HTTPClientImp::handleWrite, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); + &HTTPClientImp::handleWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } } void - handleWrite( - boost::system::error_code const& ecResult, - std::size_t bytes_transferred) + handleWrite(boost::system::error_code const& ecResult, std::size_t bytes_transferred) { if (!mShutdown) mShutdown = ecResult; @@ -363,27 +299,18 @@ public: mHeader, "\r\n\r\n", std::bind( - &HTTPClientImp::handleHeader, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); + &HTTPClientImp::handleHeader, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } } void - handleHeader( - boost::system::error_code const& ecResult, - std::size_t bytes_transferred) + handleHeader(boost::system::error_code const& ecResult, std::size_t bytes_transferred) { - std::string strHeader{ - {std::istreambuf_iterator(&mHeader)}, - std::istreambuf_iterator()}; + std::string strHeader{{std::istreambuf_iterator(&mHeader)}, std::istreambuf_iterator()}; JLOG(j_.trace()) << "Header: \"" << strHeader << "\""; - static boost::regex reStatus{ - "\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK - static boost::regex reSize{ - "\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'", boost::regex::icase}; + static boost::regex reStatus{"\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK + static boost::regex reSize{"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'", boost::regex::icase}; static boost::regex reBody{"\\`.*\\r\\n\\r\\n(.*)\\'"}; boost::smatch smMatch; @@ -392,9 +319,8 @@ public: { // XXX Use our own error code. JLOG(j_.trace()) << "No status code"; - invokeComplete(boost::system::error_code{ - boost::system::errc::bad_address, - boost::system::system_category()}); + invokeComplete( + boost::system::error_code{boost::system::errc::bad_address, boost::system::system_category()}); return; } @@ -405,17 +331,15 @@ public: std::size_t const responseSize = [&] { if (boost::regex_match(strHeader, smMatch, reSize)) - return beast::lexicalCast( - std::string(smMatch[1]), maxResponseSize_); + return beast::lexicalCast(std::string(smMatch[1]), maxResponseSize_); return maxResponseSize_; }(); if (responseSize > maxResponseSize_) { JLOG(j_.trace()) << "Response field too large"; - invokeComplete(boost::system::error_code{ - boost::system::errc::value_too_large, - boost::system::system_category()}); + invokeComplete( + boost::system::error_code{boost::system::errc::value_too_large, boost::system::system_category()}); return; } @@ -435,17 +359,12 @@ public: mResponse.prepare(responseSize - mBody.size()), boost::asio::transfer_all(), std::bind( - &HTTPClientImp::handleData, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); + &HTTPClientImp::handleData, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } } void - handleData( - boost::system::error_code const& ecResult, - std::size_t bytes_transferred) + handleData(boost::system::error_code const& ecResult, std::size_t bytes_transferred) { if (!mShutdown) mShutdown = ecResult; @@ -465,9 +384,7 @@ public: else { mResponse.commit(bytes_transferred); - std::string strBody{ - {std::istreambuf_iterator(&mResponse)}, - std::istreambuf_iterator()}; + std::string strBody{{std::istreambuf_iterator(&mResponse)}, std::istreambuf_iterator()}; invokeComplete(ecResult, mStatus, mBody + strBody); } } @@ -475,10 +392,7 @@ public: // Call cancel the deadline timer and invoke the completion routine. void - invokeComplete( - boost::system::error_code const& ecResult, - int iStatus = 0, - std::string const& strData = "") + invokeComplete(boost::system::error_code const& ecResult, int iStatus = 0, std::string const& strData = "") { boost::system::error_code ecCancel; try @@ -487,13 +401,11 @@ public: } catch (boost::system::system_error const& e) { - JLOG(j_.trace()) - << "invokeComplete: Deadline cancel error: " << e.what(); + JLOG(j_.trace()) << "invokeComplete: Deadline cancel error: " << e.what(); ecCancel = e.code(); } - JLOG(j_.debug()) << "invokeComplete: Deadline popping: " - << mDeqSites.size(); + JLOG(j_.debug()) << "invokeComplete: Deadline popping: " << mDeqSites.size(); if (!mDeqSites.empty()) { @@ -507,8 +419,7 @@ public: // ecResult: !0 = had an error, last entry // iStatus: result, if no error // strData: data, if no error - bAgain = mComplete && - mComplete(ecResult ? ecResult : ecCancel, iStatus, strData); + bAgain = mComplete && mComplete(ecResult ? ecResult : ecCancel, iStatus, strData); } if (!mDeqSites.empty() && bAgain) @@ -539,13 +450,8 @@ private: unsigned short const mPort; std::size_t const maxResponseSize_; int mStatus; - std::function - mBuild; - std::function - mComplete; + std::function mBuild; + std::function mComplete; boost::asio::basic_waitable_timer mDeadline; @@ -568,14 +474,10 @@ HTTPClient::get( std::string const& strPath, std::size_t responseMax, std::chrono::seconds timeout, - std::function complete, + std::function complete, beast::Journal& j) { - auto client = - std::make_shared(io_context, port, responseMax, j); + auto client = std::make_shared(io_context, port, responseMax, j); client->get(bSSL, deqSites, strPath, timeout, complete); } @@ -588,16 +490,12 @@ HTTPClient::get( std::string const& strPath, std::size_t responseMax, std::chrono::seconds timeout, - std::function complete, + std::function complete, beast::Journal& j) { std::deque deqSites(1, strSite); - auto client = - std::make_shared(io_context, port, responseMax, j); + auto client = std::make_shared(io_context, port, responseMax, j); client->get(bSSL, deqSites, strPath, timeout, complete); } @@ -607,21 +505,16 @@ HTTPClient::request( boost::asio::io_context& io_context, std::string strSite, unsigned short const port, - std::function - setRequest, + std::function setRequest, std::size_t responseMax, std::chrono::seconds timeout, - std::function complete, + std::function complete, beast::Journal& j) { std::deque deqSites(1, strSite); - auto client = - std::make_shared(io_context, port, responseMax, j); + auto client = std::make_shared(io_context, port, responseMax, j); client->request(bSSL, deqSites, setRequest, timeout, complete); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/net/RegisterSSLCerts.cpp b/src/libxrpl/net/RegisterSSLCerts.cpp index cd5bd631aa..a15472969e 100644 --- a/src/libxrpl/net/RegisterSSLCerts.cpp +++ b/src/libxrpl/net/RegisterSSLCerts.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #if BOOST_OS_WINDOWS @@ -32,53 +13,44 @@ #include #endif -namespace ripple { +namespace xrpl { void -registerSSLCerts( - boost::asio::ssl::context& ctx, - boost::system::error_code& ec, - beast::Journal j) +registerSSLCerts(boost::asio::ssl::context& ctx, boost::system::error_code& ec, beast::Journal j) { #if BOOST_OS_WINDOWS auto certStoreDelete = [](void* h) { if (h != nullptr) CertCloseStore(h, 0); }; - std::unique_ptr hStore{ - CertOpenSystemStore(0, "ROOT"), certStoreDelete}; + std::unique_ptr hStore{CertOpenSystemStore(0, "ROOT"), certStoreDelete}; if (!hStore) { - ec = boost::system::error_code( - GetLastError(), boost::system::system_category()); + ec = boost::system::error_code(GetLastError(), boost::system::system_category()); return; } ERR_clear_error(); - std::unique_ptr store{ - X509_STORE_new(), X509_STORE_free}; + std::unique_ptr store{X509_STORE_new(), X509_STORE_free}; if (!store) { - ec = boost::system::error_code( - static_cast(::ERR_get_error()), - boost::asio::error::get_ssl_category()); + ec = boost::system::error_code(static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category()); return; } - auto warn = [&](std::string const& mesg) { + auto warn = [&](std::string const& msg) { // Buffer based on asio recommended size char buf[256]; ::ERR_error_string_n(ec.value(), buf, sizeof(buf)); - JLOG(j.warn()) << mesg << " " << buf; + JLOG(j.warn()) << msg << " " << buf; ::ERR_clear_error(); }; PCCERT_CONTEXT pContext = NULL; - while ((pContext = CertEnumCertificatesInStore(hStore.get(), pContext)) != - NULL) + while ((pContext = CertEnumCertificatesInStore(hStore.get(), pContext)) != NULL) { unsigned char const* pbCertEncoded = pContext->pbCertEncoded; std::unique_ptr x509{ @@ -108,7 +80,7 @@ registerSSLCerts( #endif } -} // namespace ripple +} // namespace xrpl // There is a very unpleasant interaction between and // openssl x509 types (namely the former has macros that stomp diff --git a/src/libxrpl/nodestore/BatchWriter.cpp b/src/libxrpl/nodestore/BatchWriter.cpp index 14947b5d21..73213fe3ba 100644 --- a/src/libxrpl/nodestore/BatchWriter.cpp +++ b/src/libxrpl/nodestore/BatchWriter.cpp @@ -1,32 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace NodeStore { BatchWriter::BatchWriter(Callback& callback, Scheduler& scheduler) - : m_callback(callback) - , m_scheduler(scheduler) - , mWriteLoad(0) - , mWritePending(false) + : m_callback(callback), m_scheduler(scheduler), mWriteLoad(0), mWritePending(false) { mWriteSet.reserve(batchWritePreallocationSize); } @@ -83,9 +61,7 @@ BatchWriter::writeBatch() std::lock_guard sl(mWriteMutex); mWriteSet.swap(set); - XRPL_ASSERT( - mWriteSet.empty(), - "ripple::NodeStore::BatchWriter::writeBatch : writes not set"); + XRPL_ASSERT(mWriteSet.empty(), "xrpl::NodeStore::BatchWriter::writeBatch : writes not set"); mWriteLoad = set.size(); if (set.empty()) @@ -104,8 +80,8 @@ BatchWriter::writeBatch() m_callback.writeBatch(set); - report.elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - before); + report.elapsed = + std::chrono::duration_cast(std::chrono::steady_clock::now() - before); m_scheduler.onBatchWrite(report); } @@ -121,4 +97,4 @@ BatchWriter::waitForWriting() } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/Database.cpp b/src/libxrpl/nodestore/Database.cpp index 14f3299d1f..f393bf27c9 100644 --- a/src/libxrpl/nodestore/Database.cpp +++ b/src/libxrpl/nodestore/Database.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,24 +7,17 @@ #include -namespace ripple { +namespace xrpl { namespace NodeStore { -Database::Database( - Scheduler& scheduler, - int readThreads, - Section const& config, - beast::Journal journal) +Database::Database(Scheduler& scheduler, int readThreads, Section const& config, beast::Journal journal) : j_(journal) , scheduler_(scheduler) - , earliestLedgerSeq_( - get(config, "earliest_seq", XRP_LEDGER_EARLIEST_SEQ)) + , earliestLedgerSeq_(get(config, "earliest_seq", XRP_LEDGER_EARLIEST_SEQ)) , requestBundle_(get(config, "rq_bundle", 4)) , readThreads_(std::max(1, readThreads)) { - XRPL_ASSERT( - readThreads, - "ripple::NodeStore::Database::Database : nonzero threads input"); + XRPL_ASSERT(readThreads, "xrpl::NodeStore::Database::Database : nonzero threads input"); if (earliestLedgerSeq_ < 1) Throw("Invalid earliest_seq"); @@ -57,8 +31,7 @@ Database::Database( [this](int i) { runningThreads_++; - beast::setCurrentThreadName( - "db prefetch #" + std::to_string(i)); + beast::setCurrentThreadName("db prefetch #" + std::to_string(i)); decltype(read_) read; @@ -82,9 +55,7 @@ Database::Database( // extract multiple object at a time to minimize the // overhead of acquiring the mutex. - for (int cnt = 0; - !read_.empty() && cnt != requestBundle_; - ++cnt) + for (int cnt = 0; !read_.empty() && cnt != requestBundle_; ++cnt) read.insert(read_.extract(read_.begin())); } @@ -92,15 +63,14 @@ Database::Database( { XRPL_ASSERT( !it->second.empty(), - "ripple::NodeStore::Database::Database : non-empty " + "xrpl::NodeStore::Database::Database : non-empty " "data"); auto const& hash = it->first; auto const& data = it->second; auto const seqn = data[0].first; - auto obj = - fetchNodeObject(hash, seqn, FetchType::async); + auto obj = fetchNodeObject(hash, seqn, FetchType::async); // This could be further optimized: if there are // multiple requests for sequence numbers mapping to @@ -112,8 +82,7 @@ Database::Database( req.second( (seqn == req.first) || isSameDB(req.first, seqn) ? obj - : fetchNodeObject( - hash, req.first, FetchType::async)); + : fetchNodeObject(hash, req.first, FetchType::async)); } } @@ -167,17 +136,13 @@ Database::stop() while (readThreads_.load() != 0) { - XRPL_ASSERT( - steady_clock::now() - start < 30s, - "ripple::NodeStore::Database::stop : maximum stop duration"); + XRPL_ASSERT(steady_clock::now() - start < 30s, "xrpl::NodeStore::Database::stop : maximum stop duration"); std::this_thread::yield(); } JLOG(j_.debug()) << "Stop request completed in " - << duration_cast( - steady_clock::now() - start) - .count() - << " millseconds"; + << duration_cast(steady_clock::now() - start).count() + << " milliseconds"; } void @@ -207,8 +172,7 @@ Database::importInternal(Backend& dstBackend, Database& srcDB) } catch (std::exception const& e) { - JLOG(j_.error()) << "Exception caught in function " << fname - << ". Error: " << e.what(); + JLOG(j_.error()) << "Exception caught in function " << fname << ". Error: " << e.what(); return; } @@ -220,9 +184,7 @@ Database::importInternal(Backend& dstBackend, Database& srcDB) }; srcDB.for_each([&](std::shared_ptr nodeObject) { - XRPL_ASSERT( - nodeObject, - "ripple::NodeStore::Database::importInternal : non-null node"); + XRPL_ASSERT(nodeObject, "xrpl::NodeStore::Database::importInternal : non-null node"); if (!nodeObject) // This should never happen return; @@ -237,11 +199,7 @@ Database::importInternal(Backend& dstBackend, Database& srcDB) // Perform a fetch and report the time it took std::shared_ptr -Database::fetchNodeObject( - uint256 const& hash, - std::uint32_t ledgerSeq, - FetchType fetchType, - bool duplicate) +Database::fetchNodeObject(uint256 const& hash, std::uint32_t ledgerSeq, FetchType fetchType, bool duplicate) { FetchReport fetchReport(fetchType); @@ -266,9 +224,7 @@ Database::fetchNodeObject( void Database::getCountsJson(Json::Value& obj) { - XRPL_ASSERT( - obj.isObject(), - "ripple::NodeStore::Database::getCountsJson : valid input type"); + XRPL_ASSERT(obj.isObject(), "xrpl::NodeStore::Database::getCountsJson : valid input type"); { std::unique_lock lock(readLock_); @@ -288,4 +244,4 @@ Database::getCountsJson(Json::Value& obj) } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/DatabaseNodeImp.cpp b/src/libxrpl/nodestore/DatabaseNodeImp.cpp index 99b27f25b1..11152a2027 100644 --- a/src/libxrpl/nodestore/DatabaseNodeImp.cpp +++ b/src/libxrpl/nodestore/DatabaseNodeImp.cpp @@ -1,46 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace NodeStore { void -DatabaseNodeImp::store( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - std::uint32_t) +DatabaseNodeImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) { storeStats(1, data.size()); auto obj = NodeObject::createObject(type, std::move(data), hash); backend_->store(obj); - if (cache_) - { - // After the store, replace a negative cache entry if there is one - cache_->canonicalize( - hash, obj, [](std::shared_ptr const& n) { - return n->getType() == hotDUMMY; - }); - } } void @@ -49,90 +18,36 @@ DatabaseNodeImp::asyncFetch( std::uint32_t ledgerSeq, std::function const&)>&& callback) { - if (cache_) - { - std::shared_ptr obj = cache_->fetch(hash); - if (obj) - { - callback(obj->getType() == hotDUMMY ? nullptr : obj); - return; - } - } Database::asyncFetch(hash, ledgerSeq, std::move(callback)); } -void -DatabaseNodeImp::sweep() -{ - if (cache_) - cache_->sweep(); -} - std::shared_ptr -DatabaseNodeImp::fetchNodeObject( - uint256 const& hash, - std::uint32_t, - FetchReport& fetchReport, - bool duplicate) +DatabaseNodeImp::fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate) { - std::shared_ptr nodeObject = - cache_ ? cache_->fetch(hash) : nullptr; + std::shared_ptr nodeObject = nullptr; + Status status; - if (!nodeObject) + try { - JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record not " - << (cache_ ? "cached" : "found"); - - Status status; - - try - { - status = backend_->fetch(hash.data(), &nodeObject); - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) - << "fetchNodeObject " << hash - << ": Exception fetching from backend: " << e.what(); - Rethrow(); - } - - switch (status) - { - case ok: - if (cache_) - { - if (nodeObject) - cache_->canonicalize_replace_client(hash, nodeObject); - else - { - auto notFound = - NodeObject::createObject(hotDUMMY, {}, hash); - cache_->canonicalize_replace_client(hash, notFound); - if (notFound->getType() != hotDUMMY) - nodeObject = notFound; - } - } - break; - case notFound: - break; - case dataCorrupt: - JLOG(j_.fatal()) << "fetchNodeObject " << hash - << ": nodestore data is corrupted"; - break; - default: - JLOG(j_.warn()) - << "fetchNodeObject " << hash - << ": backend returns unknown result " << status; - break; - } + status = backend_->fetch(hash.data(), &nodeObject); } - else + catch (std::exception const& e) { - JLOG(j_.trace()) << "fetchNodeObject " << hash - << ": record found in cache"; - if (nodeObject->getType() == hotDUMMY) - nodeObject.reset(); + JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": Exception fetching from backend: " << e.what(); + Rethrow(); + } + + switch (status) + { + case ok: + case notFound: + break; + case dataCorrupt: + JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted"; + break; + default: + JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result " << status; + break; } if (nodeObject) @@ -144,73 +59,38 @@ DatabaseNodeImp::fetchNodeObject( std::vector> DatabaseNodeImp::fetchBatch(std::vector const& hashes) { - std::vector> results{hashes.size()}; using namespace std::chrono; auto const before = steady_clock::now(); - std::unordered_map indexMap; - std::vector cacheMisses; - uint64_t hits = 0; - uint64_t fetches = 0; + + std::vector batch{}; + batch.reserve(hashes.size()); for (size_t i = 0; i < hashes.size(); ++i) { auto const& hash = hashes[i]; - // See if the object already exists in the cache - auto nObj = cache_ ? cache_->fetch(hash) : nullptr; - ++fetches; - if (!nObj) - { - // Try the database - indexMap[&hash] = i; - cacheMisses.push_back(&hash); - } - else - { - results[i] = nObj->getType() == hotDUMMY ? nullptr : nObj; - // It was in the cache. - ++hits; - } + batch.push_back(&hash); } - JLOG(j_.debug()) << "fetchBatch - cache hits = " - << (hashes.size() - cacheMisses.size()) - << " - cache misses = " << cacheMisses.size(); - auto dbResults = backend_->fetchBatch(cacheMisses).first; - - for (size_t i = 0; i < dbResults.size(); ++i) + // Get the node objects that match the hashes from the backend. To protect + // against the backends returning fewer or more results than expected, the + // container is resized to the number of hashes. + auto results = backend_->fetchBatch(batch).first; + XRPL_ASSERT( + results.size() == hashes.size() || results.empty(), + "number of output objects either matches number of input hashes or is empty"); + results.resize(hashes.size()); + for (size_t i = 0; i < results.size(); ++i) { - auto nObj = std::move(dbResults[i]); - size_t index = indexMap[cacheMisses[i]]; - auto const& hash = hashes[index]; - - if (nObj) + if (!results[i]) { - // Ensure all threads get the same object - if (cache_) - cache_->canonicalize_replace_client(hash, nObj); + JLOG(j_.error()) << "fetchBatch - " + << "record not found in db. hash = " << strHex(hashes[i]); } - else - { - JLOG(j_.error()) - << "fetchBatch - " - << "record not found in db or cache. hash = " << strHex(hash); - if (cache_) - { - auto notFound = NodeObject::createObject(hotDUMMY, {}, hash); - cache_->canonicalize_replace_client(hash, notFound); - if (notFound->getType() != hotDUMMY) - nObj = std::move(notFound); - } - } - results[index] = std::move(nObj); } - auto fetchDurationUs = - std::chrono::duration_cast( - steady_clock::now() - before) - .count(); - updateFetchMetrics(fetches, hits, fetchDurationUs); + auto fetchDurationUs = std::chrono::duration_cast(steady_clock::now() - before).count(); + updateFetchMetrics(hashes.size(), 0, fetchDurationUs); return results; } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/DatabaseRotatingImp.cpp b/src/libxrpl/nodestore/DatabaseRotatingImp.cpp index 60a25ff870..f25b9d068e 100644 --- a/src/libxrpl/nodestore/DatabaseRotatingImp.cpp +++ b/src/libxrpl/nodestore/DatabaseRotatingImp.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace NodeStore { DatabaseRotatingImp::DatabaseRotatingImp( @@ -42,9 +23,7 @@ DatabaseRotatingImp::DatabaseRotatingImp( void DatabaseRotatingImp::rotate( std::unique_ptr&& newBackend, - std::function const& f) + std::function const& f) { // Pass these two names to the callback function std::string const newWritableBackendName = newBackend->getName(); @@ -101,11 +80,7 @@ DatabaseRotatingImp::sync() } void -DatabaseRotatingImp::store( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - std::uint32_t) +DatabaseRotatingImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) { auto nObj = NodeObject::createObject(type, std::move(data), hash); @@ -118,18 +93,8 @@ DatabaseRotatingImp::store( storeStats(1, nObj->getData().size()); } -void -DatabaseRotatingImp::sweep() -{ - // nothing to do -} - std::shared_ptr -DatabaseRotatingImp::fetchNodeObject( - uint256 const& hash, - std::uint32_t, - FetchReport& fetchReport, - bool duplicate) +DatabaseRotatingImp::fetchNodeObject(uint256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate) { auto fetch = [&](std::shared_ptr const& backend) { Status status; @@ -195,8 +160,7 @@ DatabaseRotatingImp::fetchNodeObject( } void -DatabaseRotatingImp::for_each( - std::function)> f) +DatabaseRotatingImp::for_each(std::function)> f) { auto [writable, archive] = [&] { std::lock_guard lock(mutex_); @@ -211,4 +175,4 @@ DatabaseRotatingImp::for_each( } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/DecodedBlob.cpp b/src/libxrpl/nodestore/DecodedBlob.cpp index 6d3019dc20..ad704cb84e 100644 --- a/src/libxrpl/nodestore/DecodedBlob.cpp +++ b/src/libxrpl/nodestore/DecodedBlob.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) @@ -73,9 +54,7 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) std::shared_ptr DecodedBlob::createObject() { - XRPL_ASSERT( - m_success, - "ripple::NodeStore::DecodedBlob::createObject : valid object type"); + XRPL_ASSERT(m_success, "xrpl::NodeStore::DecodedBlob::createObject : valid object type"); std::shared_ptr object; @@ -83,12 +62,11 @@ DecodedBlob::createObject() { Blob data(m_objectData, m_objectData + m_dataBytes); - object = NodeObject::createObject( - m_objectType, std::move(data), uint256::fromVoid(m_key)); + object = NodeObject::createObject(m_objectType, std::move(data), uint256::fromVoid(m_key)); } return object; } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/DummyScheduler.cpp b/src/libxrpl/nodestore/DummyScheduler.cpp index a70c2f35a4..21c1b5c92e 100644 --- a/src/libxrpl/nodestore/DummyScheduler.cpp +++ b/src/libxrpl/nodestore/DummyScheduler.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace NodeStore { void @@ -40,4 +21,4 @@ DummyScheduler::onBatchWrite(BatchWriteReport const& report) } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/ManagerImp.cpp b/src/libxrpl/nodestore/ManagerImp.cpp index 94abfd9aed..9d78097aae 100644 --- a/src/libxrpl/nodestore/ManagerImp.cpp +++ b/src/libxrpl/nodestore/ManagerImp.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -37,8 +18,8 @@ void ManagerImp::missing_backend() { Throw( - "Your rippled.cfg is missing a [node_db] entry, " - "please see the rippled-example.cfg file!"); + "Your xrpld.cfg is missing a [node_db] entry, " + "please see the xrpld-example.cfg file!"); } // We shouldn't rely on global variables for lifetime management because their @@ -63,11 +44,7 @@ ManagerImp::ManagerImp() } std::unique_ptr -ManagerImp::make_Backend( - Section const& parameters, - std::size_t burstSize, - Scheduler& scheduler, - beast::Journal journal) +ManagerImp::make_Backend(Section const& parameters, std::size_t burstSize, Scheduler& scheduler, beast::Journal journal) { std::string const type{get(parameters, "type")}; if (type.empty()) @@ -79,8 +56,7 @@ ManagerImp::make_Backend( missing_backend(); } - return factory->createInstance( - NodeObject::keyBytes, parameters, burstSize, scheduler, journal); + return factory->createInstance(NodeObject::keyBytes, parameters, burstSize, scheduler, journal); } std::unique_ptr @@ -93,8 +69,7 @@ ManagerImp::make_Database( { auto backend{make_Backend(config, burstSize, scheduler, journal)}; backend->open(); - return std::make_unique( - scheduler, readThreads, std::move(backend), config, journal); + return std::make_unique(scheduler, readThreads, std::move(backend), config, journal); } void @@ -109,12 +84,8 @@ ManagerImp::erase(Factory& factory) { std::lock_guard _(mutex_); auto const iter = - std::find_if(list_.begin(), list_.end(), [&factory](Factory* other) { - return other == &factory; - }); - XRPL_ASSERT( - iter != list_.end(), - "ripple::NodeStore::ManagerImp::erase : valid input"); + std::find_if(list_.begin(), list_.end(), [&factory](Factory* other) { return other == &factory; }); + XRPL_ASSERT(iter != list_.end(), "xrpl::NodeStore::ManagerImp::erase : valid input"); list_.erase(iter); } @@ -122,10 +93,8 @@ Factory* ManagerImp::find(std::string const& name) { std::lock_guard _(mutex_); - auto const iter = - std::find_if(list_.begin(), list_.end(), [&name](Factory* other) { - return boost::iequals(name, other->getName()); - }); + auto const iter = std::find_if( + list_.begin(), list_.end(), [&name](Factory* other) { return boost::iequals(name, other->getName()); }); if (iter == list_.end()) return nullptr; return *iter; @@ -140,4 +109,4 @@ Manager::instance() } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/NodeObject.cpp b/src/libxrpl/nodestore/NodeObject.cpp index 6cf69ac87f..2e40989e7c 100644 --- a/src/libxrpl/nodestore/NodeObject.cpp +++ b/src/libxrpl/nodestore/NodeObject.cpp @@ -1,35 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { //------------------------------------------------------------------------------ -NodeObject::NodeObject( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - PrivateAccess) +NodeObject::NodeObject(NodeObjectType type, Blob&& data, uint256 const& hash, PrivateAccess) : mType(type), mHash(hash), mData(std::move(data)) { } @@ -37,8 +14,7 @@ NodeObject::NodeObject( std::shared_ptr NodeObject::createObject(NodeObjectType type, Blob&& data, uint256 const& hash) { - return std::make_shared( - type, std::move(data), hash, PrivateAccess()); + return std::make_shared(type, std::move(data), hash, PrivateAccess()); } NodeObjectType @@ -59,4 +35,4 @@ NodeObject::getData() const return mData; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/backend/MemoryFactory.cpp b/src/libxrpl/nodestore/backend/MemoryFactory.cpp index c45debe1d0..3cb8fb7f5e 100644 --- a/src/libxrpl/nodestore/backend/MemoryFactory.cpp +++ b/src/libxrpl/nodestore/backend/MemoryFactory.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { struct MemoryDB @@ -65,8 +46,7 @@ public: open(std::string const& path) { std::lock_guard _(mutex_); - auto const result = map_.emplace( - std::piecewise_construct, std::make_tuple(path), std::make_tuple()); + auto const result = map_.emplace(std::piecewise_construct, std::make_tuple(path), std::make_tuple()); MemoryDB& db = result.first->second; if (db.open) Throw("already open"); @@ -95,10 +75,7 @@ private: MemoryDB* db_{nullptr}; public: - MemoryBackend( - size_t keyBytes, - Section const& keyValues, - beast::Journal journal) + MemoryBackend(size_t keyBytes, Section const& keyValues, beast::Journal journal) : name_(get(keyValues, "path")), journal_(journal) { boost::ignore_unused(journal_); // Keep unused journal_ just in case. @@ -140,8 +117,7 @@ public: Status fetch(void const* key, std::shared_ptr* pObject) override { - XRPL_ASSERT( - db_, "ripple::NodeStore::MemoryBackend::fetch : non-null database"); + XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::fetch : non-null database"); uint256 const hash(uint256::fromVoid(key)); std::lock_guard _(db_->mutex); @@ -177,8 +153,7 @@ public: void store(std::shared_ptr const& object) override { - XRPL_ASSERT( - db_, "ripple::NodeStore::MemoryBackend::store : non-null database"); + XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::store : non-null database"); std::lock_guard _(db_->mutex); db_->table.emplace(object->getHash(), object); } @@ -198,9 +173,7 @@ public: void for_each(std::function)> f) override { - XRPL_ASSERT( - db_, - "ripple::NodeStore::MemoryBackend::for_each : non-null database"); + XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::for_each : non-null database"); for (auto const& e : db_->table) f(e.second); } @@ -248,4 +221,4 @@ MemoryFactory::createInstance( } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/backend/NuDBFactory.cpp b/src/libxrpl/nodestore/backend/NuDBFactory.cpp index 0202dfc4e9..eb3ccb3181 100644 --- a/src/libxrpl/nodestore/backend/NuDBFactory.cpp +++ b/src/libxrpl/nodestore/backend/NuDBFactory.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class NuDBBackend : public Backend @@ -72,8 +53,7 @@ public: , scheduler_(scheduler) { if (name_.empty()) - Throw( - "nodestore: Missing path in NuDB backend"); + Throw("nodestore: Missing path in NuDB backend"); } NuDBBackend( @@ -93,8 +73,7 @@ public: , scheduler_(scheduler) { if (name_.empty()) - Throw( - "nodestore: Missing path in NuDB backend"); + Throw("nodestore: Missing path in NuDB backend"); } ~NuDBBackend() override @@ -124,15 +103,14 @@ public: } void - open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) - override + open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) override { using namespace boost::filesystem; if (db_.is_open()) { // LCOV_EXCL_START UNREACHABLE( - "ripple::NodeStore::NuDBBackend::open : database is already " + "xrpl::NodeStore::NuDBBackend::open : database is already " "open"); JLOG(j_.error()) << "database is already open"; return; @@ -146,17 +124,7 @@ public: if (createIfMissing) { create_directories(folder); - nudb::create( - dp, - kp, - lp, - appType, - uid, - salt, - keyBytes_, - blockSize_, - 0.50, - ec); + nudb::create(dp, kp, lp, appType, uid, salt, keyBytes_, blockSize_, 0.50, ec); if (ec == nudb::errc::file_exists) ec = {}; if (ec) @@ -202,8 +170,7 @@ public: boost::filesystem::remove_all(name_, ec); if (ec) { - JLOG(j_.fatal()) << "Filesystem remove_all of " << name_ - << " failed with: " << ec.message(); + JLOG(j_.fatal()) << "Filesystem remove_all of " << name_ << " failed with: " << ec.message(); } } } @@ -274,8 +241,8 @@ public: report.writeCount = 1; auto const start = std::chrono::steady_clock::now(); do_insert(no); - report.elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start); + report.elapsed = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start); scheduler_.onBatchWrite(report); } @@ -287,8 +254,8 @@ public: auto const start = std::chrono::steady_clock::now(); for (auto const& e : batch) do_insert(e); - report.elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start); + report.elapsed = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start); scheduler_.onBatchWrite(report); } @@ -310,11 +277,7 @@ public: Throw(ec); nudb::visit( dp, - [&](void const* key, - std::size_t key_bytes, - void const* data, - std::size_t size, - nudb::error_code&) { + [&](void const* key, std::size_t key_bytes, void const* data, std::size_t size, nudb::error_code&) { nudb::detail::buffer bf; auto const result = nodeobject_decompress(data, size, bf); DecodedBlob decoded(key, result.first, result.second); @@ -373,17 +336,13 @@ public: private: static std::size_t - parseBlockSize( - std::string const& name, - Section const& keyValues, - beast::Journal journal) + parseBlockSize(std::string const& name, Section const& keyValues, beast::Journal journal) { using namespace boost::filesystem; auto const folder = path(name); auto const kp = (folder / "nudb.key").string(); - std::size_t const defaultSize = - nudb::block_size(kp); // Default 4K from NuDB + std::size_t const defaultSize = nudb::block_size(kp); // Default 4K from NuDB std::size_t blockSize = defaultSize; std::string blockSizeStr; @@ -394,29 +353,23 @@ private: try { - std::size_t const parsedBlockSize = - beast::lexicalCastThrow(blockSizeStr); + std::size_t const parsedBlockSize = beast::lexicalCastThrow(blockSizeStr); // Validate: must be power of 2 between 4K and 32K - if (parsedBlockSize < 4096 || parsedBlockSize > 32768 || - (parsedBlockSize & (parsedBlockSize - 1)) != 0) + if (parsedBlockSize < 4096 || parsedBlockSize > 32768 || (parsedBlockSize & (parsedBlockSize - 1)) != 0) { std::stringstream s; - s << "Invalid nudb_block_size: " << parsedBlockSize - << ". Must be power of 2 between 4096 and 32768."; + s << "Invalid nudb_block_size: " << parsedBlockSize << ". Must be power of 2 between 4096 and 32768."; Throw(s.str()); } - JLOG(journal.info()) - << "Using custom NuDB block size: " << parsedBlockSize - << " bytes"; + JLOG(journal.info()) << "Using custom NuDB block size: " << parsedBlockSize << " bytes"; return parsedBlockSize; } catch (std::exception const& e) { std::stringstream s; - s << "Invalid nudb_block_size value: " << blockSizeStr - << ". Error: " << e.what(); + s << "Invalid nudb_block_size value: " << blockSizeStr << ". Error: " << e.what(); Throw(s.str()); } } @@ -449,8 +402,7 @@ public: Scheduler& scheduler, beast::Journal journal) override { - return std::make_unique( - keyBytes, keyValues, burstSize, scheduler, journal); + return std::make_unique(keyBytes, keyValues, burstSize, scheduler, journal); } std::unique_ptr @@ -462,8 +414,7 @@ public: nudb::context& context, beast::Journal journal) override { - return std::make_unique( - keyBytes, keyValues, burstSize, scheduler, context, journal); + return std::make_unique(keyBytes, keyValues, burstSize, scheduler, context, journal); } }; @@ -474,4 +425,4 @@ registerNuDBFactory(Manager& manager) } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/backend/NullFactory.cpp b/src/libxrpl/nodestore/backend/NullFactory.cpp index 6408e4aad5..4ecca46a9a 100644 --- a/src/libxrpl/nodestore/backend/NullFactory.cpp +++ b/src/libxrpl/nodestore/backend/NullFactory.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class NullBackend : public Backend @@ -127,12 +108,7 @@ public: } std::unique_ptr - createInstance( - size_t, - Section const&, - std::size_t, - Scheduler&, - beast::Journal) override + createInstance(size_t, Section const&, std::size_t, Scheduler&, beast::Journal) override { return std::make_unique(); } @@ -145,4 +121,4 @@ registerNullFactory(Manager& manager) } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/nodestore/backend/RocksDBFactory.cpp b/src/libxrpl/nodestore/backend/RocksDBFactory.cpp index 68fef494b6..a35f737528 100644 --- a/src/libxrpl/nodestore/backend/RocksDBFactory.cpp +++ b/src/libxrpl/nodestore/backend/RocksDBFactory.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE #include #include #include @@ -33,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class RocksDBEnv : public rocksdb::EnvWrapper @@ -100,10 +81,7 @@ public: Scheduler& scheduler, beast::Journal journal, RocksDBEnv* env) - : m_deletePath(false) - , m_journal(journal) - , m_keyBytes(keyBytes) - , m_batch(*this, scheduler) + : m_deletePath(false), m_journal(journal), m_keyBytes(keyBytes), m_batch(*this, scheduler) { if (!get_if_exists(keyValues, "path", m_name)) Throw("Missing path in RocksDBFactory backend"); @@ -111,8 +89,7 @@ public: rocksdb::BlockBasedTableOptions table_options; m_options.env = env; - bool hard_set = - keyValues.exists("hard_set") && get(keyValues, "hard_set"); + bool hard_set = keyValues.exists("hard_set") && get(keyValues, "hard_set"); if (keyValues.exists("cache_mb")) { @@ -126,10 +103,8 @@ public: if (auto const v = get(keyValues, "filter_bits")) { - bool const filter_blocks = !keyValues.exists("filter_full") || - (get(keyValues, "filter_full") == 0); - table_options.filter_policy.reset( - rocksdb::NewBloomFilterPolicy(v, filter_blocks)); + bool const filter_blocks = !keyValues.exists("filter_full") || (get(keyValues, "filter_full") == 0); + table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(v, filter_blocks)); } if (get_if_exists(keyValues, "open_files", m_options.max_open_files)) @@ -148,25 +123,21 @@ public: file_size_mb = 256; m_options.target_file_size_base = megabytes(file_size_mb); - m_options.max_bytes_for_level_base = - 5 * m_options.target_file_size_base; + m_options.max_bytes_for_level_base = 5 * m_options.target_file_size_base; m_options.write_buffer_size = 2 * m_options.target_file_size_base; } - get_if_exists( - keyValues, "file_size_mult", m_options.target_file_size_multiplier); + get_if_exists(keyValues, "file_size_mult", m_options.target_file_size_multiplier); if (keyValues.exists("bg_threads")) { - m_options.env->SetBackgroundThreads( - get(keyValues, "bg_threads"), rocksdb::Env::LOW); + m_options.env->SetBackgroundThreads(get(keyValues, "bg_threads"), rocksdb::Env::LOW); } if (keyValues.exists("high_threads")) { auto const highThreads = get(keyValues, "high_threads"); - m_options.env->SetBackgroundThreads( - highThreads, rocksdb::Env::HIGH); + m_options.env->SetBackgroundThreads(highThreads, rocksdb::Env::HIGH); // If we have high-priority threads, presumably we want to // use them for background flushes @@ -178,8 +149,7 @@ public: get_if_exists(keyValues, "block_size", table_options.block_size); - if (keyValues.exists("universal_compaction") && - (get(keyValues, "universal_compaction") != 0)) + if (keyValues.exists("universal_compaction") && (get(keyValues, "universal_compaction") != 0)) { m_options.compaction_style = rocksdb::kCompactionStyleUniversal; m_options.min_write_buffer_number_to_merge = 2; @@ -191,26 +161,18 @@ public: { rocksdb::ConfigOptions config_options; auto const s = rocksdb::GetBlockBasedTableOptionsFromString( - config_options, - table_options, - get(keyValues, "bbt_options"), - &table_options); + config_options, table_options, get(keyValues, "bbt_options"), &table_options); if (!s.ok()) - Throw( - std::string("Unable to set RocksDB bbt_options: ") + - s.ToString()); + Throw(std::string("Unable to set RocksDB bbt_options: ") + s.ToString()); } m_options.table_factory.reset(NewBlockBasedTableFactory(table_options)); if (keyValues.exists("options")) { - auto const s = rocksdb::GetOptionsFromString( - m_options, get(keyValues, "options"), &m_options); + auto const s = rocksdb::GetOptionsFromString(m_options, get(keyValues, "options"), &m_options); if (!s.ok()) - Throw( - std::string("Unable to set RocksDB options: ") + - s.ToString()); + Throw(std::string("Unable to set RocksDB options: ") + s.ToString()); } std::string s1, s2; @@ -232,7 +194,7 @@ public: { // LCOV_EXCL_START UNREACHABLE( - "ripple::NodeStore::RocksDBBackend::open : database is already " + "xrpl::NodeStore::RocksDBBackend::open : database is already " "open"); JLOG(m_journal.error()) << "database is already open"; return; @@ -242,9 +204,7 @@ public: m_options.create_if_missing = createIfMissing; rocksdb::Status status = rocksdb::DB::Open(m_options, m_name, &db); if (!status.ok() || !db) - Throw( - std::string("Unable to open/create RocksDB: ") + - status.ToString()); + Throw(std::string("Unable to open/create RocksDB: ") + status.ToString()); m_db.reset(db); } @@ -279,9 +239,7 @@ public: Status fetch(void const* key, std::shared_ptr* pObject) override { - XRPL_ASSERT( - m_db, - "ripple::NodeStore::RocksDBBackend::fetch : non-null database"); + XRPL_ASSERT(m_db, "xrpl::NodeStore::RocksDBBackend::fetch : non-null database"); pObject->reset(); Status status(ok); @@ -320,8 +278,7 @@ public: } else { - status = - Status(customCode + unsafe_cast(getStatus.code())); + status = Status(customCode + unsafe_cast(getStatus.code())); JLOG(m_journal.error()) << getStatus.ToString(); } @@ -359,7 +316,7 @@ public: { XRPL_ASSERT( m_db, - "ripple::NodeStore::RocksDBBackend::storeBatch : non-null " + "xrpl::NodeStore::RocksDBBackend::storeBatch : non-null " "database"); rocksdb::WriteBatch wb; @@ -368,12 +325,8 @@ public: EncodedBlob encoded(e); wb.Put( - rocksdb::Slice( - reinterpret_cast(encoded.getKey()), - m_keyBytes), - rocksdb::Slice( - reinterpret_cast(encoded.getData()), - encoded.getSize())); + rocksdb::Slice(reinterpret_cast(encoded.getKey()), m_keyBytes), + rocksdb::Slice(reinterpret_cast(encoded.getData()), encoded.getSize())); } rocksdb::WriteOptions const options; @@ -392,9 +345,7 @@ public: void for_each(std::function)> f) override { - XRPL_ASSERT( - m_db, - "ripple::NodeStore::RocksDBBackend::for_each : non-null database"); + XRPL_ASSERT(m_db, "xrpl::NodeStore::RocksDBBackend::for_each : non-null database"); rocksdb::ReadOptions const options; std::unique_ptr it(m_db->NewIterator(options)); @@ -403,8 +354,7 @@ public: { if (it->key().size() == m_keyBytes) { - DecodedBlob decoded( - it->key().data(), it->value().data(), it->value().size()); + DecodedBlob decoded(it->key().data(), it->value().data(), it->value().size()); if (decoded.wasOk()) { @@ -413,16 +363,14 @@ public: else { // Uh oh, corrupted data! - JLOG(m_journal.fatal()) - << "Corrupt NodeObject #" << it->key().ToString(true); + JLOG(m_journal.fatal()) << "Corrupt NodeObject #" << it->key().ToString(true); } } else { // VFALCO NOTE What does it mean to find an // incorrectly sized key? Corruption? - JLOG(m_journal.fatal()) - << "Bad key size = " << it->key().size(); + JLOG(m_journal.fatal()) << "Bad key size = " << it->key().size(); } } } @@ -477,15 +425,10 @@ public: } std::unique_ptr - createInstance( - size_t keyBytes, - Section const& keyValues, - std::size_t, - Scheduler& scheduler, - beast::Journal journal) override + createInstance(size_t keyBytes, Section const& keyValues, std::size_t, Scheduler& scheduler, beast::Journal journal) + override { - return std::make_unique( - keyBytes, keyValues, scheduler, journal, &m_env); + return std::make_unique(keyBytes, keyValues, scheduler, journal, &m_env); } }; @@ -496,6 +439,6 @@ registerRocksDBFactory(Manager& manager) } } // namespace NodeStore -} // namespace ripple +} // namespace xrpl #endif diff --git a/src/libxrpl/protocol/AMMCore.cpp b/src/libxrpl/protocol/AMMCore.cpp index 60660357ea..bb83be2724 100644 --- a/src/libxrpl/protocol/AMMCore.cpp +++ b/src/libxrpl/protocol/AMMCore.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { Currency ammLPTCurrency(Currency const& cur1, Currency const& cur2) @@ -48,24 +29,18 @@ ammLPTCurrency(Currency const& cur1, Currency const& cur2) auto const hash = sha512Half(minC, maxC); Currency currency; *currency.begin() = AMMCurrencyCode; - std::copy( - hash.begin(), hash.begin() + currency.size() - 1, currency.begin() + 1); + std::copy(hash.begin(), hash.begin() + currency.size() - 1, currency.begin() + 1); return currency; } Issue -ammLPTIssue( - Currency const& cur1, - Currency const& cur2, - AccountID const& ammAccountID) +ammLPTIssue(Currency const& cur1, Currency const& cur2, AccountID const& ammAccountID) { return Issue(ammLPTCurrency(cur1, cur2), ammAccountID); } NotTEC -invalidAMMAsset( - Issue const& issue, - std::optional> const& pair) +invalidAMMAsset(Issue const& issue, std::optional> const& pair) { if (badCurrency() == issue.currency) return temBAD_CURRENCY; @@ -77,10 +52,7 @@ invalidAMMAsset( } NotTEC -invalidAMMAssetPair( - Issue const& issue1, - Issue const& issue2, - std::optional> const& pair) +invalidAMMAssetPair(Issue const& issue1, Issue const& issue2, std::optional> const& pair) { if (issue1 == issue2) return temBAD_AMM_TOKENS; @@ -92,10 +64,7 @@ invalidAMMAssetPair( } NotTEC -invalidAMMAmount( - STAmount const& amount, - std::optional> const& pair, - bool validZero) +invalidAMMAmount(STAmount const& amount, std::optional> const& pair, bool validZero) { if (auto const res = invalidAMMAsset(amount.issue(), pair)) return res; @@ -110,13 +79,10 @@ ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot) // It should be impossible for expiration to be < TOTAL_TIME_SLOT_SECS, // but check just to be safe auto const expiration = auctionSlot[sfExpiration]; - XRPL_ASSERT( - expiration >= TOTAL_TIME_SLOT_SECS, - "ripple::ammAuctionTimeSlot : minimum expiration"); + XRPL_ASSERT(expiration >= TOTAL_TIME_SLOT_SECS, "xrpl::ammAuctionTimeSlot : minimum expiration"); if (expiration >= TOTAL_TIME_SLOT_SECS) { - if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; - current >= start) + if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; current >= start) { if (auto const diff = current - start; diff < TOTAL_TIME_SLOT_SECS) return diff / AUCTION_SLOT_INTERVAL_DURATION; @@ -131,4 +97,4 @@ ammEnabled(Rules const& rules) return rules.enabled(featureAMM) && rules.enabled(fixUniversalNumber); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/AccountID.cpp b/src/libxrpl/protocol/AccountID.cpp index 109ac3d028..4edbf5c0e7 100644 --- a/src/libxrpl/protocol/AccountID.cpp +++ b/src/libxrpl/protocol/AccountID.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -82,12 +63,9 @@ public: return cache_[index].encoding; } - auto ret = - encodeBase58Token(TokenType::AccountID, id.data(), id.size()); + auto ret = encodeBase58Token(TokenType::AccountID, id.data(), id.size()); - XRPL_ASSERT( - ret.size() <= 38, - "ripple::detail::AccountIdCache : maximum result size"); + XRPL_ASSERT(ret.size() <= 38, "xrpl::detail::AccountIdCache : maximum result size"); { std::lock_guard lock(sl); @@ -200,4 +178,4 @@ to_issuer(AccountID& issuer, std::string const& s) return true; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Asset.cpp b/src/libxrpl/protocol/Asset.cpp index 104d627d81..0076da6570 100644 --- a/src/libxrpl/protocol/Asset.cpp +++ b/src/libxrpl/protocol/Asset.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,14 +11,12 @@ #include #include -namespace ripple { +namespace xrpl { AccountID const& Asset::getIssuer() const { - return std::visit( - [&](auto&& issue) -> AccountID const& { return issue.getIssuer(); }, - issue_); + return std::visit([&](auto&& issue) -> AccountID const& { return issue.getIssuer(); }, issue_); } std::string @@ -61,8 +40,7 @@ Asset::operator()(Number const& number) const std::string to_string(Asset const& asset) { - return std::visit( - [&](auto const& issue) { return to_string(issue); }, asset.value()); + return std::visit([&](auto const& issue) { return to_string(issue); }, asset.value()); } bool @@ -77,12 +55,11 @@ Asset assetFromJson(Json::Value const& v) { if (!v.isMember(jss::currency) && !v.isMember(jss::mpt_issuance_id)) - Throw( - "assetFromJson must contain currency or mpt_issuance_id"); + Throw("assetFromJson must contain currency or mpt_issuance_id"); if (v.isMember(jss::currency)) return issueFromJson(v); return mptIssueFromJson(v); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Book.cpp b/src/libxrpl/protocol/Book.cpp index 2114deab6b..59ad739c11 100644 --- a/src/libxrpl/protocol/Book.cpp +++ b/src/libxrpl/protocol/Book.cpp @@ -1,35 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { bool isConsistent(Book const& book) { - return isConsistent(book.in) && isConsistent(book.out) && - book.in != book.out; + return isConsistent(book.in) && isConsistent(book.out) && book.in != book.out; } std::string @@ -51,4 +31,4 @@ reversed(Book const& book) return Book(book.out, book.in, book.domain); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 0cee2995db..c86ef17449 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -1,33 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include +#include + #include #include #include #include -namespace ripple { +namespace xrpl { namespace BuildInfo { @@ -36,10 +19,10 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "3.0.0-b1" +char const* const versionString = "3.2.0-b0" // clang-format on -#if defined(DEBUG) || defined(SANITIZER) +#if defined(DEBUG) || defined(SANITIZERS) "+" #ifdef GIT_COMMIT_HASH GIT_COMMIT_HASH @@ -47,13 +30,13 @@ char const* const versionString = "3.0.0-b1" #endif #ifdef DEBUG "DEBUG" -#ifdef SANITIZER +#ifdef SANITIZERS "." #endif #endif -#ifdef SANITIZER - BOOST_PP_STRINGIZE(SANITIZER) +#ifdef SANITIZERS + BOOST_PP_STRINGIZE(SANITIZERS) // cspell: disable-line #endif #endif @@ -84,10 +67,8 @@ getFullVersionString() return value; } -static constexpr std::uint64_t implementationVersionIdentifier = - 0x183B'0000'0000'0000LLU; -static constexpr std::uint64_t implementationVersionIdentifierMask = - 0xFFFF'0000'0000'0000LLU; +static constexpr std::uint64_t implementationVersionIdentifier = 0x183B'0000'0000'0000LLU; +static constexpr std::uint64_t implementationVersionIdentifierMask = 0xFFFF'0000'0000'0000LLU; std::uint64_t encodeSoftwareVersion(char const* const versionStr) @@ -126,9 +107,7 @@ encodeSoftwareVersion(char const* const versionStr) if (prefix != identifier.substr(0, prefix.length())) return 0; - if (!beast::lexicalCastChecked( - ret, - std::string(identifier.substr(prefix.length())))) + if (!beast::lexicalCastChecked(ret, std::string(identifier.substr(prefix.length())))) return 0; if (std::clamp(ret, lok, hik) != ret) @@ -164,8 +143,7 @@ getEncodedVersion() bool isRippledVersion(std::uint64_t version) { - return (version & implementationVersionIdentifierMask) == - implementationVersionIdentifier; + return (version & implementationVersionIdentifierMask) == implementationVersionIdentifier; } bool @@ -178,4 +156,4 @@ isNewerVersion(std::uint64_t version) } // namespace BuildInfo -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/ConfidentialTransfer.cpp b/src/libxrpl/protocol/ConfidentialTransfer.cpp index b278e82238..cf4503d1f0 100644 --- a/src/libxrpl/protocol/ConfidentialTransfer.cpp +++ b/src/libxrpl/protocol/ConfidentialTransfer.cpp @@ -1,334 +1,86 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -#include + +#include #include #include -namespace ripple { -int -secp256k1_elgamal_generate_keypair( - secp256k1_context const* ctx, - unsigned char* privkey, - secp256k1_pubkey* pubkey) +namespace xrpl { +void +addCommonZKPFields( + Serializer& s, + std::uint16_t txType, + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID) { - // 1. Generate 32 random bytes for the private key - do - { - if (RAND_bytes(privkey, 32) != 1) - { - return 0; // Failure - } - // 2. Verify the random data is a valid private key. - } while (secp256k1_ec_seckey_verify(ctx, privkey) != 1); - - // 3. Create the corresponding public key. - if (secp256k1_ec_pubkey_create(ctx, pubkey, privkey) != 1) - { - return 0; // Failure - } - - return 1; // Success + s.add16(txType); + s.addBitString(account); + s.add32(sequence); + s.addBitString(issuanceID); } -// ... implementation of secp256k1_elgamal_encrypt ... - -int -secp256k1_elgamal_encrypt( - secp256k1_context const* ctx, - secp256k1_pubkey* c1, - secp256k1_pubkey* c2, - secp256k1_pubkey const* pubkey_Q, - uint64_t amount, - unsigned char const* blinding_factor) +uint256 +getSendContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + AccountID const& destination, + std::uint32_t version) { - secp256k1_pubkey S; + Serializer s; + addCommonZKPFields(s, ttCONFIDENTIAL_MPT_SEND, account, sequence, issuanceID); - // First, calculate C1 = k * G - if (secp256k1_ec_pubkey_create(ctx, c1, blinding_factor) != 1) - { - return 0; - } + s.addBitString(destination); + s.addInteger(version); - // Next, calculate the shared secret S = k * Q - S = *pubkey_Q; - if (secp256k1_ec_pubkey_tweak_mul(ctx, &S, blinding_factor) != 1) - { - return 0; - } - - // --- Handle the amount --- - if (amount == 0) - { - // For amount = 0, C2 = S. - *c2 = S; - } - else - { - // For non-zero amounts, proceed as before. - unsigned char amount_scalar[32] = {0}; - secp256k1_pubkey M; - secp256k1_pubkey const* points_to_add[2]; - - // Convert amount to a 32-byte BIG-ENDIAN scalar. - for (int i = 0; i < 8; ++i) - { - amount_scalar[31 - i] = (amount >> (i * 8)) & 0xFF; - } - - // Calculate M = amount * G - if (secp256k1_ec_pubkey_create(ctx, &M, amount_scalar) != 1) - { - return 0; - } - - // Calculate C2 = M + S - points_to_add[0] = &M; - points_to_add[1] = &S; - if (secp256k1_ec_pubkey_combine(ctx, c2, points_to_add, 2) != 1) - { - return 0; - } - } - - return 1; // Success + return s.getSHA512Half(); } -// ... implementation of secp256k1_elgamal_decrypt ... -int -secp256k1_elgamal_decrypt( - secp256k1_context const* ctx, - uint64_t* amount, - secp256k1_pubkey const* c1, - secp256k1_pubkey const* c2, - unsigned char const* privkey) +uint256 +getClawbackContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + std::uint64_t amount, + AccountID const& holder) { - secp256k1_pubkey S, M, G_point, current_M, next_M; - secp256k1_pubkey const* points_to_add[2]; - unsigned char c2_bytes[33], s_bytes[33], m_bytes[33], current_m_bytes[33]; - size_t len; - uint64_t i; + Serializer s; + addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CLAWBACK, account, sequence, issuanceID); - /* Create the scalar '1' in big-endian format */ - unsigned char one_scalar[32] = {0}; - one_scalar[31] = 1; + s.add64(amount); + s.addBitString(holder); - /* --- Executable Code --- */ - - // 1. Calculate S = privkey * C1 - S = *c1; - if (secp256k1_ec_pubkey_tweak_mul(ctx, &S, privkey) != 1) - { - return 0; - } - - // 2. Check for amount = 0 by comparing serialized points - len = sizeof(c2_bytes); - if (secp256k1_ec_pubkey_serialize( - ctx, c2_bytes, &len, c2, SECP256K1_EC_COMPRESSED) != 1) - return 0; - len = sizeof(s_bytes); - if (secp256k1_ec_pubkey_serialize( - ctx, s_bytes, &len, &S, SECP256K1_EC_COMPRESSED) != 1) - return 0; - if (memcmp(c2_bytes, s_bytes, sizeof(c2_bytes)) == 0) - { - *amount = 0; - return 1; - } - - // 3. Recover M = C2 - S - if (secp256k1_ec_pubkey_negate(ctx, &S) != 1) - return 0; - points_to_add[0] = c2; - points_to_add[1] = &S; - if (secp256k1_ec_pubkey_combine(ctx, &M, points_to_add, 2) != 1) - { - return 0; - } - - // 4. Serialize M once for comparison in the loop - len = sizeof(m_bytes); - if (secp256k1_ec_pubkey_serialize( - ctx, m_bytes, &len, &M, SECP256K1_EC_COMPRESSED) != 1) - return 0; - - // 5. Brute-force search loop - if (secp256k1_ec_pubkey_create(ctx, &G_point, one_scalar) != 1) - return 0; - current_M = G_point; - - for (i = 1; i <= 1000000; ++i) - { - len = sizeof(current_m_bytes); - if (secp256k1_ec_pubkey_serialize( - ctx, - current_m_bytes, - &len, - ¤t_M, - SECP256K1_EC_COMPRESSED) != 1) - return 0; - if (memcmp(m_bytes, current_m_bytes, sizeof(m_bytes)) == 0) - { - *amount = i; - return 1; - } - - points_to_add[0] = ¤t_M; - points_to_add[1] = &G_point; - if (secp256k1_ec_pubkey_combine(ctx, &next_M, points_to_add, 2) != 1) - return 0; - current_M = next_M; - } - - return 0; // Not found + return s.getSHA512Half(); } -int -secp256k1_elgamal_add( - secp256k1_context const* ctx, - secp256k1_pubkey* sum_c1, - secp256k1_pubkey* sum_c2, - secp256k1_pubkey const* a_c1, - secp256k1_pubkey const* a_c2, - secp256k1_pubkey const* b_c1, - secp256k1_pubkey const* b_c2) +uint256 +getConvertContextHash(AccountID const& account, std::uint32_t sequence, uint192 const& issuanceID, std::uint64_t amount) { - secp256k1_pubkey const* c1_points[2] = {a_c1, b_c1}; - if (secp256k1_ec_pubkey_combine(ctx, sum_c1, c1_points, 2) != 1) - { - return 0; - } + Serializer s; + addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT, account, sequence, issuanceID); - secp256k1_pubkey const* c2_points[2] = {a_c2, b_c2}; - if (secp256k1_ec_pubkey_combine(ctx, sum_c2, c2_points, 2) != 1) - { - return 0; - } - return 1; + s.add64(amount); + + return s.getSHA512Half(); } -int -secp256k1_elgamal_subtract( - secp256k1_context const* ctx, - secp256k1_pubkey* diff_c1, - secp256k1_pubkey* diff_c2, - secp256k1_pubkey const* a_c1, - secp256k1_pubkey const* a_c2, - secp256k1_pubkey const* b_c1, - secp256k1_pubkey const* b_c2) +uint256 +getConvertBackContextHash( + AccountID const& account, + std::uint32_t sequence, + uint192 const& issuanceID, + std::uint64_t amount, + std::uint32_t version) { - // To subtract, we add the negation: (A - B) is (A + (-B)) - // Make a local, modifiable copy of B's points. - secp256k1_pubkey neg_b_c1 = *b_c1; - secp256k1_pubkey neg_b_c2 = *b_c2; + Serializer s; + addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT_BACK, account, sequence, issuanceID); - // Negate the copies - if (secp256k1_ec_pubkey_negate(ctx, &neg_b_c1) != 1 || - secp256k1_ec_pubkey_negate(ctx, &neg_b_c2) != 1) - { - return 0; // Negation failed - } + s.add64(amount); + s.addInteger(version); - // Now, add A and the negated copies of B - secp256k1_pubkey const* c1_points[2] = {a_c1, &neg_b_c1}; - if (secp256k1_ec_pubkey_combine(ctx, diff_c1, c1_points, 2) != 1) - { - return 0; - } - - secp256k1_pubkey const* c2_points[2] = {a_c2, &neg_b_c2}; - if (secp256k1_ec_pubkey_combine(ctx, diff_c2, c2_points, 2) != 1) - { - return 0; - } - - return 1; // Success -} - -// Helper function to concatenate data for hashing -static void -build_hash_input( - unsigned char* output_buffer, - size_t buffer_size, - unsigned char const* account_id, // 20 bytes - unsigned char const* mpt_issuance_id // 24 bytes -) -{ - char const* domain_separator = "EncZero"; - size_t domain_len = strlen(domain_separator); - size_t offset = 0; - - // Ensure buffer is large enough (should be checked by caller if necessary) - // Size = strlen("EncZero") + 20 + 24 = 7 + 20 + 24 = 51 bytes - - memcpy(output_buffer + offset, domain_separator, domain_len); - offset += domain_len; - - memcpy(output_buffer + offset, account_id, 20); - offset += 20; - - memcpy(output_buffer + offset, mpt_issuance_id, 24); - // offset += 24; // Final size is offset + 24 -} - -// The canonical encrypted zero - -int -generate_canonical_encrypted_zero( - secp256k1_context const* ctx, - secp256k1_pubkey* enc_zero_c1, - secp256k1_pubkey* enc_zero_c2, - secp256k1_pubkey const* pubkey, - unsigned char const* account_id, // 20 bytes - unsigned char const* mpt_issuance_id // 24 bytes -) -{ - unsigned char deterministic_scalar[32]; - unsigned char hash_input[51]; // Size calculated above - - /* 1. Create the input buffer for hashing */ - build_hash_input( - hash_input, sizeof(hash_input), account_id, mpt_issuance_id); - - /* 2. Hash the buffer to create the deterministic scalar 'r' */ - do - { - // Hash the concatenated bytes - SHA256(hash_input, sizeof(hash_input), deterministic_scalar); - - /* Note: If the hash output could be invalid (0 or >= n), - * you might need to add a nonce/counter to hash_input - * and re-hash in a loop until a valid scalar is produced. */ - } while (secp256k1_ec_seckey_verify(ctx, deterministic_scalar) != 1); - - /* 3. Encrypt the amount 0 using the deterministic scalar */ - return secp256k1_elgamal_encrypt( - ctx, - enc_zero_c1, - enc_zero_c2, - pubkey, - 0, /* The amount is zero */ - deterministic_scalar); + return s.getSHA512Half(); } bool @@ -336,10 +88,7 @@ makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2) { auto parsePubKey = [](Slice const& slice, secp256k1_pubkey& out) { return secp256k1_ec_pubkey_parse( - secp256k1Context(), - &out, - reinterpret_cast(slice.data()), - slice.length()); + secp256k1Context(), &out, reinterpret_cast(slice.data()), slice.length()); }; Slice s1{buffer.data(), ecGamalEncryptedLength}; @@ -352,15 +101,11 @@ makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2) } bool -serializeEcPair( - secp256k1_pubkey const& in1, - secp256k1_pubkey const& in2, - Buffer& buffer) +serializeEcPair(secp256k1_pubkey const& in1, secp256k1_pubkey const& in2, Buffer& buffer) { auto serializePubKey = [](secp256k1_pubkey const& pub, unsigned char* out) { size_t outLen = ecGamalEncryptedLength; // 33 bytes - int const ret = secp256k1_ec_pubkey_serialize( - secp256k1Context(), out, &outLen, &pub, SECP256K1_EC_COMPRESSED); + int const ret = secp256k1_ec_pubkey_serialize(secp256k1Context(), out, &outLen, &pub, SECP256K1_EC_COMPRESSED); return ret == 1 && outLen == ecGamalEncryptedLength; }; @@ -374,20 +119,29 @@ serializeEcPair( bool isValidCiphertext(Slice const& buffer) { - // Local/temporary variables to pass to makeEcPair. - // Their contents will be discarded when the function returns. secp256k1_pubkey key1; secp256k1_pubkey key2; - - // Call makeEcPair and return its result. return makeEcPair(buffer, key1, key2); } +bool +isValidCompressedECPoint(Slice const& buffer) +{ + if (buffer.size() != compressedECPointLength) + return false; + + // Compressed EC points must start with 0x02 or 0x03 + if (buffer[0] != 0x02 && buffer[0] != 0x03) + return false; + + secp256k1_pubkey point; + return secp256k1_ec_pubkey_parse(secp256k1Context(), &point, buffer.data(), buffer.size()) == 1; +} + TER homomorphicAdd(Slice const& a, Slice const& b, Buffer& out) { - if (a.length() != ecGamalEncryptedTotalLength || - b.length() != ecGamalEncryptedTotalLength) + if (a.length() != ecGamalEncryptedTotalLength || b.length() != ecGamalEncryptedTotalLength) return tecINTERNAL; secp256k1_pubkey aC1; @@ -401,8 +155,7 @@ homomorphicAdd(Slice const& a, Slice const& b, Buffer& out) secp256k1_pubkey sumC1; secp256k1_pubkey sumC2; - if (secp256k1_elgamal_add( - secp256k1Context(), &sumC1, &sumC2, &aC1, &aC2, &bC1, &bC2) != 1) + if (secp256k1_elgamal_add(secp256k1Context(), &sumC1, &sumC2, &aC1, &aC2, &bC1, &bC2) != 1) return tecINTERNAL; if (!serializeEcPair(sumC1, sumC2, out)) @@ -414,8 +167,7 @@ homomorphicAdd(Slice const& a, Slice const& b, Buffer& out) TER homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out) { - if (a.length() != ecGamalEncryptedTotalLength || - b.length() != ecGamalEncryptedTotalLength) + if (a.length() != ecGamalEncryptedTotalLength || b.length() != ecGamalEncryptedTotalLength) return tecINTERNAL; secp256k1_pubkey aC1; @@ -429,8 +181,7 @@ homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out) secp256k1_pubkey diffC1; secp256k1_pubkey diffC2; - if (secp256k1_elgamal_subtract( - secp256k1Context(), &diffC1, &diffC2, &aC1, &aC2, &bC1, &bC2) != 1) + if (secp256k1_elgamal_subtract(secp256k1Context(), &diffC1, &diffC2, &aC1, &aC2, &bC1, &bC2) != 1) return tecINTERNAL; if (!serializeEcPair(diffC1, diffC2, out)) @@ -439,169 +190,470 @@ homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out) return tesSUCCESS; } -TER -proveEquality( - Slice const& proof, - Slice const& encAmt, // encrypted amount - Slice const& pubkey, - uint64_t const amount, - uint256 const& txHash, // Transaction context data - std::uint32_t const spendVersion) +Buffer +generateBlindingFactor() { - if (proof.length() != ecEqualityProofLength) + unsigned char blindingFactor[ecBlindingFactorLength]; + + // todo: might need to be updated using another RNG + if (RAND_bytes(blindingFactor, ecBlindingFactorLength) != 1) + Throw("Failed to generate random number"); + + return Buffer(blindingFactor, ecBlindingFactorLength); +} + +std::optional +encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor) +{ + if (blindingFactor.size() != ecBlindingFactorLength) + return std::nullopt; + + if (pubKeySlice.size() != ecPubKeyLength) + return std::nullopt; + + secp256k1_pubkey c1, c2, pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return std::nullopt; + + if (!secp256k1_elgamal_encrypt(secp256k1Context(), &c1, &c2, &pubKey, amt, blindingFactor.data())) + return std::nullopt; + + Buffer buf(ecGamalEncryptedTotalLength); + if (!serializeEcPair(c1, c2, buf)) + return std::nullopt; + + return buf; +} + +std::optional +encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId) +{ + if (pubKeySlice.size() != ecPubKeyLength) + return std::nullopt; // LCOV_EXCL_LINE + + secp256k1_pubkey c1, c2, pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return std::nullopt; // LCOV_EXCL_LINE + + if (!generate_canonical_encrypted_zero(secp256k1Context(), &c1, &c2, &pubKey, account.data(), mptId.data())) + return std::nullopt; // LCOV_EXCL_LINE + + Buffer buf(ecGamalEncryptedTotalLength); + if (!serializeEcPair(c1, c2, buf)) + return std::nullopt; // LCOV_EXCL_LINE + + return buf; +} + +TER +verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash) +{ + if (proofSlice.size() != ecSchnorrProofLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (pubKeySlice.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (secp256k1_mpt_pok_sk_verify(secp256k1Context(), proofSlice.data(), &pubKey, contextHash.data()) != 1) + return tecBAD_PROOF; + + return tesSUCCESS; +} + +TER +verifyElGamalEncryption( + std::uint64_t const amount, + Slice const& blindingFactor, + Slice const& pubKeySlice, + Slice const& ciphertext) +{ + if (blindingFactor.size() != ecBlindingFactorLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (pubKeySlice.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey c1, c2; + if (!makeEcPair(ciphertext, c1, c2)) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (secp256k1_elgamal_verify_encryption(secp256k1Context(), &c1, &c2, &pubKey, amount, blindingFactor.data()) != 1) + return tecBAD_PROOF; + + return tesSUCCESS; +} + +TER +verifyRevealedAmount( + std::uint64_t const amount, + Slice const& blindingFactor, + ConfidentialRecipient const& holder, + ConfidentialRecipient const& issuer, + std::optional const& auditor) +{ + if (auto const res = verifyElGamalEncryption(amount, blindingFactor, holder.publicKey, holder.encryptedAmount); + !isTesSuccess(res)) + { + return res; + } + + if (auto const res = verifyElGamalEncryption(amount, blindingFactor, issuer.publicKey, issuer.encryptedAmount); + !isTesSuccess(res)) + { + return res; + } + + if (auditor) + { + if (auto const res = + verifyElGamalEncryption(amount, blindingFactor, auditor->publicKey, auditor->encryptedAmount); + !isTesSuccess(res)) + { + return res; + } + } + + return tesSUCCESS; +} + +std::size_t +getMultiCiphertextEqualityProofSize(std::size_t nRecipients) +{ + // Points (33 bytes): T_m (1) + T_rG (nRecipients) + T_rP (nRecipients) = 1 + // + 2nRecipients Scalars (32 bytes): s_m (1) + s_r (nRecipients) = 1 + + // nRecipients + return ((1 + (2 * nRecipients)) * 33) + ((1 + nRecipients) * 32); +} + +TER +verifyMultiCiphertextEqualityProof( + Slice const& proof, + std::vector const& recipients, + std::size_t const nRecipients, + uint256 const& contextHash) +{ + if (recipients.size() != nRecipients) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (proof.size() != getMultiCiphertextEqualityProofSize(nRecipients)) + return tecINTERNAL; // LCOV_EXCL_LINE + + std::vector r(nRecipients); + std::vector s(nRecipients); + std::vector pk(nRecipients); + + for (size_t i = 0; i < nRecipients; ++i) + { + auto const& recipient = recipients[i]; + if (recipient.encryptedAmount.size() != ecGamalEncryptedTotalLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (!makeEcPair(recipient.encryptedAmount, r[i], s[i])) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (recipient.publicKey.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pk[i], recipient.publicKey.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + } + + int const result = secp256k1_mpt_verify_same_plaintext_multi( + secp256k1Context(), proof.data(), proof.size(), nRecipients, r.data(), s.data(), pk.data(), contextHash.data()); + + if (result != 1) + return tecBAD_PROOF; + + return tesSUCCESS; +} + +TER +verifyClawbackEqualityProof( + uint64_t const amount, + Slice const& proof, + Slice const& pubKeySlice, + Slice const& ciphertext, + uint256 const& contextHash) +{ + secp256k1_pubkey c1, c2; + if (!makeEcPair(ciphertext, c1, c2)) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (pubKeySlice.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Note: c2, c1 order - the proof is generated with c2 first (the encrypted + // message component) because the equality proof structure expects the + // message-containing term before the blinding term. + if (secp256k1_equality_plaintext_verify( + secp256k1Context(), proof.data(), &pubKey, &c2, &c1, amount, contextHash.data()) != 1) + { + return tecBAD_PROOF; + } + + return tesSUCCESS; +} + +NotTEC +checkEncryptedAmountFormat(STObject const& object) +{ + // Current usage of this function is only for ConfidentialMPTConvert and + // ConfidentialMPTConvertBack transactions, which already enforce that these fields + // are present. + if (!object.isFieldPresent(sfHolderEncryptedAmount) || !object.isFieldPresent(sfIssuerEncryptedAmount)) + return temMALFORMED; // LCOV_EXCL_LINE + + if (object[sfHolderEncryptedAmount].length() != ecGamalEncryptedTotalLength || + object[sfIssuerEncryptedAmount].length() != ecGamalEncryptedTotalLength) + return temBAD_CIPHERTEXT; + + bool const hasAuditor = object.isFieldPresent(sfAuditorEncryptedAmount); + if (hasAuditor && object[sfAuditorEncryptedAmount].length() != ecGamalEncryptedTotalLength) + return temBAD_CIPHERTEXT; + + if (!isValidCiphertext(object[sfHolderEncryptedAmount]) || !isValidCiphertext(object[sfIssuerEncryptedAmount])) + return temBAD_CIPHERTEXT; + + if (hasAuditor && !isValidCiphertext(object[sfAuditorEncryptedAmount])) + return temBAD_CIPHERTEXT; + + return tesSUCCESS; +} + +TER +verifyAmountPcmLinkage( + Slice const& proof, + Slice const& encAmt, + Slice const& pubKeySlice, + Slice const& pcmSlice, + uint256 const& contextHash) +{ + if (proof.length() != ecPedersenProofLength) + return tecINTERNAL; + + secp256k1_pubkey c1, c2; + if (!makeEcPair(encAmt, c1, c2)) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (pubKeySlice.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (pcmSlice.size() != ecPedersenCommitmentLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pcm; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (secp256k1_elgamal_pedersen_link_verify( + secp256k1Context(), proof.data(), &c1, &c2, &pubKey, &pcm, contextHash.data()) != 1) + { + return tecBAD_PROOF; + } + + return tesSUCCESS; +} + +TER +verifyBalancePcmLinkage( + Slice const& proof, + Slice const& encAmt, + Slice const& pubKeySlice, + Slice const& pcmSlice, + uint256 const& contextHash) +{ + if (proof.length() != ecPedersenProofLength) return tecINTERNAL; secp256k1_pubkey c1; secp256k1_pubkey c2; if (!makeEcPair(encAmt, c1, c2)) - return tecINTERNAL; + return tecINTERNAL; // LCOV_EXCL_LINE - // todo: might need to change how its hashed - Serializer s; - s.addRaw(txHash.data(), txHash.bytes); - s.add32(spendVersion); - // auto const txContextId = s.getSHA512Half(); + if (pubKeySlice.size() != ecPubKeyLength) + return tecINTERNAL; // LCOV_EXCL_LINE - // todo: support equality - // if (secp256k1_equality_verify( - // secp256k1Context(), - // reinterpret_cast(proof.data()), - // proof.length(), // Length of the proof byte array (98 bytes) - // &c1, - // &c2, - // reinterpret_cast(pubkey.data()), - // amount, - // txContextId.data(), // Transaction context data - // txContextId.bytes // Length of context data - // ) != 1) - // return tecBAD_PROOF; + if (pcmSlice.size() != ecPedersenCommitmentLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pubKey; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + secp256k1_pubkey pcm; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Note: c2, c1 order - the linkage proof expects the message-containing + // component (c2 = m*G + r*Pk) before the blinding component (c1 = r*G). + if (secp256k1_elgamal_pedersen_link_verify( + secp256k1Context(), proof.data(), &pubKey, &c2, &c1, &pcm, contextHash.data()) != 1) + { + return tecBAD_PROOF; + } return tesSUCCESS; } -Buffer -encryptAmount(uint64_t amt, Slice const& pubKeySlice) -{ - Buffer buf(ecGamalEncryptedTotalLength); - - // Allocate ciphertext placeholders - secp256k1_pubkey c1, c2; - - // todo: might need to be updated using another RNG - // Prepare a random blinding factor - unsigned char blindingFactor[32]; - if (RAND_bytes(blindingFactor, 32) != 1) - Throw("Failed to generate random number"); - - secp256k1_pubkey pubKey; - - std::memcpy(pubKey.data, pubKeySlice.data(), ecPubKeyLength); - - // Encrypt the amount - if (!secp256k1_elgamal_encrypt( - secp256k1Context(), &c1, &c2, &pubKey, amt, blindingFactor)) - Throw("Failed to encrypt amount"); - - // Serialize the ciphertext pair into the buffer - if (!serializeEcPair(c1, c2, buf)) - Throw( - "Failed to serialize into 66 byte compressed format"); - - return buf; -} - -Buffer -encryptCanonicalZeroAmount( - Slice const& pubKeySlice, - AccountID const& account, - MPTID const& mptId) -{ - Buffer buf(ecGamalEncryptedTotalLength); - - // Allocate ciphertext placeholders - secp256k1_pubkey c1, c2; - secp256k1_pubkey pubKey; - - std::memcpy(pubKey.data, pubKeySlice.data(), ecPubKeyLength); - - // Encrypt the amount - if (!generate_canonical_encrypted_zero( - secp256k1Context(), - &c1, - &c2, - &pubKey, - account.data(), - mptId.data())) - Throw("Failed to encrypt amount"); - - // Serialize the ciphertext pair into the buffer - if (!serializeEcPair(c1, c2, buf)) - Throw( - "Failed to serialize into 66 byte compressed format"); - - return buf; -} - TER -verifyConfidentialSendProof( +verifyAggregatedBulletproof( Slice const& proof, - Slice const& encSenderBalance, - Slice const& encSenderAmt, - Slice const& encDestAmt, - Slice const& encIssuerAmt, - Slice const& senderPubKey, - Slice const& destPubKey, - Slice const& issuerPubKey, - std::uint32_t const version, - uint256 const& txHash) + std::vector const& compressedCommitments, + uint256 const& contextHash) { - // if (proof.length() != ecConfidentialSendProofLength) - // return tecINTERNAL; + // 1. Validate Aggregation Factor (m), m to be a power of 2 + std::size_t const m = compressedCommitments.size(); + if (m == 0 || (m & (m - 1)) != 0) + return tecINTERNAL; // LCOV_EXCL_LINE - secp256k1_pubkey balC1, balC2; - if (!makeEcPair(encSenderBalance, balC1, balC2)) - return tecINTERNAL; + // 2. Prepare Pedersen Commitments, parse from compressed format + auto const ctx = secp256k1Context(); + std::vector commitments(m); + for (size_t i = 0; i < m; ++i) + { + // Sanity check length + if (compressedCommitments[i].size() != ecPedersenCommitmentLength) + return tecINTERNAL; // LCOV_EXCL_LINE - secp256k1_pubkey senderC1, senderC2; - if (!makeEcPair(encSenderAmt, senderC1, senderC2)) - return tecINTERNAL; + if (secp256k1_ec_pubkey_parse( + ctx, &commitments[i], compressedCommitments[i].data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + } - secp256k1_pubkey destC1, destC2; - if (!makeEcPair(encDestAmt, destC1, destC2)) - return tecINTERNAL; + // 3. Prepare Generator Vectors (G_vec, H_vec) + // The range proof requires vectors of size 64 * m + std::size_t const n = 64 * m; + std::vector G_vec(n); + std::vector H_vec(n); - secp256k1_pubkey issuerC1, issuerC2; - if (!makeEcPair(encIssuerAmt, issuerC1, issuerC2)) - return tecINTERNAL; + // Retrieve deterministic generators "G" and "H" + if (secp256k1_mpt_get_generator_vector(ctx, G_vec.data(), n, (unsigned char const*)"G", 1) != 1) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } - Serializer s; - s.addRaw(txHash.data(), txHash.bytes); - s.add32(version); - // auto const txContextId = s.getSHA512Half(); + if (secp256k1_mpt_get_generator_vector(ctx, H_vec.data(), n, (unsigned char const*)"H", 1) != 1) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } - // todo: equality and range proof verification - // if (secp256k1_equal_range_verify( - // secp256k1Context(), - // reinterpret_cast(proof.data()), - // proof.length(), - // txContextId.data(), - // &balC1, - // &balC2, - // &senderC1, - // &senderC2, - // reinterpret_cast(senderPubKey.data()), - // &destC1, - // &destC2, - // reinterpret_cast(destPubKey.data()), - // &issuerC1, - // &issuerC2, - // reinterpret_cast(issuerPubKey.data()), - // txContextId.data(), - // txContextId.bytes) != 1) - // return tecBAD_PROOF; + // 4. Prepare Base Generator (pk_base / H) + secp256k1_pubkey pk_base; + if (secp256k1_mpt_get_h_generator(ctx, &pk_base) != 1) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + + // 5. Verify the Proof + int const result = secp256k1_bulletproof_verify_agg( + ctx, + G_vec.data(), + H_vec.data(), + reinterpret_cast(proof.data()), + proof.size(), + commitments.data(), + m, + &pk_base, + contextHash.data()); + + if (result != 1) + return tecBAD_PROOF; return tesSUCCESS; } -} // namespace ripple +TER +computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitment, Buffer& out) +{ + if (balanceCommitment.size() != ecPedersenCommitmentLength || amountCommitment.size() != ecPedersenCommitmentLength) + return tecINTERNAL; + + auto const ctx = secp256k1Context(); + + secp256k1_pubkey pcBalance; + if (secp256k1_ec_pubkey_parse(ctx, &pcBalance, balanceCommitment.data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; + + secp256k1_pubkey pcAmount; + if (secp256k1_ec_pubkey_parse(ctx, &pcAmount, amountCommitment.data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; + + // Negate PC_amount point to get -PC_amount + if (!secp256k1_ec_pubkey_negate(ctx, &pcAmount)) + return tecINTERNAL; + + // Compute pcRem = pcBalance + (-pcAmount) + secp256k1_pubkey const* summands[2] = {&pcBalance, &pcAmount}; + secp256k1_pubkey pcRem; + if (!secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2)) + return tecINTERNAL; + + // Serialize result to compressed format + out.alloc(ecPedersenCommitmentLength); + size_t outLen = ecPedersenCommitmentLength; + if (secp256k1_ec_pubkey_serialize(ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED) != 1) + return tecINTERNAL; + + return tesSUCCESS; +} + +TER +computeConvertBackRemainder(Slice const& commitment, std::uint64_t amount, Buffer& out) +{ + if (commitment.size() != ecPedersenCommitmentLength || amount == 0) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const ctx = secp256k1Context(); + + // Parse commitment from compressed format + secp256k1_pubkey pcBalance; + if (secp256k1_ec_pubkey_parse(ctx, &pcBalance, commitment.data(), ecPedersenCommitmentLength) != 1) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Convert amount to 32-byte big-endian scalar + unsigned char mScalar[32] = {0}; + std::uint64_t amountBigEndian = boost::endian::native_to_big(amount); + std::memcpy(&mScalar[24], &amountBigEndian, sizeof(amountBigEndian)); + + // Compute mG = amount * G + secp256k1_pubkey mG; + if (!secp256k1_ec_pubkey_create(ctx, &mG, mScalar)) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Negate mG to get -mG + if (!secp256k1_ec_pubkey_negate(ctx, &mG)) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Compute pcRem = pcBalance + (-mG) + secp256k1_pubkey const* summands[2] = {&pcBalance, &mG}; + secp256k1_pubkey pcRem; + if (!secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2)) + return tecINTERNAL; // LCOV_EXCL_LINE + + // Serialize result to compressed format + out.alloc(ecPedersenCommitmentLength); + size_t outLen = ecPedersenCommitmentLength; + if (secp256k1_ec_pubkey_serialize(ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED) != 1 || + outLen != ecPedersenCommitmentLength) + return tecINTERNAL; // LCOV_EXCL_LINE + + return tesSUCCESS; +} +} // namespace xrpl diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index ec295343ce..33ec869db6 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 - 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace RPC { namespace detail { @@ -179,6 +160,24 @@ constexpr ErrorInfo unknownError; //------------------------------------------------------------------------------ +void +inject_error(error_code_i code, Json::Value& json) +{ + ErrorInfo const& info(get_error_info(code)); + json[jss::error] = info.token; + json[jss::error_code] = info.code; + json[jss::error_message] = info.message; +} + +void +inject_error(error_code_i code, std::string const& message, Json::Value& json) +{ + ErrorInfo const& info(get_error_info(code)); + json[jss::error] = info.token; + json[jss::error_code] = info.code; + json[jss::error_message] = message; +} + ErrorInfo const& get_error_info(error_code_i code) { @@ -222,10 +221,8 @@ error_code_http_status(error_code_i code) std::string rpcErrorString(Json::Value const& jv) { - XRPL_ASSERT( - RPC::contains_error(jv), - "ripple::RPC::rpcErrorString : input contains an error"); + XRPL_ASSERT(RPC::contains_error(jv), "xrpl::RPC::rpcErrorString : input contains an error"); return jv[jss::error].asString() + jv[jss::error_message].asString(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index eeeee1c185..834341f8d6 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -38,10 +19,10 @@ #include #include -namespace ripple { +namespace xrpl { inline std::size_t -hash_value(ripple::uint256 const& feature) +hash_value(xrpl::uint256 const& feature) { std::size_t seed = 0; using namespace boost; @@ -89,8 +70,7 @@ class FeatureCollections uint256 feature; Feature() = delete; - explicit Feature(std::string const& name_, uint256 const& feature_) - : name(name_), feature(feature_) + explicit Feature(std::string const& name_, uint256 const& feature_) : name(name_), feature(feature_) { } @@ -110,21 +90,18 @@ class FeatureCollections // Intermediate types to help with readability template - using feature_hashed_unique = boost::multi_index::hashed_unique< - boost::multi_index::tag, - boost::multi_index::member>; + using feature_hashed_unique = boost::multi_index:: + hashed_unique, boost::multi_index::member>; // Intermediate types to help with readability using feature_indexing = boost::multi_index::indexed_by< - boost::multi_index::random_access< - boost::multi_index::tag>, + boost::multi_index::random_access>, feature_hashed_unique, feature_hashed_unique>; // This multi_index_container provides access to the features collection by // name, index, and uint256 feature identifier - boost::multi_index::multi_index_container - features; + boost::multi_index::multi_index_container features; std::map all; std::map supported; std::size_t upVotes = 0; @@ -171,10 +148,7 @@ public: getRegisteredFeature(std::string const& name) const; uint256 - registerFeature( - std::string const& name, - Supported support, - VoteBehavior vote); + registerFeature(std::string const& name, Supported support, VoteBehavior vote); /** Tell FeatureCollections when registration is complete. */ bool @@ -224,15 +198,13 @@ public: FeatureCollections::FeatureCollections() { - features.reserve(ripple::detail::numFeatures); + features.reserve(xrpl::detail::numFeatures); } std::optional FeatureCollections::getRegisteredFeature(std::string const& name) const { - XRPL_ASSERT( - readOnly.load(), - "ripple::FeatureCollections::getRegisteredFeature : startup completed"); + XRPL_ASSERT(readOnly.load(), "xrpl::FeatureCollections::getRegisteredFeature : startup completed"); Feature const* feature = getByName(name); if (feature) return feature->feature; @@ -247,10 +219,7 @@ check(bool condition, char const* logicErrorMessage) } uint256 -FeatureCollections::registerFeature( - std::string const& name, - Supported support, - VoteBehavior vote) +FeatureCollections::registerFeature(std::string const& name, Supported support, VoteBehavior vote) { check(!readOnly, "Attempting to register a feature after startup."); check( @@ -259,9 +228,7 @@ FeatureCollections::registerFeature( Feature const* i = getByName(name); if (!i) { - check( - features.size() < detail::numFeatures, - "More features defined than allocated."); + check(features.size() < detail::numFeatures, "More features defined than allocated."); auto const f = sha512Half(Slice(name.data(), name.size())); @@ -270,8 +237,7 @@ FeatureCollections::registerFeature( auto const getAmendmentSupport = [=]() { if (vote == VoteBehavior::Obsolete) return AmendmentSupport::Retired; - return support == Supported::yes ? AmendmentSupport::Supported - : AmendmentSupport::Unsupported; + return support == Supported::yes ? AmendmentSupport::Supported : AmendmentSupport::Unsupported; }; all.emplace(name, getAmendmentSupport()); @@ -284,15 +250,9 @@ FeatureCollections::registerFeature( else ++downVotes; } - check( - upVotes + downVotes == supported.size(), - "Feature counting logic broke"); - check( - supported.size() <= features.size(), - "More supported features than defined features"); - check( - features.size() == all.size(), - "The 'all' features list is populated incorrectly"); + check(upVotes + downVotes == supported.size(), "Feature counting logic broke"); + check(supported.size() <= features.size(), "More supported features than defined features"); + check(features.size() == all.size(), "The 'all' features list is populated incorrectly"); return f; } else @@ -311,9 +271,7 @@ FeatureCollections::registrationIsDone() size_t FeatureCollections::featureToBitsetIndex(uint256 const& f) const { - XRPL_ASSERT( - readOnly.load(), - "ripple::FeatureCollections::featureToBitsetIndex : startup completed"); + XRPL_ASSERT(readOnly.load(), "xrpl::FeatureCollections::featureToBitsetIndex : startup completed"); Feature const* feature = getByFeature(f); if (!feature) @@ -325,9 +283,7 @@ FeatureCollections::featureToBitsetIndex(uint256 const& f) const uint256 const& FeatureCollections::bitsetIndexToFeature(size_t i) const { - XRPL_ASSERT( - readOnly.load(), - "ripple::FeatureCollections::bitsetIndexToFeature : startup completed"); + XRPL_ASSERT(readOnly.load(), "xrpl::FeatureCollections::bitsetIndexToFeature : startup completed"); Feature const& feature = getByIndex(i); return feature.feature; } @@ -335,9 +291,7 @@ FeatureCollections::bitsetIndexToFeature(size_t i) const std::string FeatureCollections::featureToName(uint256 const& f) const { - XRPL_ASSERT( - readOnly.load(), - "ripple::FeatureCollections::featureToName : startup completed"); + XRPL_ASSERT(readOnly.load(), "xrpl::FeatureCollections::featureToName : startup completed"); Feature const* feature = getByFeature(f); return feature ? feature->name : to_string(f); } @@ -430,25 +384,32 @@ featureToName(uint256 const& f) #undef XRPL_FEATURE #pragma push_macro("XRPL_FIX") #undef XRPL_FIX -#pragma push_macro("XRPL_RETIRE") -#undef XRPL_RETIRE +#pragma push_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FEATURE +#pragma push_macro("XRPL_RETIRE_FIX") +#undef XRPL_RETIRE_FIX -#define XRPL_FEATURE(name, supported, vote) \ - uint256 const feature##name = registerFeature(#name, supported, vote); -#define XRPL_FIX(name, supported, vote) \ - uint256 const fix##name = registerFeature("fix" #name, supported, vote); +#define XRPL_FEATURE(name, supported, vote) uint256 const feature##name = registerFeature(#name, supported, vote); +#define XRPL_FIX(name, supported, vote) uint256 const fix##name = registerFeature("fix" #name, supported, vote); // clang-format off -#define XRPL_RETIRE(name) \ - [[deprecated("The referenced amendment has been retired")]] \ - [[maybe_unused]] \ - uint256 const retired##name = retireFeature(#name); +#define XRPL_RETIRE_FEATURE(name) \ + [[deprecated("The referenced feature amendment has been retired")]] \ + [[maybe_unused]] \ + uint256 const retiredFeature##name = retireFeature(#name); + +#define XRPL_RETIRE_FIX(name) \ + [[deprecated("The referenced fix amendment has been retired")]] \ + [[maybe_unused]] \ + uint256 const retiredFix##name = retireFeature("fix" #name); // clang-format on #include -#undef XRPL_RETIRE -#pragma pop_macro("XRPL_RETIRE") +#undef XRPL_RETIRE_FEATURE +#pragma pop_macro("XRPL_RETIRE_FEATURE") +#undef XRPL_RETIRE_FIX +#pragma pop_macro("XRPL_RETIRE_FIX") #undef XRPL_FIX #pragma pop_macro("XRPL_FIX") #undef XRPL_FEATURE @@ -459,7 +420,6 @@ featureToName(uint256 const& f) // // Use initialization of one final static variable to set // featureCollections::readOnly. -[[maybe_unused]] static bool const readOnlySet = - featureCollections.registrationIsDone(); +[[maybe_unused]] static bool const readOnlySet = featureCollections.registrationIsDone(); -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/IOUAmount.cpp b/src/libxrpl/protocol/IOUAmount.cpp index 9bd1ceb5eb..cfad753edc 100644 --- a/src/libxrpl/protocol/IOUAmount.cpp +++ b/src/libxrpl/protocol/IOUAmount.cpp @@ -1,27 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - +#include +// Do not remove. Forces IOUAmount.h to stay first, to verify it can compile +// without any hidden dependencies #include #include #include #include -#include +#include #include @@ -33,11 +17,11 @@ #include #include -namespace ripple { +namespace xrpl { namespace { -// Use a static inside a function to help prevent order-of-initialzation issues +// Use a static inside a function to help prevent order-of-initialization issues LocalValue& getStaticSTNumberSwitchover() { @@ -59,11 +43,23 @@ setSTNumberSwitchover(bool v) } /* The range for the mantissa when normalized */ -static std::int64_t constexpr minMantissa = 1000000000000000ull; -static std::int64_t constexpr maxMantissa = 9999999999999999ull; +// log(2^63,10) ~ 18.96 +// +static std::int64_t constexpr minMantissa = STAmount::cMinValue; +static std::int64_t constexpr maxMantissa = STAmount::cMaxValue; /* The range for the exponent when normalized */ -static int constexpr minExponent = -96; -static int constexpr maxExponent = 80; +static int constexpr minExponent = STAmount::cMinOffset; +static int constexpr maxExponent = STAmount::cMaxOffset; + +IOUAmount +IOUAmount::fromNumber(Number const& number) +{ + // Need to create a default IOUAmount and assign directly so it doesn't try + // to normalize, which calls fromNumber + IOUAmount result{}; + std::tie(result.mantissa_, result.exponent_) = number.normalizeToRange(minMantissa, maxMantissa); + return result; +} IOUAmount IOUAmount::minPositiveAmount() @@ -83,8 +79,7 @@ IOUAmount::normalize() if (getSTNumberSwitchover()) { Number const v{mantissa_, exponent_}; - mantissa_ = v.mantissa(); - exponent_ = v.exponent(); + *this = fromNumber(v); if (exponent_ > maxExponent) Throw("value overflow"); if (exponent_ < minExponent) @@ -125,8 +120,7 @@ IOUAmount::normalize() mantissa_ = -mantissa_; } -IOUAmount::IOUAmount(Number const& other) - : mantissa_(other.mantissa()), exponent_(other.exponent()) +IOUAmount::IOUAmount(Number const& other) : IOUAmount(fromNumber(other)) { if (exponent_ > maxExponent) Throw("value overflow"); @@ -187,11 +181,7 @@ to_string(IOUAmount const& amount) } IOUAmount -mulRatio( - IOUAmount const& amt, - std::uint32_t num, - std::uint32_t den, - bool roundUp) +mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp) { using namespace boost::multiprecision; @@ -218,8 +208,7 @@ mulRatio( static auto log10Floor = [](uint128_t const& v) { // Find the index of the first element >= the requested element, the // index is the log of the element in the log table. - auto const l = - std::lower_bound(powerTable.begin(), powerTable.end(), v); + auto const l = std::lower_bound(powerTable.begin(), powerTable.end(), v); int index = std::distance(powerTable.begin(), l); // If we're not equal, subtract to get the floor if (*l != v) @@ -231,20 +220,17 @@ mulRatio( static auto log10Ceil = [](uint128_t const& v) { // Find the index of the first element >= the requested element, the // index is the log of the element in the log table. - auto const l = - std::lower_bound(powerTable.begin(), powerTable.end(), v); + auto const l = std::lower_bound(powerTable.begin(), powerTable.end(), v); return int(std::distance(powerTable.begin(), l)); }; - static auto const fl64 = - log10Floor(std::numeric_limits::max()); + static auto const fl64 = log10Floor(std::numeric_limits::max()); bool const neg = amt.mantissa() < 0; uint128_t const den128(den); // a 32 value * a 64 bit value and stored in a 128 bit value. This will // never overflow - uint128_t const mul = - uint128_t(neg ? -amt.mantissa() : amt.mantissa()) * uint128_t(num); + uint128_t const mul = uint128_t(neg ? -amt.mantissa() : amt.mantissa()) * uint128_t(num); auto low = mul / den128; uint128_t rem(mul - low * den128); @@ -322,4 +308,4 @@ mulRatio( return result; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 486945992a..33c836eab6 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -44,7 +25,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Type-specific prefix for calculating ledger indices. @@ -96,6 +77,8 @@ enum class LedgerNameSpace : std::uint16_t { PERMISSIONED_DOMAIN = 'm', DELEGATE = 'E', VAULT = 'V', + LOAN_BROKER = 'l', // lower-case L + LOAN = 'L', // No longer used or supported. Left here to reserve the space // to avoid accidental reuse. @@ -114,22 +97,17 @@ indexHash(LedgerNameSpace space, Args const&... args) uint256 getBookBase(Book const& book) { - XRPL_ASSERT( - isConsistent(book), "ripple::getBookBase : input is consistent"); + XRPL_ASSERT(isConsistent(book), "xrpl::getBookBase : input is consistent"); - auto const index = book.domain ? indexHash( - LedgerNameSpace::BOOK_DIR, - book.in.currency, - book.out.currency, - book.in.account, - book.out.account, - *(book.domain)) - : indexHash( - LedgerNameSpace::BOOK_DIR, - book.in.currency, - book.out.currency, - book.in.account, - book.out.account); + auto const index = book.domain + ? indexHash( + LedgerNameSpace::BOOK_DIR, + book.in.currency, + book.out.currency, + book.in.account, + book.out.account, + *(book.domain)) + : indexHash(LedgerNameSpace::BOOK_DIR, book.in.currency, book.out.currency, book.in.account, book.out.account); // Return with quality 0. auto k = keylet::quality({ltDIR_NODE, index}, 0); @@ -140,9 +118,8 @@ getBookBase(Book const& book) uint256 getQualityNext(uint256 const& uBase) { - static constexpr uint256 nextq( - "0000000000000000000000000000000000000000000000010000000000000000"); - return uBase + nextq; + static constexpr uint256 nextQuality("0000000000000000000000000000000000000000000000010000000000000000"); + return uBase + nextQuality; } std::uint64_t @@ -155,14 +132,13 @@ getQuality(uint256 const& uBase) uint256 getTicketIndex(AccountID const& account, std::uint32_t ticketSeq) { - return indexHash( - LedgerNameSpace::TICKET, account, std::uint32_t(ticketSeq)); + return indexHash(LedgerNameSpace::TICKET, account, std::uint32_t(ticketSeq)); } uint256 getTicketIndex(AccountID const& account, SeqProxy ticketSeq) { - XRPL_ASSERT(ticketSeq.isTicket(), "ripple::getTicketIndex : valid input"); + XRPL_ASSERT(ticketSeq.isTicket(), "xrpl::getTicketIndex : valid input"); return getTicketIndex(account, ticketSeq.value()); } @@ -195,8 +171,7 @@ child(uint256 const& key) noexcept Keylet const& skip() noexcept { - static Keylet const ret{ - ltLEDGER_HASHES, indexHash(LedgerNameSpace::SKIP_LIST)}; + static Keylet const ret{ltLEDGER_HASHES, indexHash(LedgerNameSpace::SKIP_LIST)}; return ret; } @@ -205,32 +180,27 @@ skip(LedgerIndex ledger) noexcept { return { ltLEDGER_HASHES, - indexHash( - LedgerNameSpace::SKIP_LIST, - std::uint32_t(static_cast(ledger) >> 16))}; + indexHash(LedgerNameSpace::SKIP_LIST, std::uint32_t(static_cast(ledger) >> 16))}; } Keylet const& amendments() noexcept { - static Keylet const ret{ - ltAMENDMENTS, indexHash(LedgerNameSpace::AMENDMENTS)}; + static Keylet const ret{ltAMENDMENTS, indexHash(LedgerNameSpace::AMENDMENTS)}; return ret; } Keylet const& fees() noexcept { - static Keylet const ret{ - ltFEE_SETTINGS, indexHash(LedgerNameSpace::FEE_SETTINGS)}; + static Keylet const ret{ltFEE_SETTINGS, indexHash(LedgerNameSpace::FEE_SETTINGS)}; return ret; } Keylet const& negativeUNL() noexcept { - static Keylet const ret{ - ltNEGATIVE_UNL, indexHash(LedgerNameSpace::NEGATIVE_UNL)}; + static Keylet const ret{ltNEGATIVE_UNL, indexHash(LedgerNameSpace::NEGATIVE_UNL)}; return ret; } @@ -241,15 +211,12 @@ book_t::operator()(Book const& b) const } Keylet -line( - AccountID const& id0, - AccountID const& id1, - Currency const& currency) noexcept +line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept { // There is code in SetTrust that calls us with id0 == id1, to allow users // to locate and delete such "weird" trustlines. If we remove that code, we // could enable this assert: - // XRPL_ASSERT(id0 != id1, "ripple::keylet::line : accounts must be + // XRPL_ASSERT(id0 != id1, "xrpl::keylet::line : accounts must be // different"); // A trust line is shared between two accounts; while we typically think @@ -261,13 +228,7 @@ line( // two accounts (smallest then largest) and hash them in that order: auto const accounts = std::minmax(id0, id1); - return { - ltRIPPLE_STATE, - indexHash( - LedgerNameSpace::TRUST_LINE, - accounts.first, - accounts.second, - currency)}; + return {ltRIPPLE_STATE, indexHash(LedgerNameSpace::TRUST_LINE, accounts.first, accounts.second, currency)}; } Keylet @@ -279,8 +240,7 @@ offer(AccountID const& id, std::uint32_t seq) noexcept Keylet quality(Keylet const& k, std::uint64_t q) noexcept { - XRPL_ASSERT( - k.type == ltDIR_NODE, "ripple::keylet::quality : valid input type"); + XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::quality : valid input type"); // Indexes are stored in big endian format: they print as hex as stored. // Most significant bytes are first and the least significant bytes @@ -298,9 +258,7 @@ quality(Keylet const& k, std::uint64_t q) noexcept Keylet next_t::operator()(Keylet const& k) const { - XRPL_ASSERT( - k.type == ltDIR_NODE, - "ripple::keylet::next_t::operator() : valid input type"); + XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::next_t::operator() : valid input type"); return {ltDIR_NODE, getQualityNext(k.key)}; } @@ -322,8 +280,7 @@ ticket_t::operator()(AccountID const& id, SeqProxy ticketSeq) const static Keylet signers(AccountID const& account, std::uint32_t page) noexcept { - return { - ltSIGNER_LIST, indexHash(LedgerNameSpace::SIGNER_LIST, account, page)}; + return {ltSIGNER_LIST, indexHash(LedgerNameSpace::SIGNER_LIST, account, page)}; } Keylet @@ -341,25 +298,19 @@ check(AccountID const& id, std::uint32_t seq) noexcept Keylet depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept { - return { - ltDEPOSIT_PREAUTH, - indexHash(LedgerNameSpace::DEPOSIT_PREAUTH, owner, preauthorized)}; + return {ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DEPOSIT_PREAUTH, owner, preauthorized)}; } // Credentials should be sorted here, use credentials::makeSorted Keylet -depositPreauth( - AccountID const& owner, - std::set> const& authCreds) noexcept +depositPreauth(AccountID const& owner, std::set> const& authCreds) noexcept { std::vector hashes; hashes.reserve(authCreds.size()); for (auto const& o : authCreds) hashes.emplace_back(sha512Half(o.first, o.second)); - return { - ltDEPOSIT_PREAUTH, - indexHash(LedgerNameSpace::DEPOSIT_PREAUTH_CREDENTIALS, owner, hashes)}; + return {ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DEPOSIT_PREAUTH_CREDENTIALS, owner, hashes)}; } //------------------------------------------------------------------------------ @@ -394,9 +345,7 @@ escrow(AccountID const& src, std::uint32_t seq) noexcept Keylet payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept { - return { - ltPAYCHAN, - indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)}; + return {ltPAYCHAN, indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)}; } Keylet @@ -418,16 +367,14 @@ nftpage_max(AccountID const& owner) Keylet nftpage(Keylet const& k, uint256 const& token) { - XRPL_ASSERT( - k.type == ltNFTOKEN_PAGE, "ripple::keylet::nftpage : valid input type"); + XRPL_ASSERT(k.type == ltNFTOKEN_PAGE, "xrpl::keylet::nftpage : valid input type"); return {ltNFTOKEN_PAGE, (k.key & ~nft::pageMask) + (token & nft::pageMask)}; } Keylet nftoffer(AccountID const& owner, std::uint32_t seq) { - return { - ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NFTOKEN_OFFER, owner, seq)}; + return {ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NFTOKEN_OFFER, owner, seq)}; } Keylet @@ -445,14 +392,8 @@ nft_sells(uint256 const& id) noexcept Keylet amm(Asset const& issue1, Asset const& issue2) noexcept { - auto const& [minI, maxI] = - std::minmax(issue1.get(), issue2.get()); - return amm(indexHash( - LedgerNameSpace::AMM, - minI.account, - minI.currency, - maxI.account, - maxI.currency)); + auto const& [minI, maxI] = std::minmax(issue1.get(), issue2.get()); + return amm(indexHash(LedgerNameSpace::AMM, minI.account, minI.currency, maxI.account, maxI.currency)); } Keylet @@ -464,9 +405,7 @@ amm(uint256 const& id) noexcept Keylet delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept { - return { - ltDELEGATE, - indexHash(LedgerNameSpace::DELEGATE, account, authorizedAccount)}; + return {ltDELEGATE, indexHash(LedgerNameSpace::DELEGATE, account, authorizedAccount)}; } Keylet @@ -476,10 +415,7 @@ bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType) // there can only be one bridge per lockingChainCurrency. On the issuing // chain there can only be one bridge per issuingChainCurrency. auto const& issue = bridge.issue(chainType); - return { - ltBRIDGE, - indexHash( - LedgerNameSpace::BRIDGE, bridge.door(chainType), issue.currency)}; + return {ltBRIDGE, indexHash(LedgerNameSpace::BRIDGE, bridge.door(chainType), issue.currency)}; } Keylet @@ -531,9 +467,7 @@ mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept Keylet mptIssuance(MPTID const& issuanceID) noexcept { - return { - ltMPTOKEN_ISSUANCE, - indexHash(LedgerNameSpace::MPTOKEN_ISSUANCE, issuanceID)}; + return {ltMPTOKEN_ISSUANCE, indexHash(LedgerNameSpace::MPTOKEN_ISSUANCE, issuanceID)}; } Keylet @@ -545,19 +479,13 @@ mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept Keylet mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept { - return { - ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)}; + return {ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)}; } Keylet -credential( - AccountID const& subject, - AccountID const& issuer, - Slice const& credType) noexcept +credential(AccountID const& subject, AccountID const& issuer, Slice const& credType) noexcept { - return { - ltCREDENTIAL, - indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)}; + return {ltCREDENTIAL, indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)}; } Keylet @@ -566,12 +494,22 @@ vault(AccountID const& owner, std::uint32_t seq) noexcept return vault(indexHash(LedgerNameSpace::VAULT, owner, seq)); } +Keylet +loanbroker(AccountID const& owner, std::uint32_t seq) noexcept +{ + return loanbroker(indexHash(LedgerNameSpace::LOAN_BROKER, owner, seq)); +} + +Keylet +loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept +{ + return loan(indexHash(LedgerNameSpace::LOAN, loanBrokerID, loanSeq)); +} + Keylet permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept { - return { - ltPERMISSIONED_DOMAIN, - indexHash(LedgerNameSpace::PERMISSIONED_DOMAIN, account, seq)}; + return {ltPERMISSIONED_DOMAIN, indexHash(LedgerNameSpace::PERMISSIONED_DOMAIN, account, seq)}; } Keylet @@ -582,4 +520,4 @@ permissionedDomain(uint256 const& domainID) noexcept } // namespace keylet -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index 2de5e6624e..8139ef0f55 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { InnerObjectFormats::InnerObjectFormats() { @@ -155,9 +136,7 @@ InnerObjectFormats::InnerObjectFormats() {sfCredentialType, soeREQUIRED}, }); - add(sfPermission.jsonName.c_str(), - sfPermission.getCode(), - {{sfPermissionValue, soeREQUIRED}}); + add(sfPermission.jsonName.c_str(), sfPermission.getCode(), {{sfPermissionValue, soeREQUIRED}}); add(sfBatchSigner.jsonName.c_str(), sfBatchSigner.getCode(), @@ -172,6 +151,14 @@ InnerObjectFormats::InnerObjectFormats() {sfBookDirectory, soeREQUIRED}, {sfBookNode, soeREQUIRED}, }); + + add(sfCounterpartySignature.jsonName, + sfCounterpartySignature.getCode(), + { + {sfSigningPubKey, soeOPTIONAL}, + {sfTxnSignature, soeOPTIONAL}, + {sfSigners, soeOPTIONAL}, + }); } InnerObjectFormats const& @@ -191,4 +178,4 @@ InnerObjectFormats::findSOTemplateBySField(SField const& sField) const return nullptr; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Issue.cpp b/src/libxrpl/protocol/Issue.cpp index b6edf77b2a..f540b52050 100644 --- a/src/libxrpl/protocol/Issue.cpp +++ b/src/libxrpl/protocol/Issue.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { std::string Issue::getText() const @@ -68,6 +49,12 @@ Issue::native() const return *this == xrpIssue(); } +bool +Issue::integral() const +{ + return native(); +} + bool isConsistent(Issue const& ac) { @@ -96,14 +83,12 @@ issueFromJson(Json::Value const& v) { if (!v.isObject()) { - Throw( - "issueFromJson can only be specified with an 'object' Json value"); + Throw("issueFromJson can only be specified with an 'object' Json value"); } if (v.isMember(jss::mpt_issuance_id)) { - Throw( - "issueFromJson, Issue should not have mpt_issuance_id"); + Throw("issueFromJson, Issue should not have mpt_issuance_id"); } Json::Value const curStr = v[jss::currency]; @@ -111,8 +96,7 @@ issueFromJson(Json::Value const& v) if (!curStr.isString()) { - Throw( - "issueFromJson currency must be a string Json value"); + Throw("issueFromJson currency must be a string Json value"); } auto const currency = to_currency(curStr.asString()); @@ -151,4 +135,4 @@ operator<<(std::ostream& os, Issue const& x) return os; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Keylet.cpp b/src/libxrpl/protocol/Keylet.cpp index a83186547c..18bd76440a 100644 --- a/src/libxrpl/protocol/Keylet.cpp +++ b/src/libxrpl/protocol/Keylet.cpp @@ -1,35 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { bool Keylet::check(STLedgerEntry const& sle) const { - XRPL_ASSERT( - sle.getType() != ltANY || sle.getType() != ltCHILD, - "ripple::Keylet::check : valid input type"); + XRPL_ASSERT(sle.getType() != ltANY || sle.getType() != ltCHILD, "xrpl::Keylet::check : valid input type"); if (type == ltANY) return true; @@ -40,4 +19,4 @@ Keylet::check(STLedgerEntry const& sle) const return sle.getType() == type && sle.key() == key; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/LedgerFormats.cpp b/src/libxrpl/protocol/LedgerFormats.cpp index 94c6d65c88..8d9a24f741 100644 --- a/src/libxrpl/protocol/LedgerFormats.cpp +++ b/src/libxrpl/protocol/LedgerFormats.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { LedgerFormats::LedgerFormats() { @@ -41,8 +22,7 @@ LedgerFormats::LedgerFormats() #undef LEDGER_ENTRY #define UNWRAP(...) __VA_ARGS__ -#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \ - add(jss::name, tag, UNWRAP fields, commonFields); +#define LEDGER_ENTRY(tag, value, name, rpcName, fields) add(jss::name, tag, UNWRAP fields, commonFields); #include @@ -59,4 +39,4 @@ LedgerFormats::getInstance() return instance; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/LedgerHeader.cpp b/src/libxrpl/protocol/LedgerHeader.cpp index 9984a971c8..270833c6fa 100644 --- a/src/libxrpl/protocol/LedgerHeader.cpp +++ b/src/libxrpl/protocol/LedgerHeader.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { void addRaw(LedgerHeader const& info, Serializer& s, bool includeHash) @@ -53,8 +34,7 @@ deserializeHeader(Slice data, bool hasHash) header.parentHash = sit.get256(); header.txHash = sit.get256(); header.accountHash = sit.get256(); - header.parentCloseTime = - NetClock::time_point{NetClock::duration{sit.get32()}}; + header.parentCloseTime = NetClock::time_point{NetClock::duration{sit.get32()}}; header.closeTime = NetClock::time_point{NetClock::duration{sit.get32()}}; header.closeTimeResolution = NetClock::duration{sit.get8()}; header.closeFlags = sit.get8(); @@ -71,4 +51,4 @@ deserializePrefixedHeader(Slice data, bool hasHash) return deserializeHeader(data + 4, hasHash); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/MPTAmount.cpp b/src/libxrpl/protocol/MPTAmount.cpp index 17bbedea45..1950407ab5 100644 --- a/src/libxrpl/protocol/MPTAmount.cpp +++ b/src/libxrpl/protocol/MPTAmount.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { MPTAmount& MPTAmount::operator+=(MPTAmount const& other) @@ -65,4 +46,4 @@ MPTAmount::minPositiveAmount() return MPTAmount{1}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/MPTIssue.cpp b/src/libxrpl/protocol/MPTIssue.cpp index 9238b4302d..9673d6071f 100644 --- a/src/libxrpl/protocol/MPTIssue.cpp +++ b/src/libxrpl/protocol/MPTIssue.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { MPTIssue::MPTIssue(MPTID const& issuanceID) : mptID_(issuanceID) { @@ -42,8 +23,7 @@ MPTIssue::getIssuer() const // MPTID is concatenation of sequence + account static_assert(sizeof(MPTID) == (sizeof(std::uint32_t) + sizeof(AccountID))); // copy from id skipping the sequence - AccountID const* account = reinterpret_cast( - mptID_.data() + sizeof(std::uint32_t)); + AccountID const* account = reinterpret_cast(mptID_.data() + sizeof(std::uint32_t)); return *account; } @@ -86,16 +66,14 @@ mptIssueFromJson(Json::Value const& v) if (v.isMember(jss::currency) || v.isMember(jss::issuer)) { - Throw( - "mptIssueFromJson, MPTIssue should not have currency or issuer"); + Throw("mptIssueFromJson, MPTIssue should not have currency or issuer"); } Json::Value const& idStr = v[jss::mpt_issuance_id]; if (!idStr.isString()) { - Throw( - "mptIssueFromJson MPTID must be a string Json value"); + Throw("mptIssueFromJson MPTID must be a string Json value"); } MPTID id; @@ -107,4 +85,4 @@ mptIssueFromJson(Json::Value const& v) return MPTIssue{id}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp index 64fa9319de..e4ce3b7611 100644 --- a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp +++ b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { namespace RPC { void @@ -41,4 +22,4 @@ insertNFTSyntheticInJson( } } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/NFTokenID.cpp b/src/libxrpl/protocol/NFTokenID.cpp index 55b03b10a5..deed26360a 100644 --- a/src/libxrpl/protocol/NFTokenID.cpp +++ b/src/libxrpl/protocol/NFTokenID.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,19 +17,16 @@ #include #include -namespace ripple { +namespace xrpl { bool -canHaveNFTokenID( - std::shared_ptr const& serializedTx, - TxMeta const& transactionMeta) +canHaveNFTokenID(std::shared_ptr const& serializedTx, TxMeta const& transactionMeta) { if (!serializedTx) return false; TxType const tt = serializedTx->getTxnType(); - if (tt != ttNFTOKEN_MINT && tt != ttNFTOKEN_ACCEPT_OFFER && - tt != ttNFTOKEN_CANCEL_OFFER) + if (tt != ttNFTOKEN_MINT && tt != ttNFTOKEN_ACCEPT_OFFER && tt != ttNFTOKEN_CANCEL_OFFER) return false; // if the transaction failed nothing could have been delivered. @@ -75,14 +53,9 @@ getNFTokenIDFromPage(TxMeta const& transactionMeta) SField const& fName = node.getFName(); if (fName == sfCreatedNode) { - STArray const& toAddPrevNFTs = node.peekAtField(sfNewFields) - .downcast() - .getFieldArray(sfNFTokens); + STArray const& toAddPrevNFTs = node.peekAtField(sfNewFields).downcast().getFieldArray(sfNFTokens); std::transform( - toAddPrevNFTs.begin(), - toAddPrevNFTs.end(), - std::back_inserter(finalIDs), - [](STObject const& nft) { + toAddPrevNFTs.begin(), toAddPrevNFTs.end(), std::back_inserter(finalIDs), [](STObject const& nft) { return nft.getFieldH256(sfNFTokenID); }); } @@ -97,29 +70,20 @@ getNFTokenIDFromPage(TxMeta const& transactionMeta) // However, there will always be NFTs listed in the final fields, // as rippled outputs all fields in final fields even if they were // not changed. - STObject const& previousFields = - node.peekAtField(sfPreviousFields).downcast(); + STObject const& previousFields = node.peekAtField(sfPreviousFields).downcast(); if (!previousFields.isFieldPresent(sfNFTokens)) continue; - STArray const& toAddPrevNFTs = - previousFields.getFieldArray(sfNFTokens); + STArray const& toAddPrevNFTs = previousFields.getFieldArray(sfNFTokens); std::transform( - toAddPrevNFTs.begin(), - toAddPrevNFTs.end(), - std::back_inserter(prevIDs), - [](STObject const& nft) { + toAddPrevNFTs.begin(), toAddPrevNFTs.end(), std::back_inserter(prevIDs), [](STObject const& nft) { return nft.getFieldH256(sfNFTokenID); }); - STArray const& toAddFinalNFTs = node.peekAtField(sfFinalFields) - .downcast() - .getFieldArray(sfNFTokens); + STArray const& toAddFinalNFTs = + node.peekAtField(sfFinalFields).downcast().getFieldArray(sfNFTokens); std::transform( - toAddFinalNFTs.begin(), - toAddFinalNFTs.end(), - std::back_inserter(finalIDs), - [](STObject const& nft) { + toAddFinalNFTs.begin(), toAddFinalNFTs.end(), std::back_inserter(finalIDs), [](STObject const& nft) { return nft.getFieldH256(sfNFTokenID); }); } @@ -132,8 +96,7 @@ getNFTokenIDFromPage(TxMeta const& transactionMeta) // Find the first NFT ID that doesn't match. We're looking for an // added NFT, so the one we want will be the mismatch in finalIDs. - auto const diff = std::mismatch( - finalIDs.begin(), finalIDs.end(), prevIDs.begin(), prevIDs.end()); + auto const diff = std::mismatch(finalIDs.begin(), finalIDs.end(), prevIDs.begin(), prevIDs.end()); // There should always be a difference so the returned finalIDs // iterator should never be end(). But better safe than sorry. @@ -149,30 +112,22 @@ getNFTokenIDFromDeletedOffer(TxMeta const& transactionMeta) std::vector tokenIDResult; for (STObject const& node : transactionMeta.getNodes()) { - if (node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_OFFER || - node.getFName() != sfDeletedNode) + if (node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_OFFER || node.getFName() != sfDeletedNode) continue; - auto const& toAddNFT = node.peekAtField(sfFinalFields) - .downcast() - .getFieldH256(sfNFTokenID); + auto const& toAddNFT = node.peekAtField(sfFinalFields).downcast().getFieldH256(sfNFTokenID); tokenIDResult.push_back(toAddNFT); } // Deduplicate the NFT IDs because multiple offers could affect the same NFT // and hence we would get duplicate NFT IDs sort(tokenIDResult.begin(), tokenIDResult.end()); - tokenIDResult.erase( - unique(tokenIDResult.begin(), tokenIDResult.end()), - tokenIDResult.end()); + tokenIDResult.erase(unique(tokenIDResult.begin(), tokenIDResult.end()), tokenIDResult.end()); return tokenIDResult; } void -insertNFTokenID( - Json::Value& response, - std::shared_ptr const& transaction, - TxMeta const& transactionMeta) +insertNFTokenID(Json::Value& response, std::shared_ptr const& transaction, TxMeta const& transactionMeta) { if (!canHaveNFTokenID(transaction, transactionMeta)) return; @@ -186,16 +141,14 @@ insertNFTokenID( } else if (type == ttNFTOKEN_ACCEPT_OFFER) { - std::vector result = - getNFTokenIDFromDeletedOffer(transactionMeta); + std::vector result = getNFTokenIDFromDeletedOffer(transactionMeta); if (result.size() > 0) response[jss::nftoken_id] = to_string(result.front()); } else if (type == ttNFTOKEN_CANCEL_OFFER) { - std::vector result = - getNFTokenIDFromDeletedOffer(transactionMeta); + std::vector result = getNFTokenIDFromDeletedOffer(transactionMeta); response[jss::nftoken_ids] = Json::Value(Json::arrayValue); for (auto const& nftID : result) @@ -203,4 +156,4 @@ insertNFTokenID( } } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/NFTokenOfferID.cpp b/src/libxrpl/protocol/NFTokenOfferID.cpp index 921ba4e1d1..bbd67d710c 100644 --- a/src/libxrpl/protocol/NFTokenOfferID.cpp +++ b/src/libxrpl/protocol/NFTokenOfferID.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -32,19 +13,16 @@ #include #include -namespace ripple { +namespace xrpl { bool -canHaveNFTokenOfferID( - std::shared_ptr const& serializedTx, - TxMeta const& transactionMeta) +canHaveNFTokenOfferID(std::shared_ptr const& serializedTx, TxMeta const& transactionMeta) { if (!serializedTx) return false; TxType const tt = serializedTx->getTxnType(); - if (!(tt == ttNFTOKEN_MINT && serializedTx->isFieldPresent(sfAmount)) && - tt != ttNFTOKEN_CREATE_OFFER) + if (!(tt == ttNFTOKEN_MINT && serializedTx->isFieldPresent(sfAmount)) && tt != ttNFTOKEN_CREATE_OFFER) return false; // if the transaction failed nothing could have been delivered. @@ -59,8 +37,7 @@ getOfferIDFromCreatedOffer(TxMeta const& transactionMeta) { for (STObject const& node : transactionMeta.getNodes()) { - if (node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_OFFER || - node.getFName() != sfCreatedNode) + if (node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_OFFER || node.getFName() != sfCreatedNode) continue; return node.getFieldH256(sfLedgerIndex); @@ -83,4 +60,4 @@ insertNFTokenOfferID( response[jss::offer_id] = to_string(result.value()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Permissions.cpp b/src/libxrpl/protocol/Permissions.cpp index 2d5f00ef77..7e592fdc7f 100644 --- a/src/libxrpl/protocol/Permissions.cpp +++ b/src/libxrpl/protocol/Permissions.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { Permission::Permission() { @@ -30,8 +11,7 @@ Permission::Permission() #pragma push_macro("TRANSACTION") #undef TRANSACTION -#define TRANSACTION(tag, value, name, delegatable, amendment, ...) \ - {value, amendment}, +#define TRANSACTION(tag, value, name, delegable, amendment, ...) {value, amendment}, #include @@ -39,11 +19,11 @@ Permission::Permission() #pragma pop_macro("TRANSACTION") }; - delegatableTx_ = { + delegableTx_ = { #pragma push_macro("TRANSACTION") #undef TRANSACTION -#define TRANSACTION(tag, value, name, delegatable, ...) {value, delegatable}, +#define TRANSACTION(tag, value, name, delegable, ...) {value, delegable}, #include @@ -90,7 +70,7 @@ Permission::Permission() for ([[maybe_unused]] auto const& permission : granularPermissionMap_) XRPL_ASSERT( permission.second > UINT16_MAX, - "ripple::Permission::granularPermissionMap_ : granular permission " + "xrpl::Permission::granularPermissionMap_ : granular permission " "value must not exceed the maximum uint16_t value."); } @@ -110,8 +90,7 @@ Permission::getPermissionName(std::uint32_t const value) const // not a granular permission, check if it maps to a transaction type auto const txType = permissionToTxType(value); - if (auto const* item = TxFormats::getInstance().findByType(txType); - item != nullptr) + if (auto const* item = TxFormats::getInstance().findByType(txType); item != nullptr) return item->getName(); return std::nullopt; @@ -151,9 +130,7 @@ std::optional> const Permission::getTxFeature(TxType txType) const { auto const txFeaturesIt = txFeatureMap_.find(txType); - XRPL_ASSERT( - txFeaturesIt != txFeatureMap_.end(), - "ripple::Permissions::getTxFeature : tx exists in txFeatureMap_"); + XRPL_ASSERT(txFeaturesIt != txFeatureMap_.end(), "xrpl::Permissions::getTxFeature : tx exists in txFeatureMap_"); if (txFeaturesIt->second == uint256{}) return std::nullopt; @@ -161,35 +138,29 @@ Permission::getTxFeature(TxType txType) const } bool -Permission::isDelegatable( - std::uint32_t const& permissionValue, - Rules const& rules) const +Permission::isDelegable(std::uint32_t const& permissionValue, Rules const& rules) const { - auto const granularPermission = - getGranularName(static_cast(permissionValue)); + auto const granularPermission = getGranularName(static_cast(permissionValue)); if (granularPermission) // granular permissions are always allowed to be delegated return true; auto const txType = permissionToTxType(permissionValue); - auto const it = delegatableTx_.find(txType); + auto const it = delegableTx_.find(txType); - if (it == delegatableTx_.end()) + if (it == delegableTx_.end()) return false; auto const txFeaturesIt = txFeatureMap_.find(txType); - XRPL_ASSERT( - txFeaturesIt != txFeatureMap_.end(), - "ripple::Permissions::isDelegatable : tx exists in txFeatureMap_"); + XRPL_ASSERT(txFeaturesIt != txFeatureMap_.end(), "xrpl::Permissions::isDelegable : tx exists in txFeatureMap_"); // Delegation is only allowed if the required amendment for the transaction // is enabled. For transactions that do not require an amendment, delegation // is always allowed. - if (txFeaturesIt->second != uint256{} && - !rules.enabled(txFeaturesIt->second)) + if (txFeaturesIt->second != uint256{} && !rules.enabled(txFeaturesIt->second)) return false; - if (it->second == Delegation::notDelegatable) + if (it->second == Delegation::notDelegable) return false; return true; @@ -207,4 +178,4 @@ Permission::permissionToTxType(uint32_t const& value) const return static_cast(value - 1); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/PublicKey.cpp b/src/libxrpl/protocol/PublicKey.cpp index 54b50c80ef..b336b2d4b5 100644 --- a/src/libxrpl/protocol/PublicKey.cpp +++ b/src/libxrpl/protocol/PublicKey.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -32,7 +13,6 @@ #include #include -#include #include #include @@ -41,7 +21,7 @@ #include #include -namespace ripple { +namespace xrpl { std::ostream& operator<<(std::ostream& os, PublicKey const& pk) @@ -129,16 +109,11 @@ sliceToHex(Slice const& slice) std::optional ecdsaCanonicality(Slice const& sig) { - using uint264 = - boost::multiprecision::number>; + using uint264 = boost::multiprecision::number< + boost::multiprecision:: + cpp_int_backend<264, 264, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; - static uint264 const G( - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + static uint264 const G("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); // The format of a signature should be: // <30> [ <02> ] [ <02> ] @@ -175,9 +150,8 @@ ed25519Canonical(Slice const& sig) return false; // Big-endian Order, the Ed25519 subgroup order std::uint8_t const Order[] = { - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, - 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED, }; // Take the second half of signature // and byte-reverse it to big-endian. @@ -236,19 +210,14 @@ publicKeyType(Slice const& slice) } bool -verifyDigest( - PublicKey const& publicKey, - uint256 const& digest, - Slice const& sig, - bool mustBeFullyCanonical) noexcept +verifyDigest(PublicKey const& publicKey, uint256 const& digest, Slice const& sig, bool mustBeFullyCanonical) noexcept { if (publicKeyType(publicKey) != KeyType::secp256k1) LogicError("sign: secp256k1 required for digest signing"); auto const canonicality = ecdsaCanonicality(sig); if (!canonicality) return false; - if (mustBeFullyCanonical && - (*canonicality != ECDSACanonicality::fullyCanonical)) + if (mustBeFullyCanonical && (*canonicality != ECDSACanonicality::fullyCanonical)) return false; secp256k1_pubkey pubkey_imp; @@ -261,43 +230,29 @@ verifyDigest( secp256k1_ecdsa_signature sig_imp; if (secp256k1_ecdsa_signature_parse_der( - secp256k1Context(), - &sig_imp, - reinterpret_cast(sig.data()), - sig.size()) != 1) + secp256k1Context(), &sig_imp, reinterpret_cast(sig.data()), sig.size()) != 1) return false; if (*canonicality != ECDSACanonicality::fullyCanonical) { secp256k1_ecdsa_signature sig_norm; - if (secp256k1_ecdsa_signature_normalize( - secp256k1Context(), &sig_norm, &sig_imp) != 1) + if (secp256k1_ecdsa_signature_normalize(secp256k1Context(), &sig_norm, &sig_imp) != 1) return false; return secp256k1_ecdsa_verify( - secp256k1Context(), - &sig_norm, - reinterpret_cast(digest.data()), - &pubkey_imp) == 1; + secp256k1Context(), &sig_norm, reinterpret_cast(digest.data()), &pubkey_imp) == + 1; } return secp256k1_ecdsa_verify( - secp256k1Context(), - &sig_imp, - reinterpret_cast(digest.data()), - &pubkey_imp) == 1; + secp256k1Context(), &sig_imp, reinterpret_cast(digest.data()), &pubkey_imp) == 1; } bool -verify( - PublicKey const& publicKey, - Slice const& m, - Slice const& sig, - bool mustBeFullyCanonical) noexcept +verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept { if (auto const type = publicKeyType(publicKey)) { if (*type == KeyType::secp256k1) { - return verifyDigest( - publicKey, sha512Half(m), sig, mustBeFullyCanonical); + return verifyDigest(publicKey, sha512Half(m), sig); } else if (*type == KeyType::ed25519) { @@ -308,9 +263,7 @@ verify( // byte to distinguish them from secp256k1 keys // so when verifying the signature, we need to // first strip that prefix. - return ed25519_sign_open( - m.data(), m.size(), publicKey.data() + 1, sig.data()) == - 0; + return ed25519_sign_open(m.data(), m.size(), publicKey.data() + 1, sig.data()) == 0; } } return false; @@ -326,4 +279,4 @@ calcNodeID(PublicKey const& pk) return NodeID{static_cast(h)}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Quality.cpp b/src/libxrpl/protocol/Quality.cpp index 18649db561..fda0ac2e1e 100644 --- a/src/libxrpl/protocol/Quality.cpp +++ b/src/libxrpl/protocol/Quality.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,21 +7,20 @@ #include #include -namespace ripple { +namespace xrpl { Quality::Quality(std::uint64_t value) : m_value(value) { } -Quality::Quality(Amounts const& amount) - : m_value(getRate(amount.out, amount.in)) +Quality::Quality(Amounts const& amount) : m_value(getRate(amount.out, amount.in)) { } Quality& Quality::operator++() { - XRPL_ASSERT(m_value > 0, "ripple::Quality::operator++() : minimum value"); + XRPL_ASSERT(m_value > 0, "xrpl::Quality::operator++() : minimum value"); --m_value; return *this; } @@ -56,9 +36,7 @@ Quality::operator++(int) Quality& Quality::operator--() { - XRPL_ASSERT( - m_value < std::numeric_limits::max(), - "ripple::Quality::operator--() : maximum value"); + XRPL_ASSERT(m_value < std::numeric_limits::max(), "xrpl::Quality::operator--() : maximum value"); ++m_value; return *this; } @@ -71,29 +49,20 @@ Quality::operator--(int) return prev; } -template +template static Amounts -ceil_in_impl( - Amounts const& amount, - STAmount const& limit, - bool roundUp, - Quality const& quality) +ceil_in_impl(Amounts const& amount, STAmount const& limit, bool roundUp, Quality const& quality) { if (amount.in > limit) { - Amounts result( - limit, - DivRoundFunc(limit, quality.rate(), amount.out.asset(), roundUp)); + Amounts result(limit, DivRoundFunc(limit, quality.rate(), amount.out.asset(), roundUp)); // Clamp out if (result.out > amount.out) result.out = amount.out; - XRPL_ASSERT( - result.in == limit, "ripple::ceil_in_impl : result matches limit"); + XRPL_ASSERT(result.in == limit, "xrpl::ceil_in_impl : result matches limit"); return result; } - XRPL_ASSERT( - amount.in <= limit, "ripple::ceil_in_impl : result inside limit"); + XRPL_ASSERT(amount.in <= limit, "xrpl::ceil_in_impl : result inside limit"); return amount; } @@ -104,38 +73,25 @@ Quality::ceil_in(Amounts const& amount, STAmount const& limit) const } Amounts -Quality::ceil_in_strict( - Amounts const& amount, - STAmount const& limit, - bool roundUp) const +Quality::ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceil_in_impl(amount, limit, roundUp, *this); } -template +template static Amounts -ceil_out_impl( - Amounts const& amount, - STAmount const& limit, - bool roundUp, - Quality const& quality) +ceil_out_impl(Amounts const& amount, STAmount const& limit, bool roundUp, Quality const& quality) { if (amount.out > limit) { - Amounts result( - MulRoundFunc(limit, quality.rate(), amount.in.asset(), roundUp), - limit); + Amounts result(MulRoundFunc(limit, quality.rate(), amount.in.asset(), roundUp), limit); // Clamp in if (result.in > amount.in) result.in = amount.in; - XRPL_ASSERT( - result.out == limit, - "ripple::ceil_out_impl : result matches limit"); + XRPL_ASSERT(result.out == limit, "xrpl::ceil_out_impl : result matches limit"); return result; } - XRPL_ASSERT( - amount.out <= limit, "ripple::ceil_out_impl : result inside limit"); + XRPL_ASSERT(amount.out <= limit, "xrpl::ceil_out_impl : result inside limit"); return amount; } @@ -146,10 +102,7 @@ Quality::ceil_out(Amounts const& amount, STAmount const& limit) const } Amounts -Quality::ceil_out_strict( - Amounts const& amount, - STAmount const& limit, - bool roundUp) const +Quality::ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceil_out_impl(amount, limit, roundUp, *this); } @@ -158,23 +111,17 @@ Quality composed_quality(Quality const& lhs, Quality const& rhs) { STAmount const lhs_rate(lhs.rate()); - XRPL_ASSERT( - lhs_rate != beast::zero, - "ripple::composed_quality : nonzero left input"); + XRPL_ASSERT(lhs_rate != beast::zero, "xrpl::composed_quality : nonzero left input"); STAmount const rhs_rate(rhs.rate()); - XRPL_ASSERT( - rhs_rate != beast::zero, - "ripple::composed_quality : nonzero right input"); + XRPL_ASSERT(rhs_rate != beast::zero, "xrpl::composed_quality : nonzero right input"); STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.asset(), true)); std::uint64_t const stored_exponent(rate.exponent() + 100); std::uint64_t const stored_mantissa(rate.mantissa()); - XRPL_ASSERT( - (stored_exponent > 0) && (stored_exponent <= 255), - "ripple::composed_quality : valid exponent"); + XRPL_ASSERT((stored_exponent > 0) && (stored_exponent <= 255), "xrpl::composed_quality : valid exponent"); return Quality((stored_exponent << (64 - 8)) | stored_mantissa); } @@ -211,4 +158,4 @@ Quality::round(int digits) const return Quality{(exponent << (64 - 8)) | mantissa}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/QualityFunction.cpp b/src/libxrpl/protocol/QualityFunction.cpp index 9f898dca25..db004bf478 100644 --- a/src/libxrpl/protocol/QualityFunction.cpp +++ b/src/libxrpl/protocol/QualityFunction.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,12 +7,9 @@ #include #include -namespace ripple { +namespace xrpl { -QualityFunction::QualityFunction( - Quality const& quality, - QualityFunction::CLOBLikeTag) - : m_(0), b_(0), quality_(quality) +QualityFunction::QualityFunction(Quality const& quality, QualityFunction::CLOBLikeTag) : m_(0), b_(0), quality_(quality) { if (quality.rate() <= beast::zero) Throw("QualityFunction quality rate is 0."); @@ -61,4 +39,4 @@ QualityFunction::outFromAvgQ(Quality const& quality) return std::nullopt; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/RPCErr.cpp b/src/libxrpl/protocol/RPCErr.cpp index 2fc9ba173b..e25b5e574b 100644 --- a/src/libxrpl/protocol/RPCErr.cpp +++ b/src/libxrpl/protocol/RPCErr.cpp @@ -1,34 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { struct RPCErr; // VFALCO NOTE Deprecated function Json::Value -rpcError(int iError) +rpcError(error_code_i iError) { Json::Value jvResult(Json::objectValue); RPC::inject_error(iError, jvResult); @@ -42,4 +23,4 @@ isRpcError(Json::Value jvResult) return jvResult.isObject() && jvResult.isMember(jss::error); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp index dfdf60f02e..490474fdb1 100644 --- a/src/libxrpl/protocol/Rate2.cpp +++ b/src/libxrpl/protocol/Rate2.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { Rate const parityRate(QUALITY_ONE); @@ -52,7 +33,7 @@ transferFeeAsRate(std::uint16_t fee) STAmount multiply(STAmount const& amount, Rate const& rate) { - XRPL_ASSERT(rate.value, "ripple::nft::multiply : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::multiply : nonzero rate input"); if (rate == parityRate) return amount; @@ -63,7 +44,7 @@ multiply(STAmount const& amount, Rate const& rate) STAmount multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp) { - XRPL_ASSERT(rate.value, "ripple::nft::multiplyRound : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::multiplyRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -72,14 +53,9 @@ multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp) } STAmount -multiplyRound( - STAmount const& amount, - Rate const& rate, - Asset const& asset, - bool roundUp) +multiplyRound(STAmount const& amount, Rate const& rate, Asset const& asset, bool roundUp) { - XRPL_ASSERT( - rate.value, "ripple::nft::multiplyRound(Issue) : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::multiplyRound(Issue) : nonzero rate input"); if (rate == parityRate) { @@ -92,7 +68,7 @@ multiplyRound( STAmount divide(STAmount const& amount, Rate const& rate) { - XRPL_ASSERT(rate.value, "ripple::nft::divide : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::divide : nonzero rate input"); if (rate == parityRate) return amount; @@ -103,7 +79,7 @@ divide(STAmount const& amount, Rate const& rate) STAmount divideRound(STAmount const& amount, Rate const& rate, bool roundUp) { - XRPL_ASSERT(rate.value, "ripple::nft::divideRound : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::divideRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -112,14 +88,9 @@ divideRound(STAmount const& amount, Rate const& rate, bool roundUp) } STAmount -divideRound( - STAmount const& amount, - Rate const& rate, - Asset const& asset, - bool roundUp) +divideRound(STAmount const& amount, Rate const& rate, Asset const& asset, bool roundUp) { - XRPL_ASSERT( - rate.value, "ripple::nft::divideRound(Issue) : nonzero rate input"); + XRPL_ASSERT(rate.value, "xrpl::nft::divideRound(Issue) : nonzero rate input"); if (rate == parityRate) return amount; @@ -127,4 +98,4 @@ divideRound( return divRound(amount, detail::as_amount(rate), asset, roundUp); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Rules.cpp b/src/libxrpl/protocol/Rules.cpp index ec1b7ac563..e649b15ea2 100644 --- a/src/libxrpl/protocol/Rules.cpp +++ b/src/libxrpl/protocol/Rules.cpp @@ -1,29 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - +#include +// Do not remove. Forces Rules.h to stay first, to verify it can compile +// without any hidden dependencies #include +#include #include #include #include #include #include -#include #include #include @@ -31,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace { // Use a static inside a function to help prevent order-of-initialization issues @@ -52,6 +36,12 @@ getCurrentTransactionRules() void setCurrentTransactionRules(std::optional r) { + // Make global changes associated with the rules before the value is moved. + // Push the appropriate setting, instead of having the class pull every time + // the value is needed. That could get expensive fast. + bool enableLargeNumbers = !r || (r->enabled(featureSingleAssetVault) || r->enabled(featureLendingProtocol)); + Number::setMantissaScale(enableLargeNumbers ? MantissaRange::large : MantissaRange::small); + *getCurrentTransactionRulesRef() = std::move(r); } @@ -63,8 +53,7 @@ private: std::unordered_set> const& presets_; public: - explicit Impl(std::unordered_set> const& presets) - : presets_(presets) + explicit Impl(std::unordered_set> const& presets) : presets_(presets) { } @@ -101,14 +90,13 @@ public: return false; XRPL_ASSERT( presets_ == other.presets_, - "ripple::Rules::Impl::operator==(Impl) const : input presets do " + "xrpl::Rules::Impl::operator==(Impl) const : input presets do " "match"); return *digest_ == *other.digest_; } }; -Rules::Rules(std::unordered_set> const& presets) - : impl_(std::make_shared(presets)) +Rules::Rules(std::unordered_set> const& presets) : impl_(std::make_shared(presets)) { } @@ -129,7 +117,7 @@ Rules::presets() const bool Rules::enabled(uint256 const& feature) const { - XRPL_ASSERT(impl_, "ripple::Rules::enabled : initialized"); + XRPL_ASSERT(impl_, "xrpl::Rules::enabled : initialized"); return impl_->enabled(feature); } @@ -137,9 +125,7 @@ Rules::enabled(uint256 const& feature) const bool Rules::operator==(Rules const& other) const { - XRPL_ASSERT( - impl_ && other.impl_, - "ripple::Rules::operator==(Rules) const : both initialized"); + XRPL_ASSERT(impl_ && other.impl_, "xrpl::Rules::operator==(Rules) const : both initialized"); if (impl_.get() == other.impl_.get()) return true; return *impl_ == *other.impl_; @@ -158,4 +144,4 @@ isFeatureEnabled(uint256 const& feature) return rules && rules->enabled(feature); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 57e5849c00..c04c82f2bc 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { // Storage for static const members. SField::IsSigning const SField::notSigning; @@ -41,8 +22,7 @@ static SField::private_access_tag_t access; template template -TypedField::TypedField(private_access_tag_t pat, Args&&... args) - : SField(pat, std::forward(args)...) +TypedField::TypedField(private_access_tag_t pat, Args&&... args) : SField(pat, std::forward(args)...) { } @@ -56,19 +36,10 @@ TypedField::TypedField(private_access_tag_t pat, Args&&... args) #undef TYPED_SFIELD #define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ - SField const sfName( \ - access, \ - STI_##stiSuffix, \ - fieldValue, \ - std::string_view(#sfName).substr(2).data(), \ - ##__VA_ARGS__); + SField const sfName(access, STI_##stiSuffix, fieldValue, std::string_view(#sfName).substr(2).data(), ##__VA_ARGS__); #define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ SF_##stiSuffix const sfName( \ - access, \ - STI_##stiSuffix, \ - fieldValue, \ - std::string_view(#sfName).substr(2).data(), \ - ##__VA_ARGS__); + access, STI_##stiSuffix, fieldValue, std::string_view(#sfName).substr(2).data(), ##__VA_ARGS__); // SFields which, for historical reasons, do not follow naming conventions. SField const sfInvalid(access, -1, ""); @@ -85,13 +56,7 @@ SField const sfIndex(access, STI_UINT256, 258, "index"); #undef UNTYPED_SFIELD #pragma pop_macro("UNTYPED_SFIELD") -SField::SField( - private_access_tag_t, - SerializedTypeID tid, - int fv, - char const* fn, - int meta, - IsSigning signing) +SField::SField(private_access_tag_t, SerializedTypeID tid, int fv, char const* fn, int meta, IsSigning signing) : fieldCode(field_code(tid, fv)) , fieldType(tid) , fieldValue(fv) @@ -102,11 +67,9 @@ SField::SField( , jsonName(fieldName.c_str()) { XRPL_ASSERT( - !knownCodeToField.contains(fieldCode), - "ripple::SField::SField(tid,fv,fn,meta,signing) : fieldCode is unique"); + !knownCodeToField.contains(fieldCode), "xrpl::SField::SField(tid,fv,fn,meta,signing) : fieldCode is unique"); XRPL_ASSERT( - !knownNameToField.contains(fieldName), - "ripple::SField::SField(tid,fv,fn,meta,signing) : fieldName is unique"); + !knownNameToField.contains(fieldName), "xrpl::SField::SField(tid,fv,fn,meta,signing) : fieldName is unique"); knownCodeToField[fieldCode] = this; knownNameToField[fieldName] = this; } @@ -121,12 +84,8 @@ SField::SField(private_access_tag_t, int fc, char const* fn) , signingField(IsSigning::yes) , jsonName(fieldName.c_str()) { - XRPL_ASSERT( - !knownCodeToField.contains(fieldCode), - "ripple::SField::SField(fc,fn) : fieldCode is unique"); - XRPL_ASSERT( - !knownNameToField.contains(fieldName), - "ripple::SField::SField(fc,fn) : fieldName is unique"); + XRPL_ASSERT(!knownCodeToField.contains(fieldCode), "xrpl::SField::SField(fc,fn) : fieldCode is unique"); + XRPL_ASSERT(!knownNameToField.contains(fieldName), "xrpl::SField::SField(fc,fn) : fieldName is unique"); knownCodeToField[fieldCode] = this; knownNameToField[fieldName] = this; } @@ -171,4 +130,4 @@ SField::getField(std::string const& fieldName) return sfInvalid; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/SOTemplate.cpp b/src/libxrpl/protocol/SOTemplate.cpp index 0b6e321bf4..23d086f493 100644 --- a/src/libxrpl/protocol/SOTemplate.cpp +++ b/src/libxrpl/protocol/SOTemplate.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,11 +6,9 @@ #include #include -namespace ripple { +namespace xrpl { -SOTemplate::SOTemplate( - std::initializer_list uniqueFields, - std::initializer_list commonFields) +SOTemplate::SOTemplate(std::initializer_list uniqueFields, std::initializer_list commonFields) : indices_(SField::getNumFields() + 1, -1) // Unmapped indices == -1 { // Add all SOElements. @@ -69,4 +48,4 @@ SOTemplate::getIndex(SField const& sField) const return indices_[sField.getNum()]; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp index 7229c85240..b85341daf3 100644 --- a/src/libxrpl/protocol/STAccount.cpp +++ b/src/libxrpl/protocol/STAccount.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,14 +14,13 @@ #include #include -namespace ripple { +namespace xrpl { STAccount::STAccount() : STBase(), value_(beast::zero), default_(true) { } -STAccount::STAccount(SField const& n) - : STBase(n), value_(beast::zero), default_(true) +STAccount::STAccount(SField const& n) : STBase(n), value_(beast::zero), default_(true) { } @@ -61,13 +41,11 @@ STAccount::STAccount(SField const& n, Buffer&& v) : STAccount(n) memcpy(value_.begin(), v.data(), uint160::bytes); } -STAccount::STAccount(SerialIter& sit, SField const& name) - : STAccount(name, sit.getVLBuffer()) +STAccount::STAccount(SerialIter& sit, SField const& name) : STAccount(name, sit.getVLBuffer()) { } -STAccount::STAccount(SField const& n, AccountID const& v) - : STBase(n), value_(v), default_(false) +STAccount::STAccount(SField const& n, AccountID const& v) : STBase(n), value_(v), default_(false) { } @@ -92,11 +70,8 @@ STAccount::getSType() const void STAccount::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STAccount::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == STI_ACCOUNT, - "ripple::STAccount::add : valid field type"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STAccount::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == STI_ACCOUNT, "xrpl::STAccount::add : valid field type"); // Preserve the serialization behavior of an STBlob: // o If we are default (all zeros) serialize as an empty blob. @@ -126,4 +101,4 @@ STAccount::getText() const return toBase58(value()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index dfd1b3dfbe..b7c33bb907 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -66,7 +49,7 @@ #include #include -namespace ripple { +namespace xrpl { static std::uint64_t const tenTo14 = 100000000000000ull; static std::uint64_t const tenTo14m1 = tenTo14 - 1; @@ -78,14 +61,11 @@ getInt64Value(STAmount const& amount, bool valid, char const* error) { if (!valid) Throw(error); - XRPL_ASSERT( - amount.exponent() == 0, "ripple::getInt64Value : exponent is zero"); + XRPL_ASSERT(amount.exponent() == 0, "xrpl::getInt64Value : exponent is zero"); auto ret = static_cast(amount.mantissa()); - XRPL_ASSERT( - static_cast(ret) == amount.mantissa(), - "ripple::getInt64Value : mantissa must roundtrip"); + XRPL_ASSERT(static_cast(ret) == amount.mantissa(), "xrpl::getInt64Value : mantissa must roundtrip"); if (amount.negative()) ret = -ret; @@ -102,21 +82,21 @@ getSNValue(STAmount const& amount) static std::int64_t getMPTValue(STAmount const& amount) { - return getInt64Value( - amount, amount.holds(), "amount is not MPT!"); + return getInt64Value(amount, amount.holds(), "amount is not MPT!"); } static bool areComparable(STAmount const& v1, STAmount const& v2) { if (v1.holds() && v2.holds()) - return v1.native() == v2.native() && - v1.get().currency == v2.get().currency; + return v1.native() == v2.native() && v1.get().currency == v2.get().currency; if (v1.holds() && v2.holds()) return v1.get() == v2.get(); return false; } +static_assert(INITIAL_XRP.drops() == STAmount::cMaxNativeN); + STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) { std::uint64_t value = sit.get64(); @@ -175,8 +155,7 @@ STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) bool isNegative = (offset & 256) == 0; offset = (offset & 255) - 97; // center the range - if (value < cMinValue || value > cMaxValue || offset < cMinOffset || - offset > cMaxOffset) + if (value < cMinValue || value > cMaxValue || offset < cMinOffset || offset > cMaxOffset) { Throw("invalid currency value"); } @@ -199,54 +178,41 @@ STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) canonicalize(); } -STAmount::STAmount(SField const& name, std::int64_t mantissa) - : STBase(name), mAsset(xrpIssue()), mOffset(0) +STAmount::STAmount(SField const& name, std::int64_t mantissa) : STBase(name), mAsset(xrpIssue()), mOffset(0) { set(mantissa); } STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative) - : STBase(name) - , mAsset(xrpIssue()) - , mValue(mantissa) - , mOffset(0) - , mIsNegative(negative) + : STBase(name), mAsset(xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(negative) { XRPL_ASSERT( mValue <= std::numeric_limits::max(), - "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum " + "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum " "mantissa input"); } STAmount::STAmount(SField const& name, STAmount const& from) - : STBase(name) - , mAsset(from.mAsset) - , mValue(from.mValue) - , mOffset(from.mOffset) - , mIsNegative(from.mIsNegative) + : STBase(name), mAsset(from.mAsset), mValue(from.mValue), mOffset(from.mOffset), mIsNegative(from.mIsNegative) { XRPL_ASSERT( mValue <= std::numeric_limits::max(), - "ripple::STAmount::STAmount(SField, STAmount) : maximum input"); + "xrpl::STAmount::STAmount(SField, STAmount) : maximum input"); canonicalize(); } //------------------------------------------------------------------------------ STAmount::STAmount(std::uint64_t mantissa, bool negative) - : mAsset(xrpIssue()) - , mValue(mantissa) - , mOffset(0) - , mIsNegative(mantissa != 0 && negative) + : mAsset(xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(mantissa != 0 && negative) { XRPL_ASSERT( mValue <= std::numeric_limits::max(), - "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa " + "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa " "input"); } -STAmount::STAmount(XRPAmount const& amount) - : mAsset(xrpIssue()), mOffset(0), mIsNegative(amount < beast::zero) +STAmount::STAmount(XRPAmount const& amount) : mAsset(xrpIssue()), mOffset(0), mIsNegative(amount < beast::zero) { if (mIsNegative) mValue = unsafe_cast(-amount.drops()); @@ -283,11 +249,10 @@ XRPAmount STAmount::xrp() const { if (!native()) - Throw( - "Cannot return non-native STAmount as XRPAmount"); + Throw("Cannot return non-native STAmount as XRPAmount"); auto drops = static_cast(mValue); - XRPL_ASSERT(mOffset == 0, "ripple::STAmount::xrp : amount is canonical"); + XRPL_ASSERT(mOffset == 0, "xrpl::STAmount::xrp : amount is canonical"); if (mIsNegative) drops = -drops; @@ -298,7 +263,7 @@ STAmount::xrp() const IOUAmount STAmount::iou() const { - if (native() || !holds()) + if (integral()) Throw("Cannot return non-IOU STAmount as IOUAmount"); auto mantissa = static_cast(mValue); @@ -317,7 +282,7 @@ STAmount::mpt() const Throw("Cannot return STAmount as MPTAmount"); auto value = static_cast(mValue); - XRPL_ASSERT(mOffset == 0, "ripple::STAmount::mpt : amount is canonical"); + XRPL_ASSERT(mOffset == 0, "xrpl::STAmount::mpt : amount is canonical"); if (mIsNegative) value = -value; @@ -328,9 +293,7 @@ STAmount::mpt() const STAmount& STAmount::operator=(IOUAmount const& iou) { - XRPL_ASSERT( - native() == false, - "ripple::STAmount::operator=(IOUAmount) : is not XRP"); + XRPL_ASSERT(integral() == false, "xrpl::STAmount::operator=(IOUAmount) : is not integral"); mOffset = iou.exponent(); mIsNegative = iou < beast::zero; if (mIsNegative) @@ -340,6 +303,25 @@ STAmount::operator=(IOUAmount const& iou) return *this; } +STAmount& +STAmount::operator=(Number const& number) +{ + if (!getCurrentTransactionRules() || isFeatureEnabled(featureSingleAssetVault) || + isFeatureEnabled(featureLendingProtocol)) + { + *this = fromNumber(mAsset, number); + } + else + { + auto const originalMantissa = number.mantissa(); + mIsNegative = originalMantissa < 0; + mValue = mIsNegative ? -originalMantissa : originalMantissa; + mOffset = number.exponent(); + } + canonicalize(); + return *this; +} + //------------------------------------------------------------------------------ // // Operators @@ -372,12 +354,7 @@ operator+(STAmount const& v1, STAmount const& v2) if (v1 == beast::zero) { // Result must be in terms of v1 currency and issuer. - return { - v1.getFName(), - v1.asset(), - v2.mantissa(), - v2.exponent(), - v2.negative()}; + return {v1.getFName(), v1.asset(), v2.mantissa(), v2.exponent(), v2.negative()}; } if (v1.native()) @@ -423,15 +400,9 @@ operator+(STAmount const& v1, STAmount const& v2) return {v1.getFName(), v1.asset()}; if (fv >= 0) - return STAmount{ - v1.getFName(), - v1.asset(), - static_cast(fv), - ov1, - false}; + return STAmount{v1.getFName(), v1.asset(), static_cast(fv), ov1, false}; - return STAmount{ - v1.getFName(), v1.asset(), static_cast(-fv), ov1, true}; + return STAmount{v1.getFName(), v1.asset(), static_cast(-fv), ov1, true}; } STAmount @@ -469,9 +440,7 @@ getRate(STAmount const& offerOut, STAmount const& offerIn) STAmount r = divide(offerIn, offerOut, noIssue()); if (r == beast::zero) // offer is too good return 0; - XRPL_ASSERT( - (r.exponent() >= -100) && (r.exponent() <= 155), - "ripple::getRate : exponent inside range"); + XRPL_ASSERT((r.exponent() >= -100) && (r.exponent() <= 155), "xrpl::getRate : exponent inside range"); std::uint64_t ret = r.exponent() + 100; return (ret << (64 - 8)) | r.mantissa(); } @@ -518,12 +487,8 @@ canAdd(STAmount const& a, STAmount const& b) XRPAmount A = a.xrp(); XRPAmount B = b.xrp(); - if ((B > XRPAmount{0} && - A > XRPAmount{std::numeric_limits::max()} - - B) || - (B < XRPAmount{0} && - A < XRPAmount{std::numeric_limits::min()} - - B)) + if ((B > XRPAmount{0} && A > XRPAmount{std::numeric_limits::max()} - B) || + (B < XRPAmount{0} && A < XRPAmount{std::numeric_limits::min()} - B)) { return false; } @@ -537,8 +502,7 @@ canAdd(STAmount const& a, STAmount const& b) static STAmount const maxLoss{IOUAmount{1, -4}, noIssue()}; STAmount lhs = divide((a - b) + b, a, noIssue()) - one; STAmount rhs = divide((b - a) + a, b, noIssue()) - one; - return ((rhs.negative() ? -rhs : rhs) + - (lhs.negative() ? -lhs : lhs)) <= maxLoss; + return ((rhs.negative() ? -rhs : rhs) + (lhs.negative() ? -lhs : lhs)) <= maxLoss; } // MPT (overflow & underflow check) @@ -546,12 +510,8 @@ canAdd(STAmount const& a, STAmount const& b) { MPTAmount A = a.mpt(); MPTAmount B = b.mpt(); - if ((B > MPTAmount{0} && - A > MPTAmount{std::numeric_limits::max()} - - B) || - (B < MPTAmount{0} && - A < MPTAmount{std::numeric_limits::min()} - - B)) + if ((B > MPTAmount{0} && A > MPTAmount{std::numeric_limits::max()} - B) || + (B < MPTAmount{0} && A < MPTAmount{std::numeric_limits::min()} - B)) { return false; } @@ -602,9 +562,7 @@ canSubtract(STAmount const& a, STAmount const& b) return false; // Check for overflow - if (B < XRPAmount{0} && - A > XRPAmount{std::numeric_limits::max()} + - B) + if (B < XRPAmount{0} && A > XRPAmount{std::numeric_limits::max()} + B) return false; return true; @@ -627,9 +585,7 @@ canSubtract(STAmount const& a, STAmount const& b) return false; // Overflow check - if (B < MPTAmount{0} && - A > MPTAmount{std::numeric_limits::max()} + - B) + if (B < MPTAmount{0} && A > MPTAmount{std::numeric_limits::max()} + B) return false; return true; } @@ -682,7 +638,7 @@ STAmount::getFullText() const std::string STAmount::getText() const { - // keep full internal accuracy, but make more human friendly if posible + // keep full internal accuracy, but make more human friendly if possible if (*this == beast::zero) return "0"; @@ -692,8 +648,7 @@ STAmount::getText() const if (mIsNegative) ret.append(1, '-'); - bool const scientific( - (mOffset != 0) && ((mOffset < -25) || (mOffset > -5))); + bool const scientific((mOffset != 0) && ((mOffset < -25) || (mOffset > -5))); if (native() || mAsset.holds() || scientific) { @@ -708,7 +663,7 @@ STAmount::getText() const return ret; } - XRPL_ASSERT(mOffset + 43 > 0, "ripple::STAmount::getText : minimum offset"); + XRPL_ASSERT(mOffset + 43 > 0, "xrpl::STAmount::getText : minimum offset"); size_t const pad_prefix = 27; size_t const pad_suffix = 23; @@ -732,9 +687,7 @@ STAmount::getText() const if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - XRPL_ASSERT( - post_to >= post_from, - "ripple::STAmount::getText : first distance check"); + XRPL_ASSERT(post_to >= post_from, "xrpl::STAmount::getText : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -743,15 +696,11 @@ STAmount::getText() const if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - XRPL_ASSERT( - post_to >= post_from, - "ripple::STAmount::getText : second distance check"); + XRPL_ASSERT(post_to >= post_from, "xrpl::STAmount::getText : second distance check"); - post_to = std::find_if( - std::make_reverse_iterator(post_to), - std::make_reverse_iterator(post_from), - [](char c) { return c != '0'; }) - .base(); + post_to = std::find_if(std::make_reverse_iterator(post_to), std::make_reverse_iterator(post_from), [](char c) { + return c != '0'; + }).base(); // Assemble the output: if (pre_from == pre_to) @@ -781,7 +730,7 @@ STAmount::add(Serializer& s) const { if (native()) { - XRPL_ASSERT(mOffset == 0, "ripple::STAmount::add : zero offset"); + XRPL_ASSERT(mOffset == 0, "xrpl::STAmount::add : zero offset"); if (!mIsNegative) s.add64(mValue | cPositive); @@ -802,14 +751,9 @@ STAmount::add(Serializer& s) const if (*this == beast::zero) s.add64(cIssuedCurrency); else if (mIsNegative) // 512 = not native - s.add64( - mValue | - (static_cast(mOffset + 512 + 97) << (64 - 10))); + s.add64(mValue | (static_cast(mOffset + 512 + 97) << (64 - 10))); else // 256 = positive - s.add64( - mValue | - (static_cast(mOffset + 512 + 256 + 97) - << (64 - 10))); + s.add64(mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10))); s.addBitString(mAsset.get().currency); s.addBitString(mAsset.get().account); } @@ -849,7 +793,7 @@ STAmount::isDefault() const void STAmount::canonicalize() { - if (native() || mAsset.holds()) + if (integral()) { // native and MPT currency amounts should always have an offset of zero // log(2^64,10) ~ 19.2 @@ -870,16 +814,18 @@ STAmount::canonicalize() if (getSTNumberSwitchover()) { - Number num( - mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{}); + Number num(mIsNegative, mValue, mOffset, Number::unchecked{}); auto set = [&](auto const& val) { - mIsNegative = val.value() < 0; - mValue = mIsNegative ? -val.value() : val.value(); + auto const value = val.value(); + mIsNegative = value < 0; + mValue = mIsNegative ? -value : value; }; if (native()) set(XRPAmount{num}); - else + else if (mAsset.holds()) set(MPTAmount{num}); + else + Throw("Unknown integral asset type"); mOffset = 0; } else @@ -895,8 +841,7 @@ STAmount::canonicalize() // N.B. do not move the overflow check to after the // multiplication if (native() && mValue > cMaxNativeN) - Throw( - "Native currency amount out of range"); + Throw("Native currency amount out of range"); else if (!native() && mValue > maxMPTokenAmount) Throw("MPT amount out of range"); @@ -954,13 +899,11 @@ STAmount::canonicalize() XRPL_ASSERT( (mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)), - "ripple::STAmount::canonicalize : value inside range"); + "xrpl::STAmount::canonicalize : value inside range"); XRPL_ASSERT( (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)), - "ripple::STAmount::canonicalize : offset inside range"); - XRPL_ASSERT( - (mValue != 0) || (mOffset != -100), - "ripple::STAmount::canonicalize : value or offset set"); + "xrpl::STAmount::canonicalize : offset inside range"); + XRPL_ASSERT((mValue != 0) || (mOffset != -100), "xrpl::STAmount::canonicalize : value or offset set"); } void @@ -997,8 +940,7 @@ amountFromString(Asset const& asset, std::string const& amount) { auto const parts = partsFromString(amount); if ((asset.native() || asset.holds()) && parts.exponent < 0) - Throw( - "XRP and MPT must be specified as integral amount."); + Throw("XRP and MPT must be specified as integral amount."); return {asset, parts.mantissa, parts.exponent, parts.negative}; } @@ -1014,8 +956,7 @@ amountFromJson(SField const& name, Json::Value const& v) if (v.isNull()) { - Throw( - "XRP may not be specified with a null Json value"); + Throw("XRP may not be specified with a null Json value"); } else if (v.isObject()) { @@ -1062,8 +1003,7 @@ amountFromJson(SField const& name, Json::Value const& v) value = v; } - bool const native = !currencyOrMPTID.isString() || - currencyOrMPTID.asString().empty() || + bool const native = !currencyOrMPTID.isString() || currencyOrMPTID.asString().empty() || (currencyOrMPTID.asString() == systemCurrencyCode()); if (native) @@ -1087,8 +1027,7 @@ amountFromJson(SField const& name, Json::Value const& v) Issue issue; if (!to_currency(issue.currency, currencyOrMPTID.asString())) Throw("invalid currency"); - if (!issuer.isString() || - !to_issuer(issue.account, issuer.asString())) + if (!issuer.isString() || !to_issuer(issue.account, issuer.asString())) Throw("invalid issuer"); if (issue.native()) Throw("invalid issuer"); @@ -1106,7 +1045,7 @@ amountFromJson(SField const& name, Json::Value const& v) } else { - parts.mantissa = -value.asInt(); + parts.mantissa = value.asAbsUInt(); parts.negative = true; } } @@ -1119,8 +1058,7 @@ amountFromJson(SField const& name, Json::Value const& v) parts = partsFromString(value.asString()); // Can't specify XRP or MPT using fractional representation if ((asset.native() || asset.holds()) && parts.exponent < 0) - Throw( - "XRP and MPT must be specified as integral amount."); + Throw("XRP and MPT must be specified as integral amount."); } else { @@ -1140,8 +1078,7 @@ amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource) } catch (std::exception const& e) { - JLOG(debugLog().warn()) - << "amountFromJsonNoThrow: caught: " << e.what(); + JLOG(debugLog().warn()) << "amountFromJsonNoThrow: caught: " << e.what(); } return false; } @@ -1155,16 +1092,15 @@ amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource) bool operator==(STAmount const& lhs, STAmount const& rhs) { - return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() && - lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa(); + return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() && lhs.exponent() == rhs.exponent() && + lhs.mantissa() == rhs.mantissa(); } bool operator<(STAmount const& lhs, STAmount const& rhs) { if (!areComparable(lhs, rhs)) - Throw( - "Can't compare amounts that are't comparable!"); + Throw("Can't compare amounts that are't comparable!"); if (lhs.negative() != rhs.negative()) return lhs.negative(); @@ -1200,12 +1136,7 @@ operator-(STAmount const& value) if (value.mantissa() == 0) return value; return STAmount( - value.getFName(), - value.asset(), - value.mantissa(), - value.exponent(), - !value.negative(), - STAmount::unchecked{}); + value.getFName(), value.asset(), value.mantissa(), value.exponent(), !value.negative(), STAmount::unchecked{}); } //------------------------------------------------------------------------------ @@ -1217,10 +1148,7 @@ operator-(STAmount const& value) // Calculate (a * b) / c when all three values are 64-bit // without loss of precision: static std::uint64_t -muldiv( - std::uint64_t multiplier, - std::uint64_t multiplicand, - std::uint64_t divisor) +muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor) { boost::multiprecision::uint128_t ret; @@ -1230,19 +1158,15 @@ muldiv( if (ret > std::numeric_limits::max()) { Throw( - "overflow: (" + std::to_string(multiplier) + " * " + - std::to_string(multiplicand) + ") / " + std::to_string(divisor)); + "overflow: (" + std::to_string(multiplier) + " * " + std::to_string(multiplicand) + ") / " + + std::to_string(divisor)); } return static_cast(ret); } static std::uint64_t -muldiv_round( - std::uint64_t multiplier, - std::uint64_t multiplicand, - std::uint64_t divisor, - std::uint64_t rounding) +muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding) { boost::multiprecision::uint128_t ret; @@ -1253,9 +1177,8 @@ muldiv_round( if (ret > std::numeric_limits::max()) { Throw( - "overflow: ((" + std::to_string(multiplier) + " * " + - std::to_string(multiplicand) + ") + " + std::to_string(rounding) + - ") / " + std::to_string(divisor)); + "overflow: ((" + std::to_string(multiplier) + " * " + std::to_string(multiplicand) + ") + " + + std::to_string(rounding) + ") / " + std::to_string(divisor)); } return static_cast(ret); @@ -1300,10 +1223,7 @@ divide(STAmount const& num, STAmount const& den, Asset const& asset) // 10^32 to 10^33) followed by a division, so the result // is in the range of 10^16 to 10^15. return STAmount( - asset, - muldiv(numVal, tenTo17, denVal) + 5, - numOffset - denOffset - 17, - num.negative() != den.negative()); + asset, muldiv(numVal, tenTo17, denVal) + 5, numOffset - denOffset - 17, num.negative() != den.negative()); } STAmount @@ -1342,7 +1262,7 @@ multiply(STAmount const& v1, STAmount const& v2, Asset const& asset) if (getSTNumberSwitchover()) { auto const r = Number{v1} * Number{v2}; - return STAmount{asset, r.mantissa(), r.exponent()}; + return STAmount{asset, r}; } std::uint64_t value1 = v1.mantissa(); @@ -1372,11 +1292,7 @@ multiply(STAmount const& v1, STAmount const& v2, Asset const& asset) // and 10^16), so their product is in the 10^30 to 10^32 // range. Dividing their product by 10^14 maintains the // precision, by scaling the result to 10^16 to 10^18. - return STAmount( - asset, - muldiv(value1, value2, tenTo14) + 7, - offset1 + offset2 + 14, - v1.negative() != v2.negative()); + return STAmount(asset, muldiv(value1, value2, tenTo14) + 7, offset1 + offset2 + 14, v1.negative() != v2.negative()); } // This is the legacy version of canonicalizeRound. It's been in use @@ -1439,11 +1355,7 @@ canonicalizeRound(bool native, std::uint64_t& value, int& offset, bool) // rounding decisions. canonicalizeRoundStrict() tracks all of the bits in // the value being rounded. static void -canonicalizeRoundStrict( - bool native, - std::uint64_t& value, - int& offset, - bool roundUp) +canonicalizeRoundStrict(bool native, std::uint64_t& value, int& offset, bool roundUp) { if (native) { @@ -1461,8 +1373,7 @@ canonicalizeRoundStrict( value = newValue; ++offset; } - value += - (hadRemainder && roundUp) ? 10 : 9; // Add before last divide + value += (hadRemainder && roundUp) ? 10 : 9; // Add before last divide value /= 10; ++offset; } @@ -1480,6 +1391,33 @@ canonicalizeRoundStrict( } } +STAmount +roundToScale(STAmount const& value, std::int32_t scale, Number::rounding_mode rounding) +{ + // Nothing to do for integral types. + if (value.integral()) + return value; + + // Nothing to do for zero. + if (value == beast::zero) + return value; + + // If the value's exponent is greater than or equal to the scale, then + // rounding will do nothing, and might even lose precision, so just return + // the value. + if (value.exponent() >= scale) + return value; + + STAmount const referenceValue{value.asset(), STAmount::cMinValue, scale, value.negative()}; + + NumberRoundModeGuard mg(rounding); + // With an IOU, the the result of addition will be truncated to the + // precision of the larger value, which in this case is referenceValue. Then + // remove the reference value via subtraction, and we're left with the + // rounded value. + return (value + referenceValue) - referenceValue; +} + namespace { // We need a class that has an interface similar to NumberRoundModeGuard @@ -1503,15 +1441,9 @@ public: // // We might need to use NumberRoundModeGuard. Allow the caller // to pass either that or a replacement as a template parameter. -template < - void (*CanonicalizeFunc)(bool, std::uint64_t&, int&, bool), - typename MightSaveRound> +template static STAmount -mulRoundImpl( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp) +mulRoundImpl(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp) { if (v1 == beast::zero || v2 == beast::zero) return {asset}; @@ -1577,8 +1509,7 @@ mulRoundImpl( // If the we're rounding up, we want to round up away // from zero, and if we're rounding down, truncation // is implicit. - std::uint64_t amount = muldiv_round( - value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0); + std::uint64_t amount = muldiv_round(value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0); int offset = offset1 + offset2 + 14; if (resultNegative != roundUp) @@ -1612,36 +1543,22 @@ mulRoundImpl( } STAmount -mulRound( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp) +mulRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp) { - return mulRoundImpl( - v1, v2, asset, roundUp); + return mulRoundImpl(v1, v2, asset, roundUp); } STAmount -mulRoundStrict( - STAmount const& v1, - STAmount const& v2, - Asset const& asset, - bool roundUp) +mulRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp) { - return mulRoundImpl( - v1, v2, asset, roundUp); + return mulRoundImpl(v1, v2, asset, roundUp); } // We might need to use NumberRoundModeGuard. Allow the caller // to pass either that or a replacement as a template parameter. template static STAmount -divRoundImpl( - STAmount const& num, - STAmount const& den, - Asset const& asset, - bool roundUp) +divRoundImpl(STAmount const& num, STAmount const& den, Asset const& asset, bool roundUp) { if (den == beast::zero) Throw("division by zero"); @@ -1680,22 +1597,19 @@ divRoundImpl( // // We round away from zero if we're rounding up or // truncate if we're rounding down. - std::uint64_t amount = muldiv_round( - numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0); + std::uint64_t amount = muldiv_round(numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0); int offset = numOffset - denOffset - 17; if (resultNegative != roundUp) - canonicalizeRound( - asset.native() || asset.holds(), amount, offset, roundUp); + canonicalizeRound(asset.native() || asset.holds(), amount, offset, roundUp); STAmount result = [&]() { // If appropriate, tell Number the rounding mode we are using. // Note that "roundUp == true" actually means "round away from zero". // Otherwise round toward zero. using enum Number::rounding_mode; - MightSaveRound const savedRound( - roundUp ^ resultNegative ? upward : downward); + MightSaveRound const savedRound(roundUp ^ resultNegative ? upward : downward); return STAmount(asset, amount, offset, resultNegative); }(); @@ -1719,23 +1633,15 @@ divRoundImpl( } STAmount -divRound( - STAmount const& num, - STAmount const& den, - Asset const& asset, - bool roundUp) +divRound(STAmount const& num, STAmount const& den, Asset const& asset, bool roundUp) { return divRoundImpl(num, den, asset, roundUp); } STAmount -divRoundStrict( - STAmount const& num, - STAmount const& den, - Asset const& asset, - bool roundUp) +divRoundStrict(STAmount const& num, STAmount const& den, Asset const& asset, bool roundUp) { return divRoundImpl(num, den, asset, roundUp); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STArray.cpp b/src/libxrpl/protocol/STArray.cpp index bbc890ffda..8e7827cccc 100644 --- a/src/libxrpl/protocol/STArray.cpp +++ b/src/libxrpl/protocol/STArray.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,10 +12,9 @@ #include #include -namespace ripple { +namespace xrpl { -STArray::STArray(STArray&& other) - : STBase(other.getFName()), v_(std::move(other.v_)) +STArray::STArray(STArray&& other) : STBase(other.getFName()), v_(std::move(other.v_)) { } @@ -72,8 +52,7 @@ STArray::STArray(SerialIter& sit, SField const& f, int depth) : STBase(f) if ((type == STI_OBJECT) && (field == 1)) { - JLOG(debugLog().error()) - << "Encountered array with end of object marker"; + JLOG(debugLog().error()) << "Encountered array with end of object marker"; Throw("Illegal terminator in array"); } @@ -81,8 +60,7 @@ STArray::STArray(SerialIter& sit, SField const& f, int depth) : STBase(f) if (fn.isInvalid()) { - JLOG(debugLog().error()) - << "Unknown field: " << type << "/" << field; + JLOG(debugLog().error()) << "Unknown field: " << type << "/" << field; Throw("Unknown field"); } @@ -199,4 +177,4 @@ STArray::sort(bool (*compare)(STObject const&, STObject const&)) std::sort(v_.begin(), v_.end(), compare); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STBase.cpp b/src/libxrpl/protocol/STBase.cpp index ecbe6833d0..f6b1dcec58 100644 --- a/src/libxrpl/protocol/STBase.cpp +++ b/src/libxrpl/protocol/STBase.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { STBase::STBase() : fName(&sfGeneric) { @@ -36,7 +17,7 @@ STBase::STBase() : fName(&sfGeneric) STBase::STBase(SField const& n) : fName(&n) { - XRPL_ASSERT(fName, "ripple::STBase::STBase : field is set"); + XRPL_ASSERT(fName, "xrpl::STBase::STBase : field is set"); } STBase& @@ -113,16 +94,14 @@ STBase::add(Serializer& s) const { // Should never be called // LCOV_EXCL_START - UNREACHABLE("ripple::STBase::add : not implemented"); + UNREACHABLE("xrpl::STBase::add : not implemented"); // LCOV_EXCL_STOP } bool STBase::isEquivalent(STBase const& t) const { - XRPL_ASSERT( - getSType() == STI_NOTPRESENT, - "ripple::STBase::isEquivalent : type not present"); + XRPL_ASSERT(getSType() == STI_NOTPRESENT, "xrpl::STBase::isEquivalent : type not present"); return t.getSType() == STI_NOTPRESENT; } @@ -136,7 +115,7 @@ void STBase::setFName(SField const& n) { fName = &n; - XRPL_ASSERT(fName, "ripple::STBase::setFName : field is set"); + XRPL_ASSERT(fName, "xrpl::STBase::setFName : field is set"); } SField const& @@ -148,8 +127,7 @@ STBase::getFName() const void STBase::addFieldID(Serializer& s) const { - XRPL_ASSERT( - fName->isBinary(), "ripple::STBase::addFieldID : field is binary"); + XRPL_ASSERT(fName->isBinary(), "xrpl::STBase::addFieldID : field is binary"); s.addFieldID(fName->fieldType, fName->fieldValue); } @@ -161,4 +139,4 @@ operator<<(std::ostream& out, STBase const& t) return out << t.getFullText(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STBlob.cpp b/src/libxrpl/protocol/STBlob.cpp index 3d62cb5ee4..1a9dae7771 100644 --- a/src/libxrpl/protocol/STBlob.cpp +++ b/src/libxrpl/protocol/STBlob.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,10 +9,9 @@ #include #include -namespace ripple { +namespace xrpl { -STBlob::STBlob(SerialIter& st, SField const& name) - : STBase(name), value_(st.getVLBuffer()) +STBlob::STBlob(SerialIter& st, SField const& name) : STBase(name), value_(st.getVLBuffer()) { } @@ -62,11 +42,10 @@ STBlob::getText() const void STBlob::add(Serializer& s) const { - XRPL_ASSERT(getFName().isBinary(), "ripple::STBlob::add : field is binary"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STBlob::add : field is binary"); XRPL_ASSERT( - (getFName().fieldType == STI_VL) || - (getFName().fieldType == STI_ACCOUNT), - "ripple::STBlob::add : valid field type"); + (getFName().fieldType == STI_VL) || (getFName().fieldType == STI_ACCOUNT), + "xrpl::STBlob::add : valid field type"); s.addVL(value_.data(), value_.size()); } @@ -83,4 +62,4 @@ STBlob::isDefault() const return value_.empty(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STCurrency.cpp b/src/libxrpl/protocol/STCurrency.cpp index 68186bbfda..cfbbe509c6 100644 --- a/src/libxrpl/protocol/STCurrency.cpp +++ b/src/libxrpl/protocol/STCurrency.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { STCurrency::STCurrency(SField const& name) : STBase{name} { @@ -42,8 +23,7 @@ STCurrency::STCurrency(SerialIter& sit, SField const& name) : STBase{name} currency_ = sit.get160(); } -STCurrency::STCurrency(SField const& name, Currency const& currency) - : STBase{name}, currency_{currency} +STCurrency::STCurrency(SField const& name, Currency const& currency) : STBase{name}, currency_{currency} { } @@ -107,18 +87,16 @@ currencyFromJson(SField const& name, Json::Value const& v) { if (!v.isString()) { - Throw( - "currencyFromJson currency must be a string Json value"); + Throw("currencyFromJson currency must be a string Json value"); } auto const currency = to_currency(v.asString()); if (currency == badCurrency() || currency == noCurrency()) { - Throw( - "currencyFromJson currency must be a valid currency"); + Throw("currencyFromJson currency must be a valid currency"); } return STCurrency{name, currency}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 355fa4c113..ae7b3ff279 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,11 +17,10 @@ #include #include -namespace ripple { +namespace xrpl { template <> -STInteger::STInteger(SerialIter& sit, SField const& name) - : STInteger(name, sit.get8()) +STInteger::STInteger(SerialIter& sit, SField const& name) : STInteger(name, sit.get8()) { } @@ -63,8 +43,7 @@ STUInt8::getText() const return human; // LCOV_EXCL_START - JLOG(debugLog().error()) - << "Unknown result code in metadata: " << value_; + JLOG(debugLog().error()) << "Unknown result code in metadata: " << value_; // LCOV_EXCL_STOP } @@ -83,8 +62,7 @@ STUInt8::getJson(JsonOptions) const return token; // LCOV_EXCL_START - JLOG(debugLog().error()) - << "Unknown result code in metadata: " << value_; + JLOG(debugLog().error()) << "Unknown result code in metadata: " << value_; // LCOV_EXCL_STOP } @@ -94,8 +72,7 @@ STUInt8::getJson(JsonOptions) const //------------------------------------------------------------------------------ template <> -STInteger::STInteger(SerialIter& sit, SField const& name) - : STInteger(name, sit.get16()) +STInteger::STInteger(SerialIter& sit, SField const& name) : STInteger(name, sit.get16()) { } @@ -112,8 +89,7 @@ STUInt16::getText() const { if (getFName() == sfLedgerEntryType) { - auto item = LedgerFormats::getInstance().findByType( - safe_cast(value_)); + auto item = LedgerFormats::getInstance().findByType(safe_cast(value_)); if (item != nullptr) return item->getName(); @@ -121,8 +97,7 @@ STUInt16::getText() const if (getFName() == sfTransactionType) { - auto item = - TxFormats::getInstance().findByType(safe_cast(value_)); + auto item = TxFormats::getInstance().findByType(safe_cast(value_)); if (item != nullptr) return item->getName(); @@ -137,8 +112,7 @@ STUInt16::getJson(JsonOptions) const { if (getFName() == sfLedgerEntryType) { - auto item = LedgerFormats::getInstance().findByType( - safe_cast(value_)); + auto item = LedgerFormats::getInstance().findByType(safe_cast(value_)); if (item != nullptr) return item->getName(); @@ -146,8 +120,7 @@ STUInt16::getJson(JsonOptions) const if (getFName() == sfTransactionType) { - auto item = - TxFormats::getInstance().findByType(safe_cast(value_)); + auto item = TxFormats::getInstance().findByType(safe_cast(value_)); if (item != nullptr) return item->getName(); @@ -159,8 +132,7 @@ STUInt16::getJson(JsonOptions) const //------------------------------------------------------------------------------ template <> -STInteger::STInteger(SerialIter& sit, SField const& name) - : STInteger(name, sit.get32()) +STInteger::STInteger(SerialIter& sit, SField const& name) : STInteger(name, sit.get32()) { } @@ -177,8 +149,7 @@ STUInt32::getText() const { if (getFName() == sfPermissionValue) { - auto const permissionName = - Permission::getInstance().getPermissionName(value_); + auto const permissionName = Permission::getInstance().getPermissionName(value_); if (permissionName) return *permissionName; } @@ -191,8 +162,7 @@ STUInt32::getJson(JsonOptions) const { if (getFName() == sfPermissionValue) { - auto const permissionName = - Permission::getInstance().getPermissionName(value_); + auto const permissionName = Permission::getInstance().getPermissionName(value_); if (permissionName) return *permissionName; } @@ -203,8 +173,7 @@ STUInt32::getJson(JsonOptions) const //------------------------------------------------------------------------------ template <> -STInteger::STInteger(SerialIter& sit, SField const& name) - : STInteger(name, sit.get64()) +STInteger::STInteger(SerialIter& sit, SField const& name) : STInteger(name, sit.get64()) { } @@ -227,16 +196,10 @@ Json::Value STUInt64::getJson(JsonOptions) const { auto convertToString = [](uint64_t const value, int const base) { - XRPL_ASSERT( - base == 10 || base == 16, - "ripple::STUInt64::getJson : base 10 or 16"); - std::string str( - base == 10 ? 20 : 16, 0); // Allocate space depending on base - auto ret = - std::to_chars(str.data(), str.data() + str.size(), value, base); - XRPL_ASSERT( - ret.ec == std::errc(), - "ripple::STUInt64::getJson : to_chars succeeded"); + XRPL_ASSERT(base == 10 || base == 16, "xrpl::STUInt64::getJson : base 10 or 16"); + std::string str(base == 10 ? 20 : 16, 0); // Allocate space depending on base + auto ret = std::to_chars(str.data(), str.data() + str.size(), value, base); + XRPL_ASSERT(ret.ec == std::errc(), "xrpl::STUInt64::getJson : to_chars succeeded"); str.resize(std::distance(str.data(), ret.ptr)); return str; }; @@ -252,8 +215,7 @@ STUInt64::getJson(JsonOptions) const //------------------------------------------------------------------------------ template <> -STInteger::STInteger(SerialIter& sit, SField const& name) - : STInteger(name, sit.get32()) +STInteger::STInteger(SerialIter& sit, SField const& name) : STInteger(name, sit.get32()) { } @@ -278,4 +240,4 @@ STInt32::getJson(JsonOptions) const return value_; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STIssue.cpp b/src/libxrpl/protocol/STIssue.cpp index 821e17f6a7..627c61fc58 100644 --- a/src/libxrpl/protocol/STIssue.cpp +++ b/src/libxrpl/protocol/STIssue.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { STIssue::STIssue(SField const& name) : STBase{name} { @@ -63,13 +44,9 @@ STIssue::STIssue(SerialIter& sit, SField const& name) : STBase{name} { MPTID mptID; std::uint32_t sequence = sit.get32(); - static_assert( - MPTID::size() == sizeof(sequence) + sizeof(currencyOrAccount)); + static_assert(MPTID::size() == sizeof(sequence) + sizeof(currencyOrAccount)); memcpy(mptID.data(), &sequence, sizeof(sequence)); - memcpy( - mptID.data() + sizeof(sequence), - currencyOrAccount.data(), - sizeof(currencyOrAccount)); + memcpy(mptID.data() + sizeof(sequence), currencyOrAccount.data(), sizeof(currencyOrAccount)); MPTIssue issue{mptID}; asset_ = issue; } @@ -79,8 +56,7 @@ STIssue::STIssue(SerialIter& sit, SField const& name) : STBase{name} issue.currency = currencyOrAccount; issue.account = account; if (!isConsistent(issue)) - Throw( - "invalid issue: currency and account native mismatch"); + Throw("invalid issue: currency and account native mismatch"); asset_ = issue; } } @@ -158,4 +134,4 @@ issueFromJson(SField const& name, Json::Value const& v) return STIssue{name, assetFromJson(v)}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index ae80abb69f..d73da2eb3a 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -45,32 +26,28 @@ #include #include -namespace ripple { +namespace xrpl { -STLedgerEntry::STLedgerEntry(Keylet const& k) - : STObject(sfLedgerEntry), key_(k.key), type_(k.type) +STLedgerEntry::STLedgerEntry(Keylet const& k) : STObject(sfLedgerEntry), key_(k.key), type_(k.type) { auto const format = LedgerFormats::getInstance().findByType(type_); if (format == nullptr) Throw( - "Attempt to create a SLE of unknown type " + - std::to_string(safe_cast(k.type))); + "Attempt to create a SLE of unknown type " + std::to_string(safe_cast(k.type))); set(format->getSOTemplate()); setFieldU16(sfLedgerEntryType, static_cast(type_)); } -STLedgerEntry::STLedgerEntry(SerialIter& sit, uint256 const& index) - : STObject(sfLedgerEntry), key_(index) +STLedgerEntry::STLedgerEntry(SerialIter& sit, uint256 const& index) : STObject(sfLedgerEntry), key_(index) { set(sit); setSLEType(); } -STLedgerEntry::STLedgerEntry(STObject const& object, uint256 const& index) - : STObject(object), key_(index) +STLedgerEntry::STLedgerEntry(STObject const& object, uint256 const& index) : STObject(object), key_(index) { setSLEType(); } @@ -78,8 +55,7 @@ STLedgerEntry::STLedgerEntry(STObject const& object, uint256 const& index) void STLedgerEntry::setSLEType() { - auto format = LedgerFormats::getInstance().findByType( - safe_cast(getFieldU16(sfLedgerEntryType))); + auto format = LedgerFormats::getInstance().findByType(safe_cast(getFieldU16(sfLedgerEntryType))); if (format == nullptr) Throw("invalid ledger entry type"); @@ -127,8 +103,7 @@ STLedgerEntry::getSType() const std::string STLedgerEntry::getText() const { - return str( - boost::format("{ %s, %s }") % to_string(key_) % STObject::getText()); + return str(boost::format("{ %s, %s }") % to_string(key_) % STObject::getText()); } Json::Value @@ -139,8 +114,7 @@ STLedgerEntry::getJson(JsonOptions options) const ret[jss::index] = to_string(key_); if (getType() == ltMPTOKEN_ISSUANCE) - ret[jss::mpt_issuance_id] = to_string( - makeMptID(getFieldU32(sfSequence), getAccountID(sfIssuer))); + ret[jss::mpt_issuance_id] = to_string(makeMptID(getFieldU32(sfSequence), getAccountID(sfIssuer))); return ret; } @@ -153,19 +127,12 @@ STLedgerEntry::isThreadedType(Rules const& rules) const // Exclude PrevTxnID/PrevTxnLgrSeq if the fixPreviousTxnID amendment is not // enabled and the ledger object type is in the above set bool const excludePrevTxnID = !rules.enabled(fixPreviousTxnID) && - std::count( - newPreviousTxnIDTypes.cbegin(), - newPreviousTxnIDTypes.cend(), - type_); + std::count(newPreviousTxnIDTypes.cbegin(), newPreviousTxnIDTypes.cend(), type_); return !excludePrevTxnID && getFieldIndex(sfPreviousTxnID) != -1; } bool -STLedgerEntry::thread( - uint256 const& txID, - std::uint32_t ledgerSeq, - uint256& prevTxID, - std::uint32_t& prevLedgerID) +STLedgerEntry::thread(uint256 const& txID, std::uint32_t ledgerSeq, uint256& prevTxID, std::uint32_t& prevLedgerID) { uint256 oldPrevTxID = getFieldH256(sfPreviousTxnID); @@ -175,8 +142,7 @@ STLedgerEntry::thread( { // this transaction is already threaded XRPL_ASSERT( - getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq, - "ripple::STLedgerEntry::thread : ledger sequence match"); + getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq, "xrpl::STLedgerEntry::thread : ledger sequence match"); return false; } @@ -187,4 +153,4 @@ STLedgerEntry::thread( return true; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp index 975fd5723b..a549a0e482 100644 --- a/src/libxrpl/protocol/STNumber.cpp +++ b/src/libxrpl/protocol/STNumber.cpp @@ -1,28 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - +#include +// Do not remove. Keep STNumber.h first #include #include #include +#include #include +#include #include -#include +#include #include #include @@ -33,14 +18,13 @@ #include #include -namespace ripple { +namespace xrpl { -STNumber::STNumber(SField const& field, Number const& value) - : STBase(field), value_(value) +STNumber::STNumber(SField const& field, Number const& value) : STTakesAsset(field), value_(value) { } -STNumber::STNumber(SerialIter& sit, SField const& field) : STBase(field) +STNumber::STNumber(SerialIter& sit, SField const& field) : STTakesAsset(field) { // We must call these methods in separate statements // to guarantee their order of execution. @@ -61,16 +45,60 @@ STNumber::getText() const return to_string(value_); } +void +STNumber::associateAsset(Asset const& a) +{ + STTakesAsset::associateAsset(a); + + XRPL_ASSERT_PARTS(getFName().shouldMeta(SField::sMD_NeedsAsset), "STNumber::associateAsset", "field needs asset"); + + roundToAsset(a, value_); +} + void STNumber::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STNumber::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == getSType(), - "ripple::STNumber::add : field type match"); - s.add64(value_.mantissa()); - s.add32(value_.exponent()); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STNumber::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STNumber::add : field type match"); + + auto value = value_; + auto const mantissa = value.mantissa(); + auto const exponent = value.exponent(); + + SField const& field = getFName(); + if (field.shouldMeta(SField::sMD_NeedsAsset)) + { + // asset is defined in the STTakesAsset base class + if (asset_) + { + // The number should be rounded to the asset's precision, but round + // it here if it has an asset assigned. + roundToAsset(*asset_, value); + XRPL_ASSERT_PARTS(value_ == value, "xrpl::STNumber::add", "value is already rounded"); + } + else + { +#if !NDEBUG + // There are circumstances where an already-rounded Number is + // serialized without being touched by a transactor, and thus + // without an asset. We can't know if it's rounded, because it could + // represent _anything_, particularly when serializing user-provided + // Json. Regardless, the only time we should be serializing an + // STNumber is when the scale is large. + XRPL_ASSERT_PARTS( + Number::getMantissaScale() == MantissaRange::large, + "xrpl::STNumber::add", + "STNumber only used with large mantissa scale"); +#endif + } + } + + XRPL_ASSERT_PARTS( + mantissa <= std::numeric_limits::max() && mantissa >= std::numeric_limits::min(), + "xrpl::STNumber::add", + "mantissa in valid range"); + s.add64(mantissa); + s.add32(exponent); } Number const& @@ -100,9 +128,7 @@ STNumber::move(std::size_t n, void* buf) bool STNumber::isEquivalent(STBase const& t) const { - XRPL_ASSERT( - t.getSType() == this->getSType(), - "ripple::STNumber::isEquivalent : field type match"); + XRPL_ASSERT(t.getSType() == this->getSType(), "xrpl::STNumber::isEquivalent : field type match"); STNumber const& v = dynamic_cast(t); return value_ == v; } @@ -188,7 +214,7 @@ numberFromJson(SField const& field, Json::Value const& value) } else { - parts.mantissa = -value.asInt(); + parts.mantissa = value.asAbsUInt(); parts.negative = true; } } @@ -199,20 +225,20 @@ numberFromJson(SField const& field, Json::Value const& value) else if (value.isString()) { parts = partsFromString(value.asString()); - // Only strings can represent out-of-range values. - if (parts.mantissa > std::numeric_limits::max()) - Throw("too high"); + + XRPL_ASSERT_PARTS(!getCurrentTransactionRules(), "xrpld::numberFromJson", "Not in a Transactor context"); + + // Number mantissas are much bigger than the allowable parsed values, so + // it can't be out of range. + static_assert( + std::numeric_limits::max() >= std::numeric_limits::max()); } else { Throw("not a number"); } - std::int64_t mantissa = parts.mantissa; - if (parts.negative) - mantissa = -mantissa; - - return STNumber{field, Number{mantissa, parts.exponent}}; + return STNumber{field, Number{parts.negative, parts.mantissa, parts.exponent, Number::normalized{}}}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index 8fb21a638d..ad5b6fe352 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -58,10 +39,9 @@ #include #include -namespace ripple { +namespace xrpl { -STObject::STObject(STObject&& other) - : STBase(other.getFName()), v_(std::move(other.v_)), mType(other.mType) +STObject::STObject(STObject&& other) : STBase(other.getFName()), v_(std::move(other.v_)), mType(other.mType) { } @@ -74,17 +54,14 @@ STObject::STObject(SOTemplate const& type, SField const& name) : STBase(name) set(type); } -STObject::STObject(SOTemplate const& type, SerialIter& sit, SField const& name) - : STBase(name) +STObject::STObject(SOTemplate const& type, SerialIter& sit, SField const& name) : STBase(name) { v_.reserve(type.size()); set(sit); applyTemplate(type); // May throw } -STObject::STObject(SerialIter& sit, SField const& name, int depth) noexcept( - false) - : STBase(name), mType(nullptr) +STObject::STObject(SerialIter& sit, SField const& name, int depth) noexcept(false) : STBase(name), mType(nullptr) { if (depth > 10) Throw("Maximum nesting depth of STObject exceeded"); @@ -106,8 +83,7 @@ STObject::makeInnerObject(SField const& name) if (!rules || (rules->enabled(fixInnerObjTemplate) && isAMMObj) || (rules->enabled(fixInnerObjTemplate2) && !isAMMObj)) { - if (SOTemplate const* elements = - InnerObjectFormats::getInstance().findSOTemplateBySField(name)) + if (SOTemplate const* elements = InnerObjectFormats::getInstance().findSOTemplateBySField(name)) obj.set(*elements); } return obj; @@ -184,17 +160,13 @@ STObject::applyTemplate(SOTemplate const& type) v.reserve(type.size()); for (auto const& e : type) { - auto const iter = - std::find_if(v_.begin(), v_.end(), [&](detail::STVar const& b) { - return b.get().getFName() == e.sField(); - }); + auto const iter = std::find_if( + v_.begin(), v_.end(), [&](detail::STVar const& b) { return b.get().getFName() == e.sField(); }); if (iter != v_.end()) { if ((e.style() == soeDEFAULT) && iter->get().isDefault()) { - throwFieldErr( - e.sField().fieldName, - "may not be explicitly set to default."); + throwFieldErr(e.sField().fieldName, "may not be explicitly set to default."); } v.emplace_back(std::move(*iter)); v_.erase(iter); @@ -213,8 +185,7 @@ STObject::applyTemplate(SOTemplate const& type) // Anything left over in the object must be discardable if (!e->getFName().isDiscardable()) { - throwFieldErr( - e->getFName().getName(), "found in disallowed location."); + throwFieldErr(e->getFName().getName(), "found in disallowed location."); } } // Swap the template matching data in for the old data, @@ -225,8 +196,7 @@ STObject::applyTemplate(SOTemplate const& type) void STObject::applyTemplateFromSField(SField const& sField) { - SOTemplate const* elements = - InnerObjectFormats::getInstance().findSOTemplateBySField(sField); + SOTemplate const* elements = InnerObjectFormats::getInstance().findSOTemplateBySField(sField); if (elements) applyTemplate(*elements); // May throw } @@ -258,8 +228,7 @@ STObject::set(SerialIter& sit, int depth) if (type == STI_ARRAY && field == 1) { - JLOG(debugLog().error()) - << "Encountered object with embedded end-of-array marker"; + JLOG(debugLog().error()) << "Encountered object with embedded end-of-array marker"; Throw("Illegal end-of-array marker in object"); } @@ -267,8 +236,7 @@ STObject::set(SerialIter& sit, int depth) if (fn.isInvalid()) { - JLOG(debugLog().error()) << "Unknown field: field_type=" << type - << ", field_name=" << field; + JLOG(debugLog().error()) << "Unknown field: field_type=" << type << ", field_name=" << field; Throw("Unknown field"); } @@ -284,10 +252,9 @@ STObject::set(SerialIter& sit, int depth) // duplicate fields. This is a key invariant: auto const sf = getSortedFields(*this, withAllFields); - auto const dup = std::adjacent_find( - sf.cbegin(), sf.cend(), [](STBase const* lhs, STBase const* rhs) { - return lhs->getFName() == rhs->getFName(); - }); + auto const dup = std::adjacent_find(sf.cbegin(), sf.cend(), [](STBase const* lhs, STBase const* rhs) { + return lhs->getFName() == rhs->getFName(); + }); if (dup != sf.cend()) Throw("Duplicate field detected"); @@ -366,29 +333,17 @@ STObject::isEquivalent(STBase const& t) const if (mType != nullptr && v->mType == mType) { - return std::equal( - begin(), - end(), - v->begin(), - v->end(), - [](STBase const& st1, STBase const& st2) { - return (st1.getSType() == st2.getSType()) && - st1.isEquivalent(st2); - }); + return std::equal(begin(), end(), v->begin(), v->end(), [](STBase const& st1, STBase const& st2) { + return (st1.getSType() == st2.getSType()) && st1.isEquivalent(st2); + }); } auto const sf1 = getSortedFields(*this, withAllFields); auto const sf2 = getSortedFields(*v, withAllFields); - return std::equal( - sf1.begin(), - sf1.end(), - sf2.begin(), - sf2.end(), - [](STBase const* st1, STBase const* st2) { - return (st1->getSType() == st2->getSType()) && - st1->isEquivalent(*st2); - }); + return std::equal(sf1.begin(), sf1.end(), sf2.begin(), sf2.end(), [](STBase const* st1, STBase const* st2) { + return (st1->getSType() == st2->getSType()) && st1->isEquivalent(*st2); + }); } uint256 @@ -599,6 +554,12 @@ STObject::delField(int index) v_.erase(v_.begin() + index); } +SOEStyle +STObject::getStyle(SField const& field) const +{ + return mType ? mType->style(field) : soeINVALID; +} + unsigned char STObject::getFieldU8(SField const& field) const { @@ -910,8 +871,7 @@ STObject::add(Serializer& s, WhichFields whichFields) const { // Depending on whichFields, signing fields are either serialized or // not. Then fields are added to the Serializer sorted by fieldCode. - std::vector const fields{ - getSortedFields(*this, whichFields)}; + std::vector const fields{getSortedFields(*this, whichFields)}; // insert sorted for (STBase const* const field : fields) @@ -921,9 +881,8 @@ STObject::add(Serializer& s, WhichFields whichFields) const // must be OBJECT, or the object cannot be deserialized SerializedTypeID const sType{field->getSType()}; XRPL_ASSERT( - (sType != STI_OBJECT) || - (field->getFName().fieldType == STI_OBJECT), - "ripple::STObject::add : valid field type"); + (sType != STI_OBJECT) || (field->getFName().fieldType == STI_OBJECT), + "xrpl::STObject::add : valid field type"); field->addFieldID(s); field->add(s); if (sType == STI_ARRAY || sType == STI_OBJECT) @@ -941,8 +900,7 @@ STObject::getSortedFields(STObject const& objToSort, WhichFields whichFields) for (detail::STVar const& elem : objToSort.v_) { STBase const& base = elem.get(); - if ((base.getSType() != STI_NOTPRESENT) && - base.getFName().shouldInclude(whichFields)) + if ((base.getSType() != STI_NOTPRESENT) && base.getFName().shouldInclude(whichFields)) { sf.push_back(&base); } @@ -956,4 +914,4 @@ STObject::getSortedFields(STObject const& objToSort, WhichFields whichFields) return sf; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index f99fec6b87..878f6c3605 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -60,13 +41,12 @@ #include #include -namespace ripple { +namespace xrpl { namespace STParsedJSONDetail { template -constexpr std:: - enable_if_t::value && std::is_signed::value, U> - to_unsigned(S value) +constexpr std::enable_if_t::value && std::is_signed::value, U> +to_unsigned(S value) { if (value < 0 || std::numeric_limits::max() < value) Throw("Value out of range"); @@ -74,9 +54,8 @@ constexpr std:: } template -constexpr std:: - enable_if_t::value && std::is_unsigned::value, U1> - to_unsigned(U2 value) +constexpr std::enable_if_t::value && std::is_unsigned::value, U1> +to_unsigned(U2 value) { if (std::numeric_limits::max() < value) Throw("Value out of range"); @@ -96,9 +75,7 @@ make_name(std::string const& object, std::string const& field) static inline Json::Value not_an_object(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' is not a JSON object."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is not a JSON object."); } static inline Json::Value @@ -110,40 +87,31 @@ not_an_object(std::string const& object) static inline Json::Value not_an_array(std::string const& object) { - return RPC::make_error( - rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array."); } static inline Json::Value unknown_field(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' is unknown."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is unknown."); } static inline Json::Value out_of_range(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' is out of range."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is out of range."); } static inline Json::Value bad_type(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' has bad type."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has bad type."); } static inline Json::Value invalid_data(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' has invalid data."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has invalid data."); } static inline Json::Value @@ -155,25 +123,19 @@ invalid_data(std::string const& object) static inline Json::Value array_expected(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' must be a JSON array."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a JSON array."); } static inline Json::Value string_expected(std::string const& object, std::string const& field) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + make_name(object, field) + "' must be a string."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a string."); } static inline Json::Value too_deep(std::string const& object) { - return RPC::make_error( - rpcINVALID_PARAMS, - "Field '" + object + "' exceeds nesting depth limit."); + return RPC::make_error(rpcINVALID_PARAMS, "Field '" + object + "' exceeds nesting depth limit."); } static inline Json::Value @@ -181,17 +143,14 @@ singleton_expected(std::string const& object, unsigned int index) { return RPC::make_error( rpcINVALID_PARAMS, - "Field '" + object + "[" + std::to_string(index) + - "]' must be an object with a single key/object value."); + "Field '" + object + "[" + std::to_string(index) + "]' must be an object with a single key/object value."); } static inline Json::Value template_mismatch(SField const& sField) { return RPC::make_error( - rpcINVALID_PARAMS, - "Object '" + sField.getName() + - "' contents did not meet requirements for that type."); + rpcINVALID_PARAMS, "Object '" + sField.getName() + "' contents did not meet requirements for that type."); } static inline Json::Value @@ -221,21 +180,15 @@ parseUnsigned( if (value.isString()) { ret = detail::make_stvar( - field, - safe_cast( - beast::lexicalCastThrow(value.asString()))); + field, safe_cast(beast::lexicalCastThrow(value.asString()))); } else if (value.isInt()) { - ret = detail::make_stvar( - field, - to_unsigned(value.asInt())); + ret = detail::make_stvar(field, to_unsigned(value.asInt())); } else if (value.isUInt()) { - ret = detail::make_stvar( - field, - to_unsigned(value.asUInt())); + ret = detail::make_stvar(field, to_unsigned(value.asUInt())); } else { @@ -270,17 +223,14 @@ parseUint16( { std::string const strValue = value.asString(); - if (!strValue.empty() && - ((strValue[0] < '0') || (strValue[0] > '9'))) + if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9'))) { if (field == sfTransactionType) { ret = detail::make_stvar( field, safe_cast( - static_cast( - TxFormats::getInstance().findTypeByName( - strValue)))); + static_cast(TxFormats::getInstance().findTypeByName(strValue)))); if (*name == sfGeneric) name = &sfTransaction; @@ -290,9 +240,7 @@ parseUint16( ret = detail::make_stvar( field, safe_cast( - static_cast( - LedgerFormats::getInstance().findTypeByName( - strValue)))); + static_cast(LedgerFormats::getInstance().findTypeByName(strValue)))); if (*name == sfGeneric) name = &sfLedgerEntry; @@ -305,8 +253,7 @@ parseUint16( } } if (!ret) - return parseUnsigned( - field, json_name, fieldName, name, value, error); + return parseUnsigned(field, json_name, fieldName, name, value, error); } catch (std::exception const&) { @@ -336,33 +283,26 @@ parseUint32( if (field == sfPermissionValue) { std::string const strValue = value.asString(); - auto const granularPermission = - Permission::getInstance().getGranularValue(strValue); + auto const granularPermission = Permission::getInstance().getGranularValue(strValue); if (granularPermission) { - ret = detail::make_stvar( - field, *granularPermission); + ret = detail::make_stvar(field, *granularPermission); } else { - auto const& txType = - TxFormats::getInstance().findTypeByName(strValue); - ret = detail::make_stvar( - field, - Permission::getInstance().txToPermissionType(txType)); + auto const& txType = TxFormats::getInstance().findTypeByName(strValue); + ret = detail::make_stvar(field, Permission::getInstance().txToPermissionType(txType)); } } else { ret = detail::make_stvar( field, - safe_cast( - beast::lexicalCastThrow(value.asString()))); + safe_cast(beast::lexicalCastThrow(value.asString()))); } } if (!ret) - return parseUnsigned( - field, json_name, fieldName, name, value, error); + return parseUnsigned(field, json_name, fieldName, name, value, error); } catch (std::exception const&) { @@ -401,31 +341,25 @@ parseLeaf( case STI_UINT8: try { - constexpr auto minValue = - std::numeric_limits::min(); - constexpr auto maxValue = - std::numeric_limits::max(); + constexpr auto minValue = std::numeric_limits::min(); + constexpr auto maxValue = std::numeric_limits::max(); if (value.isString()) { std::string const strValue = value.asString(); - if (!strValue.empty() && - ((strValue[0] < '0') || (strValue[0] > '9'))) + if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9'))) { if (field == sfTransactionResult) { auto ter = transCode(strValue); - if (!ter || TERtoInt(*ter) < minValue || - TERtoInt(*ter) > maxValue) + if (!ter || TERtoInt(*ter) < minValue || TERtoInt(*ter) > maxValue) { error = out_of_range(json_name, fieldName); return ret; } - ret = detail::make_stvar( - field, - static_cast(TERtoInt(*ter))); + ret = detail::make_stvar(field, static_cast(TERtoInt(*ter))); } else { @@ -435,9 +369,7 @@ parseLeaf( } else { - ret = detail::make_stvar( - field, - beast::lexicalCastThrow(strValue)); + ret = detail::make_stvar(field, beast::lexicalCastThrow(strValue)); } } else if (value.isInt()) @@ -448,8 +380,7 @@ parseLeaf( return ret; } - ret = detail::make_stvar( - field, static_cast(value.asInt())); + ret = detail::make_stvar(field, static_cast(value.asInt())); } else if (value.isUInt()) { @@ -459,8 +390,7 @@ parseLeaf( return ret; } - ret = detail::make_stvar( - field, static_cast(value.asUInt())); + ret = detail::make_stvar(field, static_cast(value.asUInt())); } else { @@ -476,16 +406,14 @@ parseLeaf( break; case STI_UINT16: - ret = parseUint16( - field, json_name, fieldName, name, value, error); + ret = parseUint16(field, json_name, fieldName, name, value, error); if (!ret) return ret; break; case STI_UINT32: - ret = parseUint32( - field, json_name, fieldName, name, value, error); + ret = parseUint32(field, json_name, fieldName, name, value, error); if (!ret) return ret; @@ -500,15 +428,10 @@ parseLeaf( std::uint64_t val; - bool const useBase10 = - field.shouldMeta(SField::sMD_BaseTen); + bool const useBase10 = field.shouldMeta(SField::sMD_BaseTen); // if the field is amount, serialize as base 10 - auto [p, ec] = std::from_chars( - str.data(), - str.data() + str.size(), - val, - useBase10 ? 10 : 16); + auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16); if (ec != std::errc() || (p != str.data() + str.size())) Throw("invalid data"); @@ -517,13 +440,11 @@ parseLeaf( } else if (value.isInt()) { - ret = detail::make_stvar( - field, to_unsigned(value.asInt())); + ret = detail::make_stvar(field, to_unsigned(value.asInt())); } else if (value.isUInt()) { - ret = detail::make_stvar( - field, safe_cast(value.asUInt())); + ret = detail::make_stvar(field, safe_cast(value.asUInt())); } else { @@ -640,32 +561,25 @@ parseLeaf( { if (value.isString()) { - ret = detail::make_stvar( - field, - beast::lexicalCastThrow( - value.asString())); + ret = detail::make_stvar(field, beast::lexicalCastThrow(value.asString())); } else if (value.isInt()) { // future-proofing - a static assert failure if the JSON // library ever supports larger ints // In such case, we will need additional bounds checks here - static_assert( - std::is_same_v); + static_assert(std::is_same_v); ret = detail::make_stvar(field, value.asInt()); } else if (value.isUInt()) { auto const uintValue = value.asUInt(); - if (uintValue > - static_cast( - std::numeric_limits::max())) + if (uintValue > static_cast(std::numeric_limits::max())) { error = out_of_range(json_name, fieldName); return ret; } - ret = detail::make_stvar( - field, static_cast(uintValue)); + ret = detail::make_stvar(field, static_cast(uintValue)); } else { @@ -692,8 +606,7 @@ parseLeaf( { if (auto vBlob = strUnHex(value.asString())) { - ret = detail::make_stvar( - field, vBlob->data(), vBlob->size()); + ret = detail::make_stvar(field, vBlob->data(), vBlob->size()); } else { @@ -711,8 +624,7 @@ parseLeaf( case STI_AMOUNT: try { - ret = - detail::make_stvar(amountFromJson(field, value)); + ret = detail::make_stvar(amountFromJson(field, value)); } catch (std::exception const&) { @@ -725,8 +637,7 @@ parseLeaf( case STI_NUMBER: try { - ret = - detail::make_stvar(numberFromJson(field, value)); + ret = detail::make_stvar(numberFromJson(field, value)); } catch (std::exception const&) { @@ -790,8 +701,7 @@ parseLeaf( { std::stringstream ss; ss << fieldName << "[" << i << "][" << j << "]"; - std::string const element_name( - json_name + "." + ss.str()); + std::string const element_name(json_name + "." + ss.str()); // each element in this path has some combination of // account, currency, or issuer @@ -822,8 +732,7 @@ parseLeaf( // human account id if (!account.isString()) { - error = - string_expected(element_name, "account"); + error = string_expected(element_name, "account"); return ret; } @@ -831,12 +740,10 @@ parseLeaf( // we set it, otherwise, we assume it's an AccountID if (!uAccount.parseHex(account.asString())) { - auto const a = - parseBase58(account.asString()); + auto const a = parseBase58(account.asString()); if (!a) { - error = - invalid_data(element_name, "account"); + error = invalid_data(element_name, "account"); return ret; } uAccount = *a; @@ -848,8 +755,7 @@ parseLeaf( // human currency if (!currency.isString()) { - error = - string_expected(element_name, "currency"); + error = string_expected(element_name, "currency"); return ret; } @@ -857,11 +763,9 @@ parseLeaf( if (!uCurrency.parseHex(currency.asString())) { - if (!to_currency( - uCurrency, currency.asString())) + if (!to_currency(uCurrency, currency.asString())) { - error = - invalid_data(element_name, "currency"); + error = invalid_data(element_name, "currency"); return ret; } } @@ -878,20 +782,17 @@ parseLeaf( if (!uIssuer.parseHex(issuer.asString())) { - auto const a = - parseBase58(issuer.asString()); + auto const a = parseBase58(issuer.asString()); if (!a) { - error = - invalid_data(element_name, "issuer"); + error = invalid_data(element_name, "issuer"); return ret; } uIssuer = *a; } } - p.emplace_back( - uAccount, uCurrency, uIssuer, hasCurrency); + p.emplace_back(uAccount, uCurrency, uIssuer, hasCurrency); } tail.push_back(p); @@ -949,8 +850,7 @@ parseLeaf( case STI_XCHAIN_BRIDGE: try { - ret = detail::make_stvar( - STXChainBridge(field, value)); + ret = detail::make_stvar(STXChainBridge(field, value)); } catch (std::exception const&) { @@ -962,8 +862,7 @@ parseLeaf( case STI_CURRENCY: try { - ret = detail::make_stvar( - currencyFromJson(field, value)); + ret = detail::make_stvar(currencyFromJson(field, value)); } catch (std::exception const&) { @@ -984,20 +883,10 @@ static int const maxDepth = 64; // Forward declaration since parseObject() and parseArray() call each other. static std::optional -parseArray( - std::string const& json_name, - Json::Value const& json, - SField const& inName, - int depth, - Json::Value& error); +parseArray(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error); static std::optional -parseObject( - std::string const& json_name, - Json::Value const& json, - SField const& inName, - int depth, - Json::Value& error) +parseObject(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error) { if (!json.isObjectOrNull()) { @@ -1042,12 +931,7 @@ parseObject( try { - auto ret = parseObject( - json_name + "." + fieldName, - value, - field, - depth + 1, - error); + auto ret = parseObject(json_name + "." + fieldName, value, field, depth + 1, error); if (!ret) return std::nullopt; data.emplace_back(std::move(*ret)); @@ -1064,12 +948,7 @@ parseObject( case STI_ARRAY: try { - auto array = parseArray( - json_name + "." + fieldName, - value, - field, - depth + 1, - error); + auto array = parseArray(json_name + "." + fieldName, value, field, depth + 1, error); if (!array.has_value()) return std::nullopt; data.emplace_back(std::move(*array)); @@ -1084,8 +963,7 @@ parseObject( // Everything else (types that don't recurse). default: { - auto leaf = - parseLeaf(json_name, fieldName, &inName, value, error); + auto leaf = parseLeaf(json_name, fieldName, &inName, value, error); if (!leaf) return std::nullopt; @@ -1115,12 +993,7 @@ parseObject( } static std::optional -parseArray( - std::string const& json_name, - Json::Value const& json, - SField const& inName, - int depth, - Json::Value& error) +parseArray(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error) { if (!json.isArrayOrNull()) { @@ -1168,13 +1041,11 @@ parseArray( std::stringstream ss; ss << json_name << "." << "[" << i << "]." << objectName; - auto ret = parseObject( - ss.str(), objectFields, nameField, depth + 1, error); + auto ret = parseObject(ss.str(), objectFields, nameField, depth + 1, error); if (!ret) { std::string errMsg = error["error_message"].asString(); - error["error_message"] = - "Error at '" + ss.str() + "'. " + errMsg; + error["error_message"] = "Error at '" + ss.str() + "'. " + errMsg; return std::nullopt; } @@ -1201,12 +1072,10 @@ parseArray( //------------------------------------------------------------------------------ -STParsedJSONObject::STParsedJSONObject( - std::string const& name, - Json::Value const& json) +STParsedJSONObject::STParsedJSONObject(std::string const& name, Json::Value const& json) { using namespace STParsedJSONDetail; object = parseObject(name, json, sfGeneric, 0, error); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp index 1252ca7c6c..060f5c4d7c 100644 --- a/src/libxrpl/protocol/STPathSet.cpp +++ b/src/libxrpl/protocol/STPathSet.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -34,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { std::size_t STPathElement::get_hash(STPathElement const& element) @@ -66,8 +47,7 @@ STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name) { int iType = sit.get8(); - if (iType == STPathElement::typeNone || - iType == STPathElement::typeBoundary) + if (iType == STPathElement::typeNone || iType == STPathElement::typeBoundary) { if (path.empty()) { @@ -83,8 +63,7 @@ STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name) } else if (iType & ~STPathElement::typeAll) { - JLOG(debugLog().error()) - << "Bad path element " << iType << " in pathset"; + JLOG(debugLog().error()) << "Bad path element " << iType << " in pathset"; Throw("bad path element"); } else @@ -158,15 +137,11 @@ STPathSet::isDefault() const } bool -STPath::hasSeen( - AccountID const& account, - Currency const& currency, - AccountID const& issuer) const +STPath::hasSeen(AccountID const& account, Currency const& currency, AccountID const& issuer) const { for (auto& p : mPath) { - if (p.getAccountID() == account && p.getCurrency() == currency && - p.getIssuerID() == issuer) + if (p.getAccountID() == account && p.getCurrency() == currency && p.getIssuerID() == issuer) return true; } @@ -219,11 +194,8 @@ STPathSet::getSType() const void STPathSet::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STPathSet::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == STI_PATHSET, - "ripple::STPathSet::add : valid field type"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STPathSet::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == STI_PATHSET, "xrpl::STPathSet::add : valid field type"); bool first = true; for (auto const& spPath : value) @@ -253,4 +225,4 @@ STPathSet::add(Serializer& s) const s.add8(STPathElement::typeNone); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STTakesAsset.cpp b/src/libxrpl/protocol/STTakesAsset.cpp new file mode 100644 index 0000000000..ba57f4f2a8 --- /dev/null +++ b/src/libxrpl/protocol/STTakesAsset.cpp @@ -0,0 +1,41 @@ +#include +// Do not remove. Force STTakesAsset.h first +#include + +namespace xrpl { + +void +associateAsset(SLE& sle, Asset const& asset) +{ + // Iterating by offset is the only way to get non-const references + for (int i = 0; i < sle.getCount(); ++i) + { + STBase& entry = sle.getIndex(i); + SField const& field = entry.getFName(); + if (field.shouldMeta(SField::sMD_NeedsAsset)) + { + auto const type = entry.getSType(); + // If the field is not set or present, skip it. + if (type == STI_NOTPRESENT) + continue; + + // If the type doesn't downcast, then the flag shouldn't be on the + // SField + auto& ta = entry.downcast(); + auto const style = sle.getStyle(ta.getFName()); + XRPL_ASSERT_PARTS(style != soeINVALID, "xrpl::associateAsset", "valid template element style"); + + XRPL_ASSERT_PARTS(style != soeDEFAULT || !ta.isDefault(), "xrpl::associateAsset", "non-default value"); + ta.associateAsset(asset); + + // associateAsset in derived classes may change the underlying + // value, but it won't know anything about how the value relates to + // the SLE. If the template element is soeDEFAULT, and the value + // changed to the default value, remove the field. + if (style == soeDEFAULT && ta.isDefault()) + sle.makeFieldAbsent(field); + } + } +} + +} // namespace xrpl diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 7326f48424..5dea8be56d 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -70,7 +51,7 @@ #include #include -namespace ripple { +namespace xrpl { static auto getTxFormat(TxType type) @@ -80,8 +61,7 @@ getTxFormat(TxType type) if (format == nullptr) { Throw( - "Invalid transaction type " + - std::to_string(safe_cast>(type))); + "Invalid transaction type " + std::to_string(safe_cast>(type))); } return format; @@ -110,8 +90,7 @@ STTx::STTx(SerialIter& sit) : STObject(sfTransaction) tid_ = getHash(HashPrefix::transactionID); } -STTx::STTx(TxType type, std::function assembler) - : STObject(sfTransaction) +STTx::STTx(TxType type, std::function assembler) : STObject(sfTransaction) { auto format = getTxFormat(type); @@ -167,9 +146,7 @@ STTx::getMentionedAccounts() const { if (auto sacc = dynamic_cast(&it)) { - XRPL_ASSERT( - !sacc->isDefault(), - "ripple::STTx::getMentionedAccounts : account is set"); + XRPL_ASSERT(!sacc->isDefault(), "xrpl::STTx::getMentionedAccounts : account is set"); if (!sacc->isDefault()) list.insert(sacc->value()); } @@ -241,7 +218,7 @@ STTx::sign( { auto const data = getSigningData(*this); - auto const sig = ripple::sign(publicKey, secretKey, makeSlice(data)); + auto const sig = xrpl::sign(publicKey, secretKey, makeSlice(data)); if (signatureTarget) { @@ -256,10 +233,7 @@ STTx::sign( } Expected -STTx::checkSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules, - STObject const& sigObject) const +STTx::checkSign(Rules const& rules, STObject const& sigObject) const { try { @@ -268,9 +242,7 @@ STTx::checkSign( // multi-signing. Otherwise we're single-signing. Blob const& signingPubKey = sigObject.getFieldVL(sfSigningPubKey); - return signingPubKey.empty() - ? checkMultiSign(requireCanonicalSig, rules, sigObject) - : checkSingleSign(requireCanonicalSig, sigObject); + return signingPubKey.empty() ? checkMultiSign(rules, sigObject) : checkSingleSign(sigObject); } catch (std::exception const&) { @@ -279,35 +251,26 @@ STTx::checkSign( } Expected -STTx::checkSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules) const +STTx::checkSign(Rules const& rules) const { - if (auto const ret = checkSign(requireCanonicalSig, rules, *this); !ret) + if (auto const ret = checkSign(rules, *this); !ret) return ret; - /* Placeholder for field that will be added by Lending Protocol if (isFieldPresent(sfCounterpartySignature)) { auto const counterSig = getFieldObject(sfCounterpartySignature); - if (auto const ret = checkSign(requireCanonicalSig, rules, counterSig); - !ret) + if (auto const ret = checkSign(rules, counterSig); !ret) return Unexpected("Counterparty: " + ret.error()); } - */ return {}; } Expected -STTx::checkBatchSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules) const +STTx::checkBatchSign(Rules const& rules) const { try { - XRPL_ASSERT( - getTxnType() == ttBATCH, - "STTx::checkBatchSign : not a batch transaction"); + XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchSign : not a batch transaction"); if (getTxnType() != ttBATCH) { JLOG(debugLog().fatal()) << "not a batch transaction"; @@ -317,9 +280,8 @@ STTx::checkBatchSign( for (auto const& signer : signers) { Blob const& signingPubKey = signer.getFieldVL(sfSigningPubKey); - auto const result = signingPubKey.empty() - ? checkBatchMultiSign(signer, requireCanonicalSig, rules) - : checkBatchSingleSign(signer, requireCanonicalSig); + auto const result = + signingPubKey.empty() ? checkBatchMultiSign(signer, rules) : checkBatchSingleSign(signer); if (!result) return result; @@ -328,8 +290,7 @@ STTx::checkBatchSign( } catch (std::exception const& e) { - JLOG(debugLog().error()) - << "Batch signature check failed: " << e.what(); + JLOG(debugLog().error()) << "Batch signature check failed: " << e.what(); } return Unexpected("Internal batch signature check failure."); } @@ -384,8 +345,7 @@ STTx::getMetaSQLInsertReplaceHeader() } std::string -STTx::getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) - const +STTx::getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const { Serializer s; add(s); @@ -394,30 +354,21 @@ STTx::getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) // VFALCO This could be a free function elsewhere std::string -STTx::getMetaSQL( - Serializer rawTxn, - std::uint32_t inLedger, - char status, - std::string const& escapedMetaData) const +STTx::getMetaSQL(Serializer rawTxn, std::uint32_t inLedger, char status, std::string const& escapedMetaData) const { - static boost::format bfTrans( - "('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)"); + static boost::format bfTrans("('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)"); std::string rTxn = sqlBlobLiteral(rawTxn.peekData()); auto format = TxFormats::getInstance().findByType(tx_type_); - XRPL_ASSERT(format, "ripple::STTx::getMetaSQL : non-null type format"); + XRPL_ASSERT(format, "xrpl::STTx::getMetaSQL : non-null type format"); return str( - boost::format(bfTrans) % to_string(getTransactionID()) % - format->getName() % toBase58(getAccountID(sfAccount)) % + boost::format(bfTrans) % to_string(getTransactionID()) % format->getName() % toBase58(getAccountID(sfAccount)) % getFieldU32(sfSequence) % inLedger % status % rTxn % escapedMetaData); } static Expected -singleSignHelper( - STObject const& sigObject, - Slice const& data, - bool const fullyCanonical) +singleSignHelper(STObject const& sigObject, Slice const& data) { // We don't allow both a non-empty sfSigningPubKey and an sfSigners. // That would allow the transaction to be signed two ways. So if both @@ -432,11 +383,7 @@ singleSignHelper( if (publicKeyType(makeSlice(spk))) { Blob const signature = sigObject.getFieldVL(sfTxnSignature); - validSig = verify( - PublicKey(makeSlice(spk)), - data, - makeSlice(signature), - fullyCanonical); + validSig = verify(PublicKey(makeSlice(spk)), data, makeSlice(signature)); } } catch (std::exception const&) @@ -451,33 +398,24 @@ singleSignHelper( } Expected -STTx::checkSingleSign( - RequireFullyCanonicalSig requireCanonicalSig, - STObject const& sigObject) const +STTx::checkSingleSign(STObject const& sigObject) const { auto const data = getSigningData(*this); - bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) || - (requireCanonicalSig == STTx::RequireFullyCanonicalSig::yes); - return singleSignHelper(sigObject, makeSlice(data), fullyCanonical); + return singleSignHelper(sigObject, makeSlice(data)); } Expected -STTx::checkBatchSingleSign( - STObject const& batchSigner, - RequireFullyCanonicalSig requireCanonicalSig) const +STTx::checkBatchSingleSign(STObject const& batchSigner) const { Serializer msg; serializeBatch(msg, getFlags(), getBatchTransactionIDs()); - bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) || - (requireCanonicalSig == STTx::RequireFullyCanonicalSig::yes); - return singleSignHelper(batchSigner, msg.slice(), fullyCanonical); + return singleSignHelper(batchSigner, msg.slice()); } Expected multiSignHelper( STObject const& sigObject, std::optional txnAccountID, - bool const fullyCanonical, std::function makeMsg, Rules const& rules) { @@ -494,8 +432,7 @@ multiSignHelper( STArray const& signers{sigObject.getFieldArray(sfSigners)}; // There are well known bounds that the number of signers must be within. - if (signers.size() < STTx::minMultiSigners || - signers.size() > STTx::maxMultiSigners(&rules)) + if (signers.size() < STTx::minMultiSigners || signers.size() > STTx::maxMultiSigners) return Unexpected("Invalid Signers array size."); // Signers must be in sorted order by AccountID. @@ -531,11 +468,7 @@ multiSignHelper( if (publicKeyType(makeSlice(spk))) { Blob const signature = signer.getFieldVL(sfTxnSignature); - validSig = verify( - PublicKey(makeSlice(spk)), - makeMsg(accountID).slice(), - makeSlice(signature), - fullyCanonical); + validSig = verify(PublicKey(makeSlice(spk)), makeMsg(accountID).slice(), makeSlice(signature)); } } catch (std::exception const& e) @@ -546,22 +479,15 @@ multiSignHelper( } if (!validSig) return Unexpected( - std::string("Invalid signature on account ") + - toBase58(accountID) + errorWhat.value_or("") + "."); + std::string("Invalid signature on account ") + toBase58(accountID) + errorWhat.value_or("") + "."); } // All signatures verified. return {}; } Expected -STTx::checkBatchMultiSign( - STObject const& batchSigner, - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules) const +STTx::checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const { - bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) || - (requireCanonicalSig == RequireFullyCanonicalSig::yes); - // We can ease the computational load inside the loop a bit by // pre-constructing part of the data that we hash. Fill a Serializer // with the stuff that stays constant from signature to signature. @@ -570,7 +496,6 @@ STTx::checkBatchMultiSign( return multiSignHelper( batchSigner, std::nullopt, - fullyCanonical, [&dataStart](AccountID const& accountID) -> Serializer { Serializer s = dataStart; finishMultiSigningData(accountID, s); @@ -580,19 +505,11 @@ STTx::checkBatchMultiSign( } Expected -STTx::checkMultiSign( - RequireFullyCanonicalSig requireCanonicalSig, - Rules const& rules, - STObject const& sigObject) const +STTx::checkMultiSign(Rules const& rules, STObject const& sigObject) const { - bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) || - (requireCanonicalSig == RequireFullyCanonicalSig::yes); - // Used inside the loop in multiSignHelper to enforce that // the account owner may not multisign for themselves. - auto const txnAccountID = &sigObject != this - ? std::nullopt - : std::optional(getAccountID(sfAccount)); + auto const txnAccountID = &sigObject != this ? std::nullopt : std::optional(getAccountID(sfAccount)); // We can ease the computational load inside the loop a bit by // pre-constructing part of the data that we hash. Fill a Serializer @@ -601,7 +518,6 @@ STTx::checkMultiSign( return multiSignHelper( sigObject, txnAccountID, - fullyCanonical, [&dataStart](AccountID const& accountID) -> Serializer { Serializer s = dataStart; finishMultiSigningData(accountID, s); @@ -628,12 +544,8 @@ STTx::checkMultiSign( std::vector const& STTx::getBatchTransactionIDs() const { - XRPL_ASSERT( - getTxnType() == ttBATCH, - "STTx::getBatchTransactionIDs : not a batch transaction"); - XRPL_ASSERT( - getFieldArray(sfRawTransactions).size() != 0, - "STTx::getBatchTransactionIDs : empty raw transactions"); + XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::getBatchTransactionIDs : not a batch transaction"); + XRPL_ASSERT(getFieldArray(sfRawTransactions).size() != 0, "STTx::getBatchTransactionIDs : empty raw transactions"); // The list of inner ids is built once, then reused on subsequent calls. // After the list is built, it must always have the same size as the array @@ -686,8 +598,7 @@ isMemoOkay(STObject const& st, std::string& reason) { auto const& name = memoElement.getFName(); - if (name != sfMemoType && name != sfMemoData && - name != sfMemoFormat) + if (name != sfMemoType && name != sfMemoData && name != sfMemoFormat) { reason = "A memo may contain only MemoType, MemoData or " @@ -763,18 +674,15 @@ invalidMPTAmountInTx(STObject const& tx) auto const txType = tx[~sfTransactionType]; if (!txType) return false; - if (auto const* item = - TxFormats::getInstance().findByType(safe_cast(*txType))) + if (auto const* item = TxFormats::getInstance().findByType(safe_cast(*txType))) { for (auto const& e : item->getSOTemplate()) { if (tx.isFieldPresent(e.sField()) && e.supportMPT() != soeMPTNone) { if (auto const& field = tx.peekAtField(e.sField()); - (field.getSType() == STI_AMOUNT && - static_cast(field).holds()) || - (field.getSType() == STI_ISSUE && - static_cast(field).holds())) + (field.getSType() == STI_AMOUNT && static_cast(field).holds()) || + (field.getSType() == STI_ISSUE && static_cast(field).holds())) { if (e.supportMPT() != soeMPTSupported) return true; @@ -791,8 +699,7 @@ isRawTransactionOkay(STObject const& st, std::string& reason) if (!st.isFieldPresent(sfRawTransactions)) return true; - if (st.isFieldPresent(sfBatchSigners) && - st.getFieldArray(sfBatchSigners).size() > maxBatchTxCount) + if (st.isFieldPresent(sfBatchSigners) && st.getFieldArray(sfBatchSigners).size() > maxBatchTxCount) { reason = "Batch Signers array exceeds max entries."; return false; @@ -808,8 +715,7 @@ isRawTransactionOkay(STObject const& st, std::string& reason) { try { - TxType const tt = - safe_cast(raw.getFieldU16(sfTransactionType)); + TxType const tt = safe_cast(raw.getFieldU16(sfTransactionType)); if (tt == ttBATCH) { reason = "Raw Transactions may not contain batch transactions."; @@ -879,4 +785,4 @@ isPseudoTx(STObject const& tx) return tt == ttAMENDMENT || tt == ttFEE || tt == ttUNL_MODIFY; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STValidation.cpp b/src/libxrpl/protocol/STValidation.cpp index 51246a1830..2bea078809 100644 --- a/src/libxrpl/protocol/STValidation.cpp +++ b/src/libxrpl/protocol/STValidation.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { STBase* STValidation::copy(std::size_t n, void* buf) const @@ -70,7 +51,6 @@ STValidation::validationFormat() {sfSigningPubKey, soeREQUIRED}, {sfSignature, soeREQUIRED}, {sfConsensusHash, soeOPTIONAL}, - // featureHardenedValidations {sfCookie, soeDEFAULT}, {sfValidatedHash, soeOPTIONAL}, {sfServerVersion, soeOPTIONAL}, @@ -120,14 +100,10 @@ STValidation::isValid() const noexcept if (!valid_) { XRPL_ASSERT( - publicKeyType(getSignerPublic()) == KeyType::secp256k1, - "ripple::STValidation::isValid : valid key type"); + publicKeyType(getSignerPublic()) == KeyType::secp256k1, "xrpl::STValidation::isValid : valid key type"); valid_ = verifyDigest( - getSignerPublic(), - getSigningHash(), - makeSlice(getFieldVL(sfSignature)), - getFlags() & vfFullyCanonicalSig); + getSignerPublic(), getSigningHash(), makeSlice(getFieldVL(sfSignature)), getFlags() & vfFullyCanonicalSig); } return valid_.value(); @@ -153,4 +129,4 @@ STValidation::getSerialized() const return s.peekData(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index c46effb47e..d77aabc312 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -41,7 +22,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { defaultObject_t defaultObject; @@ -112,8 +93,7 @@ STVar::STVar(defaultObject_t, SField const& name) : STVar(name.fieldType, name) { } -STVar::STVar(nonPresentObject_t, SField const& name) - : STVar(STI_NOTPRESENT, name) +STVar::STVar(nonPresentObject_t, SField const& name) : STVar(STI_NOTPRESENT, name) { } @@ -128,7 +108,7 @@ STVar::STVar(SerializedTypeID id, SField const& name) { XRPL_ASSERT( (id == STI_NOTPRESENT) || (id == name.fieldType), - "ripple::detail::STVar::STVar(SerializedTypeID) : valid type input"); + "xrpl::detail::STVar::STVar(SerializedTypeID) : valid type input"); constructST(id, 0, name); } @@ -149,22 +129,17 @@ void STVar::constructST(SerializedTypeID id, int depth, Args&&... args) { auto constructWithDepth = [&]() { - if constexpr (std::is_same_v< - std::tuple...>, - std::tuple>) + if constexpr (std::is_same_v...>, std::tuple>) { construct(std::forward(args)...); } - else if constexpr (std::is_same_v< - std::tuple...>, - std::tuple>) + else if constexpr (std::is_same_v...>, std::tuple>) { construct(std::forward(args)..., depth); } else { - constexpr bool alwaysFalse = - !std::is_same_v, std::tuple>; + constexpr bool alwaysFalse = !std::is_same_v, std::tuple>; static_assert(alwaysFalse, "Invalid STVar constructor arguments"); } }; @@ -173,8 +148,7 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args) { case STI_NOTPRESENT: { // Last argument is always SField - SField const& field = - std::get(std::forward_as_tuple(args...)); + SField const& field = std::get(std::forward_as_tuple(args...)); construct(field); return; } @@ -244,4 +218,4 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args) } } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 3612b0cc4d..312184dcc0 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,16 +12,14 @@ #include #include -namespace ripple { +namespace xrpl { STVector256::STVector256(SerialIter& sit, SField const& name) : STBase(name) { auto const slice = sit.getSlice(sit.getVLDataLength()); if (slice.size() % uint256::size() != 0) - Throw( - "Bad serialization for STVector256: " + - std::to_string(slice.size())); + Throw("Bad serialization for STVector256: " + std::to_string(slice.size())); auto const cnt = slice.size() / uint256::size(); @@ -77,11 +56,8 @@ STVector256::isDefault() const void STVector256::add(Serializer& s) const { - XRPL_ASSERT( - getFName().isBinary(), "ripple::STVector256::add : field is binary"); - XRPL_ASSERT( - getFName().fieldType == STI_VECTOR256, - "ripple::STVector256::add : valid field type"); + XRPL_ASSERT(getFName().isBinary(), "xrpl::STVector256::add : field is binary"); + XRPL_ASSERT(getFName().fieldType == STI_VECTOR256, "xrpl::STVector256::add : valid field type"); s.addVL(mValue.begin(), mValue.end(), mValue.size() * (256 / 8)); } @@ -103,4 +79,4 @@ STVector256::getJson(JsonOptions) const return ret; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/STXChainBridge.cpp b/src/libxrpl/protocol/STXChainBridge.cpp index e835735f08..ed79c28f29 100644 --- a/src/libxrpl/protocol/STXChainBridge.cpp +++ b/src/libxrpl/protocol/STXChainBridge.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { STXChainBridge::STXChainBridge() : STBase{sfXChainBridge} { @@ -69,30 +50,25 @@ STXChainBridge::STXChainBridge(STObject const& o) { } -STXChainBridge::STXChainBridge(Json::Value const& v) - : STXChainBridge{sfXChainBridge, v} +STXChainBridge::STXChainBridge(Json::Value const& v) : STXChainBridge{sfXChainBridge, v} { } -STXChainBridge::STXChainBridge(SField const& name, Json::Value const& v) - : STBase{name} +STXChainBridge::STXChainBridge(SField const& name, Json::Value const& v) : STBase{name} { if (!v.isObject()) { - Throw( - "STXChainBridge can only be specified with a 'object' Json value"); + Throw("STXChainBridge can only be specified with a 'object' Json value"); } auto checkExtra = [](Json::Value const& v) { - static auto const jbridge = - ripple::STXChainBridge().getJson(ripple::JsonOptions::none); + static auto const bridgeJson = xrpl::STXChainBridge().getJson(xrpl::JsonOptions::none); for (auto it = v.begin(); it != v.end(); ++it) { std::string const name = it.memberName(); - if (!jbridge.isMember(name)) + if (!bridgeJson.isMember(name)) { - Throw( - "STXChainBridge extra field detected: " + name); + Throw("STXChainBridge extra field detected: " + name); } } return true; @@ -106,36 +82,28 @@ STXChainBridge::STXChainBridge(SField const& name, Json::Value const& v) if (!lockingChainDoorStr.isString()) { - Throw( - "STXChainBridge LockingChainDoor must be a string Json value"); + Throw("STXChainBridge LockingChainDoor must be a string Json value"); } if (!issuingChainDoorStr.isString()) { - Throw( - "STXChainBridge IssuingChainDoor must be a string Json value"); + Throw("STXChainBridge IssuingChainDoor must be a string Json value"); } - auto const lockingChainDoor = - parseBase58(lockingChainDoorStr.asString()); - auto const issuingChainDoor = - parseBase58(issuingChainDoorStr.asString()); + auto const lockingChainDoor = parseBase58(lockingChainDoorStr.asString()); + auto const issuingChainDoor = parseBase58(issuingChainDoorStr.asString()); if (!lockingChainDoor) { - Throw( - "STXChainBridge LockingChainDoor must be a valid account"); + Throw("STXChainBridge LockingChainDoor must be a valid account"); } if (!issuingChainDoor) { - Throw( - "STXChainBridge IssuingChainDoor must be a valid account"); + Throw("STXChainBridge IssuingChainDoor must be a valid account"); } lockingChainDoor_ = STAccount{sfLockingChainDoor, *lockingChainDoor}; - lockingChainIssue_ = - STIssue{sfLockingChainIssue, issueFromJson(lockingChainIssue)}; + lockingChainIssue_ = STIssue{sfLockingChainIssue, issueFromJson(lockingChainIssue)}; issuingChainDoor_ = STAccount{sfIssuingChainDoor, *issuingChainDoor}; - issuingChainIssue_ = - STIssue{sfIssuingChainIssue, issueFromJson(issuingChainIssue)}; + issuingChainIssue_ = STIssue{sfIssuingChainIssue, issueFromJson(issuingChainIssue)}; } STXChainBridge::STXChainBridge(SerialIter& sit, SField const& name) @@ -171,11 +139,10 @@ std::string STXChainBridge::getText() const { return str( - boost::format("{ %s = %s, %s = %s, %s = %s, %s = %s }") % - sfLockingChainDoor.getName() % lockingChainDoor_.getText() % - sfLockingChainIssue.getName() % lockingChainIssue_.getText() % - sfIssuingChainDoor.getName() % issuingChainDoor_.getText() % - sfIssuingChainIssue.getName() % issuingChainIssue_.getText()); + boost::format("{ %s = %s, %s = %s, %s = %s, %s = %s }") % sfLockingChainDoor.getName() % + lockingChainDoor_.getText() % sfLockingChainIssue.getName() % lockingChainIssue_.getText() % + sfIssuingChainDoor.getName() % issuingChainDoor_.getText() % sfIssuingChainIssue.getName() % + issuingChainIssue_.getText()); } STObject @@ -205,8 +172,8 @@ STXChainBridge::isEquivalent(STBase const& t) const bool STXChainBridge::isDefault() const { - return lockingChainDoor_.isDefault() && lockingChainIssue_.isDefault() && - issuingChainDoor_.isDefault() && issuingChainIssue_.isDefault(); + return lockingChainDoor_.isDefault() && lockingChainIssue_.isDefault() && issuingChainDoor_.isDefault() && + issuingChainIssue_.isDefault(); } std::unique_ptr @@ -226,4 +193,4 @@ STXChainBridge::move(std::size_t n, void* buf) { return emplace(n, buf, std::move(*this)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/SecretKey.cpp b/src/libxrpl/protocol/SecretKey.cpp index 06b1061c1e..ee112b9072 100644 --- a/src/libxrpl/protocol/SecretKey.cpp +++ b/src/libxrpl/protocol/SecretKey.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,7 +17,6 @@ #include #include -#include #include #include @@ -46,7 +26,7 @@ #include #include -namespace ripple { +namespace xrpl { SecretKey::~SecretKey() { @@ -97,7 +77,7 @@ deriveDeterministicRootKey(Seed const& seed) std::array buf; std::copy(seed.begin(), seed.end(), buf.begin()); - // The odds that this loop executes more than once are neglible + // The odds that this loop executes more than once are negligible // but *just* in case someone managed to generate a key that required // more iterations loop a few times. for (std::uint32_t seq = 0; seq != 128; ++seq) @@ -157,7 +137,7 @@ private: std::copy(generator_.begin(), generator_.end(), buf.begin()); copy_uint32(buf.data() + 33, seq); - // The odds that this loop executes more than once are neglible + // The odds that this loop executes more than once are negligible // but we impose a maximum limit just in case. for (std::uint32_t subseq = 0; subseq != 128; ++subseq) { @@ -176,22 +156,16 @@ private: } public: - explicit Generator(Seed const& seed) - : root_(deriveDeterministicRootKey(seed)) + explicit Generator(Seed const& seed) : root_(deriveDeterministicRootKey(seed)) { secp256k1_pubkey pubkey; - if (secp256k1_ec_pubkey_create( - secp256k1Context(), &pubkey, root_.data()) != 1) + if (secp256k1_ec_pubkey_create(secp256k1Context(), &pubkey, root_.data()) != 1) LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed"); auto len = generator_.size(); if (secp256k1_ec_pubkey_serialize( - secp256k1Context(), - generator_.data(), - &len, - &pubkey, - SECP256K1_EC_COMPRESSED) != 1) + secp256k1Context(), generator_.data(), &len, &pubkey, SECP256K1_EC_COMPRESSED) != 1) LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed"); } @@ -209,8 +183,7 @@ public: auto gsk = [this, tweak = calculateTweak(ordinal)]() { auto rpk = root_; - if (secp256k1_ec_seckey_tweak_add( - secp256k1Context(), rpk.data(), tweak.data()) == 1) + if (secp256k1_ec_seckey_tweak_add(secp256k1Context(), rpk.data(), tweak.data()) == 1) { SecretKey sk{Slice{rpk.data(), rpk.size()}}; secure_erase(rpk.data(), rpk.size()); @@ -245,8 +218,7 @@ signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest) unsigned char sig[72]; size_t len = sizeof(sig); - if (secp256k1_ecdsa_signature_serialize_der( - secp256k1Context(), sig, &len, &sig_imp) != 1) + if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sig_imp) != 1) LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed"); return Buffer{sig, len}; @@ -262,8 +234,7 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m) { case KeyType::ed25519: { Buffer b(64); - ed25519_sign( - m.data(), m.size(), sk.data(), pk.data() + 1, b.data()); + ed25519_sign(m.data(), m.size(), sk.data(), pk.data() + 1, b.data()); return b; } case KeyType::secp256k1: { @@ -283,10 +254,8 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m) unsigned char sig[72]; size_t len = sizeof(sig); - if (secp256k1_ecdsa_signature_serialize_der( - secp256k1Context(), sig, &len, &sig_imp) != 1) - LogicError( - "sign: secp256k1_ecdsa_signature_serialize_der failed"); + if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sig_imp) != 1) + LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed"); return Buffer{sig, len}; } @@ -335,22 +304,14 @@ derivePublicKey(KeyType type, SecretKey const& sk) case KeyType::secp256k1: { secp256k1_pubkey pubkey_imp; if (secp256k1_ec_pubkey_create( - secp256k1Context(), - &pubkey_imp, - reinterpret_cast(sk.data())) != 1) - LogicError( - "derivePublicKey: secp256k1_ec_pubkey_create failed"); + secp256k1Context(), &pubkey_imp, reinterpret_cast(sk.data())) != 1) + LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed"); unsigned char pubkey[33]; std::size_t len = sizeof(pubkey); - if (secp256k1_ec_pubkey_serialize( - secp256k1Context(), - pubkey, - &len, - &pubkey_imp, - SECP256K1_EC_COMPRESSED) != 1) - LogicError( - "derivePublicKey: secp256k1_ec_pubkey_serialize failed"); + if (secp256k1_ec_pubkey_serialize(secp256k1Context(), pubkey, &len, &pubkey_imp, SECP256K1_EC_COMPRESSED) != + 1) + LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed"); return PublicKey{Slice{pubkey, len}}; } @@ -401,4 +362,4 @@ parseBase58(TokenType type, std::string const& s) return SecretKey(makeSlice(result)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Seed.cpp b/src/libxrpl/protocol/Seed.cpp index 095c09e7c0..2629d08439 100644 --- a/src/libxrpl/protocol/Seed.cpp +++ b/src/libxrpl/protocol/Seed.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -39,7 +20,7 @@ #include #include -namespace ripple { +namespace xrpl { Seed::~Seed() { @@ -99,10 +80,8 @@ parseGenericSeed(std::string const& str, bool rfc1751) if (str.empty()) return std::nullopt; - if (parseBase58(str) || - parseBase58(TokenType::NodePublic, str) || - parseBase58(TokenType::AccountPublic, str) || - parseBase58(TokenType::NodePrivate, str) || + if (parseBase58(str) || parseBase58(TokenType::NodePublic, str) || + parseBase58(TokenType::AccountPublic, str) || parseBase58(TokenType::NodePrivate, str) || parseBase58(TokenType::AccountSecret, str)) { return std::nullopt; @@ -143,4 +122,4 @@ seedAs1751(Seed const& seed) return encodedKey; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index 098e68d2b2..bb3eb17ae3 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { int Serializer::add16(std::uint16_t i) @@ -53,8 +34,7 @@ Serializer::add32(HashPrefix p) { // This should never trigger; the size & type of a hash prefix are // integral parts of the protocol and unlikely to ever change. - static_assert( - std::is_same_v>); + static_assert(std::is_same_v>); return add32(safe_cast(p)); } @@ -127,8 +107,7 @@ Serializer::addFieldID(int type, int name) { int ret = mData.size(); XRPL_ASSERT( - (type > 0) && (type < 256) && (name > 0) && (name < 256), - "ripple::Serializer::addFieldID : inputs inside range"); + (type > 0) && (type < 256) && (name > 0) && (name < 256), "xrpl::Serializer::addFieldID : inputs inside range"); if (type < 16) { @@ -198,9 +177,8 @@ Serializer::addVL(Blob const& vector) int ret = addEncoded(vector.size()); addRaw(vector); XRPL_ASSERT( - mData.size() == - (ret + vector.size() + encodeLengthLength(vector.size())), - "ripple::Serializer::addVL : size matches expected"); + mData.size() == (ret + vector.size() + encodeLengthLength(vector.size())), + "xrpl::Serializer::addVL : size matches expected"); return ret; } @@ -388,8 +366,7 @@ SerialIter::get32() p_ += 4; used_ += 4; remain_ -= 4; - return (std::uint64_t(t[0]) << 24) + (std::uint64_t(t[1]) << 16) + - (std::uint64_t(t[2]) << 8) + std::uint64_t(t[3]); + return (std::uint64_t(t[0]) << 24) + (std::uint64_t(t[1]) << 16) + (std::uint64_t(t[2]) << 8) + std::uint64_t(t[3]); } std::uint64_t @@ -401,9 +378,8 @@ SerialIter::get64() p_ += 8; used_ += 8; remain_ -= 8; - return (std::uint64_t(t[0]) << 56) + (std::uint64_t(t[1]) << 48) + - (std::uint64_t(t[2]) << 40) + (std::uint64_t(t[3]) << 32) + - (std::uint64_t(t[4]) << 24) + (std::uint64_t(t[5]) << 16) + + return (std::uint64_t(t[0]) << 56) + (std::uint64_t(t[1]) << 48) + (std::uint64_t(t[2]) << 40) + + (std::uint64_t(t[3]) << 32) + (std::uint64_t(t[4]) << 24) + (std::uint64_t(t[5]) << 16) + (std::uint64_t(t[6]) << 8) + std::uint64_t(t[7]); } @@ -443,8 +419,7 @@ SerialIter::getFieldID(int& type, int& name) // uncommon type type = get8(); if (type < 16) - Throw( - "gFID: uncommon type out of range " + std::to_string(type)); + Throw("gFID: uncommon type out of range " + std::to_string(type)); } if (name == 0) @@ -452,8 +427,7 @@ SerialIter::getFieldID(int& type, int& name) // uncommon name name = get8(); if (name < 16) - Throw( - "gFID: uncommon name out of range " + std::to_string(name)); + Throw("gFID: uncommon name out of range " + std::to_string(name)); } } @@ -462,8 +436,7 @@ template T SerialIter::getRawHelper(int size) { - static_assert( - std::is_same::value || std::is_same::value, ""); + static_assert(std::is_same::value || std::is_same::value, ""); if (remain_ < size) Throw("invalid SerialIter getRaw"); T result(size); @@ -504,8 +477,7 @@ SerialIter::getVLDataLength() } else { - XRPL_ASSERT( - lenLen == 3, "ripple::SerialIter::getVLDataLength : lenLen is 3"); + XRPL_ASSERT(lenLen == 3, "xrpl::SerialIter::getVLDataLength : lenLen is 3"); int b2 = get8(); int b3 = get8(); datLen = Serializer::decodeVLLength(b1, b2, b3); @@ -538,4 +510,4 @@ SerialIter::getVLBuffer() return getRawHelper(getVLDataLength()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/Sign.cpp b/src/libxrpl/protocol/Sign.cpp index 27c2b0435c..fe18941940 100644 --- a/src/libxrpl/protocol/Sign.cpp +++ b/src/libxrpl/protocol/Sign.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,15 +9,10 @@ #include #include -namespace ripple { +namespace xrpl { void -sign( - STObject& st, - HashPrefix const& prefix, - KeyType type, - SecretKey const& sk, - SF_VL const& sigField) +sign(STObject& st, HashPrefix const& prefix, KeyType type, SecretKey const& sk, SF_VL const& sigField) { Serializer ss; ss.add32(prefix); @@ -45,11 +21,7 @@ sign( } bool -verify( - STObject const& st, - HashPrefix const& prefix, - PublicKey const& pk, - SF_VL const& sigField) +verify(STObject const& st, HashPrefix const& prefix, PublicKey const& pk, SF_VL const& sigField) { auto const sig = get(st, sigField); if (!sig) @@ -57,8 +29,7 @@ verify( Serializer ss; ss.add32(prefix); st.addWithoutSigningFields(ss); - return verify( - pk, Slice(ss.data(), ss.size()), Slice(sig->data(), sig->size())); + return verify(pk, Slice(ss.data(), ss.size()), Slice(sig->data(), sig->size())); } // Questions regarding buildMultiSigningData: @@ -109,4 +80,4 @@ startMultiSigningData(STObject const& obj) return s; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index b9fdefd1a5..eee27e58da 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,11 +8,9 @@ #include #include -namespace ripple { +namespace xrpl { -std::unordered_map< - TERUnderlyingType, - std::pair> const& +std::unordered_map> const& transResults() { // clang-format off @@ -286,11 +265,9 @@ transCode(std::string const& token) static auto const results = [] { auto& byTer = transResults(); auto range = boost::make_iterator_range(byTer.begin(), byTer.end()); - auto tRange = boost::adaptors::transform(range, [](auto const& r) { - return std::make_pair(r.second.first, r.first); - }); - std::unordered_map const byToken( - tRange.begin(), tRange.end()); + auto tRange = + boost::adaptors::transform(range, [](auto const& r) { return std::make_pair(r.second.first, r.first); }); + std::unordered_map const byToken(tRange.begin(), tRange.end()); return byToken; }(); @@ -302,4 +279,4 @@ transCode(std::string const& token) return TER::fromInt(r->second); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/TxFormats.cpp b/src/libxrpl/protocol/TxFormats.cpp index 1966c29b51..00a560de1b 100644 --- a/src/libxrpl/protocol/TxFormats.cpp +++ b/src/libxrpl/protocol/TxFormats.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { TxFormats::TxFormats() { @@ -55,8 +36,7 @@ TxFormats::TxFormats() #undef TRANSACTION #define UNWRAP(...) __VA_ARGS__ -#define TRANSACTION( \ - tag, value, name, delegatable, amendment, privileges, fields) \ +#define TRANSACTION(tag, value, name, delegable, amendment, privileges, fields) \ add(jss::name, tag, UNWRAP fields, commonFields); #include @@ -74,4 +54,4 @@ TxFormats::getInstance() return instance; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 965a955e44..62e62a9b5c 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,21 +18,16 @@ #include #include -namespace ripple { +namespace xrpl { TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj) - : transactionID_(txid) - , ledgerSeq_(ledger) - , nodes_(obj.getFieldArray(sfAffectedNodes)) + : transactionID_(txid), ledgerSeq_(ledger), nodes_(obj.getFieldArray(sfAffectedNodes)) { result_ = obj.getFieldU8(sfTransactionResult); index_ = obj.getFieldU32(sfTransactionIndex); - auto affectedNodes = - dynamic_cast(obj.peekAtPField(sfAffectedNodes)); - XRPL_ASSERT( - affectedNodes, - "ripple::TxMeta::TxMeta(STObject) : type cast succeeded"); + auto affectedNodes = dynamic_cast(obj.peekAtPField(sfAffectedNodes)); + XRPL_ASSERT(affectedNodes, "xrpl::TxMeta::TxMeta(STObject) : type cast succeeded"); if (affectedNodes) nodes_ = *affectedNodes; @@ -82,10 +58,7 @@ TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger) } void -TxMeta::setAffectedNode( - uint256 const& node, - SField const& type, - std::uint16_t nodeType) +TxMeta::setAffectedNode(uint256 const& node, SField const& type, std::uint16_t nodeType) { // make sure the node exists and force its type for (auto& n : nodes_) @@ -101,9 +74,7 @@ TxMeta::setAffectedNode( nodes_.push_back(STObject(type)); STObject& obj = nodes_.back(); - XRPL_ASSERT( - obj.getFName() == type, - "ripple::TxMeta::setAffectedNode : field type match"); + XRPL_ASSERT(obj.getFName() == type, "xrpl::TxMeta::setAffectedNode : field type match"); obj.setFieldH256(sfLedgerIndex, node); obj.setFieldU16(sfLedgerEntryType, nodeType); } @@ -118,38 +89,30 @@ TxMeta::getAffectedAccounts() const // Meta#getAffectedAccounts for (auto const& node : nodes_) { - int index = node.getFieldIndex( - (node.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields); + int index = node.getFieldIndex((node.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields); if (index != -1) { - auto const* inner = - dynamic_cast(&node.peekAtIndex(index)); - XRPL_ASSERT( - inner, - "ripple::getAffectedAccounts : STObject type cast succeeded"); + auto const* inner = dynamic_cast(&node.peekAtIndex(index)); + XRPL_ASSERT(inner, "xrpl::getAffectedAccounts : STObject type cast succeeded"); if (inner) { for (auto const& field : *inner) { if (auto sa = dynamic_cast(&field)) { - XRPL_ASSERT( - !sa->isDefault(), - "ripple::getAffectedAccounts : account is set"); + XRPL_ASSERT(!sa->isDefault(), "xrpl::getAffectedAccounts : account is set"); if (!sa->isDefault()) list.insert(sa->value()); } else if ( - (field.getFName() == sfLowLimit) || - (field.getFName() == sfHighLimit) || - (field.getFName() == sfTakerPays) || - (field.getFName() == sfTakerGets)) + (field.getFName() == sfLowLimit) || (field.getFName() == sfHighLimit) || + (field.getFName() == sfTakerPays) || (field.getFName() == sfTakerGets)) { auto lim = dynamic_cast(&field); XRPL_ASSERT( lim, - "ripple::getAffectedAccounts : STAmount type cast " + "xrpl::getAffectedAccounts : STAmount type cast " "succeeded"); if (lim != nullptr) @@ -162,8 +125,7 @@ TxMeta::getAffectedAccounts() const } else if (field.getFName() == sfMPTokenIssuanceID) { - auto mptID = - dynamic_cast const*>(&field); + auto mptID = dynamic_cast const*>(&field); if (mptID != nullptr) { auto issuer = MPTIssue(mptID->value()).getIssuer(); @@ -192,9 +154,7 @@ TxMeta::getAffectedNode(SLE::ref node, SField const& type) nodes_.push_back(STObject(type)); STObject& obj = nodes_.back(); - XRPL_ASSERT( - obj.getFName() == type, - "ripple::TxMeta::getAffectedNode(SLE::ref) : field type match"); + XRPL_ASSERT(obj.getFName() == type, "xrpl::TxMeta::getAffectedNode(SLE::ref) : field type match"); obj.setFieldH256(sfLedgerIndex, index); obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType)); @@ -210,7 +170,7 @@ TxMeta::getAffectedNode(uint256 const& node) return n; } // LCOV_EXCL_START - UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found"); + UNREACHABLE("xrpl::TxMeta::getAffectedNode(uint256) : node not found"); Throw("Affected node not found"); return *(nodes_.begin()); // Silence compiler warning. // LCOV_EXCL_STOP @@ -220,7 +180,7 @@ STObject TxMeta::getAsObject() const { STObject metaData(sfTransactionMetaData); - XRPL_ASSERT(result_ != 255, "ripple::TxMeta::getAsObject : result_ is set"); + XRPL_ASSERT(result_ != 255, "xrpl::TxMeta::getAsObject : result_ is set"); metaData.setFieldU8(sfTransactionResult, result_); metaData.setFieldU32(sfTransactionIndex, index_); metaData.emplace_back(nodes_); @@ -238,9 +198,7 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) { result_ = TERtoInt(result); index_ = index; - XRPL_ASSERT( - (result_ == 0) || ((result_ > 100) && (result_ <= 255)), - "ripple::TxMeta::addRaw : valid TER input"); + XRPL_ASSERT((result_ == 0) || ((result_ > 100) && (result_ <= 255)), "xrpl::TxMeta::addRaw : valid TER input"); nodes_.sort([](STObject const& o1, STObject const& o2) { return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); @@ -249,4 +207,4 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) getAsObject().add(s); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/UintTypes.cpp b/src/libxrpl/protocol/UintTypes.cpp index dadfccfa9f..ca29147989 100644 --- a/src/libxrpl/protocol/UintTypes.cpp +++ b/src/libxrpl/protocol/UintTypes.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { // For details on the protocol-level serialization please visit // https://xrpl.org/serialization.html#currency-codes @@ -59,19 +40,16 @@ to_string(Currency const& currency) if (currency == noCurrency()) return "1"; - static constexpr Currency sIsoBits( - "FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF"); + static constexpr Currency sIsoBits("FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF"); if ((currency & sIsoBits).isZero()) { std::string const iso( - currency.data() + detail::isoCodeOffset, - currency.data() + detail::isoCodeOffset + detail::isoCodeLength); + currency.data() + detail::isoCodeOffset, currency.data() + detail::isoCodeOffset + detail::isoCodeLength); // Specifying the system currency code using ISO-style representation // is not allowed. - if ((iso != systemCurrencyCode()) && - (iso.find_first_not_of(detail::isoCharSet) == std::string::npos)) + if ((iso != systemCurrencyCode()) && (iso.find_first_not_of(detail::isoCharSet) == std::string::npos)) { return iso; } @@ -97,8 +75,7 @@ to_currency(Currency& currency, std::string const& code) currency = beast::zero; - std::copy( - code.begin(), code.end(), currency.begin() + detail::isoCodeOffset); + std::copy(code.begin(), code.end(), currency.begin() + detail::isoCodeOffset); return true; } @@ -136,4 +113,4 @@ badCurrency() return currency; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/XChainAttestations.cpp b/src/libxrpl/protocol/XChainAttestations.cpp index e61224b570..5f109ea272 100644 --- a/src/libxrpl/protocol/XChainAttestations.cpp +++ b/src/libxrpl/protocol/XChainAttestations.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -41,7 +22,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace Attestations { AttestationBase::AttestationBase( @@ -63,9 +44,7 @@ AttestationBase::AttestationBase( } bool -AttestationBase::equalHelper( - AttestationBase const& lhs, - AttestationBase const& rhs) +AttestationBase::equalHelper(AttestationBase const& lhs, AttestationBase const& rhs) { return std::tie( lhs.attestationSignerAccount, @@ -86,23 +65,17 @@ AttestationBase::equalHelper( } bool -AttestationBase::sameEventHelper( - AttestationBase const& lhs, - AttestationBase const& rhs) +AttestationBase::sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs) { - return std::tie( - lhs.sendingAccount, - lhs.sendingAmount, - lhs.wasLockingChainSend) == - std::tie( - rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend); + return std::tie(lhs.sendingAccount, lhs.sendingAmount, lhs.wasLockingChainSend) == + std::tie(rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend); } bool AttestationBase::verify(STXChainBridge const& bridge) const { std::vector msg = message(bridge); - return ripple::verify(publicKey, makeSlice(msg), signature); + return xrpl::verify(publicKey, makeSlice(msg), signature); } AttestationBase::AttestationBase(STObject const& o) @@ -117,9 +90,7 @@ AttestationBase::AttestationBase(STObject const& o) } AttestationBase::AttestationBase(Json::Value const& v) - : attestationSignerAccount{Json::getOrThrow( - v, - sfAttestationSignerAccount)} + : attestationSignerAccount{Json::getOrThrow(v, sfAttestationSignerAccount)} , publicKey{Json::getOrThrow(v, sfPublicKey)} , signature{Json::getOrThrow(v, sfSignature)} , sendingAccount{Json::getOrThrow(v, sfAccount)} @@ -196,8 +167,7 @@ AttestationClaim::AttestationClaim(STObject const& o) } AttestationClaim::AttestationClaim(Json::Value const& v) - : AttestationBase{v} - , claimID{Json::getOrThrow(v, sfXChainClaimID)} + : AttestationBase{v}, claimID{Json::getOrThrow(v, sfXChainClaimID)} { if (v.isMember(sfDestination.getJsonName())) dst = Json::getOrThrow(v, sfDestination); @@ -206,8 +176,7 @@ AttestationClaim::AttestationClaim(Json::Value const& v) STObject AttestationClaim::toSTObject() const { - STObject o = - STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement); + STObject o = STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement); addHelper(o); o[sfXChainClaimID] = claimID; if (dst) @@ -246,13 +215,7 @@ std::vector AttestationClaim::message(STXChainBridge const& bridge) const { return AttestationClaim::message( - bridge, - sendingAccount, - sendingAmount, - rewardAccount, - wasLockingChainSend, - claimID, - dst); + bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst); } bool @@ -264,15 +227,13 @@ AttestationClaim::validAmounts() const bool AttestationClaim::sameEvent(AttestationClaim const& rhs) const { - return AttestationClaim::sameEventHelper(*this, rhs) && - tie(claimID, dst) == tie(rhs.claimID, rhs.dst); + return AttestationClaim::sameEventHelper(*this, rhs) && tie(claimID, dst) == tie(rhs.claimID, rhs.dst); } bool operator==(AttestationClaim const& lhs, AttestationClaim const& rhs) { - return AttestationClaim::equalHelper(lhs, rhs) && - tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst); + return AttestationClaim::equalHelper(lhs, rhs) && tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst); } AttestationCreateAccount::AttestationCreateAccount(STObject const& o) @@ -285,9 +246,7 @@ AttestationCreateAccount::AttestationCreateAccount(STObject const& o) AttestationCreateAccount::AttestationCreateAccount(Json::Value const& v) : AttestationBase{v} - , createCount{Json::getOrThrow( - v, - sfXChainAccountCreateCount)} + , createCount{Json::getOrThrow(v, sfXChainAccountCreateCount)} , toCreate{Json::getOrThrow(v, sfDestination)} , rewardAmount{Json::getOrThrow(v, sfSignatureReward)} { @@ -349,8 +308,7 @@ AttestationCreateAccount::AttestationCreateAccount( STObject AttestationCreateAccount::toSTObject() const { - STObject o = STObject::makeInnerObject( - sfXChainCreateAccountAttestationCollectionElement); + STObject o = STObject::makeInnerObject(sfXChainCreateAccountAttestationCollectionElement); addHelper(o); o[sfXChainAccountCreateCount] = createCount; @@ -392,14 +350,7 @@ std::vector AttestationCreateAccount::message(STXChainBridge const& bridge) const { return AttestationCreateAccount::message( - bridge, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccount, - wasLockingChainSend, - createCount, - toCreate); + bridge, sendingAccount, sendingAmount, rewardAmount, rewardAccount, wasLockingChainSend, createCount, toCreate); } bool @@ -412,14 +363,11 @@ bool AttestationCreateAccount::sameEvent(AttestationCreateAccount const& rhs) const { return AttestationCreateAccount::sameEventHelper(*this, rhs) && - std::tie(createCount, toCreate, rewardAmount) == - std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); + std::tie(createCount, toCreate, rewardAmount) == std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); } bool -operator==( - AttestationCreateAccount const& lhs, - AttestationCreateAccount const& rhs) +operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) { return AttestationCreateAccount::equalHelper(lhs, rhs) && std::tie(lhs.createCount, lhs.toCreate, lhs.rewardAmount) == @@ -429,8 +377,7 @@ operator==( } // namespace Attestations SField const& XChainClaimAttestation::ArrayFieldName{sfXChainClaimAttestations}; -SField const& XChainCreateAccountAttestation::ArrayFieldName{ - sfXChainCreateAccountAttestations}; +SField const& XChainCreateAccountAttestation::ArrayFieldName{sfXChainCreateAccountAttestations}; XChainClaimAttestation::XChainClaimAttestation( AccountID const& keyAccount_, @@ -487,8 +434,7 @@ XChainClaimAttestation::XChainClaimAttestation(Json::Value const& v) dst = Json::getOrThrow(v, sfDestination); }; -XChainClaimAttestation::XChainClaimAttestation( - XChainClaimAttestation::TSignedAttestation const& claimAtt) +XChainClaimAttestation::XChainClaimAttestation(XChainClaimAttestation::TSignedAttestation const& claimAtt) : XChainClaimAttestation{ claimAtt.attestationSignerAccount, claimAtt.publicKey, @@ -503,12 +449,10 @@ STObject XChainClaimAttestation::toSTObject() const { STObject o = STObject::makeInnerObject(sfXChainClaimProofSig); - o[sfAttestationSignerAccount] = - STAccount{sfAttestationSignerAccount, keyAccount}; + o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; o[sfPublicKey] = publicKey; o[sfAmount] = STAmount{sfAmount, amount}; - o[sfAttestationRewardAccount] = - STAccount{sfAttestationRewardAccount, rewardAccount}; + o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; o[sfWasLockingChainSend] = wasLockingChainSend; if (dst) o[sfDestination] = STAccount{sfDestination, *dst}; @@ -518,36 +462,19 @@ XChainClaimAttestation::toSTObject() const bool operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs) { - return std::tie( - lhs.keyAccount, - lhs.publicKey, - lhs.amount, - lhs.rewardAccount, - lhs.wasLockingChainSend, - lhs.dst) == - std::tie( - rhs.keyAccount, - rhs.publicKey, - rhs.amount, - rhs.rewardAccount, - rhs.wasLockingChainSend, - rhs.dst); + return std::tie(lhs.keyAccount, lhs.publicKey, lhs.amount, lhs.rewardAccount, lhs.wasLockingChainSend, lhs.dst) == + std::tie(rhs.keyAccount, rhs.publicKey, rhs.amount, rhs.rewardAccount, rhs.wasLockingChainSend, rhs.dst); } -XChainClaimAttestation::MatchFields::MatchFields( - XChainClaimAttestation::TSignedAttestation const& att) - : amount{att.sendingAmount} - , wasLockingChainSend{att.wasLockingChainSend} - , dst{att.dst} +XChainClaimAttestation::MatchFields::MatchFields(XChainClaimAttestation::TSignedAttestation const& att) + : amount{att.sendingAmount}, wasLockingChainSend{att.wasLockingChainSend}, dst{att.dst} { } AttestationMatch -XChainClaimAttestation::match( - XChainClaimAttestation::MatchFields const& rhs) const +XChainClaimAttestation::match(XChainClaimAttestation::MatchFields const& rhs) const { - if (std::tie(amount, wasLockingChainSend) != - std::tie(rhs.amount, rhs.wasLockingChainSend)) + if (std::tie(amount, wasLockingChainSend) != std::tie(rhs.amount, rhs.wasLockingChainSend)) return AttestationMatch::nonDstMismatch; if (dst != rhs.dst) return AttestationMatch::matchExceptDst; @@ -574,8 +501,7 @@ XChainCreateAccountAttestation::XChainCreateAccountAttestation( { } -XChainCreateAccountAttestation::XChainCreateAccountAttestation( - STObject const& o) +XChainCreateAccountAttestation::XChainCreateAccountAttestation(STObject const& o) : XChainCreateAccountAttestation{ o[sfAttestationSignerAccount], PublicKey{o[sfPublicKey]}, @@ -585,8 +511,7 @@ XChainCreateAccountAttestation::XChainCreateAccountAttestation( o[sfWasLockingChainSend] != 0, o[sfDestination]} {}; -XChainCreateAccountAttestation ::XChainCreateAccountAttestation( - Json::Value const& v) +XChainCreateAccountAttestation ::XChainCreateAccountAttestation(Json::Value const& v) : XChainCreateAccountAttestation{ Json::getOrThrow(v, sfAttestationSignerAccount), Json::getOrThrow(v, sfPublicKey), @@ -616,21 +541,18 @@ XChainCreateAccountAttestation::toSTObject() const { STObject o = STObject::makeInnerObject(sfXChainCreateAccountProofSig); - o[sfAttestationSignerAccount] = - STAccount{sfAttestationSignerAccount, keyAccount}; + o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; o[sfPublicKey] = publicKey; o[sfAmount] = STAmount{sfAmount, amount}; o[sfSignatureReward] = STAmount{sfSignatureReward, rewardAmount}; - o[sfAttestationRewardAccount] = - STAccount{sfAttestationRewardAccount, rewardAccount}; + o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; o[sfWasLockingChainSend] = wasLockingChainSend; o[sfDestination] = STAccount{sfDestination, dst}; return o; } -XChainCreateAccountAttestation::MatchFields::MatchFields( - XChainCreateAccountAttestation::TSignedAttestation const& att) +XChainCreateAccountAttestation::MatchFields::MatchFields(XChainCreateAccountAttestation::TSignedAttestation const& att) : amount{att.sendingAmount} , rewardAmount(att.rewardAmount) , wasLockingChainSend{att.wasLockingChainSend} @@ -639,8 +561,7 @@ XChainCreateAccountAttestation::MatchFields::MatchFields( } AttestationMatch -XChainCreateAccountAttestation::match( - XChainCreateAccountAttestation::MatchFields const& rhs) const +XChainCreateAccountAttestation::match(XChainCreateAccountAttestation::MatchFields const& rhs) const { if (std::tie(amount, rewardAmount, wasLockingChainSend) != std::tie(rhs.amount, rhs.rewardAmount, rhs.wasLockingChainSend)) @@ -651,9 +572,7 @@ XChainCreateAccountAttestation::match( } bool -operator==( - XChainCreateAccountAttestation const& lhs, - XChainCreateAccountAttestation const& rhs) +operator==(XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs) { return std::tie( lhs.keyAccount, @@ -676,8 +595,7 @@ operator==( //------------------------------------------------------------------------------ // template -XChainAttestationsBase::XChainAttestationsBase( - XChainAttestationsBase::AttCollection&& atts) +XChainAttestationsBase::XChainAttestationsBase(XChainAttestationsBase::AttCollection&& atts) : attestations_{std::move(atts)} { } @@ -711,8 +629,7 @@ XChainAttestationsBase::end() } template -XChainAttestationsBase::XChainAttestationsBase( - Json::Value const& v) +XChainAttestationsBase::XChainAttestationsBase(Json::Value const& v) { if (!v.isObject()) { @@ -725,8 +642,7 @@ XChainAttestationsBase::XChainAttestationsBase( auto const jAtts = v[jss::attestations]; if (jAtts.size() > maxAttestations) - Throw( - "XChainAttestationsBase exceeded max number of attestations"); + Throw("XChainAttestationsBase exceeded max number of attestations"); std::vector r; r.reserve(jAtts.size()); @@ -740,8 +656,7 @@ template XChainAttestationsBase::XChainAttestationsBase(STArray const& arr) { if (arr.size() > maxAttestations) - Throw( - "XChainAttestationsBase exceeded max number of attestations"); + Throw("XChainAttestationsBase exceeded max number of attestations"); attestations_.reserve(arr.size()); for (auto const& o : arr) @@ -761,4 +676,4 @@ XChainAttestationsBase::toSTArray() const template class XChainAttestationsBase; template class XChainAttestationsBase; -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/digest.cpp b/src/libxrpl/protocol/digest.cpp index 2626ec0968..aa5600dde0 100644 --- a/src/libxrpl/protocol/digest.cpp +++ b/src/libxrpl/protocol/digest.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,22 +5,17 @@ #include -namespace ripple { +namespace xrpl { openssl_ripemd160_hasher::openssl_ripemd160_hasher() { - static_assert( - sizeof(decltype(openssl_ripemd160_hasher::ctx_)) == - sizeof(RIPEMD160_CTX), - ""); + static_assert(sizeof(decltype(openssl_ripemd160_hasher::ctx_)) == sizeof(RIPEMD160_CTX), ""); auto const ctx = reinterpret_cast(ctx_); RIPEMD160_Init(ctx); } void -openssl_ripemd160_hasher::operator()( - void const* data, - std::size_t size) noexcept +openssl_ripemd160_hasher::operator()(void const* data, std::size_t size) noexcept { auto const ctx = reinterpret_cast(ctx_); RIPEMD160_Update(ctx, data, size); @@ -57,9 +33,7 @@ openssl_ripemd160_hasher::operator result_type() noexcept openssl_sha512_hasher::openssl_sha512_hasher() { - static_assert( - sizeof(decltype(openssl_sha512_hasher::ctx_)) == sizeof(SHA512_CTX), - ""); + static_assert(sizeof(decltype(openssl_sha512_hasher::ctx_)) == sizeof(SHA512_CTX), ""); auto const ctx = reinterpret_cast(ctx_); SHA512_Init(ctx); } @@ -83,9 +57,7 @@ openssl_sha512_hasher::operator result_type() noexcept openssl_sha256_hasher::openssl_sha256_hasher() { - static_assert( - sizeof(decltype(openssl_sha256_hasher::ctx_)) == sizeof(SHA256_CTX), - ""); + static_assert(sizeof(decltype(openssl_sha256_hasher::ctx_)) == sizeof(SHA256_CTX), ""); auto const ctx = reinterpret_cast(ctx_); SHA256_Init(ctx); } @@ -105,4 +77,4 @@ openssl_sha256_hasher::operator result_type() noexcept return digest; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index 52cffd7a5c..1b73b06380 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -1,21 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== // /* The base58 encoding & decoding routines in the b58_ref namespace are taken * from Bitcoin but have been modified from the original. @@ -137,10 +119,9 @@ of another base), and doing the multi-precision computations with larger coefficients sizes greatly speeds up the multi-precision computations. */ -namespace ripple { +namespace xrpl { -static constexpr char const* alphabetForward = - "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"; +static constexpr char const* alphabetForward = "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"; static constexpr std::array const alphabetReverse = []() { std::array map{}; @@ -160,11 +141,7 @@ digest(void const* data, std::size_t size) noexcept return static_cast(h); } -template < - class Hasher, - class T, - std::size_t N, - class = std::enable_if_t> +template > static typename Hasher::result_type digest(std::array const& v) { @@ -220,11 +197,7 @@ namespace b58_ref { namespace detail { std::string -encodeBase58( - void const* message, - std::size_t size, - void* temp, - std::size_t temp_size) +encodeBase58(void const* message, std::size_t size, void* temp, std::size_t temp_size) { auto pbegin = reinterpret_cast(message); auto const pend = pbegin + size; @@ -252,8 +225,7 @@ encodeBase58( iter[-1] = carry % 58; carry /= 58; } - XRPL_ASSERT( - carry == 0, "ripple::b58_ref::detail::encodeBase58 : zero carry"); + XRPL_ASSERT(carry == 0, "xrpl::b58_ref::detail::encodeBase58 : zero carry"); pbegin++; } @@ -303,14 +275,12 @@ decodeBase58(std::string const& s) *iter = carry % 256; carry /= 256; } - XRPL_ASSERT( - carry == 0, "ripple::b58_ref::detail::decodeBase58 : zero carry"); + XRPL_ASSERT(carry == 0, "xrpl::b58_ref::detail::decodeBase58 : zero carry"); ++psz; --remain; } // Skip leading zeroes in b256. - auto iter = std::find_if( - b256.begin(), b256.end(), [](unsigned char c) { return c != 0; }); + auto iter = std::find_if(b256.begin(), b256.end(), [](unsigned char c) { return c != 0; }); std::string result; result.reserve(zeroes + (b256.end() - iter)); result.assign(zeroes, 0x00); @@ -341,8 +311,7 @@ encodeBase58Token(TokenType type, void const* token, std::size_t size) std::memcpy(buf.data() + 1, token, size); checksum(buf.data() + 1 + size, buf.data(), 1 + size); - return detail::encodeBase58( - buf.data(), expanded, buf.data() + expanded, bufsize - expanded); + return detail::encodeBase58(buf.data(), expanded, buf.data() + expanded, bufsize - expanded); } std::string @@ -385,8 +354,7 @@ b256_to_b58_be(std::span input, std::span out) return Unexpected(TokenCodecErrc::inputTooLarge); }; - auto count_leading_zeros = - [](std::span const& col) -> std::size_t { + auto count_leading_zeros = [](std::span const& col) -> std::size_t { std::size_t count = 0; for (auto const& c : col) { @@ -405,8 +373,7 @@ b256_to_b58_be(std::span input, std::span out) // Allocate enough base 2^64 coeff for encoding 38 bytes // log(2^(38*8),2^64)) ~= 4.75. So 5 coeff are enough std::array base_2_64_coeff_buf{}; - std::span const base_2_64_coeff = - [&]() -> std::span { + std::span const base_2_64_coeff = [&]() -> std::span { // convert input from big endian to native u64, lowest coeff first std::size_t num_coeff = 0; for (int i = 0; i < base_2_64_coeff_buf.size(); ++i) @@ -418,10 +385,8 @@ b256_to_b58_be(std::span input, std::span out) auto const src_i_end = input.size() - i * 8; if (src_i_end >= 8) { - std::memcpy( - &base_2_64_coeff_buf[num_coeff], &input[src_i_end - 8], 8); - boost::endian::big_to_native_inplace( - base_2_64_coeff_buf[num_coeff]); + std::memcpy(&base_2_64_coeff_buf[num_coeff], &input[src_i_end - 8], 8); + boost::endian::big_to_native_inplace(base_2_64_coeff_buf[num_coeff]); } else { @@ -448,8 +413,7 @@ b256_to_b58_be(std::span input, std::span out) while (cur_2_64_end > 0) { base_58_10_coeff[num_58_10_coeffs] = - ripple::b58_fast::detail::inplace_bigint_div_rem( - base_2_64_coeff.subspan(0, cur_2_64_end), B_58_10); + xrpl::b58_fast::detail::inplace_bigint_div_rem(base_2_64_coeff.subspan(0, cur_2_64_end), B_58_10); num_58_10_coeffs += 1; if (base_2_64_coeff[cur_2_64_end - 1] == 0) { @@ -459,8 +423,7 @@ b256_to_b58_be(std::span input, std::span out) // Translate the result into the alphabet // Put all the zeros at the beginning, then all the values from the output - std::fill( - out.begin(), out.begin() + input_zeros, ::ripple::alphabetForward[0]); + std::fill(out.begin(), out.begin() + input_zeros, ::xrpl::alphabetForward[0]); // iterate through the base 58^10 coeff // convert to base 58 big endian then @@ -478,8 +441,7 @@ b256_to_b58_be(std::span input, std::span out) { return Unexpected(TokenCodecErrc::inputTooLarge); } - std::array const b58_be = - ripple::b58_fast::detail::b58_10_to_b58_be(base_58_10_coeff[i]); + std::array const b58_be = xrpl::b58_fast::detail::b58_10_to_b58_be(base_58_10_coeff[i]); std::size_t to_skip = 0; std::span b58_be_s{b58_be.data(), b58_be.size()}; if (skip_zeros) @@ -493,7 +455,7 @@ b256_to_b58_be(std::span input, std::span out) } for (auto b58_coeff : b58_be_s.subspan(to_skip)) { - out[out_index] = ::ripple::alphabetForward[b58_coeff]; + out[out_index] = ::xrpl::alphabetForward[b58_coeff]; out_index += 1; } } @@ -522,7 +484,7 @@ b58_to_b256_be(std::string_view input, std::span out) std::size_t count = 0; for (auto const& c : col) { - if (c != ::ripple::alphabetForward[0]) + if (c != ::xrpl::alphabetForward[0]) { return count; } @@ -537,16 +499,13 @@ b58_to_b256_be(std::string_view input, std::span out) // (33 bytes for nodepublic + 1 byte token + 4 bytes checksum) // log(2^(38*8),58^10)) ~= 5.18. So 6 coeff are enough std::array b_58_10_coeff{}; - auto [num_full_coeffs, partial_coeff_len] = - ripple::b58_fast::detail::div_rem(input.size(), 10); + auto [num_full_coeffs, partial_coeff_len] = xrpl::b58_fast::detail::div_rem(input.size(), 10); auto const num_partial_coeffs = partial_coeff_len ? 1 : 0; auto const num_b_58_10_coeffs = num_full_coeffs + num_partial_coeffs; - XRPL_ASSERT( - num_b_58_10_coeffs <= b_58_10_coeff.size(), - "ripple::b58_fast::detail::b58_to_b256_be : maximum coeff"); + XRPL_ASSERT(num_b_58_10_coeffs <= b_58_10_coeff.size(), "xrpl::b58_fast::detail::b58_to_b256_be : maximum coeff"); for (unsigned char c : input.substr(0, partial_coeff_len)) { - auto cur_val = ::ripple::alphabetReverse[c]; + auto cur_val = ::xrpl::alphabetReverse[c]; if (cur_val < 0) { return Unexpected(TokenCodecErrc::invalidEncodingChar); @@ -559,7 +518,7 @@ b58_to_b256_be(std::string_view input, std::span out) for (int j = 0; j < num_full_coeffs; ++j) { unsigned char c = input[partial_coeff_len + j * 10 + i]; - auto cur_val = ::ripple::alphabetReverse[c]; + auto cur_val = ::xrpl::alphabetReverse[c]; if (cur_val < 0) { return Unexpected(TokenCodecErrc::invalidEncodingChar); @@ -580,16 +539,14 @@ b58_to_b256_be(std::string_view input, std::span out) std::uint64_t const c = b_58_10_coeff[i]; { - auto code = ripple::b58_fast::detail::inplace_bigint_mul( - std::span(&result[0], cur_result_size + 1), B_58_10); + auto code = xrpl::b58_fast::detail::inplace_bigint_mul(std::span(&result[0], cur_result_size + 1), B_58_10); if (code != TokenCodecErrc::success) { return Unexpected(code); } } { - auto code = ripple::b58_fast::detail::inplace_bigint_add( - std::span(&result[0], cur_result_size + 1), c); + auto code = xrpl::b58_fast::detail::inplace_bigint_add(std::span(&result[0], cur_result_size + 1), c); if (code != TokenCodecErrc::success) { return Unexpected(code); @@ -641,10 +598,7 @@ b58_to_b256_be(std::string_view input, std::span out) } // namespace detail B58Result> -encodeBase58Token( - TokenType token_type, - std::span input, - std::span out) +encodeBase58Token(TokenType token_type, std::span input, std::span out) { constexpr std::size_t tmpBufSize = 128; std::array buf; @@ -667,19 +621,15 @@ encodeBase58Token( return detail::b256_to_b58_be(b58Span, out); } // Convert from base 58 to base 256, largest coefficients first -// The input is encoded in XPRL format, with the token in the first +// The input is encoded in XRPL format, with the token in the first // byte and the checksum in the last four bytes. // The decoded base 256 value does not include the token type or checksum. // It is an error if the token type or checksum does not match. B58Result> -decodeBase58Token( - TokenType type, - std::string_view s, - std::span outBuf) +decodeBase58Token(TokenType type, std::string_view s, std::span outBuf) { std::array tmpBuf; - auto const decodeResult = - detail::b58_to_b256_be(s, std::span(tmpBuf.data(), tmpBuf.size())); + auto const decodeResult = detail::b58_to_b256_be(s, std::span(tmpBuf.data(), tmpBuf.size())); if (!decodeResult) return decodeResult; @@ -721,10 +671,8 @@ encodeBase58Token(TokenType type, void const* token, std::size_t size) // over-allocation, this function uses 128 (again, over-allocation assuming // 2 base 58 char per byte) sr.resize(128); - std::span outSp( - reinterpret_cast(sr.data()), sr.size()); - std::span inSp( - reinterpret_cast(token), size); + std::span outSp(reinterpret_cast(sr.data()), sr.size()); + std::span inSp(reinterpret_cast(token), size); auto r = b58_fast::encodeBase58Token(type, inSp, outSp); if (!r) return {}; @@ -739,8 +687,7 @@ decodeBase58Token(std::string const& s, TokenType type) // The largest object encoded as base58 is 33 bytes; 64 is plenty (and // there's no benefit making it smaller) sr.resize(64); - std::span outSp( - reinterpret_cast(sr.data()), sr.size()); + std::span outSp(reinterpret_cast(sr.data()), sr.size()); auto r = b58_fast::decodeBase58Token(type, s, outSp); if (!r) return {}; @@ -750,4 +697,4 @@ decodeBase58Token(std::string const& s, TokenType type) } // namespace b58_fast #endif // _MSC_VER -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/rdb/DatabaseCon.cpp b/src/libxrpl/rdb/DatabaseCon.cpp new file mode 100644 index 0000000000..344df85b4a --- /dev/null +++ b/src/libxrpl/rdb/DatabaseCon.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace xrpl { + +class CheckpointersCollection +{ + std::uintptr_t nextId_{0}; + // Mutex protects the CheckpointersCollection + std::mutex mutex_; + // Each checkpointer is given a unique id. All the checkpointers that are + // part of a DatabaseCon are part of this collection. When the DatabaseCon + // is destroyed, its checkpointer is removed from the collection + std::unordered_map> checkpointers_; + +public: + std::shared_ptr + fromId(std::uintptr_t id) + { + std::lock_guard l{mutex_}; + auto it = checkpointers_.find(id); + if (it != checkpointers_.end()) + return it->second; + return {}; + } + + void + erase(std::uintptr_t id) + { + std::lock_guard lock{mutex_}; + checkpointers_.erase(id); + } + + std::shared_ptr + create(std::shared_ptr const& session, JobQueue& jobQueue, Logs& logs) + { + std::lock_guard lock{mutex_}; + auto const id = nextId_++; + auto const r = makeCheckpointer(id, session, jobQueue, logs); + checkpointers_[id] = r; + return r; + } +}; + +CheckpointersCollection checkpointers; + +std::shared_ptr +checkpointerFromId(std::uintptr_t id) +{ + return checkpointers.fromId(id); +} + +DatabaseCon::~DatabaseCon() +{ + if (checkpointer_) + { + checkpointers.erase(checkpointer_->id()); + + std::weak_ptr wk(checkpointer_); + checkpointer_.reset(); + + // The references to our Checkpointer held by 'checkpointer_' and + // 'checkpointers' have been removed, so if the use count is nonzero, a + // checkpoint is currently in progress. Wait for it to end, otherwise + // creating a new DatabaseCon to the same database may fail due to the + // database being locked by our (now old) Checkpointer. + while (wk.use_count()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } +} + +std::unique_ptr const> DatabaseCon::Setup::globalPragma; + +void +DatabaseCon::setupCheckpointing(JobQueue* q, Logs& l) +{ + if (!q) + Throw("No JobQueue"); + checkpointer_ = checkpointers.create(session_, *q, l); +} + +} // namespace xrpl diff --git a/src/xrpld/core/detail/SociDB.cpp b/src/libxrpl/rdb/SociDB.cpp similarity index 68% rename from src/xrpld/core/detail/SociDB.cpp rename to src/libxrpl/rdb/SociDB.cpp index 5b298dac43..2f8c5f1ac6 100644 --- a/src/xrpld/core/detail/SociDB.cpp +++ b/src/libxrpl/rdb/SociDB.cpp @@ -1,33 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated" #endif -#include -#include -#include - #include #include +#include +#include #include @@ -35,23 +14,18 @@ #include -namespace ripple { +namespace xrpl { static auto checkpointPageCount = 1000; namespace detail { std::string -getSociSqliteInit( - std::string const& name, - std::string const& dir, - std::string const& ext) +getSociSqliteInit(std::string const& name, std::string const& dir, std::string const& ext) { if (name.empty()) { - Throw( - "Sqlite databases must specify a dir and a name. Name: " + name + - " Dir: " + dir); + Throw("Sqlite databases must specify a dir and a name. Name: " + name + " Dir: " + dir); } boost::filesystem::path file(dir); if (is_directory(file)) @@ -69,8 +43,7 @@ getSociInit(BasicConfig const& config, std::string const& dbName) Throw("Unsupported soci backend: " + backendName); auto const path = config.legacy("database_path"); - auto const ext = - dbName == "validators" || dbName == "peerfinder" ? ".sqlite" : ".db"; + auto const ext = dbName == "validators" || dbName == "peerfinder" ? ".sqlite" : ".db"; return detail::getSociSqliteInit(dbName, path, ext); } @@ -80,8 +53,7 @@ DBConfig::DBConfig(std::string const& dbPath) : connectionString_(dbPath) { } -DBConfig::DBConfig(BasicConfig const& config, std::string const& dbName) - : DBConfig(detail::getSociInit(config, dbName)) +DBConfig::DBConfig(BasicConfig const& config, std::string const& dbName) : DBConfig(detail::getSociInit(config, dbName)) { } @@ -104,10 +76,7 @@ open(soci::session& s, BasicConfig const& config, std::string const& dbName) } void -open( - soci::session& s, - std::string const& beName, - std::string const& connectionString) +open(soci::session& s, std::string const& beName, std::string const& connectionString) { if (beName == "sqlite") s.open(soci::sqlite3, connectionString); @@ -134,8 +103,7 @@ getKBUsedAll(soci::session& s) { if (!getConnection(s)) Throw("No connection found."); - return static_cast( - sqlite_api::sqlite3_memory_used() / kilobytes(1)); + return static_cast(sqlite_api::sqlite3_memory_used() / kilobytes(1)); } std::uint32_t @@ -145,8 +113,7 @@ getKBUsedDB(soci::session& s) if (auto conn = getConnection(s)) { int cur = 0, hiw = 0; - sqlite_api::sqlite3_db_status( - conn, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0); + sqlite_api::sqlite3_db_status(conn, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0); return cur / kilobytes(1); } Throw(""); @@ -202,21 +169,13 @@ namespace { class WALCheckpointer : public Checkpointer { public: - WALCheckpointer( - std::uintptr_t id, - std::weak_ptr session, - JobQueue& q, - Logs& logs) - : id_(id) - , session_(std::move(session)) - , jobQueue_(q) - , j_(logs.journal("WALCheckpointer")) + WALCheckpointer(std::uintptr_t id, std::weak_ptr session, JobQueue& q, Logs& logs) + : id_(id), session_(std::move(session)), jobQueue_(q), j_(logs.journal("WALCheckpointer")) { if (auto [conn, keepAlive] = getConnection(); conn) { (void)keepAlive; - sqlite_api::sqlite3_wal_hook( - conn, &sqliteWALHook, reinterpret_cast(id_)); + sqlite_api::sqlite3_wal_hook(conn, &sqliteWALHook, reinterpret_cast(id_)); } } @@ -225,7 +184,7 @@ public: { if (auto p = session_.lock()) { - return {ripple::getConnection(*p), p}; + return {xrpl::getConnection(*p), p}; } return {nullptr, std::shared_ptr{}}; } @@ -276,8 +235,7 @@ public: return; int log = 0, ckpt = 0; - int ret = sqlite3_wal_checkpoint_v2( - conn, nullptr, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt); + int ret = sqlite3_wal_checkpoint_v2(conn, nullptr, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt); auto fname = sqlite3_db_filename(conn, "main"); if (ret != SQLITE_OK) @@ -287,8 +245,7 @@ public: } else { - JLOG(j_.trace()) << "WAL(" << fname << "): frames=" << log - << ", written=" << ckpt; + JLOG(j_.trace()) << "WAL(" << fname << "): frames=" << log << ", written=" << ckpt; } std::lock_guard lock(mutex_); @@ -298,7 +255,7 @@ public: protected: std::uintptr_t const id_; // session is owned by the DatabaseCon parent that holds the checkpointer. - // It is possible (tho rare) for the DatabaseCon class to be destoryed + // It is possible (though rare) for the DatabaseCon class to be destroyed // before the checkpointer. std::weak_ptr session_; std::mutex mutex_; @@ -308,16 +265,11 @@ protected: beast::Journal const j_; static int - sqliteWALHook( - void* cpId, - sqlite_api::sqlite3* conn, - char const* dbName, - int walSize) + sqliteWALHook(void* cpId, sqlite_api::sqlite3* conn, char const* dbName, int walSize) { if (walSize >= checkpointPageCount) { - if (auto checkpointer = - checkpointerFromId(reinterpret_cast(cpId))) + if (auto checkpointer = checkpointerFromId(reinterpret_cast(cpId))) { checkpointer->schedule(); } @@ -333,17 +285,12 @@ protected: } // namespace std::shared_ptr -makeCheckpointer( - std::uintptr_t id, - std::weak_ptr session, - JobQueue& queue, - Logs& logs) +makeCheckpointer(std::uintptr_t id, std::weak_ptr session, JobQueue& queue, Logs& logs) { - return std::make_shared( - id, std::move(session), queue, logs); + return std::make_shared(id, std::move(session), queue, logs); } -} // namespace ripple +} // namespace xrpl #if defined(__clang__) #pragma clang diagnostic pop diff --git a/src/libxrpl/resource/Charge.cpp b/src/libxrpl/resource/Charge.cpp index 8c96e3696f..eece5355f0 100644 --- a/src/libxrpl/resource/Charge.cpp +++ b/src/libxrpl/resource/Charge.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,11 +5,10 @@ #include #include -namespace ripple { +namespace xrpl { namespace Resource { -Charge::Charge(value_type cost, std::string const& label) - : m_cost(cost), m_label(label) +Charge::Charge(value_type cost, std::string const& label) : m_cost(cost), m_label(label) { } @@ -78,4 +58,4 @@ Charge::operator*(value_type m) const } } // namespace Resource -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/resource/Consumer.cpp b/src/libxrpl/resource/Consumer.cpp index 9ba3345f28..11c23b1044 100644 --- a/src/libxrpl/resource/Consumer.cpp +++ b/src/libxrpl/resource/Consumer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,11 +10,10 @@ #include #include -namespace ripple { +namespace xrpl { namespace Resource { -Consumer::Consumer(Logic& logic, Entry& entry) - : m_logic(&logic), m_entry(&entry) +Consumer::Consumer(Logic& logic, Entry& entry) : m_logic(&logic), m_entry(&entry) { } @@ -41,8 +21,7 @@ Consumer::Consumer() : m_logic(nullptr), m_entry(nullptr) { } -Consumer::Consumer(Consumer const& other) - : m_logic(other.m_logic), m_entry(nullptr) +Consumer::Consumer(Consumer const& other) : m_logic(other.m_logic), m_entry(nullptr) { if (m_logic && other.m_entry) { @@ -116,15 +95,14 @@ Consumer::charge(Charge const& what, std::string const& context) bool Consumer::warn() { - XRPL_ASSERT(m_entry, "ripple::Resource::Consumer::warn : non-null entry"); + XRPL_ASSERT(m_entry, "xrpl::Resource::Consumer::warn : non-null entry"); return m_logic->warn(*m_entry); } bool Consumer::disconnect(beast::Journal const& j) { - XRPL_ASSERT( - m_entry, "ripple::Resource::Consumer::disconnect : non-null entry"); + XRPL_ASSERT(m_entry, "xrpl::Resource::Consumer::disconnect : non-null entry"); bool const d = m_logic->disconnect(*m_entry); if (d) { @@ -136,15 +114,14 @@ Consumer::disconnect(beast::Journal const& j) int Consumer::balance() { - XRPL_ASSERT( - m_entry, "ripple::Resource::Consumer::balance : non-null entry"); + XRPL_ASSERT(m_entry, "xrpl::Resource::Consumer::balance : non-null entry"); return m_logic->balance(*m_entry); } Entry& Consumer::entry() { - XRPL_ASSERT(m_entry, "ripple::Resource::Consumer::entry : non-null entry"); + XRPL_ASSERT(m_entry, "xrpl::Resource::Consumer::entry : non-null entry"); return *m_entry; } @@ -162,4 +139,4 @@ operator<<(std::ostream& os, Consumer const& v) } } // namespace Resource -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/resource/Fees.cpp b/src/libxrpl/resource/Fees.cpp index 6d81cbbd25..d5999458b7 100644 --- a/src/libxrpl/resource/Fees.cpp +++ b/src/libxrpl/resource/Fees.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace Resource { Charge const feeMalformedRequest(200, "malformed request"); @@ -45,4 +26,4 @@ Charge const feeDrop(6000, "dropped"); // See also Resource::Logic::charge for log level cutoff values } // namespace Resource -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/resource/ResourceManager.cpp b/src/libxrpl/resource/ResourceManager.cpp index 08e0bcd408..787ceff768 100644 --- a/src/libxrpl/resource/ResourceManager.cpp +++ b/src/libxrpl/resource/ResourceManager.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -41,7 +22,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace Resource { class ManagerImp : public Manager @@ -55,9 +36,7 @@ private: std::condition_variable cond_; public: - ManagerImp( - beast::insight::Collector::ptr const& collector, - beast::Journal journal) + ManagerImp(beast::insight::Collector::ptr const& collector, beast::Journal journal) : journal_(journal), logic_(collector, stopwatch(), journal) { thread_ = std::thread{&ManagerImp::run, this}; @@ -85,10 +64,7 @@ public: } Consumer - newInboundEndpoint( - beast::IP::Endpoint const& address, - bool const proxy, - std::string_view forwardedFor) override + newInboundEndpoint(beast::IP::Endpoint const& address, bool const proxy, std::string_view forwardedFor) override { if (!proxy) return newInboundEndpoint(address); @@ -97,14 +73,11 @@ public: auto const proxiedIp = boost::asio::ip::make_address(forwardedFor, ec); if (ec) { - journal_.warn() - << "forwarded for (" << forwardedFor << ") from proxy " - << address.to_string() - << " doesn't convert to IP endpoint: " << ec.message(); + journal_.warn() << "forwarded for (" << forwardedFor << ") from proxy " << address.to_string() + << " doesn't convert to IP endpoint: " << ec.message(); return newInboundEndpoint(address); } - return newInboundEndpoint( - beast::IPAddressConversion::from_asio(proxiedIp)); + return newInboundEndpoint(beast::IPAddressConversion::from_asio(proxiedIp)); } Consumer @@ -159,7 +132,7 @@ private: void run() { - beast::setCurrentThreadName("Resource::Manager"); + beast::setCurrentThreadName("Resource::Mngr"); for (;;) { logic_.periodicActivity(); @@ -182,12 +155,10 @@ Manager::~Manager() = default; //------------------------------------------------------------------------------ std::unique_ptr -make_Manager( - beast::insight::Collector::ptr const& collector, - beast::Journal journal) +make_Manager(beast::insight::Collector::ptr const& collector, beast::Journal journal) { return std::make_unique(collector, journal); } } // namespace Resource -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/server/JSONRPCUtil.cpp b/src/libxrpl/server/JSONRPCUtil.cpp index 69adb235ee..634bb07850 100644 --- a/src/libxrpl/server/JSONRPCUtil.cpp +++ b/src/libxrpl/server/JSONRPCUtil.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { std::string getHTTPHeaderTimestamp() @@ -46,20 +27,12 @@ getHTTPHeaderTimestamp() #else gmtime_s(&now_gmt, &now); #endif - strftime( - buffer, - sizeof(buffer), - "Date: %a, %d %b %Y %H:%M:%S +0000\r\n", - &now_gmt); + strftime(buffer, sizeof(buffer), "Date: %a, %d %b %Y %H:%M:%S +0000\r\n", &now_gmt); return std::string(buffer); } void -HTTPReply( - int nStatus, - std::string const& content, - Json::Output const& output, - beast::Journal j) +HTTPReply(int nStatus, std::string const& content, Json::Output const& output, beast::Journal j) { JLOG(j.trace()) << "HTTP Reply " << nStatus << " " << content; @@ -158,4 +131,4 @@ HTTPReply( output("\r\n"); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/server/Port.cpp b/src/libxrpl/server/Port.cpp index be86a77a9f..389714a40f 100644 --- a/src/libxrpl/server/Port.cpp +++ b/src/libxrpl/server/Port.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -40,13 +21,13 @@ #include #include -namespace ripple { +namespace xrpl { bool Port::secure() const { - return protocol.count("peer") > 0 || protocol.count("https") > 0 || - protocol.count("wss") > 0 || protocol.count("wss2") > 0; + return protocol.count("peer") > 0 || protocol.count("https") > 0 || protocol.count("wss") > 0 || + protocol.count("wss2") > 0; } std::string @@ -130,8 +111,7 @@ populate( { if (is_unspecified(*addr)) { - nets4.push_back( - boost::asio::ip::make_network_v4("0.0.0.0/0")); + nets4.push_back(boost::asio::ip::make_network_v4("0.0.0.0/0")); nets6.push_back(boost::asio::ip::make_network_v6("::/0")); // No reason to allow more IPs--it would be redundant. break; @@ -183,8 +163,7 @@ populate( if (v4Net != v4Net.canonical()) { log << "The configured subnet " << v4Net.to_string() - << " is not the same as the network address, which is " - << v4Net.canonical().to_string(); + << " is not the same as the network address, which is " << v4Net.canonical().to_string(); Throw(); } nets4.push_back(v4Net); @@ -194,8 +173,7 @@ populate( if (v6Net != v6Net.canonical()) { log << "The configured subnet " << v6Net.to_string() - << " is not the same as the network address, which is " - << v6Net.canonical().to_string(); + << " is not the same as the network address, which is " << v6Net.canonical().to_string(); Throw(); } nets6.push_back(v6Net); @@ -203,8 +181,7 @@ populate( } catch (boost::system::system_error const& e) { - log << "Invalid value '" << ip << "' for key '" << field << "' in [" - << section.name() << "]: " << e.what(); + log << "Invalid value '" << ip << "' for key '" << field << "' in [" << section.name() << "]: " << e.what(); Throw(); } } @@ -224,8 +201,7 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) } catch (std::exception const&) { - log << "Invalid value '" << *optResult << "' for key 'ip' in [" - << section.name() << "]"; + log << "Invalid value '" << *optResult << "' for key 'ip' in [" << section.name() << "]"; Rethrow(); } } @@ -256,8 +232,7 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) auto const optResult = section.get("protocol"); if (optResult) { - for (auto const& s : beast::rfc2616::split_commas( - optResult->begin(), optResult->end())) + for (auto const& s : beast::rfc2616::split_commas(optResult->begin(), optResult->end())) port.protocol.insert(s); } } @@ -269,8 +244,7 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) { try { - port.limit = - safe_cast(beast::lexicalCastThrow(lim)); + port.limit = safe_cast(beast::lexicalCastThrow(lim)); } catch (std::exception const&) { @@ -287,8 +261,7 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) { try { - port.ws_queue_limit = - beast::lexicalCastThrow(*optResult); + port.ws_queue_limit = beast::lexicalCastThrow(*optResult); // Queue must be greater than 0 if (port.ws_queue_limit == 0) @@ -309,12 +282,7 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) } populate(section, "admin", log, port.admin_nets_v4, port.admin_nets_v6); - populate( - section, - "secure_gateway", - log, - port.secure_gateway_nets_v4, - port.secure_gateway_nets_v6); + populate(section, "secure_gateway", log, port.secure_gateway_nets_v4, port.secure_gateway_nets_v6); set(port.user, "user", section); set(port.password, "password", section); @@ -325,18 +293,13 @@ parse_Port(ParsedPort& port, Section const& section, std::ostream& log) set(port.ssl_chain, "ssl_chain", section); set(port.ssl_ciphers, "ssl_ciphers", section); - port.pmd_options.server_enable = - section.value_or("permessage_deflate", true); - port.pmd_options.client_max_window_bits = - section.value_or("client_max_window_bits", 15); - port.pmd_options.server_max_window_bits = - section.value_or("server_max_window_bits", 15); - port.pmd_options.client_no_context_takeover = - section.value_or("client_no_context_takeover", false); - port.pmd_options.server_no_context_takeover = - section.value_or("server_no_context_takeover", false); + port.pmd_options.server_enable = section.value_or("permessage_deflate", true); + port.pmd_options.client_max_window_bits = section.value_or("client_max_window_bits", 15); + port.pmd_options.server_max_window_bits = section.value_or("server_max_window_bits", 15); + port.pmd_options.client_no_context_takeover = section.value_or("client_no_context_takeover", false); + port.pmd_options.server_no_context_takeover = section.value_or("server_no_context_takeover", false); port.pmd_options.compLevel = section.value_or("compress_level", 8); port.pmd_options.memLevel = section.value_or("memory_level", 4); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/rdb/detail/State.cpp b/src/libxrpl/server/State.cpp similarity index 59% rename from src/xrpld/app/rdb/detail/State.cpp rename to src/libxrpl/server/State.cpp index c3de860689..4e3a1584c2 100644 --- a/src/xrpld/app/rdb/detail/State.cpp +++ b/src/libxrpl/server/State.cpp @@ -1,31 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. +#include - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -namespace ripple { +namespace xrpl { void -initStateDB( - soci::session& session, - BasicConfig const& config, - std::string const& dbName) +initStateDB(soci::session& session, BasicConfig const& config, std::string const& dbName) { open(session, config, dbName); @@ -47,11 +25,9 @@ initStateDB( { // SOCI requires boost::optional (not std::optional) as the parameter. boost::optional countO; - session << "SELECT COUNT(Key) FROM DbState WHERE Key = 1;", - soci::into(countO); + session << "SELECT COUNT(Key) FROM DbState WHERE Key = 1;", soci::into(countO); if (!countO) - Throw( - "Failed to fetch Key Count from DbState."); + Throw("Failed to fetch Key Count from DbState."); count = *countO; } @@ -63,11 +39,9 @@ initStateDB( { // SOCI requires boost::optional (not std::optional) as the parameter. boost::optional countO; - session << "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;", - soci::into(countO); + session << "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;", soci::into(countO); if (!countO) - Throw( - "Failed to fetch Key Count from CanDelete."); + Throw("Failed to fetch Key Count from CanDelete."); count = *countO; } @@ -81,8 +55,7 @@ LedgerIndex getCanDelete(soci::session& session) { LedgerIndex seq; - session << "SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;", - soci::into(seq); + session << "SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;", soci::into(seq); ; return seq; } @@ -90,8 +63,7 @@ getCanDelete(soci::session& session) LedgerIndex setCanDelete(soci::session& session, LedgerIndex canDelete) { - session << "UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;", - soci::use(canDelete); + session << "UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;", soci::use(canDelete); return canDelete; } @@ -101,8 +73,7 @@ getSavedState(soci::session& session) SavedState state; session << "SELECT WritableDb, ArchiveDb, LastRotatedLedger" " FROM DbState WHERE Key = 1;", - soci::into(state.writableDb), soci::into(state.archiveDb), - soci::into(state.lastRotated); + soci::into(state.writableDb), soci::into(state.archiveDb), soci::into(state.lastRotated); return state; } @@ -115,8 +86,7 @@ setSavedState(soci::session& session, SavedState const& state) " ArchiveDb = :archiveDb," " LastRotatedLedger = :lastRotated" " WHERE Key = 1;", - soci::use(state.writableDb), soci::use(state.archiveDb), - soci::use(state.lastRotated); + soci::use(state.writableDb), soci::use(state.archiveDb), soci::use(state.lastRotated); } void @@ -127,4 +97,4 @@ setLastRotated(soci::session& session, LedgerIndex seq) soci::use(seq); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/server/Vacuum.cpp b/src/libxrpl/server/Vacuum.cpp new file mode 100644 index 0000000000..cb31c6fa7a --- /dev/null +++ b/src/libxrpl/server/Vacuum.cpp @@ -0,0 +1,49 @@ +#include + +#include + +#include + +namespace xrpl { + +bool +doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) +{ + boost::filesystem::path dbPath = setup.dataDir / TxDBName; + + uintmax_t const dbSize = file_size(dbPath); + XRPL_ASSERT(dbSize != static_cast(-1), "ripple:doVacuumDB : file_size succeeded"); + + if (auto available = space(dbPath.parent_path()).available; available < dbSize) + { + std::cerr << "The database filesystem must have at least as " + "much free space as the size of " + << dbPath.string() << ", which is " << dbSize << " bytes. Only " << available + << " bytes are available.\n"; + return false; + } + + auto txnDB = std::make_unique(setup, TxDBName, setup.txPragma, TxDBInit, j); + auto& session = txnDB->getSession(); + std::uint32_t pageSize; + + // Only the most trivial databases will fit in memory on typical + // (recommended) hardware. Force temp files to be written to disk + // regardless of the config settings. + session << boost::format(CommonDBPragmaTemp) % "file"; + session << "PRAGMA page_size;", soci::into(pageSize); + + std::cout << "VACUUM beginning. page_size: " << pageSize << std::endl; + + session << "VACUUM;"; + XRPL_ASSERT(setup.globalPragma, "ripple:doVacuumDB : non-null global pragma"); + for (auto const& p : *setup.globalPragma) + session << p; + session << "PRAGMA page_size;", soci::into(pageSize); + + std::cout << "VACUUM finished. page_size: " << pageSize << std::endl; + + return true; +} + +} // namespace xrpl diff --git a/src/xrpld/app/rdb/detail/Wallet.cpp b/src/libxrpl/server/Wallet.cpp similarity index 70% rename from src/xrpld/app/rdb/detail/Wallet.cpp rename to src/libxrpl/server/Wallet.cpp index 0a329f2ccb..51f1326674 100644 --- a/src/xrpld/app/rdb/detail/Wallet.cpp +++ b/src/libxrpl/server/Wallet.cpp @@ -1,53 +1,26 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include +#include +#include #include -namespace ripple { +namespace xrpl { std::unique_ptr makeWalletDB(DatabaseCon::Setup const& setup, beast::Journal j) { // wallet database - return std::make_unique( - setup, WalletDBName, std::array(), WalletDBInit, j); + return std::make_unique(setup, WalletDBName, std::array(), WalletDBInit, j); } std::unique_ptr -makeTestWalletDB( - DatabaseCon::Setup const& setup, - std::string const& dbname, - beast::Journal j) +makeTestWalletDB(DatabaseCon::Setup const& setup, std::string const& dbname, beast::Journal j) { // wallet database - return std::make_unique( - setup, dbname.data(), std::array(), WalletDBInit, j); + return std::make_unique(setup, dbname.data(), std::array(), WalletDBInit, j); } void -getManifests( - soci::session& session, - std::string const& dbTable, - ManifestCache& mCache, - beast::Journal j) +getManifests(soci::session& session, std::string const& dbTable, ManifestCache& mCache, beast::Journal j) { // Load manifests stored in database std::string const sql = "SELECT RawData FROM " + dbTable + ";"; @@ -76,18 +49,14 @@ getManifests( } static void -saveManifest( - soci::session& session, - std::string const& dbTable, - std::string const& serialized) +saveManifest(soci::session& session, std::string const& dbTable, std::string const& serialized) { // soci does not support bulk insertion of blob data // Do not reuse blob because manifest ecdsa signatures vary in length // but blob write length is expected to be >= the last write soci::blob rawData(session); convert(serialized, rawData); - session << "INSERT INTO " << dbTable << " (RawData) VALUES (:rawData);", - soci::use(rawData); + session << "INSERT INTO " << dbTable << " (RawData) VALUES (:rawData);", soci::use(rawData); } void @@ -136,17 +105,14 @@ getNodeIdentity(soci::session& session) // SOCI requires boost::optional (not std::optional) as the parameter. boost::optional pubKO, priKO; soci::statement st = - (session.prepare - << "SELECT PublicKey, PrivateKey FROM NodeIdentity;", + (session.prepare << "SELECT PublicKey, PrivateKey FROM NodeIdentity;", soci::into(pubKO), soci::into(priKO)); st.execute(); while (st.fetch()) { - auto const sk = parseBase58( - TokenType::NodePrivate, priKO.value_or("")); - auto const pk = parseBase58( - TokenType::NodePublic, pubKO.value_or("")); + auto const sk = parseBase58(TokenType::NodePrivate, priKO.value_or("")); + auto const pk = parseBase58(TokenType::NodePublic, pubKO.value_or("")); // Only use if the public and secret keys are a pair if (sk && pk && (*pk == derivePublicKey(KeyType::secp256k1, *sk))) @@ -160,8 +126,7 @@ getNodeIdentity(soci::session& session) session << str( boost::format("INSERT INTO NodeIdentity (PublicKey,PrivateKey) " "VALUES ('%s','%s');") % - toBase58(TokenType::NodePublic, newpublicKey) % - toBase58(TokenType::NodePrivate, newsecretKey)); + toBase58(TokenType::NodePublic, newpublicKey) % toBase58(TokenType::NodePrivate, newsecretKey)); return {newpublicKey, newsecretKey}; } @@ -177,8 +142,7 @@ getPeerReservationTable(soci::session& session, beast::Journal j) // but no one else does. Because it is too tedious? It would be easy if we // had a jOOQ for C++. soci::statement st = - (session.prepare - << "SELECT PublicKey, Description FROM PeerReservations;", + (session.prepare << "SELECT PublicKey, Description FROM PeerReservations;", soci::into(valPubKey), soci::into(valDesc)); st.execute(); @@ -190,8 +154,7 @@ getPeerReservationTable(soci::session& session, beast::Journal j) // unreachable. continue; } - auto const optNodeId = - parseBase58(TokenType::NodePublic, *valPubKey); + auto const optNodeId = parseBase58(TokenType::NodePublic, *valPubKey); if (!optNodeId) { JLOG(j.warn()) << "load: not a public key: " << valPubKey; @@ -204,10 +167,7 @@ getPeerReservationTable(soci::session& session, beast::Journal j) } void -insertPeerReservation( - soci::session& session, - PublicKey const& nodeId, - std::string const& description) +insertPeerReservation(soci::session& session, PublicKey const& nodeId, std::string const& description) { auto const sNodeId = toBase58(TokenType::NodePublic, nodeId); session << "INSERT INTO PeerReservations (PublicKey, Description) " @@ -221,8 +181,7 @@ void deletePeerReservation(soci::session& session, PublicKey const& nodeId) { auto const sNodeId = toBase58(TokenType::NodePublic, nodeId); - session << "DELETE FROM PeerReservations WHERE PublicKey = :nodeId", - soci::use(sNodeId); + session << "DELETE FROM PeerReservations WHERE PublicKey = :nodeId", soci::use(sNodeId); } bool @@ -258,8 +217,7 @@ readAmendments( boost::optional vote)> const& callback) { // lambda that converts the internally stored int to an AmendmentVote. - auto intToVote = [](boost::optional const& dbVote) - -> boost::optional { + auto intToVote = [](boost::optional const& dbVote) -> boost::optional { return safe_cast(dbVote.value_or(1)); }; @@ -274,10 +232,7 @@ readAmendments( boost::optional amendment_name; boost::optional vote_to_veto; soci::statement st = - (session.prepare << sql, - soci::into(amendment_hash), - soci::into(amendment_name), - soci::into(vote_to_veto)); + (session.prepare << sql, soci::into(amendment_hash), soci::into(amendment_name), soci::into(vote_to_veto)); st.execute(); while (st.fetch()) { @@ -286,11 +241,7 @@ readAmendments( } void -voteAmendment( - soci::session& session, - uint256 const& amendment, - std::string const& name, - AmendmentVote vote) +voteAmendment(soci::session& session, uint256 const& amendment, std::string const& name, AmendmentVote vote) { soci::transaction tr(session); std::string sql = @@ -303,4 +254,4 @@ voteAmendment( tr.commit(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMap.cpp b/src/libxrpl/shamap/SHAMap.cpp index 4d2100ceab..e84a620b77 100644 --- a/src/libxrpl/shamap/SHAMap.cpp +++ b/src/libxrpl/shamap/SHAMap.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,33 +7,26 @@ #include #include -namespace ripple { +namespace xrpl { [[nodiscard]] intr_ptr::SharedPtr -makeTypedLeaf( - SHAMapNodeType type, - boost::intrusive_ptr item, - std::uint32_t owner) +makeTypedLeaf(SHAMapNodeType type, boost::intrusive_ptr item, std::uint32_t owner) { if (type == SHAMapNodeType::tnTRANSACTION_NM) return intr_ptr::make_shared(std::move(item), owner); if (type == SHAMapNodeType::tnTRANSACTION_MD) - return intr_ptr::make_shared( - std::move(item), owner); + return intr_ptr::make_shared(std::move(item), owner); if (type == SHAMapNodeType::tnACCOUNT_STATE) - return intr_ptr::make_shared( - std::move(item), owner); + return intr_ptr::make_shared(std::move(item), owner); LogicError( "Attempt to create leaf node of unknown type " + - std::to_string( - static_cast>(type))); + std::to_string(static_cast>(type))); } -SHAMap::SHAMap(SHAMapType t, Family& f) - : f_(f), journal_(f.journal()), state_(SHAMapState::Modifying), type_(t) +SHAMap::SHAMap(SHAMapType t, Family& f) : f_(f), journal_(f.journal()), state_(SHAMapState::Modifying), type_(t) { root_ = intr_ptr::make_shared(cowid_); } @@ -78,8 +52,7 @@ SHAMap::SHAMap(SHAMap const& other, bool isMutable) , backed_(other.backed_) { // If either map may change, they cannot share nodes - if ((state_ != SHAMapState::Immutable) || - (other.state_ != SHAMapState::Immutable)) + if ((state_ != SHAMapState::Immutable) || (other.state_ != SHAMapState::Immutable)) { unshare(); } @@ -92,10 +65,7 @@ SHAMap::snapShot(bool isMutable) const } void -SHAMap::dirtyUp( - SharedPtrNodeStack& stack, - uint256 const& target, - intr_ptr::SharedPtr child) +SHAMap::dirtyUp(SharedPtrNodeStack& stack, uint256 const& target, intr_ptr::SharedPtr child) { // walk the tree up from through the inner nodes to the root_ // update hashes and links @@ -103,22 +73,18 @@ SHAMap::dirtyUp( // child can be an inner node or a leaf XRPL_ASSERT( - (state_ != SHAMapState::Synching) && (state_ != SHAMapState::Immutable), - "ripple::SHAMap::dirtyUp : valid state"); - XRPL_ASSERT( - child && (child->cowid() == cowid_), - "ripple::SHAMap::dirtyUp : valid child input"); + (state_ != SHAMapState::Synching) && (state_ != SHAMapState::Immutable), "xrpl::SHAMap::dirtyUp : valid state"); + XRPL_ASSERT(child && (child->cowid() == cowid_), "xrpl::SHAMap::dirtyUp : valid child input"); while (!stack.empty()) { - auto node = - intr_ptr::dynamic_pointer_cast(stack.top().first); + auto node = intr_ptr::dynamic_pointer_cast(stack.top().first); SHAMapNodeID nodeID = stack.top().second; stack.pop(); - XRPL_ASSERT(node, "ripple::SHAMap::dirtyUp : non-null node"); + XRPL_ASSERT(node, "xrpl::SHAMap::dirtyUp : non-null node"); int branch = selectBranch(nodeID, target); - XRPL_ASSERT(branch >= 0, "ripple::SHAMap::dirtyUp : valid branch"); + XRPL_ASSERT(branch >= 0, "xrpl::SHAMap::dirtyUp : valid branch"); node = unshareNode(std::move(node), nodeID); node->setChild(branch, std::move(child)); @@ -130,9 +96,7 @@ SHAMap::dirtyUp( SHAMapLeafNode* SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const { - XRPL_ASSERT( - stack == nullptr || stack->empty(), - "ripple::SHAMap::walkTowardsKey : empty stack input"); + XRPL_ASSERT(stack == nullptr || stack->empty(), "xrpl::SHAMap::walkTowardsKey : empty stack input"); auto inNode = root_; SHAMapNodeID nodeID; @@ -141,8 +105,7 @@ SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const if (stack != nullptr) stack->push({inNode, nodeID}); - auto const inner = - intr_ptr::static_pointer_cast(inNode); + auto const inner = intr_ptr::static_pointer_cast(inNode); auto const branch = selectBranch(nodeID, id); if (inner->isEmptyBranch(branch)) return nullptr; @@ -168,17 +131,15 @@ SHAMap::findKey(uint256 const& id) const intr_ptr::SharedPtr SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const { - XRPL_ASSERT(backed_, "ripple::SHAMap::fetchNodeFromDB : is backed"); + XRPL_ASSERT(backed_, "xrpl::SHAMap::fetchNodeFromDB : is backed"); auto obj = f_.db().fetchNodeObject(hash.as_uint256(), ledgerSeq_); return finishFetch(hash, obj); } intr_ptr::SharedPtr -SHAMap::finishFetch( - SHAMapHash const& hash, - std::shared_ptr const& object) const +SHAMap::finishFetch(SHAMapHash const& hash, std::shared_ptr const& object) const { - XRPL_ASSERT(backed_, "ripple::SHAMap::finishFetch : is backed"); + XRPL_ASSERT(backed_, "xrpl::SHAMap::finishFetch : is backed"); try { @@ -192,8 +153,7 @@ SHAMap::finishFetch( return {}; } - auto node = - SHAMapTreeNode::makeFromPrefix(makeSlice(object->getData()), hash); + auto node = SHAMapTreeNode::makeFromPrefix(makeSlice(object->getData()), hash); if (node) canonicalize(hash, node); return node; @@ -204,8 +164,7 @@ SHAMap::finishFetch( } catch (...) { - JLOG(journal_.warn()) - << "finishFetch exception: unknonw exception: " << hash; + JLOG(journal_.warn()) << "finishFetch exception: unknown exception: " << hash; } return {}; @@ -219,16 +178,10 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const { try { - auto node = - SHAMapTreeNode::makeFromPrefix(makeSlice(*nodeData), hash); + auto node = SHAMapTreeNode::makeFromPrefix(makeSlice(*nodeData), hash); if (node) { - filter->gotNode( - true, - hash, - ledgerSeq_, - std::move(*nodeData), - node->getType()); + filter->gotNode(true, hash, ledgerSeq_, std::move(*nodeData), node->getType()); if (backed_) canonicalize(hash, node); } @@ -236,8 +189,7 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const } catch (std::exception const& x) { - JLOG(f_.journal().warn()) - << "Invalid node/data, hash=" << hash << ": " << x.what(); + JLOG(f_.journal().warn()) << "Invalid node/data, hash=" << hash << ": " << x.what(); } } return {}; @@ -320,8 +272,7 @@ SHAMap::descend(SHAMapInnerNode* parent, int branch) const if (ret || !backed_) return ret; - intr_ptr::SharedPtr node = - fetchNodeNT(parent->getChildHash(branch)); + intr_ptr::SharedPtr node = fetchNodeNT(parent->getChildHash(branch)); if (!node) return nullptr; @@ -356,28 +307,18 @@ SHAMap::descendNoStore(SHAMapInnerNode& parent, int branch) const } std::pair -SHAMap::descend( - SHAMapInnerNode* parent, - SHAMapNodeID const& parentID, - int branch, - SHAMapSyncFilter* filter) const +SHAMap::descend(SHAMapInnerNode* parent, SHAMapNodeID const& parentID, int branch, SHAMapSyncFilter* filter) const { - XRPL_ASSERT( - parent->isInner(), "ripple::SHAMap::descend : valid parent input"); - XRPL_ASSERT( - (branch >= 0) && (branch < branchFactor), - "ripple::SHAMap::descend : valid branch input"); - XRPL_ASSERT( - !parent->isEmptyBranch(branch), - "ripple::SHAMap::descend : parent branch is non-empty"); + XRPL_ASSERT(parent->isInner(), "xrpl::SHAMap::descend : valid parent input"); + XRPL_ASSERT((branch >= 0) && (branch < branchFactor), "xrpl::SHAMap::descend : valid branch input"); + XRPL_ASSERT(!parent->isEmptyBranch(branch), "xrpl::SHAMap::descend : parent branch is non-empty"); SHAMapTreeNode* child = parent->getChildPointer(branch); if (!child) { auto const& childHash = parent->getChildHash(branch); - intr_ptr::SharedPtr childNode = - fetchNodeNT(childHash, filter); + intr_ptr::SharedPtr childNode = fetchNodeNT(childHash, filter); if (childNode) { @@ -416,8 +357,7 @@ SHAMap::descendAsync( f_.db().asyncFetch( hash.as_uint256(), ledgerSeq_, - [this, hash, cb{std::move(callback)}]( - std::shared_ptr const& object) { + [this, hash, cb{std::move(callback)}](std::shared_ptr const& object) { auto node = finishFetch(hash, object); cb(node, hash); }); @@ -437,15 +377,11 @@ intr_ptr::SharedPtr SHAMap::unshareNode(intr_ptr::SharedPtr node, SHAMapNodeID const& nodeID) { // make sure the node is suitable for the intended operation (copy on write) - XRPL_ASSERT( - node->cowid() <= cowid_, - "ripple::SHAMap::unshareNode : node valid for cowid"); + XRPL_ASSERT(node->cowid() <= cowid_, "xrpl::SHAMap::unshareNode : node valid for cowid"); if (node->cowid() != cowid_) { // have a CoW - XRPL_ASSERT( - state_ != SHAMapState::Immutable, - "ripple::SHAMap::unshareNode : not immutable"); + XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::unshareNode : not immutable"); node = intr_ptr::static_pointer_cast(node->clone(cowid_)); if (nodeID.isRoot()) root_ = node; @@ -458,8 +394,7 @@ SHAMap::belowHelper( intr_ptr::SharedPtr node, SharedPtrNodeStack& stack, int branch, - std::tuple, std::function> const& - loopParams) const + std::tuple, std::function> const& loopParams) const { auto& [init, cmp, incr] = loopParams; if (node->isLeaf()) @@ -478,9 +413,7 @@ SHAMap::belowHelper( if (!inner->isEmptyBranch(i)) { node.adopt(descendThrow(inner.get(), i)); - XRPL_ASSERT( - !stack.empty(), - "ripple::SHAMap::belowHelper : non-empty stack"); + XRPL_ASSERT(!stack.empty(), "xrpl::SHAMap::belowHelper : non-empty stack"); if (node->isLeaf()) { auto n = intr_ptr::static_pointer_cast(node); @@ -497,10 +430,7 @@ SHAMap::belowHelper( return nullptr; } SHAMapLeafNode* -SHAMap::lastBelow( - intr_ptr::SharedPtr node, - SharedPtrNodeStack& stack, - int branch) const +SHAMap::lastBelow(intr_ptr::SharedPtr node, SharedPtrNodeStack& stack, int branch) const { auto init = branchFactor - 1; auto cmp = [](int i) { return i >= 0; }; @@ -509,10 +439,7 @@ SHAMap::lastBelow( return belowHelper(node, stack, branch, {init, cmp, incr}); } SHAMapLeafNode* -SHAMap::firstBelow( - intr_ptr::SharedPtr node, - SharedPtrNodeStack& stack, - int branch) const +SHAMap::firstBelow(intr_ptr::SharedPtr node, SharedPtrNodeStack& stack, int branch) const { auto init = 0; auto cmp = [](int i) { return i <= branchFactor; }; @@ -545,7 +472,7 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const if (!nextNode) { // LCOV_EXCL_START - UNREACHABLE("ripple::SHAMap::onlyBelow : no next node"); + UNREACHABLE("xrpl::SHAMap::onlyBelow : no next node"); return no_item; // LCOV_EXCL_STOP } @@ -556,17 +483,14 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const // An inner node must have at least one leaf // below it, unless it's the root_ auto const leaf = static_cast(node); - XRPL_ASSERT( - leaf->peekItem() || (leaf == root_.get()), - "ripple::SHAMap::onlyBelow : valid inner node"); + XRPL_ASSERT(leaf->peekItem() || (leaf == root_.get()), "xrpl::SHAMap::onlyBelow : valid inner node"); return leaf->peekItem(); } SHAMapLeafNode const* SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const { - XRPL_ASSERT( - stack.empty(), "ripple::SHAMap::peekFirstItem : empty stack input"); + XRPL_ASSERT(stack.empty(), "xrpl::SHAMap::peekFirstItem : empty stack input"); SHAMapLeafNode* node = firstBelow(root_, stack); if (!node) { @@ -580,18 +504,13 @@ SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const SHAMapLeafNode const* SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const { - XRPL_ASSERT( - !stack.empty(), "ripple::SHAMap::peekNextItem : non-empty stack input"); - XRPL_ASSERT( - stack.top().first->isLeaf(), - "ripple::SHAMap::peekNextItem : stack starts with leaf"); + XRPL_ASSERT(!stack.empty(), "xrpl::SHAMap::peekNextItem : non-empty stack input"); + XRPL_ASSERT(stack.top().first->isLeaf(), "xrpl::SHAMap::peekNextItem : stack starts with leaf"); stack.pop(); while (!stack.empty()) { auto [node, nodeID] = stack.top(); - XRPL_ASSERT( - !node->isLeaf(), - "ripple::SHAMap::peekNextItem : another node is not leaf"); + XRPL_ASSERT(!node->isLeaf(), "xrpl::SHAMap::peekNextItem : another node is not leaf"); auto inner = intr_ptr::static_pointer_cast(node); for (auto i = selectBranch(nodeID, id) + 1; i < branchFactor; ++i) { @@ -601,9 +520,7 @@ SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const auto leaf = firstBelow(node, stack, i); if (!leaf) Throw(type_, id); - XRPL_ASSERT( - leaf->isLeaf(), - "ripple::SHAMap::peekNextItem : leaf is valid"); + XRPL_ASSERT(leaf->isLeaf(), "xrpl::SHAMap::peekNextItem : leaf is valid"); return leaf; } } @@ -648,15 +565,12 @@ SHAMap::upper_bound(uint256 const& id) const { auto leaf = static_cast(node.get()); if (leaf->peekItem()->key() > id) - return const_iterator( - this, leaf->peekItem().get(), std::move(stack)); + return const_iterator(this, leaf->peekItem().get(), std::move(stack)); } else { auto inner = intr_ptr::static_pointer_cast(node); - for (auto branch = selectBranch(nodeID, id) + 1; - branch < branchFactor; - ++branch) + for (auto branch = selectBranch(nodeID, id) + 1; branch < branchFactor; ++branch) { if (!inner->isEmptyBranch(branch)) { @@ -664,8 +578,7 @@ SHAMap::upper_bound(uint256 const& id) const auto leaf = firstBelow(node, stack, branch); if (!leaf) Throw(type_, id); - return const_iterator( - this, leaf->peekItem().get(), std::move(stack)); + return const_iterator(this, leaf->peekItem().get(), std::move(stack)); } } } @@ -685,14 +598,12 @@ SHAMap::lower_bound(uint256 const& id) const { auto leaf = static_cast(node.get()); if (leaf->peekItem()->key() < id) - return const_iterator( - this, leaf->peekItem().get(), std::move(stack)); + return const_iterator(this, leaf->peekItem().get(), std::move(stack)); } else { auto inner = intr_ptr::static_pointer_cast(node); - for (int branch = selectBranch(nodeID, id) - 1; branch >= 0; - --branch) + for (int branch = selectBranch(nodeID, id) - 1; branch >= 0; --branch) { if (!inner->isEmptyBranch(branch)) { @@ -700,8 +611,7 @@ SHAMap::lower_bound(uint256 const& id) const auto leaf = lastBelow(node, stack, branch); if (!leaf) Throw(type_, id); - return const_iterator( - this, leaf->peekItem().get(), std::move(stack)); + return const_iterator(this, leaf->peekItem().get(), std::move(stack)); } } } @@ -721,9 +631,7 @@ bool SHAMap::delItem(uint256 const& id) { // delete the item with this ID - XRPL_ASSERT( - state_ != SHAMapState::Immutable, - "ripple::SHAMap::delItem : not immutable"); + XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::delItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(id, &stack); @@ -731,8 +639,7 @@ SHAMap::delItem(uint256 const& id) if (stack.empty()) Throw(type_, id); - auto leaf = - intr_ptr::dynamic_pointer_cast(stack.top().first); + auto leaf = intr_ptr::dynamic_pointer_cast(stack.top().first); stack.pop(); if (!leaf || (leaf->peekItem()->key() != id)) @@ -746,8 +653,7 @@ SHAMap::delItem(uint256 const& id) while (!stack.empty()) { - auto node = - intr_ptr::static_pointer_cast(stack.top().first); + auto node = intr_ptr::static_pointer_cast(stack.top().first); SHAMapNodeID nodeID = stack.top().second; stack.pop(); @@ -775,8 +681,7 @@ SHAMap::delItem(uint256 const& id) { if (!node->isEmptyBranch(i)) { - node->setChild( - i, intr_ptr::SharedPtr{}); + node->setChild(i, intr_ptr::SharedPtr{}); break; } } @@ -800,16 +705,10 @@ SHAMap::delItem(uint256 const& id) } bool -SHAMap::addGiveItem( - SHAMapNodeType type, - boost::intrusive_ptr item) +SHAMap::addGiveItem(SHAMapNodeType type, boost::intrusive_ptr item) { - XRPL_ASSERT( - state_ != SHAMapState::Immutable, - "ripple::SHAMap::addGiveItem : not immutable"); - XRPL_ASSERT( - type != SHAMapNodeType::tnINNER, - "ripple::SHAMap::addGiveItem : valid type input"); + XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::addGiveItem : not immutable"); + XRPL_ASSERT(type != SHAMapNodeType::tnINNER, "xrpl::SHAMap::addGiveItem : valid type input"); // add the specified item, does not update uint256 tag = item->key(); @@ -835,9 +734,7 @@ SHAMap::addGiveItem( // easy case, we end on an inner node auto inner = intr_ptr::static_pointer_cast(node); int branch = selectBranch(nodeID, tag); - XRPL_ASSERT( - inner->isEmptyBranch(branch), - "ripple::SHAMap::addGiveItem : inner branch is empty"); + XRPL_ASSERT(inner->isEmptyBranch(branch), "xrpl::SHAMap::addGiveItem : inner branch is empty"); inner->setChild(branch, makeTypedLeaf(type, std::move(item), cowid_)); } else @@ -846,16 +743,13 @@ SHAMap::addGiveItem( // items auto leaf = intr_ptr::static_pointer_cast(node); auto otherItem = leaf->peekItem(); - XRPL_ASSERT( - otherItem && (tag != otherItem->key()), - "ripple::SHAMap::addGiveItem : non-null item"); + XRPL_ASSERT(otherItem && (tag != otherItem->key()), "xrpl::SHAMap::addGiveItem : non-null item"); node = intr_ptr::make_shared(node->cowid()); unsigned int b1, b2; - while ((b1 = selectBranch(nodeID, tag)) == - (b2 = selectBranch(nodeID, otherItem->key()))) + while ((b1 = selectBranch(nodeID, tag)) == (b2 = selectBranch(nodeID, otherItem->key()))) { stack.push({node, nodeID}); @@ -866,8 +760,7 @@ SHAMap::addGiveItem( } // we can add the two leaf nodes here - XRPL_ASSERT( - node->isInner(), "ripple::SHAMap::addGiveItem : node is inner"); + XRPL_ASSERT(node->isInner(), "xrpl::SHAMap::addGiveItem : node is inner"); auto inner = static_cast(node.get()); inner->setChild(b1, makeTypedLeaf(type, std::move(item), cowid_)); @@ -879,9 +772,7 @@ SHAMap::addGiveItem( } bool -SHAMap::addItem( - SHAMapNodeType type, - boost::intrusive_ptr item) +SHAMap::addItem(SHAMapNodeType type, boost::intrusive_ptr item) { return addGiveItem(type, std::move(item)); } @@ -899,16 +790,12 @@ SHAMap::getHash() const } bool -SHAMap::updateGiveItem( - SHAMapNodeType type, - boost::intrusive_ptr item) +SHAMap::updateGiveItem(SHAMapNodeType type, boost::intrusive_ptr item) { // can't change the tag but can change the hash uint256 tag = item->key(); - XRPL_ASSERT( - state_ != SHAMapState::Immutable, - "ripple::SHAMap::updateGiveItem : not immutable"); + XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::updateGiveItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(tag, &stack); @@ -916,15 +803,14 @@ SHAMap::updateGiveItem( if (stack.empty()) Throw(type_, tag); - auto node = - intr_ptr::dynamic_pointer_cast(stack.top().first); + auto node = intr_ptr::dynamic_pointer_cast(stack.top().first); auto nodeID = stack.top().second; stack.pop(); if (!node || (node->peekItem()->key() != tag)) { // LCOV_EXCL_START - UNREACHABLE("ripple::SHAMap::updateGiveItem : invalid node"); + UNREACHABLE("xrpl::SHAMap::updateGiveItem : invalid node"); return false; // LCOV_EXCL_STOP } @@ -970,9 +856,7 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) if (newRoot) { root_ = newRoot; - XRPL_ASSERT( - root_->getHash() == hash, - "ripple::SHAMap::fetchRoot : root hash do match"); + XRPL_ASSERT(root_->getHash() == hash, "xrpl::SHAMap::fetchRoot : root hash do match"); return true; } @@ -992,19 +876,16 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) first call SHAMapTreeNode::unshare(). */ intr_ptr::SharedPtr -SHAMap::writeNode(NodeObjectType t, intr_ptr::SharedPtr node) - const +SHAMap::writeNode(NodeObjectType t, intr_ptr::SharedPtr node) const { - XRPL_ASSERT( - node->cowid() == 0, "ripple::SHAMap::writeNode : valid input node"); - XRPL_ASSERT(backed_, "ripple::SHAMap::writeNode : is backed"); + XRPL_ASSERT(node->cowid() == 0, "xrpl::SHAMap::writeNode : valid input node"); + XRPL_ASSERT(backed_, "xrpl::SHAMap::writeNode : is backed"); canonicalize(node->getHash(), node); Serializer s; node->serializeWithPrefix(s); - f_.db().store( - t, std::move(s.modData()), node->getHash().as_uint256(), ledgerSeq_); + f_.db().store(t, std::move(s.modData()), node->getHash().as_uint256(), ledgerSeq_); return node; } @@ -1017,8 +898,7 @@ SHAMap::preFlushNode(intr_ptr::SharedPtr node) const { // A shared node should never need to be flushed // because that would imply someone modified it - XRPL_ASSERT( - node->cowid(), "ripple::SHAMap::preFlushNode : valid input node"); + XRPL_ASSERT(node->cowid(), "xrpl::SHAMap::preFlushNode : valid input node"); if (node->cowid() != cowid_) { @@ -1046,8 +926,7 @@ SHAMap::flushDirty(NodeObjectType t) int SHAMap::walkSubTree(bool doWrite, NodeObjectType t) { - XRPL_ASSERT( - !doWrite || backed_, "ripple::SHAMap::walkSubTree : valid input"); + XRPL_ASSERT(!doWrite || backed_, "xrpl::SHAMap::walkSubTree : valid input"); int flushed = 0; @@ -1113,8 +992,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) // The semantics of this changes when we move to c++-20 // Right now no move will occur; With c++-20 child will // be moved from. - node = intr_ptr::static_pointer_cast( - std::move(child)); + node = intr_ptr::static_pointer_cast(std::move(child)); pos = 0; } else @@ -1124,7 +1002,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) XRPL_ASSERT( node->cowid() == cowid_, - "ripple::SHAMap::walkSubTree : node cowid do " + "xrpl::SHAMap::walkSubTree : node cowid do " "match"); child->updateHash(); child->unshare(); @@ -1145,8 +1023,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) node->unshare(); if (doWrite) - node = intr_ptr::static_pointer_cast( - writeNode(t, std::move(node))); + node = intr_ptr::static_pointer_cast(writeNode(t, std::move(node))); ++flushed; @@ -1158,9 +1035,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) stack.pop(); // Hook this inner node to its parent - XRPL_ASSERT( - parent->cowid() == cowid_, - "ripple::SHAMap::walkSubTree : parent cowid do match"); + XRPL_ASSERT(parent->cowid() == cowid_, "xrpl::SHAMap::walkSubTree : parent cowid do match"); parent->shareChild(pos, node); // Continue with parent's next child, if any @@ -1205,8 +1080,7 @@ SHAMap::dump(bool hash) const if (child) { XRPL_ASSERT( - child->getHash() == inner->getChildHash(i), - "ripple::SHAMap::dump : child hash do match"); + child->getHash() == inner->getChildHash(i), "xrpl::SHAMap::dump : child hash do match"); stack.push({child, nodeID.getChildNodeID(i)}); } } @@ -1223,23 +1097,16 @@ intr_ptr::SharedPtr SHAMap::cacheLookup(SHAMapHash const& hash) const { auto ret = f_.getTreeNodeCache()->fetch(hash.as_uint256()); - XRPL_ASSERT( - !ret || !ret->cowid(), - "ripple::SHAMap::cacheLookup : not found or zero cowid"); + XRPL_ASSERT(!ret || !ret->cowid(), "xrpl::SHAMap::cacheLookup : not found or zero cowid"); return ret; } void -SHAMap::canonicalize( - SHAMapHash const& hash, - intr_ptr::SharedPtr& node) const +SHAMap::canonicalize(SHAMapHash const& hash, intr_ptr::SharedPtr& node) const { - XRPL_ASSERT(backed_, "ripple::SHAMap::canonicalize : is backed"); - XRPL_ASSERT( - node->cowid() == 0, "ripple::SHAMap::canonicalize : valid node input"); - XRPL_ASSERT( - node->getHash() == hash, - "ripple::SHAMap::canonicalize : node hash do match"); + XRPL_ASSERT(backed_, "xrpl::SHAMap::canonicalize : is backed"); + XRPL_ASSERT(node->cowid() == 0, "xrpl::SHAMap::canonicalize : valid node input"); + XRPL_ASSERT(node->getHash() == hash, "xrpl::SHAMap::canonicalize : node hash do match"); f_.getTreeNodeCache()->canonicalize_replace_client(hash.as_uint256(), node); } @@ -1249,14 +1116,12 @@ SHAMap::invariants() const { (void)getHash(); // update node hashes auto node = root_.get(); - XRPL_ASSERT(node, "ripple::SHAMap::invariants : non-null root node"); - XRPL_ASSERT( - !node->isLeaf(), "ripple::SHAMap::invariants : root node is not leaf"); + XRPL_ASSERT(node, "xrpl::SHAMap::invariants : non-null root node"); + XRPL_ASSERT(!node->isLeaf(), "xrpl::SHAMap::invariants : root node is not leaf"); SharedPtrNodeStack stack; - for (auto leaf = peekFirstItem(stack); leaf != nullptr; - leaf = peekNextItem(leaf->peekItem()->key(), stack)) + for (auto leaf = peekFirstItem(stack); leaf != nullptr; leaf = peekNextItem(leaf->peekItem()->key(), stack)) ; node->invariants(true); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapDelta.cpp b/src/libxrpl/shamap/SHAMapDelta.cpp index 2fc3152fc3..d8aabcc67c 100644 --- a/src/libxrpl/shamap/SHAMapDelta.cpp +++ b/src/libxrpl/shamap/SHAMapDelta.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { // This code is used to compare another node's transaction tree // to our own. It returns a map containing all items that are different @@ -72,11 +53,9 @@ SHAMap::walkBranch( { // unmatched if (isFirstMap) - differences.insert( - std::make_pair(item->key(), DeltaRef(item, nullptr))); + differences.insert(std::make_pair(item->key(), DeltaRef(item, nullptr))); else - differences.insert( - std::make_pair(item->key(), DeltaRef(nullptr, item))); + differences.insert(std::make_pair(item->key(), DeltaRef(nullptr, item))); if (--maxCount <= 0) return false; @@ -85,11 +64,9 @@ SHAMap::walkBranch( { // non-matching items with same tag if (isFirstMap) - differences.insert(std::make_pair( - item->key(), DeltaRef(item, otherMapItem))); + differences.insert(std::make_pair(item->key(), DeltaRef(item, otherMapItem))); else - differences.insert(std::make_pair( - item->key(), DeltaRef(otherMapItem, item))); + differences.insert(std::make_pair(item->key(), DeltaRef(otherMapItem, item))); if (--maxCount <= 0) return false; @@ -108,11 +85,9 @@ SHAMap::walkBranch( { // otherMapItem was unmatched, must add if (isFirstMap) // this is first map, so other item is from second - differences.insert(std::make_pair( - otherMapItem->key(), DeltaRef(nullptr, otherMapItem))); + differences.insert(std::make_pair(otherMapItem->key(), DeltaRef(nullptr, otherMapItem))); else - differences.insert(std::make_pair( - otherMapItem->key(), DeltaRef(otherMapItem, nullptr))); + differences.insert(std::make_pair(otherMapItem->key(), DeltaRef(otherMapItem, nullptr))); if (--maxCount <= 0) return false; @@ -129,16 +104,13 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const // many differences throws on corrupt tables or missing nodes CAUTION: // otherMap is not locked and must be immutable - XRPL_ASSERT( - isValid() && otherMap.isValid(), - "ripple::SHAMap::compare : valid state and valid input"); + XRPL_ASSERT(isValid() && otherMap.isValid(), "xrpl::SHAMap::compare : valid state and valid input"); if (getHash() == otherMap.getHash()) return true; using StackEntry = std::pair; - std::stack> - nodeStack; // track nodes we've pushed + std::stack> nodeStack; // track nodes we've pushed nodeStack.push({root_.get(), otherMap.root_.get()}); while (!nodeStack.empty()) @@ -149,7 +121,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const if (!ourNode || !otherNode) { // LCOV_EXCL_START - UNREACHABLE("ripple::SHAMap::compare : missing a node"); + UNREACHABLE("xrpl::SHAMap::compare : missing a node"); Throw(type_, uint256()); // LCOV_EXCL_STOP } @@ -163,24 +135,19 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const { if (ours->peekItem()->slice() != other->peekItem()->slice()) { - differences.insert(std::make_pair( - ours->peekItem()->key(), - DeltaRef(ours->peekItem(), other->peekItem()))); + differences.insert( + std::make_pair(ours->peekItem()->key(), DeltaRef(ours->peekItem(), other->peekItem()))); if (--maxCount <= 0) return false; } } else { - differences.insert(std::make_pair( - ours->peekItem()->key(), - DeltaRef(ours->peekItem(), nullptr))); + differences.insert(std::make_pair(ours->peekItem()->key(), DeltaRef(ours->peekItem(), nullptr))); if (--maxCount <= 0) return false; - differences.insert(std::make_pair( - other->peekItem()->key(), - DeltaRef(nullptr, other->peekItem()))); + differences.insert(std::make_pair(other->peekItem()->key(), DeltaRef(nullptr, other->peekItem()))); if (--maxCount <= 0) return false; } @@ -189,16 +156,14 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const { auto ours = static_cast(ourNode); auto other = static_cast(otherNode); - if (!walkBranch( - ours, other->peekItem(), true, differences, maxCount)) + if (!walkBranch(ours, other->peekItem(), true, differences, maxCount)) return false; } else if (ourNode->isLeaf() && otherNode->isInner()) { auto ours = static_cast(ourNode); auto other = static_cast(otherNode); - if (!otherMap.walkBranch( - other, ours->peekItem(), false, differences, maxCount)) + if (!otherMap.walkBranch(other, ours->peekItem(), false, differences, maxCount)) return false; } else if (ourNode->isInner() && otherNode->isInner()) @@ -212,28 +177,24 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const { // We have a branch, the other tree does not SHAMapTreeNode* iNode = descendThrow(ours, i); - if (!walkBranch( - iNode, nullptr, true, differences, maxCount)) + if (!walkBranch(iNode, nullptr, true, differences, maxCount)) return false; } else if (ours->isEmptyBranch(i)) { // The other tree has a branch, we do not SHAMapTreeNode* iNode = otherMap.descendThrow(other, i); - if (!otherMap.walkBranch( - iNode, nullptr, false, differences, maxCount)) + if (!otherMap.walkBranch(iNode, nullptr, false, differences, maxCount)) return false; } else // The two trees have different non-empty branches - nodeStack.push( - {descendThrow(ours, i), - otherMap.descendThrow(other, i)}); + nodeStack.push({descendThrow(ours, i), otherMap.descendThrow(other, i)}); } } else { // LCOV_EXCL_START - UNREACHABLE("ripple::SHAMap::compare : invalid node"); + UNREACHABLE("xrpl::SHAMap::compare : invalid node"); // LCOV_EXCL_STOP } } @@ -242,8 +203,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const } void -SHAMap::walkMap(std::vector& missingNodes, int maxMissing) - const +SHAMap::walkMap(std::vector& missingNodes, int maxMissing) const { if (!root_->isInner()) // root_ is only node, and we have it return; @@ -262,15 +222,12 @@ SHAMap::walkMap(std::vector& missingNodes, int maxMissing) { if (!node->isEmptyBranch(i)) { - intr_ptr::SharedPtr nextNode = - descendNoStore(*node, i); + intr_ptr::SharedPtr nextNode = descendNoStore(*node, i); if (nextNode) { if (nextNode->isInner()) - nodeStack.push( - intr_ptr::static_pointer_cast( - nextNode)); + nodeStack.push(intr_ptr::static_pointer_cast(nextNode)); } else { @@ -284,9 +241,7 @@ SHAMap::walkMap(std::vector& missingNodes, int maxMissing) } bool -SHAMap::walkMapParallel( - std::vector& missingNodes, - int maxMissing) const +SHAMap::walkMapParallel(std::vector& missingNodes, int maxMissing) const { if (!root_->isInner()) // root_ is only node, and we have it return false; @@ -294,8 +249,7 @@ SHAMap::walkMapParallel( using StackEntry = intr_ptr::SharedPtr; std::array, 16> topChildren; { - auto const& innerRoot = - intr_ptr::static_pointer_cast(root_); + auto const& innerRoot = intr_ptr::static_pointer_cast(root_); for (int i = 0; i < 16; ++i) { if (!innerRoot->isEmptyBranch(i)) @@ -319,8 +273,7 @@ SHAMap::walkMapParallel( if (!child || !child->isInner()) continue; - nodeStacks[rootChildIndex].push( - intr_ptr::static_pointer_cast(child)); + nodeStacks[rootChildIndex].push(intr_ptr::static_pointer_cast(child)); JLOG(journal_.debug()) << "starting worker " << rootChildIndex; workers.push_back(std::thread( @@ -330,32 +283,25 @@ SHAMap::walkMapParallel( { while (!nodeStack.empty()) { - intr_ptr::SharedPtr node = - std::move(nodeStack.top()); - XRPL_ASSERT( - node, - "ripple::SHAMap::walkMapParallel : non-null node"); + intr_ptr::SharedPtr node = std::move(nodeStack.top()); + XRPL_ASSERT(node, "xrpl::SHAMap::walkMapParallel : non-null node"); nodeStack.pop(); for (int i = 0; i < 16; ++i) { if (node->isEmptyBranch(i)) continue; - intr_ptr::SharedPtr nextNode = - descendNoStore(*node, i); + intr_ptr::SharedPtr nextNode = descendNoStore(*node, i); if (nextNode) { if (nextNode->isInner()) - nodeStack.push( - intr_ptr::static_pointer_cast< - SHAMapInnerNode>(nextNode)); + nodeStack.push(intr_ptr::static_pointer_cast(nextNode)); } else { std::lock_guard l{m}; - missingNodes.emplace_back( - type_, node->getChildHash(i)); + missingNodes.emplace_back(type_, node->getChildHash(i)); if (--maxMissing <= 0) return; } @@ -385,4 +331,4 @@ SHAMap::walkMapParallel( return false; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapInnerNode.cpp b/src/libxrpl/shamap/SHAMapInnerNode.cpp index 1b55887098..5ccca9c2f4 100644 --- a/src/libxrpl/shamap/SHAMapInnerNode.cpp +++ b/src/libxrpl/shamap/SHAMapInnerNode.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,11 +8,9 @@ #include #include -namespace ripple { +namespace xrpl { -SHAMapInnerNode::SHAMapInnerNode( - std::uint32_t cowid, - std::uint8_t numAllocatedChildren) +SHAMapInnerNode::SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren) : SHAMapTreeNode(cowid), hashesAndChildren_(numAllocatedChildren) { } @@ -43,10 +22,8 @@ SHAMapInnerNode::partialDestructor() { intr_ptr::SharedPtr* children; // structured bindings can't be captured in c++ 17; use tie instead - std::tie(std::ignore, std::ignore, children) = - hashesAndChildren_.getHashesAndChildren(); - iterNonEmptyChildIndexes( - [&](auto branchNum, auto indexNum) { children[indexNum].reset(); }); + std::tie(std::ignore, std::ignore, children) = hashesAndChildren_.getHashesAndChildren(); + iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { children[indexNum].reset(); }); } template @@ -66,8 +43,7 @@ SHAMapInnerNode::iterNonEmptyChildIndexes(F&& f) const void SHAMapInnerNode::resizeChildArrays(std::uint8_t toAllocate) { - hashesAndChildren_ = - TaggedPointer(std::move(hashesAndChildren_), isBranch_, toAllocate); + hashesAndChildren_ = TaggedPointer(std::move(hashesAndChildren_), isBranch_, toAllocate); } std::optional @@ -88,23 +64,18 @@ SHAMapInnerNode::clone(std::uint32_t cowid) const SHAMapHash *cloneHashes, *thisHashes; intr_ptr::SharedPtr*cloneChildren, *thisChildren; // structured bindings can't be captured in c++ 17; use tie instead - std::tie(std::ignore, cloneHashes, cloneChildren) = - p->hashesAndChildren_.getHashesAndChildren(); - std::tie(std::ignore, thisHashes, thisChildren) = - hashesAndChildren_.getHashesAndChildren(); + std::tie(std::ignore, cloneHashes, cloneChildren) = p->hashesAndChildren_.getHashesAndChildren(); + std::tie(std::ignore, thisHashes, thisChildren) = hashesAndChildren_.getHashesAndChildren(); if (thisIsSparse) { int cloneChildIndex = 0; - iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { - cloneHashes[cloneChildIndex++] = thisHashes[indexNum]; - }); + iterNonEmptyChildIndexes( + [&](auto branchNum, auto indexNum) { cloneHashes[cloneChildIndex++] = thisHashes[indexNum]; }); } else { - iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { - cloneHashes[branchNum] = thisHashes[indexNum]; - }); + iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { cloneHashes[branchNum] = thisHashes[indexNum]; }); } spinlock sl(lock_); @@ -113,25 +84,20 @@ SHAMapInnerNode::clone(std::uint32_t cowid) const if (thisIsSparse) { int cloneChildIndex = 0; - iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { - cloneChildren[cloneChildIndex++] = thisChildren[indexNum]; - }); + iterNonEmptyChildIndexes( + [&](auto branchNum, auto indexNum) { cloneChildren[cloneChildIndex++] = thisChildren[indexNum]; }); } else { - iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { - cloneChildren[branchNum] = thisChildren[indexNum]; - }); + iterNonEmptyChildIndexes( + [&](auto branchNum, auto indexNum) { cloneChildren[branchNum] = thisChildren[indexNum]; }); } return p; } intr_ptr::SharedPtr -SHAMapInnerNode::makeFullInner( - Slice data, - SHAMapHash const& hash, - bool hashValid) +SHAMapInnerNode::makeFullInner(Slice data, SHAMapHash const& hash, bool hashValid) { // A full inner node is serialized as 16 256-bit hashes, back to back: if (data.size() != branchFactor * uint256::bytes) @@ -168,8 +134,7 @@ SHAMapInnerNode::makeCompressedInner(Slice data) // representing a one byte "position" and a 256-bit hash: constexpr std::size_t chunkSize = uint256::bytes + 1; - if (auto const s = data.size(); - (s % chunkSize != 0) || (s > chunkSize * branchFactor)) + if (auto const s = data.size(); (s % chunkSize != 0) || (s > chunkSize * branchFactor)) Throw("Invalid CI node"); SerialIter si(data); @@ -218,8 +183,7 @@ SHAMapInnerNode::updateHashDeep() SHAMapHash* hashes; intr_ptr::SharedPtr* children; // structured bindings can't be captured in c++ 17; use tie instead - std::tie(std::ignore, hashes, children) = - hashesAndChildren_.getHashesAndChildren(); + std::tie(std::ignore, hashes, children) = hashesAndChildren_.getHashesAndChildren(); iterNonEmptyChildIndexes([&](auto branchNum, auto indexNum) { if (auto p = children[indexNum].get()) hashes[indexNum] = p->getHash(); @@ -230,8 +194,7 @@ SHAMapInnerNode::updateHashDeep() void SHAMapInnerNode::serializeForWire(Serializer& s) const { - XRPL_ASSERT( - !isEmpty(), "ripple::SHAMapInnerNode::serializeForWire : is non-empty"); + XRPL_ASSERT(!isEmpty(), "xrpl::SHAMapInnerNode::serializeForWire : is non-empty"); // If the node is sparse, then only send non-empty branches: if (getBranchCount() < 12) @@ -246,8 +209,7 @@ SHAMapInnerNode::serializeForWire(Serializer& s) const } else { - iterChildren( - [&](SHAMapHash const& hh) { s.addBitString(hh.as_uint256()); }); + iterChildren([&](SHAMapHash const& hh) { s.addBitString(hh.as_uint256()); }); s.add8(wireTypeInner); } } @@ -255,13 +217,10 @@ SHAMapInnerNode::serializeForWire(Serializer& s) const void SHAMapInnerNode::serializeWithPrefix(Serializer& s) const { - XRPL_ASSERT( - !isEmpty(), - "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty"); + XRPL_ASSERT(!isEmpty(), "xrpl::SHAMapInnerNode::serializeWithPrefix : is non-empty"); s.add32(HashPrefix::innerNode); - iterChildren( - [&](SHAMapHash const& hh) { s.addBitString(hh.as_uint256()); }); + iterChildren([&](SHAMapHash const& hh) { s.addBitString(hh.as_uint256()); }); } std::string @@ -282,13 +241,9 @@ SHAMapInnerNode::getString(SHAMapNodeID const& id) const void SHAMapInnerNode::setChild(int m, intr_ptr::SharedPtr child) { - XRPL_ASSERT( - (m >= 0) && (m < branchFactor), - "ripple::SHAMapInnerNode::setChild : valid branch input"); - XRPL_ASSERT(cowid_, "ripple::SHAMapInnerNode::setChild : nonzero cowid"); - XRPL_ASSERT( - child.get() != this, - "ripple::SHAMapInnerNode::setChild : valid child input"); + XRPL_ASSERT((m >= 0) && (m < branchFactor), "xrpl::SHAMapInnerNode::setChild : valid branch input"); + XRPL_ASSERT(cowid_, "xrpl::SHAMapInnerNode::setChild : nonzero cowid"); + XRPL_ASSERT(child.get() != this, "xrpl::SHAMapInnerNode::setChild : valid child input"); auto const dstIsBranch = [&] { if (child) @@ -300,8 +255,7 @@ SHAMapInnerNode::setChild(int m, intr_ptr::SharedPtr child) auto const dstToAllocate = popcnt16(dstIsBranch); // change hashesAndChildren to remove the element, or make room for the // added element, if necessary - hashesAndChildren_ = TaggedPointer( - std::move(hashesAndChildren_), isBranch_, dstIsBranch, dstToAllocate); + hashesAndChildren_ = TaggedPointer(std::move(hashesAndChildren_), isBranch_, dstIsBranch, dstToAllocate); isBranch_ = dstIsBranch; @@ -316,41 +270,27 @@ SHAMapInnerNode::setChild(int m, intr_ptr::SharedPtr child) hash_.zero(); XRPL_ASSERT( - getBranchCount() <= hashesAndChildren_.capacity(), - "ripple::SHAMapInnerNode::setChild : maximum branch count"); + getBranchCount() <= hashesAndChildren_.capacity(), "xrpl::SHAMapInnerNode::setChild : maximum branch count"); } // finished modifying, now make shareable void -SHAMapInnerNode::shareChild( - int m, - intr_ptr::SharedPtr const& child) +SHAMapInnerNode::shareChild(int m, intr_ptr::SharedPtr const& child) { - XRPL_ASSERT( - (m >= 0) && (m < branchFactor), - "ripple::SHAMapInnerNode::shareChild : valid branch input"); - XRPL_ASSERT(cowid_, "ripple::SHAMapInnerNode::shareChild : nonzero cowid"); - XRPL_ASSERT( - child, "ripple::SHAMapInnerNode::shareChild : non-null child input"); - XRPL_ASSERT( - child.get() != this, - "ripple::SHAMapInnerNode::shareChild : valid child input"); + XRPL_ASSERT((m >= 0) && (m < branchFactor), "xrpl::SHAMapInnerNode::shareChild : valid branch input"); + XRPL_ASSERT(cowid_, "xrpl::SHAMapInnerNode::shareChild : nonzero cowid"); + XRPL_ASSERT(child, "xrpl::SHAMapInnerNode::shareChild : non-null child input"); + XRPL_ASSERT(child.get() != this, "xrpl::SHAMapInnerNode::shareChild : valid child input"); - XRPL_ASSERT( - !isEmptyBranch(m), - "ripple::SHAMapInnerNode::shareChild : non-empty branch input"); + XRPL_ASSERT(!isEmptyBranch(m), "xrpl::SHAMapInnerNode::shareChild : non-empty branch input"); hashesAndChildren_.getChildren()[*getChildIndex(m)] = child; } SHAMapTreeNode* SHAMapInnerNode::getChildPointer(int branch) { - XRPL_ASSERT( - branch >= 0 && branch < branchFactor, - "ripple::SHAMapInnerNode::getChildPointer : valid branch input"); - XRPL_ASSERT( - !isEmptyBranch(branch), - "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input"); + XRPL_ASSERT(branch >= 0 && branch < branchFactor, "xrpl::SHAMapInnerNode::getChildPointer : valid branch input"); + XRPL_ASSERT(!isEmptyBranch(branch), "xrpl::SHAMapInnerNode::getChildPointer : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -362,12 +302,8 @@ SHAMapInnerNode::getChildPointer(int branch) intr_ptr::SharedPtr SHAMapInnerNode::getChild(int branch) { - XRPL_ASSERT( - branch >= 0 && branch < branchFactor, - "ripple::SHAMapInnerNode::getChild : valid branch input"); - XRPL_ASSERT( - !isEmptyBranch(branch), - "ripple::SHAMapInnerNode::getChild : non-empty branch input"); + XRPL_ASSERT(branch >= 0 && branch < branchFactor, "xrpl::SHAMapInnerNode::getChild : valid branch input"); + XRPL_ASSERT(!isEmptyBranch(branch), "xrpl::SHAMapInnerNode::getChild : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -379,9 +315,7 @@ SHAMapInnerNode::getChild(int branch) SHAMapHash const& SHAMapInnerNode::getChildHash(int m) const { - XRPL_ASSERT( - (m >= 0) && (m < branchFactor), - "ripple::SHAMapInnerNode::getChildHash : valid branch input"); + XRPL_ASSERT((m >= 0) && (m < branchFactor), "xrpl::SHAMapInnerNode::getChildHash : valid branch input"); if (auto const i = getChildIndex(m)) return hashesAndChildren_.getHashes()[*i]; @@ -389,24 +323,16 @@ SHAMapInnerNode::getChildHash(int m) const } intr_ptr::SharedPtr -SHAMapInnerNode::canonicalizeChild( - int branch, - intr_ptr::SharedPtr node) +SHAMapInnerNode::canonicalizeChild(int branch, intr_ptr::SharedPtr node) { - XRPL_ASSERT( - branch >= 0 && branch < branchFactor, - "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input"); - XRPL_ASSERT( - node != nullptr, - "ripple::SHAMapInnerNode::canonicalizeChild : valid node input"); - XRPL_ASSERT( - !isEmptyBranch(branch), - "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input"); + XRPL_ASSERT(branch >= 0 && branch < branchFactor, "xrpl::SHAMapInnerNode::canonicalizeChild : valid branch input"); + XRPL_ASSERT(node != nullptr, "xrpl::SHAMapInnerNode::canonicalizeChild : valid node input"); + XRPL_ASSERT(!isEmptyBranch(branch), "xrpl::SHAMapInnerNode::canonicalizeChild : non-empty branch input"); auto const childIndex = *getChildIndex(branch); auto [_, hashes, children] = hashesAndChildren_.getHashesAndChildren(); XRPL_ASSERT( node->getHash() == hashes[childIndex], - "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs " + "xrpl::SHAMapInnerNode::canonicalizeChild : node and branch inputs " "hash do match"); packed_spinlock sl(lock_, childIndex); @@ -429,17 +355,14 @@ void SHAMapInnerNode::invariants(bool is_root) const { [[maybe_unused]] unsigned count = 0; - auto [numAllocated, hashes, children] = - hashesAndChildren_.getHashesAndChildren(); + auto [numAllocated, hashes, children] = hashesAndChildren_.getHashesAndChildren(); if (numAllocated != branchFactor) { auto const branchCount = getBranchCount(); for (int i = 0; i < branchCount; ++i) { - XRPL_ASSERT( - hashes[i].isNonZero(), - "ripple::SHAMapInnerNode::invariants : nonzero hash in branch"); + XRPL_ASSERT(hashes[i].isNonZero(), "xrpl::SHAMapInnerNode::invariants : nonzero hash in branch"); if (children[i] != nullptr) children[i]->invariants(); ++count; @@ -453,7 +376,7 @@ SHAMapInnerNode::invariants(bool is_root) const { XRPL_ASSERT( (isBranch_ & (1 << i)), - "ripple::SHAMapInnerNode::invariants : valid branch when " + "xrpl::SHAMapInnerNode::invariants : valid branch when " "nonzero hash"); if (children[i] != nullptr) children[i]->invariants(); @@ -463,7 +386,7 @@ SHAMapInnerNode::invariants(bool is_root) const { XRPL_ASSERT( (isBranch_ & (1 << i)) == 0, - "ripple::SHAMapInnerNode::invariants : valid branch when " + "xrpl::SHAMapInnerNode::invariants : valid branch when " "zero hash"); } } @@ -471,15 +394,12 @@ SHAMapInnerNode::invariants(bool is_root) const if (!is_root) { - XRPL_ASSERT( - hash_.isNonZero(), - "ripple::SHAMapInnerNode::invariants : nonzero hash"); - XRPL_ASSERT( - count >= 1, "ripple::SHAMapInnerNode::invariants : minimum count"); + XRPL_ASSERT(hash_.isNonZero(), "xrpl::SHAMapInnerNode::invariants : nonzero hash"); + XRPL_ASSERT(count >= 1, "xrpl::SHAMapInnerNode::invariants : minimum count"); } XRPL_ASSERT( (count == 0) ? hash_.isZero() : hash_.isNonZero(), - "ripple::SHAMapInnerNode::invariants : hash and count do match"); + "xrpl::SHAMapInnerNode::invariants : hash and count do match"); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapLeafNode.cpp b/src/libxrpl/shamap/SHAMapLeafNode.cpp index a6ba55a2c7..7f449af3a7 100644 --- a/src/libxrpl/shamap/SHAMapLeafNode.cpp +++ b/src/libxrpl/shamap/SHAMapLeafNode.cpp @@ -1,46 +1,22 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { -SHAMapLeafNode::SHAMapLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid) +SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr item, std::uint32_t cowid) : SHAMapTreeNode(cowid), item_(std::move(item)) { XRPL_ASSERT( item_->size() >= 12, - "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "xrpl::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" "SHAMapItem const>, std::uint32_t) : minimum input size"); } -SHAMapLeafNode::SHAMapLeafNode( - boost::intrusive_ptr item, - std::uint32_t cowid, - SHAMapHash const& hash) +SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr item, std::uint32_t cowid, SHAMapHash const& hash) : SHAMapTreeNode(cowid, hash), item_(std::move(item)) { XRPL_ASSERT( item_->size() >= 12, - "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "xrpl::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" "SHAMapItem const>, std::uint32_t, SHAMapHash const&) : minimum input " "size"); } @@ -54,7 +30,7 @@ SHAMapLeafNode::peekItem() const bool SHAMapLeafNode::setItem(boost::intrusive_ptr item) { - XRPL_ASSERT(cowid_, "ripple::SHAMapLeafNode::setItem : nonzero cowid"); + XRPL_ASSERT(cowid_, "xrpl::SHAMapLeafNode::setItem : nonzero cowid"); item_ = std::move(item); auto const oldHash = hash_; @@ -92,9 +68,8 @@ SHAMapLeafNode::getString(SHAMapNodeID const& id) const void SHAMapLeafNode::invariants(bool) const { - XRPL_ASSERT( - hash_.isNonZero(), "ripple::SHAMapLeafNode::invariants : nonzero hash"); - XRPL_ASSERT(item_, "ripple::SHAMapLeafNode::invariants : non-null item"); + XRPL_ASSERT(hash_.isNonZero(), "xrpl::SHAMapLeafNode::invariants : nonzero hash"); + XRPL_ASSERT(item_, "xrpl::SHAMapLeafNode::invariants : non-null item"); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapNodeID.cpp b/src/libxrpl/shamap/SHAMapNodeID.cpp index 189a127620..e8840f398d 100644 --- a/src/libxrpl/shamap/SHAMapNodeID.cpp +++ b/src/libxrpl/shamap/SHAMapNodeID.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -namespace ripple { +namespace xrpl { static uint256 const& depthMask(unsigned int depth) @@ -53,15 +34,10 @@ depthMask(unsigned int depth) } // canonicalize the hash to a node ID for this depth -SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash) - : id_(hash), depth_(depth) +SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash) : id_(hash), depth_(depth) { - XRPL_ASSERT( - depth <= SHAMap::leafDepth, - "ripple::SHAMapNodeID::SHAMapNodeID : maximum depth input"); - XRPL_ASSERT( - id_ == (id_ & depthMask(depth)), - "ripple::SHAMapNodeID::SHAMapNodeID : hash and depth inputs do match"); + XRPL_ASSERT(depth <= SHAMap::leafDepth, "xrpl::SHAMapNodeID::SHAMapNodeID : maximum depth input"); + XRPL_ASSERT(id_ == (id_ & depthMask(depth)), "xrpl::SHAMapNodeID::SHAMapNodeID : hash and depth inputs do match"); } std::string @@ -76,9 +52,7 @@ SHAMapNodeID::getRawString() const SHAMapNodeID SHAMapNodeID::getChildNodeID(unsigned int m) const { - XRPL_ASSERT( - m < SHAMap::branchFactor, - "ripple::SHAMapNodeID::getChildNodeID : valid branch input"); + XRPL_ASSERT(m < SHAMap::branchFactor, "xrpl::SHAMapNodeID::getChildNodeID : valid branch input"); // A SHAMap has exactly 65 levels, so nodes must not exceed that // depth; if they do, this breaks the invariant of never allowing @@ -88,13 +62,10 @@ SHAMapNodeID::getChildNodeID(unsigned int m) const // We throw (but never assert) if the node is at level 64, since // entries at that depth are leaf nodes and have no children and even // constructing a child node from them would break the above invariant. - XRPL_ASSERT( - depth_ <= SHAMap::leafDepth, - "ripple::SHAMapNodeID::getChildNodeID : maximum leaf depth"); + XRPL_ASSERT(depth_ <= SHAMap::leafDepth, "xrpl::SHAMapNodeID::getChildNodeID : maximum leaf depth"); if (depth_ >= SHAMap::leafDepth) - Throw( - "Request for child node ID of " + to_string(*this)); + Throw("Request for child node ID of " + to_string(*this)); if (id_ != (id_ & depthMask(depth_))) Throw("Incorrect mask for " + to_string(*this)); @@ -135,18 +106,15 @@ selectBranch(SHAMapNodeID const& id, uint256 const& hash) else branch >>= 4; - XRPL_ASSERT( - branch < SHAMap::branchFactor, "ripple::selectBranch : maximum result"); + XRPL_ASSERT(branch < SHAMap::branchFactor, "xrpl::selectBranch : maximum result"); return branch; } SHAMapNodeID SHAMapNodeID::createID(int depth, uint256 const& key) { - XRPL_ASSERT( - (depth >= 0) && (depth < 65), - "ripple::SHAMapNodeID::createID : valid branch input"); + XRPL_ASSERT((depth >= 0) && (depth < 65), "xrpl::SHAMapNodeID::createID : valid branch input"); return SHAMapNodeID(depth, key & depthMask(depth)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapSync.cpp b/src/libxrpl/shamap/SHAMapSync.cpp index e6049f1083..503505b80c 100644 --- a/src/libxrpl/shamap/SHAMapSync.cpp +++ b/src/libxrpl/shamap/SHAMapSync.cpp @@ -1,33 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { void -SHAMap::visitLeaves( - std::function const& - item)> const& leafFunction) const +SHAMap::visitLeaves(std::function const& item)> const& leafFunction) const { visitNodes([&leafFunction](SHAMapTreeNode& node) { if (!node.isInner()) @@ -59,8 +38,7 @@ SHAMap::visitNodes(std::function const& function) const { if (!node->isEmptyBranch(pos)) { - intr_ptr::SharedPtr child = - descendNoStore(*node, pos); + intr_ptr::SharedPtr child = descendNoStore(*node, pos); if (!function(*child)) return; @@ -79,8 +57,7 @@ SHAMap::visitNodes(std::function const& function) const } // descend to the child's first position - node = - intr_ptr::static_pointer_cast(child); + node = intr_ptr::static_pointer_cast(child); pos = 0; } } @@ -99,9 +76,7 @@ SHAMap::visitNodes(std::function const& function) const } void -SHAMap::visitDifferences( - SHAMap const* have, - std::function const& function) const +SHAMap::visitDifferences(SHAMap const* have, std::function const& function) const { // Visit every node in this SHAMap that is not present // in the specified SHAMap @@ -117,8 +92,7 @@ SHAMap::visitDifferences( if (root_->isLeaf()) { auto leaf = intr_ptr::static_pointer_cast(root_); - if (!have || - !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash())) + if (!have || !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash())) function(*root_); return; } @@ -149,14 +123,9 @@ SHAMap::visitDifferences( if (next->isInner()) { if (!have || !have->hasInnerNode(childID, childHash)) - stack.push( - {static_cast(next), childID}); + stack.push({static_cast(next), childID}); } - else if ( - !have || - !have->hasLeafNode( - static_cast(next)->peekItem()->key(), - childHash)) + else if (!have || !have->hasLeafNode(static_cast(next)->peekItem()->key(), childHash)) { if (!function(*next)) return; @@ -192,9 +161,7 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) // we already know this child node is missing fullBelow = false; } - else if ( - !backed_ || - !f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256())) + else if (!backed_ || !f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256())) { bool pending = false; auto d = descendAsync( @@ -202,13 +169,10 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) branch, mn.filter_, pending, - [node, nodeID, branch, &mn]( - intr_ptr::SharedPtr found, - SHAMapHash const&) { + [node, nodeID, branch, &mn](intr_ptr::SharedPtr found, SHAMapHash const&) { // a read completed asynchronously std::unique_lock lock{mn.deferLock_}; - mn.finishedReads_.emplace_back( - node, nodeID, branch, std::move(found)); + mn.finishedReads_.emplace_back(node, nodeID, branch, std::move(found)); mn.deferCondVar_.notify_one(); }); @@ -223,15 +187,12 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) fullBelow = false; // for now, not known full below mn.missingHashes_.insert(childHash); - mn.missingNodes_.emplace_back( - nodeID.getChildNodeID(branch), childHash.as_uint256()); + mn.missingNodes_.emplace_back(nodeID.getChildNodeID(branch), childHash.as_uint256()); if (--mn.max_ <= 0) return; } - else if ( - d->isInner() && - !static_cast(d)->isFullBelow(mn.generation_)) + else if (d->isInner() && !static_cast(d)->isFullBelow(mn.generation_)) { mn.stack_.push(se); @@ -269,12 +230,7 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn) int complete = 0; while (complete != mn.deferred_) { - std::tuple< - SHAMapInnerNode*, - SHAMapNodeID, - int, - intr_ptr::SharedPtr> - deferredNode; + std::tuple> deferredNode; { std::unique_lock lock{mn.deferLock_}; @@ -299,8 +255,7 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn) } else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second)) { - mn.missingNodes_.emplace_back( - parentID.getChildNodeID(branch), nodeHash.as_uint256()); + mn.missingNodes_.emplace_back(parentID.getChildNodeID(branch), nodeHash.as_uint256()); --mn.max_; } } @@ -317,10 +272,8 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn) std::vector> SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) { - XRPL_ASSERT( - root_->getHash().isNonZero(), - "ripple::SHAMap::getMissingNodes : nonzero root hash"); - XRPL_ASSERT(max > 0, "ripple::SHAMap::getMissingNodes : valid max input"); + XRPL_ASSERT(root_->getHash().isNonZero(), "xrpl::SHAMap::getMissingNodes : nonzero root hash"); + XRPL_ASSERT(max > 0, "xrpl::SHAMap::getMissingNodes : valid max input"); MissingNodes mn( max, @@ -328,9 +281,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) 512, // number of async reads per pass f_.getFullBelowCache()->getGeneration()); - if (!root_->isInner() || - intr_ptr::static_pointer_cast(root_)->isFullBelow( - mn.generation_)) + if (!root_->isInner() || intr_ptr::static_pointer_cast(root_)->isFullBelow(mn.generation_)) { clearSynching(); return std::move(mn.missingNodes_); @@ -342,12 +293,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // (randomly selected) inner node. This increases the likelihood // that the two threads will produce different request sets (which is // more efficient than sending identical requests). - MissingNodes::StackEntry pos{ - static_cast(root_.get()), - SHAMapNodeID(), - rand_int(255), - 0, - true}; + MissingNodes::StackEntry pos{static_cast(root_.get()), SHAMapNodeID(), rand_int(255), 0, true}; auto& node = std::get<0>(pos); auto& nextChild = std::get<3>(pos); auto& fullBelow = std::get<4>(pos); @@ -379,9 +325,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // This is a node we are continuing to process fullBelow = fullBelow && was; // was and still is } - XRPL_ASSERT( - node, - "ripple::SHAMap::getMissingNodes : first non-null node"); + XRPL_ASSERT(node, "xrpl::SHAMap::getMissingNodes : first non-null node"); } } @@ -401,8 +345,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // Recheck nodes we could not finish before for (auto const& [innerNode, nodeId] : mn.resumes_) if (!innerNode->isFullBelow(mn.generation_)) - mn.stack_.push(std::make_tuple( - innerNode, nodeId, rand_int(255), 0, true)); + mn.stack_.push(std::make_tuple(innerNode, nodeId, rand_int(255), 0, true)); mn.resumes_.clear(); } @@ -412,9 +355,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // Resume at the top of the stack pos = mn.stack_.top(); mn.stack_.pop(); - XRPL_ASSERT( - node, - "ripple::SHAMap::getMissingNodes : second non-null node"); + XRPL_ASSERT(node, "xrpl::SHAMap::getMissingNodes : second non-null node"); } } @@ -455,9 +396,7 @@ SHAMap::getNodeFat( if (node == nullptr || wanted != nodeID) { - JLOG(journal_.info()) - << "peer requested node that is not in the map: " << wanted - << " but found " << nodeID; + JLOG(journal_.info()) << "peer requested node that is not in the map: " << wanted << " but found " << nodeID; return false; } @@ -503,18 +442,14 @@ SHAMap::getNodeFat( { // If there's more than one child, reduce the depth // If only one child, follow the chain - stack.emplace( - childNode, - childID, - (bc > 1) ? (depth - 1) : depth); + stack.emplace(childNode, childID, (bc > 1) ? (depth - 1) : depth); } else if (childNode->isInner() || fatLeaves) { // Just include this node s.erase(); childNode->serializeForWire(s); - data.emplace_back( - std::make_pair(childID, s.getData())); + data.emplace_back(std::make_pair(childID, s.getData())); } } } @@ -532,22 +467,17 @@ SHAMap::serializeRoot(Serializer& s) const } SHAMapAddNode -SHAMap::addRootNode( - SHAMapHash const& hash, - Slice const& rootNode, - SHAMapSyncFilter* filter) +SHAMap::addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter* filter) { // we already have a root_ node if (root_->getHash().isNonZero()) { JLOG(journal_.trace()) << "got root node, already have one"; - XRPL_ASSERT( - root_->getHash() == hash, - "ripple::SHAMap::addRootNode : valid hash input"); + XRPL_ASSERT(root_->getHash() == hash, "xrpl::SHAMap::addRootNode : valid hash input"); return SHAMapAddNode::duplicate(); } - XRPL_ASSERT(cowid_ >= 1, "ripple::SHAMap::addRootNode : valid cowid"); + XRPL_ASSERT(cowid_ >= 1, "xrpl::SHAMap::addRootNode : valid cowid"); auto node = SHAMapTreeNode::makeFromWire(rootNode); if (!node || node->getHash() != hash) return SHAMapAddNode::invalid(); @@ -564,25 +494,16 @@ SHAMap::addRootNode( { Serializer s; root_->serializeWithPrefix(s); - filter->gotNode( - false, - root_->getHash(), - ledgerSeq_, - std::move(s.modData()), - root_->getType()); + filter->gotNode(false, root_->getHash(), ledgerSeq_, std::move(s.modData()), root_->getType()); } return SHAMapAddNode::useful(); } SHAMapAddNode -SHAMap::addKnownNode( - SHAMapNodeID const& node, - Slice const& rawNode, - SHAMapSyncFilter* filter) +SHAMap::addKnownNode(SHAMapNodeID const& node, Slice const& rawNode, SHAMapSyncFilter* filter) { - XRPL_ASSERT( - !node.isRoot(), "ripple::SHAMap::addKnownNode : valid node input"); + XRPL_ASSERT(!node.isRoot(), "xrpl::SHAMap::addKnownNode : valid node input"); if (!isSynching()) { @@ -594,12 +515,11 @@ SHAMap::addKnownNode( SHAMapNodeID currNodeID; auto currNode = root_.get(); - while (currNode->isInner() && - !static_cast(currNode)->isFullBelow(generation) && + while (currNode->isInner() && !static_cast(currNode)->isFullBelow(generation) && (currNodeID.getDepth() < node.getDepth())) { int const branch = selectBranch(currNodeID, node.getNodeID()); - XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch"); + XRPL_ASSERT(branch >= 0, "xrpl::SHAMap::addKnownNode : valid branch"); auto inner = static_cast(currNode); if (inner->isEmptyBranch(branch)) { @@ -614,8 +534,7 @@ SHAMap::addKnownNode( } auto prevNode = inner; - std::tie(currNode, currNodeID) = - descend(inner, currNodeID, branch, filter); + std::tie(currNode, currNodeID) = descend(inner, currNodeID, branch, filter); if (currNode != nullptr) continue; @@ -635,20 +554,14 @@ SHAMap::addKnownNode( // propagate further down the line. if (newNode->isLeaf()) { - auto const& actualKey = - static_cast(newNode.get()) - ->peekItem() - ->key(); + auto const& actualKey = static_cast(newNode.get())->peekItem()->key(); // Validate that this leaf belongs at the target position - auto const expectedNodeID = - SHAMapNodeID::createID(node.getDepth(), actualKey); + auto const expectedNodeID = SHAMapNodeID::createID(node.getDepth(), actualKey); if (expectedNodeID.getNodeID() != node.getNodeID()) { - JLOG(journal_.debug()) - << "Leaf node position mismatch: " - << "expected=" << expectedNodeID.getNodeID() - << ", actual=" << node.getNodeID(); + JLOG(journal_.debug()) << "Leaf node position mismatch: " + << "expected=" << expectedNodeID.getNodeID() << ", actual=" << node.getNodeID(); return SHAMapAddNode::invalid(); } } @@ -656,8 +569,7 @@ SHAMap::addKnownNode( // Inner nodes must be at a level strictly less than 64 // but leaf nodes (while notionally at level 64) can be // at any depth up to and including 64: - if ((currNodeID.getDepth() > leafDepth) || - (newNode->isInner() && currNodeID.getDepth() == leafDepth)) + if ((currNodeID.getDepth() > leafDepth) || (newNode->isInner() && currNodeID.getDepth() == leafDepth)) { // Map is provably invalid state_ = SHAMapState::Invalid; @@ -669,8 +581,7 @@ SHAMap::addKnownNode( // Either this node is broken or we didn't request it (yet) JLOG(journal_.warn()) << "unable to hook node " << node; JLOG(journal_.info()) << " stuck at " << currNodeID; - JLOG(journal_.info()) << "got depth=" << node.getDepth() - << ", walked to= " << currNodeID.getDepth(); + JLOG(journal_.info()) << "got depth=" << node.getDepth() << ", walked to= " << currNodeID.getDepth(); return SHAMapAddNode::useful(); } @@ -683,12 +594,7 @@ SHAMap::addKnownNode( { Serializer s; newNode->serializeWithPrefix(s); - filter->gotNode( - false, - childHash, - ledgerSeq_, - std::move(s.modData()), - newNode->getType()); + filter->gotNode(false, childHash, ledgerSeq_, std::move(s.modData()), newNode->getType()); } return SHAMapAddNode::useful(); @@ -727,8 +633,7 @@ SHAMap::deepCompare(SHAMap& other) const if (!otherNode->isLeaf()) return false; auto& nodePeek = static_cast(node)->peekItem(); - auto& otherNodePeek = - static_cast(otherNode)->peekItem(); + auto& otherNodePeek = static_cast(otherNode)->peekItem(); if (nodePeek->key() != otherNodePeek->key()) return false; if (nodePeek->slice() != otherNodePeek->slice()) @@ -771,9 +676,7 @@ SHAMap::deepCompare(SHAMap& other) const /** Does this map have this inner node? */ bool -SHAMap::hasInnerNode( - SHAMapNodeID const& targetNodeID, - SHAMapHash const& targetNodeHash) const +SHAMap::hasInnerNode(SHAMapNodeID const& targetNodeID, SHAMapHash const& targetNodeHash) const { auto node = root_.get(); SHAMapNodeID nodeID; @@ -810,8 +713,7 @@ SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const if (inner->isEmptyBranch(branch)) return false; // Dead end, node must not be here - if (inner->getChildHash(branch) == - targetNodeHash) // Matching leaf, no need to retrieve it + if (inner->getChildHash(branch) == targetNodeHash) // Matching leaf, no need to retrieve it return true; node = descendThrow(inner, branch); @@ -834,10 +736,8 @@ SHAMap::getProofPath(uint256 const& key) const return {}; } - if (auto const& node = stack.top().first; !node || node->isInner() || - intr_ptr::static_pointer_cast(node) - ->peekItem() - ->key() != key) + if (auto const& node = stack.top().first; + !node || node->isInner() || intr_ptr::static_pointer_cast(node)->peekItem()->key() != key) { JLOG(journal_.debug()) << "no path to " << key; return {}; @@ -853,16 +753,12 @@ SHAMap::getProofPath(uint256 const& key) const stack.pop(); } - JLOG(journal_.debug()) << "getPath for key " << key << ", path length " - << path.size(); + JLOG(journal_.debug()) << "getPath for key " << key << ", path length " << path.size(); return path; } bool -SHAMap::verifyProofPath( - uint256 const& rootHash, - uint256 const& key, - std::vector const& path) +SHAMap::verifyProofPath(uint256 const& rootHash, uint256 const& key, std::vector const& path) { if (path.empty() || path.size() > 65) return false; @@ -884,8 +780,7 @@ SHAMap::verifyProofPath( if (node->isInner()) { auto nodeId = SHAMapNodeID::createID(depth, key); - hash = static_cast(node.get()) - ->getChildHash(selectBranch(nodeId, key)); + hash = static_cast(node.get())->getChildHash(selectBranch(nodeId, key)); } else { @@ -903,4 +798,4 @@ SHAMap::verifyProofPath( return false; } -} // namespace ripple +} // namespace xrpl diff --git a/src/libxrpl/shamap/SHAMapTreeNode.cpp b/src/libxrpl/shamap/SHAMapTreeNode.cpp index 049a4da80f..156570a60f 100644 --- a/src/libxrpl/shamap/SHAMapTreeNode.cpp +++ b/src/libxrpl/shamap/SHAMapTreeNode.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,29 +10,21 @@ #include #include -namespace ripple { +namespace xrpl { intr_ptr::SharedPtr -SHAMapTreeNode::makeTransaction( - Slice data, - SHAMapHash const& hash, - bool hashValid) +SHAMapTreeNode::makeTransaction(Slice data, SHAMapHash const& hash, bool hashValid) { - auto item = - make_shamapitem(sha512Half(HashPrefix::transactionID, data), data); + auto item = make_shamapitem(sha512Half(HashPrefix::transactionID, data), data); if (hashValid) - return intr_ptr::make_shared( - std::move(item), 0, hash); + return intr_ptr::make_shared(std::move(item), 0, hash); return intr_ptr::make_shared(std::move(item), 0); } intr_ptr::SharedPtr -SHAMapTreeNode::makeTransactionWithMeta( - Slice data, - SHAMapHash const& hash, - bool hashValid) +SHAMapTreeNode::makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool hashValid) { Serializer s(data.data(), data.size()); @@ -62,25 +35,20 @@ SHAMapTreeNode::makeTransactionWithMeta( // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.bytes)) - Throw( - "Short TXN+MD node (" + std::to_string(s.size()) + ")"); + Throw("Short TXN+MD node (" + std::to_string(s.size()) + ")"); s.chop(tag.bytes); auto item = make_shamapitem(tag, s.slice()); if (hashValid) - return intr_ptr::make_shared( - std::move(item), 0, hash); + return intr_ptr::make_shared(std::move(item), 0, hash); return intr_ptr::make_shared(std::move(item), 0); } intr_ptr::SharedPtr -SHAMapTreeNode::makeAccountState( - Slice data, - SHAMapHash const& hash, - bool hashValid) +SHAMapTreeNode::makeAccountState(Slice data, SHAMapHash const& hash, bool hashValid) { Serializer s(data.data(), data.size()); @@ -91,8 +59,7 @@ SHAMapTreeNode::makeAccountState( // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.bytes)) - Throw( - "Short AS node (" + std::to_string(s.size()) + ")"); + Throw("Short AS node (" + std::to_string(s.size()) + ")"); s.chop(tag.bytes); @@ -102,11 +69,9 @@ SHAMapTreeNode::makeAccountState( auto item = make_shamapitem(tag, s.slice()); if (hashValid) - return intr_ptr::make_shared( - std::move(item), 0, hash); + return intr_ptr::make_shared(std::move(item), 0, hash); - return intr_ptr::make_shared( - std::move(item), 0); + return intr_ptr::make_shared(std::move(item), 0); } intr_ptr::SharedPtr @@ -137,8 +102,7 @@ SHAMapTreeNode::makeFromWire(Slice rawNode) if (type == wireTypeTransactionWithMeta) return makeTransactionWithMeta(rawNode, hash, hashValid); - Throw( - "wire: Unknown type (" + std::to_string(type) + ")"); + Throw("wire: Unknown type (" + std::to_string(type) + ")"); } intr_ptr::SharedPtr @@ -150,10 +114,8 @@ SHAMapTreeNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash) // FIXME: Use SerialIter::get32? // Extract the prefix auto const type = safe_cast( - (safe_cast(rawNode[0]) << 24) + - (safe_cast(rawNode[1]) << 16) + - (safe_cast(rawNode[2]) << 8) + - (safe_cast(rawNode[3]))); + (safe_cast(rawNode[0]) << 24) + (safe_cast(rawNode[1]) << 16) + + (safe_cast(rawNode[2]) << 8) + (safe_cast(rawNode[3]))); rawNode.remove_prefix(4); @@ -172,9 +134,7 @@ SHAMapTreeNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash) return makeTransactionWithMeta(rawNode, hash, hashValid); Throw( - "prefix: unknown type (" + - std::to_string(safe_cast>(type)) + - ")"); + "prefix: unknown type (" + std::to_string(safe_cast>(type)) + ")"); } std::string @@ -183,4 +143,4 @@ SHAMapTreeNode::getString(SHAMapNodeID const& id) const return to_string(id); } -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AMMCalc_test.cpp b/src/test/app/AMMCalc_test.cpp index 7349b38766..bc50f02d3d 100644 --- a/src/test/app/AMMCalc_test.cpp +++ b/src/test/app/AMMCalc_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { /** AMM Calculator. Uses AMM formulas to simulate the payment engine @@ -42,8 +23,8 @@ class AMMCalc_test : public beast::unit_test::suite { using token_iter = boost::sregex_token_iterator; using steps = std::vector>; - using trates = std::map; - using swapargs = std::tuple; + using transfer_rates = std::map; + using swapargs = std::tuple; jtx::Account const gw{jtx::Account("gw")}; token_iter const end_; @@ -120,10 +101,10 @@ class AMMCalc_test : public beast::unit_test::suite return {{{*a1, *a2}, amm}}; } - std::optional + std::optional getTransferRate(token_iter& p) { - trates rates{}; + transfer_rates rates{}; if (p == end_) return rates; std::string str = *p; @@ -134,8 +115,8 @@ class AMMCalc_test : public beast::unit_test::suite { if (auto const rate = getRate(p++)) { - auto const [currency, trate, delimited] = *rate; - rates[currency] = trate; + auto const [currency, transferRate, delimited] = *rate; + rates[currency] = transferRate; if (delimited) break; } @@ -199,22 +180,21 @@ class AMMCalc_test : public beast::unit_test::suite auto const vp = std::get(args); STAmount sout = std::get(args); auto const fee = std::get(args); - auto const rates = std::get(args); + auto const rates = std::get(args); STAmount resultOut = sout; STAmount resultIn{}; STAmount sin{}; int limitingStep = vp.size(); STAmount limitStepOut{}; - auto trate = [&](auto const& amt) { + auto transferRate = [&](auto const& amt) { auto const currency = to_string(amt.issue().currency); - return rates.find(currency) != rates.end() ? rates.at(currency) - : QUALITY_ONE; + return rates.find(currency) != rates.end() ? rates.at(currency) : QUALITY_ONE; }; // swap out reverse sin = sout; for (auto it = vp.rbegin(); it != vp.rend(); ++it) { - sout = mulratio(sin, trate(sin), QUALITY_ONE, true); + sout = mulratio(sin, transferRate(sin), QUALITY_ONE, true); auto const [amts, amm] = *it; // assume no amm limit if (amm) @@ -241,7 +221,7 @@ class AMMCalc_test : public beast::unit_test::suite for (int i = limitingStep + 1; i < vp.size(); ++i) { auto const [amts, amm] = vp[i]; - sin = mulratio(sin, QUALITY_ONE, trate(sin), false); + sin = mulratio(sin, QUALITY_ONE, transferRate(sin), false); if (amm) { sout = swapAssetIn(amts, sin, fee); @@ -254,8 +234,7 @@ class AMMCalc_test : public beast::unit_test::suite sin = sout; resultOut = sout; } - std::cout << "in: " << toString(resultIn) - << " out: " << toString(resultOut) << std::endl; + std::cout << "in: " << toString(resultIn) << " out: " << toString(resultOut) << std::endl; } void @@ -264,26 +243,22 @@ class AMMCalc_test : public beast::unit_test::suite auto const vp = std::get(args); STAmount sin = std::get(args); auto const fee = std::get(args); - auto const rates = std::get(args); + auto const rates = std::get(args); STAmount resultIn = sin; STAmount resultOut{}; STAmount sout{}; int limitingStep = 0; STAmount limitStepIn{}; - auto trate = [&](auto const& amt) { + auto transferRate = [&](auto const& amt) { auto const currency = to_string(amt.issue().currency); - return rates.find(currency) != rates.end() ? rates.at(currency) - : QUALITY_ONE; + return rates.find(currency) != rates.end() ? rates.at(currency) : QUALITY_ONE; }; // Swap in forward for (auto it = vp.begin(); it != vp.end(); ++it) { auto const [amts, amm] = *it; - sin = mulratio( - sin, - QUALITY_ONE, - trate(sin), - false); // out of the next step + sin = mulratio(sin, QUALITY_ONE, transferRate(sin), + false); // out of the next step // assume no amm limit if (amm) { @@ -308,7 +283,7 @@ class AMMCalc_test : public beast::unit_test::suite // swap out if limiting step for (int i = limitingStep - 1; i >= 0; --i) { - sout = mulratio(sin, trate(sin), QUALITY_ONE, false); + sout = mulratio(sin, transferRate(sin), QUALITY_ONE, false); auto const [amts, amm] = vp[i]; if (amm) { @@ -321,9 +296,8 @@ class AMMCalc_test : public beast::unit_test::suite } resultIn = sin; } - resultOut = mulratio(resultOut, QUALITY_ONE, trate(resultOut), true); - std::cout << "in: " << toString(resultIn) - << " out: " << toString(resultOut) << std::endl; + resultOut = mulratio(resultOut, QUALITY_ONE, transferRate(resultOut), true); + std::cout << "in: " << toString(resultIn) << " out: " << toString(resultOut) << std::endl; } void @@ -397,11 +371,7 @@ class AMMCalc_test : public beast::unit_test::suite { Account const amm("amm"); auto const LPT = amm["LPT"]; - std::cout - << to_string( - ammLPTokens(pool->first.in, pool->first.out, LPT) - .iou()) - << std::endl; + std::cout << to_string(ammLPTokens(pool->first.in, pool->first.out, LPT).iou()) << std::endl; return true; } } @@ -428,17 +398,11 @@ class AMMCalc_test : public beast::unit_test::suite env.current()->rules(), beast::Journal(beast::Journal::getNullSink())); ammOffer) - std::cout - << "amm offer: " << toString(ammOffer->in) - << " " << toString(ammOffer->out) - << "\nnew pool: " - << toString(pool->first.in + ammOffer->in) - << " " - << toString(pool->first.out - ammOffer->out) - << std::endl; + std::cout << "amm offer: " << toString(ammOffer->in) << " " << toString(ammOffer->out) + << "\nnew pool: " << toString(pool->first.in + ammOffer->in) << " " + << toString(pool->first.out - ammOffer->out) << std::endl; else - std::cout << "can't change the pool's SP quality" - << std::endl; + std::cout << "can't change the pool's SP quality" << std::endl; return true; } } @@ -458,7 +422,7 @@ class AMMCalc_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp index 707113fe32..65cf7f0a60 100644 --- a/src/test/app/AMMClawback_test.cpp +++ b/src/test/app/AMMClawback_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -23,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class AMMClawback_test : public beast::unit_test::suite { @@ -53,9 +36,7 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, XRP(100), USD(100)); env.close(); - env(amm::ammClawback( - gw, Account("unknown"), USD, XRP, std::nullopt), - ter(terNO_ACCOUNT)); + env(amm::ammClawback(gw, Account("unknown"), USD, XRP, std::nullopt), ter(terNO_ACCOUNT)); } // Test if asset pair provided does not exist. This should @@ -87,8 +68,7 @@ class AMMClawback_test : public beast::unit_test::suite // The AMM account does not exist at all now. // It should return terNO_AMM error. - env(amm::ammClawback(gw, alice, USD, gw["EUR"], std::nullopt), - ter(terNO_AMM)); + env(amm::ammClawback(gw, alice, USD, gw["EUR"], std::nullopt), ter(terNO_AMM)); } // Test if the issuer field and holder field is the same. This should @@ -114,12 +94,10 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); // Issuer can not clawback from himself. - env(amm::ammClawback(gw, gw, USD, XRP, std::nullopt), - ter(temMALFORMED)); + env(amm::ammClawback(gw, gw, USD, XRP, std::nullopt), ter(temMALFORMED)); // Holder can not clawback from himself. - env(amm::ammClawback(alice, alice, USD, XRP, std::nullopt), - ter(temMALFORMED)); + env(amm::ammClawback(alice, alice, USD, XRP, std::nullopt), ter(temMALFORMED)); } // Test if the Asset field matches the Account field. @@ -145,12 +123,7 @@ class AMMClawback_test : public beast::unit_test::suite // The Asset's issuer field is alice, while the Account field is gw. // This should return temMALFORMED because they do not match. - env(amm::ammClawback( - gw, - alice, - Issue{gw["USD"].currency, alice.id()}, - XRP, - std::nullopt), + env(amm::ammClawback(gw, alice, Issue{gw["USD"].currency, alice.id()}, XRP, std::nullopt), ter(temMALFORMED)); } @@ -178,12 +151,7 @@ class AMMClawback_test : public beast::unit_test::suite // The Asset's issuer subfield is gw account and Amount's issuer // subfield is alice account. Return temBAD_AMOUNT because // they do not match. - env(amm::ammClawback( - gw, - alice, - USD, - XRP, - STAmount{Issue{gw["USD"].currency, alice.id()}, 1}), + env(amm::ammClawback(gw, alice, USD, XRP, STAmount{Issue{gw["USD"].currency, alice.id()}, 1}), ter(temBAD_AMOUNT)); } @@ -209,21 +177,11 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); // Return temBAD_AMOUNT if the Amount value is less than 0. - env(amm::ammClawback( - gw, - alice, - USD, - XRP, - STAmount{Issue{gw["USD"].currency, gw.id()}, -1}), + env(amm::ammClawback(gw, alice, USD, XRP, STAmount{Issue{gw["USD"].currency, gw.id()}, -1}), ter(temBAD_AMOUNT)); // Return temBAD_AMOUNT if the Amount value is 0. - env(amm::ammClawback( - gw, - alice, - USD, - XRP, - STAmount{Issue{gw["USD"].currency, gw.id()}, 0}), + env(amm::ammClawback(gw, alice, USD, XRP, STAmount{Issue{gw["USD"].currency, gw.id()}, 0}), ter(temBAD_AMOUNT)); } @@ -249,8 +207,7 @@ class AMMClawback_test : public beast::unit_test::suite // If asfAllowTrustLineClawback is not set, the issuer is not // allowed to send the AMMClawback transaction. - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - ter(tecNO_PERMISSION)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), ter(tecNO_PERMISSION)); } // Test invalid flag. @@ -275,9 +232,7 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); // Return temINVALID_FLAG when providing invalid flag. - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - txflags(tfTwoAssetIfEmpty), - ter(temINVALID_FLAG)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), txflags(tfTwoAssetIfEmpty), ter(temINVALID_FLAG)); } // Test if tfClawTwoAssets is set when the two assets in the AMM pool @@ -307,9 +262,7 @@ class AMMClawback_test : public beast::unit_test::suite // but the issuer only issues USD in the pool. The issuer is not // allowed to set tfClawTwoAssets flag if he did not issue both // assets in the pool. - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - txflags(tfClawTwoAssets), - ter(temINVALID_FLAG)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), txflags(tfClawTwoAssets), ter(temINVALID_FLAG)); } // Test clawing back XRP is being prohibited. @@ -336,8 +289,7 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); // Clawback XRP is prohibited. - env(amm::ammClawback(gw, alice, XRP, USD, std::nullopt), - ter(temMALFORMED)); + env(amm::ammClawback(gw, alice, XRP, USD, std::nullopt), ter(temMALFORMED)); } } @@ -368,8 +320,7 @@ class AMMClawback_test : public beast::unit_test::suite // When featureAMMClawback is not enabled, AMMClawback is disabled. // Because when featureAMMClawback is disabled, we can not create // amm account, call amm::ammClawback directly for testing purpose. - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - ter(temDISABLED)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), ter(temDISABLED)); } } @@ -414,12 +365,10 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); // gw clawback 1000 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice's initial balance for USD is 3000 USD. Alice deposited 2000 @@ -436,17 +385,14 @@ class AMMClawback_test : public beast::unit_test::suite // 1000 USD and 500 EUR was withdrawn from the AMM pool, so the // current balance is 1000 USD and 500 EUR. - BEAST_EXPECT(amm.expectBalances( - USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectBalances(USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); // Alice has half of its initial lptokens Left. - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); // gw clawback another 1000 USD from the AMM pool. The AMM pool will // be empty and get deleted. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice should still has 1000 USD because gw clawed back from the @@ -489,14 +435,12 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, XRP(1000), USD(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(2000), XRP(1000), IOUAmount{1414213562373095, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2000), XRP(1000), IOUAmount{1414213562373095, -9})); auto aliceXrpBalance = env.balance(alice, XRP); // gw clawback 1000 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice's initial balance for USD is 3000 USD. Alice deposited 2000 @@ -506,23 +450,19 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(alice, USD(1000))); // Alice will get 500 XRP back. - BEAST_EXPECT( - expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); aliceXrpBalance = env.balance(alice, XRP); // 1000 USD and 500 XRP was withdrawn from the AMM pool, so the // current balance is 1000 USD and 500 XRP. - BEAST_EXPECT(amm.expectBalances( - USD(1000), XRP(500), IOUAmount{7071067811865475, -10})); + BEAST_EXPECT(amm.expectBalances(USD(1000), XRP(500), IOUAmount{7071067811865475, -10})); // Alice has half of its initial lptokens Left. - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{7071067811865475, -10})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865475, -10})); // gw clawback another 1000 USD from the AMM pool. The AMM pool will // be empty and get deleted. - env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice should still has 1000 USD because gw clawed back from the @@ -531,8 +471,7 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(alice, USD(1000))); // Alice will get another 500 XRP back. - BEAST_EXPECT( - expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); // amm is automatically deleted. BEAST_EXPECT(!amm.ammExists()); @@ -583,15 +522,12 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); // gw clawback 1000 USD from the AMM pool - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice's initial balance for USD is 6000 USD. Alice deposited 4000 @@ -607,23 +543,18 @@ class AMMClawback_test : public beast::unit_test::suite // 1000 USD and 1250 EUR was withdrawn from the AMM pool, so the // current balance is 3000 USD and 3750 EUR. if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(3000), EUR(3750), IOUAmount{3354101966249685, -12})); + BEAST_EXPECT(amm.expectBalances(USD(3000), EUR(3750), IOUAmount{3354101966249685, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(3000), EUR(3750), IOUAmount{3354101966249684, -12})); + BEAST_EXPECT(amm.expectBalances(USD(3000), EUR(3750), IOUAmount{3354101966249684, -12})); // Alice has 3/4 of its initial lptokens Left. if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{3354101966249685, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{3354101966249685, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{3354101966249684, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{3354101966249684, -12})); // gw clawback another 500 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, EUR, USD(500)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(500)), ter(tesSUCCESS)); env.close(); // Alice should still has 2000 USD because gw clawed back from the @@ -636,13 +567,10 @@ class AMMClawback_test : public beast::unit_test::suite STAmount{EUR, UINT64_C(3125000000000001), -12}, IOUAmount{2795084971874738, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(2500), EUR(3125), IOUAmount{2795084971874737, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2500), EUR(3125), IOUAmount{2795084971874737, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(alice, EUR) == - STAmount(EUR, UINT64_C(2874999999999999), -12)); + BEAST_EXPECT(env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2874999999999999), -12)); else BEAST_EXPECT(env.balance(alice, EUR) == EUR(2875)); @@ -659,8 +587,7 @@ class AMMClawback_test : public beast::unit_test::suite STAmount{EUR, UINT64_C(3123750000000002), -12}, IOUAmount{2793966937885989, -12})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2499000000000001), -12}, @@ -668,28 +595,21 @@ class AMMClawback_test : public beast::unit_test::suite IOUAmount{2793966937885988, -12})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - env.balance(alice, EUR) == - STAmount(EUR, UINT64_C(2876'249999999998), -12)); + BEAST_EXPECT(env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2876'249999999998), -12)); else if (!features[fixAMMClawbackRounding]) BEAST_EXPECT(env.balance(alice, EUR) == EUR(2876.25)); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(alice, EUR) == - STAmount(EUR, UINT64_C(2876'249999999999), -12)); + BEAST_EXPECT(env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2876'249999999999), -12)); // gw clawback 4000 USD, exceeding the current balance. We // will clawback all. - env(amm::ammClawback(gw, alice, USD, EUR, USD(4000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(4000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(2000))); // All alice's EUR in the pool goes back to alice. - BEAST_EXPECT( - env.balance(alice, EUR) == - STAmount(EUR, UINT64_C(6000000000000000), -12)); + BEAST_EXPECT(env.balance(alice, EUR) == STAmount(EUR, UINT64_C(6000000000000000), -12)); // amm is automatically deleted. BEAST_EXPECT(!amm.ammExists()); @@ -737,48 +657,38 @@ class AMMClawback_test : public beast::unit_test::suite // gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD. AMM amm(env, gw, XRP(2000), USD(1000), ter(tesSUCCESS)); - BEAST_EXPECT(amm.expectBalances( - USD(1000), XRP(2000), IOUAmount{1414213562373095, -9})); + BEAST_EXPECT(amm.expectBalances(USD(1000), XRP(2000), IOUAmount{1414213562373095, -9})); amm.deposit(alice, USD(1000), XRP(2000)); - BEAST_EXPECT(amm.expectBalances( - USD(2000), XRP(4000), IOUAmount{2828427124746190, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2000), XRP(4000), IOUAmount{2828427124746190, -9})); amm.deposit(bob, USD(1000), XRP(2000)); - BEAST_EXPECT(amm.expectBalances( - USD(3000), XRP(6000), IOUAmount{4242640687119285, -9})); + BEAST_EXPECT(amm.expectBalances(USD(3000), XRP(6000), IOUAmount{4242640687119285, -9})); env.close(); // gw2 creates AMM pool of XRP/EUR, alice and bob deposit XRP/EUR. AMM amm2(env, gw2, XRP(3000), EUR(1000), ter(tesSUCCESS)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm2.expectBalances( - EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); else - BEAST_EXPECT(amm2.expectBalances( - EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); amm2.deposit(alice, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); else - BEAST_EXPECT(amm2.expectBalances( - EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); amm2.deposit(bob, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm2.expectBalances( - EUR(3000), XRP(9000), IOUAmount{5196152422706634, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(3000), XRP(9000), IOUAmount{5196152422706634, -9})); else - BEAST_EXPECT(amm2.expectBalances( - EUR(3000), XRP(9000), IOUAmount{5196152422706631, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(3000), XRP(9000), IOUAmount{5196152422706631, -9})); env.close(); auto aliceXrpBalance = env.balance(alice, XRP); auto bobXrpBalance = env.balance(bob, XRP); // gw clawback 500 USD from alice in amm - env(amm::ammClawback(gw, alice, USD, XRP, USD(500)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(500)), ter(tesSUCCESS)); env.close(); // Alice's initial balance for USD is 6000 USD. Alice deposited 1000 @@ -791,37 +701,26 @@ class AMMClawback_test : public beast::unit_test::suite // Alice gets 1000 XRP back. if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000) - XRPAmount(1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000) - XRPAmount(1))); else - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); aliceXrpBalance = env.balance(alice, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(2500), XRP(5000), IOUAmount{3535533905932738, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2500), XRP(5000), IOUAmount{3535533905932738, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(2500), XRP(5000), IOUAmount{3535533905932737, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2500), XRP(5000), IOUAmount{3535533905932737, -9})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(2500), - XRPAmount(5000000001), - IOUAmount{3'535'533'905932738, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2500), XRPAmount(5000000001), IOUAmount{3'535'533'905932738, -9})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{7071067811865480, -10})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{7071067811865474, -10})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9})); // gw clawback 10 USD from bob in amm. env(amm::ammClawback(gw, bob, USD, XRP, USD(10)), ter(tesSUCCESS)); @@ -831,18 +730,14 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(bob, USD(4000))); // Bob gets 20 XRP back. - BEAST_EXPECT( - expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(20))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(20))); bobXrpBalance = env.balance(bob, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - STAmount{USD, UINT64_C(2490000000000001), -12}, - XRP(4980), - IOUAmount{3521391770309008, -9})); + STAmount{USD, UINT64_C(2490000000000001), -12}, XRP(4980), IOUAmount{3521391770309008, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9})); + BEAST_EXPECT(amm.expectBalances(USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2490000000000001), -12}, @@ -850,74 +745,54 @@ class AMMClawback_test : public beast::unit_test::suite IOUAmount{3521391'770309008, -9})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{7071067811865480, -10})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{7071067811865474, -10})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); // gw2 clawback 200 EUR from amm2. - env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, EUR(4000))); env.require(balance(bob, EUR(3000))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(600))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600))); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(600))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600))); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(600) - XRPAmount{1})); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600) - XRPAmount{1})); aliceXrpBalance = env.balance(alice, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2800), - XRPAmount(8400000001), - IOUAmount{4849742261192856, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2800), XRPAmount(8400000001), IOUAmount{4849742261192856, -9})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm2.expectLPTokens( - alice, IOUAmount{1385640646055103, -9})); + BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount{1385640646055103, -9})); else - BEAST_EXPECT(amm2.expectLPTokens( - alice, IOUAmount{1385640646055102, -9})); + BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount{1385640646055102, -9})); if (!features[fixAMMv1_3]) - BEAST_EXPECT( - amm2.expectLPTokens(bob, IOUAmount{1732050807568878, -9})); + BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount{1732050807568878, -9})); else - BEAST_EXPECT( - amm2.expectLPTokens(bob, IOUAmount{1732050807568877, -9})); + BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount{1732050807568877, -9})); // gw claw back 1000 USD from alice in amm, which exceeds alice's // balance. This will clawback all the remaining LP tokens of alice // (corresponding 500 USD / 1000 XRP). - env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(5000))); @@ -925,37 +800,26 @@ class AMMClawback_test : public beast::unit_test::suite // Alice gets 1000 XRP back. if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000) - XRPAmount{1})); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000) - XRPAmount{1})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(1000))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); aliceXrpBalance = env.balance(alice, XRP); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - STAmount{USD, UINT64_C(1990000000000001), -12}, - XRP(3980), - IOUAmount{2814284989122460, -9})); + STAmount{USD, UINT64_C(1990000000000001), -12}, XRP(3980), IOUAmount{2814284989122460, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(1'990), - XRPAmount{3'980'000'001}, - IOUAmount{2814284989122459, -9})); + BEAST_EXPECT(amm.expectBalances(USD(1'990), XRPAmount{3'980'000'001}, IOUAmount{2814284989122459, -9})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(1990000000000001), -12}, @@ -965,8 +829,7 @@ class AMMClawback_test : public beast::unit_test::suite // gw clawback 1000 USD from bob in amm, which also exceeds bob's // balance in amm. All bob's lptoken in amm will be consumed, which // corresponds to 990 USD / 1980 XRP - env(amm::ammClawback(gw, bob, USD, XRP, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, USD, XRP, USD(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(5000))); @@ -974,8 +837,7 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance)); - BEAST_EXPECT( - expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(1980))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(1980))); bobXrpBalance = env.balance(bob, XRP); // Now neither alice nor bob has any lptoken in amm. @@ -985,8 +847,7 @@ class AMMClawback_test : public beast::unit_test::suite // gw2 claw back 1000 EUR from alice in amm2, which exceeds alice's // balance. All alice's lptokens will be consumed, which corresponds // to 800EUR / 2400 XRP. - env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, EUR(4000))); @@ -994,8 +855,7 @@ class AMMClawback_test : public beast::unit_test::suite // Alice gets another 2400 XRP back, bob's XRP balance remains the // same. - BEAST_EXPECT( - expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(2400))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(2400))); BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance)); aliceXrpBalance = env.balance(alice, XRP); @@ -1004,22 +864,16 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(2000), - XRPAmount(6000000001), - IOUAmount{3464101615137754, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(2000), XRPAmount(6000000001), IOUAmount{3464101615137754, -9})); // gw2 claw back 2000 EUR from bob in amm2, which exceeds bob's // balance. All bob's lptokens will be consumed, which corresponds // to 1000EUR / 3000 XRP. - env(amm::ammClawback(gw2, bob, EUR, XRP, EUR(2000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw2, bob, EUR, XRP, EUR(2000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, EUR(4000))); @@ -1029,8 +883,7 @@ class AMMClawback_test : public beast::unit_test::suite // same. BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance)); - BEAST_EXPECT( - expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(3000))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(3000))); bobXrpBalance = env.balance(bob, XRP); // Neither alice nor bob has any lptoken in amm2 @@ -1038,16 +891,11 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm2.expectBalances( - EUR(1000), - XRPAmount(3000000001), - IOUAmount{1732050807568877, -9})); + BEAST_EXPECT(amm2.expectBalances(EUR(1000), XRPAmount(3000000001), IOUAmount{1732050807568877, -9})); } } @@ -1106,44 +954,32 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); amm.deposit(bob, USD(2000), EUR(2500)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(6000), EUR(7500), IOUAmount{6708203932499370, -12})); + BEAST_EXPECT(amm.expectBalances(USD(6000), EUR(7500), IOUAmount{6708203932499370, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(6000), EUR(7500), IOUAmount{6708203932499368, -12})); + BEAST_EXPECT(amm.expectBalances(USD(6000), EUR(7500), IOUAmount{6708203932499368, -12})); amm.deposit(carol, USD(1000), EUR(1250)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(7000), EUR(8750), IOUAmount{7826237921249265, -12})); + BEAST_EXPECT(amm.expectBalances(USD(7000), EUR(8750), IOUAmount{7826237921249265, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(7000), EUR(8750), IOUAmount{7826237921249262, -12})); + BEAST_EXPECT(amm.expectBalances(USD(7000), EUR(8750), IOUAmount{7826237921249262, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999579, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{2236067977499790, -12})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2236067977499790, -12})); else - BEAST_EXPECT( - amm.expectLPTokens(bob, IOUAmount{2236067977499789, -12})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2236067977499789, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - carol, IOUAmount{1118033988749895, -12})); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - carol, IOUAmount{1118033988749894, -12})); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12})); env.require(balance(alice, USD(2000))); env.require(balance(alice, EUR(1000))); @@ -1153,8 +989,7 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(carol, EUR(2750))); // gw clawback all the bob's USD in amm. (2000 USD / 2500 EUR) - env(amm::ammClawback(gw, bob, USD, EUR, std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, USD, EUR, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) @@ -1169,40 +1004,29 @@ class AMMClawback_test : public beast::unit_test::suite IOUAmount{5590169943749473, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999579, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - carol, IOUAmount{1118033988749895, -12})); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - carol, IOUAmount{1118033988749894, -12})); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12})); // Bob will get 2500 EUR back. env.require(balance(alice, USD(2000))); env.require(balance(alice, EUR(1000))); - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(3000000000000000), -12)); + BEAST_EXPECT(env.balance(bob, USD) == STAmount(USD, UINT64_C(3000000000000000), -12)); if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(bob, EUR) == - STAmount(EUR, UINT64_C(5000000000000001), -12)); + BEAST_EXPECT(env.balance(bob, EUR) == STAmount(EUR, UINT64_C(5000000000000001), -12)); else - BEAST_EXPECT( - env.balance(bob, EUR) == - STAmount(EUR, UINT64_C(4999999999999999), -12)); + BEAST_EXPECT(env.balance(bob, EUR) == STAmount(EUR, UINT64_C(4999999999999999), -12)); env.require(balance(carol, USD(3000))); env.require(balance(carol, EUR(2750))); // gw2 clawback all carol's EUR in amm. (1000 USD / 1250 EUR) - env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) BEAST_EXPECT(amm.expectBalances( @@ -1216,17 +1040,14 @@ class AMMClawback_test : public beast::unit_test::suite IOUAmount{4472135954999579, -12})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); else - BEAST_EXPECT(amm.expectLPTokens( - alice, IOUAmount{4472135954999579, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(0))); // gw2 clawback all alice's EUR in amm. (4000 USD / 5000 EUR) - env(amm::ammClawback(gw2, alice, EUR, USD, std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw2, alice, EUR, USD, std::nullopt), ter(tesSUCCESS)); env.close(); env.require(balance(carol, EUR(2750))); @@ -1260,64 +1081,45 @@ class AMMClawback_test : public beast::unit_test::suite // gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD. AMM amm(env, gw, XRP(2000), USD(10000), ter(tesSUCCESS)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + BEAST_EXPECT(amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); else - BEAST_EXPECT(amm.expectBalances( - USD(10000), XRP(2000), IOUAmount{4472135954999579, -9})); + BEAST_EXPECT(amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999579, -9})); amm.deposit(alice, USD(1000), XRP(200)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(11000), XRP(2200), IOUAmount{4919349550499538, -9})); + BEAST_EXPECT(amm.expectBalances(USD(11000), XRP(2200), IOUAmount{4919349550499538, -9})); else - BEAST_EXPECT(amm.expectBalances( - USD(11000), XRP(2200), IOUAmount{4919349550499536, -9})); + BEAST_EXPECT(amm.expectBalances(USD(11000), XRP(2200), IOUAmount{4919349550499536, -9})); amm.deposit(bob, USD(2000), XRP(400)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(13000), XRP(2600), IOUAmount{5813776741499453, -9})); + BEAST_EXPECT(amm.expectBalances(USD(13000), XRP(2600), IOUAmount{5813776741499453, -9})); else - BEAST_EXPECT(amm.expectBalances( - USD(13000), XRP(2600), IOUAmount{5813776741499451, -9})); + BEAST_EXPECT(amm.expectBalances(USD(13000), XRP(2600), IOUAmount{5813776741499451, -9})); env.close(); auto aliceXrpBalance = env.balance(alice, XRP); auto bobXrpBalance = env.balance(bob, XRP); // gw clawback all alice's USD in amm. (1000 USD / 200 XRP) - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(12000), XRP(2400), IOUAmount{5366563145999495, -9})); + BEAST_EXPECT(amm.expectBalances(USD(12000), XRP(2400), IOUAmount{5366563145999495, -9})); else - BEAST_EXPECT(amm.expectBalances( - USD(12000), - XRPAmount(2400000001), - IOUAmount{5366563145999494, -9})); + BEAST_EXPECT(amm.expectBalances(USD(12000), XRPAmount(2400000001), IOUAmount{5366563145999494, -9})); if (!features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(200))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(200))); else - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(200) - XRPAmount{1})); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(200) - XRPAmount{1})); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); // gw clawback all bob's USD in amm. (2000 USD / 400 XRP) - env(amm::ammClawback(gw, bob, USD, XRP, std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, USD, XRP, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + BEAST_EXPECT(amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); else - BEAST_EXPECT(amm.expectBalances( - USD(10000), - XRPAmount(2000000001), - IOUAmount{4472135954999579, -9})); - BEAST_EXPECT( - expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(400))); + BEAST_EXPECT(amm.expectBalances(USD(10000), XRPAmount(2000000001), IOUAmount{4472135954999579, -9})); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(400))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); } @@ -1369,19 +1171,16 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000))); amm.deposit(bob, USD(4000), EUR(1000)); - BEAST_EXPECT( - amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); if (!features[fixAMMv1_3]) amm.deposit(carol, USD(2000), EUR(500)); else amm.deposit(carol, USD(2000.25), EUR(500)); - BEAST_EXPECT( - amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); + BEAST_EXPECT(amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); // gw clawback 1000 USD from carol. env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); + BEAST_EXPECT(amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(2000))); @@ -1393,21 +1192,16 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); // 250 EUR goes back to carol. BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback 1000 USD from bob with tfClawTwoAssets flag. // then the corresponding EUR will also be clawed back // by gw. - env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), - txflags(tfClawTwoAssets), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), txflags(tfClawTwoAssets), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); @@ -1420,15 +1214,11 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback all USD from alice and set tfClawTwoAssets. - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), - txflags(tfClawTwoAssets), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), txflags(tfClawTwoAssets), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000))); @@ -1442,9 +1232,7 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); } @@ -1490,64 +1278,37 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, gw["USD"](1000), gw2["USD"](1500), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - gw["USD"](1000), - gw2["USD"](1500), - IOUAmount{1224744871391589, -12})); + BEAST_EXPECT(amm.expectBalances(gw["USD"](1000), gw2["USD"](1500), IOUAmount{1224744871391589, -12})); amm.deposit(bob, gw["USD"](2000), gw2["USD"](3000)); - BEAST_EXPECT(amm.expectBalances( - gw["USD"](3000), - gw2["USD"](4500), - IOUAmount{3674234614174767, -12})); + BEAST_EXPECT(amm.expectBalances(gw["USD"](3000), gw2["USD"](4500), IOUAmount{3674234614174767, -12})); // Issuer does not match with asset. - env(amm::ammClawback( - gw, - alice, - gw2["USD"], - gw["USD"], - STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), + env(amm::ammClawback(gw, alice, gw2["USD"], gw["USD"], STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), ter(temMALFORMED)); // gw2 clawback 500 gw2[USD] from alice. - env(amm::ammClawback( - gw2, - alice, - gw2["USD"], - gw["USD"], - STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), + env(amm::ammClawback(gw2, alice, gw2["USD"], gw["USD"], STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(amm.expectBalances( - STAmount{gw["USD"], UINT64_C(2666666666666667), -12}, - gw2["USD"](4000), - IOUAmount{3265986323710904, -12})); + STAmount{gw["USD"], UINT64_C(2666666666666667), -12}, gw2["USD"](4000), IOUAmount{3265986323710904, -12})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2449489742783178, -12})); - BEAST_EXPECT( - env.balance(alice, gw["USD"]) == - STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); + BEAST_EXPECT(env.balance(alice, gw["USD"]) == STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); BEAST_EXPECT(env.balance(alice, gw2["USD"]) == gw2["USD"](4500)); BEAST_EXPECT(env.balance(bob, gw["USD"]) == gw["USD"](5000)); BEAST_EXPECT(env.balance(bob, gw2["USD"]) == gw2["USD"](2000)); // gw clawback all gw["USD"] from bob. - env(amm::ammClawback(gw, bob, gw["USD"], gw2["USD"], std::nullopt), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, gw["USD"], gw2["USD"], std::nullopt), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(amm.expectBalances( - STAmount{gw["USD"], UINT64_C(6666666666666670), -13}, - gw2["USD"](1000), - IOUAmount{8164965809277260, -13})); + STAmount{gw["USD"], UINT64_C(6666666666666670), -13}, gw2["USD"](1000), IOUAmount{8164965809277260, -13})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); - BEAST_EXPECT( - env.balance(alice, gw["USD"]) == - STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); + BEAST_EXPECT(env.balance(alice, gw["USD"]) == STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); BEAST_EXPECT(env.balance(alice, gw2["USD"]) == gw2["USD"](4500)); BEAST_EXPECT(env.balance(bob, gw["USD"]) == gw["USD"](5000)); // Bob gets 3000 gw2["USD"] back and now his balance is 5000. @@ -1594,41 +1355,32 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, gw, USD(1000), EUR(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(1000), EUR(2000), IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectBalances(USD(1000), EUR(2000), IOUAmount{1414213562373095, -12})); amm.deposit(gw2, USD(2000), EUR(4000)); - BEAST_EXPECT(amm.expectBalances( - USD(3000), EUR(6000), IOUAmount{4242640687119285, -12})); + BEAST_EXPECT(amm.expectBalances(USD(3000), EUR(6000), IOUAmount{4242640687119285, -12})); amm.deposit(alice, USD(3000), EUR(6000)); - BEAST_EXPECT(amm.expectBalances( - USD(6000), EUR(12000), IOUAmount{8485281374238570, -12})); + BEAST_EXPECT(amm.expectBalances(USD(6000), EUR(12000), IOUAmount{8485281374238570, -12})); BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{2828427124746190, -12})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); // gw claws back 1000 USD from gw2. env(amm::ammClawback(gw, gw2, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); + BEAST_EXPECT(amm.expectBalances(USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); else - BEAST_EXPECT(amm.expectBalances( - USD(5000), EUR(10000), IOUAmount{7071067811865474, -12})); + BEAST_EXPECT(amm.expectBalances(USD(5000), EUR(10000), IOUAmount{7071067811865474, -12})); BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); else - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); @@ -1640,37 +1392,26 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - USD(4500), - STAmount(EUR, UINT64_C(9000000000000001), -12), - IOUAmount{6363961030678928, -12})); + USD(4500), STAmount(EUR, UINT64_C(9000000000000001), -12), IOUAmount{6363961030678928, -12})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(4500), EUR(9000), IOUAmount{6363961030678928, -12})); + BEAST_EXPECT(amm.expectBalances(USD(4500), EUR(9000), IOUAmount{6363961030678928, -12})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - USD(4500), - STAmount(EUR, UINT64_C(9000000000000001), -12), - IOUAmount{6363961030678927, -12})); + USD(4500), STAmount(EUR, UINT64_C(9000000000000001), -12), IOUAmount{6363961030678927, -12})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); else - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); @@ -1682,36 +1423,25 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - USD(2500), - STAmount(EUR, UINT64_C(5000000000000001), -12), - IOUAmount{3535533905932738, -12})); + USD(2500), STAmount(EUR, UINT64_C(5000000000000001), -12), IOUAmount{3535533905932738, -12})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT(amm.expectBalances( - USD(2500), EUR(5000), IOUAmount{3535533905932738, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2500), EUR(5000), IOUAmount{3535533905932738, -12})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) BEAST_EXPECT(amm.expectBalances( - USD(2500), - STAmount(EUR, UINT64_C(5000000000000001), -12), - IOUAmount{3535533905932737, -12})); + USD(2500), STAmount(EUR, UINT64_C(5000000000000001), -12), IOUAmount{3535533905932737, -12})); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); else if (!features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); else - BEAST_EXPECT( - amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12})); BEAST_EXPECT(env.balance(alice, USD) == USD(4000)); BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); @@ -1747,8 +1477,7 @@ class AMMClawback_test : public beast::unit_test::suite // Alice did not deposit in the amm pool. So AMMClawback from Alice // will fail. - env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), - ter(tecAMM_BALANCE)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), ter(tecAMM_BALANCE)); } void @@ -1789,31 +1518,26 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); // freeze trustline env(trust(gw, alice["USD"](0), tfSetFreeze)); env.close(); // gw clawback 1000 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(1000))); env.require(balance(alice, EUR(2500))); - BEAST_EXPECT(amm.expectBalances( - USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectBalances(USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); // Alice has half of its initial lptokens Left. - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); // gw clawback another 1000 USD from the AMM pool. The AMM pool will // be empty and get deleted. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); // Alice should still has 1000 USD because gw clawed back from the @@ -1857,8 +1581,7 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); // freeze trustlines env(trust(gw, alice["USD"](0), tfSetFreeze)); @@ -1866,16 +1589,13 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); // gw clawback 1000 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(1000))); env.require(balance(alice, EUR(2500))); - BEAST_EXPECT(amm.expectBalances( - USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectBalances(USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); } // test gw global freeze. @@ -1910,24 +1630,20 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectBalances(USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); // global freeze env(fset(gw, asfGlobalFreeze)); env.close(); // gw clawback 1000 USD from the AMM pool. - env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); env.require(balance(alice, USD(1000))); env.require(balance(alice, EUR(2500))); - BEAST_EXPECT(amm.expectBalances( - USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); - BEAST_EXPECT( - amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectBalances(USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); } // Test both assets are issued by the same issuer. And issuer sets @@ -1967,28 +1683,23 @@ class AMMClawback_test : public beast::unit_test::suite AMM amm(env, alice, EUR(2000), USD(8000), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000))); + BEAST_EXPECT(amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000))); amm.deposit(bob, USD(4000), EUR(1000)); - BEAST_EXPECT( - amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); if (!features[fixAMMv1_3]) amm.deposit(carol, USD(2000), EUR(500)); else amm.deposit(carol, USD(2000.25), EUR(500)); - BEAST_EXPECT( - amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); + BEAST_EXPECT(amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); // global freeze env(fset(gw, asfGlobalFreeze)); env.close(); // gw clawback 1000 USD from carol. - env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); + BEAST_EXPECT(amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(2000))); @@ -2000,21 +1711,16 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); // 250 EUR goes back to carol. BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback 1000 USD from bob with tfClawTwoAssets flag. // then the corresponding EUR will also be clawed back // by gw. - env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), - txflags(tfClawTwoAssets), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), txflags(tfClawTwoAssets), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); @@ -2027,18 +1733,13 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback all USD from alice and set tfClawTwoAssets. - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), - txflags(tfClawTwoAssets), - ter(tesSUCCESS)); + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), txflags(tfClawTwoAssets), ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000))); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); @@ -2050,9 +1751,7 @@ class AMMClawback_test : public beast::unit_test::suite if (!features[fixAMMv1_3]) BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(5999'999999999999), -12)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); } } @@ -2060,7 +1759,7 @@ class AMMClawback_test : public beast::unit_test::suite void testSingleDepositAndClawback(FeatureBitset features) { - testcase("test single depoit and clawback"); + testcase("test single deposit and clawback"); using namespace jtx; std::string logs; @@ -2093,8 +1792,7 @@ class AMMClawback_test : public beast::unit_test::suite amm.deposit(alice, USD(400)); env.close(); - BEAST_EXPECT(amm.expectBalances( - USD(800), XRP(100), IOUAmount{2828427124746190, -10})); + BEAST_EXPECT(amm.expectBalances(USD(800), XRP(100), IOUAmount{2828427124746190, -10})); auto aliceXrpBalance = env.balance(alice, XRP); @@ -2102,22 +1800,16 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) - BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(5656854249492380), -13), - XRP(70.710678), - IOUAmount(200000))); + BEAST_EXPECT( + amm.expectBalances(STAmount(USD, UINT64_C(5656854249492380), -13), XRP(70.710678), IOUAmount(200000))); else - BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(565'685424949238), -12), - XRP(70.710679), - IOUAmount(200000))); + BEAST_EXPECT( + amm.expectBalances(STAmount(USD, UINT64_C(565'685424949238), -12), XRP(70.710679), IOUAmount(200000))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3]) - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(29.289322))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(29.289322))); else - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, aliceXrpBalance + XRP(29.289321))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(29.289321))); } void @@ -2129,34 +1821,26 @@ class AMMClawback_test : public beast::unit_test::suite using namespace jtx; std::string logs; - auto setupAccounts = - [&](Env& env, Account& gw, Account& alice, Account& bob) { - env.fund(XRP(100000), gw, alice, bob); - env.close(); - env(fset(gw, asfAllowTrustLineClawback)); - env.close(); + auto setupAccounts = [&](Env& env, Account& gw, Account& alice, Account& bob) { + env.fund(XRP(100000), gw, alice, bob); + env.close(); + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); - auto const USD = gw["USD"]; - env.trust(USD(100000), alice); - env(pay(gw, alice, USD(50000))); - env.trust(USD(100000), bob); - env(pay(gw, bob, USD(40000))); - env.close(); + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(50000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(40000))); + env.close(); - return USD; - }; + return USD; + }; auto getLPTokenBalances = - [&](auto& env, - auto const& amm, - auto const& account) -> std::pair { - auto const lpToken = - getAccountLines( - env, account, amm.lptIssue())[jss::lines][0u][jss::balance] - .asString(); - auto const lpTokenBalance = - amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value] - .asString(); + [&](auto& env, auto const& amm, auto const& account) -> std::pair { + auto const lpToken = getAccountLines(env, account, amm.lptIssue())[jss::lines][0u][jss::balance].asString(); + auto const lpTokenBalance = amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value].asString(); return {lpToken, lpTokenBalance}; }; @@ -2172,30 +1856,23 @@ class AMMClawback_test : public beast::unit_test::suite amm.withdraw(alice, IOUAmount{1'876123487565916, -15}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1414.21356237366" && - lpTokenBalance == "1414.213562374"); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); + BEAST_EXPECT(lpToken == "1414.21356237366" && lpTokenBalance == "1414.213562374"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); if (!features[fixAMMClawbackRounding] || !features[fixAMMv1_3]) { - env(amm::ammClawback(gw, alice, USD, XRP, USD(1)), - ter(tecAMM_BALANCE)); + env(amm::ammClawback(gw, alice, USD, XRP, USD(1)), ter(tecAMM_BALANCE)); BEAST_EXPECT(amm.ammExists()); } else { auto const lpBalance = IOUAmount{989, -12}; env(amm::ammClawback(gw, alice, USD, XRP, USD(1))); - BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(7000000000000000), -28), - XRPAmount(1), - lpBalance)); + BEAST_EXPECT( + amm.expectBalances(STAmount(USD, UINT64_C(7000000000000000), -28), XRPAmount(1), lpBalance)); BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); } } @@ -2211,14 +1888,10 @@ class AMMClawback_test : public beast::unit_test::suite amm.deposit(bob, IOUAmount{1'000'000}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1416.08968586066" && - lpTokenBalance == "1416.089685861"); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); + BEAST_EXPECT(lpToken == "1416.08968586066" && lpTokenBalance == "1416.089685861"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); env(amm::ammClawback(gw, alice, USD, XRP, USD(0.5))); @@ -2240,10 +1913,8 @@ class AMMClawback_test : public beast::unit_test::suite else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) { auto const lpBalance = IOUAmount{708'9829046743238, -13}; - BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(5013266196406999), -16), - XRPAmount(1002655), - lpBalance)); + BEAST_EXPECT( + amm.expectBalances(STAmount(USD, UINT64_C(5013266196406999), -16), XRPAmount(1002655), lpBalance)); BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); } } @@ -2260,28 +1931,21 @@ class AMMClawback_test : public beast::unit_test::suite amm.withdraw(alice, IOUAmount{1'876123487565916, -15}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1414.21356237366" && - lpTokenBalance == "1414.213562374"); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); + BEAST_EXPECT(lpToken == "1414.21356237366" && lpTokenBalance == "1414.213562374"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); if (!features[fixAMMClawbackRounding] && !features[fixAMMv1_3]) { - env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), - ter(tecAMM_BALANCE)); + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), ter(tecAMM_BALANCE)); } else if (!features[fixAMMClawbackRounding]) { env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt)); BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(2410000000000000), -28), - XRPAmount(1), - IOUAmount{34, -11})); + STAmount(USD, UINT64_C(2410000000000000), -28), XRPAmount(1), IOUAmount{34, -11})); } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) { @@ -2312,14 +1976,10 @@ class AMMClawback_test : public beast::unit_test::suite amm.withdraw(alice, IOUAmount{1'576123487565916, -15}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1.414213562374011" && - lpTokenBalance == "1.414213562374"); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); + BEAST_EXPECT(lpToken == "1.414213562374011" && lpTokenBalance == "1.414213562374"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) @@ -2329,8 +1989,7 @@ class AMMClawback_test : public beast::unit_test::suite } else { - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), - ter(tecINTERNAL)); + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), ter(tecINTERNAL)); BEAST_EXPECT(amm.ammExists()); } } @@ -2354,27 +2013,20 @@ class AMMClawback_test : public beast::unit_test::suite amm.withdraw(alice, IOUAmount{1'076123487565916, -15}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1.414213562374011" && - lpTokenBalance == "1.414213562374"); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); + BEAST_EXPECT(lpToken == "1.414213562374011" && lpTokenBalance == "1.414213562374"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); if (features[fixAMMClawbackRounding]) { - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), - txflags(tfClawTwoAssets)); + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), txflags(tfClawTwoAssets)); BEAST_EXPECT(!amm.ammExists()); } else { - env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), - txflags(tfClawTwoAssets), - ter(tecINTERNAL)); + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), txflags(tfClawTwoAssets), ter(tecINTERNAL)); BEAST_EXPECT(amm.ammExists()); } } @@ -2398,42 +2050,32 @@ class AMMClawback_test : public beast::unit_test::suite amm.withdraw(alice, IOUAmount{1'076123487565916, -12}); amm.withdrawAll(bob); - auto [lpToken, lpTokenBalance] = - getLPTokenBalances(env, amm, alice); + auto [lpToken, lpTokenBalance] = getLPTokenBalances(env, amm, alice); - BEAST_EXPECT( - lpToken == "1414.213562373101" && - lpTokenBalance == "1414.2135623731"); + BEAST_EXPECT(lpToken == "1414.213562373101" && lpTokenBalance == "1414.2135623731"); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && res.value()); if (!features[fixAMMClawbackRounding] && !features[fixAMMv1_3]) { env(amm::ammClawback(gw, alice, USD, EUR, USD(1))); BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(4), -15), - STAmount(EUR, UINT64_C(8), -9), - IOUAmount{6, -12})); + STAmount(USD, UINT64_C(4), -15), STAmount(EUR, UINT64_C(8), -9), IOUAmount{6, -12})); } else if (!features[fixAMMClawbackRounding]) { // sqrt(amount * amount2) >= LPTokens and exceeds the allowed // tolerance - env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), - ter(tecINVARIANT_FAILED)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), ter(tecINVARIANT_FAILED)); BEAST_EXPECT(amm.ammExists()); } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) { - env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), - txflags(tfClawTwoAssets)); + env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), txflags(tfClawTwoAssets)); auto const lpBalance = IOUAmount{5, -12}; - BEAST_EXPECT(amm.expectBalances( - STAmount(USD, UINT64_C(4), -15), - STAmount(EUR, UINT64_C(8), -9), - lpBalance)); + BEAST_EXPECT( + amm.expectBalances(STAmount(USD, UINT64_C(4), -15), STAmount(EUR, UINT64_C(8), -9), lpBalance)); BEAST_EXPECT(amm.expectLPTokens(alice, lpBalance)); } } @@ -2442,14 +2084,13 @@ class AMMClawback_test : public beast::unit_test::suite void run() override { - FeatureBitset const all = jtx::testable_amendments(); + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + FeatureBitset const all = jtx::testable_amendments() - featureSingleAssetVault - featureLendingProtocol; testInvalidRequest(); testFeatureDisabled(all - featureAMMClawback); - for (auto const& features : - {all - fixAMMv1_3 - fixAMMClawbackRounding, - all - fixAMMClawbackRounding, - all}) + for (auto const& features : {all - fixAMMv1_3 - fixAMMClawbackRounding, all - fixAMMClawbackRounding, all}) { testAMMClawbackSpecificAmount(features); testAMMClawbackExceedBalance(features); @@ -2464,6 +2105,6 @@ class AMMClawback_test : public beast::unit_test::suite } } }; -BEAST_DEFINE_TESTSUITE(AMMClawback, app, ripple); +BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AMMExtended_test.cpp b/src/test/app/AMMExtended_test.cpp index b0e810fce3..4eecb05905 100644 --- a/src/test/app/AMMExtended_test.cpp +++ b/src/test/app/AMMExtended_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { /** @@ -45,6 +26,9 @@ namespace test { */ struct AMMExtended_test : public jtx::AMMTest { + // Use small Number mantissas for the life of this test. + NumberMantissaScaleGuard const sg_{xrpl::MantissaRange::small}; + private: void testRmFundedOffer(FeatureBitset features) @@ -61,14 +45,10 @@ private: // funded and not used for the payment. using namespace jtx; + Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - XRP(10'000), - {USD(200'000), BTC(2'000)}); + fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(200'000), BTC(2'000)}); // Must be two offers at the same quality // "taker gets" must be XRP @@ -86,24 +66,17 @@ private: PathSet paths(Path(XRP, USD), Path(USD)); - env(pay(alice, bob, USD(100)), - json(paths.json()), - sendmax(BTC(1'000)), - txflags(tfPartialPayment)); + env(pay(alice, bob, USD(100)), json(paths.json()), sendmax(BTC(1'000)), txflags(tfPartialPayment)); if (!features[fixAMMv1_1]) { BEAST_EXPECT(ammCarol.expectBalances( - STAmount{BTC, UINT64_C(1'001'000000374812), -12}, - USD(100'000), - ammCarol.tokens())); + STAmount{BTC, UINT64_C(1'001'000000374812), -12}, USD(100'000), ammCarol.tokens())); } else { BEAST_EXPECT(ammCarol.expectBalances( - STAmount{BTC, UINT64_C(1'001'000000374815), -12}, - USD(100'000), - ammCarol.tokens())); + STAmount{BTC, UINT64_C(1'001'000000374815), -12}, USD(100'000), ammCarol.tokens())); } env.require(balance(bob, USD(200'100))); @@ -172,15 +145,10 @@ private: AMM ammDan(env, dan, XRP(10'000), USD1(10'050)); - env(pay(alice, carol, USD2(50)), - path(~USD1, bob), - sendmax(XRP(50)), - txflags(tfNoRippleDirect)); - BEAST_EXPECT(ammDan.expectBalances( - XRP(10'050), USD1(10'000), ammDan.tokens())); + env(pay(alice, carol, USD2(50)), path(~USD1, bob), sendmax(XRP(50)), txflags(tfNoRippleDirect)); + BEAST_EXPECT(ammDan.expectBalances(XRP(10'050), USD1(10'000), ammDan.tokens())); - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, XRP(20'000) - XRP(50) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, XRP(20'000) - XRP(50) - txfee(env, 1))); BEAST_EXPECT(expectHolding(env, bob, USD1(100))); BEAST_EXPECT(expectHolding(env, bob, USD2(0))); BEAST_EXPECT(expectHolding(env, carol, USD2(50))); @@ -202,26 +170,18 @@ private: [&](AMM& ammAlice, Env& env) { // Order that can't be filled TER const killedCode{TER{tecKILLED}}; - env(offer(carol, USD(100), XRP(100)), - txflags(tfFillOrKill), - ter(killedCode)); + env(offer(carol, USD(100), XRP(100)), txflags(tfFillOrKill), ter(killedCode)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // fee = AMM - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRP(30'000) - (txfee(env, 1)))); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(30'000) - (txfee(env, 1)))); BEAST_EXPECT(expectOffers(env, carol, 0)); BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); // Order that can be filled - env(offer(carol, XRP(100), USD(100)), - txflags(tfFillOrKill), - ter(tesSUCCESS)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'100), ammAlice.tokens())); - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRP(30'000) + XRP(100) - txfee(env, 2))); + env(offer(carol, XRP(100), USD(100)), txflags(tfFillOrKill), ter(tesSUCCESS)); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'100), ammAlice.tokens())); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(30'000) + XRP(100) - txfee(env, 2))); BEAST_EXPECT(expectHolding(env, carol, USD(29'900))); BEAST_EXPECT(expectOffers(env, carol, 0)); }, @@ -234,17 +194,13 @@ private: // and add nothing on the books. testAMM( [&](AMM& ammAlice, Env& env) { - env(offer(carol, XRP(200), USD(200)), - txflags(tfImmediateOrCancel), - ter(tesSUCCESS)); + env(offer(carol, XRP(200), USD(200)), txflags(tfImmediateOrCancel), ter(tesSUCCESS)); // AMM generates a synthetic offer of 100USD/100XRP // to match the CLOB offer quality. - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'100), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'100), ammAlice.tokens())); // +AMM - offer * fee - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRP(30'000) + XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(30'000) + XRP(100) - txfee(env, 1))); // AMM BEAST_EXPECT(expectHolding(env, carol, USD(29'900))); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -261,10 +217,8 @@ private: // Carol's offer should stay in the ledger. env(offer(carol, XRP(100), USD(100), tfPassive)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens())); - BEAST_EXPECT(expectOffers( - env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens())); + BEAST_EXPECT(expectOffers(env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}})); }, {{XRP(10'100), USD(10'000)}}, 0, @@ -282,9 +236,7 @@ private: env(offer(carol, XRP(100), USD(100), tfPassive)); env.close(); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'900), - STAmount{USD, UINT64_C(9'082'56880733945), -11}, - ammAlice.tokens())); + XRP(10'900), STAmount{USD, UINT64_C(9'082'56880733945), -11}, ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); BEAST_EXPECT(expectOffers(env, alice, 1)); }, @@ -313,14 +265,10 @@ private: auto const xrpTransferred = XRPAmount{3'061'224'490}; env(offer(bob, USD(1), XRP(4'000))); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(150'000) + xrpTransferred, - USD(49), - IOUAmount{273'861'278752583, -8})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(150'000) + xrpTransferred, USD(49), IOUAmount{273'861'278752583, -8})); BEAST_EXPECT(expectHolding(env, bob, STAmount{USD, 101})); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(300'000) - xrpTransferred - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(300'000) - xrpTransferred - txfee(env, 1))); BEAST_EXPECT(expectOffers(env, bob, 0)); } @@ -343,17 +291,14 @@ private: AMM ammAlice(env, alice, XRP(150'000), USD(51)); env(offer(bob, USD(1), XRP(3'000))); - BEAST_EXPECT( - ammAlice.expectBalances(XRP(153'000), USD(50), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(153'000), USD(50), ammAlice.tokens())); auto jrr = ledgerEntryState(env, bob, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1"); jrr = ledgerEntryRoot(env, bob); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string( - (XRP(200'000) - XRP(3'000) - env.current()->fees().base * 1) - .xrp())); + to_string((XRP(200'000) - XRP(3'000) - env.current()->fees().base * 1).xrp())); } void @@ -379,15 +324,13 @@ private: env(pay(alice, alice, XRP(500)), sendmax(USD(100))); - BEAST_EXPECT( - ammBob.expectBalances(USD(300), XRP(1'000), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(USD(300), XRP(1'000), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, alice, USD(0))); auto jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10'000) + XRP(500) - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(10'000) + XRP(500) - env.current()->fees().base * 2).xrp())); } void @@ -401,26 +344,18 @@ private: [&](AMM& ammAlice, Env& env) { // Alice converts USD to XRP which should fail // due to PartialPayment. - env(pay(alice, alice, XRP(100)), - sendmax(USD(100)), - ter(tecPATH_PARTIAL)); + env(pay(alice, alice, XRP(100)), sendmax(USD(100)), ter(tecPATH_PARTIAL)); // Alice converts USD to XRP, should succeed because // we permit partial payment - env(pay(alice, alice, XRP(100)), - sendmax(USD(100)), - txflags(tfPartialPayment)); + env(pay(alice, alice, XRP(100)), sendmax(USD(100)), txflags(tfPartialPayment)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{9'900'990'100}, USD(10'100), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{9'900'990'100}, USD(10'100), ammAlice.tokens())); // initial 30,000 - 10,000AMM - 100pay BEAST_EXPECT(expectHolding(env, alice, USD(19'900))); // initial 30,000 - 10,0000AMM + 99.009900pay - fee*3 BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - XRP(30'000) - XRP(10'000) + XRPAmount{99'009'900} - - ammCrtFee(env) - txfee(env, 2))); + env, alice, XRP(30'000) - XRP(10'000) + XRPAmount{99'009'900} - ammCrtFee(env) - txfee(env, 2))); }, {{XRP(10'000), USD(10'000)}}, 0, @@ -442,8 +377,7 @@ private: env(trust(bob, USD(100))); env.close(); env(pay(alice, bob, USD(100)), sendmax(XRP(100))); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, bob, USD(100))); }, {{XRP(10'000), USD(10'100)}}, @@ -466,10 +400,8 @@ private: env(trust(bob, USD(100))); env.close(); env(pay(alice, bob, XRP(100)), sendmax(USD(100))); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'100), ammAlice.tokens())); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(1'000) + XRP(100) - txfee(env, 1))); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'100), ammAlice.tokens())); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(1'000) + XRP(100) - txfee(env, 1))); }, {{XRP(10'100), USD(10'000)}}, 0, @@ -515,14 +447,10 @@ private: Json::Value jtp{Json::arrayValue}; jtp[0u][0u][jss::currency] = "XRP"; - env(pay(alice, bob, EUR1(30)), - json(jss::Paths, jtp), - sendmax(USD1(333))); + env(pay(alice, bob, EUR1(30)), json(jss::Paths, jtp), sendmax(USD1(333))); env.close(); - BEAST_EXPECT(ammCarol.expectBalances( - XRP(49'700), - STAmount{USD1, UINT64_C(5'030'181086519115), -12}, - ammCarol.tokens())); + BEAST_EXPECT( + ammCarol.expectBalances(XRP(49'700), STAmount{USD1, UINT64_C(5'030'181086519115), -12}, ammCarol.tokens())); BEAST_EXPECT(expectOffers(env, dan, 1, {{Amounts{XRP(200), EUR(20)}}})); BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR1, 30})); } @@ -551,9 +479,7 @@ private: // fees: // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) + // 1 for payment == 4 - auto const starting_xrp = XRP(100) + - env.current()->fees().accountReserve(3) + - env.current()->fees().base * 4; + auto const starting_xrp = XRP(100) + env.current()->fees().accountReserve(3) + env.current()->fees().base * 4; env.fund(starting_xrp, gw1, gw2, gw3, alice); env.fund(XRP(2'000), bob); @@ -574,18 +500,13 @@ private: // The pool gets only 100XRP for ~109.09USD, even though // it can exchange more. - BEAST_EXPECT(ammBob.expectBalances( - XRP(1'100), - STAmount{USD1, UINT64_C(1'090'909090909091), -12}, - ammBob.tokens())); + BEAST_EXPECT( + ammBob.expectBalances(XRP(1'100), STAmount{USD1, UINT64_C(1'090'909090909091), -12}, ammBob.tokens())); auto jrr = ledgerEntryState(env, alice, gw1, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == - "109.090909090909"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "109.090909090909"); jrr = ledgerEntryRoot(env, alice); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName] == XRP(350).value().getText()); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName] == XRP(350).value().getText()); } void @@ -610,13 +531,11 @@ private: AMM ammAlice(env, alice, USD(150), XRP(150'100)); env(offer(bob, XRP(100), USD(0.1))); - BEAST_EXPECT(ammAlice.expectBalances( - USD(150.1), XRP(150'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(USD(150.1), XRP(150'000), ammAlice.tokens())); auto const jrr = ledgerEntryState(env, bob, gw, "USD"); // Bob pays 0.005 transfer fee. Note 10**-10 round-off. - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == "-0.8995000001"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-0.8995000001"); } void @@ -630,12 +549,10 @@ private: [&](AMM& ammAlice, Env& env) { env(offer(carol, USD(100), XRP(100)), json(jss::Flags, tfSell)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(9'999), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(9'999), ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); BEAST_EXPECT(expectHolding(env, carol, USD(30'101))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRP(30'000) - XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(30'000) - XRP(100) - txfee(env, 1))); }, {{XRP(9'900), USD(10'100)}}, 0, @@ -652,8 +569,7 @@ private: Env env{*this, features}; - auto const starting_xrp = - XRP(100) + reserve(env, 1) + env.current()->fees().base * 2; + auto const starting_xrp = XRP(100) + reserve(env, 1) + env.current()->fees().base * 2; env.fund(starting_xrp, gw, alice); env.fund(XRP(2'000), bob); @@ -671,8 +587,7 @@ private: // Selling XRP. // Will sell all 100 XRP and get more USD than asked for. env(offer(alice, USD(100), XRP(200)), json(jss::Flags, tfSell)); - BEAST_EXPECT( - ammBob.expectBalances(XRP(1'100), USD(2'000), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(1'100), USD(2'000), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, alice, USD(200))); BEAST_EXPECT(expectLedgerEntryRoot(env, alice, XRP(250))); BEAST_EXPECT(expectOffers(env, alice, 0)); @@ -690,15 +605,8 @@ private: auto const XTS = gw["XTS"]; auto const XXX = gw["XXX"]; - auto const starting_xrp = - XRP(100.1) + reserve(env, 1) + env.current()->fees().base * 2; - fund( - env, - gw, - {alice, bob}, - starting_xrp, - {XTS(100), XXX(100)}, - Fund::All); + auto const starting_xrp = XRP(100.1) + reserve(env, 1) + env.current()->fees().base * 2; + fund(env, gw, {alice, bob}, starting_xrp, {XTS(100), XXX(100)}, Fund::All); AMM ammAlice(env, alice, XTS(100), XXX(100)); @@ -707,34 +615,24 @@ private: payment[jss::id] = env.seq(bob); payment[jss::build_path] = true; payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1)); - payment[jss::tx_json][jss::Sequence] = - env.current() - ->read(keylet::account(bob.id())) - ->getFieldU32(sfSequence); + payment[jss::tx_json][jss::Sequence] = env.current()->read(keylet::account(bob.id()))->getFieldU32(sfSequence); payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base); - payment[jss::tx_json][jss::SendMax] = - bob["XTS"](1.5).value().getJson(JsonOptions::none); + payment[jss::tx_json][jss::SendMax] = bob["XTS"](1.5).value().getJson(JsonOptions::none); payment[jss::tx_json][jss::Flags] = tfPartialPayment; auto const jrr = env.rpc("json", "submit", to_string(payment)); BEAST_EXPECT(jrr[jss::result][jss::status] == "success"); BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS"); if (!features[fixAMMv1_1]) { - BEAST_EXPECT(ammAlice.expectBalances( - STAmount(XTS, UINT64_C(101'010101010101), -12), - XXX(99), - ammAlice.tokens())); - BEAST_EXPECT(expectHolding( - env, bob, STAmount{XTS, UINT64_C(98'989898989899), -12})); + BEAST_EXPECT( + ammAlice.expectBalances(STAmount(XTS, UINT64_C(101'010101010101), -12), XXX(99), ammAlice.tokens())); + BEAST_EXPECT(expectHolding(env, bob, STAmount{XTS, UINT64_C(98'989898989899), -12})); } else { - BEAST_EXPECT(ammAlice.expectBalances( - STAmount(XTS, UINT64_C(101'0101010101011), -13), - XXX(99), - ammAlice.tokens())); - BEAST_EXPECT(expectHolding( - env, bob, STAmount{XTS, UINT64_C(98'9898989898989), -13})); + BEAST_EXPECT( + ammAlice.expectBalances(STAmount(XTS, UINT64_C(101'0101010101011), -13), XXX(99), ammAlice.tokens())); + BEAST_EXPECT(expectHolding(env, bob, STAmount{XTS, UINT64_C(98'9898989898989), -13})); } BEAST_EXPECT(expectHolding(env, bob, XXX(101))); } @@ -749,12 +647,7 @@ private: { Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(15'000), EUR(15'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(15'000), EUR(15'000)}, Fund::All); // The scenario: // o USD/XRP AMM is created. @@ -770,10 +663,8 @@ private: env(offer(carol, USD(100), EUR(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); - BEAST_EXPECT(ammBob.expectBalances( - XRP(10'000), EUR(10'100), ammBob.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(10'000), EUR(10'100), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(15'100))); BEAST_EXPECT(expectHolding(env, carol, EUR(14'900))); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -782,12 +673,7 @@ private: { Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(15'000), EUR(15'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(15'000), EUR(15'000)}, Fund::All); // The scenario: // o USD/XRP AMM is created. @@ -805,8 +691,7 @@ private: env(offer(carol, USD(100), EUR(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(15'100))); BEAST_EXPECT(expectHolding(env, carol, EUR(14'900))); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -816,12 +701,7 @@ private: { Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(15'000), EUR(15'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(15'000), EUR(15'000)}, Fund::All); // The scenario: // o USD/XRP offer is created. @@ -839,8 +719,7 @@ private: env(offer(carol, USD(100), EUR(100))); env.close(); - BEAST_EXPECT(ammBob.expectBalances( - XRP(10'000), EUR(10'100), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(10'000), EUR(10'100), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(15'100))); BEAST_EXPECT(expectHolding(env, carol, EUR(14'900))); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -865,11 +744,9 @@ private: fund(env, gw, {alice, bob}, {USD(20'000)}, Fund::All); AMM ammBob(env, bob, XRP(20'000), USD(200)); // alice submits a tfSell | tfFillOrKill offer that does not cross. - env(offer(alice, USD(2.1), XRP(210), tfSell | tfFillOrKill), - ter(killedCode)); + env(offer(alice, USD(2.1), XRP(210), tfSell | tfFillOrKill), ter(killedCode)); - BEAST_EXPECT( - ammBob.expectBalances(XRP(20'000), USD(200), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(20'000), USD(200), ammBob.tokens())); BEAST_EXPECT(expectOffers(env, bob, 0)); } { @@ -880,12 +757,9 @@ private: // Even though tfSell is present it doesn't matter this time. env(offer(alice, USD(2), XRP(220), tfSell | tfFillOrKill)); env.close(); - BEAST_EXPECT(ammBob.expectBalances( - XRP(20'220), - STAmount{USD, UINT64_C(197'8239366963403), -13}, - ammBob.tokens())); - BEAST_EXPECT(expectHolding( - env, alice, STAmount{USD, UINT64_C(1'002'17606330366), -11})); + BEAST_EXPECT( + ammBob.expectBalances(XRP(20'220), STAmount{USD, UINT64_C(197'8239366963403), -13}, ammBob.tokens())); + BEAST_EXPECT(expectHolding(env, alice, STAmount{USD, UINT64_C(1'002'17606330366), -11})); BEAST_EXPECT(expectOffers(env, alice, 0)); } { @@ -898,12 +772,9 @@ private: env(offer(alice, USD(10), XRP(1'500), tfSell | tfFillOrKill)); env.close(); - BEAST_EXPECT(ammBob.expectBalances( - XRP(21'500), - STAmount{USD, UINT64_C(186'046511627907), -12}, - ammBob.tokens())); - BEAST_EXPECT(expectHolding( - env, alice, STAmount{USD, UINT64_C(1'013'953488372093), -12})); + BEAST_EXPECT( + ammBob.expectBalances(XRP(21'500), STAmount{USD, UINT64_C(186'046511627907), -12}, ammBob.tokens())); + BEAST_EXPECT(expectHolding(env, alice, STAmount{USD, UINT64_C(1'013'953488372093), -12})); BEAST_EXPECT(expectOffers(env, alice, 0)); } { @@ -916,8 +787,7 @@ private: fund(env, gw, {alice, bob}, {USD(10'000)}, Fund::All); AMM ammBob(env, bob, XRP(5000), USD(10)); - env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill), - ter(tecKILLED)); + env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill), ter(tecKILLED)); env.close(); BEAST_EXPECT(expectOffers(env, alice, 0)); BEAST_EXPECT(expectOffers(env, bob, 0)); @@ -941,8 +811,7 @@ private: env.close(); // AMM doesn't pay the transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); BEAST_EXPECT(expectOffers(env, carol, 0)); }, @@ -961,8 +830,7 @@ private: env(offer(carol, XRP(100), USD(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'100), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'100), ammAlice.tokens())); // Carol pays 25% transfer fee BEAST_EXPECT(expectHolding(env, carol, USD(29'875))); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -975,12 +843,7 @@ private: { // Bridged crossing. Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(15'000), EUR(15'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(15'000), EUR(15'000)}, Fund::All); env(rate(gw, 1.25)); // The scenario: @@ -999,8 +862,7 @@ private: env.close(); // AMM doesn't pay the transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(15'100))); // Carol pays 25% transfer fee. BEAST_EXPECT(expectHolding(env, carol, EUR(14'875))); @@ -1012,12 +874,7 @@ private: // Bridged crossing. The transfer fee is paid on the step not // involving AMM as src/dst. Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(15'000), EUR(15'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(15'000), EUR(15'000)}, Fund::All); env(rate(gw, 1.25)); // The scenario: @@ -1039,14 +896,12 @@ private: // account but not from the remaining offer. // AMM doesn't pay the transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'050), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'050), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(15'050))); // Carol pays 25% transfer fee. BEAST_EXPECT(expectHolding(env, carol, EUR(14'937.5))); BEAST_EXPECT(expectOffers(env, carol, 0)); - BEAST_EXPECT( - expectOffers(env, bob, 1, {{Amounts{EUR(50), XRP(50)}}})); + BEAST_EXPECT(expectOffers(env, bob, 1, {{Amounts{EUR(50), XRP(50)}}})); } { @@ -1084,8 +939,7 @@ private: env.close(); // AMM doesn't pay the transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(100))); // Carol pays 25% transfer fee: 1250 - 100(offer) - 25(transfer fee) BEAST_EXPECT(expectHolding(env, carol, EUR(1'125))); @@ -1127,8 +981,7 @@ private: env.close(); // AMM pay doesn't transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(100))); // Carol pays 25% transfer fee: 1000 - 100(offer) - 25(transfer fee) BEAST_EXPECT(expectHolding(env, carol, EUR(875))); @@ -1157,8 +1010,7 @@ private: env(offer(alice, USD_bob(100), XRP(100))); env.close(); - BEAST_EXPECT(ammBob.expectBalances( - XRP(10'100), USD_bob(10'000), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(10'100), USD_bob(10'000), ammBob.tokens())); BEAST_EXPECT(expectOffers(env, alice, 0)); BEAST_EXPECT(expectHolding(env, alice, USD_bob(100))); } @@ -1216,14 +1068,10 @@ private: env.close(); // This payment caused the assert. - env(pay(ann, ann, D_BUX(30)), - path(A_BUX, D_BUX), - sendmax(A_BUX(30)), - ter(temBAD_PATH)); + env(pay(ann, ann, D_BUX(30)), path(A_BUX, D_BUX), sendmax(A_BUX(30)), ter(temBAD_PATH)); env.close(); - BEAST_EXPECT( - ammBob.expectBalances(A_BUX(30), D_BUX(30), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(A_BUX(30), D_BUX(30), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, ann, A_BUX(none))); BEAST_EXPECT(expectHolding(env, ann, D_BUX(0))); BEAST_EXPECT(expectHolding(env, cam, A_BUX(none))); @@ -1346,8 +1194,7 @@ private: AMM ammAlice(env, alice, USD(1'000), XRP(1'050)); // Set up authorized trust line for AMM. - env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}), - txflags(tfSetfAuth)); + env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}), txflags(tfSetfAuth)); env.close(); env(pay(gw, bob, USD(50))); @@ -1359,8 +1206,7 @@ private: env(offer(bob, XRP(50), USD(50))); env.close(); - BEAST_EXPECT( - ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, bob, 0)); BEAST_EXPECT(expectHolding(env, bob, USD(0))); } @@ -1379,8 +1225,7 @@ private: // Alice doesn't have the funds { - AMM ammAlice( - env, alice, USD(1'000), XRP(1'000), ter(tecUNFUNDED_AMM)); + AMM ammAlice(env, alice, USD(1'000), XRP(1'000), ter(tecUNFUNDED_AMM)); } env(fset(gw, asfRequireAuth)); @@ -1419,16 +1264,14 @@ private: AMM ammAlice(env, alice, USD(1'000), XRP(1'050)); // Set up authorized trust line for AMM. - env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}), - txflags(tfSetfAuth)); + env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}), txflags(tfSetfAuth)); env.close(); // Now bob creates his offer again, which crosses with alice's AMM. env(offer(bob, XRP(50), USD(50))); env.close(); - BEAST_EXPECT( - ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, bob, 0)); BEAST_EXPECT(expectHolding(env, bob, USD(0))); } @@ -1437,7 +1280,10 @@ private: testOffers() { using namespace jtx; - FeatureBitset const all{testable_amendments()}; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + FeatureBitset const all{testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; + testRmFundedOffer(all); testRmFundedOffer(all - fixAMMv1_1 - fixAMMv1_3); testEnforceNoRipple(all); @@ -1481,25 +1327,14 @@ private: STPathSet st; STAmount sa; STAmount da; - std::tie(st, sa, da) = find_paths( - env, - alice, - bob, - bob["AUD"](-1), - std::optional(XRP(100'000'000))); + std::tie(st, sa, da) = find_paths(env, alice, bob, bob["AUD"](-1), std::optional(XRP(100'000'000))); BEAST_EXPECT(st.empty()); - std::tie(st, sa, da) = find_paths( - env, - alice, - bob, - bob["USD"](-1), - std::optional(XRP(100'000'000))); + std::tie(st, sa, da) = find_paths(env, alice, bob, bob["USD"](-1), std::optional(XRP(100'000'000))); // Alice sends all requested 100,000,000XRP BEAST_EXPECT(sa == XRP(100'000'000)); // Bob gets ~99.99USD. This is the amount Bob // can get out of AMM for 100,000,000XRP. - BEAST_EXPECT(equal( - da, STAmount{bob["USD"].issue(), UINT64_C(99'9999000001), -10})); + BEAST_EXPECT(equal(da, STAmount{bob["USD"].issue(), UINT64_C(99'9999000001), -10})); } // carol holds gateway AUD, sells gateway AUD for XRP @@ -1523,12 +1358,10 @@ private: env(pay(alice, bob, AUD(10)), sendmax(XRP(100)), paths(XRP)); env.close(); // AMM offer is 51.282052XRP/11AUD, 11AUD/1.1 = 10AUD to bob - BEAST_EXPECT( - ammCarol.expectBalances(XRP(51), AUD(40), ammCarol.tokens())); + BEAST_EXPECT(ammCarol.expectBalances(XRP(51), AUD(40), ammCarol.tokens())); BEAST_EXPECT(expectHolding(env, bob, AUD(10))); - auto const result = - find_paths(env, alice, bob, Account(bob)["USD"](25)); + auto const result = find_paths(env, alice, bob, Account(bob)["USD"](25)); BEAST_EXPECT(std::get<0>(result).empty()); } @@ -1543,16 +1376,14 @@ private: Env env = pathTestEnv(); fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All); AMM ammCharlie(env, charlie, XRP(10), USD(11)); - auto [st, sa, da] = - find_paths(env, alice, bob, USD(-1), XRP(1).value()); + auto [st, sa, da] = find_paths(env, alice, bob, USD(-1), XRP(1).value()); BEAST_EXPECT(sa == XRP(1)); BEAST_EXPECT(equal(da, USD(1))); if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1)) { auto const& pathElem = st[0][0]; BEAST_EXPECT( - pathElem.isOffer() && pathElem.getIssuerID() == gw.id() && - pathElem.getCurrency() == USD.currency); + pathElem.isOffer() && pathElem.getIssuerID() == gw.id() && pathElem.getCurrency() == USD.currency); } } { @@ -1561,16 +1392,14 @@ private: fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All); AMM ammCharlie(env, charlie, XRP(11), USD(10)); env.close(); - auto [st, sa, da] = - find_paths(env, alice, bob, drops(-1), USD(1).value()); + auto [st, sa, da] = find_paths(env, alice, bob, drops(-1), USD(1).value()); BEAST_EXPECT(sa == USD(1)); BEAST_EXPECT(equal(da, XRP(1))); if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1)) { auto const& pathElem = st[0][0]; BEAST_EXPECT( - pathElem.isOffer() && - pathElem.getIssuerID() == xrpAccount() && + pathElem.isOffer() && pathElem.getIssuerID() == xrpAccount() && pathElem.getCurrency() == xrpCurrency()); } } @@ -1621,8 +1450,7 @@ private: { auto const& send_amt = XRP(10); - std::tie(st, sa, da) = - find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency()); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(st.empty()); } @@ -1631,16 +1459,14 @@ private: // no path should exist for this since dest account // does not exist. auto const& send_amt = XRP(200); - std::tie(st, sa, da) = find_paths( - env, A1, Account{"A0"}, send_amt, std::nullopt, xrpCurrency()); + std::tie(st, sa, da) = find_paths(env, A1, Account{"A0"}, send_amt, std::nullopt, xrpCurrency()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(st.empty()); } { auto const& send_amt = G3["ABC"](10); - std::tie(st, sa, da) = - find_paths(env, A2, G3, send_amt, std::nullopt, xrpCurrency()); + std::tie(st, sa, da) = find_paths(env, A2, G3, send_amt, std::nullopt, xrpCurrency()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRPAmount{101'010'102})); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"])))); @@ -1648,8 +1474,7 @@ private: { auto const& send_amt = A2["ABC"](1); - std::tie(st, sa, da) = - find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency()); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRPAmount{10'010'011})); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3))); @@ -1657,8 +1482,7 @@ private: { auto const& send_amt = A3["ABC"](1); - std::tie(st, sa, da) = - find_paths(env, A1, A3, send_amt, std::nullopt, xrpCurrency()); + std::tie(st, sa, da) = find_paths(env, A1, A3, send_amt, std::nullopt, xrpCurrency()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRPAmount{10'010'011})); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2))); @@ -1695,8 +1519,7 @@ private: STAmount sa, da; auto const& send_amt = XRP(10); - std::tie(st, sa, da) = - find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["ABC"](1))); BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue())))); @@ -1753,8 +1576,7 @@ private: // A) Borrow or repay -- // Source -> Destination (repay source issuer) auto const& send_amt = G1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1764,8 +1586,7 @@ private: // A2) Borrow or repay -- // Source -> Destination (repay destination issuer) auto const& send_amt = A1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1775,8 +1596,7 @@ private: // B) Common gateway -- // Source -> AC -> Destination auto const& send_amt = A3["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same(st, stpath(G1))); @@ -1786,24 +1606,18 @@ private: // C) Gateway to gateway -- // Source -> OB -> Destination auto const& send_amt = G2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1["HKD"](10))); - BEAST_EXPECT(same( - st, - stpath(IPE(G2["HKD"])), - stpath(M1), - stpath(M2), - stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); + BEAST_EXPECT( + same(st, stpath(IPE(G2["HKD"])), stpath(M1), stpath(M2), stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); } { // D) User to unlinked gateway via order book -- // Source -> AC -> OB -> Destination auto const& send_amt = G2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1819,8 +1633,7 @@ private: // Source -> AC -> OB to XRP -> OB from XRP -> AC -> // Destination auto const& send_amt = A2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1869,8 +1682,7 @@ private: auto const& send_amt = A2["HKD"](10); STPathSet st; STAmount sa, da; - std::tie(st, sa, da) = - find_paths(env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency); + std::tie(st, sa, da) = find_paths(env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1["HKD"](10))); BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2))); @@ -1889,8 +1701,8 @@ private: // This removes no ripple for carol, // different from the original test fund(env, gw, {carol}, XRP(10'000), {}, Fund::Acct); - auto const AMMXRPPool = env.current()->fees().increment * 2; - env.fund(reserve(env, 5) + ammCrtFee(env) + AMMXRPPool, bob); + auto const ammXrpPool = env.current()->fees().increment * 2; + env.fund(reserve(env, 5) + ammCrtFee(env) + ammXrpPool, bob); env.close(); env.trust(USD(1'000), alice, bob, carol); env.trust(EUR(1'000), alice, bob, carol); @@ -1906,7 +1718,7 @@ private: // tecPATH_DRY, but the entire path should not be marked as dry. // This is the second error case to test (when flowV1 is used). env(offer(bob, EUR(50), XRP(50))); - AMM ammBob(env, bob, AMMXRPPool, USD(150)); + AMM ammBob(env, bob, ammXrpPool, USD(150)); env(pay(alice, carol, USD(1'000'000)), path(~XRP, ~USD), @@ -1928,13 +1740,7 @@ private: // simple IOU/IOU offer Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(10'000), - {BTC(100), USD(150)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, XRP(10'000), {BTC(100), USD(150)}, Fund::All); AMM ammBob(env, bob, BTC(100), USD(150)); @@ -1944,20 +1750,13 @@ private: BEAST_EXPECT(expectHolding(env, bob, BTC(0))); BEAST_EXPECT(expectHolding(env, bob, USD(0))); BEAST_EXPECT(expectHolding(env, carol, USD(200))); - BEAST_EXPECT( - ammBob.expectBalances(BTC(150), USD(100), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(BTC(150), USD(100), ammBob.tokens())); } { // simple IOU/XRP XRP/IOU offer Env env(*this, features); - fund( - env, - gw, - {alice, carol, bob}, - XRP(10'000), - {BTC(100), USD(150)}, - Fund::All); + fund(env, gw, {alice, carol, bob}, XRP(10'000), {BTC(100), USD(150)}, Fund::All); AMM ammBobBTC_XRP(env, bob, BTC(100), XRP(150)); AMM ammBobXRP_USD(env, bob, XRP(100), USD(150)); @@ -1968,59 +1767,40 @@ private: BEAST_EXPECT(expectHolding(env, bob, BTC(0))); BEAST_EXPECT(expectHolding(env, bob, USD(0))); BEAST_EXPECT(expectHolding(env, carol, USD(200))); - BEAST_EXPECT(ammBobBTC_XRP.expectBalances( - BTC(150), XRP(100), ammBobBTC_XRP.tokens())); - BEAST_EXPECT(ammBobXRP_USD.expectBalances( - XRP(150), USD(100), ammBobXRP_USD.tokens())); + BEAST_EXPECT(ammBobBTC_XRP.expectBalances(BTC(150), XRP(100), ammBobBTC_XRP.tokens())); + BEAST_EXPECT(ammBobXRP_USD.expectBalances(XRP(150), USD(100), ammBobXRP_USD.tokens())); } { // simple XRP -> USD through offer and sendmax Env env(*this, features); - fund( - env, - gw, - {alice, carol, bob}, - XRP(10'000), - {USD(150)}, - Fund::All); + fund(env, gw, {alice, carol, bob}, XRP(10'000), {USD(150)}, Fund::All); AMM ammBob(env, bob, XRP(100), USD(150)); env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, alice, xrpMinusFee(env, 10'000 - 50))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(10'000) - XRP(100) - ammCrtFee(env))); + BEAST_EXPECT(expectLedgerEntryRoot(env, alice, xrpMinusFee(env, 10'000 - 50))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(10'000) - XRP(100) - ammCrtFee(env))); BEAST_EXPECT(expectHolding(env, bob, USD(0))); BEAST_EXPECT(expectHolding(env, carol, USD(200))); - BEAST_EXPECT( - ammBob.expectBalances(XRP(150), USD(100), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(150), USD(100), ammBob.tokens())); } { // simple USD -> XRP through offer and sendmax Env env(*this, features); - fund( - env, - gw, - {alice, carol, bob}, - XRP(10'000), - {USD(100)}, - Fund::All); + fund(env, gw, {alice, carol, bob}, XRP(10'000), {USD(100)}, Fund::All); AMM ammBob(env, bob, USD(100), XRP(150)); env(pay(alice, carol, XRP(50)), path(~XRP), sendmax(USD(50))); BEAST_EXPECT(expectHolding(env, alice, USD(50))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(10'000) - XRP(150) - ammCrtFee(env))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(10'000) - XRP(150) - ammCrtFee(env))); BEAST_EXPECT(expectHolding(env, bob, USD(0))); BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(10'000 + 50))); - BEAST_EXPECT( - ammBob.expectBalances(USD(150), XRP(100), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(USD(150), XRP(100), ammBob.tokens())); } { // test unfunded offers are removed when payment succeeds @@ -2049,10 +1829,7 @@ private: BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50))); BEAST_EXPECT(isOffer(env, bob, BTC(40), EUR(50))); - env(pay(alice, carol, USD(50)), - path(~USD), - path(~EUR, ~USD), - sendmax(BTC(60))); + env(pay(alice, carol, USD(50)), path(~USD), path(~EUR, ~USD), sendmax(BTC(60))); env.require(balance(alice, BTC(10))); env.require(balance(bob, BTC(50))); @@ -2064,8 +1841,7 @@ private: // found unfunded BEAST_EXPECT(!isOffer(env, bob, BTC(40), EUR(50))); // unchanged - BEAST_EXPECT( - ammBob.expectBalances(EUR(100), USD(150), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(EUR(100), USD(150), ammBob.tokens())); } { // test unfunded offers are removed when the payment fails. @@ -2104,8 +1880,7 @@ private: // unfund offer env(pay(bob, gw, EUR(50))); - BEAST_EXPECT(ammBobBTC_USD.expectBalances( - BTC(50), USD(50), ammBobBTC_USD.tokens())); + BEAST_EXPECT(ammBobBTC_USD.expectBalances(BTC(50), USD(50), ammBobBTC_USD.tokens())); BEAST_EXPECT(isOffer(env, bob, BTC(60), EUR(50))); BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1))); BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50))); @@ -2149,21 +1924,19 @@ private: }(); BEAST_EXPECT(flowResult.removableOffers.size() == 1); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - if (flowResult.removableOffers.empty()) - return false; - Sandbox sb(&view, tapNONE); - for (auto const& o : flowResult.removableOffers) - if (auto ok = sb.peek(keylet::offer(o))) - offerDelete(sb, ok, flowJournal); - sb.apply(view); - return true; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + if (flowResult.removableOffers.empty()) + return false; + Sandbox sb(&view, tapNONE); + for (auto const& o : flowResult.removableOffers) + if (auto ok = sb.peek(keylet::offer(o))) + offerDelete(sb, ok, flowJournal); + sb.apply(view); + return true; + }); // used in payment, but since payment failed should be untouched - BEAST_EXPECT(ammBobBTC_USD.expectBalances( - BTC(50), USD(50), ammBobBTC_USD.tokens())); + BEAST_EXPECT(ammBobBTC_USD.expectBalances(BTC(50), USD(50), ammBobBTC_USD.tokens())); BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1))); // found unfunded BEAST_EXPECT(!isOffer(env, bob, BTC(60), EUR(50))); @@ -2200,8 +1973,7 @@ private: txflags(tfNoRippleDirect | tfPartialPayment)); BEAST_EXPECT(expectHolding(env, carol, EUR(1))); - BEAST_EXPECT(ammBob.expectBalances( - USD(8.4), XRPAmount{20}, ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(USD(8.4), XRPAmount{20}, ammBob.tokens())); } } @@ -2215,12 +1987,7 @@ private: // payment via AMM Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(1'000), - {USD(1'000), GBP(1'000)}); + fund(env, gw, {alice, bob, carol}, XRP(1'000), {USD(1'000), GBP(1'000)}); env(rate(gw, 1.25)); env.close(); @@ -2238,22 +2005,17 @@ private: if (!features[fixAMMv1_1]) { // 120GBP is swapped in for 107.1428USD - BEAST_EXPECT(amm.expectBalances( - GBP(1'120), - STAmount{USD, UINT64_C(892'8571428571428), -13}, - amm.tokens())); + BEAST_EXPECT( + amm.expectBalances(GBP(1'120), STAmount{USD, UINT64_C(892'8571428571428), -13}, amm.tokens())); } else { - BEAST_EXPECT(amm.expectBalances( - GBP(1'120), - STAmount{USD, UINT64_C(892'8571428571429), -13}, - amm.tokens())); + BEAST_EXPECT( + amm.expectBalances(GBP(1'120), STAmount{USD, UINT64_C(892'8571428571429), -13}, amm.tokens())); } // 25% of 85.7142USD is paid in tr fee // 85.7142*1.25 = 107.1428USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'085'714285714286), -12))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'085'714285714286), -12))); } { @@ -2261,12 +2023,7 @@ private: Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(1'000), EUR(1'000), GBP(1'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(1'000), EUR(1'000), GBP(1'000)}); env(rate(gw, 1.25)); env.close(); @@ -2288,29 +2045,19 @@ private: // consumed offer is 120GBP/120EUR // ed doesn't pay tr fee BEAST_EXPECT(expectHolding(env, ed, EUR(880), GBP(1'120))); - BEAST_EXPECT( - expectOffers(env, ed, 1, {Amounts{GBP(880), EUR(880)}})); + BEAST_EXPECT(expectOffers(env, ed, 1, {Amounts{GBP(880), EUR(880)}})); // 25% on 96EUR is paid in tr fee 96*1.25 = 120EUR // 96EUR is swapped in for 87.5912USD - BEAST_EXPECT(amm.expectBalances( - EUR(1'096), - STAmount{USD, UINT64_C(912'4087591240876), -13}, - amm.tokens())); + BEAST_EXPECT(amm.expectBalances(EUR(1'096), STAmount{USD, UINT64_C(912'4087591240876), -13}, amm.tokens())); // 25% on 70.0729USD is paid in tr fee 70.0729*1.25 = 87.5912USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'070'07299270073), -11))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'070'07299270073), -11))); } { // Payment via AMM, AMM Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(1'000), EUR(1'000), GBP(1'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(1'000), EUR(1'000), GBP(1'000)}); env(rate(gw, 1.25)); env.close(); @@ -2329,10 +2076,8 @@ private: // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for // 107.1428EUR - BEAST_EXPECT(amm1.expectBalances( - GBP(1'120), - STAmount{EUR, UINT64_C(892'8571428571428), -13}, - amm1.tokens())); + BEAST_EXPECT( + amm1.expectBalances(GBP(1'120), STAmount{EUR, UINT64_C(892'8571428571428), -13}, amm1.tokens())); // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 = // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD BEAST_EXPECT(amm2.expectBalances( @@ -2345,10 +2090,8 @@ private: // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for // 107.1428EUR - BEAST_EXPECT(amm1.expectBalances( - GBP(1'120), - STAmount{EUR, UINT64_C(892'8571428571429), -13}, - amm1.tokens())); + BEAST_EXPECT( + amm1.expectBalances(GBP(1'120), STAmount{EUR, UINT64_C(892'8571428571429), -13}, amm1.tokens())); // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 = // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD BEAST_EXPECT(amm2.expectBalances( @@ -2357,8 +2100,7 @@ private: amm2.tokens())); } // 25% on 63.1578USD is paid in tr fee 63.1578*1.25 = 78.9473USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'063'157894736842), -12))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'063'157894736842), -12))); } { // AMM offer crossing @@ -2373,8 +2115,7 @@ private: env.close(); // 100USD is swapped in for 100EUR - BEAST_EXPECT( - amm.expectBalances(USD(1'100), EUR(1'000), amm.tokens())); + BEAST_EXPECT(amm.expectBalances(USD(1'100), EUR(1'000), amm.tokens())); // alice pays 25% tr fee on 100USD 1100-100*1.25 = 975USD BEAST_EXPECT(expectHolding(env, alice, USD(975), EUR(1'200))); BEAST_EXPECT(expectOffers(env, alice, 0)); @@ -2384,12 +2125,7 @@ private: // Payment via AMM with limit quality Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(1'000), - {USD(1'000), GBP(1'000)}); + fund(env, gw, {alice, bob, carol}, XRP(1'000), {USD(1'000), GBP(1'000)}); env(rate(gw, 1.25)); env.close(); @@ -2406,13 +2142,9 @@ private: // alice buys 125USD with 142.8571GBP and pays 25% tr fee // on 142.8571GBP // 1,000 - 142.8571*1.25 = 821.4285GBP - BEAST_EXPECT(expectHolding( - env, alice, STAmount(GBP, UINT64_C(821'4285714285712), -13))); + BEAST_EXPECT(expectHolding(env, alice, STAmount(GBP, UINT64_C(821'4285714285712), -13))); // 142.8571GBP is swapped in for 125USD - BEAST_EXPECT(amm.expectBalances( - STAmount{GBP, UINT64_C(1'142'857142857143), -12}, - USD(875), - amm.tokens())); + BEAST_EXPECT(amm.expectBalances(STAmount{GBP, UINT64_C(1'142'857142857143), -12}, USD(875), amm.tokens())); // 25% on 100USD is paid in tr fee // 100*1.25 = 125USD BEAST_EXPECT(expectHolding(env, carol, USD(1'100))); @@ -2422,12 +2154,7 @@ private: // than requested Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(1'000), - {USD(1'200), GBP(1'200)}); + fund(env, gw, {alice, bob, carol}, XRP(1'000), {USD(1'200), GBP(1'200)}); env(rate(gw, 1.25)); env.close(); @@ -2448,23 +2175,17 @@ private: // 1,200 - 24*1.25 = 1,170GBP BEAST_EXPECT(expectHolding(env, alice, GBP(1'170))); // 24GBP is swapped in for 28.125USD - BEAST_EXPECT(amm.expectBalances( - GBP(1'024), USD(1'171.875), amm.tokens())); + BEAST_EXPECT(amm.expectBalances(GBP(1'024), USD(1'171.875), amm.tokens())); } else { // alice buys 28.125USD with 24GBP and pays 25% tr fee // on 24GBP // 1,200 - 24*1.25 =~ 1,170GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'169'999999999999), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'169'999999999999), -12})); // 24GBP is swapped in for 28.125USD - BEAST_EXPECT(amm.expectBalances( - STAmount{GBP, UINT64_C(1'024'000000000001), -12}, - USD(1'171.875), - amm.tokens())); + BEAST_EXPECT( + amm.expectBalances(STAmount{GBP, UINT64_C(1'024'000000000001), -12}, USD(1'171.875), amm.tokens())); } // 25% on 22.5USD is paid in tr fee // 22.5*1.25 = 28.125USD @@ -2476,12 +2197,7 @@ private: Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(1'400), EUR(1'400), GBP(1'400)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(1'400), EUR(1'400), GBP(1'400)}); env(rate(gw, 1.25)); env.close(); @@ -2503,10 +2219,7 @@ private: // alice buys 70.4210EUR with 70.4210GBP via the offer // and pays 25% tr fee on 70.4210GBP // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'311'973684210527), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'311'973684210527), -12})); // ed doesn't pay tr fee, the balances reflect consumed offer // 70.4210GBP/70.4210EUR BEAST_EXPECT(expectHolding( @@ -2533,10 +2246,7 @@ private: // alice buys 70.4210EUR with 70.4210GBP via the offer // and pays 25% tr fee on 70.4210GBP // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'311'973684210525), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'311'973684210525), -12})); // ed doesn't pay tr fee, the balances reflect consumed offer // 70.4210GBP/70.4210EUR BEAST_EXPECT(expectHolding( @@ -2559,8 +2269,7 @@ private: amm.tokens())); } // 25% on 59.7321USD is paid in tr fee 59.7321*1.25 = 74.6651USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'459'732142857143), -12))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'459'732142857143), -12))); } { // Payment via AMM and offer with limit quality, deliver less @@ -2568,12 +2277,7 @@ private: Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(1'400), EUR(1'400), GBP(1'400)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(1'400), EUR(1'400), GBP(1'400)}); env(rate(gw, 1.25)); env.close(); @@ -2595,10 +2299,7 @@ private: // alice buys 53.3322EUR with 56.3368GBP via the amm // and pays 25% tr fee on 56.3368GBP // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'329'578947368421), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'329'578947368421), -12})); //// 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 ///= 70.4210EUR // 56.3368GBP is swapped in for 53.3322EUR @@ -2612,10 +2313,7 @@ private: // alice buys 53.3322EUR with 56.3368GBP via the amm // and pays 25% tr fee on 56.3368GBP // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'329'57894736842), -11})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'329'57894736842), -11})); //// 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 ///= 70.4210EUR // 56.3368GBP is swapped in for 53.3322EUR @@ -2639,8 +2337,7 @@ private: STAmount{EUR, UINT64_C(957'3341836734693), -13}, STAmount{USD, UINT64_C(1'340'267857142857), -12}}})); // 25% on 47.7857USD is paid in tr fee 47.7857*1.25 = 59.7321USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'447'785714285714), -12))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'447'785714285714), -12))); } { // Payment via AMM, AMM with limit quality, deliver less @@ -2648,12 +2345,7 @@ private: Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(1'400), EUR(1'400), GBP(1'400)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(1'400), EUR(1'400), GBP(1'400)}); env(rate(gw, 1.25)); env.close(); @@ -2673,10 +2365,7 @@ private: // alice buys 53.3322EUR with 107.5308GBP // 25% on 86.0246GBP is paid in tr fee // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'292'469135802469), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'292'469135802469), -12})); // 86.0246GBP is swapped in for 79.2106EUR BEAST_EXPECT(amm1.expectBalances( STAmount{GBP, UINT64_C(1'086'024691358025), -12}, @@ -2694,10 +2383,7 @@ private: // alice buys 53.3322EUR with 107.5308GBP // 25% on 86.0246GBP is paid in tr fee // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{GBP, UINT64_C(1'292'469135802466), -12})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{GBP, UINT64_C(1'292'469135802466), -12})); // 86.0246GBP is swapped in for 79.2106EUR BEAST_EXPECT(amm1.expectBalances( STAmount{GBP, UINT64_C(1'086'024691358027), -12}, @@ -2711,20 +2397,14 @@ private: amm2.tokens())); } // 25% on 66.7432USD is paid in tr fee 66.7432*1.25 = 83.4291USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount(USD, UINT64_C(1'466'743295019157), -12))); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(1'466'743295019157), -12))); } { // Payment by the issuer via AMM, AMM with limit quality, // deliver less than requested Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(1'000), - {USD(1'400), EUR(1'400), GBP(1'400)}); + fund(env, gw, {alice, bob, carol}, XRP(1'000), {USD(1'400), EUR(1'400), GBP(1'400)}); env(rate(gw, 1.25)); env.close(); @@ -2768,8 +2448,7 @@ private: amm2.tokens())); } // 25% on 81.1111USD is paid in tr fee 81.1111*1.25 = 101.3888USD - BEAST_EXPECT(expectHolding( - env, carol, STAmount{USD, UINT64_C(1'481'111111111111), -12})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(1'481'111111111111), -12})); } } @@ -2796,8 +2475,7 @@ private: sendmax(XRP(100)), txflags(tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); - BEAST_EXPECT( - ammBob.expectBalances(XRP(1'050), USD(1'000), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(1'050), USD(1'000), ammBob.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(2'050))); BEAST_EXPECT(expectOffers(env, bob, 1, {{{XRP(100), USD(50)}}})); } @@ -2814,13 +2492,7 @@ private: Env env(*this, testable_amendments()); // Note, if alice doesn't have default ripple, then pay // fails with tecPATH_DRY. - fund( - env, - gw, - {alice, bob}, - XRP(10'000), - {USD(200), EUR(200)}, - Fund::All); + fund(env, gw, {alice, bob}, XRP(10'000), {USD(200), EUR(200)}, Fund::All); AMM ammAliceXRP_USD(env, alice, XRP(100), USD(101)); AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(101)); @@ -2838,13 +2510,7 @@ private: Env env(*this); // Note, if alice doesn't have default ripple, then pay fails // with tecPATH_DRY. - fund( - env, - gw, - {alice, bob}, - XRP(10'000), - {USD(200), EUR(200)}, - Fund::All); + fund(env, gw, {alice, bob}, XRP(10'000), {USD(200), EUR(200)}, Fund::All); AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100)); AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100)); @@ -2862,13 +2528,7 @@ private: Env env(*this); // Note, if alice doesn't have default ripple, then pay fails // with tecPATH_DRY. - fund( - env, - gw, - {alice, bob}, - XRP(10'000), - {USD(200), EUR(200), JPY(200)}, - Fund::All); + fund(env, gw, {alice, bob}, XRP(10'000), {USD(200), EUR(200), JPY(200)}, Fund::All); AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100)); AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100)); @@ -2907,11 +2567,9 @@ private: // offer, removes 999 more as unfunded, then hits the step limit. env(offer(alice, USD(1'000), XRP(1'000))); if (!features[fixAMMv1_1]) - env.require(balance( - alice, STAmount{USD, UINT64_C(2'050126257867561), -15})); + env.require(balance(alice, STAmount{USD, UINT64_C(2'050126257867561), -15})); else - env.require(balance( - alice, STAmount{USD, UINT64_C(2'050125257867587), -15})); + env.require(balance(alice, STAmount{USD, UINT64_C(2'050125257867587), -15})); env.require(owners(alice, 2)); env.require(balance(bob, USD(0))); env.require(owners(bob, 1'001)); @@ -2940,36 +2598,23 @@ private: Env env(*this, features); fund(env, gw, {alice, bob, carol}, XRP(10'000)); env.trust(USD(100), alice, bob, carol); + env(pay(alice, bob, USD(10)), deliver_min(USD(10)), ter(temBAD_AMOUNT)); + env(pay(alice, bob, USD(10)), deliver_min(USD(-5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); + env(pay(alice, bob, USD(10)), deliver_min(XRP(5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); env(pay(alice, bob, USD(10)), - delivermin(USD(10)), - ter(temBAD_AMOUNT)); - env(pay(alice, bob, USD(10)), - delivermin(USD(-5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay(alice, bob, USD(10)), - delivermin(XRP(5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay(alice, bob, USD(10)), - delivermin(Account(carol)["USD"](5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay(alice, bob, USD(10)), - delivermin(USD(15)), + deliver_min(Account(carol)["USD"](5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); + env(pay(alice, bob, USD(10)), deliver_min(USD(15)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); env(pay(gw, carol, USD(50))); AMM ammCarol(env, carol, XRP(10), USD(15)); env(pay(alice, bob, USD(10)), paths(XRP), - delivermin(USD(7)), + deliver_min(USD(7)), txflags(tfPartialPayment), sendmax(XRP(5)), ter(tecPATH_PARTIAL)); - env.require(balance( - alice, - drops(10'000'000'000 - env.current()->fees().base.drops()))); + env.require(balance(alice, drops(10'000'000'000 - env.current()->fees().base.drops()))); env.require(balance(bob, XRP(10'000))); } @@ -2981,7 +2626,7 @@ private: AMM ammBob(env, bob, XRP(1'000), USD(1'100)); env(pay(alice, alice, USD(10'000)), paths(XRP), - delivermin(USD(100)), + deliver_min(USD(100)), txflags(tfPartialPayment), sendmax(XRP(100))); env.require(balance(alice, USD(100))); @@ -2995,17 +2640,16 @@ private: AMM ammBob(env, bob, XRP(5'500), USD(1'200)); env(pay(alice, carol, USD(10'000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(1'000)), ter(tecPATH_PARTIAL)); env(pay(alice, carol, USD(10'000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(1'100))); - BEAST_EXPECT( - ammBob.expectBalances(XRP(6'600), USD(1'000), ammBob.tokens())); + BEAST_EXPECT(ammBob.expectBalances(XRP(6'600), USD(1'000), ammBob.tokens())); env.require(balance(carol, USD(200))); } @@ -3024,28 +2668,24 @@ private: { env(pay(alice, carol, USD(10'000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(200))); env.require(balance(bob, USD(0))); env.require(balance(carol, USD(200))); - BEAST_EXPECT(ammDan.expectBalances( - XRP(1'100), USD(1'000), ammDan.tokens())); + BEAST_EXPECT(ammDan.expectBalances(XRP(1'100), USD(1'000), ammDan.tokens())); } else { env(pay(alice, carol, USD(10'000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRPAmount(200'000'001))); env.require(balance(bob, USD(0))); - env.require(balance( - carol, STAmount{USD, UINT64_C(200'00000090909), -11})); + env.require(balance(carol, STAmount{USD, UINT64_C(200'00000090909), -11})); BEAST_EXPECT(ammDan.expectBalances( - XRPAmount{1'100'000'001}, - STAmount{USD, UINT64_C(999'99999909091), -11}, - ammDan.tokens())); + XRPAmount{1'100'000'001}, STAmount{USD, UINT64_C(999'99999909091), -11}, ammDan.tokens())); } } } @@ -3058,8 +2698,6 @@ private: using namespace jtx; Account const becky{"becky"}; - bool const supportsPreauth = {features[featureDepositPreauth]}; - // The initial implementation of DepositAuth had a bug where an // account with the DepositAuth flag set could not make a payment // to itself. That bug was fixed in the DepositPreauth amendment. @@ -3080,22 +2718,14 @@ private: // Make sure the payment works if PaymentAuth is not involved. env(pay(becky, becky, USD(10)), path(~USD), sendmax(XRP(10))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(107'692'308), USD(130), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount(107'692'308), USD(130), ammAlice.tokens())); // becky decides to require authorization for deposits. env(fset(becky, asfDepositAuth)); env.close(); - // becky pays herself again. Whether it succeeds depends on - // whether featureDepositPreauth is enabled. - TER const expect{ - supportsPreauth ? TER{tesSUCCESS} : TER{tecNO_PERMISSION}}; - - env(pay(becky, becky, USD(10)), - path(~USD), - sendmax(XRP(10)), - ter(expect)); + // becky pays herself again. + env(pay(becky, becky, USD(10)), path(~USD), sendmax(XRP(10)), ter(tesSUCCESS)); env.close(); } @@ -3142,9 +2772,7 @@ private: // Note that even though alice is paying bob in XRP, the payment // is still not allowed since the payment passes through an // offer. - env(pay(alice, bob, drops(1)), - sendmax(USD(1)), - ter(tecNO_PERMISSION)); + env(pay(alice, bob, drops(1)), sendmax(USD(1)), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(bobXrpBalance == env.balance(bob, XRP)); @@ -3190,8 +2818,7 @@ private: env(pay(alice, bob, drops(1)), sendmax(USD(1))); env.close(); - BEAST_EXPECT(ammCarol.expectBalances( - USD(101), XRPAmount(100), ammCarol.tokens())); + BEAST_EXPECT(ammCarol.expectBalances(USD(101), XRPAmount(100), ammCarol.tokens())); } void @@ -3256,8 +2883,7 @@ private: // test: can buy more assets on that line env(offer(bob, G1["USD"](5), XRP(25))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(525), G1["USD"](100), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(525), G1["USD"](100), ammAlice.tokens())); } { @@ -3312,15 +2938,11 @@ private: // Is cleared via a TrustSet with ClearFreeze flag // test: sets LowFreeze | HighFreeze flags env(trust(G1, bob["USD"](0), tfClearFreeze)); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 2u))) return; - auto ff = - affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfLowLimit.fieldName] == - G1["USD"](0).value().getJson(JsonOptions::none)); + auto ff = affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; + BEAST_EXPECT(ff[sfLowLimit.fieldName] == G1["USD"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze)); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze)); env.close(); @@ -3367,10 +2989,7 @@ private: // Account without GlobalFreeze (proving operations normally // work) // test: visible offers where taker_pays is unfrozen issuer - auto offers = env.rpc( - "book_offers", - std::string("USD/") + G1.human(), - "XRP")[jss::result][jss::offers]; + auto offers = env.rpc("book_offers", std::string("USD/") + G1.human(), "XRP")[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 1u))) return; std::set accounts; @@ -3381,10 +3000,7 @@ private: BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts)); // test: visible offers where taker_gets is unfrozen issuer - offers = env.rpc( - "book_offers", - "XRP", - std::string("USD/") + G1.human())[jss::result][jss::offers]; + offers = env.rpc("book_offers", "XRP", std::string("USD/") + G1.human())[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 1u))) return; accounts.clear(); @@ -3437,17 +3053,11 @@ private: { // test: book_offers shows offers // (should these actually be filtered?) - auto offers = env.rpc( - "book_offers", - "XRP", - std::string("USD/") + G1.human())[jss::result][jss::offers]; + auto offers = env.rpc("book_offers", "XRP", std::string("USD/") + G1.human())[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 1u))) return; - offers = env.rpc( - "book_offers", - std::string("USD/") + G1.human(), - "XRP")[jss::result][jss::offers]; + offers = env.rpc("book_offers", std::string("USD/") + G1.human(), "XRP")[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 1u))) return; } @@ -3498,19 +3108,16 @@ private: env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1))); env.close(); - BEAST_EXPECT( - ammA3.expectBalances(XRP(1'001), G1["USD"](1'000), ammA3.tokens())); + BEAST_EXPECT(ammA3.expectBalances(XRP(1'001), G1["USD"](1'000), ammA3.tokens())); // test: someone else creates an offer providing liquidity env(offer(A4, XRP(999), G1["USD"](999))); env.close(); // The offer consumes AMM offer - BEAST_EXPECT( - ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens())); + BEAST_EXPECT(ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens())); // test: AMM line is frozen - auto const a3am = - STAmount{Issue{to_currency("USD"), ammA3.ammAccount()}, 0}; + auto const a3am = STAmount{Issue{to_currency("USD"), ammA3.ammAccount()}, 0}; env(trust(G1, a3am, tfSetFreeze)); auto const info = ammA3.ammRpcInfo(); BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool()); @@ -3520,8 +3127,7 @@ private: env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1))); env.close(); // AMM is not consumed - BEAST_EXPECT( - ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens())); + BEAST_EXPECT(ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens())); // removal buy successful OfferCreate // test: freeze the new offer @@ -3559,8 +3165,7 @@ private: // Attach signers to alice. env(signers(alice, 2, {{becky, 1}, {bogie, 1}}), sig(alie)); env.close(); - int const signerListOwners{features[featureMultiSignReserve] ? 2 : 5}; - env.require(owners(alice, signerListOwners + 0)); + env.require(owners(alice, 2)); msig const ms{becky, bogie}; @@ -3577,16 +3182,13 @@ private: std::nullopt, ms, ter(tesSUCCESS)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); ammAlice.deposit(alice, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); ammAlice.withdraw(alice, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); ammAlice.vote({}, 1'000); BEAST_EXPECT(ammAlice.expectTradingFee(1'000)); @@ -3594,8 +3196,7 @@ private: env(ammAlice.bid({.account = alice, .bidMin = 100}), ms).close(); BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, IOUAmount{4'000})); // 4000 tokens burnt - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{9'996'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{9'996'000, 0})); } void @@ -3609,12 +3210,7 @@ private: Env env(*this, features); - fund( - env, - gw, - {alice, bob, carol}, - XRP(10'000), - {USD(2'000), EUR(1'000)}); + fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(2'000), EUR(1'000)}); AMM bobXRP_USD(env, bob, XRP(1'000), USD(1'000)); AMM bobUSD_EUR(env, bob, USD(1'000), EUR(1'000)); @@ -3641,12 +3237,7 @@ private: env.trust(USD(1'000), alice, bob); env.trust(EUR(1'000), alice, bob); env.close(); - fund( - env, - bob, - {alice, gw}, - {BobUSD(100), BobEUR(100)}, - Fund::IOUOnly); + fund(env, bob, {alice, gw}, {BobUSD(100), BobEUR(100)}, Fund::IOUOnly); env.close(); AMM ammBobXRP_USD(env, bob, XRP(100), BobUSD(100)); @@ -3657,7 +3248,7 @@ private: Path const p = [&] { Path result; - result.push_back(allpe(gw, BobUSD)); + result.push_back(allPathElements(gw, BobUSD)); result.push_back(cpe(EUR.currency)); return result; }(); @@ -3679,10 +3270,7 @@ private: AMM ammBob(env, bob, XRP(100), USD(100)); // payment path: XRP -> XRP/USD -> USD/XRP - env(pay(alice, carol, XRP(100)), - path(~USD, ~XRP), - txflags(tfNoRippleDirect), - ter(temBAD_SEND_XRP_PATHS)); + env(pay(alice, carol, XRP(100)), path(~USD, ~XRP), txflags(tfNoRippleDirect), ter(temBAD_SEND_XRP_PATHS)); } { @@ -3772,7 +3360,9 @@ private: testFlow() { using namespace jtx; - FeatureBitset const all{testable_amendments()}; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas in the transaction engine + FeatureBitset const all{testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; testFalseDry(all); testBookStep(all); @@ -3786,7 +3376,9 @@ private: testCrossingLimits() { using namespace jtx; - FeatureBitset const all{testable_amendments()}; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas in the transaction engine + FeatureBitset const all{testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; testStepLimit(all); testStepLimit(all - fixAMMv1_1 - fixAMMv1_3); } @@ -3795,7 +3387,9 @@ private: testDeliverMin() { using namespace jtx; - FeatureBitset const all{testable_amendments()}; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas in the transaction engine + FeatureBitset const all{testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; test_convert_all_of_an_asset(all); test_convert_all_of_an_asset(all - fixAMMv1_1 - fixAMMv1_3); } @@ -3803,9 +3397,10 @@ private: void testDepositAuth() { - auto const supported{jtx::testable_amendments()}; - testPayment(supported - featureDepositPreauth); - testPayment(supported); + // For now, just disable SAV entirely, which locks in the small Number + // mantissas in the transaction engine + FeatureBitset const all{jtx::testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; + testPayment(all); testPayIOU(); } @@ -3813,7 +3408,9 @@ private: testFreeze() { using namespace test::jtx; - auto const sa = testable_amendments(); + // For now, just disable SAV entirely, which locks in the small Number + // mantissas in the transaction engine + FeatureBitset const sa{testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; testRippleState(sa); testGlobalFreeze(sa); testOffersWhenFrozen(sa); @@ -3822,20 +3419,13 @@ private: void testMultisign() { - using namespace jtx; - auto const all = testable_amendments(); - - testTxMultisign( - all - featureMultiSignReserve - featureExpandedSignerList); - testTxMultisign(all - featureExpandedSignerList); - testTxMultisign(all); + testTxMultisign(jtx::testable_amendments()); } void testPayStrand() { - using namespace jtx; - auto const all = testable_amendments(); + auto const all = jtx::testable_amendments(); testToStrand(all); testRIPD1373(all); @@ -3857,7 +3447,7 @@ private: } }; -BEAST_DEFINE_TESTSUITE_PRIO(AMMExtended, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(AMMExtended, app, xrpl, 1); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 3e0d65894f..8a60e5f667 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -40,7 +21,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { /** @@ -49,7 +30,18 @@ namespace test { */ struct AMM_test : public jtx::AMMTest { + // Use small Number mantissas for the life of this test. + NumberMantissaScaleGuard const sg_{xrpl::MantissaRange::small}; + private: + static FeatureBitset + testable_amendments() + { + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + return jtx::testable_amendments() - featureSingleAssetVault - featureLendingProtocol; + } + void testInstanceCreate() { @@ -57,22 +49,22 @@ private: using namespace jtx; +#if NUMBERTODO // XRP to IOU, with featureSingleAssetVault testAMM( [&](AMM& ammAlice, Env&) { - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); }, {}, 0, {}, {testable_amendments() | featureSingleAssetVault}); +#endif // XRP to IOU, without featureSingleAssetVault testAMM( [&](AMM& ammAlice, Env&) { - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); }, {}, 0, @@ -82,8 +74,7 @@ private: // IOU to IOU testAMM( [&](AMM& ammAlice, Env&) { - BEAST_EXPECT(ammAlice.expectBalances( - USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); }, {{USD(20'000), BTC(0.5)}}); @@ -95,8 +86,7 @@ private: env.close(); // no transfer fee on create AMM ammAlice(env, alice, USD(20'000), BTC(0.5)); - BEAST_EXPECT(ammAlice.expectBalances( - USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); BEAST_EXPECT(expectHolding(env, alice, USD(0))); BEAST_EXPECT(expectHolding(env, alice, BTC(0))); } @@ -126,8 +116,7 @@ private: env.close(); env(fset(gw, asfGlobalFreeze)); env.close(); - AMM ammAliceFail( - env, alice, XRP(10'000), USD(10'000), ter(tecFROZEN)); + AMM ammAliceFail(env, alice, XRP(10'000), USD(10'000), ter(tecFROZEN)); env(fclear(gw, asfGlobalFreeze)); env.close(); AMM ammAlice(env, alice, XRP(10'000), USD(10'000)); @@ -143,12 +132,8 @@ private: 1'000); // Make sure asset comparison works. - BEAST_EXPECT( - STIssue(sfAsset, STAmount(XRP(2'000)).issue()) == - STIssue(sfAsset, STAmount(XRP(2'000)).issue())); - BEAST_EXPECT( - STIssue(sfAsset, STAmount(XRP(2'000)).issue()) != - STIssue(sfAsset, STAmount(USD(2'000)).issue())); + BEAST_EXPECT(STIssue(sfAsset, STAmount(XRP(2'000)).issue()) == STIssue(sfAsset, STAmount(XRP(2'000)).issue())); + BEAST_EXPECT(STIssue(sfAsset, STAmount(XRP(2'000)).issue()) != STIssue(sfAsset, STAmount(USD(2'000)).issue())); } void @@ -162,8 +147,7 @@ private: { Env env{*this}; fund(env, gw, {alice}, {USD(30'000)}, Fund::All); - AMM ammAlice( - env, alice, XRP(10'000), XRP(10'000), ter(temBAD_AMM_TOKENS)); + AMM ammAlice(env, alice, XRP(10'000), XRP(10'000), ter(temBAD_AMM_TOKENS)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -171,8 +155,7 @@ private: { Env env{*this}; fund(env, gw, {alice}, {USD(30'000)}, Fund::All); - AMM ammAlice( - env, alice, USD(10'000), USD(10'000), ter(temBAD_AMM_TOKENS)); + AMM ammAlice(env, alice, USD(10'000), USD(10'000), ter(temBAD_AMM_TOKENS)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -184,11 +167,9 @@ private: BEAST_EXPECT(!ammAlice.ammExists()); AMM ammAlice1(env, alice, XRP(10'000), USD(0), ter(temBAD_AMOUNT)); BEAST_EXPECT(!ammAlice1.ammExists()); - AMM ammAlice2( - env, alice, XRP(10'000), USD(-10'000), ter(temBAD_AMOUNT)); + AMM ammAlice2(env, alice, XRP(10'000), USD(-10'000), ter(temBAD_AMOUNT)); BEAST_EXPECT(!ammAlice2.ammExists()); - AMM ammAlice3( - env, alice, XRP(-10'000), USD(10'000), ter(temBAD_AMOUNT)); + AMM ammAlice3(env, alice, XRP(-10'000), USD(10'000), ter(temBAD_AMOUNT)); BEAST_EXPECT(!ammAlice3.ammExists()); } @@ -196,8 +177,7 @@ private: { Env env{*this}; fund(env, gw, {alice}, {USD(30'000)}, Fund::All); - AMM ammAlice( - env, alice, XRP(10'000), BAD(10'000), ter(temBAD_CURRENCY)); + AMM ammAlice(env, alice, XRP(10'000), BAD(10'000), ter(temBAD_CURRENCY)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -205,8 +185,7 @@ private: { Env env{*this}; fund(env, gw, {alice}, {USD(30'000)}, Fund::All); - AMM ammAlice( - env, alice, XRP(10'000), USD(40'000), ter(tecUNFUNDED_AMM)); + AMM ammAlice(env, alice, XRP(10'000), USD(40'000), ter(tecUNFUNDED_AMM)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -214,8 +193,7 @@ private: { Env env{*this}; fund(env, gw, {alice}, {USD(30'000)}, Fund::All); - AMM ammAlice( - env, alice, XRP(40'000), USD(10'000), ter(tecUNFUNDED_AMM)); + AMM ammAlice(env, alice, XRP(40'000), USD(10'000), ter(tecUNFUNDED_AMM)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -239,10 +217,8 @@ private: } // AMM already exists - testAMM([&](AMM& ammAlice, Env& env) { - AMM ammCarol( - env, carol, XRP(10'000), USD(10'000), ter(tecDUPLICATE)); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { AMM ammCarol(env, carol, XRP(10'000), USD(10'000), ter(tecDUPLICATE)); }); // Invalid flags { @@ -325,8 +301,7 @@ private: // Insufficient reserve, XRP/IOU { Env env(*this); - auto const starting_xrp = - XRP(1'000) + reserve(env, 3) + env.current()->fees().base * 4; + auto const starting_xrp = XRP(1'000) + reserve(env, 3) + env.current()->fees().base * 4; env.fund(starting_xrp, gw); env.fund(starting_xrp, alice); env.trust(USD(2'000), alice); @@ -335,15 +310,13 @@ private: env.close(); env(offer(alice, XRP(101), USD(100))); env(offer(alice, XRP(102), USD(100))); - AMM ammAlice( - env, alice, XRP(1'000), USD(1'000), ter(tecUNFUNDED_AMM)); + AMM ammAlice(env, alice, XRP(1'000), USD(1'000), ter(tecUNFUNDED_AMM)); } // Insufficient reserve, IOU/IOU { Env env(*this); - auto const starting_xrp = - reserve(env, 4) + env.current()->fees().base * 5; + auto const starting_xrp = reserve(env, 4) + env.current()->fees().base * 5; env.fund(starting_xrp, gw); env.fund(starting_xrp, alice); env.trust(USD(2'000), alice); @@ -354,8 +327,7 @@ private: env.close(); env(offer(alice, EUR(101), USD(100))); env(offer(alice, EUR(102), USD(100))); - AMM ammAlice( - env, alice, EUR(1'000), USD(1'000), ter(tecINSUF_RESERVE_LINE)); + AMM ammAlice(env, alice, EUR(1'000), USD(1'000), ter(tecINSUF_RESERVE_LINE)); } // Insufficient fee @@ -382,17 +354,9 @@ private: testAMM([&](AMM& ammAlice, Env& env) { fund(env, gw, {alice}, {EUR(10'000)}, Fund::IOUOnly); AMM ammAMMToken( - env, - alice, - EUR(10'000), - STAmount{ammAlice.lptIssue(), 1'000'000}, - ter(tecAMM_INVALID_TOKENS)); + env, alice, EUR(10'000), STAmount{ammAlice.lptIssue(), 1'000'000}, ter(tecAMM_INVALID_TOKENS)); AMM ammAMMToken1( - env, - alice, - STAmount{ammAlice.lptIssue(), 1'000'000}, - EUR(10'000), - ter(tecAMM_INVALID_TOKENS)); + env, alice, STAmount{ammAlice.lptIssue(), 1'000'000}, EUR(10'000), ter(tecAMM_INVALID_TOKENS)); }); // AMM with two LPTokens from other AMMs. @@ -402,11 +366,7 @@ private: auto const token1 = ammAlice.lptIssue(); auto const token2 = ammAlice1.lptIssue(); AMM ammAMMTokens( - env, - alice, - STAmount{token1, 1'000'000}, - STAmount{token2, 1'000'000}, - ter(tecAMM_INVALID_TOKENS)); + env, alice, STAmount{token1, 1'000'000}, STAmount{token2, 1'000'000}, ter(tecAMM_INVALID_TOKENS)); }); // Issuer has DefaultRipple disabled @@ -418,8 +378,7 @@ private: env.fund(XRP(30'000), alice); env.trust(USD(30'000), alice); env(pay(gw, alice, USD(30'000))); - AMM ammAlice( - env, alice, XRP(10'000), USD(10'000), ter(terNO_RIPPLE)); + AMM ammAlice(env, alice, XRP(10'000), USD(10'000), ter(terNO_RIPPLE)); Account const gw1("gw1"); env.fund(XRP(30'000), gw1); env(fclear(gw1, asfDefaultRipple)); @@ -429,8 +388,7 @@ private: AMM ammGwGw1(env, gw, USD(10'000), USD1(10'000), ter(terNO_RIPPLE)); env.trust(USD1(30'000), alice); env(pay(gw1, alice, USD1(30'000))); - AMM ammAlice1( - env, alice, USD(10'000), USD1(10'000), ter(terNO_RIPPLE)); + AMM ammAlice1(env, alice, USD(10'000), USD1(10'000), ter(terNO_RIPPLE)); } } @@ -443,12 +401,7 @@ private: testAMM([&](AMM& ammAlice, Env& env) { // Invalid flags - ammAlice.deposit( - alice, - 1'000'000, - std::nullopt, - tfWithdrawAll, - ter(temINVALID_FLAG)); + ammAlice.deposit(alice, 1'000'000, std::nullopt, tfWithdrawAll, ter(temINVALID_FLAG)); // Invalid options std::vector>> invalidOptions = { // flags, tokens, asset1In, asset2in, EPrice, tfee - {tfLPToken, - 1'000, - std::nullopt, - USD(100), - std::nullopt, - std::nullopt}, - {tfLPToken, - 1'000, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt}, - {tfLPToken, - 1'000, - std::nullopt, - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt}, - {tfLPToken, - std::nullopt, - USD(100), - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt}, - {tfLPToken, - 1'000, - XRP(100), - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt}, - {tfLPToken, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - 1'000}, - {tfSingleAsset, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}, - {tfSingleAsset, - std::nullopt, - std::nullopt, - USD(100), - std::nullopt, - std::nullopt}, - {tfSingleAsset, - std::nullopt, - std::nullopt, - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt}, - {tfSingleAsset, - std::nullopt, - USD(100), - std::nullopt, - std::nullopt, - 1'000}, - {tfTwoAsset, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}, - {tfTwoAsset, - std::nullopt, - XRP(100), - USD(100), - STAmount{USD, 1, -1}, - std::nullopt}, - {tfTwoAsset, - std::nullopt, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt}, - {tfTwoAsset, - std::nullopt, - XRP(100), - USD(100), - std::nullopt, - 1'000}, - {tfTwoAsset, - std::nullopt, - std::nullopt, - USD(100), - STAmount{USD, 1, -1}, - std::nullopt}, - {tfOneAssetLPToken, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}, - {tfOneAssetLPToken, - std::nullopt, - XRP(100), - USD(100), - std::nullopt, - std::nullopt}, - {tfOneAssetLPToken, - std::nullopt, - XRP(100), - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt}, - {tfOneAssetLPToken, - 1'000, - XRP(100), - std::nullopt, - std::nullopt, - 1'000}, - {tfLimitLPToken, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}, - {tfLimitLPToken, - 1'000, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt}, - {tfLimitLPToken, - std::nullopt, - USD(100), - XRP(100), - std::nullopt, - std::nullopt}, - {tfLimitLPToken, - std::nullopt, - XRP(100), - std::nullopt, - STAmount{USD, 1, -1}, - 1'000}, - {tfTwoAssetIfEmpty, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - 1'000}, - {tfTwoAssetIfEmpty, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt}, - {tfTwoAssetIfEmpty, - std::nullopt, - XRP(100), - USD(100), - STAmount{USD, 1, -1}, - std::nullopt}, + {tfLPToken, 1'000, std::nullopt, USD(100), std::nullopt, std::nullopt}, + {tfLPToken, 1'000, XRP(100), std::nullopt, std::nullopt, std::nullopt}, + {tfLPToken, 1'000, std::nullopt, std::nullopt, STAmount{USD, 1, -1}, std::nullopt}, + {tfLPToken, std::nullopt, USD(100), std::nullopt, STAmount{USD, 1, -1}, std::nullopt}, + {tfLPToken, 1'000, XRP(100), std::nullopt, STAmount{USD, 1, -1}, std::nullopt}, + {tfLPToken, 1'000, std::nullopt, std::nullopt, std::nullopt, 1'000}, + {tfSingleAsset, 1'000, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + {tfSingleAsset, std::nullopt, std::nullopt, USD(100), std::nullopt, std::nullopt}, + {tfSingleAsset, std::nullopt, std::nullopt, std::nullopt, STAmount{USD, 1, -1}, std::nullopt}, + {tfSingleAsset, std::nullopt, USD(100), std::nullopt, std::nullopt, 1'000}, + {tfTwoAsset, 1'000, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + {tfTwoAsset, std::nullopt, XRP(100), USD(100), STAmount{USD, 1, -1}, std::nullopt}, + {tfTwoAsset, std::nullopt, XRP(100), std::nullopt, std::nullopt, std::nullopt}, + {tfTwoAsset, std::nullopt, XRP(100), USD(100), std::nullopt, 1'000}, + {tfTwoAsset, std::nullopt, std::nullopt, USD(100), STAmount{USD, 1, -1}, std::nullopt}, + {tfOneAssetLPToken, 1'000, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + {tfOneAssetLPToken, std::nullopt, XRP(100), USD(100), std::nullopt, std::nullopt}, + {tfOneAssetLPToken, std::nullopt, XRP(100), std::nullopt, STAmount{USD, 1, -1}, std::nullopt}, + {tfOneAssetLPToken, 1'000, XRP(100), std::nullopt, std::nullopt, 1'000}, + {tfLimitLPToken, 1'000, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + {tfLimitLPToken, 1'000, USD(100), std::nullopt, std::nullopt, std::nullopt}, + {tfLimitLPToken, std::nullopt, USD(100), XRP(100), std::nullopt, std::nullopt}, + {tfLimitLPToken, std::nullopt, XRP(100), std::nullopt, STAmount{USD, 1, -1}, 1'000}, + {tfTwoAssetIfEmpty, std::nullopt, std::nullopt, std::nullopt, std::nullopt, 1'000}, + {tfTwoAssetIfEmpty, 1'000, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + {tfTwoAssetIfEmpty, std::nullopt, XRP(100), USD(100), STAmount{USD, 1, -1}, std::nullopt}, {tfTwoAssetIfEmpty | tfLPToken, std::nullopt, XRP(100), @@ -642,34 +465,23 @@ private: Json::Value jv = Json::objectValue; jv[jss::Account] = alice.human(); jv[jss::TransactionType] = jss::AMMDeposit; - jv[jss::Asset] = - STIssue(sfAsset, XRP).getJson(JsonOptions::none); - jv[jss::Asset2] = - STIssue(sfAsset, USD).getJson(JsonOptions::none); + jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::none); + jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::none); jv[jss::Fee] = "-1"; env(jv, ter(temBAD_FEE)); } // Invalid tokens - ammAlice.deposit( - alice, 0, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); - ammAlice.deposit( - alice, - IOUAmount{-1}, - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(alice, 0, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(alice, IOUAmount{-1}, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); { Json::Value jv = Json::objectValue; jv[jss::Account] = alice.human(); jv[jss::TransactionType] = jss::AMMDeposit; - jv[jss::Asset] = - STIssue(sfAsset, XRP).getJson(JsonOptions::none); - jv[jss::Asset2] = - STIssue(sfAsset, USD).getJson(JsonOptions::none); - jv[jss::LPTokenOut] = - USD(100).value().getJson(JsonOptions::none); + jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::none); + jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::none); + jv[jss::LPTokenOut] = USD(100).value().getJson(JsonOptions::none); jv[jss::Flags] = tfLPToken; env(jv, ter(temBAD_AMM_TOKENS)); } @@ -705,63 +517,21 @@ private: } // Depositing mismatched token, invalid Asset1In.issue - ammAlice.deposit( - alice, - GBP(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(alice, GBP(100), std::nullopt, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); // Depositing mismatched token, invalid Asset2In.issue - ammAlice.deposit( - alice, - USD(100), - GBP(100), - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(alice, USD(100), GBP(100), std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); // Depositing mismatched token, Asset1In.issue == Asset2In.issue - ammAlice.deposit( - alice, - USD(100), - USD(100), - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(alice, USD(100), USD(100), std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); // Invalid amount value - ammAlice.deposit( - alice, - USD(0), - std::nullopt, - std::nullopt, - std::nullopt, - ter(temBAD_AMOUNT)); - ammAlice.deposit( - alice, - USD(-1'000), - std::nullopt, - std::nullopt, - std::nullopt, - ter(temBAD_AMOUNT)); - ammAlice.deposit( - alice, - USD(10), - std::nullopt, - USD(-1), - std::nullopt, - ter(temBAD_AMOUNT)); + ammAlice.deposit(alice, USD(0), std::nullopt, std::nullopt, std::nullopt, ter(temBAD_AMOUNT)); + ammAlice.deposit(alice, USD(-1'000), std::nullopt, std::nullopt, std::nullopt, ter(temBAD_AMOUNT)); + ammAlice.deposit(alice, USD(10), std::nullopt, USD(-1), std::nullopt, ter(temBAD_AMOUNT)); // Bad currency - ammAlice.deposit( - alice, - BAD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(temBAD_CURRENCY)); + ammAlice.deposit(alice, BAD(100), std::nullopt, std::nullopt, std::nullopt, ter(temBAD_CURRENCY)); // Invalid Account Account bad("bad"); @@ -821,54 +591,28 @@ private: // Deposit amount is invalid // Calculated amount to deposit is 98,000,000 - ammAlice.deposit( - alice, - USD(0), - std::nullopt, - STAmount{USD, 1, -1}, - std::nullopt, - ter(tecUNFUNDED_AMM)); + ammAlice.deposit(alice, USD(0), std::nullopt, STAmount{USD, 1, -1}, std::nullopt, ter(tecUNFUNDED_AMM)); // Calculated amount is 0 - ammAlice.deposit( - alice, - USD(0), - std::nullopt, - STAmount{USD, 2'000, -6}, - std::nullopt, - ter(tecAMM_FAILED)); + ammAlice.deposit(alice, USD(0), std::nullopt, STAmount{USD, 2'000, -6}, std::nullopt, ter(tecAMM_FAILED)); // Deposit non-empty AMM - ammAlice.deposit( - carol, - XRP(100), - USD(100), - std::nullopt, - tfTwoAssetIfEmpty, - ter(tecAMM_NOT_EMPTY)); + ammAlice.deposit(carol, XRP(100), USD(100), std::nullopt, tfTwoAssetIfEmpty, ter(tecAMM_NOT_EMPTY)); }); // Tiny deposit testAMM( [&](AMM& ammAlice, Env& env) { - auto const enabledv1_3 = - env.current()->rules().enabled(fixAMMv1_3); - auto const err = - !enabledv1_3 ? ter(temBAD_AMOUNT) : ter(tesSUCCESS); + auto const enabledV1_3 = env.current()->rules().enabled(fixAMMv1_3); + auto const err = !enabledV1_3 ? ter(temBAD_AMOUNT) : ter(tesSUCCESS); // Pre-amendment XRP deposit side is rounded to 0 // and deposit fails. // Post-amendment XRP deposit side is rounded to 1 // and deposit succeeds. - ammAlice.deposit( - carol, IOUAmount{1, -4}, std::nullopt, std::nullopt, err); + ammAlice.deposit(carol, IOUAmount{1, -4}, std::nullopt, std::nullopt, err); // Pre/post-amendment LPTokens is rounded to 0 and deposit // fails with tecAMM_INVALID_TOKENS. ammAlice.deposit( - carol, - STAmount{USD, 1, -12}, - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + carol, STAmount{USD, 1, -12}, std::nullopt, std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); }, std::nullopt, 0, @@ -878,8 +622,7 @@ private: // Invalid AMM testAMM([&](AMM& ammAlice, Env& env) { ammAlice.withdrawAll(alice); - ammAlice.deposit( - alice, 10'000, std::nullopt, std::nullopt, ter(terNO_AMM)); + ammAlice.deposit(alice, 10'000, std::nullopt, std::nullopt, ter(terNO_AMM)); }); // Globally frozen asset @@ -895,33 +638,10 @@ private: // If the issuer set global freeze, the holder cannot // deposit the other non-frozen token when AMMClawback is // enabled. - ammAlice.deposit( - carol, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - 1'000'000, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - XRP(100), - USD(100), - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, XRP(100), USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); }, std::nullopt, 0, @@ -940,50 +660,18 @@ private: else // Cannot deposit non-frozen token if the other token is // frozen when AMMClawback is enabled - ammAlice.deposit( - carol, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.deposit( - carol, - 1'000'000, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); env(trust(gw, carol["USD"](0), tfClearFreeze)); // Individually frozen AMM - env(trust( - gw, - STAmount{ - Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, - tfSetFreeze)); + env(trust(gw, STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, tfSetFreeze)); env.close(); // Can deposit non-frozen token ammAlice.deposit(carol, XRP(100)); - ammAlice.deposit( - carol, - 1'000'000, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); }, std::nullopt, 0, @@ -996,41 +684,15 @@ private: env(trust(gw, carol["USD"](0), tfSetFreeze)); env(trust(gw, carol["BTC"](0), tfSetFreeze)); env.close(); - ammAlice.deposit( - carol, - 1'000'000, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); env(trust(gw, carol["USD"](0), tfClearFreeze)); // Individually frozen AMM - env(trust( - gw, - STAmount{ - Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, - tfSetFreeze)); + env(trust(gw, STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, tfSetFreeze)); env.close(); // Cannot deposit non-frozen token - ammAlice.deposit( - carol, - 1'000'000, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - BTC(0.01), - std::nullopt, - std::nullopt, - ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), BTC(0.01), std::nullopt, std::nullopt, ter(tecFROZEN)); }, {{USD(20'000), BTC(0.5)}}); @@ -1055,21 +717,9 @@ private: // if featureAMMClawback is enabled, bob can not deposit XRP // because he's not authorized to hold the paired token // gw["USD"]. - amm.deposit( - bob, - XRP(10), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecNO_AUTH)); + amm.deposit(bob, XRP(10), std::nullopt, std::nullopt, std::nullopt, ter(tecNO_AUTH)); else - amm.deposit( - bob, - XRP(10), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tesSUCCESS)); + amm.deposit(bob, XRP(10), std::nullopt, std::nullopt, std::nullopt, ter(tesSUCCESS)); } // Insufficient XRP balance @@ -1078,26 +728,14 @@ private: env.close(); // Adds LPT trustline ammAlice.deposit(bob, XRP(10)); - ammAlice.deposit( - bob, - XRP(1'000), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecUNFUNDED_AMM)); + ammAlice.deposit(bob, XRP(1'000), std::nullopt, std::nullopt, std::nullopt, ter(tecUNFUNDED_AMM)); }); // Insufficient USD balance testAMM([&](AMM& ammAlice, Env& env) { fund(env, gw, {bob}, {USD(1'000)}, Fund::Acct); env.close(); - ammAlice.deposit( - bob, - USD(1'001), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecUNFUNDED_AMM)); + ammAlice.deposit(bob, USD(1'001), std::nullopt, std::nullopt, std::nullopt, ter(tecUNFUNDED_AMM)); }); // Insufficient USD balance by tokens @@ -1140,8 +778,7 @@ private: // Insufficient reserve, XRP/IOU { Env env(*this); - auto const starting_xrp = - reserve(env, 4) + env.current()->fees().base * 4; + auto const starting_xrp = reserve(env, 4) + env.current()->fees().base * 4; env.fund(XRP(10'000), gw); env.fund(XRP(10'000), alice); env.fund(starting_xrp, carol); @@ -1154,29 +791,16 @@ private: env(offer(carol, XRP(100), USD(101))); env(offer(carol, XRP(100), USD(102))); AMM ammAlice(env, alice, XRP(1'000), USD(1'000)); - ammAlice.deposit( - carol, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecINSUF_RESERVE_LINE)); + ammAlice.deposit(carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecINSUF_RESERVE_LINE)); env(offer(carol, XRP(100), USD(103))); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecINSUF_RESERVE_LINE)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecINSUF_RESERVE_LINE)); } // Insufficient reserve, IOU/IOU { Env env(*this); - auto const starting_xrp = - reserve(env, 4) + env.current()->fees().base * 4; + auto const starting_xrp = reserve(env, 4) + env.current()->fees().base * 4; env.fund(XRP(10'000), gw); env.fund(XRP(10'000), alice); env.fund(starting_xrp, carol); @@ -1193,22 +817,14 @@ private: env(offer(carol, XRP(100), USD(101))); env(offer(carol, XRP(100), USD(102))); AMM ammAlice(env, alice, XRP(1'000), USD(1'000)); - ammAlice.deposit( - carol, - XRP(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecINSUF_RESERVE_LINE)); + ammAlice.deposit(carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecINSUF_RESERVE_LINE)); } // Invalid min testAMM([&](AMM& ammAlice, Env& env) { // min tokens can't be <= zero - ammAlice.deposit( - carol, 0, XRP(100), tfSingleAsset, ter(temBAD_AMM_TOKENS)); - ammAlice.deposit( - carol, -1, XRP(100), tfSingleAsset, ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(carol, 0, XRP(100), tfSingleAsset, ter(temBAD_AMM_TOKENS)); + ammAlice.deposit(carol, -1, XRP(100), tfSingleAsset, ter(temBAD_AMM_TOKENS)); ammAlice.deposit( carol, 0, @@ -1333,49 +949,36 @@ private: // Equal deposit, tokens rounded to 0 testAMM([&](AMM& amm, Env& env) { - amm.deposit(DepositArg{ - .tokens = IOUAmount{1, -12}, - .err = ter(tecAMM_INVALID_TOKENS)}); + amm.deposit(DepositArg{.tokens = IOUAmount{1, -12}, .err = ter(tecAMM_INVALID_TOKENS)}); }); // Equal deposit limit, tokens rounded to 0 testAMM( [&](AMM& amm, Env& env) { amm.deposit(DepositArg{ - .asset1In = STAmount{USD, 1, -15}, - .asset2In = XRPAmount{1}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .asset1In = STAmount{USD, 1, -15}, .asset2In = XRPAmount{1}, .err = ter(tecAMM_INVALID_TOKENS)}); }, - {.pool = {{USD(1'000'000), XRP(1'000'000)}}, - .features = {features - fixAMMv1_3}}); + {.pool = {{USD(1'000'000), XRP(1'000'000)}}, .features = {features - fixAMMv1_3}}); testAMM([&](AMM& amm, Env& env) { amm.deposit(DepositArg{ - .asset1In = STAmount{USD, 1, -15}, - .asset2In = XRPAmount{1}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .asset1In = STAmount{USD, 1, -15}, .asset2In = XRPAmount{1}, .err = ter(tecAMM_INVALID_TOKENS)}); }); // Single deposit by asset, tokens rounded to 0 testAMM([&](AMM& amm, Env& env) { - amm.deposit(DepositArg{ - .asset1In = STAmount{USD, 1, -15}, - .err = ter(tecAMM_INVALID_TOKENS)}); + amm.deposit(DepositArg{.asset1In = STAmount{USD, 1, -15}, .err = ter(tecAMM_INVALID_TOKENS)}); }); // Single deposit by tokens, tokens rounded to 0 testAMM([&](AMM& amm, Env& env) { amm.deposit(DepositArg{ - .tokens = IOUAmount{1, -10}, - .asset1In = STAmount{USD, 1, -15}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .tokens = IOUAmount{1, -10}, .asset1In = STAmount{USD, 1, -15}, .err = ter(tecAMM_INVALID_TOKENS)}); }); - // Single deposit with eprice, tokens rounded to 0 + // Single deposit with EPrice, tokens rounded to 0 testAMM([&](AMM& amm, Env& env) { amm.deposit(DepositArg{ - .asset1In = STAmount{USD, 1, -15}, - .maxEP = STAmount{USD, 1, -1}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .asset1In = STAmount{USD, 1, -15}, .maxEP = STAmount{USD, 1, -1}, .err = ter(tecAMM_INVALID_TOKENS)}); }); } @@ -1384,38 +987,33 @@ private: { testcase("Deposit"); - using namespace jtx; auto const all = testable_amendments(); + using namespace jtx; // Equal deposit: 1000000 tokens, 10% of the current pool testAMM([&](AMM& ammAlice, Env& env) { auto const baseFee = env.current()->fees().base; ammAlice.deposit(carol, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); // 30,000 less deposited 1,000 BEAST_EXPECT(expectHolding(env, carol, USD(29'000))); // 30,000 less deposited 1,000 and 10 drops tx fee - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRPAmount{29'000'000'000 - baseFee})); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRPAmount{29'000'000'000 - baseFee})); }); // equal asset deposit: unit test to exercise the rounding-down of // LPTokens in the AMMHelpers.cpp: adjustLPTokens calculations // The LPTokens need to have 16 significant digits and a fractional part - for (Number const deltaLPTokens : - {Number{UINT64_C(100000'0000000009), -10}, - Number{UINT64_C(100000'0000000001), -10}}) + for (Number const& deltaLPTokens : + {Number{UINT64_C(100000'0000000009), -10}, Number{UINT64_C(100000'0000000001), -10}}) { testAMM([&](AMM& ammAlice, Env& env) { // initial LPToken balance IOUAmount const initLPToken = ammAlice.getLPTokensBalance(); - IOUAmount const newLPTokens{ - deltaLPTokens.mantissa(), deltaLPTokens.exponent()}; + IOUAmount const newLPTokens{deltaLPTokens}; // carol performs a two-asset deposit - ammAlice.deposit( - DepositArg{.account = carol, .tokens = newLPTokens}); + ammAlice.deposit(DepositArg{.account = carol, .tokens = newLPTokens}); IOUAmount const finalLPToken = ammAlice.getLPTokensBalance(); @@ -1436,24 +1034,18 @@ private: Number const deltaXRP = fr * 1e10; Number const deltaUSD = fr * 1e4; - STAmount const depositUSD = - STAmount{USD, deltaUSD.mantissa(), deltaUSD.exponent()}; + STAmount const depositUSD = STAmount{USD, deltaUSD}; - STAmount const depositXRP = - STAmount{XRP, deltaXRP.mantissa(), deltaXRP.exponent()}; + STAmount const depositXRP = STAmount{XRP, deltaXRP}; // initial LPTokens (1e7) + newLPTokens BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000) + depositXRP, - USD(10'000) + depositUSD, - IOUAmount{1, 7} + newLPTokens)); + XRP(10'000) + depositXRP, USD(10'000) + depositUSD, IOUAmount{1, 7} + newLPTokens)); // 30,000 less deposited depositUSD - BEAST_EXPECT( - expectHolding(env, carol, USD(30'000) - depositUSD)); + BEAST_EXPECT(expectHolding(env, carol, USD(30'000) - depositUSD)); // 30,000 less deposited depositXRP and 10 drops tx fee - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRP(30'000) - depositXRP - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(30'000) - depositXRP - txfee(env, 1))); }); } @@ -1464,85 +1056,66 @@ private: // Deposit 100USD/100XRP testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, USD(100), XRP(100)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); }); // Equal limit deposit. // Try to deposit 200USD/100XRP. Is truncated to 100USD/100XRP. testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, USD(200), XRP(100)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); }); // Try to deposit 100USD/200XRP. Is truncated to 100USD/100XRP. testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, USD(100), XRP(200)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'100), IOUAmount{10'100'000, 0})); }); // Single deposit: 1000 USD testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, USD(1'000)); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'999'99999999999), -11}, - IOUAmount{10'488'088'48170151, -8})); + XRP(10'000), STAmount{USD, UINT64_C(10'999'99999999999), -11}, IOUAmount{10'488'088'48170151, -8})); }); // Single deposit: 1000 XRP testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, XRP(1'000)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(10'000), IOUAmount{10'488'088'48170151, -8})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(10'000), IOUAmount{10'488'088'48170151, -8})); }); // Single deposit: 100000 tokens worth of USD testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, 100000, USD(205)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'201), IOUAmount{10'100'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'201), IOUAmount{10'100'000, 0})); }); // Single deposit: 100000 tokens worth of XRP - testAMM([&](AMM& ammAlice, Env&) { + testAMM([&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 100'000, XRP(205)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'201), USD(10'000), IOUAmount{10'100'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'201), USD(10'000), IOUAmount{10'100'000, 0})); }); // Single deposit with EP not exceeding specified: // 100USD with EP not to exceed 0.1 (AssetIn/TokensOut) testAMM([&](AMM& ammAlice, Env&) { - ammAlice.deposit( - carol, USD(1'000), std::nullopt, STAmount{USD, 1, -1}); + ammAlice.deposit(carol, USD(1'000), std::nullopt, STAmount{USD, 1, -1}); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'999'99999999999), -11}, - IOUAmount{10'488'088'48170151, -8})); + XRP(10'000), STAmount{USD, UINT64_C(10'999'99999999999), -11}, IOUAmount{10'488'088'48170151, -8})); }); // Single deposit with EP not exceeding specified: // 100USD with EP not to exceed 0.002004 (AssetIn/TokensOut) testAMM([&](AMM& ammAlice, Env&) { - ammAlice.deposit( - carol, USD(100), std::nullopt, STAmount{USD, 2004, -6}); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, 10'080'16, -2}, - IOUAmount{10'040'000, 0})); + ammAlice.deposit(carol, USD(100), std::nullopt, STAmount{USD, 2004, -6}); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), STAmount{USD, 10'080'16, -2}, IOUAmount{10'040'000, 0})); }); // Single deposit with EP not exceeding specified: // 0USD with EP not to exceed 0.002004 (AssetIn/TokensOut) testAMM([&](AMM& ammAlice, Env&) { - ammAlice.deposit( - carol, USD(0), std::nullopt, STAmount{USD, 2004, -6}); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, 10'080'16, -2}, - IOUAmount{10'040'000, 0})); + ammAlice.deposit(carol, USD(0), std::nullopt, STAmount{USD, 2004, -6}); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), STAmount{USD, 10'080'16, -2}, IOUAmount{10'040'000, 0})); }); // IOU to IOU + transfer fee @@ -1552,15 +1125,13 @@ private: env(rate(gw, 1.25)); env.close(); AMM ammAlice(env, alice, USD(20'000), BTC(0.5)); - BEAST_EXPECT(ammAlice.expectBalances( - USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); BEAST_EXPECT(expectHolding(env, alice, USD(0))); BEAST_EXPECT(expectHolding(env, alice, BTC(0))); fund(env, gw, {carol}, {USD(2'000), BTC(0.05)}, Fund::Acct); // no transfer fee on deposit ammAlice.deposit(carol, 10); - BEAST_EXPECT(ammAlice.expectBalances( - USD(22'000), BTC(0.55), IOUAmount{110, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(22'000), BTC(0.55), IOUAmount{110, 0})); BEAST_EXPECT(expectHolding(env, carol, USD(0))); BEAST_EXPECT(expectHolding(env, carol, BTC(0))); } @@ -1569,25 +1140,19 @@ private: testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, IOUAmount{1, -3}); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'000'000'001}, - STAmount{USD, UINT64_C(10'000'000001), -6}, - IOUAmount{10'000'000'001, -3})); + XRPAmount{10'000'000'001}, STAmount{USD, UINT64_C(10'000'000001), -6}, IOUAmount{10'000'000'001, -3})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{1, -3})); }); testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, XRPAmount{1}); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'000'000'001}, - USD(10'000), - IOUAmount{1'000'000'000049999, -8})); + BEAST_EXPECT( + ammAlice.expectBalances(XRPAmount{10'000'000'001}, USD(10'000), IOUAmount{1'000'000'000049999, -8})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{49999, -8})); }); testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, STAmount{USD, 1, -10}); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'000'00000000008), -11}, - IOUAmount{10'000'000'00000004, -8})); + XRP(10'000), STAmount{USD, UINT64_C(10'000'00000000008), -11}, IOUAmount{10'000'000'00000004, -8})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{4, -8})); }); @@ -1597,88 +1162,48 @@ private: Env env(*this, feat); env.fund(XRP(30000), gw); AMM ammGw(env, gw, XRP(10'000), USD(10'000)); - BEAST_EXPECT( - ammGw.expectBalances(XRP(10'000), USD(10'000), ammGw.tokens())); + BEAST_EXPECT(ammGw.expectBalances(XRP(10'000), USD(10'000), ammGw.tokens())); ammGw.deposit(gw, 1'000'000); - BEAST_EXPECT(ammGw.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000})); + BEAST_EXPECT(ammGw.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000})); ammGw.deposit(gw, USD(1'000)); BEAST_EXPECT(ammGw.expectBalances( - XRP(11'000), - STAmount{USD, UINT64_C(11'999'99999999998), -11}, - IOUAmount{11'489'125'29307605, -8})); + XRP(11'000), STAmount{USD, UINT64_C(11'999'99999999998), -11}, IOUAmount{11'489'125'29307605, -8})); } // Issuer deposit testAMM([&](AMM& ammAlice, Env& env) { ammAlice.deposit(gw, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000})); ammAlice.deposit(gw, USD(1'000)); BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), - STAmount{USD, UINT64_C(11'999'99999999998), -11}, - IOUAmount{11'489'125'29307605, -8})); + XRP(11'000), STAmount{USD, UINT64_C(11'999'99999999998), -11}, IOUAmount{11'489'125'29307605, -8})); }); // Min deposit testAMM([&](AMM& ammAlice, Env& env) { // Equal deposit by tokens ammAlice.deposit( - carol, - 1'000'000, - XRP(1'000), - USD(1'000), - std::nullopt, - tfLPToken, - std::nullopt, - std::nullopt); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + carol, 1'000'000, XRP(1'000), USD(1'000), std::nullopt, tfLPToken, std::nullopt, std::nullopt); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); }); testAMM([&](AMM& ammAlice, Env& env) { // Equal deposit by asset ammAlice.deposit( - carol, - 1'000'000, - XRP(1'000), - USD(1'000), - std::nullopt, - tfTwoAsset, - std::nullopt, - std::nullopt); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + carol, 1'000'000, XRP(1'000), USD(1'000), std::nullopt, tfTwoAsset, std::nullopt, std::nullopt); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); }); testAMM([&](AMM& ammAlice, Env& env) { // Single deposit by asset ammAlice.deposit( - carol, - 488'088, - XRP(1'000), - std::nullopt, - std::nullopt, - tfSingleAsset, - std::nullopt, - std::nullopt); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(10'000), IOUAmount{10'488'088'48170151, -8})); + carol, 488'088, XRP(1'000), std::nullopt, std::nullopt, tfSingleAsset, std::nullopt, std::nullopt); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(10'000), IOUAmount{10'488'088'48170151, -8})); }); testAMM([&](AMM& ammAlice, Env& env) { // Single deposit by asset ammAlice.deposit( - carol, - 488'088, - USD(1'000), - std::nullopt, - std::nullopt, - tfSingleAsset, - std::nullopt, - std::nullopt); + carol, 488'088, USD(1'000), std::nullopt, std::nullopt, tfSingleAsset, std::nullopt, std::nullopt); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'999'99999999999), -11}, - IOUAmount{10'488'088'48170151, -8})); + XRP(10'000), STAmount{USD, UINT64_C(10'999'99999999999), -11}, IOUAmount{10'488'088'48170151, -8})); }); } @@ -1687,8 +1212,8 @@ private: { testcase("Invalid Withdraw"); - using namespace jtx; auto const all = testable_amendments(); + using namespace jtx; testAMM( [&](AMM& ammAlice, Env& env) { @@ -1766,96 +1291,26 @@ private: NotTEC>> invalidOptions = { // tokens, asset1Out, asset2Out, EPrice, flags, ter - {std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - temMALFORMED}, - {std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - tfSingleAsset | tfTwoAsset, - temMALFORMED}, - {1'000, - std::nullopt, - std::nullopt, - std::nullopt, - tfWithdrawAll, - temMALFORMED}, - {std::nullopt, - USD(0), - XRP(100), - std::nullopt, - tfWithdrawAll | tfLPToken, - temMALFORMED}, - {std::nullopt, - std::nullopt, - USD(100), - std::nullopt, - tfWithdrawAll, - temMALFORMED}, + {std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, temMALFORMED}, + {std::nullopt, std::nullopt, std::nullopt, std::nullopt, tfSingleAsset | tfTwoAsset, temMALFORMED}, + {1'000, std::nullopt, std::nullopt, std::nullopt, tfWithdrawAll, temMALFORMED}, + {std::nullopt, USD(0), XRP(100), std::nullopt, tfWithdrawAll | tfLPToken, temMALFORMED}, + {std::nullopt, std::nullopt, USD(100), std::nullopt, tfWithdrawAll, temMALFORMED}, {std::nullopt, std::nullopt, std::nullopt, std::nullopt, tfWithdrawAll | tfOneAssetWithdrawAll, temMALFORMED}, - {std::nullopt, - USD(100), - std::nullopt, - std::nullopt, - tfWithdrawAll, - temMALFORMED}, - {std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - tfOneAssetWithdrawAll, - temMALFORMED}, - {1'000, - std::nullopt, - USD(100), - std::nullopt, - std::nullopt, - temMALFORMED}, - {std::nullopt, - std::nullopt, - std::nullopt, - IOUAmount{250, 0}, - tfWithdrawAll, - temMALFORMED}, - {1'000, - std::nullopt, - std::nullopt, - IOUAmount{250, 0}, - std::nullopt, - temMALFORMED}, - {std::nullopt, - std::nullopt, - USD(100), - IOUAmount{250, 0}, - std::nullopt, - temMALFORMED}, - {std::nullopt, - XRP(100), - USD(100), - IOUAmount{250, 0}, - std::nullopt, - temMALFORMED}, - {1'000, - XRP(100), - USD(100), - std::nullopt, - std::nullopt, - temMALFORMED}, - {std::nullopt, - XRP(100), - USD(100), - std::nullopt, - tfWithdrawAll, - temMALFORMED}}; + {std::nullopt, USD(100), std::nullopt, std::nullopt, tfWithdrawAll, temMALFORMED}, + {std::nullopt, std::nullopt, std::nullopt, std::nullopt, tfOneAssetWithdrawAll, temMALFORMED}, + {1'000, std::nullopt, USD(100), std::nullopt, std::nullopt, temMALFORMED}, + {std::nullopt, std::nullopt, std::nullopt, IOUAmount{250, 0}, tfWithdrawAll, temMALFORMED}, + {1'000, std::nullopt, std::nullopt, IOUAmount{250, 0}, std::nullopt, temMALFORMED}, + {std::nullopt, std::nullopt, USD(100), IOUAmount{250, 0}, std::nullopt, temMALFORMED}, + {std::nullopt, XRP(100), USD(100), IOUAmount{250, 0}, std::nullopt, temMALFORMED}, + {1'000, XRP(100), USD(100), std::nullopt, std::nullopt, temMALFORMED}, + {std::nullopt, XRP(100), USD(100), std::nullopt, tfWithdrawAll, temMALFORMED}}; for (auto const& it : invalidOptions) { ammAlice.withdraw( @@ -1871,69 +1326,27 @@ private: } // Invalid tokens - ammAlice.withdraw( - alice, 0, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); - ammAlice.withdraw( - alice, - IOUAmount{-1}, - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.withdraw(alice, 0, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); + ammAlice.withdraw(alice, IOUAmount{-1}, std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); // Mismatched token, invalid Asset1Out issue - ammAlice.withdraw( - alice, - GBP(100), - std::nullopt, - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.withdraw(alice, GBP(100), std::nullopt, std::nullopt, ter(temBAD_AMM_TOKENS)); // Mismatched token, invalid Asset2Out issue - ammAlice.withdraw( - alice, - USD(100), - GBP(100), - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.withdraw(alice, USD(100), GBP(100), std::nullopt, ter(temBAD_AMM_TOKENS)); // Mismatched token, Asset1Out.issue == Asset2Out.issue - ammAlice.withdraw( - alice, - USD(100), - USD(100), - std::nullopt, - ter(temBAD_AMM_TOKENS)); + ammAlice.withdraw(alice, USD(100), USD(100), std::nullopt, ter(temBAD_AMM_TOKENS)); // Invalid amount value - ammAlice.withdraw( - alice, USD(0), std::nullopt, std::nullopt, ter(temBAD_AMOUNT)); - ammAlice.withdraw( - alice, - USD(-100), - std::nullopt, - std::nullopt, - ter(temBAD_AMOUNT)); - ammAlice.withdraw( - alice, - USD(10), - std::nullopt, - IOUAmount{-1}, - ter(temBAD_AMOUNT)); + ammAlice.withdraw(alice, USD(0), std::nullopt, std::nullopt, ter(temBAD_AMOUNT)); + ammAlice.withdraw(alice, USD(-100), std::nullopt, std::nullopt, ter(temBAD_AMOUNT)); + ammAlice.withdraw(alice, USD(10), std::nullopt, IOUAmount{-1}, ter(temBAD_AMOUNT)); // Invalid amount/token value, withdraw all tokens from one side // of the pool. - ammAlice.withdraw( - alice, - USD(10'000), - std::nullopt, - std::nullopt, - ter(tecAMM_BALANCE)); - ammAlice.withdraw( - alice, - XRP(10'000), - std::nullopt, - std::nullopt, - ter(tecAMM_BALANCE)); + ammAlice.withdraw(alice, USD(10'000), std::nullopt, std::nullopt, ter(tecAMM_BALANCE)); + ammAlice.withdraw(alice, XRP(10'000), std::nullopt, std::nullopt, ter(tecAMM_BALANCE)); ammAlice.withdraw( alice, std::nullopt, @@ -1946,12 +1359,7 @@ private: ter(tecAMM_BALANCE)); // Bad currency - ammAlice.withdraw( - alice, - BAD(100), - std::nullopt, - std::nullopt, - ter(temBAD_CURRENCY)); + ammAlice.withdraw(alice, BAD(100), std::nullopt, std::nullopt, ter(temBAD_CURRENCY)); // Invalid Account Account bad("bad"); @@ -1980,31 +1388,15 @@ private: ter(terNO_AMM)); // Carol is not a Liquidity Provider - ammAlice.withdraw( - carol, 10'000, std::nullopt, std::nullopt, ter(tecAMM_BALANCE)); + ammAlice.withdraw(carol, 10'000, std::nullopt, std::nullopt, ter(tecAMM_BALANCE)); // Withdrawing from one side. // XRP by tokens - ammAlice.withdraw( - alice, - IOUAmount(9'999'999'9999, -4), - XRP(0), - std::nullopt, - ter(tecAMM_BALANCE)); + ammAlice.withdraw(alice, IOUAmount(9'999'999'9999, -4), XRP(0), std::nullopt, ter(tecAMM_BALANCE)); // USD by tokens - ammAlice.withdraw( - alice, - IOUAmount(9'999'999'9, -1), - USD(0), - std::nullopt, - ter(tecAMM_BALANCE)); + ammAlice.withdraw(alice, IOUAmount(9'999'999'9, -1), USD(0), std::nullopt, ter(tecAMM_BALANCE)); // XRP - ammAlice.withdraw( - alice, - XRP(10'000), - std::nullopt, - std::nullopt, - ter(tecAMM_BALANCE)); + ammAlice.withdraw(alice, XRP(10'000), std::nullopt, std::nullopt, ter(tecAMM_BALANCE)); // USD ammAlice.withdraw( alice, @@ -2023,17 +1415,10 @@ private: // while leaving a tiny amount in USD pool. // Post-amendment: // Most of the pool is withdrawn with remaining tiny amounts - auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) - : ter(tecAMM_BALANCE); - ammAlice.withdraw( - alice, - IOUAmount{9'999'999'9999, -4}, - std::nullopt, - std::nullopt, - err); + auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) : ter(tecAMM_BALANCE); + ammAlice.withdraw(alice, IOUAmount{9'999'999'9999, -4}, std::nullopt, std::nullopt, err); if (env.enabled(fixAMMv1_3)) - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(1), STAmount{USD, 1, -7}, IOUAmount{1, -4})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount(1), STAmount{USD, 1, -7}, IOUAmount{1, -4})); }, std::nullopt, 0, @@ -2048,17 +1433,10 @@ private: // Equal withdraw but due to XRP precision limit, // this results in full withdraw of XRP pool only, // while leaving a tiny amount in USD pool. - auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) - : ter(tecAMM_BALANCE); - ammAlice.withdraw( - alice, - IOUAmount{9'999'999'999999999, -9}, - std::nullopt, - std::nullopt, - err); + auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) : ter(tecAMM_BALANCE); + ammAlice.withdraw(alice, IOUAmount{9'999'999'999999999, -9}, std::nullopt, std::nullopt, err); if (env.enabled(fixAMMv1_3)) - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(1), STAmount{USD, 1, -11}, IOUAmount{1, -8})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount(1), STAmount{USD, 1, -11}, IOUAmount{1, -8})); }, std::nullopt, 0, @@ -2068,8 +1446,7 @@ private: // Invalid AMM testAMM([&](AMM& ammAlice, Env& env) { ammAlice.withdrawAll(alice); - ammAlice.withdraw( - alice, 10'000, std::nullopt, std::nullopt, ter(terNO_AMM)); + ammAlice.withdraw(alice, 10'000, std::nullopt, std::nullopt, ter(terNO_AMM)); }); // Globally frozen asset @@ -2078,10 +1455,8 @@ private: env.close(); // Can withdraw non-frozen token ammAlice.withdraw(alice, XRP(100)); - ammAlice.withdraw( - alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw( - alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); }); // Individually frozen (AMM) account @@ -2090,22 +1465,15 @@ private: env.close(); // Can withdraw non-frozen token ammAlice.withdraw(alice, XRP(100)); - ammAlice.withdraw( - alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw( - alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); env(trust(gw, alice["USD"](0), tfClearFreeze)); // Individually frozen AMM - env(trust( - gw, - STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, - tfSetFreeze)); + env(trust(gw, STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, tfSetFreeze)); // Can withdraw non-frozen token ammAlice.withdraw(alice, XRP(100)); - ammAlice.withdraw( - alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw( - alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt, ter(tecFROZEN)); }); // Carol withdraws more than she owns @@ -2113,17 +1481,10 @@ private: // Single deposit of 100000 worth of tokens, // which is 10% of the pool. Carol is LP now. ammAlice.deposit(carol, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); - ammAlice.withdraw( - carol, - 2'000'000, - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + ammAlice.withdraw(carol, 2'000'000, std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); }); // Withdraw with EPrice limit. Fails to withdraw, calculated tokens @@ -2131,11 +1492,8 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 1'000'000); - auto const err = env.enabled(fixAMMv1_3) - ? ter(tecAMM_INVALID_TOKENS) - : ter(tecAMM_FAILED); - ammAlice.withdraw( - carol, USD(100), std::nullopt, IOUAmount{500, 0}, err); + auto const err = env.enabled(fixAMMv1_3) ? ter(tecAMM_INVALID_TOKENS) : ter(tecAMM_FAILED); + ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{500, 0}, err); }, std::nullopt, 0, @@ -2146,48 +1504,28 @@ private: // to withdraw are greater than the LP shares. testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw( - carol, - USD(100), - std::nullopt, - IOUAmount{600, 0}, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{600, 0}, ter(tecAMM_INVALID_TOKENS)); }); // Withdraw with EPrice limit. Fails to withdraw, amount1 // to withdraw is less than 1700USD. testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw( - carol, - USD(1'700), - std::nullopt, - IOUAmount{520, 0}, - ter(tecAMM_FAILED)); + ammAlice.withdraw(carol, USD(1'700), std::nullopt, IOUAmount{520, 0}, ter(tecAMM_FAILED)); }); // Deposit/Withdraw the same amount with the trading fee testAMM( [&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, USD(1'000)); - ammAlice.withdraw( - carol, - USD(1'000), - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, USD(1'000), std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); }, std::nullopt, 1'000); testAMM( [&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, XRP(1'000)); - ammAlice.withdraw( - carol, - XRP(1'000), - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, XRP(1'000), std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); }, std::nullopt, 1'000); @@ -2195,70 +1533,33 @@ private: // Deposit/Withdraw the same amount fails due to the tokens adjustment testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, STAmount{USD, 1, -6}); - ammAlice.withdraw( - carol, - STAmount{USD, 1, -6}, - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, STAmount{USD, 1, -6}, std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); }); // Withdraw close to one side of the pool. Account's LP tokens // are rounded to all LP tokens. testAMM( [&](AMM& ammAlice, Env& env) { - auto const err = env.enabled(fixAMMv1_3) - ? ter(tecINVARIANT_FAILED) - : ter(tecAMM_BALANCE); + auto const err = env.enabled(fixAMMv1_3) ? ter(tecINVARIANT_FAILED) : ter(tecAMM_BALANCE); ammAlice.withdraw( - alice, - STAmount{USD, UINT64_C(9'999'999999999999), -12}, - std::nullopt, - std::nullopt, - err); + alice, STAmount{USD, UINT64_C(9'999'999999999999), -12}, std::nullopt, std::nullopt, err); }, {.features = {all, all - fixAMMv1_3}, .noLog = true}); // Tiny withdraw testAMM([&](AMM& ammAlice, Env&) { // XRP amount to withdraw is 0 - ammAlice.withdraw( - alice, - IOUAmount{1, -5}, - std::nullopt, - std::nullopt, - ter(tecAMM_FAILED)); + ammAlice.withdraw(alice, IOUAmount{1, -5}, std::nullopt, std::nullopt, ter(tecAMM_FAILED)); // Calculated tokens to withdraw are 0 - ammAlice.withdraw( - alice, - std::nullopt, - STAmount{USD, 1, -11}, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(alice, std::nullopt, STAmount{USD, 1, -11}, std::nullopt, ter(tecAMM_INVALID_TOKENS)); ammAlice.deposit(carol, STAmount{USD, 1, -10}); - ammAlice.withdraw( - carol, - std::nullopt, - STAmount{USD, 1, -9}, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); - ammAlice.withdraw( - carol, - std::nullopt, - XRPAmount{1}, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, std::nullopt, STAmount{USD, 1, -9}, std::nullopt, ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(carol, std::nullopt, XRPAmount{1}, std::nullopt, ter(tecAMM_INVALID_TOKENS)); + ammAlice.withdraw(WithdrawArg{.tokens = IOUAmount{1, -10}, .err = ter(tecAMM_INVALID_TOKENS)}); ammAlice.withdraw(WithdrawArg{ - .tokens = IOUAmount{1, -10}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .asset1Out = STAmount{USD, 1, -15}, .asset2Out = XRPAmount{1}, .err = ter(tecAMM_INVALID_TOKENS)}); ammAlice.withdraw(WithdrawArg{ - .asset1Out = STAmount{USD, 1, -15}, - .asset2Out = XRPAmount{1}, - .err = ter(tecAMM_INVALID_TOKENS)}); - ammAlice.withdraw(WithdrawArg{ - .tokens = IOUAmount{1, -10}, - .asset1Out = STAmount{USD, 1, -15}, - .err = ter(tecAMM_INVALID_TOKENS)}); + .tokens = IOUAmount{1, -10}, .asset1Out = STAmount{USD, 1, -15}, .err = ter(tecAMM_INVALID_TOKENS)}); }); } @@ -2267,8 +1568,8 @@ private: { testcase("Withdraw"); - using namespace jtx; auto const all = testable_amendments(); + using namespace jtx; // Equal withdrawal by Carol: 1000000 of tokens, 10% of the current // pool @@ -2277,31 +1578,25 @@ private: // Single deposit of 100000 worth of tokens, // which is 10% of the pool. Carol is LP now. ammAlice.deposit(carol, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); - BEAST_EXPECT( - ammAlice.expectLPTokens(carol, IOUAmount{1'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0})); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{1'000'000, 0})); // 30,000 less deposited 1,000 BEAST_EXPECT(expectHolding(env, carol, USD(29'000))); // 30,000 less deposited 1,000 and 10 drops tx fee - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRPAmount{29'000'000'000 - baseFee})); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRPAmount{29'000'000'000 - baseFee})); // Carol withdraws all tokens ammAlice.withdraw(carol, 1'000'000); - BEAST_EXPECT( - ammAlice.expectLPTokens(carol, IOUAmount(beast::Zero()))); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount(beast::Zero()))); BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); - BEAST_EXPECT(expectLedgerEntryRoot( - env, carol, XRPAmount{30'000'000'000 - 2 * baseFee})); + BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRPAmount{30'000'000'000 - 2 * baseFee})); }); // Equal withdrawal by tokens 1000000, 10% // of the current pool testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, 1'000'000); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(9'000), USD(9'000), IOUAmount{9'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(9'000), USD(9'000), IOUAmount{9'000'000, 0})); }); // Equal withdrawal with a limit. Withdraw XRP200. @@ -2311,15 +1606,13 @@ private: // in this case - XRP100/USD100. testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, XRP(200), USD(100)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(9'900), USD(9'900), IOUAmount{9'900'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(9'900), USD(9'900), IOUAmount{9'900'000, 0})); }); // Equal withdrawal with a limit. XRP100/USD100. testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, XRP(100), USD(200)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(9'900), USD(9'900), IOUAmount{9'900'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(9'900), USD(9'900), IOUAmount{9'900'000, 0})); }); // Single withdrawal by amount XRP1000 @@ -2327,15 +1620,10 @@ private: [&](AMM& ammAlice, Env& env) { ammAlice.withdraw(alice, XRP(1'000)); if (!env.enabled(fixAMMv1_3)) - BEAST_EXPECT(ammAlice.expectBalances( - XRP(9'000), - USD(10'000), - IOUAmount{9'486'832'98050514, -8})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(9'000), USD(10'000), IOUAmount{9'486'832'98050514, -8})); else BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{9'000'000'001}, - USD(10'000), - IOUAmount{9'486'832'98050514, -8})); + XRPAmount{9'000'000'001}, USD(10'000), IOUAmount{9'486'832'98050514, -8})); }, std::nullopt, 0, @@ -2345,19 +1633,14 @@ private: // Single withdrawal by tokens 10000. testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, 10'000, USD(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(9980.01), IOUAmount{9'990'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(9980.01), IOUAmount{9'990'000, 0})); }); // Withdraw all tokens. testAMM([&](AMM& ammAlice, Env& env) { env(trust(carol, STAmount{ammAlice.lptIssue(), 10'000})); // Can SetTrust only for AMM LP tokens - env(trust( - carol, - STAmount{ - Issue{EUR.currency, ammAlice.ammAccount()}, 10'000}), - ter(tecNO_PERMISSION)); + env(trust(carol, STAmount{Issue{EUR.currency, ammAlice.ammAccount()}, 10'000}), ter(tecNO_PERMISSION)); env.close(); ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); @@ -2366,18 +1649,15 @@ private: // Can create AMM for the XRP/USD pair AMM ammCarol(env, carol, XRP(10'000), USD(10'000)); - BEAST_EXPECT(ammCarol.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammCarol.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); }); // Single deposit 1000USD, withdraw all tokens in USD testAMM([&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, USD(1'000)); ammAlice.withdrawAll(carol, USD(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); - BEAST_EXPECT( - ammAlice.expectLPTokens(carol, IOUAmount(beast::Zero()))); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount(beast::Zero()))); }); // Single deposit 1000USD, withdraw all tokens in XRP @@ -2385,9 +1665,7 @@ private: ammAlice.deposit(carol, USD(1'000)); ammAlice.withdrawAll(carol, XRP(0)); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(9'090'909'091), - STAmount{USD, UINT64_C(10'999'99999999999), -11}, - IOUAmount{10'000'000, 0})); + XRPAmount(9'090'909'091), STAmount{USD, UINT64_C(10'999'99999999999), -11}, IOUAmount{10'000'000, 0})); }); // Single deposit/withdraw by the same account @@ -2403,13 +1681,9 @@ private: lpTokens = ammAlice.deposit(carol, XRPAmount(1)); ammAlice.withdraw(carol, lpTokens, XRPAmount(0)); if (!env.enabled(fixAMMv1_3)) - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); else - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(10'000'000'001), - USD(10'000), - ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount(10'000'000'001), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); }, std::nullopt, @@ -2424,8 +1698,7 @@ private: auto const aliceTokens = ammAlice.deposit(alice, USD(1'000)); ammAlice.withdraw(alice, aliceTokens, USD(0)); ammAlice.withdraw(carol, carolTokens, USD(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); BEAST_EXPECT(ammAlice.expectLPTokens(alice, ammAlice.tokens())); }); @@ -2434,8 +1707,7 @@ private: testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, 1'000'000); ammAlice.withdrawAll(carol); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0})); }); // Equal deposit 10%, withdraw all tokens in USD @@ -2443,29 +1715,22 @@ private: ammAlice.deposit(carol, 1'000'000); ammAlice.withdrawAll(carol, USD(0)); BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), - STAmount{USD, UINT64_C(9'090'909090909092), -12}, - IOUAmount{10'000'000, 0})); + XRP(11'000), STAmount{USD, UINT64_C(9'090'909090909092), -12}, IOUAmount{10'000'000, 0})); }); // Equal deposit 10%, withdraw all tokens in XRP testAMM([&](AMM& ammAlice, Env&) { ammAlice.deposit(carol, 1'000'000); ammAlice.withdrawAll(carol, XRP(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(9'090'909'091), - USD(11'000), - IOUAmount{10'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount(9'090'909'091), USD(11'000), IOUAmount{10'000'000, 0})); }); // Withdraw with EPrice limit. testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw( - carol, USD(100), std::nullopt, IOUAmount{520, 0}); - BEAST_EXPECT(ammAlice.expectLPTokens( - carol, IOUAmount{153'846'15384616, -8})); + ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{520, 0}); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{153'846'15384616, -8})); if (!env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(11'000'000'000), @@ -2484,17 +1749,14 @@ private: ammAlice.withdrawAll(carol); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); }, - {.features = {all, all - fixAMMv1_3, all - fixAMMv1_1 - fixAMMv1_3}, - .noLog = true}); + {.features = {all, all - fixAMMv1_3, all - fixAMMv1_1 - fixAMMv1_3}, .noLog = true}); // Withdraw with EPrice limit. AssetOut is 0. testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw( - carol, USD(0), std::nullopt, IOUAmount{520, 0}); - BEAST_EXPECT(ammAlice.expectLPTokens( - carol, IOUAmount{153'846'15384616, -8})); + ammAlice.withdraw(carol, USD(0), std::nullopt, IOUAmount{520, 0}); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{153'846'15384616, -8})); if (!env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) BEAST_EXPECT(ammAlice.expectBalances( XRP(11'000), @@ -2524,21 +1786,18 @@ private: env.close(); // no transfer fee on create AMM ammAlice(env, alice, USD(20'000), BTC(0.5)); - BEAST_EXPECT(ammAlice.expectBalances( - USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); BEAST_EXPECT(expectHolding(env, alice, USD(0))); BEAST_EXPECT(expectHolding(env, alice, BTC(0))); fund(env, gw, {carol}, {USD(2'000), BTC(0.05)}, Fund::Acct); // no transfer fee on deposit ammAlice.deposit(carol, 10); - BEAST_EXPECT(ammAlice.expectBalances( - USD(22'000), BTC(0.55), IOUAmount{110, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(22'000), BTC(0.55), IOUAmount{110, 0})); BEAST_EXPECT(expectHolding(env, carol, USD(0))); BEAST_EXPECT(expectHolding(env, carol, BTC(0))); // no transfer fee on withdraw ammAlice.withdraw(carol, 10); - BEAST_EXPECT(ammAlice.expectBalances( - USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0, 0})); BEAST_EXPECT(expectHolding(env, carol, USD(2'000))); BEAST_EXPECT(expectHolding(env, carol, BTC(0.05))); @@ -2549,24 +1808,17 @@ private: // By tokens ammAlice.withdraw(alice, IOUAmount{1, -3}); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{9'999'999'999}, - STAmount{USD, UINT64_C(9'999'999999), -6}, - IOUAmount{9'999'999'999, -3})); + XRPAmount{9'999'999'999}, STAmount{USD, UINT64_C(9'999'999999), -6}, IOUAmount{9'999'999'999, -3})); }); testAMM( [&](AMM& ammAlice, Env& env) { // Single XRP pool ammAlice.withdraw(alice, std::nullopt, XRPAmount{1}); if (!env.enabled(fixAMMv1_3)) - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{9'999'999'999}, - USD(10'000), - IOUAmount{9'999'999'9995, -4})); + BEAST_EXPECT( + ammAlice.expectBalances(XRPAmount{9'999'999'999}, USD(10'000), IOUAmount{9'999'999'9995, -4})); else - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - USD(10'000), - IOUAmount{9'999'999'9995, -4})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{9'999'999'9995, -4})); }, std::nullopt, 0, @@ -2576,42 +1828,34 @@ private: // Single USD pool ammAlice.withdraw(alice, std::nullopt, STAmount{USD, 1, -10}); BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(9'999'9999999999), -10}, - IOUAmount{9'999'999'99999995, -8})); + XRP(10'000), STAmount{USD, UINT64_C(9'999'9999999999), -10}, IOUAmount{9'999'999'99999995, -8})); }); // Withdraw close to entire pool // Equal by tokens testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, IOUAmount{9'999'999'999, -3}); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{1}, STAmount{USD, 1, -6}, IOUAmount{1, -3})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{1}, STAmount{USD, 1, -6}, IOUAmount{1, -3})); }); // USD by tokens testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, IOUAmount{9'999'999}, USD(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), STAmount{USD, 1, -10}, IOUAmount{1})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), STAmount{USD, 1, -10}, IOUAmount{1})); }); // XRP by tokens testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, IOUAmount{9'999'900}, XRP(0)); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{1}, USD(10'000), IOUAmount{100})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{1}, USD(10'000), IOUAmount{100})); }); // USD testAMM([&](AMM& ammAlice, Env&) { - ammAlice.withdraw( - alice, STAmount{USD, UINT64_C(9'999'99999999999), -11}); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10000), STAmount{USD, 1, -11}, IOUAmount{316227765, -9})); + ammAlice.withdraw(alice, STAmount{USD, UINT64_C(9'999'99999999999), -11}); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10000), STAmount{USD, 1, -11}, IOUAmount{316227765, -9})); }); // XRP testAMM([&](AMM& ammAlice, Env&) { ammAlice.withdraw(alice, XRPAmount{9'999'999'999}); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{1}, USD(10'000), IOUAmount{100})); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{1}, USD(10'000), IOUAmount{100})); }); } @@ -2623,64 +1867,28 @@ private: testAMM([&](AMM& ammAlice, Env& env) { // Invalid flags - ammAlice.vote( - std::nullopt, - 1'000, - tfWithdrawAll, - std::nullopt, - std::nullopt, - ter(temINVALID_FLAG)); + ammAlice.vote(std::nullopt, 1'000, tfWithdrawAll, std::nullopt, std::nullopt, ter(temINVALID_FLAG)); // Invalid fee. - ammAlice.vote( - std::nullopt, - 1'001, - std::nullopt, - std::nullopt, - std::nullopt, - ter(temBAD_FEE)); + ammAlice.vote(std::nullopt, 1'001, std::nullopt, std::nullopt, std::nullopt, ter(temBAD_FEE)); BEAST_EXPECT(ammAlice.expectTradingFee(0)); // Invalid Account Account bad("bad"); env.memoize(bad); - ammAlice.vote( - bad, - 1'000, - std::nullopt, - seq(1), - std::nullopt, - ter(terNO_ACCOUNT)); + ammAlice.vote(bad, 1'000, std::nullopt, seq(1), std::nullopt, ter(terNO_ACCOUNT)); // Invalid AMM - ammAlice.vote( - alice, - 1'000, - std::nullopt, - std::nullopt, - {{USD, GBP}}, - ter(terNO_AMM)); + ammAlice.vote(alice, 1'000, std::nullopt, std::nullopt, {{USD, GBP}}, ter(terNO_AMM)); // Account is not LP - ammAlice.vote( - carol, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecAMM_INVALID_TOKENS)); + ammAlice.vote(carol, 1'000, std::nullopt, std::nullopt, std::nullopt, ter(tecAMM_INVALID_TOKENS)); }); // Invalid AMM testAMM([&](AMM& ammAlice, Env& env) { ammAlice.withdrawAll(alice); - ammAlice.vote( - alice, - 1'000, - std::nullopt, - std::nullopt, - std::nullopt, - ter(terNO_AMM)); + ammAlice.vote(alice, 1'000, std::nullopt, std::nullopt, std::nullopt, ter(terNO_AMM)); }); } @@ -2688,8 +1896,8 @@ private: testFeeVote() { testcase("Fee Vote"); - using namespace jtx; auto const all = testable_amendments(); + using namespace jtx; // One vote sets fee to 1%. testAMM([&](AMM& ammAlice, Env& env) { @@ -2837,7 +2045,7 @@ private: BEAST_EXPECT(amm.expectAuctionSlot(100, 0, IOUAmount{0})); // gw burns all but one of its LPTokens through a bid transaction - // this transaction suceeds because the bid price is less than + // this transaction succeeds because the bid price is less than // the total outstanding LPToken balance env(amm.bid({ .account = gw, @@ -2850,8 +2058,7 @@ private: BEAST_EXPECT(amm.expectAuctionSlot(100, 0, IOUAmount{999'999})); // 999'999 tokens are burned, only 1 LPToken is owned by gw - BEAST_EXPECT( - amm.expectBalances(XRP(1'000), USD(1'000), IOUAmount{1})); + BEAST_EXPECT(amm.expectBalances(XRP(1'000), USD(1'000), IOUAmount{1})); // gw owns only 1 LPToken in its balance BEAST_EXPECT(Number{amm.getLPTokensBalance(gw)} == 1); @@ -2891,7 +2098,7 @@ private: ter(temBAD_AMOUNT)); } - // Invlaid Min/Max combination + // Invalid Min/Max combination env(ammAlice.bid({ .account = carol, .bidMin = 200, @@ -3033,6 +2240,10 @@ private: using namespace jtx; using namespace std::chrono; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + features = features - featureSingleAssetVault - featureLendingProtocol; + // Auction slot initially is owned by AMM creator, who pays 0 price. // Bid 110 tokens. Pay bidMin. @@ -3042,8 +2253,7 @@ private: env(ammAlice.bid({.account = carol, .bidMin = 110})); BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{110})); // 110 tokens are burned. - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{10'999'890, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{10'999'890, 0})); }, std::nullopt, 0, @@ -3055,17 +2265,13 @@ private: [&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 1'000'000); // Bid exactly 110. Pay 110 because the pay price is < 110. - env(ammAlice.bid( - {.account = carol, .bidMin = 110, .bidMax = 110})); + env(ammAlice.bid({.account = carol, .bidMin = 110, .bidMax = 110})); BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{110})); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{10'999'890})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{10'999'890})); // Bid exactly 180-200. Pay 180 because the pay price is < 180. - env(ammAlice.bid( - {.account = alice, .bidMin = 180, .bidMax = 200})); + env(ammAlice.bid({.account = alice, .bidMin = 180, .bidMax = 200})); BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{180})); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(11'000), USD(11'000), IOUAmount{10'999'814'5, -1})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(11'000), USD(11'000), IOUAmount{10'999'814'5, -1})); }, std::nullopt, 0, @@ -3084,8 +2290,7 @@ private: ammAlice.deposit(bob, 1'000'000); // Bid, pay the computed price. env(ammAlice.bid({.account = bob})); - BEAST_EXPECT( - ammAlice.expectAuctionSlot(0, 0, IOUAmount(1155, -1))); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount(1155, -1))); // Bid bidMax fails because the computed price is higher. env(ammAlice.bid({ @@ -3095,8 +2300,7 @@ private: ter(tecAMM_FAILED)); // Bid MaxSlotPrice succeeds - pay computed price env(ammAlice.bid({.account = carol, .bidMax = 600})); - BEAST_EXPECT( - ammAlice.expectAuctionSlot(0, 0, IOUAmount{121'275, -3})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{121'275, -3})); // Bid Min/MaxSlotPrice fails because the computed price is not // in range @@ -3107,10 +2311,8 @@ private: }), ter(tecAMM_FAILED)); // Bid Min/MaxSlotPrice succeeds - pay computed price - env(ammAlice.bid( - {.account = carol, .bidMin = 100, .bidMax = 600})); - BEAST_EXPECT( - ammAlice.expectAuctionSlot(0, 0, IOUAmount{127'33875, -5})); + env(ammAlice.bid({.account = carol, .bidMin = 100, .bidMax = 600})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{127'33875, -5})); }, std::nullopt, 0, @@ -3125,13 +2327,10 @@ private: fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct); ammAlice.deposit(bob, 1'000'000); if (!features[fixAMMv1_3]) - BEAST_EXPECT(ammAlice.expectBalances( - XRP(12'000), USD(12'000), IOUAmount{12'000'000, 0})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(12'000), USD(12'000), IOUAmount{12'000'000, 0})); else - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{12'000'000'001}, - USD(12'000), - IOUAmount{12'000'000, 0})); + BEAST_EXPECT( + ammAlice.expectBalances(XRPAmount{12'000'000'001}, USD(12'000), IOUAmount{12'000'000, 0})); // Initial state. Pay bidMin. env(ammAlice.bid({.account = carol, .bidMin = 110})).close(); @@ -3140,39 +2339,27 @@ private: // 1st Interval after close, price for 0th interval. env(ammAlice.bid({.account = bob})); env.close(seconds(AUCTION_SLOT_INTERVAL_DURATION + 1)); - BEAST_EXPECT( - ammAlice.expectAuctionSlot(0, 1, IOUAmount{1'155, -1})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 1, IOUAmount{1'155, -1})); // 10th Interval after close, price for 1st interval. env(ammAlice.bid({.account = carol})); env.close(seconds(10 * AUCTION_SLOT_INTERVAL_DURATION + 1)); - BEAST_EXPECT( - ammAlice.expectAuctionSlot(0, 10, IOUAmount{121'275, -3})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 10, IOUAmount{121'275, -3})); // 20th Interval (expired) after close, price for 10th interval. env(ammAlice.bid({.account = bob})); - env.close(seconds( - AUCTION_SLOT_TIME_INTERVALS * - AUCTION_SLOT_INTERVAL_DURATION + - 1)); - BEAST_EXPECT(ammAlice.expectAuctionSlot( - 0, std::nullopt, IOUAmount{127'33875, -5})); + env.close(seconds(AUCTION_SLOT_TIME_INTERVALS * AUCTION_SLOT_INTERVAL_DURATION + 1)); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, std::nullopt, IOUAmount{127'33875, -5})); // 0 Interval. env(ammAlice.bid({.account = carol, .bidMin = 110})).close(); - BEAST_EXPECT(ammAlice.expectAuctionSlot( - 0, std::nullopt, IOUAmount{110})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, std::nullopt, IOUAmount{110})); // ~321.09 tokens burnt on bidding fees. if (!features[fixAMMv1_3]) - BEAST_EXPECT(ammAlice.expectBalances( - XRP(12'000), - USD(12'000), - IOUAmount{11'999'678'91, -2})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(12'000), USD(12'000), IOUAmount{11'999'678'91, -2})); else - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{12'000'000'001}, - USD(12'000), - IOUAmount{11'999'678'91, -2})); + BEAST_EXPECT( + ammAlice.expectBalances(XRPAmount{12'000'000'001}, USD(12'000), IOUAmount{11'999'678'91, -2})); }, std::nullopt, 0, @@ -3202,11 +2389,9 @@ private: ammTokens -= slotPrice; BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, slotPrice)); if (!features[fixAMMv1_3]) - BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), USD(13'000), ammTokens)); + BEAST_EXPECT(ammAlice.expectBalances(XRP(13'000), USD(13'000), ammTokens)); else - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'003}, USD(13'000), ammTokens)); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{13'000'000'003}, USD(13'000), ammTokens)); // Discounted trade for (int i = 0; i < 10; ++i) { @@ -3220,43 +2405,25 @@ private: // carol, bob, and ed pay ~0.99USD in fees. if (!features[fixAMMv1_1]) { - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'499'00572620545), -11)); - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(18'999'00572616195), -11)); - BEAST_EXPECT( - env.balance(ed, USD) == - STAmount(USD, UINT64_C(18'999'00572611841), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'499'00572620545), -11)); + BEAST_EXPECT(env.balance(bob, USD) == STAmount(USD, UINT64_C(18'999'00572616195), -11)); + BEAST_EXPECT(env.balance(ed, USD) == STAmount(USD, UINT64_C(18'999'00572611841), -11)); // USD pool is slightly higher because of the fees. BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount(USD, UINT64_C(13'002'98282151419), -11), - ammTokens)); + XRP(13'000), STAmount(USD, UINT64_C(13'002'98282151419), -11), ammTokens)); } else { - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'499'00572620544), -11)); - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(18'999'00572616194), -11)); - BEAST_EXPECT( - env.balance(ed, USD) == - STAmount(USD, UINT64_C(18'999'0057261184), -10)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'499'00572620544), -11)); + BEAST_EXPECT(env.balance(bob, USD) == STAmount(USD, UINT64_C(18'999'00572616194), -11)); + BEAST_EXPECT(env.balance(ed, USD) == STAmount(USD, UINT64_C(18'999'0057261184), -10)); // USD pool is slightly higher because of the fees. if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount(USD, UINT64_C(13'002'98282151422), -11), - ammTokens)); + XRP(13'000), STAmount(USD, UINT64_C(13'002'98282151422), -11), ammTokens)); else BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'003}, - STAmount(USD, UINT64_C(13'002'98282151422), -11), - ammTokens)); + XRPAmount{13'000'000'003}, STAmount(USD, UINT64_C(13'002'98282151422), -11), ammTokens)); } ammTokens = ammAlice.getLPTokensBalance(); // Trade with the fee @@ -3270,82 +2437,54 @@ private: // than the trading fee. if (!features[fixAMMv1_1]) { - BEAST_EXPECT( - env.balance(dan, USD) == - STAmount(USD, UINT64_C(19'490'056722744), -9)); + BEAST_EXPECT(env.balance(dan, USD) == STAmount(USD, UINT64_C(19'490'056722744), -9)); // USD pool gains more in dan's fees. BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'012'92609877019), -11}, - ammTokens)); + XRP(13'000), STAmount{USD, UINT64_C(13'012'92609877019), -11}, ammTokens)); // Discounted fee payment ammAlice.deposit(carol, USD(100)); ammTokens = ammAlice.getLPTokensBalance(); BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'112'92609877019), -11}, - ammTokens)); - env(pay(carol, bob, USD(100)), - path(~USD), - sendmax(XRP(110))); + XRP(13'000), STAmount{USD, UINT64_C(13'112'92609877019), -11}, ammTokens)); + env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); env.close(); // carol pays 100000 drops in fees // 99900668XRP swapped in for 100USD BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'100'000'668}, - STAmount{USD, UINT64_C(13'012'92609877019), -11}, - ammTokens)); + XRPAmount{13'100'000'668}, STAmount{USD, UINT64_C(13'012'92609877019), -11}, ammTokens)); } else { if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(dan, USD) == - STAmount(USD, UINT64_C(19'490'05672274399), -11)); + BEAST_EXPECT(env.balance(dan, USD) == STAmount(USD, UINT64_C(19'490'05672274399), -11)); else - BEAST_EXPECT( - env.balance(dan, USD) == - STAmount(USD, UINT64_C(19'490'05672274398), -11)); + BEAST_EXPECT(env.balance(dan, USD) == STAmount(USD, UINT64_C(19'490'05672274398), -11)); // USD pool gains more in dan's fees. if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'012'92609877023), -11}, - ammTokens)); + XRP(13'000), STAmount{USD, UINT64_C(13'012'92609877023), -11}, ammTokens)); else BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'003}, - STAmount{USD, UINT64_C(13'012'92609877024), -11}, - ammTokens)); + XRPAmount{13'000'000'003}, STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); // Discounted fee payment ammAlice.deposit(carol, USD(100)); ammTokens = ammAlice.getLPTokensBalance(); if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'112'92609877023), -11}, - ammTokens)); + XRP(13'000), STAmount{USD, UINT64_C(13'112'92609877023), -11}, ammTokens)); else BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'003}, - STAmount{USD, UINT64_C(13'112'92609877024), -11}, - ammTokens)); - env(pay(carol, bob, USD(100)), - path(~USD), - sendmax(XRP(110))); + XRPAmount{13'000'000'003}, STAmount{USD, UINT64_C(13'112'92609877024), -11}, ammTokens)); + env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); env.close(); // carol pays 100000 drops in fees // 99900668XRP swapped in for 100USD if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'100'000'668}, - STAmount{USD, UINT64_C(13'012'92609877023), -11}, - ammTokens)); + XRPAmount{13'100'000'668}, STAmount{USD, UINT64_C(13'012'92609877023), -11}, ammTokens)); else BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'100'000'671}, - STAmount{USD, UINT64_C(13'012'92609877024), -11}, - ammTokens)); + XRPAmount{13'100'000'671}, STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); } // Payment with the trading fee env(pay(alice, carol, XRP(100)), path(~XRP), sendmax(USD(110))); @@ -3356,36 +2495,26 @@ private: if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'114'03663047264), -11}, - ammTokens)); + XRPAmount{13'000'000'668}, STAmount{USD, UINT64_C(13'114'03663047264), -11}, ammTokens)); } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'114'03663047269), -11}, - ammTokens)); + XRPAmount{13'000'000'668}, STAmount{USD, UINT64_C(13'114'03663047269), -11}, ammTokens)); } else { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'671}, - STAmount{USD, UINT64_C(13'114'03663044937), -11}, - ammTokens)); + XRPAmount{13'000'000'671}, STAmount{USD, UINT64_C(13'114'03663044937), -11}, ammTokens)); } // Auction slot expired, no discounted fee env.close(seconds(TOTAL_TIME_SLOT_SECS + 1)); // clock is parent's based env.close(); if (!features[fixAMMv1_1]) - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'399'00572620545), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'399'00572620545), -11)); else if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'399'00572620544), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'399'00572620544), -11)); ammTokens = ammAlice.getLPTokensBalance(); for (int i = 0; i < 10; ++i) { @@ -3396,33 +2525,21 @@ private: // trading fees vs discounted fee. if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) { - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'389'06197177128), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'389'06197177128), -11)); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'123'98038490681), -11}, - ammTokens)); + XRPAmount{13'000'000'668}, STAmount{USD, UINT64_C(13'123'98038490681), -11}, ammTokens)); } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) { - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'389'06197177124), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'389'06197177124), -11)); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'123'98038490689), -11}, - ammTokens)); + XRPAmount{13'000'000'668}, STAmount{USD, UINT64_C(13'123'98038490689), -11}, ammTokens)); } else { - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'389'06197177129), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'389'06197177129), -11)); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'000'000'671}, - STAmount{USD, UINT64_C(13'123'98038488352), -11}, - ammTokens)); + XRPAmount{13'000'000'671}, STAmount{USD, UINT64_C(13'123'98038488352), -11}, ammTokens)); } env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); env.close(); @@ -3432,23 +2549,17 @@ private: if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(13'100'824'790), - STAmount{USD, UINT64_C(13'023'98038490681), -11}, - ammTokens)); + XRPAmount(13'100'824'790), STAmount{USD, UINT64_C(13'023'98038490681), -11}, ammTokens)); } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(13'100'824'790), - STAmount{USD, UINT64_C(13'023'98038490689), -11}, - ammTokens)); + XRPAmount(13'100'824'790), STAmount{USD, UINT64_C(13'023'98038490689), -11}, ammTokens)); } else { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(13'100'824'793), - STAmount{USD, UINT64_C(13'023'98038488352), -11}, - ammTokens)); + XRPAmount(13'100'824'793), STAmount{USD, UINT64_C(13'023'98038488352), -11}, ammTokens)); } }, std::nullopt, @@ -3460,29 +2571,23 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { // Bid a tiny amount - auto const tiny = - Number{STAmount::cMinValue, STAmount::cMinOffset}; - env(ammAlice.bid( - {.account = alice, .bidMin = IOUAmount{tiny}})); + auto const tiny = Number{STAmount::cMinValue, STAmount::cMinOffset}; + env(ammAlice.bid({.account = alice, .bidMin = IOUAmount{tiny}})); // Auction slot purchase price is equal to the tiny amount // since the minSlotPrice is 0 with no trading fee. BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{tiny})); // The purchase price is too small to affect the total tokens - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); // Bid the tiny amount env(ammAlice.bid({ .account = alice, - .bidMin = - IOUAmount{STAmount::cMinValue, STAmount::cMinOffset}, + .bidMin = IOUAmount{STAmount::cMinValue, STAmount::cMinOffset}, })); // Pay slightly higher price - BEAST_EXPECT(ammAlice.expectAuctionSlot( - 0, 0, IOUAmount{tiny * Number{105, -2}})); + BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{tiny * Number{105, -2}})); // The purchase price is still too small to affect the total // tokens - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); }, std::nullopt, 0, @@ -3532,10 +2637,7 @@ private: // But trades with the discounted fee since she still owns the slot. // Alice pays 10011 drops in fees env(pay(alice, bob, USD(10)), path(~USD), sendmax(XRP(11))); - BEAST_EXPECT(amm.expectBalances( - XRPAmount{1'010'010'011}, - USD(1'000), - IOUAmount{1'004'487'562112089, -9})); + BEAST_EXPECT(amm.expectBalances(XRPAmount{1'010'010'011}, USD(1'000), IOUAmount{1'004'487'562112089, -9})); // Bob pays the full fee ~0.1USD env(pay(bob, alice, XRP(10)), path(~XRP), sendmax(USD(11))); if (!features[fixAMMv1_1]) @@ -3566,13 +2668,8 @@ private: { auto jtx = env.jt(tx, seq(1), fee(baseFee)); env.app().config().features.erase(featureAMM); - PreflightContext pfctx( - env.app(), - *jtx.stx, - env.current()->rules(), - tapNONE, - env.journal); - auto pf = Transactor::invokePreflight(pfctx); + PreflightContext pfCtx(env.app(), *jtx.stx, env.current()->rules(), tapNONE, env.journal); + auto pf = Transactor::invokePreflight(pfCtx); BEAST_EXPECT(pf == temDISABLED); env.app().config().features.insert(featureAMM); } @@ -3581,13 +2678,8 @@ private: auto jtx = env.jt(tx, seq(1), fee(baseFee)); jtx.jv["TxnSignature"] = "deadbeef"; jtx.stx = env.ust(jtx); - PreflightContext pfctx( - env.app(), - *jtx.stx, - env.current()->rules(), - tapNONE, - env.journal); - auto pf = Transactor::invokePreflight(pfctx); + PreflightContext pfCtx(env.app(), *jtx.stx, env.current()->rules(), tapNONE, env.journal); + auto pf = Transactor::invokePreflight(pfCtx); BEAST_EXPECT(pf != tesSUCCESS); } @@ -3596,13 +2688,8 @@ private: jtx.jv["Asset2"]["currency"] = "XRP"; jtx.jv["Asset2"].removeMember("issuer"); jtx.stx = env.ust(jtx); - PreflightContext pfctx( - env.app(), - *jtx.stx, - env.current()->rules(), - tapNONE, - env.journal); - auto pf = Transactor::invokePreflight(pfctx); + PreflightContext pfCtx(env.app(), *jtx.stx, env.current()->rules(), tapNONE, env.journal); + auto pf = Transactor::invokePreflight(pfCtx); BEAST_EXPECT(pf == temBAD_AMM_TOKENS); } } @@ -3626,14 +2713,11 @@ private: // XRP balance is below reserve AMM ammAlice(env, acct, XRP(10), USD(10)); // Pay below reserve - env(pay(carol, ammAlice.ammAccount(), XRP(10)), - ter(tecNO_PERMISSION)); + env(pay(carol, ammAlice.ammAccount(), XRP(10)), ter(tecNO_PERMISSION)); // Pay above reserve - env(pay(carol, ammAlice.ammAccount(), XRP(300)), - ter(tecNO_PERMISSION)); + env(pay(carol, ammAlice.ammAccount(), XRP(300)), ter(tecNO_PERMISSION)); // Pay IOU - env(pay(carol, ammAlice.ammAccount(), USD(10)), - ter(tecNO_PERMISSION)); + env(pay(carol, ammAlice.ammAccount(), USD(10)), ter(tecNO_PERMISSION)); } { Env env(*this); @@ -3641,11 +2725,9 @@ private: // XRP balance is above reserve AMM ammAlice(env, acct, XRP(1'000'000), USD(100)); // Pay below reserve - env(pay(carol, ammAlice.ammAccount(), XRP(10)), - ter(tecNO_PERMISSION)); + env(pay(carol, ammAlice.ammAccount(), XRP(10)), ter(tecNO_PERMISSION)); // Pay above reserve - env(pay(carol, ammAlice.ammAccount(), XRP(1'000'000)), - ter(tecNO_PERMISSION)); + env(pay(carol, ammAlice.ammAccount(), XRP(1'000'000)), ter(tecNO_PERMISSION)); } } @@ -3664,46 +2746,28 @@ private: testAMM([&](AMM& ammAlice, Env& env) { auto const pk = carol.pk(); auto const settleDelay = 100s; - NetClock::time_point const cancelAfter = - env.current()->info().parentCloseTime + 200s; - env(paychan::create( - carol, - ammAlice.ammAccount(), - XRP(1'000), - settleDelay, - pk, - cancelAfter), + NetClock::time_point const cancelAfter = env.current()->header().parentCloseTime + 200s; + env(paychan::create(carol, ammAlice.ammAccount(), XRP(1'000), settleDelay, pk, cancelAfter), ter(tecNO_PERMISSION)); }); // Can't pay into AMM with checks. testAMM([&](AMM& ammAlice, Env& env) { - env(check::create(env.master.id(), ammAlice.ammAccount(), XRP(100)), - ter(tecNO_PERMISSION)); + env(check::create(env.master.id(), ammAlice.ammAccount(), XRP(100)), ter(tecNO_PERMISSION)); }); // Pay amounts close to one side of the pool testAMM( [&](AMM& ammAlice, Env& env) { // Can't consume whole pool - env(pay(alice, carol, USD(100)), - path(~USD), - sendmax(XRP(1'000'000'000)), - ter(tecPATH_PARTIAL)); - env(pay(alice, carol, XRP(100)), - path(~XRP), - sendmax(USD(1'000'000'000)), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(100)), path(~USD), sendmax(XRP(1'000'000'000)), ter(tecPATH_PARTIAL)); + env(pay(alice, carol, XRP(100)), path(~XRP), sendmax(USD(1'000'000'000)), ter(tecPATH_PARTIAL)); // Overflow - env(pay(alice, - carol, - STAmount{USD, UINT64_C(99'999999999), -9}), + env(pay(alice, carol, STAmount{USD, UINT64_C(99'999999999), -9}), path(~USD), sendmax(XRP(1'000'000'000)), ter(tecPATH_PARTIAL)); - env(pay(alice, - carol, - STAmount{USD, UINT64_C(999'99999999), -8}), + env(pay(alice, carol, STAmount{USD, UINT64_C(999'99999999), -8}), path(~USD), sendmax(XRP(1'000'000'000)), ter(tecPATH_PARTIAL)); @@ -3712,10 +2776,7 @@ private: sendmax(USD(1'000'000'000)), ter(tecPATH_PARTIAL)); // Sender doesn't have enough funds - env(pay(alice, carol, USD(99.99)), - path(~USD), - sendmax(XRP(1'000'000'000)), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(99.99)), path(~USD), sendmax(XRP(1'000'000'000)), ter(tecPATH_PARTIAL)); env(pay(alice, carol, STAmount{xrpIssue(), 99'990'000}), path(~XRP), sendmax(USD(1'000'000'000)), @@ -3741,10 +2802,7 @@ private: // Individually frozen AMM testAMM([&](AMM& ammAlice, Env& env) { - env(trust( - gw, - STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, - tfSetFreeze)); + env(trust(gw, STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, tfSetFreeze)); env.close(); env(pay(alice, carol, USD(1)), path(~USD), @@ -3777,24 +2835,23 @@ private: testcase("Basic Payment"); using namespace jtx; + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + features = features - featureSingleAssetVault - featureLendingProtocol - featureLendingProtocol; + // Payment 100USD for 100XRP. // Force one path with tfNoRippleDirect. testAMM( [&](AMM& ammAlice, Env& env) { env.fund(jtx::XRP(30'000), bob); env.close(); - env(pay(bob, carol, USD(100)), - path(~USD), - sendmax(XRP(100)), - txflags(tfNoRippleDirect)); + env(pay(bob, carol, USD(100)), path(~USD), sendmax(XRP(100)), txflags(tfNoRippleDirect)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // Initial balance 30,000 + 100 BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); // Initial balance 30,000 - 100(sendmax) - 10(tx fee) - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); }, {{XRP(10'000), USD(10'100)}}, 0, @@ -3808,13 +2865,11 @@ private: env.close(); env(pay(bob, carol, USD(100)), sendmax(XRP(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // Initial balance 30,000 + 100 BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); // Initial balance 30,000 - 100(sendmax) - 10(tx fee) - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); }, {{XRP(10'000), USD(10'100)}}, 0, @@ -3829,13 +2884,11 @@ private: env.close(); env(pay(bob, carol, USD(100)), path(~USD), sendmax(XRP(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // Initial balance 30,000 + 100 BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); // Initial balance 30,000 - 100(sendmax) - 10(tx fee) - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); }, {{XRP(10'000), USD(10'100)}}, 0, @@ -3852,25 +2905,21 @@ private: env(pay(bob, carol, USD(100)), path(~USD), sendmax(XRP(100)), - txflags( - tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); + txflags(tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'010), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'010), USD(10'000), ammAlice.tokens())); // Initial balance 30,000 + 10(limited by limitQuality) BEAST_EXPECT(expectHolding(env, carol, USD(30'010))); // Initial balance 30,000 - 10(limited by limitQuality) - 10(tx // fee) - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(10) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(10) - txfee(env, 1))); // Fails because of limitQuality. Would have sent // ~98.91USD/110XRP has it not been for limitQuality. env(pay(bob, carol, USD(100)), path(~USD), sendmax(XRP(100)), - txflags( - tfNoRippleDirect | tfPartialPayment | tfLimitQuality), + txflags(tfNoRippleDirect | tfPartialPayment | tfLimitQuality), ter(tecPATH_DRY)); env.close(); }, @@ -3892,18 +2941,12 @@ private: env(pay(bob, carol, USD(100)), path(~USD), sendmax(XRP(110)), - txflags( - tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); + txflags(tfNoRippleDirect | tfPartialPayment | tfLimitQuality)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'010), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'010), USD(10'000), ammAlice.tokens())); // 10USD - 10% transfer fee - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'009'09090909091), -11})); - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(10) - txfee(env, 1))); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'009'09090909091), -11})); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(10) - txfee(env, 1))); }, {{XRP(10'000), USD(10'010)}}, 0, @@ -3932,8 +2975,7 @@ private: // is taken from the offer. { Env env(*this, features); - fund( - env, gw, {alice, carol}, {USD(30'000), EUR(30'000)}, Fund::All); + fund(env, gw, {alice, carol}, {USD(30'000), EUR(30'000)}, Fund::All); env.close(); env.fund(XRP(1'000), bob); env.close(); @@ -3941,15 +2983,10 @@ private: auto ammUSD_EUR = AMM(env, alice, EUR(10'000), USD(10'000)); env(offer(alice, XRP(101), USD(100)), txflags(tfPassive)); env.close(); - env(pay(bob, carol, USD(100)), - path(~EUR, ~USD), - sendmax(XRP(102)), - txflags(tfPartialPayment)); + env(pay(bob, carol, USD(100)), path(~EUR, ~USD), sendmax(XRP(102)), txflags(tfPartialPayment)); env.close(); BEAST_EXPECT(ammEUR_XRP.expectBalances( - XRPAmount(10'030'082'730), - STAmount(EUR, UINT64_C(9'970'007498125468), -12), - ammEUR_XRP.tokens())); + XRPAmount(10'030'082'730), STAmount(EUR, UINT64_C(9'970'007498125468), -12), ammEUR_XRP.tokens())); if (!features[fixAMMv1_1]) { BEAST_EXPECT(ammUSD_EUR.expectBalances( @@ -3958,12 +2995,9 @@ private: ammUSD_EUR.tokens())); // fixReducedOffersV2 changes the expected results slightly. - Amounts const expectedAmounts = - env.closed()->rules().enabled(fixReducedOffersV2) + Amounts const expectedAmounts = env.closed()->rules().enabled(fixReducedOffersV2) ? Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233787816), -14)} - : Amounts{ - XRPAmount(30'201'749), - STAmount(USD, UINT64_C(29'90272233787818), -14)}; + : Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233787818), -14)}; BEAST_EXPECT(expectOffers(env, alice, 1, {{expectedAmounts}})); } @@ -3975,12 +3009,9 @@ private: ammUSD_EUR.tokens())); // fixReducedOffersV2 changes the expected results slightly. - Amounts const expectedAmounts = - env.closed()->rules().enabled(fixReducedOffersV2) + Amounts const expectedAmounts = env.closed()->rules().enabled(fixReducedOffersV2) ? Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233782839), -14)} - : Amounts{ - XRPAmount(30'201'749), - STAmount(USD, UINT64_C(29'90272233782840), -14)}; + : Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233782840), -14)}; BEAST_EXPECT(expectOffers(env, alice, 1, {{expectedAmounts}})); } @@ -3988,10 +3019,7 @@ private: BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, 30'100})); // Initial 1,000 - 30082730(AMM pool) - 70798251(offer) - 10(tx fee) BEAST_EXPECT(expectLedgerEntryRoot( - env, - bob, - XRP(1'000) - XRPAmount{30'082'730} - XRPAmount{70'798'251} - - txfee(env, 1))); + env, bob, XRP(1'000) - XRPAmount{30'082'730} - XRPAmount{70'798'251} - txfee(env, 1))); } // Default path (with AMM) has a better quality than a non-default path. @@ -4008,37 +3036,24 @@ private: env.close(); env(offer(alice, EUR(100), USD(100)), txflags(tfPassive)); env.close(); - env(pay(bob, carol, USD(100)), - path(~EUR, ~USD), - sendmax(XRP(102)), - txflags(tfPartialPayment)); + env(pay(bob, carol, USD(100)), path(~EUR, ~USD), sendmax(XRP(102)), txflags(tfPartialPayment)); env.close(); BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(10'050'238'637), - STAmount(USD, UINT64_C(9'950'01249687578), -11), - ammAlice.tokens())); + XRPAmount(10'050'238'637), STAmount(USD, UINT64_C(9'950'01249687578), -11), ammAlice.tokens())); BEAST_EXPECT(expectOffers( env, alice, 2, - {{Amounts{ - XRPAmount(50'487'378), - STAmount(EUR, UINT64_C(49'98750312422), -11)}, + {{Amounts{XRPAmount(50'487'378), STAmount(EUR, UINT64_C(49'98750312422), -11)}, Amounts{ STAmount(EUR, UINT64_C(49'98750312422), -11), STAmount(USD, UINT64_C(49'98750312422), -11)}}})); // Initial 30,000 + 99.99999999999 - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'099'99999999999), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'099'99999999999), -11})); // Initial 1,000 - 50238637(AMM pool) - 50512622(offer) - 10(tx // fee) BEAST_EXPECT(expectLedgerEntryRoot( - env, - bob, - XRP(1'000) - XRPAmount{50'238'637} - XRPAmount{50'512'622} - - txfee(env, 1))); + env, bob, XRP(1'000) - XRPAmount{50'238'637} - XRPAmount{50'512'622} - txfee(env, 1))); }, std::nullopt, 0, @@ -4053,35 +3068,24 @@ private: env.close(); env(offer(bob, XRP(100), USD(100)), txflags(tfPassive)); env.close(); - env(pay(alice, carol, USD(200)), - sendmax(XRP(200)), - txflags(tfPartialPayment)); + env(pay(alice, carol, USD(200)), sendmax(XRP(200)), txflags(tfPartialPayment)); env.close(); if (!features[fixAMMv1_1]) { - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // Initial 30,000 + 200 BEAST_EXPECT(expectHolding(env, carol, USD(30'200))); } else { BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), - STAmount(USD, UINT64_C(10'000'00000000001), -11), - ammAlice.tokens())); - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount(USD, UINT64_C(30'199'99999999999), -11))); + XRP(10'100), STAmount(USD, UINT64_C(10'000'00000000001), -11), ammAlice.tokens())); + BEAST_EXPECT(expectHolding(env, carol, STAmount(USD, UINT64_C(30'199'99999999999), -11))); } // Initial 30,000 - 10000(AMM pool LP) - 100(AMM offer) - // - 100(offer) - 10(tx fee) - one reserve BEAST_EXPECT(expectLedgerEntryRoot( - env, - alice, - XRP(30'000) - XRP(10'000) - XRP(100) - XRP(100) - - ammCrtFee(env) - txfee(env, 1))); + env, alice, XRP(30'000) - XRP(10'000) - XRP(100) - XRP(100) - ammCrtFee(env) - txfee(env, 1))); BEAST_EXPECT(expectOffers(env, bob, 0)); }, {{XRP(10'000), USD(10'100)}}, @@ -4099,12 +3103,9 @@ private: env(offer(bob, XRP(50), USD(150)), txflags(tfPassive)); env.close(); AMM ammAlice(env, alice, XRP(1'000), USD(1'050)); - env(pay(alice, carol, USD(200)), - sendmax(XRP(200)), - txflags(tfPartialPayment)); + env(pay(alice, carol, USD(200)), sendmax(XRP(200)), txflags(tfPartialPayment)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(1'050), USD(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(1'050), USD(1'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(2'200))); BEAST_EXPECT(expectOffers(env, bob, 0)); } @@ -4116,13 +3117,11 @@ private: env.close(); env(offer(bob, USD(100), XRP(100))); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'100), USD(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'100), USD(10'000), ammAlice.tokens())); // Initial 1,000 + 100 BEAST_EXPECT(expectHolding(env, bob, USD(1'100))); // Initial 30,000 - 100(offer) - 10(tx fee) - BEAST_EXPECT(expectLedgerEntryRoot( - env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); + BEAST_EXPECT(expectLedgerEntryRoot(env, bob, XRP(30'000) - XRP(100) - txfee(env, 1))); BEAST_EXPECT(expectOffers(env, bob, 0)); }, {{XRP(10'000), USD(10'100)}}, @@ -4143,8 +3142,7 @@ private: env(offer(carol, EUR(100), GBP(100))); env.close(); // No transfer fee - BEAST_EXPECT(ammAlice.expectBalances( - GBP(1'100), EUR(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(GBP(1'100), EUR(1'000), ammAlice.tokens())); // Initial 30,000 - 100(offer) - 25% transfer fee BEAST_EXPECT(expectHolding(env, carol, GBP(29'875))); // Initial 30,000 + 100(offer) @@ -4171,10 +3169,8 @@ private: // on higher limit out, which generates a larger offer // with lower quality. Consequently, the offer fails // to cross. - BEAST_EXPECT( - amm.expectBalances(XRP(1'000), USD(500), amm.tokens())); - BEAST_EXPECT(expectOffers( - env, carol, 1, {{Amounts{XRP(100), USD(55)}}})); + BEAST_EXPECT(amm.expectBalances(XRP(1'000), USD(500), amm.tokens())); + BEAST_EXPECT(expectOffers(env, carol, 1, {{Amounts{XRP(100), USD(55)}}})); } else { @@ -4186,21 +3182,12 @@ private: // quality. // AMM offer ~50USD/91XRP BEAST_EXPECT(amm.expectBalances( - XRPAmount(909'090'909), - STAmount{USD, UINT64_C(550'000000055), -9}, - amm.tokens())); + XRPAmount(909'090'909), STAmount{USD, UINT64_C(550'000000055), -9}, amm.tokens())); // Offer ~91XRP/49.99USD - BEAST_EXPECT(expectOffers( - env, - carol, - 1, - {{Amounts{ - XRPAmount{9'090'909}, - STAmount{USD, 4'99999995, -8}}}})); - // Carol pays 0.1% fee on ~50USD =~ 0.05USD BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'949'94999999494), -11)); + expectOffers(env, carol, 1, {{Amounts{XRPAmount{9'090'909}, STAmount{USD, 4'99999995, -8}}}})); + // Carol pays 0.1% fee on ~50USD =~ 0.05USD + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(29'949'94999999494), -11)); } }, {{XRP(1'000), USD(500)}}, @@ -4215,18 +3202,14 @@ private: env.close(); if (!features[fixAMMv1_1]) { - BEAST_EXPECT(amm.expectBalances( - XRP(990), - STAmount{USD, UINT64_C(505'050505050505), -12}, - amm.tokens())); + BEAST_EXPECT( + amm.expectBalances(XRP(990), STAmount{USD, UINT64_C(505'050505050505), -12}, amm.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); } else { - BEAST_EXPECT(amm.expectBalances( - XRP(990), - STAmount{USD, UINT64_C(505'0505050505051), -13}, - amm.tokens())); + BEAST_EXPECT( + amm.expectBalances(XRP(990), STAmount{USD, UINT64_C(505'0505050505051), -13}, amm.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); } }, @@ -4238,13 +3221,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { Account const ed("ed"); - fund( - env, - gw, - {bob, ed}, - XRP(30'000), - {GBP(2'000), EUR(2'000)}, - Fund::Acct); + fund(env, gw, {bob, ed}, XRP(30'000), {GBP(2'000), EUR(2'000)}, Fund::Acct); env(rate(gw, 1.25)); env.close(); // The auto-bridge is worse quality than AMM, is not consumed @@ -4286,15 +3263,9 @@ private: // = 58.825 = ~29941.17 // carol bought ~72.93EUR at the cost of ~70.68GBP // the offer is partially consumed - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{GBP, UINT64_C(29'941'16770347333), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{GBP, UINT64_C(29'941'16770347333), -11})); // Initial 30,000 + ~49.3(offers = 39.3(AMM) + 10(LOB)) - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{EUR, UINT64_C(30'049'31517120716), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{EUR, UINT64_C(30'049'31517120716), -11})); } else { @@ -4325,15 +3296,9 @@ private: // = 88.35 = ~29911.64 // carol bought ~72.93EUR at the cost of ~70.68GBP // the offer is partially consumed - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{GBP, UINT64_C(29'911'64396400896), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{GBP, UINT64_C(29'911'64396400896), -11})); // Initial 30,000 + ~72.93(offers = 62.93(AMM) + 10(LOB)) - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{EUR, UINT64_C(30'072'93416277865), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{EUR, UINT64_C(30'072'93416277865), -11})); } // Initial 2000 + 10 = 2010 BEAST_EXPECT(expectHolding(env, bob, GBP(2'010))); @@ -4357,13 +3322,9 @@ private: fund(env, gw, {bob}, {GBP(200), EUR(200)}, Fund::Acct); env(rate(gw, 1.25)); env.close(); - env(pay(bob, carol, EUR(100)), - path(~EUR), - sendmax(GBP(125)), - txflags(tfPartialPayment)); + env(pay(bob, carol, EUR(100)), path(~EUR), sendmax(GBP(125)), txflags(tfPartialPayment)); env.close(); - BEAST_EXPECT(ammAlice.expectBalances( - GBP(1'100), EUR(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(GBP(1'100), EUR(1'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, bob, GBP(75))); BEAST_EXPECT(expectHolding(env, carol, EUR(30'080))); }, @@ -4404,8 +3365,7 @@ private: env.close(); BEAST_EXPECT(expectHolding(env, bob, CAN(0))); BEAST_EXPECT(expectHolding(env, dan, CAN(356.25), GBP(43.75))); - BEAST_EXPECT(ammAlice.expectBalances( - GBP(10'125), EUR(10'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(GBP(10'125), EUR(10'000), ammAlice.tokens())); BEAST_EXPECT(expectHolding(env, ed, EUR(300), USD(100))); BEAST_EXPECT(expectHolding(env, carol, USD(80))); }, @@ -4447,12 +3407,7 @@ private: { Env env(*this, features); auto const ETH = gw["ETH"]; - fund( - env, - gw, - {alice}, - XRP(100'000), - {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)}); + fund(env, gw, {alice}, XRP(100'000), {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)}); fund(env, gw, {carol, bob}, XRP(1'000), {USD(200)}, Fund::Acct); AMM xrp_eur(env, alice, XRP(10'100), EUR(10'000)); AMM eur_btc(env, alice, EUR(10'000), BTC(10'200)); @@ -4471,9 +3426,7 @@ private: // XRP-ETH-EUR-USD // This path provides ~26.06USD/26.2XRP BEAST_EXPECT(xrp_eth.expectBalances( - XRPAmount(10'026'208'900), - STAmount{ETH, UINT64_C(10'073'65779244494), -11}, - xrp_eth.tokens())); + XRPAmount(10'026'208'900), STAmount{ETH, UINT64_C(10'073'65779244494), -11}, xrp_eth.tokens())); BEAST_EXPECT(eth_eur.expectBalances( STAmount{ETH, UINT64_C(10'926'34220755506), -11}, STAmount{EUR, UINT64_C(10'973'54232078752), -11}, @@ -4485,16 +3438,12 @@ private: // XRP-USD path // This path provides ~73.9USD/74.1XRP BEAST_EXPECT(xrp_usd.expectBalances( - XRPAmount(10'224'106'246), - STAmount{USD, UINT64_C(10'126'06848287914), -11}, - xrp_usd.tokens())); + XRPAmount(10'224'106'246), STAmount{USD, UINT64_C(10'126'06848287914), -11}, xrp_usd.tokens())); } else { BEAST_EXPECT(xrp_eth.expectBalances( - XRPAmount(10'026'208'900), - STAmount{ETH, UINT64_C(10'073'65779244461), -11}, - xrp_eth.tokens())); + XRPAmount(10'026'208'900), STAmount{ETH, UINT64_C(10'073'65779244461), -11}, xrp_eth.tokens())); BEAST_EXPECT(eth_eur.expectBalances( STAmount{ETH, UINT64_C(10'926'34220755539), -11}, STAmount{EUR, UINT64_C(10'973'5423207872), -10}, @@ -4506,9 +3455,7 @@ private: // XRP-USD path // This path provides ~73.9USD/74.1XRP BEAST_EXPECT(xrp_usd.expectBalances( - XRPAmount(10'224'106'246), - STAmount{USD, UINT64_C(10'126'06848287943), -11}, - xrp_usd.tokens())); + XRPAmount(10'224'106'246), STAmount{USD, UINT64_C(10'126'06848287943), -11}, xrp_usd.tokens())); } // XRP-EUR-BTC-USD @@ -4517,12 +3464,9 @@ private: // shows a different distribution: // XRP-EUR-BTC-USD 11.6USD/11.64XRP, XRP-USD 60.7USD/60.8XRP, // XRP-ETH-EUR-USD 27.6USD/27.6XRP - BEAST_EXPECT(xrp_eur.expectBalances( - XRP(10'100), EUR(10'000), xrp_eur.tokens())); - BEAST_EXPECT(eur_btc.expectBalances( - EUR(10'000), BTC(10'200), eur_btc.tokens())); - BEAST_EXPECT(btc_usd.expectBalances( - BTC(10'100), USD(10'000), btc_usd.tokens())); + BEAST_EXPECT(xrp_eur.expectBalances(XRP(10'100), EUR(10'000), xrp_eur.tokens())); + BEAST_EXPECT(eur_btc.expectBalances(EUR(10'000), BTC(10'200), eur_btc.tokens())); + BEAST_EXPECT(btc_usd.expectBalances(BTC(10'100), USD(10'000), btc_usd.tokens())); BEAST_EXPECT(expectHolding(env, carol, USD(300))); } @@ -4531,42 +3475,28 @@ private: { Env env(*this, features); auto const ETH = gw["ETH"]; - fund( - env, - gw, - {alice}, - XRP(40'000), - {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)}); + fund(env, gw, {alice}, XRP(40'000), {EUR(50'000), BTC(50'000), ETH(50'000), USD(50'000)}); fund(env, gw, {carol, bob}, XRP(1000), {USD(200)}, Fund::Acct); AMM xrp_eur(env, alice, XRP(10'100), EUR(10'000)); AMM eur_btc(env, alice, EUR(10'000), BTC(10'200)); AMM btc_usd(env, alice, BTC(10'100), USD(10'000)); AMM xrp_eth(env, alice, XRP(10'000), ETH(10'100)); AMM eth_eur(env, alice, ETH(10'900), EUR(11'000)); - env(pay(bob, carol, USD(100)), - path(~EUR, ~BTC, ~USD), - path(~ETH, ~EUR, ~BTC, ~USD), - sendmax(XRP(200))); + env(pay(bob, carol, USD(100)), path(~EUR, ~BTC, ~USD), path(~ETH, ~EUR, ~BTC, ~USD), sendmax(XRP(200))); if (!features[fixAMMv1_1]) { // XRP-EUR-BTC-USD path provides ~17.8USD/~18.7XRP // XRP-ETH-EUR-BTC-USD path provides ~82.2USD/82.4XRP BEAST_EXPECT(xrp_eur.expectBalances( - XRPAmount(10'118'738'472), - STAmount{EUR, UINT64_C(9'981'544436337968), -12}, - xrp_eur.tokens())); + XRPAmount(10'118'738'472), STAmount{EUR, UINT64_C(9'981'544436337968), -12}, xrp_eur.tokens())); BEAST_EXPECT(eur_btc.expectBalances( STAmount{EUR, UINT64_C(10'101'16096785173), -11}, STAmount{BTC, UINT64_C(10'097'91426968066), -11}, eur_btc.tokens())); BEAST_EXPECT(btc_usd.expectBalances( - STAmount{BTC, UINT64_C(10'202'08573031934), -11}, - USD(9'900), - btc_usd.tokens())); + STAmount{BTC, UINT64_C(10'202'08573031934), -11}, USD(9'900), btc_usd.tokens())); BEAST_EXPECT(xrp_eth.expectBalances( - XRPAmount(10'082'446'397), - STAmount{ETH, UINT64_C(10'017'41072778012), -11}, - xrp_eth.tokens())); + XRPAmount(10'082'446'397), STAmount{ETH, UINT64_C(10'017'41072778012), -11}, xrp_eth.tokens())); BEAST_EXPECT(eth_eur.expectBalances( STAmount{ETH, UINT64_C(10'982'58927221988), -11}, STAmount{EUR, UINT64_C(10'917'2945958103), -10}, @@ -4575,21 +3505,15 @@ private: else { BEAST_EXPECT(xrp_eur.expectBalances( - XRPAmount(10'118'738'472), - STAmount{EUR, UINT64_C(9'981'544436337923), -12}, - xrp_eur.tokens())); + XRPAmount(10'118'738'472), STAmount{EUR, UINT64_C(9'981'544436337923), -12}, xrp_eur.tokens())); BEAST_EXPECT(eur_btc.expectBalances( STAmount{EUR, UINT64_C(10'101'16096785188), -11}, STAmount{BTC, UINT64_C(10'097'91426968059), -11}, eur_btc.tokens())); BEAST_EXPECT(btc_usd.expectBalances( - STAmount{BTC, UINT64_C(10'202'08573031941), -11}, - USD(9'900), - btc_usd.tokens())); + STAmount{BTC, UINT64_C(10'202'08573031941), -11}, USD(9'900), btc_usd.tokens())); BEAST_EXPECT(xrp_eth.expectBalances( - XRPAmount(10'082'446'397), - STAmount{ETH, UINT64_C(10'017'41072777996), -11}, - xrp_eth.tokens())); + XRPAmount(10'082'446'397), STAmount{ETH, UINT64_C(10'017'41072777996), -11}, xrp_eth.tokens())); BEAST_EXPECT(eth_eur.expectBalances( STAmount{ETH, UINT64_C(10'982'58927222004), -11}, STAmount{EUR, UINT64_C(10'917'2945958102), -10}, @@ -4618,27 +3542,16 @@ private: { // Carol gets ~29.91USD because of the AMM offers limit BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'030), - STAmount{USD, UINT64_C(9'970'089730807577), -12}, - ammAlice.tokens())); - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'029'91026919241), -11})); + XRP(10'030), STAmount{USD, UINT64_C(9'970'089730807577), -12}, ammAlice.tokens())); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'029'91026919241), -11})); } else { BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'030), - STAmount{USD, UINT64_C(9'970'089730807827), -12}, - ammAlice.tokens())); - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'029'91026919217), -11})); + XRP(10'030), STAmount{USD, UINT64_C(9'970'089730807827), -12}, ammAlice.tokens())); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'029'91026919217), -11})); } - BEAST_EXPECT( - expectOffers(env, alice, 1, {{{EUR(140), XRP(100)}}})); + BEAST_EXPECT(expectOffers(env, alice, 1, {{{EUR(140), XRP(100)}}})); }, std::nullopt, 0, @@ -4659,26 +3572,18 @@ private: path(~XRP, ~USD), sendmax(EUR(400)), txflags(tfPartialPayment | tfNoRippleDirect)); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'101'010'102}, USD(9'900), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(XRPAmount{10'101'010'102}, USD(9'900), ammAlice.tokens())); if (!features[fixAMMv1_1]) { // Carol gets ~100USD - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'099'99999999999), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'099'99999999999), -11})); } else { BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); } - BEAST_EXPECT(expectOffers( - env, - alice, - 1, - {{{STAmount{EUR, UINT64_C(39'1858572), -7}, - XRPAmount{27'989'898}}}})); + BEAST_EXPECT( + expectOffers(env, alice, 1, {{{STAmount{EUR, UINT64_C(39'1858572), -7}, XRPAmount{27'989'898}}}})); }, std::nullopt, 0, @@ -4696,28 +3601,16 @@ private: if (!features[fixAMMv1_1]) { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'049'825'373}, - STAmount{USD, UINT64_C(10'049'92586949302), -11}, - ammAlice.tokens())); + XRPAmount{10'049'825'373}, STAmount{USD, UINT64_C(10'049'92586949302), -11}, ammAlice.tokens())); BEAST_EXPECT(expectOffers( - env, - bob, - 1, - {{{XRPAmount{50'074'629}, - STAmount{USD, UINT64_C(50'07513050698), -11}}}})); + env, bob, 1, {{{XRPAmount{50'074'629}, STAmount{USD, UINT64_C(50'07513050698), -11}}}})); } else { BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'049'825'372}, - STAmount{USD, UINT64_C(10'049'92587049303), -11}, - ammAlice.tokens())); + XRPAmount{10'049'825'372}, STAmount{USD, UINT64_C(10'049'92587049303), -11}, ammAlice.tokens())); BEAST_EXPECT(expectOffers( - env, - bob, - 1, - {{{XRPAmount{50'074'628}, - STAmount{USD, UINT64_C(50'07512950697), -11}}}})); + env, bob, 1, {{{XRPAmount{50'074'628}, STAmount{USD, UINT64_C(50'07512950697), -11}}}})); BEAST_EXPECT(expectHolding(env, carol, USD(30'100))); } } @@ -4751,17 +3644,13 @@ private: auto const baseFee = env.current()->fees().base.drops(); auto const token1 = ammAlice.lptIssue(); auto priceXRP = ammAssetOut( - STAmount{XRPAmount{10'000'000'000}}, - STAmount{token1, 10'000'000}, - STAmount{token1, 5'000'000}, - 0); + STAmount{XRPAmount{10'000'000'000}}, STAmount{token1, 10'000'000}, STAmount{token1, 5'000'000}, 0); // Carol places an order to buy LPTokens env(offer(carol, STAmount{token1, 5'000'000}, priceXRP)); // Alice places an order to sell LPTokens env(offer(alice, priceXRP, STAmount{token1, 5'000'000})); // Pool's LPTokens balance doesn't change - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000})); // Carol is Liquidity Provider BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{5'000'000})); BEAST_EXPECT(ammAlice.expectLPTokens(alice, IOUAmount{5'000'000})); @@ -4774,23 +3663,14 @@ private: env(ammAlice.bid({.account = carol, .bidMin = 100})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{4'999'900})); BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{100})); - BEAST_EXPECT( - accountBalance(env, carol) == - std::to_string(22500000000 - 4 * baseFee)); + BEAST_EXPECT(accountBalance(env, carol) == std::to_string(22500000000 - 4 * baseFee)); priceXRP = ammAssetOut( - STAmount{XRPAmount{10'000'000'000}}, - STAmount{token1, 9'999'900}, - STAmount{token1, 4'999'900}, - 0); + STAmount{XRPAmount{10'000'000'000}}, STAmount{token1, 9'999'900}, STAmount{token1, 4'999'900}, 0); // Carol withdraws ammAlice.withdrawAll(carol, XRP(0)); + BEAST_EXPECT(accountBalance(env, carol) == std::to_string(29999949999 - 5 * baseFee)); BEAST_EXPECT( - accountBalance(env, carol) == - std::to_string(29999949999 - 5 * baseFee)); - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{10'000'000'000} - priceXRP, - USD(10'000), - IOUAmount{5'000'000})); + ammAlice.expectBalances(XRPAmount{10'000'000'000} - priceXRP, USD(10'000), IOUAmount{5'000'000})); BEAST_EXPECT(ammAlice.expectLPTokens(alice, IOUAmount{5'000'000})); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); }); @@ -4803,8 +3683,7 @@ private: ammAlice1.deposit(carol, 1'000'000); auto const token1 = ammAlice.lptIssue(); auto const token2 = ammAlice1.lptIssue(); - env(offer(alice, STAmount{token1, 100}, STAmount{token2, 100}), - txflags(tfPassive)); + env(offer(alice, STAmount{token1, 100}, STAmount{token2, 100}), txflags(tfPassive)); env.close(); BEAST_EXPECT(expectOffers(env, alice, 1)); env(offer(carol, STAmount{token2, 100}, STAmount{token1, 100})); @@ -4815,8 +3694,7 @@ private: BEAST_EXPECT( expectHolding(env, carol, STAmount{token2, 1'000'100}) && expectHolding(env, carol, STAmount{token1, 999'900})); - BEAST_EXPECT( - expectOffers(env, alice, 0) && expectOffers(env, carol, 0)); + BEAST_EXPECT(expectOffers(env, alice, 0) && expectOffers(env, carol, 0)); }); // LPs pay LPTokens directly. Must trust set because the trust line @@ -4855,12 +3733,11 @@ private: testAmendment() { testcase("Amendment"); - using namespace jtx; FeatureBitset const all{testable_amendments()}; FeatureBitset const noAMM{all - featureAMM}; FeatureBitset const noNumber{all - fixUniversalNumber}; - FeatureBitset const noAMMAndNumber{ - all - featureAMM - fixUniversalNumber}; + FeatureBitset const noAMMAndNumber{all - featureAMM - fixUniversalNumber}; + using namespace jtx; for (auto const& feature : {noAMM, noNumber, noAMMAndNumber}) { @@ -4873,8 +3750,7 @@ private: amm.vote(VoteArg{.tfee = 100, .err = ter(temDISABLED)}); amm.withdraw(WithdrawArg{.tokens = 100, .err = ter(temMALFORMED)}); amm.withdraw(WithdrawArg{.err = ter(temDISABLED)}); - amm.deposit( - DepositArg{.asset1In = USD(100), .err = ter(temDISABLED)}); + amm.deposit(DepositArg{.asset1In = USD(100), .err = ter(temDISABLED)}); amm.ammDelete(alice, ter(temDISABLED)); } } @@ -4887,16 +3763,9 @@ private: testAMM([&](AMM& ammAlice, Env& env) { auto const info = env.rpc( - "json", - "account_info", - std::string( - "{\"account\": \"" + to_string(ammAlice.ammAccount()) + - "\"}")); - auto const flags = - info[jss::result][jss::account_data][jss::Flags].asUInt(); - BEAST_EXPECT( - flags == - (lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth)); + "json", "account_info", std::string("{\"account\": \"" + to_string(ammAlice.ammAccount()) + "\"}")); + auto const flags = info[jss::result][jss::account_data][jss::Flags].asUInt(); + BEAST_EXPECT(flags == (lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth)); }); } @@ -4986,9 +3855,7 @@ private: prep( [&](Env& env) { AMM amm(env, LP1, TST(25), XRP(250)); }, [&](Env& env) { - lp2TSTBalance = - getAccountLines(env, LP2, TST)["lines"][0u]["balance"] - .asString(); + lp2TSTBalance = getAccountLines(env, LP2, TST)["lines"][0u]["balance"].asString(); auto const offer = getAccountOffers(env, LP2)["offers"][0u]; lp2TakerGets = offer["taker_gets"].asString(); lp2TakerPays = offer["taker_pays"]["value"].asString(); @@ -4997,27 +3864,17 @@ private: prep( [&](Env& env) { if (!features[fixAMMv1_1]) - env(offer( - LP1, - XRPAmount{18'095'133}, - STAmount{TST, UINT64_C(1'68737984885388), -14}), + env(offer(LP1, XRPAmount{18'095'133}, STAmount{TST, UINT64_C(1'68737984885388), -14}), txflags(tfPassive)); else - env(offer( - LP1, - XRPAmount{18'095'132}, - STAmount{TST, UINT64_C(1'68737976189735), -14}), + env(offer(LP1, XRPAmount{18'095'132}, STAmount{TST, UINT64_C(1'68737976189735), -14}), txflags(tfPassive)); }, [&](Env& env) { - BEAST_EXPECT( - lp2TSTBalance == - getAccountLines(env, LP2, TST)["lines"][0u]["balance"] - .asString()); + BEAST_EXPECT(lp2TSTBalance == getAccountLines(env, LP2, TST)["lines"][0u]["balance"].asString()); auto const offer = getAccountOffers(env, LP2)["offers"][0u]; BEAST_EXPECT(lp2TakerGets == offer["taker_gets"].asString()); - BEAST_EXPECT( - lp2TakerPays == offer["taker_pays"]["value"].asString()); + BEAST_EXPECT(lp2TakerPays == offer["taker_pays"]["value"].asString()); }); } @@ -5042,17 +3899,13 @@ private: // Carol gets fewer LPToken ~994, because of the single deposit // fee ammAlice.deposit(carol, USD(3'000)); - BEAST_EXPECT(ammAlice.expectLPTokens( - carol, IOUAmount{994'981155689671, -12})); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{994'981155689671, -12})); BEAST_EXPECT(expectHolding(env, carol, USD(27'000))); // Set fee to 0 ammAlice.vote(alice, 0); ammAlice.withdrawAll(carol, USD(0)); // Carol gets back less than the original deposit - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(29'994'96220068281), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(29'994'96220068281), -11})); }, {{USD(1'000), EUR(1'000)}}, 0, @@ -5064,8 +3917,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { auto const balance = env.balance(carol, USD); - auto tokensFee = ammAlice.deposit( - carol, USD(1'000), std::nullopt, STAmount{USD, 1, -1}); + auto tokensFee = ammAlice.deposit(carol, USD(1'000), std::nullopt, STAmount{USD, 1, -1}); auto const deposit = balance - env.balance(carol, USD); ammAlice.withdrawAll(carol, USD(0)); ammAlice.vote(alice, 0); @@ -5086,8 +3938,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { auto const balance = env.balance(carol, USD); - auto const tokensFee = ammAlice.deposit( - carol, USD(200), std::nullopt, STAmount{USD, 2020, -6}); + auto const tokensFee = ammAlice.deposit(carol, USD(200), std::nullopt, STAmount{USD, 2020, -6}); auto const deposit = balance - env.balance(carol, USD); ammAlice.withdrawAll(carol, USD(0)); ammAlice.vote(alice, 0); @@ -5116,10 +3967,7 @@ private: BEAST_EXPECT(ammAlice.expectTradingFee(1'000)); // Single withdrawal. Carol gets ~5USD less than deposited. ammAlice.withdrawAll(carol, USD(0)); - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(29'994'97487437186), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(29'994'97487437186), -11})); }, {{USD(1'000), EUR(1'000)}}, 0, @@ -5130,8 +3978,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.deposit(carol, 1'000'000); - auto const tokensFee = ammAlice.withdraw( - carol, USD(100), std::nullopt, IOUAmount{520, 0}); + auto const tokensFee = ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{520, 0}); // carol withdraws ~1,443.44USD auto const balanceAfterWithdraw = [&]() { if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) @@ -5150,28 +3997,19 @@ private: BEAST_EXPECT(ammAlice.expectTradingFee(0)); auto const tokensNoFee = ammAlice.withdraw(carol, deposit); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(30'443'43891402717), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402717), -11)); else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(30'443'43891402716), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402716), -11)); else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(30'443'43891402713), -11)); + BEAST_EXPECT(env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402713), -11)); // carol pays ~4008 LPTokens in fees or ~0.5% of the no-fee // LPTokens if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT( - tokensNoFee == IOUAmount(746'579'80779913, -8)); + BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779913, -8)); else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT( - tokensNoFee == IOUAmount(746'579'80779912, -8)); + BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779912, -8)); else - BEAST_EXPECT( - tokensNoFee == IOUAmount(746'579'80779911, -8)); + BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779911, -8)); BEAST_EXPECT(tokensFee == IOUAmount(750'588'23529411, -8)); }, std::nullopt, @@ -5182,22 +4020,13 @@ private: // Payment, 1% fee testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(1'000), - {USD(1'000), EUR(1'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(1'000), {USD(1'000), EUR(1'000)}, Fund::Acct); // Alice contributed 1010EUR and 1000USD to the pool BEAST_EXPECT(expectHolding(env, alice, EUR(28'990))); BEAST_EXPECT(expectHolding(env, alice, USD(29'000))); BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); // Carol pays to Alice with no fee - env(pay(carol, alice, EUR(10)), - path(~EUR), - sendmax(USD(10)), - txflags(tfNoRippleDirect)); + env(pay(carol, alice, EUR(10)), path(~EUR), sendmax(USD(10)), txflags(tfNoRippleDirect)); env.close(); // Alice has 10EUR more and Carol has 10USD less BEAST_EXPECT(expectHolding(env, alice, EUR(29'000))); @@ -5208,20 +4037,14 @@ private: ammAlice.vote(alice, 1'000); BEAST_EXPECT(ammAlice.expectTradingFee(1'000)); // Bob pays to Carol with 1% fee - env(pay(bob, carol, USD(10)), - path(~USD), - sendmax(EUR(15)), - txflags(tfNoRippleDirect)); + env(pay(bob, carol, USD(10)), path(~USD), sendmax(EUR(15)), txflags(tfNoRippleDirect)); env.close(); // Bob sends 10.1~EUR to pay 10USD - BEAST_EXPECT(expectHolding( - env, bob, STAmount{EUR, UINT64_C(989'8989898989899), -13})); + BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR, UINT64_C(989'8989898989899), -13})); // Carol got 10USD BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); BEAST_EXPECT(ammAlice.expectBalances( - USD(1'000), - STAmount{EUR, UINT64_C(1'010'10101010101), -11}, - ammAlice.tokens())); + USD(1'000), STAmount{EUR, UINT64_C(1'010'10101010101), -11}, ammAlice.tokens())); }, {{USD(1'000), EUR(1'010)}}, 0, @@ -5246,14 +4069,8 @@ private: env.close(); // Alice gets fewer ~4.97EUR for ~5.02USD, the difference goes // to the pool - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(29'995'02512562814), -11})); - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{EUR, UINT64_C(30'004'97487437186), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(29'995'02512562814), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{EUR, UINT64_C(30'004'97487437186), -11})); BEAST_EXPECT(expectOffers( env, carol, @@ -5288,33 +4105,21 @@ private: { Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(2'000), EUR(2'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(2'000), EUR(2'000)}); env(offer(carol, EUR(5), USD(5))); AMM ammAlice(env, alice, USD(1'005), EUR(1'000)); - env(pay(bob, ed, USD(10)), - path(~USD), - sendmax(EUR(15)), - txflags(tfNoRippleDirect)); + env(pay(bob, ed, USD(10)), path(~USD), sendmax(EUR(15)), txflags(tfNoRippleDirect)); BEAST_EXPECT(expectHolding(env, ed, USD(2'010))); if (!features[fixAMMv1_1]) { BEAST_EXPECT(expectHolding(env, bob, EUR(1'990))); - BEAST_EXPECT(ammAlice.expectBalances( - USD(1'000), EUR(1'005), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(USD(1'000), EUR(1'005), ammAlice.tokens())); } else { - BEAST_EXPECT(expectHolding( - env, bob, STAmount(EUR, UINT64_C(1989'999999999999), -12))); + BEAST_EXPECT(expectHolding(env, bob, STAmount(EUR, UINT64_C(1989'999999999999), -12))); BEAST_EXPECT(ammAlice.expectBalances( - USD(1'000), - STAmount(EUR, UINT64_C(1005'000000000001), -12), - ammAlice.tokens())); + USD(1'000), STAmount(EUR, UINT64_C(1005'000000000001), -12), ammAlice.tokens())); } BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -5324,41 +4129,23 @@ private: { Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(2'000), EUR(2'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(2'000), EUR(2'000)}); env(offer(carol, EUR(5), USD(5))); // Set 0.25% fee AMM ammAlice(env, alice, USD(1'005), EUR(1'000), false, 250); - env(pay(bob, ed, USD(10)), - path(~USD), - sendmax(EUR(15)), - txflags(tfNoRippleDirect)); + env(pay(bob, ed, USD(10)), path(~USD), sendmax(EUR(15)), txflags(tfNoRippleDirect)); BEAST_EXPECT(expectHolding(env, ed, USD(2'010))); if (!features[fixAMMv1_1]) { - BEAST_EXPECT(expectHolding( - env, - bob, - STAmount{EUR, UINT64_C(1'989'987453007618), -12})); + BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR, UINT64_C(1'989'987453007618), -12})); BEAST_EXPECT(ammAlice.expectBalances( - USD(1'000), - STAmount{EUR, UINT64_C(1'005'012546992382), -12}, - ammAlice.tokens())); + USD(1'000), STAmount{EUR, UINT64_C(1'005'012546992382), -12}, ammAlice.tokens())); } else { - BEAST_EXPECT(expectHolding( - env, - bob, - STAmount{EUR, UINT64_C(1'989'987453007628), -12})); + BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR, UINT64_C(1'989'987453007628), -12})); BEAST_EXPECT(ammAlice.expectBalances( - USD(1'000), - STAmount{EUR, UINT64_C(1'005'012546992372), -12}, - ammAlice.tokens())); + USD(1'000), STAmount{EUR, UINT64_C(1'005'012546992372), -12}, ammAlice.tokens())); } BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -5369,23 +4156,14 @@ private: { Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(2'000), EUR(2'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(2'000), EUR(2'000)}); env(offer(carol, EUR(10), USD(10))); // Set 1% fee AMM ammAlice(env, alice, USD(1'005), EUR(1'000), false, 1'000); - env(pay(bob, ed, USD(10)), - path(~USD), - sendmax(EUR(15)), - txflags(tfNoRippleDirect)); + env(pay(bob, ed, USD(10)), path(~USD), sendmax(EUR(15)), txflags(tfNoRippleDirect)); BEAST_EXPECT(expectHolding(env, ed, USD(2'010))); BEAST_EXPECT(expectHolding(env, bob, EUR(1'990))); - BEAST_EXPECT(ammAlice.expectBalances( - USD(1'005), EUR(1'000), ammAlice.tokens())); + BEAST_EXPECT(ammAlice.expectBalances(USD(1'005), EUR(1'000), ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -5396,26 +4174,15 @@ private: { Env env(*this, features); Account const ed("ed"); - fund( - env, - gw, - {alice, bob, carol, ed}, - XRP(1'000), - {USD(2'000), EUR(2'000)}); + fund(env, gw, {alice, bob, carol, ed}, XRP(1'000), {USD(2'000), EUR(2'000)}); env(offer(carol, EUR(9), USD(9))); // Set 1% fee AMM ammAlice(env, alice, USD(1'005), EUR(1'000), false, 1'000); - env(pay(bob, ed, USD(10)), - path(~USD), - sendmax(EUR(15)), - txflags(tfNoRippleDirect)); + env(pay(bob, ed, USD(10)), path(~USD), sendmax(EUR(15)), txflags(tfNoRippleDirect)); BEAST_EXPECT(expectHolding(env, ed, USD(2'010))); - BEAST_EXPECT(expectHolding( - env, bob, STAmount{EUR, UINT64_C(1'989'993923296712), -12})); + BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR, UINT64_C(1'989'993923296712), -12})); BEAST_EXPECT(ammAlice.expectBalances( - USD(1'004), - STAmount{EUR, UINT64_C(1'001'006076703288), -12}, - ammAlice.tokens())); + USD(1'004), STAmount{EUR, UINT64_C(1'001'006076703288), -12}, ammAlice.tokens())); BEAST_EXPECT(expectOffers(env, carol, 0)); } } @@ -5437,13 +4204,8 @@ private: Account const chris("chris"); Account const simon("simon"); Account const ben("ben"); - Account const nataly("nataly"); - fund( - env, - gw, - {bob, ed, paul, dan, chris, simon, ben, nataly}, - {USD(1'500'000)}, - Fund::Acct); + Account const natalie("natalie"); + fund(env, gw, {bob, ed, paul, dan, chris, simon, ben, natalie}, {USD(1'500'000)}, Fund::Acct); for (int i = 0; i < 10; ++i) { ammAlice.deposit(ben, STAmount{USD, 1, -10}); @@ -5462,34 +4224,26 @@ private: ammAlice.withdrawAll(ed, USD(0)); ammAlice.deposit(paul, USD(100'000)); ammAlice.withdrawAll(paul, USD(0)); - ammAlice.deposit(nataly, USD(1'000'000)); - ammAlice.withdrawAll(nataly, USD(0)); + ammAlice.deposit(natalie, USD(1'000'000)); + ammAlice.withdrawAll(natalie, USD(0)); } // Due to round off some accounts have a tiny gain, while // other have a tiny loss. The last account to withdraw // gets everything in the pool. if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'000'0000000013), -10}, - IOUAmount{10'000'000})); + XRP(10'000), STAmount{USD, UINT64_C(10'000'0000000013), -10}, IOUAmount{10'000'000})); else if (features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'000'0000000003), -10}, - IOUAmount{10'000'000})); + XRP(10'000), STAmount{USD, UINT64_C(10'000'0000000003), -10}, IOUAmount{10'000'000})); else - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000})); BEAST_EXPECT(expectHolding(env, ben, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, simon, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, chris, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, dan, USD(1'500'000))); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT(expectHolding( - env, - carol, - STAmount{USD, UINT64_C(30'000'00000000001), -11})); + BEAST_EXPECT(expectHolding(env, carol, STAmount{USD, UINT64_C(30'000'00000000001), -11})); else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); else @@ -5497,37 +4251,23 @@ private: BEAST_EXPECT(expectHolding(env, ed, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, paul, USD(1'500'000))); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT(expectHolding( - env, - nataly, - STAmount{USD, UINT64_C(1'500'000'000000002), -9})); + BEAST_EXPECT(expectHolding(env, natalie, STAmount{USD, UINT64_C(1'500'000'000000002), -9})); else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) - BEAST_EXPECT(expectHolding( - env, - nataly, - STAmount{USD, UINT64_C(1'500'000'000000005), -9})); + BEAST_EXPECT(expectHolding(env, natalie, STAmount{USD, UINT64_C(1'500'000'000000005), -9})); else - BEAST_EXPECT(expectHolding(env, nataly, USD(1'500'000))); + BEAST_EXPECT(expectHolding(env, natalie, USD(1'500'000))); ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); if (!features[fixAMMv1_1]) - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{USD, UINT64_C(30'000'0000000013), -10})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{USD, UINT64_C(30'000'0000000013), -10})); else if (features[fixAMMv1_3]) - BEAST_EXPECT(expectHolding( - env, - alice, - STAmount{USD, UINT64_C(30'000'0000000003), -10})); + BEAST_EXPECT(expectHolding(env, alice, STAmount{USD, UINT64_C(30'000'0000000003), -10})); else BEAST_EXPECT(expectHolding(env, alice, USD(30'000))); - // alice XRP balance is 30,000initial - 50 ammcreate fee - + // alice XRP balance is 30,000 initial - 50 AMMCreate fee - // 10drops fee BEAST_EXPECT( - accountBalance(env, alice) == - std::to_string( - 29950000000 - env.current()->fees().base.drops())); + accountBalance(env, alice) == std::to_string(29950000000 - env.current()->fees().base.drops())); }, std::nullopt, 0, @@ -5544,14 +4284,8 @@ private: Account const chris("chris"); Account const simon("simon"); Account const ben("ben"); - Account const nataly("nataly"); - fund( - env, - gw, - {bob, ed, paul, dan, chris, simon, ben, nataly}, - XRP(2'000'000), - {}, - Fund::Acct); + Account const natalie("natalie"); + fund(env, gw, {bob, ed, paul, dan, chris, simon, ben, natalie}, XRP(2'000'000), {}, Fund::Acct); for (int i = 0; i < 10; ++i) { ammAlice.deposit(ben, XRPAmount{1}); @@ -5570,69 +4304,50 @@ private: ammAlice.withdrawAll(ed, XRP(0)); ammAlice.deposit(paul, XRP(100'000)); ammAlice.withdrawAll(paul, XRP(0)); - ammAlice.deposit(nataly, XRP(1'000'000)); - ammAlice.withdrawAll(nataly, XRP(0)); + ammAlice.deposit(natalie, XRP(1'000'000)); + ammAlice.withdrawAll(natalie, XRP(0)); } auto const baseFee = env.current()->fees().base.drops(); if (!features[fixAMMv1_3]) { // No round off with XRP in this test - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), USD(10'000), IOUAmount{10'000'000})); + BEAST_EXPECT(ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000})); ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); // 20,000 initial - (deposit+withdraw) * 10 - auto const xrpBalance = - (XRP(2'000'000) - txfee(env, 20)).getText(); + auto const xrpBalance = (XRP(2'000'000) - txfee(env, 20)).getText(); BEAST_EXPECT(accountBalance(env, ben) == xrpBalance); BEAST_EXPECT(accountBalance(env, simon) == xrpBalance); BEAST_EXPECT(accountBalance(env, chris) == xrpBalance); BEAST_EXPECT(accountBalance(env, dan) == xrpBalance); // 30,000 initial - (deposit+withdraw) * 10 - BEAST_EXPECT( - accountBalance(env, carol) == - std::to_string(30'000'000'000 - 20 * baseFee)); + BEAST_EXPECT(accountBalance(env, carol) == std::to_string(30'000'000'000 - 20 * baseFee)); BEAST_EXPECT(accountBalance(env, ed) == xrpBalance); BEAST_EXPECT(accountBalance(env, paul) == xrpBalance); - BEAST_EXPECT(accountBalance(env, nataly) == xrpBalance); - // 30,000 initial - 50 ammcreate fee - 10drops withdraw fee - BEAST_EXPECT( - accountBalance(env, alice) == - std::to_string(29'950'000'000 - baseFee)); + BEAST_EXPECT(accountBalance(env, natalie) == xrpBalance); + // 30,000 initial - 50 AMMCreate fee - 10drops withdraw fee + BEAST_EXPECT(accountBalance(env, alice) == std::to_string(29'950'000'000 - baseFee)); } else { // post-amendment the rounding takes place to ensure // AMM invariant - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount(10'000'000'080), - USD(10'000), - IOUAmount{10'000'000})); + BEAST_EXPECT( + ammAlice.expectBalances(XRPAmount(10'000'000'080), USD(10'000), IOUAmount{10'000'000})); ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); - auto const xrpBalance = - XRP(2'000'000) - txfee(env, 20) - drops(10); + auto const xrpBalance = XRP(2'000'000) - txfee(env, 20) - drops(10); auto const xrpBalanceText = xrpBalance.getText(); BEAST_EXPECT(accountBalance(env, ben) == xrpBalanceText); BEAST_EXPECT(accountBalance(env, simon) == xrpBalanceText); BEAST_EXPECT(accountBalance(env, chris) == xrpBalanceText); BEAST_EXPECT(accountBalance(env, dan) == xrpBalanceText); - BEAST_EXPECT( - accountBalance(env, carol) == - std::to_string(30'000'000'000 - 20 * baseFee - 10)); - BEAST_EXPECT( - accountBalance(env, ed) == - (xrpBalance + drops(2)).getText()); - BEAST_EXPECT( - accountBalance(env, paul) == - (xrpBalance + drops(3)).getText()); - BEAST_EXPECT( - accountBalance(env, nataly) == - (xrpBalance + drops(5)).getText()); - BEAST_EXPECT( - accountBalance(env, alice) == - std::to_string(29'950'000'000 - baseFee + 80)); + BEAST_EXPECT(accountBalance(env, carol) == std::to_string(30'000'000'000 - 20 * baseFee - 10)); + BEAST_EXPECT(accountBalance(env, ed) == (xrpBalance + drops(2)).getText()); + BEAST_EXPECT(accountBalance(env, paul) == (xrpBalance + drops(3)).getText()); + BEAST_EXPECT(accountBalance(env, natalie) == (xrpBalance + drops(5)).getText()); + BEAST_EXPECT(accountBalance(env, alice) == std::to_string(29'950'000'000 - baseFee + 80)); } }, std::nullopt, @@ -5678,24 +4393,10 @@ private: .bidMin = 1000, }), ter(tecAMM_EMPTY)); - amm.vote( - std::nullopt, - 100, - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecAMM_EMPTY)); - amm.withdraw( - alice, 100, std::nullopt, std::nullopt, ter(tecAMM_EMPTY)); - amm.deposit( - alice, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecAMM_EMPTY)); - env(trust(alice, STAmount{amm.lptIssue(), 10'000}), - ter(tecAMM_EMPTY)); + amm.vote(std::nullopt, 100, std::nullopt, std::nullopt, std::nullopt, ter(tecAMM_EMPTY)); + amm.withdraw(alice, 100, std::nullopt, std::nullopt, ter(tecAMM_EMPTY)); + amm.deposit(alice, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecAMM_EMPTY)); + env(trust(alice, STAmount{amm.lptIssue(), 10'000}), ter(tecAMM_EMPTY)); // Can deposit with tfTwoAssetIfEmpty option amm.deposit( @@ -5708,8 +4409,7 @@ private: std::nullopt, std::nullopt, 1'000); - BEAST_EXPECT( - amm.expectBalances(XRP(10'000), USD(10'000), amm.tokens())); + BEAST_EXPECT(amm.expectBalances(XRP(10'000), USD(10'000), amm.tokens())); BEAST_EXPECT(amm.expectTradingFee(1'000)); BEAST_EXPECT(amm.expectAuctionSlot(100, 0, IOUAmount{0})); @@ -5773,40 +4473,30 @@ private: using namespace jtx; testAMM([&](AMM& amm, Env& env) { amm.setClose(false); - auto const info = env.rpc( - "json", - "account_info", - std::string( - "{\"account\": \"" + to_string(amm.ammAccount()) + "\"}")); + auto const info = + env.rpc("json", "account_info", std::string("{\"account\": \"" + to_string(amm.ammAccount()) + "\"}")); try { - BEAST_EXPECT( - info[jss::result][jss::account_data][jss::AMMID] - .asString() == to_string(amm.ammID())); + BEAST_EXPECT(info[jss::result][jss::account_data][jss::AMMID].asString() == to_string(amm.ammID())); } catch (...) { fail(); } amm.deposit(carol, 1'000); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; try { bool found = false; for (auto const& node : affected) { if (node.isMember(sfModifiedNode.fieldName) && - node[sfModifiedNode.fieldName] - [sfLedgerEntryType.fieldName] - .asString() == "AccountRoot" && - node[sfModifiedNode.fieldName][sfFinalFields.fieldName] - [jss::Account] - .asString() == to_string(amm.ammAccount())) + node[sfModifiedNode.fieldName][sfLedgerEntryType.fieldName].asString() == "AccountRoot" && + node[sfModifiedNode.fieldName][sfFinalFields.fieldName][jss::Account].asString() == + to_string(amm.ammAccount())) { - found = node[sfModifiedNode.fieldName] - [sfFinalFields.fieldName][jss::AMMID] - .asString() == to_string(amm.ammID()); + found = node[sfModifiedNode.fieldName][sfFinalFields.fieldName][jss::AMMID].asString() == + to_string(amm.ammID()); break; } } @@ -5836,19 +4526,13 @@ private: auto prep = [&](Env& env, auto gwRate, auto gw1Rate) { fund(env, gw, {alice, carol, bob, ed}, XRP(2'000), {USD(2'000)}); env.fund(XRP(2'000), gw1); - fund( - env, - gw1, - {alice, carol, bob, ed}, - {ETH(2'000), CAN(2'000)}, - Fund::IOUOnly); + fund(env, gw1, {alice, carol, bob, ed}, {ETH(2'000), CAN(2'000)}, Fund::IOUOnly); env(rate(gw, gwRate)); env(rate(gw1, gw1Rate)); env.close(); }; - for (auto const& rates : - {std::make_pair(1.5, 1.9), std::make_pair(1.9, 1.5)}) + for (auto const& rates : {std::make_pair(1.5, 1.9), std::make_pair(1.9, 1.5)}) { // Offer Selection @@ -5874,20 +4558,15 @@ private: } if (i > 0) amm.emplace(env, ed, USD(1'000), ETH(1'000)); - env(pay(carol, bob, USD(100)), - path(~USD), - sendmax(ETH(500))); + env(pay(carol, bob, USD(100)), path(~USD), sendmax(ETH(500))); env.close(); // CLOB and AMM, AMM is not selected if (i == 2) { - BEAST_EXPECT(amm->expectBalances( - USD(1'000), ETH(1'000), amm->tokens())); + BEAST_EXPECT(amm->expectBalances(USD(1'000), ETH(1'000), amm->tokens())); } BEAST_EXPECT(expectHolding(env, bob, USD(2'100))); - q[i] = Quality(Amounts{ - ETH(2'000) - env.balance(carol, ETH), - env.balance(bob, USD) - USD(2'000)}); + q[i] = Quality(Amounts{ETH(2'000) - env.balance(carol, ETH), env.balance(bob, USD) - USD(2'000)}); } // CLOB is better quality than AMM BEAST_EXPECT(q[0] > q[1]); @@ -5916,8 +4595,7 @@ private: // AMM is not selected if (i > 0) { - BEAST_EXPECT(amm->expectBalances( - USD(1'000), ETH(1'000), amm->tokens())); + BEAST_EXPECT(amm->expectBalances(USD(1'000), ETH(1'000), amm->tokens())); } if (i == 0 || i == 2) { @@ -5927,8 +4605,7 @@ private: // Fails to cross because AMM is not selected else { - BEAST_EXPECT(expectOffers( - env, alice, 1, {Amounts{USD(400), ETH(400)}})); + BEAST_EXPECT(expectOffers(env, alice, 1, {Amounts{USD(400), ETH(400)}})); } BEAST_EXPECT(expectOffers(env, ed, 0)); } @@ -5951,15 +4628,12 @@ private: } if (i > 0) amm.emplace(env, ed, USD(1'000), ETH(1'000)); - env(pay(carol, bob, USD(100)), - path(~USD), - sendmax(ETH(500))); + env(pay(carol, bob, USD(100)), path(~USD), sendmax(ETH(500))); env.close(); // AMM and CLOB are selected if (i > 0) { - BEAST_EXPECT(!amm->expectBalances( - USD(1'000), ETH(1'000), amm->tokens())); + BEAST_EXPECT(!amm->expectBalances(USD(1'000), ETH(1'000), amm->tokens())); } if (i == 2 && !features[fixAMMv1_1]) { @@ -5971,28 +4645,16 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, - UINT64_C(378'6327949540823), - -13}, - STAmount{ - USD, - UINT64_C(283'9745962155617), - -13}}}})); + STAmount{ETH, UINT64_C(378'6327949540823), -13}, + STAmount{USD, UINT64_C(283'9745962155617), -13}}}})); else BEAST_EXPECT(expectOffers( env, ed, 1, {{Amounts{ - STAmount{ - ETH, - UINT64_C(378'6327949540813), - -13}, - STAmount{ - USD, - UINT64_C(283'974596215561), - -12}}}})); + STAmount{ETH, UINT64_C(378'6327949540813), -13}, + STAmount{USD, UINT64_C(283'974596215561), -12}}}})); } else { @@ -6002,28 +4664,16 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, - UINT64_C(325'299461620749), - -12}, - STAmount{ - USD, - UINT64_C(243'9745962155617), - -13}}}})); + STAmount{ETH, UINT64_C(325'299461620749), -12}, + STAmount{USD, UINT64_C(243'9745962155617), -13}}}})); else BEAST_EXPECT(expectOffers( env, ed, 1, {{Amounts{ - STAmount{ - ETH, - UINT64_C(325'299461620748), - -12}, - STAmount{ - USD, - UINT64_C(243'974596215561), - -12}}}})); + STAmount{ETH, UINT64_C(325'299461620748), -12}, + STAmount{USD, UINT64_C(243'974596215561), -12}}}})); } } else if (i == 2) @@ -6035,12 +4685,8 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, UINT64_C(378'6327949540812), -13}, - STAmount{ - USD, - UINT64_C(283'9745962155609), - -13}}}})); + STAmount{ETH, UINT64_C(378'6327949540812), -13}, + STAmount{USD, UINT64_C(283'9745962155609), -13}}}})); } else { @@ -6049,18 +4695,12 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, UINT64_C(325'2994616207479), -13}, - STAmount{ - USD, - UINT64_C(243'9745962155609), - -13}}}})); + STAmount{ETH, UINT64_C(325'2994616207479), -13}, + STAmount{USD, UINT64_C(243'9745962155609), -13}}}})); } } BEAST_EXPECT(expectHolding(env, bob, USD(2'100))); - q[i] = Quality(Amounts{ - ETH(2'000) - env.balance(carol, ETH), - env.balance(bob, USD) - USD(2'000)}); + q[i] = Quality(Amounts{ETH(2'000) - env.balance(carol, ETH), env.balance(bob, USD) - USD(2'000)}); } // AMM is better quality BEAST_EXPECT(q[1] > q[0]); @@ -6086,8 +4726,7 @@ private: // AMM is selected in both cases if (i > 0) { - BEAST_EXPECT(!amm->expectBalances( - USD(1'000), ETH(1'000), amm->tokens())); + BEAST_EXPECT(!amm->expectBalances(USD(1'000), ETH(1'000), amm->tokens())); } // Partially crosses, AMM is selected, CLOB fails // limitQuality @@ -6097,17 +4736,14 @@ private: { if (!features[fixAMMv1_1]) { - BEAST_EXPECT(expectOffers( - env, ed, 1, {{Amounts{ETH(400), USD(250)}}})); + BEAST_EXPECT(expectOffers(env, ed, 1, {{Amounts{ETH(400), USD(250)}}})); BEAST_EXPECT(expectOffers( env, alice, 1, {{Amounts{ - STAmount{ - USD, UINT64_C(40'5694150420947), -13}, - STAmount{ - ETH, UINT64_C(64'91106406735152), -14}, + STAmount{USD, UINT64_C(40'5694150420947), -13}, + STAmount{ETH, UINT64_C(64'91106406735152), -14}, }}})); } else @@ -6120,10 +4756,8 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, UINT64_C(335'0889359326475), -13}, - STAmount{ - USD, UINT64_C(209'4305849579047), -13}, + STAmount{ETH, UINT64_C(335'0889359326475), -13}, + STAmount{USD, UINT64_C(209'4305849579047), -13}, }}})); BEAST_EXPECT(expectOffers(env, alice, 0)); } @@ -6138,10 +4772,8 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, UINT64_C(335'0889359326485), -13}, - STAmount{ - USD, UINT64_C(209'4305849579053), -13}, + STAmount{ETH, UINT64_C(335'0889359326485), -13}, + STAmount{USD, UINT64_C(209'4305849579053), -13}, }}})); BEAST_EXPECT(expectOffers(env, alice, 0)); } @@ -6153,10 +4785,8 @@ private: ed, 1, {{Amounts{ - STAmount{ - ETH, UINT64_C(335'0889359326475), -13}, - STAmount{ - USD, UINT64_C(209'4305849579047), -13}, + STAmount{ETH, UINT64_C(335'0889359326475), -13}, + STAmount{USD, UINT64_C(209'4305849579047), -13}, }}})); BEAST_EXPECT(expectOffers(env, alice, 0)); } @@ -6198,10 +4828,7 @@ private: if (i > 0) amm.emplace(env, ed, ETH(1'000), USD(1'000)); - env(pay(carol, bob, USD(100)), - path(~USD), - path(~CAN, ~USD), - sendmax(ETH(600))); + env(pay(carol, bob, USD(100)), path(~USD), path(~CAN, ~USD), sendmax(ETH(600))); env.close(); BEAST_EXPECT(expectHolding(env, bob, USD(2'100))); @@ -6212,15 +4839,12 @@ private: { // Liquidity is consumed from AMM strand only BEAST_EXPECT(amm->expectBalances( - STAmount{ETH, UINT64_C(1'176'66038955758), -11}, - USD(850), - amm->tokens())); + STAmount{ETH, UINT64_C(1'176'66038955758), -11}, USD(850), amm->tokens())); } else { BEAST_EXPECT(amm->expectBalances( - STAmount{ - ETH, UINT64_C(1'179'540094339627), -12}, + STAmount{ETH, UINT64_C(1'179'540094339627), -12}, STAmount{USD, UINT64_C(847'7880529867501), -13}, amm->tokens())); BEAST_EXPECT(expectOffers( @@ -6228,24 +4852,12 @@ private: ed, 2, {{Amounts{ - STAmount{ - ETH, - UINT64_C(343'3179205198749), - -13}, - STAmount{ - CAN, - UINT64_C(343'3179205198749), - -13}, + STAmount{ETH, UINT64_C(343'3179205198749), -13}, + STAmount{CAN, UINT64_C(343'3179205198749), -13}, }, Amounts{ - STAmount{ - CAN, - UINT64_C(362'2119470132499), - -13}, - STAmount{ - USD, - UINT64_C(362'2119470132499), - -13}, + STAmount{CAN, UINT64_C(362'2119470132499), -13}, + STAmount{USD, UINT64_C(362'2119470132499), -13}, }}})); } } @@ -6255,10 +4867,7 @@ private: { // Liquidity is consumed from AMM strand only BEAST_EXPECT(amm->expectBalances( - STAmount{ - ETH, UINT64_C(1'176'660389557593), -12}, - USD(850), - amm->tokens())); + STAmount{ETH, UINT64_C(1'176'660389557593), -12}, USD(850), amm->tokens())); } else { @@ -6271,30 +4880,16 @@ private: ed, 2, {{Amounts{ - STAmount{ - ETH, - UINT64_C(343'3179205198749), - -13}, - STAmount{ - CAN, - UINT64_C(343'3179205198749), - -13}, + STAmount{ETH, UINT64_C(343'3179205198749), -13}, + STAmount{CAN, UINT64_C(343'3179205198749), -13}, }, Amounts{ - STAmount{ - CAN, - UINT64_C(362'2119470132499), - -13}, - STAmount{ - USD, - UINT64_C(362'2119470132499), - -13}, + STAmount{CAN, UINT64_C(362'2119470132499), -13}, + STAmount{USD, UINT64_C(362'2119470132499), -13}, }}})); } } - q[i] = Quality(Amounts{ - ETH(2'000) - env.balance(carol, ETH), - env.balance(bob, USD) - USD(2'000)}); + q[i] = Quality(Amounts{ETH(2'000) - env.balance(carol, ETH), env.balance(bob, USD) - USD(2'000)}); } BEAST_EXPECT(q[1] > q[0]); BEAST_EXPECT(q[2] > q[0] && q[2] < q[1]); @@ -6319,37 +4914,23 @@ private: std::optional extra = std::nullopt) { Env env(*this, features); fund(env, gw, {alice}, XRP(1'000), {USD(10)}); - AMM amm( - env, - gw, - XRP(10), - USD(10), - {.tfee = tfee, .close = closeLedger}); + AMM amm(env, gw, XRP(10), USD(10), {.tfee = tfee, .close = closeLedger}); amm.deposit(alice, USD(10), XRP(10)); amm.vote(VoteArg{.account = alice, .tfee = tfee, .err = ter(err1)}); - amm.withdraw(WithdrawArg{ - .account = gw, .asset1Out = USD(1), .err = ter(err2)}); + amm.withdraw(WithdrawArg{.account = gw, .asset1Out = USD(1), .err = ter(err2)}); // with the amendment disabled and ledger not closed, // second vote succeeds if the first vote sets the trading fee // to non-zero; if the first vote sets the trading fee to >0 && // <9 then the second withdraw succeeds if the second vote sets // the trading fee so that the discounted fee is non-zero amm.vote(VoteArg{.account = alice, .tfee = 20, .err = ter(err3)}); - amm.withdraw(WithdrawArg{ - .account = gw, .asset1Out = USD(2), .err = ter(err4)}); + amm.withdraw(WithdrawArg{.account = gw, .asset1Out = USD(2), .err = ter(err4)}); }; // ledger is closed after each transaction, vote/withdraw don't fail // regardless whether the amendment is enabled or not test(all, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 0, true); - test( - all - fixInnerObjTemplate, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - 0, - true); + test(all - fixInnerObjTemplate, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 0, true); // ledger is not closed after each transaction // vote/withdraw don't fail if the amendment is enabled test(all, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 0, false); @@ -6357,49 +4938,21 @@ private: // second vote/withdraw still fail: second vote fails because // the initial trading fee is 0, consequently second withdraw fails // because the second vote fails - test( - all - fixInnerObjTemplate, - tefEXCEPTION, - tefEXCEPTION, - tefEXCEPTION, - tefEXCEPTION, - 0, - false); + test(all - fixInnerObjTemplate, tefEXCEPTION, tefEXCEPTION, tefEXCEPTION, tefEXCEPTION, 0, false); // if non-zero trading/discounted fee then vote/withdraw // don't fail whether the ledger is closed or not and // the amendment is enabled or not test(all, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 10, true); - test( - all - fixInnerObjTemplate, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - 10, - true); + test(all - fixInnerObjTemplate, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 10, true); test(all, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 10, false); - test( - all - fixInnerObjTemplate, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - tesSUCCESS, - 10, - false); + test(all - fixInnerObjTemplate, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 10, false); // non-zero trading fee but discounted fee is 0, vote doesn't fail // but withdraw fails test(all, tesSUCCESS, tesSUCCESS, tesSUCCESS, tesSUCCESS, 9, false); // second vote sets the trading fee to non-zero, consequently // second withdraw doesn't fail even if the amendment is not // enabled and the ledger is not closed - test( - all - fixInnerObjTemplate, - tesSUCCESS, - tefEXCEPTION, - tesSUCCESS, - tesSUCCESS, - 9, - false); + test(all - fixInnerObjTemplate, tesSUCCESS, tefEXCEPTION, tesSUCCESS, tesSUCCESS, 9, false); } void @@ -6419,14 +4972,12 @@ private: // side is generated first SucceedShouldFail, // Succeed in pre-fix, fail after fix // due to small quality difference - Fail, // Both fail because the quality can't be matched - Succeed // Both succeed + Fail, // Both fail because the quality can't be matched + Succeed // Both succeed }; using enum Status; - auto const xrpIouAmounts10_100 = - TAmounts{XRPAmount{10}, IOUAmount{100}}; - auto const iouXrpAmounts10_100 = - TAmounts{IOUAmount{10}, XRPAmount{100}}; + auto const xrpIouAmounts10_100 = TAmounts{XRPAmount{10}, IOUAmount{100}}; + auto const iouXrpAmounts10_100 = TAmounts{IOUAmount{10}, XRPAmount{100}}; // clang-format off std::vector> tests = { //Pool In , Pool Out, Quality , Fee, Status @@ -6495,6 +5046,8 @@ private: Env env(*this, features, std::make_unique(&logs)); auto rules = env.current()->rules(); CurrentTransactionRulesGuard rg(rules); + NumberMantissaScaleGuard sg(MantissaRange::small); + for (auto const& t : tests) { auto getPool = [&](std::string const& v, bool isXRP) { @@ -6505,21 +5058,15 @@ private: auto const& quality = std::get(t); auto const tfee = std::get(t); auto const status = std::get(t); - auto const poolInIsXRP = - boost::regex_search(std::get<0>(t), match, rx); - auto const poolOutIsXRP = - boost::regex_search(std::get<1>(t), match, rx); + auto const poolInIsXRP = boost::regex_search(std::get<0>(t), match, rx); + auto const poolOutIsXRP = boost::regex_search(std::get<1>(t), match, rx); assert(!(poolInIsXRP && poolOutIsXRP)); auto const poolIn = getPool(std::get<0>(t), poolInIsXRP); auto const poolOut = getPool(std::get<1>(t), poolOutIsXRP); try { auto const amounts = changeSpotPriceQuality( - Amounts{poolIn, poolOut}, - quality, - tfee, - env.current()->rules(), - env.journal); + Amounts{poolIn, poolOut}, quality, tfee, env.current()->rules(), env.journal); if (amounts) { if (status == SucceedShouldSucceedResize) @@ -6534,24 +5081,19 @@ private: if (!features[fixAMMv1_1]) BEAST_EXPECT( Quality{*amounts} >= quality || - withinRelativeDistance( - Quality{*amounts}, quality, Number{1, -7})); + withinRelativeDistance(Quality{*amounts}, quality, Number{1, -7})); else BEAST_EXPECT(Quality{*amounts} >= quality); } else if (status == FailShouldSucceed) { - BEAST_EXPECT( - features[fixAMMv1_1] && - Quality{*amounts} >= quality); + BEAST_EXPECT(features[fixAMMv1_1] && Quality{*amounts} >= quality); } else if (status == SucceedShouldFail) { BEAST_EXPECT( - !features[fixAMMv1_1] && - Quality{*amounts} < quality && - withinRelativeDistance( - Quality{*amounts}, quality, Number{1, -7})); + !features[fixAMMv1_1] && Quality{*amounts} < quality && + withinRelativeDistance(Quality{*amounts}, quality, Number{1, -7})); } } else @@ -6566,29 +5108,15 @@ private: if (isXRP(poolIn)) { auto const takerPays = STAmount{xrpIssue(), 1}; - return Amounts{ - takerPays, - swapAssetIn( - Amounts{poolIn, poolOut}, - takerPays, - tfee)}; + return Amounts{takerPays, swapAssetIn(Amounts{poolIn, poolOut}, takerPays, tfee)}; } else if (isXRP(poolOut)) { auto const takerGets = STAmount{xrpIssue(), 1}; - return Amounts{ - swapAssetOut( - Amounts{poolIn, poolOut}, - takerGets, - tfee), - takerGets}; + return Amounts{swapAssetOut(Amounts{poolIn, poolOut}, takerGets, tfee), takerGets}; } - auto const takerPays = toAmount( - getIssue(poolIn), Number{1, -10} * poolIn); - return Amounts{ - takerPays, - swapAssetIn( - Amounts{poolIn, poolOut}, takerPays, tfee)}; + auto const takerPays = toAmount(getIssue(poolIn), Number{1, -10} * poolIn); + return Amounts{takerPays, swapAssetIn(Amounts{poolIn, poolOut}, takerPays, tfee)}; }(); BEAST_EXPECT(Quality(tinyOffer) < quality); } @@ -6604,18 +5132,15 @@ private: } catch (std::runtime_error const& e) { - BEAST_EXPECT( - !strcmp(e.what(), "changeSpotPriceQuality failed")); - BEAST_EXPECT( - !features[fixAMMv1_1] && status == FailShouldSucceed); + BEAST_EXPECT(!strcmp(e.what(), "changeSpotPriceQuality failed")); + BEAST_EXPECT(!features[fixAMMv1_1] && status == FailShouldSucceed); } } // Test negative discriminant { // b**2 - 4 * a * c -> 1 * 1 - 4 * 1 * 1 = -3 - auto const res = - solveQuadraticEqSmallest(Number{1}, Number{1}, Number{1}); + auto const res = solveQuadraticEqSmallest(Number{1}, Number{1}, Number{1}); BEAST_EXPECT(!res.has_value()); } } @@ -6915,8 +5440,7 @@ private: }) { testcase(input.testCase); - for (auto const& features : - {all - fixAMMOverflowOffer - fixAMMv1_1 - fixAMMv1_3, all}) + for (auto const& features : {all - fixAMMOverflowOffer - fixAMMv1_1 - fixAMMv1_3, all}) { Env env(*this, features, std::make_unique(&logs)); @@ -6938,21 +5462,13 @@ private: env(pay(bitstamp, trader, usdBIT(100'000))); env.close(); - AMM amm{ - env, - trader, - usdGH(input.poolUsdGH), - usdBIT(input.poolUsdBIT)}; + AMM amm{env, trader, usdGH(input.poolUsdGH), usdBIT(input.poolUsdBIT)}; env.close(); - IOUAmount const preSwapLPTokenBalance = - amm.getLPTokensBalance(); + IOUAmount const preSwapLPTokenBalance = amm.getLPTokensBalance(); env(offer(trader, usdBIT(1), btcGH(input.offer1BtcGH))); - env(offer( - trader, - btcGH(input.offer2BtcGH), - usdGH(input.offer2UsdGH))); + env(offer(trader, btcGH(input.offer2BtcGH), usdGH(input.offer2UsdGH))); env.close(); env(pay(trader, trader, input.sendUsdGH), @@ -6962,37 +5478,28 @@ private: txflags(tfPartialPayment)); env.close(); - auto const failUsdGH = - features[fixAMMv1_1] ? input.failUsdGHr : input.failUsdGH; - auto const failUsdBIT = - features[fixAMMv1_1] ? input.failUsdBITr : input.failUsdBIT; - auto const goodUsdGH = - features[fixAMMv1_1] ? input.goodUsdGHr : input.goodUsdGH; - auto const goodUsdBIT = - features[fixAMMv1_1] ? input.goodUsdBITr : input.goodUsdBIT; - auto const lpTokenBalance = - env.enabled(fixAMMv1_3) && input.lpTokenBalanceAlt + auto const failUsdGH = features[fixAMMv1_1] ? input.failUsdGHr : input.failUsdGH; + auto const failUsdBIT = features[fixAMMv1_1] ? input.failUsdBITr : input.failUsdBIT; + auto const goodUsdGH = features[fixAMMv1_1] ? input.goodUsdGHr : input.goodUsdGH; + auto const goodUsdBIT = features[fixAMMv1_1] ? input.goodUsdBITr : input.goodUsdBIT; + auto const lpTokenBalance = env.enabled(fixAMMv1_3) && input.lpTokenBalanceAlt ? *input.lpTokenBalanceAlt : input.lpTokenBalance; if (!features[fixAMMOverflowOffer]) { - BEAST_EXPECT(amm.expectBalances( - failUsdGH, failUsdBIT, lpTokenBalance)); + BEAST_EXPECT(amm.expectBalances(failUsdGH, failUsdBIT, lpTokenBalance)); } else { - BEAST_EXPECT(amm.expectBalances( - goodUsdGH, goodUsdBIT, lpTokenBalance)); + BEAST_EXPECT(amm.expectBalances(goodUsdGH, goodUsdBIT, lpTokenBalance)); // Invariant: LPToken balance must not change in a // payment or a swap transaction - BEAST_EXPECT( - amm.getLPTokensBalance() == preSwapLPTokenBalance); + BEAST_EXPECT(amm.getLPTokensBalance() == preSwapLPTokenBalance); // Invariant: The square root of (product of the pool // balances) must be at least the LPTokenBalance - Number const sqrtPoolProduct = - root2(goodUsdGH * goodUsdBIT); + Number const sqrtPoolProduct = root2(goodUsdGH * goodUsdBIT); // Include a tiny tolerance for the test cases using // .goodUsdGH{usdGH, uint64_t(35'44113971506987), @@ -7002,9 +5509,7 @@ private: // to 99.99999999999994227040383754105 which gets // internally rounded to 100, due to representation // error. - BEAST_EXPECT( - (sqrtPoolProduct + Number{1, -14} >= - input.lpTokenBalance)); + BEAST_EXPECT((sqrtPoolProduct + Number{1, -14} >= input.lpTokenBalance)); } } } @@ -7020,8 +5525,7 @@ private: STAmount const iouPool{USD, UINT64_C(803040'9987141784), -10}; STAmount const xrpBob{XRP, UINT64_C(1092'878933)}; - STAmount const iouBob{ - USD, UINT64_C(3'988035892323031), -28}; // 3.9...e-13 + STAmount const iouBob{USD, UINT64_C(3'988035892323031), -28}; // 3.9...e-13 testAMM( [&](AMM& amm, Env& env) { @@ -7038,13 +5542,12 @@ private: env.close(); // Assert that AMM is unchanged. - BEAST_EXPECT( - amm.expectBalances(xrpBegin, iouBegin, amm.tokens())); + BEAST_EXPECT(amm.expectBalances(xrpBegin, iouBegin, amm.tokens())); }, {{xrpPool, iouPool}}, 889, std::nullopt, - {jtx::testable_amendments() | fixAMMv1_1}); + {testable_amendments() | fixAMMv1_1}); } void @@ -7073,20 +5576,15 @@ private: if (!features[fixAMMv1_1]) { - BEAST_EXPECT(amm.expectBalances( - XRP(200'000), USD(100'000), amm.tokens())); - BEAST_EXPECT(expectOffers( - env, alice, 1, {{Amounts{XRP(1), USD(0.01)}}})); + BEAST_EXPECT(amm.expectBalances(XRP(200'000), USD(100'000), amm.tokens())); + BEAST_EXPECT(expectOffers(env, alice, 1, {{Amounts{XRP(1), USD(0.01)}}})); // Carol's offer is blocked by alice's offer - BEAST_EXPECT(expectOffers( - env, carol, 1, {{Amounts{USD(0.49), XRP(1)}}})); + BEAST_EXPECT(expectOffers(env, carol, 1, {{Amounts{USD(0.49), XRP(1)}}})); } else { - BEAST_EXPECT(amm.expectBalances( - XRPAmount(200'000'980'005), USD(99'999.51), amm.tokens())); - BEAST_EXPECT(expectOffers( - env, alice, 1, {{Amounts{XRP(1), USD(0.01)}}})); + BEAST_EXPECT(amm.expectBalances(XRPAmount(200'000'980'005), USD(99'999.51), amm.tokens())); + BEAST_EXPECT(expectOffers(env, alice, 1, {{Amounts{XRP(1), USD(0.01)}}})); // Carol's offer crosses AMM BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -7108,8 +5606,7 @@ private: env.close(); // The same result as with the blocking offer - BEAST_EXPECT(amm.expectBalances( - XRPAmount(200'000'980'005), USD(99'999.51), amm.tokens())); + BEAST_EXPECT(amm.expectBalances(XRPAmount(200'000'980'005), USD(99'999.51), amm.tokens())); // Carol's offer crosses AMM BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -7128,28 +5625,17 @@ private: env.close(); if (!features[fixAMMv1_1]) { - BEAST_EXPECT( - amm.expectBalances(XRP(1'000), USD(500), amm.tokens())); - BEAST_EXPECT(expectOffers( - env, bob, 1, {{Amounts{USD(1), XRPAmount(500)}}})); - BEAST_EXPECT(expectOffers( - env, carol, 1, {{Amounts{XRP(100), USD(55)}}})); + BEAST_EXPECT(amm.expectBalances(XRP(1'000), USD(500), amm.tokens())); + BEAST_EXPECT(expectOffers(env, bob, 1, {{Amounts{USD(1), XRPAmount(500)}}})); + BEAST_EXPECT(expectOffers(env, carol, 1, {{Amounts{XRP(100), USD(55)}}})); } else { BEAST_EXPECT(amm.expectBalances( - XRPAmount(909'090'909), - STAmount{USD, UINT64_C(550'000000055), -9}, - amm.tokens())); - BEAST_EXPECT(expectOffers( - env, - carol, - 1, - {{Amounts{ - XRPAmount{9'090'909}, - STAmount{USD, 4'99999995, -8}}}})); - BEAST_EXPECT(expectOffers( - env, bob, 1, {{Amounts{USD(1), XRPAmount(500)}}})); + XRPAmount(909'090'909), STAmount{USD, UINT64_C(550'000000055), -9}, amm.tokens())); + BEAST_EXPECT( + expectOffers(env, carol, 1, {{Amounts{XRPAmount{9'090'909}, STAmount{USD, 4'99999995, -8}}}})); + BEAST_EXPECT(expectOffers(env, bob, 1, {{Amounts{USD(1), XRPAmount(500)}}})); } } @@ -7162,16 +5648,9 @@ private: AMM amm(env, alice, XRP(1'000), USD(500)); env(offer(carol, XRP(100), USD(55))); env.close(); - BEAST_EXPECT(amm.expectBalances( - XRPAmount(909'090'909), - STAmount{USD, UINT64_C(550'000000055), -9}, - amm.tokens())); - BEAST_EXPECT(expectOffers( - env, - carol, - 1, - {{Amounts{ - XRPAmount{9'090'909}, STAmount{USD, 4'99999995, -8}}}})); + BEAST_EXPECT( + amm.expectBalances(XRPAmount(909'090'909), STAmount{USD, UINT64_C(550'000000055), -9}, amm.tokens())); + BEAST_EXPECT(expectOffers(env, carol, 1, {{Amounts{XRPAmount{9'090'909}, STAmount{USD, 4'99999995, -8}}}})); } } @@ -7185,12 +5664,7 @@ private: { std::string logs; Env env(*this, features, std::make_unique(&logs)); - fund( - env, - gw, - {alice, carol}, - XRP(1'000'000'000), - {USD(1'000'000'000)}); + fund(env, gw, {alice, carol}, XRP(1'000'000'000), {USD(1'000'000'000)}); AMM amm(env, gw, XRP(2), USD(1)); amm.deposit(alice, IOUAmount{1'876123487565916, -15}); amm.deposit(carol, IOUAmount{1'000'000}); @@ -7198,13 +5672,9 @@ private: BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{0})); amm.withdrawAll(carol); BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{0})); - auto const lpToken = getAccountLines( - env, gw, amm.lptIssue())[jss::lines][0u][jss::balance]; - auto const lpTokenBalance = - amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value]; - BEAST_EXPECT( - lpToken == "1414.213562373095" && - lpTokenBalance == "1414.213562373"); + auto const lpToken = getAccountLines(env, gw, amm.lptIssue())[jss::lines][0u][jss::balance]; + auto const lpTokenBalance = amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value]; + BEAST_EXPECT(lpToken == "1414.213562373095" && lpTokenBalance == "1414.213562373"); if (!features[fixAMMv1_1]) { amm.withdrawAll(gw, std::nullopt, ter(tecAMM_BALANCE)); @@ -7223,24 +5693,15 @@ private: { Env env(*this, features); auto const ABC = gw["ABC"]; - fund( - env, - gw, - {alice, carol, bob}, - XRP(1'000), - {USD(1'000'000'000), ABC(1'000'000'000'000)}); + fund(env, gw, {alice, carol, bob}, XRP(1'000), {USD(1'000'000'000), ABC(1'000'000'000'000)}); AMM amm(env, lp, ABC(2'000'000), USD(1)); amm.deposit(alice, IOUAmount{1'876123487565916, -15}); amm.deposit(carol, IOUAmount{1'000'000}); amm.withdrawAll(alice); amm.withdrawAll(carol); - auto const lpToken = getAccountLines( - env, lp, amm.lptIssue())[jss::lines][0u][jss::balance]; - auto const lpTokenBalance = - amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value]; - BEAST_EXPECT( - lpToken == "1414.213562373095" && - lpTokenBalance == "1414.213562373"); + auto const lpToken = getAccountLines(env, lp, amm.lptIssue())[jss::lines][0u][jss::balance]; + auto const lpTokenBalance = amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value]; + BEAST_EXPECT(lpToken == "1414.213562373095" && lpTokenBalance == "1414.213562373"); if (!features[fixAMMv1_1]) { amm.withdrawAll(lp, std::nullopt, ter(tecAMM_BALANCE)); @@ -7260,11 +5721,9 @@ private: fund(env, gw, {alice}, XRP(1'000), {USD(1'000)}); AMM amm(env, gw, XRP(10), USD(10)); amm.deposit(alice, 1'000); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); BEAST_EXPECT(res && !res.value()); - res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && !res.value()); } // IOU/IOU, issuer of both IOU @@ -7273,11 +5732,9 @@ private: fund(env, gw, {alice}, XRP(1'000), {USD(1'000), EUR(1'000)}); AMM amm(env, gw, EUR(10), USD(10)); amm.deposit(alice, 1'000); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); BEAST_EXPECT(res && !res.value()); - res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); + res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), alice); BEAST_EXPECT(res && !res.value()); } // IOU/IOU, issuer of one IOU @@ -7289,8 +5746,7 @@ private: fund(env, gw1, {gw}, XRP(1'000), {YAN(1'000)}, Fund::IOUOnly); AMM amm(env, gw1, YAN(10), USD(10)); amm.deposit(gw, 1'000); - auto res = - isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); + auto res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw); BEAST_EXPECT(res && !res.value()); res = isOnlyLiquidityProvider(*env.current(), amm.lptIssue(), gw1); BEAST_EXPECT(res && !res.value()); @@ -7339,9 +5795,7 @@ private: // allowed for clawing back from an AMM account. Please notice the // `issuer` subfield represents the account being clawed back, which // is confusing. - auto const error = features[featureSingleAssetVault] - ? ter{tecPSEUDO_ACCOUNT} - : ter{tecAMM_ACCOUNT}; + auto const error = features[featureSingleAssetVault] ? ter{tecPSEUDO_ACCOUNT} : ter{tecAMM_ACCOUNT}; Issue usd(USD.issue().currency, amm.ammAccount()); auto amount = amountFromString(usd, "10"); env(claw(gw, amount), error); @@ -7371,13 +5825,7 @@ private: { Env env(*this, features); testAMMDeposit(env, [&](AMM& amm) { - amm.deposit( - alice, - USD(100), - XRP(100), - std::nullopt, - tfTwoAsset, - ter(tecFROZEN)); + amm.deposit(alice, USD(100), XRP(100), std::nullopt, tfTwoAsset, ter(tecFROZEN)); }); } @@ -7386,13 +5834,7 @@ private: { Env env(*this, features); testAMMDeposit(env, [&](AMM& amm) { - amm.deposit( - alice, - USD(100), - std::nullopt, - std::nullopt, - tfSingleAsset, - ter(tecFROZEN)); + amm.deposit(alice, USD(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecFROZEN)); }); } @@ -7403,13 +5845,7 @@ private: // when feature AMMClawback is enabled. Env env(*this, features); testAMMDeposit(env, [&](AMM& amm) { - amm.deposit( - alice, - XRP(100), - std::nullopt, - std::nullopt, - tfSingleAsset, - ter(tecFROZEN)); + amm.deposit(alice, XRP(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecFROZEN)); }); } else @@ -7419,13 +5855,7 @@ private: // when feature AMMClawback is not enabled. Env env(*this, features); testAMMDeposit(env, [&](AMM& amm) { - amm.deposit( - alice, - XRP(100), - std::nullopt, - std::nullopt, - tfSingleAsset, - ter(tesSUCCESS)); + amm.deposit(alice, XRP(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tesSUCCESS)); }); } } @@ -7436,13 +5866,11 @@ private: testcase("Fix Reserve Check On Withdrawal"); using namespace jtx; - auto const err = features[fixAMMv1_2] ? ter(tecINSUFFICIENT_RESERVE) - : ter(tesSUCCESS); + auto const err = features[fixAMMv1_2] ? ter(tecINSUFFICIENT_RESERVE) : ter(tesSUCCESS); auto test = [&](auto&& cb) { Env env(*this, features); - auto const starting_xrp = - reserve(env, 2) + env.current()->fees().base * 5; + auto const starting_xrp = reserve(env, 2) + env.current()->fees().base * 5; env.fund(starting_xrp, gw); env.fund(starting_xrp, alice); env.trust(USD(2'000), alice); @@ -7459,22 +5887,13 @@ private: // Equal withdraw with a limit test([&](AMM& amm) { - amm.withdraw(WithdrawArg{ - .account = alice, - .asset1Out = EUR(0.1), - .asset2Out = USD(0.1), - .err = err}); - amm.withdraw(WithdrawArg{ - .account = alice, - .asset1Out = USD(0.1), - .asset2Out = EUR(0.1), - .err = err}); + amm.withdraw(WithdrawArg{.account = alice, .asset1Out = EUR(0.1), .asset2Out = USD(0.1), .err = err}); + amm.withdraw(WithdrawArg{.account = alice, .asset1Out = USD(0.1), .asset2Out = EUR(0.1), .err = err}); }); // Single withdraw test([&](AMM& amm) { - amm.withdraw(WithdrawArg{ - .account = alice, .asset1Out = EUR(0.1), .err = err}); + amm.withdraw(WithdrawArg{.account = alice, .asset1Out = EUR(0.1), .err = err}); amm.withdraw(WithdrawArg{.account = alice, .asset1Out = USD(0.1)}); }); } @@ -7499,13 +5918,9 @@ private: auto const keylet = keylet::amm(amount.issue(), amount2.issue()); for (int i = 0; i < 256; ++i) { - AccountID const accountId = - ripple::pseudoAccountAddress(*env.current(), keylet.key); + AccountID const accountId = xrpl::pseudoAccountAddress(*env.current(), keylet.key); - env(pay(env.master.id(), accountId, XRP(1000)), - seq(autofill), - fee(autofill), - sig(autofill)); + env(pay(env.master.id(), accountId, XRP(1000)), seq(autofill), fee(autofill), sig(autofill)); } AMM ammAlice( @@ -7513,15 +5928,11 @@ private: alice, amount, amount2, - features[featureSingleAssetVault] ? ter{terADDRESS_COLLISION} - : ter{tecDUPLICATE}); + features[featureSingleAssetVault] ? ter{terADDRESS_COLLISION} : ter{tecDUPLICATE}); }; - testCase( - "tecDUPLICATE", testable_amendments() - featureSingleAssetVault); - testCase( - "terADDRESS_COLLISION", - testable_amendments() | featureSingleAssetVault); + testCase("tecDUPLICATE", testable_amendments() - featureSingleAssetVault); + testCase("terADDRESS_COLLISION", testable_amendments() | featureSingleAssetVault); } void @@ -7545,20 +5956,16 @@ private: AMM amm(env, gw, xrpBalance, xpmBalance, CreateArg{.tfee = tfee_}); // AMM LPToken balance required to replicate single deposit failure - STAmount lptAMMBalance{ - amm.lptIssue(), UINT64_C(3'234'987'266'485968), -6}; - auto const burn = - IOUAmount{amm.getLPTokensBalance() - lptAMMBalance}; + STAmount lptAMMBalance{amm.lptIssue(), UINT64_C(3'234'987'266'485968), -6}; + auto const burn = IOUAmount{amm.getLPTokensBalance() - lptAMMBalance}; // burn tokens to get to the required AMM state env(amm.bid(BidArg{.account = gw, .bidMin = burn, .bidMax = burn})); cb(amm, env); }; test( [&](AMM& amm, Env& env) { - auto const err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) - : ter(tecUNFUNDED_AMM); - amm.deposit(DepositArg{ - .account = alice, .asset1In = amount, .err = err}); + auto const err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS) : ter(tecUNFUNDED_AMM); + amm.deposit(DepositArg{.account = alice, .asset1In = amount, .err = err}); }, tfee); test( @@ -7566,8 +5973,7 @@ private: auto const [amount, amount2, lptAMM] = amm.balances(XRP, XPM); auto const withdraw = STAmount{XPM, 1, -5}; amm.withdraw(WithdrawArg{.asset1Out = STAmount{XPM, 1, -5}}); - auto const [amount_, amount2_, lptAMM_] = - amm.balances(XRP, XPM); + auto const [amount_, amount2_, lptAMM_] = amm.balances(XRP, XPM); if (!env.enabled(fixAMMv1_3)) BEAST_EXPECT((amount2 - amount2_) > withdraw); else @@ -7577,16 +5983,12 @@ private: } void - invariant( - jtx::AMM& amm, - jtx::Env& env, - std::string const& msg, - bool shouldFail) + invariant(jtx::AMM& amm, jtx::Env& env, std::string const& msg, bool shouldFail) { auto const [amount, amount2, lptBalance] = amm.balances(GBP, EUR); - NumberRoundModeGuard g( - env.enabled(fixAMMv1_3) ? Number::upward : Number::getround()); + NumberMantissaScaleGuard sg(MantissaRange::small); + NumberRoundModeGuard g(env.enabled(fixAMMv1_3) ? Number::upward : Number::getround()); auto const res = root2(amount * amount2); if (shouldFail) @@ -7612,23 +6014,11 @@ private: { testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); - ammAlice.deposit( - DepositArg{.account = bob, .asset1In = deposit}); - invariant( - ammAlice, - env, - "dep1", - deposit == STAmount{EUR, 1, -3} && - !env.enabled(fixAMMv1_3)); + ammAlice.deposit(DepositArg{.account = bob, .asset1In = deposit}); + invariant(ammAlice, env, "dep1", deposit == STAmount{EUR, 1, -3} && !env.enabled(fixAMMv1_3)); }, {{GBP(30'000), EUR(30'000)}}, 0, @@ -7639,24 +6029,13 @@ private: // Two-asset proportional deposit (1:1 pool ratio) testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); - STAmount const depositEuro{ - EUR, UINT64_C(10'1234567890123456), -16}; - STAmount const depositGBP{ - GBP, UINT64_C(10'1234567890123456), -16}; + STAmount const depositEuro{EUR, UINT64_C(10'1234567890123456), -16}; + STAmount const depositGBP{GBP, UINT64_C(10'1234567890123456), -16}; - ammAlice.deposit(DepositArg{ - .account = bob, - .asset1In = depositEuro, - .asset2In = depositGBP}); + ammAlice.deposit(DepositArg{.account = bob, .asset1In = depositEuro, .asset2In = depositGBP}); invariant(ammAlice, env, "dep2", false); }, {{GBP(30'000), EUR(30'000)}}, @@ -7669,27 +6048,14 @@ private: { testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); STAmount const depositEuro{EUR, 1, exponent}; STAmount const depositGBP{GBP, 1, exponent}; - ammAlice.deposit(DepositArg{ - .account = bob, - .asset1In = depositEuro, - .asset2In = depositGBP}); - invariant( - ammAlice, - env, - "dep3", - exponent != -3 && !env.enabled(fixAMMv1_3)); + ammAlice.deposit(DepositArg{.account = bob, .asset1In = depositEuro, .asset2In = depositGBP}); + invariant(ammAlice, env, "dep3", exponent != -3 && !env.enabled(fixAMMv1_3)); }, {{GBP(10'000), EUR(30'000)}}, 0, @@ -7700,18 +6066,10 @@ private: // tfLPToken deposit testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); - ammAlice.deposit(DepositArg{ - .account = bob, - .tokens = IOUAmount{10'1234567890123456, -16}}); + ammAlice.deposit(DepositArg{.account = bob, .tokens = IOUAmount{10'1234567890123456, -16}}); invariant(ammAlice, env, "dep4", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7732,19 +6090,10 @@ private: { testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(1'000'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(1'000'000)}, Fund::Acct); env.close(); - ammAlice.deposit(DepositArg{ - .account = bob, - .tokens = tokens, - .asset1In = STAmount{EUR, 1, 6}}); + ammAlice.deposit(DepositArg{.account = bob, .tokens = tokens, .asset1In = STAmount{EUR, 1, 6}}); invariant(ammAlice, env, "dep5", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7757,17 +6106,10 @@ private: // 1'000 GBP with EP not to exceed 5 (GBP/TokensOut) testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); - ammAlice.deposit( - bob, GBP(1'000), std::nullopt, STAmount{GBP, 5}); + ammAlice.deposit(bob, GBP(1'000), std::nullopt, STAmount{GBP, 5}); invariant(ammAlice, env, "dep6", false); }, {{GBP(30'000), EUR(30'000)}}, @@ -7797,8 +6139,7 @@ private: // tfWithdrawAll mode testAMM( [&](AMM& ammAlice, Env& env) { - ammAlice.withdraw( - WithdrawArg{.account = alice, .flags = tfWithdrawAll}); + ammAlice.withdraw(WithdrawArg{.account = alice, .flags = tfWithdrawAll}); invariant(ammAlice, env, "with2", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7828,10 +6169,8 @@ private: // errors testAMM( [&](AMM& ammAlice, Env& env) { - ammAlice.withdraw(WithdrawArg{ - .account = alice, - .asset1Out = STAmount{GBP, 1'234}, - .flags = tfSingleAsset}); + ammAlice.withdraw( + WithdrawArg{.account = alice, .asset1Out = STAmount{GBP, 1'234}, .flags = tfSingleAsset}); invariant(ammAlice, env, "with4", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7842,22 +6181,13 @@ private: // tfOneAssetWithdrawAll mode testAMM( [&](AMM& ammAlice, Env& env) { - fund( - env, - gw, - {bob}, - XRP(10'000'000), - {GBP(100'000), EUR(100'000)}, - Fund::Acct); + fund(env, gw, {bob}, XRP(10'000'000), {GBP(100'000), EUR(100'000)}, Fund::Acct); env.close(); - ammAlice.deposit(DepositArg{ - .account = bob, .asset1In = STAmount{GBP, 3'456}}); + ammAlice.deposit(DepositArg{.account = bob, .asset1In = STAmount{GBP, 3'456}}); - ammAlice.withdraw(WithdrawArg{ - .account = bob, - .asset1Out = STAmount{GBP, 1'000}, - .flags = tfOneAssetWithdrawAll}); + ammAlice.withdraw( + WithdrawArg{.account = bob, .asset1Out = STAmount{GBP, 1'000}, .flags = tfOneAssetWithdrawAll}); invariant(ammAlice, env, "with5", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7869,10 +6199,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.withdraw(WithdrawArg{ - .account = alice, - .tokens = 1'000, - .asset1Out = STAmount{GBP, 100}, - .flags = tfOneAssetLPToken}); + .account = alice, .tokens = 1'000, .asset1Out = STAmount{GBP, 100}, .flags = tfOneAssetLPToken}); invariant(ammAlice, env, "with6", false); }, {{GBP(7'000), EUR(30'000)}}, @@ -7884,10 +6211,7 @@ private: testAMM( [&](AMM& ammAlice, Env& env) { ammAlice.withdraw(WithdrawArg{ - .account = alice, - .asset1Out = STAmount{GBP, 100}, - .maxEP = IOUAmount{2}, - .flags = tfLimitLPToken}); + .account = alice, .asset1Out = STAmount{GBP, 100}, .maxEP = IOUAmount{2}, .flags = tfLimitLPToken}); invariant(ammAlice, env, "with7", true); }, {{GBP(7'000), EUR(30'000)}}, @@ -7899,7 +6223,7 @@ private: void run() override { - FeatureBitset const all{jtx::testable_amendments()}; + FeatureBitset const all{testable_amendments()}; testInvalidInstance(); testInstanceCreate(); testInvalidDeposit(all); @@ -7917,8 +6241,7 @@ private: testBasicPaymentEngine(all); testBasicPaymentEngine(all - fixAMMv1_1 - fixAMMv1_3); testBasicPaymentEngine(all - fixReducedOffersV2); - testBasicPaymentEngine( - all - fixAMMv1_1 - fixAMMv1_3 - fixReducedOffersV2); + testBasicPaymentEngine(all - fixAMMv1_1 - fixAMMv1_3 - fixReducedOffersV2); testAMMTokens(); testAmendment(); testFlags(); @@ -7957,8 +6280,7 @@ private: testAMMDepositWithFrozenAssets(all); testAMMDepositWithFrozenAssets(all - featureAMMClawback); testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback); - testAMMDepositWithFrozenAssets( - all - fixAMMv1_1 - fixAMMv1_3 - featureAMMClawback); + testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - fixAMMv1_3 - featureAMMClawback); testFixReserveCheckOnWithdrawal(all); testFixReserveCheckOnWithdrawal(all - fixAMMv1_2); testDepositAndWithdrawRounding(all); @@ -7971,7 +6293,7 @@ private: } }; -BEAST_DEFINE_TESTSUITE_PRIO(AMM, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(AMM, app, xrpl, 1); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index a8f946c454..7c9a593cae 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class AccountDelete_test : public beast::unit_test::suite @@ -36,8 +17,7 @@ private: verifyDeliveredAmount(jtx::Env& env, STAmount const& amount) { // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; // Verify DeliveredAmount and delivered_amount metadata are correct. // We can't use env.meta() here, because meta() doesn't include @@ -101,9 +81,7 @@ public: env(acctdelete(alice, becky), fee(drops(-1)), ter(temBAD_FEE)); // Invalid flags. - env(acctdelete(alice, becky), - txflags(tfImmediateOrCancel), - ter(temINVALID_FLAG)); + env(acctdelete(alice, becky), txflags(tfImmediateOrCancel), ter(temINVALID_FLAG)); // Account deletion has a high fee. Make sure the fee requirement // behaves as we expect. @@ -111,9 +89,7 @@ public: env(acctdelete(alice, becky), ter(telINSUF_FEE_P)); // Try a fee one drop less than the required amount. - env(acctdelete(alice, becky), - fee(acctDelFee - drops(1)), - ter(telINSUF_FEE_P)); + env(acctdelete(alice, becky), fee(acctDelFee - drops(1)), ter(telINSUF_FEE_P)); // alice's account is created too recently to be deleted. env(acctdelete(alice, becky), fee(acctDelFee), ter(tecTOO_SOON)); @@ -122,7 +98,7 @@ public: env(trust(becky, gw["USD"](1000))); env.close(); - // Give carol a deposit preauthorization, an offer, a ticket, + // Give carol a deposit pre-authorization, an offer, a ticket, // a signer list, and a DID. Even with all that she's still deletable. env(deposit::auth(carol, becky)); std::uint32_t const carolOfferSeq{env.seq(carol)}; @@ -164,9 +140,7 @@ public: BEAST_EXPECT(!env.closed()->exists(keylet::ownerDir(alice.id()))); // Verify that alice's XRP, minus the fee, was transferred to becky. - BEAST_EXPECT( - env.balance(becky) == - aliceOldBalance + beckyOldBalance - acctDelFee); + BEAST_EXPECT(env.balance(becky) == aliceOldBalance + beckyOldBalance - acctDelFee); } // Attempt to delete becky's account but get stopped by the trust line. @@ -195,15 +169,12 @@ public: auto const carolOldBalance{env.balance(carol)}; // Verify that Carol's account, directory, deposit - // preauthorization, offer, ticket, and signer list exist. + // pre-authorization, offer, ticket, and signer list exist. BEAST_EXPECT(env.closed()->exists(keylet::account(carol.id()))); BEAST_EXPECT(env.closed()->exists(keylet::ownerDir(carol.id()))); - BEAST_EXPECT(env.closed()->exists( - keylet::depositPreauth(carol.id(), becky.id()))); - BEAST_EXPECT( - env.closed()->exists(keylet::offer(carol.id(), carolOfferSeq))); - BEAST_EXPECT(env.closed()->exists( - keylet::ticket(carol.id(), carolTicketSeq))); + BEAST_EXPECT(env.closed()->exists(keylet::depositPreauth(carol.id(), becky.id()))); + BEAST_EXPECT(env.closed()->exists(keylet::offer(carol.id(), carolOfferSeq))); + BEAST_EXPECT(env.closed()->exists(keylet::ticket(carol.id(), carolTicketSeq))); BEAST_EXPECT(env.closed()->exists(keylet::signers(carol.id()))); // Delete carol's account even with stuff in her directory. Show @@ -215,18 +186,13 @@ public: // Verify that Carol's account, directory, and other stuff are gone. BEAST_EXPECT(!env.closed()->exists(keylet::account(carol.id()))); BEAST_EXPECT(!env.closed()->exists(keylet::ownerDir(carol.id()))); - BEAST_EXPECT(!env.closed()->exists( - keylet::depositPreauth(carol.id(), becky.id()))); - BEAST_EXPECT(!env.closed()->exists( - keylet::offer(carol.id(), carolOfferSeq))); - BEAST_EXPECT(!env.closed()->exists( - keylet::ticket(carol.id(), carolTicketSeq))); + BEAST_EXPECT(!env.closed()->exists(keylet::depositPreauth(carol.id(), becky.id()))); + BEAST_EXPECT(!env.closed()->exists(keylet::offer(carol.id(), carolOfferSeq))); + BEAST_EXPECT(!env.closed()->exists(keylet::ticket(carol.id(), carolTicketSeq))); BEAST_EXPECT(!env.closed()->exists(keylet::signers(carol.id()))); // Verify that Carol's XRP, minus the fee, was transferred to becky. - BEAST_EXPECT( - env.balance(becky) == - carolOldBalance + beckyOldBalance - acctDelFee); + BEAST_EXPECT(env.balance(becky) == carolOldBalance + beckyOldBalance - acctDelFee); // Since becky received an influx of XRP, her lsfPasswordSpent bit // is cleared and she can change her regular key for free again. @@ -287,12 +253,8 @@ public: testcase("Owned types"); - // We want to test both... - // o Old-style PayChannels without a recipient backlink as well as - // o New-styled PayChannels with the backlink. - // So we start the test using old-style PayChannels. Then we pass - // the amendment to get new-style PayChannels. - Env env{*this, testable_amendments() - fixPayChanRecipientOwnerDir}; + // We want to test PayChannels with the backlink. + Env env{*this, testable_amendments()}; Account const alice("alice"); Account const becky("becky"); Account const gw("gw"); @@ -351,8 +313,7 @@ public: // Now cancel the escrow, but create a payment channel between // alice and becky. - bool const withTokenEscrow = - env.current()->rules().enabled(featureTokenEscrow); + bool const withTokenEscrow = env.current()->rules().enabled(featureTokenEscrow); if (withTokenEscrow) { Account const gw1("gw1"); @@ -374,9 +335,7 @@ public: incLgrSeqForAccDel(env, gw1); - env(acctdelete(gw1, becky), - fee(acctDelFee), - ter(tecHAS_OBLIGATIONS)); + env(acctdelete(gw1, becky), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); env.close(); env(escrow::cancel(becky, carol, escrowSeq)); @@ -386,29 +345,23 @@ public: env(escrow::cancel(becky, alice, escrowSeq)); env.close(); - Keylet const alicePayChanKey{ - keylet::payChan(alice, becky, env.seq(alice))}; + Keylet const alicePayChanKey{keylet::payChan(alice, becky, env.seq(alice))}; - env(payChanCreate( - alice, becky, XRP(57), 4s, env.now() + 2s, alice.pk())); + env(payChanCreate(alice, becky, XRP(57), 4s, env.now() + 2s, alice.pk())); env.close(); - // An old-style PayChannel does not add a back link from the - // destination. So with the PayChannel in place becky should be - // able to delete her account, but alice should not. + // With the PayChannel in place becky and alice should not be + // able to delete her account auto const beckyBalance{env.balance(becky)}; env(acctdelete(alice, gw), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); - env(acctdelete(becky, gw), fee(acctDelFee)); - verifyDeliveredAmount(env, beckyBalance - acctDelFee); + env(acctdelete(becky, gw), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); env.close(); - // Alice cancels her PayChannel which will leave her with only offers + // Alice cancels her PayChannel, which will leave her with only offers // in her directory. // Lambda to close a PayChannel. - auto payChanClose = [](jtx::Account const& account, - Keylet const& payChanKeylet, - PublicKey const& pk) { + auto payChanClose = [](jtx::Account const& account, Keylet const& payChanKeylet, PublicKey const& pk) { Json::Value jv; jv[jss::TransactionType] = jss::PaymentChannelClaim; jv[jss::Flags] = tfClose; @@ -420,14 +373,8 @@ public: env(payChanClose(alice, alicePayChanKey, alice.pk())); env.close(); - // Now enable the amendment so PayChannels add a backlink from the - // destination. - env.enableFeature(fixPayChanRecipientOwnerDir); - env.close(); - - // gw creates a PayChannel with alice as the destination. With the - // amendment passed this should prevent alice from deleting her - // account. + // gw creates a PayChannel with alice as the destination, this should + // prevent alice from deleting her account. Keylet const gwPayChanKey{keylet::payChan(gw, alice, env.seq(gw))}; env(payChanCreate(gw, alice, XRP(68), 4s, env.now() + 2s, alice.pk())); @@ -449,138 +396,6 @@ public: env.close(); } - void - testResurrection() - { - // Create an account with an old-style PayChannel. Delete the - // destination of the PayChannel then resurrect the destination. - // The PayChannel should still work. - using namespace jtx; - - testcase("Resurrection"); - - // We need an old-style PayChannel that doesn't provide a backlink - // from the destination. So don't enable the amendment with that fix. - Env env{*this, testable_amendments() - fixPayChanRecipientOwnerDir}; - Account const alice("alice"); - Account const becky("becky"); - - env.fund(XRP(10000), alice, becky); - env.close(); - - // Verify that becky's account root is present. - Keylet const beckyAcctKey{keylet::account(becky.id())}; - BEAST_EXPECT(env.closed()->exists(beckyAcctKey)); - - using namespace std::chrono_literals; - Keylet const payChanKey{keylet::payChan(alice, becky, env.seq(alice))}; - auto const payChanXRP = XRP(37); - - env(payChanCreate( - alice, becky, payChanXRP, 4s, env.now() + 1h, alice.pk())); - env.close(); - BEAST_EXPECT(env.closed()->exists(payChanKey)); - - // Close enough ledgers to be able to delete becky's account. - incLgrSeqForAccDel(env, becky); - - auto const beckyPreDelBalance{env.balance(becky)}; - - auto const acctDelFee{drops(env.current()->fees().increment)}; - env(acctdelete(becky, alice), fee(acctDelFee)); - verifyDeliveredAmount(env, beckyPreDelBalance - acctDelFee); - env.close(); - - // Verify that becky's account root is gone. - BEAST_EXPECT(!env.closed()->exists(beckyAcctKey)); - - // All it takes is a large enough XRP payment to resurrect - // becky's account. Try too small a payment. - env(pay(alice, - becky, - drops(env.current()->fees().accountReserve(0)) - XRP(1)), - ter(tecNO_DST_INSUF_XRP)); - env.close(); - - // Actually resurrect becky's account. - env(pay(alice, becky, XRP(10))); - env.close(); - - // becky's account root should be back. - BEAST_EXPECT(env.closed()->exists(beckyAcctKey)); - BEAST_EXPECT(env.balance(becky) == XRP(10)); - - // becky's resurrected account can be the destination of alice's - // PayChannel. - auto payChanClaim = [&]() { - Json::Value jv; - jv[jss::TransactionType] = jss::PaymentChannelClaim; - jv[jss::Account] = alice.human(); - jv[sfChannel.jsonName] = to_string(payChanKey.key); - jv[sfBalance.jsonName] = - payChanXRP.value().getJson(JsonOptions::none); - return jv; - }; - env(payChanClaim()); - env.close(); - - BEAST_EXPECT(env.balance(becky) == XRP(10) + payChanXRP); - } - - void - testAmendmentEnable() - { - // Start with the featureDeletableAccounts amendment disabled. - // Then enable the amendment and delete an account. - using namespace jtx; - - testcase("Amendment enable"); - - Env env{*this, testable_amendments() - featureDeletableAccounts}; - Account const alice("alice"); - Account const becky("becky"); - - env.fund(XRP(10000), alice, becky); - env.close(); - - // Close enough ledgers to be able to delete alice's account. - incLgrSeqForAccDel(env, alice); - - // Verify that alice's account root is present. - Keylet const aliceAcctKey{keylet::account(alice.id())}; - BEAST_EXPECT(env.closed()->exists(aliceAcctKey)); - - auto const alicePreDelBal{env.balance(alice)}; - auto const beckyPreDelBal{env.balance(becky)}; - - auto const acctDelFee{drops(env.current()->fees().increment)}; - env(acctdelete(alice, becky), fee(acctDelFee), ter(temDISABLED)); - env.close(); - - // Verify that alice's account root is still present and alice and - // becky both have their XRP. - BEAST_EXPECT(env.current()->exists(aliceAcctKey)); - BEAST_EXPECT(env.balance(alice) == alicePreDelBal); - BEAST_EXPECT(env.balance(becky) == beckyPreDelBal); - - // When the amendment is enabled the previous transaction is - // retried into the new open ledger and succeeds. - env.enableFeature(featureDeletableAccounts); - env.close(); - - // alice's account is still in the most recently closed ledger. - BEAST_EXPECT(env.closed()->exists(aliceAcctKey)); - - // Verify that alice's account root is gone from the current ledger - // and becky has alice's XRP. - BEAST_EXPECT(!env.current()->exists(aliceAcctKey)); - BEAST_EXPECT( - env.balance(becky) == alicePreDelBal + beckyPreDelBal - acctDelFee); - - env.close(); - BEAST_EXPECT(!env.closed()->exists(aliceAcctKey)); - } - void testTooManyOffers() { @@ -646,8 +461,7 @@ public: // alice's offers. for (std::uint32_t i{0}; i < offerCount; ++i) - BEAST_EXPECT( - closed->exists(keylet::offer(alice.id(), offerSeq0 + i))); + BEAST_EXPECT(closed->exists(keylet::offer(alice.id(), offerSeq0 + i))); } // Delete alice's account. Should fail because she has too many @@ -677,13 +491,11 @@ public: // alice's former directory nodes. for (std::uint32_t i{0}; i < ((offerCount / 32) + 1); ++i) - BEAST_EXPECT( - !closed->exists(keylet::page(aliceOwnerDirKey, i))); + BEAST_EXPECT(!closed->exists(keylet::page(aliceOwnerDirKey, i))); // alice's former offers. for (std::uint32_t i{0}; i < offerCount; ++i) - BEAST_EXPECT( - !closed->exists(keylet::offer(alice.id(), offerSeq0 + i))); + BEAST_EXPECT(!closed->exists(keylet::offer(alice.id(), offerSeq0 + i))); } } @@ -763,9 +575,7 @@ public: // // The balance of env.master should not change. auto const masterBalance{env.balance(env.master)}; - env(acctdelete(alice, env.master), - fee(acctDelFee), - ter(terINSUF_FEE_B)); + env(acctdelete(alice, env.master), fee(acctDelFee), ter(terINSUF_FEE_B)); env.close(); { std::shared_ptr const closed{env.closed()}; @@ -810,8 +620,7 @@ public: BEAST_EXPECT(closed->exists(keylet::account(bob.id()))); for (std::uint32_t i = 0; i < 250; ++i) { - BEAST_EXPECT( - closed->exists(keylet::ticket(bob.id(), ticketSeq + i))); + BEAST_EXPECT(closed->exists(keylet::ticket(bob.id(), ticketSeq + i))); } } @@ -830,8 +639,7 @@ public: BEAST_EXPECT(!closed->exists(keylet::account(bob.id()))); for (std::uint32_t i = 0; i < 250; ++i) { - BEAST_EXPECT( - !closed->exists(keylet::ticket(bob.id(), ticketSeq + i))); + BEAST_EXPECT(!closed->exists(keylet::ticket(bob.id(), ticketSeq + i))); } } } @@ -895,8 +703,7 @@ public: testDestinationDepositAuthCredentials() { { - testcase( - "Destination Constraints with DepositPreauth and Credentials"); + testcase("Destination Constraints with DepositPreauth and Credentials"); using namespace test::jtx; @@ -916,8 +723,7 @@ public: env.close(); // get credentials index - auto const jv = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jv = credentials::ledgerEntry(env, becky, carol, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); // Close enough ledgers to be able to delete becky's account. @@ -926,10 +732,7 @@ public: auto const acctDelFee{drops(env.current()->fees().increment)}; // becky use credentials but they aren't accepted - env(acctdelete(becky, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(tecBAD_CREDENTIALS)); + env(acctdelete(becky, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(tecBAD_CREDENTIALS)); env.close(); { @@ -941,10 +744,7 @@ public: } // Fail, credentials still not accepted - env(acctdelete(becky, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(tecBAD_CREDENTIALS)); + env(acctdelete(becky, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(tecBAD_CREDENTIALS)); env.close(); // becky accept the credentials @@ -952,16 +752,10 @@ public: env.close(); // Fail, credentials doesn’t belong to carol - env(acctdelete(carol, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(tecBAD_CREDENTIALS)); + env(acctdelete(carol, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(tecBAD_CREDENTIALS)); // Fail, no depositPreauth for provided credentials - env(acctdelete(becky, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(tecNO_PERMISSION)); + env(acctdelete(becky, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(tecNO_PERMISSION)); env.close(); // alice create DepositPreauth Object @@ -970,38 +764,28 @@ public: // becky attempts to delete her account, but alice won't take her // XRP, so the delete is blocked. - env(acctdelete(becky, alice), - fee(acctDelFee), - ter(tecNO_PERMISSION)); + env(acctdelete(becky, alice), fee(acctDelFee), ter(tecNO_PERMISSION)); // becky use empty credentials and can't delete account - env(acctdelete(becky, alice), - fee(acctDelFee), - credentials::ids({}), - ter(temMALFORMED)); + env(acctdelete(becky, alice), fee(acctDelFee), credentials::ids({}), ter(temMALFORMED)); // becky use bad credentials and can't delete account env(acctdelete(becky, alice), - credentials::ids( - {"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6E" - "A288BE4"}), + credentials::ids({"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6E" + "A288BE4"}), fee(acctDelFee), ter(tecBAD_CREDENTIALS)); env.close(); // becky use credentials and can delete account - env(acctdelete(becky, alice), - credentials::ids({credIdx}), - fee(acctDelFee)); + env(acctdelete(becky, alice), credentials::ids({credIdx}), fee(acctDelFee)); env.close(); { // check that credential object deleted too - auto const jNoCred = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jNoCred = credentials::ledgerEntry(env, becky, carol, credType); BEAST_EXPECT( - jNoCred.isObject() && jNoCred.isMember(jss::result) && - jNoCred[jss::result].isMember(jss::error) && + jNoCred.isObject() && jNoCred.isMember(jss::result) && jNoCred[jss::result].isMember(jss::error) && jNoCred[jss::result][jss::error] == "entryNotFound"); } @@ -1012,24 +796,18 @@ public: env(credentials::accept(daria, carol, credType)); env.close(); std::string const credDaria = - credentials::ledgerEntry( - env, daria, carol, credType)[jss::result][jss::index] - .asString(); + credentials::ledgerEntry(env, daria, carol, credType)[jss::result][jss::index].asString(); // daria use valid credentials, which aren't required and can // delete her account - env(acctdelete(daria, carol), - credentials::ids({credDaria}), - fee(acctDelFee)); + env(acctdelete(daria, carol), credentials::ids({credDaria}), fee(acctDelFee)); env.close(); // check that credential object deleted too - auto const jNoCred = - credentials::ledgerEntry(env, daria, carol, credType); + auto const jNoCred = credentials::ledgerEntry(env, daria, carol, credType); BEAST_EXPECT( - jNoCred.isObject() && jNoCred.isMember(jss::result) && - jNoCred[jss::result].isMember(jss::error) && + jNoCred.isObject() && jNoCred.isMember(jss::result) && jNoCred[jss::result].isMember(jss::error) && jNoCred[jss::result][jss::error] == "entryNotFound"); } @@ -1045,11 +823,9 @@ public: env(credentials::accept(eaton, carol, credType)); env.close(); std::string const credEaton = - credentials::ledgerEntry( - env, eaton, carol, credType)[jss::result][jss::index] - .asString(); + credentials::ledgerEntry(env, eaton, carol, credType)[jss::result][jss::index].asString(); - // fred make preauthorization through authorized account + // fred make pre-authorization through authorized account env(fset(fred, asfDepositAuth)); env.close(); env(deposit::auth(fred, eaton)); @@ -1061,18 +837,14 @@ public: // eaton use valid credentials, but he already authorized // through "Authorized" field. - env(acctdelete(eaton, fred), - credentials::ids({credEaton}), - fee(acctDelFee)); + env(acctdelete(eaton, fred), credentials::ids({credEaton}), fee(acctDelFee)); env.close(); // check that credential object deleted too - auto const jNoCred = - credentials::ledgerEntry(env, eaton, carol, credType); + auto const jNoCred = credentials::ledgerEntry(env, eaton, carol, credType); BEAST_EXPECT( - jNoCred.isObject() && jNoCred.isMember(jss::result) && - jNoCred[jss::result].isMember(jss::error) && + jNoCred.isObject() && jNoCred.isMember(jss::result) && jNoCred[jss::result].isMember(jss::error) && jNoCred[jss::result][jss::error] == "entryNotFound"); } @@ -1084,37 +856,27 @@ public: env.close(); auto jv = credentials::create(john, carol, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 20; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 20; jv[sfExpiration.jsonName] = t; env(jv); env.close(); env(credentials::accept(john, carol, credType)); env.close(); jv = credentials::ledgerEntry(env, john, carol, credType); - std::string const credIdx = - jv[jss::result][jss::index].asString(); + std::string const credIdx = jv[jss::result][jss::index].asString(); incLgrSeqForAccDel(env, john); // credentials are expired // john use credentials but can't delete account - env(acctdelete(john, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(tecEXPIRED)); + env(acctdelete(john, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(tecEXPIRED)); env.close(); { // check that expired credential object deleted - auto jv = - credentials::ledgerEntry(env, john, carol, credType); + auto jv = credentials::ledgerEntry(env, john, carol, credType); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && jv[jss::result].isMember(jss::error) && jv[jss::result][jss::error] == "entryNotFound"); } } @@ -1151,10 +913,7 @@ public: env(deposit::auth(alice, becky)); env.close(); - env(acctdelete(becky, alice), - credentials::ids({credIdx}), - fee(acctDelFee), - ter(temDISABLED)); + env(acctdelete(becky, alice), credentials::ids({credIdx}), fee(acctDelFee), ter(temDISABLED)); env.close(); } } @@ -1184,8 +943,7 @@ public: env.close(); // get credentials index - auto const jv = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jv = credentials::ledgerEntry(env, becky, carol, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); // Close enough ledgers to be able to delete carol's account. @@ -1197,11 +955,9 @@ public: { // check that credential object deleted too BEAST_EXPECT(!env.le(credIdx)); - auto const jv = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jv = credentials::ledgerEntry(env, becky, carol, credType); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && jv[jss::result].isMember(jss::error) && jv[jss::result][jss::error] == "entryNotFound"); } } @@ -1228,8 +984,7 @@ public: env.close(); // get credentials index - auto const jv = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jv = credentials::ledgerEntry(env, becky, carol, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); // Close enough ledgers to be able to delete carol's account. @@ -1241,11 +996,9 @@ public: { // check that credential object deleted too BEAST_EXPECT(!env.le(credIdx)); - auto const jv = - credentials::ledgerEntry(env, becky, carol, credType); + auto const jv = credentials::ledgerEntry(env, becky, carol, credType); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && jv[jss::result].isMember(jss::error) && jv[jss::result][jss::error] == "entryNotFound"); } } @@ -1257,8 +1010,6 @@ public: testBasics(); testDirectories(); testOwnedTypes(); - testResurrection(); - testAmendmentEnable(); testTooManyOffers(); testImplicitlyCreatedTrustline(); testBalanceTooSmallForFee(); @@ -1269,7 +1020,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, xrpl, 2); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AccountTxPaging_test.cpp b/src/test/app/AccountTxPaging_test.cpp index 46a56f58e3..27078f0578 100644 --- a/src/test/app/AccountTxPaging_test.cpp +++ b/src/test/app/AccountTxPaging_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,16 +6,14 @@ #include -namespace ripple { +namespace xrpl { class AccountTxPaging_test : public beast::unit_test::suite { bool checkTransaction(Json::Value const& tx, int sequence, int ledger) { - return ( - tx[jss::tx][jss::Sequence].asInt() == sequence && - tx[jss::tx][jss::ledger_index].asInt() == ledger); + return (tx[jss::tx][jss::Sequence].asInt() == sequence && tx[jss::tx][jss::ledger_index].asInt() == ledger); } auto @@ -270,6 +249,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple); +BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/AmendmentTable_test.cpp b/src/test/app/AmendmentTable_test.cpp index 35f59ea2d8..1e4b096927 100644 --- a/src/test/app/AmendmentTable_test.cpp +++ b/src/test/app/AmendmentTable_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { class AmendmentTable_test final : public beast::unit_test::suite { @@ -53,9 +34,7 @@ private: } static Section - makeSection( - std::string const& name, - std::vector const& amendments) + makeSection(std::string const& name, std::vector const& amendments) { Section section(name); for (auto const& a : amendments) @@ -81,17 +60,13 @@ private: makeConfig() { auto cfg = test::jtx::envconfig(); - cfg->section(SECTION_AMENDMENTS) = - makeSection(SECTION_AMENDMENTS, enabled_); - cfg->section(SECTION_VETO_AMENDMENTS) = - makeSection(SECTION_VETO_AMENDMENTS, vetoed_); + cfg->section(SECTION_AMENDMENTS) = makeSection(SECTION_AMENDMENTS, enabled_); + cfg->section(SECTION_VETO_AMENDMENTS) = makeSection(SECTION_VETO_AMENDMENTS, vetoed_); return cfg; } static std::vector - makeFeatureInfo( - std::vector const& amendments, - VoteBehavior voteBehavior) + makeFeatureInfo(std::vector const& amendments, VoteBehavior voteBehavior) { std::vector result; result.reserve(amendments.size()); @@ -111,8 +86,7 @@ private: static std::vector makeDefaultYes(uint256 const amendment) { - std::vector result{ - {to_string(amendment), amendment, VoteBehavior::DefaultYes}}; + std::vector result{{to_string(amendment), amendment, VoteBehavior::DefaultYes}}; return result; } @@ -139,10 +113,7 @@ private: template static void - combine_arg( - std::vector& dest, - std::vector const& src, - Args const&... args) + combine_arg(std::vector& dest, std::vector const& src, Args const&... args) { assert(dest.capacity() >= dest.size() + src.size()); std::copy(src.begin(), src.end(), std::back_inserter(dest)); @@ -170,14 +141,11 @@ private: // Enabled amendments are typically a subset of supported amendments. // Vetoed amendments should be supported but not enabled. // Unsupported amendments may be added to the AmendmentTable. - std::vector const - yes_{"g", "i", "k", "m", "o", "q", "r", "s", "t", "u"}; - std::vector const - enabled_{"b", "d", "f", "h", "j", "l", "n", "p"}; + std::vector const yes_{"g", "i", "k", "m", "o", "q", "r", "s", "t", "u"}; + std::vector const enabled_{"b", "d", "f", "h", "j", "l", "n", "p"}; std::vector const vetoed_{"a", "c", "e"}; std::vector const obsolete_{"0", "1", "2"}; - std::vector const allSupported_{ - combine(yes_, enabled_, vetoed_, obsolete_)}; + std::vector const allSupported_{combine(yes_, enabled_, vetoed_, obsolete_)}; std::vector const unsupported_{"v", "w", "x"}; std::vector const unsupportedMajority_{"y", "z"}; @@ -199,8 +167,7 @@ public: Section const& enabled, Section const& vetoed) { - return make_AmendmentTable( - app, majorityTime, supported, enabled, vetoed, journal_); + return make_AmendmentTable(app, majorityTime, supported, enabled, vetoed, journal_); } std::unique_ptr @@ -217,22 +184,16 @@ public: std::unique_ptr makeTable(test::jtx::Env& env, std::chrono::seconds majorityTime) { - static std::vector const supported = - combine( - makeDefaultYes(yes_), - // Use non-intuitive default votes for "enabled_" and "vetoed_" - // so that when the tests later explicitly enable or veto them, - // we can be certain that they are not simply going by their - // default vote setting. - makeDefaultNo(enabled_), - makeDefaultYes(vetoed_), - makeObsolete(obsolete_)); - return makeTable( - env.app(), - majorityTime, - supported, - makeSection(enabled_), - makeSection(vetoed_)); + static std::vector const supported = combine( + makeDefaultYes(yes_), + // Use non-intuitive default votes for "enabled_" and "vetoed_" + // so that when the tests later explicitly enable or veto them, + // we can be certain that they are not simply going by their + // default vote setting. + makeDefaultNo(enabled_), + makeDefaultYes(vetoed_), + makeObsolete(obsolete_)); + return makeTable(env.app(), majorityTime, supported, makeSection(enabled_), makeSection(vetoed_)); } void @@ -289,16 +250,14 @@ public: // Verify that unsupportedID is not in table. uint256 const unsupportedID = amendmentId(unsupported_[0]); { - Json::Value const unsupp = - table->getJson(unsupportedID, true)[to_string(unsupportedID)]; + Json::Value const unsupp = table->getJson(unsupportedID, true)[to_string(unsupportedID)]; BEAST_EXPECT(unsupp.size() == 0); } // After vetoing unsupportedID verify that it is in table. table->veto(unsupportedID); { - Json::Value const unsupp = - table->getJson(unsupportedID, true)[to_string(unsupportedID)]; + Json::Value const unsupp = table->getJson(unsupportedID, true)[to_string(unsupportedID)]; BEAST_EXPECT(unsupp[jss::vetoed].asBool()); } } @@ -324,8 +283,7 @@ public: } catch (std::exception const& e) { - BEAST_EXPECT( - e.what() == "Invalid entry '" + id + "' in [Test]"); + BEAST_EXPECT(e.what() == "Invalid entry '" + id + "' in [Test]"); } } @@ -341,9 +299,7 @@ public: } catch (std::exception const& e) { - BEAST_EXPECT( - e.what() == - "Invalid entry '" + id + " Test Name' in [Test]"); + BEAST_EXPECT(e.what() == "Invalid entry '" + id + " Test Name' in [Test]"); } } @@ -362,8 +318,7 @@ public: } catch (std::exception const& e) { - BEAST_EXPECT( - e.what() == "Invalid entry '" + sid + " Name' in [Test]"); + BEAST_EXPECT(e.what() == "Invalid entry '" + sid + " Name' in [Test]"); } } @@ -382,8 +337,7 @@ public: } catch (std::exception const& e) { - BEAST_EXPECT( - e.what() == "Invalid entry '" + sid + " Name' in [Test]"); + BEAST_EXPECT(e.what() == "Invalid entry '" + sid + " Name' in [Test]"); } } @@ -403,8 +357,7 @@ public: } catch (std::exception const& e) { - BEAST_EXPECT( - e.what() == "Invalid entry '" + sid + " Name' in [Test]"); + BEAST_EXPECT(e.what() == "Invalid entry '" + sid + " Name' in [Test]"); } } } @@ -435,9 +388,7 @@ public: bool const enabled = table->isEnabled(supportedID); bool const found = allEnabled.find(supportedID) != allEnabled.end(); BEAST_EXPECTS( - enabled == found, - a + (enabled ? " enabled " : " disabled ") + - (found ? " found" : " not found")); + enabled == found, a + (enabled ? " enabled " : " disabled ") + (found ? " found" : " not found")); } // All supported and unVetoed amendments should be returned as desired. @@ -463,9 +414,7 @@ public: BEAST_EXPECT(table->unVeto(unvetoedID)); std::vector const desired = table->getDesired(); - BEAST_EXPECT( - std::find(desired.begin(), desired.end(), unvetoedID) != - desired.end()); + BEAST_EXPECT(std::find(desired.begin(), desired.end(), unvetoedID) != desired.end()); } // Veto all supported amendments. Now desired should be empty. @@ -494,8 +443,7 @@ public: trustedValidators.reserve(num); for (int i = 0; i < num; ++i) { - auto const& back = - ret.emplace_back(randomKeyPair(KeyType::secp256k1)); + auto const& back = ret.emplace_back(randomKeyPair(KeyType::secp256k1)); trustedValidators.insert(back.first); } table->trustChanged(trustedValidators); @@ -525,7 +473,7 @@ public: // Parameters: // table: Our table of known and vetoed amendments - // validators: The addreses of validators we trust + // validators: The addresses of validators we trust // votes: Amendments and the number of validators who vote for them // ourVotes: The amendments we vote for in our validation // enabled: In/out enabled amendments @@ -553,14 +501,9 @@ public: } auto v = std::make_shared( - ripple::NetClock::time_point{}, - pub, - sec, - calcNodeID(pub), - [&field](STValidation& v) { + xrpl::NetClock::time_point{}, pub, sec, calcNodeID(pub), [&field](STValidation& v) { if (!field.empty()) - v.setFieldV256( - sfAmendments, STVector256(sfAmendments, field)); + v.setFieldV256(sfAmendments, STVector256(sfAmendments, field)); v.setFieldU32(sfLedgerSequence, 6180339); }); @@ -569,8 +512,7 @@ public: ourVotes = table.doValidation(enabled); - auto actions = - table.doVoting(rules, roundTime, enabled, majority, validations); + auto actions = table.doVoting(rules, roundTime, enabled, majority, validations); for (auto const& [hash, action] : actions) { // This code assumes other validators do as we do @@ -589,15 +531,13 @@ public: case tfGotMajority: if (majority.find(hash) != majority.end()) - Throw( - "got majority while having majority"); + Throw("got majority while having majority"); majority[hash] = roundTime; break; case tfLostMajority: if (majority.find(hash) == majority.end()) - Throw( - "lost majority without majority"); + Throw("lost majority without majority"); majority.erase(hash); break; @@ -616,8 +556,7 @@ public: auto const testAmendment = amendmentId("TestAmendment"); test::jtx::Env env{*this, feat}; - auto table = - makeTable(env, weeks(2), emptyYes_, emptySection_, emptySection_); + auto table = makeTable(env, weeks(2), emptyYes_, emptySection_, emptySection_); auto const validators = makeValidators(10, table); @@ -626,30 +565,20 @@ public: std::set enabled; majorityAmendments_t majority; - doRound( - env.current()->rules(), - *table, - weeks{1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{1}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(majority.empty()); uint256 const unsupportedID = amendmentId(unsupported_[0]); { - Json::Value const unsupp = - table->getJson(unsupportedID, false)[to_string(unsupportedID)]; + Json::Value const unsupp = table->getJson(unsupportedID, false)[to_string(unsupportedID)]; BEAST_EXPECT(unsupp.size() == 0); } table->veto(unsupportedID); { - Json::Value const unsupp = - table->getJson(unsupportedID, false)[to_string(unsupportedID)]; + Json::Value const unsupp = table->getJson(unsupportedID, false)[to_string(unsupportedID)]; BEAST_EXPECT(!unsupp[jss::vetoed].asBool()); } @@ -657,15 +586,7 @@ public: votes.emplace_back(testAmendment, validators.size()); - doRound( - env.current()->rules(), - *table, - weeks{2}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{2}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); @@ -673,15 +594,7 @@ public: // Note that the simulation code assumes others behave as we do, // so the amendment won't get enabled - doRound( - env.current()->rules(), - *table, - weeks{5}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{5}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); } @@ -695,12 +608,7 @@ public: auto const testAmendment = amendmentId("vetoedAmendment"); test::jtx::Env env{*this, feat}; - auto table = makeTable( - env, - weeks(2), - emptyYes_, - emptySection_, - makeSection(testAmendment)); + auto table = makeTable(env, weeks(2), emptyYes_, emptySection_, makeSection(testAmendment)); auto const validators = makeValidators(10, table); @@ -709,44 +617,20 @@ public: std::set enabled; majorityAmendments_t majority; - doRound( - env.current()->rules(), - *table, - weeks{1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{1}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(majority.empty()); votes.emplace_back(testAmendment, validators.size()); - doRound( - env.current()->rules(), - *table, - weeks{2}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{2}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); majority[testAmendment] = hourTime(weeks{1}); - doRound( - env.current()->rules(), - *table, - weeks{5}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{5}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.empty()); BEAST_EXPECT(enabled.empty()); } @@ -758,8 +642,7 @@ public: testcase("voteEnable"); test::jtx::Env env{*this, feat}; - auto table = makeTable( - env, weeks(2), makeDefaultYes(yes_), emptySection_, emptySection_); + auto table = makeTable(env, weeks(2), makeDefaultYes(yes_), emptySection_, emptySection_); auto const validators = makeValidators(10, table); @@ -769,15 +652,7 @@ public: majorityAmendments_t majority; // Week 1: We should vote for all known amendments not enabled - doRound( - env.current()->rules(), - *table, - weeks{1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{1}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.size() == yes_.size()); BEAST_EXPECT(enabled.empty()); for (auto const& i : yes_) @@ -788,15 +663,7 @@ public: votes.emplace_back(amendmentId(i), validators.size()); // Week 2: We should recognize a majority - doRound( - env.current()->rules(), - *table, - weeks{2}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{2}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(ourVotes.size() == yes_.size()); BEAST_EXPECT(enabled.empty()); @@ -804,27 +671,11 @@ public: BEAST_EXPECT(majority[amendmentId(i)] == hourTime(weeks{2})); // Week 5: We should enable the amendment - doRound( - env.current()->rules(), - *table, - weeks{5}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{5}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.size() == yes_.size()); // Week 6: We should remove it from our votes and from having a majority - doRound( - env.current()->rules(), - *table, - weeks{6}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{6}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.size() == yes_.size()); BEAST_EXPECT(ourVotes.empty()); for (auto const& i : yes_) @@ -839,12 +690,7 @@ public: auto const testAmendment = amendmentId("detectMajority"); test::jtx::Env env{*this, feat}; - auto table = makeTable( - env, - weeks(2), - makeDefaultYes(testAmendment), - emptySection_, - emptySection_); + auto table = makeTable(env, weeks(2), makeDefaultYes(testAmendment), emptySection_, emptySection_); auto const validators = makeValidators(16, table); @@ -859,15 +705,7 @@ public: if ((i > 0) && (i < 17)) votes.emplace_back(testAmendment, i); - doRound( - env.current()->rules(), - *table, - weeks{i}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{i}, validators, votes, ourVotes, enabled, majority); if (i < 13) // 13 => 13/16 = 0.8125 => > 80% { @@ -909,12 +747,7 @@ public: auto const testAmendment = amendmentId("lostMajority"); test::jtx::Env env{*this, feat}; - auto table = makeTable( - env, - weeks(8), - makeDefaultYes(testAmendment), - emptySection_, - emptySection_); + auto table = makeTable(env, weeks(8), makeDefaultYes(testAmendment), emptySection_, emptySection_); auto const validators = makeValidators(16, table); @@ -928,15 +761,7 @@ public: votes.emplace_back(testAmendment, validators.size()); - doRound( - env.current()->rules(), - *table, - weeks{1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{1}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(!majority.empty()); @@ -950,15 +775,7 @@ public: // Gradually reduce support votes.emplace_back(testAmendment, validators.size() - i); - doRound( - env.current()->rules(), - *table, - weeks{i + 1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{i + 1}, validators, votes, ourVotes, enabled, majority); if (i < 4) // 16 - 3 = 13 => 13/16 = 0.8125 => > 80% { // 16 - 4 = 12 => 12/16 = 0.75 => < 80% @@ -985,15 +802,9 @@ public: auto const testAmendment = amendmentId("changedUNL"); test::jtx::Env env{*this, feat}; - auto table = makeTable( - env, - weeks(8), - makeDefaultYes(testAmendment), - emptySection_, - emptySection_); + auto table = makeTable(env, weeks(8), makeDefaultYes(testAmendment), emptySection_, emptySection_); - std::vector> validators = - makeValidators(10, table); + std::vector> validators = makeValidators(10, table); std::set enabled; majorityAmendments_t majority; @@ -1005,15 +816,7 @@ public: votes.emplace_back(testAmendment, validators.size() - 2); - doRound( - env.current()->rules(), - *table, - weeks{1}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{1}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(majority.empty()); @@ -1024,22 +827,18 @@ public: // A lambda that updates the AmendmentTable with the latest // trusted validators. - auto callTrustChanged = - [](std::vector> const& validators, - std::unique_ptr const& table) { - // We need a hash_set to pass to trustChanged. - hash_set trustedValidators; - trustedValidators.reserve(validators.size()); - std::for_each( - validators.begin(), - validators.end(), - [&trustedValidators](auto const& val) { - trustedValidators.insert(val.first); - }); + auto callTrustChanged = [](std::vector> const& validators, + std::unique_ptr const& table) { + // We need a hash_set to pass to trustChanged. + hash_set trustedValidators; + trustedValidators.reserve(validators.size()); + std::for_each(validators.begin(), validators.end(), [&trustedValidators](auto const& val) { + trustedValidators.insert(val.first); + }); - // Tell the AmendmentTable that the UNL changed. - table->trustChanged(trustedValidators); - }; + // Tell the AmendmentTable that the UNL changed. + table->trustChanged(trustedValidators); + }; // Tell the table that there's been a change in trusted validators. callTrustChanged(validators, table); @@ -1051,15 +850,7 @@ public: votes.emplace_back(testAmendment, validators.size() - 2); - doRound( - env.current()->rules(), - *table, - weeks{2}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{2}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(!majority.empty()); @@ -1067,8 +858,7 @@ public: { // One of the validators goes flaky and doesn't send validations // (without the UNL changing) so the amendment loses majority. - std::pair const savedValidator = - validators.front(); + std::pair const savedValidator = validators.front(); validators.erase(validators.begin()); std::vector> votes; @@ -1076,15 +866,7 @@ public: votes.emplace_back(testAmendment, validators.size() - 2); - doRound( - env.current()->rules(), - *table, - weeks{3}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{3}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(majority.empty()); @@ -1095,15 +877,7 @@ public: votes.front().second = validators.size() - 2; - doRound( - env.current()->rules(), - *table, - weeks{4}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{4}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(!majority.empty()); @@ -1117,15 +891,7 @@ public: votes.front().second = validators.size() - 2; - doRound( - env.current()->rules(), - *table, - weeks{5}, - validators, - votes, - ourVotes, - enabled, - majority); + doRound(env.current()->rules(), *table, weeks{5}, validators, votes, ourVotes, enabled, majority); BEAST_EXPECT(enabled.empty()); BEAST_EXPECT(majority.empty()); @@ -1150,18 +916,12 @@ public: { test::jtx::Env env{*this, feat}; auto const testAmendment = amendmentId("validatorFlapping"); - auto table = makeTable( - env, - weeks(1), - makeDefaultYes(testAmendment), - emptySection_, - emptySection_); + auto table = makeTable(env, weeks(1), makeDefaultYes(testAmendment), emptySection_, emptySection_); // Make two lists of validators, one with a missing validator, to // make it easy to simulate validator flapping. auto const allValidators = makeValidators(11, table); - decltype(allValidators) const mostValidators( - allValidators.begin() + 1, allValidators.end()); + decltype(allValidators) const mostValidators(allValidators.begin() + 1, allValidators.end()); BEAST_EXPECT(allValidators.size() == mostValidators.size() + 1); std::set enabled; @@ -1203,9 +963,7 @@ public: // no flapping. Otherwise we should only have majority // if allValidators vote -- which means there are no // missing validators. - bool const expectMajority = (delay <= 24) - ? true - : &thisHoursValidators == &allValidators; + bool const expectMajority = (delay <= 24) ? true : &thisHoursValidators == &allValidators; BEAST_EXPECT(majority.empty() != expectMajority); } else @@ -1236,9 +994,7 @@ public: std::set enabled; std::for_each( - unsupported_.begin(), - unsupported_.end(), - [&enabled](auto const& s) { enabled.insert(amendmentId(s)); }); + unsupported_.begin(), unsupported_.end(), [&enabled](auto const& s) { enabled.insert(amendmentId(s)); }); majorityAmendments_t majority; table->doValidatedLedger(1, enabled, majority); @@ -1246,18 +1002,14 @@ public: BEAST_EXPECT(!table->firstUnsupportedExpected()); NetClock::duration t{1000s}; - std::for_each( - unsupportedMajority_.begin(), - unsupportedMajority_.end(), - [&majority, &t](auto const& s) { - majority[amendmentId(s)] = NetClock::time_point{--t}; - }); + std::for_each(unsupportedMajority_.begin(), unsupportedMajority_.end(), [&majority, &t](auto const& s) { + majority[amendmentId(s)] = NetClock::time_point{--t}; + }); table->doValidatedLedger(1, enabled, majority); BEAST_EXPECT(table->hasUnsupportedEnabled()); BEAST_EXPECT( - table->firstUnsupportedExpected() && - *table->firstUnsupportedExpected() == NetClock::time_point{t} + w); + table->firstUnsupportedExpected() && *table->firstUnsupportedExpected() == NetClock::time_point{t} + w); // Make sure the table knows when it needs an update. BEAST_EXPECT(!table->needValidatedLedger(256)); @@ -1290,6 +1042,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AmendmentTable, app, ripple); +BEAST_DEFINE_TESTSUITE(AmendmentTable, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Batch_test.cpp b/src/test/app/Batch_test.cpp index 7b5c9dee60..72f3677e3b 100644 --- a/src/test/app/Batch_test.cpp +++ b/src/test/app/Batch_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -34,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Batch_test : public beast::unit_test::suite @@ -76,27 +57,19 @@ class Batch_test : public beast::unit_test::suite } void - validateInnerTxn( - jtx::Env& env, - std::string const& batchID, - TestLedgerData const& ledgerResult) + validateInnerTxn(jtx::Env& env, std::string const& batchID, TestLedgerData const& ledgerResult) { Json::Value const jrr = env.rpc("tx", ledgerResult.txHash)[jss::result]; BEAST_EXPECT(jrr[sfTransactionType.jsonName] == ledgerResult.txType); - BEAST_EXPECT( - jrr[jss::meta][sfTransactionResult.jsonName] == - ledgerResult.result); + BEAST_EXPECT(jrr[jss::meta][sfTransactionResult.jsonName] == ledgerResult.result); BEAST_EXPECT(jrr[jss::meta][sfParentBatchID.jsonName] == batchID); } void - validateClosedLedger( - jtx::Env& env, - std::vector const& ledgerResults) + validateClosedLedger(jtx::Env& env, std::vector const& ledgerResults) { auto const jrr = getLastLedger(env); - auto const transactions = - jrr[jss::result][jss::ledger][jss::transactions]; + auto const transactions = jrr[jss::result][jss::ledger][jss::transactions]; BEAST_EXPECT(transactions.size() == ledgerResults.size()); for (TestLedgerData const& ledgerResult : ledgerResults) { @@ -104,10 +77,8 @@ class Batch_test : public beast::unit_test::suite BEAST_EXPECT(txn[jss::hash].asString() == ledgerResult.txHash); BEAST_EXPECT(txn.isMember(jss::metaData)); Json::Value const meta = txn[jss::metaData]; - BEAST_EXPECT( - txn[sfTransactionType.jsonName] == ledgerResult.txType); - BEAST_EXPECT( - meta[sfTransactionResult.jsonName] == ledgerResult.result); + BEAST_EXPECT(txn[sfTransactionType.jsonName] == ledgerResult.txType); + BEAST_EXPECT(meta[sfTransactionResult.jsonName] == ledgerResult.result); if (ledgerResult.batchID) validateInnerTxn(env, *ledgerResult.batchID, ledgerResult); } @@ -167,15 +138,19 @@ class Batch_test : public beast::unit_test::suite void testEnable(FeatureBitset features) { - testcase("enabled"); - using namespace test::jtx; using namespace std::literals; + bool const withInnerSigFix = features[fixBatchInnerSigs]; + for (bool const withBatch : {true, false}) { + testcase << "enabled: Batch " << (withBatch ? "enabled" : "disabled") + << ", Inner Sig Fix: " << (withInnerSigFix ? "enabled" : "disabled"); + auto const amend = withBatch ? features : features - featureBatch; - test::jtx::Env env{*this, envconfig(), amend}; + + test::jtx::Env env{*this, amend}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -187,8 +162,7 @@ class Batch_test : public beast::unit_test::suite { auto const seq = env.seq(alice); auto const batchFee = batch::calcBatchFee(env, 0, 2); - auto const txResult = - withBatch ? ter(tesSUCCESS) : ter(temDISABLED); + auto const txResult = withBatch ? ter(tesSUCCESS) : ter(temDISABLED); env(batch::outer(alice, seq, batchFee, tfAllOrNothing), batch::inner(pay(alice, bob, XRP(1)), seq + 1), batch::inner(pay(alice, bob, XRP(1)), seq + 2), @@ -198,14 +172,11 @@ class Batch_test : public beast::unit_test::suite // tfInnerBatchTxn // If the feature is disabled, the transaction fails with - // temINVALID_FLAG If the feature is enabled, the transaction fails + // temINVALID_FLAG. If the feature is enabled, the transaction fails // early in checkValidity() { - auto const txResult = - withBatch ? ter(telENV_RPC_FAILED) : ter(temINVALID_FLAG); - env(pay(alice, bob, XRP(1)), - txflags(tfInnerBatchTxn), - txResult); + auto const txResult = withBatch ? ter(telENV_RPC_FAILED) : ter(temINVALID_FLAG); + env(pay(alice, bob, XRP(1)), txflags(tfInnerBatchTxn), txResult); env.close(); } @@ -224,7 +195,7 @@ class Batch_test : public beast::unit_test::suite //---------------------------------------------------------------------- // preflight - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -234,8 +205,7 @@ class Batch_test : public beast::unit_test::suite // temBAD_FEE: preflight1 { - env(batch::outer(alice, env.seq(alice), XRP(-1), tfAllOrNothing), - ter(temBAD_FEE)); + env(batch::outer(alice, env.seq(alice), XRP(-1), tfAllOrNothing), ter(temBAD_FEE)); env.close(); } @@ -244,8 +214,7 @@ class Batch_test : public beast::unit_test::suite { auto const seq = env.seq(alice); auto const batchFee = batch::calcBatchFee(env, 0, 0); - env(batch::outer(alice, seq, batchFee, tfInnerBatchTxn), - ter(telENV_RPC_FAILED)); + env(batch::outer(alice, seq, batchFee, tfInnerBatchTxn), ter(telENV_RPC_FAILED)); env.close(); } @@ -253,8 +222,7 @@ class Batch_test : public beast::unit_test::suite { auto const seq = env.seq(alice); auto const batchFee = batch::calcBatchFee(env, 0, 0); - env(batch::outer(alice, seq, batchFee, tfDisallowXRP), - ter(temINVALID_FLAG)); + env(batch::outer(alice, seq, batchFee, tfDisallowXRP), ter(temINVALID_FLAG)); env.close(); } @@ -272,8 +240,7 @@ class Batch_test : public beast::unit_test::suite { auto const seq = env.seq(alice); auto const batchFee = batch::calcBatchFee(env, 0, 0); - env(batch::outer(alice, seq, batchFee, tfAllOrNothing), - ter(temARRAY_EMPTY)); + env(batch::outer(alice, seq, batchFee, tfAllOrNothing), ter(temARRAY_EMPTY)); env.close(); } @@ -325,8 +292,7 @@ class Batch_test : public beast::unit_test::suite auto const seq = env.seq(alice); auto const batchFee = batch::calcBatchFee(env, 0, 2); env(batch::outer(alice, seq, batchFee, tfAllOrNothing), - batch::inner( - batch::outer(alice, seq, batchFee, tfAllOrNothing), seq), + batch::inner(batch::outer(alice, seq, batchFee, tfAllOrNothing), seq), batch::inner(pay(alice, bob, XRP(1)), seq + 2), ter(telENV_RPC_FAILED)); env.close(); @@ -367,12 +333,9 @@ class Batch_test : public beast::unit_test::suite auto tx1 = pay(alice, bob, XRP(1)); tx1[sfSigners.jsonName] = Json::arrayValue; tx1[sfSigners.jsonName][0U][sfSigner.jsonName] = Json::objectValue; - tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] = - alice.human(); - tx1[sfSigners.jsonName][0U][sfSigner.jsonName] - [sfSigningPubKey.jsonName] = strHex(alice.pk()); - tx1[sfSigners.jsonName][0U][sfSigner.jsonName] - [sfTxnSignature.jsonName] = "DEADBEEF"; + tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] = alice.human(); + tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfSigningPubKey.jsonName] = strHex(alice.pk()); + tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfTxnSignature.jsonName] = "DEADBEEF"; env(batch::outer(alice, seq, batchFee, tfAllOrNothing), batch::inner(tx1, seq + 1), batch::inner(pay(alice, bob, XRP(1)), seq + 2), @@ -421,6 +384,40 @@ class Batch_test : public beast::unit_test::suite env.close(); } + // temBAD_FEE: Inner txn with negative fee + { + auto const seq = env.seq(alice); + auto const batchFee = batch::calcBatchFee(env, 0, 2); + auto tx1 = batch::inner(pay(alice, bob, XRP(1)), seq + 1); + tx1[jss::Fee] = "-1"; + env(batch::outer(alice, seq, batchFee, tfAllOrNothing), + tx1, + batch::inner(pay(alice, bob, XRP(2)), seq + 2), + ter(temBAD_FEE)); + env.close(); + } + + // temBAD_FEE: Inner txn with non-integer fee + { + auto const seq = env.seq(alice); + auto const batchFee = batch::calcBatchFee(env, 0, 2); + auto tx1 = batch::inner(pay(alice, bob, XRP(1)), seq + 1); + tx1[jss::Fee] = "1.5"; + env.set_parse_failure_expected(true); + try + { + env(batch::outer(alice, seq, batchFee, tfAllOrNothing), + tx1, + batch::inner(pay(alice, bob, XRP(2)), seq + 2)); + fail("Expected parse_error for fractional fee"); + } + catch (jtx::parse_error const&) + { + BEAST_EXPECT(true); + } + env.set_parse_failure_expected(false); + } + // temSEQ_AND_TICKET: Batch: inner txn cannot have both Sequence // and TicketSequence. { @@ -489,17 +486,7 @@ class Batch_test : public beast::unit_test::suite env(batch::outer(alice, seq, batchFee, tfAllOrNothing), batch::inner(pay(alice, bob, XRP(10)), seq + 1), batch::inner(pay(alice, bob, XRP(5)), seq + 2), - batch::sig( - bob, - carol, - alice, - bob, - carol, - alice, - bob, - carol, - alice, - alice), + batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice), ter(telENV_RPC_FAILED)); env.close(); } @@ -564,15 +551,11 @@ class Batch_test : public beast::unit_test::suite batch::inner(pay(bob, alice, XRP(5)), bobSeq)); Serializer msg; - serializeBatch( - msg, tfAllOrNothing, jt.stx->getBatchTransactionIDs()); - auto const sig = ripple::sign(bob.pk(), bob.sk(), msg.slice()); - jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName] - [sfAccount.jsonName] = bob.human(); - jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName] - [sfSigningPubKey.jsonName] = strHex(alice.pk()); - jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName] - [sfTxnSignature.jsonName] = + serializeBatch(msg, tfAllOrNothing, jt.stx->getBatchTransactionIDs()); + auto const sig = xrpl::sign(bob.pk(), bob.sk(), msg.slice()); + jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfAccount.jsonName] = bob.human(); + jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfSigningPubKey.jsonName] = strHex(alice.pk()); + jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfTxnSignature.jsonName] = strHex(Slice{sig.data(), sig.size()}); env(jt.jv, ter(temBAD_SIGNATURE)); @@ -604,7 +587,7 @@ class Batch_test : public beast::unit_test::suite //---------------------------------------------------------------------- // preclaim - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -845,7 +828,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -936,7 +919,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1174,7 +1157,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee Without Signer { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1196,7 +1179,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee With MultiSign { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1223,7 +1206,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee With MultiSign + BatchSigners { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1252,7 +1235,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee With MultiSign + BatchSigners.Signers { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1284,7 +1267,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee With BatchSigners { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1308,7 +1291,7 @@ class Batch_test : public beast::unit_test::suite // Bad Fee Dynamic Fee Calculation { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1317,16 +1300,15 @@ class Batch_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob, gw); env.close(); - auto const ammCreate = - [&alice](STAmount const& amount, STAmount const& amount2) { - Json::Value jv; - jv[jss::Account] = alice.human(); - jv[jss::Amount] = amount.getJson(JsonOptions::none); - jv[jss::Amount2] = amount2.getJson(JsonOptions::none); - jv[jss::TradingFee] = 0; - jv[jss::TransactionType] = jss::AMMCreate; - return jv; - }; + auto const ammCreate = [&alice](STAmount const& amount, STAmount const& amount2) { + Json::Value jv; + jv[jss::Account] = alice.human(); + jv[jss::Amount] = amount.getJson(JsonOptions::none); + jv[jss::Amount2] = amount2.getJson(JsonOptions::none); + jv[jss::TradingFee] = 0; + jv[jss::TransactionType] = jss::AMMCreate; + return jv; + }; auto const batchFee = batch::calcBatchFee(env, 0, 2); auto const seq = env.seq(alice); @@ -1348,7 +1330,7 @@ class Batch_test : public beast::unit_test::suite // telENV_RPC_FAILED: Batch: txns array exceeds 8 entries. { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1373,7 +1355,7 @@ class Batch_test : public beast::unit_test::suite // temARRAY_TOO_LARGE: Batch: txns array exceeds 8 entries. { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1394,19 +1376,16 @@ class Batch_test : public beast::unit_test::suite batch::inner(pay(alice, bob, XRP(1)), aliceSeq), batch::inner(pay(alice, bob, XRP(1)), aliceSeq)); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - auto const result = - ripple::apply(env.app(), view, *jt.stx, tapNONE, j); - BEAST_EXPECT( - !result.applied && result.ter == temARRAY_TOO_LARGE); - return result.applied; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + auto const result = xrpl::apply(env.app(), view, *jt.stx, tapNONE, j); + BEAST_EXPECT(!result.applied && result.ter == temARRAY_TOO_LARGE); + return result.applied; + }); } // telENV_RPC_FAILED: Batch: signers array exceeds 8 entries. { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1425,7 +1404,7 @@ class Batch_test : public beast::unit_test::suite // temARRAY_TOO_LARGE: Batch: signers array exceeds 8 entries. { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1440,14 +1419,11 @@ class Batch_test : public beast::unit_test::suite batch::inner(pay(alice, bob, XRP(5)), aliceSeq + 2), batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob)); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - auto const result = - ripple::apply(env.app(), view, *jt.stx, tapNONE, j); - BEAST_EXPECT( - !result.applied && result.ter == temARRAY_TOO_LARGE); - return result.applied; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + auto const result = xrpl::apply(env.app(), view, *jt.stx, tapNONE, j); + BEAST_EXPECT(!result.applied && result.ter == temARRAY_TOO_LARGE); + return result.applied; + }); } } @@ -1459,7 +1435,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1595,7 +1571,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -1778,27 +1754,9 @@ class Batch_test : public beast::unit_test::suite env, tesSUCCESS, batch::outer(alice, seq, batchFee, tfOnlyOne), - batch::inner( - offer( - alice, - alice["USD"](100), - XRP(100), - tfImmediateOrCancel), - seq + 1), - batch::inner( - offer( - alice, - alice["USD"](100), - XRP(100), - tfImmediateOrCancel), - seq + 2), - batch::inner( - offer( - alice, - alice["USD"](100), - XRP(100), - tfImmediateOrCancel), - seq + 3), + batch::inner(offer(alice, alice["USD"](100), XRP(100), tfImmediateOrCancel), seq + 1), + batch::inner(offer(alice, alice["USD"](100), XRP(100), tfImmediateOrCancel), seq + 2), + batch::inner(offer(alice, alice["USD"](100), XRP(100), tfImmediateOrCancel), seq + 3), batch::inner(pay(alice, bob, XRP(100)), seq + 4), batch::inner(pay(alice, carol, XRP(100)), seq + 5), batch::inner(pay(alice, dave, XRP(100)), seq + 6)); @@ -1827,7 +1785,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2017,13 +1975,7 @@ class Batch_test : public beast::unit_test::suite batch::outer(alice, seq, batchFee, tfUntilFailure), batch::inner(pay(alice, bob, XRP(100)), seq + 1), batch::inner(pay(alice, carol, XRP(100)), seq + 2), - batch::inner( - offer( - alice, - alice["USD"](100), - XRP(100), - tfImmediateOrCancel), - seq + 3), + batch::inner(offer(alice, alice["USD"](100), XRP(100), tfImmediateOrCancel), seq + 3), batch::inner(pay(alice, dave, XRP(100)), seq + 4)); env.close(); @@ -2049,7 +2001,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2211,13 +2163,7 @@ class Batch_test : public beast::unit_test::suite batch::outer(alice, seq, batchFee, tfIndependent), batch::inner(pay(alice, bob, XRP(100)), seq + 1), batch::inner(pay(alice, carol, XRP(100)), seq + 2), - batch::inner( - offer( - alice, - alice["USD"](100), - XRP(100), - tfImmediateOrCancel), - seq + 3)); + batch::inner(offer(alice, alice["USD"](100), XRP(100), tfImmediateOrCancel), seq + 3)); env.close(); std::vector testCases = { @@ -2235,14 +2181,25 @@ class Batch_test : public beast::unit_test::suite } void - testInnerSubmitRPC(FeatureBitset features) + doTestInnerSubmitRPC(FeatureBitset features, bool withBatch) { - testcase("inner submit rpc"); + bool const withInnerSigFix = features[fixBatchInnerSigs]; + + std::string const testName = [&]() { + std::stringstream ss; + ss << "inner submit rpc: batch " << (withBatch ? "enabled" : "disabled") + << ", inner sig fix: " << (withInnerSigFix ? "enabled" : "disabled") << ": "; + return ss.str(); + }(); + + auto const amend = withBatch ? features : features - featureBatch; using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, amend}; + if (!BEAST_EXPECT(amend[featureBatch] == withBatch)) + return; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2250,75 +2207,144 @@ class Batch_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob); env.close(); - auto submitAndValidate = [&](Slice const& slice) { + auto submitAndValidate = [&](std::string caseName, + Slice const& slice, + int line, + std::optional expectedEnabled = std::nullopt, + std::optional expectedDisabled = std::nullopt, + bool expectInvalidFlag = false) { + testcase << testName << caseName << (expectInvalidFlag ? " - Expected to reach tx engine!" : ""); auto const jrr = env.rpc("submit", strHex(slice))[jss::result]; - BEAST_EXPECT( - jrr[jss::status] == "error" && - jrr[jss::error] == "invalidTransaction" && - jrr[jss::error_exception] == - "fails local checks: Malformed: Invalid inner batch " - "transaction."); + auto const expected = withBatch ? expectedEnabled.value_or( + "fails local checks: Malformed: Invalid inner batch " + "transaction.") + : expectedDisabled.value_or("fails local checks: Empty SigningPubKey."); + if (expectInvalidFlag) + { + expect( + jrr[jss::status] == "success" && jrr[jss::engine_result] == "temINVALID_FLAG", + pretty(jrr), + __FILE__, + line); + } + else + { + expect( + jrr[jss::status] == "error" && jrr[jss::error] == "invalidTransaction" && + jrr[jss::error_exception] == expected, + pretty(jrr), + __FILE__, + line); + } env.close(); }; // Invalid RPC Submission: TxnSignature - // - has `TxnSignature` field + // + has `TxnSignature` field // - has no `SigningPubKey` field // - has no `Signers` field - // - has `tfInnerBatchTxn` flag + // + has `tfInnerBatchTxn` flag { auto txn = batch::inner(pay(alice, bob, XRP(1)), env.seq(alice)); txn[sfTxnSignature] = "DEADBEEF"; STParsedJSONObject parsed("test", txn.getTxn()); Serializer s; parsed.object->add(s); - submitAndValidate(s.slice()); + submitAndValidate("TxnSignature set", s.slice(), __LINE__); } // Invalid RPC Submission: SigningPubKey // - has no `TxnSignature` field - // - has `SigningPubKey` field + // + has `SigningPubKey` field // - has no `Signers` field - // - has `tfInnerBatchTxn` flag + // + has `tfInnerBatchTxn` flag { auto txn = batch::inner(pay(alice, bob, XRP(1)), env.seq(alice)); txn[sfSigningPubKey] = strHex(alice.pk()); STParsedJSONObject parsed("test", txn.getTxn()); Serializer s; parsed.object->add(s); - submitAndValidate(s.slice()); + submitAndValidate( + "SigningPubKey set", s.slice(), __LINE__, std::nullopt, "fails local checks: Invalid signature."); } // Invalid RPC Submission: Signers // - has no `TxnSignature` field - // - has empty `SigningPubKey` field - // - has `Signers` field - // - has `tfInnerBatchTxn` flag + // + has empty `SigningPubKey` field + // + has `Signers` field + // + has `tfInnerBatchTxn` flag { auto txn = batch::inner(pay(alice, bob, XRP(1)), env.seq(alice)); txn[sfSigners] = Json::arrayValue; STParsedJSONObject parsed("test", txn.getTxn()); Serializer s; parsed.object->add(s); - submitAndValidate(s.slice()); + submitAndValidate( + "Signers set", s.slice(), __LINE__, std::nullopt, "fails local checks: Invalid Signers array size."); + } + + { + // Fully signed inner batch transaction + auto const txn = batch::inner(pay(alice, bob, XRP(1)), env.seq(alice)); + auto const jt = env.jt(txn.getTxn()); + + STParsedJSONObject parsed("test", jt.jv); + Serializer s; + parsed.object->add(s); + submitAndValidate("Fully signed", s.slice(), __LINE__, std::nullopt, std::nullopt, !withBatch); } // Invalid RPC Submission: tfInnerBatchTxn // - has no `TxnSignature` field - // - has empty `SigningPubKey` field + // + has empty `SigningPubKey` field // - has no `Signers` field - // - has `tfInnerBatchTxn` flag + // + has `tfInnerBatchTxn` flag { auto txn = batch::inner(pay(alice, bob, XRP(1)), env.seq(alice)); STParsedJSONObject parsed("test", txn.getTxn()); Serializer s; parsed.object->add(s); - auto const jrr = env.rpc("submit", strHex(s.slice()))[jss::result]; - BEAST_EXPECT( - jrr[jss::status] == "success" && - jrr[jss::engine_result] == "temINVALID_FLAG"); + submitAndValidate( + "No signing fields set", + s.slice(), + __LINE__, + "fails local checks: Empty SigningPubKey.", + "fails local checks: Empty SigningPubKey.", + withBatch && !withInnerSigFix); + } - env.close(); + // Invalid RPC Submission: tfInnerBatchTxn pseudo-transaction + // - has no `TxnSignature` field + // + has empty `SigningPubKey` field + // - has no `Signers` field + // + has `tfInnerBatchTxn` flag + { + STTx amendTx(ttAMENDMENT, [seq = env.closed()->header().seq + 1](auto& obj) { + obj.setAccountID(sfAccount, AccountID()); + obj.setFieldH256(sfAmendment, fixBatchInnerSigs); + obj.setFieldU32(sfLedgerSequence, seq); + obj.setFieldU32(sfFlags, tfInnerBatchTxn); + }); + auto txn = batch::inner(amendTx.getJson(JsonOptions::none), env.seq(alice)); + STParsedJSONObject parsed("test", txn.getTxn()); + Serializer s; + parsed.object->add(s); + submitAndValidate( + "Pseudo-transaction", + s.slice(), + __LINE__, + withInnerSigFix ? "fails local checks: Empty SigningPubKey." + : "fails local checks: Cannot submit pseudo transactions.", + "fails local checks: Empty SigningPubKey."); + } + } + + void + testInnerSubmitRPC(FeatureBitset features) + { + for (bool const withBatch : {true, false}) + { + doTestInnerSubmitRPC(features, withBatch); } } @@ -2330,7 +2356,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2377,7 +2403,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2409,8 +2435,7 @@ class Batch_test : public beast::unit_test::suite auto const sle = env.le(keylet::account(alice)); BEAST_EXPECT(sle); - BEAST_EXPECT( - sle->getFieldVL(sfDomain) == Blob(domain.begin(), domain.end())); + BEAST_EXPECT(sle->getFieldVL(sfDomain) == Blob(domain.begin(), domain.end())); // Alice consumes sequences (# of txns) BEAST_EXPECT(env.seq(alice) == seq + 3); @@ -2430,7 +2455,7 @@ class Batch_test : public beast::unit_test::suite // tfIndependent: account delete success { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2445,8 +2470,7 @@ class Batch_test : public beast::unit_test::suite auto const preBob = env.balance(bob); auto const seq = env.seq(alice); - auto const batchFee = batch::calcBatchFee(env, 0, 2) + - env.current()->fees().increment; + auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment; auto const [txIDs, batchID] = submitBatch( env, tesSUCCESS, @@ -2471,7 +2495,7 @@ class Batch_test : public beast::unit_test::suite // tfIndependent: account delete fails { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2489,8 +2513,7 @@ class Batch_test : public beast::unit_test::suite env.close(); auto const seq = env.seq(alice); - auto const batchFee = batch::calcBatchFee(env, 0, 2) + - env.current()->fees().increment; + auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment; auto const [txIDs, batchID] = submitBatch( env, tesSUCCESS, @@ -2516,7 +2539,7 @@ class Batch_test : public beast::unit_test::suite // tfAllOrNothing: account delete fails { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2531,8 +2554,7 @@ class Batch_test : public beast::unit_test::suite auto const preBob = env.balance(bob); auto const seq = env.seq(alice); - auto const batchFee = batch::calcBatchFee(env, 0, 2) + - env.current()->fees().increment; + auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment; auto const [txIDs, batchID] = submitBatch( env, tesSUCCESS, @@ -2554,6 +2576,181 @@ class Batch_test : public beast::unit_test::suite } } + void + testLoan(FeatureBitset features) + { + testcase("loan"); + + bool const lendingBatchEnabled = + !std::any_of(Batch::disabledTxTypes.begin(), Batch::disabledTxTypes.end(), [](auto const& disabled) { + return disabled == ttLOAN_BROKER_SET; + }); + + using namespace test::jtx; + + test::jtx::Env env{*this, features | featureSingleAssetVault | featureLendingProtocol | featureMPTokensV1}; + + Account const issuer{"issuer"}; + // For simplicity, lender will be the sole actor for the vault & + // brokers. + Account const lender{"lender"}; + // Borrower only wants to borrow + Account const borrower{"borrower"}; + + // Fund the accounts and trust lines with the same amount so that tests + // can use the same values regardless of the asset. + env.fund(XRP(100'000), issuer, noripple(lender, borrower)); + env.close(); + + // Just use an XRP asset + PrettyAsset const asset{xrpIssue(), 1'000'000}; + + Vault vault{env}; + + auto const deposit = asset(50'000); + auto const debtMaximumValue = asset(25'000).value(); + auto const coverDepositValue = asset(1000).value(); + + auto [tx, vaultKeylet] = vault.create({.owner = lender, .asset = asset}); + env(tx); + env.close(); + BEAST_EXPECT(env.le(vaultKeylet)); + + env(vault.deposit({.depositor = lender, .id = vaultKeylet.key, .amount = deposit})); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(lender.id(), env.seq(lender)); + + { + using namespace loanBroker; + env(set(lender, vaultKeylet.key), + managementFeeRate(TenthBips16(100)), + debtMaximum(debtMaximumValue), + coverRateMinimum(TenthBips32(percentageToTenthBips(10))), + coverRateLiquidation(TenthBips32(percentageToTenthBips(25)))); + + env(coverDeposit(lender, brokerKeylet.key, coverDepositValue)); + + env.close(); + } + + { + using namespace loan; + using namespace std::chrono_literals; + + auto const lenderSeq = env.seq(lender); + auto const batchFee = batch::calcBatchFee(env, 0, 2); + + auto const loanKeylet = keylet::loan(brokerKeylet.key, 1); + { + auto const [txIDs, batchID] = submitBatch( + env, + lendingBatchEnabled ? temBAD_SIGNATURE : temINVALID_INNER_BATCH, + batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing), + batch::inner( + env.json( + set(lender, brokerKeylet.key, asset(1000).value()), + // Not allowed to include the counterparty signature + sig(sfCounterpartySignature, borrower), + sig(none), + fee(none), + seq(none)), + lenderSeq + 1), + batch::inner(pay(lender, loanKeylet.key, STAmount{asset, asset(500).value()}), lenderSeq + 2)); + } + { + auto const [txIDs, batchID] = submitBatch( + env, + temINVALID_INNER_BATCH, + batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing), + batch::inner( + env.json( + set(lender, brokerKeylet.key, asset(1000).value()), + // Counterparty must be set + sig(none), + fee(none), + seq(none)), + lenderSeq + 1), + batch::inner(pay(lender, loanKeylet.key, STAmount{asset, asset(500).value()}), lenderSeq + 2)); + } + { + auto const [txIDs, batchID] = submitBatch( + env, + lendingBatchEnabled ? temBAD_SIGNER : temINVALID_INNER_BATCH, + batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing), + batch::inner( + env.json( + set(lender, brokerKeylet.key, asset(1000).value()), + // Counterparty must sign the outer transaction + counterparty(borrower.id()), + sig(none), + fee(none), + seq(none)), + lenderSeq + 1), + batch::inner(pay(lender, loanKeylet.key, STAmount{asset, asset(500).value()}), lenderSeq + 2)); + } + { + // LoanSet normally charges at least 2x base fee, but since the + // signature check is done by the batch, it only charges the + // base fee. + auto const batchFee = batch::calcBatchFee(env, 1, 2); + auto const [txIDs, batchID] = submitBatch( + env, + lendingBatchEnabled ? TER(tesSUCCESS) : TER(temINVALID_INNER_BATCH), + batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing), + batch::inner( + env.json( + set(lender, brokerKeylet.key, asset(1000).value()), + counterparty(borrower.id()), + sig(none), + fee(none), + seq(none)), + lenderSeq + 1), + batch::inner( + pay( + // However, this inner transaction will fail, + // because the lender is not allowed to draw the + // transaction + lender, + loanKeylet.key, + STAmount{asset, asset(500).value()}), + lenderSeq + 2), + batch::sig(borrower)); + } + env.close(); + BEAST_EXPECT(env.le(brokerKeylet)); + BEAST_EXPECT(!env.le(loanKeylet)); + { + // LoanSet normally charges at least 2x base fee, but since the + // signature check is done by the batch, it only charges the + // base fee. + auto const lenderSeq = env.seq(lender); + auto const batchFee = batch::calcBatchFee(env, 1, 2); + auto const [txIDs, batchID] = submitBatch( + env, + lendingBatchEnabled ? TER(tesSUCCESS) : TER(temINVALID_INNER_BATCH), + batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing), + batch::inner( + env.json( + set(lender, brokerKeylet.key, asset(1000).value()), + counterparty(borrower.id()), + sig(none), + fee(none), + seq(none)), + lenderSeq + 1), + batch::inner(manage(lender, loanKeylet.key, tfLoanImpair), lenderSeq + 2), + batch::sig(borrower)); + } + env.close(); + BEAST_EXPECT(env.le(brokerKeylet)); + if (auto const sleLoan = env.le(loanKeylet); + lendingBatchEnabled ? BEAST_EXPECT(sleLoan) : !BEAST_EXPECT(!sleLoan)) + { + BEAST_EXPECT(sleLoan->isFlag(lsfLoanImpaired)); + } + } + } + void testObjectCreateSequence(FeatureBitset features) { @@ -2562,7 +2759,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2615,8 +2812,7 @@ class Batch_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob) == preBob); // Alice pays USD & Bob receives USD - BEAST_EXPECT( - env.balance(alice, USD.issue()) == preAliceUSD + USD(10)); + BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10)); BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10)); } @@ -2675,7 +2871,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2733,7 +2929,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2795,7 +2991,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2844,7 +3040,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2892,7 +3088,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -2955,7 +3151,7 @@ class Batch_test : public beast::unit_test::suite // overwritten by the payment in the batch transaction. Because the // terPRE_SEQ is outside of the batch this noop transaction will ge // reapplied in the following ledger - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob, carol); env.close(); @@ -3002,7 +3198,7 @@ class Batch_test : public beast::unit_test::suite // IMPORTANT: The batch txn is applied first, then the noop txn. // Because of this ordering, the noop txn is not applied and is // overwritten by the payment in the batch transaction. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3044,7 +3240,7 @@ class Batch_test : public beast::unit_test::suite // IMPORTANT: The batch txn is applied first, then the noop txn. // Because of this ordering, the noop txn is not applied and is // overwritten by the payment in the batch transaction. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3081,7 +3277,7 @@ class Batch_test : public beast::unit_test::suite // Outer Batch terPRE_SEQ { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob, carol); env.close(); @@ -3139,7 +3335,7 @@ class Batch_test : public beast::unit_test::suite // IMPORTANT: The batch txn is applied first, then the noop txn. // Because of this ordering, the noop txn is not applied and is // overwritten by the payment in the batch transaction. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3150,8 +3346,7 @@ class Batch_test : public beast::unit_test::suite auto const aliceSeq = env.seq(alice); // AccountSet Txn - auto const noopTxn = - env.jt(noop(alice), ticket::use(aliceTicketSeq + 1)); + auto const noopTxn = env.jt(noop(alice), ticket::use(aliceTicketSeq + 1)); auto const noopTxnID = to_string(noopTxn.stx->getTransactionID()); env(noopTxn, ter(tesSUCCESS)); @@ -3188,7 +3383,7 @@ class Batch_test : public beast::unit_test::suite // IMPORTANT: The batch txn is applied first, then the noop txn. // Because of this ordering, the noop txn is not applied and is // overwritten by the payment in the batch transaction. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3209,8 +3404,7 @@ class Batch_test : public beast::unit_test::suite ticket::use(aliceTicketSeq)); // AccountSet Txn - auto const noopTxn = - env.jt(noop(alice), ticket::use(aliceTicketSeq + 1)); + auto const noopTxn = env.jt(noop(alice), ticket::use(aliceTicketSeq + 1)); env(noopTxn); env.close(); @@ -3250,7 +3444,7 @@ class Batch_test : public beast::unit_test::suite // batch will run in the close ledger process. The batch will be // allied and then retry this transaction in the current ledger. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3297,7 +3491,7 @@ class Batch_test : public beast::unit_test::suite // Create Object Before Batch Txn { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3344,7 +3538,7 @@ class Batch_test : public beast::unit_test::suite // batch will run in the close ledger process. The batch will be // applied and then retry this transaction in the current ledger. - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; env.fund(XRP(10000), alice, bob); env.close(); @@ -3391,7 +3585,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -3410,7 +3604,7 @@ class Batch_test : public beast::unit_test::suite BEAST_EXPECT(!passesLocalChecks(stx, reason)); BEAST_EXPECT(reason == "Cannot submit pseudo transactions."); env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { - auto const result = ripple::apply(env.app(), view, stx, tapNONE, j); + auto const result = xrpl::apply(env.app(), view, stx, tapNONE, j); BEAST_EXPECT(!result.applied && result.ter == temINVALID_FLAG); return result.applied; }); @@ -3424,13 +3618,13 @@ class Batch_test : public beast::unit_test::suite // another transaction is part of the batch, the batch might fail // because the sequence is out of order. This is because the canonical // order of transactions is determined by the account first. So in this - // case, alice's batch comes after bobs self submitted transaction even + // case, alice's batch comes after bob's self submitted transaction even // though the payment was submitted after the batch. using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; XRPAmount const baseFee = env.current()->fees().base; auto const alice = Account("alice"); @@ -3492,8 +3686,7 @@ class Batch_test : public beast::unit_test::suite BEAST_EXPECT(env.seq(bob) == bobSeq + 2); // Alice pays XRP & Fee; Bob receives XRP & pays Fee - BEAST_EXPECT( - env.balance(alice) == preAlice - XRP(10) - batchFee - baseFee); + BEAST_EXPECT(env.balance(alice) == preAlice - XRP(10) - batchFee - baseFee); BEAST_EXPECT(env.balance(bob) == preBob + XRP(10) - baseFee); } @@ -3509,8 +3702,8 @@ class Batch_test : public beast::unit_test::suite { test::jtx::Env env{ *this, - makeSmallQueueConfig( - {{"minimum_txn_in_ledger_standalone", "2"}}), + makeSmallQueueConfig({{"minimum_txn_in_ledger_standalone", "2"}}), + features, nullptr, beast::severities::kError}; @@ -3550,11 +3743,7 @@ class Batch_test : public beast::unit_test::suite // Replace Queued Batch { - env(batch::outer( - alice, - aliceSeq, - openLedgerFee(env, batchFee), - tfAllOrNothing), + env(batch::outer(alice, aliceSeq, openLedgerFee(env, batchFee), tfAllOrNothing), batch::inner(pay(alice, bob, XRP(10)), aliceSeq + 1), batch::inner(pay(bob, alice, XRP(5)), bobSeq), batch::sig(bob), @@ -3569,8 +3758,8 @@ class Batch_test : public beast::unit_test::suite { test::jtx::Env env{ *this, - makeSmallQueueConfig( - {{"minimum_txn_in_ledger_standalone", "2"}}), + makeSmallQueueConfig({{"minimum_txn_in_ledger_standalone", "2"}}), + features, nullptr, beast::severities::kError}; @@ -3617,12 +3806,7 @@ class Batch_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - Env env( - *this, - envconfig(), - features, - nullptr, - beast::severities::kDisabled); + Env env(*this, envconfig(), features, nullptr, beast::severities::kDisabled); auto alice = Account("alice"); auto bob = Account("bob"); @@ -3642,10 +3826,8 @@ class Batch_test : public beast::unit_test::suite Serializer s; jt.stx->add(s); std::string reason; - auto transaction = - std::make_shared(jt.stx, reason, env.app()); - env.app().getOPs().processTransaction( - transaction, false, true, NetworkOPs::FailHard::yes); + auto transaction = std::make_shared(jt.stx, reason, env.app()); + env.app().getOPs().processTransaction(transaction, false, true, NetworkOPs::FailHard::yes); return transaction->getID(); }; @@ -3653,18 +3835,14 @@ class Batch_test : public beast::unit_test::suite { // Submit a tx with tfInnerBatchTxn uint256 const txBad = submitTx(tfInnerBatchTxn); - BEAST_EXPECT( - env.app().getHashRouter().getFlags(txBad) == - HashRouterFlags::UNDEFINED); + BEAST_EXPECT(env.app().getHashRouter().getFlags(txBad) == HashRouterFlags::UNDEFINED); } // Validate: NetworkOPs::processTransaction() { uint256 const txid = processTxn(tfInnerBatchTxn); // HashRouter::getFlags() should return LedgerFlags::BAD - BEAST_EXPECT( - env.app().getHashRouter().getFlags(txid) == - HashRouterFlags::BAD); + BEAST_EXPECT(env.app().getHashRouter().getFlags(txid) == HashRouterFlags::BAD); } } @@ -3678,7 +3856,7 @@ class Batch_test : public beast::unit_test::suite // delegated non atomic inner { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -3723,7 +3901,7 @@ class Batch_test : public beast::unit_test::suite // delegated atomic inner { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -3775,7 +3953,7 @@ class Batch_test : public beast::unit_test::suite // this also makes sure tfInnerBatchTxn won't block delegated AccountSet // with granular permission { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); @@ -3824,7 +4002,7 @@ class Batch_test : public beast::unit_test::suite // this also makes sure tfInnerBatchTxn won't block delegated // MPTokenIssuanceSet with granular permission { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; Account alice{"alice"}; Account bob{"bob"}; env.fund(XRP(100000), alice, bob); @@ -3837,8 +4015,7 @@ class Batch_test : public beast::unit_test::suite env.close(); // alice gives granular permission to bob of MPTokenIssuanceLock - env(delegate::set( - alice, bob, {"MPTokenIssuanceLock", "MPTokenIssuanceUnlock"})); + env(delegate::set(alice, bob, {"MPTokenIssuanceLock", "MPTokenIssuanceUnlock"})); env.close(); auto const seq = env.seq(alice); @@ -3880,7 +4057,7 @@ class Batch_test : public beast::unit_test::suite // this also makes sure tfInnerBatchTxn won't block delegated TrustSet // with granular permission { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; Account gw{"gw"}; Account alice{"alice"}; Account bob{"bob"}; @@ -3890,8 +4067,7 @@ class Batch_test : public beast::unit_test::suite env(trust(alice, gw["USD"](50))); env.close(); - env(delegate::set( - gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); + env(delegate::set(gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); env.close(); auto const seq = env.seq(gw); @@ -3920,7 +4096,7 @@ class Batch_test : public beast::unit_test::suite // inner transaction not authorized by the delegating account. { - test::jtx::Env env{*this, envconfig()}; + test::jtx::Env env{*this, features}; Account gw{"gw"}; Account alice{"alice"}; Account bob{"bob"}; @@ -3930,8 +4106,7 @@ class Batch_test : public beast::unit_test::suite env(trust(alice, gw["USD"](50))); env.close(); - env(delegate::set( - gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); + env(delegate::set(gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); env.close(); auto const seq = env.seq(gw); @@ -3968,7 +4143,7 @@ class Batch_test : public beast::unit_test::suite testcase("Validate RPC response"); using namespace jtx; - Env env(*this); + Env env(*this, features); Account const alice("alice"); Account const bob("bob"); env.fund(XRP(10000), alice, bob); @@ -3986,11 +4161,9 @@ class Batch_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(jr.isMember(jss::account_sequence_available)); - BEAST_EXPECT( - jr[jss::account_sequence_available].asUInt() == aliceSeq + 1); + BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1); BEAST_EXPECT(jr.isMember(jss::account_sequence_next)); - BEAST_EXPECT( - jr[jss::account_sequence_next].asUInt() == aliceSeq + 1); + BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1); BEAST_EXPECT(jr.isMember(jss::open_ledger_cost)); BEAST_EXPECT(jr[jss::open_ledger_cost] == to_string(baseFee)); BEAST_EXPECT(jr.isMember(jss::validated_ledger_index)); @@ -4009,11 +4182,9 @@ class Batch_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(jr.isMember(jss::account_sequence_available)); - BEAST_EXPECT( - jr[jss::account_sequence_available].asUInt() == aliceSeq + 1); + BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1); BEAST_EXPECT(jr.isMember(jss::account_sequence_next)); - BEAST_EXPECT( - jr[jss::account_sequence_next].asUInt() == aliceSeq + 1); + BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1); BEAST_EXPECT(jr.isMember(jss::open_ledger_cost)); BEAST_EXPECT(jr[jss::open_ledger_cost] == to_string(baseFee)); BEAST_EXPECT(jr.isMember(jss::validated_ledger_index)); @@ -4031,8 +4202,7 @@ class Batch_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(jr.isMember(jss::account_sequence_available)); - BEAST_EXPECT( - jr[jss::account_sequence_available].asUInt() == aliceSeq); + BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq); BEAST_EXPECT(jr.isMember(jss::account_sequence_next)); BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq); BEAST_EXPECT(jr.isMember(jss::open_ledger_cost)); @@ -4045,7 +4215,7 @@ class Batch_test : public beast::unit_test::suite testBatchCalculateBaseFee(FeatureBitset features) { using namespace jtx; - Env env(*this); + Env env(*this, features); Account const alice("alice"); Account const bob("bob"); Account const carol("carol"); @@ -4064,8 +4234,7 @@ class Batch_test : public beast::unit_test::suite XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2); auto jtx = env.jt( batch::outer(alice, seq, batchFee, tfAllOrNothing), - batch::inner( - batch::outer(alice, seq, batchFee, tfAllOrNothing), seq), + batch::inner(batch::outer(alice, seq, batchFee, tfAllOrNothing), seq), batch::inner(pay(alice, bob, XRP(1)), seq + 2)); XRPAmount const txBaseFee = getBaseFee(jtx); BEAST_EXPECT(txBaseFee == XRPAmount(INITIAL_XRP)); @@ -4101,17 +4270,7 @@ class Batch_test : public beast::unit_test::suite batch::outer(alice, seq, batchFee, tfAllOrNothing), batch::inner(pay(alice, bob, XRP(10)), seq + 1), batch::inner(pay(alice, bob, XRP(5)), seq + 2), - batch::sig( - bob, - carol, - alice, - bob, - carol, - alice, - bob, - carol, - alice, - alice)); + batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice)); XRPAmount const txBaseFee = getBaseFee(jtx); BEAST_EXPECT(txBaseFee == XRPAmount(INITIAL_XRP)); } @@ -4147,6 +4306,7 @@ class Batch_test : public beast::unit_test::suite testAccountActivation(features); testAccountSet(features); testAccountDelete(features); + testLoan(features); testObjectCreateSequence(features); testObjectCreateTicket(features); testObjectCreate3rdParty(features); @@ -4169,11 +4329,12 @@ public: { using namespace test::jtx; auto const sa = testable_amendments(); + testWithFeats(sa - fixBatchInnerSigs); testWithFeats(sa); } }; -BEAST_DEFINE_TESTSUITE(Batch, app, ripple); +BEAST_DEFINE_TESTSUITE(Batch, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index 5d59e2ebd9..42c600c22b 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -30,18 +11,17 @@ namespace jtx { class expiration { private: - std::uint32_t const expry_; + std::uint32_t const expiry_; public: - explicit expiration(NetClock::time_point const& expiry) - : expry_{expiry.time_since_epoch().count()} + explicit expiration(NetClock::time_point const& expiry) : expiry_{expiry.time_since_epoch().count()} { } void operator()(Env&, JTx& jt) const { - jt[sfExpiration.jsonName] = expry_; + jt[sfExpiration.jsonName] = expiry_; } }; @@ -86,8 +66,6 @@ public: class Check_test : public beast::unit_test::suite { - FeatureBitset const disallowIncoming{featureDisallowIncoming}; - static uint256 getCheckIndex(AccountID const& account, std::uint32_t uSequence) { @@ -99,13 +77,10 @@ class Check_test : public beast::unit_test::suite checksOnAccount(test::jtx::Env& env, test::jtx::Account account) { std::vector> result; - forEachItem( - *env.current(), - account, - [&result](std::shared_ptr const& sle) { - if (sle && sle->getType() == ltCHECK) - result.push_back(sle); - }); + forEachItem(*env.current(), account, [&result](std::shared_ptr const& sle) { + if (sle && sle->getType() == ltCHECK) + result.push_back(sle); + }); return result; } @@ -117,8 +92,7 @@ class Check_test : public beast::unit_test::suite verifyDeliveredAmount(test::jtx::Env& env, STAmount const& amount) { // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; // Verify DeliveredAmount and delivered_amount metadata are correct. env.close(); @@ -130,11 +104,8 @@ class Check_test : public beast::unit_test::suite // DeliveredAmount and delivered_amount should both be present and // equal amount. - BEAST_EXPECT( - meta[sfDeliveredAmount.jsonName] == - amount.getJson(JsonOptions::none)); - BEAST_EXPECT( - meta[jss::delivered_amount] == amount.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[sfDeliveredAmount.jsonName] == amount.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[jss::delivered_amount] == amount.getJson(JsonOptions::none)); } void @@ -144,25 +115,6 @@ class Check_test : public beast::unit_test::suite using namespace test::jtx; Account const alice{"alice"}; - { - // If the Checks amendment is not enabled, you should not be able - // to create, cash, or cancel checks. - Env env{*this, features - featureChecks}; - - env.fund(XRP(1000), alice); - env.close(); - - uint256 const checkId{ - getCheckIndex(env.master, env.seq(env.master))}; - env(check::create(env.master, alice, XRP(100)), ter(temDISABLED)); - env.close(); - - env(check::cash(alice, checkId, XRP(100)), ter(temDISABLED)); - env.close(); - - env(check::cancel(alice, checkId), ter(temDISABLED)); - env.close(); - } { // If the Checks amendment is enabled all check-related // facilities should be available. @@ -171,16 +123,14 @@ class Check_test : public beast::unit_test::suite env.fund(XRP(1000), alice); env.close(); - uint256 const checkId1{ - getCheckIndex(env.master, env.seq(env.master))}; + uint256 const checkId1{getCheckIndex(env.master, env.seq(env.master))}; env(check::create(env.master, alice, XRP(100))); env.close(); env(check::cash(alice, checkId1, XRP(100))); env.close(); - uint256 const checkId2{ - getCheckIndex(env.master, env.seq(env.master))}; + uint256 const checkId2{getCheckIndex(env.master, env.seq(env.master))}; env(check::create(env.master, alice, XRP(100))); env.close(); @@ -211,8 +161,7 @@ class Check_test : public beast::unit_test::suite // Note that no trust line has been set up for alice, but alice can // still write a check for USD. You don't have to have the funds // necessary to cover a check in order to write a check. - auto writeTwoChecks = [&env, &USD, this]( - Account const& from, Account const& to) { + auto writeTwoChecks = [&env, &USD, this](Account const& from, Account const& to) { std::uint32_t const fromOwnerCount{ownerCount(env, from)}; std::uint32_t const toOwnerCount{ownerCount(env, to)}; @@ -229,8 +178,7 @@ class Check_test : public beast::unit_test::suite BEAST_EXPECT(checksOnAccount(env, to).size() == toCkCount + 2); env.require(owners(from, fromOwnerCount + 2)); - env.require( - owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount)); + env.require(owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount)); }; // from to writeTwoChecks(alice, bob); @@ -281,9 +229,7 @@ class Check_test : public beast::unit_test::suite // alice uses multisigning to create a check. XRPAmount const baseFeeDrops{env.current()->fees().base}; - env(check::create(alice, bob, USD(50)), - msig(bogie, demon), - fee(3 * baseFeeDrops)); + env(check::create(alice, bob, USD(50)), msig(bogie, demon), fee(3 * baseFeeDrops)); env.close(); BEAST_EXPECT(checksOnAccount(env, alice).size() == aliceCount + 7); BEAST_EXPECT(checksOnAccount(env, bob).size() == bobCount + 7); @@ -296,24 +242,12 @@ class Check_test : public beast::unit_test::suite using namespace test::jtx; - // test flag doesn't set unless amendment enabled - { - Env env{*this, features - disallowIncoming}; - Account const alice{"alice"}; - env.fund(XRP(10000), alice); - env(fset(alice, asfDisallowIncomingCheck)); - env.close(); - auto const sle = env.le(alice); - uint32_t flags = sle->getFlags(); - BEAST_EXPECT(!(flags & lsfDisallowIncomingCheck)); - } - Account const gw{"gateway"}; Account const alice{"alice"}; Account const bob{"bob"}; IOU const USD{gw["USD"]}; - Env env{*this, features | disallowIncoming}; + Env env{*this, features}; STAmount const startBalance{XRP(1000).value()}; env.fund(startBalance, gw, alice, bob); @@ -323,10 +257,7 @@ class Check_test : public beast::unit_test::suite * Attempt to create two checks from `from` to `to` and * require they both result in error/success code `expected` */ - auto writeTwoChecksDI = [&env, &USD, this]( - Account const& from, - Account const& to, - TER expected) { + auto writeTwoChecksDI = [&env, &USD, this](Account const& from, Account const& to, TER expected) { std::uint32_t const fromOwnerCount{ownerCount(env, from)}; std::uint32_t const toOwnerCount{ownerCount(env, to)}; @@ -341,13 +272,11 @@ class Check_test : public beast::unit_test::suite if (expected == tesSUCCESS) { - BEAST_EXPECT( - checksOnAccount(env, from).size() == fromCkCount + 2); + BEAST_EXPECT(checksOnAccount(env, from).size() == fromCkCount + 2); BEAST_EXPECT(checksOnAccount(env, to).size() == toCkCount + 2); env.require(owners(from, fromOwnerCount + 2)); - env.require( - owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount)); + env.require(owners(to, to == from ? fromOwnerCount + 2 : toOwnerCount)); return; } @@ -405,15 +334,11 @@ class Check_test : public beast::unit_test::suite env.close(); // Bad fee. - env(check::create(alice, bob, USD(50)), - fee(drops(-10)), - ter(temBAD_FEE)); + env(check::create(alice, bob, USD(50)), fee(drops(-10)), ter(temBAD_FEE)); env.close(); // Bad flags. - env(check::create(alice, bob, USD(50)), - txflags(tfImmediateOrCancel), - ter(temINVALID_FLAG)); + env(check::create(alice, bob, USD(50)), txflags(tfImmediateOrCancel), ter(temINVALID_FLAG)); env.close(); // Check to self. @@ -445,9 +370,7 @@ class Check_test : public beast::unit_test::suite } // Bad expiration. - env(check::create(alice, bob, USD(50)), - expiration(NetClock::time_point{}), - ter(temBAD_EXPIRATION)); + env(check::create(alice, bob, USD(50)), expiration(NetClock::time_point{}), ter(temBAD_EXPIRATION)); env.close(); // Destination does not exist. @@ -544,9 +467,7 @@ class Check_test : public beast::unit_test::suite } // Expired expiration. - env(check::create(alice, bob, USD(50)), - expiration(env.now()), - ter(tecEXPIRED)); + env(check::create(alice, bob, USD(50)), expiration(env.now()), ter(tecEXPIRED)); env.close(); using namespace std::chrono_literals; @@ -558,9 +479,7 @@ class Check_test : public beast::unit_test::suite env.fund(env.current()->fees().accountReserve(1) - drops(1), cheri); env.close(); - env(check::create(cheri, bob, USD(50)), - fee(drops(env.current()->fees().base)), - ter(tecINSUFFICIENT_RESERVE)); + env(check::create(cheri, bob, USD(50)), fee(drops(env.current()->fees().base)), ter(tecINSUFFICIENT_RESERVE)); env.close(); env(pay(bob, cheri, drops(env.current()->fees().base + 1))); @@ -601,10 +520,8 @@ class Check_test : public beast::unit_test::suite env(check::cash(bob, chkId, XRP(10))); env.close(); - env.require( - balance(alice, startBalance - XRP(10) - drops(baseFeeDrops))); - env.require( - balance(bob, startBalance + XRP(10) - drops(baseFeeDrops))); + env.require(balance(alice, startBalance - XRP(10) - drops(baseFeeDrops))); + env.require(balance(bob, startBalance + XRP(10) - drops(baseFeeDrops))); BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -620,19 +537,15 @@ class Check_test : public beast::unit_test::suite { // Write a check that chews into alice's reserve. STAmount const reserve{env.current()->fees().reserve}; - STAmount const checkAmount{ - startBalance - reserve - drops(baseFeeDrops)}; + STAmount const checkAmount{startBalance - reserve - drops(baseFeeDrops)}; uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, checkAmount)); env.close(); // bob tries to cash for more than the check amount. - env(check::cash(bob, chkId, checkAmount + drops(1)), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkId, checkAmount + drops(1)), ter(tecPATH_PARTIAL)); env.close(); - env(check::cash( - bob, chkId, check::DeliverMin(checkAmount + drops(1))), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkId, check::DeliverMin(checkAmount + drops(1))), ter(tecPATH_PARTIAL)); env.close(); // bob cashes exactly the check amount. This is successful @@ -641,8 +554,7 @@ class Check_test : public beast::unit_test::suite env(check::cash(bob, chkId, check::DeliverMin(checkAmount))); verifyDeliveredAmount(env, drops(checkAmount.mantissa())); env.require(balance(alice, reserve)); - env.require(balance( - bob, startBalance + checkAmount - drops(baseFeeDrops * 3))); + env.require(balance(bob, startBalance + checkAmount - drops(baseFeeDrops * 3))); BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -658,8 +570,7 @@ class Check_test : public beast::unit_test::suite { // Write a check that goes one drop past what alice can pay. STAmount const reserve{env.current()->fees().reserve}; - STAmount const checkAmount{ - startBalance - reserve - drops(baseFeeDrops - 1)}; + STAmount const checkAmount{startBalance - reserve - drops(baseFeeDrops - 1)}; uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, checkAmount)); env.close(); @@ -673,8 +584,7 @@ class Check_test : public beast::unit_test::suite env(check::cash(bob, chkId, check::DeliverMin(drops(1)))); verifyDeliveredAmount(env, drops(checkAmount.mantissa() - 1)); env.require(balance(alice, reserve)); - env.require(balance( - bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1))); + env.require(balance(bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1))); BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -682,8 +592,7 @@ class Check_test : public beast::unit_test::suite // Make alice's and bob's balances easy to think about. env(pay(env.master, alice, checkAmount + drops(baseFeeDrops - 1))); - env(pay( - bob, env.master, checkAmount - drops(baseFeeDrops * 3 + 1))); + env(pay(bob, env.master, checkAmount - drops(baseFeeDrops * 3 + 1))); env.close(); env.require(balance(alice, startBalance)); env.require(balance(bob, startBalance)); @@ -698,9 +607,6 @@ class Check_test : public beast::unit_test::suite using namespace test::jtx; - bool const cashCheckMakesTrustLine = - features[featureCheckCashMakesTrustLine]; - Account const gw{"gateway"}; Account const alice{"alice"}; Account const bob{"bob"}; @@ -733,26 +639,10 @@ class Check_test : public beast::unit_test::suite // and fails because he hasn't got a trust line for USD. env(pay(gw, alice, USD(0.5))); env.close(); - if (!cashCheckMakesTrustLine) - { - // If cashing a check automatically creates a trustline then - // this returns tesSUCCESS and the check is removed from the - // ledger which would mess up later tests. - env(check::cash(bob, chkId1, USD(10)), ter(tecNO_LINE)); - env.close(); - } // bob sets up the trust line, but not at a high enough limit. env(trust(bob, USD(9.5))); env.close(); - if (!cashCheckMakesTrustLine) - { - // If cashing a check is allowed to exceed the trust line - // limit then this returns tesSUCCESS and the check is - // removed from the ledger which would mess up later tests. - env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL)); - env.close(); - } // bob sets the trust line limit high enough but asks for more // than the check's SendMax. @@ -827,34 +717,31 @@ class Check_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 2); BEAST_EXPECT(ownerCount(env, bob) == 1); - if (cashCheckMakesTrustLine) - { - // Automatic trust lines are enabled. But one aspect of - // automatic trust lines is that they allow the account - // cashing a check to exceed their trust line limit. Show - // that at work. - // - // bob's trust line limit is currently USD(10.5). Show that - // a payment to bob cannot exceed that trust line, but cashing - // a check can. + // Automatic trust lines are enabled. But one aspect of + // automatic trust lines is that they allow the account + // cashing a check to exceed their trust line limit. Show + // that at work. + // + // bob's trust line limit is currently USD(10.5). Show that + // a payment to bob cannot exceed that trust line, but cashing + // a check can. - // Payment of 20 USD fails. - env(pay(gw, bob, USD(20)), ter(tecPATH_PARTIAL)); - env.close(); + // Payment of 20 USD fails. + env(pay(gw, bob, USD(20)), ter(tecPATH_PARTIAL)); + env.close(); - uint256 const chkId20{getCheckIndex(gw, env.seq(gw))}; - env(check::create(gw, bob, USD(20))); - env.close(); + uint256 const chkId20{getCheckIndex(gw, env.seq(gw))}; + env(check::create(gw, bob, USD(20))); + env.close(); - // However cashing a check for 20 USD succeeds. - env(check::cash(bob, chkId20, USD(20))); - env.close(); - env.require(balance(bob, USD(30))); + // However cashing a check for 20 USD succeeds. + env(check::cash(bob, chkId20, USD(20))); + env.close(); + env.require(balance(bob, USD(30))); - // Clean up this most recent experiment so the rest of the - // tests work. - env(pay(bob, gw, USD(20))); - } + // Clean up this most recent experiment so the rest of the + // tests work. + env(pay(bob, gw, USD(20))); // ... so bob cancels alice's remaining check. env(check::cancel(bob, chkId3)); @@ -895,8 +782,7 @@ class Check_test : public beast::unit_test::suite // bob attempts to cash a check for the amount on the check. // Should fail, since alice doesn't have the funds. - env(check::cash(bob, chkId9, check::DeliverMin(USD(9))), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkId9, check::DeliverMin(USD(9))), ter(tecPATH_PARTIAL)); env.close(); // bob sets a DeliverMin of 7 and gets all that alice has. @@ -969,8 +855,7 @@ class Check_test : public beast::unit_test::suite env(check::create(alice, bob, USD(7))); env.close(); - env(check::cash(bob, chkId, USD(7)), - ter(cashCheckMakesTrustLine ? tecNO_AUTH : tecNO_LINE)); + env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH)); env.close(); // Now give bob a trustline for USD. bob still can't cash the @@ -985,17 +870,6 @@ class Check_test : public beast::unit_test::suite env(trust(gw, bob["USD"](1)), txflags(tfSetfAuth)); env.close(); - // bob tries to cash the check again but fails because his trust - // limit is too low. - if (!cashCheckMakesTrustLine) - { - // If cashing a check is allowed to exceed the trust line - // limit then this returns tesSUCCESS and the check is - // removed from the ledger which would mess up later tests. - env(check::cash(bob, chkId, USD(7)), ter(tecPATH_PARTIAL)); - env.close(); - } - // Two possible outcomes here depending on whether cashing a // check can build a trust line: // o If it can't build a trust line, then since bob set his @@ -1004,7 +878,7 @@ class Check_test : public beast::unit_test::suite // o If it can build a trust line, then the check is allowed to // exceed the trust limit and bob gets the full transfer. env(check::cash(bob, chkId, check::DeliverMin(USD(4)))); - STAmount const bobGot = cashCheckMakesTrustLine ? USD(7) : USD(5); + STAmount const bobGot = USD(7); verifyDeliveredAmount(env, bobGot); env.require(balance(alice, USD(8) - bobGot)); env.require(balance(bob, bobGot)); @@ -1016,14 +890,8 @@ class Check_test : public beast::unit_test::suite } // Use a regular key and also multisign to cash a check. - // featureMultiSignReserve changes the reserve on a SignerList, so - // check both before and after. - for (auto const& testFeatures : - {features - featureMultiSignReserve, - features | featureMultiSignReserve}) { - Env env{*this, testFeatures}; - + Env env{*this, features}; env.fund(XRP(1000), gw, alice, bob); env.close(); @@ -1052,11 +920,7 @@ class Check_test : public beast::unit_test::suite env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby)); env.close(); - // If featureMultiSignReserve is enabled then bob's signer list - // has an owner count of 1, otherwise it's 4. - int const signersCount = { - testFeatures[featureMultiSignReserve] ? 1 : 4}; - BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1); + BEAST_EXPECT(ownerCount(env, bob) == 2); // bob uses his regular key to cash a check. env(check::cash(bob, chkId1, (USD(1))), sig(bobby)); @@ -1066,20 +930,18 @@ class Check_test : public beast::unit_test::suite BEAST_EXPECT(checksOnAccount(env, alice).size() == 1); BEAST_EXPECT(checksOnAccount(env, bob).size() == 1); BEAST_EXPECT(ownerCount(env, alice) == 2); - BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1); + BEAST_EXPECT(ownerCount(env, bob) == 2); // bob uses multisigning to cash a check. XRPAmount const baseFeeDrops{env.current()->fees().base}; - env(check::cash(bob, chkId2, (USD(2))), - msig(bogie, demon), - fee(3 * baseFeeDrops)); + env(check::cash(bob, chkId2, (USD(2))), msig(bogie, demon), fee(3 * baseFeeDrops)); env.close(); env.require(balance(alice, USD(5))); env.require(balance(bob, USD(3))); BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); BEAST_EXPECT(ownerCount(env, alice) == 1); - BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1); + BEAST_EXPECT(ownerCount(env, bob) == 2); } } @@ -1127,8 +989,7 @@ class Check_test : public beast::unit_test::suite // bob attempts to cash the check for face value. Should fail. env(check::cash(bob, chkId125, USD(125)), ter(tecPATH_PARTIAL)); env.close(); - env(check::cash(bob, chkId125, check::DeliverMin(USD(101))), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkId125, check::DeliverMin(USD(101))), ter(tecPATH_PARTIAL)); env.close(); // bob decides that he'll accept anything USD(75) or up. @@ -1188,59 +1049,53 @@ class Check_test : public beast::unit_test::suite // There are two test lambdas: one for a Payment and one for a Check. // This shows whether a Payment and a Check behave the same. - auto testNonIssuerQPay = [&env, &alice, &bob, &USD]( - Account const& truster, - IOU const& iou, - auto const& inOrOut, - double pct, - double amount) { - // Capture bob's and alice's balances so we can test at the end. - STAmount const aliceStart{env.balance(alice, USD.issue()).value()}; - STAmount const bobStart{env.balance(bob, USD.issue()).value()}; + auto testNonIssuerQPay = + [&env, &alice, &bob, &USD]( + Account const& truster, IOU const& iou, auto const& inOrOut, double pct, double amount) { + // Capture bob's and alice's balances so we can test at the end. + STAmount const aliceStart{env.balance(alice, USD.issue()).value()}; + STAmount const bobStart{env.balance(bob, USD.issue()).value()}; - // Set the modified quality. - env(trust(truster, iou(1000)), inOrOut(pct)); - env.close(); + // Set the modified quality. + env(trust(truster, iou(1000)), inOrOut(pct)); + env.close(); - env(pay(alice, bob, USD(amount)), sendmax(USD(10))); - env.close(); - env.require(balance(alice, aliceStart - USD(10))); - env.require(balance(bob, bobStart + USD(10))); + env(pay(alice, bob, USD(amount)), sendmax(USD(10))); + env.close(); + env.require(balance(alice, aliceStart - USD(10))); + env.require(balance(bob, bobStart + USD(10))); - // Return the quality to the unmodified state so it doesn't - // interfere with upcoming tests. - env(trust(truster, iou(1000)), inOrOut(0)); - env.close(); - }; + // Return the quality to the unmodified state so it doesn't + // interfere with upcoming tests. + env(trust(truster, iou(1000)), inOrOut(0)); + env.close(); + }; - auto testNonIssuerQCheck = [&env, &alice, &bob, &USD]( - Account const& truster, - IOU const& iou, - auto const& inOrOut, - double pct, - double amount) { - // Capture bob's and alice's balances so we can test at the end. - STAmount const aliceStart{env.balance(alice, USD.issue()).value()}; - STAmount const bobStart{env.balance(bob, USD.issue()).value()}; + auto testNonIssuerQCheck = + [&env, &alice, &bob, &USD]( + Account const& truster, IOU const& iou, auto const& inOrOut, double pct, double amount) { + // Capture bob's and alice's balances so we can test at the end. + STAmount const aliceStart{env.balance(alice, USD.issue()).value()}; + STAmount const bobStart{env.balance(bob, USD.issue()).value()}; - // Set the modified quality. - env(trust(truster, iou(1000)), inOrOut(pct)); - env.close(); + // Set the modified quality. + env(trust(truster, iou(1000)), inOrOut(pct)); + env.close(); - uint256 const chkId = getCheckIndex(alice, env.seq(alice)); - env(check::create(alice, bob, USD(10))); - env.close(); + uint256 const chkId = getCheckIndex(alice, env.seq(alice)); + env(check::create(alice, bob, USD(10))); + env.close(); - env(check::cash(bob, chkId, USD(amount))); - env.close(); - env.require(balance(alice, aliceStart - USD(10))); - env.require(balance(bob, bobStart + USD(10))); + env(check::cash(bob, chkId, USD(amount))); + env.close(); + env.require(balance(alice, aliceStart - USD(10))); + env.require(balance(bob, bobStart + USD(10))); - // Return the quality to the unmodified state so it doesn't - // interfere with upcoming tests. - env(trust(truster, iou(1000)), inOrOut(0)); - env.close(); - }; + // Return the quality to the unmodified state so it doesn't + // interfere with upcoming tests. + env(trust(truster, iou(1000)), inOrOut(0)); + env.close(); + }; // pct amount testNonIssuerQPay(alice, gw["USD"], qIn, 50, 10); @@ -1387,23 +1242,6 @@ class Check_test : public beast::unit_test::suite env(pay(gw, alice, USD(20))); env.close(); - // Before bob gets a trustline, have him try to cash a check. - // Should fail. - { - uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; - env(check::create(alice, bob, USD(20))); - env.close(); - - if (!features[featureCheckCashMakesTrustLine]) - { - // If cashing a check automatically creates a trustline then - // this returns tesSUCCESS and the check is removed from the - // ledger which would mess up later tests. - env(check::cash(bob, chkId, USD(20)), ter(tecNO_LINE)); - env.close(); - } - } - // Now set up bob's trustline. env(trust(bob, USD(20))); env.close(); @@ -1454,18 +1292,13 @@ class Check_test : public beast::unit_test::suite env.close(); // Same set of failing cases for both IOU and XRP check cashing. - auto failingCases = [&env, &gw, &alice, &bob]( - uint256 const& chkId, STAmount const& amount) { + auto failingCases = [&env, &gw, &alice, &bob](uint256 const& chkId, STAmount const& amount) { // Bad fee. - env(check::cash(bob, chkId, amount), - fee(drops(-10)), - ter(temBAD_FEE)); + env(check::cash(bob, chkId, amount), fee(drops(-10)), ter(temBAD_FEE)); env.close(); // Bad flags. - env(check::cash(bob, chkId, amount), - txflags(tfImmediateOrCancel), - ter(temINVALID_FLAG)); + env(check::cash(bob, chkId, amount), txflags(tfImmediateOrCancel), ter(temINVALID_FLAG)); env.close(); // Missing both Amount and DeliverMin. @@ -1489,8 +1322,7 @@ class Check_test : public beast::unit_test::suite neg.negate(); env(check::cash(bob, chkId, neg), ter(temBAD_AMOUNT)); env.close(); - env(check::cash(bob, chkId, amount.zeroed()), - ter(temBAD_AMOUNT)); + env(check::cash(bob, chkId, amount.zeroed()), ter(temBAD_AMOUNT)); env.close(); } @@ -1533,8 +1365,7 @@ class Check_test : public beast::unit_test::suite env.close(); // DeliverMin bigger than SendMax. - env(check::cash(bob, chkId, check::DeliverMin(amount + amount)), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkId, check::DeliverMin(amount + amount)), ter(tecPATH_PARTIAL)); env.close(); }; @@ -1568,8 +1399,7 @@ class Check_test : public beast::unit_test::suite env(check::cash(bob, chkIdFroz1, USD(1)), ter(tecPATH_PARTIAL)); env.close(); - env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))), ter(tecPATH_PARTIAL)); env.close(); env(fclear(gw, asfGlobalFreeze)); @@ -1586,8 +1416,7 @@ class Check_test : public beast::unit_test::suite env.close(); env(check::cash(bob, chkIdFroz2, USD(2)), ter(tecPATH_PARTIAL)); env.close(); - env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))), ter(tecPATH_PARTIAL)); env.close(); // Clear that freeze. Now check cashing works. @@ -1603,8 +1432,7 @@ class Check_test : public beast::unit_test::suite env.close(); env(check::cash(bob, chkIdFroz3, USD(3)), ter(tecFROZEN)); env.close(); - env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))), - ter(tecFROZEN)); + env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))), ter(tecFROZEN)); env.close(); // Clear that freeze. Now check cashing works again. @@ -1621,8 +1449,7 @@ class Check_test : public beast::unit_test::suite env.close(); env(check::cash(bob, chkIdFroz4, USD(4)), ter(terNO_LINE)); env.close(); - env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))), - ter(terNO_LINE)); + env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))), ter(terNO_LINE)); env.close(); // Clear bob's freeze bit and the check should be cashable. @@ -1640,8 +1467,7 @@ class Check_test : public beast::unit_test::suite env.close(); env(check::cash(bob, chkIdNoDest1, USD(1)), ter(tecDST_TAG_NEEDED)); env.close(); - env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))), - ter(tecDST_TAG_NEEDED)); + env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))), ter(tecDST_TAG_NEEDED)); env.close(); // bob can cash a check with a destination tag. @@ -1675,13 +1501,8 @@ class Check_test : public beast::unit_test::suite Account const zoe{"zoe"}; IOU const USD{gw["USD"]}; - // featureMultiSignReserve changes the reserve on a SignerList, so - // check both before and after. - for (auto const& testFeatures : - {features - featureMultiSignReserve, - features | featureMultiSignReserve}) { - Env env{*this, testFeatures}; + Env env{*this, features}; env.fund(XRP(1000), gw, alice, bob, zoe); env.close(); @@ -1703,18 +1524,15 @@ class Check_test : public beast::unit_test::suite // Three checks that expire in 10 minutes. using namespace std::chrono_literals; uint256 const chkIdNotExp1{getCheckIndex(alice, env.seq(alice))}; - env(check::create(alice, bob, XRP(10)), - expiration(env.now() + 600s)); + env(check::create(alice, bob, XRP(10)), expiration(env.now() + 600s)); env.close(); uint256 const chkIdNotExp2{getCheckIndex(alice, env.seq(alice))}; - env(check::create(alice, bob, USD(10)), - expiration(env.now() + 600s)); + env(check::create(alice, bob, USD(10)), expiration(env.now() + 600s)); env.close(); uint256 const chkIdNotExp3{getCheckIndex(alice, env.seq(alice))}; - env(check::create(alice, bob, XRP(10)), - expiration(env.now() + 600s)); + env(check::create(alice, bob, XRP(10)), expiration(env.now() + 600s)); env.close(); // Three checks that expire in one second. @@ -1799,36 +1617,29 @@ class Check_test : public beast::unit_test::suite env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie)); env.close(); - // If featureMultiSignReserve is enabled then alices's signer list - // has an owner count of 1, otherwise it's 4. - int const signersCount{ - testFeatures[featureMultiSignReserve] ? 1 : 4}; - // alice uses her regular key to cancel a check. env(check::cancel(alice, chkIdReg), sig(alie)); env.close(); BEAST_EXPECT(checksOnAccount(env, alice).size() == 3); - BEAST_EXPECT(ownerCount(env, alice) == signersCount + 3); + BEAST_EXPECT(ownerCount(env, alice) == 4); // alice uses multisigning to cancel a check. XRPAmount const baseFeeDrops{env.current()->fees().base}; - env(check::cancel(alice, chkIdMSig), - msig(bogie, demon), - fee(3 * baseFeeDrops)); + env(check::cancel(alice, chkIdMSig), msig(bogie, demon), fee(3 * baseFeeDrops)); env.close(); BEAST_EXPECT(checksOnAccount(env, alice).size() == 2); - BEAST_EXPECT(ownerCount(env, alice) == signersCount + 2); + BEAST_EXPECT(ownerCount(env, alice) == 3); // Creator and destination cancel the remaining unexpired checks. env(check::cancel(alice, chkId3), sig(alice)); env.close(); BEAST_EXPECT(checksOnAccount(env, alice).size() == 1); - BEAST_EXPECT(ownerCount(env, alice) == signersCount + 1); + BEAST_EXPECT(ownerCount(env, alice) == 2); env(check::cancel(bob, chkIdNotExp3)); env.close(); BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(ownerCount(env, alice) == signersCount + 0); + BEAST_EXPECT(ownerCount(env, alice) == 1); } } @@ -1849,9 +1660,7 @@ class Check_test : public beast::unit_test::suite env.close(); // Bad fee. - env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))), - fee(drops(-10)), - ter(temBAD_FEE)); + env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))), fee(drops(-10)), ter(temBAD_FEE)); env.close(); // Bad flags. @@ -1861,8 +1670,7 @@ class Check_test : public beast::unit_test::suite env.close(); // Non-existent check. - env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))), - ter(tecNO_ENTRY)); + env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))), ter(tecNO_ENTRY)); env.close(); } @@ -1887,8 +1695,7 @@ class Check_test : public beast::unit_test::suite env(check::cash(bob, chkId, check::DeliverMin(XRP(100)))); // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; env.close(); Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta]; @@ -2003,10 +1810,6 @@ class Check_test : public beast::unit_test::suite { // Explore automatic trust line creation when a check is cashed. // - // This capability is enabled by the featureCheckCashMakesTrustLine - // amendment. So this test executes only when that amendment is - // active. - assert(features[featureCheckCashMakesTrustLine]); testcase("Trust Line Creation"); @@ -2025,11 +1828,7 @@ class Check_test : public beast::unit_test::suite void verifyOwners(std::uint32_t line) const { - suite.expect( - ownerCount(env, acct) == owners, - "Owner count mismatch", - __FILE__, - line); + suite.expect(ownerCount(env, acct) == owners, "Owner count mismatch", __FILE__, line); } // Operators to make using the class more convenient. @@ -2038,7 +1837,7 @@ class Check_test : public beast::unit_test::suite return acct; } - operator ripple::AccountID() const + operator xrpl::AccountID() const { return acct.id(); } @@ -2083,8 +1882,7 @@ class Check_test : public beast::unit_test::suite env(check::create(gw1, yui, CK8(99))); env.close(); - env(check::cash(yui, chkId, CK8(99)), - ter(tecNO_LINE_INSUF_RESERVE)); + env(check::cash(yui, chkId, CK8(99)), ter(tecNO_LINE_INSUF_RESERVE)); env.close(); alice.verifyOwners(__LINE__); @@ -2115,14 +1913,9 @@ class Check_test : public beast::unit_test::suite // between the same two accounts but with two different currencies. // The lambda expects the two trust lines to be largely similar. auto cmpTrustLines = [this, &env]( - Account const& acct1, - Account const& acct2, - IOU const& offerIou, - IOU const& checkIou) { - auto const offerLine = - env.le(keylet::line(acct1, acct2, offerIou.currency)); - auto const checkLine = - env.le(keylet::line(acct1, acct2, checkIou.currency)); + Account const& acct1, Account const& acct2, IOU const& offerIou, IOU const& checkIou) { + auto const offerLine = env.le(keylet::line(acct1, acct2, offerIou.currency)); + auto const checkLine = env.le(keylet::line(acct1, acct2, checkIou.currency)); if (offerLine == nullptr || checkLine == nullptr) { BEAST_EXPECT(offerLine == nullptr && checkLine == nullptr); @@ -2135,50 +1928,39 @@ class Check_test : public beast::unit_test::suite // Lambda that compares the contents of required STAmounts // without comparing the currency. - auto cmpReqAmount = - [this, offerLine, checkLine](SF_AMOUNT const& sfield) { - STAmount const offerAmount = offerLine->at(sfield); - STAmount const checkAmount = checkLine->at(sfield); + auto cmpReqAmount = [this, offerLine, checkLine](SF_AMOUNT const& sfield) { + STAmount const offerAmount = offerLine->at(sfield); + STAmount const checkAmount = checkLine->at(sfield); - // Neither STAmount should be native. - if (!BEAST_EXPECT( - !offerAmount.native() && !checkAmount.native())) - return; + // Neither STAmount should be native. + if (!BEAST_EXPECT(!offerAmount.native() && !checkAmount.native())) + return; - BEAST_EXPECT( - offerAmount.issue().account == - checkAmount.issue().account); - BEAST_EXPECT( - offerAmount.negative() == checkAmount.negative()); - BEAST_EXPECT( - offerAmount.mantissa() == checkAmount.mantissa()); - BEAST_EXPECT( - offerAmount.exponent() == checkAmount.exponent()); - }; + BEAST_EXPECT(offerAmount.issue().account == checkAmount.issue().account); + BEAST_EXPECT(offerAmount.negative() == checkAmount.negative()); + BEAST_EXPECT(offerAmount.mantissa() == checkAmount.mantissa()); + BEAST_EXPECT(offerAmount.exponent() == checkAmount.exponent()); + }; cmpReqAmount(sfBalance); cmpReqAmount(sfLowLimit); cmpReqAmount(sfHighLimit); } { // Lambda that compares the contents of optional fields. - auto cmpOptField = - [this, offerLine, checkLine](auto const& sfield) { - // Expect both fields to either be present or absent. - if (!BEAST_EXPECT( - offerLine->isFieldPresent(sfield) == - checkLine->isFieldPresent(sfield))) - return; + auto cmpOptField = [this, offerLine, checkLine](auto const& sfield) { + // Expect both fields to either be present or absent. + if (!BEAST_EXPECT(offerLine->isFieldPresent(sfield) == checkLine->isFieldPresent(sfield))) + return; - // If both fields are absent then there's nothing - // further to check. - if (!offerLine->isFieldPresent(sfield)) - return; + // If both fields are absent then there's nothing + // further to check. + if (!offerLine->isFieldPresent(sfield)) + return; - // Both optional fields are present so we can compare - // them. - BEAST_EXPECT( - offerLine->at(sfield) == checkLine->at(sfield)); - }; + // Both optional fields are present so we can compare + // them. + BEAST_EXPECT(offerLine->at(sfield) == checkLine->at(sfield)); + }; cmpOptField(sfLowNode); cmpOptField(sfLowQualityIn); cmpOptField(sfLowQualityOut); @@ -2203,8 +1985,7 @@ class Check_test : public beast::unit_test::suite IOU const OF1 = gw1["OF1"]; env(offer(gw1, XRP(98), OF1(98))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, OF1.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, OF1.currency)) == nullptr); env(offer(alice, OF1(98), XRP(98))); ++alice.owners; env.close(); @@ -2222,8 +2003,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))}; env(check::create(gw1, alice, CK1(98))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, CK1.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, CK1.currency)) == nullptr); env(check::cash(alice, chkId, CK1(98))); ++alice.owners; verifyDeliveredAmount(env, CK1(98)); @@ -2252,8 +2032,7 @@ class Check_test : public beast::unit_test::suite IOU const OF1 = gw1["OF1"]; env(offer(alice, XRP(97), OF1(97))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, OF1.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, OF1.currency)) == nullptr); env(offer(bob, OF1(97), XRP(97))); ++bob.owners; env.close(); @@ -2277,15 +2056,12 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, CK1(97))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, CK1.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, CK1.currency)) == nullptr); env(check::cash(bob, chkId, CK1(97)), ter(terNO_RIPPLE)); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, bob, OF1.currency)) != nullptr); - BEAST_EXPECT( - env.le(keylet::line(gw1, bob, CK1.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, bob, OF1.currency)) != nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, bob, CK1.currency)) == nullptr); // Delete alice's check since it is no longer needed. env(check::cancel(alice, chkId)); @@ -2309,8 +2085,7 @@ class Check_test : public beast::unit_test::suite IOU const OF2 = gw1["OF2"]; env(offer(gw1, XRP(96), OF2(96))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, OF2.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, OF2.currency)) == nullptr); env(offer(alice, OF2(96), XRP(96))); ++alice.owners; env.close(); @@ -2328,8 +2103,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))}; env(check::create(gw1, alice, CK2(96))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, CK2.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, CK2.currency)) == nullptr); env(check::cash(alice, chkId, CK2(96))); ++alice.owners; verifyDeliveredAmount(env, CK2(96)); @@ -2355,8 +2129,7 @@ class Check_test : public beast::unit_test::suite IOU const OF2 = gw1["OF2"]; env(offer(alice, XRP(95), OF2(95))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, OF2.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, OF2.currency)) == nullptr); env(offer(bob, OF2(95), XRP(95))); ++bob.owners; env.close(); @@ -2371,8 +2144,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, CK2(95))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, CK2.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, CK2.currency)) == nullptr); env(check::cash(bob, chkId, CK2(95))); ++bob.owners; verifyDeliveredAmount(env, CK2(95)); @@ -2404,8 +2176,7 @@ class Check_test : public beast::unit_test::suite IOU const OF3 = gw1["OF3"]; env(offer(gw1, XRP(94), OF3(94))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, OF3.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, OF3.currency)) == nullptr); env(offer(alice, OF3(94), XRP(94))); ++alice.owners; env.close(); @@ -2423,8 +2194,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))}; env(check::create(gw1, alice, CK3(94))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, CK3.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, CK3.currency)) == nullptr); env(check::cash(alice, chkId, CK3(94))); ++alice.owners; verifyDeliveredAmount(env, CK3(94)); @@ -2450,8 +2220,7 @@ class Check_test : public beast::unit_test::suite IOU const OF3 = gw1["OF3"]; env(offer(alice, XRP(93), OF3(93))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, OF3.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, OF3.currency)) == nullptr); env(offer(bob, OF3(93), XRP(93))); ++bob.owners; env.close(); @@ -2466,8 +2235,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, CK3(93))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, CK3.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, CK3.currency)) == nullptr); env(check::cash(bob, chkId, CK3(93))); ++bob.owners; verifyDeliveredAmount(env, CK3(93)); @@ -2493,8 +2261,7 @@ class Check_test : public beast::unit_test::suite IOU const OF4 = gw1["OF4"]; env(offer(gw1, XRP(92), OF4(92)), ter(tecFROZEN)); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr); env(offer(alice, OF4(92), XRP(92)), ter(tecFROZEN)); env.close(); @@ -2508,8 +2275,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))}; env(check::create(gw1, alice, CK4(92)), ter(tecFROZEN)); env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr); env(check::cash(alice, chkId, CK4(92)), ter(tecNO_ENTRY)); env.close(); @@ -2520,10 +2286,8 @@ class Check_test : public beast::unit_test::suite // Because gw1 has set lsfGlobalFreeze, neither trust line // is created. - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr); - BEAST_EXPECT( - env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr); } //------------ lsfGlobalFreeze, check written by non-issuer ------------ { @@ -2535,8 +2299,7 @@ class Check_test : public beast::unit_test::suite IOU const OF4 = gw1["OF4"]; env(offer(alice, XRP(91), OF4(91)), ter(tecFROZEN)); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, OF4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, OF4.currency)) == nullptr); env(offer(bob, OF4(91), XRP(91)), ter(tecFROZEN)); env.close(); @@ -2550,8 +2313,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, CK4(91)), ter(tecFROZEN)); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, CK4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, CK4.currency)) == nullptr); env(check::cash(bob, chkId, CK4(91)), ter(tecNO_ENTRY)); env.close(); @@ -2562,10 +2324,8 @@ class Check_test : public beast::unit_test::suite // Because gw1 has set lsfGlobalFreeze, neither trust line // is created. - BEAST_EXPECT( - env.le(keylet::line(gw1, bob, OF4.currency)) == nullptr); - BEAST_EXPECT( - env.le(keylet::line(gw1, bob, CK4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, bob, OF4.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw1, bob, CK4.currency)) == nullptr); } //-------------- lsfRequireAuth, check written by issuer --------------- @@ -2589,8 +2349,7 @@ class Check_test : public beast::unit_test::suite env(offer(gw2, XRP(92), OF5(92))); ++gw2.owners; env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr); env(offer(alice, OF5(92), XRP(92)), ter(tecNO_LINE)); env.close(); @@ -2612,8 +2371,7 @@ class Check_test : public beast::unit_test::suite env(check::create(gw2, alice, CK5(92))); ++gw2.owners; env.close(); - BEAST_EXPECT( - env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr); env(check::cash(alice, chkId, CK5(92)), ter(tecNO_AUTH)); env.close(); @@ -2625,10 +2383,8 @@ class Check_test : public beast::unit_test::suite // Because gw2 has set lsfRequireAuth, neither trust line // is created. - BEAST_EXPECT( - env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr); - BEAST_EXPECT( - env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr); // Since we don't need it any more, remove gw2's check. env(check::cancel(gw2, chkId)); @@ -2647,8 +2403,7 @@ class Check_test : public beast::unit_test::suite env(offer(alice, XRP(91), OF5(91)), ter(tecUNFUNDED_OFFER)); env.close(); env(offer(bob, OF5(91), XRP(91)), ter(tecNO_LINE)); - BEAST_EXPECT( - env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr); env.close(); gw2.verifyOwners(__LINE__); @@ -2660,8 +2415,7 @@ class Check_test : public beast::unit_test::suite uint256 const chkId{getCheckIndex(alice, env.seq(alice))}; env(check::create(alice, bob, CK5(91))); env.close(); - BEAST_EXPECT( - env.le(keylet::line(alice, bob, CK5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(alice, bob, CK5.currency)) == nullptr); env(check::cash(bob, chkId, CK5(91)), ter(tecPATH_PARTIAL)); env.close(); @@ -2676,10 +2430,8 @@ class Check_test : public beast::unit_test::suite // Because gw2 has set lsfRequireAuth, neither trust line // is created. - BEAST_EXPECT( - env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr); - BEAST_EXPECT( - env.le(keylet::line(gw2, bob, CK5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr); + BEAST_EXPECT(env.le(keylet::line(gw2, bob, CK5.currency)) == nullptr); } } @@ -2707,14 +2459,11 @@ public: { using namespace test::jtx; auto const sa = testable_amendments(); - testWithFeats(sa - featureCheckCashMakesTrustLine); - testWithFeats(sa - disallowIncoming); testWithFeats(sa); - - testTrustLineCreation(sa); // Test with featureCheckCashMakesTrustLine + testTrustLineCreation(sa); } }; -BEAST_DEFINE_TESTSUITE(Check, app, ripple); +BEAST_DEFINE_TESTSUITE(Check, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Clawback_test.cpp b/src/test/app/Clawback_test.cpp index adfe80133a..d169e9e165 100644 --- a/src/test/app/Clawback_test.cpp +++ b/src/test/app/Clawback_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class Clawback_test : public beast::unit_test::suite { @@ -269,9 +250,7 @@ class Clawback_test : public beast::unit_test::suite env.require(balance(alice, bob["USD"](-10))); // fails due to invalid flag - env(claw(alice, bob["USD"](5)), - txflags(0x00008000), - ter(temINVALID_FLAG)); + env(claw(alice, bob["USD"](5)), txflags(0x00008000), ter(temINVALID_FLAG)); env.close(); // fails due to negative amount @@ -956,5 +935,5 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Clawback, app, ripple); -} // namespace ripple +BEAST_DEFINE_TESTSUITE(Clawback, app, xrpl); +} // namespace xrpl diff --git a/src/test/app/ConfidentialTransfer_test.cpp b/src/test/app/ConfidentialTransfer_test.cpp index 1ffc652c68..4804381606 100644 --- a/src/test/app/ConfidentialTransfer_test.cpp +++ b/src/test/app/ConfidentialTransfer_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,68 +5,250 @@ #include -namespace ripple { +namespace xrpl { class ConfidentialTransfer_test : public beast::unit_test::suite { - // A 66-byte array of random unsigned char values - constexpr static unsigned char badCiphertext[ecGamalEncryptedTotalLength] = - {0x3E, 0x9A, 0x0F, 0x7C, 0x51, 0xD8, 0x22, 0x8B, 0x6E, 0x14, 0xC9, - 0xF5, 0x4D, 0x6A, 0x03, 0x81, 0x77, 0x2B, 0xEE, 0x9F, 0x10, 0xC2, - 0x57, 0x3D, 0x88, 0x65, 0x0C, 0xAB, 0xF1, 0x4E, 0x19, 0x96, 0x2A, - 0x73, 0xDC, 0x44, 0xB8, 0x5F, 0x01, 0xEA, 0x87, 0x36, 0x60, 0xCE, - 0x92, 0x25, 0x7D, 0x5B, 0xC0, 0x1E, 0x48, 0xF9, 0x84, 0x33, 0x67, - 0xAD, 0x0B, 0xE3, 0x91, 0x50, 0xDA, 0x2F, 0x75, 0xC6, 0xBD, 0x42}; + // Get a bad ciphertext with valid structure but cryptographic invalid for + // testing purposes. For preflight test purposes. + static Buffer const& + getBadCiphertext() + { + static Buffer const badCiphertext = []() { + Buffer buf(ecGamalEncryptedTotalLength); + std::memset(buf.data(), 0xFF, ecGamalEncryptedTotalLength); + + buf.data()[0] = 0x02; + buf.data()[ecGamalEncryptedLength] = 0x02; + return buf; + }(); + + return badCiphertext; + } + + // Get a trivial buffer that is structurally and mathematically valid, but + // contains invalid data that does not match the ledger state. For preclaim + // test purposes. + static Buffer const& + getTrivialCiphertext() + { + static Buffer const trivialCiphertext = []() { + Buffer buf(ecGamalEncryptedTotalLength); + std::memset(buf.data(), 0, ecGamalEncryptedTotalLength); + + buf.data()[0] = 0x02; + buf.data()[ecGamalEncryptedLength] = 0x02; + + buf.data()[ecGamalEncryptedLength - 1] = 0x01; + buf.data()[ecGamalEncryptedTotalLength - 1] = 0x01; + + return buf; + }(); + + return trivialCiphertext; + } + + // Returns a valid compressed EC point (33 bytes) that can pass preflight + // validation but contains invalid data for preclaim test purposes. + static Buffer const& + getTrivialCommitment() + { + static Buffer const trivialCommitment = []() { + Buffer buf(ecPedersenCommitmentLength); + std::memset(buf.data(), 0, ecPedersenCommitmentLength); + + // 0x02 prefix for compressed EC point with even y-coordinate + buf.data()[0] = 0x02; + // Set last byte to make it a valid x-coordinate on the curve + buf.data()[ecPedersenCommitmentLength - 1] = 0x01; + + return buf; + }(); + + return trivialCommitment; + } + + std::string + getTrivialSendProofHex(size_t nRecipients) + { + size_t const sizeEquality = getMultiCiphertextEqualityProofSize(nRecipients); + size_t const totalSize = sizeEquality + (2 * ecPedersenProofLength) + ecDoubleBulletproofLength; + + Buffer buf(totalSize); + std::memset(buf.data(), 0, totalSize); + + for (std::size_t i = 0; i < totalSize; i += ecGamalEncryptedLength) + { + buf.data()[i] = 0x02; + if (i + ecGamalEncryptedLength - 1 < totalSize) + buf.data()[i + ecGamalEncryptedLength - 1] = 0x01; + } + + return strHex(buf); + } void testConvert(FeatureBitset features) { testcase("Convert"); using namespace test::jtx; + + // Basic convert test + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 0, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.convert({ + .account = bob, + .amt = 20, + }); + + mptAlice.convert({ + .account = bob, + .amt = 40, + }); + + mptAlice.convert({ + .account = bob, + .amt = 40, + }); + } + + // Edge case: minimum amount (1) + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 1); + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + mptAlice.convert({ + .account = bob, + .amt = 0, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.convert({ + .account = bob, + .amt = 1, + }); + } + + // Edge case: maxMPTokenAmount + // Using raw JSON to avoid automatic decryption checks in MPTTester + // which don't work for very large amounts (brute-force decryption is slow) + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, maxMPTokenAmount); + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + // First convert with amt=0 to register public key (uses MPTTester) + mptAlice.convert({ + .account = bob, + .amt = 0, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + // Second convert with maxMPTokenAmount using raw JSON + Buffer const blindingFactor = generateBlindingFactor(); + auto const holderCiphertext = mptAlice.encryptAmount(bob, maxMPTokenAmount, blindingFactor); + auto const issuerCiphertext = mptAlice.encryptAmount(alice, maxMPTokenAmount, blindingFactor); + + Json::Value jv; + jv[jss::Account] = bob.human(); + jv[jss::TransactionType] = jss::ConfidentialMPTConvert; + jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); + jv[sfMPTAmount.jsonName] = std::to_string(maxMPTokenAmount); + jv[sfHolderEncryptedAmount.jsonName] = strHex(holderCiphertext); + jv[sfIssuerEncryptedAmount.jsonName] = strHex(issuerCiphertext); + jv[sfBlindingFactor.jsonName] = strHex(blindingFactor); + + env(jv, ter(tesSUCCESS)); + + // Verify the public balance was reduced + env.require(mptbalance(mptAlice, bob, 0)); + } + } + + void + testConvertWithAuditor(FeatureBitset features) + { + testcase("Convert with auditor"); + using namespace test::jtx; + Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); - MPTTester mptAlice(env, alice, {.holders = {bob}}); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(auditor); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 0, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); mptAlice.convert({ .account = bob, .amt = 20, - .proof = "123", }); mptAlice.convert({ .account = bob, - .amt = 40, - .proof = "123", - }); - - mptAlice.convert({ - .account = bob, - .amt = 40, - .proof = "123", + .amt = 30, }); } @@ -95,104 +258,197 @@ class ConfidentialTransfer_test : public beast::unit_test::suite testcase("Convert preflight"); using namespace test::jtx; - Env env{*this, features - featureConfidentialTransfer}; - Account const alice("alice"); - Account const bob("bob"); - MPTTester mptAlice(env, alice, {.holders = {bob}}); + // Alice (issuer) tries to convert her own tokens - should fail + { + Env env{*this, features}; + Account const alice("alice"); + MPTTester mptAlice(env, alice); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + mptAlice.generateKeyPair(alice); - mptAlice.authorize({.account = bob}); - env.close(); - mptAlice.pay(alice, bob, 100); - env.close(); + mptAlice.convert( + {.account = alice, .amt = 10, .holderPubKey = mptAlice.getPubKey(alice), .err = temMALFORMED}); + } - mptAlice.generateKeyPair(alice); - mptAlice.generateKeyPair(bob); + { + Env env{*this, features - featureConfidentialTransfer}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.set( - {.account = alice, - .pubKey = mptAlice.getPubKey(alice), - .err = temDISABLED}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = temDISABLED}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); - env.close(); + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); - env.enableFeature(featureConfidentialTransfer); - env.close(); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice), .err = temDISABLED}); - mptAlice.convert( - {.account = alice, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = temMALFORMED}); + mptAlice.convert({.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = temDISABLED}); + } - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .holderEncryptedAmt = Buffer{}, - .err = temBAD_CIPHERTEXT}); + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .issuerEncryptedAmt = Buffer{}, - .err = temBAD_CIPHERTEXT}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); - mptAlice.convert( - {.account = bob, - .amt = maxMPTokenAmount + 1, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = temBAD_AMOUNT}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); - mptAlice.convert( - {.account = bob, - .amt = 1, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .holderEncryptedAmt = - Buffer{badCiphertext, ecGamalEncryptedTotalLength}, - .err = temBAD_CIPHERTEXT}); + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); - mptAlice.convert( - {.account = bob, - .amt = 1, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .issuerEncryptedAmt = - Buffer{badCiphertext, ecGamalEncryptedTotalLength}, - .err = temBAD_CIPHERTEXT}); + mptAlice.convert( + {.account = alice, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = temMALFORMED}); - // invalid pub key - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = Buffer{}, - .err = temMALFORMED}); + // blinding factor length is invalid + mptAlice.convert( + {.account = alice, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .blindingFactor = makeZeroBuffer(10), + .err = temMALFORMED}); - // todo: change to to check proof size - // mptAlice.convert( - // {.account = bob, - // .amt = 10, - // .proof = "123", - // .holderPubKey = mptAlice.getPubKey(bob), - // .err = temMALFORMED}); + // Holder encrypted amount is empty (length 0) + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .holderEncryptedAmt = Buffer{}, + .err = temBAD_CIPHERTEXT}); + + // Issuer encrypted amount is empty (length 0) + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .issuerEncryptedAmt = Buffer{}, + .err = temBAD_CIPHERTEXT}); + + // Auditor encrypted amount has invalid length (must be 66 bytes) + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .auditorEncryptedAmt = makeZeroBuffer(10), + .err = temBAD_CIPHERTEXT}); + + // Auditor encrypted amount has correct length but invalid data + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .auditorEncryptedAmt = getBadCiphertext(), + .err = temBAD_CIPHERTEXT}); + + // Amount exceeds maximum allowed MPT amount + mptAlice.convert( + {.account = bob, + .amt = maxMPTokenAmount + 1, + .holderPubKey = mptAlice.getPubKey(bob), + .err = temBAD_AMOUNT}); + + // Holder encrypted amount has correct length but invalid data + mptAlice.convert( + {.account = bob, + .amt = 1, + .holderPubKey = mptAlice.getPubKey(bob), + .holderEncryptedAmt = getBadCiphertext(), + .err = temBAD_CIPHERTEXT}); + + // Issuer encrypted amount has correct length but invalid data (not + // a valid EC point) + mptAlice.convert( + {.account = bob, + .amt = 1, + .holderPubKey = mptAlice.getPubKey(bob), + .issuerEncryptedAmt = getBadCiphertext(), + .err = temBAD_CIPHERTEXT}); + + // Holder public key is invalid (empty buffer) + mptAlice.convert({.account = bob, .amt = 10, .holderPubKey = Buffer{}, .err = temMALFORMED}); + + // Holder public key has correct length but invalid EC point data + mptAlice.convert( + {.account = bob, .amt = 10, .holderPubKey = makeZeroBuffer(ecPubKeyLength), .err = temMALFORMED}); + } + + // when registering holder pub key, the transaction must include a + // Schnorr proof of knowledge for the corresponding secret key + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert( + {.account = bob, + .amt = 10, + .fillSchnorrProof = false, + .holderPubKey = mptAlice.getPubKey(bob), + .err = temMALFORMED}); + + mptAlice.convert( + {.account = bob, + .amt = 0, + .fillSchnorrProof = false, + .holderPubKey = mptAlice.getPubKey(bob), + .err = temMALFORMED}); + + // proof length is invalid + mptAlice.convert( + {.account = bob, + .amt = 10, + .proof = std::string(10, 'A'), + .holderPubKey = mptAlice.getPubKey(bob), + .err = temMALFORMED}); + } + + // when holder pub key already registered, Schnorr proof must not be + // provided + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + // this will register bob's pub key, + // and convert 10 to confidential balance + mptAlice.convert({ + .account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + // proof must not be provided after pub key was registered + mptAlice.convert({.account = bob, .amt = 20, .fillSchnorrProof = true, .err = temMALFORMED}); + } } void @@ -207,23 +463,15 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.set( - {.account = alice, - .pubKey = mptAlice.getPubKey(alice), - .err = temDISABLED}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice), .err = temDISABLED}); } // pub key is invalid @@ -233,21 +481,44 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); + // Issuer pub key is invalid (empty) + mptAlice.set({.account = alice, .issuerPubKey = Buffer{}, .err = temMALFORMED}); + + // Issuer pub key has correct length but invalid EC point data + mptAlice.set({.account = alice, .issuerPubKey = makeZeroBuffer(ecPubKeyLength), .err = temMALFORMED}); + + // Auditor key is invalid length mptAlice.set( - {.account = alice, .pubKey = Buffer{}, .err = temMALFORMED}); + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = makeZeroBuffer(10), + .err = temMALFORMED}); + + // Auditor key has correct length but invalid EC point data + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = makeZeroBuffer(ecPubKeyLength), + .err = temMALFORMED}); + + // Cannot set auditor key without issuer key + mptAlice.set({.account = alice, .auditorPubKey = mptAlice.getPubKey(alice), .err = temMALFORMED}); + + // Cannot set Holder and issuer Keys in the same transaction + mptAlice.set( + {.account = alice, .holder = bob, .issuerPubKey = mptAlice.getPubKey(alice), .err = temMALFORMED}); + + // Cannot set Holder and auditor Keys in the same transaction + mptAlice.set( + {.account = alice, .holder = bob, .auditorPubKey = mptAlice.getPubKey(alice), .err = temMALFORMED}); } // issuance has disabled confidential transfer @@ -257,24 +528,16 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | - tfMPTNoConfidentialTransfer}); + // no tfMPTCanPrivacy flag enabled + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.set( - {.account = alice, - .pubKey = mptAlice.getPubKey(alice), - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice), .err = tecNO_PERMISSION}); } } @@ -284,33 +547,23 @@ class ConfidentialTransfer_test : public beast::unit_test::suite testcase("Convert preclaim"); using namespace test::jtx; - // tfMPTNoConfidentialTransfer is set on issuance + // tfMPTCanPrivacy is not set on issuance { Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | - tfMPTNoConfidentialTransfer}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecNO_PERMISSION}); + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecNO_PERMISSION}); } // issuer has not uploaded their sfIssuerElGamalPublicKey @@ -320,25 +573,16 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecNO_PERMISSION}); + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecNO_PERMISSION}); } // issuance does not exist @@ -348,26 +592,18 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.destroy(); mptAlice.generateKeyPair(bob); mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecOBJECT_NOT_FOUND}); + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecOBJECT_NOT_FOUND}); } // bob has not created MPToken @@ -377,23 +613,47 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert( + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecOBJECT_NOT_FOUND}); + } + + // Verification of Issuer and and holder ciphertexts + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.convert( {.account = bob, .amt = 10, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), - .err = tecOBJECT_NOT_FOUND}); + .holderEncryptedAmt = getTrivialCiphertext(), + .err = tecBAD_PROOF}); + + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .issuerEncryptedAmt = getTrivialCiphertext(), + .err = tecBAD_PROOF}); } // trying to convert more than what bob has @@ -403,29 +663,19 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert( - {.account = bob, - .amt = 200, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecINSUFFICIENT_FUNDS}); + {.account = bob, .amt = 200, .holderPubKey = mptAlice.getPubKey(bob), .err = tecINSUFFICIENT_FUNDS}); } // holder cannot upload pk again @@ -435,36 +685,21 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.convert({.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob)}); // cannot upload pk again - mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecDUPLICATE}); + mptAlice.convert({.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecDUPLICATE}); } // cannot convert if locked @@ -474,39 +709,27 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); mptAlice.generateKeyPair(bob); mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecINSUFFICIENT_FUNDS}); + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecINSUFFICIENT_FUNDS}); - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); mptAlice.convert({ .account = bob, .amt = 10, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); } @@ -519,33 +742,23 @@ class ConfidentialTransfer_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth}); + {.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); // Unauthorize bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); mptAlice.convert( - {.account = bob, - .amt = 10, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tecINSUFFICIENT_FUNDS}); + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecINSUFFICIENT_FUNDS}); // auth bob mptAlice.authorize({ @@ -556,12 +769,124 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convert({ .account = bob, .amt = 10, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); } - // todo: test well formed proof + // cannot convert if auditor key is set, but auditor amount is not + // provided + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(auditor); + + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + + // no auditor encrypted amt provided + mptAlice.convert( + {.account = bob, + .amt = 10, + .fillAuditorEncryptedAmt = false, + .holderPubKey = mptAlice.getPubKey(bob), + .err = tecNO_PERMISSION}); + } + + // cannot convert if tx include auditor ciphertext, but does not have + // auditing enabled + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + // there is no auditor key set + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .auditorEncryptedAmt = getTrivialCiphertext(), + .err = tecNO_PERMISSION}); + } + + // Auditor key set successfully, auditor ciphertext mathematically + // correct, but contains invalid data (mismatching amount). + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor}); + + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(auditor); + + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + + mptAlice.convert( + {.account = bob, + .amt = 10, + .holderPubKey = mptAlice.getPubKey(bob), + .auditorEncryptedAmt = getTrivialCiphertext(), + .err = tecBAD_PROOF}); + } + + // invalid proof when registering holder pub key + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert( + {.account = bob, + .amt = 10, + .proof = std::string(ecSchnorrProofLength * 2, 'A'), + .holderPubKey = mptAlice.getPubKey(bob), + .err = tecBAD_PROOF}); + } } void @@ -574,26 +899,20 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -612,26 +931,20 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -656,16 +969,12 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.destroy(); mptAlice.generateKeyPair(bob); @@ -673,23 +982,17 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.mergeInbox({.account = bob, .err = tecOBJECT_NOT_FOUND}); } - // tfMPTNoConfidentialTransfer is set on issuance + // tfMPTCanPrivacy is not set on issuance { Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | - tfMPTNoConfidentialTransfer}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); @@ -704,15 +1007,11 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.mergeInbox({.account = bob, .err = tecOBJECT_NOT_FOUND}); } @@ -724,20 +1023,14 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); @@ -756,10 +1049,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -771,49 +1061,18 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // Convert 60 out of 100 - mptAlice.convert( - {.account = bob, - .amt = 60, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tesSUCCESS}); - - BEAST_EXPECT(mptAlice.getBalance(bob) == 40); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - bob, MPTTester::HOLDER_ENCRYPTED_INBOX) == 60); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - bob, MPTTester::HOLDER_ENCRYPTED_SPENDING) == 0); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - bob, MPTTester::ISSUER_ENCRYPTED_BALANCE) == 60); + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); // bob merge inbox mptAlice.mergeInbox({ .account = bob, }); - mptAlice.convert( - {.account = carol, - .amt = 20, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(carol), - .err = tesSUCCESS}); - - BEAST_EXPECT(mptAlice.getBalance(carol) == 30); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - carol, MPTTester::HOLDER_ENCRYPTED_INBOX) == 20); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - carol, MPTTester::HOLDER_ENCRYPTED_SPENDING) == 0); - BEAST_EXPECT( - mptAlice.getDecryptedBalance( - carol, MPTTester::ISSUER_ENCRYPTED_BALANCE) == 20); + // carol convert 20 to confidential + mptAlice.convert({.account = carol, .amt = 20, .holderPubKey = mptAlice.getPubKey(carol)}); // carol merge inbox mptAlice.mergeInbox({ @@ -821,38 +1080,94 @@ class ConfidentialTransfer_test : public beast::unit_test::suite }); // bob sends 10 to carol - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, // will be encrypted internally - .proof = "123", - .err = tesSUCCESS}); + mptAlice.send({ + .account = bob, + .dest = carol, + .amt = 10, + }); // bob sends 1 to carol again - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 1, - .proof = "123", - .err = tesSUCCESS}); + mptAlice.send({ + .account = bob, + .dest = carol, + .amt = 1, + }); mptAlice.mergeInbox({ .account = carol, }); // carol sends 15 backto bob - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 15, - .proof = "123", - .err = tesSUCCESS}); + mptAlice.send({ + .account = carol, + .dest = bob, + .amt = 15, + }); + } + + void + testSendWithAuditor(FeatureBitset features) + { + testcase("test confidential send with auditor"); + using namespace test::jtx; + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 100); + mptAlice.pay(alice, carol, 50); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + mptAlice.generateKeyPair(auditor); + + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + + // Convert 60 out of 100 + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); + + // bob merge inbox + mptAlice.mergeInbox({ + .account = bob, + }); + + mptAlice.convert({.account = carol, .amt = 20, .holderPubKey = mptAlice.getPubKey(carol)}); + + // carol merge inbox + mptAlice.mergeInbox({ + .account = carol, + }); + + // bob sends 10 to carol + mptAlice.send({.account = bob, .dest = carol, .amt = 10}); + + // bob sends 1 to carol again + mptAlice.send({.account = bob, .dest = carol, .amt = 1}); + + mptAlice.mergeInbox({ + .account = carol, + }); + + // carol sends 15 backto bob + mptAlice.send({.account = carol, .dest = bob, .amt = 15}); } void testSendPreflight(FeatureBitset features) { - testcase("test ConfidentialSend Preflight"); + testcase("test ConfidentialMPTSend Preflight"); using namespace test::jtx; // test disabled @@ -866,19 +1181,14 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.create(); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); - env.close(); mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), + .senderEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), + .destEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), + .issuerEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), .err = temDISABLED}); } @@ -890,127 +1200,204 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create(); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.pay(alice, bob, 100); mptAlice.pay(alice, carol, 50); - env.close(); + + mptAlice.convert({ + .account = bob, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.convert({ + .account = carol, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(carol), + }); // issuer can not be the same as sender - mptAlice.send( - {.account = alice, - .dest = carol, - .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .err = temMALFORMED}); + mptAlice.send({.account = alice, .dest = carol, .amt = 10, .err = temMALFORMED}); // can not send to self - mptAlice.send( - {.account = bob, - .dest = bob, - .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .err = temMALFORMED}); + mptAlice.send({.account = bob, .dest = bob, .amt = 10, .err = temMALFORMED}); // sender encrypted amount wrong length mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = Buffer(10), - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), + .senderEncryptedAmt = makeZeroBuffer(10), .err = temBAD_CIPHERTEXT}); // dest encrypted amount wrong length mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = Buffer(10), - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), + .destEncryptedAmt = makeZeroBuffer(10), .err = temBAD_CIPHERTEXT}); // issuer encrypted amount wrong length mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = Buffer(10), + .issuerEncryptedAmt = makeZeroBuffer(10), .err = temBAD_CIPHERTEXT}); - auto const ciphertextHex = generatePlaceholderCiphertext(); - // sender encrypted amount malformed mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .destEncryptedAmt = ciphertextHex, - .issuerEncryptedAmt = ciphertextHex, + .proof = getTrivialSendProofHex(3), + .senderEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = temBAD_CIPHERTEXT}); // dest encrypted amount malformed mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = ciphertextHex, - .destEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), - .issuerEncryptedAmt = ciphertextHex, + .proof = getTrivialSendProofHex(3), + .destEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = temBAD_CIPHERTEXT}); // issuer encrypted amount malformed mptAlice.send( {.account = bob, .dest = carol, .amt = 10, - .proof = "123", - .senderEncryptedAmt = ciphertextHex, - .destEncryptedAmt = ciphertextHex, - .issuerEncryptedAmt = - Buffer(ripple::ecGamalEncryptedTotalLength), + .proof = getTrivialSendProofHex(3), + .issuerEncryptedAmt = makeZeroBuffer(ecGamalEncryptedTotalLength), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = temBAD_CIPHERTEXT}); - // todo: proof length check + // invalid proof length + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = std::string(10, 'A'), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), + .err = temMALFORMED}); + + // invalid amount Pedersen commitment length + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(3), + .amountCommitment = makeZeroBuffer(100), + .balanceCommitment = getTrivialCommitment(), + .err = temMALFORMED}); + + // invalid balance Pedersen commitment length + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(3), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = makeZeroBuffer(100), + .err = temMALFORMED}); + + // amount Pedersen commitment has correct length but invalid EC point data + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(3), + .amountCommitment = makeZeroBuffer(ecPedersenCommitmentLength), + .balanceCommitment = getTrivialCommitment(), + .err = temMALFORMED}); + + // balance Pedersen commitment has correct length but invalid EC point data + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(3), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = makeZeroBuffer(ecPedersenCommitmentLength), + .err = temMALFORMED}); + } + + // test bad ciphertext + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + mptAlice.generateKeyPair(auditor); + + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + mptAlice.pay(alice, bob, 100); + mptAlice.pay(alice, carol, 50); + + mptAlice.convert({ + .account = bob, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.convert({ + .account = carol, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(carol), + }); + + // auditor encrypted amount wrong length + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(4), + .auditorEncryptedAmt = makeZeroBuffer(10), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), + .err = temBAD_CIPHERTEXT}); + + // auditor encrypted amount (correct length, invalid data) + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(4), + .auditorEncryptedAmt = getBadCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), + .err = temBAD_CIPHERTEXT}); } } void testSendPreclaim(FeatureBitset features) { - testcase("test ConfidentialSend Preclaim"); + testcase("test ConfidentialMPTSend Preclaim"); using namespace test::jtx; Env env{*this, features}; @@ -1022,8 +1409,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave, eve}}); // authorize bob, carol, dave (not eve) - mptAlice.create( - {.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); mptAlice.authorize({.account = carol}); @@ -1034,28 +1420,16 @@ class ConfidentialTransfer_test : public beast::unit_test::suite // fund bob, carol (not dave or eve) mptAlice.pay(alice, bob, 100); mptAlice.pay(alice, carol, 50); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); mptAlice.generateKeyPair(dave); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); - env.close(); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // bob and carol convert some funds to confidential - mptAlice.convert( - {.account = bob, - .amt = 60, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tesSUCCESS}); - mptAlice.convert( - {.account = carol, - .amt = 20, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(carol), - .err = tesSUCCESS}); + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob), .err = tesSUCCESS}); + mptAlice.convert({.account = carol, .amt = 20, .holderPubKey = mptAlice.getPubKey(carol), .err = tesSUCCESS}); // bob and carol merge inbox mptAlice.mergeInbox({ @@ -1065,8 +1439,6 @@ class ConfidentialTransfer_test : public beast::unit_test::suite .account = carol, }); - auto const ciphertextHex = generatePlaceholderCiphertext(); - // issuance not found { Env env{*this, features}; @@ -1075,28 +1447,26 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create({.flags = tfMPTCanTransfer}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // destroy the issuance mptAlice.destroy(); - env.close(); Json::Value jv; jv[jss::Account] = bob.human(); jv[jss::Destination] = carol.human(); - jv[jss::TransactionType] = jss::ConfidentialSend; + jv[jss::TransactionType] = jss::ConfidentialMPTSend; jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); - - auto const encryptedAmt = strHex(ciphertextHex); - jv[sfSenderEncryptedAmount] = encryptedAmt; - jv[sfDestinationEncryptedAmount] = encryptedAmt; - jv[sfIssuerEncryptedAmount] = encryptedAmt; - jv[sfZKProof] = "123"; + jv[sfSenderEncryptedAmount] = strHex(getTrivialCiphertext()); + jv[sfDestinationEncryptedAmount] = strHex(getTrivialCiphertext()); + jv[sfIssuerEncryptedAmount] = strHex(getTrivialCiphertext()); + jv[sfAmountCommitment] = strHex(getTrivialCommitment()); + jv[sfBalanceCommitment] = strHex(getTrivialCommitment()); + jv[sfZKProof] = getTrivialSendProofHex(3); env(jv, ter(tecOBJECT_NOT_FOUND)); } @@ -1108,9 +1478,12 @@ class ConfidentialTransfer_test : public beast::unit_test::suite {.account = bob, .dest = unknown, .amt = 10, - .proof = "123", - .destEncryptedAmt = ciphertextHex, - .issuerEncryptedAmt = ciphertextHex, + .proof = getTrivialSendProofHex(3), + .senderEncryptedAmt = getTrivialCiphertext(), + .destEncryptedAmt = getTrivialCiphertext(), + .issuerEncryptedAmt = getTrivialCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = tecNO_TARGET}); } @@ -1120,13 +1493,23 @@ class ConfidentialTransfer_test : public beast::unit_test::suite {.account = bob, .dest = dave, .amt = 10, - .proof = "123", + .proof = getTrivialSendProofHex(3), + .senderEncryptedAmt = getTrivialCiphertext(), + .destEncryptedAmt = getTrivialCiphertext(), + .issuerEncryptedAmt = getTrivialCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = tecNO_PERMISSION}); mptAlice.send( {.account = dave, .dest = carol, .amt = 10, - .proof = "123", + .proof = getTrivialSendProofHex(3), + .senderEncryptedAmt = getTrivialCiphertext(), + .destEncryptedAmt = getTrivialCiphertext(), + .issuerEncryptedAmt = getTrivialCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = tecNO_PERMISSION}); } @@ -1136,8 +1519,12 @@ class ConfidentialTransfer_test : public beast::unit_test::suite {.account = bob, .dest = eve, .amt = 10, - .proof = "123", - .destEncryptedAmt = ciphertextHex, + .proof = getTrivialSendProofHex(3), + .senderEncryptedAmt = getTrivialCiphertext(), + .destEncryptedAmt = getTrivialCiphertext(), + .issuerEncryptedAmt = getTrivialCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), .err = tecOBJECT_NOT_FOUND}); } @@ -1145,96 +1532,61 @@ class ConfidentialTransfer_test : public beast::unit_test::suite { // lock issuance mptAlice.set({.account = alice, .flags = tfMPTLock}); - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, - .proof = "123", - .err = tecLOCKED}); + mptAlice.send({.account = bob, .dest = carol, .amt = 10, .err = tecLOCKED}); // unlock issuance mptAlice.set({.account = alice, .flags = tfMPTUnlock}); // now can send - mptAlice.send( - {.account = bob, .dest = carol, .amt = 1, .proof = "123"}); + mptAlice.send({.account = bob, .dest = carol, .amt = 1}); } // sender is locked { // lock bob mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, - .proof = "123", - .err = tecLOCKED}); + mptAlice.send({.account = bob, .dest = carol, .amt = 10, .err = tecLOCKED}); // unlock bob - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); // now can send - mptAlice.send( - {.account = bob, .dest = carol, .amt = 2, .proof = "123"}); + mptAlice.send({.account = bob, .dest = carol, .amt = 2}); } // destination is locked { // lock carol - mptAlice.set( - {.account = alice, .holder = carol, .flags = tfMPTLock}); - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, - .proof = "123", - .err = tecLOCKED}); + mptAlice.set({.account = alice, .holder = carol, .flags = tfMPTLock}); + mptAlice.send({.account = bob, .dest = carol, .amt = 10, .err = tecLOCKED}); // unlock carol - mptAlice.set( - {.account = alice, .holder = carol, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = carol, .flags = tfMPTUnlock}); // now can send - mptAlice.send( - {.account = bob, .dest = carol, .amt = 3, .proof = "123"}); + mptAlice.send({.account = bob, .dest = carol, .amt = 3}); } // sender not authorized { // unauthorize bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, - .proof = "123", - .err = tecNO_AUTH}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.send({.account = bob, .dest = carol, .amt = 10, .err = tecNO_AUTH}); // authorize bob again mptAlice.authorize({ .account = alice, .holder = bob, }); // now can send - mptAlice.send( - {.account = bob, .dest = carol, .amt = 4, .proof = "123"}); + mptAlice.send({.account = bob, .dest = carol, .amt = 4}); } // destination not authorized { // unauthorize carol - mptAlice.authorize( - {.account = alice, .holder = carol, .flags = tfMPTUnauthorize}); - mptAlice.send( - {.account = bob, - .dest = carol, - .amt = 10, - .proof = "123", - .err = tecNO_AUTH}); + mptAlice.authorize({.account = alice, .holder = carol, .flags = tfMPTUnauthorize}); + mptAlice.send({.account = bob, .dest = carol, .amt = 10, .err = tecNO_AUTH}); // authorize carol again mptAlice.authorize({ .account = alice, .holder = carol, }); // now can send - mptAlice.send( - {.account = bob, .dest = carol, .amt = 5, .proof = "123"}); + mptAlice.send({.account = bob, .dest = carol, .amt = 5}); } // cannot send when MPTCanTransfer is not set @@ -1245,8 +1597,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1258,16 +1609,10 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // Convert 60 out of 100 - mptAlice.convert( - {.account = bob, - .amt = 60, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tesSUCCESS}); + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob), .err = tesSUCCESS}); // bob merge inbox mptAlice.mergeInbox({ @@ -1275,11 +1620,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite }); mptAlice.convert( - {.account = carol, - .amt = 20, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(carol), - .err = tesSUCCESS}); + {.account = carol, .amt = 20, .holderPubKey = mptAlice.getPubKey(carol), .err = tesSUCCESS}); // carol merge inbox mptAlice.mergeInbox({ @@ -1291,9 +1632,171 @@ class ConfidentialTransfer_test : public beast::unit_test::suite {.account = bob, .dest = carol, .amt = 10, // will be encrypted internally - .proof = "123", .err = tecNO_AUTH}); } + + // bad proof + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanPrivacy | tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 100); + mptAlice.pay(alice, carol, 50); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob), .err = tesSUCCESS}); + + mptAlice.mergeInbox({ + .account = bob, + }); + + mptAlice.convert( + {.account = carol, .amt = 20, .holderPubKey = mptAlice.getPubKey(carol), .err = tesSUCCESS}); + + mptAlice.mergeInbox({ + .account = carol, + }); + + mptAlice.send( + {.account = bob, .dest = carol, .amt = 10, .proof = getTrivialSendProofHex(3), .err = tecBAD_PROOF}); + } + + // No Auditor key set, but auditor encrypted amt provided + { + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(4), + .auditorEncryptedAmt = getTrivialCiphertext(), + .err = tecNO_PERMISSION}); + } + + // Auditor CipherText is Valid, but does not match the Txn Amount + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + mptAlice.generateKeyPair(auditor); + + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + mptAlice.pay(alice, bob, 100); + mptAlice.pay(alice, carol, 50); + + mptAlice.convert({ + .account = bob, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.convert({ + .account = carol, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(carol), + }); + + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(4), + .auditorEncryptedAmt = getTrivialCiphertext(), + .amountCommitment = getTrivialCommitment(), + .balanceCommitment = getTrivialCommitment(), + .err = tecBAD_PROOF}); + } + } + + void + testSendRangeProof(FeatureBitset features) + { + testcase("test ConfidentialMPTSend Range Proof"); + + using namespace test::jtx; + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanPrivacy | tfMPTCanTransfer}); + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 1000); + mptAlice.pay(alice, carol, 1000); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + { + // Bob converts 60 + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.mergeInbox({.account = bob}); + + mptAlice.convert({.account = carol, .amt = 50, .holderPubKey = mptAlice.getPubKey(carol)}); + mptAlice.mergeInbox({.account = carol}); + + // Bob has 60, tries to send 70. Invalid remaining balance. + mptAlice.send({.account = bob, .dest = carol, .amt = 70, .err = tecBAD_PROOF}); + + // Bob has 60, tries to send 61. Invalid remaining balance. + mptAlice.send({.account = bob, .dest = carol, .amt = 61, .err = tecBAD_PROOF}); + + // Bob has 60, sends 60. Remainder is exactly 0. Valid remaining balance. + mptAlice.send({.account = bob, .dest = carol, .amt = 60, .err = tesSUCCESS}); + } + + { + // Bob converts 100. + mptAlice.convert({.account = bob, .amt = 100}); + mptAlice.mergeInbox({.account = bob}); + + // Bob has 100, tries to send 2^64-1. Invalid remaining balance. + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 0xFFFFFFFFFFFFFFFF, // Max uint64 + .err = tecBAD_PROOF}); + + // Bob sends 1, remaining 99. + mptAlice.send({.account = bob, .dest = carol, .amt = 1, .err = tesSUCCESS}); + + // Bob sends 100, but only has 99. Invalid remaining balance. + mptAlice.send({.account = bob, .dest = carol, .amt = 100, .err = tecBAD_PROOF}); + } + + // todo: test m exceeding range, require using scala and refactor } void @@ -1309,34 +1812,24 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 100, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); - mptAlice.authorize( - {.account = bob, - .flags = tfMPTUnauthorize, - .err = tecHAS_OBLIGATIONS}); + mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize, .err = tecHAS_OBLIGATIONS}); } // cannot delete mptoken where it has encrypted balance @@ -1347,21 +1840,15 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); @@ -1369,22 +1856,17 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convert({ .account = bob, .amt = 100, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); mptAlice.convert({ .account = carol, .amt = 0, - .proof = "123", .holderPubKey = mptAlice.getPubKey(carol), }); // carol cannot delete even if he has encrypted zero amount - mptAlice.authorize( - {.account = carol, - .flags = tfMPTUnauthorize, - .err = tecHAS_OBLIGATIONS}); + mptAlice.authorize({.account = carol, .flags = tfMPTUnauthorize, .err = tecHAS_OBLIGATIONS}); } // can delete mptoken if outstanding confidential balance is zero @@ -1394,26 +1876,18 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - - env.close(); - mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 0, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -1423,34 +1897,26 @@ class ConfidentialTransfer_test : public beast::unit_test::suite }); } - // can delete mptoken if issuance has been destroyed and has encrypted - // zero balance + // can delete mptoken if issuance has been destroyed and has + // encrypted zero balance { Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - - env.close(); - mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 0, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -1461,7 +1927,43 @@ class ConfidentialTransfer_test : public beast::unit_test::suite .flags = tfMPTUnauthorize, }); } - // todo: test with convert back and delete + // test with convert back and delete + // can delete mptoken if converted back (COA returns to zero) + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 100, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.mergeInbox({ + .account = bob, + }); + + mptAlice.convertBack({.account = bob, .amt = 100}); + + mptAlice.pay(bob, alice, 100); + + // Should be able to delete as Confidential Outstanding amount is 0 + mptAlice.authorize({ + .account = bob, + .flags = tfMPTUnauthorize, + }); + } } void @@ -1469,31 +1971,219 @@ class ConfidentialTransfer_test : public beast::unit_test::suite { testcase("Convert back"); using namespace test::jtx; + + // Basic convert back test + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.mergeInbox({ + .account = bob, + }); + + mptAlice.convertBack({ + .account = bob, + .amt = 30, + }); + + mptAlice.convertBack({ + .account = bob, + .amt = 10, + }); + } + + // Edge case: minimum amount (1) + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 2); + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 2, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.mergeInbox({ + .account = bob, + }); + + mptAlice.convertBack({ + .account = bob, + .amt = 1, + }); + } + + // Edge case: maxMPTokenAmount + // Using raw JSON to avoid automatic decryption checks in MPTTester + // which don't work for very large amounts (brute-force decryption is slow) + // TODO: improve this test once there is bounded decryption or optimized decryption for large amounts + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, maxMPTokenAmount); + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + // Convert maxMPTokenAmount to confidential using raw JSON + Buffer const convertBlindingFactor = generateBlindingFactor(); + auto const convertHolderCiphertext = mptAlice.encryptAmount(bob, maxMPTokenAmount, convertBlindingFactor); + auto const convertIssuerCiphertext = mptAlice.encryptAmount(alice, maxMPTokenAmount, convertBlindingFactor); + auto const convertContextHash = + getConvertContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), maxMPTokenAmount); + auto const schnorrProof = mptAlice.getSchnorrProof(bob, convertContextHash); + BEAST_EXPECT(schnorrProof.has_value()); + + { + Json::Value jv; + jv[jss::Account] = bob.human(); + jv[jss::TransactionType] = jss::ConfidentialMPTConvert; + jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); + jv[sfMPTAmount.jsonName] = std::to_string(maxMPTokenAmount); + jv[sfHolderElGamalPublicKey.jsonName] = strHex(*mptAlice.getPubKey(bob)); + jv[sfHolderEncryptedAmount.jsonName] = strHex(convertHolderCiphertext); + jv[sfIssuerEncryptedAmount.jsonName] = strHex(convertIssuerCiphertext); + jv[sfBlindingFactor.jsonName] = strHex(convertBlindingFactor); + jv[sfZKProof.jsonName] = strHex(*schnorrProof); + + env(jv, ter(tesSUCCESS)); + } + + // Merge inbox using raw JSON - moves funds from inbox to spending balance + { + Json::Value jv; + jv[jss::Account] = bob.human(); + jv[jss::TransactionType] = jss::ConfidentialMPTMergeInbox; + jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); + + env(jv, ter(tesSUCCESS)); + } + + // ConvertBack maxMPTokenAmount - 1 using raw JSON + // After convert + merge, spending balance = maxMPTokenAmount + // We convert back maxMPTokenAmount - 1 to leave remainder of 1 + std::uint64_t const convertBackAmt = maxMPTokenAmount - 1; + + Buffer const convertBackBlindingFactor = generateBlindingFactor(); + auto const convertBackHolderCiphertext = + mptAlice.encryptAmount(bob, convertBackAmt, convertBackBlindingFactor); + auto const convertBackIssuerCiphertext = + mptAlice.encryptAmount(alice, convertBackAmt, convertBackBlindingFactor); + + // Get the encrypted spending balance from ledger (no decryption needed) + auto const encryptedSpendingBalance = + mptAlice.getEncryptedBalance(bob, MPTTester::HOLDER_ENCRYPTED_SPENDING); + BEAST_EXPECT(encryptedSpendingBalance.has_value()); + + // Generate pedersen commitment for the known spending balance + Buffer const pcBlindingFactor = generateBlindingFactor(); + Buffer const pedersenCommitment = mptAlice.getPedersenCommitment(maxMPTokenAmount, pcBlindingFactor); + + // Generate the proof using known spending balance value + auto const version = mptAlice.getMPTokenVersion(bob); + uint256 const convertBackContextHash = + getConvertBackContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), convertBackAmt, version); + + Buffer const proof = mptAlice.getConvertBackProof( + bob, + convertBackAmt, + convertBackContextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = maxMPTokenAmount, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + { + Json::Value jv; + jv[jss::Account] = bob.human(); + jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack; + jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); + jv[sfMPTAmount.jsonName] = std::to_string(convertBackAmt); + jv[sfHolderEncryptedAmount.jsonName] = strHex(convertBackHolderCiphertext); + jv[sfIssuerEncryptedAmount.jsonName] = strHex(convertBackIssuerCiphertext); + jv[sfBlindingFactor.jsonName] = strHex(convertBackBlindingFactor); + jv[sfBalanceCommitment.jsonName] = strHex(pedersenCommitment); + jv[sfZKProof.jsonName] = strHex(proof); + + env(jv, ter(tesSUCCESS)); + } + + // Verify the public balance was restored (minus 1 remaining in confidential) + env.require(mptbalance(mptAlice, bob, convertBackAmt)); + } + } + + void + testConvertBackWithAuditor(FeatureBitset features) + { + testcase("Convert back with auditor"); + using namespace test::jtx; + Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); - MPTTester mptAlice(env, alice, {.holders = {bob}}); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(auditor); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -1504,14 +2194,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convertBack({ .account = bob, .amt = 30, - .proof = "123", }); - - // mptAlice.convertBack({ - // .account = bob, - // .amt = 10, - // .proof = "123", - // }); } void @@ -1526,24 +2209,15 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .err = temDISABLED}); + mptAlice.convertBack({.account = bob, .amt = 30, .err = temDISABLED}); } { @@ -1552,27 +2226,20 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -1580,53 +2247,42 @@ class ConfidentialTransfer_test : public beast::unit_test::suite .account = bob, }); + mptAlice.convertBack({.account = alice, .amt = 30, .err = temMALFORMED}); + + mptAlice.convertBack({.account = bob, .amt = 0, .err = temBAD_AMOUNT}); + + mptAlice.convertBack({.account = bob, .amt = maxMPTokenAmount + 1, .err = temBAD_AMOUNT}); + + // invalid blinding factor length + mptAlice.convertBack({.account = alice, .amt = 30, .blindingFactor = Buffer{}, .err = temMALFORMED}); + + // Balance commitment has correct length but invalid EC point data mptAlice.convertBack( - {.account = alice, + {.account = bob, .amt = 30, - .proof = "123", + .pedersenCommitment = makeZeroBuffer(ecPedersenCommitmentLength), .err = temMALFORMED}); - mptAlice.convertBack( - {.account = bob, - .amt = 0, - .proof = "123", - .err = temBAD_AMOUNT}); + mptAlice.convertBack({.account = bob, .amt = 30, .holderEncryptedAmt = Buffer{}, .err = temBAD_CIPHERTEXT}); + + mptAlice.convertBack({.account = bob, .amt = 30, .issuerEncryptedAmt = Buffer{}, .err = temBAD_CIPHERTEXT}); mptAlice.convertBack( - {.account = bob, - .amt = maxMPTokenAmount + 1, - .proof = "123", - .err = temBAD_AMOUNT}); + {.account = bob, .amt = 30, .holderEncryptedAmt = getBadCiphertext(), .err = temBAD_CIPHERTEXT}); mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .holderEncryptedAmt = Buffer{}, - .err = temBAD_CIPHERTEXT}); + {.account = bob, .amt = 30, .issuerEncryptedAmt = getBadCiphertext(), .err = temBAD_CIPHERTEXT}); mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .issuerEncryptedAmt = Buffer{}, - .err = temBAD_CIPHERTEXT}); + {.account = bob, .amt = 30, .auditorEncryptedAmt = makeZeroBuffer(10), .err = temBAD_CIPHERTEXT}); mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .holderEncryptedAmt = - Buffer{badCiphertext, ecGamalEncryptedTotalLength}, - .err = temBAD_CIPHERTEXT}); + {.account = bob, .amt = 30, .auditorEncryptedAmt = getBadCiphertext(), .err = temBAD_CIPHERTEXT}); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .issuerEncryptedAmt = - Buffer{badCiphertext, ecGamalEncryptedTotalLength}, - .err = temBAD_CIPHERTEXT}); + // invalid proof length + mptAlice.convertBack({.account = bob, .amt = 30, .proof = Buffer{}, .err = temMALFORMED}); + + mptAlice.convertBack({.account = bob, .amt = 30, .proof = makeZeroBuffer(100), .err = temMALFORMED}); } } @@ -1643,53 +2299,35 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.destroy(); mptAlice.generateKeyPair(bob); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .err = tecOBJECT_NOT_FOUND}); + mptAlice.convertBack({.account = bob, .amt = 30, .err = tecOBJECT_NOT_FOUND}); } - // tfMPTNoConfidentialTransfer is set on issuance + // tfMPTCanPrivacy is not set on issuance { Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | - tfMPTNoConfidentialTransfer}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.convertBack({.account = bob, .amt = 30, .err = tecNO_PERMISSION}); } // no mptoken @@ -1699,22 +2337,14 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .err = tecOBJECT_NOT_FOUND}); + mptAlice.convertBack({.account = bob, .amt = 30, .err = tecOBJECT_NOT_FOUND}); } // bob doesn't have encrypted balances @@ -1724,28 +2354,18 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); - mptAlice.convertBack( - {.account = bob, - .amt = 30, - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.convertBack({.account = bob, .amt = 30, .err = tecNO_PERMISSION}); } // bob tries to convert back more than COA @@ -1756,22 +2376,16 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); - env.close(); mptAlice.pay(alice, bob, 100); mptAlice.pay(alice, carol, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); @@ -1779,7 +2393,6 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); @@ -1790,15 +2403,10 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convert({ .account = carol, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(carol), }); - mptAlice.convertBack( - {.account = bob, - .amt = 300, - .proof = "123", - .err = tecINSUFFICIENT_FUNDS}); + mptAlice.convertBack({.account = bob, .amt = 300, .err = tecINSUFFICIENT_FUNDS}); } // cannot convert if locked or unauth @@ -1809,45 +2417,38 @@ class ConfidentialTransfer_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth}); + {.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); - env.close(); mptAlice.pay(alice, bob, 100); - env.close(); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.generateKeyPair(bob); mptAlice.convert({ .account = bob, .amt = 40, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); mptAlice.mergeInbox({.account = bob}); mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); - mptAlice.convertBack( - {.account = bob, .amt = 10, .proof = "123", .err = tecLOCKED}); + mptAlice.convertBack({.account = bob, .amt = 10, .err = tecLOCKED}); - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); - mptAlice.convertBack({.account = bob, .amt = 10, .proof = "123"}); + mptAlice.convertBack({ + .account = bob, + .amt = 10, + }); - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); - mptAlice.convertBack( - {.account = bob, .amt = 10, .proof = "123", .err = tecNO_AUTH}); + mptAlice.convertBack({.account = bob, .amt = 10, .err = tecNO_AUTH}); mptAlice.authorize({ .account = alice, @@ -1857,9 +2458,107 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.convertBack({ .account = bob, .amt = 10, - .proof = "123", }); } + + // Verification of holder and issuer ciphertexts during convertBack + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.convert({.account = bob, .amt = 50, .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.mergeInbox({.account = bob}); + + // Holder encrypted amount is valid format but mathematically incorrect for this convertBack + mptAlice.convertBack( + {.account = bob, .amt = 10, .holderEncryptedAmt = getTrivialCiphertext(), .err = tecBAD_PROOF}); + + // Issuer encrypted amount is valid format but mathematically incorrect for this convertBack + mptAlice.convertBack( + {.account = bob, .amt = 10, .issuerEncryptedAmt = getTrivialCiphertext(), .err = tecBAD_PROOF}); + } + + // Alice has NOT set an auditor key, but Bob provides + // auditorEncryptedAmt + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + // Bob converts funds to confidential so he has something to convert + // back + mptAlice.convert({.account = bob, .amt = 50, .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.mergeInbox({.account = bob}); + + mptAlice.convertBack( + {.account = bob, + .amt = 10, + // Provide valid ciphertext to pass preflight + .auditorEncryptedAmt = getTrivialCiphertext(), + .err = tecNO_PERMISSION}); + } + + // we set the auditor key, but convertBack omits auditorEncryptedAmt + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor}); + + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(auditor); + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + + // Convert funds so Bob has a balance + mptAlice.convert({ + .account = bob, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(bob), + }); + mptAlice.mergeInbox({.account = bob}); + + // ConvertBack WITHOUT auditorEncryptedAmt + mptAlice.convertBack({ + .account = bob, + .amt = 10, + .fillAuditorEncryptedAmt = false, + .err = tecNO_PERMISSION, + }); + + // ConvertBack where auditor ciphertext mathematically + // correct, but contains invalid data (mismatching amount). + mptAlice.convertBack( + {.account = bob, .amt = 10, .auditorEncryptedAmt = getTrivialCiphertext(), .err = tecBAD_PROOF}); + } } void @@ -1871,20 +2570,17 @@ class ConfidentialTransfer_test : public beast::unit_test::suite using namespace std::chrono; - Account const alice("alice"); // issuer - Account const bob("bob"); // holder + Account const alice("alice"); + Account const bob("bob"); Account const carol("carol"); - Account const dpIssuer("dpIssuer"); // holder + Account const dpIssuer("dpIssuer"); env.fund(XRP(50000), dpIssuer); env.close(); char const credType[] = "abcde"; MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1896,24 +2592,22 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // Bob require preauthorization env(fset(bob, asfDepositAuth)); env.close(); - mptAlice.convert( - {.account = carol, - .amt = 50, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(carol), - .err = tesSUCCESS}); - mptAlice.convert( - {.account = bob, - .amt = 50, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob), - .err = tesSUCCESS}); + mptAlice.convert({ + .account = carol, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(carol), + }); + mptAlice.convert({ + .account = bob, + .amt = 50, + .holderPubKey = mptAlice.getPubKey(bob), + }); // carol merge inbox mptAlice.mergeInbox({ @@ -1926,23 +2620,13 @@ class ConfidentialTransfer_test : public beast::unit_test::suite }); // carol sends 10 to bob, but not authorized - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.send({.account = carol, .dest = bob, .amt = 10, .err = tecNO_PERMISSION}); // Bob authorize alice env(deposit::auth(bob, carol)); env.close(); - mptAlice.send({ - .account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - }); + mptAlice.send({.account = carol, .dest = bob, .amt = 10}); // Create credentials env(credentials::create(bob, dpIssuer, credType)); @@ -1952,48 +2636,26 @@ class ConfidentialTransfer_test : public beast::unit_test::suite auto const jv = credentials::ledgerEntry(env, bob, dpIssuer, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - .credentials = {{credIdx}}}); + mptAlice.send({.account = carol, .dest = bob, .amt = 10, .credentials = {{credIdx}}}); // Bob revoke authorization env(deposit::unauth(bob, carol)); env.close(); - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.send({.account = carol, .dest = bob, .amt = 10, .err = tecNO_PERMISSION}); - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - .credentials = {{credIdx}}, - .err = tecNO_PERMISSION}); + mptAlice.send({.account = carol, .dest = bob, .amt = 10, .credentials = {{credIdx}}, .err = tecNO_PERMISSION}); // Bob authorize credentials env(deposit::authCredentials(bob, {{dpIssuer, credType}})); env.close(); - mptAlice.send( - {.account = carol, - .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.send({.account = carol, .dest = bob, .amt = 10, .err = tecNO_PERMISSION}); mptAlice.send({ .account = carol, .dest = bob, - .amt = 10, // will be encrypted internally - .proof = "123", + .amt = 10, .credentials = {{credIdx}}, }); } @@ -2001,7 +2663,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite void testClawback(FeatureBitset features) { - testcase("test ConfidentialClawback"); + testcase("test ConfidentialMPTClawback"); using namespace test::jtx; Env env{*this, features}; @@ -2011,8 +2673,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const dave("dave"); MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}}); - mptAlice.create( - {.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); mptAlice.authorize({.account = carol}); @@ -2024,17 +2685,13 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); mptAlice.generateKeyPair(dave); - mptAlice.set({.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // setup bob. // after setup, bob's spending balance is 60, inbox balance is 0. { // bob converts 60 to confidential - mptAlice.convert( - {.account = bob, - .amt = 60, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); // bob merge inbox mptAlice.mergeInbox({ @@ -2046,11 +2703,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite // after setup, carol's spending balance is 120, inbox balance is 0. { // carol converts 120 to confidential - mptAlice.convert( - {.account = carol, - .amt = 120, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(carol)}); + mptAlice.convert({.account = carol, .amt = 120, .holderPubKey = mptAlice.getPubKey(carol)}); // carol merge inbox mptAlice.mergeInbox({ @@ -2061,40 +2714,115 @@ class ConfidentialTransfer_test : public beast::unit_test::suite // setup dave. // dave will not merge inbox. // after setup, dave's inbox balance is 200, spending balance is 0. - mptAlice.convert( - {.account = dave, - .amt = 200, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(dave)}); + mptAlice.convert({.account = dave, .amt = 200, .holderPubKey = mptAlice.getPubKey(dave)}); // setup: carol confidential send 50 to bob. - // after send, bob's inbox balance is 50, spending balance remains 60. - // carol's inbox balance remains 0, spending balance drops to 70. - mptAlice.send( - {.account = carol, .dest = bob, .amt = 50, .proof = "123"}); + // after send, bob's inbox balance is 50, spending balance + // remains 60. carol's inbox balance remains 0, spending balance + // drops to 70. + mptAlice.send({.account = carol, .dest = bob, .amt = 50}); // alice clawback all confidential balance from bob, 110 in total. // bob has balance in both inbox and spending. These balances should - // become zero after clawback, which is verified in the confidentialClaw - // function. - mptAlice.confidentialClaw( - {.account = alice, .holder = bob, .amt = 110, .proof = "123"}); + // become zero after clawback, which is verified in the + // confidentialClaw function. + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 110}); // alice clawback all confidential balance from carol, which is 70. // carol only has balance in spending. - mptAlice.confidentialClaw( - {.account = alice, .holder = carol, .amt = 70, .proof = "123"}); + mptAlice.confidentialClaw({.account = alice, .holder = carol, .amt = 70}); // alice clawback all confidential balance from dave, which is 200. // dave only has balance in inbox. - mptAlice.confidentialClaw( - {.account = alice, .holder = dave, .amt = 200, .proof = "123"}); + mptAlice.confidentialClaw({.account = alice, .holder = dave, .amt = 200}); + } + + void + testClawbackWithAuditor(FeatureBitset features) + { + testcase("test ConfidentialMPTClawback with auditor"); + using namespace test::jtx; + + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const dave("dave"); + Account const auditor("auditor"); + MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}, .auditor = auditor}); + + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + mptAlice.authorize({.account = carol}); + mptAlice.pay(alice, carol, 200); + mptAlice.authorize({.account = dave}); + mptAlice.pay(alice, dave, 300); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.generateKeyPair(carol); + mptAlice.generateKeyPair(dave); + mptAlice.generateKeyPair(auditor); + mptAlice.set( + {.account = alice, + .issuerPubKey = mptAlice.getPubKey(alice), + .auditorPubKey = mptAlice.getPubKey(auditor)}); + + // setup bob. + // after setup, bob's spending balance is 60, inbox balance is 0. + { + // bob converts 60 to confidential + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); + + // bob merge inbox + mptAlice.mergeInbox({ + .account = bob, + }); + } + + // setup carol. + // after setup, carol's spending balance is 120, inbox balance is 0. + { + // carol converts 120 to confidential + mptAlice.convert({.account = carol, .amt = 120, .holderPubKey = mptAlice.getPubKey(carol)}); + + // carol merge inbox + mptAlice.mergeInbox({ + .account = carol, + }); + } + + // setup dave. + // dave will not merge inbox. + // after setup, dave's inbox balance is 200, spending balance is 0. + mptAlice.convert({.account = dave, .amt = 200, .holderPubKey = mptAlice.getPubKey(dave)}); + + // setup: carol confidential send 50 to bob. + // after send, bob's inbox balance is 50, spending balance + // remains 60. carol's inbox balance remains 0, spending balance + // drops to 70. + mptAlice.send({.account = carol, .dest = bob, .amt = 50}); + + // alice clawback all confidential balance from bob, 110 in total. + // bob has balance in both inbox and spending. These balances should + // become zero after clawback, which is verified in the + // confidentialClaw function. + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 110}); + + // alice clawback all confidential balance from carol, which is 70. + // carol only has balance in spending. + mptAlice.confidentialClaw({.account = alice, .holder = carol, .amt = 70}); + + // alice clawback all confidential balance from dave, which is 200. + // dave only has balance in inbox. + mptAlice.confidentialClaw({.account = alice, .holder = dave, .amt = 200}); } void testClawbackPreflight(FeatureBitset features) { - testcase("test ConfidentialClawback Preflight"); + testcase("test ConfidentialMPTClawback Preflight"); using namespace test::jtx; // test feature disabled @@ -2106,14 +2834,8 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.create(); mptAlice.authorize({.account = bob}); - env.close(); - mptAlice.confidentialClaw( - {.account = alice, - .holder = bob, - .amt = 10, - .proof = "123", - .err = temDISABLED}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 10, .proof = "123", .err = temDISABLED}); } // test malformed @@ -2125,59 +2847,44 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const carol("carol"); MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create(); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.pay(alice, bob, 100); mptAlice.pay(alice, carol, 50); - env.close(); // only issuer can clawback - mptAlice.confidentialClaw( - {.account = carol, - .holder = bob, - .amt = 10, - .proof = "123", - .err = temMALFORMED}); + mptAlice.confidentialClaw({.account = carol, .holder = bob, .amt = 10, .err = temMALFORMED}); // invalid issuance ID, whose issuer is not alice { Json::Value jv; jv[jss::Account] = alice.human(); jv[sfHolder] = bob.human(); - jv[jss::TransactionType] = jss::ConfidentialClawback; + jv[jss::TransactionType] = jss::ConfidentialMPTClawback; jv[sfMPTAmount] = std::to_string(10); jv[sfZKProof] = "123"; // wrong issuance ID - jv[sfMPTokenIssuanceID] = - "00000004AE123A8556F3CF91154711376AFB0F894F832B3E"; + jv[sfMPTokenIssuanceID] = "00000004AE123A8556F3CF91154711376AFB0F894F832B3E"; env(jv, ter(temMALFORMED)); } // issuer cannot clawback from self - mptAlice.confidentialClaw( - {.account = alice, - .holder = alice, - .amt = 10, - .proof = "123", - .err = temMALFORMED}); + mptAlice.confidentialClaw({.account = alice, .holder = alice, .amt = 10, .err = temMALFORMED}); // invalid amount - mptAlice.confidentialClaw( - {.account = alice, - .holder = bob, - .amt = 0, - .proof = "123", - .err = temBAD_AMOUNT}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 0, .err = temBAD_AMOUNT}); - // todo: proof length check + // invalid proof length + mptAlice.confidentialClaw( + {.account = alice, .holder = bob, .amt = 10, .proof = "123", .err = temMALFORMED}); } } @@ -2189,8 +2896,8 @@ class ConfidentialTransfer_test : public beast::unit_test::suite { // set up, alice is the issuer, bob and carol are authorized - // holders. dave is not authorized. bob has confidential balance, - // carol does not. + // holders. dave is not authorized. bob has confidential + // balance, carol does not. Env env{*this, features}; Account const alice("alice"); Account const bob("bob"); @@ -2198,9 +2905,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const dave("dave"); MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}}); - mptAlice.create( - {.flags = - tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); mptAlice.authorize({.account = carol}); @@ -2211,13 +2916,11 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); mptAlice.generateKeyPair(carol); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); mptAlice.convert({ .account = bob, .amt = 60, - .proof = "123", .holderPubKey = mptAlice.getPubKey(bob), }); mptAlice.mergeInbox({ @@ -2227,32 +2930,17 @@ class ConfidentialTransfer_test : public beast::unit_test::suite // holder does not exist { Account const unknown("unknown"); - mptAlice.confidentialClaw( - {.account = alice, - .holder = unknown, - .amt = 10, - .proof = "123", - .err = tecNO_TARGET}); + mptAlice.confidentialClaw({.account = alice, .holder = unknown, .amt = 10, .err = tecNO_TARGET}); } // dave does not hold mpt at all, no MPT object { - mptAlice.confidentialClaw( - {.account = alice, - .holder = dave, - .amt = 10, - .proof = "123", - .err = tecOBJECT_NOT_FOUND}); + mptAlice.confidentialClaw({.account = alice, .holder = dave, .amt = 10, .err = tecOBJECT_NOT_FOUND}); } // carol has no confidential balance { - mptAlice.confidentialClaw( - {.account = alice, - .holder = carol, - .amt = 10, - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.confidentialClaw({.account = alice, .holder = carol, .amt = 10, .err = tecNO_PERMISSION}); } } @@ -2263,19 +2951,12 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create({.flags = tfMPTCanTransfer}); + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); - env.close(); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); - mptAlice.confidentialClaw( - {.account = alice, - .holder = bob, - .amt = 10, - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 10, .err = tecNO_PERMISSION}); } // no issuer key @@ -2284,17 +2965,11 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create({.flags = tfMPTCanClawback}); + mptAlice.create({.flags = tfMPTCanClawback | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - env.close(); - mptAlice.confidentialClaw( - {.account = alice, - .holder = bob, - .amt = 10, - .proof = "123", - .err = tecNO_PERMISSION}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 10, .err = tecNO_PERMISSION}); } // issuance not found @@ -2303,22 +2978,21 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Account const alice("alice"); Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create({.flags = tfMPTCanClawback}); + mptAlice.create({.flags = tfMPTCanClawback | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.generateKeyPair(alice); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); // destroy the issuance mptAlice.destroy(); - env.close(); Json::Value jv; jv[jss::Account] = alice.human(); jv[sfHolder] = bob.human(); - jv[jss::TransactionType] = jss::ConfidentialClawback; + jv[jss::TransactionType] = jss::ConfidentialMPTClawback; jv[sfMPTAmount] = std::to_string(10); - jv[sfZKProof] = "123"; + std::string const dummyProof(196, '0'); + jv[sfZKProof] = dummyProof; jv[sfMPTokenIssuanceID] = to_string(mptAlice.issuanceID()); env(jv, ter(tecOBJECT_NOT_FOUND)); @@ -2326,26 +3000,18 @@ class ConfidentialTransfer_test : public beast::unit_test::suite // helper function to set up accounts to test lock and unauthorize // cases. after set up, bob has confidential balance 60 in spending. - auto setupAccounts = [&](Env& env, - Account const& alice, - Account const& bob) -> MPTTester { + auto setupAccounts = [&](Env& env, Account const& alice, Account const& bob) -> MPTTester { MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create( - {.flags = tfMPTCanTransfer | tfMPTCanClawback | - tfMPTRequireAuth | tfMPTCanLock}); + {.flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanLock | tfMPTCanPrivacy}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); mptAlice.pay(alice, bob, 100); mptAlice.generateKeyPair(alice); mptAlice.generateKeyPair(bob); - mptAlice.set( - {.account = alice, .pubKey = mptAlice.getPubKey(alice)}); - mptAlice.convert( - {.account = bob, - .amt = 60, - .proof = "123", - .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)}); mptAlice.mergeInbox({ .account = bob, }); @@ -2362,8 +3028,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); // clawback should still work - mptAlice.confidentialClaw( - {.account = alice, .holder = bob, .amt = 60, .proof = "123"}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 60}); } // lock globally @@ -2375,8 +3040,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite mptAlice.set({.account = alice, .flags = tfMPTLock}); // clawback should still work - mptAlice.confidentialClaw( - {.account = alice, .holder = bob, .amt = 60, .proof = "123"}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 60}); } // unauthorize should not block clawback @@ -2387,45 +3051,775 @@ class ConfidentialTransfer_test : public beast::unit_test::suite MPTTester mptAlice = setupAccounts(env, alice, bob); // unauthorize bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); // clawback should still work - mptAlice.confidentialClaw( - {.account = alice, .holder = bob, .amt = 60, .proof = "123"}); + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 60}); } - // todo: test zkp verification failure + // insufficient funds, clawback amount exceeding confidential + // outstanding amount + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice = setupAccounts(env, alice, bob); + + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 10000, .err = tecINSUFFICIENT_FUNDS}); + } + } + + void + testClawbackProof(FeatureBitset features) + { + testcase("ConfidentialMPTClawback Proof"); + using namespace test::jtx; + + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + + // lambda function to set up MPT with alice as issuer, bob and carol + // as authorized holders, and fund 1000 mpt to bob and 2000 mpt to + // carol. + auto setupEnv = [&](Env& env) -> MPTTester { + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanPrivacy}); + + for (auto const& [acct, amt] : {std::pair{bob, 1000}, {carol, 2000}}) + { + mptAlice.authorize({.account = acct}); + mptAlice.pay(alice, acct, amt); + mptAlice.generateKeyPair(acct); + } + + mptAlice.generateKeyPair(alice); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + return mptAlice; + }; + + // lambda function to test a set of bad clawback amounts that should + // return tecBAD_PROOF + auto checkBadProofs = [&](MPTTester& mpt, Account const& holder, std::initializer_list amts) { + for (auto const badAmt : amts) + { + mpt.confidentialClaw({.account = alice, .holder = holder, .amt = badAmt, .err = tecBAD_PROOF}); + } + }; + + // SCENARIO 1: clawback from inbox only or spending only balances. + // bob converts 500 and merge inbox, + // carol converts 1000, but not merge inbox. + // after setup, bob has 500 in spending, carol has 1000 in inbox. + { + Env env{*this, features}; + auto mptAlice = setupEnv(env); + + // bob converts and merges + mptAlice.convert({.account = bob, .amt = 500, .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.mergeInbox({ + .account = bob, + }); + // carol converts without merge + mptAlice.convert({.account = carol, .amt = 1000, .holderPubKey = mptAlice.getPubKey(carol)}); + + // verify proof fails with invalid clawback amount + // bob: 500 in Spending, 0 in Inbox + checkBadProofs(mptAlice, bob, {1, 10, 70, 100, 110, 200, 499, 501, 600}); + + // carol: 1000 in Inbox, 0 in Spending + checkBadProofs(mptAlice, carol, {1, 10, 50, 500, 777, 850, 999, 1001, 1200}); + + // clawback with correct amount that passes proof verification + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 500}); + mptAlice.confidentialClaw({.account = alice, .holder = carol, .amt = 1000}); + } + + // SCENARIO 2: clawback from mixed inbox and spending balances. + // bob converts 300 to confidential and merge inbox, + // carol converts 400 to confidential and merge inbox, + // bob sends 100 to carol, carol sends 100 to bob. + // After setup, bob has 100 in inbox and 200 in spending; + // carol has 100 in inbox and 300 in spending. + { + Env env{*this, features}; + auto mptAlice = setupEnv(env); + + mptAlice.convert({.account = bob, .amt = 300, .holderPubKey = mptAlice.getPubKey(bob)}); + mptAlice.mergeInbox({ + .account = bob, + }); + mptAlice.convert({.account = carol, .amt = 400, .holderPubKey = mptAlice.getPubKey(carol)}); + mptAlice.mergeInbox({ + .account = carol, + }); + mptAlice.send({.account = bob, .dest = carol, .amt = 100}); + mptAlice.send({.account = carol, .dest = bob, .amt = 100}); + + // verify proof fails with invalid clawback amount + // bob: 100 in inbox, 200 in spending + checkBadProofs(mptAlice, bob, {1, 10, 50, 100, 200, 299, 301, 400}); + + // proof failure for incorrect amount when clawbacking from + // carol carol: 100 in inbox, 300 in spending + checkBadProofs(mptAlice, carol, {1, 10, 50, 100, 300, 399, 401, 501}); + + // clawback with correct amount that passes proof verification + mptAlice.confidentialClaw({.account = alice, .holder = bob, .amt = 300}); + mptAlice.confidentialClaw({.account = alice, .holder = carol, .amt = 400}); + } + } + + void + testMutatePrivacy(FeatureBitset features) + { + testcase("mutate lsfMPTCanPrivacy"); + using namespace test::jtx; + + // can not create mpt issuance with tmfMPTCannotMutatePrivacy + // when featureDynamicMPT is disabled + { + Env env{*this, features - featureDynamicMPT}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 0, .mutableFlags = tmfMPTCannotMutatePrivacy, .err = temDISABLED}); + } + + // can not create mpt issuance with tmfMPTCannotMutatePrivacy when + // featureConfidentialTransfer is disabled + { + Env env{*this, features - featureConfidentialTransfer}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 0, .mutableFlags = tmfMPTCannotMutatePrivacy, .err = temDISABLED}); + } + + // if lsmfMPTCannotMutatePrivacy is set, can not set/clear + // lsfMPTCanPrivacy + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer, .mutableFlags = tmfMPTCannotMutatePrivacy}); + + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetPrivacy, .err = tecNO_PERMISSION}); + + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearPrivacy, .err = tecNO_PERMISSION}); + } + + // Toggle lsfMPTCanPrivacy + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create( + {.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanPrivacy, .mutableFlags = tmfMPTCanMutateCanLock}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + auto holderPubKeySet = false; + auto verifyToggle = [&](TER expectedResult, uint64_t amt) { + if (!holderPubKeySet) + mptAlice.convert( + {.account = bob, .amt = amt, .holderPubKey = mptAlice.getPubKey(bob), .err = expectedResult}); + else + mptAlice.convert({ + .account = bob, + .amt = amt, + .err = expectedResult, + }); + + if (expectedResult == tesSUCCESS) + { + holderPubKeySet = true; + mptAlice.mergeInbox({ + .account = bob, + }); + + // make sure there's no confidential outstanding balance + // for the next toggle test + mptAlice.convertBack({ + .account = bob, + .amt = amt, + }); + } + }; + + // set lsfMPTCanPrivacy, but no effect because lsfMPTCanPrivacy + // was already set + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetPrivacy}); + verifyToggle(tesSUCCESS, 10); + + // clear lsfMPTCanPrivacy + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearPrivacy}); + verifyToggle(tecNO_PERMISSION, 10); + + // can clear lsfMPTCanPrivacy again but has no effect + // for privacy settings + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearPrivacy | tmfMPTSetCanLock}); + verifyToggle(tecNO_PERMISSION, 20); + + // set lsfMPTCanPrivacy again + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetPrivacy}); + verifyToggle(tesSUCCESS, 30); + } + + // can not mutate lsfPrivacy when there's confidential + // outstanding amount + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // lsmfMPTCannotMutatePrivacy is false by default, + // so that lsfMPTCanPrivacy can be mutated + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + mptAlice.generateKeyPair(bob); + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + // bob convert 50 to confidential + mptAlice.convert({.account = bob, .amt = 50, .holderPubKey = mptAlice.getPubKey(bob)}); + + // set or clear lsfMPTCanPrivacy should fail because of + // confidential outstanding balance + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetPrivacy, .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearPrivacy, .err = tecNO_PERMISSION}); + + // bob merge inbox + mptAlice.mergeInbox({ + .account = bob, + }); + + // bob convert back all confidential balance + mptAlice.convertBack({ + .account = bob, + .amt = 50, + }); + + // now clear lsfMPTCanPrivacy should succeed, + // because there's no confidential outstanding balance + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearPrivacy}); + + // bob can not convert because lsfMPTCanPrivacy was cleared + // successfully + mptAlice.convert( + {.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob), .err = tecNO_PERMISSION}); + + // can set lsfMPTCanPrivacy again when there's no confidential + // outstanding balance + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetPrivacy}); + mptAlice.convert({ + .account = bob, + .amt = 10, + }); + } + } + + void + testConvertBackPedersenProof(FeatureBitset features) + { + testcase("Convert back pedersen proof"); + using namespace test::jtx; + + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // --------------- Setup test --------------- // + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.mergeInbox({ + .account = bob, + }); + + // for ease of understanding, generate all the fields here instead of + // autofilling + uint64_t const amt = 10; + Buffer const blindingFactor = generateBlindingFactor(); + Buffer const pcBlindingFactor = generateBlindingFactor(); + + auto const spendingBalance = mptAlice.getDecryptedBalance(bob, MPTTester::HOLDER_ENCRYPTED_SPENDING); + BEAST_EXPECT(spendingBalance.has_value()); + auto const encryptedSpendingBalance = mptAlice.getEncryptedBalance(bob, MPTTester::HOLDER_ENCRYPTED_SPENDING); + BEAST_EXPECT(encryptedSpendingBalance.has_value() && !encryptedSpendingBalance->empty()); + + Buffer const pedersenCommitment = mptAlice.getPedersenCommitment(*spendingBalance, pcBlindingFactor); + Buffer const issuerCiphertext = mptAlice.encryptAmount(alice, amt, blindingFactor); + Buffer const bobCiphertext = mptAlice.encryptAmount(bob, amt, blindingFactor); + auto const version = mptAlice.getMPTokenVersion(bob); + + // --------------- Finish setup --------------- // + + // These tests verify that the pedersen linkage proof validation + // correctly rejects proofs generated with incorrect parameters. + // The pedersen linkage proof proves that the balance commitment + // PC = balance*G + rho*H is derived from the holder's encrypted + // spending balance. + + // Helper to combine pedersen proof and bulletproof + auto const combineProofs = [](Buffer const& pedersenProof, Buffer const& bulletproof) { + Buffer combinedProof(pedersenProof.size() + bulletproof.size()); + std::memcpy(combinedProof.data(), pedersenProof.data(), pedersenProof.size()); + std::memcpy(combinedProof.data() + pedersenProof.size(), bulletproof.data(), bulletproof.size()); + return combinedProof; + }; + + auto const holderPubKey = mptAlice.getPubKey(bob); + BEAST_EXPECT(holderPubKey.has_value()); + + // Test 1: Proof generated with wrong pedersen commitment value. + // The proof uses PC(1, rho) but the transaction submits PC(balance, rho). + // Verification fails because the proof doesn't match the submitted commitment. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor); + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = badPedersenCommitment, // wrong pedersen commitment + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 2: Proof generated with wrong blinding factor (rho). + // The pedersen commitment PC = balance*G + rho*H requires the same rho + // used in proof generation. Using a different rho breaks the linkage. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = generateBlindingFactor(), // wrong blinding factor + }); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 3: Proof generated with wrong balance value. + // The proof claims balance=1 but the encrypted spending balance contains + // the actual balance. Verification fails because the values don't match. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = 1, // wrong balance + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 4: Correct proof but wrong pedersen commitment in transaction. + // The proof is generated correctly, but the transaction submits a + // different pedersen commitment. Verification fails because the + // submitted commitment doesn't match what the proof was generated for. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor); + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = badPedersenCommitment, // wrong pedersen commitment + .err = tecBAD_PROOF}); + } + + // Test 5: Proof generated with wrong context hash. + // The context hash binds the proof to a specific transaction (account, + // sequence, issuanceID, amount, version). Using a different context hash + // makes the proof invalid for this transaction, preventing replay attacks. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + uint256 const badContextHash{1}; + Buffer const pedersenProof = mptAlice.getBalanceLinkageProof( + bob, + badContextHash, // wrong context hash + *holderPubKey, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + // Bulletproof uses correct context hash so only pedersen proof fails + Buffer const bulletproof = + mptAlice.getBulletproof({*spendingBalance - amt}, {pcBlindingFactor}, contextHash); + + Buffer const proof = combineProofs(pedersenProof, bulletproof); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 6: Correct proof to verify the test setup is valid. + // All parameters are correct, so the transaction should succeed. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + mptAlice.convertBack({ + .account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + }); + } + } + + void + testConvertBackBulletproof(FeatureBitset features) + { + testcase("Convert back bulletproof"); + using namespace test::jtx; + + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // --------------- Setup test --------------- // + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy}); + + mptAlice.authorize({.account = bob}); + mptAlice.pay(alice, bob, 100); + + mptAlice.generateKeyPair(alice); + + mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)}); + + mptAlice.generateKeyPair(bob); + + mptAlice.convert({ + .account = bob, + .amt = 40, + .holderPubKey = mptAlice.getPubKey(bob), + }); + + mptAlice.mergeInbox({ + .account = bob, + }); + + // for ease of understanding, generate all the fields here instead of + // autofilling + uint64_t const amt = 10; + Buffer const blindingFactor = generateBlindingFactor(); + Buffer const pcBlindingFactor = generateBlindingFactor(); + + auto const spendingBalance = mptAlice.getDecryptedBalance(bob, MPTTester::HOLDER_ENCRYPTED_SPENDING); + BEAST_EXPECT(spendingBalance.has_value()); + auto const encryptedSpendingBalance = mptAlice.getEncryptedBalance(bob, MPTTester::HOLDER_ENCRYPTED_SPENDING); + BEAST_EXPECT(encryptedSpendingBalance.has_value() && !encryptedSpendingBalance->empty()); + + Buffer const pedersenCommitment = mptAlice.getPedersenCommitment(*spendingBalance, pcBlindingFactor); + Buffer const issuerCiphertext = mptAlice.encryptAmount(alice, amt, blindingFactor); + Buffer const bobCiphertext = mptAlice.encryptAmount(bob, amt, blindingFactor); + auto const version = mptAlice.getMPTokenVersion(bob); + + // --------------- Finish setup --------------- // + + // These tests verify that the bulletproof (range proof) validation + // correctly rejects proofs generated with incorrect parameters. + // The bulletproof proves that the remaining balance (balance - amount) + // is non-negative, i.e., in the range [0, 2^64-1]. This prevents + // overdrafts where a user tries to convert back more than they have. + + // Helper to combine pedersen proof and bulletproof + auto const combineProofs = [](Buffer const& pedersenProof, Buffer const& bulletproof) { + Buffer combinedProof(pedersenProof.size() + bulletproof.size()); + std::memcpy(combinedProof.data(), pedersenProof.data(), pedersenProof.size()); + std::memcpy(combinedProof.data() + pedersenProof.size(), bulletproof.data(), bulletproof.size()); + return combinedProof; + }; + + auto const holderPubKey = mptAlice.getPubKey(bob); + BEAST_EXPECT(holderPubKey.has_value()); + + // Helper to generate pedersen proof with correct parameters. + // The pedersen proof links the encrypted balance to the pedersen commitment. + auto const getPedersenProof = [&](uint256 const& contextHash) { + return mptAlice.getBalanceLinkageProof( + bob, + contextHash, + *holderPubKey, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + }; + + // Test 1: Bulletproof generated with wrong remaining balance. + // The bulletproof claims remaining balance is 1, but the pedersen + // commitment was created with (balance - amount). The verifier computes + // PC_rem = PC - amount*G and checks if the bulletproof matches, which fails. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const bulletproof = mptAlice.getBulletproof( + {1}, // wrong remaining balance + {pcBlindingFactor}, + contextHash); + + Buffer const proof = combineProofs(getPedersenProof(contextHash), bulletproof); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 2: Bulletproof generated with wrong blinding factor. + // The bulletproof must use the same blinding factor (rho) as the pedersen + // commitment PC = (balance - amount)*G + rho*H. Using a different rho + // creates a commitment mismatch and verification fails. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const bulletproof = mptAlice.getBulletproof( + {*spendingBalance - amt}, + {generateBlindingFactor()}, // wrong blinding factor + contextHash); + + Buffer const proof = combineProofs(getPedersenProof(contextHash), bulletproof); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 3: Bulletproof generated with wrong context hash. + // The context hash binds the proof to a specific transaction (account, + // sequence, issuanceID, amount, version). Using a different context hash + // makes the proof invalid for this transaction, preventing replay attacks. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + uint256 const badContextHash{1}; + Buffer const bulletproof = mptAlice.getBulletproof( + {*spendingBalance - amt}, + {pcBlindingFactor}, + badContextHash); // wrong context hash + + Buffer const proof = combineProofs(getPedersenProof(contextHash), bulletproof); + + mptAlice.convertBack( + {.account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + .err = tecBAD_PROOF}); + } + + // Test 4: Correct proof to verify the test setup is valid. + // All parameters are correct, so the transaction should succeed. + { + uint256 const contextHash = + getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version); + + Buffer const proof = mptAlice.getConvertBackProof( + bob, + amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = *spendingBalance, + .encryptedAmt = *encryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + + mptAlice.convertBack({ + .account = bob, + .amt = amt, + .proof = proof, + .holderEncryptedAmt = bobCiphertext, + .issuerEncryptedAmt = issuerCiphertext, + .blindingFactor = blindingFactor, + .pedersenCommitment = pedersenCommitment, + }); + } } void testWithFeats(FeatureBitset features) { + // ConfidentialMPTConvert testConvert(features); testConvertPreflight(features); testConvertPreclaim(features); + testConvertWithAuditor(features); + // ConfidentialMPTMergeInbox testMergeInbox(features); testMergeInboxPreflight(features); testMergeInboxPreclaim(features); testSetPreflight(features); - // ConfidentialSend + // ConfidentialMPTSend testSend(features); testSendPreflight(features); testSendPreclaim(features); + testSendRangeProof(features); testSendDepositPreauth(features); + testSendWithAuditor(features); - // ConfidentialClawback + // ConfidentialMPTClawback testClawback(features); testClawbackPreflight(features); testClawbackPreclaim(features); + testClawbackProof(features); + testClawbackWithAuditor(features); testDelete(features); + // ConfidentialMPTConvertBack testConvertBack(features); testConvertBackPreflight(features); testConvertBackPreclaim(features); + testConvertBackWithAuditor(features); + testConvertBackPedersenProof(features); + testConvertBackBulletproof(features); + + testMutatePrivacy(features); } public: @@ -2439,5 +3833,5 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ConfidentialTransfer, app, ripple); -} // namespace ripple +BEAST_DEFINE_TESTSUITE(ConfidentialTransfer, app, xrpl); +} // namespace xrpl diff --git a/src/test/app/Credentials_test.cpp b/src/test/app/Credentials_test.cpp index ed19c4da2a..31c867c24d 100644 --- a/src/test/app/Credentials_test.cpp +++ b/src/test/app/Credentials_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { struct Credentials_test : public beast::unit_test::suite @@ -58,8 +39,7 @@ struct Credentials_test : public beast::unit_test::suite env.close(); // Test Create credentials - env(credentials::create(subject, issuer, credType), - credentials::uri(uri)); + env(credentials::create(subject, issuer, credType), credentials::uri(uri)); env.close(); { auto const sleCred = env.le(credKey); @@ -74,21 +54,14 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, subject)); BEAST_EXPECT(checkVL(sleCred, sfCredentialType, credType)); BEAST_EXPECT(checkVL(sleCred, sfURI, uri)); - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } env(credentials::accept(subject, issuer, credType)); @@ -118,11 +91,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, subject)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } } @@ -132,8 +103,7 @@ struct Credentials_test : public beast::unit_test::suite auto const credKey = credentials::keylet(issuer, issuer, credType); - env(credentials::create(issuer, issuer, credType), - credentials::uri(uri)); + env(credentials::create(issuer, issuer, credType), credentials::uri(uri)); env.close(); { auto const sleCred = env.le(credKey); @@ -144,27 +114,18 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(sleCred->getAccountID(sfSubject) == issuer.id()); BEAST_EXPECT(sleCred->getAccountID(sfIssuer) == issuer.id()); BEAST_EXPECT((sleCred->getFieldU32(sfFlags) & lsfAccepted)); - BEAST_EXPECT( - sleCred->getFieldU64(sfIssuerNode) == - sleCred->getFieldU64(sfSubjectNode)); + BEAST_EXPECT(sleCred->getFieldU64(sfIssuerNode) == sleCred->getFieldU64(sfSubjectNode)); BEAST_EXPECT(ownerCount(env, issuer) == 1); BEAST_EXPECT(checkVL(sleCred, sfCredentialType, credType)); BEAST_EXPECT(checkVL(sleCred, sfURI, uri)); - auto const jle = - credentials::ledgerEntry(env, issuer, issuer, credType); + auto const jle = credentials::ledgerEntry(env, issuer, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - issuer.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == issuer.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } env(credentials::deleteCred(issuer, issuer, issuer, credType)); @@ -174,11 +135,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, issuer)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, issuer, issuer, credType); + auto const jle = credentials::ledgerEntry(env, issuer, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } } @@ -224,11 +183,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, subject)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } @@ -262,11 +219,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, subject)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } @@ -298,11 +253,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, issuer)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } @@ -336,11 +289,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, issuer)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } @@ -354,10 +305,7 @@ struct Credentials_test : public beast::unit_test::suite auto const credKey = credentials::keylet(subject, issuer, credType); auto jv = credentials::create(subject, issuer, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count(); + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count(); jv[sfExpiration.jsonName] = t + 20; env(jv); @@ -377,11 +325,9 @@ struct Credentials_test : public beast::unit_test::suite BEAST_EXPECT(!ownerCount(env, subject)); // check no credential exists anymore - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } } @@ -396,16 +342,13 @@ struct Credentials_test : public beast::unit_test::suite env(credentials::deleteCred(subject, subject, issuer, credType)); env.close(); { - auto const credKey = - credentials::keylet(subject, issuer, credType); + auto const credKey = credentials::keylet(subject, issuer, credType); BEAST_EXPECT(!env.le(credKey)); BEAST_EXPECT(!ownerCount(env, subject)); BEAST_EXPECT(!ownerCount(env, issuer)); - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } } @@ -418,16 +361,13 @@ struct Credentials_test : public beast::unit_test::suite env(credentials::deleteCred(issuer, subject, issuer, credType)); env.close(); { - auto const credKey = - credentials::keylet(subject, issuer, credType); + auto const credKey = credentials::keylet(subject, issuer, credType); BEAST_EXPECT(!env.le(credKey)); BEAST_EXPECT(!ownerCount(env, subject)); BEAST_EXPECT(!ownerCount(env, issuer)); - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && jle[jss::result].isMember(jss::error) && jle[jss::result][jss::error] == "entryNotFound"); } } @@ -500,27 +440,19 @@ struct Credentials_test : public beast::unit_test::suite "WULE" "fv28o37gfwEFB3872TFO8GSDSDVD"; static_assert(longURI.size() > maxCredentialURILength); - env(credentials::create(subject, issuer, credType), - credentials::uri(longURI), - ter(temMALFORMED)); + env(credentials::create(subject, issuer, credType), credentials::uri(longURI), ter(temMALFORMED)); } { testcase("Credentials fail, URI empty."); - env(credentials::create(subject, issuer, credType), - credentials::uri(""), - ter(temMALFORMED)); + env(credentials::create(subject, issuer, credType), credentials::uri(""), ter(temMALFORMED)); } { testcase("Credentials fail, expiration in the past."); auto jv = credentials::create(subject, issuer, credType); // current time in ripple epoch - 1s - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() - - 1; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() - 1; jv[sfExpiration.jsonName] = t; env(jv, ter(tecEXPIRED)); } @@ -542,21 +474,14 @@ struct Credentials_test : public beast::unit_test::suite env.close(); // check credential still present - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } { @@ -567,10 +492,7 @@ struct Credentials_test : public beast::unit_test::suite // Everything below can only be tested on open ledger. auto const res1 = directory::bumpLastPage( - env, - directory::maximumPageIndex(env), - keylet::ownerDir(issuer.id()), - directory::adjustOwnerNode); + env, directory::maximumPageIndex(env), keylet::ownerDir(issuer.id()), directory::adjustOwnerNode); BEAST_EXPECT(res1); auto const jv = credentials::create(issuer, subject, credType); @@ -581,10 +503,7 @@ struct Credentials_test : public beast::unit_test::suite // Fill subject directory env(ticket::create(subject, 63)); auto const res2 = directory::bumpLastPage( - env, - directory::maximumPageIndex(env), - keylet::ownerDir(subject.id()), - directory::adjustOwnerNode); + env, directory::maximumPageIndex(env), keylet::ownerDir(subject.id()), directory::adjustOwnerNode); BEAST_EXPECT(res2); env(jv, ter(tecDIR_FULL)); @@ -641,8 +560,7 @@ struct Credentials_test : public beast::unit_test::suite { testcase("CredentialsAccept fail, Credential doesn't exist."); - env(credentials::accept(subject, issuer, credType), - ter(tecNO_ENTRY)); + env(credentials::accept(subject, issuer, credType), ter(tecNO_ENTRY)); env.close(); } @@ -655,8 +573,7 @@ struct Credentials_test : public beast::unit_test::suite } { - testcase( - "CredentialsAccept fail, invalid credentialType param."); + testcase("CredentialsAccept fail, invalid credentialType param."); auto jv = credentials::accept(subject, issuer, ""); env(jv, ter(temMALFORMED)); } @@ -674,26 +591,18 @@ struct Credentials_test : public beast::unit_test::suite env(credentials::create(subject, issuer, credType)); env.close(); - env(credentials::accept(subject, issuer, credType), - ter(tecINSUFFICIENT_RESERVE)); + env(credentials::accept(subject, issuer, credType), ter(tecINSUFFICIENT_RESERVE)); env.close(); // check credential still present - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } } @@ -716,26 +625,18 @@ struct Credentials_test : public beast::unit_test::suite testcase("CredentialsAccept fail, lsfAccepted already set."); env(credentials::accept(subject, issuer, credType)); env.close(); - env(credentials::accept(subject, issuer, credType), - ter(tecDUPLICATE)); + env(credentials::accept(subject, issuer, credType), ter(tecDUPLICATE)); env.close(); // check credential still present - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } { @@ -743,26 +644,20 @@ struct Credentials_test : public beast::unit_test::suite testcase("CredentialsAccept fail, expired credentials."); auto jv = credentials::create(subject, issuer, credType2); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count(); + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count(); jv[sfExpiration.jsonName] = t; env(jv); env.close(); // credentials are expired now - env(credentials::accept(subject, issuer, credType2), - ter(tecEXPIRED)); + env(credentials::accept(subject, issuer, credType2), ter(tecEXPIRED)); env.close(); // check that expired credentials were deleted - auto const jDelCred = - credentials::ledgerEntry(env, subject, issuer, credType2); + auto const jDelCred = credentials::ledgerEntry(env, subject, issuer, credType2); BEAST_EXPECT( jDelCred.isObject() && jDelCred.isMember(jss::result) && - jDelCred[jss::result].isMember(jss::error) && - jDelCred[jss::result][jss::error] == "entryNotFound"); + jDelCred[jss::result].isMember(jss::error) && jDelCred[jss::result][jss::error] == "entryNotFound"); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, subject) == 1); @@ -795,12 +690,10 @@ struct Credentials_test : public beast::unit_test::suite env.close(); // check that expired credentials were deleted - auto const jDelCred = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jDelCred = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( jDelCred.isObject() && jDelCred.isMember(jss::result) && - jDelCred[jss::result].isMember(jss::error) && - jDelCred[jss::result][jss::error] == "entryNotFound"); + jDelCred[jss::result].isMember(jss::error) && jDelCred[jss::result][jss::error] == "entryNotFound"); } } } @@ -824,15 +717,13 @@ struct Credentials_test : public beast::unit_test::suite { testcase("CredentialsDelete fail, no Credentials."); - env(credentials::deleteCred(subject, subject, issuer, credType), - ter(tecNO_ENTRY)); + env(credentials::deleteCred(subject, subject, issuer, credType), ter(tecNO_ENTRY)); env.close(); } { testcase("CredentialsDelete fail, invalid Subject account."); - auto jv = - credentials::deleteCred(subject, subject, issuer, credType); + auto jv = credentials::deleteCred(subject, subject, issuer, credType); jv[jss::Subject] = to_string(xrpAccount()); env(jv, ter(temINVALID_ACCOUNT_ID)); env.close(); @@ -840,16 +731,14 @@ struct Credentials_test : public beast::unit_test::suite { testcase("CredentialsDelete fail, invalid Issuer account."); - auto jv = - credentials::deleteCred(subject, subject, issuer, credType); + auto jv = credentials::deleteCred(subject, subject, issuer, credType); jv[jss::Issuer] = to_string(xrpAccount()); env(jv, ter(temINVALID_ACCOUNT_ID)); env.close(); } { - testcase( - "CredentialsDelete fail, invalid credentialType param."); + testcase("CredentialsDelete fail, invalid credentialType param."); auto jv = credentials::deleteCred(subject, subject, issuer, ""); env(jv, ter(temMALFORMED)); } @@ -861,26 +750,18 @@ struct Credentials_test : public beast::unit_test::suite env.close(); // Other account can't delete credentials without expiration - env(credentials::deleteCred(other, subject, issuer, credType2), - ter(tecNO_PERMISSION)); + env(credentials::deleteCred(other, subject, issuer, credType2), ter(tecNO_PERMISSION)); env.close(); // check credential still present - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType2); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType2); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType2))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType2))); } { @@ -888,43 +769,30 @@ struct Credentials_test : public beast::unit_test::suite auto jv = credentials::create(subject, issuer, credType); // current time in ripple epoch + 1000s - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 1000; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 1000; jv[sfExpiration.jsonName] = t; env(jv); env.close(); // Other account can't delete credentials that not expired - env(credentials::deleteCred(other, subject, issuer, credType), - ter(tecNO_PERMISSION)); + env(credentials::deleteCred(other, subject, issuer, credType), ter(tecNO_PERMISSION)); env.close(); // check credential still present - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == subject.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); } { testcase("CredentialsDelete fail, no Issuer and Subject."); - auto jv = - credentials::deleteCred(subject, subject, issuer, credType); + auto jv = credentials::deleteCred(subject, subject, issuer, credType); jv.removeMember(jss::Subject); jv.removeMember(jss::Issuer); env(jv, ter(temMALFORMED)); @@ -934,8 +802,7 @@ struct Credentials_test : public beast::unit_test::suite { testcase("CredentialsDelete fail, invalid fee."); - auto jv = - credentials::deleteCred(subject, subject, issuer, credType); + auto jv = credentials::deleteCred(subject, subject, issuer, credType); jv[jss::Fee] = -1; env(jv, ter(temBAD_FEE)); env.close(); @@ -943,10 +810,8 @@ struct Credentials_test : public beast::unit_test::suite { testcase("deleteSLE fail, bad SLE."); - auto view = std::make_shared( - env.current().get(), ApplyFlags::tapNONE); - auto ter = - ripple::credentials::deleteSLE(*view, {}, env.journal); + auto view = std::make_shared(env.current().get(), ApplyFlags::tapNONE); + auto ter = xrpl::credentials::deleteSLE(*view, {}, env.journal); BEAST_EXPECT(ter == tecNO_ENTRY); } } @@ -970,12 +835,9 @@ struct Credentials_test : public beast::unit_test::suite { testcase("Credentials fail, Feature is not enabled."); - env(credentials::create(subject, issuer, credType), - ter(temDISABLED)); - env(credentials::accept(subject, issuer, credType), - ter(temDISABLED)); - env(credentials::deleteCred(subject, subject, issuer, credType), - ter(temDISABLED)); + env(credentials::create(subject, issuer, credType), ter(temDISABLED)); + env(credentials::accept(subject, issuer, credType), ter(temDISABLED)); + env(credentials::deleteCred(subject, subject, issuer, credType), ter(temDISABLED)); } } } @@ -1008,16 +870,13 @@ struct Credentials_test : public beast::unit_test::suite { Json::Value params; params[jss::account] = subject.human(); - auto const jv = env.rpc( - "json", "account_tx", to_string(params))[jss::result]; + auto const jv = env.rpc("json", "account_tx", to_string(params))[jss::result]; BEAST_EXPECT(jv[jss::transactions].size() == 4); auto const& tx0(jv[jss::transactions][0u][jss::tx]); - BEAST_EXPECT( - tx0[jss::TransactionType] == jss::CredentialAccept); + BEAST_EXPECT(tx0[jss::TransactionType] == jss::CredentialAccept); auto const& tx1(jv[jss::transactions][1u][jss::tx]); - BEAST_EXPECT( - tx1[jss::TransactionType] == jss::CredentialCreate); + BEAST_EXPECT(tx1[jss::TransactionType] == jss::CredentialCreate); txHash0 = tx0[jss::hash].asString(); txHash1 = tx1[jss::hash].asString(); } @@ -1025,16 +884,13 @@ struct Credentials_test : public beast::unit_test::suite { Json::Value params; params[jss::account] = issuer.human(); - auto const jv = env.rpc( - "json", "account_tx", to_string(params))[jss::result]; + auto const jv = env.rpc("json", "account_tx", to_string(params))[jss::result]; BEAST_EXPECT(jv[jss::transactions].size() == 4); auto const& tx0(jv[jss::transactions][0u][jss::tx]); - BEAST_EXPECT( - tx0[jss::TransactionType] == jss::CredentialAccept); + BEAST_EXPECT(tx0[jss::TransactionType] == jss::CredentialAccept); auto const& tx1(jv[jss::transactions][1u][jss::tx]); - BEAST_EXPECT( - tx1[jss::TransactionType] == jss::CredentialCreate); + BEAST_EXPECT(tx1[jss::TransactionType] == jss::CredentialCreate); BEAST_EXPECT(txHash0 == tx0[jss::hash].asString()); BEAST_EXPECT(txHash1 == tx1[jss::hash].asString()); @@ -1045,28 +901,24 @@ struct Credentials_test : public beast::unit_test::suite { Json::Value params; params[jss::account] = subject.human(); - auto jv = env.rpc( - "json", "account_objects", to_string(params))[jss::result]; + auto jv = env.rpc("json", "account_objects", to_string(params))[jss::result]; BEAST_EXPECT(jv[jss::account_objects].size() == 1); auto const& object(jv[jss::account_objects][0u]); - BEAST_EXPECT( - object["LedgerEntryType"].asString() == jss::Credential); + BEAST_EXPECT(object["LedgerEntryType"].asString() == jss::Credential); objectIdx = object[jss::index].asString(); } { Json::Value params; params[jss::account] = issuer.human(); - auto jv = env.rpc( - "json", "account_objects", to_string(params))[jss::result]; + auto jv = env.rpc("json", "account_objects", to_string(params))[jss::result]; BEAST_EXPECT(jv[jss::account_objects].size() == 1); auto const& object(jv[jss::account_objects][0u]); - BEAST_EXPECT( - object["LedgerEntryType"].asString() == jss::Credential); + BEAST_EXPECT(object["LedgerEntryType"].asString() == jss::Credential); BEAST_EXPECT(objectIdx == object[jss::index].asString()); } } @@ -1078,9 +930,7 @@ struct Credentials_test : public beast::unit_test::suite using namespace test::jtx; bool const enabled = features[fixInvalidTxFlags]; - testcase( - std::string("Test flag, fix ") + - (enabled ? "enabled" : "disabled")); + testcase(std::string("Test flag, fix ") + (enabled ? "enabled" : "disabled")); char const credType[] = "abcde"; Account const issuer{"issuer"}; @@ -1094,17 +944,10 @@ struct Credentials_test : public beast::unit_test::suite env.close(); { - ter const expected( - enabled ? TER(temINVALID_FLAG) : TER(tesSUCCESS)); - env(credentials::create(subject, issuer, credType), - txflags(tfTransferable), - expected); - env(credentials::accept(subject, issuer, credType), - txflags(tfSellNFToken), - expected); - env(credentials::deleteCred(subject, subject, issuer, credType), - txflags(tfPassive), - expected); + ter const expected(enabled ? TER(temINVALID_FLAG) : TER(tesSUCCESS)); + env(credentials::create(subject, issuer, credType), txflags(tfTransferable), expected); + env(credentials::accept(subject, issuer, credType), txflags(tfSellNFToken), expected); + env(credentials::deleteCred(subject, subject, issuer, credType), txflags(tfPassive), expected); } } } @@ -1127,7 +970,7 @@ struct Credentials_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Credentials, app, ripple); +BEAST_DEFINE_TESTSUITE(Credentials, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/CrossingLimits_test.cpp b/src/test/app/CrossingLimits_test.cpp index 18fc21078c..0451822492 100644 --- a/src/test/app/CrossingLimits_test.cpp +++ b/src/test/app/CrossingLimits_test.cpp @@ -1,26 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class CrossingLimits_test : public beast::unit_test::suite @@ -81,15 +64,15 @@ public: int const maxConsumed = 1000; env.fund(XRP(100000000), gw, "alice", "bob", "carol"); - int const bobsOfferCount = maxConsumed + 150; - env.trust(USD(bobsOfferCount), "bob"); - env(pay(gw, "bob", USD(bobsOfferCount))); + int const bobOfferCount = maxConsumed + 150; + env.trust(USD(bobOfferCount), "bob"); + env(pay(gw, "bob", USD(bobOfferCount))); env.close(); - n_offers(env, bobsOfferCount, "bob", XRP(1), USD(1)); + n_offers(env, bobOfferCount, "bob", XRP(1), USD(1)); // Alice offers to buy Bob's offers. However she hits the offer // crossing limit, so she can't buy them all at once. - env(offer("alice", USD(bobsOfferCount), XRP(bobsOfferCount))); + env(offer("alice", USD(bobOfferCount), XRP(bobOfferCount))); env.close(); env.require(balance("alice", USD(maxConsumed))); env.require(balance("bob", USD(150))); @@ -120,19 +103,19 @@ public: // The payment engine allows 1000 offers to cross. int const maxConsumed = 1000; - int const evitasOfferCount{maxConsumed + 49}; + int const evitaOfferCount{maxConsumed + 49}; env.trust(USD(1000), "alice"); env(pay(gw, "alice", USD(1000))); env.trust(USD(1000), "carol"); env(pay(gw, "carol", USD(1))); - env.trust(USD(evitasOfferCount + 1), "evita"); - env(pay(gw, "evita", USD(evitasOfferCount + 1))); + env.trust(USD(evitaOfferCount + 1), "evita"); + env(pay(gw, "evita", USD(evitaOfferCount + 1))); // The payment engine has a limit of 1000 funded or unfunded offers. int const carolsOfferCount{700}; n_offers(env, 400, "alice", XRP(1), USD(1)); n_offers(env, carolsOfferCount, "carol", XRP(1), USD(1)); - n_offers(env, evitasOfferCount, "evita", XRP(1), USD(1)); + n_offers(env, evitaOfferCount, "evita", XRP(1), USD(1)); // Bob offers to buy 1000 XRP for 1000 USD. He takes all 400 USD from // Alice's offers, 1 USD from Carol's and then removes 599 of Carol's @@ -143,8 +126,8 @@ public: env.require(owners("alice", 1)); env.require(balance("carol", USD(0))); env.require(owners("carol", carolsOfferCount - 599)); - env.require(balance("evita", USD(evitasOfferCount + 1))); - env.require(owners("evita", evitasOfferCount + 1)); + env.require(balance("evita", USD(evitaOfferCount + 1))); + env.require(owners("evita", evitaOfferCount + 1)); // Dan offers to buy maxConsumed + 50 XRP USD. He removes all of // Carol's remaining offers as unfunded, then takes @@ -284,9 +267,8 @@ public: // strand dry until the liquidity is actually used) // The implementation allows any single step to consume at most 1000 - // offers. With the `FlowSortStrands` feature enabled, if the total - // number of offers consumed by all the steps combined exceeds 1500, the - // payment stops. + // offers.If the total number of offers consumed by all the steps + // combined exceeds 1500, the payment stops. { Env env(*this, features); @@ -301,8 +283,7 @@ public: // best quality n_offers(env, 2000, alice, EUR(2), XRP(1)); n_offers(env, 100, alice, XRP(1), USD(4)); - n_offers( - env, 801, carol, XRP(1), USD(3)); // only one offer is funded + n_offers(env, 801, carol, XRP(1), USD(3)); // only one offer is funded n_offers(env, 1000, alice, XRP(1), USD(3)); n_offers(env, 1, alice, EUR(500), USD(500)); @@ -321,7 +302,7 @@ public: // offers unfunded. // b. Carol's remaining 800 offers are consumed as unfunded. // c. 199 of alice's XRP(1) to USD(3) offers are consumed. - // A book step is allowed to consume a maxium of 1000 offers + // A book step is allowed to consume a maximum of 1000 offers // at a given quality, and that limit is now reached. // d. Now the strand is dry, even though there are still funded // XRP(1) to USD(3) offers available. @@ -359,8 +340,7 @@ public: env.require(balance(alice, USD(2503))); env.require(balance(alice, EUR(1100))); - auto const numAOffers = - 2000 + 100 + 1000 + 1 - (2 * 100 + 2 * 199 + 1 + 1); + auto const numAOffers = 2000 + 100 + 1000 + 1 - (2 * 100 + 2 * 199 + 1 + 1); env.require(offers(alice, numAOffers)); env.require(owners(alice, numAOffers + 2)); @@ -381,8 +361,7 @@ public: n_offers(env, 1, alice, EUR(1), USD(10)); n_offers(env, 2000, alice, EUR(2), XRP(1)); n_offers(env, 100, alice, XRP(1), USD(4)); - n_offers( - env, 801, carol, XRP(1), USD(3)); // only one offer is funded + n_offers(env, 801, carol, XRP(1), USD(3)); // only one offer is funded n_offers(env, 1000, alice, XRP(1), USD(3)); n_offers(env, 1, alice, EUR(499), USD(499)); @@ -402,7 +381,7 @@ public: // offers unfunded. // b. Carol's remaining 800 offers are consumed as unfunded. // c. 199 of alice's XRP(1) to USD(3) offers are consumed. - // A book step is allowed to consume a maxium of 1000 offers + // A book step is allowed to consume a maximum of 1000 offers // at a given quality, and that limit is now reached. // d. Now the strand is dry, even though there are still funded // XRP(1) to USD(3) offers available. Bob has spent 400 EUR and @@ -432,8 +411,7 @@ public: env.require(balance(alice, USD(2494))); env.require(balance(alice, EUR(1100))); - auto const numAOffers = - 1 + 2000 + 100 + 1000 + 1 - (1 + 2 * 100 + 2 * 199 + 1 + 1); + auto const numAOffers = 1 + 2000 + 100 + 1000 + 1 - (1 + 2 * 100 + 2 * 199 + 1 + 1); env.require(offers(alice, numAOffers)); env.require(owners(alice, numAOffers + 2)); @@ -474,16 +452,12 @@ public: // below the limit. However, if all the offers are consumed it would // create a tecOVERSIZE error. - // The featureFlowSortStrands introduces a way of tracking the total - // number of consumed offers; with this feature the transaction no - // longer fails with a tecOVERSIZE error. // The implementation allows any single step to consume at most 1000 - // offers. With the `FlowSortStrands` feature enabled, if the total - // number of offers consumed by all the steps combined exceeds 1500, the - // payment stops. Since the first set of offers consumes 998 offers, the - // second set will consume 998, which is not over the limit and the - // payment stops. So 2*998, or 1996 is the expected value when - // `FlowSortStrands` is enabled. + // offers. If the total number of offers consumed by all the steps + // combined exceeds 1500, the payment stops. Since the first set of + // offers consumes 998 offers, the second set will consume 998, which is + // not over the limit and the payment stops. So 2*998, or 1996 is the + // expected value. n_offers(env, 998, alice, XRP(1.00), USD(1)); n_offers(env, 998, alice, XRP(0.99), USD(1)); n_offers(env, 998, alice, XRP(0.98), USD(1)); @@ -491,24 +465,10 @@ public: n_offers(env, 998, alice, XRP(0.96), USD(1)); n_offers(env, 998, alice, XRP(0.95), USD(1)); - bool const withSortStrands = features[featureFlowSortStrands]; - - auto const expectedTER = [&]() -> TER { - if (!withSortStrands) - return TER{tecOVERSIZE}; - return tesSUCCESS; - }(); - - env(offer(bob, USD(8000), XRP(8000)), ter(expectedTER)); + env(offer(bob, USD(8000), XRP(8000)), ter(tesSUCCESS)); env.close(); - auto const expectedUSD = [&] { - if (!withSortStrands) - return USD(0); - return USD(1996); - }(); - - env.require(balance(bob, expectedUSD)); + env.require(balance(bob, USD(1996))); } void @@ -524,13 +484,11 @@ public: using namespace jtx; auto const sa = testable_amendments(); testAll(sa); - testAll(sa - featureFlowSortStrands); testAll(sa - featurePermissionedDEX); - testAll(sa - featureFlowSortStrands - featurePermissionedDEX); } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(CrossingLimits, app, ripple, 10); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(CrossingLimits, app, xrpl, 10); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index 870a42fd99..f83571deab 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { struct DID_test : public beast::unit_test::suite @@ -79,9 +60,7 @@ struct DID_test : public beast::unit_test::suite // Pay alice almost enough to make the reserve for a DID. env(pay(env.master, alice, drops(incReserve + 2 * baseFee - 1))); - BEAST_EXPECT( - env.balance(alice) == - acctReserve + incReserve + drops(baseFee - 1)); + BEAST_EXPECT(env.balance(alice) == acctReserve + incReserve + drops(baseFee - 1)); env.close(); // alice still does not have enough XRP for the reserve of a DID. @@ -132,11 +111,7 @@ struct DID_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 0); // all empty fields - env(did::set(alice), - did::uri(""), - did::document(""), - did::data(""), - ter(temEMPTY_DID)); + env(did::set(alice), did::uri(""), did::document(""), did::data(""), ter(temEMPTY_DID)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -152,19 +127,14 @@ struct DID_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 0); // attestation is too long - env(did::set(alice), - did::document("data"), - did::data(longString), - ter(temMALFORMED)); + env(did::set(alice), did::document("data"), did::data(longString), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); // some empty fields, some optional fields // pre-fix amendment auto const fixEnabled = env.current()->rules().enabled(fixEmptyDID); - env(did::set(alice), - did::uri(""), - fixEnabled ? ter(tecEMPTY_DID) : ter(tesSUCCESS)); + env(did::set(alice), did::uri(""), fixEnabled ? ter(tecEMPTY_DID) : ter(tesSUCCESS)); env.close(); auto const expectedOwnerReserve = fixEnabled ? 0 : 1; BEAST_EXPECT(ownerCount(env, alice) == expectedOwnerReserve); @@ -250,10 +220,7 @@ struct DID_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, francis) == 1); // URI + DIDDocument + Data - env(did::set(george), - did::uri("uri"), - did::document("data"), - did::data("attest")); + env(did::set(george), did::uri("uri"), did::document("data"), did::data("attest")); BEAST_EXPECT(ownerCount(env, george) == 1); } @@ -398,7 +365,7 @@ struct DID_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(DID, app, ripple); +BEAST_DEFINE_TESTSUITE(DID, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/DNS_test.cpp b/src/test/app/DNS_test.cpp index c4e476de9f..0d41c0f419 100644 --- a/src/test/app/DNS_test.cpp +++ b/src/test/app/DNS_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,14 +7,14 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class DNS_test : public beast::unit_test::suite { using endpoint_type = boost::asio::ip::tcp::endpoint; using error_code = boost::system::error_code; - std::weak_ptr work_; + std::weak_ptr work_; endpoint_type lastEndpoint_{}; parsedURL pUrl_; std::string port_; @@ -50,16 +31,15 @@ public: void makeRequest(endpoint_type const& lastEndpoint, bool lastStatus) { - auto onFetch = [&](error_code const& errorCode, - endpoint_type const& endpoint, - ripple::detail::response_type&& resp) { - BEAST_EXPECT(!errorCode); - lastEndpoint_ = endpoint; - resolved_[endpoint.address().to_string()]++; - cv_.notify_all(); - }; + auto onFetch = + [&](error_code const& errorCode, endpoint_type const& endpoint, xrpl::detail::response_type&& resp) { + BEAST_EXPECT(!errorCode); + lastEndpoint_ = endpoint; + resolved_[endpoint.address().to_string()]++; + cv_.notify_all(); + }; - auto sp = std::make_shared( + auto sp = std::make_shared( pUrl_.domain, pUrl_.path, port_, @@ -111,8 +91,7 @@ public: for (int i = 1; i <= 4; ++i) { makeRequest(lastEndpoint_, true); - BEAST_EXPECT( - resolved_.size() == 1 && resolved_.begin()->second == i); + BEAST_EXPECT(resolved_.size() == 1 && resolved_.begin()->second == i); } if (!isMultipleEndpoints()) return; @@ -129,7 +108,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DNS, app, ripple, 20); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DNS, app, xrpl, 20); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index 2c0903fc54..2207c83148 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -22,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Delegate_test : public beast::unit_test::suite { @@ -39,8 +22,7 @@ class Delegate_test : public beast::unit_test::suite env.fund(XRP(1000000), gw, alice, bob); env.close(); - auto res = features[featurePermissionDelegationV1_1] ? ter(tesSUCCESS) - : ter(temDISABLED); + auto res = features[featurePermissionDelegationV1_1] ? ter(tesSUCCESS) : ter(temDISABLED); // can not set Delegate when feature disabled env(delegate::set(gw, alice, {"Payment"}), res); @@ -69,61 +51,42 @@ class Delegate_test : public beast::unit_test::suite auto const entry = delegate::entry(env, gw, alice); BEAST_EXPECT(entry[jss::result][jss::error] == "entryNotFound"); - auto const permissions = std::vector{ - "Payment", - "EscrowCreate", - "EscrowFinish", - "TrustlineAuthorize", - "CheckCreate"}; + auto const permissions = + std::vector{"Payment", "EscrowCreate", "EscrowFinish", "TrustlineAuthorize", "CheckCreate"}; env(delegate::set(gw, alice, permissions)); env.close(); // this lambda function is used to compare the json value of ledger // entry response with the given vector of permissions. - auto comparePermissions = - [&](Json::Value const& jle, - std::vector const& permissions, - Account const& account, - Account const& authorize) { - BEAST_EXPECT( - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node)); - BEAST_EXPECT( - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Delegate); - BEAST_EXPECT( - jle[jss::result][jss::node][jss::Account] == - account.human()); - BEAST_EXPECT( - jle[jss::result][jss::node][sfAuthorize.jsonName] == - authorize.human()); + auto comparePermissions = [&](Json::Value const& jle, + std::vector const& permissions, + Account const& account, + Account const& authorize) { + BEAST_EXPECT(!jle[jss::result].isMember(jss::error) && jle[jss::result].isMember(jss::node)); + BEAST_EXPECT(jle[jss::result][jss::node]["LedgerEntryType"] == jss::Delegate); + BEAST_EXPECT(jle[jss::result][jss::node][jss::Account] == account.human()); + BEAST_EXPECT(jle[jss::result][jss::node][sfAuthorize.jsonName] == authorize.human()); - auto const& jPermissions = - jle[jss::result][jss::node][sfPermissions.jsonName]; - unsigned i = 0; - for (auto const& permission : permissions) - { - BEAST_EXPECT( - jPermissions[i][sfPermission.jsonName] - [sfPermissionValue.jsonName] == permission); - i++; - } - }; + auto const& jPermissions = jle[jss::result][jss::node][sfPermissions.jsonName]; + unsigned i = 0; + for (auto const& permission : permissions) + { + BEAST_EXPECT(jPermissions[i][sfPermission.jsonName][sfPermissionValue.jsonName] == permission); + i++; + } + }; // get ledger entry with valid parameter - comparePermissions( - delegate::entry(env, gw, alice), permissions, gw, alice); + comparePermissions(delegate::entry(env, gw, alice), permissions, gw, alice); // gw updates permission - auto const newPermissions = std::vector{ - "Payment", "AMMCreate", "AMMDeposit", "AMMWithdraw"}; + auto const newPermissions = std::vector{"Payment", "AMMCreate", "AMMDeposit", "AMMWithdraw"}; env(delegate::set(gw, alice, newPermissions)); env.close(); // get ledger entry again, permissions should be updated to // newPermissions - comparePermissions( - delegate::entry(env, gw, alice), newPermissions, gw, alice); + comparePermissions(delegate::entry(env, gw, alice), newPermissions, gw, alice); // gw deletes all permissions delegated to alice, this will delete // the @@ -136,8 +99,7 @@ class Delegate_test : public beast::unit_test::suite // alice can delegate permissions to gw as well env(delegate::set(alice, gw, permissions)); env.close(); - comparePermissions( - delegate::entry(env, alice, gw), permissions, alice, gw); + comparePermissions(delegate::entry(env, alice, gw), permissions, alice, gw); auto const response = delegate::entry(env, gw, alice); // alice has not been granted any permissions by gw BEAST_EXPECT(response[jss::result][jss::error] == "entryNotFound"); @@ -216,18 +178,16 @@ class Delegate_test : public beast::unit_test::suite // when authorizing account which does not exist, should return // tecNO_TARGET { - env(delegate::set(gw, Account("unknown"), {"Payment"}), - ter(tecNO_TARGET)); + env(delegate::set(gw, Account("unknown"), {"Payment"}), ter(tecNO_TARGET)); } - // non-delegatable transaction + // non-delegable transaction { env(delegate::set(gw, alice, {"SetRegularKey"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"AccountSet"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"SignerListSet"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"DelegateSet"}), ter(temMALFORMED)); - env(delegate::set(gw, alice, {"EnableAmendment"}), - ter(temMALFORMED)); + env(delegate::set(gw, alice, {"EnableAmendment"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"UNLModify"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"SetFee"}), ter(temMALFORMED)); env(delegate::set(gw, alice, {"Batch"}), ter(temMALFORMED)); @@ -248,13 +208,11 @@ class Delegate_test : public beast::unit_test::suite Account carol{"carol"}; env.fund(drops(env.current()->fees().accountReserve(0)), alice); - env.fund( - drops(env.current()->fees().accountReserve(1)), bob, carol); + env.fund(drops(env.current()->fees().accountReserve(1)), bob, carol); env.close(); // alice does not have enough reserve to create Delegate - env(delegate::set(alice, bob, {"Payment"}), - ter(tecINSUFFICIENT_RESERVE)); + env(delegate::set(alice, bob, {"Payment"}), ter(tecINSUFFICIENT_RESERVE)); // bob has enough reserve env(delegate::set(bob, alice, {"Payment"})); @@ -262,8 +220,7 @@ class Delegate_test : public beast::unit_test::suite // now bob create another Delegate, he does not have // enough reserve - env(delegate::set(bob, carol, {"Payment"}), - ter(tecINSUFFICIENT_RESERVE)); + env(delegate::set(bob, carol, {"Payment"}), ter(tecINSUFFICIENT_RESERVE)); } // test reserve when sending transaction on behalf of other account @@ -282,10 +239,7 @@ class Delegate_test : public beast::unit_test::suite // bob set DID on behalf of alice, but alice does not have enough // reserve - env(did::set(alice), - did::uri("uri"), - delegate::as(bob), - ter(tecINSUFFICIENT_RESERVE)); + env(did::set(alice), did::uri("uri"), delegate::as(bob), ter(tecINSUFFICIENT_RESERVE)); // bob can set DID for himself because he has enough reserve env(did::set(bob), did::uri("uri")); @@ -312,10 +266,7 @@ class Delegate_test : public beast::unit_test::suite auto bobBalance = env.balance(bob); auto carolBalance = env.balance(carol); - env(pay(alice, carol, XRP(100)), - fee(XRP(2000)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(pay(alice, carol, XRP(100)), fee(XRP(2000)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(bob) == bobBalance); @@ -346,10 +297,7 @@ class Delegate_test : public beast::unit_test::suite auto bobBalance = env.balance(bob); auto carolBalance = env.balance(carol); - env(pay(alice, carol, XRP(100)), - fee(XRP(2000)), - delegate::as(bob), - ter(terINSUF_FEE_B)); + env(pay(alice, carol, XRP(100)), fee(XRP(2000)), delegate::as(bob), ter(terINSUF_FEE_B)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(bob) == bobBalance); @@ -364,10 +312,7 @@ class Delegate_test : public beast::unit_test::suite auto carolBalance = env.balance(carol); auto const feeAmt = XRP(10); - env(pay(alice, carol, XRP(20000)), - fee(feeAmt), - delegate::as(bob), - ter(tecUNFUNDED_PAYMENT)); + env(pay(alice, carol, XRP(20000)), fee(feeAmt), delegate::as(bob), ter(tecUNFUNDED_PAYMENT)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(bob) == bobBalance - feeAmt); @@ -442,8 +387,7 @@ class Delegate_test : public beast::unit_test::suite env(delegate::set(alice, bob, {"Payment"})); env.close(); - BEAST_EXPECT( - env.closed()->exists(keylet::delegate(alice.id(), bob.id()))); + BEAST_EXPECT(env.closed()->exists(keylet::delegate(alice.id(), bob.id()))); for (std::uint32_t i = 0; i < 256; ++i) env.close(); @@ -460,8 +404,7 @@ class Delegate_test : public beast::unit_test::suite BEAST_EXPECT(!env.closed()->exists(keylet::ownerDir(alice.id()))); BEAST_EXPECT(env.balance(bob) == bobBalance + aliceBalance - deleteFee); - BEAST_EXPECT( - !env.closed()->exists(keylet::delegate(alice.id(), bob.id()))); + BEAST_EXPECT(!env.closed()->exists(keylet::delegate(alice.id(), bob.id()))); } void @@ -520,14 +463,10 @@ class Delegate_test : public beast::unit_test::suite env.close(); // bob does not have permission to create check - env(check::create(alice, bob, XRP(10)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(check::create(alice, bob, XRP(10)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // carol does not have permission to create check - env(check::create(alice, bob, XRP(10)), - delegate::as(carol), - ter(terNO_DELEGATE_PERMISSION)); + env(check::create(alice, bob, XRP(10)), delegate::as(carol), ter(terNO_DELEGATE_PERMISSION)); } void @@ -560,9 +499,7 @@ class Delegate_test : public beast::unit_test::suite auto gw2Balance = env.balance(gw2, XRP); // delegate ledger object is not created yet - env(pay(gw, alice, USD(50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(pay(gw, alice, USD(50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.require(balance(bob, bobBalance)); // gw gives bob burn permission @@ -572,9 +509,7 @@ class Delegate_test : public beast::unit_test::suite gwBalance = env.balance(gw, XRP); // bob sends a payment transaction on behalf of gw - env(pay(gw, alice, USD(50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(pay(gw, alice, USD(50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); env.require(balance(bob, bobBalance)); @@ -588,9 +523,7 @@ class Delegate_test : public beast::unit_test::suite gwBalance = env.balance(gw, XRP); // can not send XRP - env(pay(gw, alice, XRP(50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(pay(gw, alice, XRP(50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); env.require(balance(bob, bobBalance)); @@ -675,9 +608,7 @@ class Delegate_test : public beast::unit_test::suite // bob can not mint on behalf of gw because he only has burn // permission - env(pay(gw, alice, USD(50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(pay(gw, alice, USD(50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); env.require(balance(bob, bobBalance)); @@ -784,8 +715,7 @@ class Delegate_test : public beast::unit_test::suite Account const gw{"gateway"}; MPTTester mpt(env, gw, {.holders = {alice, bob}}); - mpt.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mpt.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); mpt.authorize({.account = alice}); mpt.authorize({.account = bob}); @@ -821,8 +751,7 @@ class Delegate_test : public beast::unit_test::suite // Grant both granular permissions and tx level permission. { - env(delegate::set( - alice, bob, {"PaymentBurn", "PaymentMint", "Payment"})); + env(delegate::set(alice, bob, {"PaymentBurn", "PaymentMint", "Payment"})); env.close(); env(pay(alice, gw, MPT(50)), delegate::as(bob)); BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(50)); @@ -855,9 +784,7 @@ class Delegate_test : public beast::unit_test::suite env.close(); // bob can not create trustline on behalf of alice because he only // has unfreeze permission - env(trust(alice, gw["USD"](50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(alice, gw["USD"](50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); // alice creates trustline by herself @@ -869,70 +796,45 @@ class Delegate_test : public beast::unit_test::suite env.close(); // unsupported flags - env(trust(alice, gw["USD"](50), tfSetNoRipple), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(trust(alice, gw["USD"](50), tfClearNoRipple), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(trust(gw, gw["USD"](0), alice, tfSetDeepFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(trust(gw, gw["USD"](0), alice, tfClearDeepFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(alice, gw["USD"](50), tfSetNoRipple), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(trust(alice, gw["USD"](50), tfClearNoRipple), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfSetDeepFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfClearDeepFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); // supported flags with wrong permission - env(trust(gw, gw["USD"](0), alice, tfSetfAuth), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(trust(gw, gw["USD"](0), alice, tfSetFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfSetfAuth), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfSetFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); env(delegate::set(gw, bob, {"TrustlineAuthorize"})); env.close(); - env(trust(gw, gw["USD"](0), alice, tfClearFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfClearFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); // although trustline authorize is granted, bob can not change the // limit number - env(trust(gw, gw["USD"](50), alice, tfSetfAuth), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](50), alice, tfSetfAuth), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env.close(); // supported flags with correct permission env(trust(gw, gw["USD"](0), alice, tfSetfAuth), delegate::as(bob)); env.close(); - env(delegate::set( - gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); + env(delegate::set(gw, bob, {"TrustlineAuthorize", "TrustlineFreeze"})); env.close(); env(trust(gw, gw["USD"](0), alice, tfSetFreeze), delegate::as(bob)); env.close(); - env(delegate::set( - gw, bob, {"TrustlineAuthorize", "TrustlineUnfreeze"})); + env(delegate::set(gw, bob, {"TrustlineAuthorize", "TrustlineUnfreeze"})); env.close(); - env(trust(gw, gw["USD"](0), alice, tfClearFreeze), - delegate::as(bob)); + env(trust(gw, gw["USD"](0), alice, tfClearFreeze), delegate::as(bob)); env.close(); // but bob can not freeze trustline because he no longer has freeze // permission - env(trust(gw, gw["USD"](0), alice, tfSetFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, gw["USD"](0), alice, tfSetFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // cannot update LimitAmount with granular permission, both high and // low account - env(trust(alice, gw["USD"](100)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(trust(gw, alice["USD"](100)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(alice, gw["USD"](100)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(trust(gw, alice["USD"](100)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // can not set QualityIn or QualityOut auto tx = trust(alice, gw["USD"](50)); @@ -973,53 +875,34 @@ class Delegate_test : public beast::unit_test::suite env.close(); // bob does not have permission - env(trust(alice, gw["USD"](50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); - env(delegate::set( - alice, bob, {"TrustlineUnfreeze", "NFTokenCreateOffer"})); + env(trust(alice, gw["USD"](50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); + env(delegate::set(alice, bob, {"TrustlineUnfreeze", "NFTokenCreateOffer"})); env.close(); // bob still does not have permission - env(trust(alice, gw["USD"](50)), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(trust(alice, gw["USD"](50)), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // add TrustSet permission and some unrelated permission env(delegate::set( - alice, - bob, - {"TrustlineUnfreeze", - "NFTokenCreateOffer", - "TrustSet", - "AccountTransferRateSet"})); + alice, bob, {"TrustlineUnfreeze", "NFTokenCreateOffer", "TrustSet", "AccountTransferRateSet"})); env.close(); env(trust(alice, gw["USD"](50)), delegate::as(bob)); env.close(); env(delegate::set( - gw, - bob, - {"TrustlineUnfreeze", - "NFTokenCreateOffer", - "TrustSet", - "AccountTransferRateSet"})); + gw, bob, {"TrustlineUnfreeze", "NFTokenCreateOffer", "TrustSet", "AccountTransferRateSet"})); env.close(); // since bob has TrustSet permission, he does not need // TrustlineFreeze granular permission to freeze the trustline env(trust(gw, gw["USD"](0), alice, tfSetFreeze), delegate::as(bob)); - env(trust(gw, gw["USD"](0), alice, tfClearFreeze), - delegate::as(bob)); + env(trust(gw, gw["USD"](0), alice, tfClearFreeze), delegate::as(bob)); // bob can perform all the operations regarding TrustSet env(trust(gw, gw["USD"](0), alice, tfSetFreeze), delegate::as(bob)); - env(trust(gw, gw["USD"](0), alice, tfSetDeepFreeze), - delegate::as(bob)); - env(trust(gw, gw["USD"](0), alice, tfClearDeepFreeze), - delegate::as(bob)); + env(trust(gw, gw["USD"](0), alice, tfSetDeepFreeze), delegate::as(bob)); + env(trust(gw, gw["USD"](0), alice, tfClearDeepFreeze), delegate::as(bob)); env(trust(gw, gw["USD"](0), alice, tfSetfAuth), delegate::as(bob)); env(trust(alice, gw["USD"](50), tfSetNoRipple), delegate::as(bob)); - env(trust(alice, gw["USD"](50), tfClearNoRipple), - delegate::as(bob)); + env(trust(alice, gw["USD"](50), tfClearNoRipple), delegate::as(bob)); } // tfFullyCanonicalSig won't block delegated transaction @@ -1036,9 +919,7 @@ class Delegate_test : public beast::unit_test::suite env(delegate::set(gw, bob, {"TrustlineAuthorize"})); env.close(); - env(trust( - gw, gw["USD"](0), alice, tfSetfAuth | tfFullyCanonicalSig), - delegate::as(bob)); + env(trust(gw, gw["USD"](0), alice, tfSetfAuth | tfFullyCanonicalSig), delegate::as(bob)); } } @@ -1072,8 +953,7 @@ class Delegate_test : public beast::unit_test::suite // add granular permission related to AccountSet but is not the // correct permission for domain set - env(delegate::set( - alice, bob, {"TrustlineUnfreeze", "AccountEmailHashSet"})); + env(delegate::set(alice, bob, {"TrustlineUnfreeze", "AccountEmailHashSet"})); env.close(); env(jt, ter(terNO_DELEGATE_PERMISSION)); @@ -1106,8 +986,7 @@ class Delegate_test : public beast::unit_test::suite env(jt, ter(terNO_DELEGATE_PERMISSION)); // alice give granular permission of AccountEmailHashSet to bob - env(delegate::set( - alice, bob, {"AccountDomainSet", "AccountEmailHashSet"})); + env(delegate::set(alice, bob, {"AccountDomainSet", "AccountEmailHashSet"})); env.close(); env(jt); BEAST_EXPECT(to_string((*env.le(alice))[sfEmailHash]) == mh); @@ -1119,36 +998,24 @@ class Delegate_test : public beast::unit_test::suite env(jt, ter(terNO_DELEGATE_PERMISSION)); // alice give granular permission of AccountMessageKeySet to bob - env(delegate::set( - alice, - bob, - {"AccountDomainSet", - "AccountEmailHashSet", - "AccountMessageKeySet"})); + env(delegate::set(alice, bob, {"AccountDomainSet", "AccountEmailHashSet", "AccountMessageKeySet"})); env.close(); // bob can set message key for alice env(jt); - BEAST_EXPECT( - strHex((*env.le(alice))[sfMessageKey]) == - strHex(rkp.first.slice())); + BEAST_EXPECT(strHex((*env.le(alice))[sfMessageKey]) == strHex(rkp.first.slice())); jt[sfMessageKey] = ""; env(jt); BEAST_EXPECT(!env.le(alice)->isFieldPresent(sfMessageKey)); // bob does not have permission to set transfer rate for alice - env(rate(alice, 2.0), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(rate(alice, 2.0), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // alice give granular permission of AccountTransferRateSet to bob env(delegate::set( alice, bob, - {"AccountDomainSet", - "AccountEmailHashSet", - "AccountMessageKeySet", - "AccountTransferRateSet"})); + {"AccountDomainSet", "AccountEmailHashSet", "AccountMessageKeySet", "AccountTransferRateSet"})); env.close(); auto jtRate = rate(alice, 2.0); jtRate[sfDelegate] = bob.human(); @@ -1173,18 +1040,14 @@ class Delegate_test : public beast::unit_test::suite BEAST_EXPECT((*env.le(alice))[sfTickSize] == 8); // can not set asfRequireAuth flag for alice - env(fset(alice, asfRequireAuth), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, asfRequireAuth), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // reset Delegate will delete the Delegate // object env(delegate::set(alice, bob, {})); // bib still does not have permission to set asfRequireAuth for // alice - env(fset(alice, asfRequireAuth), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, asfRequireAuth), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // alice can set for herself env(fset(alice, asfRequireAuth)); env.require(flags(alice, asfRequireAuth)); @@ -1194,12 +1057,7 @@ class Delegate_test : public beast::unit_test::suite jt[sfTickSize] = 7; env(jt, ter(terNO_DELEGATE_PERMISSION)); - env(delegate::set( - alice, - bob, - {"AccountDomainSet", - "AccountEmailHashSet", - "AccountMessageKeySet"})); + env(delegate::set(alice, bob, {"AccountDomainSet", "AccountEmailHashSet", "AccountMessageKeySet"})); env.close(); // bob does not have permission to set wallet locater for alice @@ -1223,17 +1081,13 @@ class Delegate_test : public beast::unit_test::suite auto testSetClearFlag = [&](std::uint32_t flag) { // bob can not set flag on behalf of alice - env(fset(alice, flag), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, flag), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // alice set by herself env(fset(alice, flag)); env.close(); env.require(flags(alice, flag)); // bob can not clear on behalf of alice - env(fclear(alice, flag), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fclear(alice, flag), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); }; // testSetClearFlag(asfNoFreeze); @@ -1241,12 +1095,7 @@ class Delegate_test : public beast::unit_test::suite testSetClearFlag(asfAllowTrustLineClawback); // alice gives some granular permissions to bob - env(delegate::set( - alice, - bob, - {"AccountDomainSet", - "AccountEmailHashSet", - "AccountMessageKeySet"})); + env(delegate::set(alice, bob, {"AccountDomainSet", "AccountEmailHashSet", "AccountMessageKeySet"})); env.close(); testSetClearFlag(asfDefaultRipple); @@ -1260,15 +1109,11 @@ class Delegate_test : public beast::unit_test::suite testSetClearFlag(asfGlobalFreeze); // bob can not set asfAccountTxnID on behalf of alice - env(fset(alice, asfAccountTxnID), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, asfAccountTxnID), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env(fset(alice, asfAccountTxnID)); env.close(); BEAST_EXPECT(env.le(alice)->isFieldPresent(sfAccountTxnID)); - env(fclear(alice, asfAccountTxnID), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fclear(alice, asfAccountTxnID), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // bob can not set asfAuthorizedNFTokenMinter on behalf of alice Json::Value jt = fset(alice, asfAuthorizedNFTokenMinter); @@ -1277,36 +1122,24 @@ class Delegate_test : public beast::unit_test::suite env(jt, ter(terNO_DELEGATE_PERMISSION)); // bob gives alice some permissions - env(delegate::set( - bob, - alice, - {"AccountDomainSet", - "AccountEmailHashSet", - "AccountMessageKeySet"})); + env(delegate::set(bob, alice, {"AccountDomainSet", "AccountEmailHashSet", "AccountMessageKeySet"})); env.close(); // since we can not set asfNoFreeze if asfAllowTrustLineClawback is // set, which can not be clear either. Test alice set asfNoFreeze on // behalf of bob. - env(fset(alice, asfNoFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, asfNoFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); env(fset(bob, asfNoFreeze)); env.close(); env.require(flags(bob, asfNoFreeze)); // alice can not clear on behalf of bob - env(fclear(alice, asfNoFreeze), - delegate::as(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fclear(alice, asfNoFreeze), delegate::as(bob), ter(terNO_DELEGATE_PERMISSION)); // bob can not set asfDisableMaster on behalf of alice Account const bobKey{"bobKey", KeyType::secp256k1}; env(regkey(bob, bobKey)); env.close(); - env(fset(alice, asfDisableMaster), - delegate::as(bob), - sig(bob), - ter(terNO_DELEGATE_PERMISSION)); + env(fset(alice, asfDisableMaster), delegate::as(bob), sig(bob), ter(terNO_DELEGATE_PERMISSION)); } // tfFullyCanonicalSig won't block delegated transaction @@ -1317,8 +1150,7 @@ class Delegate_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob); env.close(); - env(delegate::set( - alice, bob, {"AccountDomainSet", "AccountEmailHashSet"})); + env(delegate::set(alice, bob, {"AccountDomainSet", "AccountEmailHashSet"})); env.close(); std::string const domain = "example.com"; @@ -1352,34 +1184,21 @@ class Delegate_test : public beast::unit_test::suite env.close(); // delegate ledger object is not created yet - mpt.set( - {.account = alice, - .flags = tfMPTLock, - .delegate = bob, - .err = terNO_DELEGATE_PERMISSION}); + mpt.set({.account = alice, .flags = tfMPTLock, .delegate = bob, .err = terNO_DELEGATE_PERMISSION}); // alice gives granular permission to bob of MPTokenIssuanceUnlock env(delegate::set(alice, bob, {"MPTokenIssuanceUnlock"})); env.close(); // bob does not have lock permission - mpt.set( - {.account = alice, - .flags = tfMPTLock, - .delegate = bob, - .err = terNO_DELEGATE_PERMISSION}); + mpt.set({.account = alice, .flags = tfMPTLock, .delegate = bob, .err = terNO_DELEGATE_PERMISSION}); // bob now has lock permission, but does not have unlock permission env(delegate::set(alice, bob, {"MPTokenIssuanceLock"})); env.close(); mpt.set({.account = alice, .flags = tfMPTLock, .delegate = bob}); - mpt.set( - {.account = alice, - .flags = tfMPTUnlock, - .delegate = bob, - .err = terNO_DELEGATE_PERMISSION}); + mpt.set({.account = alice, .flags = tfMPTUnlock, .delegate = bob, .err = terNO_DELEGATE_PERMISSION}); // now bob can lock and unlock - env(delegate::set( - alice, bob, {"MPTokenIssuanceLock", "MPTokenIssuanceUnlock"})); + env(delegate::set(alice, bob, {"MPTokenIssuanceLock", "MPTokenIssuanceUnlock"})); env.close(); mpt.set({.account = alice, .flags = tfMPTUnlock, .delegate = bob}); mpt.set({.account = alice, .flags = tfMPTLock, .delegate = bob}); @@ -1404,34 +1223,17 @@ class Delegate_test : public beast::unit_test::suite env.close(); mpt.set({.account = alice, .flags = tfMPTLock, .delegate = bob}); // bob does not have unlock permission - mpt.set( - {.account = alice, - .flags = tfMPTUnlock, - .delegate = bob, - .err = terNO_DELEGATE_PERMISSION}); + mpt.set({.account = alice, .flags = tfMPTUnlock, .delegate = bob, .err = terNO_DELEGATE_PERMISSION}); // alice gives bob some unrelated permission with // MPTokenIssuanceLock - env(delegate::set( - alice, - bob, - {"NFTokenMint", "MPTokenIssuanceLock", "NFTokenBurn"})); + env(delegate::set(alice, bob, {"NFTokenMint", "MPTokenIssuanceLock", "NFTokenBurn"})); env.close(); // bob can not unlock - mpt.set( - {.account = alice, - .flags = tfMPTUnlock, - .delegate = bob, - .err = terNO_DELEGATE_PERMISSION}); + mpt.set({.account = alice, .flags = tfMPTUnlock, .delegate = bob, .err = terNO_DELEGATE_PERMISSION}); // alice add MPTokenIssuanceSet to permissions - env(delegate::set( - alice, - bob, - {"NFTokenMint", - "MPTokenIssuanceLock", - "NFTokenBurn", - "MPTokenIssuanceSet"})); + env(delegate::set(alice, bob, {"NFTokenMint", "MPTokenIssuanceLock", "NFTokenBurn", "MPTokenIssuanceSet"})); mpt.set({.account = alice, .flags = tfMPTUnlock, .delegate = bob}); // alice can lock by herself mpt.set({.account = alice, .flags = tfMPTLock}); @@ -1455,10 +1257,7 @@ class Delegate_test : public beast::unit_test::suite // alice gives granular permission to bob of MPTokenIssuanceLock env(delegate::set(alice, bob, {"MPTokenIssuanceLock"})); env.close(); - mpt.set( - {.account = alice, - .flags = tfMPTLock | tfFullyCanonicalSig, - .delegate = bob}); + mpt.set({.account = alice, .flags = tfMPTLock | tfFullyCanonicalSig, .delegate = bob}); } } @@ -1482,10 +1281,7 @@ class Delegate_test : public beast::unit_test::suite auto bobBalance = env.balance(bob); auto carolBalance = env.balance(carol); - env(pay(alice, carol, XRP(100)), - fee(XRP(10)), - delegate::as(bob), - sig(bob)); + env(pay(alice, carol, XRP(100)), fee(XRP(10)), delegate::as(bob), sig(bob)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance - XRP(100)); BEAST_EXPECT(env.balance(bob) == bobBalance - XRP(10)); @@ -1513,11 +1309,7 @@ class Delegate_test : public beast::unit_test::suite auto bobBalance = env.balance(bob); auto carolBalance = env.balance(carol); - env(pay(alice, carol, XRP(100)), - fee(XRP(10)), - delegate::as(bob), - sig(alice), - ter(tefBAD_AUTH)); + env(pay(alice, carol, XRP(100)), fee(XRP(10)), delegate::as(bob), sig(alice), ter(tefBAD_AUTH)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(bob) == bobBalance); @@ -1617,10 +1409,7 @@ class Delegate_test : public beast::unit_test::suite auto dariaBalance = env.balance(daria); auto edwardBalance = env.balance(edward); - env(pay(alice, carol, XRP(100)), - fee(XRP(10)), - delegate::as(bob), - msig(daria, edward)); + env(pay(alice, carol, XRP(100)), fee(XRP(10)), delegate::as(bob), msig(daria, edward)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance - XRP(100)); BEAST_EXPECT(env.balance(bob) == bobBalance - XRP(10)); @@ -1657,11 +1446,7 @@ class Delegate_test : public beast::unit_test::suite auto dariaBalance = env.balance(daria); auto edwardBalance = env.balance(edward); - env(pay(alice, carol, XRP(100)), - fee(XRP(10)), - delegate::as(bob), - msig(daria, edward), - ter(tefBAD_QUORUM)); + env(pay(alice, carol, XRP(100)), fee(XRP(10)), delegate::as(bob), msig(daria, edward), ter(tefBAD_QUORUM)); env.close(); BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(bob) == bobBalance); @@ -1710,21 +1495,16 @@ class Delegate_test : public beast::unit_test::suite } void - testTxReqireFeatures(FeatureBitset features) + testTxRequireFeatures(FeatureBitset features) { testcase("test delegate disabled tx"); using namespace jtx; // map of tx and required feature. - // non-delegatable tx are not included. + // non-delegable tx are not included. // NFTokenMint, NFTokenBurn, NFTokenCreateOffer, NFTokenCancelOffer, // NFTokenAcceptOffer are not included, they are tested separately. std::unordered_map txRequiredFeatures{ - {"TicketCreate", featureTicketBatch}, - {"CheckCreate", featureChecks}, - {"CheckCash", featureChecks}, - {"CheckCancel", featureChecks}, - {"DepositPreauth", featureDepositPreauth}, {"Clawback", featureClawback}, {"AMMClawback", featureAMMClawback}, {"AMMCreate", featureAMM}, @@ -1765,8 +1545,7 @@ class Delegate_test : public beast::unit_test::suite // Can not delegate tx if any required feature disabled. { - auto txAmendmentDisabled = [&](FeatureBitset features, - std::string const& tx) { + auto txAmendmentDisabled = [&](FeatureBitset features, std::string const& tx) { BEAST_EXPECT(txRequiredFeatures.contains(tx)); Env env(*this, features - txRequiredFeatures[tx]); @@ -1825,9 +1604,9 @@ class Delegate_test : public beast::unit_test::suite testMultiSign(); testMultiSignQuorumNotMet(); testPermissionValue(all); - testTxReqireFeatures(all); + testTxRequireFeatures(all); } }; -BEAST_DEFINE_TESTSUITE(Delegate, app, ripple); +BEAST_DEFINE_TESTSUITE(Delegate, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/DeliverMin_test.cpp b/src/test/app/DeliverMin_test.cpp index a9373fb002..711b29cfa8 100644 --- a/src/test/app/DeliverMin_test.cpp +++ b/src/test/app/DeliverMin_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class DeliverMin_test : public beast::unit_test::suite @@ -43,35 +24,23 @@ public: env.close(); env.trust(USD(100), "alice", "bob", "carol"); env.close(); + env(pay("alice", "bob", USD(10)), deliver_min(USD(10)), ter(temBAD_AMOUNT)); + env(pay("alice", "bob", USD(10)), deliver_min(USD(-5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); + env(pay("alice", "bob", USD(10)), deliver_min(XRP(5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); env(pay("alice", "bob", USD(10)), - delivermin(USD(10)), - ter(temBAD_AMOUNT)); - env(pay("alice", "bob", USD(10)), - delivermin(USD(-5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay("alice", "bob", USD(10)), - delivermin(XRP(5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay("alice", "bob", USD(10)), - delivermin(Account("carol")["USD"](5)), - txflags(tfPartialPayment), - ter(temBAD_AMOUNT)); - env(pay("alice", "bob", USD(10)), - delivermin(USD(15)), + deliver_min(Account("carol")["USD"](5)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); + env(pay("alice", "bob", USD(10)), deliver_min(USD(15)), txflags(tfPartialPayment), ter(temBAD_AMOUNT)); env(pay(gw, "carol", USD(50))); env(offer("carol", XRP(5), USD(5))); env(pay("alice", "bob", USD(10)), paths(XRP), - delivermin(USD(7)), + deliver_min(USD(7)), txflags(tfPartialPayment), sendmax(XRP(5)), ter(tecPATH_PARTIAL)); - env.require(balance( - "alice", XRP(10000) - drops(env.current()->fees().base))); + env.require(balance("alice", XRP(10000) - drops(env.current()->fees().base))); env.require(balance("bob", XRP(10000))); } @@ -85,7 +54,7 @@ public: env(offer("bob", XRP(100), USD(100))); env(pay("alice", "alice", USD(10000)), paths(XRP), - delivermin(USD(100)), + deliver_min(USD(100)), txflags(tfPartialPayment), sendmax(XRP(100))); env.require(balance("alice", USD(100))); @@ -103,13 +72,13 @@ public: env(offer("bob", XRP(10000), USD(100))); env(pay("alice", "carol", USD(10000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(1000)), ter(tecPATH_PARTIAL)); env(pay("alice", "carol", USD(10000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(1100))); env.require(balance("bob", USD(0))); @@ -129,7 +98,7 @@ public: env(offer("dan", XRP(100), USD(100))); env(pay("alice", "carol", USD(10000)), paths(XRP), - delivermin(USD(200)), + deliver_min(USD(200)), txflags(tfPartialPayment), sendmax(XRP(200))); env.require(balance("bob", USD(0))); @@ -148,7 +117,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple); +BEAST_DEFINE_TESTSUITE(DeliverMin, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index ffe8c4448b..0cd7e7449c 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { // Helper function that returns the reserve on an account based on @@ -34,7 +15,7 @@ reserve(jtx::Env& env, std::uint32_t count) return env.current()->fees().accountReserve(count); } -// Helper function that returns true if acct has the lsfDepostAuth flag set. +// Helper function that returns true if acct has the lsfDepositAuth flag set. static bool hasDepositAuth(jtx::Env const& env, jtx::Account const& acct) { @@ -52,21 +33,6 @@ struct DepositAuth_test : public beast::unit_test::suite Account const alice{"alice"}; { - // featureDepositAuth is disabled. - Env env(*this, testable_amendments() - featureDepositAuth); - env.fund(XRP(10000), alice); - - // Note that, to support old behavior, invalid flags are ignored. - env(fset(alice, asfDepositAuth)); - env.close(); - BEAST_EXPECT(!hasDepositAuth(env, alice)); - - env(fclear(alice, asfDepositAuth)); - env.close(); - BEAST_EXPECT(!hasDepositAuth(env, alice)); - } - { - // featureDepositAuth is enabled. Env env(*this); env.fund(XRP(10000), alice); @@ -126,9 +92,7 @@ struct DepositAuth_test : public beast::unit_test::suite // Note that even though alice is paying bob in XRP, the payment // is still not allowed since the payment passes through an offer. - env(pay(alice, bob, drops(1)), - sendmax(USD(1)), - ter(tecNO_PERMISSION)); + env(pay(alice, bob, drops(1)), sendmax(USD(1)), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(bobXrpBalance == env.balance(bob, XRP)); @@ -239,14 +203,12 @@ struct DepositAuth_test : public beast::unit_test::suite // We should be able to pay bob the base reserve one more time. env(pay(alice, bob, reserve(env, 0) + drops(0))); env.close(); - BEAST_EXPECT( - env.balance(bob, XRP) == (reserve(env, 0) + reserve(env, 0))); + BEAST_EXPECT(env.balance(bob, XRP) == (reserve(env, 0) + reserve(env, 0))); // bob's above the threshold again. Any payment should fail. env(pay(alice, bob, drops(1)), ter(tecNO_PERMISSION)); env.close(); - BEAST_EXPECT( - env.balance(bob, XRP) == (reserve(env, 0) + reserve(env, 0))); + BEAST_EXPECT(env.balance(bob, XRP) == (reserve(env, 0) + reserve(env, 0))); // Take bob back down to a zero XRP balance. env(noop(bob), fee(env.balance(bob, XRP))); @@ -296,54 +258,41 @@ struct DepositAuth_test : public beast::unit_test::suite IOU const USD1(gw1["USD"]); IOU const USD2(gw2["USD"]); - auto testIssuer = [&](FeatureBitset const& features, - bool noRipplePrev, - bool noRippleNext, - bool withDepositAuth) { - assert(!withDepositAuth || features[featureDepositAuth]); + auto testIssuer = + [&](FeatureBitset const& features, bool noRipplePrev, bool noRippleNext, bool withDepositAuth) { + Env env(*this, features); - Env env(*this, features); + env.fund(XRP(10000), gw1, alice, bob); + env.close(); + env(trust(gw1, alice["USD"](10), noRipplePrev ? tfSetNoRipple : 0)); + env(trust(gw1, bob["USD"](10), noRippleNext ? tfSetNoRipple : 0)); + env.trust(USD1(10), alice, bob); - env.fund(XRP(10000), gw1, alice, bob); - env.close(); - env(trust(gw1, alice["USD"](10), noRipplePrev ? tfSetNoRipple : 0)); - env(trust(gw1, bob["USD"](10), noRippleNext ? tfSetNoRipple : 0)); - env.trust(USD1(10), alice, bob); + env(pay(gw1, alice, USD1(10))); - env(pay(gw1, alice, USD1(10))); + if (withDepositAuth) + env(fset(gw1, asfDepositAuth)); - if (withDepositAuth) - env(fset(gw1, asfDepositAuth)); + TER const result = (noRippleNext && noRipplePrev) ? TER{tecPATH_DRY} : TER{tesSUCCESS}; + env(pay(alice, bob, USD1(10)), path(gw1), ter(result)); + }; - TER const result = (noRippleNext && noRipplePrev) ? TER{tecPATH_DRY} - : TER{tesSUCCESS}; - env(pay(alice, bob, USD1(10)), path(gw1), ter(result)); - }; + auto testNonIssuer = + [&](FeatureBitset const& features, bool noRipplePrev, bool noRippleNext, bool withDepositAuth) { + Env env(*this, features); - auto testNonIssuer = [&](FeatureBitset const& features, - bool noRipplePrev, - bool noRippleNext, - bool withDepositAuth) { - assert(!withDepositAuth || features[featureDepositAuth]); + env.fund(XRP(10000), gw1, gw2, alice); + env.close(); + env(trust(alice, USD1(10), noRipplePrev ? tfSetNoRipple : 0)); + env(trust(alice, USD2(10), noRippleNext ? tfSetNoRipple : 0)); + env(pay(gw2, alice, USD2(10))); - Env env(*this, features); + if (withDepositAuth) + env(fset(alice, asfDepositAuth)); - env.fund(XRP(10000), gw1, gw2, alice); - env.close(); - env(trust(alice, USD1(10), noRipplePrev ? tfSetNoRipple : 0)); - env(trust(alice, USD2(10), noRippleNext ? tfSetNoRipple : 0)); - env(pay(gw2, alice, USD2(10))); - - if (withDepositAuth) - env(fset(alice, asfDepositAuth)); - - TER const result = (noRippleNext && noRipplePrev) ? TER{tecPATH_DRY} - : TER{tesSUCCESS}; - env(pay(gw1, gw2, USD2(10)), - path(alice), - sendmax(USD1(10)), - ter(result)); - }; + TER const result = (noRippleNext && noRipplePrev) ? TER{tecPATH_DRY} : TER{tesSUCCESS}; + env(pay(gw1, gw2, USD2(10)), path(alice), sendmax(USD1(10)), ter(result)); + }; // Test every combo of noRipplePrev, noRippleNext, and withDepositAuth for (int i = 0; i < 8; ++i) @@ -351,31 +300,9 @@ struct DepositAuth_test : public beast::unit_test::suite auto const noRipplePrev = i & 0x1; auto const noRippleNext = i & 0x2; auto const withDepositAuth = i & 0x4; - testIssuer( - testable_amendments() | featureDepositAuth, - noRipplePrev, - noRippleNext, - withDepositAuth); + testIssuer(testable_amendments(), noRipplePrev, noRippleNext, withDepositAuth); - if (!withDepositAuth) - testIssuer( - testable_amendments() - featureDepositAuth, - noRipplePrev, - noRippleNext, - withDepositAuth); - - testNonIssuer( - testable_amendments() | featureDepositAuth, - noRipplePrev, - noRippleNext, - withDepositAuth); - - if (!withDepositAuth) - testNonIssuer( - testable_amendments() - featureDepositAuth, - noRipplePrev, - noRippleNext, - withDepositAuth); + testNonIssuer(testable_amendments(), noRipplePrev, noRippleNext, withDepositAuth); } } @@ -398,8 +325,7 @@ ledgerEntryDepositPreauth( Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = acc.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); for (auto const& o : auth) { @@ -419,26 +345,6 @@ struct DepositPreauth_test : public beast::unit_test::suite Account const alice{"alice"}; Account const becky{"becky"}; { - // featureDepositPreauth is disabled. - Env env(*this, testable_amendments() - featureDepositPreauth); - env.fund(XRP(10000), alice, becky); - env.close(); - - // Should not be able to add a DepositPreauth to alice. - env(deposit::auth(alice, becky), ter(temDISABLED)); - env.close(); - env.require(owners(alice, 0)); - env.require(owners(becky, 0)); - - // Should not be able to remove a DepositPreauth from alice. - env(deposit::unauth(alice, becky), ter(temDISABLED)); - env.close(); - env.require(owners(alice, 0)); - env.require(owners(becky, 0)); - } - { - // featureDepositPreauth is enabled. The valid case is really - // simple: // o We should be able to add and remove an entry, and // o That entry should cost one reserve. // o The reserve should be returned when the entry is removed. @@ -584,7 +490,7 @@ struct DepositPreauth_test : public beast::unit_test::suite env.require(owners(carol, 1)); env.require(owners(becky, 0)); - // But carol can't meet the reserve for another preauthorization. + // But carol can't meet the reserve for another pre-authorization. env(deposit::auth(carol, alice), ter(tecINSUFFICIENT_RESERVE)); env.close(); env.require(owners(carol, 1)); @@ -621,8 +527,6 @@ struct DepositPreauth_test : public beast::unit_test::suite Account const gw{"gw"}; IOU const USD(gw["USD"]); - bool const supportsPreauth = {features[featureDepositPreauth]}; - { // The initial implementation of DepositAuth had a bug where an // account with the DepositAuth flag set could not make a payment @@ -638,8 +542,7 @@ struct DepositPreauth_test : public beast::unit_test::suite env(pay(gw, alice, USD(500))); env.close(); - env(offer(alice, XRP(100), USD(100), tfPassive), - require(offers(alice, 1))); + env(offer(alice, XRP(100), USD(100), tfPassive), require(offers(alice, 1))); env.close(); // becky pays herself USD (10) by consuming part of alice's offer. @@ -651,15 +554,8 @@ struct DepositPreauth_test : public beast::unit_test::suite env(fset(becky, asfDepositAuth)); env.close(); - // becky pays herself again. Whether it succeeds depends on - // whether featureDepositPreauth is enabled. - TER const expect{ - supportsPreauth ? TER{tesSUCCESS} : TER{tecNO_PERMISSION}}; - - env(pay(becky, becky, USD(10)), - path(~USD), - sendmax(XRP(10)), - ter(expect)); + // becky pays herself again. + env(pay(becky, becky, USD(10)), path(~USD), sendmax(XRP(10)), ter(tesSUCCESS)); env.close(); { @@ -671,29 +567,15 @@ struct DepositPreauth_test : public beast::unit_test::suite bool const supportsCredentials = features[featureCredentials]; - TER const expectCredentials( - supportsCredentials ? TER(tesSUCCESS) : TER(temDISABLED)); - TER const expectPayment( - !supportsCredentials - ? TER(temDISABLED) - : (!supportsPreauth ? TER(tecNO_PERMISSION) - : TER(tesSUCCESS))); - TER const expectDP( - !supportsPreauth - ? TER(temDISABLED) - : (!supportsCredentials ? TER(temDISABLED) - : TER(tesSUCCESS))); + TER const expectTer(!supportsCredentials ? TER(temDISABLED) : TER(tesSUCCESS)); - env(deposit::authCredentials(becky, {{carol, credType}}), - ter(expectDP)); + env(deposit::authCredentials(becky, {{carol, credType}}), ter(expectTer)); env.close(); // gw accept credentials - env(credentials::create(gw, carol, credType), - ter(expectCredentials)); + env(credentials::create(gw, carol, credType), ter(expectTer)); env.close(); - env(credentials::accept(gw, carol, credType), - ter(expectCredentials)); + env(credentials::accept(gw, carol, credType), ter(expectTer)); env.close(); auto jv = credentials::ledgerEntry(env, gw, carol, credType); @@ -702,117 +584,94 @@ struct DepositPreauth_test : public beast::unit_test::suite : "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6" "EA288BE4"; - env(pay(gw, becky, USD(100)), - credentials::ids({credIdx}), - ter(expectPayment)); + env(pay(gw, becky, USD(100)), credentials::ids({credIdx}), ter(expectTer)); env.close(); } - - { - using namespace std::chrono; - - if (!supportsPreauth) - { - auto const seq1 = env.seq(alice); - env(escrow::create(alice, becky, XRP(100)), - escrow::finish_time(env.now() + 1s)); - env.close(); - - // Failed as rule is disabled - env(escrow::finish(gw, alice, seq1), - fee(1500), - ter(tecNO_PERMISSION)); - env.close(); - } - } } - if (supportsPreauth) - { - // Make sure DepositPreauthorization works for payments. + // Make sure DepositPreauthorization works for payments. - Account const carol{"carol"}; + Account const carol{"carol"}; - Env env(*this, features); - env.fund(XRP(5000), alice, becky, carol, gw); - env.close(); + Env env(*this, features); + env.fund(XRP(5000), alice, becky, carol, gw); + env.close(); - env.trust(USD(1000), alice); - env.trust(USD(1000), becky); - env.trust(USD(1000), carol); - env.close(); + env.trust(USD(1000), alice); + env.trust(USD(1000), becky); + env.trust(USD(1000), carol); + env.close(); - env(pay(gw, alice, USD(1000))); - env.close(); + env(pay(gw, alice, USD(1000))); + env.close(); - // Make XRP and IOU payments from alice to becky. Should be fine. - env(pay(alice, becky, XRP(100))); - env(pay(alice, becky, USD(100))); - env.close(); + // Make XRP and IOU payments from alice to becky. Should be fine. + env(pay(alice, becky, XRP(100))); + env(pay(alice, becky, USD(100))); + env.close(); - // becky decides to require authorization for deposits. - env(fset(becky, asfDepositAuth)); - env.close(); + // becky decides to require authorization for deposits. + env(fset(becky, asfDepositAuth)); + env.close(); - // alice can no longer pay becky. - env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); - env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); - env.close(); + // alice can no longer pay becky. + env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); + env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); + env.close(); - // becky preauthorizes carol for deposit, which doesn't provide - // authorization for alice. - env(deposit::auth(becky, carol)); - env.close(); + // becky preauthorizes carol for deposit, which doesn't provide + // authorization for alice. + env(deposit::auth(becky, carol)); + env.close(); - // alice still can't pay becky. - env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); - env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); - env.close(); + // alice still can't pay becky. + env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); + env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); + env.close(); - // becky preauthorizes alice for deposit. - env(deposit::auth(becky, alice)); - env.close(); + // becky preauthorizes alice for deposit. + env(deposit::auth(becky, alice)); + env.close(); - // alice can now pay becky. - env(pay(alice, becky, XRP(100))); - env(pay(alice, becky, USD(100))); - env.close(); + // alice can now pay becky. + env(pay(alice, becky, XRP(100))); + env(pay(alice, becky, USD(100))); + env.close(); - // alice decides to require authorization for deposits. - env(fset(alice, asfDepositAuth)); - env.close(); + // alice decides to require authorization for deposits. + env(fset(alice, asfDepositAuth)); + env.close(); - // Even though alice is authorized to pay becky, becky is not - // authorized to pay alice. - env(pay(becky, alice, XRP(100)), ter(tecNO_PERMISSION)); - env(pay(becky, alice, USD(100)), ter(tecNO_PERMISSION)); - env.close(); + // Even though alice is authorized to pay becky, becky is not + // authorized to pay alice. + env(pay(becky, alice, XRP(100)), ter(tecNO_PERMISSION)); + env(pay(becky, alice, USD(100)), ter(tecNO_PERMISSION)); + env.close(); - // becky unauthorizes carol. Should have no impact on alice. - env(deposit::unauth(becky, carol)); - env.close(); + // becky unauthorizes carol. Should have no impact on alice. + env(deposit::unauth(becky, carol)); + env.close(); - env(pay(alice, becky, XRP(100))); - env(pay(alice, becky, USD(100))); - env.close(); + env(pay(alice, becky, XRP(100))); + env(pay(alice, becky, USD(100))); + env.close(); - // becky unauthorizes alice. alice now can't pay becky. - env(deposit::unauth(becky, alice)); - env.close(); + // becky unauthorizes alice. alice now can't pay becky. + env(deposit::unauth(becky, alice)); + env.close(); - env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); - env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); - env.close(); + env(pay(alice, becky, XRP(100)), ter(tecNO_PERMISSION)); + env(pay(alice, becky, USD(100)), ter(tecNO_PERMISSION)); + env.close(); - // becky decides to remove authorization for deposits. Now - // alice can pay becky again. - env(fclear(becky, asfDepositAuth)); - env.close(); + // becky decides to remove authorization for deposits. Now + // alice can pay becky again. + env(fclear(becky, asfDepositAuth)); + env.close(); - env(pay(alice, becky, XRP(100))); - env(pay(alice, becky, USD(100))); - env.close(); - } + env(pay(alice, becky, XRP(100))); + env(pay(alice, becky, USD(100))); + env.close(); } void @@ -835,27 +694,24 @@ struct DepositPreauth_test : public beast::unit_test::suite env.fund(XRP(5000), issuer, bob, alice); env.close(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); // Setup DepositPreauth object failed - amendent is not supported - env(deposit::authCredentials(bob, {{issuer, credType}}), - ter(temDISABLED)); + env(deposit::authCredentials(bob, {{issuer, credType}}), ter(temDISABLED)); env.close(); // But can create old DepositPreauth env(deposit::auth(bob, alice)); env.close(); - // And alice can't pay with any credentials, amendement is not + // And alice can't pay with any credentials, amendment is not // enabled std::string const invalidIdx = "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" "01E034"; - env(pay(alice, bob, XRP(10)), - credentials::ids({invalidIdx}), - ter(temDISABLED)); + env(pay(alice, bob, XRP(10)), credentials::ids({invalidIdx}), ter(temDISABLED)); env.close(); } @@ -872,28 +728,23 @@ struct DepositPreauth_test : public beast::unit_test::suite env.close(); // Get the index of the credentials - auto const jv = - credentials::ledgerEntry(env, alice, issuer, credType); + auto const jv = credentials::ledgerEntry(env, alice, issuer, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); - // Bob will accept payements from accounts with credentials signed + // Bob will accept payments from accounts with credentials signed // by 'issuer' env(deposit::authCredentials(bob, {{issuer, credType}})); env.close(); - auto const jDP = - ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); BEAST_EXPECT( - jDP.isObject() && jDP.isMember(jss::result) && - !jDP[jss::result].isMember(jss::error) && - jDP[jss::result].isMember(jss::node) && - jDP[jss::result][jss::node].isMember("LedgerEntryType") && - jDP[jss::result][jss::node]["LedgerEntryType"] == - jss::DepositPreauth); + jDP.isObject() && jDP.isMember(jss::result) && !jDP[jss::result].isMember(jss::error) && + jDP[jss::result].isMember(jss::node) && jDP[jss::result][jss::node].isMember("LedgerEntryType") && + jDP[jss::result][jss::node]["LedgerEntryType"] == jss::DepositPreauth); // Alice can't pay - empty credentials array { @@ -904,9 +755,7 @@ struct DepositPreauth_test : public beast::unit_test::suite } // Alice can't pay - not accepted credentials - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); env.close(); // Alice accept the credentials @@ -944,31 +793,26 @@ struct DepositPreauth_test : public beast::unit_test::suite env(credentials::accept(alice, issuer, credType)); env.close(); // Get the index of the credentials - auto const jv = - credentials::ledgerEntry(env, alice, issuer, credType); + auto const jv = credentials::ledgerEntry(env, alice, issuer, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); { - // Success as destination didn't enable preauthorization so + // Success as destination didn't enable pre-authorization so // valid credentials will not fail env(pay(alice, bob, XRP(100)), credentials::ids({credIdx})); } - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); { // Fail as destination didn't setup DepositPreauth object - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx}), - ter(tecNO_PERMISSION)); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx}), ter(tecNO_PERMISSION)); } // Bob setup DepositPreauth object, duplicates is not allowed - env(deposit::authCredentials( - bob, {{issuer, credType}, {issuer, credType}}), - ter(temMALFORMED)); + env(deposit::authCredentials(bob, {{issuer, credType}, {issuer, credType}}), ter(temMALFORMED)); // Bob setup DepositPreauth object env(deposit::authCredentials(bob, {{issuer, credType}})); @@ -979,16 +823,12 @@ struct DepositPreauth_test : public beast::unit_test::suite "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" "01E034"; // Alice can't pay with non-existing credentials - env(pay(alice, bob, XRP(100)), - credentials::ids({invalidIdx}), - ter(tecBAD_CREDENTIALS)); + env(pay(alice, bob, XRP(100)), credentials::ids({invalidIdx}), ter(tecBAD_CREDENTIALS)); } { // maria can't pay using valid credentials but issued for // different account - env(pay(maria, bob, XRP(100)), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(pay(maria, bob, XRP(100)), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); } { @@ -998,21 +838,15 @@ struct DepositPreauth_test : public beast::unit_test::suite env.close(); env(credentials::accept(alice, issuer, credType2)); env.close(); - auto const jv = - credentials::ledgerEntry(env, alice, issuer, credType2); - std::string const credIdx2 = - jv[jss::result][jss::index].asString(); + auto const jv = credentials::ledgerEntry(env, alice, issuer, credType2); + std::string const credIdx2 = jv[jss::result][jss::index].asString(); // Alice can't pay with invalid set of valid credentials - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx, credIdx2}), - ter(tecNO_PERMISSION)); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx, credIdx2}), ter(tecNO_PERMISSION)); } // Error, duplicate credentials - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx, credIdx}), - ter(temMALFORMED)); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx, credIdx}), ter(temMALFORMED)); // Alice can pay env(pay(alice, bob, XRP(100)), credentials::ids({credIdx})); @@ -1086,8 +920,7 @@ struct DepositPreauth_test : public beast::unit_test::suite auto& arr(jv[sfAuthorizeCredentials.jsonName]); Json::Value cred = Json::objectValue; cred[jss::Issuer] = to_string(xrpAccount()); - cred[sfCredentialType.jsonName] = - strHex(std::string_view(credType)); + cred[sfCredentialType.jsonName] = strHex(std::string_view(credType)); Json::Value credParent; credParent[jss::Credential] = cred; arr.append(std::move(credParent)); @@ -1103,20 +936,10 @@ struct DepositPreauth_test : public beast::unit_test::suite { // AuthorizeCredentials is larger than 8 elements - Account const a("a"), b("b"), c("c"), d("d"), e("e"), f("f"), - g("g"), h("h"), i("i"); + Account const a("a"), b("b"), c("c"), d("d"), e("e"), f("f"), g("g"), h("h"), i("i"); auto const& z = credType; auto jv = deposit::authCredentials( - bob, - {{a, z}, - {b, z}, - {c, z}, - {d, z}, - {e, z}, - {f, z}, - {g, z}, - {h, z}, - {i, z}}); + bob, {{a, z}, {b, z}, {c, z}, {d, z}, {e, z}, {f, z}, {g, z}, {h, z}, {i, z}}); env(jv, ter(temARRAY_TOO_LARGE)); } @@ -1139,8 +962,7 @@ struct DepositPreauth_test : public beast::unit_test::suite { // NO deposit object exists - env(deposit::unauthCredentials(bob, {{issuer, credType}}), - ter(tecNO_ENTRY)); + env(deposit::unauthCredentials(bob, {{issuer, credType}}), ter(tecNO_ENTRY)); } // Create DepositPreauth object @@ -1148,45 +970,34 @@ struct DepositPreauth_test : public beast::unit_test::suite env(deposit::authCredentials(bob, {{issuer, credType}})); env.close(); - auto const jDP = - ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); BEAST_EXPECT( - jDP.isObject() && jDP.isMember(jss::result) && - !jDP[jss::result].isMember(jss::error) && - jDP[jss::result].isMember(jss::node) && - jDP[jss::result][jss::node].isMember("LedgerEntryType") && - jDP[jss::result][jss::node]["LedgerEntryType"] == - jss::DepositPreauth); + jDP.isObject() && jDP.isMember(jss::result) && !jDP[jss::result].isMember(jss::error) && + jDP[jss::result].isMember(jss::node) && jDP[jss::result][jss::node].isMember("LedgerEntryType") && + jDP[jss::result][jss::node]["LedgerEntryType"] == jss::DepositPreauth); // Check object fields - BEAST_EXPECT( - jDP[jss::result][jss::node][jss::Account] == bob.human()); - auto const& credentials( - jDP[jss::result][jss::node]["AuthorizeCredentials"]); + BEAST_EXPECT(jDP[jss::result][jss::node][jss::Account] == bob.human()); + auto const& credentials(jDP[jss::result][jss::node]["AuthorizeCredentials"]); BEAST_EXPECT(credentials.isArray() && credentials.size() == 1); for (auto const& o : credentials) { auto const& c(o[jss::Credential]); BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human()); - BEAST_EXPECT( - c["CredentialType"].asString() == - strHex(std::string_view(credType))); + BEAST_EXPECT(c["CredentialType"].asString() == strHex(std::string_view(credType))); } // can't create duplicate - env(deposit::authCredentials(bob, {{issuer, credType}}), - ter(tecDUPLICATE)); + env(deposit::authCredentials(bob, {{issuer, credType}}), ter(tecDUPLICATE)); } // Delete DepositPreauth object { env(deposit::unauthCredentials(bob, {{issuer, credType}})); env.close(); - auto const jDP = - ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); BEAST_EXPECT( - jDP.isObject() && jDP.isMember(jss::result) && - jDP[jss::result].isMember(jss::error) && + jDP.isObject() && jDP.isMember(jss::result) && jDP[jss::result].isMember(jss::error) && jDP[jss::result][jss::error] == "entryNotFound"); } } @@ -1217,11 +1028,7 @@ struct DepositPreauth_test : public beast::unit_test::suite auto jv = credentials::create(alice, issuer, credType); // Current time in ripple epoch. // Every time ledger close, unittest timer increase by 10s - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 60; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 60; jv[sfExpiration.jsonName] = t; env(jv); env.close(); @@ -1232,11 +1039,7 @@ struct DepositPreauth_test : public beast::unit_test::suite // Create credential which not expired jv = credentials::create(alice, issuer, credType2); - uint32_t const t2 = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 1000; + uint32_t const t2 = env.current()->header().parentCloseTime.time_since_epoch().count() + 1000; jv[sfExpiration.jsonName] = t2; env(jv); env.close(); @@ -1252,31 +1055,26 @@ struct DepositPreauth_test : public beast::unit_test::suite jv = credentials::ledgerEntry(env, alice, issuer, credType2); std::string const credIdx2 = jv[jss::result][jss::index].asString(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); // Bob setup DepositPreauth object - env(deposit::authCredentials( - bob, {{issuer, credType}, {issuer, credType2}})); + env(deposit::authCredentials(bob, {{issuer, credType}, {issuer, credType2}})); env.close(); { // Alice can pay - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx, credIdx2})); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx, credIdx2})); env.close(); env.close(); // Ledger closed, time increased, alice can't pay anymore - env(pay(alice, bob, XRP(100)), - credentials::ids({credIdx, credIdx2}), - ter(tecEXPIRED)); + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx, credIdx2}), ter(tecEXPIRED)); env.close(); { // check that expired credentials were deleted - auto const jDelCred = - credentials::ledgerEntry(env, alice, issuer, credType); + auto const jDelCred = credentials::ledgerEntry(env, alice, issuer, credType); BEAST_EXPECT( jDelCred.isObject() && jDelCred.isMember(jss::result) && jDelCred[jss::result].isMember(jss::error) && @@ -1285,22 +1083,15 @@ struct DepositPreauth_test : public beast::unit_test::suite { // check that non-expired credential still present - auto const jle = - credentials::ledgerEntry(env, alice, issuer, credType2); + auto const jle = credentials::ledgerEntry(env, alice, issuer, credType2); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember( - "LedgerEntryType") && - jle[jss::result][jss::node]["LedgerEntryType"] == - jss::Credential && - jle[jss::result][jss::node][jss::Issuer] == - issuer.human() && - jle[jss::result][jss::node][jss::Subject] == - alice.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType2))); + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == issuer.human() && + jle[jss::result][jss::node][jss::Subject] == alice.human() && + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType2))); } BEAST_EXPECT(ownerCount(env, issuer) == 0); @@ -1309,11 +1100,7 @@ struct DepositPreauth_test : public beast::unit_test::suite { auto jv = credentials::create(gw, issuer, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 40; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 40; jv[sfExpiration.jsonName] = t; env(jv); env.close(); @@ -1321,8 +1108,7 @@ struct DepositPreauth_test : public beast::unit_test::suite env.close(); jv = credentials::ledgerEntry(env, gw, issuer, credType); - std::string const credIdx = - jv[jss::result][jss::index].asString(); + std::string const credIdx = jv[jss::result][jss::index].asString(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, gw) == 1); @@ -1332,18 +1118,14 @@ struct DepositPreauth_test : public beast::unit_test::suite env.close(); // credentials are expired - env(pay(gw, bob, USD(150)), - credentials::ids({credIdx}), - ter(tecEXPIRED)); + env(pay(gw, bob, USD(150)), credentials::ids({credIdx}), ter(tecEXPIRED)); env.close(); // check that expired credentials were deleted - auto const jDelCred = - credentials::ledgerEntry(env, gw, issuer, credType); + auto const jDelCred = credentials::ledgerEntry(env, gw, issuer, credType); BEAST_EXPECT( jDelCred.isObject() && jDelCred.isMember(jss::result) && - jDelCred[jss::result].isMember(jss::error) && - jDelCred[jss::result][jss::error] == "entryNotFound"); + jDelCred[jss::result].isMember(jss::error) && jDelCred[jss::result][jss::error] == "entryNotFound"); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, gw) == 0); @@ -1362,11 +1144,7 @@ struct DepositPreauth_test : public beast::unit_test::suite // Create credentials auto jv = credentials::create(zelda, issuer, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 50; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 50; jv[sfExpiration.jsonName] = t; env(jv); env.close(); @@ -1379,7 +1157,7 @@ struct DepositPreauth_test : public beast::unit_test::suite jv = credentials::ledgerEntry(env, zelda, issuer, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); // Bob setup DepositPreauth object @@ -1387,15 +1165,12 @@ struct DepositPreauth_test : public beast::unit_test::suite env.close(); auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 1s)); env.close(); // zelda can't finish escrow with invalid credentials { - env(escrow::finish(zelda, alice, seq), - credentials::ids({}), - ter(temMALFORMED)); + env(escrow::finish(zelda, alice, seq), credentials::ids({}), ter(temMALFORMED)); env.close(); } @@ -1405,26 +1180,19 @@ struct DepositPreauth_test : public beast::unit_test::suite "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" "01E034"; - env(escrow::finish(zelda, alice, seq), - credentials::ids({invalidIdx}), - ter(tecBAD_CREDENTIALS)); + env(escrow::finish(zelda, alice, seq), credentials::ids({invalidIdx}), ter(tecBAD_CREDENTIALS)); env.close(); } { // Ledger closed, time increased, zelda can't finish escrow - env(escrow::finish(zelda, alice, seq), - credentials::ids({credIdx}), - fee(1500), - ter(tecEXPIRED)); + env(escrow::finish(zelda, alice, seq), credentials::ids({credIdx}), fee(1500), ter(tecEXPIRED)); env.close(); } // check that expired credentials were deleted - auto const jDelCred = - credentials::ledgerEntry(env, zelda, issuer, credType); + auto const jDelCred = credentials::ledgerEntry(env, zelda, issuer, credType); BEAST_EXPECT( - jDelCred.isObject() && jDelCred.isMember(jss::result) && - jDelCred[jss::result].isMember(jss::error) && + jDelCred.isObject() && jDelCred.isMember(jss::result) && jDelCred[jss::result].isMember(jss::error) && jDelCred[jss::result][jss::error] == "entryNotFound"); } } @@ -1445,14 +1213,7 @@ struct DepositPreauth_test : public beast::unit_test::suite env.fund(XRP(5000), stock, alice, bob); std::vector credentials = { - {"a", "a"}, - {"b", "b"}, - {"c", "c"}, - {"d", "d"}, - {"e", "e"}, - {"f", "f"}, - {"g", "g"}, - {"h", "h"}}; + {"a", "a"}, {"b", "b"}, {"c", "c"}, {"d", "d"}, {"e", "e"}, {"f", "f"}, {"g", "g"}, {"h", "h"}}; for (auto const& c : credentials) env.fund(XRP(5000), c.issuer); @@ -1473,26 +1234,20 @@ struct DepositPreauth_test : public beast::unit_test::suite env(deposit::authCredentials(stock, credentials)); env.close(); - auto const dp = - ledgerEntryDepositPreauth(env, stock, credentials); - auto const& authCred( - dp[jss::result][jss::node]["AuthorizeCredentials"]); - BEAST_EXPECT( - authCred.isArray() && - authCred.size() == credentials.size()); - std::vector> readedCreds; + auto const dp = ledgerEntryDepositPreauth(env, stock, credentials); + auto const& authCred(dp[jss::result][jss::node]["AuthorizeCredentials"]); + BEAST_EXPECT(authCred.isArray() && authCred.size() == credentials.size()); + std::vector> readCreds; for (auto const& o : authCred) { auto const& c(o[jss::Credential]); auto issuer = c[jss::Issuer].asString(); if (BEAST_EXPECT(pubKey2Acc.contains(issuer))) - readedCreds.emplace_back( - pubKey2Acc.at(issuer), - c["CredentialType"].asString()); + readCreds.emplace_back(pubKey2Acc.at(issuer), c["CredentialType"].asString()); } - BEAST_EXPECT(std::ranges::is_sorted(readedCreds)); + BEAST_EXPECT(std::ranges::is_sorted(readCreds)); env(deposit::unauthCredentials(stock, credentials)); env.close(); @@ -1508,24 +1263,21 @@ struct DepositPreauth_test : public beast::unit_test::suite for (int i = 0; i < 10; ++i) { std::ranges::shuffle(credentials, gen); - env(deposit::authCredentials(stock, credentials), - ter(tecDUPLICATE)); + env(deposit::authCredentials(stock, credentials), ter(tecDUPLICATE)); } } testcase("Check duplicate credentials."); { // check duplicates in depositPreauth params - std::vector copyCredentials( - credentials.begin(), credentials.end() - 1); + std::vector copyCredentials(credentials.begin(), credentials.end() - 1); std::ranges::shuffle(copyCredentials, gen); for (auto const& c : copyCredentials) { auto credentials2 = copyCredentials; credentials2.push_back(c); - env(deposit::authCredentials(stock, credentials2), - ter(temMALFORMED)); + env(deposit::authCredentials(stock, credentials2), ter(temMALFORMED)); } // create batch of credentials and save their hashes @@ -1537,12 +1289,8 @@ struct DepositPreauth_test : public beast::unit_test::suite env(credentials::accept(alice, c.issuer, c.credType)); env.close(); - credentialIDs.push_back(credentials::ledgerEntry( - env, - alice, - c.issuer, - c.credType)[jss::result][jss::index] - .asString()); + credentialIDs.push_back( + credentials::ledgerEntry(env, alice, c.issuer, c.credType)[jss::result][jss::index].asString()); } // check duplicates in payment params @@ -1551,9 +1299,7 @@ struct DepositPreauth_test : public beast::unit_test::suite auto credentialIDs2 = credentialIDs; credentialIDs2.push_back(h); - env(pay(alice, bob, XRP(100)), - credentials::ids(credentialIDs2), - ter(temMALFORMED)); + env(pay(alice, bob, XRP(100)), credentials::ids(credentialIDs2), ter(temMALFORMED)); } } } @@ -1564,8 +1310,6 @@ struct DepositPreauth_test : public beast::unit_test::suite testEnable(); testInvalid(); auto const supported{jtx::testable_amendments()}; - testPayment(supported - featureDepositPreauth - featureCredentials); - testPayment(supported - featureDepositPreauth); testPayment(supported - featureCredentials); testPayment(supported); testCredentialsPayment(); @@ -1575,8 +1319,8 @@ struct DepositPreauth_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(DepositAuth, app, ripple); -BEAST_DEFINE_TESTSUITE(DepositPreauth, app, ripple); +BEAST_DEFINE_TESTSUITE(DepositAuth, app, xrpl); +BEAST_DEFINE_TESTSUITE(DepositPreauth, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Discrepancy_test.cpp b/src/test/app/Discrepancy_test.cpp index da41969885..b56cb5b7c6 100644 --- a/src/test/app/Discrepancy_test.cpp +++ b/src/test/app/Discrepancy_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { class Discrepancy_test : public beast::unit_test::suite { @@ -88,20 +69,14 @@ class Discrepancy_test : public beast::unit_test::suite env.close(); test::PathSet payPaths{ - test::Path{A2["JPY"], A2}, - test::Path{XRP, A2["JPY"], A2}, - test::Path{A6, XRP, A2["JPY"], A2}}; + test::Path{A2["JPY"], A2}, test::Path{XRP, A2["JPY"], A2}, test::Path{A6, XRP, A2["JPY"], A2}}; - env(pay(A1, A1, A2["JPY"](1000)), - json(payPaths.json()), - txflags(tfPartialPayment), - sendmax(A3["CNY"](56))); + env(pay(A1, A1, A2["JPY"](1000)), json(payPaths.json()), txflags(tfPartialPayment), sendmax(A3["CNY"](56))); env.close(); Json::Value jrq2; jrq2[jss::binary] = false; - jrq2[jss::transaction] = - env.tx()->getJson(JsonOptions::none)[jss::hash]; + jrq2[jss::transaction] = env.tx()->getJson(JsonOptions::none)[jss::hash]; jrq2[jss::id] = 3; auto jrr = env.rpc("json", "tx", to_string(jrq2))[jss::result]; uint64_t fee{jrr[jss::Fee].asUInt()}; @@ -121,19 +96,14 @@ class Discrepancy_test : public beast::unit_test::suite if (node && node[sfLedgerEntryType.fieldName] == jss::AccountRoot) { - Json::Value prevFields = - node.isMember(sfPreviousFields.fieldName) - ? node[sfPreviousFields.fieldName] - : node[sfNewFields.fieldName]; - Json::Value finalFields = node.isMember(sfFinalFields.fieldName) - ? node[sfFinalFields.fieldName] - : node[sfNewFields.fieldName]; + Json::Value prevFields = node.isMember(sfPreviousFields.fieldName) ? node[sfPreviousFields.fieldName] + : node[sfNewFields.fieldName]; + Json::Value finalFields = node.isMember(sfFinalFields.fieldName) ? node[sfFinalFields.fieldName] + : node[sfNewFields.fieldName]; if (prevFields) - sumPrev += beast::lexicalCastThrow( - prevFields[sfBalance.fieldName].asString()); + sumPrev += beast::lexicalCastThrow(prevFields[sfBalance.fieldName].asString()); if (finalFields) - sumFinal += beast::lexicalCastThrow( - finalFields[sfBalance.fieldName].asString()); + sumFinal += beast::lexicalCastThrow(finalFields[sfBalance.fieldName].asString()); } } // the difference in balances (final and prev) should be the @@ -152,6 +122,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Discrepancy, app, ripple); +BEAST_DEFINE_TESTSUITE(Discrepancy, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/EscrowToken_test.cpp b/src/test/app/EscrowToken_test.cpp index 8535582af9..1f3b3bab70 100644 --- a/src/test/app/EscrowToken_test.cpp +++ b/src/test/app/EscrowToken_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -32,16 +13,13 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct EscrowToken_test : public beast::unit_test::suite { static uint64_t - mptEscrowed( - jtx::Env const& env, - jtx::Account const& account, - jtx::MPT const& mpt) + mptEscrowed(jtx::Env const& env, jtx::Account const& account, jtx::MPT const& mpt) { auto const sle = env.le(keylet::mptoken(mpt.mpt(), account)); if (sle && sle->isFieldPresent(sfLockedAmount)) @@ -59,17 +37,13 @@ struct EscrowToken_test : public beast::unit_test::suite } jtx::PrettyAmount - issuerBalance( - jtx::Env& env, - jtx::Account const& account, - Issue const& issue) + issuerBalance(jtx::Env& env, jtx::Account const& account, Issue const& issue) { Json::Value params; params[jss::account] = account.human(); auto jrr = env.rpc("json", "gateway_balances", to_string(params)); auto const result = jrr[jss::result]; - auto const obligations = - result[jss::obligations][to_string(issue.currency)]; + auto const obligations = result[jss::obligations][to_string(issue.currency)]; if (obligations.isNull()) return {STAmount(issue, 0), account.name()}; STAmount const amount = amountFromString(issue, obligations.asString()); @@ -77,10 +51,7 @@ struct EscrowToken_test : public beast::unit_test::suite } jtx::PrettyAmount - issuerEscrowed( - jtx::Env& env, - jtx::Account const& account, - Issue const& issue) + issuerEscrowed(jtx::Env& env, jtx::Account const& account, Issue const& issue) { Json::Value params; params[jss::account] = account.human(); @@ -103,8 +74,7 @@ struct EscrowToken_test : public beast::unit_test::suite for (bool const withTokenEscrow : {false, true}) { - auto const amend = - withTokenEscrow ? features : features - featureTokenEscrow; + auto const amend = withTokenEscrow ? features : features - featureTokenEscrow; Env env{*this, amend}; auto const baseFee = env.current()->fees().base; auto const alice = Account("alice"); @@ -120,10 +90,8 @@ struct EscrowToken_test : public beast::unit_test::suite env(pay(gw, bob, USD(5000))); env.close(); - auto const createResult = - withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT); - auto const finishResult = - withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET); + auto const createResult = withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT); + auto const finishResult = withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET); auto const seq1 = env.seq(alice); env(escrow::create(alice, bob, USD(1'000)), @@ -153,8 +121,7 @@ struct EscrowToken_test : public beast::unit_test::suite for (bool const withTokenEscrow : {false, true}) { - auto const amend = - withTokenEscrow ? features : features - featureTokenEscrow; + auto const amend = withTokenEscrow ? features : features - featureTokenEscrow; Env env{*this, amend}; auto const baseFee = env.current()->fees().base; auto const alice = Account("alice"); @@ -265,10 +232,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const USD = gw["USD"]; env.fund(XRP(5000), alice, bob, gw); - env(escrow::create(alice, bob, USD(1)), - escrow::finish_time(env.now() + 1s), - fee(XRP(-1)), - ter(temBAD_FEE)); + env(escrow::create(alice, bob, USD(1)), escrow::finish_time(env.now() + 1s), fee(XRP(-1)), ter(temBAD_FEE)); env.close(); } @@ -578,12 +542,14 @@ struct EscrowToken_test : public beast::unit_test::suite env(pay(gw, bob, USD(1))); env.close(); + bool const largeMantissa = features[featureSingleAssetVault] || features[featureLendingProtocol]; + // alice cannot create escrow for 1/10 iou - precision loss env(escrow::create(alice, bob, USD(1)), escrow::condition(escrow::cb1), escrow::finish_time(env.now() + 1s), fee(baseFee * 150), - ter(tecPRECISION_LOSS)); + ter(largeMantissa ? (TER)tesSUCCESS : (TER)tecPRECISION_LOSS)); env.close(); } } @@ -786,7 +752,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.trust(USD(1), bob); env.close(); - // alice cannot finish because bobs limit is too low + // alice cannot finish because bob's limit is too low env(escrow::finish(alice, alice, seq1), escrow::condition(escrow::cb1), escrow::fulfillment(escrow::fb1), @@ -823,7 +789,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.trust(USD(1), bob); env.close(); - // bob can finish even if bobs limit is too low + // bob can finish even if bob's limit is too low auto const bobPreLimit = env.limit(bob, USD); env(escrow::finish(bob, alice, seq1), @@ -833,7 +799,7 @@ struct EscrowToken_test : public beast::unit_test::suite ter(tesSUCCESS)); env.close(); - // bobs limit is not changed + // bob's limit is not changed BEAST_EXPECT(env.limit(bob, USD) == bobPreLimit); } } @@ -884,9 +850,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // alice cannot cancel because she is not authorized - env(escrow::cancel(bob, alice, seq1), - fee(baseFee), - ter(tecNO_AUTH)); + env(escrow::cancel(bob, alice, seq1), fee(baseFee), ter(tecNO_AUTH)); env.close(); } } @@ -930,8 +894,7 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000)); BEAST_EXPECT(env.balance(bob, USD) == preBobUSD); - BEAST_EXPECT( - issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); + BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000)); } { @@ -965,8 +928,7 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000)); BEAST_EXPECT(env.balance(bob, USD) == preBobUSD); - BEAST_EXPECT( - issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); + BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000)); } { @@ -1012,91 +974,74 @@ struct EscrowToken_test : public beast::unit_test::suite env(escrow::create(alice, alice, USD(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 500s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const aa = env.le(keylet::escrow(alice.id(), aseq)); BEAST_EXPECT(aa); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) != aod.end()); } { - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), aa) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), aa) != iod.end()); } env(escrow::create(bob, bob, USD(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const bb = env.le(keylet::escrow(bob.id(), bseq)); BEAST_EXPECT(bb); { - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); } { - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bb) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bb) != iod.end()); } env.close(5s); env(escrow::finish(alice, alice, aseq)); { BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bb) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bb) != iod.end()); } env.close(5s); env(escrow::cancel(bob, bob, bseq)); { BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) == bod.end()); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bb) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bb) == iod.end()); } } { @@ -1115,18 +1060,13 @@ struct EscrowToken_test : public beast::unit_test::suite auto const aseq = env.seq(alice); auto const bseq = env.seq(bob); - env(escrow::create(alice, bob, USD(1'000)), - escrow::finish_time(env.now() + 1s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + env(escrow::create(alice, bob, USD(1'000)), escrow::finish_time(env.now() + 1s)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); env(escrow::create(bob, carol, USD(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const ab = env.le(keylet::escrow(alice.id(), aseq)); @@ -1136,29 +1076,23 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(bc); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) != aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) != bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2); - BEAST_EXPECT( - std::find(cod.begin(), cod.end(), bc) != cod.end()); + BEAST_EXPECT(std::find(cod.begin(), cod.end(), bc) != cod.end()); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 5); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), ab) != iod.end()); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bc) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), ab) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bc) != iod.end()); } env.close(5s); @@ -1167,27 +1101,22 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 4); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), ab) == iod.end()); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bc) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), ab) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bc) != iod.end()); } env.close(5s); @@ -1196,27 +1125,22 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) == bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), ab) == iod.end()); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), bc) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), ab) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), bc) == iod.end()); } } @@ -1234,12 +1158,9 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); auto const aseq = env.seq(alice); - env(escrow::create(alice, gw, USD(1'000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create(alice, gw, USD(1'000)), escrow::finish_time(env.now() + 1s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); env(escrow::create(gw, carol, USD(1'000)), escrow::finish_time(env.now() + 1s), @@ -1251,18 +1172,16 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(ag); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ag) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ag) != aod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 3); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), ag) != iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), ag) != iod.end()); } env.close(5s); @@ -1270,18 +1189,16 @@ struct EscrowToken_test : public beast::unit_test::suite { BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ag) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ag) == aod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 2); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), ag) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), ag) == iod.end()); } } } @@ -1511,8 +1428,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto const transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); // bob can finish escrow env(escrow::finish(bob, alice, seq1), @@ -1549,8 +1465,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); // issuer changes rate higher env(rate(gw, 1.26)); @@ -1592,8 +1507,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); // issuer changes rate lower env(rate(gw, 1.00)); @@ -1610,7 +1524,7 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == USD(10125)); } - // test cancel doesnt charge rate + // test cancel doesn't charge rate { Env env{*this, features}; auto const baseFee = env.current()->fees().base; @@ -1635,8 +1549,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee)); env.close(); auto transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); // issuer changes rate lower env(rate(gw, 1.00)); @@ -1693,7 +1606,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto const postBobLimit = env.limit(bob, USD); - // bobs limit is NOT changed + // bob's limit is NOT changed BEAST_EXPECT(postBobLimit == preBobLimit); } } @@ -1953,8 +1866,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // clear freeze on alice trustline - env(trust( - gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze)); + env(trust(gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze)); env.close(); // create escrow success @@ -1978,8 +1890,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // reset freeze on alice and bob trustline - env(trust( - gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze)); + env(trust(gw, USD(10'000), alice, tfClearFreeze | tfClearDeepFreeze)); env(trust(gw, USD(10'000), bob, tfClearFreeze | tfClearDeepFreeze)); env.close(); @@ -1996,16 +1907,14 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // bob cancel escrow fails because of deep frozen assets - env(escrow::cancel(bob, alice, seq1), - fee(baseFee), - ter(tesSUCCESS)); + env(escrow::cancel(bob, alice, seq1), fee(baseFee), ter(tesSUCCESS)); env.close(); } } void - testIOUINSF(FeatureBitset features) + testIOUInsufficientFunds(FeatureBitset features) { - testcase("IOU Insuficient Funds"); + testcase("IOU Insufficient Funds"); using namespace test::jtx; using namespace std::literals; @@ -2095,12 +2004,14 @@ struct EscrowToken_test : public beast::unit_test::suite env(pay(gw, bob, USD(1))); env.close(); + bool const largeMantissa = features[featureSingleAssetVault] || features[featureLendingProtocol]; + // alice cannot create escrow for 1/10 iou - precision loss env(escrow::create(alice, bob, USD(1)), escrow::condition(escrow::cb1), escrow::finish_time(env.now() + 1s), fee(baseFee * 150), - ter(tecPRECISION_LOSS)); + ter(largeMantissa ? (TER)tesSUCCESS : (TER)tecPRECISION_LOSS)); env.close(); auto const seq1 = env.seq(alice); @@ -2130,8 +2041,7 @@ struct EscrowToken_test : public beast::unit_test::suite for (bool const withTokenEscrow : {false, true}) { - auto const amend = - withTokenEscrow ? features : features - featureTokenEscrow; + auto const amend = withTokenEscrow ? features : features - featureTokenEscrow; Env env{*this, amend}; auto const baseFee = env.current()->fees().base; auto const alice = Account("alice"); @@ -2140,19 +2050,14 @@ struct EscrowToken_test : public beast::unit_test::suite env.fund(XRP(5000), bob); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); env.close(); - auto const createResult = - withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT); - auto const finishResult = - withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET); + auto const createResult = withTokenEscrow ? ter(tesSUCCESS) : ter(temBAD_AMOUNT); + auto const finishResult = withTokenEscrow ? ter(tesSUCCESS) : ter(tecNO_TARGET); auto const seq1 = env.seq(alice); env(escrow::create(alice, bob, MPT(1'000)), @@ -2189,8 +2094,7 @@ struct EscrowToken_test : public beast::unit_test::suite for (bool const withMPT : {true, false}) { - auto const amend = - withMPT ? features : features - featureMPTokensV1; + auto const amend = withMPT ? features : features - featureMPTokensV1; Env env{*this, amend}; auto const baseFee = env.current()->fees().base; auto const alice = Account("alice"); @@ -2200,16 +2104,11 @@ struct EscrowToken_test : public beast::unit_test::suite Json::Value jv = escrow::create(alice, bob, XRP(1)); jv.removeMember(jss::Amount); - jv[jss::Amount][jss::mpt_issuance_id] = - "00000004A407AF5856CCF3C42619DAA925813FC955C72983"; + jv[jss::Amount][jss::mpt_issuance_id] = "00000004A407AF5856CCF3C42619DAA925813FC955C72983"; jv[jss::Amount][jss::value] = "-1"; auto const result = withMPT ? ter(temBAD_AMOUNT) : ter(temDISABLED); - env(jv, - escrow::condition(escrow::cb1), - escrow::finish_time(env.now() + 1s), - fee(baseFee * 150), - result); + env(jv, escrow::condition(escrow::cb1), escrow::finish_time(env.now() + 1s), fee(baseFee * 150), result); env.close(); } @@ -2222,10 +2121,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2257,10 +2153,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -2284,11 +2177,9 @@ struct EscrowToken_test : public beast::unit_test::suite env.fund(XRP(10'000), alice, bob, gw); env.close(); - auto const mpt = ripple::test::jtx::MPT( - alice.name(), makeMptID(env.seq(alice), alice)); + auto const mpt = xrpl::test::jtx::MPT(alice.name(), makeMptID(env.seq(alice), alice)); Json::Value jv = escrow::create(alice, bob, mpt(2)); - jv[jss::Amount][jss::mpt_issuance_id] = - "00000004A407AF5856CCF3C42619DAA925813FC955C72983"; + jv[jss::Amount][jss::mpt_issuance_id] = "00000004A407AF5856CCF3C42619DAA925813FC955C72983"; env(jv, escrow::condition(escrow::cb1), escrow::finish_time(env.now() + 1s), @@ -2306,8 +2197,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2332,10 +2222,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); auto const MPT = mptGw["MPT"]; env(escrow::create(alice, bob, MPT(4)), @@ -2356,10 +2243,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = - tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = gw, .holder = alice}); auto const MPT = mptGw["MPT"]; @@ -2367,8 +2251,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // unauthorize account - mptGw.authorize( - {.account = gw, .holder = alice, .flags = tfMPTUnauthorize}); + mptGw.authorize({.account = gw, .holder = alice, .flags = tfMPTUnauthorize}); env(escrow::create(alice, bob, MPT(5)), escrow::condition(escrow::cb1), @@ -2388,10 +2271,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = - tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = gw, .holder = alice}); mptGw.authorize({.account = bob}); @@ -2402,8 +2282,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // unauthorize dest - mptGw.authorize( - {.account = gw, .holder = bob, .flags = tfMPTUnauthorize}); + mptGw.authorize({.account = gw, .holder = bob, .flags = tfMPTUnauthorize}); env(escrow::create(alice, bob, MPT(6)), escrow::condition(escrow::cb1), @@ -2423,9 +2302,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2454,9 +2331,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2484,8 +2359,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2510,10 +2384,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2537,10 +2408,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2574,10 +2442,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = - tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = gw, .holder = alice}); mptGw.authorize({.account = bob}); @@ -2596,8 +2461,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // unauthorize dest - mptGw.authorize( - {.account = gw, .holder = bob, .flags = tfMPTUnauthorize}); + mptGw.authorize({.account = gw, .holder = bob, .flags = tfMPTUnauthorize}); env(escrow::finish(bob, alice, seq1), escrow::condition(escrow::cb1), @@ -2617,20 +2481,17 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); auto const seq1 = env.seq(alice); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - Sandbox sb(&view, tapNONE); - auto sleNew = - std::make_shared(keylet::escrow(alice, seq1)); - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - STAmount amt(mpt, 10); - sleNew->setAccountID(sfDestination, bob); - sleNew->setFieldAmount(sfAmount, amt); - sb.insert(sleNew); - sb.apply(view); - return true; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + Sandbox sb(&view, tapNONE); + auto sleNew = std::make_shared(keylet::escrow(alice, seq1)); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + STAmount amt(mpt, 10); + sleNew->setAccountID(sfDestination, bob); + sleNew->setFieldAmount(sfAmount, amt); + sb.insert(sleNew); + sb.apply(view); + return true; + }); env(escrow::finish(bob, alice, seq1), escrow::condition(escrow::cb1), @@ -2650,9 +2511,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -2701,10 +2560,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -2737,10 +2593,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -2774,10 +2627,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -2817,10 +2667,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = - tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = gw, .holder = alice}); mptGw.authorize({.account = bob}); @@ -2839,8 +2686,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); // unauthorize account - mptGw.authorize( - {.account = gw, .holder = alice, .flags = tfMPTUnauthorize}); + mptGw.authorize({.account = gw, .holder = alice, .flags = tfMPTUnauthorize}); env(escrow::cancel(bob, alice, seq1), ter(tecNO_AUTH)); env.close(); @@ -2855,24 +2701,19 @@ struct EscrowToken_test : public beast::unit_test::suite env.fund(XRP(10'000), alice, bob); auto const seq1 = env.seq(alice); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - Sandbox sb(&view, tapNONE); - auto sleNew = - std::make_shared(keylet::escrow(alice, seq1)); - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - STAmount amt(mpt, 10); - sleNew->setAccountID(sfDestination, bob); - sleNew->setFieldAmount(sfAmount, amt); - sb.insert(sleNew); - sb.apply(view); - return true; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + Sandbox sb(&view, tapNONE); + auto sleNew = std::make_shared(keylet::escrow(alice, seq1)); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + STAmount amt(mpt, 10); + sleNew->setAccountID(sfDestination, bob); + sleNew->setFieldAmount(sfAmount, amt); + sb.insert(sleNew); + sb.apply(view); + return true; + }); - env(escrow::cancel(bob, alice, seq1), - fee(baseFee), - ter(tecOBJECT_NOT_FOUND)); + env(escrow::cancel(bob, alice, seq1), fee(baseFee), ter(tecOBJECT_NOT_FOUND)); env.close(); } } @@ -2894,10 +2735,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.fund(XRP(5000), bob); MPTTester mptGw(env, gw, {.holders = {alice, carol}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = carol}); auto const MPT = mptGw["MPT"]; @@ -3071,10 +2909,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3108,14 +2943,12 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(1)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0); - BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice)) - ->isFieldPresent(sfLockedAmount)); + BEAST_EXPECT(!env.le(keylet::mptoken(MPT.mpt(), alice))->isFieldPresent(sfLockedAmount)); BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(1)); BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0); BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT); BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0); - BEAST_EXPECT(!env.le(keylet::mptIssuance(MPT.mpt())) - ->isFieldPresent(sfLockedAmount)); + BEAST_EXPECT(!env.le(keylet::mptIssuance(MPT.mpt()))->isFieldPresent(sfLockedAmount)); } // Max MPT Amount Issued (Escrow Max MPT) @@ -3127,10 +2960,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3157,8 +2987,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); - BEAST_EXPECT( - env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount)); + BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == maxMPTokenAmount); BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT); BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0); @@ -3179,11 +3008,9 @@ struct EscrowToken_test : public beast::unit_test::suite ter(tesSUCCESS)); env.close(); - BEAST_EXPECT( - env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount)); + BEAST_EXPECT(env.balance(alice, MPT) == preAliceMPT - MPT(maxMPTokenAmount)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 0); - BEAST_EXPECT( - env.balance(bob, MPT) == preBobMPT + MPT(maxMPTokenAmount)); + BEAST_EXPECT(env.balance(bob, MPT) == preBobMPT + MPT(maxMPTokenAmount)); BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0); BEAST_EXPECT(env.balance(gw, MPT) == outstandingMPT); BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 0); @@ -3205,10 +3032,7 @@ struct EscrowToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3221,74 +3045,60 @@ struct EscrowToken_test : public beast::unit_test::suite env(escrow::create(alice, alice, MPT(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 500s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const aa = env.le(keylet::escrow(alice.id(), aseq)); BEAST_EXPECT(aa); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) != aod.end()); } { - ripple::Dir iod(*env.current(), keylet::ownerDir(gw.id())); + xrpl::Dir iod(*env.current(), keylet::ownerDir(gw.id())); BEAST_EXPECT(std::distance(iod.begin(), iod.end()) == 1); - BEAST_EXPECT( - std::find(iod.begin(), iod.end(), aa) == iod.end()); + BEAST_EXPECT(std::find(iod.begin(), iod.end(), aa) == iod.end()); } env(escrow::create(bob, bob, MPT(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const bb = env.le(keylet::escrow(bob.id(), bseq)); BEAST_EXPECT(bb); { - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); } env.close(5s); env(escrow::finish(alice, alice, aseq)); { BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); } env.close(5s); env(escrow::cancel(bob, bob, bseq)); { BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) == bod.end()); } } @@ -3297,10 +3107,7 @@ struct EscrowToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptGw(env, gw, {.holders = {alice, bob, carol}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); mptGw.authorize({.account = carol}); @@ -3312,18 +3119,13 @@ struct EscrowToken_test : public beast::unit_test::suite auto const aseq = env.seq(alice); auto const bseq = env.seq(bob); - env(escrow::create(alice, bob, MPT(1'000)), - escrow::finish_time(env.now() + 1s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + env(escrow::create(alice, bob, MPT(1'000)), escrow::finish_time(env.now() + 1s)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); env(escrow::create(bob, carol, MPT(1'000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const ab = env.le(keylet::escrow(alice.id(), aseq)); @@ -3333,22 +3135,18 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(bc); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 2); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) != aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 3); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) != bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2); - BEAST_EXPECT( - std::find(cod.begin(), cod.end(), bc) != cod.end()); + BEAST_EXPECT(std::find(cod.begin(), cod.end(), bc) != cod.end()); } env.close(5s); @@ -3357,19 +3155,16 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(env.le(keylet::escrow(bob.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 2); } @@ -3379,19 +3174,16 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(!env.le(keylet::escrow(bob.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bob.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bob.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) == bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); } } @@ -3412,10 +3204,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -3477,10 +3266,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.transferFee = 25000, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + {.transferFee = 25000, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3498,8 +3284,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto const transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125); BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125); @@ -3515,11 +3300,9 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, MPT) == preAlice - delta); BEAST_EXPECT(env.balance(bob, MPT) == MPT(10'100)); - auto const escrowedWithFix = - env.current()->rules().enabled(fixTokenEscrowV1) ? 0 : 25; + auto const escrowedWithFix = env.current()->rules().enabled(fixTokenEscrowV1) ? 0 : 25; auto const outstandingWithFix = - env.current()->rules().enabled(fixTokenEscrowV1) ? MPT(19'975) - : MPT(20'000); + env.current()->rules().enabled(fixTokenEscrowV1) ? MPT(19'975) : MPT(20'000); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == escrowedWithFix); BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == escrowedWithFix); BEAST_EXPECT(env.balance(gw, MPT) == -outstandingWithFix); @@ -3535,10 +3318,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.transferFee = 25000, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + {.transferFee = 25000, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3558,8 +3338,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto const transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); // alice can cancel escrow env(escrow::cancel(alice, alice, seq1), fee(baseFee)); @@ -3582,10 +3361,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.transferFee = 25000, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + {.transferFee = 25000, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3603,8 +3379,7 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); auto const transferRate = escrow::rate(env, alice, seq1); - BEAST_EXPECT( - transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); + BEAST_EXPECT(transferRate.value == std::uint32_t(1'000'000'000 * 1.25)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 125); BEAST_EXPECT(issuerMPTEscrowed(env, MPT) == 125); @@ -3639,9 +3414,7 @@ struct EscrowToken_test : public beast::unit_test::suite MPTTester mptGw(env, gw, {.holders = {alice, bob}}); mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTRequireAuth}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = gw, .holder = alice}); mptGw.authorize({.account = bob}); @@ -3681,10 +3454,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer | tfMPTCanLock}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3732,8 +3502,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3801,10 +3570,7 @@ struct EscrowToken_test : public beast::unit_test::suite auto const gw = Account("gw"); MPTTester mptGw(env, gw, {.holders = {alice, bob}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; @@ -3828,10 +3594,7 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0); BEAST_EXPECT(env.balance(gw, MPT) == MPT(-10)); mptGw.authorize({.account = bob, .flags = tfMPTUnauthorize}); - mptGw.destroy( - {.id = mptGw.issuanceID(), - .ownerCount = 1, - .err = tecHAS_OBLIGATIONS}); + mptGw.destroy({.id = mptGw.issuanceID(), .ownerCount = 1, .err = tecHAS_OBLIGATIONS}); env(escrow::finish(bob, alice, seq1), escrow::condition(escrow::cb1), @@ -3855,10 +3618,7 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); MPTTester mptGw(env, gw, {.holders = {alice}}); - mptGw.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanEscrow | tfMPTCanTransfer}); + mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanEscrow | tfMPTCanTransfer}); mptGw.authorize({.account = alice}); auto const MPT = mptGw["MPT"]; env(pay(gw, alice, MPT(10'000))); @@ -3877,10 +3637,7 @@ struct EscrowToken_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, MPT) == MPT(0)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10); - mptGw.authorize( - {.account = alice, - .flags = tfMPTUnauthorize, - .err = tecHAS_OBLIGATIONS}); + mptGw.authorize({.account = alice, .flags = tfMPTUnauthorize, .err = tecHAS_OBLIGATIONS}); env(escrow::finish(bob, alice, seq1), escrow::condition(escrow::cb1), @@ -3914,7 +3671,7 @@ struct EscrowToken_test : public beast::unit_test::suite testIOULimitAmount(features); testIOURequireAuth(features); testIOUFreeze(features); - testIOUINSF(features); + testIOUInsufficientFunds(features); testIOUPrecisionLoss(features); } @@ -3943,13 +3700,16 @@ public: { using namespace test::jtx; FeatureBitset const all{testable_amendments()}; - testIOUWithFeats(all); - testMPTWithFeats(all); - testMPTWithFeats(all - fixTokenEscrowV1); + for (FeatureBitset const& feats : {all - featureSingleAssetVault - featureLendingProtocol, all}) + { + testIOUWithFeats(feats); + testMPTWithFeats(feats); + testMPTWithFeats(feats - fixTokenEscrowV1); + } } }; -BEAST_DEFINE_TESTSUITE(EscrowToken, app, ripple); +BEAST_DEFINE_TESTSUITE(EscrowToken, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 8d993f9162..652049270f 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct Escrow_test : public beast::unit_test::suite @@ -46,8 +27,7 @@ struct Escrow_test : public beast::unit_test::suite Env env(*this, features); auto const baseFee = env.current()->fees().base; env.fund(XRP(5000), "alice", "bob"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() + 1s)); env.close(); auto const seq1 = env.seq("alice"); @@ -90,15 +70,12 @@ struct Escrow_test : public beast::unit_test::suite auto const ts = env.now() + 97s; auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(ts)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(ts)); // Advance the ledger, verifying that the finish won't complete // prematurely. for (; env.now() < ts; env.close()) - env(escrow::finish("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::finish("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); env(escrow::finish("bob", "alice", seq), fee(baseFee * 150)); } @@ -114,16 +91,12 @@ struct Escrow_test : public beast::unit_test::suite auto const ts = env.now() + 117s; auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::condition(escrow::cb1), - escrow::cancel_time(ts)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::condition(escrow::cb1), escrow::cancel_time(ts)); // Advance the ledger, verifying that the cancel won't complete // prematurely. for (; env.now() < ts; env.close()) - env(escrow::cancel("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); // Verify that a finish won't work anymore. env(escrow::finish("bob", "alice", seq), @@ -148,26 +121,18 @@ struct Escrow_test : public beast::unit_test::suite auto const cts = env.now() + 192s; auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(fts), - escrow::cancel_time(cts)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(fts), escrow::cancel_time(cts)); // Advance the ledger, verifying that the finish and cancel won't // complete prematurely. for (; env.now() < fts; env.close()) { - env(escrow::finish("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); - env(escrow::cancel("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::finish("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); + env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); } // Verify that a cancel still won't work - env(escrow::cancel("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); // And verify that a finish will env(escrow::finish("bob", "alice", seq), fee(baseFee * 150)); @@ -185,34 +150,24 @@ struct Escrow_test : public beast::unit_test::suite auto const cts = env.now() + 184s; auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(fts), - escrow::cancel_time(cts)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(fts), escrow::cancel_time(cts)); // Advance the ledger, verifying that the finish and cancel won't // complete prematurely. for (; env.now() < fts; env.close()) { - env(escrow::finish("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); - env(escrow::cancel("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::finish("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); + env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); } // Continue advancing, verifying that the cancel won't complete // prematurely. At this point a finish would succeed. for (; env.now() < cts; env.close()) - env(escrow::cancel("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); // Verify that finish will no longer work, since we are past the // cancel activation time. - env(escrow::finish("bob", "alice", seq), - fee(baseFee * 150), - ter(tecNO_PERMISSION)); + env(escrow::finish("bob", "alice", seq), fee(baseFee * 150), ter(tecNO_PERMISSION)); // And verify that a cancel will succeed. env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150)); @@ -237,17 +192,12 @@ struct Escrow_test : public beast::unit_test::suite // Check to make sure that we correctly detect if tags are really // required: env(fset(bob, asfRequireDest)); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 1s), - ter(tecDST_TAG_NEEDED)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 1s), ter(tecDST_TAG_NEEDED)); // set source and dest tags auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 1s), - stag(1), - dtag(2)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 1s), stag(1), dtag(2)); auto const sle = env.le(keylet::escrow(alice.id(), seq)); BEAST_EXPECT(sle); @@ -271,16 +221,6 @@ struct Escrow_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - { - // Respect the "asfDisallowXRP" account flag: - Env env(*this, features - featureDepositAuth); - - env.fund(XRP(5000), "bob", "george"); - env(fset("george", asfDisallowXRP)); - env(escrow::create("bob", "george", XRP(10)), - escrow::finish_time(env.now() + 1s), - ter(tecNO_TARGET)); - } { // Ignore the "asfDisallowXRP" account flag, which we should // have been doing before. @@ -288,8 +228,7 @@ struct Escrow_test : public beast::unit_test::suite env.fund(XRP(5000), "bob", "george"); env(fset("george", asfDisallowXRP)); - env(escrow::create("bob", "george", XRP(10)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create("bob", "george", XRP(10)), escrow::finish_time(env.now() + 1s)); } } @@ -336,9 +275,7 @@ struct Escrow_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); env(escrow::finish("carol", "alice", seqFt), fee(150 * baseFee)); - BEAST_EXPECT( - env.balance("bob") == - XRP(5200)); // 5100 (from last transaction) + 100 + BEAST_EXPECT(env.balance("bob") == XRP(5200)); // 5100 (from last transaction) + 100 } void @@ -361,9 +298,7 @@ struct Escrow_test : public beast::unit_test::suite ter(temINVALID_FLAG)); // Finish time is in the past - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(env.now() - 5s), - ter(tecNO_PERMISSION)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() - 5s), ter(tecNO_PERMISSION)); // Cancel time is in the past env(escrow::create("alice", "bob", XRP(1000)), @@ -372,45 +307,33 @@ struct Escrow_test : public beast::unit_test::suite ter(tecNO_PERMISSION)); // no destination account - env(escrow::create("alice", "carol", XRP(1000)), - escrow::finish_time(env.now() + 1s), - ter(tecNO_DST)); + env(escrow::create("alice", "carol", XRP(1000)), escrow::finish_time(env.now() + 1s), ter(tecNO_DST)); env.fund(XRP(5000), "carol"); // Using non-XRP: - bool const withTokenEscrow = - env.current()->rules().enabled(featureTokenEscrow); + bool const withTokenEscrow = env.current()->rules().enabled(featureTokenEscrow); { // tecNO_PERMISSION: token escrow is enabled but the issuer did not // set the asfAllowTrustLineLocking flag - auto const txResult = - withTokenEscrow ? ter(tecNO_PERMISSION) : ter(temBAD_AMOUNT); + auto const txResult = withTokenEscrow ? ter(tecNO_PERMISSION) : ter(temBAD_AMOUNT); env(escrow::create("alice", "carol", Account("alice")["USD"](500)), escrow::finish_time(env.now() + 5s), txResult); } // Sending zero or no XRP: - env(escrow::create("alice", "carol", XRP(0)), - escrow::finish_time(env.now() + 1s), - ter(temBAD_AMOUNT)); - env(escrow::create("alice", "carol", XRP(-1000)), - escrow::finish_time(env.now() + 1s), - ter(temBAD_AMOUNT)); + env(escrow::create("alice", "carol", XRP(0)), escrow::finish_time(env.now() + 1s), ter(temBAD_AMOUNT)); + env(escrow::create("alice", "carol", XRP(-1000)), escrow::finish_time(env.now() + 1s), ter(temBAD_AMOUNT)); // Fail if neither CancelAfter nor FinishAfter are specified: env(escrow::create("alice", "carol", XRP(1)), ter(temBAD_EXPIRATION)); // Fail if neither a FinishTime nor a condition are attached: - env(escrow::create("alice", "carol", XRP(1)), - escrow::cancel_time(env.now() + 1s), - ter(temMALFORMED)); + env(escrow::create("alice", "carol", XRP(1)), escrow::cancel_time(env.now() + 1s), ter(temMALFORMED)); // Fail if FinishAfter has already passed: - env(escrow::create("alice", "carol", XRP(1)), - escrow::finish_time(env.now() - 1s), - ter(tecNO_PERMISSION)); + env(escrow::create("alice", "carol", XRP(1)), escrow::finish_time(env.now() - 1s), ter(tecNO_PERMISSION)); // If both CancelAfter and FinishAfter are set, then CancelAfter must // be strictly later than FinishAfter. @@ -443,18 +366,13 @@ struct Escrow_test : public beast::unit_test::suite { // Fail if the sender wants to send more than he has: auto const accountReserve = drops(env.current()->fees().reserve); - auto const accountIncrement = - drops(env.current()->fees().increment); + auto const accountIncrement = drops(env.current()->fees().increment); env.fund(accountReserve + accountIncrement + XRP(50), "daniel"); - env(escrow::create("daniel", "bob", XRP(51)), - escrow::finish_time(env.now() + 1s), - ter(tecUNFUNDED)); + env(escrow::create("daniel", "bob", XRP(51)), escrow::finish_time(env.now() + 1s), ter(tecUNFUNDED)); env.fund(accountReserve + accountIncrement + XRP(50), "evan"); - env(escrow::create("evan", "bob", XRP(50)), - escrow::finish_time(env.now() + 1s), - ter(tecUNFUNDED)); + env(escrow::create("evan", "bob", XRP(50)), escrow::finish_time(env.now() + 1s), ter(tecUNFUNDED)); env.fund(accountReserve, "frank"); env(escrow::create("frank", "bob", XRP(1)), @@ -465,21 +383,16 @@ struct Escrow_test : public beast::unit_test::suite { // Specify incorrect sequence number env.fund(XRP(5000), "hannah"); auto const seq = env.seq("hannah"); - env(escrow::create("hannah", "hannah", XRP(10)), - escrow::finish_time(env.now() + 1s), - fee(150 * baseFee)); + env(escrow::create("hannah", "hannah", XRP(10)), escrow::finish_time(env.now() + 1s), fee(150 * baseFee)); env.close(); - env(escrow::finish("hannah", "hannah", seq + 7), - fee(150 * baseFee), - ter(tecNO_TARGET)); + env(escrow::finish("hannah", "hannah", seq + 7), fee(150 * baseFee), ter(tecNO_TARGET)); } { // Try to specify a condition for a non-conditional payment env.fund(XRP(5000), "ivan"); auto const seq = env.seq("ivan"); - env(escrow::create("ivan", "ivan", XRP(10)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create("ivan", "ivan", XRP(10)), escrow::finish_time(env.now() + 1s)); env.close(); env(escrow::finish("ivan", "ivan", seq), escrow::condition(escrow::cb1), @@ -503,8 +416,7 @@ struct Escrow_test : public beast::unit_test::suite auto const baseFee = env.current()->fees().base; env.fund(XRP(5000), "alice", "bob"); auto const seq = env.seq("alice"); - env(escrow::create("alice", "alice", XRP(1000)), - escrow::finish_time(env.now() + 5s)); + env(escrow::create("alice", "alice", XRP(1000)), escrow::finish_time(env.now() + 5s)); env.require(balance("alice", XRP(4000) - drops(baseFee))); // Not enough time has elapsed for a finish and canceling isn't @@ -528,8 +440,7 @@ struct Escrow_test : public beast::unit_test::suite auto const baseFee = env.current()->fees().base; env.fund(XRP(5000), "alice", "bob", "zelda"); auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(env.now() + 5s)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() + 5s)); env.require(balance("alice", XRP(4000) - drops(baseFee))); // Not enough time has elapsed for a finish and canceling isn't @@ -559,8 +470,7 @@ struct Escrow_test : public beast::unit_test::suite env.close(); auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(env.now() + 5s)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() + 5s)); env.require(balance("alice", XRP(4000) - drops(baseFee))); // Not enough time has elapsed for a finish and canceling isn't @@ -600,8 +510,7 @@ struct Escrow_test : public beast::unit_test::suite env.close(); auto const seq = env.seq("alice"); - env(escrow::create("alice", "bob", XRP(1000)), - escrow::finish_time(env.now() + 5s)); + env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() + 5s)); env.require(balance("alice", XRP(4000) - drops(baseFee))); env.close(); @@ -649,10 +558,8 @@ struct Escrow_test : public beast::unit_test::suite // requires the fulfillment associated with the escrow. env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION)); env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION)); - env(escrow::finish("bob", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); - env(escrow::finish("alice", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); env.close(); env(escrow::finish("bob", "alice", seq), @@ -674,10 +581,8 @@ struct Escrow_test : public beast::unit_test::suite env.close(); // Finish is now possible but requires the cryptocondition. - env(escrow::finish("bob", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); - env(escrow::finish("alice", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); // Enable deposit authorization. After this only Alice can finish // the escrow. @@ -718,12 +623,9 @@ struct Escrow_test : public beast::unit_test::suite env.close(); // Finish is now possible but requires the cryptocondition. - env(escrow::finish("alice", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); - env(escrow::finish("bob", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); - env(escrow::finish("zelda", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("zelda", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); // Alice enables deposit authorization. After this only Alice or // Zelda (because Zelda is preauthorized) can finish the escrow. @@ -771,8 +673,7 @@ struct Escrow_test : public beast::unit_test::suite BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1); // Attempt to finish without a fulfillment - env(escrow::finish("bob", "alice", seq), - ter(tecCRYPTOCONDITION_ERROR)); + env(escrow::finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR)); BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1); // Attempt to finish with a condition instead of a fulfillment @@ -1108,12 +1009,8 @@ struct Escrow_test : public beast::unit_test::suite // Assemble finish that is missing the Condition or the Fulfillment // since either both must be present, or neither can: - env(escrow::finish("bob", "alice", seq), - escrow::condition(escrow::cb3), - ter(temMALFORMED)); - env(escrow::finish("bob", "alice", seq), - escrow::fulfillment(escrow::fb3), - ter(temMALFORMED)); + env(escrow::finish("bob", "alice", seq), escrow::condition(escrow::cb3), ter(temMALFORMED)); + env(escrow::finish("bob", "alice", seq), escrow::fulfillment(escrow::fb3), ter(temMALFORMED)); // Now finish it. env(escrow::finish("bob", "alice", seq), @@ -1128,12 +1025,10 @@ struct Escrow_test : public beast::unit_test::suite Env env(*this, features); env.fund(XRP(5000), "alice", "bob"); - std::array cb = { - {0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49, - 0x52, 0x92, 0x67, 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19, - 0xD7, 0x29, 0xB2, 0x38, 0x2C, 0xED, 0x8B, 0x29, 0x6C, - 0x3C, 0x02, 0x8F, 0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07, - 0x81, 0x03, 0x06, 0x34, 0xD2, 0x82, 0x02, 0x03, 0xC8}}; + std::array cb = {{0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49, 0x52, 0x92, 0x67, + 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19, 0xD7, 0x29, 0xB2, 0x38, 0x2C, 0xED, + 0x8B, 0x29, 0x6C, 0x3C, 0x02, 0x8F, 0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07, + 0x81, 0x03, 0x06, 0x34, 0xD2, 0x82, 0x02, 0x03, 0xC8}}; // FIXME: this transaction should, eventually, return temDISABLED // instead of temMALFORMED. @@ -1165,68 +1060,55 @@ struct Escrow_test : public beast::unit_test::suite env(escrow::create(alice, alice, XRP(1000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 500s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const aa = env.le(keylet::escrow(alice.id(), aseq)); BEAST_EXPECT(aa); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) != aod.end()); } env(escrow::create(bruce, bruce, XRP(1000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const bb = env.le(keylet::escrow(bruce.id(), bseq)); BEAST_EXPECT(bb); { - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); } env.close(5s); env(escrow::finish(alice, alice, aseq)); { BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), aa) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), aa) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) != bod.end()); } env.close(5s); env(escrow::cancel(bruce, bruce, bseq)); { BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq))); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bb) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bb) == bod.end()); } } { @@ -1237,18 +1119,13 @@ struct Escrow_test : public beast::unit_test::suite auto const aseq = env.seq(alice); auto const bseq = env.seq(bruce); - env(escrow::create(alice, bruce, XRP(1000)), - escrow::finish_time(env.now() + 1s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + env(escrow::create(alice, bruce, XRP(1000)), escrow::finish_time(env.now() + 1s)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); env(escrow::create(bruce, carol, XRP(1000)), escrow::finish_time(env.now() + 1s), escrow::cancel_time(env.now() + 2s)); - BEAST_EXPECT( - (*env.meta())[sfTransactionResult] == - static_cast(tesSUCCESS)); + BEAST_EXPECT((*env.meta())[sfTransactionResult] == static_cast(tesSUCCESS)); env.close(5s); auto const ab = env.le(keylet::escrow(alice.id(), aseq)); @@ -1258,22 +1135,18 @@ struct Escrow_test : public beast::unit_test::suite BEAST_EXPECT(bc); { - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) != aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) != aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) != bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); - BEAST_EXPECT( - std::find(cod.begin(), cod.end(), bc) != cod.end()); + BEAST_EXPECT(std::find(cod.begin(), cod.end(), bc) != cod.end()); } env.close(5s); @@ -1282,19 +1155,16 @@ struct Escrow_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(env.le(keylet::escrow(bruce.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) != bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) != bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1); } @@ -1304,19 +1174,16 @@ struct Escrow_test : public beast::unit_test::suite BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq))); BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq))); - ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id())); + xrpl::Dir aod(*env.current(), keylet::ownerDir(alice.id())); BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0); - BEAST_EXPECT( - std::find(aod.begin(), aod.end(), ab) == aod.end()); + BEAST_EXPECT(std::find(aod.begin(), aod.end(), ab) == aod.end()); - ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); + xrpl::Dir bod(*env.current(), keylet::ownerDir(bruce.id())); BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), ab) == bod.end()); - BEAST_EXPECT( - std::find(bod.begin(), bod.end(), bc) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), ab) == bod.end()); + BEAST_EXPECT(std::find(bod.begin(), bod.end(), bc) == bod.end()); - ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id())); + xrpl::Dir cod(*env.current(), keylet::ownerDir(carol.id())); BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 0); } } @@ -1338,16 +1205,8 @@ struct Escrow_test : public beast::unit_test::suite { auto const jtx = env.jt( - escrow::create("alice", "carol", XRP(1000)), - escrow::finish_time(env.now() + 1s), - seq(1), - fee(baseFee)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + escrow::create("alice", "carol", XRP(1000)), escrow::finish_time(env.now() + 1s), seq(1), fee(baseFee)); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); @@ -1355,14 +1214,8 @@ struct Escrow_test : public beast::unit_test::suite } { - auto const jtx = - env.jt(escrow::cancel("bob", "alice", 3), seq(1), fee(baseFee)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + auto const jtx = env.jt(escrow::cancel("bob", "alice", 3), seq(1), fee(baseFee)); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); @@ -1370,14 +1223,8 @@ struct Escrow_test : public beast::unit_test::suite } { - auto const jtx = - env.jt(escrow::finish("bob", "alice", 3), seq(1), fee(baseFee)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + auto const jtx = env.jt(escrow::finish("bob", "alice", 3), seq(1), fee(baseFee)); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); @@ -1425,9 +1272,7 @@ struct Escrow_test : public beast::unit_test::suite auto const ts = env.now() + 97s; std::uint32_t const escrowSeq = aliceTicket; - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(ts), - ticket::use(aliceTicket)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(ts), ticket::use(aliceTicket)); BEAST_EXPECT(env.seq(alice) == aliceRootSeq); env.require(tickets(alice, 0)); env.require(tickets(bob, bobTicketCount)); @@ -1444,15 +1289,10 @@ struct Escrow_test : public beast::unit_test::suite } // bob tries to re-use a ticket, which is rejected. - env(escrow::finish(bob, alice, escrowSeq), - fee(150 * baseFee), - ticket::use(bobTicket), - ter(tefNO_TICKET)); + env(escrow::finish(bob, alice, escrowSeq), fee(150 * baseFee), ticket::use(bobTicket), ter(tefNO_TICKET)); // bob uses one of his remaining tickets. Success! - env(escrow::finish(bob, alice, escrowSeq), - fee(150 * baseFee), - ticket::use(--bobTicket)); + env(escrow::finish(bob, alice, escrowSeq), fee(150 * baseFee), ticket::use(--bobTicket)); env.close(); BEAST_EXPECT(env.seq(bob) == bobRootSeq); } @@ -1514,9 +1354,7 @@ struct Escrow_test : public beast::unit_test::suite BEAST_EXPECT(env.seq(bob) == bobRootSeq); // Verify that the cancel succeeds. - env(escrow::cancel(bob, alice, escrowSeq), - fee(150 * baseFee), - ticket::use(bobTicket++)); + env(escrow::cancel(bob, alice, escrowSeq), fee(150 * baseFee), ticket::use(bobTicket++)); env.close(); BEAST_EXPECT(env.seq(bob) == bobRootSeq); @@ -1548,8 +1386,7 @@ struct Escrow_test : public beast::unit_test::suite env.close(); auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 1s)); env.close(); env(fset(bob, asfDepositAuth)); @@ -1560,9 +1397,7 @@ struct Escrow_test : public beast::unit_test::suite std::string const credIdx = "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" "E4"; - env(escrow::finish(bob, alice, seq), - credentials::ids({credIdx}), - ter(temDISABLED)); + env(escrow::finish(bob, alice, seq), credentials::ids({credIdx}), ter(temDISABLED)); } { @@ -1573,23 +1408,19 @@ struct Escrow_test : public beast::unit_test::suite env(credentials::create(carol, zelda, credType)); env.close(); - auto const jv = - credentials::ledgerEntry(env, carol, zelda, credType); + auto const jv = credentials::ledgerEntry(env, carol, zelda, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 50s)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 50s)); env.close(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); // Fail, credentials not accepted - env(escrow::finish(carol, alice, seq), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); env.close(); @@ -1597,14 +1428,10 @@ struct Escrow_test : public beast::unit_test::suite env.close(); // Fail, credentials doesn’t belong to root account - env(escrow::finish(dillon, alice, seq), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(escrow::finish(dillon, alice, seq), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); // Fail, no depositPreauth - env(escrow::finish(carol, alice, seq), - credentials::ids({credIdx}), - ter(tecNO_PERMISSION)); + env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}), ter(tecNO_PERMISSION)); env(deposit::authCredentials(bob, {{zelda, credType}})); env.close(); @@ -1628,13 +1455,11 @@ struct Escrow_test : public beast::unit_test::suite env.close(); env(credentials::accept(carol, zelda, credType)); env.close(); - auto const jv = - credentials::ledgerEntry(env, carol, zelda, credType); + auto const jv = credentials::ledgerEntry(env, carol, zelda, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 50s)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 50s)); // time advance env.close(); env.close(); @@ -1643,36 +1468,32 @@ struct Escrow_test : public beast::unit_test::suite env.close(); env.close(); - // Succeed, Bob doesn't require preauthorization + // Succeed, Bob doesn't require pre-authorization env(escrow::finish(carol, alice, seq), credentials::ids({credIdx})); env.close(); { - char const credType2[] = "fghijk"; + char const credType2[] = "random"; env(credentials::create(bob, zelda, credType2)); env.close(); env(credentials::accept(bob, zelda, credType2)); env.close(); auto const credIdxBob = - credentials::ledgerEntry( - env, bob, zelda, credType2)[jss::result][jss::index] - .asString(); + credentials::ledgerEntry(env, bob, zelda, credType2)[jss::result][jss::index].asString(); auto const seq = env.seq(alice); - env(escrow::create(alice, bob, XRP(1000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create(alice, bob, XRP(1000)), escrow::finish_time(env.now() + 1s)); env.close(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); env(deposit::authCredentials(bob, {{zelda, credType}})); env.close(); // Use any valid credentials if account == dst - env(escrow::finish(bob, alice, seq), - credentials::ids({credIdxBob})); + env(escrow::finish(bob, alice, seq), credentials::ids({credIdxBob})); env.close(); } } @@ -1707,7 +1528,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Escrow, app, ripple); +BEAST_DEFINE_TESTSUITE(Escrow, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/FeeVote_test.cpp b/src/test/app/FeeVote_test.cpp index 4fe0a62e3b..15dd385d65 100644 --- a/src/test/app/FeeVote_test.cpp +++ b/src/test/app/FeeVote_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct FeeSettingsFields @@ -46,10 +27,7 @@ struct FeeSettingsFields }; STTx -createFeeTx( - Rules const& rules, - std::uint32_t seq, - FeeSettingsFields const& fields) +createFeeTx(Rules const& rules, std::uint32_t seq, FeeSettingsFields const& fields) { auto fill = [&](auto& obj) { obj.setAccountID(sfAccount, AccountID()); @@ -58,30 +36,18 @@ createFeeTx( if (rules.enabled(featureXRPFees)) { // New XRPFees format - all three fields are REQUIRED + obj.setFieldAmount(sfBaseFeeDrops, fields.baseFeeDrops ? *fields.baseFeeDrops : XRPAmount{0}); + obj.setFieldAmount(sfReserveBaseDrops, fields.reserveBaseDrops ? *fields.reserveBaseDrops : XRPAmount{0}); obj.setFieldAmount( - sfBaseFeeDrops, - fields.baseFeeDrops ? *fields.baseFeeDrops : XRPAmount{0}); - obj.setFieldAmount( - sfReserveBaseDrops, - fields.reserveBaseDrops ? *fields.reserveBaseDrops - : XRPAmount{0}); - obj.setFieldAmount( - sfReserveIncrementDrops, - fields.reserveIncrementDrops ? *fields.reserveIncrementDrops - : XRPAmount{0}); + sfReserveIncrementDrops, fields.reserveIncrementDrops ? *fields.reserveIncrementDrops : XRPAmount{0}); } else { // Legacy format - all four fields are REQUIRED obj.setFieldU64(sfBaseFee, fields.baseFee ? *fields.baseFee : 0); - obj.setFieldU32( - sfReserveBase, fields.reserveBase ? *fields.reserveBase : 0); - obj.setFieldU32( - sfReserveIncrement, - fields.reserveIncrement ? *fields.reserveIncrement : 0); - obj.setFieldU32( - sfReferenceFeeUnits, - fields.referenceFeeUnits ? *fields.referenceFeeUnits : 0); + obj.setFieldU32(sfReserveBase, fields.reserveBase ? *fields.reserveBase : 0); + obj.setFieldU32(sfReserveIncrement, fields.reserveIncrement ? *fields.reserveIncrement : 0); + obj.setFieldU32(sfReferenceFeeUnits, fields.referenceFeeUnits ? *fields.referenceFeeUnits : 0); } }; return STTx(ttFEE, fill); @@ -141,16 +107,12 @@ createInvalidFeeTx( bool applyFeeAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx) { - auto const res = - apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal); + auto const res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal); return res.ter == tesSUCCESS; } bool -verifyFeeObject( - std::shared_ptr const& ledger, - Rules const& rules, - FeeSettingsFields const& expected) +verifyFeeObject(std::shared_ptr const& ledger, Rules const& rules, FeeSettingsFields const& expected) { auto const feeObject = ledger->read(keylet::fees()); if (!feeObject) @@ -164,28 +126,20 @@ verifyFeeObject( if (rules.enabled(featureXRPFees)) { - if (feeObject->isFieldPresent(sfBaseFee) || - feeObject->isFieldPresent(sfReserveBase) || - feeObject->isFieldPresent(sfReserveIncrement) || - feeObject->isFieldPresent(sfReferenceFeeUnits)) + if (feeObject->isFieldPresent(sfBaseFee) || feeObject->isFieldPresent(sfReserveBase) || + feeObject->isFieldPresent(sfReserveIncrement) || feeObject->isFieldPresent(sfReferenceFeeUnits)) return false; - if (!checkEquality( - sfBaseFeeDrops, expected.baseFeeDrops.value_or(XRPAmount{0}))) + if (!checkEquality(sfBaseFeeDrops, expected.baseFeeDrops.value_or(XRPAmount{0}))) return false; - if (!checkEquality( - sfReserveBaseDrops, - expected.reserveBaseDrops.value_or(XRPAmount{0}))) + if (!checkEquality(sfReserveBaseDrops, expected.reserveBaseDrops.value_or(XRPAmount{0}))) return false; - if (!checkEquality( - sfReserveIncrementDrops, - expected.reserveIncrementDrops.value_or(XRPAmount{0}))) + if (!checkEquality(sfReserveIncrementDrops, expected.reserveIncrementDrops.value_or(XRPAmount{0}))) return false; } else { - if (feeObject->isFieldPresent(sfBaseFeeDrops) || - feeObject->isFieldPresent(sfReserveBaseDrops) || + if (feeObject->isFieldPresent(sfBaseFeeDrops) || feeObject->isFieldPresent(sfReserveBaseDrops) || feeObject->isFieldPresent(sfReserveIncrementDrops)) return false; @@ -232,10 +186,7 @@ class FeeVote_test : public beast::unit_test::suite } { Section config; - config.append( - {"reference_fee = 50", - "account_reserve = 1234567", - "owner_reserve = 1234"}); + config.append({"reference_fee = 50", "account_reserve = 1234567", "owner_reserve = 1234"}); auto setup = setup_FeeVote(config); BEAST_EXPECT(setup.reference_fee == 50); BEAST_EXPECT(setup.account_reserve == 1234567); @@ -243,10 +194,7 @@ class FeeVote_test : public beast::unit_test::suite } { Section config; - config.append( - {"reference_fee = blah", - "account_reserve = yada", - "owner_reserve = foo"}); + config.append({"reference_fee = blah", "account_reserve = yada", "owner_reserve = foo"}); // Illegal values are ignored, and the defaults left unchanged auto setup = setup_FeeVote(config); BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee); @@ -255,28 +203,18 @@ class FeeVote_test : public beast::unit_test::suite } { Section config; - config.append( - {"reference_fee = -50", - "account_reserve = -1234567", - "owner_reserve = -1234"}); + config.append({"reference_fee = -50", "account_reserve = -1234567", "owner_reserve = -1234"}); // Illegal values are ignored, and the defaults left unchanged auto setup = setup_FeeVote(config); BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee); - BEAST_EXPECT( - setup.account_reserve == static_cast(-1234567)); - BEAST_EXPECT( - setup.owner_reserve == static_cast(-1234)); + BEAST_EXPECT(setup.account_reserve == static_cast(-1234567)); + BEAST_EXPECT(setup.owner_reserve == static_cast(-1234)); } { - auto const big64 = std::to_string( - static_cast( - std::numeric_limits::max()) + - 1); + auto const big64 = + std::to_string(static_cast(std::numeric_limits::max()) + 1); Section config; - config.append( - {"reference_fee = " + big64, - "account_reserve = " + big64, - "owner_reserve = " + big64}); + config.append({"reference_fee = " + big64, "account_reserve = " + big64, "owner_reserve = " + big64}); // Illegal values are ignored, and the defaults left unchanged auto setup = setup_FeeVote(config); BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee); @@ -294,22 +232,15 @@ class FeeVote_test : public beast::unit_test::suite { jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Create the next ledger to apply transaction to - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Test successful fee transaction with legacy fields FeeSettingsFields fields{ - .baseFee = 10, - .reserveBase = 200000, - .reserveIncrement = 50000, - .referenceFeeUnits = 10}; + .baseFee = 10, .reserveBase = 200000, .reserveIncrement = 50000, .referenceFeeUnits = 10}; auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields); OpenView accum(ledger.get()); @@ -324,14 +255,10 @@ class FeeVote_test : public beast::unit_test::suite { jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Create the next ledger to apply transaction to - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); FeeSettingsFields fields{ .baseFeeDrops = XRPAmount{10}, @@ -357,48 +284,36 @@ class FeeVote_test : public beast::unit_test::suite { jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Create the next ledger to apply transaction to - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Test transaction with missing required legacy fields - auto invalidTx = createInvalidFeeTx( - ledger->rules(), ledger->seq(), true, false, 1); + auto invalidTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), true, false, 1); OpenView accum(ledger.get()); BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx)); // Test transaction with new format fields when XRPFees is disabled - auto disallowedTx = createInvalidFeeTx( - ledger->rules(), ledger->seq(), false, true, 2); + auto disallowedTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), false, true, 2); BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx)); } { jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Create the next ledger to apply transaction to - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Test transaction with missing required new fields - auto invalidTx = createInvalidFeeTx( - ledger->rules(), ledger->seq(), true, false, 3); + auto invalidTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), true, false, 3); OpenView accum(ledger.get()); BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx)); // Test transaction with legacy fields when XRPFees is enabled - auto disallowedTx = createInvalidFeeTx( - ledger->rules(), ledger->seq(), false, true, 4); + auto disallowedTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), false, true, 4); BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx)); } } @@ -410,14 +325,10 @@ class FeeVote_test : public beast::unit_test::suite jtx::Env env(*this, jtx::testable_amendments()); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Create the next ledger to apply transaction to - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); auto feeTx = createFeeTx( ledger->rules(), @@ -449,13 +360,9 @@ class FeeVote_test : public beast::unit_test::suite jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); FeeSettingsFields fields1{ .baseFeeDrops = XRPAmount{10}, @@ -472,8 +379,7 @@ class FeeVote_test : public beast::unit_test::suite BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1)); // Apply second fee transaction with different values - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); FeeSettingsFields fields2{ .baseFeeDrops = XRPAmount{20}, @@ -498,13 +404,9 @@ class FeeVote_test : public beast::unit_test::suite jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Test transaction with wrong ledger sequence auto feeTx = createFeeTx( @@ -529,13 +431,9 @@ class FeeVote_test : public beast::unit_test::suite jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); FeeSettingsFields fields1{ .baseFeeDrops = XRPAmount{10}, @@ -551,13 +449,10 @@ class FeeVote_test : public beast::unit_test::suite BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1)); - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Apply partial update (only some fields) - FeeSettingsFields fields2{ - .baseFeeDrops = XRPAmount{20}, - .reserveBaseDrops = XRPAmount{200000}}; + FeeSettingsFields fields2{.baseFeeDrops = XRPAmount{20}, .reserveBaseDrops = XRPAmount{200000}}; auto feeTx2 = createFeeTx(ledger->rules(), ledger->seq(), fields2); { @@ -577,20 +472,15 @@ class FeeVote_test : public beast::unit_test::suite jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); // Test invalid transaction with non-zero account - this should fail // validation auto invalidTx = STTx(ttFEE, [&](auto& obj) { - obj.setAccountID( - sfAccount, - AccountID(1)); // Should be zero (this makes it invalid) + obj.setAccountID(sfAccount, + AccountID(1)); // Should be zero (this makes it invalid) obj.setFieldU32(sfLedgerSequence, ledger->seq()); obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10}); obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000}); @@ -619,20 +509,13 @@ class FeeVote_test : public beast::unit_test::suite auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote")); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); auto sec = randomSecretKey(); auto pub = derivePublicKey(KeyType::secp256k1, sec); auto val = std::make_shared( - env.app().timeKeeper().now(), - pub, - sec, - calcNodeID(pub), - [](STValidation& v) { + env.app().timeKeeper().now(), pub, sec, calcNodeID(pub), [](STValidation& v) { v.setFieldU32(sfLedgerSequence, 12345); }); @@ -643,9 +526,7 @@ class FeeVote_test : public beast::unit_test::suite feeVote->doValidation(currentFees, ledger->rules(), *val); BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops)); - BEAST_EXPECT( - val->getFieldAmount(sfBaseFeeDrops) == - XRPAmount(setup.reference_fee)); + BEAST_EXPECT(val->getFieldAmount(sfBaseFeeDrops) == XRPAmount(setup.reference_fee)); } // Test with XRPFees disabled (legacy format) @@ -654,20 +535,13 @@ class FeeVote_test : public beast::unit_test::suite auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote")); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); auto sec = randomSecretKey(); auto pub = derivePublicKey(KeyType::secp256k1, sec); auto val = std::make_shared( - env.app().timeKeeper().now(), - pub, - sec, - calcNodeID(pub), - [](STValidation& v) { + env.app().timeKeeper().now(), pub, sec, calcNodeID(pub), [](STValidation& v) { v.setFieldU32(sfLedgerSequence, 12345); }); @@ -696,24 +570,19 @@ class FeeVote_test : public beast::unit_test::suite Env env(*this, testable_amendments() | featureXRPFees); // establish what the current fees are - BEAST_EXPECT( - env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE}); + BEAST_EXPECT(env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE}); BEAST_EXPECT(env.current()->fees().reserve == XRPAmount{200'000'000}); BEAST_EXPECT(env.current()->fees().increment == XRPAmount{50'000'000}); auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote")); auto ledger = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // doVoting requires a flag ledger (every 256th ledger) // We need to create a ledger at sequence 256 to make it a flag ledger for (int i = 0; i < 256 - 1; ++i) { - ledger = std::make_shared( - *ledger, env.app().timeKeeper().closeTime()); + ledger = std::make_shared(*ledger, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(ledger->isFlagLedger()); @@ -726,28 +595,19 @@ class FeeVote_test : public beast::unit_test::suite auto pub = derivePublicKey(KeyType::secp256k1, sec); auto val = std::make_shared( - env.app().timeKeeper().now(), - pub, - sec, - calcNodeID(pub), - [&](STValidation& v) { + env.app().timeKeeper().now(), pub, sec, calcNodeID(pub), [&](STValidation& v) { v.setFieldU32(sfLedgerSequence, ledger->seq()); // Vote for different fees than current - v.setFieldAmount( - sfBaseFeeDrops, XRPAmount{setup.reference_fee}); - v.setFieldAmount( - sfReserveBaseDrops, XRPAmount{setup.account_reserve}); - v.setFieldAmount( - sfReserveIncrementDrops, - XRPAmount{setup.owner_reserve}); + v.setFieldAmount(sfBaseFeeDrops, XRPAmount{setup.reference_fee}); + v.setFieldAmount(sfReserveBaseDrops, XRPAmount{setup.account_reserve}); + v.setFieldAmount(sfReserveIncrementDrops, XRPAmount{setup.owner_reserve}); }); if (i % 2) val->setTrusted(); validations.push_back(val); } - auto txSet = std::make_shared( - SHAMapType::TRANSACTION, env.app().getNodeFamily()); + auto txSet = std::make_shared(SHAMapType::TRANSACTION, env.app().getNodeFamily()); // This should not throw since we have a flag ledger feeVote->doVoting(ledger, validations, txSet); @@ -772,15 +632,9 @@ class FeeVote_test : public beast::unit_test::suite BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits)); // Check the values - BEAST_EXPECT( - feeTx.getFieldAmount(sfBaseFeeDrops) == - XRPAmount{setup.reference_fee}); - BEAST_EXPECT( - feeTx.getFieldAmount(sfReserveBaseDrops) == - XRPAmount{setup.account_reserve}); - BEAST_EXPECT( - feeTx.getFieldAmount(sfReserveIncrementDrops) == - XRPAmount{setup.owner_reserve}); + BEAST_EXPECT(feeTx.getFieldAmount(sfBaseFeeDrops) == XRPAmount{setup.reference_fee}); + BEAST_EXPECT(feeTx.getFieldAmount(sfReserveBaseDrops) == XRPAmount{setup.account_reserve}); + BEAST_EXPECT(feeTx.getFieldAmount(sfReserveIncrementDrops) == XRPAmount{setup.owner_reserve}); } void @@ -799,7 +653,7 @@ class FeeVote_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(FeeVote, app, ripple); +BEAST_DEFINE_TESTSUITE(FeeVote, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/FixNFTokenPageLinks_test.cpp b/src/test/app/FixNFTokenPageLinks_test.cpp index 5c810169e6..88f368e9cf 100644 --- a/src/test/app/FixNFTokenPageLinks_test.cpp +++ b/src/test/app/FixNFTokenPageLinks_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { class FixNFTokenPageLinks_test : public beast::unit_test::suite { @@ -59,9 +40,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // creation of NFT pages that are completely full. This lambda // tells us the taxon value we should pass in in order for the // internal representation to match the passed in value. - auto internalTaxon = [this, &env]( - Account const& acct, - std::uint32_t taxon) -> std::uint32_t { + auto internalTaxon = [this, &env](Account const& acct, std::uint32_t taxon) -> std::uint32_t { std::uint32_t tokenSeq = [this, &env, &acct]() { auto const le = env.le(acct); if (BEAST_EXPECT(le)) @@ -70,9 +49,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite }(); // We must add FirstNFTokenSequence. - tokenSeq += env.le(acct) - ->at(~sfFirstNFTokenSequence) - .value_or(env.seq(acct)); + tokenSeq += env.le(acct)->at(~sfFirstNFTokenSequence).value_or(env.seq(acct)); return toUInt32(nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); }; @@ -87,8 +64,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // populated. std::uint32_t const intTaxon = (i / 16) + (i & 0b10000 ? 2 : 0); uint32_t const extTaxon = internalTaxon(owner, intTaxon); - nfts.push_back( - token::getNextID(env, owner, extTaxon, tfTransferable)); + nfts.push_back(token::getNextID(env, owner, extTaxon, tfTransferable)); env(token::mint(owner, extTaxon), txflags(tfTransferable)); env.close(); } @@ -104,15 +80,13 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite params[jss::account] = owner.human(); auto resp = env.rpc("json", "account_objects", to_string(params)); - Json::Value const& acctObjs = - resp[jss::result][jss::account_objects]; + Json::Value const& acctObjs = resp[jss::result][jss::account_objects]; int pageCount = 0; for (Json::UInt i = 0; i < acctObjs.size(); ++i) { if (BEAST_EXPECT( - acctObjs[i].isMember(sfNFTokens.jsonName) && - acctObjs[i][sfNFTokens.jsonName].isArray())) + acctObjs[i].isMember(sfNFTokens.jsonName) && acctObjs[i][sfNFTokens.jsonName].isArray())) { BEAST_EXPECT(acctObjs[i][sfNFTokens.jsonName].size() == 32); ++pageCount; @@ -141,9 +115,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite env.fund(XRP(1000), alice); auto const linkFixFee = drops(env.current()->fees().increment); - env(ledgerStateFix::nftPageLinks(alice, alice), - fee(linkFixFee), - ter(temDISABLED)); + env(ledgerStateFix::nftPageLinks(alice, alice), fee(linkFixFee), ter(temDISABLED)); } Env env{*this, testable_amendments()}; @@ -154,7 +126,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // Preflight { - // Fail preflight1. Can't combine AcccountTxnID and ticket. + // Fail preflight1. Can't combine AccountTxnID and ticket. Json::Value tx = ledgerStateFix::nftPageLinks(alice, alice); tx[sfAccountTxnID.jsonName] = "00000000000000000000000000000000" @@ -166,10 +138,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // Invalid flags. auto const linkFixFee = drops(env.current()->fees().increment); - env(ledgerStateFix::nftPageLinks(alice, alice), - fee(linkFixFee), - txflags(tfPassive), - ter(temINVALID_FLAG)); + env(ledgerStateFix::nftPageLinks(alice, alice), fee(linkFixFee), txflags(tfPassive), ter(temINVALID_FLAG)); { // ledgerStateFix::nftPageLinks requires an Owner field. @@ -190,9 +159,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // Preclaim Account const carol("carol"); env.memoize(carol); - env(ledgerStateFix::nftPageLinks(alice, carol), - fee(linkFixFee), - ter(tecOBJECT_NOT_FOUND)); + env(ledgerStateFix::nftPageLinks(alice, carol), fee(linkFixFee), ter(tecOBJECT_NOT_FOUND)); } void @@ -213,17 +180,13 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // Owner has no pages to fix. auto const linkFixFee = drops(env.current()->fees().increment); - env(ledgerStateFix::nftPageLinks(alice, alice), - fee(linkFixFee), - ter(tecFAILED_PROCESSING)); + env(ledgerStateFix::nftPageLinks(alice, alice), fee(linkFixFee), ter(tecFAILED_PROCESSING)); // Alice has only one page. env(token::mint(alice), txflags(tfTransferable)); env.close(); - env(ledgerStateFix::nftPageLinks(alice, alice), - fee(linkFixFee), - ter(tecFAILED_PROCESSING)); + env(ledgerStateFix::nftPageLinks(alice, alice), fee(linkFixFee), ter(tecFAILED_PROCESSING)); // Alice has at least three pages. for (std::uint32_t i = 0; i < 64; ++i) @@ -232,9 +195,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite env.close(); } - env(ledgerStateFix::nftPageLinks(alice, alice), - fee(linkFixFee), - ter(tecFAILED_PROCESSING)); + env(ledgerStateFix::nftPageLinks(alice, alice), fee(linkFixFee), ter(tecFAILED_PROCESSING)); } void @@ -299,15 +260,13 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // alice's "middle" page is still present, but has no links. { - auto aliceMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); + auto aliceMiddleNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(aliceMiddleNFTokenPage)) return; - BEAST_EXPECT( - !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT(!aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } //********************************************************************** @@ -344,13 +303,11 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // bob's "middle" page is still present, but has lost the // NextPageMin field. { - auto bobMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); + auto bobMiddleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(bobMiddleNFTokenPage)) return; - BEAST_EXPECT( - bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -375,10 +332,8 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite dariaNFTs.reserve(32); for (int i = 0; i < 32; ++i) { - uint256 const offerIndex = - keylet::nftoffer(carol, env.seq(carol)).key; - env(token::createOffer(carol, carolNFTs.back(), XRP(0)), - txflags(tfSellNFToken)); + uint256 const offerIndex = keylet::nftoffer(carol, env.seq(carol)).key; + env(token::createOffer(carol, carolNFTs.back(), XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(daria, offerIndex)); @@ -397,8 +352,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // carol's "middle" page is still present, but has lost the // NextPageMin field. - auto carolMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + auto carolMiddleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(carolMiddleNFTokenPage)) return; @@ -411,8 +365,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // back from daria. for (uint256 const& nft : dariaNFTs) { - uint256 const offerIndex = - keylet::nftoffer(carol, env.seq(carol)).key; + uint256 const offerIndex = keylet::nftoffer(carol, env.seq(carol)).key; env(token::createOffer(carol, nft, drops(1)), token::owner(daria)); env.close(); @@ -429,22 +382,19 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // carol's "middle" page is present and still has no NextPageMin field. { - auto carolMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + auto carolMiddleNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(carolMiddleNFTokenPage)) return; - BEAST_EXPECT( - carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT(carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } // carol has a "last" page again, but it has no PreviousPageMin field. { auto carolLastNFTokenPage = env.le(keylet::nftpage_max(carol)); - BEAST_EXPECT( - !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -453,9 +403,7 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite //********************************************************************** // Verify that the LedgerStateFix transaction is not enabled. auto const linkFixFee = drops(env.current()->fees().increment); - env(ledgerStateFix::nftPageLinks(daria, alice), - fee(linkFixFee), - ter(temDISABLED)); + env(ledgerStateFix::nftPageLinks(daria, alice), fee(linkFixFee), ter(temDISABLED)); // Wait 15 ledgers so the LedgerStateFix transaction is no longer // retried. @@ -476,15 +424,13 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // alice's "middle" page is still present and has no links. { - auto aliceMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); + auto aliceMiddleNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(aliceMiddleNFTokenPage)) return; - BEAST_EXPECT( - !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT(!aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } // The server "remembers" daria's failed nftPageLinks transaction @@ -496,20 +442,18 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite env(ledgerStateFix::nftPageLinks(daria, alice), fee(linkFixFee)); env.close(); - // alices's last page should now be present and include no links. + // alice's last page should now be present and include no links. { auto aliceLastNFTokenPage = env.le(keylet::nftpage_max(alice)); if (!BEAST_EXPECT(aliceLastNFTokenPage)) return; - BEAST_EXPECT( - !aliceLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!aliceLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!aliceLastNFTokenPage->isFieldPresent(sfNextPageMin)); } // alice's middle page should be gone. - BEAST_EXPECT(!env.le(keylet::nftpage( - keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex))); + BEAST_EXPECT(!env.le(keylet::nftpage(keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex))); BEAST_EXPECT(nftCount(env, alice) == 32); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -525,13 +469,11 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // bob's "middle" page is still present and missing NextPageMin. { - auto bobMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); + auto bobMiddleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(bobMiddleNFTokenPage)) return; - BEAST_EXPECT( - bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -548,28 +490,22 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite return; BEAST_EXPECT(bobLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - bobLastNFTokenPage->at(sfPreviousPageMin) != - bobMiddleNFTokenPageIndex); + BEAST_EXPECT(bobLastNFTokenPage->at(sfPreviousPageMin) != bobMiddleNFTokenPageIndex); BEAST_EXPECT(!bobLastNFTokenPage->isFieldPresent(sfNextPageMin)); - auto const bobNewFirstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(bob), - bobLastNFTokenPage->at(sfPreviousPageMin))); + auto const bobNewFirstNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(bob), bobLastNFTokenPage->at(sfPreviousPageMin))); if (!BEAST_EXPECT(bobNewFirstNFTokenPage)) return; BEAST_EXPECT( bobNewFirstNFTokenPage->isFieldPresent(sfNextPageMin) && - bobNewFirstNFTokenPage->at(sfNextPageMin) == - lastPageKeylet.key); - BEAST_EXPECT( - !bobNewFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + bobNewFirstNFTokenPage->at(sfNextPageMin) == lastPageKeylet.key); + BEAST_EXPECT(!bobNewFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); } // bob's middle page should be gone. - BEAST_EXPECT(!env.le(keylet::nftpage( - keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex))); + BEAST_EXPECT(!env.le(keylet::nftpage(keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex))); BEAST_EXPECT(nftCount(env, bob) == 64); BEAST_EXPECT(ownerCount(env, bob) == 2); @@ -582,22 +518,19 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite // carol's "middle" page is present and has no NextPageMin field. { - auto carolMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + auto carolMiddleNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(carolMiddleNFTokenPage)) return; - BEAST_EXPECT( - carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT(carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); } // carol has a "last" page, but it has no PreviousPageMin field. { auto carolLastNFTokenPage = env.le(keylet::nftpage_max(carol)); - BEAST_EXPECT( - !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -608,17 +541,15 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite { // carol's "middle" page is present and now has a NextPageMin field. auto const lastPageKeylet = keylet::nftpage_max(carol); - auto carolMiddleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + auto carolMiddleNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); if (!BEAST_EXPECT(carolMiddleNFTokenPage)) return; - BEAST_EXPECT( - carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT( carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin) && - carolMiddleNFTokenPage->at(sfNextPageMin) == - lastPageKeylet.key); + carolMiddleNFTokenPage->at(sfNextPageMin) == lastPageKeylet.key); // carol has a "last" page that includes a PreviousPageMin field. auto carolLastNFTokenPage = env.le(lastPageKeylet); @@ -627,23 +558,19 @@ class FixNFTokenPageLinks_test : public beast::unit_test::suite BEAST_EXPECT( carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin) && - carolLastNFTokenPage->at(sfPreviousPageMin) == - carolMiddleNFTokenPageIndex); + carolLastNFTokenPage->at(sfPreviousPageMin) == carolMiddleNFTokenPageIndex); BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); // carol also has a "first" page that includes a NextPageMin field. - auto carolFirstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(carol), - carolMiddleNFTokenPage->at(sfPreviousPageMin))); + auto carolFirstNFTokenPage = + env.le(keylet::nftpage(keylet::nftpage_min(carol), carolMiddleNFTokenPage->at(sfPreviousPageMin))); if (!BEAST_EXPECT(carolFirstNFTokenPage)) return; BEAST_EXPECT( carolFirstNFTokenPage->isFieldPresent(sfNextPageMin) && - carolFirstNFTokenPage->at(sfNextPageMin) == - carolMiddleNFTokenPageIndex); - BEAST_EXPECT( - !carolFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + carolFirstNFTokenPage->at(sfNextPageMin) == carolMiddleNFTokenPageIndex); + BEAST_EXPECT(!carolFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); } // With the link repair, the server knows that carol has 96 NFTs. @@ -661,6 +588,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, app, ripple); +BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index 6c4331c7c8..551bd117d8 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -29,20 +10,15 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { bool -getNoRippleFlag( - jtx::Env const& env, - jtx::Account const& src, - jtx::Account const& dst, - Currency const& cur) +getNoRippleFlag(jtx::Env const& env, jtx::Account const& src, jtx::Account const& dst, Currency const& cur) { if (auto sle = env.le(keylet::line(src, dst, cur))) { - auto const flag = - (src.id() > dst.id()) ? lsfHighNoRipple : lsfLowNoRipple; + auto const flag = (src.id() > dst.id()) ? lsfHighNoRipple : lsfLowNoRipple; return sle->isFlag(flag); } Throw("No line in getTrustFlag"); @@ -99,9 +75,7 @@ struct Flow_test : public beast::unit_test::suite env(pay(gw, alice, USD(100))); env(pay(alice, bob, USD(110)), paths(USD), ter(tecPATH_PARTIAL)); env.require(balance(bob, USD(0))); - env(pay(alice, bob, USD(110)), - paths(USD), - txflags(tfPartialPayment)); + env(pay(alice, bob, USD(110)), paths(USD), txflags(tfPartialPayment)); env.require(balance(bob, USD(100))); } { @@ -114,10 +88,7 @@ struct Flow_test : public beast::unit_test::suite env.trust(USDB(10), carol); env.trust(USDC(10), dan); env(pay(alice, dan, USDC(10)), paths(USDA)); - env.require( - balance(bob, USDA(10)), - balance(carol, USDB(10)), - balance(dan, USDC(10))); + env.require(balance(bob, USDA(10)), balance(carol, USDB(10)), balance(dan, USDC(10))); } { // Pay by rippling through accounts, specify path @@ -133,10 +104,7 @@ struct Flow_test : public beast::unit_test::suite // alice will redeem to bob; a transfer fee will be charged env(pay(bob, alice, USDB(6))); - env(pay(alice, dan, USDC(5)), - path(bob, carol), - sendmax(USDA(6)), - txflags(tfNoRippleDirect)); + env(pay(alice, dan, USDC(5)), path(bob, carol), sendmax(USDA(6)), txflags(tfNoRippleDirect)); env.require(balance(dan, USDC(5))); env.require(balance(alice, USDB(0.5))); } @@ -152,10 +120,7 @@ struct Flow_test : public beast::unit_test::suite env.trust(USDC(10), dan); env(rate(bob, 1.1)); - env(pay(alice, dan, USDC(5)), - path(bob, carol), - sendmax(USDA(6)), - txflags(tfNoRippleDirect)); + env(pay(alice, dan, USDC(5)), path(bob, carol), sendmax(USDA(6)), txflags(tfNoRippleDirect)); env.require(balance(dan, USDC(5))); env.require(balance(bob, USDA(5))); } @@ -175,10 +140,7 @@ struct Flow_test : public beast::unit_test::suite // Pay alice so she redeems to carol and a transfer fee is charged env(pay(carol, alice, USDC(10))); - env(pay(alice, erin, USDD(5)), - path(carol, dan), - path(bob, dan), - txflags(tfNoRippleDirect)); + env(pay(alice, erin, USDD(5)), path(carol, dan), path(bob, dan), txflags(tfNoRippleDirect)); env.require(balance(erin, USDD(5))); env.require(balance(dan, USDB(5))); @@ -199,9 +161,7 @@ struct Flow_test : public beast::unit_test::suite ter(tecPATH_DRY)); env.require(balance(carol, USDB(0))); - env(pay(alice, carol, USDB(5)), - sendmax(USDA(4)), - txflags(tfPartialPayment)); + env(pay(alice, carol, USDB(5)), sendmax(USDA(4)), txflags(tfPartialPayment)); env.require(balance(carol, USDB(4))); } } @@ -234,15 +194,10 @@ struct Flow_test : public beast::unit_test::suite env(pay(alice, bob, USDA(100))); env.require(balance(bob, USDA(100))); - env(pay(dan, carol, USDA(10)), - path(bob), - sendmax(USDD(100)), - txflags(tfNoRippleDirect)); + env(pay(dan, carol, USDA(10)), path(bob), sendmax(USDD(100)), txflags(tfNoRippleDirect)); env.require(balance(bob, USDA(90))); if (bobAliceQOut > bobDanQIn) - env.require(balance( - bob, - USDD(10.0 * double(bobAliceQOut) / double(bobDanQIn)))); + env.require(balance(bob, USDD(10.0 * double(bobAliceQOut) / double(bobDanQIn)))); else env.require(balance(bob, USDD(10))); env.require(balance(carol, USDA(10))); @@ -261,8 +216,7 @@ struct Flow_test : public beast::unit_test::suite env(pay(alice, bob, USDA(10))); env.require(balance(bob, USDA(10))); env(pay(bob, carol, USDA(5)), sendmax(USDA(10))); - auto const effectiveQ = - carolAliceQIn > 100 ? 1.0 : carolAliceQIn / 100.0; + auto const effectiveQ = carolAliceQIn > 100 ? 1.0 : carolAliceQIn / 100.0; env.require(balance(bob, USDA(10.0 - 5.0 / effectiveQ))); } @@ -410,10 +364,7 @@ struct Flow_test : public beast::unit_test::suite BEAST_EXPECT(isOffer(env, bob, BTC(40), EUR(50))); BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50))); - env(pay(alice, carol, USD(50)), - path(~USD), - path(~EUR, ~USD), - sendmax(BTC(60))); + env(pay(alice, carol, USD(50)), path(~USD), path(~EUR, ~USD), sendmax(BTC(60))); env.require(balance(alice, BTC(10))); env.require(balance(bob, BTC(50))); @@ -499,17 +450,16 @@ struct Flow_test : public beast::unit_test::suite }(); BEAST_EXPECT(flowResult.removableOffers.size() == 1); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - if (flowResult.removableOffers.empty()) - return false; - Sandbox sb(&view, tapNONE); - for (auto const& o : flowResult.removableOffers) - if (auto ok = sb.peek(keylet::offer(o))) - offerDelete(sb, ok, flowJournal); - sb.apply(view); - return true; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + if (flowResult.removableOffers.empty()) + return false; + Sandbox sb(&view, tapNONE); + for (auto const& o : flowResult.removableOffers) + if (auto ok = sb.peek(keylet::offer(o))) + offerDelete(sb, ok, flowJournal); + sb.apply(view); + return true; + }); // used in payment, but since payment failed should be untouched BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50))); @@ -545,8 +495,7 @@ struct Flow_test : public beast::unit_test::suite // USD(0.5) of bob's USD offer. If we provide 1 drop for less // than USD(0.5), then the remaining fractional offer would // block the order book. - TER const expectedTER = - reducedOffersV2 ? TER(tecPATH_DRY) : TER(tesSUCCESS); + TER const expectedTER = reducedOffersV2 ? TER(tecPATH_DRY) : TER(tesSUCCESS); env(pay(alice, carol, EUR(1)), path(~XRP, ~EUR), sendmax(USD(0.4)), @@ -566,13 +515,11 @@ struct Flow_test : public beast::unit_test::suite std::uint64_t const bookRate = [&usdOffer]() { // Extract the least significant 64 bits from the // book page. That's where the quality is stored. - std::string bookDirStr = - to_string(usdOffer->at(sfBookDirectory)); + std::string bookDirStr = to_string(usdOffer->at(sfBookDirectory)); bookDirStr.erase(0, 48); return std::stoull(bookDirStr, nullptr, 16); }(); - std::uint64_t const actualRate = getRate( - usdOffer->at(sfTakerGets), usdOffer->at(sfTakerPays)); + std::uint64_t const actualRate = getRate(usdOffer->at(sfTakerGets), usdOffer->at(sfTakerPays)); // We expect the actual rate of the offer to be worse // (larger) than the rate of the book page holding the @@ -608,9 +555,7 @@ struct Flow_test : public beast::unit_test::suite env.trust(USD(1000), alice, bob); env(offer(gw, XRP(125), USD(125))); env(pay(alice, bob, USD(100)), sendmax(XRP(200))); - env.require( - balance(alice, xrpMinusFee(env, 10000 - 125)), - balance(bob, USD(100))); + env.require(balance(alice, xrpMinusFee(env, 10000 - 125)), balance(bob, USD(100))); } void @@ -706,13 +651,10 @@ struct Flow_test : public beast::unit_test::suite offersOnAccount(jtx::Env& env, jtx::Account account) { std::vector> result; - forEachItem( - *env.current(), - account, - [&result](std::shared_ptr const& sle) { - if (sle->getType() == ltOFFER) - result.push_back(sle); - }); + forEachItem(*env.current(), account, [&result](std::shared_ptr const& sle) { + if (sle->getType() == ltOFFER) + result.push_back(sle); + }); return result; } @@ -770,9 +712,7 @@ struct Flow_test : public beast::unit_test::suite BEAST_EXPECT(offer[sfTakerPays] == USD(500)); } - env(pay(alice, alice, EUR(600)), - sendmax(USD(500)), - txflags(tfPartialPayment)); + env(pay(alice, alice, EUR(600)), sendmax(USD(500)), txflags(tfPartialPayment)); env.close(); env.require(owners(alice, 3)); @@ -841,9 +781,7 @@ struct Flow_test : public beast::unit_test::suite BEAST_EXPECT(offer[sfTakerPays] == USD(500)); } - env(pay(alice, alice, EUR(60)), - sendmax(USD(50)), - txflags(tfPartialPayment)); + env(pay(alice, alice, EUR(60)), sendmax(USD(50)), txflags(tfPartialPayment)); env.close(); env.require(owners(alice, 3)); @@ -886,10 +824,7 @@ struct Flow_test : public beast::unit_test::suite // Consuming the offer changes the owner count, which could also cause // liquidity to decrease in the forward pass auto const toSend = consumeOffer ? USD(10) : USD(9); - env(pay(alice, alice, toSend), - path(~USD), - sendmax(XRP(20000)), - txflags(tfPartialPayment | tfNoRippleDirect)); + env(pay(alice, alice, toSend), path(~USD), sendmax(XRP(20000)), txflags(tfPartialPayment | tfNoRippleDirect)); } void @@ -911,24 +846,11 @@ struct Flow_test : public beast::unit_test::suite env.close(); env(trust(bob, USD(20))); - STAmount tinyAmt1{ - USD.issue(), - 9000000000000000ll, - -17, - false, - STAmount::unchecked{}}; - STAmount tinyAmt3{ - USD.issue(), - 9000000000000003ll, - -17, - false, - STAmount::unchecked{}}; + STAmount tinyAmt1{USD.issue(), 9000000000000000ll, -17, false, STAmount::unchecked{}}; + STAmount tinyAmt3{USD.issue(), 9000000000000003ll, -17, false, STAmount::unchecked{}}; env(offer(gw, drops(9000000000), tinyAmt3)); - env(pay(alice, bob, tinyAmt1), - path(~USD), - sendmax(drops(9000000000)), - txflags(tfNoRippleDirect)); + env(pay(alice, bob, tinyAmt1), path(~USD), sendmax(drops(9000000000)), txflags(tfNoRippleDirect)); BEAST_EXPECT(!isOffer(env, gw, XRP(0), USD(0))); } @@ -945,35 +867,22 @@ struct Flow_test : public beast::unit_test::suite env.close(); env(trust(alice, USD(20))); - STAmount tinyAmt1{ - USD.issue(), - 9000000000000000ll, - -17, - false, - STAmount::unchecked{}}; - STAmount tinyAmt3{ - USD.issue(), - 9000000000000003ll, - -17, - false, - STAmount::unchecked{}}; + STAmount tinyAmt1{USD.issue(), 9000000000000000ll, -17, false, STAmount::unchecked{}}; + STAmount tinyAmt3{USD.issue(), 9000000000000003ll, -17, false, STAmount::unchecked{}}; env(pay(gw, alice, tinyAmt1)); env(offer(gw, tinyAmt3, drops(9000000000))); - env(pay(alice, bob, drops(9000000000)), - path(~XRP), - sendmax(USD(1)), - txflags(tfNoRippleDirect)); + env(pay(alice, bob, drops(9000000000)), path(~XRP), sendmax(USD(1)), txflags(tfNoRippleDirect)); BEAST_EXPECT(!isOffer(env, gw, USD(0), XRP(0))); } } void - testReexecuteDirectStep(FeatureBitset features) + testReExecuteDirectStep(FeatureBitset features) { - testcase("ReexecuteDirectStep"); + testcase("ReExecuteDirectStep"); using namespace jtx; Env env(*this, features); @@ -991,45 +900,37 @@ struct Flow_test : public beast::unit_test::suite BEAST_EXPECT(!getNoRippleFlag(env, gw, alice, usdC)); - env(pay( - gw, - alice, - // 12.55.... - STAmount{ - USD.issue(), std::uint64_t(1255555555555555ull), -14, false})); + env( + pay(gw, + alice, + // 12.55.... + STAmount{USD.issue(), std::uint64_t(1255555555555555ull), -14, false})); env(offer( gw, // 5.0... - STAmount{ - USD.issue(), std::uint64_t(5000000000000000ull), -15, false}, + STAmount{USD.issue(), std::uint64_t(5000000000000000ull), -15, false}, XRP(1000))); env(offer( gw, // .555... - STAmount{ - USD.issue(), std::uint64_t(5555555555555555ull), -16, false}, + STAmount{USD.issue(), std::uint64_t(5555555555555555ull), -16, false}, XRP(10))); env(offer( gw, // 4.44.... - STAmount{ - USD.issue(), std::uint64_t(4444444444444444ull), -15, false}, + STAmount{USD.issue(), std::uint64_t(4444444444444444ull), -15, false}, XRP(.1))); env(offer( alice, // 17 - STAmount{ - USD.issue(), std::uint64_t(1700000000000000ull), -14, false}, + STAmount{USD.issue(), std::uint64_t(1700000000000000ull), -14, false}, XRP(.001))); - env(pay(alice, bob, XRP(10000)), - path(~XRP), - sendmax(USD(100)), - txflags(tfPartialPayment | tfNoRippleDirect)); + env(pay(alice, bob, XRP(10000)), path(~XRP), sendmax(USD(100)), txflags(tfPartialPayment | tfNoRippleDirect)); } void @@ -1155,9 +1056,7 @@ struct Flow_test : public beast::unit_test::suite env.close(); // This payment caused the assert. - env(pay(ann, ann, CTB(0.687)), - sendmax(drops(20000000000)), - txflags(tfPartialPayment)); + env(pay(ann, ann, CTB(0.687)), sendmax(drops(20000000000)), txflags(tfPartialPayment)); } void @@ -1173,9 +1072,7 @@ struct Flow_test : public beast::unit_test::suite env.fund(XRP(10000), alice); env.close(); - env(pay(alice, alice, alice["USD"](100)), - path(~alice["USD"]), - ter(temBAD_PATH)); + env(pay(alice, alice, alice["USD"](100)), path(~alice["USD"]), ter(temBAD_PATH)); } void @@ -1289,8 +1186,7 @@ struct Flow_test : public beast::unit_test::suite env(pay(alice, bob, XRP(1000)), ticket::use(ticketSeq)); env.close(); env.require(balance(bob, XRP(1000))); - env.require( - balance(alice, XRP(9000) - (env.current()->fees().base * 2))); + env.require(balance(alice, XRP(9000) - (env.current()->fees().base * 2))); } void @@ -1310,7 +1206,7 @@ struct Flow_test : public beast::unit_test::suite testSelfFundedXRPEndpoint(false, features); testSelfFundedXRPEndpoint(true, features); testUnfundedOffer(features); - testReexecuteDirectStep(features); + testReExecuteDirectStep(features); testSelfPayLowQualityOffer(features); testTicketPay(features); } @@ -1348,8 +1244,8 @@ struct Flow_manual_test : public Flow_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(Flow, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Flow_manual, app, ripple, 4); +BEAST_DEFINE_TESTSUITE_PRIO(Flow, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Flow_manual, app, xrpl, 4); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Freeze_test.cpp b/src/test/app/Freeze_test.cpp index 3bde3a30af..9d7db52e56 100644 --- a/src/test/app/Freeze_test.cpp +++ b/src/test/app/Freeze_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { class Freeze_test : public beast::unit_test::suite { @@ -88,15 +69,11 @@ class Freeze_test : public beast::unit_test::suite // Is created via a TrustSet with SetFreeze flag // test: sets LowFreeze | HighFreeze flags env(trust(G1, bob["USD"](0), tfSetFreeze)); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 2u))) return; - auto ff = - affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfLowLimit.fieldName] == - G1["USD"](0).value().getJson(JsonOptions::none)); + auto ff = affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; + BEAST_EXPECT(ff[sfLowLimit.fieldName] == G1["USD"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze)); env.close(); @@ -106,18 +83,12 @@ class Freeze_test : public beast::unit_test::suite // Account with line frozen by issuer // test: can buy more assets on that line env(offer(bob, G1["USD"](5), XRP(25))); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 5u))) return; - auto ff = - affected[3u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfHighLimit.fieldName] == - bob["USD"](100).value().getJson(JsonOptions::none)); - auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15} - .value() - .getJson(JsonOptions::none); + auto ff = affected[3u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; + BEAST_EXPECT(ff[sfHighLimit.fieldName] == bob["USD"](100).value().getJson(JsonOptions::none)); + auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15}.value().getJson(JsonOptions::none); BEAST_EXPECT(ff[sfBalance.fieldName] == amt); env.close(); } @@ -174,15 +145,11 @@ class Freeze_test : public beast::unit_test::suite // Is cleared via a TrustSet with ClearFreeze flag // test: sets LowFreeze | HighFreeze flags env(trust(G1, bob["USD"](0), tfClearFreeze)); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 2u))) return; - auto ff = - affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfLowLimit.fieldName] == - G1["USD"](0).value().getJson(JsonOptions::none)); + auto ff = affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; + BEAST_EXPECT(ff[sfLowLimit.fieldName] == G1["USD"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze)); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze)); env.close(); @@ -230,8 +197,7 @@ class Freeze_test : public beast::unit_test::suite } // test: Issuer deep freezing not already frozen line must fail - env(trust(G1, A1["USD"](0), tfSetDeepFreeze), - ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](0), tfSetDeepFreeze), ter(tecNO_PERMISSION)); env(trust(G1, A1["USD"](0), tfSetFreeze)); env.close(); @@ -277,8 +243,7 @@ class Freeze_test : public beast::unit_test::suite env(trust(G1, A1["USD"](0), tfSetDeepFreeze), ter(temINVALID_FLAG)); // test: clearing deep freeze before amendment fails - env(trust(G1, A1["USD"](0), tfClearDeepFreeze), - ter(temINVALID_FLAG)); + env(trust(G1, A1["USD"](0), tfClearDeepFreeze), ter(temINVALID_FLAG)); } } @@ -314,8 +279,7 @@ class Freeze_test : public beast::unit_test::suite // test: cannot create deep frozen trustline without normal freeze if (features[featureDeepFreeze]) { - env(trust(G1, A1["USD"](1000), tfSetDeepFreeze), - ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](1000), tfSetDeepFreeze), ter(tecNO_PERMISSION)); env.close(); env.require(lines(A1, 0)); } @@ -353,14 +317,10 @@ class Freeze_test : public beast::unit_test::suite { // test: can't have both set and clear flag families in the same // transaction - env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearFreeze), - ter(tecNO_PERMISSION)); - env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearDeepFreeze), - ter(tecNO_PERMISSION)); - env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearFreeze), - ter(tecNO_PERMISSION)); - env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearDeepFreeze), - ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearFreeze), ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearDeepFreeze), ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearFreeze), ter(tecNO_PERMISSION)); + env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearDeepFreeze), ter(tecNO_PERMISSION)); } else { @@ -368,10 +328,8 @@ class Freeze_test : public beast::unit_test::suite // trust line env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearFreeze)); { - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; - BEAST_EXPECT(checkArraySize( - affected, 1u)); // means no trustline changes + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; + BEAST_EXPECT(checkArraySize(affected, 1u)); // means no trustline changes } } } @@ -430,10 +388,7 @@ class Freeze_test : public beast::unit_test::suite { // Account without GlobalFreeze (proving operations normally work) // test: visible offers where taker_pays is unfrozen issuer - auto offers = env.rpc( - "book_offers", - std::string("USD/") + G1.human(), - "XRP")[jss::result][jss::offers]; + auto offers = env.rpc("book_offers", std::string("USD/") + G1.human(), "XRP")[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 2u))) return; std::set accounts; @@ -445,10 +400,7 @@ class Freeze_test : public beast::unit_test::suite BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts)); // test: visible offers where taker_gets is unfrozen issuer - offers = env.rpc( - "book_offers", - "XRP", - std::string("USD/") + G1.human())[jss::result][jss::offers]; + offers = env.rpc("book_offers", "XRP", std::string("USD/") + G1.human())[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 2u))) return; accounts.clear(); @@ -506,17 +458,11 @@ class Freeze_test : public beast::unit_test::suite // test: book_offers shows offers // (should these actually be filtered?) - offers = env.rpc( - "book_offers", - "XRP", - std::string("USD/") + G1.human())[jss::result][jss::offers]; + offers = env.rpc("book_offers", "XRP", std::string("USD/") + G1.human())[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 2u))) return; - offers = env.rpc( - "book_offers", - std::string("USD/") + G1.human(), - "XRP")[jss::result][jss::offers]; + offers = env.rpc("book_offers", std::string("USD/") + G1.human(), "XRP")[jss::result][jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 2u))) return; } @@ -572,8 +518,7 @@ class Freeze_test : public beast::unit_test::suite } if (features[featureDeepFreeze]) { - env(trust( - G1, deepFrozenAcc["USD"](0), tfSetFreeze | tfSetDeepFreeze)); + env(trust(G1, deepFrozenAcc["USD"](0), tfSetFreeze | tfSetDeepFreeze)); { auto const flags = getTrustlineFlags(env, 2u, 1u); BEAST_EXPECT(!(flags & (lsfLowFreeze | lsfLowDeepFreeze))); @@ -612,21 +557,18 @@ class Freeze_test : public beast::unit_test::suite // test: cannot deep freeze already frozen line when no freeze // enacted - env(trust(G1, frozenAcc["USD"](0), tfSetDeepFreeze), - ter(tecNO_PERMISSION)); + env(trust(G1, frozenAcc["USD"](0), tfSetDeepFreeze), ter(tecNO_PERMISSION)); } else { // test: previous functionality, checking there's no changes to a // trust line env(trust(G1, A1["USD"](0), tfSetFreeze)); - auto affected = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 1u))) return; - auto let = affected[0u][sfModifiedNode.fieldName] - [sfLedgerEntryType.fieldName]; + auto let = affected[0u][sfModifiedNode.fieldName][sfLedgerEntryType.fieldName]; BEAST_EXPECT(let == jss::AccountRoot); } @@ -687,9 +629,7 @@ class Freeze_test : public beast::unit_test::suite auto offers = getAccountOffers(env, A3)[jss::offers]; if (!BEAST_EXPECT(checkArraySize(offers, 1u))) return; - BEAST_EXPECT( - offers[0u][jss::taker_gets] == - G1["USD"](999).value().getJson(JsonOptions::none)); + BEAST_EXPECT(offers[0u][jss::taker_gets] == G1["USD"](999).value().getJson(JsonOptions::none)); // test: someone else creates an offer providing liquidity env(offer(A4, XRP(999), G1["USD"](999))); @@ -697,15 +637,11 @@ class Freeze_test : public beast::unit_test::suite // test: owner of partially consumed offers line is frozen env(trust(G1, A3["USD"](0), tfSetFreeze)); - auto affected = - env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; + auto affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 2u))) return; - auto ff = - affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfHighLimit.fieldName] == - G1["USD"](0).value().getJson(JsonOptions::none)); + auto ff = affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; + BEAST_EXPECT(ff[sfHighLimit.fieldName] == G1["USD"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze)); BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfHighFreeze); env.close(); @@ -727,27 +663,22 @@ class Freeze_test : public beast::unit_test::suite // removal buy successful OfferCreate // test: freeze the new offer env(trust(G1, A4["USD"](0), tfSetFreeze)); - affected = - env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; + affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 2u))) return; ff = affected[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName]; - BEAST_EXPECT( - ff[sfLowLimit.fieldName] == - G1["USD"](0).value().getJson(JsonOptions::none)); + BEAST_EXPECT(ff[sfLowLimit.fieldName] == G1["USD"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze); BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze)); env.close(); // test: can no longer create a crossing offer env(offer(A2, G1["USD"](999), XRP(999))); - affected = - env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; + affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, 8u))) return; auto created = affected[0u][sfCreatedNode.fieldName]; - BEAST_EXPECT( - created[sfNewFields.fieldName][jss::Account] == A2.human()); + BEAST_EXPECT(created[sfNewFields.fieldName][jss::Account] == A2.human()); env.close(); // test: offer was removed by offer_create @@ -819,20 +750,15 @@ class Freeze_test : public beast::unit_test::suite // test: can still buy from A2 env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill)); env.close(); - env.require( - balance(A1, USD(1001)), balance(A2, USD(998)), offers(A1, 0)); + env.require(balance(A1, USD(1001)), balance(A2, USD(998)), offers(A1, 0)); // test: cannot create passive sell offer - env(offer(A1, XRP(2), USD(1)), - txflags(tfPassive), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(2), USD(1)), txflags(tfPassive), ter(tecUNFUNDED_OFFER)); env.close(); env.require(balance(A1, USD(1001)), offers(A1, 0)); // test: cannot sell to A3 - env(offer(A1, XRP(1), USD(1)), - txflags(tfFillOrKill), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(1), USD(1)), txflags(tfFillOrKill), ter(tecUNFUNDED_OFFER)); env.close(); env.require(balance(A1, USD(1001)), offers(A1, 0)); @@ -848,27 +774,19 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: cannot create passive buy offer - env(offer(A1, USD(1), XRP(0.5)), - txflags(tfPassive), - ter(tecFROZEN)); + env(offer(A1, USD(1), XRP(0.5)), txflags(tfPassive), ter(tecFROZEN)); env.close(); // test: cannot buy from A2 - env(offer(A1, USD(1), XRP(2)), - txflags(tfFillOrKill), - ter(tecFROZEN)); + env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill), ter(tecFROZEN)); env.close(); // test: cannot create passive sell offer - env(offer(A1, XRP(2), USD(1)), - txflags(tfPassive), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(2), USD(1)), txflags(tfPassive), ter(tecUNFUNDED_OFFER)); env.close(); // test: cannot sell to A3 - env(offer(A1, XRP(1), USD(1)), - txflags(tfFillOrKill), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(1), USD(1)), txflags(tfFillOrKill), ter(tecUNFUNDED_OFFER)); env.close(); env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze)); @@ -892,18 +810,13 @@ class Freeze_test : public beast::unit_test::suite env.require(balance(A1, USD(1001)), balance(A2, USD(998))); env(offer(A2, XRP(1.1), USD(1)), txflags(tfFillOrKill)); env.close(); - env.require( - balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1)); + env.require(balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1)); // test: A3 wants to buy from A1, must fail - env.require( - balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1)); - env(offer(A3, USD(1), XRP(1.9)), - txflags(tfFillOrKill), - ter(tecKILLED)); + env.require(balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1)); + env(offer(A3, USD(1), XRP(1.9)), txflags(tfFillOrKill), ter(tecKILLED)); env.close(); - env.require( - balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0)); + env.require(balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0)); env(trust(G1, A1["USD"](0), tfClearFreeze)); env.close(); @@ -924,22 +837,15 @@ class Freeze_test : public beast::unit_test::suite // test: A2 wants to sell to A1, must fail env.require(balance(A1, USD(1002)), balance(A2, USD(997))); - env(offer(A2, XRP(1.1), USD(1)), - txflags(tfFillOrKill), - ter(tecKILLED)); + env(offer(A2, XRP(1.1), USD(1)), txflags(tfFillOrKill), ter(tecKILLED)); env.close(); - env.require( - balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1)); + env.require(balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1)); // test: A3 wants to buy from A1, must fail - env.require( - balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1)); - env(offer(A3, USD(1), XRP(1.9)), - txflags(tfFillOrKill), - ter(tecKILLED)); + env.require(balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1)); + env(offer(A3, USD(1), XRP(1.9)), txflags(tfFillOrKill), ter(tecKILLED)); env.close(); - env.require( - balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0)); + env.require(balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0)); env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze)); env.close(); @@ -961,12 +867,9 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 wants to buy, must fail - env(offer(A1, USD(1), XRP(2)), - txflags(tfFillOrKill), - ter(tecKILLED)); + env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill), ter(tecKILLED)); env.close(); - env.require( - balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 0)); + env.require(balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 0)); // test: A1 can create passive sell offer env(offer(A1, XRP(2), USD(1)), txflags(tfPassive)); @@ -994,27 +897,19 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot create passive buy offer - env(offer(A1, USD(1), XRP(0.5)), - txflags(tfPassive), - ter(tecFROZEN)); + env(offer(A1, USD(1), XRP(0.5)), txflags(tfPassive), ter(tecFROZEN)); env.close(); // test: A1 cannot buy, must fail - env(offer(A1, USD(1), XRP(2)), - txflags(tfFillOrKill), - ter(tecFROZEN)); + env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill), ter(tecFROZEN)); env.close(); // test: A1 cannot create passive sell offer - env(offer(A1, XRP(2), USD(1)), - txflags(tfPassive), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(2), USD(1)), txflags(tfPassive), ter(tecUNFUNDED_OFFER)); env.close(); // test: A1 cannot sell to A3 - env(offer(A1, XRP(1), USD(1)), - txflags(tfFillOrKill), - ter(tecUNFUNDED_OFFER)); + env(offer(A1, XRP(1), USD(1)), txflags(tfFillOrKill), ter(tecUNFUNDED_OFFER)); env.close(); env(trust(A1, limit, tfClearFreeze | tfClearDeepFreeze)); @@ -1055,19 +950,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot send USD using XRP through A2 offer - env(pay(A1, G1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(A1, G1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); // test: G1 cannot send USD using XRP through A2 offer - env(pay(G1, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(G1, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze)); @@ -1081,19 +968,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot send USD using XRP through A2 offer - env(pay(A1, G1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(A1, G1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); // test: G1 cannot send USD using XRP through A2 offer - env(pay(G1, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(G1, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze)); @@ -1107,17 +986,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 can send USD using XRP through A2 offer - env(pay(A1, G1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect)); + env(pay(A1, G1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect)); env.close(); // test: G1 can send USD using XRP through A2 offer - env(pay(G1, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect)); + env(pay(G1, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect)); env.close(); env(trust(A2, limit, tfClearFreeze)); @@ -1132,19 +1005,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot send USD using XRP through A2 offer - env(pay(A1, G1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(A1, G1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); // test: G1 cannot send USD using XRP through A2 offer - env(pay(G1, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(G1, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze)); @@ -1165,17 +1030,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 can send XRP using USD through A2 offer - env(pay(A1, G1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(A1, G1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); // test: G1 can send XRP using USD through A2 offer - env(pay(G1, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(G1, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze)); @@ -1190,19 +1049,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot send XRP using USD through A2 offer - env(pay(A1, G1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(A1, G1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); // test: G1 cannot send XRP using USD through A2 offer - env(pay(G1, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(G1, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze)); @@ -1216,17 +1067,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 can send XRP using USD through A2 offer - env(pay(A1, G1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(A1, G1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); // test: G1 can send XRP using USD through A2 offer - env(pay(G1, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(G1, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); env(trust(A2, limit, tfClearFreeze)); @@ -1241,19 +1086,11 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A1 cannot send XRP using USD through A2 offer - env(pay(A1, G1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(A1, G1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); // test: G1 cannot send XRP using USD through A2 offer - env(pay(G1, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_PARTIAL)); + env(pay(G1, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_PARTIAL)); env.close(); env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze)); @@ -1715,32 +1552,19 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: can still use XRP to make payment - env(pay(A1, A2, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect)); + env(pay(A1, A2, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect)); env.close(); // test: cannot use USD to make payment - env(pay(A1, A2, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_DRY)); + env(pay(A1, A2, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_DRY)); env.close(); // test: can still receive USD payments. - env(pay(A2, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect)); + env(pay(A2, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect)); env.close(); // test: can still receive XRP payments. - env(pay(A2, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(A2, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); env(trust(G1, A1["USD"](0), tfClearFreeze)); @@ -1755,33 +1579,19 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: can still use XRP to make payment - env(pay(A1, A2, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect)); + env(pay(A1, A2, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect)); env.close(); // test: cannot use USD to make payment - env(pay(A1, A2, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_DRY)); + env(pay(A1, A2, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect), ter(tecPATH_DRY)); env.close(); // test: cannot receive USD payments. - env(pay(A2, A1, USD(10)), - path(~USD), - sendmax(XRP(11)), - txflags(tfNoRippleDirect), - ter(tecPATH_DRY)); + env(pay(A2, A1, USD(10)), path(~USD), sendmax(XRP(11)), txflags(tfNoRippleDirect), ter(tecPATH_DRY)); env.close(); // test: can still receive XRP payments. - env(pay(A2, A1, XRP(10)), - path(~XRP), - sendmax(USD(11)), - txflags(tfNoRippleDirect)); + env(pay(A2, A1, XRP(10)), path(~XRP), sendmax(USD(11)), txflags(tfNoRippleDirect)); env.close(); env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze)); @@ -1849,8 +1659,7 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A2 cannot send USD for NFT - env(token::acceptSellOffer(A2, sellOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptSellOffer(A2, sellOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze)); @@ -1865,8 +1674,7 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A2 cannot send USD for NFT - env(token::acceptSellOffer(A2, sellOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptSellOffer(A2, sellOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze)); @@ -1874,8 +1682,7 @@ class Freeze_test : public beast::unit_test::suite } // Testing A1 nft buy offer when A2 deep frozen by issuer - if (features[featureDeepFreeze] && - features[fixEnforceNFTokenTrustlineV2]) + if (features[featureDeepFreeze] && features[fixEnforceNFTokenTrustlineV2]) { env(trust(G1, A2["USD"](0), tfSetFreeze | tfSetDeepFreeze)); env.close(); @@ -1950,8 +1757,7 @@ class Freeze_test : public beast::unit_test::suite env.close(); // test: A2 cannot send USD for NFT - env(token::acceptSellOffer(A2, sellOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptSellOffer(A2, sellOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze)); @@ -1959,8 +1765,7 @@ class Freeze_test : public beast::unit_test::suite } // Testing brokered offer acceptance - if (features[featureDeepFreeze] && - features[fixEnforceNFTokenTrustlineV2]) + if (features[featureDeepFreeze] && features[fixEnforceNFTokenTrustlineV2]) { Account broker{"broker"}; env.fund(XRP(10000), broker); @@ -1979,15 +1784,12 @@ class Freeze_test : public beast::unit_test::suite env(token::createOffer(A1, nftID, USD(11)), token::owner(A2)); env.close(); - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecFROZEN)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecFROZEN)); env.close(); } // Testing transfer fee - if (features[featureDeepFreeze] && - features[fixEnforceNFTokenTrustlineV2]) + if (features[featureDeepFreeze] && features[fixEnforceNFTokenTrustlineV2]) { Account minter{"minter"}; env.fund(XRP(10000), minter); @@ -1995,24 +1797,18 @@ class Freeze_test : public beast::unit_test::suite env(trust(G1, minter["USD"](1000))); env.close(); - uint256 const nftID{ - token::getNextID(env, minter, 0u, tfTransferable, 1u)}; - env(token::mint(minter, 0), - token::xferFee(1u), - txflags(tfTransferable)); + uint256 const nftID{token::getNextID(env, minter, 0u, tfTransferable, 1u)}; + env(token::mint(minter, 0), token::xferFee(1u), txflags(tfTransferable)); env.close(); - uint256 const minterSellIdx = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, drops(1)), - txflags(tfSellNFToken)); + uint256 const minterSellIdx = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, drops(1)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(A2, minterSellIdx)); env.close(); uint256 const sellIdx = keylet::nftoffer(A2, env.seq(A2)).key; - env(token::createOffer(A2, nftID, USD(100)), - txflags(tfSellNFToken)); + env(token::createOffer(A2, nftID, USD(100)), txflags(tfSellNFToken)); env.close(); env(trust(G1, minter["USD"](1000), tfSetFreeze | tfSetDeepFreeze)); env.close(); @@ -2023,28 +1819,19 @@ class Freeze_test : public beast::unit_test::suite // Helper function to extract trustline flags from open ledger uint32_t - getTrustlineFlags( - test::jtx::Env& env, - size_t expectedArraySize, - size_t expectedArrayIndex, - bool modified = true) + getTrustlineFlags(test::jtx::Env& env, size_t expectedArraySize, size_t expectedArrayIndex, bool modified = true) { using namespace test::jtx; - auto const affected = - env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; + auto const affected = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; if (!BEAST_EXPECT(checkArraySize(affected, expectedArraySize))) return 0; if (modified) { - return affected[expectedArrayIndex][sfModifiedNode.fieldName] - [sfFinalFields.fieldName][jss::Flags] - .asUInt(); + return affected[expectedArrayIndex][sfModifiedNode.fieldName][sfFinalFields.fieldName][jss::Flags].asUInt(); } - return affected[expectedArrayIndex][sfCreatedNode.fieldName] - [sfNewFields.fieldName][jss::Flags] - .asUInt(); + return affected[expectedArrayIndex][sfCreatedNode.fieldName][sfNewFields.fieldName][jss::Flags].asUInt(); } // Helper function that returns the index of the next check on account @@ -2055,20 +1842,15 @@ class Freeze_test : public beast::unit_test::suite } uint256 - createNFTSellOffer( - test::jtx::Env& env, - test::jtx::Account const& account, - test::jtx::PrettyAmount const& currency) + createNFTSellOffer(test::jtx::Env& env, test::jtx::Account const& account, test::jtx::PrettyAmount const& currency) { using namespace test::jtx; uint256 const nftID{token::getNextID(env, account, 0u, tfTransferable)}; env(token::mint(account, 0), txflags(tfTransferable)); env.close(); - uint256 const sellOfferIndex = - keylet::nftoffer(account, env.seq(account)).key; - env(token::createOffer(account, nftID, currency), - txflags(tfSellNFToken)); + uint256 const sellOfferIndex = keylet::nftoffer(account, env.seq(account)).key; + env(token::createOffer(account, nftID, currency), txflags(tfSellNFToken)); env.close(); return sellOfferIndex; @@ -2095,9 +1877,7 @@ public: }; using namespace test::jtx; auto const sa = testable_amendments(); - testAll( - sa - featureDeepFreeze - featurePermissionedDEX - - fixEnforceNFTokenTrustlineV2); + testAll(sa - featureDeepFreeze - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2); testAll(sa - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2); testAll(sa - featureDeepFreeze - featurePermissionedDEX); testAll(sa - featurePermissionedDEX); @@ -2107,5 +1887,5 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Freeze, app, ripple); -} // namespace ripple +BEAST_DEFINE_TESTSUITE(Freeze, app, xrpl); +} // namespace xrpl diff --git a/src/test/app/HashRouter_test.cpp b/src/test/app/HashRouter_test.cpp index 44170e152e..03bb28e35a 100644 --- a/src/test/app/HashRouter_test.cpp +++ b/src/test/app/HashRouter_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { class HashRouter_test : public beast::unit_test::suite @@ -368,7 +349,7 @@ class HashRouter_test : public beast::unit_test::suite h.set("hold_time", "alice"); h.set("relay_time", "bob"); auto const setup = setup_HashRouter(cfg); - // The set function ignores values that don't covert, so the + // The set function ignores values that don't convert, so the // defaults are left unchanged BEAST_EXPECT(setup.holdTime == 300s); BEAST_EXPECT(setup.relayTime == 30s); @@ -387,9 +368,7 @@ class HashRouter_test : public beast::unit_test::suite HF f2 = HF::SAVED; HF combined = f1 | f2; - BEAST_EXPECT( - static_cast(combined) == - (static_cast(f1) | static_cast(f2))); + BEAST_EXPECT(static_cast(combined) == (static_cast(f1) | static_cast(f2))); HF temp = f1; temp |= f2; @@ -423,7 +402,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(HashRouter, app, ripple); +BEAST_DEFINE_TESTSUITE(HashRouter, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index 925776a1b4..9d2c1da335 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -39,7 +20,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class Invariants_test : public beast::unit_test::suite @@ -48,18 +29,18 @@ class Invariants_test : public beast::unit_test::suite // on the ledger after creating two accounts, but before closing it, and // before the Precheck function. These should only be valid functions, and // not direct manipulations. Preclose is not commonly used. - using Preclose = std::function; + using Preclose = std::function; // this is common setup/method for running a failing invariant check. The // precheck function is used to manipulate the ApplyContext with view // changes that will cause the check to fail. - using Precheck = std::function; + using Precheck = std::function; + + static FeatureBitset + defaultAmendments() + { + return xrpl::test::jtx::testable_amendments() | featureInvariantsV1_1 | featureSingleAssetVault; + } /** Run a specific test case to put the ledger into a state that will be * detected by an invariant. Simulates the actions of a transaction that @@ -84,15 +65,26 @@ class Invariants_test : public beast::unit_test::suite Precheck const& precheck, XRPAmount fee = XRPAmount{}, STTx tx = STTx{ttACCOUNT_SET, [](STObject&) {}}, - std::initializer_list ters = - {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + std::initializer_list ters = {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + Preclose const& preclose = {}, + TxAccount setTxAccount = TxAccount::None) + { + return doInvariantCheck( + test::jtx::Env(*this, defaultAmendments()), expect_logs, precheck, fee, tx, ters, preclose, setTxAccount); + } + + void + doInvariantCheck( + test::jtx::Env&& env, + std::vector const& expect_logs, + Precheck const& precheck, + XRPAmount fee = XRPAmount{}, + STTx tx = STTx{ttACCOUNT_SET, [](STObject&) {}}, + std::initializer_list ters = {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, Preclose const& preclose = {}, TxAccount setTxAccount = TxAccount::None) { using namespace test::jtx; - FeatureBitset amendments = testable_amendments() | - featureInvariantsV1_1 | featureSingleAssetVault; - Env env{*this, amendments}; Account const A1{"A1"}; Account const A2{"A2"}; @@ -101,20 +93,29 @@ class Invariants_test : public beast::unit_test::suite BEAST_EXPECT(preclose(A1, A2, env)); env.close(); + if (setTxAccount != TxAccount::None) + tx.setAccountID(sfAccount, setTxAccount == TxAccount::A1 ? A1.id() : A2.id()); + + return doInvariantCheck(std::move(env), A1, A2, expect_logs, precheck, fee, tx, ters); + } + + void + doInvariantCheck( + test::jtx::Env&& env, + test::jtx::Account const& A1, + test::jtx::Account const& A2, + std::vector const& expect_logs, + Precheck const& precheck, + XRPAmount fee = XRPAmount{}, + STTx tx = STTx{ttACCOUNT_SET, [](STObject&) {}}, + std::initializer_list ters = {tecINVARIANT_FAILED, tefINVARIANT_FAILED}) + { + using namespace test::jtx; + OpenView ov{*env.current()}; test::StreamSink sink{beast::severities::kWarning}; beast::Journal jlog{sink}; - if (setTxAccount != TxAccount::None) - tx.setAccountID( - sfAccount, setTxAccount == TxAccount::A1 ? A1.id() : A2.id()); - ApplyContext ac{ - env.app(), - ov, - tx, - tesSUCCESS, - env.current()->fees().base, - tapNONE, - jlog}; + ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, tapNONE, jlog}; BEAST_EXPECT(precheck(A1, A2, ac)); @@ -126,20 +127,21 @@ class Invariants_test : public beast::unit_test::suite for (TER const& terExpect : ters) { terActual = ac.checkInvariants(terActual, fee); - BEAST_EXPECT(terExpect == terActual); + BEAST_EXPECTS(terExpect == terActual, std::to_string(TERtoInt(terActual))); auto const messages = sink.messages().str(); - BEAST_EXPECT( - messages.starts_with("Invariant failed:") || - messages.starts_with("Transaction caused an exception")); + + if (terActual != tesSUCCESS) + { + BEAST_EXPECTS( + messages.starts_with("Invariant failed:") || + messages.starts_with("Transaction caused an exception"), + messages); + } + // std::cerr << messages << '\n'; for (auto const& m : expect_logs) { - if (messages.find(m) == std::string::npos) - { - // uncomment if you want to log the invariant failure - // std::cerr << " --> " << m << std::endl; - fail(); - } + BEAST_EXPECTS(messages.find(m) != std::string::npos, m); } } } @@ -150,8 +152,7 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "XRP created"; doInvariantCheck( - {{"XRP net change was positive: 500"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"XRP net change was positive: 500"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // put a single account in the view and "manufacture" some XRP auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) @@ -170,16 +171,18 @@ class Invariants_test : public beast::unit_test::suite testcase << "account root removed"; // An account was deleted, but not by an AccountDelete transaction. - doInvariantCheck( - {{"an account root was deleted"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // remove an account from the view - auto const sle = ac.view().peek(keylet::account(A1.id())); - if (!sle) - return false; - ac.view().erase(sle); - return true; - }); + doInvariantCheck({{"an account root was deleted"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // remove an account from the view + auto sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sle->at(sfBalance) = beast::zero; + ac.view().erase(sle); + return true; + }); // Successful AccountDelete transaction that didn't delete an account. // @@ -188,9 +191,7 @@ class Invariants_test : public beast::unit_test::suite // After a discussion with the team, we believe that's okay. doInvariantCheck( {{"account deletion succeeded without deleting an account"}}, - [](Account const&, Account const&, ApplyContext& ac) { - return true; - }, + [](Account const&, Account const&, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); @@ -200,10 +201,15 @@ class Invariants_test : public beast::unit_test::suite {{"account deletion succeeded but deleted multiple accounts"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { // remove two accounts from the view - auto const sleA1 = ac.view().peek(keylet::account(A1.id())); - auto const sleA2 = ac.view().peek(keylet::account(A2.id())); + auto sleA1 = ac.view().peek(keylet::account(A1.id())); + auto sleA2 = ac.view().peek(keylet::account(A2.id())); if (!sleA1 || !sleA2) return false; + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sleA1->at(sfBalance) = beast::zero; + sleA2->at(sfBalance) = beast::zero; ac.view().erase(sleA1); ac.view().erase(sleA2); return true; @@ -218,6 +224,46 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "account root deletion left artifact"; + doInvariantCheck( + {{"account deletion left behind a non-zero balance"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + // A1 has a balance. Delete A1 + auto const a1 = A1.id(); + auto const sleA1 = ac.view().peek(keylet::account(a1)); + if (!sleA1) + return false; + if (!BEAST_EXPECT(*sleA1->at(sfBalance) != beast::zero)) + return false; + + ac.view().erase(sleA1); + + return true; + }, + XRPAmount{}, + STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}); + + doInvariantCheck( + {{"account deletion left behind a non-zero owner count"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + // Increment A1's owner count, then delete A1 + auto const a1 = A1.id(); + auto const sleA1 = ac.view().peek(keylet::account(a1)); + if (!sleA1) + return false; + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sleA1->at(sfBalance) = beast::zero; + BEAST_EXPECT(sleA1->at(sfOwnerCount) == 0); + adjustOwnerCount(ac.view(), sleA1, 1, ac.journal); + + ac.view().erase(sleA1); + + return true; + }, + XRPAmount{}, + STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}); + for (auto const& keyletInfo : directAccountKeylets) { // TODO: Use structured binding once LLVM 16 is the minimum @@ -232,35 +278,43 @@ class Invariants_test : public beast::unit_test::suite using namespace std::string_literals; doInvariantCheck( - {{"account deletion left behind a "s + type.c_str() + - " object"}}, + {{"account deletion left behind a "s + type.c_str() + " object"}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { // Add an object to the ledger for account A1, then delete // A1 auto const a1 = A1.id(); - auto const sleA1 = ac.view().peek(keylet::account(a1)); + auto sleA1 = ac.view().peek(keylet::account(a1)); if (!sleA1) return false; auto const key = std::invoke(keyletfunc, a1); auto const newSLE = std::make_shared(key); ac.view().insert(newSLE); + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the + // desired check. + sleA1->at(sfBalance) = beast::zero; ac.view().erase(sleA1); return true; }, XRPAmount{}, STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}); - }; + } // NFT special case doInvariantCheck( {{"account deletion left behind a NFTokenPage object"}}, [&](Account const& A1, Account const&, ApplyContext& ac) { // remove an account from the view - auto const sle = ac.view().peek(keylet::account(A1.id())); + auto sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sle->at(sfBalance) = beast::zero; + sle->at(sfOwnerCount) = 0; ac.view().erase(sle); return true; }, @@ -284,13 +338,18 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { // Delete the AMM account without cleaning up the directory or // deleting the AMM object - auto const sle = ac.view().peek(keylet::account(ammAcctID)); + auto sle = ac.view().peek(keylet::account(ammAcctID)); if (!sle) return false; BEAST_EXPECT(sle->at(~sfAMMID)); BEAST_EXPECT(sle->at(~sfAMMID) == ammKey); + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sle->at(sfBalance) = beast::zero; + sle->at(sfOwnerCount) = 0; ac.view().erase(sle); return true; @@ -313,16 +372,14 @@ class Invariants_test : public beast::unit_test::suite // Delete all the AMM's trust lines, remove the AMM from the AMM // account's directory (this deletes the directory), and delete // the AMM account. Do not delete the AMM object. - auto const sle = ac.view().peek(keylet::account(ammAcctID)); + auto sle = ac.view().peek(keylet::account(ammAcctID)); if (!sle) return false; BEAST_EXPECT(sle->at(~sfAMMID)); BEAST_EXPECT(sle->at(~sfAMMID) == ammKey); - for (auto const& trustKeylet : - {keylet::line(ammAcctID, A1["USD"]), - keylet::line(A1, ammIssue)}) + for (auto const& trustKeylet : {keylet::line(ammAcctID, A1["USD"]), keylet::line(A1, ammIssue)}) { if (auto const line = ac.view().peek(trustKeylet); !line) { @@ -333,12 +390,8 @@ class Invariants_test : public beast::unit_test::suite STAmount const lowLimit = line->at(sfLowLimit); STAmount const highLimit = line->at(sfHighLimit); BEAST_EXPECT( - trustDelete( - ac.view(), - line, - lowLimit.getIssuer(), - highLimit.getIssuer(), - ac.journal) == tesSUCCESS); + trustDelete(ac.view(), line, lowLimit.getIssuer(), highLimit.getIssuer(), ac.journal) == + tesSUCCESS); } } @@ -347,12 +400,14 @@ class Invariants_test : public beast::unit_test::suite return false; auto const ownerDirKeylet = keylet::ownerDir(ammAcctID); - BEAST_EXPECT(ac.view().dirRemove( - ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey, false)); - BEAST_EXPECT( - !ac.view().exists(ownerDirKeylet) || - ac.view().emptyDirDelete(ownerDirKeylet)); + BEAST_EXPECT(ac.view().dirRemove(ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey, false)); + BEAST_EXPECT(!ac.view().exists(ownerDirKeylet) || ac.view().emptyDirDelete(ownerDirKeylet)); + // Clear the balance so the "account deletion left behind a + // non-zero balance" check doesn't trip earlier than the desired + // check. + sle->at(sfBalance) = beast::zero; + sle->at(sfOwnerCount) = 0; ac.view().erase(sle); return true; @@ -377,8 +432,7 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "ledger entry types don't match"; doInvariantCheck( - {{"ledger entry type mismatch"}, - {"XRP net change of -1000000000 doesn't match fee 0"}}, + {{"ledger entry type mismatch"}, {"XRP net change of -1000000000 doesn't match fee 0"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // replace an entry in the table with an SLE of a different type auto const sle = ac.view().peek(keylet::account(A1.id())); @@ -390,8 +444,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"invalid ledger entry type added"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"invalid ledger entry type added"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // add an entry in the table with an SLE of an invalid type auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) @@ -400,8 +453,7 @@ class Invariants_test : public beast::unit_test::suite // make a dummy escrow ledger entry, then change the type to an // unsupported value so that the valid type invariant check // will fail. - auto const sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto const sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); // We don't use ltNICKNAME directly since it's marked deprecated // to prevent accidental use elsewhere. @@ -417,11 +469,9 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "trust lines with XRP not allowed"; doInvariantCheck( - {{"an XRP trust line was created"}}, - [](Account const& A1, Account const& A2, ApplyContext& ac) { + {{"an XRP trust line was created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { // create simple trust SLE with xrp currency - auto const sleNew = std::make_shared( - keylet::line(A1, A2, xrpIssue().currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, xrpIssue().currency)); ac.view().insert(sleNew); return true; }); @@ -437,8 +487,7 @@ class Invariants_test : public beast::unit_test::suite {{"a trust line with deep freeze flag without normal freeze was " "created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - auto const sleNew = std::make_shared( - keylet::line(A1, A2, A1["USD"].currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, A1["USD"].currency)); sleNew->setFieldAmount(sfLowLimit, A1["USD"](0)); sleNew->setFieldAmount(sfHighLimit, A1["USD"](0)); @@ -453,8 +502,7 @@ class Invariants_test : public beast::unit_test::suite {{"a trust line with deep freeze flag without normal freeze was " "created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - auto const sleNew = std::make_shared( - keylet::line(A1, A2, A1["USD"].currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, A1["USD"].currency)); sleNew->setFieldAmount(sfLowLimit, A1["USD"](0)); sleNew->setFieldAmount(sfHighLimit, A1["USD"](0)); std::uint32_t uFlags = 0u; @@ -468,8 +516,7 @@ class Invariants_test : public beast::unit_test::suite {{"a trust line with deep freeze flag without normal freeze was " "created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - auto const sleNew = std::make_shared( - keylet::line(A1, A2, A1["USD"].currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, A1["USD"].currency)); sleNew->setFieldAmount(sfLowLimit, A1["USD"](0)); sleNew->setFieldAmount(sfHighLimit, A1["USD"](0)); std::uint32_t uFlags = 0u; @@ -483,8 +530,7 @@ class Invariants_test : public beast::unit_test::suite {{"a trust line with deep freeze flag without normal freeze was " "created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - auto const sleNew = std::make_shared( - keylet::line(A1, A2, A1["USD"].currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, A1["USD"].currency)); sleNew->setFieldAmount(sfLowLimit, A1["USD"](0)); sleNew->setFieldAmount(sfHighLimit, A1["USD"](0)); std::uint32_t uFlags = 0u; @@ -498,8 +544,7 @@ class Invariants_test : public beast::unit_test::suite {{"a trust line with deep freeze flag without normal freeze was " "created"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - auto const sleNew = std::make_shared( - keylet::line(A1, A2, A1["USD"].currency)); + auto const sleNew = std::make_shared(keylet::line(A1, A2, A1["USD"].currency)); sleNew->setFieldAmount(sfLowLimit, A1["USD"](0)); sleNew->setFieldAmount(sfHighLimit, A1["USD"](0)); std::uint32_t uFlags = 0u; @@ -518,55 +563,49 @@ class Invariants_test : public beast::unit_test::suite Account G1{"G1"}; // Helper function to establish the trustlines - auto const createTrustlines = - [&](Account const& A1, Account const& A2, Env& env) { - // Preclose callback to establish trust lines with gateway - env.fund(XRP(1000), G1); + auto const createTrustlines = [&](Account const& A1, Account const& A2, Env& env) { + // Preclose callback to establish trust lines with gateway + env.fund(XRP(1000), G1); - env.trust(G1["USD"](10000), A1); - env.trust(G1["USD"](10000), A2); - env.close(); + env.trust(G1["USD"](10000), A1); + env.trust(G1["USD"](10000), A2); + env.close(); - env(pay(G1, A1, G1["USD"](1000))); - env(pay(G1, A2, G1["USD"](1000))); - env.close(); + env(pay(G1, A1, G1["USD"](1000))); + env(pay(G1, A2, G1["USD"](1000))); + env.close(); - return true; - }; - - auto const A1FrozenByIssuer = - [&](Account const& A1, Account const& A2, Env& env) { - createTrustlines(A1, A2, env); - env(trust(G1, A1["USD"](10000), tfSetFreeze)); - env.close(); - - return true; - }; - - auto const A1DeepFrozenByIssuer = - [&](Account const& A1, Account const& A2, Env& env) { - A1FrozenByIssuer(A1, A2, env); - env(trust(G1, A1["USD"](10000), tfSetDeepFreeze)); - env.close(); - - return true; - }; - - auto const changeBalances = [&](Account const& A1, - Account const& A2, - ApplyContext& ac, - int A1Balance, - int A2Balance) { - auto const sleA1 = ac.view().peek(keylet::line(A1, G1["USD"])); - auto const sleA2 = ac.view().peek(keylet::line(A2, G1["USD"])); - - sleA1->setFieldAmount(sfBalance, G1["USD"](A1Balance)); - sleA2->setFieldAmount(sfBalance, G1["USD"](A2Balance)); - - ac.view().update(sleA1); - ac.view().update(sleA2); + return true; }; + auto const A1FrozenByIssuer = [&](Account const& A1, Account const& A2, Env& env) { + createTrustlines(A1, A2, env); + env(trust(G1, A1["USD"](10000), tfSetFreeze)); + env.close(); + + return true; + }; + + auto const A1DeepFrozenByIssuer = [&](Account const& A1, Account const& A2, Env& env) { + A1FrozenByIssuer(A1, A2, env); + env(trust(G1, A1["USD"](10000), tfSetDeepFreeze)); + env.close(); + + return true; + }; + + auto const changeBalances = + [&](Account const& A1, Account const& A2, ApplyContext& ac, int A1Balance, int A2Balance) { + auto const sleA1 = ac.view().peek(keylet::line(A1, G1["USD"])); + auto const sleA2 = ac.view().peek(keylet::line(A2, G1["USD"])); + + sleA1->setFieldAmount(sfBalance, G1["USD"](A1Balance)); + sleA2->setFieldAmount(sfBalance, G1["USD"](A2Balance)); + + ac.view().update(sleA1); + ac.view().update(sleA2); + }; + // test: imitating frozen A1 making a payment to A2. doInvariantCheck( {{"Attempting to move frozen funds"}}, @@ -624,8 +663,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"incorrect account XRP balance"}, - {"XRP net change was positive: 99999999000000001"}}, + {{"incorrect account XRP balance"}, {"XRP net change was positive: 99999999000000001"}}, [this](Account const& A1, Account const&, ApplyContext& ac) { // balance exceeds genesis amount auto const sle = ac.view().peek(keylet::account(A1.id())); @@ -640,8 +678,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"incorrect account XRP balance"}, - {"XRP net change of -1000000001 doesn't match fee 0"}}, + {{"incorrect account XRP balance"}, {"XRP net change of -1000000001 doesn't match fee 0"}}, [this](Account const& A1, Account const&, ApplyContext& ac) { // balance is negative auto const sle = ac.view().peek(keylet::account(A1.id())); @@ -662,26 +699,21 @@ class Invariants_test : public beast::unit_test::suite testcase << "Transaction fee checks"; doInvariantCheck( - {{"fee paid was negative: -1"}, - {"XRP net change of 0 doesn't match fee -1"}}, + {{"fee paid was negative: -1"}, {"XRP net change of 0 doesn't match fee -1"}}, [](Account const&, Account const&, ApplyContext&) { return true; }, XRPAmount{-1}); doInvariantCheck( {{"fee paid exceeds system limit: "s + to_string(INITIAL_XRP)}, - {"XRP net change of 0 doesn't match fee "s + - to_string(INITIAL_XRP)}}, + {"XRP net change of 0 doesn't match fee "s + to_string(INITIAL_XRP)}}, [](Account const&, Account const&, ApplyContext&) { return true; }, XRPAmount{INITIAL_XRP}); doInvariantCheck( - {{"fee paid is 20 exceeds fee specified in transaction."}, - {"XRP net change of 0 doesn't match fee 20"}}, + {{"fee paid is 20 exceeds fee specified in transaction."}, {"XRP net change of 0 doesn't match fee 20"}}, [](Account const&, Account const&, ApplyContext&) { return true; }, XRPAmount{20}, - STTx{ttACCOUNT_SET, [](STObject& tx) { - tx.setFieldAmount(sfFee, XRPAmount{10}); - }}); + STTx{ttACCOUNT_SET, [](STObject& tx) { tx.setFieldAmount(sfFee, XRPAmount{10}); }}); } void @@ -690,55 +722,46 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "no bad offers"; - doInvariantCheck( - {{"offer with a bad amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // offer with negative takerpays - auto const sle = ac.view().peek(keylet::account(A1.id())); - if (!sle) - return false; - auto sleNew = std::make_shared( - keylet::offer(A1.id(), (*sle)[sfSequence])); - sleNew->setAccountID(sfAccount, A1.id()); - sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); - sleNew->setFieldAmount(sfTakerPays, XRP(-1)); - ac.view().insert(sleNew); - return true; - }); + doInvariantCheck({{"offer with a bad amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // offer with negative takerpays + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared(keylet::offer(A1.id(), (*sle)[sfSequence])); + sleNew->setAccountID(sfAccount, A1.id()); + sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); + sleNew->setFieldAmount(sfTakerPays, XRP(-1)); + ac.view().insert(sleNew); + return true; + }); - doInvariantCheck( - {{"offer with a bad amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // offer with negative takergets - auto const sle = ac.view().peek(keylet::account(A1.id())); - if (!sle) - return false; - auto sleNew = std::make_shared( - keylet::offer(A1.id(), (*sle)[sfSequence])); - sleNew->setAccountID(sfAccount, A1.id()); - sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); - sleNew->setFieldAmount(sfTakerPays, A1["USD"](10)); - sleNew->setFieldAmount(sfTakerGets, XRP(-1)); - ac.view().insert(sleNew); - return true; - }); + doInvariantCheck({{"offer with a bad amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // offer with negative takergets + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared(keylet::offer(A1.id(), (*sle)[sfSequence])); + sleNew->setAccountID(sfAccount, A1.id()); + sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); + sleNew->setFieldAmount(sfTakerPays, A1["USD"](10)); + sleNew->setFieldAmount(sfTakerGets, XRP(-1)); + ac.view().insert(sleNew); + return true; + }); - doInvariantCheck( - {{"offer with a bad amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // offer XRP to XRP - auto const sle = ac.view().peek(keylet::account(A1.id())); - if (!sle) - return false; - auto sleNew = std::make_shared( - keylet::offer(A1.id(), (*sle)[sfSequence])); - sleNew->setAccountID(sfAccount, A1.id()); - sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); - sleNew->setFieldAmount(sfTakerPays, XRP(10)); - sleNew->setFieldAmount(sfTakerGets, XRP(11)); - ac.view().insert(sleNew); - return true; - }); + doInvariantCheck({{"offer with a bad amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // offer XRP to XRP + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared(keylet::offer(A1.id(), (*sle)[sfSequence])); + sleNew->setAccountID(sfAccount, A1.id()); + sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]); + sleNew->setFieldAmount(sfTakerPays, XRP(10)); + sleNew->setFieldAmount(sfTakerGets, XRP(11)); + ac.view().insert(sleNew); + return true; + }); } void @@ -748,30 +771,26 @@ class Invariants_test : public beast::unit_test::suite testcase << "no zero escrow"; doInvariantCheck( - {{"XRP net change of -1000000 doesn't match fee 0"}, - {"escrow specifies invalid amount"}}, + {{"XRP net change of -1000000 doesn't match fee 0"}, {"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // escrow with negative amount auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); sleNew->setFieldAmount(sfAmount, XRP(-1)); ac.view().insert(sleNew); return true; }); doInvariantCheck( - {{"XRP net change was positive: 100000000000000001"}, - {"escrow specifies invalid amount"}}, + {{"XRP net change was positive: 100000000000000001"}, {"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // escrow with too-large amount auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); // Use `drops(1)` to bypass a call to STAmount::canonicalize // with an invalid value sleNew->setFieldAmount(sfAmount, INITIAL_XRP + drops(1)); @@ -781,17 +800,14 @@ class Invariants_test : public beast::unit_test::suite // IOU < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // escrow with too-little iou auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); - Issue const usd{ - Currency(0x5553440000000000), AccountID(0x4985601)}; + Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)}; STAmount amt(usd, -1); sleNew->setFieldAmount(sfAmount, amt); ac.view().insert(sleNew); @@ -800,14 +816,12 @@ class Invariants_test : public beast::unit_test::suite // IOU bad currency doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // escrow with bad iou currency auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); Issue const bad{badCurrency(), AccountID(0x4985601)}; STAmount amt(bad, 1); @@ -818,17 +832,14 @@ class Invariants_test : public beast::unit_test::suite // MPT < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // escrow with too-little mpt auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared( - keylet::escrow(A1, (*sle)[sfSequence] + 2)); + auto sleNew = std::make_shared(keylet::escrow(A1, (*sle)[sfSequence] + 2)); - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; STAmount amt(mpt, -1); sleNew->setFieldAmount(sfAmount, amt); ac.view().insert(sleNew); @@ -837,17 +848,14 @@ class Invariants_test : public beast::unit_test::suite // MPT OutstandingAmount < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // mpissuance outstanding is negative + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // mptissuance outstanding is negative auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - auto sleNew = - std::make_shared(keylet::mptIssuance(mpt.getMptID())); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = std::make_shared(keylet::mptIssuance(mpt.getMptID())); sleNew->setFieldU64(sfOutstandingAmount, -1); ac.view().insert(sleNew); return true; @@ -855,17 +863,14 @@ class Invariants_test : public beast::unit_test::suite // MPT LockedAmount < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // mpissuance locked is less than locked + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // mptissuance locked is less than locked auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - auto sleNew = - std::make_shared(keylet::mptIssuance(mpt.getMptID())); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = std::make_shared(keylet::mptIssuance(mpt.getMptID())); sleNew->setFieldU64(sfLockedAmount, -1); ac.view().insert(sleNew); return true; @@ -873,17 +878,14 @@ class Invariants_test : public beast::unit_test::suite // MPT OutstandingAmount < LockedAmount doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - // mpissuance outstanding is less than locked + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { + // mptissuance outstanding is less than locked auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - auto sleNew = - std::make_shared(keylet::mptIssuance(mpt.getMptID())); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = std::make_shared(keylet::mptIssuance(mpt.getMptID())); sleNew->setFieldU64(sfOutstandingAmount, 1); sleNew->setFieldU64(sfLockedAmount, 10); ac.view().insert(sleNew); @@ -892,17 +894,14 @@ class Invariants_test : public beast::unit_test::suite // MPT MPTAmount < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // mptoken amount is negative auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - auto sleNew = - std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); sleNew->setFieldU64(sfMPTAmount, -1); ac.view().insert(sleNew); return true; @@ -910,17 +909,14 @@ class Invariants_test : public beast::unit_test::suite // MPT LockedAmount < 0 doInvariantCheck( - {{"escrow specifies invalid amount"}}, - [](Account const& A1, Account const&, ApplyContext& ac) { + {{"escrow specifies invalid amount"}}, [](Account const& A1, Account const&, ApplyContext& ac) { // mptoken locked amount is negative auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - MPTIssue const mpt{ - MPTIssue{makeMptID(1, AccountID(0x4985601))}}; - auto sleNew = - std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); + MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); sleNew->setFieldU64(sfLockedAmount, -1); ac.view().insert(sleNew); return true; @@ -933,17 +929,15 @@ class Invariants_test : public beast::unit_test::suite using namespace test::jtx; testcase << "valid new account root"; - doInvariantCheck( - {{"account root created illegally"}}, - [](Account const&, Account const&, ApplyContext& ac) { - // Insert a new account root created by a non-payment into - // the view. - Account const A3{"A3"}; - Keylet const acctKeylet = keylet::account(A3); - auto const sleNew = std::make_shared(acctKeylet); - ac.view().insert(sleNew); - return true; - }); + doInvariantCheck({{"account root created illegally"}}, [](Account const&, Account const&, ApplyContext& ac) { + // Insert a new account root created by a non-payment into + // the view. + Account const A3{"A3"}; + Keylet const acctKeylet = keylet::account(A3); + auto const sleNew = std::make_shared(acctKeylet); + ac.view().insert(sleNew); + return true; + }); doInvariantCheck( {{"multiple accounts created in a single transaction"}}, @@ -986,9 +980,7 @@ class Invariants_test : public beast::unit_test::suite auto const sleNew = std::make_shared(acctKeylet); sleNew->setFieldU32(sfSequence, 0); sleNew->setFieldH256(sfAMMID, uint256(1)); - sleNew->setFieldU32( - sfFlags, - lsfDisableMaster | lsfDefaultRipple | lsfDefaultRipple); + sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDefaultRipple); ac.view().insert(sleNew); return true; }, @@ -1003,9 +995,7 @@ class Invariants_test : public beast::unit_test::suite auto const sleNew = std::make_shared(acctKeylet); sleNew->setFieldU32(sfSequence, ac.view().seq()); sleNew->setFieldH256(sfAMMID, uint256(1)); - sleNew->setFieldU32( - sfFlags, - lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); + sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); ac.view().insert(sleNew); return true; }, @@ -1020,8 +1010,7 @@ class Invariants_test : public beast::unit_test::suite auto const sleNew = std::make_shared(acctKeylet); sleNew->setFieldU32(sfSequence, 0); sleNew->setFieldH256(sfAMMID, uint256(1)); - sleNew->setFieldU32( - sfFlags, lsfDisableMaster | lsfDefaultRipple); + sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple); ac.view().insert(sleNew); return true; }, @@ -1036,10 +1025,7 @@ class Invariants_test : public beast::unit_test::suite auto const sleNew = std::make_shared(acctKeylet); sleNew->setFieldU32(sfSequence, 0); sleNew->setFieldH256(sfAMMID, uint256(1)); - sleNew->setFieldU32( - sfFlags, - lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth | - lsfRequireDestTag); + sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth | lsfRequireDestTag); ac.view().insert(sleNew); return true; }, @@ -1054,21 +1040,17 @@ class Invariants_test : public beast::unit_test::suite testcase << "NFTokenPage"; // lambda that returns an STArray of NFTokenIDs. - uint256 const firstNFTID( - "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000"); + uint256 const firstNFTID("0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000"); auto makeNFTokenIDs = [&firstNFTID](unsigned int nftCount) { - SOTemplate const* nfTokenTemplate = - InnerObjectFormats::getInstance().findSOTemplateBySField( - sfNFToken); + SOTemplate const* nfTokenTemplate = InnerObjectFormats::getInstance().findSOTemplateBySField(sfNFToken); uint256 nftID(firstNFTID); STArray ret; for (int i = 0; i < nftCount; ++i) { - STObject newNFToken( - *nfTokenTemplate, sfNFToken, [&nftID](STObject& object) { - object.setFieldH256(sfNFTokenID, nftID); - }); + STObject newNFToken(*nfTokenTemplate, sfNFToken, [&nftID](STObject& object) { + object.setFieldH256(sfNFTokenID, nftID); + }); ret.push_back(std::move(newNFToken)); ++nftID; } @@ -1076,9 +1058,7 @@ class Invariants_test : public beast::unit_test::suite }; doInvariantCheck( - {{"NFT page has invalid size"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + {{"NFT page has invalid size"}}, [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { auto nftPage = std::make_shared(keylet::nftpage_max(A1)); nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0)); @@ -1087,9 +1067,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"NFT page has invalid size"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + {{"NFT page has invalid size"}}, [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { auto nftPage = std::make_shared(keylet::nftpage_max(A1)); nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33)); @@ -1098,9 +1076,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"NFTs on page are not sorted"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + {{"NFTs on page are not sorted"}}, [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { STArray nfTokens = makeNFTokenIDs(2); std::iter_swap(nfTokens.begin(), nfTokens.begin() + 1); @@ -1112,9 +1088,7 @@ class Invariants_test : public beast::unit_test::suite }); doInvariantCheck( - {{"NFT contains empty URI"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + {{"NFT contains empty URI"}}, [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { STArray nfTokens = makeNFTokenIDs(1); nfTokens[0].setFieldVL(sfURI, Blob{}); @@ -1127,12 +1101,10 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {{"NFT page is improperly linked"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { auto nftPage = std::make_shared(keylet::nftpage_max(A1)); nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); - nftPage->setFieldH256( - sfPreviousPageMin, keylet::nftpage_max(A1).key); + nftPage->setFieldH256(sfPreviousPageMin, keylet::nftpage_max(A1).key); ac.view().insert(nftPage); return true; @@ -1140,12 +1112,10 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {{"NFT page is improperly linked"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const& A2, ApplyContext& ac) { + [&makeNFTokenIDs](Account const& A1, Account const& A2, ApplyContext& ac) { auto nftPage = std::make_shared(keylet::nftpage_max(A1)); nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); - nftPage->setFieldH256( - sfPreviousPageMin, keylet::nftpage_min(A2).key); + nftPage->setFieldH256(sfPreviousPageMin, keylet::nftpage_min(A2).key); ac.view().insert(nftPage); return true; @@ -1153,8 +1123,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {{"NFT page is improperly linked"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { auto nftPage = std::make_shared(keylet::nftpage_max(A1)); nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); nftPage->setFieldH256(sfNextPageMin, nftPage->key()); @@ -1165,28 +1134,22 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {{"NFT page is improperly linked"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const& A2, ApplyContext& ac) { + [&makeNFTokenIDs](Account const& A1, Account const& A2, ApplyContext& ac) { STArray nfTokens = makeNFTokenIDs(1); - auto nftPage = std::make_shared(keylet::nftpage( - keylet::nftpage_max(A1), - ++(nfTokens[0].getFieldH256(sfNFTokenID)))); + auto nftPage = std::make_shared( + keylet::nftpage(keylet::nftpage_max(A1), ++(nfTokens[0].getFieldH256(sfNFTokenID)))); nftPage->setFieldArray(sfNFTokens, std::move(nfTokens)); - nftPage->setFieldH256( - sfNextPageMin, keylet::nftpage_max(A2).key); + nftPage->setFieldH256(sfNextPageMin, keylet::nftpage_max(A2).key); ac.view().insert(nftPage); return true; }); doInvariantCheck( - {{"NFT found in incorrect page"}}, - [&makeNFTokenIDs]( - Account const& A1, Account const&, ApplyContext& ac) { + {{"NFT found in incorrect page"}}, [&makeNFTokenIDs](Account const& A1, Account const&, ApplyContext& ac) { STArray nfTokens = makeNFTokenIDs(2); - auto nftPage = std::make_shared(keylet::nftpage( - keylet::nftpage_max(A1), - (nfTokens[1].getFieldH256(sfNFTokenID)))); + auto nftPage = std::make_shared( + keylet::nftpage(keylet::nftpage_max(A1), (nfTokens[1].getFieldH256(sfNFTokenID)))); nftPage->setFieldArray(sfNFTokens, std::move(nfTokens)); ac.view().insert(nftPage); @@ -1194,120 +1157,104 @@ class Invariants_test : public beast::unit_test::suite }); } - void + static std::shared_ptr createPermissionedDomain( ApplyContext& ac, - std::shared_ptr& sle, test::jtx::Account const& A1, - test::jtx::Account const& A2) + test::jtx::Account const& A2, + std::uint32_t numCreds = 2, + std::uint32_t seq = 10) { - sle->setAccountID(sfOwner, A1); - sle->setFieldU32(sfSequence, 10); + Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), seq); + auto sle = std::make_shared(pdKeylet); - STArray credentials(sfAcceptedCredentials, 2); - for (std::size_t n = 0; n < 2; ++n) + sle->setAccountID(sfOwner, A1); + sle->setFieldU32(sfSequence, seq); + + if (numCreds) { - auto cred = STObject::makeInnerObject(sfCredential); - cred.setAccountID(sfIssuer, A2); - auto credType = "cred_type" + std::to_string(n); - cred.setFieldVL( - sfCredentialType, Slice(credType.c_str(), credType.size())); - credentials.push_back(std::move(cred)); + // This array is sorted naturally, but if you willing to change this + // behavior don't forget to use credentials::makeSorted + STArray credentials(sfAcceptedCredentials, numCreds); + for (std::size_t n = 0; n < numCreds; ++n) + { + auto cred = STObject::makeInnerObject(sfCredential); + cred.setAccountID(sfIssuer, A2); + auto credType = "cred_type" + std::to_string(n); + cred.setFieldVL(sfCredentialType, Slice(credType.c_str(), credType.size())); + credentials.push_back(std::move(cred)); + } + sle->setFieldArray(sfAcceptedCredentials, credentials); } - sle->setFieldArray(sfAcceptedCredentials, credentials); + ac.view().insert(sle); + return sle; }; void - testPermissionedDomainInvariants() + testPermissionedDomainInvariants(FeatureBitset features) { using namespace test::jtx; - testcase << "PermissionedDomain"; - doInvariantCheck( - {{"permissioned domain with no rules."}}, - [](Account const& A1, Account const&, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - slePd->setAccountID(sfOwner, A1); - slePd->setFieldU32(sfSequence, 10); + bool const fixPDEnabled = features[fixPermissionedDomainInvariant]; + std::initializer_list badTers = {tecINVARIANT_FAILED, tecINVARIANT_FAILED}; + std::initializer_list failTers = {tecINVARIANT_FAILED, tefINVARIANT_FAILED}; - ac.view().insert(slePd); - return true; + testcase << "PermissionedDomain" + std::string(fixPDEnabled ? " fix" : ""); + + doInvariantCheck( + Env(*this, features), + {{"permissioned domain with no rules."}}, + [](Account const& A1, Account const& A2, ApplyContext& ac) { + return createPermissionedDomain(ac, A1, A2, 0).get(); }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain 2"; auto constexpr tooBig = maxPermissionedDomainCredentialsArraySize + 1; doInvariantCheck( - {{"permissioned domain bad credentials size " + - std::to_string(tooBig)}}, + Env(*this, features), + {{"permissioned domain bad credentials size " + std::to_string(tooBig)}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - slePd->setAccountID(sfOwner, A1); - slePd->setFieldU32(sfSequence, 10); - - STArray credentials(sfAcceptedCredentials, tooBig); - for (std::size_t n = 0; n < tooBig; ++n) - { - auto cred = STObject::makeInnerObject(sfCredential); - cred.setAccountID(sfIssuer, A2); - auto credType = - std::string("cred_type") + std::to_string(n); - cred.setFieldVL( - sfCredentialType, - Slice(credType.c_str(), credType.size())); - credentials.push_back(std::move(cred)); - } - slePd->setFieldArray(sfAcceptedCredentials, credentials); - ac.view().insert(slePd); - return true; + return !!createPermissionedDomain(ac, A1, A2, tooBig); }, XRPAmount{}, STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain 3"; doInvariantCheck( + Env(*this, features), {{"permissioned domain credentials aren't sorted"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - slePd->setAccountID(sfOwner, A1); - slePd->setFieldU32(sfSequence, 10); + auto slePd = createPermissionedDomain(ac, A1, A2, 0); STArray credentials(sfAcceptedCredentials, 2); for (std::size_t n = 0; n < 2; ++n) { auto cred = STObject::makeInnerObject(sfCredential); cred.setAccountID(sfIssuer, A2); - auto credType = - std::string("cred_type") + std::to_string(9 - n); - cred.setFieldVL( - sfCredentialType, - Slice(credType.c_str(), credType.size())); + auto credType = std::string("cred_type") + std::to_string(9 - n); + cred.setFieldVL(sfCredentialType, Slice(credType.c_str(), credType.size())); credentials.push_back(std::move(cred)); } slePd->setFieldArray(sfAcceptedCredentials, credentials); - ac.view().insert(slePd); + ac.view().update(slePd); return true; }, XRPAmount{}, STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain 4"; doInvariantCheck( + Env(*this, features), {{"permissioned domain credentials aren't unique"}}, [](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - slePd->setAccountID(sfOwner, A1); - slePd->setFieldU32(sfSequence, 10); + auto slePd = createPermissionedDomain(ac, A1, A2, 0); STArray credentials(sfAcceptedCredentials, 2); for (std::size_t n = 0; n < 2; ++n) @@ -1318,22 +1265,20 @@ class Invariants_test : public beast::unit_test::suite credentials.push_back(std::move(cred)); } slePd->setFieldArray(sfAcceptedCredentials, credentials); - ac.view().insert(slePd); + ac.view().update(slePd); return true; }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain Set 1"; doInvariantCheck( + Env(*this, features), {{"permissioned domain with no rules."}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - // create PD - createPermissionedDomain(ac, slePd, A1, A2); + auto slePd = createPermissionedDomain(ac, A1, A2); // update PD with empty rules { @@ -1345,19 +1290,16 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain Set 2"; doInvariantCheck( - {{"permissioned domain bad credentials size " + - std::to_string(tooBig)}}, + Env(*this, features), + {{"permissioned domain bad credentials size " + std::to_string(tooBig)}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - // create PD - createPermissionedDomain(ac, slePd, A1, A2); + auto slePd = createPermissionedDomain(ac, A1, A2); // update PD { @@ -1368,9 +1310,7 @@ class Invariants_test : public beast::unit_test::suite auto cred = STObject::makeInnerObject(sfCredential); cred.setAccountID(sfIssuer, A2); auto credType = "cred_type2" + std::to_string(n); - cred.setFieldVL( - sfCredentialType, - Slice(credType.c_str(), credType.size())); + cred.setFieldVL(sfCredentialType, Slice(credType.c_str(), credType.size())); credentials.push_back(std::move(cred)); } @@ -1381,18 +1321,16 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain Set 3"; doInvariantCheck( + Env(*this, features), {{"permissioned domain credentials aren't sorted"}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - // create PD - createPermissionedDomain(ac, slePd, A1, A2); + auto slePd = createPermissionedDomain(ac, A1, A2); // update PD { @@ -1401,11 +1339,8 @@ class Invariants_test : public beast::unit_test::suite { auto cred = STObject::makeInnerObject(sfCredential); cred.setAccountID(sfIssuer, A2); - auto credType = - std::string("cred_type2") + std::to_string(9 - n); - cred.setFieldVL( - sfCredentialType, - Slice(credType.c_str(), credType.size())); + auto credType = std::string("cred_type2") + std::to_string(9 - n); + cred.setFieldVL(sfCredentialType, Slice(credType.c_str(), credType.size())); credentials.push_back(std::move(cred)); } @@ -1416,18 +1351,16 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); testcase << "PermissionedDomain Set 4"; doInvariantCheck( + Env(*this, features), {{"permissioned domain credentials aren't unique"}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - // create PD - createPermissionedDomain(ac, slePd, A1, A2); + auto slePd = createPermissionedDomain(ac, A1, A2); // update PD { @@ -1436,8 +1369,7 @@ class Invariants_test : public beast::unit_test::suite { auto cred = STObject::makeInnerObject(sfCredential); cred.setAccountID(sfIssuer, A2); - cred.setFieldVL( - sfCredentialType, Slice("cred_type", 9)); + cred.setFieldVL(sfCredentialType, Slice("cred_type", 9)); credentials.push_back(std::move(cred)); } slePd->setFieldArray(sfAcceptedCredentials, credentials); @@ -1447,8 +1379,155 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : badTers); + + std::initializer_list goodTers = {tesSUCCESS, tesSUCCESS}; + + std::vector badMoreThan1{{"transaction affected more than 1 permissioned domain entry."}}; + std::vector emptyV; + std::vector badNoDomains{{"no domain objects affected by"}}; + std::vector badNotDeleted{{"domain object modified, but not deleted by "}}; + std::vector badDeleted{{"domain object deleted by"}}; + std::vector badTx{{"domain object(s) affected by an unauthorized transaction."}}; + + { + testcase << "PermissionedDomain set 2 domains "; + doInvariantCheck( + Env(*this, features), + fixPDEnabled ? badMoreThan1 : emptyV, + [](Account const& A1, Account const& A2, ApplyContext& ac) { + createPermissionedDomain(ac, A1, A2); + createPermissionedDomain(ac, A1, A2, 2, 11); + return true; + }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : goodTers); + } + + { + testcase << "PermissionedDomain del 2 domains"; + + Env env1(*this, features); + + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); + + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + [[maybe_unused]] auto [seq2, pd2] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + std::move(env1), + A1, + A2, + fixPDEnabled ? badMoreThan1 : emptyV, + [&pd1, &pd2](Account const&, Account const&, ApplyContext& ac) { + auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1}); + auto sle2 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd2}); + ac.view().erase(sle1); + ac.view().erase(sle2); + return true; + }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_DELETE, [](STObject&) {}}, + fixPDEnabled ? failTers : goodTers); + } + + { + testcase << "PermissionedDomain set 0 domains "; + doInvariantCheck( + Env(*this, features), + fixPDEnabled ? badNoDomains : emptyV, + [](Account const&, Account const&, ApplyContext&) { return true; }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? badTers : goodTers); + } + + { + testcase << "PermissionedDomain del 0 domains"; + + Env env1(*this, features); + + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); + + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + [[maybe_unused]] auto [seq2, pd2] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + Env(*this, features), + A1, + A2, + fixPDEnabled ? badNoDomains : emptyV, + [](Account const&, Account const&, ApplyContext&) { return true; }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_DELETE, [](STObject&) {}}, + fixPDEnabled ? badTers : goodTers); + } + + { + testcase << "PermissionedDomain set, delete domain"; + + Env env1(*this, features); + + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); + + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + std::move(env1), + A1, + A2, + fixPDEnabled ? badDeleted : emptyV, + [&pd1](Account const&, Account const&, ApplyContext& ac) { + auto sle1 = ac.view().peek({ltPERMISSIONED_DOMAIN, pd1}); + ac.view().erase(sle1); + return true; + }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_SET, [](STObject&) {}}, + fixPDEnabled ? failTers : goodTers); + } + + { + testcase << "PermissionedDomain del, create domain "; + doInvariantCheck( + Env(*this, features), + fixPDEnabled ? badNotDeleted : emptyV, + [](Account const& A1, Account const& A2, ApplyContext& ac) { + createPermissionedDomain(ac, A1, A2); + return true; + }, + XRPAmount{}, + STTx{ttPERMISSIONED_DOMAIN_DELETE, [](STObject&) {}}, + fixPDEnabled ? failTers : goodTers); + } + + { + testcase << "PermissionedDomain invalid tx"; + + doInvariantCheck( + fixPDEnabled ? badTx : emptyV, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + createPermissionedDomain(ac, A1, A2); + return true; + }, + XRPAmount{}, + STTx{ttPAYMENT, [](STObject&) {}}, + failTers); + } } void @@ -1459,23 +1538,21 @@ class Invariants_test : public beast::unit_test::suite using namespace jtx; AccountID pseudoAccountID; - Preclose createPseudo = - [&, this](Account const& a, Account const& b, Env& env) { - PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + Preclose createPseudo = [&, this](Account const& a, Account const& b, Env& env) { + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; - // Create vault - Vault vault{env}; - auto [tx, vKeylet] = - vault.create({.owner = a, .asset = xrpAsset}); - env(tx); - env.close(); - if (auto const vSle = env.le(vKeylet); BEAST_EXPECT(vSle)) - { - pseudoAccountID = vSle->at(sfAccount); - } + // Create vault + Vault vault{env}; + auto [tx, vKeylet] = vault.create({.owner = a, .asset = xrpAsset}); + env(tx); + env.close(); + if (auto const vSle = env.le(vKeylet); BEAST_EXPECT(vSle)) + { + pseudoAccountID = vSle->at(sfAccount); + } - return BEAST_EXPECT(env.le(keylet::account(pseudoAccountID))); - }; + return BEAST_EXPECT(env.le(keylet::account(pseudoAccountID))); + }; /* Cases to check "pseudo-account has 0 pseudo-account fields set" @@ -1507,9 +1584,7 @@ class Invariants_test : public beast::unit_test::suite }, { "pseudo-account has a regular key", - [](SLE::pointer& sle) { - sle->at(sfRegularKey) = Account("regular").id(); - }, + [](SLE::pointer& sle) { sle->at(sfRegularKey) = Account("regular").id(); }, }, }); @@ -1572,13 +1647,43 @@ class Invariants_test : public beast::unit_test::suite }); } - void - testPermissionedDEX() + static std::pair + createPermissionedDomainEnv( + test::jtx::Env& env, + test::jtx::Account const& A1, + test::jtx::Account const& A2, + std::uint32_t numCreds = 2) { using namespace test::jtx; - testcase << "PermissionedDEX"; + + pdomain::Credentials credentials; + + for (std::size_t n = 0; n < numCreds; ++n) + { + auto credType = "cred_type" + std::to_string(n); + credentials.push_back({A2, credType}); + } + + std::uint32_t const seq = env.seq(A1); + env(pdomain::setTx(A1, credentials)); + uint256 key = pdomain::getNewDomain(env.meta()); + + // std::cout << "PD, acc: " << A1.id() << ", seq: " << seq << ", k: " << + // key << std::endl; + return {seq, key}; + } + + void + testPermissionedDEX(FeatureBitset features) + { + using namespace test::jtx; + + bool const fixPDEnabled = features[fixPermissionedDomainInvariant]; + + testcase << "PermissionedDEX" + std::string(fixPDEnabled ? " fix" : ""); doInvariantCheck( + Env(*this, features), {{"domain doesn't exist"}}, [](Account const& A1, Account const&, ApplyContext& ac) { Keylet const offerKey = keylet::offer(A1.id(), 10); @@ -1595,9 +1700,8 @@ class Invariants_test : public beast::unit_test::suite [](STObject& tx) { tx.setFieldH256( sfDomainID, - uint256{ - "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E33" - "70F3649CE134E5"}); + uint256{"F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E33" + "70F3649CE134E5"}); Account const A1{"A1"}; tx.setFieldAmount(sfTakerPays, A1["USD"](10)); tx.setFieldAmount(sfTakerGets, XRP(1)); @@ -1606,12 +1710,9 @@ class Invariants_test : public beast::unit_test::suite // missing domain ID in offer object doInvariantCheck( + Env(*this, features), {{"hybrid offer is malformed"}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - createPermissionedDomain(ac, slePd, A1, A2); - Keylet const offerKey = keylet::offer(A2.id(), 10); auto sleOffer = std::make_shared(offerKey); sleOffer->setAccountID(sfAccount, A2); @@ -1626,119 +1727,466 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ttOFFER_CREATE, [&](STObject& tx) {}}, + STTx{ttOFFER_CREATE, [&](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); // more than one entry in sfAdditionalBooks - doInvariantCheck( - {{"hybrid offer is malformed"}}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - createPermissionedDomain(ac, slePd, A1, A2); + { + Env env1(*this, features); - Keylet const offerKey = keylet::offer(A2.id(), 10); - auto sleOffer = std::make_shared(offerKey); - sleOffer->setAccountID(sfAccount, A2); - sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); - sleOffer->setFieldAmount(sfTakerGets, XRP(1)); - sleOffer->setFlag(lsfHybrid); - sleOffer->setFieldH256(sfDomainID, pdKeylet.key); + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); - STArray bookArr; - bookArr.push_back(STObject::makeInnerObject(sfBook)); - bookArr.push_back(STObject::makeInnerObject(sfBook)); - sleOffer->setFieldArray(sfAdditionalBooks, bookArr); - ac.view().insert(sleOffer); - return true; - }, - XRPAmount{}, - STTx{ttOFFER_CREATE, [&](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + std::move(env1), + A1, + A2, + {{"hybrid offer is malformed"}}, + [&pd1](Account const& A1, Account const& A2, ApplyContext& ac) { + Keylet const offerKey = keylet::offer(A2.id(), 10); + auto sleOffer = std::make_shared(offerKey); + sleOffer->setAccountID(sfAccount, A2); + sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); + sleOffer->setFieldAmount(sfTakerGets, XRP(1)); + sleOffer->setFlag(lsfHybrid); + sleOffer->setFieldH256(sfDomainID, pd1); + + STArray bookArr; + bookArr.push_back(STObject::makeInnerObject(sfBook)); + bookArr.push_back(STObject::makeInnerObject(sfBook)); + sleOffer->setFieldArray(sfAdditionalBooks, bookArr); + ac.view().insert(sleOffer); + return true; + }, + XRPAmount{}, + STTx{ttOFFER_CREATE, [&](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + } // hybrid offer missing sfAdditionalBooks - doInvariantCheck( - {{"hybrid offer is malformed"}}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - createPermissionedDomain(ac, slePd, A1, A2); + { + Env env1(*this, features); - Keylet const offerKey = keylet::offer(A2.id(), 10); - auto sleOffer = std::make_shared(offerKey); - sleOffer->setAccountID(sfAccount, A2); - sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); - sleOffer->setFieldAmount(sfTakerGets, XRP(1)); - sleOffer->setFlag(lsfHybrid); - sleOffer->setFieldH256(sfDomainID, pdKeylet.key); - ac.view().insert(sleOffer); - return true; - }, - XRPAmount{}, - STTx{ttOFFER_CREATE, [&](STObject& tx) {}}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); - doInvariantCheck( - {{"transaction consumed wrong domains"}}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - createPermissionedDomain(ac, slePd, A1, A2); + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); - Keylet const badDomainKeylet = - keylet::permissionedDomain(A1.id(), 20); - auto sleBadPd = std::make_shared(badDomainKeylet); - createPermissionedDomain(ac, sleBadPd, A1, A2); + doInvariantCheck( + std::move(env1), + A1, + A2, + {{"hybrid offer is malformed"}}, + [&pd1](Account const& A1, Account const& A2, ApplyContext& ac) { + Keylet const offerKey = keylet::offer(A2.id(), 10); + auto sleOffer = std::make_shared(offerKey); + sleOffer->setAccountID(sfAccount, A2); + sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); + sleOffer->setFieldAmount(sfTakerGets, XRP(1)); + sleOffer->setFlag(lsfHybrid); + sleOffer->setFieldH256(sfDomainID, pd1); + ac.view().insert(sleOffer); + return true; + }, + XRPAmount{}, + STTx{ttOFFER_CREATE, [&](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + } - Keylet const offerKey = keylet::offer(A2.id(), 10); - auto sleOffer = std::make_shared(offerKey); - sleOffer->setAccountID(sfAccount, A2); - sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); - sleOffer->setFieldAmount(sfTakerGets, XRP(1)); - sleOffer->setFieldH256(sfDomainID, pdKeylet.key); - ac.view().insert(sleOffer); - return true; - }, - XRPAmount{}, - STTx{ - ttOFFER_CREATE, - [&](STObject& tx) { - Account const A1{"A1"}; - Keylet const badDomainKey = - keylet::permissionedDomain(A1.id(), 20); - tx.setFieldH256(sfDomainID, badDomainKey.key); - tx.setFieldAmount(sfTakerPays, A1["USD"](10)); - tx.setFieldAmount(sfTakerGets, XRP(1)); - }}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + { + Env env1(*this, features); - doInvariantCheck( - {{"domain transaction affected regular offers"}}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - Keylet const pdKeylet = keylet::permissionedDomain(A1.id(), 10); - auto slePd = std::make_shared(pdKeylet); - createPermissionedDomain(ac, slePd, A1, A2); + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); - Keylet const offerKey = keylet::offer(A2.id(), 10); - auto sleOffer = std::make_shared(offerKey); - sleOffer->setAccountID(sfAccount, A2); - sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); - sleOffer->setFieldAmount(sfTakerGets, XRP(1)); - ac.view().insert(sleOffer); - return true; - }, - XRPAmount{}, - STTx{ - ttOFFER_CREATE, - [&](STObject& tx) { - Account const A1{"A1"}; - Keylet const domainKey = - keylet::permissionedDomain(A1.id(), 10); - tx.setFieldH256(sfDomainID, domainKey.key); - tx.setFieldAmount(sfTakerPays, A1["USD"](10)); - tx.setFieldAmount(sfTakerGets, XRP(1)); - }}, - {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + [[maybe_unused]] auto [seq2, pd2] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + std::move(env1), + A1, + A2, + {{"transaction consumed wrong domains"}}, + [&pd1](Account const& A1, Account const& A2, ApplyContext& ac) { + Keylet const offerKey = keylet::offer(A2.id(), 10); + auto sleOffer = std::make_shared(offerKey); + sleOffer->setAccountID(sfAccount, A2); + sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); + sleOffer->setFieldAmount(sfTakerGets, XRP(1)); + sleOffer->setFieldH256(sfDomainID, pd1); + ac.view().insert(sleOffer); + return true; + }, + XRPAmount{}, + STTx{ + ttOFFER_CREATE, + [&pd2, &A1](STObject& tx) { + tx.setFieldH256(sfDomainID, pd2); + tx.setFieldAmount(sfTakerPays, A1["USD"](10)); + tx.setFieldAmount(sfTakerGets, XRP(1)); + }}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + } + + { + Env env1(*this, features); + + Account const A1{"A1"}; + Account const A2{"A2"}; + env1.fund(XRP(1000), A1, A2); + env1.close(); + + [[maybe_unused]] auto [seq1, pd1] = createPermissionedDomainEnv(env1, A1, A2); + env1.close(); + + doInvariantCheck( + std::move(env1), + A1, + A2, + {{"domain transaction affected regular offers"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + Keylet const offerKey = keylet::offer(A2.id(), 10); + auto sleOffer = std::make_shared(offerKey); + sleOffer->setAccountID(sfAccount, A2); + sleOffer->setFieldAmount(sfTakerPays, A1["USD"](10)); + sleOffer->setFieldAmount(sfTakerGets, XRP(1)); + ac.view().insert(sleOffer); + return true; + }, + XRPAmount{}, + STTx{ + ttOFFER_CREATE, + [&](STObject& tx) { + Account const A1{"A1"}; + tx.setFieldH256(sfDomainID, pd1); + tx.setFieldAmount(sfTakerPays, A1["USD"](10)); + tx.setFieldAmount(sfTakerGets, XRP(1)); + }}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}); + } + } + + Keylet + createLoanBroker(jtx::Account const& a, jtx::Env& env, jtx::PrettyAsset const& asset) + { + using namespace jtx; + + // Create vault + uint256 vaultID; + Vault vault{env}; + auto [tx, vKeylet] = vault.create({.owner = a, .asset = asset}); + env(tx); + BEAST_EXPECT(env.le(vKeylet)); + + vaultID = vKeylet.key; + + // Create Loan Broker + using namespace loanBroker; + + auto const loanBrokerKeylet = keylet::loanbroker(a.id(), env.seq(a)); + // Create a Loan Broker with all default values. + env(set(a, vaultID), fee(increment)); + + return loanBrokerKeylet; + }; + + void + testNoModifiedUnmodifiableFields() + { + testcase("no modified unmodifiable fields"); + using namespace jtx; + + // Initialize with a placeholder value because there's no default ctor + Keylet loanBrokerKeylet = keylet::amendments(); + Preclose createLoanBroker = [&, this](Account const& a, Account const& b, Env& env) { + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + + loanBrokerKeylet = this->createLoanBroker(a, env, xrpAsset); + return BEAST_EXPECT(env.le(loanBrokerKeylet)); + }; + + { + auto const mods = std::to_array>({ + [](SLE::pointer& sle) { sle->at(sfSequence) += 1; }, + [](SLE::pointer& sle) { sle->at(sfOwnerNode) += 1; }, + [](SLE::pointer& sle) { sle->at(sfVaultNode) += 1; }, + [](SLE::pointer& sle) { sle->at(sfVaultID) = uint256(1u); }, + [](SLE::pointer& sle) { sle->at(sfAccount) = sle->at(sfOwner); }, + [](SLE::pointer& sle) { sle->at(sfOwner) = sle->at(sfAccount); }, + [](SLE::pointer& sle) { sle->at(sfManagementFeeRate) += 1; }, + [](SLE::pointer& sle) { sle->at(sfCoverRateMinimum) += 1; }, + [](SLE::pointer& sle) { sle->at(sfCoverRateLiquidation) += 1; }, + [](SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; }, + [](SLE::pointer& sle) { sle->at(sfLedgerIndex) = sle->at(sfVaultID).value(); }, + }); + + for (auto const& mod : mods) + { + doInvariantCheck( + {{"changed an unchangeable field"}}, + [&](Account const& A1, Account const&, ApplyContext& ac) { + auto sle = ac.view().peek(loanBrokerKeylet); + if (!sle) + return false; + mod(sle); + ac.view().update(sle); + return true; + }, + XRPAmount{}, + STTx{ttACCOUNT_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + } + } + + // TODO: Loan Object + + { + auto const mods = std::to_array>({ + [](SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; }, + [](SLE::pointer& sle) { sle->at(sfLedgerIndex) = uint256(1u); }, + }); + + for (auto const& mod : mods) + { + doInvariantCheck( + {{"changed an unchangeable field"}}, [&](Account const& A1, Account const&, ApplyContext& ac) { + auto sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + mod(sle); + ac.view().update(sle); + return true; + }); + } + } + } + + void + testValidLoanBroker() + { + testcase << "valid loan broker"; + + using namespace jtx; + + enum class Asset { XRP, IOU, MPT }; + auto const assetTypes = std::to_array({Asset::XRP, Asset::IOU, Asset::MPT}); + + for (auto const assetType : assetTypes) + { + // Initialize with a placeholder value because there's no default + // ctor + Keylet loanBrokerKeylet = keylet::amendments(); + Preclose createLoanBroker = [&, this](Account const& alice, Account const& issuer, Env& env) { + PrettyAsset const asset = [&]() { + switch (assetType) + { + case Asset::IOU: { + PrettyAsset const iouAsset = issuer["IOU"]; + env(trust(alice, iouAsset(1000))); + env(pay(issuer, alice, iouAsset(1000))); + env.close(); + return iouAsset; + } + + case Asset::MPT: { + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + PrettyAsset const mptAsset = mptt.issuanceID(); + mptt.authorize({.account = alice}); + env(pay(issuer, alice, mptAsset(1000))); + env.close(); + return mptAsset; + } + + case Asset::XRP: + default: + return PrettyAsset{xrpIssue(), 1'000'000}; + } + }(); + loanBrokerKeylet = this->createLoanBroker(alice, env, asset); + return BEAST_EXPECT(env.le(loanBrokerKeylet)); + }; + + // Ensure the test scenarios are set up completely. The test cases + // will need to recompute any of these values it needs for itself + // rather than trying to return a bunch of items + auto setupTest = [&, this](Account const& A1, Account const&, ApplyContext& ac) + -> std::optional> { + if (loanBrokerKeylet.type != ltLOAN_BROKER) + return {}; + auto sleBroker = ac.view().peek(loanBrokerKeylet); + if (!sleBroker) + return {}; + if (!BEAST_EXPECT(sleBroker->at(sfOwnerCount) == 0)) + return {}; + // Need to touch sleBroker so that it is included in the + // modified entries for the invariant to find + ac.view().update(sleBroker); + + // The pseudo-account holds the directory, so get it + auto const pseudoAccountID = sleBroker->at(sfAccount); + auto const pseudoAccountKeylet = keylet::account(pseudoAccountID); + // Strictly speaking, we don't need to load the + // ACCOUNT_ROOT, but check anyway + auto slePseudo = ac.view().peek(pseudoAccountKeylet); + if (!BEAST_EXPECT(slePseudo)) + return {}; + // Make sure the directory doesn't already exist + auto const dirKeylet = keylet::ownerDir(pseudoAccountID); + auto sleDir = ac.view().peek(dirKeylet); + auto const describe = describeOwnerDir(pseudoAccountID); + if (!sleDir) + { + // Create the directory + BEAST_EXPECT( + ::xrpl::directory::createRoot(ac.view(), dirKeylet, loanBrokerKeylet.key, describe) == 0); + + sleDir = ac.view().peek(dirKeylet); + } + + return std::make_pair(slePseudo, sleDir); + }; + + doInvariantCheck( + {{"Loan Broker with zero OwnerCount has multiple directory " + "pages"}}, + [&setupTest, this](Account const& A1, Account const& A2, ApplyContext& ac) { + auto test = setupTest(A1, A2, ac); + if (!test || !test->first || !test->second) + return false; + + auto slePseudo = test->first; + auto sleDir = test->second; + auto const describe = describeOwnerDir(slePseudo->at(sfAccount)); + + BEAST_EXPECT( + ::xrpl::directory::insertPage( + ac.view(), + 0, + sleDir, + 0, + sleDir, + slePseudo->key(), + keylet::page(sleDir->key(), 0), + describe) == 1); + + return true; + }, + XRPAmount{}, + STTx{ttLOAN_BROKER_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + + doInvariantCheck( + {{"Loan Broker with zero OwnerCount has multiple indexes in " + "the Directory root"}}, + [&setupTest](Account const& A1, Account const& A2, ApplyContext& ac) { + auto test = setupTest(A1, A2, ac); + if (!test || !test->first || !test->second) + return false; + + auto slePseudo = test->first; + auto sleDir = test->second; + auto indexes = sleDir->getFieldV256(sfIndexes); + + // Put some extra garbage into the directory + for (auto const& key : {slePseudo->key(), sleDir->key()}) + { + ::xrpl::directory::insertKey(ac.view(), sleDir, 0, false, indexes, key); + } + + return true; + }, + XRPAmount{}, + STTx{ttLOAN_BROKER_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + + doInvariantCheck( + {{"Loan Broker directory corrupt"}}, + [&setupTest](Account const& A1, Account const& A2, ApplyContext& ac) { + auto test = setupTest(A1, A2, ac); + if (!test || !test->first || !test->second) + return false; + + auto slePseudo = test->first; + auto sleDir = test->second; + auto const describe = describeOwnerDir(slePseudo->at(sfAccount)); + // Empty vector will overwrite the existing entry for the + // holding, if any, avoiding the "has multiple indexes" + // failure. + STVector256 indexes; + + // Put one meaningless key into the directory + auto const key = keylet::account(Account("random").id()).key; + ::xrpl::directory::insertKey(ac.view(), sleDir, 0, false, indexes, key); + + return true; + }, + XRPAmount{}, + STTx{ttLOAN_BROKER_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + + doInvariantCheck( + {{"Loan Broker with zero OwnerCount has an unexpected entry in " + "the directory"}}, + [&setupTest](Account const& A1, Account const& A2, ApplyContext& ac) { + auto test = setupTest(A1, A2, ac); + if (!test || !test->first || !test->second) + return false; + + auto slePseudo = test->first; + auto sleDir = test->second; + // Empty vector will overwrite the existing entry for the + // holding, if any, avoiding the "has multiple indexes" + // failure. + STVector256 indexes; + + ::xrpl::directory::insertKey(ac.view(), sleDir, 0, false, indexes, slePseudo->key()); + + return true; + }, + XRPAmount{}, + STTx{ttLOAN_BROKER_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + + doInvariantCheck( + {{"Loan Broker sequence number decreased"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + if (loanBrokerKeylet.type != ltLOAN_BROKER) + return false; + auto sleBroker = ac.view().peek(loanBrokerKeylet); + if (!sleBroker) + return false; + if (!BEAST_EXPECT(sleBroker->at(sfLoanSequence) > 0)) + return false; + // Need to touch sleBroker so that it is included in the + // modified entries for the invariant to find + ac.view().update(sleBroker); + + sleBroker->at(sfLoanSequence) -= 1; + + return true; + }, + XRPAmount{}, + STTx{ttLOAN_BROKER_SET, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + createLoanBroker); + } } void @@ -1762,9 +2210,7 @@ class Invariants_test : public beast::unit_test::suite std::optional accountAssets = {}; std::optional accountShares = {}; }; - auto constexpr adjust = [&](ApplyView& ac, - ripple::Keylet keylet, - Adjustments args) { + auto constexpr adjust = [&](ApplyView& ac, xrpl::Keylet keylet, Adjustments args) { auto sleVault = ac.peek(keylet); if (!sleVault) return false; @@ -1782,17 +2228,14 @@ class Invariants_test : public beast::unit_test::suite // Remaining fields are adjusted in terms of difference if (args.assetsTotal) - (*sleVault)[sfAssetsTotal] = - *(*sleVault)[sfAssetsTotal] + *args.assetsTotal; + (*sleVault)[sfAssetsTotal] = *(*sleVault)[sfAssetsTotal] + *args.assetsTotal; if (args.assetsAvailable) - (*sleVault)[sfAssetsAvailable] = - *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable; + (*sleVault)[sfAssetsAvailable] = *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable; ac.update(sleVault); if (args.sharesTotal) { - (*sleShares)[sfOutstandingAmount] = - *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal; + (*sleShares)[sfOutstandingAmount] = *(*sleShares)[sfOutstandingAmount] + *args.sharesTotal; ac.update(sleShares); } @@ -1805,8 +2248,7 @@ class Invariants_test : public beast::unit_test::suite auto slePseudoAccount = ac.peek(keylet::account(pseudoId)); if (!slePseudoAccount) return false; - (*slePseudoAccount)[sfBalance] = - *(*slePseudoAccount)[sfBalance] + *args.vaultAssets; + (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] + *args.vaultAssets; ac.update(slePseudoAccount); } else if (assets.holds()) @@ -1815,8 +2257,7 @@ class Invariants_test : public beast::unit_test::suite auto sleMPToken = ac.peek(keylet::mptoken(mptId, pseudoId)); if (!sleMPToken) return false; - (*sleMPToken)[sfMPTAmount] = - *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets; + (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + *args.vaultAssets; ac.update(sleMPToken); } else @@ -1831,19 +2272,16 @@ class Invariants_test : public beast::unit_test::suite auto sleAccount = ac.peek(keylet::account(pair.account)); if (!sleAccount) return false; - (*sleAccount)[sfBalance] = - *(*sleAccount)[sfBalance] + pair.amount; + (*sleAccount)[sfBalance] = *(*sleAccount)[sfBalance] + pair.amount; ac.update(sleAccount); } else if (assets.holds()) { auto const mptID = assets.get().getMptID(); - auto sleMPToken = - ac.peek(keylet::mptoken(mptID, pair.account)); + auto sleMPToken = ac.peek(keylet::mptoken(mptID, pair.account)); if (!sleMPToken) return false; - (*sleMPToken)[sfMPTAmount] = - *(*sleMPToken)[sfMPTAmount] + pair.amount; + (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount; ac.update(sleMPToken); } else @@ -1853,19 +2291,16 @@ class Invariants_test : public beast::unit_test::suite if (args.accountShares) { auto const& pair = *args.accountShares; - auto sleMPToken = - ac.peek(keylet::mptoken(mptIssuanceID, pair.account)); + auto sleMPToken = ac.peek(keylet::mptoken(mptIssuanceID, pair.account)); if (!sleMPToken) return false; - (*sleMPToken)[sfMPTAmount] = - *(*sleMPToken)[sfMPTAmount] + pair.amount; + (*sleMPToken)[sfMPTAmount] = *(*sleMPToken)[sfMPTAmount] + pair.amount; ac.update(sleMPToken); } return true; }; - constexpr auto args = - [](AccountID id, int adjustment, auto fn) -> Adjustments { + constexpr auto args = [](AccountID id, int adjustment, auto fn) -> Adjustments { Adjustments sample = { .assetsTotal = adjustment, .assetsAvailable = adjustment, @@ -1882,19 +2317,14 @@ class Invariants_test : public beast::unit_test::suite Account A3{"A3"}; Account A4{"A4"}; - auto const precloseXrp = - [&](Account const& A1, Account const& A2, Env& env) -> bool { + auto const precloseXrp = [&](Account const& A1, Account const& A2, Env& env) -> bool { env.fund(XRP(1000), A3, A4); Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); - env(vault.deposit( - {.depositor = A1, .id = keylet.key, .amount = XRP(10)})); - env(vault.deposit( - {.depositor = A2, .id = keylet.key, .amount = XRP(10)})); - env(vault.deposit( - {.depositor = A3, .id = keylet.key, .amount = XRP(10)})); + env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)})); + env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = XRP(10)})); + env(vault.deposit({.depositor = A3, .id = keylet.key, .amount = XRP(10)})); return true; }; @@ -1965,10 +2395,8 @@ class Invariants_test : public beast::unit_test::suite auto const sequence = ac.view().seq(); auto const vaultKeylet = keylet::vault(A1.id(), sequence); auto sleVault = std::make_shared(vaultKeylet); - auto const vaultPage = ac.view().dirInsert( - keylet::ownerDir(A1.id()), - sleVault->key(), - describeOwnerDir(A1.id())); + auto const vaultPage = + ac.view().dirInsert(keylet::ownerDir(A1.id()), sleVault->key(), describeOwnerDir(A1.id())); sleVault->setFieldU64(sfOwnerNode, *vaultPage); ac.view().insert(sleVault); return true; @@ -2022,13 +2450,11 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; { - auto [tx, _] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, _] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); } { - auto [tx, _] = - vault.create({.owner = A2, .asset = xrpIssue()}); + auto [tx, _] = vault.create({.owner = A2, .asset = xrpIssue()}); env(tx); } return true; @@ -2041,10 +2467,8 @@ class Invariants_test : public beast::unit_test::suite auto const insertVault = [&](Account const A) { auto const vaultKeylet = keylet::vault(A.id(), sequence); auto sleVault = std::make_shared(vaultKeylet); - auto const vaultPage = ac.view().dirInsert( - keylet::ownerDir(A.id()), - sleVault->key(), - describeOwnerDir(A.id())); + auto const vaultPage = + ac.view().dirInsert(keylet::ownerDir(A.id()), sleVault->key(), describeOwnerDir(A.id())); sleVault->setFieldU64(sfOwnerNode, *vaultPage); ac.view().insert(sleVault); }; @@ -2085,8 +2509,7 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; ac.view().erase(sleVault); @@ -2098,11 +2521,9 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); - env(vault.deposit( - {.depositor = A1, .id = keylet.key, .amount = XRP(10)})); + env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)})); return true; }); @@ -2113,8 +2534,7 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; // Note, such an "orphaned" update of MPT issuance attached to a @@ -2131,9 +2551,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {"vault operation succeeded without modifying a vault"}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - return true; - }, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttVAULT_CREATE, [](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, @@ -2146,9 +2564,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {"vault operation succeeded without modifying a vault"}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - return true; - }, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttVAULT_DEPOSIT, [](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, @@ -2161,9 +2577,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {"vault operation succeeded without modifying a vault"}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - return true; - }, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, @@ -2176,9 +2590,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {"vault operation succeeded without modifying a vault"}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - return true; - }, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttVAULT_CLAWBACK, [](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, @@ -2191,9 +2603,7 @@ class Invariants_test : public beast::unit_test::suite doInvariantCheck( {"vault operation succeeded without modifying a vault"}, - [&](Account const& A1, Account const& A2, ApplyContext& ac) { - return true; - }, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { return true; }, XRPAmount{}, STTx{ttVAULT_DELETE, [](STObject&) {}}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, @@ -2214,8 +2624,7 @@ class Invariants_test : public beast::unit_test::suite (*sleVault)[sfAssetsMaximum] = 200; ac.view().update(sleVault); - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; ac.view().erase(sleShares); @@ -2248,11 +2657,9 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); - env(vault.deposit( - {.depositor = A1, .id = keylet.key, .amount = XRP(10)})); + env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = XRP(10)})); return true; }); @@ -2269,12 +2676,10 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto slePseudoAccount = - ac.view().peek(keylet::account(*(*sleVault)[sfAccount])); + auto slePseudoAccount = ac.view().peek(keylet::account(*(*sleVault)[sfAccount])); if (!slePseudoAccount) return false; - (*slePseudoAccount)[sfBalance] = - *(*slePseudoAccount)[sfBalance] - 10; + (*slePseudoAccount)[sfBalance] = *(*slePseudoAccount)[sfBalance] - 10; ac.view().update(slePseudoAccount); // Move 10 drops to A4 to enforce total XRP balance @@ -2284,14 +2689,11 @@ class Invariants_test : public beast::unit_test::suite (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10; ac.view().update(sleA4); - return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) { - sample.assetsAvailable = (DROPS_PER_XRP * -100).value(); - sample.assetsTotal = (DROPS_PER_XRP * -200).value(); - sample.sharesTotal = -1; - })); + return adjust(ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) { + sample.assetsAvailable = (DROPS_PER_XRP * -100).value(); + sample.assetsTotal = (DROPS_PER_XRP * -200).value(); + sample.sharesTotal = -1; + })); }, XRPAmount{}, STTx{ttVAULT_SET, [](STObject& tx) {}}, @@ -2306,8 +2708,7 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - sleVault->setFieldIssue( - sfAsset, STIssue{sfAsset, MPTIssue(MPTID(42))}); + sleVault->setFieldIssue(sfAsset, STIssue{sfAsset, MPTIssue(MPTID(42))}); ac.view().update(sleVault); return true; }, @@ -2349,17 +2750,13 @@ class Invariants_test : public beast::unit_test::suite precloseXrp); doInvariantCheck( - {"vault transaction must not change loss unrealized", - "set must not change assets outstanding"}, + {"vault transaction must not change loss unrealized", "set must not change assets outstanding"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) { - sample.lossUnrealized = 13; - sample.assetsTotal = 20; - })); + return adjust(ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) { + sample.lossUnrealized = 13; + sample.assetsTotal = 20; + })); }, XRPAmount{}, STTx{ttVAULT_SET, [](STObject& tx) {}}, @@ -2374,18 +2771,10 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 100, [&](Adjustments& sample) { - sample.lossUnrealized = 13; - })); + ac.view(), keylet, args(A2.id(), 100, [&](Adjustments& sample) { sample.lossUnrealized = 13; })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { - tx.setFieldAmount(sfAmount, XRPAmount(200)); - }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx.setFieldAmount(sfAmount, XRPAmount(200)); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -2395,11 +2784,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) { - sample.assetsMaximum = 1; - })); + ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = 1; })); }, XRPAmount{}, STTx{ttVAULT_SET, [](STObject& tx) {}}, @@ -2412,11 +2797,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) { - sample.assetsMaximum = -1; - })); + ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) { sample.assetsMaximum = -1; })); }, XRPAmount{}, STTx{ttVAULT_SET, [](STObject& tx) {}}, @@ -2434,8 +2815,7 @@ class Invariants_test : public beast::unit_test::suite if (!sleVault) return false; ac.view().update(sleVault); - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; (*sleShares)[sfOutstandingAmount] = 0; @@ -2455,15 +2835,13 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; (*sleShares)[sfMaximumAmount] = 10; ac.view().update(sleShares); - return adjust( - ac.view(), keylet, args(A2.id(), 10, [](Adjustments&) {})); + return adjust(ac.view(), keylet, args(A2.id(), 10, [](Adjustments&) {})); }, XRPAmount{}, STTx{ttVAULT_DEPOSIT, [](STObject&) {}}, @@ -2475,14 +2853,12 @@ class Invariants_test : public beast::unit_test::suite {"updated shares must not exceed maximum"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - adjust( - ac.view(), keylet, args(A2.id(), 10, [](Adjustments&) {})); + adjust(ac.view(), keylet, args(A2.id(), 10, [](Adjustments&) {})); auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; (*sleShares)[sfOutstandingAmount] = maxMPTokenAmount + 1; @@ -2516,8 +2892,7 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); @@ -2543,8 +2918,7 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); @@ -2571,8 +2945,7 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); @@ -2587,8 +2960,7 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; ac.view().update(sleVault); @@ -2601,8 +2973,7 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); @@ -2626,8 +2997,7 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); @@ -2642,8 +3012,7 @@ class Invariants_test : public beast::unit_test::suite auto sleVault = ac.view().peek(keylet); if (!sleVault) return false; - auto sleShares = ac.view().peek( - keylet::mptIssuance((*sleVault)[sfShareMPTID])); + auto sleShares = ac.view().peek(keylet::mptIssuance((*sleVault)[sfShareMPTID])); if (!sleShares) return false; ac.view().update(sleVault); @@ -2656,15 +3025,13 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, [&](Account const& A1, Account const& A2, Env& env) { Vault vault{env}; - auto [tx, keylet] = - vault.create({.owner = A1, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = A1, .asset = xrpIssue()}); env(tx); return true; }); doInvariantCheck( - {"vault created by a wrong transaction type", - "account root created illegally"}, + {"vault created by a wrong transaction type", "account root created illegally"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { // The code below will create a valid vault with (almost) all // the invariants holding. Except one: it is created by the @@ -2672,17 +3039,13 @@ class Invariants_test : public beast::unit_test::suite auto const sequence = ac.view().seq(); auto const vaultKeylet = keylet::vault(A1.id(), sequence); auto sleVault = std::make_shared(vaultKeylet); - auto const vaultPage = ac.view().dirInsert( - keylet::ownerDir(A1.id()), - sleVault->key(), - describeOwnerDir(A1.id())); + auto const vaultPage = + ac.view().dirInsert(keylet::ownerDir(A1.id()), sleVault->key(), describeOwnerDir(A1.id())); sleVault->setFieldU64(sfOwnerNode, *vaultPage); - auto pseudoId = - pseudoAccountAddress(ac.view(), vaultKeylet.key); + auto pseudoId = pseudoAccountAddress(ac.view(), vaultKeylet.key); // Create pseudo-account. - auto sleAccount = - std::make_shared(keylet::account(pseudoId)); + auto sleAccount = std::make_shared(keylet::account(pseudoId)); sleAccount->setAccountID(sfAccount, pseudoId); sleAccount->setFieldAmount(sfBalance, STAmount{}); std::uint32_t const seqno = // @@ -2690,19 +3053,15 @@ class Invariants_test : public beast::unit_test::suite ? 0 // : sequence; sleAccount->setFieldU32(sfSequence, seqno); - sleAccount->setFieldU32( - sfFlags, - lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); + sleAccount->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); sleAccount->setFieldH256(sfVaultID, vaultKeylet.key); ac.view().insert(sleAccount); auto const sharesMptId = makeMptID(sequence, pseudoId); auto const sharesKeylet = keylet::mptIssuance(sharesMptId); auto sleShares = std::make_shared(sharesKeylet); - auto const sharesPage = ac.view().dirInsert( - keylet::ownerDir(pseudoId), - sharesKeylet, - describeOwnerDir(pseudoId)); + auto const sharesPage = + ac.view().dirInsert(keylet::ownerDir(pseudoId), sharesKeylet, describeOwnerDir(pseudoId)); sleShares->setFieldU64(sfOwnerNode, *sharesPage); sleShares->at(sfFlags) = 0; @@ -2718,8 +3077,7 @@ class Invariants_test : public beast::unit_test::suite sleVault->at(sfAssetsAvailable) = Number(0); sleVault->at(sfLossUnrealized) = Number(0); sleVault->at(sfShareMPTID) = sharesMptId; - sleVault->at(sfWithdrawalPolicy) = - vaultStrategyFirstComeFirstServe; + sleVault->at(sfWithdrawalPolicy) = vaultStrategyFirstComeFirstServe; ac.view().insert(sleVault); ac.view().insert(sleShares); @@ -2736,17 +3094,13 @@ class Invariants_test : public beast::unit_test::suite auto const sequence = ac.view().seq(); auto const vaultKeylet = keylet::vault(A1.id(), sequence); auto sleVault = std::make_shared(vaultKeylet); - auto const vaultPage = ac.view().dirInsert( - keylet::ownerDir(A1.id()), - sleVault->key(), - describeOwnerDir(A1.id())); + auto const vaultPage = + ac.view().dirInsert(keylet::ownerDir(A1.id()), sleVault->key(), describeOwnerDir(A1.id())); sleVault->setFieldU64(sfOwnerNode, *vaultPage); - auto pseudoId = - pseudoAccountAddress(ac.view(), vaultKeylet.key); + auto pseudoId = pseudoAccountAddress(ac.view(), vaultKeylet.key); // Create pseudo-account. - auto sleAccount = - std::make_shared(keylet::account(pseudoId)); + auto sleAccount = std::make_shared(keylet::account(pseudoId)); sleAccount->setAccountID(sfAccount, pseudoId); sleAccount->setFieldAmount(sfBalance, STAmount{}); std::uint32_t const seqno = // @@ -2754,9 +3108,7 @@ class Invariants_test : public beast::unit_test::suite ? 0 // : sequence; sleAccount->setFieldU32(sfSequence, seqno); - sleAccount->setFieldU32( - sfFlags, - lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); + sleAccount->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); // sleAccount->setFieldH256(sfVaultID, vaultKeylet.key); // Setting wrong vault key sleAccount->setFieldH256(sfVaultID, uint256(42)); @@ -2765,10 +3117,8 @@ class Invariants_test : public beast::unit_test::suite auto const sharesMptId = makeMptID(sequence, pseudoId); auto const sharesKeylet = keylet::mptIssuance(sharesMptId); auto sleShares = std::make_shared(sharesKeylet); - auto const sharesPage = ac.view().dirInsert( - keylet::ownerDir(pseudoId), - sharesKeylet, - describeOwnerDir(pseudoId)); + auto const sharesPage = + ac.view().dirInsert(keylet::ownerDir(pseudoId), sharesKeylet, describeOwnerDir(pseudoId)); sleShares->setFieldU64(sfOwnerNode, *sharesPage); sleShares->at(sfFlags) = 0; @@ -2777,7 +3127,7 @@ class Invariants_test : public beast::unit_test::suite sleShares->at(sfSequence) = sequence; // sleVault->at(sfAccount) = pseudoId; - // Setting wrong pseudo acocunt ID + // Setting wrong pseudo account ID sleVault->at(sfAccount) = A2.id(); sleVault->at(sfFlags) = 0; sleVault->at(sfSequence) = sequence; @@ -2786,8 +3136,7 @@ class Invariants_test : public beast::unit_test::suite sleVault->at(sfAssetsAvailable) = Number(0); sleVault->at(sfLossUnrealized) = Number(0); sleVault->at(sfShareMPTID) = sharesMptId; - sleVault->at(sfWithdrawalPolicy) = - vaultStrategyFirstComeFirstServe; + sleVault->at(sfWithdrawalPolicy) = vaultStrategyFirstComeFirstServe; ac.view().insert(sleVault); ac.view().insert(sleShares); @@ -2798,29 +3147,24 @@ class Invariants_test : public beast::unit_test::suite {tecINVARIANT_FAILED, tefINVARIANT_FAILED}); doInvariantCheck( - {"shares issuer and vault pseudo-account must be the same", - "shares issuer must exist"}, + {"shares issuer and vault pseudo-account must be the same", "shares issuer must exist"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const sequence = ac.view().seq(); auto const vaultKeylet = keylet::vault(A1.id(), sequence); auto sleVault = std::make_shared(vaultKeylet); - auto const vaultPage = ac.view().dirInsert( - keylet::ownerDir(A1.id()), - sleVault->key(), - describeOwnerDir(A1.id())); + auto const vaultPage = + ac.view().dirInsert(keylet::ownerDir(A1.id()), sleVault->key(), describeOwnerDir(A1.id())); sleVault->setFieldU64(sfOwnerNode, *vaultPage); auto const sharesMptId = makeMptID(sequence, A2.id()); auto const sharesKeylet = keylet::mptIssuance(sharesMptId); auto sleShares = std::make_shared(sharesKeylet); - auto const sharesPage = ac.view().dirInsert( - keylet::ownerDir(A2.id()), - sharesKeylet, - describeOwnerDir(A2.id())); + auto const sharesPage = + ac.view().dirInsert(keylet::ownerDir(A2.id()), sharesKeylet, describeOwnerDir(A2.id())); sleShares->setFieldU64(sfOwnerNode, *sharesPage); sleShares->at(sfFlags) = 0; - // Setting wrong pseudo acocunt ID + // Setting wrong pseudo account ID sleShares->at(sfIssuer) = AccountID(uint160(42)); sleShares->at(sfOutstandingAmount) = 0; sleShares->at(sfSequence) = sequence; @@ -2833,8 +3177,7 @@ class Invariants_test : public beast::unit_test::suite sleVault->at(sfAssetsAvailable) = Number(0); sleVault->at(sfLossUnrealized) = Number(0); sleVault->at(sfShareMPTID) = sharesMptId; - sleVault->at(sfWithdrawalPolicy) = - vaultStrategyFirstComeFirstServe; + sleVault->at(sfWithdrawalPolicy) = vaultStrategyFirstComeFirstServe; ac.view().insert(sleVault); ac.view().insert(sleShares); @@ -2850,11 +3193,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [](Adjustments& sample) { - sample.vaultAssets.reset(); - })); + ac.view(), keylet, args(A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); })); }, XRPAmount{}, STTx{ttVAULT_DEPOSIT, [](STObject&) {}}, @@ -2866,18 +3205,10 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 200, [&](Adjustments& sample) { - sample.assetsMaximum = 1; - })); + ac.view(), keylet, args(A2.id(), 200, [&](Adjustments& sample) { sample.assetsMaximum = 1; })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { - tx.setFieldAmount(sfAmount, XRPAmount(200)); - }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx.setFieldAmount(sfAmount, XRPAmount(200)); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -2887,8 +3218,7 @@ class Invariants_test : public beast::unit_test::suite // The operation makes no sense, but the defensive check in // ValidVault::finalize is otherwise impossible to trigger. doInvariantCheck( - {"deposit must increase vault balance", - "deposit must change depositor balance"}, + {"deposit must increase vault balance", "deposit must change depositor balance"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); @@ -2899,12 +3229,9 @@ class Invariants_test : public beast::unit_test::suite (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10; ac.view().update(sleA4); - return adjust( - ac.view(), - keylet, - args(A3.id(), -10, [&](Adjustments& sample) { - sample.accountAssets->amount = -100; - })); + return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) { + sample.accountAssets->amount = -100; + })); }, XRPAmount{100}, STTx{ @@ -2932,18 +3259,13 @@ class Invariants_test : public beast::unit_test::suite (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10; ac.view().update(sleA3); - return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.vaultAssets = -20; - sample.accountAssets->amount = 10; - })); + return adjust(ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { + sample.vaultAssets = -20; + sample.accountAssets->amount = 10; + })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -2960,17 +3282,12 @@ class Invariants_test : public beast::unit_test::suite (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] - 10; ac.view().update(sleA3); - return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.accountAssets->amount = 0; - })); + return adjust(ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { + sample.accountAssets->amount = 0; + })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -2980,16 +3297,10 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.accountShares.reset(); - })); + ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { sample.accountShares.reset(); })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -3000,16 +3311,10 @@ class Invariants_test : public beast::unit_test::suite auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [](Adjustments& sample) { - sample.sharesTotal = 0; - })); + ac.view(), keylet, args(A2.id(), 10, [](Adjustments& sample) { sample.sharesTotal = 0; })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -3021,18 +3326,13 @@ class Invariants_test : public beast::unit_test::suite "amount"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.accountShares->amount = -5; - sample.sharesTotal = -10; - })); + return adjust(ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { + sample.accountShares->amount = -5; + sample.sharesTotal = -10; + })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(5); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(5); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -3046,11 +3346,7 @@ class Invariants_test : public beast::unit_test::suite auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.assetsTotal = 11; - })); + ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { sample.assetsTotal = 11; })); }, XRPAmount{2000}, STTx{ @@ -3065,22 +3361,16 @@ class Invariants_test : public beast::unit_test::suite TxAccount::A2); doInvariantCheck( - {"deposit and assets outstanding must add up", - "deposit and assets available must add up"}, + {"deposit and assets outstanding must add up", "deposit and assets available must add up"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), 10, [&](Adjustments& sample) { - sample.assetsTotal = 7; - sample.assetsAvailable = 7; - })); + return adjust(ac.view(), keylet, args(A2.id(), 10, [&](Adjustments& sample) { + sample.assetsTotal = 7; + sample.assetsAvailable = 7; + })); }, XRPAmount{}, - STTx{ - ttVAULT_DEPOSIT, - [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, + STTx{ttVAULT_DEPOSIT, [](STObject& tx) { tx[sfAmount] = XRPAmount(10); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -3091,11 +3381,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [](Adjustments& sample) { - sample.vaultAssets.reset(); - })); + ac.view(), keylet, args(A2.id(), 0, [](Adjustments& sample) { sample.vaultAssets.reset(); })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3118,12 +3404,9 @@ class Invariants_test : public beast::unit_test::suite (*sleA4)[sfBalance] = *(*sleA4)[sfBalance] + 10; ac.view().update(sleA4); - return adjust( - ac.view(), - keylet, - args(A3.id(), -10, [&](Adjustments& sample) { - sample.accountAssets->amount = -100; - })); + return adjust(ac.view(), keylet, args(A3.id(), -10, [&](Adjustments& sample) { + sample.accountAssets->amount = -100; + })); }, XRPAmount{100}, STTx{ @@ -3154,13 +3437,10 @@ class Invariants_test : public beast::unit_test::suite (*sleA3)[sfBalance] = *(*sleA3)[sfBalance] + 10; ac.view().update(sleA3); - return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.vaultAssets = 10; - sample.accountAssets->amount = -20; - })); + return adjust(ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { + sample.vaultAssets = 10; + sample.accountAssets->amount = -20; + })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3173,11 +3453,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); if (!adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - *sample.vaultAssets -= 5; - }))) + ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { *sample.vaultAssets -= 5; }))) return false; auto sleA3 = ac.view().peek(keylet::account(A3.id())); if (!sleA3) @@ -3187,9 +3463,7 @@ class Invariants_test : public beast::unit_test::suite return true; }, XRPAmount{}, - STTx{ - ttVAULT_WITHDRAW, - [&](STObject& tx) { tx.setAccountID(sfDestination, A3.id()); }}, + STTx{ttVAULT_WITHDRAW, [&](STObject& tx) { tx.setAccountID(sfDestination, A3.id()); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseXrp, TxAccount::A2); @@ -3199,11 +3473,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.accountShares.reset(); - })); + ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3216,11 +3486,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [](Adjustments& sample) { - sample.sharesTotal = 0; - })); + ac.view(), keylet, args(A2.id(), -10, [](Adjustments& sample) { sample.sharesTotal = 0; })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3234,13 +3500,10 @@ class Invariants_test : public beast::unit_test::suite "amount"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.accountShares->amount = 5; - sample.sharesTotal = 10; - })); + return adjust(ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { + sample.accountShares->amount = 5; + sample.sharesTotal = 10; + })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3249,17 +3512,13 @@ class Invariants_test : public beast::unit_test::suite TxAccount::A2); doInvariantCheck( - {"withdrawal and assets outstanding must add up", - "withdrawal and assets available must add up"}, + {"withdrawal and assets outstanding must add up", "withdrawal and assets available must add up"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.assetsTotal = -15; - sample.assetsAvailable = -15; - })); + return adjust(ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { + sample.assetsTotal = -15; + sample.assetsAvailable = -15; + })); }, XRPAmount{}, STTx{ttVAULT_WITHDRAW, [](STObject&) {}}, @@ -3276,11 +3535,7 @@ class Invariants_test : public beast::unit_test::suite auto const keylet = keylet::vault(A1.id(), ac.view().seq()); return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.assetsTotal = -7; - })); + ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { sample.assetsTotal = -7; })); }, XRPAmount{2000}, STTx{ @@ -3294,8 +3549,7 @@ class Invariants_test : public beast::unit_test::suite precloseXrp, TxAccount::A2); - auto const precloseMpt = - [&](Account const& A1, Account const& A2, Env& env) -> bool { + auto const precloseMpt = [&](Account const& A1, Account const& A2, Env& env) -> bool { env.fund(XRP(1000), A3, A4); // Create MPT asset @@ -3335,12 +3589,9 @@ class Invariants_test : public beast::unit_test::suite Vault vault{env}; auto [tx, keylet] = vault.create({.owner = A1, .asset = asset}); env(tx); - env(vault.deposit( - {.depositor = A1, .id = keylet.key, .amount = asset(10)})); - env(vault.deposit( - {.depositor = A2, .id = keylet.key, .amount = asset(10)})); - env(vault.deposit( - {.depositor = A4, .id = keylet.key, .amount = asset(10)})); + env(vault.deposit({.depositor = A1, .id = keylet.key, .amount = asset(10)})); + env(vault.deposit({.depositor = A2, .id = keylet.key, .amount = asset(10)})); + env(vault.deposit({.depositor = A4, .id = keylet.key, .amount = asset(10)})); return true; }; @@ -3350,17 +3601,12 @@ class Invariants_test : public beast::unit_test::suite "amount"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); - return adjust( - ac.view(), - keylet, - args(A2.id(), -10, [&](Adjustments& sample) { - sample.accountShares->amount = 5; - })); + return adjust(ac.view(), keylet, args(A2.id(), -10, [&](Adjustments& sample) { + sample.accountShares->amount = 5; + })); }, XRPAmount{}, - STTx{ - ttVAULT_WITHDRAW, - [&](STObject& tx) { tx[sfAccount] = A3.id(); }}, + STTx{ttVAULT_WITHDRAW, [&](STObject& tx) { tx[sfAccount] = A3.id(); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseMpt, TxAccount::A2); @@ -3371,16 +3617,10 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); return adjust( - ac.view(), - keylet, - args(A2.id(), -1, [&](Adjustments& sample) { - sample.vaultAssets.reset(); - })); + ac.view(), keylet, args(A2.id(), -1, [&](Adjustments& sample) { sample.vaultAssets.reset(); })); }, XRPAmount{}, - STTx{ - ttVAULT_CLAWBACK, - [&](STObject& tx) { tx[sfAccount] = A3.id(); }}, + STTx{ttVAULT_CLAWBACK, [&](STObject& tx) { tx[sfAccount] = A3.id(); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseMpt); @@ -3389,10 +3629,7 @@ class Invariants_test : public beast::unit_test::suite {"clawback may only be performed by the asset issuer"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); - return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) {})); + return adjust(ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) {})); }, XRPAmount{}, STTx{ttVAULT_CLAWBACK, [](STObject&) {}}, @@ -3404,15 +3641,10 @@ class Invariants_test : public beast::unit_test::suite {"clawback may only be performed by the asset issuer"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); - return adjust( - ac.view(), - keylet, - args(A2.id(), 0, [&](Adjustments& sample) {})); + return adjust(ac.view(), keylet, args(A2.id(), 0, [&](Adjustments& sample) {})); }, XRPAmount{}, - STTx{ - ttVAULT_CLAWBACK, - [&](STObject& tx) { tx[sfAccount] = A4.id(); }}, + STTx{ttVAULT_CLAWBACK, [&](STObject& tx) { tx[sfAccount] = A4.id(); }}, {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseMpt); @@ -3423,11 +3655,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); return adjust( - ac.view(), - keylet, - args(A4.id(), 10, [&](Adjustments& sample) { - sample.sharesTotal = 0; - })); + ac.view(), keylet, args(A4.id(), 10, [&](Adjustments& sample) { sample.sharesTotal = 0; })); }, XRPAmount{}, STTx{ @@ -3444,11 +3672,7 @@ class Invariants_test : public beast::unit_test::suite [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); return adjust( - ac.view(), - keylet, - args(A4.id(), -10, [&](Adjustments& sample) { - sample.accountShares.reset(); - })); + ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) { sample.accountShares.reset(); })); }, XRPAmount{}, STTx{ @@ -3466,14 +3690,11 @@ class Invariants_test : public beast::unit_test::suite "clawback and assets available must add up"}, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq() - 2); - return adjust( - ac.view(), - keylet, - args(A4.id(), -10, [&](Adjustments& sample) { - sample.accountShares->amount = -8; - sample.assetsTotal = -7; - sample.assetsAvailable = -7; - })); + return adjust(ac.view(), keylet, args(A4.id(), -10, [&](Adjustments& sample) { + sample.accountShares->amount = -8; + sample.assetsTotal = -7; + sample.assetsAvailable = -7; + })); }, XRPAmount{}, STTx{ @@ -3486,6 +3707,189 @@ class Invariants_test : public beast::unit_test::suite precloseMpt); } + void + testConfidentialMPTTransfer() + { + using namespace test::jtx; + testcase << "ValidConfidentialMPToken"; + + MPTID mptID; + + // Generate an MPT with privacy, issue 100 tokens to A2. + // Perform a confidential conversion to populate encrypted state. + auto const precloseConfidential = [&mptID](Account const& A1, Account const& A2, Env& env) -> bool { + MPTTester mpt(env, A1, {.holders = {A2}, .fund = false}); + mpt.create({.flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + mptID = mpt.issuanceID(); + + mpt.authorize({.account = A2}); + mpt.pay(A1, A2, 100); + + mpt.generateKeyPair(A1); + mpt.set({.account = A1, .issuerPubKey = mpt.getPubKey(A1)}); + + mpt.generateKeyPair(A2); + mpt.convert({ + .account = A2, + .amt = 100, + .holderPubKey = mpt.getPubKey(A2), + }); + return true; + }; + + // badDelete + doInvariantCheck( + {"MPToken deleted with encrypted fields while COA > 0"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, A2.id())); + if (!sleToken) + return false; + // Force an erase of the object while the COA remains 100 + ac.view().erase(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + precloseConfidential); + + // badConsistency + doInvariantCheck( + {"MPToken encrypted field existence inconsistency"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, A2.id())); + if (!sleToken) + return false; + // Remove one of the required encrypted fields to create a mismatch + sleToken->makeFieldAbsent(sfIssuerEncryptedBalance); + ac.view().update(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseConfidential); + + // requiresPrivacyFlag + auto const precloseNoPrivacy = [&mptID](Account const& A1, Account const& A2, Env& env) -> bool { + MPTTester mpt(env, A1, {.holders = {A2}, .fund = false}); + // completely omitted the tfMPTCanPrivacy flag here. + mpt.create({.flags = tfMPTCanTransfer}); + mptID = mpt.issuanceID(); + mpt.authorize({.account = A2}); + mpt.pay(A1, A2, 100); + return true; + }; + + doInvariantCheck( + {"MPToken has encrypted fields but Issuance does not have lsfMPTCanPrivacy set"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, A2.id())); + if (!sleToken) + return false; + // Inject fields correctly, but the Issuance was built without the privacy flag. + sleToken->setFieldVL(sfConfidentialBalanceInbox, Blob{0x00}); + sleToken->setFieldVL(sfIssuerEncryptedBalance, Blob{0x00}); + ac.view().update(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseNoPrivacy); + + // badCOA + doInvariantCheck( + {"Confidential outstanding amount exceeds total outstanding amount"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleIssuance = ac.view().peek(keylet::mptIssuance(mptID)); + if (!sleIssuance) + return false; + // Total outstanding is natively 100; bloat the COA over 100 + sleIssuance->setFieldU64(sfConfidentialOutstandingAmount, 200); + ac.view().update(sleIssuance); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_ISSUANCE_SET, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseConfidential); + + // Conservation Violation + doInvariantCheck( + {"Token conservation violation for MPT"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleIssuance = ac.view().peek(keylet::mptIssuance(mptID)); + if (!sleIssuance) + return false; + + sleIssuance->setFieldU64( + sfConfidentialOutstandingAmount, sleIssuance->getFieldU64(sfConfidentialOutstandingAmount) - 10); + ac.view().update(sleIssuance); + + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseConfidential); + + // badVersion + doInvariantCheck( + {"MPToken sfConfidentialBalanceVersion not updated when sfConfidentialBalanceSpending changed"}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, A2.id())); + if (!sleToken) + return false; + sleToken->setFieldVL(sfConfidentialBalanceSpending, Blob{0xBA, 0xDD}); + + // DO NOT update sfConfidentialBalanceVersion + ac.view().update(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseConfidential); + + // Skipping Deleted MPTs (Issuance deleted) + auto const precloseOrphan = [&mptID](Account const& A1, Account const& A2, Env& env) -> bool { + MPTTester mpt(env, A1, {.holders = {A2}, .fund = false}); + mpt.create({.flags = tfMPTCanTransfer | tfMPTCanPrivacy}); + mptID = mpt.issuanceID(); + mpt.authorize({.account = A2}); + + // Generate privacy keys and convert 0 amount so Bob has the encrypted fields + mpt.generateKeyPair(A1); + mpt.set({.account = A1, .issuerPubKey = mpt.getPubKey(A1)}); + mpt.generateKeyPair(A2); + mpt.convert({ + .account = A2, + .amt = 0, + .holderPubKey = mpt.getPubKey(A2), + }); + + // Immediately destroy the issuance. A2's empty, encrypted token object lives on. + mpt.destroy(); + return true; + }; + + doInvariantCheck( + {}, + [&mptID](Account const& A1, Account const& A2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, A2.id())); + if (!sleToken) + return false; + // Safely able to erase the deleted token. + ac.view().erase(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tesSUCCESS, tesSUCCESS}, + precloseOrphan); + } + public: void run() override @@ -3503,14 +3907,19 @@ public: testNoZeroEscrow(); testValidNewAccountRoot(); testNFTokenPageInvariants(); - testPermissionedDomainInvariants(); + testPermissionedDomainInvariants(defaultAmendments() | fixPermissionedDomainInvariant); + testPermissionedDomainInvariants(defaultAmendments() - fixPermissionedDomainInvariant); + testPermissionedDEX(defaultAmendments() | fixPermissionedDomainInvariant); + testPermissionedDEX(defaultAmendments() - fixPermissionedDomainInvariant); + testNoModifiedUnmodifiableFields(); testValidPseudoAccounts(); - testPermissionedDEX(); + testValidLoanBroker(); testVault(); + testConfidentialMPTTransfer(); } }; -BEAST_DEFINE_TESTSUITE(Invariants, app, ripple); +BEAST_DEFINE_TESTSUITE(Invariants, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LPTokenTransfer_test.cpp b/src/test/app/LPTokenTransfer_test.cpp index eccd864e71..055b72ebe6 100644 --- a/src/test/app/LPTokenTransfer_test.cpp +++ b/src/test/app/LPTokenTransfer_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class LPTokenTransfer_test : public jtx::AMMTest @@ -37,18 +18,15 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); AMM ammAlice(env, alice, USD(20'000), BTC(0.5)); - BEAST_EXPECT( - ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(20'000), BTC(0.5), IOUAmount{100, 0})); fund(env, gw, {carol}, {USD(4'000), BTC(1)}, Fund::Acct); ammAlice.deposit(carol, 10); - BEAST_EXPECT( - ammAlice.expectBalances(USD(22'000), BTC(0.55), IOUAmount{110, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(22'000), BTC(0.55), IOUAmount{110, 0})); fund(env, gw, {bob}, {USD(4'000), BTC(1)}, Fund::Acct); ammAlice.deposit(bob, 10); - BEAST_EXPECT( - ammAlice.expectBalances(USD(24'000), BTC(0.60), IOUAmount{120, 0})); + BEAST_EXPECT(ammAlice.expectBalances(USD(24'000), BTC(0.60), IOUAmount{120, 0})); auto const lpIssue = ammAlice.lptIssue(); env.trust(STAmount{lpIssue, 500}, alice); @@ -68,8 +46,7 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // cannot transfer to an amm account - env(pay(carol, lpIssue.getIssuer(), STAmount{lpIssue, 5}), - ter(tecNO_PERMISSION)); + env(pay(carol, lpIssue.getIssuer(), STAmount{lpIssue, 5}), ter(tecNO_PERMISSION)); env.close(); if (features[fixFrozenLPTokenTransfer]) @@ -92,12 +69,7 @@ class LPTokenTransfer_test : public jtx::AMMTest using namespace jtx; Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(10'000), EUR(10'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(10'000), EUR(10'000)}, Fund::All); AMM ammAlice(env, alice, USD(10'000), EUR(10'000)); ammAlice.deposit(carol, 1'000); ammAlice.deposit(bob, 1'000); @@ -125,10 +97,7 @@ class LPTokenTransfer_test : public jtx::AMMTest { // with fixFrozenLPTokenTransfer, alice fails to consume carol's // offer since carol's USD is frozen - env(pay(alice, bob, STAmount{lpIssue, 10}), - txflags(tfPartialPayment), - sendmax(XRP(10)), - ter(tecPATH_DRY)); + env(pay(alice, bob, STAmount{lpIssue, 10}), txflags(tfPartialPayment), sendmax(XRP(10)), ter(tecPATH_DRY)); env.close(); BEAST_EXPECT(expectOffers(env, carol, 1)); @@ -137,9 +106,7 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // alice successfully consumes carol's offer - env(pay(alice, bob, STAmount{lpIssue, 10}), - txflags(tfPartialPayment), - sendmax(XRP(10))); + env(pay(alice, bob, STAmount{lpIssue, 10}), txflags(tfPartialPayment), sendmax(XRP(10))); env.close(); BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -147,9 +114,7 @@ class LPTokenTransfer_test : public jtx::AMMTest { // without fixFrozenLPTokenTransfer, alice can consume carol's offer // even when carol's USD is frozen - env(pay(alice, bob, STAmount{lpIssue, 10}), - txflags(tfPartialPayment), - sendmax(XRP(10))); + env(pay(alice, bob, STAmount{lpIssue, 10}), txflags(tfPartialPayment), sendmax(XRP(10))); env.close(); BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -162,8 +127,7 @@ class LPTokenTransfer_test : public jtx::AMMTest // even when carol's USD is frozen { // carol creates an offer to buy lptoken - env(offer(carol, STAmount{lpIssue, 10}, XRP(10)), - txflags(tfPassive)); + env(offer(carol, STAmount{lpIssue, 10}, XRP(10)), txflags(tfPassive)); env.close(); BEAST_EXPECT(expectOffers(env, carol, 1)); @@ -172,9 +136,7 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // alice successfully consumes carol's offer - env(pay(alice, bob, XRP(10)), - txflags(tfPartialPayment), - sendmax(STAmount{lpIssue, 10})); + env(pay(alice, bob, XRP(10)), txflags(tfPartialPayment), sendmax(STAmount{lpIssue, 10})); env.close(); BEAST_EXPECT(expectOffers(env, carol, 0)); } @@ -188,12 +150,7 @@ class LPTokenTransfer_test : public jtx::AMMTest using namespace jtx; Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(10'000), EUR(10'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(10'000), EUR(10'000)}, Fund::All); AMM ammAlice(env, alice, USD(10'000), EUR(10'000)); ammAlice.deposit(carol, 1'000); ammAlice.deposit(bob, 1'000); @@ -212,9 +169,7 @@ class LPTokenTransfer_test : public jtx::AMMTest // sell lptoken when one of the assets is frozen // carol can't create an offer to sell lptoken - env(offer(carol, XRP(10), STAmount{lpIssue, 10}), - txflags(tfPassive), - ter(tecUNFUNDED_OFFER)); + env(offer(carol, XRP(10), STAmount{lpIssue, 10}), txflags(tfPassive), ter(tecUNFUNDED_OFFER)); env.close(); BEAST_EXPECT(expectOffers(env, carol, 0)); @@ -223,16 +178,14 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // carol can create an offer to sell lptoken after USD is unfrozen - env(offer(carol, XRP(10), STAmount{lpIssue, 10}), - txflags(tfPassive)); + env(offer(carol, XRP(10), STAmount{lpIssue, 10}), txflags(tfPassive)); env.close(); BEAST_EXPECT(expectOffers(env, carol, 1)); } else { // without fixFrozenLPTokenTransfer, carol can create an offer - env(offer(carol, XRP(10), STAmount{lpIssue, 10}), - txflags(tfPassive)); + env(offer(carol, XRP(10), STAmount{lpIssue, 10}), txflags(tfPassive)); env.close(); BEAST_EXPECT(expectOffers(env, carol, 1)); } @@ -292,8 +245,7 @@ class LPTokenTransfer_test : public jtx::AMMTest BEAST_EXPECT( expectHolding(env, carol, STAmount{token2, 10'000'000}) && expectHolding(env, carol, STAmount{token1, 10'000'000})); - BEAST_EXPECT( - expectOffers(env, alice, 1) && expectOffers(env, carol, 0)); + BEAST_EXPECT(expectOffers(env, alice, 1) && expectOffers(env, carol, 0)); } else { @@ -305,8 +257,7 @@ class LPTokenTransfer_test : public jtx::AMMTest BEAST_EXPECT( expectHolding(env, carol, STAmount{token2, 10'000'100}) && expectHolding(env, carol, STAmount{token1, 9'999'900})); - BEAST_EXPECT( - expectOffers(env, alice, 0) && expectOffers(env, carol, 0)); + BEAST_EXPECT(expectOffers(env, alice, 0) && expectOffers(env, carol, 0)); } } @@ -318,12 +269,7 @@ class LPTokenTransfer_test : public jtx::AMMTest using namespace jtx; Env env{*this, features}; - fund( - env, - gw, - {alice, bob, carol}, - {USD(10'000), EUR(10'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(10'000), EUR(10'000)}, Fund::All); AMM ammAlice(env, alice, USD(10'000), EUR(10'000)); ammAlice.deposit(carol, 1'000); ammAlice.deposit(bob, 1'000); @@ -342,8 +288,7 @@ class LPTokenTransfer_test : public jtx::AMMTest // with fixFrozenLPTokenTransfer enabled, bob fails to cash the check if (features[fixFrozenLPTokenTransfer]) - env(check::cash(bob, carolChkId, STAmount{lpIssue, 10}), - ter(tecPATH_PARTIAL)); + env(check::cash(bob, carolChkId, STAmount{lpIssue, 10}), ter(tecPATH_PARTIAL)); else env(check::cash(bob, carolChkId, STAmount{lpIssue, 10})); @@ -369,12 +314,7 @@ class LPTokenTransfer_test : public jtx::AMMTest Env env{*this, features}; // Setup AMM - fund( - env, - gw, - {alice, bob, carol}, - {USD(10'000), EUR(10'000)}, - Fund::All); + fund(env, gw, {alice, bob, carol}, {USD(10'000), EUR(10'000)}, Fund::All); AMM ammAlice(env, alice, USD(10'000), EUR(10'000)); ammAlice.deposit(carol, 1'000); ammAlice.deposit(bob, 1'000); @@ -388,8 +328,7 @@ class LPTokenTransfer_test : public jtx::AMMTest // bob creates a sell offer for lptoken uint256 const sellOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; - env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), - txflags(tfSellNFToken)); + env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), txflags(tfSellNFToken)); env.close(); // gateway freezes carol's USD @@ -405,8 +344,7 @@ class LPTokenTransfer_test : public jtx::AMMTest // carol fails to accept bob's offer with lptoken because carol's // USD is frozen - env(token::acceptSellOffer(carol, sellOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptSellOffer(carol, sellOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); // gateway unfreezes carol's USD @@ -417,15 +355,13 @@ class LPTokenTransfer_test : public jtx::AMMTest env(token::acceptSellOffer(carol, sellOfferIndex)); env.close(); - // gateway freezes bobs's USD + // gateway freezes bob's USD env(trust(gw, bob["USD"](0), tfSetFreeze)); env.close(); // bob fails to create a buy offer with lptoken for carol's nft // since bob's USD is frozen - env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), - token::owner(carol), - ter(tecUNFUNDED_OFFER)); + env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), token::owner(carol), ter(tecUNFUNDED_OFFER)); env.close(); // gateway unfreezes bob's USD @@ -433,8 +369,7 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // bob can now create a buy offer - env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), - token::owner(carol)); + env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), token::owner(carol)); env.close(); } else @@ -451,10 +386,8 @@ class LPTokenTransfer_test : public jtx::AMMTest env.close(); // bob creates a buy offer with lptoken despite bob's USD is frozen - uint256 const buyOfferIndex = - keylet::nftoffer(bob, env.seq(bob)).key; - env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), - token::owner(carol)); + uint256 const buyOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; + env(token::createOffer(bob, nftID, STAmount{lpIssue, 10}), token::owner(carol)); env.close(); // carol accepts bob's offer @@ -481,6 +414,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LPTokenTransfer, app, ripple); +BEAST_DEFINE_TESTSUITE(LPTokenTransfer, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LedgerHistory_test.cpp b/src/test/app/LedgerHistory_test.cpp index 1d440f6420..eeca551f35 100644 --- a/src/test/app/LedgerHistory_test.cpp +++ b/src/test/app/LedgerHistory_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class LedgerHistory_test : public beast::unit_test::suite @@ -56,19 +37,14 @@ public: { assert(!stx); return std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); } - auto res = std::make_shared( - *prev, prev->info().closeTime + closeOffset); + auto res = std::make_shared(*prev, prev->header().closeTime + closeOffset); if (stx) { OpenView accum(&*res); - applyTransaction( - env.app(), accum, *stx, false, tapNONE, env.journal); + applyTransaction(env.app(), accum, *stx, false, tapNONE, env.journal); accum.apply(*res); } res->updateSkipList(); @@ -80,10 +56,7 @@ public: res->unshare(); // Accept ledger - res->setAccepted( - res->info().closeTime, - res->info().closeTimeResolution, - true /* close time correct*/); + res->setAccepted(res->header().closeTime, res->header().closeTimeResolution, true /* close time correct*/); lh.insert(res, false); return res; } @@ -98,10 +71,7 @@ public: // No mismatch { bool found = false; - Env env{ - *this, - envconfig(), - std::make_unique("MISMATCH ", &found)}; + Env env{*this, envconfig(), std::make_unique("MISMATCH ", &found)}; LedgerHistory lh{beast::insight::NullCollector::New(), env.app()}; auto const genesis = makeLedger({}, env, lh, 0s); uint256 const dummyTxHash{1}; @@ -114,11 +84,7 @@ public: // Close time mismatch { bool found = false; - Env env{ - *this, - envconfig(), - std::make_unique( - "MISMATCH on close time", &found)}; + Env env{*this, envconfig(), std::make_unique("MISMATCH on close time", &found)}; LedgerHistory lh{beast::insight::NullCollector::New(), env.app()}; auto const genesis = makeLedger({}, env, lh, 0s); auto const ledgerA = makeLedger(genesis, env, lh, 4s); @@ -134,11 +100,7 @@ public: // Prior ledger mismatch { bool found = false; - Env env{ - *this, - envconfig(), - std::make_unique( - "MISMATCH on prior ledger", &found)}; + Env env{*this, envconfig(), std::make_unique("MISMATCH on prior ledger", &found)}; LedgerHistory lh{beast::insight::NullCollector::New(), env.app()}; auto const genesis = makeLedger({}, env, lh, 0s); auto const ledgerA = makeLedger(genesis, env, lh, 4s); @@ -157,14 +119,10 @@ public: // somehow generate different ledgers for (bool const txBug : {true, false}) { - std::string const msg = txBug - ? "MISMATCH with same consensus transaction set" - : "MISMATCH on consensus transaction set"; + std::string const msg = + txBug ? "MISMATCH with same consensus transaction set" : "MISMATCH on consensus transaction set"; bool found = false; - Env env{ - *this, - envconfig(), - std::make_unique(msg, &found)}; + Env env{*this, envconfig(), std::make_unique(msg, &found)}; LedgerHistory lh{beast::insight::NullCollector::New(), env.app()}; Account alice{"A1"}; @@ -172,12 +130,10 @@ public: env.fund(XRP(1000), alice, bob); env.close(); - auto const ledgerBase = - env.app().getLedgerMaster().getClosedLedger(); + auto const ledgerBase = env.app().getLedgerMaster().getClosedLedger(); JTx txAlice = env.jt(noop(alice)); - auto const ledgerA = - makeLedger(ledgerBase, env, lh, 4s, txAlice.stx); + auto const ledgerA = makeLedger(ledgerBase, env, lh, 4s, txAlice.stx); JTx txBob = env.jt(noop(bob)); auto const ledgerB = makeLedger(ledgerBase, env, lh, 4s, txBob.stx); @@ -185,10 +141,7 @@ public: lh.builtLedger(ledgerA, txAlice.stx->getTransactionID(), {}); // Simulate the bug by claiming ledgerB had the same consensus hash // as ledgerA, but somehow generated different ledgers - lh.validatedLedger( - ledgerB, - txBug ? txAlice.stx->getTransactionID() - : txBob.stx->getTransactionID()); + lh.validatedLedger(ledgerB, txBug ? txAlice.stx->getTransactionID() : txBob.stx->getTransactionID()); BEAST_EXPECT(found); } @@ -201,7 +154,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerHistory, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerHistory, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LedgerLoad_test.cpp b/src/test/app/LedgerLoad_test.cpp index c151bc7b4a..b4e84a3123 100644 --- a/src/test/app/LedgerLoad_test.cpp +++ b/src/test/app/LedgerLoad_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -32,7 +13,7 @@ #include -namespace ripple { +namespace xrpl { class LedgerLoad_test : public beast::unit_test::suite { @@ -40,7 +21,7 @@ class LedgerLoad_test : public beast::unit_test::suite std::unique_ptr cfg, std::string const& dbPath, std::string const& ledger, - Config::StartUpType type, + StartUpType type, std::optional trapTxHash) { cfg->START_LEDGER = ledger; @@ -88,8 +69,7 @@ class LedgerLoad_test : public beast::unit_test::suite } retval.ledger = env.rpc("ledger", "current", "full")[jss::result]; - BEAST_EXPECT( - retval.ledger[jss::ledger][jss::accountState].size() == 102); + BEAST_EXPECT(retval.ledger[jss::ledger][jss::accountState].size() == 102); retval.hashes = [&] { for (auto const& it : retval.ledger[jss::ledger][jss::accountState]) @@ -102,10 +82,7 @@ class LedgerLoad_test : public beast::unit_test::suite BEAST_EXPECT(retval.hashes.size() == 41); retval.trapTxHash = [&]() { - auto const txs = env.rpc( - "ledger", - std::to_string(41), - "tx")[jss::result][jss::ledger][jss::transactions]; + auto const txs = env.rpc("ledger", std::to_string(41), "tx")[jss::result][jss::ledger][jss::transactions]; BEAST_EXPECT(txs.isArray() && txs.size() > 0); uint256 tmp; BEAST_EXPECT(tmp.parseHex(txs[0u][jss::hash].asString())); @@ -128,18 +105,11 @@ class LedgerLoad_test : public beast::unit_test::suite // create a new env with the ledger file specified for startup Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - sd.ledgerFile, - Config::LOAD_FILE, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, sd.ledgerFile, StartUpType::LOAD_FILE, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; - BEAST_EXPECT( - sd.ledger[jss::ledger][jss::accountState].size() == - jrb[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(sd.ledger[jss::ledger][jss::accountState].size() == jrb[jss::ledger][jss::accountState].size()); } void @@ -153,12 +123,7 @@ class LedgerLoad_test : public beast::unit_test::suite except([&] { Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - "", - Config::LOAD_FILE, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, "", StartUpType::LOAD_FILE, std::nullopt), nullptr, beast::severities::kDisabled); }); @@ -167,25 +132,15 @@ class LedgerLoad_test : public beast::unit_test::suite except([&] { Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - "badfile.json", - Config::LOAD_FILE, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, "badfile.json", StartUpType::LOAD_FILE, std::nullopt), nullptr, beast::severities::kDisabled); }); // make a corrupted version of the ledger file (last 10 bytes removed). boost::system::error_code ec; - auto ledgerFileCorrupt = - boost::filesystem::path{sd.dbPath} / "ledgerdata_bad.json"; - copy_file( - sd.ledgerFile, - ledgerFileCorrupt, - copy_options::overwrite_existing, - ec); + auto ledgerFileCorrupt = boost::filesystem::path{sd.dbPath} / "ledgerdata_bad.json"; + copy_file(sd.ledgerFile, ledgerFileCorrupt, copy_options::overwrite_existing, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; auto filesize = file_size(ledgerFileCorrupt, ec); @@ -198,12 +153,7 @@ class LedgerLoad_test : public beast::unit_test::suite except([&] { Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - ledgerFileCorrupt.string(), - Config::LOAD_FILE, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, ledgerFileCorrupt.string(), StartUpType::LOAD_FILE, std::nullopt), nullptr, beast::severities::kDisabled); }); @@ -220,19 +170,12 @@ class LedgerLoad_test : public beast::unit_test::suite boost::erase_all(ledgerHash, "\""); Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - ledgerHash, - Config::LOAD, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, ledgerHash, StartUpType::LOAD, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; BEAST_EXPECT(jrb[jss::ledger][jss::accountState].size() == 98); - BEAST_EXPECT( - jrb[jss::ledger][jss::accountState].size() <= - sd.ledger[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(jrb[jss::ledger][jss::accountState].size() <= sd.ledger[jss::ledger][jss::accountState].size()); } void @@ -246,12 +189,7 @@ class LedgerLoad_test : public beast::unit_test::suite boost::erase_all(ledgerHash, "\""); Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - ledgerHash, - Config::REPLAY, - std::nullopt), + envconfig(ledgerConfig, sd.dbPath, ledgerHash, StartUpType::REPLAY, std::nullopt), nullptr, beast::severities::kDisabled); auto const jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -261,9 +199,7 @@ class LedgerLoad_test : public beast::unit_test::suite env.close(); auto const closed = env.rpc("ledger", "current", "full")[jss::result]; BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() == 98); - BEAST_EXPECT( - closed[jss::ledger][jss::accountState].size() <= - sd.ledger[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() <= sd.ledger[jss::ledger][jss::accountState].size()); } void @@ -277,12 +213,7 @@ class LedgerLoad_test : public beast::unit_test::suite boost::erase_all(ledgerHash, "\""); Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - ledgerHash, - Config::REPLAY, - sd.trapTxHash), + envconfig(ledgerConfig, sd.dbPath, ledgerHash, StartUpType::REPLAY, sd.trapTxHash), nullptr, beast::severities::kDisabled); auto const jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -292,9 +223,7 @@ class LedgerLoad_test : public beast::unit_test::suite env.close(); auto const closed = env.rpc("ledger", "current", "full")[jss::result]; BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() == 98); - BEAST_EXPECT( - closed[jss::ledger][jss::accountState].size() <= - sd.ledger[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() <= sd.ledger[jss::ledger][jss::accountState].size()); } void @@ -312,12 +241,7 @@ class LedgerLoad_test : public beast::unit_test::suite // replay when trapTxHash is set to an invalid transaction Env env( *this, - envconfig( - ledgerConfig, - sd.dbPath, - ledgerHash, - Config::REPLAY, - ~sd.trapTxHash), + envconfig(ledgerConfig, sd.dbPath, ledgerHash, StartUpType::REPLAY, ~sd.trapTxHash), nullptr, beast::severities::kDisabled); BEAST_EXPECT(false); @@ -341,14 +265,11 @@ class LedgerLoad_test : public beast::unit_test::suite // create a new env with the ledger "latest" specified for startup Env env( *this, - envconfig( - ledgerConfig, sd.dbPath, "latest", Config::LOAD, std::nullopt), + envconfig(ledgerConfig, sd.dbPath, "latest", StartUpType::LOAD, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; - BEAST_EXPECT( - sd.ledger[jss::ledger][jss::accountState].size() == - jrb[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(sd.ledger[jss::ledger][jss::accountState].size() == jrb[jss::ledger][jss::accountState].size()); } void @@ -360,14 +281,11 @@ class LedgerLoad_test : public beast::unit_test::suite // create a new env with specific ledger index at startup Env env( *this, - envconfig( - ledgerConfig, sd.dbPath, "43", Config::LOAD, std::nullopt), + envconfig(ledgerConfig, sd.dbPath, "43", StartUpType::LOAD, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; - BEAST_EXPECT( - sd.ledger[jss::ledger][jss::accountState].size() == - jrb[jss::ledger][jss::accountState].size()); + BEAST_EXPECT(sd.ledger[jss::ledger][jss::accountState].size() == jrb[jss::ledger][jss::accountState].size()); } public: @@ -389,6 +307,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerLoad, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerLoad, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LedgerMaster_test.cpp b/src/test/app/LedgerMaster_test.cpp index 828e4b09c2..eb346288c2 100644 --- a/src/test/app/LedgerMaster_test.cpp +++ b/src/test/app/LedgerMaster_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 XRPLF - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class LedgerMaster_test : public beast::unit_test::suite @@ -56,52 +37,46 @@ class LedgerMaster_test : public beast::unit_test::suite // build ledgers std::vector> txns; std::vector> metas; - auto const startLegSeq = env.current()->info().seq; + auto const startLegSeq = env.current()->header().seq; for (int i = 0; i < 2; ++i) { env(noop(alice)); txns.emplace_back(env.tx()); env.close(); - metas.emplace_back( - env.closed()->txRead(env.tx()->getTransactionID()).second); + metas.emplace_back(env.closed()->txRead(env.tx()->getTransactionID()).second); } // add last (empty) ledger env.close(); - auto const endLegSeq = env.closed()->info().seq; + auto const endLegSeq = env.closed()->header().seq; // test invalid range { std::uint32_t ledgerSeq = -1; std::uint32_t txnIndex = 0; - auto result = - env.app().getLedgerMaster().txnIdFromIndex(ledgerSeq, txnIndex); + auto result = env.app().getLedgerMaster().txnIdFromIndex(ledgerSeq, txnIndex); BEAST_EXPECT(!result); } // test not in ledger { uint32_t txnIndex = metas[0]->getFieldU32(sfTransactionIndex); - auto result = - env.app().getLedgerMaster().txnIdFromIndex(0, txnIndex); + auto result = env.app().getLedgerMaster().txnIdFromIndex(0, txnIndex); BEAST_EXPECT(!result); } // test empty ledger { - auto result = - env.app().getLedgerMaster().txnIdFromIndex(endLegSeq, 0); + auto result = env.app().getLedgerMaster().txnIdFromIndex(endLegSeq, 0); BEAST_EXPECT(!result); } // ended without result { uint32_t txnIndex = metas[0]->getFieldU32(sfTransactionIndex); - auto result = env.app().getLedgerMaster().txnIdFromIndex( - endLegSeq + 1, txnIndex); + auto result = env.app().getLedgerMaster().txnIdFromIndex(endLegSeq + 1, txnIndex); BEAST_EXPECT(!result); } // success (first tx) { uint32_t txnIndex = metas[0]->getFieldU32(sfTransactionIndex); - auto result = env.app().getLedgerMaster().txnIdFromIndex( - startLegSeq, txnIndex); + auto result = env.app().getLedgerMaster().txnIdFromIndex(startLegSeq, txnIndex); BEAST_EXPECT( *result == uint256("277F4FD89C20B92457FEF05FF63F6405563AD0563C73D967A29727" @@ -110,8 +85,7 @@ class LedgerMaster_test : public beast::unit_test::suite // success (second tx) { uint32_t txnIndex = metas[1]->getFieldU32(sfTransactionIndex); - auto result = env.app().getLedgerMaster().txnIdFromIndex( - startLegSeq + 1, txnIndex); + auto result = env.app().getLedgerMaster().txnIdFromIndex(startLegSeq + 1, txnIndex); BEAST_EXPECT( *result == uint256("293DF7335EBBAF4420D52E70ABF470EB4C5792CAEA2F91F76193C2" @@ -135,7 +109,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerMaster, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerMaster, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index e54f24d340..229cad21c9 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -36,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct LedgerReplay_test : public beast::unit_test::suite @@ -58,16 +39,11 @@ struct LedgerReplay_test : public beast::unit_test::suite LedgerMaster& ledgerMaster = env.app().getLedgerMaster(); auto const lastClosed = ledgerMaster.getClosedLedger(); - auto const lastClosedParent = - ledgerMaster.getLedgerByHash(lastClosed->info().parentHash); + auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash); - auto const replayed = buildLedger( - LedgerReplay(lastClosedParent, lastClosed), - tapNONE, - env.app(), - env.journal); + auto const replayed = buildLedger(LedgerReplay(lastClosedParent, lastClosed), tapNONE, env.app(), env.journal); - BEAST_EXPECT(replayed->info().hash == lastClosed->info().hash); + BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash); } }; @@ -84,18 +60,14 @@ enum class InboundLedgersBehavior { class MagicInboundLedgers : public InboundLedgers { public: - MagicInboundLedgers( - LedgerMaster& ledgerSource, - LedgerMaster& ledgerSink, - InboundLedgersBehavior bhvr) + MagicInboundLedgers(LedgerMaster& ledgerSource, LedgerMaster& ledgerSink, InboundLedgersBehavior bhvr) : ledgerSource(ledgerSource), ledgerSink(ledgerSink), bhvr(bhvr) { } virtual ~MagicInboundLedgers() = default; virtual std::shared_ptr - acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason) - override + acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason) override { if (bhvr == InboundLedgersBehavior::DropAll) return {}; @@ -109,10 +81,7 @@ public: } virtual void - acquireAsync( - uint256 const& hash, - std::uint32_t seq, - InboundLedger::Reason reason) override + acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override { } @@ -123,10 +92,7 @@ public: } virtual bool - gotLedgerData( - LedgerHash const& ledgerHash, - std::shared_ptr, - std::shared_ptr) override + gotLedgerData(LedgerHash const& ledgerHash, std::shared_ptr, std::shared_ptr) override { return false; } @@ -208,8 +174,7 @@ class TestPeer : public Peer { public: TestPeer(bool enableLedgerReplay) - : ledgerReplayEnabled_(enableLedgerReplay) - , nodePublicKey_(derivePublicKey(KeyType::ed25519, randomSecretKey())) + : ledgerReplayEnabled_(enableLedgerReplay), nodePublicKey_(derivePublicKey(KeyType::ed25519, randomSecretKey())) { } @@ -223,8 +188,7 @@ public: return {}; } void - charge(Resource::Charge const& fee, std::string const& context = {}) - override + charge(Resource::Charge const& fee, std::string const& context = {}) override { } id_t @@ -358,10 +322,7 @@ struct TestPeerSet : public PeerSet LedgerReplayMsgHandler& other, PeerSetBehavior bhvr, bool enableLedgerReplay) - : local(me) - , remote(other) - , dummyPeer(std::make_shared(enableLedgerReplay)) - , behavior(bhvr) + : local(me), remote(other), dummyPeer(std::make_shared(enableLedgerReplay)), behavior(bhvr) { } @@ -376,10 +337,8 @@ struct TestPeerSet : public PeerSet } void - sendRequest( - ::google::protobuf::Message const& msg, - protocol::MessageType type, - std::shared_ptr const& peer) override + sendRequest(::google::protobuf::Message const& msg, protocol::MessageType type, std::shared_ptr const& peer) + override { int dropRate = 0; if (behavior == PeerSetBehavior::Drop50) @@ -397,8 +356,7 @@ struct TestPeerSet : public PeerSet return; auto request = std::make_shared( dynamic_cast(msg)); - auto reply = std::make_shared( - remote.processProofPathRequest(request)); + auto reply = std::make_shared(remote.processProofPathRequest(request)); local.processProofPathResponse(reply); if (behavior == PeerSetBehavior::Repeat) local.processProofPathResponse(reply); @@ -409,8 +367,8 @@ struct TestPeerSet : public PeerSet return; auto request = std::make_shared( dynamic_cast(msg)); - auto reply = std::make_shared( - remote.processReplayDeltaRequest(request)); + auto reply = + std::make_shared(remote.processReplayDeltaRequest(request)); local.processReplayDeltaResponse(reply); if (behavior == PeerSetBehavior::Repeat) local.processReplayDeltaResponse(reply); @@ -445,18 +403,14 @@ public: LedgerReplayMsgHandler& other, PeerSetBehavior bhvr, PeerFeature peerFeature) - : local(me) - , remote(other) - , behavior(bhvr) - , enableLedgerReplay(peerFeature == PeerFeature::LedgerReplayEnabled) + : local(me), remote(other), behavior(bhvr), enableLedgerReplay(peerFeature == PeerFeature::LedgerReplayEnabled) { } std::unique_ptr build() override { - return std::make_unique( - local, remote, behavior, enableLedgerReplay); + return std::make_unique(local, remote, behavior, enableLedgerReplay); } private: @@ -503,8 +457,7 @@ struct LedgerServer auto fundedAccounts = accounts.size(); for (int i = 0; i < newAccounts; ++i) { - accounts.emplace_back( - "alice_" + std::to_string(fundedAccounts + i)); + accounts.emplace_back("alice_" + std::to_string(fundedAccounts + i)); env.fund(jtx::XRP(param.initAmount), accounts.back()); } env.close(); @@ -538,11 +491,9 @@ struct LedgerServer for (int i = 0; i < newTxes; ++i) { updateIdx(); - env.apply( - pay(accounts[fromIdx], + env(pay(accounts[fromIdx], accounts[toIdx], - jtx::drops(ledgerMaster.getClosedLedger()->fees().base) + - jtx::XRP(param.txAmount)), + jtx::drops(ledgerMaster.getClosedLedger()->fees().base) + jtx::XRP(param.txAmount)), jtx::seq(jtx::autofill), jtx::fee(jtx::autofill), jtx::sig(jtx::autofill)); @@ -596,20 +547,13 @@ public: : env(suite, jtx::envconfig(), nullptr, beast::severities::kDisabled) , app(env.app()) , ledgerMaster(env.app().getLedgerMaster()) - , inboundLedgers( - server.app.getLedgerMaster(), - ledgerMaster, - inboundBhvr) + , inboundLedgers(server.app.getLedgerMaster(), ledgerMaster, inboundBhvr) , serverMsgHandler(server.app, server.app.getLedgerReplayer()) , clientMsgHandler(env.app(), replayer) , replayer( env.app(), inboundLedgers, - std::make_unique( - clientMsgHandler, - serverMsgHandler, - behavior, - peerFeature)) + std::make_unique(clientMsgHandler, serverMsgHandler, behavior, peerFeature)) { } @@ -629,7 +573,7 @@ public: auto const l = ledgerMaster.getLedgerByHash(hash); if (!l) return false; - hash = l->info().parentHash; + hash = l->header().parentHash; } return true; } @@ -685,11 +629,9 @@ public: findTask(uint256 const& hash, int totalReplay) { std::unique_lock lock(replayer.mtx_); - auto i = std::find_if( - replayer.tasks_.begin(), replayer.tasks_.end(), [&](auto const& t) { - return t->parameter_.finishHash_ == hash && - t->parameter_.totalLedgers_ == totalReplay; - }); + auto i = std::find_if(replayer.tasks_.begin(), replayer.tasks_.end(), [&](auto const& t) { + return t->parameter_.finishHash_ == hash && t->parameter_.totalLedgers_ == totalReplay; + }); if (i == replayer.tasks_.end()) return {}; return *i; @@ -710,14 +652,10 @@ public: } bool - countsAsExpected( - std::size_t tasks, - std::size_t skipLists, - std::size_t deltas) + countsAsExpected(std::size_t tasks, std::size_t skipLists, std::size_t deltas) { std::unique_lock lock(replayer.mtx_); - return replayer.tasks_.size() == tasks && - replayer.skipLists_.size() == skipLists && + return replayer.tasks_.size() == tasks && replayer.skipLists_.size() == skipLists && replayer.deltas_.size() == deltas; } @@ -826,8 +764,7 @@ public: if (!waitForDone()) return false; - return checkStatus( - hash, totalReplay, taskExpect, skiplistExpect, deltaExpects); + return checkStatus(hash, totalReplay, taskExpect, skiplistExpect, deltaExpects); } jtx::Env env; @@ -841,10 +778,7 @@ public: using namespace beast::severities; void -logAll( - LedgerServer& server, - LedgerReplayClient& client, - beast::severities::Severity level = Severity::kTrace) +logAll(LedgerServer& server, LedgerReplayClient& client, beast::severities::Severity level = Severity::kTrace) { server.app.logs().threshold(level); client.app.logs().threshold(level); @@ -862,8 +796,7 @@ struct NetworkOfTwo PeerSetBehavior behavior = PeerSetBehavior::Good, InboundLedgersBehavior inboundBhvr = InboundLedgersBehavior::Good, PeerFeature peerFeature = PeerFeature::LedgerReplayEnabled) - : server(suite, param) - , client(suite, server, behavior, inboundBhvr, peerFeature) + : server(suite, param), client(suite, server, behavior, inboundBhvr, peerFeature) { // logAll(server, client); } @@ -908,11 +841,10 @@ struct LedgerReplayer_test : public beast::unit_test::suite { // request, missing key auto request = std::make_shared(); - request->set_ledgerhash( - l->info().hash.data(), l->info().hash.size()); + request->set_ledgerhash(l->header().hash.data(), l->header().hash.size()); request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE); - auto reply = std::make_shared( - server.msgHandler.processProofPathRequest(request)); + auto reply = + std::make_shared(server.msgHandler.processProofPathRequest(request)); BEAST_EXPECT(reply->has_error()); BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply)); } @@ -920,26 +852,23 @@ struct LedgerReplayer_test : public beast::unit_test::suite // request, wrong hash auto request = std::make_shared(); request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE); - request->set_key( - keylet::skip().key.data(), keylet::skip().key.size()); + request->set_key(keylet::skip().key.data(), keylet::skip().key.size()); uint256 hash(1234567); request->set_ledgerhash(hash.data(), hash.size()); - auto reply = std::make_shared( - server.msgHandler.processProofPathRequest(request)); + auto reply = + std::make_shared(server.msgHandler.processProofPathRequest(request)); BEAST_EXPECT(reply->has_error()); } { // good request auto request = std::make_shared(); - request->set_ledgerhash( - l->info().hash.data(), l->info().hash.size()); + request->set_ledgerhash(l->header().hash.data(), l->header().hash.size()); request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE); - request->set_key( - keylet::skip().key.data(), keylet::skip().key.size()); + request->set_key(keylet::skip().key.data(), keylet::skip().key.size()); // generate response - auto reply = std::make_shared( - server.msgHandler.processProofPathRequest(request)); + auto reply = + std::make_shared(server.msgHandler.processProofPathRequest(request)); BEAST_EXPECT(!reply->has_error()); BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply)); @@ -949,15 +878,13 @@ struct LedgerReplayer_test : public beast::unit_test::suite std::string r(reply->ledgerheader()); r.back()--; reply->set_ledgerheader(r); - BEAST_EXPECT( - !server.msgHandler.processProofPathResponse(reply)); + BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply)); r.back()++; reply->set_ledgerheader(r); BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply)); // bad proof path reply->mutable_path()->RemoveLast(); - BEAST_EXPECT( - !server.msgHandler.processProofPathResponse(reply)); + BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply)); } } } @@ -972,15 +899,15 @@ struct LedgerReplayer_test : public beast::unit_test::suite { // request, missing hash auto request = std::make_shared(); - auto reply = std::make_shared( - server.msgHandler.processReplayDeltaRequest(request)); + auto reply = + std::make_shared(server.msgHandler.processReplayDeltaRequest(request)); BEAST_EXPECT(reply->has_error()); BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply)); // request, wrong hash uint256 hash(1234567); request->set_ledgerhash(hash.data(), hash.size()); - reply = std::make_shared( - server.msgHandler.processReplayDeltaRequest(request)); + reply = + std::make_shared(server.msgHandler.processReplayDeltaRequest(request)); BEAST_EXPECT(reply->has_error()); BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply)); } @@ -988,10 +915,9 @@ struct LedgerReplayer_test : public beast::unit_test::suite { // good request auto request = std::make_shared(); - request->set_ledgerhash( - l->info().hash.data(), l->info().hash.size()); - auto reply = std::make_shared( - server.msgHandler.processReplayDeltaRequest(request)); + request->set_ledgerhash(l->header().hash.data(), l->header().hash.size()); + auto reply = + std::make_shared(server.msgHandler.processReplayDeltaRequest(request)); BEAST_EXPECT(!reply->has_error()); BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply)); @@ -1001,16 +927,13 @@ struct LedgerReplayer_test : public beast::unit_test::suite std::string r(reply->ledgerheader()); r.back()--; reply->set_ledgerheader(r); - BEAST_EXPECT( - !server.msgHandler.processReplayDeltaResponse(reply)); + BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply)); r.back()++; reply->set_ledgerheader(r); - BEAST_EXPECT( - server.msgHandler.processReplayDeltaResponse(reply)); + BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply)); // bad txns reply->mutable_transaction()->RemoveLast(); - BEAST_EXPECT( - !server.msgHandler.processReplayDeltaResponse(reply)); + BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply)); } } } @@ -1027,8 +950,7 @@ struct LedgerReplayer_test : public beast::unit_test::suite return sList; }; - LedgerReplayTask::TaskParameter tp10( - InboundLedger::Reason::GENERIC, uint256(10), 10); + LedgerReplayTask::TaskParameter tp10(InboundLedger::Reason::GENERIC, uint256(10), 10); BEAST_EXPECT(!tp10.update(uint256(777), 5, makeSkipList(10))); BEAST_EXPECT(!tp10.update(uint256(10), 5, makeSkipList(8))); BEAST_EXPECT(tp10.update(uint256(10), 10, makeSkipList(10))); @@ -1037,8 +959,7 @@ struct LedgerReplayer_test : public beast::unit_test::suite BEAST_EXPECT(tp10.canMergeInto(tp10)); // smaller task - LedgerReplayTask::TaskParameter tp9( - InboundLedger::Reason::GENERIC, uint256(9), 9); + LedgerReplayTask::TaskParameter tp9(InboundLedger::Reason::GENERIC, uint256(9), 9); BEAST_EXPECT(tp9.canMergeInto(tp10)); BEAST_EXPECT(!tp10.canMergeInto(tp9)); @@ -1059,8 +980,7 @@ struct LedgerReplayer_test : public beast::unit_test::suite BEAST_EXPECT(tp9.canMergeInto(tp10)); // larger task - LedgerReplayTask::TaskParameter tp20( - InboundLedger::Reason::GENERIC, uint256(20), 20); + LedgerReplayTask::TaskParameter tp20(InboundLedger::Reason::GENERIC, uint256(20), 20); BEAST_EXPECT(tp20.update(uint256(20), 20, makeSkipList(20))); BEAST_EXPECT(tp10.canMergeInto(tp20)); BEAST_EXPECT(tp9.canMergeInto(tp20)); @@ -1103,31 +1023,19 @@ struct LedgerReplayer_test : public beast::unit_test::suite { testcase("handshake test"); auto handshake = [&](bool client, bool server, bool expecting) -> bool { - auto request = - ripple::makeRequest(true, false, client, false, false); + auto request = xrpl::makeRequest(true, false, client, false, false); http_request_type http_request; http_request.version(request.version()); http_request.base() = request.base(); - bool serverResult = - peerFeatureEnabled(http_request, FEATURE_LEDGER_REPLAY, server); + bool serverResult = peerFeatureEnabled(http_request, FEATURE_LEDGER_REPLAY, server); if (serverResult != expecting) return false; - beast::IP::Address addr = - boost::asio::ip::make_address("172.1.1.100"); + beast::IP::Address addr = boost::asio::ip::make_address("172.1.1.100"); jtx::Env serverEnv(*this); serverEnv.app().config().LEDGER_REPLAY = server; - auto http_resp = ripple::makeResponse( - true, - http_request, - addr, - addr, - uint256{1}, - 1, - {1, 0}, - serverEnv.app()); - auto const clientResult = - peerFeatureEnabled(http_resp, FEATURE_LEDGER_REPLAY, client); + auto http_resp = xrpl::makeResponse(true, http_request, addr, addr, uint256{1}, 1, {1, 0}, serverEnv.app()); + auto const clientResult = peerFeatureEnabled(http_resp, FEATURE_LEDGER_REPLAY, client); if (clientResult != expecting) return false; @@ -1151,31 +1059,24 @@ struct LedgerReplayer_test : public beast::unit_test::suite NetworkOfTwo net(*this, {totalReplay + 1}, psBhvr, ilBhvr, peerFeature); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; + uint256 finalHash = l->header().hash; for (int i = 0; i < totalReplay; ++i) { BEAST_EXPECT(l); if (l) { net.client.ledgerMaster.storeLedger(l); - l = net.server.ledgerMaster.getLedgerByHash( - l->info().parentHash); + l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); } else break; } - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Completed); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Completed); BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Completed, - TaskStatus::Completed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); // sweep net.client.replayer.sweep(); @@ -1187,25 +1088,15 @@ struct LedgerReplayer_test : public beast::unit_test::suite { testcase("all the ledgers from InboundLedgers"); NetworkOfTwo net( - *this, - {totalReplay + 1}, - PeerSetBehavior::DropAll, - InboundLedgersBehavior::Good, - PeerFeature::None); + *this, {totalReplay + 1}, PeerSetBehavior::DropAll, InboundLedgersBehavior::Good, PeerFeature::None); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + uint256 finalHash = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Completed); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Completed); BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Completed, - TaskStatus::Completed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); // sweep net.client.replayer.sweep(); @@ -1239,24 +1130,18 @@ struct LedgerReplayer_test : public beast::unit_test::suite // feed client with start ledger since InboundLedgers drops all auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; + uint256 finalHash = l->header().hash; for (int i = 0; i < totalReplay - 1; ++i) { - l = net.server.ledgerMaster.getLedgerByHash(l->info().parentHash); + l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); } net.client.ledgerMaster.storeLedger(l); - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Completed); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Completed); BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Completed, - TaskStatus::Completed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay)); // sweep @@ -1277,17 +1162,12 @@ struct LedgerReplayer_test : public beast::unit_test::suite PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + uint256 finalHash = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); std::vector deltaStatuses; - BEAST_EXPECT(net.client.checkStatus( - finalHash, - totalReplay, - TaskStatus::NotDone, - TaskStatus::NotDone, - deltaStatuses)); + BEAST_EXPECT( + net.client.checkStatus(finalHash, totalReplay, TaskStatus::NotDone, TaskStatus::NotDone, deltaStatuses)); BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0)); net.client.replayer.stop(); @@ -1307,35 +1187,23 @@ struct LedgerReplayer_test : public beast::unit_test::suite PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + uint256 finalHash = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); auto skipList = net.client.findSkipListAcquire(finalHash); - std::uint8_t payload[55] = { - 0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2}; - auto item = - make_shamapitem(uint256(12345), Slice(payload, sizeof(payload))); + std::uint8_t payload[55] = {0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2}; + auto item = make_shamapitem(uint256(12345), Slice(payload, sizeof(payload))); skipList->processData(l->seq(), item); std::vector deltaStatuses; BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Failed, - TaskStatus::Failed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses)); // add another task - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1); BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Failed, - TaskStatus::Failed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses)); BEAST_EXPECT(net.client.countsAsExpected(2, 1, 0)); } @@ -1352,26 +1220,20 @@ struct LedgerReplayer_test : public beast::unit_test::suite PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; + uint256 finalHash = l->header().hash; net.client.ledgerMaster.storeLedger(l); - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); - auto delta = net.client.findLedgerDeltaAcquire(l->info().parentHash); + auto delta = net.client.findLedgerDeltaAcquire(l->header().parentHash); delta->processData( - l->info(), // wrong ledger info + l->header(), // wrong ledger info std::map>()); BEAST_EXPECT(net.client.taskStatus(delta) == TaskStatus::Failed); - BEAST_EXPECT( - net.client.taskStatus(net.client.findTask( - finalHash, totalReplay)) == TaskStatus::Failed); + BEAST_EXPECT(net.client.taskStatus(net.client.findTask(finalHash, totalReplay)) == TaskStatus::Failed); // add another task - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1); - BEAST_EXPECT( - net.client.taskStatus(net.client.findTask( - finalHash, totalReplay + 1)) == TaskStatus::Failed); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1); + BEAST_EXPECT(net.client.taskStatus(net.client.findTask(finalHash, totalReplay + 1)) == TaskStatus::Failed); } void @@ -1386,36 +1248,27 @@ struct LedgerReplayer_test : public beast::unit_test::suite InboundLedgersBehavior::Good, PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Completed); + uint256 finalHash = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Completed); BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Completed, - TaskStatus::Completed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay)); // same range, same reason - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1)); // same range, different reason - net.client.replayer.replay( - InboundLedger::Reason::CONSENSUS, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::CONSENSUS, finalHash, totalReplay); BEAST_EXPECT(net.client.countsAsExpected(2, 1, totalReplay - 1)); // no overlap for (int i = 0; i < totalReplay + 2; ++i) { - l = net.server.ledgerMaster.getLedgerByHash(l->info().parentHash); + l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); } - auto finalHash_early = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash_early, totalReplay); + auto finalHash_early = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash_early, totalReplay); BEAST_EXPECT(net.client.waitAndCheckStatus( finalHash_early, totalReplay, @@ -1426,26 +1279,21 @@ struct LedgerReplayer_test : public beast::unit_test::suite BEAST_EXPECT(net.client.countsAsExpected(3, 2, 2 * (totalReplay - 1))); // partial overlap - l = net.server.ledgerMaster.getLedgerByHash(l->info().parentHash); - auto finalHash_moreEarly = l->info().parentHash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash_moreEarly, totalReplay); + l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); + auto finalHash_moreEarly = l->header().parentHash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash_moreEarly, totalReplay); BEAST_EXPECT(net.client.waitAndCheckStatus( finalHash_moreEarly, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); // deltaStatuses no change - BEAST_EXPECT( - net.client.waitForLedgers(finalHash_moreEarly, totalReplay)); - BEAST_EXPECT( - net.client.countsAsExpected(4, 3, 2 * (totalReplay - 1) + 2)); + BEAST_EXPECT(net.client.waitForLedgers(finalHash_moreEarly, totalReplay)); + BEAST_EXPECT(net.client.countsAsExpected(4, 3, 2 * (totalReplay - 1) + 2)); // cover - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3); - deltaStatuses = - std::vector(totalReplay * 3 - 1, TaskStatus::Completed); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3); + deltaStatuses = std::vector(totalReplay * 3 - 1, TaskStatus::Completed); BEAST_EXPECT(net.client.waitAndCheckStatus( finalHash, totalReplay * 3, @@ -1498,17 +1346,12 @@ struct LedgerReplayerTimeout_test : public beast::unit_test::suite PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + uint256 finalHash = l->header().hash; + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); std::vector deltaStatuses; BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Failed, - TaskStatus::Failed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses)); // sweep BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0)); @@ -1529,20 +1372,14 @@ struct LedgerReplayerTimeout_test : public beast::unit_test::suite PeerFeature::LedgerReplayEnabled); auto l = net.server.ledgerMaster.getClosedLedger(); - uint256 finalHash = l->info().hash; + uint256 finalHash = l->header().hash; net.client.ledgerMaster.storeLedger(l); - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finalHash, totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Failed); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Failed); deltaStatuses.back() = TaskStatus::Completed; // in client ledgerMaster BEAST_EXPECT(net.client.waitAndCheckStatus( - finalHash, - totalReplay, - TaskStatus::Failed, - TaskStatus::Completed, - deltaStatuses)); + finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Completed, deltaStatuses)); // sweep BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1)); @@ -1577,37 +1414,28 @@ struct LedgerReplayerLong_test : public beast::unit_test::suite auto l = net.server.ledgerMaster.getClosedLedger(); for (int i = 0; i < rounds; ++i) { - finishHashes.push_back(l->info().hash); + finishHashes.push_back(l->header().hash); for (int j = 0; j < totalReplay; ++j) { - l = net.server.ledgerMaster.getLedgerByHash( - l->info().parentHash); + l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); } } BEAST_EXPECT(finishHashes.size() == rounds); for (int i = 0; i < rounds; ++i) { - net.client.replayer.replay( - InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay); + net.client.replayer.replay(InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay); } - std::vector deltaStatuses( - totalReplay - 1, TaskStatus::Completed); + std::vector deltaStatuses(totalReplay - 1, TaskStatus::Completed); for (int i = 0; i < rounds; ++i) { BEAST_EXPECT(net.client.waitAndCheckStatus( - finishHashes[i], - totalReplay, - TaskStatus::Completed, - TaskStatus::Completed, - deltaStatuses)); + finishHashes[i], totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); } - BEAST_EXPECT( - net.client.waitForLedgers(finishHashes[0], totalReplay * rounds)); - BEAST_EXPECT(net.client.countsAsExpected( - rounds, rounds, rounds * (totalReplay - 1))); + BEAST_EXPECT(net.client.waitForLedgers(finishHashes[0], totalReplay * rounds)); + BEAST_EXPECT(net.client.countsAsExpected(rounds, rounds, rounds * (totalReplay - 1))); // sweep net.client.replayer.sweep(); @@ -1615,10 +1443,10 @@ struct LedgerReplayerLong_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerReplay, app, ripple); -BEAST_DEFINE_TESTSUITE_PRIO(LedgerReplayer, app, ripple, 1); -BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, ripple); -BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, ripple); +BEAST_DEFINE_TESTSUITE(LedgerReplay, app, xrpl); +BEAST_DEFINE_TESTSUITE_PRIO(LedgerReplayer, app, xrpl, 1); +BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, xrpl); +BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LendingHelpers_test.cpp b/src/test/app/LendingHelpers_test.cpp new file mode 100644 index 0000000000..58e4c5aaa4 --- /dev/null +++ b/src/test/app/LendingHelpers_test.cpp @@ -0,0 +1,1138 @@ +#include +// DO NOT REMOVE +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace xrpl { +namespace test { + +class LendingHelpers_test : public beast::unit_test::suite +{ + void + testComputeRaisedRate() + { + using namespace jtx; + using namespace xrpl::detail; + struct TestCase + { + std::string name; + Number periodicRate; + std::uint32_t paymentsRemaining; + Number expectedRaisedRate; + }; + + auto const testCases = std::vector{ + { + .name = "Zero payments remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 0, + .expectedRaisedRate = Number{1}, // (1 + r)^0 = 1 + }, + { + .name = "One payment remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 1, + .expectedRaisedRate = Number{105, -2}, + }, // 1.05^1 + { + .name = "Multiple payments remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 3, + .expectedRaisedRate = Number{1157625, -6}, + }, // 1.05^3 + { + .name = "Zero periodic rate", + .periodicRate = Number{0}, + .paymentsRemaining = 5, + .expectedRaisedRate = Number{1}, // (1 + 0)^5 = 1 + }}; + + for (auto const& tc : testCases) + { + testcase("computeRaisedRate: " + tc.name); + + auto const computedRaisedRate = computeRaisedRate(tc.periodicRate, tc.paymentsRemaining); + BEAST_EXPECTS( + computedRaisedRate == tc.expectedRaisedRate, + "Raised rate mismatch: expected " + to_string(tc.expectedRaisedRate) + ", got " + + to_string(computedRaisedRate)); + } + } + + void + testComputePaymentFactor() + { + using namespace jtx; + using namespace xrpl::detail; + struct TestCase + { + std::string name; + Number periodicRate; + std::uint32_t paymentsRemaining; + Number expectedPaymentFactor; + }; + + auto const testCases = std::vector{ + { + .name = "Zero periodic rate", + .periodicRate = Number{0}, + .paymentsRemaining = 4, + .expectedPaymentFactor = Number{25, -2}, + }, // 1/4 = 0.25 + { + .name = "One payment remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 1, + .expectedPaymentFactor = Number{105, -2}, + }, // 0.05/1 = 1.05 + { + .name = "Multiple payments remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 3, + .expectedPaymentFactor = Number{3672085646312450436, -19}, + }, // from calc + { + .name = "Zero payments remaining", + .periodicRate = Number{5, -2}, + .paymentsRemaining = 0, + .expectedPaymentFactor = Number{0}, + } // edge case + }; + + for (auto const& tc : testCases) + { + testcase("computePaymentFactor: " + tc.name); + + auto const computedPaymentFactor = computePaymentFactor(tc.periodicRate, tc.paymentsRemaining); + BEAST_EXPECTS( + computedPaymentFactor == tc.expectedPaymentFactor, + "Payment factor mismatch: expected " + to_string(tc.expectedPaymentFactor) + ", got " + + to_string(computedPaymentFactor)); + } + } + + void + testLoanPeriodicPayment() + { + using namespace jtx; + using namespace xrpl::detail; + + struct TestCase + { + std::string name; + Number principalOutstanding; + Number periodicRate; + std::uint32_t paymentsRemaining; + Number expectedPeriodicPayment; + }; + + auto const testCases = std::vector{ + { + .name = "Zero principal outstanding", + .principalOutstanding = Number{0}, + .periodicRate = Number{5, -2}, + .paymentsRemaining = 5, + .expectedPeriodicPayment = Number{0}, + }, + { + .name = "Zero payments remaining", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .paymentsRemaining = 0, + .expectedPeriodicPayment = Number{0}, + }, + { + .name = "Zero periodic rate", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{0}, + .paymentsRemaining = 4, + .expectedPeriodicPayment = Number{250}, + }, + { + .name = "Standard case", + .principalOutstanding = Number{1'000}, + .periodicRate = loanPeriodicRate(TenthBips32(100'000), 30 * 24 * 60 * 60), + .paymentsRemaining = 3, + .expectedPeriodicPayment = Number{389569066396123265, -15}, // from calc + }, + }; + + for (auto const& tc : testCases) + { + testcase("loanPeriodicPayment: " + tc.name); + + auto const computedPeriodicPayment = + loanPeriodicPayment(tc.principalOutstanding, tc.periodicRate, tc.paymentsRemaining); + BEAST_EXPECTS( + computedPeriodicPayment == tc.expectedPeriodicPayment, + "Periodic payment mismatch: expected " + to_string(tc.expectedPeriodicPayment) + ", got " + + to_string(computedPeriodicPayment)); + } + } + + void + testLoanPrincipalFromPeriodicPayment() + { + using namespace jtx; + using namespace xrpl::detail; + + struct TestCase + { + std::string name; + Number periodicPayment; + Number periodicRate; + std::uint32_t paymentsRemaining; + Number expectedPrincipalOutstanding; + }; + + auto const testCases = std::vector{ + { + .name = "Zero periodic payment", + .periodicPayment = Number{0}, + .periodicRate = Number{5, -2}, + .paymentsRemaining = 5, + .expectedPrincipalOutstanding = Number{0}, + }, + { + .name = "Zero payments remaining", + .periodicPayment = Number{1'000}, + .periodicRate = Number{5, -2}, + .paymentsRemaining = 0, + .expectedPrincipalOutstanding = Number{0}, + }, + { + .name = "Zero periodic rate", + .periodicPayment = Number{250}, + .periodicRate = Number{0}, + .paymentsRemaining = 4, + .expectedPrincipalOutstanding = Number{1'000}, + }, + { + .name = "Standard case", + .periodicPayment = Number{389569066396123265, -15}, // from calc + .periodicRate = loanPeriodicRate(TenthBips32(100'000), 30 * 24 * 60 * 60), + .paymentsRemaining = 3, + .expectedPrincipalOutstanding = Number{1'000}, + }, + }; + + for (auto const& tc : testCases) + { + testcase("loanPrincipalFromPeriodicPayment: " + tc.name); + + auto const computedPrincipalOutstanding = + loanPrincipalFromPeriodicPayment(tc.periodicPayment, tc.periodicRate, tc.paymentsRemaining); + BEAST_EXPECTS( + computedPrincipalOutstanding == tc.expectedPrincipalOutstanding, + "Principal outstanding mismatch: expected " + to_string(tc.expectedPrincipalOutstanding) + ", got " + + to_string(computedPrincipalOutstanding)); + } + } + + void + testComputeOverpaymentComponents() + { + testcase("computeOverpaymentComponents"); + using namespace jtx; + using namespace xrpl::detail; + + Account const issuer{"issuer"}; + PrettyAsset const IOU = issuer["IOU"]; + int32_t const loanScale = 1; + auto const overpayment = Number{1'000}; + auto const overpaymentInterestRate = TenthBips32{10'000}; // 10% + auto const overpaymentFeeRate = TenthBips32{50'000}; // 50% + auto const managementFeeRate = TenthBips16{10'000}; // 10% + + auto const expectedOverpaymentFee = Number{500}; // 50% of 1,000 + auto const expectedOverpaymentInterestGross = Number{100}; // 10% of 1,000 + auto const expectedOverpaymentInterestNet = Number{90}; // 100 - 10% of 100 + auto const expectedOverpaymentManagementFee = Number{10}; // 10% of 100 + auto const expectedPrincipalPortion = Number{400}; // 1,000 - 100 - 500 + + auto const components = detail::computeOverpaymentComponents( + IOU, loanScale, overpayment, overpaymentInterestRate, overpaymentFeeRate, managementFeeRate); + + BEAST_EXPECT(components.untrackedManagementFee == expectedOverpaymentFee); + + BEAST_EXPECT(components.untrackedInterest == expectedOverpaymentInterestNet); + + BEAST_EXPECT(components.trackedInterestPart() == expectedOverpaymentInterestNet); + + BEAST_EXPECT(components.trackedManagementFeeDelta == expectedOverpaymentManagementFee); + BEAST_EXPECT(components.trackedPrincipalDelta == expectedPrincipalPortion); + BEAST_EXPECT( + components.trackedManagementFeeDelta + components.untrackedInterest == expectedOverpaymentInterestGross); + + BEAST_EXPECT( + components.trackedManagementFeeDelta + components.untrackedInterest + components.trackedPrincipalDelta + + components.untrackedManagementFee == + overpayment); + } + + void + testComputeInterestAndFeeParts() + { + using namespace jtx; + using namespace xrpl::detail; + + struct TestCase + { + std::string name; + Number interest; + TenthBips16 managementFeeRate; + Number expectedInterestPart; + Number expectedFeePart; + }; + + Account const issuer{"issuer"}; + PrettyAsset const IOU = issuer["IOU"]; + std::int32_t const loanScale = 1; + + auto const testCases = std::vector{ + {.name = "Zero interest", + .interest = Number{0}, + .managementFeeRate = TenthBips16{10'000}, + .expectedInterestPart = Number{0}, + .expectedFeePart = Number{0}}, + {.name = "Zero fee rate", + .interest = Number{1'000}, + .managementFeeRate = TenthBips16{0}, + .expectedInterestPart = Number{1'000}, + .expectedFeePart = Number{0}}, + {.name = "10% fee rate", + .interest = Number{1'000}, + .managementFeeRate = TenthBips16{10'000}, + .expectedInterestPart = Number{900}, + .expectedFeePart = Number{100}}, + }; + + for (auto const& tc : testCases) + { + testcase("computeInterestAndFeeParts: " + tc.name); + + auto const [computedInterestPart, computedFeePart] = + computeInterestAndFeeParts(IOU, tc.interest, tc.managementFeeRate, loanScale); + BEAST_EXPECTS( + computedInterestPart == tc.expectedInterestPart, + "Interest part mismatch: expected " + to_string(tc.expectedInterestPart) + ", got " + + to_string(computedInterestPart)); + BEAST_EXPECTS( + computedFeePart == tc.expectedFeePart, + "Fee part mismatch: expected " + to_string(tc.expectedFeePart) + ", got " + to_string(computedFeePart)); + } + } + + void + testLoanLatePaymentInterest() + { + using namespace jtx; + using namespace xrpl::detail; + struct TestCase + { + std::string name; + Number principalOutstanding; + TenthBips32 lateInterestRate; + NetClock::time_point parentCloseTime; + std::uint32_t nextPaymentDueDate; + Number expectedLateInterest; + }; + + auto const testCases = std::vector{ + { + .name = "On-time payment", + .principalOutstanding = Number{1'000}, + .lateInterestRate = TenthBips32{10'000}, // 10% + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .nextPaymentDueDate = 3'000, + .expectedLateInterest = Number{0}, + }, + { + .name = "Early payment", + .principalOutstanding = Number{1'000}, + .lateInterestRate = TenthBips32{10'000}, // 10% + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .nextPaymentDueDate = 4'000, + .expectedLateInterest = Number{0}, + }, + { + .name = "No principal outstanding", + .principalOutstanding = Number{0}, + .lateInterestRate = TenthBips32{10'000}, // 10% + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .nextPaymentDueDate = 2'000, + .expectedLateInterest = Number{0}, + }, + { + .name = "No late interest rate", + .principalOutstanding = Number{1'000}, + .lateInterestRate = TenthBips32{0}, // 0% + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .nextPaymentDueDate = 2'000, + .expectedLateInterest = Number{0}, + }, + { + .name = "Late payment", + .principalOutstanding = Number{1'000}, + .lateInterestRate = TenthBips32{100'000}, // 100% + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .nextPaymentDueDate = 2'000, + .expectedLateInterest = Number{317097919837645865, -19}, // from calc + }, + }; + + for (auto const& tc : testCases) + { + testcase("loanLatePaymentInterest: " + tc.name); + + auto const computedLateInterest = loanLatePaymentInterest( + tc.principalOutstanding, tc.lateInterestRate, tc.parentCloseTime, tc.nextPaymentDueDate); + BEAST_EXPECTS( + computedLateInterest == tc.expectedLateInterest, + "Late interest mismatch: expected " + to_string(tc.expectedLateInterest) + ", got " + + to_string(computedLateInterest)); + } + } + + void + testLoanAccruedInterest() + { + using namespace jtx; + using namespace xrpl::detail; + struct TestCase + { + std::string name; + Number principalOutstanding; + Number periodicRate; + NetClock::time_point parentCloseTime; + std::uint32_t startDate; + std::uint32_t prevPaymentDate; + std::uint32_t paymentInterval; + Number expectedAccruedInterest; + }; + + auto const testCases = std::vector{ + { + .name = "Zero principal outstanding", + .principalOutstanding = Number{0}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .startDate = 2'000, + .prevPaymentDate = 2'500, + .paymentInterval = 30 * 24 * 60 * 60, + .expectedAccruedInterest = Number{0}, + }, + { + .name = "Before start date", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{1'000}}, + .startDate = 2'000, + .prevPaymentDate = 1'500, + .paymentInterval = 30 * 24 * 60 * 60, + .expectedAccruedInterest = Number{0}, + }, + { + .name = "Zero periodic rate", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{0}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .startDate = 2'000, + .prevPaymentDate = 2'500, + .paymentInterval = 30 * 24 * 60 * 60, + .expectedAccruedInterest = Number{0}, + }, + { + .name = "Zero payment interval", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .startDate = 2'000, + .prevPaymentDate = 2'500, + .paymentInterval = 0, + .expectedAccruedInterest = Number{0}, + }, + { + .name = "Standard case", + .principalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .startDate = 1'000, + .prevPaymentDate = 2'000, + .paymentInterval = 30 * 24 * 60 * 60, + .expectedAccruedInterest = Number{1929012345679012346, -20}, // from calc + }, + }; + + for (auto const& tc : testCases) + { + testcase("loanAccruedInterest: " + tc.name); + + auto const computedAccruedInterest = loanAccruedInterest( + tc.principalOutstanding, + tc.periodicRate, + tc.parentCloseTime, + tc.startDate, + tc.prevPaymentDate, + tc.paymentInterval); + BEAST_EXPECTS( + computedAccruedInterest == tc.expectedAccruedInterest, + "Accrued interest mismatch: expected " + to_string(tc.expectedAccruedInterest) + ", got " + + to_string(computedAccruedInterest)); + } + } + + // This test overlaps with testLoanAccruedInterest, the test cases only + // exercise the computeFullPaymentInterest parts unique to it. + void + testComputeFullPaymentInterest() + { + using namespace jtx; + using namespace xrpl::detail; + + struct TestCase + { + std::string name; + Number rawPrincipalOutstanding; + Number periodicRate; + NetClock::time_point parentCloseTime; + std::uint32_t paymentInterval; + std::uint32_t prevPaymentDate; + std::uint32_t startDate; + TenthBips32 closeInterestRate; + Number expectedFullPaymentInterest; + }; + + auto const testCases = std::vector{ + { + .name = "Zero principal outstanding", + .rawPrincipalOutstanding = Number{0}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .paymentInterval = 30 * 24 * 60 * 60, + .prevPaymentDate = 2'000, + .startDate = 1'000, + .closeInterestRate = TenthBips32{10'000}, + .expectedFullPaymentInterest = Number{0}, + }, + { + .name = "Zero close interest rate", + .rawPrincipalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .paymentInterval = 30 * 24 * 60 * 60, + .prevPaymentDate = 2'000, + .startDate = 1'000, + .closeInterestRate = TenthBips32{0}, + .expectedFullPaymentInterest = Number{1929012345679012346, -20}, // from calc + }, + { + .name = "Standard case", + .rawPrincipalOutstanding = Number{1'000}, + .periodicRate = Number{5, -2}, + .parentCloseTime = NetClock::time_point{NetClock::duration{3'000}}, + .paymentInterval = 30 * 24 * 60 * 60, + .prevPaymentDate = 2'000, + .startDate = 1'000, + .closeInterestRate = TenthBips32{10'000}, + .expectedFullPaymentInterest = Number{1000192901234567901, -16}, // from calc + }, + }; + + for (auto const& tc : testCases) + { + testcase("computeFullPaymentInterest: " + tc.name); + + auto const computedFullPaymentInterest = computeFullPaymentInterest( + tc.rawPrincipalOutstanding, + tc.periodicRate, + tc.parentCloseTime, + tc.paymentInterval, + tc.prevPaymentDate, + tc.startDate, + tc.closeInterestRate); + BEAST_EXPECTS( + computedFullPaymentInterest == tc.expectedFullPaymentInterest, + "Full payment interest mismatch: expected " + to_string(tc.expectedFullPaymentInterest) + ", got " + + to_string(computedFullPaymentInterest)); + } + } + + void + testTryOverpaymentNoInterestNoFee() + { + // This test ensures that overpayment with no interest works correctly. + testcase("tryOverpayment - No Interest No Fee"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{0}; // 0% + TenthBips32 const loanInterestRate{0}; // 0% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + Number const overpaymentAmount{50}; + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, loanScale, overpaymentAmount, TenthBips32(0), TenthBips32(0), managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + BEAST_EXPECTS( + actualPaymentParts.valueChange == 0, + " valueChange mismatch: expected 0, got " + to_string(actualPaymentParts.valueChange)); + + BEAST_EXPECTS( + actualPaymentParts.feePaid == 0, + " feePaid mismatch: expected 0, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.interestPaid == 0, + " interestPaid mismatch: expected 0, got " + to_string(actualPaymentParts.interestPaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == overpaymentAmount, + " principalPaid mismatch: expected " + to_string(overpaymentAmount) + ", got " + + to_string(actualPaymentParts.principalPaid)); + + // =========== VALIDATE STATE CHANGES =========== + BEAST_EXPECTS( + loanProperties.loanState.interestDue - newState.interestDue == 0, + " interest change mismatch: expected 0, got " + + to_string(loanProperties.loanState.interestDue - newState.interestDue)); + + BEAST_EXPECTS( + loanProperties.loanState.managementFeeDue - newState.managementFeeDue == 0, + " management fee change mismatch: expected 0, got " + + to_string(loanProperties.loanState.managementFeeDue - newState.managementFeeDue)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + } + + void + testTryOverpaymentNoInterestOverpaymentFee() + { + testcase("tryOverpayment - No Interest With Overpayment Fee"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{0}; // 0% + TenthBips32 const loanInterestRate{0}; // 0% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, + loanScale, + Number{50, 0}, + TenthBips32(0), + TenthBips32(10'000), // 10% overpayment fee + managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + BEAST_EXPECTS( + actualPaymentParts.valueChange == 0, + " valueChange mismatch: expected 0, got " + to_string(actualPaymentParts.valueChange)); + + BEAST_EXPECTS( + actualPaymentParts.feePaid == 5, + " feePaid mismatch: expected 5, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == 45, + " principalPaid mismatch: expected 45, got `" + to_string(actualPaymentParts.principalPaid)); + + BEAST_EXPECTS( + actualPaymentParts.interestPaid == 0, + " interestPaid mismatch: expected 0, got " + to_string(actualPaymentParts.interestPaid)); + + // =========== VALIDATE STATE CHANGES =========== + // With no Loan interest, interest outstanding should not change + BEAST_EXPECTS( + loanProperties.loanState.interestDue - newState.interestDue == 0, + " interest change mismatch: expected 0, got " + + to_string(loanProperties.loanState.interestDue - newState.interestDue)); + + // With no Loan management fee, management fee due should not change + BEAST_EXPECTS( + loanProperties.loanState.managementFeeDue - newState.managementFeeDue == 0, + " management fee change mismatch: expected 0, got " + + to_string(loanProperties.loanState.managementFeeDue - newState.managementFeeDue)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + } + + void + testTryOverpaymentLoanInterestNoOverpaymentFees() + { + testcase("tryOverpayment - Loan Interest, No Overpayment Fees"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{0}; // 0% + TenthBips32 const loanInterestRate{10'000}; // 10% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, + loanScale, + Number{50, 0}, + TenthBips32(0), // no overpayment interest + TenthBips32(0), // 0% overpayment fee + managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + // with no overpayment interest portion, value change should equal + // interest decrease + BEAST_EXPECTS( + (actualPaymentParts.valueChange == Number{-228802, -5}), + " valueChange mismatch: expected " + to_string(Number{-228802, -5}) + ", got " + + to_string(actualPaymentParts.valueChange)); + + // with no fee portion, fee paid should be zero + BEAST_EXPECTS( + actualPaymentParts.feePaid == 0, + " feePaid mismatch: expected 0, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == 50, + " principalPaid mismatch: expected 50, got `" + to_string(actualPaymentParts.principalPaid)); + + // with no interest portion, interest paid should be zero + BEAST_EXPECTS( + actualPaymentParts.interestPaid == 0, + " interestPaid mismatch: expected 0, got " + to_string(actualPaymentParts.interestPaid)); + + // =========== VALIDATE STATE CHANGES =========== + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + + BEAST_EXPECTS( + actualPaymentParts.valueChange == newState.interestDue - loanProperties.loanState.interestDue, + " valueChange mismatch: expected " + + to_string(newState.interestDue - loanProperties.loanState.interestDue) + ", got " + + to_string(actualPaymentParts.valueChange)); + + // With no Loan management fee, management fee due should not change + BEAST_EXPECTS( + loanProperties.loanState.managementFeeDue - newState.managementFeeDue == 0, + " management fee change mismatch: expected 0, got " + + to_string(loanProperties.loanState.managementFeeDue - newState.managementFeeDue)); + } + + void + testTryOverpaymentLoanInterestOverpaymentInterest() + { + testcase("tryOverpayment - Loan Interest, Overpayment Interest, No Fee"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{0}; // 0% + TenthBips32 const loanInterestRate{10'000}; // 10% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, + loanScale, + Number{50, 0}, + TenthBips32(10'000), // 10% overpayment interest + TenthBips32(0), // 0% overpayment fee + managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + // with overpayment interest portion, interest paid should be 5 + BEAST_EXPECTS( + actualPaymentParts.interestPaid == 5, + " interestPaid mismatch: expected 5, got " + to_string(actualPaymentParts.interestPaid)); + + // With overpayment interest portion, value change should equal the + // interest decrease plus overpayment interest portion + BEAST_EXPECTS( + (actualPaymentParts.valueChange == Number{-205922, -5} + actualPaymentParts.interestPaid), + " valueChange mismatch: expected " + + to_string(actualPaymentParts.valueChange - actualPaymentParts.interestPaid) + ", got " + + to_string(actualPaymentParts.valueChange)); + + // with no fee portion, fee paid should be zero + BEAST_EXPECTS( + actualPaymentParts.feePaid == 0, + " feePaid mismatch: expected 0, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == 45, + " principalPaid mismatch: expected 45, got `" + to_string(actualPaymentParts.principalPaid)); + + // =========== VALIDATE STATE CHANGES =========== + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + + // The change in interest is equal to the value change sans the + // overpayment interest + BEAST_EXPECTS( + actualPaymentParts.valueChange - actualPaymentParts.interestPaid == + newState.interestDue - loanProperties.loanState.interestDue, + " valueChange mismatch: expected " + + to_string( + newState.interestDue - loanProperties.loanState.interestDue + actualPaymentParts.interestPaid) + + ", got " + to_string(actualPaymentParts.valueChange)); + + // With no Loan management fee, management fee due should not change + BEAST_EXPECTS( + loanProperties.loanState.managementFeeDue - newState.managementFeeDue == 0, + " management fee change mismatch: expected 0, got " + + to_string(loanProperties.loanState.managementFeeDue - newState.managementFeeDue)); + } + + void + testTryOverpaymentLoanInterestFeeOverpaymentInterestNoFee() + { + testcase( + "tryOverpayment - Loan Interest and Fee, Overpayment Interest, No " + "Fee"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{10'000}; // 10% + TenthBips32 const loanInterestRate{10'000}; // 10% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, + loanScale, + Number{50, 0}, + TenthBips32(10'000), // 10% overpayment interest + TenthBips32(0), // 0% overpayment fee + managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + + // Since there is loan management fee, the fee is charged against + // overpayment interest portion first, so interest paid remains 4.5 + BEAST_EXPECTS( + (actualPaymentParts.interestPaid == Number{45, -1}), + " interestPaid mismatch: expected 4.5, got " + to_string(actualPaymentParts.interestPaid)); + + // With overpayment interest portion, value change should equal the + // interest decrease plus overpayment interest portion + BEAST_EXPECTS( + (actualPaymentParts.valueChange == Number{-18533, -4} + actualPaymentParts.interestPaid), + " valueChange mismatch: expected " + to_string(Number{-18533, -4} + actualPaymentParts.interestPaid) + + ", got " + to_string(actualPaymentParts.valueChange)); + + // While there is no overpayment fee, fee paid should equal the + // management fee charged against the overpayment interest portion + BEAST_EXPECTS( + (actualPaymentParts.feePaid == Number{5, -1}), + " feePaid mismatch: expected 0.5, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == 45, + " principalPaid mismatch: expected 45, got `" + to_string(actualPaymentParts.principalPaid)); + + // =========== VALIDATE STATE CHANGES =========== + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + + // Note that the management fee value change is not captured, as this + // value is not needed to correctly update the Vault state. + BEAST_EXPECTS( + (newState.managementFeeDue - loanProperties.loanState.managementFeeDue == Number{-20592, -5}), + " management fee change mismatch: expected " + to_string(Number{-20592, -5}) + ", got " + + to_string(newState.managementFeeDue - loanProperties.loanState.managementFeeDue)); + + BEAST_EXPECTS( + actualPaymentParts.valueChange - actualPaymentParts.interestPaid == + newState.interestDue - loanProperties.loanState.interestDue, + " valueChange mismatch: expected " + + to_string(newState.interestDue - loanProperties.loanState.interestDue) + ", got " + + to_string(actualPaymentParts.valueChange - actualPaymentParts.interestPaid)); + } + + void + testTryOverpaymentLoanInterestFeeOverpaymentInterestFee() + { + testcase("tryOverpayment - Loan Interest, Fee, Overpayment Interest, Fee"); + + using namespace jtx; + using namespace xrpl::detail; + + Env env{*this}; + Account const issuer{"issuer"}; + PrettyAsset const asset = issuer["USD"]; + std::int32_t const loanScale = -5; + TenthBips16 const managementFeeRate{10'000}; // 10% + TenthBips32 const loanInterestRate{10'000}; // 10% + Number const loanPrincipal{1'000}; + std::uint32_t const paymentInterval = 30 * 24 * 60 * 60; + std::uint32_t const paymentsRemaining = 10; + auto const periodicRate = loanPeriodicRate(loanInterestRate, paymentInterval); + + auto const overpaymentComponents = computeOverpaymentComponents( + asset, + loanScale, + Number{50, 0}, + TenthBips32(10'000), // 10% overpayment interest + TenthBips32(10'000), // 10% overpayment fee + managementFeeRate); + + auto const loanProperties = computeLoanProperties( + asset, loanPrincipal, loanInterestRate, paymentInterval, paymentsRemaining, managementFeeRate, loanScale); + + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanProperties.loanState, + loanProperties.periodicPayment, + periodicRate, + paymentsRemaining, + managementFeeRate, + env.journal); + + BEAST_EXPECT(ret); + + auto const& [actualPaymentParts, newLoanProperties] = *ret; + auto const& newState = newLoanProperties.loanState; + + // =========== VALIDATE PAYMENT PARTS =========== + + // Since there is loan management fee, the fee is charged against + // overpayment interest portion first, so interest paid remains 4.5 + BEAST_EXPECTS( + (actualPaymentParts.interestPaid == Number{45, -1}), + " interestPaid mismatch: expected 4.5, got " + to_string(actualPaymentParts.interestPaid)); + + // With overpayment interest portion, value change should equal the + // interest decrease plus overpayment interest portion + BEAST_EXPECTS( + (actualPaymentParts.valueChange == Number{-164737, -5} + actualPaymentParts.interestPaid), + " valueChange mismatch: expected " + to_string(Number{-164737, -5} + actualPaymentParts.interestPaid) + + ", got " + to_string(actualPaymentParts.valueChange)); + + // While there is no overpayment fee, fee paid should equal the + // management fee charged against the overpayment interest portion + BEAST_EXPECTS( + (actualPaymentParts.feePaid == Number{55, -1}), + " feePaid mismatch: expected 5.5, got " + to_string(actualPaymentParts.feePaid)); + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == 40, + " principalPaid mismatch: expected 40, got `" + to_string(actualPaymentParts.principalPaid)); + + // =========== VALIDATE STATE CHANGES =========== + + BEAST_EXPECTS( + actualPaymentParts.principalPaid == + loanProperties.loanState.principalOutstanding - newState.principalOutstanding, + " principalPaid mismatch: expected " + + to_string(loanProperties.loanState.principalOutstanding - newState.principalOutstanding) + ", got " + + to_string(actualPaymentParts.principalPaid)); + + // Note that the management fee value change is not captured, as this + // value is not needed to correctly update the Vault state. + BEAST_EXPECTS( + (newState.managementFeeDue - loanProperties.loanState.managementFeeDue == Number{-18304, -5}), + " management fee change mismatch: expected " + to_string(Number{-18304, -5}) + ", got " + + to_string(newState.managementFeeDue - loanProperties.loanState.managementFeeDue)); + + BEAST_EXPECTS( + actualPaymentParts.valueChange - actualPaymentParts.interestPaid == + newState.interestDue - loanProperties.loanState.interestDue, + " valueChange mismatch: expected " + + to_string(newState.interestDue - loanProperties.loanState.interestDue) + ", got " + + to_string(actualPaymentParts.valueChange - actualPaymentParts.interestPaid)); + } + +public: + void + run() override + { + testTryOverpaymentNoInterestNoFee(); + testTryOverpaymentNoInterestOverpaymentFee(); + testTryOverpaymentLoanInterestNoOverpaymentFees(); + testTryOverpaymentLoanInterestOverpaymentInterest(); + testTryOverpaymentLoanInterestFeeOverpaymentInterestNoFee(); + testTryOverpaymentLoanInterestFeeOverpaymentInterestFee(); + + testComputeFullPaymentInterest(); + testLoanAccruedInterest(); + testLoanLatePaymentInterest(); + testLoanPeriodicPayment(); + testLoanPrincipalFromPeriodicPayment(); + testComputeRaisedRate(); + testComputePaymentFactor(); + testComputeOverpaymentComponents(); + testComputeInterestAndFeeParts(); + } +}; + +BEAST_DEFINE_TESTSUITE(LendingHelpers, app, xrpl); + +} // namespace test +} // namespace xrpl diff --git a/src/test/app/LoadFeeTrack_test.cpp b/src/test/app/LoadFeeTrack_test.cpp index 80110b073d..61174fc9e9 100644 --- a/src/test/app/LoadFeeTrack_test.cpp +++ b/src/test/app/LoadFeeTrack_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { class LoadFeeTrack_test : public beast::unit_test::suite { @@ -42,13 +23,9 @@ public: return f; }(); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{10000}, l, fees, false) == - XRPAmount{10000}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{10000}, l, fees, false) == XRPAmount{10000}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); } { Fees const fees = [&]() { @@ -59,13 +36,9 @@ public: return f; }(); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{10000}, l, fees, false) == - XRPAmount{10000}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{10000}, l, fees, false) == XRPAmount{10000}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); } { Fees const fees = [&]() { @@ -76,17 +49,13 @@ public: return f; }(); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{10000}, l, fees, false) == - XRPAmount{10000}); - BEAST_EXPECT( - scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{0}, l, fees, false) == XRPAmount{0}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{10000}, l, fees, false) == XRPAmount{10000}); + BEAST_EXPECT(scaleFeeLoad(XRPAmount{1}, l, fees, false) == XRPAmount{1}); } } }; -BEAST_DEFINE_TESTSUITE(LoadFeeTrack, app, ripple); +BEAST_DEFINE_TESTSUITE(LoadFeeTrack, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/LoanBroker_test.cpp b/src/test/app/LoanBroker_test.cpp new file mode 100644 index 0000000000..58052e3fb1 --- /dev/null +++ b/src/test/app/LoanBroker_test.cpp @@ -0,0 +1,1733 @@ +#include + +#include + +#include + +namespace xrpl { +namespace test { + +class LoanBroker_test : public beast::unit_test::suite +{ + // Ensure that all the features needed for Lending Protocol are included, + // even if they are set to unsupported. + FeatureBitset const all{ + jtx::testable_amendments() | featureMPTokensV1 | featureSingleAssetVault | featureLendingProtocol}; + + void + testDisabled() + { + testcase("Disabled"); + // Lending Protocol depends on Single Asset Vault (SAV). Test + // combinations of the two amendments. + // Single Asset Vault depends on MPTokensV1, but don't test every combo + // of that. + using namespace jtx; + auto failAll = [this](FeatureBitset features, bool goodVault = false) { + Env env(*this, features); + + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + + // Try to create a vault + PrettyAsset const asset{xrpIssue(), 1'000'000}; + Vault vault{env}; + auto const [tx, keylet] = vault.create({.owner = alice, .asset = asset}); + env(tx, ter(goodVault ? ter(tesSUCCESS) : ter(temDISABLED))); + env.close(); + BEAST_EXPECT(static_cast(env.le(keylet)) == goodVault); + + using namespace loanBroker; + // Can't create a loan broker regardless of whether the vault exists + env(set(alice, keylet.key), ter(temDISABLED)); + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + // Other LoanBroker transactions are disabled, too. + // 1. LoanBrokerCoverDeposit + env(coverDeposit(alice, brokerKeylet.key, asset(1000)), ter(temDISABLED)); + // 2. LoanBrokerCoverWithdraw + env(coverWithdraw(alice, brokerKeylet.key, asset(1000)), ter(temDISABLED)); + // 3. LoanBrokerCoverClawback + env(coverClawback(alice), ter(temDISABLED)); + env(coverClawback(alice), loanBrokerID(brokerKeylet.key), ter(temDISABLED)); + env(coverClawback(alice), amount(asset(0)), ter(temDISABLED)); + env(coverClawback(alice), loanBrokerID(brokerKeylet.key), amount(asset(1000)), ter(temDISABLED)); + // 4. LoanBrokerDelete + env(del(alice, brokerKeylet.key), ter(temDISABLED)); + }; + failAll(all - featureMPTokensV1); + failAll(all - featureSingleAssetVault - featureLendingProtocol); + failAll(all - featureSingleAssetVault); + failAll(all - featureLendingProtocol, true); + } + + struct VaultInfo + { + jtx::PrettyAsset asset; + uint256 vaultID; + jtx::Account pseudoAccount; + VaultInfo(jtx::PrettyAsset const& asset_, uint256 const& vaultID_, AccountID const& pseudo) + : asset(asset_), vaultID(vaultID_), pseudoAccount("vault", pseudo) + { + } + }; + + void + lifecycle( + char const* label, + jtx::Env& env, + jtx::Account const& issuer, + jtx::Account const& alice, + jtx::Account const& evan, + jtx::Account const& bystander, + VaultInfo const& vault, + VaultInfo const& badVault, + std::function modifyJTx, + std::function checkBroker, + std::function changeBroker, + std::function checkChangedBroker) + { + { + auto const& asset = vault.asset.raw(); + testcase << "Lifecycle: " + << (asset.native() ? "XRP " + : asset.holds() ? "IOU " + : asset.holds() ? "MPT " + : "Unknown ") + << label; + } + + using namespace jtx; + using namespace loanBroker; + + // Bogus assets to use in test cases + static PrettyAsset const badMptAsset = [&]() { + MPTTester badMptt{env, evan, mptInitNoFund}; + badMptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + env.close(); + return badMptt["BAD"]; + }(); + static PrettyAsset const badIouAsset = evan["BAD"]; + static Account const nonExistent{"NonExistent"}; + static PrettyAsset const ghostIouAsset = nonExistent["GST"]; + PrettyAsset const vaultPseudoIouAsset = vault.pseudoAccount["PSD"]; + + auto const badKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + env(set(alice, badVault.vaultID)); + env.close(); + auto const badBrokerPseudo = [&]() { + if (auto const le = env.le(badKeylet); BEAST_EXPECT(le)) + { + return Account{"Bad Broker pseudo-account", le->at(sfAccount)}; + } + // Just to make the build work + return vault.pseudoAccount; + }(); + PrettyAsset const badBrokerPseudoIouAsset = badBrokerPseudo["WAT"]; + + auto const keylet = keylet::loanbroker(alice.id(), env.seq(alice)); + { + // Start with default values + auto jtx = env.jt(set(alice, vault.vaultID)); + // Modify as desired + if (modifyJTx) + jtx = modifyJTx(jtx); + // Successfully create a Loan Broker + env(jtx); + } + + env.close(); + if (auto broker = env.le(keylet); BEAST_EXPECT(broker)) + { + // log << "Broker after create: " << to_string(broker->getJson()) + // << std::endl; + BEAST_EXPECT(broker->at(sfVaultID) == vault.vaultID); + BEAST_EXPECT(broker->at(sfAccount) != alice.id()); + BEAST_EXPECT(broker->at(sfOwner) == alice.id()); + BEAST_EXPECT(broker->at(sfFlags) == 0); + BEAST_EXPECT(broker->at(sfSequence) == env.seq(alice) - 1); + BEAST_EXPECT(broker->at(sfOwnerCount) == 0); + BEAST_EXPECT(broker->at(sfLoanSequence) == 1); + BEAST_EXPECT(broker->at(sfDebtTotal) == 0); + BEAST_EXPECT(broker->at(sfCoverAvailable) == 0); + if (checkBroker) + checkBroker(broker); + + // if (auto const vaultSLE = env.le(keylet::vault(vault.vaultID))) + //{ + // log << "Vault: " << to_string(vaultSLE->getJson()) << + // std::endl; + // } + // Load the pseudo-account + Account const pseudoAccount{"Broker pseudo-account", broker->at(sfAccount)}; + + auto const pseudoKeylet = keylet::account(pseudoAccount); + if (auto const pseudo = env.le(pseudoKeylet); BEAST_EXPECT(pseudo)) + { + // log << "Pseudo-account after create: " + // << to_string(pseudo->getJson()) << std::endl + // << std::endl; + BEAST_EXPECT(pseudo->at(sfFlags) == (lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth)); + BEAST_EXPECT(pseudo->at(sfSequence) == 0); + BEAST_EXPECT(pseudo->at(sfBalance) == beast::zero); + BEAST_EXPECT(pseudo->at(sfOwnerCount) == (vault.asset.raw().native() ? 0 : 1)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfAccountTxnID)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfRegularKey)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfEmailHash)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfWalletLocator)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfWalletSize)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfMessageKey)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfTransferRate)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfDomain)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfTickSize)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfTicketCount)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfNFTokenMinter)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfMintedNFTokens)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfBurnedNFTokens)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfFirstNFTokenSequence)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfAMMID)); + BEAST_EXPECT(!pseudo->isFieldPresent(sfVaultID)); + BEAST_EXPECT(pseudo->at(sfLoanBrokerID) == keylet.key); + } + + { + // Get the AccountInfo RPC result for the broker pseudo-account + std::string const pseudoStr = to_string(pseudoAccount.id()); + auto const accountInfo = env.rpc("account_info", pseudoStr); + if (BEAST_EXPECT(accountInfo.isObject())) + { + auto const& accountData = accountInfo[jss::result][jss::account_data]; + if (BEAST_EXPECT(accountData.isObject())) + { + BEAST_EXPECT(accountData[jss::Account] == pseudoStr); + BEAST_EXPECT(accountData[sfLoanBrokerID] == to_string(keylet.key)); + } + auto const& pseudoInfo = accountInfo[jss::result][jss::pseudo_account]; + if (BEAST_EXPECT(pseudoInfo.isObject())) + { + BEAST_EXPECT(pseudoInfo[jss::type] == "LoanBroker"); + } + } + } + + auto verifyCoverAmount = [&env, &vault, &pseudoAccount, &broker, &keylet, this](auto n) { + using namespace jtx; + + if (BEAST_EXPECT(broker = env.le(keylet))) + { + auto const amount = vault.asset(n); + BEAST_EXPECT(broker->at(sfCoverAvailable) == amount.number()); + env.require(balance(pseudoAccount, amount)); + } + }; + + // Test Cover funding before allowing alterations + env(coverDeposit(alice, uint256(0), vault.asset(10)), ter(temINVALID)); + env(coverDeposit(evan, keylet.key, vault.asset(10)), ter(tecNO_PERMISSION)); + env(coverDeposit(evan, keylet.key, vault.asset(0)), ter(temBAD_AMOUNT)); + env(coverDeposit(evan, keylet.key, vault.asset(-10)), ter(temBAD_AMOUNT)); + env(coverDeposit(alice, vault.vaultID, vault.asset(10)), ter(tecNO_ENTRY)); + + verifyCoverAmount(0); + + // Test cover clawback failure cases BEFORE depositing any cover + // Need one of brokerID or amount + env(coverClawback(alice), ter(temINVALID)); + env(coverClawback(alice), loanBrokerID(uint256(0)), ter(temINVALID)); + env(coverClawback(alice), amount(XRP(1000)), ter(temBAD_AMOUNT)); + env(coverClawback(alice), amount(vault.asset(-10)), ter(temBAD_AMOUNT)); + // Clawbacks with an MPT need to specify the broker ID + env(coverClawback(alice), amount(badMptAsset(1)), ter(temINVALID)); + env(coverClawback(evan), loanBrokerID(vault.vaultID), ter(tecNO_ENTRY)); + // Only the issuer can clawback + env(coverClawback(alice), loanBrokerID(keylet.key), ter(tecNO_PERMISSION)); + if (vault.asset.raw().native()) + { + // Can not clawback XRP under any circumstances + env(coverClawback(issuer), loanBrokerID(keylet.key), ter(tecNO_PERMISSION)); + } + else + { + if (vault.asset.raw().holds()) + { + // Clawbacks without a loanBrokerID need to specify an IOU + // with the broker's pseudo-account as the issuer + env(coverClawback(alice), amount(ghostIouAsset(1)), ter(tecNO_ENTRY)); + env(coverClawback(alice), amount(badIouAsset(1)), ter(tecOBJECT_NOT_FOUND)); + // Pseudo-account is not for a broker + env(coverClawback(alice), amount(vaultPseudoIouAsset(1)), ter(tecOBJECT_NOT_FOUND)); + // If we specify a pseudo-account as the IOU amount, it + // needs to match the loan broker + env(coverClawback(issuer), + loanBrokerID(keylet.key), + amount(badBrokerPseudoIouAsset(10)), + ter(tecWRONG_ASSET)); + PrettyAsset const brokerWrongCurrencyAsset = pseudoAccount["WAT"]; + env(coverClawback(issuer), + loanBrokerID(keylet.key), + amount(brokerWrongCurrencyAsset(10)), + ter(tecWRONG_ASSET)); + } + else + { + // Clawbacks with an MPT need to specify the broker ID, even + // if the asset is valid + BEAST_EXPECT(vault.asset.raw().holds()); + env(coverClawback(alice), amount(vault.asset(10)), ter(temINVALID)); + } + // Since no cover has been deposited, there's nothing to claw + // back + env(coverClawback(issuer), + loanBrokerID(keylet.key), + amount(vault.asset(10)), + ter(tecINSUFFICIENT_FUNDS)); + } + env.close(); + + // Fund the cover deposit + env(coverDeposit(alice, keylet.key, vault.asset(10))); + env.close(); + verifyCoverAmount(10); + + // Test withdrawal failure cases + env(coverWithdraw(alice, uint256(0), vault.asset(10)), ter(temINVALID)); + env(coverWithdraw(evan, keylet.key, vault.asset(10)), ter(tecNO_PERMISSION)); + env(coverWithdraw(evan, keylet.key, vault.asset(0)), ter(temBAD_AMOUNT)); + env(coverWithdraw(evan, keylet.key, vault.asset(-10)), ter(temBAD_AMOUNT)); + env(coverWithdraw(alice, vault.vaultID, vault.asset(10)), ter(tecNO_ENTRY)); + env(coverWithdraw(alice, keylet.key, vault.asset(900)), ter(tecINSUFFICIENT_FUNDS)); + + // Skip this test for XRP, because that can always be sent + if (!vault.asset.raw().native()) + { + TER const expected = vault.asset.raw().holds() ? tecNO_AUTH : tecNO_LINE; + env(coverWithdraw(alice, keylet.key, vault.asset(1)), destination(bystander), ter(expected)); + } + + // Can not withdraw to the zero address + env(coverWithdraw(alice, keylet.key, vault.asset(1)), destination(AccountID{}), ter(temMALFORMED)); + + // Withdraw some of the cover amount + env(coverWithdraw(alice, keylet.key, vault.asset(7))); + env.close(); + verifyCoverAmount(3); + + // Add some more cover + env(coverDeposit(alice, keylet.key, vault.asset(5))); + env.close(); + verifyCoverAmount(8); + + // Withdraw some more. Send it to Evan. Very generous, considering + // how much trouble he's been. + env(coverWithdraw(alice, keylet.key, vault.asset(1)), destination(evan)); + env.close(); + verifyCoverAmount(7); + + // Withdraw some more. Send it to Evan. Very generous, considering + // how much trouble he's been. + env(coverWithdraw(alice, keylet.key, vault.asset(1)), destination(evan), dtag(3)); + env.close(); + verifyCoverAmount(6); + + if (!vault.asset.raw().native()) + { + // Issuer claws back some of the cover + env(coverClawback(issuer), loanBrokerID(keylet.key), amount(vault.asset(2))); + env.close(); + verifyCoverAmount(4); + + // Deposit some back + env(coverDeposit(alice, keylet.key, vault.asset(5))); + env.close(); + verifyCoverAmount(9); + + // Issuer claws it all back in various different ways + for (auto const& tx : { + // defer autofills until submission time + env.json(coverClawback(issuer), loanBrokerID(keylet.key), fee(none), seq(none), sig(none)), + env.json( + coverClawback(issuer), + loanBrokerID(keylet.key), + amount(vault.asset(0)), + fee(none), + seq(none), + sig(none)), + env.json( + coverClawback(issuer), + loanBrokerID(keylet.key), + amount(vault.asset(6)), + fee(none), + seq(none), + sig(none)), + // amount will be truncated to what's available + env.json( + coverClawback(issuer), + loanBrokerID(keylet.key), + amount(vault.asset(100)), + fee(none), + seq(none), + sig(none)), + }) + { + // Issuer claws it all back + env(tx); + env.close(); + verifyCoverAmount(0); + + // Deposit some back + env(coverDeposit(alice, keylet.key, vault.asset(6))); + env.close(); + verifyCoverAmount(6); + } + } + + // no-op + env(set(alice, vault.vaultID), loanBrokerID(keylet.key)); + env.close(); + + // Make modifications to the broker + if (changeBroker) + changeBroker(broker); + + env.close(); + + // Check the results of modifications + if (BEAST_EXPECT(broker = env.le(keylet)) && checkChangedBroker) + checkChangedBroker(broker); + + // Verify that fields get removed when set to default values + // Debt maximum: explicit 0 + // Data: explicit empty + env(set(alice, vault.vaultID), loanBrokerID(broker->key()), debtMaximum(Number(0)), data("")); + env.close(); + + // Check the updated fields + if (BEAST_EXPECT(broker = env.le(keylet))) + { + BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum)); + BEAST_EXPECT(!broker->isFieldPresent(sfData)); + } + + ///////////////////////////////////// + // try to delete the wrong broker object + env(del(alice, vault.vaultID), ter(tecNO_ENTRY)); + // evan tries to delete the broker + env(del(evan, keylet.key), ter(tecNO_PERMISSION)); + + // Get the "bad" broker out of the way + env(del(alice, badKeylet.key)); + env.close(); + + // Note alice's balance of the asset and the broker account's cover + // funds + auto const aliceBalance = env.balance(alice, vault.asset); + auto const coverFunds = env.balance(pseudoAccount, vault.asset); + BEAST_EXPECT(coverFunds.number() == broker->at(sfCoverAvailable)); + BEAST_EXPECT(coverFunds != beast::zero); + verifyCoverAmount(6); + + // delete the broker + // log << "Broker before delete: " << to_string(broker->getJson()) + // << std::endl; + // if (auto const pseudo = env.le(pseudoKeylet); + // BEAST_EXPECT(pseudo)) + //{ + // log << "Pseudo-account before delete: " + // << to_string(pseudo->getJson()) << std::endl + // << std::endl; + //} + + env(del(alice, keylet.key)); + env.close(); + { + broker = env.le(keylet); + BEAST_EXPECT(!broker); + auto pseudo = env.le(pseudoKeylet); + BEAST_EXPECT(!pseudo); + } + auto const expectedBalance = aliceBalance + coverFunds - + (aliceBalance.value().native() ? STAmount(env.current()->fees().base.value()) : vault.asset(0)); + env.require(balance(alice, expectedBalance)); + env.require(balance(pseudoAccount, vault.asset(none))); + } + } + + void + testLifecycle() + { + testcase("Lifecycle"); + using namespace jtx; + + // Create 3 loan brokers: one for XRP, one for an IOU, and one for an + // MPT. That'll require three corresponding SAVs. + Env env(*this, all); + + Account issuer{"issuer"}; + // For simplicity, alice will be the sole actor for the vault & brokers. + Account alice{"alice"}; + // Evan will attempt to be naughty + Account evan{"evan"}; + // Bystander doesn't have anything to do with the SAV or Broker, or any + // of the relevant tokens + Account bystander{"bystander"}; + Vault vault{env}; + + // Fund the accounts and trust lines with the same amount so that tests + // can use the same values regardless of the asset. + env.fund(XRP(100'000), issuer, noripple(alice, evan, bystander)); + env.close(); + + env(fset(issuer, asfAllowTrustLineClawback)); + env.close(); + + // Create assets + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + PrettyAsset const iouAsset = issuer["IOU"]; + env(trust(alice, iouAsset(1'000'000))); + env(trust(evan, iouAsset(1'000'000))); + env.close(); + env(pay(issuer, evan, iouAsset(100'000))); + env(pay(issuer, alice, iouAsset(100'000))); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + env.close(); + PrettyAsset const mptAsset = mptt["MPT"]; + mptt.authorize({.account = alice}); + mptt.authorize({.account = evan}); + env.close(); + env(pay(issuer, alice, mptAsset(100'000))); + env(pay(issuer, evan, mptAsset(100'000))); + env.close(); + + std::array const assets{xrpAsset, iouAsset, mptAsset}; + + // Create vaults + std::vector vaults; + for (auto const& asset : assets) + { + auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); + env(tx); + env.close(); + if (auto const le = env.le(keylet); BEAST_EXPECT(env.le(keylet))) + { + vaults.emplace_back(asset, keylet.key, le->at(sfAccount)); + } + + env(vault.deposit({.depositor = alice, .id = keylet.key, .amount = asset(50)})); + env.close(); + } + VaultInfo const badVault = [&]() -> VaultInfo { + auto [tx, keylet] = vault.create({.owner = alice, .asset = iouAsset}); + env(tx); + env.close(); + if (auto const le = env.le(keylet); BEAST_EXPECT(env.le(keylet))) + { + return {iouAsset, keylet.key, le->at(sfAccount)}; + } + // This should never happen + return {iouAsset, keylet.key, evan.id()}; + }(); + + auto const aliceOriginalCount = env.ownerCount(alice); + + // Create and update Loan Brokers + for (auto const& vault : vaults) + { + { + // Get the AccountInfo RPC result for the vault pseudo-account + std::string const pseudoStr = to_string(vault.pseudoAccount.id()); + auto const accountInfo = env.rpc("account_info", pseudoStr); + if (BEAST_EXPECT(accountInfo.isObject())) + { + auto const& accountData = accountInfo[jss::result][jss::account_data]; + if (BEAST_EXPECT(accountData.isObject())) + { + BEAST_EXPECT(accountData[jss::Account] == pseudoStr); + BEAST_EXPECT(accountData[sfVaultID] == to_string(vault.vaultID)); + } + auto const& pseudoInfo = accountInfo[jss::result][jss::pseudo_account]; + if (BEAST_EXPECT(pseudoInfo.isObject())) + { + BEAST_EXPECT(pseudoInfo[jss::type] == "Vault"); + } + } + } + + using namespace loanBroker; + using namespace xrpl::Lending; + + TenthBips32 const tenthBipsZero{0}; + + auto badKeylet = keylet::vault(alice.id(), env.seq(alice)); + // Try some failure cases + // not the vault owner + env(set(evan, vault.vaultID), ter(tecNO_PERMISSION)); + // not a vault + env(set(alice, badKeylet.key), ter(tecNO_ENTRY)); + // flags are checked first + env(set(evan, vault.vaultID, ~tfUniversal), ter(temINVALID_FLAG)); + // field length validation + // sfData: good length, bad account + env(set(evan, vault.vaultID), data(std::string(maxDataPayloadLength, 'X')), ter(tecNO_PERMISSION)); + // sfData: too long + env(set(evan, vault.vaultID), data(std::string(maxDataPayloadLength + 1, 'Y')), ter(temINVALID)); + // sfManagementFeeRate: good value, bad account + env(set(evan, vault.vaultID), managementFeeRate(maxManagementFeeRate), ter(tecNO_PERMISSION)); + // sfManagementFeeRate: too big + env(set(evan, vault.vaultID), managementFeeRate(maxManagementFeeRate + TenthBips16(10)), ter(temINVALID)); + // sfCoverRateMinimum and sfCoverRateLiquidation are linked + // Cover: good value, bad account + env(set(evan, vault.vaultID), + coverRateMinimum(maxCoverRate), + coverRateLiquidation(maxCoverRate), + ter(tecNO_PERMISSION)); + // CoverMinimum: too big + env(set(evan, vault.vaultID), + coverRateMinimum(maxCoverRate + 1), + coverRateLiquidation(maxCoverRate + 1), + ter(temINVALID)); + // CoverLiquidation: too big + env(set(evan, vault.vaultID), + coverRateMinimum(maxCoverRate / 2), + coverRateLiquidation(maxCoverRate + 1), + ter(temINVALID)); + // Cover: zero min, non-zero liquidation - implicit and + // explicit zero values. + env(set(evan, vault.vaultID), coverRateLiquidation(maxCoverRate), ter(temINVALID)); + env(set(evan, vault.vaultID), + coverRateMinimum(tenthBipsZero), + coverRateLiquidation(maxCoverRate), + ter(temINVALID)); + // Cover: non-zero min, zero liquidation - implicit and + // explicit zero values. + env(set(evan, vault.vaultID), coverRateMinimum(maxCoverRate), ter(temINVALID)); + env(set(evan, vault.vaultID), + coverRateMinimum(maxCoverRate), + coverRateLiquidation(tenthBipsZero), + ter(temINVALID)); + // sfDebtMaximum: good value, bad account + env(set(evan, vault.vaultID), debtMaximum(Number(0)), ter(tecNO_PERMISSION)); + // sfDebtMaximum: overflow + env(set(evan, vault.vaultID), debtMaximum(Number(1, 100)), ter(temINVALID)); + // sfDebtMaximum: negative + env(set(evan, vault.vaultID), debtMaximum(Number(-1)), ter(temINVALID)); + + std::string testData; + lifecycle( + "default fields", + env, + issuer, + alice, + evan, + bystander, + vault, + badVault, + // No modifications + {}, + [&](SLE::const_ref broker) { + // Extra checks + BEAST_EXPECT(!broker->isFieldPresent(sfManagementFeeRate)); + BEAST_EXPECT(!broker->isFieldPresent(sfCoverRateMinimum)); + BEAST_EXPECT(!broker->isFieldPresent(sfCoverRateLiquidation)); + BEAST_EXPECT(!broker->isFieldPresent(sfData)); + BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum)); + BEAST_EXPECT(broker->at(sfDebtMaximum) == 0); + BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 0); + BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 0); + + BEAST_EXPECT(env.ownerCount(alice) == aliceOriginalCount + 4); + }, + [&](SLE::const_ref broker) { + // Modifications + + // Update the fields + auto const nextKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + + // fields that can't be changed + // LoanBrokerID + env(set(alice, vault.vaultID), loanBrokerID(nextKeylet.key), ter(tecNO_ENTRY), THISLINE); + // VaultID + env(set(alice, nextKeylet.key), loanBrokerID(broker->key()), ter(tecNO_ENTRY), THISLINE); + // Owner + env(set(evan, vault.vaultID), loanBrokerID(broker->key()), ter(tecNO_PERMISSION), THISLINE); + // ManagementFeeRate + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + managementFeeRate(maxManagementFeeRate), + ter(temINVALID), + THISLINE); + // CoverRateMinimum + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + coverRateMinimum(maxManagementFeeRate), + ter(temINVALID), + THISLINE); + // CoverRateLiquidation + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + coverRateLiquidation(maxManagementFeeRate), + ter(temINVALID), + THISLINE); + + // fields that can be changed + testData = "Test Data 1234"; + // Bad data: too long + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + data(std::string(maxDataPayloadLength + 1, 'W')), + ter(temINVALID), + THISLINE); + + // Bad debt maximum + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + debtMaximum(Number(-175, -1)), + ter(temINVALID), + THISLINE); + Number debtMax{175, -1}; + if (vault.asset.integral()) + { + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + data(testData), + debtMaximum(debtMax), + ter(tecPRECISION_LOSS), + THISLINE); + roundToAsset(vault.asset, debtMax); + } + // Data & Debt maximum + env(set(alice, vault.vaultID), + loanBrokerID(broker->key()), + data(testData), + debtMaximum(debtMax), + THISLINE); + }, + [&](SLE::const_ref broker) { + // Check the updated fields + BEAST_EXPECT(checkVL(broker->at(sfData), testData)); + Number const expected = STAmount{vault.asset, Number(175, -1)}; + auto const actual = broker->at(sfDebtMaximum); + BEAST_EXPECTS( + actual == expected, "Expected: " + to_string(expected) + ", Actual: " + to_string(actual)); + }); + + lifecycle( + "non-default fields", + env, + issuer, + alice, + evan, + bystander, + vault, + badVault, + [&](jtx::JTx const& jv) { + testData = "spam spam spam spam"; + // Finally, create another Loan Broker with none of the + // values at default + return env.jt( + jv, + data(testData), + managementFeeRate(TenthBips16(123)), + debtMaximum(Number(9)), + coverRateMinimum(TenthBips32(100)), + coverRateLiquidation(TenthBips32(200))); + }, + [&](SLE::const_ref broker) { + // Extra checks + BEAST_EXPECT(broker->at(sfManagementFeeRate) == 123); + BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 100); + BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 200); + BEAST_EXPECT(broker->at(sfDebtMaximum) == Number(9)); + BEAST_EXPECT(checkVL(broker->at(sfData), testData)); + }, + [&](SLE::const_ref broker) { + // Reset Data & Debt maximum to default values + env(set(alice, vault.vaultID), loanBrokerID(broker->key()), data(""), debtMaximum(Number(0))); + }, + [&](SLE::const_ref broker) { + // Check the updated fields + BEAST_EXPECT(!broker->isFieldPresent(sfData)); + BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum)); + }); + } + + BEAST_EXPECT(env.ownerCount(alice) == aliceOriginalCount); + } + + enum LoanBrokerTest { CoverClawback, CoverDeposit, CoverWithdraw, Delete, Set }; + + void + testLoanBroker( + std::function getAsset, + LoanBrokerTest brokerTest) + { + using namespace jtx; + using namespace loanBroker; + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Env env(*this); + Vault vault{env}; + + env.fund(XRP(100'000), issuer, alice); + env.close(); + + PrettyAsset const asset = [&]() { + if (getAsset) + return getAsset(env, issuer, alice); + env(trust(alice, issuer["IOU"](1'000'000)), THISLINE); + env.close(); + return PrettyAsset(issuer["IOU"]); + }(); + + env(pay(issuer, alice, asset(100'000)), THISLINE); + env.close(); + + auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); + env(tx, THISLINE); + env.close(); + auto const le = env.le(vaultKeylet); + VaultInfo vaultInfo = [&]() { + if (BEAST_EXPECT(le)) + return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)}; + return VaultInfo{asset, {}, {}}; + }(); + if (vaultInfo.vaultID == uint256{}) + return; + + env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(50)}), THISLINE); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + env(set(alice, vaultInfo.vaultID), THISLINE); + env.close(); + + auto broker = env.le(brokerKeylet); + if (!BEAST_EXPECT(broker)) + return; + + auto testZeroBrokerID = [&](auto&& getTxJv) { + auto jv = getTxJv(); + // empty broker ID + jv[sfLoanBrokerID] = ""; + env(jv, ter(temINVALID), THISLINE); + // zero broker ID + jv[sfLoanBrokerID] = to_string(uint256{}); + // needs a flag to distinguish the parsed STTx from the prior + // test + env(jv, txflags(tfFullyCanonicalSig), ter(temINVALID), THISLINE); + }; + auto testZeroVaultID = [&](auto&& getTxJv) { + auto jv = getTxJv(); + // empty broker ID + jv[sfVaultID] = ""; + env(jv, ter(temINVALID), THISLINE); + // zero broker ID + jv[sfVaultID] = to_string(uint256{}); + // needs a flag to distinguish the parsed STTx from the prior + // test + env(jv, txflags(tfFullyCanonicalSig), ter(temINVALID), THISLINE); + }; + + if (brokerTest == CoverDeposit) + { + // preflight: temINVALID (empty/zero broker id) + testZeroBrokerID([&]() { return coverDeposit(alice, brokerKeylet.key, asset(10)); }); + + // preclaim: tecWRONG_ASSET + env(coverDeposit(alice, brokerKeylet.key, issuer["BAD"](10)), ter(tecWRONG_ASSET), THISLINE); + + // preclaim: tecINSUFFICIENT_FUNDS + env(pay(alice, issuer, asset(100'000 - 50)), THISLINE); + env.close(); + env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), ter(tecINSUFFICIENT_FUNDS)); + + // preclaim: tecFROZEN + env(fset(issuer, asfGlobalFreeze), THISLINE); + env.close(); + env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), ter(tecFROZEN), THISLINE); + } + else + // Fund the cover deposit + env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), THISLINE); + env.close(); + + if (brokerTest == CoverWithdraw) + { + // preflight: temINVALID (empty/zero broker id) + testZeroBrokerID([&]() { return coverWithdraw(alice, brokerKeylet.key, asset(10)); }); + + // preclaim: tecWRONG_ASSET + env(coverWithdraw(alice, brokerKeylet.key, issuer["BAD"](10)), ter(tecWRONG_ASSET), THISLINE); + + // preclaim: tecNO_DST + Account const bogus{"bogus"}; + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), destination(bogus), ter(tecNO_DST), THISLINE); + + // preclaim: tecDST_TAG_NEEDED + Account const dest{"dest"}; + env.fund(XRP(1'000), dest); + env(fset(dest, asfRequireDest), THISLINE); + env.close(); + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), destination(dest), ter(tecDST_TAG_NEEDED), THISLINE); + + // preclaim: tecNO_PERMISSION + env(fclear(dest, asfRequireDest), THISLINE); + env(fset(dest, asfDepositAuth), THISLINE); + env.close(); + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), destination(dest), ter(tecNO_PERMISSION), THISLINE); + + // preclaim: tecFROZEN + env(trust(dest, asset(1'000)), THISLINE); + env(fclear(dest, asfDepositAuth), THISLINE); + env(fset(issuer, asfGlobalFreeze), THISLINE); + env.close(); + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), destination(dest), ter(tecFROZEN), THISLINE); + + // preclaim:: tecFROZEN (deep frozen) + env(fclear(issuer, asfGlobalFreeze), THISLINE); + env(trust(issuer, asset(1'000), dest, tfSetFreeze | tfSetDeepFreeze), THISLINE); + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), destination(dest), ter(tecFROZEN), THISLINE); + + // preclaim: tecPSEUDO_ACCOUNT + env(coverWithdraw(alice, brokerKeylet.key, asset(10)), + destination(vaultInfo.pseudoAccount), + ter(tecPSEUDO_ACCOUNT), + THISLINE); + } + + if (brokerTest == CoverClawback) + { + // preflight: temINVALID (empty/zero broker id) + testZeroBrokerID([&]() { + return env.json(coverClawback(alice), loanBrokerID(brokerKeylet.key), amount(vaultInfo.asset(2))); + }); + + if (asset.holds()) + { + // preclaim: AllowTrustLineClawback is not set + env(coverClawback(issuer), + loanBrokerID(brokerKeylet.key), + amount(vaultInfo.asset(2)), + ter(tecNO_PERMISSION), + THISLINE); + + // preclaim: NoFreeze is set + env(fset(issuer, asfAllowTrustLineClawback | asfNoFreeze), THISLINE); + env.close(); + env(coverClawback(issuer), + loanBrokerID(brokerKeylet.key), + amount(vaultInfo.asset(2)), + ter(tecNO_PERMISSION), + THISLINE); + } + else + { + // preclaim: MPTCanClawback is not set or MPTCanLock is not set + env(coverClawback(issuer), + loanBrokerID(brokerKeylet.key), + amount(vaultInfo.asset(2)), + ter(tecNO_PERMISSION), + THISLINE); + } + env.close(); + } + + if (brokerTest == Delete) + { + Account const borrower{"borrower"}; + env.fund(XRP(1'000), borrower); + env(loan::set(borrower, brokerKeylet.key, asset(50).value()), + sig(sfCounterpartySignature, alice), + fee(env.current()->fees().base * 2), + THISLINE); + + // preflight: temINVALID (empty/zero broker id) + testZeroBrokerID([&]() { return del(alice, brokerKeylet.key); }); + + // preclaim: tecHAS_OBLIGATIONS + env(del(alice, brokerKeylet.key), ter(tecHAS_OBLIGATIONS), THISLINE); + + // Repay and delete the loan + auto const loanKeylet = keylet::loan(brokerKeylet.key, 1); + env(loan::pay(borrower, loanKeylet.key, asset(50).value()), THISLINE); + env(loan::del(alice, loanKeylet.key), THISLINE); + + env(trust(issuer, asset(0), alice, tfSetFreeze | tfSetDeepFreeze), THISLINE); + // preclaim: tecFROZEN (deep frozen) + env(del(alice, brokerKeylet.key), ter(tecFROZEN), THISLINE); + env(trust(issuer, asset(0), alice, tfClearFreeze | tfClearDeepFreeze), THISLINE); + + // successful delete the loan broker object + env(del(alice, brokerKeylet.key), ter(tesSUCCESS), THISLINE); + } + else + env(del(alice, brokerKeylet.key), THISLINE); + + if (brokerTest == Set) + { + // preflight: temINVALID (empty/zero broker id) + testZeroBrokerID([&]() { return env.json(set(alice, vaultInfo.vaultID), loanBrokerID(brokerKeylet.key)); }); + // preflight: temINVALID (empty/zero vault id) + testZeroVaultID([&]() { return env.json(set(alice, vaultInfo.vaultID), loanBrokerID(brokerKeylet.key)); }); + + if (asset.holds()) + { + env(fclear(issuer, asfDefaultRipple), THISLINE); + env.close(); + // preclaim: DefaultRipple is not set + env(set(alice, vaultInfo.vaultID), ter(terNO_RIPPLE), THISLINE); + + env(fset(issuer, asfDefaultRipple), THISLINE); + env.close(); + } + + auto const amt = env.balance(alice) - env.current()->fees().accountReserve(env.ownerCount(alice)); + env(pay(alice, issuer, amt), THISLINE); + + // preclaim:: tecINSUFFICIENT_RESERVE + env(set(alice, vaultInfo.vaultID), ter(tecINSUFFICIENT_RESERVE), THISLINE); + } + } + + void + testInvalidLoanBrokerCoverClawback() + { + testcase("Invalid LoanBrokerCoverClawback"); + using namespace jtx; + using namespace loanBroker; + + // preflight + { + Account const alice{"alice"}; + Account const issuer{"issuer"}; + auto const USD = alice["USD"]; + Env env(*this); + env.fund(XRP(100'000), alice); + env.close(); + + auto jtx = env.jt(coverClawback(alice), amount(USD(100))); + + // holder == account + env(jtx, ter(temINVALID), THISLINE); + + // holder == beast::zero + STAmount bad(Issue{USD.currency, beast::zero}, 100); + jtx.jv[sfAmount] = bad.getJson(); + jtx.stx = env.ust(jtx); + Serializer s; + jtx.stx->add(s); + auto const jrr = env.rpc("submit", strHex(s.slice()))[jss::result]; + // fails in doSubmit() on STTx construction + BEAST_EXPECT(jrr[jss::error] == "invalidTransaction"); + BEAST_EXPECT(jrr[jss::error_exception] == "invalid native account"); + } + + // preclaim + + // Issue: + // AllowTrustLineClawback is not set or NoFreeze is set + testLoanBroker({}, CoverClawback); + + // MPTIssue: + // MPTCanClawback is not set + testLoanBroker( + [&](Env& env, Account const& issuer, Account const& alice) -> MPT { + MPTTester mpt({.env = env, .issuer = issuer, .holders = {alice}}); + return mpt; + }, + CoverClawback); + } + + void + testInvalidLoanBrokerCoverDeposit() + { + testcase("Invalid LoanBrokerCoverDeposit"); + using namespace jtx; + + // preclaim: + // tecWRONG_ASSET, tecINSUFFICIENT_FUNDS, frozen asset + testLoanBroker({}, CoverDeposit); + } + + void + testInvalidLoanBrokerCoverWithdraw() + { + testcase("Invalid LoanBrokerCoverWithdraw"); + using namespace jtx; + + /* + preflight: illegal net + isLegalNet() check is probably redundant. STAmount parsing + should throw an exception on deserialize + + preclaim: tecWRONG_ASSET, tecNO_DST, tecDST_TAG_NEEDED, + tecNO_PERMISSION, checkFrozen failure, checkDeepFrozenFailure, + second+third tecINSUFFICIENT_FUNDS (can this happen)? + doApply: tecPATH_DRY (can it happen, funds already checked?) + */ + testLoanBroker({}, CoverWithdraw); + } + + void + testInvalidLoanBrokerDelete() + { + using namespace jtx; + testcase("Invalid LoanBrokerDelete"); + /* + preclaim: tecHAS_OBLIGATIONS + doApply: + accountSend failure, removeEmptyHolding failure, + all tecHAS_OBLIGATIONS (can any of these happen?) + */ + testLoanBroker({}, Delete); + } + + void + testInvalidLoanBrokerSet() + { + using namespace jtx; + testcase("Invalid LoanBrokerSet"); + + /*preclaim: canAddHolding failure (can it happen with MPT? + can't create Vault if CanTransfer is not enabled.) + doApply: + first+second dirLink failure, createPseudoAccount failure, + addEmptyHolding failure + can any of these happen? + */ + testLoanBroker({}, Set); + } + + void + testLoanBrokerCoverDepositNullVault() + { + // This test is lifted directly from + // https://bugs.immunefi.com/dashboard/submission/57808 + using namespace jtx; + Env env(*this); + + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + // Create a Vault owned by alice with an XRP asset + PrettyAsset const asset{xrpIssue(), 1}; + Vault vault{env}; + auto const [createTx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); + env(createTx); + env.close(); + + // Predict LoanBroker key using alice's current sequence BEFORE submit + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + + // Create LoanBroker pointing to the vault + env(loanBroker::set(alice, vaultKeylet.key)); + env.close(); + + // Build the CoverDeposit STTx directly + STTx tx{ttLOAN_BROKER_COVER_DEPOSIT, [](STObject&) {}}; + tx.setAccountID(sfAccount, alice.id()); + tx.setFieldH256(sfLoanBrokerID, brokerKeylet.key); + tx.setFieldAmount(sfAmount, asset(1)); + + // Create a writable view cloned from the current ledger and remove the + // vault SLE + OpenView ov{*env.current()}; + test::StreamSink sink{beast::severities::kWarning}; + beast::Journal jlog{sink}; + ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, tapNONE, jlog}; + + if (auto sleBroker = ac.view().peek(keylet::loanbroker(brokerKeylet.key))) + { + auto const vaultID = (*sleBroker)[sfVaultID]; + if (auto sleVault = ac.view().peek(keylet::vault(vaultID))) + { + ac.view().erase(sleVault); + } + } + + // Invoke preclaim against the mutated (ApplyView) view; triggers + // nullptr deref + PreclaimContext pctx{env.app(), ac.view(), tesSUCCESS, tx, tapNONE, jlog}; + (void)LoanBrokerCoverDeposit::preclaim(pctx); + } + + void + testRequireAuth() + { + testcase("Require Auth - Implicit Pseudo-account authorization"); + using namespace jtx; + using namespace loanBroker; + + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Env env(*this); + Vault vault{env}; + + env.fund(XRP(100'000), issuer, alice); + env.close(); + + auto asset = MPTTester({ + .env = env, + .issuer = issuer, + .holders = {alice}, + .flags = MPTDEXFlags | tfMPTRequireAuth | tfMPTCanClawback | tfMPTCanLock, + .authHolder = true, + }); + + env(pay(issuer, alice, asset(100'000))); + env.close(); + + // Alice is not authorized, can still create the vault + asset.authorize({.account = issuer, .holder = alice, .flags = tfMPTUnauthorize}); + auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); + env(tx); + env.close(); + + auto const le = env.le(vaultKeylet); + VaultInfo vaultInfo = [&]() { + if (BEAST_EXPECT(le)) + return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)}; + return VaultInfo{asset, {}, {}}; + }(); + if (vaultInfo.vaultID == uint256{}) + return; + + // Can't unauthorize Vault pseudo-account + asset.authorize( + {.account = issuer, .holder = vaultInfo.pseudoAccount, .flags = tfMPTUnauthorize, .err = tecNO_PERMISSION}); + + auto forUnauthAuth = [&](auto&& doTx) { + for (auto const flag : {tfMPTUnauthorize, 0u}) + { + asset.authorize({.account = issuer, .holder = alice, .flags = flag}); + env.close(); + doTx(flag == 0); + env.close(); + } + }; + + // Can't deposit into Vault if the vault owner is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(51)}), err); + }); + + // Can't withdraw from Vault if the vault owner is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(vault.withdraw({.depositor = alice, .id = vaultKeylet.key, .amount = asset(1)}), err); + }); + + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + // Can create LoanBroker if the vault owner is not authorized + forUnauthAuth([&](auto) { env(set(alice, vaultInfo.vaultID)); }); + + auto const broker = env.le(brokerKeylet); + if (!BEAST_EXPECT(broker)) + return; + Account brokerPseudo("pseudo", broker->at(sfAccount)); + + // Can't unauthorize LoanBroker pseudo-account + asset.authorize( + {.account = issuer, .holder = brokerPseudo, .flags = tfMPTUnauthorize, .err = tecNO_PERMISSION}); + + // Can't cover deposit into Vault if the vault owner is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), err); + }); + + // Can't cover withdraw from Vault if the vault owner is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(coverWithdraw(alice, brokerKeylet.key, vaultInfo.asset(5)), err); + }); + + // Issuer can always cover clawback. The holder authorization is n/a. + forUnauthAuth( + [&](bool) { env(coverClawback(issuer), loanBrokerID(brokerKeylet.key), amount(vaultInfo.asset(1))); }); + } + + void + testLoanBrokerSetDebtMaximum() + { + testcase("testLoanBrokerSetDebtMaximum"); + using namespace jtx; + using namespace loanBroker; + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Env env(*this); + Vault vault{env}; + + env.fund(XRP(100'000), issuer, alice); + env.close(); + + PrettyAsset const asset = [&]() { + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + env.close(); + PrettyAsset const mptAsset = mptt["MPT"]; + mptt.authorize({.account = alice}); + env.close(); + return mptAsset; + }(); + + env(pay(issuer, alice, asset(100'000)), THISLINE); + env.close(); + + auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); + env(tx, THISLINE); + env.close(); + auto const le = env.le(vaultKeylet); + VaultInfo vaultInfo = [&]() { + if (BEAST_EXPECT(le)) + return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)}; + return VaultInfo{asset, {}, {}}; + }(); + if (vaultInfo.vaultID == uint256{}) + return; + + env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(50)}), THISLINE); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + env(set(alice, vaultInfo.vaultID), THISLINE); + env.close(); + + Account const borrower{"borrower"}; + env.fund(XRP(1'000), borrower); + env(loan::set(borrower, brokerKeylet.key, asset(50).value()), + sig(sfCounterpartySignature, alice), + fee(env.current()->fees().base * 2), + THISLINE); + auto const broker = env.le(brokerKeylet); + if (!BEAST_EXPECT(broker)) + return; + + BEAST_EXPECT(broker->at(sfDebtTotal) == 50); + auto debtTotal = broker->at(sfDebtTotal); + + auto tx2 = set(alice, vaultInfo.vaultID); + tx2[sfLoanBrokerID] = to_string(brokerKeylet.key); + tx2[sfDebtMaximum] = debtTotal - 1; + env(tx2, ter(tecLIMIT_EXCEEDED), THISLINE); + + tx2[sfDebtMaximum] = debtTotal + 1; + env(tx2, ter(tesSUCCESS), THISLINE); + + tx2[sfDebtMaximum] = 0; + env(tx2, ter(tesSUCCESS), THISLINE); + + tx2[sfDebtMaximum] = Json::Value::maxInt; + env(tx2, ter(tesSUCCESS), THISLINE); + + { + auto const dm = power(2, 64) - 1; + BEAST_EXPECT(dm > maxMPTokenAmount); + tx2[sfDebtMaximum] = dm; + env(tx2, ter(temINVALID), THISLINE); + } + + { + auto const dm = power(2, 63) - 1; + BEAST_EXPECTS(dm > maxMPTokenAmount, to_string(dm)); + tx2[sfDebtMaximum] = dm; + env(tx2, ter(temINVALID), THISLINE); + } + + { + auto const dm = power(2, 63) - 3; + BEAST_EXPECTS(dm == maxMPTokenAmount, to_string(dm)); + tx2[sfDebtMaximum] = dm; + env(tx2, ter(tesSUCCESS), THISLINE); + } + + { + auto const dm = 2 * (power(2, 62) - 1) + 1; + BEAST_EXPECTS(dm == maxMPTokenAmount, to_string(dm)); + tx2[sfDebtMaximum] = dm; + env(tx2, ter(tesSUCCESS), THISLINE); + } + + tx2[sfDebtMaximum] = Number{9223372036854775807, 0}; + env(tx2, ter(tesSUCCESS), THISLINE); + } + + void + testRIPD4323() + { + testcase << "RIPD-4323"; + using namespace jtx; + Account const issuer("issuer"); + Account const holder("holder"); + Account const& broker = issuer; + + auto test = [&](auto&& getToken) { + Env env(*this); + + env.fund(XRP(1'000), issuer, holder); + env.close(); + + auto const [token, deposit, err] = getToken(env); + + Vault vault(env); + auto const [tx, keylet] = vault.create({.owner = broker, .asset = token.asset()}); + env(tx); + env.close(); + + env(vault.deposit({.depositor = broker, .id = keylet.key, .amount = deposit}), ter(err)); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(broker, env.seq(broker)); + + env(loanBroker::set(broker, keylet.key)); + env.close(); + + env(loanBroker::coverDeposit(broker, brokerKeylet.key, deposit), ter(err)); + env.close(); + }; + + test([&](Env&) { + // issuer can issue any amount + auto const token = issuer["IOU"]; + return std::make_tuple(token, token(1'000), tesSUCCESS); + }); + std::vector, // max amount + std::uint64_t, // deposit amount + TER>> // expected error + mptTests = { + // issuer can issue up to 2'000 tokens + {2'000, 4'000, 1'000, tesSUCCESS}, + // issuer can issue 500 tokens (250 VaultDeposit + + // 250 LoanBrokerCoverDeposit) + {2'000, 2'500, 250, tesSUCCESS}, + // issuer can issue 500 tokens (250 VaultDeposit + + // 250 LoanBrokerCoverDeposit). MaximumAmount is default. + {maxMPTokenAmount - 500, std::nullopt, 250, tesSUCCESS}, + // issuer can issue 500, and fails on depositing 1'000 + {2'000, 2'500, 1'000, tecINSUFFICIENT_FUNDS}, + // issuer has already issued MaximumAmount + {2'000, 2'000, 1'000, tecINSUFFICIENT_FUNDS}, + // issuer has already issued MaximumAmount. MaximumAmount is + // default. + {maxMPTokenAmount, std::nullopt, 250, tecINSUFFICIENT_FUNDS}, + }; + for (auto const& [pay, max, deposit, err] : mptTests) + { + test([&](Env& env) -> std::tuple { + MPT const token = MPTTester( + {.env = env, + .issuer = issuer, + .holders = {holder}, + .pay = pay, + .flags = MPTDEXFlags, + .maxAmt = max}); + return std::make_tuple(token, token(deposit), err); + }); + } + } + + void + testAMB06_VaultFreezeCheckMissing() + { + testcase << "RIPD-4466 - LoanBrokerSet disallows frozen vaults"; + using namespace jtx; + Env env(*this); + + Account const issuer{"issuer"}, lender{"lender"}, borrower{"borrower"}; + env.fund(XRP(20'000), issuer, lender, borrower); + auto const IOU = issuer["IOU"]; + + Vault vault{env}; + auto [tx, vaultKeylet] = vault.create({.owner = lender, .asset = IOU.asset()}); + env(tx); + env.close(); + + // Get vault pseudo-account and FREEZE it + auto const vaultSle = env.le(vaultKeylet); + auto const vaultPseudo = vaultSle->at(sfAccount); + auto const vaultPseudoAcct = Account("VaultPseudo", vaultPseudo); + env(trust(issuer, vaultPseudoAcct["IOU"](0), tfSetFreeze)); + + env(loanBroker::set(lender, vaultKeylet.key), ter(tecFROZEN)); + } + + void + testRIPD4274IOU() + { + using namespace jtx; + Account issuer("broker"); + Account broker("issuer"); + Account dest("destination"); + auto const token = issuer["IOU"]; + + enum TrustState { + RequireAuth, + ZeroLimit, + ReachedLimit, + NearLimit, + NoTrustLine, + }; + + auto test = [&](TrustState trustState) { + Env env(*this); + + testcase << "RIPD-4274 IOU with state: " << static_cast(trustState); + + auto setTrustLine = [&](Account const& acct, TrustState state) { + switch (state) + { + case RequireAuth: + env(trust(issuer, token(0), acct, tfSetfAuth)); + break; + case ZeroLimit: { + auto jv = trust(acct, token(0)); + // set QualityIn so that the trustline is not + // auto-deleted + jv[sfQualityIn] = 10'000'000; + env(jv); + } + break; + case ReachedLimit: { + env(trust(acct, token(1'000))); + env(pay(issuer, acct, token(1'000))); + env.close(); + } + break; + case NearLimit: { + env(trust(acct, token(1'000))); + env(pay(issuer, acct, token(950))); + env.close(); + } + break; + case NoTrustLine: + // don't create a trustline + break; + default: + BEAST_EXPECT(false); + } + env.close(); + }; + + env.fund(XRP(1'000), issuer, broker, dest); + env.close(); + + if (trustState == RequireAuth) + { + env(fset(issuer, asfRequireAuth)); + env.close(); + + setTrustLine(broker, RequireAuth); + } + + setTrustLine(dest, trustState); + + env(trust(broker, token(2'000), 0)); + env(pay(issuer, broker, token(2'000))); + env.close(); + + Vault vault(env); + auto const [tx, keylet] = vault.create({.owner = broker, .asset = token.asset()}); + env(tx); + env.close(); + + // Test Vault withdraw + env(vault.deposit({.depositor = broker, .id = keylet.key, .amount = token(1'000)})); + env.close(); + + env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)}), + loanBroker::destination(dest), + ter(std::ignore)); + BEAST_EXPECT(env.ter() == tecNO_LINE); + env.close(); + + env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)})); + + // Test LoanBroker withdraw + auto const brokerKeylet = keylet::loanbroker(broker, env.seq(broker)); + + env(loanBroker::set(broker, keylet.key)); + env.close(); + + env(loanBroker::coverDeposit(broker, brokerKeylet.key, token(1'000))); + env.close(); + + env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)), + loanBroker::destination(dest), + ter(std::ignore)); + BEAST_EXPECT(env.ter() == tecNO_LINE); + env.close(); + + // Clearing RequireAuth shouldn't change the result + if (trustState == RequireAuth) + { + env(fclear(issuer, asfRequireAuth)); + env.close(); + + env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)), + loanBroker::destination(dest), + ter(std::ignore)); + BEAST_EXPECT(env.ter() == tecNO_LINE); + env.close(); + } + }; + + test(RequireAuth); + test(ZeroLimit); + test(ReachedLimit); + test(NearLimit); + test(NoTrustLine); + } + + void + testRIPD4274MPT() + { + using namespace jtx; + Account issuer("broker"); + Account broker("issuer"); + Account dest("destination"); + + enum MPTState { + RequireAuth, + ReachedMAX, + NoMPT, + }; + + auto test = [&](MPTState MPTState) { + Env env(*this); + + testcase << "RIPD-4274 MPT with state: " << static_cast(MPTState); + + env.fund(XRP(1'000), issuer, broker, dest); + env.close(); + + auto const maybeToken = [&]() -> std::optional { + switch (MPTState) + { + case RequireAuth: { + auto tester = MPTTester( + {.env = env, + .issuer = issuer, + .holders = {broker, dest}, + .pay = 2'000, + .flags = MPTDEXFlags | tfMPTRequireAuth, + .authHolder = true, + .maxAmt = 5'000}); + // unauthorize dest + tester.authorize({.account = issuer, .holder = dest, .flags = tfMPTUnauthorize}); + return tester; + } + case ReachedMAX: { + auto tester = MPTTester( + {.env = env, + .issuer = issuer, + .holders = {broker, dest}, + .pay = 2'000, + .flags = MPTDEXFlags, + .maxAmt = 4'000}); + BEAST_EXPECT(env.balance(issuer, tester) == tester(-4'000)); + return tester; + } + case NoMPT: { + return MPTTester( + {.env = env, + .issuer = issuer, + .holders = {broker}, + .pay = 2'000, + .flags = MPTDEXFlags, + .maxAmt = 4'000}); + } + default: + return std::nullopt; + } + }(); + if (!BEAST_EXPECT(maybeToken)) + return; + + auto const& token = *maybeToken; + + Vault vault(env); + auto const [tx, keylet] = vault.create({.owner = broker, .asset = token.asset()}); + env(tx); + env.close(); + + // Test Vault withdraw + env(vault.deposit({.depositor = broker, .id = keylet.key, .amount = token(1'000)})); + env.close(); + + env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)}), + loanBroker::destination(dest), + ter(std::ignore)); + + // Shouldn't fail if at MaximumAmount since no new tokens are issued + TER const err = MPTState == ReachedMAX ? TER(tesSUCCESS) : tecNO_AUTH; + BEAST_EXPECT(env.ter() == err); + env.close(); + + if (err != tesSUCCESS) + { + env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)})); + } + + // Test LoanBroker withdraw + auto const brokerKeylet = keylet::loanbroker(broker, env.seq(broker)); + + env(loanBroker::set(broker, keylet.key)); + env.close(); + + env(loanBroker::coverDeposit(broker, brokerKeylet.key, token(1'000))); + env.close(); + + env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)), + loanBroker::destination(dest), + ter(std::ignore)); + BEAST_EXPECT(env.ter() == err); + env.close(); + }; + + test(RequireAuth); + test(ReachedMAX); + test(NoMPT); + } + + void + testRIPD4274() + { + testRIPD4274IOU(); + testRIPD4274MPT(); + } + +public: + void + run() override + { + testLoanBrokerSetDebtMaximum(); + testLoanBrokerCoverDepositNullVault(); + + testDisabled(); + testLifecycle(); + testInvalidLoanBrokerCoverClawback(); + testInvalidLoanBrokerCoverDeposit(); + testInvalidLoanBrokerCoverWithdraw(); + testInvalidLoanBrokerDelete(); + testInvalidLoanBrokerSet(); + testRequireAuth(); + + testRIPD4323(); + testAMB06_VaultFreezeCheckMissing(); + + testRIPD4274(); + + // TODO: Write clawback failure tests with an issuer / MPT that doesn't + // have the right flags set. + } +}; + +BEAST_DEFINE_TESTSUITE(LoanBroker, tx, xrpl); + +} // namespace test +} // namespace xrpl diff --git a/src/test/app/Loan_test.cpp b/src/test/app/Loan_test.cpp new file mode 100644 index 0000000000..5deb1f179c --- /dev/null +++ b/src/test/app/Loan_test.cpp @@ -0,0 +1,6866 @@ +#include +// +#include +#include + +#include +#include +#include +#include + +#include +#include +// cspell: words LOANTODO + +#include + +namespace xrpl { +namespace test { + +class Loan_test : public beast::unit_test::suite +{ +protected: + // Ensure that all the features needed for Lending Protocol are included, + // even if they are set to unsupported. + FeatureBitset const all{ + jtx::testable_amendments() | featureMPTokensV1 | featureSingleAssetVault | featureLendingProtocol}; + + std::string const iouCurrency{"IOU"}; + + void + testDisabled() + { + testcase("Disabled"); + // Lending Protocol depends on Single Asset Vault (SAV). Test + // combinations of the two amendments. + // Single Asset Vault depends on MPTokensV1, but don't test every combo + // of that. + using namespace jtx; + auto failAll = [this](FeatureBitset features) { + Env env(*this, features); + + Account const alice{"alice"}; + Account const bob{"bob"}; + env.fund(XRP(10000), alice, bob); + + auto const keylet = keylet::loanbroker(alice, env.seq(alice)); + + using namespace std::chrono_literals; + using namespace loan; + + // counter party signature is optional on LoanSet. Confirm that by + // sending transaction without one. + auto setTx = env.jt(set(alice, keylet.key, Number(10000)), ter(temDISABLED)); + env(setTx); + + // All loan transactions are disabled. + // 1. LoanSet + setTx = env.jt(setTx, sig(sfCounterpartySignature, bob), ter(temDISABLED)); + env(setTx); + // Actual sequence will be based off the loan broker, but we + // obviously don't have one of those if the amendment is disabled + auto const loanKeylet = keylet::loan(keylet.key, env.seq(alice)); + // Other Loan transactions are disabled, too. + // 2. LoanDelete + env(del(alice, loanKeylet.key), ter(temDISABLED)); + // 3. LoanManage + env(manage(alice, loanKeylet.key, tfLoanImpair), ter(temDISABLED)); + // 4. LoanPay + env(pay(alice, loanKeylet.key, XRP(500)), ter(temDISABLED)); + }; + failAll(all - featureMPTokensV1); + failAll(all - featureSingleAssetVault - featureLendingProtocol); + failAll(all - featureSingleAssetVault); + failAll(all - featureLendingProtocol); + } + + struct BrokerParameters + { + Number vaultDeposit = 1'000'000; + Number debtMax = 25'000; + TenthBips32 coverRateMin = percentageToTenthBips(10); + int coverDeposit = 1000; + TenthBips16 managementFeeRate{100}; + TenthBips32 coverRateLiquidation = percentageToTenthBips(25); + std::string data{}; + std::uint32_t flags = 0; + + Number + maxCoveredLoanValue(Number const& currentDebt) const + { + NumberRoundModeGuard mg(Number::downward); + auto debtLimit = coverDeposit * tenthBipsPerUnity.value() / coverRateMin.value(); + + return debtLimit - currentDebt; + } + + static BrokerParameters const& + defaults() + { + static BrokerParameters const result{}; + return result; + } + + // TODO: create an operator() which returns a transaction similar to + // LoanParameters + }; + + struct BrokerInfo + { + jtx::PrettyAsset asset; + uint256 brokerID; + uint256 vaultID; + BrokerParameters params; + BrokerInfo( + jtx::PrettyAsset const& asset_, + Keylet const& brokerKeylet_, + Keylet const& vaultKeylet_, + BrokerParameters const& p) + : asset(asset_), brokerID(brokerKeylet_.key), vaultID(vaultKeylet_.key), params(p) + { + } + + Keylet + brokerKeylet() const + { + return keylet::loanbroker(brokerID); + } + Keylet + vaultKeylet() const + { + return keylet::vault(vaultID); + } + + int + vaultScale(jtx::Env const& env) const + { + using namespace jtx; + + auto const vaultSle = env.le(keylet::vault(vaultID)); + return getAssetsTotalScale(vaultSle); + } + }; + + struct LoanParameters + { + // The account submitting the transaction. May be borrower or broker. + jtx::Account account; + // The counterparty. Should be the other of borrower or broker. + jtx::Account counter; + // Whether the counterparty is specified in the `counterparty` field, or + // only signs. + bool counterpartyExplicit = true; + Number principalRequest; + std::optional setFee{}; + std::optional originationFee{}; + std::optional serviceFee{}; + std::optional lateFee{}; + std::optional closeFee{}; + std::optional overFee{}; + std::optional interest{}; + std::optional lateInterest{}; + std::optional closeInterest{}; + std::optional overpaymentInterest{}; + std::optional payTotal{}; + std::optional payInterval{}; + std::optional gracePd{}; + std::optional flags{}; + + template + jtx::JTx + operator()(jtx::Env& env, BrokerInfo const& broker, FN const&... fN) const + { + using namespace jtx; + using namespace jtx::loan; + + JTx jt{loan::set(account, broker.brokerID, broker.asset(principalRequest).number(), flags.value_or(0))}; + + sig(sfCounterpartySignature, counter)(env, jt); + + fee{setFee.value_or(env.current()->fees().base * 2)}(env, jt); + + if (counterpartyExplicit) + counterparty(counter)(env, jt); + if (originationFee) + loanOriginationFee(broker.asset(*originationFee).number())(env, jt); + if (serviceFee) + loanServiceFee(broker.asset(*serviceFee).number())(env, jt); + if (lateFee) + latePaymentFee(broker.asset(*lateFee).number())(env, jt); + if (closeFee) + closePaymentFee(broker.asset(*closeFee).number())(env, jt); + if (overFee) + overpaymentFee (*overFee)(env, jt); + if (interest) + interestRate (*interest)(env, jt); + if (lateInterest) + lateInterestRate (*lateInterest)(env, jt); + if (closeInterest) + closeInterestRate (*closeInterest)(env, jt); + if (overpaymentInterest) + overpaymentInterestRate (*overpaymentInterest)(env, jt); + if (payTotal) + paymentTotal (*payTotal)(env, jt); + if (payInterval) + paymentInterval (*payInterval)(env, jt); + if (gracePd) + gracePeriod (*gracePd)(env, jt); + + return env.jt(jt, fN...); + } + }; + + struct PaymentParameters + { + Number overpaymentFactor = Number{1}; + std::optional overpaymentExtra = std::nullopt; + std::uint32_t flags = 0; + bool showStepBalances = false; + bool validateBalances = true; + + static PaymentParameters const& + defaults() + { + static PaymentParameters const result{}; + return result; + } + }; + + struct LoanState + { + std::uint32_t previousPaymentDate = 0; + NetClock::time_point startDate = {}; + std::uint32_t nextPaymentDate = 0; + std::uint32_t paymentRemaining = 0; + std::int32_t const loanScale = 0; + Number totalValue = 0; + Number principalOutstanding = 0; + Number managementFeeOutstanding = 0; + Number periodicPayment = 0; + std::uint32_t flags = 0; + std::uint32_t const paymentInterval = 0; + TenthBips32 const interestRate{}; + }; + + /** Helper class to compare the expected state of a loan and loan broker + * against the data in the ledger. + */ + struct VerifyLoanStatus + { + public: + jtx::Env const& env; + BrokerInfo const& broker; + jtx::Account const& pseudoAccount; + Keylet const& loanKeylet; + + VerifyLoanStatus( + jtx::Env const& env_, + BrokerInfo const& broker_, + jtx::Account const& pseudo_, + Keylet const& keylet_) + : env(env_), broker(broker_), pseudoAccount(pseudo_), loanKeylet(keylet_) + { + } + + /** Checks the expected broker state against the ledger + */ + void + checkBroker( + Number const& principalOutstanding, + Number const& interestOwed, + TenthBips32 interestRate, + std::uint32_t paymentInterval, + std::uint32_t paymentsRemaining, + std::uint32_t ownerCount) const + { + using namespace jtx; + if (auto brokerSle = env.le(keylet::loanbroker(broker.brokerID)); env.test.BEAST_EXPECT(brokerSle)) + { + TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)}; + auto const brokerDebt = brokerSle->at(sfDebtTotal); + auto const expectedDebt = principalOutstanding + interestOwed; + env.test.BEAST_EXPECT(brokerDebt == expectedDebt); + env.test.BEAST_EXPECT( + env.balance(pseudoAccount, broker.asset).number() == brokerSle->at(sfCoverAvailable)); + env.test.BEAST_EXPECT(brokerSle->at(sfOwnerCount) == ownerCount); + + if (auto vaultSle = env.le(keylet::vault(brokerSle->at(sfVaultID))); env.test.BEAST_EXPECT(vaultSle)) + { + Account const vaultPseudo{"vaultPseudoAccount", vaultSle->at(sfAccount)}; + env.test.BEAST_EXPECT( + vaultSle->at(sfAssetsAvailable) == env.balance(vaultPseudo, broker.asset).number()); + if (ownerCount == 0) + { + // Allow some slop for rounding IOUs + + // TODO: This needs to be an exact match once all the + // other rounding issues are worked out. + auto const total = vaultSle->at(sfAssetsTotal); + auto const available = vaultSle->at(sfAssetsAvailable); + env.test.BEAST_EXPECT( + total == available || + (!broker.asset.integral() && available != 0 && + ((total - available) / available < Number(1, -6)))); + env.test.BEAST_EXPECT(vaultSle->at(sfLossUnrealized) == 0); + } + } + } + } + + void + checkPayment( + std::int32_t loanScale, + jtx::Account const& account, + jtx::PrettyAmount const& balanceBefore, + STAmount const& expectedPayment, + jtx::PrettyAmount const& adjustment) const + { + auto const borrowerScale = std::max(loanScale, balanceBefore.number().exponent()); + + STAmount const balanceChangeAmount{ + broker.asset, roundToAsset(broker.asset, expectedPayment + adjustment, borrowerScale)}; + { + auto const difference = roundToScale( + env.balance(account, broker.asset) - (balanceBefore - balanceChangeAmount), borrowerScale); + env.test.expect( + roundToScale(difference, loanScale) >= beast::zero, + "Balance before: " + to_string(balanceBefore.value()) + + ", expected change: " + to_string(balanceChangeAmount) + + ", difference (balance after - expected): " + to_string(difference), + __FILE__, + __LINE__); + } + } + + /** Checks both the loan and broker expect states against the ledger */ + void + operator()( + std::uint32_t previousPaymentDate, + std::uint32_t nextPaymentDate, + std::uint32_t paymentRemaining, + Number const& loanScale, + Number const& totalValue, + Number const& principalOutstanding, + Number const& managementFeeOutstanding, + Number const& periodicPayment, + std::uint32_t flags) const + { + using namespace jtx; + if (auto loan = env.le(loanKeylet); env.test.BEAST_EXPECT(loan)) + { + env.test.BEAST_EXPECT(loan->at(sfPreviousPaymentDueDate) == previousPaymentDate); + env.test.BEAST_EXPECT(loan->at(sfPaymentRemaining) == paymentRemaining); + env.test.BEAST_EXPECT(loan->at(sfNextPaymentDueDate) == nextPaymentDate); + env.test.BEAST_EXPECT(loan->at(sfLoanScale) == loanScale); + env.test.BEAST_EXPECT(loan->at(sfTotalValueOutstanding) == totalValue); + env.test.BEAST_EXPECT(loan->at(sfPrincipalOutstanding) == principalOutstanding); + env.test.BEAST_EXPECT(loan->at(sfManagementFeeOutstanding) == managementFeeOutstanding); + env.test.BEAST_EXPECT(loan->at(sfPeriodicPayment) == periodicPayment); + env.test.BEAST_EXPECT(loan->at(sfFlags) == flags); + + auto const ls = constructRoundedLoanState(loan); + + auto const interestRate = TenthBips32{loan->at(sfInterestRate)}; + auto const paymentInterval = loan->at(sfPaymentInterval); + checkBroker(principalOutstanding, ls.interestDue, interestRate, paymentInterval, paymentRemaining, 1); + + if (auto brokerSle = env.le(keylet::loanbroker(broker.brokerID)); env.test.BEAST_EXPECT(brokerSle)) + { + if (auto vaultSle = env.le(keylet::vault(brokerSle->at(sfVaultID))); + env.test.BEAST_EXPECT(vaultSle)) + { + if ((flags & lsfLoanImpaired) && !(flags & lsfLoanDefault)) + { + env.test.BEAST_EXPECT( + vaultSle->at(sfLossUnrealized) == totalValue - managementFeeOutstanding); + } + else + { + env.test.BEAST_EXPECT(vaultSle->at(sfLossUnrealized) == 0); + } + } + } + } + } + + /** Checks both the loan and broker expect states against the ledger */ + void + operator()(LoanState const& state) const + { + operator()( + state.previousPaymentDate, + state.nextPaymentDate, + state.paymentRemaining, + state.loanScale, + state.totalValue, + state.principalOutstanding, + state.managementFeeOutstanding, + state.periodicPayment, + state.flags); + }; + }; + + BrokerInfo + createVaultAndBroker( + jtx::Env& env, + jtx::PrettyAsset const& asset, + jtx::Account const& lender, + BrokerParameters const& params = BrokerParameters::defaults()) + { + using namespace jtx; + + Vault vault{env}; + + auto const deposit = asset(params.vaultDeposit); + auto const debtMaximumValue = asset(params.debtMax).value(); + auto const coverDepositValue = asset(params.coverDeposit).value(); + + auto const coverRateMinValue = params.coverRateMin; + + auto [tx, vaultKeylet] = vault.create({.owner = lender, .asset = asset}); + env(tx); + env.close(); + BEAST_EXPECT(env.le(vaultKeylet)); + + env(vault.deposit({.depositor = lender, .id = vaultKeylet.key, .amount = deposit})); + env.close(); + if (auto const vault = env.le(keylet::vault(vaultKeylet.key)); BEAST_EXPECT(vault)) + { + BEAST_EXPECT(vault->at(sfAssetsAvailable) == deposit.value()); + } + + auto const keylet = keylet::loanbroker(lender.id(), env.seq(lender)); + + using namespace loanBroker; + env(set(lender, vaultKeylet.key, params.flags), + data(params.data), + managementFeeRate(params.managementFeeRate), + debtMaximum(debtMaximumValue), + coverRateMinimum(coverRateMinValue), + coverRateLiquidation(TenthBips32(params.coverRateLiquidation))); + + if (coverDepositValue != beast::zero) + env(coverDeposit(lender, keylet.key, coverDepositValue)); + + env.close(); + + return {asset, keylet, vaultKeylet, params}; + } + + /// Get the state without checking anything + LoanState + getCurrentState(jtx::Env const& env, BrokerInfo const& broker, Keylet const& loanKeylet) + { + using d = NetClock::duration; + using tp = NetClock::time_point; + + // Lookup the current loan state + if (auto loan = env.le(loanKeylet); BEAST_EXPECT(loan)) + { + return LoanState{ + .previousPaymentDate = loan->at(sfPreviousPaymentDueDate), + .startDate = tp{d{loan->at(sfStartDate)}}, + .nextPaymentDate = loan->at(sfNextPaymentDueDate), + .paymentRemaining = loan->at(sfPaymentRemaining), + .loanScale = loan->at(sfLoanScale), + .totalValue = loan->at(sfTotalValueOutstanding), + .principalOutstanding = loan->at(sfPrincipalOutstanding), + .managementFeeOutstanding = loan->at(sfManagementFeeOutstanding), + .periodicPayment = loan->at(sfPeriodicPayment), + .flags = loan->at(sfFlags), + .paymentInterval = loan->at(sfPaymentInterval), + .interestRate = TenthBips32{loan->at(sfInterestRate)}, + }; + } + return LoanState{}; + } + + /// Get the state and check the values against the parameters used in + /// `lifecycle` + LoanState + getCurrentState( + jtx::Env const& env, + BrokerInfo const& broker, + Keylet const& loanKeylet, + VerifyLoanStatus const& verifyLoanStatus) + { + using namespace std::chrono_literals; + using d = NetClock::duration; + using tp = NetClock::time_point; + + auto const state = getCurrentState(env, broker, loanKeylet); + BEAST_EXPECT(state.previousPaymentDate == 0); + BEAST_EXPECT(tp{d{state.nextPaymentDate}} == state.startDate + 600s); + BEAST_EXPECT(state.paymentRemaining == 12); + BEAST_EXPECT(state.principalOutstanding == broker.asset(1000).value()); + BEAST_EXPECT( + state.loanScale >= + (broker.asset.integral() ? 0 : std::max(broker.vaultScale(env), state.principalOutstanding.exponent()))); + BEAST_EXPECT(state.paymentInterval == 600); + { + NumberRoundModeGuard mg(Number::upward); + BEAST_EXPECT( + state.totalValue == + roundToAsset(broker.asset, state.periodicPayment * state.paymentRemaining, state.loanScale)); + } + BEAST_EXPECT( + state.managementFeeOutstanding == + computeManagementFee( + broker.asset, + state.totalValue - state.principalOutstanding, + broker.params.managementFeeRate, + state.loanScale)); + + verifyLoanStatus(state); + + return state; + } + + bool + canImpairLoan(jtx::Env const& env, BrokerInfo const& broker, LoanState const& state) + { + if (auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + if (auto const vaultSle = env.le(keylet::vault(brokerSle->at(sfVaultID))); BEAST_EXPECT(vaultSle)) + { + // log << vaultSle->getJson() << std::endl; + auto const assetsUnavailable = vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable); + auto const unrealizedLoss = + vaultSle->at(sfLossUnrealized) + state.totalValue - state.managementFeeOutstanding; + + if (!BEAST_EXPECT(unrealizedLoss <= assetsUnavailable)) + { + return false; + } + } + } + return true; + } + + enum class AssetType { XRP = 0, IOU = 1, MPT = 2 }; + + // Specify the accounts as params to allow other accounts to be used + jtx::PrettyAsset + createAsset( + jtx::Env& env, + AssetType assetType, + BrokerParameters const& brokerParams, + jtx::Account const& issuer, + jtx::Account const& lender, + jtx::Account const& borrower) + { + using namespace jtx; + + switch (assetType) + { + case AssetType::XRP: + // TODO: remove the factor, and set up loans in drops + return PrettyAsset{xrpIssue(), 1'000'000}; + + case AssetType::IOU: { + PrettyAsset const asset{issuer[iouCurrency]}; + + auto const limit = asset(100 * (brokerParams.vaultDeposit + brokerParams.coverDeposit)); + if (lender != issuer) + env(trust(lender, limit)); + if (borrower != issuer) + env(trust(borrower, limit)); + + return asset; + } + + case AssetType::MPT: { + // Enough to cover initial fees + if (!env.le(keylet::account(issuer))) + env.fund(env.current()->fees().accountReserve(10) * 10, issuer); + if (!env.le(keylet::account(lender))) + env.fund(env.current()->fees().accountReserve(10) * 10, noripple(lender)); + if (!env.le(keylet::account(borrower))) + env.fund(env.current()->fees().accountReserve(10) * 10, noripple(borrower)); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + // Scale the MPT asset so interest is interesting + PrettyAsset const asset{mptt.issuanceID(), 10'000}; + // Need to do the authorization here because mptt isn't + // accessible outside + if (lender != issuer) + mptt.authorize({.account = lender}); + if (borrower != issuer) + mptt.authorize({.account = borrower}); + + env.close(); + + return asset; + } + + default: + throw std::runtime_error("Unknown asset type"); + } + } + + void + describeLoan( + jtx::Env& env, + BrokerParameters const& brokerParams, + LoanParameters const& loanParams, + AssetType assetType, + jtx::Account const& issuer, + jtx::Account const& lender, + jtx::Account const& borrower) + { + using namespace jtx; + + auto const asset = createAsset(env, assetType, brokerParams, issuer, lender, borrower); + auto const principal = asset(loanParams.principalRequest).number(); + auto const interest = loanParams.interest.value_or(TenthBips32{}); + auto const interval = loanParams.payInterval.value_or(LoanSet::defaultPaymentInterval); + auto const total = loanParams.payTotal.value_or(LoanSet::defaultPaymentTotal); + auto const feeRate = brokerParams.managementFeeRate; + auto const props = computeLoanProperties( + asset, principal, interest, interval, total, feeRate, asset(brokerParams.vaultDeposit).number().exponent()); + log << "Loan properties:\n" + << "\tPrincipal: " << principal << std::endl + << "\tInterest rate: " << interest << std::endl + << "\tPayment interval: " << interval << std::endl + << "\tManagement Fee Rate: " << feeRate << std::endl + << "\tTotal Payments: " << total << std::endl + << "\tPeriodic Payment: " << props.periodicPayment << std::endl + << "\tTotal Value: " << props.loanState.valueOutstanding << std::endl + << "\tManagement Fee: " << props.loanState.managementFeeDue << std::endl + << "\tLoan Scale: " << props.loanScale << std::endl + << "\tFirst payment principal: " << props.firstPaymentPrincipal << std::endl; + + // checkGuards returns a TER, so success is 0 + BEAST_EXPECT(!checkLoanGuards( + asset, + asset(loanParams.principalRequest).number(), + loanParams.interest.value_or(TenthBips32{}) != beast::zero, + loanParams.payTotal.value_or(LoanSet::defaultPaymentTotal), + props, + env.journal)); + } + + std::optional> + createLoan( + jtx::Env& env, + AssetType assetType, + BrokerParameters const& brokerParams, + LoanParameters const& loanParams, + jtx::Account const& issuer, + jtx::Account const& lender, + jtx::Account const& borrower) + { + using namespace jtx; + + // Enough to cover initial fees + env.fund(env.current()->fees().accountReserve(10) * 10, issuer); + if (lender != issuer) + env.fund(env.current()->fees().accountReserve(10) * 10, noripple(lender)); + if (borrower != issuer && borrower != lender) + env.fund(env.current()->fees().accountReserve(10) * 10, noripple(borrower)); + + describeLoan(env, brokerParams, loanParams, assetType, issuer, lender, borrower); + + // Make the asset + auto const asset = createAsset(env, assetType, brokerParams, issuer, lender, borrower); + + env.close(); + if (asset.native() || lender != issuer) + env( + pay((asset.native() ? env.master : issuer), + lender, + asset(brokerParams.vaultDeposit + brokerParams.coverDeposit))); + // Fund the borrower later once we know the total loan + // size + + BrokerInfo const broker = createVaultAndBroker(env, asset, lender, brokerParams); + + auto const pseudoAcctOpt = [&]() -> std::optional { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return std::nullopt; + auto const brokerPseudo = brokerSle->at(sfAccount); + return Account("Broker pseudo-account", brokerPseudo); + }(); + if (!pseudoAcctOpt) + return std::nullopt; + Account const& pseudoAcct = *pseudoAcctOpt; + + auto const loanKeyletOpt = [&]() -> std::optional { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return std::nullopt; + + // Broker has no loans + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); + + // The loan keylet is based on the LoanSequence of the + // _LOAN_BROKER_ object. + auto const loanSequence = brokerSle->at(sfLoanSequence); + return keylet::loan(broker.brokerID, loanSequence); + }(); + if (!loanKeyletOpt) + return std::nullopt; + Keylet const& loanKeylet = *loanKeyletOpt; + + env(loanParams(env, broker)); + + env.close(); + + return std::make_tuple(broker, loanKeylet, pseudoAcct); + } + + void + topUpBorrower( + jtx::Env& env, + BrokerInfo const& broker, + jtx::Account const& issuer, + jtx::Account const& borrower, + LoanState const& state, + std::optional const& servFee) + { + using namespace jtx; + + STAmount const serviceFee = broker.asset(servFee.value_or(0)); + + // Ensure the borrower has enough funds to make the payments + // (including tx fees, if necessary) + auto const borrowerBalance = env.balance(borrower, broker.asset); + + auto const baseFee = env.current()->fees().base; + + // Add extra for transaction fees and reserves, if appropriate, or a + // tiny amount for the extra paid in each transaction + auto const totalNeeded = state.totalValue + (serviceFee * state.paymentRemaining) + + (broker.asset.native() ? Number( + baseFee * state.paymentRemaining + + env.current()->fees().accountReserve(env.ownerCount(borrower))) + : broker.asset(15).number()); + + auto const shortage = totalNeeded - borrowerBalance.number(); + + if (shortage > beast::zero && (broker.asset.native() || issuer != borrower)) + env(pay((broker.asset.native() ? env.master : issuer), borrower, STAmount{broker.asset, shortage})); + } + + void + makeLoanPayments( + jtx::Env& env, + BrokerInfo const& broker, + LoanParameters const& loanParams, + Keylet const& loanKeylet, + VerifyLoanStatus const& verifyLoanStatus, + jtx::Account const& issuer, + jtx::Account const& lender, + jtx::Account const& borrower, + PaymentParameters const& paymentParams = PaymentParameters::defaults()) + { + // Make all the individual payments + using namespace jtx; + using namespace jtx::loan; + using namespace std::chrono_literals; + using d = NetClock::duration; + + bool const showStepBalances = paymentParams.showStepBalances; + + auto const currencyLabel = getCurrencyLabel(broker.asset); + + auto const baseFee = env.current()->fees().base; + + env.close(); + auto state = getCurrentState(env, broker, loanKeylet); + + verifyLoanStatus(state); + + STAmount const serviceFee = broker.asset(loanParams.serviceFee.value_or(0)); + + topUpBorrower(env, broker, issuer, borrower, state, loanParams.serviceFee); + + // Periodic payment amount will consist of + // 1. principal outstanding (1000) + // 2. interest interest rate (at 12%) + // 3. payment interval (600s) + // 4. loan service fee (2) + // Calculate these values without the helper functions + // to verify they're working correctly The numbers in + // the below BEAST_EXPECTs may not hold across assets. + auto const periodicRate = loanPeriodicRate(state.interestRate, state.paymentInterval); + STAmount const roundedPeriodicPayment{ + broker.asset, roundPeriodicPayment(broker.asset, state.periodicPayment, state.loanScale)}; + + if (!showStepBalances) + log << currencyLabel << " Payment components: " + << "Payments remaining, " + << "rawInterest, rawPrincipal, " + "rawMFee, " + << "trackedValueDelta, trackedPrincipalDelta, " + "trackedInterestDelta, trackedMgmtFeeDelta, special" + << std::endl; + + // Include the service fee + STAmount const totalDue = roundToScale(roundedPeriodicPayment + serviceFee, state.loanScale, Number::upward); + + auto currentRoundedState = + constructLoanState(state.totalValue, state.principalOutstanding, state.managementFeeOutstanding); + { + auto const raw = computeTheoreticalLoanState( + state.periodicPayment, periodicRate, state.paymentRemaining, broker.params.managementFeeRate); + + if (showStepBalances) + { + log << currencyLabel << " Starting loan balances: " + << "\n\tTotal value: " << currentRoundedState.valueOutstanding + << "\n\tPrincipal: " << currentRoundedState.principalOutstanding + << "\n\tInterest: " << currentRoundedState.interestDue + << "\n\tMgmt fee: " << currentRoundedState.managementFeeDue << "\n\tPayments remaining " + << state.paymentRemaining << std::endl; + } + else + { + log << currencyLabel << " Loan starting state: " << state.paymentRemaining << ", " << raw.interestDue + << ", " << raw.principalOutstanding << ", " << raw.managementFeeDue << ", " + << currentRoundedState.valueOutstanding << ", " << currentRoundedState.principalOutstanding << ", " + << currentRoundedState.interestDue << ", " << currentRoundedState.managementFeeDue << std::endl; + } + } + + // Try to pay a little extra to show that it's _not_ + // taken + auto const extraAmount = paymentParams.overpaymentExtra + ? broker.asset(*paymentParams.overpaymentExtra).value() + : std::min(broker.asset(10).value(), STAmount{broker.asset, totalDue / 20}); + + STAmount const transactionAmount = + STAmount{broker.asset, totalDue * paymentParams.overpaymentFactor} + extraAmount; + + auto const borrowerInitialBalance = env.balance(borrower, broker.asset).number(); + auto const initialState = state; + detail::PaymentComponents totalPaid{ + .trackedValueDelta = 0, .trackedPrincipalDelta = 0, .trackedManagementFeeDelta = 0}; + Number totalInterestPaid = 0; + Number totalFeesPaid = 0; + std::size_t totalPaymentsMade = 0; + + xrpl::LoanState currentTrueState = computeTheoreticalLoanState( + state.periodicPayment, periodicRate, state.paymentRemaining, broker.params.managementFeeRate); + + auto validateBorrowerBalance = [&]() { + if (borrower == issuer || !paymentParams.validateBalances) + return; + auto const totalSpent = + (totalPaid.trackedValueDelta + totalFeesPaid + + (broker.asset.native() ? Number(baseFee) * totalPaymentsMade : numZero)); + BEAST_EXPECT(env.balance(borrower, broker.asset).number() == borrowerInitialBalance - totalSpent); + }; + + auto const defaultRound = broker.asset.integral() ? 3 : 0; + auto truncate = [defaultRound](Number const& n, std::optional places = std::nullopt) { + auto const p = places.value_or(defaultRound); + if (p == 0) + return n; + auto const factor = Number{1, p}; + return (n * factor).truncate() / factor; + }; + while (state.paymentRemaining > 0) + { + validateBorrowerBalance(); + // Compute the expected principal amount + auto const paymentComponents = detail::computePaymentComponents( + broker.asset.raw(), + state.loanScale, + state.totalValue, + state.principalOutstanding, + state.managementFeeOutstanding, + state.periodicPayment, + periodicRate, + state.paymentRemaining, + broker.params.managementFeeRate); + + BEAST_EXPECT( + paymentComponents.trackedValueDelta <= roundedPeriodicPayment || + (paymentComponents.specialCase == detail::PaymentSpecialCase::final && + paymentComponents.trackedValueDelta >= roundedPeriodicPayment)); + BEAST_EXPECT( + paymentComponents.trackedValueDelta == + paymentComponents.trackedPrincipalDelta + paymentComponents.trackedInterestPart() + + paymentComponents.trackedManagementFeeDelta); + + xrpl::LoanState const nextTrueState = computeTheoreticalLoanState( + state.periodicPayment, periodicRate, state.paymentRemaining - 1, broker.params.managementFeeRate); + detail::LoanStateDeltas const deltas = currentTrueState - nextTrueState; + BEAST_EXPECT(deltas.total() == deltas.principal + deltas.interest + deltas.managementFee); + BEAST_EXPECT( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || + deltas.total() == state.periodicPayment || + (state.loanScale - (deltas.total() - state.periodicPayment).exponent()) > 14); + + if (!showStepBalances) + log << currencyLabel << " Payment components: " << state.paymentRemaining << ", " + + << deltas.interest << ", " << deltas.principal << ", " << deltas.managementFee << ", " + << paymentComponents.trackedValueDelta << ", " << paymentComponents.trackedPrincipalDelta << ", " + << paymentComponents.trackedInterestPart() << ", " << paymentComponents.trackedManagementFeeDelta + << ", " + << (paymentComponents.specialCase == detail::PaymentSpecialCase::final ? "final" + : paymentComponents.specialCase == detail::PaymentSpecialCase::extra ? "extra" + : "none") + << std::endl; + + auto const totalDueAmount = STAmount{broker.asset, paymentComponents.trackedValueDelta + serviceFee}; + + if (paymentParams.validateBalances) + { + // Due to the rounding algorithms to keep the interest and + // principal in sync with "true" values, the computed amount + // may be a little less than the rounded fixed payment + // amount. For integral types, the difference should be < 3 + // (1 unit for each of the interest and management fee). For + // IOUs, the difference should be dust. + Number const diff = totalDue - totalDueAmount; + BEAST_EXPECT( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || diff == beast::zero || + (diff > beast::zero && + ((broker.asset.integral() && (static_cast(diff) < 3)) || + (state.loanScale - diff.exponent() > 13)))); + + BEAST_EXPECT( + paymentComponents.trackedPrincipalDelta >= beast::zero && + paymentComponents.trackedPrincipalDelta <= state.principalOutstanding); + BEAST_EXPECT( + paymentComponents.specialCase != detail::PaymentSpecialCase::final || + paymentComponents.trackedPrincipalDelta == state.principalOutstanding); + } + + auto const borrowerBalanceBeforePayment = env.balance(borrower, broker.asset); + + // Make the payment + env(pay(borrower, loanKeylet.key, transactionAmount, paymentParams.flags)); + + env.close(d{state.paymentInterval / 2}); + + if (paymentParams.validateBalances) + { + // Need to account for fees if the loan is in XRP + PrettyAmount adjustment = broker.asset(0); + if (broker.asset.native()) + { + adjustment = env.current()->fees().base; + } + + // Check the result + verifyLoanStatus.checkPayment( + state.loanScale, borrower, borrowerBalanceBeforePayment, totalDueAmount, adjustment); + } + + if (showStepBalances) + { + auto const loanSle = env.le(loanKeylet); + if (!BEAST_EXPECT(loanSle)) + // No reason for this not to exist + return; + auto const current = constructRoundedLoanState(loanSle); + auto const errors = nextTrueState - current; + log << currencyLabel << " Loan balances: " + << "\n\tAmount taken: " << paymentComponents.trackedValueDelta + << "\n\tTotal value: " << current.valueOutstanding + << " (true: " << truncate(nextTrueState.valueOutstanding) << ", error: " << truncate(errors.total()) + << ")\n\tPrincipal: " << current.principalOutstanding + << " (true: " << truncate(nextTrueState.principalOutstanding) + << ", error: " << truncate(errors.principal) << ")\n\tInterest: " << current.interestDue + << " (true: " << truncate(nextTrueState.interestDue) << ", error: " << truncate(errors.interest) + << ")\n\tMgmt fee: " << current.managementFeeDue + << " (true: " << truncate(nextTrueState.managementFeeDue) + << ", error: " << truncate(errors.managementFee) << ")\n\tPayments remaining " + << loanSle->at(sfPaymentRemaining) << std::endl; + + currentRoundedState = current; + } + + --state.paymentRemaining; + state.previousPaymentDate = state.nextPaymentDate; + if (paymentComponents.specialCase == detail::PaymentSpecialCase::final) + { + state.paymentRemaining = 0; + state.nextPaymentDate = 0; + } + else + { + state.nextPaymentDate += state.paymentInterval; + } + state.principalOutstanding -= paymentComponents.trackedPrincipalDelta; + state.managementFeeOutstanding -= paymentComponents.trackedManagementFeeDelta; + state.totalValue -= paymentComponents.trackedValueDelta; + + if (paymentParams.validateBalances) + verifyLoanStatus(state); + + totalPaid.trackedValueDelta += paymentComponents.trackedValueDelta; + totalPaid.trackedPrincipalDelta += paymentComponents.trackedPrincipalDelta; + totalPaid.trackedManagementFeeDelta += paymentComponents.trackedManagementFeeDelta; + totalInterestPaid += paymentComponents.trackedInterestPart(); + totalFeesPaid += serviceFee; + ++totalPaymentsMade; + + currentTrueState = nextTrueState; + } + validateBorrowerBalance(); + + // Loan is paid off + BEAST_EXPECT(state.paymentRemaining == 0); + BEAST_EXPECT(state.principalOutstanding == 0); + + auto const initialInterestDue = + initialState.totalValue - (initialState.principalOutstanding + initialState.managementFeeOutstanding); + if (paymentParams.validateBalances) + { + // Make sure all the payments add up + BEAST_EXPECT(totalPaid.trackedValueDelta == initialState.totalValue); + BEAST_EXPECT(totalPaid.trackedPrincipalDelta == initialState.principalOutstanding); + BEAST_EXPECT(totalPaid.trackedManagementFeeDelta == initialState.managementFeeOutstanding); + // This is almost a tautology given the previous checks, but + // check it anyway for completeness. + BEAST_EXPECT(totalInterestPaid == initialInterestDue); + BEAST_EXPECT(totalPaymentsMade == initialState.paymentRemaining); + } + + if (showStepBalances) + { + auto const loanSle = env.le(loanKeylet); + if (!BEAST_EXPECT(loanSle)) + // No reason for this not to exist + return; + log << currencyLabel << " Total amounts paid: " + << "\n\tTotal value: " << totalPaid.trackedValueDelta + << " (initial: " << truncate(initialState.totalValue) + << ", error: " << truncate(initialState.totalValue - totalPaid.trackedValueDelta) + << ")\n\tPrincipal: " << totalPaid.trackedPrincipalDelta + << " (initial: " << truncate(initialState.principalOutstanding) + << ", error: " << truncate(initialState.principalOutstanding - totalPaid.trackedPrincipalDelta) + << ")\n\tInterest: " << totalInterestPaid << " (initial: " << truncate(initialInterestDue) + << ", error: " << truncate(initialInterestDue - totalInterestPaid) + << ")\n\tMgmt fee: " << totalPaid.trackedManagementFeeDelta + << " (initial: " << truncate(initialState.managementFeeOutstanding) + << ", error: " << truncate(initialState.managementFeeOutstanding - totalPaid.trackedManagementFeeDelta) + << ")\n\tTotal payments made: " << totalPaymentsMade << std::endl; + } + } + + void + runLoan(AssetType assetType, BrokerParameters const& brokerParams, LoanParameters const& loanParams) + { + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + Env env(*this, all); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower); + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + auto pseudoAcct = std::get(*loanResult); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet); + + makeLoanPayments( + env, + broker, + loanParams, + loanKeylet, + verifyLoanStatus, + issuer, + lender, + borrower, + PaymentParameters{.showStepBalances = true}); + } + + /** Runs through the complete lifecycle of a loan + * + * 1. Create a loan. + * 2. Test a bunch of transaction failure conditions. + * 3. Use the `toEndOfLife` callback to take the loan to 0. How that is done + * depends on the callback. e.g. Default, Early payoff, make all the + * normal payments, etc. + * 4. Delete the loan. The loan will alternate between being deleted by the + * lender and the borrower. + */ + void + lifecycle( + std::string const& caseLabel, + char const* label, + jtx::Env& env, + Number const& loanAmount, + int interestExponent, + jtx::Account const& lender, + jtx::Account const& borrower, + jtx::Account const& evan, + BrokerInfo const& broker, + jtx::Account const& pseudoAcct, + std::uint32_t flags, + // The end of life callback is expected to take the loan to 0 payments + // remaining, one way or another + std::function toEndOfLife) + { + auto const [keylet, loanSequence] = [&]() { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + // will be invalid + return std::make_pair(keylet::loan(broker.brokerID), std::uint32_t(0)); + + // Broker has no loans + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); + + // The loan keylet is based on the LoanSequence of the _LOAN_BROKER_ + // object. + auto const loanSequence = brokerSle->at(sfLoanSequence); + return std::make_pair(keylet::loan(broker.brokerID, loanSequence), loanSequence); + }(); + + VerifyLoanStatus const verifyLoanStatus(env, broker, pseudoAcct, keylet); + + // No loans yet + verifyLoanStatus.checkBroker(0, 0, TenthBips32{0}, 1, 0, 0); + + if (!BEAST_EXPECT(loanSequence != 0)) + return; + + testcase << caseLabel << " " << label; + + using namespace jtx; + using namespace loan; + using namespace std::chrono_literals; + + auto applyExponent = [interestExponent, this](TenthBips32 value) mutable { + BEAST_EXPECT(value > TenthBips32(0)); + while (interestExponent > 0) + { + auto const oldValue = value; + value *= 10; + --interestExponent; + BEAST_EXPECT(value / 10 == oldValue); + } + while (interestExponent < 0) + { + auto const oldValue = value; + value /= 10; + ++interestExponent; + BEAST_EXPECT(value * 10 == oldValue); + } + return value; + }; + + auto const borrowerOwnerCount = env.ownerCount(borrower); + + auto const loanSetFee = env.current()->fees().base * 2; + LoanParameters const loanParams{ + .account = borrower, + .counter = lender, + .counterpartyExplicit = false, + .principalRequest = loanAmount, + .setFee = loanSetFee, + .originationFee = 1, + .serviceFee = 2, + .lateFee = 3, + .closeFee = 4, + .overFee = applyExponent(percentageToTenthBips(5) / 10), + .interest = applyExponent(percentageToTenthBips(12)), + // 2.4% + .lateInterest = applyExponent(percentageToTenthBips(24) / 10), + .closeInterest = applyExponent(percentageToTenthBips(36) / 10), + .overpaymentInterest = applyExponent(percentageToTenthBips(48) / 10), + .payTotal = 12, + .payInterval = 600, + .gracePd = 60, + .flags = flags, + }; + Number const principalRequestAmount = broker.asset(loanParams.principalRequest).value(); + auto const originationFeeAmount = broker.asset(*loanParams.originationFee).value(); + auto const serviceFeeAmount = broker.asset(*loanParams.serviceFee).value(); + auto const lateFeeAmount = broker.asset(*loanParams.lateFee).value(); + auto const closeFeeAmount = broker.asset(*loanParams.closeFee).value(); + + auto const borrowerStartbalance = env.balance(borrower, broker.asset); + + auto createJtx = loanParams(env, broker); + // Successfully create a Loan + env(createJtx); + + env.close(); + + auto const startDate = env.current()->header().parentCloseTime.time_since_epoch().count(); + + if (auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 1); + } + + { + // Need to account for fees if the loan is in XRP + PrettyAmount adjustment = broker.asset(0); + if (broker.asset.native()) + { + adjustment = 2 * env.current()->fees().base; + } + + BEAST_EXPECT( + env.balance(borrower, broker.asset).value() == + borrowerStartbalance.value() + principalRequestAmount - originationFeeAmount - adjustment.value()); + } + + auto const loanFlags = createJtx.stx->isFlag(tfLoanOverpayment) ? lsfLoanOverpayment : LedgerSpecificFlags(0); + + if (auto loan = env.le(keylet); BEAST_EXPECT(loan)) + { + // log << "loan after create: " << to_string(loan->getJson()) + // << std::endl; + BEAST_EXPECT(loan->isFlag(lsfLoanOverpayment) == createJtx.stx->isFlag(tfLoanOverpayment)); + BEAST_EXPECT(loan->at(sfLoanSequence) == loanSequence); + BEAST_EXPECT(loan->at(sfBorrower) == borrower.id()); + BEAST_EXPECT(loan->at(sfLoanBrokerID) == broker.brokerID); + BEAST_EXPECT(loan->at(sfLoanOriginationFee) == originationFeeAmount); + BEAST_EXPECT(loan->at(sfLoanServiceFee) == serviceFeeAmount); + BEAST_EXPECT(loan->at(sfLatePaymentFee) == lateFeeAmount); + BEAST_EXPECT(loan->at(sfClosePaymentFee) == closeFeeAmount); + BEAST_EXPECT(loan->at(sfOverpaymentFee) == *loanParams.overFee); + BEAST_EXPECT(loan->at(sfInterestRate) == *loanParams.interest); + BEAST_EXPECT(loan->at(sfLateInterestRate) == *loanParams.lateInterest); + BEAST_EXPECT(loan->at(sfCloseInterestRate) == *loanParams.closeInterest); + BEAST_EXPECT(loan->at(sfOverpaymentInterestRate) == *loanParams.overpaymentInterest); + BEAST_EXPECT(loan->at(sfStartDate) == startDate); + BEAST_EXPECT(loan->at(sfPaymentInterval) == *loanParams.payInterval); + BEAST_EXPECT(loan->at(sfGracePeriod) == *loanParams.gracePd); + BEAST_EXPECT(loan->at(sfPreviousPaymentDueDate) == 0); + BEAST_EXPECT(loan->at(sfNextPaymentDueDate) == startDate + *loanParams.payInterval); + BEAST_EXPECT(loan->at(sfPaymentRemaining) == *loanParams.payTotal); + BEAST_EXPECT( + loan->at(sfLoanScale) >= + (broker.asset.integral() ? 0 : std::max(broker.vaultScale(env), principalRequestAmount.exponent()))); + BEAST_EXPECT(loan->at(sfPrincipalOutstanding) == principalRequestAmount); + } + + auto state = getCurrentState(env, broker, keylet, verifyLoanStatus); + + auto const loanProperties = computeLoanProperties( + broker.asset.raw(), + state.principalOutstanding, + state.interestRate, + state.paymentInterval, + state.paymentRemaining, + broker.params.managementFeeRate, + state.loanScale); + + verifyLoanStatus( + 0, + startDate + *loanParams.payInterval, + *loanParams.payTotal, + state.loanScale, + loanProperties.loanState.valueOutstanding, + principalRequestAmount, + loanProperties.loanState.managementFeeDue, + loanProperties.periodicPayment, + loanFlags | 0); + + // Manage the loan + // no-op + env(manage(lender, keylet.key, 0)); + { + // no flags + auto jt = manage(lender, keylet.key, 0); + jt.removeMember(sfFlags.getName()); + env(jt); + } + // Only the lender can manage + env(manage(evan, keylet.key, 0), ter(tecNO_PERMISSION)); + // unknown flags + env(manage(lender, keylet.key, tfLoanManageMask), ter(temINVALID_FLAG)); + // combinations of flags are not allowed + env(manage(lender, keylet.key, tfLoanUnimpair | tfLoanImpair), ter(temINVALID_FLAG)); + env(manage(lender, keylet.key, tfLoanImpair | tfLoanDefault), ter(temINVALID_FLAG)); + env(manage(lender, keylet.key, tfLoanUnimpair | tfLoanDefault), ter(temINVALID_FLAG)); + env(manage(lender, keylet.key, tfLoanUnimpair | tfLoanImpair | tfLoanDefault), ter(temINVALID_FLAG)); + // invalid loan ID + env(manage(lender, broker.brokerID, tfLoanImpair), ter(tecNO_ENTRY)); + // Loan is unimpaired, can't unimpair it again + env(manage(lender, keylet.key, tfLoanUnimpair), ter(tecNO_PERMISSION)); + // Loan is unimpaired, it can go into default, but only after it's past + // due + env(manage(lender, keylet.key, tfLoanDefault), ter(tecTOO_SOON)); + + // Check the vault + bool const canImpair = canImpairLoan(env, broker, state); + // Impair the loan, if possible + env(manage(lender, keylet.key, tfLoanImpair), canImpair ? ter(tesSUCCESS) : ter(tecLIMIT_EXCEEDED)); + // Unimpair the loan + env(manage(lender, keylet.key, tfLoanUnimpair), canImpair ? ter(tesSUCCESS) : ter(tecNO_PERMISSION)); + + auto const nextDueDate = startDate + *loanParams.payInterval; + + env.close(); + + verifyLoanStatus( + 0, + nextDueDate, + *loanParams.payTotal, + loanProperties.loanScale, + loanProperties.loanState.valueOutstanding, + principalRequestAmount, + loanProperties.loanState.managementFeeDue, + loanProperties.periodicPayment, + loanFlags | 0); + + // Can't delete the loan yet. It has payments remaining. + env(del(lender, keylet.key), ter(tecHAS_OBLIGATIONS)); + + if (BEAST_EXPECT(toEndOfLife)) + toEndOfLife(keylet, verifyLoanStatus); + env.close(); + + // Verify the loan is at EOL + if (auto loan = env.le(keylet); BEAST_EXPECT(loan)) + { + BEAST_EXPECT(loan->at(sfPaymentRemaining) == 0); + BEAST_EXPECT(loan->at(sfPrincipalOutstanding) == 0); + } + auto const borrowerStartingBalance = env.balance(borrower, broker.asset); + + // Try to delete the loan broker with an active loan + env(loanBroker::del(lender, broker.brokerID), ter(tecHAS_OBLIGATIONS)); + // Ensure the above tx doesn't get ordered after the LoanDelete and + // delete our broker! + env.close(); + + // Test failure cases + env(del(lender, keylet.key, tfLoanOverpayment), ter(temINVALID_FLAG)); + env(del(evan, keylet.key), ter(tecNO_PERMISSION)); + env(del(lender, broker.brokerID), ter(tecNO_ENTRY)); + + // Delete the loan + // Either the borrower or the lender can delete the loan. Alternate + // between who does it across tests. + static unsigned deleteCounter = 0; + auto const deleter = ++deleteCounter % 2 ? lender : borrower; + env(del(deleter, keylet.key)); + env.close(); + + PrettyAmount adjustment = broker.asset(0); + if (deleter == borrower) + { + // Need to account for fees if the loan is in XRP + if (broker.asset.native()) + { + adjustment = env.current()->fees().base; + } + } + + // No loans left + verifyLoanStatus.checkBroker(0, 0, *loanParams.interest, 1, 0, 0); + + BEAST_EXPECT(env.balance(borrower, broker.asset).value() == borrowerStartingBalance.value() - adjustment); + BEAST_EXPECT(env.ownerCount(borrower) == borrowerOwnerCount); + + if (auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); + } + } + + std::string + getCurrencyLabel(Asset const& asset) + { + return (asset.native() ? "XRP" : asset.holds() ? "IOU" : asset.holds() ? "MPT" : "Unknown"); + } + + /** Wrapper to run a series of lifecycle tests for a given asset and loan + * amount + * + * Will be used in the future to vary the loan parameters. For now, it is + * only called once. + * + * Tests a bunch of LoanSet failure conditions before lifecycle. + */ + template + void + testCaseWrapper( + jtx::Env& env, + jtx::MPTTester& mptt, + std::array const& assets, + BrokerInfo const& broker, + Number const& loanAmount, + int interestExponent) + { + using namespace jtx; + using namespace Lending; + + auto const& asset = broker.asset.raw(); + auto const currencyLabel = getCurrencyLabel(asset); + auto const caseLabel = [&]() { + std::stringstream ss; + ss << "Lifecycle: " << loanAmount << " " << currencyLabel << " Scale interest to: " << interestExponent + << " "; + return ss.str(); + }(); + testcase << caseLabel; + + using namespace loan; + using namespace std::chrono_literals; + using d = NetClock::duration; + using tp = NetClock::time_point; + + Account const issuer{"issuer"}; + // For simplicity, lender will be the sole actor for the vault & + // brokers. + Account const lender{"lender"}; + // Borrower only wants to borrow + Account const borrower{"borrower"}; + // Evan will attempt to be naughty + Account const evan{"evan"}; + // Do not fund alice + Account const alice{"alice"}; + + Number const principalRequest = broker.asset(loanAmount).value(); + Number const maxCoveredLoanValue = broker.params.maxCoveredLoanValue(0); + BEAST_EXPECT(maxCoveredLoanValue == 1000 * 100 / 10); + Number const maxCoveredLoanRequest = broker.asset(maxCoveredLoanValue).value(); + Number const totalVaultRequest = broker.asset(broker.params.vaultDeposit).value(); + Number const debtMaximumRequest = broker.asset(broker.params.debtMax).value(); + + auto const loanSetFee = fee(env.current()->fees().base * 2); + + auto const pseudoAcct = [&]() { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return lender; + auto const brokerPseudo = brokerSle->at(sfAccount); + return Account("Broker pseudo-account", brokerPseudo); + }(); + + auto const baseFee = env.current()->fees().base; + + auto badKeylet = keylet::vault(lender.id(), env.seq(lender)); + // Try some failure cases + // flags are checked first + env(set(evan, broker.brokerID, principalRequest, tfLoanSetMask), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(temINVALID_FLAG)); + + // field length validation + // sfData: good length, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + data(std::string(maxDataPayloadLength, 'X')), + loanSetFee, + ter(tefBAD_AUTH)); + // sfData: too long + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + data(std::string(maxDataPayloadLength + 1, 'Y')), + loanSetFee, + ter(temINVALID)); + + // field range validation + // sfOverpaymentFee: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + overpaymentFee(maxOverpaymentFee), + loanSetFee, + ter(tefBAD_AUTH)); + // sfOverpaymentFee: too big + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + overpaymentFee(maxOverpaymentFee + 1), + loanSetFee, + ter(temINVALID)); + + // sfInterestRate: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + interestRate(maxInterestRate), + loanSetFee, + ter(tefBAD_AUTH)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + interestRate(TenthBips32(0)), + loanSetFee, + ter(tefBAD_AUTH)); + // sfInterestRate: too big + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + interestRate(maxInterestRate + 1), + loanSetFee, + ter(temINVALID)); + // sfInterestRate: too small + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + interestRate(TenthBips32(-1)), + loanSetFee, + ter(temINVALID)); + + // sfLateInterestRate: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + lateInterestRate(maxLateInterestRate), + loanSetFee, + ter(tefBAD_AUTH)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + lateInterestRate(TenthBips32(0)), + loanSetFee, + ter(tefBAD_AUTH)); + // sfLateInterestRate: too big + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + lateInterestRate(maxLateInterestRate + 1), + loanSetFee, + ter(temINVALID)); + // sfLateInterestRate: too small + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + lateInterestRate(TenthBips32(-1)), + loanSetFee, + ter(temINVALID)); + + // sfCloseInterestRate: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + closeInterestRate(maxCloseInterestRate), + loanSetFee, + ter(tefBAD_AUTH)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + closeInterestRate(TenthBips32(0)), + loanSetFee, + ter(tefBAD_AUTH)); + // sfCloseInterestRate: too big + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + closeInterestRate(maxCloseInterestRate + 1), + loanSetFee, + ter(temINVALID)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + closeInterestRate(TenthBips32(-1)), + loanSetFee, + ter(temINVALID)); + + // sfOverpaymentInterestRate: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + overpaymentInterestRate(maxOverpaymentInterestRate), + loanSetFee, + ter(tefBAD_AUTH)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + overpaymentInterestRate(TenthBips32(0)), + loanSetFee, + ter(tefBAD_AUTH)); + // sfOverpaymentInterestRate: too big + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + overpaymentInterestRate(maxOverpaymentInterestRate + 1), + loanSetFee, + ter(temINVALID)); + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + overpaymentInterestRate(TenthBips32(-1)), + loanSetFee, + ter(temINVALID)); + + // sfPaymentTotal: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + paymentTotal(LoanSet::minPaymentTotal), + loanSetFee, + ter(tefBAD_AUTH)); + // sfPaymentTotal: too small (there is no max) + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + paymentTotal(LoanSet::minPaymentTotal - 1), + loanSetFee, + ter(temINVALID)); + + // sfPaymentInterval: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + paymentInterval(LoanSet::minPaymentInterval), + loanSetFee, + ter(tefBAD_AUTH)); + // sfPaymentInterval: too small (there is no max) + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + paymentInterval(LoanSet::minPaymentInterval - 1), + loanSetFee, + ter(temINVALID)); + + // sfGracePeriod: good value, bad account + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, borrower), + paymentInterval(LoanSet::minPaymentInterval * 2), + gracePeriod(LoanSet::minPaymentInterval * 2), + loanSetFee, + ter(tefBAD_AUTH)); + // sfGracePeriod: larger than paymentInterval + env(set(evan, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + paymentInterval(LoanSet::minPaymentInterval * 2), + gracePeriod(LoanSet::minPaymentInterval * 3), + loanSetFee, + ter(temINVALID)); + + // insufficient fee - single sign + env(set(borrower, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + ter(telINSUF_FEE_P)); + // insufficient fee - multisign + env(signers(lender, 2, {{evan, 1}, {borrower, 1}})); + env(signers(borrower, 2, {{evan, 1}, {lender, 1}})); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(evan, lender), + msig(sfCounterpartySignature, evan, borrower), + fee(env.current()->fees().base * 5 - 1), + ter(telINSUF_FEE_P)); + // Bad multisign signatures for borrower (Account) + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(alice, issuer), + msig(sfCounterpartySignature, evan, borrower), + fee(env.current()->fees().base * 5), + ter(tefBAD_SIGNATURE)); + // Bad multisign signatures for issuer (Counterparty) + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(evan, lender), + msig(sfCounterpartySignature, alice, issuer), + fee(env.current()->fees().base * 5 - 1), + ter(tefBAD_SIGNATURE)); + env(signers(lender, none)); + env(signers(borrower, none)); + // multisign sufficient fee, but no signers set up + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(evan, lender), + msig(sfCounterpartySignature, evan, borrower), + fee(env.current()->fees().base * 5), + ter(tefNOT_MULTI_SIGNING)); + // not the broker owner, no counterparty, not signed by broker + // owner + env(set(borrower, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, evan), + loanSetFee, + ter(tefBAD_AUTH)); + // not the broker owner, counterparty is borrower + env(set(evan, broker.brokerID, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + loanSetFee, + ter(tecNO_PERMISSION)); + // not a LoanBroker object, no counterparty + env(set(lender, badKeylet.key, principalRequest), + sig(sfCounterpartySignature, evan), + loanSetFee, + ter(temBAD_SIGNER)); + // not a LoanBroker object, counterparty is valid + env(set(lender, badKeylet.key, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + loanSetFee, + ter(tecNO_ENTRY)); + // borrower doesn't exist + env(set(lender, broker.brokerID, principalRequest), + counterparty(alice), + sig(sfCounterpartySignature, alice), + loanSetFee, + ter(terNO_ACCOUNT)); + + // Request more funds than the vault has available + env(set(evan, broker.brokerID, totalVaultRequest + 1), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecINSUFFICIENT_FUNDS)); + + // Request more funds than the broker's first-loss capital can + // cover. + env(set(evan, broker.brokerID, maxCoveredLoanRequest + 1), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecINSUFFICIENT_FUNDS)); + + // Frozen trust line / locked MPT issuance + // XRP can not be frozen, but run through the loop anyway to test + // the tecLIMIT_EXCEEDED case + { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return; + + auto const vaultPseudo = [&]() { + auto const vaultSle = env.le(keylet::vault(brokerSle->at(sfVaultID))); + if (!BEAST_EXPECT(vaultSle)) + // This will be wrong, but the test has failed anyway. + return lender; + auto const vaultPseudo = Account("Vault pseudo-account", vaultSle->at(sfAccount)); + return vaultPseudo; + }(); + + auto const [freeze, deepfreeze, unfreeze, expectedResult] = + [&]() -> std::tuple< + std::function, + std::function, + std::function, + TER> { + // Freeze / lock the asset + std::function empty; + if (broker.asset.native()) + { + // XRP can't be frozen + return std::make_tuple(empty, empty, empty, tesSUCCESS); + } + else if (broker.asset.holds()) + { + auto freeze = [&](Account const& holder) { + env(trust(issuer, holder[iouCurrency](0), tfSetFreeze)); + }; + auto deepfreeze = [&](Account const& holder) { + env(trust(issuer, holder[iouCurrency](0), tfSetFreeze | tfSetDeepFreeze)); + }; + auto unfreeze = [&](Account const& holder) { + env(trust(issuer, holder[iouCurrency](0), tfClearFreeze | tfClearDeepFreeze)); + }; + return std::make_tuple(freeze, deepfreeze, unfreeze, tecFROZEN); + } + else + { + auto freeze = [&](Account const& holder) { + mptt.set({.account = issuer, .holder = holder, .flags = tfMPTLock}); + }; + auto unfreeze = [&](Account const& holder) { + mptt.set({.account = issuer, .holder = holder, .flags = tfMPTUnlock}); + }; + return std::make_tuple(freeze, empty, unfreeze, tecLOCKED); + } + }(); + + // Try freezing the accounts that can't be frozen + if (freeze) + { + for (auto const& account : {vaultPseudo, evan}) + { + // Freeze the account + freeze(account); + + // Try to create a loan with a frozen line + env(set(evan, broker.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(expectedResult)); + + // Unfreeze the account + BEAST_EXPECT(unfreeze); + unfreeze(account); + + // Ensure the line is unfrozen with a request that is fine + // except too it requests more principal than the broker can + // carry + env(set(evan, broker.brokerID, debtMaximumRequest + 1), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecLIMIT_EXCEEDED)); + } + } + + // Deep freeze the borrower, which prevents them from receiving + // funds + if (deepfreeze) + { + // Make sure evan has a trust line that so the issuer can + // freeze it. (Don't need to do this for the borrower, + // because LoanSet will create a line to the borrower + // automatically.) + env(trust(evan, issuer[iouCurrency](100'000))); + + for (auto const& account : {// these accounts can't be frozen, which deep freeze + // implies + vaultPseudo, + evan, + // these accounts can't be deep frozen + lender}) + { + // Freeze evan + deepfreeze(account); + + // Try to create a loan with a deep frozen line + env(set(evan, broker.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(expectedResult)); + + // Unfreeze evan + BEAST_EXPECT(unfreeze); + unfreeze(account); + + // Ensure the line is unfrozen with a request that is fine + // except too it requests more principal than the broker can + // carry + env(set(evan, broker.brokerID, debtMaximumRequest + 1), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecLIMIT_EXCEEDED)); + } + } + } + + // Finally! Create a loan + std::string testData; + + auto coverAvailable = [&env, this](uint256 const& brokerID, Number const& expected) { + if (auto const brokerSle = env.le(keylet::loanbroker(brokerID)); BEAST_EXPECT(brokerSle)) + { + auto const available = brokerSle->at(sfCoverAvailable); + BEAST_EXPECT(available == expected); + return available; + } + return Number{}; + }; + auto getDefaultInfo = [&env, this](LoanState const& state, BrokerInfo const& broker) { + if (auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + BEAST_EXPECT( + state.loanScale >= (broker.asset.integral() + ? 0 + : std::max(broker.vaultScale(env), state.principalOutstanding.exponent()))); + NumberRoundModeGuard mg(Number::upward); + auto const defaultAmount = roundToAsset( + broker.asset, + std::min( + tenthBipsOfValue( + tenthBipsOfValue(brokerSle->at(sfDebtTotal), broker.params.coverRateMin), + broker.params.coverRateLiquidation), + state.totalValue - state.managementFeeOutstanding), + state.loanScale); + return std::make_pair(defaultAmount, brokerSle->at(sfOwner)); + } + return std::make_pair(Number{}, AccountID{}); + }; + auto replenishCover = [&env, &coverAvailable]( + BrokerInfo const& broker, + AccountID const& brokerAcct, + Number const& startingCoverAvailable, + Number const& amountToBeCovered) { + coverAvailable(broker.brokerID, startingCoverAvailable - amountToBeCovered); + env(loanBroker::coverDeposit(brokerAcct, broker.brokerID, STAmount{broker.asset, amountToBeCovered})); + coverAvailable(broker.brokerID, startingCoverAvailable); + env.close(); + }; + + auto defaultImmediately = [&](std::uint32_t baseFlag, bool impair = true) { + return [&, impair, baseFlag](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { + // toEndOfLife + // + // Default the loan + + // Initialize values with the current state + auto state = getCurrentState(env, broker, loanKeylet, verifyLoanStatus); + BEAST_EXPECT(state.flags == baseFlag); + + auto const& broker = verifyLoanStatus.broker; + auto const startingCoverAvailable = + coverAvailable(broker.brokerID, broker.asset(broker.params.coverDeposit).number()); + + if (impair) + { + // Check the vault + bool const canImpair = canImpairLoan(env, broker, state); + // Impair the loan, if possible + env(manage(lender, loanKeylet.key, tfLoanImpair), + canImpair ? ter(tesSUCCESS) : ter(tecLIMIT_EXCEEDED)); + + if (canImpair) + { + state.flags |= tfLoanImpair; + state.nextPaymentDate = env.now().time_since_epoch().count(); + + // Once the loan is impaired, it can't be impaired again + env(manage(lender, loanKeylet.key, tfLoanImpair), ter(tecNO_PERMISSION)); + } + verifyLoanStatus(state); + } + + auto const nextDueDate = tp{d{state.nextPaymentDate}}; + + // Can't default the loan yet. The grace period hasn't + // expired + env(manage(lender, loanKeylet.key, tfLoanDefault), ter(tecTOO_SOON)); + + // Let some time pass so that the loan can be + // defaulted + env.close(nextDueDate + 60s); + + auto const [amountToBeCovered, brokerAcct] = getDefaultInfo(state, broker); + + // Default the loan + env(manage(lender, loanKeylet.key, tfLoanDefault)); + env.close(); + + // The LoanBroker just lost some of it's first-loss capital. + // Replenish it. + replenishCover(broker, brokerAcct, startingCoverAvailable, amountToBeCovered); + + state.flags |= tfLoanDefault; + state.paymentRemaining = 0; + state.totalValue = 0; + state.principalOutstanding = 0; + state.managementFeeOutstanding = 0; + state.nextPaymentDate = 0; + verifyLoanStatus(state); + + // Once a loan is defaulted, it can't be managed + env(manage(lender, loanKeylet.key, tfLoanUnimpair), ter(tecNO_PERMISSION)); + env(manage(lender, loanKeylet.key, tfLoanImpair), ter(tecNO_PERMISSION)); + // Can't make a payment on it either + env(pay(borrower, loanKeylet.key, broker.asset(300)), ter(tecKILLED)); + }; + }; + + auto singlePayment = [&](Keylet const& loanKeylet, + VerifyLoanStatus const& verifyLoanStatus, + LoanState& state, + STAmount const& payoffAmount, + std::uint32_t numPayments, + std::uint32_t baseFlag, + std::uint32_t txFlags) { + // toEndOfLife + // + verifyLoanStatus(state); + + // Send some bogus pay transactions + env(pay(borrower, keylet::loan(uint256(0)).key, broker.asset(10), txFlags), ter(temINVALID)); + // broker.asset(80) is less than a single payment, but all these + // checks fail before that matters + env(pay(borrower, loanKeylet.key, broker.asset(-80), txFlags), ter(temBAD_AMOUNT)); + env(pay(borrower, broker.brokerID, broker.asset(80), txFlags), ter(tecNO_ENTRY)); + env(pay(evan, loanKeylet.key, broker.asset(80), txFlags), ter(tecNO_PERMISSION)); + + // TODO: Write a general "isFlag" function? See STObject::isFlag. + // Maybe add a static overloaded member? + if (!(state.flags & lsfLoanOverpayment)) + { + // If the loan does not allow overpayments, send a payment that + // tries to make an overpayment. Do not include `txFlags`, so we + // don't end up duplicating the next test transaction. + env(pay(borrower, + loanKeylet.key, + STAmount{broker.asset, state.periodicPayment * Number{15, -1}}, + tfLoanOverpayment), + fee(XRPAmount{baseFee * (Number{15, -1} / loanPaymentsPerFeeIncrement + 1)}), + ter(temINVALID_FLAG)); + } + // Try to send a payment marked as multiple mutually exclusive + // payment types. Do not include `txFlags`, so we don't duplicate + // the prior test transaction. + env(pay(borrower, + loanKeylet.key, + broker.asset(state.periodicPayment * 2), + tfLoanLatePayment | tfLoanFullPayment), + ter(temINVALID_FLAG)); + env(pay(borrower, + loanKeylet.key, + broker.asset(state.periodicPayment * 2), + tfLoanLatePayment | tfLoanOverpayment), + ter(temINVALID_FLAG)); + env(pay(borrower, + loanKeylet.key, + broker.asset(state.periodicPayment * 2), + tfLoanOverpayment | tfLoanFullPayment), + ter(temINVALID_FLAG)); + env(pay(borrower, + loanKeylet.key, + broker.asset(state.periodicPayment * 2), + tfLoanLatePayment | tfLoanOverpayment | tfLoanFullPayment), + ter(temINVALID_FLAG)); + + { + auto const otherAsset = broker.asset.raw() == assets[0].raw() ? assets[1] : assets[0]; + env(pay(borrower, loanKeylet.key, otherAsset(100), txFlags), ter(tecWRONG_ASSET)); + } + + // Amount doesn't cover a single payment + env(pay(borrower, loanKeylet.key, STAmount{broker.asset, 1}, txFlags), ter(tecINSUFFICIENT_PAYMENT)); + + // Get the balance after these failed transactions take + // fees + auto const borrowerBalanceBeforePayment = env.balance(borrower, broker.asset); + + BEAST_EXPECT(payoffAmount > state.principalOutstanding); + // Try to pay a little extra to show that it's _not_ + // taken + auto const transactionAmount = payoffAmount + broker.asset(10); + + // Send a transaction that tries to pay more than the borrowers's + // balance + XRPAmount const badFee{ + baseFee * + (borrowerBalanceBeforePayment.number() * 2 / state.periodicPayment / loanPaymentsPerFeeIncrement + 1)}; + env(pay(borrower, + loanKeylet.key, + STAmount{broker.asset, borrowerBalanceBeforePayment.number() * 2}, + txFlags), + fee(badFee), + ter(tecINSUFFICIENT_FUNDS)); + + XRPAmount const goodFee{baseFee * (numPayments / loanPaymentsPerFeeIncrement + 1)}; + env(pay(borrower, loanKeylet.key, transactionAmount, txFlags), fee(goodFee)); + + env.close(); + + // log << env.meta()->getJson() << std::endl; + + // Need to account for fees if the loan is in XRP + PrettyAmount adjustment = broker.asset(0); + if (broker.asset.native()) + { + adjustment = badFee + goodFee; + } + + state.paymentRemaining = 0; + state.principalOutstanding = 0; + state.totalValue = 0; + state.managementFeeOutstanding = 0; + state.previousPaymentDate = state.nextPaymentDate + state.paymentInterval * (numPayments - 1); + state.nextPaymentDate = 0; + verifyLoanStatus(state); + + verifyLoanStatus.checkPayment( + state.loanScale, borrower, borrowerBalanceBeforePayment, payoffAmount, adjustment); + + // Can't impair or default a paid off loan + env(manage(lender, loanKeylet.key, tfLoanImpair), ter(tecNO_PERMISSION)); + env(manage(lender, loanKeylet.key, tfLoanDefault), ter(tecNO_PERMISSION)); + }; + + auto fullPayment = [&](std::uint32_t baseFlag) { + return [&, baseFlag](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { + // toEndOfLife + // + auto state = getCurrentState(env, broker, loanKeylet, verifyLoanStatus); + env.close(state.startDate + 20s); + auto const loanAge = (env.now() - state.startDate).count(); + BEAST_EXPECT(loanAge == 30); + + // Full payoff amount will consist of + // 1. principal outstanding (1000) + // 2. accrued interest (at 12%) + // 3. prepayment penalty (closeInterest at 3.6%) + // 4. close payment fee (4) + // Calculate these values without the helper functions + // to verify they're working correctly The numbers in + // the below BEAST_EXPECTs may not hold across assets. + Number const interval = state.paymentInterval; + auto const periodicRate = interval * Number(12, -2) / secondsInYear; + BEAST_EXPECT(periodicRate == Number(2283105022831050228ULL, -24, Number::normalized{})); + STAmount const principalOutstanding{broker.asset, state.principalOutstanding}; + STAmount const accruedInterest{ + broker.asset, state.principalOutstanding * periodicRate * loanAge / interval}; + BEAST_EXPECT(accruedInterest == broker.asset(Number(1141552511415525, -19))); + STAmount const prepaymentPenalty{broker.asset, state.principalOutstanding * Number(36, -3)}; + BEAST_EXPECT(prepaymentPenalty == broker.asset(36)); + STAmount const closePaymentFee = broker.asset(4); + auto const payoffAmount = roundToScale( + principalOutstanding + accruedInterest + prepaymentPenalty + closePaymentFee, state.loanScale); + BEAST_EXPECT( + payoffAmount == + roundToAsset(broker.asset, broker.asset(Number(1040000114155251, -12)).number(), state.loanScale)); + + // The terms of this loan actually make the early payoff + // more expensive than just making payments + BEAST_EXPECT(payoffAmount > state.paymentRemaining * (state.periodicPayment + broker.asset(2).value())); + + singlePayment(loanKeylet, verifyLoanStatus, state, payoffAmount, 1, baseFlag, tfLoanFullPayment); + }; + }; + + auto combineAllPayments = [&](std::uint32_t baseFlag) { + return [&, baseFlag](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { + // toEndOfLife + // + + auto state = getCurrentState(env, broker, loanKeylet, verifyLoanStatus); + env.close(); + + BEAST_EXPECT( + STAmount(broker.asset, state.periodicPayment) == broker.asset(Number(8333457002039338267, -17))); + + // Make all the payments in one transaction + // service fee is 2 + auto const startingPayments = state.paymentRemaining; + STAmount const payoffAmount = [&]() { + NumberRoundModeGuard mg(Number::upward); + auto const rawPayoff = startingPayments * (state.periodicPayment + broker.asset(2).value()); + STAmount payoffAmount{broker.asset, rawPayoff}; + BEAST_EXPECTS(payoffAmount == broker.asset(Number(1024014840244721, -12)), to_string(payoffAmount)); + BEAST_EXPECT(payoffAmount > state.principalOutstanding); + + payoffAmount = roundToScale(payoffAmount, state.loanScale); + + return payoffAmount; + }(); + + auto const totalPayoffValue = state.totalValue + startingPayments * broker.asset(2).value(); + STAmount const totalPayoffAmount{broker.asset, totalPayoffValue}; + + BEAST_EXPECTS( + totalPayoffAmount == payoffAmount, + "Payoff amount: " + to_string(payoffAmount) + ". Total Value: " + to_string(totalPayoffAmount)); + + singlePayment(loanKeylet, verifyLoanStatus, state, payoffAmount, state.paymentRemaining, baseFlag, 0); + }; + }; + + // There are a lot of fields that can be set on a loan, but most + // of them only affect the "math" when a payment is made. The + // only one that really affects behavior is the + // `tfLoanOverpayment` flag. + lifecycle( + caseLabel, + "Loan overpayment allowed - Impair and Default", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + defaultImmediately(lsfLoanOverpayment)); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Impair and Default", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + 0, + defaultImmediately(0)); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Default without Impair", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + defaultImmediately(lsfLoanOverpayment, false)); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Default without Impair", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + 0, + defaultImmediately(0, false)); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Pay off immediately", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + 0, + fullPayment(0)); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Pay off immediately", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + fullPayment(lsfLoanOverpayment)); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Combine all payments", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + 0, + combineAllPayments(0)); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Combine all payments", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + combineAllPayments(lsfLoanOverpayment)); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Make payments", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + 0, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { + // toEndOfLife + // + // Draw and make multiple payments + auto state = getCurrentState(env, broker, loanKeylet, verifyLoanStatus); + BEAST_EXPECT(state.flags == 0); + env.close(); + + verifyLoanStatus(state); + + env.close(state.startDate + 20s); + auto const loanAge = (env.now() - state.startDate).count(); + BEAST_EXPECT(loanAge == 30); + + // Periodic payment amount will consist of + // 1. principal outstanding (1000) + // 2. interest interest rate (at 12%) + // 3. payment interval (600s) + // 4. loan service fee (2) + // Calculate these values without the helper functions + // to verify they're working correctly The numbers in + // the below BEAST_EXPECTs may not hold across assets. + Number const interval = state.paymentInterval; + auto const periodicRate = interval * Number(12, -2) / secondsInYear; + BEAST_EXPECT(periodicRate == Number(2283105022831050228, -24, Number::normalized{})); + STAmount const roundedPeriodicPayment{ + broker.asset, roundPeriodicPayment(broker.asset, state.periodicPayment, state.loanScale)}; + + testcase << currencyLabel << " Payment components: " + << "Payments remaining, rawInterest, rawPrincipal, " + "rawMFee, trackedValueDelta, trackedPrincipalDelta, " + "trackedInterestDelta, trackedMgmtFeeDelta, special"; + + auto const serviceFee = broker.asset(2); + + BEAST_EXPECT( + roundedPeriodicPayment == + roundToScale( + broker.asset(Number(8333457002039338267, -17), Number::upward), + state.loanScale, + Number::upward)); + // 83334570.01162141 + // Include the service fee + STAmount const totalDue = + roundToScale(roundedPeriodicPayment + serviceFee, state.loanScale, Number::upward); + // Only check the first payment since the rounding + // may drift as payments are made + BEAST_EXPECT( + totalDue == + roundToScale( + broker.asset(Number(8533457002039338267, -17), Number::upward), + state.loanScale, + Number::upward)); + + { + auto const raw = computeTheoreticalLoanState( + state.periodicPayment, periodicRate, state.paymentRemaining, broker.params.managementFeeRate); + auto const rounded = constructLoanState( + state.totalValue, state.principalOutstanding, state.managementFeeOutstanding); + testcase << currencyLabel << " Loan starting state: " << state.paymentRemaining << ", " + << raw.interestDue << ", " << raw.principalOutstanding << ", " << raw.managementFeeDue + << ", " << rounded.valueOutstanding << ", " << rounded.principalOutstanding << ", " + << rounded.interestDue << ", " << rounded.managementFeeDue; + } + + // Try to pay a little extra to show that it's _not_ + // taken + STAmount const transactionAmount = STAmount{broker.asset, totalDue} + broker.asset(10); + // Only check the first payment since the rounding + // may drift as payments are made + BEAST_EXPECT( + transactionAmount == + roundToScale( + broker.asset(Number(9533457002039400, -14), Number::upward), state.loanScale, Number::upward)); + + auto const initialState = state; + detail::PaymentComponents totalPaid{ + .trackedValueDelta = 0, .trackedPrincipalDelta = 0, .trackedManagementFeeDelta = 0}; + Number totalInterestPaid = 0; + std::size_t totalPaymentsMade = 0; + + xrpl::LoanState currentTrueState = computeTheoreticalLoanState( + state.periodicPayment, periodicRate, state.paymentRemaining, broker.params.managementFeeRate); + + while (state.paymentRemaining > 0) + { + // Compute the expected principal amount + auto const paymentComponents = detail::computePaymentComponents( + broker.asset.raw(), + state.loanScale, + state.totalValue, + state.principalOutstanding, + state.managementFeeOutstanding, + state.periodicPayment, + periodicRate, + state.paymentRemaining, + broker.params.managementFeeRate); + + BEAST_EXPECTS( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || + paymentComponents.trackedValueDelta <= roundedPeriodicPayment, + "Delta: " + to_string(paymentComponents.trackedValueDelta) + + ", periodic payment: " + to_string(roundedPeriodicPayment)); + + xrpl::LoanState const nextTrueState = computeTheoreticalLoanState( + state.periodicPayment, + periodicRate, + state.paymentRemaining - 1, + broker.params.managementFeeRate); + detail::LoanStateDeltas const deltas = currentTrueState - nextTrueState; + + testcase << currencyLabel << " Payment components: " << state.paymentRemaining << ", " + << deltas.interest << ", " << deltas.principal << ", " << deltas.managementFee << ", " + << paymentComponents.trackedValueDelta << ", " << paymentComponents.trackedPrincipalDelta + << ", " << paymentComponents.trackedInterestPart() << ", " + << paymentComponents.trackedManagementFeeDelta << ", " + << (paymentComponents.specialCase == detail::PaymentSpecialCase::final ? "final" + : paymentComponents.specialCase == detail::PaymentSpecialCase::extra ? "extra" + : "none"); + + auto const totalDueAmount = + STAmount{broker.asset, paymentComponents.trackedValueDelta + serviceFee.number()}; + + // Due to the rounding algorithms to keep the interest and + // principal in sync with "true" values, the computed amount + // may be a little less than the rounded fixed payment + // amount. For integral types, the difference should be < 3 + // (1 unit for each of the interest and management fee). For + // IOUs, the difference should be after the 8th digit. + Number const diff = totalDue - totalDueAmount; + BEAST_EXPECT( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || diff == beast::zero || + (diff > beast::zero && + ((broker.asset.integral() && (static_cast(diff) < 3)) || + (state.loanScale - diff.exponent() > 13)))); + + BEAST_EXPECT( + paymentComponents.trackedValueDelta == + paymentComponents.trackedPrincipalDelta + paymentComponents.trackedInterestPart() + + paymentComponents.trackedManagementFeeDelta); + BEAST_EXPECT( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || + paymentComponents.trackedValueDelta <= roundedPeriodicPayment); + + BEAST_EXPECT( + state.paymentRemaining < 12 || + roundToAsset(broker.asset, deltas.principal, state.loanScale, Number::upward) == + roundToScale( + broker.asset(Number(8333228691531218890, -17), Number::upward), + state.loanScale, + Number::upward)); + BEAST_EXPECT( + paymentComponents.trackedPrincipalDelta >= beast::zero && + paymentComponents.trackedPrincipalDelta <= state.principalOutstanding); + BEAST_EXPECT( + paymentComponents.specialCase != detail::PaymentSpecialCase::final || + paymentComponents.trackedPrincipalDelta == state.principalOutstanding); + BEAST_EXPECT( + paymentComponents.specialCase == detail::PaymentSpecialCase::final || + (state.periodicPayment.exponent() - + (deltas.principal + deltas.interest + deltas.managementFee - state.periodicPayment) + .exponent()) > 14); + + auto const borrowerBalanceBeforePayment = env.balance(borrower, broker.asset); + + if (canImpairLoan(env, broker, state)) + // Making a payment will unimpair the loan + env(manage(lender, loanKeylet.key, tfLoanImpair)); + + env.close(); + + // Make the payment + env(pay(borrower, loanKeylet.key, transactionAmount)); + + env.close(); + + // Need to account for fees if the loan is in XRP + PrettyAmount adjustment = broker.asset(0); + if (broker.asset.native()) + { + adjustment = env.current()->fees().base; + } + + // Check the result + verifyLoanStatus.checkPayment( + state.loanScale, borrower, borrowerBalanceBeforePayment, totalDueAmount, adjustment); + + --state.paymentRemaining; + state.previousPaymentDate = state.nextPaymentDate; + if (paymentComponents.specialCase == detail::PaymentSpecialCase::final) + { + state.paymentRemaining = 0; + state.nextPaymentDate = 0; + } + else + { + state.nextPaymentDate += state.paymentInterval; + } + state.principalOutstanding -= paymentComponents.trackedPrincipalDelta; + state.managementFeeOutstanding -= paymentComponents.trackedManagementFeeDelta; + state.totalValue -= paymentComponents.trackedValueDelta; + + verifyLoanStatus(state); + + totalPaid.trackedValueDelta += paymentComponents.trackedValueDelta; + totalPaid.trackedPrincipalDelta += paymentComponents.trackedPrincipalDelta; + totalPaid.trackedManagementFeeDelta += paymentComponents.trackedManagementFeeDelta; + totalInterestPaid += paymentComponents.trackedInterestPart(); + ++totalPaymentsMade; + + currentTrueState = nextTrueState; + } + + // Loan is paid off + BEAST_EXPECT(state.paymentRemaining == 0); + BEAST_EXPECT(state.principalOutstanding == 0); + + // Make sure all the payments add up + BEAST_EXPECT(totalPaid.trackedValueDelta == initialState.totalValue); + BEAST_EXPECT(totalPaid.trackedPrincipalDelta == initialState.principalOutstanding); + BEAST_EXPECT(totalPaid.trackedManagementFeeDelta == initialState.managementFeeOutstanding); + // This is almost a tautology given the previous checks, but + // check it anyway for completeness. + BEAST_EXPECT( + totalInterestPaid == + initialState.totalValue - + (initialState.principalOutstanding + initialState.managementFeeOutstanding)); + BEAST_EXPECT(totalPaymentsMade == initialState.paymentRemaining); + + // Can't impair or default a paid off loan + env(manage(lender, loanKeylet.key, tfLoanImpair), ter(tecNO_PERMISSION)); + env(manage(lender, loanKeylet.key, tfLoanDefault), ter(tecNO_PERMISSION)); + }); + +#if LOANTODO + // TODO + + /* + LoanPay fails with tecINVARIANT_FAILED error when loan_broker(also + borrower) tries to do the payment. Here's the scenario: Create a XRP + loan with loan broker as borrower, loan origination fee and loan service + fee. Loan broker makes the first payment with periodic payment and loan + service fee. + */ + + auto time = [&](std::string label, std::function timed) { + if (!BEAST_EXPECT(timed)) + return; + + using clock_type = std::chrono::steady_clock; + using duration_type = std::chrono::milliseconds; + + auto const start = clock_type::now(); + timed(); + auto const duration = std::chrono::duration_cast(clock_type::now() - start); + + log << label << " took " << duration.count() << "ms" << std::endl; + + return duration; + }; + + lifecycle( + caseLabel, + "timing", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { + // Estimate optimal values for loanPaymentsPerFeeIncrement and + // loanMaximumPaymentsPerTransaction. + using namespace loan; + + auto const state = getCurrentState(env, broker, verifyLoanStatus.keylet); + auto const serviceFee = broker.asset(2).value(); + + STAmount const totalDue{ + broker.asset, + roundPeriodicPayment(broker.asset, state.periodicPayment + serviceFee, state.loanScale)}; + + // Make a single payment + time("single payment", [&]() { env(pay(borrower, loanKeylet.key, totalDue)); }); + env.close(); + + // Make all but the final payment + auto const numPayments = (state.paymentRemaining - 2); + STAmount const bigPayment{broker.asset, totalDue * numPayments}; + XRPAmount const bigFee{baseFee * (numPayments / loanPaymentsPerFeeIncrement + 1)}; + time("ten payments", [&]() { env(pay(borrower, loanKeylet.key, bigPayment), fee(bigFee)); }); + env.close(); + + time("final payment", [&]() { + // Make the final payment + env(pay(borrower, loanKeylet.key, totalDue + STAmount{broker.asset, 1})); + }); + env.close(); + }); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Explicit overpayment", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { throw 0; }); + + lifecycle( + caseLabel, + "Loan overpayment prohibited - Late payment", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { throw 0; }); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Late payment", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { throw 0; }); + + lifecycle( + caseLabel, + "Loan overpayment allowed - Late payment and overpayment", + env, + loanAmount, + interestExponent, + lender, + borrower, + evan, + broker, + pseudoAcct, + tfLoanOverpayment, + [&](Keylet const& loanKeylet, VerifyLoanStatus const& verifyLoanStatus) { throw 0; }); + +#endif + } + + void + testLoanSet() + { + using namespace jtx; + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + struct CaseArgs + { + bool requireAuth = false; + bool authorizeBorrower = false; + int initialXRP = 1'000'000; + }; + + auto const testCase = [&, this]( + std::function mptTest, + std::function iouTest, + CaseArgs args = {}) { + Env env(*this, all); + env.fund(XRP(args.initialXRP), issuer, lender, borrower); + env.close(); + if (args.requireAuth) + { + env(fset(issuer, asfRequireAuth)); + env.close(); + } + + // We need two different asset types, MPT and IOU. Prepare MPT + // first + MPTTester mptt{env, issuer, mptInitNoFund}; + + auto const none = LedgerSpecificFlags(0); + mptt.create({.flags = tfMPTCanTransfer | tfMPTCanLock | (args.requireAuth ? tfMPTRequireAuth : none)}); + env.close(); + PrettyAsset mptAsset = mptt.issuanceID(); + mptt.authorize({.account = lender}); + mptt.authorize({.account = borrower}); + env.close(); + if (args.requireAuth) + { + mptt.authorize({.account = issuer, .holder = lender}); + if (args.authorizeBorrower) + mptt.authorize({.account = issuer, .holder = borrower}); + env.close(); + } + + env(pay(issuer, lender, mptAsset(10'000'000))); + env.close(); + + // Prepare IOU + PrettyAsset const iouAsset = issuer[iouCurrency]; + env(trust(lender, iouAsset(10'000'000))); + env(trust(borrower, iouAsset(10'000'000))); + env.close(); + if (args.requireAuth) + { + env(trust(issuer, iouAsset(0), lender, tfSetfAuth)); + env(pay(issuer, lender, iouAsset(10'000'000))); + if (args.authorizeBorrower) + { + env(trust(issuer, iouAsset(0), borrower, tfSetfAuth)); + env(pay(issuer, borrower, iouAsset(10'000))); + } + } + else + { + env(pay(issuer, lender, iouAsset(10'000'000))); + env(pay(issuer, borrower, iouAsset(10'000))); + } + env.close(); + + // Create vaults and loan brokers + std::array const assets{mptAsset, iouAsset}; + std::vector brokers; + for (auto const& asset : assets) + { + brokers.emplace_back(createVaultAndBroker(env, asset, lender)); + } + + if (mptTest) + (mptTest)(env, brokers[0], mptt); + if (iouTest) + (iouTest)(env, brokers[1]); + }; + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("MPT issuer is borrower, issuer submits"); + env(set(issuer, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + + testcase("MPT issuer is borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(issuer), + sig(sfCounterpartySignature, issuer), + fee(env.current()->fees().base * 5)); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("IOU issuer is borrower, issuer submits"); + env(set(issuer, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + + testcase("IOU issuer is borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(issuer), + sig(sfCounterpartySignature, issuer), + fee(env.current()->fees().base * 5)); + }, + CaseArgs{.requireAuth = true}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("MPT unauthorized borrower, borrower submits"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + + testcase("MPT unauthorized borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("IOU unauthorized borrower, borrower submits"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + + testcase("IOU unauthorized borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + }, + CaseArgs{.requireAuth = true}); + + auto const [acctReserve, incReserve] = [this]() -> std::pair { + Env env{*this, testable_amendments()}; + return { + env.current()->fees().accountReserve(0).drops() / DROPS_PER_XRP.drops(), + env.current()->fees().increment.drops() / DROPS_PER_XRP.drops()}; + }(); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, MPTTester& mptt) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "MPT authorized borrower, borrower submits, borrower has " + "no reserve"); + mptt.authorize({.account = borrower, .flags = tfMPTUnauthorize}); + env.close(); + + auto const mptoken = keylet::mptoken(mptt.issuanceID(), borrower); + auto const sleMPT1 = env.le(mptoken); + BEAST_EXPECT(sleMPT1 == nullptr); + + // Burn some XRP + env(noop(borrower), fee(XRP(acctReserve * 2 + incReserve * 2))); + env.close(); + + // Cannot create loan, not enough reserve to create MPToken + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecINSUFFICIENT_RESERVE}); + env.close(); + + // Can create loan now, will implicitly create MPToken + env(pay(issuer, borrower, XRP(incReserve))); + env.close(); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + env.close(); + + auto const sleMPT2 = env.le(mptoken); + BEAST_EXPECT(sleMPT2 != nullptr); + }, + {}, + CaseArgs{.initialXRP = acctReserve * 2 + incReserve * 8 + 1}); + + testCase( + {}, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "IOU authorized borrower, borrower submits, borrower has " + "no reserve"); + // Remove trust line from borrower to issuer + env.trust(broker.asset(0), borrower); + env.close(); + + env(pay(borrower, issuer, broker.asset(10'000))); + env.close(); + auto const trustline = keylet::line(borrower, broker.asset.raw().get()); + auto const sleLine1 = env.le(trustline); + BEAST_EXPECT(sleLine1 == nullptr); + + // Burn some XRP + env(noop(borrower), fee(XRP(acctReserve * 2 + incReserve * 2))); + env.close(); + + // Cannot create loan, not enough reserve to create trust line + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_LINE_INSUF_RESERVE}); + env.close(); + + // Can create loan now, will implicitly create trust line + env(pay(issuer, borrower, XRP(incReserve))); + env.close(); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + env.close(); + + auto const sleLine2 = env.le(trustline); + BEAST_EXPECT(sleLine2 != nullptr); + }, + CaseArgs{.initialXRP = acctReserve * 2 + incReserve * 8 + 1}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, MPTTester& mptt) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "MPT authorized borrower, borrower submits, lender has " + "no reserve"); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), lender); + auto const sleMPT1 = env.le(mptoken); + BEAST_EXPECT(sleMPT1 != nullptr); + + env(pay(lender, issuer, broker.asset(sleMPT1->at(sfMPTAmount)))); + env.close(); + + mptt.authorize({.account = lender, .flags = tfMPTUnauthorize}); + env.close(); + + auto const sleMPT2 = env.le(mptoken); + BEAST_EXPECT(sleMPT2 == nullptr); + + // Burn some XRP + env(noop(lender), fee(XRP(incReserve))); + env.close(); + + // Cannot create loan, not enough reserve to create MPToken + env(set(borrower, broker.brokerID, principalRequest), + loanOriginationFee(broker.asset(1).value()), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecINSUFFICIENT_RESERVE}); + env.close(); + + // Can create loan now, will implicitly create MPToken + env(pay(issuer, lender, XRP(incReserve))); + env.close(); + env(set(borrower, broker.brokerID, principalRequest), + loanOriginationFee(broker.asset(1).value()), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + env.close(); + + auto const sleMPT3 = env.le(mptoken); + BEAST_EXPECT(sleMPT3 != nullptr); + }, + {}, + CaseArgs{.initialXRP = acctReserve * 2 + incReserve * 8 + 1}); + + testCase( + {}, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "IOU authorized borrower, borrower submits, lender has no " + "reserve"); + // Remove trust line from lender to issuer + env.trust(broker.asset(0), lender); + env.close(); + + auto const trustline = keylet::line(lender, broker.asset.raw().get()); + auto const sleLine1 = env.le(trustline); + BEAST_EXPECT(sleLine1 != nullptr); + + env(pay(lender, issuer, broker.asset(abs(sleLine1->at(sfBalance).value())))); + env.close(); + auto const sleLine2 = env.le(trustline); + BEAST_EXPECT(sleLine2 == nullptr); + + // Burn some XRP + env(noop(lender), fee(XRP(incReserve))); + env.close(); + + // Cannot create loan, not enough reserve to create trust line + env(set(borrower, broker.brokerID, principalRequest), + loanOriginationFee(broker.asset(1).value()), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_LINE_INSUF_RESERVE}); + env.close(); + + // Can create loan now, will implicitly create trust line + env(pay(issuer, lender, XRP(incReserve))); + env.close(); + env(set(borrower, broker.brokerID, principalRequest), + loanOriginationFee(broker.asset(1).value()), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + env.close(); + + auto const sleLine3 = env.le(trustline); + BEAST_EXPECT(sleLine3 != nullptr); + }, + CaseArgs{.initialXRP = acctReserve * 2 + incReserve * 8 + 1}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, MPTTester& mptt) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("MPT authorized borrower, unauthorized lender"); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), lender); + auto const sleMPT1 = env.le(mptoken); + BEAST_EXPECT(sleMPT1 != nullptr); + + env(pay(lender, issuer, broker.asset(sleMPT1->at(sfMPTAmount)))); + env.close(); + + mptt.authorize({.account = lender, .flags = tfMPTUnauthorize}); + env.close(); + + auto const sleMPT2 = env.le(mptoken); + BEAST_EXPECT(sleMPT2 == nullptr); + + // Cannot create loan, lender not authorized to receive fee + env(set(borrower, broker.brokerID, principalRequest), + loanOriginationFee(broker.asset(1).value()), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + env.close(); + + // Cannot create loan, even without an origination fee + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter{tecNO_AUTH}); + env.close(); + + // No MPToken for lender - no authorization and no payment + auto const sleMPT3 = env.le(mptoken); + BEAST_EXPECT(sleMPT3 == nullptr); + }, + {}, + CaseArgs{.requireAuth = true, .authorizeBorrower = true}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("MPT authorized borrower, borrower submits"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("IOU authorized borrower, borrower submits"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5)); + }, + CaseArgs{.requireAuth = true, .authorizeBorrower = true}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("MPT authorized borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + fee(env.current()->fees().base * 5)); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + + testcase("IOU authorized borrower, lender submits"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + fee(env.current()->fees().base * 5)); + }, + CaseArgs{.requireAuth = true, .authorizeBorrower = true}); + + jtx::Account const alice{"alice"}; + jtx::Account const bella{"bella"}; + auto const msigSetup = [&](Env& env, Account const& account) { + Json::Value tx1 = signers(account, 2, {{alice, 1}, {bella, 1}}); + env(tx1); + env.close(); + }; + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + msigSetup(env, lender); + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "MPT authorized borrower, borrower submits, lender " + "multisign"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(sfCounterpartySignature, alice, bella), + fee(env.current()->fees().base * 5)); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + msigSetup(env, lender); + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "IOU authorized borrower, borrower submits, lender " + "multisign"); + env(set(borrower, broker.brokerID, principalRequest), + counterparty(lender), + msig(sfCounterpartySignature, alice, bella), + fee(env.current()->fees().base * 5)); + }, + CaseArgs{.requireAuth = true, .authorizeBorrower = true}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + msigSetup(env, borrower); + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "MPT authorized borrower, lender submits, borrower " + "multisign"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + msig(sfCounterpartySignature, alice, bella), + fee(env.current()->fees().base * 5)); + }, + [&, this](Env& env, BrokerInfo const& broker) { + using namespace loan; + msigSetup(env, borrower); + Number const principalRequest = broker.asset(1'000).value(); + + testcase( + "IOU authorized borrower, lender submits, borrower " + "multisign"); + env(set(lender, broker.brokerID, principalRequest), + counterparty(borrower), + msig(sfCounterpartySignature, alice, bella), + fee(env.current()->fees().base * 5)); + }, + CaseArgs{.requireAuth = true, .authorizeBorrower = true}); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + Vault vault{env}; + auto tx = vault.set({.owner = lender, .id = broker.vaultID}); + tx[sfAssetsMaximum] = BrokerParameters::defaults().vaultDeposit; + env(tx); + env.close(); + + testcase("Vault at maximum value"); + env(set(issuer, broker.brokerID, principalRequest), + counterparty(lender), + interestRate(TenthBips32(10'000)), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + ter(tecLIMIT_EXCEEDED), + THISLINE); + }, + nullptr); + + testCase( + [&, this](Env& env, BrokerInfo const& broker, auto&) { + using namespace loan; + Number const principalRequest = broker.asset(1'000).value(); + Vault vault{env}; + auto tx = vault.set({.owner = lender, .id = broker.vaultID}); + tx[sfAssetsMaximum] = BrokerParameters::defaults().vaultDeposit + broker.asset(1).number(); + env(tx); + env.close(); + + testcase("Vault maximum value exceeded"); + env(set(issuer, broker.brokerID, principalRequest), + counterparty(lender), + interestRate(TenthBips32(100'000)), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 5), + paymentTotal(2), + paymentInterval(3600 * 24), + ter(tecLIMIT_EXCEEDED), + THISLINE); + }, + nullptr); + } + + void + testLifecycle() + { + testcase("Lifecycle"); + using namespace jtx; + + // Create 3 loan brokers: one for XRP, one for an IOU, and one for + // an MPT. That'll require three corresponding SAVs. + Env env(*this, all); + + Account const issuer{"issuer"}; + // For simplicity, lender will be the sole actor for the vault & + // brokers. + Account const lender{"lender"}; + // Borrower only wants to borrow + Account const borrower{"borrower"}; + // Evan will attempt to be naughty + Account const evan{"evan"}; + // Do not fund alice + Account const alice{"alice"}; + + // Fund the accounts and trust lines with the same amount so that + // tests can use the same values regardless of the asset. + env.fund(XRP(100'000'000), issuer, noripple(lender, borrower, evan)); + env.close(); + + // Create assets + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + PrettyAsset const iouAsset = issuer[iouCurrency]; + env(trust(lender, iouAsset(10'000'000))); + env(trust(borrower, iouAsset(10'000'000))); + env(trust(evan, iouAsset(10'000'000))); + env(pay(issuer, evan, iouAsset(1'000'000))); + env(pay(issuer, lender, iouAsset(10'000'000))); + // Fund the borrower with enough to cover interest and fees + env(pay(issuer, borrower, iouAsset(10'000))); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + // Scale the MPT asset a little bit so we can get some interest + PrettyAsset const mptAsset{mptt.issuanceID(), 100}; + mptt.authorize({.account = lender}); + mptt.authorize({.account = borrower}); + mptt.authorize({.account = evan}); + env(pay(issuer, lender, mptAsset(10'000'000))); + env(pay(issuer, evan, mptAsset(1'000'000))); + // Fund the borrower with enough to cover interest and fees + env(pay(issuer, borrower, mptAsset(10'000))); + env.close(); + + std::array const assets{iouAsset, xrpAsset, mptAsset}; + + // Create vaults and loan brokers + std::vector brokers; + for (auto const& asset : assets) + { + brokers.emplace_back( + createVaultAndBroker(env, asset, lender, BrokerParameters{.data = "spam spam spam spam"})); + } + + // Create and update Loans + for (auto const& broker : brokers) + { + for (int amountExponent = 3; amountExponent >= 3; --amountExponent) + { + Number const loanAmount{1, amountExponent}; + for (int interestExponent = 0; interestExponent >= 0; --interestExponent) + { + testCaseWrapper(env, mptt, assets, broker, loanAmount, interestExponent); + } + } + + if (auto brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == 0); + + auto const coverAvailable = brokerSle->at(sfCoverAvailable); + env(loanBroker::coverWithdraw(lender, broker.brokerID, STAmount(broker.asset, coverAvailable))); + env.close(); + + brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + BEAST_EXPECT(brokerSle && brokerSle->at(sfCoverAvailable) == 0); + } + // Verify we can delete the loan broker + env(loanBroker::del(lender, broker.brokerID)); + env.close(); + } + } + + void + testSelfLoan() + { + testcase << "Self Loan"; + + using namespace jtx; + using namespace std::chrono_literals; + // Create 3 loan brokers: one for XRP, one for an IOU, and one for + // an MPT. That'll require three corresponding SAVs. + Env env(*this, all); + + Account const issuer{"issuer"}; + // For simplicity, lender will be the sole actor for the vault & + // brokers. + Account const lender{"lender"}; + + // Fund the accounts and trust lines with the same amount so that + // tests can use the same values regardless of the asset. + env.fund(XRP(100'000'000), issuer, noripple(lender)); + env.close(); + + // Use an XRP asset for simplicity + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + + // Create vaults and loan brokers + BrokerInfo broker{createVaultAndBroker(env, xrpAsset, lender)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + // The LoanSet json can be created without a counterparty signature, + // but it will not pass preflight + auto createJson = + env.json(set(lender, broker.brokerID, broker.asset(principalRequest).value()), fee(loanSetFee)); + env(createJson, ter(temBAD_SIGNER)); + + // Adding an empty counterparty signature object also fails, but + // at the RPC level. + createJson = env.json(createJson, json(sfCounterpartySignature, Json::objectValue)); + env(createJson, ter(telENV_RPC_FAILED)); + + if (auto const jt = env.jt(createJson); BEAST_EXPECT(jt.stx)) + { + Serializer s; + jt.stx->add(s); + auto const jr = env.rpc("submit", strHex(s.slice())); + + BEAST_EXPECT(jr.isMember(jss::result)); + auto const jResult = jr[jss::result]; + BEAST_EXPECT(jResult[jss::error] == "invalidTransaction"); + BEAST_EXPECT(jResult[jss::error_exception] == "fails local checks: Transaction has bad signature."); + } + + // Copy the transaction signature into the counterparty signature. + Json::Value counterpartyJson{Json::objectValue}; + counterpartyJson[sfTxnSignature] = createJson[sfTxnSignature]; + counterpartyJson[sfSigningPubKey] = createJson[sfSigningPubKey]; + if (!BEAST_EXPECT(!createJson.isMember(jss::Signers))) + counterpartyJson[sfSigners] = createJson[sfSigners]; + + // The duplicated signature works + createJson = env.json(createJson, json(sfCounterpartySignature, counterpartyJson)); + env(createJson); + + env.close(); + + auto const startDate = env.current()->header().parentCloseTime; + + // Loan is successfully created + { + auto const res = env.rpc("account_objects", lender.human()); + auto const objects = res[jss::result][jss::account_objects]; + + std::map types; + BEAST_EXPECT(objects.size() == 4); + for (auto const& object : objects) + { + ++types[object[sfLedgerEntryType].asString()]; + } + BEAST_EXPECT(types.size() == 4); + for (std::string const type : {"MPToken", "Vault", "LoanBroker", "Loan"}) + { + BEAST_EXPECT(types[type] == 1); + } + } + auto const loanID = [&]() { + Json::Value params(Json::objectValue); + params[jss::account] = lender.human(); + params[jss::type] = "Loan"; + auto const res = env.rpc("json", "account_objects", to_string(params)); + auto const objects = res[jss::result][jss::account_objects]; + + BEAST_EXPECT(objects.size() == 1); + + auto const loan = objects[0u]; + BEAST_EXPECT(loan[sfBorrower] == lender.human()); + // soeDEFAULT fields are not returned if they're in the default + // state + BEAST_EXPECT(!loan.isMember(sfCloseInterestRate)); + BEAST_EXPECT(!loan.isMember(sfClosePaymentFee)); + BEAST_EXPECT(loan[sfFlags] == 0); + BEAST_EXPECT(loan[sfGracePeriod] == 60); + BEAST_EXPECT(!loan.isMember(sfInterestRate)); + BEAST_EXPECT(!loan.isMember(sfLateInterestRate)); + BEAST_EXPECT(!loan.isMember(sfLatePaymentFee)); + BEAST_EXPECT(loan[sfLoanBrokerID] == to_string(broker.brokerID)); + BEAST_EXPECT(!loan.isMember(sfLoanOriginationFee)); + BEAST_EXPECT(loan[sfLoanSequence] == 1); + BEAST_EXPECT(!loan.isMember(sfLoanServiceFee)); + BEAST_EXPECT(loan[sfNextPaymentDueDate] == loan[sfStartDate].asUInt() + 60); + BEAST_EXPECT(!loan.isMember(sfOverpaymentFee)); + BEAST_EXPECT(!loan.isMember(sfOverpaymentInterestRate)); + BEAST_EXPECT(loan[sfPaymentInterval] == 60); + BEAST_EXPECT(loan[sfPeriodicPayment] == "1000000000"); + BEAST_EXPECT(loan[sfPaymentRemaining] == 1); + BEAST_EXPECT(!loan.isMember(sfPreviousPaymentDueDate)); + BEAST_EXPECT(loan[sfPrincipalOutstanding] == "1000000000"); + BEAST_EXPECT(loan[sfTotalValueOutstanding] == "1000000000"); + BEAST_EXPECT(!loan.isMember(sfLoanScale)); + BEAST_EXPECT(loan[sfStartDate].asUInt() == startDate.time_since_epoch().count()); + + return loan["index"].asString(); + }(); + auto const loanKeylet{keylet::loan(uint256{std::string_view(loanID)})}; + + env.close(startDate); + + // Make a payment + env(pay(lender, loanKeylet.key, broker.asset(1000))); + } + + void + testBatchBypassCounterparty() + { + // From FIND-001 + testcase << "Batch Bypass Counterparty"; + + bool const lendingBatchEnabled = + !std::any_of(Batch::disabledTxTypes.begin(), Batch::disabledTxTypes.end(), [](auto const& disabled) { + return disabled == ttLOAN_BROKER_SET; + }); + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + BrokerParameters brokerParams; + env.fund(XRP(brokerParams.vaultDeposit * 100), lender, borrower); + env.close(); + + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + + BrokerInfo broker{createVaultAndBroker(env, xrpAsset, lender, brokerParams)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto forgedLoanSet = set(borrower, broker.brokerID, principalRequest, 0); + + Json::Value randomData{Json::objectValue}; + randomData[jss::SigningPubKey] = Json::StaticString{"2600"}; + Json::Value sigObject{Json::objectValue}; + sigObject[jss::SigningPubKey] = strHex(lender.pk().slice()); + Serializer ss; + ss.add32(HashPrefix::txSign); + parse(randomData).addWithoutSigningFields(ss); + auto const sig = xrpl::sign(borrower.pk(), borrower.sk(), ss.slice()); + sigObject[jss::TxnSignature] = strHex(Slice{sig.data(), sig.size()}); + + forgedLoanSet[Json::StaticString{"CounterpartySignature"}] = sigObject; + + // ? Fails because the lender hasn't signed the tx + env(env.json(forgedLoanSet, fee(loanSetFee)), ter(telENV_RPC_FAILED)); + + auto const seq = env.seq(borrower); + auto const batchFee = batch::calcBatchFee(env, 1, 2); + // ! Should fail because the lender hasn't signed the tx + env(batch::outer(borrower, seq, batchFee, tfAllOrNothing), + batch::inner(forgedLoanSet, seq + 1), + batch::inner(pay(borrower, lender, XRP(1)), seq + 2), + ter(lendingBatchEnabled ? temBAD_SIGNATURE : temINVALID_INNER_BATCH)); + env.close(); + + // ? Check that the loan was NOT created + { + Json::Value params(Json::objectValue); + params[jss::account] = borrower.human(); + params[jss::type] = "Loan"; + auto const res = env.rpc("json", "account_objects", to_string(params)); + auto const objects = res[jss::result][jss::account_objects]; + BEAST_EXPECT(objects.size() == 0); + } + } + + void + testWrongMaxDebtBehavior() + { + // From FIND-003 + testcase << "Wrong Max Debt Behavior"; + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + + BrokerParameters brokerParams{.debtMax = 0}; + env.fund(XRP(brokerParams.vaultDeposit * 100), issuer, noripple(lender)); + env.close(); + + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + + BrokerInfo broker{createVaultAndBroker(env, xrpAsset, lender, brokerParams)}; + + if (auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); BEAST_EXPECT(brokerSle)) + { + BEAST_EXPECT(brokerSle->at(sfDebtMaximum) == 0); + } + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json(set(lender, broker.brokerID, principalRequest), fee(loanSetFee)); + + Json::Value counterpartyJson{Json::objectValue}; + counterpartyJson[sfTxnSignature] = createJson[sfTxnSignature]; + counterpartyJson[sfSigningPubKey] = createJson[sfSigningPubKey]; + if (!BEAST_EXPECT(!createJson.isMember(jss::Signers))) + counterpartyJson[sfSigners] = createJson[sfSigners]; + + createJson = env.json(createJson, json(sfCounterpartySignature, counterpartyJson)); + env(createJson); + + env.close(); + } + + void + testLoanPayComputePeriodicPaymentValidRateInvariant() + { + // From FIND-012 + testcase << "LoanPay xrpl::detail::computePeriodicPayment : " + "valid rate"; + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + BrokerParameters brokerParams; + env.fund(XRP(brokerParams.vaultDeposit * 100), issuer, lender, borrower); + env.close(); + + PrettyAsset const xrpAsset{xrpIssue(), 1'000'000}; + BrokerInfo broker{createVaultAndBroker(env, xrpAsset, lender, brokerParams)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{640562, -5}; + + Number const serviceFee{2462611968}; + std::uint32_t const numPayments{4294967295 / 800}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + loanServiceFee(serviceFee), + paymentTotal(numPayments), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["CloseInterestRate"] = 55374; + createJson["ClosePaymentFee"] = "3825205248"; + createJson["LatePaymentFee"] = "237"; + createJson["LoanOriginationFee"] = "0"; + createJson["OverpaymentFee"] = 35167; + createJson["OverpaymentInterestRate"] = 1360; + createJson["PaymentInterval"] = 727; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + // Fails in preclaim because principal requested can't be + // represented as XRP + env(createJson, ter(tecPRECISION_LOSS), THISLINE); + env.close(); + + BEAST_EXPECT(!env.le(keylet)); + + Number const actualPrincipal{6}; + + createJson[sfPrincipalRequested] = actualPrincipal; + createJson.removeMember(sfSequence.jsonName); + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + // Fails in doApply because the payment is too small to be + // represented as XRP. + env(createJson, ter(tecPRECISION_LOSS), THISLINE); + env.close(); + } + + void + testRPC() + { + // This will expand as more test cases are added. Some functionality + // is tested in other test functions. + testcase("RPC"); + + using namespace jtx; + + Env env(*this, all); + + auto lowerFee = [&]() { + // Run the local fee back down. + while (env.app().getFeeTrack().lowerLocalFee()) + ; + }; + + auto const baseFee = env.current()->fees().base; + + Account const alice{"alice"}; + std::string const borrowerPass = "borrower"; + std::string const borrowerSeed = "ssBRAsLpH4778sLNYC4ik1JBJsBVf"; + Account borrower{borrowerPass, KeyType::ed25519}; + auto const lenderPass = "lender"; + std::string const lenderSeed = "shPTCZGwTEhJrYT8NbcNkeaa8pzPM"; + Account lender{lenderPass, KeyType::ed25519}; + + env.fund(XRP(1'000'000), alice, lender, borrower); + env.close(); + env(noop(lender)); + env(noop(lender)); + env(noop(lender)); + env(noop(lender)); + env(noop(lender)); + env.close(); + + { + testcase("RPC AccountSet"); + Json::Value txJson{Json::objectValue}; + txJson[sfTransactionType] = "AccountSet"; + txJson[sfAccount] = borrower.human(); + + auto const signParams = [&]() { + Json::Value signParams{Json::objectValue}; + signParams[jss::passphrase] = borrowerPass; + signParams[jss::key_type] = "ed25519"; + signParams[jss::tx_json] = txJson; + return signParams; + }(); + auto const jSign = env.rpc("json", "sign", to_string(signParams)); + BEAST_EXPECT(jSign.isMember(jss::result) && jSign[jss::result].isMember(jss::tx_json)); + auto txSignResult = jSign[jss::result][jss::tx_json]; + auto txSignBlob = jSign[jss::result][jss::tx_blob].asString(); + txSignResult.removeMember(jss::hash); + + auto const jtx = env.jt(txJson, sig(borrower)); + BEAST_EXPECT(txSignResult == jtx.jv); + + lowerFee(); + auto const jSubmit = env.rpc("submit", txSignBlob); + BEAST_EXPECT( + jSubmit.isMember(jss::result) && jSubmit[jss::result].isMember(jss::engine_result) && + jSubmit[jss::result][jss::engine_result].asString() == "tesSUCCESS"); + + lowerFee(); + env(jtx.jv, sig(none), seq(none), fee(none), ter(tefPAST_SEQ)); + } + + { + testcase("RPC LoanSet - illegal signature_target"); + + Json::Value txJson{Json::objectValue}; + txJson[sfTransactionType] = "AccountSet"; + txJson[sfAccount] = borrower.human(); + + auto const borrowerSignParams = [&]() { + Json::Value params{Json::objectValue}; + params[jss::passphrase] = borrowerPass; + params[jss::key_type] = "ed25519"; + params[jss::signature_target] = "Destination"; + params[jss::tx_json] = txJson; + return params; + }(); + auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams)); + BEAST_EXPECT( + jSignBorrower.isMember(jss::result) && jSignBorrower[jss::result].isMember(jss::error) && + jSignBorrower[jss::result][jss::error] == "invalidParams" && + jSignBorrower[jss::result].isMember(jss::error_message) && + jSignBorrower[jss::result][jss::error_message] == "Destination"); + } + { + testcase("RPC LoanSet - sign and submit borrower initiated"); + // 1. Borrower creates the transaction + Json::Value txJson{Json::objectValue}; + txJson[sfTransactionType] = "LoanSet"; + txJson[sfAccount] = borrower.human(); + txJson[sfCounterparty] = lender.human(); + txJson[sfLoanBrokerID] = + "FF924CD18A236C2B49CF8E80A351CEAC6A10171DC9F110025646894FEC" + "F83F" + "5C"; + txJson[sfPrincipalRequested] = "100000000"; + txJson[sfPaymentTotal] = 10000; + txJson[sfPaymentInterval] = 3600; + txJson[sfGracePeriod] = 300; + txJson[sfFlags] = 65536; // tfLoanOverpayment + txJson[sfFee] = to_string(24 * baseFee / 10); + + // 2. Borrower signs the transaction + auto const borrowerSignParams = [&]() { + Json::Value params{Json::objectValue}; + params[jss::passphrase] = borrowerPass; + params[jss::key_type] = "ed25519"; + params[jss::tx_json] = txJson; + return params; + }(); + auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams)); + BEAST_EXPECTS( + jSignBorrower.isMember(jss::result) && jSignBorrower[jss::result].isMember(jss::tx_json), + to_string(jSignBorrower)); + auto const txBorrowerSignResult = jSignBorrower[jss::result][jss::tx_json]; + auto const txBorrowerSignBlob = jSignBorrower[jss::result][jss::tx_blob].asString(); + + // 2a. Borrower attempts to submit the transaction. It doesn't + // work + { + lowerFee(); + auto const jSubmitBlob = env.rpc("submit", txBorrowerSignBlob); + BEAST_EXPECT(jSubmitBlob.isMember(jss::result)); + auto const jSubmitBlobResult = jSubmitBlob[jss::result]; + BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json)); + // Transaction fails because the CounterpartySignature is + // missing + BEAST_EXPECT( + jSubmitBlobResult.isMember(jss::engine_result) && + jSubmitBlobResult[jss::engine_result].asString() == "temBAD_SIGNER"); + } + + // 3. Borrower sends the signed transaction to the lender + // 4. Lender signs the transaction + auto const lenderSignParams = [&]() { + Json::Value params{Json::objectValue}; + params[jss::passphrase] = lenderPass; + params[jss::key_type] = "ed25519"; + params[jss::signature_target] = "CounterpartySignature"; + params[jss::tx_json] = txBorrowerSignResult; + return params; + }(); + auto const jSignLender = env.rpc("json", "sign", to_string(lenderSignParams)); + BEAST_EXPECT(jSignLender.isMember(jss::result) && jSignLender[jss::result].isMember(jss::tx_json)); + auto const txLenderSignResult = jSignLender[jss::result][jss::tx_json]; + auto const txLenderSignBlob = jSignLender[jss::result][jss::tx_blob].asString(); + + // 5. Lender submits the signed transaction blob + lowerFee(); + auto const jSubmitBlob = env.rpc("submit", txLenderSignBlob); + BEAST_EXPECT(jSubmitBlob.isMember(jss::result)); + auto const jSubmitBlobResult = jSubmitBlob[jss::result]; + BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json)); + auto const jSubmitBlobTx = jSubmitBlobResult[jss::tx_json]; + // To get far enough to return tecNO_ENTRY means that the + // signatures all validated. Of course the transaction won't + // succeed because no Vault or Broker were created. + BEAST_EXPECTS( + jSubmitBlobResult.isMember(jss::engine_result) && + jSubmitBlobResult[jss::engine_result].asString() == "tecNO_ENTRY", + to_string(jSubmitBlobResult)); + + BEAST_EXPECT(!jSubmitBlob.isMember(jss::error) && !jSubmitBlobResult.isMember(jss::error)); + + // 4-alt. Lender submits the transaction json originally + // received from the Borrower. It gets signed, but is now a + // duplicate, so fails. Borrower could done this instead of + // steps 4 and 5. + lowerFee(); + auto const jSubmitJson = env.rpc("json", "submit", to_string(lenderSignParams)); + BEAST_EXPECT(jSubmitJson.isMember(jss::result)); + auto const jSubmitJsonResult = jSubmitJson[jss::result]; + BEAST_EXPECT(jSubmitJsonResult.isMember(jss::tx_json)); + auto const jSubmitJsonTx = jSubmitJsonResult[jss::tx_json]; + // Since the previous tx claimed a fee, this duplicate is not + // going anywhere + BEAST_EXPECTS( + jSubmitJsonResult.isMember(jss::engine_result) && + jSubmitJsonResult[jss::engine_result].asString() == "tefPAST_SEQ", + to_string(jSubmitJsonResult)); + + BEAST_EXPECT(!jSubmitJson.isMember(jss::error) && !jSubmitJsonResult.isMember(jss::error)); + + BEAST_EXPECT(jSubmitBlobTx == jSubmitJsonTx); + } + + { + testcase("RPC LoanSet - sign and submit lender initiated"); + // 1. Lender creates the transaction + Json::Value txJson{Json::objectValue}; + txJson[sfTransactionType] = "LoanSet"; + txJson[sfAccount] = lender.human(); + txJson[sfCounterparty] = borrower.human(); + txJson[sfLoanBrokerID] = + "FF924CD18A236C2B49CF8E80A351CEAC6A10171DC9F110025646894FEC" + "F83F" + "5C"; + txJson[sfPrincipalRequested] = "100000000"; + txJson[sfPaymentTotal] = 10000; + txJson[sfPaymentInterval] = 3600; + txJson[sfGracePeriod] = 300; + txJson[sfFlags] = 65536; // tfLoanOverpayment + txJson[sfFee] = to_string(24 * baseFee / 10); + + // 2. Lender signs the transaction + auto const lenderSignParams = [&]() { + Json::Value params{Json::objectValue}; + params[jss::passphrase] = lenderPass; + params[jss::key_type] = "ed25519"; + params[jss::tx_json] = txJson; + return params; + }(); + auto const jSignLender = env.rpc("json", "sign", to_string(lenderSignParams)); + BEAST_EXPECT(jSignLender.isMember(jss::result) && jSignLender[jss::result].isMember(jss::tx_json)); + auto const txLenderSignResult = jSignLender[jss::result][jss::tx_json]; + auto const txLenderSignBlob = jSignLender[jss::result][jss::tx_blob].asString(); + + // 2a. Lender attempts to submit the transaction. It doesn't + // work + { + lowerFee(); + auto const jSubmitBlob = env.rpc("submit", txLenderSignBlob); + BEAST_EXPECT(jSubmitBlob.isMember(jss::result)); + auto const jSubmitBlobResult = jSubmitBlob[jss::result]; + BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json)); + // Transaction fails because the CounterpartySignature is + // missing + BEAST_EXPECT( + jSubmitBlobResult.isMember(jss::engine_result) && + jSubmitBlobResult[jss::engine_result].asString() == "temBAD_SIGNER"); + } + + // 3. Lender sends the signed transaction to the Borrower + // 4. Borrower signs the transaction + auto const borrowerSignParams = [&]() { + Json::Value params{Json::objectValue}; + params[jss::passphrase] = borrowerPass; + params[jss::key_type] = "ed25519"; + params[jss::signature_target] = "CounterpartySignature"; + params[jss::tx_json] = txLenderSignResult; + return params; + }(); + auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams)); + BEAST_EXPECT(jSignBorrower.isMember(jss::result) && jSignBorrower[jss::result].isMember(jss::tx_json)); + auto const txBorrowerSignResult = jSignBorrower[jss::result][jss::tx_json]; + auto const txBorrowerSignBlob = jSignBorrower[jss::result][jss::tx_blob].asString(); + + // 5. Borrower submits the signed transaction blob + lowerFee(); + auto const jSubmitBlob = env.rpc("submit", txBorrowerSignBlob); + BEAST_EXPECT(jSubmitBlob.isMember(jss::result)); + auto const jSubmitBlobResult = jSubmitBlob[jss::result]; + BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json)); + auto const jSubmitBlobTx = jSubmitBlobResult[jss::tx_json]; + // To get far enough to return tecNO_ENTRY means that the + // signatures all validated. Of course the transaction won't + // succeed because no Vault or Broker were created. + BEAST_EXPECTS( + jSubmitBlobResult.isMember(jss::engine_result) && + jSubmitBlobResult[jss::engine_result].asString() == "tecNO_ENTRY", + to_string(jSubmitBlobResult)); + + BEAST_EXPECT(!jSubmitBlob.isMember(jss::error) && !jSubmitBlobResult.isMember(jss::error)); + + // 4-alt. Borrower submits the transaction json originally + // received from the Lender. It gets signed, but is now a + // duplicate, so fails. Lender could done this instead of steps + // 4 and 5. + lowerFee(); + auto const jSubmitJson = env.rpc("json", "submit", to_string(borrowerSignParams)); + BEAST_EXPECT(jSubmitJson.isMember(jss::result)); + auto const jSubmitJsonResult = jSubmitJson[jss::result]; + BEAST_EXPECT(jSubmitJsonResult.isMember(jss::tx_json)); + auto const jSubmitJsonTx = jSubmitJsonResult[jss::tx_json]; + // Since the previous tx claimed a fee, this duplicate is not + // going anywhere + BEAST_EXPECTS( + jSubmitJsonResult.isMember(jss::engine_result) && + jSubmitJsonResult[jss::engine_result].asString() == "tefPAST_SEQ", + to_string(jSubmitJsonResult)); + + BEAST_EXPECT(!jSubmitJson.isMember(jss::error) && !jSubmitJsonResult.isMember(jss::error)); + + BEAST_EXPECT(jSubmitBlobTx == jSubmitJsonTx); + } + } + + void + testServiceFeeOnBrokerDeepFreeze() + { + testcase << "Service Fee On Broker Deep Freeze"; + using namespace jtx; + using namespace loan; + Account const issuer("issuer"); + Account const borrower("borrower"); + Account const broker("broker"); + auto const IOU = issuer["IOU"]; + + for (bool const deepFreeze : {true, false}) + { + Env env(*this); + + auto getCoverBalance = [&](BrokerInfo const& brokerInfo, auto const& accountField) { + if (auto const le = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(le)) + { + auto const account = le->at(accountField); + if (auto const sleLine = env.le(keylet::line(account, IOU)); BEAST_EXPECT(sleLine)) + { + STAmount balance = sleLine->at(sfBalance); + if (account > issuer.id()) + balance.negate(); + return balance; + } + } + return STAmount{IOU}; + }; + + env.fund(XRP(20'000), issuer, broker, borrower); + env.close(); + + env(trust(broker, IOU(20'000'000))); + env(pay(issuer, broker, IOU(10'000'000))); + env.close(); + + auto const brokerInfo = createVaultAndBroker(env, IOU, broker); + + BEAST_EXPECT(getCoverBalance(brokerInfo, sfAccount) == IOU(1'000)); + + auto const keylet = keylet::loan(brokerInfo.brokerID, 1); + + env(set(borrower, brokerInfo.brokerID, 10'000), + sig(sfCounterpartySignature, broker), + loanServiceFee(IOU(100).value()), + paymentInterval(100), + fee(XRP(100))); + env.close(); + + env(trust(borrower, IOU(20'000'000))); + // The borrower increases their limit and acquires some IOU so + // they can pay interest + env(pay(issuer, borrower, IOU(500))); + env.close(); + + if (auto const le = env.le(keylet::loan(keylet.key)); BEAST_EXPECT(le)) + { + if (deepFreeze) + { + env(trust(issuer, broker["IOU"](0), tfSetFreeze | tfSetDeepFreeze)); + env.close(); + } + + env(pay(borrower, keylet.key, IOU(10'100)), fee(XRP(100))); + env.close(); + + if (deepFreeze) + { + // The fee goes to the broker pseudo-account + BEAST_EXPECT(getCoverBalance(brokerInfo, sfAccount) == IOU(1'100)); + BEAST_EXPECT(getCoverBalance(brokerInfo, sfOwner) == IOU(8'999'000)); + } + else + { + // The fee goes to the broker account + BEAST_EXPECT(getCoverBalance(brokerInfo, sfOwner) == IOU(8'999'100)); + BEAST_EXPECT(getCoverBalance(brokerInfo, sfAccount) == IOU(1'000)); + } + } + }; + } + + void + testIssuerLoan() + { + testcase << "Issuer Loan"; + + using namespace jtx; + using namespace loan; + Account const issuer("issuer"); + Account const borrower = issuer; + Account const lender("lender"); + Env env(*this); + + env.fund(XRP(1'000), issuer, lender); + + std::int64_t constexpr issuerBalance = 10'000'000; + MPTTester asset({.env = env, .issuer = issuer, .holders = {lender}, .pay = issuerBalance}); + + BrokerParameters const brokerParams{ + .debtMax = 200, + }; + auto const broker = createVaultAndBroker(env, asset, lender, brokerParams); + auto const loanSetFee = fee(env.current()->fees().base * 2); + // Create Loan + env(set(borrower, broker.brokerID, 200), sig(sfCounterpartySignature, lender), loanSetFee); + env.close(); + // Issuer should not create MPToken + BEAST_EXPECT(!env.le(keylet::mptoken(asset.issuanceID(), issuer))); + // Issuer "borrowed" 200, OutstandingAmount decreased by 200 + BEAST_EXPECT(env.balance(issuer, asset) == asset(-issuerBalance + 200)); + // Pay Loan + auto const loanKeylet = keylet::loan(broker.brokerID, 1); + env(pay(borrower, loanKeylet.key, asset(200))); + env.close(); + // Issuer "re-payed" 200, OutstandingAmount increased by 200 + BEAST_EXPECT(env.balance(issuer, asset) == asset(-issuerBalance)); + } + + void + testInvalidLoanDelete() + { + testcase("Invalid LoanDelete"); + using namespace jtx; + using namespace loan; + + // preflight: temINVALID, LoanID == zero + { + Account const alice{"alice"}; + Env env(*this); + env.fund(XRP(1'000), alice); + env.close(); + env(del(alice, beast::zero), ter(temINVALID)); + } + } + + void + testInvalidLoanManage() + { + testcase("Invalid LoanManage"); + using namespace jtx; + using namespace loan; + + // preflight: temINVALID, LoanID == zero + { + Account const alice{"alice"}; + Env env(*this); + env.fund(XRP(1'000), alice); + env.close(); + env(manage(alice, beast::zero, tfLoanDefault), ter(temINVALID)); + } + } + + void + testInvalidLoanPay() + { + testcase("Invalid LoanPay"); + using namespace jtx; + using namespace loan; + Account const lender{"lender"}; + Account const issuer{"issuer"}; + Account const borrower{"borrower"}; + auto const IOU = issuer["IOU"]; + + // preclaim + Env env(*this); + env.fund(XRP(1'000), lender, issuer, borrower); + env(trust(lender, IOU(10'000'000)), THISLINE); + env(pay(issuer, lender, IOU(5'000'000)), THISLINE); + BrokerInfo brokerInfo{createVaultAndBroker(env, issuer["IOU"], lender)}; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + STAmount const debtMaximumRequest = brokerInfo.asset(1'000).value(); + + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + THISLINE); + + env.close(); + + std::uint32_t const loanSequence = 1; + auto const loanKeylet = keylet::loan(brokerInfo.brokerID, loanSequence); + + env(fset(issuer, asfGlobalFreeze), THISLINE); + env.close(); + + // preclaim: tecFROZEN + env(pay(borrower, loanKeylet.key, debtMaximumRequest), ter(tecFROZEN), THISLINE); + env.close(); + + env(fclear(issuer, asfGlobalFreeze), THISLINE); + env.close(); + + auto const pseudoBroker = [&]() -> std::optional { + if (auto brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + return Account{"pseudo", brokerSle->at(sfAccount)}; + } + else + { + return std::nullopt; + } + }(); + if (!pseudoBroker) + return; + + // Lender and pseudoaccount must both be frozen + env(trust(issuer, lender["IOU"](1'000), lender, tfSetFreeze | tfSetDeepFreeze), THISLINE); + env(trust(issuer, (*pseudoBroker)["IOU"](1'000), *pseudoBroker, tfSetFreeze | tfSetDeepFreeze), THISLINE); + env.close(); + + // preclaim: tecFROZEN due to deep frozen + env(pay(borrower, loanKeylet.key, debtMaximumRequest), ter(tecFROZEN), THISLINE); + env.close(); + + // Only one needs to be unfrozen + env(trust(issuer, lender["IOU"](1'000), tfClearFreeze | tfClearDeepFreeze), THISLINE); + env.close(); + + // The payment is late by this point + env(pay(borrower, loanKeylet.key, debtMaximumRequest), ter(tecEXPIRED), THISLINE); + env.close(); + env(pay(borrower, loanKeylet.key, debtMaximumRequest, tfLoanLatePayment), THISLINE); + env.close(); + + // preclaim: tecKILLED + // note that tecKILLED in loanMakePayment() + // doesn't happen because of the preclaim check. + env(pay(borrower, loanKeylet.key, debtMaximumRequest), ter(tecKILLED), THISLINE); + } + + void + testInvalidLoanSet() + { + testcase("Invalid LoanSet"); + using namespace jtx; + using namespace loan; + Account const lender{"lender"}; + Account const issuer{"issuer"}; + Account const borrower{"borrower"}; + auto const IOU = issuer["IOU"]; + + auto testWrapper = [&](auto&& test) { + Env env(*this); + env.fund(XRP(1'000), lender, issuer, borrower); + env(trust(lender, IOU(10'000'000))); + env(pay(issuer, lender, IOU(5'000'000))); + BrokerInfo brokerInfo{createVaultAndBroker(env, issuer["IOU"], lender)}; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const debtMaximumRequest = brokerInfo.asset(1'000).value(); + test(env, brokerInfo, loanSetFee, debtMaximumRequest); + }; + + // preflight: + testWrapper( + [&](Env& env, BrokerInfo const& brokerInfo, jtx::fee const& loanSetFee, Number const& debtMaximumRequest) { + // first temBAD_SIGNER: TODO + // invalid grace period + { + // zero grace period + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + gracePeriod(0), + loanSetFee, + ter(temINVALID)); + + // grace period less than default minimum + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + gracePeriod(LoanSet::defaultGracePeriod - 1), + loanSetFee, + ter(temINVALID)); + + // grace period greater than payment interval + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + paymentInterval(120), + gracePeriod(121), + loanSetFee, + ter(temINVALID)); + } + // empty/zero broker ID + { + auto jv = set(borrower, uint256{}, debtMaximumRequest); + + auto testZeroBrokerID = [&](std::string const& id, std::uint32_t flags = 0) { + // empty broker ID + jv[sfLoanBrokerID] = id; + env(jv, sig(sfCounterpartySignature, lender), loanSetFee, txflags(flags), ter(temINVALID)); + }; + // empty broker ID + testZeroBrokerID(std::string("")); + // zero broker ID + // needs a flag to distinguish the parsed STTx from the prior + // test + testZeroBrokerID(to_string(uint256{}), tfFullyCanonicalSig); + } + + // preflightCheckSigningKey() failure: + // can it happen? the signature is checked before transactor + // executes + + JTx tx = env.jt( + set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee); + STTx local = *(tx.stx); + auto counterpartySig = local.getFieldObject(sfCounterpartySignature); + auto badPubKey = counterpartySig.getFieldVL(sfSigningPubKey); + badPubKey[20] ^= 0xAA; + counterpartySig.setFieldVL(sfSigningPubKey, badPubKey); + local.setFieldObject(sfCounterpartySignature, counterpartySig); + Json::Value jvResult; + jvResult[jss::tx_blob] = strHex(local.getSerializer().slice()); + auto res = env.rpc("json", "submit", to_string(jvResult))["result"]; + BEAST_EXPECT( + res[jss::error] == "invalidTransaction" && + res[jss::error_exception] == "fails local checks: Counterparty: Invalid signature."); + }); + + // preclaim: + testWrapper( + [&](Env& env, BrokerInfo const& brokerInfo, jtx::fee const& loanSetFee, Number const& debtMaximumRequest) { + // canAddHoldingFailure (IOU only, if MPT doesn't have + // MPTCanTransfer set, then can't create Vault/LoanBroker, + // and LoanSet will fail with different error + env(fclear(issuer, asfDefaultRipple)); + env.close(); + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(terNO_RIPPLE)); + }); + + // doApply: + testWrapper( + [&](Env& env, BrokerInfo const& brokerInfo, jtx::fee const& loanSetFee, Number const& debtMaximumRequest) { + auto const amt = env.balance(borrower) - env.current()->fees().accountReserve(env.ownerCount(borrower)); + env(pay(borrower, issuer, amt)); + + // tecINSUFFICIENT_RESERVE + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecINSUFFICIENT_RESERVE)); + + // addEmptyHolding failure + env(pay(issuer, borrower, amt)); + env(fset(issuer, asfGlobalFreeze)); + env.close(); + + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + ter(tecFROZEN)); + }); + } + + void + testAccountSendMptMinAmountInvariant() + { + // (From FIND-006) + testcase << "LoanSet trigger xrpl::accountSendMPT : minimum amount " + "and MPT"; + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + PrettyAsset const mptAsset = mptt.issuanceID(); + mptt.authorize({.account = lender}); + mptt.authorize({.account = borrower}); + env(pay(issuer, lender, mptAsset(2'000'000))); + env(pay(issuer, borrower, mptAsset(1'000))); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, mptAsset, lender)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["CloseInterestRate"] = 76671; + createJson["ClosePaymentFee"] = "2061925410"; + createJson["GracePeriod"] = 434; + createJson["InterestRate"] = 50302; + createJson["LateInterestRate"] = 30322; + createJson["LatePaymentFee"] = "294427911"; + createJson["LoanOriginationFee"] = "3250635102"; + createJson["LoanServiceFee"] = "9557386"; + createJson["OverpaymentFee"] = 51249; + createJson["OverpaymentInterestRate"] = 14304; + createJson["PaymentInterval"] = 434; + createJson["PaymentTotal"] = "2891743748"; + createJson["PrincipalRequested"] = "8516.98"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, ter(temINVALID)); + env.close(); + } + + void + testLoanPayDebtDecreaseInvariant() + { + // From FIND-007 + testcase << "LoanPay xrpl::LoanPay::doApply : debtDecrease " + "rounding good"; + + using namespace jtx; + using namespace std::chrono_literals; + using namespace Lending; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + auto trustLenderTx = env.json(trust(lender, iouAsset(1'000'000'000))); + env(trustLenderTx); + auto trustBorrowerTx = env.json(trust(borrower, iouAsset(1'000'000'000))); + env(trustBorrowerTx); + auto payLenderTx = pay(issuer, lender, iouAsset(100'000'000)); + env(payLenderTx); + auto payIssuerTx = pay(issuer, borrower, iouAsset(1'000'000)); + env(payIssuerTx); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender)}; + + using namespace loan; + + auto const baseFee = env.current()->fees().base; + auto const loanSetFee = fee(baseFee * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["ClosePaymentFee"] = "0"; + createJson["GracePeriod"] = 60; + createJson["InterestRate"] = 24346; + createJson["LateInterestRate"] = 65535; + createJson["LatePaymentFee"] = "0"; + createJson["LoanOriginationFee"] = "218"; + createJson["LoanServiceFee"] = "0"; + createJson["PaymentInterval"] = 60; + createJson["PaymentTotal"] = 5678; + createJson["PrincipalRequested"] = "9924.81"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, ter(tesSUCCESS)); + env.close(); + + auto const pseudoAcct = [&]() { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return lender; + auto const brokerPseudo = brokerSle->at(sfAccount); + return Account("Broker pseudo-account", brokerPseudo); + }(); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, keylet); + auto const originalState = getCurrentState(env, broker, keylet); + verifyLoanStatus(originalState); + + Number const payment{3'269'349'176'470'588, -12}; + XRPAmount const payFee{baseFee * ((payment / originalState.periodicPayment) / loanPaymentsPerFeeIncrement + 1)}; + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, payment}), fee(payFee)); + BEAST_EXPECT(to_string(payment) == "3269.349176470588"); + env(loanPayTx, ter(tesSUCCESS)); + env.close(); + + auto const newState = getCurrentState(env, broker, keylet); + BEAST_EXPECT(isRounded(broker.asset, newState.managementFeeOutstanding, originalState.loanScale)); + BEAST_EXPECT(newState.managementFeeOutstanding < originalState.managementFeeOutstanding); + BEAST_EXPECT(isRounded(broker.asset, newState.totalValue, originalState.loanScale)); + BEAST_EXPECT(isRounded(broker.asset, newState.principalOutstanding, originalState.loanScale)); + } + + void + testLoanPayComputePeriodicPaymentValidTotalInterestInvariant() + { + // From FIND-010 + testcase << "xrpl::loanComputePaymentParts : valid total interest"; + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + auto trustLenderTx = env.json(trust(lender, iouAsset(1'000'000'000))); + env(trustLenderTx); + auto trustBorrowerTx = env.json(trust(borrower, iouAsset(1'000'000'000))); + env(trustBorrowerTx); + auto payLenderTx = pay(issuer, lender, iouAsset(100'000'000)); + env(payLenderTx); + auto payIssuerTx = pay(issuer, borrower, iouAsset(1'000'000)); + env(payIssuerTx); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["CloseInterestRate"] = 47299; + createJson["ClosePaymentFee"] = "3985819770"; + createJson["InterestRate"] = 92; + createJson["LatePaymentFee"] = "3866894865"; + createJson["LoanOriginationFee"] = "0"; + createJson["LoanServiceFee"] = "2348810240"; + createJson["OverpaymentFee"] = 58545; + createJson["PaymentInterval"] = 60; + createJson["PaymentTotal"] = 1; + createJson["PrincipalRequested"] = "0.000763058"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, THISLINE); + env.close(); + + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, Number{}})); + loanPayTx["Amount"]["value"] = "0.000281284125490196"; + env(loanPayTx, ter(tecINSUFFICIENT_PAYMENT), THISLINE); + env.close(); + } + + void + testDosLoanPay() + { + // From FIND-005 + testcase << "DoS LoanPay"; + + using namespace jtx; + using namespace std::chrono_literals; + using namespace Lending; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + env(trust(lender, iouAsset(100'000'000))); + env(trust(borrower, iouAsset(100'000'000))); + env(pay(issuer, lender, iouAsset(10'000'000))); + env(pay(issuer, borrower, iouAsset(1'000))); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + auto const baseFee = env.current()->fees().base; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["ClosePaymentFee"] = "0"; + createJson["GracePeriod"] = 60; + createJson["InterestRate"] = 20930; + createJson["LateInterestRate"] = 77049; + createJson["LatePaymentFee"] = "0"; + createJson["LoanServiceFee"] = "0"; + createJson["OverpaymentFee"] = 7; + createJson["OverpaymentInterestRate"] = 66653; + createJson["PaymentInterval"] = 60; + createJson["PaymentTotal"] = 3239184; + createJson["PrincipalRequested"] = "3959.37"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, ter(tesSUCCESS)); + env.close(); + + auto const stateBefore = getCurrentState(env, broker, keylet); + BEAST_EXPECT(stateBefore.paymentRemaining == 3239184); + BEAST_EXPECT(stateBefore.paymentRemaining > loanMaximumPaymentsPerTransaction); + + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, Number{}})); + Number const amount{395937, -2}; + loanPayTx["Amount"]["value"] = to_string(amount); + XRPAmount const payFee{ + baseFee * std::int64_t(amount / stateBefore.periodicPayment / loanPaymentsPerFeeIncrement + 1)}; + env(loanPayTx, ter(tesSUCCESS), fee(payFee)); + env.close(); + + auto const stateAfter = getCurrentState(env, broker, keylet); + BEAST_EXPECT(stateAfter.paymentRemaining == stateBefore.paymentRemaining - loanMaximumPaymentsPerTransaction); + } + + void + testLoanPayComputePeriodicPaymentValidTotalPrincipalPaidInvariant() + { + // From FIND-009 + testcase << "xrpl::loanComputePaymentParts : totalPrincipalPaid " + "rounded"; + + using namespace jtx; + using namespace std::chrono_literals; + using namespace Lending; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + auto trustLenderTx = env.json(trust(lender, iouAsset(1'000'000'000))); + env(trustLenderTx); + auto trustBorrowerTx = env.json(trust(borrower, iouAsset(1'000'000'000))); + env(trustBorrowerTx); + auto payLenderTx = pay(issuer, lender, iouAsset(100'000'000)); + env(payLenderTx); + auto payIssuerTx = pay(issuer, borrower, iouAsset(1'000'000)); + env(payIssuerTx); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["ClosePaymentFee"] = "0"; + createJson["InterestRate"] = 24346; + createJson["LateInterestRate"] = 65535; + createJson["LatePaymentFee"] = "0"; + createJson["LoanOriginationFee"] = "218"; + createJson["LoanServiceFee"] = "0"; + createJson["PaymentInterval"] = 60; + createJson["PaymentTotal"] = 5678; + createJson["PrincipalRequested"] = "9924.81"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, ter(tesSUCCESS)); + env.close(); + + auto const baseFee = env.current()->fees().base; + + auto const stateBefore = getCurrentState(env, broker, keylet); + + { + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, Number{}})); + Number const amount{3074'745'058'823'529, -12}; + BEAST_EXPECT(to_string(amount) == "3074.745058823529"); + XRPAmount const payFee{baseFee * (amount / stateBefore.periodicPayment / loanPaymentsPerFeeIncrement + 1)}; + loanPayTx["Amount"]["value"] = to_string(amount); + env(loanPayTx, fee(payFee), ter(tesSUCCESS)); + env.close(); + } + + { + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, Number{}})); + Number const amount{6732'118'170'944'051, -12}; + BEAST_EXPECT(to_string(amount) == "6732.118170944051"); + XRPAmount const payFee{baseFee * (amount / stateBefore.periodicPayment / loanPaymentsPerFeeIncrement + 1)}; + loanPayTx["Amount"]["value"] = to_string(amount); + env(loanPayTx, fee(payFee), ter(tesSUCCESS)); + env.close(); + } + + auto const stateAfter = getCurrentState(env, broker, keylet); + // Total interest outstanding is non-negative + BEAST_EXPECT(stateAfter.totalValue >= stateAfter.principalOutstanding); + // Principal paid is non-negative + BEAST_EXPECT(stateBefore.principalOutstanding >= stateAfter.principalOutstanding); + // Total value change is non-negative + BEAST_EXPECT(stateBefore.totalValue >= stateAfter.totalValue); + // Value delta is larger or same as principal delta (meaning + // non-negative interest paid) + BEAST_EXPECT( + (stateBefore.totalValue - stateAfter.totalValue) >= + (stateBefore.principalOutstanding - stateAfter.principalOutstanding)); + } + + void + testLoanPayComputePeriodicPaymentValidTotalInterestPaidInvariant() + { + // From FIND-008 + testcase << "xrpl::loanComputePaymentParts : loanValueChange rounded"; + + using namespace jtx; + using namespace std::chrono_literals; + using namespace Lending; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + auto trustLenderTx = env.json(trust(lender, iouAsset(1'000'000'000))); + env(trustLenderTx); + auto trustBorrowerTx = env.json(trust(borrower, iouAsset(1'000'000'000))); + env(trustBorrowerTx); + auto payLenderTx = pay(issuer, lender, iouAsset(100'000'000)); + env(payLenderTx); + auto payIssuerTx = pay(issuer, borrower, iouAsset(10'000'000)); + env(payIssuerTx); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender)}; + { + auto const coverDepositValue = broker.asset(broker.params.coverDeposit * 10).value(); + env(loanBroker::coverDeposit(lender, broker.brokerID, coverDepositValue)); + env.close(); + } + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest{1, 3}; + + auto createJson = env.json( + set(borrower, broker.brokerID, principalRequest), + fee(loanSetFee), + json(sfCounterpartySignature, Json::objectValue)); + + createJson["ClosePaymentFee"] = "0"; + createJson["InterestRate"] = 12833; + createJson["LateInterestRate"] = 77048; + createJson["LatePaymentFee"] = "0"; + createJson["LoanOriginationFee"] = "218"; + createJson["LoanServiceFee"] = "0"; + createJson["PaymentInterval"] = 752; + createJson["PaymentTotal"] = 5678; + createJson["PrincipalRequested"] = "9924.81"; + + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); + env(createJson, ter(tesSUCCESS)); + env.close(); + + auto const baseFee = env.current()->fees().base; + + auto const stateBefore = getCurrentState(env, broker, keylet); + BEAST_EXPECT(stateBefore.paymentRemaining == 5678); + BEAST_EXPECT(stateBefore.paymentRemaining > loanMaximumPaymentsPerTransaction); + + auto loanPayTx = env.json(pay(borrower, keylet.key, STAmount{broker.asset, Number{}})); + Number const amount{9924'81, -2}; + BEAST_EXPECT(to_string(amount) == "9924.81"); + XRPAmount const payFee{baseFee * (amount / stateBefore.periodicPayment / loanPaymentsPerFeeIncrement + 1)}; + loanPayTx["Amount"]["value"] = to_string(amount); + env(loanPayTx, fee(payFee), ter(tesSUCCESS)); + env.close(); + + auto const stateAfter = getCurrentState(env, broker, keylet); + BEAST_EXPECT(stateAfter.paymentRemaining == stateBefore.paymentRemaining - loanMaximumPaymentsPerTransaction); + } + + void + testLoanNextPaymentDueDateOverflow() + { + // For FIND-013 + testcase << "Prevent nextPaymentDueDate overflow"; + + using namespace jtx; + using namespace std::chrono_literals; + using namespace Lending; + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const iouAsset = issuer[iouCurrency]; + auto trustLenderTx = env.json(trust(lender, iouAsset(1'000'000'000))); + env(trustLenderTx); + auto trustBorrowerTx = env.json(trust(borrower, iouAsset(1'000'000'000))); + env(trustBorrowerTx); + auto payLenderTx = pay(issuer, lender, iouAsset(100'000'000)); + env(payLenderTx); + auto payIssuerTx = pay(issuer, borrower, iouAsset(10'000'000)); + env(payIssuerTx); + env.close(); + + BrokerParameters const brokerParams{.debtMax = Number{0}, .coverRateMin = TenthBips32{1}}; + BrokerInfo broker{createVaultAndBroker(env, iouAsset, lender, brokerParams)}; + + using namespace loan; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + + using timeType = decltype(sfNextPaymentDueDate)::type::value_type; + static_assert(std::is_same_v); + timeType constexpr maxTime = std::numeric_limits::max(); + static_assert(maxTime == 4'294'967'295); + + auto const baseJson = [&]() { + auto createJson = env.json( + set(borrower, broker.brokerID, Number{55524'81, -2}), + fee(loanSetFee), + closePaymentFee(0), + gracePeriod(LoanSet::defaultGracePeriod), + interestRate(TenthBips32(12833)), + lateInterestRate(TenthBips32(77048)), + latePaymentFee(0), + loanOriginationFee(218), + json(sfCounterpartySignature, Json::objectValue)); + + createJson.removeMember(sfSequence.getJsonName()); + + return createJson; + }(); + + auto const baseFee = env.current()->fees().base; + + auto parentCloseTime = [&]() { return env.current()->parentCloseTime().time_since_epoch().count(); }; + auto maxLoanTime = [&]() { + auto const startDate = parentCloseTime(); + + BEAST_EXPECT(startDate >= 50); + + return maxTime - startDate; + }; + + { + // straight-up overflow: interval + auto const interval = maxLoanTime() + 1; + auto const total = 1; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // straight-up overflow: total + // min interval is 60 + auto const interval = 60; + auto const total = maxLoanTime() + 1; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // straight-up overflow: grace period + // min interval is 60 + auto const interval = maxLoanTime() + 1; + auto const total = 1; + auto const grace = interval; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total), gracePeriod(grace)); + + // The grace period can't be larger than the interval. + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // Overflow with multiplication of a few large intervals + auto const interval = 1'000'000'000; + auto const total = 10; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // Overflow with multiplication of many small payments + // min interval is 60 + auto const interval = 60; + auto const total = 1'000'000'000; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // Overflow with an absurdly large grace period + // min interval is 60 + auto const total = 60; + auto const interval = (maxLoanTime() - total) / total; + auto const grace = interval; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total), gracePeriod(grace)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tecKILLED)); + env.close(); + } + { + // Start date when the ledger is closed will be larger + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + auto const grace = 100; + auto const interval = maxLoanTime() - grace; + auto const total = 1; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total), gracePeriod(grace)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tesSUCCESS)); + env.close(); + + // The transaction is killed in the closed ledger + auto const meta = env.meta(); + if (BEAST_EXPECT(meta)) + { + BEAST_EXPECT(meta->at(sfTransactionResult) == tecKILLED); + } + + // If the transaction had succeeded, the loan would exist + auto const loanSle = env.le(keylet); + // but it doesn't + BEAST_EXPECT(!loanSle); + } + { + // Start date when the ledger is closed will be larger + auto const brokerStateBefore = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSequence = brokerStateBefore->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + auto const closeStartDate = (parentCloseTime() / 10 + 1) * 10; + auto const grace = 5'000; + auto const interval = maxTime - closeStartDate - grace; + auto const total = 1; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total), gracePeriod(grace)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tesSUCCESS)); + env.close(); + + // The transaction succeeds in the closed ledger + auto const meta = env.meta(); + if (BEAST_EXPECT(meta)) + { + BEAST_EXPECT(meta->at(sfTransactionResult) == tesSUCCESS); + } + + // This loan exists + auto const afterState = getCurrentState(env, broker, keylet); + BEAST_EXPECT(afterState.nextPaymentDate == maxTime - grace); + BEAST_EXPECT(afterState.previousPaymentDate == 0); + BEAST_EXPECT(afterState.paymentRemaining == 1); + } + + { + // Ensure the borrower has funds to pay back the loan + env(pay(issuer, borrower, iouAsset(Number{1'055'524'81, -2}))); + + // Start date when the ledger is closed will be larger + auto const closeStartDate = (parentCloseTime() / 10 + 1) * 10; + auto const grace = 5'000; + auto const maxLoanTime = maxTime - closeStartDate - grace; + auto const total = [&]() { + if (maxLoanTime % 5 == 0) + return 5; + if (maxLoanTime % 3 == 0) + return 3; + if (maxLoanTime % 2 == 0) + return 2; + return 0; + }(); + if (!BEAST_EXPECT(total != 0)) + return; + + auto const brokerState = env.le(keylet::loanbroker(broker.brokerID)); + // Intentionally shadow the outer values + auto const loanSequence = brokerState->at(sfLoanSequence); + auto const keylet = keylet::loan(broker.brokerID, loanSequence); + + auto const interval = maxLoanTime / total; + auto createJson = env.json(baseJson, paymentInterval(interval), paymentTotal(total), gracePeriod(grace)); + + env(createJson, sig(sfCounterpartySignature, lender), ter(tesSUCCESS)); + env.close(); + + // This loan exists + auto const beforeState = getCurrentState(env, broker, keylet); + BEAST_EXPECT(beforeState.nextPaymentDate == closeStartDate + interval); + BEAST_EXPECT(beforeState.previousPaymentDate == 0); + BEAST_EXPECT(beforeState.paymentRemaining == total); + BEAST_EXPECT(beforeState.periodicPayment > 0); + + // pay all but the last payment + { + NumberRoundModeGuard mg{Number::upward}; + Number const payment = beforeState.periodicPayment * (total - 1); + XRPAmount const payFee{baseFee * ((total - 1) / loanPaymentsPerFeeIncrement + 1)}; + STAmount const paymentAmount = roundToScale(STAmount{broker.asset, payment}, beforeState.loanScale); + auto loanPayTx = env.json(pay(borrower, keylet.key, paymentAmount), fee(payFee)); + env(loanPayTx, ter(tesSUCCESS)); + env.close(); + } + + // The loan is on the last payment + auto const afterState = getCurrentState(env, broker, keylet); + BEAST_EXPECT(afterState.paymentRemaining == 1); + BEAST_EXPECT(afterState.nextPaymentDate == maxTime - grace); + BEAST_EXPECT(afterState.previousPaymentDate == maxTime - grace - interval); + } + } + + void + testRequireAuth() + { + testcase("Require Auth - Implicit Pseudo-account authorization"); + using namespace jtx; + using namespace loan; + Account const lender{"lender"}; + Account const issuer{"issuer"}; + Account const borrower{"borrower"}; + Env env(*this); + + env.fund(XRP(100'000), issuer, lender, borrower); + env.close(); + + auto asset = MPTTester({ + .env = env, + .issuer = issuer, + .holders = {lender, borrower}, + .flags = MPTDEXFlags | tfMPTRequireAuth | tfMPTCanClawback | tfMPTCanLock, + .authHolder = true, + }); + + env(pay(issuer, lender, asset(5'000'000))); + BrokerInfo brokerInfo{createVaultAndBroker(env, asset, lender)}; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + STAmount const debtMaximumRequest = brokerInfo.asset(1'000).value(); + + auto forUnauthAuth = [&](auto&& doTx) { + for (auto const flag : {tfMPTUnauthorize, 0u}) + { + asset.authorize({.account = issuer, .holder = borrower, .flags = flag}); + env.close(); + doTx(flag == 0); + env.close(); + } + }; + + // Can't create a loan if the borrower is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(set(borrower, brokerInfo.brokerID, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + err); + }); + + std::uint32_t constexpr loanSequence = 1; + auto const loanKeylet = keylet::loan(brokerInfo.brokerID, loanSequence); + + // Can't loan pay if the borrower is not authorized + forUnauthAuth([&](bool authorized) { + auto const err = !authorized ? ter(tecNO_AUTH) : ter(tesSUCCESS); + env(pay(borrower, loanKeylet.key, debtMaximumRequest), err); + }); + } + + void + testCoverDepositWithdrawNonTransferableMPT() + { + testcase("CoverDeposit and CoverWithdraw reject MPT without CanTransfer"); + using namespace jtx; + using namespace loanBroker; + + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const alice{"alice"}; + + env.fund(XRP(100'000), issuer, alice); + env.close(); + + MPTTester mpt{env, issuer, mptInitNoFund}; + + mpt.create({.flags = tfMPTCanTransfer, .mutableFlags = tmfMPTCanMutateCanTransfer}); + + env.close(); + + PrettyAsset const asset = mpt["MPT"]; + mpt.authorize({.account = alice}); + env.close(); + + // Issuer can fund the holder even if CanTransfer is not set. + env(pay(issuer, alice, asset(100))); + env.close(); + + Vault vault{env}; + auto const [createTx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); + env(createTx); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice)); + env(set(alice, vaultKeylet.key)); + env.close(); + + auto const brokerSle = env.le(brokerKeylet); + if (!BEAST_EXPECT(brokerSle)) + return; + + Account const pseudoAccount{"Loan Broker pseudo-account", brokerSle->at(sfAccount)}; + + // Remove CanTransfer after the broker is set up. + mpt.set({.mutableFlags = tmfMPTClearCanTransfer}); + env.close(); + + // Standard Payment path should forbid third-party transfers. + env(pay(alice, pseudoAccount, asset(1)), ter(tecNO_AUTH)); + env.close(); + + // Cover cannot be transferred to broker account + auto const depositAmount = asset(1); + env(coverDeposit(alice, brokerKeylet.key, depositAmount), ter{tecNO_AUTH}); + env.close(); + + if (auto const refreshed = env.le(brokerKeylet); BEAST_EXPECT(refreshed)) + { + BEAST_EXPECT(refreshed->at(sfCoverAvailable) == 0); + env.require(balance(pseudoAccount, asset(0))); + } + + // Set CanTransfer again and transfer some deposit + mpt.set({.mutableFlags = tmfMPTSetCanTransfer}); + env.close(); + + env(coverDeposit(alice, brokerKeylet.key, depositAmount)); + env.close(); + + if (auto const refreshed = env.le(brokerKeylet); BEAST_EXPECT(refreshed)) + { + BEAST_EXPECT(refreshed->at(sfCoverAvailable) == 1); + env.require(balance(pseudoAccount, depositAmount)); + } + + // Remove CanTransfer after the deposit + mpt.set({.mutableFlags = tmfMPTClearCanTransfer}); + env.close(); + + // Cover cannot be transferred from broker account + env(coverWithdraw(alice, brokerKeylet.key, depositAmount), ter{tecNO_AUTH}); + env.close(); + + // Set CanTransfer again and withdraw + mpt.set({.mutableFlags = tmfMPTSetCanTransfer}); + env.close(); + + env(coverWithdraw(alice, brokerKeylet.key, depositAmount)); + env.close(); + + if (auto const refreshed = env.le(brokerKeylet); BEAST_EXPECT(refreshed)) + { + BEAST_EXPECT(refreshed->at(sfCoverAvailable) == 0); + env.require(balance(pseudoAccount, asset(0))); + } + } + +#if LOANTODO + void + testLoanPayLateFullPaymentBypassesPenalties() + { + testcase("LoanPay full payment skips late penalties"); + using namespace jtx; + using namespace loan; + using namespace std::chrono_literals; + + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000), issuer, lender, borrower); + env.close(); + + PrettyAsset const asset = issuer[iouCurrency]; + env(trust(lender, asset(100'000'000))); + env(trust(borrower, asset(100'000'000))); + env(pay(issuer, lender, asset(50'000'000))); + env(pay(issuer, borrower, asset(5'000'000))); + env.close(); + + BrokerInfo broker{createVaultAndBroker(env, asset, lender)}; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + + auto const brokerPreLoan = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerPreLoan)) + return; + + auto const loanSequence = brokerPreLoan->at(sfLoanSequence); + auto const loanKeylet = keylet::loan(broker.brokerID, loanSequence); + + Number const principal = asset(1'000).value(); + Number const serviceFee = asset(2).value(); + Number const lateFee = asset(5).value(); + Number const closeFee = asset(4).value(); + + env(set(borrower, broker.brokerID, principal), + sig(sfCounterpartySignature, lender), + loanServiceFee(serviceFee), + latePaymentFee(lateFee), + closePaymentFee(closeFee), + interestRate(percentageToTenthBips(12)), + lateInterestRate(percentageToTenthBips(24) / 10), + closeInterestRate(percentageToTenthBips(5)), + paymentTotal(12), + paymentInterval(600), + gracePeriod(0), + fee(loanSetFee)); + env.close(); + + auto state1 = getCurrentState(env, broker, loanKeylet); + if (!BEAST_EXPECT(state1.paymentRemaining > 1)) + return; + + using d = NetClock::duration; + using tp = NetClock::time_point; + auto const overdueClose = tp{d{state1.nextPaymentDate + state1.paymentInterval}}; + env.close(overdueClose); + + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + auto const loanSle = env.le(loanKeylet); + if (!BEAST_EXPECT(brokerSle && loanSle)) + return; + + auto state = getCurrentState(env, broker, loanKeylet); + + TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)}; + TenthBips32 const interestRateValue{loanSle->at(sfInterestRate)}; + TenthBips32 const lateInterestRateValue{loanSle->at(sfLateInterestRate)}; + TenthBips32 const closeInterestRateValue{loanSle->at(sfCloseInterestRate)}; + + Number const closePaymentFeeRounded = + roundToAsset(broker.asset, loanSle->at(sfClosePaymentFee), state.loanScale); + Number const latePaymentFeeRounded = roundToAsset(broker.asset, loanSle->at(sfLatePaymentFee), state.loanScale); + + auto const roundedLoanState = + constructLoanState(state.totalValue, state.principalOutstanding, state.managementFeeOutstanding); + Number const totalInterestOutstanding = roundedLoanState.interestDue; + + auto const periodicRate = loanPeriodicRate(interestRateValue, state.paymentInterval); + auto const rawLoanState = + computeTheoreticalLoanState(state.periodicPayment, periodicRate, state.paymentRemaining, managementFeeRate); + + auto const parentCloseTime = env.current()->parentCloseTime(); + auto const startDateSeconds = static_cast(state.startDate.time_since_epoch().count()); + + Number const fullPaymentInterest = computeFullPaymentInterest( + rawLoanState.principalOutstanding, + periodicRate, + parentCloseTime, + state.paymentInterval, + state.previousPaymentDate, + startDateSeconds, + closeInterestRateValue); + + Number const roundedFullInterestAmount = roundToAsset(broker.asset, fullPaymentInterest, state.loanScale); + Number const roundedFullManagementFee = + computeManagementFee(broker.asset, roundedFullInterestAmount, managementFeeRate, state.loanScale); + Number const roundedFullInterest = roundedFullInterestAmount - roundedFullManagementFee; + + Number const trackedValueDelta = + state.principalOutstanding + totalInterestOutstanding + state.managementFeeOutstanding; + Number const untrackedManagementFee = + closePaymentFeeRounded + roundedFullManagementFee - state.managementFeeOutstanding; + Number const untrackedInterest = roundedFullInterest - totalInterestOutstanding; + + Number const baseFullDue = trackedValueDelta + untrackedInterest + untrackedManagementFee; + BEAST_EXPECT(baseFullDue == roundToAsset(broker.asset, baseFullDue, state.loanScale)); + + auto const overdueSeconds = parentCloseTime.time_since_epoch().count() - state.nextPaymentDate; + if (!BEAST_EXPECT(overdueSeconds > 0)) + return; + + Number const overdueRate = loanPeriodicRate(lateInterestRateValue, overdueSeconds); + Number const lateInterestRaw = state.principalOutstanding * overdueRate; + Number const lateInterestRounded = roundToAsset(broker.asset, lateInterestRaw, state.loanScale); + Number const lateManagementFeeRounded = + computeManagementFee(broker.asset, lateInterestRounded, managementFeeRate, state.loanScale); + Number const penaltyDue = lateInterestRounded + lateManagementFeeRounded + latePaymentFeeRounded; + BEAST_EXPECT(penaltyDue > Number{}); + + auto const balanceBefore = env.balance(borrower, broker.asset).number(); + + STAmount const paymentAmount{broker.asset.raw(), baseFullDue}; + env(pay(borrower, loanKeylet.key, paymentAmount, tfLoanFullPayment)); + env.close(); + + if (auto const meta = env.meta(); BEAST_EXPECT(meta)) + BEAST_EXPECT(meta->at(sfTransactionResult) == tesSUCCESS); + + auto const balanceAfter = env.balance(borrower, broker.asset).number(); + Number const actualPaid = balanceBefore - balanceAfter; + BEAST_EXPECT(actualPaid == baseFullDue); + + Number const expectedWithPenalty = baseFullDue + penaltyDue; + BEAST_EXPECT(expectedWithPenalty > actualPaid); + BEAST_EXPECT(expectedWithPenalty - actualPaid == penaltyDue); + } + + void + testLoanCoverMinimumRoundingExploit() + { + auto testLoanCoverMinimumRoundingExploit = [&, this](Number const& principalRequest) { + testcase << "LoanBrokerCoverClawback drains cover via rounding" + << " principalRequested=" << to_string(principalRequest); + + using namespace jtx; + using namespace loan; + using namespace loanBroker; + + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(1'000'000'000), issuer, lender, borrower); + env.close(); + + env(fset(issuer, asfAllowTrustLineClawback)); + env.close(); + + PrettyAsset const asset = issuer[iouCurrency]; + env(trust(lender, asset(2'000'0000))); + env(trust(borrower, asset(2'000'0000))); + env.close(); + + env(pay(issuer, lender, asset(2'000'0000))); + env.close(); + + BrokerParameters brokerParams{.debtMax = 0, .coverRateMin = TenthBips32{10'000}}; + BrokerInfo broker{createVaultAndBroker(env, asset, lender, brokerParams)}; + + auto const loanSetFee = fee(env.current()->fees().base * 2); + auto createTx = env.jt( + set(borrower, broker.brokerID, principalRequest), + sig(sfCounterpartySignature, lender), + loanSetFee, + paymentInterval(600), + paymentTotal(1), + gracePeriod(60)); + env(createTx); + env.close(); + + auto const brokerBefore = env.le(keylet::loanbroker(broker.brokerID)); + BEAST_EXPECT(brokerBefore); + if (!brokerBefore) + return; + + Number const debtOutstanding = brokerBefore->at(sfDebtTotal); + Number const coverAvailableBefore = brokerBefore->at(sfCoverAvailable); + + BEAST_EXPECT(debtOutstanding > Number{}); + BEAST_EXPECT(coverAvailableBefore > Number{}); + + log << "debt=" << to_string(debtOutstanding) << " cover_available=" << to_string(coverAvailableBefore); + + env(coverClawback(issuer, 0), loanBrokerID(broker.brokerID)); + env.close(); + + auto const brokerAfter = env.le(keylet::loanbroker(broker.brokerID)); + BEAST_EXPECT(brokerAfter); + if (!brokerAfter) + return; + + Number const debtAfter = brokerAfter->at(sfDebtTotal); + // the debt has not changed + BEAST_EXPECT(debtAfter == debtOutstanding); + + Number const coverAvailableAfter = brokerAfter->at(sfCoverAvailable); + + // since the cover rate min != 0, the cover available should not + // be zero + BEAST_EXPECT(coverAvailableAfter != Number{}); + }; + + // Call the lambda with different principal values + testLoanCoverMinimumRoundingExploit(Number{1, -30}); // 1e-30 units + testLoanCoverMinimumRoundingExploit(Number{1, -20}); // 1e-20 units + testLoanCoverMinimumRoundingExploit(Number{1, -10}); // 1e-10 units + testLoanCoverMinimumRoundingExploit(Number{1, 1}); // 1e-10 units + } +#endif + + void + testPoC_UnsignedUnderflowOnFullPayAfterEarlyPeriodic() + { + // --- PoC Summary ---------------------------------------------------- + // Scenario: Borrower makes one periodic payment early (before next due) + // so doPayment sets sfPreviousPaymentDueDate to the (future) + // sfNextPaymentDueDate and advances sfNextPaymentDueDate by one + // interval. Borrower then immediately performs a full-payment + // (tfLoanFullPayment). Why it matters: Full-payment interest accrual + // uses + // delta = now - max(prevPaymentDate, startDate) + // with an unsigned clock representation (uint32). If prevPaymentDate is + // in the future, the subtraction underflows to a very large positive + // number. This inflates roundedFullInterest and total full-close due, + // and LoanPay applies the inflated valueChange to the vault + // (sfAssetsTotal), increasing NAV. + // -------------------------------------------------------------------- + testcase("PoC: Unsigned-underflow full-pay accrual after early periodic"); + + using namespace jtx; + using namespace loan; + using namespace std::chrono_literals; + + Env env(*this, all); + + Account const lender{"poc_lender4"}; + Account const borrower{"poc_borrower4"}; + env.fund(XRP(3'000'000), lender, borrower); + env.close(); + + PrettyAsset const asset{xrpIssue(), 1'000'000}; + BrokerParameters brokerParams{}; + auto const broker = createVaultAndBroker(env, asset, lender, brokerParams); + + // Create a 3-payment loan so full-payment path is enabled after 1 + // periodic payment. + auto const loanSetFee = fee(env.current()->fees().base * 2); + Number const principalRequest = asset(1000).value(); + auto const originationFee = asset(0).value(); + auto const serviceFee = asset(1).value(); + auto const serviceFeePA = asset(1); + auto const lateFee = asset(0).value(); + auto const closeFee = asset(0).value(); + auto const interest = percentageToTenthBips(12); + auto const lateInterest = percentageToTenthBips(12) / 10; + auto const closeInterest = percentageToTenthBips(12) / 10; + auto const overpaymentInterest = percentageToTenthBips(12) / 10; + auto const total = 3u; + auto const interval = 600u; + auto const grace = 60u; + + auto createJtx = env.jt( + set(borrower, broker.brokerID, principalRequest, 0), + sig(sfCounterpartySignature, lender), + loanOriginationFee(originationFee), + loanServiceFee(serviceFee), + latePaymentFee(lateFee), + closePaymentFee(closeFee), + overpaymentFee(percentageToTenthBips(5) / 10), + interestRate(interest), + lateInterestRate(lateInterest), + closeInterestRate(closeInterest), + overpaymentInterestRate(overpaymentInterest), + paymentTotal(total), + paymentInterval(interval), + gracePeriod(grace), + fee(loanSetFee)); + + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + BEAST_EXPECT(brokerSle); + auto const loanSequence = brokerSle ? brokerSle->at(sfLoanSequence) : 0; + auto const loanKeylet = keylet::loan(broker.brokerID, loanSequence); + + env(createJtx); + env.close(); + + // Compute a regular periodic due and pay it early (before next due). + auto state = getCurrentState(env, broker, loanKeylet); + Number const periodicRate = loanPeriodicRate(state.interestRate, state.paymentInterval); + auto const components = detail::computePaymentComponents( + asset.raw(), + state.loanScale, + state.totalValue, + state.principalOutstanding, + state.managementFeeOutstanding, + state.periodicPayment, + periodicRate, + state.paymentRemaining, + brokerParams.managementFeeRate); + STAmount const regularDue{asset, components.trackedValueDelta + serviceFeePA.number()}; + // now < nextDue immediately after creation, so this is an early pay. + env(pay(borrower, loanKeylet.key, regularDue)); + env.close(); + + // Immediately attempt a full payoff. Compute the exact full-payment + // due to ensure the tx applies. + auto after = getCurrentState(env, broker, loanKeylet); + auto const loanSle = env.le(loanKeylet); + BEAST_EXPECT(loanSle); + auto const brokerSle2 = env.le(keylet::loanbroker(broker.brokerID)); + BEAST_EXPECT(brokerSle2); + + auto const closePaymentFee = loanSle ? loanSle->at(sfClosePaymentFee) : Number{}; + auto const closeInterestRate = loanSle ? TenthBips32{loanSle->at(sfCloseInterestRate)} : TenthBips32{}; + auto const managementFeeRate = brokerSle2 ? TenthBips16{brokerSle2->at(sfManagementFeeRate)} : TenthBips16{}; + + Number const periodicRate2 = loanPeriodicRate(after.interestRate, after.paymentInterval); + // Accrued + prepayment-penalty interest based on current periodic + // schedule + auto const fullPaymentInterest = computeFullPaymentInterest( + detail::loanPrincipalFromPeriodicPayment(after.periodicPayment, periodicRate2, after.paymentRemaining), + periodicRate2, + env.current()->parentCloseTime(), + after.paymentInterval, + after.previousPaymentDate, + static_cast(after.startDate.time_since_epoch().count()), + closeInterestRate); + + // Round to asset scale and split interest/fee parts + auto const roundedInterest = roundToAsset(asset.raw(), fullPaymentInterest, after.loanScale); + Number const roundedFullMgmtFee = + computeManagementFee(asset.raw(), roundedInterest, managementFeeRate, after.loanScale); + Number const roundedFullInterest = roundedInterest - roundedFullMgmtFee; + + // Show both signed and unsigned deltas to highlight the underflow. + auto const nowSecs = static_cast(env.current()->parentCloseTime().time_since_epoch().count()); + auto const startSecs = static_cast(after.startDate.time_since_epoch().count()); + auto const lastPaymentDate = std::max(after.previousPaymentDate, startSecs); + auto const signedDelta = static_cast(nowSecs) - static_cast(lastPaymentDate); + auto const unsignedDelta = static_cast(nowSecs - lastPaymentDate); + log << "PoC window: prev=" << after.previousPaymentDate << " start=" << startSecs << " now=" << nowSecs + << " signedDelta=" << signedDelta << " unsignedDelta=" << unsignedDelta << std::endl; + + // Reference (clamped) computation: emulate a non-negative accrual + // window by clamping prevPaymentDate to 'now' for the full-pay path. + auto const prevClamped = std::min(after.previousPaymentDate, nowSecs); + auto const fullPaymentInterestClamped = computeFullPaymentInterest( + detail::loanPrincipalFromPeriodicPayment(after.periodicPayment, periodicRate2, after.paymentRemaining), + periodicRate2, + env.current()->parentCloseTime(), + after.paymentInterval, + prevClamped, + startSecs, + closeInterestRate); + auto const roundedInterestClamped = roundToAsset(asset.raw(), fullPaymentInterestClamped, after.loanScale); + Number const roundedFullMgmtFeeClamped = + computeManagementFee(asset.raw(), roundedInterestClamped, managementFeeRate, after.loanScale); + Number const roundedFullInterestClamped = roundedInterestClamped - roundedFullMgmtFeeClamped; + STAmount const fullDueClamped{ + asset, + after.principalOutstanding + roundedFullInterestClamped + roundedFullMgmtFeeClamped + closePaymentFee}; + + // Collect vault NAV before closing payment + auto const vaultId2 = brokerSle2 ? brokerSle2->at(sfVaultID) : uint256{}; + auto const vaultKey2 = keylet::vault(vaultId2); + auto const vaultBefore = env.le(vaultKey2); + BEAST_EXPECT(vaultBefore); + Number const assetsTotalBefore = vaultBefore ? vaultBefore->at(sfAssetsTotal) : Number{}; + + STAmount const fullDue{ + asset, after.principalOutstanding + roundedFullInterest + roundedFullMgmtFee + closePaymentFee}; + + log << "PoC payoff: principalOutstanding=" << after.principalOutstanding + << " roundedFullInterest=" << roundedFullInterest << " roundedFullMgmtFee=" << roundedFullMgmtFee + << " closeFee=" << closePaymentFee << " fullDue=" << to_string(fullDue.getJson()) << std::endl; + log << "PoC reference (clamped): roundedFullInterestClamped=" << roundedFullInterestClamped + << " roundedFullMgmtFeeClamped=" << roundedFullMgmtFeeClamped + << " fullDueClamped=" << to_string(fullDueClamped.getJson()) << std::endl; + + env(pay(borrower, loanKeylet.key, fullDue), txflags(tfLoanFullPayment)); + env.close(); + + // Sanity: underflow present (unsigned delta very large relative to + // interval) + BEAST_EXPECT(unsignedDelta > after.paymentInterval); + + // Compare vault NAV before/after the full close + auto const vaultAfter = env.le(vaultKey2); + BEAST_EXPECT(vaultAfter); + if (vaultAfter) + { + auto const assetsTotalAfter = vaultAfter->at(sfAssetsTotal); + log << "PoC NAV: assetsTotalBefore=" << assetsTotalBefore << " assetsTotalAfter=" << assetsTotalAfter + << " delta=" << (assetsTotalAfter - assetsTotalBefore) << std::endl; + + // Value-based proof: underflowed window yields a payoff larger than + // the clamped (non-underflow) reference. + BEAST_EXPECT(fullDue == fullDueClamped); + if (fullDue > fullDueClamped) + log << "PoC delta: overcharge (fullDue > clamped)" << std::endl; + } + + // Loan should be paid off + auto const finalLoan = env.le(loanKeylet); + BEAST_EXPECT(finalLoan); + if (finalLoan) + { + BEAST_EXPECT(finalLoan->at(sfPaymentRemaining) == 0); + BEAST_EXPECT(finalLoan->at(sfPrincipalOutstanding) == 0); + } + } + + void + testDustManipulation() + { + testcase("Dust manipulation"); + + using namespace jtx; + using namespace std::chrono_literals; + Env env(*this, all); + + // Setup: Create accounts + Account issuer{"issuer"}; + Account lender{"lender"}; + Account borrower{"borrower"}; + Account victim{"victim"}; + + env.fund(XRP(1'000'000'00), issuer, lender, borrower, victim); + env.close(); + + // Step 1: Create vault with IOU asset + auto asset = issuer["USD"]; + env(trust(lender, asset(100000))); + env(trust(borrower, asset(100000))); + env(trust(victim, asset(100000))); + env(pay(issuer, lender, asset(50000))); + env(pay(issuer, borrower, asset(50000))); + env(pay(issuer, victim, asset(50000))); + env.close(); + + BrokerParameters brokerParams{ + .vaultDeposit = 10000, + .debtMax = Number{0}, + .coverRateMin = TenthBips32{1000}, + .coverRateLiquidation = TenthBips32{2500}}; + + auto broker = createVaultAndBroker(env, asset, lender, brokerParams); + + auto const loanKeyletOpt = [&]() -> std::optional { + auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); + if (!BEAST_EXPECT(brokerSle)) + return std::nullopt; + + // Broker has no loans + BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); + + // The loan keylet is based on the LoanSequence of the + // _LOAN_BROKER_ object. + auto const loanSequence = brokerSle->at(sfLoanSequence); + return keylet::loan(broker.brokerID, loanSequence); + }(); + if (!loanKeyletOpt) + return; + + auto const& vaultKeylet = broker.vaultKeylet(); + + { + auto const vaultSle = env.le(vaultKeylet); + Number assetsTotal = vaultSle->at(sfAssetsTotal); + Number assetsAvail = vaultSle->at(sfAssetsAvailable); + + log << "Before loan creation:" << std::endl; + log << " AssetsTotal: " << assetsTotal << std::endl; + log << " AssetsAvailable: " << assetsAvail << std::endl; + log << " Difference: " << (assetsTotal - assetsAvail) << std::endl; + + // before the loan the assets total and available should be equal + BEAST_EXPECT(assetsAvail == assetsTotal); + BEAST_EXPECT(assetsAvail == broker.asset(brokerParams.vaultDeposit).number()); + } + + Keylet const& loanKeylet = *loanKeyletOpt; + + LoanParameters const loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = Number{100}, + .interest = TenthBips32{1922}, + .payTotal = 5816, + .payInterval = 86400 * 6, + .gracePd = 86400 * 5, + }; + + env(loanParams(env, broker)); + env.close(); + + // Wait for loan to be late enough to default + env.close(std::chrono::seconds(86400 * 40)); // 40 days + + { + auto const vaultSle = env.le(vaultKeylet); + Number assetsTotal = vaultSle->at(sfAssetsTotal); + Number assetsAvail = vaultSle->at(sfAssetsAvailable); + + log << "After loan creation:" << std::endl; + log << " AssetsTotal: " << assetsTotal << std::endl; + log << " AssetsAvailable: " << assetsAvail << std::endl; + log << " Difference: " << (assetsTotal - assetsAvail) << std::endl; + + auto const loanSle = env.le(loanKeylet); + if (!BEAST_EXPECT(loanSle)) + return; + auto const state = constructRoundedLoanState(loanSle); + + log << "Loan state:" << std::endl; + log << " ValueOutstanding: " << state.valueOutstanding << std::endl; + log << " PrincipalOutstanding: " << state.principalOutstanding << std::endl; + log << " InterestOutstanding: " << state.interestOutstanding() << std::endl; + log << " InterestDue: " << state.interestDue << std::endl; + log << " FeeDue: " << state.managementFeeDue << std::endl; + + // after loan creation the assets total and available should + // reflect the value of the loan + BEAST_EXPECT(assetsAvail < assetsTotal); + BEAST_EXPECT(assetsAvail == broker.asset(brokerParams.vaultDeposit - loanParams.principalRequest).number()); + BEAST_EXPECT(assetsTotal == broker.asset(brokerParams.vaultDeposit + state.interestDue).number()); + } + + // Step 7: Trigger default (dust adjustment will occur) + env(jtx::loan::manage(lender, loanKeylet.key, tfLoanDefault)); + env.close(); + + // Step 8: Verify phantom assets created + { + auto const vaultSle2 = env.le(vaultKeylet); + Number assetsTotal2 = vaultSle2->at(sfAssetsTotal); + Number assetsAvail2 = vaultSle2->at(sfAssetsAvailable); + + log << "After default:" << std::endl; + log << " AssetsTotal: " << assetsTotal2 << std::endl; + log << " AssetsAvailable: " << assetsAvail2 << std::endl; + log << " Difference: " << (assetsTotal2 - assetsAvail2) << std::endl; + + // after a default the assets total and available should be equal + BEAST_EXPECT(assetsAvail2 == assetsTotal2); + } + } + + void + testRIPD3831() + { + using namespace jtx; + + testcase("RIPD-3831"); + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + BrokerParameters const brokerParams{ + .vaultDeposit = 100000, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + // .managementFeeRate = TenthBips16{5919}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = Number{200'000, -6}, + .lateFee = Number{200, -6}, + .interest = TenthBips32{50'000}, + .payTotal = 10, + .payInterval = 150}; + + auto const assetType = AssetType::XRP; + + Env env(*this, all); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower); + + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + + using tp = NetClock::time_point; + using d = NetClock::duration; + + auto state = getCurrentState(env, broker, loanKeylet); + if (auto loan = env.le(loanKeylet); BEAST_EXPECT(loan)) + { + env.close(tp{d{loan->at(sfNextPaymentDueDate) + loan->at(sfGracePeriod) + 1}}); + } + + topUpBorrower(env, broker, issuer, borrower, state, loanParams.serviceFee); + + using namespace jtx::loan; + + auto jv = pay(borrower, loanKeylet.key, drops(XRPAmount(state.totalValue))); + + { + auto const submitParam = to_string(jv); + auto const jr = env.rpc("submit", borrower.name(), submitParam); + + BEAST_EXPECT(jr.isMember(jss::result)); + auto const jResult = jr[jss::result]; + } + + env.close(); + + // Make sure the system keeps responding + env(noop(borrower)); + env.close(); + env(noop(issuer)); + env.close(); + env(noop(lender)); + env.close(); + } + + void + testRIPD3459() + { + testcase("RIPD-3459 - LoanBroker incorrect debt total"); + + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + BrokerParameters const brokerParams{ + .vaultDeposit = 200'000, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = TenthBips16{500}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = Number{100'000, -4}, + .interest = TenthBips32{100'000}, + .payTotal = 10}; + + auto const assetType = AssetType::MPT; + + Env env(*this, all); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower); + + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + auto pseudoAcct = std::get(*loanResult); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet); + + if (auto const brokerSle = env.le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle)) + { + if (auto const loanSle = env.le(loanKeylet); BEAST_EXPECT(loanSle)) + { + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == loanSle->at(sfTotalValueOutstanding)); + } + } + + makeLoanPayments( + env, + broker, + loanParams, + loanKeylet, + verifyLoanStatus, + issuer, + lender, + borrower, + PaymentParameters{.showStepBalances = true}); + + if (auto const brokerSle = env.le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle)) + { + if (auto const loanSle = env.le(loanKeylet); BEAST_EXPECT(loanSle)) + { + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == loanSle->at(sfTotalValueOutstanding)); + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == beast::zero); + } + } + } + + void + testRIPD3901() + { + testcase("Crash with tfLoanOverpayment"); + using namespace jtx; + using namespace loan; + Account const lender{"lender"}; + Account const issuer{"issuer"}; + Account const borrower{"borrower"}; + Account const depositor{"depositor"}; + auto const txfee = fee(XRP(100)); + + Env env(*this); + Vault vault(env); + + env.fund(XRP(10'000), lender, issuer, borrower, depositor); + env.close(); + + auto [tx, vaultKeyLet] = vault.create({.owner = lender, .asset = xrpIssue()}); + env(tx, txfee); + env.close(); + + env(vault.deposit({.depositor = depositor, .id = vaultKeyLet.key, .amount = XRP(1'000)}), txfee); + env.close(); + + auto const brokerKeyLet = keylet::loanbroker(lender.id(), env.seq(lender)); + + env(loanBroker::set(lender, vaultKeyLet.key), txfee); + env.close(); + + // BrokerInfo brokerInfo{xrpIssue(), keylet, vaultKeyLet, {}}; + + STAmount const debtMaximumRequest = XRPAmount(200'000); + + env(set(borrower, brokerKeyLet.key, debtMaximumRequest), + sig(sfCounterpartySignature, lender), + interestRate(TenthBips32(50'000)), + paymentTotal(2), + paymentInterval(150), + txflags(tfLoanOverpayment), + txfee); + env.close(); + + std::uint32_t const loanSequence = 1; + auto const loanKeylet = keylet::loan(brokerKeyLet.key, loanSequence); + + if (auto loan = env.le(loanKeylet); env.test.BEAST_EXPECT(loan)) + { + env(loan::pay(borrower, loanKeylet.key, XRPAmount(150'001)), txflags(tfLoanOverpayment), txfee); + env.close(); + } + } + + void + testRoundingAllowsUndercoverage() + { + testcase("Minimum cover rounding allows undercoverage (XRP)"); + + using namespace jtx; + using namespace loanBroker; + + Env env(*this, all); + + Account const lender{"lender"}; + Account const borrower{"borrower"}; + + env.fund(XRP(200'000), lender, borrower); + env.close(); + + // Vault with XRP asset + Vault vault{env}; + auto [vaultCreate, vaultKeylet] = vault.create({.owner = lender, .asset = xrpIssue()}); + env(vaultCreate); + env.close(); + BEAST_EXPECT(env.le(vaultKeylet)); + + // Seed the vault with XRP so it can fund the loan principal + PrettyAsset const xrpAsset{xrpIssue(), 1}; + + BrokerParameters const brokerParams{ + .vaultDeposit = 1'000, + .debtMax = Number{0}, + .coverRateMin = TenthBips32{10'000}, + .coverDeposit = 82, + }; + + auto const brokerInfo = createVaultAndBroker(env, xrpAsset, lender, brokerParams); + // Create a loan with principal 804 XRP and 0% interest (so + // DebtTotal increases by exactly 804) + env(loan::set(borrower, brokerInfo.brokerID, xrpAsset(804).value()), + loan::interestRate(TenthBips32(0)), + sig(sfCounterpartySignature, lender), + fee(env.current()->fees().base * 2)); + BEAST_EXPECT(env.ter() == tesSUCCESS); + env.close(); + + // Verify DebtTotal is exactly 804 + if (auto const brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + log << *brokerSle << std::endl; + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == Number(804)); + } + + // Attempt to withdraw 2 XRP to self, leaving 80 XRP CoverAvailable. + // The minimum is 80.4 XRP, which rounds up to 81 XRP, so this fails. + env(coverWithdraw(lender, brokerInfo.brokerID, xrpAsset(2).value()), ter(tecINSUFFICIENT_FUNDS)); + BEAST_EXPECT(env.ter() == tecINSUFFICIENT_FUNDS); + env.close(); + + // Attempt to withdraw 1 XRP to self, leaving 81 XRP CoverAvailable. + // because that leaves sufficient cover, this succeeds + env(coverWithdraw(lender, brokerInfo.brokerID, xrpAsset(1).value())); + BEAST_EXPECT(env.ter() == tesSUCCESS); + env.close(); + + // Validate CoverAvailable == 80 XRP and DebtTotal remains 804 + if (auto const brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + log << *brokerSle << std::endl; + BEAST_EXPECT(brokerSle->at(sfCoverAvailable) == xrpAsset(81).value()); + BEAST_EXPECT(brokerSle->at(sfDebtTotal) == Number(804)); + + // Also demonstrate that the true minimum (804 * 10%) exceeds 80 + auto const theoreticalMin = tenthBipsOfValue(Number(804), TenthBips32(10'000)); + log << "Theoretical min cover: " << theoreticalMin << std::endl; + BEAST_EXPECT(Number(804, -1) == theoreticalMin); + } + } + + void + testRIPD3902() + { + testcase("RIPD-3902 - 1 IOU loan payments"); + + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + BrokerParameters const brokerParams{ + .vaultDeposit = 10, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = TenthBips16{0}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = Number{1, 0}, + .interest = TenthBips32{100'000}, + .payTotal = 5, + .payInterval = 150, + .gracePd = 60}; + + auto const assetType = AssetType::IOU; + + Env env(*this, all); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower); + + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + auto pseudoAcct = std::get(*loanResult); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet); + + makeLoanPayments( + env, + broker, + loanParams, + loanKeylet, + verifyLoanStatus, + issuer, + lender, + borrower, + PaymentParameters{.showStepBalances = true}); + } + + void + testBorrowerIsBroker() + { + testcase("Test Borrower is Broker"); + using namespace jtx; + using namespace loan; + Account const broker{"broker"}; + Account const issuer{"issuer"}; + Account const borrower_{"borrower"}; + Account const depositor{"depositor"}; + + auto testLoanAsset = [&](auto&& getMaxDebt, auto const& borrower) { + Env env(*this); + Vault vault(env); + + if (borrower == broker) + env.fund(XRP(10'000), broker, issuer, depositor); + else + env.fund(XRP(10'000), broker, borrower, issuer, depositor); + env.close(); + + auto const xrpFee = XRP(100); + auto const txFee = fee(xrpFee); + + STAmount const debtMaximumRequest = getMaxDebt(env); + + auto const& asset = debtMaximumRequest.asset(); + auto const initialVault = asset(debtMaximumRequest * 100); + + auto [tx, vaultKeylet] = vault.create({.owner = broker, .asset = asset}); + env(tx, txFee); + env.close(); + + env(vault.deposit({.depositor = depositor, .id = vaultKeylet.key, .amount = initialVault}), txFee); + env.close(); + + auto const brokerKeylet = keylet::loanbroker(broker.id(), env.seq(broker)); + + env(loanBroker::set(broker, vaultKeylet.key), txFee); + env.close(); + + auto const serviceFee = 101; + + env(set(broker, brokerKeylet.key, debtMaximumRequest), + counterparty(borrower), + sig(sfCounterpartySignature, borrower), + loanServiceFee(serviceFee), + paymentTotal(10), + txFee); + env.close(); + + std::uint32_t const loanSequence = 1; + auto const loanKeylet = keylet::loan(brokerKeylet.key, loanSequence); + + auto const brokerBalanceBefore = env.balance(broker, asset); + + if (auto const loanSle = env.le(loanKeylet); env.test.BEAST_EXPECT(loanSle)) + { + auto const payment = loanSle->at(sfPeriodicPayment); + auto const totalPayment = payment + serviceFee; + env(loan::pay(borrower, loanKeylet.key, asset(totalPayment)), txFee); + env.close(); + if (auto const vaultSle = env.le(vaultKeylet); BEAST_EXPECT(vaultSle)) + { + auto const expected = [&]() { + // The service fee is transferred to the broker if + // a borrower is not the broker + if (borrower != broker) + return brokerBalanceBefore.number() + serviceFee; + // Since a borrower is the broker, the payment is + // transferred to the Vault from the broker but not + // the service fee. + // If the asset is XRP then the broker pays the txfee. + if (asset.native()) + return brokerBalanceBefore.number() - payment - xrpFee.number(); + return brokerBalanceBefore.number() - payment; + }(); + BEAST_EXPECT(env.balance(broker, asset).value() == asset(expected).value()); + } + } + }; + // Test when a borrower is the broker and is not to verify correct + // service fee transfer in both cases. + for (auto const& borrowerAcct : {broker, borrower_}) + { + testLoanAsset([&](Env&) -> STAmount { return STAmount{XRPAmount{200'000}}; }, borrowerAcct); + testLoanAsset( + [&](Env& env) -> STAmount { + auto const IOU = issuer["USD"]; + env(trust(broker, IOU(1'000'000'000))); + env(trust(depositor, IOU(1'000'000'000))); + env(pay(issuer, broker, IOU(100'000'000))); + env(pay(issuer, depositor, IOU(100'000'000))); + env.close(); + return IOU(200'000); + }, + borrowerAcct); + testLoanAsset( + [&](Env& env) -> STAmount { + MPTTester mpt({.env = env, .issuer = issuer, .holders = {broker, depositor}, .pay = 100'000'000}); + return mpt(200'000); + }, + borrowerAcct); + } + } + + void + testIssuerIsBorrower() + { + testcase("RIPD-4096 - Issuer as borrower"); + + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + + BrokerParameters const brokerParams{ + .vaultDeposit = 100'000, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = TenthBips16{0}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{.account = lender, .counter = issuer, .principalRequest = Number{10000}}; + + auto const assetType = AssetType::IOU; + + Env env(*this, all); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, issuer); + + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + auto pseudoAcct = std::get(*loanResult); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet); + + makeLoanPayments( + env, + broker, + loanParams, + loanKeylet, + verifyLoanStatus, + issuer, + lender, + issuer, + PaymentParameters{.showStepBalances = true}); + } + + void + testLimitExceeded() + { + testcase("RIPD-4125 - overpayment"); + + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + BrokerParameters const brokerParams{ + .vaultDeposit = 100'000, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = TenthBips16{0}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = Number{200000, -6}, + .interest = TenthBips32{50000}, + .payTotal = 3, + .payInterval = 200, + .gracePd = 60, + .flags = tfLoanOverpayment, + }; + + auto const assetType = AssetType::XRP; + + Env env(*this, makeConfig(), all, nullptr, beast::severities::Severity::kWarning); + + auto loanResult = createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower); + + if (!BEAST_EXPECT(loanResult)) + return; + + auto broker = std::get(*loanResult); + auto loanKeylet = std::get(*loanResult); + auto pseudoAcct = std::get(*loanResult); + + VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet); + + auto const state = getCurrentState(env, broker, loanKeylet); + + env(loan::pay( + borrower, loanKeylet.key, STAmount{broker.asset, state.periodicPayment * 3 / 2 + 1}, tfLoanOverpayment)); + env.close(); + + PaymentParameters paymentParams{ + .showStepBalances = false, + .validateBalances = true, + }; + + makeLoanPayments( + env, broker, loanParams, loanKeylet, verifyLoanStatus, issuer, lender, borrower, paymentParams); + } + + void + testOverpaymentManagementFee() + { + testcase("testOverpaymentManagementFee"); + + using namespace jtx; + using namespace loan; + + Env env(*this, all); + + Account const lender{"lender"}, borrower{"borrower"}; + + env.fund(XRP(10'000'000), lender, borrower); + env.close(); + + PrettyAsset const asset{xrpIssue(), 1000}; + + auto const result = createVaultAndBroker( + env, + asset, + lender, + { + .vaultDeposit = asset(100'000).value(), + .managementFeeRate = TenthBips16(10'000), + }); + + auto const loanSetFee = fee(env.current()->fees().base * 2); + + auto const loanKeylet = + keylet::loan(result.brokerKeylet().key, (env.le(result.brokerKeylet()))->at(sfLoanSequence)); + env(loan::set(borrower, result.brokerKeylet().key, asset(10'000).value(), tfLoanOverpayment), + sig(sfCounterpartySignature, lender), + loan::paymentInterval(86400 * 30), + loan::paymentTotal(3), + loan::overpaymentInterestRate(TenthBips32(percentageToTenthBips(20))), + loanSetFee); + + // From calculator + auto const expectedOverpaymentManagementFee = Number{33333, 0}; + auto const loanBrokerBalanceBefore = env.balance(lender); + + auto const loanPayFee = fee(env.current()->fees().base * 2); + env(pay(borrower, loanKeylet.key, asset(5'000).value(), tfLoanOverpayment), loanPayFee); + env.close(); + + BEAST_EXPECTS( + env.balance(lender) - loanBrokerBalanceBefore == expectedOverpaymentManagementFee, + "overpayment management fee missmatch; expected:" + to_string(expectedOverpaymentManagementFee) + + " got: " + to_string(env.balance(lender) - loanBrokerBalanceBefore)); + } + + void + testLoanPayBrokerOwnerMissingTrustline() + { + testcase << "LoanPay Broker Owner Missing Trustline (PoC)"; + using namespace jtx; + using namespace loan; + Account const issuer("issuer"); + Account const borrower("borrower"); + Account const broker("broker"); + auto const IOU = issuer["IOU"]; + Env env(*this, all); + env.fund(XRP(20'000), issuer, broker, borrower); + env.close(); + // Set up trustlines and fund accounts + env(trust(broker, IOU(20'000'000))); + env(trust(borrower, IOU(20'000'000))); + env(pay(issuer, broker, IOU(10'000'000))); + env(pay(issuer, borrower, IOU(1'000))); + env.close(); + // Create vault and broker + auto const brokerInfo = createVaultAndBroker(env, IOU, broker); + // Create a loan first (this creates debt) + auto const keylet = keylet::loan(brokerInfo.brokerID, 1); + env(set(borrower, brokerInfo.brokerID, 10'000), + sig(sfCounterpartySignature, broker), + loanServiceFee(IOU(100).value()), + paymentInterval(100), + fee(XRP(100))); + env.close(); + // Ensure broker has sufficient cover so brokerPayee == brokerOwner + // We need coverAvailable >= (debtTotal * coverRateMinimum) + // Deposit enough cover to ensure the fee goes to broker owner + // The default coverRateMinimum is 10%, so for a 10,000 loan we need + // at least 1,000 cover. Default cover is 1,000, so we add more to be + // safe. + auto const additionalCover = IOU(50'000).value(); + env(loanBroker::coverDeposit(broker, brokerInfo.brokerID, STAmount{IOU, additionalCover})); + env.close(); + // Verify broker owner has a trustline + auto const brokerTrustline = keylet::line(broker, IOU); + BEAST_EXPECT(env.le(brokerTrustline) != nullptr); + // Broker owner deletes their trustline + // First, pay any positive balance to issuer to zero it out + auto const brokerBalance = env.balance(broker, IOU); + env(pay(broker, issuer, brokerBalance)); + env.close(); + // Remove the trustline by setting limit to 0 + env(trust(broker, IOU(0))); + env.close(); + // Verify trustline is deleted + BEAST_EXPECT(env.le(brokerTrustline) == nullptr); + // Now borrower tries to make a payment + // We should get a tesSUCCESS instead of a tecNO_LINE. + env(pay(borrower, keylet.key, IOU(10'100)), fee(XRP(100)), ter(tesSUCCESS)); + env.close(); + // Verify trustline is still deleted + BEAST_EXPECT(env.le(brokerTrustline) == nullptr); + // Verify the service fee went to the broker pseudo-account + if (auto const brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + Account const pseudo("pseudo-account", brokerSle->at(sfAccount)); + auto const balance = env.balance(pseudo, IOU); + // 1,000 default + 50,000 extra + 100 service fee from LoanPay + BEAST_EXPECTS(balance == IOU(51'100), to_string(Json::Value(balance))); + } + } + + void + testLoanPayBrokerOwnerUnauthorizedMPT() + { + testcase << "LoanPay Broker Owner MPT unauthorized"; + using namespace jtx; + using namespace loan; + + Account const issuer("issuer"); + Account const borrower("borrower"); + Account const broker("broker"); + + Env env(*this, all); + env.fund(XRP(20'000), issuer, broker, borrower); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + + PrettyAsset const MPT{mptt.issuanceID()}; + + // Authorize broker and borrower + mptt.authorize({.account = broker}); + mptt.authorize({.account = borrower}); + + env.close(); + + // Fund accounts + env(pay(issuer, broker, MPT(10'000'000))); + env(pay(issuer, borrower, MPT(1'000))); + env.close(); + + // Create vault and broker + auto const brokerInfo = createVaultAndBroker(env, MPT, broker); + // Create a loan first (this creates debt) + auto const keylet = keylet::loan(brokerInfo.brokerID, 1); + env(set(borrower, brokerInfo.brokerID, 10'000), + sig(sfCounterpartySignature, broker), + loanServiceFee(MPT(100).value()), + paymentInterval(100), + fee(XRP(100))); + env.close(); + // Ensure broker has sufficient cover so brokerPayee == brokerOwner + // We need coverAvailable >= (debtTotal * coverRateMinimum) + // Deposit enough cover to ensure the fee goes to broker owner + // The default coverRateMinimum is 10%, so for a 10,000 loan we need + // at least 1,000 cover. Default cover is 1,000, so we add more to be + // safe. + auto const additionalCover = MPT(50'000).value(); + env(loanBroker::coverDeposit(broker, brokerInfo.brokerID, STAmount{MPT, additionalCover})); + env.close(); + // Verify broker owner is authorized + auto const brokerMpt = keylet::mptoken(mptt.issuanceID(), broker); + BEAST_EXPECT(env.le(brokerMpt) != nullptr); + // Broker owner unauthorizes. + // First, pay any positive balance to issuer to zero it out + auto const brokerBalance = env.balance(broker, MPT); + env(pay(broker, issuer, brokerBalance)); + env.close(); + // Then, unauthorize the MPT. + mptt.authorize({.account = broker, .flags = tfMPTUnauthorize}); + env.close(); + // Verify the MPT is unauthorized. + BEAST_EXPECT(env.le(brokerMpt) == nullptr); + // Now borrower tries to make a payment + // We should get a tesSUCCESS instead of a tecNO_AUTH. + auto const borrowerBalance = env.balance(borrower, MPT); + env(pay(borrower, keylet.key, MPT(10'100)), fee(XRP(100)), ter(tesSUCCESS)); + env.close(); + // Verify the MPT is still unauthorized. + BEAST_EXPECT(env.le(brokerMpt) == nullptr); + // Verify the service fee went to the broker pseudo-account + if (auto const brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + Account const pseudo("pseudo-account", brokerSle->at(sfAccount)); + auto const balance = env.balance(pseudo, MPT); + // 1,000 default + 50,000 extra + 100 service fee from LoanPay + BEAST_EXPECTS(balance == MPT(51'100), to_string(Json::Value(balance))); + } + } + + void + testLoanPayBrokerOwnerNoPermissionedDomainMPT() + { + testcase << "LoanPay Broker Owner without permissioned domain of the MPT"; + using namespace jtx; + using namespace loan; + + Account const issuer("issuer"); + Account const borrower("borrower"); + Account const broker("broker"); + + Env env(*this, all); + env.fund(XRP(20'000), issuer, broker, borrower); + env.close(); + + auto credType = "credential1"; + + pdomain::Credentials const credentials1{{issuer, credType}}; + env(pdomain::setTx(issuer, credentials1)); + env.close(); + + auto domainID = pdomain::getNewDomain(env.meta()); + + env(credentials::create(broker, issuer, credType)); + env(credentials::accept(broker, issuer, credType)); + env.close(); + + env(credentials::create(borrower, issuer, credType)); + env(credentials::accept(borrower, issuer, credType)); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({ + .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer | tfMPTCanLock, + .domainID = domainID, + }); + + PrettyAsset const MPT{mptt.issuanceID()}; + + // Authorize broker and borrower + mptt.authorize({.account = broker}); + mptt.authorize({.account = borrower}); + + env.close(); + + // Fund accounts + env(pay(issuer, broker, MPT(10'000'000))); + env(pay(issuer, borrower, MPT(1'000))); + env.close(); + + // Create vault and broker + auto const brokerInfo = createVaultAndBroker(env, MPT, broker); + // Create a loan first (this creates debt) + auto const keylet = keylet::loan(brokerInfo.brokerID, 1); + env(set(borrower, brokerInfo.brokerID, 10'000), + sig(sfCounterpartySignature, broker), + loanServiceFee(MPT(100).value()), + paymentInterval(100), + fee(XRP(100))); + env.close(); + // Ensure broker has sufficient cover so brokerPayee == brokerOwner + // We need coverAvailable >= (debtTotal * coverRateMinimum) + // Deposit enough cover to ensure the fee goes to broker owner + // The default coverRateMinimum is 10%, so for a 10,000 loan we need + // at least 1,000 cover. Default cover is 1,000, so we add more to be + // safe. + auto const additionalCover = MPT(50'000).value(); + env(loanBroker::coverDeposit(broker, brokerInfo.brokerID, STAmount{MPT, additionalCover})); + env.close(); + // Verify broker owner is authorized + auto const brokerMpt = keylet::mptoken(mptt.issuanceID(), broker); + BEAST_EXPECT(env.le(brokerMpt) != nullptr); + // Remove the credentials for the Broker owner. + // First, pay any positive balance to issuer to zero it out + auto const brokerBalance = env.balance(broker, MPT); + env(pay(broker, issuer, brokerBalance)); + env.close(); + + env(credentials::deleteCred(broker, broker, issuer, credType)); + env.close(); + + // Make sure the broker is not authorized to hold the MPT after we + // deleted the credentials + env(pay(issuer, broker, MPT(1'000)), ter(tecNO_AUTH)); + + // Now borrower tries to make a payment + // We should get a tesSUCCESS instead of a tecNO_AUTH. + auto const borrowerBalance = env.balance(borrower, MPT); + env(pay(borrower, keylet.key, MPT(10'100)), fee(XRP(100)), ter(tesSUCCESS)); + env.close(); + // Verify broker is still not authorized + env(pay(issuer, broker, MPT(1'000)), ter(tecNO_AUTH)); + // Verify the service fee went to the broker pseudo-account + if (auto const brokerSle = env.le(keylet::loanbroker(brokerInfo.brokerID)); BEAST_EXPECT(brokerSle)) + { + Account const pseudo("pseudo-account", brokerSle->at(sfAccount)); + auto const balance = env.balance(pseudo, MPT); + // 1,000 default + 50,000 extra + 100 service fee from LoanPay + BEAST_EXPECTS(balance == MPT(51'100), to_string(Json::Value(balance))); + } + } + + void + testLoanSetBrokerOwnerNoPermissionedDomainMPT() + { + testcase << "LoanSet Broker Owner without permissioned domain of the MPT"; + using namespace jtx; + using namespace loan; + + Account const issuer("issuer"); + Account const borrower("borrower"); + Account const broker("broker"); + + Env env(*this, all); + env.fund(XRP(20'000), issuer, broker, borrower); + env.close(); + + auto credType = "credential1"; + + pdomain::Credentials const credentials1{{issuer, credType}}; + env(pdomain::setTx(issuer, credentials1)); + env.close(); + + auto domainID = pdomain::getNewDomain(env.meta()); + + // Add credentials for the broker and borrower + env(credentials::create(broker, issuer, credType)); + env(credentials::accept(broker, issuer, credType)); + env.close(); + + env(credentials::create(borrower, issuer, credType)); + env(credentials::accept(borrower, issuer, credType)); + env.close(); + + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({ + .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer | tfMPTCanLock, + .domainID = domainID, + }); + + PrettyAsset const MPT{mptt.issuanceID()}; + + // Authorize broker and borrower + mptt.authorize({.account = broker}); + mptt.authorize({.account = borrower}); + env.close(); + + // Fund accounts + env(pay(issuer, broker, MPT(10'000'000))); + env(pay(issuer, borrower, MPT(1'000))); + env.close(); + + // Create vault and broker + auto const brokerInfo = createVaultAndBroker(env, MPT, broker); + + // Remove the credentials for the Broker owner. + // Clear the balance first. + auto const brokerBalance = env.balance(broker, MPT); + env(pay(broker, issuer, brokerBalance)); + env.close(); + // Delete the credentials + env(credentials::deleteCred(broker, broker, issuer, credType)); + env.close(); + + // Create a loan, this should fail for tecNO_AUTH + env(set(borrower, brokerInfo.brokerID, 10'000), + sig(sfCounterpartySignature, broker), + loanServiceFee(MPT(100).value()), + paymentInterval(100), + fee(XRP(100)), + ter(tecNO_AUTH)); + env.close(); + } + + void + testSequentialFLCDepletion() + { + testcase << "First-Loss Capital Depletion on Sequential Defaults"; + + using namespace jtx; + using namespace loan; + using namespace loanBroker; + + Env env(*this, all); + + Account const issuer{"issuer"}; + Account const lender{"lender"}; + Account const borrowerA{"borrowerA"}; + Account const borrowerB{"borrowerB"}; + + env.fund(XRP(1'000'000), issuer, lender, borrowerA, borrowerB); + env.close(); + + PrettyAsset const asset = xrpIssue(); + auto const vaultDepositAmount = asset(200'000); // Enough for 2 x 50k loans plus interest/fees + + auto const brokerInfo = createVaultAndBroker( + env, + asset, + lender, + { + .vaultDeposit = vaultDepositAmount.value(), + .debtMax = 0, + .coverRateMin = TenthBips32(20000), // 20% + .coverDeposit = 21'000, + .managementFeeRate = TenthBips16(100), // 0.1% + .coverRateLiquidation = TenthBips32(100000), + }); + auto const brokerKeylet = brokerInfo.brokerKeylet(); + + // Create two identical loans: each 50,000 XRP principal (scaled down to + // avoid funding issues) Total DebtTotal will be ~100,000 XRP (principal + // + interest) Formula will calculate cover as: 100% × (20% × 100,000) = + // 20,000 XRP So we need FLC = 20,000 XRP to be fully consumed by first + // default + auto const principalAmount = Number(50'000); + auto const loanPaymentInterval = 2592000; // 30 days + auto const loanGracePeriod = 604800; // 7 days + + // Create Loan A + auto loanATx = env.jt( + set(borrowerA, brokerKeylet.key, principalAmount), + sig(sfCounterpartySignature, lender), + interestRate(TenthBips32(500)), // 5% + paymentTotal(12), + loan::paymentInterval(loanPaymentInterval), + loan::gracePeriod(loanGracePeriod), + fee(XRP(10))); // Sufficient fee for multi-sig transaction + env(loanATx); + env.close(); + + auto const loanAKeylet = keylet::loan(brokerKeylet.key, 1); + + // Create Loan B + auto loanBTx = env.jt( + set(borrowerB, brokerKeylet.key, principalAmount), + sig(sfCounterpartySignature, lender), + interestRate(TenthBips32(500)), // 5% + paymentTotal(12), + loan::paymentInterval(loanPaymentInterval), + loan::gracePeriod(loanGracePeriod), + fee(XRP(10))); // Sufficient fee for multi-sig transaction + env(loanBTx); + env.close(); + + auto const loanBKeylet = keylet::loan(brokerKeylet.key, 2); + + auto loanASle = env.le(loanAKeylet); + if (!BEAST_EXPECT(loanASle)) + return; + + // Advance time past grace period for both loans to be defaultable + auto const loanANextDue = loanASle->at(sfNextPaymentDueDate); + auto const loanAGrace = loanASle->at(sfGracePeriod); + env.close(std::chrono::seconds{loanANextDue + loanAGrace + 60}); + + env(manage(lender, loanAKeylet.key, tfLoanDefault), ter(tesSUCCESS)); + env.close(); + + // Verify Loan A is defaulted + loanASle = env.le(loanAKeylet); + if (!BEAST_EXPECT(loanASle)) + return; + BEAST_EXPECT(loanASle->isFlag(lsfLoanDefault)); + BEAST_EXPECT(loanASle->at(sfPaymentRemaining) == 0); + + // Check broker state after first default (from committed ledger) + auto brokerSle = env.le(brokerKeylet); + if (!BEAST_EXPECT(brokerSle)) + return; + auto const afterFirstDebtTotal = brokerSle->at(sfDebtTotal); + auto const afterFirstCoverAvailable = brokerSle->at(sfCoverAvailable); + + // DebtTotal should have decreased by Loan A's debt + BEAST_EXPECT(afterFirstDebtTotal == 50'134); + + // CoverAvailable should have decreased significantly + BEAST_EXPECT(afterFirstCoverAvailable == 946); + + env(manage(lender, loanBKeylet.key, tfLoanDefault), ter(tesSUCCESS)); + + brokerSle = env.le(brokerKeylet); + if (!BEAST_EXPECT(brokerSle)) + return; + auto const afterSecondDebtTotal = brokerSle->at(sfDebtTotal); + auto const afterSecondCoverAvailable = brokerSle->at(sfCoverAvailable); + + BEAST_EXPECT(afterSecondDebtTotal == 0); + + BEAST_EXPECT(afterSecondCoverAvailable == 0); + } + +public: + void + run() override + { +#if LOANTODO + testLoanPayLateFullPaymentBypassesPenalties(); + testLoanCoverMinimumRoundingExploit(); +#endif + testInvalidLoanSet(); + + testCoverDepositWithdrawNonTransferableMPT(); + testPoC_UnsignedUnderflowOnFullPayAfterEarlyPeriodic(); + + testDisabled(); + testSelfLoan(); + testIssuerLoan(); + testLoanSet(); + testLifecycle(); + testServiceFeeOnBrokerDeepFreeze(); + + testRPC(); + testInvalidLoanDelete(); + testInvalidLoanManage(); + testInvalidLoanPay(); + + testBatchBypassCounterparty(); + testLoanPayComputePeriodicPaymentValidRateInvariant(); + testAccountSendMptMinAmountInvariant(); + testLoanPayDebtDecreaseInvariant(); + testWrongMaxDebtBehavior(); + testLoanPayComputePeriodicPaymentValidTotalInterestInvariant(); + testDosLoanPay(); + testLoanPayComputePeriodicPaymentValidTotalPrincipalPaidInvariant(); + testLoanPayComputePeriodicPaymentValidTotalInterestPaidInvariant(); + testLoanNextPaymentDueDateOverflow(); + + testRequireAuth(); + testDustManipulation(); + + testRIPD3831(); + testRIPD3459(); + testRIPD3901(); + testRIPD3902(); + testRoundingAllowsUndercoverage(); + testBorrowerIsBroker(); + testIssuerIsBorrower(); + testLimitExceeded(); + testOverpaymentManagementFee(); + testLoanPayBrokerOwnerMissingTrustline(); + testLoanPayBrokerOwnerUnauthorizedMPT(); + testLoanPayBrokerOwnerNoPermissionedDomainMPT(); + testLoanSetBrokerOwnerNoPermissionedDomainMPT(); + testSequentialFLCDepletion(); + } +}; + +class LoanBatch_test : public Loan_test +{ +protected: + beast::xor_shift_engine engine_; + + std::uniform_int_distribution<> assetDist{0, 2}; + std::uniform_int_distribution principalDist{100'000, 1'000'000'000}; + std::uniform_int_distribution interestRateDist{0, 10000}; + std::uniform_int_distribution<> paymentTotalDist{12, 10000}; + std::uniform_int_distribution<> paymentIntervalDist{60, 3600 * 24 * 30}; + std::uniform_int_distribution managementFeeRateDist{0, 10'000}; + std::uniform_int_distribution<> serviceFeeDist{0, 20}; + /* + # Generate parameters that are more likely to be valid + principal = Decimal(str(rand.randint(100000, + 100'000'000))).quantize(ROUND_TARGET) + + interest_rate = Decimal(rand.randint(1, 10000)) / + Decimal(100000) + + payment_total = rand.randint(12, 10000) + + payment_interval = Decimal(str(rand.randint(60, 2629746))) + + interest_fee = Decimal(rand.randint(0, 100000)) / + Decimal(100000) +*/ + + void + testRandomLoan() + { + using namespace jtx; + + Account const issuer("issuer"); + Account const lender("lender"); + Account const borrower("borrower"); + + // Determine all the random parameters at once + AssetType assetType = static_cast(assetDist(engine_)); + auto const principalRequest = principalDist(engine_); + TenthBips16 managementFeeRate{managementFeeRateDist(engine_)}; + auto const serviceFee = serviceFeeDist(engine_); + TenthBips32 interest{interestRateDist(engine_)}; + auto const payTotal = paymentTotalDist(engine_); + auto const payInterval = paymentIntervalDist(engine_); + + BrokerParameters brokerParams{ + .vaultDeposit = principalRequest * 10, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = managementFeeRate}; + LoanParameters loanParams{ + .account = lender, + .counter = borrower, + .principalRequest = principalRequest, + .serviceFee = serviceFee, + .interest = interest, + .payTotal = payTotal, + .payInterval = payInterval, + }; + + runLoan(assetType, brokerParams, loanParams); + } + +public: + void + run() override + { + auto const argument = arg(); + auto const numIterations = [s = arg()]() -> int { + int defaultNum = 5; + if (s.empty()) + return defaultNum; + try + { + std::size_t pos; + auto const r = stoi(s, &pos); + if (pos != s.size()) + return defaultNum; + return r; + } + catch (...) + { + return defaultNum; + } + }(); + + using namespace jtx; + + auto const updateInterval = std::min(numIterations / 5, 100); + + for (int i = 0; i < numIterations; ++i) + { + if (i % updateInterval == 0) + testcase << "Random Loan Test iteration " << (i + 1) << "/" << numIterations; + testRandomLoan(); + } + } +}; + +class LoanArbitrary_test : public LoanBatch_test +{ + void + run() override + { + using namespace jtx; + + BrokerParameters const brokerParams{ + .vaultDeposit = 10000, + .debtMax = 0, + .coverRateMin = TenthBips32{0}, + .managementFeeRate = TenthBips16{0}, + .coverRateLiquidation = TenthBips32{0}}; + LoanParameters const loanParams{ + .account = Account("lender"), + .counter = Account("borrower"), + .principalRequest = Number{200000, -6}, + .interest = TenthBips32{50000}, + .payTotal = 2, + .payInterval = 200}; + + runLoan(AssetType::XRP, brokerParams, loanParams); + } +}; + +BEAST_DEFINE_TESTSUITE(Loan, tx, xrpl); +BEAST_DEFINE_TESTSUITE_MANUAL(LoanBatch, tx, xrpl); +BEAST_DEFINE_TESTSUITE_MANUAL(LoanArbitrary, tx, xrpl); + +} // namespace test +} // namespace xrpl diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index f776695337..b9e3b8e988 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class MPToken_test : public beast::unit_test::suite @@ -61,11 +42,7 @@ class MPToken_test : public beast::unit_test::suite // tries to set a txfee while not enabling in the flag mptAlice.create( - {.maxAmt = 100, - .assetScale = 0, - .transferFee = 1, - .metadata = "test", - .err = temMALFORMED}); + {.maxAmt = 100, .assetScale = 0, .transferFee = 1, .metadata = "test", .err = temMALFORMED}); if (!features[featureSingleAssetVault]) { @@ -93,11 +70,7 @@ class MPToken_test : public beast::unit_test::suite { // tries to set DomainID when RequireAuth is not set mptAlice.create( - {.maxAmt = 100, - .assetScale = 0, - .metadata = "test", - .domainID = uint256(42), - .err = temMALFORMED}); + {.maxAmt = 100, .assetScale = 0, .metadata = "test", .domainID = uint256(42), .err = temMALFORMED}); // tries to set zero DomainID mptAlice.create( @@ -127,20 +100,10 @@ class MPToken_test : public beast::unit_test::suite .err = temMALFORMED}); // empty metadata returns error - mptAlice.create( - {.maxAmt = 100, - .assetScale = 0, - .transferFee = 0, - .metadata = "", - .err = temMALFORMED}); + mptAlice.create({.maxAmt = 100, .assetScale = 0, .transferFee = 0, .metadata = "", .err = temMALFORMED}); - // MaximumAmout of 0 returns error - mptAlice.create( - {.maxAmt = 0, - .assetScale = 1, - .transferFee = 1, - .metadata = "test", - .err = temMALFORMED}); + // MaximumAmount of 0 returns error + mptAlice.create({.maxAmt = 0, .assetScale = 1, .transferFee = 1, .metadata = "test", .err = temMALFORMED}); // MaximumAmount larger than 63 bit returns error mptAlice.create( @@ -177,16 +140,14 @@ class MPToken_test : public beast::unit_test::suite .transferFee = 10, .metadata = "123", .ownerCount = 1, - .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | - tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback}); + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | + tfMPTCanClawback}); // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; Json::Value const result = env.rpc("tx", txHash)[jss::result]; - BEAST_EXPECT( - result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); + BEAST_EXPECT(result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); } if (features[featureSingleAssetVault]) @@ -195,8 +156,7 @@ class MPToken_test : public beast::unit_test::suite Account const credIssuer1{"credIssuer1"}; std::string const credType = "credential"; - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; { Env env{*this, features}; @@ -215,19 +175,16 @@ class MPToken_test : public beast::unit_test::suite .transferFee = 10, .metadata = "123", .ownerCount = 1, - .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | - tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback, + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | + tfMPTCanClawback, .domainID = domainId1, }); // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; Json::Value const result = env.rpc("tx", txHash)[jss::result]; - BEAST_EXPECT( - result[sfMaximumAmount.getJsonName()] == - "9223372036854775807"); + BEAST_EXPECT(result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); } } } @@ -249,8 +206,7 @@ class MPToken_test : public beast::unit_test::suite env.enableFeature(featureMPTokensV1); - mptAlice.destroy( - {.id = id, .flags = 0x00000001, .err = temINVALID_FLAG}); + mptAlice.destroy({.id = id, .flags = 0x00000001, .err = temINVALID_FLAG}); } // MPTokenIssuanceDestroy (preclaim) @@ -258,10 +214,7 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.destroy( - {.id = makeMptID(env.seq(alice), alice), - .ownerCount = 0, - .err = tecOBJECT_NOT_FOUND}); + mptAlice.destroy({.id = makeMptID(env.seq(alice), alice), .ownerCount = 0, .err = tecOBJECT_NOT_FOUND}); mptAlice.create({.ownerCount = 1}); @@ -314,10 +267,7 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features - featureMPTokensV1}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.authorize( - {.account = bob, - .id = makeMptID(env.seq(alice), alice), - .err = temDISABLED}); + mptAlice.authorize({.account = bob, .id = makeMptID(env.seq(alice), alice), .err = temDISABLED}); } // Validate fields in MPTokenAuthorize (preflight) @@ -329,11 +279,9 @@ class MPToken_test : public beast::unit_test::suite // The only valid MPTokenAuthorize flag is tfMPTUnauthorize, which // has a value of 1 - mptAlice.authorize( - {.account = bob, .flags = 0x00000002, .err = temINVALID_FLAG}); + mptAlice.authorize({.account = bob, .flags = 0x00000002, .err = temINVALID_FLAG}); - mptAlice.authorize( - {.account = bob, .holder = bob, .err = temMALFORMED}); + mptAlice.authorize({.account = bob, .holder = bob, .err = temMALFORMED}); mptAlice.authorize({.holder = alice, .err = temMALFORMED}); } @@ -345,11 +293,9 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); auto const id = makeMptID(env.seq(alice), alice); - mptAlice.authorize( - {.holder = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); + mptAlice.authorize({.holder = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); - mptAlice.authorize( - {.account = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); + mptAlice.authorize({.account = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); } // Test bad scenarios without allowlisting in MPTokenAuthorize @@ -361,8 +307,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create({.ownerCount = 1}); // bob submits a tx with a holder field - mptAlice.authorize( - {.account = bob, .holder = alice, .err = tecNO_PERMISSION}); + mptAlice.authorize({.account = bob, .holder = alice, .err = tecNO_PERMISSION}); // alice tries to hold onto her own token mptAlice.authorize({.account = alice, .err = tecNO_PERMISSION}); @@ -384,10 +329,7 @@ class MPToken_test : public beast::unit_test::suite // bob tries to delete his MPToken, but fails since he still // holds tokens - mptAlice.authorize( - {.account = bob, - .flags = tfMPTUnauthorize, - .err = tecHAS_OBLIGATIONS}); + mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize, .err = tecHAS_OBLIGATIONS}); // bob pays back alice 100 tokens mptAlice.pay(bob, alice, 100); @@ -399,10 +341,7 @@ class MPToken_test : public beast::unit_test::suite // bob receives error when he tries to delete his MPToken that has // already been deleted mptAlice.authorize( - {.account = bob, - .holderCount = 0, - .flags = tfMPTUnauthorize, - .err = tecOBJECT_NOT_FOUND}); + {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize, .err = tecOBJECT_NOT_FOUND}); } // Test bad scenarios with allow-listing in MPTokenAuthorize (preclaim) @@ -419,7 +358,7 @@ class MPToken_test : public beast::unit_test::suite // a mptoken yet mptAlice.authorize({.holder = bob, .err = tecOBJECT_NOT_FOUND}); - // alice specifys a holder acct that doesn't exist + // alice specifies a holder acct that doesn't exist mptAlice.authorize({.holder = cindy, .err = tecNO_DST}); // bob now holds a mptoken object @@ -440,8 +379,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.authorize({.holder = bob}); // bob deletes his mptoken - mptAlice.authorize( - {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); } // Test mptoken reserve requirement - first two mpts free (doApply) @@ -452,11 +390,7 @@ class MPToken_test : public beast::unit_test::suite // 1 drop BEAST_EXPECT(incReserve > XRPAmount(1)); - MPTTester mptAlice1( - env, - alice, - {.holders = {bob}, - .xrpHolders = acctReserve + (incReserve - 1)}); + MPTTester mptAlice1(env, alice, {.holders = {bob}, .xrpHolders = acctReserve + (incReserve - 1)}); mptAlice1.create(); MPTTester mptAlice2(env, alice, {.fund = false}); @@ -471,11 +405,9 @@ class MPToken_test : public beast::unit_test::suite // second mpt free mptAlice2.authorize({.account = bob, .holderCount = 2}); - mptAlice3.authorize( - {.account = bob, .err = tecINSUFFICIENT_RESERVE}); + mptAlice3.authorize({.account = bob, .err = tecINSUFFICIENT_RESERVE}); - env(pay( - env.master, bob, drops(incReserve + incReserve + incReserve))); + env(pay(env.master, bob, drops(incReserve + incReserve + incReserve))); env.close(); mptAlice3.authorize({.account = bob, .holderCount = 3}); @@ -502,12 +434,10 @@ class MPToken_test : public beast::unit_test::suite // bob creates a mptoken mptAlice.authorize({.account = bob, .holderCount = 1}); - mptAlice.authorize( - {.account = bob, .holderCount = 1, .err = tecDUPLICATE}); + mptAlice.authorize({.account = bob, .holderCount = 1, .err = tecDUPLICATE}); // bob deletes his mptoken - mptAlice.authorize( - {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); } // With allowlisting @@ -526,14 +456,9 @@ class MPToken_test : public beast::unit_test::suite mptAlice.authorize({.account = alice, .holder = bob}); // Unauthorize bob's mptoken - mptAlice.authorize( - {.account = alice, - .holder = bob, - .holderCount = 1, - .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .holderCount = 1, .flags = tfMPTUnauthorize}); - mptAlice.authorize( - {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); } // Holder can have dangling MPToken even if issuance has been destroyed. @@ -552,8 +477,7 @@ class MPToken_test : public beast::unit_test::suite // bob can delete his mptoken even though issuance is no longer // existent - mptAlice.authorize( - {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); } } @@ -571,10 +495,7 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features - featureMPTokensV1}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.set( - {.account = bob, - .id = makeMptID(env.seq(alice), alice), - .err = temDISABLED}); + mptAlice.set({.account = bob, .id = makeMptID(env.seq(alice), alice), .err = temDISABLED}); env.enableFeature(featureMPTokensV1); @@ -584,79 +505,44 @@ class MPToken_test : public beast::unit_test::suite // test invalid flag - only valid flags are tfMPTLock (1) and Unlock // (2) - mptAlice.set( - {.account = alice, - .flags = 0x00000008, - .err = temINVALID_FLAG}); + mptAlice.set({.account = alice, .flags = 0x00000008, .err = temINVALID_FLAG}); - if (!features[featureSingleAssetVault] && - !features[featureDynamicMPT]) + if (!features[featureSingleAssetVault] && !features[featureDynamicMPT] && + !features[featureConfidentialTransfer]) { // test invalid flags - nothing is being changed - mptAlice.set( - {.account = alice, - .flags = 0x00000000, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .flags = 0x00000000, .err = tecNO_PERMISSION}); - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = 0x00000000, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .holder = bob, .flags = 0x00000000, .err = tecNO_PERMISSION}); // cannot set DomainID since SAV is not enabled - mptAlice.set( - {.account = alice, - .domainID = uint256(42), - .err = temDISABLED}); + mptAlice.set({.account = alice, .domainID = uint256(42), .err = temDISABLED}); } else { // test invalid flags - nothing is being changed - mptAlice.set( - {.account = alice, - .flags = 0x00000000, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .flags = 0x00000000, .err = temMALFORMED}); - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = 0x00000000, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = bob, .flags = 0x00000000, .err = temMALFORMED}); - if (!features[featurePermissionedDomains] || - !features[featureSingleAssetVault]) + if (!features[featurePermissionedDomains] || !features[featureSingleAssetVault]) { // cannot set DomainID since PD is not enabled - mptAlice.set( - {.account = alice, - .domainID = uint256(42), - .err = temDISABLED}); + mptAlice.set({.account = alice, .domainID = uint256(42), .err = temDISABLED}); } else if (features[featureSingleAssetVault]) { // cannot set DomainID since Holder is set - mptAlice.set( - {.account = alice, - .holder = bob, - .domainID = uint256(42), - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = bob, .domainID = uint256(42), .err = temMALFORMED}); } } // set both lock and unlock flags at the same time will fail - mptAlice.set( - {.account = alice, - .flags = tfMPTLock | tfMPTUnlock, - .err = temINVALID_FLAG}); + mptAlice.set({.account = alice, .flags = tfMPTLock | tfMPTUnlock, .err = temINVALID_FLAG}); // if the holder is the same as the acct that submitted the tx, // tx fails - mptAlice.set( - {.account = alice, - .holder = alice, - .flags = tfMPTLock, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = alice, .flags = tfMPTLock, .err = temMALFORMED}); } // Validate fields in MPTokenIssuanceSet (preclaim) @@ -669,32 +555,18 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create({.ownerCount = 1}); // alice tries to lock a mptissuance that has disabled locking - mptAlice.set( - {.account = alice, - .flags = tfMPTLock, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .flags = tfMPTLock, .err = tecNO_PERMISSION}); // alice tries to unlock mptissuance that has disabled locking - mptAlice.set( - {.account = alice, - .flags = tfMPTUnlock, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .flags = tfMPTUnlock, .err = tecNO_PERMISSION}); // issuer tries to lock a bob's mptoken that has disabled // locking - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTLock, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION}); // issuer tries to unlock a bob's mptoken that has disabled // locking - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTUnlock, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock, .err = tecNO_PERMISSION}); } // Validate fields in MPTokenIssuanceSet (preclaim) @@ -705,38 +577,28 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // alice trying to set when the mptissuance doesn't exist yet - mptAlice.set( - {.id = makeMptID(env.seq(alice), alice), - .flags = tfMPTLock, - .err = tecOBJECT_NOT_FOUND}); + mptAlice.set({.id = makeMptID(env.seq(alice), alice), .flags = tfMPTLock, .err = tecOBJECT_NOT_FOUND}); // create a mptokenissuance with locking mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock}); // a non-issuer acct tries to set the mptissuance - mptAlice.set( - {.account = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION}); + mptAlice.set({.account = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION}); // trying to set a holder who doesn't have a mptoken - mptAlice.set( - {.holder = bob, - .flags = tfMPTLock, - .err = tecOBJECT_NOT_FOUND}); + mptAlice.set({.holder = bob, .flags = tfMPTLock, .err = tecOBJECT_NOT_FOUND}); // trying to set a holder who doesn't exist - mptAlice.set( - {.holder = cindy, .flags = tfMPTLock, .err = tecNO_DST}); + mptAlice.set({.holder = cindy, .flags = tfMPTLock, .err = tecNO_DST}); } - if (features[featureSingleAssetVault] && - features[featurePermissionedDomains]) + if (features[featureSingleAssetVault] && features[featurePermissionedDomains]) { // Add permissioned domain Account const credIssuer1{"credIssuer1"}; std::string const credType = "credential"; - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; { Env env{*this, features}; @@ -745,11 +607,9 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create({}); // Trying to set DomainID on a public MPTokenIssuance - mptAlice.set( - {.domainID = uint256(42), .err = tecNO_PERMISSION}); + mptAlice.set({.domainID = uint256(42), .err = tecNO_PERMISSION}); - mptAlice.set( - {.domainID = beast::zero, .err = tecNO_PERMISSION}); + mptAlice.set({.domainID = beast::zero, .err = tecNO_PERMISSION}); } { @@ -759,19 +619,12 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create({.flags = tfMPTRequireAuth}); // Trying to set non-existing DomainID - mptAlice.set( - {.domainID = uint256(42), .err = tecOBJECT_NOT_FOUND}); + mptAlice.set({.domainID = uint256(42), .err = tecOBJECT_NOT_FOUND}); // Trying to lock but locking is disabled - mptAlice.set( - {.flags = tfMPTUnlock, - .domainID = uint256(42), - .err = tecNO_PERMISSION}); + mptAlice.set({.flags = tfMPTUnlock, .domainID = uint256(42), .err = tecNO_PERMISSION}); - mptAlice.set( - {.flags = tfMPTUnlock, - .domainID = beast::zero, - .err = tecNO_PERMISSION}); + mptAlice.set({.flags = tfMPTUnlock, .domainID = beast::zero, .err = tecNO_PERMISSION}); } } } @@ -792,8 +645,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // create a mptokenissuance with locking - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); mptAlice.authorize({.account = bob, .holderCount = 1}); @@ -813,43 +665,33 @@ class MPToken_test : public beast::unit_test::suite mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); // alice unlocks bob's mptoken - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); // locks up bob's mptoken again mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); if (!features[featureSingleAssetVault]) { - // Delete bobs' mptoken even though it is locked + // Delete bob's mptoken even though it is locked mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize}); - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTUnlock, - .err = tecOBJECT_NOT_FOUND}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock, .err = tecOBJECT_NOT_FOUND}); return; } // Cannot delete locked MPToken - mptAlice.authorize( - {.account = bob, - .flags = tfMPTUnauthorize, - .err = tecNO_PERMISSION}); + mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize, .err = tecNO_PERMISSION}); // alice unlocks mptissuance mptAlice.set({.account = alice, .flags = tfMPTUnlock}); // alice unlocks bob's mptoken - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); // alice unlocks mptissuance and bob's mptoken again despite that // they are already unlocked. Make sure this will not change the // flags - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); mptAlice.set({.account = alice, .flags = tfMPTUnlock}); } @@ -865,8 +707,7 @@ class MPToken_test : public beast::unit_test::suite Account const credIssuer1{"credIssuer1"}; env.fund(XRP(1000), credIssuer1); - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; env(pdomain::setTx(credIssuer1, credentials1)); return [&]() { @@ -879,8 +720,7 @@ class MPToken_test : public beast::unit_test::suite Account const credIssuer2{"credIssuer2"}; env.fund(XRP(1000), credIssuer2); - pdomain::Credentials const credentials2{ - {.issuer = credIssuer2, .credType = credType}}; + pdomain::Credentials const credentials2{{.issuer = credIssuer2, .credType = credType}}; env(pdomain::setTx(credIssuer2, credentials2)); return [&]() { @@ -892,8 +732,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // create a mptokenissuance with auth. - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth}); BEAST_EXPECT(mptAlice.checkDomainID(std::nullopt)); // reset "domain not set" to "domain not set", i.e. no change @@ -970,9 +809,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.authorize({.account = bob}); for (auto flags : {tfNoRippleDirect, tfLimitQuality}) - env(pay(alice, bob, MPT(10)), - txflags(flags), - ter(temINVALID_FLAG)); + env(pay(alice, bob, MPT(10)), txflags(flags), ter(temINVALID_FLAG)); } // Invalid combination of send, sendMax, deliverMin, paths @@ -990,32 +827,17 @@ class MPToken_test : public beast::unit_test::suite // sendMax and DeliverMin are valid XRP amount, // but is invalid combination with MPT amount auto const MPT = mptAlice["MPT"]; - env(pay(alice, carol, MPT(100)), - sendmax(XRP(100)), - ter(temMALFORMED)); - env(pay(alice, carol, MPT(100)), - delivermin(XRP(100)), - ter(temBAD_AMOUNT)); + env(pay(alice, carol, MPT(100)), sendmax(XRP(100)), ter(temMALFORMED)); + env(pay(alice, carol, MPT(100)), deliver_min(XRP(100)), ter(temBAD_AMOUNT)); // sendMax MPT is invalid with IOU or XRP auto const USD = alice["USD"]; - env(pay(alice, carol, USD(100)), - sendmax(MPT(100)), - ter(temMALFORMED)); - env(pay(alice, carol, XRP(100)), - sendmax(MPT(100)), - ter(temMALFORMED)); - env(pay(alice, carol, USD(100)), - delivermin(MPT(100)), - ter(temBAD_AMOUNT)); - env(pay(alice, carol, XRP(100)), - delivermin(MPT(100)), - ter(temBAD_AMOUNT)); + env(pay(alice, carol, USD(100)), sendmax(MPT(100)), ter(temMALFORMED)); + env(pay(alice, carol, XRP(100)), sendmax(MPT(100)), ter(temMALFORMED)); + env(pay(alice, carol, USD(100)), deliver_min(MPT(100)), ter(temBAD_AMOUNT)); + env(pay(alice, carol, XRP(100)), deliver_min(MPT(100)), ter(temBAD_AMOUNT)); // sendmax and amount are different MPT issue - test::jtx::MPT const MPT1( - "MPT", makeMptID(env.seq(alice) + 10, alice)); - env(pay(alice, carol, MPT1(100)), - sendmax(MPT(100)), - ter(temMALFORMED)); + test::jtx::MPT const MPT1("MPT", makeMptID(env.seq(alice) + 10, alice)); + env(pay(alice, carol, MPT1(100)), sendmax(MPT(100)), ter(temMALFORMED)); // paths is invalid env(pay(alice, carol, MPT(100)), path(~USD), ter(temMALFORMED)); } @@ -1040,9 +862,7 @@ class MPToken_test : public beast::unit_test::suite payment[jss::build_path] = true; auto jrr = env.rpc("json", "submit", to_string(payment)); BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::result][jss::error_message] == - "Field 'build_path' not allowed in this context."); + BEAST_EXPECT(jrr[jss::result][jss::error_message] == "Field 'build_path' not allowed in this context."); } // Can't pay negative amount @@ -1106,10 +926,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth | tfMPTCanTransfer}); mptAlice.authorize({.account = bob}); @@ -1123,10 +940,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth | tfMPTCanTransfer}); // bob creates an empty MPToken mptAlice.authorize({.account = bob}); @@ -1138,16 +952,14 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(alice, bob, 100); // alice UNAUTHORIZES bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); // bob fails to send back to alice because he is no longer // authorize to move his funds! mptAlice.pay(bob, alice, 100, tecNO_AUTH); } - if (features[featureSingleAssetVault] && - features[featurePermissionedDomains]) + if (features[featureSingleAssetVault] && features[featurePermissionedDomains]) { // If RequireAuth is enabled and domain is a match, payment succeeds { @@ -1157,8 +969,7 @@ class MPToken_test : public beast::unit_test::suite env.fund(XRP(1000), credIssuer1, bob); auto const domainId1 = [&]() { - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; env(pdomain::setTx(credIssuer1, credentials1)); return [&]() { @@ -1171,7 +982,7 @@ class MPToken_test : public beast::unit_test::suite env(credentials::accept(bob, credIssuer1, credType)); env.close(); - MPTTester mptAlice(env, alice, {}); + MPTTester mptAlice(env, alice); env.close(); mptAlice.create({ @@ -1199,8 +1010,7 @@ class MPToken_test : public beast::unit_test::suite env.fund(XRP(1000), credIssuer1, bob); auto const domainId1 = [&]() { - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; env(pdomain::setTx(credIssuer1, credentials1)); return [&]() { @@ -1213,7 +1023,7 @@ class MPToken_test : public beast::unit_test::suite env(credentials::accept(bob, credIssuer1, credType)); env.close(); - MPTTester mptAlice(env, alice, {}); + MPTTester mptAlice(env, alice); env.close(); mptAlice.create({ @@ -1233,10 +1043,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(alice, bob, 100); // alice UNAUTHORIZES bob - mptAlice.authorize( - {.account = alice, - .holder = bob, - .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); // bob is still authorized, via domain mptAlice.pay(bob, alice, 10); @@ -1259,8 +1066,7 @@ class MPToken_test : public beast::unit_test::suite env.fund(XRP(1000), credIssuer1, credIssuer2, bob, carol); auto const domainId1 = [&]() { - pdomain::Credentials const credentials{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials{{.issuer = credIssuer1, .credType = credType}}; env(pdomain::setTx(credIssuer1, credentials)); return [&]() { @@ -1271,8 +1077,7 @@ class MPToken_test : public beast::unit_test::suite auto const domainId2 = [&]() { pdomain::Credentials const credentials{ - {.issuer = credIssuer1, .credType = credType}, - {.issuer = credIssuer2, .credType = credType}}; + {.issuer = credIssuer1, .credType = credType}, {.issuer = credIssuer2, .credType = credType}}; env(pdomain::setTx(credIssuer2, credentials)); return [&]() { @@ -1293,7 +1098,7 @@ class MPToken_test : public beast::unit_test::suite env(credentials::accept(carol, credIssuer2, credType)); env.close(); - MPTTester mptAlice(env, alice, {}); + MPTTester mptAlice(env, alice); env.close(); mptAlice.create({ @@ -1331,8 +1136,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); // bob loses his authorization and can no longer send MPT - env(credentials::deleteCred( - credIssuer1, bob, credIssuer1, credType)); + env(credentials::deleteCred(credIssuer1, bob, credIssuer1, credType)); env.close(); mptAlice.pay(bob, carol, 10, tecNO_AUTH); @@ -1375,8 +1179,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); // issuer to holder mptAlice.pay(alice, bob, 100, tecNO_AUTH); @@ -1414,8 +1217,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanTransfer}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1453,11 +1255,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); // Transfer fee is 10% - mptAlice.create( - {.transferFee = 10'000, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer}); + mptAlice.create({.transferFee = 10'000, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); // Holders create MPToken mptAlice.authorize({.account = bob}); @@ -1480,9 +1278,7 @@ class MPToken_test : public beast::unit_test::suite auto const MPT = mptAlice["MPT"]; // SendMax doesn't cover the fee - env(pay(bob, carol, MPT(100)), - sendmax(MPT(109)), - ter(tecPATH_PARTIAL)); + env(pay(bob, carol, MPT(100)), sendmax(MPT(109)), ter(tecPATH_PARTIAL)); // Payment succeeds if sufficient SendMax is included. // 100 to carol, 10 to issuer @@ -1493,9 +1289,7 @@ class MPToken_test : public beast::unit_test::suite BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200)); // Payment succeeds if partial payment even if // SendMax is less than deliver amount - env(pay(bob, carol, MPT(100)), - sendmax(MPT(90)), - txflags(tfPartialPayment)); + env(pay(bob, carol, MPT(100)), sendmax(MPT(90)), txflags(tfPartialPayment)); // 82 to carol, 8 to issuer (90 / 1.1 ~ 81.81 (rounded to nearest) = // 82) BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690)); @@ -1508,8 +1302,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); // Holders create MPToken mptAlice.authorize({.account = bob}); @@ -1518,20 +1311,14 @@ class MPToken_test : public beast::unit_test::suite auto const MPT = mptAlice["MPT"]; // SendMax is less than the amount - env(pay(bob, carol, MPT(100)), - sendmax(MPT(99)), - ter(tecPATH_PARTIAL)); - env(pay(bob, alice, MPT(100)), - sendmax(MPT(99)), - ter(tecPATH_PARTIAL)); + env(pay(bob, carol, MPT(100)), sendmax(MPT(99)), ter(tecPATH_PARTIAL)); + env(pay(bob, alice, MPT(100)), sendmax(MPT(99)), ter(tecPATH_PARTIAL)); // Payment succeeds if sufficient SendMax is included. env(pay(bob, carol, MPT(100)), sendmax(MPT(100))); BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100)); // Payment succeeds if partial payment - env(pay(bob, carol, MPT(100)), - sendmax(MPT(99)), - txflags(tfPartialPayment)); + env(pay(bob, carol, MPT(100)), sendmax(MPT(99)), txflags(tfPartialPayment)); BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199)); } @@ -1541,8 +1328,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); // Holders create MPToken mptAlice.authorize({.account = bob}); @@ -1554,14 +1340,11 @@ class MPToken_test : public beast::unit_test::suite // deliver amount < deliverMin env(pay(bob, alice, MPT(100)), sendmax(MPT(99)), - delivermin(MPT(100)), + deliver_min(MPT(100)), txflags(tfPartialPayment), ter(tecPATH_PARTIAL)); // Payment succeeds if deliver amount >= deliverMin - env(pay(bob, alice, MPT(100)), - sendmax(MPT(99)), - delivermin(MPT(99)), - txflags(tfPartialPayment)); + env(pay(bob, alice, MPT(100)), sendmax(MPT(99)), deliver_min(MPT(99)), txflags(tfPartialPayment)); } // Issuer fails trying to send more than the maximum amount allowed @@ -1570,11 +1353,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.maxAmt = 100, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer}); + mptAlice.create({.maxAmt = 100, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); mptAlice.authorize({.account = bob}); @@ -1612,8 +1391,7 @@ class MPToken_test : public beast::unit_test::suite Json::Value jv; jv[jss::secret] = alice.name(); jv[jss::tx_json] = pay(alice, bob, mpt); - jv[jss::tx_json][jss::Amount][jss::value] = - to_string(maxMPTokenAmount + 1); + jv[jss::tx_json][jss::Amount][jss::value] = std::to_string(maxMPTokenAmount + 1); auto const jrr = env.rpc("json", "submit", to_string(jv)); BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); } @@ -1626,11 +1404,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); mptAlice.create( - {.maxAmt = 10'000, - .transferFee = 100, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer}); + {.maxAmt = 10'000, .transferFee = 100, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); auto const MPT = mptAlice["MPT"]; mptAlice.authorize({.account = bob}); @@ -1640,33 +1414,22 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(alice, bob, 10'000); // payment between the holders - env(pay(bob, carol, MPT(10'000)), - sendmax(MPT(10'000)), - txflags(tfPartialPayment)); + env(pay(bob, carol, MPT(10'000)), sendmax(MPT(10'000)), txflags(tfPartialPayment)); // Verify the metadata - auto const meta = env.meta()->getJson( - JsonOptions::none)[sfAffectedNodes.fieldName]; + auto const meta = env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName]; // Issuer got 10 in the transfer fees BEAST_EXPECT( - meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName] - [sfOutstandingAmount.fieldName] == "9990"); + meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName][sfOutstandingAmount.fieldName] == "9990"); // Destination account got 9'990 - BEAST_EXPECT( - meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName] - [sfMPTAmount.fieldName] == "9990"); + BEAST_EXPECT(meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName][sfMPTAmount.fieldName] == "9990"); // Source account spent 10'000 BEAST_EXPECT( - meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName] - [sfMPTAmount.fieldName] == "10000"); - BEAST_EXPECT( - !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName] - .isMember(sfMPTAmount.fieldName)); + meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName][sfMPTAmount.fieldName] == "10000"); + BEAST_EXPECT(!meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName].isMember(sfMPTAmount.fieldName)); // payment between the holders fails without // partial payment - env(pay(bob, carol, MPT(10'000)), - sendmax(MPT(10'000)), - ter(tecPATH_PARTIAL)); + env(pay(bob, carol, MPT(10'000)), sendmax(MPT(10'000)), ter(tecPATH_PARTIAL)); } // Pay maximum allowed amount @@ -1675,11 +1438,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.maxAmt = maxMPTokenAmount, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer}); + mptAlice.create({.maxAmt = maxMPTokenAmount, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); auto const MPT = mptAlice["MPT"]; mptAlice.authorize({.account = bob}); @@ -1687,13 +1446,11 @@ class MPToken_test : public beast::unit_test::suite // issuer sends holder the max amount allowed mptAlice.pay(alice, bob, maxMPTokenAmount); - BEAST_EXPECT( - mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); + BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); // payment between the holders mptAlice.pay(bob, carol, maxMPTokenAmount); - BEAST_EXPECT( - mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); + BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); // holder pays back to the issuer mptAlice.pay(carol, alice, maxMPTokenAmount); BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0)); @@ -1754,8 +1511,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.maxAmt = 100, .ownerCount = 1, .flags = tfMPTCanTransfer}); + mptAlice.create({.maxAmt = 100, .ownerCount = 1, .flags = tfMPTCanTransfer}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1772,8 +1528,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1811,10 +1566,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth | tfMPTCanTransfer}); env(pay(diana, bob, XRP(500))); env.close(); @@ -1824,7 +1576,7 @@ class MPToken_test : public beast::unit_test::suite // alice authorizes bob to hold funds mptAlice.authorize({.account = alice, .holder = bob}); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); @@ -1845,8 +1597,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); env(credentials::accept(alice, dpIssuer, credType)); env.close(); - auto const jv = - credentials::ledgerEntry(env, alice, dpIssuer, credType); + auto const jv = credentials::ledgerEntry(env, alice, dpIssuer, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); // alice sends 100 MPT to bob with credentials which aren't required @@ -1890,10 +1641,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth | tfMPTCanTransfer}); env(pay(diana, bob, XRP(500))); env.close(); @@ -1903,7 +1651,7 @@ class MPToken_test : public beast::unit_test::suite // alice authorizes bob to hold funds mptAlice.authorize({.account = alice, .holder = bob}); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); @@ -1960,12 +1708,10 @@ class MPToken_test : public beast::unit_test::suite // Transaction has amount/issue fields. // Exclude pseudo-transaction SetFee. Don't consider // the Fee field since it's included in every transaction. - if (e.supportMPT() == soeMPTNotSupported && - e.sField().getName() != jss::Fee && + if (e.supportMPT() == soeMPTNotSupported && e.sField().getName() != jss::Fee && format.getName() != jss::SetFee) { - txWithAmounts.insert( - format.getName() + e.sField().fieldName); + txWithAmounts.insert(format.getName() + e.sField().fieldName); break; } } @@ -1982,18 +1728,15 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, feature}; env.fund(XRP(1'000), alice); env.fund(XRP(1'000), carol); - auto test = [&](Json::Value const& jv, - std::string const& mptField) { - txWithAmounts.erase( - jv[jss::TransactionType].asString() + mptField); + auto test = [&](Json::Value const& jv, std::string const& mptField) { + txWithAmounts.erase(jv[jss::TransactionType].asString() + mptField); // tx is signed auto jtx = env.jt(jv); Serializer s; jtx.stx->add(s); auto jrr = env.rpc("submit", strHex(s.slice())); - BEAST_EXPECT( - jrr[jss::result][jss::error] == "invalidTransaction"); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidTransaction"); // tx is unsigned Json::Value jv1; @@ -2005,17 +1748,12 @@ class MPToken_test : public beast::unit_test::suite jrr = env.rpc("json", "sign", to_string(jv1)); BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); }; - auto toSFieldRef = [](SField const& field) { - return std::ref(field); - }; - auto setMPTFields = [&](SField const& field, - Json::Value& jv, - bool withAmount = true) { + auto toSFieldRef = [](SField const& field) { return std::ref(field); }; + auto setMPTFields = [&](SField const& field, Json::Value& jv, bool withAmount = true) { jv[jss::Asset] = to_json(xrpIssue()); jv[jss::Asset2] = to_json(USD.issue()); if (withAmount) - jv[field.fieldName] = - USD(10).value().getJson(JsonOptions::none); + jv[field.fieldName] = USD(10).value().getJson(JsonOptions::none); if (field == sfAsset) jv[jss::Asset] = to_json(mpt.get()); else if (field == sfAsset2) @@ -2032,12 +1770,10 @@ class MPToken_test : public beast::unit_test::suite Json::Value jv; jv[jss::TransactionType] = jss::AMMCreate; jv[jss::Account] = alice.human(); - jv[jss::Amount] = (field.fieldName == sfAmount.fieldName) - ? mpt.getJson(JsonOptions::none) - : "100000000"; - jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName) - ? mpt.getJson(JsonOptions::none) - : "100000000"; + jv[jss::Amount] = + (field.fieldName == sfAmount.fieldName) ? mpt.getJson(JsonOptions::none) : "100000000"; + jv[jss::Amount2] = + (field.fieldName == sfAmount2.fieldName) ? mpt.getJson(JsonOptions::none) : "100000000"; jv[jss::TradingFee] = 0; test(jv, field.fieldName); }; @@ -2086,10 +1822,7 @@ class MPToken_test : public beast::unit_test::suite test(jv, field.fieldName); }; for (SField const& field : - {toSFieldRef(sfBidMin), - toSFieldRef(sfBidMax), - toSFieldRef(sfAsset), - toSFieldRef(sfAsset2)}) + {toSFieldRef(sfBidMin), toSFieldRef(sfBidMax), toSFieldRef(sfAsset), toSFieldRef(sfAsset2)}) ammBid(field); // AMMClawback auto ammClawback = [&](SField const& field) { @@ -2100,10 +1833,7 @@ class MPToken_test : public beast::unit_test::suite setMPTFields(field, jv); test(jv, field.fieldName); }; - for (SField const& field : - {toSFieldRef(sfAmount), - toSFieldRef(sfAsset), - toSFieldRef(sfAsset2)}) + for (SField const& field : {toSFieldRef(sfAmount), toSFieldRef(sfAsset), toSFieldRef(sfAsset2)}) ammClawback(field); // AMMDelete auto ammDelete = [&](SField const& field) { @@ -2196,8 +1926,7 @@ class MPToken_test : public beast::unit_test::suite Json::Value jv; jv[jss::TransactionType] = jss::NFTokenAcceptOffer; jv[jss::Account] = alice.human(); - jv[sfNFTokenBrokerFee.fieldName] = - mpt.getJson(JsonOptions::none); + jv[sfNFTokenBrokerFee.fieldName] = mpt.getJson(JsonOptions::none); test(jv, sfNFTokenBrokerFee.fieldName); } // NFTokenMint @@ -2232,39 +1961,19 @@ class MPToken_test : public beast::unit_test::suite } // XChainCreateClaimID { - Json::Value const jv = - xchain_create_claim_id(alice, jvb, mpt, alice); + Json::Value const jv = xchain_create_claim_id(alice, jvb, mpt, alice); test(jv, sfSignatureReward.fieldName); } // XChainAddClaimAttestation { - Json::Value const jv = claim_attestation( - alice, - jvb, - alice, - mpt, - alice, - true, - 1, - alice, - signer(alice)); + Json::Value const jv = claim_attestation(alice, jvb, alice, mpt, alice, true, 1, alice, signer(alice)); test(jv, jss::Amount.c_str()); } // XChainAddAccountCreateAttestation { - Json::Value jv = create_account_attestation( - alice, - jvb, - alice, - mpt, - XRP(10), - alice, - false, - 1, - alice, - signer(alice)); - for (auto const& field : - {sfAmount.fieldName, sfSignatureReward.fieldName}) + Json::Value jv = + create_account_attestation(alice, jvb, alice, mpt, XRP(10), alice, false, 1, alice, signer(alice)); + for (auto const& field : {sfAmount.fieldName, sfSignatureReward.fieldName}) { jv[field] = mpt.getJson(JsonOptions::none); test(jv, field); @@ -2272,10 +1981,8 @@ class MPToken_test : public beast::unit_test::suite } // XChainAccountCreateCommit { - Json::Value jv = sidechain_xchain_account_create( - alice, jvb, alice, mpt, XRP(10)); - for (auto const& field : - {sfAmount.fieldName, sfSignatureReward.fieldName}) + Json::Value jv = sidechain_xchain_account_create(alice, jvb, alice, mpt, XRP(10)); + for (auto const& field : {sfAmount.fieldName, sfSignatureReward.fieldName}) { jv[field] = mpt.getJson(JsonOptions::none); test(jv, field); @@ -2290,28 +1997,16 @@ class MPToken_test : public beast::unit_test::suite jv[jss::TransactionType] = tt; jv[jss::Account] = alice.human(); jv[sfXChainBridge.fieldName] = jvb; - jv[sfSignatureReward.fieldName] = - rewardAmount.getJson(JsonOptions::none); - jv[sfMinAccountCreateAmount.fieldName] = - minAccountAmount.getJson(JsonOptions::none); + jv[sfSignatureReward.fieldName] = rewardAmount.getJson(JsonOptions::none); + jv[sfMinAccountCreateAmount.fieldName] = minAccountAmount.getJson(JsonOptions::none); test(jv, field); }; auto reward = STAmount{sfSignatureReward, mpt}; auto minAmount = STAmount{sfMinAccountCreateAmount, USD(10)}; - for (SField const& field : - {std::ref(sfSignatureReward), - std::ref(sfMinAccountCreateAmount)}) + for (SField const& field : {std::ref(sfSignatureReward), std::ref(sfMinAccountCreateAmount)}) { - bridgeTx( - jss::XChainCreateBridge, - reward, - minAmount, - field.fieldName); - bridgeTx( - jss::XChainModifyBridge, - reward, - minAmount, - field.fieldName); + bridgeTx(jss::XChainCreateBridge, reward, minAmount, field.fieldName); + bridgeTx(jss::XChainModifyBridge, reward, minAmount, field.fieldName); reward = STAmount{sfSignatureReward, USD(10)}; minAmount = STAmount{sfMinAccountCreateAmount, mpt}; } @@ -2336,8 +2031,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create(); - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; BEAST_EXPECTS( txHash == "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC" @@ -2348,8 +2042,7 @@ class MPToken_test : public beast::unit_test::suite // Expect mpt_issuance_id field BEAST_EXPECT(meta.isMember(jss::mpt_issuance_id)); BEAST_EXPECT(id == to_string(mptAlice.issuanceID())); - BEAST_EXPECTS( - id == "00000004AE123A8556F3CF91154711376AFB0F894F832B3D", id); + BEAST_EXPECTS(id == "00000004AE123A8556F3CF91154711376AFB0F894F832B3D", id); } void @@ -2368,8 +2061,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); auto const USD = alice["USD"]; - auto const mpt = ripple::test::jtx::MPT( - alice.name(), makeMptID(env.seq(alice), alice)); + auto const mpt = xrpl::test::jtx::MPT(alice.name(), makeMptID(env.seq(alice), alice)); env(claw(alice, bob["USD"](5), bob), ter(temMALFORMED)); env.close(); @@ -2391,8 +2083,7 @@ class MPToken_test : public beast::unit_test::suite env.close(); auto const USD = alice["USD"]; - auto const mpt = ripple::test::jtx::MPT( - alice.name(), makeMptID(env.seq(alice), alice)); + auto const mpt = xrpl::test::jtx::MPT(alice.name(), makeMptID(env.seq(alice), alice)); // clawing back IOU from a MPT holder fails env(claw(alice, bob["USD"](5), bob), ter(temMALFORMED)); @@ -2450,16 +2141,14 @@ class MPToken_test : public beast::unit_test::suite env.close(); MPTTester mptAlice(env, alice, {.holders = {bob}}); - auto const fakeMpt = ripple::test::jtx::MPT( - alice.name(), makeMptID(env.seq(alice), alice)); + auto const fakeMpt = xrpl::test::jtx::MPT(alice.name(), makeMptID(env.seq(alice), alice)); // issuer tries to clawback MPT where issuance doesn't exist env(claw(alice, fakeMpt(5), bob), ter(tecOBJECT_NOT_FOUND)); env.close(); // alice creates issuance - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); // alice tries to clawback from someone who doesn't have MPToken mptAlice.claw(alice, bob, 1, tecOBJECT_NOT_FOUND); @@ -2489,11 +2178,10 @@ class MPToken_test : public beast::unit_test::suite env.fund(XRP(1000), alice, bob); env.close(); - auto const mpt = ripple::test::jtx::MPT( - alice.name(), makeMptID(env.seq(alice), alice)); + auto const mpt = xrpl::test::jtx::MPT(alice.name(), makeMptID(env.seq(alice), alice)); Json::Value jv = claw(alice, mpt(1), bob); - jv[jss::Amount][jss::value] = to_string(maxMPTokenAmount + 1); + jv[jss::Amount][jss::value] = std::to_string(maxMPTokenAmount + 1); Json::Value jv1; jv1[jss::secret] = alice.name(); jv1[jss::tx_json] = jv; @@ -2516,8 +2204,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // alice creates issuance - mptAlice.create( - {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); // bob creates a MPToken mptAlice.authorize({.account = bob}); @@ -2542,10 +2229,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // alice creates issuance - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanLock | tfMPTCanClawback}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock | tfMPTCanClawback}); // bob creates a MPToken mptAlice.authorize({.account = bob}); @@ -2567,10 +2251,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // alice creates issuance - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanLock | tfMPTCanClawback}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock | tfMPTCanClawback}); // bob creates a MPToken mptAlice.authorize({.account = bob}); @@ -2592,10 +2273,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); // alice creates issuance - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanClawback | tfMPTRequireAuth}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback | tfMPTRequireAuth}); // bob creates a MPToken mptAlice.authorize({.account = bob}); @@ -2607,8 +2285,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(alice, bob, 100); // alice unauthorizes bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); mptAlice.claw(alice, bob, 100); } @@ -2670,7 +2347,7 @@ class MPToken_test : public beast::unit_test::suite STAmount const amt3{asset3, 10'000}; { - testcase("Test STAmount MPT arithmetics"); + testcase("Test STAmount MPT arithmetic"); using namespace std::string_literals; STAmount res = multiply(amt1, amt2, asset3); BEAST_EXPECT(res == amt3); @@ -2707,7 +2384,7 @@ class MPToken_test : public beast::unit_test::suite } { - testcase("Test MPTAmount arithmetics"); + testcase("Test MPTAmount arithmetic"); MPTAmount mptAmt1{100}; MPTAmount const mptAmt2{100}; BEAST_EXPECT((mptAmt1 += mptAmt2) == MPTAmount{200}); @@ -2722,16 +2399,14 @@ class MPToken_test : public beast::unit_test::suite testcase("Test MPTIssue from/to Json"); MPTIssue const issue1{asset1.get()}; Json::Value const jv = to_json(issue1); - BEAST_EXPECT( - jv[jss::mpt_issuance_id] == to_string(asset1.get())); + BEAST_EXPECT(jv[jss::mpt_issuance_id] == to_string(asset1.get())); BEAST_EXPECT(issue1 == mptIssueFromJson(jv)); } { testcase("Test Asset from/to Json"); Json::Value const jv = to_json(asset1); - BEAST_EXPECT( - jv[jss::mpt_issuance_id] == to_string(asset1.get())); + BEAST_EXPECT(jv[jss::mpt_issuance_id] == to_string(asset1.get())); BEAST_EXPECT( to_string(jv) == "{\"mpt_issuance_id\":" @@ -2752,10 +2427,8 @@ class MPToken_test : public beast::unit_test::suite { Env env{*this, features - featureDynamicMPT}; MPTTester mptAlice(env, alice); - mptAlice.create( - {.ownerCount = 0, .mutableFlags = 2, .err = temDISABLED}); - mptAlice.create( - {.ownerCount = 0, .mutableFlags = 0, .err = temDISABLED}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 2, .err = temDISABLED}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 0, .err = temDISABLED}); } // MutableFlags contains invalid values @@ -2764,18 +2437,12 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice); // Value 1 is reserved for MPT lock. - mptAlice.create( - {.ownerCount = 0, .mutableFlags = 1, .err = temINVALID_FLAG}); - mptAlice.create( - {.ownerCount = 0, .mutableFlags = 17, .err = temINVALID_FLAG}); - mptAlice.create( - {.ownerCount = 0, - .mutableFlags = 65535, - .err = temINVALID_FLAG}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 1, .err = temINVALID_FLAG}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 17, .err = temINVALID_FLAG}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 65535, .err = temINVALID_FLAG}); // MutableFlags can not be 0 - mptAlice.create( - {.ownerCount = 0, .mutableFlags = 0, .err = temINVALID_FLAG}); + mptAlice.create({.ownerCount = 0, .mutableFlags = 0, .err = temINVALID_FLAG}); } } @@ -2796,40 +2463,16 @@ class MPToken_test : public beast::unit_test::suite auto const mptID = makeMptID(env.seq(alice), alice); // MutableFlags is not allowed when DynamicMPT is not enabled - mptAlice.set( - {.account = alice, - .id = mptID, - .mutableFlags = 2, - .err = temDISABLED}); - mptAlice.set( - {.account = alice, - .id = mptID, - .mutableFlags = 0, - .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .mutableFlags = 2, .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .mutableFlags = 0, .err = temDISABLED}); // MPTokenMetadata is not allowed when DynamicMPT is not enabled - mptAlice.set( - {.account = alice, - .id = mptID, - .metadata = "test", - .err = temDISABLED}); - mptAlice.set( - {.account = alice, - .id = mptID, - .metadata = "", - .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .metadata = "test", .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .metadata = "", .err = temDISABLED}); // TransferFee is not allowed when DynamicMPT is not enabled - mptAlice.set( - {.account = alice, - .id = mptID, - .transferFee = 100, - .err = temDISABLED}); - mptAlice.set( - {.account = alice, - .id = mptID, - .transferFee = 0, - .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .transferFee = 100, .err = temDISABLED}); + mptAlice.set({.account = alice, .id = mptID, .transferFee = 0, .err = temDISABLED}); } // Can not provide holder when MutableFlags, MPTokenMetadata or @@ -2840,28 +2483,13 @@ class MPToken_test : public beast::unit_test::suite auto const mptID = makeMptID(env.seq(alice), alice); // Holder is not allowed when MutableFlags is present - mptAlice.set( - {.account = alice, - .holder = bob, - .id = mptID, - .mutableFlags = 2, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = bob, .id = mptID, .mutableFlags = 2, .err = temMALFORMED}); // Holder is not allowed when MPTokenMetadata is present - mptAlice.set( - {.account = alice, - .holder = bob, - .id = mptID, - .metadata = "test", - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = bob, .id = mptID, .metadata = "test", .err = temMALFORMED}); // Holder is not allowed when TransferFee is present - mptAlice.set( - {.account = alice, - .holder = bob, - .id = mptID, - .transferFee = 100, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .holder = bob, .id = mptID, .transferFee = 100, .err = temMALFORMED}); } // Can not set Flags when MutableFlags, MPTokenMetadata or @@ -2871,29 +2499,16 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create( {.ownerCount = 1, - .mutableFlags = tmfMPTCanMutateMetadata | - tmfMPTCanMutateCanLock | tmfMPTCanMutateTransferFee}); + .mutableFlags = tmfMPTCanMutateMetadata | tmfMPTCanMutateCanLock | tmfMPTCanMutateTransferFee}); // Setting flags is not allowed when MutableFlags is present - mptAlice.set( - {.account = alice, - .flags = tfMPTCanLock, - .mutableFlags = 2, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .flags = tfMPTCanLock, .mutableFlags = 2, .err = temMALFORMED}); // Setting flags is not allowed when MPTokenMetadata is present - mptAlice.set( - {.account = alice, - .flags = tfMPTCanLock, - .metadata = "test", - .err = temMALFORMED}); + mptAlice.set({.account = alice, .flags = tfMPTCanLock, .metadata = "test", .err = temMALFORMED}); // setting flags is not allowed when TransferFee is present - mptAlice.set( - {.account = alice, - .flags = tfMPTCanLock, - .transferFee = 100, - .err = temMALFORMED}); + mptAlice.set({.account = alice, .flags = tfMPTCanLock, .transferFee = 100, .err = temMALFORMED}); } // Flags being 0 or tfFullyCanonicalSig is fine @@ -2905,19 +2520,10 @@ class MPToken_test : public beast::unit_test::suite {.transferFee = 10, .ownerCount = 1, .flags = tfMPTCanTransfer, - .mutableFlags = - tmfMPTCanMutateTransferFee | tmfMPTCanMutateMetadata}); + .mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanMutateMetadata}); - mptAlice.set( - {.account = alice, - .flags = 0, - .transferFee = 100, - .metadata = "test"}); - mptAlice.set( - {.account = alice, - .flags = tfFullyCanonicalSig, - .transferFee = 200, - .metadata = "test2"}); + mptAlice.set({.account = alice, .flags = 0, .transferFee = 100, .metadata = "test"}); + mptAlice.set({.account = alice, .flags = tfFullyCanonicalSig, .transferFee = 200, .metadata = "test2"}); } // Invalid MutableFlags @@ -2928,11 +2534,7 @@ class MPToken_test : public beast::unit_test::suite for (auto const flags : {10000, 0, 5000}) { - mptAlice.set( - {.account = alice, - .id = mptID, - .mutableFlags = flags, - .err = temINVALID_FLAG}); + mptAlice.set({.account = alice, .id = mptID, .mutableFlags = flags, .err = temINVALID_FLAG}); } } @@ -2949,17 +2551,13 @@ class MPToken_test : public beast::unit_test::suite tmfMPTSetCanTrade | tmfMPTClearCanTrade, tmfMPTSetCanTransfer | tmfMPTClearCanTransfer, tmfMPTSetCanClawback | tmfMPTClearCanClawback, + tmfMPTSetPrivacy | tmfMPTClearPrivacy, tmfMPTSetCanLock | tmfMPTClearCanLock | tmfMPTClearCanTrade, - tmfMPTSetCanTransfer | tmfMPTClearCanTransfer | - tmfMPTSetCanEscrow | tmfMPTClearCanClawback}; + tmfMPTSetCanTransfer | tmfMPTClearCanTransfer | tmfMPTSetCanEscrow | tmfMPTClearCanClawback}; for (auto const& mutableFlags : flagCombinations) { - mptAlice.set( - {.account = alice, - .id = mptID, - .mutableFlags = mutableFlags, - .err = temINVALID_FLAG}); + mptAlice.set({.account = alice, .id = mptID, .mutableFlags = mutableFlags, .err = temINVALID_FLAG}); } } @@ -2986,10 +2584,7 @@ class MPToken_test : public beast::unit_test::suite for (auto const& mutableFlag : mutableFlags) { - mptAlice.set( - {.account = alice, - .mutableFlags = mutableFlag, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .mutableFlags = mutableFlag, .err = tecNO_PERMISSION}); } } @@ -2998,12 +2593,10 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, .mutableFlags = tmfMPTCanMutateMetadata}); + mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateMetadata}); std::string metadata(maxMPTokenMetadataLength + 1, 'a'); - mptAlice.set( - {.account = alice, .metadata = metadata, .err = temMALFORMED}); + mptAlice.set({.account = alice, .metadata = metadata, .err = temMALFORMED}); } // Can not mutate metadata when it is not mutable @@ -3012,10 +2605,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({.ownerCount = 1}); - mptAlice.set( - {.account = alice, - .metadata = "test", - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .metadata = "test", .err = tecNO_PERMISSION}); } // Transfer fee exceeding the max value @@ -3024,14 +2614,10 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); auto const mptID = makeMptID(env.seq(alice), alice); - mptAlice.create( - {.ownerCount = 1, .mutableFlags = tmfMPTCanMutateTransferFee}); + mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateTransferFee}); mptAlice.set( - {.account = alice, - .id = mptID, - .transferFee = maxTransferFee + 1, - .err = temBAD_TRANSFER_FEE}); + {.account = alice, .id = mptID, .transferFee = maxTransferFee + 1, .err = temBAD_TRANSFER_FEE}); } // Test setting non-zero transfer fee and clearing MPTCanTransfer at the @@ -3044,24 +2630,17 @@ class MPToken_test : public beast::unit_test::suite {.transferFee = 100, .ownerCount = 1, .flags = tfMPTCanTransfer, - .mutableFlags = - tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); + .mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); // Can not set non-zero transfer fee and clear MPTCanTransfer at the // same time mptAlice.set( - {.account = alice, - .mutableFlags = tmfMPTClearCanTransfer, - .transferFee = 1, - .err = temMALFORMED}); + {.account = alice, .mutableFlags = tmfMPTClearCanTransfer, .transferFee = 1, .err = temMALFORMED}); // Can set transfer fee to zero and clear MPTCanTransfer at the same // time. tfMPTCanTransfer will be cleared and TransferFee field will // be removed. - mptAlice.set( - {.account = alice, - .mutableFlags = tmfMPTClearCanTransfer, - .transferFee = 0}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTransfer, .transferFee = 0}); BEAST_EXPECT(!mptAlice.isTransferFeePresent()); } @@ -3070,24 +2649,15 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .mutableFlags = - tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); + mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); - mptAlice.set( - {.account = alice, - .transferFee = 100, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION}); // Can not set transfer fee even when trying to set MPTCanTransfer // at the same time. MPTCanTransfer must be set first, then transfer // fee can be set in a separate transaction. mptAlice.set( - {.account = alice, - .mutableFlags = tmfMPTSetCanTransfer, - .transferFee = 100, - .err = tecNO_PERMISSION}); + {.account = alice, .mutableFlags = tmfMPTSetCanTransfer, .transferFee = 100, .err = tecNO_PERMISSION}); } // Can not mutate transfer fee when it is not mutable @@ -3095,18 +2665,11 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.transferFee = 10, - .ownerCount = 1, - .flags = tfMPTCanTransfer}); + mptAlice.create({.transferFee = 10, .ownerCount = 1, .flags = tfMPTCanTransfer}); - mptAlice.set( - {.account = alice, - .transferFee = 100, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION}); - mptAlice.set( - {.account = alice, .transferFee = 0, .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .transferFee = 0, .err = tecNO_PERMISSION}); } // Set some flags mutable. Can not mutate the others @@ -3116,14 +2679,10 @@ class MPToken_test : public beast::unit_test::suite mptAlice.create( {.ownerCount = 1, - .mutableFlags = tmfMPTCanMutateCanTrade | - tmfMPTCanMutateCanTransfer | tmfMPTCanMutateMetadata}); + .mutableFlags = tmfMPTCanMutateCanTrade | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateMetadata}); // Can not mutate transfer fee - mptAlice.set( - {.account = alice, - .transferFee = 100, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION}); auto const invalidFlags = { tmfMPTSetCanLock, @@ -3138,22 +2697,16 @@ class MPToken_test : public beast::unit_test::suite // Can not mutate flags which are not mutable for (auto const& mutableFlag : invalidFlags) { - mptAlice.set( - {.account = alice, - .mutableFlags = mutableFlag, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .mutableFlags = mutableFlag, .err = tecNO_PERMISSION}); } // Can mutate MPTCanTrade mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTrade}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanTrade}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTrade}); // Can mutate MPTCanTransfer - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTSetCanTransfer}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTransfer}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); // Can mutate metadata mptAlice.set({.account = alice, .metadata = "test"}); @@ -3173,10 +2726,7 @@ class MPToken_test : public beast::unit_test::suite { Env env{*this, features}; MPTTester mptAlice(env, alice); - mptAlice.create( - {.metadata = "test", - .ownerCount = 1, - .mutableFlags = tmfMPTCanMutateMetadata}); + mptAlice.create({.metadata = "test", .ownerCount = 1, .mutableFlags = tmfMPTCanMutateMetadata}); std::vector metadatas = { "mutate metadata", @@ -3208,8 +2758,8 @@ class MPToken_test : public beast::unit_test::suite .flags = tfMPTCanTransfer, .mutableFlags = tmfMPTCanMutateTransferFee}); - for (std::uint16_t const fee : std::initializer_list{ - 1, 10, 100, 200, 500, 1000, maxTransferFee}) + for (std::uint16_t const fee : + std::initializer_list{1, 10, 100, 200, 500, 1000, maxTransferFee}) { mptAlice.set({.account = alice, .transferFee = fee}); BEAST_EXPECT(mptAlice.checkTransferFee(fee)); @@ -3226,17 +2776,12 @@ class MPToken_test : public beast::unit_test::suite // Test flag toggling { - auto testFlagToggle = [&](std::uint32_t createFlags, - std::uint32_t setFlags, - std::uint32_t clearFlags) { + auto testFlagToggle = [&](std::uint32_t createFlags, std::uint32_t setFlags, std::uint32_t clearFlags) { Env env{*this, features}; MPTTester mptAlice(env, alice); // Create the MPT object with the specified initial flags - mptAlice.create( - {.metadata = "test", - .ownerCount = 1, - .mutableFlags = createFlags}); + mptAlice.create({.metadata = "test", .ownerCount = 1, .mutableFlags = createFlags}); // Set and clear the flag multiple times mptAlice.set({.account = alice, .mutableFlags = setFlags}); @@ -3249,28 +2794,12 @@ class MPToken_test : public beast::unit_test::suite mptAlice.set({.account = alice, .mutableFlags = clearFlags}); }; - testFlagToggle( - tmfMPTCanMutateCanLock, tfMPTCanLock, tmfMPTClearCanLock); - testFlagToggle( - tmfMPTCanMutateRequireAuth, - tmfMPTSetRequireAuth, - tmfMPTClearRequireAuth); - testFlagToggle( - tmfMPTCanMutateCanEscrow, - tmfMPTSetCanEscrow, - tmfMPTClearCanEscrow); - testFlagToggle( - tmfMPTCanMutateCanTrade, - tmfMPTSetCanTrade, - tmfMPTClearCanTrade); - testFlagToggle( - tmfMPTCanMutateCanTransfer, - tmfMPTSetCanTransfer, - tmfMPTClearCanTransfer); - testFlagToggle( - tmfMPTCanMutateCanClawback, - tmfMPTSetCanClawback, - tmfMPTClearCanClawback); + testFlagToggle(tmfMPTCanMutateCanLock, tfMPTCanLock, tmfMPTClearCanLock); + testFlagToggle(tmfMPTCanMutateRequireAuth, tmfMPTSetRequireAuth, tmfMPTClearRequireAuth); + testFlagToggle(tmfMPTCanMutateCanEscrow, tmfMPTSetCanEscrow, tmfMPTClearCanEscrow); + testFlagToggle(tmfMPTCanMutateCanTrade, tmfMPTSetCanTrade, tmfMPTClearCanTrade); + testFlagToggle(tmfMPTCanMutateCanTransfer, tmfMPTSetCanTransfer, tmfMPTClearCanTransfer); + testFlagToggle(tmfMPTCanMutateCanClawback, tmfMPTSetCanClawback, tmfMPTClearCanClawback); } } @@ -3291,22 +2820,18 @@ class MPToken_test : public beast::unit_test::suite {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock | tfMPTCanTransfer, - .mutableFlags = tmfMPTCanMutateCanLock | - tmfMPTCanMutateCanTrade | tmfMPTCanMutateTransferFee}); + .mutableFlags = tmfMPTCanMutateCanLock | tmfMPTCanMutateCanTrade | tmfMPTCanMutateTransferFee}); mptAlice.authorize({.account = bob, .holderCount = 1}); // Lock bob's mptoken mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); // Can mutate the mutable flags and fields - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanLock}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanLock}); mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanLock}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanLock}); mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTrade}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanTrade}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTrade}); mptAlice.set({.account = alice, .transferFee = 200}); } @@ -3318,23 +2843,18 @@ class MPToken_test : public beast::unit_test::suite {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock, - .mutableFlags = tmfMPTCanMutateCanLock | - tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata}); + .mutableFlags = tmfMPTCanMutateCanLock | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata}); mptAlice.authorize({.account = bob, .holderCount = 1}); // Lock issuance mptAlice.set({.account = alice, .flags = tfMPTLock}); // Can mutate the mutable flags and fields - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanLock}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanLock}); mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanLock}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTSetCanClawback}); - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanClawback}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanLock}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanClawback}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanClawback}); mptAlice.set({.account = alice, .metadata = "mutate"}); } @@ -3346,40 +2866,23 @@ class MPToken_test : public beast::unit_test::suite {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock, - .mutableFlags = tmfMPTCanMutateCanLock | - tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata}); + .mutableFlags = tmfMPTCanMutateCanLock | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata}); mptAlice.authorize({.account = bob, .holderCount = 1}); // Can lock and unlock mptAlice.set({.account = alice, .flags = tfMPTLock}); mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); mptAlice.set({.account = alice, .flags = tfMPTUnlock}); - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); // Clear lsfMPTCanLock - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanLock}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanLock}); // Can not lock or unlock - mptAlice.set( - {.account = alice, - .flags = tfMPTLock, - .err = tecNO_PERMISSION}); - mptAlice.set( - {.account = alice, - .flags = tfMPTUnlock, - .err = tecNO_PERMISSION}); - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTLock, - .err = tecNO_PERMISSION}); - mptAlice.set( - {.account = alice, - .holder = bob, - .flags = tfMPTUnlock, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .flags = tfMPTLock, .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .flags = tfMPTUnlock, .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock, .err = tecNO_PERMISSION}); // Set MPTCanLock again mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock}); @@ -3388,8 +2891,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.set({.account = alice, .flags = tfMPTLock}); mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); mptAlice.set({.account = alice, .flags = tfMPTUnlock}); - mptAlice.set( - {.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); } } @@ -3404,10 +2906,7 @@ class MPToken_test : public beast::unit_test::suite Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .flags = tfMPTRequireAuth, - .mutableFlags = tmfMPTCanMutateRequireAuth}); + mptAlice.create({.ownerCount = 1, .flags = tfMPTRequireAuth, .mutableFlags = tmfMPTCanMutateRequireAuth}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = alice, .holder = bob}); @@ -3416,15 +2915,13 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(alice, bob, 1000); // Unauthorize bob - mptAlice.authorize( - {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + mptAlice.authorize({.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); // Can not pay to bob mptAlice.pay(bob, alice, 100, tecNO_AUTH); // Clear RequireAuth - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearRequireAuth}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearRequireAuth}); // Can pay to bob mptAlice.pay(alice, bob, 1000); @@ -3457,10 +2954,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {carol, bob}}); mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer, - .mutableFlags = tmfMPTCanMutateCanEscrow}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer, .mutableFlags = tmfMPTCanMutateCanEscrow}); mptAlice.authorize({.account = carol}); mptAlice.authorize({.account = bob}); @@ -3506,10 +3000,7 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); - mptAlice.create( - {.ownerCount = 1, - .mutableFlags = - tmfMPTCanMutateCanTransfer | tmfMPTCanMutateTransferFee}); + mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateCanTransfer | tmfMPTCanMutateTransferFee}); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -3521,22 +3012,15 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(bob, carol, 50, tecNO_AUTH); // Can not set non-zero transfer fee when MPTCanTransfer is not set - mptAlice.set( - {.account = alice, - .transferFee = 100, - .err = tecNO_PERMISSION}); + mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION}); // Can not set non-zero transfer fee even when trying to set // MPTCanTransfer at the same time mptAlice.set( - {.account = alice, - .mutableFlags = tmfMPTSetCanTransfer, - .transferFee = 100, - .err = tecNO_PERMISSION}); + {.account = alice, .mutableFlags = tmfMPTSetCanTransfer, .transferFee = 100, .err = tecNO_PERMISSION}); // Alice sets MPTCanTransfer - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTSetCanTransfer}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTransfer}); // Can set transfer fee now BEAST_EXPECT(!mptAlice.isTransferFeePresent()); @@ -3547,8 +3031,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.pay(bob, carol, 50); // Alice clears MPTCanTransfer - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); // TransferFee field is removed when MPTCanTransfer is cleared BEAST_EXPECT(!mptAlice.isTransferFeePresent()); @@ -3567,14 +3050,12 @@ class MPToken_test : public beast::unit_test::suite {.transferFee = 100, .ownerCount = 1, .flags = tfMPTCanTransfer, - .mutableFlags = - tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); + .mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanMutateCanTransfer}); BEAST_EXPECT(mptAlice.checkTransferFee(100)); // Clear MPTCanTransfer and transfer fee is removed - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanTransfer}); BEAST_EXPECT(!mptAlice.isTransferFeePresent()); // Can still set transfer fee to zero, although it is already zero @@ -3597,10 +3078,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob}}); - mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .mutableFlags = tmfMPTCanMutateCanClawback}); + mptAlice.create({.ownerCount = 1, .holderCount = 0, .mutableFlags = tmfMPTCanMutateCanClawback}); // Bob creates an MPToken mptAlice.authorize({.account = bob}); @@ -3618,8 +3096,7 @@ class MPToken_test : public beast::unit_test::suite mptAlice.claw(alice, bob, 1); // Clear MPTCanClawback - mptAlice.set( - {.account = alice, .mutableFlags = tmfMPTClearCanClawback}); + mptAlice.set({.account = alice, .mutableFlags = tmfMPTClearCanClawback}); // Can not clawback mptAlice.claw(alice, bob, 1, tecNO_PERMISSION); @@ -3694,7 +3171,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(MPToken, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(MPToken, app, xrpl, 2); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Manifest_test.cpp b/src/test/app/Manifest_test.cpp index deaa2adbad..5b7e34ad5b 100644 --- a/src/test/app/Manifest_test.cpp +++ b/src/test/app/Manifest_test.cpp @@ -1,40 +1,21 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include -#include #include -#include #include #include #include #include #include +#include +#include +#include #include #include #include -namespace ripple { +namespace xrpl { namespace test { class Manifest_test : public beast::unit_test::suite @@ -74,8 +55,7 @@ private: if (!is_directory(dbPath)) { // someone created a file where we want to put our directory - Throw( - "Cannot create directory: " + dbPath.string()); + Throw("Cannot create directory: " + dbPath.string()); } } static boost::filesystem::path @@ -107,12 +87,7 @@ public: } std::string - makeManifestString( - PublicKey const& pk, - SecretKey const& sk, - PublicKey const& spk, - SecretKey const& ssk, - int seq) + makeManifestString(PublicKey const& pk, SecretKey const& sk, PublicKey const& spk, SecretKey const& ssk, int seq) { STObject st(sfGeneric); st[sfSequence] = seq; @@ -120,25 +95,16 @@ public: st[sfSigningPubKey] = spk; sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk); - sign( - st, - HashPrefix::manifest, - *publicKeyType(pk), - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, *publicKeyType(pk), sk, sfMasterSignature); Serializer s; st.add(s); - return base64_encode( - std::string(static_cast(s.data()), s.size())); + return base64_encode(std::string(static_cast(s.data()), s.size())); } std::string - makeRevocationString( - SecretKey const& sk, - KeyType type, - bool invalidSig = false) + makeRevocationString(SecretKey const& sk, KeyType type, bool invalidSig = false) { auto const pk = derivePublicKey(type, sk); @@ -146,21 +112,13 @@ public: st[sfSequence] = std::numeric_limits::max(); st[sfPublicKey] = pk; - sign( - st, - HashPrefix::manifest, - type, - invalidSig ? randomSecretKey() : sk, - sfMasterSignature); - BEAST_EXPECT( - invalidSig ^ - verify(st, HashPrefix::manifest, pk, sfMasterSignature)); + sign(st, HashPrefix::manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature); + BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::manifest, pk, sfMasterSignature)); Serializer s; st.add(s); - return base64_encode( - std::string(static_cast(s.data()), s.size())); + return base64_encode(std::string(static_cast(s.data()), s.size())); } Manifest @@ -172,15 +130,8 @@ public: st[sfSequence] = std::numeric_limits::max(); st[sfPublicKey] = pk; - sign( - st, - HashPrefix::manifest, - type, - invalidSig ? randomSecretKey() : sk, - sfMasterSignature); - BEAST_EXPECT( - invalidSig ^ - verify(st, HashPrefix::manifest, pk, sfMasterSignature)); + sign(st, HashPrefix::manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature); + BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::manifest, pk, sfMasterSignature)); Serializer s; st.add(s); @@ -190,8 +141,7 @@ public: if (auto r = deserializeManifest(std::move(m))) return std::move(*r); Throw("Could not create a revocation manifest"); - return *deserializeManifest( - std::string{}); // Silence compiler warning. + return *deserializeManifest(std::string{}); // Silence compiler warning. } Manifest @@ -214,34 +164,24 @@ public: sign(st, HashPrefix::manifest, stype, ssk); BEAST_EXPECT(verify(st, HashPrefix::manifest, spk)); - sign( - st, - HashPrefix::manifest, - type, - invalidSig ? randomSecretKey() : sk, - sfMasterSignature); - BEAST_EXPECT( - invalidSig ^ - verify(st, HashPrefix::manifest, pk, sfMasterSignature)); + sign(st, HashPrefix::manifest, type, invalidSig ? randomSecretKey() : sk, sfMasterSignature); + BEAST_EXPECT(invalidSig ^ verify(st, HashPrefix::manifest, pk, sfMasterSignature)); Serializer s; st.add(s); - std::string m( - static_cast(s.data()), - s.size()); // non-const so can be moved + std::string m(static_cast(s.data()), + s.size()); // non-const so can be moved if (auto r = deserializeManifest(std::move(m))) return std::move(*r); Throw("Could not create a manifest"); - return *deserializeManifest( - std::string{}); // Silence compiler warning. + return *deserializeManifest(std::string{}); // Silence compiler warning. } Manifest clone(Manifest const& m) { - Manifest m2( - m.serialized, m.masterKey, m.signingKey, m.sequence, m.domain); + Manifest m2(m.serialized, m.masterKey, m.signingKey, m.sequence, m.domain); return m2; } @@ -259,52 +199,35 @@ public: auto dbCon = makeTestWalletDB(setup, dbName, env.journal); - auto getPopulatedManifests = - [](ManifestCache const& cache) -> std::vector { + auto getPopulatedManifests = [](ManifestCache const& cache) -> std::vector { std::vector result; result.reserve(32); - cache.for_each_manifest( - [&result](Manifest const& man) { result.push_back(&man); }); + cache.for_each_manifest([&result](Manifest const& man) { result.push_back(&man); }); return result; }; - auto sort = [](std::vector mv) - -> std::vector { - std::sort( - mv.begin(), - mv.end(), - [](Manifest const* lhs, Manifest const* rhs) { - return lhs->serialized < rhs->serialized; - }); + auto sort = [](std::vector mv) -> std::vector { + std::sort(mv.begin(), mv.end(), [](Manifest const* lhs, Manifest const* rhs) { + return lhs->serialized < rhs->serialized; + }); return mv; }; - std::vector const inManifests( - sort(getPopulatedManifests(m))); + std::vector const inManifests(sort(getPopulatedManifests(m))); auto& app = env.app(); auto unl = std::make_unique( - m, - m, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + m, m, env.timeKeeper(), app.config().legacy("database_path"), env.journal); { // save should not store untrusted master keys to db // except for revocations - m.save( - *dbCon, - "ValidatorManifests", - [&unl](PublicKey const& pubKey) { - return unl->listed(pubKey); - }); + m.save(*dbCon, "ValidatorManifests", [&unl](PublicKey const& pubKey) { return unl->listed(pubKey); }); ManifestCache loaded; loaded.load(*dbCon, "ValidatorManifests"); // check that all loaded manifests are revocations - std::vector const loadedManifests( - sort(getPopulatedManifests(loaded))); + std::vector const loadedManifests(sort(getPopulatedManifests(loaded))); for (auto const& man : loadedManifests) BEAST_EXPECT(man->revoked()); @@ -315,22 +238,15 @@ public: std::vector keys; std::string cfgManifest; for (auto const& man : inManifests) - s1.push_back( - toBase58(TokenType::NodePublic, man->masterKey)); + s1.push_back(toBase58(TokenType::NodePublic, man->masterKey)); unl->load({}, s1, keys); - m.save( - *dbCon, - "ValidatorManifests", - [&unl](PublicKey const& pubKey) { - return unl->listed(pubKey); - }); + m.save(*dbCon, "ValidatorManifests", [&unl](PublicKey const& pubKey) { return unl->listed(pubKey); }); ManifestCache loaded; loaded.load(*dbCon, "ValidatorManifests"); // check that the manifest caches are the same - std::vector const loadedManifests( - sort(getPopulatedManifests(loaded))); + std::vector const loadedManifests(sort(getPopulatedManifests(loaded))); if (inManifests.size() == loadedManifests.size()) { @@ -338,9 +254,7 @@ public: inManifests.begin(), inManifests.end(), loadedManifests.begin(), - [](Manifest const* lhs, Manifest const* rhs) { - return *lhs == *rhs; - })); + [](Manifest const* lhs, Manifest const* rhs) { return *lhs == *rhs; })); } else { @@ -353,74 +267,44 @@ public: std::vector const emptyRevocation; std::string const badManifest = "bad manifest"; - BEAST_EXPECT(!loaded.load( - *dbCon, - "ValidatorManifests", - badManifest, - emptyRevocation)); + BEAST_EXPECT(!loaded.load(*dbCon, "ValidatorManifests", badManifest, emptyRevocation)); auto const sk = randomSecretKey(); auto const pk = derivePublicKey(KeyType::ed25519, sk); auto const kp = randomKeyPair(KeyType::secp256k1); - std::string const cfgManifest = - makeManifestString(pk, sk, kp.first, kp.second, 0); + std::string const cfgManifest = makeManifestString(pk, sk, kp.first, kp.second, 0); - BEAST_EXPECT(loaded.load( - *dbCon, - "ValidatorManifests", - cfgManifest, - emptyRevocation)); + BEAST_EXPECT(loaded.load(*dbCon, "ValidatorManifests", cfgManifest, emptyRevocation)); } { // load config revocation ManifestCache loaded; std::string const emptyManifest; - std::vector const badRevocation = { - "bad revocation"}; - BEAST_EXPECT(!loaded.load( - *dbCon, - "ValidatorManifests", - emptyManifest, - badRevocation)); + std::vector const badRevocation = {"bad revocation"}; + BEAST_EXPECT(!loaded.load(*dbCon, "ValidatorManifests", emptyManifest, badRevocation)); auto const sk = randomSecretKey(); auto const keyType = KeyType::ed25519; auto const pk = derivePublicKey(keyType, sk); auto const kp = randomKeyPair(KeyType::secp256k1); - std::vector const nonRevocation = { - makeManifestString(pk, sk, kp.first, kp.second, 0)}; + std::vector const nonRevocation = {makeManifestString(pk, sk, kp.first, kp.second, 0)}; - BEAST_EXPECT(!loaded.load( - *dbCon, - "ValidatorManifests", - emptyManifest, - nonRevocation)); + BEAST_EXPECT(!loaded.load(*dbCon, "ValidatorManifests", emptyManifest, nonRevocation)); BEAST_EXPECT(!loaded.revoked(pk)); - std::vector const badSigRevocation = { - makeRevocationString(sk, keyType, true)}; - BEAST_EXPECT(!loaded.load( - *dbCon, - "ValidatorManifests", - emptyManifest, - badSigRevocation)); + std::vector const badSigRevocation = {makeRevocationString(sk, keyType, true)}; + BEAST_EXPECT(!loaded.load(*dbCon, "ValidatorManifests", emptyManifest, badSigRevocation)); BEAST_EXPECT(!loaded.revoked(pk)); - std::vector const cfgRevocation = { - makeRevocationString(sk, keyType)}; - BEAST_EXPECT(loaded.load( - *dbCon, - "ValidatorManifests", - emptyManifest, - cfgRevocation)); + std::vector const cfgRevocation = {makeRevocationString(sk, keyType)}; + BEAST_EXPECT(loaded.load(*dbCon, "ValidatorManifests", emptyManifest, cfgRevocation)); BEAST_EXPECT(loaded.revoked(pk)); } } - boost::filesystem::remove( - getDatabasePath() / boost::filesystem::path(dbName)); + boost::filesystem::remove(getDatabasePath() / boost::filesystem::path(dbName)); } void @@ -430,8 +314,7 @@ public: auto const sk = randomSecretKey(); auto const pk = derivePublicKey(KeyType::ed25519, sk); auto const kp = randomKeyPair(KeyType::secp256k1); - auto const m = makeManifest( - sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0); + auto const m = makeManifest(sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0); STObject st(sfGeneric); st[sfSequence] = 0; @@ -466,8 +349,7 @@ public: auto const kp0 = randomKeyPair(KeyType::secp256k1); BEAST_EXPECT( ManifestDisposition::accepted == - cache.applyManifest(makeManifest( - sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0))); + cache.applyManifest(makeManifest(sk, KeyType::ed25519, kp0.second, KeyType::secp256k1, 0))); BEAST_EXPECT(cache.getSigningKey(pk) == kp0.first); BEAST_EXPECT(cache.getMasterKey(kp0.first) == pk); @@ -478,8 +360,7 @@ public: auto const kp1 = randomKeyPair(KeyType::secp256k1); BEAST_EXPECT( ManifestDisposition::accepted == - cache.applyManifest(makeManifest( - sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1))); + cache.applyManifest(makeManifest(sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 1))); BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first); BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk); BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first); @@ -488,8 +369,7 @@ public: // applied with the same signing key but a higher sequence BEAST_EXPECT( ManifestDisposition::badEphemeralKey == - cache.applyManifest(makeManifest( - sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2))); + cache.applyManifest(makeManifest(sk, KeyType::ed25519, kp1.second, KeyType::secp256k1, 2))); BEAST_EXPECT(cache.getSigningKey(pk) == kp1.first); BEAST_EXPECT(cache.getMasterKey(kp1.first) == pk); BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first); @@ -497,9 +377,7 @@ public: // getSigningKey should return std::nullopt for a revoked master public // key getMasterKey should return std::nullopt for an ephemeral public // key from a revoked master public key - BEAST_EXPECT( - ManifestDisposition::accepted == - cache.applyManifest(makeRevocation(sk, KeyType::ed25519))); + BEAST_EXPECT(ManifestDisposition::accepted == cache.applyManifest(makeRevocation(sk, KeyType::ed25519))); BEAST_EXPECT(cache.revoked(pk)); BEAST_EXPECT(cache.getSigningKey(pk) == pk); BEAST_EXPECT(cache.getMasterKey(kp0.first) == kp0.first); @@ -512,9 +390,8 @@ public: testcase("validator token"); { - auto const valSecret = parseBase58( - TokenType::NodePrivate, - "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"); + auto const valSecret = + parseBase58(TokenType::NodePrivate, "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"); // Format token string to test trim() std::vector const tokenBlob = { @@ -579,12 +456,7 @@ public: if (version != 0) st[sfVersion] = version; - sign( - st, - HashPrefix::manifest, - KeyType::ed25519, - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, KeyType::ed25519, sk, sfMasterSignature); sign(st, HashPrefix::manifest, KeyType::secp256k1, ssk); Serializer s; @@ -604,35 +476,18 @@ public: void testManifestDeserialization() { - std::array const keyTypes{ - {KeyType::ed25519, KeyType::secp256k1}}; + std::array const keyTypes{{KeyType::ed25519, KeyType::secp256k1}}; std::uint32_t sequence = 0; // public key with invalid type - std::array const badKey{ - 0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B, - 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6, - 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20}; + std::array const badKey{0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B, + 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6, + 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20}; // Short public key: std::array const shortKey{ - 0x03, - 0x30, - 0xE7, - 0xFC, - 0x9D, - 0x56, - 0xBB, - 0x25, - 0xD6, - 0x89, - 0x3B, - 0xA3, - 0xF3, - 0x17, - 0xAE, - 0x5B}; + 0x03, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B, 0xA3, 0xF3, 0x17, 0xAE, 0x5B}; auto toString = [](STObject const& st) { Serializer s; @@ -651,42 +506,34 @@ public: auto const ssk = generateSecretKey(sKeyType, randomSeed()); auto const spk = derivePublicKey(sKeyType, ssk); - auto buildManifestObject = - [&](std::uint32_t seq, - std::optional domain, - bool noSigningPublic = false, - bool noSignature = false) { - STObject st(sfGeneric); - st[sfSequence] = seq; - st[sfPublicKey] = pk; + auto buildManifestObject = [&](std::uint32_t seq, + std::optional domain, + bool noSigningPublic = false, + bool noSignature = false) { + STObject st(sfGeneric); + st[sfSequence] = seq; + st[sfPublicKey] = pk; - if (domain) - st[sfDomain] = makeSlice(*domain); + if (domain) + st[sfDomain] = makeSlice(*domain); - if (!noSigningPublic) - st[sfSigningPubKey] = spk; + if (!noSigningPublic) + st[sfSigningPubKey] = spk; - sign( - st, - HashPrefix::manifest, - keyType, - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, keyType, sk, sfMasterSignature); - if (!noSignature) - sign(st, HashPrefix::manifest, sKeyType, ssk); + if (!noSignature) + sign(st, HashPrefix::manifest, sKeyType, ssk); - return st; - }; + return st; + }; { - testcase << "deserializeManifest: normal manifest (" - << to_string(keyType) << " + " + testcase << "deserializeManifest: normal manifest (" << to_string(keyType) << " + " << to_string(sKeyType) << ")"; { // valid manifest without domain - auto const st = - buildManifestObject(++sequence, std::nullopt); + auto const st = buildManifestObject(++sequence, std::nullopt); auto const m = toString(st); auto const manifest = deserializeManifest(m); @@ -701,32 +548,27 @@ public: } { // invalid manifest (empty domain) - auto const st = - buildManifestObject(++sequence, std::string{}); + auto const st = buildManifestObject(++sequence, std::string{}); BEAST_EXPECT(!deserializeManifest(toString(st))); } { // invalid manifest (domain too short) - auto const st = - buildManifestObject(++sequence, std::string{"a.b"}); + auto const st = buildManifestObject(++sequence, std::string{"a.b"}); BEAST_EXPECT(!deserializeManifest(toString(st))); } { // invalid manifest (domain too long) std::string s(254, 'a'); - auto const st = - buildManifestObject(++sequence, s + ".example.com"); + auto const st = buildManifestObject(++sequence, s + ".example.com"); BEAST_EXPECT(!deserializeManifest(toString(st))); } { // invalid manifest (domain component too long) std::string s(72, 'a'); - auto const st = - buildManifestObject(++sequence, s + ".example.com"); + auto const st = buildManifestObject(++sequence, s + ".example.com"); BEAST_EXPECT(!deserializeManifest(toString(st))); } - auto const st = buildManifestObject( - ++sequence, std::string{"example.com"}); + auto const st = buildManifestObject(++sequence, std::string{"example.com"}); { // valid manifest with domain @@ -818,12 +660,7 @@ public: st[sfPublicKey] = pk; st[sfSigningPubKey] = pk; - sign( - st, - HashPrefix::manifest, - keyType, - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, keyType, sk, sfMasterSignature); sign(st, HashPrefix::manifest, sKeyType, sk); @@ -832,17 +669,13 @@ public: } { - testcase << "deserializeManifest: revocation manifest (" - << to_string(keyType) << " + " + testcase << "deserializeManifest: revocation manifest (" << to_string(keyType) << " + " << to_string(sKeyType) << ")"; // valid revocation { - auto const st = buildManifestObject( - std::numeric_limits::max(), - std::nullopt, - true, - true); + auto const st = + buildManifestObject(std::numeric_limits::max(), std::nullopt, true, true); auto const m = toString(st); auto const manifest = deserializeManifest(m); @@ -860,29 +693,20 @@ public: } { // can't specify an ephemeral signing key - auto const st = buildManifestObject( - std::numeric_limits::max(), - std::nullopt, - true, - false); + auto const st = + buildManifestObject(std::numeric_limits::max(), std::nullopt, true, false); BEAST_EXPECT(!deserializeManifest(toString(st))); } { // can't specify an ephemeral signature - auto const st = buildManifestObject( - std::numeric_limits::max(), - std::nullopt, - false, - true); + auto const st = + buildManifestObject(std::numeric_limits::max(), std::nullopt, false, true); BEAST_EXPECT(!deserializeManifest(toString(st))); } { // can't specify an ephemeral key & signature - auto const st = buildManifestObject( - std::numeric_limits::max(), - std::nullopt, - false, - false); + auto const st = + buildManifestObject(std::numeric_limits::max(), std::nullopt, false, false); BEAST_EXPECT(!deserializeManifest(toString(st))); } @@ -909,19 +733,13 @@ public: st[sfDomain] = makeSlice(domain); st[sfSigningPubKey] = pk2; - sign( - st, - HashPrefix::manifest, - KeyType::secp256k1, - sk1, - sfMasterSignature); + sign(st, HashPrefix::manifest, KeyType::secp256k1, sk1, sfMasterSignature); sign(st, HashPrefix::manifest, KeyType::secp256k1, sk2); Serializer s; st.add(s); - return deserializeManifest( - std::string(static_cast(s.data()), s.size())); + return deserializeManifest(std::string(static_cast(s.data()), s.size())); }; BEAST_EXPECT(test("example.com")); @@ -972,9 +790,7 @@ public: BEAST_EXPECT(!test(std::string(64, 'a') + "." + std::string(64, 'b'))); // Overall too long: - BEAST_EXPECT(!test( - std::string(63, 'a') + "." + std::string(63, 'b') + - ".example.com")); + BEAST_EXPECT(!test(std::string(63, 'a') + "." + std::string(63, 'b') + ".example.com")); } void @@ -988,20 +804,16 @@ public: auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a); auto const kp_a0 = randomKeyPair(KeyType::secp256k1); auto const kp_a1 = randomKeyPair(KeyType::secp256k1); - auto const s_a0 = makeManifest( - sk_a, KeyType::ed25519, kp_a0.second, KeyType::secp256k1, 0); - auto const s_a1 = makeManifest( - sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 1); - auto const s_a2 = makeManifest( - sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 2); + auto const s_a0 = makeManifest(sk_a, KeyType::ed25519, kp_a0.second, KeyType::secp256k1, 0); + auto const s_a1 = makeManifest(sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 1); + auto const s_a2 = makeManifest(sk_a, KeyType::ed25519, kp_a1.second, KeyType::secp256k1, 2); auto const s_aMax = makeRevocation(sk_a, KeyType::ed25519); auto const sk_b = randomSecretKey(); auto const kp_b0 = randomKeyPair(KeyType::secp256k1); auto const kp_b1 = randomKeyPair(KeyType::secp256k1); auto const kp_b2 = randomKeyPair(KeyType::secp256k1); - auto const s_b0 = makeManifest( - sk_b, KeyType::ed25519, kp_b0.second, KeyType::secp256k1, 0); + auto const s_b0 = makeManifest(sk_b, KeyType::ed25519, kp_b0.second, KeyType::secp256k1, 0); auto const s_b1 = makeManifest( sk_b, KeyType::ed25519, @@ -1009,70 +821,45 @@ public: KeyType::secp256k1, 1, true); // invalidSig - auto const s_b2 = makeManifest( - sk_b, KeyType::ed25519, kp_b2.second, KeyType::ed25519, 2); + auto const s_b2 = makeManifest(sk_b, KeyType::ed25519, kp_b2.second, KeyType::ed25519, 2); auto const fake = s_b2.serialized + '\0'; // applyManifest should accept new manifests with // higher sequence numbers - BEAST_EXPECT( - cache.applyManifest(clone(s_a0)) == - ManifestDisposition::accepted); - BEAST_EXPECT( - cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); + auto const seq0 = cache.sequence(); + BEAST_EXPECT(cache.applyManifest(clone(s_a0)) == ManifestDisposition::accepted); + BEAST_EXPECT(cache.sequence() > seq0); - BEAST_EXPECT( - cache.applyManifest(clone(s_a1)) == - ManifestDisposition::accepted); - BEAST_EXPECT( - cache.applyManifest(clone(s_a1)) == ManifestDisposition::stale); - BEAST_EXPECT( - cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); + auto const seq1 = cache.sequence(); + BEAST_EXPECT(cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.sequence() == seq1); - BEAST_EXPECT( - cache.applyManifest(clone(s_a2)) == - ManifestDisposition::badEphemeralKey); + BEAST_EXPECT(cache.applyManifest(clone(s_a1)) == ManifestDisposition::accepted); + BEAST_EXPECT(cache.applyManifest(clone(s_a1)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); + + BEAST_EXPECT(cache.applyManifest(clone(s_a2)) == ManifestDisposition::badEphemeralKey); // applyManifest should accept manifests with max sequence numbers // that revoke the master public key BEAST_EXPECT(!cache.revoked(pk_a)); BEAST_EXPECT(s_aMax.revoked()); - BEAST_EXPECT( - cache.applyManifest(clone(s_aMax)) == - ManifestDisposition::accepted); - BEAST_EXPECT( - cache.applyManifest(clone(s_aMax)) == - ManifestDisposition::stale); - BEAST_EXPECT( - cache.applyManifest(clone(s_a1)) == ManifestDisposition::stale); - BEAST_EXPECT( - cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.applyManifest(clone(s_aMax)) == ManifestDisposition::accepted); + BEAST_EXPECT(cache.applyManifest(clone(s_aMax)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.applyManifest(clone(s_a1)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.applyManifest(clone(s_a0)) == ManifestDisposition::stale); BEAST_EXPECT(cache.revoked(pk_a)); // applyManifest should reject manifests with invalid signatures - BEAST_EXPECT( - cache.applyManifest(clone(s_b0)) == - ManifestDisposition::accepted); - BEAST_EXPECT( - cache.applyManifest(clone(s_b0)) == ManifestDisposition::stale); + BEAST_EXPECT(cache.applyManifest(clone(s_b0)) == ManifestDisposition::accepted); + BEAST_EXPECT(cache.applyManifest(clone(s_b0)) == ManifestDisposition::stale); BEAST_EXPECT(!deserializeManifest(fake)); - BEAST_EXPECT( - cache.applyManifest(clone(s_b1)) == - ManifestDisposition::invalid); - BEAST_EXPECT( - cache.applyManifest(clone(s_b2)) == - ManifestDisposition::accepted); + BEAST_EXPECT(cache.applyManifest(clone(s_b1)) == ManifestDisposition::invalid); + BEAST_EXPECT(cache.applyManifest(clone(s_b2)) == ManifestDisposition::accepted); - auto const s_c0 = makeManifest( - kp_b2.second, - KeyType::ed25519, - randomSecretKey(), - KeyType::ed25519, - 47); - BEAST_EXPECT( - cache.applyManifest(clone(s_c0)) == - ManifestDisposition::badMasterKey); + auto const s_c0 = makeManifest(kp_b2.second, KeyType::ed25519, randomSecretKey(), KeyType::ed25519, 47); + BEAST_EXPECT(cache.applyManifest(clone(s_c0)) == ManifestDisposition::badMasterKey); } testLoadStore(cache); @@ -1085,7 +872,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Manifest, app, ripple); +BEAST_DEFINE_TESTSUITE(Manifest, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/MultiSign_test.cpp b/src/test/app/MultiSign_test.cpp index 776e163cd4..3d732ee2e0 100644 --- a/src/test/app/MultiSign_test.cpp +++ b/src/test/app/MultiSign_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -22,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class MultiSign_test : public beast::unit_test::suite @@ -71,60 +54,47 @@ public: Env env{*this, features}; Account const alice{"alice", KeyType::secp256k1}; - // The reserve required for a signer list changes with the passage - // of featureMultiSignReserve. Make the required adjustments. - bool const reserve1{features[featureMultiSignReserve]}; - // Pay alice enough to meet the initial reserve, but not enough to // meet the reserve for a SignerListSet. auto const fee = env.current()->fees().base; - auto const smallSignersReserve = reserve1 ? XRP(250) : XRP(350); - env.fund(smallSignersReserve - drops(1), alice); + env.fund(XRP(250) - drops(1), alice); env.close(); env.require(owners(alice, 0)); { // Attach a signer list to alice. Should fail. - Json::Value smallSigners = signers(alice, 1, {{bogie, 1}}); - env(smallSigners, ter(tecINSUFFICIENT_RESERVE)); + Json::Value signersList = signers(alice, 1, {{bogie, 1}}); + env(signersList, ter(tecINSUFFICIENT_RESERVE)); env.close(); env.require(owners(alice, 0)); // Fund alice enough to set the signer list, then attach signers. env(pay(env.master, alice, fee + drops(1))); env.close(); - env(smallSigners); + env(signersList); env.close(); - env.require(owners(alice, reserve1 ? 1 : 3)); + env.require(owners(alice, 1)); } { // Pay alice enough to almost make the reserve for the biggest // possible list. - auto const addReserveBigSigners = reserve1 ? XRP(0) : XRP(350); - env(pay(env.master, alice, addReserveBigSigners + fee - drops(1))); + env(pay(env.master, alice, fee - drops(1))); // Replace with the biggest possible signer list. Should fail. Json::Value bigSigners = signers( alice, 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}}); + {{bogie, 1}, {demon, 1}, {ghost, 1}, {haunt, 1}, {jinni, 1}, {phase, 1}, {shade, 1}, {spook, 1}}); env(bigSigners, ter(tecINSUFFICIENT_RESERVE)); env.close(); - env.require(owners(alice, reserve1 ? 1 : 3)); + env.require(owners(alice, 1)); // Fund alice one more drop (plus the fee) and succeed. env(pay(env.master, alice, fee + drops(1))); env.close(); env(bigSigners); env.close(); - env.require(owners(alice, reserve1 ? 1 : 10)); + env.require(owners(alice, 1)); } // Remove alice's signer list and get the owner count back. env(signers(alice, jtx::none)); @@ -159,14 +129,7 @@ public: env(signers( alice, 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {demon, 1}, - {spook, 1}}), + {{bogie, 1}, {demon, 1}, {ghost, 1}, {haunt, 1}, {jinni, 1}, {phase, 1}, {demon, 1}, {spook, 1}}), ter(temBAD_SIGNER)); // Set a quorum of zero. Should fail. @@ -176,25 +139,16 @@ public: env(signers( alice, 9, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}}), + {{bogie, 1}, {demon, 1}, {ghost, 1}, {haunt, 1}, {jinni, 1}, {phase, 1}, {shade, 1}, {spook, 1}}), ter(temBAD_QUORUM)); // clang-format off - // Make a signer list that's too big. Should fail. (Even with - // ExpandedSignerList) + // Make a signer list that's too big. Should fail. Account const spare("spare", KeyType::secp256k1); env(signers( alice, 1, - features[featureExpandedSignerList] - ? std::vector{{bogie, 1}, {demon, 1}, {ghost, 1}, + std::vector{{bogie, 1}, {demon, 1}, {ghost, 1}, {haunt, 1}, {jinni, 1}, {phase, 1}, {shade, 1}, {spook, 1}, {spare, 1}, {acc10, 1}, {acc11, 1}, {acc12, 1}, @@ -204,10 +158,7 @@ public: {acc22, 1}, {acc23, 1}, {acc24, 1}, {acc25, 1}, {acc26, 1}, {acc27, 1}, {acc28, 1}, {acc29, 1}, {acc30, 1}, - {acc31, 1}, {acc32, 1}, {acc33, 1}} - : std::vector{{bogie, 1}, {demon, 1}, {ghost, 1}, - {haunt, 1}, {jinni, 1}, {phase, 1}, - {shade, 1}, {spook, 1}, {spare, 1}}), + {acc31, 1}, {acc32, 1}, {acc33, 1}}), ter(temMALFORMED)); // clang-format on env.close(); @@ -228,7 +179,7 @@ public: // Attach phantom signers to alice and use them for a transaction. env(signers(alice, 1, {{bogie, 1}, {demon, 1}})); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4)); + env.require(owners(alice, 1)); // This should work. auto const baseFee = env.current()->fees().base; @@ -253,17 +204,13 @@ public: env(noop(alice), msig(demon, demon), fee(3 * baseFee), - rpc("invalidTransaction", - "fails local checks: Duplicate Signers not allowed.")); + rpc("invalidTransaction", "fails local checks: Duplicate Signers not allowed.")); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); // A non-signer should fail. aliceSeq = env.seq(alice); - env(noop(alice), - msig(bogie, spook), - fee(3 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop(alice), msig(bogie, spook), fee(3 * baseFee), ter(tefBAD_SIGNATURE)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -296,16 +243,9 @@ public: env(signers( alice, 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}})); + {{bogie, 1}, {demon, 1}, {ghost, 1}, {haunt, 1}, {jinni, 1}, {phase, 1}, {shade, 1}, {spook, 1}})); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 10)); + env.require(owners(alice, 1)); // This should work. auto const baseFee = env.current()->fees().base; @@ -317,19 +257,14 @@ public: // This should fail because the fee is too small. aliceSeq = env.seq(alice); - env(noop(alice), - msig(bogie), - fee((2 * baseFee) - 1), - ter(telINSUF_FEE_P)); + env(noop(alice), msig(bogie), fee((2 * baseFee) - 1), ter(telINSUF_FEE_P)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); // This should work. aliceSeq = env.seq(alice); - env(noop(alice), - msig(bogie, demon, ghost, haunt, jinni, phase, shade, spook), - fee(9 * baseFee)); + env(noop(alice), msig(bogie, demon, ghost, haunt, jinni, phase, shade, spook), fee(9 * baseFee)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); @@ -360,15 +295,12 @@ public: // Make sure the transaction fails if they are not. env(signers(alice, 1, {{bogie, 1}, {demon, 1}})); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4)); + env.require(owners(alice, 1)); msig phantoms{bogie, demon}; std::reverse(phantoms.signers.begin(), phantoms.signers.end()); std::uint32_t const aliceSeq = env.seq(alice); - env(noop(alice), - phantoms, - rpc("invalidTransaction", - "fails local checks: Unsorted Signers array.")); + env(noop(alice), phantoms, rpc("invalidTransaction", "fails local checks: Unsorted Signers array.")); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); } @@ -399,7 +331,7 @@ public: // Attach signers to alice env(signers(alice, 4, {{becky, 3}, {cheri, 4}}), sig(alice)); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4)); + env.require(owners(alice, 1)); // Attempt a multisigned transaction that meets the quorum. auto const baseFee = env.current()->fees().base; @@ -466,10 +398,7 @@ public: // cheri should not be able to multisign using her master key. aliceSeq = env.seq(alice); - env(noop(alice), - msig(cheri), - fee(2 * baseFee), - ter(tefMASTER_DISABLED)); + env(noop(alice), msig(cheri), fee(2 * baseFee), ter(tefMASTER_DISABLED)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -486,9 +415,7 @@ public: // Both becky and cheri should be able to sign using regular keys. aliceSeq = env.seq(alice); - env(noop(alice), - fee(3 * baseFee), - msig(Reg{becky, beck}, Reg{cheri, cher})); + env(noop(alice), fee(3 * baseFee), msig(Reg{becky, beck}, Reg{cheri, cher})); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); } @@ -555,8 +482,7 @@ public: aliceSeq = env.seq(alice); Json::Value jv_one = setup_tx(); cheri_sign(jv_one); - auto jrr = - env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; + auto jrr = env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); // for the second sign_for, use the returned tx_json with @@ -569,10 +495,7 @@ public: Json::Value jv_submit; jv_submit[jss::tx_json] = jrr[jss::tx_json]; - jrr = env.rpc( - "json", - "submit_multisigned", - to_string(jv_submit))[jss::result]; + jrr = env.rpc("json", "submit_multisigned", to_string(jv_submit))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); @@ -582,16 +505,12 @@ public: // failure case -- SigningPubKey not empty aliceSeq = env.seq(alice); Json::Value jv_one = setup_tx(); - jv_one[jss::tx_json][jss::SigningPubKey] = - strHex(alice.pk().slice()); + jv_one[jss::tx_json][jss::SigningPubKey] = strHex(alice.pk().slice()); cheri_sign(jv_one); - auto jrr = - env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; + auto jrr = env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "When multi-signing 'tx_json.SigningPubKey' must be empty."); + BEAST_EXPECT(jrr[jss::error_message] == "When multi-signing 'tx_json.SigningPubKey' must be empty."); } { @@ -600,8 +519,7 @@ public: Json::Value jv_one = setup_tx(); jv_one[jss::tx_json][jss::Fee] = -1; cheri_sign(jv_one); - auto jrr = - env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; + auto jrr = env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); // for the second sign_for, use the returned tx_json with @@ -614,26 +532,19 @@ public: Json::Value jv_submit; jv_submit[jss::tx_json] = jrr[jss::tx_json]; - jrr = env.rpc( - "json", - "submit_multisigned", - to_string(jv_submit))[jss::result]; + jrr = env.rpc("json", "submit_multisigned", to_string(jv_submit))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid Fee field. Fees must be greater than zero."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid Fee field. Fees must be greater than zero."); } { // failure case - bad fee v2 aliceSeq = env.seq(alice); Json::Value jv_one = setup_tx(); - jv_one[jss::tx_json][jss::Fee] = - alice["USD"](10).value().getFullText(); + jv_one[jss::tx_json][jss::Fee] = alice["USD"](10).value().getFullText(); cheri_sign(jv_one); - auto jrr = - env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; + auto jrr = env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); // for the second sign_for, use the returned tx_json with @@ -646,10 +557,7 @@ public: Json::Value jv_submit; jv_submit[jss::tx_json] = jrr[jss::tx_json]; - jrr = env.rpc( - "json", - "submit_multisigned", - to_string(jv_submit))[jss::result]; + jrr = env.rpc("json", "submit_multisigned", to_string(jv_submit))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error] == "internal"); BEAST_EXPECT(jrr[jss::error_message] == "Internal error."); @@ -674,8 +582,7 @@ public: aliceSeq = env.seq(alice); Json::Value jv_one = setup_tx(); cheri_sign(jv_one); - auto jrr = - env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; + auto jrr = env.rpc("json", "sign_for", to_string(jv_one))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); // for the second sign_for, use the returned tx_json with @@ -690,10 +597,7 @@ public: Json::Value jv_submit; jv_submit[jss::tx_json] = jrr[jss::tx_json]; - jrr = env.rpc( - "json", - "submit_multisigned", - to_string(jv_submit))[jss::result]; + jrr = env.rpc("json", "submit_multisigned", to_string(jv_submit))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); @@ -718,16 +622,12 @@ public: { aliceSeq = env.seq(alice); Json::Value jv = setup_tx(); - jv[jss::tx_json][sfSigners.fieldName] = - Json::Value{Json::arrayValue}; + jv[jss::tx_json][sfSigners.fieldName] = Json::Value{Json::arrayValue}; becky_sign(jv); - auto jrr = env.rpc( - "json", "submit_multisigned", to_string(jv))[jss::result]; + auto jrr = env.rpc("json", "submit_multisigned", to_string(jv))[jss::result]; BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "tx_json.Signers array may not be empty."); + BEAST_EXPECT(jrr[jss::error_message] == "tx_json.Signers array may not be empty."); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); } @@ -736,7 +636,7 @@ public: void testHeterogeneousSigners(FeatureBitset features) { - testcase("Heterogenious Signers"); + testcase("Heterogeneous Signers"); using namespace jtx; Env env{*this, features}; @@ -765,10 +665,9 @@ public: env.close(); // Attach signers to alice. - env(signers(alice, 1, {{becky, 1}, {cheri, 1}, {daria, 1}, {jinni, 1}}), - sig(alie)); + env(signers(alice, 1, {{becky, 1}, {cheri, 1}, {daria, 1}, {jinni, 1}}), sig(alie)); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 6)); + env.require(owners(alice, 1)); // Each type of signer should succeed individually. auto const baseFee = env.current()->fees().base; @@ -799,36 +698,23 @@ public: // Should also work if all signers sign. aliceSeq = env.seq(alice); - env(noop(alice), - fee(5 * baseFee), - msig(becky, Reg{cheri, cher}, Reg{daria, dari}, jinni)); + env(noop(alice), fee(5 * baseFee), msig(becky, Reg{cheri, cher}, Reg{daria, dari}, jinni)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // Require all signers to sign. - env(signers( - alice, - 0x3FFFC, - {{becky, 0xFFFF}, - {cheri, 0xFFFF}, - {daria, 0xFFFF}, - {jinni, 0xFFFF}}), - sig(alie)); + env(signers(alice, 0x3FFFC, {{becky, 0xFFFF}, {cheri, 0xFFFF}, {daria, 0xFFFF}, {jinni, 0xFFFF}}), sig(alie)); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 6)); + env.require(owners(alice, 1)); aliceSeq = env.seq(alice); - env(noop(alice), - fee(9 * baseFee), - msig(becky, Reg{cheri, cher}, Reg{daria, dari}, jinni)); + env(noop(alice), fee(9 * baseFee), msig(becky, Reg{cheri, cher}, Reg{daria, dari}, jinni)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // Try cheri with both key types. aliceSeq = env.seq(alice); - env(noop(alice), - fee(5 * baseFee), - msig(becky, cheri, Reg{daria, dari}, jinni)); + env(noop(alice), fee(5 * baseFee), msig(becky, cheri, Reg{daria, dari}, jinni)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); @@ -846,29 +732,18 @@ public: {spook, 0xFFFF}}), sig(alie)); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 10)); + env.require(owners(alice, 1)); aliceSeq = env.seq(alice); env(noop(alice), fee(9 * baseFee), - msig( - becky, - Reg{cheri, cher}, - Reg{daria, dari}, - haunt, - jinni, - phase, - shade, - spook)); + msig(becky, Reg{cheri, cher}, Reg{daria, dari}, haunt, jinni, phase, shade, spook)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // One signer short should fail. aliceSeq = env.seq(alice); - env(noop(alice), - msig(becky, cheri, haunt, jinni, phase, shade, spook), - fee(8 * baseFee), - ter(tefBAD_QUORUM)); + env(noop(alice), msig(becky, cheri, haunt, jinni, phase, shade, spook), fee(8 * baseFee), ter(tefBAD_QUORUM)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -908,9 +783,7 @@ public: // Master key tests. // M0: A lone master key cannot be disabled. - env(fset(alice, asfDisableMaster), - sig(alice), - ter(tecNO_ALTERNATIVE_KEY)); + env(fset(alice, asfDisableMaster), sig(alice), ter(tecNO_ALTERNATIVE_KEY)); // Add a regular key. Account const alie{"alie", KeyType::ed25519}; @@ -930,10 +803,7 @@ public: // L0: A lone signer list cannot be removed. auto const baseFee = env.current()->fees().base; - env(signers(alice, jtx::none), - msig(bogie), - fee(2 * baseFee), - ter(tecNO_ALTERNATIVE_KEY)); + env(signers(alice, jtx::none), msig(bogie), fee(2 * baseFee), ter(tecNO_ALTERNATIVE_KEY)); // Enable the master key. env(fclear(alice, asfDisableMaster), msig(bogie), fee(2 * baseFee)); @@ -1022,15 +892,12 @@ public: // Attach signers to alice. env(signers(alice, 2, {{becky, 1}, {bogie, 1}}), sig(alie)); env.close(); - int const signerListOwners{features[featureMultiSignReserve] ? 1 : 4}; - env.require(owners(alice, signerListOwners + 0)); + env.require(owners(alice, 1)); // Multisign a ttPAYMENT. auto const baseFee = env.current()->fees().base; std::uint32_t aliceSeq = env.seq(alice); - env(pay(alice, env.master, XRP(1)), - msig(becky, bogie), - fee(3 * baseFee)); + env(pay(alice, env.master, XRP(1)), msig(becky, bogie), fee(3 * baseFee)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); @@ -1048,12 +915,9 @@ public: BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // Multisign a ttTRUST_SET - env(trust("alice", USD(100)), - msig(becky, bogie), - fee(3 * baseFee), - require(lines("alice", 1))); + env(trust("alice", USD(100)), msig(becky, bogie), fee(3 * baseFee), require(lines("alice", 1))); env.close(); - env.require(owners(alice, signerListOwners + 1)); + env.require(owners(alice, 2)); // Multisign a ttOFFER_CREATE transaction. env(pay(gw, alice, USD(50))); @@ -1062,30 +926,23 @@ public: env.require(balance(gw, alice["USD"](-50))); std::uint32_t const offerSeq = env.seq(alice); - env(offer(alice, XRP(50), USD(50)), - msig(becky, bogie), - fee(3 * baseFee)); + env(offer(alice, XRP(50), USD(50)), msig(becky, bogie), fee(3 * baseFee)); env.close(); - env.require(owners(alice, signerListOwners + 2)); + env.require(owners(alice, 3)); // Now multisign a ttOFFER_CANCEL canceling the offer we just created. { aliceSeq = env.seq(alice); - env(offer_cancel(alice, offerSeq), - seq(aliceSeq), - msig(becky, bogie), - fee(3 * baseFee)); + env(offer_cancel(alice, offerSeq), seq(aliceSeq), msig(becky, bogie), fee(3 * baseFee)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); - env.require(owners(alice, signerListOwners + 1)); + env.require(owners(alice, 2)); } // Multisign a ttSIGNER_LIST_SET. - env(signers(alice, 3, {{becky, 1}, {bogie, 1}, {demon, 1}}), - msig(becky, bogie), - fee(3 * baseFee)); + env(signers(alice, 3, {{becky, 1}, {bogie, 1}, {demon, 1}}), msig(becky, bogie), fee(3 * baseFee)); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 2 : 6)); + env.require(owners(alice, 2)); } void @@ -1117,9 +974,7 @@ public: STTx local = *(tx.stx); local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Empty SigningPubKey."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Empty SigningPubKey."); } { // Single-sign, but invalidate the signature. @@ -1131,9 +986,7 @@ public: local.setFieldVL(sfTxnSignature, badSig); // Signature should fail. auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Invalid signature."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Invalid signature."); } { // Single-sign, but invalidate the sequence number. @@ -1144,9 +997,7 @@ public: local.setFieldU32(sfSequence, seq + 1); // Signature should fail. auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Invalid signature."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Invalid signature."); } { // Multisign, but leave a nonempty sfSigningPubKey. @@ -1155,8 +1006,7 @@ public: local[sfSigningPubKey] = alice.pk(); // Insert sfSigningPubKey auto const info = submitSTTx(local); BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Cannot both single- and multi-sign."); + info[jss::result][jss::error_exception] == "fails local checks: Cannot both single- and multi-sign."); } { // Both multi- and single-sign with an empty SigningPubKey. @@ -1166,8 +1016,7 @@ public: local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey auto const info = submitSTTx(local); BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Cannot both single- and multi-sign."); + info[jss::result][jss::error_exception] == "fails local checks: Cannot both single- and multi-sign."); } { // Multisign but invalidate one of the signatures. @@ -1181,8 +1030,8 @@ public: // Signature should fail. auto const info = submitSTTx(local); BEAST_EXPECT( - info[jss::result][jss::error_exception].asString().find( - "Invalid signature on account r") != std::string::npos); + info[jss::result][jss::error_exception].asString().find("Invalid signature on account r") != + std::string::npos); } { // Multisign with an empty signers array should fail. @@ -1190,75 +1039,57 @@ public: STTx local = *(tx.stx); local.peekFieldArray(sfSigners).clear(); // Empty Signers array. auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Invalid Signers array size."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Invalid Signers array size."); } { - // Multisign 9 (!ExpandedSignerList) | 33 (ExpandedSignerList) times - // should fail. JTx tx = env.jt( noop(alice), fee(2 * baseFee), - features[featureExpandedSignerList] ? msig( - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie) - : msig( - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie, - bogie)); + msig( + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie, + bogie)); STTx local = *(tx.stx); auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Invalid Signers array size."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Invalid Signers array size."); } { // The account owner may not multisign for themselves. JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(alice)); STTx local = *(tx.stx); auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Invalid multisigner."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Invalid multisigner."); } { // No duplicate multisignatures allowed. @@ -1266,8 +1097,7 @@ public: STTx local = *(tx.stx); auto const info = submitSTTx(local); BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Duplicate Signers not allowed."); + info[jss::result][jss::error_exception] == "fails local checks: Duplicate Signers not allowed."); } { // Multisignatures must be submitted in sorted order. @@ -1278,9 +1108,7 @@ public: std::reverse(signers.begin(), signers.end()); // Signature should fail. auto const info = submitSTTx(local); - BEAST_EXPECT( - info[jss::result][jss::error_exception] == - "fails local checks: Unsorted Signers array."); + BEAST_EXPECT(info[jss::result][jss::error_exception] == "fails local checks: Unsorted Signers array."); } } @@ -1297,10 +1125,7 @@ public: env.close(); auto const baseFee = env.current()->fees().base; - env(noop(alice), - msig(becky, demon), - fee(3 * baseFee), - ter(tefNOT_MULTI_SIGNING)); + env(noop(alice), msig(becky, demon), fee(3 * baseFee), ter(tefNOT_MULTI_SIGNING)); } void @@ -1340,27 +1165,18 @@ public: // Since becky's master key is disabled she can no longer // multisign for alice. - env(noop(alice), - msig(becky), - fee(2 * baseFee), - ter(tefMASTER_DISABLED)); + env(noop(alice), msig(becky), fee(2 * baseFee), ter(tefMASTER_DISABLED)); env.close(); // Becky cannot 2-level multisign for alice. 2-level multisigning // is not supported. - env(noop(alice), - msig(Reg{becky, bogie}), - fee(2 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop(alice), msig(Reg{becky, bogie}), fee(2 * baseFee), ter(tefBAD_SIGNATURE)); env.close(); // Verify that becky cannot sign with a regular key that she has // not yet enabled. Account const beck{"beck", KeyType::ed25519}; - env(noop(alice), - msig(Reg{becky, beck}), - fee(2 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop(alice), msig(Reg{becky, beck}), fee(2 * baseFee), ter(tefBAD_SIGNATURE)); env.close(); // Once becky gives herself the regular key, she can sign for alice @@ -1373,10 +1189,7 @@ public: // The presence of becky's regular key does not influence whether she // can 2-level multisign; it still won't work. - env(noop(alice), - msig(Reg{becky, demon}), - fee(2 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop(alice), msig(Reg{becky, demon}), fee(2 * baseFee), ter(tefBAD_SIGNATURE)); env.close(); } @@ -1422,35 +1235,26 @@ public: BEAST_EXPECT(jvSig2[jss::result][jss::status].asString() == "success"); // Save the hash with one signature for use later. - std::string const hash1 = - jvSig2[jss::result][jss::tx_json][jss::hash].asString(); + std::string const hash1 = jvSig2[jss::result][jss::tx_json][jss::hash].asString(); // Add the next signature and sign again. jvSig2[jss::result][jss::account] = ghost.human(); jvSig2[jss::result][jss::secret] = ghost.name(); - Json::Value jvSubmit = - env.rpc("json", "sign_for", to_string(jvSig2[jss::result])); - BEAST_EXPECT( - jvSubmit[jss::result][jss::status].asString() == "success"); + Json::Value jvSubmit = env.rpc("json", "sign_for", to_string(jvSig2[jss::result])); + BEAST_EXPECT(jvSubmit[jss::result][jss::status].asString() == "success"); // Save the hash with two signatures for use later. - std::string const hash2 = - jvSubmit[jss::result][jss::tx_json][jss::hash].asString(); + std::string const hash2 = jvSubmit[jss::result][jss::tx_json][jss::hash].asString(); BEAST_EXPECT(hash1 != hash2); // Submit the result of the two signatures. - Json::Value jvResult = env.rpc( - "json", "submit_multisigned", to_string(jvSubmit[jss::result])); - BEAST_EXPECT( - jvResult[jss::result][jss::status].asString() == "success"); - BEAST_EXPECT( - jvResult[jss::result][jss::engine_result].asString() == - "tesSUCCESS"); + Json::Value jvResult = env.rpc("json", "submit_multisigned", to_string(jvSubmit[jss::result])); + BEAST_EXPECT(jvResult[jss::result][jss::status].asString() == "success"); + BEAST_EXPECT(jvResult[jss::result][jss::engine_result].asString() == "tesSUCCESS"); // The hash from the submit should be the same as the hash from the // second signing. - BEAST_EXPECT( - hash2 == jvResult[jss::result][jss::tx_json][jss::hash].asString()); + BEAST_EXPECT(hash2 == jvResult[jss::result][jss::tx_json][jss::hash].asString()); env.close(); // The transaction we just submitted should now be available and @@ -1458,104 +1262,7 @@ public: Json::Value jvTx = env.rpc("tx", hash2); BEAST_EXPECT(jvTx[jss::result][jss::status].asString() == "success"); BEAST_EXPECT(jvTx[jss::result][jss::validated].asString() == "true"); - BEAST_EXPECT( - jvTx[jss::result][jss::meta][sfTransactionResult.jsonName] - .asString() == "tesSUCCESS"); - } - - void - testAmendmentTransition() - { - testcase("Amendment Transition"); - - // The OwnerCount associated with a SignerList changes once the - // featureMultiSignReserve amendment goes live. Create a couple - // of signer lists before and after the amendment goes live and - // verify that the OwnerCount is managed properly for all of them. - using namespace jtx; - Account const alice{"alice", KeyType::secp256k1}; - Account const becky{"becky", KeyType::ed25519}; - Account const cheri{"cheri", KeyType::secp256k1}; - Account const daria{"daria", KeyType::ed25519}; - - Env env{*this, testable_amendments() - featureMultiSignReserve}; - env.fund(XRP(1000), alice, becky, cheri, daria); - env.close(); - - // Give alice and becky signer lists before the amendment goes live. - env(signers(alice, 1, {{bogie, 1}})); - env(signers( - becky, - 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}})); - env.close(); - - env.require(owners(alice, 3)); - env.require(owners(becky, 10)); - - // Enable the amendment. - env.enableFeature(featureMultiSignReserve); - env.close(); - - // Give cheri and daria signer lists after the amendment goes live. - env(signers(cheri, 1, {{bogie, 1}})); - env(signers( - daria, - 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}})); - env.close(); - - env.require(owners(alice, 3)); - env.require(owners(becky, 10)); - env.require(owners(cheri, 1)); - env.require(owners(daria, 1)); - - // Delete becky's signer list; her OwnerCount should drop to zero. - // Replace alice's signer list; her OwnerCount should drop to one. - env(signers(becky, jtx::none)); - env(signers( - alice, - 1, - {{bogie, 1}, - {demon, 1}, - {ghost, 1}, - {haunt, 1}, - {jinni, 1}, - {phase, 1}, - {shade, 1}, - {spook, 1}})); - env.close(); - - env.require(owners(alice, 1)); - env.require(owners(becky, 0)); - env.require(owners(cheri, 1)); - env.require(owners(daria, 1)); - - // Delete the three remaining signer lists. Everybody's OwnerCount - // should now be zero. - env(signers(alice, jtx::none)); - env(signers(cheri, jtx::none)); - env(signers(daria, jtx::none)); - env.close(); - - env.require(owners(alice, 0)); - env.require(owners(becky, 0)); - env.require(owners(cheri, 0)); - env.require(owners(daria, 0)); + BEAST_EXPECT(jvTx[jss::result][jss::meta][sfTransactionResult.jsonName].asString() == "tesSUCCESS"); } void @@ -1576,18 +1283,14 @@ public: std::uint32_t const aliceSeq = env.seq(alice); // Attach phantom signers to alice using a ticket. - env(signers(alice, 1, {{bogie, 1}, {demon, 1}}), - ticket::use(aliceTicketSeq++)); + env(signers(alice, 1, {{bogie, 1}, {demon, 1}}), ticket::use(aliceTicketSeq++)); env.close(); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); BEAST_EXPECT(env.seq(alice) == aliceSeq); // This should work. auto const baseFee = env.current()->fees().base; - env(noop(alice), - msig(bogie, demon), - fee(3 * baseFee), - ticket::use(aliceTicketSeq++)); + env(noop(alice), msig(bogie, demon), fee(3 * baseFee), ticket::use(aliceTicketSeq++)); env.close(); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -1602,9 +1305,6 @@ public: void testSignersWithTags(FeatureBitset features) { - if (!features[featureExpandedSignerList]) - return; - testcase("Signers With Tags"); using namespace jtx; @@ -1612,21 +1312,19 @@ public: Account const alice{"alice", KeyType::ed25519}; env.fund(XRP(1000), alice); env.close(); - uint8_t tag1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + uint8_t tag1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - uint8_t tag2[] = - "hello world some ascii 32b long"; // including 1 byte for NUL + uint8_t tag2[] = "hello world some ascii 32b long"; // including 1 byte for NUL - uint256 bogie_tag = ripple::base_uint<256>::fromVoid(tag1); - uint256 demon_tag = ripple::base_uint<256>::fromVoid(tag2); + uint256 bogie_tag = xrpl::base_uint<256>::fromVoid(tag1); + uint256 demon_tag = xrpl::base_uint<256>::fromVoid(tag2); // Attach phantom signers to alice and use them for a transaction. env(signers(alice, 1, {{bogie, 1, bogie_tag}, {demon, 1, demon_tag}})); env.close(); - env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4)); + env.require(owners(alice, 1)); // This should work. auto const baseFee = env.current()->fees().base; @@ -1651,17 +1349,13 @@ public: env(noop(alice), msig(demon, demon), fee(3 * baseFee), - rpc("invalidTransaction", - "fails local checks: Duplicate Signers not allowed.")); + rpc("invalidTransaction", "fails local checks: Duplicate Signers not allowed.")); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); // A non-signer should fail. aliceSeq = env.seq(alice); - env(noop(alice), - msig(bogie, spook), - fee(3 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop(alice), msig(bogie, spook), fee(3 * baseFee), ter(tefBAD_SIGNATURE)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -1691,14 +1385,10 @@ public: env.close(); bool const enabled = features[fixInvalidTxFlags]; - testcase( - std::string("SignerListSet flag, fix ") + - (enabled ? "enabled" : "disabled")); + testcase(std::string("SignerListSet flag, fix ") + (enabled ? "enabled" : "disabled")); ter const expected(enabled ? TER(temINVALID_FLAG) : TER(tesSUCCESS)); - env(signers(alice, 2, {{bogie, 1}, {ghost, 1}}), - expected, - txflags(tfPassive)); + env(signers(alice, 2, {{bogie, 1}, {ghost, 1}}), expected, txflags(tfPassive)); env.close(); } @@ -1761,12 +1451,6 @@ public: using namespace jtx; auto const all = testable_amendments(); - // The reserve required on a signer list changes based on - // featureMultiSignReserve. Limits on the number of signers - // changes based on featureExpandedSignerList. Test both with and - // without. - testAll(all - featureMultiSignReserve - featureExpandedSignerList); - testAll(all - featureExpandedSignerList); testAll(all); testSignerListSetFlags(all - fixInvalidTxFlags); @@ -1774,12 +1458,10 @@ public: testSignerListObject(all - fixIncludeKeyletFields); testSignerListObject(all); - - testAmendmentTransition(); } }; -BEAST_DEFINE_TESTSUITE(MultiSign, app, ripple); +BEAST_DEFINE_TESTSUITE(MultiSign, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/NFTokenAuth_test.cpp b/src/test/app/NFTokenAuth_test.cpp index f0d7cc3700..1e7afc9bb0 100644 --- a/src/test/app/NFTokenAuth_test.cpp +++ b/src/test/app/NFTokenAuth_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class NFTokenAuth_test : public beast::unit_test::suite { @@ -33,16 +14,12 @@ class NFTokenAuth_test : public beast::unit_test::suite uint32_t xfee = 0u) { using namespace test::jtx; - auto const nftID{ - token::getNextID(env, account, 0u, tfTransferable, xfee)}; - env(token::mint(account, 0), - token::xferFee(xfee), - txflags(tfTransferable)); + auto const nftID{token::getNextID(env, account, 0u, tfTransferable, xfee)}; + env(token::mint(account, 0), token::xferFee(xfee), txflags(tfTransferable)); env.close(); auto const sellIdx = keylet::nftoffer(account, env.seq(account)).key; - env(token::createOffer(account, nftID, currency), - txflags(tfSellNFToken)); + env(token::createOffer(account, nftID, currency), txflags(tfSellNFToken)); env.close(); return std::make_tuple(nftID, sellIdx); @@ -121,18 +98,14 @@ public: auto const [nftID, _] = mintAndOfferNFT(env, A2, drops(1)); // test: check that buyer can't make an offer if they're not authorized. - env(token::createOffer(A1, nftID, USD(10)), - token::owner(A2), - ter(tecUNFUNDED_OFFER)); + env(token::createOffer(A1, nftID, USD(10)), token::owner(A2), ter(tecUNFUNDED_OFFER)); env.close(); // Artificially create an unauthorized trustline with balance. Don't // close ledger before running the actual tests against this trustline. // After ledger is closed, the trustline will not exist. - auto const unauthTrustline = [&](OpenView& view, - beast::Journal) -> bool { - auto const sleA1 = - std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); + auto const unauthTrustline = [&](OpenView& view, beast::Journal) -> bool { + auto const sleA1 = std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); sleA1->setFieldAmount(sfBalance, A1["USD"](-1000)); view.rawInsert(sleA1); return true; @@ -142,9 +115,7 @@ public: if (features[fixEnforceNFTokenTrustlineV2]) { // test: check that buyer can't make an offer even with balance - env(token::createOffer(A1, nftID, USD(10)), - token::owner(A2), - ter(tecNO_AUTH)); + env(token::createOffer(A1, nftID, USD(10)), token::owner(A2), ter(tecNO_AUTH)); } else { @@ -196,10 +167,8 @@ public: // trustline with balance. Don't close ledger before running the actual // tests against this trustline. After ledger is closed, the trustline // will not exist. - auto const unauthTrustline = [&](OpenView& view, - beast::Journal) -> bool { - auto const sleA1 = - std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); + auto const unauthTrustline = [&](OpenView& view, beast::Journal) -> bool { + auto const sleA1 = std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); sleA1->setFieldAmount(sfBalance, A1["USD"](-1000)); view.rawInsert(sleA1); return true; @@ -241,15 +210,11 @@ public: { // test: can't create sell offer if there is no trustline but auth // required - env(token::createOffer(A2, nftID, USD(10)), - txflags(tfSellNFToken), - ter(tecNO_LINE)); + env(token::createOffer(A2, nftID, USD(10)), txflags(tfSellNFToken), ter(tecNO_LINE)); env(trust(A2, limit)); // test: can't create sell offer if not authorized to hold token - env(token::createOffer(A2, nftID, USD(10)), - txflags(tfSellNFToken), - ter(tecNO_AUTH)); + env(token::createOffer(A2, nftID, USD(10)), txflags(tfSellNFToken), ter(tecNO_AUTH)); // Authorizing trustline to make an offer creation possible env(trust(G1, USD(0), A2, tfSetfAuth)); @@ -322,10 +287,8 @@ public: env.close(); // Creating an artificial unauth trustline - auto const unauthTrustline = [&](OpenView& view, - beast::Journal) -> bool { - auto const sleA1 = - std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); + auto const unauthTrustline = [&](OpenView& view, beast::Journal) -> bool { + auto const sleA1 = std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); sleA1->setFieldAmount(sfBalance, A1["USD"](-1000)); view.rawInsert(sleA1); return true; @@ -372,9 +335,7 @@ public: if (features[fixEnforceNFTokenTrustlineV2]) { // test: G1 requires authorization of broker, no trust line exists - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecNO_LINE)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecNO_LINE)); env.close(); // trust line created, but not authorized @@ -382,9 +343,7 @@ public: env.close(); // test: G1 requires authorization of broker - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecNO_AUTH)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecNO_AUTH)); env.close(); // test: can still be brokered without broker fee. @@ -394,8 +353,7 @@ public: else { // Old behavior: broker can receive IOUs without the authorization - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1))); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1))); env.close(); BEAST_EXPECT(env.balance(broker, USD) == USD(1)); @@ -444,10 +402,8 @@ public: env(trust(A1, USD(0))); env.close(); - auto const unauthTrustline = [&](OpenView& view, - beast::Journal) -> bool { - auto const sleA1 = - std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); + auto const unauthTrustline = [&](OpenView& view, beast::Journal) -> bool { + auto const sleA1 = std::make_shared(keylet::line(A1, G1, G1["USD"].currency)); sleA1->setFieldAmount(sfBalance, A1["USD"](-1000)); view.rawInsert(sleA1); return true; @@ -457,9 +413,7 @@ public: if (features[fixEnforceNFTokenTrustlineV2]) { // test: G1 requires authorization of A2 - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecNO_AUTH)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecNO_AUTH)); env.close(); } } @@ -510,9 +464,7 @@ public: if (features[fixEnforceNFTokenTrustlineV2]) { // test: G1 requires authorization of broker, no trust line exists - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecNO_LINE)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecNO_LINE)); env.close(); // trust line created, but not authorized @@ -520,9 +472,7 @@ public: env.close(); // test: G1 requires authorization of A2 - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1)), - ter(tecNO_AUTH)); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(tecNO_AUTH)); env.close(); // test: cannot be brokered even without broker fee. @@ -532,8 +482,7 @@ public: else { // Old behavior: broker can receive IOUs without the authorization - env(token::brokerOffers(broker, buyIdx, sellIdx), - token::brokerFee(USD(1))); + env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1))); env.close(); BEAST_EXPECT(env.balance(A2, USD) == USD(10)); @@ -572,8 +521,7 @@ public: // We authorized A1 and A2, but not the minter. // Now mint NFT - auto const [nftID, minterSellIdx] = - mintAndOfferNFT(env, minter, drops(1), 1); + auto const [nftID, minterSellIdx] = mintAndOfferNFT(env, minter, drops(1), 1); env(token::acceptSellOffer(A1, minterSellIdx)); uint256 const sellIdx = keylet::nftoffer(A1, env.seq(A1)).key; @@ -601,8 +549,7 @@ public: using namespace test::jtx; static FeatureBitset const all{testable_amendments()}; - static std::array const features = { - all - fixEnforceNFTokenTrustlineV2, all}; + static std::array const features = {all - fixEnforceNFTokenTrustlineV2, all}; for (auto const feature : features) { @@ -619,6 +566,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, app, xrpl, 2); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index 75c88a06c9..915bb6ec79 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class NFTokenBurn_test : public beast::unit_test::suite { @@ -51,11 +32,8 @@ class NFTokenBurn_test : public beast::unit_test::suite size_t const tokenCancelCount) { using namespace test::jtx; - uint256 const nftokenID = - token::getNextID(env, owner, 0, tfTransferable); - env(token::mint(owner, 0), - token::uri(std::string(maxTokenURILength, 'u')), - txflags(tfTransferable)); + uint256 const nftokenID = token::getNextID(env, owner, 0, tfTransferable); + env(token::mint(owner, 0), token::uri(std::string(maxTokenURILength, 'u')), txflags(tfTransferable)); env.close(); offerIndexes.reserve(tokenCancelCount); @@ -64,8 +42,7 @@ class NFTokenBurn_test : public beast::unit_test::suite { // Create sell offer offerIndexes.push_back(keylet::nftoffer(owner, env.seq(owner)).key); - env(token::createOffer(owner, nftokenID, drops(1)), - txflags(tfSellNFToken)); + env(token::createOffer(owner, nftokenID, drops(1)), txflags(tfSellNFToken)); env.close(); } @@ -88,12 +65,10 @@ class NFTokenBurn_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); // Iterate the state and print all NFTokenPages. - if (!jrr.isMember(jss::result) || - !jrr[jss::result].isMember(jss::state)) + if (!jrr.isMember(jss::result) || !jrr[jss::result].isMember(jss::state)) { std::cout << "No ledger state found!" << std::endl; return; @@ -106,13 +81,10 @@ class NFTokenBurn_test : public beast::unit_test::suite } for (Json::UInt i = 0; i < state.size(); ++i) { - if (state[i].isMember(sfNFTokens.jsonName) && - state[i][sfNFTokens.jsonName].isArray()) + if (state[i].isMember(sfNFTokens.jsonName) && state[i][sfNFTokens.jsonName].isArray()) { - std::uint32_t tokenCount = - state[i][sfNFTokens.jsonName].size(); - std::cout << tokenCount << " NFtokens in page " - << state[i][jss::index].asString() << std::endl; + std::uint32_t tokenCount = state[i][sfNFTokens.jsonName].size(); + std::cout << tokenCount << " NFtokens in page " << state[i][jss::index].asString() << std::endl; if (vol == noisy) { @@ -121,16 +93,10 @@ class NFTokenBurn_test : public beast::unit_test::suite else { if (tokenCount > 0) - std::cout << "first: " - << state[i][sfNFTokens.jsonName][0u] - .toStyledString() - << std::endl; + std::cout << "first: " << state[i][sfNFTokens.jsonName][0u].toStyledString() << std::endl; if (tokenCount > 1) - std::cout - << "last: " - << state[i][sfNFTokens.jsonName][tokenCount - 1] - .toStyledString() - << std::endl; + std::cout << "last: " << state[i][sfNFTokens.jsonName][tokenCount - 1].toStyledString() + << std::endl; } } } @@ -184,22 +150,18 @@ class NFTokenBurn_test : public beast::unit_test::suite // prevent alice's and minter's NFTs from clustering together // in becky's directory. // - // Use a default initialized mercenne_twister because we want the + // Use a default initialized mersenne_twister because we want the // effect of random numbers, but we want the test to run the same // way each time. std::mt19937 engine; - std::uniform_int_distribution feeDist( - decltype(maxTransferFee){}, maxTransferFee); + std::uniform_int_distribution feeDist(decltype(maxTransferFee){}, maxTransferFee); alice.nfts.reserve(105); while (alice.nfts.size() < 105) { std::uint16_t const xferFee = feeDist(engine); - alice.nfts.push_back(token::getNextID( - env, alice, 0u, tfTransferable | tfBurnable, xferFee)); - env(token::mint(alice), - txflags(tfTransferable | tfBurnable), - token::xferFee(xferFee)); + alice.nfts.push_back(token::getNextID(env, alice, 0u, tfTransferable | tfBurnable, xferFee)); + env(token::mint(alice), txflags(tfTransferable | tfBurnable), token::xferFee(xferFee)); env.close(); } @@ -207,8 +169,7 @@ class NFTokenBurn_test : public beast::unit_test::suite while (minter.nfts.size() < 105) { std::uint16_t const xferFee = feeDist(engine); - minter.nfts.push_back(token::getNextID( - env, alice, 0u, tfTransferable | tfBurnable, xferFee)); + minter.nfts.push_back(token::getNextID(env, alice, 0u, tfTransferable | tfBurnable, xferFee)); env(token::mint(minter), txflags(tfTransferable | tfBurnable), token::xferFee(xferFee), @@ -226,10 +187,8 @@ class NFTokenBurn_test : public beast::unit_test::suite { // We do the same work on alice and minter, so make a lambda. auto xferNFT = [&env, &becky](AcctStat& acct, auto& iter) { - uint256 offerIndex = - keylet::nftoffer(acct.acct, env.seq(acct.acct)).key; - env(token::createOffer(acct, *iter, XRP(0)), - txflags(tfSellNFToken)); + uint256 offerIndex = keylet::nftoffer(acct.acct, env.seq(acct.acct)).key; + env(token::createOffer(acct, *iter, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(becky, offerIndex)); env.close(); @@ -251,33 +210,24 @@ class NFTokenBurn_test : public beast::unit_test::suite // Next we'll create offers for all of those NFTs. This calls for // another lambda. - auto addOffers = - [&env](AcctStat& owner, AcctStat& other1, AcctStat& other2) { - for (uint256 nft : owner.nfts) - { - // Create sell offers for owner. - env(token::createOffer(owner, nft, drops(1)), - txflags(tfSellNFToken), - token::destination(other1)); - env(token::createOffer(owner, nft, drops(1)), - txflags(tfSellNFToken), - token::destination(other2)); - env.close(); + auto addOffers = [&env](AcctStat& owner, AcctStat& other1, AcctStat& other2) { + for (uint256 nft : owner.nfts) + { + // Create sell offers for owner. + env(token::createOffer(owner, nft, drops(1)), txflags(tfSellNFToken), token::destination(other1)); + env(token::createOffer(owner, nft, drops(1)), txflags(tfSellNFToken), token::destination(other2)); + env.close(); - // Create buy offers for other1 and other2. - env(token::createOffer(other1, nft, drops(1)), - token::owner(owner)); - env(token::createOffer(other2, nft, drops(1)), - token::owner(owner)); - env.close(); + // Create buy offers for other1 and other2. + env(token::createOffer(other1, nft, drops(1)), token::owner(owner)); + env(token::createOffer(other2, nft, drops(1)), token::owner(owner)); + env.close(); - env(token::createOffer(other2, nft, drops(2)), - token::owner(owner)); - env(token::createOffer(other1, nft, drops(2)), - token::owner(owner)); - env.close(); - } - }; + env(token::createOffer(other2, nft, drops(2)), token::owner(owner)); + env(token::createOffer(other1, nft, drops(2)), token::owner(owner)); + env.close(); + } + }; addOffers(alice, becky, minter); addOffers(becky, minter, alice); addOffers(minter, alice, becky); @@ -292,8 +242,7 @@ class NFTokenBurn_test : public beast::unit_test::suite std::uniform_int_distribution acctDist(0, 2); std::uniform_int_distribution mintDist(0, 1); - while (stats[0]->nfts.size() > 0 || stats[1]->nfts.size() > 0 || - stats[2]->nfts.size() > 0) + while (stats[0]->nfts.size() > 0 || stats[1]->nfts.size() > 0 || stats[2]->nfts.size() > 0) { // Pick an account to burn an nft. If there are no nfts left // pick again. @@ -302,8 +251,7 @@ class NFTokenBurn_test : public beast::unit_test::suite continue; // Pick one of the nfts. - std::uniform_int_distribution nftDist( - 0lu, owner.nfts.size() - 1); + std::uniform_int_distribution nftDist(0lu, owner.nfts.size() - 1); auto nftIter = owner.nfts.begin() + nftDist(engine); uint256 const nft = *nftIter; owner.nfts.erase(nftIter); @@ -311,10 +259,9 @@ class NFTokenBurn_test : public beast::unit_test::suite // Decide which of the accounts should burn the nft. If the // owner is becky then any of the three accounts can burn. // Otherwise either alice or minter can burn. - AcctStat& burner = owner.acct == becky.acct - ? *(stats[acctDist(engine)]) - : mintDist(engine) ? alice - : minter; + AcctStat& burner = owner.acct == becky.acct ? *(stats[acctDist(engine)]) + : mintDist(engine) ? alice + : minter; if (owner.acct == burner.acct) env(token::burn(burner, nft)); @@ -369,19 +316,13 @@ class NFTokenBurn_test : public beast::unit_test::suite // creation of NFT pages that are completely full. This lambda // tells us the taxon value we should pass in in order for the // internal representation to match the passed in value. - auto internalTaxon = [&env]( - Account const& acct, - std::uint32_t taxon) -> std::uint32_t { - std::uint32_t tokenSeq = - env.le(acct)->at(~sfMintedNFTokens).value_or(0); + auto internalTaxon = [&env](Account const& acct, std::uint32_t taxon) -> std::uint32_t { + std::uint32_t tokenSeq = env.le(acct)->at(~sfMintedNFTokens).value_or(0); // We must add FirstNFTokenSequence. - tokenSeq += env.le(acct) - ->at(~sfFirstNFTokenSequence) - .value_or(env.seq(acct)); + tokenSeq += env.le(acct)->at(~sfFirstNFTokenSequence).value_or(env.seq(acct)); - return toUInt32( - nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); + return toUInt32(nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); }; for (std::uint32_t i = 0; i < 96; ++i) @@ -409,19 +350,16 @@ class NFTokenBurn_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); Json::Value& state = jrr[jss::result][jss::state]; int pageCount = 0; for (Json::UInt i = 0; i < state.size(); ++i) { - if (state[i].isMember(sfNFTokens.jsonName) && - state[i][sfNFTokens.jsonName].isArray()) + if (state[i].isMember(sfNFTokens.jsonName) && state[i][sfNFTokens.jsonName].isArray()) { - BEAST_EXPECT( - state[i][sfNFTokens.jsonName].size() == 32); + BEAST_EXPECT(state[i][sfNFTokens.jsonName].size() == 32); ++pageCount; } } @@ -454,8 +392,7 @@ class NFTokenBurn_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); Json::Value& state = jrr[jss::result][jss::state]; @@ -480,17 +417,13 @@ class NFTokenBurn_test : public beast::unit_test::suite if (!BEAST_EXPECT(lastNFTokenPage)) return; - uint256 const middleNFTokenPageIndex = - lastNFTokenPage->at(sfPreviousPageMin); - auto middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + uint256 const middleNFTokenPageIndex = lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - uint256 const firstNFTokenPageIndex = - middleNFTokenPage->at(sfPreviousPageMin); - auto firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + uint256 const firstNFTokenPageIndex = middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); if (!BEAST_EXPECT(firstNFTokenPage)) return; @@ -508,8 +441,7 @@ class NFTokenBurn_test : public beast::unit_test::suite if (!BEAST_EXPECT(lastNFTokenPage)) return; - BEAST_EXPECT( - lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); + BEAST_EXPECT(lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); BEAST_EXPECT(lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); @@ -526,30 +458,21 @@ class NFTokenBurn_test : public beast::unit_test::suite // are moved into the last page. lastNFTokenPage = env.le(keylet::nftpage_max(alice)); BEAST_EXPECT(lastNFTokenPage); - BEAST_EXPECT( - lastNFTokenPage->at(~sfPreviousPageMin) == - firstNFTokenPageIndex); + BEAST_EXPECT(lastNFTokenPage->at(~sfPreviousPageMin) == firstNFTokenPageIndex); BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); - BEAST_EXPECT( - lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + BEAST_EXPECT(lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); // The "middle" page should be gone. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); BEAST_EXPECT(!middleNFTokenPage); // The "first" page should still be present and linked to // the last page. - firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); BEAST_EXPECT(firstNFTokenPage); - BEAST_EXPECT( - !firstNFTokenPage->isFieldPresent(sfPreviousPageMin)); - BEAST_EXPECT( - firstNFTokenPage->at(~sfNextPageMin) == - lastNFTokenPage->key()); - BEAST_EXPECT( - lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + BEAST_EXPECT(!firstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(firstNFTokenPage->at(~sfNextPageMin) == lastNFTokenPage->key()); + BEAST_EXPECT(lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); } else { @@ -561,12 +484,10 @@ class NFTokenBurn_test : public beast::unit_test::suite // The "middle" page is still present, but has lost the // NextPageMin field. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - BEAST_EXPECT( - middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -595,17 +516,13 @@ class NFTokenBurn_test : public beast::unit_test::suite if (!BEAST_EXPECT(lastNFTokenPage)) return; - uint256 const middleNFTokenPageIndex = - lastNFTokenPage->at(sfPreviousPageMin); - auto middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + uint256 const middleNFTokenPageIndex = lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - uint256 const firstNFTokenPageIndex = - middleNFTokenPage->at(sfPreviousPageMin); - auto firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + uint256 const firstNFTokenPageIndex = middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); if (!BEAST_EXPECT(firstNFTokenPage)) return; @@ -620,21 +537,15 @@ class NFTokenBurn_test : public beast::unit_test::suite // Verify that middle page is gone and the links in the two // remaining pages are correct. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); BEAST_EXPECT(!middleNFTokenPage); lastNFTokenPage = env.le(keylet::nftpage_max(alice)); BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); - BEAST_EXPECT( - lastNFTokenPage->getFieldH256(sfPreviousPageMin) == - firstNFTokenPageIndex); + BEAST_EXPECT(lastNFTokenPage->getFieldH256(sfPreviousPageMin) == firstNFTokenPageIndex); - firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); - BEAST_EXPECT( - firstNFTokenPage->getFieldH256(sfNextPageMin) == - keylet::nftpage_max(alice).key); + firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); + BEAST_EXPECT(firstNFTokenPage->getFieldH256(sfNextPageMin) == keylet::nftpage_max(alice).key); BEAST_EXPECT(!firstNFTokenPage->isFieldPresent(sfPreviousPageMin)); // Burn the remaining nfts. @@ -661,17 +572,13 @@ class NFTokenBurn_test : public beast::unit_test::suite if (!BEAST_EXPECT(lastNFTokenPage)) return; - uint256 const middleNFTokenPageIndex = - lastNFTokenPage->at(sfPreviousPageMin); - auto middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + uint256 const middleNFTokenPageIndex = lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - uint256 const firstNFTokenPageIndex = - middleNFTokenPage->at(sfPreviousPageMin); - auto firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + uint256 const firstNFTokenPageIndex = middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); if (!BEAST_EXPECT(firstNFTokenPage)) return; @@ -685,13 +592,11 @@ class NFTokenBurn_test : public beast::unit_test::suite } // Verify the first page is gone. - firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); BEAST_EXPECT(!firstNFTokenPage); // Check the links in the other two pages. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); @@ -720,20 +625,16 @@ class NFTokenBurn_test : public beast::unit_test::suite // are moved into the last page. lastNFTokenPage = env.le(keylet::nftpage_max(alice)); BEAST_EXPECT(lastNFTokenPage); - BEAST_EXPECT( - !lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); - BEAST_EXPECT( - lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + BEAST_EXPECT(lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); // The "middle" page should be gone. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); BEAST_EXPECT(!middleNFTokenPage); // The "first" page should still be gone. - firstNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), firstNFTokenPageIndex)); + firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); BEAST_EXPECT(!firstNFTokenPage); } else @@ -746,12 +647,10 @@ class NFTokenBurn_test : public beast::unit_test::suite // The "middle" page is still present, but has lost the // NextPageMin field. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - BEAST_EXPECT( - !middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfNextPageMin)); } @@ -798,40 +697,28 @@ class NFTokenBurn_test : public beast::unit_test::suite STTx tx{ttACCOUNT_SET, [](STObject&) {}}; test::StreamSink sink{beast::severities::kWarning}; beast::Journal jlog{sink}; - ApplyContext ac{ - env.app(), - ov, - tx, - tesSUCCESS, - env.current()->fees().base, - tapNONE, - jlog}; + ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, tapNONE, jlog}; // Verify that the last page is present and contains one NFT. - auto lastNFTokenPage = - ac.view().peek(keylet::nftpage_max(alice)); + auto lastNFTokenPage = ac.view().peek(keylet::nftpage_max(alice)); if (!BEAST_EXPECT(lastNFTokenPage)) return; - BEAST_EXPECT( - lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); + BEAST_EXPECT(lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); // Erase that last page. ac.view().erase(lastNFTokenPage); // Exercise the invariant. TER terActual = tesSUCCESS; - for (TER const& terExpect : - {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) + for (TER const& terExpect : {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) { terActual = ac.checkInvariants(terActual, XRPAmount{}); BEAST_EXPECT(terExpect == terActual); - BEAST_EXPECT( - sink.messages().str().starts_with("Invariant failed:")); + BEAST_EXPECT(sink.messages().str().starts_with("Invariant failed:")); // uncomment to log the invariant failure message // log << " --> " << sink.messages().str() << std::endl; BEAST_EXPECT( - sink.messages().str().find( - "Last NFT page deleted with non-empty directory") != + sink.messages().str().find("Last NFT page deleted with non-empty directory") != std::string::npos); } } @@ -842,21 +729,12 @@ class NFTokenBurn_test : public beast::unit_test::suite STTx tx{ttACCOUNT_SET, [](STObject&) {}}; test::StreamSink sink{beast::severities::kWarning}; beast::Journal jlog{sink}; - ApplyContext ac{ - env.app(), - ov, - tx, - tesSUCCESS, - env.current()->fees().base, - tapNONE, - jlog}; + ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, tapNONE, jlog}; // Verify that the middle page is present. - auto lastNFTokenPage = - ac.view().peek(keylet::nftpage_max(alice)); - auto middleNFTokenPage = ac.view().peek(keylet::nftpage( - keylet::nftpage_min(alice), - lastNFTokenPage->getFieldH256(sfPreviousPageMin))); + auto lastNFTokenPage = ac.view().peek(keylet::nftpage_max(alice)); + auto middleNFTokenPage = ac.view().peek( + keylet::nftpage(keylet::nftpage_min(alice), lastNFTokenPage->getFieldH256(sfPreviousPageMin))); BEAST_EXPECT(middleNFTokenPage); // Remove the NextMinPage link from the middle page to fire @@ -866,18 +744,14 @@ class NFTokenBurn_test : public beast::unit_test::suite // Exercise the invariant. TER terActual = tesSUCCESS; - for (TER const& terExpect : - {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) + for (TER const& terExpect : {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) { terActual = ac.checkInvariants(terActual, XRPAmount{}); BEAST_EXPECT(terExpect == terActual); - BEAST_EXPECT( - sink.messages().str().starts_with("Invariant failed:")); + BEAST_EXPECT(sink.messages().str().starts_with("Invariant failed:")); // uncomment to log the invariant failure message // log << " --> " << sink.messages().str() << std::endl; - BEAST_EXPECT( - sink.messages().str().find("Lost NextMinPage link") != - std::string::npos); + BEAST_EXPECT(sink.messages().str().find("Lost NextMinPage link") != std::string::npos); } } } @@ -906,8 +780,7 @@ class NFTokenBurn_test : public beast::unit_test::suite // When the token is burned, 498 sell offers and 1 buy offer are // removed. In total, 499 offers are removed std::vector offerIndexes; - auto const nftokenID = createNftAndOffers( - env, alice, offerIndexes, maxDeletableTokenOfferEntries - 2); + auto const nftokenID = createNftAndOffers(env, alice, offerIndexes, maxDeletableTokenOfferEntries - 2); // Verify all sell offers are present in the ledger. for (uint256 const& offerIndex : offerIndexes) @@ -916,10 +789,8 @@ class NFTokenBurn_test : public beast::unit_test::suite } // Becky creates a buy offer - uint256 const beckyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftokenID, drops(1)), - token::owner(alice)); + uint256 const beckyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftokenID, drops(1)), token::owner(alice)); env.close(); // Burn the token @@ -955,8 +826,7 @@ class NFTokenBurn_test : public beast::unit_test::suite // After we burn the token, 500 of the sell offers should be // removed, and one is left over std::vector offerIndexes; - auto const nftokenID = createNftAndOffers( - env, alice, offerIndexes, maxDeletableTokenOfferEntries + 1); + auto const nftokenID = createNftAndOffers(env, alice, offerIndexes, maxDeletableTokenOfferEntries + 1); // Verify all sell offers are present in the ledger. for (uint256 const& offerIndex : offerIndexes) @@ -999,8 +869,7 @@ class NFTokenBurn_test : public beast::unit_test::suite // are removed. // In total, 500 offers are removed std::vector offerIndexes; - auto const nftokenID = createNftAndOffers( - env, alice, offerIndexes, maxDeletableTokenOfferEntries - 1); + auto const nftokenID = createNftAndOffers(env, alice, offerIndexes, maxDeletableTokenOfferEntries - 1); // Verify all sell offers are present in the ledger. for (uint256 const& offerIndex : offerIndexes) @@ -1009,11 +878,9 @@ class NFTokenBurn_test : public beast::unit_test::suite } // becky creates 2 buy offers - env(token::createOffer(becky, nftokenID, drops(1)), - token::owner(alice)); + env(token::createOffer(becky, nftokenID, drops(1)), token::owner(alice)); env.close(); - env(token::createOffer(becky, nftokenID, drops(1)), - token::owner(alice)); + env(token::createOffer(becky, nftokenID, drops(1)), token::owner(alice)); env.close(); // Burn the token @@ -1071,19 +938,13 @@ class NFTokenBurn_test : public beast::unit_test::suite // creation of NFT pages that are completely full. This lambda // tells us the taxon value we should pass in in order for the // internal representation to match the passed in value. - auto internalTaxon = [&env]( - Account const& acct, - std::uint32_t taxon) -> std::uint32_t { - std::uint32_t tokenSeq = - env.le(acct)->at(~sfMintedNFTokens).value_or(0); + auto internalTaxon = [&env](Account const& acct, std::uint32_t taxon) -> std::uint32_t { + std::uint32_t tokenSeq = env.le(acct)->at(~sfMintedNFTokens).value_or(0); // We must add FirstNFTokenSequence. - tokenSeq += env.le(acct) - ->at(~sfFirstNFTokenSequence) - .value_or(env.seq(acct)); + tokenSeq += env.le(acct)->at(~sfFirstNFTokenSequence).value_or(env.seq(acct)); - return toUInt32( - nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); + return toUInt32(nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); }; for (std::uint32_t i = 0; i < 96; ++i) @@ -1096,16 +957,13 @@ class NFTokenBurn_test : public beast::unit_test::suite // populated. std::uint32_t const intTaxon = (i / 16) + (i & 0b10000 ? 2 : 0); uint32_t const extTaxon = internalTaxon(minter, intTaxon); - nfts.push_back( - token::getNextID(env, minter, extTaxon, tfTransferable)); + nfts.push_back(token::getNextID(env, minter, extTaxon, tfTransferable)); env(token::mint(minter, extTaxon), txflags(tfTransferable)); env.close(); // Minter creates an offer for the NFToken. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nfts.back(), XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nfts.back(), XRP(0)), txflags(tfSellNFToken)); env.close(); // alice accepts the offer. @@ -1123,19 +981,16 @@ class NFTokenBurn_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); Json::Value& state = jrr[jss::result][jss::state]; int pageCount = 0; for (Json::UInt i = 0; i < state.size(); ++i) { - if (state[i].isMember(sfNFTokens.jsonName) && - state[i][sfNFTokens.jsonName].isArray()) + if (state[i].isMember(sfNFTokens.jsonName) && state[i][sfNFTokens.jsonName].isArray()) { - BEAST_EXPECT( - state[i][sfNFTokens.jsonName].size() == 32); + BEAST_EXPECT(state[i][sfNFTokens.jsonName].size() == 32); ++pageCount; } } @@ -1157,17 +1012,13 @@ class NFTokenBurn_test : public beast::unit_test::suite if (!BEAST_EXPECT(lastNFTokenPage)) return; - uint256 const middleNFTokenPageIndex = - lastNFTokenPage->at(sfPreviousPageMin); - auto middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + uint256 const middleNFTokenPageIndex = lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; - uint256 const firstNFTokenPageIndex = - middleNFTokenPage->at(sfPreviousPageMin); - auto firstNFTokenPage = env.le( - keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); + uint256 const firstNFTokenPageIndex = middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); if (!BEAST_EXPECT(firstNFTokenPage)) return; @@ -1179,10 +1030,8 @@ class NFTokenBurn_test : public beast::unit_test::suite nfts.pop_back(); // alice creates an offer for the NFToken. - uint256 const aliceOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, last32NFTs.back(), XRP(0)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, last32NFTs.back(), XRP(0)), txflags(tfSellNFToken)); env.close(); // minter accepts the offer. @@ -1199,8 +1048,7 @@ class NFTokenBurn_test : public beast::unit_test::suite // The "middle" page is still present, but has lost the // NextPageMin field. - middleNFTokenPage = env.le(keylet::nftpage( - keylet::nftpage_min(alice), middleNFTokenPageIndex)); + middleNFTokenPage = env.le(keylet::nftpage(keylet::nftpage_min(alice), middleNFTokenPageIndex)); if (!BEAST_EXPECT(middleNFTokenPage)) return; BEAST_EXPECT(middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); @@ -1208,19 +1056,15 @@ class NFTokenBurn_test : public beast::unit_test::suite // Attempt to delete alice's account, but fail because she owns NFTs. auto const acctDelFee{drops(env.current()->fees().increment)}; - env(acctdelete(alice, minter), - fee(acctDelFee), - ter(tecHAS_OBLIGATIONS)); + env(acctdelete(alice, minter), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); env.close(); // minter sells the last 32 NFTs back to alice. for (uint256 nftID : last32NFTs) { // minter creates an offer for the NFToken. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); // alice accepts the offer. @@ -1239,8 +1083,7 @@ class NFTokenBurn_test : public beast::unit_test::suite return env.rpc("json", "account_objects", to_string(params)); }(); BEAST_EXPECT(!acctObjs.isMember(jss::marker)); - BEAST_EXPECT( - acctObjs[jss::result][jss::account_objects].size() == 2); + BEAST_EXPECT(acctObjs[jss::result][jss::account_objects].size() == 2); } { // Try the account_nfts RPC command. It only returns 64 NFTs @@ -1252,8 +1095,7 @@ class NFTokenBurn_test : public beast::unit_test::suite return env.rpc("json", "account_nfts", to_string(params)); }(); BEAST_EXPECT(!aliceNFTs.isMember(jss::marker)); - BEAST_EXPECT( - aliceNFTs[jss::result][jss::account_nfts].size() == 64); + BEAST_EXPECT(aliceNFTs[jss::result][jss::account_nfts].size() == 64); } } @@ -1278,6 +1120,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurn, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurn, app, xrpl, 3); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index 0e3dca361c..65bd97ec32 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { class NFTokenDir_test : public beast::unit_test::suite { @@ -47,12 +28,10 @@ class NFTokenDir_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); // Iterate the state and print all NFTokenPages. - if (!jrr.isMember(jss::result) || - !jrr[jss::result].isMember(jss::state)) + if (!jrr.isMember(jss::result) || !jrr[jss::result].isMember(jss::state)) { std::cout << "No ledger state found!" << std::endl; return; @@ -65,13 +44,10 @@ class NFTokenDir_test : public beast::unit_test::suite } for (Json::UInt i = 0; i < state.size(); ++i) { - if (state[i].isMember(sfNFTokens.jsonName) && - state[i][sfNFTokens.jsonName].isArray()) + if (state[i].isMember(sfNFTokens.jsonName) && state[i][sfNFTokens.jsonName].isArray()) { - std::uint32_t tokenCount = - state[i][sfNFTokens.jsonName].size(); - std::cout << tokenCount << " NFtokens in page " - << state[i][jss::index].asString() << std::endl; + std::uint32_t tokenCount = state[i][sfNFTokens.jsonName].size(); + std::cout << tokenCount << " NFtokens in page " << state[i][jss::index].asString() << std::endl; if (vol == noisy) { @@ -80,16 +56,10 @@ class NFTokenDir_test : public beast::unit_test::suite else { if (tokenCount > 0) - std::cout << "first: " - << state[i][sfNFTokens.jsonName][0u] - .toStyledString() - << std::endl; + std::cout << "first: " << state[i][sfNFTokens.jsonName][0u].toStyledString() << std::endl; if (tokenCount > 1) - std::cout - << "last: " - << state[i][sfNFTokens.jsonName][tokenCount - 1] - .toStyledString() - << std::endl; + std::cout << "last: " << state[i][sfNFTokens.jsonName][tokenCount - 1].toStyledString() + << std::endl; } } } @@ -125,10 +95,8 @@ class NFTokenDir_test : public beast::unit_test::suite nftIDs.reserve(nftCount); for (int i = 0; i < nftCount; ++i) { - std::uint32_t taxon = - toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0))); - nftIDs.emplace_back( - token::getNextID(env, issuer, taxon, tfTransferable)); + std::uint32_t taxon = toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0))); + nftIDs.emplace_back(token::getNextID(env, issuer, taxon, tfTransferable)); env(token::mint(issuer, taxon), txflags(tfTransferable)); env.close(); } @@ -139,8 +107,7 @@ class NFTokenDir_test : public beast::unit_test::suite for (uint256 const& nftID : nftIDs) { offers.emplace_back(keylet::nftoffer(issuer, env.seq(issuer)).key); - env(token::createOffer(issuer, nftID, XRP(0)), - txflags((tfSellNFToken))); + env(token::createOffer(issuer, nftID, XRP(0)), txflags((tfSellNFToken))); env.close(); } @@ -172,203 +139,187 @@ class NFTokenDir_test : public beast::unit_test::suite // with identical 96-low-bits are all kept on the same page. // Lambda that exercises the lopsided splits. - auto exerciseLopsided = - [this, - &features](std::initializer_list seeds) { - Env env{*this, features}; + auto exerciseLopsided = [this, &features](std::initializer_list seeds) { + Env env{*this, features}; - // Eventually all of the NFTokens will be owned by buyer. - Account const buyer{"buyer"}; - env.fund(XRP(10000), buyer); + // Eventually all of the NFTokens will be owned by buyer. + Account const buyer{"buyer"}; + env.fund(XRP(10000), buyer); + env.close(); + + // Create accounts for all of the seeds and fund those accounts. + std::vector accounts; + accounts.reserve(seeds.size()); + for (std::string_view seed : seeds) + { + Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); + env.fund(XRP(10000), account); + + // Do not close the ledger inside the loop. If accounts are + // initialized at different ledgers, they will have + // different account sequences. That would cause the + // accounts to have different NFTokenID sequence numbers. + } + env.close(); + + // All of the accounts create one NFT and and offer that NFT to + // buyer. + std::vector nftIDs; + std::vector offers; + offers.reserve(accounts.size()); + for (Account const& account : accounts) + { + // Mint the NFT. + uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable)); + env(token::mint(account, 0), txflags(tfTransferable)); env.close(); - // Create accounts for all of the seeds and fund those accounts. - std::vector accounts; - accounts.reserve(seeds.size()); - for (std::string_view seed : seeds) - { - Account const& account = accounts.emplace_back( - Account::base58Seed, std::string(seed)); - env.fund(XRP(10000), account); + // Create an offer to give the NFT to buyer for free. + offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key); + env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken))); + } + env.close(); - // Do not close the ledger inside the loop. If accounts are - // initialized at different ledgers, they will have - // different account sequences. That would cause the - // accounts to have different NFTokenID sequence numbers. - } + // buyer accepts all of the offers. + for (uint256 const& offer : offers) + { + env(token::acceptSellOffer(buyer, offer)); + env.close(); + } + + // This can be a good time to look at the NFT pages. + // printNFTPages(env, noisy); + + // Verify that all NFTs are owned by buyer and findable in the + // ledger by having buyer create sell offers for all of their + // NFTs. Attempting to sell an offer that the ledger can't find + // generates a non-tesSUCCESS error code. + for (uint256 const& nftID : nftIDs) + { + uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken)); env.close(); - // All of the accounts create one NFT and and offer that NFT to - // buyer. - std::vector nftIDs; - std::vector offers; - offers.reserve(accounts.size()); - for (Account const& account : accounts) - { - // Mint the NFT. - uint256 const& nftID = nftIDs.emplace_back( - token::getNextID(env, account, 0, tfTransferable)); - env(token::mint(account, 0), txflags(tfTransferable)); - env.close(); + env(token::cancelOffer(buyer, {offerID})); + } - // Create an offer to give the NFT to buyer for free. - offers.emplace_back( - keylet::nftoffer(account, env.seq(account)).key); - env(token::createOffer(account, nftID, XRP(0)), - token::destination(buyer), - txflags((tfSellNFToken))); - } - env.close(); + // Verify that all the NFTs are owned by buyer. + Json::Value buyerNFTs = [&env, &buyer]() { + Json::Value params; + params[jss::account] = buyer.human(); + params[jss::type] = "state"; + return env.rpc("json", "account_nfts", to_string(params)); + }(); - // buyer accepts all of the offers. - for (uint256 const& offer : offers) - { - env(token::acceptSellOffer(buyer, offer)); - env.close(); - } + BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size()); + for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts]) + { + uint256 ownedID; + BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString())); + auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID); - // This can be a good time to look at the NFT pages. - // printNFTPages(env, noisy); + // Assuming we find the NFT, erase it so we know it's been + // found and can't be found again. + if (BEAST_EXPECT(foundIter != nftIDs.end())) + nftIDs.erase(foundIter); + } - // Verify that all NFTs are owned by buyer and findable in the - // ledger by having buyer create sell offers for all of their - // NFTs. Attempting to sell an offer that the ledger can't find - // generates a non-tesSUCCESS error code. - for (uint256 const& nftID : nftIDs) - { - uint256 const offerID = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(100)), - txflags(tfSellNFToken)); - env.close(); - - env(token::cancelOffer(buyer, {offerID})); - } - - // Verify that all the NFTs are owned by buyer. - Json::Value buyerNFTs = [&env, &buyer]() { - Json::Value params; - params[jss::account] = buyer.human(); - params[jss::type] = "state"; - return env.rpc("json", "account_nfts", to_string(params)); - }(); - - BEAST_EXPECT( - buyerNFTs[jss::result][jss::account_nfts].size() == - nftIDs.size()); - for (Json::Value const& ownedNFT : - buyerNFTs[jss::result][jss::account_nfts]) - { - uint256 ownedID; - BEAST_EXPECT(ownedID.parseHex( - ownedNFT[sfNFTokenID.jsonName].asString())); - auto const foundIter = - std::find(nftIDs.begin(), nftIDs.end(), ownedID); - - // Assuming we find the NFT, erase it so we know it's been - // found and can't be found again. - if (BEAST_EXPECT(foundIter != nftIDs.end())) - nftIDs.erase(foundIter); - } - - // All NFTs should now be accounted for, so nftIDs should be - // empty. - BEAST_EXPECT(nftIDs.empty()); - }; + // All NFTs should now be accounted for, so nftIDs should be + // empty. + BEAST_EXPECT(nftIDs.empty()); + }; // These seeds cause a lopsided split where the new NFT is added // to the upper page. - static std::initializer_list const - splitAndAddToHi{ - "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea + static std::initializer_list const splitAndAddToHi{ + "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea - "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24 - "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24 - "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24 + "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24 + "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24 + "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24 - // These eight need to be kept together by the implementation. - "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed - "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed - "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed - "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed - "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed - "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed - "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed - "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed + // These eight need to be kept together by the implementation. + "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed + "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed + "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed + "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed + "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed + "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed + "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed + "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed - "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f + "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f - "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9 - // Adding this NFT splits the page. It is added to the upper - // page. - "sp6JS7f14BuwFY8Mw6ut1hFrqWoY5", // 32. 0x503b6ba9 - }; + // Adding this NFT splits the page. It is added to the upper + // page. + "sp6JS7f14BuwFY8Mw6ut1hFrqWoY5", // 32. 0x503b6ba9 + }; // These seeds cause a lopsided split where the new NFT is added // to the lower page. - static std::initializer_list const - splitAndAddToLo{ - "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea - "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea + static std::initializer_list const splitAndAddToLo{ + "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea + "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea - "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24 - "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24 - "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24 - "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24 + "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24 + "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24 + "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24 + "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24 - // These eight need to be kept together by the implementation. - "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed - "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed - "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed - "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed - "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed - "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed - "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed - "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed + // These eight need to be kept together by the implementation. + "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed + "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed + "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed + "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed + "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed + "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed + "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed + "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed - "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f - "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f + "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f + "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f - "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9 - "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9 + "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9 - // Adding this NFT splits the page. It is added to the lower - // page. - "sp6JS7f14BuwFY8Mw6xCigaMwC6Dp", // 32. 0x309b67ed - }; + // Adding this NFT splits the page. It is added to the lower + // page. + "sp6JS7f14BuwFY8Mw6xCigaMwC6Dp", // 32. 0x309b67ed + }; // Run the test cases. exerciseLopsided(splitAndAddToHi); @@ -388,118 +339,99 @@ class NFTokenDir_test : public beast::unit_test::suite // the index for the new page. This test recreates the problem. // Lambda that exercises the split. - auto exercise = - [this, - &features](std::initializer_list seeds) { - Env env{ - *this, - envconfig(), - features, - nullptr, - beast::severities::kDisabled}; + auto exercise = [this, &features](std::initializer_list seeds) { + Env env{*this, envconfig(), features, nullptr, beast::severities::kDisabled}; - // Eventually all of the NFTokens will be owned by buyer. - Account const buyer{"buyer"}; - env.fund(XRP(10000), buyer); + // Eventually all of the NFTokens will be owned by buyer. + Account const buyer{"buyer"}; + env.fund(XRP(10000), buyer); + env.close(); + + // Create accounts for all of the seeds and fund those accounts. + std::vector accounts; + accounts.reserve(seeds.size()); + for (std::string_view seed : seeds) + { + Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); + env.fund(XRP(10000), account); + + // Do not close the ledger inside the loop. If accounts are + // initialized at different ledgers, they will have + // different account sequences. That would cause the + // accounts to have different NFTokenID sequence numbers. + } + env.close(); + + // All of the accounts create one NFT and and offer that NFT to + // buyer. + std::vector nftIDs; + std::vector offers; + offers.reserve(accounts.size()); + for (Account const& account : accounts) + { + // Mint the NFT. + uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable)); + env(token::mint(account, 0), txflags(tfTransferable)); env.close(); - // Create accounts for all of the seeds and fund those accounts. - std::vector accounts; - accounts.reserve(seeds.size()); - for (std::string_view seed : seeds) - { - Account const& account = accounts.emplace_back( - Account::base58Seed, std::string(seed)); - env.fund(XRP(10000), account); + // Create an offer to give the NFT to buyer for free. + offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key); + env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken))); + } + env.close(); - // Do not close the ledger inside the loop. If accounts are - // initialized at different ledgers, they will have - // different account sequences. That would cause the - // accounts to have different NFTokenID sequence numbers. - } + // buyer accepts all of the but the last. The last offer + // causes the page to split. + for (std::size_t i = 0; i < offers.size() - 1; ++i) + { + env(token::acceptSellOffer(buyer, offers[i])); + env.close(); + } + + env(token::acceptSellOffer(buyer, offers.back())); + env.close(); + + // This can be a good time to look at the NFT pages. + // printNFTPages(env, noisy); + + // Verify that all NFTs are owned by buyer and findable in the + // ledger by having buyer create sell offers for all of their + // NFTs. Attempting to sell an offer that the ledger can't find + // generates a non-tesSUCCESS error code. + for (uint256 const& nftID : nftIDs) + { + uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken)); env.close(); - // All of the accounts create one NFT and and offer that NFT to - // buyer. - std::vector nftIDs; - std::vector offers; - offers.reserve(accounts.size()); - for (Account const& account : accounts) - { - // Mint the NFT. - uint256 const& nftID = nftIDs.emplace_back( - token::getNextID(env, account, 0, tfTransferable)); - env(token::mint(account, 0), txflags(tfTransferable)); - env.close(); + env(token::cancelOffer(buyer, {offerID})); + } - // Create an offer to give the NFT to buyer for free. - offers.emplace_back( - keylet::nftoffer(account, env.seq(account)).key); - env(token::createOffer(account, nftID, XRP(0)), - token::destination(buyer), - txflags((tfSellNFToken))); - } - env.close(); + // Verify that all the NFTs are owned by buyer. + Json::Value buyerNFTs = [&env, &buyer]() { + Json::Value params; + params[jss::account] = buyer.human(); + params[jss::type] = "state"; + return env.rpc("json", "account_nfts", to_string(params)); + }(); - // buyer accepts all of the but the last. The last offer - // causes the page to split. - for (std::size_t i = 0; i < offers.size() - 1; ++i) - { - env(token::acceptSellOffer(buyer, offers[i])); - env.close(); - } + BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size()); + for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts]) + { + uint256 ownedID; + BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString())); + auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID); - env(token::acceptSellOffer(buyer, offers.back())); - env.close(); + // Assuming we find the NFT, erase it so we know it's been + // found and can't be found again. + if (BEAST_EXPECT(foundIter != nftIDs.end())) + nftIDs.erase(foundIter); + } - // This can be a good time to look at the NFT pages. - // printNFTPages(env, noisy); - - // Verify that all NFTs are owned by buyer and findable in the - // ledger by having buyer create sell offers for all of their - // NFTs. Attempting to sell an offer that the ledger can't find - // generates a non-tesSUCCESS error code. - for (uint256 const& nftID : nftIDs) - { - uint256 const offerID = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(100)), - txflags(tfSellNFToken)); - env.close(); - - env(token::cancelOffer(buyer, {offerID})); - } - - // Verify that all the NFTs are owned by buyer. - Json::Value buyerNFTs = [&env, &buyer]() { - Json::Value params; - params[jss::account] = buyer.human(); - params[jss::type] = "state"; - return env.rpc("json", "account_nfts", to_string(params)); - }(); - - BEAST_EXPECT( - buyerNFTs[jss::result][jss::account_nfts].size() == - nftIDs.size()); - for (Json::Value const& ownedNFT : - buyerNFTs[jss::result][jss::account_nfts]) - { - uint256 ownedID; - BEAST_EXPECT(ownedID.parseHex( - ownedNFT[sfNFTokenID.jsonName].asString())); - auto const foundIter = - std::find(nftIDs.begin(), nftIDs.end(), ownedID); - - // Assuming we find the NFT, erase it so we know it's been - // found and can't be found again. - if (BEAST_EXPECT(foundIter != nftIDs.end())) - nftIDs.erase(foundIter); - } - - // All NFTs should now be accounted for, so nftIDs should be - // empty. - BEAST_EXPECT(nftIDs.empty()); - }; + // All NFTs should now be accounted for, so nftIDs should be + // empty. + BEAST_EXPECT(nftIDs.empty()); + }; // These seeds fill the last 17 entries of the initial page with // equivalent NFTs. The split should keep these together. @@ -647,8 +579,7 @@ class NFTokenDir_test : public beast::unit_test::suite accounts.reserve(seeds.size()); for (std::string_view seed : seeds) { - Account const& account = - accounts.emplace_back(Account::base58Seed, std::string(seed)); + Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); env.fund(XRP(10000), account); // Do not close the ledger inside the loop. If accounts are @@ -665,17 +596,13 @@ class NFTokenDir_test : public beast::unit_test::suite for (Account const& account : accounts) { // Mint the NFT. - uint256 const& nftID = nftIDs.emplace_back( - token::getNextID(env, account, 0, tfTransferable)); + uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable)); env(token::mint(account, 0), txflags(tfTransferable)); env.close(); // Create an offer to give the NFT to buyer for free. - offers.emplace_back( - keylet::nftoffer(account, env.seq(account)).key); - env(token::createOffer(account, nftID, XRP(0)), - token::destination(buyer), - txflags((tfSellNFToken))); + offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key); + env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken))); } env.close(); @@ -700,8 +627,7 @@ class NFTokenDir_test : public beast::unit_test::suite } // buyer accepts the last offer which causes a page overflow. - env(token::acceptSellOffer(buyer, offerForPageOverflow), - ter(tecNO_SUITABLE_NFTOKEN_PAGE)); + env(token::acceptSellOffer(buyer, offerForPageOverflow), ter(tecNO_SUITABLE_NFTOKEN_PAGE)); // Verify that all expected NFTs are owned by buyer and findable in // the ledger by having buyer create sell offers for all of their NFTs. @@ -710,8 +636,7 @@ class NFTokenDir_test : public beast::unit_test::suite for (uint256 const& nftID : nftIDs) { uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(100)), - txflags(tfSellNFToken)); + env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken)); env.close(); env(token::cancelOffer(buyer, {offerID})); @@ -725,16 +650,12 @@ class NFTokenDir_test : public beast::unit_test::suite return env.rpc("json", "account_nfts", to_string(params)); }(); - BEAST_EXPECT( - buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size()); - for (Json::Value const& ownedNFT : - buyerNFTs[jss::result][jss::account_nfts]) + BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size()); + for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts]) { uint256 ownedID; - BEAST_EXPECT( - ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString())); - auto const foundIter = - std::find(nftIDs.begin(), nftIDs.end(), ownedID); + BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString())); + auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID); // Assuming we find the NFT, erase it so we know it's been found // and can't be found again. @@ -818,8 +739,7 @@ class NFTokenDir_test : public beast::unit_test::suite accounts.reserve(seeds.size()); for (std::string_view seed : seeds) { - Account const& account = - accounts.emplace_back(Account::base58Seed, std::string(seed)); + Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); env.fund(XRP(10000), account); // Do not close the ledger inside the loop. If accounts are @@ -842,20 +762,16 @@ class NFTokenDir_test : public beast::unit_test::suite for (Account const& account : accounts) { // Mint the NFT. Tweak the taxon so zero is always stored. - std::uint32_t taxon = - toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0))); + std::uint32_t taxon = toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0))); - uint256 const& nftID = nftIDsByPage[i].emplace_back( - token::getNextID(env, account, taxon, tfTransferable)); + uint256 const& nftID = + nftIDsByPage[i].emplace_back(token::getNextID(env, account, taxon, tfTransferable)); env(token::mint(account, taxon), txflags(tfTransferable)); env.close(); // Create an offer to give the NFT to buyer for free. - offers[i].emplace_back( - keylet::nftoffer(account, env.seq(account)).key); - env(token::createOffer(account, nftID, XRP(0)), - token::destination(buyer), - txflags((tfSellNFToken))); + offers[i].emplace_back(keylet::nftoffer(account, env.seq(account)).key); + env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken))); } } env.close(); @@ -905,8 +821,7 @@ class NFTokenDir_test : public beast::unit_test::suite // the transaction succeeded. for (uint256 const& offer : overflowOffers) { - env(token::acceptSellOffer(buyer, offer), - ter(tecNO_SUITABLE_NFTOKEN_PAGE)); + env(token::acceptSellOffer(buyer, offer), ter(tecNO_SUITABLE_NFTOKEN_PAGE)); env.close(); } @@ -918,8 +833,7 @@ class NFTokenDir_test : public beast::unit_test::suite { for (uint256 const& nftID : vec) { - env(token::createOffer(buyer, nftID, XRP(100)), - txflags(tfSellNFToken)); + env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken)); env.close(); } } @@ -937,8 +851,7 @@ class NFTokenDir_test : public beast::unit_test::suite if (!marker.empty()) params[jss::marker] = marker; - return env.rpc( - "json", "account_objects", to_string(params)); + return env.rpc("json", "account_objects", to_string(params)); }(); marker.clear(); @@ -993,8 +906,7 @@ class NFTokenDir_test : public beast::unit_test::suite return env.rpc("json", "account_objects", to_string(params)); }(); BEAST_EXPECT( - remainingOffers.isMember(jss::result) && - remainingOffers[jss::result].isMember(jss::account_objects) && + remainingOffers.isMember(jss::result) && remainingOffers[jss::result].isMember(jss::account_objects) && remainingOffers[jss::result][jss::account_objects].size() == 0); } @@ -1043,8 +955,7 @@ class NFTokenDir_test : public beast::unit_test::suite if (ownedNFT.isMember(sfNFTokenID.jsonName)) { uint256 ownedID; - BEAST_EXPECT(ownedID.parseHex( - ownedNFT[sfNFTokenID.jsonName].asString())); + BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString())); auto const foundIter = allNftIDs.find(ownedID); // Assuming we find the NFT, erase it so we know it's been found @@ -1079,9 +990,9 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDir, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDir, app, xrpl, 1); -} // namespace ripple +} // namespace xrpl // Seed that produces an account with the low-32 bits == 0xFFFFFFFF in // case it is needed for future testing: diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 7d7774c15c..1b9ce82d4a 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,12 +8,10 @@ #include -namespace ripple { +namespace xrpl { class NFTokenBaseUtil_test : public beast::unit_test::suite { - FeatureBitset const disallowIncoming{featureDisallowIncoming}; - // Helper function that returns the number of NFTs minted by an issuer. static std::uint32_t mintedCount(test::jtx::Env const& env, test::jtx::Account const& issuer) @@ -78,7 +57,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite std::uint32_t lastClose(test::jtx::Env& env) { - return env.current()->info().parentCloseTime.time_since_epoch().count(); + return env.current()->header().parentCloseTime.time_since_epoch().count(); } void @@ -110,8 +89,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(mintedCount(env, master) == 1); BEAST_EXPECT(burnedCount(env, master) == 1); - uint256 const nftId1{ - token::getNextID(env, env.master, 0u, tfTransferable)}; + uint256 const nftId1{token::getNextID(env, env.master, 0u, tfTransferable)}; env(token::mint(env.master, 0u), txflags(tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, master) == 1); @@ -121,10 +99,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite Account const alice{"alice"}; env.fund(XRP(10000), alice); env.close(); - uint256 const aliceOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId1, XRP(1000)), - token::owner(master)); + uint256 const aliceOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId1, XRP(1000)), token::owner(master)); env.close(); BEAST_EXPECT(ownerCount(env, master) == 1); @@ -189,28 +165,22 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // A lambda that checks alice's ownerCount, mintedCount, and // burnedCount all in one fell swoop. - auto checkAliceOwnerMintedBurned = [&env, this, &alice]( - std::uint32_t owners, - std::uint32_t minted, - std::uint32_t burned, - int line) { - auto oneCheck = - [line, this]( - char const* type, std::uint32_t found, std::uint32_t exp) { + auto checkAliceOwnerMintedBurned = + [&env, this, &alice](std::uint32_t owners, std::uint32_t minted, std::uint32_t burned, int line) { + auto oneCheck = [line, this](char const* type, std::uint32_t found, std::uint32_t exp) { if (found == exp) pass(); else { std::stringstream ss; - ss << "Wrong " << type << " count. Found: " << found - << "; Expected: " << exp; + ss << "Wrong " << type << " count. Found: " << found << "; Expected: " << exp; fail(ss.str(), __FILE__, line); } }; - oneCheck("owner", ownerCount(env, alice), owners); - oneCheck("minted", mintedCount(env, alice), minted); - oneCheck("burned", burnedCount(env, alice), burned); - }; + oneCheck("owner", ownerCount(env, alice), owners); + oneCheck("minted", mintedCount(env, alice), minted); + oneCheck("burned", burnedCount(env, alice), burned); + }; // alice still does not have enough XRP for the reserve of an NFT // page. @@ -273,8 +243,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // alice burns a non-existent NFT. - env(token::burn(alice, token::getID(env, alice, 197, 5)), - ter(tecNO_ENTRY)); + env(token::burn(alice, token::getID(env, alice, 197, 5)), ter(tecNO_ENTRY)); env.close(); checkAliceOwnerMintedBurned(0, 33, 33, __LINE__); @@ -283,8 +252,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter. env(token::setMinter(alice, minter)); env.close(); - BEAST_EXPECT( - env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id()); + BEAST_EXPECT(env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id()); // A lambda that checks minter's and alice's ownerCount, // mintedCount, and burnedCount all in one fell swoop. @@ -296,32 +264,22 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite std::uint32_t minterMinted, std::uint32_t minterBurned, int line) { - auto oneCheck = [this]( - char const* type, - std::uint32_t found, - std::uint32_t exp, - int line) { + auto oneCheck = [this](char const* type, std::uint32_t found, std::uint32_t exp, int line) { if (found == exp) pass(); else { std::stringstream ss; - ss << "Wrong " << type << " count. Found: " << found - << "; Expected: " << exp; + ss << "Wrong " << type << " count. Found: " << found << "; Expected: " << exp; fail(ss.str(), __FILE__, line); } }; oneCheck("alice owner", ownerCount(env, alice), aliceOwners, line); - oneCheck( - "alice minted", mintedCount(env, alice), aliceMinted, line); - oneCheck( - "alice burned", burnedCount(env, alice), aliceBurned, line); - oneCheck( - "minter owner", ownerCount(env, minter), minterOwners, line); - oneCheck( - "minter minted", mintedCount(env, minter), minterMinted, line); - oneCheck( - "minter burned", burnedCount(env, minter), minterBurned, line); + oneCheck("alice minted", mintedCount(env, alice), aliceMinted, line); + oneCheck("alice burned", burnedCount(env, alice), aliceBurned, line); + oneCheck("minter owner", ownerCount(env, minter), minterOwners, line); + oneCheck("minter minted", mintedCount(env, minter), minterMinted, line); + oneCheck("minter burned", burnedCount(env, minter), minterBurned, line); }; std::uint32_t nftSeq = 33; @@ -334,10 +292,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter still does not have enough XRP for the reserve of an NFT // page. Just for grins (and code coverage), minter mints NFTs that // include a URI. - env(token::mint(minter), - token::issuer(alice), - token::uri("uri"), - ter(tecINSUFFICIENT_RESERVE)); + env(token::mint(minter), token::issuer(alice), token::uri("uri"), ter(tecINSUFFICIENT_RESERVE)); env.close(); checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__); @@ -365,10 +320,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // That NFT page is full. Creating an additional NFT page requires // additional reserve. - env(token::mint(minter), - token::issuer(alice), - token::uri("uri"), - ter(tecINSUFFICIENT_RESERVE)); + env(token::mint(minter), token::issuer(alice), token::uri("uri"), ter(tecINSUFFICIENT_RESERVE)); env.close(); checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__); @@ -386,8 +338,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { env(token::burn(minter, token::getID(env, alice, 0, nftSeq++))); env.close(); - checkMintersOwnerMintedBurned( - 0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__); + checkMintersOwnerMintedBurned(0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__); } // minter has one more NFT to burn. Should take her owner count to @@ -397,8 +348,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__); // minter burns a non-existent NFT. - env(token::burn(minter, token::getID(env, alice, 2009, 3)), - ter(tecNO_ENTRY)); + env(token::burn(minter, token::getID(env, alice, 2009, 3)), ter(tecNO_ENTRY)); env.close(); checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__); } @@ -434,29 +384,28 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Note that we're bypassing almost all of the ledger's safety // checks with this modify() call. If you call close() between // here and the end of the test all the effort will be lost. - env.app().openLedger().modify( - [&alice](OpenView& view, beast::Journal j) { - // Get the account root we want to hijack. - auto const sle = view.read(keylet::account(alice.id())); - if (!sle) - return false; // This would be really surprising! + env.app().openLedger().modify([&alice](OpenView& view, beast::Journal j) { + // Get the account root we want to hijack. + auto const sle = view.read(keylet::account(alice.id())); + if (!sle) + return false; // This would be really surprising! - // Just for sanity's sake we'll check that the current value - // of sfMintedNFTokens matches what we expect. - auto replacement = std::make_shared(*sle, sle->key()); - if (replacement->getFieldU32(sfMintedNFTokens) != 1) - return false; // Unexpected test conditions. + // Just for sanity's sake we'll check that the current value + // of sfMintedNFTokens matches what we expect. + auto replacement = std::make_shared(*sle, sle->key()); + if (replacement->getFieldU32(sfMintedNFTokens) != 1) + return false; // Unexpected test conditions. - // Wequence number is generated by sfFirstNFTokenSequence + - // sfMintedNFTokens. We can replace the two fields with any - // numbers as long as they add up to the largest valid number. - // In our case, sfFirstNFTokenSequence is set to the largest - // valid number, and sfMintedNFTokens is set to zero. - (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE; - (*replacement)[sfMintedNFTokens] = 0x0000'0000; - view.rawReplace(replacement); - return true; - }); + // Sequence number is generated by sfFirstNFTokenSequence + + // sfMintedNFTokens. We can replace the two fields with any + // numbers as long as they add up to the largest valid number. + // In our case, sfFirstNFTokenSequence is set to the largest + // valid number, and sfMintedNFTokens is set to zero. + (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE; + (*replacement)[sfMintedNFTokens] = 0x0000'0000; + view.rawReplace(replacement); + return true; + }); // See whether alice is at the boundary that causes an error. env(token::mint(alice, 0u), ter(tesSUCCESS)); @@ -492,18 +441,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // preflight // Set a negative fee. - env(token::mint(alice, 0u), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::mint(alice, 0u), fee(STAmount(10ull, true)), ter(temBAD_FEE)); // Set an invalid flag. env(token::mint(alice, 0u), txflags(0x00008000), ter(temINVALID_FLAG)); // Can't set a transfer fee if the NFT does not have the tfTRANSFERABLE // flag set. - env(token::mint(alice, 0u), - token::xferFee(maxTransferFee), - ter(temMALFORMED)); + env(token::mint(alice, 0u), token::xferFee(maxTransferFee), ter(temMALFORMED)); // Set a bad transfer fee. env(token::mint(alice, 0u), @@ -518,25 +463,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::mint(alice, 0u), token::uri(""), ter(temMALFORMED)); // Invalid URI: too long. - env(token::mint(alice, 0u), - token::uri(std::string(maxTokenURILength + 1, 'q')), - ter(temMALFORMED)); + env(token::mint(alice, 0u), token::uri(std::string(maxTokenURILength + 1, 'q')), ter(temMALFORMED)); //---------------------------------------------------------------------- // preclaim // Non-existent issuer. - env(token::mint(alice, 0u), - token::issuer(Account("demon")), - ter(tecNO_ISSUER)); + env(token::mint(alice, 0u), token::issuer(Account("demon")), ter(tecNO_ISSUER)); //---------------------------------------------------------------------- // doApply // Existent issuer, but not given minting permission - env(token::mint(minter, 0u), - token::issuer(alice), - ter(tecNO_PERMISSION)); + env(token::mint(minter, 0u), token::issuer(alice), ter(tecNO_PERMISSION)); } void @@ -561,8 +500,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const nftAlice0ID = - token::getNextID(env, alice, 0, tfTransferable); + uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable); env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -571,16 +509,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // preflight // Set a negative fee. - env(token::burn(alice, nftAlice0ID), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::burn(alice, nftAlice0ID), fee(STAmount(10ull, true)), ter(temBAD_FEE)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); // Set an invalid flag. - env(token::burn(alice, nftAlice0ID), - txflags(0x00008000), - ter(temINVALID_FLAG)); + env(token::burn(alice, nftAlice0ID), txflags(0x00008000), ter(temINVALID_FLAG)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); @@ -588,8 +522,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // preclaim // Try to burn a token that doesn't exist. - env(token::burn(alice, token::getID(env, alice, 0, 1)), - ter(tecNO_ENTRY)); + env(token::burn(alice, token::getID(env, alice, 0, 1)), ter(tecNO_ENTRY)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); @@ -620,16 +553,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const nftAlice0ID = - token::getNextID(env, alice, 0, tfTransferable, 10); - env(token::mint(alice, 0u), - txflags(tfTransferable), - token::xferFee(10)); + uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable, 10); + env(token::mint(alice, 0u), txflags(tfTransferable), token::xferFee(10)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); - uint256 const nftXrpOnlyID = - token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable); + uint256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable); env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -648,47 +577,35 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // buyer tries to create an NFTokenOffer, but doesn't have the reserve. - env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), - token::owner(alice), - ter(tecINSUFFICIENT_RESERVE)); + env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), token::owner(alice), ter(tecINSUFFICIENT_RESERVE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // Set a negative fee. - env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), fee(STAmount(10ull, true)), ter(temBAD_FEE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // Set an invalid flag. - env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), - txflags(0x00008000), - ter(temINVALID_FLAG)); + env(token::createOffer(buyer, nftAlice0ID, XRP(1000)), txflags(0x00008000), ter(temINVALID_FLAG)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // Set an invalid amount. - env(token::createOffer(buyer, nftXrpOnlyID, buyer["USD"](1)), - ter(temBAD_AMOUNT)); - env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](0)), - ter(temBAD_AMOUNT)); - env(token::createOffer(buyer, nftXrpOnlyID, drops(0)), - ter(temBAD_AMOUNT)); + env(token::createOffer(buyer, nftXrpOnlyID, buyer["USD"](1)), ter(temBAD_AMOUNT)); + env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](0)), ter(temBAD_AMOUNT)); + env(token::createOffer(buyer, nftXrpOnlyID, drops(0)), ter(temBAD_AMOUNT)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // Set a bad expiration. - env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](1)), - token::expiration(0), - ter(temBAD_EXPIRATION)); + env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](1)), token::expiration(0), ter(temBAD_EXPIRATION)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // Invalid Owner field and tfSellToken flag relationships. // A buy offer must specify the owner. - env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)), - ter(temMALFORMED)); + env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); @@ -701,9 +618,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 1); // An owner may not offer to buy their own token. - env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)), - token::owner(alice), - ter(temMALFORMED)); + env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)), token::owner(alice), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -735,25 +650,21 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, buyer) == 0); // The nftID must be present in the ledger. - env(token::createOffer( - buyer, token::getID(env, alice, 0, 1), XRP(1000)), + env(token::createOffer(buyer, token::getID(env, alice, 0, 1), XRP(1000)), token::owner(alice), ter(tecNO_ENTRY)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // The nftID must be present in the ledger of a sell offer too. - env(token::createOffer( - alice, token::getID(env, alice, 0, 1), XRP(1000)), + env(token::createOffer(alice, token::getID(env, alice, 0, 1), XRP(1000)), txflags(tfSellNFToken), ter(tecNO_ENTRY)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); // buyer must have the funds to pay for their offer. - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecNO_LINE)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecNO_LINE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); @@ -763,9 +674,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Issuer (alice) must have a trust line for the offered funds. - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecNO_LINE)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecNO_LINE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -775,9 +684,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Issuer (alice) must have a trust line for the offered funds and // the trust line may not be frozen. - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecFROZEN)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecFROZEN)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -796,9 +703,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(trust(gw, buyer["AUD"](999), tfSetFreeze)); env.close(); - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecFROZEN)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecFROZEN)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -808,9 +713,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(trust(buyer, gwAUD(1000))); env.close(); - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecUNFUNDED_OFFER)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecUNFUNDED_OFFER)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); // the trust line. @@ -823,9 +726,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // However buyer doesn't have enough XRP to cover the reserve for // an NFT offer. - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecINSUFFICIENT_RESERVE)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecINSUFFICIENT_RESERVE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -834,9 +735,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(pay(env.master, buyer, XRP(50) + drops(baseFee * 12 - 1))); env.close(); - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tecINSUFFICIENT_RESERVE)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tecINSUFFICIENT_RESERVE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -846,9 +745,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // We don't care whether the offer is fully funded until the offer is // accepted. Success at last! - env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), - token::owner(alice), - ter(tesSUCCESS)); + env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)), token::owner(alice), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 2); } @@ -870,18 +767,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const nftAlice0ID = - token::getNextID(env, alice, 0, tfTransferable); + uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable); env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); // This is the offer we'll try to cancel. - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftAlice0ID, XRP(1)), - token::owner(alice), - ter(tesSUCCESS)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftAlice0ID, XRP(1)), token::owner(alice), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -889,16 +782,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // preflight // Set a negative fee. - env(token::cancelOffer(buyer, {buyerOfferIndex}), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::cancelOffer(buyer, {buyerOfferIndex}), fee(STAmount(10ull, true)), ter(temBAD_FEE)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); // Set an invalid flag. - env(token::cancelOffer(buyer, {buyerOfferIndex}), - txflags(0x00008000), - ter(temINVALID_FLAG)); + env(token::cancelOffer(buyer, {buyerOfferIndex}), txflags(0x00008000), ter(temINVALID_FLAG)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -913,8 +802,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // List of tokens to delete is too long. { - std::vector offers( - maxTokenOfferCancelCount + 1, buyerOfferIndex); + std::vector offers(maxTokenOfferCancelCount + 1, buyerOfferIndex); env(token::cancelOffer(buyer, offers), ter(temMALFORMED)); env.close(); @@ -922,8 +810,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // Duplicate entries are not allowed in the list of offers to cancel. - env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}), - ter(temMALFORMED)); + env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -989,78 +876,79 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.fund(XRP(1000), alice, buyer, gw); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == 0); - uint256 const nftAlice0ID = - token::getNextID(env, alice, 0, tfTransferable); + uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable); env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 1); + uint8_t aliceCount = 1; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); - uint256 const nftXrpOnlyID = - token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable); + uint256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable); env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 1); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); uint256 nftNoXferID = token::getNextID(env, alice, 0); env(token::mint(alice, 0)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 1); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); // alice creates sell offers for her nfts. - uint256 const plainOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAlice0ID, XRP(10)), - txflags(tfSellNFToken)); + uint256 const plainOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAlice0ID, XRP(10)), txflags(tfSellNFToken)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 2); + aliceCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); - uint256 const audOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAlice0ID, gwAUD(30)), - txflags(tfSellNFToken)); + uint256 const audOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAlice0ID, gwAUD(30)), txflags(tfSellNFToken)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 3); + aliceCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); - uint256 const xrpOnlyOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftXrpOnlyID, XRP(20)), - txflags(tfSellNFToken)); + uint256 const xrpOnlyOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftXrpOnlyID, XRP(20)), txflags(tfSellNFToken)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 4); + aliceCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); - uint256 const noXferOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftNoXferID, XRP(30)), - txflags(tfSellNFToken)); + uint256 const noXferOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftNoXferID, XRP(30)), txflags(tfSellNFToken)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 5); + aliceCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); // alice creates a sell offer that will expire soon. - uint256 const aliceExpOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const aliceExpOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; env(token::createOffer(alice, nftNoXferID, XRP(40)), txflags(tfSellNFToken), token::expiration(lastClose(env) + 5)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 6); + aliceCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); + + // buyer creates a Buy offer that will expire soon. + uint256 const buyerExpOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftAlice0ID, XRP(40)), + token::owner(alice), + token::expiration(lastClose(env) + 5)); + env.close(); + uint8_t buyerCount = 1; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); //---------------------------------------------------------------------- // preflight // Set a negative fee. - env(token::acceptSellOffer(buyer, noXferOfferIndex), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::acceptSellOffer(buyer, noXferOfferIndex), fee(STAmount(10ull, true)), ter(temBAD_FEE)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Set an invalid flag. - env(token::acceptSellOffer(buyer, noXferOfferIndex), - txflags(0x00008000), - ter(temINVALID_FLAG)); + env(token::acceptSellOffer(buyer, noXferOfferIndex), txflags(0x00008000), ter(temINVALID_FLAG)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Supply nether an sfNFTokenBuyOffer nor an sfNFTokenSellOffer field. { @@ -1068,27 +956,25 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite jv.removeMember(sfNFTokenSellOffer.jsonName); env(jv, ter(temMALFORMED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // A buy offer may not contain a sfNFTokenBrokerFee field. { Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex); - jv[sfNFTokenBrokerFee.jsonName] = - STAmount(500000).getJson(JsonOptions::none); + jv[sfNFTokenBrokerFee.jsonName] = STAmount(500000).getJson(JsonOptions::none); env(jv, ter(temMALFORMED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // A sell offer may not contain a sfNFTokenBrokerFee field. { Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex); - jv[sfNFTokenBrokerFee.jsonName] = - STAmount(500000).getJson(JsonOptions::none); + jv[sfNFTokenBrokerFee.jsonName] = STAmount(500000).getJson(JsonOptions::none); env(jv, ter(temMALFORMED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // A brokered offer may not contain a negative or zero brokerFee. @@ -1096,45 +982,56 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite token::brokerFee(gwAUD(0)), ter(temMALFORMED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); //---------------------------------------------------------------------- // preclaim // The buy offer must be non-zero. - env(token::acceptBuyOffer(buyer, beast::zero), - ter(tecOBJECT_NOT_FOUND)); + env(token::acceptBuyOffer(buyer, beast::zero), ter(tecOBJECT_NOT_FOUND)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The buy offer must be present in the ledger. uint256 const missingOfferIndex = keylet::nftoffer(alice, 1).key; - env(token::acceptBuyOffer(buyer, missingOfferIndex), - ter(tecOBJECT_NOT_FOUND)); + env(token::acceptBuyOffer(buyer, missingOfferIndex), ter(tecOBJECT_NOT_FOUND)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The buy offer must not have expired. - env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(tecEXPIRED)); + // NOTE: this is only a preclaim check with the + // fixExpiredNFTokenOfferRemoval amendment disabled. + env(token::acceptBuyOffer(alice, buyerExpOfferIndex), ter(tecEXPIRED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + if (features[fixExpiredNFTokenOfferRemoval]) + { + buyerCount--; + } + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The sell offer must be non-zero. - env(token::acceptSellOffer(buyer, beast::zero), - ter(tecOBJECT_NOT_FOUND)); + env(token::acceptSellOffer(buyer, beast::zero), ter(tecOBJECT_NOT_FOUND)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The sell offer must be present in the ledger. - env(token::acceptSellOffer(buyer, missingOfferIndex), - ter(tecOBJECT_NOT_FOUND)); + env(token::acceptSellOffer(buyer, missingOfferIndex), ter(tecOBJECT_NOT_FOUND)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The sell offer must not have expired. + // NOTE: this is only a preclaim check with the + // fixExpiredNFTokenOfferRemoval amendment disabled. env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(tecEXPIRED)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + // Alice's count is decremented by one when the expired offer is + // removed. + if (features[fixExpiredNFTokenOfferRemoval]) + { + aliceCount--; + } + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); //---------------------------------------------------------------------- // preclaim brokered @@ -1146,52 +1043,53 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); env(pay(gw, buyer, gwAUD(30))); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 7); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + aliceCount++; + buyerCount++; + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); + + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // We're about to exercise offer brokering, so we need // corresponding buy and sell offers. { // buyer creates a buy offer for one of alice's nfts. - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)), - token::owner(alice)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)), token::owner(alice)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + buyerCount++; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // gw attempts to broker offers that are not for the same token. - env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex), - ter(tecNFTOKEN_BUY_SELL_MISMATCH)); + env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex), ter(tecNFTOKEN_BUY_SELL_MISMATCH)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // gw attempts to broker offers that are not for the same currency. - env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex), - ter(tecNFTOKEN_BUY_SELL_MISMATCH)); + env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex), ter(tecNFTOKEN_BUY_SELL_MISMATCH)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // In a brokered offer, the buyer must offer greater than or // equal to the selling price. - env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex), - ter(tecINSUFFICIENT_PAYMENT)); + env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex), ter(tecINSUFFICIENT_PAYMENT)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Remove buyer's offer. env(token::cancelOffer(buyer, {buyerOfferIndex})); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + buyerCount--; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } { // buyer creates a buy offer for one of alice's nfts. - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)), - token::owner(alice)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)), token::owner(alice)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + buyerCount++; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Broker sets their fee in a denomination other than the one // used by the offers @@ -1199,14 +1097,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite token::brokerFee(XRP(40)), ter(tecNFTOKEN_BUY_SELL_MISMATCH)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Broker fee way too big. env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex), token::brokerFee(gwAUD(31)), ter(tecINSUFFICIENT_PAYMENT)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Broker fee is smaller, but still too big once the offer // seller's minimum is taken into account. @@ -1214,120 +1112,108 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite token::brokerFee(gwAUD(1.5)), ter(tecINSUFFICIENT_PAYMENT)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Remove buyer's offer. env(token::cancelOffer(buyer, {buyerOfferIndex})); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + buyerCount--; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } //---------------------------------------------------------------------- // preclaim buy { // buyer creates a buy offer for one of alice's nfts. - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)), - token::owner(alice)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)), token::owner(alice)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + buyerCount++; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Don't accept a buy offer if the sell flag is set. - env(token::acceptBuyOffer(buyer, plainOfferIndex), - ter(tecNFTOKEN_OFFER_TYPE_MISMATCH)); + env(token::acceptBuyOffer(buyer, plainOfferIndex), ter(tecNFTOKEN_OFFER_TYPE_MISMATCH)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 7); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); // An account can't accept its own offer. - env(token::acceptBuyOffer(buyer, buyerOfferIndex), - ter(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER)); + env(token::acceptBuyOffer(buyer, buyerOfferIndex), ter(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // An offer acceptor must have enough funds to pay for the offer. env(pay(buyer, gw, gwAUD(30))); env.close(); BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0)); - env(token::acceptBuyOffer(alice, buyerOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptBuyOffer(alice, buyerOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // alice gives her NFT to gw, so alice no longer owns nftAlice0. { - uint256 const offerIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAlice0ID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const offerIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAlice0ID, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(gw, offerIndex)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 7); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); } env(pay(gw, buyer, gwAUD(30))); env.close(); // alice can't accept a buy offer for an NFT she no longer owns. - env(token::acceptBuyOffer(alice, buyerOfferIndex), - ter(tecNO_PERMISSION)); + env(token::acceptBuyOffer(alice, buyerOfferIndex), ter(tecNO_PERMISSION)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Remove buyer's offer. env(token::cancelOffer(buyer, {buyerOfferIndex})); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + buyerCount--; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } //---------------------------------------------------------------------- // preclaim sell { // buyer creates a buy offer for one of alice's nfts. - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)), - token::owner(alice)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)), token::owner(alice)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + buyerCount++; + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Don't accept a sell offer without the sell flag set. - env(token::acceptSellOffer(alice, buyerOfferIndex), - ter(tecNFTOKEN_OFFER_TYPE_MISMATCH)); + env(token::acceptSellOffer(alice, buyerOfferIndex), ter(tecNFTOKEN_OFFER_TYPE_MISMATCH)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 7); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); // An account can't accept its own offer. - env(token::acceptSellOffer(alice, plainOfferIndex), - ter(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER)); + env(token::acceptSellOffer(alice, plainOfferIndex), ter(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The seller must currently be in possession of the token they // are selling. alice gave nftAlice0ID to gw. - env(token::acceptSellOffer(buyer, plainOfferIndex), - ter(tecNO_PERMISSION)); + env(token::acceptSellOffer(buyer, plainOfferIndex), ter(tecNO_PERMISSION)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // gw gives nftAlice0ID back to alice. That allows us to check // buyer attempting to accept one of alice's offers with // insufficient funds. { - uint256 const offerIndex = - keylet::nftoffer(gw, env.seq(gw)).key; - env(token::createOffer(gw, nftAlice0ID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const offerIndex = keylet::nftoffer(gw, env.seq(gw)).key; + env(token::createOffer(gw, nftAlice0ID, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, offerIndex)); env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 7); + BEAST_EXPECT(ownerCount(env, alice) == aliceCount); } env(pay(buyer, gw, gwAUD(30))); env.close(); BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0)); - env(token::acceptSellOffer(buyer, audOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptSellOffer(buyer, audOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } //---------------------------------------------------------------------- @@ -1363,16 +1249,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // 1. creates an alice nft // 2. minted by minter and // 3. transfers that nft to buyer. - auto nftToBuyer = [&env, &alice, &minter1, &buyer]( - std::uint32_t flags) { + auto nftToBuyer = [&env, &alice, &minter1, &buyer](std::uint32_t flags) { uint256 const nftID{token::getNextID(env, alice, 0u, flags)}; env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags)); env.close(); - uint256 const offerIndex = - keylet::nftoffer(minter1, env.seq(minter1)).key; - env(token::createOffer(minter1, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const offerIndex = keylet::nftoffer(minter1, env.seq(minter1)).key; + env(token::createOffer(minter1, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(buyer, offerIndex)); @@ -1384,17 +1267,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // An NFT without flagBurnable can only be burned by its owner. { uint256 const noBurnID = nftToBuyer(0); - env(token::burn(alice, noBurnID), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::burn(alice, noBurnID), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); - env(token::burn(minter1, noBurnID), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::burn(minter1, noBurnID), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); - env(token::burn(minter2, noBurnID), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::burn(minter2, noBurnID), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -1405,9 +1282,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // An NFT with flagBurnable can be burned by the issuer. { uint256 const burnableID = nftToBuyer(tfBurnable); - env(token::burn(minter2, burnableID), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::burn(minter2, burnableID), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -1441,10 +1316,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // minter1 is no longer alice's minter, so no longer has - // permisson to burn alice's nfts. - env(token::burn(minter1, burnableID), - token::owner(buyer), - ter(tecNO_PERMISSION)); + // permission to burn alice's nfts. + env(token::burn(minter1, burnableID), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); @@ -1479,24 +1352,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Don't set flagOnlyXRP and offers can be made with IOUs. { - uint256 const nftIOUsOkayID{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftIOUsOkayID{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); - uint256 const aliceOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 3); BEAST_EXPECT(ownerCount(env, buyer) == 1); - uint256 const buyerOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)), - token::owner(alice)); + uint256 const buyerOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)), token::owner(alice)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 2); @@ -1515,35 +1383,28 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Set flagOnlyXRP and offers using IOUs are rejected. { - uint256 const nftOnlyXRPID{ - token::getNextID(env, alice, 0u, tfOnlyXRP | tfTransferable)}; + uint256 const nftOnlyXrpID{token::getNextID(env, alice, 0u, tfOnlyXRP | tfTransferable)}; env(token::mint(alice, 0u), txflags(tfOnlyXRP | tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); - env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)), - txflags(tfSellNFToken), - ter(temBAD_AMOUNT)); + env(token::createOffer(alice, nftOnlyXrpID, gwAUD(50)), txflags(tfSellNFToken), ter(temBAD_AMOUNT)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); BEAST_EXPECT(ownerCount(env, buyer) == 1); - env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)), - token::owner(alice), - ter(temBAD_AMOUNT)); + env(token::createOffer(buyer, nftOnlyXrpID, gwAUD(50)), token::owner(alice), ter(temBAD_AMOUNT)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 1); // However offers for XRP are okay. BEAST_EXPECT(ownerCount(env, alice) == 2); - env(token::createOffer(alice, nftOnlyXRPID, XRP(60)), - txflags(tfSellNFToken)); + env(token::createOffer(alice, nftOnlyXrpID, XRP(60)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 3); BEAST_EXPECT(ownerCount(env, buyer) == 1); - env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)), - token::owner(alice)); + env(token::createOffer(buyer, nftOnlyXrpID, XRP(60)), token::owner(alice)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 2); } @@ -1569,8 +1430,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // presence (or absence) of the fixRemoveNFTokenAutoTrustLine // amendment. So we test both cases here. for (auto const& tweakedFeatures : - {features - fixRemoveNFTokenAutoTrustLine, - features | fixRemoveNFTokenAutoTrustLine}) + {features - fixRemoveNFTokenAutoTrustLine, features | fixRemoveNFTokenAutoTrustLine}) { Env env{*this, tweakedFeatures}; env.fund(XRP(1000), alice, becky, cheri, gw); @@ -1595,38 +1455,28 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // fee will not allow creating offers that use IOUs for payment. for (std::uint32_t xferFee : {0, 1}) { - uint256 const nftNoAutoTrustID{ - token::getNextID(env, alice, 0u, tfTransferable, xferFee)}; - env(token::mint(alice, 0u), - token::xferFee(xferFee), - txflags(tfTransferable)); + uint256 const nftNoAutoTrustID{token::getNextID(env, alice, 0u, tfTransferable, xferFee)}; + env(token::mint(alice, 0u), token::xferFee(xferFee), txflags(tfTransferable)); env.close(); // becky buys the nft for 1 drop. - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), token::owner(alice)); env.close(); env(token::acceptBuyOffer(alice, beckyBuyOfferIndex)); env.close(); // becky attempts to sell the nft for AUD. - TER const createOfferTER = - xferFee ? TER(tecNO_LINE) : TER(tesSUCCESS); - uint256 const beckyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; + TER const createOfferTER = xferFee ? TER(tecNO_LINE) : TER(tesSUCCESS); + uint256 const beckyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), txflags(tfSellNFToken), ter(createOfferTER)); env.close(); // cheri offers to buy the nft for CAD. - uint256 const cheriOfferIndex = - keylet::nftoffer(cheri, env.seq(cheri)).key; - env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)), - token::owner(becky), - ter(createOfferTER)); + uint256 const cheriOfferIndex = keylet::nftoffer(cheri, env.seq(cheri)).key; + env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)), token::owner(becky), ter(createOfferTER)); env.close(); // To keep things tidy, cancel the offers. @@ -1639,14 +1489,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { std::uint16_t transferFee = 10000; // 10% - uint256 const nftAutoTrustID{token::getNextID( - env, alice, 0u, tfTransferable | tfTrustLine, transferFee)}; + uint256 const nftAutoTrustID{ + token::getNextID(env, alice, 0u, tfTransferable | tfTrustLine, transferFee)}; // If the fixRemoveNFTokenAutoTrustLine amendment is active // then this transaction fails. { - TER const mintTER = - tweakedFeatures[fixRemoveNFTokenAutoTrustLine] + TER const mintTER = tweakedFeatures[fixRemoveNFTokenAutoTrustLine] ? static_cast(temINVALID_FLAG) : static_cast(tesSUCCESS); @@ -1662,19 +1511,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite break; } // becky buys the nft for 1 drop. - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, drops(1)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, drops(1)), token::owner(alice)); env.close(); env(token::acceptBuyOffer(alice, beckyBuyOfferIndex)); env.close(); // becky sells the nft for AUD. - uint256 const beckySellOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), - txflags(tfSellNFToken)); + uint256 const beckySellOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(cheri, beckySellOfferIndex)); env.close(); @@ -1683,10 +1528,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10)); // becky buys the nft back for CAD. - uint256 const beckyBuyBackOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)), - token::owner(cheri)); + uint256 const beckyBuyBackOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)), token::owner(cheri)); env.close(); env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex)); env.close(); @@ -1699,18 +1542,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // flagCreateTrustLines will work for preestablished trust lines. { std::uint16_t transferFee = 5000; // 5% - uint256 const nftNoAutoTrustID{token::getNextID( - env, alice, 0u, tfTransferable, transferFee)}; - env(token::mint(alice, 0u), - token::xferFee(transferFee), - txflags(tfTransferable)); + uint256 const nftNoAutoTrustID{token::getNextID(env, alice, 0u, tfTransferable, transferFee)}; + env(token::mint(alice, 0u), token::xferFee(transferFee), txflags(tfTransferable)); env.close(); // alice sells the nft using AUD. - uint256 const aliceSellOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)), - txflags(tfSellNFToken)); + uint256 const aliceSellOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(cheri, aliceSellOfferIndex)); env.close(); @@ -1721,14 +1559,10 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210)); // cheri can't sell the NFT for EUR, but can for CAD. - env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)), - txflags(tfSellNFToken), - ter(tecNO_LINE)); + env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)), txflags(tfSellNFToken), ter(tecNO_LINE)); env.close(); - uint256 const cheriSellOfferIndex = - keylet::nftoffer(cheri, env.seq(cheri)).key; - env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)), - txflags(tfSellNFToken)); + uint256 const cheriSellOfferIndex = keylet::nftoffer(cheri, env.seq(cheri)).key; + env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(becky, cheriSellOfferIndex)); env.close(); @@ -1761,8 +1595,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // First try an nft made by alice without flagTransferable set. { BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const nftAliceNoTransferID{ - token::getNextID(env, alice, 0u)}; + uint256 const nftAliceNoTransferID{token::getNextID(env, alice, 0u)}; env(token::mint(alice, 0u), token::xferFee(0)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -1774,10 +1607,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite ter(tefNFTOKEN_IS_NOT_TRANSFERABLE)); // alice offers to sell the nft and becky accepts the offer. - uint256 const aliceSellOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)), - txflags(tfSellNFToken)); + uint256 const aliceSellOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(becky, aliceSellOfferIndex)); env.close(); @@ -1804,10 +1635,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice offers to buy the nft back from becky. becky accepts // the offer. - uint256 const aliceBuyOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)), - token::owner(becky)); + uint256 const aliceBuyOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)), token::owner(becky)); env.close(); env(token::acceptBuyOffer(becky, aliceBuyOfferIndex)); env.close(); @@ -1826,8 +1655,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, minter) == 0); - uint256 const nftMinterNoTransferID{ - token::getNextID(env, alice, 0u)}; + uint256 const nftMinterNoTransferID{token::getNextID(env, alice, 0u)}; env(token::mint(minter), token::issuer(alice)); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -1863,10 +1691,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter successfully offers their nft for sale. BEAST_EXPECT(ownerCount(env, minter) == 1); - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)), - txflags(tfSellNFToken)); + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -1900,10 +1726,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice can create an offer to buy the nft. BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const aliceBuyOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)), - token::owner(becky)); + uint256 const aliceBuyOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)), token::owner(becky)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -1917,10 +1741,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Now minter can create an offer to buy the nft. BEAST_EXPECT(ownerCount(env, minter) == 0); - uint256 const minterBuyOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)), - token::owner(becky)); + uint256 const minterBuyOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)), token::owner(becky)); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -1952,24 +1774,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // by anybody. { BEAST_EXPECT(ownerCount(env, alice) == 0); - uint256 const nftAliceID{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftAliceID{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 1); // Both alice and becky can make offers for alice's nft. - uint256 const aliceSellOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftAliceID, XRP(20)), - txflags(tfSellNFToken)); + uint256 const aliceSellOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftAliceID, XRP(20)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAliceID, XRP(21)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAliceID, XRP(21)), token::owner(alice)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); @@ -1980,10 +1797,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, becky) == 2); // becky offers to sell the nft. - uint256 const beckySellOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAliceID, XRP(22)), - txflags(tfSellNFToken)); + uint256 const beckySellOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAliceID, XRP(22)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, becky) == 3); @@ -1997,10 +1812,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, minter) == 1); // minter offers to sell the nft. - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftAliceID, XRP(23)), - txflags(tfSellNFToken)); + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftAliceID, XRP(23)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, becky) == 1); @@ -2021,7 +1834,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, becky) == 1); BEAST_EXPECT(ownerCount(env, minter) == 0); - // Just for tidyness, becky burns the token before shutting + // Just for tidiness, becky burns the token before shutting // things down. env(token::burn(becky, nftAliceID)); env.close(); @@ -2076,16 +1889,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, carol) == 1); BEAST_EXPECT(ownerCount(env, minter) == 1); - uint256 const nftID = - token::getNextID(env, alice, 0u, tfTransferable); + uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable); env(token::mint(alice), txflags(tfTransferable)); env.close(); // Becky buys the nft for XAU(10). Check balances. - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(10)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice)); env.close(); BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000)); BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000)); @@ -2096,10 +1906,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990)); // becky sells nft to carol. alice's balance should not change. - uint256 const beckySellOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(10)), - txflags(tfSellNFToken)); + uint256 const beckySellOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(10)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(carol, beckySellOfferIndex)); env.close(); @@ -2108,10 +1916,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990)); // minter buys nft from carol. alice's balance should not change. - uint256 const minterBuyOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(10)), - token::owner(carol)); + uint256 const minterBuyOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(10)), token::owner(carol)); env.close(); env(token::acceptBuyOffer(carol, minterBuyOfferIndex)); env.close(); @@ -2122,10 +1928,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter sells the nft to alice. gwXAU balances should finish // where they started. - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(10)), - txflags(tfSellNFToken)); + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(10)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, minterSellOfferIndex)); env.close(); @@ -2146,16 +1950,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Set the smallest possible transfer fee. { // An nft with a transfer fee of 1 basis point. - uint256 const nftID = - token::getNextID(env, alice, 0u, tfTransferable, 1); + uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1); env(token::mint(alice), txflags(tfTransferable), token::xferFee(1)); env.close(); // Becky buys the nft for XAU(10). Check balances. - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(10)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice)); env.close(); BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000)); BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000)); @@ -2166,10 +1967,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990)); // becky sells nft to carol. alice's balance goes up. - uint256 const beckySellOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(10)), - txflags(tfSellNFToken)); + uint256 const beckySellOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(10)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(carol, beckySellOfferIndex)); env.close(); @@ -2179,10 +1978,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990)); // minter buys nft from carol. alice's balance goes up. - uint256 const minterBuyOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(10)), - token::owner(carol)); + uint256 const minterBuyOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(10)), token::owner(carol)); env.close(); env(token::acceptBuyOffer(carol, minterBuyOfferIndex)); env.close(); @@ -2194,10 +1991,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter sells the nft to alice. Because alice is part of the // transaction no transfer fee is removed. - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(10)), - txflags(tfSellNFToken)); + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(10)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, minterSellOfferIndex)); env.close(); @@ -2236,18 +2031,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Make an nft with a transfer fee of 50%. - uint256 const nftID = token::getNextID( - env, alice, 0u, tfTransferable, maxTransferFee); - env(token::mint(alice), - txflags(tfTransferable), - token::xferFee(maxTransferFee)); + uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, maxTransferFee); + env(token::mint(alice), txflags(tfTransferable), token::xferFee(maxTransferFee)); env.close(); // Becky buys the nft for XAU(10). Check balances. - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(10)), - token::owner(alice)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice)); env.close(); BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000)); BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000)); @@ -2258,10 +2048,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990)); // becky sells nft to minter. alice's balance goes up. - uint256 const beckySellOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, gwXAU(100)), - txflags(tfSellNFToken)); + uint256 const beckySellOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, gwXAU(100)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(minter, beckySellOfferIndex)); env.close(); @@ -2271,10 +2059,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900)); // carol buys nft from minter. alice's balance goes up. - uint256 const carolBuyOfferIndex = - keylet::nftoffer(carol, env.seq(carol)).key; - env(token::createOffer(carol, nftID, gwXAU(10)), - token::owner(minter)); + uint256 const carolBuyOfferIndex = keylet::nftoffer(carol, env.seq(carol)).key; + env(token::createOffer(carol, nftID, gwXAU(10)), token::owner(minter)); env.close(); env(token::acceptBuyOffer(minter, carolBuyOfferIndex)); env.close(); @@ -2286,10 +2072,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // carol sells the nft to alice. Because alice is part of the // transaction no transfer fee is removed. - uint256 const carolSellOfferIndex = - keylet::nftoffer(carol, env.seq(carol)).key; - env(token::createOffer(carol, nftID, gwXAU(10)), - txflags(tfSellNFToken)); + uint256 const carolSellOfferIndex = keylet::nftoffer(carol, env.seq(carol)).key; + env(token::createOffer(carol, nftID, gwXAU(10)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, carolSellOfferIndex)); env.close(); @@ -2327,8 +2111,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.disableFeature(fixUniversalNumber); // An nft with a transfer fee of 1 basis point. - uint256 const nftID = - token::getNextID(env, alice, 0u, tfTransferable, 1); + uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1); env(token::mint(alice), txflags(tfTransferable), token::xferFee(1)); env.close(); @@ -2336,8 +2119,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice there should be no transfer fee. STAmount aliceBalance = env.balance(alice); STAmount minterBalance = env.balance(minter); - uint256 const minterBuyOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const minterBuyOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice)); env.close(); env(token::acceptBuyOffer(alice, minterBuyOfferIndex)); @@ -2351,8 +2133,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice does not get any transfer fee. auto pmt = NumberSwitchOver ? drops(50000) : drops(99999); STAmount carolBalance = env.balance(carol); - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(carol, minterSellOfferIndex)); @@ -2366,8 +2147,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // carol sells to becky. This is the smallest amount to pay for a // transfer that enables a transfer fee of 1 basis point. STAmount beckyBalance = env.balance(becky); - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; pmt = NumberSwitchOver ? drops(50001) : drops(100000); env(token::createOffer(becky, nftID, pmt), token::owner(carol)); env.close(); @@ -2387,8 +2167,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // of an IOU. { // An nft with a transfer fee of 1 basis point. - uint256 const nftID = - token::getNextID(env, alice, 0u, tfTransferable, 1); + uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1); env(token::mint(alice), txflags(tfTransferable), token::xferFee(1)); env.close(); @@ -2400,25 +2179,21 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(pay(becky, gw, env.balance(becky, gwXAU))); env.close(); - STAmount const startXAUBalance( - gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5); + STAmount const startXAUBalance(gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5); env(pay(gw, alice, startXAUBalance)); env(pay(gw, minter, startXAUBalance)); env(pay(gw, becky, startXAUBalance)); env.close(); // Here is the smallest expressible gwXAU amount. - STAmount tinyXAU( - gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset); + STAmount tinyXAU(gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset); // minter buys the nft for tinyXAU. Since the transfer involves // alice there should be no transfer fee. STAmount aliceBalance = env.balance(alice, gwXAU); STAmount minterBalance = env.balance(minter, gwXAU); - uint256 const minterBuyOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, tinyXAU), - token::owner(alice)); + uint256 const minterBuyOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, tinyXAU), token::owner(alice)); env.close(); env(token::acceptBuyOffer(alice, minterBuyOfferIndex)); env.close(); @@ -2429,10 +2204,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // minter sells to carol. STAmount carolBalance = env.balance(carol, gwXAU); - uint256 const minterSellOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, tinyXAU), - txflags(tfSellNFToken)); + uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, tinyXAU), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(carol, minterSellOfferIndex)); env.close(); @@ -2446,14 +2219,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // carol sells to becky. This is the smallest gwXAU amount // to pay for a transfer that enables a transfer fee of 1. - STAmount const cheapNFT( - gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5); + STAmount const cheapNFT(gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5); STAmount beckyBalance = env.balance(becky, gwXAU); - uint256 const beckyBuyOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, cheapNFT), - token::owner(carol)); + uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftID, cheapNFT), token::owner(carol)); env.close(); env(token::acceptBuyOffer(carol, beckyBuyOfferIndex)); env.close(); @@ -2515,29 +2285,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite else { std::stringstream ss; - ss << "Taxon recovery failed from nftID " - << to_string(nftID) << ". Expected: " << taxon + ss << "Taxon recovery failed from nftID " << to_string(nftID) << ". Expected: " << taxon << "; got: " << gotTaxon; fail(ss.str()); } }; uint256 const nftAliceID = token::getID( - env, - alice, - taxon, - rand_int(), - rand_int(), - rand_int()); + env, alice, taxon, rand_int(), rand_int(), rand_int()); check(taxon, nftAliceID); uint256 const nftBeckyID = token::getID( - env, - becky, - taxon, - rand_int(), - rand_int(), - rand_int()); + env, becky, taxon, rand_int(), rand_int(), rand_int()); check(taxon, nftBeckyID); } } @@ -2586,8 +2345,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite std::string uri; std::uint32_t taxon; - Entry(std::string uri_, std::uint32_t taxon_) - : uri(std::move(uri_)), taxon(taxon_) + Entry(std::string uri_, std::uint32_t taxon_) : uri(std::move(uri_)), taxon(taxon_) { } }; @@ -2630,12 +2388,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite sortedNFTs.reserve(nfts.size()); for (std::size_t i = 0; i < nfts.size(); ++i) sortedNFTs.push_back(nfts[i]); - std::sort( - sortedNFTs.begin(), - sortedNFTs.end(), - [](Json::Value const& lhs, Json::Value const& rhs) { - return lhs[jss::nft_serial] < rhs[jss::nft_serial]; - }); + std::sort(sortedNFTs.begin(), sortedNFTs.end(), [](Json::Value const& lhs, Json::Value const& rhs) { + return lhs[jss::nft_serial] < rhs[jss::nft_serial]; + }); for (std::size_t i = 0; i < entries.size(); ++i) { @@ -2675,39 +2430,24 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::setMinter(issuer, minter)); env.close(); - uint256 const nftokenID = - token::getNextID(env, issuer, 0, tfTransferable); - env(token::mint(minter, 0), - token::issuer(issuer), - txflags(tfTransferable)); + uint256 const nftokenID = token::getNextID(env, issuer, 0, tfTransferable); + env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable)); env.close(); // Test how adding a Destination field to an offer affects permissions // for canceling offers. { - uint256 const offerMinterToIssuer = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(issuer), - txflags(tfSellNFToken)); + uint256 const offerMinterToIssuer = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(issuer), txflags(tfSellNFToken)); - uint256 const offerMinterToBuyer = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(buyer), - txflags(tfSellNFToken)); + uint256 const offerMinterToBuyer = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); - uint256 const offerIssuerToMinter = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftokenID, drops(1)), - token::owner(minter), - token::destination(minter)); + uint256 const offerIssuerToMinter = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftokenID, drops(1)), token::owner(minter), token::destination(minter)); - uint256 const offerIssuerToBuyer = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftokenID, drops(1)), - token::owner(minter), - token::destination(buyer)); + uint256 const offerIssuerToBuyer = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftokenID, drops(1)), token::owner(minter), token::destination(buyer)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 2); @@ -2721,14 +2461,10 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Note that issuer does not have any special permissions regarding // offer cancellation. issuer cannot cancel an offer for an // NFToken they issued. - env(token::cancelOffer(issuer, {offerMinterToBuyer}), - ter(tecNO_PERMISSION)); - env(token::cancelOffer(buyer, {offerMinterToIssuer}), - ter(tecNO_PERMISSION)); - env(token::cancelOffer(buyer, {offerIssuerToMinter}), - ter(tecNO_PERMISSION)); - env(token::cancelOffer(minter, {offerIssuerToBuyer}), - ter(tecNO_PERMISSION)); + env(token::cancelOffer(issuer, {offerMinterToBuyer}), ter(tecNO_PERMISSION)); + env(token::cancelOffer(buyer, {offerMinterToIssuer}), ter(tecNO_PERMISSION)); + env(token::cancelOffer(buyer, {offerIssuerToMinter}), ter(tecNO_PERMISSION)); + env(token::cancelOffer(minter, {offerIssuerToBuyer}), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 2); BEAST_EXPECT(ownerCount(env, minter) == 3); @@ -2749,11 +2485,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Test how adding a Destination field to a sell offer affects // accepting that offer. { - uint256 const offerMinterSellsToBuyer = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(buyer), - txflags(tfSellNFToken)); + uint256 const offerMinterSellsToBuyer = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -2761,8 +2494,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // issuer cannot accept a sell offer where they are not the // destination. - env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer), - ter(tecNO_PERMISSION)); + env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -2779,11 +2511,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Test how adding a Destination field to a buy offer affects // accepting that offer. { - uint256 const offerMinterBuysFromBuyer = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::owner(buyer), - token::destination(buyer)); + uint256 const offerMinterBuysFromBuyer = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::owner(buyer), token::destination(buyer)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -2791,8 +2520,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // issuer cannot accept a buy offer where they are the // destination. - env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer), - ter(tecNO_PERMISSION)); + env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -2808,18 +2536,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // If a destination other than the NFToken owner is set, that // destination must act as a broker. The NFToken owner may not // simply accept the offer. - uint256 const offerBuyerBuysFromMinter = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID, drops(1)), - token::owner(minter), - token::destination(broker)); + uint256 const offerBuyerBuysFromMinter = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID, drops(1)), token::owner(minter), token::destination(broker)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 1); BEAST_EXPECT(ownerCount(env, buyer) == 1); - env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter), - ter(tecNO_PERMISSION)); + env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter), ter(tecNO_PERMISSION)); env.close(); // Clean up the unused offer. @@ -2833,16 +2557,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Show that a sell offer's Destination can broker that sell offer // to another account. { - uint256 const offerMinterToBroker = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(broker), - txflags(tfSellNFToken)); + uint256 const offerMinterToBroker = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(broker), txflags(tfSellNFToken)); - uint256 const offerBuyerToMinter = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID, drops(1)), - token::owner(minter)); + uint256 const offerBuyerToMinter = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID, drops(1)), token::owner(minter)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); @@ -2852,9 +2571,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // issuer cannot broker the offers, because they are not the // Destination. - env(token::brokerOffers( - issuer, offerBuyerToMinter, offerMinterToBroker), - ter(tecNO_PERMISSION)); + env(token::brokerOffers(issuer, offerBuyerToMinter, offerMinterToBroker), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -2863,8 +2580,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Since broker is the sell offer's destination, they can broker // the two offers. - env(token::brokerOffers( - broker, offerBuyerToMinter, offerMinterToBroker)); + env(token::brokerOffers(broker, offerBuyerToMinter, offerMinterToBroker)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 0); @@ -2875,21 +2591,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Destination doesn't match, but can complete if the Destination // does match. { - uint256 const offerBuyerToMinter = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID, drops(1)), - token::destination(minter), - txflags(tfSellNFToken)); + uint256 const offerBuyerToMinter = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID, drops(1)), token::destination(minter), txflags(tfSellNFToken)); - uint256 const offerMinterToBuyer = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::owner(buyer)); + uint256 const offerMinterToBuyer = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::owner(buyer)); - uint256 const offerIssuerToBuyer = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftokenID, drops(1)), - token::owner(buyer)); + uint256 const offerIssuerToBuyer = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftokenID, drops(1)), token::owner(buyer)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); @@ -2899,18 +2608,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // Cannot broker offers when the sell destination is not the // buyer. - env(token::brokerOffers( - broker, offerIssuerToBuyer, offerBuyerToMinter), - ter(tecNO_PERMISSION)); + env(token::brokerOffers(broker, offerIssuerToBuyer, offerBuyerToMinter), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); BEAST_EXPECT(ownerCount(env, minter) == 1); BEAST_EXPECT(ownerCount(env, buyer) == 2); - env(token::brokerOffers( - broker, offerMinterToBuyer, offerBuyerToMinter), - ter(tecNO_PERMISSION)); + env(token::brokerOffers(broker, offerMinterToBuyer, offerBuyerToMinter), ter(tecNO_PERMISSION)); env.close(); // Buyer is successful with acceptOffer. @@ -2938,24 +2643,16 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Show that if a buy and a sell offer both have the same destination, // then that destination can broker the offers. { - uint256 const offerMinterToBroker = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(broker), - txflags(tfSellNFToken)); + uint256 const offerMinterToBroker = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(broker), txflags(tfSellNFToken)); - uint256 const offerBuyerToBroker = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID, drops(1)), - token::owner(minter), - token::destination(broker)); + uint256 const offerBuyerToBroker = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID, drops(1)), token::owner(minter), token::destination(broker)); { // Cannot broker offers when the sell destination is not the // buyer or the broker. - env(token::brokerOffers( - issuer, offerBuyerToBroker, offerMinterToBroker), - ter(tecNO_PERMISSION)); + env(token::brokerOffers(issuer, offerBuyerToBroker, offerMinterToBroker), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -2963,8 +2660,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // Broker is successful if they are the destination of both offers. - env(token::brokerOffers( - broker, offerBuyerToBroker, offerMinterToBroker)); + env(token::brokerOffers(broker, offerBuyerToBroker, offerMinterToBroker)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 0); @@ -2979,19 +2675,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite using namespace test::jtx; - // test flag doesn't set unless amendment enabled - { - Env env{*this, features - disallowIncoming}; - Account const alice{"alice"}; - env.fund(XRP(10000), alice); - env(fset(alice, asfDisallowIncomingNFTokenOffer)); - env.close(); - auto const sle = env.le(alice); - uint32_t flags = sle->getFlags(); - BEAST_EXPECT(!(flags & lsfDisallowIncomingNFTokenOffer)); - } - - Env env{*this, features | disallowIncoming}; + Env env{*this, features}; Account const issuer{"issuer"}; Account const minter{"minter"}; @@ -3003,11 +2687,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::setMinter(issuer, minter)); env.close(); - uint256 const nftokenID = - token::getNextID(env, issuer, 0, tfTransferable); - env(token::mint(minter, 0), - token::issuer(issuer), - txflags(tfTransferable)); + uint256 const nftokenID = token::getNextID(env, issuer, 0, tfTransferable); + env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable)); env.close(); // enable flag @@ -3032,12 +2713,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // create offer (allowed now) then cancel { - uint256 const offerIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offerIndex = keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(buyer), - txflags(tfSellNFToken)); + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); env.close(); env(token::cancelOffer(minter, {offerIndex})); @@ -3046,12 +2724,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // create offer, enable flag, then cancel { - uint256 const offerIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offerIndex = keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(buyer), - txflags(tfSellNFToken)); + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); env.close(); env(fset(buyer, asfDisallowIncomingNFTokenOffer)); @@ -3066,12 +2741,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // create offer then transfer { - uint256 const offerIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offerIndex = keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID, drops(1)), - token::destination(buyer), - txflags(tfSellNFToken)); + env(token::createOffer(minter, nftokenID, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(buyer, offerIndex)); @@ -3086,17 +2758,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // a random offer to buy the token { - env(token::createOffer(alice, nftokenID, drops(1)), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::createOffer(alice, nftokenID, drops(1)), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); } // minter offer to buy the token { - env(token::createOffer(minter, nftokenID, drops(1)), - token::owner(buyer), - ter(tecNO_PERMISSION)); + env(token::createOffer(minter, nftokenID, drops(1)), token::owner(buyer), ter(tecNO_PERMISSION)); env.close(); } @@ -3106,17 +2774,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // enable flag env(fset(buyer, asfDisallowIncomingNFTokenOffer)); // a sell offer from the minter to the buyer should be rejected - env(token::mint(minter), - token::amount(drops(1)), - token::destination(buyer), - ter(tecNO_PERMISSION)); + env(token::mint(minter), token::amount(drops(1)), token::destination(buyer), ter(tecNO_PERMISSION)); env.close(); // disable flag env(fclear(buyer, asfDisallowIncomingNFTokenOffer)); - env(token::mint(minter), - token::amount(drops(1)), - token::destination(buyer)); + env(token::mint(minter), token::amount(drops(1)), token::destination(buyer)); env.close(); } } @@ -3142,53 +2805,43 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::setMinter(issuer, minter)); env.close(); - uint256 const nftokenID0 = - token::getNextID(env, issuer, 0, tfTransferable); - env(token::mint(minter, 0), - token::issuer(issuer), - txflags(tfTransferable)); + uint256 const nftokenID0 = token::getNextID(env, issuer, 0, tfTransferable); + env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable)); env.close(); - uint256 const nftokenID1 = - token::getNextID(env, issuer, 0, tfTransferable); - env(token::mint(minter, 0), - token::issuer(issuer), - txflags(tfTransferable)); + uint256 const nftokenID1 = token::getNextID(env, issuer, 0, tfTransferable); + env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable)); env.close(); + uint8_t issuerCount, minterCount, buyerCount; // Test how adding an Expiration field to an offer affects permissions // for cancelling offers. { std::uint32_t const expiration = lastClose(env) + 25; - uint256 const offerMinterToIssuer = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offerMinterToIssuer = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID0, drops(1)), token::destination(issuer), token::expiration(expiration), txflags(tfSellNFToken)); - uint256 const offerMinterToAnyone = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offerMinterToAnyone = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID0, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); - uint256 const offerIssuerToMinter = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftokenID0, drops(1)), - token::owner(minter), - token::expiration(expiration)); + uint256 const offerIssuerToMinter = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftokenID0, drops(1)), token::owner(minter), token::expiration(expiration)); - uint256 const offerBuyerToMinter = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, drops(1)), - token::owner(minter), - token::expiration(expiration)); + uint256 const offerBuyerToMinter = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, drops(1)), token::owner(minter), token::expiration(expiration)); env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 1); - BEAST_EXPECT(ownerCount(env, minter) == 3); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + issuerCount = 1; + minterCount = 3; + buyerCount = 1; + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Test who gets to cancel the offers. Anyone outside of the // offer-owner/destination pair should not be able to cancel @@ -3196,38 +2849,40 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // // Note that these are tec responses, so these transactions will // not be retried by the ledger. - env(token::cancelOffer(issuer, {offerMinterToAnyone}), - ter(tecNO_PERMISSION)); - env(token::cancelOffer(buyer, {offerIssuerToMinter}), - ter(tecNO_PERMISSION)); + env(token::cancelOffer(issuer, {offerMinterToAnyone}), ter(tecNO_PERMISSION)); + env(token::cancelOffer(buyer, {offerIssuerToMinter}), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(lastClose(env) < expiration); - BEAST_EXPECT(ownerCount(env, issuer) == 1); - BEAST_EXPECT(ownerCount(env, minter) == 3); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // The offer creator can cancel their own unexpired offer. env(token::cancelOffer(minter, {offerMinterToAnyone})); + minterCount--; // The destination of a sell offer can cancel the NFT owner's // unexpired offer. env(token::cancelOffer(issuer, {offerMinterToIssuer})); + minterCount--; // Close enough ledgers to get past the expiration. while (lastClose(env) < expiration) env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 1); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Anyone can cancel expired offers. env(token::cancelOffer(issuer, {offerBuyerToMinter})); + buyerCount--; env(token::cancelOffer(buyer, {offerIssuerToMinter})); + issuerCount--; env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // Show that: // 1. An unexpired sell offer with an expiration can be accepted. @@ -3236,64 +2891,86 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { std::uint32_t const expiration = lastClose(env) + 25; - uint256 const offer0 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offer0 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID0, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); + minterCount++; - uint256 const offer1 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const offer1 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID1, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); + minterCount++; env.close(); BEAST_EXPECT(lastClose(env) < expiration); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 3); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // Anyone can accept an unexpired sell offer. env(token::acceptSellOffer(buyer, offer0)); + minterCount--; + buyerCount++; // Close enough ledgers to get past the expiration. while (lastClose(env) < expiration) env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // No one can accept an expired sell offer. env(token::acceptSellOffer(buyer, offer1), ter(tecEXPIRED)); - env(token::acceptSellOffer(issuer, offer1), ter(tecEXPIRED)); + + // With fixExpiredNFTokenOfferRemoval amendment, the first accept + // attempt deletes the expired offer. Without the amendment, + // the offer remains and we can try to accept it again. + if (features[fixExpiredNFTokenOfferRemoval]) + { + // After amendment: offer was deleted by first accept attempt + minterCount--; + env(token::acceptSellOffer(issuer, offer1), ter(tecOBJECT_NOT_FOUND)); + } + else + { + // Before amendment: offer still exists, second accept also + // fails + env(token::acceptSellOffer(issuer, offer1), ter(tecEXPIRED)); + } env.close(); - // The expired sell offer is still in the ledger. - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + // Check if the expired sell offer behavior matches amendment status + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); - // Anyone can cancel the expired sell offer. - env(token::cancelOffer(issuer, {offer1})); - env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + if (!features[fixExpiredNFTokenOfferRemoval]) + { + // Before amendment: expired offer still exists and needs to be + // cancelled + env(token::cancelOffer(issuer, {offer1})); + env.close(); + minterCount--; + } + // Ensure that owner counts are correct with and without the + // amendment + BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0); + BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1); + BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1); // Transfer nftokenID0 back to minter so we start the next test in // a simple place. - uint256 const offerSellBack = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, XRP(0)), - txflags(tfSellNFToken), - token::destination(minter)); + uint256 const offerSellBack = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, XRP(0)), txflags(tfSellNFToken), token::destination(minter)); env.close(); env(token::acceptSellOffer(minter, offerSellBack)); + buyerCount--; env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // Show that: // 1. An unexpired buy offer with an expiration can be accepted. @@ -3303,19 +2980,17 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite std::uint32_t const expiration = lastClose(env) + 25; uint256 const offer0 = keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, drops(1)), - token::owner(minter), - token::expiration(expiration)); + env(token::createOffer(buyer, nftokenID0, drops(1)), token::owner(minter), token::expiration(expiration)); + buyerCount++; uint256 const offer1 = keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID1, drops(1)), - token::owner(minter), - token::expiration(expiration)); + env(token::createOffer(buyer, nftokenID1, drops(1)), token::owner(minter), token::expiration(expiration)); + buyerCount++; env.close(); BEAST_EXPECT(lastClose(env) < expiration); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // An unexpired buy offer can be accepted. env(token::acceptBuyOffer(minter, offer0)); @@ -3324,40 +2999,60 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite while (lastClose(env) < expiration) env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // An expired buy offer cannot be accepted. env(token::acceptBuyOffer(minter, offer1), ter(tecEXPIRED)); - env(token::acceptBuyOffer(issuer, offer1), ter(tecEXPIRED)); + + // With fixExpiredNFTokenOfferRemoval amendment, the first accept + // attempt deletes the expired offer. Without the amendment, + // the offer remains and we can try to accept it again. + if (features[fixExpiredNFTokenOfferRemoval]) + { + // After amendment: offer was deleted by first accept attempt + buyerCount--; + env(token::acceptBuyOffer(issuer, offer1), ter(tecOBJECT_NOT_FOUND)); + } + else + { + // Before amendment: offer still exists, second accept also + // fails + env(token::acceptBuyOffer(issuer, offer1), ter(tecEXPIRED)); + } env.close(); - // The expired buy offer is still in the ledger. - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + // Check if the expired buy offer behavior matches amendment status + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); - // Anyone can cancel the expired buy offer. - env(token::cancelOffer(issuer, {offer1})); - env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + if (!features[fixExpiredNFTokenOfferRemoval]) + { + // Before amendment: expired offer still exists and can be + // cancelled + env(token::cancelOffer(issuer, {offer1})); + env.close(); + buyerCount--; + } + // Ensure that owner counts are the same with and without the + // amendment + BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0); + BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1); + BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1); // Transfer nftokenID0 back to minter so we start the next test in // a simple place. - uint256 const offerSellBack = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, XRP(0)), - txflags(tfSellNFToken), - token::destination(minter)); + uint256 const offerSellBack = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, XRP(0)), txflags(tfSellNFToken), token::destination(minter)); env.close(); env(token::acceptSellOffer(minter, offerSellBack)); env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + buyerCount--; + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // Show that in brokered mode: // 1. An unexpired sell offer with an expiration can be accepted. @@ -3366,75 +3061,90 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { std::uint32_t const expiration = lastClose(env) + 25; - uint256 const sellOffer0 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const sellOffer0 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID0, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); + minterCount++; - uint256 const sellOffer1 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const sellOffer1 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID1, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); + minterCount++; - uint256 const buyOffer0 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, drops(1)), - token::owner(minter)); + uint256 const buyOffer0 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, drops(1)), token::owner(minter)); + buyerCount++; - uint256 const buyOffer1 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID1, drops(1)), - token::owner(minter)); + uint256 const buyOffer1 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID1, drops(1)), token::owner(minter)); + buyerCount++; env.close(); BEAST_EXPECT(lastClose(env) < expiration); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 3); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // An unexpired offer can be brokered. env(token::brokerOffers(issuer, buyOffer0, sellOffer0)); + minterCount--; // Close enough ledgers to get past the expiration. while (lastClose(env) < expiration) env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); // If the sell offer is expired it cannot be brokered. - env(token::brokerOffers(issuer, buyOffer1, sellOffer1), - ter(tecEXPIRED)); + env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(tecEXPIRED)); env.close(); - // The expired sell offer is still in the ledger. - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 2); + if (features[fixExpiredNFTokenOfferRemoval]) + { + // With amendment: expired offers are deleted + minterCount--; + } - // Anyone can cancel the expired sell offer. - env(token::cancelOffer(buyer, {buyOffer1, sellOffer1})); + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); + + if (features[fixExpiredNFTokenOfferRemoval]) + { + // The buy offer was deleted, so no need to cancel it + // The sell offer still exists, so we can cancel it + env(token::cancelOffer(buyer, {buyOffer1})); + buyerCount--; + } + else + { + // Anyone can cancel the expired offers + env(token::cancelOffer(buyer, {buyOffer1, sellOffer1})); + minterCount--; + buyerCount--; + } env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + // Ensure that owner counts are the same with and without the + // amendment + BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0); + BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1); + BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1); // Transfer nftokenID0 back to minter so we start the next test in // a simple place. - uint256 const offerSellBack = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, XRP(0)), - txflags(tfSellNFToken), - token::destination(minter)); + uint256 const offerSellBack = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, XRP(0)), txflags(tfSellNFToken), token::destination(minter)); env.close(); env(token::acceptSellOffer(minter, offerSellBack)); env.close(); - BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 1); - BEAST_EXPECT(ownerCount(env, buyer) == 0); + buyerCount--; + BEAST_EXPECT(ownerCount(env, issuer) == issuerCount); + BEAST_EXPECT(ownerCount(env, minter) == minterCount); + BEAST_EXPECT(ownerCount(env, buyer) == buyerCount); } // Show that in brokered mode: // 1. An unexpired buy offer with an expiration can be accepted. @@ -3443,27 +3153,17 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { std::uint32_t const expiration = lastClose(env) + 25; - uint256 const sellOffer0 = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID0, drops(1)), - txflags(tfSellNFToken)); + uint256 const sellOffer0 = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID0, drops(1)), txflags(tfSellNFToken)); - uint256 const sellOffer1 = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftokenID1, drops(1)), - txflags(tfSellNFToken)); + uint256 const sellOffer1 = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftokenID1, drops(1)), txflags(tfSellNFToken)); - uint256 const buyOffer0 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, drops(1)), - token::expiration(expiration), - token::owner(minter)); + uint256 const buyOffer0 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, drops(1)), token::expiration(expiration), token::owner(minter)); - uint256 const buyOffer1 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID1, drops(1)), - token::expiration(expiration), - token::owner(minter)); + uint256 const buyOffer1 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID1, drops(1)), token::expiration(expiration), token::owner(minter)); env.close(); BEAST_EXPECT(lastClose(env) < expiration); @@ -3482,18 +3182,28 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, minter) == 2); BEAST_EXPECT(ownerCount(env, buyer) == 2); - // If the buy offer is expired it cannot be brokered. - env(token::brokerOffers(issuer, buyOffer1, sellOffer1), - ter(tecEXPIRED)); + env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(tecEXPIRED)); env.close(); - // The expired buy offer is still in the ledger. BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 2); - - // Anyone can cancel the expired buy offer. - env(token::cancelOffer(minter, {buyOffer1, sellOffer1})); + if (features[fixExpiredNFTokenOfferRemoval]) + { + // After amendment: expired offers were deleted during broker + // attempt + BEAST_EXPECT(ownerCount(env, minter) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == 1); + // The buy offer was deleted, so no need to cancel it + // The sell offer still exists, so we can cancel it + env(token::cancelOffer(minter, {sellOffer1})); + } + else + { + // Before amendment: expired offers still exist in ledger + BEAST_EXPECT(ownerCount(env, minter) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == 2); + // Anyone can cancel the expired offers + env(token::cancelOffer(minter, {buyOffer1, sellOffer1})); + } env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -3501,11 +3211,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Transfer nftokenID0 back to minter so we start the next test in // a simple place. - uint256 const offerSellBack = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, XRP(0)), - txflags(tfSellNFToken), - token::destination(minter)); + uint256 const offerSellBack = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, XRP(0)), txflags(tfSellNFToken), token::destination(minter)); env.close(); env(token::acceptSellOffer(minter, offerSellBack)); env.close(); @@ -3521,29 +3228,21 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { std::uint32_t const expiration = lastClose(env) + 25; - uint256 const sellOffer0 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const sellOffer0 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID0, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); - uint256 const sellOffer1 = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const sellOffer1 = keylet::nftoffer(minter, env.seq(minter)).key; env(token::createOffer(minter, nftokenID1, drops(1)), token::expiration(expiration), txflags(tfSellNFToken)); - uint256 const buyOffer0 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, drops(1)), - token::expiration(expiration), - token::owner(minter)); + uint256 const buyOffer0 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, drops(1)), token::expiration(expiration), token::owner(minter)); - uint256 const buyOffer1 = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID1, drops(1)), - token::expiration(expiration), - token::owner(minter)); + uint256 const buyOffer1 = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID1, drops(1)), token::expiration(expiration), token::owner(minter)); env.close(); BEAST_EXPECT(lastClose(env) < expiration); @@ -3562,18 +3261,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, minter) == 2); BEAST_EXPECT(ownerCount(env, buyer) == 2); - // If the offers are expired they cannot be brokered. - env(token::brokerOffers(issuer, buyOffer1, sellOffer1), - ter(tecEXPIRED)); + env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(tecEXPIRED)); env.close(); // The expired offers are still in the ledger. BEAST_EXPECT(ownerCount(env, issuer) == 0); - BEAST_EXPECT(ownerCount(env, minter) == 2); - BEAST_EXPECT(ownerCount(env, buyer) == 2); - - // Anyone can cancel the expired offers. - env(token::cancelOffer(issuer, {buyOffer1, sellOffer1})); + if (!features[fixExpiredNFTokenOfferRemoval]) + { + // Before amendment: expired offers still exist in ledger + BEAST_EXPECT(ownerCount(env, minter) == 2); + BEAST_EXPECT(ownerCount(env, buyer) == 2); + // Anyone can cancel the expired offers + env(token::cancelOffer(issuer, {buyOffer1, sellOffer1})); + } env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -3581,11 +3281,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Transfer nftokenID0 back to minter so we start the next test in // a simple place. - uint256 const offerSellBack = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftokenID0, XRP(0)), - txflags(tfSellNFToken), - token::destination(minter)); + uint256 const offerSellBack = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftokenID0, XRP(0)), txflags(tfSellNFToken), token::destination(minter)); env.close(); env(token::acceptSellOffer(minter, offerSellBack)); env.close(); @@ -3615,14 +3312,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::setMinter(alice, minter)); env.close(); - uint256 const nftokenID = - token::getNextID(env, alice, 0, tfTransferable); + uint256 const nftokenID = token::getNextID(env, alice, 0, tfTransferable); env(token::mint(alice, 0), txflags(tfTransferable)); env.close(); // Anyone can cancel an expired offer. - uint256 const expiredOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const expiredOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; env(token::createOffer(alice, nftokenID, XRP(1000)), txflags(tfSellNFToken), @@ -3631,8 +3326,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // The offer has not expired yet, so becky can't cancel it now. BEAST_EXPECT(ownerCount(env, alice) == 2); - env(token::cancelOffer(becky, {expiredOfferIndex}), - ter(tecNO_PERMISSION)); + env(token::cancelOffer(becky, {expiredOfferIndex}), ter(tecNO_PERMISSION)); env.close(); // Close a couple of ledgers and advance the time. Then becky @@ -3645,18 +3339,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Create a couple of offers with a destination. Those offers // should be cancellable by the creator and the destination. - uint256 const dest1OfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const dest1OfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftokenID, XRP(1000)), - token::destination(becky), - txflags(tfSellNFToken)); + env(token::createOffer(alice, nftokenID, XRP(1000)), token::destination(becky), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); // Minter can't cancel that offer, but becky (the destination) can. - env(token::cancelOffer(minter, {dest1OfferIndex}), - ter(tecNO_PERMISSION)); + env(token::cancelOffer(minter, {dest1OfferIndex}), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); @@ -3665,12 +3355,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 1); // alice can cancel her own offer, even if becky is the destination. - uint256 const dest2OfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const dest2OfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftokenID, XRP(1000)), - token::destination(becky), - txflags(tfSellNFToken)); + env(token::createOffer(alice, nftokenID, XRP(1000)), token::destination(becky), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 2); @@ -3681,26 +3368,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // The issuer has no special permissions regarding offer cancellation. // Minter creates a token with alice as issuer. alice cannot cancel // minter's offer. - uint256 const mintersNFTokenID = - token::getNextID(env, alice, 0, tfTransferable); - env(token::mint(minter, 0), - token::issuer(alice), - txflags(tfTransferable)); + uint256 const mintersNFTokenID = token::getNextID(env, alice, 0, tfTransferable); + env(token::mint(minter, 0), token::issuer(alice), txflags(tfTransferable)); env.close(); - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, mintersNFTokenID, XRP(1000)), - txflags(tfSellNFToken)); + env(token::createOffer(minter, mintersNFTokenID, XRP(1000)), txflags(tfSellNFToken)); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 2); // Nobody other than minter should be able to cancel minter's offer. - env(token::cancelOffer(alice, {minterOfferIndex}), - ter(tecNO_PERMISSION)); - env(token::cancelOffer(becky, {minterOfferIndex}), - ter(tecNO_PERMISSION)); + env(token::cancelOffer(alice, {minterOfferIndex}), ter(tecNO_PERMISSION)); + env(token::cancelOffer(becky, {minterOfferIndex}), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 2); @@ -3742,20 +3422,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite for (uint32_t i = 0; i < maxTokenOfferCancelCount + 1; ++i) { Account const nftAcct(std::string("nftAcct") + std::to_string(i)); - Account const offerAcct( - std::string("offerAcct") + std::to_string(i)); + Account const offerAcct(std::string("offerAcct") + std::to_string(i)); env.fund(XRP(1000), nftAcct, offerAcct); env.close(); - uint256 const nftokenID = - token::getNextID(env, nftAcct, 0, tfTransferable); - env(token::mint(nftAcct, 0), - token::uri(uri), - txflags(tfTransferable)); + uint256 const nftokenID = token::getNextID(env, nftAcct, 0, tfTransferable); + env(token::mint(nftAcct, 0), token::uri(uri), txflags(tfTransferable)); env.close(); - offerIndexes.push_back( - keylet::nftoffer(offerAcct, env.seq(offerAcct)).key); + offerIndexes.push_back(keylet::nftoffer(offerAcct, env.seq(offerAcct)).key); env(token::createOffer(offerAcct, nftokenID, drops(1)), token::owner(nftAcct), token::expiration(lastClose(env) + 5)); @@ -3786,16 +3461,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // But alice adds a sell offer to the list... { - uint256 const nftokenID = - token::getNextID(env, alice, 0, tfTransferable); - env(token::mint(alice, 0), - token::uri(uri), - txflags(tfTransferable)); + uint256 const nftokenID = token::getNextID(env, alice, 0, tfTransferable); + env(token::mint(alice, 0), token::uri(uri), txflags(tfTransferable)); env.close(); offerIndexes.push_back(keylet::nftoffer(alice, env.seq(alice)).key); - env(token::createOffer(alice, nftokenID, drops(1)), - txflags(tfSellNFToken)); + env(token::createOffer(alice, nftokenID, drops(1)), txflags(tfSellNFToken)); env.close(); // alice's owner count should now to 2 for the nft and the offer. @@ -3867,20 +3538,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Lambda to check owner count of all accounts is one. auto checkOwnerCountIsOne = - [this, &env]( - std::initializer_list> - accounts, - int line) { + [this, &env](std::initializer_list> accounts, int line) { for (Account const& acct : accounts) { - if (std::uint32_t ownerCount = - test::jtx::ownerCount(env, acct); - ownerCount != 1) + if (std::uint32_t ownerCount = test::jtx::ownerCount(env, acct); ownerCount != 1) { std::stringstream ss; - ss << "Account " << acct.human() - << " expected ownerCount == 1. Got " - << ownerCount; + ss << "Account " << acct.human() << " expected ownerCount == 1. Got " << ownerCount; fail(ss.str(), __FILE__, line); } } @@ -3888,12 +3552,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Lambda that mints an NFT and returns the nftID. auto mintNFT = [&env, &issuer, &minter](std::uint16_t xferFee = 0) { - uint256 const nftID = - token::getNextID(env, issuer, 0, tfTransferable, xferFee); - env(token::mint(minter, 0), - token::issuer(issuer), - token::xferFee(xferFee), - txflags(tfTransferable)); + uint256 const nftID = token::getNextID(env, issuer, 0, tfTransferable, xferFee); + env(token::mint(minter, 0), token::issuer(issuer), token::xferFee(xferFee), txflags(tfTransferable)); env.close(); return nftID; }; @@ -3909,18 +3569,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); // buyer creates their offer. Note: a buy offer can never // offer zero. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(1)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter)); env.close(); auto const minterBalance = env.balance(minter); @@ -3929,8 +3585,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const issuerBalance = env.balance(issuer); // Broker charges no brokerFee. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex)); env.close(); // Note that minter's XRP balance goes up even though they @@ -3956,23 +3611,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); // buyer creates their offer. Note: a buy offer can never // offer zero. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(1)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter)); env.close(); // Broker attempts to charge a 1.1 XRP brokerFee and fails. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(XRP(1.1)), ter(tecINSUFFICIENT_PAYMENT)); env.close(); @@ -3983,17 +3633,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const issuerBalance = env.balance(issuer); // Broker charges a 0.5 XRP brokerFee. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - token::brokerFee(XRP(0.5))); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(XRP(0.5))); env.close(); // Note that minter's XRP balance goes up even though they // requested XRP(0). BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5)); BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1)); - BEAST_EXPECT( - env.balance(broker) == brokerBalance + XRP(0.5) - baseFee); + BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.5) - baseFee); BEAST_EXPECT(env.balance(issuer) == issuerBalance); // Burn the NFT so the next test starts with a clean state. @@ -4012,18 +3659,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(maxTransferFee); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); // buyer creates their offer. Note: a buy offer can never // offer zero. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(1)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter)); env.close(); auto const minterBalance = env.balance(minter); @@ -4032,8 +3675,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const issuerBalance = env.balance(issuer); // Broker charges no brokerFee. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex)); env.close(); // Note that minter's XRP balance goes up even though they @@ -4059,18 +3701,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(maxTransferFee); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, XRP(0)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken)); env.close(); // buyer creates their offer. Note: a buy offer can never // offer zero. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, XRP(1)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter)); env.close(); auto const minterBalance = env.balance(minter); @@ -4079,9 +3717,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const issuerBalance = env.balance(issuer); // Broker charges a 0.75 XRP brokerFee. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - token::brokerFee(XRP(0.75))); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(XRP(0.75))); env.close(); // Note that, with a 50% transfer fee, issuer gets 1/2 of what's @@ -4089,8 +3725,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // remainder after both broker and minter take their cuts BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125)); BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1)); - BEAST_EXPECT( - env.balance(broker) == brokerBalance + XRP(0.75) - baseFee); + BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.75) - baseFee); BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125)); // Burn the NFT so the next test starts with a clean state. @@ -4102,10 +3737,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // gwXAU(amount). auto setXAUBalance = [this, &gw, &gwXAU, &env]( - std::initializer_list> - accounts, - int amount, - int line) { + std::initializer_list> accounts, int amount, int line) { for (Account const& acct : accounts) { auto const xauAmt = gwXAU(amount); @@ -4123,8 +3755,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite if (env.balance(acct, gwXAU) != xauAmt) { std::stringstream ss; - ss << "Unable to set " << acct.human() - << " account balance to gwXAU(" << amount << ")"; + ss << "Unable to set " << acct.human() << " account balance to gwXAU(" << amount << ")"; this->fail(ss.str(), __FILE__, line); } } @@ -4139,25 +3770,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(1000)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(1000)), txflags(tfSellNFToken)); env.close(); { // buyer creates an offer for more XAU than they currently // own. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1001)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1001)), token::owner(minter)); env.close(); // broker attempts to broker the offers but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); // Cancel buyer's bad offer so the next test starts in a @@ -4168,16 +3793,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // buyer creates an offer for less that what minter is // asking. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(999)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(999)), token::owner(minter)); env.close(); // broker attempts to broker the offers but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - ter(tecINSUFFICIENT_PAYMENT)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), ter(tecINSUFFICIENT_PAYMENT)); env.close(); // Cancel buyer's bad offer so the next test starts in a @@ -4187,22 +3808,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // buyer creates a large enough offer. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1000)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter)); env.close(); // Broker attempts to charge a brokerFee but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(gwXAU(0.1)), ter(tecINSUFFICIENT_PAYMENT)); env.close(); // broker charges no brokerFee and succeeds. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); @@ -4228,24 +3845,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(maxTransferFee); // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(900)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken)); env.close(); { // buyer creates an offer for more XAU than they currently // own. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1001)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1001)), token::owner(minter)); env.close(); // broker attempts to broker the offers but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); // Cancel buyer's bad offer so the next test starts in a @@ -4256,16 +3867,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // buyer creates an offer for less that what minter is // asking. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(899)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(899)), token::owner(minter)); env.close(); // broker attempts to broker the offers but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - ter(tecINSUFFICIENT_PAYMENT)); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), ter(tecINSUFFICIENT_PAYMENT)); env.close(); // Cancel buyer's bad offer so the next test starts in a @@ -4274,25 +3881,20 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); } // buyer creates a large enough offer. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1000)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter)); env.close(); // Broker attempts to charge a brokerFee larger than the // difference between the two offers but cannot. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(gwXAU(101)), ter(tecINSUFFICIENT_PAYMENT)); env.close(); // broker charges the full difference between the two offers and // succeeds. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - token::brokerFee(gwXAU(100))); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(gwXAU(100))); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); @@ -4318,25 +3920,19 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(maxTransferFee / 2); // 25% // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(900)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken)); env.close(); // buyer creates a large enough offer. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1000)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter)); env.close(); // broker charges half difference between the two offers and // succeeds. 25% of the remaining difference goes to issuer. // The rest goes to minter. - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - token::brokerFee(gwXAU(50))); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(gwXAU(50))); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); @@ -4360,22 +3956,16 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite uint256 const nftID = mintNFT(maxTransferFee / 2); // 25% // minter creates their offer. - uint256 const minterOfferIndex = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, gwXAU(900)), - txflags(tfSellNFToken)); + uint256 const minterOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken)); env.close(); // buyer creates a large enough offer. - uint256 const buyOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID, gwXAU(1000)), - token::owner(minter)); + uint256 const buyOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter)); env.close(); - env(token::brokerOffers( - broker, buyOfferIndex, minterOfferIndex), - token::brokerFee(gwXAU(50))); + env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex), token::brokerFee(gwXAU(50))); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); BEAST_EXPECT(ownerCount(env, minter) == 1); @@ -4420,11 +4010,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(nftCount(env, buyer2) == 0); // Both buyer1 and buyer2 create buy offers for nftId. - uint256 const buyer1OfferIndex = - keylet::nftoffer(buyer1, env.seq(buyer1)).key; + uint256 const buyer1OfferIndex = keylet::nftoffer(buyer1, env.seq(buyer1)).key; env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer)); - uint256 const buyer2OfferIndex = - keylet::nftoffer(buyer2, env.seq(buyer2)).key; + uint256 const buyer2OfferIndex = keylet::nftoffer(buyer2, env.seq(buyer2)).key; env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer)); env.close(); @@ -4434,11 +4022,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // returned, so we skip the marker stuff. Json::Value params; params[jss::nft_id] = to_string(nftId); - Json::Value buyOffers = - env.rpc("json", "nft_buy_offers", to_string(params)); + Json::Value buyOffers = env.rpc("json", "nft_buy_offers", to_string(params)); - if (buyOffers.isMember(jss::result) && - buyOffers[jss::result].isMember(jss::offers)) + if (buyOffers.isMember(jss::result) && buyOffers[jss::result].isMember(jss::offers)) return buyOffers[jss::result][jss::offers].size(); return 0; @@ -4507,9 +4093,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // NFTokenMint BEAST_EXPECT(ownerCount(env, issuer) == 10); uint256 const nftId{token::getNextID(env, issuer, 0u, tfTransferable)}; - env(token::mint(issuer, 0u), - txflags(tfTransferable), - ticket::use(issuerTicketSeq++)); + env(token::mint(issuer, 0u), txflags(tfTransferable), ticket::use(issuerTicketSeq++)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 10); BEAST_EXPECT(ticketCount(env, issuer) == 9); @@ -4517,32 +4101,26 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // NFTokenCreateOffer BEAST_EXPECT(ownerCount(env, buyer) == 10); uint256 const offerIndex0 = keylet::nftoffer(buyer, buyerTicketSeq).key; - env(token::createOffer(buyer, nftId, XRP(1)), - token::owner(issuer), - ticket::use(buyerTicketSeq++)); + env(token::createOffer(buyer, nftId, XRP(1)), token::owner(issuer), ticket::use(buyerTicketSeq++)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 10); BEAST_EXPECT(ticketCount(env, buyer) == 9); // NFTokenCancelOffer - env(token::cancelOffer(buyer, {offerIndex0}), - ticket::use(buyerTicketSeq++)); + env(token::cancelOffer(buyer, {offerIndex0}), ticket::use(buyerTicketSeq++)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 8); BEAST_EXPECT(ticketCount(env, buyer) == 8); // NFTokenCreateOffer. buyer tries again. uint256 const offerIndex1 = keylet::nftoffer(buyer, buyerTicketSeq).key; - env(token::createOffer(buyer, nftId, XRP(2)), - token::owner(issuer), - ticket::use(buyerTicketSeq++)); + env(token::createOffer(buyer, nftId, XRP(2)), token::owner(issuer), ticket::use(buyerTicketSeq++)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 8); BEAST_EXPECT(ticketCount(env, buyer) == 7); // NFTokenAcceptOffer. issuer accepts buyer's offer. - env(token::acceptBuyOffer(issuer, offerIndex1), - ticket::use(issuerTicketSeq++)); + env(token::acceptBuyOffer(issuer, offerIndex1), ticket::use(issuerTicketSeq++)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 8); BEAST_EXPECT(ownerCount(env, buyer) == 8); @@ -4591,9 +4169,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); uint256 const nftId{token::getNextID(env, issuer, 0u, tfTransferable)}; - env(token::mint(minter, 0u), - token::issuer(issuer), - txflags(tfTransferable)); + env(token::mint(minter, 0u), token::issuer(issuer), txflags(tfTransferable)); env.close(); // At the moment issuer and minter cannot delete themselves. @@ -4612,8 +4188,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter)); env.close(); - uint256 const carlaOfferIndex = - keylet::nftoffer(carla, env.seq(carla)).key; + uint256 const carlaOfferIndex = keylet::nftoffer(carla, env.seq(carla)).key; env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter)); env.close(); @@ -4682,11 +4257,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // A lambda that validates nft_XXX_offers query responses. - auto checkOffers = [this, &env, &nftID]( - char const* request, - int expectCount, - int expectMarkerCount, - int line) { + auto checkOffers = [this, &env, &nftID](char const* request, int expectCount, int expectMarkerCount, int line) { int markerCount = 0; Json::Value allOffers(Json::arrayValue); std::string marker; @@ -4706,21 +4277,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // If there are no offers for the NFT we get an error if (expectCount == 0) { - if (expect( - nftOffers.isMember(jss::result), - "expected \"result\"", - __FILE__, - line)) + if (expect(nftOffers.isMember(jss::result), "expected \"result\"", __FILE__, line)) { - if (expect( - nftOffers[jss::result].isMember(jss::error), - "expected \"error\"", - __FILE__, - line)) + if (expect(nftOffers[jss::result].isMember(jss::error), "expected \"error\"", __FILE__, line)) { expect( - nftOffers[jss::result][jss::error].asString() == - "objectNotFound", + nftOffers[jss::result][jss::error].asString() == "objectNotFound", "expected \"objectNotFound\"", __FILE__, line); @@ -4730,11 +4292,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } marker.clear(); - if (expect( - nftOffers.isMember(jss::result), - "expected \"result\"", - __FILE__, - line)) + if (expect(nftOffers.isMember(jss::result), "expected \"result\"", __FILE__, line)) { Json::Value& result = nftOffers[jss::result]; @@ -4744,11 +4302,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite marker = result[jss::marker].asString(); } - if (expect( - result.isMember(jss::offers), - "expected \"offers\"", - __FILE__, - line)) + if (expect(result.isMember(jss::offers), "expected \"offers\"", __FILE__, line)) { Json::Value& someOffers = result[jss::offers]; for (std::size_t i = 0; i < someOffers.size(); ++i) @@ -4758,16 +4312,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } while (!marker.empty()); // Verify the contents of allOffers makes sense. - expect( - allOffers.size() == expectCount, - "Unexpected returned offer count", - __FILE__, - line); - expect( - markerCount == expectMarkerCount, - "Unexpected marker count", - __FILE__, - line); + expect(allOffers.size() == expectCount, "Unexpected returned offer count", __FILE__, line); + expect(markerCount == expectMarkerCount, "Unexpected marker count", __FILE__, line); std::optional globalFlags; std::set offerIndexes; std::set amounts; @@ -4777,11 +4323,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite if (!globalFlags) globalFlags = offer[jss::flags].asInt(); - expect( - *globalFlags == offer[jss::flags].asInt(), - "Inconsistent flags returned", - __FILE__, - line); + expect(*globalFlags == offer[jss::flags].asInt(), "Inconsistent flags returned", __FILE__, line); // The test conditions should produce unique indexes and // amounts for all offers. @@ -4789,16 +4331,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite amounts.insert(offer[jss::amount].asString()); } - expect( - offerIndexes.size() == expectCount, - "Duplicate indexes returned?", - __FILE__, - line); - expect( - amounts.size() == expectCount, - "Duplicate amounts returned?", - __FILE__, - line); + expect(offerIndexes.size() == expectCount, "Duplicate indexes returned?", __FILE__, line); + expect(amounts.size() == expectCount, "Duplicate amounts returned?", __FILE__, line); }; // There are no sell offers. @@ -4806,20 +4340,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // A lambda that generates sell offers. STAmount sellPrice = XRP(0); - auto makeSellOffers = - [&env, &issuer, &nftID, &sellPrice](STAmount const& limit) { - // Save a little test time by not closing too often. - int offerCount = 0; - while (sellPrice < limit) - { - sellPrice += XRP(1); - env(token::createOffer(issuer, nftID, sellPrice), - txflags(tfSellNFToken)); - if (++offerCount % 10 == 0) - env.close(); - } - env.close(); - }; + auto makeSellOffers = [&env, &issuer, &nftID, &sellPrice](STAmount const& limit) { + // Save a little test time by not closing too often. + int offerCount = 0; + while (sellPrice < limit) + { + sellPrice += XRP(1); + env(token::createOffer(issuer, nftID, sellPrice), txflags(tfSellNFToken)); + if (++offerCount % 10 == 0) + env.close(); + } + env.close(); + }; // There is one sell offer. makeSellOffers(XRP(1)); @@ -4846,20 +4378,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // A lambda that generates buy offers. STAmount buyPrice = XRP(0); - auto makeBuyOffers = - [&env, &buyer, &issuer, &nftID, &buyPrice](STAmount const& limit) { - // Save a little test time by not closing too often. - int offerCount = 0; - while (buyPrice < limit) - { - buyPrice += XRP(1); - env(token::createOffer(buyer, nftID, buyPrice), - token::owner(issuer)); - if (++offerCount % 10 == 0) - env.close(); - } - env.close(); - }; + auto makeBuyOffers = [&env, &buyer, &issuer, &nftID, &buyPrice](STAmount const& limit) { + // Save a little test time by not closing too often. + int offerCount = 0; + while (buyPrice < limit) + { + buyPrice += XRP(1); + env(token::createOffer(buyer, nftID, buyPrice), token::owner(issuer)); + if (++offerCount % 10 == 0) + env.close(); + } + env.close(); + }; // There is one buy offer; makeBuyOffers(XRP(1)); @@ -4909,46 +4439,32 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Create an NFT that we'll make XRP offers for. - uint256 const nftID0{ - token::getNextID(env, issuer, 0u, tfTransferable)}; + uint256 const nftID0{token::getNextID(env, issuer, 0u, tfTransferable)}; env(token::mint(issuer, 0), txflags(tfTransferable)); env.close(); // Create an NFT that we'll make IOU offers for. - uint256 const nftID1{ - token::getNextID(env, issuer, 1u, tfTransferable)}; + uint256 const nftID1{token::getNextID(env, issuer, 1u, tfTransferable)}; env(token::mint(issuer, 1), txflags(tfTransferable)); env.close(); TER const offerCreateTER = temBAD_AMOUNT; // Make offers with negative amounts for the NFTs - uint256 const sellNegXrpOfferIndex = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftID0, XRP(-2)), - txflags(tfSellNFToken), - ter(offerCreateTER)); + uint256 const sellNegXrpOfferIndex = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftID0, XRP(-2)), txflags(tfSellNFToken), ter(offerCreateTER)); env.close(); - uint256 const sellNegIouOfferIndex = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftID1, gwXAU(-2)), - txflags(tfSellNFToken), - ter(offerCreateTER)); + uint256 const sellNegIouOfferIndex = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftID1, gwXAU(-2)), txflags(tfSellNFToken), ter(offerCreateTER)); env.close(); - uint256 const buyNegXrpOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID0, XRP(-1)), - token::owner(issuer), - ter(offerCreateTER)); + uint256 const buyNegXrpOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID0, XRP(-1)), token::owner(issuer), ter(offerCreateTER)); env.close(); - uint256 const buyNegIouOfferIndex = - keylet::nftoffer(buyer, env.seq(buyer)).key; - env(token::createOffer(buyer, nftID1, gwXAU(-1)), - token::owner(issuer), - ter(offerCreateTER)); + uint256 const buyNegIouOfferIndex = keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::createOffer(buyer, nftID1, gwXAU(-1)), token::owner(issuer), ter(offerCreateTER)); env.close(); { @@ -4956,32 +4472,24 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite TER const offerAcceptTER = tecOBJECT_NOT_FOUND; // Sell offers. - env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex), - ter(offerAcceptTER)); + env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex), ter(offerAcceptTER)); env.close(); - env(token::acceptSellOffer(buyer, sellNegIouOfferIndex), - ter(offerAcceptTER)); + env(token::acceptSellOffer(buyer, sellNegIouOfferIndex), ter(offerAcceptTER)); env.close(); // Buy offers. - env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex), - ter(offerAcceptTER)); + env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex), ter(offerAcceptTER)); env.close(); - env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex), - ter(offerAcceptTER)); + env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex), ter(offerAcceptTER)); env.close(); } { TER const offerAcceptTER = tecOBJECT_NOT_FOUND; // Brokered offers. - env(token::brokerOffers( - gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex), - ter(offerAcceptTER)); + env(token::brokerOffers(gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex), ter(offerAcceptTER)); env.close(); - env(token::brokerOffers( - gw, buyNegIouOfferIndex, sellNegIouOfferIndex), - ter(offerAcceptTER)); + env(token::brokerOffers(gw, buyNegIouOfferIndex, sellNegIouOfferIndex), ter(offerAcceptTER)); env.close(); } } @@ -4993,8 +4501,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.fund(XRP(1000000), issuer, buyer); // Create an NFT that we'll make offers for. - uint256 const nftID{ - token::getNextID(env, issuer, 0u, tfTransferable)}; + uint256 const nftID{token::getNextID(env, issuer, 0u, tfTransferable)}; env(token::mint(issuer, 0), txflags(tfTransferable)); env.close(); @@ -5040,15 +4547,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(rate(gw, 1.02)); env.close(); - auto expectInitialState = [this, - &env, - &buyer, - &minter, - &secondarySeller, - &broker, - &gw, - &gwXAU, - &gwXPB]() { + auto expectInitialState = [this, &env, &buyer, &minter, &secondarySeller, &broker, &gw, &gwXAU, &gwXPB]() { // Buyer should have XAU 1000, XPB 0 // Minter should have XAU 0, XPB 0 // Secondary seller should have XAU 0, XPB 0 @@ -5065,107 +4564,80 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(gw, buyer["XPB"]) == gwXPB(0)); BEAST_EXPECT(env.balance(gw, minter["XAU"]) == gwXAU(0)); BEAST_EXPECT(env.balance(gw, minter["XPB"]) == gwXPB(0)); - BEAST_EXPECT( - env.balance(gw, secondarySeller["XAU"]) == gwXAU(0)); - BEAST_EXPECT( - env.balance(gw, secondarySeller["XPB"]) == gwXPB(0)); + BEAST_EXPECT(env.balance(gw, secondarySeller["XAU"]) == gwXAU(0)); + BEAST_EXPECT(env.balance(gw, secondarySeller["XPB"]) == gwXPB(0)); BEAST_EXPECT(env.balance(gw, broker["XAU"]) == gwXAU(-5000)); BEAST_EXPECT(env.balance(gw, broker["XPB"]) == gwXPB(0)); }; - auto reinitializeTrustLineBalances = [&expectInitialState, - &env, - &buyer, - &minter, - &secondarySeller, - &broker, - &gw, - &gwXAU, - &gwXPB]() { - if (auto const difference = - gwXAU(1000) - env.balance(buyer, gwXAU); - difference > gwXAU(0)) - env(pay(gw, buyer, difference)); - if (env.balance(buyer, gwXPB) > gwXPB(0)) - env(pay(buyer, gw, env.balance(buyer, gwXPB))); - if (env.balance(minter, gwXAU) > gwXAU(0)) - env(pay(minter, gw, env.balance(minter, gwXAU))); - if (env.balance(minter, gwXPB) > gwXPB(0)) - env(pay(minter, gw, env.balance(minter, gwXPB))); - if (env.balance(secondarySeller, gwXAU) > gwXAU(0)) - env( - pay(secondarySeller, - gw, - env.balance(secondarySeller, gwXAU))); - if (env.balance(secondarySeller, gwXPB) > gwXPB(0)) - env( - pay(secondarySeller, - gw, - env.balance(secondarySeller, gwXPB))); - auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU); - if (brokerDiff > gwXAU(0)) - env(pay(gw, broker, brokerDiff)); - else if (brokerDiff < gwXAU(0)) - { - brokerDiff.negate(); - env(pay(broker, gw, brokerDiff)); - } - if (env.balance(broker, gwXPB) > gwXPB(0)) - env(pay(broker, gw, env.balance(broker, gwXPB))); - env.close(); - expectInitialState(); - }; + auto reinitializeTrustLineBalances = + [&expectInitialState, &env, &buyer, &minter, &secondarySeller, &broker, &gw, &gwXAU, &gwXPB]() { + if (auto const difference = gwXAU(1000) - env.balance(buyer, gwXAU); difference > gwXAU(0)) + env(pay(gw, buyer, difference)); + if (env.balance(buyer, gwXPB) > gwXPB(0)) + env(pay(buyer, gw, env.balance(buyer, gwXPB))); + if (env.balance(minter, gwXAU) > gwXAU(0)) + env(pay(minter, gw, env.balance(minter, gwXAU))); + if (env.balance(minter, gwXPB) > gwXPB(0)) + env(pay(minter, gw, env.balance(minter, gwXPB))); + if (env.balance(secondarySeller, gwXAU) > gwXAU(0)) + env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXAU))); + if (env.balance(secondarySeller, gwXPB) > gwXPB(0)) + env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXPB))); + auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU); + if (brokerDiff > gwXAU(0)) + env(pay(gw, broker, brokerDiff)); + else if (brokerDiff < gwXAU(0)) + { + brokerDiff.negate(); + env(pay(broker, gw, brokerDiff)); + } + if (env.balance(broker, gwXPB) > gwXPB(0)) + env(pay(broker, gw, env.balance(broker, gwXPB))); + env.close(); + expectInitialState(); + }; auto mintNFT = [&env](Account const& minter, int transferFee = 0) { - uint256 const nftID = token::getNextID( - env, minter, 0, tfTransferable, transferFee); - env(token::mint(minter), - token::xferFee(transferFee), - txflags(tfTransferable)); + uint256 const nftID = token::getNextID(env, minter, 0, tfTransferable, transferFee); + env(token::mint(minter), token::xferFee(transferFee), txflags(tfTransferable)); env.close(); return nftID; }; - auto createBuyOffer = - [&env]( - Account const& offerer, - Account const& owner, - uint256 const& nftID, - STAmount const& amount, - std::optional const terCode = {}) { - uint256 const offerID = - keylet::nftoffer(offerer, env.seq(offerer)).key; - env(token::createOffer(offerer, nftID, amount), - token::owner(owner), - terCode ? ter(*terCode) - : ter(static_cast(tesSUCCESS))); - env.close(); - return offerID; - }; + auto createBuyOffer = [&env]( + Account const& offerer, + Account const& owner, + uint256 const& nftID, + STAmount const& amount, + std::optional const terCode = {}) { + uint256 const offerID = keylet::nftoffer(offerer, env.seq(offerer)).key; + env(token::createOffer(offerer, nftID, amount), + token::owner(owner), + terCode ? ter(*terCode) : ter(static_cast(tesSUCCESS))); + env.close(); + return offerID; + }; - auto createSellOffer = - [&env]( - Account const& offerer, - uint256 const& nftID, - STAmount const& amount, - std::optional const terCode = {}) { - uint256 const offerID = - keylet::nftoffer(offerer, env.seq(offerer)).key; - env(token::createOffer(offerer, nftID, amount), - txflags(tfSellNFToken), - terCode ? ter(*terCode) - : ter(static_cast(tesSUCCESS))); - env.close(); - return offerID; - }; + auto createSellOffer = [&env]( + Account const& offerer, + uint256 const& nftID, + STAmount const& amount, + std::optional const terCode = {}) { + uint256 const offerID = keylet::nftoffer(offerer, env.seq(offerer)).key; + env(token::createOffer(offerer, nftID, amount), + txflags(tfSellNFToken), + terCode ? ter(*terCode) : ter(static_cast(tesSUCCESS))); + env.close(); + return offerID; + }; { // Buyer attempts to send 100% of their balance of an IOU // (sellside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createSellOffer(minter, nftID, gwXAU(1000)); + auto const offerID = createSellOffer(minter, nftID, gwXAU(1000)); TER const sellTER = tecINSUFFICIENT_FUNDS; env(token::acceptSellOffer(buyer, offerID), ter(sellTER)); env.close(); @@ -5177,8 +4649,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // (buyside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createBuyOffer(buyer, minter, nftID, gwXAU(1000)); + auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000)); TER const sellTER = tecINSUFFICIENT_FUNDS; env(token::acceptBuyOffer(minter, offerID), ter(sellTER)); env.close(); @@ -5204,8 +4675,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // fee would be greater than the buyer's balance (buyside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createBuyOffer(buyer, minter, nftID, gwXAU(995)); + auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(995)); TER const sellTER = tecINSUFFICIENT_FUNDS; env(token::acceptBuyOffer(minter, offerID), ter(sellTER)); env.close(); @@ -5235,8 +4705,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // (buyside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createBuyOffer(buyer, minter, nftID, gwXAU(900)); + auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(900)); env(token::acceptBuyOffer(minter, offerID)); env.close(); @@ -5257,8 +4726,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); auto const nftID = mintNFT(minter); - auto const offerID = - createSellOffer(minter, nftID, gwXAU(1000)); + auto const offerID = createSellOffer(minter, nftID, gwXAU(1000)); env(token::acceptSellOffer(buyer, offerID)); env.close(); @@ -5279,8 +4747,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); auto const nftID = mintNFT(minter); - auto const offerID = - createBuyOffer(buyer, minter, nftID, gwXAU(1000)); + auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000)); env(token::acceptBuyOffer(minter, offerID)); env.close(); @@ -5295,8 +4762,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createSellOffer(minter, nftID, gwXAU(1000)); + auto const offerID = createSellOffer(minter, nftID, gwXAU(1000)); TER const sellTER = tesSUCCESS; env(token::acceptSellOffer(gw, offerID), ter(sellTER)); env.close(); @@ -5311,8 +4777,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const nftID = mintNFT(minter); TER const offerTER = tesSUCCESS; - auto const offerID = - createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER}); + auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER}); TER const sellTER = tesSUCCESS; env(token::acceptBuyOffer(minter, offerID), ter(sellTER)); env.close(); @@ -5325,8 +4790,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // than minter trusts (sellside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = - createSellOffer(minter, nftID, gwXAU(5000)); + auto const offerID = createSellOffer(minter, nftID, gwXAU(5000)); TER const sellTER = tesSUCCESS; env(token::acceptSellOffer(gw, offerID), ter(sellTER)); env.close(); @@ -5341,8 +4805,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto const nftID = mintNFT(minter); TER const offerTER = tesSUCCESS; - auto const offerID = - createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER}); + auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER}); TER const sellTER = tesSUCCESS; env(token::acceptBuyOffer(minter, offerID), ter(sellTER)); env.close(); @@ -5370,8 +4833,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite reinitializeTrustLineBalances(); auto const nftID = mintNFT(gw); - auto const offerID = - createBuyOffer(buyer, gw, nftID, gwXAU(1000)); + auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(1000)); env(token::acceptBuyOffer(gw, offerID)); env.close(); @@ -5385,8 +4847,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite reinitializeTrustLineBalances(); auto const nftID = mintNFT(gw); auto const offerID = createSellOffer(gw, nftID, gwXAU(2000)); - env(token::acceptSellOffer(buyer, offerID), - ter(static_cast(tecINSUFFICIENT_FUNDS))); + env(token::acceptSellOffer(buyer, offerID), ter(static_cast(tecINSUFFICIENT_FUNDS))); env.close(); expectInitialState(); } @@ -5396,10 +4857,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // (buyside) reinitializeTrustLineBalances(); auto const nftID = mintNFT(gw); - auto const offerID = - createBuyOffer(buyer, gw, nftID, gwXAU(2000)); - env(token::acceptBuyOffer(gw, offerID), - ter(static_cast(tecINSUFFICIENT_FUNDS))); + auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(2000)); + env(token::acceptBuyOffer(gw, offerID), ter(static_cast(tecINSUFFICIENT_FUNDS))); env.close(); expectInitialState(); } @@ -5409,8 +4868,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); auto const offerID = createSellOffer(minter, nftID, gwXPB(10)); - env(token::acceptSellOffer(buyer, offerID), - ter(static_cast(tecINSUFFICIENT_FUNDS))); + env(token::acceptSellOffer(buyer, offerID), ter(static_cast(tecINSUFFICIENT_FUNDS))); env.close(); expectInitialState(); } @@ -5419,14 +4877,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // have no trust line for and buyer has none of (buyside). reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const offerID = createBuyOffer( - buyer, - minter, - nftID, - gwXPB(10), - {static_cast(tecUNFUNDED_OFFER)}); - env(token::acceptBuyOffer(minter, offerID), - ter(static_cast(tecOBJECT_NOT_FOUND))); + auto const offerID = + createBuyOffer(buyer, minter, nftID, gwXPB(10), {static_cast(tecUNFUNDED_OFFER)}); + env(token::acceptBuyOffer(minter, offerID), ter(static_cast(tecOBJECT_NOT_FOUND))); env.close(); expectInitialState(); } @@ -5457,8 +4910,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); auto const nftID = mintNFT(minter); - auto const offerID = - createBuyOffer(buyer, minter, nftID, gwXPB(10)); + auto const offerID = createBuyOffer(buyer, minter, nftID, gwXPB(10)); env(token::acceptBuyOffer(minter, offerID)); env.close(); @@ -5475,14 +4927,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // secondarySeller has to sell it because transfer fees only // happen on secondary sales auto const nftID = mintNFT(minter, 3000); // 3% - auto const primaryOfferID = - createSellOffer(minter, nftID, XRP(0)); + auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0)); env(token::acceptSellOffer(secondarySeller, primaryOfferID)); env.close(); // now we can do a secondary sale - auto const offerID = - createSellOffer(secondarySeller, nftID, gwXAU(1000)); + auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(1000)); TER const sellTER = tecINSUFFICIENT_FUNDS; env(token::acceptSellOffer(buyer, offerID), ter(sellTER)); env.close(); @@ -5497,17 +4947,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // secondarySeller has to sell it because transfer fees only // happen on secondary sales auto const nftID = mintNFT(minter, 3000); // 3% - auto const primaryOfferID = - createSellOffer(minter, nftID, XRP(0)); + auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0)); env(token::acceptSellOffer(secondarySeller, primaryOfferID)); env.close(); // now we can do a secondary sale - auto const offerID = - createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000)); + auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000)); TER const sellTER = tecINSUFFICIENT_FUNDS; - env(token::acceptBuyOffer(secondarySeller, offerID), - ter(sellTER)); + env(token::acceptBuyOffer(secondarySeller, offerID), ter(sellTER)); env.close(); expectInitialState(); @@ -5520,14 +4967,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // secondarySeller has to sell it because transfer fees only // happen on secondary sales auto const nftID = mintNFT(minter, 3000); // 3% - auto const primaryOfferID = - createSellOffer(minter, nftID, XRP(0)); + auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0)); env(token::acceptSellOffer(secondarySeller, primaryOfferID)); env.close(); // now we can do a secondary sale - auto const offerID = - createSellOffer(secondarySeller, nftID, gwXAU(900)); + auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(900)); env(token::acceptSellOffer(buyer, offerID)); env.close(); @@ -5535,8 +4980,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873)); BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82)); BEAST_EXPECT(env.balance(gw, minter["XAU"]) == gwXAU(-27)); - BEAST_EXPECT( - env.balance(gw, secondarySeller["XAU"]) == gwXAU(-873)); + BEAST_EXPECT(env.balance(gw, secondarySeller["XAU"]) == gwXAU(-873)); BEAST_EXPECT(env.balance(gw, buyer["XAU"]) == gwXAU(-82)); } { @@ -5547,14 +4991,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // secondarySeller has to sell it because transfer fees only // happen on secondary sales auto const nftID = mintNFT(minter, 3000); // 3% - auto const primaryOfferID = - createSellOffer(minter, nftID, XRP(0)); + auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0)); env(token::acceptSellOffer(secondarySeller, primaryOfferID)); env.close(); // now we can do a secondary sale - auto const offerID = - createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900)); + auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900)); env(token::acceptBuyOffer(secondarySeller, offerID)); env.close(); @@ -5565,8 +5007,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // pays 900 plus 2% transfer fee on XAU - 918 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82)); BEAST_EXPECT(env.balance(gw, minter["XAU"]) == gwXAU(-27)); - BEAST_EXPECT( - env.balance(gw, secondarySeller["XAU"]) == gwXAU(-873)); + BEAST_EXPECT(env.balance(gw, secondarySeller["XAU"]) == gwXAU(-873)); BEAST_EXPECT(env.balance(gw, buyer["XAU"]) == gwXAU(-82)); } { @@ -5588,12 +5029,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite reinitializeTrustLineBalances(); auto const nftID = mintNFT(minter); - auto const sellOffer = - createSellOffer(minter, nftID, gwXAU(300)); - auto const buyOffer = - createBuyOffer(buyer, minter, nftID, gwXAU(500)); - env(token::brokerOffers(broker, buyOffer, sellOffer), - token::brokerFee(gwXAU(100))); + auto const sellOffer = createSellOffer(minter, nftID, gwXAU(300)); + auto const buyOffer = createBuyOffer(buyer, minter, nftID, gwXAU(500)); + env(token::brokerOffers(broker, buyOffer, sellOffer), token::brokerFee(gwXAU(100))); env.close(); BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400)); @@ -5624,18 +5062,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // secondarySeller has to sell it because transfer fees only // happen on secondary sales auto const nftID = mintNFT(minter, 3000); // 3% - auto const primaryOfferID = - createSellOffer(minter, nftID, XRP(0)); + auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0)); env(token::acceptSellOffer(secondarySeller, primaryOfferID)); env.close(); // now we can do a secondary sale - auto const sellOffer = - createSellOffer(secondarySeller, nftID, gwXAU(300)); - auto const buyOffer = - createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500)); - env(token::brokerOffers(broker, buyOffer, sellOffer), - token::brokerFee(gwXAU(100))); + auto const sellOffer = createSellOffer(secondarySeller, nftID, gwXAU(300)); + auto const buyOffer = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500)); + env(token::brokerOffers(broker, buyOffer, sellOffer), token::brokerFee(gwXAU(100))); env.close(); BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12)); @@ -5644,8 +5078,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100)); BEAST_EXPECT(env.balance(gw, minter["XAU"]) == gwXAU(-12)); BEAST_EXPECT(env.balance(gw, buyer["XAU"]) == gwXAU(-490)); - BEAST_EXPECT( - env.balance(gw, secondarySeller["XAU"]) == gwXAU(-388)); + BEAST_EXPECT(env.balance(gw, secondarySeller["XAU"]) == gwXAU(-388)); BEAST_EXPECT(env.balance(gw, broker["XAU"]) == gwXAU(-5100)); } } @@ -5700,15 +5133,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Bob creates a buy offer for 5 XRP. Alice creates a sell offer // for 0 XRP. - uint256 const bobBuyOfferIndex = - keylet::nftoffer(bob, env.seq(bob)).key; + uint256 const bobBuyOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId, XRP(5)), token::owner(alice)); - uint256 const aliceSellOfferIndex = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, XRP(0)), - token::destination(bob), - txflags(tfSellNFToken)); + uint256 const aliceSellOfferIndex = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, XRP(0)), token::destination(bob), txflags(tfSellNFToken)); env.close(); // bob accepts alice's offer but forgets to remove the old buy offer. @@ -5719,16 +5148,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(env.le(keylet::nftoffer(bobBuyOfferIndex))); // Bob creates a sell offer for the gift NFT from alice. - uint256 const bobSellOfferIndex = - keylet::nftoffer(bob, env.seq(bob)).key; + uint256 const bobSellOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId, XRP(4)), txflags(tfSellNFToken)); env.close(); // bob now has a buy offer and a sell offer on the books. A broker // spots this and swoops in to make a profit. BEAST_EXPECT(nftCount(env, bob) == 1); - auto const bobsPriorBalance = env.balance(bob); - auto const brokersPriorBalance = env.balance(broker); + auto const bobPriorBalance = env.balance(bob); + auto const brokerPriorBalance = env.balance(broker); env(token::brokerOffers(broker, bobBuyOfferIndex, bobSellOfferIndex), token::brokerFee(XRP(1)), ter(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER)); @@ -5737,8 +5165,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // A tec result was returned, so no state should change other // than the broker burning their transaction fee. BEAST_EXPECT(nftCount(env, bob) == 1); - BEAST_EXPECT(env.balance(bob) == bobsPriorBalance); - BEAST_EXPECT(env.balance(broker) == brokersPriorBalance - baseFee); + BEAST_EXPECT(env.balance(bob) == bobPriorBalance); + BEAST_EXPECT(env.balance(broker) == brokerPriorBalance - baseFee); } void @@ -5753,7 +5181,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Close the ledger until the ledger sequence is large enough to delete // the account (no longer within ) - // This is enforced by the featureDeletableAccounts amendment auto incLgrSeqForAcctDel = [&](Env& env, Account const& acct) { int const delta = [&]() -> int { if (env.seq(acct) + 255 > openLedgerSeq(env)) @@ -5771,8 +5198,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto incLgrSeqForFixNftRemint = [&](Env& env, Account const& acct) { int delta = 0; auto const deletableLgrSeq = - (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) + - (*env.le(acct))[sfMintedNFTokens] + 255; + (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) + (*env.le(acct))[sfMintedNFTokens] + 255; if (deletableLgrSeq > openLedgerSeq(env)) delta = deletableLgrSeq - openLedgerSeq(env); @@ -5872,8 +5298,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } env.close(); - // Increment ledger sequence to the number that is - // enforced by the featureDeletableAccounts amendment incLgrSeqForAcctDel(env, alice); // Verify that alice's account root is present. @@ -5886,7 +5310,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice tries to delete her account, but is unsuccessful. // Due to authorized minting, alice's account sequence does not // advance while minter mints NFTokens for her. - // The new account deletion retriction enabled by this amendment will enforce // alice to wait for more ledgers to close before she can // delete her account, to prevent duplicate NFTokenIDs @@ -5931,9 +5355,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // The new NFT minted will not have the same ID // as any of the NFTs authorized minter minted - BEAST_EXPECT( - std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == - nftIDs.end()); + BEAST_EXPECT(std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == nftIDs.end()); } // When an account mints and burns a batch of NFTokens using tickets, @@ -5969,15 +5391,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice burns 50 NFTs using tickets for (auto const nftokenID : nftIDs) { - env(token::burn(alice, nftokenID), - ticket::use(aliceTicketSeq++)); + env(token::burn(alice, nftokenID), ticket::use(aliceTicketSeq++)); } env.close(); BEAST_EXPECT(ticketCount(env, alice) == 0); - // Increment ledger sequence to the number that is - // enforced by the featureDeletableAccounts amendment incLgrSeqForAcctDel(env, alice); // Verify that alice's account root is present. @@ -5990,7 +5409,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice tries to delete her account, but is unsuccessful. // Due to authorized minting, alice's account sequence does not // advance while minter mints NFTokens for her using tickets. - // The new account deletion retriction enabled by this amendment will enforce // alice to wait for more ledgers to close before she can // delete her account, to prevent duplicate NFTokenIDs @@ -6035,9 +5454,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // The new NFT minted will not have the same ID // as any of the NFTs authorized minter minted using tickets - BEAST_EXPECT( - std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == - nftIDs.end()); + BEAST_EXPECT(std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == nftIDs.end()); } // When an authorized minter mints and burns a batch of NFTokens using // tickets, issuer's account needs to wait a longer time before it can @@ -6071,9 +5488,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { uint256 const nftokenID = token::getNextID(env, alice, 0u); nftIDs.push_back(nftokenID); - env(token::mint(minter), - token::issuer(alice), - ticket::use(minterTicketSeq++)); + env(token::mint(minter), token::issuer(alice), ticket::use(minterTicketSeq++)); } env.close(); @@ -6086,8 +5501,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ticketCount(env, minter) == 0); - // Increment ledger sequence to the number that is - // enforced by the featureDeletableAccounts amendment incLgrSeqForAcctDel(env, alice); // Verify that alice's account root is present. @@ -6098,7 +5511,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice tries to delete her account, but is unsuccessful. // Due to authorized minting, alice's account sequence does not // advance while minter mints NFTokens for her using tickets. - // The new account deletion retriction enabled by this amendment will enforce // alice to wait for more ledgers to close before she can delete her // account, to prevent duplicate NFTokenIDs @@ -6144,9 +5557,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // The new NFT minted will not have the same ID // as one of NFTs authorized minter minted using tickets - BEAST_EXPECT( - std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == - nftIDs.end()); + BEAST_EXPECT(std::find(nftIDs.begin(), nftIDs.end(), remintNFTokenID) == nftIDs.end()); } void @@ -6165,19 +5576,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.fund(XRP(10000), alice, buyer); env.close(); - env(token::mint(alice), - token::amount(XRP(10000)), - ter(temDISABLED)); + env(token::mint(alice), token::amount(XRP(10000)), ter(temDISABLED)); env.close(); - env(token::mint(alice), - token::destination("buyer"), - ter(temDISABLED)); + env(token::mint(alice), token::destination("buyer"), ter(temDISABLED)); env.close(); - env(token::mint(alice), - token::expiration(lastClose(env) + 25), - ter(temDISABLED)); + env(token::mint(alice), token::expiration(lastClose(env) + 25), ter(temDISABLED)); env.close(); return; @@ -6200,16 +5605,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // Destination field specified but Amount field not specified - env(token::mint(alice), - token::destination(buyer), - ter(temMALFORMED)); + env(token::mint(alice), token::destination(buyer), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); // Expiration field specified but Amount field not specified - env(token::mint(alice), - token::expiration(lastClose(env) + 25), - ter(temMALFORMED)); + env(token::mint(alice), token::expiration(lastClose(env) + 25), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, buyer) == 0); } @@ -6217,50 +5618,33 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // The destination may not be the account submitting the // transaction. - env(token::mint(alice), - token::amount(XRP(1000)), - token::destination(alice), - ter(temMALFORMED)); + env(token::mint(alice), token::amount(XRP(1000)), token::destination(alice), ter(temMALFORMED)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); // The destination must be an account already established in the // ledger. - env(token::mint(alice), - token::amount(XRP(1000)), - token::destination(Account("demon")), - ter(tecNO_DST)); + env(token::mint(alice), token::amount(XRP(1000)), token::destination(Account("demon")), ter(tecNO_DST)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); } { // Set a bad expiration. - env(token::mint(alice), - token::amount(XRP(1000)), - token::expiration(0), - ter(temBAD_EXPIRATION)); + env(token::mint(alice), token::amount(XRP(1000)), token::expiration(0), ter(temBAD_EXPIRATION)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); // The new NFTokenOffer may not have passed its expiration time. - env(token::mint(alice), - token::amount(XRP(1000)), - token::expiration(lastClose(env)), - ter(tecEXPIRED)); + env(token::mint(alice), token::amount(XRP(1000)), token::expiration(lastClose(env)), ter(tecEXPIRED)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); } { // Set an invalid amount. - env(token::mint(alice), - token::amount(buyer["USD"](1)), - txflags(tfOnlyXRP), - ter(temBAD_AMOUNT)); - env(token::mint(alice), - token::amount(buyer["USD"](0)), - ter(temBAD_AMOUNT)); + env(token::mint(alice), token::amount(buyer["USD"](1)), txflags(tfOnlyXRP), ter(temBAD_AMOUNT)); + env(token::mint(alice), token::amount(buyer["USD"](0)), ter(temBAD_AMOUNT)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -6276,10 +5660,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // If the IOU issuer and the NFToken issuer are the same, // then that issuer does not need a trust line to accept their // fee. - env(token::mint(gw), - token::amount(gwAUD(1000)), - txflags(tfTransferable), - token::xferFee(10)); + env(token::mint(gw), token::amount(gwAUD(1000)), txflags(tfTransferable), token::xferFee(10)); env.close(); // Give alice the needed trust line, but freeze it. @@ -6297,9 +5678,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, alice) == 0); // Seller (alice) must have a trust line may not be frozen. - env(token::mint(alice), - token::amount(gwAUD(1000)), - ter(tecFROZEN)); + env(token::mint(alice), token::amount(gwAUD(1000)), ter(tecFROZEN)); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); @@ -6317,9 +5696,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // doesn't have reserve for 2 objects (NFTokenPage, Offer) - env(token::mint(bob), - token::amount(XRP(0)), - ter(tecINSUFFICIENT_RESERVE)); + env(token::mint(bob), token::amount(XRP(0)), ter(tecINSUFFICIENT_RESERVE)); env.close(); // have reserve for NFTokenPage, Offer @@ -6331,9 +5708,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // doesn't have reserve for Offer env(pay(env.master, bob, drops(baseFee))); env.close(); - env(token::mint(bob), - token::amount(XRP(0)), - ter(tecINSUFFICIENT_RESERVE)); + env(token::mint(bob), token::amount(XRP(0)), ter(tecINSUFFICIENT_RESERVE)); env.close(); // have reserve for Offer @@ -6372,8 +5747,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite token::amount(XRP(10)), token::destination(buyer), token::expiration(lastClose(env) + 25)); - uint256 const offerAliceSellsToBuyer = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const offerAliceSellsToBuyer = keylet::nftoffer(alice, env.seq(alice)).key; env(token::cancelOffer(alice, {offerAliceSellsToBuyer})); env.close(); @@ -6382,8 +5756,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite token::amount(XRP(10)), token::destination(alice), token::expiration(lastClose(env) + 25)); - uint256 const offerBuyerSellsToAlice = - keylet::nftoffer(buyer, env.seq(buyer)).key; + uint256 const offerBuyerSellsToAlice = keylet::nftoffer(buyer, env.seq(buyer)).key; env(token::cancelOffer(alice, {offerBuyerSellsToAlice})); env.close(); @@ -6393,9 +5766,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Minter will have offer not issuer BEAST_EXPECT(ownerCount(env, minter) == 0); BEAST_EXPECT(ownerCount(env, issuer) == 0); - env(token::mint(minter), - token::issuer(issuer), - token::amount(drops(1))); + env(token::mint(minter), token::issuer(issuer), token::amount(drops(1))); env.close(); BEAST_EXPECT(ownerCount(env, minter) == 2); BEAST_EXPECT(ownerCount(env, issuer) == 0); @@ -6425,7 +5796,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // // The values of these fields are dependent on the NFTokenID/OfferID // changed in its corresponding transaction. We want to validate each - // transaction to make sure the synethic fields hold the right values. + // transaction to make sure the synthetic fields hold the right values. testcase("Test synthetic fields from JSON response"); @@ -6444,12 +5815,10 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // transaction auto verifyNFTokenID = [&](uint256 const& actualNftID) { // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; env.close(); - Json::Value const meta = - env.rpc("tx", txHash)[jss::result][jss::meta]; + Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta]; // Expect nftokens_id field if (!BEAST_EXPECT(meta.isMember(jss::nftoken_id))) @@ -6464,55 +5833,50 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Verify `nftoken_ids` value equals to the NFTokenIDs that were // changed in the most recent NFTokenCancelOffer transaction - auto verifyNFTokenIDsInCancelOffer = - [&](std::vector actualNftIDs) { - // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + auto verifyNFTokenIDsInCancelOffer = [&](std::vector actualNftIDs) { + // Get the hash for the most recent transaction. + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; - env.close(); - Json::Value const meta = - env.rpc("tx", txHash)[jss::result][jss::meta]; + env.close(); + Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta]; - // Expect nftokens_ids field and verify the values - if (!BEAST_EXPECT(meta.isMember(jss::nftoken_ids))) - return; + // Expect nftokens_ids field and verify the values + if (!BEAST_EXPECT(meta.isMember(jss::nftoken_ids))) + return; - // Convert NFT IDs from Json::Value to uint256 - std::vector metaIDs; - std::transform( - meta[jss::nftoken_ids].begin(), - meta[jss::nftoken_ids].end(), - std::back_inserter(metaIDs), - [this](Json::Value id) { - uint256 nftID; - BEAST_EXPECT(nftID.parseHex(id.asString())); - return nftID; - }); + // Convert NFT IDs from Json::Value to uint256 + std::vector metaIDs; + std::transform( + meta[jss::nftoken_ids].begin(), + meta[jss::nftoken_ids].end(), + std::back_inserter(metaIDs), + [this](Json::Value id) { + uint256 nftID; + BEAST_EXPECT(nftID.parseHex(id.asString())); + return nftID; + }); - // Sort both array to prepare for comparison - std::sort(metaIDs.begin(), metaIDs.end()); - std::sort(actualNftIDs.begin(), actualNftIDs.end()); + // Sort both array to prepare for comparison + std::sort(metaIDs.begin(), metaIDs.end()); + std::sort(actualNftIDs.begin(), actualNftIDs.end()); - // Make sure the expect number of NFTs is correct - BEAST_EXPECT(metaIDs.size() == actualNftIDs.size()); + // Make sure the expect number of NFTs is correct + BEAST_EXPECT(metaIDs.size() == actualNftIDs.size()); - // Check the value of NFT ID in the meta with the - // actual values - for (size_t i = 0; i < metaIDs.size(); ++i) - BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]); - }; + // Check the value of NFT ID in the meta with the + // actual values + for (size_t i = 0; i < metaIDs.size(); ++i) + BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]); + }; // Verify `offer_id` value equals to the offerID that was // changed in the most recent NFTokenCreateOffer tx auto verifyNFTokenOfferID = [&](uint256 const& offerID) { // Get the hash for the most recent transaction. - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; env.close(); - Json::Value const meta = - env.rpc("tx", txHash)[jss::result][jss::meta]; + Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta]; // Expect offer_id field and verify the value if (!BEAST_EXPECT(meta.isMember(jss::offer_id))) @@ -6527,14 +5891,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // Alice mints 2 NFTs // Verify the NFTokenIDs are correct in the NFTokenMint tx meta - uint256 const nftId1{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId1{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId1); - uint256 const nftId2{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId2{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId2); @@ -6542,32 +5904,26 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Alice creates one sell offer for each NFT // Verify the offer indexes are correct in the NFTokenCreateOffer tx // meta - uint256 const aliceOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId1, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId1, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex1); - uint256 const aliceOfferIndex2 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId2, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex2 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId2, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex2); // Alice cancels two offers she created // Verify the NFTokenIDs are correct in the NFTokenCancelOffer tx // meta - env(token::cancelOffer( - alice, {aliceOfferIndex1, aliceOfferIndex2})); + env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2})); env.close(); verifyNFTokenIDsInCancelOffer({nftId1, nftId2}); // Bobs creates a buy offer for nftId1 // Verify the offer id is correct in the NFTokenCreateOffer tx meta - auto const bobBuyOfferIndex = - keylet::nftoffer(bob, env.seq(bob)).key; + auto const bobBuyOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice)); env.close(); verifyNFTokenOfferID(bobBuyOfferIndex); @@ -6582,31 +5938,25 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Check `nftoken_ids` in brokered mode { // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId); // Alice creates sell offer and set broker as destination - uint256 const offerAliceToBroker = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - token::destination(broker), - txflags(tfSellNFToken)); + uint256 const offerAliceToBroker = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), token::destination(broker), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(offerAliceToBroker); // Bob creates buy offer - uint256 const offerBobToBroker = - keylet::nftoffer(bob, env.seq(bob)).key; + uint256 const offerBobToBroker = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId, drops(1)), token::owner(alice)); env.close(); verifyNFTokenOfferID(offerBobToBroker); // Check NFTokenID meta for NFTokenAcceptOffer in brokered mode - env(token::brokerOffers( - broker, offerBobToBroker, offerAliceToBroker)); + env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker)); env.close(); verifyNFTokenID(nftId); } @@ -6615,39 +5965,32 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // multiple offers are cancelled for the same NFT { // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId); // Alice creates 2 sell offers for the same NFT - uint256 const aliceOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex1); - uint256 const aliceOfferIndex2 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex2 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex2); // Make sure the metadata only has 1 nft id, since both offers are // for the same nft - env(token::cancelOffer( - alice, {aliceOfferIndex1, aliceOfferIndex2})); + env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2})); env.close(); verifyNFTokenIDsInCancelOffer({nftId}); } if (features[featureNFTokenMintOffer]) { - uint256 const aliceMintWithOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const aliceMintWithOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; env(token::mint(alice), token::amount(XRP(0))); env.close(); verifyNFTokenOfferID(aliceMintWithOfferIndex1); @@ -6662,18 +6005,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite using namespace test::jtx; // Lambda that mints an NFT and then creates a sell offer - auto mintAndCreateSellOffer = [](test::jtx::Env& env, - test::jtx::Account const& acct, - STAmount const amt) -> uint256 { + auto mintAndCreateSellOffer = + [](test::jtx::Env& env, test::jtx::Account const& acct, STAmount const amt) -> uint256 { // acct mints a NFT - uint256 const nftId{ - token::getNextID(env, acct, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, acct, 0u, tfTransferable)}; env(token::mint(acct, 0u), txflags(tfTransferable)); env.close(); // acct makes an sell offer - uint256 const sellOfferIndex = - keylet::nftoffer(acct, env.seq(acct)).key; + uint256 const sellOfferIndex = keylet::nftoffer(acct, env.seq(acct)).key; env(token::createOffer(acct, nftId, amt), txflags(tfSellNFToken)); env.close(); @@ -6700,8 +6040,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // alice mints an NFT and create a sell offer for 0 XRP - auto const sellOfferIndex = - mintAndCreateSellOffer(env, alice, XRP(0)); + auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0)); // Bob owns no object BEAST_EXPECT(ownerCount(env, bob) == 0); @@ -6730,8 +6069,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // Bob is not able to accept the offer with only the account // reserve (200,000,000 drops) - env(token::acceptSellOffer(bob, sellOfferIndex), - ter(tecINSUFFICIENT_RESERVE)); + env(token::acceptSellOffer(bob, sellOfferIndex), ter(tecINSUFFICIENT_RESERVE)); env.close(); // after prev transaction, Bob owns `200M - base fee` drops due @@ -6747,8 +6085,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // However, this transaction will still fail because the reserve // requirement is `base fee` drops higher - env(token::acceptSellOffer(bob, sellOfferIndex), - ter(tecINSUFFICIENT_RESERVE)); + env(token::acceptSellOffer(bob, sellOfferIndex), ter(tecINSUFFICIENT_RESERVE)); env.close(); // Send bob `base fee * 2` drops @@ -6786,8 +6123,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite for (size_t i = 0; i < 200; i++) { // alice mints an NFT and creates a sell offer for 0 XRP - auto const sellOfferIndex = - mintAndCreateSellOffer(env, alice, XRP(0)); + auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0)); // Bob is able to accept the offer env(token::acceptSellOffer(bob, sellOfferIndex)); @@ -6797,13 +6133,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite else { // alice mints the first NFT and creates a sell offer for 0 XRP - auto const sellOfferIndex1 = - mintAndCreateSellOffer(env, alice, XRP(0)); + auto const sellOfferIndex1 = mintAndCreateSellOffer(env, alice, XRP(0)); // Bob cannot accept this offer because he doesn't have the // reserve for the NFT - env(token::acceptSellOffer(bob, sellOfferIndex1), - ter(tecINSUFFICIENT_RESERVE)); + env(token::acceptSellOffer(bob, sellOfferIndex1), ter(tecINSUFFICIENT_RESERVE)); env.close(); // Give bob enough reserve @@ -6823,11 +6157,10 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite for (size_t i = 0; i < 31; i++) { // alice mints an NFT and creates a sell offer for 0 XRP - auto const sellOfferIndex = - mintAndCreateSellOffer(env, alice, XRP(0)); + auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0)); // Bob can accept the offer because the new NFT is stored in - // an existing NFTokenPage so no new reserve is requried + // an existing NFTokenPage so no new reserve is required env(token::acceptSellOffer(bob, sellOfferIndex)); env.close(); } @@ -6836,13 +6169,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // alice now mints the 33rd NFT and creates an sell offer for 0 // XRP - auto const sellOfferIndex33 = - mintAndCreateSellOffer(env, alice, XRP(0)); + auto const sellOfferIndex33 = mintAndCreateSellOffer(env, alice, XRP(0)); // Bob fails to accept this NFT because he does not have enough // reserve for a new NFTokenPage - env(token::acceptSellOffer(bob, sellOfferIndex33), - ter(tecINSUFFICIENT_RESERVE)); + env(token::acceptSellOffer(bob, sellOfferIndex33), ter(tecINSUFFICIENT_RESERVE)); env.close(); // Send bob incremental reserve @@ -6882,8 +6213,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); @@ -6895,8 +6225,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // accepting the buy offer fails because bob's balance is `base fee` // drops lower than the required amount, since the previous tx burnt // drops for tx fee. - env(token::acceptBuyOffer(alice, buyOfferIndex), - ter(tecINSUFFICIENT_FUNDS)); + env(token::acceptBuyOffer(alice, buyOfferIndex), ter(tecINSUFFICIENT_FUNDS)); env.close(); // send Bob `base fee` drops @@ -6932,22 +6261,17 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); // Alice creates sell offer and set broker as destination - uint256 const offerAliceToBroker = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, XRP(1)), - token::destination(broker), - txflags(tfSellNFToken)); + uint256 const offerAliceToBroker = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, XRP(1)), token::destination(broker), txflags(tfSellNFToken)); env.close(); // Bob creates buy offer - uint256 const offerBobToBroker = - keylet::nftoffer(bob, env.seq(bob)).key; + uint256 const offerBobToBroker = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice)); env.close(); @@ -6955,9 +6279,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Returns insufficient funds, because bob burnt tx fee when he // created his buy offer, which makes his spendable balance to be // less than the required amount. - env(token::brokerOffers( - broker, offerBobToBroker, offerAliceToBroker), - ter(tecINSUFFICIENT_FUNDS)); + env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker), ter(tecINSUFFICIENT_FUNDS)); env.close(); // send Bob `base fee` drops @@ -6965,8 +6287,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // broker offers. - env(token::brokerOffers( - broker, offerBobToBroker, offerAliceToBroker)); + env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker)); env.close(); } } @@ -7011,11 +6332,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // // In both cases we remove the fixRemoveNFTokenAutoTrustLine amendment. // Otherwise we can't create NFTokens with tfTrustLine enabled. - FeatureBitset const localFeatures = - features - fixRemoveNFTokenAutoTrustLine; + FeatureBitset const localFeatures = features - fixRemoveNFTokenAutoTrustLine; for (FeatureBitset feats : - {localFeatures - fixEnforceNFTokenTrustline, - localFeatures | fixEnforceNFTokenTrustline}) + {localFeatures - fixEnforceNFTokenTrustline, localFeatures | fixEnforceNFTokenTrustline}) { Env env{*this, feats}; env.fund(XRP(1000), issuer, becky, cheri, gw); @@ -7030,31 +6349,21 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // issuer creates two NFTs: one with and one without AutoTrustLine. std::uint16_t xferFee = 5000; // 5% - uint256 const nftAutoTrustID{token::getNextID( - env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; - env(token::mint(issuer, 0u), - token::xferFee(xferFee), - txflags(tfTransferable | tfTrustLine)); + uint256 const nftAutoTrustID{token::getNextID(env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; + env(token::mint(issuer, 0u), token::xferFee(xferFee), txflags(tfTransferable | tfTrustLine)); env.close(); - uint256 const nftNoAutoTrustID{ - token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; - env(token::mint(issuer, 0u), - token::xferFee(xferFee), - txflags(tfTransferable)); + uint256 const nftNoAutoTrustID{token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; + env(token::mint(issuer, 0u), token::xferFee(xferFee), txflags(tfTransferable)); env.close(); // becky buys the nfts for 1 drop each. { - uint256 const beckyBuyOfferIndex1 = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, drops(1)), - token::owner(issuer)); + uint256 const beckyBuyOfferIndex1 = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, drops(1)), token::owner(issuer)); - uint256 const beckyBuyOfferIndex2 = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), - token::owner(issuer)); + uint256 const beckyBuyOfferIndex2 = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), token::owner(issuer)); env.close(); env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1)); @@ -7063,17 +6372,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // becky creates offers to sell the nfts for AUD. - uint256 const beckyAutoTrustOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), - txflags(tfSellNFToken)); + uint256 const beckyAutoTrustOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), txflags(tfSellNFToken)); env.close(); // Creating an offer for the NFToken without tfTrustLine fails // because issuer does not have a trust line for AUD. - env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), - txflags(tfSellNFToken), - ter(tecNO_LINE)); + env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), txflags(tfSellNFToken), ter(tecNO_LINE)); env.close(); // issuer creates a trust line. Now the offer create for the @@ -7083,10 +6388,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 1); - uint256 const beckyNoAutoTrustOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), - txflags(tfSellNFToken)); + uint256 const beckyNoAutoTrustOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), txflags(tfSellNFToken)); env.close(); // Now that the offers are in place, issuer removes the trustline. @@ -7116,8 +6419,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // With fixEnforceNFTokenTrustline cheri can't accept the // offer because issuer could not get their transfer fee // without the appropriate trustline. - env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex), - ter(tecNO_LINE)); + env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex), ter(tecNO_LINE)); env.close(); // But if issuer re-establishes the trustline then the offer @@ -7182,8 +6484,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // // We remove the fixRemoveNFTokenAutoTrustLine amendment. Otherwise // we can't create NFTokens with tfTrustLine enabled. - FeatureBitset const localFeatures = - features - fixRemoveNFTokenAutoTrustLine; + FeatureBitset const localFeatures = features - fixRemoveNFTokenAutoTrustLine; Env env{*this, localFeatures}; env.fund(XRP(1000), issuer, becky, cheri); @@ -7198,31 +6499,21 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // issuer creates two NFTs: one with and one without AutoTrustLine. std::uint16_t xferFee = 5000; // 5% - uint256 const nftAutoTrustID{token::getNextID( - env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; - env(token::mint(issuer, 0u), - token::xferFee(xferFee), - txflags(tfTransferable | tfTrustLine)); + uint256 const nftAutoTrustID{token::getNextID(env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; + env(token::mint(issuer, 0u), token::xferFee(xferFee), txflags(tfTransferable | tfTrustLine)); env.close(); - uint256 const nftNoAutoTrustID{ - token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; - env(token::mint(issuer, 0u), - token::xferFee(xferFee), - txflags(tfTransferable)); + uint256 const nftNoAutoTrustID{token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; + env(token::mint(issuer, 0u), token::xferFee(xferFee), txflags(tfTransferable)); env.close(); // becky buys the nfts for 1 drop each. { - uint256 const beckyBuyOfferIndex1 = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, drops(1)), - token::owner(issuer)); + uint256 const beckyBuyOfferIndex1 = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, drops(1)), token::owner(issuer)); - uint256 const beckyBuyOfferIndex2 = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), - token::owner(issuer)); + uint256 const beckyBuyOfferIndex2 = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), token::owner(issuer)); env.close(); env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1)); @@ -7237,9 +6528,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Without featureNFTokenMintOffer becky simply can't // create an offer for a non-tfTrustLine NFToken that would // pay the transfer fee in issuer's own IOU. - env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), - txflags(tfSellNFToken), - ter(tecNO_LINE)); + env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), txflags(tfSellNFToken), ter(tecNO_LINE)); env.close(); // And issuer can't create a trust line to themselves. @@ -7248,10 +6537,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // However if the NFToken has the tfTrustLine flag set, // then becky can create the offer. - uint256 const beckyAutoTrustOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, isISU(100)), - txflags(tfSellNFToken)); + uint256 const beckyAutoTrustOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, isISU(100)), txflags(tfSellNFToken)); env.close(); // And cheri can accept the offer. @@ -7267,15 +6554,11 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // With featureNFTokenMintOffer things go better. // becky creates offers to sell the nfts for ISU. - uint256 const beckyNoAutoTrustOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), - txflags(tfSellNFToken)); + uint256 const beckyNoAutoTrustOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), txflags(tfSellNFToken)); env.close(); - uint256 const beckyAutoTrustOfferIndex = - keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftAutoTrustID, isISU(100)), - txflags(tfSellNFToken)); + uint256 const beckyAutoTrustOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, isISU(100)), txflags(tfSellNFToken)); env.close(); // cheri accepts becky's offers. Behavior is uniform: @@ -7318,8 +6601,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.fund(XRP(10000), issuer); env.close(); - auto const expectedTer = - modifyEnabled ? TER{tesSUCCESS} : TER{temINVALID_FLAG}; + auto const expectedTer = modifyEnabled ? TER{tesSUCCESS} : TER{temINVALID_FLAG}; env(token::mint(issuer, 0u), txflags(tfMutable), ter(expectedTer)); env.close(); } @@ -7359,32 +6641,22 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); // Set a negative fee. Exercises invalid preflight1. - env(token::modify(issuer, nftId), - fee(STAmount(10ull, true)), - ter(temBAD_FEE)); + env(token::modify(issuer, nftId), fee(STAmount(10ull, true)), ter(temBAD_FEE)); env.close(); // Invalid Flags - env(token::modify(issuer, nftId), - txflags(0x00000001), - ter(temINVALID_FLAG)); + env(token::modify(issuer, nftId), txflags(0x00000001), ter(temINVALID_FLAG)); // Invalid Owner - env(token::modify(issuer, nftId), - token::owner(issuer), - ter(temMALFORMED)); + env(token::modify(issuer, nftId), token::owner(issuer), ter(temMALFORMED)); env.close(); // Invalid URI length = 0 - env(token::modify(issuer, nftId), - token::uri(""), - ter(temMALFORMED)); + env(token::modify(issuer, nftId), token::uri(""), ter(temMALFORMED)); env.close(); // Invalid URI length > 256 - env(token::modify(issuer, nftId), - token::uri(std::string(maxTokenURILength + 1, 'q')), - ter(temMALFORMED)); + env(token::modify(issuer, nftId), token::uri(std::string(maxTokenURILength + 1, 'q')), ter(temMALFORMED)); env.close(); } { @@ -7394,8 +6666,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { // NFToken not exists - uint256 const nftIDNotExists{ - token::getNextID(env, issuer, 0u, tfMutable)}; + uint256 const nftIDNotExists{token::getNextID(env, issuer, 0u, tfMutable)}; env.close(); env(token::modify(issuer, nftIDNotExists), ter(tecNO_ENTRY)); @@ -7403,33 +6674,26 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } { // Invalid NFToken flag - uint256 const nftIDNotModifiable{ - token::getNextID(env, issuer, 0u)}; + uint256 const nftIDNotModifiable{token::getNextID(env, issuer, 0u)}; env(token::mint(issuer, 0u)); env.close(); - env(token::modify(issuer, nftIDNotModifiable), - ter(tecNO_PERMISSION)); + env(token::modify(issuer, nftIDNotModifiable), ter(tecNO_PERMISSION)); env.close(); } { // Unauthorized account - uint256 const nftId{ - token::getNextID(env, issuer, 0u, tfMutable)}; + uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)}; env(token::mint(issuer, 0u), txflags(tfMutable)); env.close(); - env(token::modify(bob, nftId), - token::owner(issuer), - ter(tecNO_PERMISSION)); + env(token::modify(bob, nftId), token::owner(issuer), ter(tecNO_PERMISSION)); env.close(); env(token::setMinter(issuer, alice)); env.close(); - env(token::modify(bob, nftId), - token::owner(issuer), - ter(tecNO_PERMISSION)); + env(token::modify(bob, nftId), token::owner(issuer), ter(tecNO_PERMISSION)); env.close(); } } @@ -7456,16 +6720,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite Json::Value params; params[jss::account] = acct.human(); params[jss::type] = "state"; - auto response = - env.rpc("json", "account_nfts", to_string(params)); + auto response = env.rpc("json", "account_nfts", to_string(params)); return response[jss::result][jss::account_nfts]; }; // lambda that checks for the expected URI value of an NFToken - auto checkURI = [&accountNFTs, this]( - Account const& acct, - char const* uri, - int line) { + auto checkURI = [&accountNFTs, this](Account const& acct, char const* uri, int line) { auto const nfts = accountNFTs(acct); if (nfts.size() == 1) pass(); @@ -7484,8 +6744,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite else { std::ostringstream text; - text << "checkURI: unexpected URI present on line " - << line; + text << "checkURI: unexpected URI present on line " << line; fail(text.str(), __FILE__, line); } return; @@ -7496,8 +6755,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite else { std::ostringstream text; - text << "checkURI: unexpected URI contents on line " - << line; + text << "checkURI: unexpected URI contents on line " << line; fail(text.str(), __FILE__, line); } }; @@ -7525,10 +6783,8 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite checkURI(issuer, "uri", __LINE__); // Account != Owner - uint256 const offerID = - keylet::nftoffer(issuer, env.seq(issuer)).key; - env(token::createOffer(issuer, nftId, XRP(0)), - txflags(tfSellNFToken)); + uint256 const offerID = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftId, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, offerID)); env.close(); @@ -7537,17 +6793,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite checkURI(alice, "uri", __LINE__); // Modify by owner fails. - env(token::modify(alice, nftId), - token::uri("new_uri"), - ter(tecNO_PERMISSION)); + env(token::modify(alice, nftId), token::uri("new_uri"), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, alice) == 1); checkURI(alice, "uri", __LINE__); - env(token::modify(issuer, nftId), - token::owner(alice), - token::uri("new_uri")); + env(token::modify(issuer, nftId), token::owner(alice), token::uri("new_uri")); env.close(); BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, alice) == 1); @@ -7557,18 +6809,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); checkURI(alice, nullptr, __LINE__); - env(token::modify(issuer, nftId), - token::owner(alice), - token::uri("uri")); + env(token::modify(issuer, nftId), token::owner(alice), token::uri("uri")); env.close(); checkURI(alice, "uri", __LINE__); // Modify by authorized minter env(token::setMinter(issuer, bob)); env.close(); - env(token::modify(bob, nftId), - token::owner(alice), - token::uri("new_uri")); + env(token::modify(bob, nftId), token::owner(alice), token::uri("new_uri")); env.close(); checkURI(alice, "new_uri", __LINE__); @@ -7576,9 +6824,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); checkURI(alice, nullptr, __LINE__); - env(token::modify(bob, nftId), - token::owner(alice), - token::uri("uri")); + env(token::modify(bob, nftId), token::owner(alice), token::uri("uri")); env.close(); checkURI(alice, "uri", __LINE__); } @@ -7632,8 +6878,8 @@ public: run() override { testWithFeats( - allFeatures - fixNFTokenReserve - featureNFTokenMintOffer - - featureDynamicNFT); + allFeatures - fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT - + fixExpiredNFTokenOfferRemoval); } }; @@ -7642,9 +6888,7 @@ class NFTokenDisallowIncoming_test : public NFTokenBaseUtil_test void run() override { - testWithFeats( - allFeatures - featureDisallowIncoming - fixNFTokenReserve - - featureNFTokenMintOffer - featureDynamicNFT); + testWithFeats(allFeatures - fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT); } }; @@ -7653,8 +6897,7 @@ class NFTokenWOMintOffer_test : public NFTokenBaseUtil_test void run() override { - testWithFeats( - allFeatures - featureNFTokenMintOffer - featureDynamicNFT); + testWithFeats(allFeatures - featureNFTokenMintOffer - featureDynamicNFT); } }; @@ -7667,6 +6910,15 @@ class NFTokenWOModify_test : public NFTokenBaseUtil_test } }; +class NFTokenWOExpiredOfferRemoval_test : public NFTokenBaseUtil_test +{ + void + run() override + { + testWithFeats(allFeatures - fixExpiredNFTokenOfferRemoval); + } +}; + class NFTokenAllFeatures_test : public NFTokenBaseUtil_test { void @@ -7676,10 +6928,10 @@ class NFTokenAllFeatures_test : public NFTokenBaseUtil_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, app, xrpl, 2); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/NetworkID_test.cpp b/src/test/app/NetworkID_test.cpp index 07a4641c0e..5fddc8f641 100644 --- a/src/test/app/NetworkID_test.cpp +++ b/src/test/app/NetworkID_test.cpp @@ -1,28 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Dev Null Productions - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== +// Copyright (c) 2020 Dev Null Productions #include #include #include -namespace ripple { +namespace xrpl { namespace test { class NetworkID_test : public beast::unit_test::suite @@ -54,9 +37,7 @@ public: auto const alice = Account{"alice"}; - auto const runTx = [&](test::jtx::Env& env, - Json::Value const& jv, - TER expectedOutcome) { + auto const runTx = [&](test::jtx::Env& env, Json::Value const& jv, TER expectedOutcome) { env.memoize(env.master); env.memoize(alice); @@ -129,15 +110,12 @@ public: jvn[jss::TransactionType] = jss::AccountSet; jvn[jss::Fee] = to_string(env.current()->fees().base); jvn[jss::Sequence] = env.seq(alice); - jvn[jss::LastLedgerSequence] = env.current()->info().seq + 2; + jvn[jss::LastLedgerSequence] = env.current()->header().seq + 2; auto jt = env.jtnofill(jvn); Serializer s; jt.stx->add(s); BEAST_EXPECT( - env.rpc( - "submit", - strHex(s.slice()))[jss::result][jss::engine_result] == - "telREQUIRES_NETWORK_ID"); + env.rpc("submit", strHex(s.slice()))[jss::result][jss::engine_result] == "telREQUIRES_NETWORK_ID"); env.close(); } @@ -159,7 +137,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(NetworkID, app, ripple); +BEAST_DEFINE_TESTSUITE(NetworkID, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/NetworkOPs_test.cpp b/src/test/app/NetworkOPs_test.cpp index edea55105b..ffca1ed79d 100644 --- a/src/test/app/NetworkOPs_test.cpp +++ b/src/test/app/NetworkOPs_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Dev Null Productions - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { class NetworkOPs_test : public beast::unit_test::suite @@ -38,7 +19,7 @@ public: void testAllBadHeldTransactions() { - // All trasactions are already marked as SF_BAD, and we should be able + // All transactions are already marked as SF_BAD, and we should be able // to handle the case properly without an assertion failure testcase("No valid transactions in batch"); @@ -47,34 +28,27 @@ public: { using namespace jtx; auto const alice = Account{"alice"}; - Env env{ - *this, - envconfig(), - std::make_unique(&logs), - beast::severities::kAll}; + Env env{*this, envconfig(), std::make_unique(&logs), beast::severities::kAll}; env.memoize(env.master); env.memoize(alice); auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10)); - auto transacionId = jtx.stx->getTransactionID(); - env.app().getHashRouter().setFlags( - transacionId, HashRouterFlags::HELD); + auto transactionId = jtx.stx->getTransactionID(); + env.app().getHashRouter().setFlags(transactionId, HashRouterFlags::HELD); env(jtx, json(jss::Sequence, 1), ter(terNO_ACCOUNT)); - env.app().getHashRouter().setFlags( - transacionId, HashRouterFlags::BAD); + env.app().getHashRouter().setFlags(transactionId, HashRouterFlags::BAD); env.close(); } - BEAST_EXPECT( - logs.find("No transaction to process!") != std::string::npos); + BEAST_EXPECT(logs.find("No transaction to process!") != std::string::npos); } }; -BEAST_DEFINE_TESTSUITE(NetworkOPs, app, ripple); +BEAST_DEFINE_TESTSUITE(NetworkOPs, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/OfferStream_test.cpp b/src/test/app/OfferStream_test.cpp index 35f38da29a..218653a5d4 100644 --- a/src/test/app/OfferStream_test.cpp +++ b/src/test/app/OfferStream_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class OfferStream_test : public beast::unit_test::suite { @@ -39,6 +20,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(OfferStream, app, ripple); +BEAST_DEFINE_TESTSUITE(OfferStream, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index 5d56a72cc7..4847b7edb0 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class OfferBaseUtil_test : public beast::unit_test::suite @@ -39,27 +20,20 @@ class OfferBaseUtil_test : public beast::unit_test::suite std::uint32_t lastClose(jtx::Env& env) { - return env.current()->info().parentCloseTime.time_since_epoch().count(); + return env.current()->header().parentCloseTime.time_since_epoch().count(); } static auto - ledgerEntryOffer( - jtx::Env& env, - jtx::Account const& acct, - std::uint32_t offer_seq) + ledgerEntryOffer(jtx::Env& env, jtx::Account const& acct, std::uint32_t offer_seq) { Json::Value jvParams; jvParams[jss::offer][jss::account] = acct.human(); jvParams[jss::offer][jss::seq] = offer_seq; - return env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; } static auto - getBookOffers( - jtx::Env& env, - Issue const& taker_pays, - Issue const& taker_gets) + getBookOffers(jtx::Env& env, Issue const& taker_pays, Issue const& taker_gets) { Json::Value jvbp; jvbp[jss::ledger_index] = "current"; @@ -121,15 +95,10 @@ public: PathSet paths(Path(XRP, USD), Path(USD)); - env(pay(alice, bob, USD(100)), - json(paths.json()), - sendmax(BTC(1000)), - txflags(tfPartialPayment)); + env(pay(alice, bob, USD(100)), json(paths.json()), sendmax(BTC(1000)), txflags(tfPartialPayment)); env.require(balance(bob, USD(100))); - BEAST_EXPECT( - !isOffer(env, carol, BTC(1), USD(100)) && - isOffer(env, carol, BTC(49), XRP(49))); + BEAST_EXPECT(!isOffer(env, carol, BTC(1), USD(100)) && isOffer(env, carol, BTC(49), XRP(49))); } void @@ -162,26 +131,18 @@ public: // cancel the offer above and replace it with a new offer auto const offer2Seq = env.seq(alice); - env(offer(alice, XRP(300), USD(100)), - json(jss::OfferSequence, offer1Seq), - require(offers(alice, 1))); + env(offer(alice, XRP(300), USD(100)), json(jss::OfferSequence, offer1Seq), require(offers(alice, 1))); env.close(); - BEAST_EXPECT( - isOffer(env, alice, XRP(300), USD(100)) && - !isOffer(env, alice, XRP(500), USD(100))); + BEAST_EXPECT(isOffer(env, alice, XRP(300), USD(100)) && !isOffer(env, alice, XRP(500), USD(100))); // Test canceling non-existent offer. // auto const offer3Seq = env.seq (alice); - env(offer(alice, XRP(400), USD(200)), - json(jss::OfferSequence, offer1Seq), - require(offers(alice, 2))); + env(offer(alice, XRP(400), USD(200)), json(jss::OfferSequence, offer1Seq), require(offers(alice, 2))); env.close(); - BEAST_EXPECT( - isOffer(env, alice, XRP(300), USD(100)) && - isOffer(env, alice, XRP(400), USD(200))); + BEAST_EXPECT(isOffer(env, alice, XRP(300), USD(100)) && isOffer(env, alice, XRP(400), USD(200))); // Test cancellation now with OfferCancel tx auto const offer4Seq = env.seq(alice); @@ -199,13 +160,10 @@ public: // an offer. Show that the attempt to remove the offer fails. env.require(offers(alice, 2)); - // featureDepositPreauths changes the return code on an expired Offer. - // Adapt to that. - bool const featPreauth{features[featureDepositPreauth]}; env(offer(alice, XRP(5), USD(2)), json(sfExpiration.fieldName, lastClose(env)), json(jss::OfferSequence, offer2Seq), - ter(featPreauth ? TER{tecEXPIRED} : TER{tesSUCCESS})); + ter(tecEXPIRED)); env.close(); env.require(offers(alice, 2)); @@ -308,10 +266,7 @@ public: // stAmountCalcSwitchover2 was inactive.) env(offer(erin, drops(2), USD(1))); - env(pay(alice, bob, USD(1)), - path(~USD), - sendmax(XRP(102)), - txflags(tfNoRippleDirect | tfPartialPayment)); + env(pay(alice, bob, USD(1)), path(~USD), sendmax(XRP(102)), txflags(tfNoRippleDirect | tfPartialPayment)); env.require(offers(carol, 0), offers(dan, 1)); @@ -366,22 +321,15 @@ public: env(offer(alice, USD(1), aliceTakerGets)); env.close(); - env.require( - offers(carol, 0), - balance( - carol, - initialCarolUSD)); // offer is removed but not taken + env.require(offers(carol, 0), balance(carol, + initialCarolUSD)); // offer is removed but not taken if (crossBothOffers) { - env.require( - offers(alice, 0), - balance(alice, USD(1))); // alice's offer is crossed + env.require(offers(alice, 0), balance(alice, USD(1))); // alice's offer is crossed } else { - env.require( - offers(alice, 1), - balance(alice, USD(0))); // alice's offer is not crossed + env.require(offers(alice, 1), balance(alice, USD(0))); // alice's offer is not crossed } } @@ -405,26 +353,18 @@ public: env.close(); env.require(offers(bob, 1), offers(carol, 1)); - std::uint32_t const flags = partialPayment - ? (tfNoRippleDirect | tfPartialPayment) - : tfNoRippleDirect; + std::uint32_t const flags = partialPayment ? (tfNoRippleDirect | tfPartialPayment) : tfNoRippleDirect; - TER const expectedTer = - partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL}; + TER const expectedTer = partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL}; - env(pay(alice, bob, USD(5)), - path(~USD), - sendmax(XRP(1)), - txflags(flags), - ter(expectedTer)); + env(pay(alice, bob, USD(5)), path(~USD), sendmax(XRP(1)), txflags(flags), ter(expectedTer)); env.close(); if (expectedTer == tesSUCCESS) { env.require(offers(carol, 0)); - env.require(balance( - carol, - initialCarolUSD)); // offer is removed but not taken + env.require(balance(carol, + initialCarolUSD)); // offer is removed but not taken } else { @@ -494,22 +434,15 @@ public: env(offer(alice, USD(1), aliceTakerGets)); env.close(); - env.require( - offers(carol, 0), - balance( - carol, - initialCarolUSD)); // offer is removed but not taken + env.require(offers(carol, 0), balance(carol, + initialCarolUSD)); // offer is removed but not taken if (crossBothOffers) { - env.require( - offers(alice, 0), - balance(alice, USD(1))); // alice's offer is crossed + env.require(offers(alice, 0), balance(alice, USD(1))); // alice's offer is crossed } else { - env.require( - offers(alice, 1), - balance(alice, USD(0))); // alice's offer is not crossed + env.require(offers(alice, 1), balance(alice, USD(0))); // alice's offer is not crossed } } @@ -536,26 +469,18 @@ public: env.close(); env.require(offers(bob, 1), offers(carol, 1)); - std::uint32_t const flags = partialPayment - ? (tfNoRippleDirect | tfPartialPayment) - : tfNoRippleDirect; + std::uint32_t const flags = partialPayment ? (tfNoRippleDirect | tfPartialPayment) : tfNoRippleDirect; - TER const expectedTer = - partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL}; + TER const expectedTer = partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL}; - env(pay(alice, bob, USD(5)), - path(~USD), - sendmax(EUR(10)), - txflags(flags), - ter(expectedTer)); + env(pay(alice, bob, USD(5)), path(~USD), sendmax(EUR(10)), txflags(flags), ter(expectedTer)); env.close(); if (expectedTer == tesSUCCESS) { env.require(offers(carol, 0)); - env.require(balance( - carol, - initialCarolUSD)); // offer is removed but not taken + env.require(balance(carol, + initialCarolUSD)); // offer is removed but not taken } else { @@ -631,10 +556,7 @@ public: env(offer(dan, XRP(50), USD1(50))); - env(pay(alice, carol, USD2(50)), - path(~USD1, bob), - sendmax(XRP(50)), - txflags(tfNoRippleDirect)); + env(pay(alice, carol, USD2(50)), path(~USD1, bob), sendmax(XRP(50)), txflags(tfNoRippleDirect)); env.require(balance(alice, xrpMinusFee(env, 10000 - 50))); env.require(balance(bob, USD1(100))); @@ -756,13 +678,10 @@ public: offersOnAccount(jtx::Env& env, jtx::Account account) { std::vector> result; - forEachItem( - *env.current(), - account, - [&result](std::shared_ptr const& sle) { - if (sle->getType() == ltOFFER) - result.push_back(sle); - }); + forEachItem(*env.current(), account, [&result](std::shared_ptr const& sle) { + if (sle->getType() == ltOFFER) + result.push_back(sle); + }); return result; } @@ -791,9 +710,7 @@ public: env.close(); // bob creates an offer that expires before the next ledger close. - env(offer(bob, USD(500), XRP(500)), - json(sfExpiration.fieldName, lastClose(env) + 1), - ter(tesSUCCESS)); + env(offer(bob, USD(500), XRP(500)), json(sfExpiration.fieldName, lastClose(env) + 1), ter(tesSUCCESS)); // The offer expires (it's not removed yet). env.close(); @@ -810,9 +727,7 @@ public: // Order that can't be filled but will remove bob's expired offer: { TER const killedCode{TER{tecKILLED}}; - env(offer(alice, XRP(1000), USD(1000)), - txflags(tfFillOrKill), - ter(killedCode)); + env(offer(alice, XRP(1000), USD(1000)), txflags(tfFillOrKill), ter(killedCode)); } env.require( balance(alice, startBalance - (f * 2)), @@ -825,9 +740,7 @@ public: offers(bob, 1)); // Order that can be filled - env(offer(alice, XRP(500), USD(500)), - txflags(tfFillOrKill), - ter(tesSUCCESS)); + env(offer(alice, XRP(500), USD(500)), txflags(tfFillOrKill), ter(tesSUCCESS)); env.require( balance(alice, startBalance - (f * 3) + XRP(500)), @@ -856,22 +769,15 @@ public: // No cross: { TER const expectedCode = tecKILLED; - env(offer(alice, XRP(1000), USD(1000)), - txflags(tfImmediateOrCancel), - ter(expectedCode)); + env(offer(alice, XRP(1000), USD(1000)), txflags(tfImmediateOrCancel), ter(expectedCode)); } env.require( - balance(alice, startBalance - f - f), - balance(alice, USD(1000)), - owners(alice, 1), - offers(alice, 0)); + balance(alice, startBalance - f - f), balance(alice, USD(1000)), owners(alice, 1), offers(alice, 0)); // Partially cross: env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS)); - env(offer(alice, XRP(1000), USD(1000)), - txflags(tfImmediateOrCancel), - ter(tesSUCCESS)); + env(offer(alice, XRP(1000), USD(1000)), txflags(tfImmediateOrCancel), ter(tesSUCCESS)); env.require( balance(alice, startBalance - f - f - f + XRP(50)), @@ -885,9 +791,7 @@ public: // Fully cross: env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS)); - env(offer(alice, XRP(50), USD(50)), - txflags(tfImmediateOrCancel), - ter(tesSUCCESS)); + env(offer(alice, XRP(50), USD(50)), txflags(tfImmediateOrCancel), ter(tesSUCCESS)); env.require( balance(alice, startBalance - f - f - f - f + XRP(100)), @@ -1009,18 +913,12 @@ public: env.close(); // Order that has invalid flags - env(offer(alice, USD(1000), XRP(1000)), - txflags(tfImmediateOrCancel + 1), - ter(temINVALID_FLAG)); - env.require( - balance(alice, startBalance), owners(alice, 0), offers(alice, 0)); + env(offer(alice, USD(1000), XRP(1000)), txflags(tfImmediateOrCancel + 1), ter(temINVALID_FLAG)); + env.require(balance(alice, startBalance), owners(alice, 0), offers(alice, 0)); // Order with incompatible flags - env(offer(alice, USD(1000), XRP(1000)), - txflags(tfImmediateOrCancel | tfFillOrKill), - ter(temINVALID_FLAG)); - env.require( - balance(alice, startBalance), owners(alice, 0), offers(alice, 0)); + env(offer(alice, USD(1000), XRP(1000)), txflags(tfImmediateOrCancel | tfFillOrKill), ter(temINVALID_FLAG)); + env.require(balance(alice, startBalance), owners(alice, 0), offers(alice, 0)); // Sell and buy the same asset { @@ -1054,9 +952,7 @@ public: // Offer with a bad offer sequence { - env(offer(alice, USD(1000), XRP(1000)), - json(jss::OfferSequence, std::uint32_t(0)), - ter(temBAD_SEQUENCE)); + env(offer(alice, USD(1000), XRP(1000)), json(jss::OfferSequence, std::uint32_t(0)), ter(temBAD_SEQUENCE)); env.require(owners(alice, 1), offers(alice, 0)); } @@ -1095,44 +991,22 @@ public: env(trust(alice, usdOffer), ter(tesSUCCESS)); env(pay(gw, alice, usdOffer), ter(tesSUCCESS)); env.close(); - env.require( - balance(alice, startBalance - f), - balance(alice, usdOffer), - offers(alice, 0), - owners(alice, 1)); + env.require(balance(alice, startBalance - f), balance(alice, usdOffer), offers(alice, 0), owners(alice, 1)); - // Place an offer that should have already expired. - // The DepositPreauth amendment changes the return code; adapt to that. - bool const featPreauth{features[featureDepositPreauth]}; + env(offer(alice, xrpOffer, usdOffer), json(sfExpiration.fieldName, lastClose(env)), ter(tecEXPIRED)); - env(offer(alice, xrpOffer, usdOffer), - json(sfExpiration.fieldName, lastClose(env)), - ter(featPreauth ? TER{tecEXPIRED} : TER{tesSUCCESS})); - - env.require( - balance(alice, startBalance - f - f), - balance(alice, usdOffer), - offers(alice, 0), - owners(alice, 1)); + env.require(balance(alice, startBalance - f - f), balance(alice, usdOffer), offers(alice, 0), owners(alice, 1)); env.close(); // Add an offer that expires before the next ledger close - env(offer(alice, xrpOffer, usdOffer), - json(sfExpiration.fieldName, lastClose(env) + 1), - ter(tesSUCCESS)); + env(offer(alice, xrpOffer, usdOffer), json(sfExpiration.fieldName, lastClose(env) + 1), ter(tesSUCCESS)); env.require( - balance(alice, startBalance - f - f - f), - balance(alice, usdOffer), - offers(alice, 1), - owners(alice, 2)); + balance(alice, startBalance - f - f - f), balance(alice, usdOffer), offers(alice, 1), owners(alice, 2)); // The offer expires (it's not removed yet) env.close(); env.require( - balance(alice, startBalance - f - f - f), - balance(alice, usdOffer), - offers(alice, 1), - owners(alice, 2)); + balance(alice, startBalance - f - f - f), balance(alice, usdOffer), offers(alice, 1), owners(alice, 2)); // Add offer - the expired offer is removed env(offer(bob, usdOffer, xrpOffer), ter(tesSUCCESS)); @@ -1188,8 +1062,7 @@ public: env.fund(reserve(env, 0) + f + XRP(1), "carol"); env.close(); env(offer("carol", usdOffer, xrpOffer), ter(tecINSUF_RESERVE_OFFER)); - env.require( - balance("carol", reserve(env, 0) + XRP(1)), owners("carol", 0)); + env.require(balance("carol", reserve(env, 0) + XRP(1)), owners("carol", 0)); // Account has enough for the reserve plus one // offer, and the fee. @@ -1203,16 +1076,13 @@ public: env.fund(reserve(env, 1) + f + xrpOffer, "eve"); env.close(); env(offer("eve", usdOffer, xrpOffer), ter(tesSUCCESS)); - env.require( - balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1)); + env.require(balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1)); } void testSelfCross(bool use_partner, FeatureBitset features) { - testcase( - std::string("Self-crossing") + - (use_partner ? ", with partner account" : "")); + testcase(std::string("Self-crossing") + (use_partner ? ", with partner account" : "")); using namespace jtx; @@ -1321,15 +1191,14 @@ public: testNegativeBalance(FeatureBitset features) { // This test creates an offer test for negative balance - // with transfer fees and miniscule funds. + // with transfer fees and minuscule funds. testcase("Negative Balance"); using namespace jtx; // This is one of the few tests where fixReducedOffersV2 changes the // results. So test both with and without fixReducedOffersV2. - for (FeatureBitset localFeatures : - {features - fixReducedOffersV2, features | fixReducedOffersV2}) + for (FeatureBitset localFeatures : {features - fixReducedOffersV2, features | fixReducedOffersV2}) { Env env{*this, localFeatures}; @@ -1344,8 +1213,7 @@ public: auto const gw_initial_balance = drops(1149999730); auto const alice_initial_balance = drops(499946999680); auto const bob_initial_balance = drops(10199999920); - auto const small_amount = - STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33}; + auto const small_amount = STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33}; env.fund(gw_initial_balance, gw); env.fund(alice_initial_balance, alice); @@ -1371,13 +1239,10 @@ public: // verify balances auto jrr = ledgerEntryState(env, alice, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); jrr = ledgerEntryState(env, bob, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == - "-2710505431213761e-33"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-2710505431213761e-33"); // create crossing offer std::uint32_t const bobOfferSeq = env.seq(bob); @@ -1389,12 +1254,9 @@ public: // offer does not cross alice's offer and goes straight into // the ledger. jrr = ledgerEntryState(env, bob, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == - "-2710505431213761e-33"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-2710505431213761e-33"); - Json::Value const bobOffer = - ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node]; + Json::Value const bobOffer = ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node]; BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] == "1"); BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] == "2000000000"); return; @@ -1410,29 +1272,22 @@ public: auto const crossingDelta = drops(1); jrr = ledgerEntryState(env, alice, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); BEAST_EXPECT( env.balance(alice, xrpIssue()) == - alice_initial_balance - env.current()->fees().base * 3 - - crossingDelta); + alice_initial_balance - env.current()->fees().base * 3 - crossingDelta); jrr = ledgerEntryState(env, bob, gw, "USD"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); - BEAST_EXPECT( - env.balance(bob, xrpIssue()) == - bob_initial_balance - env.current()->fees().base * 2 + - crossingDelta); + env.balance(bob, xrpIssue()) == bob_initial_balance - env.current()->fees().base * 2 + crossingDelta); } } void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features) { - testcase( - std::string("Offer Crossing with XRP, ") + - (reverse_order ? "Reverse" : "Normal") + " order"); + testcase(std::string("Offer Crossing with XRP, ") + (reverse_order ? "Reverse" : "Normal") + " order"); using namespace jtx; @@ -1468,18 +1323,14 @@ public: jrr = ledgerEntryRoot(env, bob); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10000) - XRP(reverse_order ? 4000 : 3000) - - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(10000) - XRP(reverse_order ? 4000 : 3000) - env.current()->fees().base * 2).xrp())); jrr = ledgerEntryState(env, alice, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499"); jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10000) + XRP(reverse_order ? 4000 : 3000) - - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(10000) + XRP(reverse_order ? 4000 : 3000) - env.current()->fees().base * 2).xrp())); } void @@ -1511,16 +1362,14 @@ public: jrr = ledgerEntryRoot(env, bob); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(100000) - XRP(3000) - env.current()->fees().base * 1) - .xrp())); + to_string((XRP(100000) - XRP(3000) - env.current()->fees().base * 1).xrp())); jrr = ledgerEntryState(env, alice, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499"); jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(100000) + XRP(3000) - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(100000) + XRP(3000) - env.current()->fees().base * 2).xrp())); } void @@ -1564,11 +1413,9 @@ public: env(offer_cancel(env.master, nextOfferSeq)); - env(offer_cancel(env.master, env.seq(env.master)), - ter(temBAD_SEQUENCE)); + env(offer_cancel(env.master, env.seq(env.master)), ter(temBAD_SEQUENCE)); - env(offer_cancel(env.master, env.seq(env.master) + 1), - ter(temBAD_SEQUENCE)); + env(offer_cancel(env.master, env.seq(env.master) + 1), ter(temBAD_SEQUENCE)); env.close(); } @@ -1602,11 +1449,8 @@ public: env.require(owners(alice, 1), owners(bob, 2)); auto jro = ledgerEntryOffer(env, bob, bobOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == XRP(500).value().getText()); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == XRP(500).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == USD(100).value().getJson(JsonOptions::none)); env(pay(alice, alice, XRP(500)), sendmax(USD(100))); @@ -1615,8 +1459,7 @@ public: jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10000) + XRP(500) - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(10000) + XRP(500) - env.current()->fees().base * 2).xrp())); jrr = ledgerEntryState(env, bob, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100"); @@ -1648,8 +1491,7 @@ public: env(trust(carol, bob["EUR"](1000))); auto const bobOfferSeq = env.seq(bob); - env(offer(bob, alice["USD"](50), carol["EUR"](200)), - ter(tecUNFUNDED_OFFER)); + env(offer(bob, alice["USD"](50), carol["EUR"](200)), ter(tecUNFUNDED_OFFER)); env(offer(alice, carol["EUR"](200), alice["USD"](50))); @@ -1686,11 +1528,8 @@ public: // The previous payment reduced the remaining offer amount by 200 XRP auto jro = ledgerEntryOffer(env, bob, bobOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == XRP(300).value().getText()); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == - USD(60).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == XRP(300).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == USD(60).value().getJson(JsonOptions::none)); // the balance between alice and gw is 160 USD..200 less the 40 taken // by the offer @@ -1700,8 +1539,7 @@ public: jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10000) + XRP(200) - env.current()->fees().base * 2) - .xrp())); + to_string((XRP(10000) + XRP(200) - env.current()->fees().base * 2).xrp())); // bob got 40 USD from partial consumption of the offer jrr = ledgerEntryState(env, bob, gw, "USD"); @@ -1709,15 +1547,11 @@ public: // Alice converts USD to XRP which should fail // due to PartialPayment. - env(pay(alice, alice, XRP(600)), - sendmax(USD(100)), - ter(tecPATH_PARTIAL)); + env(pay(alice, alice, XRP(600)), sendmax(USD(100)), ter(tecPATH_PARTIAL)); // Alice converts USD to XRP, should succeed because // we permit partial payment - env(pay(alice, alice, XRP(600)), - sendmax(USD(100)), - txflags(tfPartialPayment)); + env(pay(alice, alice, XRP(600)), sendmax(USD(100)), txflags(tfPartialPayment)); // Verify the offer was consumed jro = ledgerEntryOffer(env, bob, bobOfferSeq); @@ -1733,9 +1567,7 @@ public: jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - to_string((XRP(10000) + XRP(200) + XRP(300) - - env.current()->fees().base * 4) - .xrp())); + to_string((XRP(10000) + XRP(200) + XRP(300) - env.current()->fees().base * 4).xrp())); // bob now has 100 USD - 40 from the first payment and 60 from the // second (partial) payment @@ -1778,11 +1610,8 @@ public: BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475"); auto jro = ledgerEntryOffer(env, carol, carolOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == - USD(25).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == XRP(250).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == USD(25).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == XRP(250).value().getText()); } void @@ -1822,15 +1651,11 @@ public: jrr = ledgerEntryRoot(env, bob); BEAST_EXPECT( jrr[jss::node][sfBalance.fieldName] == - std::to_string( - XRP(10000).value().mantissa() + XRP(250).value().mantissa())); + std::to_string(XRP(10000).value().mantissa() + XRP(250).value().mantissa())); auto jro = ledgerEntryOffer(env, carol, carolOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == XRP(250).value().getText()); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == - USD(25).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == XRP(250).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == USD(25).value().getJson(JsonOptions::none)); } void @@ -1885,18 +1710,12 @@ public: BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-370"); auto jro = ledgerEntryOffer(env, carol, carolOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == XRP(200).value().getText()); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == - USD(20).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == XRP(200).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == USD(20).value().getJson(JsonOptions::none)); jro = ledgerEntryOffer(env, dan, danOfferSeq); - BEAST_EXPECT( - jro[jss::node][jss::TakerGets] == - gw2["EUR"](20).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jro[jss::node][jss::TakerPays] == XRP(200).value().getText()); + BEAST_EXPECT(jro[jss::node][jss::TakerGets] == gw2["EUR"](20).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jro[jss::node][jss::TakerPays] == XRP(200).value().getText()); } void @@ -1990,9 +1809,7 @@ public: // fees: // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) + // 1 for payment == 4 - auto const starting_xrp = XRP(100) + - env.current()->fees().accountReserve(3) + - env.current()->fees().base * 4; + auto const starting_xrp = XRP(100) + env.current()->fees().accountReserve(3) + env.current()->fees().base * 4; env.fund(starting_xrp, gw1, gw2, gw3, alice, bob); env.close(); @@ -2014,8 +1831,7 @@ public: BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "100"); jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName] == - STAmount(env.current()->fees().accountReserve(3)).getText()); + jrr[jss::node][sfBalance.fieldName] == STAmount(env.current()->fees().accountReserve(3)).getText()); jrr = ledgerEntryState(env, bob, gw1, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400"); @@ -2059,20 +1875,17 @@ public: env(offer(bob, XRP(100), USD(0.1))); auto jrr = ledgerEntryState(env, alice, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == - "49.96666666666667"); + BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "49.96666666666667"); jrr = ledgerEntryState(env, bob, gw, "USD"); - Json::Value const bobsUSD = - jrr[jss::node][sfBalance.fieldName][jss::value]; + Json::Value const bobUSD = jrr[jss::node][sfBalance.fieldName][jss::value]; if (!NumberSwitchOver) { - BEAST_EXPECT(bobsUSD == "-0.966500000033334"); + BEAST_EXPECT(bobUSD == "-0.966500000033334"); } else { - BEAST_EXPECT(bobsUSD == "-0.9665000000333333"); + BEAST_EXPECT(bobUSD == "-0.9665000000333333"); } } } @@ -2091,9 +1904,7 @@ public: auto const bob = Account{"bob"}; auto const USD = gw["USD"]; - auto const starting_xrp = XRP(100) + - env.current()->fees().accountReserve(1) + - env.current()->fees().base * 2; + auto const starting_xrp = XRP(100) + env.current()->fees().accountReserve(1) + env.current()->fees().base * 2; env.fund(starting_xrp, gw, alice, bob); env.close(); @@ -2113,8 +1924,7 @@ public: BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100"); jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName] == - STAmount(env.current()->fees().accountReserve(1)).getText()); + jrr[jss::node][sfBalance.fieldName] == STAmount(env.current()->fees().accountReserve(1)).getText()); jrr = ledgerEntryState(env, bob, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400"); @@ -2134,9 +1944,7 @@ public: auto const bob = Account{"bob"}; auto const USD = gw["USD"]; - auto const starting_xrp = XRP(100) + - env.current()->fees().accountReserve(1) + - env.current()->fees().base * 2; + auto const starting_xrp = XRP(100) + env.current()->fees().accountReserve(1) + env.current()->fees().base * 2; env.fund(starting_xrp, gw, alice, bob); env.close(); @@ -2158,8 +1966,7 @@ public: BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-200"); jrr = ledgerEntryRoot(env, alice); BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName] == - STAmount(env.current()->fees().accountReserve(1)).getText()); + jrr[jss::node][sfBalance.fieldName] == STAmount(env.current()->fees().accountReserve(1)).getText()); jrr = ledgerEntryState(env, bob, gw, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-300"); @@ -2180,9 +1987,7 @@ public: auto const XTS = gw["XTS"]; auto const XXX = gw["XXX"]; - auto const starting_xrp = XRP(100.1) + - env.current()->fees().accountReserve(1) + - env.current()->fees().base * 2; + auto const starting_xrp = XRP(100.1) + env.current()->fees().accountReserve(1) + env.current()->fees().base * 2; env.fund(starting_xrp, gw, alice, bob); env.close(); @@ -2207,22 +2012,16 @@ public: payment[jss::id] = env.seq(bob); payment[jss::build_path] = true; payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1)); - payment[jss::tx_json][jss::Sequence] = - env.current() - ->read(keylet::account(bob.id())) - ->getFieldU32(sfSequence); + payment[jss::tx_json][jss::Sequence] = env.current()->read(keylet::account(bob.id()))->getFieldU32(sfSequence); payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base); - payment[jss::tx_json][jss::SendMax] = - bob["XTS"](1.5).value().getJson(JsonOptions::none); + payment[jss::tx_json][jss::SendMax] = bob["XTS"](1.5).value().getJson(JsonOptions::none); auto jrr = wsc->invoke("submit", payment); BEAST_EXPECT(jrr[jss::status] == "success"); BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS"); if (wsc->version() == 2) { - BEAST_EXPECT( - jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5); } @@ -2244,13 +2043,9 @@ public: // a trust line defined). If the trustline is not defaulted then the tests // will not pass. void - verifyDefaultTrustline( - jtx::Env& env, - jtx::Account const& account, - jtx::PrettyAmount const& expectBalance) + verifyDefaultTrustline(jtx::Env& env, jtx::Account const& account, jtx::PrettyAmount const& expectBalance) { - auto const sleTrust = - env.le(keylet::line(account.id(), expectBalance.value().issue())); + auto const sleTrust = env.le(keylet::line(account.id(), expectBalance.value().issue())); BEAST_EXPECT(sleTrust); if (sleTrust) { @@ -2313,7 +2108,7 @@ public: // clang-format off TestData const tests[]{ - // acct fundXrp bookAmt preTrust offerAmt tec spentXrp balanceUSD offers owners + // acct fundXrp bookAmt preTrust offerAmount tec spentXrp balanceUSD offers owners {"ann", reserve(env, 0) + 0 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account is at the reserve, and will dip below once fees are subtracted. {"bev", reserve(env, 0) + 1 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account has just enough for the reserve and the fee. {"cam", reserve(env, 0) + 2 * f, 0, noPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0}, // Account has enough for the reserve, the fee and the offer, and a bit more, but not enough for the reserve after the offer is placed. @@ -2393,8 +2188,7 @@ public: std::uint32_t const acctOfferSeq = env.seq(acct) - 1; BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd); - BEAST_EXPECT( - env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp); + BEAST_EXPECT(env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp); env.require(offers(acct, t.offers)); env.require(owners(acct, t.owners)); @@ -2419,8 +2213,7 @@ public: else { // Verify that no trustline was created. - auto const sleTrust = - env.le(keylet::line(acct, USD.issue())); + auto const sleTrust = env.le(keylet::line(acct, USD.issue())); BEAST_EXPECT(!sleTrust); } } @@ -2472,8 +2265,8 @@ public: // The scenario: // o alice has USD but wants XRP. // o bob has XRP but wants USD. - auto const alicesXRP = env.balance(alice); - auto const bobsXRP = env.balance(bob); + auto const aliceXRP = env.balance(alice); + auto const bobXRP = env.balance(bob); env(offer(alice, xrpOffer, usdOffer)); env.close(); @@ -2483,8 +2276,8 @@ public: env.require( balance(alice, USD(0)), balance(bob, usdOffer), - balance(alice, alicesXRP + xrpOffer - fee), - balance(bob, bobsXRP - xrpOffer - fee), + balance(alice, aliceXRP + xrpOffer - fee), + balance(bob, bobXRP - xrpOffer - fee), offers(alice, 0), offers(bob, 0)); @@ -2500,13 +2293,13 @@ public: env.require(offers(alice, 0)); verifyDefaultTrustline(env, bob, USD(1)); { - auto const bobsOffers = offersOnAccount(env, bob); - BEAST_EXPECT(bobsOffers.size() == 1); - auto const& bobsOffer = *(bobsOffers.front()); + auto const bobOffers = offersOnAccount(env, bob); + BEAST_EXPECT(bobOffers.size() == 1); + auto const& bobOffer = *(bobOffers.front()); - BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER); - BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1)); - BEAST_EXPECT(bobsOffer[sfTakerPays] == XRP(1)); + BEAST_EXPECT(bobOffer[sfLedgerEntryType] == ltOFFER); + BEAST_EXPECT(bobOffer[sfTakerGets] == USD(1)); + BEAST_EXPECT(bobOffer[sfTakerPays] == XRP(1)); } } @@ -2557,11 +2350,7 @@ public: env(offer(bob, usdOffer, eurOffer)); env.close(); - env.require( - balance(alice, eurOffer), - balance(bob, usdOffer), - offers(alice, 0), - offers(bob, 0)); + env.require(balance(alice, eurOffer), balance(bob, usdOffer), offers(alice, 0), offers(bob, 0)); // Alice's offer crossing created a default EUR trustline and // Bob's offer crossing created a default USD trustline: @@ -2586,13 +2375,13 @@ public: env.require(balance(bob, EUR(999))); { - auto bobsOffers = offersOnAccount(env, bob); - if (BEAST_EXPECT(bobsOffers.size() == 1)) + auto bobOffers = offersOnAccount(env, bob); + if (BEAST_EXPECT(bobOffers.size() == 1)) { - auto const& bobsOffer = *(bobsOffers.front()); + auto const& bobOffer = *(bobOffers.front()); - BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1)); - BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1)); + BEAST_EXPECT(bobOffer[sfTakerGets] == USD(1)); + BEAST_EXPECT(bobOffer[sfTakerPays] == EUR(1)); } } @@ -2681,22 +2470,22 @@ public: verifyDefaultTrustline(env, bob, EUR(400)); verifyDefaultTrustline(env, carol, USD(400)); { - auto const alicesOffers = offersOnAccount(env, alice); - BEAST_EXPECT(alicesOffers.size() == 1); - auto const& alicesOffer = *(alicesOffers.front()); + auto const aliceOffers = offersOnAccount(env, alice); + BEAST_EXPECT(aliceOffers.size() == 1); + auto const& aliceOffer = *(aliceOffers.front()); - BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER); - BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600)); - BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(600)); + BEAST_EXPECT(aliceOffer[sfLedgerEntryType] == ltOFFER); + BEAST_EXPECT(aliceOffer[sfTakerGets] == USD(600)); + BEAST_EXPECT(aliceOffer[sfTakerPays] == XRP(600)); } { - auto const bobsOffers = offersOnAccount(env, bob); - BEAST_EXPECT(bobsOffers.size() == 1); - auto const& bobsOffer = *(bobsOffers.front()); + auto const bobOffers = offersOnAccount(env, bob); + BEAST_EXPECT(bobOffers.size() == 1); + auto const& bobOffer = *(bobOffers.front()); - BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER); - BEAST_EXPECT(bobsOffer[sfTakerGets] == XRP(600)); - BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600)); + BEAST_EXPECT(bobOffer[sfLedgerEntryType] == ltOFFER); + BEAST_EXPECT(bobOffer[sfTakerGets] == XRP(600)); + BEAST_EXPECT(bobOffer[sfTakerPays] == EUR(600)); } // carol makes an offer that exactly consumes alice and bob's offers. @@ -2714,15 +2503,15 @@ public: verifyDefaultTrustline(env, carol, USD(1000)); // In pre-flow code alice's offer is left empty in the ledger. - auto const alicesOffers = offersOnAccount(env, alice); - if (alicesOffers.size() != 0) + auto const aliceOffers = offersOnAccount(env, alice); + if (aliceOffers.size() != 0) { - BEAST_EXPECT(alicesOffers.size() == 1); - auto const& alicesOffer = *(alicesOffers.front()); + BEAST_EXPECT(aliceOffers.size() == 1); + auto const& aliceOffer = *(aliceOffers.front()); - BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER); - BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0)); - BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(0)); + BEAST_EXPECT(aliceOffer[sfLedgerEntryType] == ltOFFER); + BEAST_EXPECT(aliceOffer[sfTakerGets] == USD(0)); + BEAST_EXPECT(aliceOffer[sfTakerPays] == XRP(0)); } } @@ -2888,8 +2677,7 @@ public: // Check results BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd); - BEAST_EXPECT( - env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp); + BEAST_EXPECT(env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp); env.require(offers(acct, t.offers)); env.require(owners(acct, t.owners)); @@ -2946,8 +2734,7 @@ public: env.close(); { // alice submits a tfSell | tfFillOrKill offer that does not cross. - env(offer(alice, USD(21), XRP(2100), tfSell | tfFillOrKill), - ter(killedCode)); + env(offer(alice, USD(21), XRP(2100), tfSell | tfFillOrKill), ter(killedCode)); env.close(); env.require(balance(alice, USD(none))); env.require(offers(alice, 0)); @@ -2980,8 +2767,7 @@ public: // all of the offer is consumed. // We're using bob's left-over offer for XRP(500), USD(5) - env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill), - ter(killedCode)); + env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill), ter(killedCode)); env.close(); env.require(balance(alice, USD(35))); env.require(offers(alice, 0)); @@ -3893,16 +3679,16 @@ public: // Place alice's tiny offer in the book first. Let's see what happens // when a reasonable offer crosses it. - STAmount const alicesCnyOffer{ + STAmount const aliceCnyOffer{ CNY.issue(), std::uint64_t(4926000000000000), -23}; - env(offer(alice, alicesCnyOffer, drops(1), tfPassive)); + env(offer(alice, aliceCnyOffer, drops(1), tfPassive)); env.close(); // bob places an ordinary offer - STAmount const bobsCnyStartBalance{ + STAmount const bobCnyStartBalance{ CNY.issue(), std::uint64_t(3767479960090235), -15}; - env(pay(gw, bob, bobsCnyStartBalance)); + env(pay(gw, bob, bobCnyStartBalance)); env.close(); env(offer( @@ -3911,9 +3697,9 @@ public: STAmount{CNY.issue(), std::uint64_t(1000000000000000), -20})); env.close(); - env.require(balance(alice, alicesCnyOffer)); + env.require(balance(alice, aliceCnyOffer)); env.require(balance(alice, startXrpBalance - fee - drops(1))); - env.require(balance(bob, bobsCnyStartBalance - alicesCnyOffer)); + env.require(balance(bob, bobCnyStartBalance - aliceCnyOffer)); env.require(balance(bob, startXrpBalance - (fee * 2) + drops(1))); } @@ -4049,12 +3835,9 @@ public: auto actorOffers = offersOnAccount(env, actor.acct); auto const offerCount = std::distance( actorOffers.begin(), - std::remove_if( - actorOffers.begin(), - actorOffers.end(), - [](std::shared_ptr& offer) { - return (*offer)[sfTakerGets].signum() == 0; - })); + std::remove_if(actorOffers.begin(), actorOffers.end(), [](std::shared_ptr& offer) { + return (*offer)[sfTakerGets].signum() == 0; + })); BEAST_EXPECT(offerCount == actor.offers); env.require(balance(actor.acct, actor.xrp)); @@ -4198,12 +3981,9 @@ public: auto actorOffers = offersOnAccount(env, actor.acct); auto const offerCount = std::distance( actorOffers.begin(), - std::remove_if( - actorOffers.begin(), - actorOffers.end(), - [](std::shared_ptr& offer) { - return (*offer)[sfTakerGets].signum() == 0; - })); + std::remove_if(actorOffers.begin(), actorOffers.end(), [](std::shared_ptr& offer) { + return (*offer)[sfTakerGets].signum() == 0; + })); BEAST_EXPECT(offerCount == actor.offers); env.require(balance(actor.acct, actor.xrp)); @@ -4453,12 +4233,10 @@ public: // MM places offers float const rate = 0.9f; // 0.9 USD = 1 EUR - env(offer(mm, EUR(4000000 * rate), USD(4000000)), - json(jss::Flags, tfSell)); + env(offer(mm, EUR(4000000 * rate), USD(4000000)), json(jss::Flags, tfSell)); float const reverseRate = 1.0f / rate * 1.00101f; - env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)), - json(jss::Flags, tfSell)); + env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)), json(jss::Flags, tfSell)); env.close(); // There should be a path available from hot US to cold EUR @@ -4470,13 +4248,10 @@ public: jvParams[jss::destination_amount][jss::value] = 10; jvParams[jss::source_account] = hotUS.human(); - Json::Value const jrr{env.rpc( - "json", "ripple_path_find", to_string(jvParams))[jss::result]}; + Json::Value const jrr{env.rpc("json", "ripple_path_find", to_string(jvParams))[jss::result]}; BEAST_EXPECT(jrr[jss::status] == "success"); - BEAST_EXPECT( - jrr[jss::alternatives].isArray() && - jrr[jss::alternatives].size() > 0); + BEAST_EXPECT(jrr[jss::alternatives].isArray() && jrr[jss::alternatives].size() > 0); } // Send the payment using the found path. env(pay(hotUS, coldEU, EUR(10)), sendmax(USD(11.1223326))); @@ -4518,21 +4293,13 @@ public: env(fset(gw, asfRequireAuth)); env.close(); - // The test behaves differently with or without DepositPreauth. - bool const preauth = features[featureDepositPreauth]; - // Before DepositPreauth an account with lsfRequireAuth set could not // create an offer to buy their own currency. After DepositPreauth // they can. - env(offer(gw, gwUSD(40), XRP(4000)), - ter(preauth ? TER{tesSUCCESS} : TER{tecNO_LINE})); + env(offer(gw, gwUSD(40), XRP(4000)), ter(tesSUCCESS)); env.close(); - env.require(offers(gw, preauth ? 1 : 0)); - - if (!preauth) - // The rest of the test verifies DepositPreauth behavior. - return; + env.require(offers(gw, 1)); // Set up an authorized trust line and pay alice gwUSD 50. env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth)); @@ -4562,10 +4329,8 @@ public: testcase("Deleted offer issuer"); - auto trustLineExists = [](jtx::Env const& env, - jtx::Account const& src, - jtx::Account const& dst, - Currency const& cur) -> bool { + auto trustLineExists = + [](jtx::Env const& env, jtx::Account const& src, jtx::Account const& dst, Currency const& cur) -> bool { return bool(env.le(keylet::line(src, dst, cur))); }; @@ -4605,8 +4370,7 @@ public: { // The ledger sequence needs to far enough ahead of the account // sequence before the account can be deleted. - int const delta = - [&env, &gw, openLedgerSeq = env.current()->seq()]() -> int { + int const delta = [&env, &gw, openLedgerSeq = env.current()->seq()]() -> int { std::uint32_t const gwSeq{env.seq(gw)}; if (gwSeq + 255 > openLedgerSeq) return gwSeq - openLedgerSeq + 255; @@ -4617,8 +4381,7 @@ public: env.close(); // Account deletion has a high fee. Account for that. - env(acctdelete(gw, alice), - fee(drops(env.current()->fees().increment))); + env(acctdelete(gw, alice), fee(drops(env.current()->fees().increment))); env.close(); // Verify that gw's account root is gone from the ledger. @@ -4731,40 +4494,31 @@ public: env(offer(alice, XTS(30), XXX(10)), json(jss::Flags, tfSell)); std::map> offers; - forEachItem( - *env.current(), alice, [&](std::shared_ptr const& sle) { - if (sle->getType() == ltOFFER) - offers.emplace( - (*sle)[sfSequence], - std::make_pair( - (*sle)[sfTakerPays], (*sle)[sfTakerGets])); - }); + forEachItem(*env.current(), alice, [&](std::shared_ptr const& sle) { + if (sle->getType() == ltOFFER) + offers.emplace((*sle)[sfSequence], std::make_pair((*sle)[sfTakerPays], (*sle)[sfTakerGets])); + }); // first offer auto it = offers.begin(); BEAST_EXPECT(it != offers.end()); - BEAST_EXPECT( - it->second.first == XTS(10) && it->second.second < XXX(30) && - it->second.second > XXX(29.9994)); + BEAST_EXPECT(it->second.first == XTS(10) && it->second.second < XXX(30) && it->second.second > XXX(29.9994)); // second offer ++it; BEAST_EXPECT(it != offers.end()); - BEAST_EXPECT( - it->second.first == XTS(30) && it->second.second == XXX(10)); + BEAST_EXPECT(it->second.first == XTS(30) && it->second.second == XXX(10)); // third offer ++it; BEAST_EXPECT(it != offers.end()); - BEAST_EXPECT( - it->second.first == XTS(10.0002) && it->second.second == XXX(30)); + BEAST_EXPECT(it->second.first == XTS(10.0002) && it->second.second == XXX(30)); // fourth offer // exact TakerPays is XTS(1/.033333) ++it; BEAST_EXPECT(it != offers.end()); - BEAST_EXPECT( - it->second.first == XTS(30) && it->second.second == XXX(10)); + BEAST_EXPECT(it->second.first == XTS(30) && it->second.second == XXX(10)); BEAST_EXPECT(++it == offers.end()); } @@ -4773,13 +4527,11 @@ public: static std::vector> sortedOffersOnAccount(jtx::Env& env, jtx::Account const& acct) { - std::vector> offers{ - offersOnAccount(env, acct)}; + std::vector> offers{offersOnAccount(env, acct)}; std::sort( offers.begin(), offers.end(), - [](std::shared_ptr const& rhs, - std::shared_ptr const& lhs) { + [](std::shared_ptr const& rhs, std::shared_ptr const& lhs) { return (*rhs)[sfSequence] < (*lhs)[sfSequence]; }); return offers; @@ -5069,15 +4821,12 @@ public: // tfFillOrKill, TakerPays must be filled { - TER const err = - features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED; + TER const err = features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED; env(offer(maker, XRP(100), USD(100))); env.close(); - env(offer(taker, USD(100), XRP(101)), - txflags(tfFillOrKill), - ter(err)); + env(offer(taker, USD(100), XRP(101)), txflags(tfFillOrKill), ter(err)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5094,9 +4843,7 @@ public: env(offer(maker, USD(100), XRP(100))); env.close(); - env(offer(taker, XRP(100), USD(101)), - txflags(tfFillOrKill), - ter(err)); + env(offer(taker, XRP(100), USD(101)), txflags(tfFillOrKill), ter(err)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5113,9 +4860,7 @@ public: env(offer(maker, USD(100), EUR(100))); env.close(); - env(offer(taker, EUR(100), USD(101)), - txflags(tfFillOrKill), - ter(err)); + env(offer(taker, EUR(100), USD(101)), txflags(tfFillOrKill), ter(err)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5135,8 +4880,7 @@ public: env(offer(maker, XRP(101), USD(101))); env.close(); - env(offer(taker, USD(100), XRP(101)), - txflags(tfFillOrKill | tfSell)); + env(offer(taker, USD(100), XRP(101)), txflags(tfFillOrKill | tfSell)); env.close(); makerUSDBalance -= USD(101); @@ -5148,8 +4892,7 @@ public: env(offer(maker, USD(101), XRP(101))); env.close(); - env(offer(taker, XRP(100), USD(101)), - txflags(tfFillOrKill | tfSell)); + env(offer(taker, XRP(100), USD(101)), txflags(tfFillOrKill | tfSell)); env.close(); makerUSDBalance += USD(101); @@ -5161,8 +4904,7 @@ public: env(offer(maker, USD(101), EUR(101))); env.close(); - env(offer(taker, EUR(100), USD(101)), - txflags(tfFillOrKill | tfSell)); + env(offer(taker, EUR(100), USD(101)), txflags(tfFillOrKill | tfSell)); env.close(); makerUSDBalance += USD(101); @@ -5180,9 +4922,7 @@ public: env(offer(maker, XRP(100), USD(100))); env.close(); - env(offer(taker, USD(100), XRP(99)), - txflags(flags), - ter(tecKILLED)); + env(offer(taker, USD(100), XRP(99)), txflags(flags), ter(tecKILLED)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5192,9 +4932,7 @@ public: env(offer(maker, USD(100), XRP(100))); env.close(); - env(offer(taker, XRP(100), USD(99)), - txflags(flags), - ter(tecKILLED)); + env(offer(taker, XRP(100), USD(99)), txflags(flags), ter(tecKILLED)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5204,9 +4942,7 @@ public: env(offer(maker, USD(100), EUR(100))); env.close(); - env(offer(taker, EUR(100), USD(99)), - txflags(flags), - ter(tecKILLED)); + env(offer(taker, EUR(100), USD(99)), txflags(flags), ter(tecKILLED)); env.close(); makerXRPBalance -= txfee(env, 1); @@ -5215,12 +4951,9 @@ public: } BEAST_EXPECT( - env.balance(maker, USD) == makerUSDBalance && - env.balance(taker, USD) == takerUSDBalance && - env.balance(maker, EUR) == makerEURBalance && - env.balance(taker, EUR) == takerEURBalance && - env.balance(maker, XRP) == makerXRPBalance && - env.balance(taker, XRP) == takerXRPBalance); + env.balance(maker, USD) == makerUSDBalance && env.balance(taker, USD) == takerUSDBalance && + env.balance(maker, EUR) == makerEURBalance && env.balance(taker, EUR) == takerEURBalance && + env.balance(maker, XRP) == makerXRPBalance && env.balance(taker, XRP) == takerXRPBalance); } void @@ -5331,10 +5064,10 @@ class Offer_manual_test : public OfferBaseUtil_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, ripple, 2); -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, ripple, 20); +BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, xrpl, 2); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, xrpl, 20); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Oracle_test.cpp b/src/test/app/Oracle_test.cpp index c81d441abc..66a8969164 100644 --- a/src/test/app/Oracle_test.cpp +++ b/src/test/app/Oracle_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace oracle { @@ -63,14 +44,8 @@ private: // Insufficient reserve if the data series extends to greater than 5 { Env env(*this); - env.fund( - env.current()->fees().accountReserve(1) + - env.current()->fees().base * 2, - owner); - Oracle oracle( - env, - {.owner = owner, - .fee = static_cast(env.current()->fees().base.drops())}); + env.fund(env.current()->fees().accountReserve(1) + env.current()->fees().base * 2, owner); + Oracle oracle(env, {.owner = owner, .fee = static_cast(env.current()->fees().base.drops())}); BEAST_EXPECT(oracle.exists()); oracle.set(UpdateArg{ .series = @@ -87,40 +62,31 @@ private: { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}, false); // Invalid flag - oracle.set(CreateArg{ - .flags = tfSellNFToken, - .fee = baseFee, - .err = ter(temINVALID_FLAG)}); + oracle.set(CreateArg{.flags = tfSellNFToken, .fee = baseFee, .err = ter(temINVALID_FLAG)}); // Duplicate token pair oracle.set(CreateArg{ - .series = {{"XRP", "USD", 740, 1}, {"XRP", "USD", 750, 1}}, - .fee = baseFee, - .err = ter(temMALFORMED)}); + .series = {{"XRP", "USD", 740, 1}, {"XRP", "USD", 750, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); // Price is not included oracle.set(CreateArg{ - .series = - {{"XRP", "USD", 740, 1}, {"XRP", "EUR", std::nullopt, 1}}, + .series = {{"XRP", "USD", 740, 1}, {"XRP", "EUR", std::nullopt, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); // Token pair is in update and delete oracle.set(CreateArg{ - .series = - {{"XRP", "USD", 740, 1}, {"XRP", "USD", std::nullopt, 1}}, + .series = {{"XRP", "USD", 740, 1}, {"XRP", "USD", std::nullopt, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); // Token pair is in add and delete oracle.set(CreateArg{ - .series = - {{"XRP", "EUR", 740, 1}, {"XRP", "EUR", std::nullopt, 1}}, + .series = {{"XRP", "EUR", 740, 1}, {"XRP", "EUR", std::nullopt, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); @@ -140,23 +106,16 @@ private: {"XRP", "U11", 740, 1}}, .fee = baseFee, .err = ter(temARRAY_TOO_LARGE)}); - oracle.set(CreateArg{ - .series = {}, .fee = baseFee, .err = ter(temARRAY_EMPTY)}); + oracle.set(CreateArg{.series = {}, .fee = baseFee, .err = ter(temARRAY_EMPTY)}); } // Array of token pair exceeds 10 after update { Env env{*this}; - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); - Oracle oracle( - env, - CreateArg{ - .owner = owner, - .series = {{{"XRP", "USD", 740, 1}}}, - .fee = baseFee}); + Oracle oracle(env, CreateArg{.owner = owner, .series = {{{"XRP", "USD", 740, 1}}}, .fee = baseFee}); oracle.set(UpdateArg{ .series = { @@ -177,17 +136,13 @@ private: { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}, false); // Asset class or provider not included on create oracle.set(CreateArg{ - .assetClass = std::nullopt, - .provider = "provider", - .fee = baseFee, - .err = ter(temMALFORMED)}); + .assetClass = std::nullopt, .provider = "provider", .fee = baseFee, .err = ter(temMALFORMED)}); oracle.set(CreateArg{ .assetClass = "currency", .provider = std::nullopt, @@ -197,14 +152,10 @@ private: // Asset class or provider are included on update // and don't match the current values - oracle.set(CreateArg{ - .fee = static_cast(env.current()->fees().base.drops())}); + oracle.set(CreateArg{.fee = static_cast(env.current()->fees().base.drops())}); BEAST_EXPECT(oracle.exists()); oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 740, 1}}, - .provider = "provider1", - .fee = baseFee, - .err = ter(temMALFORMED)}); + .series = {{"XRP", "USD", 740, 1}}, .provider = "provider1", .fee = baseFee, .err = ter(temMALFORMED)}); oracle.set(UpdateArg{ .series = {{"XRP", "USD", 740, 1}}, .assetClass = "currency1", @@ -214,66 +165,49 @@ private: { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}, false); // Fields too long // Asset class std::string assetClass(17, '0'); - oracle.set(CreateArg{ - .assetClass = assetClass, - .fee = baseFee, - .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.assetClass = assetClass, .fee = baseFee, .err = ter(temMALFORMED)}); // provider std::string const large(257, '0'); - oracle.set(CreateArg{ - .provider = large, .fee = baseFee, .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.provider = large, .fee = baseFee, .err = ter(temMALFORMED)}); // URI - oracle.set(CreateArg{ - .uri = large, .fee = baseFee, .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.uri = large, .fee = baseFee, .err = ter(temMALFORMED)}); // Empty field // Asset class - oracle.set(CreateArg{ - .assetClass = "", .fee = baseFee, .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.assetClass = "", .fee = baseFee, .err = ter(temMALFORMED)}); // provider - oracle.set(CreateArg{ - .provider = "", .fee = baseFee, .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.provider = "", .fee = baseFee, .err = ter(temMALFORMED)}); // URI - oracle.set( - CreateArg{.uri = "", .fee = baseFee, .err = ter(temMALFORMED)}); + oracle.set(CreateArg{.uri = "", .fee = baseFee, .err = ter(temMALFORMED)}); } { // Different owner creates a new object and fails because // of missing fields currency/provider Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); Account const some("some"); env.fund(XRP(1'000), owner); env.fund(XRP(1'000), some); Oracle oracle(env, {.owner = owner, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); - oracle.set(UpdateArg{ - .owner = some, - .series = {{"XRP", "USD", 740, 1}}, - .fee = baseFee, - .err = ter(temMALFORMED)}); + oracle.set( + UpdateArg{.owner = some, .series = {{"XRP", "USD", 740, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); } { // Invalid update time using namespace std::chrono; Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); auto closeTime = [&]() { - return duration_cast( - env.current()->info().closeTime.time_since_epoch() - - 10'000s) - .count(); + return duration_cast(env.current()->header().closeTime.time_since_epoch() - 10'000s).count(); }; env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); @@ -291,10 +225,8 @@ private: .lastUpdateTime = static_cast(closeTime() + 311), .fee = baseFee, .err = ter(tecINVALID_UPDATE_TIME)}); - oracle.set( - UpdateArg{.series = {{"XRP", "USD", 740, 1}}, .fee = baseFee}); - BEAST_EXPECT(oracle.expectLastUpdateTime( - static_cast(testStartTime.count() + 450))); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 740, 1}}, .fee = baseFee}); + BEAST_EXPECT(oracle.expectLastUpdateTime(static_cast(testStartTime.count() + 450))); // Less than the previous lastUpdateTime oracle.set(UpdateArg{ .series = {{"XRP", "USD", 740, 1}}, @@ -312,8 +244,7 @@ private: { // delete token pair that doesn't exist Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); @@ -323,30 +254,22 @@ private: .err = ter(tecTOKEN_PAIR_NOT_FOUND)}); // delete all token pairs oracle.set(UpdateArg{ - .series = {{"XRP", "USD", std::nullopt, std::nullopt}}, - .fee = baseFee, - .err = ter(tecARRAY_EMPTY)}); + .series = {{"XRP", "USD", std::nullopt, std::nullopt}}, .fee = baseFee, .err = ter(tecARRAY_EMPTY)}); } { // same BaseAsset and QuoteAsset Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle( - env, - {.owner = owner, - .series = {{"USD", "USD", 740, 1}}, - .fee = baseFee, - .err = ter(temMALFORMED)}); + env, {.owner = owner, .series = {{"USD", "USD", 740, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); } { // Scale is greater than maxPriceScale Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle( env, @@ -359,14 +282,11 @@ private: { // Updating token pair to add and delete Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); oracle.set(UpdateArg{ - .series = - {{"XRP", "EUR", std::nullopt, std::nullopt}, - {"XRP", "EUR", 740, 1}}, + .series = {{"XRP", "EUR", std::nullopt, std::nullopt}, {"XRP", "EUR", 740, 1}}, .fee = baseFee, .err = ter(temMALFORMED)}); // Delete token pair that doesn't exist in this oracle @@ -386,14 +306,9 @@ private: // Bad fee Env env(*this); env.fund(XRP(1'000), owner); - Oracle oracle( - env, {.owner = owner, .fee = -1, .err = ter(temBAD_FEE)}); - Oracle oracle1( - env, - {.owner = owner, - .fee = static_cast(env.current()->fees().base.drops())}); - oracle.set( - UpdateArg{.owner = owner, .fee = -1, .err = ter(temBAD_FEE)}); + Oracle oracle(env, {.owner = owner, .fee = -1, .err = ter(temBAD_FEE)}); + Oracle oracle1(env, {.owner = owner, .fee = static_cast(env.current()->fees().base.drops())}); + oracle.set(UpdateArg{.owner = owner, .fee = -1, .err = ter(temBAD_FEE)}); } } @@ -405,21 +320,17 @@ private: Account const owner("owner"); auto test = [&](Env& env, DataSeries const& series, std::uint16_t adj) { - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); auto const count = ownerCount(env, owner); - Oracle oracle( - env, {.owner = owner, .series = series, .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .series = series, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); BEAST_EXPECT(ownerCount(env, owner) == (count + adj)); auto const entry = oracle.ledgerEntry(); BEAST_EXPECT(entry[jss::node][jss::Owner] == owner.human()); if (features[fixIncludeKeyletFields]) { - BEAST_EXPECT( - entry[jss::node][jss::OracleDocumentID] == - oracle.documentID()); + BEAST_EXPECT(entry[jss::node][jss::OracleDocumentID] == oracle.documentID()); } else { @@ -451,17 +362,13 @@ private: { // Different owner creates a new object Env env(*this, features); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); Account const some("some"); env.fund(XRP(1'000), owner); env.fund(XRP(1'000), some); Oracle oracle(env, {.owner = owner, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); - oracle.set(CreateArg{ - .owner = some, - .series = {{"912810RR9", "USD", 740, 1}}, - .fee = baseFee}); + oracle.set(CreateArg{.owner = some, .series = {{"912810RR9", "USD", 740, 1}}, .fee = baseFee}); BEAST_EXPECT(Oracle::exists(env, some, oracle.documentID())); } } @@ -473,8 +380,7 @@ private: using namespace jtx; Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); Account const owner("owner"); env.fund(XRP(1'000), owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); @@ -484,28 +390,19 @@ private: // Invalid account Account const bad("bad"); env.memoize(bad); - oracle.remove( - {.owner = bad, - .seq = seq(1), - .fee = baseFee, - .err = ter(terNO_ACCOUNT)}); + oracle.remove({.owner = bad, .seq = seq(1), .fee = baseFee, .err = ter(terNO_ACCOUNT)}); } // Invalid DocumentID - oracle.remove( - {.documentID = 2, .fee = baseFee, .err = ter(tecNO_ENTRY)}); + oracle.remove({.documentID = 2, .fee = baseFee, .err = ter(tecNO_ENTRY)}); // Invalid owner Account const invalid("invalid"); env.fund(XRP(1'000), invalid); - oracle.remove( - {.owner = invalid, .fee = baseFee, .err = ter(tecNO_ENTRY)}); + oracle.remove({.owner = invalid, .fee = baseFee, .err = ter(tecNO_ENTRY)}); // Invalid flags - oracle.remove( - {.flags = tfSellNFToken, - .fee = baseFee, - .err = ter(temINVALID_FLAG)}); + oracle.remove({.flags = tfSellNFToken, .fee = baseFee, .err = ter(temINVALID_FLAG)}); // Bad fee oracle.remove({.fee = -1, .err = ter(temBAD_FEE)}); @@ -519,11 +416,9 @@ private: Account const owner("owner"); auto test = [&](Env& env, DataSeries const& series, std::uint16_t adj) { - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); - Oracle oracle( - env, {.owner = owner, .series = series, .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .series = series, .fee = baseFee}); auto const count = ownerCount(env, owner); BEAST_EXPECT(oracle.exists()); oracle.remove({.fee = baseFee}); @@ -556,29 +451,19 @@ private: { // deleting the account deletes the oracles Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); auto const alice = Account("alice"); auto const acctDelFee{drops(env.current()->fees().increment)}; env.fund(XRP(1'000), owner); env.fund(XRP(1'000), alice); - Oracle oracle( - env, - {.owner = owner, - .series = {{"XRP", "USD", 740, 1}}, - .fee = baseFee}); - Oracle oracle1( - env, - {.owner = owner, - .documentID = 2, - .series = {{"XRP", "EUR", 740, 1}}, - .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .series = {{"XRP", "USD", 740, 1}}, .fee = baseFee}); + Oracle oracle1(env, {.owner = owner, .documentID = 2, .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); BEAST_EXPECT(ownerCount(env, owner) == 2); BEAST_EXPECT(oracle.exists()); BEAST_EXPECT(oracle1.exists()); auto const index = env.closed()->seq(); - auto const hash = env.closed()->info().hash; + auto const hash = env.closed()->header().hash; for (int i = 0; i < 256; ++i) env.close(); env(acctdelete(owner, alice), fee(acctDelFee)); @@ -592,8 +477,7 @@ private: jvParams[field] = value; jvParams[jss::binary] = false; jvParams[jss::type] = jss::oracle; - Json::Value jrr = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams)); BEAST_EXPECT(jrr[jss::result][jss::state].size() == 2); }; verifyLedgerData(jss::ledger_index, index); @@ -610,16 +494,14 @@ private: { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); auto count = ownerCount(env, owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); // update existing pair - oracle.set( - UpdateArg{.series = {{"XRP", "USD", 740, 2}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 740, 2}}, .fee = baseFee}); BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 740, 2}})); // owner count is increased by 1 since the oracle object is added // with one token pair @@ -627,19 +509,14 @@ private: BEAST_EXPECT(ownerCount(env, owner) == count); // add new pairs, not-included pair is reset - oracle.set( - UpdateArg{.series = {{"XRP", "EUR", 700, 2}}, .fee = baseFee}); - BEAST_EXPECT(oracle.expectPrice( - {{"XRP", "USD", 0, 0}, {"XRP", "EUR", 700, 2}})); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 700, 2}}, .fee = baseFee}); + BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 0, 0}, {"XRP", "EUR", 700, 2}})); // owner count is not changed since the number of pairs is 2 BEAST_EXPECT(ownerCount(env, owner) == count); // update both pairs - oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}}, - .fee = baseFee}); - BEAST_EXPECT(oracle.expectPrice( - {{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}})); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}}, .fee = baseFee}); + BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}})); // owner count is not changed since the number of pairs is 2 BEAST_EXPECT(ownerCount(env, owner) == count); @@ -657,9 +534,7 @@ private: BEAST_EXPECT(ownerCount(env, owner) == count); // update two pairs and delete four - oracle.set(UpdateArg{ - .series = {{"BTC", "USD", std::nullopt, std::nullopt}}, - .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"BTC", "USD", std::nullopt, std::nullopt}}, .fee = baseFee}); oracle.set(UpdateArg{ .series = {{"XRP", "USD", 742, 2}, @@ -668,8 +543,7 @@ private: {"YAN", "EUR", std::nullopt, std::nullopt}, {"CAN", "EUR", std::nullopt, std::nullopt}}, .fee = baseFee}); - BEAST_EXPECT(oracle.expectPrice( - {{"XRP", "USD", 742, 2}, {"XRP", "EUR", 711, 2}})); + BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 742, 2}, {"XRP", "EUR", 711, 2}})); // owner count is decreased by 1 since the number of pairs is 2 count -= 1; BEAST_EXPECT(ownerCount(env, owner) == count); @@ -678,57 +552,37 @@ private: // Min reserve to create and update { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); - env.fund( - env.current()->fees().accountReserve(1) + - env.current()->fees().base * 2, - owner); + auto const baseFee = static_cast(env.current()->fees().base.drops()); + env.fund(env.current()->fees().accountReserve(1) + env.current()->fees().base * 2, owner); Oracle oracle(env, {.owner = owner, .fee = baseFee}); - oracle.set( - UpdateArg{.series = {{"XRP", "USD", 742, 2}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 742, 2}}, .fee = baseFee}); } for (bool const withFixOrder : {false, true}) { // Should be same order as creation - Env env( - *this, - withFixOrder ? testable_amendments() - : testable_amendments() - fixPriceOracleOrder); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + Env env(*this, withFixOrder ? testable_amendments() : testable_amendments() - fixPriceOracleOrder); + auto const baseFee = static_cast(env.current()->fees().base.drops()); auto test = [&](Env& env, DataSeries const& series) { env.fund(XRP(1'000), owner); - Oracle oracle( - env, {.owner = owner, .series = series, .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .series = series, .fee = baseFee}); BEAST_EXPECT(oracle.exists()); auto sle = env.le(keylet::oracle(owner, oracle.documentID())); - BEAST_EXPECT( - sle->getFieldArray(sfPriceDataSeries).size() == - series.size()); + BEAST_EXPECT(sle->getFieldArray(sfPriceDataSeries).size() == series.size()); auto const beforeQuoteAssetName1 = - sle->getFieldArray(sfPriceDataSeries)[0] - .getFieldCurrency(sfQuoteAsset) - .getText(); + sle->getFieldArray(sfPriceDataSeries)[0].getFieldCurrency(sfQuoteAsset).getText(); auto const beforeQuoteAssetName2 = - sle->getFieldArray(sfPriceDataSeries)[1] - .getFieldCurrency(sfQuoteAsset) - .getText(); + sle->getFieldArray(sfPriceDataSeries)[1].getFieldCurrency(sfQuoteAsset).getText(); oracle.set(UpdateArg{.series = series, .fee = baseFee}); sle = env.le(keylet::oracle(owner, oracle.documentID())); auto const afterQuoteAssetName1 = - sle->getFieldArray(sfPriceDataSeries)[0] - .getFieldCurrency(sfQuoteAsset) - .getText(); + sle->getFieldArray(sfPriceDataSeries)[0].getFieldCurrency(sfQuoteAsset).getText(); auto const afterQuoteAssetName2 = - sle->getFieldArray(sfPriceDataSeries)[1] - .getFieldCurrency(sfQuoteAsset) - .getText(); + sle->getFieldArray(sfPriceDataSeries)[1].getFieldCurrency(sfQuoteAsset).getText(); if (env.current()->rules().enabled(fixPriceOracleOrder)) { @@ -746,15 +600,14 @@ private: } void - testMultisig(FeatureBitset features) + testMultisig() { testcase("Multisig"); using namespace jtx; Oracle::setFee(100'000); - Env env(*this, features); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + Env env(*this); + auto const baseFee = static_cast(env.current()->fees().base.drops()); Account const alice{"alice", KeyType::secp256k1}; Account const bogie{"bogie", KeyType::secp256k1}; @@ -772,39 +625,24 @@ private: // Attach signers to alice. env(signers(alice, 2, {{becky, 1}, {bogie, 1}, {ed, 2}}), sig(alie)); env.close(); - // if multiSignReserve disabled then its 2 + 1 per signer - int const signerListOwners{features[featureMultiSignReserve] ? 1 : 5}; - env.require(owners(alice, signerListOwners)); + + env.require(owners(alice, 1)); // Create // Force close (true) and time advancement because the close time // is no longer 0. - Oracle oracle( - env, - CreateArg{.owner = alice, .fee = baseFee, .close = true}, - false); - oracle.set(CreateArg{ - .msig = msig(becky), .fee = baseFee, .err = ter(tefBAD_QUORUM)}); - oracle.set(CreateArg{ - .msig = msig(zelda), .fee = baseFee, .err = ter(tefBAD_SIGNATURE)}); + Oracle oracle(env, CreateArg{.owner = alice, .fee = baseFee, .close = true}, false); + oracle.set(CreateArg{.msig = msig(becky), .fee = baseFee, .err = ter(tefBAD_QUORUM)}); + oracle.set(CreateArg{.msig = msig(zelda), .fee = baseFee, .err = ter(tefBAD_SIGNATURE)}); oracle.set(CreateArg{.msig = msig(becky, bogie), .fee = baseFee}); BEAST_EXPECT(oracle.exists()); // Update oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 740, 1}}, - .msig = msig(becky), - .fee = baseFee, - .err = ter(tefBAD_QUORUM)}); + .series = {{"XRP", "USD", 740, 1}}, .msig = msig(becky), .fee = baseFee, .err = ter(tefBAD_QUORUM)}); oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 740, 1}}, - .msig = msig(zelda), - .fee = baseFee, - .err = ter(tefBAD_SIGNATURE)}); - oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 741, 1}}, - .msig = msig(becky, bogie), - .fee = baseFee}); + .series = {{"XRP", "USD", 740, 1}}, .msig = msig(zelda), .fee = baseFee, .err = ter(tefBAD_SIGNATURE)}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 741, 1}}, .msig = msig(becky, bogie), .fee = baseFee}); BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 741, 1}})); // remove the signer list env(signers(alice, jtx::none), sig(alie)); @@ -820,24 +658,14 @@ private: .fee = baseFee, .err = ter(tefBAD_SIGNATURE)}); // updated list succeeds - oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 7412, 2}}, - .msig = msig(zelda, bob), - .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 7412, 2}}, .msig = msig(zelda, bob), .fee = baseFee}); BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 7412, 2}})); - oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 74245, 3}}, - .msig = msig(ed), - .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 74245, 3}}, .msig = msig(ed), .fee = baseFee}); BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 74245, 3}})); // Remove - oracle.remove( - {.msig = msig(bob), .fee = baseFee, .err = ter(tefBAD_QUORUM)}); - oracle.remove( - {.msig = msig(becky), - .fee = baseFee, - .err = ter(tefBAD_SIGNATURE)}); + oracle.remove({.msig = msig(bob), .fee = baseFee, .err = ter(tefBAD_QUORUM)}); + oracle.remove({.msig = msig(becky), .fee = baseFee, .err = ter(tefBAD_SIGNATURE)}); oracle.remove({.msig = msig(ed), .fee = baseFee}); BEAST_EXPECT(!oracle.exists()); } @@ -851,13 +679,11 @@ private: auto const features = testable_amendments() - featurePriceOracle; Account const owner("owner"); Env env(*this, features); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); env.fund(XRP(1'000), owner); { - Oracle oracle( - env, {.owner = owner, .fee = baseFee, .err = ter(temDISABLED)}); + Oracle oracle(env, {.owner = owner, .fee = baseFee, .err = ter(temDISABLED)}); } { @@ -879,15 +705,11 @@ public: testDelete(); testUpdate(); testAmendment(); - for (auto const& features : - {all, - all - featureMultiSignReserve - featureExpandedSignerList, - all - featureExpandedSignerList}) - testMultisig(features); + testMultisig(); } }; -BEAST_DEFINE_TESTSUITE(Oracle, app, ripple); +BEAST_DEFINE_TESTSUITE(Oracle, app, xrpl); } // namespace oracle @@ -895,4 +717,4 @@ BEAST_DEFINE_TESTSUITE(Oracle, app, ripple); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/OversizeMeta_test.cpp b/src/test/app/OversizeMeta_test.cpp index fb6faa3ec3..d5e2948f5b 100644 --- a/src/test/app/OversizeMeta_test.cpp +++ b/src/test/app/OversizeMeta_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { // Make sure "plump" order books don't have problems @@ -61,7 +42,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(PlumpBook, app, ripple, 5); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(PlumpBook, app, xrpl, 5); //------------------------------------------------------------------------------ @@ -76,7 +57,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ThinBook, app, ripple); +BEAST_DEFINE_TESTSUITE(ThinBook, app, xrpl); //------------------------------------------------------------------------------ @@ -119,7 +100,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(OversizeMeta, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(OversizeMeta, app, xrpl, 3); //------------------------------------------------------------------------------ @@ -179,13 +160,12 @@ public: void run() override { - auto const result = - bfind(100, 9000, [&](std::size_t n) { return oversize(n); }); + auto const result = bfind(100, 9000, [&](std::size_t n) { return oversize(n); }); log << "Min oversize offers = " << result << '\n'; } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(FindOversizeCross, app, ripple, 50); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(FindOversizeCross, app, xrpl, 50); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Path_test.cpp b/src/test/app/Path_test.cpp index 26b3dab898..c019c2b8a3 100644 --- a/src/test/app/Path_test.cpp +++ b/src/test/app/Path_test.cpp @@ -1,33 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -#include #include #include #include +#include #include #include #include @@ -42,7 +23,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { //------------------------------------------------------------------------------ @@ -159,8 +140,7 @@ public: params[jss::command] = "ripple_path_find"; params[jss::source_account] = toBase58(src); params[jss::destination_account] = toBase58(dst); - params[jss::destination_amount] = - saDstAmount.getJson(JsonOptions::none); + params[jss::destination_amount] = saDstAmount.getJson(JsonOptions::none); if (saSendMax) params[jss::send_max] = saSendMax->getJson(JsonOptions::none); if (saSrcCurrency) @@ -175,13 +155,12 @@ public: Json::Value result; gate g; - app.getJobQueue().postCoro( - jtCLIENT, "RPC-Client", [&](auto const& coro) { - context.params = std::move(params); - context.coro = coro; - RPC::doCommand(context, result); - g.signal(); - }); + app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) { + context.params = std::move(params); + context.coro = coro; + RPC::doCommand(context, result); + g.signal(); + }); using namespace std::chrono_literals; BEAST_EXPECT(g.wait_for(5s)); @@ -199,8 +178,7 @@ public: std::optional const& saSrcCurrency = std::nullopt, std::optional const& domain = std::nullopt) { - Json::Value result = find_paths_request( - env, src, dst, saDstAmount, saSendMax, saSrcCurrency, domain); + Json::Value result = find_paths_request(env, src, dst, saDstAmount, saSendMax, saSrcCurrency, domain); BEAST_EXPECT(!result.isMember(jss::error)); STAmount da; @@ -220,8 +198,7 @@ public: sa = amountFromJson(sfGeneric, path[jss::source_amount]); if (path.isMember(jss::destination_amount)) - da = amountFromJson( - sfGeneric, path[jss::destination_amount]); + da = amountFromJson(sfGeneric, path[jss::destination_amount]); if (path.isMember(jss::paths_computed)) { @@ -269,53 +246,45 @@ public: Json::Value result; gate g; // Test RPC::Tuning::max_src_cur source currencies. - app.getJobQueue().postCoro( - jtCLIENT, "RPC-Client", [&](auto const& coro) { - context.params = rpf( - Account("alice"), Account("bob"), RPC::Tuning::max_src_cur); - context.coro = coro; - RPC::doCommand(context, result); - g.signal(); - }); + app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) { + context.params = rpf(Account("alice"), Account("bob"), RPC::Tuning::max_src_cur); + context.coro = coro; + RPC::doCommand(context, result); + g.signal(); + }); BEAST_EXPECT(g.wait_for(5s)); BEAST_EXPECT(!result.isMember(jss::error)); // Test more than RPC::Tuning::max_src_cur source currencies. - app.getJobQueue().postCoro( - jtCLIENT, "RPC-Client", [&](auto const& coro) { - context.params = - rpf(Account("alice"), - Account("bob"), - RPC::Tuning::max_src_cur + 1); - context.coro = coro; - RPC::doCommand(context, result); - g.signal(); - }); + app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) { + context.params = rpf(Account("alice"), Account("bob"), RPC::Tuning::max_src_cur + 1); + context.coro = coro; + RPC::doCommand(context, result); + g.signal(); + }); BEAST_EXPECT(g.wait_for(5s)); BEAST_EXPECT(result.isMember(jss::error)); // Test RPC::Tuning::max_auto_src_cur source currencies. for (auto i = 0; i < (RPC::Tuning::max_auto_src_cur - 1); ++i) env.trust(Account("alice")[std::to_string(i + 100)](100), "bob"); - app.getJobQueue().postCoro( - jtCLIENT, "RPC-Client", [&](auto const& coro) { - context.params = rpf(Account("alice"), Account("bob"), 0); - context.coro = coro; - RPC::doCommand(context, result); - g.signal(); - }); + app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) { + context.params = rpf(Account("alice"), Account("bob"), 0); + context.coro = coro; + RPC::doCommand(context, result); + g.signal(); + }); BEAST_EXPECT(g.wait_for(5s)); BEAST_EXPECT(!result.isMember(jss::error)); // Test more than RPC::Tuning::max_auto_src_cur source currencies. env.trust(Account("alice")["AUD"](100), "bob"); - app.getJobQueue().postCoro( - jtCLIENT, "RPC-Client", [&](auto const& coro) { - context.params = rpf(Account("alice"), Account("bob"), 0); - context.coro = coro; - RPC::doCommand(context, result); - g.signal(); - }); + app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) { + context.params = rpf(Account("alice"), Account("bob"), 0); + context.coro = coro; + RPC::doCommand(context, result); + g.signal(); + }); BEAST_EXPECT(g.wait_for(5s)); BEAST_EXPECT(result.isMember(jss::error)); } @@ -329,8 +298,7 @@ public: env.fund(XRP(10000), "alice", "bob"); env.close(); - auto const result = - find_paths(env, "alice", "bob", Account("bob")["USD"](5)); + auto const result = find_paths(env, "alice", "bob", Account("bob")["USD"](5)); BEAST_EXPECT(std::get<0>(result).empty()); } @@ -346,8 +314,7 @@ public: STPathSet st; STAmount sa; - std::tie(st, sa, std::ignore) = - find_paths(env, "alice", "bob", Account("bob")["USD"](5)); + std::tie(st, sa, std::ignore) = find_paths(env, "alice", "bob", Account("bob")["USD"](5)); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(sa, Account("alice")["USD"](5))); } @@ -375,9 +342,7 @@ public: void path_find(bool const domainEnabled) { - testcase( - std::string("path find") + (domainEnabled ? " w/ " : " w/o ") + - "domain"); + testcase(std::string("path find") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); auto const gw = Account("gateway"); @@ -395,14 +360,8 @@ public: STPathSet st; STAmount sa; - std::tie(st, sa, std::ignore) = find_paths( - env, - "alice", - "bob", - Account("bob")["USD"](5), - std::nullopt, - std::nullopt, - domainID); + std::tie(st, sa, std::ignore) = + find_paths(env, "alice", "bob", Account("bob")["USD"](5), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(same(st, stpath("gateway"))); BEAST_EXPECT(equal(sa, Account("alice")["USD"](5))); } @@ -411,9 +370,7 @@ public: xrp_to_xrp(bool const domainEnabled) { using namespace jtx; - testcase( - std::string("XRP to XRP") + (domainEnabled ? " w/ " : " w/o ") + - "domain"); + testcase(std::string("XRP to XRP") + (domainEnabled ? " w/ " : " w/o ") + "domain"); Env env = pathTestEnv(); env.fund(XRP(10000), "alice", "bob"); env.close(); @@ -422,17 +379,14 @@ public: if (domainEnabled) domainID = setupDomain(env, {"alice", "bob"}); - auto const result = find_paths( - env, "alice", "bob", XRP(5), std::nullopt, std::nullopt, domainID); + auto const result = find_paths(env, "alice", "bob", XRP(5), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(std::get<0>(result).empty()); } void path_find_consume_all(bool const domainEnabled) { - testcase( - std::string("path find consume all") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + testcase(std::string("path find consume all") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; { @@ -447,20 +401,13 @@ public: std::optional domainID; if (domainEnabled) - domainID = setupDomain( - env, {"alice", "bob", "carol", "dan", "edward"}); + domainID = setupDomain(env, {"alice", "bob", "carol", "dan", "edward"}); STPathSet st; STAmount sa; STAmount da; - std::tie(st, sa, da) = find_paths( - env, - "alice", - "edward", - Account("edward")["USD"](-1), - std::nullopt, - std::nullopt, - domainID); + std::tie(st, sa, da) = + find_paths(env, "alice", "edward", Account("edward")["USD"](-1), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(same(st, stpath("dan"), stpath("bob", "carol"))); BEAST_EXPECT(equal(sa, Account("alice")["USD"](110))); BEAST_EXPECT(equal(da, Account("edward")["USD"](110))); @@ -480,8 +427,7 @@ public: std::optional domainID; if (domainEnabled) { - domainID = - setupDomain(env, {"alice", "bob", "carol", "gateway"}); + domainID = setupDomain(env, {"alice", "bob", "carol", "gateway"}); env(offer("carol", XRP(100), USD(100)), domain(*domainID)); } else @@ -533,9 +479,7 @@ public: void alternative_path_consume_both(bool const domainEnabled) { - testcase( - std::string("alternative path consume both") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + testcase(std::string("alternative path consume both") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); auto const gw = Account("gateway"); @@ -552,20 +496,16 @@ public: std::optional domainID; if (domainEnabled) { - domainID = - setupDomain(env, {"alice", "bob", "gateway", "gateway2"}); + domainID = setupDomain(env, {"alice", "bob", "gateway", "gateway2"}); env(pay(gw, "alice", USD(70)), domain(*domainID)); env(pay(gw2, "alice", gw2_USD(70)), domain(*domainID)); - env(pay("alice", "bob", Account("bob")["USD"](140)), - paths(Account("alice")["USD"]), - domain(*domainID)); + env(pay("alice", "bob", Account("bob")["USD"](140)), paths(Account("alice")["USD"]), domain(*domainID)); } else { env(pay(gw, "alice", USD(70))); env(pay(gw2, "alice", gw2_USD(70))); - env(pay("alice", "bob", Account("bob")["USD"](140)), - paths(Account("alice")["USD"])); + env(pay("alice", "bob", Account("bob")["USD"](140)), paths(Account("alice")["USD"])); } env.require(balance("alice", USD(0))); @@ -582,8 +522,7 @@ public: alternative_paths_consume_best_transfer(bool const domainEnabled) { testcase( - std::string("alternative paths consume best transfer") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + std::string("alternative paths consume best transfer") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); auto const gw = Account("gateway"); @@ -601,8 +540,7 @@ public: std::optional domainID; if (domainEnabled) { - domainID = - setupDomain(env, {"alice", "bob", "gateway", "gateway2"}); + domainID = setupDomain(env, {"alice", "bob", "gateway", "gateway2"}); env(pay(gw, "alice", USD(70)), domain(*domainID)); env(pay(gw2, "alice", gw2_USD(70)), domain(*domainID)); env(pay("alice", "bob", USD(70)), domain(*domainID)); @@ -656,12 +594,10 @@ public: } void - alternative_paths_limit_returned_paths_to_best_quality( - bool const domainEnabled) + alternative_paths_limit_returned_paths_to_best_quality(bool const domainEnabled) { testcase( - std::string( - "alternative paths - limit returned paths to best quality") + + std::string("alternative paths - limit returned paths to best quality") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); @@ -689,35 +625,21 @@ public: std::optional domainID; if (domainEnabled) { - domainID = - setupDomain(env, {"alice", "bob", "carol", "dan", gw, gw2}); + domainID = setupDomain(env, {"alice", "bob", "carol", "dan", gw, gw2}); } STPathSet st; STAmount sa; - std::tie(st, sa, std::ignore) = find_paths( - env, - "alice", - "bob", - Account("bob")["USD"](5), - std::nullopt, - std::nullopt, - domainID); - BEAST_EXPECT(same( - st, - stpath("gateway"), - stpath("gateway2"), - stpath("dan"), - stpath("carol"))); + std::tie(st, sa, std::ignore) = + find_paths(env, "alice", "bob", Account("bob")["USD"](5), std::nullopt, std::nullopt, domainID); + BEAST_EXPECT(same(st, stpath("gateway"), stpath("gateway2"), stpath("dan"), stpath("carol"))); BEAST_EXPECT(equal(sa, Account("alice")["USD"](5))); } void issues_path_negative_issue(bool const domainEnabled) { - testcase( - std::string("path negative: Issue #5") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + testcase(std::string("path negative: Issue #5") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); env.fund(XRP(10000), "alice", "bob", "carol", "dan"); @@ -736,27 +658,13 @@ public: domainID = setupDomain(env, {"alice", "bob", "carol", "dan"}); } - auto result = find_paths( - env, - "alice", - "bob", - Account("bob")["USD"](25), - std::nullopt, - std::nullopt, - domainID); + auto result = find_paths(env, "alice", "bob", Account("bob")["USD"](25), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(std::get<0>(result).empty()); env(pay("alice", "bob", Account("alice")["USD"](25)), ter(tecPATH_DRY)); env.close(); - result = find_paths( - env, - "alice", - "bob", - Account("alice")["USD"](25), - std::nullopt, - std::nullopt, - domainID); + result = find_paths(env, "alice", "bob", Account("alice")["USD"](25), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(std::get<0>(result).empty()); env.require(balance("alice", Account("bob")["USD"](0))); @@ -786,8 +694,7 @@ public: env.trust(Account("dan")["USD"](20), "bob"); env.trust(Account("alice")["USD"](20), "carol"); env.trust(Account("carol")["USD"](20), "dan"); - env(pay("alice", "bob", Account("bob")["USD"](55)), - paths(Account("alice")["USD"])); + env(pay("alice", "bob", Account("bob")["USD"](55)), paths(Account("alice")["USD"])); env.require(balance("bob", Account("alice")["USD"](40))); env.require(balance("bob", Account("dan")["USD"](15))); } @@ -807,8 +714,7 @@ public: env.trust(Account("dan")["USD"](100), "bob"); env.trust(Account("alice")["USD"](25), "carol"); env.trust(Account("carol")["USD"](75), "dan"); - env(pay("alice", "bob", Account("bob")["USD"](50)), - paths(Account("alice")["USD"])); + env(pay("alice", "bob", Account("bob")["USD"](50)), paths(Account("alice")["USD"])); env.require(balance("alice", Account("edward")["USD"](-25))); env.require(balance("alice", Account("carol")["USD"](-25))); env.require(balance("bob", Account("edward")["USD"](25))); @@ -825,9 +731,7 @@ public: void via_offers_via_gateway(bool const domainEnabled) { - testcase( - std::string("via gateway") + (domainEnabled ? " w/ " : " w/o ") + - "domain"); + testcase(std::string("via gateway") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); auto const gw = Account("gateway"); @@ -847,10 +751,7 @@ public: domainID = setupDomain(env, {"alice", "bob", "carol", gw}); env(offer("carol", XRP(50), AUD(50)), domain(*domainID)); env.close(); - env(pay("alice", "bob", AUD(10)), - sendmax(XRP(100)), - paths(XRP), - domain(*domainID)); + env(pay("alice", "bob", AUD(10)), sendmax(XRP(100)), paths(XRP), domain(*domainID)); env.close(); } else @@ -864,14 +765,8 @@ public: env.require(balance("bob", AUD(10))); env.require(balance("carol", AUD(39))); - auto const result = find_paths( - env, - "alice", - "bob", - Account("bob")["USD"](25), - std::nullopt, - std::nullopt, - domainID); + auto const result = + find_paths(env, "alice", "bob", Account("bob")["USD"](25), std::nullopt, std::nullopt, domainID); BEAST_EXPECT(std::get<0>(result).empty()); } @@ -888,8 +783,7 @@ public: STPathSet st; STAmount sa; - std::tie(st, sa, std::ignore) = - find_paths(env, "alice", "carol", Account("carol")["USD"](5)); + std::tie(st, sa, std::ignore) = find_paths(env, "alice", "carol", Account("carol")["USD"](5)); BEAST_EXPECT(same(st, stpath("bob"))); BEAST_EXPECT(equal(sa, Account("alice")["USD"](5))); } @@ -934,9 +828,7 @@ public: jv); auto const jv_l = - env.le(keylet::line( - Account("bob").id(), Account("alice")["USD"].issue())) - ->getJson(JsonOptions::none); + env.le(keylet::line(Account("bob").id(), Account("alice")["USD"].issue()))->getJson(JsonOptions::none); for (auto it = jv.begin(); it != jv.end(); ++it) BEAST_EXPECT(*it == jv_l[it.memberName()]); } @@ -978,18 +870,13 @@ public: jv); auto const jv_l = - env.le(keylet::line( - Account("bob").id(), Account("alice")["USD"].issue())) - ->getJson(JsonOptions::none); + env.le(keylet::line(Account("bob").id(), Account("alice")["USD"].issue()))->getJson(JsonOptions::none); for (auto it = jv.begin(); it != jv.end(); ++it) BEAST_EXPECT(*it == jv_l[it.memberName()]); env.trust(Account("bob")["USD"](0), "alice"); env.trust(Account("alice")["USD"](0), "bob"); - BEAST_EXPECT( - env.le(keylet::line( - Account("bob").id(), Account("alice")["USD"].issue())) == - nullptr); + BEAST_EXPECT(env.le(keylet::line(Account("bob").id(), Account("alice")["USD"].issue())) == nullptr); } void @@ -1033,25 +920,18 @@ public: jv); auto const jv_l = - env.le(keylet::line( - Account("alice").id(), Account("bob")["USD"].issue())) - ->getJson(JsonOptions::none); + env.le(keylet::line(Account("alice").id(), Account("bob")["USD"].issue()))->getJson(JsonOptions::none); for (auto it = jv.begin(); it != jv.end(); ++it) BEAST_EXPECT(*it == jv_l[it.memberName()]); env(pay("alice", "bob", Account("alice")["USD"](50))); - BEAST_EXPECT( - env.le(keylet::line( - Account("alice").id(), Account("bob")["USD"].issue())) == - nullptr); + BEAST_EXPECT(env.le(keylet::line(Account("alice").id(), Account("bob")["USD"].issue())) == nullptr); } void path_find_01(bool const domainEnabled) { - testcase( - std::string("Path Find: XRP -> XRP and XRP -> IOU") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + testcase(std::string("Path Find: XRP -> XRP and XRP -> IOU") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); Account A1{"A1"}; @@ -1103,8 +983,7 @@ public: { auto const& send_amt = XRP(10); - std::tie(st, sa, da) = find_paths( - env, A1, A2, send_amt, std::nullopt, xrpCurrency(), domainID); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency(), domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(st.empty()); } @@ -1113,22 +992,14 @@ public: // no path should exist for this since dest account // does not exist. auto const& send_amt = XRP(200); - std::tie(st, sa, da) = find_paths( - env, - A1, - Account{"A0"}, - send_amt, - std::nullopt, - xrpCurrency(), - domainID); + std::tie(st, sa, da) = find_paths(env, A1, Account{"A0"}, send_amt, std::nullopt, xrpCurrency(), domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(st.empty()); } { auto const& send_amt = G3["ABC"](10); - std::tie(st, sa, da) = find_paths( - env, A2, G3, send_amt, std::nullopt, xrpCurrency(), domainID); + std::tie(st, sa, da) = find_paths(env, A2, G3, send_amt, std::nullopt, xrpCurrency(), domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRP(100))); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"])))); @@ -1136,8 +1007,7 @@ public: { auto const& send_amt = A2["ABC"](1); - std::tie(st, sa, da) = find_paths( - env, A1, A2, send_amt, std::nullopt, xrpCurrency(), domainID); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency(), domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRP(10))); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3))); @@ -1145,8 +1015,7 @@ public: { auto const& send_amt = A3["ABC"](1); - std::tie(st, sa, da) = find_paths( - env, A1, A3, send_amt, std::nullopt, xrpCurrency(), domainID); + std::tie(st, sa, da) = find_paths(env, A1, A3, send_amt, std::nullopt, xrpCurrency(), domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, XRP(10))); BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2))); @@ -1156,9 +1025,7 @@ public: void path_find_02(bool const domainEnabled) { - testcase( - std::string("Path Find: non-XRP -> XRP") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + testcase(std::string("Path Find: non-XRP -> XRP") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); Account A1{"A1"}; @@ -1195,14 +1062,7 @@ public: auto const& send_amt = XRP(10); { - std::tie(st, sa, da) = find_paths( - env, - A1, - A2, - send_amt, - std::nullopt, - A2["ABC"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["ABC"](1))); BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue())))); @@ -1212,8 +1072,7 @@ public: // paths if (domainEnabled) { - std::tie(st, sa, da) = find_paths( - env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(st.empty()); } @@ -1223,8 +1082,7 @@ public: path_find_04(bool const domainEnabled) { testcase( - std::string( - "Path Find: Bitstamp and SnapSwap, liquidity with no offers") + + std::string("Path Find: Bitstamp and SnapSwap, liquidity with no offers") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; Env env = pathTestEnv(); @@ -1262,14 +1120,7 @@ public: { auto const& send_amt = A2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - A2, - send_amt, - std::nullopt, - A2["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, A2["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same(st, stpath(G1BS, M1, G2SW))); @@ -1277,14 +1128,7 @@ public: { auto const& send_amt = A1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A2, - A1, - send_amt, - std::nullopt, - A1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A2, A1, send_amt, std::nullopt, A1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A2["HKD"](10))); BEAST_EXPECT(same(st, stpath(G2SW, M1, G1BS))); @@ -1292,14 +1136,7 @@ public: { auto const& send_amt = A2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - G1BS, - A2, - send_amt, - std::nullopt, - A1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, G1BS, A2, send_amt, std::nullopt, A1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1BS["HKD"](10))); BEAST_EXPECT(same(st, stpath(M1, G2SW))); @@ -1307,14 +1144,7 @@ public: { auto const& send_amt = M1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - M1, - G1BS, - send_amt, - std::nullopt, - A1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, M1, G1BS, send_amt, std::nullopt, A1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, M1["HKD"](10))); BEAST_EXPECT(st.empty()); @@ -1322,14 +1152,7 @@ public: { auto const& send_amt = A1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - G2SW, - A1, - send_amt, - std::nullopt, - A1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, G2SW, A1, send_amt, std::nullopt, A1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G2SW["HKD"](10))); BEAST_EXPECT(same(st, stpath(M1, G1BS))); @@ -1340,8 +1163,8 @@ public: path_find_05(bool const domainEnabled) { testcase( - std::string("Path Find: non-XRP -> non-XRP, same currency") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + std::string("Path Find: non-XRP -> non-XRP, same currency") + (domainEnabled ? " w/ " : " w/o ") + + "domain"); using namespace jtx; Env env = pathTestEnv(); Account A1{"A1"}; @@ -1381,8 +1204,7 @@ public: std::optional domainID; if (domainEnabled) { - domainID = - setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2}); + domainID = setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2}); env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(*domainID)); env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(*domainID)); env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(*domainID)); @@ -1401,14 +1223,7 @@ public: // A) Borrow or repay -- // Source -> Destination (repay source issuer) auto const& send_amt = G1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - G1, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1418,14 +1233,7 @@ public: // A2) Borrow or repay -- // Source -> Destination (repay destination issuer) auto const& send_amt = A1["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - G1, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1435,14 +1243,7 @@ public: // B) Common gateway -- // Source -> AC -> Destination auto const& send_amt = A3["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - A3, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same(st, stpath(G1))); @@ -1452,36 +1253,18 @@ public: // C) Gateway to gateway -- // Source -> OB -> Destination auto const& send_amt = G2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - G1, - G2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1["HKD"](10))); - BEAST_EXPECT(same( - st, - stpath(IPE(G2["HKD"])), - stpath(M1), - stpath(M2), - stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); + BEAST_EXPECT( + same(st, stpath(IPE(G2["HKD"])), stpath(M1), stpath(M2), stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); } { // D) User to unlinked gateway via order book -- // Source -> AC -> OB -> Destination auto const& send_amt = G2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - G2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1497,14 +1280,7 @@ public: // Source -> AC -> OB to XRP -> OB from XRP -> AC -> // Destination auto const& send_amt = A2["HKD"](10); - std::tie(st, sa, da) = find_paths( - env, - A1, - A2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainID); + std::tie(st, sa, da) = find_paths(env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1520,8 +1296,8 @@ public: path_find_06(bool const domainEnabled) { testcase( - std::string("Path Find: non-XRP -> non-XRP, same currency)") + - (domainEnabled ? " w/ " : " w/o ") + "domain"); + std::string("Path Find: non-XRP -> non-XRP, same currency)") + (domainEnabled ? " w/ " : " w/o ") + + "domain"); using namespace jtx; Env env = pathTestEnv(); Account A1{"A1"}; @@ -1564,8 +1340,7 @@ public: auto const& send_amt = A2["HKD"](10); STPathSet st; STAmount sa, da; - std::tie(st, sa, da) = find_paths( - env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency, domainID); + std::tie(st, sa, da) = find_paths(env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency, domainID); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1["HKD"](10))); BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2))); @@ -1574,9 +1349,7 @@ public: void receive_max(bool const domainEnabled) { - testcase( - std::string("Receive max") + (domainEnabled ? " w/ " : " w/o ") + - "domain"); + testcase(std::string("Receive max") + (domainEnabled ? " w/ " : " w/o ") + "domain"); using namespace jtx; auto const alice = Account("alice"); @@ -1607,22 +1380,14 @@ public: env.close(); } - auto [st, sa, da] = find_paths( - env, - alice, - bob, - USD(-1), - XRP(100).value(), - std::nullopt, - domainID); + auto [st, sa, da] = find_paths(env, alice, bob, USD(-1), XRP(100).value(), std::nullopt, domainID); BEAST_EXPECT(sa == XRP(10)); BEAST_EXPECT(equal(da, USD(10))); if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1)) { auto const& pathElem = st[0][0]; BEAST_EXPECT( - pathElem.isOffer() && pathElem.getIssuerID() == gw.id() && - pathElem.getCurrency() == USD.currency); + pathElem.isOffer() && pathElem.getIssuerID() == gw.id() && pathElem.getCurrency() == USD.currency); } } { @@ -1648,22 +1413,14 @@ public: env.close(); } - auto [st, sa, da] = find_paths( - env, - alice, - bob, - drops(-1), - USD(100).value(), - std::nullopt, - domainID); + auto [st, sa, da] = find_paths(env, alice, bob, drops(-1), USD(100).value(), std::nullopt, domainID); BEAST_EXPECT(sa == USD(10)); BEAST_EXPECT(equal(da, XRP(10))); if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1)) { auto const& pathElem = st[0][0]; BEAST_EXPECT( - pathElem.isOffer() && - pathElem.getIssuerID() == xrpAccount() && + pathElem.isOffer() && pathElem.getIssuerID() == xrpAccount() && pathElem.getCurrency() == xrpCurrency()); } } @@ -1681,10 +1438,7 @@ public: auto const bob = Account("bob"); auto const george = Account("george"); auto const USD = george["USD"]; - auto test = [&](std::string casename, - bool aliceRipple, - bool bobRipple, - bool expectPath) { + auto test = [&](std::string casename, bool aliceRipple, bool bobRipple, bool expectPath) { testcase(casename); Env env = pathTestEnv(); @@ -1692,26 +1446,15 @@ public: env.close(); // Set the same flags at both ends of the trustline, even though // only george's matter. - env(trust( - alice, - USD(100), - aliceRipple ? tfClearNoRipple : tfSetNoRipple)); - env(trust( - george, - alice["USD"](100), - aliceRipple ? tfClearNoRipple : tfSetNoRipple)); - env(trust( - bob, USD(100), bobRipple ? tfClearNoRipple : tfSetNoRipple)); - env(trust( - george, - bob["USD"](100), - bobRipple ? tfClearNoRipple : tfSetNoRipple)); + env(trust(alice, USD(100), aliceRipple ? tfClearNoRipple : tfSetNoRipple)); + env(trust(george, alice["USD"](100), aliceRipple ? tfClearNoRipple : tfSetNoRipple)); + env(trust(bob, USD(100), bobRipple ? tfClearNoRipple : tfSetNoRipple)); + env(trust(george, bob["USD"](100), bobRipple ? tfClearNoRipple : tfSetNoRipple)); env.close(); env(pay(george, alice, USD(70))); env.close(); - auto [st, sa, da] = - find_paths(env, "alice", "bob", Account("bob")["USD"](5)); + auto [st, sa, da] = find_paths(env, "alice", "bob", Account("bob")["USD"](5)); BEAST_EXPECT(equal(da, bob["USD"](5))); if (expectPath) @@ -1777,8 +1520,7 @@ public: env(pay(G2, M2, G2["HKD"](5000))); env.close(); - std::optional domainID = - setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2}); + std::optional domainID = setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2}); BEAST_EXPECT(domainID); func(env, M1, M2, G1, G2, *domainID); @@ -1791,13 +1533,7 @@ public: // Source -> Destination (repay source issuer) auto const& send_amt = G1["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - A1, - G1, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1808,13 +1544,7 @@ public: // Source -> Destination (repay destination issuer) auto const& send_amt = A1["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - A1, - G1, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); @@ -1825,13 +1555,7 @@ public: // Source -> AC -> Destination auto const& send_amt = A3["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - A1, - A3, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same(st, stpath(G1))); @@ -1842,21 +1566,11 @@ public: // Source -> OB -> Destination auto const& send_amt = G2["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - G1, - G2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, G1["HKD"](10))); - BEAST_EXPECT(same( - st, - stpath(IPE(G2["HKD"])), - stpath(M1), - stpath(M2), - stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); + BEAST_EXPECT( + same(st, stpath(IPE(G2["HKD"])), stpath(M1), stpath(M2), stpath(IPE(xrpIssue()), IPE(G2["HKD"])))); } { @@ -1864,13 +1578,7 @@ public: // Source -> AC -> OB -> Destination auto const& send_amt = G2["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - A1, - G2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1887,13 +1595,7 @@ public: // Destination auto const& send_amt = A2["HKD"](10); std::tie(st, sa, da) = find_paths( - env, - A1, - A2, - send_amt, - std::nullopt, - G1["HKD"].currency, - domainEnabled ? domainID : std::nullopt); + env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency, domainEnabled ? domainID : std::nullopt); BEAST_EXPECT(equal(da, send_amt)); BEAST_EXPECT(equal(sa, A1["HKD"](10))); BEAST_EXPECT(same( @@ -1909,77 +1611,34 @@ public: // offers to make sure that hybrid offers work in pathfinding for open // order book { - testPathfind([](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); + testPathfind([](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); env(offer(M2, XRP(10000), G2["HKD"](1000))); env(offer(M2, G1["HKD"](1000), XRP(10000))); }); - testPathfind([](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); + testPathfind([](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); env(offer(M2, G1["HKD"](1000), XRP(10000))); }); - testPathfind([](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID), - txflags(tfHybrid)); + testPathfind([](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID), txflags(tfHybrid)); }); - testPathfind([](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { + testPathfind([](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { env(offer(M1, G1["HKD"](1000), G2["HKD"](1000))); env(offer(M2, XRP(10000), G2["HKD"](1000))); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID), - txflags(tfHybrid)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID), txflags(tfHybrid)); }); - testPathfind([](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { + testPathfind([](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { env(offer(M1, G1["HKD"](1000), G2["HKD"](1000))); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID), - txflags(tfHybrid)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID), txflags(tfHybrid)); }); } @@ -1988,72 +1647,34 @@ public: // order book { testPathfind( - [](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID)); + [](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID)); }, true); testPathfind( - [](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID)); + [](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID)); }, true); testPathfind( - [](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID), - txflags(tfHybrid)); + [](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID), txflags(tfHybrid)); }, true); testPathfind( - [](Env& env, - Account M1, - Account M2, - Account G1, - Account G2, - uint256 domainID) { - env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), - domain(domainID)); - env(offer(M2, XRP(10000), G2["HKD"](1000)), - domain(domainID), - txflags(tfHybrid)); - env(offer(M2, G1["HKD"](1000), XRP(10000)), - domain(domainID), - txflags(tfHybrid)); + [](Env& env, Account M1, Account M2, Account G1, Account G2, uint256 domainID) { + env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)), domain(domainID)); + env(offer(M2, XRP(10000), G2["HKD"](1000)), domain(domainID), txflags(tfHybrid)); + env(offer(M2, G1["HKD"](1000), XRP(10000)), domain(domainID), txflags(tfHybrid)); }, true); } @@ -2066,8 +1687,7 @@ public: using namespace jtx; Env env = pathTestEnv(); PermissionedDEX permDex(env); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - permDex; + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = permDex; AMM amm(env, alice, XRP(10), USD(50)); STPathSet st; @@ -2076,13 +1696,11 @@ public: auto const& send_amt = XRP(1); // doing pathfind with domain won't include amm - std::tie(st, sa, da) = find_paths( - env, bob, carol, send_amt, std::nullopt, USD.currency, domainID); + std::tie(st, sa, da) = find_paths(env, bob, carol, send_amt, std::nullopt, USD.currency, domainID); BEAST_EXPECT(st.empty()); // a non-domain pathfind returns amm in the path - std::tie(st, sa, da) = - find_paths(env, bob, carol, send_amt, std::nullopt, USD.currency); + std::tie(st, sa, da) = find_paths(env, bob, carol, send_amt, std::nullopt, USD.currency); BEAST_EXPECT(same(st, stpath(gw, IPE(xrpIssue())))); } @@ -2108,8 +1726,7 @@ public: path_find_consume_all(domainEnabled); alternative_path_consume_both(domainEnabled); alternative_paths_consume_best_transfer(domainEnabled); - alternative_paths_limit_returned_paths_to_best_quality( - domainEnabled); + alternative_paths_limit_returned_paths_to_best_quality(domainEnabled); issues_path_negative_issue(domainEnabled); via_offers_via_gateway(domainEnabled); xrp_to_xrp(domainEnabled); @@ -2133,7 +1750,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Path, app, ripple); +BEAST_DEFINE_TESTSUITE(Path, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index 9cbe4817b0..019dd42ca1 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,19 +8,14 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { using namespace jtx::paychan; struct PayChan_test : public beast::unit_test::suite { - FeatureBitset const disallowIncoming{featureDisallowIncoming}; - static std::pair> - channelKeyAndSle( - ReadView const& view, - jtx::Account const& account, - jtx::Account const& dst) + channelKeyAndSle(ReadView const& view, jtx::Account const& account, jtx::Account const& dst) { auto const sle = view.read(keylet::account(account)); if (!sle) @@ -49,11 +25,7 @@ struct PayChan_test : public beast::unit_test::suite } static Buffer - signClaimAuth( - PublicKey const& pk, - SecretKey const& sk, - uint256 const& channel, - STAmount const& authAmt) + signClaimAuth(PublicKey const& pk, SecretKey const& sk, uint256 const& channel, STAmount const& authAmt) { Serializer msg; serializePayChanAuthorization(msg, channel, authAmt.xrp()); @@ -112,27 +84,19 @@ struct PayChan_test : public beast::unit_test::suite { // bad amounts (non-xrp, negative amounts) - env(create(alice, bob, USDA(1000), settleDelay, pk), - ter(temBAD_AMOUNT)); + env(create(alice, bob, USDA(1000), settleDelay, pk), ter(temBAD_AMOUNT)); env(fund(alice, chan, USDA(1000)), ter(temBAD_AMOUNT)); - env(create(alice, bob, XRP(-1000), settleDelay, pk), - ter(temBAD_AMOUNT)); + env(create(alice, bob, XRP(-1000), settleDelay, pk), ter(temBAD_AMOUNT)); env(fund(alice, chan, XRP(-1000)), ter(temBAD_AMOUNT)); } // invalid account - env(create(alice, "noAccount", XRP(1000), settleDelay, pk), - ter(tecNO_DST)); + env(create(alice, "noAccount", XRP(1000), settleDelay, pk), ter(tecNO_DST)); // can't create channel to the same account - env(create(alice, alice, XRP(1000), settleDelay, pk), - ter(temDST_IS_SRC)); + env(create(alice, alice, XRP(1000), settleDelay, pk), ter(temDST_IS_SRC)); // invalid channel - env(fund( - alice, - channel(alice, "noAccount", env.seq(alice) - 1), - XRP(1000)), - ter(tecNO_ENTRY)); + env(fund(alice, channel(alice, "noAccount", env.seq(alice) - 1), XRP(1000)), ter(tecNO_ENTRY)); // not enough funds env(create(alice, bob, XRP(10000), settleDelay, pk), ter(tecUNFUNDED)); @@ -176,8 +140,7 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk())); BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); @@ -187,8 +150,7 @@ struct PayChan_test : public beast::unit_test::suite // claim again preBob = env.balance(bob); - env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()), - ter(tecUNFUNDED_PAYMENT)); + env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()), ter(tecUNFUNDED_PAYMENT)); BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); BEAST_EXPECT(env.balance(bob) == preBob - feeDrops); @@ -199,10 +161,8 @@ struct PayChan_test : public beast::unit_test::suite STAmount const authAmt = chanBal + XRP(500); STAmount const reqAmt = authAmt + STAmount{1}; assert(reqAmt <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); - env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()), - ter(temBAD_AMOUNT)); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()), ter(temBAD_AMOUNT)); BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); BEAST_EXPECT(env.balance(bob) == preBob); @@ -216,28 +176,14 @@ struct PayChan_test : public beast::unit_test::suite { // Wrong signing key auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500)); - env(claim( - bob, - chan, - XRP(1500).value(), - XRP(1500).value(), - Slice(sig), - bob.pk()), - ter(temBAD_SIGNER)); + env(claim(bob, chan, XRP(1500).value(), XRP(1500).value(), Slice(sig), bob.pk()), ter(temBAD_SIGNER)); BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); } { // Bad signature auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500)); - env(claim( - bob, - chan, - XRP(1500).value(), - XRP(1500).value(), - Slice(sig), - alice.pk()), - ter(temBAD_SIGNATURE)); + env(claim(bob, chan, XRP(1500).value(), XRP(1500).value(), Slice(sig), alice.pk()), ter(temBAD_SIGNATURE)); BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); } @@ -261,20 +207,8 @@ struct PayChan_test : public beast::unit_test::suite testcase("Disallow Incoming Flag"); using namespace jtx; - // test flag doesn't set unless amendment enabled - { - Env env{*this, features - disallowIncoming}; - Account const alice{"alice"}; - env.fund(XRP(10000), alice); - env(fset(alice, asfDisallowIncomingPayChan)); - env.close(); - auto const sle = env.le(alice); - uint32_t flags = sle->getFlags(); - BEAST_EXPECT(!(flags & lsfDisallowIncomingPayChan)); - } - using namespace std::literals::chrono_literals; - Env env{*this, features | disallowIncoming}; + Env env{*this, features}; auto const alice = Account("alice"); auto const bob = Account("bob"); auto const cho = Account("cho"); @@ -289,8 +223,7 @@ struct PayChan_test : public beast::unit_test::suite // channel creation from alice to bob is disallowed { auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, XRP(1000), settleDelay, pk), - ter(tecNO_PERMISSION)); + env(create(alice, bob, XRP(1000), settleDelay, pk), ter(tecNO_PERMISSION)); BEAST_EXPECT(!channelExists(*env.current(), chan)); } @@ -301,8 +234,7 @@ struct PayChan_test : public beast::unit_test::suite // channel creation from bob to alice is now disallowed { auto const chan = channel(bob, alice, env.seq(bob)); - env(create(bob, alice, XRP(1000), settleDelay, pk), - ter(tecNO_PERMISSION)); + env(create(bob, alice, XRP(1000), settleDelay, pk), ter(tecNO_PERMISSION)); BEAST_EXPECT(!channelExists(*env.current(), chan)); } @@ -313,16 +245,14 @@ struct PayChan_test : public beast::unit_test::suite // now the channel between alice and bob can exist { auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, XRP(1000), settleDelay, pk), - ter(tesSUCCESS)); + env(create(alice, bob, XRP(1000), settleDelay, pk), ter(tesSUCCESS)); BEAST_EXPECT(channelExists(*env.current(), chan)); } // a channel from cho to alice isn't allowed { auto const chan = channel(cho, alice, env.seq(cho)); - env(create(cho, alice, XRP(1000), settleDelay, pk), - ter(tecNO_PERMISSION)); + env(create(cho, alice, XRP(1000), settleDelay, pk), ter(tecNO_PERMISSION)); BEAST_EXPECT(!channelExists(*env.current(), chan)); } @@ -333,8 +263,7 @@ struct PayChan_test : public beast::unit_test::suite // now a channel from cho to alice is allowed { auto const chan = channel(cho, alice, env.seq(cho)); - env(create(cho, alice, XRP(1000), settleDelay, pk), - ter(tesSUCCESS)); + env(create(cho, alice, XRP(1000), settleDelay, pk), ter(tesSUCCESS)); BEAST_EXPECT(channelExists(*env.current(), chan)); } } @@ -354,8 +283,7 @@ struct PayChan_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob); auto const pk = alice.pk(); auto const settleDelay = 100s; - NetClock::time_point const cancelAfter = - env.current()->info().parentCloseTime + 3600s; + NetClock::time_point const cancelAfter = env.current()->header().parentCloseTime + 3600s; auto const channelFunds = XRP(1000); auto const chan = channel(alice, bob, env.seq(alice)); env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter)); @@ -371,8 +299,7 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk())); auto const feeDrops = env.current()->fees().base; BEAST_EXPECT(!channelExists(*env.current(), chan)); @@ -386,8 +313,7 @@ struct PayChan_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob, carol); auto const pk = alice.pk(); auto const settleDelay = 100s; - NetClock::time_point const cancelAfter = - env.current()->info().parentCloseTime + 3600s; + NetClock::time_point const cancelAfter = env.current()->header().parentCloseTime + 3600s; auto const channelFunds = XRP(1000); auto const chan = channel(alice, bob, env.seq(alice)); env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter)); @@ -407,9 +333,7 @@ struct PayChan_test : public beast::unit_test::suite { for (bool const withFixPayChan : {true, false}) { - auto const amend = withFixPayChan - ? features - : features - fixPayChanCancelAfter; + auto const amend = withFixPayChan ? features : features - fixPayChanCancelAfter; Env env{*this, amend}; env.fund(XRP(10000), alice, bob); env.close(); @@ -417,13 +341,9 @@ struct PayChan_test : public beast::unit_test::suite auto const pk = alice.pk(); auto const settleDelay = 100s; auto const channelFunds = XRP(1000); - NetClock::time_point const cancelAfter = - env.current()->info().parentCloseTime - 1s; - auto const txResult = - withFixPayChan ? ter(tecEXPIRED) : ter(tesSUCCESS); - env(create( - alice, bob, channelFunds, settleDelay, pk, cancelAfter), - txResult); + NetClock::time_point const cancelAfter = env.current()->header().parentCloseTime - 1s; + auto const txResult = withFixPayChan ? ter(tecEXPIRED) : ter(tesSUCCESS); + env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter), txResult); } } // fixPayChanCancelAfter @@ -431,9 +351,7 @@ struct PayChan_test : public beast::unit_test::suite { for (bool const withFixPayChan : {true, false}) { - auto const amend = withFixPayChan - ? features - : features - fixPayChanCancelAfter; + auto const amend = withFixPayChan ? features : features - fixPayChanCancelAfter; Env env{*this, amend}; env.fund(XRP(10000), alice, bob); env.close(); @@ -441,11 +359,8 @@ struct PayChan_test : public beast::unit_test::suite auto const pk = alice.pk(); auto const settleDelay = 100s; auto const channelFunds = XRP(1000); - NetClock::time_point const cancelAfter = - env.current()->info().parentCloseTime; - env(create( - alice, bob, channelFunds, settleDelay, pk, cancelAfter), - ter(tesSUCCESS)); + NetClock::time_point const cancelAfter = env.current()->header().parentCloseTime; + env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter), ter(tesSUCCESS)); } } } @@ -463,7 +378,7 @@ struct PayChan_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob, carol); auto const pk = alice.pk(); auto const settleDelay = 3600s; - auto const closeTime = env.current()->info().parentCloseTime; + auto const closeTime = env.current()->header().parentCloseTime; auto const minExpiration = closeTime + settleDelay; NetClock::time_point const cancelAfter = closeTime + 7200s; auto const channelFunds = XRP(1000); @@ -473,46 +388,28 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(!channelExpiration(*env.current(), chan)); // Owner closes, will close after settleDelay env(claim(alice, chan), txflags(tfClose)); - auto counts = [](auto const& t) { - return t.time_since_epoch().count(); - }; - BEAST_EXPECT( - *channelExpiration(*env.current(), chan) == counts(minExpiration)); + auto counts = [](auto const& t) { return t.time_since_epoch().count(); }; + BEAST_EXPECT(*channelExpiration(*env.current(), chan) == counts(minExpiration)); // increase the expiration time - env(fund( - alice, chan, XRP(1), NetClock::time_point{minExpiration + 100s})); - BEAST_EXPECT( - *channelExpiration(*env.current(), chan) == - counts(minExpiration) + 100); + env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration + 100s})); + BEAST_EXPECT(*channelExpiration(*env.current(), chan) == counts(minExpiration) + 100); // decrease the expiration, but still above minExpiration - env(fund( - alice, chan, XRP(1), NetClock::time_point{minExpiration + 50s})); - BEAST_EXPECT( - *channelExpiration(*env.current(), chan) == - counts(minExpiration) + 50); + env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration + 50s})); + BEAST_EXPECT(*channelExpiration(*env.current(), chan) == counts(minExpiration) + 50); // decrease the expiration below minExpiration - env(fund( - alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}), - ter(temBAD_EXPIRATION)); - BEAST_EXPECT( - *channelExpiration(*env.current(), chan) == - counts(minExpiration) + 50); + env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}), ter(temBAD_EXPIRATION)); + BEAST_EXPECT(*channelExpiration(*env.current(), chan) == counts(minExpiration) + 50); env(claim(bob, chan), txflags(tfRenew), ter(tecNO_PERMISSION)); - BEAST_EXPECT( - *channelExpiration(*env.current(), chan) == - counts(minExpiration) + 50); + BEAST_EXPECT(*channelExpiration(*env.current(), chan) == counts(minExpiration) + 50); env(claim(alice, chan), txflags(tfRenew)); BEAST_EXPECT(!channelExpiration(*env.current(), chan)); // decrease the expiration below minExpiration - env(fund( - alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}), - ter(temBAD_EXPIRATION)); + env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}), ter(temBAD_EXPIRATION)); BEAST_EXPECT(!channelExpiration(*env.current(), chan)); env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration})); env.close(minExpiration); // Try to extend the expiration after the expiration has already passed - env(fund( - alice, chan, XRP(1), NetClock::time_point{minExpiration + 1000s})); + env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration + 1000s})); BEAST_EXPECT(!channelExists(*env.current(), chan)); } @@ -528,8 +425,7 @@ struct PayChan_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob); auto const pk = alice.pk(); auto const settleDelay = 3600s; - NetClock::time_point const settleTimepoint = - env.current()->info().parentCloseTime + settleDelay; + NetClock::time_point const settleTimepoint = env.current()->header().parentCloseTime + settleDelay; auto const channelFunds = XRP(1000); auto const chan = channel(alice, bob, env.seq(alice)); env(create(alice, bob, channelFunds, settleDelay, pk)); @@ -547,8 +443,7 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk())); BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); @@ -566,8 +461,7 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk())); BEAST_EXPECT(!channelExists(*env.current(), chan)); auto const feeDrops = env.current()->fees().base; @@ -638,8 +532,7 @@ struct PayChan_test : public beast::unit_test::suite auto const delta = XRP(500); auto const reqBal = chanBal + delta; assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, reqBal); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, reqBal); env(claim(bob, chan, reqBal, std::nullopt, Slice(sig), alice.pk())); BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); auto const feeDrops = env.current()->fees().base; @@ -655,8 +548,7 @@ struct PayChan_test : public beast::unit_test::suite auto const delta = XRP(500); auto const reqBal = chanBal + delta; assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, reqBal); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, reqBal); env(claim(bob, chan, reqBal, std::nullopt, Slice(sig), alice.pk())); BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); auto const feeDrops = env.current()->fees().base; @@ -675,16 +567,6 @@ struct PayChan_test : public beast::unit_test::suite auto const alice = Account("alice"); auto const bob = Account("bob"); - { - // Create a channel where dst disallows XRP - Env env(*this, features - featureDepositAuth); - env.fund(XRP(10000), alice, bob); - env(fset(bob, asfDisallowXRP)); - auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, XRP(1000), 3600s, alice.pk()), - ter(tecNO_TARGET)); - BEAST_EXPECT(!channelExists(*env.current(), chan)); - } { // Create a channel where dst disallows XRP. Ignore that flag, // since it's just advisory. @@ -696,19 +578,6 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(channelExists(*env.current(), chan)); } - { - // Claim to a channel where dst disallows XRP - // (channel is created before disallow xrp is set) - Env env(*this, features - featureDepositAuth); - env.fund(XRP(10000), alice, bob); - auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, XRP(1000), 3600s, alice.pk())); - BEAST_EXPECT(channelExists(*env.current(), chan)); - - env(fset(bob, asfDisallowXRP)); - auto const reqBal = XRP(500).value(); - env(claim(alice, chan, reqBal, reqBal), ter(tecNO_TARGET)); - } { // Claim to a channel where dst disallows XRP (channel is // created before disallow xrp is set). Ignore that flag @@ -743,14 +612,12 @@ struct PayChan_test : public beast::unit_test::suite auto const channelFunds = XRP(1000); { auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, channelFunds, settleDelay, pk), - ter(tecDST_TAG_NEEDED)); + env(create(alice, bob, channelFunds, settleDelay, pk), ter(tecDST_TAG_NEEDED)); BEAST_EXPECT(!channelExists(*env.current(), chan)); } { auto const chan = channel(alice, bob, env.seq(alice)); - env(create( - alice, bob, channelFunds, settleDelay, pk, std::nullopt, 1)); + env(create(alice, bob, channelFunds, settleDelay, pk, std::nullopt, 1)); BEAST_EXPECT(channelExists(*env.current(), chan)); } } @@ -788,8 +655,7 @@ struct PayChan_test : public beast::unit_test::suite env.close(); // alice claims. Fails because bob's lsfDepositAuth flag is set. - env(claim(alice, chan, XRP(500).value(), XRP(500).value()), - ter(tecNO_PERMISSION)); + env(claim(alice, chan, XRP(500).value(), XRP(500).value()), ter(tecNO_PERMISSION)); env.close(); // Claim with signature @@ -801,8 +667,7 @@ struct PayChan_test : public beast::unit_test::suite // alice claims with signature. Fails since bob has // lsfDepositAuth flag set. - env(claim(alice, chan, delta, delta, Slice(sig), pk), - ter(tecNO_PERMISSION)); + env(claim(alice, chan, delta, delta, Slice(sig), pk), ter(tecNO_PERMISSION)); env.close(); BEAST_EXPECT(env.balance(bob) == preBob); @@ -819,14 +684,13 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob) == preBob + delta - baseFee); } { - // Explore the limits of deposit preauthorization. + // Explore the limits of deposit pre-authorization. auto const delta = XRP(600).value(); auto const sig = signClaimAuth(pk, alice.sk(), chan, delta); // carol claims and fails. Only channel participants (bob or // alice) may claim. - env(claim(carol, chan, delta, delta, Slice(sig), pk), - ter(tecNO_PERMISSION)); + env(claim(carol, chan, delta, delta, Slice(sig), pk), ter(tecNO_PERMISSION)); env.close(); // bob preauthorizes carol for deposit. But after that carol @@ -834,13 +698,11 @@ struct PayChan_test : public beast::unit_test::suite env(deposit::auth(bob, carol)); env.close(); - env(claim(carol, chan, delta, delta, Slice(sig), pk), - ter(tecNO_PERMISSION)); + env(claim(carol, chan, delta, delta, Slice(sig), pk), ter(tecNO_PERMISSION)); // Since alice is not preauthorized she also may not claim // for bob. - env(claim(alice, chan, delta, delta, Slice(sig), pk), - ter(tecNO_PERMISSION)); + env(claim(alice, chan, delta, delta, Slice(sig), pk), ter(tecNO_PERMISSION)); env.close(); // However if bob preauthorizes alice for deposit then she can @@ -851,11 +713,10 @@ struct PayChan_test : public beast::unit_test::suite env(claim(alice, chan, delta, delta, Slice(sig), pk)); env.close(); - BEAST_EXPECT( - env.balance(bob) == preBob + delta - (3 * baseFee)); + BEAST_EXPECT(env.balance(bob) == preBob + delta - (3 * baseFee)); } { - // bob removes preauthorization of alice. Once again she + // bob removes pre-authorization of alice. Once again she // cannot submit a claim. auto const delta = XRP(800).value(); @@ -873,8 +734,7 @@ struct PayChan_test : public beast::unit_test::suite // alice claims successfully. env(claim(alice, chan, delta, delta)); env.close(); - BEAST_EXPECT( - env.balance(bob) == preBob + XRP(800) - (5 * baseFee)); + BEAST_EXPECT(env.balance(bob) == preBob + XRP(800) - (5 * baseFee)); } } } @@ -916,37 +776,28 @@ struct PayChan_test : public beast::unit_test::suite { // create credentials auto jv = credentials::create(alice, carol, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 100; + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count() + 100; jv[sfExpiration.jsonName] = t; env(jv); env.close(); } - auto const jv = - credentials::ledgerEntry(env, alice, carol, credType); + auto const jv = credentials::ledgerEntry(env, alice, carol, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); - // Bob require preauthorization + // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); // Fail, credentials not accepted - env(claim(alice, chan, delta, delta), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(claim(alice, chan, delta, delta), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); env.close(); env(credentials::accept(alice, carol, credType)); env.close(); // Fail, no depositPreauth object - env(claim(alice, chan, delta, delta), - credentials::ids({credIdx}), - ter(tecNO_PERMISSION)); + env(claim(alice, chan, delta, delta), credentials::ids({credIdx}), ter(tecNO_PERMISSION)); env.close(); // Setup deposit authorization @@ -954,22 +805,16 @@ struct PayChan_test : public beast::unit_test::suite env.close(); // Fail, credentials doesn’t belong to root account - env(claim(dillon, chan, delta, delta), - credentials::ids({credIdx}), - ter(tecBAD_CREDENTIALS)); + env(claim(dillon, chan, delta, delta), credentials::ids({credIdx}), ter(tecBAD_CREDENTIALS)); // Fails because bob's lsfDepositAuth flag is set. env(claim(alice, chan, delta, delta), ter(tecNO_PERMISSION)); // Fail, bad credentials index. - env(claim(alice, chan, delta, delta), - credentials::ids({credBadIdx}), - ter(tecBAD_CREDENTIALS)); + env(claim(alice, chan, delta, delta), credentials::ids({credBadIdx}), ter(tecBAD_CREDENTIALS)); // Fail, empty credentials - env(claim(alice, chan, delta, delta), - credentials::ids({}), - ter(temMALFORMED)); + env(claim(alice, chan, delta, delta), credentials::ids({}), ter(temMALFORMED)); { // claim fails cause of expired credentials @@ -978,9 +823,7 @@ struct PayChan_test : public beast::unit_test::suite for (int i = 0; i < 10; ++i) env.close(); - env(claim(alice, chan, delta, delta), - credentials::ids({credIdx}), - ter(tecEXPIRED)); + env(claim(alice, chan, delta, delta), credentials::ids({credIdx}), ter(tecEXPIRED)); env.close(); } @@ -990,14 +833,11 @@ struct PayChan_test : public beast::unit_test::suite env(credentials::accept(alice, carol, credType)); env.close(); - auto const jv = - credentials::ledgerEntry(env, alice, carol, credType); - std::string const credIdx = - jv[jss::result][jss::index].asString(); + auto const jv = credentials::ledgerEntry(env, alice, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); // Success - env(claim(alice, chan, delta, delta), - credentials::ids({credIdx})); + env(claim(alice, chan, delta, delta), credentials::ids({credIdx})); } } @@ -1024,8 +864,7 @@ struct PayChan_test : public beast::unit_test::suite env.close(); } - auto const jv = - credentials::ledgerEntry(env, alice, carol, credType); + auto const jv = credentials::ledgerEntry(env, alice, carol, credType); std::string const credIdx = jv[jss::result][jss::index].asString(); // Succeed, lsfDepositAuth is not set @@ -1057,9 +896,7 @@ struct PayChan_test : public beast::unit_test::suite env(deposit::auth(bob, alice)); env.close(); - env(claim(alice, chan, XRP(500).value(), XRP(500).value()), - credentials::ids({credIdx}), - ter(temDISABLED)); + env(claim(alice, chan, XRP(500).value(), XRP(500).value()), credentials::ids({credIdx}), ter(temDISABLED)); } } @@ -1109,11 +946,9 @@ struct PayChan_test : public beast::unit_test::suite auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_channels", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_channels", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -1124,23 +959,19 @@ struct PayChan_test : public beast::unit_test::suite testInvalidAccountParam(Json::Value(Json::arrayValue)); } { - auto const r = - env.rpc("account_channels", alice.human(), bob.human()); + auto const r = env.rpc("account_channels", alice.human(), bob.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); BEAST_EXPECT(r[jss::result][jss::validated]); } { auto const r = env.rpc("account_channels", alice.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); BEAST_EXPECT(r[jss::result][jss::validated]); } { - auto const r = - env.rpc("account_channels", bob.human(), alice.human()); + auto const r = env.rpc("account_channels", bob.human(), alice.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 0); BEAST_EXPECT(r[jss::result][jss::validated]); } @@ -1148,8 +979,7 @@ struct PayChan_test : public beast::unit_test::suite env(create(alice, bob, channelFunds, settleDelay, pk)); env.close(); { - auto const r = - env.rpc("account_channels", alice.human(), bob.human()); + auto const r = env.rpc("account_channels", alice.human(), bob.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 2); BEAST_EXPECT(r[jss::result][jss::validated]); BEAST_EXPECT(chan1Str != chan2Str); @@ -1202,8 +1032,7 @@ struct PayChan_test : public beast::unit_test::suite test::jtx::Account const& src, std::optional limit = std::nullopt, Json::Value const& marker = Json::nullValue, - std::optional const& dst = - std::nullopt) { + std::optional const& dst = std::nullopt) { Json::Value jvc; jvc[jss::account] = src.human(); if (dst) @@ -1213,8 +1042,7 @@ struct PayChan_test : public beast::unit_test::suite if (marker) jvc[jss::marker] = marker; - return env.rpc( - "json", "account_channels", to_string(jvc))[jss::result]; + return env.rpc("json", "account_channels", to_string(jvc))[jss::result]; }; { @@ -1249,8 +1077,7 @@ struct PayChan_test : public beast::unit_test::suite auto const s = r[jss::channels].size(); for (int j = 0; j < s; ++j) { - auto const dstAcc = - c[j][jss::destination_account].asString(); + auto const dstAcc = c[j][jss::destination_account].asString(); BEAST_EXPECT(leftToFind.count(dstAcc)); leftToFind.erase(dstAcc); } @@ -1303,14 +1130,11 @@ struct PayChan_test : public beast::unit_test::suite Json::Value jvc; jvc[jss::account] = alice.human(); - return env.rpc( - "json", "account_channels", to_string(jvc))[jss::result]; + return env.rpc("json", "account_channels", to_string(jvc))[jss::result]; }(); BEAST_EXPECT(r.isMember(jss::channels)); BEAST_EXPECT(r[jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::channels][0u][jss::destination_account].asString() == - bob.human()); + BEAST_EXPECT(r[jss::channels][0u][jss::destination_account].asString() == bob.human()); } void @@ -1339,13 +1163,9 @@ struct PayChan_test : public beast::unit_test::suite // test for all api versions forAllApiVersions([&, this](unsigned apiVersion) { - testcase( - "PayChan Channel_Auth RPC Api " + std::to_string(apiVersion)); + testcase("PayChan Channel_Auth RPC Api " + std::to_string(apiVersion)); args[jss::api_version] = apiVersion; - auto const rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + auto const rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; auto const error = apiVersion < 2u ? "invalidParams" : "badKeyType"; BEAST_EXPECT(rs[jss::error] == error); }); @@ -1370,27 +1190,21 @@ struct PayChan_test : public beast::unit_test::suite env.close(); std::string chan1PkStr; { - auto const r = - env.rpc("account_channels", alice.human(), bob.human()); + auto const r = env.rpc("account_channels", alice.human(), bob.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); BEAST_EXPECT(r[jss::result][jss::validated]); - chan1PkStr = - r[jss::result][jss::channels][0u][jss::public_key].asString(); + chan1PkStr = r[jss::result][jss::channels][0u][jss::public_key].asString(); } { auto const r = env.rpc("account_channels", alice.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str); BEAST_EXPECT(r[jss::result][jss::validated]); - chan1PkStr = - r[jss::result][jss::channels][0u][jss::public_key].asString(); + chan1PkStr = r[jss::result][jss::channels][0u][jss::public_key].asString(); } { - auto const r = - env.rpc("account_channels", bob.human(), alice.human()); + auto const r = env.rpc("account_channels", bob.human(), alice.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 0); BEAST_EXPECT(r[jss::result][jss::validated]); } @@ -1398,8 +1212,7 @@ struct PayChan_test : public beast::unit_test::suite env(create(alice, bob, channelFunds, settleDelay, pk)); env.close(); { - auto const r = - env.rpc("account_channels", alice.human(), bob.human()); + auto const r = env.rpc("account_channels", alice.human(), bob.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 2); BEAST_EXPECT(r[jss::result][jss::validated]); BEAST_EXPECT(chan1Str != chan2Str); @@ -1422,28 +1235,24 @@ struct PayChan_test : public beast::unit_test::suite { // Verify chan1 auth - auto const rs = - env.rpc("channel_authorize", "alice", chan1Str, "1000"); + auto const rs = env.rpc("channel_authorize", "alice", chan1Str, "1000"); auto const sig = rs[jss::result][jss::signature].asString(); BEAST_EXPECT(!sig.empty()); { - auto const rv = env.rpc( - "channel_verify", chan1PkStr, chan1Str, "1000", sig); + auto const rv = env.rpc("channel_verify", chan1PkStr, chan1Str, "1000", sig); BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool()); } { // use pk hex to verify auto const pkAsHex = sliceToHex(pk.slice()); - auto const rv = - env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig); + auto const rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig); BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool()); } { // malformed amount auto const pkAsHex = sliceToHex(pk.slice()); - auto rv = - env.rpc("channel_verify", pkAsHex, chan1Str, "1000x", sig); + auto rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000x", sig); BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 ", sig); BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); @@ -1453,8 +1262,7 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); rv = env.rpc("channel_verify", pkAsHex, chan1Str, " ", sig); BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); - rv = env.rpc( - "channel_verify", pkAsHex, chan1Str, "1000 1000", sig); + rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 1000", sig); BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1,000", sig); BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed"); @@ -1468,24 +1276,21 @@ struct PayChan_test : public beast::unit_test::suite auto const pkAsHex = sliceToHex(pk.slice()); auto chan1StrBad = chan1Str; chan1StrBad.pop_back(); - auto rv = env.rpc( - "channel_verify", pkAsHex, chan1StrBad, "1000", sig); + auto rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000"); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); chan1StrBad = chan1Str; chan1StrBad.push_back('0'); - rv = env.rpc( - "channel_verify", pkAsHex, chan1StrBad, "1000", sig); + rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000"); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); chan1StrBad = chan1Str; chan1StrBad.back() = 'x'; - rv = env.rpc( - "channel_verify", pkAsHex, chan1StrBad, "1000", sig); + rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000"); BEAST_EXPECT(rv[jss::error] == "channelMalformed"); @@ -1493,100 +1298,77 @@ struct PayChan_test : public beast::unit_test::suite { // give an ill formed base 58 public key auto illFormedPk = chan1PkStr.substr(0, chan1PkStr.size() - 1); - auto const rv = env.rpc( - "channel_verify", illFormedPk, chan1Str, "1000", sig); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", illFormedPk, chan1Str, "1000", sig); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } { // give an ill formed hex public key auto const pkAsHex = sliceToHex(pk.slice()); auto illFormedPk = pkAsHex.substr(0, chan1PkStr.size() - 1); - auto const rv = env.rpc( - "channel_verify", illFormedPk, chan1Str, "1000", sig); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", illFormedPk, chan1Str, "1000", sig); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } } { // Try to verify chan2 auth with chan1 key - auto const rs = - env.rpc("channel_authorize", "alice", chan2Str, "1000"); + auto const rs = env.rpc("channel_authorize", "alice", chan2Str, "1000"); auto const sig = rs[jss::result][jss::signature].asString(); BEAST_EXPECT(!sig.empty()); { - auto const rv = env.rpc( - "channel_verify", chan1PkStr, chan1Str, "1000", sig); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", chan1PkStr, chan1Str, "1000", sig); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } { // use pk hex to verify auto const pkAsHex = sliceToHex(pk.slice()); - auto const rv = - env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } } { // Try to explicitly specify secp256k1 and Ed25519 keys: - auto const chan = - to_string(channel(charlie, alice, env.seq(charlie))); - env(create( - charlie, alice, channelFunds, settleDelay, charlie.pk())); + auto const chan = to_string(channel(charlie, alice, env.seq(charlie))); + env(create(charlie, alice, channelFunds, settleDelay, charlie.pk())); env.close(); std::string cpk; { - auto const r = - env.rpc("account_channels", charlie.human(), alice.human()); + auto const r = env.rpc("account_channels", charlie.human(), alice.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan); BEAST_EXPECT(r[jss::result][jss::validated]); - cpk = r[jss::result][jss::channels][0u][jss::public_key] - .asString(); + cpk = r[jss::result][jss::channels][0u][jss::public_key].asString(); } // Try to authorize without specifying a key type, expect an error: - auto const rs = - env.rpc("channel_authorize", "charlie", chan, "1000"); + auto const rs = env.rpc("channel_authorize", "charlie", chan, "1000"); auto const sig = rs[jss::result][jss::signature].asString(); BEAST_EXPECT(!sig.empty()); { - auto const rv = - env.rpc("channel_verify", cpk, chan, "1000", sig); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", cpk, chan, "1000", sig); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } // Try to authorize using an unknown key type, except an error: - auto const rs1 = - env.rpc("channel_authorize", "charlie", "nyx", chan, "1000"); + auto const rs1 = env.rpc("channel_authorize", "charlie", "nyx", chan, "1000"); BEAST_EXPECT(rs1[jss::error] == "badKeyType"); // Try to authorize using secp256k1; the authorization _should_ // succeed but the verification should fail: - auto const rs2 = env.rpc( - "channel_authorize", "charlie", "secp256k1", chan, "1000"); + auto const rs2 = env.rpc("channel_authorize", "charlie", "secp256k1", chan, "1000"); auto const sig2 = rs2[jss::result][jss::signature].asString(); BEAST_EXPECT(!sig2.empty()); { - auto const rv = - env.rpc("channel_verify", cpk, chan, "1000", sig2); - BEAST_EXPECT( - !rv[jss::result][jss::signature_verified].asBool()); + auto const rv = env.rpc("channel_verify", cpk, chan, "1000", sig2); + BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool()); } // Try to authorize using Ed25519; expect success: - auto const rs3 = env.rpc( - "channel_authorize", "charlie", "ed25519", chan, "1000"); + auto const rs3 = env.rpc("channel_authorize", "charlie", "ed25519", chan, "1000"); auto const sig3 = rs3[jss::result][jss::signature].asString(); BEAST_EXPECT(!sig3.empty()); { - auto const rv = - env.rpc("channel_verify", cpk, chan, "1000", sig3); + auto const rv = env.rpc("channel_verify", cpk, chan, "1000", sig3); BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool()); } } @@ -1605,10 +1387,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::amount] = "2000"; args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "invalidParams"); } { @@ -1617,10 +1396,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::channel_id] = chan1Str; args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "invalidParams"); } { @@ -1629,10 +1405,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::amount] = "2000"; args[jss::channel_id] = chan1Str; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "invalidParams"); } { @@ -1643,10 +1416,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; args[jss::seed] = "seed can be anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "invalidParams"); } { @@ -1656,10 +1426,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::channel_id] = chan1Str + "1"; args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "channelMalformed"); } { @@ -1669,10 +1436,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::channel_id] = chan1Str; args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed"); } { @@ -1682,10 +1446,7 @@ struct PayChan_test : public beast::unit_test::suite args[jss::channel_id] = chan1Str; args[jss::key_type] = "secp256k1"; args[jss::passphrase] = "passphrase_can_be_anything"; - rs = env.rpc( - "json", - "channel_authorize", - args.toStyledString())[jss::result]; + rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result]; BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed"); } } @@ -1712,33 +1473,19 @@ struct PayChan_test : public beast::unit_test::suite { auto const chan = to_string(channel(alice, bob, env.seq(alice))); env(create(alice, bob, channelFunds, settleDelay, pk)); - auto const r = - env.rpc("account_channels", alice.human(), bob.human()); + auto const r = env.rpc("account_channels", alice.human(), bob.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan); - BEAST_EXPECT(!r[jss::result][jss::channels][0u].isMember( - jss::destination_tag)); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan); + BEAST_EXPECT(!r[jss::result][jss::channels][0u].isMember(jss::destination_tag)); } { std::uint32_t dstTag = 42; auto const chan = to_string(channel(alice, carol, env.seq(alice))); - env(create( - alice, - carol, - channelFunds, - settleDelay, - pk, - cancelAfter, - dstTag)); - auto const r = - env.rpc("account_channels", alice.human(), carol.human()); + env(create(alice, carol, channelFunds, settleDelay, pk, cancelAfter, dstTag)); + auto const r = env.rpc("account_channels", alice.human(), carol.human()); BEAST_EXPECT(r[jss::result][jss::channels].size() == 1); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::channel_id] == chan); - BEAST_EXPECT( - r[jss::result][jss::channels][0u][jss::destination_tag] == - dstTag); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::channel_id] == chan); + BEAST_EXPECT(r[jss::result][jss::channels][0u][jss::destination_tag] == dstTag); } } @@ -1774,13 +1521,7 @@ struct PayChan_test : public beast::unit_test::suite auto const authAmt = XRP(100); auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); - jv = claim( - bob, - chan, - authAmt.value(), - authAmt.value(), - Slice(sig), - alice.pk()); + jv = claim(bob, chan, authAmt.value(), authAmt.value(), Slice(sig), alice.pk()); jv["PublicKey"] = pkHex.substr(2, pkHex.size() - 2); env(jv, ter(temMALFORMED)); jv["PublicKey"] = pkHex.substr(0, pkHex.size() - 2); @@ -1825,58 +1566,23 @@ struct PayChan_test : public beast::unit_test::suite auto const settleDelay = 100s; auto const pk = alice.pk(); - auto inOwnerDir = [](ReadView const& view, - Account const& acc, - std::shared_ptr const& chan) -> bool { - ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id())); - return std::find(ownerDir.begin(), ownerDir.end(), chan) != - ownerDir.end(); + auto inOwnerDir = [](ReadView const& view, Account const& acc, std::shared_ptr const& chan) -> bool { + xrpl::Dir const ownerDir(view, keylet::ownerDir(acc.id())); + return std::find(ownerDir.begin(), ownerDir.end(), chan) != ownerDir.end(); }; - auto ownerDirCount = [](ReadView const& view, - Account const& acc) -> std::size_t { - ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id())); + auto ownerDirCount = [](ReadView const& view, Account const& acc) -> std::size_t { + xrpl::Dir const ownerDir(view, keylet::ownerDir(acc.id())); return std::distance(ownerDir.begin(), ownerDir.end()); }; - { - // Test without adding the paychan to the recipient's owner - // directory - Env env(*this, features - fixPayChanRecipientOwnerDir); - env.fund(XRP(10000), alice, bob); - env(create(alice, bob, XRP(1000), settleDelay, pk)); - env.close(); - auto const [chan, chanSle] = - channelKeyAndSle(*env.current(), alice, bob); - BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1); - BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); - if (features[fixIncludeKeyletFields]) - { - BEAST_EXPECT((*chanSle)[sfSequence] == env.seq(alice) - 1); - } - else - { - BEAST_EXPECT(!chanSle->isFieldPresent(sfSequence)); - } - // close the channel - env(claim(bob, chan), txflags(tfClose)); - BEAST_EXPECT(!channelExists(*env.current(), chan)); - BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0); - BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); - } - { // Test with adding the paychan to the recipient's owner directory Env env{*this, features}; env.fund(XRP(10000), alice, bob); env(create(alice, bob, XRP(1000), settleDelay, pk)); env.close(); - auto const [chan, chanSle] = - channelKeyAndSle(*env.current(), alice, bob); + auto const [chan, chanSle] = channelKeyAndSle(*env.current(), alice, bob); BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle)); BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1); BEAST_EXPECT(inOwnerDir(*env.current(), bob, chanSle)); @@ -1893,30 +1599,17 @@ struct PayChan_test : public beast::unit_test::suite { // Test removing paychans created before adding to the recipient's // owner directory - Env env(*this, features - fixPayChanRecipientOwnerDir); + Env env(*this, features); env.fund(XRP(10000), alice, bob); // create the channel before the amendment activates env(create(alice, bob, XRP(1000), settleDelay, pk)); env.close(); - auto const [chan, chanSle] = - channelKeyAndSle(*env.current(), alice, bob); + auto const [chan, chanSle] = channelKeyAndSle(*env.current(), alice, bob); BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle)); BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1); - BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); - env.enableFeature(fixPayChanRecipientOwnerDir); - env.close(); - BEAST_EXPECT( - env.current()->rules().enabled(fixPayChanRecipientOwnerDir)); - // These checks look redundant, but if you don't `close` after the - // `create` these checks will fail. I believe this is due to the - // create running with one set of amendments initially, then with a - // different set with the ledger closes (tho I haven't dug into it) - BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle)); - BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle)); - BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0); + BEAST_EXPECT(inOwnerDir(*env.current(), bob, chanSle)); + BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1); - // close the channel after the amendment activates env(claim(bob, chan), txflags(tfClose)); BEAST_EXPECT(!channelExists(*env.current(), chan)); BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle)); @@ -1932,38 +1625,24 @@ struct PayChan_test : public beast::unit_test::suite testcase("Account Delete"); using namespace test::jtx; using namespace std::literals::chrono_literals; - auto rmAccount = [this]( - Env& env, - Account const& toRm, - Account const& dst, - TER expectedTer = tesSUCCESS) { + auto rmAccount = [this](Env& env, Account const& toRm, Account const& dst, TER expectedTer = tesSUCCESS) { // only allow an account to be deleted if the account's sequence // number is at least 256 less than the current ledger sequence - for (auto minRmSeq = env.seq(toRm) + 257; - env.current()->seq() < minRmSeq; - env.close()) + for (auto minRmSeq = env.seq(toRm) + 257; env.current()->seq() < minRmSeq; env.close()) { } - env(acctdelete(toRm, dst), - fee(drops(env.current()->fees().increment)), - ter(expectedTer)); + env(acctdelete(toRm, dst), fee(drops(env.current()->fees().increment)), ter(expectedTer)); env.close(); - this->BEAST_EXPECT( - isTesSuccess(expectedTer) == - !env.closed()->exists(keylet::account(toRm.id()))); + this->BEAST_EXPECT(isTesSuccess(expectedTer) == !env.closed()->exists(keylet::account(toRm.id()))); }; auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); - for (bool const withOwnerDirFix : {false, true}) { - auto const amd = withOwnerDirFix - ? features - : features - fixPayChanRecipientOwnerDir; - Env env{*this, amd}; + Env env{*this, features}; env.fund(XRP(10000), alice, bob, carol); env.close(); @@ -1977,12 +1656,7 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000)); rmAccount(env, alice, carol, tecHAS_OBLIGATIONS); - // can only remove bob if the channel isn't in their owner direcotry - rmAccount( - env, - bob, - carol, - withOwnerDirFix ? TER(tecHAS_OBLIGATIONS) : TER(tesSUCCESS)); + rmAccount(env, bob, carol, TER(tecHAS_OBLIGATIONS)); auto const feeDrops = env.current()->fees().base; auto chanBal = channelBalance(*env.current(), chan); @@ -1996,161 +1670,27 @@ struct PayChan_test : public beast::unit_test::suite auto authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - // claim should fail if the dst was removed - if (withOwnerDirFix) - { - env(claim(alice, chan, reqBal, authAmt)); - env.close(); - BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - BEAST_EXPECT(env.balance(bob) == preBob + delta); - chanBal = reqBal; - } - else - { - auto const preAlice = env.balance(alice); - env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST)); - env.close(); - BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - BEAST_EXPECT(env.balance(bob) == preBob); - BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops); - } + env(claim(alice, chan, reqBal, authAmt)); + env.close(); + BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); + BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); + BEAST_EXPECT(env.balance(bob) == preBob + delta); + chanBal = reqBal; - // fund should fail if the dst was removed - if (withOwnerDirFix) - { - auto const preAlice = env.balance(alice); - env(fund(alice, chan, XRP(1000))); - env.close(); - BEAST_EXPECT( - env.balance(alice) == preAlice - XRP(1000) - feeDrops); - BEAST_EXPECT( - channelAmount(*env.current(), chan) == chanAmt + XRP(1000)); - chanAmt = chanAmt + XRP(1000); - } - else - { - auto const preAlice = env.balance(alice); - env(fund(alice, chan, XRP(1000)), ter(tecNO_DST)); - env.close(); - BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - } + auto const preAlice = env.balance(alice); + env(fund(alice, chan, XRP(1000))); + env.close(); + BEAST_EXPECT(env.balance(alice) == preAlice - XRP(1000) - feeDrops); + BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt + XRP(1000)); + chanAmt = chanAmt + XRP(1000); { // Owner closes, will close after settleDelay env(claim(alice, chan), txflags(tfClose)); env.close(); - // settle delay hasn't ellapsed. Channels should exist. + // settle delay hasn't elapsed. Channels should exist. BEAST_EXPECT(channelExists(*env.current(), chan)); - auto const closeTime = env.current()->info().parentCloseTime; - auto const minExpiration = closeTime + settleDelay; - env.close(minExpiration); - env(claim(alice, chan), txflags(tfClose)); - BEAST_EXPECT(!channelExists(*env.current(), chan)); - } - } - - { - // test resurrected account - Env env{*this, features - fixPayChanRecipientOwnerDir}; - env.fund(XRP(10000), alice, bob, carol); - env.close(); - - // Create a channel from alice to bob - auto const pk = alice.pk(); - auto const settleDelay = 100s; - auto const chan = channel(alice, bob, env.seq(alice)); - env(create(alice, bob, XRP(1000), settleDelay, pk)); - env.close(); - BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0)); - BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000)); - - // Since `fixPayChanRecipientOwnerDir` is not active, can remove bob - rmAccount(env, bob, carol); - BEAST_EXPECT(!env.closed()->exists(keylet::account(bob.id()))); - - auto const feeDrops = env.current()->fees().base; - auto chanBal = channelBalance(*env.current(), chan); - auto chanAmt = channelAmount(*env.current(), chan); - BEAST_EXPECT(chanBal == XRP(0)); - BEAST_EXPECT(chanAmt == XRP(1000)); - auto preBob = env.balance(bob); - auto const delta = XRP(50); - auto reqBal = chanBal + delta; - auto authAmt = reqBal + XRP(100); - assert(reqBal <= chanAmt); - - { - // claim should fail, since bob doesn't exist - auto const preAlice = env.balance(alice); - env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST)); - env.close(); - BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - BEAST_EXPECT(env.balance(bob) == preBob); - BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops); - } - - { - // fund should fail, sincebob doesn't exist - auto const preAlice = env.balance(alice); - env(fund(alice, chan, XRP(1000)), ter(tecNO_DST)); - env.close(); - BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - } - - // resurrect bob - env(pay(alice, bob, XRP(20))); - env.close(); - BEAST_EXPECT(env.closed()->exists(keylet::account(bob.id()))); - - { - // alice should be able to claim - preBob = env.balance(bob); - reqBal = chanBal + delta; - authAmt = reqBal + XRP(100); - env(claim(alice, chan, reqBal, authAmt)); - BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - BEAST_EXPECT(env.balance(bob) == preBob + delta); - chanBal = reqBal; - } - - { - // bob should be able to claim - preBob = env.balance(bob); - reqBal = chanBal + delta; - authAmt = reqBal + XRP(100); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); - env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk())); - BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal); - BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt); - BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops); - chanBal = reqBal; - } - - { - // alice should be able to fund - auto const preAlice = env.balance(alice); - env(fund(alice, chan, XRP(1000))); - BEAST_EXPECT( - env.balance(alice) == preAlice - XRP(1000) - feeDrops); - BEAST_EXPECT( - channelAmount(*env.current(), chan) == chanAmt + XRP(1000)); - chanAmt = chanAmt + XRP(1000); - } - - { - // Owner closes, will close after settleDelay - env(claim(alice, chan), txflags(tfClose)); - env.close(); - // settle delay hasn't ellapsed. Channels should exist. - BEAST_EXPECT(channelExists(*env.current(), chan)); - auto const closeTime = env.current()->info().parentCloseTime; + auto const closeTime = env.current()->header().parentCloseTime; auto const minExpiration = closeTime + settleDelay; env.close(minExpiration); env(claim(alice, chan), txflags(tfClose)); @@ -2186,8 +1726,7 @@ struct PayChan_test : public beast::unit_test::suite auto const settleDelay = 100s; auto const chan = channel(alice, bob, aliceTicketSeq); - env(create(alice, bob, XRP(1000), settleDelay, pk), - ticket::use(aliceTicketSeq++)); + env(create(alice, bob, XRP(1000), settleDelay, pk), ticket::use(aliceTicketSeq++)); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -2218,8 +1757,7 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - env(claim(alice, chan, reqBal, authAmt), - ticket::use(aliceTicketSeq++)); + env(claim(alice, chan, reqBal, authAmt), ticket::use(aliceTicketSeq++)); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); BEAST_EXPECT(env.seq(alice) == aliceSeq); @@ -2236,10 +1774,8 @@ struct PayChan_test : public beast::unit_test::suite auto const reqBal = chanBal + delta; auto const authAmt = reqBal + XRP(100); assert(reqBal <= chanAmt); - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); - env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()), - ticket::use(bobTicketSeq++)); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()), ticket::use(bobTicketSeq++)); env.require(tickets(bob, env.seq(bob) - bobTicketSeq)); BEAST_EXPECT(env.seq(bob) == bobSeq); @@ -2272,8 +1808,7 @@ struct PayChan_test : public beast::unit_test::suite assert(reqAmt <= chanAmt); // Note that since claim() returns a tem (neither tec nor tes), // the ticket is not consumed. So we don't increment bobTicket. - auto const sig = - signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); + auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt); env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()), ticket::use(bobTicketSeq), ter(temBAD_AMOUNT)); @@ -2287,9 +1822,7 @@ struct PayChan_test : public beast::unit_test::suite } // Dst tries to fund the channel - env(fund(bob, chan, XRP(1000)), - ticket::use(bobTicketSeq++), - ter(tecNO_PERMISSION)); + env(fund(bob, chan, XRP(1000)), ticket::use(bobTicketSeq++), ter(tecNO_PERMISSION)); env.require(tickets(bob, env.seq(bob) - bobTicketSeq)); BEAST_EXPECT(env.seq(bob) == bobSeq); @@ -2301,9 +1834,7 @@ struct PayChan_test : public beast::unit_test::suite // Dst closes channel auto const preAlice = env.balance(alice); auto const preBob = env.balance(bob); - env(claim(bob, chan), - txflags(tfClose), - ticket::use(bobTicketSeq++)); + env(claim(bob, chan), txflags(tfClose), ticket::use(bobTicketSeq++)); env.require(tickets(bob, env.seq(bob) - bobTicketSeq)); BEAST_EXPECT(env.seq(bob) == bobSeq); @@ -2353,13 +1884,12 @@ public: { using namespace test::jtx; FeatureBitset const all{testable_amendments()}; - testWithFeats(all - disallowIncoming); testWithFeats(all); testDepositAuthCreds(); testMetaAndOwnership(all - fixIncludeKeyletFields); } }; -BEAST_DEFINE_TESTSUITE(PayChan, app, ripple); +BEAST_DEFINE_TESTSUITE(PayChan, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/PayStrand_test.cpp b/src/test/app/PayStrand_test.cpp index 16a6861bfd..9b534d9284 100644 --- a/src/test/app/PayStrand_test.cpp +++ b/src/test/app/PayStrand_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +14,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { struct DirectStepInfo @@ -70,12 +53,7 @@ trustFlag(TrustFlag f, bool useHigh) } bool -getTrustFlag( - jtx::Env const& env, - jtx::Account const& src, - jtx::Account const& dst, - Currency const& cur, - TrustFlag flag) +getTrustFlag(jtx::Env const& env, jtx::Account const& src, jtx::Account const& dst, Currency const& cur, TrustFlag flag) { if (auto sle = env.le(keylet::line(src, dst, cur))) { @@ -95,15 +73,15 @@ equal(std::unique_ptr const& s1, DirectStepInfo const& dsi) } bool -equal(std::unique_ptr const& s1, XRPEndpointStepInfo const& xrpsi) +equal(std::unique_ptr const& s1, XRPEndpointStepInfo const& xrpStepInfo) { if (!s1) return false; - return test::xrpEndpointStepEqual(*s1, xrpsi.acc); + return test::xrpEndpointStepEqual(*s1, xrpStepInfo.acc); } bool -equal(std::unique_ptr const& s1, ripple::Book const& bsi) +equal(std::unique_ptr const& s1, xrpl::Book const& bsi) { if (!s1) return false; @@ -141,8 +119,7 @@ equal(Strand const& strand, Args&&... args) STPathElement ape(AccountID const& a) { - return STPathElement( - STPathElement::typeAccount, a, xrpCurrency(), xrpAccount()); + return STPathElement(STPathElement::typeAccount, a, xrpCurrency(), xrpAccount()); }; // Issue path element @@ -150,18 +127,14 @@ STPathElement ipe(Issue const& iss) { return STPathElement( - STPathElement::typeCurrency | STPathElement::typeIssuer, - xrpAccount(), - iss.currency, - iss.account); + STPathElement::typeCurrency | STPathElement::typeIssuer, xrpAccount(), iss.currency, iss.account); }; // Issuer path element STPathElement iape(AccountID const& account) { - return STPathElement( - STPathElement::typeIssuer, xrpAccount(), xrpCurrency(), account); + return STPathElement(STPathElement::typeIssuer, xrpAccount(), xrpCurrency(), account); }; class ElementComboIter @@ -186,9 +159,7 @@ class ElementComboIter }; std::uint16_t state_ = 0; - static_assert( - safe_cast(SB::last) <= sizeof(decltype(state_)) * 8, - ""); + static_assert(safe_cast(SB::last) <= sizeof(decltype(state_)) * 8, ""); STPathElement const* prev_ = nullptr; // disallow iss and cur to be specified with acc is specified (simplifies // some tests) @@ -228,17 +199,11 @@ public: bool valid() const { - return (allowCompound_ || - !(has(SB::acc) && hasAny({SB::cur, SB::iss}))) && + return (allowCompound_ || !(has(SB::acc) && hasAny({SB::cur, SB::iss}))) && (!hasAny({SB::prevAcc, SB::prevCur, SB::prevIss}) || prev_) && - (!hasAny( - {SB::rootAcc, SB::sameAccIss, SB::existingAcc, SB::prevAcc}) || - has(SB::acc)) && - (!hasAny( - {SB::rootIss, SB::sameAccIss, SB::existingIss, SB::prevIss}) || - has(SB::iss)) && - (!hasAny({SB::xrp, SB::existingCur, SB::prevCur}) || - has(SB::cur)) && + (!hasAny({SB::rootAcc, SB::sameAccIss, SB::existingAcc, SB::prevAcc}) || has(SB::acc)) && + (!hasAny({SB::rootIss, SB::sameAccIss, SB::existingIss, SB::prevIss}) || has(SB::iss)) && + (!hasAny({SB::xrp, SB::existingCur, SB::prevCur}) || has(SB::cur)) && // These will be duplicates (count({SB::xrp, SB::existingCur, SB::prevCur}) <= 1) && (count({SB::rootAcc, SB::existingAcc, SB::prevAcc}) <= 1) && @@ -257,11 +222,7 @@ public: return !has(SB::last); } - template < - class Col, - class AccFactory, - class IssFactory, - class CurrencyFactory> + template void emplace_into( Col& col, @@ -317,7 +278,7 @@ public: struct ExistingElementPool { std::vector accounts; - std::vector currencies; + std::vector currencies; std::vector currencyNames; jtx::Account @@ -327,7 +288,7 @@ struct ExistingElementPool return accounts[id]; } - ripple::Currency + xrpl::Currency getCurrency(size_t id) { assert(id < currencies.size()); @@ -357,8 +318,7 @@ struct ExistingElementPool ExistingElementPool& p_; ResetState state_; - explicit StateGuard(ExistingElementPool& p) - : p_{p}, state_{p.getResetState()} + explicit StateGuard(ExistingElementPool& p) : p_{p}, state_{p.getResetState()} { } ~StateGuard() @@ -373,11 +333,7 @@ struct ExistingElementPool // currency/account; the offer owner is either the specified // account or the issuer of the "taker gets" account void - setupEnv( - jtx::Env& env, - size_t numAct, - size_t numCur, - std::optional const& offererIndex) + setupEnv(jtx::Env& env, size_t numAct, size_t numCur, std::optional const& offererIndex) { using namespace jtx; @@ -415,8 +371,7 @@ struct ExistingElementPool env.fund(XRP(100000), a); // Every account trusts every other account with every currency - for (auto ai1 = accounts.begin(), aie = accounts.end(); ai1 != aie; - ++ai1) + for (auto ai1 = accounts.begin(), aie = accounts.end(); ai1 != aie; ++ai1) { for (auto ai2 = accounts.begin(); ai2 != aie; ++ai2) { @@ -446,20 +401,17 @@ struct ExistingElementPool ious.emplace_back(a[cn]); // create offers from every currency to every other currency - for (auto takerPays = ious.begin(), ie = ious.end(); takerPays != ie; - ++takerPays) + for (auto takerPays = ious.begin(), ie = ious.end(); takerPays != ie; ++takerPays) { for (auto takerGets = ious.begin(); takerGets != ie; ++takerGets) { if (takerPays == takerGets) continue; - auto const owner = - offererIndex ? accounts[*offererIndex] : takerGets->account; + auto const owner = offererIndex ? accounts[*offererIndex] : takerGets->account; if (owner.id() != takerGets->account.id()) env(pay(takerGets->account, owner, (*takerGets)(1000))); - env(offer(owner, (*takerPays)(1000), (*takerGets)(1000)), - txflags(tfPassive)); + env(offer(owner, (*takerPays)(1000), (*takerGets)(1000)), txflags(tfPassive)); } env.close(); } @@ -467,8 +419,7 @@ struct ExistingElementPool // create offers to/from xrp to every other ious for (auto const& iou : ious) { - auto const owner = - offererIndex ? accounts[*offererIndex] : iou.account; + auto const owner = offererIndex ? accounts[*offererIndex] : iou.account; env(offer(owner, iou(1000), XRP(1000)), txflags(tfPassive)); env(offer(owner, XRP(1000), iou(1000)), txflags(tfPassive)); env.close(); @@ -501,21 +452,20 @@ struct ExistingElementPool { std::vector> diffs; - auto xrpBalance = [](ReadView const& v, ripple::Keylet const& k) { + auto xrpBalance = [](ReadView const& v, xrpl::Keylet const& k) { auto const sle = v.read(k); if (!sle) return STAmount{}; return (*sle)[sfBalance]; }; - auto lineBalance = [](ReadView const& v, ripple::Keylet const& k) { + auto lineBalance = [](ReadView const& v, xrpl::Keylet const& k) { auto const sle = v.read(k); if (!sle) return STAmount{}; return (*sle)[sfBalance]; }; std::uint64_t totalXRP[2]{}; - for (auto ai1 = accounts.begin(), aie = accounts.end(); ai1 != aie; - ++ai1) + for (auto ai1 = accounts.begin(), aie = accounts.end(); ai1 != aie; ++ai1) { { // XRP balance @@ -551,7 +501,7 @@ struct ExistingElementPool return getAccount(nextAvailAccount++); } - ripple::Currency + xrpl::Currency getAvailCurrency() { return getCurrency(nextAvailCurrency++); @@ -573,8 +523,7 @@ struct ExistingElementPool auto issF = [&] { return this->getAvailAccount(); }; auto currencyF = [&] { return this->getAvailCurrency(); }; - STPathElement const* prevOuter = - prefix.empty() ? nullptr : &prefix.back(); + STPathElement const* prevOuter = prefix.empty() ? nullptr : &prefix.back(); ElementComboIter outer(prevOuter); std::vector outerResult; @@ -586,28 +535,14 @@ struct ExistingElementPool { StateGuard og{*this}; outerResult = prefix; - outer.emplace_into( - outerResult, - accF, - issF, - currencyF, - existingAcc, - existingCur, - existingIss); + outer.emplace_into(outerResult, accF, issF, currencyF, existingAcc, existingCur, existingIss); STPathElement const* prevInner = &outerResult.back(); ElementComboIter inner(prevInner); while (inner.next()) { StateGuard ig{*this}; result = outerResult; - inner.emplace_into( - result, - accF, - issF, - currencyF, - existingAcc, - existingCur, - existingIss); + inner.emplace_into(result, accF, issF, currencyF, existingAcc, existingCur, existingIss); result.insert(result.end(), suffix.begin(), suffix.end()); f(sendMax, deliver, result); } @@ -636,7 +571,7 @@ struct PayStrand_test : public beast::unit_test::suite auto const usdC = USD.currency; using D = DirectStepInfo; - using B = ripple::Book; + using B = xrpl::Book; using XRPS = XRPEndpointStepInfo; AMMContext ammContext(alice, false); @@ -663,8 +598,7 @@ struct PayStrand_test : public beast::unit_test::suite env.app().logs().journal("Flow")); BEAST_EXPECT(ter == expTer); if (sizeof...(expSteps) != 0) - BEAST_EXPECT(equal( - strand, std::forward(expSteps)...)); + BEAST_EXPECT(equal(strand, std::forward(expSteps)...)); }; { @@ -675,8 +609,7 @@ struct PayStrand_test : public beast::unit_test::suite env(pay(gw, alice, EUR(100))); { - STPath const path = - STPath({ipe(bob["USD"]), cpe(EUR.currency)}); + STPath const path = STPath({ipe(bob["USD"]), cpe(EUR.currency)}); auto [ter, _] = toStrand( *env.current(), alice, @@ -726,14 +659,7 @@ struct PayStrand_test : public beast::unit_test::suite env(pay(gw, carol, USD(100))); // Insert implied account - test( - env, - USD, - std::nullopt, - STPath(), - tesSUCCESS, - D{alice, gw, usdC}, - D{gw, bob, usdC}); + test(env, USD, std::nullopt, STPath(), tesSUCCESS, D{alice, gw, usdC}, D{gw, bob, usdC}); env.trust(EUR(1000), alice, bob); // Insert implied offer @@ -786,11 +712,7 @@ struct PayStrand_test : public beast::unit_test::suite env, xrpIssue(), USD.issue(), - STPath({STPathElement{ - STPathElement::typeCurrency, - xrpAccount(), - xrpCurrency(), - xrpAccount()}}), + STPath({STPathElement{STPathElement::typeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()}}), tesSUCCESS, D{alice, gw, usdC}, B{USD, XRP, std::nullopt}, @@ -868,39 +790,23 @@ struct PayStrand_test : public beast::unit_test::suite } // Create an offer with the same in/out issue - test( - env, - EUR, - USD.issue(), - STPath({ipe(USD), ipe(EUR)}), - temBAD_PATH); + test(env, EUR, USD.issue(), STPath({ipe(USD), ipe(EUR)}), temBAD_PATH); // Path element with type zero test( env, USD, std::nullopt, - STPath({STPathElement( - 0, xrpAccount(), xrpCurrency(), xrpAccount())}), + STPath({STPathElement(0, xrpAccount(), xrpCurrency(), xrpAccount())}), temBAD_PATH); // The same account can't appear more than once on a path // `gw` will be used from alice->carol and implied between carol // and bob - test( - env, - USD, - std::nullopt, - STPath({ape(gw), ape(carol)}), - temBAD_PATH_LOOP); + test(env, USD, std::nullopt, STPath({ape(gw), ape(carol)}), temBAD_PATH_LOOP); // The same offer can't appear more than once on a path - test( - env, - EUR, - USD.issue(), - STPath({ipe(EUR), ipe(USD), ipe(EUR)}), - temBAD_PATH_LOOP); + test(env, EUR, USD.issue(), STPath({ipe(EUR), ipe(USD), ipe(EUR)}), temBAD_PATH_LOOP); } { @@ -1030,11 +936,7 @@ struct PayStrand_test : public beast::unit_test::suite std::nullopt, env.app().logs().journal("Flow")); BEAST_EXPECT(ter == tesSUCCESS); - BEAST_EXPECT(equal( - strand, - D{alice, gw, usdC}, - B{USD.issue(), xrpIssue(), std::nullopt}, - XRPS{bob})); + BEAST_EXPECT(equal(strand, D{alice, gw, usdC}, B{USD.issue(), xrpIssue(), std::nullopt}, XRPS{bob})); } } @@ -1063,13 +965,12 @@ struct PayStrand_test : public beast::unit_test::suite env(offer(bob, XRP(100), bob["USD"](100)), txflags(tfPassive)); env(offer(gw, XRP(100), USD(100)), txflags(tfPassive)); - env(offer(bob, bob["USD"](100), bob["EUR"](100)), - txflags(tfPassive)); + env(offer(bob, bob["USD"](100), bob["EUR"](100)), txflags(tfPassive)); env(offer(gw, USD(100), EUR(100)), txflags(tfPassive)); Path const p = [&] { Path result; - result.push_back(allpe(gw, bob["USD"])); + result.push_back(allPathElements(gw, bob["USD"])); result.push_back(cpe(EUR.currency)); return result; }(); @@ -1095,10 +996,7 @@ struct PayStrand_test : public beast::unit_test::suite env(offer(bob, USD(100), XRP(100)), txflags(tfPassive)); // payment path: XRP -> XRP/USD -> USD/XRP - env(pay(alice, carol, XRP(100)), - path(~USD, ~XRP), - txflags(tfNoRippleDirect), - ter(temBAD_SEND_XRP_PATHS)); + env(pay(alice, carol, XRP(100)), path(~USD, ~XRP), txflags(tfNoRippleDirect), ter(temBAD_SEND_XRP_PATHS)); } { @@ -1199,61 +1097,29 @@ struct PayStrand_test : public beast::unit_test::suite AccountID const srcAcc = alice.id(); AccountID dstAcc = bob.id(); STPathSet pathSet; - ::ripple::path::RippleCalc::Input inputs; + ::xrpl::path::RippleCalc::Input inputs; inputs.defaultPathsAllowed = true; try { PaymentSandbox sb{env.current().get(), tapNONE}; { - auto const r = ::ripple::path::RippleCalc::rippleCalculate( - sb, - sendMax, - deliver, - dstAcc, - noAccount(), - pathSet, - std::nullopt, - env.app().logs(), - &inputs); + auto const r = ::xrpl::path::RippleCalc::rippleCalculate( + sb, sendMax, deliver, dstAcc, noAccount(), pathSet, std::nullopt, env.app().logs(), &inputs); BEAST_EXPECT(r.result() == temBAD_PATH); } { - auto const r = ::ripple::path::RippleCalc::rippleCalculate( - sb, - sendMax, - deliver, - noAccount(), - srcAcc, - pathSet, - std::nullopt, - env.app().logs(), - &inputs); + auto const r = ::xrpl::path::RippleCalc::rippleCalculate( + sb, sendMax, deliver, noAccount(), srcAcc, pathSet, std::nullopt, env.app().logs(), &inputs); BEAST_EXPECT(r.result() == temBAD_PATH); } { - auto const r = ::ripple::path::RippleCalc::rippleCalculate( - sb, - noAccountAmount, - deliver, - dstAcc, - srcAcc, - pathSet, - std::nullopt, - env.app().logs(), - &inputs); + auto const r = ::xrpl::path::RippleCalc::rippleCalculate( + sb, noAccountAmount, deliver, dstAcc, srcAcc, pathSet, std::nullopt, env.app().logs(), &inputs); BEAST_EXPECT(r.result() == temBAD_PATH); } { - auto const r = ::ripple::path::RippleCalc::rippleCalculate( - sb, - sendMax, - noAccountAmount, - dstAcc, - srcAcc, - pathSet, - std::nullopt, - env.app().logs(), - &inputs); + auto const r = ::xrpl::path::RippleCalc::rippleCalculate( + sb, sendMax, noAccountAmount, dstAcc, srcAcc, pathSet, std::nullopt, env.app().logs(), &inputs); BEAST_EXPECT(r.result() == temBAD_PATH); } } @@ -1281,7 +1147,7 @@ struct PayStrand_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PayStrand, app, ripple); +BEAST_DEFINE_TESTSUITE(PayStrand, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/PermissionedDEX_test.cpp b/src/test/app/PermissionedDEX_test.cpp index 80c75a2daf..7a55866780 100644 --- a/src/test/app/PermissionedDEX_test.cpp +++ b/src/test/app/PermissionedDEX_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -47,7 +28,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { using namespace jtx; @@ -72,8 +53,7 @@ class PermissionedDEX_test : public beast::unit_test::suite { auto offerInDir = [&](uint256 const& directory, uint64_t const pageIndex, - std::optional domain = - std::nullopt) -> bool { + std::optional domain = std::nullopt) -> bool { auto const page = env.le(keylet::page(directory, pageIndex)); if (!page) return false; @@ -104,10 +84,7 @@ class PermissionedDEX_test : public beast::unit_test::suite return false; if (!domainOffer && sle->isFieldPresent(sfDomainID)) return false; - if (!offerInDir( - sle->getFieldH256(sfBookDirectory), - sle->getFieldU64(sfBookNode), - (*sle)[~sfDomainID])) + if (!offerInDir(sle->getFieldH256(sfBookDirectory), sle->getFieldU64(sfBookNode), (*sle)[~sfDomainID])) return false; if (sle->isFlag(lsfHybrid)) @@ -119,8 +96,7 @@ class PermissionedDEX_test : public beast::unit_test::suite if (sle->getFieldArray(sfAdditionalBooks).size() != 1) return false; - auto const& additionalBookDirs = - sle->getFieldArray(sfAdditionalBooks); + auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks); for (auto const& bookDir : additionalBookDirs) { @@ -143,21 +119,13 @@ class PermissionedDEX_test : public beast::unit_test::suite } uint256 - getBookDirKey( - Book const& book, - STAmount const& takerPays, - STAmount const& takerGets) + getBookDirKey(Book const& book, STAmount const& takerPays, STAmount const& takerGets) { - return keylet::quality( - keylet::book(book), getRate(takerGets, takerPays)) - .key; + return keylet::quality(keylet::book(book), getRate(takerGets, takerPays)).key; } std::optional - getDefaultOfferDirKey( - Env const& env, - Account const& account, - std::uint32_t offerSeq) + getDefaultOfferDirKey(Env const& env, Account const& account, std::uint32_t offerSeq) { if (auto const sle = env.le(keylet::offer(account.id(), offerSeq))) return Keylet(ltDIR_NODE, (*sle)[sfBookDirectory]).key; @@ -193,12 +161,9 @@ class PermissionedDEX_test : public beast::unit_test::suite // test preflight { Env env(*this, features - featurePermissionedDEX); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); - env(offer(bob, XRP(10), USD(10)), - domain(domainID), - ter(temDISABLED)); + env(offer(bob, XRP(10), USD(10)), domain(domainID), ter(temDISABLED)); env.close(); env.enableFeature(featurePermissionedDEX); @@ -210,8 +175,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // preclaim - someone outside of the domain cannot create domain offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // create devin account who is not part of the domain Account devin("devin"); @@ -222,9 +186,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env(pay(gw, devin, USD(100))); env.close(); - env(offer(devin, XRP(10), USD(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(offer(devin, XRP(10), USD(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); // domain owner also issues a credential for devin @@ -232,9 +194,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin still cannot create offer since he didn't accept credential - env(offer(devin, XRP(10), USD(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(offer(devin, XRP(10), USD(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); env(credentials::accept(devin, domainOwner, credType)); @@ -247,8 +207,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // preclaim - someone with expired cred cannot create domain offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // create devin account who is not part of the domain Account devin("devin"); @@ -260,10 +219,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); auto jv = credentials::create(devin, domainOwner, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count(); + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count(); jv[sfExpiration.jsonName] = t + 20; env(jv); @@ -278,24 +234,19 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(std::chrono::seconds(20)); // devin cannot create offer with expired cred - env(offer(devin, XRP(10), USD(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(offer(devin, XRP(10), USD(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); } // preclaim - cannot create an offer in a non existent domain { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); uint256 const badDomain{ "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134" "E5"}; - env(offer(bob, XRP(10), USD(10)), - domain(badDomain), - ter(tecNO_PERMISSION)); + env(offer(bob, XRP(10), USD(10)), domain(badDomain), ter(tecNO_PERMISSION)); env.close(); } @@ -303,60 +254,51 @@ class PermissionedDEX_test : public beast::unit_test::suite // domain { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); - env(credentials::deleteCred( - domainOwner, gw, domainOwner, credType)); + env(credentials::deleteCred(domainOwner, gw, domainOwner, credType)); env.close(); auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); } // apply - offer can be created even if takerpays issuer is not in // domain { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); - env(credentials::deleteCred( - domainOwner, gw, domainOwner, credType)); + env(credentials::deleteCred(domainOwner, gw, domainOwner, credType)); env.close(); auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, USD(10), XRP(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, USD(10), XRP(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, USD(10), XRP(10), 0, true)); } // apply - two domain offers cross with each other { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); BEAST_EXPECT(ownerCount(env, bob) == 3); // a non domain offer cannot cross with domain offer env(offer(carol, USD(10), XRP(10))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); auto const aliceOfferSeq{env.seq(alice)}; env(offer(alice, USD(10), XRP(10)), domain(domainID)); @@ -370,8 +312,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // apply - create lots of domain offers { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); std::vector offerSeqs; offerSeqs.reserve(100); @@ -383,8 +324,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); } for (auto const offerSeq : offerSeqs) @@ -404,14 +344,9 @@ class PermissionedDEX_test : public beast::unit_test::suite // test preflight - without enabling featurePermissionedDEX amendment { Env env(*this, features - featurePermissionedDEX); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); - env(pay(bob, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(temDISABLED)); + env(pay(bob, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(temDISABLED)); env.close(); env.enableFeature(featurePermissionedDEX); @@ -420,35 +355,26 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - env(pay(bob, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(bob, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); } // preclaim - cannot send payment with non existent domain { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); uint256 const badDomain{ "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134" "E5"}; - env(pay(bob, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(badDomain), - ter(tecNO_PERMISSION)); + env(pay(bob, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(badDomain), ter(tecNO_PERMISSION)); env.close(); } // preclaim - payment with non-domain destination fails { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); @@ -463,11 +389,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin is not part of domain - env(pay(alice, devin, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(pay(alice, devin, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); // domain owner also issues a credential for devin @@ -475,29 +397,21 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin has not yet accepted cred - env(pay(alice, devin, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(pay(alice, devin, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); env(credentials::accept(devin, domainOwner, credType)); env.close(); // devin can now receive payment after he is in domain - env(pay(alice, devin, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(alice, devin, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); } // preclaim - non-domain sender cannot send payment { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); @@ -512,11 +426,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin tries to send domain payment - env(pay(devin, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(pay(devin, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); // domain owner also issues a credential for devin @@ -524,48 +434,34 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin has not yet accepted cred - env(pay(devin, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecNO_PERMISSION)); + env(pay(devin, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecNO_PERMISSION)); env.close(); env(credentials::accept(devin, domainOwner, credType)); env.close(); // devin can now send payment after he is in domain - env(pay(devin, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(devin, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); } // apply - domain owner can always send and receive domain payment { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); // domain owner can always be destination - env(pay(alice, domainOwner, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(alice, domainOwner, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); // domain owner can send - env(pay(domainOwner, alice, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(domainOwner, alice, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); } } @@ -578,27 +474,20 @@ class PermissionedDEX_test : public beast::unit_test::suite // test domain cross currency payment consuming one offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // create a regular offer without domain auto const regularOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, regularOfferSeq, XRP(10), USD(10))); + BEAST_EXPECT(checkOffer(env, bob, regularOfferSeq, XRP(10), USD(10))); - auto const regularDirKey = - getDefaultOfferDirKey(env, bob, regularOfferSeq); + auto const regularDirKey = getDefaultOfferDirKey(env, bob, regularOfferSeq); BEAST_EXPECT(regularDirKey); BEAST_EXPECT(checkDirectorySize(env, *regularDirKey, 1)); // a domain payment cannot consume regular offers - env(pay(alice, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); // create a domain offer @@ -606,24 +495,18 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, domainOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, domainOfferSeq, XRP(10), USD(10), 0, true)); - auto const domainDirKey = - getDefaultOfferDirKey(env, bob, domainOfferSeq); + auto const domainDirKey = getDefaultOfferDirKey(env, bob, domainOfferSeq); BEAST_EXPECT(domainDirKey); BEAST_EXPECT(checkDirectorySize(env, *domainDirKey, 1)); // cross-currency permissioned payment consumed // domain offer instead of regular offer - env(pay(alice, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(alice, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); BEAST_EXPECT(!offerExists(env, bob, domainOfferSeq)); - BEAST_EXPECT( - checkOffer(env, bob, regularOfferSeq, XRP(10), USD(10))); + BEAST_EXPECT(checkOffer(env, bob, regularOfferSeq, XRP(10), USD(10))); // domain directory is empty BEAST_EXPECT(checkDirectorySize(env, *domainDirKey, 0)); @@ -633,8 +516,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // test domain payment consuming two offers in the path { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const EUR = gw["EUR"]; env.trust(EUR(1000), alice); @@ -651,75 +533,53 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); // payment fail because there isn't eur offer - env(pay(alice, carol, EUR(10)), - path(~USD, ~EUR), - sendmax(XRP(10)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, EUR(10)), path(~USD, ~EUR), sendmax(XRP(10)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); // bob creates a regular USD/EUR offer auto const regularOfferSeq{env.seq(bob)}; env(offer(bob, USD(10), EUR(10))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, regularOfferSeq, USD(10), EUR(10))); + BEAST_EXPECT(checkOffer(env, bob, regularOfferSeq, USD(10), EUR(10))); // alice tries to pay again, but still fails because the regular // offer cannot be consumed - env(pay(alice, carol, EUR(10)), - path(~USD, ~EUR), - sendmax(XRP(10)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, EUR(10)), path(~USD, ~EUR), sendmax(XRP(10)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); // bob creates a domain USD/EUR offer auto const eurOfferSeq{env.seq(bob)}; env(offer(bob, USD(10), EUR(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, eurOfferSeq, USD(10), EUR(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(10), EUR(10), 0, true)); // alice successfully consume two domain offers: xrp/usd and usd/eur - env(pay(alice, carol, EUR(5)), - sendmax(XRP(5)), - domain(domainID), - path(~USD, ~EUR)); + env(pay(alice, carol, EUR(5)), sendmax(XRP(5)), domain(domainID), path(~USD, ~EUR)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, true)); - BEAST_EXPECT( - checkOffer(env, bob, eurOfferSeq, USD(5), EUR(5), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(5), EUR(5), 0, true)); // alice successfully consume two domain offers and deletes them // we compute path this time using `paths` - env(pay(alice, carol, EUR(5)), - sendmax(XRP(5)), - domain(domainID), - paths(XRP)); + env(pay(alice, carol, EUR(5)), sendmax(XRP(5)), domain(domainID), paths(XRP)); env.close(); BEAST_EXPECT(!offerExists(env, bob, usdOfferSeq)); BEAST_EXPECT(!offerExists(env, bob, eurOfferSeq)); // regular offer is not consumed - BEAST_EXPECT( - checkOffer(env, bob, regularOfferSeq, USD(10), EUR(10))); + BEAST_EXPECT(checkOffer(env, bob, regularOfferSeq, USD(10), EUR(10))); } // domain payment cannot consume offer from another domain { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // Fund devin and create USD trustline Account badDomainOwner("badDomainOwner"); @@ -747,25 +607,17 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // domain payment can't consume an offer from another domain - env(pay(alice, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); // bob creates an offer under the right domain auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); // domain payment now consumes from the right domain - env(pay(alice, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(alice, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); BEAST_EXPECT(!offerExists(env, bob, bobOfferSeq)); @@ -776,8 +628,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); @@ -802,8 +653,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // offer becomes unfunded when offer owner's cred expires { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // create devin account who is not part of the domain Account devin("devin"); @@ -815,10 +665,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); auto jv = credentials::create(devin, domainOwner, credType); - uint32_t const t = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count(); + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count(); jv[sfExpiration.jsonName] = t + 20; env(jv); @@ -831,61 +678,41 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // devin's offer can still be consumed while his cred isn't expired - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, devin, offerSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, devin, offerSeq, XRP(5), USD(5), 0, true)); // advance time env.close(std::chrono::seconds(20)); // devin's offer is unfunded now due to expired cred - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT( - checkOffer(env, devin, offerSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, devin, offerSeq, XRP(5), USD(5), 0, true)); } // offer becomes unfunded when offer owner's cred is removed { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const offerSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); // bob's offer can still be consumed while his cred exists - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, offerSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, offerSeq, XRP(5), USD(5), 0, true)); // remove bob's cred - env(credentials::deleteCred( - domainOwner, bob, domainOwner, credType)); + env(credentials::deleteCred(domainOwner, bob, domainOwner, credType)); env.close(); // bob's offer is unfunded now due to expired cred - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, offerSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, offerSeq, XRP(5), USD(5), 0, true)); } } @@ -898,8 +725,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // payment. If the domain wishes to control who is allowed to ripple // through, they should set the rippling individually Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const EURA = alice["EUR"]; auto const EURB = bob["EUR"]; @@ -923,10 +749,7 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); // payment no longer works because carol has no ripple on bob - env(pay(alice, carol, EURB(5)), - paths(EURA), - domain(domainID), - ter(tecPATH_DRY)); + env(pay(alice, carol, EURB(5)), paths(EURA), domain(domainID), ter(tecPATH_DRY)); env.close(); env.require(balance(bob, EURA(10)), balance(carol, EURB(10))); } @@ -939,8 +762,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // whether the issuer is in the domain should NOT affect whether an // offer can be consumed in domain payment Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // create an xrp/usd offer with usd as takergets auto const bobOffer1Seq{env.seq(bob)}; @@ -952,10 +774,8 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, USD(10), XRP(10)), domain(domainID), txflags(tfPassive)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOffer1Seq, XRP(10), USD(10), 0, true)); - BEAST_EXPECT(checkOffer( - env, bob, bobOffer2Seq, USD(10), XRP(10), lsfPassive, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOffer1Seq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOffer2Seq, USD(10), XRP(10), lsfPassive, true)); // remove gateway from domain env(credentials::deleteCred(domainOwner, gw, domainOwner, credType)); @@ -963,19 +783,13 @@ class PermissionedDEX_test : public beast::unit_test::suite // payment succeeds even if issuer is not in domain // xrp/usd offer is consumed - env(pay(alice, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(alice, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); BEAST_EXPECT(!offerExists(env, bob, bobOffer1Seq)); // payment succeeds even if issuer is not in domain // usd/xrp offer is consumed - env(pay(alice, carol, XRP(10)), - path(~XRP), - sendmax(USD(10)), - domain(domainID)); + env(pay(alice, carol, XRP(10)), path(~XRP), sendmax(USD(10)), domain(domainID)); env.close(); BEAST_EXPECT(!offerExists(env, bob, bobOffer2Seq)); } @@ -985,11 +799,10 @@ class PermissionedDEX_test : public beast::unit_test::suite { testcase("Remove unfunded offer"); - // checking that an unfunded offer will be implictly removed by a - // successfuly payment tx + // checking that an unfunded offer will be implicitly removed by a + // successful payment tx Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const aliceOfferSeq{env.seq(alice)}; env(offer(alice, XRP(100), USD(100)), domain(domainID)); @@ -999,10 +812,8 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(20), USD(20)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(20), USD(20), 0, true)); - BEAST_EXPECT( - checkOffer(env, alice, aliceOfferSeq, XRP(100), USD(100), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(20), USD(20), 0, true)); + BEAST_EXPECT(checkOffer(env, alice, aliceOfferSeq, XRP(100), USD(100), 0, true)); auto const domainDirKey = getDefaultOfferDirKey(env, bob, bobOfferSeq); BEAST_EXPECT(domainDirKey); @@ -1012,14 +823,10 @@ class PermissionedDEX_test : public beast::unit_test::suite env(credentials::deleteCred(domainOwner, alice, domainOwner, credType)); env.close(); - env(pay(gw, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(gw, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); // alice's unfunded offer is removed implicitly BEAST_EXPECT(!offerExists(env, alice, aliceOfferSeq)); @@ -1032,16 +839,11 @@ class PermissionedDEX_test : public beast::unit_test::suite testcase("AMM not used"); Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); AMM amm(env, alice, XRP(10), USD(50)); // a domain payment isn't able to consume AMM - env(pay(bob, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(bob, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); // a non domain payment can use AMM @@ -1061,53 +863,38 @@ class PermissionedDEX_test : public beast::unit_test::suite // test preflight - invalid hybrid flag { Env env(*this, features - featurePermissionedDEX); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); - env(offer(bob, XRP(10), USD(10)), - domain(domainID), - txflags(tfHybrid), - ter(temDISABLED)); + env(offer(bob, XRP(10), USD(10)), domain(domainID), txflags(tfHybrid), ter(temDISABLED)); env.close(); - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - ter(temINVALID_FLAG)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), ter(temINVALID_FLAG)); env.close(); env.enableFeature(featurePermissionedDEX); env.close(); // hybrid offer must have domainID - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - ter(temINVALID_FLAG)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), ter(temINVALID_FLAG)); env.close(); // hybrid offer must have domainID auto const offerSeq{env.seq(bob)}; - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, offerSeq, XRP(10), USD(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, offerSeq, XRP(10), USD(10), lsfHybrid, true)); } // apply - domain offer can cross with hybrid { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const bobOfferSeq{env.seq(bob)}; - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); BEAST_EXPECT(offerExists(env, bob, bobOfferSeq)); BEAST_EXPECT(ownerCount(env, bob) == 3); @@ -1123,19 +910,15 @@ class PermissionedDEX_test : public beast::unit_test::suite // apply - open offer can cross with hybrid { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const bobOfferSeq{env.seq(bob)}; - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); BEAST_EXPECT(offerExists(env, bob, bobOfferSeq)); BEAST_EXPECT(ownerCount(env, bob) == 3); - BEAST_EXPECT(checkOffer( - env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); auto const aliceOfferSeq{env.seq(alice)}; env(offer(alice, USD(10), XRP(10))); @@ -1150,22 +933,18 @@ class PermissionedDEX_test : public beast::unit_test::suite // domain book { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, true)); BEAST_EXPECT(ownerCount(env, bob) == 3); // hybrid offer auto crosses with domain offer auto const aliceOfferSeq{env.seq(alice)}; - env(offer(alice, USD(10), XRP(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(alice, USD(10), XRP(10)), domain(domainID), txflags(tfHybrid)); env.close(); BEAST_EXPECT(!offerExists(env, alice, aliceOfferSeq)); @@ -1177,30 +956,24 @@ class PermissionedDEX_test : public beast::unit_test::suite // because by default, it only tries to cross domain offers { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const bobOfferSeq{env.seq(bob)}; env(offer(bob, XRP(10), USD(10))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, false)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, false)); BEAST_EXPECT(ownerCount(env, bob) == 3); // hybrid offer auto crosses with domain offer auto const aliceOfferSeq{env.seq(alice)}; - env(offer(alice, USD(10), XRP(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(alice, USD(10), XRP(10)), domain(domainID), txflags(tfHybrid)); env.close(); BEAST_EXPECT(offerExists(env, alice, aliceOfferSeq)); BEAST_EXPECT(offerExists(env, bob, bobOfferSeq)); - BEAST_EXPECT( - checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, false)); - BEAST_EXPECT(checkOffer( - env, alice, aliceOfferSeq, USD(10), XRP(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), 0, false)); + BEAST_EXPECT(checkOffer(env, alice, aliceOfferSeq, USD(10), XRP(10), lsfHybrid, true)); BEAST_EXPECT(ownerCount(env, alice) == 3); } } @@ -1214,8 +987,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // in this case, the hybrid offer will be considered as unfunded even in // a regular payment Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const hybridOfferSeq{env.seq(bob)}; env(offer(bob, XRP(50), USD(50)), txflags(tfHybrid), domain(domainID)); @@ -1227,24 +999,15 @@ class PermissionedDEX_test : public beast::unit_test::suite // bob's hybrid offer is unfunded and can not be consumed in a domain // payment - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, hybridOfferSeq, XRP(50), USD(50), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, hybridOfferSeq, XRP(50), USD(50), lsfHybrid, true)); // bob's unfunded hybrid offer can't be consumed even with a regular // payment - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, hybridOfferSeq, XRP(50), USD(50), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, hybridOfferSeq, XRP(50), USD(50), lsfHybrid, true)); // create a regular offer auto const regularOfferSeq{env.seq(bob)}; @@ -1253,12 +1016,9 @@ class PermissionedDEX_test : public beast::unit_test::suite BEAST_EXPECT(offerExists(env, bob, regularOfferSeq)); BEAST_EXPECT(checkOffer(env, bob, regularOfferSeq, XRP(10), USD(10))); - auto const sleHybridOffer = - env.le(keylet::offer(bob.id(), hybridOfferSeq)); + auto const sleHybridOffer = env.le(keylet::offer(bob.id(), hybridOfferSeq)); BEAST_EXPECT(sleHybridOffer); - auto const openDir = - sleHybridOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256( - sfBookDirectory); + auto const openDir = sleHybridOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory); BEAST_EXPECT(checkDirectorySize(env, openDir, 2)); // this normal payment should consume the regular offer and remove the @@ -1279,22 +1039,15 @@ class PermissionedDEX_test : public beast::unit_test::suite // both non domain and domain payments can consume hybrid offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const hybridOfferSeq{env.seq(bob)}; - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, hybridOfferSeq, XRP(5), USD(5), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, hybridOfferSeq, XRP(5), USD(5), lsfHybrid, true)); // hybrid offer can't be consumed since bob is not in domain anymore env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5))); @@ -1307,8 +1060,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // wrong domainID { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); // Fund accounts Account badDomainOwner("badDomainOwner"); @@ -1329,28 +1081,17 @@ class PermissionedDEX_test : public beast::unit_test::suite env.close(); auto const hybridOfferSeq{env.seq(bob)}; - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); // other domains can't consume the offer - env(pay(devin, badDomainOwner, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(badDomainID), - ter(tecPATH_DRY)); + env(pay(devin, badDomainOwner, USD(5)), path(~USD), sendmax(XRP(5)), domain(badDomainID), ter(tecPATH_DRY)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, hybridOfferSeq, XRP(10), USD(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, hybridOfferSeq, XRP(10), USD(10), lsfHybrid, true)); - env(pay(alice, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID)); + env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, hybridOfferSeq, XRP(5), USD(5), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, hybridOfferSeq, XRP(5), USD(5), lsfHybrid, true)); // hybrid offer can't be consumed since bob is not in domain anymore env(pay(alice, carol, USD(5)), path(~USD), sendmax(XRP(5))); @@ -1362,8 +1103,7 @@ class PermissionedDEX_test : public beast::unit_test::suite // test domain payment consuming two offers w/ hybrid offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const EUR = gw["EUR"]; env.trust(EUR(1000), alice); @@ -1379,46 +1119,31 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); // payment fail because there isn't eur offer - env(pay(alice, carol, EUR(5)), - path(~USD, ~EUR), - sendmax(XRP(5)), - domain(domainID), - ter(tecPATH_PARTIAL)); + env(pay(alice, carol, EUR(5)), path(~USD, ~EUR), sendmax(XRP(5)), domain(domainID), ter(tecPATH_PARTIAL)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, true)); // bob creates a hybrid eur offer auto const eurOfferSeq{env.seq(bob)}; - env(offer(bob, USD(10), EUR(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(bob, USD(10), EUR(10)), domain(domainID), txflags(tfHybrid)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, eurOfferSeq, USD(10), EUR(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(10), EUR(10), lsfHybrid, true)); // alice successfully consume two domain offers: xrp/usd and usd/eur - env(pay(alice, carol, EUR(5)), - path(~USD, ~EUR), - sendmax(XRP(5)), - domain(domainID)); + env(pay(alice, carol, EUR(5)), path(~USD, ~EUR), sendmax(XRP(5)), domain(domainID)); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, true)); - BEAST_EXPECT(checkOffer( - env, bob, eurOfferSeq, USD(5), EUR(5), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, true)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(5), EUR(5), lsfHybrid, true)); } // test regular payment using a regular offer and a hybrid offer { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const EUR = gw["EUR"]; env.trust(EUR(1000), alice); @@ -1435,26 +1160,20 @@ class PermissionedDEX_test : public beast::unit_test::suite env(offer(bob, XRP(10), USD(10))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, false)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(10), USD(10), 0, false)); // bob creates a hybrid eur offer auto const eurOfferSeq{env.seq(bob)}; - env(offer(bob, USD(10), EUR(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(bob, USD(10), EUR(10)), domain(domainID), txflags(tfHybrid)); env.close(); - BEAST_EXPECT(checkOffer( - env, bob, eurOfferSeq, USD(10), EUR(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(10), EUR(10), lsfHybrid, true)); // alice successfully consume two offers: xrp/usd and usd/eur env(pay(alice, carol, EUR(5)), path(~USD, ~EUR), sendmax(XRP(5))); env.close(); - BEAST_EXPECT( - checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, false)); - BEAST_EXPECT(checkOffer( - env, bob, eurOfferSeq, USD(5), EUR(5), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, usdOfferSeq, XRP(5), USD(5), 0, false)); + BEAST_EXPECT(checkOffer(env, bob, eurOfferSeq, USD(5), EUR(5), lsfHybrid, true)); } } @@ -1462,8 +1181,7 @@ class PermissionedDEX_test : public beast::unit_test::suite testHybridOfferDirectories(FeatureBitset features) { Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); std::vector offerSeqs; offerSeqs.reserve(100); @@ -1480,22 +1198,16 @@ class PermissionedDEX_test : public beast::unit_test::suite { auto const bobOfferSeq{env.seq(bob)}; offerSeqs.emplace_back(bobOfferSeq); - env(offer(bob, XRP(10), USD(10)), - txflags(tfHybrid), - domain(domainID)); + env(offer(bob, XRP(10), USD(10)), txflags(tfHybrid), domain(domainID)); env.close(); auto const sleOffer = env.le(keylet::offer(bob.id(), bobOfferSeq)); BEAST_EXPECT(sleOffer); BEAST_EXPECT(sleOffer->getFieldH256(sfBookDirectory) == domainDir); - BEAST_EXPECT( - sleOffer->getFieldArray(sfAdditionalBooks).size() == 1); - BEAST_EXPECT( - sleOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256( - sfBookDirectory) == openDir); + BEAST_EXPECT(sleOffer->getFieldArray(sfAdditionalBooks).size() == 1); + BEAST_EXPECT(sleOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory) == openDir); - BEAST_EXPECT(checkOffer( - env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); + BEAST_EXPECT(checkOffer(env, bob, bobOfferSeq, XRP(10), USD(10), lsfHybrid, true)); BEAST_EXPECT(checkDirectorySize(env, domainDir, i)); BEAST_EXPECT(checkDirectorySize(env, openDir, i)); } @@ -1517,8 +1229,7 @@ class PermissionedDEX_test : public beast::unit_test::suite testcase("Auto bridge"); Env env(*this, features); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - PermissionedDEX(env); + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = PermissionedDEX(env); auto const EUR = gw["EUR"]; for (auto const& account : {alice, bob, carol}) @@ -1553,7 +1264,7 @@ public: { FeatureBitset const all{jtx::testable_amendments()}; - // Test domain offer (w/o hyrbid) + // Test domain offer (w/o hybrid) testOfferCreate(all); testPayment(all); testBookStep(all); @@ -1571,7 +1282,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(PermissionedDEX, app, ripple); +BEAST_DEFINE_TESTSUITE(PermissionedDEX, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/PermissionedDomains_test.cpp b/src/test/app/PermissionedDomains_test.cpp index b177261e37..8485202144 100644 --- a/src/test/app/PermissionedDomains_test.cpp +++ b/src/test/app/PermissionedDomains_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { using namespace jtx; @@ -52,19 +33,22 @@ exceptionExpected(Env& env, Json::Value const& jv) class PermissionedDomains_test : public beast::unit_test::suite { - FeatureBitset withoutFeature_{ - testable_amendments() - featurePermissionedDomains}; + FeatureBitset withoutFeature_{testable_amendments() - featurePermissionedDomains}; FeatureBitset withFeature_{ testable_amendments() // | featurePermissionedDomains | featureCredentials}; + FeatureBitset withFix_{ + testable_amendments() // + | featurePermissionedDomains | featureCredentials}; + // Verify that each tx type can execute if the feature is enabled. void - testEnabled() + testEnabled(FeatureBitset features) { testcase("Enabled"); Account const alice("alice"); - Env env(*this, withFeature_); + Env env(*this, features); env.fund(XRP(1000), alice); pdomain::Credentials credentials{{alice, "first credential"}}; env(pdomain::setTx(alice, credentials)); @@ -108,10 +92,7 @@ class PermissionedDomains_test : public beast::unit_test::suite // Verify that bad inputs fail for each of create new and update // behaviors of PermissionedDomainSet void - testBadData( - Account const& account, - Env& env, - std::optional domain = std::nullopt) + testBadData(Account const& account, Env& env, std::optional domain = std::nullopt) { Account const alice2("alice2"); Account const alice3("alice3"); @@ -127,8 +108,7 @@ class PermissionedDomains_test : public beast::unit_test::suite auto const setFee(drops(env.current()->fees().increment)); // Test empty credentials. - env(pdomain::setTx(account, pdomain::Credentials(), domain), - ter(temARRAY_EMPTY)); + env(pdomain::setTx(account, pdomain::Credentials(), domain), ter(temARRAY_EMPTY)); // Test 11 credentials. pdomain::Credentials const credentials11{ @@ -143,11 +123,8 @@ class PermissionedDomains_test : public beast::unit_test::suite {alice10, "credential9"}, {alice11, "credential10"}, {alice12, "credential11"}}; - BEAST_EXPECT( - credentials11.size() == - maxPermissionedDomainCredentialsArraySize + 1); - env(pdomain::setTx(account, credentials11, domain), - ter(temARRAY_TOO_LARGE)); + BEAST_EXPECT(credentials11.size() == maxPermissionedDomainCredentialsArraySize + 1); + env(pdomain::setTx(account, credentials11, domain), ter(temARRAY_TOO_LARGE)); // Test credentials including non-existent issuer. Account const nobody("nobody"); @@ -162,9 +139,7 @@ class PermissionedDomains_test : public beast::unit_test::suite env(pdomain::setTx(account, credentialsNon, domain), ter(tecNO_ISSUER)); // Test bad fee - env(pdomain::setTx(account, credentials11, domain), - fee(1, true), - ter(temBAD_FEE)); + env(pdomain::setTx(account, credentials11, domain), fee(1, true), ter(temBAD_FEE)); pdomain::Credentials const credentials4{ {alice2, "credential1"}, @@ -176,15 +151,12 @@ class PermissionedDomains_test : public beast::unit_test::suite auto const credentialOrig = txJsonMutable["AcceptedCredentials"][2u]; // Remove Issuer from a credential and apply. - txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember( - jss::Issuer); - BEAST_EXPECT( - exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); + txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember(jss::Issuer); + BEAST_EXPECT(exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); // Make an empty CredentialType. txJsonMutable["AcceptedCredentials"][2u] = credentialOrig; - txJsonMutable["AcceptedCredentials"][2u][jss::Credential] - ["CredentialType"] = ""; + txJsonMutable["AcceptedCredentials"][2u][jss::Credential]["CredentialType"] = ""; env(txJsonMutable, ter(temMALFORMED)); // Make too long CredentialType. @@ -192,22 +164,16 @@ class PermissionedDomains_test : public beast::unit_test::suite "Cred0123456789012345678901234567890123456789012345678901234567890"; static_assert(longCredentialType.size() == maxCredentialTypeLength + 1); txJsonMutable["AcceptedCredentials"][2u] = credentialOrig; - txJsonMutable["AcceptedCredentials"][2u][jss::Credential] - ["CredentialType"] = std::string(longCredentialType); - BEAST_EXPECT( - exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); + txJsonMutable["AcceptedCredentials"][2u][jss::Credential]["CredentialType"] = std::string(longCredentialType); + BEAST_EXPECT(exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); // Remove Credentialtype from a credential and apply. - txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember( - "CredentialType"); - BEAST_EXPECT( - exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); + txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember("CredentialType"); + BEAST_EXPECT(exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); // Remove both - txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember( - jss::Issuer); - BEAST_EXPECT( - exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); + txJsonMutable["AcceptedCredentials"][2u][jss::Credential].removeMember(jss::Issuer); + BEAST_EXPECT(exceptionExpected(env, txJsonMutable).starts_with("invalidParams")); // Make 2 identical credentials. Duplicates are not supported by // permissioned domains, so transactions should return errors @@ -226,8 +192,7 @@ class PermissionedDomains_test : public beast::unit_test::suite auto const sorted = pdomain::sortCredentials(credentialsDup); BEAST_EXPECT(sorted.size() == 4); - env(pdomain::setTx(account, credentialsDup, domain), - ter(temMALFORMED)); + env(pdomain::setTx(account, credentialsDup, domain), ter(temMALFORMED)); env.close(); env(pdomain::setTx(account, sorted, domain)); @@ -239,8 +204,7 @@ class PermissionedDomains_test : public beast::unit_test::suite d = pdomain::getNewDomain(env.meta()); env.close(); auto objects = pdomain::getObjects(account, env); - auto const fromObject = - pdomain::credentialsFromJson(objects[d], human2Acc); + auto const fromObject = pdomain::credentialsFromJson(objects[d], human2Acc); auto const sortedCreds = pdomain::sortCredentials(credentialsDup); BEAST_EXPECT(fromObject == sortedCreds); } @@ -259,8 +223,7 @@ class PermissionedDomains_test : public beast::unit_test::suite for (auto const& c : credentialsSame) human2Acc.emplace(c.issuer.human(), c.issuer); - BEAST_EXPECT( - credentialsSame != pdomain::sortCredentials(credentialsSame)); + BEAST_EXPECT(credentialsSame != pdomain::sortCredentials(credentialsSame)); env(pdomain::setTx(account, credentialsSame, domain)); uint256 d; @@ -270,8 +233,7 @@ class PermissionedDomains_test : public beast::unit_test::suite d = pdomain::getNewDomain(env.meta()); env.close(); auto objects = pdomain::getObjects(account, env); - auto const fromObject = - pdomain::credentialsFromJson(objects[d], human2Acc); + auto const fromObject = pdomain::credentialsFromJson(objects[d], human2Acc); auto const sortedCreds = pdomain::sortCredentials(credentialsSame); BEAST_EXPECT(fromObject == sortedCreds); } @@ -279,10 +241,10 @@ class PermissionedDomains_test : public beast::unit_test::suite // Test PermissionedDomainSet void - testSet() + testSet(FeatureBitset features) { testcase("Set"); - Env env(*this, withFeature_); + Env env(*this, features); env.set_parse_failure_expected(true); int const accNum = 12; @@ -321,9 +283,7 @@ class PermissionedDomains_test : public beast::unit_test::suite BEAST_EXPECT(object["LedgerEntryType"] == "PermissionedDomain"); BEAST_EXPECT(object["Owner"] == alice[0].human()); BEAST_EXPECT(object["Sequence"] == tx["Sequence"]); - BEAST_EXPECT( - pdomain::credentialsFromJson(object, human2Acc) == - credentials1); + BEAST_EXPECT(pdomain::credentialsFromJson(object, human2Acc) == credentials1); } // Make longest possible CredentialType. @@ -332,8 +292,7 @@ class PermissionedDomains_test : public beast::unit_test::suite "Cred0123456789012345678901234567890123456789012345678901234567" "89"; static_assert(longCredentialType.size() == maxCredentialTypeLength); - pdomain::Credentials const longCredentials{ - {alice[1], std::string(longCredentialType)}}; + pdomain::Credentials const longCredentials{{alice[1], std::string(longCredentialType)}}; env(pdomain::setTx(alice[0], longCredentials)); @@ -345,19 +304,15 @@ class PermissionedDomains_test : public beast::unit_test::suite BEAST_EXPECT(tx["Account"] == alice[0].human()); bool findSeq = false; - for (auto const& [domain, object] : - pdomain::getObjects(alice[0], env)) + for (auto const& [domain, object] : pdomain::getObjects(alice[0], env)) { findSeq = object["Sequence"] == tx["Sequence"]; if (findSeq) { BEAST_EXPECT(domain.isNonZero()); - BEAST_EXPECT( - object["LedgerEntryType"] == "PermissionedDomain"); + BEAST_EXPECT(object["LedgerEntryType"] == "PermissionedDomain"); BEAST_EXPECT(object["Owner"] == alice[0].human()); - BEAST_EXPECT( - pdomain::credentialsFromJson(object, human2Acc) == - longCredentials); + BEAST_EXPECT(pdomain::credentialsFromJson(object, human2Acc) == longCredentials); break; } } @@ -380,52 +335,39 @@ class PermissionedDomains_test : public beast::unit_test::suite }; uint256 domain2; { - BEAST_EXPECT( - credentials10.size() == - maxPermissionedDomainCredentialsArraySize); - BEAST_EXPECT( - credentials10 != pdomain::sortCredentials(credentials10)); + BEAST_EXPECT(credentials10.size() == maxPermissionedDomainCredentialsArraySize); + BEAST_EXPECT(credentials10 != pdomain::sortCredentials(credentials10)); env(pdomain::setTx(alice[0], credentials10)); auto tx = env.tx()->getJson(JsonOptions::none); domain2 = pdomain::getNewDomain(env.meta()); auto objects = pdomain::getObjects(alice[0], env); auto object = objects[domain2]; - BEAST_EXPECT( - pdomain::credentialsFromJson(object, human2Acc) == - pdomain::sortCredentials(credentials10)); + BEAST_EXPECT(pdomain::credentialsFromJson(object, human2Acc) == pdomain::sortCredentials(credentials10)); } // Update with 1 credential. env(pdomain::setTx(alice[0], credentials1, domain2)); BEAST_EXPECT( - pdomain::credentialsFromJson( - pdomain::getObjects(alice[0], env)[domain2], human2Acc) == - credentials1); + pdomain::credentialsFromJson(pdomain::getObjects(alice[0], env)[domain2], human2Acc) == credentials1); // Update with 10 credentials. env(pdomain::setTx(alice[0], credentials10, domain2)); env.close(); BEAST_EXPECT( - pdomain::credentialsFromJson( - pdomain::getObjects(alice[0], env)[domain2], human2Acc) == + pdomain::credentialsFromJson(pdomain::getObjects(alice[0], env)[domain2], human2Acc) == pdomain::sortCredentials(credentials10)); // Update from the wrong owner. - env(pdomain::setTx(alice[2], credentials1, domain2), - ter(tecNO_PERMISSION)); + env(pdomain::setTx(alice[2], credentials1, domain2), ter(tecNO_PERMISSION)); // Update a uint256(0) domain - env(pdomain::setTx(alice[0], credentials1, uint256(0)), - ter(temMALFORMED)); + env(pdomain::setTx(alice[0], credentials1, uint256(0)), ter(temMALFORMED)); // Update non-existent domain - env(pdomain::setTx(alice[0], credentials1, uint256(75)), - ter(tecNO_ENTRY)); + env(pdomain::setTx(alice[0], credentials1, uint256(75)), ter(tecNO_ENTRY)); // Wrong flag - env(pdomain::setTx(alice[0], credentials1), - txflags(tfClawTwoAssets), - ter(temINVALID_FLAG)); + env(pdomain::setTx(alice[0], credentials1), txflags(tfClawTwoAssets), ter(temINVALID_FLAG)); // Test bad data when creating a domain. testBadData(alice[0], env); @@ -440,9 +382,7 @@ class PermissionedDomains_test : public beast::unit_test::suite std::size_t ownerSeq = env.seq(alice[0]); while (deleteDelta + ownerSeq > env.current()->seq()) env.close(); - env(acctdelete(alice[0], alice[2]), - fee(acctDelFee), - ter(tecHAS_OBLIGATIONS)); + env(acctdelete(alice[0], alice[2]), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); } { @@ -459,10 +399,10 @@ class PermissionedDomains_test : public beast::unit_test::suite // Test PermissionedDomainDelete void - testDelete() + testDelete(FeatureBitset features) { testcase("Delete"); - Env env(*this, withFeature_); + Env env(*this, features); Account const alice("alice"); env.fund(XRP(1000), alice); @@ -485,14 +425,10 @@ class PermissionedDomains_test : public beast::unit_test::suite env(pdomain::deleteTx(alice, uint256(75)), ter(tecNO_ENTRY)); // Test bad fee - env(pdomain::deleteTx(alice, uint256(75)), - ter(temBAD_FEE), - fee(1, true)); + env(pdomain::deleteTx(alice, uint256(75)), ter(temBAD_FEE), fee(1, true)); // Wrong flag - env(pdomain::deleteTx(alice, domain), - ter(temINVALID_FLAG), - txflags(tfClawTwoAssets)); + env(pdomain::deleteTx(alice, domain), ter(temINVALID_FLAG), txflags(tfClawTwoAssets)); // Delete a zero domain. env(pdomain::deleteTx(alice, uint256(0)), ter(temMALFORMED)); @@ -516,14 +452,14 @@ class PermissionedDomains_test : public beast::unit_test::suite } void - testAccountReserve() + testAccountReserve(FeatureBitset features) { // Verify that the reserve behaves as expected for creating. testcase("Account Reserve"); using namespace test::jtx; - Env env(*this, withFeature_); + Env env(*this, features); Account const alice("alice"); // Fund alice enough to exist, but not enough to meet @@ -546,9 +482,7 @@ class PermissionedDomains_test : public beast::unit_test::suite // Pay alice almost enough to make the reserve. env(pay(env.master, alice, incReserve + drops(2 * baseFee) - drops(1))); - BEAST_EXPECT( - env.balance(alice) == - acctReserve + incReserve + drops(baseFee) - drops(1)); + BEAST_EXPECT(env.balance(alice) == acctReserve + incReserve + drops(baseFee) - drops(1)); env.close(); // alice still does not have enough XRP for the reserve. @@ -570,16 +504,20 @@ public: void run() override { - testEnabled(); + testEnabled(withFeature_); + testEnabled(withFix_); testCredentialsDisabled(); testDisabled(); - testSet(); - testDelete(); - testAccountReserve(); + testSet(withFeature_); + testSet(withFix_); + testDelete(withFeature_); + testDelete(withFix_); + testAccountReserve(withFeature_); + testAccountReserve(withFix_); } }; -BEAST_DEFINE_TESTSUITE(PermissionedDomains, app, ripple); +BEAST_DEFINE_TESTSUITE(PermissionedDomains, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/PseudoTx_test.cpp b/src/test/app/PseudoTx_test.cpp index 53adf795c2..29e13888c3 100644 --- a/src/test/app/PseudoTx_test.cpp +++ b/src/test/app/PseudoTx_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct PseudoTx_test : public beast::unit_test::suite @@ -66,8 +49,7 @@ struct PseudoTx_test : public beast::unit_test::suite { std::vector res; - res.emplace_back(STTx( - ttACCOUNT_SET, [&](auto& obj) { obj[sfAccount] = AccountID(1); })); + res.emplace_back(STTx(ttACCOUNT_SET, [&](auto& obj) { obj[sfAccount] = AccountID(1); })); res.emplace_back(STTx(ttPAYMENT, [&](auto& obj) { obj.setAccountID(sfAccount, AccountID(2)); @@ -83,20 +65,17 @@ struct PseudoTx_test : public beast::unit_test::suite using namespace jtx; Env env(*this, features); - for (auto const& stx : - getPseudoTxs(env.closed()->rules(), env.closed()->seq() + 1)) + for (auto const& stx : getPseudoTxs(env.closed()->rules(), env.closed()->seq() + 1)) { std::string reason; BEAST_EXPECT(isPseudoTx(stx)); BEAST_EXPECT(!passesLocalChecks(stx, reason)); BEAST_EXPECT(reason == "Cannot submit pseudo transactions."); - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - auto const result = - ripple::apply(env.app(), view, stx, tapNONE, j); - BEAST_EXPECT(!result.applied && result.ter == temINVALID); - return result.applied; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + auto const result = xrpl::apply(env.app(), view, stx, tapNONE, j); + BEAST_EXPECT(!result.applied && result.ter == temINVALID); + return result.applied; + }); } } @@ -124,7 +103,7 @@ struct PseudoTx_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PseudoTx, app, ripple); +BEAST_DEFINE_TESTSUITE(PseudoTx, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/RCLValidations_test.cpp b/src/test/app/RCLValidations_test.cpp index fce4e94048..495176104b 100644 --- a/src/test/app/RCLValidations_test.cpp +++ b/src/test/app/RCLValidations_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class RCLValidations_test : public beast::unit_test::suite @@ -36,11 +17,9 @@ class RCLValidations_test : public beast::unit_test::suite testcase("Change validation trusted status"); auto keys = randomKeyPair(KeyType::secp256k1); auto v = std::make_shared( - ripple::NetClock::time_point{}, - keys.first, - keys.second, - calcNodeID(keys.first), - [&](STValidation& v) { v.setFieldU32(sfLedgerSequence, 123456); }); + xrpl::NetClock::time_point{}, keys.first, keys.second, calcNodeID(keys.first), [&](STValidation& v) { + v.setFieldU32(sfLedgerSequence, 123456); + }); BEAST_EXPECT(v->isTrusted()); v->setUntrusted(); @@ -75,16 +54,12 @@ class RCLValidations_test : public beast::unit_test::suite jtx::Env env(*this); Config config; - auto prev = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); + auto prev = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); history.push_back(prev); for (auto i = 0; i < (2 * maxAncestors + 1); ++i) { - auto next = std::make_shared( - *prev, env.app().timeKeeper().closeTime()); + auto next = std::make_shared(*prev, env.app().timeKeeper().closeTime()); next->updateSkipList(); history.push_back(next); prev = next; @@ -92,8 +67,7 @@ class RCLValidations_test : public beast::unit_test::suite // altHistory agrees with first half of regular history Seq const diverge = history.size() / 2; - std::vector> altHistory( - history.begin(), history.begin() + diverge); + std::vector> altHistory(history.begin(), history.begin() + diverge); // advance clock to get new ledgers using namespace std::chrono_literals; env.timeKeeper().set(env.timeKeeper().now() + 1200s); @@ -101,8 +75,7 @@ class RCLValidations_test : public beast::unit_test::suite bool forceHash = true; while (altHistory.size() < history.size()) { - auto next = std::make_shared( - *prev, env.app().timeKeeper().closeTime()); + auto next = std::make_shared(*prev, env.app().timeKeeper().closeTime()); // Force a different hash on the first iteration next->updateSkipList(); BEAST_EXPECT(next->read(keylet::fees())); @@ -130,13 +103,13 @@ class RCLValidations_test : public beast::unit_test::suite { std::shared_ptr ledger = history.back(); RCLValidatedLedger a{ledger, env.journal}; - BEAST_EXPECT(a.seq() == ledger->info().seq); + BEAST_EXPECT(a.seq() == ledger->header().seq); BEAST_EXPECT(a.minSeq() == a.seq() - maxAncestors); // Ensure the ancestral 256 ledgers have proper ID for (Seq s = a.seq(); s > 0; s--) { if (s >= a.minSeq()) - BEAST_EXPECT(a[s] == history[s - 1]->info().hash); + BEAST_EXPECT(a[s] == history[s - 1]->header().hash); else BEAST_EXPECT(a[s] == ID{0}); } @@ -238,16 +211,12 @@ class RCLValidations_test : public beast::unit_test::suite jtx::Env env(*this); auto& j = env.journal; Config config; - auto prev = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); + auto prev = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); history.push_back(prev); for (auto i = 0; i < (maxAncestors + 10); ++i) { - auto next = std::make_shared( - *prev, env.app().timeKeeper().closeTime()); + auto next = std::make_shared(*prev, env.app().timeKeeper().closeTime()); next->updateSkipList(); history.push_back(next); prev = next; @@ -273,7 +242,7 @@ class RCLValidations_test : public beast::unit_test::suite BEAST_EXPECT(trie.branchSupport(ledg_258) == 4); // Move three of the s258 ledgers to s259, which splits the trie - // due to the 256 ancestory limit + // due to the 256 ancestry limit BEAST_EXPECT(trie.remove(ledg_258, 3)); trie.insert(ledg_259, 3); trie.getPreferred(1); @@ -294,12 +263,11 @@ class RCLValidations_test : public beast::unit_test::suite // then verify the remove call works // past bug: remove had assumed the first child of a node in the trie // which matches is the *only* child in the trie which matches. - // This is **NOT** true with the limited 256 ledger ancestory + // This is **NOT** true with the limited 256 ledger ancestry // quirk of RCLValidation and prevents deleting the old support // for ledger 257 - BEAST_EXPECT( - trie.remove(RCLValidatedLedger{history[257], env.journal}, 1)); + BEAST_EXPECT(trie.remove(RCLValidatedLedger{history[257], env.journal}, 1)); trie.insert(RCLValidatedLedger{history[258], env.journal}, 1); trie.getPreferred(1); // trie.dump(std::cout); @@ -327,7 +295,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RCLValidations, app, ripple); +BEAST_DEFINE_TESTSUITE(RCLValidations, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/ReducedOffer_test.cpp b/src/test/app/ReducedOffer_test.cpp index c991daef85..b967096eb8 100644 --- a/src/test/app/ReducedOffer_test.cpp +++ b/src/test/app/ReducedOffer_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,42 +6,30 @@ #include -namespace ripple { +namespace xrpl { namespace test { class ReducedOffer_test : public beast::unit_test::suite { static auto - ledgerEntryOffer( - jtx::Env& env, - jtx::Account const& acct, - std::uint32_t offer_seq) + ledgerEntryOffer(jtx::Env& env, jtx::Account const& acct, std::uint32_t offer_seq) { Json::Value jvParams; jvParams[jss::offer][jss::account] = acct.human(); jvParams[jss::offer][jss::seq] = offer_seq; - return env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; } static bool - offerInLedger( - jtx::Env& env, - jtx::Account const& acct, - std::uint32_t offerSeq) + offerInLedger(jtx::Env& env, jtx::Account const& acct, std::uint32_t offerSeq) { Json::Value ledgerOffer = ledgerEntryOffer(env, acct, offerSeq); - return !( - ledgerOffer.isMember(jss::error) && - ledgerOffer[jss::error].asString() == "entryNotFound"); + return !(ledgerOffer.isMember(jss::error) && ledgerOffer[jss::error].asString() == "entryNotFound"); } // Common code to clean up unneeded offers. static void - cleanupOldOffers( - jtx::Env& env, - std::initializer_list> - list) + cleanupOldOffers(jtx::Env& env, std::initializer_list> list) { for (auto [acct, offerSeq] : list) env(offer_cancel(acct, offerSeq)); @@ -99,10 +68,8 @@ public: // 2. Collects the results, and // 3. Cleans up for the next offer pair. // Returns 1 if the crossed offer has a bad rate for the book. - auto exerciseOfferPair = - [this, &env, &alice, &bob]( - Amounts const& inLedger, - Amounts const& newOffer) -> unsigned int { + auto exerciseOfferPair = [this, &env, &alice, &bob]( + Amounts const& inLedger, Amounts const& newOffer) -> unsigned int { // Put inLedger offer in the ledger so newOffer can cross it. std::uint32_t const aliceOfferSeq = env.seq(alice); env(offer(alice, inLedger.in, inLedger.out)); @@ -112,9 +79,8 @@ public: STAmount const initialRate = Quality(newOffer).rate(); std::uint32_t const bobOfferSeq = env.seq(bob); STAmount const bobInitialBalance = env.balance(bob); - STAmount const bobsFee = env.current()->fees().base; - env(offer(bob, newOffer.in, newOffer.out, tfSell), - fee(bobsFee)); + STAmount const bobFee = env.current()->fees().base; + env(offer(bob, newOffer.in, newOffer.out, tfSell), fee(bobFee)); env.close(); STAmount const bobFinalBalance = env.balance(bob); @@ -128,20 +94,16 @@ public: // bob's offer should be in the ledger, but reduced in size. unsigned int badRate = 1; { - Json::Value bobOffer = - ledgerEntryOffer(env, bob, bobOfferSeq); + Json::Value bobOffer = ledgerEntryOffer(env, bob, bobOfferSeq); - STAmount const reducedTakerGets = amountFromJson( - sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]); - STAmount const reducedTakerPays = amountFromJson( - sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]); - STAmount const bobGot = - env.balance(bob) + bobsFee - bobInitialBalance; + STAmount const reducedTakerGets = + amountFromJson(sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]); + STAmount const reducedTakerPays = + amountFromJson(sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]); + STAmount const bobGot = env.balance(bob) + bobFee - bobInitialBalance; BEAST_EXPECT(reducedTakerPays < newOffer.in); BEAST_EXPECT(reducedTakerGets < newOffer.out); - STAmount const inLedgerRate = - Quality(Amounts{reducedTakerPays, reducedTakerGets}) - .rate(); + STAmount const inLedgerRate = Quality(Amounts{reducedTakerPays, reducedTakerGets}).rate(); badRate = inLedgerRate > initialRate ? 1 : 0; @@ -152,11 +114,8 @@ public: // was computed. if (badRate == 0) { - STAmount const tweakedTakerPays = - reducedTakerPays + drops(1); - STAmount const tweakedRate = - Quality(Amounts{tweakedTakerPays, reducedTakerGets}) - .rate(); + STAmount const tweakedTakerPays = reducedTakerPays + drops(1); + STAmount const tweakedRate = Quality(Amounts{tweakedTakerPays, reducedTakerGets}).rate(); BEAST_EXPECT(tweakedRate > initialRate); } #if 0 @@ -177,31 +136,25 @@ public: // In preparation for the next iteration make sure the two // offers are gone from the ledger. - cleanupOldOffers( - env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return badRate; }; // bob's offer (the new offer) is the same every time: - Amounts const bobsOffer{ - STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)}; + Amounts const bobOffer{STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)}; // alice's offer has a slightly smaller TakerPays with each // iteration. This should mean that the size of the offer bob // places in the ledger should increase with each iteration. unsigned int blockedCount = 0; - for (std::uint64_t mantissaReduce = 1'000'000'000ull; - mantissaReduce <= 5'000'000'000ull; + for (std::uint64_t mantissaReduce = 1'000'000'000ull; mantissaReduce <= 5'000'000'000ull; mantissaReduce += 20'000'000ull) { STAmount aliceUSD{ - bobsOffer.out.issue(), - bobsOffer.out.mantissa() - mantissaReduce, - bobsOffer.out.exponent()}; - STAmount aliceXRP{ - bobsOffer.in.issue(), bobsOffer.in.mantissa() - 1}; - Amounts alicesOffer{aliceUSD, aliceXRP}; - blockedCount += exerciseOfferPair(alicesOffer, bobsOffer); + bobOffer.out.issue(), bobOffer.out.mantissa() - mantissaReduce, bobOffer.out.exponent()}; + STAmount aliceXRP{bobOffer.in.issue(), bobOffer.in.mantissa() - 1}; + Amounts aliceOffer{aliceUSD, aliceXRP}; + blockedCount += exerciseOfferPair(aliceOffer, bobOffer); } // None of the test cases should produce a potentially blocking @@ -239,10 +192,8 @@ public: // 1. Exercises one offer pair, // 2. Collects the results, and // 3. Cleans up for the next offer pair. - auto exerciseOfferPair = - [this, &env, &alice, &bob]( - Amounts const& inLedger, - Amounts const& newOffer) -> unsigned int { + auto exerciseOfferPair = [this, &env, &alice, &bob]( + Amounts const& inLedger, Amounts const& newOffer) -> unsigned int { // Get the inLedger offer into the ledger so newOffer can cross // it. STAmount const initialRate = Quality(inLedger).rate(); @@ -262,30 +213,23 @@ public: { // If the in-ledger offer was not consumed then further // results are meaningless. - cleanupOldOffers( - env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return 1; } // alice's offer should still be in the ledger, but reduced in // size. unsigned int badRate = 1; { - Json::Value aliceOffer = - ledgerEntryOffer(env, alice, aliceOfferSeq); + Json::Value aliceOffer = ledgerEntryOffer(env, alice, aliceOfferSeq); - STAmount const reducedTakerGets = amountFromJson( - sfTakerGets, - aliceOffer[jss::node][sfTakerGets.jsonName]); - STAmount const reducedTakerPays = amountFromJson( - sfTakerPays, - aliceOffer[jss::node][sfTakerPays.jsonName]); - STAmount const aliceGot = - env.balance(alice) - aliceInitialBalance; + STAmount const reducedTakerGets = + amountFromJson(sfTakerGets, aliceOffer[jss::node][sfTakerGets.jsonName]); + STAmount const reducedTakerPays = + amountFromJson(sfTakerPays, aliceOffer[jss::node][sfTakerPays.jsonName]); + STAmount const aliceGot = env.balance(alice) - aliceInitialBalance; BEAST_EXPECT(reducedTakerPays < inLedger.in); BEAST_EXPECT(reducedTakerGets < inLedger.out); - STAmount const inLedgerRate = - Quality(Amounts{reducedTakerPays, reducedTakerGets}) - .rate(); + STAmount const inLedgerRate = Quality(Amounts{reducedTakerPays, reducedTakerGets}).rate(); badRate = inLedgerRate > initialRate ? 1 : 0; // If the inLedgerRate is less than initial rate, then @@ -295,11 +239,8 @@ public: // was computed. if (badRate == 0) { - STAmount const tweakedTakerPays = - reducedTakerPays + drops(1); - STAmount const tweakedRate = - Quality(Amounts{tweakedTakerPays, reducedTakerGets}) - .rate(); + STAmount const tweakedTakerPays = reducedTakerPays + drops(1); + STAmount const tweakedRate = Quality(Amounts{tweakedTakerPays, reducedTakerGets}).rate(); BEAST_EXPECT(tweakedRate > initialRate); } #if 0 @@ -321,32 +262,26 @@ public: // In preparation for the next iteration make sure the two // offers are gone from the ledger. - cleanupOldOffers( - env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return badRate; }; // alice's offer (the old offer) is the same every time: - Amounts const aliceOffer{ - STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)}; + Amounts const aliceOffer{STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)}; // bob's offer has a slightly smaller TakerPays with each iteration. // This should mean that the size of the offer alice leaves in the // ledger should increase with each iteration. unsigned int blockedCount = 0; - for (std::uint64_t mantissaReduce = 1'000'000'000ull; - mantissaReduce <= 4'000'000'000ull; + for (std::uint64_t mantissaReduce = 1'000'000'000ull; mantissaReduce <= 4'000'000'000ull; mantissaReduce += 20'000'000ull) { STAmount bobUSD{ - aliceOffer.out.issue(), - aliceOffer.out.mantissa() - mantissaReduce, - aliceOffer.out.exponent()}; - STAmount bobXRP{ - aliceOffer.in.issue(), aliceOffer.in.mantissa() - 1}; - Amounts bobsOffer{bobUSD, bobXRP}; + aliceOffer.out.issue(), aliceOffer.out.mantissa() - mantissaReduce, aliceOffer.out.exponent()}; + STAmount bobXRP{aliceOffer.in.issue(), aliceOffer.in.mantissa() - 1}; + Amounts bobOffer{bobUSD, bobXRP}; - blockedCount += exerciseOfferPair(aliceOffer, bobsOffer); + blockedCount += exerciseOfferPair(aliceOffer, bobOffer); } // None of the test cases should produce a potentially blocking @@ -376,8 +311,7 @@ public: env.trust(USD(1000), alice, bob); int blockedOrderBookCount = 0; - for (STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1); - initialBobUSD += USD(0.025)) + for (STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1); initialBobUSD += USD(0.025)) { // underfund bob's offer env(pay(gw, bob, initialBobUSD)); @@ -399,8 +333,7 @@ public: // then we use that as evidence that bob's offer blocked the // order book. { - bool const bobsOfferGone = - !offerInLedger(env, bob, bobOfferSeq); + bool const bobOfferGone = !offerInLedger(env, bob, bobOfferSeq); STAmount const aliceBalanceUSD = env.balance(alice, USD); // Sanity check the ledger if alice got USD. @@ -408,27 +341,24 @@ public: { BEAST_EXPECT(aliceBalanceUSD == initialBobUSD); BEAST_EXPECT(env.balance(bob, USD) == USD(0)); - BEAST_EXPECT(bobsOfferGone); + BEAST_EXPECT(bobOfferGone); } // Track occurrences of order book blocking. - if (!bobsOfferGone && aliceBalanceUSD.signum() == 0) + if (!bobOfferGone && aliceBalanceUSD.signum() == 0) { ++blockedOrderBookCount; } // In preparation for the next iteration clean up any // leftover offers. - cleanupOldOffers( - env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); // Zero out alice's and bob's USD balances. - if (STAmount const aliceBalance = env.balance(alice, USD); - aliceBalance.signum() > 0) + if (STAmount const aliceBalance = env.balance(alice, USD); aliceBalance.signum() > 0) env(pay(alice, gw, aliceBalance)); - if (STAmount const bobBalance = env.balance(bob, USD); - bobBalance.signum() > 0) + if (STAmount const bobBalance = env.balance(bob, USD); bobBalance.signum() > 0) env(pay(bob, gw, bobBalance)); env.close(); @@ -467,17 +397,13 @@ public: env.trust(USD(1000), alice, bob); env.trust(EUR(1000), alice, bob); - STAmount const eurOffer( - EUR.issue(), /*mantissa*/ 2957, /*exponent*/ -76); - STAmount const usdOffer( - USD.issue(), /*mantissa*/ 7109, /*exponent*/ -76); + STAmount const eurOffer(EUR.issue(), /*mantissa*/ 2957, /*exponent*/ -76); + STAmount const usdOffer(USD.issue(), /*mantissa*/ 7109, /*exponent*/ -76); - STAmount const endLoop( - USD.issue(), /*mantissa*/ 50, /*exponent*/ -81); + STAmount const endLoop(USD.issue(), /*mantissa*/ 50, /*exponent*/ -81); int blockedOrderBookCount = 0; - for (STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop; - initialBobUSD += tinyUSD) + for (STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop; initialBobUSD += tinyUSD) { // underfund bob's offer env(pay(gw, bob, initialBobUSD)); @@ -497,14 +423,13 @@ public: // Examine the aftermath of alice's offer. { - bool const bobsOfferGone = - !offerInLedger(env, bob, bobOfferSeq); + bool const bobOfferGone = !offerInLedger(env, bob, bobOfferSeq); STAmount aliceBalanceUSD = env.balance(alice, USD); #if 0 std::cout - << "bobs initial: " << initialBobUSD + << "bob initial: " << initialBobUSD << "; alice final: " << aliceBalanceUSD - << "; bobs offer: " << bobsOfferJson.toStyledString() + << "; bob offer: " << bobOfferJson.toStyledString() << std::endl; #endif // Sanity check the ledger if alice got USD. @@ -512,11 +437,11 @@ public: { BEAST_EXPECT(aliceBalanceUSD == initialBobUSD); BEAST_EXPECT(env.balance(bob, USD) == USD(0)); - BEAST_EXPECT(bobsOfferGone); + BEAST_EXPECT(bobOfferGone); } // Track occurrences of order book blocking. - if (!bobsOfferGone && aliceBalanceUSD.signum() == 0) + if (!bobOfferGone && aliceBalanceUSD.signum() == 0) { ++blockedOrderBookCount; } @@ -524,14 +449,11 @@ public: // In preparation for the next iteration clean up any // leftover offers. - cleanupOldOffers( - env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); // Zero out alice's and bob's IOU balances. - auto zeroBalance = [&env, &gw]( - Account const& acct, IOU const& iou) { - if (STAmount const balance = env.balance(acct, iou); - balance.signum() > 0) + auto zeroBalance = [&env, &gw](Account const& acct, IOU const& iou) { + if (STAmount const balance = env.balance(acct, iou); balance.signum() > 0) env(pay(acct, gw, balance)); }; @@ -551,10 +473,8 @@ public: Amounts jsonOfferToAmounts(Json::Value const& json) { - STAmount const in = - amountFromJson(sfTakerPays, json[sfTakerPays.jsonName]); - STAmount const out = - amountFromJson(sfTakerGets, json[sfTakerGets.jsonName]); + STAmount const in = amountFromJson(sfTakerPays, json[sfTakerPays.jsonName]); + STAmount const out = amountFromJson(sfTakerGets, json[sfTakerGets.jsonName]); return {in, out}; } @@ -577,8 +497,7 @@ public: // Make one test run without fixReducedOffersV2 and one with. for (FeatureBitset features : - {testable_amendments() - fixReducedOffersV2, - testable_amendments() | fixReducedOffersV2}) + {testable_amendments() - fixReducedOffersV2, testable_amendments() | fixReducedOffersV2}) { // Make sure none of the offers we generate are under funded. Env env{*this, features}; @@ -600,17 +519,14 @@ public: // 2. Collects the results, and // 3. Cleans up for the next offer trio. auto exerciseOfferTrio = - [this, &env, &alice, &bob, &carol, &USD]( - Amounts const& carolOffer) -> unsigned int { + [this, &env, &alice, &bob, &carol, &USD](Amounts const& carolOffer) -> unsigned int { // alice submits an offer that may become a blocker. std::uint32_t const aliceOfferSeq = env.seq(alice); static Amounts const aliceInitialOffer(USD(2), drops(3382562)); env(offer(alice, aliceInitialOffer.in, aliceInitialOffer.out)); env.close(); STAmount const initialRate = - Quality(jsonOfferToAmounts(ledgerEntryOffer( - env, alice, aliceOfferSeq)[jss::node])) - .rate(); + Quality(jsonOfferToAmounts(ledgerEntryOffer(env, alice, aliceOfferSeq)[jss::node])).rate(); // bob submits an offer that is more desirable than alice's std::uint32_t const bobOfferSeq = env.seq(bob); @@ -620,39 +536,29 @@ public: // Now carol's offer consumes bob's and partially crosses // alice's. The tfSell flag is important. std::uint32_t const carolOfferSeq = env.seq(carol); - env(offer(carol, carolOffer.in, carolOffer.out), - txflags(tfSell)); + env(offer(carol, carolOffer.in, carolOffer.out), txflags(tfSell)); env.close(); // carol's offer should not have made it into the ledger and // bob's offer should be fully consumed. - if (!BEAST_EXPECT( - !offerInLedger(env, carol, carolOfferSeq) && - !offerInLedger(env, bob, bobOfferSeq))) + if (!BEAST_EXPECT(!offerInLedger(env, carol, carolOfferSeq) && !offerInLedger(env, bob, bobOfferSeq))) { // If carol's or bob's offers are still in the ledger then // further results are meaningless. - cleanupOldOffers( - env, - {{alice, aliceOfferSeq}, - {bob, bobOfferSeq}, - {carol, carolOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}}); return 1; } // alice's offer should still be in the ledger, but reduced in // size. unsigned int badRate = 1; { - Json::Value aliceOffer = - ledgerEntryOffer(env, alice, aliceOfferSeq); + Json::Value aliceOffer = ledgerEntryOffer(env, alice, aliceOfferSeq); - Amounts aliceReducedOffer = - jsonOfferToAmounts(aliceOffer[jss::node]); + Amounts aliceReducedOffer = jsonOfferToAmounts(aliceOffer[jss::node]); BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in); BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out); - STAmount const inLedgerRate = - Quality(aliceReducedOffer).rate(); + STAmount const inLedgerRate = Quality(aliceReducedOffer).rate(); badRate = inLedgerRate > initialRate ? 1 : 0; // If the inLedgerRate is less than initial rate, then @@ -667,10 +573,7 @@ public: aliceReducedOffer.in.mantissa() + 1, aliceReducedOffer.in.exponent(), aliceReducedOffer.in.negative()); - STAmount const tweakedRate = - Quality( - Amounts{aliceReducedOffer.in, tweakedTakerGets}) - .rate(); + STAmount const tweakedRate = Quality(Amounts{aliceReducedOffer.in, tweakedTakerGets}).rate(); BEAST_EXPECT(tweakedRate > initialRate); } #if 0 @@ -690,11 +593,7 @@ public: // In preparation for the next iteration make sure all three // offers are gone from the ledger. - cleanupOldOffers( - env, - {{alice, aliceOfferSeq}, - {bob, bobOfferSeq}, - {carol, carolOfferSeq}}); + cleanupOldOffers(env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}, {carol, carolOfferSeq}}); return badRate; }; @@ -705,8 +604,7 @@ public: STAmount const step(increaseGets.issue(), 1, -8); for (unsigned int i = 0; i < loopCount; ++i) { - blockedCount += exerciseOfferTrio( - Amounts(drops(1642020), USD(1) + increaseGets)); + blockedCount += exerciseOfferTrio(Amounts(drops(1642020), USD(1) + increaseGets)); increaseGets += step; } } @@ -738,7 +636,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(ReducedOffer, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(ReducedOffer, app, xrpl, 2); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Regression_test.cpp b/src/test/app/Regression_test.cpp index 16c2c25f7c..052b334ef5 100644 --- a/src/test/app/Regression_test.cpp +++ b/src/test/app/Regression_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct Regression_test : public beast::unit_test::suite @@ -62,32 +45,27 @@ struct Regression_test : public beast::unit_test::suite // be reproduced against an open ledger. Make a local // closed ledger and work with it directly. auto closed = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); auto expectedDrops = INITIAL_XRP; - BEAST_EXPECT(closed->info().drops == expectedDrops); + BEAST_EXPECT(closed->header().drops == expectedDrops); auto const aliceXRP = 400; auto const aliceAmount = XRP(aliceXRP); - auto next = std::make_shared( - *closed, env.app().timeKeeper().closeTime()); + auto next = std::make_shared(*closed, env.app().timeKeeper().closeTime()); { // Fund alice auto const jt = env.jt(pay(env.master, "alice", aliceAmount)); OpenView accum(&*next); - auto const result = - ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal); + auto const result = xrpl::apply(env.app(), accum, *jt.stx, tapNONE, env.journal); BEAST_EXPECT(result.ter == tesSUCCESS); BEAST_EXPECT(result.applied); accum.apply(*next); } expectedDrops -= next->fees().base; - BEAST_EXPECT(next->info().drops == expectedDrops); + BEAST_EXPECT(next->header().drops == expectedDrops); { auto const sle = next->read(keylet::account(Account("alice").id())); BEAST_EXPECT(sle); @@ -103,8 +81,7 @@ struct Regression_test : public beast::unit_test::suite OpenView accum(&*next); - auto const result = - ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal); + auto const result = xrpl::apply(env.app(), accum, *jt.stx, tapNONE, env.journal); BEAST_EXPECT(result.ter == tecINSUFF_FEE); BEAST_EXPECT(result.applied); @@ -118,7 +95,7 @@ struct Regression_test : public beast::unit_test::suite BEAST_EXPECT(balance == XRP(0)); } expectedDrops -= aliceXRP * dropsPerXRP; - BEAST_EXPECT(next->info().drops == expectedDrops); + BEAST_EXPECT(next->header().drops == expectedDrops); } void @@ -132,8 +109,7 @@ struct Regression_test : public beast::unit_test::suite auto test256r1key = [&env](Account const& acct) { auto const baseFee = env.current()->fees().base; std::uint32_t const acctSeq = env.seq(acct); - Json::Value jsonNoop = - env.json(noop(acct), fee(baseFee), seq(acctSeq), sig(acct)); + Json::Value jsonNoop = env.json(noop(acct), fee(baseFee), seq(acctSeq), sig(acct)); JTx jt = env.jt(jsonNoop); jt.fill_sig = false; @@ -154,9 +130,7 @@ struct Regression_test : public beast::unit_test::suite secp256r1Sig->setFieldVL(sfSigningPubKey, *pubKeyBlob); jt.stx.reset(secp256r1Sig.release()); - env(jt, - rpc("invalidTransaction", - "fails local checks: Invalid signature.")); + env(jt, rpc("invalidTransaction", "fails local checks: Invalid signature.")); }; Account const alice{"alice", KeyType::secp256k1}; @@ -174,8 +148,7 @@ struct Regression_test : public beast::unit_test::suite testcase("Autofilled fee should use the escalated fee"); using namespace jtx; Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->section("transaction_queue") - .set("minimum_txn_in_ledger_standalone", "3"); + cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3"); cfg->FEES.reference_fee = 10; return cfg; })); @@ -247,10 +220,8 @@ struct Regression_test : public beast::unit_test::suite std::vector buffers; buffers.emplace_back(buffer(request, 1024)); - buffers.emplace_back( - buffer(request.data() + 1024, request.length() - 1024)); - BEAST_EXPECT( - jrReader.parse(jvRequest, buffers) && jvRequest.isObject()); + buffers.emplace_back(buffer(request.data() + 1024, request.length() - 1024)); + BEAST_EXPECT(jrReader.parse(jvRequest, buffers) && jvRequest.isObject()); } void @@ -271,9 +242,7 @@ struct Regression_test : public beast::unit_test::suite auto const alice_index = keylet::account(alice).key; if (BEAST_EXPECT(alice_index.isNonZero())) { - env(check::cash( - alice, alice_index, check::DeliverMin(XRP(100))), - ter(tecNO_ENTRY)); + env(check::cash(alice, alice_index, check::DeliverMin(XRP(100))), ter(tecNO_ENTRY)); } } @@ -281,8 +250,7 @@ struct Regression_test : public beast::unit_test::suite auto const bob_index = keylet::account(bob).key; auto const digest = [&]() -> std::optional { - auto const& state = - env.app().getLedgerMaster().getClosedLedger()->stateMap(); + auto const& state = env.app().getLedgerMaster().getClosedLedger()->stateMap(); SHAMapHash digest; if (!state.peekItem(bob_index, digest)) return std::nullopt; @@ -299,30 +267,21 @@ struct Regression_test : public beast::unit_test::suite return result; }; - if (BEAST_EXPECT(bob_index.isNonZero()) && - BEAST_EXPECT(digest.has_value())) + if (BEAST_EXPECT(bob_index.isNonZero()) && BEAST_EXPECT(digest.has_value())) { auto& cache = env.app().cachedSLEs(); cache.del(*digest, false); - auto const beforeCounts = - mapCounts(CountedObjects::getInstance().getCounts(0)); + auto const beforeCounts = mapCounts(CountedObjects::getInstance().getCounts(0)); - env(check::cash(alice, bob_index, check::DeliverMin(XRP(100))), - ter(tecNO_ENTRY)); + env(check::cash(alice, bob_index, check::DeliverMin(XRP(100))), ter(tecNO_ENTRY)); - auto const afterCounts = - mapCounts(CountedObjects::getInstance().getCounts(0)); + auto const afterCounts = mapCounts(CountedObjects::getInstance().getCounts(0)); using namespace std::string_literals; + BEAST_EXPECT(beforeCounts.at("CachedView::hit"s) == afterCounts.at("CachedView::hit"s)); BEAST_EXPECT( - beforeCounts.at("CachedView::hit"s) == - afterCounts.at("CachedView::hit"s)); - BEAST_EXPECT( - beforeCounts.at("CachedView::hitExpired"s) + 1 == - afterCounts.at("CachedView::hitExpired"s)); - BEAST_EXPECT( - beforeCounts.at("CachedView::miss"s) == - afterCounts.at("CachedView::miss"s)); + beforeCounts.at("CachedView::hitExpired"s) + 1 == afterCounts.at("CachedView::hitExpired"s)); + BEAST_EXPECT(beforeCounts.at("CachedView::miss"s) == afterCounts.at("CachedView::miss"s)); } } } @@ -340,7 +299,7 @@ struct Regression_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Regression, app, ripple); +BEAST_DEFINE_TESTSUITE(Regression, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/SHAMapStore_test.cpp b/src/test/app/SHAMapStore_test.cpp index 29fbc8022c..9e0a971685 100644 --- a/src/test/app/SHAMapStore_test.cpp +++ b/src/test/app/SHAMapStore_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class SHAMapStore_test : public beast::unit_test::suite @@ -54,49 +35,37 @@ class SHAMapStore_test : public beast::unit_test::suite } bool - goodLedger( - jtx::Env& env, - Json::Value const& json, - std::string ledgerID, - bool checkDB = false) + goodLedger(jtx::Env& env, Json::Value const& json, std::string ledgerID, bool checkDB = false) { - auto good = json.isMember(jss::result) && - !RPC::contains_error(json[jss::result]) && + auto good = json.isMember(jss::result) && !RPC::contains_error(json[jss::result]) && json[jss::result][jss::ledger][jss::ledger_index] == ledgerID; if (!good || !checkDB) return good; auto const seq = json[jss::result][jss::ledger_index].asUInt(); - std::optional oinfo = - env.app().getRelationalDatabase().getLedgerInfoByIndex(seq); - if (!oinfo) + std::optional outInfo = env.app().getRelationalDatabase().getLedgerInfoByIndex(seq); + if (!outInfo) return false; - LedgerInfo const& info = oinfo.value(); + LedgerHeader const& info = outInfo.value(); std::string const outHash = to_string(info.hash); LedgerIndex const outSeq = info.seq; std::string const outParentHash = to_string(info.parentHash); std::string const outDrops = to_string(info.drops); - std::uint64_t const outCloseTime = - info.closeTime.time_since_epoch().count(); - std::uint64_t const outParentCloseTime = - info.parentCloseTime.time_since_epoch().count(); - std::uint64_t const outCloseTimeResolution = - info.closeTimeResolution.count(); + std::uint64_t const outCloseTime = info.closeTime.time_since_epoch().count(); + std::uint64_t const outParentCloseTime = info.parentCloseTime.time_since_epoch().count(); + std::uint64_t const outCloseTimeResolution = info.closeTimeResolution.count(); std::uint64_t const outCloseFlags = info.closeFlags; std::string const outAccountHash = to_string(info.accountHash); std::string const outTxHash = to_string(info.txHash); auto const& ledger = json[jss::result][jss::ledger]; - return outHash == ledger[jss::ledger_hash].asString() && - outSeq == seq && - outParentHash == ledger[jss::parent_hash].asString() && - outDrops == ledger[jss::total_coins].asString() && + return outHash == ledger[jss::ledger_hash].asString() && outSeq == seq && + outParentHash == ledger[jss::parent_hash].asString() && outDrops == ledger[jss::total_coins].asString() && outCloseTime == ledger[jss::close_time].asUInt() && outParentCloseTime == ledger[jss::parent_close_time].asUInt() && - outCloseTimeResolution == - ledger[jss::close_time_resolution].asUInt() && + outCloseTimeResolution == ledger[jss::close_time_resolution].asUInt() && outCloseFlags == ledger[jss::close_flags].asUInt() && outAccountHash == ledger[jss::account_hash].asString() && outTxHash == ledger[jss::transaction_hash].asString(); @@ -105,8 +74,7 @@ class SHAMapStore_test : public beast::unit_test::suite bool bad(Json::Value const& json, error_code_i error = rpcLGR_NOT_FOUND) { - return json.isMember(jss::result) && - RPC::contains_error(json[jss::result]) && + return json.isMember(jss::result) && RPC::contains_error(json[jss::result]) && json[jss::result][jss::error_code] == error; } @@ -114,8 +82,7 @@ class SHAMapStore_test : public beast::unit_test::suite getHash(Json::Value const& json) { BEAST_EXPECT( - json.isMember(jss::result) && - json[jss::result].isMember(jss::ledger) && + json.isMember(jss::result) && json[jss::result].isMember(jss::ledger) && json[jss::result][jss::ledger].isMember(jss::ledger_hash) && json[jss::result][jss::ledger][jss::ledger_hash].isString()); return json[jss::result][jss::ledger][jss::ledger_hash].asString(); @@ -124,9 +91,7 @@ class SHAMapStore_test : public beast::unit_test::suite void ledgerCheck(jtx::Env& env, int const rows, int const first) { - auto const [actualRows, actualFirst, actualLast] = - dynamic_cast(&env.app().getRelationalDatabase()) - ->getLedgerCountMinMax(); + auto const [actualRows, actualFirst, actualLast] = env.app().getRelationalDatabase().getLedgerCountMinMax(); BEAST_EXPECT(actualRows == rows); BEAST_EXPECT(actualFirst == first); @@ -136,17 +101,13 @@ class SHAMapStore_test : public beast::unit_test::suite void transactionCheck(jtx::Env& env, int const rows) { - BEAST_EXPECT( - dynamic_cast(&env.app().getRelationalDatabase()) - ->getTransactionCount() == rows); + BEAST_EXPECT(env.app().getRelationalDatabase().getTransactionCount() == rows); } void accountTransactionCheck(jtx::Env& env, int const rows) { - BEAST_EXPECT( - dynamic_cast(&env.app().getRelationalDatabase()) - ->getAccountTransactionCount() == rows); + BEAST_EXPECT(env.app().getRelationalDatabase().getAccountTransactionCount() == rows); } int @@ -223,11 +184,8 @@ public: for (auto i = 3; i < deleteInterval + lastRotated; ++i) { - ledgers.emplace( - std::make_pair(i, env.rpc("ledger", std::to_string(i)))); - BEAST_EXPECT( - goodLedger(env, ledgers[i], std::to_string(i), true) && - getHash(ledgers[i]).length()); + ledgers.emplace(std::make_pair(i, env.rpc("ledger", std::to_string(i)))); + BEAST_EXPECT(goodLedger(env, ledgers[i], std::to_string(i), true) && getHash(ledgers[i]).length()); } ledgerCheck(env, deleteInterval + 1, 2); @@ -239,8 +197,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "current"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(deleteInterval + 4))); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(deleteInterval + 4))); } store.rendezvous(); @@ -255,22 +212,16 @@ public: accountTransactionCheck(env, 2 * deleteInterval); // The last iteration of this loop should trigger a rotate - for (auto i = lastRotated - 1; i < lastRotated + deleteInterval - 1; - ++i) + for (auto i = lastRotated - 1; i < lastRotated + deleteInterval - 1; ++i) { env.close(); ledgerTmp = env.rpc("ledger", "current"); BEAST_EXPECT(goodLedger(env, ledgerTmp, std::to_string(i + 3))); - ledgers.emplace( - std::make_pair(i, env.rpc("ledger", std::to_string(i)))); - BEAST_EXPECT( - store.getLastRotated() == lastRotated || - i == lastRotated + deleteInterval - 2); - BEAST_EXPECT( - goodLedger(env, ledgers[i], std::to_string(i), true) && - getHash(ledgers[i]).length()); + ledgers.emplace(std::make_pair(i, env.rpc("ledger", std::to_string(i)))); + BEAST_EXPECT(store.getLastRotated() == lastRotated || i == lastRotated + deleteInterval - 2); + BEAST_EXPECT(goodLedger(env, ledgers[i], std::to_string(i), true) && getHash(ledgers[i]).length()); } store.rendezvous(); @@ -308,8 +259,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -324,8 +274,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); } store.rendezvous(); @@ -341,8 +290,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -381,8 +329,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -391,12 +338,9 @@ public: BEAST_EXPECT(lastRotated == store.getLastRotated()); // This does not kick off a cleanup - canDelete = env.rpc( - "can_delete", std::to_string(ledgerSeq + deleteInterval / 2)); + canDelete = env.rpc("can_delete", std::to_string(ledgerSeq + deleteInterval / 2)); BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result])); - BEAST_EXPECT( - canDelete[jss::result][jss::can_delete] == - ledgerSeq + deleteInterval / 2); + BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == ledgerSeq + deleteInterval / 2); store.rendezvous(); @@ -408,8 +352,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); } store.rendezvous(); @@ -425,8 +368,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -438,8 +380,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); } store.rendezvous(); @@ -452,9 +393,7 @@ public: // This does not kick off a cleanup canDelete = env.rpc("can_delete", "always"); BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result])); - BEAST_EXPECT( - canDelete[jss::result][jss::can_delete] == - std::numeric_limits::max()); + BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == std::numeric_limits::max()); for (; ledgerSeq < lastRotated + deleteInterval; ++ledgerSeq) { @@ -462,8 +401,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -475,8 +413,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); } store.rendezvous(); @@ -497,8 +434,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq), true)); } store.rendezvous(); @@ -510,8 +446,7 @@ public: env.close(); auto ledger = env.rpc("ledger", "validated"); - BEAST_EXPECT( - goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); + BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++), true)); } store.rendezvous(); @@ -523,13 +458,9 @@ public: } std::unique_ptr - makeBackendRotating( - jtx::Env& env, - NodeStoreScheduler& scheduler, - std::string path) + makeBackendRotating(jtx::Env& env, NodeStoreScheduler& scheduler, std::string path) { - Section section{ - env.app().config().section(ConfigSection::nodeDatabase())}; + Section section{env.app().config().section(ConfigSection::nodeDatabase())}; boost::filesystem::path newPath; if (!BEAST_EXPECT(path.size())) @@ -539,8 +470,7 @@ public: auto backend{NodeStore::Manager::instance().make_Backend( section, - megabytes(env.app().config().getValueFor( - SizedItem::burstSize, std::nullopt)), + megabytes(env.app().config().getValueFor(SizedItem::burstSize, std::nullopt)), scheduler, env.app().logs().journal("NodeStoreTest"))}; backend->open(); @@ -558,23 +488,8 @@ public: Env env(*this, envconfig(onlineDelete)); ///////////////////////////////////////////////////////////// - // Create the backend. Normally, SHAMapStoreImp handles all these - // details - auto nscfg = env.app().config().section(ConfigSection::nodeDatabase()); - - // Provide default values: - if (!nscfg.exists("cache_size")) - nscfg.set( - "cache_size", - std::to_string(env.app().config().getValueFor( - SizedItem::treeCacheSize, std::nullopt))); - - if (!nscfg.exists("cache_age")) - nscfg.set( - "cache_age", - std::to_string(env.app().config().getValueFor( - SizedItem::treeCacheAge, std::nullopt))); - + // Create NodeStore with two backends to allow online deletion of data. + // Normally, SHAMapStoreImp handles all these details. NodeStoreScheduler scheduler(env.app().getJobQueue()); std::string const writableDb = "write"; @@ -582,9 +497,8 @@ public: auto writableBackend = makeBackendRotating(env, scheduler, writableDb); auto archiveBackend = makeBackendRotating(env, scheduler, archiveDb); - // Create NodeStore with two backends to allow online deletion of - // data constexpr int readThreads = 4; + auto nscfg = env.app().config().section(ConfigSection::nodeDatabase()); auto dbr = std::make_unique( scheduler, readThreads, @@ -599,11 +513,9 @@ public: std::atomic threadNum = 0; { - auto newBackend = makeBackendRotating( - env, scheduler, std::to_string(++threadNum)); + auto newBackend = makeBackendRotating(env, scheduler, std::to_string(++threadNum)); - auto const cb = [&](std::string const& writableName, - std::string const& archiveName) { + auto const cb = [&](std::string const& writableName, std::string const& archiveName) { BEAST_EXPECT(writableName == "1"); BEAST_EXPECT(archiveName == "write"); // Ensure that dbr functions can be called from within the @@ -619,25 +531,21 @@ public: ///////////////////////////////////////////////////////////// // Do something stupid. Try to re-enter rotate from inside the callback. { - auto const cb = [&](std::string const& writableName, - std::string const& archiveName) { + auto const cb = [&](std::string const& writableName, std::string const& archiveName) { BEAST_EXPECT(writableName == "3"); BEAST_EXPECT(archiveName == "2"); // Ensure that dbr functions can be called from within the // callback BEAST_EXPECT(dbr->getName() == "3"); }; - auto const cbReentrant = [&](std::string const& writableName, - std::string const& archiveName) { + auto const cbReentrant = [&](std::string const& writableName, std::string const& archiveName) { BEAST_EXPECT(writableName == "2"); BEAST_EXPECT(archiveName == "1"); - auto newBackend = makeBackendRotating( - env, scheduler, std::to_string(++threadNum)); + auto newBackend = makeBackendRotating(env, scheduler, std::to_string(++threadNum)); // Reminder: doing this is stupid and should never happen dbr->rotate(std::move(newBackend), cb); }; - auto newBackend = makeBackendRotating( - env, scheduler, std::to_string(++threadNum)); + auto newBackend = makeBackendRotating(env, scheduler, std::to_string(++threadNum)); dbr->rotate(std::move(newBackend), cbReentrant); } @@ -656,7 +564,7 @@ public: }; // VFALCO This test fails because of thread asynchronous issues -BEAST_DEFINE_TESTSUITE(SHAMapStore, app, ripple); +BEAST_DEFINE_TESTSUITE(SHAMapStore, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/SetAuth_test.cpp b/src/test/app/SetAuth_test.cpp index dfa831a72e..400e2b0e29 100644 --- a/src/test/app/SetAuth_test.cpp +++ b/src/test/app/SetAuth_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { struct SetAuth_test : public beast::unit_test::suite @@ -31,16 +12,12 @@ struct SetAuth_test : public beast::unit_test::suite // If the trust line does not exist, then it should // be created under the new rules. static Json::Value - auth( - jtx::Account const& account, - jtx::Account const& dest, - std::string const& currency) + auth(jtx::Account const& account, jtx::Account const& dest, std::string const& currency) { using namespace jtx; Json::Value jv; jv[jss::Account] = account.human(); - jv[jss::LimitAmount] = STAmount(Issue{to_currency(currency), dest}) - .getJson(JsonOptions::none); + jv[jss::LimitAmount] = STAmount(Issue{to_currency(currency), dest}).getJson(JsonOptions::none); jv[jss::TransactionType] = jss::TrustSet; jv[jss::Flags] = tfSetfAuth; return jv; @@ -59,8 +36,7 @@ struct SetAuth_test : public beast::unit_test::suite env(fset(gw, asfRequireAuth)); env.close(); env(auth(gw, "alice", "USD")); - BEAST_EXPECT( - env.le(keylet::line(Account("alice").id(), gw.id(), USD.currency))); + BEAST_EXPECT(env.le(keylet::line(Account("alice").id(), gw.id(), USD.currency))); env(trust("alice", USD(1000))); env(trust("bob", USD(1000))); env(pay(gw, "alice", USD(100))); @@ -80,7 +56,7 @@ struct SetAuth_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SetAuth, app, ripple); +BEAST_DEFINE_TESTSUITE(SetAuth, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/SetRegularKey_test.cpp b/src/test/app/SetRegularKey_test.cpp index 3bceec335c..aec8dddc7a 100644 --- a/src/test/app/SetRegularKey_test.cpp +++ b/src/test/app/SetRegularKey_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class SetRegularKey_test : public beast::unit_test::suite { @@ -47,9 +28,7 @@ public: env(noop(alice), sig(alice), ter(tefMASTER_DISABLED)); testcase("Re-enable master key"); - env(fclear(alice, asfDisableMaster), - sig(alice), - ter(tefMASTER_DISABLED)); + env(fclear(alice, asfDisableMaster), sig(alice), ter(tefMASTER_DISABLED)); env(fclear(alice, asfDisableMaster), sig(bob)); env(noop(alice), sig(bob)); @@ -86,17 +65,13 @@ public: env.fund(XRP(10000), alice, bob); auto ar = env.le(alice); - BEAST_EXPECT( - ar->isFieldPresent(sfFlags) && - ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == 0)); + BEAST_EXPECT(ar->isFieldPresent(sfFlags) && ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == 0)); env(regkey(alice, bob), sig(alice), fee(0)); ar = env.le(alice); BEAST_EXPECT( - ar->isFieldPresent(sfFlags) && - ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == - lsfPasswordSpent)); + ar->isFieldPresent(sfFlags) && ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == lsfPasswordSpent)); // The second SetRegularKey transaction with Fee=0 should fail. env(regkey(alice, bob), sig(alice), fee(0), ter(telINSUF_FEE_P)); @@ -104,9 +79,7 @@ public: env.trust(bob["USD"](1), alice); env(pay(bob, alice, bob["USD"](1))); ar = env.le(alice); - BEAST_EXPECT( - ar->isFieldPresent(sfFlags) && - ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == 0)); + BEAST_EXPECT(ar->isFieldPresent(sfFlags) && ((ar->getFieldU32(sfFlags) & lsfPasswordSpent) == 0)); } void @@ -147,9 +120,7 @@ public: env.close(); // Disable alice's master key using a ticket. - env(fset(alice, asfDisableMaster), - sig(alice), - ticket::use(--ticketSeq)); + env(fset(alice, asfDisableMaster), sig(alice), ticket::use(--ticketSeq)); env.close(); // alice should be able to sign using the regular key but not the @@ -161,9 +132,7 @@ public: BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // Re-enable the master key using a ticket. - env(fclear(alice, asfDisableMaster), - sig(alie), - ticket::use(--ticketSeq)); + env(fclear(alice, asfDisableMaster), sig(alie), ticket::use(--ticketSeq)); env.close(); // Disable the regular key using a ticket. @@ -188,6 +157,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(SetRegularKey, app, ripple); +BEAST_DEFINE_TESTSUITE(SetRegularKey, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/SetTrust_test.cpp index 00ca0aa3a7..4704365550 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/SetTrust_test.cpp @@ -1,41 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class SetTrust_test : public beast::unit_test::suite { - FeatureBitset const disallowIncoming{featureDisallowIncoming}; - public: void testTrustLineDelete() { - testcase( - "Test deletion of trust lines: revert trust line limit to zero"); + testcase("Test deletion of trust lines: revert trust line limit to zero"); using namespace jtx; Env env(*this); @@ -170,10 +148,7 @@ public: } void - testFreeTrustlines( - FeatureBitset features, - bool thirdLineCreatesLE, - bool createOnHighAcct) + testFreeTrustlines(FeatureBitset features, bool thirdLineCreatesLE, bool createOnHighAcct) { if (thirdLineCreatesLE) testcase("Allow two free trustlines"); @@ -209,20 +184,16 @@ public: if (thirdLineCreatesLE) { // creator does not have enough for the third trust line - env(trust(creator, assistor["USD"](100)), - ter(tecNO_LINE_INSUF_RESERVE), - require(lines(creator, 2))); + env(trust(creator, assistor["USD"](100)), ter(tecNO_LINE_INSUF_RESERVE), require(lines(creator, 2))); } else { // First establish opposite trust direction from assistor - env(trust(assistor, creator["USD"](100)), - require(lines(creator, 3))); + env(trust(assistor, creator["USD"](100)), require(lines(creator, 3))); // creator does not have enough to create the other direction on // the existing trust line ledger entry - env(trust(creator, assistor["USD"](100)), - ter(tecINSUF_RESERVE_LINE)); + env(trust(creator, assistor["USD"](100)), ter(tecINSUF_RESERVE_LINE)); } // Fund creator additional amount to cover @@ -230,13 +201,11 @@ public: if (thirdLineCreatesLE) { - env(trust(creator, assistor["USD"](100)), - require(lines(creator, 3))); + env(trust(creator, assistor["USD"](100)), require(lines(creator, 3))); } else { - env(trust(creator, assistor["USD"](100)), - require(lines(creator, 3))); + env(trust(creator, assistor["USD"](100)), require(lines(creator, 3))); Json::Value jv; jv["account"] = creator.human(); @@ -309,32 +278,23 @@ public: env.fund(XRP(10000), gw, alice); // Require valid tf flags - for (std::uint64_t badFlag = 1u; - badFlag <= std::numeric_limits::max(); - badFlag *= 2) + for (std::uint64_t badFlag = 1u; badFlag <= std::numeric_limits::max(); badFlag *= 2) { if (badFlag & tfTrustSetMask) - env(trust( - alice, - gw["USD"](100), - static_cast(badFlag)), - ter(temINVALID_FLAG)); + env(trust(alice, gw["USD"](100), static_cast(badFlag)), ter(temINVALID_FLAG)); } // trust amount can't be XRP env(trust_explicit_amt(alice, drops(10000)), ter(temBAD_LIMIT)); // trust amount can't be badCurrency IOU - env(trust_explicit_amt(alice, gw[to_string(badCurrency())](100)), - ter(temBAD_CURRENCY)); + env(trust_explicit_amt(alice, gw[to_string(badCurrency())](100)), ter(temBAD_CURRENCY)); // trust amount can't be negative env(trust(alice, gw["USD"](-1000)), ter(temBAD_LIMIT)); // trust amount can't be from invalid issuer - env(trust_explicit_amt( - alice, STAmount{Issue{to_currency("USD"), noAccount()}, 100}), - ter(temDST_NEEDED)); + env(trust_explicit_amt(alice, STAmount{Issue{to_currency("USD"), noAccount()}, 100}), ter(temDST_NEEDED)); // trust cannot be to self env(trust(alice, alice["USD"](100)), ter(temDST_IS_SRC)); @@ -438,13 +398,9 @@ public: } void - testModifyQualityOfTrustline( - FeatureBitset features, - bool createQuality, - bool createOnHighAcct) + testModifyQualityOfTrustline(FeatureBitset features, bool createQuality, bool createOnHighAcct) { - testcase << "SetTrust " << (createQuality ? "creates" : "removes") - << " quality of trustline for " + testcase << "SetTrust " << (createQuality ? "creates" : "removes") << " quality of trustline for " << (createOnHighAcct ? "high" : "low") << " account"; using namespace jtx; @@ -476,11 +432,8 @@ public: auto quality = exists ? 1000 : 0; BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 1); - BEAST_EXPECT( - lines[jss::result][jss::lines][0u][jss::quality_in] == quality); - BEAST_EXPECT( - lines[jss::result][jss::lines][0u][jss::quality_out] == - quality); + BEAST_EXPECT(lines[jss::result][jss::lines][0u][jss::quality_in] == quality); + BEAST_EXPECT(lines[jss::result][jss::lines][0u][jss::quality_out] == quality); }; env(tx1, require(lines(toAcct, 1)), require(lines(fromAcct, 1))); @@ -497,25 +450,11 @@ public: using namespace test::jtx; - // test flag doesn't set unless amendment enabled - { - Env env{*this, features - disallowIncoming}; - Account const alice{"alice"}; - env.fund(XRP(10000), alice); - env(fset(alice, asfDisallowIncomingTrustline)); - env.close(); - auto const sle = env.le(alice); - uint32_t flags = sle->getFlags(); - BEAST_EXPECT(!(flags & lsfDisallowIncomingTrustline)); - } - // fixDisallowIncomingV1 { for (bool const withFix : {true, false}) { - auto const amend = withFix - ? features | disallowIncoming - : (features | disallowIncoming) - fixDisallowIncomingV1; + auto const amend = withFix ? features : features - fixDisallowIncomingV1; Env env{*this, amend}; auto const dist = Account("dist"); @@ -537,21 +476,17 @@ public: // withFix: can set trustline // withOutFix: cannot set trustline - auto const trustResult = - withFix ? ter(tesSUCCESS) : ter(tecNO_PERMISSION); - env(trust(gw, distUSD(10000)), - txflags(tfSetfAuth), - trustResult); + auto const trustResult = withFix ? ter(tesSUCCESS) : ter(tecNO_PERMISSION); + env(trust(gw, distUSD(10000)), txflags(tfSetfAuth), trustResult); env.close(); - auto const txResult = - withFix ? ter(tesSUCCESS) : ter(tecPATH_DRY); + auto const txResult = withFix ? ter(tesSUCCESS) : ter(tecPATH_DRY); env(pay(gw, dist, USD(1000)), txResult); env.close(); } } - Env env{*this, features | disallowIncoming}; + Env env{*this, features}; auto const gw = Account{"gateway"}; auto const alice = Account{"alice"}; @@ -649,10 +584,9 @@ public: { using namespace test::jtx; auto const sa = testable_amendments(); - testWithFeats(sa - disallowIncoming); testWithFeats(sa); } }; -BEAST_DEFINE_TESTSUITE(SetTrust, app, ripple); +BEAST_DEFINE_TESTSUITE(SetTrust, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/TheoreticalQuality_test.cpp b/src/test/app/TheoreticalQuality_test.cpp index 814e6f7136..1f626ad477 100644 --- a/src/test/app/TheoreticalQuality_test.cpp +++ b/src/test/app/TheoreticalQuality_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct RippleCalcTestParams @@ -63,27 +44,18 @@ struct RippleCalcTestParams { if (pe.isMember(jss::account)) { - assert( - !pe.isMember(jss::currency) && - !pe.isMember(jss::issuer)); + assert(!pe.isMember(jss::currency) && !pe.isMember(jss::issuer)); p.emplace_back( - *parseBase58( - pe[jss::account].asString()), - std::nullopt, - std::nullopt); + *parseBase58(pe[jss::account].asString()), std::nullopt, std::nullopt); } - else if ( - pe.isMember(jss::currency) && pe.isMember(jss::issuer)) + else if (pe.isMember(jss::currency) && pe.isMember(jss::issuer)) { - auto const currency = - to_currency(pe[jss::currency].asString()); + auto const currency = to_currency(pe[jss::currency].asString()); std::optional issuer; if (!isXRP(currency)) - issuer = *parseBase58( - pe[jss::issuer].asString()); + issuer = *parseBase58(pe[jss::issuer].asString()); else - assert(isXRP(*parseBase58( - pe[jss::issuer].asString()))); + assert(isXRP(*parseBase58(pe[jss::issuer].asString()))); p.emplace_back(std::nullopt, currency, issuer); } else @@ -131,20 +103,14 @@ class RandomAccountParams return; auto const percent = qualityPercentDist_(engine_); - auto const& field = - qDir == QualityDirection::in ? sfQualityIn : sfQualityOut; - auto const value = - static_cast((percent / 100) * QUALITY_ONE); + auto const& field = qDir == QualityDirection::in ? sfQualityIn : sfQualityOut; + auto const value = static_cast((percent / 100) * QUALITY_ONE); jv[field.jsonName] = value; }; // Setup the trust amounts and in/out qualities (but not the balances) void - setupTrustLine( - jtx::Env& env, - jtx::Account const& acc, - jtx::Account const& peer, - Currency const& currency) + setupTrustLine(jtx::Env& env, jtx::Account const& acc, jtx::Account const& peer, Currency const& currency) { using namespace jtx; IOU const iou{peer, currency}; @@ -156,13 +122,9 @@ class RandomAccountParams }; public: - explicit RandomAccountParams( - std::uint32_t trustAmount = 100, - std::uint32_t initialBalance = 50) + explicit RandomAccountParams(std::uint32_t trustAmount = 100, std::uint32_t initialBalance = 50) // Use a deterministic seed so the unit tests run in a reproducible way - : engine_{1977u} - , trustAmount_{trustAmount} - , initialBalance_{initialBalance} {}; + : engine_{1977u}, trustAmount_{trustAmount}, initialBalance_{initialBalance} {}; void maybeSetTransferRate(jtx::Env& env, jtx::Account const& acc) @@ -173,29 +135,19 @@ public: // Set the initial balance, taking into account the qualities void - setInitialBalance( - jtx::Env& env, - jtx::Account const& acc, - jtx::Account const& peer, - Currency const& currency) + setInitialBalance(jtx::Env& env, jtx::Account const& acc, jtx::Account const& peer, Currency const& currency) { using namespace jtx; IOU const iou{acc, currency}; // This payment sets the acc's balance to `initialBalance`. // Since input qualities complicate this payment, use `sendMax` with // `initialBalance` to make sure the balance is set correctly. - env(pay(peer, acc, iou(trustAmount_)), - sendmax(iou(initialBalance_)), - txflags(tfPartialPayment)); + env(pay(peer, acc, iou(trustAmount_)), sendmax(iou(initialBalance_)), txflags(tfPartialPayment)); env.close(); } void - maybeSetInitialBalance( - jtx::Env& env, - jtx::Account const& acc, - jtx::Account const& peer, - Currency const& currency) + maybeSetInitialBalance(jtx::Env& env, jtx::Account const& acc, jtx::Account const& peer, Currency const& currency) { using namespace jtx; if (zeroOneDist_(engine_) > probRedeem_) @@ -206,11 +158,7 @@ public: // Setup the trust amounts and in/out qualities (but not the balances) on // both sides of the trust line void - setupTrustLines( - jtx::Env& env, - jtx::Account const& acc1, - jtx::Account const& acc2, - Currency const& currency) + setupTrustLines(jtx::Env& env, jtx::Account const& acc1, jtx::Account const& acc2, Currency const& currency) { setupTrustLine(env, acc1, acc2, currency); setupTrustLine(env, acc2, acc1, currency); @@ -289,20 +237,18 @@ class TheoreticalQuality_test : public beast::unit_test::suite for (auto const& strand : sr.second) { Quality const theoreticalQ = *qualityUpperBound(sb, strand); - auto const f = flow( - sb, strand, IOUAmount(10, 0), IOUAmount(5, 0), dummyJ); + auto const f = flow(sb, strand, IOUAmount(10, 0), IOUAmount(5, 0), dummyJ); BEAST_EXPECT(f.success); Quality const actualQ(f.out, f.in); if (actualQ != theoreticalQ && !compareClose(actualQ, theoreticalQ)) { BEAST_EXPECT(actualQ == theoreticalQ); // get the failure - log << "\nAcutal != Theoretical\n"; + log << "\nActual != Theoretical\n"; log << "\nTQ: " << prettyQuality(theoreticalQ) << "\n"; log << "AQ: " << prettyQuality(actualQ) << "\n"; logStrand(log, strand); } - if (expectedQ && expectedQ != theoreticalQ && - !compareClose(*expectedQ, theoreticalQ)) + if (expectedQ && expectedQ != theoreticalQ && !compareClose(*expectedQ, theoreticalQ)) { BEAST_EXPECT(expectedQ == theoreticalQ); // get the failure log << "\nExpected != Theoretical\n"; @@ -370,8 +316,7 @@ public: auto const carol = Account("carol" + iterAsStr); auto const dan = Account("dan" + iterAsStr); std::array accounts{{alice, bob, carol, dan}}; - static_assert( - numAccounts == 4, "Path is only correct for four accounts"); + static_assert(numAccounts == 4, "Path is only correct for four accounts"); path const accountsPath(accounts[1], accounts[2]); env.fund(XRP(10000), alice, bob, carol, dan); env.close(); @@ -389,18 +334,14 @@ public: if (j == numAccounts) continue; - rndAccParams.setupTrustLines( - env, accounts[ii], accounts[j], currency); - rndAccParams.maybeSetInitialBalance( - env, accounts[ii], accounts[j], currency); + rndAccParams.setupTrustLines(env, accounts[ii], accounts[j], currency); + rndAccParams.maybeSetInitialBalance(env, accounts[ii], accounts[j], currency); } // Accounts are set up, make the payment IOU const iou{accounts.back(), currency}; RippleCalcTestParams rcp{env.json( - pay(accounts.front(), accounts.back(), iou(paymentAmount)), - accountsPath, - txflags(tfNoRippleDirect))}; + pay(accounts.front(), accounts.back(), iou(paymentAmount)), accountsPath, txflags(tfNoRippleDirect))}; testCase(rcp, env.closed()); } @@ -446,8 +387,7 @@ public: auto const USDB = bob["USD"]; auto const EURC = carol["EUR"]; constexpr std::size_t const numAccounts = 5; - std::array accounts{ - {alice, bob, carol, dan, oscar}}; + std::array accounts{{alice, bob, carol, dan, oscar}}; // sendmax should be in USDB and delivered amount should be in EURC // normalized path should be: @@ -462,14 +402,10 @@ public: for (auto const& currency : {usdCurrency, eurCurrency}) { - rndAccParams.setupTrustLines( - env, alice, bob, currency); // first step in payment - rndAccParams.setupTrustLines( - env, carol, dan, currency); // last step in payment - rndAccParams.setupTrustLines( - env, oscar, bob, currency); // offer owner - rndAccParams.setupTrustLines( - env, oscar, carol, currency); // offer owner + rndAccParams.setupTrustLines(env, alice, bob, currency); // first step in payment + rndAccParams.setupTrustLines(env, carol, dan, currency); // last step in payment + rndAccParams.setupTrustLines(env, oscar, bob, currency); // offer owner + rndAccParams.setupTrustLines(env, oscar, carol, currency); // offer owner } rndAccParams.maybeSetInitialBalance(env, alice, bob, usdCurrency); @@ -498,8 +434,7 @@ public: { testcase("Relative quality distance"); - auto toQuality = [](std::uint64_t mantissa, - int exponent = 0) -> Quality { + auto toQuality = [](std::uint64_t mantissa, int exponent = 0) -> Quality { // The only way to construct a Quality from an STAmount is to take // their ratio. Set the denominator STAmount to `one` to easily // create a quality from a single amount @@ -511,18 +446,14 @@ public: BEAST_EXPECT(relativeDistance(toQuality(100), toQuality(100)) == 0); BEAST_EXPECT(relativeDistance(toQuality(100), toQuality(100, 1)) == 9); BEAST_EXPECT(relativeDistance(toQuality(100), toQuality(110)) == .1); - BEAST_EXPECT( - relativeDistance(toQuality(100, 90), toQuality(110, 90)) == .1); - BEAST_EXPECT( - relativeDistance(toQuality(100, 90), toQuality(110, 91)) == 10); - BEAST_EXPECT( - relativeDistance(toQuality(100, 0), toQuality(100, 90)) == 1e90); + BEAST_EXPECT(relativeDistance(toQuality(100, 90), toQuality(110, 90)) == .1); + BEAST_EXPECT(relativeDistance(toQuality(100, 90), toQuality(110, 91)) == 10); + BEAST_EXPECT(relativeDistance(toQuality(100, 0), toQuality(100, 90)) == 1e90); // Make the mantissa in the smaller value bigger than the mantissa in // the larger value. Instead of checking the exact result, we check that // it's large. If the values did not compare correctly in // `relativeDistance`, then the returned value would be negative. - BEAST_EXPECT( - relativeDistance(toQuality(102, 0), toQuality(101, 90)) >= 1e89); + BEAST_EXPECT(relativeDistance(toQuality(102, 0), toQuality(101, 90)) >= 1e89); } void @@ -552,7 +483,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(TheoreticalQuality, app, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(TheoreticalQuality, app, xrpl, 3); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Ticket_test.cpp b/src/test/app/Ticket_test.cpp index 70a5a48adf..0835c02289 100644 --- a/src/test/app/Ticket_test.cpp +++ b/src/test/app/Ticket_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class Ticket_test : public beast::unit_test::suite { @@ -38,19 +19,14 @@ class Ticket_test : public beast::unit_test::suite Json::Value const& tx{env.tx()->getJson(JsonOptions::none)}; { - std::string const txType = - tx[sfTransactionType.jsonName].asString(); + std::string const txType = tx[sfTransactionType.jsonName].asString(); - if (!BEAST_EXPECTS( - txType == jss::TicketCreate, - "Unexpected TransactionType: "s + txType)) + if (!BEAST_EXPECTS(txType == jss::TicketCreate, "Unexpected TransactionType: "s + txType)) return; } std::uint32_t const count = {tx[sfTicketCount.jsonName].asUInt()}; - if (!BEAST_EXPECTS( - count >= 1, - "Unexpected ticket count: "s + std::to_string(count))) + if (!BEAST_EXPECTS(count >= 1, "Unexpected ticket count: "s + std::to_string(count))) return; std::uint32_t const txSeq = {tx[sfSequence.jsonName].asUInt()}; @@ -59,8 +35,7 @@ class Ticket_test : public beast::unit_test::suite Json::Value const& metadata = env.meta()->getJson(JsonOptions::none); if (!BEAST_EXPECTS( metadata.isMember(sfTransactionResult.jsonName) && - metadata[sfTransactionResult.jsonName].asString() == - "tesSUCCESS", + metadata[sfTransactionResult.jsonName].asString() == "tesSUCCESS", "Not metadata for successful TicketCreate.")) return; @@ -76,20 +51,16 @@ class Ticket_test : public beast::unit_test::suite if (node.isMember(sfModifiedNode.jsonName)) { Json::Value const& modified = node[sfModifiedNode.jsonName]; - std::string const entryType = - modified[sfLedgerEntryType.jsonName].asString(); + std::string const entryType = modified[sfLedgerEntryType.jsonName].asString(); if (entryType == jss::AccountRoot) { - auto const& previousFields = - modified[sfPreviousFields.jsonName]; + auto const& previousFields = modified[sfPreviousFields.jsonName]; auto const& finalFields = modified[sfFinalFields.jsonName]; { // Verify the account root Sequence did the right thing. - std::uint32_t const prevSeq = - previousFields[sfSequence.jsonName].asUInt(); + std::uint32_t const prevSeq = previousFields[sfSequence.jsonName].asUInt(); - acctRootFinalSeq = - finalFields[sfSequence.jsonName].asUInt(); + acctRootFinalSeq = finalFields[sfSequence.jsonName].asUInt(); if (txSeq == 0) { @@ -100,13 +71,11 @@ class Ticket_test : public beast::unit_test::suite { // Transaction used a (plain) Sequence. BEAST_EXPECT(prevSeq == txSeq); - BEAST_EXPECT( - acctRootFinalSeq == prevSeq + count + 1); + BEAST_EXPECT(acctRootFinalSeq == prevSeq + count + 1); } } - std::uint32_t const consumedTickets = { - txSeq == 0u ? 1u : 0u}; + std::uint32_t const consumedTickets = {txSeq == 0u ? 1u : 0u}; // If... // 1. The TicketCount is 1 and @@ -115,28 +84,23 @@ class Ticket_test : public beast::unit_test::suite // previous TicketCount is not reported. // But, since the count did not change, we know it equals // the final Ticket count. - bool const unreportedPrevTicketCount = { - count == 1 && txSeq == 0}; + bool const unreportedPrevTicketCount = {count == 1 && txSeq == 0}; // Verify the OwnerCount did the right thing if (unreportedPrevTicketCount) { // The number of Tickets should not have changed, so // the previous OwnerCount should not be reported. - BEAST_EXPECT( - !previousFields.isMember(sfOwnerCount.jsonName)); + BEAST_EXPECT(!previousFields.isMember(sfOwnerCount.jsonName)); } else { // Verify the OwnerCount did the right thing. - std::uint32_t const prevCount = { - previousFields[sfOwnerCount.jsonName].asUInt()}; + std::uint32_t const prevCount = {previousFields[sfOwnerCount.jsonName].asUInt()}; - std::uint32_t const finalCount = { - finalFields[sfOwnerCount.jsonName].asUInt()}; + std::uint32_t const finalCount = {finalFields[sfOwnerCount.jsonName].asUInt()}; - BEAST_EXPECT( - prevCount + count - consumedTickets == finalCount); + BEAST_EXPECT(prevCount + count - consumedTickets == finalCount); } // Verify TicketCount metadata. @@ -146,8 +110,7 @@ class Ticket_test : public beast::unit_test::suite { // The number of Tickets should not have changed, so // the previous TicketCount should not be reported. - BEAST_EXPECT( - !previousFields.isMember(sfTicketCount.jsonName)); + BEAST_EXPECT(!previousFields.isMember(sfTicketCount.jsonName)); } else { @@ -155,17 +118,12 @@ class Ticket_test : public beast::unit_test::suite // should have been greater than zero. std::uint32_t const startCount = { previousFields.isMember(sfTicketCount.jsonName) - ? previousFields[sfTicketCount.jsonName] - .asUInt() + ? previousFields[sfTicketCount.jsonName].asUInt() : 0u}; - BEAST_EXPECT( - (startCount == 0u) ^ - previousFields.isMember(sfTicketCount.jsonName)); + BEAST_EXPECT((startCount == 0u) ^ previousFields.isMember(sfTicketCount.jsonName)); - BEAST_EXPECT( - startCount + count - consumedTickets == - finalFields[sfTicketCount.jsonName]); + BEAST_EXPECT(startCount + count - consumedTickets == finalFields[sfTicketCount.jsonName]); } } else if (entryType == jss::DirectoryNode) @@ -174,25 +132,19 @@ class Ticket_test : public beast::unit_test::suite } else { - fail( - "Unexpected modified node: "s + entryType, - __FILE__, - __LINE__); + fail("Unexpected modified node: "s + entryType, __FILE__, __LINE__); } } else if (node.isMember(sfCreatedNode.jsonName)) { Json::Value const& created = node[sfCreatedNode.jsonName]; - std::string const entryType = - created[sfLedgerEntryType.jsonName].asString(); + std::string const entryType = created[sfLedgerEntryType.jsonName].asString(); if (entryType == jss::Ticket) { auto const& newFields = created[sfNewFields.jsonName]; - BEAST_EXPECT( - newFields[sfAccount.jsonName].asString() == account); - ticketSeqs.push_back( - newFields[sfTicketSequence.jsonName].asUInt()); + BEAST_EXPECT(newFields[sfAccount.jsonName].asString() == account); + ticketSeqs.push_back(newFields[sfTicketSequence.jsonName].asUInt()); } else if (entryType == jss::DirectoryNode) { @@ -200,17 +152,13 @@ class Ticket_test : public beast::unit_test::suite } else { - fail( - "Unexpected created node: "s + entryType, - __FILE__, - __LINE__); + fail("Unexpected created node: "s + entryType, __FILE__, __LINE__); } } else if (node.isMember(sfDeletedNode.jsonName)) { Json::Value const& deleted = node[sfDeletedNode.jsonName]; - std::string const entryType = - deleted[sfLedgerEntryType.jsonName].asString(); + std::string const entryType = deleted[sfLedgerEntryType.jsonName].asString(); if (entryType == jss::Ticket) { @@ -219,21 +167,16 @@ class Ticket_test : public beast::unit_test::suite // Verify the account of the deleted ticket. auto const& finalFields = deleted[sfFinalFields.jsonName]; - BEAST_EXPECT( - finalFields[sfAccount.jsonName].asString() == account); + BEAST_EXPECT(finalFields[sfAccount.jsonName].asString() == account); // Verify the deleted ticket has the right TicketSequence. BEAST_EXPECT( - finalFields[sfTicketSequence.jsonName].asUInt() == - tx[sfTicketSequence.jsonName].asUInt()); + finalFields[sfTicketSequence.jsonName].asUInt() == tx[sfTicketSequence.jsonName].asUInt()); } } else { - fail( - "Unexpected node type in TicketCreate metadata.", - __FILE__, - __LINE__); + fail("Unexpected node type in TicketCreate metadata.", __FILE__, __LINE__); } } BEAST_EXPECT(directoryChanged); @@ -241,9 +184,7 @@ class Ticket_test : public beast::unit_test::suite // Verify that all the expected Tickets were created. BEAST_EXPECT(ticketSeqs.size() == count); std::sort(ticketSeqs.begin(), ticketSeqs.end()); - BEAST_EXPECT( - std::adjacent_find(ticketSeqs.begin(), ticketSeqs.end()) == - ticketSeqs.end()); + BEAST_EXPECT(std::adjacent_find(ticketSeqs.begin(), ticketSeqs.end()) == ticketSeqs.end()); BEAST_EXPECT(*ticketSeqs.rbegin() == acctRootFinalSeq - 1); } @@ -281,25 +222,19 @@ class Ticket_test : public beast::unit_test::suite // was deleted. BEAST_EXPECT(tx[sfSequence.jsonName].asUInt() == 0); std::string const account{tx[sfAccount.jsonName].asString()}; - if (!BEAST_EXPECTS( - tx.isMember(sfTicketSequence.jsonName), - "Not metadata for a ticket consuming transaction.")) + if (!BEAST_EXPECTS(tx.isMember(sfTicketSequence.jsonName), "Not metadata for a ticket consuming transaction.")) return; std::uint32_t const ticketSeq{tx[sfTicketSequence.jsonName].asUInt()}; Json::Value const& metadata{env.meta()->getJson(JsonOptions::none)}; - if (!BEAST_EXPECTS( - metadata.isMember(sfTransactionResult.jsonName), - "Metadata is missing TransactionResult.")) + if (!BEAST_EXPECTS(metadata.isMember(sfTransactionResult.jsonName), "Metadata is missing TransactionResult.")) return; { - std::string const transactionResult{ - metadata[sfTransactionResult.jsonName].asString()}; + std::string const transactionResult{metadata[sfTransactionResult.jsonName].asString()}; if (!BEAST_EXPECTS( - transactionResult == "tesSUCCESS" || - transactionResult.compare(0, 3, "tec") == 0, + transactionResult == "tesSUCCESS" || transactionResult.compare(0, 3, "tec") == 0, transactionResult + " neither tesSUCCESS nor tec")) return; } @@ -315,16 +250,13 @@ class Ticket_test : public beast::unit_test::suite if (node.isMember(sfModifiedNode.jsonName)) { Json::Value const& modified{node[sfModifiedNode.jsonName]}; - std::string const entryType = - modified[sfLedgerEntryType.jsonName].asString(); + std::string const entryType = modified[sfLedgerEntryType.jsonName].asString(); if (entryType == "AccountRoot" && - modified[sfFinalFields.jsonName][sfAccount.jsonName] - .asString() == account) + modified[sfFinalFields.jsonName][sfAccount.jsonName].asString() == account) { acctRootFound = true; - auto const& previousFields = - modified[sfPreviousFields.jsonName]; + auto const& previousFields = modified[sfPreviousFields.jsonName]; auto const& finalFields = modified[sfFinalFields.jsonName]; acctRootSeq = finalFields[sfSequence.jsonName].asUInt(); @@ -337,38 +269,29 @@ class Ticket_test : public beast::unit_test::suite "AccountRoot previous is missing TicketCount")) return; - std::uint32_t const prevTicketCount = - previousFields[sfTicketCount.jsonName].asUInt(); + std::uint32_t const prevTicketCount = previousFields[sfTicketCount.jsonName].asUInt(); BEAST_EXPECT(prevTicketCount > 0); if (prevTicketCount == 1) - BEAST_EXPECT( - !finalFields.isMember(sfTicketCount.jsonName)); + BEAST_EXPECT(!finalFields.isMember(sfTicketCount.jsonName)); else BEAST_EXPECT( finalFields.isMember(sfTicketCount.jsonName) && - finalFields[sfTicketCount.jsonName].asUInt() == - prevTicketCount - 1); + finalFields[sfTicketCount.jsonName].asUInt() == prevTicketCount - 1); } } else if (node.isMember(sfDeletedNode.jsonName)) { Json::Value const& deleted{node[sfDeletedNode.jsonName]}; - std::string const entryType{ - deleted[sfLedgerEntryType.jsonName].asString()}; + std::string const entryType{deleted[sfLedgerEntryType.jsonName].asString()}; if (entryType == jss::Ticket) { // Verify the account of the deleted ticket. - BEAST_EXPECT( - deleted[sfFinalFields.jsonName][sfAccount.jsonName] - .asString() == account); + BEAST_EXPECT(deleted[sfFinalFields.jsonName][sfAccount.jsonName].asString() == account); // Verify the deleted ticket has the right TicketSequence. - BEAST_EXPECT( - deleted[sfFinalFields.jsonName] - [sfTicketSequence.jsonName] - .asUInt() == ticketSeq); + BEAST_EXPECT(deleted[sfFinalFields.jsonName][sfTicketSequence.jsonName].asUInt() == ticketSeq); ++ticketsRemoved; } @@ -379,52 +302,6 @@ class Ticket_test : public beast::unit_test::suite BEAST_EXPECT(ticketSeq < acctRootSeq); } - void - testTicketNotEnabled() - { - testcase("Feature Not Enabled"); - - using namespace test::jtx; - Env env{*this, testable_amendments() - featureTicketBatch}; - - env(ticket::create(env.master, 1), ter(temDISABLED)); - env.close(); - env.require(owners(env.master, 0), tickets(env.master, 0)); - - env(noop(env.master), ticket::use(1), ter(temMALFORMED)); - env(noop(env.master), - ticket::use(1), - seq(env.seq(env.master)), - ter(temMALFORMED)); - - // Close enough ledgers that the previous transactions are no - // longer retried. - for (int i = 0; i < 8; ++i) - env.close(); - - env.enableFeature(featureTicketBatch); - env.close(); - env.require(owners(env.master, 0), tickets(env.master, 0)); - - std::uint32_t ticketSeq{env.seq(env.master) + 1}; - env(ticket::create(env.master, 2)); - checkTicketCreateMeta(env); - env.close(); - env.require(owners(env.master, 2), tickets(env.master, 2)); - - env(noop(env.master), ticket::use(ticketSeq++)); - checkTicketConsumeMeta(env); - env.close(); - env.require(owners(env.master, 1), tickets(env.master, 1)); - - env(fset(env.master, asfDisableMaster), - ticket::use(ticketSeq++), - ter(tecNO_ALTERNATIVE_KEY)); - checkTicketConsumeMeta(env); - env.close(); - env.require(owners(env.master, 0), tickets(env.master, 0)); - } - void testTicketCreatePreflightFail() { @@ -484,9 +361,7 @@ class Ticket_test : public beast::unit_test::suite Account alice{"alice"}; env.memoize(alice); - env(ticket::create(alice, 1), - json(jss::Sequence, 1), - ter(terNO_ACCOUNT)); + env(ticket::create(alice, 1), json(jss::Sequence, 1), ter(terNO_ACCOUNT)); } { // Exceed the threshold where tickets can no longer be @@ -510,9 +385,7 @@ class Ticket_test : public beast::unit_test::suite env.require(owners(alice, 250), tickets(alice, 250)); // Adding one more ticket will exceed the threshold. - env(ticket::create(alice, 2), - ticket::use(ticketSeq + 1), - ter(tecDIR_FULL)); + env(ticket::create(alice, 2), ticket::use(ticketSeq + 1), ter(tecDIR_FULL)); env.close(); env.require(owners(alice, 249), tickets(alice, 249)); @@ -544,9 +417,7 @@ class Ticket_test : public beast::unit_test::suite // Adding 250 tickets (while consuming one) will exceed the // threshold. - env(ticket::create(alice, 250), - ticket::use(ticketSeq_AB + 0), - ter(tecDIR_FULL)); + env(ticket::create(alice, 250), ticket::use(ticketSeq_AB + 0), ter(tecDIR_FULL)); env.close(); env.require(owners(alice, 1), tickets(alice, 1)); @@ -582,10 +453,7 @@ class Ticket_test : public beast::unit_test::suite env.require(owners(alice, 0), tickets(alice, 0)); // Give alice enough to exactly meet the reserve for one Ticket. - env( - pay(env.master, - alice, - env.current()->fees().accountReserve(1) - env.balance(alice))); + env(pay(env.master, alice, env.current()->fees().accountReserve(1) - env.balance(alice))); env.close(); env(ticket::create(alice, 1)); @@ -595,11 +463,7 @@ class Ticket_test : public beast::unit_test::suite // Give alice not quite enough to make the reserve for a total of // 250 Tickets. - env( - pay(env.master, - alice, - env.current()->fees().accountReserve(250) - drops(1) - - env.balance(alice))); + env(pay(env.master, alice, env.current()->fees().accountReserve(250) - drops(1) - env.balance(alice))); env.close(); // alice doesn't quite have the reserve for a total of 250 @@ -610,10 +474,7 @@ class Ticket_test : public beast::unit_test::suite // Give alice enough so she can make the reserve for all 250 // Tickets. - env(pay( - env.master, - alice, - env.current()->fees().accountReserve(250) - env.balance(alice))); + env(pay(env.master, alice, env.current()->fees().accountReserve(250) - env.balance(alice))); env.close(); std::uint32_t const ticketSeq{env.seq(alice) + 1}; @@ -702,10 +563,7 @@ class Ticket_test : public beast::unit_test::suite checkTicketCreateMeta(env); env.close(); - env(noop(alice), - ticket::use(ticketSeq_G), - json(R"({"AccountTxnID": "0"})"), - ter(temINVALID)); + env(noop(alice), ticket::use(ticketSeq_G), json(R"({"AccountTxnID": "0"})"), ter(temINVALID)); env.close(); env.require(owners(alice, 2), tickets(alice, 1)); } @@ -798,10 +656,8 @@ class Ticket_test : public beast::unit_test::suite TxType txType) { error_code_i txErrCode{rpcSUCCESS}; - using TxPair = std:: - pair, std::shared_ptr>; - std::variant maybeTx = - Transaction::load(txID, env.app(), txErrCode); + using TxPair = std::pair, std::shared_ptr>; + std::variant maybeTx = Transaction::load(txID, env.app(), txErrCode); BEAST_EXPECT(txErrCode == rpcSUCCESS); if (auto txPtr = std::get_if(&maybeTx)) @@ -875,11 +731,9 @@ class Ticket_test : public beast::unit_test::suite Json::Value jr = env.rpc("json", "sign", to_string(tx)); // Verify that "sign" inserted a "Sequence": 0 field. - if (BEAST_EXPECT(jr[jss::result][jss::tx_json].isMember( - sfSequence.jsonName))) + if (BEAST_EXPECT(jr[jss::result][jss::tx_json].isMember(sfSequence.jsonName))) { - BEAST_EXPECT( - jr[jss::result][jss::tx_json][sfSequence.jsonName] == 0); + BEAST_EXPECT(jr[jss::result][jss::tx_json][sfSequence.jsonName] == 0); } // "sign" should not have consumed any of alice's tickets. @@ -910,11 +764,9 @@ class Ticket_test : public beast::unit_test::suite Json::Value jr = env.rpc("json", "submit", to_string(tx)); // Verify that "submit" inserted a "Sequence": 0 field. - if (BEAST_EXPECT(jr[jss::result][jss::tx_json].isMember( - sfSequence.jsonName))) + if (BEAST_EXPECT(jr[jss::result][jss::tx_json].isMember(sfSequence.jsonName))) { - BEAST_EXPECT( - jr[jss::result][jss::tx_json][sfSequence.jsonName] == 0); + BEAST_EXPECT(jr[jss::result][jss::tx_json][sfSequence.jsonName] == 0); } // "submit" should have consumed the last of alice's tickets. @@ -926,70 +778,40 @@ class Ticket_test : public beast::unit_test::suite void testFixBothSeqAndTicket() { + using namespace test::jtx; + // It is an error if a transaction contains a non-zero Sequence field // and a TicketSequence field. Verify that the error is detected. testcase("Fix both Seq and Ticket"); - // Try the test without featureTicketBatch enabled. - using namespace test::jtx; - { - Env env{*this, testable_amendments() - featureTicketBatch}; - Account alice{"alice"}; + Env env{*this, testable_amendments()}; + Account alice{"alice"}; - env.fund(XRP(10000), alice); - env.close(); + env.fund(XRP(10000), alice); + env.close(); - // Fail to create a ticket. - std::uint32_t const ticketSeq = env.seq(alice) + 1; - env(ticket::create(alice, 1), ter(temDISABLED)); - env.close(); - env.require(owners(alice, 0), tickets(alice, 0)); - BEAST_EXPECT(ticketSeq == env.seq(alice) + 1); + // Create a ticket. + std::uint32_t const ticketSeq = env.seq(alice) + 1; + env(ticket::create(alice, 1)); + env.close(); + env.require(owners(alice, 1), tickets(alice, 1)); + BEAST_EXPECT(ticketSeq + 1 == env.seq(alice)); - // Create a transaction that includes both a ticket and a non-zero - // sequence number. Since a ticket is used and tickets are not yet - // enabled the transaction should be malformed. - env(noop(alice), - ticket::use(ticketSeq), - seq(env.seq(alice)), - ter(temMALFORMED)); - env.close(); - } - // Try the test with featureTicketBatch enabled. - { - Env env{*this, testable_amendments()}; - Account alice{"alice"}; + // Create a transaction that includes both a ticket and a non-zero + // sequence number. The transaction fails with temSEQ_AND_TICKET. + env(noop(alice), ticket::use(ticketSeq), seq(env.seq(alice)), ter(temSEQ_AND_TICKET)); + env.close(); - env.fund(XRP(10000), alice); - env.close(); - - // Create a ticket. - std::uint32_t const ticketSeq = env.seq(alice) + 1; - env(ticket::create(alice, 1)); - env.close(); - env.require(owners(alice, 1), tickets(alice, 1)); - BEAST_EXPECT(ticketSeq + 1 == env.seq(alice)); - - // Create a transaction that includes both a ticket and a non-zero - // sequence number. The transaction fails with temSEQ_AND_TICKET. - env(noop(alice), - ticket::use(ticketSeq), - seq(env.seq(alice)), - ter(temSEQ_AND_TICKET)); - env.close(); - - // Verify that the transaction failed by looking at alice's - // sequence number and tickets. - env.require(owners(alice, 1), tickets(alice, 1)); - BEAST_EXPECT(ticketSeq + 1 == env.seq(alice)); - } + // Verify that the transaction failed by looking at alice's + // sequence number and tickets. + env.require(owners(alice, 1), tickets(alice, 1)); + BEAST_EXPECT(ticketSeq + 1 == env.seq(alice)); } public: void run() override { - testTicketNotEnabled(); testTicketCreatePreflightFail(); testTicketCreatePreclaimFail(); testTicketInsufficientReserve(); @@ -1000,6 +822,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Ticket, app, ripple); +BEAST_DEFINE_TESTSUITE(Ticket, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Transaction_ordering_test.cpp b/src/test/app/Transaction_ordering_test.cpp index 5ace79db59..f7d431fc90 100644 --- a/src/test/app/Transaction_ordering_test.cpp +++ b/src/test/app/Transaction_ordering_test.cpp @@ -1,25 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include -namespace ripple { +namespace xrpl { namespace test { struct Transaction_ordering_test : public beast::unit_test::suite @@ -37,8 +20,7 @@ struct Transaction_ordering_test : public beast::unit_test::suite auto const aliceSequence = env.seq(alice); auto const tx1 = env.jt(noop(alice), seq(aliceSequence)); - auto const tx2 = - env.jt(noop(alice), seq(aliceSequence + 1), last_ledger_seq(7)); + auto const tx2 = env.jt(noop(alice), seq(aliceSequence + 1), last_ledger_seq(7)); env(tx1); env.close(); @@ -50,16 +32,12 @@ struct Transaction_ordering_test : public beast::unit_test::suite env.close(); { - auto const result = - env.rpc("tx", to_string(tx1.stx->getTransactionID())); - BEAST_EXPECT( - result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); + auto const result = env.rpc("tx", to_string(tx1.stx->getTransactionID())); + BEAST_EXPECT(result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); } { - auto const result = - env.rpc("tx", to_string(tx2.stx->getTransactionID())); - BEAST_EXPECT( - result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); + auto const result = env.rpc("tx", to_string(tx2.stx->getTransactionID())); + BEAST_EXPECT(result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); } } @@ -81,8 +59,7 @@ struct Transaction_ordering_test : public beast::unit_test::suite auto const aliceSequence = env.seq(alice); auto const tx1 = env.jt(noop(alice), seq(aliceSequence)); - auto const tx2 = - env.jt(noop(alice), seq(aliceSequence + 1), last_ledger_seq(7)); + auto const tx2 = env.jt(noop(alice), seq(aliceSequence + 1), last_ledger_seq(7)); env(tx2, ter(terPRE_SEQ)); BEAST_EXPECT(env.seq(alice) == aliceSequence); @@ -93,16 +70,12 @@ struct Transaction_ordering_test : public beast::unit_test::suite env.close(); { - auto const result = - env.rpc("tx", to_string(tx1.stx->getTransactionID())); - BEAST_EXPECT( - result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); + auto const result = env.rpc("tx", to_string(tx1.stx->getTransactionID())); + BEAST_EXPECT(result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); } { - auto const result = - env.rpc("tx", to_string(tx2.stx->getTransactionID())); - BEAST_EXPECT( - result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); + auto const result = env.rpc("tx", to_string(tx2.stx->getTransactionID())); + BEAST_EXPECT(result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); } } @@ -126,8 +99,7 @@ struct Transaction_ordering_test : public beast::unit_test::suite std::vector tx; for (auto i = 0; i < 5; ++i) { - tx.emplace_back(env.jt( - noop(alice), seq(aliceSequence + i), last_ledger_seq(7))); + tx.emplace_back(env.jt(noop(alice), seq(aliceSequence + i), last_ledger_seq(7))); } for (auto i = 1; i < 5; ++i) @@ -144,10 +116,8 @@ struct Transaction_ordering_test : public beast::unit_test::suite for (auto i = 0; i < 5; ++i) { - auto const result = - env.rpc("tx", to_string(tx[i].stx->getTransactionID())); - BEAST_EXPECT( - result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); + auto const result = env.rpc("tx", to_string(tx[i].stx->getTransactionID())); + BEAST_EXPECT(result["result"]["meta"]["TransactionResult"] == "tesSUCCESS"); } } @@ -160,7 +130,7 @@ struct Transaction_ordering_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Transaction_ordering, app, ripple); +BEAST_DEFINE_TESTSUITE(Transaction_ordering, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/TrustAndBalance_test.cpp b/src/test/app/TrustAndBalance_test.cpp index f39d9e0313..aa06ccbdf1 100644 --- a/src/test/app/TrustAndBalance_test.cpp +++ b/src/test/app/TrustAndBalance_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { class TrustAndBalance_test : public beast::unit_test::suite { @@ -76,36 +57,24 @@ class TrustAndBalance_test : public beast::unit_test::suite jrr = ledgerEntryState(env, gw, alice, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::value] == "800"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == - alice.human()); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::value] == "800"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == alice.human()); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] == "0"); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human()); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human()); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); // modify the credit limit env(trust(alice, gw["USD"](700))); jrr = ledgerEntryState(env, gw, alice, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::value] == "700"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == - alice.human()); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::value] == "700"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == alice.human()); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] == "0"); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human()); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == gw.human()); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); // set negative limit - expect failure env(trust(alice, gw["USD"](-1)), ter(temBAD_LIMIT)); @@ -128,17 +97,12 @@ class TrustAndBalance_test : public beast::unit_test::suite // check the ledger state for the trust line jrr = ledgerEntryState(env, alice, bob, "USD"); BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::value] == "500"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == bob.human()); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::value] == "500"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::issuer] == bob.human()); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.fieldName][jss::currency] == "USD"); BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::value] == "600"); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == alice.human()); - BEAST_EXPECT( - jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::issuer] == alice.human()); + BEAST_EXPECT(jrr[jss::node][sfLowLimit.fieldName][jss::currency] == "USD"); } void @@ -186,8 +150,7 @@ class TrustAndBalance_test : public beast::unit_test::suite testWithTransferFee(bool subscribe, bool with_rate, FeatureBitset features) { testcase( - std::string("Direct Payment: ") + - (with_rate ? "With " : "Without ") + " Xfer Fee, " + + std::string("Direct Payment: ") + (with_rate ? "With " : "Without ") + " Xfer Fee, " + (subscribe ? "With " : "Without ") + " Subscribe"); using namespace test::jtx; @@ -252,12 +215,9 @@ class TrustAndBalance_test : public beast::unit_test::suite auto const& t = jval[jss::transaction]; return t[jss::TransactionType] == jss::Payment; })); - BEAST_EXPECT(wsc->findMsg(5s, [](auto const& jval) { - return jval[jss::type] == "ledgerClosed"; - })); + BEAST_EXPECT(wsc->findMsg(5s, [](auto const& jval) { return jval[jss::type] == "ledgerClosed"; })); - BEAST_EXPECT( - wsc->invoke("unsubscribe", jv)[jss::status] == "success"); + BEAST_EXPECT(wsc->invoke("unsubscribe", jv)[jss::status] == "success"); } } @@ -302,9 +262,7 @@ class TrustAndBalance_test : public beast::unit_test::suite // alice sends bob issues to bob with a max spend in alice issues. // expect fail since gw is not involved - env(pay(alice, bob, bob["AUD"](1)), - sendmax(alice["AUD"](1.1)), - ter(tecPATH_DRY)); + env(pay(alice, bob, bob["AUD"](1)), sendmax(alice["AUD"](1.1)), ter(tecPATH_DRY)); env.require(balance(alice, gw["AUD"](1.1))); env.require(balance(bob, gw["AUD"](3))); @@ -354,9 +312,7 @@ class TrustAndBalance_test : public beast::unit_test::suite void testIndirectMultiPath(bool with_rate, FeatureBitset features) { - testcase( - std::string("Indirect Payment, Multi Path, ") + - (with_rate ? "With " : "Without ") + " Xfer Fee, "); + testcase(std::string("Indirect Payment, Multi Path, ") + (with_rate ? "With " : "Without ") + " Xfer Fee, "); using namespace test::jtx; Env env{*this, features}; @@ -389,20 +345,12 @@ class TrustAndBalance_test : public beast::unit_test::suite test::jtx::path(bob), test::jtx::path(carol)); else - env(pay(alice, amazon, gw["USD"](150)), - test::jtx::path(bob), - test::jtx::path(carol)); + env(pay(alice, amazon, gw["USD"](150)), test::jtx::path(bob), test::jtx::path(carol)); if (with_rate) { - env.require(balance( - alice, - STAmount( - carol["USD"].issue(), - 6500000000000000ull, - -14, - true, - STAmount::unchecked{}))); + env.require( + balance(alice, STAmount(carol["USD"].issue(), 6500000000000000ull, -14, true, STAmount::unchecked{}))); env.require(balance(carol, gw["USD"](35))); } else @@ -435,24 +383,20 @@ class TrustAndBalance_test : public beast::unit_test::suite jvs[jss::streams].append("transactions"); BEAST_EXPECT(wsc->invoke("subscribe", jvs)[jss::status] == "success"); - char const* invoiceid = - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"; + char const* invoiceId = "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"; Json::Value jv; - auto tx = env.jt( - pay(env.master, alice, XRP(10000)), - json(sfInvoiceID.fieldName, invoiceid)); + auto tx = env.jt(pay(env.master, alice, XRP(10000)), json(sfInvoiceID.fieldName, invoiceId)); jv[jss::tx_blob] = strHex(tx.stx->getSerializer().slice()); auto jrr = wsc->invoke("submit", jv)[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); - BEAST_EXPECT(jrr[jss::tx_json][sfInvoiceID.fieldName] == invoiceid); + BEAST_EXPECT(jrr[jss::tx_json][sfInvoiceID.fieldName] == invoiceId); env.close(); using namespace std::chrono_literals; - BEAST_EXPECT(wsc->findMsg(2s, [invoiceid](auto const& jval) { + BEAST_EXPECT(wsc->findMsg(2s, [invoiceId](auto const& jval) { auto const& t = jval[jss::transaction]; - return t[jss::TransactionType] == jss::Payment && - t[sfInvoiceID.fieldName] == invoiceid; + return t[jss::TransactionType] == jss::Payment && t[sfInvoiceID.fieldName] == invoiceId; })); BEAST_EXPECT(wsc->invoke("unsubscribe", jv)[jss::status] == "success"); @@ -486,6 +430,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(TrustAndBalance, app, ripple); +BEAST_DEFINE_TESTSUITE(TrustAndBalance, app, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index ebc9c7d413..13feceb74e 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -87,8 +68,7 @@ class TxQPosNegFlows_test : public beast::unit_test::suite auto calcMedFeeLevel(FeeLevel64 const feeLevel1, FeeLevel64 const feeLevel2) { - FeeLevel64 const expectedMedFeeLevel = - (feeLevel1 + feeLevel2 + FeeLevel64{1}) / 2; + FeeLevel64 const expectedMedFeeLevel = (feeLevel1 + feeLevel2 + FeeLevel64{1}) / 2; return std::max(expectedMedFeeLevel, minEscalationFeeLevel).fee(); } @@ -118,7 +98,7 @@ class TxQPosNegFlows_test : public beast::unit_test::suite // fee (1) and amendment (numUpVotedAmendments()) // pseudotransactions. The queue treats the fees on these // transactions as though they are ordinary transactions. - auto const flagPerLedger = 1 + ripple::detail::numUpVotedAmendments(); + auto const flagPerLedger = 1 + xrpl::detail::numUpVotedAmendments(); auto const flagMaxQueue = ledgersInQueue * flagPerLedger; checkMetrics(*this, env, 0, flagMaxQueue, 0, flagPerLedger); @@ -350,13 +330,7 @@ public: env(noop(env.master), fee(baseFee * 2), queued); ++metrics.txCount; - checkMetrics( - *this, - env, - metrics.txCount, - metrics.txQMaxSize, - metrics.txPerLedger + 1, - metrics.txPerLedger); + checkMetrics(*this, env, metrics.txCount, metrics.txQMaxSize, metrics.txPerLedger + 1, metrics.txPerLedger); } void @@ -419,10 +393,7 @@ public: env(noop(alice), ticket::use(tkt1 + 10), fee(baseFee * 2.0), queued); env(noop(alice), ticket::use(tkt1 + 11), fee(baseFee * 2.1), queued); env(noop(alice), ticket::use(tkt1 + 12), fee(baseFee * 2.2), queued); - env(noop(alice), - ticket::use(tkt1 + 13), - fee(baseFee * 2.3), - ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), ticket::use(tkt1 + 13), fee(baseFee * 2.3), ter(telCAN_NOT_QUEUE_FULL)); checkMetrics(*this, env, 8, 8, 5, 4, expectedMinFeeLevel); // Check which of the queued transactions got into the ledger by @@ -528,22 +499,10 @@ public: env(noop(alice), ticket::use(tkt1 + 15), fee(baseFee * 2.7), queued); env(noop(alice), ticket::use(tkt250 - 2), fee(baseFee * 2.6), queued); env(noop(alice), ticket::use(tkt1 + 16), fee(baseFee * 2.5), queued); - env(noop(alice), - ticket::use(tkt250 - 3), - fee(baseFee * 2.4), - ter(telCAN_NOT_QUEUE_FULL)); - env(noop(alice), - ticket::use(tkt1 + 17), - fee(baseFee * 2.3), - ter(telCAN_NOT_QUEUE_FULL)); - env(noop(alice), - ticket::use(tkt250 - 4), - fee(baseFee * 2.2), - ter(telCAN_NOT_QUEUE_FULL)); - env(noop(alice), - ticket::use(tkt1 + 18), - fee(baseFee * 2.1), - ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), ticket::use(tkt250 - 3), fee(baseFee * 2.4), ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), ticket::use(tkt1 + 17), fee(baseFee * 2.3), ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), ticket::use(tkt250 - 4), fee(baseFee * 2.2), ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), ticket::use(tkt1 + 18), fee(baseFee * 2.1), ter(telCAN_NOT_QUEUE_FULL)); checkMetrics(*this, env, 10, 12, 7, 6); @@ -584,24 +543,12 @@ public: // let's try replacing them. // The lowest fee ticket is baseFee * 2.1, trying to replace it - env(noop(alice), - ticket::use(tkt1 + 18), - fee(baseFee * 2.1 * 1.25 - 1), - ter(telCAN_NOT_QUEUE_FEE)); - env(noop(alice), - ticket::use(tkt1 + 18), - fee(baseFee * 2.1 * 1.25 + 1), - queued); + env(noop(alice), ticket::use(tkt1 + 18), fee(baseFee * 2.1 * 1.25 - 1), ter(telCAN_NOT_QUEUE_FEE)); + env(noop(alice), ticket::use(tkt1 + 18), fee(baseFee * 2.1 * 1.25 + 1), queued); // New lowest fee ticket is baseFee * 2.2 - env(noop(alice), - ticket::use(tkt250 - 4), - fee(baseFee * 2.2 * 1.25 - 1), - ter(telCAN_NOT_QUEUE_FEE)); - env(noop(alice), - ticket::use(tkt250 - 4), - fee(baseFee * 2.2 * 1.25 + 1), - queued); + env(noop(alice), ticket::use(tkt250 - 4), fee(baseFee * 2.2 * 1.25 - 1), ter(telCAN_NOT_QUEUE_FEE)); + env(noop(alice), ticket::use(tkt250 - 4), fee(baseFee * 2.2 * 1.25 + 1), queued); env.close(); env.require(owners(alice, 227), tickets(alice, 227)); @@ -677,10 +624,7 @@ public: checkMetrics(*this, env, 0, std::nullopt, 3, 2); // Future transaction for Alice - fails - env(noop(alice), - fee(openLedgerCost(env)), - seq(env.seq(alice) + 1), - ter(terPRE_SEQ)); + env(noop(alice), fee(openLedgerCost(env)), seq(env.seq(alice) + 1), ter(terPRE_SEQ)); checkMetrics(*this, env, 0, std::nullopt, 3, 2); // Current transaction for Alice: held @@ -745,7 +689,7 @@ public: env(noop(daria)); checkMetrics(*this, env, 0, std::nullopt, 3, 2); - BEAST_EXPECT(env.current()->info().seq == 6); + BEAST_EXPECT(env.current()->header().seq == 6); // Fail to queue an item with a low LastLedgerSeq env(noop(alice), last_ledger_seq(7), ter(telCAN_NOT_QUEUE)); // Queue an item with a sufficient LastLedgerSeq. @@ -766,16 +710,12 @@ public: auto aliceStat = txQ.getAccountTxs(alice.id()); BEAST_EXPECT(aliceStat.size() == 1); BEAST_EXPECT(aliceStat.begin()->feeLevel == baseFeeLevel); - BEAST_EXPECT( - aliceStat.begin()->lastValid && - *aliceStat.begin()->lastValid == 8); + BEAST_EXPECT(aliceStat.begin()->lastValid && *aliceStat.begin()->lastValid == 8); BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker()); auto bobStat = txQ.getAccountTxs(bob.id()); BEAST_EXPECT(bobStat.size() == 1); - BEAST_EXPECT( - bobStat.begin()->feeLevel == - FeeLevel64{baseFeeLevel.fee() * largeFeeMultiplier}); + BEAST_EXPECT(bobStat.begin()->feeLevel == FeeLevel64{baseFeeLevel.fee() * largeFeeMultiplier}); BEAST_EXPECT(!bobStat.begin()->lastValid); BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker()); @@ -996,13 +936,11 @@ public: Env::ParsedResult parsed; - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) { - auto const result = ripple::apply( - env.app(), view, *jt.stx, tapNONE, env.journal); - parsed.ter = result.ter; - return result.applied; - }); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { + auto const result = xrpl::apply(env.app(), view, *jt.stx, tapNONE, env.journal); + parsed.ter = result.ter; + return result.applied; + }); env.postconditions(jt, parsed); } checkMetrics(*this, env, 1, std::nullopt, 4, 2); @@ -1022,8 +960,7 @@ public: Env env( *this, makeConfig( - {{"minimum_txn_in_ledger_standalone", "3"}}, - {{"account_reserve", "200"}, {"owner_reserve", "50"}})); + {{"minimum_txn_in_ledger_standalone", "3"}}, {{"account_reserve", "200"}, {"owner_reserve", "50"}})); auto alice = Account("alice"); auto bob = Account("bob"); @@ -1073,7 +1010,7 @@ public: // Charlie - queue a transaction, with a higher fee // than default env(noop(charlie), fee(15), queued); - checkMetrics(*this, env, 6, initQueueMax, 4, 3); + checkMetrics(*this, env, 6, initQueueMax, 4, 3, 257); BEAST_EXPECT(env.seq(alice) == aliceSeq); BEAST_EXPECT(env.seq(bob) == bobSeq); @@ -1094,14 +1031,10 @@ public: // Alice - fill up the queue std::int64_t aliceFee = 27; aliceSeq = env.seq(alice); - auto lastLedgerSeq = env.current()->info().seq + 2; + auto lastLedgerSeq = env.current()->header().seq + 2; for (auto i = 0; i < 7; i++) { - env(noop(alice), - seq(aliceSeq), - json(jss::LastLedgerSequence, lastLedgerSeq + i), - fee(--aliceFee), - queued); + env(noop(alice), seq(aliceSeq), json(jss::LastLedgerSequence, lastLedgerSeq + i), fee(--aliceFee), queued); ++aliceSeq; } checkMetrics(*this, env, 8, 8, 5, 4, 513); @@ -1115,12 +1048,10 @@ public: for (auto const& tx : aliceStat) { BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq); - BEAST_EXPECT( - tx.feeLevel == toFeeLevel(XRPAmount(--aliceFee), baseFee)); + BEAST_EXPECT(tx.feeLevel == toFeeLevel(XRPAmount(--aliceFee), baseFee)); BEAST_EXPECT(tx.lastValid); BEAST_EXPECT( - (tx.consequences.fee() == drops(aliceFee) && - tx.consequences.potentialSpend() == drops(0) && + (tx.consequences.fee() == drops(aliceFee) && tx.consequences.potentialSpend() == drops(0) && !tx.consequences.isBlocker()) || tx.seqProxy.value() == env.seq(alice) + 6); ++seq; @@ -1157,20 +1088,14 @@ public: // Alice wants this tx more than the dropped tx, // so resubmits with higher fee, but the queue // is full, and her account is the cheapest. - env(noop(alice), - seq(aliceSeq - 1), - fee(aliceFee), - ter(telCAN_NOT_QUEUE_FULL)); + env(noop(alice), seq(aliceSeq - 1), fee(aliceFee), ter(telCAN_NOT_QUEUE_FULL)); checkMetrics(*this, env, 8, 8, 5, 4, 538); // Try to replace a middle item in the queue // without enough fee. aliceSeq = env.seq(alice) + 2; aliceFee = 29; - env(noop(alice), - seq(aliceSeq), - fee(aliceFee), - ter(telCAN_NOT_QUEUE_FEE)); + env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE_FEE)); checkMetrics(*this, env, 8, 8, 5, 4, 538); // Replace a middle item from the queue successfully @@ -1190,12 +1115,8 @@ public: // bankrupt Alice. Fails, because an account can't have // more than the minimum reserve in flight before the // last queued transaction - aliceFee = - env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62); - env(noop(alice), - seq(aliceSeq), - fee(aliceFee), - ter(telCAN_NOT_QUEUE_BALANCE)); + aliceFee = env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62); + env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 4, 10, 6, 5); // Try to spend more than Alice can afford with all the other txs. @@ -1214,10 +1135,7 @@ public: // the fee is checked against the balance aliceFee /= 5; ++aliceSeq; - env(noop(alice), - seq(aliceSeq), - fee(aliceFee), - ter(telCAN_NOT_QUEUE_BALANCE)); + env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 4, 10, 6, 5); env.close(); @@ -1250,12 +1168,8 @@ public: // Try to replace a middle item in the queue // with enough fee to bankrupt bob and make the // later transactions unable to pay their fees - std::int64_t bobFee = - env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1); - env(noop(bob), - seq(bobSeq + 5), - fee(bobFee), - ter(telCAN_NOT_QUEUE_BALANCE)); + std::int64_t bobFee = env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1); + env(noop(bob), seq(bobSeq + 5), fee(bobFee), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 10, 12, 7, 6); // Attempt to replace a middle item in the queue with enough fee @@ -1264,12 +1178,8 @@ public: // // The attempt fails because the sum of bob's fees now exceeds the // (artificially lowered to 200 drops) account reserve. - bobFee = - env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10); - env(noop(bob), - seq(bobSeq + 5), - fee(bobFee), - ter(telCAN_NOT_QUEUE_BALANCE)); + bobFee = env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10); + env(noop(bob), seq(bobSeq + 5), fee(bobFee), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 10, 12, 7, 6); // Close the ledger and verify that the queued transactions succeed @@ -1380,44 +1290,29 @@ public: // This next test should remain unchanged regardless of // transaction ordering BEAST_EXPECT( - aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq + - gwenSeq + hankSeq + 6 == - env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) + - env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank)); + aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq + gwenSeq + hankSeq + 6 == + env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) + env.seq(elmo) + env.seq(fred) + + env.seq(gwen) + env.seq(hank)); // These tests may change if TxQ ordering is changed using namespace std::string_literals; BEAST_EXPECTS( - aliceSeq == env.seq(alice), - "alice: "s + std::to_string(aliceSeq) + ", " + - std::to_string(env.seq(alice))); + aliceSeq == env.seq(alice), "alice: "s + std::to_string(aliceSeq) + ", " + std::to_string(env.seq(alice))); BEAST_EXPECTS( - bobSeq + 1 == env.seq(bob), - "bob: "s + std::to_string(bobSeq) + ", " + - std::to_string(env.seq(bob))); + bobSeq + 1 == env.seq(bob), "bob: "s + std::to_string(bobSeq) + ", " + std::to_string(env.seq(bob))); BEAST_EXPECTS( charlieSeq + 2 == env.seq(charlie), - "charlie: "s + std::to_string(charlieSeq) + ", " + - std::to_string(env.seq(charlie))); + "charlie: "s + std::to_string(charlieSeq) + ", " + std::to_string(env.seq(charlie))); BEAST_EXPECTS( dariaSeq + 1 == env.seq(daria), - "daria: "s + std::to_string(dariaSeq) + ", " + - std::to_string(env.seq(daria))); + "daria: "s + std::to_string(dariaSeq) + ", " + std::to_string(env.seq(daria))); BEAST_EXPECTS( - elmoSeq + 1 == env.seq(elmo), - "elmo: "s + std::to_string(elmoSeq) + ", " + - std::to_string(env.seq(elmo))); + elmoSeq + 1 == env.seq(elmo), "elmo: "s + std::to_string(elmoSeq) + ", " + std::to_string(env.seq(elmo))); BEAST_EXPECTS( - fredSeq == env.seq(fred), - "fred: "s + std::to_string(fredSeq) + ", " + - std::to_string(env.seq(fred))); + fredSeq == env.seq(fred), "fred: "s + std::to_string(fredSeq) + ", " + std::to_string(env.seq(fred))); BEAST_EXPECTS( - gwenSeq == env.seq(gwen), - "gwen: "s + std::to_string(gwenSeq) + ", " + - std::to_string(env.seq(gwen))); + gwenSeq == env.seq(gwen), "gwen: "s + std::to_string(gwenSeq) + ", " + std::to_string(env.seq(gwen))); BEAST_EXPECTS( - hankSeq + 1 == env.seq(hank), - "hank: "s + std::to_string(hankSeq) + ", " + - std::to_string(env.seq(hank))); + hankSeq + 1 == env.seq(hank), "hank: "s + std::to_string(hankSeq) + ", " + std::to_string(env.seq(hank))); // Which sequences get incremented may change if TxQ ordering is // changed @@ -1443,19 +1338,10 @@ public: BEAST_EXPECT(qTxCount1.size() <= 3); // Fill up the queue again - env(noop(alice), - seq(aliceSeq + qTxCount1[alice.id()]++), - fee(15), - queued); + env(noop(alice), seq(aliceSeq + qTxCount1[alice.id()]++), fee(15), queued); env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15), queued); - env(noop(charlie), - seq(charlieSeq + qTxCount1[charlie.id()]++), - fee(15), - queued); - env(noop(daria), - seq(dariaSeq + qTxCount1[daria.id()]++), - fee(15), - queued); + env(noop(charlie), seq(charlieSeq + qTxCount1[charlie.id()]++), fee(15), queued); + env(noop(daria), seq(dariaSeq + qTxCount1[daria.id()]++), fee(15), queued); env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15), queued); env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15), queued); env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15), queued); @@ -1466,10 +1352,7 @@ public: // Add another transaction, with a higher fee, // Not high enough to get into the ledger, but high // enough to get into the queue (and kick somebody out) - env(noop(alice), - fee(100), - seq(aliceSeq + qTxCount1[alice.id()]++), - queued); + env(noop(alice), fee(100), seq(aliceSeq + qTxCount1[alice.id()]++), queued); checkMetrics(*this, env, 10, 10, 6, 5, minFeeLevel); @@ -1486,50 +1369,34 @@ public: // This next test should remain unchanged regardless of // transaction ordering BEAST_EXPECT( - aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq + - gwenSeq + hankSeq + 7 == - env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) + - env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank)); + aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq + gwenSeq + hankSeq + 7 == + env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) + env.seq(elmo) + env.seq(fred) + + env.seq(gwen) + env.seq(hank)); // These tests may change if TxQ ordering is changed BEAST_EXPECTS( - aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] == - env.seq(alice), - "alice: "s + std::to_string(aliceSeq) + ", " + - std::to_string(env.seq(alice))); + aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] == env.seq(alice), + "alice: "s + std::to_string(aliceSeq) + ", " + std::to_string(env.seq(alice))); BEAST_EXPECTS( bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.seq(bob), - "bob: "s + std::to_string(bobSeq) + ", " + - std::to_string(env.seq(bob))); + "bob: "s + std::to_string(bobSeq) + ", " + std::to_string(env.seq(bob))); BEAST_EXPECTS( - charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] == - env.seq(charlie), - "charlie: "s + std::to_string(charlieSeq) + ", " + - std::to_string(env.seq(charlie))); + charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] == env.seq(charlie), + "charlie: "s + std::to_string(charlieSeq) + ", " + std::to_string(env.seq(charlie))); BEAST_EXPECTS( - dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] == - env.seq(daria), - "daria: "s + std::to_string(dariaSeq) + ", " + - std::to_string(env.seq(daria))); + dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] == env.seq(daria), + "daria: "s + std::to_string(dariaSeq) + ", " + std::to_string(env.seq(daria))); BEAST_EXPECTS( - elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] == - env.seq(elmo), - "elmo: "s + std::to_string(elmoSeq) + ", " + - std::to_string(env.seq(elmo))); + elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] == env.seq(elmo), + "elmo: "s + std::to_string(elmoSeq) + ", " + std::to_string(env.seq(elmo))); BEAST_EXPECTS( - fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] == - env.seq(fred), - "fred: "s + std::to_string(fredSeq) + ", " + - std::to_string(env.seq(fred))); + fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] == env.seq(fred), + "fred: "s + std::to_string(fredSeq) + ", " + std::to_string(env.seq(fred))); BEAST_EXPECTS( - gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] == - env.seq(gwen), - "gwen: "s + std::to_string(gwenSeq) + ", " + - std::to_string(env.seq(gwen))); + gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] == env.seq(gwen), + "gwen: "s + std::to_string(gwenSeq) + ", " + std::to_string(env.seq(gwen))); BEAST_EXPECTS( - hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] == - env.seq(hank), - "hank: "s + std::to_string(hankSeq) + ", " + - std::to_string(env.seq(hank))); + hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] == env.seq(hank), + "hank: "s + std::to_string(hankSeq) + ", " + std::to_string(env.seq(hank))); } void @@ -1553,9 +1420,7 @@ public: // Immediately after the fset, the sfAccountTxnID field // is still uninitialized, so preflight succeeds here, // and this txn fails because it can't be stored in the queue. - env(noop(alice), - json(R"({"AccountTxnID": "0"})"), - ter(telCAN_NOT_QUEUE)); + env(noop(alice), json(R"({"AccountTxnID": "0"})"), ter(telCAN_NOT_QUEUE)); checkMetrics(*this, env, 0, std::nullopt, 2, 1); env.close(); @@ -1602,10 +1467,8 @@ public: // calculate median fee level. if (i == 4) { - double const feeMultiplier = - static_cast(cost.drops()) / baseFee; - medFeeLevel = FeeLevel64{static_cast( - feeMultiplier * baseFeeLevel.fee())}; + double const feeMultiplier = static_cast(cost.drops()) / baseFee; + medFeeLevel = FeeLevel64{static_cast(feeMultiplier * baseFeeLevel.fee())}; } env(noop(alice), fee(cost)); @@ -1694,8 +1557,7 @@ public: Env env( *this, makeConfig( - {{"minimum_txn_in_ledger_standalone", "3"}}, - {{"account_reserve", "200"}, {"owner_reserve", "50"}})); + {{"minimum_txn_in_ledger_standalone", "3"}}, {{"account_reserve", "200"}, {"owner_reserve", "50"}})); auto alice = Account("alice"); auto bob = Account("bob"); @@ -1735,16 +1597,12 @@ public: // up to Alice's reserve. env(offer(bob, drops(5000), USD(5000)), fee(openLedgerCost(env)), - require( - balance(alice, drops(250)), owners(alice, 1), lines(alice, 1))); + require(balance(alice, drops(250)), owners(alice, 1), lines(alice, 1))); checkMetrics(*this, env, 4, 6, 5, 3); // Try adding a new transaction. // Too many fees in flight. - env(noop(alice), - fee(drops(200)), - seq(aliceSeq + 1), - ter(telCAN_NOT_QUEUE_BALANCE)); + env(noop(alice), fee(drops(200)), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 4, 6, 5, 3); // Close the ledger. All of Alice's transactions @@ -1755,10 +1613,7 @@ public: // Still can't add a new transaction for Alice, // no matter the fee. - env(noop(alice), - fee(drops(200)), - seq(aliceSeq + 1), - ter(telCAN_NOT_QUEUE_BALANCE)); + env(noop(alice), fee(drops(200)), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 1, 10, 3, 5); /* At this point, Alice's transaction is indefinitely @@ -1817,15 +1672,9 @@ public: env(noop(alice), seq(aliceSeq + 1), queued); // Can't replace either queued transaction with a blocker - env(fset(alice, asfAccountTxnID), - seq(aliceSeq + 0), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(fset(alice, asfAccountTxnID), seq(aliceSeq + 0), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); - env(regkey(alice, bob), - seq(aliceSeq + 1), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(regkey(alice, bob), seq(aliceSeq + 1), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); // Can't append a blocker to the queue. env(signers(alice, 2, {{bob}, {charlie}, {daria}}), @@ -1852,10 +1701,7 @@ public: // Since there's only one entry in the queue we can replace // that entry with a blocker. - env(regkey(alice, bob), - seq(aliceSeq + 0), - fee(baseFee * 2), - queued); + env(regkey(alice, bob), seq(aliceSeq + 0), fee(baseFee * 2), queued); // Now that there's a blocker in the queue we can't append to // the queue. @@ -1865,10 +1711,7 @@ public: env(noop(bob), queued); // We can replace the blocker with a different blocker. - env(signers(alice, 2, {{bob}, {charlie}, {daria}}), - seq(aliceSeq + 0), - fee(baseFee * 2.6), - queued); + env(signers(alice, 2, {{bob}, {charlie}, {daria}}), seq(aliceSeq + 0), fee(baseFee * 2.6), queued); // Prove that the queue is still blocked. env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED)); @@ -1952,20 +1795,12 @@ public: env(noop(alice), ticket::use(tkt + 1), queued); // Can't replace either queued transaction with a blocker - env(fset(alice, asfAccountTxnID), - ticket::use(tkt + 1), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(fset(alice, asfAccountTxnID), ticket::use(tkt + 1), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); - env(regkey(alice, bob), - ticket::use(tkt + 2), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(regkey(alice, bob), ticket::use(tkt + 2), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); // Can't append a blocker to the queue. - env(signers(alice, 2, {{bob}, {charlie}, {daria}}), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(signers(alice, 2, {{bob}, {charlie}, {daria}}), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); env(signers(alice, 2, {{bob}, {charlie}, {daria}}), ticket::use(tkt + 0), @@ -1996,41 +1831,26 @@ public: // Since there's an entry in the queue we cannot append a // blocker to the account's queue. - env(regkey(alice, bob), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); - env(regkey(alice, bob), - ticket::use(tkt + 1), - fee(baseFee * 2), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(regkey(alice, bob), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); + env(regkey(alice, bob), ticket::use(tkt + 1), fee(baseFee * 2), ter(telCAN_NOT_QUEUE_BLOCKS)); // However we can _replace_ that lone entry with a blocker. - env(regkey(alice, bob), - ticket::use(tkt + 0), - fee(baseFee * 2), - queued); + env(regkey(alice, bob), ticket::use(tkt + 0), fee(baseFee * 2), queued); // Now that there's a blocker in the queue we can't append to // the queue. env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED)); - env(noop(alice), - ticket::use(tkt + 1), - ter(telCAN_NOT_QUEUE_BLOCKED)); + env(noop(alice), ticket::use(tkt + 1), ter(telCAN_NOT_QUEUE_BLOCKED)); // Other accounts are unaffected. env(noop(bob), queued); // We can replace the blocker with a different blocker. - env(signers(alice, 2, {{bob}, {charlie}, {daria}}), - ticket::use(tkt + 0), - fee(baseFee * 2.6), - queued); + env(signers(alice, 2, {{bob}, {charlie}, {daria}}), ticket::use(tkt + 0), fee(baseFee * 2.6), queued); // Prove that the queue is still blocked. env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED)); - env(noop(alice), - ticket::use(tkt + 1), - ter(telCAN_NOT_QUEUE_BLOCKED)); + env(noop(alice), ticket::use(tkt + 1), ter(telCAN_NOT_QUEUE_BLOCKED)); // We can replace the blocker with a non-blocker. Then we can // successfully append to the queue. @@ -2060,9 +1880,7 @@ public: // Since there's a blocker in the queue we can't append to // the queue. - env(noop(alice), - ticket::use(tkt + 1), - ter(telCAN_NOT_QUEUE_BLOCKED)); + env(noop(alice), ticket::use(tkt + 1), ter(telCAN_NOT_QUEUE_BLOCKED)); // Other accounts are unaffected. env(noop(bob), queued); @@ -2087,8 +1905,7 @@ public: Env env( *this, makeConfig( - {{"minimum_txn_in_ledger_standalone", "3"}}, - {{"account_reserve", "200"}, {"owner_reserve", "50"}})); + {{"minimum_txn_in_ledger_standalone", "3"}}, {{"account_reserve", "200"}, {"owner_reserve", "50"}})); auto alice = Account("alice"); auto charlie = Account("charlie"); @@ -2162,10 +1979,7 @@ public: // So even a noop will look like alice // doesn't have the balance to pay the fee - env(noop(alice), - fee(drops(51)), - seq(aliceSeq + 2), - ter(terINSUF_FEE_B)); + env(noop(alice), fee(drops(51)), seq(aliceSeq + 2), ter(terINSUF_FEE_B)); checkMetrics(*this, env, 2, limit * 2, limit + 1, limit); env.close(); @@ -2195,10 +2009,7 @@ public: // So even a noop will look like alice // doesn't have the balance to pay the fee - env(noop(alice), - fee(drops(51)), - seq(aliceSeq + 1), - ter(telCAN_NOT_QUEUE_BALANCE)); + env(noop(alice), fee(drops(51)), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 1, limit * 2, limit + 1, limit); env.close(); @@ -2286,8 +2097,7 @@ public: checkMetrics(*this, env, 0, limit * 2, 2, limit); // The payment succeeds - env.require( - balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0)); + env.require(balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0)); ////////////////////////////////////////// // Large IOU payment allows later txs @@ -2446,12 +2256,7 @@ public: env.memoize("carol"); { auto const jtx = env.jt(offer_cancel(alice, 3), seq(5), fee(10)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(10)); @@ -2461,14 +2266,8 @@ public: { auto USD = alice["USD"]; - auto const jtx = - env.jt(trust("carol", USD(50000000)), seq(1), fee(10)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + auto const jtx = env.jt(trust("carol", USD(50000000)), seq(1), fee(10)); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(10)); @@ -2477,12 +2276,7 @@ public: { auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10)); - auto const pf = preflight( - env.app(), - env.current()->rules(), - *jtx.stx, - tapNONE, - env.journal); + auto const pf = preflight(env.app(), env.current()->rules(), *jtx.stx, tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(pf.consequences.fee() == drops(10)); @@ -2590,18 +2384,9 @@ public: // Charlie is paying a high enough fee to go straight into the // ledger in order to get into the vicinity of an assert which // should no longer fire :-). - env(noop(charlie), - fee(baseFee * 800), - seq(charlieSeq - 1), - ter(tefPAST_SEQ)); - env(noop(charlie), - fee(baseFee * 800), - seq(charlieSeq + 1), - ter(terPRE_SEQ)); - env(noop(charlie), - fee(baseFee * 800), - seq(charlieSeq), - ter(tesSUCCESS)); + env(noop(charlie), fee(baseFee * 800), seq(charlieSeq - 1), ter(tefPAST_SEQ)); + env(noop(charlie), fee(baseFee * 800), seq(charlieSeq + 1), ter(terPRE_SEQ)); + env(noop(charlie), fee(baseFee * 800), seq(charlieSeq), ter(tesSUCCESS)); } void @@ -2614,13 +2399,10 @@ public: auto fee = env.rpc("fee"); - if (BEAST_EXPECT(fee.isMember(jss::result)) && - BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) + if (BEAST_EXPECT(fee.isMember(jss::result)) && BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) { auto const& result = fee[jss::result]; - BEAST_EXPECT( - result.isMember(jss::ledger_current_index) && - result[jss::ledger_current_index] == 3); + BEAST_EXPECT(result.isMember(jss::ledger_current_index) && result[jss::ledger_current_index] == 3); BEAST_EXPECT(result.isMember(jss::current_ledger_size)); BEAST_EXPECT(result.isMember(jss::current_queue_size)); BEAST_EXPECT(result.isMember(jss::expected_ledger_size)); @@ -2643,13 +2425,10 @@ public: fee = env.rpc("fee"); - if (BEAST_EXPECT(fee.isMember(jss::result)) && - BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) + if (BEAST_EXPECT(fee.isMember(jss::result)) && BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) { auto const& result = fee[jss::result]; - BEAST_EXPECT( - result.isMember(jss::ledger_current_index) && - result[jss::ledger_current_index] == 4); + BEAST_EXPECT(result.isMember(jss::ledger_current_index) && result[jss::ledger_current_index] == 4); BEAST_EXPECT(result.isMember(jss::current_ledger_size)); BEAST_EXPECT(result.isMember(jss::current_queue_size)); BEAST_EXPECT(result.isMember(jss::expected_ledger_size)); @@ -2702,17 +2481,11 @@ public: checkMetrics(*this, env, 0, std::nullopt, 2, 1); auto const aliceSeq = env.seq(alice); - BEAST_EXPECT(env.current()->info().seq == 3); + BEAST_EXPECT(env.current()->header().seq == 3); env(noop(alice), seq(aliceSeq), last_ledger_seq(5), ter(terQUEUED)); env(noop(alice), seq(aliceSeq + 1), last_ledger_seq(5), ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 2), - last_ledger_seq(10), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 3), - last_ledger_seq(11), - ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 2), last_ledger_seq(10), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 3), last_ledger_seq(11), ter(terQUEUED)); checkMetrics(*this, env, 4, std::nullopt, 2, 1); auto const bobSeq = env.seq(bob); // Ledger 4 gets 3, @@ -2738,9 +2511,7 @@ public: env(noop(alice), seq(aliceSeq + 1), ter(terPRE_SEQ)); // Cannot fill the gap with a blocker since Alice's queue is not empty. - env(fset(alice, asfAccountTxnID), - seq(aliceSeq), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(fset(alice, asfAccountTxnID), seq(aliceSeq), ter(telCAN_NOT_QUEUE_BLOCKS)); checkMetrics(*this, env, 2, 40, 5, 4); // However we can fill the gap with a non-blocker. @@ -2748,9 +2519,7 @@ public: checkMetrics(*this, env, 3, 40, 5, 4); // Attempt to queue up a new aliceSeq + 1 tx that's a blocker. - env(fset(alice, asfAccountTxnID), - seq(aliceSeq + 1), - ter(telCAN_NOT_QUEUE_BLOCKS)); + env(fset(alice, asfAccountTxnID), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKS)); checkMetrics(*this, env, 3, 40, 5, 4); // Queue up a non-blocker replacement for aliceSeq + 1. @@ -2780,9 +2549,7 @@ public: testcase("full queue gap handling"); auto cfg = makeConfig( - {{"minimum_txn_in_ledger_standalone", "1"}, - {"ledgers_in_queue", "10"}, - {"maximum_txn_per_account", "11"}}); + {{"minimum_txn_in_ledger_standalone", "1"}, {"ledgers_in_queue", "10"}, {"maximum_txn_per_account", "11"}}); cfg->FEES.reference_fee = 10; Env env(*this, std::move(cfg)); @@ -2798,50 +2565,20 @@ public: checkMetrics(*this, env, 0, std::nullopt, 2, 1); auto const aliceSeq = env.seq(alice); - BEAST_EXPECT(env.current()->info().seq == 3); + BEAST_EXPECT(env.current()->header().seq == 3); // Start by procuring tickets for alice to use to keep her queue full // without affecting the sequence gap that will appear later. - env(ticket::create(alice, 11), - seq(aliceSeq + 0), - fee(baseFee * 20 + 1), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 11), - last_ledger_seq(11), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 12), - last_ledger_seq(11), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 13), - last_ledger_seq(11), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 14), - last_ledger_seq(11), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 15), - last_ledger_seq(11), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 16), - last_ledger_seq(5), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 17), - last_ledger_seq(5), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 18), - last_ledger_seq(5), - ter(terQUEUED)); - env(noop(alice), - seq(aliceSeq + 19), - last_ledger_seq(11), - ter(terQUEUED)); + env(ticket::create(alice, 11), seq(aliceSeq + 0), fee(baseFee * 20 + 1), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 11), last_ledger_seq(11), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 12), last_ledger_seq(11), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 13), last_ledger_seq(11), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 14), last_ledger_seq(11), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 15), last_ledger_seq(11), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 16), last_ledger_seq(5), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 17), last_ledger_seq(5), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 18), last_ledger_seq(5), ter(terQUEUED)); + env(noop(alice), seq(aliceSeq + 19), last_ledger_seq(11), ter(terQUEUED)); checkMetrics(*this, env, 10, std::nullopt, 2, 1); auto const bobSeq = env.seq(bob); @@ -2951,7 +2688,7 @@ public: // Queue up several transactions for alice sign-and-submit auto const aliceSeq = env.seq(alice); - auto const lastLedgerSeq = env.current()->info().seq + 2; + auto const lastLedgerSeq = env.current()->header().seq + 2; auto submitParams = Json::Value(Json::objectValue); for (int i = 0; i < 5; ++i) @@ -2964,9 +2701,7 @@ public: json(jss::LastLedgerSequence, lastLedgerSeq), ter(terQUEUED))(submitParams); else - envs( - noop(alice), fee(baseFee * 100), seq(none), ter(terQUEUED))( - submitParams); + envs(noop(alice), fee(baseFee * 100), seq(none), ter(terQUEUED))(submitParams); } checkMetrics(*this, env, 5, std::nullopt, 7, 6); { @@ -2976,12 +2711,10 @@ public: for (auto const& tx : aliceStat) { BEAST_EXPECT(tx.seqProxy == seq); - BEAST_EXPECT( - tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 100}); + BEAST_EXPECT(tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 100}); if (seq.value() == aliceSeq + 2) { - BEAST_EXPECT( - tx.lastValid && *tx.lastValid == lastLedgerSeq); + BEAST_EXPECT(tx.lastValid && *tx.lastValid == lastLedgerSeq); } else { @@ -3031,15 +2764,13 @@ public: ++seq; BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq); - BEAST_EXPECT( - tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 100}); + BEAST_EXPECT(tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 100}); BEAST_EXPECT(!tx.lastValid); ++seq; } } // Now, fill the gap. - envs(noop(alice), fee(baseFee * 100), seq(none), ter(terQUEUED))( - submitParams); + envs(noop(alice), fee(baseFee * 100), seq(none), ter(terQUEUED))(submitParams); checkMetrics(*this, env, 5, 18, 10, 9); { auto aliceStat = txQ.getAccountTxs(alice.id()); @@ -3092,24 +2823,18 @@ public: prevLedgerWithQueue[jss::account] = alice.human(); prevLedgerWithQueue[jss::queue] = true; prevLedgerWithQueue[jss::ledger_index] = 3; - BEAST_EXPECT(env.current()->info().seq > 3); + BEAST_EXPECT(env.current()->header().seq > 3); { // account_info without the "queue" argument. - auto const info = - env.rpc("json", "account_info", to_string(withoutQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withoutQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data)); } { // account_info with the "queue" argument. - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; BEAST_EXPECT(result.isMember(jss::queue_data)); auto const& queue_data = result[jss::queue_data]; @@ -3128,11 +2853,8 @@ public: checkMetrics(*this, env, 0, 6, 4, 3); { - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; BEAST_EXPECT(result.isMember(jss::queue_data)); auto const& queue_data = result[jss::queue_data]; @@ -3147,22 +2869,15 @@ public: } auto submitParams = Json::Value(Json::objectValue); - envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))( - submitParams); - envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))( - submitParams); - envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))( - submitParams); - envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))( - submitParams); + envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))(submitParams); + envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))(submitParams); + envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))(submitParams); + envs(noop(alice), fee(baseFee * 10), seq(none), ter(terQUEUED))(submitParams); checkMetrics(*this, env, 4, 6, 4, 3); { - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; auto const& data = result[jss::account_data]; BEAST_EXPECT(result.isMember(jss::queue_data)); @@ -3171,19 +2886,15 @@ public: BEAST_EXPECT(queue_data.isMember(jss::txn_count)); BEAST_EXPECT(queue_data[jss::txn_count] == 4); BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence)); - BEAST_EXPECT( - queue_data[jss::lowest_sequence] == data[jss::Sequence]); + BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]); BEAST_EXPECT(queue_data.isMember(jss::highest_sequence)); BEAST_EXPECT( queue_data[jss::highest_sequence] == - data[jss::Sequence].asUInt() + - queue_data[jss::txn_count].asUInt() - 1); + data[jss::Sequence].asUInt() + queue_data[jss::txn_count].asUInt() - 1); BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued)); BEAST_EXPECT(queue_data[jss::auth_change_queued] == false); BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total)); - BEAST_EXPECT( - queue_data[jss::max_spend_drops_total] == - std::to_string(baseFee * 40)); + BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == std::to_string(baseFee * 40)); BEAST_EXPECT(queue_data.isMember(jss::transactions)); auto const& queued = queue_data[jss::transactions]; BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]); @@ -3191,16 +2902,13 @@ public: { auto const& item = queued[i]; BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i); - BEAST_EXPECT( - item[jss::fee_level] == - std::to_string(baseFeeLevel.fee() * 10)); + BEAST_EXPECT(item[jss::fee_level] == std::to_string(baseFeeLevel.fee() * 10)); BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence)); BEAST_EXPECT(item.isMember(jss::fee)); BEAST_EXPECT(item[jss::fee] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::max_spend_drops)); - BEAST_EXPECT( - item[jss::max_spend_drops] == std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::max_spend_drops] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::auth_change)); BEAST_EXPECT(item[jss::auth_change].asBool() == false); } @@ -3222,11 +2930,8 @@ public: checkMetrics(*this, env, 1, 8, 5, 4); { - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; auto const& data = result[jss::account_data]; BEAST_EXPECT(result.isMember(jss::queue_data)); @@ -3235,19 +2940,15 @@ public: BEAST_EXPECT(queue_data.isMember(jss::txn_count)); BEAST_EXPECT(queue_data[jss::txn_count] == 1); BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence)); - BEAST_EXPECT( - queue_data[jss::lowest_sequence] == data[jss::Sequence]); + BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]); BEAST_EXPECT(queue_data.isMember(jss::highest_sequence)); BEAST_EXPECT( queue_data[jss::highest_sequence] == - data[jss::Sequence].asUInt() + - queue_data[jss::txn_count].asUInt() - 1); + data[jss::Sequence].asUInt() + queue_data[jss::txn_count].asUInt() - 1); BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued)); BEAST_EXPECT(queue_data[jss::auth_change_queued] == true); BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total)); - BEAST_EXPECT( - queue_data[jss::max_spend_drops_total] == - std::to_string(baseFee * 10)); + BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == std::to_string(baseFee * 10)); BEAST_EXPECT(queue_data.isMember(jss::transactions)); auto const& queued = queue_data[jss::transactions]; BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]); @@ -3255,14 +2956,11 @@ public: { auto const& item = queued[i]; BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i); - BEAST_EXPECT( - item[jss::fee_level] == - std::to_string(baseFeeLevel.fee() * 10)); + BEAST_EXPECT(item[jss::fee_level] == std::to_string(baseFeeLevel.fee() * 10)); BEAST_EXPECT(item.isMember(jss::fee)); BEAST_EXPECT(item[jss::fee] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::max_spend_drops)); - BEAST_EXPECT( - item[jss::max_spend_drops] == std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::max_spend_drops] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::auth_change)); if (i == queued.size() - 1) @@ -3279,19 +2977,12 @@ public: } } - envs( - noop(alice), - fee(baseFee * 10), - seq(none), - ter(telCAN_NOT_QUEUE_BLOCKED))(submitParams); + envs(noop(alice), fee(baseFee * 10), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(submitParams); checkMetrics(*this, env, 1, 8, 5, 4); { - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; auto const& data = result[jss::account_data]; BEAST_EXPECT(result.isMember(jss::queue_data)); @@ -3300,19 +2991,15 @@ public: BEAST_EXPECT(queue_data.isMember(jss::txn_count)); BEAST_EXPECT(queue_data[jss::txn_count] == 1); BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence)); - BEAST_EXPECT( - queue_data[jss::lowest_sequence] == data[jss::Sequence]); + BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]); BEAST_EXPECT(queue_data.isMember(jss::highest_sequence)); BEAST_EXPECT( queue_data[jss::highest_sequence] == - data[jss::Sequence].asUInt() + - queue_data[jss::txn_count].asUInt() - 1); + data[jss::Sequence].asUInt() + queue_data[jss::txn_count].asUInt() - 1); BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued)); BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool()); BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total)); - BEAST_EXPECT( - queue_data[jss::max_spend_drops_total] == - std::to_string(baseFee * 10)); + BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == std::to_string(baseFee * 10)); BEAST_EXPECT(queue_data.isMember(jss::transactions)); auto const& queued = queue_data[jss::transactions]; BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]); @@ -3320,19 +3007,14 @@ public: { auto const& item = queued[i]; BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i); - BEAST_EXPECT( - item[jss::fee_level] == - std::to_string(baseFeeLevel.fee() * 10)); + BEAST_EXPECT(item[jss::fee_level] == std::to_string(baseFeeLevel.fee() * 10)); if (i == queued.size() - 1) { BEAST_EXPECT(item.isMember(jss::fee)); - BEAST_EXPECT( - item[jss::fee] == std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::fee] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::max_spend_drops)); - BEAST_EXPECT( - item[jss::max_spend_drops] == - std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::max_spend_drops] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::auth_change)); BEAST_EXPECT(item[jss::auth_change].asBool()); BEAST_EXPECT(item.isMember(jss::LastLedgerSequence)); @@ -3341,12 +3023,9 @@ public: else { BEAST_EXPECT(item.isMember(jss::fee)); - BEAST_EXPECT( - item[jss::fee] == std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::fee] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::max_spend_drops)); - BEAST_EXPECT( - item[jss::max_spend_drops] == - std::to_string(baseFee * 10)); + BEAST_EXPECT(item[jss::max_spend_drops] == std::to_string(baseFee * 10)); BEAST_EXPECT(item.isMember(jss::auth_change)); BEAST_EXPECT(!item[jss::auth_change].asBool()); BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence)); @@ -3355,11 +3034,8 @@ public: } { - auto const info = - env.rpc("json", "account_info", to_string(prevLedgerWithQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - RPC::contains_error(info[jss::result])); + auto const info = env.rpc("json", "account_info", to_string(prevLedgerWithQueue)); + BEAST_EXPECT(info.isMember(jss::result) && RPC::contains_error(info[jss::result])); } env.close(); @@ -3368,11 +3044,8 @@ public: checkMetrics(*this, env, 0, 10, 0, 5); { - auto const info = - env.rpc("json", "account_info", to_string(withQueue)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withQueue)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& result = info[jss::result]; BEAST_EXPECT(result.isMember(jss::queue_data)); auto const& queue_data = result[jss::queue_data]; @@ -3403,12 +3076,9 @@ public: { auto const server_info = env.rpc("server_info"); - BEAST_EXPECT( - server_info.isMember(jss::result) && - server_info[jss::result].isMember(jss::info)); + BEAST_EXPECT(server_info.isMember(jss::result) && server_info[jss::result].isMember(jss::info)); auto const& info = server_info[jss::result][jss::info]; - BEAST_EXPECT( - info.isMember(jss::load_factor) && info[jss::load_factor] == 1); + BEAST_EXPECT(info.isMember(jss::load_factor) && info[jss::load_factor] == 1); BEAST_EXPECT(!info.isMember(jss::load_factor_server)); BEAST_EXPECT(!info.isMember(jss::load_factor_local)); BEAST_EXPECT(!info.isMember(jss::load_factor_net)); @@ -3417,23 +3087,14 @@ public: { auto const server_state = env.rpc("server_state"); auto const& state = server_state[jss::result][jss::state]; + BEAST_EXPECT(state.isMember(jss::load_factor) && state[jss::load_factor] == 256); + BEAST_EXPECT(state.isMember(jss::load_base) && state[jss::load_base] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor_server) && state[jss::load_factor_server] == 256); BEAST_EXPECT( - state.isMember(jss::load_factor) && - state[jss::load_factor] == 256); + state.isMember(jss::load_factor_fee_escalation) && state[jss::load_factor_fee_escalation] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) && state[jss::load_factor_fee_queue] == 256); BEAST_EXPECT( - state.isMember(jss::load_base) && state[jss::load_base] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_server) && - state[jss::load_factor_server] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_escalation) && - state[jss::load_factor_fee_escalation] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_queue) && - state[jss::load_factor_fee_queue] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_reference) && - state[jss::load_factor_fee_reference] == 256); + state.isMember(jss::load_factor_fee_reference) && state[jss::load_factor_fee_reference] == 256); } checkMetrics(*this, env, 0, 6, 0, 3); @@ -3444,98 +3105,62 @@ public: auto aliceSeq = env.seq(alice); auto submitParams = Json::Value(Json::objectValue); for (auto i = 0; i < 4; ++i) - envs( - noop(alice), - fee(baseFee * 10), - seq(aliceSeq + i), - ter(terQUEUED))(submitParams); + envs(noop(alice), fee(baseFee * 10), seq(aliceSeq + i), ter(terQUEUED))(submitParams); checkMetrics(*this, env, 4, 6, 4, 3); { auto const server_info = env.rpc("server_info"); - BEAST_EXPECT( - server_info.isMember(jss::result) && - server_info[jss::result].isMember(jss::info)); + BEAST_EXPECT(server_info.isMember(jss::result) && server_info[jss::result].isMember(jss::info)); auto const& info = server_info[jss::result][jss::info]; // Avoid double rounding issues by comparing to a range. BEAST_EXPECT( - info.isMember(jss::load_factor) && - info[jss::load_factor] > 888.88 && - info[jss::load_factor] < 888.89); - BEAST_EXPECT( - info.isMember(jss::load_factor_server) && - info[jss::load_factor_server] == 1); + info.isMember(jss::load_factor) && info[jss::load_factor] > 888.88 && info[jss::load_factor] < 888.89); + BEAST_EXPECT(info.isMember(jss::load_factor_server) && info[jss::load_factor_server] == 1); BEAST_EXPECT(!info.isMember(jss::load_factor_local)); BEAST_EXPECT(!info.isMember(jss::load_factor_net)); BEAST_EXPECT( - info.isMember(jss::load_factor_fee_escalation) && - info[jss::load_factor_fee_escalation] > 888.88 && + info.isMember(jss::load_factor_fee_escalation) && info[jss::load_factor_fee_escalation] > 888.88 && info[jss::load_factor_fee_escalation] < 888.89); } { auto const server_state = env.rpc("server_state"); auto const& state = server_state[jss::result][jss::state]; + BEAST_EXPECT(state.isMember(jss::load_factor) && state[jss::load_factor] == 227555); + BEAST_EXPECT(state.isMember(jss::load_base) && state[jss::load_base] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor_server) && state[jss::load_factor_server] == 256); BEAST_EXPECT( - state.isMember(jss::load_factor) && - state[jss::load_factor] == 227555); + state.isMember(jss::load_factor_fee_escalation) && state[jss::load_factor_fee_escalation] == 227555); + BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) && state[jss::load_factor_fee_queue] == 256); BEAST_EXPECT( - state.isMember(jss::load_base) && state[jss::load_base] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_server) && - state[jss::load_factor_server] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_escalation) && - state[jss::load_factor_fee_escalation] == 227555); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_queue) && - state[jss::load_factor_fee_queue] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_reference) && - state[jss::load_factor_fee_reference] == 256); + state.isMember(jss::load_factor_fee_reference) && state[jss::load_factor_fee_reference] == 256); } env.app().getFeeTrack().setRemoteFee(256000); { auto const server_info = env.rpc("server_info"); - BEAST_EXPECT( - server_info.isMember(jss::result) && - server_info[jss::result].isMember(jss::info)); + BEAST_EXPECT(server_info.isMember(jss::result) && server_info[jss::result].isMember(jss::info)); auto const& info = server_info[jss::result][jss::info]; // Avoid double rounding issues by comparing to a range. - BEAST_EXPECT( - info.isMember(jss::load_factor) && - info[jss::load_factor] == 1000); + BEAST_EXPECT(info.isMember(jss::load_factor) && info[jss::load_factor] == 1000); BEAST_EXPECT(!info.isMember(jss::load_factor_server)); BEAST_EXPECT(!info.isMember(jss::load_factor_local)); + BEAST_EXPECT(info.isMember(jss::load_factor_net) && info[jss::load_factor_net] == 1000); BEAST_EXPECT( - info.isMember(jss::load_factor_net) && - info[jss::load_factor_net] == 1000); - BEAST_EXPECT( - info.isMember(jss::load_factor_fee_escalation) && - info[jss::load_factor_fee_escalation] > 888.88 && + info.isMember(jss::load_factor_fee_escalation) && info[jss::load_factor_fee_escalation] > 888.88 && info[jss::load_factor_fee_escalation] < 888.89); } { auto const server_state = env.rpc("server_state"); auto const& state = server_state[jss::result][jss::state]; + BEAST_EXPECT(state.isMember(jss::load_factor) && state[jss::load_factor] == 256000); + BEAST_EXPECT(state.isMember(jss::load_base) && state[jss::load_base] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor_server) && state[jss::load_factor_server] == 256000); BEAST_EXPECT( - state.isMember(jss::load_factor) && - state[jss::load_factor] == 256000); + state.isMember(jss::load_factor_fee_escalation) && state[jss::load_factor_fee_escalation] == 227555); + BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) && state[jss::load_factor_fee_queue] == 256); BEAST_EXPECT( - state.isMember(jss::load_base) && state[jss::load_base] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_server) && - state[jss::load_factor_server] == 256000); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_escalation) && - state[jss::load_factor_fee_escalation] == 227555); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_queue) && - state[jss::load_factor_fee_queue] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_reference) && - state[jss::load_factor_fee_reference] == 256); + state.isMember(jss::load_factor_fee_reference) && state[jss::load_factor_fee_reference] == 256); } env.app().getFeeTrack().setRemoteFee(256); @@ -3547,65 +3172,48 @@ public: { auto const server_info = env.rpc("server_info"); - BEAST_EXPECT( - server_info.isMember(jss::result) && - server_info[jss::result].isMember(jss::info)); + BEAST_EXPECT(server_info.isMember(jss::result) && server_info[jss::result].isMember(jss::info)); auto const& info = server_info[jss::result][jss::info]; // Avoid double rounding issues by comparing to a range. BEAST_EXPECT( - info.isMember(jss::load_factor) && - info[jss::load_factor] > 888.88 && - info[jss::load_factor] < 888.89); + info.isMember(jss::load_factor) && info[jss::load_factor] > 888.88 && info[jss::load_factor] < 888.89); // There can be a race between LoadManager lowering the fee, // and the call to server_info, so check a wide range. // The important thing is that it's not 1. BEAST_EXPECT( - info.isMember(jss::load_factor_server) && - info[jss::load_factor_server] > 1.245 && + info.isMember(jss::load_factor_server) && info[jss::load_factor_server] > 1.245 && info[jss::load_factor_server] < 2.4415); BEAST_EXPECT( - info.isMember(jss::load_factor_local) && - info[jss::load_factor_local] > 1.245 && + info.isMember(jss::load_factor_local) && info[jss::load_factor_local] > 1.245 && info[jss::load_factor_local] < 2.4415); BEAST_EXPECT(!info.isMember(jss::load_factor_net)); BEAST_EXPECT( - info.isMember(jss::load_factor_fee_escalation) && - info[jss::load_factor_fee_escalation] > 888.88 && + info.isMember(jss::load_factor_fee_escalation) && info[jss::load_factor_fee_escalation] > 888.88 && info[jss::load_factor_fee_escalation] < 888.89); } { auto const server_state = env.rpc("server_state"); auto const& state = server_state[jss::result][jss::state]; - BEAST_EXPECT( - state.isMember(jss::load_factor) && - state[jss::load_factor] == 227555); - BEAST_EXPECT( - state.isMember(jss::load_base) && state[jss::load_base] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor) && state[jss::load_factor] == 227555); + BEAST_EXPECT(state.isMember(jss::load_base) && state[jss::load_base] == 256); // There can be a race between LoadManager lowering the fee, // and the call to server_info, so check a wide range. // The important thing is that it's not 256. BEAST_EXPECT( - state.isMember(jss::load_factor_server) && - state[jss::load_factor_server] >= 320 && + state.isMember(jss::load_factor_server) && state[jss::load_factor_server] >= 320 && state[jss::load_factor_server] <= 625); BEAST_EXPECT( - state.isMember(jss::load_factor_fee_escalation) && - state[jss::load_factor_fee_escalation] == 227555); + state.isMember(jss::load_factor_fee_escalation) && state[jss::load_factor_fee_escalation] == 227555); + BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) && state[jss::load_factor_fee_queue] == 256); BEAST_EXPECT( - state.isMember(jss::load_factor_fee_queue) && - state[jss::load_factor_fee_queue] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_reference) && - state[jss::load_factor_fee_reference] == 256); + state.isMember(jss::load_factor_fee_reference) && state[jss::load_factor_fee_reference] == 256); } env.close(); { auto const server_info = env.rpc("server_info"); - BEAST_EXPECT( - server_info.isMember(jss::result) && - server_info[jss::result].isMember(jss::info)); + BEAST_EXPECT(server_info.isMember(jss::result) && server_info[jss::result].isMember(jss::info)); auto const& info = server_info[jss::result][jss::info]; // Avoid double rounding issues by comparing to a range. @@ -3613,13 +3221,10 @@ public: // and the call to server_info, so check a wide range. // The important thing is that it's not 1. BEAST_EXPECT( - info.isMember(jss::load_factor) && - info[jss::load_factor] > 1.245 && - info[jss::load_factor] < 2.4415); + info.isMember(jss::load_factor) && info[jss::load_factor] > 1.245 && info[jss::load_factor] < 2.4415); BEAST_EXPECT(!info.isMember(jss::load_factor_server)); BEAST_EXPECT( - info.isMember(jss::load_factor_local) && - info[jss::load_factor_local] > 1.245 && + info.isMember(jss::load_factor_local) && info[jss::load_factor_local] > 1.245 && info[jss::load_factor_local] < 2.4415); BEAST_EXPECT(!info.isMember(jss::load_factor_net)); BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation)); @@ -3628,27 +3233,19 @@ public: auto const server_state = env.rpc("server_state"); auto const& state = server_state[jss::result][jss::state]; BEAST_EXPECT( - state.isMember(jss::load_factor) && - state[jss::load_factor] >= 320 && - state[jss::load_factor] <= 625); - BEAST_EXPECT( - state.isMember(jss::load_base) && state[jss::load_base] == 256); + state.isMember(jss::load_factor) && state[jss::load_factor] >= 320 && state[jss::load_factor] <= 625); + BEAST_EXPECT(state.isMember(jss::load_base) && state[jss::load_base] == 256); // There can be a race between LoadManager lowering the fee, // and the call to server_info, so check a wide range. // The important thing is that it's not 256. BEAST_EXPECT( - state.isMember(jss::load_factor_server) && - state[jss::load_factor_server] >= 320 && + state.isMember(jss::load_factor_server) && state[jss::load_factor_server] >= 320 && state[jss::load_factor_server] <= 625); BEAST_EXPECT( - state.isMember(jss::load_factor_fee_escalation) && - state[jss::load_factor_fee_escalation] == 256); + state.isMember(jss::load_factor_fee_escalation) && state[jss::load_factor_fee_escalation] == 256); + BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) && state[jss::load_factor_fee_queue] == 256); BEAST_EXPECT( - state.isMember(jss::load_factor_fee_queue) && - state[jss::load_factor_fee_queue] == 256); - BEAST_EXPECT( - state.isMember(jss::load_factor_fee_reference) && - state[jss::load_factor_fee_reference] == 256); + state.isMember(jss::load_factor_fee_reference) && state[jss::load_factor_fee_reference] == 256); } } @@ -3670,8 +3267,7 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); } - Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"}, - i{"i"}; + Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"}, i{"i"}; // Fund the first few accounts at non escalated fee env.fund(XRP(50000), noripple(a, b, c, d)); @@ -3680,31 +3276,20 @@ public: // First transaction establishes the messaging using namespace std::chrono_literals; BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && - jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 256 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 256 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); // Last transaction escalates the fee BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && - jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) && - jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 227555 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 227555 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 227555 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); @@ -3712,16 +3297,11 @@ public: // Closing ledger should publish a status update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && - jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 256 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 256 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); @@ -3743,56 +3323,37 @@ public: // Last transaction escalates the fee BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && - jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) && - jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 200000 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 200000 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 200000 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); env.close(); // Ledger close publishes with escalated fees for queued transactions BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && - jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) && - jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 184320 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 184320 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 184320 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); env.close(); // ledger close clears queue so fee is back to normal BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus" && - jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && - jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && - jv.isMember(jss::load_factor_server) && - jv[jss::load_factor_server] == 256 && - jv.isMember(jss::load_factor_fee_escalation) && - jv[jss::load_factor_fee_escalation] == 256 && - jv.isMember(jss::load_factor_fee_queue) && - jv[jss::load_factor_fee_queue] == 256 && - jv.isMember(jss::load_factor_fee_reference) && + return jv[jss::type] == "serverStatus" && jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 && + jv.isMember(jss::load_base) && jv[jss::load_base] == 256 && jv.isMember(jss::load_factor_server) && + jv[jss::load_factor_server] == 256 && jv.isMember(jss::load_factor_fee_escalation) && + jv[jss::load_factor_fee_escalation] == 256 && jv.isMember(jss::load_factor_fee_queue) && + jv[jss::load_factor_fee_queue] == 256 && jv.isMember(jss::load_factor_fee_reference) && jv[jss::load_factor_fee_reference] == 256; })); - BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus"; - })); + BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) { return jv[jss::type] == "serverStatus"; })); auto jv = wsc->invoke("unsubscribe", stream); BEAST_EXPECT(jv[jss::status] == "success"); @@ -3815,8 +3376,7 @@ public: fillQueue(env, alice); auto calcTotalFee = [&](std::int64_t alreadyPaid, - std::optional numToClear = - std::nullopt) -> std::uint64_t { + std::optional numToClear = std::nullopt) -> std::uint64_t { auto totalFactor = 0; auto const metrics = env.app().getTxQ().getMetrics(*env.current()); if (!numToClear) @@ -3828,8 +3388,7 @@ public: } auto const den = (metrics.txPerLedger * metrics.txPerLedger); - FeeLevel64 feeLevel = - (metrics.medFeeLevel * totalFactor + FeeLevel64{den - 1}) / den; + FeeLevel64 feeLevel = (metrics.medFeeLevel * totalFactor + FeeLevel64{den - 1}) / den; auto result = toDrops(feeLevel, env.current()->fees().base).drops(); @@ -3840,17 +3399,14 @@ public: return result; }; - testcase("straightfoward positive case"); + testcase("straightforward positive case"); { // Queue up some transactions at a too-low fee. auto aliceSeq = env.seq(alice); std::uint64_t totalPaid = 0; for (int i = 0; i < 2; ++i) { - env(noop(alice), - fee(baseFee * 10), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(baseFee * 10), seq(aliceSeq++), ter(terQUEUED)); totalPaid += baseFee * 10; } @@ -3858,10 +3414,7 @@ public: // This will be the first tx to call the operative function, // but it won't succeed. totalPaid += openLedgerCost(env).drops(); - env(noop(alice), - fee(openLedgerCost(env)), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(openLedgerCost(env)), seq(aliceSeq++), ter(terQUEUED)); checkMetrics(*this, env, 3, std::nullopt, 4, 3); @@ -3895,28 +3448,21 @@ public: uint64_t totalPaid = 0; for (int i = 0; i < 2; ++i) { - env(noop(alice), - fee(baseFee * 10), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(baseFee * 10), seq(aliceSeq++), ter(terQUEUED)); totalPaid += baseFee * 10; } // Queue up a transaction paying the open ledger fee // This will be the first tx to call the operative function, // but it won't succeed. - env(noop(alice), - fee(openLedgerCost(env)), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(openLedgerCost(env)), seq(aliceSeq++), ter(terQUEUED)); checkMetrics(*this, env, 3, std::nullopt, 9, 3); // Figure out how much it would cost to cover all the // queued txs + itself auto const metrics = env.app().getTxQ().getMetrics(*env.current()); - std::uint64_t const totalFee = - calcTotalFee(totalPaid, metrics.txCount); + std::uint64_t const totalFee = calcTotalFee(totalPaid, metrics.txCount); // Replacing the last tx with the large fee succeeds. --aliceSeq; env(noop(alice), fee(totalFee), seq(aliceSeq++)); @@ -3935,10 +3481,7 @@ public: auto aliceSeq = env.seq(alice); for (int i = 0; i < 5; ++i) { - env(noop(alice), - fee(baseFee * 10), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(baseFee * 10), seq(aliceSeq++), ter(terQUEUED)); } checkMetrics(*this, env, 5, 24, 13, 12); @@ -3950,15 +3493,13 @@ public: env(noop(alice), fee(totalFee), seq(aliceSeq++)); checkMetrics(*this, env, 2, 24, 16, 12); - auto const aliceQueue = - env.app().getTxQ().getAccountTxs(alice.id()); + auto const aliceQueue = env.app().getTxQ().getAccountTxs(alice.id()); BEAST_EXPECT(aliceQueue.size() == 2); SeqProxy seq = SeqProxy::sequence(aliceSeq); for (auto const& tx : aliceQueue) { BEAST_EXPECT(tx.seqProxy == seq); - BEAST_EXPECT( - tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 10}); + BEAST_EXPECT(tx.feeLevel == FeeLevel64{baseFeeLevel.fee() * 10}); seq.advanceBy(1); } @@ -3975,18 +3516,12 @@ public: uint64_t totalPaid = 0; for (int i = 0; i < 2; ++i) { - env(noop(alice), - fee(baseFee * 20), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(baseFee * 20), seq(aliceSeq++), ter(terQUEUED)); totalPaid += baseFee * 20; } for (int i = 0; i < 2; ++i) { - env(noop(alice), - fee(baseFee * 2.2), - seq(aliceSeq++), - ter(terQUEUED)); + env(noop(alice), fee(baseFee * 2.2), seq(aliceSeq++), ter(terQUEUED)); totalPaid += baseFee * 2.2; } @@ -4207,10 +3742,8 @@ public: // which won't work if unit tests are separated to only // be callable via RPC.) env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { - auto const tx = - env.jt(noop(alice), seq(aliceSeq), fee(openLedgerCost(env))); - auto const result = - ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j); + auto const tx = env.jt(noop(alice), seq(aliceSeq), fee(openLedgerCost(env))); + auto const result = xrpl::apply(env.app(), view, *tx.stx, tapUNLIMITED, j); BEAST_EXPECT(result.ter == tesSUCCESS && result.applied); return result.applied; }); @@ -4277,12 +3810,8 @@ public: // which won't work if unit tests are separated to only // be callable via RPC.) env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { - auto const tx = env.jt( - noop(alice), - ticket::use(tktSeq0 + 1), - fee(openLedgerCost(env))); - auto const result = - ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j); + auto const tx = env.jt(noop(alice), ticket::use(tktSeq0 + 1), fee(openLedgerCost(env))); + auto const result = xrpl::apply(env.app(), view, *tx.stx, tapUNLIMITED, j); BEAST_EXPECT(result.ter == tesSUCCESS && result.applied); return result.applied; }); @@ -4330,7 +3859,7 @@ public: } void - testReexecutePreflight() + testReExecutePreflight() { // The TxQ caches preflight results. But there are situations where // that cache must become invalidated, like if amendments change. @@ -4349,19 +3878,17 @@ public: Account const ellie("ellie"); Account const fiona("fiona"); + constexpr int ledgersInQueue = 30; auto cfg = makeConfig( {{"minimum_txn_in_ledger_standalone", "1"}, - {"ledgers_in_queue", "5"}, + {"ledgers_in_queue", std::to_string(ledgersInQueue)}, {"maximum_txn_per_account", "10"}}, {{"account_reserve", "1000"}, {"owner_reserve", "50"}}); auto& votingSection = cfg->section("voting"); - votingSection.set( - "account_reserve", - std::to_string(cfg->FEES.reference_fee.drops() * 100)); + votingSection.set("account_reserve", std::to_string(cfg->FEES.reference_fee.drops() * 100)); - votingSection.set( - "reference_fee", std::to_string(cfg->FEES.reference_fee.drops())); + votingSection.set("reference_fee", std::to_string(cfg->FEES.reference_fee.drops())); Env env(*this, std::move(cfg)); @@ -4377,7 +3904,9 @@ public: env.close(); env.fund(XRP(10000), fiona); env.close(); - checkMetrics(*this, env, 0, 10, 0, 2); + + auto const metrics = env.app().getTxQ().getMetrics(*env.current()); + checkMetrics(*this, env, 0, ledgersInQueue * metrics.txPerLedger, 0, 2); // Close ledgers until the amendments show up. int i = 0; @@ -4387,9 +3916,8 @@ public: if (!getMajorityAmendments(*env.closed()).empty()) break; } - auto expectedPerLedger = ripple::detail::numUpVotedAmendments() + 1; - checkMetrics( - *this, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger); + auto expectedPerLedger = xrpl::detail::numUpVotedAmendments() + 1; + checkMetrics(*this, env, 0, ledgersInQueue * expectedPerLedger, 0, expectedPerLedger); // Now wait 2 weeks modulo 256 ledgers for the amendments to be // enabled. Speed the process by closing ledgers every 80 minutes, @@ -4404,13 +3932,7 @@ public: auto const baseFee = env.current()->fees().base.drops(); // We're very close to the flag ledger. Fill the ledger. fillQueue(env, alice); - checkMetrics( - *this, - env, - 0, - 5 * expectedPerLedger, - expectedPerLedger + 1, - expectedPerLedger); + checkMetrics(*this, env, 0, ledgersInQueue * expectedPerLedger, expectedPerLedger + 1, expectedPerLedger); // Fill everyone's queues. auto seqAlice = env.seq(alice); @@ -4422,46 +3944,21 @@ public: // Use fees to guarantee order int txFee{static_cast(baseFee * 9)}; - auto prepareFee = [&](uint64_t multiplier) { - return fee(txFee - multiplier * baseFee / 10); - }; + auto prepareFee = [&](uint64_t multiplier) { return fee(txFee - multiplier * baseFee / 10); }; uint64_t multiplier = 0; for (int i = 0; i < 10; ++i) { - env(noop(alice), - seq(seqAlice++), - prepareFee(++multiplier), - ter(terQUEUED)); - env(noop(bob), - seq(seqBob++), - prepareFee(++multiplier), - ter(terQUEUED)); - env(noop(carol), - seq(seqCarol++), - prepareFee(++multiplier), - ter(terQUEUED)); - env(noop(daria), - seq(seqDaria++), - prepareFee(++multiplier), - ter(terQUEUED)); - env(noop(ellie), - seq(seqEllie++), - prepareFee(++multiplier), - ter(terQUEUED)); - env(noop(fiona), - seq(seqFiona++), - prepareFee(++multiplier), - ter(terQUEUED)); + env(noop(alice), seq(seqAlice++), prepareFee(++multiplier), ter(terQUEUED)); + env(noop(bob), seq(seqBob++), prepareFee(++multiplier), ter(terQUEUED)); + env(noop(carol), seq(seqCarol++), prepareFee(++multiplier), ter(terQUEUED)); + env(noop(daria), seq(seqDaria++), prepareFee(++multiplier), ter(terQUEUED)); + env(noop(ellie), seq(seqEllie++), prepareFee(++multiplier), ter(terQUEUED)); + env(noop(fiona), seq(seqFiona++), prepareFee(++multiplier), ter(terQUEUED)); } - std::size_t expectedInQueue = 60; + std::size_t expectedInQueue = multiplier; checkMetrics( - *this, - env, - expectedInQueue, - 5 * expectedPerLedger, - expectedPerLedger + 1, - expectedPerLedger); + *this, env, expectedInQueue, ledgersInQueue * expectedPerLedger, expectedPerLedger + 1, expectedPerLedger); // The next close should cause the in-ledger amendments to change. // Alice's queued transactions have a cached PreflightResult @@ -4476,43 +3973,20 @@ public: { env.close(closeDuration); auto expectedInLedger = expectedInQueue; - expectedInQueue = - (expectedInQueue > expectedPerLedger + 2 - ? expectedInQueue - (expectedPerLedger + 2) - : 0); + expectedInQueue = (expectedInQueue > expectedPerLedger + 2 ? expectedInQueue - (expectedPerLedger + 2) : 0); expectedInLedger -= expectedInQueue; ++expectedPerLedger; checkMetrics( - *this, - env, - expectedInQueue, - 5 * expectedPerLedger, - expectedInLedger, - expectedPerLedger); + *this, env, expectedInQueue, ledgersInQueue * expectedPerLedger, expectedInLedger, expectedPerLedger); { auto const expectedPerAccount = expectedInQueue / 6; auto const expectedRemainder = expectedInQueue % 6; BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount); - BEAST_EXPECT( - env.seq(bob) == - seqBob - expectedPerAccount - - (expectedRemainder > 4 ? 1 : 0)); - BEAST_EXPECT( - env.seq(carol) == - seqCarol - expectedPerAccount - - (expectedRemainder > 3 ? 1 : 0)); - BEAST_EXPECT( - env.seq(daria) == - seqDaria - expectedPerAccount - - (expectedRemainder > 2 ? 1 : 0)); - BEAST_EXPECT( - env.seq(ellie) == - seqEllie - expectedPerAccount - - (expectedRemainder > 1 ? 1 : 0)); - BEAST_EXPECT( - env.seq(fiona) == - seqFiona - expectedPerAccount - - (expectedRemainder > 0 ? 1 : 0)); + BEAST_EXPECT(env.seq(bob) == seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0)); + BEAST_EXPECT(env.seq(carol) == seqCarol - expectedPerAccount - (expectedRemainder > 3 ? 1 : 0)); + BEAST_EXPECT(env.seq(daria) == seqDaria - expectedPerAccount - (expectedRemainder > 2 ? 1 : 0)); + BEAST_EXPECT(env.seq(ellie) == seqEllie - expectedPerAccount - (expectedRemainder > 1 ? 1 : 0)); + BEAST_EXPECT(env.seq(fiona) == seqFiona - expectedPerAccount - (expectedRemainder > 0 ? 1 : 0)); } } while (expectedInQueue > 0); } @@ -4577,29 +4051,16 @@ public: auto seqAlice = env.seq(alice); auto const seqSaveAlice = seqAlice; int feeDrops = baseFee * 4; - env(noop(alice), - seq(seqAlice++), - fee(--feeDrops), - last_ledger_seq(7), - ter(terQUEUED)); + env(noop(alice), seq(seqAlice++), fee(--feeDrops), last_ledger_seq(7), ter(terQUEUED)); env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED)); env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED)); BEAST_EXPECT(env.seq(alice) == seqSaveAlice); // Similarly for bob, but bob uses tickets in his transactions. // The drop penalty works a little differently with tickets. - env(noop(bob), - ticket::use(bobTicketSeq + 0), - last_ledger_seq(7), - ter(terQUEUED)); - env(noop(bob), - ticket::use(bobTicketSeq + 1), - fee(--feeDrops), - ter(terQUEUED)); - env(noop(bob), - ticket::use(bobTicketSeq + 2), - fee(--feeDrops), - ter(terQUEUED)); + env(noop(bob), ticket::use(bobTicketSeq + 0), last_ledger_seq(7), ter(terQUEUED)); + env(noop(bob), ticket::use(bobTicketSeq + 1), fee(--feeDrops), ter(terQUEUED)); + env(noop(bob), ticket::use(bobTicketSeq + 2), fee(--feeDrops), ter(terQUEUED)); // Fill the queue with higher fee transactions so alice's and // bob's transactions are stuck in the queue. @@ -4742,23 +4203,15 @@ public: // Verify that bob's first transaction was removed from the queue // by queueing another low fee transaction into that spot. - env(noop(bob), - ticket::use(bobTicketSeq + 0), - fee(baseFee * 1.2), - ter(terQUEUED)); + env(noop(bob), ticket::use(bobTicketSeq + 0), fee(baseFee * 1.2), ter(terQUEUED)); // Verify that bob's second transaction was removed from the queue // by queueing another low fee transaction into that spot. - env(noop(bob), - ticket::use(bobTicketSeq + 1), - fee(baseFee * 1.1), - ter(terQUEUED)); + env(noop(bob), ticket::use(bobTicketSeq + 1), fee(baseFee * 1.1), ter(terQUEUED)); // Verify that the last entry in bob's queue is still there // by trying to replace it and having that fail. - env(noop(bob), - ticket::use(bobTicketSeq + 2), - ter(telCAN_NOT_QUEUE_FEE)); + env(noop(bob), ticket::use(bobTicketSeq + 2), ter(telCAN_NOT_QUEUE_FEE)); } void @@ -4792,9 +4245,7 @@ public: auto const aliceSeq = env.seq(alice); env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED)); - env(offer(alice, USD(1000), XRP(1001)), - seq(aliceSeq + 1), - ter(terQUEUED)); + env(offer(alice, USD(1000), XRP(1001)), seq(aliceSeq + 1), ter(terQUEUED)); // Alice creates transactions that cancel the first set of // offers, one through another offer, and one cancel @@ -4803,9 +4254,7 @@ public: json(jss::OfferSequence, aliceSeq), ter(terQUEUED)); - env(offer_cancel(alice, aliceSeq + 1), - seq(aliceSeq + 3), - ter(terQUEUED)); + env(offer_cancel(alice, aliceSeq + 1), seq(aliceSeq + 3), ter(terQUEUED)); env.close(); @@ -4825,13 +4274,9 @@ public: // Alice creates a couple offers using tickets, consuming the // tickets in reverse order auto const aliceSeq = env.seq(alice); - env(offer(alice, USD(1000), XRP(1000)), - ticket::use(aliceTkt + 4), - ter(terQUEUED)); + env(offer(alice, USD(1000), XRP(1000)), ticket::use(aliceTkt + 4), ter(terQUEUED)); - env(offer(alice, USD(1000), XRP(1001)), - ticket::use(aliceTkt + 3), - ter(terQUEUED)); + env(offer(alice, USD(1000), XRP(1001)), ticket::use(aliceTkt + 3), ter(terQUEUED)); // Alice creates a couple more transactions that cancel the first // set of offers, also in reverse order. This allows Alice to submit @@ -4844,16 +4289,12 @@ public: json(jss::OfferSequence, aliceTkt + 4), ter(terQUEUED)); - env(offer_cancel(alice, aliceTkt + 3), - ticket::use(aliceTkt + 1), - ter(terQUEUED)); + env(offer_cancel(alice, aliceTkt + 3), ticket::use(aliceTkt + 1), ter(terQUEUED)); // Create a couple more offers using sequences env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED)); - env(offer(alice, USD(1000), XRP(1001)), - seq(aliceSeq + 1), - ter(terQUEUED)); + env(offer(alice, USD(1000), XRP(1001)), seq(aliceSeq + 1), ter(terQUEUED)); // And try to cancel those using tickets env(offer(alice, USD(1000), XRP(1002)), @@ -4861,9 +4302,7 @@ public: json(jss::OfferSequence, aliceSeq), ter(terQUEUED)); - env(offer_cancel(alice, aliceSeq + 1), - ticket::use(aliceTkt + 6), - ter(terQUEUED)); + env(offer_cancel(alice, aliceSeq + 1), ticket::use(aliceTkt + 6), ter(terQUEUED)); env.close(); @@ -4887,9 +4326,7 @@ public: *this, makeConfig( {{"minimum_txn_in_ledger_standalone", "3"}}, - {{"reference_fee", "0"}, - {"account_reserve", "0"}, - {"owner_reserve", "0"}})); + {{"reference_fee", "0"}, {"account_reserve", "0"}, {"owner_reserve", "0"}})); checkMetrics(*this, env, 0, std::nullopt, 0, 3); @@ -4901,39 +4338,22 @@ public: { auto const fee = env.rpc("fee"); - if (BEAST_EXPECT(fee.isMember(jss::result)) && - BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) + if (BEAST_EXPECT(fee.isMember(jss::result)) && BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) { auto const& result = fee[jss::result]; BEAST_EXPECT(result.isMember(jss::levels)); auto const& levels = result[jss::levels]; - BEAST_EXPECT( - levels.isMember(jss::median_level) && - levels[jss::median_level] == "128000"); - BEAST_EXPECT( - levels.isMember(jss::minimum_level) && - levels[jss::minimum_level] == "256"); - BEAST_EXPECT( - levels.isMember(jss::open_ledger_level) && - levels[jss::open_ledger_level] == "256"); - BEAST_EXPECT( - levels.isMember(jss::reference_level) && - levels[jss::reference_level] == "256"); + BEAST_EXPECT(levels.isMember(jss::median_level) && levels[jss::median_level] == "128000"); + BEAST_EXPECT(levels.isMember(jss::minimum_level) && levels[jss::minimum_level] == "256"); + BEAST_EXPECT(levels.isMember(jss::open_ledger_level) && levels[jss::open_ledger_level] == "256"); + BEAST_EXPECT(levels.isMember(jss::reference_level) && levels[jss::reference_level] == "256"); auto const& drops = result[jss::drops]; - BEAST_EXPECT( - drops.isMember(jss::base_fee) && - drops[jss::base_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::median_fee) && - drops[jss::median_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::minimum_fee) && - drops[jss::minimum_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::open_ledger_fee) && - drops[jss::open_ledger_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::base_fee) && drops[jss::base_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::median_fee) && drops[jss::median_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::minimum_fee) && drops[jss::minimum_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::open_ledger_fee) && drops[jss::open_ledger_fee] == "0"); } } @@ -4969,39 +4389,22 @@ public: { auto const fee = env.rpc("fee"); - if (BEAST_EXPECT(fee.isMember(jss::result)) && - BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) + if (BEAST_EXPECT(fee.isMember(jss::result)) && BEAST_EXPECT(!RPC::contains_error(fee[jss::result]))) { auto const& result = fee[jss::result]; BEAST_EXPECT(result.isMember(jss::levels)); auto const& levels = result[jss::levels]; - BEAST_EXPECT( - levels.isMember(jss::median_level) && - levels[jss::median_level] == "128000"); - BEAST_EXPECT( - levels.isMember(jss::minimum_level) && - levels[jss::minimum_level] == "256"); - BEAST_EXPECT( - levels.isMember(jss::open_ledger_level) && - levels[jss::open_ledger_level] == "355555"); - BEAST_EXPECT( - levels.isMember(jss::reference_level) && - levels[jss::reference_level] == "256"); + BEAST_EXPECT(levels.isMember(jss::median_level) && levels[jss::median_level] == "128000"); + BEAST_EXPECT(levels.isMember(jss::minimum_level) && levels[jss::minimum_level] == "256"); + BEAST_EXPECT(levels.isMember(jss::open_ledger_level) && levels[jss::open_ledger_level] == "355555"); + BEAST_EXPECT(levels.isMember(jss::reference_level) && levels[jss::reference_level] == "256"); auto const& drops = result[jss::drops]; - BEAST_EXPECT( - drops.isMember(jss::base_fee) && - drops[jss::base_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::median_fee) && - drops[jss::median_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::minimum_fee) && - drops[jss::minimum_fee] == "0"); - BEAST_EXPECT( - drops.isMember(jss::open_ledger_fee) && - drops[jss::open_ledger_fee] == "1389"); + BEAST_EXPECT(drops.isMember(jss::base_fee) && drops[jss::base_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::median_fee) && drops[jss::median_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::minimum_fee) && drops[jss::minimum_fee] == "0"); + BEAST_EXPECT(drops.isMember(jss::open_ledger_fee) && drops[jss::open_ledger_fee] == "1389"); } } @@ -5047,7 +4450,7 @@ public: testScaling(); testInLedgerSeq(); testInLedgerTicket(); - testReexecutePreflight(); + testReExecutePreflight(); testQueueFullDropPenalty(); testCancelQueuedOffers(); testZeroReferenceFee(); @@ -5063,8 +4466,8 @@ class TxQMetaInfo_test : public TxQPosNegFlows_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app, ripple, 1); -BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app, xrpl, 1); +BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app, xrpl, 1); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/ValidatorKeys_test.cpp b/src/test/app/ValidatorKeys_test.cpp index 427ada132c..c688b2661f 100644 --- a/src/test/app/ValidatorKeys_test.cpp +++ b/src/test/app/ValidatorKeys_test.cpp @@ -1,35 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include #include #include #include #include #include +#include #include -namespace ripple { +namespace xrpl { namespace test { class ValidatorKeys_test : public beast::unit_test::suite @@ -38,8 +19,7 @@ class ValidatorKeys_test : public beast::unit_test::suite std::string const seed = "shUwVw52ofnCUX5m7kPTKzJdr4HEH"; // Used with [validation_token] - std::string const tokenSecretStr = - "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"; + std::string const tokenSecretStr = "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"; std::vector const tokenBlob = { " " @@ -80,26 +60,18 @@ public: { // We're only using Env for its Journal. That Journal gives better // coverage in unit tests. - test::jtx::Env env{ - *this, - test::jtx::envconfig(), - nullptr, - beast::severities::kDisabled}; + test::jtx::Env env{*this, test::jtx::envconfig(), nullptr, beast::severities::kDisabled}; beast::Journal journal{env.app().journal("ValidatorKeys_test")}; // Keys/ID when using [validation_seed] - SecretKey const seedSecretKey = - generateSecretKey(KeyType::secp256k1, *parseBase58(seed)); - PublicKey const seedPublicKey = - derivePublicKey(KeyType::secp256k1, seedSecretKey); + SecretKey const seedSecretKey = generateSecretKey(KeyType::secp256k1, *parseBase58(seed)); + PublicKey const seedPublicKey = derivePublicKey(KeyType::secp256k1, seedSecretKey); NodeID const seedNodeID = calcNodeID(seedPublicKey); // Keys when using [validation_token] - auto const tokenSecretKey = - *parseBase58(TokenType::NodePrivate, tokenSecretStr); + auto const tokenSecretKey = *parseBase58(TokenType::NodePrivate, tokenSecretStr); - auto const tokenPublicKey = - derivePublicKey(KeyType::secp256k1, tokenSecretKey); + auto const tokenPublicKey = derivePublicKey(KeyType::secp256k1, tokenSecretKey); auto const m = deserializeManifest(base64_decode(tokenManifest)); BEAST_EXPECT(m); @@ -190,7 +162,7 @@ public: } }; // namespace test -BEAST_DEFINE_TESTSUITE(ValidatorKeys, app, ripple); +BEAST_DEFINE_TESTSUITE(ValidatorKeys, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/ValidatorList_test.cpp b/src/test/app/ValidatorList_test.cpp index 2b004c3b52..4955686966 100644 --- a/src/test/app/ValidatorList_test.cpp +++ b/src/test/app/ValidatorList_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -35,7 +16,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class ValidatorList_test : public beast::unit_test::suite @@ -61,12 +42,7 @@ private: } static std::string - makeManifestString( - PublicKey const& pk, - SecretKey const& sk, - PublicKey const& spk, - SecretKey const& ssk, - int seq) + makeManifestString(PublicKey const& pk, SecretKey const& sk, PublicKey const& spk, SecretKey const& ssk, int seq) { STObject st(sfGeneric); st[sfSequence] = seq; @@ -78,12 +54,7 @@ private: sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk); } - sign( - st, - HashPrefix::manifest, - *publicKeyType(pk), - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, *publicKeyType(pk), sk, sfMasterSignature); Serializer s; st.add(s); @@ -98,12 +69,7 @@ private: st[sfSequence] = std::numeric_limits::max(); st[sfPublicKey] = pk; - sign( - st, - HashPrefix::manifest, - *publicKeyType(pk), - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, *publicKeyType(pk), sk, sfMasterSignature); Serializer s; st.add(s); @@ -120,12 +86,7 @@ private: return { masterPublic, signingKeys.first, - base64_encode(makeManifestString( - masterPublic, - secret, - signingKeys.first, - signingKeys.second, - 1))}; + base64_encode(makeManifestString(masterPublic, secret, signingKeys.first, signingKeys.second, 1))}; } std::string @@ -135,16 +96,16 @@ private: std::size_t validUntil, std::optional validFrom = {}) { - std::string data = "{\"sequence\":" + std::to_string(sequence) + - ",\"expiration\":" + std::to_string(validUntil); + std::string data = + "{\"sequence\":" + std::to_string(sequence) + ",\"expiration\":" + std::to_string(validUntil); if (validFrom) data += ",\"effective\":" + std::to_string(*validFrom); data += ",\"validators\":["; for (auto const& val : validators) { - data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) + - "\",\"manifest\":\"" + val.manifest + "\"},"; + data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) + "\",\"manifest\":\"" + val.manifest + + "\"},"; } data.pop_back(); @@ -153,9 +114,7 @@ private: } std::string - signList( - std::string const& blob, - std::pair const& keys) + signList(std::string const& blob, std::pair const& keys) { auto const data = base64_decode(blob); return strHex(sign(keys.first, keys.second, makeSlice(data))); @@ -195,22 +154,13 @@ private: auto& app = env.app(); { auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); BEAST_EXPECT(trustedKeys->quorum() == 1); } { std::size_t minQuorum = 0; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal, - minQuorum); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal, minQuorum); BEAST_EXPECT(trustedKeys->quorum() == minQuorum); } } @@ -220,8 +170,7 @@ private: { testcase("Config Load"); - jtx::Env env( - *this, jtx::envconfig(), nullptr, beast::severities::kDisabled); + jtx::Env env(*this, jtx::envconfig(), nullptr, beast::severities::kDisabled); auto& app = env.app(); std::vector const emptyCfgKeys; std::vector const emptyCfgPublishers; @@ -230,18 +179,12 @@ private: auto const localSigningPublicOuter = localSigningKeys.first; auto const localSigningSecret = localSigningKeys.second; auto const localMasterSecret = randomSecretKey(); - auto const localMasterPublic = - derivePublicKey(KeyType::ed25519, localMasterSecret); + auto const localMasterPublic = derivePublicKey(KeyType::ed25519, localMasterSecret); - std::string const cfgManifest(makeManifestString( - localMasterPublic, - localMasterSecret, - localSigningPublicOuter, - localSigningSecret, - 1)); + std::string const cfgManifest( + makeManifestString(localMasterPublic, localMasterSecret, localSigningPublicOuter, localSigningSecret, 1)); - auto format = [](PublicKey const& publicKey, - char const* comment = nullptr) { + auto format = [](PublicKey const& publicKey, char const* comment = nullptr) { auto ret = toBase58(TokenType::NodePublic, publicKey); if (comment) @@ -264,32 +207,23 @@ private: format(configList[3], " Leading Whitespace"), format(configList[4], " Trailing Whitespace "), format(configList[5], " Leading & Trailing Whitespace "), - format( - configList[6], - " Leading, Trailing & Internal Whitespace "), + format(configList[6], " Leading, Trailing & Internal Whitespace "), format(configList[7], " ")}); { ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); // Correct (empty) configuration - BEAST_EXPECT( - trustedKeys->load({}, emptyCfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, emptyCfgPublishers)); // load local validator key with or without manifest - BEAST_EXPECT(trustedKeys->load( - localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load(localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter)); manifests.applyManifest(*deserializeManifest(cfgManifest)); - BEAST_EXPECT(trustedKeys->load( - localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load(localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->listed(localMasterPublic)); BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter)); @@ -298,11 +232,7 @@ private: // load should add validator keys from config ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); BEAST_EXPECT(trustedKeys->load({}, cfgKeys, emptyCfgPublishers)); @@ -313,42 +243,29 @@ private: auto const masterNode1 = randomMasterKey(); auto const masterNode2 = randomMasterKey(); - std::vector cfgMasterKeys( - {format(masterNode1), format(masterNode2, " Comment")}); - BEAST_EXPECT( - trustedKeys->load({}, cfgMasterKeys, emptyCfgPublishers)); + std::vector cfgMasterKeys({format(masterNode1), format(masterNode2, " Comment")}); + BEAST_EXPECT(trustedKeys->load({}, cfgMasterKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->listed(masterNode1)); BEAST_EXPECT(trustedKeys->listed(masterNode2)); // load should reject invalid config keys - BEAST_EXPECT( - !trustedKeys->load({}, {"NotAPublicKey"}, emptyCfgPublishers)); - BEAST_EXPECT(!trustedKeys->load( - {}, {format(randomNode(), "!")}, emptyCfgPublishers)); + BEAST_EXPECT(!trustedKeys->load({}, {"NotAPublicKey"}, emptyCfgPublishers)); + BEAST_EXPECT(!trustedKeys->load({}, {format(randomNode(), "!")}, emptyCfgPublishers)); // load terminates when encountering an invalid entry auto const goodKey = randomNode(); - BEAST_EXPECT(!trustedKeys->load( - {}, - {format(randomNode(), "!"), format(goodKey)}, - emptyCfgPublishers)); + BEAST_EXPECT(!trustedKeys->load({}, {format(randomNode(), "!"), format(goodKey)}, emptyCfgPublishers)); BEAST_EXPECT(!trustedKeys->listed(goodKey)); } { // local validator key on config list ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); - auto const localSigningPublic = - parseBase58(TokenType::NodePublic, cfgKeys.front()); + auto const localSigningPublic = parseBase58(TokenType::NodePublic, cfgKeys.front()); - BEAST_EXPECT(trustedKeys->load( - *localSigningPublic, cfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load(*localSigningPublic, cfgKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic); BEAST_EXPECT(trustedKeys->listed(*localSigningPublic)); @@ -359,15 +276,10 @@ private: // local validator key not on config list ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const localSigningPublic = randomNode(); - BEAST_EXPECT(trustedKeys->load( - localSigningPublic, cfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load(localSigningPublic, cfgKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic); BEAST_EXPECT(trustedKeys->listed(localSigningPublic)); @@ -378,16 +290,11 @@ private: // local validator key (with manifest) not on config list ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); manifests.applyManifest(*deserializeManifest(cfgManifest)); - BEAST_EXPECT(trustedKeys->load( - localSigningPublicOuter, cfgKeys, emptyCfgPublishers)); + BEAST_EXPECT(trustedKeys->load(localSigningPublicOuter, cfgKeys, emptyCfgPublishers)); BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic); BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter)); @@ -398,11 +305,7 @@ private: { ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); // load should reject invalid validator list signing keys std::vector badPublishers({"NotASigningKey"}); @@ -410,8 +313,7 @@ private: // load should reject validator list signing keys with invalid // encoding - std::vector keys( - {randomMasterKey(), randomMasterKey(), randomMasterKey()}); + std::vector keys({randomMasterKey(), randomMasterKey(), randomMasterKey()}); badPublishers.clear(); for (auto const& key : keys) badPublishers.push_back(toBase58(TokenType::NodePublic, key)); @@ -428,30 +330,20 @@ private: BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); for (auto const& key : keys) BEAST_EXPECT(trustedKeys->trustedPublisher(key)); - BEAST_EXPECT( - trustedKeys->getListThreshold() == keys.size() / 2 + 1); + BEAST_EXPECT(trustedKeys->getListThreshold() == keys.size() / 2 + 1); } { ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); - std::vector keys( - {randomMasterKey(), - randomMasterKey(), - randomMasterKey(), - randomMasterKey()}); + std::vector keys({randomMasterKey(), randomMasterKey(), randomMasterKey(), randomMasterKey()}); std::vector cfgPublishers; for (auto const& key : keys) cfgPublishers.push_back(strHex(key)); // explicitly set the list threshold - BEAST_EXPECT(trustedKeys->load( - {}, emptyCfgKeys, cfgPublishers, std::size_t(2))); + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers, std::size_t(2))); for (auto const& key : keys) BEAST_EXPECT(trustedKeys->trustedPublisher(key)); BEAST_EXPECT(trustedKeys->getListThreshold() == 2); @@ -462,15 +354,10 @@ private: ManifestCache valManifests; ManifestCache pubManifests; auto trustedKeys = std::make_unique( - valManifests, - pubManifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + valManifests, pubManifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const pubRevokedSecret = randomSecretKey(); - auto const pubRevokedPublic = - derivePublicKey(KeyType::ed25519, pubRevokedSecret); + auto const pubRevokedPublic = derivePublicKey(KeyType::ed25519, pubRevokedSecret); auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1); // make this manifest revoked (seq num = max) // -- thus should not be loaded @@ -485,8 +372,7 @@ private: auto legitKey1 = randomMasterKey(); auto legitKey2 = randomMasterKey(); - std::vector cfgPublishers = { - strHex(pubRevokedPublic), strHex(legitKey1), strHex(legitKey2)}; + std::vector cfgPublishers = {strHex(pubRevokedPublic), strHex(legitKey1), strHex(legitKey2)}; BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic)); @@ -501,15 +387,10 @@ private: ManifestCache valManifests; ManifestCache pubManifests; auto trustedKeys = std::make_unique( - valManifests, - pubManifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + valManifests, pubManifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const pubRevokedSecret = randomSecretKey(); - auto const pubRevokedPublic = - derivePublicKey(KeyType::ed25519, pubRevokedSecret); + auto const pubRevokedPublic = derivePublicKey(KeyType::ed25519, pubRevokedSecret); auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1); // make this manifest revoked (seq num = max) // -- thus should not be loaded @@ -523,10 +404,8 @@ private: // this one is not revoked (and not in the manifest cache at all.) auto legitKey = randomMasterKey(); - std::vector cfgPublishers = { - strHex(pubRevokedPublic), strHex(legitKey)}; - BEAST_EXPECT(trustedKeys->load( - {}, emptyCfgKeys, cfgPublishers, std::size_t(2))); + std::vector cfgPublishers = {strHex(pubRevokedPublic), strHex(legitKey)}; + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers, std::size_t(2))); BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic)); BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey)); @@ -543,93 +422,74 @@ private: std::string const siteUri = "testApplyList.test"; - auto checkAvailable = - [this]( - auto const& trustedKeys, - auto const& hexPublic, - auto const& manifest, - auto const version, - std::vector> const& - expected) { - auto const available = trustedKeys->getAvailable(hexPublic); + auto checkAvailable = [this]( + auto const& trustedKeys, + auto const& hexPublic, + auto const& manifest, + auto const version, + std::vector> const& expected) { + auto const available = trustedKeys->getAvailable(hexPublic); - BEAST_EXPECT(!version || available); - if (available) + BEAST_EXPECT(!version || available); + if (available) + { + auto const& a = *available; + BEAST_EXPECT(a[jss::public_key] == hexPublic); + BEAST_EXPECT(a[jss::manifest] == manifest); + // Because multiple lists were processed, the version was + // overridden + BEAST_EXPECT(a[jss::version] == version); + if (version == 1) { - auto const& a = *available; - BEAST_EXPECT(a[jss::public_key] == hexPublic); - BEAST_EXPECT(a[jss::manifest] == manifest); - // Because multiple lists were processed, the version was - // overridden - BEAST_EXPECT(a[jss::version] == version); - if (version == 1) - { - BEAST_EXPECT(expected.size() == 1); - BEAST_EXPECT(a[jss::blob] == expected[0].first); - BEAST_EXPECT(a[jss::signature] == expected[0].second); - BEAST_EXPECT(!a.isMember(jss::blobs_v2)); - } - else if (BEAST_EXPECT(a.isMember(jss::blobs_v2))) - { - BEAST_EXPECT(!a.isMember(jss::blob)); - BEAST_EXPECT(!a.isMember(jss::signature)); - auto const& blobs_v2 = a[jss::blobs_v2]; - BEAST_EXPECT( - blobs_v2.isArray() && - blobs_v2.size() == expected.size()); + BEAST_EXPECT(expected.size() == 1); + BEAST_EXPECT(a[jss::blob] == expected[0].first); + BEAST_EXPECT(a[jss::signature] == expected[0].second); + BEAST_EXPECT(!a.isMember(jss::blobs_v2)); + } + else if (BEAST_EXPECT(a.isMember(jss::blobs_v2))) + { + BEAST_EXPECT(!a.isMember(jss::blob)); + BEAST_EXPECT(!a.isMember(jss::signature)); + auto const& blobs_v2 = a[jss::blobs_v2]; + BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == expected.size()); - for (unsigned int i = 0; i < expected.size(); ++i) - { - BEAST_EXPECT( - blobs_v2[i][jss::blob] == expected[i].first); - BEAST_EXPECT( - blobs_v2[i][jss::signature] == - expected[i].second); - } + for (unsigned int i = 0; i < expected.size(); ++i) + { + BEAST_EXPECT(blobs_v2[i][jss::blob] == expected[i].first); + BEAST_EXPECT(blobs_v2[i][jss::signature] == expected[i].second); } } - }; + } + }; ManifestCache manifests; jtx::Env env(*this); auto& app = env.app(); auto trustedKeys = std::make_unique( - manifests, - manifests, - env.app().timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.app().timeKeeper(), app.config().legacy("database_path"), env.journal); - auto expectTrusted = - [this, &trustedKeys](std::vector const& list) { - for (auto const& val : list) - { - BEAST_EXPECT(trustedKeys->listed(val.masterPublic)); - BEAST_EXPECT(trustedKeys->listed(val.signingPublic)); - } - }; + auto expectTrusted = [this, &trustedKeys](std::vector const& list) { + for (auto const& val : list) + { + BEAST_EXPECT(trustedKeys->listed(val.masterPublic)); + BEAST_EXPECT(trustedKeys->listed(val.signingPublic)); + } + }; - auto expectUntrusted = - [this, &trustedKeys](std::vector const& list) { - for (auto const& val : list) - { - BEAST_EXPECT(!trustedKeys->listed(val.masterPublic)); - BEAST_EXPECT(!trustedKeys->listed(val.signingPublic)); - } - }; + auto expectUntrusted = [this, &trustedKeys](std::vector const& list) { + for (auto const& val : list) + { + BEAST_EXPECT(!trustedKeys->listed(val.masterPublic)); + BEAST_EXPECT(!trustedKeys->listed(val.signingPublic)); + } + }; auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); - auto const hexPublic = - strHex(publisherPublic.begin(), publisherPublic.end()); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); + auto const hexPublic = strHex(publisherPublic.begin(), publisherPublic.end()); auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1); - auto const manifest1 = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys1.first, - pubSigningKeys1.second, - 1)); + auto const manifest1 = base64_encode( + makeManifestString(publisherPublic, publisherSecret, pubSigningKeys1.first, pubSigningKeys1.second, 1)); std::vector cfgKeys1({strHex(publisherPublic)}); std::vector emptyCfgKeys; @@ -655,32 +515,23 @@ private: env.timeKeeper().set(env.timeKeeper().now() + 1s); auto const version = 1; auto const sequence1 = 1; - auto const expiredblob = makeList( - lists.at(1), - sequence1, - env.timeKeeper().now().time_since_epoch().count()); + auto const expiredblob = makeList(lists.at(1), sequence1, env.timeKeeper().now().time_since_epoch().count()); auto const expiredSig = signList(expiredblob, pubSigningKeys1); NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s; auto const sequence2 = 2; - auto const blob2 = makeList( - lists.at(2), sequence2, validUntil.time_since_epoch().count()); + auto const blob2 = makeList(lists.at(2), sequence2, validUntil.time_since_epoch().count()); auto const sig2 = signList(blob2, pubSigningKeys1); checkResult( - trustedKeys->applyLists( - manifest1, - version, - {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version, {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}}, siteUri), publisherPublic, ListDisposition::expired, ListDisposition::accepted); expectTrusted(lists.at(2)); - checkAvailable( - trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}}); + checkAvailable(trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}}); // Do not apply future lists, but process them auto const version2 = 2; @@ -688,28 +539,18 @@ private: auto const effective7 = validUntil - 60s; auto const expiration7 = effective7 + 3600s; auto const blob7 = makeList( - lists.at(7), - sequence7, - expiration7.time_since_epoch().count(), - effective7.time_since_epoch().count()); + lists.at(7), sequence7, expiration7.time_since_epoch().count(), effective7.time_since_epoch().count()); auto const sig7 = signList(blob7, pubSigningKeys1); auto const sequence8 = 8; auto const effective8 = expiration7 - 60s; auto const expiration8 = effective8 + 3600s; auto const blob8 = makeList( - lists.at(8), - sequence8, - expiration8.time_since_epoch().count(), - effective8.time_since_epoch().count()); + lists.at(8), sequence8, expiration8.time_since_epoch().count(), effective8.time_since_epoch().count()); auto const sig8 = signList(blob8, pubSigningKeys1); checkResult( - trustedKeys->applyLists( - manifest1, - version2, - {{blob7, sig7, {}}, {blob8, sig8, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version2, {{blob7, sig7, {}}, {blob8, sig8, {}}}, siteUri), publisherPublic, ListDisposition::pending, ListDisposition::pending); @@ -722,10 +563,7 @@ private: auto const effective6 = effective7 - 60s; auto const expiration6 = effective6 + 3600s; auto const blob6 = makeList( - lists.at(6), - sequence6, - expiration6.time_since_epoch().count(), - effective6.time_since_epoch().count()); + lists.at(6), sequence6, expiration6.time_since_epoch().count(), effective6.time_since_epoch().count()); auto const sig6 = signList(blob6, pubSigningKeys1); // Process future list that is overridden by a later list @@ -733,18 +571,11 @@ private: auto const effective6a = effective6 + 60s; auto const expiration6a = effective6a + 3600s; auto const blob6a = makeList( - lists.at(5), - sequence6a, - expiration6a.time_since_epoch().count(), - effective6a.time_since_epoch().count()); + lists.at(5), sequence6a, expiration6a.time_since_epoch().count(), effective6a.time_since_epoch().count()); auto const sig6a = signList(blob6a, pubSigningKeys1); checkResult( - trustedKeys->applyLists( - manifest1, - version, - {{blob6a, sig6a, {}}, {blob6, sig6, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version, {{blob6a, sig6a, {}}, {blob6, sig6, {}}}, siteUri), publisherPublic, ListDisposition::pending, ListDisposition::pending); @@ -755,11 +586,7 @@ private: // Do not apply re-process lists known future sequence numbers checkResult( - trustedKeys->applyLists( - manifest1, - version, - {{blob7, sig7, {}}, {blob6, sig6, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), publisherPublic, ListDisposition::known_sequence, ListDisposition::known_sequence); @@ -770,33 +597,24 @@ private: // try empty or mangled manifest checkResult( - trustedKeys->applyLists( - "", version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), + trustedKeys->applyLists("", version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), publisherPublic, ListDisposition::invalid, ListDisposition::invalid); checkResult( trustedKeys->applyLists( - base64_encode("not a manifest"), - version, - {{blob7, sig7, {}}, {blob6, sig6, {}}}, - siteUri), + base64_encode("not a manifest"), version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), publisherPublic, ListDisposition::invalid, ListDisposition::invalid); // do not use list from untrusted publisher - auto const untrustedManifest = base64_encode(makeManifestString( - randomMasterKey(), - publisherSecret, - pubSigningKeys1.first, - pubSigningKeys1.second, - 1)); + auto const untrustedManifest = base64_encode( + makeManifestString(randomMasterKey(), publisherSecret, pubSigningKeys1.first, pubSigningKeys1.second, 1)); checkResult( - trustedKeys->applyLists( - untrustedManifest, version, {{blob2, sig2, {}}}, siteUri), + trustedKeys->applyLists(untrustedManifest, version, {{blob2, sig2, {}}}, siteUri), publisherPublic, ListDisposition::untrusted, ListDisposition::untrusted); @@ -804,21 +622,18 @@ private: // do not use list with unhandled version auto const badVersion = 666; checkResult( - trustedKeys->applyLists( - manifest1, badVersion, {{blob2, sig2, {}}}, siteUri), + trustedKeys->applyLists(manifest1, badVersion, {{blob2, sig2, {}}}, siteUri), publisherPublic, ListDisposition::unsupported_version, ListDisposition::unsupported_version); // apply list with highest sequence number auto const sequence3 = 3; - auto const blob3 = makeList( - lists.at(3), sequence3, validUntil.time_since_epoch().count()); + auto const blob3 = makeList(lists.at(3), sequence3, validUntil.time_since_epoch().count()); auto const sig3 = signList(blob3, pubSigningKeys1); checkResult( - trustedKeys->applyLists( - manifest1, version, {{blob3, sig3, {}}}, siteUri), + trustedKeys->applyLists(manifest1, version, {{blob3, sig3, {}}}, siteUri), publisherPublic, ListDisposition::accepted, ListDisposition::accepted); @@ -830,19 +645,11 @@ private: // Note that blob6a is not present, because it was dropped during // processing checkAvailable( - trustedKeys, - hexPublic, - manifest1, - 2, - {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); + trustedKeys, hexPublic, manifest1, 2, {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); // do not re-apply lists with past or current sequence numbers checkResult( - trustedKeys->applyLists( - manifest1, - version, - {{blob2, sig2, {}}, {blob3, sig3, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version, {{blob2, sig2, {}}, {blob3, sig3, {}}}, siteUri), publisherPublic, ListDisposition::stale, ListDisposition::same_sequence); @@ -850,26 +657,16 @@ private: // apply list with new publisher key updated by manifest. Also send some // old lists along with the old manifest auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1); - auto manifest2 = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys2.first, - pubSigningKeys2.second, - 2)); + auto manifest2 = base64_encode( + makeManifestString(publisherPublic, publisherSecret, pubSigningKeys2.first, pubSigningKeys2.second, 2)); auto const sequence4 = 4; - auto const blob4 = makeList( - lists.at(4), sequence4, validUntil.time_since_epoch().count()); + auto const blob4 = makeList(lists.at(4), sequence4, validUntil.time_since_epoch().count()); auto const sig4 = signList(blob4, pubSigningKeys2); checkResult( trustedKeys->applyLists( - manifest2, - version, - {{blob2, sig2, manifest1}, - {blob3, sig3, manifest1}, - {blob4, sig4, {}}}, - siteUri), + manifest2, version, {{blob2, sig2, manifest1}, {blob3, sig3, manifest1}, {blob4, sig4, {}}}, siteUri), publisherPublic, ListDisposition::stale, ListDisposition::accepted); @@ -879,19 +676,13 @@ private: expectTrusted(lists.at(4)); checkAvailable( - trustedKeys, - hexPublic, - manifest2, - 2, - {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); + trustedKeys, hexPublic, manifest2, 2, {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); auto const sequence5 = 5; - auto const blob5 = makeList( - lists.at(5), sequence5, validUntil.time_since_epoch().count()); + auto const blob5 = makeList(lists.at(5), sequence5, validUntil.time_since_epoch().count()); auto const badSig = signList(blob5, pubSigningKeys1); checkResult( - trustedKeys->applyLists( - manifest1, version, {{blob5, badSig, {}}}, siteUri), + trustedKeys->applyLists(manifest1, version, {{blob5, badSig, {}}}, siteUri), publisherPublic, ListDisposition::invalid, ListDisposition::invalid); @@ -903,11 +694,7 @@ private: // Reprocess the pending list, but the signature is no longer valid checkResult( - trustedKeys->applyLists( - manifest1, - version, - {{blob7, sig7, {}}, {blob8, sig8, {}}}, - siteUri), + trustedKeys->applyLists(manifest1, version, {{blob7, sig7, {}}, {blob8, sig8, {}}}, siteUri), publisherPublic, ListDisposition::invalid, ListDisposition::invalid); @@ -920,21 +707,12 @@ private: // updateTrusted. Note that the timekeeper is NOT moved, so the close // time will be ahead of the test's wall clock trustedKeys->updateTrusted( - {}, - effective6 + 1s, - env.app().getOPs(), - env.app().overlay(), - env.app().getHashRouter()); + {}, effective6 + 1s, env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); expectUntrusted(lists.at(3)); expectTrusted(lists.at(6)); - checkAvailable( - trustedKeys, - hexPublic, - manifest2, - 2, - {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); + checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}}); // Automatically rotate the LAST pending list using updateTrusted, // bypassing blob7. Note that the timekeeper IS moved, so the provided @@ -942,11 +720,7 @@ private: // clock is used. env.timeKeeper().set(effective8); trustedKeys->updateTrusted( - {}, - effective8 + 1s, - env.app().getOPs(), - env.app().overlay(), - env.app().getHashRouter()); + {}, effective8 + 1s, env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); expectUntrusted(lists.at(6)); expectUntrusted(lists.at(7)); @@ -961,11 +735,7 @@ private: auto const sig8_2 = signList(blob8, pubSigningKeys2); checkResult( - trustedKeys->applyLists( - manifest2, - version, - {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}}, - siteUri), + trustedKeys->applyLists(manifest2, version, {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}}, siteUri), publisherPublic, ListDisposition::invalid, ListDisposition::same_sequence); @@ -977,17 +747,14 @@ private: // do not apply list with revoked publisher key // applied list is removed due to revoked publisher key auto const signingKeysMax = randomKeyPair(KeyType::secp256k1); - auto maxManifest = base64_encode( - makeRevocationString(publisherPublic, publisherSecret)); + auto maxManifest = base64_encode(makeRevocationString(publisherPublic, publisherSecret)); auto const sequence9 = 9; - auto const blob9 = makeList( - lists.at(9), sequence9, validUntil.time_since_epoch().count()); + auto const blob9 = makeList(lists.at(9), sequence9, validUntil.time_since_epoch().count()); auto const sig9 = signList(blob9, signingKeysMax); checkResult( - trustedKeys->applyLists( - maxManifest, version, {{blob9, sig9, {}}}, siteUri), + trustedKeys->applyLists(maxManifest, version, {{blob9, sig9, {}}}, siteUri), publisherPublic, ListDisposition::untrusted, ListDisposition::untrusted); @@ -1014,24 +781,14 @@ private: jtx::Env env(*this); auto& app = env.app(); auto trustedKeys = std::make_unique( - manifests, - manifests, - env.app().timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.app().timeKeeper(), app.config().legacy("database_path"), env.journal); auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); - auto const hexPublic = - strHex(publisherPublic.begin(), publisherPublic.end()); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); + auto const hexPublic = strHex(publisherPublic.begin(), publisherPublic.end()); auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1); - auto const manifest = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys1.first, - pubSigningKeys1.second, - 1)); + auto const manifest = base64_encode( + makeManifestString(publisherPublic, publisherSecret, pubSigningKeys1.first, pubSigningKeys1.second, 1)); std::vector cfgKeys1({strHex(publisherPublic)}); std::vector emptyCfgKeys; @@ -1050,8 +807,7 @@ private: // Process a list env.timeKeeper().set(env.timeKeeper().now() + 1s); NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s; - auto const blob = - makeList(list, 1, validUntil.time_since_epoch().count()); + auto const blob = makeList(list, 1, validUntil.time_since_epoch().count()); auto const sig = signList(blob, pubSigningKeys1); { @@ -1061,13 +817,12 @@ private: } BEAST_EXPECT( - trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri) - .bestDisposition() == ListDisposition::accepted); + trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri).bestDisposition() == + ListDisposition::accepted); { // invalid public key - auto const available = - trustedKeys->getAvailable(hexPublic + "invalid", 1); + auto const available = trustedKeys->getAvailable(hexPublic + "invalid", 1); BEAST_EXPECT(!available); } @@ -1149,11 +904,7 @@ private: jtx::Env env(*this); auto& app = env.app(); auto trustedKeysOuter = std::make_unique( - manifestsOuter, - manifestsOuter, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifestsOuter, manifestsOuter, env.timeKeeper(), app.config().legacy("database_path"), env.journal); std::vector cfgPublishersOuter; hash_set activeValidatorsOuter; @@ -1174,8 +925,7 @@ private: unseenValidators.emplace(calcNodeID(valKey)); } - BEAST_EXPECT( - trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter)); + BEAST_EXPECT(trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter)); // updateTrusted should make all configured validators trusted // even if they are not active/seen @@ -1191,12 +941,10 @@ private: BEAST_EXPECT(changes.added == activeValidatorsOuter); BEAST_EXPECT(changes.removed.empty()); - BEAST_EXPECT( - trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f)); + BEAST_EXPECT(trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f)); for (auto const& val : cfgKeys) { - if (auto const valKey = - parseBase58(TokenType::NodePublic, val)) + if (auto const valKey = parseBase58(TokenType::NodePublic, val)) { BEAST_EXPECT(trustedKeysOuter->listed(*valKey)); BEAST_EXPECT(trustedKeysOuter->trusted(*valKey)); @@ -1213,20 +961,16 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.added.empty()); BEAST_EXPECT(changes.removed.empty()); - BEAST_EXPECT( - trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f)); + BEAST_EXPECT(trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f)); } { // update with manifests auto const masterPrivate = randomSecretKey(); - auto const masterPublic = - derivePublicKey(KeyType::ed25519, masterPrivate); + auto const masterPublic = derivePublicKey(KeyType::ed25519, masterPrivate); - std::vector cfgKeys( - {toBase58(TokenType::NodePublic, masterPublic)}); + std::vector cfgKeys({toBase58(TokenType::NodePublic, masterPublic)}); - BEAST_EXPECT( - trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter)); + BEAST_EXPECT(trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter)); auto const signingKeys1 = randomKeyPair(KeyType::secp256k1); auto const signingPublic1 = signingKeys1.first; @@ -1241,24 +985,17 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.added == asNodeIDs({masterPublic})); BEAST_EXPECT(changes.removed.empty()); - BEAST_EXPECT( - trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f)); + BEAST_EXPECT(trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f)); BEAST_EXPECT(trustedKeysOuter->listed(masterPublic)); BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic)); BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1)); BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1)); // Should trust the ephemeral signing key from the applied manifest - auto m1 = deserializeManifest(makeManifestString( - masterPublic, - masterPrivate, - signingPublic1, - signingKeys1.second, - 1)); + auto m1 = deserializeManifest( + makeManifestString(masterPublic, masterPrivate, signingPublic1, signingKeys1.second, 1)); - BEAST_EXPECT( - manifestsOuter.applyManifest(std::move(*m1)) == - ManifestDisposition::accepted); + BEAST_EXPECT(manifestsOuter.applyManifest(std::move(*m1)) == ManifestDisposition::accepted); BEAST_EXPECT(trustedKeysOuter->listed(masterPublic)); BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic)); BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1)); @@ -1268,15 +1005,9 @@ private: // from the newest applied manifest auto const signingKeys2 = randomKeyPair(KeyType::secp256k1); auto const signingPublic2 = signingKeys2.first; - auto m2 = deserializeManifest(makeManifestString( - masterPublic, - masterPrivate, - signingPublic2, - signingKeys2.second, - 2)); - BEAST_EXPECT( - manifestsOuter.applyManifest(std::move(*m2)) == - ManifestDisposition::accepted); + auto m2 = deserializeManifest( + makeManifestString(masterPublic, masterPrivate, signingPublic2, signingKeys2.second, 2)); + BEAST_EXPECT(manifestsOuter.applyManifest(std::move(*m2)) == ManifestDisposition::accepted); BEAST_EXPECT(trustedKeysOuter->listed(masterPublic)); BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic)); BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2)); @@ -1288,15 +1019,11 @@ private: auto const signingKeysMax = randomKeyPair(KeyType::secp256k1); auto const signingPublicMax = signingKeysMax.first; activeValidatorsOuter.emplace(calcNodeID(signingPublicMax)); - auto mMax = deserializeManifest( - makeRevocationString(masterPublic, masterPrivate)); + auto mMax = deserializeManifest(makeRevocationString(masterPublic, masterPrivate)); BEAST_EXPECT(mMax->revoked()); - BEAST_EXPECT( - manifestsOuter.applyManifest(std::move(*mMax)) == - ManifestDisposition::accepted); - BEAST_EXPECT( - manifestsOuter.getSigningKey(masterPublic) == masterPublic); + BEAST_EXPECT(manifestsOuter.applyManifest(std::move(*mMax)) == ManifestDisposition::accepted); + BEAST_EXPECT(manifestsOuter.getSigningKey(masterPublic) == masterPublic); BEAST_EXPECT(manifestsOuter.revoked(masterPublic)); // Revoked key remains trusted until list is updated @@ -1311,8 +1038,7 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic})); BEAST_EXPECT(changes.added.empty()); - BEAST_EXPECT( - trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f)); + BEAST_EXPECT(trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f)); BEAST_EXPECT(trustedKeysOuter->listed(masterPublic)); BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic)); BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax)); @@ -1326,14 +1052,9 @@ private: // Make quorum unattainable if lists from any publishers are // unavailable auto trustedKeys = std::make_unique( - manifestsOuter, - manifestsOuter, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifestsOuter, manifestsOuter, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); std::vector cfgPublishers({strHex(publisherPublic)}); std::vector emptyCfgKeys; @@ -1348,36 +1069,24 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.removed.empty()); BEAST_EXPECT(changes.added.empty()); - BEAST_EXPECT( - trustedKeys->quorum() == - std::numeric_limits::max()); + BEAST_EXPECT(trustedKeys->quorum() == std::numeric_limits::max()); } { // Trust explicitly listed validators also when list threshold is // higher than 1 auto trustedKeys = std::make_unique( - manifestsOuter, - manifestsOuter, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifestsOuter, manifestsOuter, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const masterPrivate = randomSecretKey(); - auto const masterPublic = - derivePublicKey(KeyType::ed25519, masterPrivate); - std::vector cfgKeys( - {toBase58(TokenType::NodePublic, masterPublic)}); + auto const masterPublic = derivePublicKey(KeyType::ed25519, masterPrivate); + std::vector cfgKeys({toBase58(TokenType::NodePublic, masterPublic)}); auto const publisher1Secret = randomSecretKey(); - auto const publisher1Public = - derivePublicKey(KeyType::ed25519, publisher1Secret); + auto const publisher1Public = derivePublicKey(KeyType::ed25519, publisher1Secret); auto const publisher2Secret = randomSecretKey(); - auto const publisher2Public = - derivePublicKey(KeyType::ed25519, publisher2Secret); - std::vector cfgPublishers( - {strHex(publisher1Public), strHex(publisher2Public)}); + auto const publisher2Public = derivePublicKey(KeyType::ed25519, publisher2Secret); + std::vector cfgPublishers({strHex(publisher1Public), strHex(publisher2Public)}); - BEAST_EXPECT( - trustedKeys->load({}, cfgKeys, cfgPublishers, std::size_t(2))); + BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishers, std::size_t(2))); TrustChanges changes = trustedKeys->updateTrusted( activeValidatorsOuter, @@ -1395,12 +1104,7 @@ private: std::size_t const minQuorum = 1; ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal, - minQuorum); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal, minQuorum); std::size_t n = 10; std::vector cfgKeys; @@ -1457,35 +1161,26 @@ private: auto const publisherKeys = randomKeyPair(KeyType::secp256k1); auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1); auto const manifest = base64_encode(makeManifestString( - publisherKeys.first, - publisherKeys.second, - pubSigningKeys.first, - pubSigningKeys.second, - 1)); + publisherKeys.first, publisherKeys.second, pubSigningKeys.first, pubSigningKeys.second, 1)); std::vector cfgKeys({strHex(publisherKeys.first)}); BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys)); std::vector list({randomValidator(), randomValidator()}); - hash_set activeValidators( - asNodeIDs({list[0].masterPublic, list[1].masterPublic})); + hash_set activeValidators(asNodeIDs({list[0].masterPublic, list[1].masterPublic})); // do not apply expired list auto const version = 1; auto const sequence = 1; using namespace std::chrono_literals; - NetClock::time_point const validUntil = - env.timeKeeper().now() + 60s; - auto const blob = - makeList(list, sequence, validUntil.time_since_epoch().count()); + NetClock::time_point const validUntil = env.timeKeeper().now() + 60s; + auto const blob = makeList(list, sequence, validUntil.time_since_epoch().count()); auto const sig = signList(blob, pubSigningKeys); BEAST_EXPECT( ListDisposition::accepted == - trustedKeys - ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri) - .bestDisposition()); + trustedKeys->applyLists(manifest, version, {{blob, sig, {}}}, siteUri).bestDisposition()); TrustChanges changes = trustedKeys->updateTrusted( activeValidators, @@ -1513,26 +1208,19 @@ private: BEAST_EXPECT(changes.added.empty()); BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic)); BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic)); - BEAST_EXPECT( - trustedKeys->quorum() == - std::numeric_limits::max()); + BEAST_EXPECT(trustedKeys->quorum() == std::numeric_limits::max()); // (Re)trust validators from new valid list std::vector list2({list[0], randomValidator()}); activeValidators.insert(calcNodeID(list2[1].masterPublic)); auto const sequence2 = 2; - NetClock::time_point const expiration2 = - env.timeKeeper().now() + 60s; - auto const blob2 = makeList( - list2, sequence2, expiration2.time_since_epoch().count()); + NetClock::time_point const expiration2 = env.timeKeeper().now() + 60s; + auto const blob2 = makeList(list2, sequence2, expiration2.time_since_epoch().count()); auto const sig2 = signList(blob2, pubSigningKeys); BEAST_EXPECT( ListDisposition::accepted == - trustedKeys - ->applyLists( - manifest, version, {{blob2, sig2, {}}}, siteUri) - .bestDisposition()); + trustedKeys->applyLists(manifest, version, {{blob2, sig2, {}}}, siteUri).bestDisposition()); changes = trustedKeys->updateTrusted( activeValidators, @@ -1541,9 +1229,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(changes.removed.empty()); - BEAST_EXPECT( - changes.added == - asNodeIDs({list2[0].masterPublic, list2[1].masterPublic})); + BEAST_EXPECT(changes.added == asNodeIDs({list2[0].masterPublic, list2[1].masterPublic})); for (Validator const& val : list2) { BEAST_EXPECT(trustedKeys->trusted(val.masterPublic)); @@ -1556,11 +1242,7 @@ private: { // Test 1-9 configured validators auto trustedKeys = std::make_unique( - manifestsOuter, - manifestsOuter, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifestsOuter, manifestsOuter, env.timeKeeper(), app.config().legacy("database_path"), env.journal); std::vector cfgPublishers; hash_set activeValidators; @@ -1584,8 +1266,7 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.removed.empty()); BEAST_EXPECT(changes.added == asNodeIDs({valKey})); - BEAST_EXPECT( - trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)); + BEAST_EXPECT(trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)); for (auto const& key : activeKeys) BEAST_EXPECT(trustedKeys->trusted(key)); } @@ -1593,18 +1274,13 @@ private: { // Test 2-9 configured validators as validator auto trustedKeys = std::make_unique( - manifestsOuter, - manifestsOuter, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifestsOuter, manifestsOuter, env.timeKeeper(), app.config().legacy("database_path"), env.journal); auto const localKey = randomNode(); std::vector cfgPublishers; hash_set activeValidators; hash_set activeKeys; - std::vector cfgKeys{ - toBase58(TokenType::NodePublic, localKey)}; + std::vector cfgKeys{toBase58(TokenType::NodePublic, localKey)}; cfgKeys.reserve(9); while (cfgKeys.size() < cfgKeys.capacity()) @@ -1614,8 +1290,7 @@ private: activeValidators.emplace(calcNodeID(valKey)); activeKeys.emplace(valKey); - BEAST_EXPECT( - trustedKeys->load(localKey, cfgKeys, cfgPublishers)); + BEAST_EXPECT(trustedKeys->load(localKey, cfgKeys, cfgPublishers)); TrustChanges changes = trustedKeys->updateTrusted( activeValidators, env.timeKeeper().now(), @@ -1626,11 +1301,9 @@ private: if (cfgKeys.size() > 2) BEAST_EXPECT(changes.added == asNodeIDs({valKey})); else - BEAST_EXPECT( - changes.added == asNodeIDs({localKey, valKey})); + BEAST_EXPECT(changes.added == asNodeIDs({localKey, valKey})); - BEAST_EXPECT( - trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)); + BEAST_EXPECT(trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)); for (auto const& key : activeKeys) BEAST_EXPECT(trustedKeys->trusted(key)); @@ -1640,11 +1313,7 @@ private: // Trusted set should include all validators from multiple lists ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); hash_set activeValidators; std::vector valKeys; @@ -1653,19 +1322,14 @@ private: while (valKeys.size() != maxKeys) { valKeys.push_back(randomValidator()); - activeValidators.emplace( - calcNodeID(valKeys.back().masterPublic)); + activeValidators.emplace(calcNodeID(valKeys.back().masterPublic)); } // locals[0]: from 0 to maxKeys - 4 // locals[1]: from 1 to maxKeys - 2 // locals[2]: from 2 to maxKeys constexpr static int publishers = 3; - std::array< - std::pair< - decltype(valKeys)::const_iterator, - decltype(valKeys)::const_iterator>, - publishers> + std::array, publishers> locals = { std::make_pair(valKeys.cbegin(), valKeys.cend() - 4), std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2), @@ -1674,41 +1338,28 @@ private: auto addPublishedList = [&, this](int i) { auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1); auto const manifest = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys.first, - pubSigningKeys.second, - 1)); + publisherPublic, publisherSecret, pubSigningKeys.first, pubSigningKeys.second, 1)); - std::vector cfgPublishers( - {strHex(publisherPublic)}); + std::vector cfgPublishers({strHex(publisherPublic)}); std::vector emptyCfgKeys; // Threshold of 1 will result in a union of all the lists - BEAST_EXPECT(trustedKeys->load( - {}, emptyCfgKeys, cfgPublishers, std::size_t(1))); + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers, std::size_t(1))); auto const version = 1; auto const sequence = 1; using namespace std::chrono_literals; - NetClock::time_point const validUntil = - env.timeKeeper().now() + 3600s; - std::vector localKeys{ - locals[i].first, locals[i].second}; - auto const blob = makeList( - localKeys, sequence, validUntil.time_since_epoch().count()); + NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s; + std::vector localKeys{locals[i].first, locals[i].second}; + auto const blob = makeList(localKeys, sequence, validUntil.time_since_epoch().count()); auto const sig = signList(blob, pubSigningKeys); BEAST_EXPECT( ListDisposition::accepted == - trustedKeys - ->applyLists( - manifest, version, {{blob, sig, {}}}, siteUri) - .bestDisposition()); + trustedKeys->applyLists(manifest, version, {{blob, sig, {}}}, siteUri).bestDisposition()); }; // Apply multiple published lists @@ -1723,8 +1374,7 @@ private: env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f)); + BEAST_EXPECT(trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f)); hash_set added; for (auto const& val : valKeys) @@ -1739,11 +1389,7 @@ private: // Trusted set should include validators from intersection of lists ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); hash_set activeValidators; std::vector valKeys; @@ -1752,21 +1398,16 @@ private: while (valKeys.size() != maxKeys) { valKeys.push_back(randomValidator()); - activeValidators.emplace( - calcNodeID(valKeys.back().masterPublic)); + activeValidators.emplace(calcNodeID(valKeys.back().masterPublic)); } // locals[0]: from 0 to maxKeys - 4 // locals[1]: from 1 to maxKeys - 2 // locals[2]: from 2 to maxKeys - // interesection of at least 2: same as locals[1] + // intersection of at least 2: same as locals[1] // intersection when 1 is dropped: from 2 to maxKeys - 4 constexpr static int publishers = 3; - std::array< - std::pair< - decltype(valKeys)::const_iterator, - decltype(valKeys)::const_iterator>, - publishers> + std::array, publishers> locals = { std::make_pair(valKeys.cbegin(), valKeys.cend() - 4), std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2), @@ -1774,51 +1415,34 @@ private: }; auto addPublishedList = [&, this]( - int i, - NetClock::time_point& validUntil1, - NetClock::time_point& validUntil2) { + int i, NetClock::time_point& validUntil1, NetClock::time_point& validUntil2) { auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1); auto const manifest = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys.first, - pubSigningKeys.second, - 1)); + publisherPublic, publisherSecret, pubSigningKeys.first, pubSigningKeys.second, 1)); - std::vector cfgPublishers( - {strHex(publisherPublic)}); + std::vector cfgPublishers({strHex(publisherPublic)}); std::vector emptyCfgKeys; - BEAST_EXPECT( - trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); auto const version = 1; auto const sequence = 1; using namespace std::chrono_literals; // Want to drop 1 sooner - NetClock::time_point const validUntil = env.timeKeeper().now() + - (i == 2 ? 120s - : i == 1 ? 60s - : 3600s); + NetClock::time_point const validUntil = env.timeKeeper().now() + (i == 2 ? 120s : i == 1 ? 60s : 3600s); if (i == 1) validUntil1 = validUntil; else if (i == 2) validUntil2 = validUntil; - std::vector localKeys{ - locals[i].first, locals[i].second}; - auto const blob = makeList( - localKeys, sequence, validUntil.time_since_epoch().count()); + std::vector localKeys{locals[i].first, locals[i].second}; + auto const blob = makeList(localKeys, sequence, validUntil.time_since_epoch().count()); auto const sig = signList(blob, pubSigningKeys); BEAST_EXPECT( ListDisposition::accepted == - trustedKeys - ->applyLists( - manifest, version, {{blob, sig, {}}}, siteUri) - .bestDisposition()); + trustedKeys->applyLists(manifest, version, {{blob, sig, {}}}, siteUri).bestDisposition()); }; // Apply multiple published lists @@ -1835,9 +1459,7 @@ private: env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->quorum() == - std::ceil((valKeys.size() - 3) * 0.8f)); + BEAST_EXPECT(trustedKeys->quorum() == std::ceil((valKeys.size() - 3) * 0.8f)); for (auto const& val : valKeys) BEAST_EXPECT(trustedKeys->listed(val.masterPublic)); @@ -1866,9 +1488,7 @@ private: env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->quorum() == - std::ceil((valKeys.size() - 6) * 0.8f)); + BEAST_EXPECT(trustedKeys->quorum() == std::ceil((valKeys.size() - 6) * 0.8f)); for (auto const& val : valKeys) BEAST_EXPECT(trustedKeys->listed(val.masterPublic)); @@ -1899,9 +1519,7 @@ private: env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->quorum() == - std::numeric_limits::max()); + BEAST_EXPECT(trustedKeys->quorum() == std::numeric_limits::max()); removed.clear(); for (std::size_t i = 0; i < maxKeys; ++i) @@ -1932,19 +1550,13 @@ private: jtx::Env env(*this); auto& app = env.app(); - auto toStr = [](PublicKey const& publicKey) { - return toBase58(TokenType::NodePublic, publicKey); - }; + auto toStr = [](PublicKey const& publicKey) { return toBase58(TokenType::NodePublic, publicKey); }; // Config listed keys { ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); // Empty list has no expiration BEAST_EXPECT(trustedKeys->expires() == std::nullopt); @@ -1952,9 +1564,7 @@ private: // Config listed keys have maximum expiry PublicKey localCfgListed = randomNode(); trustedKeys->load({}, {toStr(localCfgListed)}, {}); - BEAST_EXPECT( - trustedKeys->expires() && - trustedKeys->expires().value() == NetClock::time_point::max()); + BEAST_EXPECT(trustedKeys->expires() && trustedKeys->expires().value() == NetClock::time_point::max()); BEAST_EXPECT(trustedKeys->listed(localCfgListed)); } @@ -1962,11 +1572,7 @@ private: { ManifestCache manifests; auto trustedKeys = std::make_unique( - manifests, - manifests, - env.app().timeKeeper(), - app.config().legacy("database_path"), - env.journal); + manifests, manifests, env.app().timeKeeper(), app.config().legacy("database_path"), env.journal); std::vector validators = {randomValidator()}; hash_set activeValidators; @@ -1985,31 +1591,20 @@ private: using namespace std::chrono_literals; auto addPublishedList = [this, &env, &trustedKeys, &validators]() { auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1); auto const manifest = base64_encode(makeManifestString( - publisherPublic, - publisherSecret, - pubSigningKeys.first, - pubSigningKeys.second, - 1)); + publisherPublic, publisherSecret, pubSigningKeys.first, pubSigningKeys.second, 1)); - std::vector cfgPublishers( - {strHex(publisherPublic)}); + std::vector cfgPublishers({strHex(publisherPublic)}); std::vector emptyCfgKeys; - BEAST_EXPECT( - trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); + BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers)); auto const version = 2; auto const sequence1 = 1; - NetClock::time_point const expiration1 = - env.timeKeeper().now() + 1800s; - auto const blob1 = makeList( - validators, - sequence1, - expiration1.time_since_epoch().count()); + NetClock::time_point const expiration1 = env.timeKeeper().now() + 1800s; + auto const blob1 = makeList(validators, sequence1, expiration1.time_since_epoch().count()); auto const sig1 = signList(blob1, pubSigningKeys); NetClock::time_point const effective2 = expiration1 - 300s; @@ -2040,8 +1635,7 @@ private: // Apply first list checkResult( - trustedKeys->applyLists( - prep1.manifest, prep1.version, prep1.blobs, siteUri), + trustedKeys->applyLists(prep1.manifest, prep1.version, prep1.blobs, siteUri), prep1.publisherPublic, ListDisposition::pending, ListDisposition::accepted); @@ -2052,15 +1646,12 @@ private: // Apply second list checkResult( - trustedKeys->applyLists( - prep2.manifest, prep2.version, prep2.blobs, siteUri), + trustedKeys->applyLists(prep2.manifest, prep2.version, prep2.blobs, siteUri), prep2.publisherPublic, ListDisposition::pending, ListDisposition::accepted); // We now have loaded both lists, so expiration is known - BEAST_EXPECT( - trustedKeys->expires() && - trustedKeys->expires().value() == prep1.expirations.back()); + BEAST_EXPECT(trustedKeys->expires() && trustedKeys->expires().value() == prep1.expirations.back()); // Advance past the first list's LAST validFrom date. It remains // the earliest validUntil, while rotating in the second list @@ -2072,9 +1663,7 @@ private: env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->expires() && - trustedKeys->expires().value() == prep1.expirations.back()); + BEAST_EXPECT(trustedKeys->expires() && trustedKeys->expires().value() == prep1.expirations.back()); BEAST_EXPECT(!changes.added.empty()); BEAST_EXPECT(changes.removed.empty()); } @@ -2089,9 +1678,7 @@ private: env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); - BEAST_EXPECT( - trustedKeys->expires() && - trustedKeys->expires().value() == prep1.expirations.back()); + BEAST_EXPECT(trustedKeys->expires() && trustedKeys->expires().value() == prep1.expirations.back()); BEAST_EXPECT(changes.added.empty()); BEAST_EXPECT(changes.removed.empty()); } @@ -2106,9 +1693,7 @@ private: ManifestCache manifests; auto createValidatorList = - [&](std::uint32_t vlSize, - std::optional minimumQuorum = {}) - -> std::shared_ptr { + [&](std::uint32_t vlSize, std::optional minimumQuorum = {}) -> std::shared_ptr { auto trustedKeys = std::make_shared( manifests, manifests, @@ -2135,8 +1720,7 @@ private: env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); - if (minimumQuorum == trustedKeys->quorum() || - trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)) + if (minimumQuorum == trustedKeys->quorum() || trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)) return trustedKeys; } return nullptr; @@ -2187,8 +1771,7 @@ private: env.app().getHashRouter()); BEAST_EXPECT( validators->quorum() == - static_cast(std::ceil( - std::max((us - nUnlSize) * 0.8f, us * 0.6f)))); + static_cast(std::ceil(std::max((us - nUnlSize) * 0.8f, us * 0.6f)))); } } } @@ -2206,8 +1789,7 @@ private: { //-- set == get, //-- check quorum, with nUNL size: 0, 30, 18, 12 - auto nUnlChange = [&](std::uint32_t nUnlSize, - std::uint32_t quorum) -> bool { + auto nUnlChange = [&](std::uint32_t nUnlSize, std::uint32_t quorum) -> bool { hash_set nUnl; auto it = unl.begin(); for (std::uint32_t i = 0; i < nUnlSize; ++i) @@ -2313,7 +1895,7 @@ private: { testcase("Sha512 hashing"); // Tests that ValidatorList hash_append helpers with a single blob - // returns the same result as ripple::Sha512Half used by the + // returns the same result as xrpl::Sha512Half used by the // TMValidatorList protocol message handler std::string const manifest = "This is not really a manifest"; std::string const blob = "This is not really a blob"; @@ -2330,8 +1912,7 @@ private: BEAST_EXPECT(global != sha512Half(signature, blobVector, version)); { - std::map blobMap{ - {99, blobVector[0]}}; + std::map blobMap{{99, blobVector[0]}}; BEAST_EXPECT(global == sha512Half(manifest, blobMap, version)); BEAST_EXPECT(global != sha512Half(blob, blobMap, version)); } @@ -2367,8 +1948,7 @@ private: std::uint32_t const manifestCutoff = 7; auto extractHeader = [this](Message& message) { - auto const& buffer = - message.getBuffer(compression::Compressed::Off); + auto const& buffer = message.getBuffer(compression::Compressed::Off); boost::beast::multi_buffer buffers; @@ -2376,162 +1956,117 @@ private: auto start = buffer.begin(); auto end = buffer.end(); std::vector slice(start, end); - buffers.commit(boost::asio::buffer_copy( - buffers.prepare(slice.size()), boost::asio::buffer(slice))); + buffers.commit(boost::asio::buffer_copy(buffers.prepare(slice.size()), boost::asio::buffer(slice))); boost::system::error_code ec; - auto header = - detail::parseMessageHeader(ec, buffers.data(), buffers.size()); + auto header = detail::parseMessageHeader(ec, buffers.data(), buffers.size()); BEAST_EXPECT(!ec); return std::make_pair(header, buffers); }; - auto extractProtocolMessage1 = [this, - &extractHeader](Message& message) { + auto extractProtocolMessage1 = [this, &extractHeader](Message& message) { auto [header, buffers] = extractHeader(message); - if (BEAST_EXPECT(header) && - BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST)) + if (BEAST_EXPECT(header) && BEAST_EXPECT(header->message_type == protocol::mtVALIDATOR_LIST)) { - auto const msg = - detail::parseMessageContent( - *header, buffers.data()); + auto const msg = detail::parseMessageContent(*header, buffers.data()); BEAST_EXPECT(msg); return msg; } return std::shared_ptr(); }; - auto extractProtocolMessage2 = [this, - &extractHeader](Message& message) { + auto extractProtocolMessage2 = [this, &extractHeader](Message& message) { auto [header, buffers] = extractHeader(message); - if (BEAST_EXPECT(header) && - BEAST_EXPECT( - header->message_type == - protocol::mtVALIDATORLISTCOLLECTION)) + if (BEAST_EXPECT(header) && BEAST_EXPECT(header->message_type == protocol::mtVALIDATOR_LIST_COLLECTION)) { - auto const msg = detail::parseMessageContent< - protocol::TMValidatorListCollection>( - *header, buffers.data()); + auto const msg = + detail::parseMessageContent(*header, buffers.data()); BEAST_EXPECT(msg); return msg; } return std::shared_ptr(); }; - auto verifyMessage = - [this, - manifestCutoff, - &extractProtocolMessage1, - &extractProtocolMessage2]( - auto const version, - auto const& manifest, - auto const& blobInfos, - auto const& messages, - std::vector>> - expectedInfo) { - BEAST_EXPECT(messages.size() == expectedInfo.size()); - auto msgIter = expectedInfo.begin(); - for (auto const& messageWithHash : messages) + auto verifyMessage = [this, manifestCutoff, &extractProtocolMessage1, &extractProtocolMessage2]( + auto const version, + auto const& manifest, + auto const& blobInfos, + auto const& messages, + std::vector>> expectedInfo) { + BEAST_EXPECT(messages.size() == expectedInfo.size()); + auto msgIter = expectedInfo.begin(); + for (auto const& messageWithHash : messages) + { + if (!BEAST_EXPECT(msgIter != expectedInfo.end())) + break; + if (!BEAST_EXPECT(messageWithHash.message)) + continue; + auto const& expectedSeqs = msgIter->second; + auto seqIter = expectedSeqs.begin(); + auto const size = messageWithHash.message->getBuffer(compression::Compressed::Off).size(); + // This size is arbitrary, but shouldn't change + BEAST_EXPECT(size == msgIter->first); + if (expectedSeqs.size() == 1) { - if (!BEAST_EXPECT(msgIter != expectedInfo.end())) - break; - if (!BEAST_EXPECT(messageWithHash.message)) - continue; - auto const& expectedSeqs = msgIter->second; - auto seqIter = expectedSeqs.begin(); - auto const size = - messageWithHash.message - ->getBuffer(compression::Compressed::Off) - .size(); - // This size is arbitrary, but shouldn't change - BEAST_EXPECT(size == msgIter->first); - if (expectedSeqs.size() == 1) + auto const msg = extractProtocolMessage1(*messageWithHash.message); + auto const expectedVersion = 1; + if (BEAST_EXPECT(msg)) { - auto const msg = - extractProtocolMessage1(*messageWithHash.message); - auto const expectedVersion = 1; - if (BEAST_EXPECT(msg)) - { - BEAST_EXPECT(msg->version() == expectedVersion); - if (!BEAST_EXPECT(seqIter != expectedSeqs.end())) - continue; - auto const& expectedBlob = blobInfos.at(*seqIter); - BEAST_EXPECT( - (*seqIter < manifestCutoff) == - !!expectedBlob.manifest); - auto const expectedManifest = - *seqIter < manifestCutoff && - expectedBlob.manifest - ? *expectedBlob.manifest - : manifest; - BEAST_EXPECT(msg->manifest() == expectedManifest); - BEAST_EXPECT(msg->blob() == expectedBlob.blob); - BEAST_EXPECT( - msg->signature() == expectedBlob.signature); - ++seqIter; - BEAST_EXPECT(seqIter == expectedSeqs.end()); + BEAST_EXPECT(msg->version() == expectedVersion); + if (!BEAST_EXPECT(seqIter != expectedSeqs.end())) + continue; + auto const& expectedBlob = blobInfos.at(*seqIter); + BEAST_EXPECT((*seqIter < manifestCutoff) == !!expectedBlob.manifest); + auto const expectedManifest = + *seqIter < manifestCutoff && expectedBlob.manifest ? *expectedBlob.manifest : manifest; + BEAST_EXPECT(msg->manifest() == expectedManifest); + BEAST_EXPECT(msg->blob() == expectedBlob.blob); + BEAST_EXPECT(msg->signature() == expectedBlob.signature); + ++seqIter; + BEAST_EXPECT(seqIter == expectedSeqs.end()); - BEAST_EXPECT( - messageWithHash.hash == - sha512Half( - expectedManifest, - expectedBlob.blob, - expectedBlob.signature, - expectedVersion)); - } - } - else - { - std::vector hashingBlobs; - hashingBlobs.reserve(msgIter->second.size()); - - auto const msg = - extractProtocolMessage2(*messageWithHash.message); - if (BEAST_EXPECT(msg)) - { - BEAST_EXPECT(msg->version() == version); - BEAST_EXPECT(msg->manifest() == manifest); - for (auto const& blobInfo : msg->blobs()) - { - if (!BEAST_EXPECT( - seqIter != expectedSeqs.end())) - break; - auto const& expectedBlob = - blobInfos.at(*seqIter); - hashingBlobs.push_back(expectedBlob); - BEAST_EXPECT( - blobInfo.has_manifest() == - !!expectedBlob.manifest); - BEAST_EXPECT( - blobInfo.has_manifest() == - (*seqIter < manifestCutoff)); - - if (*seqIter < manifestCutoff) - BEAST_EXPECT( - blobInfo.manifest() == - *expectedBlob.manifest); - BEAST_EXPECT( - blobInfo.blob() == expectedBlob.blob); - BEAST_EXPECT( - blobInfo.signature() == - expectedBlob.signature); - ++seqIter; - } - BEAST_EXPECT(seqIter == expectedSeqs.end()); - } BEAST_EXPECT( messageWithHash.hash == - sha512Half(manifest, hashingBlobs, version)); + sha512Half(expectedManifest, expectedBlob.blob, expectedBlob.signature, expectedVersion)); } - ++msgIter; } - BEAST_EXPECT(msgIter == expectedInfo.end()); - }; - auto verifyBuildMessages = - [this]( - std::pair const& result, - std::size_t expectedSequence, - std::size_t expectedSize) { - BEAST_EXPECT(result.first == expectedSequence); - BEAST_EXPECT(result.second == expectedSize); - }; + else + { + std::vector hashingBlobs; + hashingBlobs.reserve(msgIter->second.size()); + + auto const msg = extractProtocolMessage2(*messageWithHash.message); + if (BEAST_EXPECT(msg)) + { + BEAST_EXPECT(msg->version() == version); + BEAST_EXPECT(msg->manifest() == manifest); + for (auto const& blobInfo : msg->blobs()) + { + if (!BEAST_EXPECT(seqIter != expectedSeqs.end())) + break; + auto const& expectedBlob = blobInfos.at(*seqIter); + hashingBlobs.push_back(expectedBlob); + BEAST_EXPECT(blobInfo.has_manifest() == !!expectedBlob.manifest); + BEAST_EXPECT(blobInfo.has_manifest() == (*seqIter < manifestCutoff)); + + if (*seqIter < manifestCutoff) + BEAST_EXPECT(blobInfo.manifest() == *expectedBlob.manifest); + BEAST_EXPECT(blobInfo.blob() == expectedBlob.blob); + BEAST_EXPECT(blobInfo.signature() == expectedBlob.signature); + ++seqIter; + } + BEAST_EXPECT(seqIter == expectedSeqs.end()); + } + BEAST_EXPECT(messageWithHash.hash == sha512Half(manifest, hashingBlobs, version)); + } + ++msgIter; + } + BEAST_EXPECT(msgIter == expectedInfo.end()); + }; + auto verifyBuildMessages = [this]( + std::pair const& result, + std::size_t expectedSequence, + std::size_t expectedSize) { + BEAST_EXPECT(result.first == expectedSequence); + BEAST_EXPECT(result.second == expectedSize); + }; std::string const manifest = "This is not a manifest"; std::uint32_t const version = 2; @@ -2567,10 +2102,7 @@ private: // This peer has a VL ahead of our "current" verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 1, 8, maxSequence, version, manifest, blobInfos, messages), - 0, - 0); + ValidatorList::buildValidatorListMessages(1, 8, maxSequence, version, manifest, blobInfos, messages), 0, 0); BEAST_EXPECT(messages.size() == 0); // Don't repeat the work if messages is populated, even though the @@ -2579,27 +2111,18 @@ private: // real code. messages.emplace_back(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 1, 3, maxSequence, version, manifest, blobInfos, messages), - 5, - 0); + ValidatorList::buildValidatorListMessages(1, 3, maxSequence, version, manifest, blobInfos, messages), 5, 0); BEAST_EXPECT(messages.size() == 1 && !messages.front().message); // Generate a version 1 message messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 1, 3, maxSequence, version, manifest, blobInfos, messages), - 5, - 1); - if (BEAST_EXPECT(messages.size() == 1) && - BEAST_EXPECT(messages.front().message)) + ValidatorList::buildValidatorListMessages(1, 3, maxSequence, version, manifest, blobInfos, messages), 5, 1); + if (BEAST_EXPECT(messages.size() == 1) && BEAST_EXPECT(messages.front().message)) { auto const& messageWithHash = messages.front(); auto const msg = extractProtocolMessage1(*messageWithHash.message); - auto const size = - messageWithHash.message->getBuffer(compression::Compressed::Off) - .size(); + auto const size = messageWithHash.message->getBuffer(compression::Compressed::Off).size(); // This size is arbitrary, but shouldn't change BEAST_EXPECT(size == 108); auto const& expected = blobInfos.at(5); @@ -2610,10 +2133,7 @@ private: BEAST_EXPECT(msg->blob() == expected.blob); BEAST_EXPECT(msg->signature() == expected.signature); } - BEAST_EXPECT( - messageWithHash.hash == - sha512Half( - *expected.manifest, expected.blob, expected.signature, 1)); + BEAST_EXPECT(messageWithHash.hash == sha512Half(*expected.manifest, expected.blob, expected.signature, 1)); } // Version 2 @@ -2623,13 +2143,7 @@ private: // This peer has a VL ahead of us. verifyBuildMessages( ValidatorList::buildValidatorListMessages( - 2, - maxSequence * 2, - maxSequence, - version, - manifest, - blobInfos, - messages), + 2, maxSequence * 2, maxSequence, version, manifest, blobInfos, messages), 0, 0); BEAST_EXPECT(messages.size() == 0); @@ -2640,8 +2154,7 @@ private: // real code. messages.emplace_back(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 3, maxSequence, version, manifest, blobInfos, messages), + ValidatorList::buildValidatorListMessages(2, 3, maxSequence, version, manifest, blobInfos, messages), maxSequence, 0); BEAST_EXPECT(messages.size() == 1 && !messages.front().message); @@ -2649,72 +2162,46 @@ private: // Generate a version 2 message. Don't send the current messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 5, maxSequence, version, manifest, blobInfos, messages), + ValidatorList::buildValidatorListMessages(2, 5, maxSequence, version, manifest, blobInfos, messages), maxSequence, 4); - verifyMessage( - version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}}); + verifyMessage(version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}}); // Test message splitting on size limits. // Set a limit that should give two messages messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 5, maxSequence, version, manifest, blobInfos, messages, 300), + ValidatorList::buildValidatorListMessages(2, 5, maxSequence, version, manifest, blobInfos, messages, 300), maxSequence, 4); - verifyMessage( - version, - manifest, - blobInfos, - messages, - {{212, {6, 7}}, {192, {10, 12}}}); + verifyMessage(version, manifest, blobInfos, messages, {{212, {6, 7}}, {192, {10, 12}}}); // Set a limit between the size of the two earlier messages so one // will split and the other won't messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 5, maxSequence, version, manifest, blobInfos, messages, 200), + ValidatorList::buildValidatorListMessages(2, 5, maxSequence, version, manifest, blobInfos, messages, 200), maxSequence, 4); - verifyMessage( - version, - manifest, - blobInfos, - messages, - {{108, {6}}, {108, {7}}, {192, {10, 12}}}); + verifyMessage(version, manifest, blobInfos, messages, {{108, {6}}, {108, {7}}, {192, {10, 12}}}); // Set a limit so that all the VLs are sent individually messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 5, maxSequence, version, manifest, blobInfos, messages, 150), + ValidatorList::buildValidatorListMessages(2, 5, maxSequence, version, manifest, blobInfos, messages, 150), maxSequence, 4); - verifyMessage( - version, - manifest, - blobInfos, - messages, - {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}}); + verifyMessage(version, manifest, blobInfos, messages, {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}}); // Set a limit smaller than some of the messages. Because single // messages send regardless, they will all still be sent messages.clear(); verifyBuildMessages( - ValidatorList::buildValidatorListMessages( - 2, 5, maxSequence, version, manifest, blobInfos, messages, 108), + ValidatorList::buildValidatorListMessages(2, 5, maxSequence, version, manifest, blobInfos, messages, 108), maxSequence, 4); - verifyMessage( - version, - manifest, - blobInfos, - messages, - {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}}); + verifyMessage(version, manifest, blobInfos, messages, {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}}); } void @@ -2756,76 +2243,48 @@ private: std::vector& publishers // out ) -> std::unique_ptr { auto result = std::make_unique( - valManifests, - pubManifests, - env.timeKeeper(), - app.config().legacy("database_path"), - env.journal); + valManifests, pubManifests, env.timeKeeper(), app.config().legacy("database_path"), env.journal); std::vector cfgPublishers; for (std::size_t i = 0; i < countTotal; ++i) { auto const publisherSecret = randomSecretKey(); - auto const publisherPublic = - derivePublicKey(KeyType::ed25519, publisherSecret); + auto const publisherPublic = derivePublicKey(KeyType::ed25519, publisherSecret); auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1); cfgPublishers.push_back(strHex(publisherPublic)); - constexpr auto revoked = - std::numeric_limits::max(); + constexpr auto revoked = std::numeric_limits::max(); auto const manifest = base64_encode(makeManifestString( publisherPublic, publisherSecret, pubSigningKeys.first, pubSigningKeys.second, i < countRevoked ? revoked : 1)); - publishers.push_back(Publisher{ - i < countRevoked, - publisherPublic, - pubSigningKeys, - manifest}); + publishers.push_back(Publisher{i < countRevoked, publisherPublic, pubSigningKeys, manifest}); } std::vector const emptyCfgKeys; - auto threshold = - listThreshold > 0 ? std::optional(listThreshold) : std::nullopt; + auto threshold = listThreshold > 0 ? std::optional(listThreshold) : std::nullopt; if (self) { - valManifests.applyManifest( - *deserializeManifest(base64_decode(self->manifest))); - BEAST_EXPECT(result->load( - self->signingPublic, - emptyCfgKeys, - cfgPublishers, - threshold)); + valManifests.applyManifest(*deserializeManifest(base64_decode(self->manifest))); + BEAST_EXPECT(result->load(self->signingPublic, emptyCfgKeys, cfgPublishers, threshold)); } else { - BEAST_EXPECT( - result->load({}, emptyCfgKeys, cfgPublishers, threshold)); + BEAST_EXPECT(result->load({}, emptyCfgKeys, cfgPublishers, threshold)); } for (std::size_t i = 0; i < countTotal; ++i) { using namespace std::chrono_literals; - publishers[i].expiry = env.timeKeeper().now() + - (i == countTotal - 1 ? 60s : 3600s); - auto const blob = makeList( - valKeys, - 1, - publishers[i].expiry.time_since_epoch().count()); + publishers[i].expiry = env.timeKeeper().now() + (i == countTotal - 1 ? 60s : 3600s); + auto const blob = makeList(valKeys, 1, publishers[i].expiry.time_since_epoch().count()); auto const sig = signList(blob, publishers[i].signingKeys); BEAST_EXPECT( - result - ->applyLists( - publishers[i].manifest, - 1, - {{blob, sig, {}}}, - siteUri) - .bestDisposition() == - (publishers[i].revoked ? ListDisposition::untrusted - : ListDisposition::accepted)); + result->applyLists(publishers[i].manifest, 1, {{blob, sig, {}}}, siteUri).bestDisposition() == + (publishers[i].revoked ? ListDisposition::untrusted : ListDisposition::accepted)); } return result; @@ -2860,8 +2319,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -2920,8 +2378,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -2986,8 +2443,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3056,8 +2512,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3124,8 +2579,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3192,8 +2646,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3258,8 +2711,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3280,8 +2732,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); BEAST_EXPECT(trustedKeys->trusted(self.masterPublic)); for (auto const& val : valKeys) @@ -3319,8 +2770,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3341,8 +2791,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); BEAST_EXPECT(trustedKeys->trusted(self.masterPublic)); for (auto const& val : valKeys) @@ -3380,8 +2829,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3401,8 +2849,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); BEAST_EXPECT(trustedKeys->trusted(self.masterPublic)); for (auto const& val : valKeys) @@ -3438,8 +2885,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3459,8 +2905,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); for (auto const& val : valKeys) { @@ -3505,8 +2950,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3573,8 +3017,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3641,8 +3084,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3701,8 +3143,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3763,8 +3204,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3826,8 +3266,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3888,8 +3327,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -3952,8 +3390,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -3991,8 +3428,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -4038,8 +3474,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; added.insert(calcNodeID(self.masterPublic)); @@ -4108,8 +3543,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f)); - BEAST_EXPECT( - trustedKeys->getTrustedMasterKeys().size() == keysTotal); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == keysTotal); hash_set added; for (auto const& val : valKeys) @@ -4164,7 +3598,7 @@ public: } }; // namespace test -BEAST_DEFINE_TESTSUITE(ValidatorList, app, ripple); +BEAST_DEFINE_TESTSUITE(ValidatorList, app, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index cd60a5ed99..3b616ad5c9 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,7 +17,7 @@ #include -namespace ripple { +namespace xrpl { namespace detail { constexpr char const* realValidatorContents() @@ -69,8 +50,7 @@ private: using namespace jtx; Env env(*this, envconfig(), nullptr, beast::severities::kDisabled); - auto trustedSites = - std::make_unique(env.app(), env.journal); + auto trustedSites = std::make_unique(env.app(), env.journal); // load should accept empty sites list std::vector emptyCfgSites; @@ -137,25 +117,18 @@ private: bool failApply = false; int serverVersion = 1; std::chrono::seconds expiresFromNow = detail::default_expires; - std::chrono::seconds effectiveOverlap = - detail::default_effective_overlap; + std::chrono::seconds effectiveOverlap = detail::default_effective_overlap; int expectedRefreshMin = 0; }; void - testFetchList( - detail::DirGuard const& good, - std::vector const& paths) + testFetchList(detail::DirGuard const& good, std::vector const& paths) { testcase << "Fetch list - " << boost::algorithm::join( - paths | - boost::adaptors::transformed( - [](FetchListConfig const& cfg) { - return cfg.path + - (cfg.ssl ? " [https] v" : " [http] v") + - std::to_string(cfg.serverVersion) + - " " + cfg.msg; - }), + paths | boost::adaptors::transformed([](FetchListConfig const& cfg) { + return cfg.path + (cfg.ssl ? " [https] v" : " [http] v") + + std::to_string(cfg.serverVersion) + " " + cfg.msg; + }), ", "); using namespace jtx; @@ -198,19 +171,11 @@ private: while (item.list.size() < listSize) item.list.push_back(TrustedPublisherServer::randomValidator()); - NetClock::time_point const expires = - env.timeKeeper().now() + cfg.expiresFromNow; - NetClock::time_point const effective2 = - expires - cfg.effectiveOverlap; - NetClock::time_point const expires2 = - effective2 + cfg.expiresFromNow; + NetClock::time_point const expires = env.timeKeeper().now() + cfg.expiresFromNow; + NetClock::time_point const effective2 = expires - cfg.effectiveOverlap; + NetClock::time_point const expires2 = effective2 + cfg.expiresFromNow; item.server = make_TrustedPublisherServer( - env.app().getIOContext(), - item.list, - expires, - {{effective2, expires2}}, - cfg.ssl, - cfg.serverVersion); + env.app().getIOContext(), item.list, expires, {{effective2, expires2}}, cfg.ssl, cfg.serverVersion); std::string pubHex = strHex(item.server->publisherPublic()); cfgPublishers.push_back(pubHex); @@ -223,8 +188,7 @@ private: } std::stringstream uri; - uri << (cfg.ssl ? "https://" : "http://") - << item.server->local_endpoint() << cfg.path; + uri << (cfg.ssl ? "https://" : "http://") << item.server->local_endpoint() << cfg.path; item.uri = uri.str(); } @@ -250,10 +214,8 @@ private: { for (auto const& val : u.list) { - BEAST_EXPECT( - trustedKeys.listed(val.masterPublic) != u.cfg.failApply); - BEAST_EXPECT( - trustedKeys.listed(val.signingPublic) != u.cfg.failApply); + BEAST_EXPECT(trustedKeys.listed(val.masterPublic) != u.cfg.failApply); + BEAST_EXPECT(trustedKeys.listed(val.signingPublic) != u.cfg.failApply); } Json::Value myStatus; @@ -261,30 +223,24 @@ private: if (vs[jss::uri].asString().find(u.uri) != std::string::npos) myStatus = vs; BEAST_EXPECTS( - myStatus[jss::last_refresh_message].asString().empty() != - u.cfg.failFetch, + myStatus[jss::last_refresh_message].asString().empty() != u.cfg.failFetch, to_string(myStatus) + "\n" + sink.messages().str()); if (!u.cfg.msg.empty()) { - BEAST_EXPECTS( - sink.messages().str().find(u.cfg.msg) != std::string::npos, - sink.messages().str()); + BEAST_EXPECTS(sink.messages().str().find(u.cfg.msg) != std::string::npos, sink.messages().str()); } if (u.cfg.expectedRefreshMin) { BEAST_EXPECTS( - myStatus[jss::refresh_interval_min].asInt() == - u.cfg.expectedRefreshMin, - to_string(myStatus)); + myStatus[jss::refresh_interval_min].asInt() == u.cfg.expectedRefreshMin, to_string(myStatus)); } if (u.cfg.failFetch) { using namespace std::chrono; - std::stringstream nextRefreshStr{ - myStatus[jss::next_refresh_time].asString()}; + std::stringstream nextRefreshStr{myStatus[jss::next_refresh_time].asString()}; system_clock::time_point nextRefresh; date::from_stream(nextRefreshStr, "%Y-%b-%d %T", nextRefresh); BEAST_EXPECT(!nextRefreshStr.fail()); @@ -299,8 +255,7 @@ private: void testFileList(std::vector> const& paths) { - testcase << "File list - " << paths[0].first - << (paths.size() > 1 ? ", " + paths[1].first : ""); + testcase << "File list - " << paths[0].first << (paths.size() > 1 ? ", " + paths[1].first : ""); using namespace jtx; @@ -345,16 +300,10 @@ private: for (auto const& vs : jv[jss::validator_sites]) if (vs[jss::uri].asString().find(u.uri) != std::string::npos) myStatus = vs; - BEAST_EXPECTS( - myStatus[jss::last_refresh_message].asString().empty() != - u.shouldFail, - to_string(myStatus)); + BEAST_EXPECTS(myStatus[jss::last_refresh_message].asString().empty() != u.shouldFail, to_string(myStatus)); if (u.shouldFail) { - BEAST_EXPECTS( - sink.messages().str().find(u.expectMsg) != - std::string::npos, - sink.messages().str()); + BEAST_EXPECTS(sink.messages().str().find(u.expectMsg) != std::string::npos, sink.messages().str()); } } } @@ -370,27 +319,19 @@ private: }; { // Create a file with a real validator list - detail::FileDirGuard good( - *this, "test_val", "vl.txt", detail::realValidatorContents()); + detail::FileDirGuard good(*this, "test_val", "vl.txt", detail::realValidatorContents()); // Create a file with arbitrary content - detail::FileDirGuard hello( - *this, "test_val", "helloworld.txt", "Hello, world!"); + detail::FileDirGuard hello(*this, "test_val", "helloworld.txt", "Hello, world!"); // Create a file with malformed Json - detail::FileDirGuard json( - *this, - "test_val", - "json.txt", - R"json({ "version": 2, "extra" : "value" })json"); + detail::FileDirGuard json(*this, "test_val", "json.txt", R"json({ "version": 2, "extra" : "value" })json"); auto const goodPath = fullPath(good); auto const helloPath = fullPath(hello); auto const jsonPath = fullPath(json); auto const missingPath = jsonPath + ".bad"; testFileList({ {goodPath, ""}, - {helloPath, - "Unable to parse JSON response from file://" + helloPath}, - {jsonPath, - "Missing fields in JSON response from file://" + jsonPath}, + {helloPath, "Unable to parse JSON response from file://" + helloPath}, + {jsonPath, "Missing fields in JSON response from file://" + jsonPath}, {missingPath, "Problem retrieving from file://" + missingPath}, }); } @@ -409,179 +350,68 @@ public: testFetchList(good, {{"/validators", "", ssl}}); testFetchList(good, {{"/validators2", "", ssl}}); // fetch multiple sites - testFetchList( - good, {{"/validators", "", ssl}, {"/validators", "", ssl}}); - testFetchList( - good, {{"/validators", "", ssl}, {"/validators2", "", ssl}}); - testFetchList( - good, {{"/validators2", "", ssl}, {"/validators", "", ssl}}); - testFetchList( - good, {{"/validators2", "", ssl}, {"/validators2", "", ssl}}); + testFetchList(good, {{"/validators", "", ssl}, {"/validators", "", ssl}}); + testFetchList(good, {{"/validators", "", ssl}, {"/validators2", "", ssl}}); + testFetchList(good, {{"/validators2", "", ssl}, {"/validators", "", ssl}}); + testFetchList(good, {{"/validators2", "", ssl}, {"/validators2", "", ssl}}); // fetch single site with single redirects testFetchList(good, {{"/redirect_once/301", "", ssl}}); testFetchList(good, {{"/redirect_once/302", "", ssl}}); testFetchList(good, {{"/redirect_once/307", "", ssl}}); testFetchList(good, {{"/redirect_once/308", "", ssl}}); // one redirect, one not - testFetchList( - good, - {{"/validators", "", ssl}, {"/redirect_once/302", "", ssl}}); - testFetchList( - good, - {{"/validators2", "", ssl}, {"/redirect_once/302", "", ssl}}); + testFetchList(good, {{"/validators", "", ssl}, {"/redirect_once/302", "", ssl}}); + testFetchList(good, {{"/validators2", "", ssl}, {"/redirect_once/302", "", ssl}}); // UNLs with a "gap" between validUntil of one and validFrom of the // next testFetchList( - good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - detail::default_expires, - std::chrono::seconds{-90}}}); - // fetch single site with undending redirect (fails to load) - testFetchList( - good, - {{"/redirect_forever/301", - "Exceeded max redirects", - ssl, - true, - true}}); + good, {{"/validators2", "", ssl, false, false, 1, detail::default_expires, std::chrono::seconds{-90}}}); + // fetch single site with unending redirect (fails to load) + testFetchList(good, {{"/redirect_forever/301", "Exceeded max redirects", ssl, true, true}}); // two that redirect forever testFetchList( good, - {{"/redirect_forever/307", - "Exceeded max redirects", - ssl, - true, - true}, - {"/redirect_forever/308", - "Exceeded max redirects", - ssl, - true, - true}}); - // one undending redirect, one not + {{"/redirect_forever/307", "Exceeded max redirects", ssl, true, true}, + {"/redirect_forever/308", "Exceeded max redirects", ssl, true, true}}); + // one unending redirect, one not + testFetchList( + good, {{"/validators", "", ssl}, {"/redirect_forever/302", "Exceeded max redirects", ssl, true, true}}); + // one unending redirect, one not testFetchList( good, - {{"/validators", "", ssl}, - {"/redirect_forever/302", - "Exceeded max redirects", - ssl, - true, - true}}); - // one undending redirect, one not - testFetchList( - good, - {{"/validators2", "", ssl}, - {"/redirect_forever/302", - "Exceeded max redirects", - ssl, - true, - true}}); + {{"/validators2", "", ssl}, {"/redirect_forever/302", "Exceeded max redirects", ssl, true, true}}); // invalid redir Location + testFetchList(good, {{"/redirect_to/ftp://invalid-url/302", "Invalid redirect location", ssl, true, true}}); testFetchList( - good, - {{"/redirect_to/ftp://invalid-url/302", - "Invalid redirect location", - ssl, - true, - true}}); - testFetchList( - good, - {{"/redirect_to/file://invalid-url/302", - "Invalid redirect location", - ssl, - true, - true}}); + good, {{"/redirect_to/file://invalid-url/302", "Invalid redirect location", ssl, true, true}}); // invalid json - testFetchList( - good, - {{"/validators/bad", - "Unable to parse JSON response", - ssl, - true, - true}}); - testFetchList( - good, - {{"/validators2/bad", - "Unable to parse JSON response", - ssl, - true, - true}}); + testFetchList(good, {{"/validators/bad", "Unable to parse JSON response", ssl, true, true}}); + testFetchList(good, {{"/validators2/bad", "Unable to parse JSON response", ssl, true, true}}); // error status returned - testFetchList( - good, - {{"/bad-resource", "returned bad status", ssl, true, true}}); + testFetchList(good, {{"/bad-resource", "returned bad status", ssl, true, true}}); // location field missing - testFetchList( - good, - {{"/redirect_nolo/308", - "returned a redirect with no Location", - ssl, - true, - true}}); + testFetchList(good, {{"/redirect_nolo/308", "returned a redirect with no Location", ssl, true, true}}); // json fields missing - testFetchList( - good, - {{"/validators/missing", - "Missing fields in JSON response", - ssl, - true, - true}}); - testFetchList( - good, - {{"/validators2/missing", - "Missing fields in JSON response", - ssl, - true, - true}}); + testFetchList(good, {{"/validators/missing", "Missing fields in JSON response", ssl, true, true}}); + testFetchList(good, {{"/validators2/missing", "Missing fields in JSON response", ssl, true, true}}); // timeout - testFetchList( - good, {{"/sleep/13", "took too long", ssl, true, true}}); + testFetchList(good, {{"/sleep/13", "took too long", ssl, true, true}}); // bad manifest format using known versions // * Retrieves a v1 formatted list claiming version 2 - testFetchList( - good, {{"/validators", "Missing fields", ssl, true, true, 2}}); + testFetchList(good, {{"/validators", "Missing fields", ssl, true, true, 2}}); // * Retrieves a v2 formatted list claiming version 1 - testFetchList( - good, {{"/validators2", "Missing fields", ssl, true, true, 0}}); + testFetchList(good, {{"/validators2", "Missing fields", ssl, true, true, 0}}); // bad manifest version // Because versions other than 1 are treated as v2, the v1 // list won't have the blobs_v2 fields, and thus will claim to have // missing fields - testFetchList( - good, {{"/validators", "Missing fields", ssl, true, true, 4}}); - testFetchList( - good, - {{"/validators2", - "1 unsupported version", - ssl, - false, - true, - 4}}); + testFetchList(good, {{"/validators", "Missing fields", ssl, true, true, 4}}); + testFetchList(good, {{"/validators2", "1 unsupported version", ssl, false, true, 4}}); using namespace std::chrono_literals; // get expired validator list + testFetchList(good, {{"/validators", "Applied 1 expired validator list(s)", ssl, false, false, 1, 0s}}); testFetchList( - good, - {{"/validators", - "Applied 1 expired validator list(s)", - ssl, - false, - false, - 1, - 0s}}); - testFetchList( - good, - {{"/validators2", - "Applied 1 expired validator list(s)", - ssl, - false, - false, - 1, - 0s, - -1s}}); + good, {{"/validators2", "Applied 1 expired validator list(s)", ssl, false, false, 1, 0s, -1s}}); // force an out-of-range validUntil value testFetchList( good, @@ -591,33 +421,19 @@ public: false, true, 1, - std::chrono::seconds{Json::Value::maxInt + 1}}}); + std::chrono::seconds{Json::Value::minInt}}}); // force an out-of-range validUntil value on the future list // The first list is accepted. The second fails. The parser // returns the "best" result, so this looks like a success. testFetchList( good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - std::chrono::seconds{Json::Value::maxInt - 300}, - 299s}}); + {{"/validators2", "", ssl, false, false, 1, std::chrono::seconds{Json::Value::maxInt - 300}, 299s}}); // force an out-of-range validFrom value // The first list is accepted. The second fails. The parser // returns the "best" result, so this looks like a success. testFetchList( good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - std::chrono::seconds{Json::Value::maxInt - 300}, - 301s}}); + {{"/validators2", "", ssl, false, false, 1, std::chrono::seconds{Json::Value::maxInt - 300}, 301s}}); // force an out-of-range validUntil value on _both_ lists testFetchList( good, @@ -627,7 +443,7 @@ public: false, true, 1, - std::chrono::seconds{Json::Value::maxInt + 1}, + std::chrono::seconds{Json::Value::minInt}, std::chrono::seconds{Json::Value::maxInt - 6000}}}); // verify refresh intervals are properly clamped testFetchList( @@ -707,7 +523,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(ValidatorSite, app, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(ValidatorSite, app, xrpl, 2); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index bdebb70d09..5d31c674c0 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -1,26 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include +#include +#include #include #include @@ -38,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -46,15 +28,14 @@ #include -namespace ripple { +namespace xrpl { class Vault_test : public beast::unit_test::suite { - using PrettyAsset = ripple::test::jtx::PrettyAsset; - using PrettyAmount = ripple::test::jtx::PrettyAmount; + using PrettyAsset = xrpl::test::jtx::PrettyAsset; + using PrettyAmount = xrpl::test::jtx::PrettyAmount; - static auto constexpr negativeAmount = - [](PrettyAsset const& asset) -> PrettyAmount { + static auto constexpr negativeAmount = [](PrettyAsset const& asset) -> PrettyAmount { return {STAmount{asset.raw(), 1ul, 0, true, STAmount::unchecked{}}, ""}; }; @@ -69,10 +50,7 @@ class Vault_test : public beast::unit_test::suite Account dave{"dave"}; auto const testSequence = [&, this]( - std::string const& prefix, - Env& env, - Vault& vault, - PrettyAsset const& asset) { + std::string const& prefix, Env& env, Vault& vault, PrettyAsset const& asset) { auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); tx[sfData] = "AFEED00E"; tx[sfAssetsMaximum] = asset(100).number(); @@ -82,26 +60,20 @@ class Vault_test : public beast::unit_test::suite std::uint64_t const scale = asset.raw().holds() ? 1 : 1e6; auto const [share, vaultAccount] = - [&env, - keylet = keylet, - asset, - this]() -> std::tuple { + [&env, keylet = keylet, asset, this]() -> std::tuple { auto const vault = env.le(keylet); BEAST_EXPECT(vault != nullptr); - if (asset.raw().holds() && !asset.raw().native()) + if (!asset.integral()) BEAST_EXPECT(vault->at(sfScale) == 6); else BEAST_EXPECT(vault->at(sfScale) == 0); - auto const shares = - env.le(keylet::mptIssuance(vault->at(sfShareMPTID))); + auto const shares = env.le(keylet::mptIssuance(vault->at(sfShareMPTID))); BEAST_EXPECT(shares != nullptr); - if (asset.raw().holds() && !asset.raw().native()) + if (!asset.integral()) BEAST_EXPECT(shares->at(sfAssetScale) == 6); else BEAST_EXPECT(shares->at(sfAssetScale) == 0); - return { - MPTIssue(vault->at(sfShareMPTID)), - Account("vault", vault->at(sfAccount))}; + return {MPTIssue(vault->at(sfShareMPTID)), Account("vault", vault->at(sfAccount))}; }(); auto const shares = share.raw().get(); env.memoize(vaultAccount); @@ -115,36 +87,25 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " fail to deposit more than assets held"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(10000)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(10000)}); env(tx, ter(tecINSUFFICIENT_FUNDS)); env.close(); } { testcase(prefix + " deposit non-zero amount"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(50 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(50 * scale)); } { testcase(prefix + " deposit non-zero amount again"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(100 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(100 * scale)); } { @@ -163,8 +124,7 @@ class Vault_test : public beast::unit_test::suite } { - testcase( - prefix + " fail to set maximum lower than current amount"); + testcase(prefix + " fail to set maximum lower than current amount"); auto tx = vault.set({.owner = owner, .id = keylet.key}); tx[sfAssetsMaximum] = asset(50).number(); env(tx, ter(tecLIMIT_EXCEEDED)); @@ -205,10 +165,7 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " fail to deposit more than maximum"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecLIMIT_EXCEEDED)); env.close(); } @@ -223,50 +180,36 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " fail to withdraw more than assets held"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx, ter(tecINSUFFICIENT_FUNDS)); env.close(); } { testcase(prefix + " deposit some more"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(200 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(200 * scale)); } { testcase(prefix + " clawback some"); - auto code = - asset.raw().native() ? ter(temMALFORMED) : ter(tesSUCCESS); - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(10)}); + auto code = asset.raw().native() ? ter(temMALFORMED) : ter(tesSUCCESS); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(10)}); env(tx, code); env.close(); if (!asset.raw().native()) { - BEAST_EXPECT( - env.balance(depositor, shares) == share(190 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(190 * scale)); } } { testcase(prefix + " clawback all"); - auto code = asset.raw().native() ? ter(tecNO_PERMISSION) - : ter(tesSUCCESS); - auto tx = vault.clawback( - {.issuer = issuer, .id = keylet.key, .holder = depositor}); + auto code = asset.raw().native() ? ter(tecNO_PERMISSION) : ter(tesSUCCESS); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor}); env(tx, code); env.close(); if (!asset.raw().native()) @@ -275,19 +218,13 @@ class Vault_test : public beast::unit_test::suite { auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(10)}); + {.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(10)}); env(tx, ter{tecPRECISION_LOSS}); env.close(); } { - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecPRECISION_LOSS}); env.close(); } @@ -297,72 +234,46 @@ class Vault_test : public beast::unit_test::suite if (!asset.raw().native()) { testcase(prefix + " deposit again"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(200)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(200)}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(200 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(200 * scale)); } else { testcase(prefix + " deposit/withdrawal same or less than fee"); auto const amount = env.current()->fees().base; - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = amount}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = amount}); env(tx); env.close(); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = amount}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = amount}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = amount}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = amount}); env(tx); env.close(); // Withdraw to 3rd party - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = amount}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = amount}); tx[sfDestination] = charlie.human(); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = amount - 1}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = amount - 1}); env(tx); env.close(); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = amount - 1}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = amount - 1}); env(tx); env.close(); } { - testcase( - prefix + " fail to withdraw to 3rd party lsfDepositAuth"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + testcase(prefix + " fail to withdraw to 3rd party lsfDepositAuth"); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); tx[sfDestination] = alice.human(); env(tx, ter{tecNO_PERMISSION}); env.close(); @@ -370,10 +281,7 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " fail to withdraw to zero destination"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); tx[sfDestination] = "0"; env(tx, ter(temMALFORMED)); env.close(); @@ -381,26 +289,16 @@ class Vault_test : public beast::unit_test::suite if (!asset.raw().native()) { - testcase( - prefix + " fail to withdraw to 3rd party no authorization"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + testcase(prefix + " fail to withdraw to 3rd party no authorization"); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); tx[sfDestination] = erin.human(); - env(tx, - ter{asset.raw().holds() ? tecNO_LINE : tecNO_AUTH}); + env(tx, ter{asset.raw().holds() ? tecNO_LINE : tecNO_AUTH}); env.close(); } { - testcase( - prefix + - " fail to withdraw to 3rd party lsfRequireDestTag"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + testcase(prefix + " fail to withdraw to 3rd party lsfRequireDestTag"); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); tx[sfDestination] = dave.human(); env(tx, ter{tecDST_TAG_NEEDED}); env.close(); @@ -408,10 +306,7 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " withdraw to 3rd party lsfRequireDestTag"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); tx[sfDestination] = dave.human(); tx[sfDestinationTag] = "0"; env(tx); @@ -420,24 +315,21 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " deposit again"); - auto tx = vault.deposit( - {.depositor = dave, .id = keylet.key, .amount = asset(50)}); + auto tx = vault.deposit({.depositor = dave, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); } { testcase(prefix + " fail to withdraw lsfRequireDestTag"); - auto tx = vault.withdraw( - {.depositor = dave, .id = keylet.key, .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = dave, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecDST_TAG_NEEDED}); env.close(); } { testcase(prefix + " withdraw with tag"); - auto tx = vault.withdraw( - {.depositor = dave, .id = keylet.key, .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = dave, .id = keylet.key, .amount = asset(50)}); tx[sfDestinationTag] = "0"; env(tx); env.close(); @@ -445,46 +337,32 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " withdraw to authorized 3rd party"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); tx[sfDestination] = charlie.human(); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(100 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(100 * scale)); } { testcase(prefix + " withdraw to issuer"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); tx[sfDestination] = issuer.human(); env(tx); env.close(); - BEAST_EXPECT( - env.balance(depositor, shares) == share(50 * scale)); + BEAST_EXPECT(env.balance(depositor, shares) == share(50 * scale)); } if (!asset.raw().native()) { testcase(prefix + " issuer deposits"); - auto tx = vault.deposit( - {.depositor = issuer, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = issuer, .id = keylet.key, .amount = asset(10)}); env(tx); env.close(); BEAST_EXPECT(env.balance(issuer, shares) == share(10 * scale)); testcase(prefix + " issuer withdraws"); - tx = vault.withdraw( - {.depositor = issuer, - .id = keylet.key, - .amount = share(10 * scale)}); + tx = vault.withdraw({.depositor = issuer, .id = keylet.key, .amount = share(10 * scale)}); env(tx); env.close(); BEAST_EXPECT(env.balance(issuer, shares) == share(0 * scale)); @@ -492,36 +370,27 @@ class Vault_test : public beast::unit_test::suite { testcase(prefix + " withdraw remaining assets"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); BEAST_EXPECT(env.balance(depositor, shares) == share(0)); if (!asset.raw().native()) { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx, ter{tecPRECISION_LOSS}); env.close(); } { - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = share(10)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = share(10)}); env(tx, ter{tecINSUFFICIENT_FUNDS}); env.close(); } } - if (!asset.raw().native() && asset.raw().holds()) + if (!asset.integral()) { testcase(prefix + " temporary authorization for 3rd party"); env(trust(erin, asset(1000))); @@ -529,8 +398,7 @@ class Vault_test : public beast::unit_test::suite env(pay(issuer, erin, asset(10))); // Erin deposits all in vault, then sends shares to depositor - auto tx = vault.deposit( - {.depositor = erin, .id = keylet.key, .amount = asset(10)}); + auto tx = vault.deposit({.depositor = erin, .id = keylet.key, .amount = asset(10)}); env(tx); env.close(); { @@ -541,10 +409,7 @@ class Vault_test : public beast::unit_test::suite env.close(); // depositor will gain MPToken for shares again - env(vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1)})); + env(vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1)})); env.close(); env(tx); @@ -553,10 +418,7 @@ class Vault_test : public beast::unit_test::suite testcase(prefix + " withdraw to authorized 3rd party"); // Depositor withdraws assets, destined to Erin - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(10)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(10)}); tx[sfDestination] = erin.human(); env(tx); env.close(); @@ -574,10 +436,7 @@ class Vault_test : public beast::unit_test::suite env.close(); // Depositor withdraws remaining single asset - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1)}); env(tx); env.close(); } @@ -598,9 +457,7 @@ class Vault_test : public beast::unit_test::suite } }; - auto testCases = [&, this]( - std::string prefix, - std::function setup) { + auto testCases = [&, this](std::string prefix, std::function setup) { Env env{*this, testable_amendments() | featureSingleAssetVault}; Vault vault{env}; @@ -617,9 +474,7 @@ class Vault_test : public beast::unit_test::suite testSequence(prefix, env, vault, asset); }; - testCases("XRP", [&](Env& env) -> PrettyAsset { - return {xrpIssue(), 1'000'000}; - }); + testCases("XRP", [&](Env& env) -> PrettyAsset { return {xrpIssue(), 1'000'000}; }); testCases("IOU", [&](Env& env) -> Asset { PrettyAsset asset = issuer["IOU"]; @@ -638,8 +493,7 @@ class Vault_test : public beast::unit_test::suite testCases("MPT", [&](Env& env) -> Asset { MPTTester mptt{env, issuer, mptInitNoFund}; - mptt.create( - {.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); PrettyAsset asset = mptt.issuanceID(); mptt.authorize({.account = depositor}); mptt.authorize({.account = charlie}); @@ -657,92 +511,96 @@ class Vault_test : public beast::unit_test::suite struct CaseArgs { - FeatureBitset features = - testable_amendments() | featureSingleAssetVault; + FeatureBitset features = testable_amendments() | featureSingleAssetVault; }; - auto testCase = [&, this]( - std::function test, - CaseArgs args = {}) { - Env env{*this, args.features}; - Account issuer{"issuer"}; - Account owner{"owner"}; - Vault vault{env}; - env.fund(XRP(1000), issuer, owner); - env.close(); + auto testCase = + [&, this]( + std::function test, + CaseArgs args = {}) { + Env env{*this, args.features}; + Account issuer{"issuer"}; + Account owner{"owner"}; + Vault vault{env}; + env.fund(XRP(1000), issuer, owner); + env.close(); - env(fset(issuer, asfAllowTrustLineClawback)); - env(fset(issuer, asfRequireAuth)); - env.close(); + env(fset(issuer, asfAllowTrustLineClawback)); + env(fset(issuer, asfRequireAuth)); + env.close(); - PrettyAsset asset = issuer["IOU"]; - env(trust(owner, asset(1000))); - env(trust(issuer, asset(0), owner, tfSetfAuth)); - env(pay(issuer, owner, asset(1000))); - env.close(); + PrettyAsset asset = issuer["IOU"]; + env(trust(owner, asset(1000))); + env(trust(issuer, asset(0), owner, tfSetfAuth)); + env(pay(issuer, owner, asset(1000))); + env.close(); - test(env, issuer, owner, asset, vault); - }; + test(env, issuer, owner, asset, vault); + }; - testCase( - [&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { + auto testDisabled = [&](TER resultAfterCreate = temDISABLED) { + return [&, resultAfterCreate]( + Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { testcase("disabled single asset vault"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx, ter{temDISABLED}); { auto tx = vault.set({.owner = owner, .id = keylet.key}); - env(tx, ter{temDISABLED}); + env(tx, data("test"), ter{resultAfterCreate}); } { - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); - env(tx, ter{temDISABLED}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(10)}); + env(tx, ter{resultAfterCreate}); } { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); - env(tx, ter{temDISABLED}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); + env(tx, ter{resultAfterCreate}); } { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(10)}); - env(tx, ter{temDISABLED}); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(10)}); + env(tx, ter{resultAfterCreate}); } { auto tx = vault.del({.owner = owner, .id = keylet.key}); + env(tx, ter{resultAfterCreate}); + } + }; + }; + + testCase(testDisabled(), {.features = testable_amendments() - featureSingleAssetVault}); + + testCase(testDisabled(tecNO_ENTRY), {.features = testable_amendments() - featureMPTokensV1}); + + testCase( + [&](Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { + testcase("disabled permissioned domains"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + env(tx); + + tx[sfFlags] = tx[sfFlags].asUInt() | tfVaultPrivate; + tx[sfDomainID] = to_string(base_uint<256>(42ul)); + env(tx, ter{temDISABLED}); + + { + auto tx = vault.set({.owner = owner, .id = keylet.key}); + env(tx, data("Test")); + + tx[sfDomainID] = to_string(base_uint<256>(13ul)); env(tx, ter{temDISABLED}); } }, - {.features = testable_amendments() - featureSingleAssetVault}); + {.features = testable_amendments() - featurePermissionedDomains}); - testCase([&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid flags"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -756,29 +614,19 @@ class Vault_test : public beast::unit_test::suite } { - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[sfFlags] = tfClearDeepFreeze; env(tx, ter{temINVALID_FLAG}); } { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[sfFlags] = tfClearDeepFreeze; env(tx, ter{temINVALID_FLAG}); } { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(10)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(10)}); tx[sfFlags] = tfClearDeepFreeze; env(tx, ter{temINVALID_FLAG}); } @@ -790,11 +638,7 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid fee"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -808,29 +652,19 @@ class Vault_test : public beast::unit_test::suite } { - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[jss::Fee] = "-1"; env(tx, ter{temBAD_FEE}); } { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[jss::Fee] = "-1"; env(tx, ter{temBAD_FEE}); } { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(10)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(10)}); tx[jss::Fee] = "-1"; env(tx, ter{temBAD_FEE}); } @@ -843,15 +677,10 @@ class Vault_test : public beast::unit_test::suite }); testCase( - [&](Env& env, - Account const&, - Account const& owner, - Asset const&, - Vault& vault) { + [&](Env& env, Account const&, Account const& owner, Asset const&, Vault& vault) { testcase("disabled permissioned domain"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpIssue()}); tx[sfDomainID] = to_string(base_uint<256>(42ul)); env(tx, ter{temDISABLED}); @@ -867,18 +696,12 @@ class Vault_test : public beast::unit_test::suite env(tx, ter{temDISABLED}); } }, - {.features = (testable_amendments() | featureSingleAssetVault) - - featurePermissionedDomains}); + {.features = (testable_amendments() | featureSingleAssetVault) - featurePermissionedDomains}); - testCase([&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { testcase("use zero vault"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = xrpIssue()}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpIssue()}); { auto tx = vault.set({ @@ -889,27 +712,17 @@ class Vault_test : public beast::unit_test::suite } { - auto tx = vault.deposit( - {.depositor = owner, - .id = beast::zero, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = owner, .id = beast::zero, .amount = asset(10)}); env(tx, ter(temMALFORMED)); } { - auto tx = vault.withdraw( - {.depositor = owner, - .id = beast::zero, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = owner, .id = beast::zero, .amount = asset(10)}); env(tx, ter{temMALFORMED}); } { - auto tx = vault.clawback( - {.issuer = issuer, - .id = beast::zero, - .holder = owner, - .amount = asset(10)}); + auto tx = vault.clawback({.issuer = issuer, .id = beast::zero, .holder = owner, .amount = asset(10)}); env(tx, ter{temMALFORMED}); } @@ -922,69 +735,36 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { - testcase("clawback from self"); - - auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); - - { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = issuer, - .amount = asset(10)}); - env(tx, ter{temMALFORMED}); - } - }); - - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("withdraw to bad destination"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[jss::Destination] = "0"; env(tx, ter{temMALFORMED}); } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("create with Scale"); { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); tx[sfScale] = 255; env(tx, ter(temMALFORMED)); } { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); tx[sfScale] = 19; env(tx, ter(temMALFORMED)); } // accepted range from 0 to 18 { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); tx[sfScale] = 18; env(tx); env.close(); @@ -994,8 +774,7 @@ class Vault_test : public beast::unit_test::suite } { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); tx[sfScale] = 0; env(tx); env.close(); @@ -1005,8 +784,7 @@ class Vault_test : public beast::unit_test::suite } { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); auto const sleVault = env.le(keylet); @@ -1015,11 +793,7 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("create or set invalid data"); auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1051,11 +825,7 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("set nothing updated"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1066,11 +836,7 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("create with invalid metadata"); auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1090,11 +856,7 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("set negative maximum"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1106,35 +868,23 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid deposit amount"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); { - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = negativeAmount(asset)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = negativeAmount(asset)}); env(tx, ter(temBAD_AMOUNT)); } { - auto tx = vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(0)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(0)}); env(tx, ter(temBAD_AMOUNT)); } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid set immutable flag"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1146,63 +896,42 @@ class Vault_test : public beast::unit_test::suite } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid withdraw amount"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = negativeAmount(asset)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = negativeAmount(asset)}); env(tx, ter(temBAD_AMOUNT)); } { - auto tx = vault.withdraw( - {.depositor = owner, .id = keylet.key, .amount = asset(0)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(0)}); env(tx, ter(temBAD_AMOUNT)); } }); - testCase([&](Env& env, - Account const& issuer, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const& issuer, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid clawback"); auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + // Preclaim only checks for native assets. + if (asset.native()) { - auto tx = vault.clawback( - {.issuer = owner, - .id = keylet.key, - .holder = issuer, - .amount = asset(50)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(50)}); env(tx, ter(temMALFORMED)); } { auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = negativeAmount(asset)}); + {.issuer = issuer, .id = keylet.key, .holder = owner, .amount = negativeAmount(asset)}); env(tx, ter(temBAD_AMOUNT)); } }); - testCase([&](Env& env, - Account const&, - Account const& owner, - Asset const& asset, - Vault& vault) { + testCase([&](Env& env, Account const&, Account const& owner, Asset const& asset, Vault& vault) { testcase("invalid create"); auto [tx1, keylet] = vault.create({.owner = owner, .asset = asset}); @@ -1280,10 +1009,7 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const& asset, Vault& vault) { testcase("nothing to deposit to"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet::skip().key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet::skip().key, .amount = asset(10)}); env(tx, ter(tecNO_ENTRY)); }); @@ -1295,10 +1021,7 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const& asset, Vault& vault) { testcase("nothing to withdraw from"); - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet::skip().key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet::skip().key, .amount = asset(10)}); env(tx, ter(tecNO_ENTRY)); }); @@ -1348,7 +1071,7 @@ class Vault_test : public beast::unit_test::suite Vault& vault) { auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); testcase("insufficient fee"); - env(tx, fee(env.current()->fees().base), ter(telINSUF_FEE_P)); + env(tx, fee(env.current()->fees().base - 1), ter(telINSUF_FEE_P)); }); testCase([this]( @@ -1415,10 +1138,7 @@ class Vault_test : public beast::unit_test::suite { { testcase("IOU fail because MPT is disabled"); - Env env{ - *this, - (testable_amendments() - featureMPTokensV1) | - featureSingleAssetVault}; + Env env{*this, (testable_amendments() - featureMPTokensV1) | featureSingleAssetVault}; Account issuer{"issuer"}; Account owner{"owner"}; env.fund(XRP(1000), issuer, owner); @@ -1426,8 +1146,7 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; Asset asset = issuer["IOU"].asset(); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx, ter(temDISABLED)); env.close(); @@ -1445,8 +1164,7 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; Asset asset = issuer["IOU"].asset(); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx, ter(tecFROZEN)); env.close(); @@ -1464,8 +1182,7 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; Asset asset = issuer["IOU"].asset(); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx, ter(terNO_RIPPLE)); env.close(); } @@ -1481,8 +1198,7 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; Asset asset = issuer["IOU"].asset(); { - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx, ter(terNO_ACCOUNT)); env.close(); } @@ -1497,9 +1213,8 @@ class Vault_test : public beast::unit_test::suite Account const carol("carol"); IOU const USD = gw["USD"]; - auto const [asset1, asset2] = - std::pair(XRP(10000), USD(10000)); - auto tofund = [&](STAmount const& a) -> STAmount { + auto const [asset1, asset2] = std::pair(XRP(10000), USD(10000)); + auto toFund = [&](STAmount const& a) -> STAmount { if (a.native()) { auto const defXRP = XRP(30000); @@ -1512,8 +1227,8 @@ class Vault_test : public beast::unit_test::suite return defIOU; return a + STAmount{a.issue(), 1000}; }; - auto const toFund1 = tofund(asset1); - auto const toFund2 = tofund(asset2); + auto const toFund1 = toFund(asset1); + auto const toFund2 = toFund(asset2); BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); if (!asset1.native() && !asset2.native()) @@ -1523,15 +1238,13 @@ class Vault_test : public beast::unit_test::suite else if (asset2.native()) fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); - AMM ammAlice( - env, alice, asset1, asset2, CreateArg{.log = false, .tfee = 0}); + AMM ammAlice(env, alice, asset1, asset2, CreateArg{.log = false, .tfee = 0}); Account const owner{"owner"}; env.fund(XRP(1000000), owner); Vault vault{env}; - auto [tx, k] = - vault.create({.owner = owner, .asset = ammAlice.lptIssue()}); + auto [tx, k] = vault.create({.owner = owner, .asset = ammAlice.lptIssue()}); env(tx, ter{tecWRONG_ASSET}); env.close(); } @@ -1630,14 +1343,10 @@ class Vault_test : public beast::unit_test::suite { testcase("nontransferable deposits"); - auto tx1 = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(40)}); + auto tx1 = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(40)}); env(tx1); - auto tx2 = vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(60)}); + auto tx2 = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(60)}); env(tx2); env.close(); } @@ -1646,17 +1355,11 @@ class Vault_test : public beast::unit_test::suite [&env, key = keylet.key, this]() -> AccountID { auto jvVault = env.rpc("vault_info", strHex(key)); - BEAST_EXPECT( - jvVault[jss::result][jss::vault][sfAssetsTotal] == "100"); - BEAST_EXPECT( - jvVault[jss::result][jss::vault][jss::shares] - [sfOutstandingAmount] == "100000000"); + BEAST_EXPECT(jvVault[jss::result][jss::vault][sfAssetsTotal] == "100"); + BEAST_EXPECT(jvVault[jss::result][jss::vault][jss::shares][sfOutstandingAmount] == "100000000"); // Vault pseudo-account - return parseBase58( - jvVault[jss::result][jss::vault][jss::Account] - .asString()) - .value(); + return parseBase58(jvVault[jss::result][jss::vault][jss::Account].asString()).value(); }(); auto const MptID = makeMptID(1, vaultAccount); @@ -1670,14 +1373,10 @@ class Vault_test : public beast::unit_test::suite { testcase("nontransferable shares can be used to withdraw"); - auto tx1 = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(20)}); + auto tx1 = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(20)}); env(tx1); - auto tx2 = vault.withdraw( - {.depositor = owner, .id = keylet.key, .amount = asset(30)}); + auto tx2 = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(30)}); env(tx2); env.close(); } @@ -1685,23 +1384,16 @@ class Vault_test : public beast::unit_test::suite { testcase("nontransferable shares balance check"); auto jvVault = env.rpc("vault_info", strHex(keylet.key)); - BEAST_EXPECT( - jvVault[jss::result][jss::vault][sfAssetsTotal] == "50"); - BEAST_EXPECT( - jvVault[jss::result][jss::vault][jss::shares] - [sfOutstandingAmount] == "50000000"); + BEAST_EXPECT(jvVault[jss::result][jss::vault][sfAssetsTotal] == "50"); + BEAST_EXPECT(jvVault[jss::result][jss::vault][jss::shares][sfOutstandingAmount] == "50000000"); } { testcase("nontransferable shares withdraw rest"); - auto tx1 = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(20)}); + auto tx1 = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(20)}); env(tx1); - auto tx2 = vault.withdraw( - {.depositor = owner, .id = keylet.key, .amount = asset(30)}); + auto tx2 = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(30)}); env(tx2); env.close(); } @@ -1747,9 +1439,9 @@ class Vault_test : public beast::unit_test::suite MPTTester mptt{env, issuer, mptInitNoFund}; auto const none = LedgerSpecificFlags(0); mptt.create( - {.flags = tfMPTCanTransfer | tfMPTCanLock | - (args.enableClawback ? tfMPTCanClawback : none) | - (args.requireAuth ? tfMPTRequireAuth : none)}); + {.flags = tfMPTCanTransfer | tfMPTCanLock | (args.enableClawback ? tfMPTCanClawback : none) | + (args.requireAuth ? tfMPTRequireAuth : none), + .mutableFlags = tmfMPTCanMutateCanTransfer}); PrettyAsset asset = mptt.issuanceID(); mptt.authorize({.account = owner}); mptt.authorize({.account = depositor}); @@ -1774,11 +1466,8 @@ class Vault_test : public beast::unit_test::suite Vault& vault, MPTTester& mptt) { testcase("MPT nothing to clawback from"); - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet::skip().key, - .holder = depositor, - .amount = asset(10)}); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet::skip().key, .holder = depositor, .amount = asset(10)}); env(tx, ter(tecNO_ENTRY)); }); @@ -1812,10 +1501,7 @@ class Vault_test : public beast::unit_test::suite mptt.set({.account = issuer, .flags = tfMPTLock}); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter{tecLOCKED}); env.close(); @@ -1836,10 +1522,7 @@ class Vault_test : public beast::unit_test::suite auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx); env.close(); @@ -1856,21 +1539,14 @@ class Vault_test : public beast::unit_test::suite mptt.set({.account = issuer, .flags = tfMPTLock}); env.close(); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecLOCKED)); tx[sfDestination] = issuer.human(); env(tx, ter(tecLOCKED)); // Clawback is still permitted, even with global lock - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx); env.close(); @@ -1897,16 +1573,25 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx); env.close(); { - auto tx = vault.clawback( - {.issuer = owner, .id = keylet.key, .holder = depositor}); + auto tx = vault.clawback({ + .issuer = depositor, + .id = keylet.key, + .holder = depositor, + }); + env(tx, ter(tecNO_PERMISSION)); + } + + { + auto tx = vault.clawback({ + .issuer = owner, + .id = keylet.key, + .holder = depositor, + }); env(tx, ter(tecNO_PERMISSION)); } }); @@ -1922,33 +1607,24 @@ class Vault_test : public beast::unit_test::suite MPTTester& mptt) { testcase("MPT depositor without MPToken, auth required"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx); env.close(); { // Remove depositor MPToken and it will not be re-created - mptt.authorize( - {.account = depositor, .flags = tfMPTUnauthorize}); + mptt.authorize({.account = depositor, .flags = tfMPTUnauthorize}); env.close(); - auto const mptoken = - keylet::mptoken(mptt.issuanceID(), depositor); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), depositor); auto const sleMPT1 = env.le(mptoken); BEAST_EXPECT(sleMPT1 == nullptr); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter{tecNO_AUTH}); env.close(); @@ -1962,10 +1638,7 @@ class Vault_test : public beast::unit_test::suite env.fund(XRP(1000), charlie); env.close(); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); tx[sfDestination] = charlie.human(); env(tx, ter(tecNO_AUTH)); } @@ -1983,35 +1656,27 @@ class Vault_test : public beast::unit_test::suite MPTTester& mptt) { testcase("MPT depositor without MPToken, no auth required"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); auto v = env.le(keylet); BEAST_EXPECT(v); tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); // all assets held by depositor + {.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); // all assets held by depositor env(tx); env.close(); { // Remove depositor's MPToken and it will be re-created - mptt.authorize( - {.account = depositor, .flags = tfMPTUnauthorize}); + mptt.authorize({.account = depositor, .flags = tfMPTUnauthorize}); env.close(); - auto const mptoken = - keylet::mptoken(mptt.issuanceID(), depositor); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), depositor); auto const sleMPT1 = env.le(mptoken); BEAST_EXPECT(sleMPT1 == nullptr); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx); env.close(); @@ -2022,19 +1687,14 @@ class Vault_test : public beast::unit_test::suite { // Remove 3rd party MPToken and it will not be re-created - mptt.authorize( - {.account = owner, .flags = tfMPTUnauthorize}); + mptt.authorize({.account = owner, .flags = tfMPTUnauthorize}); env.close(); - auto const mptoken = - keylet::mptoken(mptt.issuanceID(), owner); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), owner); auto const sleMPT1 = env.le(mptoken); BEAST_EXPECT(sleMPT1 == nullptr); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); tx[sfDestination] = owner.human(); env(tx, ter(tecNO_AUTH)); env.close(); @@ -2048,10 +1708,8 @@ class Vault_test : public beast::unit_test::suite auto const [acctReserve, incReserve] = [this]() -> std::pair { Env env{*this, testable_amendments()}; return { - env.current()->fees().accountReserve(0).drops() / - DROPS_PER_XRP.drops(), - env.current()->fees().increment.drops() / - DROPS_PER_XRP.drops()}; + env.current()->fees().accountReserve(0).drops() / DROPS_PER_XRP.drops(), + env.current()->fees().increment.drops() / DROPS_PER_XRP.drops()}; }(); testCase( @@ -2063,10 +1721,9 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const& asset, Vault& vault, MPTTester& mptt) { - testcase("MPT failed reserve to re-create MPToken"); + testcase("MPT fail reserve to re-create MPToken"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); auto v = env.le(keylet); @@ -2076,28 +1733,25 @@ class Vault_test : public beast::unit_test::suite env.close(); tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(1000)}); // all assets held by owner + {.depositor = owner, .id = keylet.key, .amount = asset(1000)}); // all assets held by owner env(tx); env.close(); { // Remove owners's MPToken and it will not be re-created - mptt.authorize( - {.account = owner, .flags = tfMPTUnauthorize}); + mptt.authorize({.account = owner, .flags = tfMPTUnauthorize}); env.close(); - auto const mptoken = - keylet::mptoken(mptt.issuanceID(), owner); + auto const mptoken = keylet::mptoken(mptt.issuanceID(), owner); auto const sleMPT = env.le(mptoken); BEAST_EXPECT(sleMPT == nullptr); + // Use one reserve so the next transaction fails + env(ticket::create(owner, 1)); + env.close(); + // No reserve to create MPToken for asset in VaultWithdraw - tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(100)}); env(tx, ter{tecINSUFFICIENT_RESERVE}); env.close(); @@ -2109,8 +1763,7 @@ class Vault_test : public beast::unit_test::suite env.close(); } }, - {.requireAuth = false, - .initialXRP = acctReserve + incReserve * 4 - 1}); + {.requireAuth = false, .initialXRP = acctReserve + incReserve * 4 + 1}); testCase([this]( Env& env, @@ -2126,19 +1779,12 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx); env.close(); { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx); } @@ -2146,33 +1792,22 @@ class Vault_test : public beast::unit_test::suite env.close(); { - auto [tx, keylet] = - vault.create({.owner = depositor, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = depositor, .asset = asset}); env(tx, ter{tecOBJECT_NOT_FOUND}); } { - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecOBJECT_NOT_FOUND}); } { - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecOBJECT_NOT_FOUND}); } { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx, ter{tecOBJECT_NOT_FOUND}); } @@ -2193,14 +1828,11 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx); env.close(); - auto const issuanceId = [&env](ripple::Keylet keylet) -> MPTID { + auto const issuanceId = [&env](xrpl::Keylet keylet) -> MPTID { auto const vault = env.le(keylet); return vault->at(sfShareMPTID); }(keylet); @@ -2211,10 +1843,7 @@ class Vault_test : public beast::unit_test::suite env(pay(depositor, owner, shares(1))); env.close(); - tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = shares(1)}); + tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = shares(1)}); env(tx); env.close(); @@ -2222,11 +1851,7 @@ class Vault_test : public beast::unit_test::suite env(pay(depositor, owner, shares(1))); env.close(); - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(0)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(0)}); env(tx); env.close(); @@ -2255,11 +1880,7 @@ class Vault_test : public beast::unit_test::suite env.close(); // destroy all remaining shares, so we can delete vault - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx); env.close(); @@ -2280,24 +1901,17 @@ class Vault_test : public beast::unit_test::suite MPTTester& mptt) { testcase("MPT clawback disabled"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx); env.close(); { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx, ter{tecNO_PERMISSION}); } }, @@ -2315,24 +1929,15 @@ class Vault_test : public beast::unit_test::suite auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1000)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1000)}); env(tx); env.close(); - mptt.authorize( - {.account = issuer, - .holder = depositor, - .flags = tfMPTUnauthorize}); + mptt.authorize({.account = issuer, .holder = depositor, .flags = tfMPTUnauthorize}); env.close(); { - auto tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + auto tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecNO_AUTH)); // Withdrawal to other (authorized) accounts works @@ -2347,19 +1952,17 @@ class Vault_test : public beast::unit_test::suite { // Cannot deposit some more - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecNO_AUTH)); } + { + // Cannot clawback if issuer is the holder + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = issuer, .amount = asset(800)}); + env(tx, ter(tecNO_PERMISSION)); + } // Clawback works - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(800)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(800)}); env(tx); env.close(); @@ -2379,25 +1982,20 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - auto const vaultAccount = - [&env, keylet = keylet, this]() -> AccountID { + auto const vaultAccount = [&env, keylet = keylet, this]() -> AccountID { auto const vault = env.le(keylet); BEAST_EXPECT(vault != nullptr); return vault->at(sfAccount); }(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx); env.close(); tx = [&]() { Json::Value jv; jv[jss::Account] = issuer.human(); - jv[sfMPTokenIssuanceID] = - to_string(asset.get().getMptID()); + jv[sfMPTokenIssuanceID] = to_string(asset.get().getMptID()); jv[jss::Holder] = toBase58(vaultAccount); jv[jss::TransactionType] = jss::MPTokenIssuanceSet; jv[jss::Flags] = tfMPTLock; @@ -2406,24 +2004,14 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecLOCKED)); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); env(tx, ter(tecLOCKED)); // Clawback works, even when locked - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(100)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(100)}); env(tx); // Can delete an empty vault even when asset is locked. @@ -2442,9 +2030,7 @@ class Vault_test : public beast::unit_test::suite Vault vault{env}; MPTTester mptt{env, issuer, mptInitNoFund}; - mptt.create( - {.flags = tfMPTCanTransfer | tfMPTCanLock | lsfMPTCanClawback | - tfMPTRequireAuth}); + mptt.create({.flags = tfMPTCanTransfer | tfMPTCanLock | lsfMPTCanClawback | tfMPTRequireAuth}); mptt.authorize({.account = owner}); mptt.authorize({.account = issuer, .holder = owner}); PrettyAsset asset = mptt.issuanceID(); @@ -2463,6 +2049,47 @@ class Vault_test : public beast::unit_test::suite env(tx2, ter{tecWRONG_ASSET}); env.close(); } + + testCase([this]( + Env& env, + Account const&, + Account const& owner, + Account const& depositor, + PrettyAsset const& asset, + Vault& vault, + MPTTester& mptt) { + testcase("MPT non-transferable"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + env(tx); + env.close(); + + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); + env(tx); + env.close(); + + // Remove CanTransfer + mptt.set({.mutableFlags = tmfMPTClearCanTransfer}); + env.close(); + + env(tx, ter{tecNO_AUTH}); + env.close(); + + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(100)}); + + env(tx, ter{tecNO_AUTH}); + env.close(); + + // Restore CanTransfer + mptt.set({.mutableFlags = tmfMPTSetCanTransfer}); + env.close(); + + env(tx); + env.close(); + + // Delete vault with zero balance + env(vault.del({.owner = owner, .id = keylet.key})); + }); } void @@ -2473,55 +2100,58 @@ class Vault_test : public beast::unit_test::suite struct CaseArgs { int initialXRP = 1000; + Number initialIOU = 200; double transferRate = 1.0; + bool charlieRipple = true; }; - auto testCase = - [&, this]( - std::function vaultAccount, - Vault& vault, - PrettyAsset const& asset, - std::function issuanceId)> test, - CaseArgs args = {}) { - Env env{*this, testable_amendments() | featureSingleAssetVault}; - Account const owner{"owner"}; - Account const issuer{"issuer"}; - Account const charlie{"charlie"}; - Vault vault{env}; - env.fund(XRP(args.initialXRP), issuer, owner, charlie); - env(fset(issuer, asfAllowTrustLineClawback)); - env.close(); + auto testCase = [&, this]( + std::function vaultAccount, + Vault& vault, + PrettyAsset const& asset, + std::function issuanceId)> test, + CaseArgs args = {}) { + Env env{*this, testable_amendments() | featureSingleAssetVault}; + Account const owner{"owner"}; + Account const issuer{"issuer"}; + Account const charlie{"charlie"}; + Vault vault{env}; + env.fund(XRP(args.initialXRP), issuer, owner, charlie); + env(fset(issuer, asfAllowTrustLineClawback)); + env.close(); - PrettyAsset const asset = issuer["IOU"]; - env.trust(asset(1000), owner); + PrettyAsset const asset = issuer["IOU"]; + env.trust(asset(1000), owner); + env(pay(issuer, owner, asset(args.initialIOU))); + env.close(); + if (!args.charlieRipple) + { + env(fset(issuer, 0, asfDefaultRipple)); + env.close(); env.trust(asset(1000), charlie); - env(pay(issuer, owner, asset(200))); - env(rate(issuer, args.transferRate)); env.close(); + env(pay(issuer, charlie, asset(args.initialIOU))); + env.close(); + env(fset(issuer, asfDefaultRipple)); + } + else + env.trust(asset(1000), charlie); + env.close(); + env(rate(issuer, args.transferRate)); + env.close(); - auto const vaultAccount = - [&env](ripple::Keylet keylet) -> Account { - return Account("vault", env.le(keylet)->at(sfAccount)); - }; - auto const issuanceId = [&env](ripple::Keylet keylet) -> MPTID { - return env.le(keylet)->at(sfShareMPTID); - }; - - test( - env, - owner, - issuer, - charlie, - vaultAccount, - vault, - asset, - issuanceId); + auto const vaultAccount = [&env](xrpl::Keylet keylet) -> Account { + return Account("vault", env.le(keylet)->at(sfAccount)); }; + auto const issuanceId = [&env](xrpl::Keylet keylet) -> MPTID { return env.le(keylet)->at(sfShareMPTID); }; + + test(env, owner, issuer, charlie, vaultAccount, vault, asset, issuanceId); + }; testCase([&, this]( Env& env, @@ -2545,8 +2175,7 @@ class Vault_test : public beast::unit_test::suite Json::Value jv; jv[jss::Account] = issuer.human(); { - auto& ja = jv[jss::LimitAmount] = - foo(0).value().getJson(JsonOptions::none); + auto& ja = jv[jss::LimitAmount] = foo(0).value().getJson(JsonOptions::none); ja[jss::issuer] = toBase58(account); } jv[jss::TransactionType] = jss::TrustSet; @@ -2558,15 +2187,13 @@ class Vault_test : public beast::unit_test::suite } { - auto tx = vault.deposit( - {.depositor = issuer, .id = keylet.key, .amount = foo(20)}); + auto tx = vault.deposit({.depositor = issuer, .id = keylet.key, .amount = foo(20)}); env(tx, ter{tecWRONG_ASSET}); env.close(); } { - auto tx = vault.withdraw( - {.depositor = issuer, .id = keylet.key, .amount = foo(20)}); + auto tx = vault.withdraw({.depositor = issuer, .id = keylet.key, .amount = foo(20)}); env(tx, ter{tecWRONG_ASSET}); env.close(); } @@ -2590,8 +2217,7 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); Asset const share = Asset(issuanceId(keylet)); @@ -2601,8 +2227,7 @@ class Vault_test : public beast::unit_test::suite Json::Value jv; jv[jss::Account] = issuer.human(); { - auto& ja = jv[jss::LimitAmount] = - asset(0).value().getJson(JsonOptions::none); + auto& ja = jv[jss::LimitAmount] = asset(0).value().getJson(JsonOptions::none); ja[jss::issuer] = toBase58(account); } jv[jss::TransactionType] = jss::TrustSet; @@ -2617,18 +2242,12 @@ class Vault_test : public beast::unit_test::suite // is reported as "locked" state of the vault shares, because // this state is attached to shares by means of the transitive // isFrozen. - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(80)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(80)}); env(tx, ter{tecLOCKED}); } { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(100)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(100)}); env(tx, ter{tecLOCKED}); // also when trying to withdraw to a 3rd party @@ -2639,11 +2258,7 @@ class Vault_test : public beast::unit_test::suite { // Clawback works, even when locked - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(50)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(50)}); env(tx); env.close(); } @@ -2653,10 +2268,7 @@ class Vault_test : public beast::unit_test::suite env(trustSet); env.close(); - env(vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = share(50'000'000)})); + env(vault.withdraw({.depositor = owner, .id = keylet.key, .amount = share(50'000'000)})); env(vault.del({.owner = owner, .id = keylet.key})); env.close(); @@ -2674,15 +2286,11 @@ class Vault_test : public beast::unit_test::suite auto issuanceId) { testcase("IOU transfer fees not applied"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); auto const issue = asset.raw().get(); @@ -2690,39 +2298,27 @@ class Vault_test : public beast::unit_test::suite // transfer fees ignored on deposit BEAST_EXPECT(env.balance(owner, issue) == asset(100)); - BEAST_EXPECT( - env.balance(vaultAccount(keylet), issue) == asset(100)); + BEAST_EXPECT(env.balance(vaultAccount(keylet), issue) == asset(100)); { - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(50)}); + auto tx = + vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(50)}); env(tx); env.close(); } // transfer fees ignored on clawback BEAST_EXPECT(env.balance(owner, issue) == asset(100)); - BEAST_EXPECT( - env.balance(vaultAccount(keylet), issue) == asset(50)); + BEAST_EXPECT(env.balance(vaultAccount(keylet), issue) == asset(50)); - env(vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = share(20'000'000)})); + env(vault.withdraw({.depositor = owner, .id = keylet.key, .amount = share(20'000'000)})); // transfer fees ignored on withdraw BEAST_EXPECT(env.balance(owner, issue) == asset(120)); - BEAST_EXPECT( - env.balance(vaultAccount(keylet), issue) == asset(30)); + BEAST_EXPECT(env.balance(vaultAccount(keylet), issue) == asset(30)); { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = share(30'000'000)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = share(30'000'000)}); tx[sfDestination] = charlie.human(); env(tx); } @@ -2730,8 +2326,7 @@ class Vault_test : public beast::unit_test::suite // transfer fees ignored on withdraw to 3rd party BEAST_EXPECT(env.balance(owner, issue) == asset(120)); BEAST_EXPECT(env.balance(charlie, issue) == asset(30)); - BEAST_EXPECT( - env.balance(vaultAccount(keylet), issue) == asset(0)); + BEAST_EXPECT(env.balance(vaultAccount(keylet), issue) == asset(0)); env(vault.del({.owner = owner, .id = keylet.key})); env.close(); @@ -2753,16 +2348,12 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); // Withdraw to 3rd party works - auto const withdrawToCharlie = [&](ripple::Keylet keylet) { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto const withdrawToCharlie = [&](xrpl::Keylet keylet) { + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[sfDestination] = charlie.human(); return tx; }(keylet); @@ -2773,8 +2364,7 @@ class Vault_test : public beast::unit_test::suite env.close(); // Cannot withdraw - auto const withdraw = vault.withdraw( - {.depositor = owner, .id = keylet.key, .amount = asset(10)}); + auto const withdraw = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(withdraw, ter{tecFROZEN}); // Cannot withdraw to 3rd party @@ -2783,20 +2373,13 @@ class Vault_test : public beast::unit_test::suite { // Cannot deposit some more - auto tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecFROZEN}); } { // Clawback still works - auto tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(0)}); + auto tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(0)}); env(tx); env.close(); } @@ -2820,8 +2403,7 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); Account const erin{"erin"}; @@ -2829,11 +2411,8 @@ class Vault_test : public beast::unit_test::suite env.close(); // Withdraw to 3rd party without trust line - auto const tx1 = [&](ripple::Keylet keylet) { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto const tx1 = [&](xrpl::Keylet keylet) { + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[sfDestination] = erin.human(); return tx; }(keylet); @@ -2859,32 +2438,157 @@ class Vault_test : public beast::unit_test::suite env.trust(asset(0), owner); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(200)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(200)})); env.close(); - auto trustline = - env.le(keylet::line(owner, asset.raw().get())); + auto trustline = env.le(keylet::line(owner, asset.raw().get())); BEAST_EXPECT(trustline == nullptr); // Withdraw without trust line, will succeed - auto const tx1 = [&](ripple::Keylet keylet) { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto const tx1 = [&](xrpl::Keylet keylet) { + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); return tx; }(keylet); env(tx1); }); + testCase( + [&, this]( + Env& env, + Account const& owner, + Account const& issuer, + Account const& charlie, + auto vaultAccount, + Vault& vault, + PrettyAsset const& asset, + std::function issuanceId) { + testcase("IOU non-transferable"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + tx[sfScale] = 0; + env(tx); + env.close(); + + // Turn on noripple on the pseudo account's trust line. + // Charlie's is already set. + env(trust(issuer, vaultAccount(keylet)["IOU"], tfSetNoRipple), THISLINE); + + { + // Charlie cannot deposit + auto tx = vault.deposit({.depositor = charlie, .id = keylet.key, .amount = asset(100)}); + env(tx, ter{terNO_RIPPLE}, THISLINE); + env.close(); + } + + { + PrettyAsset shares = issuanceId(keylet); + auto tx1 = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)}); + env(tx1, THISLINE); + env.close(); + + // Charlie cannot receive funds + auto tx2 = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = shares(100)}); + tx2[sfDestination] = charlie.human(); + env(tx2, ter{terNO_RIPPLE}, THISLINE); + env.close(); + + { + // Create MPToken for shares held by Charlie + Json::Value tx{Json::objectValue}; + tx[sfAccount] = charlie.human(); + tx[sfMPTokenIssuanceID] = to_string(shares.raw().get().getMptID()); + tx[sfTransactionType] = jss::MPTokenAuthorize; + env(tx); + env.close(); + } + env(pay(owner, charlie, shares(100)), THISLINE); + env.close(); + + // Charlie cannot withdraw + auto tx3 = vault.withdraw({.depositor = charlie, .id = keylet.key, .amount = shares(100)}); + env(tx3, ter{terNO_RIPPLE}); + env.close(); + + env(pay(charlie, owner, shares(100)), THISLINE); + env.close(); + } + + tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(100)}); + env(tx, THISLINE); + env.close(); + + // Delete vault with zero balance + env(vault.del({.owner = owner, .id = keylet.key}), THISLINE); + }, + {.charlieRipple = false}); + + testCase( + [&, this]( + Env& env, + Account const& owner, + Account const& issuer, + Account const& charlie, + auto const& vaultAccount, + Vault& vault, + PrettyAsset const& asset, + auto&&...) { + testcase("IOU calculation rounding"); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); + tx[sfScale] = 1; + env(tx); + env.close(); + + auto const startingOwnerBalance = env.balance(owner, asset); + BEAST_EXPECT((startingOwnerBalance.value() == STAmount{asset, 11875, -2})); + + // This operation (first deposit 100, then 3.75 x 5) is known to + // have triggered calculation rounding errors in Number + // (addition and division), causing the last deposit to be + // blocked by Vault invariants. + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); + + auto const tx1 = + vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(Number(375, -2))}); + for (auto i = 0; i < 5; ++i) + { + env(tx1); + } + env.close(); + + { + STAmount const xfer{asset, 1185, -1}; + BEAST_EXPECT(env.balance(owner, asset) == startingOwnerBalance.value() - xfer); + BEAST_EXPECT(env.balance(vaultAccount(keylet), asset) == xfer); + + auto const vault = env.le(keylet); + BEAST_EXPECT(vault->at(sfAssetsAvailable) == xfer); + BEAST_EXPECT(vault->at(sfAssetsTotal) == xfer); + } + + // Total vault balance should be 118.5 IOU. Withdraw and delete + // the vault to verify this exact amount was deposited and the + // owner has matching shares + env(vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(Number(1000 + 37 * 5, -1))})); + + { + BEAST_EXPECT(env.balance(owner, asset) == startingOwnerBalance.value()); + BEAST_EXPECT(env.balance(vaultAccount(keylet), asset) == beast::zero); + auto const vault = env.le(keylet); + BEAST_EXPECT(vault->at(sfAssetsAvailable) == beast::zero); + BEAST_EXPECT(vault->at(sfAssetsTotal) == beast::zero); + } + + env(vault.del({.owner = owner, .id = keylet.key})); + env.close(); + }, + {.initialIOU = Number(11875, -2)}); + auto const [acctReserve, incReserve] = [this]() -> std::pair { Env env{*this, testable_amendments()}; return { - env.current()->fees().accountReserve(0).drops() / - DROPS_PER_XRP.drops(), - env.current()->fees().increment.drops() / - DROPS_PER_XRP.drops()}; + env.current()->fees().accountReserve(0).drops() / DROPS_PER_XRP.drops(), + env.current()->fees().increment.drops() / DROPS_PER_XRP.drops()}; }(); testCase( @@ -2898,8 +2602,7 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const& asset, auto&&...) { testcase("IOU no trust line to depositor no reserve"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); @@ -2908,21 +2611,17 @@ class Vault_test : public beast::unit_test::suite env.trust(asset(0), owner); env.close(); - env(vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(200)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(200)})); env.close(); - auto trustline = - env.le(keylet::line(owner, asset.raw().get())); + auto trustline = env.le(keylet::line(owner, asset.raw().get())); BEAST_EXPECT(trustline == nullptr); + env(ticket::create(owner, 1)); + env.close(); + // Fail because not enough reserve to create trust line - tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecNO_LINE_INSUF_RESERVE}); env.close(); @@ -2933,7 +2632,7 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); }, - CaseArgs{.initialXRP = acctReserve + incReserve * 4 - 1}); + CaseArgs{.initialXRP = acctReserve + incReserve * 4 + 1}); testCase( [&, this]( @@ -2946,23 +2645,18 @@ class Vault_test : public beast::unit_test::suite PrettyAsset const& asset, auto&&...) { testcase("IOU no reserve for share MPToken"); - auto [tx, keylet] = - vault.create({.owner = owner, .asset = asset}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset}); env(tx); env.close(); env(pay(owner, charlie, asset(100))); env.close(); - // Use up some reserve on tickets - env(ticket::create(charlie, 2)); + env(ticket::create(charlie, 3)); env.close(); // Fail because not enough reserve to create MPToken for shares - tx = vault.deposit( - {.depositor = charlie, - .id = keylet.key, - .amount = asset(100)}); + tx = vault.deposit({.depositor = charlie, .id = keylet.key, .amount = asset(100)}); env(tx, ter{tecINSUFFICIENT_RESERVE}); env.close(); @@ -2973,7 +2667,7 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); }, - CaseArgs{.initialXRP = acctReserve + incReserve * 4 - 1}); + CaseArgs{.initialXRP = acctReserve + incReserve * 4 + 1}); testCase([&, this]( Env& env, @@ -2990,16 +2684,12 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); // Withdraw to 3rd party works - auto const withdrawToCharlie = [&](ripple::Keylet keylet) { - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto const withdrawToCharlie = [&](xrpl::Keylet keylet) { + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); tx[sfDestination] = charlie.human(); return tx; }(keylet); @@ -3010,8 +2700,7 @@ class Vault_test : public beast::unit_test::suite env.close(); // Can withdraw - auto const withdraw = vault.withdraw( - {.depositor = owner, .id = keylet.key, .amount = asset(10)}); + auto const withdraw = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(withdraw); env.close(); @@ -3019,11 +2708,7 @@ class Vault_test : public beast::unit_test::suite env(withdrawToCharlie, ter{tecFROZEN}); env.close(); - env(vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(0)})); + env(vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(0)})); env.close(); env(vault.del({.owner = owner, .id = keylet.key})); @@ -3045,8 +2730,7 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - env(vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(100)})); + env(vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(100)})); env.close(); env(fset(issuer, asfGlobalFreeze)); @@ -3054,10 +2738,7 @@ class Vault_test : public beast::unit_test::suite { // Cannot withdraw - auto tx = vault.withdraw( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + auto tx = vault.withdraw({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecFROZEN}); // Cannot withdraw to 3rd party @@ -3066,20 +2747,13 @@ class Vault_test : public beast::unit_test::suite env.close(); // Cannot deposit some more - tx = vault.deposit( - {.depositor = owner, - .id = keylet.key, - .amount = asset(10)}); + tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(10)}); env(tx, ter{tecFROZEN}); } // Clawback is permitted - env(vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(0)})); + env(vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(0)})); env.close(); env(vault.del({.owner = owner, .id = keylet.key})); @@ -3104,15 +2778,7 @@ class Vault_test : public beast::unit_test::suite Account credIssuer2{"credIssuer2"}; std::string const credType = "credential"; Vault vault{env}; - env.fund( - XRP(1000), - issuer, - owner, - depositor, - charlie, - pdOwner, - credIssuer1, - credIssuer2); + env.fund(XRP(1000), issuer, owner, depositor, charlie, pdOwner, credIssuer1, credIssuer2); env.close(); env(fset(issuer, asfAllowTrustLineClawback)); env.close(); @@ -3127,25 +2793,20 @@ class Vault_test : public beast::unit_test::suite env(pay(issuer, charlie, asset(5))); env.close(); - auto [tx, keylet] = vault.create( - {.owner = owner, .asset = asset, .flags = tfVaultPrivate}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate}); env(tx); env.close(); BEAST_EXPECT(env.le(keylet)); { testcase("private vault owner can deposit"); - auto tx = vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(50)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(50)}); env(tx); } { testcase("private vault depositor not authorized yet"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); } @@ -3160,8 +2821,7 @@ class Vault_test : public beast::unit_test::suite testcase("private vault set domainId"); { - pdomain::Credentials const credentials1{ - {.issuer = credIssuer1, .credType = credType}}; + pdomain::Credentials const credentials1{{.issuer = credIssuer1, .credType = credType}}; env(pdomain::setTx(pdOwner, credentials1)); auto const domainId1 = [&]() { @@ -3181,8 +2841,7 @@ class Vault_test : public beast::unit_test::suite { pdomain::Credentials const credentials{ - {.issuer = credIssuer1, .credType = credType}, - {.issuer = credIssuer2, .credType = credType}}; + {.issuer = credIssuer1, .credType = credType}, {.issuer = credIssuer2, .credType = credType}}; env(pdomain::setTx(pdOwner, credentials)); auto const domainId = [&]() { @@ -3205,16 +2864,12 @@ class Vault_test : public beast::unit_test::suite { testcase("private vault depositor still not authorized"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); env.close(); } - auto const credKeylet = - credentials::keylet(depositor, credIssuer1, credType); + auto const credKeylet = credentials::keylet(depositor, credIssuer1, credType); { testcase("private vault depositor now authorized"); env(credentials::create(depositor, credIssuer1, credType)); @@ -3225,33 +2880,24 @@ class Vault_test : public beast::unit_test::suite auto credSle = env.le(credKeylet); BEAST_EXPECT(credSle != nullptr); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); - tx = vault.deposit( - {.depositor = charlie, .id = keylet.key, .amount = asset(50)}); + tx = vault.deposit({.depositor = charlie, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); env.close(); } { testcase("private vault depositor lost authorization"); - env(credentials::deleteCred( - credIssuer1, depositor, credIssuer1, credType)); - env(credentials::deleteCred( - credIssuer1, charlie, credIssuer1, credType)); + env(credentials::deleteCred(credIssuer1, depositor, credIssuer1, credType)); + env(credentials::deleteCred(credIssuer1, charlie, credIssuer1, credType)); env.close(); auto credSle = env.le(credKeylet); BEAST_EXPECT(credSle == nullptr); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); env.close(); } @@ -3264,13 +2910,9 @@ class Vault_test : public beast::unit_test::suite { testcase("private vault expired authorization"); - uint32_t const closeTime = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count(); + uint32_t const closeTime = env.current()->header().parentCloseTime.time_since_epoch().count(); { - auto tx0 = - credentials::create(depositor, credIssuer2, credType); + auto tx0 = credentials::create(depositor, credIssuer2, credType); tx0[sfExpiration] = closeTime + 20; env(tx0); tx0 = credentials::create(charlie, credIssuer2, credType); @@ -3284,15 +2926,11 @@ class Vault_test : public beast::unit_test::suite } { - auto tx1 = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx1 = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx1); env.close(); - auto const tokenKeylet = keylet::mptoken( - shares.get().getMptID(), depositor.id()); + auto const tokenKeylet = keylet::mptoken(shares.get().getMptID(), depositor.id()); BEAST_EXPECT(env.le(tokenKeylet) != nullptr); } @@ -3302,14 +2940,10 @@ class Vault_test : public beast::unit_test::suite env.close(); env.close(); - auto const credsKeylet = - credentials::keylet(depositor, credIssuer2, credType); + auto const credsKeylet = credentials::keylet(depositor, credIssuer2, credType); BEAST_EXPECT(env.le(credsKeylet) != nullptr); - auto tx2 = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(1)}); + auto tx2 = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1)}); env(tx2, ter{tecEXPIRED}); env.close(); @@ -3317,17 +2951,12 @@ class Vault_test : public beast::unit_test::suite } { - auto const credsKeylet = - credentials::keylet(charlie, credIssuer2, credType); + auto const credsKeylet = credentials::keylet(charlie, credIssuer2, credType); BEAST_EXPECT(env.le(credsKeylet) != nullptr); - auto const tokenKeylet = keylet::mptoken( - shares.get().getMptID(), charlie.id()); + auto const tokenKeylet = keylet::mptoken(shares.get().getMptID(), charlie.id()); BEAST_EXPECT(env.le(tokenKeylet) == nullptr); - auto tx3 = vault.deposit( - {.depositor = charlie, - .id = keylet.key, - .amount = asset(2)}); + auto tx3 = vault.deposit({.depositor = charlie, .id = keylet.key, .amount = asset(2)}); env(tx3, ter{tecEXPIRED}); env.close(); @@ -3343,32 +2972,18 @@ class Vault_test : public beast::unit_test::suite env(tx); env.close(); - tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); env.close(); - tx = vault.withdraw( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + tx = vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = depositor, - .amount = asset(0)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = depositor, .amount = asset(0)}); env(tx); - tx = vault.clawback( - {.issuer = issuer, - .id = keylet.key, - .holder = owner, - .amount = asset(0)}); + tx = vault.clawback({.issuer = issuer, .id = keylet.key, .holder = owner, .amount = asset(0)}); env(tx); env.close(); @@ -3397,13 +3012,11 @@ class Vault_test : public beast::unit_test::suite env.close(); PrettyAsset asset = xrpIssue(); - auto [tx, keylet] = vault.create( - {.owner = owner, .asset = asset, .flags = tfVaultPrivate}); + auto [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate}); env(tx); env.close(); - auto const [vaultAccount, issuanceId] = - [&env, keylet = keylet, this]() -> std::tuple { + auto const [vaultAccount, issuanceId] = [&env, keylet = keylet, this]() -> std::tuple { auto const vault = env.le(keylet); BEAST_EXPECT(vault != nullptr); return {vault->at(sfAccount), vault->at(sfShareMPTID)}; @@ -3414,8 +3027,7 @@ class Vault_test : public beast::unit_test::suite { testcase("private XRP vault owner can deposit"); - auto tx = vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(50)}); + auto tx = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); } @@ -3427,17 +3039,13 @@ class Vault_test : public beast::unit_test::suite { testcase("private XRP vault depositor not authorized yet"); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx, ter{tecNO_AUTH}); } { testcase("private XRP vault set DomainID"); - pdomain::Credentials const credentials{ - {.issuer = owner, .credType = credType}}; + pdomain::Credentials const credentials{{.issuer = owner, .credType = credType}}; env(pdomain::setTx(owner, credentials)); auto const domainId = [&]() { @@ -3459,10 +3067,7 @@ class Vault_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(env.le(credKeylet)); - auto tx = vault.deposit( - {.depositor = depositor, - .id = keylet.key, - .amount = asset(50)}); + auto tx = vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(50)}); env(tx); env.close(); } @@ -3499,17 +3104,12 @@ class Vault_test : public beast::unit_test::suite auto const keylet = keylet::vault(owner.id(), env.seq(owner)); for (int i = 0; i < 256; ++i) { - AccountID const accountId = - ripple::pseudoAccountAddress(*env.current(), keylet.key); + AccountID const accountId = xrpl::pseudoAccountAddress(*env.current(), keylet.key); - env(pay(env.master.id(), accountId, XRP(1000)), - seq(autofill), - fee(autofill), - sig(autofill)); + env(pay(env.master.id(), accountId, XRP(1000)), seq(autofill), fee(autofill), sig(autofill)); } - auto [tx, keylet1] = - vault.create({.owner = owner, .asset = xrpIssue()}); + auto [tx, keylet1] = vault.create({.owner = owner, .asset = xrpIssue()}); BEAST_EXPECT(keylet.key == keylet1.key); env(tx, ter{terADDRESS_COLLISION}); } @@ -3528,15 +3128,13 @@ class Vault_test : public beast::unit_test::suite MPTIssue shares; PrettyAsset const& share; Vault& vault; - ripple::Keylet keylet; + xrpl::Keylet keylet; Issue assets; PrettyAsset const& asset; std::function)> peek; }; - auto testCase = [&, this]( - std::uint8_t scale, - std::function test) { + auto testCase = [&, this](std::uint8_t scale, std::function test) { Env env{*this, testable_amendments() | featureSingleAssetVault}; Account const owner{"owner"}; Account const issuer{"issuer"}; @@ -3557,37 +3155,31 @@ class Vault_test : public beast::unit_test::suite tx[sfScale] = scale; env(tx); - auto const [vaultAccount, issuanceId] = - [&env](ripple::Keylet keylet) -> std::tuple { + auto const [vaultAccount, issuanceId] = [&env](xrpl::Keylet keylet) -> std::tuple { auto const vault = env.le(keylet); - return { - Account("vault", vault->at(sfAccount)), - vault->at(sfShareMPTID)}; + return {Account("vault", vault->at(sfAccount)), vault->at(sfShareMPTID)}; }(keylet); MPTIssue shares(issuanceId); env.memoize(vaultAccount); - auto const peek = - [=, &env, this](std::function fn) -> bool { - return env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) -> bool { - Sandbox sb(&view, tapNONE); - auto vault = sb.peek(keylet::vault(keylet.key)); - if (!BEAST_EXPECT(vault != nullptr)) - return false; - auto shares = sb.peek( - keylet::mptIssuance(vault->at(sfShareMPTID))); - if (!BEAST_EXPECT(shares != nullptr)) - return false; - if (fn(*vault, *shares)) - { - sb.update(vault); - sb.update(shares); - sb.apply(view); - return true; - } + auto const peek = [=, &env, this](std::function fn) -> bool { + return env.app().openLedger().modify([&](OpenView& view, beast::Journal j) -> bool { + Sandbox sb(&view, tapNONE); + auto vault = sb.peek(keylet::vault(keylet.key)); + if (!BEAST_EXPECT(vault != nullptr)) return false; - }); + auto shares = sb.peek(keylet::mptIssuance(vault->at(sfShareMPTID))); + if (!BEAST_EXPECT(shares != nullptr)) + return false; + if (fn(*vault, *shares)) + { + sb.update(vault); + sb.update(shares); + sb.apply(view); + return true; + } + return false; + }); }; test( @@ -3607,10 +3199,7 @@ class Vault_test : public beast::unit_test::suite testCase(18, [&, this](Env& env, Data d) { testcase("Scale deposit overflow on first deposit"); - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(10)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(10)}); env(tx, ter{tecPATH_DRY}); env.close(); }); @@ -3619,19 +3208,13 @@ class Vault_test : public beast::unit_test::suite testcase("Scale deposit overflow on second deposit"); { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(5)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(5)}); env(tx); env.close(); } { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(10)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(10)}); env(tx, ter{tecPATH_DRY}); env.close(); } @@ -3641,19 +3224,13 @@ class Vault_test : public beast::unit_test::suite testcase("Scale deposit overflow on total shares"); { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(5)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(5)}); env(tx); env.close(); } { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(5)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(5)}); env(tx, ter{tecPATH_DRY}); env.close(); } @@ -3663,25 +3240,18 @@ class Vault_test : public beast::unit_test::suite testcase("Scale deposit exact"); auto const start = env.balance(d.depositor, d.assets).number(); - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(1)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(1)}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(10)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - 1)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - 1)); }); testCase(1, [&, this](Env& env, Data d) { testcase("Scale deposit insignificant amount"); auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(9, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(9, -2))}); env(tx, ter{tecPRECISION_LOSS}); }); @@ -3690,15 +3260,11 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(15, -1))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(15, -1))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(15)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(15, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(15, -1))); }); testCase(1, [&, this](Env& env, Data d) { @@ -3709,41 +3275,29 @@ class Vault_test : public beast::unit_test::suite // vault and receive 12 shares in exchange { auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(125, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(125, -2))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(12, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(12, -1))); } { auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(1201, -3))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(1201, -3))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(24)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(24, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(24, -1))); } { auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(1299, -3))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(1299, -3))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(36)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(36, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(36, -1))); } }); @@ -3753,28 +3307,20 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); // round to 12 auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(1201, -3))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(1201, -3))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(12, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(12, -1))); { // round to 6 auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(69, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(69, -2))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(18)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(18, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(18, -1))); } }); @@ -3784,28 +3330,20 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); // round to 12 auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(1299, -3))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(1299, -3))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(12)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(12, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(12, -1))); { // round to 6 auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(62, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(62, -2))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(18)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(18, -1))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(18, -1))); } }); @@ -3813,21 +3351,13 @@ class Vault_test : public beast::unit_test::suite // initial setup: deposit 100 IOU, receive 1000 shares auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(100, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(100, 0))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, Number(-1000, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, Number(-1000, 0))); { testcase("Scale redeem exact"); @@ -3837,22 +3367,13 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.share, Number(100, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.share, Number(100, 0))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(10, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(90, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, Number(-900, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(10, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(90, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, Number(-900, 0))); } { @@ -3872,22 +3393,13 @@ class Vault_test : public beast::unit_test::suite // closed (because a modification like above is not persistent), // which is why the checks below are expected to pass. auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.share, Number(25, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.share, Number(25, 0))}); env(tx, ter{tecINSUFFICIENT_FUNDS}); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900 - 25)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(25, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(900 - 25, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(900 - 25, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900 - 25)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(25, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(900 - 25, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(900 - 25, 0))); } { @@ -3899,39 +3411,26 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.share, Number(21, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.share, Number(21, 0))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(875 - 21)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(21, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(875 - 21, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(875 - 21, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(875 - 21)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(21, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(875 - 21, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(875 - 21, 0))); } { testcase("Scale redeem rest"); auto const rest = env.balance(d.depositor, d.shares).number(); - tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.share, rest)}); + tx = + d.vault.withdraw({.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.share, rest)}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares).number() == 0); } }); @@ -3939,19 +3438,14 @@ class Vault_test : public beast::unit_test::suite testcase("Scale withdraw overflow"); { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(5)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(5)}); env(tx); env.close(); } { auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(10, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(10, 0))}); env(tx, ter{tecPATH_DRY}); env.close(); } @@ -3961,21 +3455,13 @@ class Vault_test : public beast::unit_test::suite // initial setup: deposit 100 IOU, receive 1000 shares auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(100, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(100, 0))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, Number(-1000, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, Number(-1000, 0))); { testcase("Scale withdraw exact"); @@ -3988,30 +3474,19 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(10, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(10, 0))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(10, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(90, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, Number(-900, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(10, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(90, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, Number(-900, 0))); } { testcase("Scale withdraw insignificant amount"); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(4, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(4, -2))}); env(tx, ter{tecPRECISION_LOSS}); } @@ -4035,22 +3510,13 @@ class Vault_test : public beast::unit_test::suite // closed (because a modification like above is not persistent), // which is why the checks below are expected to pass. auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(25, -1))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(25, -1))}); env(tx, ter{tecINSUFFICIENT_FUNDS}); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900 - 25)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(25, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(900 - 25, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(900 - 25, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900 - 25)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(25, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(900 - 25, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(900 - 25, 0))); } { @@ -4064,22 +3530,13 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(375, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(375, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(875 - 38)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(38, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(875 - 38, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(875 - 38, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(875 - 38)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(38, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(875 - 38, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(875 - 38, 0))); } { @@ -4093,22 +3550,13 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(372, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(372, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(837 - 37)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(37, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(837 - 37, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(837 - 37, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(837 - 37)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(37, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(837 - 37, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(837 - 37, 0))); } { @@ -4116,40 +3564,26 @@ class Vault_test : public beast::unit_test::suite auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(9, -2))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(9, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(800 - 1)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start + Number(1, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(800 - 1, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(800 - 1, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(800 - 1)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start + Number(1, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(800 - 1, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(800 - 1, 0))); } { testcase("Scale withdraw rest"); - auto const rest = - env.balance(d.vaultAccount, d.assets).number(); + auto const rest = env.balance(d.vaultAccount, d.assets).number(); - tx = d.vault.withdraw( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, rest)}); + tx = + d.vault.withdraw({.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, rest)}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares).number() == 0); } }); @@ -4157,10 +3591,7 @@ class Vault_test : public beast::unit_test::suite testcase("Scale clawback overflow"); { - auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = d.asset(5)}); + auto tx = d.vault.deposit({.depositor = d.depositor, .id = d.keylet.key, .amount = d.asset(5)}); env(tx); env.close(); } @@ -4180,21 +3611,13 @@ class Vault_test : public beast::unit_test::suite // initial setup: deposit 100 IOU, receive 1000 shares auto const start = env.balance(d.depositor, d.assets).number(); auto tx = d.vault.deposit( - {.depositor = d.depositor, - .id = d.keylet.key, - .amount = STAmount(d.asset, Number(100, 0))}); + {.depositor = d.depositor, .id = d.keylet.key, .amount = STAmount(d.asset, Number(100, 0))}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(1000)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start - Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(100, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(1000, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start - Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(100, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(1000, 0))); { testcase("Scale clawback exact"); // assetsToSharesWithdraw: @@ -4212,17 +3635,10 @@ class Vault_test : public beast::unit_test::suite .amount = STAmount(d.asset, Number(10, 0))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start)); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(90, 0))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(900, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start)); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(90, 0))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(900, 0))); } { @@ -4252,17 +3668,10 @@ class Vault_test : public beast::unit_test::suite .amount = STAmount(d.asset, Number(25, -1))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(900 - 25)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start)); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(900 - 25, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(900 - 25, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(900 - 25)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start)); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(900 - 25, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(900 - 25, 0))); } { @@ -4282,17 +3691,10 @@ class Vault_test : public beast::unit_test::suite .amount = STAmount(d.asset, Number(375, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(875 - 38)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start)); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(875 - 38, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(875 - 38, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(875 - 38)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start)); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(875 - 38, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(875 - 38, 0))); } { @@ -4312,17 +3714,10 @@ class Vault_test : public beast::unit_test::suite .amount = STAmount(d.asset, Number(372, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(837 - 37)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start)); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(837 - 37, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(837 - 37, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(837 - 37)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start)); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(837 - 37, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(837 - 37, 0))); } { @@ -4336,23 +3731,15 @@ class Vault_test : public beast::unit_test::suite .amount = STAmount(d.asset, Number(9, -2))}); env(tx); env.close(); - BEAST_EXPECT( - env.balance(d.depositor, d.shares) == d.share(800 - 1)); - BEAST_EXPECT( - env.balance(d.depositor, d.assets) == - STAmount(d.asset, start)); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets) == - STAmount(d.asset, Number(800 - 1, -1))); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares) == - STAmount(d.share, -Number(800 - 1, 0))); + BEAST_EXPECT(env.balance(d.depositor, d.shares) == d.share(800 - 1)); + BEAST_EXPECT(env.balance(d.depositor, d.assets) == STAmount(d.asset, start)); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets) == STAmount(d.asset, Number(800 - 1, -1))); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares) == STAmount(d.share, -Number(800 - 1, 0))); } { testcase("Scale clawback rest"); - auto const rest = - env.balance(d.vaultAccount, d.assets).number(); + auto const rest = env.balance(d.vaultAccount, d.assets).number(); d.peek([](SLE& vault, auto&) -> bool { vault[sfAssetsAvailable] = Number(5); return true; @@ -4363,17 +3750,12 @@ class Vault_test : public beast::unit_test::suite // * when the ledger is closed with unmodified AssetsAvailable // because a modification like above is not persistent. tx = d.vault.clawback( - {.issuer = d.issuer, - .id = d.keylet.key, - .holder = d.depositor, - .amount = STAmount(d.asset, rest)}); + {.issuer = d.issuer, .id = d.keylet.key, .holder = d.depositor, .amount = STAmount(d.asset, rest)}); env(tx); env.close(); BEAST_EXPECT(env.balance(d.depositor, d.shares).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.assets).number() == 0); - BEAST_EXPECT( - env.balance(d.vaultAccount, d.shares).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.assets).number() == 0); + BEAST_EXPECT(env.balance(d.vaultAccount, d.shares).number() == 0); } }); } @@ -4403,8 +3785,7 @@ class Vault_test : public beast::unit_test::suite // Set some fields { - auto tx1 = vault.deposit( - {.depositor = owner, .id = keylet.key, .amount = asset(50)}); + auto tx1 = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(50)}); env(tx1); auto tx2 = vault.set({.owner = owner, .id = keylet.key}); @@ -4420,29 +3801,19 @@ class Vault_test : public beast::unit_test::suite }(); auto const check = [&, keylet = keylet, sle = sleVault, this]( - Json::Value const& vault, - Json::Value const& issuance = Json::nullValue) { + Json::Value const& vault, Json::Value const& issuance = Json::nullValue) { BEAST_EXPECT(vault.isObject()); - constexpr auto checkString = - [](auto& node, SField const& field, std::string v) -> bool { - return node.isMember(field.fieldName) && - node[field.fieldName].isString() && - node[field.fieldName] == v; + constexpr auto checkString = [](auto& node, SField const& field, std::string v) -> bool { + return node.isMember(field.fieldName) && node[field.fieldName].isString() && node[field.fieldName] == v; }; - constexpr auto checkObject = - [](auto& node, SField const& field, Json::Value v) -> bool { - return node.isMember(field.fieldName) && - node[field.fieldName].isObject() && - node[field.fieldName] == v; + constexpr auto checkObject = [](auto& node, SField const& field, Json::Value v) -> bool { + return node.isMember(field.fieldName) && node[field.fieldName].isObject() && node[field.fieldName] == v; }; - constexpr auto checkInt = - [](auto& node, SField const& field, int v) -> bool { + constexpr auto checkInt = [](auto& node, SField const& field, int v) -> bool { return node.isMember(field.fieldName) && - ((node[field.fieldName].isInt() && - node[field.fieldName] == Json::Int(v)) || - (node[field.fieldName].isUInt() && - node[field.fieldName] == Json::UInt(v))); + ((node[field.fieldName].isInt() && node[field.fieldName] == Json::Int(v)) || + (node[field.fieldName].isUInt() && node[field.fieldName] == Json::UInt(v))); }; BEAST_EXPECT(vault["LedgerEntryType"].asString() == "Vault"); @@ -4450,36 +3821,26 @@ class Vault_test : public beast::unit_test::suite BEAST_EXPECT(checkInt(vault, sfFlags, 0)); // Ignore all other standard fields, this test doesn't care - BEAST_EXPECT( - checkString(vault, sfAccount, toBase58(sle->at(sfAccount)))); - BEAST_EXPECT( - checkObject(vault, sfAsset, to_json(sle->at(sfAsset)))); + BEAST_EXPECT(checkString(vault, sfAccount, toBase58(sle->at(sfAccount)))); + BEAST_EXPECT(checkObject(vault, sfAsset, to_json(sle->at(sfAsset)))); BEAST_EXPECT(checkString(vault, sfAssetsAvailable, "50")); BEAST_EXPECT(checkString(vault, sfAssetsMaximum, "1000")); BEAST_EXPECT(checkString(vault, sfAssetsTotal, "50")); - BEAST_EXPECT(checkString(vault, sfLossUnrealized, "0")); + BEAST_EXPECT(!vault.isMember(sfLossUnrealized.getJsonName())); auto const strShareID = strHex(sle->at(sfShareMPTID)); BEAST_EXPECT(checkString(vault, sfShareMPTID, strShareID)); BEAST_EXPECT(checkString(vault, sfOwner, toBase58(owner.id()))); BEAST_EXPECT(checkInt(vault, sfSequence, sequence)); - BEAST_EXPECT(checkInt( - vault, sfWithdrawalPolicy, vaultStrategyFirstComeFirstServe)); + BEAST_EXPECT(checkInt(vault, sfWithdrawalPolicy, vaultStrategyFirstComeFirstServe)); if (issuance.isObject()) { - BEAST_EXPECT( - issuance["LedgerEntryType"].asString() == - "MPTokenIssuance"); - BEAST_EXPECT( - issuance[jss::mpt_issuance_id].asString() == strShareID); + BEAST_EXPECT(issuance["LedgerEntryType"].asString() == "MPTokenIssuance"); + BEAST_EXPECT(issuance[jss::mpt_issuance_id].asString() == strShareID); BEAST_EXPECT(checkInt(issuance, sfSequence, 1)); - BEAST_EXPECT(checkInt( - issuance, - sfFlags, - int(lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer))); - BEAST_EXPECT( - checkString(issuance, sfOutstandingAmount, "50000000")); + BEAST_EXPECT(checkInt(issuance, sfFlags, int(lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer))); + BEAST_EXPECT(checkString(issuance, sfOutstandingAmount, "50000000")); } }; @@ -4514,8 +3875,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::vault] = to_string(uint256(42)); auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == "entryNotFound"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound"); } { @@ -4525,8 +3885,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = issuer.human(); jvParams[jss::vault][jss::seq] = 1'000'000; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == "entryNotFound"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound"); } { @@ -4535,9 +3894,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::vault] = 42; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedRequest"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4547,9 +3904,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = 42; jvParams[jss::vault][jss::seq] = sequence; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedOwner"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedOwner"); } { @@ -4559,9 +3914,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = issuer.human(); jvParams[jss::vault][jss::seq] = "foo"; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedRequest"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4571,9 +3924,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = issuer.human(); jvParams[jss::vault][jss::seq] = -1; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedRequest"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4583,9 +3934,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = issuer.human(); jvParams[jss::vault][jss::seq] = 1e20; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedRequest"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4595,9 +3944,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault][jss::owner] = issuer.human(); jvParams[jss::vault][jss::seq] = true; auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams)); - BEAST_EXPECT( - jvVault[jss::result][jss::error].asString() == - "malformedRequest"); + BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4606,8 +3953,7 @@ class Vault_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::account] = owner.human(); jvParams[jss::type] = jss::vault; - auto jv = env.rpc( - "json", "account_objects", to_string(jvParams))[jss::result]; + auto jv = env.rpc("json", "account_objects", to_string(jvParams))[jss::result]; BEAST_EXPECT(jv[jss::account_objects].size() == 1); check(jv[jss::account_objects][0u]); @@ -4620,22 +3966,18 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::binary] = false; jvParams[jss::type] = jss::vault; - Json::Value jv = - env.rpc("json", "ledger_data", to_string(jvParams)); + Json::Value jv = env.rpc("json", "ledger_data", to_string(jvParams)); BEAST_EXPECT(jv[jss::result][jss::state].size() == 1); check(jv[jss::result][jss::state][0u]); } { testcase("RPC vault_info command line"); - Json::Value jv = - env.rpc("vault_info", strHex(keylet.key), "validated"); + Json::Value jv = env.rpc("vault_info", strHex(keylet.key), "validated"); BEAST_EXPECT(!jv[jss::result].isMember(jss::error)); BEAST_EXPECT(jv[jss::result].isMember(jss::vault)); - check( - jv[jss::result][jss::vault], - jv[jss::result][jss::vault][jss::shares]); + check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]); } { @@ -4647,9 +3989,7 @@ class Vault_test : public beast::unit_test::suite BEAST_EXPECT(!jv[jss::result].isMember(jss::error)); BEAST_EXPECT(jv[jss::result].isMember(jss::vault)); - check( - jv[jss::result][jss::vault], - jv[jss::result][jss::vault][jss::shares]); + check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]); } { @@ -4658,8 +3998,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::vault_id] = "foobar"; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4668,8 +4007,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::vault_id] = 0; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4682,9 +4020,7 @@ class Vault_test : public beast::unit_test::suite BEAST_EXPECT(!jv[jss::result].isMember(jss::error)); BEAST_EXPECT(jv[jss::result].isMember(jss::vault)); - check( - jv[jss::result][jss::vault], - jv[jss::result][jss::vault][jss::shares]); + check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]); } { @@ -4694,8 +4030,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = owner.human(); jvParams[jss::seq] = "foobar"; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4705,8 +4040,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = owner.human(); jvParams[jss::seq] = 0; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4716,8 +4050,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = owner.human(); jvParams[jss::seq] = -1; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4727,8 +4060,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = owner.human(); jvParams[jss::seq] = 1e20; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4738,8 +4070,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = owner.human(); jvParams[jss::seq] = true; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4749,8 +4080,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::owner] = "foobar"; jvParams[jss::seq] = sequence; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4759,8 +4089,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::owner] = owner.human(); auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4769,8 +4098,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::seq] = sequence; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4780,8 +4108,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault_id] = strHex(keylet.key); jvParams[jss::seq] = sequence; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4791,8 +4118,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::vault_id] = strHex(keylet.key); jvParams[jss::owner] = owner.human(); auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4805,8 +4131,7 @@ class Vault_test : public beast::unit_test::suite jvParams[jss::seq] = sequence; jvParams[jss::owner] = owner.human(); auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4814,8 +4139,7 @@ class Vault_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; auto jv = env.rpc("json", "vault_info", to_string(jvParams)); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { @@ -4827,23 +4151,19 @@ class Vault_test : public beast::unit_test::suite { testcase("RPC vault_info command line invalid index"); Json::Value jv = env.rpc("vault_info", "0", "validated"); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "malformedRequest"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "malformedRequest"); } { testcase("RPC vault_info command line invalid index"); - Json::Value jv = - env.rpc("vault_info", strHex(uint256(42)), "validated"); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "entryNotFound"); + Json::Value jv = env.rpc("vault_info", strHex(uint256(42)), "validated"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "entryNotFound"); } { testcase("RPC vault_info command line invalid ledger"); Json::Value jv = env.rpc("vault_info", strHex(keylet.key), "0"); - BEAST_EXPECT( - jv[jss::result][jss::error].asString() == "lgrNotFound"); + BEAST_EXPECT(jv[jss::result][jss::error].asString() == "lgrNotFound"); } } @@ -4862,9 +4182,7 @@ class Vault_test : public beast::unit_test::suite PrettyAsset asset = xrpIssue(); }; - auto const xrpBalance = - [this]( - Env const& env, Account const& account) -> std::optional { + auto const xrpBalance = [this](Env const& env, Account const& account) -> std::optional { auto sle = env.le(keylet::account(account.id())); if (BEAST_EXPECT(sle != nullptr)) return sle->getFieldAmount(sfBalance).xrp().drops(); @@ -4921,24 +4239,17 @@ class Vault_test : public beast::unit_test::suite if (!BEAST_EXPECT(startBalance.has_value())) return; - tx = vault.deposit( - {.depositor = carol, - .id = keylet.key, - .amount = asset(amount)}); + tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)}); env(tx, delegate::as(alice)); env.close(); BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount); - tx = vault.withdraw( - {.depositor = carol, - .id = keylet.key, - .amount = asset(amount - 1)}); + tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(amount - 1)}); env(tx, delegate::as(alice)); env.close(); BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - 1); - tx = vault.withdraw( - {.depositor = carol, .id = keylet.key, .amount = asset(1)}); + tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(1)}); env(tx); env.close(); BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee); @@ -4957,27 +4268,17 @@ class Vault_test : public beast::unit_test::suite if (!BEAST_EXPECT(startBalance.has_value())) return; - tx = vault.deposit( - {.depositor = carol, - .id = keylet.key, - .amount = asset(amount)}); + tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)}); env(tx); env.close(); - BEAST_EXPECT( - xrpBalance(env, carol) == *startBalance - amount - baseFee); + BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount - baseFee); - tx = vault.withdraw( - {.depositor = carol, - .id = keylet.key, - .amount = asset(baseFee)}); + tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(baseFee)}); env(tx, delegate::as(alice)); env.close(); BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount); - tx = vault.withdraw( - {.depositor = carol, - .id = keylet.key, - .amount = asset(amount - baseFee)}); + tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(amount - baseFee)}); env(tx, delegate::as(alice)); env.close(); BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee); @@ -4988,6 +4289,707 @@ class Vault_test : public beast::unit_test::suite }); } + void + testVaultClawbackBurnShares() + { + using namespace test::jtx; + using namespace loanBroker; + using namespace loan; + Env env(*this, beast::severities::kWarning); + + auto const vaultAssetBalance = [&](Keylet const& vaultKeylet) { + auto const sleVault = env.le(vaultKeylet); + BEAST_EXPECT(sleVault != nullptr); + + return std::make_pair(sleVault->at(sfAssetsAvailable), sleVault->at(sfAssetsTotal)); + }; + + auto const vaultShareBalance = [&](Keylet const& vaultKeylet) { + auto const sleVault = env.le(vaultKeylet); + BEAST_EXPECT(sleVault != nullptr); + + auto const sleIssuance = env.le(keylet::mptIssuance(sleVault->at(sfShareMPTID))); + BEAST_EXPECT(sleIssuance != nullptr); + + return sleIssuance->at(sfOutstandingAmount); + }; + + auto const setupVault = + [&](PrettyAsset const& asset, Account const& owner, Account const& depositor) -> std::pair { + Vault vault{env}; + + auto const& [tx, vaultKeylet] = vault.create({.owner = owner, .asset = asset}); + env(tx, ter(tesSUCCESS), THISLINE); + env.close(); + + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + + Asset share = vaultSle->at(sfShareMPTID); + + env(vault.deposit({.depositor = depositor, .id = vaultKeylet.key, .amount = asset(100)}), + ter(tesSUCCESS), + THISLINE); + env.close(); + + auto const& [availablePreDefault, totalPreDefault] = vaultAssetBalance(vaultKeylet); + BEAST_EXPECT(availablePreDefault == totalPreDefault); + BEAST_EXPECT(availablePreDefault == asset(100).value()); + + // attempt to clawback shares while there are assets fails + env(vault.clawback( + {.issuer = owner, .id = vaultKeylet.key, .holder = depositor, .amount = share(0).value()}), + ter(tecNO_PERMISSION), + THISLINE); + env.close(); + + auto const& sharesAvailable = vaultShareBalance(vaultKeylet); + auto const& brokerKeylet = keylet::loanbroker(owner.id(), env.seq(owner)); + + env(set(owner, vaultKeylet.key), THISLINE); + env.close(); + + auto const& loanKeylet = keylet::loan(brokerKeylet.key, 1); + + // Create a simple Loan for the full amount of Vault assets + env(set(depositor, brokerKeylet.key, asset(100).value()), + loan::interestRate(TenthBips32(0)), + gracePeriod(60), + paymentInterval(120), + paymentTotal(10), + sig(sfCounterpartySignature, owner), + fee(env.current()->fees().base * 2), + ter(tesSUCCESS), + THISLINE); + env.close(); + + // attempt to clawback shares while there assetsAvailable == 0 and + // assetsTotal > 0 fails + env(vault.clawback( + {.issuer = owner, .id = vaultKeylet.key, .holder = depositor, .amount = share(0).value()}), + ter(tecNO_PERMISSION), + THISLINE); + env.close(); + + env.close(std::chrono::seconds{120 + 60}); + + env(manage(owner, loanKeylet.key, tfLoanDefault), ter(tesSUCCESS), THISLINE); + + auto const& [availablePostDefault, totalPostDefault] = vaultAssetBalance(vaultKeylet); + + BEAST_EXPECT(availablePostDefault == totalPostDefault); + BEAST_EXPECT(availablePostDefault == asset(0).value()); + BEAST_EXPECT(vaultShareBalance(vaultKeylet) == sharesAvailable); + + return std::make_pair(vault, vaultKeylet); + }; + + auto const testCase = + [&](PrettyAsset const& asset, std::string const& prefix, Account const& owner, Account const& depositor) { + { + testcase("VaultClawback (share) - " + prefix + " owner asset clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + .amount = asset(100).value(), + }), + // when asset is XRP or owner is not issuer clawback fail + // when owner is issuer precision loss occurs as vault is + // empty + asset.native() ? ter(temMALFORMED) + : asset.raw().getIssuer() != owner.id() ? ter(tecNO_PERMISSION) + : ter(tecPRECISION_LOSS), + THISLINE); + env.close(); + } + + { + testcase("VaultClawback (share) - " + prefix + " owner incomplete share clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor); + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + if (!vaultSle) + return; + Asset share = vaultSle->at(sfShareMPTID); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + .amount = share(1).value(), + }), + ter(tecLIMIT_EXCEEDED), + THISLINE); + env.close(); + } + + { + testcase("VaultClawback (share) - " + prefix + " owner implicit complete share clawback"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + }), + // when owner is issuer implicit clawback fails + asset.native() || asset.raw().getIssuer() != owner.id() ? ter(tesSUCCESS) : ter(tecWRONG_ASSET), + THISLINE); + env.close(); + } + + { + testcase("VaultClawback (share) - " + prefix + " owner explicit complete share clawback succeeds"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor); + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + if (!vaultSle) + return; + Asset share = vaultSle->at(sfShareMPTID); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + .amount = share(vaultShareBalance(vaultKeylet)).value(), + }), + ter(tesSUCCESS), + THISLINE); + env.close(); + } + { + testcase("VaultClawback (share) - " + prefix + " owner can clawback own shares"); + auto [vault, vaultKeylet] = setupVault(asset, owner, owner); + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + if (!vaultSle) + return; + Asset share = vaultSle->at(sfShareMPTID); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = owner, + .amount = share(vaultShareBalance(vaultKeylet)).value(), + }), + ter(tesSUCCESS), + THISLINE); + env.close(); + } + + { + testcase("VaultClawback (share) - " + prefix + " empty vault share clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, owner); + auto const& vaultSle = env.le(vaultKeylet); + if (BEAST_EXPECT(vaultSle != nullptr)) + return; + Asset share = vaultSle->at(sfShareMPTID); + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = owner, + .amount = share(vaultShareBalance(vaultKeylet)).value(), + }), + ter(tesSUCCESS), + THISLINE); + + // Now the vault is empty, clawback again fails + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = owner, + }), + ter(tecNO_PERMISSION), + THISLINE); + env.close(); + } + }; + + Account owner{"alice"}; + Account depositor{"bob"}; + Account issuer{"issuer"}; + + env.fund(XRP(10000), issuer, owner, depositor); + env.close(); + + // Test XRP + PrettyAsset xrp = xrpIssue(); + testCase(xrp, "XRP", owner, depositor); + testCase(xrp, "XRP (depositor is owner)", owner, owner); + + // Test IOU + PrettyAsset IOU = issuer["IOU"]; + env(fset(issuer, asfAllowTrustLineClawback)); + env.close(); + + env.trust(IOU(1000), owner); + env.trust(IOU(1000), depositor); + env(pay(issuer, owner, IOU(100))); + env(pay(issuer, depositor, IOU(100))); + env.close(); + testCase(IOU, "IOU", owner, depositor); + testCase(IOU, "IOU (owner is issuer)", issuer, depositor); + + // Test MPT + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + PrettyAsset MPT = mptt.issuanceID(); + mptt.authorize({.account = owner}); + mptt.authorize({.account = depositor}); + env(pay(issuer, owner, MPT(1000))); + env(pay(issuer, depositor, MPT(1000))); + env.close(); + testCase(MPT, "MPT", owner, depositor); + testCase(MPT, "MPT (owner is issuer)", issuer, depositor); + } + + void + testVaultClawbackAssets() + { + using namespace test::jtx; + using namespace loanBroker; + using namespace loan; + Env env(*this); + + auto const setupVault = [&](PrettyAsset const& asset, + Account const& owner, + Account const& depositor, + Account const& issuer) -> std::pair { + Vault vault{env}; + + auto const& [tx, vaultKeylet] = vault.create({.owner = owner, .asset = asset}); + env(tx, ter(tesSUCCESS), THISLINE); + env.close(); + + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + env(vault.deposit({.depositor = depositor, .id = vaultKeylet.key, .amount = asset(100)}), + ter(tesSUCCESS), + THISLINE); + env.close(); + + return std::make_pair(vault, vaultKeylet); + }; + + auto const testCase = [&](PrettyAsset const& asset, + std::string const& prefix, + Account const& owner, + Account const& depositor, + Account const& issuer) { + if (asset.native()) + { + testcase("VaultClawback (asset) - " + prefix + " issuer XRP clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + // If the asset is XRP, clawback with amount fails as malformed + // when asset is specified. + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = issuer, + .amount = asset(1).value(), + }), + ter(temMALFORMED), + THISLINE); + // When asset is implicit, clawback fails as no permission. + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = issuer, + }), + ter(tecNO_PERMISSION), + THISLINE); + return; + } + + { + testcase("VaultClawback (asset) - " + prefix + " clawback for different asset fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + + Account issuer2{"issuer2"}; + PrettyAsset asset2 = issuer2["FOO"]; + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = depositor, + .amount = asset2(1).value(), + }), + ter(tecWRONG_ASSET), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " ambiguous owner/issuer asset clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, issuer, depositor, issuer); + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = issuer, + }), + ter(tecWRONG_ASSET), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " non-issuer asset clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + }), + ter(tecNO_PERMISSION), + THISLINE); + + env(vault.clawback({ + .issuer = owner, + .id = vaultKeylet.key, + .holder = depositor, + .amount = asset(1).value(), + }), + ter(tecNO_PERMISSION), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " issuer clawback from self fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, issuer, issuer); + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = issuer, + }), + ter(tecNO_PERMISSION), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " issuer share clawback fails"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + auto const& vaultSle = env.le(vaultKeylet); + BEAST_EXPECT(vaultSle != nullptr); + if (!vaultSle) + return; + Asset share = vaultSle->at(sfShareMPTID); + + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = depositor, + .amount = share(1).value(), + }), + ter(tecNO_PERMISSION), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " partial issuer asset clawback succeeds"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = depositor, + .amount = asset(1).value(), + }), + ter(tesSUCCESS), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " full issuer asset clawback succeeds"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = depositor, + .amount = asset(100).value(), + }), + ter(tesSUCCESS), + THISLINE); + } + + { + testcase("VaultClawback (asset) - " + prefix + " implicit full issuer asset clawback succeeds"); + auto [vault, vaultKeylet] = setupVault(asset, owner, depositor, issuer); + + env(vault.clawback({ + .issuer = issuer, + .id = vaultKeylet.key, + .holder = depositor, + }), + ter(tesSUCCESS), + THISLINE); + } + }; + + Account owner{"alice"}; + Account depositor{"bob"}; + Account issuer{"issuer"}; + + env.fund(XRP(10000), issuer, owner, depositor); + env.close(); + + // Test XRP + PrettyAsset xrp = xrpIssue(); + testCase(xrp, "XRP", owner, depositor, issuer); + + // Test IOU + PrettyAsset IOU = issuer["IOU"]; + env(fset(issuer, asfAllowTrustLineClawback)); + env.close(); + env.trust(IOU(1000), owner); + env.trust(IOU(1000), depositor); + env(pay(issuer, owner, IOU(1000))); + env(pay(issuer, depositor, IOU(1000))); + env.close(); + testCase(IOU, "IOU", owner, depositor, issuer); + + // Test MPT + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + PrettyAsset MPT = mptt.issuanceID(); + mptt.authorize({.account = owner}); + mptt.authorize({.account = depositor}); + env(pay(issuer, depositor, MPT(1000))); + env.close(); + testCase(MPT, "MPT", owner, depositor, issuer); + } + + void + testAssetsMaximum() + { + testcase("Assets Maximum"); + + using namespace test::jtx; + + Env env{*this, testable_amendments() | featureSingleAssetVault}; + Account const owner{"owner"}; + Account const issuer{"issuer"}; + + Vault vault{env}; + env.fund(XRP(1'000'000), issuer, owner); + env.close(); + + auto const maxInt64 = std::to_string(std::numeric_limits::max()); + BEAST_EXPECT(maxInt64 == "9223372036854775807"); + + // Naming things is hard + auto const maxInt64Plus1 = + std::to_string(static_cast(std::numeric_limits::max()) + 1); + BEAST_EXPECT(maxInt64Plus1 == "9223372036854775808"); + + auto const initialXRP = to_string(INITIAL_XRP); + BEAST_EXPECT(initialXRP == "100000000000000000"); + + auto const initialXRPPlus1 = to_string(INITIAL_XRP + 1); + BEAST_EXPECT(initialXRPPlus1 == "100000000000000001"); + + { + testcase("Assets Maximum: XRP"); + + PrettyAsset const xrpAsset = xrpIssue(); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpAsset}); + tx[sfData] = "4D65746144617461"; + + tx[sfAssetsMaximum] = maxInt64; + env(tx, ter(tefEXCEPTION), THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRPPlus1; + env(tx, ter(tefEXCEPTION), THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRP; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = maxInt64Plus1; + env(tx, ter(tefEXCEPTION), THISLINE); + env.close(); + + // This value will be rounded + auto const insertAt = maxInt64Plus1.size() - 3; + auto const decimalTest = + maxInt64Plus1.substr(0, insertAt) + "." + maxInt64Plus1.substr(insertAt); // (max int64+1) / 1000 + BEAST_EXPECT(decimalTest == "9223372036854775.808"); + tx[sfAssetsMaximum] = decimalTest; + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT(vaultSle->at(sfAssetsMaximum) == 9223372036854776); + } + + { + testcase("Assets Maximum: MPT"); + + PrettyAsset const mptAsset = [&]() { + MPTTester mptt{env, issuer, mptInitNoFund}; + mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); + env.close(); + PrettyAsset const mptAsset = mptt["MPT"]; + mptt.authorize({.account = owner}); + env.close(); + return mptAsset; + }(); + + env(pay(issuer, owner, mptAsset(100'000)), THISLINE); + env.close(); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = mptAsset}); + tx[sfData] = "4D65746144617461"; + + tx[sfAssetsMaximum] = maxInt64; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRPPlus1; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRP; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = maxInt64Plus1; + env(tx, ter(tefEXCEPTION), THISLINE); + env.close(); + + // This value will be rounded + auto const insertAt = maxInt64Plus1.size() - 1; + auto const decimalTest = + maxInt64Plus1.substr(0, insertAt) + "." + maxInt64Plus1.substr(insertAt); // (max int64+1) / 10 + BEAST_EXPECT(decimalTest == "922337203685477580.8"); + tx[sfAssetsMaximum] = decimalTest; + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT(vaultSle->at(sfAssetsMaximum) == 922337203685477581); + } + + { + testcase("Assets Maximum: IOU"); + + // Almost anything goes with IOUs + PrettyAsset iouAsset = issuer["IOU"]; + env.trust(iouAsset(1000), owner); + env(pay(issuer, owner, iouAsset(200))); + env.close(); + + auto [tx, keylet] = vault.create({.owner = owner, .asset = iouAsset}); + tx[sfData] = "4D65746144617461"; + + tx[sfAssetsMaximum] = maxInt64; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRPPlus1; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = initialXRP; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = maxInt64Plus1; + env(tx, THISLINE); + env.close(); + + tx[sfAssetsMaximum] = "1000000000000000e80"; + env.close(); + + tx[sfAssetsMaximum] = "1000000000000000e-96"; + env.close(); + + // These values will be rounded to 15 significant digits + { + auto const insertAt = maxInt64Plus1.size() - 1; + auto const decimalTest = + maxInt64Plus1.substr(0, insertAt) + "." + maxInt64Plus1.substr(insertAt); // (max int64+1) / 10 + BEAST_EXPECT(decimalTest == "922337203685477580.8"); + tx[sfAssetsMaximum] = decimalTest; + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT((vaultSle->at(sfAssetsMaximum) == Number{9223372036854776, 2, Number::normalized{}})); + } + { + tx[sfAssetsMaximum] = "9223372036854775807e40"; // max int64 * 10^40 + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT((vaultSle->at(sfAssetsMaximum) == Number{9223372036854776, 43, Number::normalized{}})); + } + { + tx[sfAssetsMaximum] = "9223372036854775807e-40"; // max int64 * 10^-40 + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT((vaultSle->at(sfAssetsMaximum) == Number{9223372036854776, -37, Number::normalized{}})); + } + { + tx[sfAssetsMaximum] = "9223372036854775807e-100"; // max int64 * 10^-100 + auto const newKeylet = keylet::vault(owner.id(), env.seq(owner)); + env(tx, THISLINE); + env.close(); + + // Field 'AssetsMaximum' may not be explicitly set to default. + auto const vaultSle = env.le(newKeylet); + if (!BEAST_EXPECT(vaultSle)) + return; + + BEAST_EXPECT(vaultSle->at(sfAssetsMaximum) == numZero); + } + + // What _can't_ IOUs do? + // 1. Exceed maximum exponent / offset + tx[sfAssetsMaximum] = "1000000000000000e81"; + env(tx, ter(tefEXCEPTION), THISLINE); + env.close(); + + // 2. Mantissa larger than uint64 max + try + { + tx[sfAssetsMaximum] = "18446744073709551617e5"; // uint64 max + 1 + env(tx, THISLINE); + BEAST_EXPECT(false); + } + catch (parse_error const& e) + { + using namespace std::string_literals; + BEAST_EXPECT( + e.what() == + "invalidParamsField 'tx_json.AssetsMaximum' has invalid " + "data."s); + } + } + } + public: void run() override @@ -5006,9 +5008,12 @@ public: testScaleIOU(); testRPC(); testDelegate(); + testVaultClawbackBurnShares(); + testVaultClawbackAssets(); + testAssetsMaximum(); } }; -BEAST_DEFINE_TESTSUITE_PRIO(Vault, app, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(Vault, app, xrpl, 1); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/app/XChain_test.cpp b/src/test/app/XChain_test.cpp index 311ddda59b..2921e10ae4 100644 --- a/src/test/app/XChain_test.cpp +++ b/src/test/app/XChain_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -42,7 +23,7 @@ #include #include -namespace ripple::test { +namespace xrpl::test { // SEnv class - encapsulate jtx::Env to make it more user-friendly, // for example having APIs that return a *this reference so that calls can be @@ -151,8 +132,7 @@ struct SEnv { STXChainBridge b(jvb); - auto tryGet = - [&](STXChainBridge::ChainType ct) -> std::shared_ptr { + auto tryGet = [&](STXChainBridge::ChainType ct) -> std::shared_ptr { if (auto r = env_.le(keylet::bridge(b, ct))) { if ((*r)[sfXChainBridge] == b) @@ -186,8 +166,7 @@ struct SEnv std::shared_ptr caClaimID(Json::Value const& jvb, std::uint64_t seq) { - return env_.le( - keylet::xChainCreateAccountClaimID(STXChainBridge(jvb), seq)); + return env_.le(keylet::xChainCreateAccountClaimID(STXChainBridge(jvb), seq)); } }; @@ -214,15 +193,7 @@ struct XEnv : public jtx::XChainBridgeObjects, public SEnv } else { - this->fund( - xrp_funds, - scDoor, - scAlice, - scBob, - scCarol, - scGw, - scAttester, - scReward); + this->fund(xrp_funds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); for (auto& ra : payees) this->fund(xrp_funds, ra); @@ -266,7 +237,7 @@ struct BalanceTransfer balance from_; balance to_; - balance payor_; // pays the rewards + balance payer_; // pays the rewards std::vector reward_accounts; // receives the reward XRPAmount txFees_; @@ -274,13 +245,13 @@ struct BalanceTransfer T& env, jtx::Account const& from_acct, jtx::Account const& to_acct, - jtx::Account const& payor, + jtx::Account const& payer, jtx::Account const* payees, size_t num_payees, bool withClaim) : from_(env, from_acct) , to_(env, to_acct) - , payor_(env, payor) + , payer_(env, payer) , reward_accounts([&]() { std::vector r; r.reserve(num_payees); @@ -296,17 +267,10 @@ struct BalanceTransfer T& env, jtx::Account const& from_acct, jtx::Account const& to_acct, - jtx::Account const& payor, + jtx::Account const& payer, std::vector const& payees, bool withClaim) - : BalanceTransfer( - env, - from_acct, - to_acct, - payor, - &payees[0], - payees.size(), - withClaim) + : BalanceTransfer(env, from_acct, to_acct, payer, &payees[0], payees.size(), withClaim) { } @@ -314,35 +278,27 @@ struct BalanceTransfer payees_received(STAmount const& reward) const { return std::all_of( - reward_accounts.begin(), - reward_accounts.end(), - [&](balance const& b) { return b.diff() == reward; }); + reward_accounts.begin(), reward_accounts.end(), [&](balance const& b) { return b.diff() == reward; }); } bool check_most_balances(STAmount const& amt, STAmount const& reward) { - return from_.diff() == -amt && to_.diff() == amt && - payees_received(reward); + return from_.diff() == -amt && to_.diff() == amt && payees_received(reward); } bool - has_happened( - STAmount const& amt, - STAmount const& reward, - bool check_payer = true) + has_happened(STAmount const& amt, STAmount const& reward, bool check_payer = true) { - auto reward_cost = - multiply(reward, STAmount(reward_accounts.size()), reward.issue()); - return check_most_balances(amt, reward) && - (!check_payer || payor_.diff() == -(reward_cost + txFees_)); + auto reward_cost = multiply(reward, STAmount(reward_accounts.size()), reward.issue()); + return check_most_balances(amt, reward) && (!check_payer || payer_.diff() == -(reward_cost + txFees_)); } bool has_not_happened() { return check_most_balances(STAmount(0), STAmount(0)) && - payor_.diff() <= txFees_; // could have paid fee for failed claim + payer_.diff() <= txFees_; // could have paid fee for failed claim } }; @@ -369,18 +325,13 @@ struct BridgeDef return {}; return minAccountCreate; }(); - mcEnv.tx(bridge_create(doorA, jvb, reward, optAccountCreate)) - .tx(jtx::signers(doorA, quorum, signers)) - .close(); + mcEnv.tx(bridge_create(doorA, jvb, reward, optAccountCreate)).tx(jtx::signers(doorA, quorum, signers)).close(); - scEnv.tx(bridge_create(doorB, jvb, reward, optAccountCreate)) - .tx(jtx::signers(doorB, quorum, signers)) - .close(); + scEnv.tx(bridge_create(doorB, jvb, reward, optAccountCreate)).tx(jtx::signers(doorB, quorum, signers)).close(); } }; -struct XChain_test : public beast::unit_test::suite, - public jtx::XChainBridgeObjects +struct XChain_test : public beast::unit_test::suite, public jtx::XChainBridgeObjects { XRPAmount reserve(std::uint32_t count) @@ -437,44 +388,31 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this).tx(create_bridge(mcDoor)).close(); // Bridge not owned by one of the door account. - XEnv(*this).tx( - create_bridge(mcBob), ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); + XEnv(*this).tx(create_bridge(mcBob), ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); // Create twice on the same account - XEnv(*this) - .tx(create_bridge(mcDoor)) - .close() - .tx(create_bridge(mcDoor), ter(tecDUPLICATE)); + XEnv(*this).tx(create_bridge(mcDoor)).close().tx(create_bridge(mcDoor), ter(tecDUPLICATE)); // Create USD bridge Alice -> Bob ... should succeed - XEnv(*this).tx( - create_bridge( - mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), - ter(tesSUCCESS)); + XEnv(*this).tx(create_bridge(mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), ter(tesSUCCESS)); // Create USD bridge, Alice is both the locking door and locking issue, // ... should fail. XEnv(*this).tx( - create_bridge( - mcAlice, bridge(mcAlice, mcAlice["USD"], mcBob, mcBob["USD"])), + create_bridge(mcAlice, bridge(mcAlice, mcAlice["USD"], mcBob, mcBob["USD"])), ter(temXCHAIN_BRIDGE_BAD_ISSUES)); // Bridge where the two door accounts are equal. XEnv(*this).tx( - create_bridge( - mcBob, bridge(mcBob, mcGw["USD"], mcBob, mcGw["USD"])), - ter(temXCHAIN_EQUAL_DOOR_ACCOUNTS)); + create_bridge(mcBob, bridge(mcBob, mcGw["USD"], mcBob, mcGw["USD"])), ter(temXCHAIN_EQUAL_DOOR_ACCOUNTS)); // Both door accounts are on the same chain. This is not allowed. // Although it doesn't violate any invariants, it's not a useful thing // to do and it complicates the "add claim" transactions. XEnv(*this) - .tx(create_bridge( - mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]))) + .tx(create_bridge(mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]))) .close() - .tx(create_bridge( - mcBob, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), - ter(tecDUPLICATE)) + .tx(create_bridge(mcBob, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), ter(tecDUPLICATE)) .close(); // Create a bridge on an account with exactly enough balance to @@ -492,36 +430,27 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcuDoor, jvub), ter(tecINSUFFICIENT_RESERVE)); // Reward amount is non-xrp - XEnv(*this).tx( - create_bridge(mcDoor, jvb, mcUSD(1)), - ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); + XEnv(*this).tx(create_bridge(mcDoor, jvb, mcUSD(1)), ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); // Reward amount is XRP and negative - XEnv(*this).tx( - create_bridge(mcDoor, jvb, XRP(-1)), - ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); + XEnv(*this).tx(create_bridge(mcDoor, jvb, XRP(-1)), ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); // Reward amount is 1 xrp => should succeed XEnv(*this).tx(create_bridge(mcDoor, jvb, XRP(1)), ter(tesSUCCESS)); // Min create amount is 1 xrp, mincreate is 1 xrp => should succeed - XEnv(*this).tx( - create_bridge(mcDoor, jvb, XRP(1), XRP(1)), ter(tesSUCCESS)); + XEnv(*this).tx(create_bridge(mcDoor, jvb, XRP(1), XRP(1)), ter(tesSUCCESS)); // Min create amount is non-xrp XEnv(*this).tx( - create_bridge(mcDoor, jvb, XRP(1), mcUSD(100)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + create_bridge(mcDoor, jvb, XRP(1), mcUSD(100)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // Min create amount is zero (should fail, currently succeeds) - XEnv(*this).tx( - create_bridge(mcDoor, jvb, XRP(1), XRP(0)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + XEnv(*this).tx(create_bridge(mcDoor, jvb, XRP(1), XRP(0)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // Min create amount is negative XEnv(*this).tx( - create_bridge(mcDoor, jvb, XRP(1), XRP(-1)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + create_bridge(mcDoor, jvb, XRP(1), XRP(-1)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // coverage test: BridgeCreate::preflight() - create bridge when feature // disabled. @@ -532,20 +461,13 @@ struct XChain_test : public beast::unit_test::suite, // coverage test: BridgeCreate::preclaim() returns tecNO_ISSUER. XEnv(*this).tx( - create_bridge( - mcAlice, bridge(mcAlice, mcuAlice["USD"], mcBob, mcBob["USD"])), - ter(tecNO_ISSUER)); + create_bridge(mcAlice, bridge(mcAlice, mcuAlice["USD"], mcBob, mcBob["USD"])), ter(tecNO_ISSUER)); // coverage test: create_bridge transaction with incorrect flag - XEnv(*this).tx( - create_bridge(mcAlice, jvb), - txflags(tfFillOrKill), - ter(temINVALID_FLAG)); + XEnv(*this).tx(create_bridge(mcAlice, jvb), txflags(tfFillOrKill), ter(temINVALID_FLAG)); // coverage test: create_bridge transaction with xchain feature disabled - XEnv(*this) - .disableFeature(featureXChainBridge) - .tx(create_bridge(mcAlice, jvb), ter(temDISABLED)); + XEnv(*this).disableFeature(featureXChainBridge).tx(create_bridge(mcAlice, jvb), ter(temDISABLED)); } void @@ -611,7 +533,7 @@ struct XChain_test : public beast::unit_test::suite, auto CEUR = C["EUR"]; auto GEUR = scGw["EUR"]; - // Accounts to own single brdiges + // Accounts to own single bridges Account const a1("a1"); Account const a2("a2"); Account const a3("a3"); @@ -630,39 +552,28 @@ struct XChain_test : public beast::unit_test::suite, // Add the exact same bridge to two different accounts (one locking // account and one issuing) env.tx(create_bridge(a3, bridge(a3, GUSD, a4, a4["USD"]))).close(); - env.tx(create_bridge(a4, bridge(a3, GUSD, a4, a4["USD"])), - ter(tecDUPLICATE)) - .close(); + env.tx(create_bridge(a4, bridge(a3, GUSD, a4, a4["USD"])), ter(tecDUPLICATE)).close(); // Add the exact same bridge to two different accounts (one issuing // account and one locking - opposite order from the test above) env.tx(create_bridge(a5, bridge(a6, GUSD, a5, a5["USD"]))).close(); - env.tx(create_bridge(a6, bridge(a6, GUSD, a5, a5["USD"])), - ter(tecDUPLICATE)) - .close(); + env.tx(create_bridge(a6, bridge(a6, GUSD, a5, a5["USD"])), ter(tecDUPLICATE)).close(); // Test case 1 ~ 5, create bridges auto const goodBridge1 = bridge(A, GUSD, B, BUSD); auto const goodBridge2 = bridge(A, BUSD, C, CUSD); env.tx(create_bridge(B, goodBridge1)).close(); // Issuing asset is the same, this is a duplicate - env.tx(create_bridge(B, bridge(A, GEUR, B, BUSD)), ter(tecDUPLICATE)) - .close(); + env.tx(create_bridge(B, bridge(A, GEUR, B, BUSD)), ter(tecDUPLICATE)).close(); env.tx(create_bridge(A, goodBridge2), ter(tesSUCCESS)).close(); // Locking asset is the same - this is a duplicate - env.tx(create_bridge(A, bridge(A, BUSD, B, BEUR)), ter(tecDUPLICATE)) - .close(); + env.tx(create_bridge(A, bridge(A, BUSD, B, BEUR)), ter(tecDUPLICATE)).close(); // Locking asset is USD - this is a duplicate even tho it has a // different issuer - env.tx(create_bridge(A, bridge(A, CUSD, B, BEUR)), ter(tecDUPLICATE)) - .close(); + env.tx(create_bridge(A, bridge(A, CUSD, B, BEUR)), ter(tecDUPLICATE)).close(); // Test case 6 and 7, commits - env.tx(trust(C, BUSD(1000))) - .tx(trust(A, BUSD(1000))) - .close() - .tx(pay(B, C, BUSD(1000))) - .close(); + env.tx(trust(C, BUSD(1000))).tx(trust(A, BUSD(1000))).close().tx(pay(B, C, BUSD(1000))).close(); auto const aBalanceStart = env.balance(A, BUSD); auto const cBalanceStart = env.balance(C, BUSD); env.tx(xchain_commit(C, goodBridge1, 1, BUSD(50))).close(); @@ -872,14 +783,10 @@ struct XChain_test : public beast::unit_test::suite, auto const& expected = expected_result[test_result.size()]; - mcEnv.tx( - create_bridge(a, bridge(a, ia, b, ib)), - ter(TER::fromInt(expected.first))); + mcEnv.tx(create_bridge(a, bridge(a, ia, b, ib)), ter(TER::fromInt(expected.first))); TER mcTER = mcEnv.env_.ter(); - scEnv.tx( - create_bridge(b, bridge(a, ia, b, ib)), - ter(TER::fromInt(expected.second))); + scEnv.tx(create_bridge(b, bridge(a, ia, b, ib)), ter(TER::fromInt(expected.second))); TER scTER = scEnv.env_.ter(); bool pass = mcTER == tesSUCCESS && scTER == tesSUCCESS; @@ -888,8 +795,7 @@ struct XChain_test : public beast::unit_test::suite, }; auto apply_ics = [&](auto const& lc, auto const& ics) { - std::apply( - [&](auto const&... ic) { (testcase(lc, ic), ...); }, ics); + std::apply([&](auto const&... ic) { (testcase(lc, ic), ...); }, ics); }; std::apply([&](auto const&... lc) { (apply_ics(lc, ics), ...); }, lcs); @@ -902,8 +808,7 @@ struct XChain_test : public beast::unit_test::suite, std::cout << "Markdown output for matrix test: " << fname << "\n"; auto print_res = [](auto tup) -> std::string { - std::string status = std::string(transToken(std::get<0>(tup))) + - " / " + transToken(std::get<1>(tup)); + std::string status = std::string(transToken(std::get<0>(tup))) + " / " + transToken(std::get<1>(tup)); if (std::get<2>(tup)) return status; @@ -921,19 +826,11 @@ struct XChain_test : public beast::unit_test::suite, // first two header lines res += "| `issuing ->` | "; - std::apply( - [&](auto const&... ic) { - ((res += ic.first, res += " | "), ...); - }, - ics); + std::apply([&](auto const&... ic) { ((res += ic.first, res += " | "), ...); }, ics); res += "\n"; res += "| :--- | "; - std::apply( - [&](auto const&... ic) { - (((void)ic.first, res += ":---: | "), ...); - }, - ics); + std::apply([&](auto const&... ic) { (((void)ic.first, res += ":---: | "), ...); }, ics); res += "\n"; auto output = [&](auto const& lc, auto const& ic) { @@ -946,13 +843,11 @@ struct XChain_test : public beast::unit_test::suite, res += "| "; res += lc.first; res += " | "; - std::apply( - [&](auto const&... ic) { (output(lc, ic), ...); }, ics); + std::apply([&](auto const&... ic) { (output(lc, ic), ...); }, ics); res += "\n"; }; - std::apply( - [&](auto const&... lc) { (output_ics(lc, ics), ...); }, lcs); + std::apply([&](auto const&... lc) { (output_ics(lc, ics), ...); }, lcs); return res; }; @@ -965,8 +860,8 @@ struct XChain_test : public beast::unit_test::suite, std::ofstream ofs(ter_fname); for (auto& t : test_result) { - ofs << "{ " << std::string(transToken(std::get<0>(t))) << ", " - << std::string(transToken(std::get<1>(t))) << "}\n,"; + ofs << "{ " << std::string(transToken(std::get<0>(t))) << ", " << std::string(transToken(std::get<1>(t))) + << "}\n,"; } #endif } @@ -979,11 +874,7 @@ struct XChain_test : public beast::unit_test::suite, // Changing a non-existent bridge should fail XEnv(*this).tx( - bridge_modify( - mcAlice, - bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]), - XRP(2), - std::nullopt), + bridge_modify(mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]), XRP(2), std::nullopt), ter(tecNO_ENTRY)); // must change something @@ -999,29 +890,21 @@ struct XChain_test : public beast::unit_test::suite, .tx(bridge_modify(mcDoor, jvb, {}, {}), ter(temMALFORMED)); // Reward amount is non-xrp - XEnv(*this).tx( - bridge_modify(mcDoor, jvb, mcUSD(2), XRP(10)), - ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); + XEnv(*this).tx(bridge_modify(mcDoor, jvb, mcUSD(2), XRP(10)), ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); // Reward amount is XRP and negative - XEnv(*this).tx( - bridge_modify(mcDoor, jvb, XRP(-2), XRP(10)), - ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); + XEnv(*this).tx(bridge_modify(mcDoor, jvb, XRP(-2), XRP(10)), ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); // Min create amount is non-xrp XEnv(*this).tx( - bridge_modify(mcDoor, jvb, XRP(2), mcUSD(10)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + bridge_modify(mcDoor, jvb, XRP(2), mcUSD(10)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // Min create amount is zero - XEnv(*this).tx( - bridge_modify(mcDoor, jvb, XRP(2), XRP(0)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + XEnv(*this).tx(bridge_modify(mcDoor, jvb, XRP(2), XRP(0)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // Min create amount is negative XEnv(*this).tx( - bridge_modify(mcDoor, jvb, XRP(2), XRP(-10)), - ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); + bridge_modify(mcDoor, jvb, XRP(2), XRP(-10)), ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); // First check the regular claim process (without bridge_modify) for (auto withClaim : {false, true}) @@ -1043,25 +926,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) @@ -1069,8 +936,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum)); @@ -1099,29 +965,12 @@ struct XChain_test : public beast::unit_test::suite, // Now modify the reward on the bridge mcEnv.tx(bridge_modify(mcDoor, jvb, XRP(2), XRP(10))).close(); - scEnv.tx(bridge_modify(Account::master, jvb, XRP(2), XRP(10))) - .close(); + scEnv.tx(bridge_modify(Account::master, jvb, XRP(2), XRP(10))).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) @@ -1129,8 +978,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } // make sure the reward accounts indeed received the original @@ -1162,40 +1010,21 @@ struct XChain_test : public beast::unit_test::suite, // change signers - claim should not be processed is the batch // is signed by original signers - scEnv.tx(jtx::signers(Account::master, quorum, alt_signers)) - .close(); + scEnv.tx(jtx::signers(Account::master, quorum, alt_signers)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); // submit claim using outdated signers - should fail scEnv .multiTx( - claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers), + claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers), ter(tecNO_PERMISSION)) .close(); if (withClaim) { // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } // make sure transfer has not happened as we sent attestations @@ -1203,40 +1032,26 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // submit claim using current signers - should succeed - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - alt_signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, alt_signers)) .close(); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } // make sure the transfer went through as we sent attestations // using new signers - BEAST_EXPECT( - transfer.has_happened(amt, split_reward_quorum, false)); + BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum, false)); } // coverage test: bridge_modify transaction with incorrect flag XEnv(*this) .tx(create_bridge(mcDoor, jvb)) .close() - .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(2)), - txflags(tfFillOrKill), - ter(temINVALID_FLAG)); + .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(2)), txflags(tfFillOrKill), ter(temINVALID_FLAG)); // coverage test: bridge_modify transaction with xchain feature // disabled @@ -1250,8 +1065,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this) .tx(create_bridge(mcDoor, jvb)) .close() - .tx(bridge_modify(mcAlice, jvb, XRP(1), XRP(2)), - ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); + .tx(bridge_modify(mcAlice, jvb, XRP(1), XRP(2)), ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); /** * test tfClearAccountCreateAmount flag in BridgeModify tx @@ -1262,18 +1076,13 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this) .tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))) .close() - .tx(sidechain_xchain_account_create( - mcAlice, jvb, scuAlice, XRP(100), reward)) + .tx(sidechain_xchain_account_create(mcAlice, jvb, scuAlice, XRP(100), reward)) .close() - .tx(bridge_modify(mcDoor, jvb, {}, XRP(2)), - txflags(tfClearAccountCreateAmount), - ter(temMALFORMED)) + .tx(bridge_modify(mcDoor, jvb, {}, XRP(2)), txflags(tfClearAccountCreateAmount), ter(temMALFORMED)) .close() - .tx(bridge_modify(mcDoor, jvb, XRP(3), {}), - txflags(tfClearAccountCreateAmount)) + .tx(bridge_modify(mcDoor, jvb, XRP(3), {}), txflags(tfClearAccountCreateAmount)) .close() - .tx(sidechain_xchain_account_create( - mcAlice, jvb, scuBob, XRP(100), XRP(3)), + .tx(sidechain_xchain_account_create(mcAlice, jvb, scuBob, XRP(100), XRP(3)), ter(tecXCHAIN_CREATE_ACCOUNT_DISABLED)) .close(); } @@ -1311,11 +1120,7 @@ struct XChain_test : public beast::unit_test::suite, // Non-existent bridge XEnv(*this, true) - .tx(xchain_create_claim_id( - scAlice, - bridge(mcAlice, mcAlice["USD"], scBob, scBob["USD"]), - reward, - mcAlice), + .tx(xchain_create_claim_id(scAlice, bridge(mcAlice, mcAlice["USD"], scBob, scBob["USD"]), reward, mcAlice), ter(tecNO_ENTRY)) .close(); @@ -1324,8 +1129,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(Account::master, jvb)) .fund(res1 - xrp_dust, scuAlice) // barely not enough .close() - .tx(xchain_create_claim_id(scuAlice, jvb, reward, mcAlice), - ter(tecINSUFFICIENT_RESERVE)) + .tx(xchain_create_claim_id(scuAlice, jvb, reward, mcAlice), ter(tecINSUFFICIENT_RESERVE)) .close(); // The specified reward doesn't match the reward on the bridge (test @@ -1334,17 +1138,14 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this, true) .tx(create_bridge(Account::master, jvb)) .close() - .tx(xchain_create_claim_id( - scAlice, jvb, split_reward_quorum, mcAlice), - ter(tecXCHAIN_REWARD_MISMATCH)) + .tx(xchain_create_claim_id(scAlice, jvb, split_reward_quorum, mcAlice), ter(tecXCHAIN_REWARD_MISMATCH)) .close(); // A reward amount that isn't XRP XEnv(*this, true) .tx(create_bridge(Account::master, jvb)) .close() - .tx(xchain_create_claim_id(scAlice, jvb, mcUSD(1), mcAlice), - ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)) + .tx(xchain_create_claim_id(scAlice, jvb, mcUSD(1), mcAlice), ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)) .close(); // coverage test: xchain_create_claim_id transaction with incorrect @@ -1352,9 +1153,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this, true) .tx(create_bridge(Account::master, jvb)) .close() - .tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice), - txflags(tfFillOrKill), - ter(temINVALID_FLAG)) + .tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice), txflags(tfFillOrKill), ter(temINVALID_FLAG)) .close(); // coverage test: xchain_create_claim_id transaction with xchain @@ -1363,8 +1162,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(Account::master, jvb)) .disableFeature(featureXChainBridge) .close() - .tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice), - ter(temDISABLED)) + .tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice), ter(temDISABLED)) .close(); } @@ -1378,8 +1176,7 @@ struct XChain_test : public beast::unit_test::suite, testcase("Commit"); // Commit to a non-existent bridge - XEnv(*this).tx( - xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), ter(tecNO_ENTRY)); + XEnv(*this).tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), ter(tecNO_ENTRY)); // check that reward not deducted when doing the commit { @@ -1388,10 +1185,7 @@ struct XChain_test : public beast::unit_test::suite, Balance alice_bal(xenv, mcAlice); auto const amt = XRP(1000); - xenv.tx(create_bridge(mcDoor, jvb)) - .close() - .tx(xchain_commit(mcAlice, jvb, 1, amt, scBob)) - .close(); + xenv.tx(create_bridge(mcDoor, jvb)).close().tx(xchain_commit(mcAlice, jvb, 1, amt, scBob)).close(); STAmount claim_cost = amt; BEAST_EXPECT(alice_bal.diff() == -(claim_cost + tx_fee)); @@ -1401,8 +1195,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this) .tx(create_bridge(mcDoor, jvb)) .close() - .tx(xchain_commit(mcAlice, jvb, 1, XRP(-1), scBob), - ter(temBAD_AMOUNT)); + .tx(xchain_commit(mcAlice, jvb, 1, XRP(-1), scBob), ter(temBAD_AMOUNT)); // Commit an amount whose issue that does not match the expected // issue on the bridge (either LockingChainIssue or @@ -1410,8 +1203,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this) .tx(create_bridge(mcDoor, jvb)) .close() - .tx(xchain_commit(mcAlice, jvb, 1, mcUSD(100), scBob), - ter(temBAD_ISSUER)); + .tx(xchain_commit(mcAlice, jvb, 1, mcUSD(100), scBob), ter(temBAD_ISSUER)); // Commit an amount that would put the sender below the required // reserve (if XRP) @@ -1419,8 +1211,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor, jvb)) .fund(res0 + one_xrp - xrp_dust, mcuAlice) // barely not enough .close() - .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), - ter(tecUNFUNDED_PAYMENT)); + .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), ter(tecUNFUNDED_PAYMENT)); XEnv(*this) .tx(create_bridge(mcDoor, jvb)) @@ -1436,8 +1227,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor, jvb)) .fund(res0, mcuAlice) // barely not enough .close() - .tx(xchain_commit(mcuAlice, jvb, 1, res0 + one_xrp, scBob), - ter(tecUNFUNDED_PAYMENT)); + .tx(xchain_commit(mcuAlice, jvb, 1, res0 + one_xrp, scBob), ter(tecUNFUNDED_PAYMENT)); auto jvb_USD = bridge(mcDoor, mcUSD, scGw, scUSD); @@ -1453,16 +1243,14 @@ struct XChain_test : public beast::unit_test::suite, .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline .tx(create_bridge(mcDoor, jvb_USD)) .close() - .tx(xchain_commit(mcDoor, jvb_USD, 1, mcUSD(1), scBob), - ter(tecXCHAIN_SELF_COMMIT)); + .tx(xchain_commit(mcDoor, jvb_USD, 1, mcUSD(1), scBob), ter(tecXCHAIN_SELF_COMMIT)); // commit sent from mcAlice which has no IOU balance => should fail XEnv(*this) .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline .tx(create_bridge(mcDoor, jvb_USD)) .close() - .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scBob), - ter(terNO_LINE)); + .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scBob), ter(terNO_LINE)); // commit sent from mcAlice which has no IOU balance => should fail // just changed the destination to scGw (which is the door account @@ -1471,8 +1259,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline .tx(create_bridge(mcDoor, jvb_USD)) .close() - .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scGw), - ter(terNO_LINE)); + .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scGw), ter(terNO_LINE)); // commit sent from mcAlice which has a IOU balance => should // succeed @@ -1490,9 +1277,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this) .tx(create_bridge(mcDoor)) .close() - .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), - txflags(tfFillOrKill), - ter(temINVALID_FLAG)); + .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), txflags(tfFillOrKill), ter(temINVALID_FLAG)); // coverage test: xchain_commit transaction with xchain feature // disabled @@ -1500,8 +1285,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor)) .disableFeature(featureXChainBridge) .close() - .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), - ter(temDISABLED)); + .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob), ter(temDISABLED)); } void @@ -1513,9 +1297,7 @@ struct XChain_test : public beast::unit_test::suite, XRPAmount res0 = reserve(0); XRPAmount tx_fee = txFee(); - auto multiTtxFee = [&](std::uint32_t m) -> STAmount { - return multiply(tx_fee, STAmount(m), xrpIssue()); - }; + auto multiTtxFee = [&](std::uint32_t m) -> STAmount { return multiply(tx_fee, STAmount(m), xrpIssue()); }; // Add an attestation to a claim id that has already reached quorum. // This should succeed and share in the reward. @@ -1543,21 +1325,11 @@ struct XChain_test : public beast::unit_test::suite, auto const amt = XRP(1000); mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); scEnv .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers, - UT_XCHAIN_DEFAULT_QUORUM)) + scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, UT_XCHAIN_DEFAULT_QUORUM)) .close(); scEnv .tx(claim_attestation( @@ -1577,8 +1349,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted BEAST_EXPECT(scEnv.claimID(jvb) == claimID); } @@ -1628,27 +1399,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - 3, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[0], 3, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers_, - 3)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers_, 3)) .close(); if (withClaim) @@ -1656,14 +1409,12 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } BEAST_EXPECT(!scEnv.claimID(jvb, 1)); // claim id deleted - BEAST_EXPECT(transfer.has_happened( - amt, divide(reward, STAmount(3), reward.issue()))); + BEAST_EXPECT(transfer.has_happened(amt, divide(reward, STAmount(3), reward.issue()))); } // 4,4 => should succeed @@ -1687,8 +1438,7 @@ struct XChain_test : public beast::unit_test::suite, } return result; }(); - STAmount const split_reward_ = - divide(reward, STAmount(signers_.size()), reward.issue()); + STAmount const split_reward_ = divide(reward, STAmount(signers_.size()), reward.issue()); mcEnv.tx(create_bridge(mcDoor, jvb)).close(); @@ -1705,28 +1455,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[2], - 2, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[2], 2, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers_, - 2, - 2)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers_, 2, 2)) .close(); if (withClaim) @@ -1734,14 +1465,12 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted - BEAST_EXPECT(transfer.has_happened( - amt, divide(reward, STAmount(2), reward.issue()))); + BEAST_EXPECT(transfer.has_happened(amt, divide(reward, STAmount(2), reward.issue()))); } // 1,2 => should fail @@ -1781,41 +1510,19 @@ struct XChain_test : public beast::unit_test::suite, auto const amt = XRP(1000); mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - 2, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[0], 2, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers_, - 2)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers_, 2)) .close(); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } - BEAST_EXPECT( - !!scEnv.claimID(jvb, claimID)); // claim id still present + BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id still present BEAST_EXPECT(transfer.has_not_happened()); } @@ -1857,28 +1564,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[1], - 2, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[1], 2, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers_, - 2, - 1)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers_, 2, 1)) .close(); if (withClaim) @@ -1886,14 +1574,10 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } - BEAST_EXPECT( - !!scEnv.claimID(jvb, claimID)); // claim id still present + BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id still present BEAST_EXPECT(transfer.has_not_happened()); } @@ -1913,18 +1597,12 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20))) .close() - .tx(sidechain_xchain_account_create( - mcAlice, jvb, scuAlice, amt, reward)) - .tx(sidechain_xchain_account_create( - mcBob, jvb, scuBob, amt, reward)) - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuCarol, amt, reward)) + .tx(sidechain_xchain_account_create(mcAlice, jvb, scuAlice, amt, reward)) + .tx(sidechain_xchain_account_create(mcBob, jvb, scuBob, amt, reward)) + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuCarol, amt, reward)) .close(); - BEAST_EXPECT( - door.diff() == - (multiply(amt_plus_reward, STAmount(3), xrpIssue()) - - tx_fee)); + BEAST_EXPECT(door.diff() == (multiply(amt_plus_reward, STAmount(3), xrpIssue()) - tx_fee)); BEAST_EXPECT(carol.diff() == -(amt + reward + tx_fee)); } @@ -1947,11 +1625,10 @@ struct XChain_test : public beast::unit_test::suite, // att_create_acct_vec return vectors of size 2, so 2*3 txns BEAST_EXPECT(attester.diff() == -multiTtxFee(6)); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // ca claim id present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count still 0 + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // ca claim id present + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 } { @@ -1960,16 +1637,14 @@ struct XChain_test : public beast::unit_test::suite, Balance attester(scEnv, scAttester); Balance door(scEnv, Account::master); - scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 3, 2)) - .close(); + scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 3, 2)).close(); BEAST_EXPECT(door.diff() == STAmount(0)); // att_create_acct_vec return vectors of size 3, so 3 txns BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count still 0 + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 } { @@ -1978,16 +1653,14 @@ struct XChain_test : public beast::unit_test::suite, Balance attester(scEnv, scAttester); Balance door(scEnv, Account::master); - scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2)) - .close(); + scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2)).close(); BEAST_EXPECT(door.diff() == STAmount(0)); // att_create_acct_vec return vectors of size 3, so 3 txns BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count still 0 + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 } { @@ -1996,8 +1669,7 @@ struct XChain_test : public beast::unit_test::suite, Balance attester(scEnv, scAttester); Balance door(scEnv, Account::master); - scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 3, 1)) - .close(); + scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 3, 1)).close(); BEAST_EXPECT(door.diff() == -amt_plus_reward); // att_create_acct_vec return vectors of size 3, so 3 txns @@ -2016,17 +1688,15 @@ struct XChain_test : public beast::unit_test::suite, Balance attester(scEnv, scAttester); Balance door(scEnv, Account::master); - scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2)) - .close(); + scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2)).close(); BEAST_EXPECT(door.diff() == STAmount(0)); // att_create_acct_vec return vectors of size 3, so 3 txns BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 1); // claim count still 1 + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present + BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count still 1 } { @@ -2077,10 +1747,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); Balance carol(mcEnv, mcCarol); - mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, amt, reward)) - .close(); + mcEnv.tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, amt, reward)).close(); BEAST_EXPECT(door.diff() == amt_plus_reward); BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee)); @@ -2094,14 +1761,12 @@ struct XChain_test : public beast::unit_test::suite, Balance door(scEnv, Account::master); scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count is one less + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT( - scEnv.claimCount(jvb) == 1); // claim count was incremented + BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted + BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); BEAST_EXPECT(door.diff() == -reward); @@ -2123,10 +1788,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); Balance carol(mcEnv, mcCarol); - mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scAlice, amt, reward)) - .close(); + mcEnv.tx(sidechain_xchain_account_create(mcCarol, jvb, scAlice, amt, reward)).close(); BEAST_EXPECT(door.diff() == amt_plus_reward); BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee)); @@ -2141,14 +1803,12 @@ struct XChain_test : public beast::unit_test::suite, Balance alice(scEnv, scAlice); scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count is one less + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT( - scEnv.claimCount(jvb) == 1); // claim count was incremented + BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted + BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented BEAST_EXPECT(door.diff() == -amt_plus_reward); BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); @@ -2170,10 +1830,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); Balance carol(mcEnv, mcCarol); - mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scAlice, amt, reward)) - .close(); + mcEnv.tx(sidechain_xchain_account_create(mcCarol, jvb, scAlice, amt, reward)).close(); BEAST_EXPECT(door.diff() == amt_plus_reward); BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee)); @@ -2189,14 +1846,12 @@ struct XChain_test : public beast::unit_test::suite, Balance alice(scEnv, scAlice); scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count is one less + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT( - scEnv.claimCount(jvb) == 1); // claim count was incremented + BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted + BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented BEAST_EXPECT(door.diff() == -reward); BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); @@ -2220,20 +1875,14 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20))) .close() - .tx(sidechain_xchain_account_create( - mcAlice, jvb, scuAlice, amt, reward)) + .tx(sidechain_xchain_account_create(mcAlice, jvb, scuAlice, amt, reward)) .close() // make sure Alice gets claim #1 - .tx(sidechain_xchain_account_create( - mcBob, jvb, scuBob, amt, reward)) + .tx(sidechain_xchain_account_create(mcBob, jvb, scuBob, amt, reward)) .close() // make sure Bob gets claim #2 - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuCarol, amt, reward)) + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuCarol, amt, reward)) .close(); // and Carol will get claim #3 - BEAST_EXPECT( - door.diff() == - (multiply(amt_plus_reward, STAmount(3), xrpIssue()) - - tx_fee)); + BEAST_EXPECT(door.diff() == (multiply(amt_plus_reward, STAmount(3), xrpIssue()) - tx_fee)); BEAST_EXPECT(carol.diff() == -(amt + reward + tx_fee)); } @@ -2270,58 +1919,42 @@ struct XChain_test : public beast::unit_test::suite, .close(); txCount += 3; - BEAST_EXPECTS( - !!scEnv.caClaimID(jvb, 1), "claim id 1 still there"); - BEAST_EXPECTS( - !!scEnv.caClaimID(jvb, 2), "claim id 2 still there"); - BEAST_EXPECTS( - !!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); - BEAST_EXPECTS( - scEnv.claimCount(jvb) == 0, "No account created yet"); + BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 1), "claim id 1 still there"); + BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 2), "claim id 2 still there"); + BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); + BEAST_EXPECTS(scEnv.claimCount(jvb) == 0, "No account created yet"); - scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 1)) - .close(); + scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 1)).close(); txCount += 1; - BEAST_EXPECTS( - !!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); - BEAST_EXPECTS( - scEnv.claimCount(jvb) == 0, "No account created yet"); + BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); + BEAST_EXPECTS(scEnv.claimCount(jvb) == 0, "No account created yet"); - scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 1, 2)) - .close(); + scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 1, 2)).close(); txCount += 1; BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 deleted"); BEAST_EXPECTS(scEnv.claimCount(jvb) == 1, "scuAlice created"); scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 1, 3)) - .multiTx( - att_create_acct_vec(1, amt, scuAlice, 1, 3), - ter(tecXCHAIN_ACCOUNT_CREATE_PAST)) + .multiTx(att_create_acct_vec(1, amt, scuAlice, 1, 3), ter(tecXCHAIN_ACCOUNT_CREATE_PAST)) .close(); txCount += 2; BEAST_EXPECTS(!scEnv.caClaimID(jvb, 2), "claim id 2 deleted"); BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 not added"); - BEAST_EXPECTS( - scEnv.claimCount(jvb) == 2, "scuAlice & scuBob created"); + BEAST_EXPECTS(scEnv.claimCount(jvb) == 2, "scuAlice & scuBob created"); - scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 0)) - .close(); + scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 0)).close(); txCount += 1; BEAST_EXPECTS(!scEnv.caClaimID(jvb, 3), "claim id 3 deleted"); - BEAST_EXPECTS( - scEnv.claimCount(jvb) == 3, "All 3 accounts created"); + BEAST_EXPECTS(scEnv.claimCount(jvb) == 3, "All 3 accounts created"); // because of the division of the rewards among attesters, // sometimes a couple drops are left over unspent in the // door account (here 2 drops) - BEAST_EXPECT( - multiply(amt_plus_reward, STAmount(3), xrpIssue()) + - door.diff() < - drops(3)); + BEAST_EXPECT(multiply(amt_plus_reward, STAmount(3), xrpIssue()) + door.diff() < drops(3)); BEAST_EXPECT(attester.diff() == -multiTtxFee(txCount)); BEAST_EXPECT(scEnv.balance(scuAlice) == amt); BEAST_EXPECT(scEnv.balance(scuBob) == amt); @@ -2339,16 +1972,7 @@ struct XChain_test : public beast::unit_test::suite, scEnv.tx(create_bridge(Account::master, jvb)) .tx(jtx::signers(Account::master, quorum, signers)) .close() - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - XRP(1000), - payees[0], - true, - 1, - {}, - signers[0]), + .tx(claim_attestation(scAttester, jvb, mcAlice, XRP(1000), payees[0], true, 1, {}, signers[0]), txflags(tfFillOrKill), ter(temINVALID_FLAG)) .close(); @@ -2362,16 +1986,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(jtx::signers(Account::master, quorum, signers)) .disableFeature(featureXChainBridge) .close() - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - XRP(1000), - payees[0], - true, - 1, - {}, - signers[0]), + .tx(claim_attestation(scAttester, jvb, mcAlice, XRP(1000), payees[0], true, 1, {}, signers[0]), ter(temDISABLED)) .close(); } @@ -2407,19 +2022,10 @@ struct XChain_test : public beast::unit_test::suite, for (int i = 0; i < signers.size(); ++i) { - auto const att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[i], - true, - claimID, - dst, - signers[i]); + auto const att = + claim_attestation(scAttester, jvb, mcAlice, amt, payees[i], true, claimID, dst, signers[i]); - TER const expectedTER = - i < quorum ? tesSUCCESS : TER{tecXCHAIN_NO_CLAIM_ID}; + TER const expectedTER = i < quorum ? tesSUCCESS : TER{tecXCHAIN_NO_CLAIM_ID}; if (i + 1 == quorum) scEnv.tx(att, ter(expectedTER)).close(); else @@ -2428,8 +2034,7 @@ struct XChain_test : public beast::unit_test::suite, if (i + 1 < quorum) BEAST_EXPECT(dstStartBalance == scEnv.env_.balance(dst)); else - BEAST_EXPECT( - dstStartBalance + amt == scEnv.env_.balance(dst)); + BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst)); } BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst)); } @@ -2473,47 +2078,25 @@ struct XChain_test : public beast::unit_test::suite, { // G1: master key - auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - alt_signers[0]); + auto att = + claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, alt_signers[0]); scEnv.tx(att).close(); } { // G2: regular key // alt_signers[0] is the regular key of alt_signers[1] // There should be 2 attestations after the transaction - scEnv - .tx(jtx::regkey( - alt_signers[1].account, alt_signers[0].account)) - .close(); - auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[1], - true, - claimID, - dst, - alt_signers[0]); - att[sfAttestationSignerAccount.getJsonName()] = - alt_signers[1].account.human(); + scEnv.tx(jtx::regkey(alt_signers[1].account, alt_signers[0].account)).close(); + auto att = + claim_attestation(scAttester, jvb, mcAlice, amt, payees[1], true, claimID, dst, alt_signers[0]); + att[sfAttestationSignerAccount.getJsonName()] = alt_signers[1].account.human(); scEnv.tx(att).close(); } { // B3: public key and non-exist (unfunded) account mismatch // G3: public key and non-exist (unfunded) account match - auto const unfundedSigner1 = - alt_signers[UT_XCHAIN_DEFAULT_NUM_SIGNERS - 1]; - auto const unfundedSigner2 = - alt_signers[UT_XCHAIN_DEFAULT_NUM_SIGNERS - 2]; + auto const unfundedSigner1 = alt_signers[UT_XCHAIN_DEFAULT_NUM_SIGNERS - 1]; + auto const unfundedSigner2 = alt_signers[UT_XCHAIN_DEFAULT_NUM_SIGNERS - 2]; auto att = claim_attestation( scAttester, jvb, @@ -2524,83 +2107,41 @@ struct XChain_test : public beast::unit_test::suite, claimID, dst, unfundedSigner1); - att[sfAttestationSignerAccount.getJsonName()] = - unfundedSigner2.account.human(); - scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)) - .close(); - att[sfAttestationSignerAccount.getJsonName()] = - unfundedSigner1.account.human(); + att[sfAttestationSignerAccount.getJsonName()] = unfundedSigner2.account.human(); + scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); + att[sfAttestationSignerAccount.getJsonName()] = unfundedSigner1.account.human(); scEnv.tx(att).close(); } { // B2: single item signer list std::vector tempSignerList = {signers[0]}; - scEnv.tx( - jtx::signers(alt_signers[2].account, 1, tempSignerList)); + scEnv.tx(jtx::signers(alt_signers[2].account, 1, tempSignerList)); auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[2], - true, - claimID, - dst, - tempSignerList.front()); - att[sfAttestationSignerAccount.getJsonName()] = - alt_signers[2].account.human(); - scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)) - .close(); + scAttester, jvb, mcAlice, amt, payees[2], true, claimID, dst, tempSignerList.front()); + att[sfAttestationSignerAccount.getJsonName()] = alt_signers[2].account.human(); + scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); } { // B1: disabled master key - scEnv.tx(fset(alt_signers[2].account, asfDisableMaster, 0)) - .close(); - auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[2], - true, - claimID, - dst, - alt_signers[2]); - scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)) - .close(); + scEnv.tx(fset(alt_signers[2].account, asfDisableMaster, 0)).close(); + auto att = + claim_attestation(scAttester, jvb, mcAlice, amt, payees[2], true, claimID, dst, alt_signers[2]); + scEnv.tx(att, ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); } { // --B4: not on signer list - auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - signers[0]); + auto att = claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, signers[0]); scEnv.tx(att, ter(tecNO_PERMISSION)).close(); } { // --B5: missing sfAttestationSignerAccount field - // Then submit the one with the field. Should rearch quorum. - auto att = claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[3], - true, - claimID, - dst, - alt_signers[3]); + // Then submit the one with the field. Should reach quorum. + auto att = + claim_attestation(scAttester, jvb, mcAlice, amt, payees[3], true, claimID, dst, alt_signers[3]); att.removeMember(sfAttestationSignerAccount.getJsonName()); scEnv.tx(att, ter(temMALFORMED)).close(); BEAST_EXPECT(dstStartBalance == scEnv.env_.balance(dst)); - att[sfAttestationSignerAccount.getJsonName()] = - alt_signers[3].account.human(); + att[sfAttestationSignerAccount.getJsonName()] = alt_signers[3].account.human(); scEnv.tx(att).close(); BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst)); } @@ -2608,7 +2149,7 @@ struct XChain_test : public beast::unit_test::suite, } void - testXChainAddAccountCreateNonBatchAttestation() + testXChainAddAccountCreateNonBatchAttestation() // cspell: disable-line { using namespace jtx; @@ -2647,10 +2188,7 @@ struct XChain_test : public beast::unit_test::suite, Balance bal_doorA(mcEnv, doorA); Balance bal_a(mcEnv, a); - mcEnv - .tx(sidechain_xchain_account_create( - a, xrp_b.jvb, ua, amt, xrp_b.reward)) - .close(); + mcEnv.tx(sidechain_xchain_account_create(a, xrp_b.jvb, ua, amt, xrp_b.reward)).close(); BEAST_EXPECT(bal_doorA.diff() == amt_plus_reward); BEAST_EXPECT(bal_a.diff() == -(amt_plus_reward + tx_fee)); @@ -2659,19 +2197,8 @@ struct XChain_test : public beast::unit_test::suite, for (int i = 0; i < signers.size(); ++i) { auto const att = create_account_attestation( - signers[0].account, - xrp_b.jvb, - a, - amt, - xrp_b.reward, - signers[i].account, - true, - 1, - ua, - signers[i]); - TER const expectedTER = i < xrp_b.quorum - ? tesSUCCESS - : TER{tecXCHAIN_ACCOUNT_CREATE_PAST}; + signers[0].account, xrp_b.jvb, a, amt, xrp_b.reward, signers[i].account, true, 1, ua, signers[i]); + TER const expectedTER = i < xrp_b.quorum ? tesSUCCESS : TER{tecXCHAIN_ACCOUNT_CREATE_PAST}; scEnv.tx(att, ter(expectedTER)).close(); if (i + 1 < xrp_b.quorum) @@ -2715,33 +2242,16 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum)); @@ -2769,27 +2279,11 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - 1, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[0], 1, withClaim); jtx::signer master_signer(Account::master); scEnv - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - master_signer), + .tx(claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, master_signer), ter(tecXCHAIN_NO_SIGNERS_LIST)) .close(); @@ -2820,27 +2314,11 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - 1, - withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, &payees[0], 1, withClaim); jtx::signer master_signer(payees[0]); scEnv - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - master_signer), + .tx(claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, master_signer), ter(tecXCHAIN_NO_SIGNERS_LIST)) .close(); @@ -2856,38 +2334,22 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(create_bridge(mcDoor, jvb)).close(); - auto jvb_unknown = - bridge(mcBob, xrpIssue(), Account::master, xrpIssue()); + auto jvb_unknown = bridge(mcBob, xrpIssue(), Account::master, xrpIssue()); scEnv.tx(create_bridge(Account::master, jvb)) .tx(jtx::signers(Account::master, quorum, signers)) .close() - .tx(xchain_create_claim_id( - scAlice, jvb_unknown, reward, mcAlice), - ter(tecNO_ENTRY)) + .tx(xchain_create_claim_id(scAlice, jvb_unknown, reward, mcAlice), ter(tecNO_ENTRY)) .close(); auto dst(withClaim ? std::nullopt : std::optional{scBob}); auto const amt = XRP(1000); std::uint32_t const claimID = 1; - mcEnv - .tx(xchain_commit(mcAlice, jvb_unknown, claimID, amt, dst), - ter(tecNO_ENTRY)) - .close(); + mcEnv.tx(xchain_commit(mcAlice, jvb_unknown, claimID, amt, dst), ter(tecNO_ENTRY)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); scEnv - .tx(claim_attestation( - scAttester, - jvb_unknown, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - signers[0]), + .tx(claim_attestation(scAttester, jvb_unknown, mcAlice, amt, payees[0], true, claimID, dst, signers[0]), ter(tecNO_ENTRY)) .close(); @@ -2896,10 +2358,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb_unknown, claimID, amt, scBob), - ter(tecNO_ENTRY)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb_unknown, claimID, amt, scBob), ter(tecNO_ENTRY)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -2925,21 +2384,11 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); // attest using non-existent claim id scEnv - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - 999, - dst, - signers[0]), + .tx(claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, 999, dst, signers[0]), ter(tecXCHAIN_NO_CLAIM_ID)) .close(); if (withClaim) @@ -2947,10 +2396,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // claim using non-existent claim id - scEnv - .tx(xchain_claim(scAlice, jvb, 999, amt, scBob), - ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, 999, amt, scBob), ter(tecXCHAIN_NO_CLAIM_ID)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -2977,25 +2423,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) { @@ -3003,10 +2433,7 @@ struct XChain_test : public beast::unit_test::suite, // submit a claim transaction with the wrong account (scGw // instead of scAlice) - scEnv - .tx(xchain_claim(scGw, jvb, claimID, amt, scBob), - ter(tecXCHAIN_BAD_CLAIM_ID)) - .close(); + scEnv.tx(xchain_claim(scGw, jvb, claimID, amt, scBob), ter(tecXCHAIN_BAD_CLAIM_ID)).close(); BEAST_EXPECT(transfer.has_not_happened()); } else @@ -3035,8 +2462,7 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); // don't send any attestations @@ -3045,10 +2471,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3075,32 +2498,18 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); auto tooFew = quorum - 1; scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers, - tooFew)) + .multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, tooFew)) .close(); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3126,21 +2535,11 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scAlice, payees, withClaim); scEnv .multiTx( - claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - 0, - dst, - signers), + claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, 0, dst, signers), ter(tecXCHAIN_NO_CLAIM_ID)) .close(); if (withClaim) @@ -3148,10 +2547,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, 0, amt, scBob), - ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, 0, amt, scBob), ter(tecXCHAIN_NO_CLAIM_ID)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3181,25 +2577,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) @@ -3207,10 +2587,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, scUSD(1000), scBob), - ter(temBAD_AMOUNT)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, scUSD(1000), scBob), ter(temBAD_AMOUNT)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3237,35 +2614,16 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scuBob), - ter(tecNO_DST)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scuBob), ter(tecNO_DST)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3295,48 +2653,20 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); if (withClaim) { - scEnv - .multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)) + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) .close(); BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecUNFUNDED_PAYMENT)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecUNFUNDED_PAYMENT)).close(); } else { - auto txns = claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers); + auto txns = claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i) { scEnv.tx(txns[i]).close(); @@ -3346,10 +2676,7 @@ struct XChain_test : public beast::unit_test::suite, // The attestation should succeed, because it adds an // attestation, but the claim should fail with insufficient // funds - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecUNFUNDED_PAYMENT)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecUNFUNDED_PAYMENT)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3371,8 +2698,7 @@ struct XChain_test : public beast::unit_test::suite, res0 + reward, scuAlice) // just not enough because of fees .close() - .tx(xchain_create_claim_id(scuAlice, jvb, reward, mcAlice), - ter(tecINSUFFICIENT_RESERVE)) + .tx(xchain_create_claim_id(scuAlice, jvb, reward, mcAlice), ter(tecINSUFFICIENT_RESERVE)) .close(); auto dst(withClaim ? std::nullopt : std::optional{scBob}); @@ -3380,20 +2706,10 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); - BalanceTransfer transfer( - scEnv, Account::master, scBob, scuAlice, payees, withClaim); + BalanceTransfer transfer(scEnv, Account::master, scBob, scuAlice, payees, withClaim); scEnv - .tx(claim_attestation( - scAttester, - jvb, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - signers[0]), + .tx(claim_attestation(scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, signers[0]), ter(tecXCHAIN_NO_CLAIM_ID)) .close(); if (withClaim) @@ -3401,10 +2717,7 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scuAlice, jvb, claimID, amt, scBob), - ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); + scEnv.tx(xchain_claim(scuAlice, jvb, claimID, amt, scBob), ter(tecXCHAIN_NO_CLAIM_ID)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3432,23 +2745,8 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); - auto txns = claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); + auto txns = claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i) { scEnv.tx(txns[i]).close(); @@ -3460,26 +2758,19 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecNO_PERMISSION)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecNO_PERMISSION)).close(); // the transfer failed, but check that we can still use the // claimID with a different account Balance scCarol_bal(scEnv, scCarol); - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol)).close(); BEAST_EXPECT(scCarol_bal.diff() == amt); } else { scEnv.tx(txns.back()).close(); - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecNO_PERMISSION)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecNO_PERMISSION)).close(); // A way would be to remove deposit auth and resubmit the // attestations (even though the witness servers won't do // it) @@ -3515,23 +2806,8 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); - auto txns = claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); + auto txns = claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i) { scEnv.tx(txns[i]).close(); @@ -3542,26 +2818,19 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecDST_TAG_NEEDED)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecDST_TAG_NEEDED)).close(); // the transfer failed, but check that we can still use the // claimID with a different account Balance scCarol_bal(scEnv, scCarol); - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol)).close(); BEAST_EXPECT(scCarol_bal.diff() == amt); } else { scEnv.tx(txns.back()).close(); - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), - ter(tecDST_TAG_NEEDED)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob), ter(tecDST_TAG_NEEDED)).close(); // A way would be to remove the destination tag requirement // and resubmit the attestations (even though the witness // servers won't do it) @@ -3602,16 +2871,7 @@ struct XChain_test : public beast::unit_test::suite, // should not occur because dest account has deposit auth set Balance scBob_bal(scEnv, scBob); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); BEAST_EXPECT(scBob_bal.diff() == STAmount(0)); // Check that check that we still can use the claimID to transfer @@ -3643,32 +2903,14 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // claim wrong amount - scEnv - .tx(xchain_claim(scAlice, jvb, claimID, one_xrp, scBob), - ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, one_xrp, scBob), ter(tecXCHAIN_CLAIM_NO_QUORUM)).close(); } BEAST_EXPECT(transfer.has_not_happened()); @@ -3696,24 +2938,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); Balance scAlice_bal(scEnv, scAlice); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); STAmount claim_cost = reward; @@ -3722,14 +2949,12 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); claim_cost += tx_fee; } BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum)); - BEAST_EXPECT( - scAlice_bal.diff() == -claim_cost); // because reward % 4 == 0 + BEAST_EXPECT(scAlice_bal.diff() == -claim_cost); // because reward % 4 == 0 } // Verify that if a reward is not evenly divisible among the reward @@ -3754,24 +2979,9 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM, - withClaim); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM, withClaim); Balance scAlice_bal(scEnv, scAlice); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); STAmount claim_cost = tiny_reward; if (withClaim) @@ -3779,14 +2989,12 @@ struct XChain_test : public beast::unit_test::suite, BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); claim_cost += tx_fee; } BEAST_EXPECT(transfer.has_happened(amt, tiny_reward_split)); - BEAST_EXPECT( - scAlice_bal.diff() == -(claim_cost - tiny_reward_remainder)); + BEAST_EXPECT(scAlice_bal.diff() == -(claim_cost - tiny_reward_remainder)); } // If a reward distribution fails for one of the reward accounts @@ -3816,35 +3024,19 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close(); BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM - 1, - withClaim); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - alt_payees, - true, - claimID, - dst, - signers)); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM - 1, withClaim); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, alt_payees, true, claimID, dst, signers)); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } // this also checks that only 3 * split_reward was deducted from - // scAlice (the payor account), since we passed alt_payees to + // scAlice (the payer account), since we passed alt_payees to // BalanceTransfer BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum)); } @@ -3875,35 +3067,19 @@ struct XChain_test : public beast::unit_test::suite, // split_reward BalanceTransfer transfer( - scEnv, - Account::master, - scBob, - scAlice, - &payees[0], - UT_XCHAIN_DEFAULT_QUORUM - 1, - withClaim); - scEnv.multiTx(claim_attestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers)); + scEnv, Account::master, scBob, scAlice, &payees[0], UT_XCHAIN_DEFAULT_QUORUM - 1, withClaim); + scEnv.multiTx(claim_attestations(scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); if (withClaim) { BEAST_EXPECT(transfer.has_not_happened()); // need to submit a claim transactions - scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)) - .close(); + scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob)).close(); } // this also checks that only 3 * split_reward was deducted from - // scAlice (the payor account), since we passed payees.size() - + // scAlice (the payer account), since we passed payees.size() - // 1 to BalanceTransfer BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum)); @@ -3915,9 +3091,7 @@ struct XChain_test : public beast::unit_test::suite, XEnv(*this, true) .tx(create_bridge(Account::master, jvb)) .close() - .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob), - txflags(tfFillOrKill), - ter(temINVALID_FLAG)) + .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob), txflags(tfFillOrKill), ter(temINVALID_FLAG)) .close(); // coverage test: xchain_claim transaction with xchain feature @@ -3926,16 +3100,14 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(Account::master, jvb)) .disableFeature(featureXChainBridge) .close() - .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob), - ter(temDISABLED)) + .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob), ter(temDISABLED)) .close(); // coverage test: XChainClaim::preclaim - isLockingChain = true; XEnv(*this) .tx(create_bridge(mcDoor, jvb)) .close() - .tx(xchain_claim(mcAlice, jvb, 1, XRP(1000), mcBob), - ter(tecXCHAIN_NO_CLAIM_ID)); + .tx(xchain_claim(mcAlice, jvb, 1, XRP(1000), mcBob), ter(tecXCHAIN_NO_CLAIM_ID)); } void @@ -3953,27 +3125,21 @@ struct XChain_test : public beast::unit_test::suite, auto const amt = XRP(111); auto const amt_plus_reward = amt + reward; - scEnv.tx(create_bridge(Account::master, jvb)) - .tx(jtx::signers(Account::master, quorum, signers)) - .close(); + scEnv.tx(create_bridge(Account::master, jvb)).tx(jtx::signers(Account::master, quorum, signers)).close(); Balance door(scEnv, Account::master); // scEnv.tx(att_create_acct_batch1(1, amt, // Account::master)).close(); - scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2)) - .close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT( - scEnv.claimCount(jvb) == 0); // claim count is one less + scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2)).close(); + BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present + BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less // scEnv.tx(att_create_acct_batch2(1, amt, // Account::master)).close(); - scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2, 2)) - .close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT( - scEnv.claimCount(jvb) == 1); // claim count was incremented + scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2, 2)).close(); + BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted + BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented BEAST_EXPECT(door.diff() == -reward); } @@ -3989,8 +3155,7 @@ struct XChain_test : public beast::unit_test::suite, Balance carol(mcEnv, mcCarol); mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(19), reward), + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(19), reward), ter(tecXCHAIN_INSUFF_CREATE_AMOUNT)) .close(); @@ -4007,8 +3172,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(20), reward), + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(20), reward), txflags(tfFillOrKill), ter(temINVALID_FLAG)) .close(); @@ -4026,9 +3190,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); mcEnv.disableFeature(featureXChainBridge) - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(20), reward), - ter(temDISABLED)) + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(20), reward), ter(temDISABLED)) .close(); BEAST_EXPECT(door.diff() == STAmount(0)); @@ -4042,10 +3204,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); - mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(-20), reward), - ter(temBAD_AMOUNT)) + mcEnv.tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(-20), reward), ter(temBAD_AMOUNT)) .close(); BEAST_EXPECT(door.diff() == STAmount(0)); @@ -4059,10 +3218,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); - mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(20), XRP(-1)), - ter(temBAD_AMOUNT)) + mcEnv.tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(20), XRP(-1)), ter(temBAD_AMOUNT)) .close(); BEAST_EXPECT(door.diff() == STAmount(0)); @@ -4077,9 +3233,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); mcEnv - .tx(sidechain_xchain_account_create( - mcDoor, jvb, scuAlice, XRP(20), XRP(1)), - ter(tecXCHAIN_SELF_COMMIT)) + .tx(sidechain_xchain_account_create(mcDoor, jvb, scuAlice, XRP(20), XRP(1)), ter(tecXCHAIN_SELF_COMMIT)) .close(); BEAST_EXPECT(door.diff() == -tx_fee); @@ -4094,8 +3248,7 @@ struct XChain_test : public beast::unit_test::suite, Balance door(mcEnv, mcDoor); mcEnv - .tx(sidechain_xchain_account_create( - mcCarol, jvb, scuAlice, XRP(20), XRP(2)), + .tx(sidechain_xchain_account_create(mcCarol, jvb, scuAlice, XRP(20), XRP(2)), ter(tecXCHAIN_REWARD_MISMATCH)) .close(); @@ -4117,8 +3270,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor, jvb)) .fund(res0 + one_xrp + tx_fee - drops(1), mcuAlice) .close() - .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), - ter(tesSUCCESS)); + .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), ter(tesSUCCESS)); // commit where the commit amount drips into the reserve, this should // fail @@ -4126,8 +3278,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor, jvb)) .fund(res0 + one_xrp - drops(1), mcuAlice) .close() - .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), - ter(tecUNFUNDED_PAYMENT)); + .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob), ter(tecUNFUNDED_PAYMENT)); auto const minAccountCreate = XRP(20); @@ -4135,12 +3286,9 @@ struct XChain_test : public beast::unit_test::suite, // this should succeed XEnv(*this) .tx(create_bridge(mcDoor, jvb, reward, minAccountCreate)) - .fund( - res0 + tx_fee + minAccountCreate + reward - drops(1), mcuAlice) + .fund(res0 + tx_fee + minAccountCreate + reward - drops(1), mcuAlice) .close() - .tx(sidechain_xchain_account_create( - mcuAlice, jvb, scuAlice, minAccountCreate, reward), - ter(tesSUCCESS)); + .tx(sidechain_xchain_account_create(mcuAlice, jvb, scuAlice, minAccountCreate, reward), ter(tesSUCCESS)); // account create commit where the commit dips into the reserve, // this should fail @@ -4148,8 +3296,7 @@ struct XChain_test : public beast::unit_test::suite, .tx(create_bridge(mcDoor, jvb, reward, minAccountCreate)) .fund(res0 + minAccountCreate + reward - drops(1), mcuAlice) .close() - .tx(sidechain_xchain_account_create( - mcuAlice, jvb, scuAlice, minAccountCreate, reward), + .tx(sidechain_xchain_account_create(mcuAlice, jvb, scuAlice, minAccountCreate, reward), ter(tecUNFUNDED_PAYMENT)); } @@ -4160,8 +3307,7 @@ struct XChain_test : public beast::unit_test::suite, testcase("Bridge Delete Door Account"); - auto const acctDelFee{ - drops(XEnv(*this).env_.current()->fees().increment)}; + auto const acctDelFee{drops(XEnv(*this).env_.current()->fees().increment)}; // Deleting an account that owns bridge should fail { @@ -4175,10 +3321,7 @@ struct XChain_test : public beast::unit_test::suite, mcEnv.close(); // try to delete mcDoor, send funds to mcAlice - mcEnv.tx( - acctdelete(mcDoor, mcAlice), - fee(acctDelFee), - ter(tecHAS_OBLIGATIONS)); + mcEnv.tx(acctdelete(mcDoor, mcAlice), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); } // Deleting an account that owns a claim id should fail @@ -4196,10 +3339,7 @@ struct XChain_test : public beast::unit_test::suite, scEnv.close(); // try to delete scAlice, send funds to scBob - scEnv.tx( - acctdelete(scAlice, scBob), - fee(acctDelFee), - ter(tecHAS_OBLIGATIONS)); + scEnv.tx(acctdelete(scAlice, scBob), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); } } @@ -4215,11 +3355,8 @@ struct XChain_test : public beast::unit_test::suite, std::uint32_t const claimID = 1; std::optional dst{scBob}; auto const amt = XRP(1000); - scEnv.tx(create_bridge(Account::master, jvb)) - .tx(jtx::signers(Account::master, quorum, signers)) - .close(); - scEnv.tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice)) - .close(); + scEnv.tx(create_bridge(Account::master, jvb)).tx(jtx::signers(Account::master, quorum, signers)).close(); + scEnv.tx(xchain_create_claim_id(scAlice, jvb, reward, mcAlice)).close(); auto jvAtt = claim_attestation( scAttester, jvb, @@ -4246,9 +3383,7 @@ struct XChain_test : public beast::unit_test::suite, Account dst{scBob}; auto const amt = XRP(1000); auto const rewardAmt = XRP(1); - scEnv.tx(create_bridge(Account::master, jvb)) - .tx(jtx::signers(Account::master, quorum, signers)) - .close(); + scEnv.tx(create_bridge(Account::master, jvb)).tx(jtx::signers(Account::master, quorum, signers)).close(); auto jvAtt = create_account_attestation( scAttester, jvb, @@ -4282,7 +3417,7 @@ struct XChain_test : public beast::unit_test::suite, testXChainCommit(); testXChainAddAttestation(); testXChainAddClaimNonBatchAttestation(); - testXChainAddAccountCreateNonBatchAttestation(); + testXChainAddAccountCreateNonBatchAttestation(); // cspell: disable-line testXChainClaim(); testXChainCreateAccount(); testFeeDipsIntoReserve(); @@ -4293,8 +3428,7 @@ struct XChain_test : public beast::unit_test::suite, // ----------------------------------------------------------- // ----------------------------------------------------------- -struct XChainSim_test : public beast::unit_test::suite, - public jtx::XChainBridgeObjects +struct XChainSim_test : public beast::unit_test::suite, public jtx::XChainBridgeObjects { private: static constexpr size_t num_signers = 5; @@ -4357,8 +3491,7 @@ private: using CreateClaimVec = jtx::JValueVec; using CreateClaimMap = std::map; - ChainStateTrack(ENV& env) - : env(env), tx_fee(env.env_.current()->fees().base) + ChainStateTrack(ENV& env) : env(env), tx_fee(env.env_.current()->fees().base) { } @@ -4374,10 +3507,7 @@ private: } uint32_t - sendCreateAttestations( - size_t signer_idx, - BridgeID bridge, - CreateClaimVec& claims) + sendCreateAttestations(size_t signer_idx, BridgeID bridge, CreateClaimVec& claims) { size_t num_successful = 0; for (auto const& c : claims) @@ -4405,6 +3535,7 @@ private: do { callback_called = false; + // cspell: ignore attns for (size_t i = 0; i < signers_attns.size(); ++i) { for (auto& [bridge, claims] : signers_attns[i]) @@ -4412,13 +3543,11 @@ private: sendAttestations(i, bridge, claims.xfer_claims); auto& c = counters[bridge]; - auto& create_claims = - claims.create_claims[c.claim_count]; + auto& create_claims = claims.create_claims[c.claim_count]; auto num_attns = create_claims.size(); if (num_attns) { - c.num_create_attn_sent += sendCreateAttestations( - i, bridge, create_claims); + c.num_create_attn_sent += sendCreateAttestations(i, bridge, create_claims); } assert(claims.create_claims[c.claim_count].empty()); } @@ -4444,10 +3573,7 @@ private: } void - receive( - jtx::Account const& acct, - STAmount amt, - std::uint64_t divisor = 1) + receive(jtx::Account const& acct, STAmount amt, std::uint64_t divisor = 1) { if (amt.issue() != xrpIssue()) return; @@ -4460,11 +3586,7 @@ private: else { it->second.expectedDiff += - (divisor == 1 ? amt - : divide( - amt, - STAmount(amt.issue(), divisor), - amt.issue())); + (divisor == 1 ? amt : divide(amt, STAmount(amt.issue(), divisor), amt.issue())); } } @@ -4473,12 +3595,7 @@ private: { if (amt.issue() != xrpIssue()) return; - receive( - acct, - times == 1 - ? -amt - : -multiply( - amt, STAmount(amt.issue(), times), amt.issue())); + receive(acct, times == 1 ? -amt : -multiply(amt, STAmount(amt.issue(), times), amt.issue())); } void @@ -4505,14 +3622,12 @@ private: struct BridgeCounters { - using complete_cb = - std::function const& signers)>; + using complete_cb = std::function const& signers)>; uint32_t claim_id{0}; uint32_t create_count{0}; // for account create. First should be 1 - uint32_t claim_count{ - 0}; // for account create. Increments after quorum for - // current create_count (starts at 1) is reached. + uint32_t claim_count{0}; // for account create. Increments after quorum for + // current create_count (starts at 1) is reached. uint32_t num_create_attn_sent{0}; // for current claim_count std::vector signers; @@ -4567,7 +3682,7 @@ private: enum SmState { st_initial, - st_claimid_created, + st_claim_id_created, st_attesting, st_attested, st_completed, @@ -4581,9 +3696,7 @@ private: class SmBase { public: - SmBase( - std::shared_ptr const& chainstate, - BridgeDef const& bridge) + SmBase(std::shared_ptr const& chainstate, BridgeDef const& bridge) : bridge_(bridge), st_(chainstate) { } @@ -4627,9 +3740,7 @@ private: std::shared_ptr const& chainstate, BridgeDef const& bridge, AccountCreate create) - : Base(chainstate, bridge) - , sm_state(st_initial) - , cr(std::move(create)) + : Base(chainstate, bridge), sm_state(st_initial), cr(std::move(create)) { } @@ -4645,9 +3756,7 @@ private: ChainStateTrack& st = srcState(); jtx::Account const& srcdoor = srcDoor(); - st.env - .tx(sidechain_xchain_account_create( - cr.from, bridge_.jvb, cr.to, cr.amt, cr.reward)) + st.env.tx(sidechain_xchain_account_create(cr.from, bridge_.jvb, cr.to, cr.amt, cr.reward)) .close(); // needed for claim_id sequence to be correct' st.spendFee(cr.from); st.transfer(cr.from, srcdoor, cr.amt); @@ -4672,9 +3781,8 @@ private: // enqueue one attestation for this signer cr.attested[signer_idx] = true; - st.signers_attns[signer_idx][&bridge_] - .create_claims[cr.claim_id - 1] - .emplace_back(create_account_attestation( + st.signers_attns[signer_idx][&bridge_].create_claims[cr.claim_id - 1].emplace_back( + create_account_attestation( bridge_.signers[signer_idx].account, bridge_.jvb, cr.from, @@ -4699,9 +3807,7 @@ private: auto complete_cb = [&](std::vector const& signers) { auto num_attestors = signers.size(); st.env.close(); - assert( - num_attestors <= - std::count(cr.attested.begin(), cr.attested.end(), true)); + assert(num_attestors <= std::count(cr.attested.begin(), cr.attested.end(), true)); assert(num_attestors >= bridge_.quorum); assert(cr.claim_id - 1 == counters.claim_count); @@ -4755,13 +3861,8 @@ private: public: using Base = SmBase; - SmTransfer( - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - Transfer xfer) - : Base(chainstate, bridge) - , xfer(std::move(xfer)) - , sm_state(st_initial) + SmTransfer(std::shared_ptr const& chainstate, BridgeDef const& bridge, Transfer xfer) + : Base(chainstate, bridge), xfer(std::move(xfer)), sm_state(st_initial) { } @@ -4776,9 +3877,7 @@ private: { ChainStateTrack& st = destState(); - st.env - .tx(xchain_create_claim_id( - xfer.to, bridge_.jvb, bridge_.reward, xfer.from)) + st.env.tx(xchain_create_claim_id(xfer.to, bridge_.jvb, bridge_.reward, xfer.from)) .close(); // needed for claim_id sequence to be // correct' st.spendFee(xfer.to); @@ -4801,9 +3900,7 @@ private: bridge_.jvb, xfer.claim_id, xfer.amt, - xfer.with_claim == WithClaim::yes - ? std::nullopt - : std::optional(xfer.finaldest))); + xfer.with_claim == WithClaim::yes ? std::nullopt : std::optional(xfer.finaldest))); st.spendFee(xfer.from); st.transfer(xfer.from, srcdoor, xfer.amt); } @@ -4836,27 +3933,22 @@ private: // enqueue one attestation for this signer xfer.attested[signer_idx] = true; - st.signers_attns[signer_idx][&bridge_] - .xfer_claims.emplace_back(claim_attestation( - bridge_.signers[signer_idx].account, - bridge_.jvb, - xfer.from, - xfer.amt, - bridge_.signers[signer_idx].account, - xfer.a2b, - xfer.claim_id, - xfer.with_claim == WithClaim::yes - ? std::nullopt - : std::optional(xfer.finaldest), - bridge_.signers[signer_idx])); + st.signers_attns[signer_idx][&bridge_].xfer_claims.emplace_back(claim_attestation( + bridge_.signers[signer_idx].account, + bridge_.jvb, + xfer.from, + xfer.amt, + bridge_.signers[signer_idx].account, + xfer.a2b, + xfer.claim_id, + xfer.with_claim == WithClaim::yes ? std::nullopt : std::optional(xfer.finaldest), + bridge_.signers[signer_idx])); break; } } // return true if quorum was reached, false otherwise - bool quorum = - std::count(xfer.attested.begin(), xfer.attested.end(), true) >= - bridge_.quorum; + bool quorum = std::count(xfer.attested.begin(), xfer.attested.end(), true) >= bridge_.quorum; if (quorum && xfer.with_claim == WithClaim::no) { distribute_reward(st); @@ -4869,8 +3961,7 @@ private: claim() { ChainStateTrack& st = destState(); - st.env.tx(xchain_claim( - xfer.to, bridge_.jvb, xfer.claim_id, xfer.amt, xfer.finaldest)); + st.env.tx(xchain_claim(xfer.to, bridge_.jvb, xfer.claim_id, xfer.amt, xfer.finaldest)); distribute_reward(st); st.transfer(dstDoor(), xfer.finaldest, xfer.amt); st.spendFee(xfer.to); @@ -4883,19 +3974,17 @@ private: { case st_initial: xfer.claim_id = create_claim_id(); - sm_state = st_claimid_created; + sm_state = st_claim_id_created; break; - case st_claimid_created: + case st_claim_id_created: commit(); sm_state = st_attesting; break; case st_attesting: - sm_state = attest(time, rnd) - ? (xfer.with_claim == WithClaim::yes ? st_attested - : st_completed) - : st_attesting; + sm_state = attest(time, rnd) ? (xfer.with_claim == WithClaim::yes ? st_attested : st_completed) + : st_attesting; break; case st_attested: @@ -4930,25 +4019,18 @@ private: BridgeDef const& bridge, Transfer transfer) { - sm_.emplace_back( - time, SmTransfer(chainstate, bridge, std::move(transfer))); + sm_.emplace_back(time, SmTransfer(chainstate, bridge, std::move(transfer))); } void - ac(uint64_t time, - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - AccountCreate ac) + ac(uint64_t time, std::shared_ptr const& chainstate, BridgeDef const& bridge, AccountCreate ac) { - sm_.emplace_back( - time, SmCreateAccount(chainstate, bridge, std::move(ac))); + sm_.emplace_back(time, SmCreateAccount(chainstate, bridge, std::move(ac))); } public: void - runSimulation( - std::shared_ptr const& st, - bool verify_balances = true) + runSimulation(std::shared_ptr const& st, bool verify_balances = true) { using namespace jtx; uint64_t time = 0; @@ -4999,8 +4081,7 @@ public: // create 10 accounts + door funded on both chains, and store // in ChainStateTracker the initial amount of these accounts - Account doorXRPLocking("doorXRPLocking"), - doorUSDLocking("doorUSDLocking"), doorUSDIssuing("doorUSDIssuing"); + Account doorXRPLocking("doorXRPLocking"), doorUSDLocking("doorUSDLocking"), doorUSDIssuing("doorUSDIssuing"); constexpr size_t num_acct = 10; auto a = [&doorXRPLocking, &doorUSDLocking, &doorUSDIssuing]() { @@ -5008,9 +4089,7 @@ public: std::vector result; result.reserve(num_acct); for (int i = 0; i < num_acct; ++i) - result.emplace_back( - "a"s + std::to_string(i), - (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + result.emplace_back("a"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); result.emplace_back("doorXRPLocking"); doorXRPLocking = result.back(); result.emplace_back("doorUSDLocking"); @@ -5059,9 +4138,7 @@ public: std::vector result; result.reserve(num_ua); for (int i = 0; i < num_ua; ++i) - result.emplace_back( - "ua"s + std::to_string(i), - (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + result.emplace_back("ua"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); return result; }(); @@ -5075,30 +4152,14 @@ public: // create XRP -> XRP bridge // ------------------------ BridgeDef xrp_b{ - doorXRPLocking, - xrpIssue(), - Account::master, - xrpIssue(), - XRP(1), - XRP(20), - quorum, - signers, - Json::nullValue}; + doorXRPLocking, xrpIssue(), Account::master, xrpIssue(), XRP(1), XRP(20), quorum, signers, Json::nullValue}; initBridge(xrp_b); // create USD -> USD bridge // ------------------------ BridgeDef usd_b{ - doorUSDLocking, - usdLocking, - doorUSDIssuing, - usdIssuing, - XRP(1), - XRP(20), - quorum, - signers, - Json::nullValue}; + doorUSDLocking, usdLocking, doorUSDIssuing, usdIssuing, XRP(1), XRP(20), quorum, signers, Json::nullValue}; initBridge(usd_b); @@ -5190,7 +4251,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(XChain, app, ripple); -BEAST_DEFINE_TESTSUITE(XChainSim, app, ripple); +BEAST_DEFINE_TESTSUITE(XChain, app, xrpl); +BEAST_DEFINE_TESTSUITE(XChainSim, app, xrpl); -} // namespace ripple::test +} // namespace xrpl::test diff --git a/src/test/app/tx/apply_test.cpp b/src/test/app/tx/apply_test.cpp index a754866c7f..fada168112 100644 --- a/src/test/app/tx/apply_test.cpp +++ b/src/test/app/tx/apply_test.cpp @@ -1,21 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Dev Null Productions - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== +// Copyright (c) 2020 Dev Null Productions #include @@ -24,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { class Apply_test : public beast::unit_test::suite { @@ -32,7 +15,7 @@ public: void run() override { - testcase("Require Fully Canonicial Signature"); + testcase("Require Fully Canonical Signature"); testFullyCanonicalSigs(); } @@ -53,25 +36,7 @@ public: STTx const tx = *std::make_shared(std::ref(sitTrans)); { - test::jtx::Env no_fully_canonical( - *this, - test::jtx::testable_amendments() - - featureRequireFullyCanonicalSig); - - Validity valid = checkValidity( - no_fully_canonical.app().getHashRouter(), - tx, - no_fully_canonical.current()->rules(), - no_fully_canonical.app().config()) - .first; - - if (valid != Validity::Valid) - fail("Non-Fully canoncial signature was not permitted"); - } - - { - test::jtx::Env fully_canonical( - *this, test::jtx::testable_amendments()); + test::jtx::Env fully_canonical(*this, test::jtx::testable_amendments()); Validity valid = checkValidity( fully_canonical.app().getHashRouter(), @@ -80,13 +45,13 @@ public: fully_canonical.app().config()) .first; if (valid == Validity::Valid) - fail("Non-Fully canoncial signature was permitted"); + fail("Non-Fully canonical signature was permitted"); } pass(); } }; -BEAST_DEFINE_TESTSUITE(Apply, tx, ripple); +BEAST_DEFINE_TESTSUITE(Apply, tx, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/Buffer_test.cpp b/src/test/basics/Buffer_test.cpp index 065c33c12f..908650982c 100644 --- a/src/test/basics/Buffer_test.cpp +++ b/src/test/basics/Buffer_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github0.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { struct Buffer_test : beast::unit_test::suite @@ -40,10 +21,9 @@ struct Buffer_test : beast::unit_test::suite void run() override { - std::uint8_t const data[] = { - 0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, - 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, - 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; + std::uint8_t const data[] = {0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, + 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, + 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; Buffer b0; BEAST_EXPECT(sane(b0)); @@ -119,8 +99,7 @@ struct Buffer_test : beast::unit_test::suite { testcase("Move Construction / Assignment"); - static_assert( - std::is_nothrow_move_constructible::value, ""); + static_assert(std::is_nothrow_move_constructible::value, ""); static_assert(std::is_nothrow_move_assignable::value, ""); { // Move-construct from empty buf @@ -280,7 +259,7 @@ struct Buffer_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Buffer, basics, ripple); +BEAST_DEFINE_TESTSUITE(Buffer, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/DetectCrash_test.cpp b/src/test/basics/DetectCrash_test.cpp index 5489ae5b26..0dd2787dff 100644 --- a/src/test/basics/DetectCrash_test.cpp +++ b/src/test/basics/DetectCrash_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { struct DetectCrash_test : public beast::unit_test::suite @@ -44,4 +25,4 @@ struct DetectCrash_test : public beast::unit_test::suite BEAST_DEFINE_TESTSUITE_MANUAL(DetectCrash, basics, beast); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/Expected_test.cpp b/src/test/basics/Expected_test.cpp index faa6b98764..186e34d2e0 100644 --- a/src/test/basics/Expected_test.cpp +++ b/src/test/basics/Expected_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github0.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct Expected_test : beast::unit_test::suite @@ -37,9 +18,7 @@ struct Expected_test : beast::unit_test::suite { // Test non-error const construction. { - auto const expected = []() -> Expected { - return "Valid value"; - }(); + auto const expected = []() -> Expected { return "Valid value"; }(); BEAST_EXPECT(expected); BEAST_EXPECT(expected.has_value()); BEAST_EXPECT(expected.value() == "Valid value"); @@ -61,9 +40,7 @@ struct Expected_test : beast::unit_test::suite } // Test non-error non-const construction. { - auto expected = []() -> Expected { - return "Valid value"; - }(); + auto expected = []() -> Expected { return "Valid value"; }(); BEAST_EXPECT(expected); BEAST_EXPECT(expected.has_value()); BEAST_EXPECT(expected.value() == "Valid value"); @@ -87,9 +64,7 @@ struct Expected_test : beast::unit_test::suite } // Test non-error overlapping type construction. { - auto expected = []() -> Expected { - return 1; - }(); + auto expected = []() -> Expected { return 1; }(); BEAST_EXPECT(expected); BEAST_EXPECT(expected.has_value()); BEAST_EXPECT(expected.value() == 1); @@ -110,9 +85,7 @@ struct Expected_test : beast::unit_test::suite } // Test error construction from rvalue. { - auto const expected = []() -> Expected { - return Unexpected(telLOCAL_ERROR); - }(); + auto const expected = []() -> Expected { return Unexpected(telLOCAL_ERROR); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(!expected.has_value()); BEAST_EXPECT(expected.error() == telLOCAL_ERROR); @@ -133,9 +106,7 @@ struct Expected_test : beast::unit_test::suite // Test error construction from lvalue. { auto const err(telLOCAL_ERROR); - auto expected = [&err]() -> Expected { - return Unexpected(err); - }(); + auto expected = [&err]() -> Expected { return Unexpected(err); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(!expected.has_value()); BEAST_EXPECT(expected.error() == telLOCAL_ERROR); @@ -155,19 +126,14 @@ struct Expected_test : beast::unit_test::suite } // Test error construction from const char*. { - auto const expected = []() -> Expected { - return Unexpected("Not what is expected!"); - }(); + auto const expected = []() -> Expected { return Unexpected("Not what is expected!"); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(!expected.has_value()); - BEAST_EXPECT( - expected.error() == std::string("Not what is expected!")); + BEAST_EXPECT(expected.error() == std::string("Not what is expected!")); } // Test error construction of string from const char*. { - auto expected = []() -> Expected { - return Unexpected("Not what is expected!"); - }(); + auto expected = []() -> Expected { return Unexpected("Not what is expected!"); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(!expected.has_value()); BEAST_EXPECT(expected.error() == "Not what is expected!"); @@ -176,9 +142,7 @@ struct Expected_test : beast::unit_test::suite } // Test non-error const construction of Expected. { - auto const expected = []() -> Expected { - return {}; - }(); + auto const expected = []() -> Expected { return {}; }(); BEAST_EXPECT(expected); bool throwOccurred = false; try @@ -195,9 +159,7 @@ struct Expected_test : beast::unit_test::suite } // Test non-error non-const construction of Expected. { - auto expected = []() -> Expected { - return {}; - }(); + auto expected = []() -> Expected { return {}; }(); BEAST_EXPECT(expected); bool throwOccurred = false; try @@ -214,17 +176,13 @@ struct Expected_test : beast::unit_test::suite } // Test error const construction of Expected. { - auto const expected = []() -> Expected { - return Unexpected("Not what is expected!"); - }(); + auto const expected = []() -> Expected { return Unexpected("Not what is expected!"); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(expected.error() == "Not what is expected!"); } // Test error non-const construction of Expected. { - auto expected = []() -> Expected { - return Unexpected("Not what is expected!"); - }(); + auto expected = []() -> Expected { return Unexpected("Not what is expected!"); }(); BEAST_EXPECT(!expected); BEAST_EXPECT(expected.error() == "Not what is expected!"); std::string const s(std::move(expected.error())); @@ -243,7 +201,7 @@ struct Expected_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Expected, basics, ripple); +BEAST_DEFINE_TESTSUITE(Expected, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/FileUtilities_test.cpp b/src/test/basics/FileUtilities_test.cpp index d1a1d50216..d8664448d6 100644 --- a/src/test/basics/FileUtilities_test.cpp +++ b/src/test/basics/FileUtilities_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { class FileUtilities_test : public beast::unit_test::suite { @@ -31,17 +12,12 @@ public: void testGetFileContents() { - using namespace ripple::detail; + using namespace xrpl::detail; using namespace boost::system; - constexpr char const* expectedContents = - "This file is very short. That's all we need."; + constexpr char const* expectedContents = "This file is very short. That's all we need."; - FileDirGuard file( - *this, - "test_file", - "test.txt", - "This is temporary text that should get overwritten"); + FileDirGuard file(*this, "test_file", "test.txt", "This is temporary text that should get overwritten"); error_code ec; auto const path = file.file(); @@ -66,8 +42,7 @@ public: { // Test with small max auto const bad = getFileContents(ec, path, 16); - BEAST_EXPECT( - ec && ec.value() == boost::system::errc::file_too_large); + BEAST_EXPECT(ec && ec.value() == boost::system::errc::file_too_large); BEAST_EXPECT(bad.empty()); } } @@ -79,6 +54,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(FileUtilities, basics, ripple); +BEAST_DEFINE_TESTSUITE(FileUtilities, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/IOUAmount_test.cpp b/src/test/basics/IOUAmount_test.cpp index dfc48c9be7..73ab0343cd 100644 --- a/src/test/basics/IOUAmount_test.cpp +++ b/src/test/basics/IOUAmount_test.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class IOUAmount_test : public beast::unit_test::suite { @@ -160,15 +141,27 @@ public: { testcase("IOU strings"); - BEAST_EXPECT(to_string(IOUAmount(-2, 0)) == "-2"); - BEAST_EXPECT(to_string(IOUAmount(0, 0)) == "0"); - BEAST_EXPECT(to_string(IOUAmount(2, 0)) == "2"); - BEAST_EXPECT(to_string(IOUAmount(25, -3)) == "0.025"); - BEAST_EXPECT(to_string(IOUAmount(-25, -3)) == "-0.025"); - BEAST_EXPECT(to_string(IOUAmount(25, 1)) == "250"); - BEAST_EXPECT(to_string(IOUAmount(-25, 1)) == "-250"); - BEAST_EXPECT(to_string(IOUAmount(2, 20)) == "2000000000000000e5"); - BEAST_EXPECT(to_string(IOUAmount(-2, -20)) == "-2000000000000000e-35"); + auto test = [this](IOUAmount const& n, std::string const& expected) { + auto const result = to_string(n); + std::stringstream ss; + ss << "to_string(" << result << "). Expected: " << expected; + BEAST_EXPECTS(result == expected, ss.str()); + }; + + for (auto const mantissaSize : {MantissaRange::small, MantissaRange::large}) + { + NumberMantissaScaleGuard mg(mantissaSize); + + test(IOUAmount(-2, 0), "-2"); + test(IOUAmount(0, 0), "0"); + test(IOUAmount(2, 0), "2"); + test(IOUAmount(25, -3), "0.025"); + test(IOUAmount(-25, -3), "-0.025"); + test(IOUAmount(25, 1), "250"); + test(IOUAmount(-25, 1), "-250"); + test(IOUAmount(2, 20), "2e20"); + test(IOUAmount(-2, -20), "-2e-20"); + } } void @@ -209,19 +202,16 @@ public: BEAST_EXPECT(tiny == mulRatio(tiny, maxUInt - 1, maxUInt, true)); // rounding down should be zero BEAST_EXPECT(beast::zero == mulRatio(tiny, 1, maxUInt, false)); - BEAST_EXPECT( - beast::zero == mulRatio(tiny, maxUInt - 1, maxUInt, false)); + BEAST_EXPECT(beast::zero == mulRatio(tiny, maxUInt - 1, maxUInt, false)); // tiny negative numbers IOUAmount tinyNeg(-minMantissa, minExponent); // Round up should give zero BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, 1, maxUInt, true)); - BEAST_EXPECT( - beast::zero == mulRatio(tinyNeg, maxUInt - 1, maxUInt, true)); + BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, maxUInt - 1, maxUInt, true)); // rounding down should be tiny BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, 1, maxUInt, false)); - BEAST_EXPECT( - tinyNeg == mulRatio(tinyNeg, maxUInt - 1, maxUInt, false)); + BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, maxUInt - 1, maxUInt, false)); } { // rounding @@ -241,8 +231,7 @@ public: { IOUAmount negOne(-1, 0); auto const rup = mulRatio(negOne, maxUInt - 1, maxUInt, true); - auto const rdown = - mulRatio(negOne, maxUInt - 1, maxUInt, false); + auto const rdown = mulRatio(negOne, maxUInt - 1, maxUInt, false); BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); } } @@ -258,7 +247,7 @@ public: IOUAmount big(maxMantissa, maxExponent); except([&] { mulRatio(big, 2, 0, true); }); } - } // namespace ripple + } // namespace xrpl //-------------------------------------------------------------------------- @@ -274,6 +263,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(IOUAmount, basics, ripple); +BEAST_DEFINE_TESTSUITE(IOUAmount, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/IntrusiveShared_test.cpp b/src/test/basics/IntrusiveShared_test.cpp index a3acc54d45..d0aa4c75e9 100644 --- a/src/test/basics/IntrusiveShared_test.cpp +++ b/src/test/basics/IntrusiveShared_test.cpp @@ -17,7 +17,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace tests { /** @@ -96,13 +96,11 @@ public: { for (int i = 0; i < maxStates; ++i) { - state[i].store( - TrackedState::uninitialized, std::memory_order_release); + state[i].store(TrackedState::uninitialized, std::memory_order_release); } nextId.store(0, std::memory_order_release); if (resetCallback) - TIBase::tracingCallback_ = [](TrackedState, - std::optional) {}; + TIBase::tracingCallback_ = [](TrackedState, std::optional) {}; } struct ResetStatesGuard @@ -129,8 +127,7 @@ public: using enum TrackedState; assert(state.size() > id_); - tracingCallback_( - state[id_].load(std::memory_order_relaxed), deletedStarted); + tracingCallback_(state[id_].load(std::memory_order_relaxed), deletedStarted); assert(state.size() > id_); // Use relaxed memory order to try to avoid atomic operations from @@ -152,9 +149,7 @@ public: using enum TrackedState; assert(state.size() > id_); - tracingCallback_( - state[id_].load(std::memory_order_relaxed), - partiallyDeletedStarted); + tracingCallback_(state[id_].load(std::memory_order_relaxed), partiallyDeletedStarted); assert(state.size() > id_); state[id_].store(partiallyDeletedStarted, std::memory_order_relaxed); @@ -167,8 +162,7 @@ public: tracingCallback_(partiallyDeleted, std::nullopt); } - static std::function)> - tracingCallback_; + static std::function)> tracingCallback_; int id_; @@ -183,8 +177,8 @@ private: std::array, TIBase::maxStates> TIBase::state; std::atomic TIBase::nextId{0}; -std::function)> - TIBase::tracingCallback_ = [](TrackedState, std::optional) {}; +std::function)> TIBase::tracingCallback_ = + [](TrackedState, std::optional) {}; } // namespace @@ -387,16 +381,15 @@ public: bool destructorRan = false; bool partialDeleteRan = false; std::latch partialDeleteStartedSyncPoint{2}; - strong->tracingCallback_ = [&](TrackedState cur, - std::optional next) { + strong->tracingCallback_ = [&](TrackedState cur, std::optional next) { using enum TrackedState; if (next == deletedStarted) { // strong goes out of scope while weak is still in scope // This checks that partialDelete has run to completion - // before the desturctor is called. A sleep is inserted + // before the destructor is called. A sleep is inserted // inside the partial delete to make sure the destructor is - // given an opportunity to run durring partial delete. + // given an opportunity to run during partial delete. BEAST_EXPECT(cur == partiallyDeleted); } if (next == partiallyDeletedStarted) @@ -455,8 +448,7 @@ public: bool destructorRan = false; bool partialDeleteRan = false; std::latch weakResetSyncPoint{2}; - strong->tracingCallback_ = [&](TrackedState cur, - std::optional next) { + strong->tracingCallback_ = [&](TrackedState cur, std::optional next) { using enum TrackedState; if (next == partiallyDeleted) { @@ -502,14 +494,9 @@ public: int s = destructionState.load(std::memory_order_relaxed); return {(s & 1) != 0, (s & 2) != 0}; }; - auto setDestructorRan = [&]() -> void { - destructionState.fetch_or(1, std::memory_order_acq_rel); - }; - auto setPartialDeleteRan = [&]() -> void { - destructionState.fetch_or(2, std::memory_order_acq_rel); - }; - auto tracingCallback = [&](TrackedState cur, - std::optional next) { + auto setDestructorRan = [&]() -> void { destructionState.fetch_or(1, std::memory_order_acq_rel); }; + auto setPartialDeleteRan = [&]() -> void { destructionState.fetch_or(2, std::memory_order_acq_rel); }; + auto tracingCallback = [&](TrackedState cur, std::optional next) { using enum TrackedState; auto [destructorRan, partialDeleteRan] = getDestructorState(); if (next == partiallyDeleted) @@ -523,13 +510,9 @@ public: setDestructorRan(); } }; - auto createVecOfPointers = [&](auto const& toClone, - std::default_random_engine& eng) - -> std::vector< - std::variant, WeakIntrusive>> { - std::vector< - std::variant, WeakIntrusive>> - result; + auto createVecOfPointers = [&](auto const& toClone, std::default_random_engine& eng) + -> std::vector, WeakIntrusive>> { + std::vector, WeakIntrusive>> result; std::uniform_int_distribution<> toCreateDist(4, 64); std::uniform_int_distribution<> isStrongDist(0, 1); auto numToCreate = toCreateDist(eng); @@ -581,8 +564,7 @@ public: // clear the temporary variables. rsg.emplace(false); - auto [destructorRan, partialDeleteRan] = - getDestructorState(); + auto [destructorRan, partialDeleteRan] = getDestructorState(); BEAST_EXPECT(!i || destructorRan); destructionState.store(0, std::memory_order_release); @@ -596,8 +578,7 @@ public: // ------ Sync Point ------ postCreateToCloneSyncPoint.arrive_and_wait(); - auto v = - createVecOfPointers(toClone[threadId], engines[threadId]); + auto v = createVecOfPointers(toClone[threadId], engines[threadId]); toClone[threadId].reset(); // ------ Sync Point ------ @@ -642,14 +623,9 @@ public: int s = destructionState.load(std::memory_order_relaxed); return {(s & 1) != 0, (s & 2) != 0}; }; - auto setDestructorRan = [&]() -> void { - destructionState.fetch_or(1, std::memory_order_acq_rel); - }; - auto setPartialDeleteRan = [&]() -> void { - destructionState.fetch_or(2, std::memory_order_acq_rel); - }; - auto tracingCallback = [&](TrackedState cur, - std::optional next) { + auto setDestructorRan = [&]() -> void { destructionState.fetch_or(1, std::memory_order_acq_rel); }; + auto setPartialDeleteRan = [&]() -> void { destructionState.fetch_or(2, std::memory_order_acq_rel); }; + auto tracingCallback = [&](TrackedState cur, std::optional next) { using enum TrackedState; auto [destructorRan, partialDeleteRan] = getDestructorState(); if (next == partiallyDeleted) @@ -664,8 +640,7 @@ public: } }; auto createVecOfPointers = [&](auto const& toClone, - std::default_random_engine& eng) - -> std::vector> { + std::default_random_engine& eng) -> std::vector> { std::vector> result; std::uniform_int_distribution<> toCreateDist(4, 64); auto numToCreate = toCreateDist(eng); @@ -710,8 +685,7 @@ public: // thread will also check that the destructor ran and // clear the temporary variables. rsg.emplace(false); - auto [destructorRan, partialDeleteRan] = - getDestructorState(); + auto [destructorRan, partialDeleteRan] = getDestructorState(); BEAST_EXPECT(!i || destructorRan); destructionState.store(0, std::memory_order_release); @@ -725,8 +699,7 @@ public: // ------ Sync Point ------ postCreateToCloneSyncPoint.arrive_and_wait(); - auto v = - createVecOfPointers(toClone[threadId], engines[threadId]); + auto v = createVecOfPointers(toClone[threadId], engines[threadId]); toClone[threadId].reset(); // ------ Sync Point ------ @@ -785,14 +758,9 @@ public: int s = destructionState.load(std::memory_order_relaxed); return {(s & 1) != 0, (s & 2) != 0}; }; - auto setDestructorRan = [&]() -> void { - destructionState.fetch_or(1, std::memory_order_acq_rel); - }; - auto setPartialDeleteRan = [&]() -> void { - destructionState.fetch_or(2, std::memory_order_acq_rel); - }; - auto tracingCallback = [&](TrackedState cur, - std::optional next) { + auto setDestructorRan = [&]() -> void { destructionState.fetch_or(1, std::memory_order_acq_rel); }; + auto setPartialDeleteRan = [&]() -> void { destructionState.fetch_or(2, std::memory_order_acq_rel); }; + auto tracingCallback = [&](TrackedState cur, std::optional next) { using enum TrackedState; auto [destructorRan, partialDeleteRan] = getDestructorState(); if (next == partiallyDeleted) @@ -833,8 +801,7 @@ public: // thread will also check that the destructor ran and // clear the temporary variables. rsg.emplace(false); - auto [destructorRan, partialDeleteRan] = - getDestructorState(); + auto [destructorRan, partialDeleteRan] = getDestructorState(); BEAST_EXPECT(!i || destructorRan); destructionState.store(0, std::memory_order_release); @@ -887,6 +854,6 @@ public: } }; // namespace tests -BEAST_DEFINE_TESTSUITE(IntrusiveShared, basics, ripple); +BEAST_DEFINE_TESTSUITE(IntrusiveShared, basics, xrpl); } // namespace tests -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/KeyCache_test.cpp b/src/test/basics/KeyCache_test.cpp index e1d57fb3e4..55b275ae09 100644 --- a/src/test/basics/KeyCache_test.cpp +++ b/src/test/basics/KeyCache_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class KeyCache_test : public beast::unit_test::suite { @@ -93,6 +74,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(KeyCache, basics, ripple); +BEAST_DEFINE_TESTSUITE(KeyCache, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index f24c0b35e1..13b2d72412 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -1,31 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { class Number_test : public beast::unit_test::suite { @@ -33,46 +15,75 @@ public: void testZero() { - testcase("zero"); + testcase << "zero " << to_string(Number::getMantissaScale()); - Number const z{0, 0}; + for (Number const& z : {Number{0, 0}, Number{0}}) + { + BEAST_EXPECT(z.mantissa() == 0); + BEAST_EXPECT(z.exponent() == Number{}.exponent()); - BEAST_EXPECT(z.mantissa() == 0); - BEAST_EXPECT(z.exponent() == Number{}.exponent()); - - BEAST_EXPECT((z + z) == z); - BEAST_EXPECT((z - z) == z); - BEAST_EXPECT(z == -z); + BEAST_EXPECT((z + z) == z); + BEAST_EXPECT((z - z) == z); + BEAST_EXPECT(z == -z); + } } void test_limits() { - testcase("test_limits"); + auto const scale = Number::getMantissaScale(); + testcase << "test_limits " << to_string(scale); bool caught = false; + auto const minMantissa = Number::minMantissa(); try { - Number x{10'000'000'000'000'000, 32768}; + Number x = Number{false, minMantissa * 10, 32768, Number::normalized{}}; } catch (std::overflow_error const&) { caught = true; } BEAST_EXPECT(caught); - Number x{10'000'000'000'000'000, 32767}; - BEAST_EXPECT((x == Number{1'000'000'000'000'000, 32768})); - Number z{1'000'000'000'000'000, -32769}; - BEAST_EXPECT(z == Number{}); - Number y{1'000'000'000'000'001'500, 32000}; - BEAST_EXPECT((y == Number{1'000'000'000'000'002, 32003})); - Number m{std::numeric_limits::min()}; - BEAST_EXPECT((m == Number{-9'223'372'036'854'776, 3})); - Number M{std::numeric_limits::max()}; - BEAST_EXPECT((M == Number{9'223'372'036'854'776, 3})); + + auto test = [this](auto const& x, auto const& y, int line) { + auto const result = x == y; + std::stringstream ss; + ss << x << " == " << y << " -> " << (result ? "true" : "false"); + expect(result, ss.str(), __FILE__, line); + }; + + test( + Number{false, minMantissa * 10, 32767, Number::normalized{}}, + Number{false, minMantissa, 32768, Number::normalized{}}, + __LINE__); + test(Number{false, minMantissa, -32769, Number::normalized{}}, Number{}, __LINE__); + test( + Number{false, minMantissa, 32000, Number::normalized{}} * 1'000 + + Number{false, 1'500, 32000, Number::normalized{}}, + Number{false, minMantissa + 2, 32003, Number::normalized{}}, + __LINE__); + // 9,223,372,036,854,775,808 + + test( + Number{std::numeric_limits::min()}, + scale == MantissaRange::small ? Number{-9'223'372'036'854'776, 3} + : Number{true, 9'223'372'036'854'775'808ULL, 0, Number::normalized{}}, + __LINE__); + test( + Number{std::numeric_limits::min() + 1}, + scale == MantissaRange::small ? Number{-9'223'372'036'854'776, 3} : Number{-9'223'372'036'854'775'807}, + __LINE__); + test( + Number{std::numeric_limits::max()}, + Number{ + scale == MantissaRange::small ? 9'223'372'036'854'776 : std::numeric_limits::max(), + 18 - Number::mantissaLog()}, + __LINE__); caught = false; try { - Number q{99'999'999'999'999'999, 32767}; + [[maybe_unused]] + Number q = Number{false, minMantissa, 32767, Number::normalized{}} * 100; } catch (std::overflow_error const&) { @@ -84,251 +95,572 @@ public: void test_add() { - testcase("test_add"); + auto const scale = Number::getMantissaScale(); + testcase << "test_add " << to_string(scale); + using Case = std::tuple; - Case c[]{ - {Number{1'000'000'000'000'000, -15}, - Number{6'555'555'555'555'555, -29}, - Number{1'000'000'000'000'066, -15}}, - {Number{-1'000'000'000'000'000, -15}, - Number{-6'555'555'555'555'555, -29}, - Number{-1'000'000'000'000'066, -15}}, - {Number{-1'000'000'000'000'000, -15}, - Number{6'555'555'555'555'555, -29}, - Number{-9'999'999'999'999'344, -16}}, - {Number{-6'555'555'555'555'555, -29}, - Number{1'000'000'000'000'000, -15}, - Number{9'999'999'999'999'344, -16}}, - {Number{}, Number{5}, Number{5}}, - {Number{5'555'555'555'555'555, -32768}, - Number{-5'555'555'555'555'554, -32768}, - Number{0}}, - {Number{-9'999'999'999'999'999, -31}, - Number{1'000'000'000'000'000, -15}, - Number{9'999'999'999'999'990, -16}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x + y == z); - bool caught = false; - try + auto const cSmall = std::to_array( + {{Number{1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'066, -15}}, + {Number{-1'000'000'000'000'000, -15}, + Number{-6'555'555'555'555'555, -29}, + Number{-1'000'000'000'000'066, -15}}, + {Number{-1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{-9'999'999'999'999'344, -16}}, + {Number{-6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'000, -15}, + Number{9'999'999'999'999'344, -16}}, + {Number{}, Number{5}, Number{5}}, + {Number{5}, Number{}, Number{5}}, + {Number{5'555'555'555'555'555, -32768}, Number{-5'555'555'555'555'554, -32768}, Number{0}}, + {Number{-9'999'999'999'999'999, -31}, + Number{1'000'000'000'000'000, -15}, + Number{9'999'999'999'999'990, -16}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items from C + // with larger mantissa + { + {Number{1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'065'556, -18}}, + {Number{-1'000'000'000'000'000, -15}, + Number{-6'555'555'555'555'555, -29}, + Number{-1'000'000'000'000'065'556, -18}}, + {Number{-1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{true, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{-6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'000, -15}, + Number{false, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{}, Number{5}, Number{5}}, + {Number{5}, Number{}, Number{5}}, + {Number{5'555'555'555'555'555'000, -32768}, Number{-5'555'555'555'555'554'000, -32768}, Number{0}}, + {Number{-9'999'999'999'999'999, -31}, + Number{1'000'000'000'000'000, -15}, + Number{9'999'999'999'999'990, -16}}, + // Items from cSmall expanded for the larger mantissa + {Number{1'000'000'000'000'000'000, -18}, + Number{6'555'555'555'555'555'555, -35}, + Number{1'000'000'000'000'000'066, -18}}, + {Number{-1'000'000'000'000'000'000, -18}, + Number{-6'555'555'555'555'555'555, -35}, + Number{-1'000'000'000'000'000'066, -18}}, + {Number{-1'000'000'000'000'000'000, -18}, + Number{6'555'555'555'555'555'555, -35}, + Number{true, 9'999'999'999'999'999'344ULL, -19, Number::normalized{}}}, + {Number{-6'555'555'555'555'555'555, -35}, + Number{1'000'000'000'000'000'000, -18}, + Number{false, 9'999'999'999'999'999'344ULL, -19, Number::normalized{}}}, + {Number{}, Number{5}, Number{5}}, + {Number{5'555'555'555'555'555'555, -32768}, Number{-5'555'555'555'555'555'554, -32768}, Number{0}}, + {Number{true, 9'999'999'999'999'999'999ULL, -37, Number::normalized{}}, + Number{1'000'000'000'000'000'000, -18}, + Number{false, 9'999'999'999'999'999'990ULL, -19, Number::normalized{}}}, + {Number{Number::maxRep}, Number{6, -1}, Number{Number::maxRep / 10, 1}}, + {Number{Number::maxRep - 1}, Number{1, 0}, Number{Number::maxRep}}, + // Test extremes + { + // Each Number operand rounds up, so the actual mantissa is + // minMantissa + Number{false, 9'999'999'999'999'999'999ULL, 0, Number::normalized{}}, + Number{false, 9'999'999'999'999'999'999ULL, 0, Number::normalized{}}, + Number{2, 19}, + }, + { + // Does not round. Mantissas are going to be > maxRep, so if + // added together as uint64_t's, the result will overflow. + // With addition using uint128_t, there's no problem. After + // normalizing, the resulting mantissa ends up less than + // maxRep. + Number{false, 9'999'999'999'999'999'990ULL, 0, Number::normalized{}}, + Number{false, 9'999'999'999'999'999'990ULL, 0, Number::normalized{}}, + Number{false, 1'999'999'999'999'999'998ULL, 1, Number::normalized{}}, + }, + }); + auto test = [this](auto const& c) { + for (auto const& [x, y, z] : c) + { + auto const result = x + y; + std::stringstream ss; + ss << x << " + " << y << " = " << result << ". Expected: " << z; + BEAST_EXPECTS(result == z, ss.str()); + } + }; + if (scale == MantissaRange::small) + test(cSmall); + else + test(cLarge); { - Number{9'999'999'999'999'999, 32768} + - Number{5'000'000'000'000'000, 32767}; + bool caught = false; + try + { + Number{false, Number::maxMantissa(), 32768, Number::normalized{}} + + Number{false, Number::minMantissa(), 32767, Number::normalized{}} * 5; + } + catch (std::overflow_error const&) + { + caught = true; + } + BEAST_EXPECT(caught); } - catch (std::overflow_error const&) - { - caught = true; - } - BEAST_EXPECT(caught); } void test_sub() { - testcase("test_sub"); + auto const scale = Number::getMantissaScale(); + testcase << "test_sub " << to_string(scale); + using Case = std::tuple; - Case c[]{ - {Number{1'000'000'000'000'000, -15}, - Number{6'555'555'555'555'555, -29}, - Number{9'999'999'999'999'344, -16}}, - {Number{6'555'555'555'555'555, -29}, - Number{1'000'000'000'000'000, -15}, - Number{-9'999'999'999'999'344, -16}}, - {Number{1'000'000'000'000'000, -15}, - Number{1'000'000'000'000'000, -15}, - Number{0}}, - {Number{1'000'000'000'000'000, -15}, - Number{1'000'000'000'000'001, -15}, - Number{-1'000'000'000'000'000, -30}}, - {Number{1'000'000'000'000'001, -15}, - Number{1'000'000'000'000'000, -15}, - Number{1'000'000'000'000'000, -30}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x - y == z); + auto const cSmall = std::to_array( + {{Number{1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{9'999'999'999'999'344, -16}}, + {Number{6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'000, -15}, + Number{-9'999'999'999'999'344, -16}}, + {Number{1'000'000'000'000'000, -15}, Number{1'000'000'000'000'000, -15}, Number{0}}, + {Number{1'000'000'000'000'000, -15}, + Number{1'000'000'000'000'001, -15}, + Number{-1'000'000'000'000'000, -30}}, + {Number{1'000'000'000'000'001, -15}, + Number{1'000'000'000'000'000, -15}, + Number{1'000'000'000'000'000, -30}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items from C + // with larger mantissa + { + {Number{1'000'000'000'000'000, -15}, + Number{6'555'555'555'555'555, -29}, + Number{false, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{6'555'555'555'555'555, -29}, + Number{1'000'000'000'000'000, -15}, + Number{true, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{1'000'000'000'000'000, -15}, Number{1'000'000'000'000'000, -15}, Number{0}}, + {Number{1'000'000'000'000'000, -15}, + Number{1'000'000'000'000'001, -15}, + Number{-1'000'000'000'000'000, -30}}, + {Number{1'000'000'000'000'001, -15}, + Number{1'000'000'000'000'000, -15}, + Number{1'000'000'000'000'000, -30}}, + // Items from cSmall expanded for the larger mantissa + {Number{1'000'000'000'000'000'000, -18}, + Number{6'555'555'555'555'555'555, -32}, + Number{false, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{6'555'555'555'555'555'555, -32}, + Number{1'000'000'000'000'000'000, -18}, + Number{true, 9'999'999'999'999'344'444ULL, -19, Number::normalized{}}}, + {Number{1'000'000'000'000'000'000, -18}, Number{1'000'000'000'000'000'000, -18}, Number{0}}, + {Number{1'000'000'000'000'000'000, -18}, + Number{1'000'000'000'000'000'001, -18}, + Number{-1'000'000'000'000'000'000, -36}}, + {Number{1'000'000'000'000'000'001, -18}, + Number{1'000'000'000'000'000'000, -18}, + Number{1'000'000'000'000'000'000, -36}}, + {Number{Number::maxRep}, Number{6, -1}, Number{Number::maxRep - 1}}, + {Number{false, Number::maxRep + 1, 0, Number::normalized{}}, + Number{1, 0}, + Number{Number::maxRep / 10 + 1, 1}}, + {Number{false, Number::maxRep + 1, 0, Number::normalized{}}, Number{3, 0}, Number{Number::maxRep}}, + {power(2, 63), Number{3, 0}, Number{Number::maxRep}}, + }); + auto test = [this](auto const& c) { + for (auto const& [x, y, z] : c) + { + auto const result = x - y; + std::stringstream ss; + ss << x << " - " << y << " = " << result << ". Expected: " << z; + BEAST_EXPECTS(result == z, ss.str()); + } + }; + if (scale == MantissaRange::small) + test(cSmall); + else + test(cLarge); } void test_mul() { - testcase("test_mul"); + auto const scale = Number::getMantissaScale(); + testcase << "test_mul " << to_string(scale); + using Case = std::tuple; + auto test = [this](auto const& c) { + for (auto const& [x, y, z] : c) + { + auto const result = x * y; + std::stringstream ss; + ss << x << " * " << y << " = " << result << ". Expected: " << z; + BEAST_EXPECTS(result == z, ss.str()); + } + }; + auto tests = [&](auto const& cSmall, auto const& cLarge) { + if (scale == MantissaRange::small) + test(cSmall); + else + test(cLarge); + }; + auto const maxMantissa = Number::maxMantissa(); + saveNumberRoundMode save{Number::setround(Number::to_nearest)}; { - Case c[]{ + auto const cSmall = std::to_array({ {Number{7}, Number{8}, Number{56}}, - {Number{1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{2000000000000000, -15}}, - {Number{-1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{-2000000000000000, -15}}, - {Number{-1414213562373095, -15}, - Number{-1414213562373095, -15}, - Number{2000000000000000, -15}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{2000000000000000, -15}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-2000000000000000, -15}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{2000000000000000, -15}}, + {Number{3214285714285706, -15}, Number{3111111111111119, -15}, Number{1000000000000000, -14}}, + {Number{1000000000000000, -32768}, Number{1000000000000000, -32768}, Number{0}}, + // Maximum mantissa range + {Number{9'999'999'999'999'999, 0}, Number{9'999'999'999'999'999, 0}, Number{9'999'999'999'999'998, 16}}, + }); + auto const cLarge = std::to_array({ + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + {Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999862, -18}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999862, -18}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999862, -18}}, {Number{3214285714285706, -15}, Number{3111111111111119, -15}, - Number{1000000000000000, -14}}, - {Number{1000000000000000, -32768}, - Number{1000000000000000, -32768}, - Number{0}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x * y == z); + Number{false, 9'999'999'999'999'999'579ULL, -18, Number::normalized{}}}, + {Number{1000000000000000000, -32768}, Number{1000000000000000000, -32768}, Number{0}}, + // Items from cSmall expanded for the larger mantissa, + // except duplicates. Sadly, it looks like sqrt(2)^2 != 2 + // with higher precision + {Number{1414213562373095049, -18}, Number{1414213562373095049, -18}, Number{2000000000000000001, -18}}, + {Number{-1414213562373095048, -18}, + Number{1414213562373095048, -18}, + Number{-1999999999999999998, -18}}, + {Number{-1414213562373095048, -18}, + Number{-1414213562373095049, -18}, + Number{1999999999999999999, -18}}, + {Number{3214285714285714278, -18}, Number{3111111111111111119, -18}, Number{10, 0}}, + // Maximum mantissa range - rounds up to 1e19 + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1, 38}}, + // Maximum int64 range + {Number{Number::maxRep, 0}, Number{Number::maxRep, 0}, Number{85'070'591'730'234'615'85, 19}}, + }); + tests(cSmall, cLarge); } Number::setround(Number::towards_zero); + testcase << "test_mul " << to_string(Number::getMantissaScale()) << " towards_zero"; { - Case c[]{ - {Number{7}, Number{8}, Number{56}}, - {Number{1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{1999999999999999, -15}}, - {Number{-1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{-1999999999999999, -15}}, - {Number{-1414213562373095, -15}, - Number{-1414213562373095, -15}, - Number{1999999999999999, -15}}, - {Number{3214285714285706, -15}, - Number{3111111111111119, -15}, - Number{9999999999999999, -15}}, - {Number{1000000000000000, -32768}, - Number{1000000000000000, -32768}, - Number{0}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x * y == z); + auto const cSmall = std::to_array( + {{Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999, -15}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999, -15}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999, -15}}, + {Number{3214285714285706, -15}, Number{3111111111111119, -15}, Number{9999999999999999, -15}}, + {Number{1000000000000000, -32768}, Number{1000000000000000, -32768}, Number{0}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + { + {Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999861, -18}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999861, -18}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999861, -18}}, + {Number{3214285714285706, -15}, + Number{3111111111111119, -15}, + Number{false, 9999999999999999579ULL, -18, Number::normalized{}}}, + {Number{1000000000000000000, -32768}, Number{1000000000000000000, -32768}, Number{0}}, + // Items from cSmall expanded for the larger mantissa, + // except duplicates. Sadly, it looks like sqrt(2)^2 != 2 + // with higher precision + {Number{1414213562373095049, -18}, Number{1414213562373095049, -18}, Number{2, 0}}, + {Number{-1414213562373095048, -18}, + Number{1414213562373095048, -18}, + Number{-1999999999999999997, -18}}, + {Number{-1414213562373095048, -18}, + Number{-1414213562373095049, -18}, + Number{1999999999999999999, -18}}, + {Number{3214285714285714278, -18}, Number{3111111111111111119, -18}, Number{10, 0}}, + // Maximum mantissa range - rounds down to maxMantissa/10e1 + // 99'999'999'999'999'999'800'000'000'000'000'000'100 + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa / 10 - 1, 20, Number::normalized{}}}, + // Maximum int64 range + // 85'070'591'730'234'615'847'396'907'784'232'501'249 + {Number{Number::maxRep, 0}, Number{Number::maxRep, 0}, Number{85'070'591'730'234'615'84, 19}}, + }); + tests(cSmall, cLarge); } Number::setround(Number::downward); + testcase << "test_mul " << to_string(Number::getMantissaScale()) << " downward"; { - Case c[]{ - {Number{7}, Number{8}, Number{56}}, - {Number{1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{1999999999999999, -15}}, - {Number{-1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{-2000000000000000, -15}}, - {Number{-1414213562373095, -15}, - Number{-1414213562373095, -15}, - Number{1999999999999999, -15}}, - {Number{3214285714285706, -15}, - Number{3111111111111119, -15}, - Number{9999999999999999, -15}}, - {Number{1000000000000000, -32768}, - Number{1000000000000000, -32768}, - Number{0}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x * y == z); + auto const cSmall = std::to_array( + {{Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999, -15}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-2000000000000000, -15}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999, -15}}, + {Number{3214285714285706, -15}, Number{3111111111111119, -15}, Number{9999999999999999, -15}}, + {Number{1000000000000000, -32768}, Number{1000000000000000, -32768}, Number{0}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + { + {Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999861, -18}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999862, -18}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999861, -18}}, + {Number{3214285714285706, -15}, + Number{3111111111111119, -15}, + Number{false, 9'999'999'999'999'999'579ULL, -18, Number::normalized{}}}, + {Number{1000000000000000000, -32768}, Number{1000000000000000000, -32768}, Number{0}}, + // Items from cSmall expanded for the larger mantissa, + // except duplicates. Sadly, it looks like sqrt(2)^2 != 2 + // with higher precision + {Number{1414213562373095049, -18}, Number{1414213562373095049, -18}, Number{2, 0}}, + {Number{-1414213562373095048, -18}, + Number{1414213562373095048, -18}, + Number{-1999999999999999998, -18}}, + {Number{-1414213562373095048, -18}, + Number{-1414213562373095049, -18}, + Number{1999999999999999999, -18}}, + {Number{3214285714285714278, -18}, Number{3111111111111111119, -18}, Number{10, 0}}, + // Maximum mantissa range - rounds down to maxMantissa/10e1 + // 99'999'999'999'999'999'800'000'000'000'000'000'100 + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa / 10 - 1, 20, Number::normalized{}}}, + // Maximum int64 range + // 85'070'591'730'234'615'847'396'907'784'232'501'249 + {Number{Number::maxRep, 0}, Number{Number::maxRep, 0}, Number{85'070'591'730'234'615'84, 19}}, + }); + tests(cSmall, cLarge); } Number::setround(Number::upward); + testcase << "test_mul " << to_string(Number::getMantissaScale()) << " upward"; { - Case c[]{ - {Number{7}, Number{8}, Number{56}}, - {Number{1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{2000000000000000, -15}}, - {Number{-1414213562373095, -15}, - Number{1414213562373095, -15}, - Number{-1999999999999999, -15}}, - {Number{-1414213562373095, -15}, - Number{-1414213562373095, -15}, - Number{2000000000000000, -15}}, - {Number{3214285714285706, -15}, - Number{3111111111111119, -15}, - Number{1000000000000000, -14}}, - {Number{1000000000000000, -32768}, - Number{1000000000000000, -32768}, - Number{0}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x * y == z); + auto const cSmall = std::to_array( + {{Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{2000000000000000, -15}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999, -15}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{2000000000000000, -15}}, + {Number{3214285714285706, -15}, Number{3111111111111119, -15}, Number{1000000000000000, -14}}, + {Number{1000000000000000, -32768}, Number{1000000000000000, -32768}, Number{0}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + { + {Number{7}, Number{8}, Number{56}}, + {Number{1414213562373095, -15}, Number{1414213562373095, -15}, Number{1999999999999999862, -18}}, + {Number{-1414213562373095, -15}, Number{1414213562373095, -15}, Number{-1999999999999999861, -18}}, + {Number{-1414213562373095, -15}, Number{-1414213562373095, -15}, Number{1999999999999999862, -18}}, + {Number{3214285714285706, -15}, Number{3111111111111119, -15}, Number{999999999999999958, -17}}, + {Number{1000000000000000000, -32768}, Number{1000000000000000000, -32768}, Number{0}}, + // Items from cSmall expanded for the larger mantissa, + // except duplicates. Sadly, it looks like sqrt(2)^2 != 2 + // with higher precision + {Number{1414213562373095049, -18}, + Number{1414213562373095049, -18}, + Number{2000000000000000001, -18}}, + {Number{-1414213562373095048, -18}, + Number{1414213562373095048, -18}, + Number{-1999999999999999997, -18}}, + {Number{-1414213562373095048, -18}, Number{-1414213562373095049, -18}, Number{2, 0}}, + {Number{3214285714285714278, -18}, + Number{3111111111111111119, -18}, + Number{1000000000000000001, -17}}, + // Maximum mantissa range - rounds up to minMantissa*10 + // 1e19*1e19=1e38 + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1, 38}}, + // Maximum int64 range + // 85'070'591'730'234'615'847'396'907'784'232'501'249 + {Number{Number::maxRep, 0}, Number{Number::maxRep, 0}, Number{85'070'591'730'234'615'85, 19}}, + }); + tests(cSmall, cLarge); } - bool caught = false; - try + testcase << "test_mul " << to_string(Number::getMantissaScale()) << " overflow"; { - Number{9'999'999'999'999'999, 32768} * - Number{5'000'000'000'000'000, 32767}; + bool caught = false; + try + { + Number{false, maxMantissa, 32768, Number::normalized{}} * + Number{false, Number::minMantissa() * 5, 32767, Number::normalized{}}; + } + catch (std::overflow_error const&) + { + caught = true; + } + BEAST_EXPECT(caught); } - catch (std::overflow_error const&) - { - caught = true; - } - BEAST_EXPECT(caught); } void test_div() { - testcase("test_div"); + auto const scale = Number::getMantissaScale(); + testcase << "test_div " << to_string(scale); + using Case = std::tuple; + auto test = [this](auto const& c) { + for (auto const& [x, y, z] : c) + { + auto const result = x / y; + std::stringstream ss; + ss << x << " / " << y << " = " << result << ". Expected: " << z; + BEAST_EXPECTS(result == z, ss.str()); + } + }; + auto const maxMantissa = Number::maxMantissa(); + auto tests = [&](auto const& cSmall, auto const& cLarge) { + if (scale == MantissaRange::small) + test(cSmall); + else + test(cLarge); + }; saveNumberRoundMode save{Number::setround(Number::to_nearest)}; { - Case c[]{ - {Number{1}, Number{2}, Number{5, -1}}, - {Number{1}, Number{10}, Number{1, -1}}, - {Number{1}, Number{-10}, Number{-1, -1}}, - {Number{0}, Number{100}, Number{0}}, - {Number{1414213562373095, -10}, - Number{1414213562373095, -10}, - Number{1}}, - {Number{9'999'999'999'999'999}, - Number{1'000'000'000'000'000}, - Number{9'999'999'999'999'999, -15}}, - {Number{2}, Number{3}, Number{6'666'666'666'666'667, -16}}, - {Number{-2}, Number{3}, Number{-6'666'666'666'666'667, -16}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x / y == z); + auto const cSmall = std::to_array( + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'667, -16}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'667, -16}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428, -16}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666'667, -19}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666'667, -19}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428'571, -19}}, + // Items from cSmall expanded for the larger mantissa, except + // duplicates. + {Number{1414213562373095049, -13}, Number{1414213562373095049, -13}, Number{1}}, + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1'000'000'000'000'000'000}, + Number{false, maxMantissa, -18, Number::normalized{}}}}); + tests(cSmall, cLarge); } + testcase << "test_div " << to_string(Number::getMantissaScale()) << " towards_zero"; Number::setround(Number::towards_zero); { - Case c[]{ - {Number{1}, Number{2}, Number{5, -1}}, - {Number{1}, Number{10}, Number{1, -1}}, - {Number{1}, Number{-10}, Number{-1, -1}}, - {Number{0}, Number{100}, Number{0}}, - {Number{1414213562373095, -10}, - Number{1414213562373095, -10}, - Number{1}}, - {Number{9'999'999'999'999'999}, - Number{1'000'000'000'000'000}, - Number{9'999'999'999'999'999, -15}}, - {Number{2}, Number{3}, Number{6'666'666'666'666'666, -16}}, - {Number{-2}, Number{3}, Number{-6'666'666'666'666'666, -16}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x / y == z); + auto const cSmall = std::to_array( + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666, -16}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666, -16}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428, -16}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666'666, -19}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666'666, -19}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428'571, -19}}, + // Items from cSmall expanded for the larger mantissa, except + // duplicates. + {Number{1414213562373095049, -13}, Number{1414213562373095049, -13}, Number{1}}, + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1'000'000'000'000'000'000}, + Number{false, maxMantissa, -18, Number::normalized{}}}}); + tests(cSmall, cLarge); } + testcase << "test_div " << to_string(Number::getMantissaScale()) << " downward"; Number::setround(Number::downward); { - Case c[]{ - {Number{1}, Number{2}, Number{5, -1}}, - {Number{1}, Number{10}, Number{1, -1}}, - {Number{1}, Number{-10}, Number{-1, -1}}, - {Number{0}, Number{100}, Number{0}}, - {Number{1414213562373095, -10}, - Number{1414213562373095, -10}, - Number{1}}, - {Number{9'999'999'999'999'999}, - Number{1'000'000'000'000'000}, - Number{9'999'999'999'999'999, -15}}, - {Number{2}, Number{3}, Number{6'666'666'666'666'666, -16}}, - {Number{-2}, Number{3}, Number{-6'666'666'666'666'667, -16}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x / y == z); + auto const cSmall = std::to_array( + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666, -16}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'667, -16}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428, -16}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666'666, -19}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666'667, -19}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428'571, -19}}, + // Items from cSmall expanded for the larger mantissa, except + // duplicates. + {Number{1414213562373095049, -13}, Number{1414213562373095049, -13}, Number{1}}, + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1'000'000'000'000'000'000}, + Number{false, maxMantissa, -18, Number::normalized{}}}}); + tests(cSmall, cLarge); } + testcase << "test_div " << to_string(Number::getMantissaScale()) << " upward"; Number::setround(Number::upward); { - Case c[]{ - {Number{1}, Number{2}, Number{5, -1}}, - {Number{1}, Number{10}, Number{1, -1}}, - {Number{1}, Number{-10}, Number{-1, -1}}, - {Number{0}, Number{100}, Number{0}}, - {Number{1414213562373095, -10}, - Number{1414213562373095, -10}, - Number{1}}, - {Number{9'999'999'999'999'999}, - Number{1'000'000'000'000'000}, - Number{9'999'999'999'999'999, -15}}, - {Number{2}, Number{3}, Number{6'666'666'666'666'667, -16}}, - {Number{-2}, Number{3}, Number{-6'666'666'666'666'666, -16}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT(x / y == z); + auto const cSmall = std::to_array( + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'667, -16}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666, -16}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'429, -16}}}); + auto const cLarge = std::to_array( + // Note that items with extremely large mantissas need to be + // calculated, because otherwise they overflow uint64. Items + // from C with larger mantissa + {{Number{1}, Number{2}, Number{5, -1}}, + {Number{1}, Number{10}, Number{1, -1}}, + {Number{1}, Number{-10}, Number{-1, -1}}, + {Number{0}, Number{100}, Number{0}}, + {Number{1414213562373095, -10}, Number{1414213562373095, -10}, Number{1}}, + {Number{9'999'999'999'999'999}, Number{1'000'000'000'000'000}, Number{9'999'999'999'999'999, -15}}, + {Number{2}, Number{3}, Number{6'666'666'666'666'666'667, -19}}, + {Number{-2}, Number{3}, Number{-6'666'666'666'666'666'666, -19}}, + {Number{1}, Number{7}, Number{1'428'571'428'571'428'572, -19}}, + // Items from cSmall expanded for the larger mantissa, except + // duplicates. + {Number{1414213562373095049, -13}, Number{1414213562373095049, -13}, Number{1}}, + {Number{false, maxMantissa, 0, Number::normalized{}}, + Number{1'000'000'000'000'000'000}, + Number{false, maxMantissa, -18, Number::normalized{}}}}); + tests(cSmall, cLarge); } + testcase << "test_div " << to_string(Number::getMantissaScale()) << " overflow"; bool caught = false; try { @@ -344,20 +676,53 @@ public: void test_root() { - testcase("test_root"); + auto const scale = Number::getMantissaScale(); + testcase << "test_root " << to_string(scale); + using Case = std::tuple; - Case c[]{ - {Number{2}, 2, Number{1414213562373095, -15}}, - {Number{2'000'000}, 2, Number{1414213562373095, -12}}, - {Number{2, -30}, 2, Number{1414213562373095, -30}}, - {Number{-27}, 3, Number{-3}}, - {Number{1}, 5, Number{1}}, - {Number{-1}, 0, Number{1}}, - {Number{5, -1}, 0, Number{0}}, - {Number{0}, 5, Number{0}}, - {Number{5625, -4}, 2, Number{75, -2}}}; - for (auto const& [x, y, z] : c) - BEAST_EXPECT((root(x, y) == z)); + auto test = [this](auto const& c) { + for (auto const& [x, y, z] : c) + { + auto const result = root(x, y); + std::stringstream ss; + ss << "root(" << x << ", " << y << ") = " << result << ". Expected: " << z; + BEAST_EXPECTS(result == z, ss.str()); + } + }; + /* + auto tests = [&](auto const& cSmall, auto const& cLarge) { + test(cSmall); + if (scale != MantissaRange::small) + test(cLarge); + }; + */ + + auto const cSmall = std::to_array( + {{Number{2}, 2, Number{1414213562373095049, -18}}, + {Number{2'000'000}, 2, Number{1414213562373095049, -15}}, + {Number{2, -30}, 2, Number{1414213562373095049, -33}}, + {Number{-27}, 3, Number{-3}}, + {Number{1}, 5, Number{1}}, + {Number{-1}, 0, Number{1}}, + {Number{5, -1}, 0, Number{0}}, + {Number{0}, 5, Number{0}}, + {Number{5625, -4}, 2, Number{75, -2}}}); + auto const cLarge = std::to_array({ + {Number{false, Number::maxMantissa() - 9, -1, Number::normalized{}}, + 2, + Number{false, 999'999'999'999'999'999, -9, Number::normalized{}}}, + {Number{false, Number::maxMantissa() - 9, 0, Number::normalized{}}, + 2, + Number{false, 3'162'277'660'168'379'330, -9, Number::normalized{}}}, + {Number{Number::maxRep}, 2, Number{false, 3'037'000'499'976049692, -9, Number::normalized{}}}, + {Number{Number::maxRep}, 4, Number{false, 55'108'98747006743627, -14, Number::normalized{}}}, + }); + test(cSmall); + if (Number::getMantissaScale() != MantissaRange::small) + { + NumberRoundModeGuard mg(Number::towards_zero); + test(cLarge); + } bool caught = false; try { @@ -380,10 +745,51 @@ public: BEAST_EXPECT(caught); } + void + test_root2() + { + auto const scale = Number::getMantissaScale(); + testcase << "test_root2 " << to_string(scale); + + auto test = [this](auto const& c) { + for (auto const& x : c) + { + auto const expected = root(x, 2); + auto const result = root2(x); + std::stringstream ss; + ss << "root2(" << x << ") = " << result << ". Expected: " << expected; + BEAST_EXPECTS(result == expected, ss.str()); + } + }; + + auto const cSmall = std::to_array({ + Number{2}, + Number{2'000'000}, + Number{2, -30}, + Number{27}, + Number{1}, + Number{5, -1}, + Number{0}, + Number{5625, -4}, + Number{Number::maxRep}, + }); + test(cSmall); + bool caught = false; + try + { + (void)root2(Number{-2}); + } + catch (std::overflow_error const&) + { + caught = true; + } + BEAST_EXPECT(caught); + } + void test_power1() { - testcase("test_power1"); + testcase << "test_power1 " << to_string(Number::getMantissaScale()); using Case = std::tuple; Case c[]{ {Number{64}, 0, Number{1}}, @@ -391,7 +797,9 @@ public: {Number{64}, 2, Number{4096}}, {Number{-64}, 2, Number{4096}}, {Number{64}, 3, Number{262144}}, - {Number{-64}, 3, Number{-262144}}}; + {Number{-64}, 3, Number{-262144}}, + {Number{64}, 11, Number{false, 7378697629483820646ULL, 1, Number::normalized{}}}, + {Number{-64}, 11, Number{true, 7378697629483820646ULL, 1, Number::normalized{}}}}; for (auto const& [x, y, z] : c) BEAST_EXPECT((power(x, y) == z)); } @@ -399,7 +807,7 @@ public: void test_power2() { - testcase("test_power2"); + testcase << "test_power2 " << to_string(Number::getMantissaScale()); using Case = std::tuple; Case c[]{ {Number{1}, 3, 7, Number{1}}, @@ -445,7 +853,7 @@ public: void testConversions() { - testcase("testConversions"); + testcase << "testConversions " << to_string(Number::getMantissaScale()); IOUAmount x{5, 6}; Number y = x; @@ -471,7 +879,7 @@ public: void test_to_integer() { - testcase("test_to_integer"); + testcase << "test_to_integer " << to_string(Number::getMantissaScale()); using Case = std::tuple; saveNumberRoundMode save{Number::setround(Number::to_nearest)}; { @@ -639,7 +1047,7 @@ public: void test_squelch() { - testcase("test_squelch"); + testcase << "test_squelch " << to_string(Number::getMantissaScale()); Number limit{1, -6}; BEAST_EXPECT((squelch(Number{2, -6}, limit) == Number{2, -6})); BEAST_EXPECT((squelch(Number{1, -6}, limit) == Number{1, -6})); @@ -652,22 +1060,92 @@ public: void testToString() { - testcase("testToString"); - BEAST_EXPECT(to_string(Number(-2, 0)) == "-2"); - BEAST_EXPECT(to_string(Number(0, 0)) == "0"); - BEAST_EXPECT(to_string(Number(2, 0)) == "2"); - BEAST_EXPECT(to_string(Number(25, -3)) == "0.025"); - BEAST_EXPECT(to_string(Number(-25, -3)) == "-0.025"); - BEAST_EXPECT(to_string(Number(25, 1)) == "250"); - BEAST_EXPECT(to_string(Number(-25, 1)) == "-250"); - BEAST_EXPECT(to_string(Number(2, 20)) == "2000000000000000e5"); - BEAST_EXPECT(to_string(Number(-2, -20)) == "-2000000000000000e-35"); + auto const scale = Number::getMantissaScale(); + testcase << "testToString " << to_string(scale); + + auto test = [this](Number const& n, std::string const& expected) { + auto const result = to_string(n); + std::stringstream ss; + ss << "to_string(" << result << "). Expected: " << expected; + BEAST_EXPECTS(result == expected, ss.str()); + }; + + test(Number(-2, 0), "-2"); + test(Number(0, 0), "0"); + test(Number(2, 0), "2"); + test(Number(25, -3), "0.025"); + test(Number(-25, -3), "-0.025"); + test(Number(25, 1), "250"); + test(Number(-25, 1), "-250"); + test(Number(2, 20), "2e20"); + test(Number(-2, -20), "-2e-20"); + // Test the edges + // ((exponent < -(25)) || (exponent > -(5))))) + // or ((exponent < -(28)) || (exponent > -(8))))) + test(Number(2, -10), "0.0000000002"); + test(Number(2, -11), "2e-11"); + + test(Number(-2, 10), "-20000000000"); + test(Number(-2, 11), "-2e11"); + + switch (scale) + { + case MantissaRange::small: + + test(Number::min(), "1e-32753"); + test(Number::max(), "9999999999999999e32768"); + test(Number::lowest(), "-9999999999999999e32768"); + { + NumberRoundModeGuard mg(Number::towards_zero); + + auto const maxMantissa = Number::maxMantissa(); + BEAST_EXPECT(maxMantissa == 9'999'999'999'999'999); + test(Number{false, maxMantissa * 1000 + 999, -3, Number::normalized()}, "9999999999999999"); + test(Number{true, maxMantissa * 1000 + 999, -3, Number::normalized()}, "-9999999999999999"); + + test(Number{std::numeric_limits::max(), -3}, "9223372036854775"); + test(-(Number{std::numeric_limits::max(), -3}), "-9223372036854775"); + + test(Number{std::numeric_limits::min(), 0}, "-9223372036854775e3"); + test(-(Number{std::numeric_limits::min(), 0}), "9223372036854775e3"); + } + break; + case MantissaRange::large: + // Test the edges + // ((exponent < -(28)) || (exponent > -(8))))) + test(Number::min(), "1e-32750"); + test(Number::max(), "9223372036854775807e32768"); + test(Number::lowest(), "-9223372036854775807e32768"); + { + NumberRoundModeGuard mg(Number::towards_zero); + + auto const maxMantissa = Number::maxMantissa(); + BEAST_EXPECT(maxMantissa == 9'999'999'999'999'999'999ULL); + test(Number{false, maxMantissa, 0, Number::normalized{}}, "9999999999999999990"); + test(Number{true, maxMantissa, 0, Number::normalized{}}, "-9999999999999999990"); + + test(Number{std::numeric_limits::max(), 0}, "9223372036854775807"); + test(-(Number{std::numeric_limits::max(), 0}), "-9223372036854775807"); + + // Because the absolute value of min is larger than max, it + // will be scaled down to fit under max. Since we're + // rounding towards zero, the 8 at the end is dropped. + test(Number{std::numeric_limits::min(), 0}, "-9223372036854775800"); + test(-(Number{std::numeric_limits::min(), 0}), "9223372036854775800"); + } + + test(Number{std::numeric_limits::max(), 0} + 1, "9223372036854775810"); + test(-(Number{std::numeric_limits::max(), 0} + 1), "-9223372036854775810"); + break; + default: + BEAST_EXPECT(false); + } } void test_relationals() { - testcase("test_relationals"); + testcase << "test_relationals " << to_string(Number::getMantissaScale()); BEAST_EXPECT(!(Number{100} < Number{10})); BEAST_EXPECT(Number{100} > Number{10}); BEAST_EXPECT(Number{100} >= Number{10}); @@ -677,7 +1155,7 @@ public: void test_stream() { - testcase("test_stream"); + testcase << "test_stream " << to_string(Number::getMantissaScale()); Number x{100}; std::ostringstream os; os << x; @@ -687,7 +1165,7 @@ public: void test_inc_dec() { - testcase("test_inc_dec"); + testcase << "test_inc_dec " << to_string(Number::getMantissaScale()); Number x{100}; Number y = +x; BEAST_EXPECT(x == y); @@ -704,19 +1182,19 @@ public: Issue const issue; Number const n{7'518'783'80596, -5}; saveNumberRoundMode const save{Number::setround(Number::to_nearest)}; - auto res2 = STAmount{issue, n.mantissa(), n.exponent()}; + auto res2 = STAmount{issue, n}; BEAST_EXPECT(res2 == STAmount{7518784}); Number::setround(Number::towards_zero); - res2 = STAmount{issue, n.mantissa(), n.exponent()}; + res2 = STAmount{issue, n}; BEAST_EXPECT(res2 == STAmount{7518783}); Number::setround(Number::downward); - res2 = STAmount{issue, n.mantissa(), n.exponent()}; + res2 = STAmount{issue, n}; BEAST_EXPECT(res2 == STAmount{7518783}); Number::setround(Number::upward); - res2 = STAmount{issue, n.mantissa(), n.exponent()}; + res2 = STAmount{issue, n}; BEAST_EXPECT(res2 == STAmount{7518784}); } @@ -744,30 +1222,149 @@ public: BEAST_EXPECT(Number(-100, -30000).truncate() == Number(0, 0)); } + void + testRounding() + { + // Test that rounding works as expected. + testcase("Rounding"); + + using NumberRoundings = std::map; + + std::map const expected{ + // Positive numbers + {Number{13, -1}, + {{Number::to_nearest, 1}, {Number::towards_zero, 1}, {Number::downward, 1}, {Number::upward, 2}}}, + {Number{23, -1}, + {{Number::to_nearest, 2}, {Number::towards_zero, 2}, {Number::downward, 2}, {Number::upward, 3}}}, + {Number{15, -1}, + {{Number::to_nearest, 2}, {Number::towards_zero, 1}, {Number::downward, 1}, {Number::upward, 2}}}, + {Number{25, -1}, + {{Number::to_nearest, 2}, {Number::towards_zero, 2}, {Number::downward, 2}, {Number::upward, 3}}}, + {Number{152, -2}, + {{Number::to_nearest, 2}, {Number::towards_zero, 1}, {Number::downward, 1}, {Number::upward, 2}}}, + {Number{252, -2}, + {{Number::to_nearest, 3}, {Number::towards_zero, 2}, {Number::downward, 2}, {Number::upward, 3}}}, + {Number{17, -1}, + {{Number::to_nearest, 2}, {Number::towards_zero, 1}, {Number::downward, 1}, {Number::upward, 2}}}, + {Number{27, -1}, + {{Number::to_nearest, 3}, {Number::towards_zero, 2}, {Number::downward, 2}, {Number::upward, 3}}}, + + // Negative numbers + {Number{-13, -1}, + {{Number::to_nearest, -1}, {Number::towards_zero, -1}, {Number::downward, -2}, {Number::upward, -1}}}, + {Number{-23, -1}, + {{Number::to_nearest, -2}, {Number::towards_zero, -2}, {Number::downward, -3}, {Number::upward, -2}}}, + {Number{-15, -1}, + {{Number::to_nearest, -2}, {Number::towards_zero, -1}, {Number::downward, -2}, {Number::upward, -1}}}, + {Number{-25, -1}, + {{Number::to_nearest, -2}, {Number::towards_zero, -2}, {Number::downward, -3}, {Number::upward, -2}}}, + {Number{-152, -2}, + {{Number::to_nearest, -2}, {Number::towards_zero, -1}, {Number::downward, -2}, {Number::upward, -1}}}, + {Number{-252, -2}, + {{Number::to_nearest, -3}, {Number::towards_zero, -2}, {Number::downward, -3}, {Number::upward, -2}}}, + {Number{-17, -1}, + {{Number::to_nearest, -2}, {Number::towards_zero, -1}, {Number::downward, -2}, {Number::upward, -1}}}, + {Number{-27, -1}, + {{Number::to_nearest, -3}, {Number::towards_zero, -2}, {Number::downward, -3}, {Number::upward, -2}}}, + }; + + for (auto const& [num, roundings] : expected) + { + for (auto const& [mode, val] : roundings) + { + NumberRoundModeGuard g{mode}; + auto const res = static_cast(num); + BEAST_EXPECTS( + res == val, + to_string(num) + " with mode " + std::to_string(mode) + " expected " + std::to_string(val) + + " got " + std::to_string(res)); + } + } + } + + void + testInt64() + { + auto const scale = Number::getMantissaScale(); + testcase << "std::int64_t " << to_string(scale); + + // Control case + BEAST_EXPECT(Number::maxMantissa() > 10); + Number ten{10}; + BEAST_EXPECT(ten.exponent() <= 0); + + if (scale == MantissaRange::small) + { + BEAST_EXPECT(std::numeric_limits::max() > INITIAL_XRP.drops()); + BEAST_EXPECT(Number::maxMantissa() < INITIAL_XRP.drops()); + Number const initalXrp{INITIAL_XRP}; + BEAST_EXPECT(initalXrp.exponent() > 0); + + Number const maxInt64{Number::maxRep}; + BEAST_EXPECT(maxInt64.exponent() > 0); + // 85'070'591'730'234'615'865'843'651'857'942'052'864 - 38 digits + BEAST_EXPECT((power(maxInt64, 2) == Number{85'070'591'730'234'62, 22})); + + Number const max = Number{false, Number::maxMantissa(), 0, Number::normalized{}}; + BEAST_EXPECT(max.exponent() <= 0); + // 99'999'999'999'999'980'000'000'000'000'001 - 32 digits + BEAST_EXPECT((power(max, 2) == Number{99'999'999'999'999'98, 16})); + } + else + { + BEAST_EXPECT(std::numeric_limits::max() > INITIAL_XRP.drops()); + BEAST_EXPECT(Number::maxMantissa() > INITIAL_XRP.drops()); + Number const initalXrp{INITIAL_XRP}; + BEAST_EXPECT(initalXrp.exponent() <= 0); + + Number const maxInt64{Number::maxRep}; + BEAST_EXPECT(maxInt64.exponent() <= 0); + // 85'070'591'730'234'615'847'396'907'784'232'501'249 - 38 digits + BEAST_EXPECT((power(maxInt64, 2) == Number{85'070'591'730'234'615'85, 19})); + + NumberRoundModeGuard mg(Number::towards_zero); + + auto const maxMantissa = Number::maxMantissa(); + Number const max = Number{false, maxMantissa, 0, Number::normalized{}}; + BEAST_EXPECT(max.mantissa() == maxMantissa / 10); + BEAST_EXPECT(max.exponent() == 1); + // 99'999'999'999'999'999'800'000'000'000'000'000'100 - also 38 + // digits + BEAST_EXPECT((power(max, 2) == Number{false, maxMantissa / 10 - 1, 20, Number::normalized{}})); + } + } + void run() override { - testZero(); - test_limits(); - test_add(); - test_sub(); - test_mul(); - test_div(); - test_root(); - test_power1(); - test_power2(); - testConversions(); - test_to_integer(); - test_squelch(); - testToString(); - test_relationals(); - test_stream(); - test_inc_dec(); - test_toSTAmount(); - test_truncate(); + for (auto const scale : {MantissaRange::small, MantissaRange::large}) + { + NumberMantissaScaleGuard sg(scale); + testZero(); + test_limits(); + testToString(); + test_add(); + test_sub(); + test_mul(); + test_div(); + test_root(); + test_root2(); + test_power1(); + test_power2(); + testConversions(); + test_to_integer(); + test_squelch(); + test_relationals(); + test_stream(); + test_inc_dec(); + test_toSTAmount(); + test_truncate(); + testRounding(); + testInt64(); + } } }; -BEAST_DEFINE_TESTSUITE(Number, basics, ripple); +BEAST_DEFINE_TESTSUITE(Number, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/PerfLog_test.cpp b/src/test/basics/PerfLog_test.cpp index 05678e699d..57eed2aed9 100644 --- a/src/test/basics/PerfLog_test.cpp +++ b/src/test/basics/PerfLog_test.cpp @@ -1,31 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -#include #include #include #include #include +#include #include #include @@ -37,7 +18,7 @@ //------------------------------------------------------------------------------ -namespace ripple { +namespace xrpl { class PerfLog_test : public beast::unit_test::suite { @@ -47,11 +28,7 @@ class PerfLog_test : public beast::unit_test::suite // We're only using Env for its Journal. That Journal gives better // coverage in unit tests. - test::jtx::Env env_{ - *this, - test::jtx::envconfig(), - nullptr, - beast::severities::kDisabled}; + test::jtx::Env env_{*this, test::jtx::envconfig(), nullptr, beast::severities::kDisabled}; beast::Journal j_{env_.app().journal("PerfLog_test")}; struct Fixture @@ -108,10 +85,8 @@ class PerfLog_test : public beast::unit_test::suite std::unique_ptr perfLog(WithFile withFile) { - perf::PerfLog::Setup const setup{ - withFile == WithFile::no ? "" : logFile(), logInterval()}; - return perf::make_PerfLog( - setup, app_, j_, [this]() { return signalStop(); }); + perf::PerfLog::Setup const setup{withFile == WithFile::no ? "" : logFile(), logInterval()}; + return perf::make_PerfLog(setup, app_, j_, [this]() { return signalStop(); }); } // Block until the log file has grown in size, indicating that the @@ -175,20 +150,16 @@ class PerfLog_test : public beast::unit_test::suite { currents.emplace_back( jsonToUint64(cur[jss::duration_us]), - cur.isMember(jss::job) ? cur[jss::job].asString() - : cur[jss::method].asString()); + cur.isMember(jss::job) ? cur[jss::job].asString() : cur[jss::method].asString()); } // Note that the longest durations should be at the front of the // vector since they were started first. - std::sort( - currents.begin(), - currents.end(), - [](Cur const& lhs, Cur const& rhs) { - if (lhs.dur != rhs.dur) - return (rhs.dur < lhs.dur); - return (lhs.name < rhs.name); - }); + std::sort(currents.begin(), currents.end(), [](Cur const& lhs, Cur const& rhs) { + if (lhs.dur != rhs.dur) + return (rhs.dur < lhs.dur); + return (lhs.name < rhs.name); + }); return currents; } @@ -219,8 +190,7 @@ public: { // Make a file that prevents PerfLog from creating its file. std::ofstream nastyFile; - nastyFile.open( - fixture.logDir().c_str(), std::ios::out | std::ios::app); + nastyFile.open(fixture.logDir().c_str(), std::ios::out | std::ios::app); if (!BEAST_EXPECT(nastyFile)) return; nastyFile.close(); @@ -258,24 +228,20 @@ public: return; auto fileWriteable = [](boost::filesystem::path const& p) -> bool { - return std::ofstream{p.c_str(), std::ios::out | std::ios::app} - .is_open(); + return std::ofstream{p.c_str(), std::ios::out | std::ios::app}.is_open(); }; if (!BEAST_EXPECT(fileWriteable(fixture.logFile()))) return; boost::filesystem::permissions( - fixture.logFile(), - perms::remove_perms | perms::owner_write | perms::others_write | - perms::group_write); + fixture.logFile(), perms::remove_perms | perms::owner_write | perms::others_write | perms::group_write); // If the test is running as root, then the write protect may have // no effect. Make sure write protect worked before proceeding. if (fileWriteable(fixture.logFile())) { - log << "Unable to write protect file. Test skipped." - << std::endl; + log << "Unable to write protect file. Test skipped." << std::endl; return; } @@ -294,9 +260,7 @@ public: // Fix file permissions so the file can be cleaned up. boost::filesystem::permissions( - fixture.logFile(), - perms::add_perms | perms::owner_write | perms::others_write | - perms::group_write); + fixture.logFile(), perms::add_perms | perms::owner_write | perms::others_write | perms::group_write); } } @@ -311,8 +275,7 @@ public: // Get the all the labels we can use for RPC interfaces without // causing an assert. - std::vector labels = - test::jtx::make_vector(ripple::RPC::getHandlerNames()); + std::vector labels = test::jtx::make_vector(xrpl::RPC::getHandlerNames()); std::shuffle(labels.begin(), labels.end(), default_prng()); // Get two IDs to associate with each label. Errors tend to happen at @@ -321,15 +284,11 @@ public: std::vector ids; ids.reserve(labels.size() * 2); std::generate_n( - std::back_inserter(ids), - labels.size(), - [i = std::numeric_limits::min()]() mutable { + std::back_inserter(ids), labels.size(), [i = std::numeric_limits::min()]() mutable { return i++; }); std::generate_n( - std::back_inserter(ids), - labels.size(), - [i = std::numeric_limits::max()]() mutable { + std::back_inserter(ids), labels.size(), [i = std::numeric_limits::max()]() mutable { return i--; }); std::shuffle(ids.begin(), ids.end(), default_prng()); @@ -341,8 +300,7 @@ public: for (int idIndex = 0; idIndex < 2; ++idIndex) { std::this_thread::sleep_for(std::chrono::microseconds(10)); - perfLog->rpcStart( - labels[labelIndex], ids[(labelIndex * 2) + idIndex]); + perfLog->rpcStart(labels[labelIndex], ids[(labelIndex * 2) + idIndex]); } } { @@ -369,8 +327,7 @@ public: // Verify that every entry in labels appears twice in currents. // If we sort by duration_us they should be in the order the // rpcStart() call was made. - std::vector const currents{ - getSortedCurrent(perfLog->currentJson()[jss::methods])}; + std::vector const currents{getSortedCurrent(perfLog->currentJson()[jss::methods])}; BEAST_EXPECT(currents.size() == labels.size() * 2); std::uint64_t prevDur = std::numeric_limits::max(); @@ -395,8 +352,7 @@ public: perfLog->rpcFinish(labels[0], ids[0 + 1]); // Note that label[0] id[0] is intentionally left unfinished. - auto validateFinalCounters = [this, &labels]( - Json::Value const& countersJson) { + auto validateFinalCounters = [this, &labels](Json::Value const& countersJson) { { Json::Value const& jobQueue = countersJson[jss::job_queue]; BEAST_EXPECT(jobQueue.isObject()); @@ -423,8 +379,7 @@ public: for (int i = 1; i < labels.size(); ++i) { Json::Value const& counter{rpc[labels[i]]}; - std::uint64_t const dur{ - jsonToUint64(counter[jss::duration_us])}; + std::uint64_t const dur{jsonToUint64(counter[jss::duration_us])}; BEAST_EXPECT(dur != 0 && dur < prevDur); prevDur = dur; BEAST_EXPECT(counter[jss::errored] == "1"); @@ -435,15 +390,12 @@ public: // Check "total" Json::Value const& total{rpc[jss::total]}; BEAST_EXPECT(total[jss::duration_us] != "0"); - BEAST_EXPECT( - jsonToUint64(total[jss::errored]) == labels.size() - 1); + BEAST_EXPECT(jsonToUint64(total[jss::errored]) == labels.size() - 1); BEAST_EXPECT(jsonToUint64(total[jss::finished]) == labels.size()); - BEAST_EXPECT( - jsonToUint64(total[jss::started]) == labels.size() * 2); + BEAST_EXPECT(jsonToUint64(total[jss::started]) == labels.size() * 2); }; - auto validateFinalCurrent = [this, - &labels](Json::Value const& currentJson) { + auto validateFinalCurrent = [this, &labels](Json::Value const& currentJson) { { Json::Value const& job_queue = currentJson[jss::jobs]; BEAST_EXPECT(job_queue.isArray()); @@ -522,8 +474,7 @@ public: JobType type; std::string typeName; - JobName(JobType t, std::string name) - : type(t), typeName(std::move(name)) + JobName(JobType t, std::string name) : type(t), typeName(std::move(name)) { } }; @@ -544,8 +495,7 @@ public: for (int i = 0; i < jobs.size(); ++i) { perfLog->jobQueue(jobs[i].type); - Json::Value const jq_counters{ - perfLog->countersJson()[jss::job_queue]}; + Json::Value const jq_counters{perfLog->countersJson()[jss::job_queue]}; BEAST_EXPECT(jq_counters.size() == i + 2); for (int j = 0; j <= i; ++j) @@ -592,18 +542,15 @@ public: // be half as many queued as started... for (int i = 0; i < jobs.size(); ++i) { - perfLog->jobStart( - jobs[i].type, microseconds{i + 1}, steady_clock::now(), i * 2); + perfLog->jobStart(jobs[i].type, microseconds{i + 1}, steady_clock::now(), i * 2); std::this_thread::sleep_for(microseconds(10)); // Check each jobType counter entry. - Json::Value const jq_counters{ - perfLog->countersJson()[jss::job_queue]}; + Json::Value const jq_counters{perfLog->countersJson()[jss::job_queue]}; for (int j = 0; j < jobs.size(); ++j) { Json::Value const& counter{jq_counters[jobs[j].typeName]}; - std::uint64_t const queued_dur_us{ - jsonToUint64(counter[jss::queued_duration_us])}; + std::uint64_t const queued_dur_us{jsonToUint64(counter[jss::queued_duration_us])}; if (j < i) { BEAST_EXPECT(counter[jss::started] == "2"); @@ -632,24 +579,17 @@ public: BEAST_EXPECT(total[jss::finished] == "0"); // Total queued duration is triangle number of (i + 1). - BEAST_EXPECT( - jsonToUint64(total[jss::queued_duration_us]) == - (((i * i) + 3 * i + 2) / 2)); + BEAST_EXPECT(jsonToUint64(total[jss::queued_duration_us]) == (((i * i) + 3 * i + 2) / 2)); BEAST_EXPECT(total[jss::running_duration_us] == "0"); } - perfLog->jobStart( - jobs[i].type, - microseconds{0}, - steady_clock::now(), - (i * 2) + 1); + perfLog->jobStart(jobs[i].type, microseconds{0}, steady_clock::now(), (i * 2) + 1); std::this_thread::sleep_for(microseconds{10}); // Verify that every entry in jobs appears twice in currents. // If we sort by duration_us they should be in the order the // rpcStart() call was made. - std::vector const currents{ - getSortedCurrent(perfLog->currentJson()[jss::jobs])}; + std::vector const currents{getSortedCurrent(perfLog->currentJson()[jss::jobs])}; BEAST_EXPECT(currents.size() == (i + 1) * 2); std::uint64_t prevDur = std::numeric_limits::max(); @@ -671,17 +611,14 @@ public: // A number of the computations in this loop care about the // number of jobs that have finished. Make that available. int const finished = ((jobs.size() - i) * 2) - 1; - perfLog->jobFinish( - jobs[i].type, microseconds(finished), (i * 2) + 1); + perfLog->jobFinish(jobs[i].type, microseconds(finished), (i * 2) + 1); std::this_thread::sleep_for(microseconds(10)); - Json::Value const jq_counters{ - perfLog->countersJson()[jss::job_queue]}; + Json::Value const jq_counters{perfLog->countersJson()[jss::job_queue]}; for (int j = 0; j < jobs.size(); ++j) { Json::Value const& counter{jq_counters[jobs[j].typeName]}; - std::uint64_t const running_dur_us{ - jsonToUint64(counter[jss::running_duration_us])}; + std::uint64_t const running_dur_us{jsonToUint64(counter[jss::running_duration_us])}; if (j < i) { BEAST_EXPECT(counter[jss::finished] == "0"); @@ -698,8 +635,7 @@ public: BEAST_EXPECT(running_dur_us == ((jobs.size() - j) * 4) - 1); } - std::uint64_t const queued_dur_us{ - jsonToUint64(counter[jss::queued_duration_us])}; + std::uint64_t const queued_dur_us{jsonToUint64(counter[jss::queued_duration_us])}; BEAST_EXPECT(queued_dur_us == j + 1); BEAST_EXPECT(counter[jss::queued] == "1"); BEAST_EXPECT(counter[jss::started] == "2"); @@ -708,31 +644,25 @@ public: // Verify values in jss::total are what we expect. Json::Value const& total{jq_counters[jss::total]}; BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size()); - BEAST_EXPECT( - jsonToUint64(total[jss::started]) == jobs.size() * 2); + BEAST_EXPECT(jsonToUint64(total[jss::started]) == jobs.size() * 2); BEAST_EXPECT(jsonToUint64(total[jss::finished]) == finished); // Total queued duration should be triangle number of // jobs.size(). int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2); - BEAST_EXPECT( - jsonToUint64(total[jss::queued_duration_us]) == queuedDur); + BEAST_EXPECT(jsonToUint64(total[jss::queued_duration_us]) == queuedDur); // Total running duration should be triangle number of finished. int const runningDur = ((finished * (finished + 1)) / 2); - BEAST_EXPECT( - jsonToUint64(total[jss::running_duration_us]) == - runningDur); + BEAST_EXPECT(jsonToUint64(total[jss::running_duration_us]) == runningDur); } - perfLog->jobFinish( - jobs[i].type, microseconds(finished + 1), (i * 2)); + perfLog->jobFinish(jobs[i].type, microseconds(finished + 1), (i * 2)); std::this_thread::sleep_for(microseconds(10)); // Verify that the two jobs we just finished no longer appear in // currents. - std::vector const currents{ - getSortedCurrent(perfLog->currentJson()[jss::jobs])}; + std::vector const currents{getSortedCurrent(perfLog->currentJson()[jss::jobs])}; BEAST_EXPECT(currents.size() == i * 2); std::uint64_t prevDur = std::numeric_limits::max(); @@ -749,8 +679,7 @@ public: } // Validate the final results. - auto validateFinalCounters = [this, - &jobs](Json::Value const& countersJson) { + auto validateFinalCounters = [this, &jobs](Json::Value const& countersJson) { { Json::Value const& rpc = countersJson[jss::rpc]; BEAST_EXPECT(rpc.isObject()); @@ -761,12 +690,10 @@ public: for (int i = jobs.size() - 1; i >= 0; --i) { Json::Value const& counter{jobQueue[jobs[i].typeName]}; - std::uint64_t const running_dur_us{ - jsonToUint64(counter[jss::running_duration_us])}; + std::uint64_t const running_dur_us{jsonToUint64(counter[jss::running_duration_us])}; BEAST_EXPECT(running_dur_us == ((jobs.size() - i) * 4) - 1); - std::uint64_t const queued_dur_us{ - jsonToUint64(counter[jss::queued_duration_us])}; + std::uint64_t const queued_dur_us{jsonToUint64(counter[jss::queued_duration_us])}; BEAST_EXPECT(queued_dur_us == i + 1); BEAST_EXPECT(counter[jss::queued] == "1"); @@ -784,13 +711,11 @@ public: // Total queued duration should be triangle number of // jobs.size(). int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2); - BEAST_EXPECT( - jsonToUint64(total[jss::queued_duration_us]) == queuedDur); + BEAST_EXPECT(jsonToUint64(total[jss::queued_duration_us]) == queuedDur); // Total running duration should be triangle number of finished. int const runningDur = ((finished * (finished + 1)) / 2); - BEAST_EXPECT( - jsonToUint64(total[jss::running_duration_us]) == runningDur); + BEAST_EXPECT(jsonToUint64(total[jss::running_duration_us]) == runningDur); }; auto validateFinalCurrent = [this](Json::Value const& currentJson) { @@ -880,37 +805,31 @@ public: perfLog->resizeJobs(1); // Lambda to validate countersJson for this test. - auto verifyCounters = [this, jobTypeName]( - Json::Value const& countersJson, - int started, - int finished, - int queued_us, - int running_us) { - BEAST_EXPECT(countersJson.isObject()); - BEAST_EXPECT(countersJson.size() == 2); + auto verifyCounters = + [this, jobTypeName]( + Json::Value const& countersJson, int started, int finished, int queued_us, int running_us) { + BEAST_EXPECT(countersJson.isObject()); + BEAST_EXPECT(countersJson.size() == 2); - BEAST_EXPECT(countersJson.isMember(jss::rpc)); - BEAST_EXPECT(countersJson[jss::rpc].isObject()); - BEAST_EXPECT(countersJson[jss::rpc].size() == 0); + BEAST_EXPECT(countersJson.isMember(jss::rpc)); + BEAST_EXPECT(countersJson[jss::rpc].isObject()); + BEAST_EXPECT(countersJson[jss::rpc].size() == 0); - BEAST_EXPECT(countersJson.isMember(jss::job_queue)); - BEAST_EXPECT(countersJson[jss::job_queue].isObject()); - BEAST_EXPECT(countersJson[jss::job_queue].size() == 1); - { - Json::Value const& job{ - countersJson[jss::job_queue][jobTypeName]}; + BEAST_EXPECT(countersJson.isMember(jss::job_queue)); + BEAST_EXPECT(countersJson[jss::job_queue].isObject()); + BEAST_EXPECT(countersJson[jss::job_queue].size() == 1); + { + Json::Value const& job{countersJson[jss::job_queue][jobTypeName]}; - BEAST_EXPECT(job.isObject()); - BEAST_EXPECT(jsonToUint64(job[jss::queued]) == 0); - BEAST_EXPECT(jsonToUint64(job[jss::started]) == started); - BEAST_EXPECT(jsonToUint64(job[jss::finished]) == finished); + BEAST_EXPECT(job.isObject()); + BEAST_EXPECT(jsonToUint64(job[jss::queued]) == 0); + BEAST_EXPECT(jsonToUint64(job[jss::started]) == started); + BEAST_EXPECT(jsonToUint64(job[jss::finished]) == finished); - BEAST_EXPECT( - jsonToUint64(job[jss::queued_duration_us]) == queued_us); - BEAST_EXPECT( - jsonToUint64(job[jss::running_duration_us]) == running_us); - } - }; + BEAST_EXPECT(jsonToUint64(job[jss::queued_duration_us]) == queued_us); + BEAST_EXPECT(jsonToUint64(job[jss::running_duration_us]) == running_us); + } + }; // Lambda to validate currentJson (always empty) for this test. auto verifyEmptyCurrent = [this](Json::Value const& currentJson) { @@ -1061,6 +980,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(PerfLog, basics, ripple); +BEAST_DEFINE_TESTSUITE(PerfLog, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/StringUtilities_test.cpp b/src/test/basics/StringUtilities_test.cpp index b3fac22b42..65134da8e5 100644 --- a/src/test/basics/StringUtilities_test.cpp +++ b/src/test/basics/StringUtilities_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { class StringUtilities_test : public beast::unit_test::suite { @@ -139,8 +120,7 @@ public: { parsedURL pUrl; - BEAST_EXPECT( - parseUrl(pUrl, "scheme://user:pass@domain:123/abc:321")); + BEAST_EXPECT(parseUrl(pUrl, "scheme://user:pass@domain:123/abc:321")); BEAST_EXPECT(pUrl.scheme == "scheme"); BEAST_EXPECT(pUrl.username == "user"); BEAST_EXPECT(pUrl.password == "pass"); @@ -239,8 +219,7 @@ public: { parsedURL pUrl; - BEAST_EXPECT( - parseUrl(pUrl, "scheme://user:pass@domain/path/with/an@sign")); + BEAST_EXPECT(parseUrl(pUrl, "scheme://user:pass@domain/path/with/an@sign")); BEAST_EXPECT(pUrl.scheme == "scheme"); BEAST_EXPECT(pUrl.username == "user"); BEAST_EXPECT(pUrl.password == "pass"); @@ -289,8 +268,7 @@ public: BEAST_EXPECT(!parseUrl(pUrl, "nonsense")); BEAST_EXPECT(!parseUrl(pUrl, "://")); BEAST_EXPECT(!parseUrl(pUrl, ":///")); - BEAST_EXPECT( - !parseUrl(pUrl, "scheme://user:pass@domain:65536/abc:321")); + BEAST_EXPECT(!parseUrl(pUrl, "scheme://user:pass@domain:65536/abc:321")); BEAST_EXPECT(!parseUrl(pUrl, "UPPER://domain:23498765/")); BEAST_EXPECT(!parseUrl(pUrl, "UPPER://domain:0/")); BEAST_EXPECT(!parseUrl(pUrl, "UPPER://domain:+7/")); @@ -322,6 +300,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(StringUtilities, basics, ripple); +BEAST_DEFINE_TESTSUITE(StringUtilities, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/TaggedCache_test.cpp b/src/test/basics/TaggedCache_test.cpp index 3d3dba698d..78dc25380b 100644 --- a/src/test/basics/TaggedCache_test.cpp +++ b/src/test/basics/TaggedCache_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { /* I guess you can put some items in, make sure they're still there. Let some @@ -151,6 +132,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(TaggedCache, basics, ripple); +BEAST_DEFINE_TESTSUITE(TaggedCache, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/Units_test.cpp b/src/test/basics/Units_test.cpp index 33dce42abb..9094730870 100644 --- a/src/test/basics/Units_test.cpp +++ b/src/test/basics/Units_test.cpp @@ -1,26 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class units_test : public beast::unit_test::suite @@ -34,17 +16,14 @@ private: { XRPAmount x{100}; BEAST_EXPECT(x.drops() == 100); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); auto y = 4u * x; BEAST_EXPECT(y.value() == 400); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); auto z = 4 * y; BEAST_EXPECT(z.value() == 1600); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); FeeLevel32 f{10}; FeeLevel32 baseFee{100}; @@ -53,23 +32,17 @@ private: BEAST_EXPECT(drops); BEAST_EXPECT(drops.value() == 1000); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t::unit_type, - unit::dropTag>)); + BEAST_EXPECT((std::is_same_v::unit_type, unit::dropTag>)); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t, - XRPAmount>)); + BEAST_EXPECT((std::is_same_v, XRPAmount>)); } { XRPAmount x{100}; BEAST_EXPECT(x.value() == 100); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); auto y = 4u * x; BEAST_EXPECT(y.value() == 400); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); FeeLevel64 f{10}; FeeLevel64 baseFee{100}; @@ -78,23 +51,17 @@ private: BEAST_EXPECT(drops); BEAST_EXPECT(drops.value() == 1000); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t::unit_type, - unit::dropTag>)); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t, - XRPAmount>)); + BEAST_EXPECT((std::is_same_v::unit_type, unit::dropTag>)); + BEAST_EXPECT((std::is_same_v, XRPAmount>)); } { FeeLevel64 x{1024}; BEAST_EXPECT(x.value() == 1024); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); std::uint64_t m = 4; auto y = m * x; BEAST_EXPECT(y.value() == 4096); - BEAST_EXPECT( - (std::is_same_v)); + BEAST_EXPECT((std::is_same_v)); XRPAmount basefee{10}; FeeLevel64 referencefee{256}; @@ -103,12 +70,8 @@ private: BEAST_EXPECT(drops); BEAST_EXPECT(drops.value() == 40); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t::unit_type, - unit::dropTag>)); - BEAST_EXPECT((std::is_same_v< - std::remove_reference_t, - XRPAmount>)); + BEAST_EXPECT((std::is_same_v::unit_type, unit::dropTag>)); + BEAST_EXPECT((std::is_same_v, XRPAmount>)); } } @@ -136,8 +99,7 @@ private: FeeLevel64 x{std::numeric_limits::max()}; auto y = x.jsonClipped(); BEAST_EXPECT(y.type() == Json::uintValue); - BEAST_EXPECT( - y == Json::Value{std::numeric_limits::max()}); + BEAST_EXPECT(y == Json::Value{std::numeric_limits::max()}); } { @@ -165,16 +127,14 @@ private: XRPAmount x{std::numeric_limits::max()}; auto y = x.jsonClipped(); BEAST_EXPECT(y.type() == Json::intValue); - BEAST_EXPECT( - y == Json::Value{std::numeric_limits::max()}); + BEAST_EXPECT(y == Json::Value{std::numeric_limits::max()}); } { XRPAmount x{std::numeric_limits::min()}; auto y = x.jsonClipped(); BEAST_EXPECT(y.type() == Json::intValue); - BEAST_EXPECT( - y == Json::Value{std::numeric_limits::min()}); + BEAST_EXPECT(y == Json::Value{std::numeric_limits::min()}); } } @@ -187,9 +147,7 @@ private: { auto make = [&](auto x) -> FeeLevel64 { return x; }; - auto explicitmake = [&](auto x) -> FeeLevel64 { - return FeeLevel64{x}; - }; + auto explicitmake = [&](auto x) -> FeeLevel64 { return FeeLevel64{x}; }; [[maybe_unused]] FeeLevel64 defaulted; @@ -274,9 +232,7 @@ private: } { auto make = [&](auto x) -> FeeLevelDouble { return x; }; - auto explicitmake = [&](auto x) -> FeeLevelDouble { - return FeeLevelDouble{x}; - }; + auto explicitmake = [&](auto x) -> FeeLevelDouble { return FeeLevelDouble{x}; }; [[maybe_unused]] FeeLevelDouble defaulted; @@ -371,7 +327,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(units, basics, ripple); +BEAST_DEFINE_TESTSUITE(units, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index 452ab80dda..391917e678 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class XRPAmount_test : public beast::unit_test::suite { @@ -222,10 +203,8 @@ public: testcase("mulRatio"); constexpr auto maxUInt32 = std::numeric_limits::max(); - constexpr auto maxXRP = - std::numeric_limits::max(); - constexpr auto minXRP = - std::numeric_limits::min(); + constexpr auto maxXRP = std::numeric_limits::max(); + constexpr auto minXRP = std::numeric_limits::min(); { // multiply by a number that would overflow then divide by the same @@ -237,11 +216,9 @@ public: // multiply and divide by values that would overflow if done // naively, and check that it gives the correct answer - big -= 0xf; // Subtract a little so it's divisable by 4 - BEAST_EXPECT( - mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3); - BEAST_EXPECT( - mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3); + big -= 0xf; // Subtract a little so it's divisible by 4 + BEAST_EXPECT(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3); + BEAST_EXPECT(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3); BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3); } @@ -254,10 +231,8 @@ public: // multiply and divide by values that would overflow if done // naively, and check that it gives the correct answer - BEAST_EXPECT( - mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3); - BEAST_EXPECT( - mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3); + BEAST_EXPECT(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3); + BEAST_EXPECT(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3); BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3); } @@ -268,44 +243,36 @@ public: BEAST_EXPECT(tiny == mulRatio(tiny, 1, maxUInt32, true)); // rounding down should be zero BEAST_EXPECT(beast::zero == mulRatio(tiny, 1, maxUInt32, false)); - BEAST_EXPECT( - beast::zero == mulRatio(tiny, maxUInt32 - 1, maxUInt32, false)); + BEAST_EXPECT(beast::zero == mulRatio(tiny, maxUInt32 - 1, maxUInt32, false)); // tiny negative numbers XRPAmount tinyNeg(-1); // Round up should give zero BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, 1, maxUInt32, true)); - BEAST_EXPECT( - beast::zero == - mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, true)); + BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, true)); // rounding down should be tiny - BEAST_EXPECT( - tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false)); + BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false)); } { // rounding { XRPAmount one(1); auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true); - auto const rdown = - mulRatio(one, maxUInt32 - 1, maxUInt32, false); + auto const rdown = mulRatio(one, maxUInt32 - 1, maxUInt32, false); BEAST_EXPECT(rup.drops() - rdown.drops() == 1); } { XRPAmount big(maxXRP); auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true); - auto const rdown = - mulRatio(big, maxUInt32 - 1, maxUInt32, false); + auto const rdown = mulRatio(big, maxUInt32 - 1, maxUInt32, false); BEAST_EXPECT(rup.drops() - rdown.drops() == 1); } { XRPAmount negOne(-1); - auto const rup = - mulRatio(negOne, maxUInt32 - 1, maxUInt32, true); - auto const rdown = - mulRatio(negOne, maxUInt32 - 1, maxUInt32, false); + auto const rup = mulRatio(negOne, maxUInt32 - 1, maxUInt32, true); + auto const rdown = mulRatio(negOne, maxUInt32 - 1, maxUInt32, false); BEAST_EXPECT(rup.drops() - rdown.drops() == 1); } } @@ -327,7 +294,7 @@ public: XRPAmount bigNegative(minXRP + 10); BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP); } - } // namespace ripple + } // namespace xrpl //-------------------------------------------------------------------------- @@ -344,6 +311,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(XRPAmount, basics, ripple); +BEAST_DEFINE_TESTSUITE(XRPAmount, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/base58_test.cpp b/src/test/basics/base58_test.cpp index 590f19a44e..5da22d533e 100644 --- a/src/test/basics/base58_test.cpp +++ b/src/test/basics/base58_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #ifndef _MSC_VER #include @@ -32,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace { @@ -49,13 +30,13 @@ randEngine() -> std::mt19937& constexpr int numTokenTypeIndexes = 9; [[nodiscard]] inline auto -tokenTypeAndSize(int i) -> std::tuple +tokenTypeAndSize(int i) -> std::tuple { assert(i < numTokenTypeIndexes); switch (i) { - using enum ripple::TokenType; + using enum xrpl::TokenType; case 0: return {None, 20}; case 1: @@ -82,9 +63,9 @@ tokenTypeAndSize(int i) -> std::tuple } [[nodiscard]] inline auto -randomTokenTypeAndSize() -> std::tuple +randomTokenTypeAndSize() -> std::tuple { - using namespace ripple; + using namespace xrpl; auto& rng = randEngine(); std::uniform_int_distribution<> d(0, 8); return tokenTypeAndSize(d(rng)); @@ -92,8 +73,7 @@ randomTokenTypeAndSize() -> std::tuple // Return the token type and subspan of `d` to use as test data. [[nodiscard]] inline auto -randomB256TestData(std::span d) - -> std::tuple> +randomB256TestData(std::span d) -> std::tuple> { auto& rng = randEngine(); std::uniform_int_distribution dist(0, 255); @@ -184,14 +164,14 @@ class base58_test : public beast::unit_test::suite if (!d) continue; auto bigInt = multiprecision_utils::randomBigInt(); - auto const boostBigInt = multiprecision_utils::toBoostMP( - std::span(bigInt.data(), bigInt.size())); + auto const boostBigInt = + multiprecision_utils::toBoostMP(std::span(bigInt.data(), bigInt.size())); auto const refDiv = boostBigInt / d; auto const refMod = boostBigInt % d; - auto const mod = b58_fast::detail::inplace_bigint_div_rem( - std::span(bigInt.data(), bigInt.size()), d); + auto const mod = + b58_fast::detail::inplace_bigint_div_rem(std::span(bigInt.data(), bigInt.size()), d); auto const foundDiv = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refMod.convert_to() == mod); BEAST_EXPECT(foundDiv == refDiv); @@ -200,18 +180,17 @@ class base58_test : public beast::unit_test::suite { std::uint64_t const d = dist(eng); auto bigInt = multiprecision_utils::randomBigInt(/*minSize*/ 2); - if (bigInt[bigInt.size() - 1] == - std::numeric_limits::max()) + if (bigInt[bigInt.size() - 1] == std::numeric_limits::max()) { bigInt[bigInt.size() - 1] -= 1; // Prevent overflow } - auto const boostBigInt = multiprecision_utils::toBoostMP( - std::span(bigInt.data(), bigInt.size())); + auto const boostBigInt = + multiprecision_utils::toBoostMP(std::span(bigInt.data(), bigInt.size())); auto const refAdd = boostBigInt + d; - auto const result = b58_fast::detail::inplace_bigint_add( - std::span(bigInt.data(), bigInt.size()), d); + auto const result = + b58_fast::detail::inplace_bigint_add(std::span(bigInt.data(), bigInt.size()), d); BEAST_EXPECT(result == TokenCodecErrc::success); auto const foundAdd = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refAdd == foundAdd); @@ -220,16 +199,15 @@ class base58_test : public beast::unit_test::suite { std::uint64_t const d = dist1(eng); // Force overflow - std::vector bigInt( - 5, std::numeric_limits::max()); + std::vector bigInt(5, std::numeric_limits::max()); - auto const boostBigInt = multiprecision_utils::toBoostMP( - std::span(bigInt.data(), bigInt.size())); + auto const boostBigInt = + multiprecision_utils::toBoostMP(std::span(bigInt.data(), bigInt.size())); auto const refAdd = boostBigInt + d; - auto const result = b58_fast::detail::inplace_bigint_add( - std::span(bigInt.data(), bigInt.size()), d); + auto const result = + b58_fast::detail::inplace_bigint_add(std::span(bigInt.data(), bigInt.size()), d); BEAST_EXPECT(result == TokenCodecErrc::overflowAdd); auto const foundAdd = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refAdd != foundAdd); @@ -241,13 +219,13 @@ class base58_test : public beast::unit_test::suite // inplace mul requires the most significant coeff to be zero to // hold the result. bigInt[bigInt.size() - 1] = 0; - auto const boostBigInt = multiprecision_utils::toBoostMP( - std::span(bigInt.data(), bigInt.size())); + auto const boostBigInt = + multiprecision_utils::toBoostMP(std::span(bigInt.data(), bigInt.size())); auto const refMul = boostBigInt * d; - auto const result = b58_fast::detail::inplace_bigint_mul( - std::span(bigInt.data(), bigInt.size()), d); + auto const result = + b58_fast::detail::inplace_bigint_mul(std::span(bigInt.data(), bigInt.size()), d); BEAST_EXPECT(result == TokenCodecErrc::success); auto const foundMul = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refMul == foundMul); @@ -256,15 +234,14 @@ class base58_test : public beast::unit_test::suite { std::uint64_t const d = dist1(eng); // Force overflow - std::vector bigInt( - 5, std::numeric_limits::max()); - auto const boostBigInt = multiprecision_utils::toBoostMP( - std::span(bigInt.data(), bigInt.size())); + std::vector bigInt(5, std::numeric_limits::max()); + auto const boostBigInt = + multiprecision_utils::toBoostMP(std::span(bigInt.data(), bigInt.size())); auto const refMul = boostBigInt * d; - auto const result = b58_fast::detail::inplace_bigint_mul( - std::span(bigInt.data(), bigInt.size()), d); + auto const result = + b58_fast::detail::inplace_bigint_mul(std::span(bigInt.data(), bigInt.size()), d); BEAST_EXPECT(result == TokenCodecErrc::inputTooLarge); auto const foundMul = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refMul != foundMul); @@ -286,19 +263,15 @@ class base58_test : public beast::unit_test::suite std::span const outBuf{b58ResultBuf[i]}; if (i == 0) { - auto const r = ripple::b58_fast::detail::b256_to_b58_be( - b256Data, outBuf); + auto const r = xrpl::b58_fast::detail::b256_to_b58_be(b256Data, outBuf); BEAST_EXPECT(r); b58Result[i] = r.value(); } else { std::array tmpBuf; - std::string const s = ripple::b58_ref::detail::encodeBase58( - b256Data.data(), - b256Data.size(), - tmpBuf.data(), - tmpBuf.size()); + std::string const s = xrpl::b58_ref::detail::encodeBase58( + b256Data.data(), b256Data.size(), tmpBuf.data(), tmpBuf.size()); BEAST_EXPECT(s.size()); b58Result[i] = outBuf.subspan(0, s.size()); std::copy(s.begin(), s.end(), b58Result[i].begin()); @@ -306,11 +279,7 @@ class base58_test : public beast::unit_test::suite } if (BEAST_EXPECT(b58Result[0].size() == b58Result[1].size())) { - if (!BEAST_EXPECT( - memcmp( - b58Result[0].data(), - b58Result[1].data(), - b58Result[0].size()) == 0)) + if (!BEAST_EXPECT(memcmp(b58Result[0].data(), b58Result[1].data(), b58Result[0].size()) == 0)) { printAsChar(b58Result[0], b58Result[1]); } @@ -318,24 +287,18 @@ class base58_test : public beast::unit_test::suite for (int i = 0; i < 2; ++i) { - std::span const outBuf{ - b256ResultBuf[i].data(), b256ResultBuf[i].size()}; + std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()}; if (i == 0) { - std::string const in( - b58Result[i].data(), - b58Result[i].data() + b58Result[i].size()); - auto const r = - ripple::b58_fast::detail::b58_to_b256_be(in, outBuf); + std::string const in(b58Result[i].data(), b58Result[i].data() + b58Result[i].size()); + auto const r = xrpl::b58_fast::detail::b58_to_b256_be(in, outBuf); BEAST_EXPECT(r); b256Result[i] = r.value(); } else { - std::string const st( - b58Result[i].begin(), b58Result[i].end()); - std::string const s = - ripple::b58_ref::detail::decodeBase58(st); + std::string const st(b58Result[i].begin(), b58Result[i].end()); + std::string const s = xrpl::b58_ref::detail::decodeBase58(st); BEAST_EXPECT(s.size()); b256Result[i] = outBuf.subspan(0, s.size()); std::copy(s.begin(), s.end(), b256Result[i].begin()); @@ -344,19 +307,14 @@ class base58_test : public beast::unit_test::suite if (BEAST_EXPECT(b256Result[0].size() == b256Result[1].size())) { - if (!BEAST_EXPECT( - memcmp( - b256Result[0].data(), - b256Result[1].data(), - b256Result[0].size()) == 0)) + if (!BEAST_EXPECT(memcmp(b256Result[0].data(), b256Result[1].data(), b256Result[0].size()) == 0)) { printAsInt(b256Result[0], b256Result[1]); } } }; - auto testTokenEncode = [&](ripple::TokenType const tokType, - std::span const& b256Data) { + auto testTokenEncode = [&](xrpl::TokenType const tokType, std::span const& b256Data) { std::array b58ResultBuf[2]; std::array, 2> b58Result; @@ -364,19 +322,16 @@ class base58_test : public beast::unit_test::suite std::array, 2> b256Result; for (int i = 0; i < 2; ++i) { - std::span const outBuf{ - b58ResultBuf[i].data(), b58ResultBuf[i].size()}; + std::span const outBuf{b58ResultBuf[i].data(), b58ResultBuf[i].size()}; if (i == 0) { - auto const r = ripple::b58_fast::encodeBase58Token( - tokType, b256Data, outBuf); + auto const r = xrpl::b58_fast::encodeBase58Token(tokType, b256Data, outBuf); BEAST_EXPECT(r); b58Result[i] = r.value(); } else { - std::string const s = ripple::b58_ref::encodeBase58Token( - tokType, b256Data.data(), b256Data.size()); + std::string const s = xrpl::b58_ref::encodeBase58Token(tokType, b256Data.data(), b256Data.size()); BEAST_EXPECT(s.size()); b58Result[i] = outBuf.subspan(0, s.size()); std::copy(s.begin(), s.end(), b58Result[i].begin()); @@ -384,11 +339,7 @@ class base58_test : public beast::unit_test::suite } if (BEAST_EXPECT(b58Result[0].size() == b58Result[1].size())) { - if (!BEAST_EXPECT( - memcmp( - b58Result[0].data(), - b58Result[1].data(), - b58Result[0].size()) == 0)) + if (!BEAST_EXPECT(memcmp(b58Result[0].data(), b58Result[1].data(), b58Result[0].size()) == 0)) { printAsChar(b58Result[0], b58Result[1]); } @@ -396,24 +347,18 @@ class base58_test : public beast::unit_test::suite for (int i = 0; i < 2; ++i) { - std::span const outBuf{ - b256ResultBuf[i].data(), b256ResultBuf[i].size()}; + std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()}; if (i == 0) { - std::string const in( - b58Result[i].data(), - b58Result[i].data() + b58Result[i].size()); - auto const r = ripple::b58_fast::decodeBase58Token( - tokType, in, outBuf); + std::string const in(b58Result[i].data(), b58Result[i].data() + b58Result[i].size()); + auto const r = xrpl::b58_fast::decodeBase58Token(tokType, in, outBuf); BEAST_EXPECT(r); b256Result[i] = r.value(); } else { - std::string const st( - b58Result[i].begin(), b58Result[i].end()); - std::string const s = - ripple::b58_ref::decodeBase58Token(st, tokType); + std::string const st(b58Result[i].begin(), b58Result[i].end()); + std::string const s = xrpl::b58_ref::decodeBase58Token(st, tokType); BEAST_EXPECT(s.size()); b256Result[i] = outBuf.subspan(0, s.size()); std::copy(s.begin(), s.end(), b256Result[i].begin()); @@ -422,19 +367,14 @@ class base58_test : public beast::unit_test::suite if (BEAST_EXPECT(b256Result[0].size() == b256Result[1].size())) { - if (!BEAST_EXPECT( - memcmp( - b256Result[0].data(), - b256Result[1].data(), - b256Result[0].size()) == 0)) + if (!BEAST_EXPECT(memcmp(b256Result[0].data(), b256Result[1].data(), b256Result[0].size()) == 0)) { printAsInt(b256Result[0], b256Result[1]); } } }; - auto testIt = [&](ripple::TokenType const tokType, - std::span const& b256Data) { + auto testIt = [&](xrpl::TokenType const tokType, std::span const& b256Data) { testRawEncode(b256Data); testTokenEncode(tokType, b256Data); }; @@ -470,8 +410,8 @@ class base58_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(base58, basics, ripple); +BEAST_DEFINE_TESTSUITE(base58, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl #endif // _MSC_VER diff --git a/src/test/basics/base_uint_test.cpp b/src/test/basics/base_uint_test.cpp index 458032d203..9fdc2c7f29 100644 --- a/src/test/basics/base_uint_test.cpp +++ b/src/test/basics/base_uint_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { // a non-hashing Hasher that just copies the bytes. @@ -66,19 +47,17 @@ struct base_uint_test : beast::unit_test::suite testComparisons() { { - static constexpr std:: - array, 6> - test_args{ - {{"0000000000000000", "0000000000000001"}, - {"0000000000000000", "ffffffffffffffff"}, - {"1234567812345678", "2345678923456789"}, - {"8000000000000000", "8000000000000001"}, - {"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"}, - {"fffffffffffffffe", "ffffffffffffffff"}}}; + static constexpr std::array, 6> test_args{ + {{"0000000000000000", "0000000000000001"}, + {"0000000000000000", "ffffffffffffffff"}, + {"1234567812345678", "2345678923456789"}, + {"8000000000000000", "8000000000000001"}, + {"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"}, + {"fffffffffffffffe", "ffffffffffffffff"}}}; for (auto const& arg : test_args) { - ripple::base_uint<64> const u{arg.first}, v{arg.second}; + xrpl::base_uint<64> const u{arg.first}, v{arg.second}; BEAST_EXPECT(u < v); BEAST_EXPECT(u <= v); BEAST_EXPECT(u != v); @@ -97,21 +76,18 @@ struct base_uint_test : beast::unit_test::suite } { - static constexpr std::array< - std::pair, - 6> - test_args{{ - {"000000000000000000000000", "000000000000000000000001"}, - {"000000000000000000000000", "ffffffffffffffffffffffff"}, - {"0123456789ab0123456789ab", "123456789abc123456789abc"}, - {"555555555555555555555555", "55555555555a555555555555"}, - {"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"}, - {"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"}, - }}; + static constexpr std::array, 6> test_args{{ + {"000000000000000000000000", "000000000000000000000001"}, + {"000000000000000000000000", "ffffffffffffffffffffffff"}, + {"0123456789ab0123456789ab", "123456789abc123456789abc"}, + {"555555555555555555555555", "55555555555a555555555555"}, + {"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"}, + {"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"}, + }}; for (auto const& arg : test_args) { - ripple::base_uint<96> const u{arg.first}, v{arg.second}; + xrpl::base_uint<96> const u{arg.first}, v{arg.second}; BEAST_EXPECT(u < v); BEAST_EXPECT(u <= v); BEAST_EXPECT(u != v); @@ -135,10 +111,8 @@ struct base_uint_test : beast::unit_test::suite { testcase("base_uint: general purpose tests"); - static_assert( - !std::is_constructible>::value); - static_assert( - !std::is_assignable>::value); + static_assert(!std::is_constructible>::value); + static_assert(!std::is_assignable>::value); testComparisons(); @@ -315,9 +289,7 @@ struct base_uint_test : beast::unit_test::suite } catch (std::invalid_argument const& e) { - BEAST_EXPECT( - e.what() == - std::string("invalid length for hex string")); + BEAST_EXPECT(e.what() == std::string("invalid length for hex string")); caught = true; } BEAST_EXPECT(caught); @@ -335,8 +307,7 @@ struct base_uint_test : beast::unit_test::suite } catch (std::range_error const& e) { - BEAST_EXPECT( - e.what() == std::string("invalid hex character")); + BEAST_EXPECT(e.what() == std::string("invalid hex character")); caught = true; } BEAST_EXPECT(caught); @@ -371,7 +342,7 @@ struct base_uint_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(base_uint, basics, ripple); +BEAST_DEFINE_TESTSUITE(base_uint, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/hardened_hash_test.cpp b/src/test/basics/hardened_hash_test.cpp index 248e807035..1a6609ac29 100644 --- a/src/test/basics/hardened_hash_test.cpp +++ b/src/test/basics/hardened_hash_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { template @@ -70,11 +51,11 @@ public: }; } // namespace detail -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ -namespace ripple { +namespace xrpl { namespace detail { @@ -85,12 +66,10 @@ template using test_hardened_unordered_map = std::unordered_map>; template -using test_hardened_unordered_multiset = - std::unordered_multiset>; +using test_hardened_unordered_multiset = std::unordered_multiset>; template -using test_hardened_unordered_multimap = - std::unordered_multimap>; +using test_hardened_unordered_multimap = std::unordered_multimap>; } // namespace detail @@ -102,13 +81,9 @@ private: std::is_integral::value && std::is_unsigned::value, "UInt must be an unsigned integral type"); - static_assert( - Bits % (8 * sizeof(UInt)) == 0, - "Bits must be a multiple of 8*sizeof(UInt)"); + static_assert(Bits % (8 * sizeof(UInt)) == 0, "Bits must be a multiple of 8*sizeof(UInt)"); - static_assert( - Bits >= (8 * sizeof(UInt)), - "Bits must be at least 8*sizeof(UInt)"); + static_assert(Bits >= (8 * sizeof(UInt)), "Bits must be at least 8*sizeof(UInt)"); static std::size_t const size = Bits / (8 * sizeof(UInt)); @@ -155,8 +130,7 @@ public: operator<<(std::ostream& s, unsigned_integer const& v) { for (std::size_t i(0); i < size; ++i) - s << std::hex << std::setfill('0') << std::setw(2 * sizeof(UInt)) - << v.m_vec[i]; + s << std::hex << std::setfill('0') << std::setw(2 * sizeof(UInt)) << v.m_vec[i]; return s; } }; @@ -167,11 +141,11 @@ using sha256_t = unsigned_integer<256, std::size_t>; static_assert(sha256_t::bits == 256, "sha256_t must have 256 bits"); #endif -} // namespace ripple +} // namespace xrpl //------------------------------------------------------------------------------ -namespace ripple { +namespace xrpl { class hardened_hash_test : public beast::unit_test::suite { @@ -253,6 +227,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(hardened_hash, basics, ripple); +BEAST_DEFINE_TESTSUITE(hardened_hash, basics, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/basics/join_test.cpp b/src/test/basics/join_test.cpp index e533635bcb..9739624c63 100644 --- a/src/test/basics/join_test.cpp +++ b/src/test/basics/join_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2022 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { struct join_test : beast::unit_test::suite @@ -42,13 +23,9 @@ struct join_test : beast::unit_test::suite }; // C++ array - test( - CollectionAndDelimiter(std::array{2, -1, 5, 10}, "/"), - "2/-1/5/10"); + test(CollectionAndDelimiter(std::array{2, -1, 5, 10}, "/"), "2/-1/5/10"); // One item C++ array edge case - test( - CollectionAndDelimiter(std::array{"test"}, " & "), - "test"); + test(CollectionAndDelimiter(std::array{"test"}, " & "), "test"); // Empty C++ array edge case test(CollectionAndDelimiter(std::array{}, ","), ""); { @@ -67,20 +44,13 @@ struct join_test : beast::unit_test::suite test(CollectionAndDelimiter(words, "\n"), "thing"); } // Initializer list - test( - CollectionAndDelimiter(std::initializer_list{19, 25}, "+"), - "19+25"); + test(CollectionAndDelimiter(std::initializer_list{19, 25}, "+"), "19+25"); // vector - test( - CollectionAndDelimiter(std::vector{0, 42}, std::to_string(99)), - "09942"); + test(CollectionAndDelimiter(std::vector{0, 42}, std::to_string(99)), "09942"); { // vector with one item edge case using namespace jtx; - test( - CollectionAndDelimiter( - std::vector{Account::master}, "xxx"), - Account::master.human()); + test(CollectionAndDelimiter(std::vector{Account::master}, "xxx"), Account::master.human()); } // empty vector edge case test(CollectionAndDelimiter(std::vector{}, ","), ""); @@ -99,7 +69,7 @@ struct join_test : beast::unit_test::suite } }; // namespace test -BEAST_DEFINE_TESTSUITE(join, basics, ripple); +BEAST_DEFINE_TESTSUITE(join, basics, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/beast/IPEndpointCommon.h b/src/test/beast/IPEndpointCommon.h index aa2c1e597f..3ca023188e 100644 --- a/src/test/beast/IPEndpointCommon.h +++ b/src/test/beast/IPEndpointCommon.h @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ namespace IP { inline Endpoint randomEP(bool v4 = true) { - using namespace ripple; + using namespace xrpl; auto dv4 = []() -> AddressV4::bytes_type { return { {static_cast(rand_int(1, UINT8_MAX)), @@ -53,9 +34,7 @@ randomEP(bool v4 = true) static_cast(rand_int(1, UINT8_MAX)), static_cast(rand_int(1, UINT8_MAX))}}; }; - return Endpoint{ - v4 ? Address{AddressV4{dv4()}} : Address{AddressV6{dv6()}}, - rand_int(1, UINT16_MAX)}; + return Endpoint{v4 ? Address{AddressV4{dv4()}} : Address{AddressV6{dv6()}}, rand_int(1, UINT16_MAX)}; } } // namespace IP diff --git a/src/test/beast/IPEndpoint_test.cpp b/src/test/beast/IPEndpoint_test.cpp index a99dccf5a0..67e3f8ed7d 100644 --- a/src/test/beast/IPEndpoint_test.cpp +++ b/src/test/beast/IPEndpoint_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - // MODULES: ../impl/IPEndpoint.cpp ../impl/IPAddressV4.cpp // ../impl/IPAddressV6.cpp @@ -39,10 +20,7 @@ class IPEndpoint_test : public unit_test::suite { public: void - shouldParseAddrV4( - std::string const& s, - std::uint32_t value, - std::string const& normal = "") + shouldParseAddrV4(std::string const& s, std::uint32_t value, std::string const& normal = "") { boost::system::error_code ec; Address const result{boost::asio::ip::make_address(s, ec)}; @@ -50,12 +28,9 @@ public: return; if (!BEAST_EXPECTS(result.is_v4(), s + " not v4")) return; - if (!BEAST_EXPECTS( - result.to_v4().to_uint() == value, s + " value mismatch")) + if (!BEAST_EXPECTS(result.to_v4().to_uint() == value, s + " value mismatch")) return; - BEAST_EXPECTS( - result.to_string() == (normal.empty() ? s : normal), - s + " as string"); + BEAST_EXPECTS(result.to_string() == (normal.empty() ? s : normal), s + " as string"); } void @@ -234,14 +209,8 @@ public: shouldParseEPV4("1.2.3.4:5 ", {{1, 2, 3, 4}}, 5, "1.2.3.4:5"); shouldParseEPV4("1.2.3.4 ", {{1, 2, 3, 4}}, 0, "1.2.3.4"); shouldParseEPV4(" 1.2.3.4", {{1, 2, 3, 4}}, 0, "1.2.3.4"); - shouldParseEPV6( - "2001:db8:a0b:12f0::1", - {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, - 0); - shouldParseEPV6( - "[2001:db8:a0b:12f0::1]:8", - {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, - 8); + shouldParseEPV6("2001:db8:a0b:12f0::1", {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, 0); + shouldParseEPV6("[2001:db8:a0b:12f0::1]:8", {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, 8); shouldParseEPV6( "[2001:2002:2003:2004:2005:2006:2007:2008]:65535", {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}}, @@ -263,10 +232,7 @@ public: BEAST_EXPECT(is_loopback(ep)); BEAST_EXPECT(to_string(ep) == "127.0.0.1:80"); // same address as v4 mapped in ipv6 - ep = Endpoint( - boost::asio::ip::make_address_v6( - boost::asio::ip::v4_mapped, AddressV4{d}), - 80); + ep = Endpoint(boost::asio::ip::make_address_v6(boost::asio::ip::v4_mapped, AddressV4{d}), 80); BEAST_EXPECT(!is_unspecified(ep)); BEAST_EXPECT(!is_public(ep)); BEAST_EXPECT(is_private(ep)); @@ -284,11 +250,8 @@ public: BEAST_EXPECT(!is_loopback(ep)); BEAST_EXPECT(to_string(ep) == "10.0.0.1"); // same address as v4 mapped in ipv6 - ep = Endpoint(boost::asio::ip::make_address_v6( - boost::asio::ip::v4_mapped, AddressV4{d})); - BEAST_EXPECT( - get_class(boost::asio::ip::make_address_v4( - boost::asio::ip::v4_mapped, ep.to_v6())) == 'A'); + ep = Endpoint(boost::asio::ip::make_address_v6(boost::asio::ip::v4_mapped, AddressV4{d})); + BEAST_EXPECT(get_class(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, ep.to_v6())) == 'A'); BEAST_EXPECT(!is_unspecified(ep)); BEAST_EXPECT(!is_public(ep)); BEAST_EXPECT(is_private(ep)); @@ -305,8 +268,7 @@ public: BEAST_EXPECT(!is_loopback(ep)); BEAST_EXPECT(to_string(ep) == "166.78.151.147"); // same address as v4 mapped in ipv6 - ep = Endpoint(boost::asio::ip::make_address_v6( - boost::asio::ip::v4_mapped, AddressV4{d})); + ep = Endpoint(boost::asio::ip::make_address_v6(boost::asio::ip::v4_mapped, AddressV4{d})); BEAST_EXPECT(!is_unspecified(ep)); BEAST_EXPECT(is_public(ep)); BEAST_EXPECT(!is_private(ep)); @@ -315,8 +277,7 @@ public: BEAST_EXPECTS(to_string(ep) == "::ffff:166.78.151.147", to_string(ep)); // a private IPv6 - AddressV6::bytes_type d2 = { - {253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; + AddressV6::bytes_type d2 = {{253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; ep = Endpoint(AddressV6{d2}); BEAST_EXPECT(!is_unspecified(ep)); BEAST_EXPECT(!is_public(ep)); @@ -399,7 +360,7 @@ public: float max_lf{0}; for (auto i = 0; i < items; ++i) { - eps.insert(randomEP(ripple::rand_int(0, 1) == 1)); + eps.insert(randomEP(xrpl::rand_int(0, 1) == 1)); max_lf = std::max(max_lf, eps.load_factor()); } BEAST_EXPECT(eps.bucket_count() >= items); @@ -424,9 +385,7 @@ public: using namespace std::literals; T t; BEAST_EXPECT(parse(text, t)); - BEAST_EXPECTS( - to_string(t) == (normal.empty() ? text : normal), - "string mismatch for "s + text); + BEAST_EXPECTS(to_string(t) == (normal.empty() ? text : normal), "string mismatch for "s + text); } template diff --git a/src/test/beast/LexicalCast_test.cpp b/src/test/beast/LexicalCast_test.cpp index 686546a475..4d55b95278 100644 --- a/src/test/beast/LexicalCast_test.cpp +++ b/src/test/beast/LexicalCast_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include diff --git a/src/test/beast/SemanticVersion_test.cpp b/src/test/beast/SemanticVersion_test.cpp index af9d2808fb..b3394235d1 100644 --- a/src/test/beast/SemanticVersion_test.cpp +++ b/src/test/beast/SemanticVersion_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2012, 2013 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -215,15 +196,9 @@ public: checkValues("1.2.3-rc1.debug.asm", 1, 2, 3, ids("rc1", "debug", "asm")); checkValues("1.2.3+full", 1, 2, 3, ids(), ids("full")); checkValues("1.2.3+full.prod", 1, 2, 3, ids(), ids("full", "prod")); + checkValues("1.2.3+full.prod.x86", 1, 2, 3, ids(), ids("full", "prod", "x86")); checkValues( - "1.2.3+full.prod.x86", 1, 2, 3, ids(), ids("full", "prod", "x86")); - checkValues( - "1.2.3-rc1.debug.asm+full.prod.x86", - 1, - 2, - 3, - ids("rc1", "debug", "asm"), - ids("full", "prod", "x86")); + "1.2.3-rc1.debug.asm+full.prod.x86", 1, 2, 3, ids("rc1", "debug", "asm"), ids("full", "prod", "x86")); } // makes sure the left version is less than the right diff --git a/src/test/beast/aged_associative_container_test.cpp b/src/test/beast/aged_associative_container_test.cpp index 017181df22..3af559c1cb 100644 --- a/src/test/beast/aged_associative_container_test.cpp +++ b/src/test/beast/aged_associative_container_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -311,9 +292,7 @@ public: template struct ContType { - template < - class Compare = std::less, - class Allocator = std::allocator> + template , class Allocator = std::allocator> using Cont = detail::aged_ordered_container< Base::is_multi::value, Base::is_map::value, @@ -353,15 +332,10 @@ public: }; template - struct TestTraitsHelper - : MaybeUnordered< - MaybeMulti, IsMulti>, - IsUnordered> + struct TestTraitsHelper : MaybeUnordered, IsMulti>, IsUnordered> { private: - using Base = MaybeUnordered< - MaybeMulti, IsMulti>, - IsUnordered>; + using Base = MaybeUnordered, IsMulti>, IsUnordered>; public: using typename Base::Key; @@ -376,8 +350,7 @@ public: static std::string name() { - return std::string("aged_") + Base::name_ordered_part() + - Base::name_multi_part() + Base::name_map_part(); + return std::string("aged_") + Base::name_ordered_part() + Base::name_multi_part() + Base::name_map_part(); } }; @@ -391,17 +364,14 @@ public: static std::string name(Cont const&) { - return TestTraits:: - name(); + return TestTraits::name(); } template struct equal_value { bool - operator()( - typename Traits::Value const& lhs, - typename Traits::Value const& rhs) + operator()(typename Traits::Value const& lhs, typename Traits::Value const& rhs) { return Traits::extract(lhs) == Traits::extract(rhs); } @@ -417,26 +387,22 @@ public: //-------------------------------------------------------------------------- template - typename std::enable_if< - Container::is_map::value && !Container::is_multi::value>::type + typename std::enable_if::type checkMapContents(Container& c, Values const& v); template - typename std::enable_if< - !(Container::is_map::value && !Container::is_multi::value)>::type + typename std::enable_if::type checkMapContents(Container, Values const&) { } // unordered template - typename std::enable_if< - std::remove_reference::type::is_unordered::value>::type + typename std::enable_if::type::is_unordered::value>::type checkUnorderedContentsRefRef(C&& c, Values const& v); template - typename std::enable_if< - !std::remove_reference::type::is_unordered::value>::type + typename std::enable_if::type::is_unordered::value>::type checkUnorderedContentsRefRef(C&&, Values const&) { } @@ -633,11 +599,8 @@ public: // Check contents via at() and operator[] // map, unordered_map template -typename std::enable_if< - Container::is_map::value && !Container::is_multi::value>::type -aged_associative_container_test_base::checkMapContents( - Container& c, - Values const& v) +typename std::enable_if::type +aged_associative_container_test_base::checkMapContents(Container& c, Values const& v) { if (v.empty()) { @@ -662,17 +625,11 @@ aged_associative_container_test_base::checkMapContents( // unordered template -typename std::enable_if< - std::remove_reference::type::is_unordered::value>::type -aged_associative_container_test_base::checkUnorderedContentsRefRef( - C&& c, - Values const& v) +typename std::enable_if::type::is_unordered::value>::type +aged_associative_container_test_base::checkUnorderedContentsRefRef(C&& c, Values const& v) { using Cont = typename std::remove_reference::type; - using Traits = TestTraits< - Cont::is_unordered::value, - Cont::is_multi::value, - Cont::is_map::value>; + using Traits = TestTraits; using size_type = typename Cont::size_type; auto const hash(c.hash_function()); auto const key_eq(c.key_eq()); @@ -681,26 +638,19 @@ aged_associative_container_test_base::checkUnorderedContentsRefRef( auto const last(c.end(i)); for (auto iter(c.begin(i)); iter != last; ++iter) { - auto const match(std::find_if( - v.begin(), - v.end(), - [iter](typename Values::value_type const& e) { - return Traits::extract(*iter) == Traits::extract(e); - })); + auto const match(std::find_if(v.begin(), v.end(), [iter](typename Values::value_type const& e) { + return Traits::extract(*iter) == Traits::extract(e); + })); BEAST_EXPECT(match != v.end()); - BEAST_EXPECT( - key_eq(Traits::extract(*iter), Traits::extract(*match))); - BEAST_EXPECT( - hash(Traits::extract(*iter)) == hash(Traits::extract(*match))); + BEAST_EXPECT(key_eq(Traits::extract(*iter), Traits::extract(*match))); + BEAST_EXPECT(hash(Traits::extract(*iter)) == hash(Traits::extract(*match))); } } } template void -aged_associative_container_test_base::checkContentsRefRef( - C&& c, - Values const& v) +aged_associative_container_test_base::checkContentsRefRef(C&& c, Values const& v) { using Cont = typename std::remove_reference::type; using size_type = typename Cont::size_type; @@ -708,18 +658,10 @@ aged_associative_container_test_base::checkContentsRefRef( BEAST_EXPECT(c.size() == v.size()); BEAST_EXPECT(size_type(std::distance(c.begin(), c.end())) == v.size()); BEAST_EXPECT(size_type(std::distance(c.cbegin(), c.cend())) == v.size()); - BEAST_EXPECT( - size_type(std::distance( - c.chronological.begin(), c.chronological.end())) == v.size()); - BEAST_EXPECT( - size_type(std::distance( - c.chronological.cbegin(), c.chronological.cend())) == v.size()); - BEAST_EXPECT( - size_type(std::distance( - c.chronological.rbegin(), c.chronological.rend())) == v.size()); - BEAST_EXPECT( - size_type(std::distance( - c.chronological.crbegin(), c.chronological.crend())) == v.size()); + BEAST_EXPECT(size_type(std::distance(c.chronological.begin(), c.chronological.end())) == v.size()); + BEAST_EXPECT(size_type(std::distance(c.chronological.cbegin(), c.chronological.cend())) == v.size()); + BEAST_EXPECT(size_type(std::distance(c.chronological.rbegin(), c.chronological.rend())) == v.size()); + BEAST_EXPECT(size_type(std::distance(c.chronological.crbegin(), c.chronological.crend())) == v.size()); checkUnorderedContentsRefRef(c, v); } @@ -737,10 +679,7 @@ template void aged_associative_container_test_base::checkContents(Cont& c) { - using Traits = TestTraits< - Cont::is_unordered::value, - Cont::is_multi::value, - Cont::is_map::value>; + using Traits = TestTraits; using Values = typename Traits::Values; checkContents(c, Values()); } @@ -782,8 +721,7 @@ aged_associative_container_test_base::testConstructEmpty() } { - typename Traits::template Cont c( - clock, MyComp(1), MyAlloc(1)); + typename Traits::template Cont c(clock, MyComp(1), MyAlloc(1)); checkContents(c); } } @@ -810,44 +748,37 @@ aged_associative_container_test_base::testConstructEmpty() } { - typename Traits::template Cont c( - clock, MyHash(1)); + typename Traits::template Cont c(clock, MyHash(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyEqual(1)); + typename Traits::template Cont c(clock, MyEqual(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyAlloc(1)); + typename Traits::template Cont c(clock, MyAlloc(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyHash(1), MyEqual(1)); + typename Traits::template Cont c(clock, MyHash(1), MyEqual(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyHash(1), MyAlloc(1)); + typename Traits::template Cont c(clock, MyHash(1), MyAlloc(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyEqual(1), MyAlloc(1)); + typename Traits::template Cont c(clock, MyEqual(1), MyAlloc(1)); checkContents(c); } { - typename Traits::template Cont c( - clock, MyHash(1), MyEqual(1), MyAlloc(1)); + typename Traits::template Cont c(clock, MyHash(1), MyEqual(1), MyAlloc(1)); checkContents(c); } } @@ -869,34 +800,29 @@ aged_associative_container_test_base::testConstructRange() testcase("range"); { - typename Traits::template Cont c( - v.begin(), v.end(), clock); + typename Traits::template Cont c(v.begin(), v.end(), clock); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyComp(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyComp(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyAlloc(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyAlloc(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyComp(1), MyAlloc(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyComp(1), MyAlloc(1)); checkContents(c, v); } // swap { - typename Traits::template Cont c1( - v.begin(), v.end(), clock); + typename Traits::template Cont c1(v.begin(), v.end(), clock); typename Traits::template Cont c2(clock); std::swap(c1, c2); checkContents(c2, v); @@ -922,44 +848,37 @@ aged_associative_container_test_base::testConstructRange() testcase("range"); { - typename Traits::template Cont c( - v.begin(), v.end(), clock); + typename Traits::template Cont c(v.begin(), v.end(), clock); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyHash(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyHash(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyEqual(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyEqual(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyAlloc(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyAlloc(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyHash(1), MyEqual(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyHash(1), MyEqual(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyHash(1), MyAlloc(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyHash(1), MyAlloc(1)); checkContents(c, v); } { - typename Traits::template Cont c( - v.begin(), v.end(), clock, MyEqual(1), MyAlloc(1)); + typename Traits::template Cont c(v.begin(), v.end(), clock, MyEqual(1), MyAlloc(1)); checkContents(c, v); } @@ -1220,9 +1139,7 @@ aged_associative_container_test_base::testReverseIterator() template void -aged_associative_container_test_base::checkInsertCopy( - Container& c, - Values const& v) +aged_associative_container_test_base::checkInsertCopy(Container& c, Values const& v) { for (auto const& e : v) c.insert(e); @@ -1231,9 +1148,7 @@ aged_associative_container_test_base::checkInsertCopy( template void -aged_associative_container_test_base::checkInsertMove( - Container& c, - Values const& v) +aged_associative_container_test_base::checkInsertMove(Container& c, Values const& v) { Values v2(v); for (auto& e : v2) @@ -1243,9 +1158,7 @@ aged_associative_container_test_base::checkInsertMove( template void -aged_associative_container_test_base::checkInsertHintCopy( - Container& c, - Values const& v) +aged_associative_container_test_base::checkInsertHintCopy(Container& c, Values const& v) { for (auto const& e : v) c.insert(c.cend(), e); @@ -1254,9 +1167,7 @@ aged_associative_container_test_base::checkInsertHintCopy( template void -aged_associative_container_test_base::checkInsertHintMove( - Container& c, - Values const& v) +aged_associative_container_test_base::checkInsertHintMove(Container& c, Values const& v) { Values v2(v); for (auto& e : v2) @@ -1266,9 +1177,7 @@ aged_associative_container_test_base::checkInsertHintMove( template void -aged_associative_container_test_base::checkEmplace( - Container& c, - Values const& v) +aged_associative_container_test_base::checkEmplace(Container& c, Values const& v) { for (auto const& e : v) c.emplace(e); @@ -1277,9 +1186,7 @@ aged_associative_container_test_base::checkEmplace( template void -aged_associative_container_test_base::checkEmplaceHint( - Container& c, - Values const& v) +aged_associative_container_test_base::checkEmplaceHint(Container& c, Values const& v) { for (auto const& e : v) c.emplace_hint(c.cend(), e); @@ -1358,12 +1265,8 @@ aged_associative_container_test_base::testChronological() typename Traits::template Cont<> c(v.begin(), v.end(), clock); - BEAST_EXPECT(std::equal( - c.chronological.cbegin(), - c.chronological.cend(), - v.begin(), - v.end(), - equal_value())); + BEAST_EXPECT( + std::equal(c.chronological.cbegin(), c.chronological.cend(), v.begin(), v.end(), equal_value())); // Test touch() with a non-const iterator. for (auto iter(v.crbegin()); iter != v.crend(); ++iter) @@ -1377,12 +1280,8 @@ aged_associative_container_test_base::testChronological() c.touch(found); } - BEAST_EXPECT(std::equal( - c.chronological.cbegin(), - c.chronological.cend(), - v.crbegin(), - v.crend(), - equal_value())); + BEAST_EXPECT( + std::equal(c.chronological.cbegin(), c.chronological.cend(), v.crbegin(), v.crend(), equal_value())); // Test touch() with a const_iterator for (auto iter(v.cbegin()); iter != v.cend(); ++iter) @@ -1396,12 +1295,8 @@ aged_associative_container_test_base::testChronological() c.touch(found); } - BEAST_EXPECT(std::equal( - c.chronological.cbegin(), - c.chronological.cend(), - v.cbegin(), - v.cend(), - equal_value())); + BEAST_EXPECT( + std::equal(c.chronological.cbegin(), c.chronological.cend(), v.cbegin(), v.cend(), equal_value())); { // Because touch (reverse_iterator pos) is not allowed, the following @@ -1454,9 +1349,7 @@ aged_associative_container_test_base::testArrayCreate() template void -aged_associative_container_test_base::reverseFillAgedContainer( - Container& c, - Values const& values) +aged_associative_container_test_base::reverseFillAgedContainer(Container& c, Values const& values) { // Just in case the passed in container was not empty. c.clear(); @@ -1482,9 +1375,7 @@ aged_associative_container_test_base::reverseFillAgedContainer( // cannot use operator-- with unordered container iterators. template Iter -aged_associative_container_test_base::nextToEndIter( - Iter beginIter, - Iter const endIter) +aged_associative_container_test_base::nextToEndIter(Iter beginIter, Iter const endIter) { if (beginIter == endIter) { @@ -1516,10 +1407,7 @@ aged_associative_container_test_base::nextToEndIter( // the whole test. template bool -aged_associative_container_test_base::doElementErase( - Container& c, - Iter const beginItr, - Iter const endItr) +aged_associative_container_test_base::doElementErase(Container& c, Iter const beginItr, Iter const endItr) { auto it(beginItr); size_t count = c.size(); @@ -1577,8 +1465,7 @@ aged_associative_container_test_base::testElementErase() { // Test standard iterators auto tempContainer(c); - if (!doElementErase( - tempContainer, tempContainer.cbegin(), tempContainer.cend())) + if (!doElementErase(tempContainer, tempContainer.cbegin(), tempContainer.cend())) return; // Test failed BEAST_EXPECT(tempContainer.empty()); @@ -1599,9 +1486,7 @@ aged_associative_container_test_base::testElementErase() auto tempContainer(c); BEAST_EXPECT(tempContainer.size() > 2); if (!doElementErase( - tempContainer, - ++tempContainer.begin(), - nextToEndIter(tempContainer.begin(), tempContainer.end()))) + tempContainer, ++tempContainer.begin(), nextToEndIter(tempContainer.begin(), tempContainer.end()))) return; // Test failed BEAST_EXPECT(tempContainer.size() == 2); @@ -1612,10 +1497,7 @@ aged_associative_container_test_base::testElementErase() auto tempContainer(c); BEAST_EXPECT(tempContainer.size() > 2); auto& chron(tempContainer.chronological); - if (!doElementErase( - tempContainer, - ++chron.begin(), - nextToEndIter(chron.begin(), chron.end()))) + if (!doElementErase(tempContainer, ++chron.begin(), nextToEndIter(chron.begin(), chron.end()))) return; // Test failed BEAST_EXPECT(tempContainer.size() == 2); @@ -1650,9 +1532,7 @@ aged_associative_container_test_base::testElementErase() // template void -aged_associative_container_test_base::doRangeErase( - Container& c, - BeginEndSrc const& beginEndSrc) +aged_associative_container_test_base::doRangeErase(Container& c, BeginEndSrc const& beginEndSrc) { BEAST_EXPECT(c.size() > 2); auto itBeginPlusOne(beginEndSrc.begin()); @@ -1812,51 +1692,35 @@ public: using T = int; static_assert( - std::is_same< - aged_set, - detail::aged_ordered_container>::value, + std::is_same, detail::aged_ordered_container>::value, "bad alias: aged_set"); static_assert( - std::is_same< - aged_multiset, - detail::aged_ordered_container>::value, + std::is_same, detail::aged_ordered_container>::value, "bad alias: aged_multiset"); static_assert( - std::is_same< - aged_map, - detail::aged_ordered_container>::value, + std::is_same, detail::aged_ordered_container>::value, "bad alias: aged_map"); static_assert( - std::is_same< - aged_multimap, - detail::aged_ordered_container>::value, + std::is_same, detail::aged_ordered_container>::value, "bad alias: aged_multimap"); static_assert( - std::is_same< - aged_unordered_set, - detail::aged_unordered_container>::value, + std::is_same, detail::aged_unordered_container>::value, "bad alias: aged_unordered_set"); static_assert( - std::is_same< - aged_unordered_multiset, - detail::aged_unordered_container>::value, + std::is_same, detail::aged_unordered_container>::value, "bad alias: aged_unordered_multiset"); static_assert( - std::is_same< - aged_unordered_map, - detail::aged_unordered_container>::value, + std::is_same, detail::aged_unordered_container>::value, "bad alias: aged_unordered_map"); static_assert( - std::is_same< - aged_unordered_multimap, - detail::aged_unordered_container>::value, + std::is_same, detail::aged_unordered_container>::value, "bad alias: aged_unordered_multimap"); void diff --git a/src/test/beast/beast_CurrentThreadName_test.cpp b/src/test/beast/beast_CurrentThreadName_test.cpp index e1de5d9ae9..2a365c6e9c 100644 --- a/src/test/beast/beast_CurrentThreadName_test.cpp +++ b/src/test/beast/beast_CurrentThreadName_test.cpp @@ -1,38 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include +#include + #include -namespace ripple { +namespace xrpl { namespace test { class CurrentThreadName_test : public beast::unit_test::suite { private: static void - exerciseName( - std::string myName, - std::atomic* stop, - std::atomic* state) + exerciseName(std::string myName, std::atomic* stop, std::atomic* state) { // Verify that upon creation a thread has no name. auto const initialThreadName = beast::getCurrentThreadName(); @@ -56,37 +36,69 @@ private: if (beast::getCurrentThreadName() == myName) *state = 2; } +#if BOOST_OS_LINUX + // Helper function to test a specific name. + // It creates a thread, sets the name, and checks if the OS-level + // name matches the expected (potentially truncated) name. + void + testName(std::string const& nameToSet, std::string const& expectedName) + { + std::thread t([&] { + beast::setCurrentThreadName(nameToSet); + + // Initialize buffer to be safe. + char actualName[beast::maxThreadNameLength + 1] = {}; + pthread_getname_np(pthread_self(), actualName, sizeof(actualName)); + + BEAST_EXPECT(std::string(actualName) == expectedName); + }); + t.join(); + } +#endif public: void run() override { - // Make two different threads with two different names. Make sure - // that the expected thread names are still there when the thread - // exits. - std::atomic stop{false}; + // Make two different threads with two different names. + // Make sure that the expected thread names are still there + // when the thread exits. + { + std::atomic stop{false}; - std::atomic stateA{0}; - std::thread tA(exerciseName, "tA", &stop, &stateA); + std::atomic stateA{0}; + std::thread tA(exerciseName, "tA", &stop, &stateA); - std::atomic stateB{0}; - std::thread tB(exerciseName, "tB", &stop, &stateB); + std::atomic stateB{0}; + std::thread tB(exerciseName, "tB", &stop, &stateB); - // Wait until both threads have set their names. - while (stateA == 0 || stateB == 0) - ; + // Wait until both threads have set their names. + while (stateA == 0 || stateB == 0) + ; - stop = true; - tA.join(); - tB.join(); + stop = true; + tA.join(); + tB.join(); - // Both threads should still have the expected name when they exit. - BEAST_EXPECT(stateA == 2); - BEAST_EXPECT(stateB == 2); + // Both threads should still have the expected name when they exit. + BEAST_EXPECT(stateA == 2); + BEAST_EXPECT(stateB == 2); + } +#if BOOST_OS_LINUX + // On Linux, verify that thread names within the 15 character limit + // are set correctly (the 16th character is reserved for the null + // terminator). + { + testName("123456789012345", + "123456789012345"); // 15 chars, maximum allowed + testName("", ""); // empty name + testName("short", "short"); // short name + } +#endif } }; BEAST_DEFINE_TESTSUITE(CurrentThreadName, beast, beast); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/beast/beast_Journal_test.cpp b/src/test/beast/beast_Journal_test.cpp index 13e2726c89..407e9ea7aa 100644 --- a/src/test/beast/beast_Journal_test.cpp +++ b/src/test/beast/beast_Journal_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/test/beast/beast_PropertyStream_test.cpp b/src/test/beast/beast_PropertyStream_test.cpp index 585c7cfe6b..c2e6ddc22b 100644 --- a/src/test/beast/beast_PropertyStream_test.cpp +++ b/src/test/beast/beast_PropertyStream_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2012, 2013 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,10 +9,7 @@ public: using Source = PropertyStream::Source; void - test_peel_name( - std::string s, - std::string const& expected, - std::string const& expected_remainder) + test_peel_name(std::string s, std::string const& expected, std::string const& expected_remainder) { try { @@ -47,10 +25,7 @@ public: } void - test_peel_leading_slash( - std::string s, - std::string const& expected, - bool should_be_found) + test_peel_leading_slash(std::string s, std::string const& expected, bool should_be_found) { try { @@ -66,10 +41,7 @@ public: } void - test_peel_trailing_slashstar( - std::string s, - std::string const& expected_remainder, - bool should_be_found) + test_peel_trailing_slashstar(std::string s, std::string const& expected_remainder, bool should_be_found) { try { @@ -130,11 +102,7 @@ public: } void - test_find( - Source& root, - std::string path, - Source* expected, - bool expected_star) + test_find(Source& root, std::string path, Source* expected, bool expected_star) { try { diff --git a/src/test/beast/beast_Zero_test.cpp b/src/test/beast/beast_Zero_test.cpp index 64239fbe85..c3dfbc8c4b 100644 --- a/src/test/beast/beast_Zero_test.cpp +++ b/src/test/beast/beast_Zero_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Nikolaos D. Bougalis - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/test/beast/beast_abstract_clock_test.cpp b/src/test/beast/beast_abstract_clock_test.cpp index 74ab833e9d..94b7909820 100644 --- a/src/test/beast/beast_abstract_clock_test.cpp +++ b/src/test/beast/beast_abstract_clock_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - // MODULES: ../impl/chrono_io.cpp #include @@ -42,8 +23,7 @@ public: std::this_thread::sleep_for(std::chrono::milliseconds(1500)); auto const t2(c.now()); - log << "t1= " << t1.time_since_epoch().count() - << ", t2= " << t2.time_since_epoch().count() + log << "t1= " << t1.time_since_epoch().count() << ", t2= " << t2.time_since_epoch().count() << ", elapsed= " << (t2 - t1).count() << std::endl; pass(); @@ -65,8 +45,7 @@ public: c.set(clock_type::time_point(std::chrono::seconds(2))); auto c3 = c.now().time_since_epoch(); - log << "[" << c1.count() << "," << c2.count() << "," << c3.count() - << "]" << std::endl; + log << "[" << c1.count() << "," << c2.count() << "," << c3.count() << "]" << std::endl; pass(); } @@ -76,9 +55,7 @@ public: { test("steady_clock", get_abstract_clock()); test("system_clock", get_abstract_clock()); - test( - "high_resolution_clock", - get_abstract_clock()); + test("high_resolution_clock", get_abstract_clock()); test_manual(); } diff --git a/src/test/beast/beast_basic_seconds_clock_test.cpp b/src/test/beast/beast_basic_seconds_clock_test.cpp index 10e5e466f3..ccdd76da20 100644 --- a/src/test/beast/beast_basic_seconds_clock_test.cpp +++ b/src/test/beast/beast_basic_seconds_clock_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include diff --git a/src/test/beast/beast_io_latency_probe_test.cpp b/src/test/beast/beast_io_latency_probe_test.cpp index 841272d05a..4a78eb77fe 100644 --- a/src/test/beast/beast_io_latency_probe_test.cpp +++ b/src/test/beast/beast_io_latency_probe_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -34,13 +15,11 @@ using namespace std::chrono_literals; -class io_latency_probe_test : public beast::unit_test::suite, - public beast::test::enable_yield_to +class io_latency_probe_test : public beast::unit_test::suite, public beast::test::enable_yield_to { - using MyTimer = - boost::asio::basic_waitable_timer; + using MyTimer = boost::asio::basic_waitable_timer; -#ifdef RIPPLED_RUNNING_IN_CI +#ifdef XRPL_RUNNING_IN_CI /** * @brief attempt to measure inaccuracy of asio waitable timers * @@ -48,9 +27,7 @@ class io_latency_probe_test : public beast::unit_test::suite, * timer inaccuracy impacts the io_probe tests below. * */ - template < - class Clock, - class MeasureClock = std::chrono::high_resolution_clock> + template struct measure_asio_timers { using duration = typename Clock::duration; @@ -62,9 +39,8 @@ class io_latency_probe_test : public beast::unit_test::suite, { using namespace std::chrono; boost::asio::io_context ios; - std::optional> - work{boost::asio::make_work_guard(ios)}; + std::optional> work{ + boost::asio::make_work_guard(ios)}; std::thread worker{[&] { ios.run(); }}; boost::asio::basic_waitable_timer timer{ios}; elapsed_times_.reserve(num_samples); @@ -103,8 +79,7 @@ class io_latency_probe_test : public beast::unit_test::suite, double sum = {0}; for (auto const& v : elapsed_times_) { - sum += static_cast( - std::chrono::duration_cast(v).count()); + sum += static_cast(std::chrono::duration_cast(v).count()); } return sum / elapsed_times_.size(); } @@ -113,9 +88,7 @@ class io_latency_probe_test : public beast::unit_test::suite, auto getMax() { - return std::chrono::duration_cast( - *std::max_element( - elapsed_times_.begin(), elapsed_times_.end())) + return std::chrono::duration_cast(*std::max_element(elapsed_times_.begin(), elapsed_times_.end())) .count(); } @@ -123,9 +96,7 @@ class io_latency_probe_test : public beast::unit_test::suite, auto getMin() { - return std::chrono::duration_cast( - *std::min_element( - elapsed_times_.begin(), elapsed_times_.end())) + return std::chrono::duration_cast(*std::min_element(elapsed_times_.begin(), elapsed_times_.end())) .count(); } }; @@ -136,10 +107,7 @@ class io_latency_probe_test : public beast::unit_test::suite, beast::io_latency_probe probe_; std::vector durations_; - test_sampler( - std::chrono::milliseconds interval, - boost::asio::io_context& ios) - : probe_(interval, ios) + test_sampler(std::chrono::milliseconds interval, boost::asio::io_context& ios) : probe_(interval, ios) { } @@ -188,17 +156,13 @@ class io_latency_probe_test : public beast::unit_test::suite, size_t expected_probe_count_max = (probe_duration / interval); size_t expected_probe_count_min = expected_probe_count_max; -#ifdef RIPPLED_RUNNING_IN_CI +#ifdef XRPL_RUNNING_IN_CI // adjust min expected based on measurements // if running in CI/VM environment measure_asio_timers tt{interval}; - log << "measured mean for timers: " << tt.getMean() - << "ms\n"; - log << "measured max for timers: " << tt.getMax() - << "ms\n"; - expected_probe_count_min = - static_cast( - duration_cast(probe_duration).count()) / + log << "measured mean for timers: " << tt.getMean() << "ms\n"; + log << "measured max for timers: " << tt.getMax() << "ms\n"; + expected_probe_count_min = static_cast(duration_cast(probe_duration).count()) / static_cast(tt.getMean()); #endif test_sampler io_probe{interval, get_io_context()}; @@ -209,8 +173,7 @@ class io_latency_probe_test : public beast::unit_test::suite, return; auto probes_seen = io_probe.durations_.size(); BEAST_EXPECTS( - probes_seen >= (expected_probe_count_min - 1) && - probes_seen <= (expected_probe_count_max + 1), + probes_seen >= (expected_probe_count_min - 1) && probes_seen <= (expected_probe_count_max + 1), std::string("probe count is ") + std::to_string(probes_seen)); io_probe.probe_.cancel_async(); // wait again in order to flush the remaining diff --git a/src/test/beast/define_print.cpp b/src/test/beast/define_print.cpp index eca6a70c90..07b1422a54 100644 --- a/src/test/beast/define_print.cpp +++ b/src/test/beast/define_print.cpp @@ -1,6 +1,3 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -26,9 +23,7 @@ public: std::size_t manual = 0; std::size_t total = 0; - auto prefix = [](suite_info const& s) { - return s.manual() ? "|M| " : " "; - }; + auto prefix = [](suite_info const& s) { return s.manual() ? "|M| " : " "; }; for (auto const& s : global_suites()) { @@ -39,8 +34,7 @@ public: ++total; } - log << amount(total, "suite") << " total, " - << amount(manual, "manual suite") << std::endl; + log << amount(total, "suite") << " total, " << amount(manual, "manual suite") << std::endl; pass(); } diff --git a/src/test/beast/xxhasher_test.cpp b/src/test/beast/xxhasher_test.cpp index 6c65fea601..868d522384 100644 --- a/src/test/beast/xxhasher_test.cpp +++ b/src/test/beast/xxhasher_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2025 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -35,9 +16,7 @@ public: std::string objectToHash{"Hello, xxHash!"}; hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 16042857369214894119ULL); + BEAST_EXPECT(static_cast(hasher) == 16042857369214894119ULL); } void @@ -50,28 +29,23 @@ public: std::string objectToHash{"Hello, xxHash!"}; hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 14440132435660934800ULL); + BEAST_EXPECT(static_cast(hasher) == 14440132435660934800ULL); } void testWithTwoSeeds() { testcase("With two seeds"); - xxhasher hasher{ - static_cast(102), static_cast(103)}; + xxhasher hasher{static_cast(102), static_cast(103)}; std::string objectToHash{"Hello, xxHash!"}; hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 14440132435660934800ULL); + BEAST_EXPECT(static_cast(hasher) == 14440132435660934800ULL); } void - testBigObjectWithMultiupleSmallUpdatesWithoutSeed() + testBigObjectWithMultipleSmallUpdatesWithoutSeed() { testcase("Big object with multiple small updates without seed"); xxhasher hasher{}; @@ -82,13 +56,11 @@ public: hasher(objectToHash.data(), objectToHash.size()); } - BEAST_EXPECT( - static_cast(hasher) == - 15296278154063476002ULL); + BEAST_EXPECT(static_cast(hasher) == 15296278154063476002ULL); } void - testBigObjectWithMultiupleSmallUpdatesWithSeed() + testBigObjectWithMultipleSmallUpdatesWithSeed() { testcase("Big object with multiple small updates with seed"); xxhasher hasher{static_cast(103)}; @@ -99,9 +71,7 @@ public: hasher(objectToHash.data(), objectToHash.size()); } - BEAST_EXPECT( - static_cast(hasher) == - 17285302196561698791ULL); + BEAST_EXPECT(static_cast(hasher) == 17285302196561698791ULL); } void @@ -120,9 +90,7 @@ public: hasher(bigObject.data(), bigObject.size()); hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 1865045178324729219ULL); + BEAST_EXPECT(static_cast(hasher) == 1865045178324729219ULL); } void @@ -141,9 +109,7 @@ public: hasher(bigObject.data(), bigObject.size()); hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 16189862915636005281ULL); + BEAST_EXPECT(static_cast(hasher) == 16189862915636005281ULL); } void @@ -159,9 +125,7 @@ public: } hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 15296278154063476002ULL); + BEAST_EXPECT(static_cast(hasher) == 15296278154063476002ULL); } void @@ -177,9 +141,7 @@ public: } hasher(objectToHash.data(), objectToHash.size()); - BEAST_EXPECT( - static_cast(hasher) == - 17285302196561698791ULL); + BEAST_EXPECT(static_cast(hasher) == 17285302196561698791ULL); } void @@ -218,8 +180,8 @@ public: testWithoutSeed(); testWithSeed(); testWithTwoSeeds(); - testBigObjectWithMultiupleSmallUpdatesWithoutSeed(); - testBigObjectWithMultiupleSmallUpdatesWithSeed(); + testBigObjectWithMultipleSmallUpdatesWithoutSeed(); + testBigObjectWithMultipleSmallUpdatesWithSeed(); testBigObjectWithSmallAndBigUpdatesWithoutSeed(); testBigObjectWithSmallAndBigUpdatesWithSeed(); testBigObjectWithOneUpdateWithoutSeed(); diff --git a/src/test/conditions/PreimageSha256_test.cpp b/src/test/conditions/PreimageSha256_test.cpp index 820b005a3f..71ba526be3 100644 --- a/src/test/conditions/PreimageSha256_test.cpp +++ b/src/test/conditions/PreimageSha256_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -32,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace cryptoconditions { class PreimageSha256_test : public beast::unit_test::suite @@ -186,8 +167,8 @@ class PreimageSha256_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PreimageSha256, conditions, ripple); +BEAST_DEFINE_TESTSUITE(PreimageSha256, conditions, xrpl); } // namespace cryptoconditions -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/ByzantineFailureSim_test.cpp b/src/test/consensus/ByzantineFailureSim_test.cpp index 887a060a5b..62899730c2 100644 --- a/src/test/consensus/ByzantineFailureSim_test.cpp +++ b/src/test/consensus/ByzantineFailureSim_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class ByzantineFailureSim_test : public beast::unit_test::suite @@ -41,8 +22,7 @@ class ByzantineFailureSim_test : public beast::unit_test::suite Sim sim; ConsensusParms const parms{}; - SimDuration const delay = - round(0.2 * parms.ledgerGRANULARITY); + SimDuration const delay = round(0.2 * parms.ledgerGRANULARITY); PeerGroup a = sim.createGroup(1); PeerGroup b = sim.createGroup(1); PeerGroup c = sim.createGroup(1); @@ -65,12 +45,10 @@ class ByzantineFailureSim_test : public beast::unit_test::suite sim.collectors.add(sc); - for (TrustGraph::ForkInfo const& fi : - sim.trustGraph.forkablePairs(0.8)) + for (TrustGraph::ForkInfo const& fi : sim.trustGraph.forkablePairs(0.8)) { std::cout << "Can fork " << PeerGroup{fi.unlA} << " " - << " " << PeerGroup{fi.unlB} << " overlap " << fi.overlap - << " required " << fi.required << "\n"; + << " " << PeerGroup{fi.unlB} << " overlap " << fi.overlap << " required " << fi.required << "\n"; }; // set prior state @@ -82,23 +60,21 @@ class ByzantineFailureSim_test : public beast::unit_test::suite { peer->submit(Tx{0}); // Peers 0,1,2,6 will close the next ledger differently by injecting - // a non-consensus approved transaciton + // a non-consensus approved transaction if (byzantineNodes.contains(peer)) { - peer->txInjections.emplace( - peer->lastClosedLedger.seq(), Tx{42}); + peer->txInjections.emplace(peer->lastClosedLedger.seq(), Tx{42}); } } sim.run(4); std::cout << "Branches: " << sim.branches() << "\n"; - std::cout << "Fully synchronized: " << std::boolalpha - << sim.synchronized() << "\n"; + std::cout << "Fully synchronized: " << std::boolalpha << sim.synchronized() << "\n"; // Not tessting anything currently. pass(); } }; -BEAST_DEFINE_TESTSUITE_MANUAL(ByzantineFailureSim, consensus, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(ByzantineFailureSim, consensus, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/Consensus_test.cpp b/src/test/consensus/Consensus_test.cpp index 7899336a6f..3227ad4d1c 100644 --- a/src/test/consensus/Consensus_test.cpp +++ b/src/test/consensus/Consensus_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Consensus_test : public beast::unit_test::suite @@ -47,33 +28,24 @@ public: ConsensusParms const p{}; // Bizarre times forcibly close - BEAST_EXPECT(shouldCloseLedger( - true, 10, 10, 10, -10s, 10s, 1s, 1s, p, journal_)); - BEAST_EXPECT(shouldCloseLedger( - true, 10, 10, 10, 100h, 10s, 1s, 1s, p, journal_)); - BEAST_EXPECT(shouldCloseLedger( - true, 10, 10, 10, 10s, 100h, 1s, 1s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, -10s, 10s, 1s, 1s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, 100h, 10s, 1s, 1s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, 10s, 100h, 1s, 1s, p, journal_)); // Rest of network has closed - BEAST_EXPECT( - shouldCloseLedger(true, 10, 3, 5, 10s, 10s, 10s, 10s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(true, 10, 3, 5, 10s, 10s, 10s, 10s, p, journal_)); // No transactions means wait until end of internval - BEAST_EXPECT( - !shouldCloseLedger(false, 10, 0, 0, 1s, 1s, 1s, 10s, p, journal_)); - BEAST_EXPECT( - shouldCloseLedger(false, 10, 0, 0, 1s, 10s, 1s, 10s, p, journal_)); + BEAST_EXPECT(!shouldCloseLedger(false, 10, 0, 0, 1s, 1s, 1s, 10s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(false, 10, 0, 0, 1s, 10s, 1s, 10s, p, journal_)); // Enforce minimum ledger open time - BEAST_EXPECT( - !shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 1s, 10s, p, journal_)); + BEAST_EXPECT(!shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 1s, 10s, p, journal_)); // Don't go too much faster than last time - BEAST_EXPECT( - !shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 3s, 10s, p, journal_)); + BEAST_EXPECT(!shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 3s, 10s, p, journal_)); - BEAST_EXPECT( - shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 10s, 10s, p, journal_)); + BEAST_EXPECT(shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 10s, 10s, p, journal_)); } void @@ -82,100 +54,68 @@ public: using namespace std::chrono_literals; testcase("check consensus"); - // Use default parameterss + // Use default parameters ConsensusParms const p{}; /////////////// // Disputes still in doubt // // Not enough time has elapsed - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(10, 2, 2, 0, 3s, 2s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(10, 2, 2, 0, 3s, 2s, false, p, true, journal_)); - // If not enough peers have propsed, ensure + // If not enough peers have proposed, ensure // more time for proposals - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(10, 2, 2, 0, 3s, 4s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(10, 2, 2, 0, 3s, 4s, false, p, true, journal_)); // Enough time has elapsed and we all agree - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(10, 2, 2, 0, 3s, 10s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(10, 2, 2, 0, 3s, 10s, false, p, true, journal_)); // Enough time has elapsed and we don't yet agree - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(10, 2, 1, 0, 3s, 10s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(10, 2, 1, 0, 3s, 10s, false, p, true, journal_)); // Our peers have moved on // Enough time has elapsed and we all agree - BEAST_EXPECT( - ConsensusState::MovedOn == - checkConsensus(10, 2, 1, 8, 3s, 10s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::MovedOn == checkConsensus(10, 2, 1, 8, 3s, 10s, false, p, true, journal_)); // If no peers, don't agree until time has passed. - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(0, 0, 0, 0, 3s, 10s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(0, 0, 0, 0, 3s, 10s, false, p, true, journal_)); // Agree if no peers and enough time has passed. - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(0, 0, 0, 0, 3s, 16s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(0, 0, 0, 0, 3s, 16s, false, p, true, journal_)); // Expire if too much time has passed without agreement - BEAST_EXPECT( - ConsensusState::Expired == - checkConsensus(10, 8, 1, 0, 1s, 19s, false, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Expired == checkConsensus(10, 8, 1, 0, 1s, 19s, false, p, true, journal_)); /////////////// // Stalled // // Not enough time has elapsed - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(10, 2, 2, 0, 3s, 2s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(10, 2, 2, 0, 3s, 2s, true, p, true, journal_)); - // If not enough peers have propsed, ensure + // If not enough peers have proposed, ensure // more time for proposals - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(10, 2, 2, 0, 3s, 4s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(10, 2, 2, 0, 3s, 4s, true, p, true, journal_)); // Enough time has elapsed and we all agree - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(10, 2, 2, 0, 3s, 10s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(10, 2, 2, 0, 3s, 10s, true, p, true, journal_)); // Enough time has elapsed and we don't yet agree, but there's nothing // left to dispute - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(10, 2, 1, 0, 3s, 10s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(10, 2, 1, 0, 3s, 10s, true, p, true, journal_)); // Our peers have moved on // Enough time has elapsed and we all agree, nothing left to dispute - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(10, 2, 1, 8, 3s, 10s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(10, 2, 1, 8, 3s, 10s, true, p, true, journal_)); // If no peers, don't agree until time has passed. - BEAST_EXPECT( - ConsensusState::No == - checkConsensus(0, 0, 0, 0, 3s, 10s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::No == checkConsensus(0, 0, 0, 0, 3s, 10s, true, p, true, journal_)); // Agree if no peers and enough time has passed. - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(0, 0, 0, 0, 3s, 16s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(0, 0, 0, 0, 3s, 16s, true, p, true, journal_)); // We are done if there's nothing left to dispute, no matter how much // time has passed - BEAST_EXPECT( - ConsensusState::Yes == - checkConsensus(10, 8, 1, 0, 1s, 19s, true, p, true, journal_)); + BEAST_EXPECT(ConsensusState::Yes == checkConsensus(10, 8, 1, 0, 1s, 19s, true, p, true, journal_)); } void @@ -215,8 +155,7 @@ public: PeerGroup peers = sim.createGroup(5); // Connected trust and network graphs with single fixed delay - peers.trustAndConnect( - peers, round(0.2 * parms.ledgerGRANULARITY)); + peers.trustAndConnect(peers, round(0.2 * parms.ledgerGRANULARITY)); // everyone submits their own ID as a TX for (Peer* p : peers) @@ -264,11 +203,9 @@ public: network.trust(network); // Fast and slow network connections - fast.connect( - fast, round(0.2 * parms.ledgerGRANULARITY)); + fast.connect(fast, round(0.2 * parms.ledgerGRANULARITY)); - slow.connect( - network, round(1.1 * parms.ledgerGRANULARITY)); + slow.connect(network, round(1.1 * parms.ledgerGRANULARITY)); // All peers submit their own ID as a transaction for (Peer* peer : network) @@ -287,16 +224,14 @@ public: BEAST_EXPECT(lcl.seq() == Ledger::Seq{1}); BEAST_EXPECT(peer->prevProposers == network.size() - 1); - BEAST_EXPECT( - peer->prevRoundTime == network[0]->prevRoundTime); + BEAST_EXPECT(peer->prevRoundTime == network[0]->prevRoundTime); BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end()); for (std::uint32_t i = 2; i < network.size(); ++i) BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end()); // Tx 0 didn't make it - BEAST_EXPECT( - peer->openTxs.find(Tx{0}) != peer->openTxs.end()); + BEAST_EXPECT(peer->openTxs.find(Tx{0}) != peer->openTxs.end()); } } } @@ -320,12 +255,9 @@ public: network.trust(network); // Fast and slow network connections - fast.connect( - fast, round(0.2 * parms.ledgerGRANULARITY)); + fast.connect(fast, round(0.2 * parms.ledgerGRANULARITY)); - slow.connect( - network, - round(1.1 * parms.ledgerGRANULARITY)); + slow.connect(network, round(1.1 * parms.ledgerGRANULARITY)); for (Peer* peer : slow) peer->runAsValidator = isParticipant; @@ -349,22 +281,17 @@ public: BEAST_EXPECT(lcl.seq() == Ledger::Seq{1}); BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end()); BEAST_EXPECT(lcl.txs().find(Tx{1}) == lcl.txs().end()); - for (std::uint32_t i = slow.size(); i < network.size(); - ++i) - BEAST_EXPECT( - lcl.txs().find(Tx{i}) != lcl.txs().end()); + for (std::uint32_t i = slow.size(); i < network.size(); ++i) + BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end()); // Tx 0-1 didn't make it - BEAST_EXPECT( - peer->openTxs.find(Tx{0}) != peer->openTxs.end()); - BEAST_EXPECT( - peer->openTxs.find(Tx{1}) != peer->openTxs.end()); + BEAST_EXPECT(peer->openTxs.find(Tx{0}) != peer->openTxs.end()); + BEAST_EXPECT(peer->openTxs.find(Tx{1}) != peer->openTxs.end()); } Peer const* slowPeer = slow[0]; if (isParticipant) - BEAST_EXPECT( - slowPeer->prevProposers == network.size() - 1); + BEAST_EXPECT(slowPeer->prevProposers == network.size() - 1); else BEAST_EXPECT(slowPeer->prevProposers == fast.size()); @@ -388,18 +315,14 @@ public: if (isParticipant) { - BEAST_EXPECT( - peer->prevProposers == network.size() - 1); - BEAST_EXPECT( - peer->prevRoundTime > slowPeer->prevRoundTime); + BEAST_EXPECT(peer->prevProposers == network.size() - 1); + BEAST_EXPECT(peer->prevRoundTime > slowPeer->prevRoundTime); } else { - BEAST_EXPECT( - peer->prevProposers == fast.size() - 1); + BEAST_EXPECT(peer->prevProposers == fast.size() - 1); // so all peers should have closed together - BEAST_EXPECT( - peer->prevRoundTime == slowPeer->prevRoundTime); + BEAST_EXPECT(peer->prevRoundTime == slowPeer->prevRoundTime); } } } @@ -448,14 +371,12 @@ public: PeerGroup network = groupA + groupB + groupC; network.trust(network); - network.connect( - network, round(0.2 * parms.ledgerGRANULARITY)); + network.connect(network, round(0.2 * parms.ledgerGRANULARITY)); // Run consensus without skew until we have a short close time // resolution Peer* firstPeer = *groupA.begin(); - while (firstPeer->lastClosedLedger.closeTimeResolution() >= - parms.proposeFRESHNESS) + while (firstPeer->lastClosedLedger.closeTimeResolution() >= parms.proposeFRESHNESS) sim.run(1); // Introduce a shift on the time of 2/3 of peers @@ -520,8 +441,7 @@ public: PeerGroup majority = majorityA + majorityB; PeerGroup network = minority + majority; - SimDuration delay = - round(0.2 * parms.ledgerGRANULARITY); + SimDuration delay = round(0.2 * parms.ledgerGRANULARITY); minority.trustAndConnect(minority + majorityA, delay); majority.trustAndConnect(majority, delay); @@ -581,8 +501,7 @@ public: { if (BEAST_EXPECT(peerJumps.closeJumps.size() == 1)) { - JumpCollector::Jump const& jump = - peerJumps.closeJumps.front(); + JumpCollector::Jump const& jump = peerJumps.closeJumps.front(); // Jump is to a different chain BEAST_EXPECT(jump.from.seq() <= jump.to.seq()); BEAST_EXPECT(!jump.to.isAncestor(jump.from)); @@ -590,11 +509,9 @@ public: } // fully validated jump forward in same chain { - if (BEAST_EXPECT( - peerJumps.fullyValidatedJumps.size() == 1)) + if (BEAST_EXPECT(peerJumps.fullyValidatedJumps.size() == 1)) { - JumpCollector::Jump const& jump = - peerJumps.fullyValidatedJumps.front(); + JumpCollector::Jump const& jump = peerJumps.fullyValidatedJumps.front(); // Jump is to a different chain with same seq BEAST_EXPECT(jump.from.seq() < jump.to.seq()); BEAST_EXPECT(jump.to.isAncestor(jump.from)); @@ -625,8 +542,7 @@ public: clique.trust(clique); PeerGroup network = loner + clique; - network.connect( - network, round(0.2 * parms.ledgerGRANULARITY)); + network.connect(network, round(0.2 * parms.ledgerGRANULARITY)); // initial round to set prior state sim.run(1); @@ -674,13 +590,12 @@ public: // Fast and slow network connections fast.connect(fast, round(0.2 * parms.ledgerGRANULARITY)); - slow.connect( - network, round(1.1 * parms.ledgerGRANULARITY)); + slow.connect(network, round(1.1 * parms.ledgerGRANULARITY)); // Run to the ledger *prior* to decreasing the resolution sim.run(increaseLedgerTimeResolutionEvery - 2); - // In order to create the discrepency, we want a case where if + // In order to create the discrepancy, we want a case where if // X = effCloseTime(closeTime, resolution, parentCloseTime) // X != effCloseTime(X, resolution, parentCloseTime) // @@ -697,8 +612,7 @@ public: NetClock::duration when = network[0]->now().time_since_epoch(); // Check we are before the 30s to 20s transition - NetClock::duration resolution = - network[0]->lastClosedLedger.closeTimeResolution(); + NetClock::duration resolution = network[0]->lastClosedLedger.closeTimeResolution(); BEAST_EXPECT(resolution == NetClock::duration{30s}); while (((when % NetClock::duration{30s}) != NetClock::duration{15s}) || @@ -775,8 +689,7 @@ public: PeerGroup network = a + b; - SimDuration delay = - round(0.2 * parms.ledgerGRANULARITY); + SimDuration delay = round(0.2 * parms.ledgerGRANULARITY); a.trustAndConnect(a, delay); b.trustAndConnect(b, delay); @@ -787,8 +700,7 @@ public: // Nodes have only seen transactions from their neighbors peer->openTxs.insert(Tx{static_cast(peer->id)}); for (Peer* to : sim.trustGraph.trustedPeers(peer)) - peer->openTxs.insert( - Tx{static_cast(to->id)}); + peer->openTxs.insert(Tx{static_cast(to->id)}); } sim.run(1); @@ -851,11 +763,7 @@ public: csf::SimDuration delay; bool reconnected = false; - Disruptor( - csf::PeerGroup& net, - csf::PeerGroup& c, - csf::PeerGroup& split, - csf::SimDuration d) + Disruptor(csf::PeerGroup& net, csf::PeerGroup& c, csf::PeerGroup& split, csf::SimDuration d) : network(net), groupCfast(c), groupCsplit(split), delay(d) { } @@ -873,8 +781,7 @@ public: // As soon as the fastC node fully validates C, disconnect // ALL c nodes from the network. The fast C node needs to disconnect // as well to prevent it from relaying the validations it did see - if (who == groupCfast[0]->id && - e.ledger.seq() == csf::Ledger::Seq{2}) + if (who == groupCfast[0]->id && e.ledger.seq() == csf::Ledger::Seq{2}) { network.disconnect(groupCsplit); network.disconnect(groupCfast); @@ -925,7 +832,7 @@ public: // for B. // - The network reconnects and the validations for generation 3 ledgers // are observed (D and the 8 C's) - // - In the old approach, 2 votes for D outweights 1 vote for each C' + // - In the old approach, 2 votes for D outweighs 1 vote for each C' // so the network would avalanche towards D and fully validate it // EVEN though C was fully validated by one node // - In the new approach, 2 votes for D are not enough to outweight the @@ -1048,7 +955,7 @@ public: // The "ahead" validators run normal speed and run ahead validating the // upper chain of ledgers. // - // Due to the uncommited support definition of the preferred branch + // Due to the uncommitted support definition of the preferred branch // protocol, even if the "behind" validators are a majority, the "ahead" // validators cannot jump to the proper branch until the "behind" // validators catch up to the same sequence number. For this test to @@ -1098,11 +1005,8 @@ public: // Simulate clients submitting 1 tx every 5 seconds to a random // validator Rate const rate{1, 5s}; - auto peerSelector = makeSelector( - network.begin(), - network.end(), - std::vector(network.size(), 1.), - sim.rng); + auto peerSelector = + makeSelector(network.begin(), network.end(), std::vector(network.size(), 1.), sim.rng); auto txSubmitter = makeSubmitter( ConstantDistribution{rate.inv()}, sim.scheduler.now(), @@ -1148,10 +1052,8 @@ public: { Dispute proposingTrue{txTrue.id(), true, numPeers, journal_}; Dispute proposingFalse{txFalse.id(), false, numPeers, journal_}; - Dispute followingTrue{ - txFollowingTrue.id(), true, numPeers, journal_}; - Dispute followingFalse{ - txFollowingFalse.id(), false, numPeers, journal_}; + Dispute followingTrue{txFollowingTrue.id(), true, numPeers, journal_}; + Dispute followingFalse{txFollowingFalse.id(), false, numPeers, journal_}; BEAST_EXPECT(proposingTrue.ID() == 99); BEAST_EXPECT(proposingFalse.ID() == 98); BEAST_EXPECT(followingTrue.ID() == 97); @@ -1176,14 +1078,10 @@ public: BEAST_EXPECT(proposingFalse.getOurVote() == false); BEAST_EXPECT(followingTrue.getOurVote() == true); BEAST_EXPECT(followingFalse.getOurVote() == false); - BEAST_EXPECT( - !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingTrue.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(clog->str() == ""); // I'm in the majority, my vote should not change @@ -1198,14 +1096,10 @@ public: BEAST_EXPECT(!followingFalse.updateVote(10, false, p)); peersUnchanged = 2; - BEAST_EXPECT( - !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingTrue.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(clog->str() == ""); // Right now, the vote is 51%. The requirement is about to jump to @@ -1296,14 +1190,10 @@ public: BEAST_EXPECT(followingFalse.getOurVote() == false); peersUnchanged = 3; - BEAST_EXPECT( - !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingTrue.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(clog->str() == ""); // Threshold jumps to 95% @@ -1341,67 +1231,33 @@ public: for (peersUnchanged = 0; peersUnchanged < 6; ++peersUnchanged) { - BEAST_EXPECT( - !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !proposingFalse.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingTrue.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT( - !followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(clog->str() == ""); } - auto expectStalled = [this, &clog]( - int txid, - bool ourVote, - int ourTime, - int peerTime, - int support, - std::uint32_t line) { - using namespace std::string_literals; + auto expectStalled = + [this, &clog](int txid, bool ourVote, int ourTime, int peerTime, int support, std::uint32_t line) { + using namespace std::string_literals; - auto const s = clog->str(); - expect(s.find("stalled"), s, __FILE__, line); - expect( - s.starts_with("Transaction "s + std::to_string(txid)), - s, - __FILE__, - line); - expect( - s.find("voting "s + (ourVote ? "YES" : "NO")) != s.npos, - s, - __FILE__, - line); - expect( - s.find("for "s + std::to_string(ourTime) + " rounds."s) != - s.npos, - s, - __FILE__, - line); - expect( - s.find( - "votes in "s + std::to_string(peerTime) + " rounds.") != - s.npos, - s, - __FILE__, - line); - expect( - s.ends_with( - "has "s + std::to_string(support) + "% support. "s), - s, - __FILE__, - line); - clog = std::make_unique(); - }; + auto const s = clog->str(); + expect(s.find("stalled"), s, __FILE__, line); + expect(s.starts_with("Transaction "s + std::to_string(txid)), s, __FILE__, line); + expect(s.find("voting "s + (ourVote ? "YES" : "NO")) != s.npos, s, __FILE__, line); + expect(s.find("for "s + std::to_string(ourTime) + " rounds."s) != s.npos, s, __FILE__, line); + expect(s.find("votes in "s + std::to_string(peerTime) + " rounds.") != s.npos, s, __FILE__, line); + expect(s.ends_with("has "s + std::to_string(support) + "% support. "s), s, __FILE__, line); + clog = std::make_unique(); + }; for (int i = 0; i < 1; ++i) { BEAST_EXPECT(!proposingTrue.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!proposingFalse.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!followingTrue.updateVote(250 + 10 * i, false, p)); - BEAST_EXPECT( - !followingFalse.updateVote(250 + 10 * i, false, p)); + BEAST_EXPECT(!followingFalse.updateVote(250 + 10 * i, false, p)); BEAST_EXPECT(proposingTrue.getOurVote() == true); BEAST_EXPECT(proposingFalse.getOurVote() == false); @@ -1422,20 +1278,16 @@ public: expectStalled(96, false, 11, 0, 3, __LINE__); // true vote has changed recently, so not stalled - BEAST_EXPECT( - !proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); BEAST_EXPECTS(clog->str() == "", clog->str()); // remaining votes have been unchanged in so long that we only // need to hit the second round at 95% to be stalled, regardless // of peers - BEAST_EXPECT( - proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged, j, clog)); expectStalled(98, false, 11, 6, 2, __LINE__); - BEAST_EXPECT( - followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged, j, clog)); expectStalled(97, true, 11, 6, 97, __LINE__); - BEAST_EXPECT( - followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged, j, clog)); expectStalled(96, false, 11, 6, 3, __LINE__); } for (int i = 1; i < 3; ++i) @@ -1443,8 +1295,7 @@ public: BEAST_EXPECT(!proposingTrue.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!proposingFalse.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!followingTrue.updateVote(250 + 10 * i, false, p)); - BEAST_EXPECT( - !followingFalse.updateVote(250 + 10 * i, false, p)); + BEAST_EXPECT(!followingFalse.updateVote(250 + 10 * i, false, p)); BEAST_EXPECT(proposingTrue.getOurVote() == true); BEAST_EXPECT(proposingFalse.getOurVote() == false); @@ -1465,18 +1316,14 @@ public: // true vote changed 2 rounds ago, and peers are NOT changing, // so stalled - BEAST_EXPECT( - proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(proposingTrue.stalled(p, true, peersUnchanged, j, clog)); expectStalled(99, true, 1 + i, 6, 97, __LINE__); // still stalled - BEAST_EXPECT( - proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged, j, clog)); expectStalled(98, false, 11 + i, 6, 2, __LINE__); - BEAST_EXPECT( - followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged, j, clog)); expectStalled(97, true, 11 + i, 6, 97, __LINE__); - BEAST_EXPECT( - followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged, j, clog)); expectStalled(96, false, 11 + i, 6, 3, __LINE__); } for (int i = 3; i < 5; ++i) @@ -1484,8 +1331,7 @@ public: BEAST_EXPECT(!proposingTrue.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!proposingFalse.updateVote(250 + 10 * i, true, p)); BEAST_EXPECT(!followingTrue.updateVote(250 + 10 * i, false, p)); - BEAST_EXPECT( - !followingFalse.updateVote(250 + 10 * i, false, p)); + BEAST_EXPECT(!followingFalse.updateVote(250 + 10 * i, false, p)); BEAST_EXPECT(proposingTrue.getOurVote() == true); BEAST_EXPECT(proposingFalse.getOurVote() == false); @@ -1501,17 +1347,13 @@ public: BEAST_EXPECT(followingFalse.stalled(p, false, 0, j, clog)); expectStalled(96, false, 11 + i, 0, 3, __LINE__); - BEAST_EXPECT( - proposingTrue.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(proposingTrue.stalled(p, true, peersUnchanged, j, clog)); expectStalled(99, true, 1 + i, 6, 97, __LINE__); - BEAST_EXPECT( - proposingFalse.stalled(p, true, peersUnchanged, j, clog)); + BEAST_EXPECT(proposingFalse.stalled(p, true, peersUnchanged, j, clog)); expectStalled(98, false, 11 + i, 6, 2, __LINE__); - BEAST_EXPECT( - followingTrue.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingTrue.stalled(p, false, peersUnchanged, j, clog)); expectStalled(97, true, 11 + i, 6, 97, __LINE__); - BEAST_EXPECT( - followingFalse.stalled(p, false, peersUnchanged, j, clog)); + BEAST_EXPECT(followingFalse.stalled(p, false, peersUnchanged, j, clog)); expectStalled(96, false, 11 + i, 6, 3, __LINE__); } } @@ -1537,6 +1379,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Consensus, consensus, ripple); +BEAST_DEFINE_TESTSUITE(Consensus, consensus, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/DistributedValidatorsSim_test.cpp b/src/test/consensus/DistributedValidatorsSim_test.cpp index 2f6ed74c23..49d2c6e7e2 100644 --- a/src/test/consensus/DistributedValidatorsSim_test.cpp +++ b/src/test/consensus/DistributedValidatorsSim_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { /** In progress simulations for diversifying and distributing validators @@ -54,8 +35,7 @@ class DistributedValidators_test : public beast::unit_test::suite ledgerLog(prefix + "_ledger.csv", std::ofstream::app); // title - log << prefix << "(" << numPeers << "," << delay.count() << ")" - << std::endl; + log << prefix << "(" << numPeers << "," << delay.count() << ")" << std::endl; // number of peers, UNLs, connections BEAST_EXPECT(numPeers >= 1); @@ -78,7 +58,7 @@ class DistributedValidators_test : public beast::unit_test::suite // Initial round to set prior state sim.run(1); - // Run for 10 minues, submitting 100 tx/second + // Run for 10 minutes, submitting 100 tx/second std::chrono::nanoseconds const simDuration = 10min; std::chrono::nanoseconds const quiet = 10s; Rate const rate{100, 1000ms}; @@ -87,11 +67,7 @@ class DistributedValidators_test : public beast::unit_test::suite HeartbeatTimer heart(sim.scheduler); // txs, start/stop/step, target - auto peerSelector = makeSelector( - peers.begin(), - peers.end(), - std::vector(numPeers, 1.), - sim.rng); + auto peerSelector = makeSelector(peers.begin(), peers.end(), std::vector(numPeers, 1.), sim.rng); auto txSubmitter = makeSubmitter( ConstantDistribution{rate.inv()}, sim.scheduler.now() + quiet, @@ -109,11 +85,9 @@ class DistributedValidators_test : public beast::unit_test::suite log << std::right; log << "| Peers: " << std::setw(2) << peers.size(); - log << " | Duration: " << std::setw(6) - << duration_cast(simDuration).count() << " ms"; + log << " | Duration: " << std::setw(6) << duration_cast(simDuration).count() << " ms"; log << " | Branches: " << std::setw(1) << sim.branches(); - log << " | Synchronized: " << std::setw(1) - << (sim.synchronized() ? "Y" : "N"); + log << " | Synchronized: " << std::setw(1) << (sim.synchronized() ? "Y" : "N"); log << " |" << std::endl; txCollector.report(simDuration, log, true); @@ -143,8 +117,7 @@ class DistributedValidators_test : public beast::unit_test::suite ledgerLog(prefix + "_ledger.csv", std::ofstream::app); // title - log << prefix << "(" << numPeers << "," << delay.count() << ")" - << std::endl; + log << prefix << "(" << numPeers << "," << delay.count() << ")" << std::endl; // number of peers, UNLs, connections int const numCNLs = std::max(int(1.00 * numPeers), 1); @@ -152,9 +125,7 @@ class DistributedValidators_test : public beast::unit_test::suite int const maxCNLSize = std::max(int(0.50 * numCNLs), 1); BEAST_EXPECT(numPeers >= 1); BEAST_EXPECT(numCNLs >= 1); - BEAST_EXPECT( - 1 <= minCNLSize && minCNLSize <= maxCNLSize && - maxCNLSize <= numPeers); + BEAST_EXPECT(1 <= minCNLSize && minCNLSize <= maxCNLSize && maxCNLSize <= numPeers); Sim sim; PeerGroup peers = sim.createGroup(numPeers); @@ -163,15 +134,9 @@ class DistributedValidators_test : public beast::unit_test::suite peers.trust(peers); // scale-free connect graph with fixed delay - std::vector const ranks = - sample(peers.size(), PowerLawDistribution{1, 3}, sim.rng); + std::vector const ranks = sample(peers.size(), PowerLawDistribution{1, 3}, sim.rng); randomRankedConnect( - peers, - ranks, - numCNLs, - std::uniform_int_distribution<>{minCNLSize, maxCNLSize}, - sim.rng, - delay); + peers, ranks, numCNLs, std::uniform_int_distribution<>{minCNLSize, maxCNLSize}, sim.rng, delay); // Initialize collectors to track statistics to report TxCollector txCollector; @@ -182,7 +147,7 @@ class DistributedValidators_test : public beast::unit_test::suite // Initial round to set prior state sim.run(1); - // Run for 10 minues, submitting 100 tx/second + // Run for 10 minutes, submitting 100 tx/second std::chrono::nanoseconds simDuration = 10min; std::chrono::nanoseconds quiet = 10s; Rate rate{100, 1000ms}; @@ -191,11 +156,7 @@ class DistributedValidators_test : public beast::unit_test::suite HeartbeatTimer heart(sim.scheduler); // txs, start/stop/step, target - auto peerSelector = makeSelector( - peers.begin(), - peers.end(), - std::vector(numPeers, 1.), - sim.rng); + auto peerSelector = makeSelector(peers.begin(), peers.end(), std::vector(numPeers, 1.), sim.rng); auto txSubmitter = makeSubmitter( ConstantDistribution{rate.inv()}, sim.scheduler.now() + quiet, @@ -213,11 +174,9 @@ class DistributedValidators_test : public beast::unit_test::suite log << std::right; log << "| Peers: " << std::setw(2) << peers.size(); - log << " | Duration: " << std::setw(6) - << duration_cast(simDuration).count() << " ms"; + log << " | Duration: " << std::setw(6) << duration_cast(simDuration).count() << " ms"; log << " | Branches: " << std::setw(1) << sim.branches(); - log << " | Synchronized: " << std::setw(1) - << (sim.synchronized() ? "Y" : "N"); + log << " | Synchronized: " << std::setw(1) << (sim.synchronized() ? "Y" : "N"); log << " |" << std::endl; txCollector.report(simDuration, log, true); @@ -244,8 +203,7 @@ class DistributedValidators_test : public beast::unit_test::suite std::chrono::milliseconds const delay(delayCount); - log << "DistributedValidators: 1 to " << maxNumValidators << " Peers" - << std::endl; + log << "DistributedValidators: 1 to " << maxNumValidators << " Peers" << std::endl; /** * Simulate with N = 1 to N @@ -273,7 +231,7 @@ class DistributedValidators_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DistributedValidators, consensus, ripple, 2); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(DistributedValidators, consensus, xrpl, 2); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/LedgerTiming_test.cpp b/src/test/consensus/LedgerTiming_test.cpp index 79c0f3f884..ac00cd1f3a 100644 --- a/src/test/consensus/LedgerTiming_test.cpp +++ b/src/test/consensus/LedgerTiming_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { class LedgerTiming_test : public beast::unit_test::suite @@ -45,8 +26,7 @@ class LedgerTiming_test : public beast::unit_test::suite std::uint32_t round = 0; do { - nextCloseResolution = getNextLedgerTimeResolution( - closeResolution, previousAgree, ++round); + nextCloseResolution = getNextLedgerTimeResolution(closeResolution, previousAgree, ++round); if (nextCloseResolution < closeResolution) ++res.decrease; else if (nextCloseResolution > closeResolution) @@ -124,6 +104,6 @@ class LedgerTiming_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerTiming, consensus, ripple); +BEAST_DEFINE_TESTSUITE(LedgerTiming, consensus, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/LedgerTrie_test.cpp b/src/test/consensus/LedgerTrie_test.cpp index 6ed45777f0..586b9231f6 100644 --- a/src/test/consensus/LedgerTrie_test.cpp +++ b/src/test/consensus/LedgerTrie_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class LedgerTrie_test : public beast::unit_test::suite @@ -678,6 +659,6 @@ class LedgerTrie_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(LedgerTrie, consensus, ripple); +BEAST_DEFINE_TESTSUITE(LedgerTrie, consensus, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index cc38ea5ab6..9e77f158a3 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -1,22 +1,3 @@ -//----------------------------------------------------------------------------- -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,13 +9,12 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { /* * This file implements the following negative UNL related tests: * -- test filling and applying ttUNL_MODIFY Tx and ledger update - * -- test ttUNL_MODIFY Tx failure without featureNegativeUNL amendment * -- test the NegativeUNLVote class. The test cases are split to multiple * test classes to allow parallel execution. * -- test the negativeUNLFilter function @@ -45,7 +25,7 @@ namespace test { /** * Test the size of the negative UNL in a ledger, - * also test if the ledger has ToDisalbe and/or ToReEnable + * also test if the ledger has ToDisable and/or ToReEnable * * @param l the ledger * @param size the expected negative UNL size @@ -54,11 +34,7 @@ namespace test { * @return true if meet all three expectation */ bool -negUnlSizeTest( - std::shared_ptr const& l, - size_t size, - bool hasToDisable, - bool hasToReEnable); +negUnlSizeTest(std::shared_ptr const& l, size_t size, bool hasToDisable, bool hasToReEnable); /** * Try to apply a ttUNL_MODIFY Tx, and test the apply result @@ -82,9 +58,7 @@ applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass); * @return true if meet the expectation */ bool -VerifyPubKeyAndSeq( - std::shared_ptr const& l, - hash_map nUnlLedgerSeq); +VerifyPubKeyAndSeq(std::shared_ptr const& l, hash_map nUnlLedgerSeq); /** * Count the number of Tx in a TxSet @@ -227,15 +201,11 @@ class NegativeUNL_test : public beast::unit_test::suite testcase("Create UNLModify Tx and apply to ledgers"); - jtx::Env env(*this, jtx::testable_amendments() | featureNegativeUNL); + jtx::Env env(*this, jtx::testable_amendments()); std::vector publicKeys = createPublicKeys(3); // genesis ledger auto l = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); - BEAST_EXPECT(l->rules().enabled(featureNegativeUNL)); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); // Record the public keys and ledger sequences of expected negative UNL // validators when we build the ledger history @@ -243,8 +213,7 @@ class NegativeUNL_test : public beast::unit_test::suite { //(1) the ledger after genesis, not a flag ledger - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]); auto txReEnable_1 = createTx(false, l->seq(), publicKeys[1]); @@ -261,8 +230,7 @@ class NegativeUNL_test : public beast::unit_test::suite // generate more ledgers for (auto i = 0; i < 256 - 2; ++i) { - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -297,8 +265,7 @@ class NegativeUNL_test : public beast::unit_test::suite BEAST_EXPECT(good_size); if (good_size) BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]); - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -350,8 +317,7 @@ class NegativeUNL_test : public beast::unit_test::suite BEAST_EXPECT(l->validatorToDisable() == publicKeys[1]); BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]); } - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -393,8 +359,7 @@ class NegativeUNL_test : public beast::unit_test::suite BEAST_EXPECT(l->negativeUNL().count(publicKeys[1])); BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]); } - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -443,8 +408,7 @@ class NegativeUNL_test : public beast::unit_test::suite BEAST_EXPECT(l->negativeUNL().count(publicKeys[1])); BEAST_EXPECT(l->validatorToReEnable() == publicKeys[0]); } - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -486,8 +450,7 @@ class NegativeUNL_test : public beast::unit_test::suite BEAST_EXPECT(l->negativeUNL().count(publicKeys[1])); BEAST_EXPECT(l->validatorToReEnable() == publicKeys[1]); } - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -501,8 +464,7 @@ class NegativeUNL_test : public beast::unit_test::suite for (auto i = 0; i < 256; ++i) { BEAST_EXPECT(negUnlSizeTest(l, 0, false, false)); - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); } BEAST_EXPECT(l->isFlagLedger()); l->updateNegativeUNL(); @@ -519,44 +481,6 @@ class NegativeUNL_test : public beast::unit_test::suite } }; -class NegativeUNLNoAmendment_test : public beast::unit_test::suite -{ - void - testNegativeUNLNoAmendment() - { - testcase("No negative UNL amendment"); - - jtx::Env env(*this, jtx::testable_amendments() - featureNegativeUNL); - std::vector publicKeys = createPublicKeys(1); - // genesis ledger - auto l = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); - BEAST_EXPECT(!l->rules().enabled(featureNegativeUNL)); - - // generate more ledgers - for (auto i = 0; i < 256 - 1; ++i) - { - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); - } - BEAST_EXPECT(l->seq() == 256); - auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]); - OpenView accum(&*l); - BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, false)); - accum.apply(*l); - BEAST_EXPECT(negUnlSizeTest(l, 0, false, false)); - } - - void - run() override - { - testNegativeUNLNoAmendment(); - } -}; - /** * Utility class for creating validators and ledger history */ @@ -582,9 +506,7 @@ struct NetworkHistory }; NetworkHistory(beast::unit_test::suite& suite, Parameter const& p) - : env(suite, jtx::testable_amendments() | featureNegativeUNL) - , param(p) - , validations(env.app().getValidations()) + : env(suite, jtx::testable_amendments()), param(p), validations(env.app().getValidations()) { createNodes(); if (!param.numLedgers) @@ -612,12 +534,9 @@ struct NetworkHistory bool createLedgerHistory() { - static uint256 fake_amemdment; // So we have different genesis ledgers + static uint256 fake_amendment; // So we have different genesis ledgers auto l = std::make_shared( - create_genesis, - env.app().config(), - std::vector{fake_amemdment++}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{fake_amendment++}, env.app().getNodeFamily()); history.push_back(l); // When putting validators into the negative UNL, we start with @@ -625,8 +544,7 @@ struct NetworkHistory int nidx = 0; while (l->seq() <= param.numLedgers) { - l = std::make_shared( - *l, env.app().timeKeeper().closeTime()); + l = std::make_shared(*l, env.app().timeKeeper().closeTime()); history.push_back(l); if (l->isFlagLedger()) @@ -660,8 +578,7 @@ struct NetworkHistory } l->updateSkipList(); } - return negUnlSizeTest( - l, param.negUNLSize, param.hasToDisable, param.hasToReEnable); + return negUnlSizeTest(l, param.negUNLSize, param.hasToDisable, param.hasToReEnable); } /** @@ -675,12 +592,8 @@ struct NetworkHistory { static auto keyPair = randomKeyPair(KeyType::secp256k1); return std::make_shared( - env.app().timeKeeper().now(), - keyPair.first, - keyPair.second, - v, - [&](STValidation& v) { - v.setFieldH256(sfLedgerHash, ledger->info().hash); + env.app().timeKeeper().now(), keyPair.first, keyPair.second, v, [&](STValidation& v) { + v.setFieldH256(sfLedgerHash, ledger->header().hash); v.setFieldU32(sfLedgerSequence, ledger->seq()); v.setFlag(vfFullValidation); }); @@ -747,18 +660,12 @@ auto defaultPreVote = [](NegativeUNLVote& vote) {}; */ template bool -voteAndCheck( - NetworkHistory& history, - NodeID const& myId, - std::size_t expect, - PreVote const& pre = defaultPreVote) +voteAndCheck(NetworkHistory& history, NodeID const& myId, std::size_t expect, PreVote const& pre = defaultPreVote) { NegativeUNLVote vote(myId, history.env.journal); pre(vote); - auto txSet = std::make_shared( - SHAMapType::TRANSACTION, history.env.app().getNodeFamily()); - vote.doVoting( - history.lastLedger(), history.UNLKeySet, history.validations, txSet); + auto txSet = std::make_shared(SHAMapType::TRANSACTION, history.env.app().getNodeFamily()); + vote.doVoting(history.lastLedger(), history.UNLKeySet, history.validations, txSet); return countTx(txSet) == expect; } @@ -777,12 +684,9 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite NegativeUNLVote vote(myId, env.journal); // one add, one remove - auto txSet = std::make_shared( - SHAMapType::TRANSACTION, env.app().getNodeFamily()); - PublicKey toDisableKey( - derivePublicKey(KeyType::ed25519, randomSecretKey())); - PublicKey toReEnableKey( - derivePublicKey(KeyType::ed25519, randomSecretKey())); + auto txSet = std::make_shared(SHAMapType::TRANSACTION, env.app().getNodeFamily()); + PublicKey toDisableKey(derivePublicKey(KeyType::ed25519, randomSecretKey())); + PublicKey toReEnableKey(derivePublicKey(KeyType::ed25519, randomSecretKey())); LedgerIndex seq(1234); BEAST_EXPECT(countTx(txSet) == 0); vote.addTx(seq, toDisableKey, NegativeUNLVote::ToDisable, txSet); @@ -836,12 +740,8 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite BEAST_EXPECT(history.goodHistory); if (history.goodHistory) { - NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); - BEAST_EXPECT(!vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations)); + NegativeUNLVote vote(history.UNLNodeIDs[3], history.env.journal); + BEAST_EXPECT(!vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations)); } } @@ -851,12 +751,8 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite BEAST_EXPECT(history.goodHistory); if (history.goodHistory) { - NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); - BEAST_EXPECT(!vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations)); + NegativeUNLVote vote(history.UNLNodeIDs[3], history.env.journal); + BEAST_EXPECT(!vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations)); } } @@ -868,18 +764,12 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite { NodeID myId = history.UNLNodeIDs[3]; history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { // skip half my validations. - return !( - history.UNLNodeIDs[idx] == myId && - l->seq() % 2 == 0); + return !(history.UNLNodeIDs[idx] == myId && l->seq() % 2 == 0); }); NegativeUNLVote vote(myId, history.env.journal); - BEAST_EXPECT(!vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations)); + BEAST_EXPECT(!vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations)); } } @@ -890,8 +780,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite // We need two chains for these tests bool wrongChainSuccess = history.goodHistory; BEAST_EXPECT(wrongChainSuccess); - NetworkHistory::LedgerHistory wrongChain = - std::move(history.history); + NetworkHistory::LedgerHistory wrongChain = std::move(history.history); // Create a new chain and use it as the one that majority of nodes // follow history.createLedgerHistory(); @@ -902,8 +791,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite NodeID myId = history.UNLNodeIDs[3]; NodeID badNode = history.UNLNodeIDs[4]; history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { // everyone but me return !(history.UNLNodeIDs[idx] == myId); }); @@ -922,10 +810,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite // local node still on wrong chain, can build a scoreTable, // but all other nodes' scores are zero - auto scoreTable = vote.buildScoreTable( - wrongChain.back(), - history.UNLNodeIDSet, - history.validations); + auto scoreTable = vote.buildScoreTable(wrongChain.back(), history.UNLNodeIDSet, history.validations); BEAST_EXPECT(scoreTable); if (scoreTable) { @@ -940,10 +825,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite // if local node switched to right history, but cannot build // scoreTable because not enough local validations - BEAST_EXPECT(!vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations)); + BEAST_EXPECT(!vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations)); } } @@ -954,14 +836,9 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return true; }); - NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); - auto scoreTable = vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); + NegativeUNLVote vote(history.UNLNodeIDs[3], history.env.journal); + auto scoreTable = vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations); BEAST_EXPECT(scoreTable); if (scoreTable) { @@ -996,8 +873,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite std::size_t numDisable, std::size_t numReEnable) { - auto [disableCandidates, reEnableCandidates] = - vote.findAllCandidates(unl, negUnl, scoreTable); + auto [disableCandidates, reEnableCandidates] = vote.findAllCandidates(unl, negUnl, scoreTable); bool rightDisable = disableCandidates.size() == numDisable; bool rightReEnable = reEnableCandidates.size() == numReEnable; return rightDisable && rightReEnable; @@ -1038,44 +914,36 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite { // all good scores - BEAST_EXPECT(checkCandidateSizes( - vote, history.UNLNodeIDSet, negUnl_012, goodScoreTable, 0, 3)); + BEAST_EXPECT(checkCandidateSizes(vote, history.UNLNodeIDSet, negUnl_012, goodScoreTable, 0, 3)); } { // all bad scores hash_map scoreTable; for (auto& n : history.UNLNodeIDs) scoreTable[n] = NegativeUNLVote::negativeUNLLowWaterMark - 1; - BEAST_EXPECT(checkCandidateSizes( - vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 35 - 3, 0)); + BEAST_EXPECT(checkCandidateSizes(vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 35 - 3, 0)); } { // all between watermarks hash_map scoreTable; for (auto& n : history.UNLNodeIDs) scoreTable[n] = NegativeUNLVote::negativeUNLLowWaterMark + 1; - BEAST_EXPECT(checkCandidateSizes( - vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 0, 0)); + BEAST_EXPECT(checkCandidateSizes(vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 0, 0)); } { // 2 good scorers in negUnl auto scoreTable = goodScoreTable; - scoreTable[*negUnl_012.begin()] = - NegativeUNLVote::negativeUNLLowWaterMark + 1; - BEAST_EXPECT(checkCandidateSizes( - vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 0, 2)); + scoreTable[*negUnl_012.begin()] = NegativeUNLVote::negativeUNLLowWaterMark + 1; + BEAST_EXPECT(checkCandidateSizes(vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 0, 2)); } { // 2 bad scorers not in negUnl auto scoreTable = goodScoreTable; - scoreTable[history.UNLNodeIDs[11]] = - NegativeUNLVote::negativeUNLLowWaterMark - 1; - scoreTable[history.UNLNodeIDs[12]] = - NegativeUNLVote::negativeUNLLowWaterMark - 1; - BEAST_EXPECT(checkCandidateSizes( - vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 2, 3)); + scoreTable[history.UNLNodeIDs[11]] = NegativeUNLVote::negativeUNLLowWaterMark - 1; + scoreTable[history.UNLNodeIDs[12]] = NegativeUNLVote::negativeUNLLowWaterMark - 1; + BEAST_EXPECT(checkCandidateSizes(vote, history.UNLNodeIDSet, negUnl_012, scoreTable, 2, 3)); } { @@ -1084,8 +952,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite hash_set UNL_temp = history.UNLNodeIDSet; UNL_temp.erase(history.UNLNodeIDs[0]); UNL_temp.erase(history.UNLNodeIDs[1]); - BEAST_EXPECT(checkCandidateSizes( - vote, UNL_temp, negUnl_012, goodScoreTable, 0, 3)); + BEAST_EXPECT(checkCandidateSizes(vote, UNL_temp, negUnl_012, goodScoreTable, 0, 3)); } { @@ -1093,13 +960,11 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite auto scoreTable = goodScoreTable; scoreTable.erase(history.UNLNodeIDs[0]); scoreTable.erase(history.UNLNodeIDs[1]); - scoreTable[history.UNLNodeIDs[2]] = - NegativeUNLVote::negativeUNLLowWaterMark + 1; + scoreTable[history.UNLNodeIDs[2]] = NegativeUNLVote::negativeUNLLowWaterMark + 1; hash_set UNL_temp = history.UNLNodeIDSet; UNL_temp.erase(history.UNLNodeIDs[0]); UNL_temp.erase(history.UNLNodeIDs[1]); - BEAST_EXPECT(checkCandidateSizes( - vote, UNL_temp, negUnl_012, scoreTable, 0, 2)); + BEAST_EXPECT(checkCandidateSizes(vote, UNL_temp, negUnl_012, scoreTable, 0, 2)); } { @@ -1114,33 +979,27 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite { // 2 new validators have good scores, already in negUnl auto scoreTable = goodScoreTable; - scoreTable[new_1] = - NegativeUNLVote::negativeUNLHighWaterMark + 1; - scoreTable[new_2] = - NegativeUNLVote::negativeUNLHighWaterMark + 1; + scoreTable[new_1] = NegativeUNLVote::negativeUNLHighWaterMark + 1; + scoreTable[new_2] = NegativeUNLVote::negativeUNLHighWaterMark + 1; hash_set negUnl_temp = negUnl_012; negUnl_temp.insert(new_1); negUnl_temp.insert(new_2); - BEAST_EXPECT(checkCandidateSizes( - vote, UNL_temp, negUnl_temp, scoreTable, 0, 3 + 2)); + BEAST_EXPECT(checkCandidateSizes(vote, UNL_temp, negUnl_temp, scoreTable, 0, 3 + 2)); } { // 2 new validators have bad scores, not in negUnl auto scoreTable = goodScoreTable; scoreTable[new_1] = 0; scoreTable[new_2] = 0; - BEAST_EXPECT(checkCandidateSizes( - vote, UNL_temp, negUnl_012, scoreTable, 0, 3)); + BEAST_EXPECT(checkCandidateSizes(vote, UNL_temp, negUnl_012, scoreTable, 0, 3)); } { // expired the new validators have bad scores, not in negUnl - vote.purgeNewValidators( - 256 + NegativeUNLVote::newValidatorDisableSkip + 1); + vote.purgeNewValidators(256 + NegativeUNLVote::newValidatorDisableSkip + 1); auto scoreTable = goodScoreTable; scoreTable[new_1] = 0; scoreTable[new_2] = 0; - BEAST_EXPECT(checkCandidateSizes( - vote, UNL_temp, negUnl_012, scoreTable, 2, 3)); + BEAST_EXPECT(checkCandidateSizes(vote, UNL_temp, negUnl_012, scoreTable, 2, 3)); } } } @@ -1184,24 +1043,23 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite //== combination 1: { - auto fillScoreTable = - [&](std::uint32_t unl_size, - std::uint32_t nUnl_size, - std::uint32_t score, - hash_set& unl, - hash_set& negUnl, - hash_map& scoreTable) { - std::vector nodeIDs; - std::vector keys = createPublicKeys(unl_size); - for (auto const& k : keys) - { - nodeIDs.emplace_back(calcNodeID(k)); - unl.emplace(nodeIDs.back()); - scoreTable[nodeIDs.back()] = score; - } - for (std::uint32_t i = 0; i < nUnl_size; ++i) - negUnl.insert(nodeIDs[i]); - }; + auto fillScoreTable = [&](std::uint32_t unl_size, + std::uint32_t nUnl_size, + std::uint32_t score, + hash_set& unl, + hash_set& negUnl, + hash_map& scoreTable) { + std::vector nodeIDs; + std::vector keys = createPublicKeys(unl_size); + for (auto const& k : keys) + { + nodeIDs.emplace_back(calcNodeID(k)); + unl.emplace(nodeIDs.back()); + scoreTable[nodeIDs.back()] = score; + } + for (std::uint32_t i = 0; i < nUnl_size; ++i) + negUnl.insert(nodeIDs[i]); + }; for (auto us : unlSizes) { @@ -1212,8 +1070,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite hash_set unl; hash_set negUnl; hash_map scoreTable; - fillScoreTable( - us, us * np / 100, score, unl, negUnl, scoreTable); + fillScoreTable(us, us * np / 100, score, unl, negUnl, scoreTable); BEAST_EXPECT(unl.size() == us); BEAST_EXPECT(negUnl.size() == us * np / 100); BEAST_EXPECT(scoreTable.size() == us); @@ -1222,77 +1079,67 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite std::size_t toReEnable_expect = 0; if (np == 0) { - if (score < - NegativeUNLVote::negativeUNLLowWaterMark) + if (score < NegativeUNLVote::negativeUNLLowWaterMark) { toDisable_expect = us; } } else if (np == 50) { - if (score > - NegativeUNLVote::negativeUNLHighWaterMark) + if (score > NegativeUNLVote::negativeUNLHighWaterMark) { toReEnable_expect = us * np / 100; } } else { - if (score > - NegativeUNLVote::negativeUNLHighWaterMark) + if (score > NegativeUNLVote::negativeUNLHighWaterMark) { toReEnable_expect = us; } } - BEAST_EXPECT(checkCandidateSizes( - vote, - unl, - negUnl, - scoreTable, - toDisable_expect, - toReEnable_expect)); + BEAST_EXPECT( + checkCandidateSizes(vote, unl, negUnl, scoreTable, toDisable_expect, toReEnable_expect)); } } } //== combination 2: { - auto fillScoreTable = - [&](std::uint32_t unl_size, - std::uint32_t nUnl_percent, - hash_set& unl, - hash_set& negUnl, - hash_map& scoreTable) { - std::vector nodeIDs; - std::vector keys = - createPublicKeys(unl_size); - for (auto const& k : keys) - { - nodeIDs.emplace_back(calcNodeID(k)); - unl.emplace(nodeIDs.back()); - } + auto fillScoreTable = [&](std::uint32_t unl_size, + std::uint32_t nUnl_percent, + hash_set& unl, + hash_set& negUnl, + hash_map& scoreTable) { + std::vector nodeIDs; + std::vector keys = createPublicKeys(unl_size); + for (auto const& k : keys) + { + nodeIDs.emplace_back(calcNodeID(k)); + unl.emplace(nodeIDs.back()); + } - std::uint32_t nIdx = 0; - for (auto score : scores) - { - scoreTable[nodeIDs[nIdx++]] = score; - scoreTable[nodeIDs[nIdx++]] = score; - } - for (; nIdx < unl_size;) - { - scoreTable[nodeIDs[nIdx++]] = scores.back(); - } + std::uint32_t nIdx = 0; + for (auto score : scores) + { + scoreTable[nodeIDs[nIdx++]] = score; + scoreTable[nodeIDs[nIdx++]] = score; + } + for (; nIdx < unl_size;) + { + scoreTable[nodeIDs[nIdx++]] = scores.back(); + } - if (nUnl_percent == 100) - { - negUnl = unl; - } - else if (nUnl_percent == 50) - { - for (std::uint32_t i = 1; i < unl_size; i += 2) - negUnl.insert(nodeIDs[i]); - } - }; + if (nUnl_percent == 100) + { + negUnl = unl; + } + else if (nUnl_percent == 50) + { + for (std::uint32_t i = 1; i < unl_size; i += 2) + negUnl.insert(nodeIDs[i]); + } + }; for (auto us : unlSizes) { @@ -1321,13 +1168,8 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite { toReEnable_expect = negUnl.size() - 12; } - BEAST_EXPECT(checkCandidateSizes( - vote, - unl, - negUnl, - scoreTable, - toDisable_expect, - toReEnable_expect)); + BEAST_EXPECT( + checkCandidateSizes(vote, unl, negUnl, scoreTable, toDisable_expect, toReEnable_expect)); } } } @@ -1369,16 +1211,13 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite BEAST_EXPECT(vote.newValidators_[n2] == 3); } - vote.newValidators( - NegativeUNLVote::newValidatorDisableSkip, {n1, n2, n3}); + vote.newValidators(NegativeUNLVote::newValidatorDisableSkip, {n1, n2, n3}); BEAST_EXPECT(vote.newValidators_.size() == 3); if (vote.newValidators_.size() == 3) { BEAST_EXPECT(vote.newValidators_[n1] == 2); BEAST_EXPECT(vote.newValidators_[n2] == 3); - BEAST_EXPECT( - vote.newValidators_[n3] == - NegativeUNLVote::newValidatorDisableSkip); + BEAST_EXPECT(vote.newValidators_[n3] == NegativeUNLVote::newValidatorDisableSkip); } vote.purgeNewValidators(NegativeUNLVote::newValidatorDisableSkip + 2); @@ -1388,9 +1227,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite vote.purgeNewValidators(NegativeUNLVote::newValidatorDisableSkip + 4); BEAST_EXPECT(vote.newValidators_.size() == 1); BEAST_EXPECT(vote.newValidators_.begin()->first == n3); - BEAST_EXPECT( - vote.newValidators_.begin()->second == - NegativeUNLVote::newValidatorDisableSkip); + BEAST_EXPECT(vote.newValidators_.begin()->second == NegativeUNLVote::newValidatorDisableSkip); } void @@ -1430,15 +1267,13 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite { for (std::uint32_t sp = 0; sp < 4; ++sp) { - NetworkHistory history = { - *this, {unlSize, 0, false, false, 256 + 2}}; + NetworkHistory history = {*this, {unlSize, 0, false, false, 256 + 2}}; BEAST_EXPECT(history.goodHistory); if (history.goodHistory) { NodeID myId = history.UNLNodeIDs[3]; history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { std::size_t k; if (idx < 2) k = 0; @@ -1447,24 +1282,20 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite else k = 2; - bool add_50 = - scorePattern[sp][k] == 50 && l->seq() % 2 == 0; + bool add_50 = scorePattern[sp][k] == 50 && l->seq() % 2 == 0; bool add_100 = scorePattern[sp][k] == 100; bool add_me = history.UNLNodeIDs[idx] == myId; return add_50 || add_100 || add_me; }); NegativeUNLVote vote(myId, history.env.journal); - auto scoreTable = vote.buildScoreTable( - history.lastLedger(), - history.UNLNodeIDSet, - history.validations); + auto scoreTable = + vote.buildScoreTable(history.lastLedger(), history.UNLNodeIDSet, history.validations); BEAST_EXPECT(scoreTable); if (scoreTable) { std::uint32_t i = 0; // looping unl - auto checkScores = [&](std::uint32_t score, - std::uint32_t k) -> bool { + auto checkScores = [&](std::uint32_t score, std::uint32_t k) -> bool { if (history.UNLNodeIDs[i] == myId) return score == 256; if (scorePattern[sp][k] == 0) @@ -1478,18 +1309,15 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite }; for (; i < 2; ++i) { - BEAST_EXPECT(checkScores( - (*scoreTable)[history.UNLNodeIDs[i]], 0)); + BEAST_EXPECT(checkScores((*scoreTable)[history.UNLNodeIDs[i]], 0)); } for (; i < 4; ++i) { - BEAST_EXPECT(checkScores( - (*scoreTable)[history.UNLNodeIDs[i]], 1)); + BEAST_EXPECT(checkScores((*scoreTable)[history.UNLNodeIDs[i]], 1)); } for (; i < unlSize; ++i) { - BEAST_EXPECT(checkScores( - (*scoreTable)[history.UNLNodeIDs[i]], 2)); + BEAST_EXPECT(checkScores((*scoreTable)[history.UNLNodeIDs[i]], 2)); } } } @@ -1551,8 +1379,7 @@ class NegativeUNLVoteGoodScore_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return true; }); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs[0], 0)); } } @@ -1565,8 +1392,7 @@ class NegativeUNLVoteGoodScore_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return true; }); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs[0], 1)); } } @@ -1594,13 +1420,11 @@ class NegativeUNLVoteOffline_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { // skip node 0 and node 1 return idx > 1; }); - BEAST_EXPECT( - voteAndCheck(history, history.UNLNodeIDs.back(), 1)); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs.back(), 1)); } } @@ -1611,19 +1435,14 @@ class NegativeUNLVoteOffline_test : public beast::unit_test::suite BEAST_EXPECT(history.goodHistory); if (history.goodHistory) { - NodeID n1 = - calcNodeID(*history.lastLedger()->negativeUNL().begin()); - NodeID n2 = - calcNodeID(*history.lastLedger()->validatorToDisable()); + NodeID n1 = calcNodeID(*history.lastLedger()->negativeUNL().begin()); + NodeID n2 = calcNodeID(*history.lastLedger()->validatorToDisable()); history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { // skip node 0 and node 1 - return history.UNLNodeIDs[idx] != n1 && - history.UNLNodeIDs[idx] != n2; + return history.UNLNodeIDs[idx] != n1 && history.UNLNodeIDs[idx] != n2; }); - BEAST_EXPECT( - voteAndCheck(history, history.UNLNodeIDs.back(), 0)); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs.back(), 0)); } } } @@ -1650,13 +1469,11 @@ class NegativeUNLVoteMaxListed_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { + [&](std::shared_ptr const& l, std::size_t idx) -> bool { // skip node 0 ~ 10 return idx > 10; }); - BEAST_EXPECT( - voteAndCheck(history, history.UNLNodeIDs.back(), 0)); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs.back(), 0)); } } } @@ -1683,8 +1500,7 @@ class NegativeUNLVoteRetiredValidator_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return idx > 1; }); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return idx > 1; }); BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs[0], 0)); } } @@ -1697,8 +1513,7 @@ class NegativeUNLVoteRetiredValidator_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return idx > 1; }); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return idx > 1; }); BEAST_EXPECT(voteAndCheck(history, NodeID(0xdeadbeef), 0)); } } @@ -1711,16 +1526,11 @@ class NegativeUNLVoteRetiredValidator_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return idx > 1; }); - BEAST_EXPECT(voteAndCheck( - history, - history.UNLNodeIDs.back(), - 1, - [&](NegativeUNLVote& vote) { - history.UNLKeySet.erase(history.UNLKeys[0]); - history.UNLKeySet.erase(history.UNLKeys[1]); - })); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return idx > 1; }); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs.back(), 1, [&](NegativeUNLVote& vote) { + history.UNLKeySet.erase(history.UNLKeys[0]); + history.UNLKeySet.erase(history.UNLKeys[1]); + })); } } } @@ -1747,60 +1557,39 @@ class NegativeUNLVoteNewValidator_test : public beast::unit_test::suite if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return true; }); - BEAST_EXPECT(voteAndCheck( - history, - history.UNLNodeIDs[0], - 0, - [&](NegativeUNLVote& vote) { - auto extra_key_1 = - randomKeyPair(KeyType::ed25519).first; - auto extra_key_2 = - randomKeyPair(KeyType::ed25519).first; - history.UNLKeySet.insert(extra_key_1); - history.UNLKeySet.insert(extra_key_2); - hash_set nowTrusted; - nowTrusted.insert(calcNodeID(extra_key_1)); - nowTrusted.insert(calcNodeID(extra_key_2)); - vote.newValidators( - history.lastLedger()->seq(), nowTrusted); - })); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs[0], 0, [&](NegativeUNLVote& vote) { + auto extra_key_1 = randomKeyPair(KeyType::ed25519).first; + auto extra_key_2 = randomKeyPair(KeyType::ed25519).first; + history.UNLKeySet.insert(extra_key_1); + history.UNLKeySet.insert(extra_key_2); + hash_set nowTrusted; + nowTrusted.insert(calcNodeID(extra_key_1)); + nowTrusted.insert(calcNodeID(extra_key_2)); + vote.newValidators(history.lastLedger()->seq(), nowTrusted); + })); } } { //== 2 expired new validators have bad scores //-- txSet.size = 1 - NetworkHistory history = { - *this, - {21, - 0, - false, - false, - NegativeUNLVote::newValidatorDisableSkip * 2}}; + NetworkHistory history = {*this, {21, 0, false, false, NegativeUNLVote::newValidatorDisableSkip * 2}}; BEAST_EXPECT(history.goodHistory); if (history.goodHistory) { history.walkHistoryAndAddValidations( - [&](std::shared_ptr const& l, - std::size_t idx) -> bool { return true; }); - BEAST_EXPECT(voteAndCheck( - history, - history.UNLNodeIDs[0], - 1, - [&](NegativeUNLVote& vote) { - auto extra_key_1 = - randomKeyPair(KeyType::ed25519).first; - auto extra_key_2 = - randomKeyPair(KeyType::ed25519).first; - history.UNLKeySet.insert(extra_key_1); - history.UNLKeySet.insert(extra_key_2); - hash_set nowTrusted; - nowTrusted.insert(calcNodeID(extra_key_1)); - nowTrusted.insert(calcNodeID(extra_key_2)); - vote.newValidators(256, nowTrusted); - })); + [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); + BEAST_EXPECT(voteAndCheck(history, history.UNLNodeIDs[0], 1, [&](NegativeUNLVote& vote) { + auto extra_key_1 = randomKeyPair(KeyType::ed25519).first; + auto extra_key_2 = randomKeyPair(KeyType::ed25519).first; + history.UNLKeySet.insert(extra_key_1); + history.UNLKeySet.insert(extra_key_2); + hash_set nowTrusted; + nowTrusted.insert(calcNodeID(extra_key_1)); + nowTrusted.insert(calcNodeID(extra_key_2)); + vote.newValidators(256, nowTrusted); + })); } } } @@ -1820,19 +1609,12 @@ class NegativeUNLVoteFilterValidations_test : public beast::unit_test::suite testcase("Filter Validations"); jtx::Env env(*this); auto l = std::make_shared( - create_genesis, - env.app().config(), - std::vector{}, - env.app().getNodeFamily()); + create_genesis, env.app().config(), std::vector{}, env.app().getNodeFamily()); auto createSTVal = [&](std::pair const& keys) { return std::make_shared( - env.app().timeKeeper().now(), - keys.first, - keys.second, - calcNodeID(keys.first), - [&](STValidation& v) { - v.setFieldH256(sfLedgerHash, l->info().hash); + env.app().timeKeeper().now(), keys.first, keys.second, calcNodeID(keys.first), [&](STValidation& v) { + v.setFieldH256(sfLedgerHash, l->header().hash); v.setFieldU32(sfLedgerSequence, l->seq()); v.setFlag(vfFullValidation); }); @@ -1885,37 +1667,26 @@ class NegativeUNLVoteFilterValidations_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus, ripple); -BEAST_DEFINE_TESTSUITE(NegativeUNLNoAmendment, consensus, ripple); +BEAST_DEFINE_TESTSUITE(NegativeUNL, consensus, xrpl); -BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus, ripple); -BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus, ripple); -BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteGoodScore, consensus, ripple, 1); -BEAST_DEFINE_TESTSUITE(NegativeUNLVoteOffline, consensus, ripple); -BEAST_DEFINE_TESTSUITE(NegativeUNLVoteMaxListed, consensus, ripple); -BEAST_DEFINE_TESTSUITE_PRIO( - NegativeUNLVoteRetiredValidator, - consensus, - ripple, - 1); -BEAST_DEFINE_TESTSUITE(NegativeUNLVoteNewValidator, consensus, ripple); -BEAST_DEFINE_TESTSUITE(NegativeUNLVoteFilterValidations, consensus, ripple); +BEAST_DEFINE_TESTSUITE(NegativeUNLVoteInternal, consensus, xrpl); +BEAST_DEFINE_TESTSUITE_MANUAL(NegativeUNLVoteScoreTable, consensus, xrpl); +BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteGoodScore, consensus, xrpl, 1); +BEAST_DEFINE_TESTSUITE(NegativeUNLVoteOffline, consensus, xrpl); +BEAST_DEFINE_TESTSUITE(NegativeUNLVoteMaxListed, consensus, xrpl); +BEAST_DEFINE_TESTSUITE_PRIO(NegativeUNLVoteRetiredValidator, consensus, xrpl, 1); +BEAST_DEFINE_TESTSUITE(NegativeUNLVoteNewValidator, consensus, xrpl); +BEAST_DEFINE_TESTSUITE(NegativeUNLVoteFilterValidations, consensus, xrpl); /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// bool -negUnlSizeTest( - std::shared_ptr const& l, - size_t size, - bool hasToDisable, - bool hasToReEnable) +negUnlSizeTest(std::shared_ptr const& l, size_t size, bool hasToDisable, bool hasToReEnable) { bool sameSize = l->negativeUNL().size() == size; - bool sameToDisable = - (l->validatorToDisable() != std::nullopt) == hasToDisable; - bool sameToReEnable = - (l->validatorToReEnable() != std::nullopt) == hasToReEnable; + bool sameToDisable = (l->validatorToDisable() != std::nullopt) == hasToDisable; + bool sameToReEnable = (l->validatorToReEnable() != std::nullopt) == hasToReEnable; return sameSize && sameToDisable && sameToReEnable; } @@ -1923,8 +1694,7 @@ negUnlSizeTest( bool applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass) { - auto const res = - apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal); + auto const res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal); if (pass) return res.ter == tesSUCCESS; else @@ -1932,9 +1702,7 @@ applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass) } bool -VerifyPubKeyAndSeq( - std::shared_ptr const& l, - hash_map nUnlLedgerSeq) +VerifyPubKeyAndSeq(std::shared_ptr const& l, hash_map nUnlLedgerSeq) { auto sle = l->read(keylet::negativeUNL()); if (!sle) @@ -1948,8 +1716,7 @@ VerifyPubKeyAndSeq( for (auto const& n : nUnlData) { - if (!n.isFieldPresent(sfFirstLedgerSequence) || - !n.isFieldPresent(sfPublicKey)) + if (!n.isFieldPresent(sfFirstLedgerSequence) || !n.isFieldPresent(sfPublicKey)) return false; auto seq = n.getFieldU32(sfFirstLedgerSequence); @@ -2007,4 +1774,4 @@ createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey) } } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/RCLCensorshipDetector_test.cpp b/src/test/consensus/RCLCensorshipDetector_test.cpp index 1581dc81c4..4093ffe900 100644 --- a/src/test/consensus/RCLCensorshipDetector_test.cpp +++ b/src/test/consensus/RCLCensorshipDetector_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class RCLCensorshipDetector_test : public beast::unit_test::suite @@ -98,6 +79,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RCLCensorshipDetector, consensus, ripple); +BEAST_DEFINE_TESTSUITE(RCLCensorshipDetector, consensus, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/ScaleFreeSim_test.cpp b/src/test/consensus/ScaleFreeSim_test.cpp index 226cf5bfed..ae70ee9174 100644 --- a/src/test/consensus/ScaleFreeSim_test.cpp +++ b/src/test/consensus/ScaleFreeSim_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class ScaleFreeSim_test : public beast::unit_test::suite @@ -48,20 +29,13 @@ class ScaleFreeSim_test : public beast::unit_test::suite PeerGroup network = sim.createGroup(N); // generate trust ranks - std::vector const ranks = - sample(network.size(), PowerLawDistribution{1, 3}, sim.rng); + std::vector const ranks = sample(network.size(), PowerLawDistribution{1, 3}, sim.rng); // generate scale-free trust graph - randomRankedTrust( - network, - ranks, - numUNLs, - std::uniform_int_distribution<>{minUNLSize, maxUNLSize}, - sim.rng); + randomRankedTrust(network, ranks, numUNLs, std::uniform_int_distribution<>{minUNLSize, maxUNLSize}, sim.rng); // nodes with a trust line in either direction are network-connected - network.connectFromTrust( - round(0.2 * parms.ledgerGRANULARITY)); + network.connectFromTrust(round(0.2 * parms.ledgerGRANULARITY)); // Initialize collectors to track statistics to report TxCollector txCollector; @@ -75,14 +49,13 @@ class ScaleFreeSim_test : public beast::unit_test::suite // Initialize timers HeartbeatTimer heart(sim.scheduler, seconds(10s)); - // Run for 10 minues, submitting 100 tx/second + // Run for 10 minutes, submitting 100 tx/second std::chrono::nanoseconds const simDuration = 10min; std::chrono::nanoseconds const quiet = 10s; Rate const rate{100, 1000ms}; // txs, start/stop/step, target - auto peerSelector = - makeSelector(network.begin(), network.end(), ranks, sim.rng); + auto peerSelector = makeSelector(network.begin(), network.end(), ranks, sim.rng); auto txSubmitter = makeSubmitter( ConstantDistribution{rate.inv()}, sim.scheduler.now() + quiet, @@ -101,12 +74,9 @@ class ScaleFreeSim_test : public beast::unit_test::suite // TODO: Clean up this formatting mess!! log << "Peers: " << network.size() << std::endl; - log << "Simulated Duration: " - << duration_cast(simDuration).count() << " ms" - << std::endl; + log << "Simulated Duration: " << duration_cast(simDuration).count() << " ms" << std::endl; log << "Branches: " << sim.branches() << std::endl; - log << "Synchronized: " << (sim.synchronized() ? "Y" : "N") - << std::endl; + log << "Synchronized: " << (sim.synchronized() ? "Y" : "N") << std::endl; log << std::endl; txCollector.report(simDuration, log); @@ -119,7 +89,7 @@ class ScaleFreeSim_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(ScaleFreeSim, consensus, ripple, 80); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(ScaleFreeSim, consensus, xrpl, 80); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp index a04e62b723..34e0c23bad 100644 --- a/src/test/consensus/Validations_test.cpp +++ b/src/test/consensus/Validations_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { class Validations_test : public beast::unit_test::suite @@ -44,8 +25,7 @@ class Validations_test : public beast::unit_test::suite // generated NetClock time to be well past its epoch to ensure // any subtractions are positive using namespace std::chrono; - return NetClock::time_point(duration_cast( - c.now().time_since_epoch() + 86400s)); + return NetClock::time_point(duration_cast(c.now().time_since_epoch() + 86400s)); } // Represents a node that can issue validations @@ -119,50 +99,28 @@ class Validations_test : public beast::unit_test::suite NetClock::duration seenOffset, bool full) const { - Validation v{ - id, - seq, - now() + signOffset, - now() + seenOffset, - currKey(), - nodeID_, - full, - loadFee_}; + Validation v{id, seq, now() + signOffset, now() + seenOffset, currKey(), nodeID_, full, loadFee_}; if (trusted_) v.setTrusted(); return v; } Validation - validate( - Ledger ledger, - NetClock::duration signOffset, - NetClock::duration seenOffset) const + validate(Ledger ledger, NetClock::duration signOffset, NetClock::duration seenOffset) const { - return validate( - ledger.id(), ledger.seq(), signOffset, seenOffset, true); + return validate(ledger.id(), ledger.seq(), signOffset, seenOffset, true); } Validation validate(Ledger ledger) const { - return validate( - ledger.id(), - ledger.seq(), - NetClock::duration{0}, - NetClock::duration{0}, - true); + return validate(ledger.id(), ledger.seq(), NetClock::duration{0}, NetClock::duration{0}, true); } Validation partial(Ledger ledger) const { - return validate( - ledger.id(), - ledger.seq(), - NetClock::duration{0}, - NetClock::duration{0}, - false); + return validate(ledger.id(), ledger.seq(), NetClock::duration{0}, NetClock::duration{0}, false); } }; @@ -286,16 +244,13 @@ class Validations_test : public beast::unit_test::suite harness.clock().advance(1s); - BEAST_EXPECT( - ValStatus::current == harness.add(n.validate(ledgerAB))); + BEAST_EXPECT(ValStatus::current == harness.add(n.validate(ledgerAB))); // Test the node changing signing key // Confirm old ledger on hand, but not new ledger - BEAST_EXPECT( - harness.vals().numTrustedForLedger(ledgerAB.id()) == 1); - BEAST_EXPECT( - harness.vals().numTrustedForLedger(ledgerABC.id()) == 0); + BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerAB.id()) == 1); + BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerABC.id()) == 0); // Rotate signing keys n.advanceKey(); @@ -303,20 +258,15 @@ class Validations_test : public beast::unit_test::suite harness.clock().advance(1s); // Cannot re-do the same full validation sequence - BEAST_EXPECT( - ValStatus::conflicting == harness.add(n.validate(ledgerAB))); + BEAST_EXPECT(ValStatus::conflicting == harness.add(n.validate(ledgerAB))); // Cannot send the same partial validation sequence - BEAST_EXPECT( - ValStatus::conflicting == harness.add(n.partial(ledgerAB))); + BEAST_EXPECT(ValStatus::conflicting == harness.add(n.partial(ledgerAB))); // Now trusts the newest ledger too harness.clock().advance(1s); - BEAST_EXPECT( - ValStatus::current == harness.add(n.validate(ledgerABC))); - BEAST_EXPECT( - harness.vals().numTrustedForLedger(ledgerAB.id()) == 1); - BEAST_EXPECT( - harness.vals().numTrustedForLedger(ledgerABC.id()) == 1); + BEAST_EXPECT(ValStatus::current == harness.add(n.validate(ledgerABC))); + BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerAB.id()) == 1); + BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerABC.id()) == 1); // Processing validations out of order should ignore the older // validation @@ -338,19 +288,14 @@ class Validations_test : public beast::unit_test::suite Node n = harness.makeNode(); // Establish a new current validation - BEAST_EXPECT( - ValStatus::current == harness.add(n.validate(ledgerA))); + BEAST_EXPECT(ValStatus::current == harness.add(n.validate(ledgerA))); // Process a validation that has "later" seq but early sign time - BEAST_EXPECT( - ValStatus::stale == - harness.add(n.validate(ledgerAB, -1s, -1s))); + BEAST_EXPECT(ValStatus::stale == harness.add(n.validate(ledgerAB, -1s, -1s))); // Process a validation that has a later seq and later sign // time - BEAST_EXPECT( - ValStatus::current == - harness.add(n.validate(ledgerABC, 1s, 1s))); + BEAST_EXPECT(ValStatus::current == harness.add(n.validate(ledgerABC, 1s, 1s))); } { @@ -359,19 +304,13 @@ class Validations_test : public beast::unit_test::suite Node n = harness.makeNode(); BEAST_EXPECT( - ValStatus::stale == - harness.add(n.validate( - ledgerA, -harness.parms().validationCURRENT_EARLY, 0s))); + ValStatus::stale == harness.add(n.validate(ledgerA, -harness.parms().validationCURRENT_EARLY, 0s))); BEAST_EXPECT( - ValStatus::stale == - harness.add(n.validate( - ledgerA, harness.parms().validationCURRENT_WALL, 0s))); + ValStatus::stale == harness.add(n.validate(ledgerA, harness.parms().validationCURRENT_WALL, 0s))); BEAST_EXPECT( - ValStatus::stale == - harness.add(n.validate( - ledgerA, 0s, harness.parms().validationCURRENT_LOCAL))); + ValStatus::stale == harness.add(n.validate(ledgerA, 0s, harness.parms().validationCURRENT_LOCAL))); } { @@ -396,8 +335,7 @@ class Validations_test : public beast::unit_test::suite // If we advance far enough for AB to expire, we can fully // validate or partially validate that sequence number again BEAST_EXPECT(ValStatus::conflicting == process(ledgerAZ)); - harness.clock().advance( - harness.parms().validationSET_EXPIRES + 1ms); + harness.clock().advance(harness.parms().validationSET_EXPIRES + 1ms); BEAST_EXPECT(ValStatus::current == process(ledgerAZ)); } } @@ -420,31 +358,23 @@ class Validations_test : public beast::unit_test::suite [&](TestValidations& vals) { vals.currentTrusted(); }, [&](TestValidations& vals) { vals.getCurrentNodeIDs(); }, [&](TestValidations& vals) { vals.getPreferred(genesisLedger); }, - [&](TestValidations& vals) { - vals.getNodesAfter(ledgerA, ledgerA.id()); - }}; + [&](TestValidations& vals) { vals.getNodesAfter(ledgerA, ledgerA.id()); }}; for (Trigger trigger : triggers) { TestHarness harness(h.oracle); Node n = harness.makeNode(); - BEAST_EXPECT( - ValStatus::current == harness.add(n.validate(ledgerAB))); + BEAST_EXPECT(ValStatus::current == harness.add(n.validate(ledgerAB))); trigger(harness.vals()); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 1); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(ledgerAB.seq(), ledgerAB.id())); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 1); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(ledgerAB.seq(), ledgerAB.id())); harness.clock().advance(harness.parms().validationCURRENT_LOCAL); // trigger check for stale trigger(harness.vals()); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 0); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == std::nullopt); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 0); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::nullopt); } } @@ -465,8 +395,7 @@ class Validations_test : public beast::unit_test::suite Ledger ledgerAD = h["ad"]; TestHarness harness(h.oracle); - Node a = harness.makeNode(), b = harness.makeNode(), - c = harness.makeNode(), d = harness.makeNode(); + Node a = harness.makeNode(), b = harness.makeNode(), c = harness.makeNode(), d = harness.makeNode(); c.untrust(); // first round a,b,c agree, d has is partial @@ -476,8 +405,7 @@ class Validations_test : public beast::unit_test::suite BEAST_EXPECT(ValStatus::current == harness.add(d.partial(ledgerA))); for (Ledger const& ledger : {ledgerA, ledgerAB, ledgerABC, ledgerAD}) - BEAST_EXPECT( - harness.vals().getNodesAfter(ledger, ledger.id()) == 0); + BEAST_EXPECT(harness.vals().getNodesAfter(ledger, ledger.id()) == 0); harness.clock().advance(5s); @@ -487,18 +415,14 @@ class Validations_test : public beast::unit_test::suite BEAST_EXPECT(ValStatus::current == harness.add(d.partial(ledgerABC))); BEAST_EXPECT(harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 3); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerAB, ledgerAB.id()) == 2); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerABC, ledgerABC.id()) == 0); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerAD, ledgerAD.id()) == 0); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerAB, ledgerAB.id()) == 2); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerABC, ledgerABC.id()) == 0); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerAD, ledgerAD.id()) == 0); // If given a ledger inconsistent with the id, is still able to check // using slower method BEAST_EXPECT(harness.vals().getNodesAfter(ledgerAD, ledgerA.id()) == 1); - BEAST_EXPECT( - harness.vals().getNodesAfter(ledgerAD, ledgerAB.id()) == 2); + BEAST_EXPECT(harness.vals().getNodesAfter(ledgerAD, ledgerAB.id()) == 2); } void @@ -521,22 +445,18 @@ class Validations_test : public beast::unit_test::suite // Only a is trusted BEAST_EXPECT(harness.vals().currentTrusted().size() == 1); - BEAST_EXPECT( - harness.vals().currentTrusted()[0].ledgerID() == ledgerA.id()); + BEAST_EXPECT(harness.vals().currentTrusted()[0].ledgerID() == ledgerA.id()); BEAST_EXPECT(harness.vals().currentTrusted()[0].seq() == ledgerA.seq()); harness.clock().advance(3s); for (auto const& node : {a, b}) - BEAST_EXPECT( - ValStatus::current == harness.add(node.validate(ledgerAC))); + BEAST_EXPECT(ValStatus::current == harness.add(node.validate(ledgerAC))); // New validation for a BEAST_EXPECT(harness.vals().currentTrusted().size() == 1); - BEAST_EXPECT( - harness.vals().currentTrusted()[0].ledgerID() == ledgerAC.id()); - BEAST_EXPECT( - harness.vals().currentTrusted()[0].seq() == ledgerAC.seq()); + BEAST_EXPECT(harness.vals().currentTrusted()[0].ledgerID() == ledgerAC.id()); + BEAST_EXPECT(harness.vals().currentTrusted()[0].seq() == ledgerAC.seq()); // Pass enough time for it to go stale harness.clock().advance(harness.parms().validationCURRENT_LOCAL); @@ -558,8 +478,7 @@ class Validations_test : public beast::unit_test::suite b.untrust(); for (auto const& node : {a, b}) - BEAST_EXPECT( - ValStatus::current == harness.add(node.validate(ledgerA))); + BEAST_EXPECT(ValStatus::current == harness.add(node.validate(ledgerA))); { hash_set const expectedKeys = {a.nodeID(), b.nodeID()}; @@ -573,8 +492,7 @@ class Validations_test : public beast::unit_test::suite b.advanceKey(); for (auto const& node : {a, b}) - BEAST_EXPECT( - ValStatus::current == harness.add(node.partial(ledgerAC))); + BEAST_EXPECT(ValStatus::current == harness.add(node.partial(ledgerAC))); { hash_set const expectedKeys = {a.nodeID(), b.nodeID()}; @@ -602,8 +520,7 @@ class Validations_test : public beast::unit_test::suite LedgerHistoryHelper h; TestHarness harness(h.oracle); - Node a = harness.makeNode(), b = harness.makeNode(), - c = harness.makeNode(), d = harness.makeNode(), + Node a = harness.makeNode(), b = harness.makeNode(), c = harness.makeNode(), d = harness.makeNode(), e = harness.makeNode(); c.untrust(); @@ -613,8 +530,7 @@ class Validations_test : public beast::unit_test::suite c.setLoadFee(12); e.setLoadFee(12); - hash_map, std::vector> - trustedValidations; + hash_map, std::vector> trustedValidations; //---------------------------------------------------------------------- // checkers @@ -629,12 +545,8 @@ class Validations_test : public beast::unit_test::suite auto const& seq = it.first.second; auto const& expectedValidations = it.second; - BEAST_EXPECT( - harness.vals().numTrustedForLedger(id) == - expectedValidations.size()); - BEAST_EXPECT( - sorted(harness.vals().getTrustedForLedger(id, seq)) == - sorted(expectedValidations)); + BEAST_EXPECT(harness.vals().numTrustedForLedger(id) == expectedValidations.size()); + BEAST_EXPECT(sorted(harness.vals().getTrustedForLedger(id, seq)) == sorted(expectedValidations)); std::uint32_t baseFee = 0; std::vector expectedFees; @@ -643,9 +555,7 @@ class Validations_test : public beast::unit_test::suite expectedFees.push_back(val.loadFee().value_or(baseFee)); } - BEAST_EXPECT( - sorted(harness.vals().fees(id, baseFee)) == - sorted(expectedFees)); + BEAST_EXPECT(sorted(harness.vals().fees(id, baseFee)) == sorted(expectedFees)); } }; @@ -663,8 +573,7 @@ class Validations_test : public beast::unit_test::suite auto const val = node.validate(ledgerA); BEAST_EXPECT(ValStatus::current == harness.add(val)); if (val.trusted()) - trustedValidations[{val.ledgerID(), val.seq()}].emplace_back( - val); + trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val); } // d disagrees { @@ -684,19 +593,16 @@ class Validations_test : public beast::unit_test::suite auto const val = node.validate(ledgerAC); BEAST_EXPECT(ValStatus::current == harness.add(val)); if (val.trusted()) - trustedValidations[{val.ledgerID(), val.seq()}].emplace_back( - val); + trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val); } // d now thinks ledger 1, but cannot re-issue a previously used seq // and attempting it should generate a conflict. { - BEAST_EXPECT( - ValStatus::conflicting == harness.add(d.partial(ledgerA))); + BEAST_EXPECT(ValStatus::conflicting == harness.add(d.partial(ledgerA))); } // e only issues partials { - BEAST_EXPECT( - ValStatus::current == harness.add(e.partial(ledgerAC))); + BEAST_EXPECT(ValStatus::current == harness.add(e.partial(ledgerAC))); } compare(); @@ -735,9 +641,7 @@ class Validations_test : public beast::unit_test::suite // change toKeep harness.vals().setSeqToKeep(ledgerB.seq() + one, ledgerB.seq() + two); // advance clock slowly - int const loops = harness.parms().validationSET_EXPIRES / - harness.parms().validationFRESHNESS + - 1; + int const loops = harness.parms().validationSET_EXPIRES / harness.parms().validationFRESHNESS + 1; for (int i = 0; i < loops; ++i) { harness.clock().advance(harness.parms().validationFRESHNESS); @@ -764,8 +668,7 @@ class Validations_test : public beast::unit_test::suite LedgerHistoryHelper h; TestHarness harness(h.oracle); - Node a = harness.makeNode(), b = harness.makeNode(), - c = harness.makeNode(); + Node a = harness.makeNode(), b = harness.makeNode(), c = harness.makeNode(); c.untrust(); Ledger ledgerA = h["a"]; @@ -795,8 +698,7 @@ class Validations_test : public beast::unit_test::suite LedgerHistoryHelper h; TestHarness harness(h.oracle); - Node a = harness.makeNode(), b = harness.makeNode(), - c = harness.makeNode(), d = harness.makeNode(); + Node a = harness.makeNode(), b = harness.makeNode(), c = harness.makeNode(), d = harness.makeNode(); c.untrust(); Ledger ledgerA = h["a"]; @@ -806,9 +708,7 @@ class Validations_test : public beast::unit_test::suite using Seq = Ledger::Seq; - auto pref = [](Ledger ledger) { - return std::make_pair(ledger.seq(), ledger.id()); - }; + auto pref = [](Ledger ledger) { return std::make_pair(ledger.seq(), ledger.id()); }; // Empty (no ledgers) BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == std::nullopt); @@ -819,8 +719,7 @@ class Validations_test : public beast::unit_test::suite BEAST_EXPECT(harness.vals().getPreferred(ledgerB) == pref(ledgerB)); // Minimum valid sequence - BEAST_EXPECT( - harness.vals().getPreferred(ledgerA, Seq{10}) == ledgerA.id()); + BEAST_EXPECT(harness.vals().getPreferred(ledgerA, Seq{10}) == ledgerA.id()); // Untrusted doesn't impact preferred ledger // (ledgerB has tie-break over ledgerA) @@ -839,8 +738,7 @@ class Validations_test : public beast::unit_test::suite // Parent of preferred-> stick with ledger for (auto const& node : {a, b, c, d}) - BEAST_EXPECT( - ValStatus::current == harness.add(node.validate(ledgerAC))); + BEAST_EXPECT(ValStatus::current == harness.add(node.validate(ledgerAC))); // Parent of preferred stays put BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == pref(ledgerA)); // Earlier different chain, switch @@ -851,11 +749,9 @@ class Validations_test : public beast::unit_test::suite // Any later grandchild or different chain is preferred harness.clock().advance(5s); for (auto const& node : {a, b, c, d}) - BEAST_EXPECT( - ValStatus::current == harness.add(node.validate(ledgerACD))); + BEAST_EXPECT(ValStatus::current == harness.add(node.validate(ledgerACD))); for (auto const& ledger : {ledgerA, ledgerB, ledgerACD}) - BEAST_EXPECT( - harness.vals().getPreferred(ledger) == pref(ledgerACD)); + BEAST_EXPECT(harness.vals().getPreferred(ledger) == pref(ledgerACD)); } void @@ -878,44 +774,30 @@ class Validations_test : public beast::unit_test::suite hash_map peerCounts; // No trusted validations or counts sticks with current ledger - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == - ledgerA.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == ledgerA.id()); ++peerCounts[ledgerB.id()]; // No trusted validations, rely on peer counts - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == - ledgerB.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == ledgerB.id()); ++peerCounts[ledgerC.id()]; // No trusted validations, tied peers goes with larger ID BEAST_EXPECT(ledgerC.id() > ledgerB.id()); - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == - ledgerC.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == ledgerC.id()); peerCounts[ledgerC.id()] += 1000; // Single trusted always wins over peer counts BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerA))); - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == - ledgerA.id()); - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerB, Seq{0}, peerCounts) == - ledgerA.id()); - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerC, Seq{0}, peerCounts) == - ledgerA.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) == ledgerA.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerB, Seq{0}, peerCounts) == ledgerA.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerC, Seq{0}, peerCounts) == ledgerA.id()); // Stick with current ledger if trusted validation ledger has too old // of a sequence - BEAST_EXPECT( - harness.vals().getPreferredLCL(ledgerB, Seq{2}, peerCounts) == - ledgerB.id()); + BEAST_EXPECT(harness.vals().getPreferredLCL(ledgerB, Seq{2}, peerCounts) == ledgerB.id()); } void @@ -942,18 +824,12 @@ class Validations_test : public beast::unit_test::suite BEAST_EXPECT(harness.vals().getNodesAfter(genesisLedger, ID{0}) == 0); // Initial preferred branch falls back to the ledger we are trying to // acquire - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(Seq{2}, ID{2})); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(Seq{2}, ID{2})); // After adding another unavailable validation, the preferred ledger // breaks ties via higher ID - BEAST_EXPECT( - ValStatus::current == - harness.add(b.validate(ID{3}, Seq{2}, 0s, 0s, true))); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(Seq{2}, ID{3})); + BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ID{3}, Seq{2}, 0s, 0s, true))); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(Seq{2}, ID{3})); // Create the ledger Ledger ledgerAB = h["ab"]; @@ -965,26 +841,20 @@ class Validations_test : public beast::unit_test::suite Validation val2 = a.validate(ID{4}, Seq{4}, 0s, 0s, true); BEAST_EXPECT(ValStatus::current == harness.add(val2)); BEAST_EXPECT(harness.vals().numTrustedForLedger(ID{4}) == 1); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(ledgerAB.seq(), ledgerAB.id())); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(ledgerAB.seq(), ledgerAB.id())); // Another node requesting that ledger still doesn't change things Validation val3 = b.validate(ID{4}, Seq{4}, 0s, 0s, true); BEAST_EXPECT(ValStatus::current == harness.add(val3)); BEAST_EXPECT(harness.vals().numTrustedForLedger(ID{4}) == 2); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(ledgerAB.seq(), ledgerAB.id())); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(ledgerAB.seq(), ledgerAB.id())); // Switch to validation that is available harness.clock().advance(5s); Ledger ledgerABCDE = h["abcde"]; BEAST_EXPECT(ValStatus::current == harness.add(a.partial(ledgerABCDE))); BEAST_EXPECT(ValStatus::current == harness.add(b.partial(ledgerABCDE))); - BEAST_EXPECT( - harness.vals().getPreferred(genesisLedger) == - std::make_pair(ledgerABCDE.seq(), ledgerABCDE.id())); + BEAST_EXPECT(harness.vals().getPreferred(genesisLedger) == std::make_pair(ledgerABCDE.seq(), ledgerABCDE.id())); } void @@ -1032,31 +902,20 @@ class Validations_test : public beast::unit_test::suite testcase("TrustChanged"); using namespace std::chrono; - auto checker = [this]( - TestValidations& vals, - hash_set const& listed, - std::vector const& trustedVals) { - Ledger::ID testID = trustedVals.empty() ? this->genesisLedger.id() - : trustedVals[0].ledgerID(); - Ledger::Seq testSeq = trustedVals.empty() - ? this->genesisLedger.seq() - : trustedVals[0].seq(); - BEAST_EXPECT(vals.currentTrusted() == trustedVals); - BEAST_EXPECT(vals.getCurrentNodeIDs() == listed); - BEAST_EXPECT( - vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) == - trustedVals.size()); - if (trustedVals.empty()) - BEAST_EXPECT( - vals.getPreferred(this->genesisLedger) == std::nullopt); - else - BEAST_EXPECT( - vals.getPreferred(this->genesisLedger)->second == testID); - BEAST_EXPECT( - vals.getTrustedForLedger(testID, testSeq) == trustedVals); - BEAST_EXPECT( - vals.numTrustedForLedger(testID) == trustedVals.size()); - }; + auto checker = + [this](TestValidations& vals, hash_set const& listed, std::vector const& trustedVals) { + Ledger::ID testID = trustedVals.empty() ? this->genesisLedger.id() : trustedVals[0].ledgerID(); + Ledger::Seq testSeq = trustedVals.empty() ? this->genesisLedger.seq() : trustedVals[0].seq(); + BEAST_EXPECT(vals.currentTrusted() == trustedVals); + BEAST_EXPECT(vals.getCurrentNodeIDs() == listed); + BEAST_EXPECT(vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) == trustedVals.size()); + if (trustedVals.empty()) + BEAST_EXPECT(vals.getPreferred(this->genesisLedger) == std::nullopt); + else + BEAST_EXPECT(vals.getPreferred(this->genesisLedger)->second == testID); + BEAST_EXPECT(vals.getTrustedForLedger(testID, testSeq) == trustedVals); + BEAST_EXPECT(vals.numTrustedForLedger(testID) == trustedVals.size()); + }; { // Trusted to untrusted @@ -1100,18 +959,15 @@ class Validations_test : public beast::unit_test::suite LedgerHistoryHelper h; TestHarness harness(h.oracle); Node a = harness.makeNode(); - Validation v = - a.validate(Ledger::ID{2}, Ledger::Seq{2}, 0s, 0s, true); + Validation v = a.validate(Ledger::ID{2}, Ledger::Seq{2}, 0s, 0s, true); BEAST_EXPECT(ValStatus::current == harness.add(v)); hash_set listed({a.nodeID()}); std::vector trustedVals({v}); auto& vals = harness.vals(); BEAST_EXPECT(vals.currentTrusted() == trustedVals); - BEAST_EXPECT( - vals.getPreferred(genesisLedger)->second == v.ledgerID()); - BEAST_EXPECT( - vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0); + BEAST_EXPECT(vals.getPreferred(genesisLedger)->second == v.ledgerID()); + BEAST_EXPECT(vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0); trustedVals.clear(); harness.vals().trustChanged({}, {a.nodeID()}); @@ -1119,8 +975,7 @@ class Validations_test : public beast::unit_test::suite h["ab"]; BEAST_EXPECT(vals.currentTrusted() == trustedVals); BEAST_EXPECT(vals.getPreferred(genesisLedger) == std::nullopt); - BEAST_EXPECT( - vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0); + BEAST_EXPECT(vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0); } } @@ -1144,7 +999,7 @@ class Validations_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Validations, consensus, ripple); +BEAST_DEFINE_TESTSUITE(Validations, consensus, xrpl); } // namespace csf } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/ClosureCounter_test.cpp b/src/test/core/ClosureCounter_test.cpp index a426a4aea4..f5e9dc7880 100644 --- a/src/test/core/ClosureCounter_test.cpp +++ b/src/test/core/ClosureCounter_test.cpp @@ -1,33 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include - #include +#include #include #include #include -namespace ripple { +namespace xrpl { namespace test { //------------------------------------------------------------------------------ @@ -36,11 +16,7 @@ class ClosureCounter_test : public beast::unit_test::suite { // We're only using Env for its Journal. That Journal gives better // coverage in unit tests. - test::jtx::Env env_{ - *this, - jtx::envconfig(), - nullptr, - beast::severities::kDisabled}; + test::jtx::Env env_{*this, jtx::envconfig(), nullptr, beast::severities::kDisabled}; beast::Journal j{env_.app().journal("ClosureCounter_test")}; void @@ -130,14 +106,12 @@ class ClosureCounter_test : public beast::unit_test::suite } // Copy constructor - TrackedString(TrackedString const& rhs) - : copies(rhs.copies + 1), moves(rhs.moves), str(rhs.str) + TrackedString(TrackedString const& rhs) : copies(rhs.copies + 1), moves(rhs.moves), str(rhs.str) { } // Move constructor - TrackedString(TrackedString&& rhs) noexcept - : copies(rhs.copies), moves(rhs.moves + 1), str(std::move(rhs.str)) + TrackedString(TrackedString&& rhs) noexcept : copies(rhs.copies), moves(rhs.moves + 1), str(std::move(rhs.str)) { } @@ -172,8 +146,7 @@ class ClosureCounter_test : public beast::unit_test::suite ClosureCounter strCounter; BEAST_EXPECT(strCounter.count() == 0); - auto wrapped = - strCounter.wrap([](TrackedString in) { return in += "!"; }); + auto wrapped = strCounter.wrap([](TrackedString in) { return in += "!"; }); BEAST_EXPECT(strCounter.count() == 1); BEAST_EXPECT(wrapped); @@ -190,8 +163,7 @@ class ClosureCounter_test : public beast::unit_test::suite ClosureCounter strCounter; BEAST_EXPECT(strCounter.count() == 0); - auto wrapped = strCounter.wrap( - [](TrackedString const& in) { return in + "!"; }); + auto wrapped = strCounter.wrap([](TrackedString const& in) { return in + "!"; }); BEAST_EXPECT(strCounter.count() == 1); BEAST_EXPECT(wrapped); @@ -208,8 +180,7 @@ class ClosureCounter_test : public beast::unit_test::suite ClosureCounter strCounter; BEAST_EXPECT(strCounter.count() == 0); - auto wrapped = - strCounter.wrap([](TrackedString& in) { return in += "!"; }); + auto wrapped = strCounter.wrap([](TrackedString& in) { return in += "!"; }); BEAST_EXPECT(strCounter.count() == 1); BEAST_EXPECT(wrapped); @@ -338,7 +309,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ClosureCounter, core, ripple); +BEAST_DEFINE_TESTSUITE(ClosureCounter, core, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/Config_test.cpp b/src/test/core/Config_test.cpp index a1a6a079cc..d5f3bb556c 100644 --- a/src/test/core/Config_test.cpp +++ b/src/test/core/Config_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,6 +5,7 @@ #include #include +#include #include #include @@ -32,12 +14,12 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { std::string configContents(std::string const& dbPath, std::string const& validatorsFile) { - static boost::format configContentsTemplate(R"rippleConfig( + static boost::format configContentsTemplate(R"xrpldConfig( [server] port_rpc port_peer @@ -70,14 +52,14 @@ protocol = wss [node_size] medium -# This is primary persistent datastore for rippled. This includes transaction +# This is primary persistent datastore for xrpld. This includes transaction # metadata, account states, and ledger headers. Helpful information can be # found on https://xrpl.org/capacity-planning.html#node-db-type # delete old ledgers while maintaining at least 2000. Do not require an # external administrative command to initiate deletion. [node_db] type=memory -path=/Users/dummy/ripple/config/db/rocksdb +path=/Users/dummy/xrpld/config/db/rocksdb open_files=2000 filter_bits=12 cache_mb=256 @@ -91,7 +73,7 @@ file_size_mult=2 # This needs to be an absolute directory reference, not a relative one. # Modify this value as required. [debug_logfile] -/Users/dummy/ripple/config/log/debug.log +/Users/dummy/xrpld/config/log/debug.log [sntp_servers] time.windows.com @@ -116,19 +98,17 @@ r.ripple.com 51235 [sqdb] backend=sqlite -)rippleConfig"); +)xrpldConfig"); - std::string dbPathSection = - dbPath.empty() ? "" : "[database_path]\n" + dbPath; - std::string valFileSection = - validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile; + std::string dbPathSection = dbPath.empty() ? "" : "[database_path]\n" + dbPath; + std::string valFileSection = validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile; return boost::str(configContentsTemplate % dbPathSection % valFileSection); } /** - Write a rippled config file and remove when done. + Write a xrpld config file and remove when done. */ -class RippledCfgGuard : public ripple::detail::FileDirGuard +class FileCfgGuard : public xrpl::detail::FileDirGuard { private: path dataDir_; @@ -138,20 +118,19 @@ private: Config config_; public: - RippledCfgGuard( + FileCfgGuard( beast::unit_test::suite& test, path subDir, path const& dbPath, + path const& configFile, path const& validatorsFile, bool useCounter = true, std::string confContents = "") : FileDirGuard( test, std::move(subDir), - path(Config::configFileName), - confContents.empty() - ? configContents(dbPath.string(), validatorsFile.string()) - : confContents, + configFile, + confContents.empty() ? configContents(dbPath.string(), validatorsFile.string()) : confContents, useCounter) , dataDir_(dbPath) { @@ -190,7 +169,7 @@ public: return fileExists(); } - ~RippledCfgGuard() + ~FileCfgGuard() { try { @@ -201,7 +180,7 @@ public: catch (std::exception& e) { // if we throw here, just let it die. - test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl; + test_.log << "Error in ~FileCfgGuard: " << e.what() << std::endl; }; } }; @@ -209,7 +188,7 @@ public: std::string valFileContents() { - std::string configContents(R"rippleConfig( + std::string configContents(R"xrpldConfig( [validators] n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj @@ -223,8 +202,8 @@ nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8 nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz [validator_list_sites] -recommendedripplevalidators.com -moreripplevalidators.net +recommended-xrpl-validators.com +more-xrpl-validators.net [validator_list_keys] 03E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D @@ -232,7 +211,7 @@ moreripplevalidators.net [validator_list_threshold] 2 -)rippleConfig"); +)xrpldConfig"); return configContents; } @@ -250,9 +229,7 @@ public: : FileDirGuard( test, std::move(subDir), - path( - validatorsFileName.empty() ? Config::validatorsFileName - : validatorsFileName), + path(validatorsFileName.empty() ? Config::validatorsFileName : validatorsFileName), valFileContents(), useCounter) { @@ -289,7 +266,7 @@ public: Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [server] port_rpc port_peer @@ -297,7 +274,7 @@ port_wss_admin [ssl_verify] 0 -)rippleConfig"); +)xrpldConfig"); c.loadFromString(toLoad); @@ -310,6 +287,116 @@ port_wss_admin BEAST_EXPECT(c.legacy("not_in_file") == "new_value"); } void + testConfigFile() + { + testcase("config_file"); + + using namespace boost::filesystem; + auto const cwd = current_path(); + + // Test both config file names. + char const* configFiles[] = {Config::configFileName, Config::configLegacyName}; + + // Config file in current directory. + for (auto const& configFile : configFiles) + { + // Use a temporary directory for testing. + beast::temp_dir td; + current_path(td.path()); + path const f = td.file(configFile); + std::ofstream o(f.string()); + o << detail::configContents("", ""); + o.close(); + + // Load the config file from the current directory and verify it. + Config c; + c.setup("", true, false, true); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values()[0] == "/Users/dummy/xrpld/config/log/debug.log"); + } + + // Config file in HOME or XDG_CONFIG_HOME directory. +#if BOOST_OS_LINUX || BOOST_OS_MACOS + for (auto const& configFile : configFiles) + { + // Point the current working directory to a temporary directory, so + // we don't pick up an actual config file from the repository root. + beast::temp_dir td; + current_path(td.path()); + + // The XDG config directory is set: the config file must be in a + // subdirectory named after the system. + { + beast::temp_dir tc; + + // Set the HOME and XDG_CONFIG_HOME environment variables. The + // HOME variable is not used when XDG_CONFIG_HOME is set, but + // must be set. + char const* h = getenv("HOME"); + setenv("HOME", tc.path().c_str(), 1); + char const* x = getenv("XDG_CONFIG_HOME"); + setenv("XDG_CONFIG_HOME", tc.path().c_str(), 1); + + // Create the config file in '${XDG_CONFIG_HOME}/[systemName]'. + path p = tc.file(systemName()); + create_directory(p); + p = tc.file(systemName() + "/" + configFile); + std::ofstream o(p.string()); + o << detail::configContents("", ""); + o.close(); + + // Load the config file from the config directory and verify it. + Config c; + c.setup("", true, false, true); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values()[0] == "/Users/dummy/xrpld/config/log/debug.log"); + + // Restore the environment variables. + h ? setenv("HOME", h, 1) : unsetenv("HOME"); + x ? setenv("XDG_CONFIG_HOME", x, 1) : unsetenv("XDG_CONFIG_HOME"); + } + + // The XDG config directory is not set: the config file must be in a + // subdirectory named .config followed by the system name. + { + beast::temp_dir tc; + + // Set only the HOME environment variable. + char const* h = getenv("HOME"); + setenv("HOME", tc.path().c_str(), 1); + char const* x = getenv("XDG_CONFIG_HOME"); + unsetenv("XDG_CONFIG_HOME"); + + // Create the config file in '${HOME}/.config/[systemName]'. + std::string s = ".config"; + path p = tc.file(s); + create_directory(p); + s += "/" + systemName(); + p = tc.file(s); + create_directory(p); + p = tc.file(s + "/" + configFile); + std::ofstream o(p.string()); + o << detail::configContents("", ""); + o.close(); + + // Load the config file from the config directory and verify it. + Config c; + c.setup("", true, false, true); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values()[0] == "/Users/dummy/xrpld/config/log/debug.log"); + + // Restore the environment variables. + h ? setenv("HOME", h, 1) : unsetenv("HOME"); + if (x) + setenv("XDG_CONFIG_HOME", x, 1); + } + } +#endif + + // Restore the current working directory. + current_path(cwd); + } + void testDbPath() { testcase("database_path"); @@ -345,11 +432,10 @@ port_wss_admin { // read from file absolute path auto const cwd = current_path(); - ripple::detail::DirGuard const g0(*this, "test_db"); + detail::DirGuard const g0(*this, "test_db"); path const dataDirRel("test_data_dir"); path const dataDirAbs(cwd / g0.subdir() / dataDirRel); - detail::RippledCfgGuard const g( - *this, g0.subdir(), dataDirAbs, "", false); + detail::FileCfgGuard const g(*this, g0.subdir(), dataDirAbs, Config::configFileName, "", false); auto const& c(g.config()); BEAST_EXPECT(g.dataDirExists()); BEAST_EXPECT(g.configFileExists()); @@ -358,7 +444,7 @@ port_wss_admin { // read from file relative path std::string const dbPath("my_db"); - detail::RippledCfgGuard const g(*this, "test_db", dbPath, ""); + detail::FileCfgGuard const g(*this, "test_db", dbPath, Config::configFileName, ""); auto const& c(g.config()); std::string const nativeDbPath = absolute(path(dbPath)).string(); BEAST_EXPECT(g.dataDirExists()); @@ -367,10 +453,9 @@ port_wss_admin } { // read from file no path - detail::RippledCfgGuard const g(*this, "test_db", "", ""); + detail::FileCfgGuard const g(*this, "test_db", "", Config::configFileName, ""); auto const& c(g.config()); - std::string const nativeDbPath = - absolute(g.subdir() / path(Config::databaseDirName)).string(); + std::string const nativeDbPath = absolute(g.subdir() / path(Config::databaseDirName)).string(); BEAST_EXPECT(g.dataDirExists()); BEAST_EXPECT(g.configFileExists()); BEAST_EXPECT(c.legacy("database_path") == nativeDbPath); @@ -397,21 +482,20 @@ port_wss_admin { Config c; - static boost::format configTemplate(R"rippleConfig( + static boost::format configTemplate(R"xrpldConfig( [validation_seed] %1% [validator_token] %2% -)rippleConfig"); +)xrpldConfig"); std::string error; auto const expectedError = "Cannot have both [validation_seed] " "and [validator_token] config sections"; try { - c.loadFromString( - boost::str(configTemplate % validationSeed % token)); + c.loadFromString(boost::str(configTemplate % validationSeed % token)); } catch (std::runtime_error& e) { @@ -429,10 +513,10 @@ port_wss_admin Config c; try { - c.loadFromString(R"rippleConfig( + c.loadFromString(R"xrpldConfig( [network_id] main -)rippleConfig"); +)xrpldConfig"); } catch (std::runtime_error& e) { @@ -444,8 +528,8 @@ main try { - c.loadFromString(R"rippleConfig( -)rippleConfig"); + c.loadFromString(R"xrpldConfig( +)xrpldConfig"); } catch (std::runtime_error& e) { @@ -457,10 +541,10 @@ main try { - c.loadFromString(R"rippleConfig( + c.loadFromString(R"xrpldConfig( [network_id] 255 -)rippleConfig"); +)xrpldConfig"); } catch (std::runtime_error& e) { @@ -472,10 +556,10 @@ main try { - c.loadFromString(R"rippleConfig( + c.loadFromString(R"xrpldConfig( [network_id] 10000 -)rippleConfig"); +)xrpldConfig"); } catch (std::runtime_error& e) { @@ -497,9 +581,7 @@ main boost::format cc("[validators_file]\n%1%\n"); std::string error; std::string const missingPath = "/no/way/this/path/exists"; - auto const expectedError = - "The file specified in [validators_file] does not exist: " + - missingPath; + auto const expectedError = "The file specified in [validators_file] does not exist: " + missingPath; try { Config c; @@ -513,14 +595,11 @@ main } { // load should throw for invalid [validators_file] - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); path const invalidFile = current_path() / vtg.subdir(); boost::format cc("[validators_file]\n%1%\n"); std::string error; - auto const expectedError = - "Invalid file specified in [validators_file]: " + - invalidFile.string(); + auto const expectedError = "Invalid file specified in [validators_file]: " + invalidFile.string(); try { Config c; @@ -535,7 +614,7 @@ main { // load validators from config into single section Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validators] n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj @@ -544,7 +623,7 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C [validator_keys] nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5 nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8 -)rippleConfig"); +)xrpldConfig"); c.loadFromString(toLoad); BEAST_EXPECT(c.legacy("validators_file").empty()); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5); @@ -553,90 +632,72 @@ nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8 { // load validator list sites and keys from config Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 [validator_list_threshold] 1 -)rippleConfig"); +)xrpldConfig"); c.loadFromString(toLoad); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] == - "ripplevalidators.com"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] == - "trustthesevalidators.gov"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] == "xrpl-validators.com"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] == "trust-these-validators.gov"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1); BEAST_EXPECT( c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] == "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801" "E566"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "1"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "1"); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::size_t(1)); } { // load validator list sites and keys from config Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 [validator_list_threshold] 0 -)rippleConfig"); +)xrpldConfig"); c.loadFromString(toLoad); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] == - "ripplevalidators.com"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] == - "trustthesevalidators.gov"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] == "xrpl-validators.com"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] == "trust-these-validators.gov"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1); BEAST_EXPECT( c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] == "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801" "E566"); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "0"); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "0"); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::nullopt); } { // load should throw if [validator_list_threshold] is greater than // the number of [validator_list_keys] Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 [validator_list_threshold] 2 -)rippleConfig"); +)xrpldConfig"); std::string error; auto const expectedError = "Value in config section [validator_list_threshold] exceeds " @@ -655,17 +716,17 @@ trustthesevalidators.gov { // load should throw if [validator_list_threshold] is malformed Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 [validator_list_threshold] value = 2 -)rippleConfig"); +)xrpldConfig"); std::string error; auto const expectedError = "Config section [validator_list_threshold] should contain " @@ -684,17 +745,17 @@ value = 2 { // load should throw if [validator_list_threshold] is negative Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 [validator_list_threshold] -1 -)rippleConfig"); +)xrpldConfig"); bool error = false; try { @@ -711,14 +772,13 @@ trustthesevalidators.gov // load should throw if [validator_list_sites] is configured but // [validator_list_keys] is not Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov -)rippleConfig"); +xrpl-validators.com +trust-these-validators.gov +)xrpldConfig"); std::string error; - auto const expectedError = - "[validator_list_keys] config section is missing"; + auto const expectedError = "[validator_list_keys] config section is missing"; try { c.loadFromString(toLoad); @@ -732,115 +792,86 @@ trustthesevalidators.gov } { // load from specified [validators_file] absolute path - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); Config c; boost::format cc("[validators_file]\n%1%\n"); c.loadFromString(boost::str(cc % vtg.validatorsFile())); BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile()); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load from specified [validators_file] file name // in config directory std::string const valFileName = "validators.txt"; - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", valFileName); - detail::RippledCfgGuard const rcg( - *this, vtg.subdir(), "", valFileName, false); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", valFileName); + detail::FileCfgGuard const rcg(*this, vtg.subdir(), "", Config::configFileName, valFileName, false); BEAST_EXPECT(vtg.validatorsFileExists()); BEAST_EXPECT(rcg.configFileExists()); auto const& c(rcg.config()); BEAST_EXPECT(c.legacy("validators_file") == valFileName); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load from specified [validators_file] relative path // to config directory - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.txt"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.txt"); auto const valFilePath = ".." / vtg.subdir() / "validators.txt"; - detail::RippledCfgGuard const rcg( - *this, vtg.subdir(), "", valFilePath, false); + detail::FileCfgGuard const rcg(*this, vtg.subdir(), "", Config::configFileName, valFilePath, false); BEAST_EXPECT(vtg.validatorsFileExists()); BEAST_EXPECT(rcg.configFileExists()); auto const& c(rcg.config()); BEAST_EXPECT(c.legacy("validators_file") == valFilePath); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load from validators file in default location - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.txt"); - detail::RippledCfgGuard const rcg( - *this, vtg.subdir(), "", "", false); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.txt"); + detail::FileCfgGuard const rcg(*this, vtg.subdir(), "", Config::configFileName, "", false); BEAST_EXPECT(vtg.validatorsFileExists()); BEAST_EXPECT(rcg.configFileExists()); auto const& c(rcg.config()); BEAST_EXPECT(c.legacy("validators_file").empty()); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load from specified [validators_file] instead // of default location - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); - detail::ValidatorsTxtGuard const vtgDefault( - *this, vtg.subdir(), "validators.txt", false); + detail::ValidatorsTxtGuard const vtgDefault(*this, vtg.subdir(), "validators.txt", false); BEAST_EXPECT(vtgDefault.validatorsFileExists()); - detail::RippledCfgGuard const rcg( - *this, vtg.subdir(), "", vtg.validatorsFile(), false); + detail::FileCfgGuard const rcg( + *this, vtg.subdir(), "", Config::configFileName, vtg.validatorsFile(), false); BEAST_EXPECT(rcg.configFileExists()); auto const& c(rcg.config()); BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile()); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load validators from both config and validators file - boost::format cc(R"rippleConfig( + boost::format cc(R"xrpldConfig( [validators_file] %1% @@ -856,41 +887,35 @@ nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB [validator_list_sites] -ripplevalidators.com -trustthesevalidators.gov +xrpl-validators.com +trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 -)rippleConfig"); - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); +)xrpldConfig"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); Config c; c.loadFromString(boost::str(cc % vtg.validatorsFile())); BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile()); BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 15); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3); - BEAST_EXPECT( - c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == - 1); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3); + BEAST_EXPECT(c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() == 1); BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2); } { // load should throw if [validator_list_threshold] is present both - // in rippled cfg and validators file - boost::format cc(R"rippleConfig( + // in xrpld.cfg and validators file + boost::format cc(R"xrpldConfig( [validators_file] %1% [validator_list_threshold] 1 -)rippleConfig"); +)xrpldConfig"); std::string error; - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); auto const expectedError = "Config section [validator_list_threshold] should contain " @@ -909,13 +934,12 @@ trustthesevalidators.gov } { // load should throw if [validators], [validator_keys] and - // [validator_list_keys] are missing from rippled cfg and + // [validator_list_keys] are missing from xrpld.cfg and // validators file Config c; boost::format cc("[validators_file]\n%1%\n"); std::string error; - detail::ValidatorsTxtGuard const vtg( - *this, "test_cfg", "validators.cfg"); + detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); auto const expectedError = "The file specified in [validators_file] does not contain a " @@ -939,9 +963,8 @@ trustthesevalidators.gov void testSetup(bool explicitPath) { - detail::RippledCfgGuard const cfg( - *this, "testSetup", explicitPath ? "test_db" : "", ""); - /* RippledCfgGuard has a Config object that gets loaded on + detail::FileCfgGuard const cfg(*this, "testSetup", explicitPath ? "test_db" : "", Config::configFileName, ""); + /* FileCfgGuard has a Config object that gets loaded on construction, but Config::setup is not reentrant, so we need a fresh config for every test case, so ignore it. */ @@ -1008,8 +1031,7 @@ trustthesevalidators.gov BEAST_EXPECT(!config.silent()); BEAST_EXPECT(config.standalone()); BEAST_EXPECT(config.LEDGER_HISTORY == 0); - BEAST_EXPECT( - config.legacy("database_path").empty() == !explicitPath); + BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath); } { Config config; @@ -1022,8 +1044,7 @@ trustthesevalidators.gov BEAST_EXPECT(!config.silent()); BEAST_EXPECT(config.standalone()); BEAST_EXPECT(config.LEDGER_HISTORY == 0); - BEAST_EXPECT( - config.legacy("database_path").empty() == !explicitPath); + BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath); } { Config config; @@ -1036,8 +1057,7 @@ trustthesevalidators.gov BEAST_EXPECT(config.silent()); BEAST_EXPECT(config.standalone()); BEAST_EXPECT(config.LEDGER_HISTORY == 0); - BEAST_EXPECT( - config.legacy("database_path").empty() == !explicitPath); + BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath); } { Config config; @@ -1050,15 +1070,14 @@ trustthesevalidators.gov BEAST_EXPECT(config.silent()); BEAST_EXPECT(config.standalone()); BEAST_EXPECT(config.LEDGER_HISTORY == 0); - BEAST_EXPECT( - config.legacy("database_path").empty() == !explicitPath); + BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath); } } void testPort() { - detail::RippledCfgGuard const cfg(*this, "testPort", "", ""); + detail::FileCfgGuard const cfg(*this, "testPort", "", Config::configFileName, ""); auto const& conf = cfg.config(); if (!BEAST_EXPECT(conf.exists("port_rpc"))) return; @@ -1077,21 +1096,17 @@ trustthesevalidators.gov void testZeroPort() { - auto const contents = std::regex_replace( - detail::configContents("", ""), - std::regex("port\\s*=\\s*\\d+"), - "port = 0"); + auto const contents = + std::regex_replace(detail::configContents("", ""), std::regex("port\\s*=\\s*\\d+"), "port = 0"); try { - detail::RippledCfgGuard const cfg( - *this, "testPort", "", "", true, contents); + detail::FileCfgGuard const cfg(*this, "testPort", "", Config::configFileName, "", true, contents); BEAST_EXPECT(false); } catch (std::exception const& ex) { - BEAST_EXPECT(std::string_view(ex.what()).starts_with( - "Invalid value '0' for key 'port'")); + BEAST_EXPECT(std::string_view(ex.what()).starts_with("Invalid value '0' for key 'port'")); } } @@ -1128,12 +1143,10 @@ r.ripple.com 51235 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() && cfg.section("port_rpc").values().empty()); BEAST_EXPECT( - cfg.exists(SECTION_IPS) && - cfg.section(SECTION_IPS).lines().size() == 1 && + cfg.exists(SECTION_IPS) && cfg.section(SECTION_IPS).lines().size() == 1 && cfg.section(SECTION_IPS).values().size() == 1); BEAST_EXPECT( - cfg.exists(SECTION_IPS_FIXED) && - cfg.section(SECTION_IPS_FIXED).lines().size() == 2 && + cfg.exists(SECTION_IPS_FIXED) && cfg.section(SECTION_IPS_FIXED).lines().size() == 2 && cfg.section(SECTION_IPS_FIXED).values().size() == 2); } @@ -1184,12 +1197,10 @@ r.ripple.com:51235 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() && cfg.section("port_rpc").values().empty()); BEAST_EXPECT( - cfg.exists(SECTION_IPS) && - cfg.section(SECTION_IPS).lines().size() == 1 && + cfg.exists(SECTION_IPS) && cfg.section(SECTION_IPS).lines().size() == 1 && cfg.section(SECTION_IPS).values().size() == 1); BEAST_EXPECT( - cfg.exists(SECTION_IPS_FIXED) && - cfg.section(SECTION_IPS_FIXED).lines().size() == 15 && + cfg.exists(SECTION_IPS_FIXED) && cfg.section(SECTION_IPS_FIXED).lines().size() == 15 && cfg.section(SECTION_IPS_FIXED).values().size() == 15); BEAST_EXPECT(cfg.IPS[0] == "r.ripple.com 51235"); @@ -1202,17 +1213,14 @@ r.ripple.com:51235 BEAST_EXPECT(cfg.IPS_FIXED[6] == "12.34.12.123 12345"); BEAST_EXPECT(cfg.IPS_FIXED[7] == "12.34.12.123 12345"); - // all ipv6 should be ignored by colon replacer, howsoever formated + // all ipv6 should be ignored by colon replacer, howsoever formatted BEAST_EXPECT(cfg.IPS_FIXED[8] == "::"); BEAST_EXPECT(cfg.IPS_FIXED[9] == "2001:db8::"); BEAST_EXPECT(cfg.IPS_FIXED[10] == "::1"); BEAST_EXPECT(cfg.IPS_FIXED[11] == "::1:12345"); BEAST_EXPECT(cfg.IPS_FIXED[12] == "[::1]:12345"); - BEAST_EXPECT( - cfg.IPS_FIXED[13] == - "2001:db8:3333:4444:5555:6666:7777:8888:12345"); - BEAST_EXPECT( - cfg.IPS_FIXED[14] == "[2001:db8:3333:4444:5555:6666:7777:8888]:1"); + BEAST_EXPECT(cfg.IPS_FIXED[13] == "2001:db8:3333:4444:5555:6666:7777:8888:12345"); + BEAST_EXPECT(cfg.IPS_FIXED[14] == "[2001:db8:3333:4444:5555:6666:7777:8888]:1"); } void @@ -1396,9 +1404,9 @@ r.ripple.com:51235 for (auto& [unit, sec, val, shouldPass] : units) { Config c; - std::string toLoad(R"rippleConfig( + std::string toLoad(R"xrpldConfig( [amendment_majority_time] -)rippleConfig"); +)xrpldConfig"); toLoad += std::to_string(val) + space + unit; space = space == "" ? " " : ""; @@ -1406,8 +1414,7 @@ r.ripple.com:51235 { c.loadFromString(toLoad); if (shouldPass) - BEAST_EXPECT( - c.AMENDMENT_MAJORITY_TIME.count() == val * sec); + BEAST_EXPECT(c.AMENDMENT_MAJORITY_TIME.count() == val * sec); else fail(); } @@ -1426,8 +1433,7 @@ r.ripple.com:51235 { testcase("overlay: unknown time"); - auto testUnknown = - [](std::string value) -> std::optional { + auto testUnknown = [](std::string value) -> std::optional { try { Config c; @@ -1461,8 +1467,7 @@ r.ripple.com:51235 testcase("overlay: diverged time"); // In bounds: - auto testDiverged = - [](std::string value) -> std::optional { + auto testDiverged = [](std::string value) -> std::optional { try { Config c; @@ -1499,6 +1504,7 @@ r.ripple.com:51235 run() override { testLegacy(); + testConfigFile(); testDbPath(); testValidatorKeys(); testValidatorsFile(); @@ -1516,6 +1522,6 @@ r.ripple.com:51235 } }; -BEAST_DEFINE_TESTSUITE(Config, core, ripple); +BEAST_DEFINE_TESTSUITE(Config, core, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/Coroutine_test.cpp b/src/test/core/Coroutine_test.cpp index 8458da647d..73dc3c2f8f 100644 --- a/src/test/core/Coroutine_test.cpp +++ b/src/test/core/Coroutine_test.cpp @@ -1,30 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include #include -namespace ripple { +namespace xrpl { namespace test { class Coroutine_test : public beast::unit_test::suite @@ -74,13 +55,12 @@ public: gate g1, g2; std::shared_ptr c; - env.app().getJobQueue().postCoro( - jtCLIENT, "Coroutine-Test", [&](auto const& cr) { - c = cr; - g1.signal(); - c->yield(); - g2.signal(); - }); + env.app().getJobQueue().postCoro(jtCLIENT, "CoroTest", [&](auto const& cr) { + c = cr; + g1.signal(); + c->yield(); + g2.signal(); + }); BEAST_EXPECT(g1.wait_for(5s)); c->join(); c->post(); @@ -101,12 +81,11 @@ public: })); gate g; - env.app().getJobQueue().postCoro( - jtCLIENT, "Coroutine-Test", [&](auto const& c) { - c->post(); - c->yield(); - g.signal(); - }); + env.app().getJobQueue().postCoro(jtCLIENT, "CoroTest", [&](auto const& c) { + c->post(); + c->yield(); + g.signal(); + }); BEAST_EXPECT(g.wait_for(5s)); } @@ -128,7 +107,7 @@ public: BEAST_EXPECT(*lv == -1); gate g; - jq.addJob(jtCLIENT, "LocalValue-Test", [&]() { + jq.addJob(jtCLIENT, "LocalValTest", [&]() { this->BEAST_EXPECT(*lv == -1); *lv = -2; this->BEAST_EXPECT(*lv == -2); @@ -139,7 +118,7 @@ public: for (int i = 0; i < N; ++i) { - jq.postCoro(jtCLIENT, "Coroutine-Test", [&, id = i](auto const& c) { + jq.postCoro(jtCLIENT, "CoroTest", [&, id = i](auto const& c) { a[id] = c; g.signal(); c->yield(); @@ -167,7 +146,7 @@ public: c->join(); } - jq.addJob(jtCLIENT, "LocalValue-Test", [&]() { + jq.addJob(jtCLIENT, "LocalValTest", [&]() { this->BEAST_EXPECT(*lv == -2); g.signal(); }); @@ -184,7 +163,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Coroutine, core, ripple); +BEAST_DEFINE_TESTSUITE(Coroutine, core, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/JobQueue_test.cpp b/src/test/core/JobQueue_test.cpp index 66f110be9c..0eee9ce6f2 100644 --- a/src/test/core/JobQueue_test.cpp +++ b/src/test/core/JobQueue_test.cpp @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include - #include +#include -namespace ripple { +namespace xrpl { namespace test { //------------------------------------------------------------------------------ @@ -39,9 +19,7 @@ class JobQueue_test : public beast::unit_test::suite { // addJob() should run the Job (and return true). std::atomic jobRan{false}; - BEAST_EXPECT(jQueue.addJob(jtCLIENT, "JobAddTest1", [&jobRan]() { - jobRan = true; - }) == true); + BEAST_EXPECT(jQueue.addJob(jtCLIENT, "JobAddTest1", [&jobRan]() { jobRan = true; }) == true); // Wait for the Job to run. while (jobRan == false) @@ -58,10 +36,7 @@ class JobQueue_test : public beast::unit_test::suite // unprotected variable on the stack should be completely safe. // Not recommended for the faint of heart... bool unprotected; - BEAST_EXPECT( - jQueue.addJob(jtCLIENT, "JobAddTest2", [&unprotected]() { - unprotected = false; - }) == false); + BEAST_EXPECT(jQueue.addJob(jtCLIENT, "JobAddTest2", [&unprotected]() { unprotected = false; }) == false); } } @@ -75,9 +50,7 @@ class JobQueue_test : public beast::unit_test::suite // Test repeated post()s until the Coro completes. std::atomic yieldCount{0}; auto const coro = jQueue.postCoro( - jtCLIENT, - "PostCoroTest1", - [&yieldCount](std::shared_ptr const& coroCopy) { + jtCLIENT, "PostCoroTest1", [&yieldCount](std::shared_ptr const& coroCopy) { while (++yieldCount < 4) coroCopy->yield(); }); @@ -104,9 +77,7 @@ class JobQueue_test : public beast::unit_test::suite // Test repeated resume()s until the Coro completes. int yieldCount{0}; auto const coro = jQueue.postCoro( - jtCLIENT, - "PostCoroTest2", - [&yieldCount](std::shared_ptr const& coroCopy) { + jtCLIENT, "PostCoroTest2", [&yieldCount](std::shared_ptr const& coroCopy) { while (++yieldCount < 4) coroCopy->yield(); }); @@ -141,10 +112,8 @@ class JobQueue_test : public beast::unit_test::suite // unprotected variable on the stack should be completely safe. // Not recommended for the faint of heart... bool unprotected; - auto const coro = jQueue.postCoro( - jtCLIENT, - "PostCoroTest3", - [&unprotected](std::shared_ptr const&) { + auto const coro = + jQueue.postCoro(jtCLIENT, "PostCoroTest3", [&unprotected](std::shared_ptr const&) { unprotected = false; }); BEAST_EXPECT(coro == nullptr); @@ -160,7 +129,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(JobQueue, core, ripple); +BEAST_DEFINE_TESTSUITE(JobQueue, core, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/SociDB_test.cpp b/src/test/core/SociDB_test.cpp index 9a3666f072..fe73d42b0a 100644 --- a/src/test/core/SociDB_test.cpp +++ b/src/test/core/SociDB_test.cpp @@ -1,40 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include - #include #include +#include #include #include -namespace ripple { +namespace xrpl { class SociDB_test final : public TestSuite { private: static void - setupSQLiteConfig( - BasicConfig& config, - boost::filesystem::path const& dbPath) + setupSQLiteConfig(BasicConfig& config, boost::filesystem::path const& dbPath) { config.overwrite("sqdb", "backend", "sqlite"); auto value = dbPath.string(); @@ -64,8 +42,7 @@ private: if (!is_directory(dbPath)) { // someone created a file where we want to put out directory - Throw( - "Cannot create directory: " + dbPath.string()); + Throw("Cannot create directory: " + dbPath.string()); } } static boost::filesystem::path @@ -98,21 +75,17 @@ public: void testSQLiteFileNames() { - // confirm that files are given the correct exensions + // confirm that files are given the correct extensions testcase("sqliteFileNames"); BasicConfig c; setupSQLiteConfig(c, getDatabasePath()); std::vector> const d( - {{"peerfinder", ".sqlite"}, - {"state", ".db"}, - {"random", ".db"}, - {"validators", ".sqlite"}}); + {{"peerfinder", ".sqlite"}, {"state", ".db"}, {"random", ".db"}, {"validators", ".sqlite"}}); for (auto const& i : d) { DBConfig sc(c, i.first); - BEAST_EXPECT( - boost::ends_with(sc.connectionString(), i.first + i.second)); + BEAST_EXPECT(boost::ends_with(sc.connectionString(), i.first + i.second)); } } void @@ -122,27 +95,19 @@ public: BasicConfig c; setupSQLiteConfig(c, getDatabasePath()); DBConfig sc(c, "SociTestDB"); - std::vector const stringData( - {"String1", "String2", "String3"}); + std::vector const stringData({"String1", "String2", "String3"}); std::vector const intData({1, 2, 3}); auto checkValues = [this, &stringData, &intData](soci::session& s) { // Check values in db std::vector stringResult(20 * stringData.size()); std::vector intResult(20 * intData.size()); - s << "SELECT StringData, IntData FROM SociTestTable;", - soci::into(stringResult), soci::into(intResult); - BEAST_EXPECT( - stringResult.size() == stringData.size() && - intResult.size() == intData.size()); + s << "SELECT StringData, IntData FROM SociTestTable;", soci::into(stringResult), soci::into(intResult); + BEAST_EXPECT(stringResult.size() == stringData.size() && intResult.size() == intData.size()); for (int i = 0; i < stringResult.size(); ++i) { - auto si = std::distance( - stringData.begin(), - std::find( - stringData.begin(), stringData.end(), stringResult[i])); - auto ii = std::distance( - intData.begin(), - std::find(intData.begin(), intData.end(), intResult[i])); + auto si = + std::distance(stringData.begin(), std::find(stringData.begin(), stringData.end(), stringResult[i])); + auto ii = std::distance(intData.begin(), std::find(intData.begin(), intData.end(), intResult[i])); BEAST_EXPECT(si == ii && si < stringResult.size()); } }; @@ -183,11 +148,9 @@ public: BasicConfig c; setupSQLiteConfig(c, getDatabasePath()); DBConfig sc(c, "SociTestDB"); - std::vector const ubid( - {(std::uint64_t)std::numeric_limits::max(), 20, 30}); + std::vector const ubid({(std::uint64_t)std::numeric_limits::max(), 20, 30}); std::vector const bid({-10, -20, -30}); - std::vector const uid( - {std::numeric_limits::max(), 2, 3}); + std::vector const uid({std::numeric_limits::max(), 2, 3}); std::vector const id({-1, -2, -3}); { @@ -213,11 +176,9 @@ public: std::uint32_t uig = 0; std::int64_t big = 0; std::uint64_t ubig = 0; - s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig), - soci::into(uig), soci::into(big), soci::into(ubig); - BEAST_EXPECT( - ig == id[0] && uig == uid[0] && big == bid[0] && - ubig == ubid[0]); + s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig), soci::into(uig), soci::into(big), + soci::into(ubig); + BEAST_EXPECT(ig == id[0] && uig == uid[0] && big == bid[0] && ubig == ubid[0]); } catch (std::exception&) { @@ -233,11 +194,9 @@ public: uint32_t uig = 0; boost::optional big; boost::optional ubig; - s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig), - soci::into(uig), soci::into(big), soci::into(ubig); - BEAST_EXPECT( - *ig == id[0] && uig == uid[0] && *big == bid[0] && - *ubig == ubid[0]); + s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig), soci::into(uig), soci::into(big), + soci::into(ubig); + BEAST_EXPECT(*ig == id[0] && uig == uid[0] && *big == bid[0] && *ubig == ubid[0]); } catch (std::exception&) { @@ -370,6 +329,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(SociDB, core, ripple); +BEAST_DEFINE_TESTSUITE(SociDB, core, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/core/Workers_test.cpp b/src/test/core/Workers_test.cpp index e37f7a71f8..1f1c16b12b 100644 --- a/src/test/core/Workers_test.cpp +++ b/src/test/core/Workers_test.cpp @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2012, 2013 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include - #include +#include +#include #include #include @@ -29,7 +9,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -namespace ripple { +namespace xrpl { /** * Dummy class for unit tests. @@ -69,8 +49,7 @@ class PerfLogTest : public PerfLog } void - jobFinish(JobType const type, std::chrono::microseconds dur, int instance) - override + jobFinish(JobType const type, std::chrono::microseconds dur, int instance) override { } @@ -122,13 +101,10 @@ public: void testThreads(int const tc1, int const tc2, int const tc3) { - testcase( - "threadCounts: " + std::to_string(tc1) + " -> " + - std::to_string(tc2) + " -> " + std::to_string(tc3)); + testcase("threadCounts: " + std::to_string(tc1) + " -> " + std::to_string(tc2) + " -> " + std::to_string(tc3)); TestCallback cb; - std::unique_ptr perfLog = - std::make_unique(); + std::unique_ptr perfLog = std::make_unique(); Workers w(cb, perfLog.get(), "Test", tc1); BEAST_EXPECT(w.getNumberOfThreads() == tc1); @@ -148,8 +124,7 @@ public: // using namespace std::chrono_literals; std::unique_lock lk{cb.mut}; - bool const signaled = - cb.cv.wait_for(lk, 10s, [&cb] { return cb.count == 0; }); + bool const signaled = cb.cv.wait_for(lk, 10s, [&cb] { return cb.count == 0; }); BEAST_EXPECT(signaled); BEAST_EXPECT(cb.count == 0); }; @@ -174,6 +149,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Workers, core, ripple); +BEAST_DEFINE_TESTSUITE(Workers, core, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf.h b/src/test/csf.h index cad647f6ca..81af3491c4 100644 --- a/src/test/csf.h +++ b/src/test/csf.h @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include diff --git a/src/test/csf/BasicNetwork.h b/src/test/csf/BasicNetwork.h index a70ee6a361..697b20c2c7 100644 --- a/src/test/csf/BasicNetwork.h +++ b/src/test/csf/BasicNetwork.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_BASICNETWORK_H_INCLUDED -#define RIPPLE_TEST_CSF_BASICNETWORK_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { /** Peer to peer network simulator. @@ -135,10 +115,7 @@ public: @return `true` if a new connection was established */ bool - connect( - Peer const& from, - Peer const& to, - duration const& delay = std::chrono::seconds{0}); + connect(Peer const& from, Peer const& to, duration const& delay = std::chrono::seconds{0}); /** Break a link. @@ -203,10 +180,7 @@ BasicNetwork::BasicNetwork(Scheduler& s) : scheduler(s) template inline bool -BasicNetwork::connect( - Peer const& from, - Peer const& to, - duration const& delay) +BasicNetwork::connect(Peer const& from, Peer const& to, duration const& delay) { if (to == from) return false; @@ -240,19 +214,16 @@ BasicNetwork::send(Peer const& from, Peer const& to, Function&& f) if (!link) return; time_point const sent = scheduler.now(); - scheduler.in( - link->delay, [from, to, sent, f = std::forward(f), this] { - // only process if still connected and connection was - // not broken since the message was sent - if (auto l = links_.edge(from, to); l && l->established <= sent) - { - f(); - } - }); + scheduler.in(link->delay, [from, to, sent, f = std::forward(f), this] { + // only process if still connected and connection was + // not broken since the message was sent + if (auto l = links_.edge(from, to); l && l->established <= sent) + { + f(); + } + }); } } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/BasicNetwork_test.cpp b/src/test/csf/BasicNetwork_test.cpp index 4580dab468..d66f5c9891 100644 --- a/src/test/csf/BasicNetwork_test.cpp +++ b/src/test/csf/BasicNetwork_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class BasicNetwork_test : public beast::unit_test::suite @@ -52,9 +33,7 @@ public: if (id == 0) { for (auto const link : net.links(this)) - net.send(this, link.target, [&, to = link.target] { - to->receive(net, this, 1); - }); + net.send(this, link.target, [&, to = link.target] { to->receive(net, this, 1); }); } else { @@ -71,9 +50,7 @@ public: if (m < 5) { for (auto const link : net.links(this)) - net.send(this, link.target, [&, mm = m, to = link.target] { - to->receive(net, this, mm); - }); + net.send(this, link.target, [&, mm = m, to = link.target] { to->receive(net, this, mm); }); } } }; @@ -146,7 +123,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(BasicNetwork, csf, ripple); +BEAST_DEFINE_TESTSUITE(BasicNetwork, csf, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/CollectorRef.h b/src/test/csf/CollectorRef.h index 309b48af1f..735a42ab16 100644 --- a/src/test/csf/CollectorRef.h +++ b/src/test/csf/CollectorRef.h @@ -1,33 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_COLLECTOREF_H_INCLUDED -#define RIPPLE_TEST_CSF_COLLECTOREF_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { -/** Holds a type-erased reference to an arbitray collector. +/** Holds a type-erased reference to an arbitrary collector. A collector is any class that implements @@ -346,6 +326,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Digraph.h b/src/test/csf/Digraph.h index e65a7af913..672445ca95 100644 --- a/src/test/csf/Digraph.h +++ b/src/test/csf/Digraph.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission target use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED -#define RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { // Dummy class when no edge data needed for graph struct NoEdgeData @@ -148,9 +128,7 @@ public: auto outVertices() const { - return boost::adaptors::transform( - graph_, - [](typename Graph::value_type const& v) { return v.first; }); + return boost::adaptors::transform(graph_, [](typename Graph::value_type const& v) { return v.first; }); } /** Range over target vertices @@ -161,9 +139,7 @@ public: auto outVertices(Vertex source) const { - auto transform = [](typename Links::value_type const& link) { - return link.first; - }; + auto transform = [](typename Links::value_type const& link) { return link.first; }; auto it = graph_.find(source); if (it != graph_.end()) return boost::adaptors::transform(it->second, transform); @@ -218,7 +194,7 @@ public: Save a GraphViz dot description of the graph @param fileName The output file (creates) - @param vertexName A invokable T vertexName(Vertex const &) that + @param vertexName A invocable T vertexName(Vertex const &) that returns the name target use for the vertex in the file T must be ostream-able */ @@ -250,5 +226,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/csf/Digraph_test.cpp b/src/test/csf/Digraph_test.cpp index df78a10733..a0cb35323d 100644 --- a/src/test/csf/Digraph_test.cpp +++ b/src/test/csf/Digraph_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission target use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Digraph_test : public beast::unit_test::suite @@ -92,7 +73,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Digraph, csf, ripple); +BEAST_DEFINE_TESTSUITE(Digraph, csf, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/Histogram.h b/src/test/csf/Histogram.h index fb0f532396..9e7b471a2b 100644 --- a/src/test/csf/Histogram.h +++ b/src/test/csf/Histogram.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_HISTOGRAM_H_INCLUDED -#define RIPPLE_TEST_CSF_HISTOGRAM_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -37,15 +17,15 @@ namespace csf { - Comparison : T a, b; bool res = a < b - Addition: T a, b; T c = a + b; - Multiplication : T a, std::size_t b; T c = a * b; - - Divison: T a; std::size_t b; T c = a/b; + - Division: T a; std::size_t b; T c = a/b; */ template > class Histogram { - // TODO: Consider logarithimic bins around expected median if this becomes - // unscaleable + // TODO: Consider logarithmic bins around expected median if this becomes + // unscalable std::map counts_; std::size_t samples = 0; @@ -130,6 +110,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Histogram_test.cpp b/src/test/csf/Histogram_test.cpp index 60f12e9a66..b0a8d8490d 100644 --- a/src/test/csf/Histogram_test.cpp +++ b/src/test/csf/Histogram_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { class Histogram_test : public beast::unit_test::suite @@ -81,7 +62,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Histogram, csf, ripple); +BEAST_DEFINE_TESTSUITE(Histogram, csf, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/Peer.h b/src/test/csf/Peer.h index 1cb2d03cc6..7b19c977d6 100644 --- a/src/test/csf/Peer.h +++ b/src/test/csf/Peer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_PEER_H_INCLUDED -#define RIPPLE_TEST_CSF_PEER_H_INCLUDED +#pragma once #include #include @@ -39,7 +19,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -423,21 +403,19 @@ struct Peer { minDuration = std::min(minDuration, link.data.delay); - // Send a messsage to neighbors to find the ledger - net.send( - this, link.target, [to = link.target, from = this, ledgerID]() { - if (auto it = to->ledgers.find(ledgerID); - it != to->ledgers.end()) - { - // if the ledger is found, send it back to the original - // requesting peer where it is added to the available - // ledgers - to->net.send(to, from, [from, ledger = it->second]() { - from->acquiringLedgers.erase(ledger.id()); - from->ledgers.emplace(ledger.id(), ledger); - }); - } - }); + // Send a message to neighbors to find the ledger + net.send(this, link.target, [to = link.target, from = this, ledgerID]() { + if (auto it = to->ledgers.find(ledgerID); it != to->ledgers.end()) + { + // if the ledger is found, send it back to the original + // requesting peer where it is added to the available + // ledgers + to->net.send(to, from, [from, ledger = it->second]() { + from->acquiringLedgers.erase(ledger.id()); + from->ledgers.emplace(ledger.id(), ledger); + }); + } + }); } acquiringLedgers[ledgerID] = scheduler.now() + 2 * minDuration; return nullptr; @@ -470,20 +448,18 @@ struct Peer { minDuration = std::min(minDuration, link.data.delay); // Send a message to neighbors to find the tx set - net.send( - this, link.target, [to = link.target, from = this, setId]() { - if (auto it = to->txSets.find(setId); - it != to->txSets.end()) - { - // If the txSet is found, send it back to the original - // requesting peer, where it is handled like a TxSet - // that was broadcast over the network - to->net.send(to, from, [from, txSet = it->second]() { - from->acquiringTxSets.erase(txSet.id()); - from->handle(txSet); - }); - } - }); + net.send(this, link.target, [to = link.target, from = this, setId]() { + if (auto it = to->txSets.find(setId); it != to->txSets.end()) + { + // If the txSet is found, send it back to the original + // requesting peer, where it is handled like a TxSet + // that was broadcast over the network + to->net.send(to, from, [from, txSet = it->second]() { + from->acquiringTxSets.erase(txSet.id()); + from->handle(txSet); + }); + } + }); } acquiringTxSets[setId] = scheduler.now() + 2 * minDuration; return nullptr; @@ -508,22 +484,12 @@ struct Peer } Result - onClose( - Ledger const& prevLedger, - NetClock::time_point closeTime, - ConsensusMode mode) + onClose(Ledger const& prevLedger, NetClock::time_point closeTime, ConsensusMode mode) { issue(CloseLedger{prevLedger, openTxs}); return Result( - TxSet{openTxs}, - Proposal( - prevLedger.id(), - Proposal::seqJoin, - TxSet::calcID(openTxs), - closeTime, - now(), - id)); + TxSet{openTxs}, Proposal(prevLedger.id(), Proposal::seqJoin, TxSet::calcID(openTxs), closeTime, now(), id)); } void @@ -535,14 +501,7 @@ struct Peer ConsensusMode const& mode, Json::Value&& consensusJson) { - onAccept( - result, - prevLedger, - closeResolution, - rawCloseTimes, - mode, - std::move(consensusJson), - validating()); + onAccept(result, prevLedger, closeResolution, rawCloseTimes, mode, std::move(consensusJson), validating()); } void @@ -560,11 +519,8 @@ struct Peer bool const consensusFail = result.state == ConsensusState::MovedOn; TxSet const acceptedTxs = injectTxs(prevLedger, result.txns); - Ledger const newLedger = oracle.accept( - prevLedger, - acceptedTxs.txs(), - closeResolution, - result.position.closeTime()); + Ledger const newLedger = + oracle.accept(prevLedger, acceptedTxs.txs(), closeResolution, result.position.closeTime()); ledgers[newLedger.id()] = newLedger; issue(AcceptLedger{newLedger, lastClosedLedger}); @@ -573,30 +529,19 @@ struct Peer lastClosedLedger = newLedger; auto const it = std::remove_if( - openTxs.begin(), openTxs.end(), [&](Tx const& tx) { - return acceptedTxs.exists(tx.id()); - }); + openTxs.begin(), openTxs.end(), [&](Tx const& tx) { return acceptedTxs.exists(tx.id()); }); openTxs.erase(it, openTxs.end()); // Only send validation if the new ledger is compatible with our // fully validated ledger - bool const isCompatible = - newLedger.isAncestor(fullyValidatedLedger); + bool const isCompatible = newLedger.isAncestor(fullyValidatedLedger); // Can only send one validated ledger per seq - if (runAsValidator && isCompatible && !consensusFail && - validations.canValidateSeq(newLedger.seq())) + if (runAsValidator && isCompatible && !consensusFail && validations.canValidateSeq(newLedger.seq())) { bool isFull = proposing; - Validation v{ - newLedger.id(), - newLedger.seq(), - now(), - now(), - key, - id, - isFull}; + Validation v{newLedger.id(), newLedger.seq(), now(), now(), key, id, isFull}; // share the new validation; it is trusted by the receiver share(v); // we trust ourselves @@ -627,17 +572,13 @@ struct Peer } Ledger::ID - getPrevLedger( - Ledger::ID const& ledgerID, - Ledger const& ledger, - ConsensusMode mode) + getPrevLedger(Ledger::ID const& ledgerID, Ledger const& ledger, ConsensusMode mode) { // only do if we are past the genesis ledger if (ledger.seq() == Ledger::Seq{0}) return ledgerID; - Ledger::ID const netLgr = - validations.getPreferred(ledger, earliestAllowedSeq()); + Ledger::ID const netLgr = validations.getPreferred(ledger, earliestAllowedSeq()); if (netLgr != ledgerID) { @@ -741,7 +682,7 @@ struct Peer template struct BroadcastMesg { - M mesg; + M msg; std::size_t seq; PeerID origin; }; @@ -767,13 +708,8 @@ struct Peer // used on the other end if (link.target->router.lastObservedSeq[bm.origin] < bm.seq) { - issue(Relay{link.target->id, bm.mesg}); - net.send( - this, - link.target, - [to = link.target, bm, id = this->id] { - to->receive(bm, id); - }); + issue(Relay{link.target->id, bm.msg}); + net.send(this, link.target, [to = link.target, bm, id = this->id] { to->receive(bm, id); }); } } } @@ -784,12 +720,12 @@ struct Peer void receive(BroadcastMesg const& bm, PeerID from) { - issue(Receive{from, bm.mesg}); + issue(Receive{from, bm.msg}); if (router.lastObservedSeq[bm.origin] < bm.seq) { router.lastObservedSeq[bm.origin] = bm.seq; - schedule(delays.onReceive(bm.mesg), [this, bm, from] { - if (handle(bm.mesg)) + schedule(delays.onReceive(bm.msg), [this, bm, from] { + if (handle(bm.msg)) send(bm, from); }); } @@ -819,8 +755,7 @@ struct Peer bool handle(TxSet const& txs) { - bool const inserted = - txSets.insert(std::make_pair(txs.id(), txs)).second; + bool const inserted = txSets.insert(std::make_pair(txs.id(), txs)).second; if (inserted) consensus.gotTxSet(now(), txs); // relay only if new @@ -925,8 +860,7 @@ struct Peer // Between rounds, we take the majority ledger // In the future, consider taking peer dominant ledger if no validations // yet - Ledger::ID bestLCL = - validations.getPreferred(lastClosedLedger, earliestAllowedSeq()); + Ledger::ID bestLCL = validations.getPreferred(lastClosedLedger, earliestAllowedSeq()); if (bestLCL == Ledger::ID{0}) bestLCL = lastClosedLedger.id(); @@ -934,8 +868,7 @@ struct Peer // Not yet modeling dynamic UNL. hash_set nowUntrusted; - consensus.startRound( - now(), bestLCL, lastClosedLedger, nowUntrusted, runAsValidator, {}); + consensus.startRound(now(), bestLCL, lastClosedLedger, nowUntrusted, runAsValidator, {}); } // Start the consensus process assuming it is not yet running @@ -958,8 +891,8 @@ struct Peer // code are positive. (e.g. proposeFRESHNESS) using namespace std::chrono; using namespace std::chrono_literals; - return NetClock::time_point(duration_cast( - scheduler.now().time_since_epoch() + 86400s + clockSkew)); + return NetClock::time_point( + duration_cast(scheduler.now().time_since_epoch() + 86400s + clockSkew)); } Ledger::ID @@ -1002,5 +935,4 @@ struct Peer } // namespace csf } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/csf/PeerGroup.h b/src/test/csf/PeerGroup.h index 0da1ef69c9..ce7325f659 100644 --- a/src/test/csf/PeerGroup.h +++ b/src/test/csf/PeerGroup.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_PEERGROUP_H_INCLUDED -#define RIPPLE_TEST_CSF_PEERGROUP_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -105,9 +85,7 @@ public: bool contains(PeerID id) { - return std::find_if(peers_.begin(), peers_.end(), [id](Peer const* p) { - return p->id == id; - }) != peers_.end(); + return std::find_if(peers_.begin(), peers_.end(), [id](Peer const* p) { return p->id == id; }) != peers_.end(); } std::size_t @@ -212,7 +190,7 @@ public: /** Establish network connections based on trust relations For each peers in this group, create outbound network connection - to the set of peers it trusts. If a coonnection already exists, it is + to the set of peers it trusts. If a connection already exists, it is not recreated. @param delay The fixed messaging delay for all established connections @@ -236,11 +214,7 @@ public: { PeerGroup res; std::set_union( - a.peers_.begin(), - a.peers_.end(), - b.peers_.begin(), - b.peers_.end(), - std::back_inserter(res.peers_)); + a.peers_.begin(), a.peers_.end(), b.peers_.begin(), b.peers_.end(), std::back_inserter(res.peers_)); return res; } @@ -251,11 +225,7 @@ public: PeerGroup res; std::set_difference( - a.peers_.begin(), - a.peers_.end(), - b.peers_.begin(), - b.peers_.end(), - std::back_inserter(res.peers_)); + a.peers_.begin(), a.peers_.end(), b.peers_.begin(), b.peers_.end(), std::back_inserter(res.peers_)); return res; } @@ -332,8 +302,7 @@ randomRankedTrust( RandomNumberDistribution sizeDist, Generator& g) { - std::vector const groups = - randomRankedGroups(peers, ranks, numGroups, sizeDist, g); + std::vector const groups = randomRankedGroups(peers, ranks, numGroups, sizeDist, g); std::uniform_int_distribution u(0, groups.size() - 1); for (auto& peer : peers) @@ -357,8 +326,7 @@ randomRankedConnect( Generator& g, SimDuration delay) { - std::vector const groups = - randomRankedGroups(peers, ranks, numGroups, sizeDist, g); + std::vector const groups = randomRankedGroups(peers, ranks, numGroups, sizeDist, g); std::uniform_int_distribution u(0, groups.size() - 1); for (auto& peer : peers) @@ -370,5 +338,4 @@ randomRankedConnect( } // namespace csf } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/csf/Proposal.h b/src/test/csf/Proposal.h index eae258a251..641fd2010a 100644 --- a/src/test/csf/Proposal.h +++ b/src/test/csf/Proposal.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_PROPOSAL_H_INCLUDED -#define RIPPLE_TEST_CSF_PROPOSAL_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { /** Proposal is a position taken in the consensus process and is represented @@ -36,6 +16,4 @@ using Proposal = ConsensusProposal; } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Scheduler.h b/src/test/csf/Scheduler.h index 62dff86402..2f7535ef16 100644 --- a/src/test/csf/Scheduler.h +++ b/src/test/csf/Scheduler.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED -#define RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -54,8 +34,7 @@ public: using time_point = typename clock_type::time_point; private: - using by_when_hook = boost::intrusive::set_base_hook< - boost::intrusive::link_mode>; + using by_when_hook = boost::intrusive::set_base_hook>; struct event : by_when_hook { @@ -94,8 +73,7 @@ private: operator=(event_impl const&) = delete; template - event_impl(time_point when_, DeducedHandler&& h) - : event(when_), h_(std::forward(h)) + event_impl(time_point when_, DeducedHandler&& h) : event(when_), h_(std::forward(h)) { } @@ -109,9 +87,8 @@ private: class queue_type { private: - using by_when_set = typename boost::intrusive::make_multiset< - event, - boost::intrusive::constant_time_size>::type; + using by_when_set = + typename boost::intrusive::make_multiset>::type; // alloc_ is owned by the scheduler boost::container::pmr::monotonic_buffer_resource* alloc_; by_when_set by_when_; @@ -123,8 +100,7 @@ private: queue_type& operator=(queue_type const&) = delete; - explicit queue_type( - boost::container::pmr::monotonic_buffer_resource* alloc); + explicit queue_type(boost::container::pmr::monotonic_buffer_resource* alloc); ~queue_type(); @@ -275,9 +251,7 @@ public: //------------------------------------------------------------------------------ -inline Scheduler::queue_type::queue_type( - boost::container::pmr::monotonic_buffer_resource* alloc) - : alloc_(alloc) +inline Scheduler::queue_type::queue_type(boost::container::pmr::monotonic_buffer_resource* alloc) : alloc_(alloc) { } @@ -312,8 +286,7 @@ Scheduler::queue_type::end() -> iterator template inline auto -Scheduler::queue_type::emplace(time_point when, Handler&& h) -> - typename by_when_set::iterator +Scheduler::queue_type::emplace(time_point when, Handler&& h) -> typename by_when_set::iterator { using event_type = event_impl>; auto const p = alloc_->allocate(sizeof(event_type)); @@ -453,6 +426,4 @@ Scheduler::step_for(std::chrono::duration const& amount) } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Scheduler_test.cpp b/src/test/csf/Scheduler_test.cpp index c31b881b03..a0b57dd87f 100644 --- a/src/test/csf/Scheduler_test.cpp +++ b/src/test/csf/Scheduler_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class Scheduler_test : public beast::unit_test::suite @@ -83,7 +64,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Scheduler, csf, ripple); +BEAST_DEFINE_TESTSUITE(Scheduler, csf, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/Sim.h b/src/test/csf/Sim.h index 0cb052305a..709226b216 100644 --- a/src/test/csf/Sim.h +++ b/src/test/csf/Sim.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_SIM_H_INCLUDED -#define RIPPLE_TEST_CSF_SIM_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -43,8 +23,7 @@ class BasicSink : public beast::Journal::Sink Scheduler::clock_type const& clock_; public: - BasicSink(Scheduler::clock_type const& clock) - : Sink(beast::severities::kDisabled, false), clock_{clock} + BasicSink(Scheduler::clock_type const& clock) : Sink(beast::severities::kDisabled, false), clock_{clock} { } @@ -54,16 +33,13 @@ public: if (level < threshold()) return; - std::cout << clock_.now().time_since_epoch().count() << " " << text - << std::endl; + std::cout << clock_.now().time_since_epoch().count() << " " << text << std::endl; } void - writeAlways(beast::severities::Severity level, std::string const& text) - override + writeAlways(beast::severities::Severity level, std::string const& text) override { - std::cout << clock_.now().time_since_epoch().count() << " " << text - << std::endl; + std::cout << clock_.now().time_since_epoch().count() << " " << text << std::endl; } }; @@ -113,13 +89,7 @@ public: for (std::size_t i = 0; i < numPeers; ++i) { peers.emplace_back( - PeerID{static_cast(peers.size())}, - scheduler, - oracle, - net, - trustGraph, - collectors, - j); + PeerID{static_cast(peers.size())}, scheduler, oracle, net, trustGraph, collectors, j); newPeers.emplace_back(&peers.back()); } PeerGroup res{newPeers}; @@ -176,6 +146,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/SimTime.h b/src/test/csf/SimTime.h index 32d657b625..2131de9b41 100644 --- a/src/test/csf/SimTime.h +++ b/src/test/csf/SimTime.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_SIMTIME_H_INCLUDED -#define RIPPLE_TEST_CSF_SIMTIME_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -38,6 +18,4 @@ using SimTime = typename SimClock::time_point; } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/TrustGraph.h b/src/test/csf/TrustGraph.h index 5770c792bc..d25925ad38 100644 --- a/src/test/csf/TrustGraph.h +++ b/src/test/csf/TrustGraph.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_UNL_H_INCLUDED -#define RIPPLE_TEST_CSF_UNL_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -129,8 +109,7 @@ public: std::set unique; for (Peer const peer : graph_.outVertices()) { - unique.emplace( - std::begin(trustedPeers(peer)), std::end(trustedPeers(peer))); + unique.emplace(std::begin(trustedPeers(peer)), std::end(trustedPeers(peer))); } std::vector uniqueUNLs(unique.begin(), unique.end()); @@ -143,18 +122,14 @@ public: { auto const& unlA = uniqueUNLs[i]; auto const& unlB = uniqueUNLs[j]; - double rhs = - 2.0 * (1. - quorum) * std::max(unlA.size(), unlB.size()); + double rhs = 2.0 * (1. - quorum) * std::max(unlA.size(), unlB.size()); int intersectionSize = - std::count_if(unlA.begin(), unlA.end(), [&](Peer p) { - return unlB.find(p) != unlB.end(); - }); + std::count_if(unlA.begin(), unlA.end(), [&](Peer p) { return unlB.find(p) != unlB.end(); }); if (intersectionSize < rhs) { - res.emplace_back( - ForkInfo{unlA, unlB, intersectionSize, rhs}); + res.emplace_back(ForkInfo{unlA, unlB, intersectionSize, rhs}); } } } @@ -173,6 +148,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Tx.h b/src/test/csf/Tx.h index 7f37d60d70..20c90cbac5 100644 --- a/src/test/csf/Tx.h +++ b/src/test/csf/Tx.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_TX_H_INCLUDED -#define RIPPLE_TEST_CSF_TX_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -164,11 +144,7 @@ public: auto populate_diffs = [&res](auto const& a, auto const& b, bool s) { auto populator = [&](auto const& tx) { res[tx.id()] = s; }; std::set_difference( - a.begin(), - a.end(), - b.begin(), - b.end(), - boost::make_function_output_iterator(std::ref(populator))); + a.begin(), a.end(), b.begin(), b.end(), boost::make_function_output_iterator(std::ref(populator))); }; populate_diffs(txs_, other.txs_, true); @@ -229,6 +205,4 @@ hash_append(Hasher& h, Tx const& tx) } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/Validation.h b/src/test/csf/Validation.h index e79222c84f..5ebbcf3ae5 100644 --- a/src/test/csf/Validation.h +++ b/src/test/csf/Validation.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_VALIDATION_H_INCLUDED -#define RIPPLE_TEST_CSF_VALIDATION_H_INCLUDED +#pragma once #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -159,15 +139,7 @@ public: asTie() const { // trusted is a status set by the receiver, so it is not part of the tie - return std::tie( - ledgerID_, - seq_, - signTime_, - seenTime_, - key_, - nodeID_, - loadFee_, - full_); + return std::tie(ledgerID_, seq_, signTime_, seenTime_, key_, nodeID_, loadFee_, full_); } bool operator==(Validation const& o) const @@ -202,6 +174,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/collectors.h b/src/test/csf/collectors.h index 0494178ae9..20fc31a01f 100644 --- a/src/test/csf/collectors.h +++ b/src/test/csf/collectors.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED -#define RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -47,7 +27,7 @@ namespace csf { /** Group of collectors. Presents a group of collectors as a single collector which process an event - by calling each collector sequentially. This is analagous to CollectorRefs + by calling each collector sequentially. This is analogous to CollectorRefs in CollectorRef.h, but does *not* erase the type information of the combined collectors. */ @@ -65,12 +45,7 @@ class Collectors template static void - apply( - std::tuple& cs, - PeerID who, - SimTime when, - E e, - std::index_sequence) + apply(std::tuple& cs, PeerID who, SimTime when, E e, std::index_sequence) { (..., apply(std::get(cs), who, when, e)); } @@ -254,18 +229,14 @@ struct TxCollector std::size_t orphaned() const { - return std::count_if(txs.begin(), txs.end(), [](auto const& it) { - return !it.second.accepted; - }); + return std::count_if(txs.begin(), txs.end(), [](auto const& it) { return !it.second.accepted; }); } // Returns the number of txs which were never validated std::size_t unvalidated() const { - return std::count_if(txs.begin(), txs.end(), [](auto const& it) { - return !it.second.validated; - }); + return std::count_if(txs.begin(), txs.end(), [](auto const& it) { return !it.second.validated; }); } template @@ -277,86 +248,64 @@ struct TxCollector return double(count) / duration_cast(simDuration).count(); }; - auto fmtS = [](SimDuration dur) { - return duration_cast>(dur).count(); - }; + auto fmtS = [](SimDuration dur) { return duration_cast>(dur).count(); }; if (printBreakline) { - log << std::setw(11) << std::setfill('-') << "-" << "-" - << std::setw(7) << std::setfill('-') << "-" << "-" - << std::setw(7) << std::setfill('-') << "-" << "-" - << std::setw(36) << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-" + << std::endl; log << std::setfill(' '); } - log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7) - << "Count" << "|" << std::setw(7) << "Per Sec" << "|" - << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) - << "10-ile" << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" - << std::left << std::endl; + log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7) << "Count" << "|" << std::setw(7) + << "Per Sec" << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile" + << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl; - log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) - << std::setfill('-') << "-" << "|" << std::setw(7) - << std::setfill('-') << "-" << "|" << std::setw(36) - << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|" + << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36) << std::setfill('-') << "-" + << std::endl; log << std::setfill(' '); - log << std::left << std::setw(11) << "Submit " << "|" << std::right - << std::setw(7) << submitted << "|" << std::setw(7) - << std::setprecision(2) << perSec(submitted) << "|" << std::setw(36) - << "" << std::endl; + log << std::left << std::setw(11) << "Submit " << "|" << std::right << std::setw(7) << submitted << "|" + << std::setw(7) << std::setprecision(2) << perSec(submitted) << "|" << std::setw(36) << "" << std::endl; - log << std::left << std::setw(11) << "Accept " << "|" << std::right - << std::setw(7) << accepted << "|" << std::setw(7) - << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) - << std::left << "From Submit" << std::right << std::setw(7) - << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f)) - << std::setw(7) << std::setprecision(2) - << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7) - << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f)) + log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7) << accepted << "|" + << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) << std::left + << "From Submit" << std::right << std::setw(7) << std::setprecision(2) + << fmtS(submitToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2) + << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7) << std::setprecision(2) + << fmtS(submitToAccept.percentile(0.9f)) << std::endl; + + log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7) << validated << "|" + << std::setw(7) << std::setprecision(2) << perSec(validated) << "|" << std::setw(15) << std::left + << "From Submit" << std::right << std::setw(7) << std::setprecision(2) + << fmtS(submitToValidate.percentile(0.1f)) << std::setw(7) << std::setprecision(2) + << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7) << std::setprecision(2) + << fmtS(submitToValidate.percentile(0.9f)) << std::endl; + + log << std::left << std::setw(11) << "Orphan" << "|" << std::right << std::setw(7) << orphaned() << "|" + << std::setw(7) << "" << "|" << std::setw(36) << std::endl; + + log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right << std::setw(7) << unvalidated() << "|" + << std::setw(7) << "" << "|" << std::setw(43) << std::endl; + + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-" << std::endl; - - log << std::left << std::setw(11) << "Validate " << "|" << std::right - << std::setw(7) << validated << "|" << std::setw(7) - << std::setprecision(2) << perSec(validated) << "|" << std::setw(15) - << std::left << "From Submit" << std::right << std::setw(7) - << std::setprecision(2) << fmtS(submitToValidate.percentile(0.1f)) - << std::setw(7) << std::setprecision(2) - << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7) - << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) - << std::endl; - - log << std::left << std::setw(11) << "Orphan" << "|" << std::right - << std::setw(7) << orphaned() << "|" << std::setw(7) << "" << "|" - << std::setw(36) << std::endl; - - log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right - << std::setw(7) << unvalidated() << "|" << std::setw(7) << "" << "|" - << std::setw(43) << std::endl; - - log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) - << std::setfill('-') << "-" << "-" << std::setw(7) - << std::setfill('-') << "-" << "-" << std::setw(36) - << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); } template void - csv(SimDuration simDuration, - T& log, - Tag const& tag, - bool printHeaders = false) + csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false) { using namespace std::chrono; auto perSec = [&simDuration](std::size_t count) { return double(count) / duration_cast(simDuration).count(); }; - auto fmtS = [](SimDuration dur) { - return duration_cast>(dur).count(); - }; + auto fmtS = [](SimDuration dur) { return duration_cast>(dur).count(); }; if (printHeaders) { @@ -414,8 +363,7 @@ struct TxCollector << std::setprecision(2) << fmtS(submitToValidate.percentile(0.5f)) << "," // txLatencySubmitToValidate90Pctl - << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) - << "," << std::endl; + << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) << "," << std::endl; } }; @@ -495,8 +443,7 @@ struct LedgerCollector auto& parentTracker = parentIt->second; if (parentTracker.fullyValidated) { - fullyValidToFullyValid.insert( - when - *parentTracker.fullyValidated); + fullyValidToFullyValid.insert(when - *parentTracker.fullyValidated); } } } @@ -507,9 +454,7 @@ struct LedgerCollector unvalidated() const { return std::count_if( - ledgers_.begin(), ledgers_.end(), [](auto const& it) { - return !it.second.fullyValidated; - }); + ledgers_.begin(), ledgers_.end(), [](auto const& it) { return !it.second.fullyValidated; }); } template @@ -521,74 +466,56 @@ struct LedgerCollector return double(count) / duration_cast(simDuration).count(); }; - auto fmtS = [](SimDuration dur) { - return duration_cast>(dur).count(); - }; + auto fmtS = [](SimDuration dur) { return duration_cast>(dur).count(); }; if (printBreakline) { - log << std::setw(11) << std::setfill('-') << "-" << "-" - << std::setw(7) << std::setfill('-') << "-" << "-" - << std::setw(7) << std::setfill('-') << "-" << "-" - << std::setw(36) << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-" + << std::endl; log << std::setfill(' '); } - log << std::left << std::setw(11) << "LedgerStats" << "|" - << std::setw(7) << "Count" << "|" << std::setw(7) << "Per Sec" - << "|" << std::setw(15) << "Latency (sec)" << std::right - << std::setw(7) << "10-ile" << std::setw(7) << "50-ile" - << std::setw(7) << "90-ile" << std::left << std::endl; + log << std::left << std::setw(11) << "LedgerStats" << "|" << std::setw(7) << "Count" << "|" << std::setw(7) + << "Per Sec" + << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile" << std::setw(7) + << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl; - log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) - << std::setfill('-') << "-" << "|" << std::setw(7) - << std::setfill('-') << "-" << "|" << std::setw(36) - << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) << std::setfill('-') << "-" << "|" + << std::setw(7) << std::setfill('-') << "-" << "|" << std::setw(36) << std::setfill('-') << "-" + << std::endl; log << std::setfill(' '); - log << std::left << std::setw(11) << "Accept " << "|" << std::right - << std::setw(7) << accepted << "|" << std::setw(7) - << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) - << std::left << "From Accept" << std::right << std::setw(7) - << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f)) - << std::setw(7) << std::setprecision(2) - << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7) - << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f)) - << std::endl; + log << std::left << std::setw(11) << "Accept " << "|" << std::right << std::setw(7) << accepted << "|" + << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) << std::left + << "From Accept" << std::right << std::setw(7) << std::setprecision(2) + << fmtS(acceptToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2) + << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7) << std::setprecision(2) + << fmtS(acceptToAccept.percentile(0.9f)) << std::endl; - log << std::left << std::setw(11) << "Validate " << "|" << std::right - << std::setw(7) << fullyValidated << "|" << std::setw(7) - << std::setprecision(2) << perSec(fullyValidated) << "|" - << std::setw(15) << std::left << "From Validate " << std::right - << std::setw(7) << std::setprecision(2) - << fmtS(fullyValidToFullyValid.percentile(0.1f)) << std::setw(7) - << std::setprecision(2) - << fmtS(fullyValidToFullyValid.percentile(0.5f)) << std::setw(7) - << std::setprecision(2) + log << std::left << std::setw(11) << "Validate " << "|" << std::right << std::setw(7) << fullyValidated << "|" + << std::setw(7) << std::setprecision(2) << perSec(fullyValidated) << "|" << std::setw(15) << std::left + << "From Validate " << std::right << std::setw(7) << std::setprecision(2) + << fmtS(fullyValidToFullyValid.percentile(0.1f)) << std::setw(7) << std::setprecision(2) + << fmtS(fullyValidToFullyValid.percentile(0.5f)) << std::setw(7) << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.9f)) << std::endl; - log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) - << std::setfill('-') << "-" << "-" << std::setw(7) - << std::setfill('-') << "-" << "-" << std::setw(36) - << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" << std::setw(36) << std::setfill('-') << "-" + << std::endl; log << std::setfill(' '); } template void - csv(SimDuration simDuration, - T& log, - Tag const& tag, - bool printHeaders = false) + csv(SimDuration simDuration, T& log, Tag const& tag, bool printHeaders = false) { using namespace std::chrono; auto perSec = [&simDuration](std::size_t count) { return double(count) / duration_cast(simDuration).count(); }; - auto fmtS = [](SimDuration dur) { - return duration_cast>(dur).count(); - }; + auto fmtS = [](SimDuration dur) { return duration_cast>(dur).count(); }; if (printHeaders) { @@ -627,16 +554,13 @@ struct LedgerCollector << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f)) << "," // ledgerLatencyFullyValidToFullyValid10Pctl - << std::setprecision(2) - << fmtS(fullyValidToFullyValid.percentile(0.1f)) + << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.1f)) << "," // ledgerLatencyFullyValidToFullyValid50Pctl - << std::setprecision(2) - << fmtS(fullyValidToFullyValid.percentile(0.5f)) + << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.5f)) << "," // ledgerLatencyFullyValidToFullyValid90Pctl - << std::setprecision(2) - << fmtS(fullyValidToFullyValid.percentile(0.9f)) << std::endl; + << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.9f)) << std::endl; } }; @@ -659,16 +583,14 @@ struct StreamCollector void on(PeerID who, SimTime when, AcceptLedger const& e) { - out << when.time_since_epoch().count() << ": Node " << who - << " accepted " << "L" << e.ledger.id() << " " << e.ledger.txs() - << "\n"; + out << when.time_since_epoch().count() << ": Node " << who << " accepted " << "L" << e.ledger.id() << " " + << e.ledger.txs() << "\n"; } void on(PeerID who, SimTime when, FullyValidateLedger const& e) { - out << when.time_since_epoch().count() << ": Node " << who - << " fully-validated " << "L" << e.ledger.id() << " " + out << when.time_since_epoch().count() << ": Node " << who << " fully-validated " << "L" << e.ledger.id() << " " << e.ledger.txs() << "\n"; } }; @@ -711,13 +633,10 @@ struct JumpCollector { // Not a direct child -> parent switch if (e.ledger.parentID() != e.prior.id()) - fullyValidatedJumps.emplace_back( - Jump{who, when, e.prior, e.ledger}); + fullyValidatedJumps.emplace_back(Jump{who, when, e.prior, e.ledger}); } }; } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/events.h b/src/test/csf/events.h index 2209a10f60..2aae22d125 100644 --- a/src/test/csf/events.h +++ b/src/test/csf/events.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_EVENTS_H_INCLUDED -#define RIPPLE_TEST_CSF_EVENTS_H_INCLUDED +#pragma once #include #include @@ -27,12 +7,12 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { // Events are emitted by peers at a variety of points during the simulation. -// Each event is emitted by a particlar peer at a particular time. Collectors +// Each event is emitted by a particular peer at a particular time. Collectors // process these events, perhaps calculating statistics or storing events to // a log for post-processing. // @@ -148,6 +128,4 @@ struct FullyValidateLedger } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/impl/Sim.cpp b/src/test/csf/impl/Sim.cpp index 6cc950180c..4fbee56f0f 100644 --- a/src/test/csf/impl/Sim.cpp +++ b/src/test/csf/impl/Sim.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -82,4 +63,4 @@ Sim::branches(PeerGroup const& g) const } // namespace csf } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/impl/ledgers.cpp b/src/test/csf/impl/ledgers.cpp index 74be491b39..12d461a214 100644 --- a/src/test/csf/impl/ledgers.cpp +++ b/src/test/csf/impl/ledgers.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -107,8 +88,7 @@ LedgerOracle::accept( next.closeTimeResolution = closeTimeResolution; next.closeTimeAgree = consensusCloseTime != NetClock::time_point{}; if (next.closeTimeAgree) - next.closeTime = effCloseTime( - consensusCloseTime, closeTimeResolution, parent.closeTime()); + next.closeTime = effCloseTime(consensusCloseTime, closeTimeResolution, parent.closeTime()); else next.closeTime = parent.closeTime() + 1s; @@ -171,4 +151,4 @@ LedgerOracle::branches(std::set const& ledgers) const } } // namespace csf } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/csf/ledgers.h b/src/test/csf/ledgers.h index 45e255ffd5..d78c7c29fa 100644 --- a/src/test/csf/ledgers.h +++ b/src/test/csf/ledgers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_LEDGERS_H_INCLUDED -#define RIPPLE_TEST_CSF_LEDGERS_H_INCLUDED +#pragma once #include @@ -35,7 +15,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -54,7 +34,7 @@ namespace csf { Ledgers are immutable value types. All ledgers with the same sequence number, transactions, close time, etc. will have the same ledger ID. The - LedgerOracle class below manges ID assignments for a simulation and is the + LedgerOracle class below manages ID assignments for a simulation and is the only way to close and create a new ledger. Since the parent ledger ID is part of type, this also means ledgers with distinct histories will have distinct ids, even if they have the same set of transactions, sequence @@ -113,14 +93,7 @@ private: auto asTie() const { - return std::tie( - seq, - txs, - closeTimeResolution, - closeTime, - closeTimeAgree, - parentID, - parentCloseTime); + return std::tie(seq, txs, closeTimeResolution, closeTime, closeTimeAgree, parentID, parentCloseTime); } friend bool @@ -249,8 +222,8 @@ private: class LedgerOracle { using InstanceMap = boost::bimaps::bimap< - boost::bimaps::set_of>, - boost::bimaps::set_of>>; + boost::bimaps::set_of>, + boost::bimaps::set_of>>; using InstanceEntry = InstanceMap::value_type; // Set of all known ledgers; note this is never pruned @@ -286,11 +259,7 @@ public: accept(Ledger const& curr, Tx tx) { using namespace std::chrono_literals; - return accept( - curr, - TxSetType{tx}, - curr.closeTimeResolution(), - curr.closeTime() + 1s); + return accept(curr, TxSetType{tx}, curr.closeTimeResolution(), curr.closeTime() + 1s); } /** Determine the number of distinct branches for the set of ledgers. @@ -353,13 +322,10 @@ struct LedgerHistoryHelper assert(seen.emplace(s.back()).second); Ledger const& parent = (*this)[s.substr(0, s.size() - 1)]; - return ledgers.emplace(s, oracle.accept(parent, Tx{++nextTx})) - .first->second; + return ledgers.emplace(s, oracle.accept(parent, Tx{++nextTx})).first->second; } }; } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/random.h b/src/test/csf/random.h index e78bbf515b..fc5098af32 100644 --- a/src/test/csf/random.h +++ b/src/test/csf/random.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_RANDOM_H_INCLUDED -#define RIPPLE_TEST_CSF_RANDOM_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -91,11 +71,7 @@ public: @param w Vector of weights of size list-first @param g the pseudo-random number generator */ - Selector( - RAIter first, - RAIter last, - std::vector const& w, - Generator& g) + Selector(RAIter first, RAIter last, std::vector const& w, Generator& g) : first_{first}, last_{last}, dd_{w.begin(), w.end()}, g_{g} { using tag = typename std::iterator_traits::iterator_category; @@ -175,6 +151,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/submitters.h b/src/test/csf/submitters.h index 2680c09712..2300b91388 100644 --- a/src/test/csf/submitters.h +++ b/src/test/csf/submitters.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_SUBMITTERS_H_INCLUDED -#define RIPPLE_TEST_CSF_SUBMITTERS_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -50,7 +30,7 @@ struct Rate /** Submits transactions to a specified peer Submits successive transactions beginning at start, then spaced according - to succesive calls of distribution(), until stop. + to successive calls of distribution(), until stop. @tparam Distribution is a `UniformRandomBitGenerator` from the STL that is used by random distributions to generate random samples @@ -99,13 +79,7 @@ class Submitter } public: - Submitter( - Distribution dist, - SimTime start, - SimTime end, - Selector& selector, - Scheduler& s, - Generator& g) + Submitter(Distribution dist, SimTime start, SimTime end, Selector& selector, Scheduler& s, Generator& g) : dist_{dist}, stop_{end}, selector_{selector}, scheduler_{s}, g_{g} { scheduler_.at(start, [&]() { submit(); }); @@ -114,20 +88,11 @@ public: template Submitter -makeSubmitter( - Distribution dist, - SimTime start, - SimTime end, - Selector& sel, - Scheduler& s, - Generator& g) +makeSubmitter(Distribution dist, SimTime start, SimTime end, Selector& sel, Scheduler& s, Generator& g) { - return Submitter( - dist, start, end, sel, s, g); + return Submitter(dist, start, end, sel, s, g); } } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/csf/timers.h b/src/test/csf/timers.h index 94b421e4b4..a071844a41 100644 --- a/src/test/csf/timers.h +++ b/src/test/csf/timers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_CSF_TIMERS_H_INCLUDED -#define RIPPLE_TEST_CSF_TIMERS_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace csf { @@ -45,10 +25,7 @@ class HeartbeatTimer SimTime startSimTime_; public: - HeartbeatTimer( - Scheduler& sched, - SimDuration interval = std::chrono::seconds{60}, - std::ostream& out = std::cerr) + HeartbeatTimer(Scheduler& sched, SimDuration interval = std::chrono::seconds{60}, std::ostream& out = std::cerr) : scheduler_{sched} , interval_{interval} , out_{out} @@ -72,10 +49,8 @@ public: RealDuration realDuration = realTime - startRealTime_; SimDuration simDuration = simTime - startSimTime_; - out_ << "Heartbeat. Time Elapsed: {sim: " - << duration_cast(simDuration).count() - << "s | real: " << duration_cast(realDuration).count() - << "s}\n" + out_ << "Heartbeat. Time Elapsed: {sim: " << duration_cast(simDuration).count() + << "s | real: " << duration_cast(realDuration).count() << "s}\n" << std::flush; scheduler_.in(interval_, [this]() { beat(scheduler_.now()); }); @@ -84,6 +59,4 @@ public: } // namespace csf } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/json/Object_test.cpp b/src/test/json/Object_test.cpp deleted file mode 100644 index 0ad5f76307..0000000000 --- a/src/test/json/Object_test.cpp +++ /dev/null @@ -1,258 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -#include -#include - -namespace Json { - -class JsonObject_test : public ripple::test::TestOutputSuite -{ - void - setup(std::string const& testName) - { - testcase(testName); - output_.clear(); - } - - std::unique_ptr writerObject_; - - Object& - makeRoot() - { - writerObject_ = - std::make_unique(stringWriterObject(output_)); - return **writerObject_; - } - - void - expectResult(std::string const& expected) - { - writerObject_.reset(); - TestOutputSuite::expectResult(expected); - } - -public: - void - testTrivial() - { - setup("trivial"); - - { - auto& root = makeRoot(); - (void)root; - } - expectResult("{}"); - } - - void - testSimple() - { - setup("simple"); - { - auto& root = makeRoot(); - root["hello"] = "world"; - root["skidoo"] = 23; - root["awake"] = false; - root["temperature"] = 98.6; - } - - expectResult( - "{\"hello\":\"world\"," - "\"skidoo\":23," - "\"awake\":false," - "\"temperature\":98.6}"); - } - - void - testOneSub() - { - setup("oneSub"); - { - auto& root = makeRoot(); - root.setArray("ar"); - } - expectResult("{\"ar\":[]}"); - } - - void - testSubs() - { - setup("subs"); - { - auto& root = makeRoot(); - - { - // Add an array with three entries. - auto array = root.setArray("ar"); - array.append(23); - array.append(false); - array.append(23.5); - } - - { - // Add an object with one entry. - auto obj = root.setObject("obj"); - obj["hello"] = "world"; - } - - { - // Add another object with two entries. - Json::Value value; - value["h"] = "w"; - value["f"] = false; - root["obj2"] = value; - } - } - - // Json::Value has an unstable order... - auto case1 = - "{\"ar\":[23,false,23.5]," - "\"obj\":{\"hello\":\"world\"}," - "\"obj2\":{\"h\":\"w\",\"f\":false}}"; - auto case2 = - "{\"ar\":[23,false,23.5]," - "\"obj\":{\"hello\":\"world\"}," - "\"obj2\":{\"f\":false,\"h\":\"w\"}}"; - writerObject_.reset(); - BEAST_EXPECT(output_ == case1 || output_ == case2); - } - - void - testSubsShort() - { - setup("subsShort"); - - { - auto& root = makeRoot(); - - { - // Add an array with three entries. - auto array = root.setArray("ar"); - array.append(23); - array.append(false); - array.append(23.5); - } - - // Add an object with one entry. - root.setObject("obj")["hello"] = "world"; - - { - // Add another object with two entries. - auto object = root.setObject("obj2"); - object.set("h", "w"); - object.set("f", false); - } - } - expectResult( - "{\"ar\":[23,false,23.5]," - "\"obj\":{\"hello\":\"world\"}," - "\"obj2\":{\"h\":\"w\",\"f\":false}}"); - } - - void - testFailureObject() - { - { - setup("object failure assign"); - auto& root = makeRoot(); - auto obj = root.setObject("o1"); - expectException([&]() { root["fail"] = "complete"; }); - } - { - setup("object failure object"); - auto& root = makeRoot(); - auto obj = root.setObject("o1"); - expectException([&]() { root.setObject("o2"); }); - } - { - setup("object failure Array"); - auto& root = makeRoot(); - auto obj = root.setArray("o1"); - expectException([&]() { root.setArray("o2"); }); - } - } - - void - testFailureArray() - { - { - setup("array failure append"); - auto& root = makeRoot(); - auto array = root.setArray("array"); - auto subarray = array.appendArray(); - auto fail = [&]() { array.append("fail"); }; - expectException(fail); - } - { - setup("array failure appendArray"); - auto& root = makeRoot(); - auto array = root.setArray("array"); - auto subarray = array.appendArray(); - auto fail = [&]() { array.appendArray(); }; - expectException(fail); - } - { - setup("array failure appendObject"); - auto& root = makeRoot(); - auto array = root.setArray("array"); - auto subarray = array.appendArray(); - auto fail = [&]() { array.appendObject(); }; - expectException(fail); - } - } - - void - testKeyFailure() - { - setup("repeating keys"); - auto& root = makeRoot(); - root.set("foo", "bar"); - root.set("baz", 0); - // setting key again throws in !NDEBUG builds - auto set_again = [&]() { root.set("foo", "bar"); }; -#ifdef NDEBUG - set_again(); - pass(); -#else - expectException(set_again); -#endif - } - - void - run() override - { - testTrivial(); - testSimple(); - - testOneSub(); - testSubs(); - testSubsShort(); - - testFailureObject(); - testFailureArray(); - testKeyFailure(); - } -}; - -BEAST_DEFINE_TESTSUITE(JsonObject, json, ripple); - -} // namespace Json diff --git a/src/test/json/TestOutputSuite.h b/src/test/json/TestOutputSuite.h index 44992df64b..88b7e22580 100644 --- a/src/test/json/TestOutputSuite.h +++ b/src/test/json/TestOutputSuite.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RPC_TESTOUTPUTSUITE_H_INCLUDED -#define RIPPLE_RPC_TESTOUTPUTSUITE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { class TestOutputSuite : public TestSuite @@ -53,6 +33,4 @@ protected: }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx.h b/src/test/jtx.h index 3d3a4f41f8..903b029f29 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_H_INCLUDED -#define RIPPLE_TEST_JTX_H_INCLUDED +#pragma once // Convenience header that includes everything @@ -71,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -78,5 +59,3 @@ #include #include - -#endif diff --git a/src/test/jtx/AMM.h b/src/test/jtx/AMM.h index 07e60369fe..4d8059d172 100644 --- a/src/test/jtx/AMM.h +++ b/src/test/jtx/AMM.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_AMM_H_INCLUDED -#define RIPPLE_TEST_JTX_AMM_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -161,11 +141,7 @@ public: ter const& ter, bool log = false, bool close = true); - AMM(Env& env, - Account const& account, - STAmount const& asset1, - STAmount const& asset2, - CreateArg const& arg); + AMM(Env& env, Account const& account, STAmount const& asset1, STAmount const& asset2, CreateArg const& arg); /** Send amm_info RPC command */ @@ -191,10 +167,7 @@ public: /** Get AMM balances for the token pair. */ std::tuple - balances( - Issue const& issue1, - Issue const& issue2, - std::optional const& account = std::nullopt) const; + balances(Issue const& issue1, Issue const& issue2, std::optional const& account = std::nullopt) const; std::tuple balances(std::optional const& account = std::nullopt) const @@ -211,10 +184,7 @@ public: * @param expectedPrice expected slot price */ [[nodiscard]] bool - expectAuctionSlot( - std::uint32_t fee, - std::optional timeSlot, - IOUAmount expectedPrice) const; + expectAuctionSlot(std::uint32_t fee, std::optional timeSlot, IOUAmount expectedPrice) const; [[nodiscard]] bool expectAuctionSlot(std::vector const& authAccount) const; @@ -282,11 +252,7 @@ public: std::optional const& ter = std::nullopt) { return withdraw( - account, - std::nullopt, - asset1OutDetails, - asset1OutDetails ? tfOneAssetWithdrawAll : tfWithdrawAll, - ter); + account, std::nullopt, asset1OutDetails, asset1OutDetails ? tfOneAssetWithdrawAll : tfWithdrawAll, ter); } IOUAmount @@ -346,8 +312,7 @@ public: } IOUAmount - getLPTokensBalance( - std::optional const& account = std::nullopt) const; + getLPTokensBalance(std::optional const& account = std::nullopt) const; friend std::ostream& operator<<(std::ostream& s, AMM const& amm) @@ -370,9 +335,7 @@ public: } void - ammDelete( - AccountID const& deleter, - std::optional const& ter = std::nullopt); + ammDelete(AccountID const& deleter, std::optional const& ter = std::nullopt); void setClose(bool close) @@ -387,9 +350,7 @@ public: } void - setTokens( - Json::Value& jv, - std::optional> const& assets = std::nullopt); + setTokens(Json::Value& jv, std::optional> const& assets = std::nullopt); private: AccountID @@ -422,17 +383,11 @@ private: } [[nodiscard]] bool - expectAmmInfo( - STAmount const& asset1, - STAmount const& asset2, - IOUAmount const& balance, - Json::Value const& jv) const; + expectAmmInfo(STAmount const& asset1, STAmount const& asset2, IOUAmount const& balance, Json::Value const& jv) + const; void - submit( - Json::Value const& jv, - std::optional const& seq, - std::optional const& ter); + submit(Json::Value const& jv, std::optional const& seq, std::optional const& ter); [[nodiscard]] bool expectAuctionSlot(auto&& cb) const; @@ -443,10 +398,7 @@ private: namespace amm { Json::Value -trust( - AccountID const& account, - STAmount const& amount, - std::uint32_t flags = 0); +trust(AccountID const& account, STAmount const& amount, std::uint32_t flags = 0); Json::Value pay(Account const& account, AccountID const& to, STAmount const& amount); @@ -461,6 +413,4 @@ ammClawback( } // namespace jtx } // namespace test -} // namespace ripple - -#endif // RIPPLE_TEST_JTX_AMM_H_INCLUDED +} // namespace xrpl diff --git a/src/test/jtx/AMMTest.h b/src/test/jtx/AMMTest.h index 17011d7633..be6e228c0a 100644 --- a/src/test/jtx/AMMTest.h +++ b/src/test/jtx/AMMTest.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_AMMTEST_H_INCLUDED -#define RIPPLE_TEST_JTX_AMMTEST_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -40,7 +20,11 @@ struct TestAMMArg std::optional> pool = std::nullopt; std::uint16_t tfee = 0; std::optional ter = std::nullopt; - std::vector features = {testable_amendments()}; + std::vector features = { + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + jtx::testable_amendments() - featureSingleAssetVault - featureLendingProtocol}; + bool noLog = false; }; @@ -85,6 +69,14 @@ protected: public: AMMTestBase(); + static FeatureBitset + testable_amendments() + { + // For now, just disable SAV entirely, which locks in the small Number + // mantissas + return jtx::testable_amendments() - featureSingleAssetVault - featureLendingProtocol; + } + protected: /** testAMM() funds 30,000XRP and 30,000IOU * for each non-XRP asset to Alice and Carol @@ -98,9 +90,7 @@ protected: std::vector const& features = {testable_amendments()}); void - testAMM( - std::function&& cb, - TestAMMArg const& arg); + testAMM(std::function&& cb, TestAMMArg const& arg); }; class AMMTest : public jtx::AMMTestBase @@ -167,6 +157,4 @@ protected: } // namespace jtx } // namespace test -} // namespace ripple - -#endif // RIPPLE_TEST_JTX_AMMTEST_H_INCLUDED +} // namespace xrpl diff --git a/src/test/jtx/AbstractClient.h b/src/test/jtx/AbstractClient.h index b447b9dedb..9b1ef178ca 100644 --- a/src/test/jtx/AbstractClient.h +++ b/src/test/jtx/AbstractClient.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_ABSTRACTCLIENT_H_INCLUDED -#define RIPPLE_TEST_ABSTRACTCLIENT_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { /* Abstract Ripple Client interface. @@ -59,6 +39,4 @@ public: }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/Account.h b/src/test/jtx/Account.h index 940960051a..6f796e08b3 100644 --- a/src/test/jtx/Account.h +++ b/src/test/jtx/Account.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ACCOUNT_H_INCLUDED -#define RIPPLE_TEST_JTX_ACCOUNT_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -59,18 +39,14 @@ public: /** @{ */ Account(std::string name, KeyType type = KeyType::secp256k1); - Account(char const* name, KeyType type = KeyType::secp256k1) - : Account(std::string(name), type) + Account(char const* name, KeyType type = KeyType::secp256k1) : Account(std::string(name), type) { } // This constructor needs to be public so `std::pair` can use it when // emplacing into the cache. However, it is logically `private`. This is // enforced with the `privateTag` parameter. - Account( - std::string name, - std::pair const& keys, - Account::privateCtorTag); + Account(std::string name, std::pair const& keys, Account::privateCtorTag); /** @} */ @@ -135,9 +111,7 @@ public: operator[](std::string const& s) const; private: - static std:: - unordered_map, Account, beast::uhash<>> - cache_; + static std::unordered_map, Account, beast::uhash<>> cache_; // Return the account from the cache & add it to the cache if needed static Account @@ -171,6 +145,4 @@ operator<=>(Account const& lhs, Account const& rhs) noexcept } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/CaptureLogs.h b/src/test/jtx/CaptureLogs.h index a8afb521c3..f8d0449977 100644 --- a/src/test/jtx/CaptureLogs.h +++ b/src/test/jtx/CaptureLogs.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_CAPTURELOGS_H_INCLUDED -#define RIPPLE_TEST_JTX_CAPTURELOGS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { /** @@ -46,27 +26,20 @@ class CaptureLogs : public Logs std::stringstream& strm_; public: - CaptureSink( - beast::severities::Severity threshold, - std::mutex& mutex, - std::stringstream& strm) - : beast::Journal::Sink(threshold, false) - , strmMutex_(mutex) - , strm_(strm) + CaptureSink(beast::severities::Severity threshold, std::mutex& mutex, std::stringstream& strm) + : beast::Journal::Sink(threshold, false), strmMutex_(mutex), strm_(strm) { } void - write(beast::severities::Severity level, std::string const& text) - override + write(beast::severities::Severity level, std::string const& text) override { std::lock_guard lock(strmMutex_); strm_ << text; } void - writeAlways(beast::severities::Severity level, std::string const& text) - override + writeAlways(beast::severities::Severity level, std::string const& text) override { std::lock_guard lock(strmMutex_); strm_ << text; @@ -74,8 +47,7 @@ class CaptureLogs : public Logs }; public: - explicit CaptureLogs(std::string* pResult) - : Logs(beast::severities::kInfo), pResult_(pResult) + explicit CaptureLogs(std::string* pResult) : Logs(beast::severities::kInfo), pResult_(pResult) { } @@ -85,15 +57,11 @@ public: } std::unique_ptr - makeSink( - std::string const& partition, - beast::severities::Severity threshold) override + makeSink(std::string const& partition, beast::severities::Severity threshold) override { return std::make_unique(threshold, strmMutex_, strm_); } }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/CheckMessageLogs.h b/src/test/jtx/CheckMessageLogs.h index fd3915440e..286cfa1844 100644 --- a/src/test/jtx/CheckMessageLogs.h +++ b/src/test/jtx/CheckMessageLogs.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_CHECKMESSAGELOGS_H_INCLUDED -#define RIPPLE_TEST_JTX_CHECKMESSAGELOGS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { /** Log manager that searches for a specific message substring @@ -37,24 +17,20 @@ class CheckMessageLogs : public Logs CheckMessageLogs& owner_; public: - CheckMessageSink( - beast::severities::Severity threshold, - CheckMessageLogs& owner) + CheckMessageSink(beast::severities::Severity threshold, CheckMessageLogs& owner) : beast::Journal::Sink(threshold, false), owner_(owner) { } void - write(beast::severities::Severity level, std::string const& text) - override + write(beast::severities::Severity level, std::string const& text) override { if (text.find(owner_.msg_) != std::string::npos) *owner_.pFound_ = true; } void - writeAlways(beast::severities::Severity level, std::string const& text) - override + writeAlways(beast::severities::Severity level, std::string const& text) override { write(level, text); } @@ -73,15 +49,11 @@ public: } std::unique_ptr - makeSink( - std::string const& partition, - beast::severities::Severity threshold) override + makeSink(std::string const& partition, beast::severities::Severity threshold) override { return std::make_unique(threshold, *this); } }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 7181ec2a3e..7d7dcd2cb8 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ENV_H_INCLUDED -#define RIPPLE_TEST_JTX_ENV_H_INCLUDED +#pragma once #include #include @@ -51,6 +31,7 @@ #include #include +#include #include #include #include @@ -58,10 +39,31 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { +/** Wrapper that captures std::source_location when implicitly constructed. + This solves the problem of combining std::source_location with variadic + templates. The std::source_location default argument is evaluated at the + call site when the wrapper is constructed via implicit conversion. + + This is a template struct that holds the value directly, allowing implicit + conversion without template argument deduction issues via CTAD. +*/ +template +struct WithSourceLocation +{ + T value; + std::source_location loc; + + // Non-explicit constructor allows implicit conversion. + // The default argument for loc is evaluated at the call site. + WithSourceLocation(T v, std::source_location l = std::source_location::current()) : value(std::move(v)), loc(l) + { + } +}; + /** Designate accounts as no-ripple in Env::fund */ template std::array @@ -83,8 +85,7 @@ testable_amendments() if (auto const f = getRegisteredFeature(s)) feats.push_back(*f); else - Throw( - "Unknown feature: " + s + " in allAmendments."); + Throw("Unknown feature: " + s + " in allAmendments."); } return FeatureBitset(feats); }(); @@ -98,17 +99,14 @@ class SuiteLogs : public Logs beast::unit_test::suite& suite_; public: - explicit SuiteLogs(beast::unit_test::suite& suite) - : Logs(beast::severities::kError), suite_(suite) + explicit SuiteLogs(beast::unit_test::suite& suite) : Logs(beast::severities::kError), suite_(suite) { } ~SuiteLogs() override = default; std::unique_ptr - makeSink( - std::string const& partition, - beast::severities::Severity threshold) override + makeSink(std::string const& partition, beast::severities::Severity threshold) override { return std::make_unique(partition, threshold, suite_); } @@ -192,10 +190,7 @@ public: { memoize(Account::master); Pathfinder::initPathTable(); - foreachFeature( - features, [&appFeats = app().config().features](uint256 const& f) { - appFeats.insert(f); - }); + foreachFeature(features, [&appFeats = app().config().features](uint256 const& f) { appFeats.insert(f); }); } /** @@ -211,9 +206,7 @@ public: * @param args collection of features * */ - Env(beast::unit_test::suite& suite_, - FeatureBitset features, - std::unique_ptr logs = nullptr) + Env(beast::unit_test::suite& suite_, FeatureBitset features, std::unique_ptr logs = nullptr) : Env(suite_, envconfig(), features, std::move(logs)) { } @@ -234,11 +227,7 @@ public: std::unique_ptr config, std::unique_ptr logs = nullptr, beast::severities::Severity thresh = beast::severities::kError) - : Env(suite_, - std::move(config), - testable_amendments(), - std::move(logs), - thresh) + : Env(suite_, std::move(config), testable_amendments(), std::move(logs), thresh) { } @@ -251,7 +240,8 @@ public: * * @param suite_ the current unit_test::suite */ - Env(beast::unit_test::suite& suite_) : Env(suite_, envconfig()) + Env(beast::unit_test::suite& suite_, beast::severities::Severity thresh = beast::severities::kError) + : Env(suite_, envconfig(), nullptr, thresh) { } @@ -311,9 +301,7 @@ public: template Json::Value - rpc(std::unordered_map const& headers, - std::string const& cmd, - Args&&... args); + rpc(std::unordered_map const& headers, std::string const& cmd, Args&&... args); template Json::Value @@ -363,9 +351,7 @@ public: @return true if no error, false if error */ bool - close( - NetClock::time_point closeTime, - std::optional consensusDelay = std::nullopt); + close(NetClock::time_point closeTime, std::optional consensusDelay = std::nullopt); /** Close and advance the ledger. @@ -558,13 +544,16 @@ public: This calls postconditions. */ virtual void - submit(JTx const& jt); + submit(JTx const& jt, std::source_location const& loc = std::source_location::current()); /** Use the submit RPC command with a provided JTx object. This calls postconditions. */ void - sign_and_submit(JTx const& jt, Json::Value params = Json::nullValue); + sign_and_submit( + JTx const& jt, + Json::Value params = Json::nullValue, + std::source_location const& loc = std::source_location::current()); /** Check expected postconditions of JTx submission. @@ -573,23 +562,39 @@ public: postconditions( JTx const& jt, ParsedResult const& parsed, - Json::Value const& jr = Json::Value()); + Json::Value const& jr = Json::Value(), + std::source_location const& loc = std::source_location::current()); /** Apply funclets and submit. */ /** @{ */ - template + template Env& - apply(JsonValue&& jv, FN const&... fN) + apply(WithSourceLocation jv, FN const&... fN) { - submit(jt(std::forward(jv), fN...)); + submit(jt(std::move(jv.value), fN...), jv.loc); return *this; } - template + template Env& - operator()(JsonValue&& jv, FN const&... fN) + apply(WithSourceLocation jv, FN const&... fN) { - return apply(std::forward(jv), fN...); + submit(jt(std::move(jv.value), fN...), jv.loc); + return *this; + } + + template + Env& + operator()(WithSourceLocation jv, FN const&... fN) + { + return apply(std::move(jv), fN...); + } + + template + Env& + operator()(WithSourceLocation jv, FN const&... fN) + { + return apply(std::move(jv), fN...); } /** @} */ @@ -717,11 +722,7 @@ public: template void - trust( - STAmount const& amount, - Account const& to0, - Account const& to1, - Accounts const&... toN) + trust(STAmount const& amount, Account const& to0, Account const& to1, Accounts const&... toN) { trust(amount, to0); trust(amount, to1, toN...); @@ -794,48 +795,30 @@ Env::rpc( std::string const& cmd, Args&&... args) { - return do_rpc( - apiVersion, - std::vector{cmd, std::forward(args)...}, - headers); + return do_rpc(apiVersion, std::vector{cmd, std::forward(args)...}, headers); } template Json::Value Env::rpc(unsigned apiVersion, std::string const& cmd, Args&&... args) { - return rpc( - apiVersion, - std::unordered_map(), - cmd, - std::forward(args)...); + return rpc(apiVersion, std::unordered_map(), cmd, std::forward(args)...); } template Json::Value -Env::rpc( - std::unordered_map const& headers, - std::string const& cmd, - Args&&... args) +Env::rpc(std::unordered_map const& headers, std::string const& cmd, Args&&... args) { - return do_rpc( - RPC::apiCommandLineVersion, - std::vector{cmd, std::forward(args)...}, - headers); + return do_rpc(RPC::apiCommandLineVersion, std::vector{cmd, std::forward(args)...}, headers); } template Json::Value Env::rpc(std::string const& cmd, Args&&... args) { - return rpc( - std::unordered_map(), - cmd, - std::forward(args)...); + return rpc(std::unordered_map(), cmd, std::forward(args)...); } } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/Env_ss.h b/src/test/jtx/Env_ss.h index a9ffcb0a26..9c178a1c13 100644 --- a/src/test/jtx/Env_ss.h +++ b/src/test/jtx/Env_ss.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ENV_SS_H_INCLUDED -#define RIPPLE_TEST_JTX_ENV_SS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -43,19 +23,20 @@ private: SignSubmitRunner& operator=(SignSubmitRunner&&) = delete; - SignSubmitRunner(Env& env, JTx&& jt) : env_(env), jt_(jt) + SignSubmitRunner(Env& env, JTx&& jt, std::source_location loc) : env_(env), jt_(jt), loc_(loc) { } void operator()(Json::Value const& params = Json::nullValue) { - env_.sign_and_submit(jt_, params); + env_.sign_and_submit(jt_, params, loc_); } private: Env& env_; JTx const jt_; + std::source_location const loc_; }; public: @@ -67,17 +48,23 @@ public: { } - template + template SignSubmitRunner - operator()(JsonValue&& jv, FN const&... fN) + operator()(WithSourceLocation jv, FN const&... fN) { - auto jtx = env_.jt(std::forward(jv), fN...); - return SignSubmitRunner(env_, std::move(jtx)); + auto jtx = env_.jt(std::move(jv.value), fN...); + return SignSubmitRunner(env_, std::move(jtx), jv.loc); + } + + template + SignSubmitRunner + operator()(WithSourceLocation jv, FN const&... fN) + { + auto jtx = env_.jt(std::move(jv.value), fN...); + return SignSubmitRunner(env_, std::move(jtx), jv.loc); } }; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/Env_test.cpp b/src/test/jtx/Env_test.cpp index 8f1f30c241..0f43691b86 100644 --- a/src/test/jtx/Env_test.cpp +++ b/src/test/jtx/Env_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -33,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Env_test : public beast::unit_test::suite @@ -52,7 +33,7 @@ public: { using namespace jtx; { - Account a("chenna"); + Account a("chad"); Account b(a); a = b; a = std::move(b); @@ -80,18 +61,10 @@ public: PrettyAmount(0u); PrettyAmount(1u); PrettyAmount(-1); - static_assert( - !std::is_trivially_constructible::value, ""); - static_assert( - !std::is_trivially_constructible:: - value, - ""); - static_assert( - !std::is_trivially_constructible::value, ""); - static_assert( - !std::is_trivially_constructible:: - value, - ""); + static_assert(!std::is_trivially_constructible::value, ""); + static_assert(!std::is_trivially_constructible::value, ""); + static_assert(!std::is_trivially_constructible::value, ""); + static_assert(!std::is_trivially_constructible::value, ""); try { @@ -158,11 +131,7 @@ public: // unfunded { Env env(*this); - env(pay("alice", "bob", XRP(1000)), - seq(1), - fee(10), - sig("alice"), - ter(terNO_ACCOUNT)); + env(pay("alice", "bob", XRP(1000)), seq(1), fee(10), sig("alice"), ter(terNO_ACCOUNT)); } // fund @@ -181,8 +150,8 @@ public: // flags env.fund(n, noripple("xavier")); env.require(nflags("xavier", asfDefaultRipple)); - env.fund(n, "yana"); - env.require(flags("yana", asfDefaultRipple)); + env.fund(n, "zachary"); + env.require(flags("zachary", asfDefaultRipple)); } // trust @@ -206,8 +175,7 @@ public: env.trust(USD(1000), alice); env(pay(gw, alice, USD(10))); BEAST_EXPECT(to_string(env.balance("alice", USD)) == "10/USD(gw)"); - BEAST_EXPECT( - to_string(env.balance(gw, alice["USD"])) == "-10/USD(alice)"); + BEAST_EXPECT(to_string(env.balance(gw, alice["USD"])) == "-10/USD(alice)"); } // seq @@ -253,10 +221,8 @@ public: env(pay(gw, "alice", USD(10)), require(balance("alice", USD(10)))); env.require(nflags("alice", asfRequireDest)); - env(fset("alice", asfRequireDest), - require(flags("alice", asfRequireDest))); - env(fclear("alice", asfRequireDest), - require(nflags("alice", asfRequireDest))); + env(fset("alice", asfRequireDest), require(flags("alice", asfRequireDest))); + env(fclear("alice", asfRequireDest), require(nflags("alice", asfRequireDest))); } // Signing with secp256k1 and ed25519 keys @@ -275,9 +241,7 @@ public: env(noop(alice)); env(noop(bob)); env(noop(alice), sig("alice"), ter(tefBAD_AUTH)); - env(noop(alice), - sig(Account("alice", KeyType::secp256k1)), - ter(tefBAD_AUTH)); + env(noop(alice), sig(Account("alice", KeyType::secp256k1)), ter(tefBAD_AUTH)); env(noop(bob), sig(Account("bob", KeyType::ed25519)), ter(tefBAD_AUTH)); env(noop(alice), sig(carol), ter(tefBAD_AUTH)); @@ -292,9 +256,7 @@ public: env(noop(alice)); env(noop(alice), sig(bob)); env(noop(alice), sig(alice), ter(tefMASTER_DISABLED)); - env(fclear(alice, asfDisableMaster), - sig(alice), - ter(tefMASTER_DISABLED)); + env(fclear(alice, asfDisableMaster), sig(alice), ter(tefMASTER_DISABLED)); env(fclear(alice, asfDisableMaster), sig(bob)); env(noop(alice), sig(alice)); } @@ -333,10 +295,7 @@ public: env(offer("carol", XRP(50), USD(50)), require(owners("carol", 2))); env(pay("alice", "bob", any(USD(10))), ter(tecPATH_DRY)); - env(pay("alice", "bob", any(USD(10))), - paths(XRP), - sendmax(XRP(10)), - ter(tecPATH_PARTIAL)); + env(pay("alice", "bob", any(USD(10))), paths(XRP), sendmax(XRP(10)), ter(tecPATH_PARTIAL)); env(pay("alice", "bob", any(USD(10))), paths(XRP), sendmax(XRP(20))); env.require(balance("bob", USD(10))); env.require(balance("carol", USD(39.5))); @@ -348,9 +307,7 @@ public: env(noop("alice"), sig("eric")); env(noop("alice"), sig("bob"), ter(tefBAD_AUTH)); env(fset("alice", asfDisableMaster), ter(tecNEED_MASTER_KEY)); - env(fset("alice", asfDisableMaster), - sig("eric"), - ter(tecNEED_MASTER_KEY)); + env(fset("alice", asfDisableMaster), sig("eric"), ter(tecNEED_MASTER_KEY)); env.require(nflags("alice", asfDisableMaster)); env(fset("alice", asfDisableMaster), sig("alice")); env.require(flags("alice", asfDisableMaster)); @@ -360,9 +317,7 @@ public: env(noop("alice"), sig("eric")); env(noop("alice"), sig("bob"), ter(tefBAD_AUTH)); env(fclear("alice", asfDisableMaster), sig("bob"), ter(tefBAD_AUTH)); - env(fclear("alice", asfDisableMaster), - sig("alice"), - ter(tefMASTER_DISABLED)); + env(fclear("alice", asfDisableMaster), sig("alice"), ter(tefMASTER_DISABLED)); env(fclear("alice", asfDisableMaster)); env.require(nflags("alice", asfDisableMaster)); env(regkey("alice", disabled)); @@ -385,8 +340,7 @@ public: env.fund(XRP(10000), alice); auto const localTxCnt = env.app().getOPs().getLocalTxCount(); - auto const queueTxCount = - env.app().getTxQ().getMetrics(*env.current()).txCount; + auto const queueTxCount = env.app().getTxQ().getMetrics(*env.current()).txCount; auto const openTxCount = env.current()->txCount(); BEAST_EXPECT(localTxCnt == 2 && queueTxCount == 0 && openTxCount == 2); @@ -406,46 +360,35 @@ public: auto jr = applyTxn(noop(alice), fee(1)); BEAST_EXPECT(jr[jss::result][jss::engine_result] == "telINSUF_FEE_P"); - BEAST_EXPECT( - env.app().getTxQ().getMetrics(*env.current()).txCount == - queueTxCount); + BEAST_EXPECT(env.app().getTxQ().getMetrics(*env.current()).txCount == queueTxCount); BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt); BEAST_EXPECT(env.current()->txCount() == openTxCount); jr = applyTxn(noop(alice), sig("bob")); BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tefBAD_AUTH"); - BEAST_EXPECT( - env.app().getTxQ().getMetrics(*env.current()).txCount == - queueTxCount); + BEAST_EXPECT(env.app().getTxQ().getMetrics(*env.current()).txCount == queueTxCount); BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt); BEAST_EXPECT(env.current()->txCount() == openTxCount); jr = applyTxn(noop(alice), seq(20)); BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terPRE_SEQ"); - BEAST_EXPECT( - env.app().getTxQ().getMetrics(*env.current()).txCount == - queueTxCount); + BEAST_EXPECT(env.app().getTxQ().getMetrics(*env.current()).txCount == queueTxCount); BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt); BEAST_EXPECT(env.current()->txCount() == openTxCount); jr = applyTxn(offer(alice, XRP(1000), USD(1000))); - BEAST_EXPECT( - jr[jss::result][jss::engine_result] == "tecUNFUNDED_OFFER"); - BEAST_EXPECT( - env.app().getTxQ().getMetrics(*env.current()).txCount == - queueTxCount); + BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tecUNFUNDED_OFFER"); + BEAST_EXPECT(env.app().getTxQ().getMetrics(*env.current()).txCount == queueTxCount); BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt); BEAST_EXPECT(env.current()->txCount() == openTxCount); jr = applyTxn(noop(alice), fee(drops(-10))); BEAST_EXPECT(jr[jss::result][jss::engine_result] == "temBAD_FEE"); - BEAST_EXPECT( - env.app().getTxQ().getMetrics(*env.current()).txCount == - queueTxCount); + BEAST_EXPECT(env.app().getTxQ().getMetrics(*env.current()).txCount == queueTxCount); BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt); BEAST_EXPECT(env.current()->txCount() == openTxCount); @@ -464,8 +407,7 @@ public: Env env(*this); env.fund(XRP(10000), "alice"); - env(signers("alice", 1, {{"alice", 1}, {"bob", 2}}), - ter(temBAD_SIGNER)); + env(signers("alice", 1, {{"alice", 1}, {"bob", 2}}), ter(temBAD_SIGNER)); env(signers("alice", 1, {{"bob", 1}, {"carol", 2}})); env(noop("alice")); @@ -473,10 +415,7 @@ public: env(noop("alice"), msig("bob"), fee(2 * baseFee)); env(noop("alice"), msig("carol"), fee(2 * baseFee)); env(noop("alice"), msig("bob", "carol"), fee(3 * baseFee)); - env(noop("alice"), - msig("bob", "carol", "dilbert"), - fee(4 * baseFee), - ter(tefBAD_SIGNATURE)); + env(noop("alice"), msig("bob", "carol", "dilbert"), fee(4 * baseFee), ter(tefBAD_SIGNATURE)); env(signers("alice", none)); } @@ -491,10 +430,8 @@ public: { Env env(*this); env.fund(XRP(10000), "alice"); - env(noop("alice"), - require(owners("alice", 0), tickets("alice", 0))); - env(ticket::create("alice", 1), - require(owners("alice", 1), tickets("alice", 1))); + env(noop("alice"), require(owners("alice", 0), tickets("alice", 0))); + env(ticket::create("alice", 1), require(owners("alice", 1), tickets("alice", 1))); } } @@ -550,10 +487,7 @@ public: auto jt2 = env.jt(noop("alice"), prop(-1)); BEAST_EXPECT(jt2.get()); BEAST_EXPECT(*jt2.get() == 65535); - auto jt3 = env.jt( - noop("alice"), - prop("Hello, world!"), - prop(false)); + auto jt3 = env.jt(noop("alice"), prop("Hello, world!"), prop(false)); BEAST_EXPECT(jt3.get()); BEAST_EXPECT(*jt3.get() == "Hello, world!"); BEAST_EXPECT(jt3.get()); @@ -615,16 +549,11 @@ public: using namespace jtx; Env env(*this); env.fund(XRP(10000), "alice"); - env(noop("alice"), memodata("data")); - env(noop("alice"), memoformat("format")); - env(noop("alice"), memotype("type")); - env(noop("alice"), memondata("format", "type")); - env(noop("alice"), memonformat("data", "type")); - env(noop("alice"), memontype("data", "format")); + env(noop("alice"), memo_data("data")); + env(noop("alice"), memo_format("format")); + env(noop("alice"), memo_type("type")); env(noop("alice"), memo("data", "format", "type")); - env(noop("alice"), - memo("data1", "format1", "type1"), - memo("data2", "format2", "type2")); + env(noop("alice"), memo("data1", "format1", "type1"), memo("data2", "format2", "type2")); } void @@ -636,12 +565,9 @@ public: memo("data", "format", "type")(env, jt); auto const& memo = jt.jv["Memos"][0u]["Memo"]; - BEAST_EXPECT( - memo["MemoData"].asString() == strHex(std::string("data"))); - BEAST_EXPECT( - memo["MemoFormat"].asString() == strHex(std::string("format"))); - BEAST_EXPECT( - memo["MemoType"].asString() == strHex(std::string("type"))); + BEAST_EXPECT(memo["MemoData"].asString() == strHex(std::string("data"))); + BEAST_EXPECT(memo["MemoFormat"].asString() == strHex(std::string("format"))); + BEAST_EXPECT(memo["MemoType"].asString() == strHex(std::string("type"))); } void @@ -706,8 +632,7 @@ public: std::uint32_t const aliceSeq = env.seq("alice"); // Sign jsonNoop. - Json::Value jsonNoop = - env.json(noop("alice"), fee(baseFee), seq(aliceSeq), sig("alice")); + Json::Value jsonNoop = env.json(noop("alice"), fee(baseFee), seq(aliceSeq), sig("alice")); // Re-sign jsonNoop. JTx jt = env.jt(jsonNoop); env(jt); @@ -756,15 +681,9 @@ public: params[jss::fee_mult_max] = 1; params[jss::fee_div_max] = 2; - auto const expectedErrorString = "Fee of " + - std::to_string(baseFee.drops()) + - " exceeds the requested tx limit of " + - std::to_string(baseFee.drops() / 2); - envs( - noop(alice), - fee(none), - seq(none), - rpc(rpcHIGH_FEE, expectedErrorString))(params); + auto const expectedErrorString = "Fee of " + std::to_string(baseFee.drops()) + + " exceeds the requested tx limit of " + std::to_string(baseFee.drops() / 2); + envs(noop(alice), fee(none), seq(none), rpc(rpcHIGH_FEE, expectedErrorString))(params); auto tx = env.tx(); BEAST_EXPECT(!tx); @@ -793,50 +712,40 @@ public: if (!neverSupportedFeat) { - log << "No unsupported features found - skipping test." - << std::endl; + log << "No unsupported features found - skipping test." << std::endl; pass(); return; } auto hasFeature = [](Env& env, uint256 const& f) { - return ( - env.app().config().features.find(f) != - env.app().config().features.end()); + return (env.app().config().features.find(f) != env.app().config().features.end()); }; { // default Env has all supported features Env env{*this}; - BEAST_EXPECT( - supported.count() == env.app().config().features.size()); - foreachFeature(supported, [&](uint256 const& f) { - this->BEAST_EXPECT(hasFeature(env, f)); - }); + BEAST_EXPECT(supported.count() == env.app().config().features.size()); + foreachFeature(supported, [&](uint256 const& f) { this->BEAST_EXPECT(hasFeature(env, f)); }); } { // a Env FeatureBitset has *only* those features - Env env{*this, FeatureBitset(featureMultiSignReserve, featureFlow)}; + Env env{*this, FeatureBitset{featureDynamicMPT | featureTokenEscrow}}; BEAST_EXPECT(env.app().config().features.size() == 2); foreachFeature(supported, [&](uint256 const& f) { - bool const has = - (f == featureMultiSignReserve || f == featureFlow); + bool const has = (f == featureDynamicMPT || f == featureTokenEscrow); this->BEAST_EXPECT(has == hasFeature(env, f)); }); } - auto const missingSomeFeatures = - testable_amendments() - featureMultiSignReserve - featureFlow; + auto const missingSomeFeatures = testable_amendments() - featureDynamicMPT - featureTokenEscrow; BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2)); { // a Env supported_features_except is missing *only* those features Env env{*this, missingSomeFeatures}; - BEAST_EXPECT( - env.app().config().features.size() == (supported.count() - 2)); + BEAST_EXPECT(env.app().config().features.size() == (supported.count() - 2)); foreachFeature(supported, [&](uint256 const& f) { - bool hasnot = - (f == featureMultiSignReserve || f == featureFlow); + bool hasnot = (f == featureDynamicMPT || f == featureTokenEscrow); this->BEAST_EXPECT(hasnot != hasFeature(env, f)); }); } @@ -846,10 +755,7 @@ public: // along with a list of explicit amendments // the unsupported feature should be enabled along with // the two supported ones - Env env{ - *this, - FeatureBitset( - featureMultiSignReserve, featureFlow, *neverSupportedFeat)}; + Env env{*this, FeatureBitset{featureDynamicMPT, featureTokenEscrow, *neverSupportedFeat}}; // this app will have just 2 supported amendments and // one additional never supported feature flag @@ -857,7 +763,7 @@ public: BEAST_EXPECT(hasFeature(env, *neverSupportedFeat)); foreachFeature(supported, [&](uint256 const& f) { - bool has = (f == featureMultiSignReserve || f == featureFlow); + bool has = (f == featureDynamicMPT || f == featureTokenEscrow); this->BEAST_EXPECT(has == hasFeature(env, f)); }); } @@ -866,19 +772,14 @@ public: // add a feature that is NOT in the supported amendments list // and omit a few standard amendments // the unsupported features should be enabled - Env env{ - *this, - missingSomeFeatures | FeatureBitset{*neverSupportedFeat}}; + Env env{*this, missingSomeFeatures | FeatureBitset{*neverSupportedFeat}}; // this app will have all supported amendments minus 2 and then the // one additional never supported feature flag - BEAST_EXPECT( - env.app().config().features.size() == - (supported.count() - 2 + 1)); + BEAST_EXPECT(env.app().config().features.size() == (supported.count() - 2 + 1)); BEAST_EXPECT(hasFeature(env, *neverSupportedFeat)); foreachFeature(supported, [&](uint256 const& f) { - bool hasnot = - (f == featureMultiSignReserve || f == featureFlow); + bool hasnot = (f == featureDynamicMPT || f == featureTokenEscrow); this->BEAST_EXPECT(hasnot != hasFeature(env, f)); }); } @@ -891,12 +792,9 @@ public: // this app will have all supported amendments and then the // one additional never supported feature flag - BEAST_EXPECT( - env.app().config().features.size() == (supported.count() + 1)); + BEAST_EXPECT(env.app().config().features.size() == (supported.count() + 1)); BEAST_EXPECT(hasFeature(env, *neverSupportedFeat)); - foreachFeature(supported, [&](uint256 const& f) { - this->BEAST_EXPECT(hasFeature(env, f)); - }); + foreachFeature(supported, [&](uint256 const& f) { this->BEAST_EXPECT(hasFeature(env, f)); }); } } @@ -944,7 +842,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Env, jtx, ripple); +BEAST_DEFINE_TESTSUITE(Env, jtx, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/JSONRPCClient.h b/src/test/jtx/JSONRPCClient.h index 3765893eb7..41129a36ec 100644 --- a/src/test/jtx/JSONRPCClient.h +++ b/src/test/jtx/JSONRPCClient.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_HTTPCLIENT_H_INCLUDED -#define RIPPLE_TEST_HTTPCLIENT_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { /** Returns a client using JSON-RPC over HTTP/S. */ @@ -34,6 +14,4 @@ std::unique_ptr makeJSONRPCClient(Config const& cfg, unsigned rpc_version = 2); } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/JTx.h b/src/test/jtx/JTx.h index 36127f1843..90fbb8a6b6 100644 --- a/src/test/jtx/JTx.h +++ b/src/test/jtx/JTx.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_JTX_H_INCLUDED -#define RIPPLE_TEST_JTX_JTX_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -47,8 +27,7 @@ struct JTx requires_t require; std::optional ter = TER{tesSUCCESS}; std::optional> rpcCode = std::nullopt; - std::optional>> - rpcException = std::nullopt; + std::optional>> rpcException = std::nullopt; bool fill_fee = true; bool fill_seq = true; bool fill_sig = true; @@ -59,6 +38,9 @@ struct JTx // Functions that sign something else after the mainSigners, such as // sfCounterpartySignature std::vector> postSigners; + // Metadata about the unit test itself + // The line where the JTx was constructed + std::optional testLine = std::nullopt; JTx() = default; JTx(JTx const&) = default; @@ -175,6 +157,4 @@ private: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/ManualTimeKeeper.h b/src/test/jtx/ManualTimeKeeper.h index c9bf4d4763..d5fdd467e1 100644 --- a/src/test/jtx/ManualTimeKeeper.h +++ b/src/test/jtx/ManualTimeKeeper.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_MANUALTIMEKEEPER_H_INCLUDED -#define RIPPLE_TEST_MANUALTIMEKEEPER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { class ManualTimeKeeper : public TimeKeeper @@ -49,6 +29,4 @@ public: }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/Oracle.h b/src/test/jtx/Oracle.h index 9d2554c18f..da241c0ce8 100644 --- a/src/test/jtx/Oracle.h +++ b/src/test/jtx/Oracle.h @@ -1,37 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ORACLE_H_INCLUDED -#define RIPPLE_TEST_JTX_ORACLE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace oracle { using AnyValue = std::variant; -using OraclesData = - std::vector, std::optional>>; +using OraclesData = std::vector, std::optional>>; // Special string value, which is converted to unquoted string in the string // passed to rpc. @@ -52,11 +31,8 @@ void toJsonHex(Json::Value& jv, AnyValue const& v); // base asset, quote asset, price, scale -using DataSeries = std::vector, - std::optional>>; +using DataSeries = + std::vector, std::optional>>; // Typical defaults for Create struct CreateArg @@ -109,8 +85,7 @@ struct RemoveArg // The value doesn't matter much, it has to be greater // than maxLastUpdateTimeDelta in order to pass LastUpdateTime // validation {close-maxLastUpdateTimeDelta,close+maxLastUpdateTimeDelta}. -constexpr static std::chrono::seconds testStartTime = - epoch_offset + std::chrono::seconds(10'000); +constexpr static std::chrono::seconds testStartTime = epoch_offset + std::chrono::seconds(10'000); /** Oracle class facilitates unit-testing of the Price Oracle feature. * It defines functions to create, update, and delete the Oracle object, @@ -151,7 +126,7 @@ public: std::optional const& quoteAsset, std::optional const& oracles = std::nullopt, std::optional const& trim = std::nullopt, - std::optional const& timeTreshold = std::nullopt); + std::optional const& timeThreshold = std::nullopt); std::uint32_t documentID() const @@ -169,7 +144,7 @@ public: exists(Env& env, AccountID const& account, std::uint32_t documentID); [[nodiscard]] bool - expectPrice(DataSeries const& pricess) const; + expectPrice(DataSeries const& prices) const; [[nodiscard]] bool expectLastUpdateTime(std::uint32_t lastUpdateTime) const; @@ -204,6 +179,4 @@ public: } // namespace oracle } // namespace jtx } // namespace test -} // namespace ripple - -#endif // RIPPLE_TEST_JTX_ORACLE_H_INCLUDED +} // namespace xrpl diff --git a/src/test/jtx/PathSet.h b/src/test/jtx/PathSet.h index df9de540a1..3f30d7193f 100644 --- a/src/test/jtx/PathSet.h +++ b/src/test/jtx/PathSet.h @@ -1,79 +1,43 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED -#define RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { /** Count offer */ inline std::size_t -countOffers( - jtx::Env& env, - jtx::Account const& account, - Issue const& takerPays, - Issue const& takerGets) +countOffers(jtx::Env& env, jtx::Account const& account, Issue const& takerPays, Issue const& takerGets) { size_t count = 0; - forEachItem( - *env.current(), account, [&](std::shared_ptr const& sle) { - if (sle->getType() == ltOFFER && - sle->getFieldAmount(sfTakerPays).issue() == takerPays && - sle->getFieldAmount(sfTakerGets).issue() == takerGets) - ++count; - }); + forEachItem(*env.current(), account, [&](std::shared_ptr const& sle) { + if (sle->getType() == ltOFFER && sle->getFieldAmount(sfTakerPays).issue() == takerPays && + sle->getFieldAmount(sfTakerGets).issue() == takerGets) + ++count; + }); return count; } inline std::size_t -countOffers( - jtx::Env& env, - jtx::Account const& account, - STAmount const& takerPays, - STAmount const& takerGets) +countOffers(jtx::Env& env, jtx::Account const& account, STAmount const& takerPays, STAmount const& takerGets) { size_t count = 0; - forEachItem( - *env.current(), account, [&](std::shared_ptr const& sle) { - if (sle->getType() == ltOFFER && - sle->getFieldAmount(sfTakerPays) == takerPays && - sle->getFieldAmount(sfTakerGets) == takerGets) - ++count; - }); + forEachItem(*env.current(), account, [&](std::shared_ptr const& sle) { + if (sle->getType() == ltOFFER && sle->getFieldAmount(sfTakerPays) == takerPays && + sle->getFieldAmount(sfTakerGets) == takerGets) + ++count; + }); return count; } /** An offer exists */ inline bool -isOffer( - jtx::Env& env, - jtx::Account const& account, - STAmount const& takerPays, - STAmount const& takerGets) +isOffer(jtx::Env& env, jtx::Account const& account, STAmount const& takerPays, STAmount const& takerGets) { return countOffers(env, account, takerPays, takerGets) > 0; } @@ -81,11 +45,7 @@ isOffer( /** An offer exists */ inline bool -isOffer( - jtx::Env& env, - jtx::Account const& account, - Issue const& takerPays, - Issue const& takerGets) +isOffer(jtx::Env& env, jtx::Account const& account, Issue const& takerPays, Issue const& takerGets) { return countOffers(env, account, takerPays, takerGets) > 0; } @@ -133,11 +93,7 @@ Path::push_back(STPathElement const& pe) inline Path& Path::push_back(Issue const& iss) { - path.emplace_back( - STPathElement::typeCurrency | STPathElement::typeIssuer, - beast::zero, - iss.currency, - iss.account); + path.emplace_back(STPathElement::typeCurrency | STPathElement::typeIssuer, beast::zero, iss.currency, iss.account); return *this; } @@ -201,6 +157,4 @@ private: }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/SignerUtils.h b/src/test/jtx/SignerUtils.h index 7b1ae5007c..37b1d85ec7 100644 --- a/src/test/jtx/SignerUtils.h +++ b/src/test/jtx/SignerUtils.h @@ -1,11 +1,10 @@ -#ifndef RIPPLE_TEST_JTX_SIGNERUTILS_H_INCLUDED -#define RIPPLE_TEST_JTX_SIGNERUTILS_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -18,8 +17,7 @@ struct Reg { } - Reg(Account const& acct_, Account const& regularSig) - : acct(acct_), sig(regularSig) + Reg(Account const& acct_, Account const& regularSig) : acct(acct_), sig(regularSig) { } @@ -27,8 +25,7 @@ struct Reg { } - Reg(char const* acct_, char const* regularSig) - : acct(acct_), sig(regularSig) + Reg(char const* acct_, char const* regularSig) : acct(acct_), sig(regularSig) { } @@ -43,14 +40,9 @@ struct Reg inline void sortSigners(std::vector& signers) { - std::sort( - signers.begin(), signers.end(), [](Reg const& lhs, Reg const& rhs) { - return lhs.acct < rhs.acct; - }); + std::sort(signers.begin(), signers.end(), [](Reg const& lhs, Reg const& rhs) { return lhs.acct < rhs.acct; }); } } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/TestHelpers.h b/src/test/jtx/TestHelpers.h index 81d2f9c5ec..c0e54900f6 100644 --- a/src/test/jtx/TestHelpers.h +++ b/src/test/jtx/TestHelpers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TESTHELPERS_H_INCLUDED -#define RIPPLE_TEST_JTX_TESTHELPERS_H_INCLUDED +#pragma once #include @@ -34,29 +14,19 @@ #include #include +#include #include -#if (defined(__clang_major__) && __clang_major__ < 15) -#include -using source_location = std::experimental::source_location; -#else -#include -using std::source_location; -#endif - -namespace ripple { +namespace xrpl { namespace test { namespace jtx { -/** Generic helper class for helper clases that set a field on a JTx. +/** Generic helper class for helper classes that set a field on a JTx. Not every helper will be able to use this because of conversions and other issues, but for classes where it's straightforward, this can simplify things. */ -template < - class SField, - class StoredValue = typename SField::type::value_type, - class OutputValue = StoredValue> +template struct JTxField { using SF = SField; @@ -68,8 +38,7 @@ protected: SV value_; public: - explicit JTxField(SF const& sfield, SV const& value) - : sfield_(sfield), value_(value) + explicit JTxField(SF const& sfield, SV const& value) : sfield_(sfield), value_(value) { } @@ -97,8 +66,7 @@ protected: SV value_; public: - explicit JTxField(SF const& sfield, SV const& value) - : sfield_(sfield), value_(value) + explicit JTxField(SF const& sfield, SV const& value) : sfield_(sfield), value_(value) { } @@ -109,8 +77,7 @@ public: } }; -struct timePointField - : public JTxField +struct timePointField : public JTxField { using SF = SF_UINT32; using SV = NetClock::time_point; @@ -121,8 +88,7 @@ protected: using base::value_; public: - explicit timePointField(SF const& sfield, SV const& value) - : JTxField(sfield, value) + explicit timePointField(SF const& sfield, SV const& value) : JTxField(sfield, value) { } @@ -144,8 +110,7 @@ protected: using base::value_; public: - explicit uint256Field(SF const& sfield, SV const& value) - : JTxField(sfield, value) + explicit uint256Field(SF const& sfield, SV const& value) : JTxField(sfield, value) { } @@ -167,8 +132,7 @@ protected: using base::value_; public: - explicit accountIDField(SF const& sfield, SV const& value) - : JTxField(sfield, value) + explicit accountIDField(SF const& sfield, SV const& value) : JTxField(sfield, value) { } @@ -179,6 +143,28 @@ public: } }; +struct stAmountField : public JTxField +{ + using SF = SF_AMOUNT; + using SV = STAmount; + using OV = Json::Value; + using base = JTxField; + +protected: + using base::value_; + +public: + explicit stAmountField(SF const& sfield, SV const& value) : JTxField(sfield, value) + { + } + + OV + value() const override + { + return value_.getJson(JsonOptions::none); + } +}; + struct blobField : public JTxField { using SF = SF_VL; @@ -187,21 +173,18 @@ struct blobField : public JTxField using JTxField::JTxField; - explicit blobField(SF const& sfield, Slice const& cond) - : JTxField(sfield, strHex(cond)) + explicit blobField(SF const& sfield, Slice const& cond) : JTxField(sfield, strHex(cond)) { } template - explicit blobField(SF const& sfield, std::array const& c) - : blobField(sfield, makeSlice(c)) + explicit blobField(SF const& sfield, std::array const& c) : blobField(sfield, makeSlice(c)) { } }; template -struct valueUnitField - : public JTxField, ValueType> +struct valueUnitField : public JTxField, ValueType> { using SF = SField; using SV = unit::ValueUnit; @@ -280,12 +263,8 @@ public: } }; -template < - class SField, - class UnitTag, - class ValueType = typename SField::type::value_type> -using valueUnitWrapper = - JTxFieldWrapper>; +template +using valueUnitWrapper = JTxFieldWrapper>; template using simpleField = JTxFieldWrapper>; @@ -294,6 +273,8 @@ using simpleField = JTxFieldWrapper>; */ auto const data = JTxFieldWrapper(sfData); +auto const amount = JTxFieldWrapper(sfAmount); + // TODO We only need this long "requires" clause as polyfill, for C++20 // implementations which are missing header. Replace with // `std::ranges::range`, and accordingly use std::ranges::begin/end @@ -372,10 +353,7 @@ checkVL(Slice const& result, std::string const& expected) [[nodiscard]] inline bool -checkVL( - std::shared_ptr const& sle, - SField const& field, - std::string const& expected) +checkVL(std::shared_ptr const& sle, SField const& field, std::string const& expected) { return strHex(expected) == strHex(sle->getFieldVL(field)); } @@ -455,52 +433,32 @@ PrettyAmount xrpMinusFee(Env const& env, std::int64_t xrpAmount); bool -expectHolding( - Env& env, - AccountID const& account, - STAmount const& value, - bool defaultLimits = false); +expectHolding(Env& env, AccountID const& account, STAmount const& value, bool defaultLimits = false); template bool -expectHolding( - Env& env, - AccountID const& account, - STAmount const& value, - Amts const&... amts) +expectHolding(Env& env, AccountID const& account, STAmount const& value, Amts const&... amts) { - return expectHolding(env, account, value, false) && - expectHolding(env, account, amts...); + return expectHolding(env, account, value, false) && expectHolding(env, account, amts...); } bool expectHolding(Env& env, AccountID const& account, None const& value); bool -expectOffers( - Env& env, - AccountID const& account, - std::uint16_t size, - std::vector const& toMatch = {}); +expectOffers(Env& env, AccountID const& account, std::uint16_t size, std::vector const& toMatch = {}); Json::Value ledgerEntryRoot(Env& env, Account const& acct); Json::Value -ledgerEntryState( - Env& env, - Account const& acct_a, - Account const& acct_b, - std::string const& currency); +ledgerEntryState(Env& env, Account const& acct_a, Account const& acct_b, std::string const& currency); Json::Value accountBalance(Env& env, Account const& acct); [[nodiscard]] bool -expectLedgerEntryRoot( - Env& env, - Account const& acct, - STAmount const& expectedValue); +expectLedgerEntryRoot(Env& env, Account const& acct, STAmount const& expectedValue); /* Payment Channel */ /******************************************************************************/ @@ -526,8 +484,7 @@ create( std::optional const& cancelAfter = std::nullopt, std::optional const& dstTag = std::nullopt) { - return create( - account.id(), to.id(), amount, settleDelay, pk, cancelAfter, dstTag); + return create(account.id(), to.id(), amount, settleDelay, pk, cancelAfter, dstTag); } Json::Value @@ -547,10 +504,7 @@ claim( std::optional const& pk = std::nullopt); uint256 -channel( - AccountID const& account, - AccountID const& dst, - std::uint32_t seqProxyValue); +channel(AccountID const& account, AccountID const& dst, std::uint32_t seqProxyValue); inline uint256 channel(Account const& account, Account const& dst, std::uint32_t seqProxyValue) @@ -570,12 +524,7 @@ channelExists(ReadView const& view, uint256 const& chan); /******************************************************************************/ void -n_offers( - Env& env, - std::size_t n, - Account const& account, - STAmount const& in, - STAmount const& out); +n_offers(Env& env, std::size_t n, Account const& account, STAmount const& in, STAmount const& out); /* Pay Strand */ /***************************************************************/ @@ -586,7 +535,7 @@ cpe(Currency const& c); // All path element STPathElement -allpe(AccountID const& a, Issue const& iss); +allPathElements(AccountID const& a, Issue const& iss); /***************************************************************/ /* Check */ @@ -610,10 +559,7 @@ create(A const& account, A const& dest, STAmount const& sendMax) // clang-format on inline Json::Value -create( - jtx::Account const& account, - jtx::Account const& dest, - STAmount const& sendMax) +create(jtx::Account const& account, jtx::Account const& dest, STAmount const& sendMax) { return create(account.id(), dest.id(), sendMax); } @@ -634,7 +580,7 @@ checkMetrics( std::size_t expectedPerLedger, std::uint64_t expectedMinFeeLevel = baseFeeLevel.fee(), std::uint64_t expectedMedFeeLevel = minEscalationFeeLevel.fee(), - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { int line = location.line(); char const* file = location.file_name(); @@ -643,81 +589,148 @@ checkMetrics( auto const metrics = env.app().getTxQ().getMetrics(*env.current()); using namespace std::string_literals; - metrics.referenceFeeLevel == baseFeeLevel - ? test.pass() - : test.fail( - "reference: "s + - std::to_string(metrics.referenceFeeLevel.value()) + "/" + - std::to_string(baseFeeLevel.value()), - file, - line); + metrics.referenceFeeLevel == baseFeeLevel ? test.pass() + : test.fail( + "reference: "s + std::to_string(metrics.referenceFeeLevel.value()) + + "/" + std::to_string(baseFeeLevel.value()), + file, + line); metrics.txCount == expectedCount ? test.pass() - : test.fail( - "txCount: "s + std::to_string(metrics.txCount) + "/" + - std::to_string(expectedCount), - file, - line); + : test.fail("txCount: "s + std::to_string(metrics.txCount) + "/" + std::to_string(expectedCount), file, line); - metrics.txQMaxSize == expectedMaxCount - ? test.pass() - : test.fail( - "txQMaxSize: "s + std::to_string(metrics.txQMaxSize.value_or(0)) + - "/" + std::to_string(expectedMaxCount.value_or(0)), - file, - line); + metrics.txQMaxSize == expectedMaxCount ? test.pass() + : test.fail( + "txQMaxSize: "s + std::to_string(metrics.txQMaxSize.value_or(0)) + + "/" + std::to_string(expectedMaxCount.value_or(0)), + file, + line); metrics.txInLedger == expectedInLedger ? test.pass() : test.fail( - "txInLedger: "s + std::to_string(metrics.txInLedger) + "/" + - std::to_string(expectedInLedger), + "txInLedger: "s + std::to_string(metrics.txInLedger) + "/" + std::to_string(expectedInLedger), file, line); metrics.txPerLedger == expectedPerLedger ? test.pass() : test.fail( - "txPerLedger: "s + std::to_string(metrics.txPerLedger) + "/" + - std::to_string(expectedPerLedger), + "txPerLedger: "s + std::to_string(metrics.txPerLedger) + "/" + std::to_string(expectedPerLedger), file, line); metrics.minProcessingFeeLevel == expectedMin ? test.pass() : test.fail( - "minProcessingFeeLevel: "s + - std::to_string(metrics.minProcessingFeeLevel.value()) + "/" + + "minProcessingFeeLevel: "s + std::to_string(metrics.minProcessingFeeLevel.value()) + "/" + std::to_string(expectedMin.value()), file, line); - metrics.medFeeLevel == expectedMed - ? test.pass() - : test.fail( - "medFeeLevel: "s + std::to_string(metrics.medFeeLevel.value()) + - "/" + std::to_string(expectedMed.value()), - file, - line); + metrics.medFeeLevel == expectedMed ? test.pass() + : test.fail( + "medFeeLevel: "s + std::to_string(metrics.medFeeLevel.value()) + "/" + + std::to_string(expectedMed.value()), + file, + line); auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger - ? expectedMed * expectedInLedger * expectedInLedger / - (expectedPerLedger * expectedPerLedger) + ? expectedMed * expectedInLedger * expectedInLedger / (expectedPerLedger * expectedPerLedger) : metrics.referenceFeeLevel; metrics.openLedgerFeeLevel == expectedCurFeeLevel ? test.pass() : test.fail( - "openLedgerFeeLevel: "s + - std::to_string(metrics.openLedgerFeeLevel.value()) + "/" + + "openLedgerFeeLevel: "s + std::to_string(metrics.openLedgerFeeLevel.value()) + "/" + std::to_string(expectedCurFeeLevel.value()), file, line); } +/* LoanBroker */ +/******************************************************************************/ + +namespace loanBroker { + +Json::Value +set(AccountID const& account, uint256 const& vaultId, std::uint32_t flags = 0); + +// Use "del" because "delete" is a reserved word in C++. +Json::Value +del(AccountID const& account, uint256 const& brokerID, std::uint32_t flags = 0); + +Json::Value +coverDeposit(AccountID const& account, uint256 const& brokerID, STAmount const& amount, std::uint32_t flags = 0); + +Json::Value +coverWithdraw(AccountID const& account, uint256 const& brokerID, STAmount const& amount, std::uint32_t flags = 0); + +// Must specify at least one of loanBrokerID or amount. +Json::Value +coverClawback(AccountID const& account, std::uint32_t flags = 0); + +auto const loanBrokerID = JTxFieldWrapper(sfLoanBrokerID); + +auto const managementFeeRate = valueUnitWrapper(sfManagementFeeRate); + +auto const debtMaximum = simpleField(sfDebtMaximum); + +auto const coverRateMinimum = valueUnitWrapper(sfCoverRateMinimum); + +auto const coverRateLiquidation = valueUnitWrapper(sfCoverRateLiquidation); + +auto const destination = JTxFieldWrapper(sfDestination); + +} // namespace loanBroker + +/* Loan */ +/******************************************************************************/ +namespace loan { + +Json::Value +set(AccountID const& account, uint256 const& loanBrokerID, Number principalRequested, std::uint32_t flags = 0); + +auto const counterparty = JTxFieldWrapper(sfCounterparty); + +// For `CounterPartySignature`, use `sig(sfCounterpartySignature, ...)` + +auto const loanOriginationFee = simpleField(sfLoanOriginationFee); + +auto const loanServiceFee = simpleField(sfLoanServiceFee); + +auto const latePaymentFee = simpleField(sfLatePaymentFee); + +auto const closePaymentFee = simpleField(sfClosePaymentFee); + +auto const overpaymentFee = valueUnitWrapper(sfOverpaymentFee); + +auto const interestRate = valueUnitWrapper(sfInterestRate); + +auto const lateInterestRate = valueUnitWrapper(sfLateInterestRate); + +auto const closeInterestRate = valueUnitWrapper(sfCloseInterestRate); + +auto const overpaymentInterestRate = valueUnitWrapper(sfOverpaymentInterestRate); + +auto const paymentTotal = simpleField(sfPaymentTotal); + +auto const paymentInterval = simpleField(sfPaymentInterval); + +auto const gracePeriod = simpleField(sfGracePeriod); + +Json::Value +manage(AccountID const& account, uint256 const& loanID, std::uint32_t flags); + +Json::Value +del(AccountID const& account, uint256 const& loanID, std::uint32_t flags = 0); + +Json::Value +pay(AccountID const& account, uint256 const& loanID, STAmount const& amount, std::uint32_t flags = 0); + +} // namespace loan + } // namespace jtx } // namespace test -} // namespace ripple - -#endif // RIPPLE_TEST_JTX_TESTHELPERS_H_INCLUDED +} // namespace xrpl diff --git a/src/test/jtx/TestSuite.h b/src/test/jtx/TestSuite.h index d54439d846..1558f68d39 100644 --- a/src/test/jtx/TestSuite.h +++ b/src/test/jtx/TestSuite.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_BASICS_TESTSUITE_H_INCLUDED -#define RIPPLE_BASICS_TESTSUITE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class TestSuite : public beast::unit_test::suite { @@ -67,14 +47,10 @@ public: template bool - expectCollectionEquals( - Collection const& actual, - Collection const& expected, - std::string const& message = "") + expectCollectionEquals(Collection const& actual, Collection const& expected, std::string const& message = "") { auto msg = addPrefix(message); - bool success = expectEquals( - actual.size(), expected.size(), msg + "Sizes are different"); + bool success = expectEquals(actual.size(), expected.size(), msg + "Sizes are different"); using std::begin; using std::end; @@ -84,11 +60,7 @@ public: for (; i != end(actual) && j != end(expected); ++i, ++j, ++k) { - if (!expectEquals( - *i, - *j, - msg + "Elements at " + std::to_string(k) + - " are different.")) + if (!expectEquals(*i, *j, msg + "Elements at " + std::to_string(k) + " are different.")) return false; } @@ -138,6 +110,4 @@ private: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index 26e676c024..a46e98ad50 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED -#define RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED +#pragma once #include @@ -42,20 +22,17 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { -class TrustedPublisherServer - : public std::enable_shared_from_this +class TrustedPublisherServer : public std::enable_shared_from_this { using endpoint_type = boost::asio::ip::tcp::endpoint; using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; - using req_type = - boost::beast::http::request; - using resp_type = - boost::beast::http::response; + using req_type = boost::beast::http::request; + using resp_type = boost::beast::http::response; using error_code = boost::system::error_code; socket_type sock_; @@ -81,21 +58,16 @@ class TrustedPublisherServer load_server_certificate() { sslCtx_.set_password_callback( - [](std::size_t, boost::asio::ssl::context_base::password_purpose) { - return "test"; - }); + [](std::size_t, boost::asio::ssl::context_base::password_purpose) { return "test"; }); sslCtx_.set_options( - boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); - sslCtx_.use_certificate_chain( - boost::asio::buffer(cert().data(), cert().size())); + sslCtx_.use_certificate_chain(boost::asio::buffer(cert().data(), cert().size())); sslCtx_.use_private_key( - boost::asio::buffer(key().data(), key().size()), - boost::asio::ssl::context::file_format::pem); + boost::asio::buffer(key().data(), key().size()), boost::asio::ssl::context::file_format::pem); sslCtx_.use_tmp_dh(boost::asio::buffer(dh().data(), dh().size())); } @@ -121,12 +93,7 @@ public: }; static std::string - makeManifestString( - PublicKey const& pk, - SecretKey const& sk, - PublicKey const& spk, - SecretKey const& ssk, - int seq) + makeManifestString(PublicKey const& pk, SecretKey const& sk, PublicKey const& spk, SecretKey const& ssk, int seq) { STObject st(sfGeneric); st[sfSequence] = seq; @@ -134,18 +101,12 @@ public: st[sfSigningPubKey] = spk; sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk); - sign( - st, - HashPrefix::manifest, - *publicKeyType(pk), - sk, - sfMasterSignature); + sign(st, HashPrefix::manifest, *publicKeyType(pk), sk, sfMasterSignature); Serializer s; st.add(s); - return base64_encode( - std::string(static_cast(s.data()), s.size())); + return base64_encode(std::string(static_cast(s.data()), s.size())); } static Validator @@ -157,12 +118,7 @@ public: return { masterPublic, signingKeys.first, - makeManifestString( - masterPublic, - secret, - signingKeys.first, - signingKeys.second, - 1)}; + makeManifestString(masterPublic, secret, signingKeys.first, signingKeys.second, 1)}; } // TrustedPublisherServer must be accessed through a shared_ptr. @@ -175,16 +131,13 @@ public: boost::asio::io_context& ioc, std::vector const& validators, NetClock::time_point validUntil, - std::vector< - std::pair> const& - futures, + std::vector> const& futures, bool useSSL = false, int version = 1, bool immediateStart = true, int sequence = 1) : sock_{ioc} - , ep_{boost::asio::ip::make_address( - ripple::test::getEnvLocalhostAddr()), + , ep_{boost::asio::ip::make_address(xrpl::test::getEnvLocalhostAddr()), // 0 means let OS pick the port based on what's available 0} , acceptor_{ioc} @@ -193,22 +146,18 @@ public: , publisherPublic_{derivePublicKey(KeyType::ed25519, publisherSecret_)} { auto const keys = randomKeyPair(KeyType::secp256k1); - auto const manifest = makeManifestString( - publisherPublic_, publisherSecret_, keys.first, keys.second, 1); + auto const manifest = makeManifestString(publisherPublic_, publisherSecret_, keys.first, keys.second, 1); std::vector blobInfo; blobInfo.reserve(futures.size() + 1); auto const [data, blob] = [&]() -> std::pair { // Builds the validator list, then encodes it into a blob. std::string data = "{\"sequence\":" + std::to_string(sequence) + - ",\"expiration\":" + - std::to_string(validUntil.time_since_epoch().count()) + - ",\"validators\":["; + ",\"expiration\":" + std::to_string(validUntil.time_since_epoch().count()) + ",\"validators\":["; for (auto const& val : validators) { - data += "{\"validation_public_key\":\"" + - strHex(val.masterPublic) + "\",\"manifest\":\"" + + data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) + "\",\"manifest\":\"" + val.manifest + "\"},"; } data.pop_back(); @@ -221,33 +170,27 @@ public: getList_ = [blob = blob, sig, manifest, version](int interval) { // Build the contents of a version 1 format UNL file std::stringstream l; - l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig - << "\"" << ",\"manifest\":\"" << manifest << "\"" - << ",\"refresh_interval\": " << interval - << ",\"version\":" << version << '}'; + l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig << "\"" << ",\"manifest\":\"" << manifest + << "\"" + << ",\"refresh_interval\": " << interval << ",\"version\":" << version << '}'; return l.str(); }; for (auto const& future : futures) { std::string data = "{\"sequence\":" + std::to_string(++sequence) + - ",\"effective\":" + - std::to_string(future.first.time_since_epoch().count()) + - ",\"expiration\":" + - std::to_string(future.second.time_since_epoch().count()) + - ",\"validators\":["; + ",\"effective\":" + std::to_string(future.first.time_since_epoch().count()) + + ",\"expiration\":" + std::to_string(future.second.time_since_epoch().count()) + ",\"validators\":["; // Use the same set of validators for simplicity for (auto const& val : validators) { - data += "{\"validation_public_key\":\"" + - strHex(val.masterPublic) + "\",\"manifest\":\"" + + data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) + "\",\"manifest\":\"" + val.manifest + "\"},"; } data.pop_back(); data += "]}"; std::string blob = base64_encode(data); - auto const sig = - strHex(sign(keys.first, keys.second, makeSlice(data))); + auto const sig = strHex(sign(keys.first, keys.second, makeSlice(data))); blobInfo.emplace_back(blob, sig); } getList2_ = [blobInfo, manifest, version](int interval) { @@ -257,15 +200,13 @@ public: std::stringstream l; for (auto const& info : blobInfo) { - l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\"" - << info.signature << "\"},"; + l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\"" << info.signature << "\"},"; } std::string blobs = l.str(); blobs.pop_back(); l.str(std::string()); - l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest - << "\"" << ",\"refresh_interval\": " << interval - << ",\"version\":" << (version + 1) << '}'; + l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest << "\"" + << ",\"refresh_interval\": " << interval << ",\"version\":" << (version + 1) << '}'; return l.str(); }; @@ -281,19 +222,15 @@ public: { error_code ec; acceptor_.open(ep_.protocol()); - acceptor_.set_option( - boost::asio::ip::tcp::acceptor::reuse_address(true), ec); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), ec); acceptor_.bind(ep_); acceptor_.listen(boost::asio::socket_base::max_listen_connections); - acceptor_.async_accept( - sock_, - [wp = std::weak_ptr{shared_from_this()}]( - error_code ec) { - if (auto p = wp.lock()) - { - p->on_accept(ec); - } - }); + acceptor_.async_accept(sock_, [wp = std::weak_ptr{shared_from_this()}](error_code ec) { + if (auto p = wp.lock()) + { + p->on_accept(ec); + } + }); } void @@ -503,16 +440,8 @@ private: boost::asio::executor_work_guard work; bool ssl; - lambda( - int id_, - TrustedPublisherServer& self_, - socket_type&& sock_, - bool ssl_) - : id(id_) - , self(self_) - , sock(std::move(sock_)) - , work(sock_.get_executor()) - , ssl(ssl_) + lambda(int id_, TrustedPublisherServer& self_, socket_type&& sock_, bool ssl_) + : id(id_), self(self_), sock(std::move(sock_)), work(sock_.get_executor()), ssl(ssl_) { } @@ -531,15 +460,12 @@ private: static int id_ = 0; std::thread{lambda{++id_, *this, std::move(sock_), useSSL_}}.detach(); - acceptor_.async_accept( - sock_, - [wp = std::weak_ptr{shared_from_this()}]( - error_code ec) { - if (auto p = wp.lock()) - { - p->on_accept(ec); - } - }); + acceptor_.async_accept(sock_, [wp = std::weak_ptr{shared_from_this()}](error_code ec) { + if (auto p = wp.lock()) + { + p->on_accept(ec); + } + }); } void @@ -593,11 +519,9 @@ private: else { int refresh = 5; - constexpr char const* refreshPrefix = - "/validators2/refresh/"; + constexpr char const* refreshPrefix = "/validators2/refresh/"; if (boost::starts_with(path, refreshPrefix)) - refresh = boost::lexical_cast( - path.substr(strlen(refreshPrefix))); + refresh = boost::lexical_cast(path.substr(strlen(refreshPrefix))); res.body() = getList2_(refresh); } } @@ -612,11 +536,9 @@ private: else { int refresh = 5; - constexpr char const* refreshPrefix = - "/validators/refresh/"; + constexpr char const* refreshPrefix = "/validators/refresh/"; if (boost::starts_with(path, refreshPrefix)) - refresh = boost::lexical_cast( - path.substr(strlen(refreshPrefix))); + refresh = boost::lexical_cast(path.substr(strlen(refreshPrefix))); res.body() = getList_(refresh); } } @@ -627,24 +549,19 @@ private: res.insert("Content-Type", "text/example"); // if huge was requested, lie about content length std::uint64_t cl = - boost::starts_with(path, "/textfile/huge") - ? std::numeric_limits::max() - : 1024; + boost::starts_with(path, "/textfile/huge") ? std::numeric_limits::max() : 1024; res.content_length(cl); if (req.method() == http::verb::get) { std::stringstream body; for (auto i = 0; i < 1024; ++i) - body << static_cast(rand_int(32, 126)), - res.body() = body.str(); + body << static_cast(rand_int(32, 126)), res.body() = body.str(); } } else if (boost::starts_with(path, "/sleep/")) { - auto const sleep_sec = - boost::lexical_cast(path.substr(7)); - std::this_thread::sleep_for( - std::chrono::seconds(sleep_sec)); + auto const sleep_sec = boost::lexical_cast(path.substr(7)); + std::this_thread::sleep_for(std::chrono::seconds(sleep_sec)); } else if (boost::starts_with(path, "/redirect")) { @@ -664,12 +581,8 @@ private: } else if (!boost::starts_with(path, "/redirect_nolo")) { - location - << (ssl ? "https://" : "http://") - << local_endpoint() - << (boost::starts_with(path, "/redirect_forever/") - ? path - : "/validators"); + location << (ssl ? "https://" : "http://") << local_endpoint() + << (boost::starts_with(path, "/redirect_forever/") ? path : "/validators"); } if (!location.str().empty()) res.insert("Location", location.str()); @@ -694,8 +607,7 @@ private: res.version(req.version()); res.insert("Server", "TrustedPublisherServer"); res.insert("Content-Type", "text/html"); - res.body() = - std::string{"An internal error occurred"} + e.what(); + res.body() = std::string{"An internal error occurred"} + e.what(); res.prepare_payload(); } @@ -719,20 +631,18 @@ make_TrustedPublisherServer( boost::asio::io_context& ioc, std::vector const& validators, NetClock::time_point validUntil, - std::vector> const& - futures, + std::vector> const& futures, bool useSSL = false, int version = 1, bool immediateStart = true, int sequence = 1) { - auto const r = std::make_shared( - ioc, validators, validUntil, futures, useSSL, version, sequence); + auto const r = + std::make_shared(ioc, validators, validUntil, futures, useSSL, version, sequence); if (immediateStart) r->start(); return r; } } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/jtx/WSClient.h b/src/test/jtx/WSClient.h index 8a479f97c3..86b81ac0ac 100644 --- a/src/test/jtx/WSClient.h +++ b/src/test/jtx/WSClient.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_WSCLIENT_H_INCLUDED -#define RIPPLE_TEST_WSCLIENT_H_INCLUDED +#pragma once #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class WSClient : public AbstractClient @@ -36,15 +16,11 @@ class WSClient : public AbstractClient public: /** Retrieve a message. */ virtual std::optional - getMsg( - std::chrono::milliseconds const& timeout = std::chrono::milliseconds{ - 0}) = 0; + getMsg(std::chrono::milliseconds const& timeout = std::chrono::milliseconds{0}) = 0; /** Retrieve a message that meets the predicate criteria. */ virtual std::optional - findMsg( - std::chrono::milliseconds const& timeout, - std::function pred) = 0; + findMsg(std::chrono::milliseconds const& timeout, std::function pred) = 0; }; /** Returns a client operating through WebSockets/S. */ @@ -56,6 +32,4 @@ makeWSClient( std::unordered_map const& headers = {}); } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/WSClient_test.cpp b/src/test/jtx/WSClient_test.cpp index 431c57558a..206b550b87 100644 --- a/src/test/jtx/WSClient_test.cpp +++ b/src/test/jtx/WSClient_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class WSClient_test : public beast::unit_test::suite @@ -46,7 +27,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(WSClient, jtx, ripple); +BEAST_DEFINE_TESTSUITE(WSClient, jtx, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/account_txn_id.h b/src/test/jtx/account_txn_id.h index 9d419a9f8a..71ac606418 100644 --- a/src/test/jtx/account_txn_id.h +++ b/src/test/jtx/account_txn_id.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ACCOUNT_TXN_ID_H_INCLUDED -#define RIPPLE_TEST_JTX_ACCOUNT_TXN_ID_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -41,5 +21,4 @@ public: }; } // namespace jtx } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/jtx/acctdelete.h b/src/test/jtx/acctdelete.h index 21d00cb727..c081eb92a5 100644 --- a/src/test/jtx/acctdelete.h +++ b/src/test/jtx/acctdelete.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ACCTDELETE_H_INCLUDED -#define RIPPLE_TEST_JTX_ACCTDELETE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -37,14 +17,9 @@ acctdelete(Account const& account, Account const& dest); // the account. If margin is specified, close the ledger so `margin` // more closes are needed void -incLgrSeqForAccDel( - jtx::Env& env, - jtx::Account const& acc, - std::uint32_t margin = 0); +incLgrSeqForAccDel(jtx::Env& env, jtx::Account const& acc, std::uint32_t margin = 0); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index f14a65f6b8..c7b66504d3 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_AMOUNT_H_INCLUDED -#define RIPPLE_TEST_JTX_AMOUNT_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { struct epsilon_multiple @@ -93,8 +73,7 @@ public: PrettyAmount& operator=(PrettyAmount const&) = default; - PrettyAmount(STAmount const& amount, std::string const& name) - : amount_(amount), name_(name) + PrettyAmount(STAmount const& amount, std::string const& name) : amount_(amount), name_(name) { } @@ -102,20 +81,14 @@ public: template PrettyAmount( T v, - std::enable_if_t< - sizeof(T) >= sizeof(int) && std::is_integral_v && - std::is_signed_v>* = nullptr) + std::enable_if_t= sizeof(int) && std::is_integral_v && std::is_signed_v>* = nullptr) : amount_((v > 0) ? v : -v, v < 0) { } /** drops */ template - PrettyAmount( - T v, - std::enable_if_t= sizeof(int) && std::is_unsigned_v>* = - nullptr) - : amount_(v) + PrettyAmount(T v, std::enable_if_t= sizeof(int) && std::is_unsigned_v>* = nullptr) : amount_(v) { } @@ -185,13 +158,11 @@ private: public: template requires std::convertible_to - PrettyAsset(A const& asset, std::uint32_t scale = 1) - : PrettyAsset{Asset{asset}, scale} + PrettyAsset(A const& asset, std::uint32_t scale = 1) : PrettyAsset{Asset{asset}, scale} { } - PrettyAsset(Asset const& asset, std::uint32_t scale = 1) - : asset_(asset), scale_(scale) + PrettyAsset(Asset const& asset, std::uint32_t scale = 1) : asset_(asset), scale_(scale) { } @@ -219,8 +190,7 @@ public: } PrettyAmount - operator()(Number v, Number::rounding_mode rounding = Number::getround()) - const + operator()(Number v, Number::rounding_mode rounding = Number::getround()) const { NumberRoundModeGuard mg(rounding); STAmount amount{asset_, v * scale_}; @@ -232,6 +202,25 @@ public: { return {asset_}; } + + bool + integral() const + { + return asset_.integral(); + } + + bool + native() const + { + return asset_.native(); + } + + template + bool + holds() const + { + return asset_.holds(); + } }; //------------------------------------------------------------------------------ @@ -239,10 +228,9 @@ public: struct BookSpec { AccountID account; - ripple::Currency currency; + xrpl::Currency currency; - BookSpec(AccountID const& account_, ripple::Currency const& currency_) - : account(account_), currency(currency_) + BookSpec(AccountID const& account_, xrpl::Currency const& currency_) : account(account_), currency(currency_) { } }; @@ -261,8 +249,14 @@ struct XRP_t return xrpIssue(); } + bool + integral() const + { + return true; + } + /** Returns an amount of XRP as PrettyAmount, - which is trivially convertable to STAmount + which is trivially convertible to STAmount @param v The number of XRP (not drops) */ @@ -271,11 +265,25 @@ struct XRP_t PrettyAmount operator()(T v) const { - using TOut = std:: - conditional_t, std::int64_t, std::uint64_t>; + using TOut = std::conditional_t, std::int64_t, std::uint64_t>; return {TOut{v} * dropsPerXRP}; } + /** Returns an amount of XRP as PrettyAmount, + which is trivially convertible to STAmount + + @param v The Number of XRP (not drops). May be fractional. + */ + PrettyAmount + operator()(Number v) const + { + auto const c = dropsPerXRP.drops(); + auto const d = std::int64_t(v * c); + if (Number(d) / c != v) + Throw("unrepresentable"); + return {d}; + } + PrettyAmount operator()(double v) const { @@ -368,10 +376,9 @@ class IOU { public: Account account; - ripple::Currency currency; + xrpl::Currency currency; - IOU(Account const& account_, ripple::Currency const& currency_) - : account(account_), currency(currency_) + IOU(Account const& account_, xrpl::Currency const& currency_) : account(account_), currency(currency_) { } @@ -385,6 +392,11 @@ public: { return issue(); } + bool + integral() const + { + return issue().integral(); + } /** Implicit conversion to Issue or Asset. @@ -400,10 +412,7 @@ public: return asset(); } - template < - class T, - class = std::enable_if_t< - sizeof(T) >= sizeof(int) && std::is_arithmetic::value>> + template = sizeof(int) && std::is_arithmetic::value>> PrettyAmount operator()(T v) const { @@ -450,14 +459,13 @@ class MPT { public: std::string name; - ripple::MPTID issuanceID; + xrpl::MPTID issuanceID; - MPT(std::string const& n, ripple::MPTID const& issuanceID_) - : name(n), issuanceID(issuanceID_) + MPT(std::string const& n, xrpl::MPTID const& issuanceID_) : name(n), issuanceID(issuanceID_) { } - ripple::MPTID const& + xrpl::MPTID const& mpt() const { return issuanceID; @@ -465,7 +473,7 @@ public: /** Explicit conversion to MPTIssue or asset. */ - ripple::MPTIssue + xrpl::MPTIssue mptIssue() const { return MPTIssue{issuanceID}; @@ -475,13 +483,18 @@ public: { return mptIssue(); } + bool + integral() const + { + return true; + } /** Implicit conversion to MPTIssue or asset. This allows passing an MPT value where an MPTIssue is expected. */ - operator ripple::MPTIssue() const + operator xrpl::MPTIssue() const { return mptIssue(); } @@ -546,8 +559,7 @@ struct AnyAmount { } - AnyAmount(STAmount const& amount, any_t const*) - : is_any(true), value(amount) + AnyAmount(STAmount const& amount, any_t const*) : is_any(true), value(amount) { } @@ -574,6 +586,4 @@ extern any_t const any; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/attester.h b/src/test/jtx/attester.h index 327fb2e487..6904135f21 100644 --- a/src/test/jtx/attester.h +++ b/src/test/jtx/attester.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ATTESTER_H_INCLUDED -#define RIPPLE_TEST_JTX_ATTESTER_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { class PublicKey; class SecretKey; @@ -62,6 +42,4 @@ sign_create_account_attestation( AccountID const& dst); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/balance.h b/src/test/jtx/balance.h index 0c4a6cca1d..83e2e3ea03 100644 --- a/src/test/jtx/balance.h +++ b/src/test/jtx/balance.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_BALANCE_H_INCLUDED -#define RIPPLE_TEST_JTX_BALANCE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -43,18 +23,15 @@ private: STAmount const value_; public: - balance(Account const& account, none_t) - : none_(true), account_(account), value_(XRP) + balance(Account const& account, none_t) : none_(true), account_(account), value_(XRP) { } - balance(Account const& account, None const& value) - : none_(true), account_(account), value_(value.asset) + balance(Account const& account, None const& value) : none_(true), account_(account), value_(value.asset) { } - balance(Account const& account, STAmount const& value) - : none_(false), account_(account), value_(value) + balance(Account const& account, STAmount const& value) : none_(false), account_(account), value_(value) { } @@ -64,6 +41,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/basic_prop.h b/src/test/jtx/basic_prop.h index a8daafba41..080eecd34b 100644 --- a/src/test/jtx/basic_prop.h +++ b/src/test/jtx/basic_prop.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED -#define RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -60,6 +40,4 @@ struct prop_type : basic_prop } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/batch.h b/src/test/jtx/batch.h index ab235c293f..c11a9fe17e 100644 --- a/src/test/jtx/batch.h +++ b/src/test/jtx/batch.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_BATCH_H_INCLUDED -#define RIPPLE_TEST_JTX_BATCH_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -43,18 +23,11 @@ namespace batch { /** Calculate Batch Fee. */ XRPAmount -calcBatchFee( - jtx::Env const& env, - uint32_t const& numSigners, - uint32_t const& txns = 0); +calcBatchFee(jtx::Env const& env, uint32_t const& numSigners, uint32_t const& txns = 0); /** Batch. */ Json::Value -outer( - jtx::Account const& account, - uint32_t seq, - STAmount const& fee, - std::uint32_t flags); +outer(jtx::Account const& account, uint32_t seq, STAmount const& fee, std::uint32_t flags); /** Adds a new Batch Txn on a JTx and autofills. */ class inner @@ -68,8 +41,7 @@ public: inner( Json::Value const& txn, std::uint32_t const& sequence, - std::optional const& ticket = std::nullopt, - std::optional const& fee = std::nullopt) + std::optional const& ticket = std::nullopt) : txn_(txn), seq_(sequence), ticket_(ticket) { txn_[jss::SigningPubKey] = ""; @@ -137,20 +109,15 @@ public: Account master; std::vector signers; - msig(Account const& masterAccount, std::vector signers_) - : master(masterAccount), signers(std::move(signers_)) + msig(Account const& masterAccount, std::vector signers_) : master(masterAccount), signers(std::move(signers_)) { sortSigners(signers); } template requires std::convertible_to - explicit msig( - Account const& masterAccount, - AccountType&& a0, - Accounts&&... aN) - : master(masterAccount) - , signers{std::forward(a0), std::forward(aN)...} + explicit msig(Account const& masterAccount, AccountType&& a0, Accounts&&... aN) + : master(masterAccount), signers{std::forward(a0), std::forward(aN)...} { sortSigners(signers); } @@ -164,6 +131,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/check.h b/src/test/jtx/check.h index 6bad6b9db5..9a1c6b2d2c 100644 --- a/src/test/jtx/check.h +++ b/src/test/jtx/check.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_CHECK_H_INCLUDED -#define RIPPLE_TEST_JTX_CHECK_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,10 +26,7 @@ struct DeliverMin /** Cash a check requiring that at least a minimum amount be delivered. */ Json::Value -cash( - jtx::Account const& dest, - uint256 const& checkId, - DeliverMin const& atLeast); +cash(jtx::Account const& dest, uint256 const& checkId, DeliverMin const& atLeast); /** Cancel a check. */ Json::Value @@ -63,6 +40,4 @@ using checks = owner_count; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/credentials.h b/src/test/jtx/credentials.h index 1a72e2360d..29ecacb11b 100644 --- a/src/test/jtx/credentials.h +++ b/src/test/jtx/credentials.h @@ -1,43 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_CREDENTIALS_H_INCLUDED -#define RIPPLE_TEST_JTX_CREDENTIALS_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace credentials { inline Keylet -keylet( - test::jtx::Account const& subject, - test::jtx::Account const& issuer, - std::string_view credType) +keylet(test::jtx::Account const& subject, test::jtx::Account const& issuer, std::string_view credType) { - return keylet::credential( - subject.id(), issuer.id(), Slice(credType.data(), credType.size())); + return keylet::credential(subject.id(), issuer.id(), Slice(credType.data(), credType.size())); } // Sets the optional URI. @@ -79,30 +55,16 @@ public: }; Json::Value -create( - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType); +create(jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType); Json::Value -accept( - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType); +accept(jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType); Json::Value -deleteCred( - jtx::Account const& acc, - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType); +deleteCred(jtx::Account const& acc, jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType); Json::Value -ledgerEntry( - jtx::Env& env, - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType); +ledgerEntry(jtx::Env& env, jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType); Json::Value ledgerEntry(jtx::Env& env, std::string const& credIdx); @@ -110,6 +72,4 @@ ledgerEntry(jtx::Env& env, std::string const& credIdx); } // namespace credentials } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/delegate.h b/src/test/jtx/delegate.h index ea368557b8..d965ab580a 100644 --- a/src/test/jtx/delegate.h +++ b/src/test/jtx/delegate.h @@ -1,43 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace delegate { Json::Value -set(jtx::Account const& account, - jtx::Account const& authorize, - std::vector const& permissions); +set(jtx::Account const& account, jtx::Account const& authorize, std::vector const& permissions); Json::Value -entry( - jtx::Env& env, - jtx::Account const& account, - jtx::Account const& authorize); +entry(jtx::Env& env, jtx::Account const& account, jtx::Account const& authorize); struct as { @@ -59,4 +35,4 @@ public: } // namespace delegate } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/delivermin.h b/src/test/jtx/delivermin.h index f8b0da2c19..3edb38ffef 100644 --- a/src/test/jtx/delivermin.h +++ b/src/test/jtx/delivermin.h @@ -1,41 +1,21 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_DELIVERMIN_H_INCLUDED -#define RIPPLE_TEST_JTX_DELIVERMIN_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { /** Sets the DeliverMin on a JTx. */ -class delivermin +class deliver_min { private: STAmount amount_; public: - delivermin(STAmount const& amount) : amount_(amount) + deliver_min(STAmount const& amount) : amount_(amount) { } @@ -45,6 +25,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/deposit.h b/src/test/jtx/deposit.h index a09979b7ac..d7762e9ae3 100644 --- a/src/test/jtx/deposit.h +++ b/src/test/jtx/deposit.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_DEPOSIT_H_INCLUDED -#define RIPPLE_TEST_JTX_DEPOSIT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -34,7 +14,7 @@ namespace deposit { Json::Value auth(Account const& account, Account const& auth); -/** Remove preauthorization for deposit. Invoke as deposit::unauth. */ +/** Remove pre-authorization for deposit. Invoke as deposit::unauth. */ Json::Value unauth(Account const& account, Account const& unauth); @@ -67,20 +47,14 @@ struct AuthorizeCredentials }; Json::Value -authCredentials( - jtx::Account const& account, - std::vector const& auth); +authCredentials(jtx::Account const& account, std::vector const& auth); Json::Value -unauthCredentials( - jtx::Account const& account, - std::vector const& auth); +unauthCredentials(jtx::Account const& account, std::vector const& auth); } // namespace deposit } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/did.h b/src/test/jtx/did.h index 0cffb60e52..9cd98a1324 100644 --- a/src/test/jtx/did.h +++ b/src/test/jtx/did.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_DID_H_INCLUDED -#define RIPPLE_TEST_JTX_DID_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -99,6 +79,4 @@ del(jtx::Account const& account); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/directory.h b/src/test/jtx/directory.h index 67e9900c6c..e9fff35434 100644 --- a/src/test/jtx/directory.h +++ b/src/test/jtx/directory.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_DIRECTORY_H_INCLUDED -#define RIPPLE_TEST_JTX_DIRECTORY_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include #include -namespace ripple::test::jtx { +namespace xrpl::test::jtx { /** Directory operations. */ namespace directory { @@ -56,8 +36,7 @@ bumpLastPage( Env& env, std::uint64_t newLastPage, Keylet directory, - std::function adjust) - -> Expected; + std::function adjust) -> Expected; /// Implementation of adjust for the most common ledger entry, i.e. one where /// page index is stored in sfOwnerNode (and only there). Pass this function @@ -76,6 +55,4 @@ maximumPageIndex(Env const& env) -> std::uint64_t } // namespace directory -} // namespace ripple::test::jtx - -#endif +} // namespace xrpl::test::jtx diff --git a/src/test/jtx/domain.h b/src/test/jtx/domain.h index 4af270c1d0..cb67ce3622 100644 --- a/src/test/jtx/domain.h +++ b/src/test/jtx/domain.h @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -42,4 +23,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/envconfig.h b/src/test/jtx/envconfig.h index 432ef28ff6..dc0c48e064 100644 --- a/src/test/jtx/envconfig.h +++ b/src/test/jtx/envconfig.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ENVCONFIG_H_INCLUDED -#define RIPPLE_TEST_JTX_ENVCONFIG_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { -// frequently used macros defined here for convinience. +// frequently used macros defined here for convenience. #define PORT_WS "port_ws" #define PORT_RPC "port_rpc" #define PORT_PEER "port_peer" @@ -63,7 +43,7 @@ envconfig() /// /// @param modfunc callable function or lambda to modify the default config. /// The first argument to the function must be std::unique_ptr to -/// ripple::Config. The function takes ownership of the unique_ptr and +/// xrpl::Config. The function takes ownership of the unique_ptr and /// relinquishes ownership by returning a unique_ptr. /// /// @param args additional arguments that will be passed to @@ -123,17 +103,11 @@ std::unique_ptr addGrpcConfig(std::unique_ptr); /// /// @param cfg config instance to be modified std::unique_ptr -addGrpcConfigWithSecureGateway( - std::unique_ptr, - std::string const& secureGateway); +addGrpcConfigWithSecureGateway(std::unique_ptr, std::string const& secureGateway); std::unique_ptr -makeConfig( - std::map extraTxQ = {}, - std::map extraVoting = {}); +makeConfig(std::map extraTxQ = {}, std::map extraVoting = {}); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/escrow.h b/src/test/jtx/escrow.h index 483db578b0..c3f535e29f 100644 --- a/src/test/jtx/escrow.h +++ b/src/test/jtx/escrow.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_ESCROW_H_INCLUDED -#define RIPPLE_TEST_JTX_ESCROW_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -68,31 +48,26 @@ rate(Env& env, Account const& account, std::uint32_t const& seq); // A PreimageSha256 fulfillments and its associated condition. std::array const fb1 = {{0xA0, 0x02, 0x80, 0x00}}; -std::array const cb1 = { - {0xA0, 0x25, 0x80, 0x20, 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, - 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, - 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, - 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55, 0x81, 0x01, 0x00}}; +std::array const cb1 = {{0xA0, 0x25, 0x80, 0x20, 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, + 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, + 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55, 0x81, 0x01, 0x00}}; // Another PreimageSha256 fulfillments and its associated condition. -std::array const fb2 = { - {0xA0, 0x05, 0x80, 0x03, 0x61, 0x61, 0x61}}; +std::array const fb2 = {{0xA0, 0x05, 0x80, 0x03, 0x61, 0x61, 0x61}}; -std::array const cb2 = { - {0xA0, 0x25, 0x80, 0x20, 0x98, 0x34, 0x87, 0x6D, 0xCF, 0xB0, - 0x5C, 0xB1, 0x67, 0xA5, 0xC2, 0x49, 0x53, 0xEB, 0xA5, 0x8C, - 0x4A, 0xC8, 0x9B, 0x1A, 0xDF, 0x57, 0xF2, 0x8F, 0x2F, 0x9D, - 0x09, 0xAF, 0x10, 0x7E, 0xE8, 0xF0, 0x81, 0x01, 0x03}}; +std::array const cb2 = {{0xA0, 0x25, 0x80, 0x20, 0x98, 0x34, 0x87, 0x6D, 0xCF, 0xB0, + 0x5C, 0xB1, 0x67, 0xA5, 0xC2, 0x49, 0x53, 0xEB, 0xA5, 0x8C, + 0x4A, 0xC8, 0x9B, 0x1A, 0xDF, 0x57, 0xF2, 0x8F, 0x2F, 0x9D, + 0x09, 0xAF, 0x10, 0x7E, 0xE8, 0xF0, 0x81, 0x01, 0x03}}; // Another PreimageSha256 fulfillment and its associated condition. -std::array const fb3 = { - {0xA0, 0x06, 0x80, 0x04, 0x6E, 0x69, 0x6B, 0x62}}; +std::array const fb3 = {{0xA0, 0x06, 0x80, 0x04, 0x6E, 0x69, 0x6B, 0x62}}; -std::array const cb3 = { - {0xA0, 0x25, 0x80, 0x20, 0x6E, 0x4C, 0x71, 0x45, 0x30, 0xC0, - 0xA4, 0x26, 0x8B, 0x3F, 0xA6, 0x3B, 0x1B, 0x60, 0x6F, 0x2D, - 0x26, 0x4A, 0x2D, 0x85, 0x7B, 0xE8, 0xA0, 0x9C, 0x1D, 0xFD, - 0x57, 0x0D, 0x15, 0x85, 0x8B, 0xD4, 0x81, 0x01, 0x04}}; +std::array const cb3 = {{0xA0, 0x25, 0x80, 0x20, 0x6E, 0x4C, 0x71, 0x45, 0x30, 0xC0, + 0xA4, 0x26, 0x8B, 0x3F, 0xA6, 0x3B, 0x1B, 0x60, 0x6F, 0x2D, + 0x26, 0x4A, 0x2D, 0x85, 0x7B, 0xE8, 0xA0, 0x9C, 0x1D, 0xFD, + 0x57, 0x0D, 0x15, 0x85, 0x8B, 0xD4, 0x81, 0x01, 0x04}}; /** Set the "FinishAfter" time tag on a JTx */ auto const finish_time = JTxFieldWrapper(sfFinishAfter); @@ -109,6 +84,4 @@ auto const fulfillment = JTxFieldWrapper(sfFulfillment); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/fee.h b/src/test/jtx/fee.h index 3e3740b80d..281066f0aa 100644 --- a/src/test/jtx/fee.h +++ b/src/test/jtx/fee.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_FEE_H_INCLUDED -#define RIPPLE_TEST_JTX_FEE_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -59,8 +39,7 @@ public: Throw("fee: not XRP"); } - explicit fee(std::uint64_t amount, bool negative = false) - : fee{STAmount{amount, negative}} + explicit fee(std::uint64_t amount, bool negative = false) : fee{STAmount{amount, negative}} { } @@ -70,6 +49,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/flags.h b/src/test/jtx/flags.h index 8d3fa4f25c..3dde1fa414 100644 --- a/src/test/jtx/flags.h +++ b/src/test/jtx/flags.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_FLAGS_H_INCLUDED -#define RIPPLE_TEST_JTX_FLAGS_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { class flags_helper @@ -131,8 +111,7 @@ private: public: template - flags(Account const& account, Args... args) - : flags_helper(args...), account_(account) + flags(Account const& account, Args... args) : flags_helper(args...), account_(account) { } @@ -148,8 +127,7 @@ private: public: template - nflags(Account const& account, Args... args) - : flags_helper(args...), account_(account) + nflags(Account const& account, Args... args) : flags_helper(args...), account_(account) { } @@ -159,6 +137,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index 999fe73e3f..f920858ea5 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,8 +27,7 @@ AMM::initialTokens() if (!env_.enabled(fixAMMv1_3)) { auto const product = number(asset1_) * number(asset2_); - return (IOUAmount)(product.mantissa() >= 0 ? root2(product) - : root2(-product)); + return (IOUAmount)(product.mantissa() >= 0 ? root2(product) : root2(-product)); } return getLPTokensBalance(); } @@ -78,10 +58,7 @@ AMM::AMM( , msig_(ms) , fee_(fee) , ammAccount_(create(tfee, flags, seq, ter)) - , lptIssue_(ripple::ammLPTIssue( - asset1_.issue().currency, - asset2_.issue().currency, - ammAccount_)) + , lptIssue_(xrpl::ammLPTIssue(asset1_.issue().currency, asset2_.issue().currency, ammAccount_)) , initialLPTokens_(initialTokens()) { } @@ -94,39 +71,12 @@ AMM::AMM( ter const& ter, bool log, bool close) - : AMM(env, - account, - asset1, - asset2, - log, - 0, - 0, - std::nullopt, - std::nullopt, - std::nullopt, - ter, - close) + : AMM(env, account, asset1, asset2, log, 0, 0, std::nullopt, std::nullopt, std::nullopt, ter, close) { } -AMM::AMM( - Env& env, - Account const& account, - STAmount const& asset1, - STAmount const& asset2, - CreateArg const& arg) - : AMM(env, - account, - asset1, - asset2, - arg.log, - arg.tfee, - arg.fee, - arg.flags, - arg.seq, - arg.ms, - arg.err, - arg.close) +AMM::AMM(Env& env, Account const& account, STAmount const& asset1, STAmount const& asset2, CreateArg const& arg) + : AMM(env, account, asset1, asset2, arg.log, arg.tfee, arg.fee, arg.flags, arg.seq, arg.ms, arg.err, arg.close) { } @@ -153,8 +103,7 @@ AMM::create( if (!ter || env_.ter() == tesSUCCESS) { - if (auto const amm = env_.current()->read( - keylet::amm(asset1_.issue(), asset2_.issue()))) + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) { return amm->getAccountID(sfAccount); } @@ -182,52 +131,36 @@ AMM::ammRpcInfo( if (issue1 || issue2) { if (issue1) - jv[jss::asset] = - STIssue(sfAsset, *issue1).getJson(JsonOptions::none); + jv[jss::asset] = STIssue(sfAsset, *issue1).getJson(JsonOptions::none); if (issue2) - jv[jss::asset2] = - STIssue(sfAsset2, *issue2).getJson(JsonOptions::none); + jv[jss::asset2] = STIssue(sfAsset2, *issue2).getJson(JsonOptions::none); } else if (!ammAccount) { - jv[jss::asset] = - STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none); - jv[jss::asset2] = - STIssue(sfAsset2, asset2_.issue()).getJson(JsonOptions::none); + jv[jss::asset] = STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none); + jv[jss::asset2] = STIssue(sfAsset2, asset2_.issue()).getJson(JsonOptions::none); } if (ammAccount) jv[jss::amm_account] = to_string(*ammAccount); } auto jr = - (apiVersion == RPC::apiInvalidVersion - ? env_.rpc("json", "amm_info", to_string(jv)) - : env_.rpc(apiVersion, "json", "amm_info", to_string(jv))); - if (jr.isObject() && jr.isMember(jss::result) && - jr[jss::result].isMember(jss::status)) + (apiVersion == RPC::apiInvalidVersion ? env_.rpc("json", "amm_info", to_string(jv)) + : env_.rpc(apiVersion, "json", "amm_info", to_string(jv))); + if (jr.isObject() && jr.isMember(jss::result) && jr[jss::result].isMember(jss::status)) return jr[jss::result]; return Json::nullValue; } std::tuple -AMM::balances( - Issue const& issue1, - Issue const& issue2, - std::optional const& account) const +AMM::balances(Issue const& issue1, Issue const& issue2, std::optional const& account) const { - if (auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) { auto const ammAccountID = amm->getAccountID(sfAccount); - auto const [asset1Balance, asset2Balance] = ammPoolHolds( - *env_.current(), - ammAccountID, - issue1, - issue2, - FreezeHandling::fhIGNORE_FREEZE, - env_.journal); - auto const lptAMMBalance = account - ? ammLPHolds(*env_.current(), *amm, *account, env_.journal) - : amm->getFieldAmount(sfLPTokenBalance); + auto const [asset1Balance, asset2Balance] = + ammPoolHolds(*env_.current(), ammAccountID, issue1, issue2, FreezeHandling::fhIGNORE_FREEZE, env_.journal); + auto const lptAMMBalance = + account ? ammLPHolds(*env_.current(), *amm, *account, env_.journal) : amm->getFieldAmount(sfLPTokenBalance); return {asset1Balance, asset2Balance, lptAMMBalance}; } return {STAmount{}, STAmount{}, STAmount{}}; @@ -240,25 +173,16 @@ AMM::expectBalances( IOUAmount const& lpt, std::optional const& account) const { - auto const [asset1Balance, asset2Balance, lptAMMBalance] = - balances(asset1.issue(), asset2.issue(), account); - return asset1 == asset1Balance && asset2 == asset2Balance && - lptAMMBalance == STAmount{lpt, lptIssue_}; + auto const [asset1Balance, asset2Balance, lptAMMBalance] = balances(asset1.issue(), asset2.issue(), account); + return asset1 == asset1Balance && asset2 == asset2Balance && lptAMMBalance == STAmount{lpt, lptIssue_}; } IOUAmount AMM::getLPTokensBalance(std::optional const& account) const { if (account) - return accountHolds( - *env_.current(), - *account, - lptIssue_, - FreezeHandling::fhZERO_IF_FROZEN, - env_.journal) - .iou(); - if (auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) + return accountHolds(*env_.current(), *account, lptIssue_, FreezeHandling::fhZERO_IF_FROZEN, env_.journal).iou(); + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) return amm->getFieldAmount(sfLPTokenBalance).iou(); return IOUAmount{0}; } @@ -266,58 +190,45 @@ AMM::getLPTokensBalance(std::optional const& account) const bool AMM::expectLPTokens(AccountID const& account, IOUAmount const& expTokens) const { - if (auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) { - auto const lptAMMBalance = - ammLPHolds(*env_.current(), *amm, account, env_.journal); + auto const lptAMMBalance = ammLPHolds(*env_.current(), *amm, account, env_.journal); return lptAMMBalance == STAmount{expTokens, lptIssue_}; } return false; } bool -AMM::expectAuctionSlot( - std::uint32_t fee, - std::optional timeSlot, - IOUAmount expectedPrice) const +AMM::expectAuctionSlot(std::uint32_t fee, std::optional timeSlot, IOUAmount expectedPrice) const { - return expectAuctionSlot([&](std::uint32_t slotFee, - std::optional slotInterval, - IOUAmount const& slotPrice, - auto const&) { - return slotFee == fee && - // Auction slot might be expired, in which case slotInterval is - // 0 - ((!timeSlot && slotInterval == 0) || slotInterval == timeSlot) && - slotPrice == expectedPrice; - }); + return expectAuctionSlot( + [&](std::uint32_t slotFee, std::optional slotInterval, IOUAmount const& slotPrice, auto const&) { + return slotFee == fee && + // Auction slot might be expired, in which case slotInterval is + // 0 + ((!timeSlot && slotInterval == 0) || slotInterval == timeSlot) && slotPrice == expectedPrice; + }); } bool AMM::expectAuctionSlot(std::vector const& authAccounts) const { - return expectAuctionSlot([&](std::uint32_t, - std::optional, - IOUAmount const&, - STArray const& accounts) { - for (auto const& account : accounts) - { - if (std::find( - authAccounts.cbegin(), - authAccounts.cend(), - account.getAccountID(sfAccount)) == authAccounts.end()) - return false; - } - return true; - }); + return expectAuctionSlot( + [&](std::uint32_t, std::optional, IOUAmount const&, STArray const& accounts) { + for (auto const& account : accounts) + { + if (std::find(authAccounts.cbegin(), authAccounts.cend(), account.getAccountID(sfAccount)) == + authAccounts.end()) + return false; + } + return true; + }); } bool AMM::expectTradingFee(std::uint16_t fee) const { - auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())); + auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())); return amm && (*amm)[sfTradingFee] == fee; } @@ -325,8 +236,7 @@ bool AMM::ammExists() const { return env_.current()->read(keylet::account(ammAccount_)) != nullptr && - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())) != - nullptr; + env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())) != nullptr; } bool @@ -338,23 +248,18 @@ AMM::expectAmmRpcInfo( std::optional const& ledger_index, std::optional const& ammAccount) const { - auto const jv = ammRpcInfo( - account, ledger_index, std::nullopt, std::nullopt, ammAccount); + auto const jv = ammRpcInfo(account, ledger_index, std::nullopt, std::nullopt, ammAccount); return expectAmmInfo(asset1, asset2, balance, jv); } bool -AMM::expectAmmInfo( - STAmount const& asset1, - STAmount const& asset2, - IOUAmount const& balance, - Json::Value const& jvres) const +AMM::expectAmmInfo(STAmount const& asset1, STAmount const& asset2, IOUAmount const& balance, Json::Value const& jvRes) + const { - if (!jvres.isMember(jss::amm)) + if (!jvRes.isMember(jss::amm)) return false; - auto const& jv = jvres[jss::amm]; - if (!jv.isMember(jss::amount) || !jv.isMember(jss::amount2) || - !jv.isMember(jss::lp_token)) + auto const& jv = jvRes[jss::amm]; + if (!jv.isMember(jss::amount) || !jv.isMember(jss::amount2) || !jv.isMember(jss::lp_token)) return false; STAmount asset1Info; if (!amountFromJsonNoThrow(asset1Info, jv[jss::amount])) @@ -368,28 +273,21 @@ AMM::expectAmmInfo( // ammRpcInfo returns unordered assets if (asset1Info.issue() != asset1.issue()) std::swap(asset1Info, asset2Info); - return asset1 == asset1Info && asset2 == asset2Info && - lptBalance == STAmount{balance, lptIssue_}; + return asset1 == asset1Info && asset2 == asset2Info && lptBalance == STAmount{balance, lptIssue_}; } void -AMM::setTokens( - Json::Value& jv, - std::optional> const& assets) +AMM::setTokens(Json::Value& jv, std::optional> const& assets) { if (assets) { - jv[jss::Asset] = - STIssue(sfAsset, assets->first).getJson(JsonOptions::none); - jv[jss::Asset2] = - STIssue(sfAsset, assets->second).getJson(JsonOptions::none); + jv[jss::Asset] = STIssue(sfAsset, assets->first).getJson(JsonOptions::none); + jv[jss::Asset2] = STIssue(sfAsset, assets->second).getJson(JsonOptions::none); } else { - jv[jss::Asset] = - STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none); - jv[jss::Asset2] = - STIssue(sfAsset, asset2_.issue()).getJson(JsonOptions::none); + jv[jss::Asset] = STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none); + jv[jss::Asset2] = STIssue(sfAsset, asset2_.issue()).getJson(JsonOptions::none); } } @@ -421,16 +319,7 @@ AMM::deposit( std::optional const& ter) { return deposit( - account, - tokens, - asset1In, - std::nullopt, - std::nullopt, - flags, - std::nullopt, - std::nullopt, - std::nullopt, - ter); + account, tokens, asset1In, std::nullopt, std::nullopt, flags, std::nullopt, std::nullopt, std::nullopt, ter); } IOUAmount @@ -444,16 +333,7 @@ AMM::deposit( { assert(!(asset2In && maxEP)); return deposit( - account, - std::nullopt, - asset1In, - asset2In, - maxEP, - flags, - std::nullopt, - std::nullopt, - std::nullopt, - ter); + account, std::nullopt, asset1In, asset2In, maxEP, flags, std::nullopt, std::nullopt, std::nullopt, ter); } IOUAmount @@ -480,26 +360,26 @@ AMM::deposit( maxEP->setJson(jv[jss::EPrice]); if (tfee) jv[jss::TradingFee] = *tfee; - std::uint32_t jvflags = 0; + std::uint32_t jvFlags = 0; if (flags) - jvflags = *flags; + jvFlags = *flags; // If including asset1In and asset2In or tokens as // deposit min amounts then must set the flags // explicitly instead of relying on this logic. - if (!(jvflags & tfDepositSubTx)) + if (!(jvFlags & tfDepositSubTx)) { if (tokens && !asset1In) - jvflags |= tfLPToken; + jvFlags |= tfLPToken; else if (tokens && asset1In) - jvflags |= tfOneAssetLPToken; + jvFlags |= tfOneAssetLPToken; else if (asset1In && asset2In) - jvflags |= tfTwoAsset; + jvFlags |= tfTwoAsset; else if (maxEP && asset1In) - jvflags |= tfLimitLPToken; + jvFlags |= tfLimitLPToken; else if (asset1In) - jvflags |= tfSingleAsset; + jvFlags |= tfSingleAsset; } - jv[jss::Flags] = jvflags; + jv[jss::Flags] = jvFlags; return deposit(account, jv, assets, seq, ter); } @@ -546,16 +426,7 @@ AMM::withdraw( std::optional const& flags, std::optional const& ter) { - return withdraw( - account, - tokens, - asset1Out, - std::nullopt, - std::nullopt, - flags, - std::nullopt, - std::nullopt, - ter); + return withdraw(account, tokens, asset1Out, std::nullopt, std::nullopt, flags, std::nullopt, std::nullopt, ter); } IOUAmount @@ -567,16 +438,7 @@ AMM::withdraw( std::optional const& ter) { assert(!(asset2Out && maxEP)); - return withdraw( - account, - std::nullopt, - asset1Out, - asset2Out, - maxEP, - std::nullopt, - std::nullopt, - std::nullopt, - ter); + return withdraw(account, std::nullopt, asset1Out, asset2Out, maxEP, std::nullopt, std::nullopt, std::nullopt, ter); } IOUAmount @@ -603,23 +465,23 @@ AMM::withdraw( STAmount const saMaxEP{*maxEP, lptIssue_}; saMaxEP.setJson(jv[jss::EPrice]); } - std::uint32_t jvflags = 0; + std::uint32_t jvFlags = 0; if (flags) - jvflags = *flags; - if (!(jvflags & tfWithdrawSubTx)) + jvFlags = *flags; + if (!(jvFlags & tfWithdrawSubTx)) { if (tokens && !asset1Out) - jvflags |= tfLPToken; + jvFlags |= tfLPToken; else if (asset1Out && asset2Out) - jvflags |= tfTwoAsset; + jvFlags |= tfTwoAsset; else if (tokens && asset1Out) - jvflags |= tfOneAssetLPToken; + jvFlags |= tfOneAssetLPToken; else if (asset1Out && maxEP) - jvflags |= tfLimitLPToken; + jvFlags |= tfLimitLPToken; else if (asset1Out) - jvflags |= tfSingleAsset; + jvFlags |= tfSingleAsset; } - jv[jss::Flags] = jvflags; + jv[jss::Flags] = jvFlags; return withdraw(account, jv, seq, assets, ter); } @@ -627,15 +489,7 @@ IOUAmount AMM::withdraw(WithdrawArg const& arg) { return withdraw( - arg.account, - arg.tokens, - arg.asset1Out, - arg.asset2Out, - arg.maxEP, - arg.flags, - arg.assets, - arg.seq, - arg.err); + arg.account, arg.tokens, arg.asset1Out, arg.asset2Out, arg.maxEP, arg.flags, arg.assets, arg.seq, arg.err); } void @@ -668,16 +522,12 @@ AMM::vote(VoteArg const& arg) Json::Value AMM::bid(BidArg const& arg) { - if (auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) { - assert( - !env_.current()->rules().enabled(fixInnerObjTemplate) || - amm->isFieldPresent(sfAuctionSlot)); + assert(!env_.current()->rules().enabled(fixInnerObjTemplate) || amm->isFieldPresent(sfAuctionSlot)); if (amm->isFieldPresent(sfAuctionSlot)) { - auto const& auctionSlot = - static_cast(amm->peekAtField(sfAuctionSlot)); + auto const& auctionSlot = static_cast(amm->peekAtField(sfAuctionSlot)); lastPurchasePrice_ = auctionSlot[sfPrice].iou(); } } @@ -685,8 +535,7 @@ AMM::bid(BidArg const& arg) bidMax_ = std::nullopt; Json::Value jv; - jv[jss::Account] = - arg.account ? arg.account->human() : creatorAccount_.human(); + jv[jss::Account] = arg.account ? arg.account->human() : creatorAccount_.human(); setTokens(jv, arg.assets); auto getBid = [&](auto const& bid) { if (std::holds_alternative(bid)) @@ -730,10 +579,7 @@ AMM::bid(BidArg const& arg) } void -AMM::submit( - Json::Value const& jv, - std::optional const& seq, - std::optional const& ter) +AMM::submit(Json::Value const& jv, std::optional const& seq, std::optional const& ter) { if (log_) std::cout << jv.toStyledString(); @@ -763,16 +609,12 @@ AMM::submit( bool AMM::expectAuctionSlot(auto&& cb) const { - if (auto const amm = - env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) + if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) { - assert( - !env_.current()->rules().enabled(fixInnerObjTemplate) || - amm->isFieldPresent(sfAuctionSlot)); + assert(!env_.current()->rules().enabled(fixInnerObjTemplate) || amm->isFieldPresent(sfAuctionSlot)); if (amm->isFieldPresent(sfAuctionSlot)) { - auto const& auctionSlot = - static_cast(amm->peekAtField(sfAuctionSlot)); + auto const& auctionSlot = static_cast(amm->peekAtField(sfAuctionSlot)); if (auctionSlot.isFieldPresent(sfAccount)) { // This could fail in pre-fixInnerObjTemplate tests @@ -780,12 +622,10 @@ AMM::expectAuctionSlot(auto&& cb) const // the failure scenarios. Access as optional // to avoid the failure. auto const slotFee = auctionSlot[~sfDiscountedFee].value_or(0); - auto const slotInterval = ammAuctionTimeSlot( - env_.app().timeKeeper().now().time_since_epoch().count(), - auctionSlot); + auto const slotInterval = + ammAuctionTimeSlot(env_.app().timeKeeper().now().time_since_epoch().count(), auctionSlot); auto const slotPrice = auctionSlot[sfPrice].iou(); - auto const authAccounts = - auctionSlot.getFieldArray(sfAuthAccounts); + auto const authAccounts = auctionSlot.getFieldArray(sfAuthAccounts); return cb(slotFee, slotInterval, slotPrice, authAccounts); } } @@ -851,4 +691,4 @@ ammClawback( } // namespace amm } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/AMMTest.cpp b/src/test/jtx/impl/AMMTest.cpp index 7238cac7eb..18359ad201 100644 --- a/src/test/jtx/impl/AMMTest.cpp +++ b/src/test/jtx/impl/AMMTest.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -107,16 +88,11 @@ AMMTestBase::testAMM( std::optional const& ter, std::vector const& vfeatures) { - testAMM( - std::move(cb), - TestAMMArg{ - .pool = pool, .tfee = tfee, .ter = ter, .features = vfeatures}); + testAMM(std::move(cb), TestAMMArg{.pool = pool, .tfee = tfee, .ter = ter, .features = vfeatures}); } void -AMMTestBase::testAMM( - std::function&& cb, - TestAMMArg const& arg) +AMMTestBase::testAMM(std::function&& cb, TestAMMArg const& arg) { using namespace jtx; @@ -124,14 +100,18 @@ AMMTestBase::testAMM( for (auto const& features : arg.features) { + // Use small Number mantissas for the life of this test. + NumberMantissaScaleGuard const sg{xrpl::MantissaRange::small}; + + // For now, just disable SAV entirely, which locks in the small Number + // mantissas Env env{ *this, - features, + features - featureSingleAssetVault - featureLendingProtocol, arg.noLog ? std::make_unique(&logs) : nullptr}; - auto const [asset1, asset2] = - arg.pool ? *arg.pool : std::make_pair(XRP(10000), USD(10000)); - auto tofund = [&](STAmount const& a) -> STAmount { + auto const [asset1, asset2] = arg.pool ? *arg.pool : std::make_pair(XRP(10000), USD(10000)); + auto toFund = [&](STAmount const& a) -> STAmount { if (a.native()) { auto const defXRP = XRP(30000); @@ -144,8 +124,8 @@ AMMTestBase::testAMM( return defIOU; return a + STAmount{a.issue(), 1000}; }; - auto const toFund1 = tofund(asset1); - auto const toFund2 = tofund(asset2); + auto const toFund1 = toFund(asset1); + auto const toFund2 = toFund(asset2); BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); if (!asset1.native() && !asset2.native()) @@ -155,14 +135,8 @@ AMMTestBase::testAMM( else if (asset2.native()) fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); - AMM ammAlice( - env, - alice, - asset1, - asset2, - CreateArg{.log = false, .tfee = arg.tfee, .err = arg.ter}); - if (BEAST_EXPECT( - ammAlice.expectBalances(asset1, asset2, ammAlice.tokens()))) + AMM ammAlice(env, alice, asset1, asset2, CreateArg{.log = false, .tfee = arg.tfee, .err = arg.ter}); + if (BEAST_EXPECT(ammAlice.expectBalances(asset1, asset2, ammAlice.tokens()))) cb(ammAlice, env); } } @@ -261,8 +235,7 @@ AMMTest::find_paths( std::optional const& saSendMax, std::optional const& saSrcCurrency) { - Json::Value result = find_paths_request( - env, src, dst, saDstAmount, saSendMax, saSrcCurrency); + Json::Value result = find_paths_request(env, src, dst, saDstAmount, saSendMax, saSrcCurrency); BEAST_EXPECT(!result.isMember(jss::error)); STAmount da; @@ -299,4 +272,4 @@ AMMTest::find_paths( } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/Account.cpp b/src/test/jtx/impl/Account.cpp index fe901848f8..31798abdc7 100644 --- a/src/test/jtx/impl/Account.cpp +++ b/src/test/jtx/impl/Account.cpp @@ -1,48 +1,21 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { -std::unordered_map, Account, beast::uhash<>> - Account::cache_; +std::unordered_map, Account, beast::uhash<>> Account::cache_; Account const Account::master( "master", generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")), Account::privateCtorTag{}); -Account::Account( - std::string name, - std::pair const& keys, - Account::privateCtorTag) - : name_(std::move(name)) - , pk_(keys.first) - , sk_(keys.second) - , id_(calcAccountID(pk_)) - , human_(toBase58(id_)) +Account::Account(std::string name, std::pair const& keys, Account::privateCtorTag) + : name_(std::move(name)), pk_(keys.first), sk_(keys.second), id_(calcAccountID(pk_)), human_(toBase58(id_)) { } @@ -73,16 +46,12 @@ Account::fromCache(AcctStringType stringType, std::string name, KeyType type) return r.first->second; } -Account::Account(std::string name, KeyType type) - : Account(fromCache(Account::other, std::move(name), type)) +Account::Account(std::string name, KeyType type) : Account(fromCache(Account::other, std::move(name), type)) { } Account::Account(AcctStringType stringType, std::string base58SeedStr) - : Account(fromCache( - Account::base58Seed, - std::move(base58SeedStr), - KeyType::secp256k1)) + : Account(fromCache(Account::base58Seed, std::move(base58SeedStr), KeyType::secp256k1)) { } @@ -104,4 +73,4 @@ Account::operator[](std::string const& s) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index ce5f6f150c..d8bcec84ee 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -46,8 +27,9 @@ #include #include +#include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -69,24 +51,18 @@ Env::AppBundle::AppBundle( { logs = std::make_unique(suite); // Use kFatal threshold to reduce noise from STObject. - setDebugLogSink( - std::make_unique("Debug", kFatal, suite)); + setDebugLogSink(std::make_unique("Debug", kFatal, suite)); } auto timeKeeper_ = std::make_unique(); timeKeeper = timeKeeper_.get(); // Hack so we don't have to call Config::setup - HTTPClient::initializeSSLContext( - config->SSL_VERIFY_DIR, - config->SSL_VERIFY_FILE, - config->SSL_VERIFY, - debugLog()); - owned = make_Application( - std::move(config), std::move(logs), std::move(timeKeeper_)); + HTTPClient::initializeSSLContext(config->SSL_VERIFY_DIR, config->SSL_VERIFY_FILE, config->SSL_VERIFY, debugLog()); + owned = make_Application(std::move(config), std::move(logs), std::move(timeKeeper_)); app = owned.get(); app->logs().threshold(thresh); if (!app->setup({})) Throw("Env::AppBundle: setup failed"); - timeKeeper->set(app->getLedgerMaster().getClosedLedger()->info().closeTime); + timeKeeper->set(app->getLedgerMaster().getClosedLedger()->header().closeTime); app->start(false /*don't start timers*/); thread = std::thread([&]() { app->run(); }); @@ -119,14 +95,12 @@ Env::closed() } bool -Env::close( - NetClock::time_point closeTime, - std::optional consensusDelay) +Env::close(NetClock::time_point closeTime, std::optional consensusDelay) { // Round up to next distinguishable value using namespace std::chrono_literals; bool res = true; - closeTime += closed()->info().closeTimeResolution - 1s; + closeTime += closed()->header().closeTimeResolution - 1s; timeKeeper().set(closeTime); // Go through the rpc interface unless we need to simulate // a specific consensus delay. @@ -149,7 +123,7 @@ Env::close( res = false; } } - timeKeeper().set(closed()->info().closeTime); + timeKeeper().set(closed()->header().closeTime); return res; } @@ -220,8 +194,7 @@ Env::balance(Account const& account, MPTIssue const& mptIssue) const return {STAmount(mptIssue, 0), account.name()}; // Make it negative - STAmount const amount{ - mptIssue, sle->getFieldU64(sfOutstandingAmount), 0, true}; + STAmount const amount{mptIssue, sle->getFieldU64(sfOutstandingAmount), 0, true}; return {amount, lookup(issuer).name()}; } else @@ -239,9 +212,7 @@ Env::balance(Account const& account, MPTIssue const& mptIssue) const PrettyAmount Env::balance(Account const& account, Asset const& asset) const { - return std::visit( - [&](auto const& issue) { return balance(account, issue); }, - asset.value()); + return std::visit([&](auto const& issue) { return balance(account, issue); }, asset.value()); } PrettyAmount @@ -298,20 +269,12 @@ Env::fund(bool setDefaultRipple, STAmount const& amount, Account const& account) jtx::seq(jtx::autofill), fee(jtx::autofill), sig(jtx::autofill)); - apply( - fset(account, asfDefaultRipple), - jtx::seq(jtx::autofill), - fee(jtx::autofill), - sig(jtx::autofill)); + apply(fset(account, asfDefaultRipple), jtx::seq(jtx::autofill), fee(jtx::autofill), sig(jtx::autofill)); require(flags(account, asfDefaultRipple)); } else { - apply( - pay(master, account, amount), - jtx::seq(jtx::autofill), - fee(jtx::autofill), - sig(jtx::autofill)); + apply(pay(master, account, amount), jtx::seq(jtx::autofill), fee(jtx::autofill), sig(jtx::autofill)); require(nflags(account, asfDefaultRipple)); } require(jtx::balance(account, amount)); @@ -321,11 +284,7 @@ void Env::trust(STAmount const& amount, Account const& account) { auto const start = balance(account); - apply( - jtx::trust(account, amount), - jtx::seq(jtx::autofill), - fee(jtx::autofill), - sig(jtx::autofill)); + apply(jtx::trust(account, amount), jtx::seq(jtx::autofill), fee(jtx::autofill), sig(jtx::autofill)); apply( pay(master, account, drops(current()->fees().base)), jtx::seq(jtx::autofill), @@ -345,8 +304,7 @@ Env::parseResult(Json::Value const& jr) if (!object.isObject()) return; if (object.isMember(jss::error_code)) - parsed.rpcCode = - safe_cast(object[jss::error_code].asInt()); + parsed.rpcCode = safe_cast(object[jss::error_code].asInt()); if (object.isMember(jss::error_message)) parsed.rpcMessage = object[jss::error_message].asString(); if (object.isMember(jss::error)) @@ -373,7 +331,7 @@ Env::parseResult(Json::Value const& jr) } void -Env::submit(JTx const& jt) +Env::submit(JTx const& jt, std::source_location const& loc) { ParsedResult parsedResult; auto const jr = [&]() { @@ -399,11 +357,11 @@ Env::submit(JTx const& jt) return Json::Value(); } }(); - return postconditions(jt, parsedResult, jr); + return postconditions(jt, parsedResult, jr, loc); } void -Env::sign_and_submit(JTx const& jt, Json::Value params) +Env::sign_and_submit(JTx const& jt, Json::Value params, std::source_location const& loc) { auto const account = lookup(jt.jv[jss::Account].asString()); auto const& passphrase = account.name(); @@ -420,9 +378,8 @@ Env::sign_and_submit(JTx const& jt, Json::Value params) // Use the provided parameters, and go straight // to the (RPC) client. assert(params.isObject()); - if (!params.isMember(jss::secret) && !params.isMember(jss::key_type) && - !params.isMember(jss::seed) && !params.isMember(jss::seed_hex) && - !params.isMember(jss::passphrase)) + if (!params.isMember(jss::secret) && !params.isMember(jss::key_type) && !params.isMember(jss::seed) && + !params.isMember(jss::seed_hex) && !params.isMember(jss::passphrase)) { params[jss::secret] = passphrase; } @@ -437,35 +394,29 @@ Env::sign_and_submit(JTx const& jt, Json::Value params) test.expect(parsedResult.ter, "ter uninitialized!"); ter_ = parsedResult.ter.value_or(telENV_RPC_FAILED); - return postconditions(jt, parsedResult, jr); + return postconditions(jt, parsedResult, jr, loc); } void -Env::postconditions( - JTx const& jt, - ParsedResult const& parsed, - Json::Value const& jr) +Env::postconditions(JTx const& jt, ParsedResult const& parsed, Json::Value const& jr, std::source_location const& loc) { - bool bad = !test.expect(parsed.ter, "apply: No ter result!"); + auto const line = jt.testLine ? " (" + to_string(*jt.testLine) + ")" : ""; + auto const locStr = std::string("(") + loc.file_name() + ":" + to_string(loc.line()) + ")"; + bool bad = !test.expect(parsed.ter, "apply " + locStr + ": No ter result!" + line); bad = (jt.ter && parsed.ter && !test.expect( *parsed.ter == *jt.ter, - "apply: Got " + transToken(*parsed.ter) + " (" + - transHuman(*parsed.ter) + "); Expected " + - transToken(*jt.ter) + " (" + transHuman(*jt.ter) + ")")); + "apply " + locStr + ": Got " + transToken(*parsed.ter) + " (" + transHuman(*parsed.ter) + "); Expected " + + transToken(*jt.ter) + " (" + transHuman(*jt.ter) + ")" + line)); using namespace std::string_literals; bad = (jt.rpcCode && !test.expect( - parsed.rpcCode == jt.rpcCode->first && - parsed.rpcMessage == jt.rpcCode->second, - "apply: Got RPC result "s + - (parsed.rpcCode - ? RPC::get_error_info(*parsed.rpcCode).token.c_str() - : "NO RESULT") + - " (" + parsed.rpcMessage + "); Expected " + - RPC::get_error_info(jt.rpcCode->first).token.c_str() + " (" + - jt.rpcCode->second + ")")) || + parsed.rpcCode == jt.rpcCode->first && parsed.rpcMessage == jt.rpcCode->second, + "apply " + locStr + ": Got RPC result "s + + (parsed.rpcCode ? RPC::get_error_info(*parsed.rpcCode).token.c_str() : "NO RESULT") + " (" + + parsed.rpcMessage + "); Expected " + RPC::get_error_info(jt.rpcCode->first).token.c_str() + " (" + + jt.rpcCode->second + ")" + line)) || bad; // If we have an rpcCode (just checked), then the rpcException check is // optional - the 'error' field may not be defined, but if it is, it must @@ -475,11 +426,9 @@ Env::postconditions( !test.expect( (jt.rpcCode && parsed.rpcError.empty()) || (parsed.rpcError == jt.rpcException->first && - (!jt.rpcException->second || - parsed.rpcException == *jt.rpcException->second)), - "apply: Got RPC result "s + parsed.rpcError + " (" + - parsed.rpcException + "); Expected " + jt.rpcException->first + - " (" + jt.rpcException->second.value_or("n/a") + ")")) || + (!jt.rpcException->second || parsed.rpcException == *jt.rpcException->second)), + "apply " + locStr + ": Got RPC result "s + parsed.rpcError + " (" + parsed.rpcException + "); Expected " + + jt.rpcException->first + " (" + jt.rpcException->second.value_or("n/a") + ")" + line)) || bad; if (bad) { @@ -550,9 +499,8 @@ Env::autofill_sig(JTx& jt) // If the sig is still needed, get it here. if (!jt.fill_sig) return; - auto const account = jv.isMember(sfDelegate.jsonName) - ? lookup(jv[sfDelegate.jsonName].asString()) - : lookup(jv[jss::Account].asString()); + auto const account = jv.isMember(sfDelegate.jsonName) ? lookup(jv[sfDelegate.jsonName].asString()) + : lookup(jv[jss::Account].asString()); if (!app().checkSigs()) { jv[jss::SigningPubKey] = strHex(account.pk().slice()); @@ -654,18 +602,14 @@ Env::do_rpc( std::vector const& args, std::unordered_map const& headers) { - auto response = - rpcClient(args, app().config(), app().logs(), apiVersion, headers); + auto response = rpcClient(args, app().config(), app().logs(), apiVersion, headers); - for (unsigned ctr = 0; (ctr < retries_) and (response.first == rpcINTERNAL); - ++ctr) + for (unsigned ctr = 0; (ctr < retries_) and (response.first == rpcINTERNAL); ++ctr) { - JLOG(journal.error()) - << "Env::do_rpc error, retrying, attempt #" << ctr + 1 << " ..."; + JLOG(journal.error()) << "Env::do_rpc error, retrying, attempt #" << ctr + 1 << " ..."; std::this_thread::sleep_for(std::chrono::milliseconds(500)); - response = - rpcClient(args, app().config(), app().logs(), apiVersion, headers); + response = rpcClient(args, app().config(), app().logs(), apiVersion, headers); } return response.second; @@ -689,4 +633,4 @@ Env::disableFeature(uint256 const feature) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/JSONRPCClient.cpp b/src/test/jtx/impl/JSONRPCClient.cpp index a4c5817788..34d0ea2f68 100644 --- a/src/test/jtx/impl/JSONRPCClient.cpp +++ b/src/test/jtx/impl/JSONRPCClient.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -33,7 +14,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class JSONRPCClient : public AbstractClient @@ -54,8 +35,7 @@ class JSONRPCClient : public AbstractClient continue; using namespace boost::asio::ip; if (pp.ip && pp.ip->is_unspecified()) - *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} - : address{address_v4::loopback()}; + *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; if (!pp.port) Throw("Use fixConfigPorts with auto ports"); @@ -166,4 +146,4 @@ makeJSONRPCClient(Config const& cfg, unsigned rpc_version) } } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/Oracle.cpp b/src/test/jtx/impl/Oracle.cpp index 97a31cbb0c..c696011da5 100644 --- a/src/test/jtx/impl/Oracle.cpp +++ b/src/test/jtx/impl/Oracle.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,13 +7,12 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace oracle { -Oracle::Oracle(Env& env, CreateArg const& arg, bool submit) - : env_(env), owner_{}, documentID_{} +Oracle::Oracle(Env& env, CreateArg const& arg, bool submit) : env_(env), owner_{}, documentID_{} { // LastUpdateTime is checked to be in range // {close-maxLastUpdateTimeDelta, close+maxLastUpdateTimeDelta}. @@ -114,20 +94,14 @@ Oracle::expectPrice(DataSeries const& series) const return false; for (auto const& data : series) { - if (std::find_if( - leSeries.begin(), - leSeries.end(), - [&](STObject const& o) -> bool { - auto const& baseAsset = o.getFieldCurrency(sfBaseAsset); - auto const& quoteAsset = - o.getFieldCurrency(sfQuoteAsset); - auto const& price = o.getFieldU64(sfAssetPrice); - auto const& scale = o.getFieldU8(sfScale); - return baseAsset.getText() == std::get<0>(data) && - quoteAsset.getText() == std::get<1>(data) && - price == std::get<2>(data) && - scale == std::get<3>(data); - }) == leSeries.end()) + if (std::find_if(leSeries.begin(), leSeries.end(), [&](STObject const& o) -> bool { + auto const& baseAsset = o.getFieldCurrency(sfBaseAsset); + auto const& quoteAsset = o.getFieldCurrency(sfQuoteAsset); + auto const& price = o.getFieldU64(sfAssetPrice); + auto const& scale = o.getFieldU8(sfScale); + return baseAsset.getText() == std::get<0>(data) && quoteAsset.getText() == std::get<1>(data) && + price == std::get<2>(data) && scale == std::get<3>(data); + }) == leSeries.end()) return false; } return true; @@ -196,8 +170,7 @@ Oracle::set(UpdateArg const& arg) Json::Value jv; if (arg.owner) owner_ = *arg.owner; - if (arg.documentID && - std::holds_alternative(*arg.documentID)) + if (arg.documentID && std::holds_alternative(*arg.documentID)) { documentID_ = std::get(*arg.documentID); jv[jss::OracleDocumentID] = documentID_; @@ -226,17 +199,13 @@ Oracle::set(UpdateArg const& arg) if (arg.lastUpdateTime) { if (std::holds_alternative(*arg.lastUpdateTime)) - jv[jss::LastUpdateTime] = to_string( - testStartTime.count() + - std::get(*arg.lastUpdateTime)); + jv[jss::LastUpdateTime] = to_string(testStartTime.count() + std::get(*arg.lastUpdateTime)); else toJson(jv[jss::LastUpdateTime], *arg.lastUpdateTime); } else jv[jss::LastUpdateTime] = to_string( - duration_cast( - env_.current()->info().closeTime.time_since_epoch()) - .count() + + duration_cast(env_.current()->header().closeTime.time_since_epoch()).count() + epoch_offset.count()); Json::Value dataSeries(Json::arrayValue); auto assetToStr = [](std::string const& s) { @@ -294,11 +263,9 @@ Oracle::ledgerEntry( if (account) { if (std::holds_alternative(*account)) - jvParams[jss::oracle][jss::account] = - to_string(std::get(*account)); + jvParams[jss::oracle][jss::account] = to_string(std::get(*account)); else - jvParams[jss::oracle][jss::account] = - std::get(*account); + jvParams[jss::oracle][jss::account] = std::get(*account); } if (documentID) toJson(jvParams[jss::oracle][jss::oracle_document_id], *documentID); @@ -377,4 +344,4 @@ validDocumentID(AnyValue const& v) } // namespace oracle } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/TestHelpers.cpp b/src/test/jtx/impl/TestHelpers.cpp index 71f44c691e..d89dec456b 100644 --- a/src/test/jtx/impl/TestHelpers.cpp +++ b/src/test/jtx/impl/TestHelpers.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -81,10 +62,7 @@ STPathElement IPE(Issue const& iss) { return STPathElement( - STPathElement::typeCurrency | STPathElement::typeIssuer, - xrpAccount(), - iss.currency, - iss.account); + STPathElement::typeCurrency | STPathElement::typeIssuer, xrpAccount(), iss.currency, iss.account); } /******************************************************************************/ @@ -103,11 +81,7 @@ xrpMinusFee(Env const& env, std::int64_t xrpAmount) }; [[nodiscard]] bool -expectHolding( - Env& env, - AccountID const& account, - STAmount const& value, - bool defaultLimits) +expectHolding(Env& env, AccountID const& account, STAmount const& value, bool defaultLimits) { if (auto const sle = env.le(keylet::line(account, value.issue()))) { @@ -123,8 +97,7 @@ expectHolding( low.setIssuer(accountLow ? account : issue.account); high.setIssuer(accountLow ? issue.account : account); - expectDefaultTrustLine = sle->getFieldAmount(sfLowLimit) == low && - sle->getFieldAmount(sfHighLimit) == high; + expectDefaultTrustLine = sle->getFieldAmount(sfLowLimit) == low && sle->getFieldAmount(sfHighLimit) == high; } auto amount = sle->getFieldAmount(sfBalance); @@ -137,21 +110,13 @@ expectHolding( } [[nodiscard]] bool -expectHolding( - Env& env, - AccountID const& account, - None const&, - Issue const& issue) +expectHolding(Env& env, AccountID const& account, None const&, Issue const& issue) { return !env.le(keylet::line(account, issue)); } [[nodiscard]] bool -expectHolding( - Env& env, - AccountID const& account, - None const&, - MPTIssue const& mptIssue) +expectHolding(Env& env, AccountID const& account, None const&, MPTIssue const& mptIssue) { return !env.le(keylet::mptoken(mptIssue.getMptID(), account)); } @@ -160,37 +125,27 @@ expectHolding( expectHolding(Env& env, AccountID const& account, None const& value) { return std::visit( - [&](auto const& issue) { - return expectHolding(env, account, value, issue); - }, - value.asset.value()); + [&](auto const& issue) { return expectHolding(env, account, value, issue); }, value.asset.value()); } [[nodiscard]] bool -expectOffers( - Env& env, - AccountID const& account, - std::uint16_t size, - std::vector const& toMatch) +expectOffers(Env& env, AccountID const& account, std::uint16_t size, std::vector const& toMatch) { std::uint16_t cnt = 0; std::uint16_t matched = 0; - forEachItem( - *env.current(), account, [&](std::shared_ptr const& sle) { - if (!sle) - return false; - if (sle->getType() == ltOFFER) - { - ++cnt; - if (std::find_if( - toMatch.begin(), toMatch.end(), [&](auto const& a) { - return a.in == sle->getFieldAmount(sfTakerPays) && - a.out == sle->getFieldAmount(sfTakerGets); - }) != toMatch.end()) - ++matched; - } - return true; - }); + forEachItem(*env.current(), account, [&](std::shared_ptr const& sle) { + if (!sle) + return false; + if (sle->getType() == ltOFFER) + { + ++cnt; + if (std::find_if(toMatch.begin(), toMatch.end(), [&](auto const& a) { + return a.in == sle->getFieldAmount(sfTakerPays) && a.out == sle->getFieldAmount(sfTakerGets); + }) != toMatch.end()) + ++matched; + } + return true; + }); return size == cnt && matched == toMatch.size(); } @@ -204,11 +159,7 @@ ledgerEntryRoot(Env& env, Account const& acct) } Json::Value -ledgerEntryState( - Env& env, - Account const& acct_a, - Account const& acct_b, - std::string const& currency) +ledgerEntryState(Env& env, Account const& acct_a, Account const& acct_b, std::string const& currency) { Json::Value jvParams; jvParams[jss::ledger_index] = "current"; @@ -227,10 +178,7 @@ accountBalance(Env& env, Account const& acct) } [[nodiscard]] bool -expectLedgerEntryRoot( - Env& env, - Account const& acct, - STAmount const& expectedValue) +expectLedgerEntryRoot(Env& env, Account const& acct, STAmount const& expectedValue) { return accountBalance(env, acct) == to_string(expectedValue.xrp()); } @@ -305,10 +253,7 @@ claim( } uint256 -channel( - AccountID const& account, - AccountID const& dst, - std::uint32_t seqProxyValue) +channel(AccountID const& account, AccountID const& dst, std::uint32_t seqProxyValue) { auto const k = keylet::payChan(account, dst, seqProxyValue); return k.key; @@ -336,12 +281,7 @@ channelExists(ReadView const& view, uint256 const& chan) /******************************************************************************/ void -n_offers( - Env& env, - std::size_t n, - Account const& account, - STAmount const& in, - STAmount const& out) +n_offers(Env& env, std::size_t n, Account const& account, STAmount const& in, STAmount const& out) { auto const ownerCount = env.le(account)->getFieldU32(sfOwnerCount); for (std::size_t i = 0; i < n; i++) @@ -359,22 +299,134 @@ n_offers( STPathElement cpe(Currency const& c) { - return STPathElement( - STPathElement::typeCurrency, xrpAccount(), c, xrpAccount()); + return STPathElement(STPathElement::typeCurrency, xrpAccount(), c, xrpAccount()); }; // All path element STPathElement -allpe(AccountID const& a, Issue const& iss) +allPathElements(AccountID const& a, Issue const& iss) { return STPathElement( - STPathElement::typeAccount | STPathElement::typeCurrency | - STPathElement::typeIssuer, + STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer, a, iss.currency, iss.account); }; +/* LoanBroker */ +/******************************************************************************/ + +namespace loanBroker { + +Json::Value +set(AccountID const& account, uint256 const& vaultId, uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanBrokerSet; + jv[sfAccount] = to_string(account); + jv[sfVaultID] = to_string(vaultId); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +del(AccountID const& account, uint256 const& brokerID, uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanBrokerDelete; + jv[sfAccount] = to_string(account); + jv[sfLoanBrokerID] = to_string(brokerID); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +coverDeposit(AccountID const& account, uint256 const& brokerID, STAmount const& amount, uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanBrokerCoverDeposit; + jv[sfAccount] = to_string(account); + jv[sfLoanBrokerID] = to_string(brokerID); + jv[sfAmount] = amount.getJson(JsonOptions::none); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +coverWithdraw(AccountID const& account, uint256 const& brokerID, STAmount const& amount, uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanBrokerCoverWithdraw; + jv[sfAccount] = to_string(account); + jv[sfLoanBrokerID] = to_string(brokerID); + jv[sfAmount] = amount.getJson(JsonOptions::none); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +coverClawback(AccountID const& account, std::uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanBrokerCoverClawback; + jv[sfAccount] = to_string(account); + jv[sfFlags] = flags; + return jv; +} + +} // namespace loanBroker + +/* Loan */ +/******************************************************************************/ +namespace loan { + +Json::Value +set(AccountID const& account, uint256 const& loanBrokerID, Number principalRequested, std::uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanSet; + jv[sfAccount] = to_string(account); + jv[sfLoanBrokerID] = to_string(loanBrokerID); + jv[sfPrincipalRequested] = to_string(principalRequested); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +manage(AccountID const& account, uint256 const& loanID, std::uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanManage; + jv[sfAccount] = to_string(account); + jv[sfLoanID] = to_string(loanID); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +del(AccountID const& account, uint256 const& loanID, std::uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanDelete; + jv[sfAccount] = to_string(account); + jv[sfLoanID] = to_string(loanID); + jv[sfFlags] = flags; + return jv; +} + +Json::Value +pay(AccountID const& account, uint256 const& loanID, STAmount const& amount, std::uint32_t flags) +{ + Json::Value jv; + jv[sfTransactionType] = jss::LoanPay; + jv[sfAccount] = to_string(account); + jv[sfLoanID] = to_string(loanID); + jv[sfAmount] = amount.getJson(); + jv[sfFlags] = flags; + return jv; +} + +} // namespace loan } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/WSClient.cpp b/src/test/jtx/impl/WSClient.cpp index a3dc7d9733..c1012b57a4 100644 --- a/src/test/jtx/impl/WSClient.cpp +++ b/src/test/jtx/impl/WSClient.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class WSClientImpl : public WSClient @@ -68,8 +49,7 @@ class WSClientImpl : public WSClient continue; using namespace boost::asio::ip; if (pp.ip && pp.ip->is_unspecified()) - *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} - : address{address_v4::loopback()}; + *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; if (!pp.port) Throw("Use fixConfigPorts with auto ports"); @@ -93,9 +73,7 @@ class WSClientImpl : public WSClient } boost::asio::io_context ios_; - std::optional> - work_; + std::optional> work_; boost::asio::strand strand_; std::thread thread_; boost::asio::ip::tcp::socket stream_; @@ -119,24 +97,21 @@ class WSClientImpl : public WSClient void cleanup() { - boost::asio::post( - ios_, boost::asio::bind_executor(strand_, [this] { - if (!peerClosed_) - { - ws_.async_close( - {}, - boost::asio::bind_executor(strand_, [&](error_code) { - try - { - stream_.cancel(); - } - catch (boost::system::system_error const&) - { - // ignored - } - })); - } - })); + boost::asio::post(ios_, boost::asio::bind_executor(strand_, [this] { + if (!peerClosed_) + { + ws_.async_close({}, boost::asio::bind_executor(strand_, [&](error_code) { + try + { + stream_.cancel(); + } + catch (boost::system::system_error const&) + { + // ignored + } + })); + } + })); work_ = std::nullopt; thread_.join(); } @@ -158,22 +133,16 @@ public: { auto const ep = getEndpoint(cfg, v2); stream_.connect(ep); - ws_.set_option(boost::beast::websocket::stream_base::decorator( - [&](boost::beast::websocket::request_type& req) { + ws_.set_option( + boost::beast::websocket::stream_base::decorator([&](boost::beast::websocket::request_type& req) { for (auto const& h : headers) req.set(h.first, h.second); })); - ws_.handshake( - ep.address().to_string() + ":" + std::to_string(ep.port()), - "/"); + ws_.handshake(ep.address().to_string() + ":" + std::to_string(ep.port()), "/"); ws_.async_read( rb_, boost::asio::bind_executor( - strand_, - std::bind( - &WSClientImpl::on_read_msg, - this, - std::placeholders::_1))); + strand_, std::bind(&WSClientImpl::on_read_msg, this, std::placeholders::_1))); } catch (std::exception&) { @@ -210,9 +179,7 @@ public: ws_.write_some(true, buffer(s)); } - auto jv = findMsg(5s, [&](Json::Value const& jval) { - return jval[jss::type] == jss::response; - }); + auto jv = findMsg(5s, [&](Json::Value const& jval) { return jval[jss::type] == jss::response; }); if (jv) { // Normalize JSON output @@ -248,9 +215,7 @@ public: } std::optional - findMsg( - std::chrono::milliseconds const& timeout, - std::function pred) override + findMsg(std::chrono::milliseconds const& timeout, std::function pred) override { std::shared_ptr m; { @@ -303,10 +268,7 @@ private: } ws_.async_read( rb_, - boost::asio::bind_executor( - strand_, - std::bind( - &WSClientImpl::on_read_msg, this, std::placeholders::_1))); + boost::asio::bind_executor(strand_, std::bind(&WSClientImpl::on_read_msg, this, std::placeholders::_1))); } // Called when the read op terminates @@ -330,4 +292,4 @@ makeWSClient( } } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/account_txn_id.cpp b/src/test/jtx/impl/account_txn_id.cpp index 3e186e7927..ceda6e7b50 100644 --- a/src/test/jtx/impl/account_txn_id.cpp +++ b/src/test/jtx/impl/account_txn_id.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -32,4 +13,4 @@ account_txn_id::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/acctdelete.cpp b/src/test/jtx/impl/acctdelete.cpp index acce912d46..0b87d501dd 100644 --- a/src/test/jtx/impl/acctdelete.cpp +++ b/src/test/jtx/impl/acctdelete.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -44,9 +25,7 @@ void incLgrSeqForAccDel(jtx::Env& env, jtx::Account const& acc, std::uint32_t margin) { using namespace jtx; - auto openLedgerSeq = [](jtx::Env& env) -> std::uint32_t { - return env.current()->seq(); - }; + auto openLedgerSeq = [](jtx::Env& env) -> std::uint32_t { return env.current()->seq(); }; int const delta = [&]() -> int { if (env.seq(acc) + 255 > openLedgerSeq(env)) @@ -61,4 +40,4 @@ incLgrSeqForAccDel(jtx::Env& env, jtx::Account const& acc, std::uint32_t margin) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index a04a6c87d2..73dad7f48e 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -93,15 +74,13 @@ operator<<(std::ostream& os, PrettyAmount const& amount) } else if (amount.value().holds()) { - os << amount.value().getText() << "/" - << to_string(amount.value().issue().currency) << "(" << amount.name() + os << amount.value().getText() << "/" << to_string(amount.value().issue().currency) << "(" << amount.name() << ")"; } else { auto const& mptIssue = amount.value().asset().get(); - os << amount.value().getText() << "/" << to_string(mptIssue) << "(" - << amount.name() << ")"; + os << amount.value().getText() << "/" << to_string(mptIssue) << "(" << amount.name() << ")"; } return os; } @@ -119,8 +98,7 @@ IOU::operator()(epsilon_t) const PrettyAmount IOU::operator()(detail::epsilon_multiple m) const { - return { - STAmount(issue(), safe_cast(m.n), -81), account.name()}; + return {STAmount(issue(), safe_cast(m.n), -81), account.name()}; } std::ostream& @@ -134,4 +112,4 @@ any_t const any{}; } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/attester.cpp b/src/test/jtx/impl/attester.cpp index 91abfc459b..04b2a037c6 100644 --- a/src/test/jtx/impl/attester.cpp +++ b/src/test/jtx/impl/attester.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -41,13 +22,7 @@ sign_claim_attestation( std::optional const& dst) { auto const toSign = Attestations::AttestationClaim::message( - bridge, - sendingAccount, - sendingAmount, - rewardAccount, - wasLockingChainSend, - claimID, - dst); + bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst); return sign(pk, sk, makeSlice(toSign)); } @@ -65,17 +40,10 @@ sign_create_account_attestation( AccountID const& dst) { auto const toSign = Attestations::AttestationCreateAccount::message( - bridge, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccount, - wasLockingChainSend, - createCount, - dst); + bridge, sendingAccount, sendingAmount, rewardAmount, rewardAccount, wasLockingChainSend, createCount, dst); return sign(pk, sk, makeSlice(toSign)); } } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/balance.cpp b/src/test/jtx/impl/balance.cpp index decbd816e1..1ebeeed437 100644 --- a/src/test/jtx/impl/balance.cpp +++ b/src/test/jtx/impl/balance.cpp @@ -1,46 +1,28 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { +#define TEST_EXPECT(cond) env.test.expect(cond, __FILE__, __LINE__) +#define TEST_EXPECTS(cond, reason) \ + ((cond) ? (env.test.pass(), true) : (env.test.fail((reason), __FILE__, __LINE__), false)) + void -doBalance( - Env& env, - AccountID const& account, - bool none, - STAmount const& value, - Issue const& issue) +doBalance(Env& env, AccountID const& account, bool none, STAmount const& value, Issue const& issue) { if (isXRP(issue)) { auto const sle = env.le(keylet::account(account)); if (none) { - env.test.expect(!sle); + TEST_EXPECT(!sle); } - else if (env.test.expect(sle)) + else if (TEST_EXPECT(sle)) { - env.test.expect(sle->getFieldAmount(sfBalance) == value); + TEST_EXPECTS( + sle->getFieldAmount(sfBalance) == value, + sle->getFieldAmount(sfBalance).getText() + " / " + value.getText()); } } else @@ -48,36 +30,31 @@ doBalance( auto const sle = env.le(keylet::line(account, issue)); if (none) { - env.test.expect(!sle); + TEST_EXPECT(!sle); } - else if (env.test.expect(sle)) + else if (TEST_EXPECT(sle)) { auto amount = sle->getFieldAmount(sfBalance); amount.setIssuer(issue.account); if (account > issue.account) amount.negate(); - env.test.expect(amount == value); + TEST_EXPECTS(amount == value, amount.getText()); } } } void -doBalance( - Env& env, - AccountID const& account, - bool none, - STAmount const& value, - MPTIssue const& mptIssue) +doBalance(Env& env, AccountID const& account, bool none, STAmount const& value, MPTIssue const& mptIssue) { auto const sle = env.le(keylet::mptoken(mptIssue.getMptID(), account)); if (none) { - env.test.expect(!sle); + TEST_EXPECT(!sle); } - else if (env.test.expect(sle)) + else if (TEST_EXPECT(sle)) { STAmount const amount{mptIssue, sle->getFieldU64(sfMPTAmount)}; - env.test.expect(amount == value); + TEST_EXPECT(amount == value); } } @@ -85,12 +62,9 @@ void balance::operator()(Env& env) const { return std::visit( - [&](auto const& issue) { - doBalance(env, account_.id(), none_, value_, issue); - }, - value_.asset().value()); + [&](auto const& issue) { doBalance(env, account_.id(), none_, value_, issue); }, value_.asset().value()); } } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/batch.cpp b/src/test/jtx/impl/batch.cpp index 055ed3fb55..3f993ddea1 100644 --- a/src/test/jtx/impl/batch.cpp +++ b/src/test/jtx/impl/batch.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,17 +9,14 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace batch { XRPAmount -calcBatchFee( - test::jtx::Env const& env, - uint32_t const& numSigners, - uint32_t const& txns) +calcBatchFee(test::jtx::Env const& env, uint32_t const& numSigners, uint32_t const& txns) { XRPAmount const feeDrops = env.current()->fees().base; return ((numSigners + 2) * feeDrops) + feeDrops * txns; @@ -46,11 +24,7 @@ calcBatchFee( // Batch. Json::Value -outer( - jtx::Account const& account, - uint32_t seq, - STAmount const& fee, - std::uint32_t flags) +outer(jtx::Account const& account, uint32_t seq, STAmount const& fee, std::uint32_t flags) { Json::Value jv; jv[jss::TransactionType] = jss::Batch; @@ -100,10 +74,8 @@ sig::operator()(Env& env, JTx& jt) const Serializer msg; serializeBatch(msg, stx.getFlags(), stx.getBatchTransactionIDs()); - auto const sig = ripple::sign( - *publicKeyType(e.sig.pk().slice()), e.sig.sk(), msg.slice()); - jo[sfTxnSignature.getJsonName()] = - strHex(Slice{sig.data(), sig.size()}); + auto const sig = xrpl::sign(*publicKeyType(e.sig.pk().slice()), e.sig.sk(), msg.slice()); + jo[sfTxnSignature.getJsonName()] = strHex(Slice{sig.data(), sig.size()}); } } @@ -140,10 +112,8 @@ msig::operator()(Env& env, JTx& jt) const Serializer msg; serializeBatch(msg, stx.getFlags(), stx.getBatchTransactionIDs()); finishMultiSigningData(e.acct.id(), msg); - auto const sig = ripple::sign( - *publicKeyType(e.sig.pk().slice()), e.sig.sk(), msg.slice()); - iso[sfTxnSignature.getJsonName()] = - strHex(Slice{sig.data(), sig.size()}); + auto const sig = xrpl::sign(*publicKeyType(e.sig.pk().slice()), e.sig.sk(), msg.slice()); + iso[sfTxnSignature.getJsonName()] = strHex(Slice{sig.data(), sig.size()}); } } @@ -151,4 +121,4 @@ msig::operator()(Env& env, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/check.cpp b/src/test/jtx/impl/check.cpp index 831bc900e7..22f348aa3f 100644 --- a/src/test/jtx/impl/check.cpp +++ b/src/test/jtx/impl/check.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -42,10 +23,7 @@ cash(jtx::Account const& dest, uint256 const& checkId, STAmount const& amount) // Cash a check requiring that at least a minimum amount be delivered. Json::Value -cash( - jtx::Account const& dest, - uint256 const& checkId, - DeliverMin const& atLeast) +cash(jtx::Account const& dest, uint256 const& checkId, DeliverMin const& atLeast) { Json::Value jv; jv[sfAccount.jsonName] = dest.human(); @@ -70,4 +48,4 @@ cancel(jtx::Account const& dest, uint256 const& checkId) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/creds.cpp b/src/test/jtx/impl/creds.cpp index eae3b9501b..5a9ecfec59 100644 --- a/src/test/jtx/impl/creds.cpp +++ b/src/test/jtx/impl/creds.cpp @@ -1,38 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace credentials { Json::Value -create( - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType) +create(jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType) { Json::Value jv; jv[jss::TransactionType] = jss::CredentialCreate; @@ -45,10 +23,7 @@ create( } Json::Value -accept( - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType) +accept(jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType) { Json::Value jv; jv[jss::TransactionType] = jss::CredentialAccept; @@ -59,11 +34,7 @@ accept( } Json::Value -deleteCred( - jtx::Account const& acc, - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType) +deleteCred(jtx::Account const& acc, jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType) { Json::Value jv; jv[jss::TransactionType] = jss::CredentialDelete; @@ -75,11 +46,7 @@ deleteCred( } Json::Value -ledgerEntry( - jtx::Env& env, - jtx::Account const& subject, - jtx::Account const& issuer, - std::string_view credType) +ledgerEntry(jtx::Env& env, jtx::Account const& subject, jtx::Account const& issuer, std::string_view credType) { Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; @@ -103,4 +70,4 @@ ledgerEntry(jtx::Env& env, std::string const& credIdx) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/delegate.cpp b/src/test/jtx/impl/delegate.cpp index 8ef2fac13d..312a3f2403 100644 --- a/src/test/jtx/impl/delegate.cpp +++ b/src/test/jtx/impl/delegate.cpp @@ -1,36 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace delegate { Json::Value -set(jtx::Account const& account, - jtx::Account const& authorize, - std::vector const& permissions) +set(jtx::Account const& account, jtx::Account const& authorize, std::vector const& permissions) { Json::Value jv; jv[jss::TransactionType] = jss::DelegateSet; @@ -64,4 +43,4 @@ entry(jtx::Env& env, jtx::Account const& account, jtx::Account const& authorize) } // namespace delegate } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/delivermin.cpp b/src/test/jtx/impl/delivermin.cpp index fe9f4e8fe6..a5c1414525 100644 --- a/src/test/jtx/impl/delivermin.cpp +++ b/src/test/jtx/impl/delivermin.cpp @@ -1,36 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { void -delivermin::operator()(Env& env, JTx& jt) const +deliver_min::operator()(Env& env, JTx& jt) const { jt.jv[jss::DeliverMin] = amount_.getJson(JsonOptions::none); } } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/deposit.cpp b/src/test/jtx/impl/deposit.cpp index 5f4ae6bdb3..4a2ecf0139 100644 --- a/src/test/jtx/impl/deposit.cpp +++ b/src/test/jtx/impl/deposit.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -51,9 +32,7 @@ unauth(jtx::Account const& account, jtx::Account const& unauth) // Add DepositPreauth. Json::Value -authCredentials( - jtx::Account const& account, - std::vector const& auth) +authCredentials(jtx::Account const& account, std::vector const& auth) { Json::Value jv; jv[sfAccount.jsonName] = account.human(); @@ -71,9 +50,7 @@ authCredentials( // Remove DepositPreauth. Json::Value -unauthCredentials( - jtx::Account const& account, - std::vector const& auth) +unauthCredentials(jtx::Account const& account, std::vector const& auth) { Json::Value jv; jv[sfAccount.jsonName] = account.human(); @@ -93,4 +70,4 @@ unauthCredentials( } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/dids.cpp b/src/test/jtx/impl/dids.cpp index 1b443a5d9d..bb782bcd43 100644 --- a/src/test/jtx/impl/dids.cpp +++ b/src/test/jtx/impl/dids.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -62,4 +43,4 @@ del(jtx::Account const& account) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/directory.cpp b/src/test/jtx/impl/directory.cpp index 8250c5422e..7231389d1e 100644 --- a/src/test/jtx/impl/directory.cpp +++ b/src/test/jtx/impl/directory.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple::test::jtx { +namespace xrpl::test::jtx { /** Directory operations. */ namespace directory { @@ -31,97 +12,94 @@ bumpLastPage( Env& env, std::uint64_t newLastPage, Keylet directory, - std::function adjust) - -> Expected + std::function adjust) -> Expected { Expected res{}; - env.app().openLedger().modify( - [&](OpenView& view, beast::Journal j) -> bool { - Sandbox sb(&view, tapNONE); + env.app().openLedger().modify([&](OpenView& view, beast::Journal j) -> bool { + Sandbox sb(&view, tapNONE); - // Find the root page - auto sleRoot = sb.peek(directory); - if (!sleRoot) - { - res = Unexpected(DirectoryRootNotFound); - return false; - } + // Find the root page + auto sleRoot = sb.peek(directory); + if (!sleRoot) + { + res = Unexpected(DirectoryRootNotFound); + return false; + } - // Find last page - auto const lastIndex = sleRoot->getFieldU64(sfIndexPrevious); - if (lastIndex == 0) - { - res = Unexpected(DirectoryTooSmall); - return false; - } + // Find last page + auto const lastIndex = sleRoot->getFieldU64(sfIndexPrevious); + if (lastIndex == 0) + { + res = Unexpected(DirectoryTooSmall); + return false; + } - if (sb.exists(keylet::page(directory, newLastPage))) - { - res = Unexpected(DirectoryPageDuplicate); - return false; - } + if (sb.exists(keylet::page(directory, newLastPage))) + { + res = Unexpected(DirectoryPageDuplicate); + return false; + } - if (lastIndex >= newLastPage) - { - res = Unexpected(InvalidLastPage); - return false; - } + if (lastIndex >= newLastPage) + { + res = Unexpected(InvalidLastPage); + return false; + } - auto slePage = sb.peek(keylet::page(directory, lastIndex)); - if (!slePage) + auto slePage = sb.peek(keylet::page(directory, lastIndex)); + if (!slePage) + { + res = Unexpected(DirectoryPageNotFound); + return false; + } + + // Copy its data and delete the page + auto indexes = slePage->getFieldV256(sfIndexes); + auto prevIndex = slePage->at(~sfIndexPrevious); + auto owner = slePage->at(~sfOwner); + sb.erase(slePage); + + // Create new page to replace slePage + auto sleNew = std::make_shared(keylet::page(directory, newLastPage)); + sleNew->setFieldH256(sfRootIndex, directory.key); + sleNew->setFieldV256(sfIndexes, indexes); + if (owner) + sleNew->setAccountID(sfOwner, *owner); + if (prevIndex) + sleNew->setFieldU64(sfIndexPrevious, *prevIndex); + sb.insert(sleNew); + + // Adjust root previous and previous node's next + sleRoot->setFieldU64(sfIndexPrevious, newLastPage); + if (prevIndex.value_or(0) == 0) + sleRoot->setFieldU64(sfIndexNext, newLastPage); + else + { + auto slePrev = sb.peek(keylet::page(directory, *prevIndex)); + if (!slePrev) { res = Unexpected(DirectoryPageNotFound); return false; } + slePrev->setFieldU64(sfIndexNext, newLastPage); + sb.update(slePrev); + } + sb.update(sleRoot); - // Copy its data and delete the page - auto indexes = slePage->getFieldV256(sfIndexes); - auto prevIndex = slePage->at(~sfIndexPrevious); - auto owner = slePage->at(~sfOwner); - sb.erase(slePage); - - // Create new page to replace slePage - auto sleNew = - std::make_shared(keylet::page(directory, newLastPage)); - sleNew->setFieldH256(sfRootIndex, directory.key); - sleNew->setFieldV256(sfIndexes, indexes); - if (owner) - sleNew->setAccountID(sfOwner, *owner); - if (prevIndex) - sleNew->setFieldU64(sfIndexPrevious, *prevIndex); - sb.insert(sleNew); - - // Adjust root previous and previous node's next - sleRoot->setFieldU64(sfIndexPrevious, newLastPage); - if (prevIndex.value_or(0) == 0) - sleRoot->setFieldU64(sfIndexNext, newLastPage); - else + // Fixup page numbers in the objects referred by indexes + if (adjust) + for (auto const key : indexes) { - auto slePrev = sb.peek(keylet::page(directory, *prevIndex)); - if (!slePrev) + if (!adjust(sb, key, newLastPage)) { - res = Unexpected(DirectoryPageNotFound); + res = Unexpected(AdjustmentError); return false; } - slePrev->setFieldU64(sfIndexNext, newLastPage); - sb.update(slePrev); } - sb.update(sleRoot); - // Fixup page numbers in the objects referred by indexes - if (adjust) - for (auto const key : indexes) - { - if (!adjust(sb, key, newLastPage)) - { - res = Unexpected(AdjustmentError); - return false; - } - } - - sb.apply(view); - return true; - }); + sb.apply(view); + return true; + }); return res; } @@ -142,4 +120,4 @@ adjustOwnerNode(ApplyView& view, uint256 key, std::uint64_t page) } // namespace directory -} // namespace ripple::test::jtx +} // namespace xrpl::test::jtx diff --git a/src/test/jtx/impl/domain.cpp b/src/test/jtx/impl/domain.cpp index 51adb4ce98..91568783d2 100644 --- a/src/test/jtx/impl/domain.cpp +++ b/src/test/jtx/impl/domain.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -33,4 +14,4 @@ domain::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index 624036196d..1def778c69 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { std::atomic envUseIPv4{false}; @@ -113,8 +94,7 @@ std::unique_ptr validator(std::unique_ptr cfg, std::string const& seed) { // If the config has valid validation keys then we run as a validator. - cfg->section(SECTION_VALIDATION_SEED) - .append(std::vector{seed.empty() ? defaultseed : seed}); + cfg->section(SECTION_VALIDATION_SEED).append(std::vector{seed.empty() ? defaultseed : seed}); return cfg; } @@ -127,9 +107,7 @@ addGrpcConfig(std::unique_ptr cfg) } std::unique_ptr -addGrpcConfigWithSecureGateway( - std::unique_ptr cfg, - std::string const& secureGateway) +addGrpcConfigWithSecureGateway(std::unique_ptr cfg, std::string const& secureGateway) { (*cfg)[SECTION_PORT_GRPC].set("ip", getEnvLocalhostAddr()); @@ -141,9 +119,7 @@ addGrpcConfigWithSecureGateway( } std::unique_ptr -makeConfig( - std::map extraTxQ, - std::map extraVoting) +makeConfig(std::map extraTxQ, std::map extraVoting) { auto p = test::jtx::envconfig(); auto& section = p->section("transaction_queue"); @@ -175,4 +151,4 @@ makeConfig( } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/escrow.cpp b/src/test/jtx/impl/escrow.cpp index a1ec6a3c5e..067c304178 100644 --- a/src/test/jtx/impl/escrow.cpp +++ b/src/test/jtx/impl/escrow.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -70,7 +51,7 @@ rate(Env& env, Account const& account, std::uint32_t const& seq) { auto const sle = env.le(keylet::escrow(account.id(), seq)); if (sle->isFieldPresent(sfTransferRate)) - return ripple::Rate((*sle)[sfTransferRate]); + return xrpl::Rate((*sle)[sfTransferRate]); return Rate{0}; } @@ -79,4 +60,4 @@ rate(Env& env, Account const& account, std::uint32_t const& seq) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/fee.cpp b/src/test/jtx/impl/fee.cpp index a58105a85f..2b1ac6c398 100644 --- a/src/test/jtx/impl/fee.cpp +++ b/src/test/jtx/impl/fee.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -40,4 +21,4 @@ fee::operator()(Env& env, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/flags.cpp b/src/test/jtx/impl/flags.cpp index a6ddfc1d71..11e7831f55 100644 --- a/src/test/jtx/impl/flags.cpp +++ b/src/test/jtx/impl/flags.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -64,4 +45,4 @@ nflags::operator()(Env& env) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/invoice_id.cpp b/src/test/jtx/impl/invoice_id.cpp index b00eb993a4..6d6dae0fbf 100644 --- a/src/test/jtx/impl/invoice_id.cpp +++ b/src/test/jtx/impl/invoice_id.cpp @@ -1,26 +1,6 @@ - -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -33,4 +13,4 @@ invoice_id::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/jtx_json.cpp b/src/test/jtx/impl/jtx_json.cpp index b76ad2ef0c..c39503d038 100644 --- a/src/test/jtx/impl/jtx_json.cpp +++ b/src/test/jtx/impl/jtx_json.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -51,4 +32,4 @@ json::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/last_ledger_sequence.cpp b/src/test/jtx/impl/last_ledger_sequence.cpp index 4b4368429f..5f29282ad6 100644 --- a/src/test/jtx/impl/last_ledger_sequence.cpp +++ b/src/test/jtx/impl/last_ledger_sequence.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -31,4 +12,4 @@ last_ledger_seq::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/ledgerStateFixes.cpp b/src/test/jtx/impl/ledgerStateFixes.cpp index b7df78dd11..f1e6b6eda1 100644 --- a/src/test/jtx/impl/ledgerStateFixes.cpp +++ b/src/test/jtx/impl/ledgerStateFixes.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,4 +27,4 @@ nftPageLinks(jtx::Account const& acct, jtx::Account const& owner) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/memo.cpp b/src/test/jtx/impl/memo.cpp index 1214ec2a2c..e503b9a073 100644 --- a/src/test/jtx/impl/memo.cpp +++ b/src/test/jtx/impl/memo.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -36,7 +17,7 @@ memo::operator()(Env&, JTx& jt) const } void -memodata::operator()(Env&, JTx& jt) const +memo_data::operator()(Env&, JTx& jt) const { auto& jv = jt.jv; auto& ma = jv["Memos"]; @@ -46,7 +27,7 @@ memodata::operator()(Env&, JTx& jt) const } void -memoformat::operator()(Env&, JTx& jt) const +memo_format::operator()(Env&, JTx& jt) const { auto& jv = jt.jv; auto& ma = jv["Memos"]; @@ -56,7 +37,7 @@ memoformat::operator()(Env&, JTx& jt) const } void -memotype::operator()(Env&, JTx& jt) const +memo_type::operator()(Env&, JTx& jt) const { auto& jv = jt.jv; auto& ma = jv["Memos"]; @@ -65,39 +46,6 @@ memotype::operator()(Env&, JTx& jt) const m["MemoType"] = strHex(s_); } -void -memondata::operator()(Env&, JTx& jt) const -{ - auto& jv = jt.jv; - auto& ma = jv["Memos"]; - auto& mi = ma[ma.size()]; - auto& m = mi["Memo"]; - m["MemoFormat"] = strHex(format_); - m["MemoType"] = strHex(type_); -} - -void -memonformat::operator()(Env&, JTx& jt) const -{ - auto& jv = jt.jv; - auto& ma = jv["Memos"]; - auto& mi = ma[ma.size()]; - auto& m = mi["Memo"]; - m["MemoData"] = strHex(data_); - m["MemoType"] = strHex(type_); -} - -void -memontype::operator()(Env&, JTx& jt) const -{ - auto& jv = jt.jv; - auto& ma = jv["Memos"]; - auto& mi = ma[ma.size()]; - auto& m = mi["Memo"]; - m["MemoData"] = strHex(data_); - m["MemoFormat"] = strHex(format_); -} - } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index a12561b346..049eb5c8bc 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -1,52 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include +#include #include #include #include -#include "test/jtx/mpt.h" #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { -ripple::Buffer -generatePlaceholderCiphertext() -{ - Buffer buf(ecGamalEncryptedTotalLength); - - buf.data()[0] = 0x02; - buf.data()[ecGamalEncryptedLength] = 0x02; - - buf.data()[ecGamalEncryptedLength - 1] = 0x01; - buf.data()[ecGamalEncryptedTotalLength - 1] = 0x01; - - return buf; -} - void mptflags::operator()(Env& env) const { @@ -79,16 +46,16 @@ MPTTester::makeHolders(std::vector const& holders) } MPTTester::MPTTester(Env& env, Account const& issuer, MPTInit const& arg) - : env_(env) - , issuer_(issuer) - , holders_(makeHolders(arg.holders)) - , close_(arg.close) + : env_(env), issuer_(issuer), holders_(makeHolders(arg.holders)), auditor_(arg.auditor), close_(arg.close) { if (arg.fund) { env_.fund(arg.xrp, issuer_); for (auto it : holders_) env_.fund(arg.xrpHolders, it.second); + + if (arg.auditor) + env_.fund(arg.xrp, *arg.auditor); } if (close_) env.close(); @@ -101,18 +68,64 @@ MPTTester::MPTTester(Env& env, Account const& issuer, MPTInit const& arg) Throw("Issuer can't be holder"); env_.require(owners(it.second, 0)); } + + if (arg.auditor) + env_.require(owners(*arg.auditor, 0)); } + if (arg.create) + create(*arg.create); } -void -MPTTester::create(MPTCreate const& arg) +MPTTester::MPTTester(Env& env, Account const& issuer, MPTID const& id, std::vector const& holders, bool close) + : env_(env), issuer_(issuer), holders_(makeHolders(holders)), id_(id), close_(close) { - if (id_) - Throw("MPT can't be reused"); - id_ = makeMptID(env_.seq(issuer_), issuer_); +} + +static MPTCreate +makeMPTCreate(MPTInitDef const& arg) +{ + if (arg.pay) + return { + .maxAmt = arg.maxAmt, + .transferFee = arg.transferFee, + .pay = {{arg.holders, *arg.pay}}, + .flags = arg.flags, + .authHolder = arg.authHolder}; + return { + .maxAmt = arg.maxAmt, + .transferFee = arg.transferFee, + .authorize = arg.holders, + .flags = arg.flags, + .authHolder = arg.authHolder}; +} + +MPTTester::MPTTester(MPTInitDef const& arg) + : MPTTester{ + arg.env, + arg.issuer, + MPTInit{ + .auditor = arg.auditor, + .fund = arg.fund, + .close = arg.close, + .create = makeMPTCreate(arg), + }} +{ +} + +MPTTester::operator MPT() const +{ + if (!id_) + Throw("MPT has not been created"); + return MPT("", *id_); +} + +Json::Value +MPTTester::createJV(MPTCreate const& arg) +{ + if (!arg.issuer) + Throw("MPTTester::createJV: issuer is not set"); Json::Value jv; - jv[sfAccount] = issuer_.human(); - jv[sfTransactionType] = jss::MPTokenIssuanceCreate; + jv[sfAccount] = arg.issuer->human(); if (arg.assetScale) jv[sfAssetScale] = *arg.assetScale; if (arg.transferFee) @@ -125,36 +138,86 @@ MPTTester::create(MPTCreate const& arg) jv[sfDomainID] = to_string(*arg.domainID); if (arg.mutableFlags) jv[sfMutableFlags] = *arg.mutableFlags; + jv[sfTransactionType] = jss::MPTokenIssuanceCreate; + + return jv; +} + +void +MPTTester::create(MPTCreate const& arg) +{ + if (id_) + Throw("MPT can't be reused"); + id_ = makeMptID(env_.seq(issuer_), issuer_); + Json::Value jv = createJV( + {.issuer = issuer_, + .maxAmt = arg.maxAmt, + .assetScale = arg.assetScale, + .transferFee = arg.transferFee, + .metadata = arg.metadata, + .mutableFlags = arg.mutableFlags, + .domainID = arg.domainID}); if (submit(arg, jv) != tesSUCCESS) { // Verify issuance doesn't exist - env_.require(requireAny([&]() -> bool { - return env_.le(keylet::mptIssuance(*id_)) == nullptr; - })); + env_.require(requireAny([&]() -> bool { return env_.le(keylet::mptIssuance(*id_)) == nullptr; })); id_.reset(); } else + { env_.require(mptflags(*this, arg.flags.value_or(0))); + auto authAndPay = [&](auto const& accts, auto const&& getAcct) { + for (auto const& it : accts) + { + authorize({.account = getAcct(it)}); + if ((arg.flags.value_or(0) & tfMPTRequireAuth) && arg.authHolder) + authorize({.account = issuer_, .holder = getAcct(it)}); + if (arg.pay && arg.pay->first.empty()) + pay(issuer_, getAcct(it), arg.pay->second); + } + if (arg.pay) + { + for (auto const& p : arg.pay->first) + pay(issuer_, p, arg.pay->second); + } + }; + if (arg.authorize) + { + if (arg.authorize->empty()) + authAndPay(holders_, [](auto const& it) { return it.second; }); + else + authAndPay(*arg.authorize, [](auto const& it) { return it; }); + } + else if (arg.pay) + { + if (arg.pay->first.empty()) + authAndPay(holders_, [](auto const& it) { return it.second; }); + else + authAndPay(arg.pay->first, [](auto const& it) { return it; }); + } + } +} + +Json::Value +MPTTester::destroyJV(MPTDestroy const& arg) +{ + Json::Value jv; + if (!arg.issuer || !arg.id) + Throw("MPTTester::destroyJV: issuer/id is not set"); + jv[sfAccount] = arg.issuer->human(); + jv[sfMPTokenIssuanceID] = to_string(*arg.id); + jv[sfTransactionType] = jss::MPTokenIssuanceDestroy; + + return jv; } void MPTTester::destroy(MPTDestroy const& arg) { - Json::Value jv; - if (arg.issuer) - jv[sfAccount] = arg.issuer->human(); - else - jv[sfAccount] = issuer_.human(); - if (arg.id) - jv[sfMPTokenIssuanceID] = to_string(*arg.id); - else - { - if (!id_) - Throw("MPT has not been created"); - jv[sfMPTokenIssuanceID] = to_string(*id_); - } - jv[sfTransactionType] = jss::MPTokenIssuanceDestroy; + if (!arg.id && !id_) + Throw("MPT has not been created"); + Json::Value jv = destroyJV({.issuer = arg.issuer ? arg.issuer : issuer_, .id = arg.id ? arg.id : id_}); submit(arg, jv); } @@ -167,25 +230,31 @@ MPTTester::holder(std::string const& holder_) const return it->second; } +Json::Value +MPTTester::authorizeJV(MPTAuthorize const& arg) +{ + Json::Value jv; + if (!arg.account || !arg.id) + Throw("MPTTester::authorizeJV: account/id is not set"); + jv[sfAccount] = arg.account->human(); + jv[sfMPTokenIssuanceID] = to_string(*arg.id); + if (arg.holder) + jv[sfHolder] = arg.holder->human(); + jv[sfTransactionType] = jss::MPTokenAuthorize; + + return jv; +} + void MPTTester::authorize(MPTAuthorize const& arg) { - Json::Value jv; - if (arg.account) - jv[sfAccount] = arg.account->human(); - else - jv[sfAccount] = issuer_.human(); - jv[sfTransactionType] = jss::MPTokenAuthorize; - if (arg.id) - jv[sfMPTokenIssuanceID] = to_string(*arg.id); - else - { - if (!id_) - Throw("MPT has not been created"); - jv[sfMPTokenIssuanceID] = to_string(*id_); - } - if (arg.holder) - jv[sfHolder] = arg.holder->human(); + if (!arg.id && !id_) + Throw("MPT has not been created"); + Json::Value jv = authorizeJV({ + .account = arg.account ? arg.account : issuer_, + .holder = arg.holder, + .id = arg.id ? arg.id : id_, + }); if (auto const result = submit(arg, jv); result == tesSUCCESS) { // Issuer authorizes @@ -197,8 +266,7 @@ MPTTester::authorize(MPTAuthorize const& arg) env_.require(mptflags(*this, flags, arg.holder)); // issuer authorizes the holder else - env_.require( - mptflags(*this, flags | lsfMPTAuthorized, arg.holder)); + env_.require(mptflags(*this, flags | lsfMPTAuthorized, arg.holder)); } // Holder authorizes else if (arg.flags.value_or(0) != tfMPTUnauthorize) @@ -211,54 +279,56 @@ MPTTester::authorize(MPTAuthorize const& arg) else { // Verify that the MPToken doesn't exist. - forObject( - [&](SLEP const& sle) { return env_.test.BEAST_EXPECT(!sle); }, - arg.account); + forObject([&](SLEP const& sle) { return env_.test.BEAST_EXPECT(!sle); }, arg.account); } } - else if ( - arg.account && *arg.account != issuer_ && - arg.flags.value_or(0) != tfMPTUnauthorize && id_) + else if (arg.account && *arg.account != issuer_ && arg.flags.value_or(0) != tfMPTUnauthorize && id_) { if (result == tecDUPLICATE) { // Verify that MPToken already exists - env_.require(requireAny([&]() -> bool { - return env_.le(keylet::mptoken(*id_, arg.account->id())) != - nullptr; - })); + env_.require( + requireAny([&]() -> bool { return env_.le(keylet::mptoken(*id_, arg.account->id())) != nullptr; })); } else { // Verify MPToken doesn't exist if holder failed authorizing(unless // it already exists) - env_.require(requireAny([&]() -> bool { - return env_.le(keylet::mptoken(*id_, arg.account->id())) == - nullptr; - })); + env_.require( + requireAny([&]() -> bool { return env_.le(keylet::mptoken(*id_, arg.account->id())) == nullptr; })); } } } void -MPTTester::set(MPTSet const& arg) +MPTTester::authorizeHolders(Holders const& holders) +{ + for (auto const& holder : holders) + { + authorize({.account = holder}); + } +} + +Json::Value +MPTTester::setJV(MPTSet const& arg) { Json::Value jv; - if (arg.account) - jv[sfAccount] = arg.account->human(); - else - jv[sfAccount] = issuer_.human(); - jv[sfTransactionType] = jss::MPTokenIssuanceSet; - if (arg.id) - jv[sfMPTokenIssuanceID] = to_string(*arg.id); - else - { - if (!id_) - Throw("MPT has not been created"); - jv[sfMPTokenIssuanceID] = to_string(*id_); - } + if (!arg.account || !arg.id) + Throw("MPTTester::setJV: account and/or id is not set"); + jv[sfAccount] = arg.account->human(); + jv[sfMPTokenIssuanceID] = to_string(*arg.id); if (arg.holder) - jv[sfHolder] = arg.holder->human(); + { + std::visit( + [&jv](T const& holder) { + if constexpr (std::is_same_v) + jv[sfHolder] = holder.human(); + else if constexpr (std::is_same_v) + jv[sfHolder] = toBase58(holder); + }, + *arg.holder); + } + if (arg.delegate) jv[sfDelegate] = arg.delegate->human(); if (arg.domainID) @@ -269,14 +339,36 @@ MPTTester::set(MPTSet const& arg) jv[sfTransferFee] = *arg.transferFee; if (arg.metadata) jv[sfMPTokenMetadata] = strHex(*arg.metadata); - if (arg.pubKey) - jv[sfIssuerElGamalPublicKey] = strHex(*arg.pubKey); + if (arg.issuerPubKey) + jv[sfIssuerElGamalPublicKey] = strHex(*arg.issuerPubKey); + if (arg.auditorPubKey) + jv[sfAuditorElGamalPublicKey] = strHex(*arg.auditorPubKey); + jv[sfTransactionType] = jss::MPTokenIssuanceSet; + + return jv; +} + +void +MPTTester::set(MPTSet const& arg) +{ + if (!arg.id && !id_) + Throw("MPT has not been created"); + Json::Value jv = setJV( + {.account = arg.account ? arg.account : issuer_, + .holder = arg.holder, + .id = arg.id ? arg.id : id_, + .mutableFlags = arg.mutableFlags, + .transferFee = arg.transferFee, + .metadata = arg.metadata, + .delegate = arg.delegate, + .domainID = arg.domainID, + .issuerPubKey = arg.issuerPubKey, + .auditorPubKey = arg.auditorPubKey}); if (submit(arg, jv) == tesSUCCESS) { - if ((arg.flags || arg.mutableFlags)) + if ((arg.flags.value_or(0) || arg.mutableFlags)) { - auto require = [&](std::optional const& holder, - bool unchanged) { + auto require = [&](std::optional const& holder, bool unchanged) { auto flags = getFlags(holder); if (!unchanged) { @@ -319,24 +411,52 @@ MPTTester::set(MPTSet const& arg) flags |= lsfMPTCanTransfer; else if (*arg.mutableFlags & tmfMPTClearCanTransfer) flags &= ~lsfMPTCanTransfer; + + if (*arg.mutableFlags & tmfMPTSetPrivacy) + flags |= lsfMPTCanPrivacy; + else if (*arg.mutableFlags & tmfMPTClearPrivacy) + flags &= ~lsfMPTCanPrivacy; } } env_.require(mptflags(*this, flags, holder)); }; if (arg.account) require(std::nullopt, arg.holder.has_value()); - if (arg.holder) - require(*arg.holder, false); + if (auto const account = (arg.holder ? std::get_if(&(*arg.holder)) : nullptr)) + require(*account, false); } - if (arg.pubKey) + if (arg.issuerPubKey) { env_.require(requireAny([&]() -> bool { return forObject([&](SLEP const& sle) -> bool { if (sle) { - return strHex((*sle)[sfIssuerElGamalPublicKey]) == - strHex(getPubKey(issuer_)); + auto const issuerPubKey = getPubKey(issuer_); + if (!issuerPubKey) + Throw("MPTTester::set: issuer's pubkey is not set"); + + return strHex((*sle)[sfIssuerElGamalPublicKey]) == strHex(*issuerPubKey); + } + return false; + }); + })); + } + + if (arg.auditorPubKey) + { + env_.require(requireAny([&]() -> bool { + return forObject([&](SLEP const& sle) -> bool { + if (sle) + { + if (!auditor_.has_value()) + Throw("MPTTester::set: auditor is not set"); + + auto const auditorPubKey = getPubKey(*auditor_); + if (!auditorPubKey) + Throw("MPTTester::set: auditor's pubkey is not set"); + + return strHex((*sle)[sfAuditorElGamalPublicKey]) == strHex(*auditorPubKey); } return false; }); @@ -346,14 +466,11 @@ MPTTester::set(MPTSet const& arg) } bool -MPTTester::forObject( - std::function const& cb, - std::optional const& holder_) const +MPTTester::forObject(std::function const& cb, std::optional const& holder_) const { if (!id_) Throw("MPT has not been created"); - auto const key = holder_ ? keylet::mptoken(*id_, holder_->id()) - : keylet::mptIssuance(*id_); + auto const key = holder_ ? keylet::mptoken(*id_, holder_->id()) : keylet::mptIssuance(*id_); if (auto const sle = env_.le(key)) return cb(sle); return false; @@ -381,36 +498,26 @@ MPTTester::printMPT(Account const& holder_) const } [[nodiscard]] bool -MPTTester::checkMPTokenAmount( - Account const& holder_, - std::int64_t expectedAmount) const +MPTTester::checkMPTokenAmount(Account const& holder_, std::int64_t expectedAmount) const { - return forObject( - [&](SLEP const& sle) { return expectedAmount == (*sle)[sfMPTAmount]; }, - holder_); + return forObject([&](SLEP const& sle) { return expectedAmount == (*sle)[sfMPTAmount]; }, holder_); } [[nodiscard]] bool MPTTester::checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const { - return forObject([&](SLEP const& sle) { - return expectedAmount == (*sle)[sfOutstandingAmount]; - }); + return forObject([&](SLEP const& sle) { return expectedAmount == (*sle)[sfOutstandingAmount]; }); } [[nodiscard]] bool MPTTester::checkIssuanceConfidentialBalance(std::int64_t expectedAmount) const { - return forObject([&](SLEP const& sle) { - return expectedAmount == - (*sle)[~sfConfidentialOutstandingAmount].value_or(0); - }); + return forObject( + [&](SLEP const& sle) { return expectedAmount == (*sle)[~sfConfidentialOutstandingAmount].value_or(0); }); } [[nodiscard]] bool -MPTTester::checkFlags( - uint32_t const expectedFlags, - std::optional const& holder) const +MPTTester::checkFlags(uint32_t const expectedFlags, std::optional const& holder) const { return expectedFlags == getFlags(holder); } @@ -420,8 +527,7 @@ MPTTester::checkMetadata(std::string const& metadata) const { return forObject([&](SLEP const& sle) -> bool { if (sle->isFieldPresent(sfMPTokenMetadata)) - return strHex(sle->getFieldVL(sfMPTokenMetadata)) == - strHex(metadata); + return strHex(sle->getFieldVL(sfMPTokenMetadata)) == strHex(metadata); return false; }); } @@ -429,9 +535,7 @@ MPTTester::checkMetadata(std::string const& metadata) const [[nodiscard]] bool MPTTester::isMetadataPresent() const { - return forObject([&](SLEP const& sle) -> bool { - return sle->isFieldPresent(sfMPTokenMetadata); - }); + return forObject([&](SLEP const& sle) -> bool { return sle->isFieldPresent(sfMPTokenMetadata); }); } [[nodiscard]] bool @@ -447,9 +551,7 @@ MPTTester::checkTransferFee(std::uint16_t transferFee) const [[nodiscard]] bool MPTTester::isTransferFeePresent() const { - return forObject([&](SLEP const& sle) -> bool { - return sle->isFieldPresent(sfTransferFee); - }); + return forObject([&](SLEP const& sle) -> bool { return sle->isFieldPresent(sfTransferFee); }); } void @@ -464,13 +566,10 @@ MPTTester::pay( Throw("MPT has not been created"); auto const srcAmt = getBalance(src); auto const destAmt = getBalance(dest); - auto const outstnAmt = getBalance(issuer_); + auto const outstandingAmt = getBalance(issuer_); if (credentials) - env_( - jtx::pay(src, dest, mpt(amount)), - ter(err.value_or(tesSUCCESS)), - credentials::ids(*credentials)); + env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS)), credentials::ids(*credentials)); else env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS))); @@ -491,24 +590,17 @@ MPTTester::pay( else { STAmount const saAmount = {*id_, amount}; - auto const actual = - multiply(saAmount, transferRate(*env_.current(), *id_)) - .mpt() - .value(); + auto const actual = multiply(saAmount, transferRate(*env_.current(), *id_)).mpt().value(); // Sender pays the transfer fee if any env_.require(mptbalance(*this, src, srcAmt - actual)); env_.require(mptbalance(*this, dest, destAmt + amount)); // Outstanding amount is reduced by the transfer fee if any - env_.require(mptbalance(*this, issuer_, outstnAmt - (actual - amount))); + env_.require(mptbalance(*this, issuer_, outstandingAmt - (actual - amount))); } } void -MPTTester::claw( - Account const& issuer, - Account const& holder, - std::int64_t amount, - std::optional err) +MPTTester::claw(Account const& issuer, Account const& holder, std::int64_t amount, std::optional err) { if (!id_) Throw("MPT has not been created"); @@ -520,10 +612,8 @@ MPTTester::claw( if (close_) env_.close(); - env_.require( - mptbalance(*this, issuer, issuerAmt - std::min(holderAmt, amount))); - env_.require( - mptbalance(*this, holder, holderAmt - std::min(holderAmt, amount))); + env_.require(mptbalance(*this, issuer, issuerAmt - std::min(holderAmt, amount))); + env_.require(mptbalance(*this, holder, holderAmt - std::min(holderAmt, amount))); } PrettyAmount @@ -531,7 +621,14 @@ MPTTester::mpt(std::int64_t amount) const { if (!id_) Throw("MPT has not been created"); - return ripple::test::jtx::MPT(issuer_.name(), *id_)(amount); + return xrpl::test::jtx::MPT(issuer_.name(), *id_)(amount); +} + +MPTTester::operator Asset() const +{ + if (!id_) + Throw("MPT has not been created"); + return Asset(*id_); } std::int64_t @@ -565,30 +662,291 @@ MPTTester::getIssuanceConfidentialBalance() const } std::optional -MPTTester::getEncryptedBalance( - Account const& account, - EncryptedBalanceType option) const +MPTTester::getClawbackProof( + Account const& holder, + std::uint64_t amount, + Buffer const& privateKey, + uint256 const& contextHash) const +{ + if (!id_) + Throw("MPT has not been created"); + + auto const sleHolder = env_.le(keylet::mptoken(*id_, holder.id())); + auto const sleIssuance = env_.le(keylet::mptIssuance(*id_)); + + if (!sleHolder || !sleIssuance) + return std::nullopt; + + auto const ciphertextBlob = sleHolder->getFieldVL(sfIssuerEncryptedBalance); + if (ciphertextBlob.size() != ecGamalEncryptedTotalLength) + return std::nullopt; + + auto const pubKeyBlob = sleIssuance->getFieldVL(sfIssuerElGamalPublicKey); + if (pubKeyBlob.size() != ecPubKeyLength) + return std::nullopt; + + secp256k1_pubkey c1, c2, pk; + auto const ctx = secp256k1Context(); + + if (!secp256k1_ec_pubkey_parse(ctx, &c1, ciphertextBlob.data(), ecGamalEncryptedLength)) + { + return std::nullopt; + } + + if (!secp256k1_ec_pubkey_parse(ctx, &c2, ciphertextBlob.data() + ecGamalEncryptedLength, ecGamalEncryptedLength)) + { + return std::nullopt; + } + + if (!secp256k1_ec_pubkey_parse(ctx, &pk, pubKeyBlob.data(), ecPubKeyLength)) + { + return std::nullopt; + } + + Buffer proof(ecEqualityProofLength); + + if (secp256k1_equality_plaintext_prove( + ctx, proof.data(), &pk, &c2, &c1, amount, privateKey.data(), contextHash.data()) != 1) + { + return std::nullopt; + } + + return proof; +} + +std::optional +MPTTester::getSchnorrProof(Account const& account, uint256 const& ctxHash) const +{ + auto const pubKey = getPubKey(account); + if (!pubKey || pubKey->size() != ecPubKeyLength) + return std::nullopt; + + auto const privKey = getPrivKey(account); + if (privKey->size() != ecPrivKeyLength) + return std::nullopt; + + secp256k1_pubkey pk; + if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pk, pubKey->data(), ecPubKeyLength) != 1) + return std::nullopt; + + Buffer proof(ecSchnorrProofLength); + + if (secp256k1_mpt_pok_sk_prove(secp256k1Context(), proof.data(), &pk, privKey->data(), ctxHash.data()) != 1) + { + return std::nullopt; + } + + return proof; +} + +std::optional +MPTTester::getConfidentialSendProof( + Account const& sender, + std::uint64_t const amount, + std::vector const& recipients, + Slice const& blindingFactor, + std::size_t const nRecipients, + uint256 const& contextHash, + PedersenProofParams const& amountParams, + PedersenProofParams const& balanceParams) const +{ + if (recipients.size() != nRecipients) + return std::nullopt; + + if (blindingFactor.size() != ecBlindingFactorLength) + return std::nullopt; + + auto const senderPubKey = getPubKey(sender); + if (!senderPubKey) + return std::nullopt; + + auto const ctx = secp256k1Context(); + + std::vector r(nRecipients); + std::vector s(nRecipients); + std::vector pk(nRecipients); + + std::vector sr; + sr.reserve(nRecipients * ecBlindingFactorLength); + + for (size_t i = 0; i < nRecipients; ++i) + { + auto const& recipient = recipients[i]; + auto const* ctData = recipient.encryptedAmount.data(); + + if (recipient.encryptedAmount.size() != ecGamalEncryptedTotalLength) + return std::nullopt; + + if (recipient.publicKey.size() != ecPubKeyLength) + return std::nullopt; + + if (!secp256k1_ec_pubkey_parse(ctx, &r[i], ctData, ecGamalEncryptedLength)) + { + return std::nullopt; + } + + if (!secp256k1_ec_pubkey_parse(ctx, &s[i], ctData + ecGamalEncryptedLength, ecGamalEncryptedLength)) + { + return std::nullopt; + } + + if (!secp256k1_ec_pubkey_parse(ctx, &pk[i], recipient.publicKey.data(), ecPubKeyLength)) + return std::nullopt; + + sr.insert(sr.end(), blindingFactor.data(), blindingFactor.data() + ecBlindingFactorLength); + } + + size_t sizeEquality = secp256k1_mpt_prove_same_plaintext_multi_size(nRecipients); + Buffer equalityProof(sizeEquality); + + // Get the multi-ciphertext equality proof + if (secp256k1_mpt_prove_same_plaintext_multi( + ctx, + equalityProof.data(), + &sizeEquality, + amount, + nRecipients, + r.data(), + s.data(), + pk.data(), + sr.data(), + contextHash.data()) != 1) + { + return std::nullopt; + } + + auto const amountLinkageProof = getAmountLinkageProof( + *senderPubKey, Buffer(blindingFactor.data(), ecBlindingFactorLength), contextHash, amountParams); + + auto const balanceLinkageProof = getBalanceLinkageProof(sender, contextHash, *senderPubKey, balanceParams); + + std::uint64_t const remainingBalance = balanceParams.amt - amount; + + // Compute the blinding factor for the remaining balance: rho_rem = rho_balance - rho_amount + unsigned char rho_rem[32]; + unsigned char neg_rho_m[32]; + + secp256k1_mpt_scalar_negate(neg_rho_m, amountParams.blindingFactor.data()); + secp256k1_mpt_scalar_add(rho_rem, balanceParams.blindingFactor.data(), neg_rho_m); + + // Generate bulletproof for the amount and remaining balance + Buffer const bulletproof = + getBulletproof({amount, remainingBalance}, {amountParams.blindingFactor, Buffer(rho_rem, 32)}, contextHash); + + OPENSSL_cleanse(neg_rho_m, 32); + OPENSSL_cleanse(rho_rem, 32); + + auto const sizeAmountLinkage = amountLinkageProof.size(); + auto const sizeBalanceLinkage = balanceLinkageProof.size(); + auto const sizeBulletproof = bulletproof.size(); + + size_t const proofSize = sizeEquality + sizeAmountLinkage + sizeBalanceLinkage + sizeBulletproof; + Buffer proof(proofSize); + + auto ptr = proof.data(); + std::memcpy(ptr, equalityProof.data(), sizeEquality); + ptr += sizeEquality; + + std::memcpy(ptr, amountLinkageProof.data(), sizeAmountLinkage); + ptr += sizeAmountLinkage; + + std::memcpy(ptr, balanceLinkageProof.data(), sizeBalanceLinkage); + ptr += sizeBalanceLinkage; + + std::memcpy(ptr, bulletproof.data(), sizeBulletproof); + + return proof; +} + +Buffer +MPTTester::getPedersenCommitment(std::uint64_t const amount, Buffer const& pedersenBlindingFactor) +{ + // Blinding factor (rho) must be a 32-byte scalar + if (pedersenBlindingFactor.size() != ecBlindingFactorLength) + Throw("Invalid blinding factor size"); + + // secp256k1_mpt_pedersen_commit doesn't handle amount 0, return a trivial + // valid commitment for test purposes + if (amount == 0) + { + Buffer buf(ecPedersenCommitmentLength); + std::memset(buf.data(), 0, ecPedersenCommitmentLength); + buf.data()[0] = 0x02; + buf.data()[ecPedersenCommitmentLength - 1] = 0x01; + return buf; + } + + secp256k1_pubkey commitment; + auto const ctx = secp256k1Context(); + + // Compute PC = m*G + rho*H + if (secp256k1_mpt_pedersen_commit(ctx, &commitment, amount, pedersenBlindingFactor.data()) != 1) + { + Throw("Pedersen commitment generation failed"); + } + + // Serialize commitment to compressed format (33 bytes) + unsigned char compressedCommitment[ecPedersenCommitmentLength]; + size_t outLen = ecPedersenCommitmentLength; + if (secp256k1_ec_pubkey_serialize(ctx, compressedCommitment, &outLen, &commitment, SECP256K1_EC_COMPRESSED) != 1 || + outLen != ecPedersenCommitmentLength) + { + Throw("Pedersen commitment serialization failed"); + } + + return Buffer{compressedCommitment, ecPedersenCommitmentLength}; +} + +Buffer +MPTTester::getConvertBackProof( + Account const& holder, + std::uint64_t const amount, + uint256 const& contextHash, + PedersenProofParams const& pcParams) const +{ + // Expected total proof length: pedersen proof + single bulletproof + std::size_t constexpr expectedProofLength = ecPedersenProofLength + ecSingleBulletproofLength; + + auto const sleMptoken = env_.le(keylet::mptoken(*id_, holder.id())); + if (!sleMptoken || !sleMptoken->isFieldPresent(sfConfidentialBalanceSpending)) + return makeZeroBuffer(expectedProofLength); + + auto const holderPubKey = getPubKey(holder); + + if (!holderPubKey) + return makeZeroBuffer(expectedProofLength); + + Buffer const pedersenProof = getBalanceLinkageProof(holder, contextHash, *holderPubKey, pcParams); + + // Generate bulletproof for the remaining balance (balance - amount) + // Use the same blinding factor as the one used to generate the PC_balance + std::uint64_t const remainingBalance = pcParams.amt - amount; + Buffer const bulletproof = getBulletproof({remainingBalance}, {pcParams.blindingFactor}, contextHash); + + // Combine pedersen proof and bulletproof + Buffer combinedProof(pedersenProof.size() + bulletproof.size()); + std::memcpy(combinedProof.data(), pedersenProof.data(), pedersenProof.size()); + std::memcpy(combinedProof.data() + pedersenProof.size(), bulletproof.data(), bulletproof.size()); + + return combinedProof; +} + +std::optional +MPTTester::getEncryptedBalance(Account const& account, EncryptedBalanceType option) const { if (!id_) Throw("MPT has not been created"); if (auto const sle = env_.le(keylet::mptoken(*id_, account.id()))) { - if (option == HOLDER_ENCRYPTED_INBOX && - sle->isFieldPresent(sfConfidentialBalanceInbox)) - return Buffer( - (*sle)[sfConfidentialBalanceInbox].data(), - (*sle)[sfConfidentialBalanceInbox].size()); - if (option == HOLDER_ENCRYPTED_SPENDING && - sle->isFieldPresent(sfConfidentialBalanceSpending)) - return Buffer( - (*sle)[sfConfidentialBalanceSpending].data(), - (*sle)[sfConfidentialBalanceSpending].size()); - if (option == ISSUER_ENCRYPTED_BALANCE && - sle->isFieldPresent(sfIssuerEncryptedBalance)) - return Buffer( - (*sle)[sfIssuerEncryptedBalance].data(), - (*sle)[sfIssuerEncryptedBalance].size()); + if (option == HOLDER_ENCRYPTED_INBOX && sle->isFieldPresent(sfConfidentialBalanceInbox)) + return Buffer((*sle)[sfConfidentialBalanceInbox].data(), (*sle)[sfConfidentialBalanceInbox].size()); + if (option == HOLDER_ENCRYPTED_SPENDING && sle->isFieldPresent(sfConfidentialBalanceSpending)) + return Buffer((*sle)[sfConfidentialBalanceSpending].data(), (*sle)[sfConfidentialBalanceSpending].size()); + if (option == ISSUER_ENCRYPTED_BALANCE && sle->isFieldPresent(sfIssuerEncryptedBalance)) + return Buffer((*sle)[sfIssuerEncryptedBalance].data(), (*sle)[sfIssuerEncryptedBalance].size()); + if (option == AUDITOR_ENCRYPTED_BALANCE && sle->isFieldPresent(sfAuditorEncryptedBalance)) + return Buffer((*sle)[sfAuditorEncryptedBalance].data(), (*sle)[sfAuditorEncryptedBalance].size()); } return {}; @@ -614,6 +972,51 @@ MPTTester::operator[](std::string const& name) const return MPT(name, issuanceID()); } +PrettyAmount +MPTTester::operator()(std::int64_t amount) const +{ + return MPT("", issuanceID())(amount); +} + +template +void +MPTTester::fillConversionCiphertexts( + T const& arg, + Json::Value& jv, + Buffer& holderCiphertext, + Buffer& issuerCiphertext, + std::optional& auditorCiphertext, + Buffer& blindingFactor) const +{ + blindingFactor = arg.blindingFactor ? *arg.blindingFactor : generateBlindingFactor(); + + // Handle Holder + if (arg.holderEncryptedAmt) + holderCiphertext = *arg.holderEncryptedAmt; + else + holderCiphertext = encryptAmount(*arg.account, *arg.amt, blindingFactor); + + jv[sfHolderEncryptedAmount.jsonName] = strHex(holderCiphertext); + + // Handle Issuer + if (arg.issuerEncryptedAmt) + issuerCiphertext = *arg.issuerEncryptedAmt; + else + issuerCiphertext = encryptAmount(issuer_, *arg.amt, blindingFactor); + + jv[sfIssuerEncryptedAmount.jsonName] = strHex(issuerCiphertext); + + // Handle Auditor + if (arg.auditorEncryptedAmt) + auditorCiphertext = *arg.auditorEncryptedAmt; + else if (auditor_.has_value() && *arg.fillAuditorEncryptedAmt) + auditorCiphertext = encryptAmount(*auditor_, *arg.amt, blindingFactor); + + // Update auditor JSON only if ciphertext exists + if (auditorCiphertext) + jv[sfAuditorEncryptedAmount.jsonName] = strHex(*auditorCiphertext); +} + void MPTTester::convert(MPTConvert const& arg) { @@ -623,7 +1026,7 @@ MPTTester::convert(MPTConvert const& arg) else Throw("Account not specified"); - jv[jss::TransactionType] = jss::ConfidentialConvert; + jv[jss::TransactionType] = jss::ConfidentialMPTConvert; if (arg.id) jv[sfMPTokenIssuanceID] = to_string(*arg.id); else @@ -638,68 +1041,86 @@ MPTTester::convert(MPTConvert const& arg) if (arg.holderPubKey) jv[sfHolderElGamalPublicKey.jsonName] = strHex(*arg.holderPubKey); - if (arg.holderEncryptedAmt) - jv[sfHolderEncryptedAmount.jsonName] = strHex(*arg.holderEncryptedAmt); - else - jv[sfHolderEncryptedAmount.jsonName] = - strHex(encryptAmount(*arg.account, *arg.amt)); + Buffer holderCiphertext; + Buffer issuerCiphertext; + std::optional auditorCiphertext; + Buffer blindingFactor; - if (arg.issuerEncryptedAmt) - jv[sfIssuerEncryptedAmount.jsonName] = strHex(*arg.issuerEncryptedAmt); - else - jv[sfIssuerEncryptedAmount.jsonName] = - strHex(encryptAmount(issuer_, *arg.amt)); + fillConversionCiphertexts(arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor); + jv[sfBlindingFactor.jsonName] = strHex(blindingFactor); if (arg.proof) jv[sfZKProof.jsonName] = *arg.proof; + else if (arg.fillSchnorrProof.value_or(arg.holderPubKey.has_value())) + { + // whether to automatically generate and attach a Schnorr proof: + // if fillSchnorrProof is explicitly set, follow its value; + // otherwise, default to generating the proof only if holder pub key is + // present. + auto const contextHash = getConvertContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt); + + auto const proof = getSchnorrProof(*arg.account, contextHash); + if (proof) + jv[sfZKProof.jsonName] = strHex(*proof); + else + jv[sfZKProof.jsonName] = strHex(makeZeroBuffer(ecSchnorrProofLength)); + } auto const holderAmt = getBalance(*arg.account); auto const prevConfidentialOutstanding = getIssuanceConfidentialBalance(); - uint64_t prevInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t prevSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t prevIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + auto const prevInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const prevSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const prevIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance) + Throw("Failed to get Pre-convert balance"); + + std::optional prevAuditorBalance; + if (arg.auditorEncryptedAmt || auditor_) + { + prevAuditorBalance = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + if (!prevAuditorBalance) + Throw("Failed to get Pre-convert balance"); + } if (submit(arg, jv) == tesSUCCESS) { - auto const postConfidentialOutstanding = - getIssuanceConfidentialBalance(); + auto const postConfidentialOutstanding = getIssuanceConfidentialBalance(); env_.require(mptbalance(*this, *arg.account, holderAmt - *arg.amt)); - env_.require(requireAny([&]() -> bool { - return prevConfidentialOutstanding + *arg.amt == - postConfidentialOutstanding; - })); + env_.require(requireAny( + [&]() -> bool { return prevConfidentialOutstanding + *arg.amt == postConfidentialOutstanding; })); - uint64_t postInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t postIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); - uint64_t postSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const postInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const postIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + auto const postSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance) + Throw("Failed to get post-convert balance"); + + if (arg.auditorEncryptedAmt || auditor_) + { + auto const postAuditorBalance = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + + if (!postAuditorBalance) + Throw("Failed to get post-convert auditor balance"); + + // auditor's encrypted balance is updated correctly + env_.require(requireAny([&]() -> bool { return *prevAuditorBalance + *arg.amt == *postAuditorBalance; })); + } // spending balance should not change - env_.require(requireAny([&]() -> bool { - return postSpendingBalance == prevSpendingBalance; - })); + env_.require(requireAny([&]() -> bool { return *postSpendingBalance == *prevSpendingBalance; })); // issuer's encrypted balance is updated correctly - env_.require(requireAny([&]() -> bool { - return prevIssuerBalance + *arg.amt == postIssuerBalance; - })); + env_.require(requireAny([&]() -> bool { return *prevIssuerBalance + *arg.amt == *postIssuerBalance; })); // holder's inbox balance is updated correctly - env_.require(requireAny([&]() -> bool { - return prevInboxBalance + *arg.amt == postInboxBalance; - })); + env_.require(requireAny([&]() -> bool { return *prevInboxBalance + *arg.amt == *postInboxBalance; })); // sum of holder's inbox and spending balance should equal to issuer's // encrypted balance - env_.require(requireAny([&]() -> bool { - return postInboxBalance + postSpendingBalance == postIssuerBalance; - })); + env_.require( + requireAny([&]() -> bool { return *postInboxBalance + *postSpendingBalance == *postIssuerBalance; })); if (arg.holderPubKey) { @@ -708,8 +1129,13 @@ MPTTester::convert(MPTConvert const& arg) [&](SLEP const& sle) -> bool { if (sle) { - return strHex((*sle)[sfHolderElGamalPublicKey]) == - strHex(getPubKey(*arg.account)); + auto const holderPubKey = getPubKey(*arg.account); + if (!holderPubKey) + Throw( + "MPTTester::convert: holder's pubkey is " + "not set"); + + return strHex((*sle)[sfHolderElGamalPublicKey]) == strHex(*holderPubKey); } return false; }, @@ -723,6 +1149,8 @@ void MPTTester::send(MPTConfidentialSend const& arg) { Json::Value jv; + jv[jss::TransactionType] = jss::ConfidentialMPTSend; + if (arg.account) jv[sfAccount] = arg.account->human(); else @@ -733,7 +1161,9 @@ MPTTester::send(MPTConfidentialSend const& arg) else Throw("Destination not specified"); - jv[jss::TransactionType] = jss::ConfidentialSend; + if (!arg.amt) + Throw("Amount not specified for testing purposes"); + if (arg.id) jv[sfMPTokenIssuanceID] = to_string(*arg.id); else @@ -743,26 +1173,27 @@ MPTTester::send(MPTConfidentialSend const& arg) jv[sfMPTokenIssuanceID] = to_string(*id_); } - // Generate the encrypted amounts if not provided - if (arg.senderEncryptedAmt) - jv[sfSenderEncryptedAmount] = strHex(*arg.senderEncryptedAmt); - else - jv[sfSenderEncryptedAmount] = - strHex(encryptAmount(*arg.account, *arg.amt)); + Buffer const blindingFactor = arg.blindingFactor ? *arg.blindingFactor : generateBlindingFactor(); - if (arg.destEncryptedAmt) - jv[sfDestinationEncryptedAmount] = strHex(*arg.destEncryptedAmt); - else - jv[sfDestinationEncryptedAmount] = - strHex(encryptAmount(*arg.dest, *arg.amt)); + // fill in the encrypted amounts if not provided + auto const senderAmt = + arg.senderEncryptedAmt ? *arg.senderEncryptedAmt : encryptAmount(*arg.account, *arg.amt, blindingFactor); + auto const destAmt = + arg.destEncryptedAmt ? *arg.destEncryptedAmt : encryptAmount(*arg.dest, *arg.amt, blindingFactor); + auto const issuerAmt = + arg.issuerEncryptedAmt ? *arg.issuerEncryptedAmt : encryptAmount(issuer_, *arg.amt, blindingFactor); - if (arg.issuerEncryptedAmt) - jv[sfIssuerEncryptedAmount] = strHex(*arg.issuerEncryptedAmt); - else - jv[sfIssuerEncryptedAmount] = strHex(encryptAmount(issuer_, *arg.amt)); + std::optional auditorAmt; + if (arg.auditorEncryptedAmt) + auditorAmt = arg.auditorEncryptedAmt; + else if (auditor_.has_value()) + auditorAmt = encryptAmount(*auditor_, *arg.amt, blindingFactor); - if (arg.proof) - jv[sfZKProof] = *arg.proof; + jv[sfSenderEncryptedAmount] = strHex(senderAmt); + jv[sfDestinationEncryptedAmount] = strHex(destAmt); + jv[sfIssuerEncryptedAmount] = strHex(issuerAmt); + if (auditorAmt) + jv[sfAuditorEncryptedAmount] = strHex(*auditorAmt); if (arg.credentials) { @@ -771,47 +1202,154 @@ MPTTester::send(MPTConfidentialSend const& arg) arr.append(hash); } + // Sender's previous confidential state + auto const prevSenderInbox = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const prevSenderSpending = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const prevSenderIssuer = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + if (!prevSenderInbox || !prevSenderSpending || !prevSenderIssuer) + Throw("Failed to get Pre-send balance"); + + std::optional prevSenderAuditor; + if (arg.auditorEncryptedAmt || auditor_) + { + prevSenderAuditor = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + if (!prevSenderAuditor) + Throw("Failed to get Pre-send balance"); + } + + // Destination's previous confidential state + auto const prevDestInbox = getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_INBOX); + auto const prevDestSpending = getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_SPENDING); + auto const prevDestIssuer = getDecryptedBalance(*arg.dest, ISSUER_ENCRYPTED_BALANCE); + if (!prevDestInbox || !prevDestSpending || !prevDestIssuer) + Throw("Failed to get Pre-send balance"); + + std::optional prevDestAuditor; + if (arg.auditorEncryptedAmt || auditor_) + { + prevDestAuditor = getDecryptedBalance(*arg.dest, AUDITOR_ENCRYPTED_BALANCE); + if (!prevDestAuditor) + Throw("Failed to get Pre-send balance"); + } + + // Fill in the commitment if not provided + Buffer amountCommitment, balanceCommitment; + auto const amountBlindingFactor = generateBlindingFactor(); + if (arg.amountCommitment) + amountCommitment = *arg.amountCommitment; + else + amountCommitment = getPedersenCommitment(*arg.amt, amountBlindingFactor); + + jv[sfAmountCommitment] = strHex(amountCommitment); + + auto const balanceBlindingFactor = generateBlindingFactor(); + if (arg.balanceCommitment) + balanceCommitment = *arg.balanceCommitment; + else + balanceCommitment = getPedersenCommitment(*prevSenderSpending, balanceBlindingFactor); + + jv[sfBalanceCommitment] = strHex(balanceCommitment); + + // Fill in the proof if not provided + if (arg.proof) + jv[sfZKProof] = *arg.proof; + else + { + auto const version = getMPTokenVersion(*arg.account); + auto const ctxHash = + getSendContextHash(arg.account->id(), env_.seq(*arg.account), *id_, arg.dest->id(), version); + + auto const nRecipients = getConfidentialRecipientCount(auditorAmt.has_value()); + std::vector recipients; + + auto const senderPubKey = getPubKey(*arg.account); + auto const destPubKey = getPubKey(*arg.dest); + auto const issuerPubKey = getPubKey(issuer_); + + // If a key is missing, we skip adding the recipient. This intentionally + // causes proof generation to fail (due to recipient count mismatch), + // triggering the dummy proof fallback. + if (senderPubKey) + recipients.push_back({Slice(*senderPubKey), senderAmt}); + if (destPubKey) + recipients.push_back({Slice(*destPubKey), destAmt}); + if (issuerPubKey) + recipients.push_back({Slice(*issuerPubKey), issuerAmt}); + + std::optional auditorPubKey; + if (auditorAmt) + { + if (!auditor_) + Throw("Auditor not registered"); + + auditorPubKey = getPubKey(*auditor_); + if (auditorPubKey) + recipients.push_back({Slice(*auditorPubKey), *auditorAmt}); + } + + auto const prevEncryptedSenderSpending = getEncryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + + std::optional proof; + + // Skip proof generation if encrypted balance is missing (e.g., + // feature disabled), or when the sender and destination are the + // same (malformed case causing pcm to be zero). This prevents a + // crash and allows certain error cases to be tested. + if (arg.account != arg.dest && prevEncryptedSenderSpending) + { + proof = getConfidentialSendProof( + *arg.account, + *arg.amt, + recipients, + blindingFactor, + nRecipients, + ctxHash, + {.pedersenCommitment = amountCommitment, + .amt = *arg.amt, + .encryptedAmt = senderAmt, + .blindingFactor = amountBlindingFactor}, + {.pedersenCommitment = balanceCommitment, + .amt = *prevSenderSpending, + .encryptedAmt = *prevEncryptedSenderSpending, + .blindingFactor = balanceBlindingFactor}); + } + + if (proof) + jv[sfZKProof.jsonName] = strHex(*proof); + else + { + size_t const sizeEquality = secp256k1_mpt_prove_same_plaintext_multi_size(nRecipients); + size_t const dummySize = sizeEquality + 2 * ecPedersenProofLength + ecDoubleBulletproofLength; + + jv[sfZKProof.jsonName] = strHex(makeZeroBuffer(dummySize)); + } + } + auto const senderPubAmt = getBalance(*arg.account); auto const destPubAmt = getBalance(*arg.dest); auto const prevCOA = getIssuanceConfidentialBalance(); auto const prevOA = getIssuanceOutstandingBalance(); - // Sender's previous confidential state - uint64_t prevSenderInbox = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t prevSenderSpending = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t prevSenderIssuer = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); - - // Destination's previous confidential state - uint64_t prevDestInbox = - getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_INBOX); - uint64_t prevDestSpending = - getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_SPENDING); - uint64_t prevDestIssuer = - getDecryptedBalance(*arg.dest, ISSUER_ENCRYPTED_BALANCE); - if (submit(arg, jv) == tesSUCCESS) { auto const postCOA = getIssuanceConfidentialBalance(); auto const postOA = getIssuanceOutstandingBalance(); // Sender's post confidential state - uint64_t postSenderInbox = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t postSenderSpending = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t postSenderIssuer = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + auto const postSenderInbox = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const postSenderSpending = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const postSenderIssuer = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + if (!postSenderInbox || !postSenderSpending || !postSenderIssuer) + Throw("Failed to get Post-send balance"); // Destination's post confidential state - uint64_t postDestInbox = - getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_INBOX); - uint64_t postDestSpending = - getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_SPENDING); - uint64_t postDestIssuer = - getDecryptedBalance(*arg.dest, ISSUER_ENCRYPTED_BALANCE); + auto const postDestInbox = getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_INBOX); + auto const postDestSpending = getDecryptedBalance(*arg.dest, HOLDER_ENCRYPTED_SPENDING); + auto const postDestIssuer = getDecryptedBalance(*arg.dest, ISSUER_ENCRYPTED_BALANCE); + + if (!postDestInbox || !postDestSpending || !postDestIssuer) + Throw("Failed to get Post-send balance"); // Public balances unchanged env_.require(mptbalance(*this, *arg.account, senderPubAmt)); @@ -823,33 +1361,41 @@ MPTTester::send(MPTConfidentialSend const& arg) // Verify sender changes env_.require(requireAny([&]() -> bool { - return prevSenderSpending >= *arg.amt && - postSenderSpending == prevSenderSpending - *arg.amt; + return *prevSenderSpending >= *arg.amt && *postSenderSpending == *prevSenderSpending - *arg.amt; })); - env_.require(requireAny( - [&]() -> bool { return postSenderInbox == prevSenderInbox; })); + env_.require(requireAny([&]() -> bool { return postSenderInbox == prevSenderInbox; })); env_.require(requireAny([&]() -> bool { - return prevSenderIssuer >= *arg.amt && - postSenderIssuer == prevSenderIssuer - *arg.amt; + return *prevSenderIssuer >= *arg.amt && *postSenderIssuer == *prevSenderIssuer - *arg.amt; })); // Verify destination changes - env_.require(requireAny([&]() -> bool { - return postDestInbox == prevDestInbox + *arg.amt; - })); - env_.require(requireAny( - [&]() -> bool { return postDestSpending == prevDestSpending; })); - env_.require(requireAny([&]() -> bool { - return postDestIssuer == prevDestIssuer + *arg.amt; - })); + env_.require(requireAny([&]() -> bool { return *postDestInbox == *prevDestInbox + *arg.amt; })); + env_.require(requireAny([&]() -> bool { return *postDestSpending == *prevDestSpending; })); + env_.require(requireAny([&]() -> bool { return *postDestIssuer == *prevDestIssuer + *arg.amt; })); // Cross checks - env_.require(requireAny([&]() -> bool { - return postSenderInbox + postSenderSpending == postSenderIssuer; - })); - env_.require(requireAny([&]() -> bool { - return postDestInbox + postDestSpending == postDestIssuer; - })); + env_.require(requireAny([&]() -> bool { return *postSenderInbox + *postSenderSpending == *postSenderIssuer; })); + env_.require(requireAny([&]() -> bool { return *postDestInbox + *postDestSpending == *postDestIssuer; })); + + if (arg.auditorEncryptedAmt || auditor_) + { + auto const postSenderAuditor = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + auto const postDestAuditor = getDecryptedBalance(*arg.dest, AUDITOR_ENCRYPTED_BALANCE); + if (!postSenderAuditor || !postDestAuditor) + Throw("Failed to get Post-send balance"); + + env_.require(requireAny([&]() -> bool { + return *postSenderAuditor == *postSenderIssuer && *postDestAuditor == *postDestIssuer; + })); + + // verify sender + env_.require(requireAny([&]() -> bool { + return prevSenderAuditor >= *arg.amt && *postSenderAuditor == *prevSenderAuditor - *arg.amt; + })); + + // verify dest + env_.require(requireAny([&]() -> bool { return *postDestAuditor == *prevDestAuditor + *arg.amt; })); + } } } @@ -865,7 +1411,7 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg) else Throw("Holder not specified"); - jv[jss::TransactionType] = jss::ConfidentialClawback; + jv[jss::TransactionType] = jss::ConfidentialMPTClawback; if (arg.id) jv[sfMPTokenIssuanceID] = to_string(*arg.id); else if (id_) @@ -878,6 +1424,22 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg) if (arg.proof) jv[sfZKProof] = *arg.proof; + else + { + std::uint32_t const seq = env_.seq(account); + uint256 const contextHash = getClawbackContextHash(account.id(), seq, *id_, *arg.amt, arg.holder->id()); + + auto const privKey = getPrivKey(account); + if (!privKey || privKey->size() != ecPrivKeyLength) + Throw("Failed to get clawback private key"); + + auto const proof = getClawbackProof(*arg.holder, *arg.amt, *privKey, contextHash); + + if (proof) + jv[sfZKProof] = strHex(*proof); + else + jv[sfZKProof] = strHex(makeZeroBuffer(ecEqualityProofLength)); + } auto const holderPubAmt = getBalance(*arg.holder); auto const prevCOA = getIssuanceConfidentialBalance(); @@ -892,26 +1454,18 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg) env_.require(mptbalance(*this, *arg.holder, holderPubAmt)); // Verify COA and OA are reduced correctly - env_.require(requireAny([&]() -> bool { - return prevCOA >= *arg.amt && postCOA == prevCOA - *arg.amt; - })); - env_.require(requireAny([&]() -> bool { - return prevOA >= *arg.amt && postOA == prevOA - *arg.amt; - })); + env_.require(requireAny([&]() -> bool { return prevCOA >= *arg.amt && postCOA == prevCOA - *arg.amt; })); + env_.require(requireAny([&]() -> bool { return prevOA >= *arg.amt && postOA == prevOA - *arg.amt; })); // Verify holder's confidential balances are zeroed out - env_.require(requireAny([&]() -> bool { - return getDecryptedBalance(*arg.holder, HOLDER_ENCRYPTED_INBOX) == - 0; - })); - env_.require(requireAny([&]() -> bool { - return getDecryptedBalance( - *arg.holder, HOLDER_ENCRYPTED_SPENDING) == 0; - })); - env_.require(requireAny([&]() -> bool { - return getDecryptedBalance(*arg.holder, ISSUER_ENCRYPTED_BALANCE) == - 0; - })); + env_.require( + requireAny([&]() -> bool { return getDecryptedBalance(*arg.holder, HOLDER_ENCRYPTED_INBOX) == 0; })); + env_.require( + requireAny([&]() -> bool { return getDecryptedBalance(*arg.holder, HOLDER_ENCRYPTED_SPENDING) == 0; })); + env_.require( + requireAny([&]() -> bool { return getDecryptedBalance(*arg.holder, ISSUER_ENCRYPTED_BALANCE) == 0; })); + env_.require( + requireAny([&]() -> bool { return getDecryptedBalance(*arg.holder, AUDITOR_ENCRYPTED_BALANCE) == 0; })); } } @@ -920,15 +1474,22 @@ MPTTester::generateKeyPair(Account const& account) { unsigned char privKey[ecPrivKeyLength]; secp256k1_pubkey pubKey; - if (!secp256k1_elgamal_generate_keypair( - secp256k1Context(), privKey, &pubKey)) + if (!secp256k1_elgamal_generate_keypair(secp256k1Context(), privKey, &pubKey)) Throw("failed to generate key pair"); - pubKeys.insert({account.id(), Buffer{pubKey.data, ecPubKeyLength}}); + // Serialize public key to compressed format (33 bytes) + unsigned char compressedPubKey[ecPubKeyLength]; + size_t outLen = ecPubKeyLength; + if (secp256k1_ec_pubkey_serialize( + secp256k1Context(), compressedPubKey, &outLen, &pubKey, SECP256K1_EC_COMPRESSED) != 1 || + outLen != ecPubKeyLength) + Throw("failed to serialize public key"); + + pubKeys.insert({account.id(), Buffer{compressedPubKey, ecPubKeyLength}}); privKeys.insert({account.id(), Buffer{privKey, ecPrivKeyLength}}); } -Buffer +std::optional MPTTester::getPubKey(Account const& account) const { auto it = pubKeys.find(account.id()); @@ -937,10 +1498,10 @@ MPTTester::getPubKey(Account const& account) const return it->second; } - Throw("Account does not have public key"); + return std::nullopt; } -Buffer +std::optional MPTTester::getPrivKey(Account const& account) const { auto it = privKeys.find(account.id()); @@ -949,49 +1510,71 @@ MPTTester::getPrivKey(Account const& account) const return it->second; } - Throw("Account does not have private key"); + return std::nullopt; } Buffer -MPTTester::encryptAmount(Account const& account, uint64_t amt) const +MPTTester::encryptAmount(Account const& account, uint64_t const amt, Buffer const& blindingFactor) const { - return ripple::encryptAmount(amt, getPubKey(account)); + if (auto const pubKey = getPubKey(account)) + { + if (auto const result = xrpl::encryptAmount(amt, *pubKey, blindingFactor)) + return *result; + } + + // Return a dummy buffer on failure to allow testing of + // failures that occur prior to encryption. + return makeZeroBuffer(ecGamalEncryptedTotalLength); } -uint64_t +std::optional MPTTester::decryptAmount(Account const& account, Buffer const& amt) const { + if (amt.size() != ecGamalEncryptedTotalLength) + return std::nullopt; + secp256k1_pubkey c1; secp256k1_pubkey c2; - uint64_t decryptedAmt; - if (!makeEcPair(amt, c1, c2)) - Throw( - "Failed to convert into individual EC components"); + return std::nullopt; - if (!secp256k1_elgamal_decrypt( - secp256k1Context(), - &decryptedAmt, - &c1, - &c2, - getPrivKey(account).data())) - Throw("Failed to decrypt amount"); + auto const privKey = getPrivKey(account); + if (!privKey || privKey->size() != ecPrivKeyLength) + return std::nullopt; + + uint64_t decryptedAmt; + if (!secp256k1_elgamal_decrypt(secp256k1Context(), &decryptedAmt, &c1, &c2, privKey->data())) + { + return std::nullopt; + } return decryptedAmt; } -uint64_t -MPTTester::getDecryptedBalance( - Account const& account, - EncryptedBalanceType balanceType) const +std::optional +MPTTester::getDecryptedBalance(Account const& account, EncryptedBalanceType balanceType) const { - auto maybeEncrypted = getEncryptedBalance(account, balanceType); - auto accountToDecrypt = - balanceType == ISSUER_ENCRYPTED_BALANCE ? issuer_ : account; - return maybeEncrypted ? decryptAmount(accountToDecrypt, *maybeEncrypted) - : 0; + auto encryptedAmt = getEncryptedBalance(account, balanceType); + + // Return zero to test cases like Feature Disabled, where the ledger object + // does not exist. + if (!encryptedAmt) + return 0; + + Account decryptor = account; + + if (balanceType == ISSUER_ENCRYPTED_BALANCE) + decryptor = issuer_; + else if (balanceType == AUDITOR_ENCRYPTED_BALANCE) + { + if (!auditor_) + return std::nullopt; + decryptor = *auditor_; + } + + return decryptAmount(decryptor, *encryptedAmt); }; void @@ -1010,34 +1593,32 @@ MPTTester::mergeInbox(MPTMergeInbox const& arg) Throw("MPT has not been created"); jv[sfMPTokenIssuanceID] = to_string(*id_); } - jv[sfTransactionType] = jss::ConfidentialMergeInbox; - uint64_t prevInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t prevSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t prevIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox; + auto const prevInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const prevSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const prevIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance) + Throw("Failed to get pre-mergeInbox balances"); + if (submit(arg, jv) == tesSUCCESS) { - uint64_t postInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t postSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t postIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + auto const postInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const postSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const postIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + if (!postInboxBalance || !postSpendingBalance || !postIssuerBalance) + Throw("Failed to get post-mergeInbox balances"); env_.require(requireAny([&]() -> bool { - return postSpendingBalance == - prevInboxBalance + prevSpendingBalance && - postInboxBalance == 0; + return *postSpendingBalance == *prevInboxBalance + *prevSpendingBalance && *postInboxBalance == 0; })); - env_.require(requireAny( - [&]() -> bool { return prevIssuerBalance == postIssuerBalance; })); + env_.require(requireAny([&]() -> bool { return *prevIssuerBalance == *postIssuerBalance; })); - env_.require(requireAny([&]() -> bool { - return postSpendingBalance + postInboxBalance == postIssuerBalance; - })); + env_.require( + requireAny([&]() -> bool { return *postSpendingBalance + *postInboxBalance == *postIssuerBalance; })); } } @@ -1050,12 +1631,27 @@ MPTTester::getIssuanceOutstandingBalance() const auto const sle = env_.current()->read(keylet::mptIssuance(*id_)); if (!sle || !sle->isFieldPresent(sfOutstandingAmount)) - Throw( - "Issuance object does not contain outstanding amount"); + Throw("Issuance object does not contain outstanding amount"); return (*sle)[sfOutstandingAmount]; } +std::uint32_t +MPTTester::getMPTokenVersion(Account const account) const +{ + if (!id_) + Throw("Issuance ID does not exist"); + + auto const sle = env_.current()->read(keylet::mptoken(*id_, account)); + + // return 0 here instead of throwing an exception since tests for + // preclaim will check if the MPToken exists + if (!sle) + return 0; + + return (*sle)[~sfConfidentialBalanceVersion].value_or(0); +} + void MPTTester::convertBack(MPTConvertBack const& arg) { @@ -1065,7 +1661,7 @@ MPTTester::convertBack(MPTConvertBack const& arg) else Throw("Account not specified"); - jv[jss::TransactionType] = jss::ConfidentialConvertBack; + jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack; if (arg.id) jv[sfMPTokenIssuanceID] = to_string(*arg.id); else @@ -1077,70 +1673,267 @@ MPTTester::convertBack(MPTConvertBack const& arg) if (arg.amt) jv[sfMPTAmount.jsonName] = std::to_string(*arg.amt); - if (arg.holderEncryptedAmt) - jv[sfHolderEncryptedAmount.jsonName] = strHex(*arg.holderEncryptedAmt); - else - jv[sfHolderEncryptedAmount.jsonName] = - strHex(encryptAmount(*arg.account, *arg.amt)); - if (arg.issuerEncryptedAmt) - jv[sfIssuerEncryptedAmount.jsonName] = strHex(*arg.issuerEncryptedAmt); + Buffer holderCiphertext; + Buffer issuerCiphertext; + std::optional auditorCiphertext; + Buffer blindingFactor; + + fillConversionCiphertexts(arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor); + + jv[sfBlindingFactor] = strHex(blindingFactor); + + auto const prevInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const prevSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const prevIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + + if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance) + Throw("Failed to get Pre-convertBack balance"); + + Buffer pedersenCommitment; + Buffer pcBlindingFactor = generateBlindingFactor(); + if (arg.pedersenCommitment) + pedersenCommitment = *arg.pedersenCommitment; else - jv[sfIssuerEncryptedAmount.jsonName] = - strHex(encryptAmount(issuer_, *arg.amt)); + pedersenCommitment = getPedersenCommitment(*prevSpendingBalance, pcBlindingFactor); + + jv[sfBalanceCommitment] = strHex(pedersenCommitment); if (arg.proof) - jv[sfZKProof.jsonName] = *arg.proof; + jv[sfZKProof.jsonName] = strHex(*arg.proof); + else + { + auto const version = getMPTokenVersion(*arg.account); + + // if the caller generated ciphertexts themselves, they should also + // generate the proof themselves from the blinding factor + uint256 const contextHash = + getConvertBackContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt, version); + auto const prevEncryptedSpendingBalance = getEncryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + + Buffer proof; + // generate a dummy proof if no encrypted amount field, so that other + // preflight/preclaim are checked + if (!prevEncryptedSpendingBalance) + proof = makeZeroBuffer(ecPedersenProofLength + ecSingleBulletproofLength); + else + { + proof = getConvertBackProof( + *arg.account, + *arg.amt, + contextHash, + { + .pedersenCommitment = pedersenCommitment, + .amt = *prevSpendingBalance, + .encryptedAmt = *prevEncryptedSpendingBalance, + .blindingFactor = pcBlindingFactor, + }); + } + jv[sfZKProof] = strHex(proof); + } auto const holderAmt = getBalance(*arg.account); auto const prevConfidentialOutstanding = getIssuanceConfidentialBalance(); - uint64_t prevInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t prevSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); - uint64_t prevIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + std::optional prevAuditorBalance; + if (arg.auditorEncryptedAmt || auditor_) + { + prevAuditorBalance = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + if (!prevAuditorBalance) + Throw("Failed to get Pre-convertBack balance"); + } if (submit(arg, jv) == tesSUCCESS) { - auto const postConfidentialOutstanding = - getIssuanceConfidentialBalance(); + auto const postConfidentialOutstanding = getIssuanceConfidentialBalance(); env_.require(mptbalance(*this, *arg.account, holderAmt + *arg.amt)); - env_.require(requireAny([&]() -> bool { - return prevConfidentialOutstanding - *arg.amt == - postConfidentialOutstanding; - })); + env_.require(requireAny( + [&]() -> bool { return prevConfidentialOutstanding - *arg.amt == postConfidentialOutstanding; })); - uint64_t postInboxBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); - uint64_t postIssuerBalance = - getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); - uint64_t postSpendingBalance = - getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + auto const postInboxBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX); + auto const postIssuerBalance = getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE); + auto const postSpendingBalance = getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING); + + if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance) + Throw("Failed to get post-convertBack balance"); + + if (arg.auditorEncryptedAmt || auditor_) + { + auto const postAuditorBalance = getDecryptedBalance(*arg.account, AUDITOR_ENCRYPTED_BALANCE); + + if (!postAuditorBalance) + Throw("Failed to get post-convertBack balance"); + + // auditor's encrypted balance is updated correctly + env_.require(requireAny([&]() -> bool { return *prevAuditorBalance - *arg.amt == *postAuditorBalance; })); + } // inbox balance should not change - env_.require(requireAny( - [&]() -> bool { return postInboxBalance == prevInboxBalance; })); + env_.require(requireAny([&]() -> bool { return *postInboxBalance == *prevInboxBalance; })); // issuer's encrypted balance is updated correctly - env_.require(requireAny([&]() -> bool { - return prevIssuerBalance - *arg.amt == postIssuerBalance; - })); + env_.require(requireAny([&]() -> bool { return *prevIssuerBalance - *arg.amt == *postIssuerBalance; })); // holder's spending balance is updated correctly - env_.require(requireAny([&]() -> bool { - return prevSpendingBalance - *arg.amt == postSpendingBalance; - })); + env_.require(requireAny([&]() -> bool { return *prevSpendingBalance - *arg.amt == *postSpendingBalance; })); // sum of holder's inbox and spending balance should equal to issuer's // encrypted balance - env_.require(requireAny([&]() -> bool { - return postInboxBalance + postSpendingBalance == postIssuerBalance; - })); + env_.require( + requireAny([&]() -> bool { return *postInboxBalance + *postSpendingBalance == *postIssuerBalance; })); } } +Buffer +MPTTester::getAmountLinkageProof( + Buffer const& pubKey, + Buffer const& blindingFactor, + uint256 const& contextHash, + PedersenProofParams const& params) const +{ + if (params.blindingFactor.size() != ecBlindingFactorLength || + params.pedersenCommitment.size() != ecPedersenCommitmentLength || pubKey.size() != ecPubKeyLength || + params.encryptedAmt.size() != ecGamalEncryptedTotalLength || blindingFactor.size() != ecBlindingFactorLength) + return makeZeroBuffer(ecPedersenProofLength); + + secp256k1_pubkey c1, c2; + auto const ctx = secp256k1Context(); + if (!secp256k1_ec_pubkey_parse(ctx, &c1, params.encryptedAmt.data(), ecGamalEncryptedLength) || + !secp256k1_ec_pubkey_parse( + ctx, &c2, params.encryptedAmt.data() + ecGamalEncryptedLength, ecGamalEncryptedLength)) + { + return Buffer(); + } + + secp256k1_pubkey pk; + if (secp256k1_ec_pubkey_parse(ctx, &pk, pubKey.data(), ecPubKeyLength) != 1) + return Buffer(); + + secp256k1_pubkey pcm; + if (secp256k1_ec_pubkey_parse(ctx, &pcm, params.pedersenCommitment.data(), ecPedersenCommitmentLength) != 1) + return Buffer(); + + Buffer proof(ecPedersenProofLength); + if (secp256k1_elgamal_pedersen_link_prove( + ctx, + proof.data(), + &c1, + &c2, + &pk, + &pcm, + params.amt, + blindingFactor.data(), + params.blindingFactor.data(), + contextHash.data()) != 1) + { + Throw("Amount Linkage Proof generation failed"); + } + + return proof; +} + +Buffer +MPTTester::getBalanceLinkageProof( + Account const& account, + uint256 const& contextHash, + Buffer const& pubKey, + PedersenProofParams const& params) const +{ + if (params.blindingFactor.size() != ecBlindingFactorLength || + params.pedersenCommitment.size() != ecPedersenCommitmentLength || pubKey.size() != ecPubKeyLength || + params.encryptedAmt.size() != ecGamalEncryptedTotalLength) + return makeZeroBuffer(ecPedersenProofLength); + + secp256k1_pubkey c1, c2; + auto const ctx = secp256k1Context(); + if (!secp256k1_ec_pubkey_parse(ctx, &c1, params.encryptedAmt.data(), ecGamalEncryptedLength) || + !secp256k1_ec_pubkey_parse( + ctx, &c2, params.encryptedAmt.data() + ecGamalEncryptedLength, ecGamalEncryptedLength)) + { + return makeZeroBuffer(ecPedersenProofLength); + } + + secp256k1_pubkey pk; + if (secp256k1_ec_pubkey_parse(ctx, &pk, pubKey.data(), ecPubKeyLength) != 1) + return Buffer(); + + secp256k1_pubkey pcm; + if (secp256k1_ec_pubkey_parse(ctx, &pcm, params.pedersenCommitment.data(), ecPedersenCommitmentLength) != 1) + return Buffer(); + + Buffer proof(ecPedersenProofLength); + + auto const privKey = getPrivKey(account); + if (!privKey || privKey->size() != ecPrivKeyLength) + Throw("Failed to get Pedersen proof private key"); + + if (secp256k1_elgamal_pedersen_link_prove( + ctx, + proof.data(), + &pk, + &c2, + &c1, + &pcm, + params.amt, + privKey->data(), + params.blindingFactor.data(), + contextHash.data()) != 1) + Throw("Pedersen proof generation failed"); + + return proof; +} + +Buffer +MPTTester::getBulletproof( + std::vector const& values, + std::vector const& blindingFactors, + uint256 const& contextHash) const +{ + std::size_t const m = values.size(); + + if (m == 0 || m > 2 || m != blindingFactors.size()) + Throw("getBulletproof: invalid input parameters"); + + for (auto const& bf : blindingFactors) + { + if (bf.size() != ecBlindingFactorLength) + Throw("Invalid blinding factor length"); + } + + // Flatten blinding factors into contiguous memory (m * 32 bytes) + std::vector blindingsFlat(m * ecBlindingFactorLength); + for (std::size_t i = 0; i < m; ++i) + std::memcpy( + blindingsFlat.data() + i * ecBlindingFactorLength, blindingFactors[i].data(), ecBlindingFactorLength); + + secp256k1_pubkey pk_base; + if (secp256k1_mpt_get_h_generator(secp256k1Context(), &pk_base) != 1) + Throw("Failed to get H generator"); + + // Proof size scales with m; use safe upper bound + Buffer bulletproof(4096); + std::size_t proofLen = 4096; + + if (secp256k1_bulletproof_prove_agg( + secp256k1Context(), + bulletproof.data(), + &proofLen, + values.data(), + blindingsFlat.data(), + m, + &pk_base, + contextHash.data()) != 1) + { + Throw("Bulletproof generation failed"); + } + + std::size_t const expectedLen = (m == 1) ? ecSingleBulletproofLength : ecDoubleBulletproofLength; + if (proofLen != expectedLen) + Throw("Unexpected bulletproof length"); + + return Buffer(bulletproof.data(), proofLen); +} + } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/multisign.cpp b/src/test/jtx/impl/multisign.cpp index fc6163a2f3..54bde3ebb9 100644 --- a/src/test/jtx/impl/multisign.cpp +++ b/src/test/jtx/impl/multisign.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,15 +7,12 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { Json::Value -signers( - Account const& account, - std::uint32_t quorum, - std::vector const& v) +signers(Account const& account, std::uint32_t quorum, std::vector const& v) { Json::Value jv; jv[jss::Account] = account.human(); @@ -97,10 +75,8 @@ msig::operator()(Env& env, JTx& jt) const jo[jss::SigningPubKey] = strHex(e.sig.pk().slice()); Serializer ss{buildMultiSigningData(*st, e.acct.id())}; - auto const sig = ripple::sign( - *publicKeyType(e.sig.pk().slice()), e.sig.sk(), ss.slice()); - jo[sfTxnSignature.getJsonName()] = - strHex(Slice{sig.data(), sig.size()}); + auto const sig = xrpl::sign(*publicKeyType(e.sig.pk().slice()), e.sig.sk(), ss.slice()); + jo[sfTxnSignature.getJsonName()] = strHex(Slice{sig.data(), sig.size()}); } }; if (!subField) @@ -111,4 +87,4 @@ msig::operator()(Env& env, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/offer.cpp b/src/test/jtx/impl/offer.cpp index f48c0f2d21..bbcfbf07c1 100644 --- a/src/test/jtx/impl/offer.cpp +++ b/src/test/jtx/impl/offer.cpp @@ -1,36 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { Json::Value -offer( - Account const& account, - STAmount const& takerPays, - STAmount const& takerGets, - std::uint32_t flags) +offer(Account const& account, STAmount const& takerPays, STAmount const& takerGets, std::uint32_t flags) { Json::Value jv; jv[jss::Account] = account.human(); @@ -54,4 +31,4 @@ offer_cancel(Account const& account, std::uint32_t offerSeq) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/owners.cpp b/src/test/jtx/impl/owners.cpp index b55986fccb..ee6efc171c 100644 --- a/src/test/jtx/impl/owners.cpp +++ b/src/test/jtx/impl/owners.cpp @@ -1,45 +1,21 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace detail { std::uint32_t owned_count_of(ReadView const& view, AccountID const& id, LedgerEntryType type) { std::uint32_t count = 0; - forEachItem( - view, id, [&count, type](std::shared_ptr const& sle) { - if (sle->getType() == type) - ++count; - }); + forEachItem(view, id, [&count, type](std::shared_ptr const& sle) { + if (sle->getType() == type) + ++count; + }); return count; } void -owned_count_helper( - test::jtx::Env& env, - AccountID const& id, - LedgerEntryType type, - std::uint32_t value) +owned_count_helper(test::jtx::Env& env, AccountID const& id, LedgerEntryType type, std::uint32_t value) { env.test.expect(owned_count_of(*env.current(), id, type) == value); } @@ -57,4 +33,4 @@ owners::operator()(Env& env) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/paths.cpp b/src/test/jtx/impl/paths.cpp index f230305469..e26f214fe4 100644 --- a/src/test/jtx/impl/paths.cpp +++ b/src/test/jtx/impl/paths.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -49,8 +30,7 @@ paths::operator()(Env& env, JTx& jt) const } Pathfinder pf( - std::make_shared( - env.current(), env.app().journal("RippleLineCache")), + std::make_shared(env.current(), env.app().journal("RippleLineCache")), from, to, in_.currency, @@ -117,4 +97,4 @@ path::operator()(Env& env, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/pay.cpp b/src/test/jtx/impl/pay.cpp index d1d994059e..9e927c6270 100644 --- a/src/test/jtx/impl/pay.cpp +++ b/src/test/jtx/impl/pay.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,4 +27,4 @@ pay(Account const& account, Account const& to, AnyAmount amount) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/permissioned_dex.cpp b/src/test/jtx/impl/permissioned_dex.cpp index 4b09a11880..87b7896663 100644 --- a/src/test/jtx/impl/permissioned_dex.cpp +++ b/src/test/jtx/impl/permissioned_dex.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -82,4 +63,4 @@ PermissionedDEX::PermissionedDEX(Env& env) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/permissioned_domains.cpp b/src/test/jtx/impl/permissioned_domains.cpp index 441ee325c8..fb802cf084 100644 --- a/src/test/jtx/impl/permissioned_domains.cpp +++ b/src/test/jtx/impl/permissioned_domains.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace pdomain { @@ -27,10 +8,7 @@ namespace pdomain { // helpers // Make json for PermissionedDomainSet transaction Json::Value -setTx( - AccountID const& account, - Credentials const& credentials, - std::optional domain) +setTx(AccountID const& account, Credentials const& credentials, std::optional domain) { Json::Value jv; jv[sfTransactionType] = jss::PermissionedDomainSet; @@ -81,8 +59,7 @@ getObjects(Account const& account, Env& env, bool withType) if (withType) { // impossible to get there Throw( - "Invalid object type: " + - object["LedgerEntryType"].asString()); // LCOV_EXCL_LINE + "Invalid object type: " + object["LedgerEntryType"].asString()); // LCOV_EXCL_LINE } continue; } @@ -102,8 +79,7 @@ objectExists(uint256 const& objID, Env& env) Json::Value params; params[jss::index] = to_string(objID); - auto const result = - env.rpc("json", "ledger_entry", to_string(params))["result"]; + auto const result = env.rpc("json", "ledger_entry", to_string(params))["result"]; if ((result["status"] == "error") && (result["error"] == "entryNotFound")) return false; @@ -119,9 +95,7 @@ objectExists(uint256 const& objID, Env& env) // Extract credentials from account_object object Credentials -credentialsFromJson( - Json::Value const& object, - std::unordered_map const& human2Acc) +credentialsFromJson(Json::Value const& object, std::unordered_map const& human2Acc) { Credentials ret; Json::Value credentials(Json::arrayValue); @@ -133,9 +107,7 @@ credentialsFromJson( auto const& issuer = obj[jss::Issuer]; auto const& credentialType = obj["CredentialType"]; auto blob = strUnHex(credentialType.asString()).value(); - ret.push_back( - {human2Acc.at(issuer.asString()), - std::string(blob.begin(), blob.end())}); + ret.push_back({human2Acc.at(issuer.asString()), std::string(blob.begin(), blob.end())}); } return ret; } @@ -161,13 +133,11 @@ getNewDomain(std::shared_ptr const& meta) for (auto const& node : a) { - if (!node.isMember("CreatedNode") || - node["CreatedNode"]["LedgerEntryType"] != "PermissionedDomain") + if (!node.isMember("CreatedNode") || node["CreatedNode"]["LedgerEntryType"] != "PermissionedDomain") { continue; } - std::ignore = - ret.parseHex(node["CreatedNode"]["LedgerIndex"].asString()); + std::ignore = ret.parseHex(node["CreatedNode"]["LedgerIndex"].asString()); break; } @@ -177,4 +147,4 @@ getNewDomain(std::shared_ptr const& meta) } // namespace pdomain } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/quality2.cpp b/src/test/jtx/impl/quality2.cpp index 46f36cb6d6..bbd0cff319 100644 --- a/src/test/jtx/impl/quality2.cpp +++ b/src/test/jtx/impl/quality2.cpp @@ -1,39 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { -qualityInPercent::qualityInPercent(double percent) - : qIn_(static_cast((percent / 100) * QUALITY_ONE)) +qualityInPercent::qualityInPercent(double percent) : qIn_(static_cast((percent / 100) * QUALITY_ONE)) { assert(percent <= 400 && percent >= 0); } -qualityOutPercent::qualityOutPercent(double percent) - : qOut_(static_cast((percent / 100) * QUALITY_ONE)) +qualityOutPercent::qualityOutPercent(double percent) : qOut_(static_cast((percent / 100) * QUALITY_ONE)) { assert(percent <= 400 && percent >= 0); } @@ -70,4 +49,4 @@ qualityOutPercent::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/rate.cpp b/src/test/jtx/impl/rate.cpp index 0526cdc28f..b4e9b2cb60 100644 --- a/src/test/jtx/impl/rate.cpp +++ b/src/test/jtx/impl/rate.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -42,4 +23,4 @@ rate(Account const& account, double multiplier) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/regkey.cpp b/src/test/jtx/impl/regkey.cpp index cff2de3e8e..a2e2198eee 100644 --- a/src/test/jtx/impl/regkey.cpp +++ b/src/test/jtx/impl/regkey.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,4 +27,4 @@ regkey(Account const& account, Account const& signer) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/sendmax.cpp b/src/test/jtx/impl/sendmax.cpp index 168ce4659d..f117458cfa 100644 --- a/src/test/jtx/impl/sendmax.cpp +++ b/src/test/jtx/impl/sendmax.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -33,4 +14,4 @@ sendmax::operator()(Env& env, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/seq.cpp b/src/test/jtx/impl/seq.cpp index 82f0e98b4c..99c6ddbf0d 100644 --- a/src/test/jtx/impl/seq.cpp +++ b/src/test/jtx/impl/seq.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -37,4 +18,4 @@ seq::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/sig.cpp b/src/test/jtx/impl/sig.cpp index 6ea1c153cb..3ea7f669a7 100644 --- a/src/test/jtx/impl/sig.cpp +++ b/src/test/jtx/impl/sig.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -50,4 +31,4 @@ sig::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/tag.cpp b/src/test/jtx/impl/tag.cpp index 9a8c491da2..8321322f75 100644 --- a/src/test/jtx/impl/tag.cpp +++ b/src/test/jtx/impl/tag.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -37,4 +18,4 @@ stag::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/testline.cpp b/src/test/jtx/impl/testline.cpp new file mode 100644 index 0000000000..fbcb1d2de7 --- /dev/null +++ b/src/test/jtx/impl/testline.cpp @@ -0,0 +1,15 @@ +#include + +namespace xrpl { +namespace test { +namespace jtx { + +void +testline::operator()(Env&, JTx& jt) const +{ + jt.testLine = line_; +} + +} // namespace jtx +} // namespace test +} // namespace xrpl diff --git a/src/test/jtx/impl/ticket.cpp b/src/test/jtx/impl/ticket.cpp index ef1ffd416b..2cb1826bbb 100644 --- a/src/test/jtx/impl/ticket.cpp +++ b/src/test/jtx/impl/ticket.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -49,4 +30,4 @@ use::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/token.cpp b/src/test/jtx/impl/token.cpp index 3bc4e9bd02..172bd75bc7 100644 --- a/src/test/jtx/impl/token.cpp +++ b/src/test/jtx/impl/token.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace token { @@ -73,8 +54,7 @@ getNextID( std::uint16_t xferFee) { // Get the nftSeq from the account root of the issuer. - std::uint32_t const nftSeq = { - env.le(issuer)->at(~sfMintedNFTokens).value_or(0)}; + std::uint32_t const nftSeq = {env.le(issuer)->at(~sfMintedNFTokens).value_or(0)}; return token::getID(env, issuer, nfTokenTaxon, nftSeq, flags, xferFee); } @@ -89,10 +69,8 @@ getID( { // We must add issuer's FirstNFTokenSequence to offset the starting NFT // sequence number. - nftSeq += - env.le(issuer)->at(~sfFirstNFTokenSequence).value_or(env.seq(issuer)); - return ripple::NFTokenMint::createNFTokenID( - flags, xferFee, issuer, nft::toTaxon(nfTokenTaxon), nftSeq); + nftSeq += env.le(issuer)->at(~sfFirstNFTokenSequence).value_or(env.seq(issuer)); + return xrpl::NFTokenMint::createNFTokenID(flags, xferFee, issuer, nft::toTaxon(nfTokenTaxon), nftSeq); } Json::Value @@ -106,10 +84,7 @@ burn(jtx::Account const& account, uint256 const& nftokenID) } Json::Value -createOffer( - jtx::Account const& account, - uint256 const& nftokenID, - STAmount const& amount) +createOffer(jtx::Account const& account, uint256 const& nftokenID, STAmount const& amount) { Json::Value jv; jv[sfAccount.jsonName] = account.human(); @@ -154,17 +129,13 @@ cancelOfferImpl(jtx::Account const& account, T const& nftokenOffers) } Json::Value -cancelOffer( - jtx::Account const& account, - std::initializer_list const& nftokenOffers) +cancelOffer(jtx::Account const& account, std::initializer_list const& nftokenOffers) { return cancelOfferImpl(account, nftokenOffers); } Json::Value -cancelOffer( - jtx::Account const& account, - std::vector const& nftokenOffers) +cancelOffer(jtx::Account const& account, std::vector const& nftokenOffers) { return cancelOfferImpl(account, nftokenOffers); } @@ -196,10 +167,7 @@ acceptSellOffer(jtx::Account const& account, uint256 const& offerIndex) } Json::Value -brokerOffers( - jtx::Account const& account, - uint256 const& buyOfferIndex, - uint256 const& sellOfferIndex) +brokerOffers(jtx::Account const& account, uint256 const& buyOfferIndex, uint256 const& sellOfferIndex) { Json::Value jv; jv[sfAccount.jsonName] = account.human(); @@ -242,4 +210,4 @@ modify(jtx::Account const& account, uint256 const& nftokenID) } // namespace token } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/trust.cpp b/src/test/jtx/impl/trust.cpp index 5e9eadca8d..08cd4ef94c 100644 --- a/src/test/jtx/impl/trust.cpp +++ b/src/test/jtx/impl/trust.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -46,11 +27,7 @@ trust(Account const& account, STAmount const& amount, std::uint32_t flags) // authorises peer (third function parameter) to hold a certain currency // (amount, the second function parameter) Json::Value -trust( - Account const& account, - STAmount const& amount, - Account const& peer, - std::uint32_t flags) +trust(Account const& account, STAmount const& amount, Account const& peer, std::uint32_t flags) { if (isXRP(amount)) Throw("trust() requires IOU"); @@ -66,10 +43,7 @@ trust( } Json::Value -claw( - Account const& account, - STAmount const& amount, - std::optional const& mptHolder) +claw(Account const& account, STAmount const& amount, std::optional const& mptHolder) { Json::Value jv; jv[jss::Account] = account.human(); @@ -84,4 +58,4 @@ claw( } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/txflags.cpp b/src/test/jtx/impl/txflags.cpp index 12c9cfeb83..7b49f9380b 100644 --- a/src/test/jtx/impl/txflags.cpp +++ b/src/test/jtx/impl/txflags.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -33,4 +14,4 @@ txflags::operator()(Env&, JTx& jt) const } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/utility.cpp b/src/test/jtx/impl/utility.cpp index fbdbaee4ef..7332358031 100644 --- a/src/test/jtx/impl/utility.cpp +++ b/src/test/jtx/impl/utility.cpp @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -#include #include #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -50,7 +30,7 @@ sign(Json::Value& jv, Account const& account, Json::Value& sigObject) Serializer ss; ss.add32(HashPrefix::txSign); parse(jv).addWithoutSigningFields(ss); - auto const sig = ripple::sign(account.pk(), account.sk(), ss.slice()); + auto const sig = xrpl::sign(account.pk(), account.sk(), ss.slice()); sigObject[jss::TxnSignature] = strHex(Slice{sig.data(), sig.size()}); } @@ -83,10 +63,7 @@ fill_seq(Json::Value& jv, ReadView const& view) } Json::Value -cmdToJSONRPC( - std::vector const& args, - beast::Journal j, - unsigned int apiVersion) +cmdToJSONRPC(std::vector const& args, beast::Journal j, unsigned int apiVersion) { Json::Value jv = Json::Value(Json::objectValue); auto const paramsObj = rpcCmdToJson(args, jv, apiVersion, j); @@ -95,14 +72,12 @@ cmdToJSONRPC( jv.clear(); // Allow parser to rewrite method. - jv[jss::method] = paramsObj.isMember(jss::method) - ? paramsObj[jss::method].asString() - : args[0]; + jv[jss::method] = paramsObj.isMember(jss::method) ? paramsObj[jss::method].asString() : args[0]; // If paramsObj is not empty, put it in a [params] array. if (paramsObj.begin() != paramsObj.end()) { - auto& paramsArray = Json::setArray(jv, jss::params); + auto& paramsArray = jv[jss::params] = Json::arrayValue; paramsArray.append(paramsObj); } if (paramsObj.isMember(jss::jsonrpc)) @@ -116,4 +91,4 @@ cmdToJSONRPC( } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/vault.cpp b/src/test/jtx/impl/vault.cpp index 663c42c6ee..90250aece0 100644 --- a/src/test/jtx/impl/vault.cpp +++ b/src/test/jtx/impl/vault.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -38,7 +19,6 @@ Vault::create(CreateArgs const& args) jv[jss::TransactionType] = jss::VaultCreate; jv[jss::Account] = args.owner.human(); jv[jss::Asset] = to_json(args.asset); - jv[jss::Fee] = STAmount(env.current()->fees().increment).getJson(); if (args.flags) jv[jss::Flags] = *args.flags; return {jv, keylet}; @@ -101,4 +81,4 @@ Vault::clawback(ClawbackArgs const& args) } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/impl/xchain_bridge.cpp b/src/test/jtx/impl/xchain_bridge.cpp index 9e8fa4795f..0f78ed3029 100644 --- a/src/test/jtx/impl/xchain_bridge.cpp +++ b/src/test/jtx/impl/xchain_bridge.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -80,8 +61,7 @@ bridge_create( jv[sfXChainBridge.getJsonName()] = bridge; jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::none); if (minAccountCreate) - jv[sfMinAccountCreateAmount.getJsonName()] = - minAccountCreate->getJson(JsonOptions::none); + jv[sfMinAccountCreateAmount.getJsonName()] = minAccountCreate->getJson(JsonOptions::none); jv[jss::TransactionType] = jss::XChainCreateBridge; return jv; @@ -99,11 +79,9 @@ bridge_modify( jv[jss::Account] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; if (reward) - jv[sfSignatureReward.getJsonName()] = - reward->getJson(JsonOptions::none); + jv[sfSignatureReward.getJsonName()] = reward->getJson(JsonOptions::none); if (minAccountCreate) - jv[sfMinAccountCreateAmount.getJsonName()] = - minAccountCreate->getJson(JsonOptions::none); + jv[sfMinAccountCreateAmount.getJsonName()] = minAccountCreate->getJson(JsonOptions::none); jv[jss::TransactionType] = jss::XChainModifyBridge; return jv; @@ -182,8 +160,7 @@ sidechain_xchain_account_create( jv[sfXChainBridge.getJsonName()] = bridge; jv[sfDestination.getJsonName()] = dst.human(); jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::none); - jv[sfSignatureReward.getJsonName()] = - reward.value.getJson(JsonOptions::none); + jv[sfSignatureReward.getJsonName()] = reward.value.getJson(JsonOptions::none); jv[jss::TransactionType] = jss::XChainAccountCreateCommit; return jv; @@ -206,15 +183,7 @@ claim_attestation( auto const& pk = signer.account.pk(); auto const& sk = signer.account.sk(); auto const sig = sign_claim_attestation( - pk, - sk, - stBridge, - sendingAccount, - sendingAmount.value, - rewardAccount, - wasLockingChainSend, - claimID, - dst); + pk, sk, stBridge, sendingAccount, sendingAmount.value, rewardAccount, wasLockingChainSend, claimID, dst); Json::Value result; @@ -225,13 +194,11 @@ claim_attestation( result[sfPublicKey.getJsonName()] = strHex(pk.slice()); result[sfSignature.getJsonName()] = strHex(sig); result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); - result[sfAmount.getJsonName()] = - sendingAmount.value.getJson(JsonOptions::none); + result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::none); result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; - result[sfXChainClaimID.getJsonName()] = - STUInt64{claimID}.getJson(JsonOptions::none); + result[sfXChainClaimID.getJsonName()] = STUInt64{claimID}.getJson(JsonOptions::none); if (dst) result[sfDestination.getJsonName()] = toBase58(*dst); @@ -278,16 +245,13 @@ create_account_attestation( result[sfPublicKey.getJsonName()] = strHex(pk.slice()); result[sfSignature.getJsonName()] = strHex(sig); result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); - result[sfAmount.getJsonName()] = - sendingAmount.value.getJson(JsonOptions::none); + result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::none); result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; - result[sfXChainAccountCreateCount.getJsonName()] = - STUInt64{createCount}.getJson(JsonOptions::none); + result[sfXChainAccountCreateCount.getJsonName()] = STUInt64{createCount}.getJson(JsonOptions::none); result[sfDestination.getJsonName()] = toBase58(dst); - result[sfSignatureReward.getJsonName()] = - rewardAmount.value.getJson(JsonOptions::none); + result[sfSignatureReward.getJsonName()] = rewardAmount.value.getJson(JsonOptions::none); result[jss::TransactionType] = jss::XChainAddAccountCreateAttestation; @@ -385,8 +349,7 @@ XChainBridgeObjects::XChainBridgeObjects() , scuGw("scuGw") , mcUSD(mcGw["USD"]) , scUSD(scGw["USD"]) - , jvXRPBridgeRPC( - bridge_rpc(mcDoor, xrpIssue(), Account::master, xrpIssue())) + , jvXRPBridgeRPC(bridge_rpc(mcDoor, xrpIssue(), Account::master, xrpIssue())) , jvb(bridge(mcDoor, xrpIssue(), Account::master, xrpIssue())) , jvub(bridge(mcuDoor, xrpIssue(), Account::master, xrpIssue())) , features(testable_amendments() | FeatureBitset{featureXChainBridge}) @@ -397,9 +360,7 @@ XChainBridgeObjects::XChainBridgeObjects() for (int i = 0; i < numSigners; ++i) { using namespace std::literals; - auto const a = Account( - "signer_"s + std::to_string(i), - (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + auto const a = Account("signer_"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); result.emplace_back(a); } return result; @@ -411,9 +372,7 @@ XChainBridgeObjects::XChainBridgeObjects() for (int i = 0; i < numSigners; ++i) { using namespace std::literals; - auto const a = Account( - "alt_signer_"s + std::to_string(i), - (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + auto const a = Account("alt_signer_"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); result.emplace_back(a); } return result; @@ -440,23 +399,12 @@ XChainBridgeObjects::XChainBridgeObjects() }()) , quorum(UT_XCHAIN_DEFAULT_QUORUM) , reward(XRP(1)) - , split_reward_quorum( - divide(reward, STAmount(UT_XCHAIN_DEFAULT_QUORUM), reward.issue())) - , split_reward_everyone(divide( - reward, - STAmount(UT_XCHAIN_DEFAULT_NUM_SIGNERS), - reward.issue())) + , split_reward_quorum(divide(reward, STAmount(UT_XCHAIN_DEFAULT_QUORUM), reward.issue())) + , split_reward_everyone(divide(reward, STAmount(UT_XCHAIN_DEFAULT_NUM_SIGNERS), reward.issue())) , tiny_reward(drops(37)) - , tiny_reward_split((divide( - tiny_reward, - STAmount(UT_XCHAIN_DEFAULT_QUORUM), - tiny_reward.issue()))) + , tiny_reward_split((divide(tiny_reward, STAmount(UT_XCHAIN_DEFAULT_QUORUM), tiny_reward.issue()))) , tiny_reward_remainder( - tiny_reward - - multiply( - tiny_reward_split, - STAmount(UT_XCHAIN_DEFAULT_QUORUM), - tiny_reward.issue())) + tiny_reward - multiply(tiny_reward_split, STAmount(UT_XCHAIN_DEFAULT_QUORUM), tiny_reward.issue())) , one_xrp(XRP(1)) , xrp_dust(divide(one_xrp, STAmount(10000), one_xrp.issue())) { @@ -483,8 +431,7 @@ void XChainBridgeObjects::createScBridgeObjects(Env& scEnv) { STAmount xrp_funds{XRP(10000)}; - scEnv.fund( - xrp_funds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); + scEnv.fund(xrp_funds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); // Signer's list must match the attestation signers scEnv(jtx::signers(Account::master, signers.size(), signers)); @@ -505,4 +452,4 @@ XChainBridgeObjects::createBridgeObjects(Env& mcEnv, Env& scEnv) } } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/invoice_id.h b/src/test/jtx/invoice_id.h index 99abd22781..fd1b7ae45b 100644 --- a/src/test/jtx/invoice_id.h +++ b/src/test/jtx/invoice_id.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_INVOICE_ID_H_INCLUDED -#define RIPPLE_TEST_JTX_INVOICE_ID_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -41,5 +21,4 @@ public: }; } // namespace jtx } // namespace test -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/test/jtx/jtx_json.h b/src/test/jtx/jtx_json.h index 47f5a3c223..c7f52fe283 100644 --- a/src/test/jtx/jtx_json.h +++ b/src/test/jtx/jtx_json.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_JSON_H_INCLUDED -#define RIPPLE_TEST_JTX_JSON_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -59,6 +39,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/last_ledger_sequence.h b/src/test/jtx/last_ledger_sequence.h index 30d5f97335..540d6ff384 100644 --- a/src/test/jtx/last_ledger_sequence.h +++ b/src/test/jtx/last_ledger_sequence.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_LAST_LEDGER_SEQUENCE_H_INCLUDED -#define RIPPLE_TEST_JTX_LAST_LEDGER_SEQUENCE_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -42,6 +22,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/ledgerStateFix.h b/src/test/jtx/ledgerStateFix.h index bf0a56cabe..7adc863cb4 100644 --- a/src/test/jtx/ledgerStateFix.h +++ b/src/test/jtx/ledgerStateFix.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_LEDGER_STATE_FIX_H_INCLUDED -#define RIPPLE_TEST_JTX_LEDGER_STATE_FIX_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -39,6 +19,4 @@ nftPageLinks(jtx::Account const& acct, jtx::Account const& owner); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/memo.h b/src/test/jtx/memo.h index 161dc70f39..2371490b30 100644 --- a/src/test/jtx/memo.h +++ b/src/test/jtx/memo.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_MEMO_H_INCLUDED -#define RIPPLE_TEST_JTX_MEMO_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -39,10 +19,7 @@ private: std::string type_; public: - memo( - std::string const& data, - std::string const& format, - std::string const& type) + memo(std::string const& data, std::string const& format, std::string const& type) : data_(data), format_(format), type_(type) { } @@ -51,13 +28,13 @@ public: operator()(Env&, JTx& jt) const; }; -class memodata +class memo_data { private: std::string s_; public: - memodata(std::string const& s) : s_(s) + memo_data(std::string const& s) : s_(s) { } @@ -65,13 +42,13 @@ public: operator()(Env&, JTx& jt) const; }; -class memoformat +class memo_format { private: std::string s_; public: - memoformat(std::string const& s) : s_(s) + memo_format(std::string const& s) : s_(s) { } @@ -79,61 +56,13 @@ public: operator()(Env&, JTx& jt) const; }; -class memotype +class memo_type { private: std::string s_; public: - memotype(std::string const& s) : s_(s) - { - } - - void - operator()(Env&, JTx& jt) const; -}; - -class memondata -{ -private: - std::string format_; - std::string type_; - -public: - memondata(std::string const& format, std::string const& type) - : format_(format), type_(type) - { - } - - void - operator()(Env&, JTx& jt) const; -}; - -class memonformat -{ -private: - std::string data_; - std::string type_; - -public: - memonformat(std::string const& data, std::string const& type) - : data_(data), type_(type) - { - } - - void - operator()(Env&, JTx& jt) const; -}; - -class memontype -{ -private: - std::string data_; - std::string format_; - -public: - memontype(std::string const& data, std::string const& format) - : data_(data), format_(format) + memo_type(std::string const& s) : s_(s) { } @@ -143,6 +72,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/mpt.h b/src/test/jtx/mpt.h index aaff78da09..780566a484 100644 --- a/src/test/jtx/mpt.h +++ b/src/test/jtx/mpt.h @@ -1,43 +1,38 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_MPT_H_INCLUDED -#define RIPPLE_TEST_JTX_MPT_H_INCLUDED +#pragma once #include #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { class MPTTester; -// Generates a syntactically valid placeholder ciphertext -ripple::Buffer -generatePlaceholderCiphertext(); +auto const MPTDEXFlags = tfMPTCanTrade | tfMPTCanTransfer; + +/*Helper lambda to create a zero-initialized buffer. +WHY THIS IS NEEDED: In C++, xrpl::Buffer(size) allocates uninitialized heap memory. +Because CI runs unit tests sequentially in the same process, uninitialized memory +often recycles "ghost data" (like valid SECP256k1 keys or Pedersen commitments) +left over from previously executed tests. +When testing malformed cryptography paths, passing uninitialized memory might +accidentally supply a valid curve point, causing the ledger's preflight checks +to falsely succeed and return tecBAD_PROOF instead of the expected temMALFORMED. +Explicitly zeroing the buffer guarantees it fails structural validation. */ +static auto makeZeroBuffer = [](size_t size) { + Buffer b(size); + if (size > 0) + std::memset(b.data(), 0, size); + return b; +}; // Check flags settings on MPT create class mptflags @@ -48,10 +43,7 @@ private: std::optional holder_; public: - mptflags( - MPTTester& tester, - std::uint32_t flags, - std::optional const& holder = std::nullopt) + mptflags(MPTTester& tester, std::uint32_t flags, std::optional const& holder = std::nullopt) : tester_(tester), flags_(flags), holder_(holder) { } @@ -92,31 +84,60 @@ public: operator()(Env& env) const; }; -struct MPTInit -{ - std::vector holders = {}; - PrettyAmount const xrp = XRP(10'000); - PrettyAmount const xrpHolders = XRP(10'000); - bool fund = true; - bool close = true; -}; -static MPTInit const mptInitNoFund{.fund = false}; +using Holders = std::vector; struct MPTCreate { + static inline std::vector AllHolders = {}; + std::optional issuer = std::nullopt; std::optional maxAmt = std::nullopt; std::optional assetScale = std::nullopt; std::optional transferFee = std::nullopt; std::optional metadata = std::nullopt; std::optional ownerCount = std::nullopt; std::optional holderCount = std::nullopt; - bool fund = true; + // authorize if seated. + // if empty vector then authorize all holders + std::optional> authorize = std::nullopt; + // pay if seated. if authorize is not seated then authorize. + // if empty vector then pay to either authorize or all holders. + std::optional, std::uint64_t>> pay = std::nullopt; std::optional flags = {0}; std::optional mutableFlags = std::nullopt; + bool authHolder = false; std::optional domainID = std::nullopt; std::optional err = std::nullopt; }; +struct MPTInit +{ + Holders holders = {}; + std::optional auditor = std::nullopt; + PrettyAmount const xrp = XRP(10'000); + PrettyAmount const xrpHolders = XRP(10'000); + bool fund = true; + bool close = true; + // create MPTIssuanceID if seated and follow rules for MPTCreate args + std::optional create = std::nullopt; +}; +static MPTInit const mptInitNoFund{.fund = false}; + +struct MPTInitDef +{ + Env& env; + Account issuer; + Holders holders = {}; + std::optional auditor = std::nullopt; + std::uint16_t transferFee = 0; + std::optional pay = std::nullopt; + std::uint32_t flags = MPTDEXFlags; + bool authHolder = false; + bool fund = false; + bool close = true; + std::optional maxAmt = std::nullopt; + std::optional err = std::nullopt; +}; + struct MPTDestroy { std::optional issuer = std::nullopt; @@ -141,7 +162,7 @@ struct MPTAuthorize struct MPTSet { std::optional account = std::nullopt; - std::optional holder = std::nullopt; + std::optional> holder = std::nullopt; std::optional id = std::nullopt; std::optional ownerCount = std::nullopt; std::optional holderCount = std::nullopt; @@ -151,7 +172,8 @@ struct MPTSet std::optional metadata = std::nullopt; std::optional delegate = std::nullopt; std::optional domainID = std::nullopt; - std::optional pubKey = std::nullopt; + std::optional issuerPubKey = std::nullopt; + std::optional auditorPubKey = std::nullopt; std::optional err = std::nullopt; }; @@ -161,9 +183,18 @@ struct MPTConvert std::optional id = std::nullopt; std::optional amt = std::nullopt; std::optional proof = std::nullopt; + std::optional fillAuditorEncryptedAmt = true; + // indicates whether to autofill schnorr proof. + // default : auto generate proof if holderPubKey is present. + // true: force proof generation. + // false: force proof omission. + std::optional fillSchnorrProof = std::nullopt; std::optional holderPubKey = std::nullopt; std::optional holderEncryptedAmt = std::nullopt; std::optional issuerEncryptedAmt = std::nullopt; + std::optional auditorEncryptedAmt = std::nullopt; + + std::optional blindingFactor = std::nullopt; std::optional ownerCount = std::nullopt; std::optional holderCount = std::nullopt; std::optional flags = std::nullopt; @@ -191,7 +222,12 @@ struct MPTConfidentialSend std::optional senderEncryptedAmt = std::nullopt; std::optional destEncryptedAmt = std::nullopt; std::optional issuerEncryptedAmt = std::nullopt; + std::optional auditorEncryptedAmt = std::nullopt; std::optional> credentials = std::nullopt; + // not an txn param, only used for autofilling + std::optional blindingFactor = std::nullopt; + std::optional amountCommitment = std::nullopt; + std::optional balanceCommitment = std::nullopt; std::optional ownerCount = std::nullopt; std::optional holderCount = std::nullopt; std::optional flags = std::nullopt; @@ -203,9 +239,14 @@ struct MPTConvertBack std::optional account = std::nullopt; std::optional id = std::nullopt; std::optional amt = std::nullopt; - std::optional proof = std::nullopt; + std::optional proof = std::nullopt; std::optional holderEncryptedAmt = std::nullopt; std::optional issuerEncryptedAmt = std::nullopt; + std::optional auditorEncryptedAmt = std::nullopt; + std::optional fillAuditorEncryptedAmt = true; + // not an txn param, only used for autofilling + std::optional blindingFactor = std::nullopt; + std::optional pedersenCommitment = std::nullopt; std::optional ownerCount = std::nullopt; std::optional holderCount = std::nullopt; std::optional flags = std::nullopt; @@ -225,11 +266,24 @@ struct MPTConfidentialClawback std::optional err = std::nullopt; }; +/** + * @brief Stores the parameters that are exclusively used to generate a + * pedersen linkage proof + */ +struct PedersenProofParams +{ + Buffer const pedersenCommitment; + uint64_t const amt; // either spending balance or value to be transferred + Buffer const encryptedAmt; + Buffer const blindingFactor; +}; + class MPTTester { Env& env_; - Account const& issuer_; + Account const issuer_; std::unordered_map const holders_; + std::optional const auditor_; std::optional id_; bool close_; std::unordered_map pubKeys; @@ -240,22 +294,46 @@ public: ISSUER_ENCRYPTED_BALANCE, HOLDER_ENCRYPTED_INBOX, HOLDER_ENCRYPTED_SPENDING, + AUDITOR_ENCRYPTED_BALANCE, }; MPTTester(Env& env, Account const& issuer, MPTInit const& constr = {}); + MPTTester(MPTInitDef const& constr); + MPTTester( + Env& env, + Account const& issuer, + MPTID const& id, + std::vector const& holders = {}, + bool close = true); + operator MPT() const; void create(MPTCreate const& arg = MPTCreate{}); + static Json::Value + createJV(MPTCreate const& arg = MPTCreate{}); + void destroy(MPTDestroy const& arg = MPTDestroy{}); + static Json::Value + destroyJV(MPTDestroy const& arg = MPTDestroy{}); + void authorize(MPTAuthorize const& arg = MPTAuthorize{}); + static Json::Value + authorizeJV(MPTAuthorize const& arg = MPTAuthorize{}); + + void + authorizeHolders(Holders const& holders); + void set(MPTSet const& set = {}); + static Json::Value + setJV(MPTSet const& set = {}); + void convert(MPTConvert const& arg = MPTConvert{}); @@ -269,15 +347,13 @@ public: convertBack(MPTConvertBack const& arg = MPTConvertBack{}); void - confidentialClaw( - MPTConfidentialClawback const& arg = MPTConfidentialClawback{}); + confidentialClaw(MPTConfidentialClawback const& arg = MPTConfidentialClawback{}); [[nodiscard]] bool checkDomainID(std::optional expected) const; [[nodiscard]] bool - checkMPTokenAmount(Account const& holder, std::int64_t expectedAmount) - const; + checkMPTokenAmount(Account const& holder, std::int64_t expectedAmount) const; [[nodiscard]] bool checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const; @@ -286,9 +362,7 @@ public: checkIssuanceConfidentialBalance(std::int64_t expectedAmount) const; [[nodiscard]] bool - checkFlags( - uint32_t const expectedFlags, - std::optional const& holder = std::nullopt) const; + checkFlags(uint32_t const expectedFlags, std::optional const& holder = std::nullopt) const; [[nodiscard]] bool checkMetadata(std::string const& metadata) const; @@ -307,6 +381,7 @@ public: { return issuer_; } + Account const& holder(std::string const& h) const; @@ -318,11 +393,7 @@ public: std::optional> credentials = std::nullopt); void - claw( - Account const& issuer, - Account const& holder, - std::int64_t amount, - std::optional err = std::nullopt); + claw(Account const& issuer, Account const& holder, std::int64_t amount, std::optional err = std::nullopt); PrettyAmount mpt(std::int64_t amount) const; @@ -342,54 +413,102 @@ public: getIssuanceConfidentialBalance() const; std::optional - getEncryptedBalance( - Account const& account, - EncryptedBalanceType option = HOLDER_ENCRYPTED_INBOX) const; + getEncryptedBalance(Account const& account, EncryptedBalanceType option = HOLDER_ENCRYPTED_INBOX) const; MPT operator[](std::string const& name) const; + PrettyAmount + operator()(std::int64_t amount) const; + + operator Asset() const; + bool printMPT(Account const& holder_) const; void generateKeyPair(Account const& account); - Buffer + std::optional getPubKey(Account const& account) const; - Buffer + std::optional getPrivKey(Account const& account) const; Buffer - encryptAmount(Account const& account, uint64_t amt) const; + encryptAmount(Account const& account, uint64_t const amt, Buffer const& blindingFactor) const; - uint64_t + std::optional decryptAmount(Account const& account, Buffer const& amt) const; - uint64_t - getDecryptedBalance( - Account const& account, - EncryptedBalanceType balanceType) const; + std::optional + getDecryptedBalance(Account const& account, EncryptedBalanceType balanceType) const; std::int64_t getIssuanceOutstandingBalance() const; + std::optional + getClawbackProof(Account const& holder, std::uint64_t amount, Buffer const& privateKey, uint256 const& txHash) + const; + + std::optional + getSchnorrProof(Account const& account, uint256 const& ctxHash) const; + + std::optional + getConfidentialSendProof( + Account const& sender, + std::uint64_t const amount, + std::vector const& recipients, + Slice const& blindingFactor, + std::size_t const nRecipients, + uint256 const& contextHash, + PedersenProofParams const& amountParams, + PedersenProofParams const& balanceParams) const; + + Buffer + getConvertBackProof( + Account const& holder, + std::uint64_t const amount, + uint256 const& contextHash, + PedersenProofParams const& pcParams) const; + + std::uint32_t + getMPTokenVersion(Account const account) const; + + Buffer + getAmountLinkageProof( + Buffer const& pubKey, + Buffer const& blindingFactor, + uint256 const& contextHash, + PedersenProofParams const& params) const; + + Buffer + getBalanceLinkageProof( + Account const& account, + uint256 const& contextHash, + Buffer const& pubKey, + PedersenProofParams const& params) const; + + Buffer + getBulletproof( + std::vector const& values, + std::vector const& blindingFactors, + uint256 const& contextHash) const; + + Buffer + getPedersenCommitment(std::uint64_t const amount, Buffer const& pedersenBlindingFactor); + private: - using SLEP = std::shared_ptr; + using SLEP = SLE::const_pointer; bool - forObject( - std::function const& cb, - std::optional const& holder = std::nullopt) const; + forObject(std::function const& cb, std::optional const& holder = std::nullopt) + const; template TER submit(A const& arg, Json::Value const& jv) { - env_( - jv, - txflags(arg.flags.value_or(0)), - ter(arg.err.value_or(tesSUCCESS))); + env_(jv, txflags(arg.flags.value_or(0)), ter(arg.err.value_or(tesSUCCESS))); auto const err = env_.ter(); if (close_) env_.close(); @@ -408,10 +527,18 @@ private: std::uint32_t getFlags(std::optional const& holder) const; + + template + void + fillConversionCiphertexts( + T const& arg, + Json::Value& jv, + Buffer& holderCiphertext, + Buffer& issuerCiphertext, + std::optional& auditorCiphertext, + Buffer& blindingFactor) const; }; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/multisign.h b/src/test/jtx/multisign.h index 7a035a9ff0..3bbf43bb05 100644 --- a/src/test/jtx/multisign.h +++ b/src/test/jtx/multisign.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_MULTISIGN_H_INCLUDED -#define RIPPLE_TEST_JTX_MULTISIGN_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -41,20 +21,14 @@ struct signer Account account; std::optional tag; - signer( - Account account_, - std::uint32_t weight_ = 1, - std::optional tag_ = std::nullopt) + signer(Account account_, std::uint32_t weight_ = 1, std::optional tag_ = std::nullopt) : weight(weight_), account(std::move(account_)), tag(std::move(tag_)) { } }; Json::Value -signers( - Account const& account, - std::uint32_t quorum, - std::vector const& v); +signers(Account const& account, std::uint32_t quorum, std::vector const& v); /** Remove a signer list. */ Json::Value @@ -76,14 +50,12 @@ public: /// a subfield. static constexpr SField* const topLevel = nullptr; - msig(SField const* subField_, std::vector signers_) - : signers(std::move(signers_)), subField(subField_) + msig(SField const* subField_, std::vector signers_) : signers(std::move(signers_)), subField(subField_) { sortSigners(signers); } - msig(SField const& subField_, std::vector signers_) - : msig{&subField_, signers_} + msig(SField const& subField_, std::vector signers_) : msig{&subField_, signers_} { } @@ -94,35 +66,21 @@ public: template requires std::convertible_to explicit msig(SField const* subField_, AccountType&& a0, Accounts&&... aN) - : msig{ - subField_, - std::vector{ - std::forward(a0), - std::forward(aN)...}} + : msig{subField_, std::vector{std::forward(a0), std::forward(aN)...}} { } template requires std::convertible_to explicit msig(SField const& subField_, AccountType&& a0, Accounts&&... aN) - : msig{ - &subField_, - std::vector{ - std::forward(a0), - std::forward(aN)...}} + : msig{&subField_, std::vector{std::forward(a0), std::forward(aN)...}} { } template - requires( - std::convertible_to && - !std::is_same_v) + requires(std::convertible_to && !std::is_same_v) explicit msig(AccountType&& a0, Accounts&&... aN) - : msig{ - topLevel, - std::vector{ - std::forward(a0), - std::forward(aN)...}} + : msig{topLevel, std::vector{std::forward(a0), std::forward(aN)...}} { } @@ -137,6 +95,4 @@ using siglists = owner_count; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/noop.h b/src/test/jtx/noop.h index 721c337766..47d12fb9af 100644 --- a/src/test/jtx/noop.h +++ b/src/test/jtx/noop.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_NOOP_H_INCLUDED -#define RIPPLE_TEST_JTX_NOOP_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -35,6 +15,4 @@ noop(Account const& account) } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/offer.h b/src/test/jtx/offer.h index 260b734ddd..dab15a4c8c 100644 --- a/src/test/jtx/offer.h +++ b/src/test/jtx/offer.h @@ -1,41 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_OFFER_H_INCLUDED -#define RIPPLE_TEST_JTX_OFFER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { /** Create an offer. */ Json::Value -offer( - Account const& account, - STAmount const& takerPays, - STAmount const& takerGets, - std::uint32_t flags = 0); +offer(Account const& account, STAmount const& takerPays, STAmount const& takerGets, std::uint32_t flags = 0); /** Cancel an offer. */ Json::Value @@ -43,6 +19,4 @@ offer_cancel(Account const& account, std::uint32_t offerSeq); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/owners.h b/src/test/jtx/owners.h index baf5d9da7d..87fa26417a 100644 --- a/src/test/jtx/owners.h +++ b/src/test/jtx/owners.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_OWNERS_H_INCLUDED -#define RIPPLE_TEST_JTX_OWNERS_H_INCLUDED +#pragma once #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { namespace detail { @@ -36,11 +16,7 @@ std::uint32_t owned_count_of(ReadView const& view, AccountID const& id, LedgerEntryType type); void -owned_count_helper( - test::jtx::Env& env, - AccountID const& id, - LedgerEntryType type, - std::uint32_t value); +owned_count_helper(test::jtx::Env& env, AccountID const& id, LedgerEntryType type, std::uint32_t value); } // namespace detail @@ -56,8 +32,7 @@ private: std::uint32_t value_; public: - owner_count(Account const& account, std::uint32_t value) - : account_(account), value_(value) + owner_count(Account const& account, std::uint32_t value) : account_(account), value_(value) { } @@ -76,8 +51,7 @@ private: std::uint32_t value_; public: - owners(Account const& account, std::uint32_t value) - : account_(account), value_(value) + owners(Account const& account, std::uint32_t value) : account_(account), value_(value) { } @@ -93,6 +67,4 @@ using offers = owner_count; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/paths.h b/src/test/jtx/paths.h index d1d5f5849a..c4e69fe3f3 100644 --- a/src/test/jtx/paths.h +++ b/src/test/jtx/paths.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_PATHS_H_INCLUDED -#define RIPPLE_TEST_JTX_PATHS_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -39,8 +19,7 @@ private: unsigned int limit_; public: - paths(Issue const& in, int depth = 7, unsigned int limit = 4) - : in_(in), depth_(depth), limit_(limit) + paths(Issue const& in, int depth = 7, unsigned int limit = 4) : in_(in), depth_(depth), limit_(limit) { } @@ -113,6 +92,4 @@ path::append(T const& t, Args const&... args) } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/pay.h b/src/test/jtx/pay.h index f9d8822f53..a155d7bdc8 100644 --- a/src/test/jtx/pay.h +++ b/src/test/jtx/pay.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_PAY_H_INCLUDED -#define RIPPLE_TEST_JTX_PAY_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -37,6 +17,4 @@ pay(Account const& account, Account const& to, AnyAmount amount); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/permissioned_dex.h b/src/test/jtx/permissioned_dex.h index b95574d94d..2023342ded 100644 --- a/src/test/jtx/permissioned_dex.h +++ b/src/test/jtx/permissioned_dex.h @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -50,4 +31,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/jtx/permissioned_domains.h b/src/test/jtx/permissioned_domains.h index ed086e366d..ff8ab129ae 100644 --- a/src/test/jtx/permissioned_domains.h +++ b/src/test/jtx/permissioned_domains.h @@ -1,45 +1,22 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_PERMISSIONED_DOMAINS_H_INCLUDED -#define RIPPLE_TEST_JTX_PERMISSIONED_DOMAINS_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace pdomain { // Helpers for PermissionedDomains testing -using Credential = ripple::test::jtx::deposit::AuthorizeCredentials; +using Credential = xrpl::test::jtx::deposit::AuthorizeCredentials; using Credentials = std::vector; // helpers // Make json for PermissionedDomainSet transaction Json::Value -setTx( - AccountID const& account, - Credentials const& credentials, - std::optional domain = std::nullopt); +setTx(AccountID const& account, Credentials const& credentials, std::optional domain = std::nullopt); // Make json for PermissionedDomainDelete transaction Json::Value @@ -55,9 +32,7 @@ objectExists(uint256 const& objID, Env& env); // Extract credentials from account_object object Credentials -credentialsFromJson( - Json::Value const& object, - std::unordered_map const& human2Acc); +credentialsFromJson(Json::Value const& object, std::unordered_map const& human2Acc); // Sort credentials the same way as PermissionedDomainSet Credentials @@ -70,6 +45,4 @@ getNewDomain(std::shared_ptr const& meta); } // namespace pdomain } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/prop.h b/src/test/jtx/prop.h index 70498074d6..b1f8cb5ffc 100644 --- a/src/test/jtx/prop.h +++ b/src/test/jtx/prop.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_PROP_H_INCLUDED -#define RIPPLE_TEST_JTX_PROP_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -35,8 +15,7 @@ struct prop std::unique_ptr p_; template - prop(Args&&... args) - : p_(std::make_unique>(std::forward(args)...)) + prop(Args&&... args) : p_(std::make_unique>(std::forward(args)...)) { } @@ -49,6 +28,4 @@ struct prop } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/quality.h b/src/test/jtx/quality.h index 4184a2e78b..34c960224f 100644 --- a/src/test/jtx/quality.h +++ b/src/test/jtx/quality.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_QUALITY_H_INCLUDED -#define RIPPLE_TEST_JTX_QUALITY_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -84,6 +64,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/rate.h b/src/test/jtx/rate.h index 6fb8c9a8e9..a92bd2364a 100644 --- a/src/test/jtx/rate.h +++ b/src/test/jtx/rate.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_RATE_H_INCLUDED -#define RIPPLE_TEST_JTX_RATE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -34,6 +14,4 @@ rate(Account const& account, double multiplier); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/regkey.h b/src/test/jtx/regkey.h index ce87c9b259..2c95baacc3 100644 --- a/src/test/jtx/regkey.h +++ b/src/test/jtx/regkey.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_REGKEY_H_INCLUDED -#define RIPPLE_TEST_JTX_REGKEY_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -39,6 +19,4 @@ regkey(Account const& account, Account const& signer); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/require.h b/src/test/jtx/require.h index 3215ac0abb..7d712e8ab7 100644 --- a/src/test/jtx/require.h +++ b/src/test/jtx/require.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_REQUIRE_H_INCLUDED -#define RIPPLE_TEST_JTX_REQUIRE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -82,6 +62,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/requires.h b/src/test/jtx/requires.h index 7375182e03..2411d040c6 100644 --- a/src/test/jtx/requires.h +++ b/src/test/jtx/requires.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_REQUIRES_H_INCLUDED -#define RIPPLE_TEST_JTX_REQUIRES_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -34,6 +14,4 @@ using requires_t = std::vector; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/rpc.h b/src/test/jtx/rpc.h index be9ce22bf7..6946cbc4e1 100644 --- a/src/test/jtx/rpc.h +++ b/src/test/jtx/rpc.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_RPC_H_INCLUDED -#define RIPPLE_TEST_JTX_RPC_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -41,15 +21,12 @@ private: public: /// If there's an error code, we expect an error message - explicit rpc(error_code_i code, std::optional m = {}) - : code_(code), errorMessage_(m) + explicit rpc(error_code_i code, std::optional m = {}) : code_(code), errorMessage_(m) { } /// If there is not a code, we expect an exception message - explicit rpc( - std::string error, - std::optional exceptionMessage = {}) + explicit rpc(std::string error, std::optional exceptionMessage = {}) : error_(error), errorException_(exceptionMessage) { } @@ -68,11 +45,9 @@ public: // always obtained from the lookup into the ErrorInfo lookup table. // // Take advantage of that fact to populate jt.rpcException. The - // check will be aware of whether the rpcExcpetion can be safely + // check will be aware of whether the rpcException can be safely // ignored. - jt.rpcCode = { - *code_, - errorMessage_ ? *errorMessage_ : errorInfo.message.c_str()}; + jt.rpcCode = {*code_, errorMessage_ ? *errorMessage_ : errorInfo.message.c_str()}; jt.rpcException = {errorInfo.token.c_str(), std::nullopt}; } if (error_) @@ -82,6 +57,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/sendmax.h b/src/test/jtx/sendmax.h index 54a1c25e2f..8a471be3cd 100644 --- a/src/test/jtx/sendmax.h +++ b/src/test/jtx/sendmax.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_SENDMAX_H_INCLUDED -#define RIPPLE_TEST_JTX_SENDMAX_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -45,6 +25,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/seq.h b/src/test/jtx/seq.h index 0227c573da..b861800ac9 100644 --- a/src/test/jtx/seq.h +++ b/src/test/jtx/seq.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_SEQ_H_INCLUDED -#define RIPPLE_TEST_JTX_SEQ_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -55,6 +35,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/sig.h b/src/test/jtx/sig.h index b96a306a37..ab22a46c69 100644 --- a/src/test/jtx/sig.h +++ b/src/test/jtx/sig.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_SIG_H_INCLUDED -#define RIPPLE_TEST_JTX_SIG_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -59,13 +39,11 @@ public: { } - explicit sig(SField const* subField, Account const& account) - : subField_(subField), account_(account) + explicit sig(SField const* subField, Account const& account) : subField_(subField), account_(account) { } - explicit sig(SField const& subField, Account const& account) - : sig(&subField, account) + explicit sig(SField const& subField, Account const& account) : sig(&subField, account) { } @@ -79,6 +57,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/tag.h b/src/test/jtx/tag.h index 28edc8f1ac..c8d5723754 100644 --- a/src/test/jtx/tag.h +++ b/src/test/jtx/tag.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TAG_H_INCLUDED -#define RIPPLE_TEST_JTX_TAG_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -60,6 +40,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/tags.h b/src/test/jtx/tags.h index 4d55929d69..c8a6170048 100644 --- a/src/test/jtx/tags.h +++ b/src/test/jtx/tags.h @@ -1,26 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TAGS_H_INCLUDED -#define RIPPLE_TEST_JTX_TAGS_H_INCLUDED - -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -62,6 +42,4 @@ static increment_t const increment; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/ter.h b/src/test/jtx/ter.h index ab37275bad..074ba307cb 100644 --- a/src/test/jtx/ter.h +++ b/src/test/jtx/ter.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TER_H_INCLUDED -#define RIPPLE_TEST_JTX_TER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -54,6 +34,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/testline.h b/src/test/jtx/testline.h new file mode 100644 index 0000000000..e2be1f0276 --- /dev/null +++ b/src/test/jtx/testline.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace xrpl { +namespace test { +namespace jtx { + +/** Store the line number of the current test in a JTx. + + Intended to help debug failing transaction submission tests. +*/ +class testline +{ +private: + int line_; + +public: + explicit testline(int line) : line_(line) + { + } + + void + operator()(Env&, JTx& jt) const; +}; + +#define THISLINE testline(__LINE__) + +} // namespace jtx +} // namespace test +} // namespace xrpl diff --git a/src/test/jtx/ticket.h b/src/test/jtx/ticket.h index 820aaee4aa..dca16ac7c6 100644 --- a/src/test/jtx/ticket.h +++ b/src/test/jtx/ticket.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TICKET_H_INCLUDED -#define RIPPLE_TEST_JTX_TICKET_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -66,6 +46,4 @@ using tickets = owner_count; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/token.h b/src/test/jtx/token.h index f22a1a01da..f6d562587a 100644 --- a/src/test/jtx/token.h +++ b/src/test/jtx/token.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_NFT_H_INCLUDED -#define RIPPLE_TEST_JTX_NFT_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -123,10 +103,7 @@ burn(jtx::Account const& account, uint256 const& nftokenID); /** Create an NFTokenOffer. */ Json::Value -createOffer( - jtx::Account const& account, - uint256 const& nftokenID, - STAmount const& amount); +createOffer(jtx::Account const& account, uint256 const& nftokenID, STAmount const& amount); /** Sets the optional Owner on an NFTokenOffer. */ class owner @@ -175,14 +152,10 @@ public: /** Cancel NFTokenOffers. */ Json::Value -cancelOffer( - jtx::Account const& account, - std::initializer_list const& nftokenOffers = {}); +cancelOffer(jtx::Account const& account, std::initializer_list const& nftokenOffers = {}); Json::Value -cancelOffer( - jtx::Account const& account, - std::vector const& nftokenOffers); +cancelOffer(jtx::Account const& account, std::vector const& nftokenOffers); /** Sets the optional RootIndex field when canceling NFTokenOffers. */ class rootIndex @@ -209,10 +182,7 @@ acceptSellOffer(jtx::Account const& account, uint256 const& offerIndex); /** Broker two NFToken offers. */ Json::Value -brokerOffers( - jtx::Account const& account, - uint256 const& buyOfferIndex, - uint256 const& sellOfferIndex); +brokerOffers(jtx::Account const& account, uint256 const& buyOfferIndex, uint256 const& sellOfferIndex); /** Sets the optional NFTokenBrokerFee field in a brokerOffer transaction. */ class brokerFee @@ -246,6 +216,4 @@ modify(jtx::Account const& account, uint256 const& nftokenID); } // namespace jtx } // namespace test -} // namespace ripple - -#endif // RIPPLE_TEST_JTX_NFT_H_INCLUDED +} // namespace xrpl diff --git a/src/test/jtx/trust.h b/src/test/jtx/trust.h index 5f0cebcbef..462538854b 100644 --- a/src/test/jtx/trust.h +++ b/src/test/jtx/trust.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TRUST_H_INCLUDED -#define RIPPLE_TEST_JTX_TRUST_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -35,20 +15,11 @@ trust(Account const& account, STAmount const& amount, std::uint32_t flags = 0); /** Change flags on a trust line. */ Json::Value -trust( - Account const& account, - STAmount const& amount, - Account const& peer, - std::uint32_t flags); +trust(Account const& account, STAmount const& amount, Account const& peer, std::uint32_t flags); Json::Value -claw( - Account const& account, - STAmount const& amount, - std::optional const& mptHolder = std::nullopt); +claw(Account const& account, STAmount const& amount, std::optional const& mptHolder = std::nullopt); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/txflags.h b/src/test/jtx/txflags.h index 9205df904a..f51c26d035 100644 --- a/src/test/jtx/txflags.h +++ b/src/test/jtx/txflags.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_TXFLAGS_H_INCLUDED -#define RIPPLE_TEST_JTX_TXFLAGS_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -43,6 +23,4 @@ public: } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/utility.h b/src/test/jtx/utility.h index 555adc21de..895d00f12b 100644 --- a/src/test/jtx/utility.h +++ b/src/test/jtx/utility.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_UTILITY_H_INCLUDED -#define RIPPLE_TEST_JTX_UTILITY_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -72,13 +52,8 @@ fill_seq(Json::Value& jv, ReadView const& view); /** Given a rippled unit test rpc command, return the corresponding JSON. */ Json::Value -cmdToJSONRPC( - std::vector const& args, - beast::Journal j, - unsigned int apiVersion); +cmdToJSONRPC(std::vector const& args, beast::Journal j, unsigned int apiVersion); } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/vault.h b/src/test/jtx/vault.h index 74c482bf17..65a5706354 100644 --- a/src/test/jtx/vault.h +++ b/src/test/jtx/vault.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_VAULT_H_INCLUDED -#define RIPPLE_TEST_JTX_VAULT_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -104,6 +84,4 @@ struct Vault } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/jtx/xchain_bridge.h b/src/test/jtx/xchain_bridge.h index 1b3841358f..cdacede234 100644 --- a/src/test/jtx/xchain_bridge.h +++ b/src/test/jtx/xchain_bridge.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TEST_JTX_XCHAINBRIDGE_H_INCLUDED -#define RIPPLE_TEST_JTX_XCHAINBRIDGE_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { @@ -90,11 +70,7 @@ sidechain_xchain_account_create( AnyAmount const& xChainFee); Json::Value -sidechain_xchain_account_claim( - Account const& acc, - Json::Value const& bridge, - Account const& dst, - AnyAmount const& amt); +sidechain_xchain_account_claim(Account const& acc, Json::Value const& bridge, Account const& dst, AnyAmount const& amt); Json::Value claim_attestation( @@ -225,18 +201,7 @@ struct XChainBridgeObjects std::size_t const fromIdx = 0) { return create_account_attestations( - scAttester, - jvb, - mcCarol, - amt, - reward, - payees, - true, - createCount, - dst, - signers, - numAtts, - fromIdx); + scAttester, jvb, mcCarol, amt, reward, payees, true, createCount, dst, signers, numAtts, fromIdx); } Json::Value @@ -246,16 +211,10 @@ struct XChainBridgeObjects STAmount const& _reward = XRP(1), std::optional const& minAccountCreate = std::nullopt) { - return bridge_create( - acc, - bridge == Json::nullValue ? jvb : bridge, - _reward, - minAccountCreate); + return bridge_create(acc, bridge == Json::nullValue ? jvb : bridge, _reward, minAccountCreate); } }; } // namespace jtx } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/ledger/BookDirs_test.cpp b/src/test/ledger/BookDirs_test.cpp index 48ee92a6fd..45e585d68d 100644 --- a/src/test/ledger/BookDirs_test.cpp +++ b/src/test/ledger/BookDirs_test.cpp @@ -1,26 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { struct BookDirs_test : public beast::unit_test::suite @@ -50,18 +33,13 @@ struct BookDirs_test : public beast::unit_test::suite { env(offer("alice", Account("alice")["USD"](50), XRP(10))); - auto d = BookDirs( - *env.current(), - Book( - Account("alice")["USD"].issue(), xrpIssue(), std::nullopt)); + auto d = BookDirs(*env.current(), Book(Account("alice")["USD"].issue(), xrpIssue(), std::nullopt)); BEAST_EXPECT(std::distance(d.begin(), d.end()) == 1); } { env(offer("alice", gw["CNY"](50), XRP(10))); - auto d = BookDirs( - *env.current(), - Book(gw["CNY"].issue(), xrpIssue(), std::nullopt)); + auto d = BookDirs(*env.current(), Book(gw["CNY"].issue(), xrpIssue(), std::nullopt)); BEAST_EXPECT(std::distance(d.begin(), d.end()) == 1); } @@ -69,9 +47,7 @@ struct BookDirs_test : public beast::unit_test::suite env.trust(Account("bob")["CNY"](10), "alice"); env(pay("bob", "alice", Account("bob")["CNY"](10))); env(offer("alice", USD(50), Account("bob")["CNY"](10))); - auto d = BookDirs( - *env.current(), - Book(USD.issue(), Account("bob")["CNY"].issue(), std::nullopt)); + auto d = BookDirs(*env.current(), Book(USD.issue(), Account("bob")["CNY"].issue(), std::nullopt)); BEAST_EXPECT(std::distance(d.begin(), d.end()) == 1); } @@ -81,8 +57,7 @@ struct BookDirs_test : public beast::unit_test::suite for (auto k = 0; k < 80; ++k) env(offer("alice", AUD(i), XRP(j))); - auto d = BookDirs( - *env.current(), Book(AUD.issue(), xrpIssue(), std::nullopt)); + auto d = BookDirs(*env.current(), Book(AUD.issue(), xrpIssue(), std::nullopt)); BEAST_EXPECT(std::distance(d.begin(), d.end()) == 240); auto i = 1, j = 3, k = 0; for (auto const& e : d) @@ -108,7 +83,7 @@ struct BookDirs_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(BookDirs, ledger, ripple); +BEAST_DEFINE_TESTSUITE(BookDirs, ledger, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 3488f25fd8..0774390490 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct Directory_test : public beast::unit_test::suite @@ -106,8 +89,7 @@ struct Directory_test : public beast::unit_test::suite do { - auto p = - view->read(keylet::page(keylet::ownerDir(alice), page)); + auto p = view->read(keylet::page(keylet::ownerDir(alice), page)); // Ensure that the entries in the page are sorted auto const& v = p->getFieldV256(sfIndexes); @@ -115,8 +97,7 @@ struct Directory_test : public beast::unit_test::suite // Ensure that the page contains the correct orders by // calculating which sequence numbers belong here. - std::uint32_t const minSeq = - firstOfferSeq + (page * dirNodeMaxEntries); + std::uint32_t const minSeq = firstOfferSeq + (page * dirNodeMaxEntries); std::uint32_t const maxSeq = minSeq + dirNodeMaxEntries; for (auto const& e : v) @@ -133,8 +114,7 @@ struct Directory_test : public beast::unit_test::suite // Now check the orderbook: it should be in the order we placed // the offers. - auto book = BookDirs( - *env.current(), Book({xrpIssue(), USD.issue(), std::nullopt})); + auto book = BookDirs(*env.current(), Book({xrpIssue(), USD.issue(), std::nullopt})); int count = 1; for (auto const& offer : book) @@ -184,7 +164,7 @@ struct Directory_test : public beast::unit_test::suite return c; }(); - // First, Alices creates a lot of trustlines, and then + // First, Alice creates a lot of trustlines, and then // deletes them in a different order: { auto cl = currencies; @@ -283,8 +263,7 @@ struct Directory_test : public beast::unit_test::suite { for (int i = 0; i < dirNodeMaxEntries; ++i) { - env(offer_cancel( - alice, firstOfferSeq + page * dirNodeMaxEntries + i)); + env(offer_cancel(alice, firstOfferSeq + page * dirNodeMaxEntries + i)); env.close(); } } @@ -293,8 +272,7 @@ struct Directory_test : public beast::unit_test::suite // should have no entries and be empty: { Sandbox sb(env.closed().get(), tapNONE); - uint256 const bookBase = - getBookBase({xrpIssue(), USD.issue(), std::nullopt}); + uint256 const bookBase = getBookBase({xrpIssue(), USD.issue(), std::nullopt}); BEAST_EXPECT(dirIsEmpty(sb, keylet::page(bookBase))); BEAST_EXPECT(!sb.succ(bookBase, getQualityNext(bookBase))); @@ -326,11 +304,9 @@ struct Directory_test : public beast::unit_test::suite env.fund(XRP(10000), alice); env.close(); - constexpr uint256 base( - "fb71c9aa3310141da4b01d6c744a98286af2d72ab5448d5adc0910ca0c910880"); + constexpr uint256 base("fb71c9aa3310141da4b01d6c744a98286af2d72ab5448d5adc0910ca0c910880"); - constexpr uint256 item( - "bad0f021aa3b2f6754a8fe82a5779730aa0bbbab82f17201ef24900efc2c7312"); + constexpr uint256 item("bad0f021aa3b2f6754a8fe82a5779730aa0bbbab82f17201ef24900efc2c7312"); { // Create a chain of three pages: @@ -350,8 +326,7 @@ struct Directory_test : public beast::unit_test::suite // Now, try to delete the item from the middle // page. This should cause all pages to be deleted: - BEAST_EXPECT(sb.dirRemove( - keylet::page(base, 0), 1, keylet::unchecked(item), false)); + BEAST_EXPECT(sb.dirRemove(keylet::page(base, 0), 1, keylet::unchecked(item), false)); BEAST_EXPECT(!sb.peek(keylet::page(base, 2))); BEAST_EXPECT(!sb.peek(keylet::page(base, 1))); BEAST_EXPECT(!sb.peek(keylet::page(base, 0))); @@ -384,8 +359,7 @@ struct Directory_test : public beast::unit_test::suite // Now, try to delete the item from page 2. // This should cause pages 2 and 3 to be // deleted: - BEAST_EXPECT(sb.dirRemove( - keylet::page(base, 0), 2, keylet::unchecked(item), false)); + BEAST_EXPECT(sb.dirRemove(keylet::page(base, 0), 2, keylet::unchecked(item), false)); BEAST_EXPECT(!sb.peek(keylet::page(base, 3))); BEAST_EXPECT(!sb.peek(keylet::page(base, 2))); @@ -415,8 +389,7 @@ struct Directory_test : public beast::unit_test::suite Json::Value params; params[jss::type] = jss::directory; params[jss::ledger_index] = "validated"; - auto const result = - env.rpc("json", "ledger_data", to_string(params))[jss::result]; + auto const result = env.rpc("json", "ledger_data", to_string(params))[jss::result]; BEAST_EXPECT(!result.isMember(jss::marker)); return result; }; @@ -435,9 +408,7 @@ struct Directory_test : public beast::unit_test::suite BEAST_EXPECTS(checkArraySize(jstate, 2), jrr.toStyledString()); for (auto const& directory : jstate) { - BEAST_EXPECT( - directory["LedgerEntryType"] == - jss::DirectoryNode); // sanity check + BEAST_EXPECT(directory["LedgerEntryType"] == jss::DirectoryNode); // sanity check // The PreviousTxnID and PreviousTxnLgrSeq fields should not be // on the DirectoryNode object when the amendment is disabled BEAST_EXPECT(!directory.isMember("PreviousTxnID")); @@ -453,7 +424,7 @@ struct Directory_test : public beast::unit_test::suite // exist env(offer(alice, XRP(1), USD(1))); auto const txID = to_string(env.tx()->getTransactionID()); - auto const ledgerSeq = env.current()->info().seq; + auto const ledgerSeq = env.current()->header().seq; env.close(); // Make sure the fields only exist if the object is touched env(noop(gw)); @@ -465,9 +436,7 @@ struct Directory_test : public beast::unit_test::suite BEAST_EXPECTS(checkArraySize(jstate, 3), jrr.toStyledString()); for (auto const& directory : jstate) { - BEAST_EXPECT( - directory["LedgerEntryType"] == - jss::DirectoryNode); // sanity check + BEAST_EXPECT(directory["LedgerEntryType"] == jss::DirectoryNode); // sanity check if (directory[jss::Owner] == gw.human()) { // gw's directory did not get touched, so it @@ -480,9 +449,7 @@ struct Directory_test : public beast::unit_test::suite // All of the other directories, including the order // book, did get touched, so they should have those // fields - BEAST_EXPECT( - directory.isMember("PreviousTxnID") && - directory["PreviousTxnID"].asString() == txID); + BEAST_EXPECT(directory.isMember("PreviousTxnID") && directory["PreviousTxnID"].asString() == txID); BEAST_EXPECT( directory.isMember("PreviousTxnLgrSeq") && directory["PreviousTxnLgrSeq"].asUInt() == ledgerSeq); @@ -519,8 +486,7 @@ struct Directory_test : public beast::unit_test::suite env, lastPage, keylet::ownerDir(alice.id()), - [lastPage, this]( - ApplyView& view, uint256 key, std::uint64_t page) { + [lastPage, this](ApplyView& view, uint256 key, std::uint64_t page) { auto sle = view.peek({ltCREDENTIAL, key}); if (!BEAST_EXPECT(sle)) return false; @@ -542,8 +508,7 @@ struct Directory_test : public beast::unit_test::suite // Destroy all objects in directory for (int i = 0; i < 64; ++i) - env(credentials::deleteCred( - alice, alice, alice, std::to_string(i))); + env(credentials::deleteCred(alice, alice, alice, std::to_string(i))); if (!full) env(credentials::deleteCred(alice, alice, alice, "foo")); @@ -556,12 +521,10 @@ struct Directory_test : public beast::unit_test::suite env.close(); }; - testCase( - testable_amendments() - fixDirectoryLimit, - [this](Env&) -> std::tuple { - testcase("directory full without fixDirectoryLimit"); - return {dirNodeMaxPages - 1, true}; - }); + testCase(testable_amendments() - fixDirectoryLimit, [this](Env&) -> std::tuple { + testcase("directory full without fixDirectoryLimit"); + return {dirNodeMaxPages - 1, true}; + }); testCase( testable_amendments(), // [this](Env&) -> std::tuple { @@ -588,7 +551,7 @@ struct Directory_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE_PRIO(Directory, ledger, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(Directory, ledger, xrpl, 1); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/ledger/PaymentSandbox_test.cpp b/src/test/ledger/PaymentSandbox_test.cpp index db7fbed019..cd5b1d1c19 100644 --- a/src/test/ledger/PaymentSandbox_test.cpp +++ b/src/test/ledger/PaymentSandbox_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class PaymentSandbox_test : public beast::unit_test::suite @@ -85,9 +66,7 @@ class PaymentSandbox_test : public beast::unit_test::suite PathSet paths(Path(gw1, USD_gw2, gw2), Path(gw2, USD_gw1, gw1)); - env(pay(snd, rcv, any(USD_gw1(4))), - json(paths.json()), - txflags(tfNoRippleDirect | tfPartialPayment)); + env(pay(snd, rcv, any(USD_gw1(4))), json(paths.json()), txflags(tfNoRippleDirect | tfPartialPayment)); env.require(balance("rcv", USD_gw1(0))); env.require(balance("rcv", USD_gw2(2))); @@ -124,23 +103,19 @@ class PaymentSandbox_test : public beast::unit_test::suite ApplyViewImpl av(&*env.current(), tapNONE); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); { auto r = accountSend(av, gw1, alice, toCredit, j); BEAST_EXPECT(r == tesSUCCESS); } BEAST_EXPECT( - accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount + toCredit); + accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount + toCredit); { auto r = accountSend(av, alice, gw1, toDebit, j); BEAST_EXPECT(r == tesSUCCESS); } BEAST_EXPECT( - accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == + accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount + toCredit - toDebit); } @@ -149,19 +124,15 @@ class PaymentSandbox_test : public beast::unit_test::suite ApplyViewImpl av(&*env.current(), tapNONE); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); rippleCredit(av, gw1, alice, toCredit, true, j); BEAST_EXPECT( - accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount + toCredit); + accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount + toCredit); rippleCredit(av, alice, gw1, toDebit, true, j); BEAST_EXPECT( - accountHolds( - av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == + accountHolds(av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount + toCredit - toDebit); } @@ -171,26 +142,20 @@ class PaymentSandbox_test : public beast::unit_test::suite PaymentSandbox pv(&av); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); { auto r = accountSend(pv, gw1, alice, toCredit, j); BEAST_EXPECT(r == tesSUCCESS); } - BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount); + BEAST_EXPECT(accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); { auto r = accountSend(pv, alice, gw1, toDebit, j); BEAST_EXPECT(r == tesSUCCESS); } BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount - toDebit); + accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount - toDebit); } { @@ -199,14 +164,10 @@ class PaymentSandbox_test : public beast::unit_test::suite PaymentSandbox pv(&av); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); rippleCredit(pv, gw1, alice, toCredit, true, j); - BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount); + BEAST_EXPECT(accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); } { @@ -215,14 +176,11 @@ class PaymentSandbox_test : public beast::unit_test::suite PaymentSandbox pv(&av); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); BEAST_EXPECT(redeemIOU(pv, alice, toDebit, iss, j) == tesSUCCESS); BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount - toDebit); + accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount - toDebit); } { @@ -231,14 +189,10 @@ class PaymentSandbox_test : public beast::unit_test::suite PaymentSandbox pv(&av); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); BEAST_EXPECT(issueIOU(pv, alice, toCredit, iss, j) == tesSUCCESS); - BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount); + BEAST_EXPECT(accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); } { @@ -247,40 +201,22 @@ class PaymentSandbox_test : public beast::unit_test::suite PaymentSandbox pv(&av); auto const iss = USD_gw1.issue(); - auto const startingAmount = accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); + auto const startingAmount = accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j); { auto r = accountSend(pv, gw1, alice, toCredit, j); BEAST_EXPECT(r == tesSUCCESS); } - BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount); + BEAST_EXPECT(accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); { PaymentSandbox pv2(&pv); - BEAST_EXPECT( - accountHolds( - pv2, - alice, - iss.currency, - iss.account, - fhIGNORE_FREEZE, - j) == startingAmount); + BEAST_EXPECT(accountHolds(pv2, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); { auto r = accountSend(pv2, gw1, alice, toCredit, j); BEAST_EXPECT(r == tesSUCCESS); } - BEAST_EXPECT( - accountHolds( - pv2, - alice, - iss.currency, - iss.account, - fhIGNORE_FREEZE, - j) == startingAmount); + BEAST_EXPECT(accountHolds(pv2, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount); } { @@ -288,9 +224,7 @@ class PaymentSandbox_test : public beast::unit_test::suite BEAST_EXPECT(r == tesSUCCESS); } BEAST_EXPECT( - accountHolds( - pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == - startingAmount - toDebit); + accountHolds(pv, alice, iss.currency, iss.account, fhIGNORE_FREEZE, j) == startingAmount - toDebit); } } @@ -312,18 +246,8 @@ class PaymentSandbox_test : public beast::unit_test::suite auto const USD = gw["USD"]; auto const issue = USD.issue(); - STAmount tinyAmt( - issue, - STAmount::cMinValue, - STAmount::cMinOffset + 1, - false, - STAmount::unchecked{}); - STAmount hugeAmt( - issue, - STAmount::cMaxValue, - STAmount::cMaxOffset - 1, - false, - STAmount::unchecked{}); + STAmount tinyAmt(issue, STAmount::cMinValue, STAmount::cMinOffset + 1, false, STAmount::unchecked{}); + STAmount hugeAmt(issue, STAmount::cMaxValue, STAmount::cMaxOffset - 1, false, STAmount::unchecked{}); ApplyViewImpl av(&*env.current(), tapNONE); PaymentSandbox pv(&av); @@ -337,11 +261,8 @@ class PaymentSandbox_test : public beast::unit_test::suite testcase("Reserve"); using namespace jtx; - auto accountFundsXRP = [](ReadView const& view, - AccountID const& id, - beast::Journal j) -> XRPAmount { - return toAmount(accountHolds( - view, id, xrpCurrency(), xrpAccount(), fhZERO_IF_FROZEN, j)); + auto accountFundsXRP = [](ReadView const& view, AccountID const& id, beast::Journal j) -> XRPAmount { + return toAmount(accountHolds(view, id, xrpCurrency(), xrpAccount(), fhZERO_IF_FROZEN, j)); }; auto reserve = [](jtx::Env& env, std::uint32_t count) -> XRPAmount { @@ -362,17 +283,14 @@ class PaymentSandbox_test : public beast::unit_test::suite // zero (there was a bug that caused her funds to become negative). { - auto r = - accountSend(sb, xrpAccount(), alice, XRP(100), env.journal); + auto r = accountSend(sb, xrpAccount(), alice, XRP(100), env.journal); BEAST_EXPECT(r == tesSUCCESS); } { - auto r = - accountSend(sb, alice, xrpAccount(), XRP(100), env.journal); + auto r = accountSend(sb, alice, xrpAccount(), XRP(100), env.journal); BEAST_EXPECT(r == tesSUCCESS); } - BEAST_EXPECT( - accountFundsXRP(sb, alice, env.journal) == beast::zero); + BEAST_EXPECT(accountFundsXRP(sb, alice, env.journal) == beast::zero); } } @@ -402,8 +320,7 @@ class PaymentSandbox_test : public beast::unit_test::suite sb.creditHook(gw.id(), alice.id(), {USD, 100}, {tlIssue, 600}); // Expect that the STAmount issuer returned by balanceHook() is correct. - STAmount const balance = - sb.balanceHook(gw.id(), alice.id(), {USD, 600}); + STAmount const balance = sb.balanceHook(gw.id(), alice.id(), {USD, 600}); BEAST_EXPECT(balance.getIssuer() == USD.issue().account); } @@ -425,7 +342,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(PaymentSandbox, ledger, ripple); +BEAST_DEFINE_TESTSUITE(PaymentSandbox, ledger, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/ledger/PendingSaves_test.cpp b/src/test/ledger/PendingSaves_test.cpp index e2a43eb585..ddf371e913 100644 --- a/src/test/ledger/PendingSaves_test.cpp +++ b/src/test/ledger/PendingSaves_test.cpp @@ -1,25 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { struct PendingSaves_test : public beast::unit_test::suite @@ -57,7 +40,7 @@ struct PendingSaves_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(PendingSaves, ledger, ripple); +BEAST_DEFINE_TESTSUITE(PendingSaves, ledger, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/ledger/SkipList_test.cpp b/src/test/ledger/SkipList_test.cpp index e0f4049c73..2f4a231c14 100644 --- a/src/test/ledger/SkipList_test.cpp +++ b/src/test/ledger/SkipList_test.cpp @@ -1,22 +1,3 @@ -//----------------------------------------------------------------------------- -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class SkipList_test : public beast::unit_test::suite @@ -36,16 +17,12 @@ class SkipList_test : public beast::unit_test::suite std::vector> history; { Config config; - auto prev = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); + auto prev = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); history.push_back(prev); for (auto i = 0; i < 1023; ++i) { - auto next = std::make_shared( - *prev, env.app().timeKeeper().closeTime()); + auto next = std::make_shared(*prev, env.app().timeKeeper().closeTime()); next->updateSkipList(); history.push_back(next); prev = next; @@ -54,44 +31,31 @@ class SkipList_test : public beast::unit_test::suite { auto l = *(std::next(std::begin(history))); - BEAST_EXPECT((*std::begin(history))->info().seq < l->info().seq); - BEAST_EXPECT( - !hashOfSeq(*l, l->info().seq + 1, env.journal).has_value()); - BEAST_EXPECT( - hashOfSeq(*l, l->info().seq, env.journal) == l->info().hash); - BEAST_EXPECT( - hashOfSeq(*l, l->info().seq - 1, env.journal) == - l->info().parentHash); - BEAST_EXPECT(!hashOfSeq(*history.back(), l->info().seq, env.journal) - .has_value()); + BEAST_EXPECT((*std::begin(history))->header().seq < l->header().seq); + BEAST_EXPECT(!hashOfSeq(*l, l->header().seq + 1, env.journal).has_value()); + BEAST_EXPECT(hashOfSeq(*l, l->header().seq, env.journal) == l->header().hash); + BEAST_EXPECT(hashOfSeq(*l, l->header().seq - 1, env.journal) == l->header().parentHash); + BEAST_EXPECT(!hashOfSeq(*history.back(), l->header().seq, env.journal).has_value()); } // ledger skip lists store up to the previous 256 hashes for (auto i = history.crbegin(); i != history.crend(); i += 256) { - for (auto n = i; - n != std::next(i, (*i)->info().seq - 256 > 1 ? 257 : 256); - ++n) + for (auto n = i; n != std::next(i, (*i)->header().seq - 256 > 1 ? 257 : 256); ++n) { - BEAST_EXPECT( - hashOfSeq(**i, (*n)->info().seq, env.journal) == - (*n)->info().hash); + BEAST_EXPECT(hashOfSeq(**i, (*n)->header().seq, env.journal) == (*n)->header().hash); } // edge case accessing beyond 256 - BEAST_EXPECT(!hashOfSeq(**i, (*i)->info().seq - 258, env.journal) - .has_value()); + BEAST_EXPECT(!hashOfSeq(**i, (*i)->header().seq - 258, env.journal).has_value()); } // every 256th hash beyond the first 256 is stored - for (auto i = history.crbegin(); i != std::next(history.crend(), -512); - i += 256) + for (auto i = history.crbegin(); i != std::next(history.crend(), -512); i += 256) { for (auto n = std::next(i, 512); n != history.crend(); n += 256) { - BEAST_EXPECT( - hashOfSeq(**i, (*n)->info().seq, env.journal) == - (*n)->info().hash); + BEAST_EXPECT(hashOfSeq(**i, (*n)->header().seq, env.journal) == (*n)->header().hash); } } } @@ -103,7 +67,7 @@ class SkipList_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SkipList, ledger, ripple); +BEAST_DEFINE_TESTSUITE(SkipList, ledger, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/ledger/View_test.cpp b/src/test/ledger/View_test.cpp index 17d3244aa2..33813e135e 100644 --- a/src/test/ledger/View_test.cpp +++ b/src/test/ledger/View_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class View_test : public beast::unit_test::suite @@ -79,8 +60,7 @@ class View_test : public beast::unit_test::suite next = view.succ(*next); if (!next) break; - view.rawErase(std::make_shared( - *view.read(keylet::unchecked(*next)))); + view.rawErase(std::make_shared(*view.read(keylet::unchecked(*next)))); } return true; }); @@ -97,17 +77,13 @@ class View_test : public beast::unit_test::suite next = ledger.succ(*next); if (!next) break; - ledger.rawErase( - std::make_shared(*ledger.read(keylet::unchecked(*next)))); + ledger.rawErase(std::make_shared(*ledger.read(keylet::unchecked(*next)))); } } // Test succ correctness void - succ( - ReadView const& v, - std::uint32_t id, - std::optional answer) + succ(ReadView const& v, std::uint32_t id, std::optional answer) { auto const next = v.succ(k(id).key); if (answer) @@ -137,13 +113,9 @@ class View_test : public beast::unit_test::suite using namespace jtx; Env env(*this); Config config; - std::shared_ptr const genesis = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); - auto const ledger = std::make_shared( - *genesis, env.app().timeKeeper().closeTime()); + std::shared_ptr const genesis = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); + auto const ledger = std::make_shared(*genesis, env.app().timeKeeper().closeTime()); wipe(*ledger); ReadView& v = *ledger; succ(v, 0, std::nullopt); @@ -404,13 +376,9 @@ class View_test : public beast::unit_test::suite using namespace jtx; Env env(*this); Config config; - std::shared_ptr const genesis = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); - auto const ledger = std::make_shared( - *genesis, env.app().timeKeeper().closeTime()); + std::shared_ptr const genesis = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); + auto const ledger = std::make_shared(*genesis, env.app().timeKeeper().closeTime()); auto setup = [&ledger](std::vector const& vec) { wipe(*ledger); @@ -519,9 +487,8 @@ class View_test : public beast::unit_test::suite } { // some full trees, some empty trees, etc - setup({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 20, 25, 30, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 66, 100}); + setup({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 25, 30, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 66, 100}); BEAST_EXPECT( sles(*ledger) == list( @@ -568,98 +535,38 @@ class View_test : public beast::unit_test::suite auto e = ledger->stateMap().end(); BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(0)) == e); BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(1)) == b); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(5))->key() == - uint256(4)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(15))->key() == - uint256(14)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(16))->key() == - uint256(15)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(19))->key() == - uint256(16)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(20))->key() == - uint256(16)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(24))->key() == - uint256(20)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(31))->key() == - uint256(30)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(32))->key() == - uint256(30)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(40))->key() == - uint256(39)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(47))->key() == - uint256(46)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(48))->key() == - uint256(47)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(64))->key() == - uint256(48)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(5))->key() == uint256(4)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(15))->key() == uint256(14)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(16))->key() == uint256(15)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(19))->key() == uint256(16)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(20))->key() == uint256(16)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(24))->key() == uint256(20)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(31))->key() == uint256(30)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(32))->key() == uint256(30)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(40))->key() == uint256(39)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(47))->key() == uint256(46)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(48))->key() == uint256(47)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(64))->key() == uint256(48)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(90))->key() == - uint256(66)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(96))->key() == - uint256(66)); - BEAST_EXPECT( - ledger->stateMap().lower_bound(uint256(100))->key() == - uint256(66)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(90))->key() == uint256(66)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(96))->key() == uint256(66)); + BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(100))->key() == uint256(66)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(0))->key() == - uint256(1)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(5))->key() == - uint256(6)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(15))->key() == - uint256(16)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(16))->key() == - uint256(20)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(18))->key() == - uint256(20)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(20))->key() == - uint256(25)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(31))->key() == - uint256(32)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(32))->key() == - uint256(33)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(47))->key() == - uint256(48)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(48))->key() == - uint256(66)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(53))->key() == - uint256(66)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(66))->key() == - uint256(100)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(70))->key() == - uint256(100)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(85))->key() == - uint256(100)); - BEAST_EXPECT( - ledger->stateMap().upper_bound(uint256(98))->key() == - uint256(100)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(0))->key() == uint256(1)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(5))->key() == uint256(6)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(15))->key() == uint256(16)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(16))->key() == uint256(20)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(18))->key() == uint256(20)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(20))->key() == uint256(25)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(31))->key() == uint256(32)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(32))->key() == uint256(33)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(47))->key() == uint256(48)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(48))->key() == uint256(66)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(53))->key() == uint256(66)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(66))->key() == uint256(100)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(70))->key() == uint256(100)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(85))->key() == uint256(100)); + BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(98))->key() == uint256(100)); BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(100)) == e); BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(155)) == e); } @@ -673,13 +580,9 @@ class View_test : public beast::unit_test::suite using namespace jtx; Env env(*this); Config config; - std::shared_ptr const genesis = std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); - auto const ledger = std::make_shared( - *genesis, env.app().timeKeeper().closeTime()); + std::shared_ptr const genesis = + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); + auto const ledger = std::make_shared(*genesis, env.app().timeKeeper().closeTime()); auto setup123 = [&ledger, this]() { // erase middle element wipe(*ledger); @@ -829,15 +732,7 @@ class View_test : public beast::unit_test::suite env.close(); // Alice's USD balance should be zero if frozen. - BEAST_EXPECT( - USD(0) == - accountHolds( - *env.closed(), - alice, - USD.currency, - gw, - fhZERO_IF_FROZEN, - env.journal)); + BEAST_EXPECT(USD(0) == accountHolds(*env.closed(), alice, USD.currency, gw, fhZERO_IF_FROZEN, env.journal)); // Thaw gw and try again. env(fclear(gw, asfGlobalFreeze)); @@ -854,28 +749,12 @@ class View_test : public beast::unit_test::suite env.close(); // Bob's balance should be zero if frozen. - BEAST_EXPECT( - USD(0) == - accountHolds( - *env.closed(), - bob, - USD.currency, - gw, - fhZERO_IF_FROZEN, - env.journal)); + BEAST_EXPECT(USD(0) == accountHolds(*env.closed(), bob, USD.currency, gw, fhZERO_IF_FROZEN, env.journal)); // gw thaws bob's trust line. bob gets his money back. env(trust(gw, USD(100), bob, tfClearFreeze)); env.close(); - BEAST_EXPECT( - USD(50) == - accountHolds( - *env.closed(), - bob, - USD.currency, - gw, - fhZERO_IF_FROZEN, - env.journal)); + BEAST_EXPECT(USD(50) == accountHolds(*env.closed(), bob, USD.currency, gw, fhZERO_IF_FROZEN, env.journal)); } { // accountHolds(). @@ -883,35 +762,15 @@ class View_test : public beast::unit_test::suite env.close(); // carol has no EUR. - BEAST_EXPECT( - EUR(0) == - accountHolds( - *env.closed(), - carol, - EUR.currency, - gw, - fhZERO_IF_FROZEN, - env.journal)); + BEAST_EXPECT(EUR(0) == accountHolds(*env.closed(), carol, EUR.currency, gw, fhZERO_IF_FROZEN, env.journal)); // But carol does have USD. BEAST_EXPECT( - USD(50) == - accountHolds( - *env.closed(), - carol, - USD.currency, - gw, - fhZERO_IF_FROZEN, - env.journal)); + USD(50) == accountHolds(*env.closed(), carol, USD.currency, gw, fhZERO_IF_FROZEN, env.journal)); // carol's XRP balance should be her holdings minus her reserve. - auto const carolsXRP = accountHolds( - *env.closed(), - carol, - xrpCurrency(), - xrpAccount(), - fhZERO_IF_FROZEN, - env.journal); + auto const carolsXRP = + accountHolds(*env.closed(), carol, xrpCurrency(), xrpAccount(), fhZERO_IF_FROZEN, env.journal); // carol's XRP balance: 10000 // base reserve: -200 // 1 trust line times its reserve: 1 * -50 @@ -926,37 +785,26 @@ class View_test : public beast::unit_test::suite // carol's XRP balance should now show as zero. BEAST_EXPECT( - XRP(0) == - accountHolds( - *env.closed(), - carol, - xrpCurrency(), - gw, - fhZERO_IF_FROZEN, - env.journal)); + XRP(0) == accountHolds(*env.closed(), carol, xrpCurrency(), gw, fhZERO_IF_FROZEN, env.journal)); } { // accountFunds(). // Gateways have whatever funds they claim to have. - auto const gwUSD = accountFunds( - *env.closed(), gw, USD(314159), fhZERO_IF_FROZEN, env.journal); + auto const gwUSD = accountFunds(*env.closed(), gw, USD(314159), fhZERO_IF_FROZEN, env.journal); BEAST_EXPECT(gwUSD == USD(314159)); // carol has funds from the gateway. - auto carolsUSD = accountFunds( - *env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal); + auto carolsUSD = accountFunds(*env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal); BEAST_EXPECT(carolsUSD == USD(50)); // If carol's funds are frozen she has no funds... env(fset(gw, asfGlobalFreeze)); env.close(); - carolsUSD = accountFunds( - *env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal); + carolsUSD = accountFunds(*env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal); BEAST_EXPECT(carolsUSD == USD(0)); // ... unless the query ignores the FROZEN state. - carolsUSD = accountFunds( - *env.closed(), carol, USD(0), fhIGNORE_FREEZE, env.journal); + carolsUSD = accountFunds(*env.closed(), carol, USD(0), fhIGNORE_FREEZE, env.journal); BEAST_EXPECT(carolsUSD == USD(50)); // Just to be tidy, thaw gw. @@ -1038,8 +886,8 @@ class View_test : public beast::unit_test::suite // Try the other interface. // Note that the different interface has different outcomes. - auto const& iA3 = rdViewA3->info(); - auto const& iA4 = rdViewA4->info(); + auto const& iA3 = rdViewA3->header(); + auto const& iA4 = rdViewA4->header(); BEAST_EXPECT(areCompatible(iA3.hash, iA3.seq, *rdViewA4, jStream, "")); BEAST_EXPECT(areCompatible(iA4.hash, iA4.seq, *rdViewA3, jStream, "")); @@ -1063,13 +911,8 @@ class View_test : public beast::unit_test::suite Env env(*this); Config config; std::shared_ptr const genesis = - std::make_shared( - create_genesis, - config, - std::vector{}, - env.app().getNodeFamily()); - auto const ledger = std::make_shared( - *genesis, env.app().timeKeeper().closeTime()); + std::make_shared(create_genesis, config, std::vector{}, env.app().getNodeFamily()); + auto const ledger = std::make_shared(*genesis, env.app().timeKeeper().closeTime()); wipe(*ledger); ledger->rawInsert(sle(1)); ReadView& v0 = *ledger; @@ -1133,14 +976,14 @@ class GetAmendments_test : public beast::unit_test::suite break; } - // There should be at least 5 amendments. Don't do exact comparison + // There should be at least 3 amendments. Don't do exact comparison // to avoid maintenance as more amendments are added in the future. BEAST_EXPECT(i == 254); - BEAST_EXPECT(majorities.size() >= 5); + BEAST_EXPECT(majorities.size() >= 2); // None of the amendments should be enabled yet. - auto enableds = getEnabledAmendments(*env.closed()); - BEAST_EXPECT(enableds.empty()); + auto enabledAmendments = getEnabledAmendments(*env.closed()); + BEAST_EXPECT(enabledAmendments.empty()); // Now wait 2 weeks modulo 256 ledgers for the amendments to be // enabled. Speed the process by closing ledgers every 80 minutes, @@ -1149,12 +992,12 @@ class GetAmendments_test : public beast::unit_test::suite { using namespace std::chrono_literals; env.close(80min); - enableds = getEnabledAmendments(*env.closed()); - if (!enableds.empty()) + enabledAmendments = getEnabledAmendments(*env.closed()); + if (!enabledAmendments.empty()) break; } BEAST_EXPECT(i == 255); - BEAST_EXPECT(enableds.size() >= 5); + BEAST_EXPECT(enabledAmendments.size() >= 2); } void @@ -1164,8 +1007,8 @@ class GetAmendments_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(View, ledger, ripple); -BEAST_DEFINE_TESTSUITE(GetAmendments, ledger, ripple); +BEAST_DEFINE_TESTSUITE(View, ledger, xrpl); +BEAST_DEFINE_TESTSUITE(GetAmendments, ledger, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/Backend_test.cpp b/src/test/nodestore/Backend_test.cpp index af5559b00f..19f3bc43e5 100644 --- a/src/test/nodestore/Backend_test.cpp +++ b/src/test/nodestore/Backend_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -38,10 +19,7 @@ class Backend_test : public TestBase { public: void - testBackend( - std::string const& type, - std::uint64_t const seedValue, - int numObjsToTest = 2000) + testBackend(std::string const& type, std::uint64_t const seedValue, int numObjsToTest = 2000) { DummyScheduler scheduler; @@ -62,8 +40,8 @@ public: { // Open the backend - std::unique_ptr backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + std::unique_ptr backend = + Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); backend->open(); // Write the batch @@ -87,8 +65,8 @@ public: { // Re-open the backend - std::unique_ptr backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + std::unique_ptr backend = + Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); backend->open(); // Read it back in @@ -110,17 +88,17 @@ public: testBackend("nudb", seedValue); -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE testBackend("rocksdb", seedValue); #endif -#ifdef RIPPLE_ENABLE_SQLITE_BACKEND_TESTS +#ifdef XRPL_ENABLE_SQLITE_BACKEND_TESTS testBackend("sqlite", seedValue); #endif } }; -BEAST_DEFINE_TESTSUITE(Backend, nodestore, ripple); +BEAST_DEFINE_TESTSUITE(Backend, nodestore, xrpl); } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/Basics_test.cpp b/src/test/nodestore/Basics_test.cpp index 0057d2658a..e37544f58e 100644 --- a/src/test/nodestore/Basics_test.cpp +++ b/src/test/nodestore/Basics_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { // Tests predictable batches, and NodeObject blob encoding @@ -59,15 +40,13 @@ public: { EncodedBlob encoded(batch[i]); - DecodedBlob decoded( - encoded.getKey(), encoded.getData(), encoded.getSize()); + DecodedBlob decoded(encoded.getKey(), encoded.getData(), encoded.getSize()); BEAST_EXPECT(decoded.wasOk()); if (decoded.wasOk()) { - std::shared_ptr const object( - decoded.createObject()); + std::shared_ptr const object(decoded.createObject()); BEAST_EXPECT(isSame(batch[i], object)); } @@ -85,7 +64,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(NodeStoreBasic, nodestore, ripple); +BEAST_DEFINE_TESTSUITE(NodeStoreBasic, nodestore, xrpl); } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/Database_test.cpp b/src/test/nodestore/Database_test.cpp index a47dfeab1a..1229923e7d 100644 --- a/src/test/nodestore/Database_test.cpp +++ b/src/test/nodestore/Database_test.cpp @@ -1,35 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -#include - #include #include #include +#include -namespace ripple { +namespace xrpl { namespace NodeStore { @@ -47,8 +27,8 @@ public: { testcase("Config"); - using namespace ripple::test; - using namespace ripple::test::jtx; + using namespace xrpl::test; + using namespace xrpl::test::jtx; auto const integrityWarning = "reducing the data integrity guarantees from the " @@ -63,12 +43,9 @@ public: if (BEAST_EXPECT(s.globalPragma->size() == 3)) { - BEAST_EXPECT( - s.globalPragma->at(0) == "PRAGMA journal_mode=wal;"); - BEAST_EXPECT( - s.globalPragma->at(1) == "PRAGMA synchronous=normal;"); - BEAST_EXPECT( - s.globalPragma->at(2) == "PRAGMA temp_store=file;"); + BEAST_EXPECT(s.globalPragma->at(0) == "PRAGMA journal_mode=wal;"); + BEAST_EXPECT(s.globalPragma->at(1) == "PRAGMA synchronous=normal;"); + BEAST_EXPECT(s.globalPragma->at(2) == "PRAGMA temp_store=file;"); } } { @@ -87,8 +64,7 @@ public: return Env( *this, std::move(p), - std::make_unique( - integrityWarning, &found), + std::make_unique(integrityWarning, &found), beast::severities::kWarning); }(); @@ -96,12 +72,9 @@ public: auto const s = setup_DatabaseCon(env.app().config()); if (BEAST_EXPECT(s.globalPragma->size() == 3)) { - BEAST_EXPECT( - s.globalPragma->at(0) == "PRAGMA journal_mode=wal;"); - BEAST_EXPECT( - s.globalPragma->at(1) == "PRAGMA synchronous=normal;"); - BEAST_EXPECT( - s.globalPragma->at(2) == "PRAGMA temp_store=file;"); + BEAST_EXPECT(s.globalPragma->at(0) == "PRAGMA journal_mode=wal;"); + BEAST_EXPECT(s.globalPragma->at(1) == "PRAGMA synchronous=normal;"); + BEAST_EXPECT(s.globalPragma->at(2) == "PRAGMA temp_store=file;"); } } { @@ -120,8 +93,7 @@ public: return Env( *this, std::move(p), - std::make_unique( - integrityWarning, &found), + std::make_unique(integrityWarning, &found), beast::severities::kWarning); }(); @@ -129,12 +101,9 @@ public: auto const s = setup_DatabaseCon(env.app().config()); if (BEAST_EXPECT(s.globalPragma->size() == 3)) { - BEAST_EXPECT( - s.globalPragma->at(0) == "PRAGMA journal_mode=memory;"); - BEAST_EXPECT( - s.globalPragma->at(1) == "PRAGMA synchronous=off;"); - BEAST_EXPECT( - s.globalPragma->at(2) == "PRAGMA temp_store=memory;"); + BEAST_EXPECT(s.globalPragma->at(0) == "PRAGMA journal_mode=memory;"); + BEAST_EXPECT(s.globalPragma->at(1) == "PRAGMA synchronous=off;"); + BEAST_EXPECT(s.globalPragma->at(2) == "PRAGMA temp_store=memory;"); } } { @@ -154,8 +123,7 @@ public: return Env( *this, std::move(p), - std::make_unique( - integrityWarning, &found), + std::make_unique(integrityWarning, &found), beast::severities::kWarning); }(); @@ -165,12 +133,9 @@ public: auto const s = setup_DatabaseCon(env.app().config()); if (BEAST_EXPECT(s.globalPragma->size() == 3)) { - BEAST_EXPECT( - s.globalPragma->at(0) == "PRAGMA journal_mode=off;"); - BEAST_EXPECT( - s.globalPragma->at(1) == "PRAGMA synchronous=extra;"); - BEAST_EXPECT( - s.globalPragma->at(2) == "PRAGMA temp_store=default;"); + BEAST_EXPECT(s.globalPragma->at(0) == "PRAGMA journal_mode=off;"); + BEAST_EXPECT(s.globalPragma->at(1) == "PRAGMA synchronous=extra;"); + BEAST_EXPECT(s.globalPragma->at(2) == "PRAGMA temp_store=default;"); } } { @@ -191,8 +156,7 @@ public: return Env( *this, std::move(p), - std::make_unique( - integrityWarning, &found), + std::make_unique(integrityWarning, &found), beast::severities::kWarning); }(); @@ -202,12 +166,9 @@ public: auto const s = setup_DatabaseCon(env.app().config()); if (BEAST_EXPECT(s.globalPragma->size() == 3)) { - BEAST_EXPECT( - s.globalPragma->at(0) == "PRAGMA journal_mode=off;"); - BEAST_EXPECT( - s.globalPragma->at(1) == "PRAGMA synchronous=extra;"); - BEAST_EXPECT( - s.globalPragma->at(2) == "PRAGMA temp_store=default;"); + BEAST_EXPECT(s.globalPragma->at(0) == "PRAGMA journal_mode=off;"); + BEAST_EXPECT(s.globalPragma->at(1) == "PRAGMA synchronous=extra;"); + BEAST_EXPECT(s.globalPragma->at(2) == "PRAGMA temp_store=default;"); } } { @@ -448,12 +409,9 @@ public: if (BEAST_EXPECT(s.txPragma.size() == 4)) { BEAST_EXPECT(s.txPragma.at(0) == "PRAGMA page_size=4096;"); - BEAST_EXPECT( - s.txPragma.at(1) == "PRAGMA journal_size_limit=1582080;"); - BEAST_EXPECT( - s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); - BEAST_EXPECT( - s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); + BEAST_EXPECT(s.txPragma.at(1) == "PRAGMA journal_size_limit=1582080;"); + BEAST_EXPECT(s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); + BEAST_EXPECT(s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); } } { @@ -471,18 +429,14 @@ public: if (BEAST_EXPECT(s.txPragma.size() == 4)) { BEAST_EXPECT(s.txPragma.at(0) == "PRAGMA page_size=512;"); - BEAST_EXPECT( - s.txPragma.at(1) == "PRAGMA journal_size_limit=2582080;"); - BEAST_EXPECT( - s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); - BEAST_EXPECT( - s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); + BEAST_EXPECT(s.txPragma.at(1) == "PRAGMA journal_size_limit=2582080;"); + BEAST_EXPECT(s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); + BEAST_EXPECT(s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); } } { // Error: Invalid values - auto const expected = - "Invalid page_size. Must be between 512 and 65536."; + auto const expected = "Invalid page_size. Must be between 512 and 65536."; bool found = false; auto p = test::jtx::envconfig(); { @@ -505,8 +459,7 @@ public: } { // Error: Invalid values - auto const expected = - "Invalid page_size. Must be between 512 and 65536."; + auto const expected = "Invalid page_size. Must be between 512 and 65536."; bool found = false; auto p = test::jtx::envconfig(); { @@ -555,10 +508,7 @@ public: //-------------------------------------------------------------------------- void - testImport( - std::string const& destBackendType, - std::string const& srcBackendType, - std::int64_t seedValue) + testImport(std::string const& destBackendType, std::string const& srcBackendType, std::int64_t seedValue) { DummyScheduler scheduler; @@ -572,8 +522,8 @@ public: // Write to source db { - std::unique_ptr src = Manager::instance().make_Database( - megabytes(4), scheduler, 2, srcParams, journal_); + std::unique_ptr src = + Manager::instance().make_Database(megabytes(4), scheduler, 2, srcParams, journal_); storeBatch(*src, batch); } @@ -581,8 +531,8 @@ public: { // Re-open the db - std::unique_ptr src = Manager::instance().make_Database( - megabytes(4), scheduler, 2, srcParams, journal_); + std::unique_ptr src = + Manager::instance().make_Database(megabytes(4), scheduler, 2, srcParams, journal_); // Set up the destination database beast::temp_dir dest_db; @@ -590,12 +540,10 @@ public: destParams.set("type", destBackendType); destParams.set("path", dest_db.path()); - std::unique_ptr dest = Manager::instance().make_Database( - megabytes(4), scheduler, 2, destParams, journal_); + std::unique_ptr dest = + Manager::instance().make_Database(megabytes(4), scheduler, 2, destParams, journal_); - testcase( - "import into '" + destBackendType + "' from '" + - srcBackendType + "'"); + testcase("import into '" + destBackendType + "' from '" + srcBackendType + "'"); // Do the import dest->importDatabase(*src); @@ -637,8 +585,8 @@ public: { // Open the database - std::unique_ptr db = Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); + std::unique_ptr db = + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); // Write the batch storeBatch(*db, batch); @@ -662,8 +610,8 @@ public: if (testPersistence) { // Re-open the database without the ephemeral DB - std::unique_ptr db = Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); + std::unique_ptr db = + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); // Read it back in Batch copy; @@ -680,10 +628,8 @@ public: // Verify default earliest ledger sequence { std::unique_ptr db = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); - BEAST_EXPECT( - db->earliestLedgerSeq() == XRP_LEDGER_EARLIEST_SEQ); + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); + BEAST_EXPECT(db->earliestLedgerSeq() == XRP_LEDGER_EARLIEST_SEQ); } // Set an invalid earliest ledger sequence @@ -691,21 +637,18 @@ public: { nodeParams.set("earliest_seq", "0"); std::unique_ptr db = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); } catch (std::runtime_error const& e) { - BEAST_EXPECT( - std::strcmp(e.what(), "Invalid earliest_seq") == 0); + BEAST_EXPECT(std::strcmp(e.what(), "Invalid earliest_seq") == 0); } { // Set a valid earliest ledger sequence nodeParams.set("earliest_seq", "1"); std::unique_ptr db = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); // Verify database uses the earliest ledger sequence setting BEAST_EXPECT(db->earliestLedgerSeq() == 1); @@ -715,17 +658,13 @@ public: try { // Set to default earliest ledger sequence - nodeParams.set( - "earliest_seq", std::to_string(XRP_LEDGER_EARLIEST_SEQ)); + nodeParams.set("earliest_seq", std::to_string(XRP_LEDGER_EARLIEST_SEQ)); std::unique_ptr db2 = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); + Manager::instance().make_Database(megabytes(4), scheduler, 2, nodeParams, journal_); } catch (std::runtime_error const& e) { - BEAST_EXPECT( - std::strcmp(e.what(), "earliest_seq set more than once") == - 0); + BEAST_EXPECT(std::strcmp(e.what(), "earliest_seq set more than once") == 0); } } } @@ -745,7 +684,7 @@ public: { testNodeStore("nudb", true, seedValue); -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE testNodeStore("rocksdb", true, seedValue); #endif } @@ -754,18 +693,18 @@ public: { testImport("nudb", "nudb", seedValue); -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE testImport("rocksdb", "rocksdb", seedValue); #endif -#if RIPPLE_ENABLE_SQLITE_BACKEND_TESTS +#if XRPL_ENABLE_SQLITE_BACKEND_TESTS testImport("sqlite", "sqlite", seedValue); #endif } } }; -BEAST_DEFINE_TESTSUITE(Database, nodestore, ripple); +BEAST_DEFINE_TESTSUITE(Database, nodestore, xrpl); } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/NuDBFactory_test.cpp b/src/test/nodestore/NuDBFactory_test.cpp index 387c83a446..7d8f1df45d 100644 --- a/src/test/nodestore/NuDBFactory_test.cpp +++ b/src/test/nodestore/NuDBFactory_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { class NuDBFactory_test : public TestBase @@ -49,17 +30,14 @@ private: // Helper function to create a backend and test basic functionality bool - testBackendFunctionality( - Section const& params, - std::size_t expectedBlocksize) + testBackendFunctionality(Section const& params, std::size_t expectedBlocksize) { try { DummyScheduler scheduler; test::SuiteJournal journal("NuDBFactory_test", *this); - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); if (!BEAST_EXPECT(backend)) return false; @@ -91,17 +69,13 @@ private: // Helper function to test log messages void - testLogMessage( - Section const& params, - beast::severities::Severity level, - std::string const& expectedMessage) + testLogMessage(Section const& params, beast::severities::Severity level, std::string const& expectedMessage) { test::StreamSink sink(level); beast::Journal journal(sink); DummyScheduler scheduler; - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); std::string logOutput = sink.messages().str(); BEAST_EXPECT(logOutput.find(expectedMessage) != std::string::npos); @@ -118,12 +92,10 @@ private: beast::Journal journal(sink); DummyScheduler scheduler; - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); std::string logOutput = sink.messages().str(); - bool hasWarning = - logOutput.find("Invalid nudb_block_size") != std::string::npos; + bool hasWarning = logOutput.find("Invalid nudb_block_size") != std::string::npos; BEAST_EXPECT(hasWarning == !shouldWork); } @@ -218,10 +190,7 @@ public: beast::temp_dir tempDir; auto params = createSection(tempDir.path(), "8192"); - testLogMessage( - params, - beast::severities::kInfo, - "Using custom NuDB block size: 8192"); + testLogMessage(params, beast::severities::kInfo, "Using custom NuDB block size: 8192"); } // Test invalid block size failure @@ -235,20 +204,14 @@ public: DummyScheduler scheduler; try { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); fail(); } catch (std::exception const& e) { std::string logOutput{e.what()}; - BEAST_EXPECT( - logOutput.find("Invalid nudb_block_size: 5000") != - std::string::npos); - BEAST_EXPECT( - logOutput.find( - "Must be power of 2 between 4096 and 32768") != - std::string::npos); + BEAST_EXPECT(logOutput.find("Invalid nudb_block_size: 5000") != std::string::npos); + BEAST_EXPECT(logOutput.find("Must be power of 2 between 4096 and 32768") != std::string::npos); } } @@ -263,17 +226,14 @@ public: DummyScheduler scheduler; try { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); fail(); } catch (std::exception const& e) { std::string logOutput{e.what()}; - BEAST_EXPECT( - logOutput.find("Invalid nudb_block_size value: invalid") != - std::string::npos); + BEAST_EXPECT(logOutput.find("Invalid nudb_block_size value: invalid") != std::string::npos); } } } @@ -309,16 +269,13 @@ public: DummyScheduler scheduler; try { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); BEAST_EXPECT(shouldWork); } catch (std::exception const& e) { std::string logOutput{e.what()}; - BEAST_EXPECT( - logOutput.find("Invalid nudb_block_size") != - std::string::npos); + BEAST_EXPECT(logOutput.find("Invalid nudb_block_size") != std::string::npos); } } } @@ -336,8 +293,7 @@ public: // Test first constructor (without nudb::context) { - auto backend1 = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend1 = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); BEAST_EXPECT(backend1 != nullptr); BEAST_EXPECT(testBackendFunctionality(params, 16384)); } @@ -377,14 +333,11 @@ public: beast::Journal journal(sink); DummyScheduler scheduler; - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); // Should log success message for valid values std::string logOutput = sink.messages().str(); - bool hasSuccessMessage = - logOutput.find("Using custom NuDB block size") != - std::string::npos; + bool hasSuccessMessage = logOutput.find("Using custom NuDB block size") != std::string::npos; BEAST_EXPECT(hasSuccessMessage); } @@ -402,8 +355,7 @@ public: DummyScheduler scheduler; try { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); fail(); } catch (...) @@ -419,8 +371,7 @@ public: { testcase("Data persistence with different block sizes"); - std::vector blockSizes = { - "4096", "8192", "16384", "32768"}; + std::vector blockSizes = {"4096", "8192", "16384", "32768"}; for (auto const& size : blockSizes) { @@ -435,8 +386,7 @@ public: // Store data { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); backend->open(); storeBatch(*backend, batch); backend->close(); @@ -444,8 +394,7 @@ public: // Retrieve data in new backend instance { - auto backend = Manager::instance().make_Backend( - params, megabytes(4), scheduler, journal); + auto backend = Manager::instance().make_Backend(params, megabytes(4), scheduler, journal); backend->open(); Batch copy; @@ -471,7 +420,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(NuDBFactory, ripple_core, ripple); +BEAST_DEFINE_TESTSUITE(NuDBFactory, xrpl_core, xrpl); } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/TestBase.h b/src/test/nodestore/TestBase.h index 8c44e9d918..dfa2b05642 100644 --- a/src/test/nodestore/TestBase.h +++ b/src/test/nodestore/TestBase.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NODESTORE_BASE_H_INCLUDED -#define RIPPLE_NODESTORE_BASE_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include -namespace ripple { +namespace xrpl { namespace NodeStore { /** Binary function that satisfies the strict-weak-ordering requirement. @@ -46,9 +26,7 @@ namespace NodeStore { struct LessThan { bool - operator()( - std::shared_ptr const& lhs, - std::shared_ptr const& rhs) const noexcept + operator()(std::shared_ptr const& lhs, std::shared_ptr const& rhs) const noexcept { return lhs->getHash() < rhs->getHash(); } @@ -56,12 +34,9 @@ struct LessThan /** Returns `true` if objects are identical. */ inline bool -isSame( - std::shared_ptr const& lhs, - std::shared_ptr const& rhs) +isSame(std::shared_ptr const& lhs, std::shared_ptr const& rhs) { - return (lhs->getType() == rhs->getType()) && - (lhs->getHash() == rhs->getHash()) && + return (lhs->getType() == rhs->getType()) && (lhs->getHash() == rhs->getHash()) && (lhs->getData() == rhs->getData()); } @@ -100,7 +75,7 @@ public: case 3: return hotUNKNOWN; } - // will never happen, but make static analysys tool happy. + // will never happen, but make static analysis tool happy. return hotUNKNOWN; }(); @@ -110,8 +85,7 @@ public: Blob blob(rand_int(rng, minPayloadBytes, maxPayloadBytes)); beast::rngfill(blob.data(), blob.size(), rng); - batch.push_back( - NodeObject::createObject(type, std::move(blob), hash)); + batch.push_back(NodeObject::createObject(type, std::move(blob), hash)); } return batch; @@ -163,8 +137,7 @@ public: { std::shared_ptr object; - Status const status = - backend.fetch(batch[i]->getHash().cbegin(), &object); + Status const status = backend.fetch(batch[i]->getHash().cbegin(), &object); BEAST_EXPECT(status == ok); @@ -184,8 +157,7 @@ public: { std::shared_ptr object; - Status const status = - backend.fetch(batch[i]->getHash().cbegin(), &object); + Status const status = backend.fetch(batch[i]->getHash().cbegin(), &object); BEAST_EXPECT(status == notFound); } @@ -201,11 +173,7 @@ public: Blob data(object->getData()); - db.store( - object->getType(), - std::move(data), - object->getHash(), - db.earliestLedgerSeq()); + db.store(object->getType(), std::move(data), object->getHash(), db.earliestLedgerSeq()); } } @@ -218,8 +186,7 @@ public: for (int i = 0; i < batch.size(); ++i) { - std::shared_ptr object = - db.fetchNodeObject(batch[i]->getHash(), 0); + std::shared_ptr object = db.fetchNodeObject(batch[i]->getHash(), 0); if (object != nullptr) pCopy->push_back(object); @@ -228,6 +195,4 @@ public: }; } // namespace NodeStore -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/nodestore/Timing_test.cpp b/src/test/nodestore/Timing_test.cpp index b2acb8eac3..09e39028e8 100644 --- a/src/test/nodestore/Timing_test.cpp +++ b/src/test/nodestore/Timing_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -46,17 +27,13 @@ #define NODESTORE_TIMING_DO_VERIFY 0 #endif -namespace ripple { +namespace xrpl { namespace NodeStore { std::unique_ptr -make_Backend( - Section const& config, - Scheduler& scheduler, - beast::Journal journal) +make_Backend(Section const& config, Scheduler& scheduler, beast::Journal journal) { - return Manager::instance().make_Backend( - config, megabytes(4), scheduler, journal); + return Manager::instance().make_Backend(config, megabytes(4), scheduler, journal); } // Fill memory with random bits @@ -123,8 +100,7 @@ public: rngcpy(data + 1, key.size() - 1, gen_); Blob value(d_size_(gen_)); rngcpy(&value[0], value.size(), gen_); - return NodeObject::createObject( - safe_cast(d_type_(gen_)), std::move(value), key); + return NodeObject::createObject(safe_cast(d_type_(gen_)), std::move(value), key); } // returns a batch of NodeObjects starting at n @@ -169,8 +145,7 @@ public: { std::string s; for (auto iter = config.begin(); iter != config.end(); ++iter) - s += (iter != config.begin() ? "," : "") + iter->first + "=" + - iter->second; + s += (iter != config.begin() ? "," : "") + iter->first + "=" + iter->second; return s; } @@ -204,8 +179,7 @@ public: std::atomic& c_; public: - parallel_for_lambda(std::size_t n, std::atomic& c) - : n_(n), c_(c) + parallel_for_lambda(std::size_t n, std::atomic& c) : n_(n), c_(c) { } @@ -232,10 +206,7 @@ public: */ template void - parallel_for( - std::size_t const n, - std::size_t number_of_threads, - Args const&... args) + parallel_for(std::size_t const n, std::size_t number_of_threads, Args const&... args) { std::atomic c(0); std::vector t; @@ -248,10 +219,7 @@ public: template void - parallel_for_id( - std::size_t const n, - std::size_t number_of_threads, - Args const&... args) + parallel_for_id(std::size_t const n, std::size_t number_of_threads, Args const&... args) { std::atomic c(0); std::vector t; @@ -266,10 +234,7 @@ public: // Insert only void - do_insert( - Section const& config, - Params const& params, - beast::Journal journal) + do_insert(Section const& config, Params const& params, beast::Journal journal) { DummyScheduler scheduler; auto backend = make_Backend(config, scheduler, journal); @@ -284,8 +249,7 @@ public: Sequence seq_; public: - explicit Body(suite& s, Backend& backend) - : suite_(s), backend_(backend), seq_(1) + explicit Body(suite& s, Backend& backend) : suite_(s), backend_(backend), seq_(1) { } @@ -305,11 +269,7 @@ public: try { - parallel_for( - params.items, - params.threads, - std::ref(*this), - std::ref(*backend)); + parallel_for(params.items, params.threads, std::ref(*this), std::ref(*backend)); } catch (std::exception const&) { @@ -323,10 +283,7 @@ public: // Fetch existing keys void - do_fetch( - Section const& config, - Params const& params, - beast::Journal journal) + do_fetch(Section const& config, Params const& params, beast::Journal journal) { DummyScheduler scheduler; auto backend = make_Backend(config, scheduler, journal); @@ -343,16 +300,8 @@ public: std::uniform_int_distribution dist_; public: - Body( - std::size_t id, - suite& s, - Params const& params, - Backend& backend) - : suite_(s) - , backend_(backend) - , seq1_(1) - , gen_(id + 1) - , dist_(0, params.items - 1) + Body(std::size_t id, suite& s, Params const& params, Backend& backend) + : suite_(s), backend_(backend), seq1_(1), gen_(id + 1), dist_(0, params.items - 1) { } @@ -375,12 +324,7 @@ public: }; try { - parallel_for_id( - params.items, - params.threads, - std::ref(*this), - std::ref(params), - std::ref(*backend)); + parallel_for_id(params.items, params.threads, std::ref(*this), std::ref(params), std::ref(*backend)); } catch (std::exception const&) { @@ -394,10 +338,7 @@ public: // Perform lookups of non-existent keys void - do_missing( - Section const& config, - Params const& params, - beast::Journal journal) + do_missing(Section const& config, Params const& params, beast::Journal journal) { DummyScheduler scheduler; auto backend = make_Backend(config, scheduler, journal); @@ -415,11 +356,7 @@ public: std::uniform_int_distribution dist_; public: - Body( - std::size_t id, - suite& s, - Params const& params, - Backend& backend) + Body(std::size_t id, suite& s, Params const& params, Backend& backend) : suite_(s) //, params_ (params) , backend_(backend) @@ -448,12 +385,7 @@ public: try { - parallel_for_id( - params.items, - params.threads, - std::ref(*this), - std::ref(params), - std::ref(*backend)); + parallel_for_id(params.items, params.threads, std::ref(*this), std::ref(params), std::ref(*backend)); } catch (std::exception const&) { @@ -467,10 +399,7 @@ public: // Fetch with present and missing keys void - do_mixed( - Section const& config, - Params const& params, - beast::Journal journal) + do_mixed(Section const& config, Params const& params, beast::Journal journal) { DummyScheduler scheduler; auto backend = make_Backend(config, scheduler, journal); @@ -490,11 +419,7 @@ public: std::uniform_int_distribution dist_; public: - Body( - std::size_t id, - suite& s, - Params const& params, - Backend& backend) + Body(std::size_t id, suite& s, Params const& params, Backend& backend) : suite_(s) //, params_ (params) , backend_(backend) @@ -536,12 +461,7 @@ public: try { - parallel_for_id( - params.items, - params.threads, - std::ref(*this), - std::ref(params), - std::ref(*backend)); + parallel_for_id(params.items, params.threads, std::ref(*this), std::ref(params), std::ref(*backend)); } catch (std::exception const&) { @@ -580,11 +500,7 @@ public: std::uniform_int_distribution older_; public: - Body( - std::size_t id, - suite& s, - Params const& params, - Backend& backend) + Body(std::size_t id, suite& s, Params const& params, Backend& backend) : suite_(s) , params_(params) , backend_(backend) @@ -650,12 +566,7 @@ public: try { - parallel_for_id( - params.items, - params.threads, - std::ref(*this), - std::ref(params), - std::ref(*backend)); + parallel_for_id(params.items, params.threads, std::ref(*this), std::ref(params), std::ref(*backend)); } catch (std::exception const&) { @@ -669,36 +580,26 @@ public: //-------------------------------------------------------------------------- - using test_func = - void (Timing_test::*)(Section const&, Params const&, beast::Journal); + using test_func = void (Timing_test::*)(Section const&, Params const&, beast::Journal); using test_list = std::vector>; duration_type - do_test( - test_func f, - Section const& config, - Params const& params, - beast::Journal journal) + do_test(test_func f, Section const& config, Params const& params, beast::Journal journal) { auto const start = clock_type::now(); (this->*f)(config, params, journal); - return std::chrono::duration_cast( - clock_type::now() - start); + return std::chrono::duration_cast(clock_type::now() - start); } void - do_tests( - std::size_t threads, - test_list const& tests, - std::vector const& config_strings) + do_tests(std::size_t threads, test_list const& tests, std::vector const& config_strings) { using std::setw; int w = 8; for (auto const& test : tests) if (w < test.first.size()) w = test.first.size(); - log << threads << " Thread" << (threads > 1 ? "s" : "") << ", " - << default_items << " Objects" << std::endl; + log << threads << " Thread" << (threads > 1 ? "s" : "") << ", " << default_items << " Objects" << std::endl; { std::stringstream ss; ss << std::left << setw(10) << "Backend" << std::right; @@ -721,12 +622,9 @@ public: Section config = parse(config_string); config.set("path", tempDir.path()); std::stringstream ss; - ss << std::left << setw(10) - << get(config, "type", std::string()) << std::right; + ss << std::left << setw(10) << get(config, "type", std::string()) << std::right; for (auto const& test : tests) - ss << " " << setw(w) - << to_string( - do_test(test.second, config, params, journal)); + ss << " " << setw(w) << to_string(do_test(test.second, config, params, journal)); ss << " " << to_string(config); log << ss.str() << std::endl; } @@ -746,7 +644,7 @@ public: */ std::string default_args = "type=nudb" -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE ";type=rocksdb,open_files=2000,filter_bits=12,cache_mb=256," "file_size_mb=8,file_size_mult=2" #endif @@ -778,7 +676,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Timing, nodestore, ripple, 1); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Timing, nodestore, xrpl, 1); } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/import_test.cpp b/src/test/nodestore/import_test.cpp index 3aeacb35f0..896f9558da 100644 --- a/src/test/nodestore/import_test.cpp +++ b/src/test/nodestore/import_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -59,7 +40,7 @@ multi(32gb): */ -namespace ripple { +namespace xrpl { namespace detail { @@ -81,10 +62,7 @@ public: save_stream_state& operator=(save_stream_state const&) = delete; explicit save_stream_state(std::ostream& os) - : os_(os) - , precision_(os.precision()) - , flags_(os.flags()) - , fill_(os.fill()) + : os_(os), precision_(os.precision()), flags_(os.flags()), fill_(os.fill()) { } }; @@ -231,11 +209,9 @@ public: return; } auto const rate = elapsed.count() / double(work); - clock_type::duration const remain( - static_cast((work_ - work) * rate)); - log << "Remaining: " << detail::fmtdur(remain) << " (" << work << " of " - << work_ << " in " << detail::fmtdur(elapsed) << ", " - << (work - prev_) << " in " << detail::fmtdur(now - report_) << ")"; + clock_type::duration const remain(static_cast((work_ - work) * rate)); + log << "Remaining: " << detail::fmtdur(remain) << " (" << work << " of " << work_ << " in " + << detail::fmtdur(elapsed) << ", " << (work - prev_) << " in " << detail::fmtdur(now - report_) << ")"; report_ = now; prev_ = work; } @@ -254,7 +230,7 @@ parse_args(std::string const& s) // '=' static boost::regex const re1( "^" // start of line - "(?:\\s*)" // whitespace (optonal) + "(?:\\s*)" // whitespace (optional) "([a-zA-Z][_a-zA-Z0-9]*)" // "(?:\\s*)" // whitespace (optional) "(?:=)" // '=' @@ -279,7 +255,7 @@ parse_args(std::string const& s) //------------------------------------------------------------------------------ -#if RIPPLE_ROCKSDB_AVAILABLE +#if XRPL_ROCKSDB_AVAILABLE class import_test : public beast::unit_test::suite { @@ -354,11 +330,9 @@ public: options.create_if_missing = false; options.max_open_files = 2000; // 5000? rocksdb::DB* pdb = nullptr; - rocksdb::Status status = - rocksdb::DB::OpenForReadOnly(options, from_path, &pdb); + rocksdb::Status status = rocksdb::DB::OpenForReadOnly(options, from_path, &pdb); if (!status.ok() || !pdb) - Throw( - "Can't open '" + from_path + "': " + status.ToString()); + Throw("Can't open '" + from_path + "': " + status.ToString()); db.reset(pdb); } // Create data file with values @@ -391,9 +365,7 @@ public: for (it->SeekToFirst(); it->Valid(); it->Next()) { if (it->key().size() != 32) - Throw( - "Unexpected key size " + - std::to_string(it->key().size())); + Throw("Unexpected key size " + std::to_string(it->key().size())); void const* const key = it->key().data(); void const* const data = it->value().data(); auto const size = it->value().size(); @@ -404,11 +376,9 @@ public: // Verify codec correctness { buffer buf2; - auto const check = - nodeobject_decompress(out.first, out.second, buf2); + auto const check = nodeobject_decompress(out.first, out.second, buf2); BEAST_EXPECT(check.second == size); - BEAST_EXPECT( - std::memcmp(check.first, clean.get(), size) == 0); + BEAST_EXPECT(std::memcmp(check.first, clean.get(), size) == 0); } // Data Record auto os = dw.prepare( @@ -428,8 +398,7 @@ public: Throw(ec); } db.reset(); - log << "Import data: " - << detail::fmtdur(std::chrono::steady_clock::now() - start); + log << "Import data: " << detail::fmtdur(std::chrono::steady_clock::now() - start); auto const df_size = df.size(ec); if (ec) Throw(ec); @@ -443,8 +412,7 @@ public: kh.pepper = pepper(kh.salt); kh.block_size = block_size(kp); kh.load_factor = std::min(65536.0 * load_factor, 65535); - kh.buckets = - std::ceil(nitems / (bucket_capacity(kh.block_size) * load_factor)); + kh.buckets = std::ceil(nitems / (bucket_capacity(kh.block_size) * load_factor)); kh.modulus = ceil_pow2(kh.buckets); native_file kf; kf.create(file_mode::append, kp, ec); @@ -462,8 +430,7 @@ public: // Build contiguous sequential sections of the // key file using multiple passes over the data. // - auto const buckets = - std::max(1, buffer_size / kh.block_size); + auto const buckets = std::max(1, buffer_size / kh.block_size); buf.reserve(buckets * kh.block_size); auto const passes = (kh.buckets + buckets - 1) / buckets; log << "items: " << nitems @@ -490,8 +457,7 @@ public: } // Insert all keys into buckets // Iterate Data File - bulk_reader r( - df, dat_file_header::size, df_size, bulk_size); + bulk_reader r(df, dat_file_header::size, df_size, bulk_size); while (!r.eof()) { auto const offset = r.offset(); @@ -516,8 +482,7 @@ public: p(log, npass * df_size + r.offset()); if (n < b0 || n >= b1) continue; - bucket b( - kh.block_size, buf.get() + (n - b0) * kh.block_size); + bucket b(kh.block_size, buf.get() + (n - b0) * kh.block_size); maybe_spill(b, dw, ec); if (ec) Throw(ec); @@ -536,8 +501,7 @@ public: Throw(ec); } } - kf.write( - (b0 + 1) * kh.block_size, buf.get(), bn * kh.block_size, ec); + kf.write((b0 + 1) * kh.block_size, buf.get(), bn * kh.block_size, ec); if (ec) Throw(ec); ++npass; @@ -549,11 +513,11 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL(import, nodestore, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(import, nodestore, xrpl); #endif //------------------------------------------------------------------------------ } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/nodestore/varint_test.cpp b/src/test/nodestore/varint_test.cpp index 3baf3c6d67..7ef624e777 100644 --- a/src/test/nodestore/varint_test.cpp +++ b/src/test/nodestore/varint_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2014, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace NodeStore { namespace tests { @@ -71,8 +52,8 @@ public: } }; -BEAST_DEFINE_TESTSUITE(varint, nodestore, ripple); +BEAST_DEFINE_TESTSUITE(varint, nodestore, xrpl); } // namespace tests } // namespace NodeStore -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/ProtocolVersion_test.cpp b/src/test/overlay/ProtocolVersion_test.cpp index da976f8901..02cbaba909 100644 --- a/src/test/overlay/ProtocolVersion_test.cpp +++ b/src/test/overlay/ProtocolVersion_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class ProtocolVersion_test : public beast::unit_test::suite { @@ -81,23 +62,15 @@ public: testcase("Protocol version negotiation"); BEAST_EXPECT(negotiateProtocolVersion("RTXP/1.2") == std::nullopt); - BEAST_EXPECT( - negotiateProtocolVersion("RTXP/1.2, XRPL/2.0, XRPL/2.1") == - make_protocol(2, 1)); - BEAST_EXPECT( - negotiateProtocolVersion("XRPL/2.2") == make_protocol(2, 2)); - BEAST_EXPECT( - negotiateProtocolVersion( - "RTXP/1.2, XRPL/2.2, XRPL/2.3, XRPL/999.999") == - make_protocol(2, 2)); - BEAST_EXPECT( - negotiateProtocolVersion("XRPL/999.999, WebSocket/1.0") == - std::nullopt); + BEAST_EXPECT(negotiateProtocolVersion("RTXP/1.2, XRPL/2.0, XRPL/2.1") == make_protocol(2, 1)); + BEAST_EXPECT(negotiateProtocolVersion("XRPL/2.2") == make_protocol(2, 2)); + BEAST_EXPECT(negotiateProtocolVersion("RTXP/1.2, XRPL/2.2, XRPL/2.3, XRPL/999.999") == make_protocol(2, 2)); + BEAST_EXPECT(negotiateProtocolVersion("XRPL/999.999, WebSocket/1.0") == std::nullopt); BEAST_EXPECT(negotiateProtocolVersion("") == std::nullopt); } } }; -BEAST_DEFINE_TESTSUITE(ProtocolVersion, overlay, ripple); +BEAST_DEFINE_TESTSUITE(ProtocolVersion, overlay, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/TMGetObjectByHash_test.cpp b/src/test/overlay/TMGetObjectByHash_test.cpp new file mode 100644 index 0000000000..c4e70ba305 --- /dev/null +++ b/src/test/overlay/TMGetObjectByHash_test.cpp @@ -0,0 +1,195 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl { +namespace test { + +using namespace jtx; + +/** + * Test for TMGetObjectByHash reply size limiting. + * + * This verifies the fix that limits TMGetObjectByHash replies to + * Tuning::hardMaxReplyNodes to prevent excessive memory usage and + * potential DoS attacks from peers requesting large numbers of objects. + */ +class TMGetObjectByHash_test : public beast::unit_test::suite +{ + using middle_type = boost::beast::tcp_stream; + using stream_type = boost::beast::ssl_stream; + using socket_type = boost::asio::ip::tcp::socket; + using shared_context = std::shared_ptr; + /** + * Test peer that captures sent messages for verification. + */ + class PeerTest : public PeerImp + { + public: + PeerTest( + Application& app, + std::shared_ptr const& slot, + http_request_type&& request, + PublicKey const& publicKey, + ProtocolVersion protocol, + Resource::Consumer consumer, + std::unique_ptr&& stream_ptr, + OverlayImpl& overlay) + : PeerImp( + app, + id_++, + slot, + std::move(request), + publicKey, + protocol, + consumer, + std::move(stream_ptr), + overlay) + { + } + + ~PeerTest() = default; + + void + run() override + { + } + + void + send(std::shared_ptr const& m) override + { + lastSentMessage_ = m; + } + + std::shared_ptr + getLastSentMessage() const + { + return lastSentMessage_; + } + + static void + resetId() + { + id_ = 0; + } + + private: + inline static Peer::id_t id_ = 0; + std::shared_ptr lastSentMessage_; + }; + + shared_context context_{make_SSLContext("")}; + ProtocolVersion protocolVersion_{1, 7}; + + std::shared_ptr + createPeer(jtx::Env& env) + { + auto& overlay = dynamic_cast(env.app().overlay()); + boost::beast::http::request request; + auto stream_ptr = std::make_unique(socket_type(env.app().getIOContext()), *context_); + + beast::IP::Endpoint local(boost::asio::ip::make_address("172.1.1.1"), 51235); + beast::IP::Endpoint remote(boost::asio::ip::make_address("172.1.1.2"), 51235); + + PublicKey key(std::get<0>(randomKeyPair(KeyType::ed25519))); + auto consumer = overlay.resourceManager().newInboundEndpoint(remote); + auto [slot, _] = overlay.peerFinder().new_inbound_slot(local, remote); + + auto peer = std::make_shared( + env.app(), slot, std::move(request), key, protocolVersion_, consumer, std::move(stream_ptr), overlay); + + overlay.add_active(peer); + return peer; + } + + std::shared_ptr + createRequest(size_t const numObjects, Env& env) + { + // Store objects in the NodeStore that will be found during the query + auto& nodeStore = env.app().getNodeStore(); + + // Create and store objects + std::vector hashes; + hashes.reserve(numObjects); + for (int i = 0; i < numObjects; ++i) + { + uint256 hash(xrpl::sha512Half(i)); + hashes.push_back(hash); + + Blob data(100, static_cast(i % 256)); + nodeStore.store(hotLEDGER, std::move(data), hash, nodeStore.earliestLedgerSeq()); + } + + // Create a request with more objects than hardMaxReplyNodes + auto request = std::make_shared(); + request->set_type(protocol::TMGetObjectByHash_ObjectType_otLEDGER); + request->set_query(true); + + for (int i = 0; i < numObjects; ++i) + { + auto object = request->add_objects(); + object->set_hash(hashes[i].data(), hashes[i].size()); + object->set_ledgerseq(i); + } + return request; + } + + /** + * Test that reply is limited to hardMaxReplyNodes when more objects + * are requested than the limit allows. + */ + void + testReplyLimit(size_t const numObjects, int const expectedReplySize) + { + testcase("Reply Limit"); + + Env env(*this); + PeerTest::resetId(); + + auto peer = createPeer(env); + + auto request = createRequest(numObjects, env); + // Call the onMessage handler + peer->onMessage(request); + + // Verify that a reply was sent + auto sentMessage = peer->getLastSentMessage(); + BEAST_EXPECT(sentMessage != nullptr); + + // Parse the reply message + auto const& buffer = sentMessage->getBuffer(compression::Compressed::Off); + + BEAST_EXPECT(buffer.size() > 6); + // Skip the message header (6 bytes: 4 for size, 2 for type) + protocol::TMGetObjectByHash reply; + BEAST_EXPECT(reply.ParseFromArray(buffer.data() + 6, buffer.size() - 6) == true); + + // Verify the reply is limited to expectedReplySize + BEAST_EXPECT(reply.objects_size() == expectedReplySize); + } + + void + run() override + { + int const limit = static_cast(Tuning::hardMaxReplyNodes); + testReplyLimit(limit + 1, limit); + testReplyLimit(limit, limit); + testReplyLimit(limit - 1, limit - 1); + } +}; + +BEAST_DEFINE_TESTSUITE(TMGetObjectByHash, overlay, xrpl); + +} // namespace test +} // namespace xrpl diff --git a/src/test/overlay/cluster_test.cpp b/src/test/overlay/cluster_test.cpp index 76bbc9d4e3..60fd5d62b3 100644 --- a/src/test/overlay/cluster_test.cpp +++ b/src/test/overlay/cluster_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,10 +6,10 @@ #include #include -namespace ripple { +namespace xrpl { namespace tests { -class cluster_test : public ripple::TestSuite +class cluster_test : public xrpl::TestSuite { test::SuiteJournal journal_; @@ -88,8 +69,7 @@ public: { testcase("Membership: Non-empty cluster and some present"); - std::vector cluster( - network.begin(), network.begin() + 16); + std::vector cluster(network.begin(), network.begin() + 16); while (cluster.size() != 32) cluster.push_back(randomNode()); @@ -102,17 +82,14 @@ public: for (auto const& n : network) { auto found = std::find(cluster.begin(), cluster.end(), n); - BEAST_EXPECT( - static_cast(c->member(n)) == - (found != cluster.end())); + BEAST_EXPECT(static_cast(c->member(n)) == (found != cluster.end())); } } { testcase("Membership: Non-empty cluster and all present"); - std::vector cluster( - network.begin(), network.begin() + 32); + std::vector cluster(network.begin(), network.begin() + 32); auto c = create(cluster); @@ -122,9 +99,7 @@ public: for (auto const& n : network) { auto found = std::find(cluster.begin(), cluster.end(), n); - BEAST_EXPECT( - static_cast(c->member(n)) == - (found != cluster.end())); + BEAST_EXPECT(static_cast(c->member(n)) == (found != cluster.end())); } } } @@ -200,8 +175,7 @@ public: while (network.size() != 8) network.push_back(randomNode()); - auto format = [](PublicKey const& publicKey, - char const* comment = nullptr) { + auto format = [](PublicKey const& publicKey, char const* comment = nullptr) { auto ret = toBase58(TokenType::NodePublic, publicKey); if (comment) @@ -224,8 +198,7 @@ public: s1.append(format(network[4], " Leading Whitespace")); s1.append(format(network[5], " Trailing Whitespace ")); s1.append(format(network[6], " Leading & Trailing Whitespace ")); - s1.append(format( - network[7], " Leading, Trailing & Internal Whitespace ")); + s1.append(format(network[7], " Leading, Trailing & Internal Whitespace ")); BEAST_EXPECT(c->load(s1)); @@ -246,7 +219,7 @@ public: BEAST_EXPECT(!c->load(s4)); // Check if we properly terminate when we encounter - // a malformed or unparseable entry: + // a malformed or unparsable entry: auto const node1 = randomNode(); auto const node2 = randomNode(); @@ -267,7 +240,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple); +BEAST_DEFINE_TESTSUITE(cluster, overlay, xrpl); } // namespace tests -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/compression_test.cpp b/src/test/overlay/compression_test.cpp index 9c1ec7cd3d..19876809d2 100644 --- a/src/test/overlay/compression_test.cpp +++ b/src/test/overlay/compression_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -49,17 +30,17 @@ #include -namespace ripple { +namespace xrpl { namespace test { -using namespace ripple::test; -using namespace ripple::test::jtx; +using namespace xrpl::test; +using namespace xrpl::test::jtx; static uint256 -ledgerHash(LedgerInfo const& info) +ledgerHash(LedgerHeader const& info) { - return ripple::sha512Half( + return xrpl::sha512Half( HashPrefix::ledgerMaster, std::uint32_t(info.seq), std::uint64_t(info.drops.drops()), @@ -84,11 +65,7 @@ public: template void - doTest( - std::shared_ptr proto, - protocol::MessageType mt, - uint16_t nbuffers, - std::string msg) + doTest(std::shared_ptr proto, protocol::MessageType mt, uint16_t nbuffers, std::string msg) { testcase("Compress/Decompress: " + msg); @@ -103,16 +80,13 @@ public: for (int i = 0; i < nbuffers; i++) { auto start = buffer.begin() + sz * i; - auto end = i < nbuffers - 1 ? (buffer.begin() + sz * (i + 1)) - : buffer.end(); + auto end = i < nbuffers - 1 ? (buffer.begin() + sz * (i + 1)) : buffer.end(); std::vector slice(start, end); - buffers.commit(boost::asio::buffer_copy( - buffers.prepare(slice.size()), boost::asio::buffer(slice))); + buffers.commit(boost::asio::buffer_copy(buffers.prepare(slice.size()), boost::asio::buffer(slice))); } boost::system::error_code ec; - auto header = ripple::detail::parseMessageHeader( - ec, buffers.data(), buffer.size()); + auto header = xrpl::detail::parseMessageHeader(ec, buffers.data(), buffer.size()); BEAST_EXPECT(header); @@ -122,27 +96,20 @@ public: std::vector decompressed; decompressed.resize(header->uncompressed_size); - BEAST_EXPECT( - header->payload_wire_size == buffer.size() - header->header_size); + BEAST_EXPECT(header->payload_wire_size == buffer.size() - header->header_size); ZeroCopyInputStream stream(buffers.data()); stream.Skip(header->header_size); - auto decompressedSize = ripple::compression::decompress( - stream, - header->payload_wire_size, - decompressed.data(), - header->uncompressed_size); + auto decompressedSize = xrpl::compression::decompress( + stream, header->payload_wire_size, decompressed.data(), header->uncompressed_size); BEAST_EXPECT(decompressedSize == header->uncompressed_size); auto const proto1 = std::make_shared(); - BEAST_EXPECT( - proto1->ParseFromArray(decompressed.data(), decompressedSize)); + BEAST_EXPECT(proto1->ParseFromArray(decompressed.data(), decompressedSize)); auto uncompressed = m.getBuffer(Compressed::Off); BEAST_EXPECT(std::equal( - uncompressed.begin() + ripple::compression::headerBytes, - uncompressed.end(), - decompressed.begin())); + uncompressed.begin() + xrpl::compression::headerBytes, uncompressed.end(), decompressed.begin())); } std::shared_ptr @@ -158,20 +125,9 @@ public: st[sfSequence] = i; st[sfPublicKey] = std::get<0>(master); st[sfSigningPubKey] = std::get<0>(signing); - st[sfDomain] = makeSlice( - std::string("example") + std::to_string(i) + - std::string(".com")); - sign( - st, - HashPrefix::manifest, - KeyType::ed25519, - std::get<1>(master), - sfMasterSignature); - sign( - st, - HashPrefix::manifest, - KeyType::ed25519, - std::get<1>(signing)); + st[sfDomain] = makeSlice(std::string("example") + std::to_string(i) + std::string(".com")); + sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature); + sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); Serializer s; st.add(s); auto* manifest = manifests->add_list(); @@ -210,21 +166,18 @@ public: auto toBinary = [this](std::string const& text) { auto blob = strUnHex(text); BEAST_EXPECT(blob); - return std::string{ - reinterpret_cast(blob->data()), blob->size()}; + return std::string{reinterpret_cast(blob->data()), blob->size()}; }; std::string usdTxBlob = ""; auto wsc = makeWSClient(env.app().config()); { - Json::Value jrequestUsd; - jrequestUsd[jss::secret] = toBase58(generateSeed("bob")); - jrequestUsd[jss::tx_json] = - pay("bob", "alice", bob["USD"](fund / 2)); - Json::Value jreply_usd = wsc->invoke("sign", jrequestUsd); + Json::Value requestUSD; + requestUSD[jss::secret] = toBase58(generateSeed("bob")); + requestUSD[jss::tx_json] = pay("bob", "alice", bob["USD"](fund / 2)); + Json::Value replyUSD = wsc->invoke("sign", requestUSD); - usdTxBlob = - toBinary(jreply_usd[jss::result][jss::tx_blob].asString()); + usdTxBlob = toBinary(replyUSD[jss::result][jss::tx_blob].asString()); } auto transaction = std::make_shared(); @@ -242,10 +195,10 @@ public: auto getLedger = std::make_shared(); getLedger->set_itype(protocol::liTS_CANDIDATE); getLedger->set_ltype(protocol::TMLedgerType::ltACCEPTED); - uint256 const hash(ripple::sha512Half(123456789)); + uint256 const hash(xrpl::sha512Half(123456789)); getLedger->set_ledgerhash(hash.begin(), hash.size()); getLedger->set_ledgerseq(123456789); - ripple::SHAMapNodeID sha(64, hash); + xrpl::SHAMapNodeID sha(64, hash); getLedger->add_nodeids(sha.getRawString()); getLedger->set_requestcookie(123456789); getLedger->set_querytype(protocol::qtINDIRECT); @@ -257,7 +210,7 @@ public: buildLedgerData(uint32_t n, Logs& logs) { auto ledgerData = std::make_shared(); - uint256 const hash(ripple::sha512Half(12356789)); + uint256 const hash(xrpl::sha512Half(12356789)); ledgerData->set_ledgerhash(hash.data(), hash.size()); ledgerData->set_ledgerseq(123456789); ledgerData->set_type(protocol::TMLedgerInfoType::liAS_NODE); @@ -271,12 +224,12 @@ public: for (int i = 0; i < n; i++) { - LedgerInfo info; + LedgerHeader info; info.seq = i; info.parentCloseTime = ct; - info.hash = ripple::sha512Half(i); - info.txHash = ripple::sha512Half(i + 1); - info.accountHash = ripple::sha512Half(i + 2); + info.hash = xrpl::sha512Half(i); + info.txHash = xrpl::sha512Half(i + 1); + info.accountHash = xrpl::sha512Half(i + 2); info.parentHash = parentHash; info.drops = XRPAmount(10); info.closeTimeResolution = resolution; @@ -284,9 +237,8 @@ public: ct += resolution; parentHash = ledgerHash(info); Serializer nData; - ripple::addRaw(info, nData); - ledgerData->add_nodes()->set_nodedata( - nData.getDataPtr(), nData.getLength()); + xrpl::addRaw(info, nData); + ledgerData->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); } return ledgerData; @@ -297,19 +249,18 @@ public: { auto getObject = std::make_shared(); - getObject->set_type(protocol::TMGetObjectByHash_ObjectType:: - TMGetObjectByHash_ObjectType_otTRANSACTION); + getObject->set_type(protocol::TMGetObjectByHash_ObjectType::TMGetObjectByHash_ObjectType_otTRANSACTION); getObject->set_query(true); getObject->set_seq(123456789); - uint256 hash(ripple::sha512Half(123456789)); + uint256 hash(xrpl::sha512Half(123456789)); getObject->set_ledgerhash(hash.data(), hash.size()); getObject->set_fat(true); for (int i = 0; i < 100; i++) { - uint256 hash(ripple::sha512Half(i)); + uint256 hash(xrpl::sha512Half(i)); auto object = getObject->add_objects(); object->set_hash(hash.data(), hash.size()); - ripple::SHAMapNodeID sha(64, hash); + xrpl::SHAMapNodeID sha(64, hash); object->set_nodeid(sha.getRawString()); object->set_index(""); object->set_data(""); @@ -330,20 +281,14 @@ public: st[sfPublicKey] = std::get<0>(master); st[sfSigningPubKey] = std::get<0>(signing); st[sfDomain] = makeSlice(std::string("example.com")); - sign( - st, - HashPrefix::manifest, - KeyType::ed25519, - std::get<1>(master), - sfMasterSignature); + sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature); sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); Serializer s; st.add(s); list->set_manifest(s.data(), s.size()); list->set_version(3); STObject signature(sfSignature); - ripple::sign( - st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); + xrpl::sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); Serializer s1; st.add(s1); list->set_signature(s1.data(), s1.size()); @@ -363,20 +308,14 @@ public: st[sfPublicKey] = std::get<0>(master); st[sfSigningPubKey] = std::get<0>(signing); st[sfDomain] = makeSlice(std::string("example.com")); - sign( - st, - HashPrefix::manifest, - KeyType::ed25519, - std::get<1>(master), - sfMasterSignature); + sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature); sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); Serializer s; st.add(s); list->set_manifest(s.data(), s.size()); list->set_version(4); STObject signature(sfSignature); - ripple::sign( - st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); + xrpl::sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(signing)); Serializer s1; st.add(s1); auto& blob = *list->add_blobs(); @@ -409,60 +348,24 @@ public: // 1.3KB doTest(buildEndpoints(100), protocol::mtENDPOINTS, 4, "TMEndpoints100"); // 242B - doTest( - buildTransaction(*logs), - protocol::mtTRANSACTION, - 1, - "TMTransaction"); + doTest(buildTransaction(*logs), protocol::mtTRANSACTION, 1, "TMTransaction"); // 87B doTest(buildGetLedger(), protocol::mtGET_LEDGER, 1, "TMGetLedger"); // 61KB - doTest( - buildLedgerData(500, *logs), - protocol::mtLEDGER_DATA, - 10, - "TMLedgerData500"); + doTest(buildLedgerData(500, *logs), protocol::mtLEDGER_DATA, 10, "TMLedgerData500"); // 122 KB - doTest( - buildLedgerData(1000, *logs), - protocol::mtLEDGER_DATA, - 20, - "TMLedgerData1000"); + doTest(buildLedgerData(1000, *logs), protocol::mtLEDGER_DATA, 20, "TMLedgerData1000"); // 1.2MB - doTest( - buildLedgerData(10000, *logs), - protocol::mtLEDGER_DATA, - 50, - "TMLedgerData10000"); + doTest(buildLedgerData(10000, *logs), protocol::mtLEDGER_DATA, 50, "TMLedgerData10000"); // 12MB - doTest( - buildLedgerData(100000, *logs), - protocol::mtLEDGER_DATA, - 100, - "TMLedgerData100000"); + doTest(buildLedgerData(100000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData100000"); // 61MB - doTest( - buildLedgerData(500000, *logs), - protocol::mtLEDGER_DATA, - 100, - "TMLedgerData500000"); + doTest(buildLedgerData(500000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData500000"); // 7.7KB - doTest( - buildGetObjectByHash(), - protocol::mtGET_OBJECTS, - 4, - "TMGetObjectByHash"); + doTest(buildGetObjectByHash(), protocol::mtGET_OBJECTS, 4, "TMGetObjectByHash"); // 895B - doTest( - buildValidatorList(), - protocol::mtVALIDATORLIST, - 4, - "TMValidatorList"); - doTest( - buildValidatorListCollection(), - protocol::mtVALIDATORLISTCOLLECTION, - 4, - "TMValidatorListCollection"); + doTest(buildValidatorList(), protocol::mtVALIDATOR_LIST, 4, "TMValidatorList"); + doTest(buildValidatorListCollection(), protocol::mtVALIDATOR_LIST_COLLECTION, 4, "TMValidatorListCollection"); } void @@ -479,16 +382,14 @@ public: c.loadFromString(str.str()); auto env = std::make_shared(*this); env->app().config().COMPRESSION = c.COMPRESSION; - env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = - c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE; + env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE; return env; }; auto handshake = [&](int outboundEnable, int inboundEnable) { - beast::IP::Address addr = - boost::asio::ip::make_address("172.1.1.100"); + beast::IP::Address addr = boost::asio::ip::make_address("172.1.1.100"); auto env = getEnv(outboundEnable); - auto request = ripple::makeRequest( + auto request = xrpl::makeRequest( true, env->app().config().COMPRESSION, false, @@ -502,25 +403,15 @@ public: auto const peerEnabled = inboundEnable && outboundEnable; // inbound is enabled if the request's header has the feature // enabled and the peer's configuration is enabled - auto const inboundEnabled = peerFeatureEnabled( - http_request, FEATURE_COMPR, "lz4", inboundEnable); + auto const inboundEnabled = peerFeatureEnabled(http_request, FEATURE_COMPR, "lz4", inboundEnable); BEAST_EXPECT(!(peerEnabled ^ inboundEnabled)); env.reset(); env = getEnv(inboundEnable); - auto http_resp = ripple::makeResponse( - true, - http_request, - addr, - addr, - uint256{1}, - 1, - {1, 0}, - env->app()); + auto http_resp = xrpl::makeResponse(true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env->app()); // outbound is enabled if the response's header has the feature // enabled and the peer's configuration is enabled - auto const outboundEnabled = peerFeatureEnabled( - http_resp, FEATURE_COMPR, "lz4", outboundEnable); + auto const outboundEnabled = peerFeatureEnabled(http_resp, FEATURE_COMPR, "lz4", outboundEnable); BEAST_EXPECT(!(peerEnabled ^ outboundEnabled)); }; handshake(1, 1); @@ -537,7 +428,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/handshake_test.cpp b/src/test/overlay/handshake_test.cpp index 936b6e5fff..8e2d5d5ec1 100644 --- a/src/test/overlay/handshake_test.cpp +++ b/src/test/overlay/handshake_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -59,7 +40,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(handshake, overlay, ripple); +BEAST_DEFINE_TESTSUITE(handshake, overlay, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index 318eae21ec..9d9aef7a36 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -38,7 +19,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -50,8 +31,7 @@ using MessageSPtr = std::shared_ptr; using LinkSPtr = std::shared_ptr; using PeerSPtr = std::shared_ptr; using PeerWPtr = std::weak_ptr; -using SquelchCB = - std::function; +using SquelchCB = std::function; using UnsquelchCB = std::function; using LinkIterCB = std::function; @@ -65,8 +45,7 @@ static constexpr std::uint32_t MAX_MESSAGES = 200000; class PeerPartial : public Peer { public: - PeerPartial() - : nodePublicKey_(derivePublicKey(KeyType::ed25519, randomSecretKey())) + PeerPartial() : nodePublicKey_(derivePublicKey(KeyType::ed25519, randomSecretKey())) { } @@ -95,8 +74,7 @@ public: return {}; } void - charge(Resource::Charge const& fee, std::string const& context = {}) - override + charge(Resource::Charge const& fee, std::string const& context = {}) override { } bool @@ -267,10 +245,7 @@ class Link using Latency = std::pair; public: - Link( - Validator& validator, - PeerSPtr peer, - Latency const& latency = {milliseconds(5), milliseconds(15)}) + Link(Validator& validator, PeerSPtr peer, Latency const& latency = {milliseconds(5), milliseconds(15)}) : validator_(validator), peer_(peer), latency_(latency), up_(true) { auto sp = peer_.lock(); @@ -369,8 +344,7 @@ public: void addPeer(PeerSPtr peer) { - links_.emplace( - std::make_pair(peer->id(), std::make_shared(*this, peer))); + links_.emplace(std::make_pair(peer->id(), std::make_shared(*this, peer))); } void @@ -393,10 +367,7 @@ public: for_links(LinkIterCB f, bool simulateSlow = false) { std::vector v; - std::transform( - links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) { - return kv.second; - }); + std::transform(links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) { return kv.second; }); std::random_device d; std::mt19937 g(d()); std::shuffle(v.begin(), v.end(), g); @@ -461,8 +432,7 @@ class PeerSim : public PeerPartial, public std::enable_shared_from_this { public: using id_t = Peer::id_t; - PeerSim(Overlay& overlay, beast::Journal journal) - : overlay_(overlay), squelch_(journal) + PeerSim(Overlay& overlay, beast::Journal journal) : overlay_(overlay), squelch_(journal) { id_ = sid_++; } @@ -506,8 +476,7 @@ public: auto validator = squelch.validatorpubkey(); PublicKey key(Slice(validator.data(), validator.size())); if (squelch.squelch()) - squelch_.addSquelch( - key, std::chrono::seconds{squelch.squelchduration()}); + squelch_.addSquelch(key, std::chrono::seconds{squelch.squelchduration()}); else squelch_.removeSquelch(key); } @@ -527,8 +496,7 @@ class OverlaySim : public Overlay, public reduce_relay::SquelchHandler public: using id_t = Peer::id_t; using clock_type = ManualClock; - OverlaySim(Application& app) - : slots_(app.logs(), *this, app.config()), logs_(app.logs()) + OverlaySim(Application& app) : slots_(app.logs(), *this, app.config()), logs_(app.logs()) { } @@ -663,13 +631,7 @@ public: return *selected.begin(); } - std::unordered_map< - id_t, - std::tuple< - reduce_relay::PeerState, - std::uint16_t, - std::uint32_t, - std::uint32_t>> + std::unordered_map> getPeers(PublicKey const& validator) { return slots_.getPeers(validator); @@ -683,10 +645,7 @@ public: private: void - squelch( - PublicKey const& validator, - Peer::id_t id, - std::uint32_t squelchDuration) const override + squelch(PublicKey const& validator, Peer::id_t id, std::uint32_t squelchDuration) const override { if (auto it = peers_.find(id); it != peers_.end()) squelch_(validator, it->second, squelchDuration); @@ -781,10 +740,7 @@ public: void enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable) { - auto it = - std::find_if(validators_.begin(), validators_.end(), [&](auto& v) { - return v.id() == validatorId; - }); + auto it = std::find_if(validators_.begin(), validators_.end(), [&](auto& v) { return v.id() == validatorId; }); assert(it != validators_.end()); if (enable) it->linkUp(peer); @@ -806,17 +762,13 @@ public: PublicKey key = v; squelch.clear_validatorpubkey(); squelch.set_validatorpubkey(key.data(), key.size()); - v.for_links({peer}, [&](Link& l, MessageSPtr) { - std::dynamic_pointer_cast(l.getPeer())->send(squelch); - }); + v.for_links( + {peer}, [&](Link& l, MessageSPtr) { std::dynamic_pointer_cast(l.getPeer())->send(squelch); }); } } void - for_rand( - std::uint32_t min, - std::uint32_t max, - std::function f) + for_rand(std::uint32_t min, std::uint32_t max, std::function f) { auto size = max - min; std::vector s(size); @@ -848,9 +800,7 @@ public: for (int m = 0; m < nMessages; ++m) { ManualClock::randAdvance(milliseconds(1800), milliseconds(2200)); - for_rand(0, nValidators, [&](std::uint32_t v) { - validators_[v].for_links(link); - }); + for_rand(0, nValidators, [&](std::uint32_t v) { validators_[v].for_links(link); }); } } @@ -881,8 +831,7 @@ public: for (auto& [_, v] : peers) { (void)_; - if (std::get(v) == - reduce_relay::PeerState::Squelched) + if (std::get(v) == reduce_relay::PeerState::Squelched) return false; } } @@ -905,20 +854,15 @@ protected: { auto peers = network_.overlay().getPeers(network_.validator(validator)); std::cout << msg << " " - << "num peers " << (int)network_.overlay().getNumPeers() - << std::endl; + << "num peers " << (int)network_.overlay().getNumPeers() << std::endl; for (auto& [k, v] : peers) - std::cout << k << ":" << (int)std::get(v) - << " "; + std::cout << k << ":" << (int)std::get(v) << " "; std::cout << std::endl; } /** Send squelch (if duration is set) or unsquelch (if duration not set) */ Peer::id_t - sendSquelch( - PublicKey const& validator, - PeerWPtr const& peerPtr, - std::optional duration) + sendSquelch(PublicKey const& validator, PeerWPtr const& peerPtr, std::optional duration) { protocol::TMSquelch squelch; bool res = duration ? true : false; @@ -957,8 +901,7 @@ protected: void random(bool log) { - std::unordered_map events{ - {LinkDown, {}}, {PeerDisconnected, {}}}; + std::unordered_map events{{LinkDown, {}}, {PeerDisconnected, {}}}; time_point lastCheck = ManualClock::now(); network_.reset(); @@ -969,16 +912,12 @@ protected: bool squelched = false; std::stringstream str; - link.send( - m, - [&](PublicKey const& key, - PeerWPtr const& peerPtr, - std::uint32_t duration) { - assert(key == validator); - auto p = sendSquelch(key, peerPtr, duration); - squelched = true; - str << p << " "; - }); + link.send(m, [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) { + assert(key == validator); + auto p = sendSquelch(key, peerPtr, duration); + squelched = true; + str << p << " "; + }); if (squelched) { @@ -987,20 +926,13 @@ protected: for (auto s : selected) str << s << " "; if (log) - std::cout - << (double)reduce_relay::epoch(now) - .count() / - 1000. - << " random, squelched, validator: " << validator.id() - << " peers: " << str.str() << std::endl; - auto countingState = - network_.overlay().isCountingState(validator); + std::cout << (double)reduce_relay::epoch(now).count() / 1000. + << " random, squelched, validator: " << validator.id() << " peers: " << str.str() + << std::endl; + auto countingState = network_.overlay().isCountingState(validator); BEAST_EXPECT( countingState == false && - selected.size() == - env_.app() - .config() - .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + selected.size() == env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); } // Trigger Link Down or Peer Disconnect event @@ -1016,19 +948,14 @@ protected: events[event].time_ = now; if (event == EventType::LinkDown) { - network_.enableLink( - validator.id(), link.peerId(), false); - events[event].isSelected_ = - network_.overlay().isSelected( - validator, link.peerId()); + network_.enableLink(validator.id(), link.peerId(), false); + events[event].isSelected_ = network_.overlay().isSelected(validator, link.peerId()); } else - events[event].isSelected_ = - network_.isSelected(link.peerId()); + events[event].isSelected_ = network_.isSelected(link.peerId()); }; auto r = rand_int(0, 1000); - if (r == (int)EventType::LinkDown || - r == (int)EventType::PeerDisconnected) + if (r == (int)EventType::LinkDown || r == (int)EventType::PeerDisconnected) { update(static_cast(r)); } @@ -1038,22 +965,18 @@ protected: { auto& event = events[EventType::PeerDisconnected]; bool allCounting = network_.allCounting(event.peer_); - network_.overlay().deletePeer( - event.peer_, - [&](PublicKey const& v, PeerWPtr const& peerPtr) { - if (event.isSelected_) - sendSquelch(v, peerPtr, {}); - event.handled_ = true; - }); + network_.overlay().deletePeer(event.peer_, [&](PublicKey const& v, PeerWPtr const& peerPtr) { + if (event.isSelected_) + sendSquelch(v, peerPtr, {}); + event.handled_ = true; + }); // Should only be unsquelched if the peer is in Selected state // If in Selected state it's possible unsquelching didn't // take place because there is no peers in Squelched state in // any of the slots where the peer is in Selected state // (allCounting is true) - bool handled = - (event.isSelected_ == false && !event.handled_) || - (event.isSelected_ == true && - (event.handled_ || allCounting)); + bool handled = (event.isSelected_ == false && !event.handled_) || + (event.isSelected_ == true && (event.handled_ || allCounting)); BEAST_EXPECT(handled); event.state_ = State::Off; event.isSelected_ = false; @@ -1077,38 +1000,28 @@ protected: bool mustHandle = false; if (event.state_ == State::On && BEAST_EXPECT(event.key_)) { - event.isSelected_ = - network_.overlay().isSelected(*event.key_, event.peer_); + event.isSelected_ = network_.overlay().isSelected(*event.key_, event.peer_); auto peers = network_.overlay().getPeers(*event.key_); - auto d = reduce_relay::epoch(now).count() - - std::get<3>(peers[event.peer_]); - mustHandle = event.isSelected_ && - d > milliseconds(reduce_relay::IDLED).count() && - network_.overlay().inState( - *event.key_, reduce_relay::PeerState::Squelched) > - 0 && + auto d = reduce_relay::epoch(now).count() - std::get<3>(peers[event.peer_]); + mustHandle = event.isSelected_ && d > milliseconds(reduce_relay::IDLED).count() && + network_.overlay().inState(*event.key_, reduce_relay::PeerState::Squelched) > 0 && peers.find(event.peer_) != peers.end(); } - network_.overlay().deleteIdlePeers( - [&](PublicKey const& v, PeerWPtr const& ptr) { - event.handled_ = true; - if (mustHandle && v == event.key_) - { - event.state_ = State::WaitReset; - sendSquelch(validator, ptr, {}); - } - }); - bool handled = - (event.handled_ && event.state_ == State::WaitReset) || - (!event.handled_ && !mustHandle); + network_.overlay().deleteIdlePeers([&](PublicKey const& v, PeerWPtr const& ptr) { + event.handled_ = true; + if (mustHandle && v == event.key_) + { + event.state_ = State::WaitReset; + sendSquelch(validator, ptr, {}); + } + }); + bool handled = (event.handled_ && event.state_ == State::WaitReset) || (!event.handled_ && !mustHandle); BEAST_EXPECT(handled); } if (event.state_ == State::WaitReset || - (event.state_ == State::On && - (now - event.time_ > (reduce_relay::IDLED + seconds(2))))) + (event.state_ == State::On && (now - event.time_ > (reduce_relay::IDLED + seconds(2))))) { - bool handled = - event.state_ == State::WaitReset || !event.handled_; + bool handled = event.state_ == State::WaitReset || !event.handled_; BEAST_EXPECT(handled); event.state_ = State::Off; event.isSelected_ = false; @@ -1125,10 +1038,8 @@ protected: // All Peer Disconnect events must be handled BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_); if (log) - std::cout << "link down count: " << down.cnt_ << "/" - << down.handledCnt_ - << " peer disconnect count: " << disconnected.cnt_ << "/" - << disconnected.handledCnt_; + std::cout << "link down count: " << down.cnt_ << "/" << down.handledCnt_ + << " peer disconnect count: " << disconnected.cnt_ << "/" << disconnected.handledCnt_; } bool @@ -1154,9 +1065,7 @@ protected: void testInitialRound(bool log) { - doTest("Initial Round", log, [this](bool log) { - BEAST_EXPECT(propagateAndSquelch(log)); - }); + doTest("Initial Round", log, [this](bool log) { BEAST_EXPECT(propagateAndSquelch(log)); }); } /** Receiving message from squelched peer too soon should not change the @@ -1177,9 +1086,8 @@ protected: testPeerUnsquelched(bool log) { ManualClock::advance(seconds(601)); - doTest("Peer Unsquelched", log, [this](bool log) { - BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false)); - }); + doTest( + "Peer Unsquelched", log, [this](bool log) { BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false)); }); } /** Propagate enough messages to generate one squelch event */ @@ -1190,22 +1098,14 @@ protected: network_.propagate( [&](Link& link, MessageSPtr message) { std::uint16_t squelched = 0; - link.send( - message, - [&](PublicKey const& key, - PeerWPtr const& peerPtr, - std::uint32_t duration) { - squelched++; - sendSquelch(key, peerPtr, duration); - }); + link.send(message, [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) { + squelched++; + sendSquelch(key, peerPtr, duration); + }); if (squelched) { BEAST_EXPECT( - squelched == - MAX_PEERS - - env_.app() - .config() - .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + squelched == MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); n++; } }, @@ -1214,9 +1114,7 @@ protected: purge, resetClock); auto selected = network_.overlay().getSelected(network_.validator(0)); - BEAST_EXPECT( - selected.size() == - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + BEAST_EXPECT(selected.size() == env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); BEAST_EXPECT(n == 1); // only one selection round auto res = checkCounting(network_.validator(0), false); BEAST_EXPECT(res); @@ -1225,24 +1123,15 @@ protected: /** Send fewer message so that squelch event is not generated */ bool - propagateNoSquelch( - bool log, - std::uint16_t nMessages, - bool countingState, - bool purge = true, - bool resetClock = true) + propagateNoSquelch(bool log, std::uint16_t nMessages, bool countingState, bool purge = true, bool resetClock = true) { bool squelched = false; network_.propagate( [&](Link& link, MessageSPtr message) { - link.send( - message, - [&](PublicKey const& key, - PeerWPtr const& peerPtr, - std::uint32_t duration) { - squelched = true; - BEAST_EXPECT(false); - }); + link.send(message, [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) { + squelched = true; + BEAST_EXPECT(false); + }); }, 1, nMessages, @@ -1275,16 +1164,8 @@ protected: BEAST_EXPECT(propagateAndSquelch(log, true, false)); auto id = network_.overlay().getSelectedPeer(network_.validator(0)); std::uint16_t unsquelched = 0; - network_.overlay().deletePeer( - id, [&](PublicKey const& key, PeerWPtr const& peer) { - unsquelched++; - }); - BEAST_EXPECT( - unsquelched == - MAX_PEERS - - env_.app() - .config() - .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + network_.overlay().deletePeer(id, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); + BEAST_EXPECT(unsquelched == MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); BEAST_EXPECT(checkCounting(network_.validator(0), true)); }); } @@ -1299,17 +1180,9 @@ protected: BEAST_EXPECT(propagateAndSquelch(log, true, false)); ManualClock::advance(reduce_relay::IDLED + seconds(1)); std::uint16_t unsquelched = 0; - network_.overlay().deleteIdlePeers( - [&](PublicKey const& key, PeerWPtr const& peer) { - unsquelched++; - }); + network_.overlay().deleteIdlePeers([&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); auto peers = network_.overlay().getPeers(network_.validator(0)); - BEAST_EXPECT( - unsquelched == - MAX_PEERS - - env_.app() - .config() - .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + BEAST_EXPECT(unsquelched == MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); BEAST_EXPECT(checkCounting(network_.validator(0), true)); }); } @@ -1324,15 +1197,12 @@ protected: BEAST_EXPECT(propagateAndSquelch(log, true, false)); auto peers = network_.overlay().getPeers(network_.validator(0)); auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) { - return std::get(it.second) == - reduce_relay::PeerState::Squelched; + return std::get(it.second) == reduce_relay::PeerState::Squelched; }); assert(it != peers.end()); std::uint16_t unsquelched = 0; network_.overlay().deletePeer( - it->first, [&](PublicKey const& key, PeerWPtr const& peer) { - unsquelched++; - }); + it->first, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); BEAST_EXPECT(unsquelched == 0); BEAST_EXPECT(checkCounting(network_.validator(0), false)); }); @@ -1477,12 +1347,9 @@ vp_base_squelch_max_selected_peers=2 { doTest("BaseSquelchReady", log, [&](bool log) { ManualClock::reset(); - auto createSlots = [&](bool baseSquelchEnabled) - -> reduce_relay::Slots { - env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = - baseSquelchEnabled; - return reduce_relay::Slots( - env_.app().logs(), network_.overlay(), env_.app().config()); + auto createSlots = [&](bool baseSquelchEnabled) -> reduce_relay::Slots { + env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = baseSquelchEnabled; + return reduce_relay::Slots(env_.app().logs(), network_.overlay(), env_.app().config()); }; // base squelching must not be ready if squelching is disabled BEAST_EXPECT(!createSlots(false).baseSquelchReady()); @@ -1513,10 +1380,7 @@ vp_base_squelch_max_selected_peers=2 { uint256 key(i); network_.overlay().updateSlotAndSquelch( - key, - network_.validator(0), - 0, - [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); + key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); } auto peers = network_.overlay().getPeers(network_.validator(0)); // first message changes Slot state to Counting and is not counted, @@ -1525,20 +1389,14 @@ vp_base_squelch_max_selected_peers=2 // add duplicate uint256 key(nMessages - 1); network_.overlay().updateSlotAndSquelch( - key, - network_.validator(0), - 0, - [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); + key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); // confirm the same number of messages peers = network_.overlay().getPeers(network_.validator(0)); BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1)); // advance the clock ManualClock::advance(reduce_relay::IDLED + seconds(1)); network_.overlay().updateSlotAndSquelch( - key, - network_.validator(0), - 0, - [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); + key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); peers = network_.overlay().getPeers(network_.validator(0)); // confirm message number increased BEAST_EXPECT(std::get<1>(peers[0]) == nMessages); @@ -1551,8 +1409,7 @@ vp_base_squelch_max_selected_peers=2 { } void - squelch(PublicKey const&, Peer::id_t, std::uint32_t duration) - const override + squelch(PublicKey const&, Peer::id_t, std::uint32_t duration) const override { if (duration > maxDuration_) maxDuration_ = duration; @@ -1573,14 +1430,12 @@ vp_base_squelch_max_selected_peers=2 auto run = [&](int npeers) { handler.maxDuration_ = 0; - reduce_relay::Slots slots( - env_.app().logs(), handler, env_.app().config()); + reduce_relay::Slots slots(env_.app().logs(), handler, env_.app().config()); // 1st message from a new peer switches the slot // to counting state and resets the counts of all peers + // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold // and switch the slot's state to peer selection. - for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2; - m++) + for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2; m++) { for (int peer = 0; peer < npeers; peer++) { @@ -1588,11 +1443,7 @@ vp_base_squelch_max_selected_peers=2 // slot's internal hash router accept the message std::uint64_t mid = m * 1000 + peer; uint256 const message{mid}; - slots.updateSlotAndSquelch( - message, - validator, - peer, - protocol::MessageType::mtVALIDATION); + slots.updateSlotAndSquelch(message, validator, peer, protocol::MessageType::mtVALIDATION); } } // make Slot's internal hash router expire all messages @@ -1622,24 +1473,14 @@ vp_base_squelch_max_selected_peers=2 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count()); using namespace beast::unit_test::detail; if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count()) - log << make_reason( - "warning: squelch duration is low", - __FILE__, - __LINE__) - << std::endl - << std::flush; + log << make_reason("warning: squelch duration is low", __FILE__, __LINE__) << std::endl << std::flush; // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS run(400); BEAST_EXPECT( handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() && handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count()); if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count()) - log << make_reason( - "warning: squelch duration is low", - __FILE__, - __LINE__) - << std::endl - << std::flush; + log << make_reason("warning: squelch duration is low", __FILE__, __LINE__) << std::endl << std::flush; }); } @@ -1655,17 +1496,15 @@ vp_base_squelch_max_selected_peers=2 << "[compression]\n" << "1\n"; c.loadFromString(str.str()); - env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = - c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE; + env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE; env_.app().config().COMPRESSION = c.COMPRESSION; }; auto handshake = [&](int outboundEnable, int inboundEnable) { - beast::IP::Address addr = - boost::asio::ip::make_address("172.1.1.100"); + beast::IP::Address addr = boost::asio::ip::make_address("172.1.1.100"); setEnv(outboundEnable); - auto request = ripple::makeRequest( + auto request = xrpl::makeRequest( true, env_.app().config().COMPRESSION, false, @@ -1679,24 +1518,14 @@ vp_base_squelch_max_selected_peers=2 auto const peerEnabled = inboundEnable && outboundEnable; // inbound is enabled if the request's header has the feature // enabled and the peer's configuration is enabled - auto const inboundEnabled = peerFeatureEnabled( - http_request, FEATURE_VPRR, inboundEnable); + auto const inboundEnabled = peerFeatureEnabled(http_request, FEATURE_VPRR, inboundEnable); BEAST_EXPECT(!(peerEnabled ^ inboundEnabled)); setEnv(inboundEnable); - auto http_resp = ripple::makeResponse( - true, - http_request, - addr, - addr, - uint256{1}, - 1, - {1, 0}, - env_.app()); + auto http_resp = xrpl::makeResponse(true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env_.app()); // outbound is enabled if the response's header has the feature // enabled and the peer's configuration is enabled - auto const outboundEnabled = - peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable); + auto const outboundEnabled = peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable); BEAST_EXPECT(!(peerEnabled ^ outboundEnabled)); }; handshake(1, 1); @@ -1755,9 +1584,9 @@ class reduce_relay_simulate_test : public reduce_relay_test } }; -BEAST_DEFINE_TESTSUITE(reduce_relay, overlay, ripple); -BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay, ripple); +BEAST_DEFINE_TESTSUITE(reduce_relay, overlay, xrpl); +BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index 88c6e7698b..498ecb6a27 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - - Copyright 2014 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { /* Findings from the test: @@ -55,8 +36,7 @@ class short_read_test : public beast::unit_test::suite private: using io_context_type = boost::asio::io_context; using strand_type = boost::asio::strand; - using timer_type = - boost::asio::basic_waitable_timer; + using timer_type = boost::asio::basic_waitable_timer; using acceptor_type = boost::asio::ip::tcp::acceptor; using socket_type = boost::asio::ip::tcp::socket; using stream_type = boost::asio::ssl::stream; @@ -65,9 +45,7 @@ private: using address_type = boost::asio::ip::address; io_context_type io_context_; - boost::optional> - work_; + boost::optional> work_; std::thread thread_; std::shared_ptr context_; @@ -190,10 +168,7 @@ private: , test_(server_.test_) , acceptor_( test_.io_context_, - endpoint_type( - boost::asio::ip::make_address( - test::getEnvLocalhostAddr()), - 0)) + endpoint_type(boost::asio::ip::make_address(test::getEnvLocalhostAddr()), 0)) , socket_(test_.io_context_) , strand_(boost::asio::make_strand(test_.io_context_)) { @@ -205,9 +180,7 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&Acceptor::close, shared_from_this())); + return post(strand_, std::bind(&Acceptor::close, shared_from_this())); acceptor_.close(); } @@ -216,12 +189,7 @@ private: { acceptor_.async_accept( socket_, - bind_executor( - strand_, - std::bind( - &Acceptor::on_accept, - shared_from_this(), - std::placeholders::_1))); + bind_executor(strand_, std::bind(&Acceptor::on_accept, shared_from_this(), std::placeholders::_1))); } void @@ -240,18 +208,12 @@ private: { if (ec) return fail("accept", ec); - auto const p = - std::make_shared(server_, std::move(socket_)); + auto const p = std::make_shared(server_, std::move(socket_)); server_.add(p); p->run(); acceptor_.async_accept( socket_, - bind_executor( - strand_, - std::bind( - &Acceptor::on_accept, - shared_from_this(), - std::placeholders::_1))); + bind_executor(strand_, std::bind(&Acceptor::on_accept, shared_from_this(), std::placeholders::_1))); } }; @@ -280,9 +242,7 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&Connection::close, shared_from_this())); + return post(strand_, std::bind(&Connection::close, shared_from_this())); if (socket_.is_open()) { socket_.close(); @@ -295,19 +255,11 @@ private: { timer_.expires_after(std::chrono::seconds(3)); timer_.async_wait(bind_executor( - strand_, - std::bind( - &Connection::on_timer, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_timer, shared_from_this(), std::placeholders::_1))); stream_.async_handshake( stream_type::server, bind_executor( - strand_, - std::bind( - &Connection::on_handshake, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_handshake, shared_from_this(), std::placeholders::_1))); } void @@ -316,8 +268,7 @@ private: if (socket_.is_open()) { if (ec != boost::asio::error::operation_aborted) - test_.log << "[server] " << what << ": " << ec.message() - << std::endl; + test_.log << "[server] " << what << ": " << ec.message() << std::endl; socket_.close(); timer_.cancel(); } @@ -347,10 +298,7 @@ private: bind_executor( strand_, std::bind( - &Connection::on_read, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + &Connection::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); #else close(); #endif @@ -363,11 +311,7 @@ private: { server_.test_.log << "[server] read: EOF" << std::endl; return stream_.async_shutdown(bind_executor( - strand_, - std::bind( - &Connection::on_shutdown, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); } if (ec) return fail("read", ec); @@ -381,10 +325,7 @@ private: bind_executor( strand_, std::bind( - &Connection::on_write, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + &Connection::on_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); } void @@ -394,11 +335,7 @@ private: if (ec) return fail("write", ec); stream_.async_shutdown(bind_executor( - strand_, - std::bind( - &Connection::on_shutdown, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); } void @@ -466,9 +403,7 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post( - strand_, - std::bind(&Connection::close, shared_from_this())); + return post(strand_, std::bind(&Connection::close, shared_from_this())); if (socket_.is_open()) { socket_.close(); @@ -481,19 +416,11 @@ private: { timer_.expires_after(std::chrono::seconds(3)); timer_.async_wait(bind_executor( - strand_, - std::bind( - &Connection::on_timer, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_timer, shared_from_this(), std::placeholders::_1))); socket_.async_connect( ep, bind_executor( - strand_, - std::bind( - &Connection::on_connect, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_connect, shared_from_this(), std::placeholders::_1))); } void @@ -502,8 +429,7 @@ private: if (socket_.is_open()) { if (ec != boost::asio::error::operation_aborted) - test_.log << "[client] " << what << ": " << ec.message() - << std::endl; + test_.log << "[client] " << what << ": " << ec.message() << std::endl; socket_.close(); timer_.cancel(); } @@ -528,11 +454,7 @@ private: stream_.async_handshake( stream_type::client, bind_executor( - strand_, - std::bind( - &Connection::on_handshake, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_handshake, shared_from_this(), std::placeholders::_1))); } void @@ -549,17 +471,10 @@ private: bind_executor( strand_, std::bind( - &Connection::on_write, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + &Connection::on_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); #else stream_.async_shutdown(bind_executor( - strand_, - std::bind( - &Connection::on_shutdown, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); #endif } @@ -577,17 +492,10 @@ private: bind_executor( strand_, std::bind( - &Connection::on_read, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + &Connection::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2))); #else stream_.async_shutdown(bind_executor( - strand_, - std::bind( - &Connection::on_shutdown, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); #endif } @@ -598,11 +506,7 @@ private: return fail("read", ec); buf_.commit(bytes_transferred); stream_.async_shutdown(bind_executor( - strand_, - std::bind( - &Connection::on_shutdown, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); } void @@ -657,6 +561,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(short_read, overlay, ripple); +BEAST_DEFINE_TESTSUITE(short_read, overlay, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/traffic_count_test.cpp b/src/test/overlay/traffic_count_test.cpp index 768ec21938..6516fe3843 100644 --- a/src/test/overlay/traffic_count_test.cpp +++ b/src/test/overlay/traffic_count_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -40,13 +21,11 @@ public: message.set_type(protocol::TMPing::ptPING); // a known message is categorized to a proper category - auto const known = - TrafficCount::categorize(message, protocol::mtPING, false); + auto const known = TrafficCount::categorize(message, protocol::mtPING, false); BEAST_EXPECT(known == TrafficCount::category::base); // an unknown message type is categorized as unknown - auto const unknown = TrafficCount::categorize( - message, static_cast(99), false); + auto const unknown = TrafficCount::categorize(message, static_cast(99), false); BEAST_EXPECT(unknown == TrafficCount::category::unknown); } @@ -76,18 +55,12 @@ public: }); auto const counts_new = m_traffic.getCounts(); - std::for_each( - counts_new.begin(), counts_new.end(), [&](auto const& pair) { - BEAST_EXPECT( - pair.second.bytesIn.load() == tc.expectedBytesIn); - BEAST_EXPECT( - pair.second.bytesOut.load() == tc.expectedBytesOut); - BEAST_EXPECT( - pair.second.messagesIn.load() == tc.expectedMessagesIn); - BEAST_EXPECT( - pair.second.messagesOut.load() == - tc.expectedMessagesOut); - }); + std::for_each(counts_new.begin(), counts_new.end(), [&](auto const& pair) { + BEAST_EXPECT(pair.second.bytesIn.load() == tc.expectedBytesIn); + BEAST_EXPECT(pair.second.bytesOut.load() == tc.expectedBytesOut); + BEAST_EXPECT(pair.second.messagesIn.load() == tc.expectedMessagesIn); + BEAST_EXPECT(pair.second.messagesOut.load() == tc.expectedMessagesOut); + }); }; auto const testcases = { @@ -133,13 +106,10 @@ public: testcase("category-to-string"); // known category returns known string value - BEAST_EXPECT( - TrafficCount::to_string(TrafficCount::category::total) == "total"); + BEAST_EXPECT(TrafficCount::to_string(TrafficCount::category::total) == "total"); // return "unknown" for unknown categories - BEAST_EXPECT( - TrafficCount::to_string( - static_cast(1000)) == "unknown"); + BEAST_EXPECT(TrafficCount::to_string(static_cast(1000)) == "unknown"); } void @@ -151,7 +121,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(traffic_count, overlay, ripple); +BEAST_DEFINE_TESTSUITE(traffic_count, overlay, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/overlay/tx_reduce_relay_test.cpp b/src/test/overlay/tx_reduce_relay_test.cpp index 83b3013514..b8e3300c03 100644 --- a/src/test/overlay/tx_reduce_relay_test.cpp +++ b/src/test/overlay/tx_reduce_relay_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -51,11 +32,7 @@ private: testConfig(bool log) { doTest("Config Test", log, [&](bool log) { - auto test = [&](bool enable, - bool metrics, - std::uint16_t min, - std::uint16_t pct, - bool success = true) { + auto test = [&](bool enable, bool metrics, std::uint16_t min, std::uint16_t pct, bool success = true) { std::stringstream str("[reduce_relay]"); str << "[reduce_relay]\n" << "tx_enable=" << static_cast(enable) << "\n" @@ -154,47 +131,28 @@ private: boost::beast::multi_buffer read_buf_; public: - tx_reduce_relay_test() - : context_(make_SSLContext("")), protocolVersion_{1, 7} + tx_reduce_relay_test() : context_(make_SSLContext("")), protocolVersion_{1, 7} { } private: void - addPeer( - jtx::Env& env, - std::vector>& peers, - std::uint16_t& nDisabled) + addPeer(jtx::Env& env, std::vector>& peers, std::uint16_t& nDisabled) { auto& overlay = dynamic_cast(env.app().overlay()); boost::beast::http::request request; - (nDisabled == 0) - ? (void)request.insert( - "X-Protocol-Ctl", - makeFeaturesRequestHeader(false, false, true, false)) - : (void)nDisabled--; + (nDisabled == 0) ? (void)request.insert("X-Protocol-Ctl", makeFeaturesRequestHeader(false, false, true, false)) + : (void)nDisabled--; auto stream_ptr = std::make_unique( - socket_type(std::forward( - env.app().getIOContext())), - *context_); - beast::IP::Endpoint local( - boost::asio::ip::make_address("172.1.1." + std::to_string(lid_))); - beast::IP::Endpoint remote( - boost::asio::ip::make_address("172.1.1." + std::to_string(rid_))); + socket_type(std::forward(env.app().getIOContext())), *context_); + beast::IP::Endpoint local(boost::asio::ip::make_address("172.1.1." + std::to_string(lid_))); + beast::IP::Endpoint remote(boost::asio::ip::make_address("172.1.1." + std::to_string(rid_))); PublicKey key(std::get<0>(randomKeyPair(KeyType::ed25519))); auto consumer = overlay.resourceManager().newInboundEndpoint(remote); auto [slot, _] = overlay.peerFinder().new_inbound_slot(local, remote); auto const peer = std::make_shared( - env.app(), - slot, - std::move(request), - key, - protocolVersion_, - consumer, - std::move(stream_ptr), - overlay); - BEAST_EXPECT( - overlay.findPeerByPublicKey(key) == std::shared_ptr{}); + env.app(), slot, std::move(request), key, protocolVersion_, consumer, std::move(stream_ptr), overlay); + BEAST_EXPECT(overlay.findPeerByPublicKey(key) == std::shared_ptr{}); overlay.add_active(peer); BEAST_EXPECT(overlay.findPeerByPublicKey(key) == peer); peers.emplace_back(peer); // overlay stores week ptr to PeerImp @@ -237,9 +195,7 @@ private: m.set_deferred(false); m.set_status(protocol::TransactionStatus::tsNEW); env.app().overlay().relay(uint256{0}, m, toSkip); - BEAST_EXPECT( - PeerTest::sendTx_ == expectRelay && - PeerTest::queueTx_ == expectQueue); + BEAST_EXPECT(PeerTest::sendTx_ == expectRelay && PeerTest::queueTx_ == expectQueue); } } @@ -264,7 +220,7 @@ private: // (20+0.25*(60-20)-5=25), queue the rest, skip counts towards relayed // (60-25-5=30) testRelay("skip", true, 60, 0, 20, 25, 25, 30, skip); - // relay to minPeers + disabled + 25% of (nPeers - minPeers - disalbed) + // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled) // (20+10+0.25*(70-20-10)=40), queue the rest (30) testRelay("disabled", true, 70, 10, 20, 25, 40, 30); // relay to minPeers + disabled-not-in-skip + 25% of (nPeers - minPeers @@ -284,6 +240,6 @@ private: } }; -BEAST_DEFINE_TESTSUITE(tx_reduce_relay, overlay, ripple); +BEAST_DEFINE_TESTSUITE(tx_reduce_relay, overlay, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/peerfinder/Livecache_test.cpp b/src/test/peerfinder/Livecache_test.cpp index a150f02f05..2c2ac01111 100644 --- a/src/test/peerfinder/Livecache_test.cpp +++ b/src/test/peerfinder/Livecache_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace PeerFinder { bool @@ -139,9 +120,7 @@ public: constexpr auto num_eps = 40; Livecache<> c(clock_, journal_); for (auto i = 0; i < num_eps; ++i) - add(beast::IP::randomEP(true), - c, - ripple::rand_int()); + add(beast::IP::randomEP(true), c, xrpl::rand_int()); auto h = c.hops.histogram(); if (!BEAST_EXPECT(!h.empty())) return; @@ -163,57 +142,32 @@ public: testcase("Shuffle"); Livecache<> c(clock_, journal_); for (auto i = 0; i < 100; ++i) - add(beast::IP::randomEP(true), - c, - ripple::rand_int(Tuning::maxHops + 1)); + add(beast::IP::randomEP(true), c, xrpl::rand_int(Tuning::maxHops + 1)); - using at_hop = std::vector; + using at_hop = std::vector; using all_hops = std::array; auto cmp_EP = [](Endpoint const& a, Endpoint const& b) { - return ( - b.hops < a.hops || (b.hops == a.hops && b.address < a.address)); + return (b.hops < a.hops || (b.hops == a.hops && b.address < a.address)); }; all_hops before; all_hops before_sorted; - for (auto i = std::make_pair(0, c.hops.begin()); - i.second != c.hops.end(); - ++i.first, ++i.second) + for (auto i = std::make_pair(0, c.hops.begin()); i.second != c.hops.end(); ++i.first, ++i.second) { - std::copy( - (*i.second).begin(), - (*i.second).end(), - std::back_inserter(before[i.first])); - std::copy( - (*i.second).begin(), - (*i.second).end(), - std::back_inserter(before_sorted[i.first])); - std::sort( - before_sorted[i.first].begin(), - before_sorted[i.first].end(), - cmp_EP); + std::copy((*i.second).begin(), (*i.second).end(), std::back_inserter(before[i.first])); + std::copy((*i.second).begin(), (*i.second).end(), std::back_inserter(before_sorted[i.first])); + std::sort(before_sorted[i.first].begin(), before_sorted[i.first].end(), cmp_EP); } c.hops.shuffle(); all_hops after; all_hops after_sorted; - for (auto i = std::make_pair(0, c.hops.begin()); - i.second != c.hops.end(); - ++i.first, ++i.second) + for (auto i = std::make_pair(0, c.hops.begin()); i.second != c.hops.end(); ++i.first, ++i.second) { - std::copy( - (*i.second).begin(), - (*i.second).end(), - std::back_inserter(after[i.first])); - std::copy( - (*i.second).begin(), - (*i.second).end(), - std::back_inserter(after_sorted[i.first])); - std::sort( - after_sorted[i.first].begin(), - after_sorted[i.first].end(), - cmp_EP); + std::copy((*i.second).begin(), (*i.second).end(), std::back_inserter(after[i.first])); + std::copy((*i.second).begin(), (*i.second).end(), std::back_inserter(after_sorted[i.first])); + std::sort(after_sorted[i.first].begin(), after_sorted[i.first].end(), cmp_EP); } // each hop bucket should contain the same items @@ -239,7 +193,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Livecache, peerfinder, ripple); +BEAST_DEFINE_TESTSUITE(Livecache, peerfinder, xrpl); } // namespace PeerFinder -} // namespace ripple +} // namespace xrpl diff --git a/src/test/peerfinder/PeerFinder_test.cpp b/src/test/peerfinder/PeerFinder_test.cpp index 64a1eb5091..49ddc52c9d 100644 --- a/src/test/peerfinder/PeerFinder_test.cpp +++ b/src/test/peerfinder/PeerFinder_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace PeerFinder { class PeerFinder_test : public beast::unit_test::suite @@ -84,8 +65,7 @@ public: TestChecker checker; TestStopwatch clock; Logic logic(clock, store, checker, journal_); - logic.addFixedPeer( - "test", beast::IP::Endpoint::from_string("65.0.0.1:5")); + logic.addFixedPeer("test", beast::IP::Endpoint::from_string("65.0.0.1:5")); { Config c; c.autoConnect = false; @@ -100,8 +80,7 @@ public: { BEAST_EXPECT(list.size() == 1); auto const [slot, _] = logic.new_outbound_slot(list.front()); - BEAST_EXPECT(logic.onConnected( - slot, beast::IP::Endpoint::from_string("65.0.0.2:5"))); + BEAST_EXPECT(logic.onConnected(slot, beast::IP::Endpoint::from_string("65.0.0.2:5"))); logic.on_closed(slot); ++n; } @@ -122,8 +101,7 @@ public: TestChecker checker; TestStopwatch clock; Logic logic(clock, store, checker, journal_); - logic.addFixedPeer( - "test", beast::IP::Endpoint::from_string("65.0.0.1:5")); + logic.addFixedPeer("test", beast::IP::Endpoint::from_string("65.0.0.1:5")); { Config c; c.autoConnect = false; @@ -141,13 +119,10 @@ public: { BEAST_EXPECT(list.size() == 1); auto const [slot, _] = logic.new_outbound_slot(list.front()); - if (!BEAST_EXPECT(logic.onConnected( - slot, beast::IP::Endpoint::from_string("65.0.0.2:5")))) + if (!BEAST_EXPECT(logic.onConnected(slot, beast::IP::Endpoint::from_string("65.0.0.2:5")))) return; std::string s = "."; - if (!BEAST_EXPECT( - logic.activate(slot, pk, false) == - PeerFinder::Result::success)) + if (!BEAST_EXPECT(logic.activate(slot, pk, false) == PeerFinder::Result::success)) return; logic.on_closed(slot); ++n; @@ -243,18 +218,15 @@ public: } auto const local = beast::IP::Endpoint::from_string("65.0.0.2:1024"); - auto const [slot, r] = logic.new_inbound_slot( - local, beast::IP::Endpoint::from_string("55.104.0.2:1025")); + auto const [slot, r] = logic.new_inbound_slot(local, beast::IP::Endpoint::from_string("55.104.0.2:1025")); BEAST_EXPECT(slot != nullptr); BEAST_EXPECT(r == Result::success); - auto const [slot1, r1] = logic.new_inbound_slot( - local, beast::IP::Endpoint::from_string("55.104.0.2:1026")); + auto const [slot1, r1] = logic.new_inbound_slot(local, beast::IP::Endpoint::from_string("55.104.0.2:1026")); BEAST_EXPECT(slot1 != nullptr); BEAST_EXPECT(r1 == Result::success); - auto const [slot2, r2] = logic.new_inbound_slot( - local, beast::IP::Endpoint::from_string("55.104.0.2:1027")); + auto const [slot2, r2] = logic.new_inbound_slot(local, beast::IP::Endpoint::from_string("55.104.0.2:1027")); BEAST_EXPECT(r2 == Result::ipLimitExceeded); if (!BEAST_EXPECT(slot2 == nullptr)) @@ -283,13 +255,11 @@ public: PublicKey const pk1(randomKeyPair(KeyType::secp256k1).first); - auto const [slot, rSlot] = logic.new_outbound_slot( - beast::IP::Endpoint::from_string("55.104.0.2:1025")); + auto const [slot, rSlot] = logic.new_outbound_slot(beast::IP::Endpoint::from_string("55.104.0.2:1025")); BEAST_EXPECT(slot != nullptr); BEAST_EXPECT(rSlot == Result::success); - auto const [slot2, r2Slot] = logic.new_outbound_slot( - beast::IP::Endpoint::from_string("55.104.0.2:1026")); + auto const [slot2, r2Slot] = logic.new_outbound_slot(beast::IP::Endpoint::from_string("55.104.0.2:1026")); BEAST_EXPECT(slot2 != nullptr); BEAST_EXPECT(r2Slot == Result::success); @@ -299,8 +269,7 @@ public: BEAST_EXPECT(logic.activate(slot, pk1, false) == Result::success); // activating a different slot with the same node ID (pk) must fail - BEAST_EXPECT( - logic.activate(slot2, pk1, false) == Result::duplicatePeer); + BEAST_EXPECT(logic.activate(slot2, pk1, false) == Result::duplicatePeer); logic.on_closed(slot); @@ -328,13 +297,11 @@ public: PublicKey const pk1(randomKeyPair(KeyType::secp256k1).first); auto const local = beast::IP::Endpoint::from_string("65.0.0.2:1024"); - auto const [slot, rSlot] = logic.new_inbound_slot( - local, beast::IP::Endpoint::from_string("55.104.0.2:1025")); + auto const [slot, rSlot] = logic.new_inbound_slot(local, beast::IP::Endpoint::from_string("55.104.0.2:1025")); BEAST_EXPECT(slot != nullptr); BEAST_EXPECT(rSlot == Result::success); - BEAST_EXPECT( - logic.activate(slot, pk1, false) == Result::inboundDisabled); + BEAST_EXPECT(logic.activate(slot, pk1, false) == Result::inboundDisabled); { Config c; @@ -348,8 +315,7 @@ public: BEAST_EXPECT(logic.activate(slot, pk1, false) == Result::success); // creating a new inbound slot must succeed as IP Limit is not exceeded - auto const [slot2, r2Slot] = logic.new_inbound_slot( - local, beast::IP::Endpoint::from_string("55.104.0.2:1026")); + auto const [slot2, r2Slot] = logic.new_inbound_slot(local, beast::IP::Endpoint::from_string("55.104.0.2:1026")); BEAST_EXPECT(slot2 != nullptr); BEAST_EXPECT(r2Slot == Result::success); @@ -372,8 +338,7 @@ public: Logic logic(clock, store, checker, journal_); try { - logic.addFixedPeer( - "test", beast::IP::Endpoint::from_string("65.0.0.2")); + logic.addFixedPeer("test", beast::IP::Endpoint::from_string("65.0.0.2")); fail("invalid endpoint successfully added"); } catch (std::runtime_error const& e) @@ -414,7 +379,7 @@ public: std::uint16_t expectOut, std::uint16_t expectIn, std::uint16_t expectIpLimit) { - ripple::Config c; + xrpl::Config c; testcase(test); @@ -423,21 +388,19 @@ public: if (maxPeers) { max = maxPeers.value(); - toLoad += "[peers_max]\n" + std::to_string(max) + "\n" + - "[peers_in_max]\n" + std::to_string(maxIn.value_or(0)) + - "\n" + "[peers_out_max]\n" + + toLoad += "[peers_max]\n" + std::to_string(max) + "\n" + "[peers_in_max]\n" + + std::to_string(maxIn.value_or(0)) + "\n" + "[peers_out_max]\n" + std::to_string(maxOut.value_or(0)) + "\n"; } else if (maxIn && maxOut) { - toLoad += "[peers_in_max]\n" + std::to_string(*maxIn) + "\n" + - "[peers_out_max]\n" + std::to_string(*maxOut) + "\n"; + toLoad += "[peers_in_max]\n" + std::to_string(*maxIn) + "\n" + "[peers_out_max]\n" + + std::to_string(*maxOut) + "\n"; } c.loadFromString(toLoad); BEAST_EXPECT( - (c.PEERS_MAX == max && c.PEERS_IN_MAX == 0 && - c.PEERS_OUT_MAX == 0) || + (c.PEERS_MAX == max && c.PEERS_IN_MAX == 0 && c.PEERS_OUT_MAX == 0) || (c.PEERS_IN_MAX == *maxIn && c.PEERS_OUT_MAX == *maxOut)); Config config = Config::makeConfig(c, port, false, 0); @@ -445,8 +408,7 @@ public: Counts counts; counts.onConfig(config); BEAST_EXPECT( - counts.out_max() == expectOut && counts.in_max() == expectIn && - config.ipLimit == expectIpLimit); + counts.out_max() == expectOut && counts.in_max() == expectIn && config.ipLimit == expectIpLimit); TestStore store; TestChecker checker; @@ -487,7 +449,7 @@ public: testcase("invalid config"); auto run = [&](std::string const& toLoad) { - ripple::Config c; + xrpl::Config c; try { c.loadFromString(toLoad); @@ -543,7 +505,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(PeerFinder, peerfinder, ripple); +BEAST_DEFINE_TESTSUITE(PeerFinder, peerfinder, xrpl); } // namespace PeerFinder -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/ApiVersion_test.cpp b/src/test/protocol/ApiVersion_test.cpp index 2dc4f4d6bb..0b7babc764 100644 --- a/src/test/protocol/ApiVersion_test.cpp +++ b/src/test/protocol/ApiVersion_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/XRPLF/rippled/ - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct ApiVersion_test : beast::unit_test::suite { @@ -38,13 +19,9 @@ struct ApiVersion_test : beast::unit_test::suite { testcase("API versions invariants"); - static_assert( - RPC::apiMinimumSupportedVersion <= - RPC::apiMaximumSupportedVersion); - static_assert( - RPC::apiMinimumSupportedVersion <= RPC::apiMaximumValidVersion); - static_assert( - RPC::apiMaximumSupportedVersion <= RPC::apiMaximumValidVersion); + static_assert(RPC::apiMinimumSupportedVersion <= RPC::apiMaximumSupportedVersion); + static_assert(RPC::apiMinimumSupportedVersion <= RPC::apiMaximumValidVersion); + static_assert(RPC::apiMaximumSupportedVersion <= RPC::apiMaximumValidVersion); static_assert(RPC::apiBetaVersion <= RPC::apiMaximumValidVersion); BEAST_EXPECT(true); @@ -68,7 +45,7 @@ struct ApiVersion_test : beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(ApiVersion, protocol, ripple); +BEAST_DEFINE_TESTSUITE(ApiVersion, protocol, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/BuildInfo_test.cpp b/src/test/protocol/BuildInfo_test.cpp index 2c40681603..d9810e93ea 100644 --- a/src/test/protocol/BuildInfo_test.cpp +++ b/src/test/protocol/BuildInfo_test.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class BuildInfo_test : public beast::unit_test::suite { @@ -33,29 +14,22 @@ public: auto encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b7"); // the first two bytes identify the particular implementation, 0x183B - BEAST_EXPECT( - (encodedVersion & 0xFFFF'0000'0000'0000LLU) == - 0x183B'0000'0000'0000LLU); + BEAST_EXPECT((encodedVersion & 0xFFFF'0000'0000'0000LLU) == 0x183B'0000'0000'0000LLU); // the next three bytes: major version, minor version, patch version, // 0x010203 - BEAST_EXPECT( - (encodedVersion & 0x0000'FFFF'FF00'0000LLU) == - 0x0000'0102'0300'0000LLU); + BEAST_EXPECT((encodedVersion & 0x0000'FFFF'FF00'0000LLU) == 0x0000'0102'0300'0000LLU); // the next two bits: { // 01 if a beta - BEAST_EXPECT( - (encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b01); + BEAST_EXPECT((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b01); // 10 if an RC encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.4-rc7"); - BEAST_EXPECT( - (encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b10); + BEAST_EXPECT((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b10); // 11 if neither an RC nor a beta encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.5"); - BEAST_EXPECT( - (encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b11); + BEAST_EXPECT((encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b11); } // the next six bits: rc/beta number (1-63) @@ -114,5 +88,5 @@ public: } }; -BEAST_DEFINE_TESTSUITE(BuildInfo, protocol, ripple); -} // namespace ripple +BEAST_DEFINE_TESTSUITE(BuildInfo, protocol, xrpl); +} // namespace xrpl diff --git a/src/test/protocol/Hooks_test.cpp b/src/test/protocol/Hooks_test.cpp index 0637b52efa..f4b33f7e4d 100644 --- a/src/test/protocol/Hooks_test.cpp +++ b/src/test/protocol/Hooks_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class Hooks_test : public beast::unit_test::suite { @@ -153,8 +134,7 @@ class Hooks_test : public beast::unit_test::suite } case STI_ACCOUNT: { - AccountID id = *parseBase58( - "rwfSjJNK2YQuN64bSWn7T2eY9FJAyAPYJT"); + AccountID id = *parseBase58("rwfSjJNK2YQuN64bSWn7T2eY9FJAyAPYJT"); dummy.setAccountID(f, id); BEAST_EXPECT(dummy.getAccountID(f) == id); BEAST_EXPECT(dummy.isFieldPresent(f)); @@ -193,6 +173,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Hooks, protocol, ripple); +BEAST_DEFINE_TESTSUITE(Hooks, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/InnerObjectFormats_test.cpp b/src/test/protocol/InnerObjectFormats_test.cpp index daf9548b8b..7d69bb7afb 100644 --- a/src/test/protocol/InnerObjectFormats_test.cpp +++ b/src/test/protocol/InnerObjectFormats_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include // RPC::containsError #include // STParsedJSONObject -namespace ripple { +namespace xrpl { namespace InnerObjectFormatsUnitTestDetail { @@ -182,8 +163,7 @@ public: Json::Reader().parse(test.txt, req); if (RPC::contains_error(req)) { - Throw( - "Internal InnerObjectFormatsParsedJSON error. Bad JSON."); + Throw("Internal InnerObjectFormatsParsedJSON error. Bad JSON."); } STParsedJSONObject parsed("request", req); bool const noObj = !parsed.object.has_value(); @@ -201,6 +181,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, protocol, ripple); +BEAST_DEFINE_TESTSUITE(InnerObjectFormatsParsedJSON, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/Issue_test.cpp b/src/test/protocol/Issue_test.cpp index 35f3a3bd8c..2321da4a6e 100644 --- a/src/test/protocol/Issue_test.cpp +++ b/src/test/protocol/Issue_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -36,15 +17,7 @@ #define STL_SET_HAS_EMPLACE 0 #endif -#ifndef RIPPLE_ASSETS_ENABLE_STD_HASH -#if BEAST_MAC || BEAST_IOS -#define RIPPLE_ASSETS_ENABLE_STD_HASH 0 -#else -#define RIPPLE_ASSETS_ENABLE_STD_HASH 1 -#endif -#endif - -namespace ripple { +namespace xrpl { class Issue_test : public beast::unit_test::suite { @@ -343,7 +316,7 @@ public: testcase("std::map , int>"); testIssueDomainMap, int>>(); -#if RIPPLE_ASSETS_ENABLE_STD_HASH +#if XRPL_ASSETS_ENABLE_STD_HASH testcase("hash_map , int>"); testIssueDomainMap, int>>(); @@ -367,7 +340,7 @@ public: testcase("std::set "); testIssueSet>(); -#if RIPPLE_ASSETS_ENABLE_STD_HASH +#if XRPL_ASSETS_ENABLE_STD_HASH testcase("std::unordered_set "); testIssueSet>(); @@ -391,7 +364,7 @@ public: testcase("std::map "); testIssueMap>(); -#if RIPPLE_ASSETS_ENABLE_STD_HASH +#if XRPL_ASSETS_ENABLE_STD_HASH testcase("std::unordered_map "); testIssueMap>(); @@ -453,12 +426,10 @@ public: // Both Books have the same domain BEAST_EXPECT(Book(a2, a3, domain1) == Book(a2, a3, domain1)); BEAST_EXPECT(Book(a2, a3, domain2) == Book(a2, a3, domain2)); - BEAST_EXPECT( - Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt)); + BEAST_EXPECT(Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt)); // Both Books have no domain - BEAST_EXPECT( - Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt)); + BEAST_EXPECT(Book(a2, a3, std::nullopt) == Book(a2, a3, std::nullopt)); // Testing comparisons with >= and <= @@ -477,10 +448,8 @@ public: BEAST_EXPECT(Book(a2, a3, std::nullopt) < Book(a2, a3, domain2)); // Comparing two Books with no domains - BEAST_EXPECT( - Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt)); - BEAST_EXPECT( - Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt)); + BEAST_EXPECT(Book(a2, a3, std::nullopt) <= Book(a2, a3, std::nullopt)); + BEAST_EXPECT(Book(a2, a3, std::nullopt) >= Book(a2, a3, std::nullopt)); // Test case where domain1 is less than domain2 BEAST_EXPECT(Book(a2, a3, domain1) <= Book(a2, a3, domain2)); @@ -528,99 +497,51 @@ public: // log << std::hex << hash (Book (a3, a4)); // log << std::hex << hash (Book (a3, a4)); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) == - hash(Book(a1, a2, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a3, std::nullopt)) == - hash(Book(a1, a3, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a4, std::nullopt)) == - hash(Book(a1, a4, std::nullopt))); - BEAST_EXPECT( - hash(Book(a2, a3, std::nullopt)) == - hash(Book(a2, a3, std::nullopt))); - BEAST_EXPECT( - hash(Book(a2, a4, std::nullopt)) == - hash(Book(a2, a4, std::nullopt))); - BEAST_EXPECT( - hash(Book(a3, a4, std::nullopt)) == - hash(Book(a3, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) == hash(Book(a1, a2, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a3, std::nullopt)) == hash(Book(a1, a3, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a4, std::nullopt)) == hash(Book(a1, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a2, a3, std::nullopt)) == hash(Book(a2, a3, std::nullopt))); + BEAST_EXPECT(hash(Book(a2, a4, std::nullopt)) == hash(Book(a2, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a3, a4, std::nullopt)) == hash(Book(a3, a4, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != - hash(Book(a1, a3, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != - hash(Book(a1, a4, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != - hash(Book(a2, a3, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != - hash(Book(a2, a4, std::nullopt))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != - hash(Book(a3, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a3, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a2, a3, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a2, a4, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a3, a4, std::nullopt))); // Books with domain - BEAST_EXPECT( - hash(Book(a1, a2, domain1)) == hash(Book(a1, a2, domain1))); - BEAST_EXPECT( - hash(Book(a1, a3, domain1)) == hash(Book(a1, a3, domain1))); - BEAST_EXPECT( - hash(Book(a1, a4, domain1)) == hash(Book(a1, a4, domain1))); - BEAST_EXPECT( - hash(Book(a2, a3, domain1)) == hash(Book(a2, a3, domain1))); - BEAST_EXPECT( - hash(Book(a2, a4, domain1)) == hash(Book(a2, a4, domain1))); - BEAST_EXPECT( - hash(Book(a3, a4, domain1)) == hash(Book(a3, a4, domain1))); - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) == - hash(Book(a1, a2, std::nullopt))); + BEAST_EXPECT(hash(Book(a1, a2, domain1)) == hash(Book(a1, a2, domain1))); + BEAST_EXPECT(hash(Book(a1, a3, domain1)) == hash(Book(a1, a3, domain1))); + BEAST_EXPECT(hash(Book(a1, a4, domain1)) == hash(Book(a1, a4, domain1))); + BEAST_EXPECT(hash(Book(a2, a3, domain1)) == hash(Book(a2, a3, domain1))); + BEAST_EXPECT(hash(Book(a2, a4, domain1)) == hash(Book(a2, a4, domain1))); + BEAST_EXPECT(hash(Book(a3, a4, domain1)) == hash(Book(a3, a4, domain1))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) == hash(Book(a1, a2, std::nullopt))); // Comparing Books with domain1 vs no domain - BEAST_EXPECT( - hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a2, domain1))); - BEAST_EXPECT( - hash(Book(a1, a3, std::nullopt)) != hash(Book(a1, a3, domain1))); - BEAST_EXPECT( - hash(Book(a1, a4, std::nullopt)) != hash(Book(a1, a4, domain1))); - BEAST_EXPECT( - hash(Book(a2, a3, std::nullopt)) != hash(Book(a2, a3, domain1))); - BEAST_EXPECT( - hash(Book(a2, a4, std::nullopt)) != hash(Book(a2, a4, domain1))); - BEAST_EXPECT( - hash(Book(a3, a4, std::nullopt)) != hash(Book(a3, a4, domain1))); + BEAST_EXPECT(hash(Book(a1, a2, std::nullopt)) != hash(Book(a1, a2, domain1))); + BEAST_EXPECT(hash(Book(a1, a3, std::nullopt)) != hash(Book(a1, a3, domain1))); + BEAST_EXPECT(hash(Book(a1, a4, std::nullopt)) != hash(Book(a1, a4, domain1))); + BEAST_EXPECT(hash(Book(a2, a3, std::nullopt)) != hash(Book(a2, a3, domain1))); + BEAST_EXPECT(hash(Book(a2, a4, std::nullopt)) != hash(Book(a2, a4, domain1))); + BEAST_EXPECT(hash(Book(a3, a4, std::nullopt)) != hash(Book(a3, a4, domain1))); // Books with domain1 but different Issues - BEAST_EXPECT( - hash(Book(a1, a2, domain1)) != hash(Book(a1, a3, domain1))); - BEAST_EXPECT( - hash(Book(a1, a2, domain1)) != hash(Book(a1, a4, domain1))); - BEAST_EXPECT( - hash(Book(a2, a3, domain1)) != hash(Book(a2, a4, domain1))); - BEAST_EXPECT( - hash(Book(a1, a2, domain1)) != hash(Book(a2, a3, domain1))); - BEAST_EXPECT( - hash(Book(a2, a4, domain1)) != hash(Book(a3, a4, domain1))); - BEAST_EXPECT( - hash(Book(a3, a4, domain1)) != hash(Book(a1, a4, domain1))); + BEAST_EXPECT(hash(Book(a1, a2, domain1)) != hash(Book(a1, a3, domain1))); + BEAST_EXPECT(hash(Book(a1, a2, domain1)) != hash(Book(a1, a4, domain1))); + BEAST_EXPECT(hash(Book(a2, a3, domain1)) != hash(Book(a2, a4, domain1))); + BEAST_EXPECT(hash(Book(a1, a2, domain1)) != hash(Book(a2, a3, domain1))); + BEAST_EXPECT(hash(Book(a2, a4, domain1)) != hash(Book(a3, a4, domain1))); + BEAST_EXPECT(hash(Book(a3, a4, domain1)) != hash(Book(a1, a4, domain1))); // Books with domain1 and domain2 - BEAST_EXPECT( - hash(Book(a1, a2, domain1)) != hash(Book(a1, a2, domain2))); - BEAST_EXPECT( - hash(Book(a1, a3, domain1)) != hash(Book(a1, a3, domain2))); - BEAST_EXPECT( - hash(Book(a1, a4, domain1)) != hash(Book(a1, a4, domain2))); - BEAST_EXPECT( - hash(Book(a2, a3, domain1)) != hash(Book(a2, a3, domain2))); - BEAST_EXPECT( - hash(Book(a2, a4, domain1)) != hash(Book(a2, a4, domain2))); - BEAST_EXPECT( - hash(Book(a3, a4, domain1)) != hash(Book(a3, a4, domain2))); + BEAST_EXPECT(hash(Book(a1, a2, domain1)) != hash(Book(a1, a2, domain2))); + BEAST_EXPECT(hash(Book(a1, a3, domain1)) != hash(Book(a1, a3, domain2))); + BEAST_EXPECT(hash(Book(a1, a4, domain1)) != hash(Book(a1, a4, domain2))); + BEAST_EXPECT(hash(Book(a2, a3, domain1)) != hash(Book(a2, a3, domain2))); + BEAST_EXPECT(hash(Book(a2, a4, domain1)) != hash(Book(a2, a4, domain2))); + BEAST_EXPECT(hash(Book(a3, a4, domain1)) != hash(Book(a3, a4, domain2))); } //-------------------------------------------------------------------------- @@ -900,7 +821,7 @@ public: testcase("std::set "); testBookSet>(); -#if RIPPLE_ASSETS_ENABLE_STD_HASH +#if XRPL_ASSETS_ENABLE_STD_HASH testcase("std::unordered_set "); testBookSet>(); @@ -924,7 +845,7 @@ public: testcase("std::map "); testBookMap>(); -#if RIPPLE_ASSETS_ENABLE_STD_HASH +#if XRPL_ASSETS_ENABLE_STD_HASH testcase("std::unordered_map "); testBookMap>(); @@ -978,6 +899,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Issue, protocol, ripple); +BEAST_DEFINE_TESTSUITE(Issue, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/Memo_test.cpp b/src/test/protocol/Memo_test.cpp index 3b36cfc368..3c5d3f5a38 100644 --- a/src/test/protocol/Memo_test.cpp +++ b/src/test/protocol/Memo_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2022 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class Memo_test : public beast::unit_test::suite { @@ -54,16 +35,14 @@ public: { // Make sure that too big a memo is flagged as invalid. JTx memoSize = makeJtxWithMemo(); - memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName] - [sfMemoData.jsonName] = std::string(2020, '0'); + memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoData.jsonName] = std::string(2020, '0'); env(memoSize, rpc("invalidTransaction", "fails local checks: The memo exceeds the maximum allowed " "size.")); // This memo is just barely small enough. - memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName] - [sfMemoData.jsonName] = std::string(2018, '1'); + memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoData.jsonName] = std::string(2018, '1'); env(memoSize); } { @@ -83,9 +62,7 @@ public: { // Put an invalid field in a Memo object. JTx memoExtra = makeJtxWithMemo(); - memoExtra - .jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfFlags.jsonName] = - 13; + memoExtra.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfFlags.jsonName] = 13; env(memoExtra, rpc("invalidTransaction", "fails local checks: A memo may contain only MemoType, " @@ -94,8 +71,7 @@ public: { // Put a character that is not allowed in a URL in a MemoType field. JTx memoBadChar = makeJtxWithMemo(); - memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName] - [sfMemoType.jsonName] = + memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfMemoType.jsonName] = strHex(std::string_view("ONE #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { namespace { @@ -55,7 +36,7 @@ struct MultiApiJson_test : beast::unit_test::suite void run() override { - using ripple::detail::MultiApiJson; + using xrpl::detail::MultiApiJson; Json::Value const obj1 = makeJson("value", 1); Json::Value const obj2 = makeJson("value", 2); @@ -65,13 +46,10 @@ struct MultiApiJson_test : beast::unit_test::suite MultiApiJson<1, 3> subject{}; static_assert(sizeof(subject) == sizeof(subject.val)); static_assert(subject.size == subject.val.size()); - static_assert( - std::is_same_v>); + static_assert(std::is_same_v>); BEAST_EXPECT(subject.val.size() == 3); - BEAST_EXPECT( - (subject.val == - std::array{jsonNull, jsonNull, jsonNull})); + BEAST_EXPECT((subject.val == std::array{jsonNull, jsonNull, jsonNull})); subject.val[0] = obj1; subject.val[1] = obj2; @@ -80,21 +58,15 @@ struct MultiApiJson_test : beast::unit_test::suite testcase("forApiVersions, forAllApiVersions"); // Some static data for test inputs - static int const primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, - 29, 31, 37, 41, 43, 47, 53, 59, 61, - 67, 71, 73, 79, 83, 89, 97}; + static int const primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; static_assert(std::size(primes) > RPC::apiMaximumValidVersion); MultiApiJson<1, 3> s1{}; - static_assert( - s1.size == - RPC::apiMaximumValidVersion + 1 - - RPC::apiMinimumSupportedVersion); + static_assert(s1.size == RPC::apiMaximumValidVersion + 1 - RPC::apiMinimumSupportedVersion); int productAllVersions = 1; - for (unsigned i = RPC::apiMinimumSupportedVersion; - i <= RPC::apiMaximumValidVersion; - ++i) + for (unsigned i = RPC::apiMinimumSupportedVersion; i <= RPC::apiMaximumValidVersion; ++i) { auto const index = i - RPC::apiMinimumSupportedVersion; BEAST_EXPECT(index == s1.index(i)); @@ -104,25 +76,15 @@ struct MultiApiJson_test : beast::unit_test::suite } BEAST_EXPECT(!s1.valid(0)); BEAST_EXPECT(!s1.valid(RPC::apiMaximumValidVersion + 1)); - BEAST_EXPECT( - !s1.valid(std::numeric_limits< - decltype(RPC::apiMaximumValidVersion.value)>::max())); + BEAST_EXPECT(!s1.valid(std::numeric_limits::max())); int result = 1; - static_assert( - RPC::apiMinimumSupportedVersion + 1 <= - RPC::apiMaximumValidVersion); - forApiVersions< - RPC::apiMinimumSupportedVersion, - RPC::apiMinimumSupportedVersion + 1>( + static_assert(RPC::apiMinimumSupportedVersion + 1 <= RPC::apiMaximumValidVersion); + forApiVersions( std::as_const(s1).visit(), - [this]( - Json::Value const& json, - unsigned int version, - int* result) { + [this](Json::Value const& json, unsigned int version, int* result) { BEAST_EXPECT( - version >= RPC::apiMinimumSupportedVersion && - version <= RPC::apiMinimumSupportedVersion + 1); + version >= RPC::apiMinimumSupportedVersion && version <= RPC::apiMinimumSupportedVersion + 1); if (BEAST_EXPECT(json.isMember("value"))) { *result *= json["value"].asInt(); @@ -130,30 +92,22 @@ struct MultiApiJson_test : beast::unit_test::suite }, &result); BEAST_EXPECT( - result == - primes[RPC::apiMinimumSupportedVersion] * - primes[RPC::apiMinimumSupportedVersion + 1]); + result == primes[RPC::apiMinimumSupportedVersion] * primes[RPC::apiMinimumSupportedVersion + 1]); // Check all the values with mutable data - forAllApiVersions( - s1.visit(), [&s1, this](Json::Value& json, auto version) { - BEAST_EXPECT(s1.val[s1.index(version)] == json); - if (BEAST_EXPECT(json.isMember("value"))) - { - BEAST_EXPECT(json["value"].asInt() == primes[version]); - } - }); + forAllApiVersions(s1.visit(), [&s1, this](Json::Value& json, auto version) { + BEAST_EXPECT(s1.val[s1.index(version)] == json); + if (BEAST_EXPECT(json.isMember("value"))) + { + BEAST_EXPECT(json["value"].asInt() == primes[version]); + } + }); result = 1; forAllApiVersions( std::as_const(s1).visit(), - [this]( - Json::Value const& json, - unsigned int version, - int* result) { - BEAST_EXPECT( - version >= RPC::apiMinimumSupportedVersion && - version <= RPC::apiMaximumValidVersion); + [this](Json::Value const& json, unsigned int version, int* result) { + BEAST_EXPECT(version >= RPC::apiMinimumSupportedVersion && version <= RPC::apiMaximumValidVersion); if (BEAST_EXPECT(json.isMember("value"))) { *result *= json["value"].asInt(); @@ -182,7 +136,7 @@ struct MultiApiJson_test : beast::unit_test::suite return !requires { forAllApiVersions( std::forward(v).visit(), // - []() {}); // missing parameters + []() {}); // missing parameters }; }(std::as_const(s1))); static_assert([](auto&& v) { @@ -253,10 +207,7 @@ struct MultiApiJson_test : beast::unit_test::suite forAllApiVersions( std::forward(v).visit(), // []( - Json::Value const&, - std::integral_constant, - int, - char const*) {}, + Json::Value const&, std::integral_constant, int, char const*) {}, 0, ""); }; @@ -327,27 +278,17 @@ struct MultiApiJson_test : beast::unit_test::suite BEAST_EXPECT(x.val[1]["name2"].asString() == "bar"); // Tests of requires clause - these are expected to match - static_assert([](auto&& v) { - return requires { v.set("name", Json::nullValue); }; - }(x)); - static_assert([](auto&& v) { - return requires { v.set("name", "value"); }; - }(x)); - static_assert( - [](auto&& v) { return requires { v.set("name", true); }; }(x)); - static_assert( - [](auto&& v) { return requires { v.set("name", 42); }; }(x)); + static_assert([](auto&& v) { return requires { v.set("name", Json::nullValue); }; }(x)); + static_assert([](auto&& v) { return requires { v.set("name", "value"); }; }(x)); + static_assert([](auto&& v) { return requires { v.set("name", true); }; }(x)); + static_assert([](auto&& v) { return requires { v.set("name", 42); }; }(x)); // Tests of requires clause - these are expected NOT to match struct foo_t final { }; - static_assert([](auto&& v) { - return !requires { v.set("name", foo_t{}); }; - }(x)); - static_assert([](auto&& v) { - return !requires { v.set("name", std::nullopt); }; - }(x)); + static_assert([](auto&& v) { return !requires { v.set("name", foo_t{}); }; }(x)); + static_assert([](auto&& v) { return !requires { v.set("name", std::nullopt); }; }(x)); } { @@ -406,8 +347,7 @@ struct MultiApiJson_test : beast::unit_test::suite v.visitor( v, std::integral_constant{}, - [](Json::Value&, std::integral_constant) { - }); + [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( @@ -415,20 +355,12 @@ struct MultiApiJson_test : beast::unit_test::suite s1, std::integral_constant{}, Overload{ - [](Json::Value& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires { - v.visitor( - v, - std::integral_constant{}, - [](Json::Value&) {}); - }; + return requires { v.visitor(v, std::integral_constant{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( @@ -444,8 +376,7 @@ struct MultiApiJson_test : beast::unit_test::suite v.visitor( v, std::integral_constant{}, - [](Json::Value const&, - std::integral_constant) {}); + [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( @@ -453,20 +384,12 @@ struct MultiApiJson_test : beast::unit_test::suite std::as_const(s1), std::integral_constant{}, Overload{ - [](Json::Value const& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value const& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires { - v.visitor( - v, - std::integral_constant{}, - [](Json::Value const&) {}); - }; + return requires { v.visitor(v, std::integral_constant{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( @@ -477,25 +400,17 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value&, unsigned) {}); - }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&, unsigned) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( s1, // 3u, Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, unsigned) { return 0; }, [](auto, auto) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value&) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( s1, // @@ -506,24 +421,19 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value const&, unsigned) {}); - }; + return requires { v.visitor(v, 1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( std::as_const(s1), // 2u, Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value const& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); + static_assert( + [](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( std::as_const(s1), // @@ -538,49 +448,37 @@ struct MultiApiJson_test : beast::unit_test::suite s1.visitor( s1, std::integral_constant{}, // to unsigned - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }) == 2); + [](Json::Value& v, unsigned) { return v["value"].asInt(); }) == 2); BEAST_EXPECT( s1.visitor( std::as_const(s1), std::integral_constant{}, // to unsigned - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }) == 3); + [](Json::Value const& v, unsigned) { return v["value"].asInt(); }) == 3); BEAST_EXPECT( s1.visitor( s1, // to const std::integral_constant{}, - [](Json::Value const& v, auto) { - return v["value"].asInt(); - }) == 5); + [](Json::Value const& v, auto) { return v["value"].asInt(); }) == 5); BEAST_EXPECT( s1.visitor( s1, // to const std::integral_constant{}, - [](Json::Value const& v) { return v["value"].asInt(); }) == - 5); + [](Json::Value const& v) { return v["value"].asInt(); }) == 5); BEAST_EXPECT( s1.visitor( s1, 3, // to long - [](Json::Value& v, long) { return v["value"].asInt(); }) == - 5); + [](Json::Value& v, long) { return v["value"].asInt(); }) == 5); BEAST_EXPECT( s1.visitor( std::as_const(s1), 1, // to long - [](Json::Value const& v, long) { - return v["value"].asInt(); - }) == 2); + [](Json::Value const& v, long) { return v["value"].asInt(); }) == 2); BEAST_EXPECT( s1.visitor( s1, // to const 2, - [](Json::Value const& v, auto) { - return v["value"].asInt(); - }) == 3); + [](Json::Value const& v, auto) { return v["value"].asInt(); }) == 3); BEAST_EXPECT( s1.visitor( s1, // type deduction @@ -590,8 +488,7 @@ struct MultiApiJson_test : beast::unit_test::suite s1.visitor( s1, // to const, type deduction 2, - [](auto const& v, auto) { return v["value"].asInt(); }) == - 3); + [](auto const& v, auto) { return v["value"].asInt(); }) == 3); BEAST_EXPECT( s1.visitor( s1, // type deduction @@ -608,18 +505,14 @@ struct MultiApiJson_test : beast::unit_test::suite s1.visitor( s1, std::integral_constant{}, - [](Json::Value& v, auto ver, auto a1, auto a2) { - return ver * a1 * a2 * v["value"].asInt(); - }, + [](Json::Value& v, auto ver, auto a1, auto a2) { return ver * a1 * a2 * v["value"].asInt(); }, 5, 7) == 2 * 5 * 7 * 3); BEAST_EXPECT( s1.visitor( s1, std::integral_constant{}, - [](Json::Value& v, auto ver, auto... args) { - return ver * (1 * ... * args) * v["value"].asInt(); - }, + [](Json::Value& v, auto ver, auto... args) { return ver * (1 * ... * args) * v["value"].asInt(); }, 5, 7) == 2 * 5 * 7 * 3); @@ -661,55 +554,27 @@ struct MultiApiJson_test : beast::unit_test::suite }(s1)); // Want these to be unambiguous - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](auto) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value&) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value&, auto...) {}); - }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&, auto...) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](Json::Value const&, auto...) {}); - }; - }(s1)); + static_assert( + [](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value const&, auto...) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](auto...) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto...) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { v.visitor(v, 1, [](auto, auto...) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto, auto...) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](auto, auto, auto...) {}); - }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto, auto, auto...) {}); }; }(s1)); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](auto, auto, auto...) {}, ""); - }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto, auto, auto...) {}, ""); }; }(s1)); - static_assert([](auto&& v) { - return requires { - v.visitor(v, 1, [](auto, auto, auto, auto...) {}, ""); - }; - }(s1)); + static_assert( + [](auto&& v) { return requires { v.visitor(v, 1, [](auto, auto, auto, auto...) {}, ""); }; }(s1)); } { @@ -725,45 +590,33 @@ struct MultiApiJson_test : beast::unit_test::suite return requires { v.visit( std::integral_constant{}, - [](Json::Value&, std::integral_constant) { - }); + [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( s1.visit( std::integral_constant{}, Overload{ - [](Json::Value& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { return requires { v.visit()( std::integral_constant{}, - [](Json::Value&, std::integral_constant) { - }); + [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( std::integral_constant{}, Overload{ - [](Json::Value& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires { - v.visit( - std::integral_constant{}, - [](Json::Value&) {}); - }; + return requires { v.visit(std::integral_constant{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit( @@ -773,11 +626,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value const&) { return 0; }, [](auto...) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires { - v.visit()( - std::integral_constant{}, - [](Json::Value&) {}); - }; + return requires { v.visit()(std::integral_constant{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( @@ -791,45 +640,33 @@ struct MultiApiJson_test : beast::unit_test::suite return requires { v.visit( std::integral_constant{}, - [](Json::Value const&, - std::integral_constant) {}); + [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( std::integral_constant{}, Overload{ - [](Json::Value const& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value const& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { return requires { v.visit()( std::integral_constant{}, - [](Json::Value const&, - std::integral_constant) {}); + [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( std::integral_constant{}, Overload{ - [](Json::Value const& v, - std::integral_constant) { - return v["value"].asInt(); - }, + [](Json::Value const& v, std::integral_constant) { return v["value"].asInt(); }, [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires { - v.visit( - std::integral_constant{}, - [](Json::Value const&) {}); - }; + return requires { v.visit(std::integral_constant{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( @@ -839,11 +676,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires { - v.visit()( - std::integral_constant{}, - [](Json::Value const&) {}); - }; + return requires { v.visit()(std::integral_constant{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( @@ -853,38 +686,26 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { v.visit(1, [](Json::Value&, unsigned) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visit(1, [](Json::Value&, unsigned) {}); }; }(s1)); BEAST_EXPECT( s1.visit( 3u, Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, unsigned) { return 0; }, [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { - v.visit()(1, [](Json::Value&, unsigned) {}); - }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visit()(1, [](Json::Value&, unsigned) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( 3u, Overload{ - [](Json::Value& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, unsigned) { return 0; }, [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { v.visit(1, [](Json::Value&) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visit(1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit( 3, @@ -892,9 +713,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value& v) { return v["value"].asInt(); }, [](Json::Value const&) { return 0; }, [](auto...) { return 0; }}) == 5); - static_assert([](auto&& v) { - return requires { v.visit()(1, [](Json::Value&) {}); }; - }(s1)); + static_assert([](auto&& v) { return requires { v.visit()(1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( 3, @@ -904,39 +723,30 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires { - v.visit(1, [](Json::Value const&, unsigned) {}); - }; + return requires { v.visit(1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( 2u, Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value const& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](Json::Value&, unsigned) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires { - v.visit()(1, [](Json::Value const&, unsigned) {}); - }; + return requires { v.visit()(1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( 2u, Overload{ - [](Json::Value const& v, unsigned) { - return v["value"].asInt(); - }, + [](Json::Value const& v, unsigned) { return v["value"].asInt(); }, [](Json::Value const&, auto) { return 0; }, [](Json::Value&, unsigned) { return 0; }, [](auto, auto) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { v.visit(1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); + static_assert( + [](auto&& v) { return requires { v.visit(1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( 2, @@ -944,9 +754,8 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value const& v) { return v["value"].asInt(); }, [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); - static_assert([](auto&& v) { - return requires { v.visit()(1, [](Json::Value const&) {}); }; - }(std::as_const(s1))); + static_assert( + [](auto&& v) { return requires { v.visit()(1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( 2, @@ -957,118 +766,66 @@ struct MultiApiJson_test : beast::unit_test::suite // Rvalue MultivarJson visitor only binds to regular reference static_assert([](auto&& v) { - return !requires { - std::forward(v).visit(1, [](Json::Value&&) {}); - }; + return !requires { std::forward(v).visit(1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value const&&) {}); - }; + return !requires { std::forward(v).visit(1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit(1, [](Json::Value&) {}); - }; + return requires { std::forward(v).visit(1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit( - 1, [](Json::Value const&) {}); - }; + return requires { std::forward(v).visit(1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value&&) {}); - }; + return !requires { std::forward(v).visit()(1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value const&&) {}); - }; + return !requires { std::forward(v).visit()(1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value&) {}); - }; + return requires { std::forward(v).visit()(1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value const&) {}); - }; + return requires { std::forward(v).visit()(1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value const&&) {}); - }; + return !requires { std::forward(v).visit(1, [](Json::Value const&&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit( - 1, [](Json::Value const&) {}); - }; + return requires { std::forward(v).visit(1, [](Json::Value const&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value const&&) {}); - }; + return !requires { std::forward(v).visit()(1, [](Json::Value const&&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit()( - 1, [](Json::Value const&) {}); - }; + return requires { std::forward(v).visit()(1, [](Json::Value const&) {}); }; }(std::move(std::as_const(s1)))); // Missing const static_assert([](auto&& v) { - return !requires { - std::forward(v).visit( - 1, [](Json::Value&, auto) {}); - }; + return !requires { std::forward(v).visit(1, [](Json::Value&, auto) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()( - 1, [](Json::Value&, auto) {}); - }; + return !requires { std::forward(v).visit()(1, [](Json::Value&, auto) {}); }; }(std::as_const(s1))); // Missing parameter - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit(1, []() {}); - }; - }(s1)); - static_assert([](auto&& v) { - return !requires { - std::forward(v).visit()(1, []() {}); - }; - }(s1)); + static_assert([](auto&& v) { return !requires { std::forward(v).visit(1, []() {}); }; }(s1)); + static_assert([](auto&& v) { return !requires { std::forward(v).visit()(1, []() {}); }; }(s1)); // Sanity checks static_assert([](auto&& v) { - return requires { - std::forward(v).visit(1, [](auto...) {}); - }; + return requires { std::forward(v).visit(1, [](auto...) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return requires { - std::forward(v).visit()(1, [](auto...) {}); - }; + return requires { std::forward(v).visit()(1, [](auto...) {}); }; }(std::as_const(s1))); } } }; -BEAST_DEFINE_TESTSUITE(MultiApiJson, protocol, ripple); +BEAST_DEFINE_TESTSUITE(MultiApiJson, protocol, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/PublicKey_test.cpp b/src/test/protocol/PublicKey_test.cpp index 0f5aef261a..cad1e87198 100644 --- a/src/test/protocol/PublicKey_test.cpp +++ b/src/test/protocol/PublicKey_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { class PublicKey_test : public beast::unit_test::suite { @@ -313,11 +294,9 @@ public: // Try converting short, long and malformed data BEAST_EXPECT(!parseBase58(TokenType::NodePublic, "")); BEAST_EXPECT(!parseBase58(TokenType::NodePublic, " ")); - BEAST_EXPECT( - !parseBase58(TokenType::NodePublic, "!ty89234gh45")); + BEAST_EXPECT(!parseBase58(TokenType::NodePublic, "!ty89234gh45")); - auto const good = toBase58( - TokenType::NodePublic, derivePublicKey(keyType, randomSecretKey())); + auto const good = toBase58(TokenType::NodePublic, derivePublicKey(keyType, randomSecretKey())); // Short (non-empty) strings { @@ -387,8 +366,7 @@ public: BEAST_EXPECT((si == sj) == (i == j)); - auto const skj = - parseBase58(TokenType::NodePublic, sj); + auto const skj = parseBase58(TokenType::NodePublic, sj); BEAST_EXPECT(skj && (keys[j] == *skj)); BEAST_EXPECT((*ski == *skj) == (i == j)); @@ -403,13 +381,10 @@ public: { auto const pk1 = derivePublicKey( - KeyType::secp256k1, - generateSecretKey( - KeyType::secp256k1, generateSeed("masterpassphrase"))); + KeyType::secp256k1, generateSecretKey(KeyType::secp256k1, generateSeed("masterpassphrase"))); - auto const pk2 = parseBase58( - TokenType::NodePublic, - "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9"); + auto const pk2 = + parseBase58(TokenType::NodePublic, "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9"); BEAST_EXPECT(pk2); BEAST_EXPECT(pk1 == *pk2); @@ -421,13 +396,10 @@ public: { auto const pk1 = derivePublicKey( - KeyType::ed25519, - generateSecretKey( - KeyType::ed25519, generateSeed("masterpassphrase"))); + KeyType::ed25519, generateSecretKey(KeyType::ed25519, generateSeed("masterpassphrase"))); - auto const pk2 = parseBase58( - TokenType::NodePublic, - "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf"); + auto const pk2 = + parseBase58(TokenType::NodePublic, "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf"); BEAST_EXPECT(pk2); BEAST_EXPECT(pk1 == *pk2); @@ -442,18 +414,14 @@ public: testcase("Miscellaneous operations"); auto const pk1 = derivePublicKey( - KeyType::secp256k1, - generateSecretKey( - KeyType::secp256k1, generateSeed("masterpassphrase"))); + KeyType::secp256k1, generateSecretKey(KeyType::secp256k1, generateSeed("masterpassphrase"))); PublicKey pk2(pk1); BEAST_EXPECT(pk1 == pk2); BEAST_EXPECT(pk2 == pk1); PublicKey pk3 = derivePublicKey( - KeyType::secp256k1, - generateSecretKey( - KeyType::secp256k1, generateSeed("arbitraryPassPhrase"))); + KeyType::secp256k1, generateSecretKey(KeyType::secp256k1, generateSeed("arbitraryPassPhrase"))); // Testing the copy assignment operation of PublicKey class pk3 = pk2; BEAST_EXPECT(pk3 == pk2); @@ -469,6 +437,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(PublicKey, protocol, ripple); +BEAST_DEFINE_TESTSUITE(PublicKey, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/Quality_test.cpp b/src/test/protocol/Quality_test.cpp index aa9918a064..1dbbbfdf3d 100644 --- a/src/test/protocol/Quality_test.cpp +++ b/src/test/protocol/Quality_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class Quality_test : public beast::unit_test::suite { @@ -35,9 +16,7 @@ public: template static STAmount - amount( - Integer integer, - std::enable_if_t::value>* = 0) + amount(Integer integer, std::enable_if_t::value>* = 0) { static_assert(std::is_integral::value, ""); return STAmount(integer, false); @@ -45,9 +24,7 @@ public: template static STAmount - amount( - Integer integer, - std::enable_if_t::value>* = 0) + amount(Integer integer, std::enable_if_t::value>* = 0) { static_assert(std::is_integral::value, ""); if (integer < 0) @@ -64,13 +41,7 @@ public: template void - ceil_in( - Quality const& q, - In1 in, - Out1 out, - Int limit, - In2 in_expected, - Out2 out_expected) + ceil_in(Quality const& q, In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected) { auto expect_result(amounts(in_expected, out_expected)); auto actual_result(q.ceil_in(amounts(in, out), amount(limit))); @@ -80,13 +51,7 @@ public: template void - ceil_out( - Quality const& q, - In1 in, - Out1 out, - Int limit, - In2 in_expected, - Out2 out_expected) + ceil_out(Quality const& q, In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected) { auto const expect_result(amounts(in_expected, out_expected)); auto const actual_result(q.ceil_out(amounts(in, out), amount(limit))); @@ -288,10 +253,9 @@ public: { Quality q(0x5d048191fb9130daull); // 126836389.7680090 Amounts const value( - amount(349469768), // 349.469768 XRP - raw(2755280000000000ull, -15)); // 2.75528 - STAmount const limit( - raw(4131113916555555, -16)); // .4131113916555555 + amount(349469768), // 349.469768 XRP + raw(2755280000000000ull, -15)); // 2.75528 + STAmount const limit(raw(4131113916555555, -16)); // .4131113916555555 Amounts const result(q.ceil_out(value, limit)); BEAST_EXPECT(result.in != beast::zero); } @@ -385,8 +349,7 @@ public: { testcase("operations"); - Quality const q11( - Amounts(STAmount(noIssue(), 731), STAmount(noIssue(), 731))); + Quality const q11(Amounts(STAmount(noIssue(), 731), STAmount(noIssue(), 731))); Quality qa(q11); Quality qb(q11); @@ -415,6 +378,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Quality, protocol, ripple); +BEAST_DEFINE_TESTSUITE(Quality, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STAccount_test.cpp b/src/test/protocol/STAccount_test.cpp index cc318b4458..76b633df80 100644 --- a/src/test/protocol/STAccount_test.cpp +++ b/src/test/protocol/STAccount_test.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { struct STAccount_test : public beast::unit_test::suite { @@ -82,8 +63,7 @@ struct STAccount_test : public beast::unit_test::suite Serializer s; zeroAcct.add(s); BEAST_EXPECT(s.size() == 21); - BEAST_EXPECT( - strHex(s) == "140000000000000000000000000000000000000000"); + BEAST_EXPECT(strHex(s) == "140000000000000000000000000000000000000000"); SerialIter sit(s.slice()); STAccount const deserializedZero(sit, sfAccount); BEAST_EXPECT(deserializedZero.isEquivalent(zeroAcct)); @@ -91,8 +71,7 @@ struct STAccount_test : public beast::unit_test::suite { // Construct from a VL that is not exactly 160 bits. Serializer s; - std::uint8_t const bits128[]{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::uint8_t const bits128[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; s.addVL(bits128, sizeof(bits128)); SerialIter sit(s.slice()); try @@ -102,8 +81,7 @@ struct STAccount_test : public beast::unit_test::suite } catch (std::runtime_error const& ex) { - BEAST_EXPECT( - ex.what() == std::string("Invalid STAccount size")); + BEAST_EXPECT(ex.what() == std::string("Invalid STAccount size")); } } @@ -132,8 +110,7 @@ struct STAccount_test : public beast::unit_test::suite } { - auto const s = - "âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f"; + auto const s = "âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f"; BEAST_EXPECT(!parseBase58(s)); } } @@ -146,6 +123,6 @@ struct STAccount_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STAccount, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STAccount, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STAmount_test.cpp b/src/test/protocol/STAmount_test.cpp index 5d3fdfb28a..98bcc7b1bc 100644 --- a/src/test/protocol/STAmount_test.cpp +++ b/src/test/protocol/STAmount_test.cpp @@ -1,29 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include +#include -namespace ripple { +namespace xrpl { class STAmount_test : public beast::unit_test::suite { @@ -53,18 +35,9 @@ public: mantissa--; if (mantissa < STAmount::cMinValue) - return { - amount.issue(), - mantissa, - amount.exponent(), - amount.negative()}; + return {amount.issue(), mantissa, amount.exponent(), amount.negative()}; - return { - amount.issue(), - mantissa, - amount.exponent(), - amount.negative(), - STAmount::unchecked{}}; + return {amount.issue(), mantissa, amount.exponent(), amount.negative(), STAmount::unchecked{}}; } if (valueDigits == 999999999) @@ -72,18 +45,9 @@ public: mantissa++; if (mantissa > STAmount::cMaxValue) - return { - amount.issue(), - mantissa, - amount.exponent(), - amount.negative()}; + return {amount.issue(), mantissa, amount.exponent(), amount.negative()}; - return { - amount.issue(), - mantissa, - amount.exponent(), - amount.negative(), - STAmount::unchecked{}}; + return {amount.issue(), mantissa, amount.exponent(), amount.negative(), STAmount::unchecked{}}; } return amount; @@ -109,9 +73,8 @@ public: if (res != cmp) { - log << "(" << num.getText() << "/" << den.getText() << ") X " - << mul.getText() << " = " << res.getText() << " not " - << cmp.getText(); + log << "(" << num.getText() << "/" << den.getText() << ") X " << mul.getText() << " = " << res.getText() + << " not " << cmp.getText(); fail("Rounding"); return; } @@ -126,14 +89,11 @@ public: BEAST_EXPECT(!prod1.native()); - STAmount prod2( - noIssue(), - static_cast(a) * static_cast(b)); + STAmount prod2(noIssue(), static_cast(a) * static_cast(b)); if (prod1 != prod2) { - log << "nn(" << aa.getFullText() << " * " << bb.getFullText() - << ") = " << prod1.getFullText() << " not " + log << "nn(" << aa.getFullText() << " * " << bb.getFullText() << ") = " << prod1.getFullText() << " not " << prod2.getFullText(); fail("Multiplication result is not exact"); } @@ -142,10 +102,7 @@ public: //-------------------------------------------------------------------------- void - testSetValue( - std::string const& value, - Issue const& issue, - bool success = true) + testSetValue(std::string const& value, Issue const& issue, bool success = true) { try { @@ -233,8 +190,7 @@ public: // VFALCO NOTE Why repeat "STAmount fail" so many times?? unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail"); unexpected(serializeAndDeserialize(one) != one, "STAmount fail"); - unexpected( - serializeAndDeserialize(hundred) != hundred, "STAmount fail"); + unexpected(serializeAndDeserialize(hundred) != hundred, "STAmount fail"); unexpected(!zeroSt.native(), "STAmount fail"); unexpected(!hundred.native(), "STAmount fail"); unexpected(zeroSt != beast::zero, "STAmount fail"); @@ -316,8 +272,7 @@ public: STAmount zeroSt(noIssue()), one(noIssue(), 1), hundred(noIssue(), 100); unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail"); unexpected(serializeAndDeserialize(one) != one, "STAmount fail"); - unexpected( - serializeAndDeserialize(hundred) != hundred, "STAmount fail"); + unexpected(serializeAndDeserialize(hundred) != hundred, "STAmount fail"); unexpected(zeroSt.native(), "STAmount fail"); unexpected(hundred.native(), "STAmount fail"); unexpected(zeroSt != beast::zero, "STAmount fail"); @@ -379,33 +334,19 @@ public: unexpected((hundred != hundred), "STAmount fail"); unexpected(STAmount(noIssue()).getText() != "0", "STAmount fail"); unexpected(STAmount(noIssue(), 31).getText() != "31", "STAmount fail"); + unexpected(STAmount(noIssue(), 31, 1).getText() != "310", "STAmount fail"); + unexpected(STAmount(noIssue(), 31, -1).getText() != "3.1", "STAmount fail"); + unexpected(STAmount(noIssue(), 31, -2).getText() != "0.31", "STAmount fail"); unexpected( - STAmount(noIssue(), 31, 1).getText() != "310", "STAmount fail"); + multiply(STAmount(noIssue(), 20), STAmount(3), noIssue()).getText() != "60", "STAmount multiply fail 1"); unexpected( - STAmount(noIssue(), 31, -1).getText() != "3.1", "STAmount fail"); - unexpected( - STAmount(noIssue(), 31, -2).getText() != "0.31", "STAmount fail"); - unexpected( - multiply(STAmount(noIssue(), 20), STAmount(3), noIssue()) - .getText() != "60", - "STAmount multiply fail 1"); - unexpected( - multiply(STAmount(noIssue(), 20), STAmount(3), xrpIssue()) - .getText() != "60", - "STAmount multiply fail 2"); - unexpected( - multiply(STAmount(20), STAmount(3), noIssue()).getText() != "60", - "STAmount multiply fail 3"); - unexpected( - multiply(STAmount(20), STAmount(3), xrpIssue()).getText() != "60", - "STAmount multiply fail 4"); + multiply(STAmount(noIssue(), 20), STAmount(3), xrpIssue()).getText() != "60", "STAmount multiply fail 2"); + unexpected(multiply(STAmount(20), STAmount(3), noIssue()).getText() != "60", "STAmount multiply fail 3"); + unexpected(multiply(STAmount(20), STAmount(3), xrpIssue()).getText() != "60", "STAmount multiply fail 4"); - if (divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText() != - "20") + if (divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText() != "20") { - log << "60/3 = " - << divide(STAmount(noIssue(), 60), STAmount(3), noIssue()) - .getText(); + log << "60/3 = " << divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText(); fail("STAmount divide fail"); } else @@ -413,30 +354,21 @@ public: pass(); } + unexpected(divide(STAmount(noIssue(), 60), STAmount(3), xrpIssue()).getText() != "20", "STAmount divide fail"); + unexpected( - divide(STAmount(noIssue(), 60), STAmount(3), xrpIssue()) - .getText() != "20", + divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), noIssue()).getText() != "20", "STAmount divide fail"); unexpected( - divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), noIssue()) - .getText() != "20", - "STAmount divide fail"); - - unexpected( - divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), xrpIssue()) - .getText() != "20", + divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), xrpIssue()).getText() != "20", "STAmount divide fail"); STAmount a1(noIssue(), 60), a2(noIssue(), 10, -1); - unexpected( - divide(a2, a1, noIssue()) != amountFromQuality(getRate(a1, a2)), - "STAmount setRate(getRate) fail"); + unexpected(divide(a2, a1, noIssue()) != amountFromQuality(getRate(a1, a2)), "STAmount setRate(getRate) fail"); - unexpected( - divide(a1, a2, noIssue()) != amountFromQuality(getRate(a2, a1)), - "STAmount setRate(getRate) fail"); + unexpected(divide(a1, a2, noIssue()) != amountFromQuality(getRate(a2, a1)), "STAmount setRate(getRate) fail"); } //-------------------------------------------------------------------------- @@ -451,13 +383,11 @@ public: // and getNeeded unexpected( - getRate(STAmount(1), STAmount(10)) != - (((100ull - 14) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(1), STAmount(10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 1"); unexpected( - getRate(STAmount(10), STAmount(1)) != - (((100ull - 16) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(10), STAmount(1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 2"); unexpected( @@ -471,23 +401,19 @@ public: "STAmount getRate fail 4"); unexpected( - getRate(STAmount(noIssue(), 1), STAmount(10)) != - (((100ull - 14) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(noIssue(), 1), STAmount(10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 5"); unexpected( - getRate(STAmount(noIssue(), 10), STAmount(1)) != - (((100ull - 16) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(noIssue(), 10), STAmount(1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 6"); unexpected( - getRate(STAmount(1), STAmount(noIssue(), 10)) != - (((100ull - 14) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(1), STAmount(noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 7"); unexpected( - getRate(STAmount(10), STAmount(noIssue(), 1)) != - (((100ull - 16) << (64 - 8)) | 1000000000000000ull), + getRate(STAmount(10), STAmount(noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull), "STAmount getRate fail 8"); roundTest(1, 3, 3); @@ -511,19 +437,13 @@ public: testcase("underflow"); STAmount bigNative(STAmount::cMaxNative / 2); - STAmount bigValue( - noIssue(), - (STAmount::cMinValue + STAmount::cMaxValue) / 2, - STAmount::cMaxOffset - 1); - STAmount smallValue( - noIssue(), - (STAmount::cMinValue + STAmount::cMaxValue) / 2, - STAmount::cMinOffset + 1); + STAmount bigValue(noIssue(), (STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1); + STAmount smallValue(noIssue(), (STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1); STAmount zeroSt(noIssue(), 0); - STAmount smallXsmall = multiply(smallValue, smallValue, noIssue()); + STAmount smallXSmall = multiply(smallValue, smallValue, noIssue()); - BEAST_EXPECT(smallXsmall == beast::zero); + BEAST_EXPECT(smallXSmall == beast::zero); STAmount bigDsmall = divide(smallValue, bigValue, noIssue()); @@ -604,6 +524,203 @@ public: #endif } + void + testParseJson() + { + static_assert(!std::is_convertible_v); + + { + STAmount const stnum{sfNumber}; + BEAST_EXPECT(stnum.getSType() == STI_AMOUNT); + BEAST_EXPECT(stnum.getText() == "0"); + BEAST_EXPECT(stnum.isDefault() == true); + BEAST_EXPECT(stnum.value() == Number{0}); + } + + { + BEAST_EXPECT(amountFromJson(sfNumber, Json::Value(42)) == XRPAmount(42)); + BEAST_EXPECT(amountFromJson(sfNumber, Json::Value(-42)) == XRPAmount(-42)); + + BEAST_EXPECT(amountFromJson(sfNumber, Json::UInt(42)) == XRPAmount(42)); + + BEAST_EXPECT(amountFromJson(sfNumber, "-123") == XRPAmount(-123)); + + BEAST_EXPECT(amountFromJson(sfNumber, "123") == XRPAmount(123)); + BEAST_EXPECT(amountFromJson(sfNumber, "-123") == XRPAmount(-123)); + + BEAST_EXPECT(amountFromJson(sfNumber, "3.14e2") == XRPAmount(314)); + BEAST_EXPECT(amountFromJson(sfNumber, "-3.14e2") == XRPAmount(-314)); + + BEAST_EXPECT(amountFromJson(sfNumber, "0") == XRPAmount(0)); + BEAST_EXPECT(amountFromJson(sfNumber, "-0") == XRPAmount(0)); + + constexpr auto imin = std::numeric_limits::min(); + BEAST_EXPECT(amountFromJson(sfNumber, imin) == XRPAmount(imin)); + BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(imin)) == XRPAmount(imin)); + + constexpr auto imax = std::numeric_limits::max(); + BEAST_EXPECT(amountFromJson(sfNumber, imax) == XRPAmount(imax)); + BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(imax)) == XRPAmount(imax)); + + constexpr auto umax = std::numeric_limits::max(); + BEAST_EXPECT(amountFromJson(sfNumber, umax) == XRPAmount(umax)); + BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(umax)) == XRPAmount(umax)); + + // XRP does not handle fractional part + try + { + auto _ = amountFromJson(sfNumber, "0.0"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "XRP and MPT must be specified as integral amount."; + BEAST_EXPECT(e.what() == expected); + } + + // XRP does not handle fractional part + try + { + auto _ = amountFromJson(sfNumber, "1000e-2"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "XRP and MPT must be specified as integral amount."; + BEAST_EXPECT(e.what() == expected); + } + + // Obvious non-numbers tested here + try + { + auto _ = amountFromJson(sfNumber, ""); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "e"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'e' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "1e"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'1e' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "e2"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'e2' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, Json::Value()); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "XRP may not be specified with a null Json value"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson( + sfNumber, + "123456789012345678901234567890123456789012345678901234" + "5678" + "901234567890123456789012345678901234567890123456789012" + "3456" + "78901234567890123456789012345678901234567890"); + BEAST_EXPECT(false); + } + catch (std::bad_cast const& e) + { + BEAST_EXPECT(true); + } + + // We do not handle leading zeros + try + { + auto _ = amountFromJson(sfNumber, "001"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'001' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "000.0"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'000.0' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + // We do not handle dangling dot + try + { + auto _ = amountFromJson(sfNumber, ".1"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'.1' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "1."); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'1.' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + + try + { + auto _ = amountFromJson(sfNumber, "1.e3"); + BEAST_EXPECT(false); + } + catch (std::runtime_error const& e) + { + std::string const expected = "'1.e3' is not a number"; + BEAST_EXPECT(e.what() == expected); + } + } + } + void testConvertXRP() { @@ -612,8 +729,7 @@ public: Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)}; Issue const xrp{xrpIssue()}; - for (std::uint64_t drops = 100000000000000000; drops != 1; - drops = drops / 10) + for (std::uint64_t drops = 100000000000000000; drops != 1; drops = drops / 10) { auto const t = amountFromString(xrp, std::to_string(drops)); auto const s = t.xrp(); @@ -645,8 +761,7 @@ public: Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)}; Issue const xrp{xrpIssue()}; - for (std::uint64_t dollars = 10000000000; dollars != 1; - dollars = dollars / 10) + for (std::uint64_t dollars = 10000000000; dollars != 1; dollars = dollars / 10) { auto const t = amountFromString(usd, std::to_string(dollars)); auto const s = t.iou(); @@ -829,8 +944,7 @@ public: // Overflow check for max MPT amounts { - STAmount amt1( - mpt, std::numeric_limits::max()); + STAmount amt1(mpt, std::numeric_limits::max()); STAmount amt2(mpt, 1); BEAST_EXPECT(canAdd(amt1, amt2) == false); } @@ -1002,8 +1116,7 @@ public: // Overflow check for max positive MPT amounts (should fail) { - STAmount amt1( - mpt, std::numeric_limits::max()); + STAmount amt1(mpt, std::numeric_limits::max()); STAmount amt2(mpt, -2); BEAST_EXPECT(canSubtract(amt1, amt2) == false); } @@ -1041,6 +1154,7 @@ public: testArithmetic(); testUnderflow(); testRounding(); + testParseJson(); testConvertXRP(); testConvertIOU(); testCanAddXRP(); @@ -1052,6 +1166,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(STAmount, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STAmount, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STInteger_test.cpp b/src/test/protocol/STInteger_test.cpp index 6c4cdd6fcf..74340d53ea 100644 --- a/src/test/protocol/STInteger_test.cpp +++ b/src/test/protocol/STInteger_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -namespace ripple { +namespace xrpl { struct STInteger_test : public beast::unit_test::suite { @@ -40,9 +21,7 @@ struct STInteger_test : public beast::unit_test::suite // there is some special handling for sfTransactionResult STUInt8 tr(sfTransactionResult, 0); BEAST_EXPECT(tr.value() == 0); - BEAST_EXPECT( - tr.getText() == - "The transaction was applied. Only final in a validated ledger."); + BEAST_EXPECT(tr.getText() == "The transaction was applied. Only final in a validated ledger."); BEAST_EXPECT(tr.getSType() == STI_UINT8); BEAST_EXPECT(tr.getJson(JsonOptions::none) == "tesSUCCESS"); @@ -120,8 +99,7 @@ struct STInteger_test : public beast::unit_test::suite BEAST_EXPECT(u64_2.value() == 0xFFFFFFFFFFFFFFFFull); BEAST_EXPECT(u64_2.getText() == "18446744073709551615"); BEAST_EXPECT(u64_2.getSType() == STI_UINT64); - BEAST_EXPECT( - u64_2.getJson(JsonOptions::none) == "18446744073709551615"); + BEAST_EXPECT(u64_2.getJson(JsonOptions::none) == "18446744073709551615"); } void @@ -158,6 +136,6 @@ struct STInteger_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STInteger, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STInteger, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STIssue_test.cpp b/src/test/protocol/STIssue_test.cpp index 6ef80cd379..cfd047e752 100644 --- a/src/test/protocol/STIssue_test.cpp +++ b/src/test/protocol/STIssue_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class STIssue_test : public beast::unit_test::suite @@ -142,12 +123,8 @@ public: BEAST_EXPECT(STIssue(sfAsset, asset1) != asset3); BEAST_EXPECT(STIssue(sfAsset, asset1) == asset1); BEAST_EXPECT(STIssue(sfAsset, asset1).getText() == "XRP"); - BEAST_EXPECT( - STIssue(sfAsset, asset2).getText() == - "USD/rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"); - BEAST_EXPECT( - STIssue(sfAsset, asset3).getText() == - "000000000000000000000000000000000000000000000002"); + BEAST_EXPECT(STIssue(sfAsset, asset2).getText() == "USD/rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"); + BEAST_EXPECT(STIssue(sfAsset, asset3).getText() == "000000000000000000000000000000000000000000000002"); } void @@ -159,7 +136,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(STIssue, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STIssue, protocol, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STNumber_test.cpp b/src/test/protocol/STNumber_test.cpp index 6f2c57ecb0..a1a94accaa 100644 --- a/src/test/protocol/STNumber_test.cpp +++ b/src/test/protocol/STNumber_test.cpp @@ -1,26 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include +#include #include #include @@ -28,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { struct STNumber_test : public beast::unit_test::suite { @@ -47,10 +29,8 @@ struct STNumber_test : public beast::unit_test::suite } void - run() override + doRun() { - static_assert(!std::is_convertible_v); - { STNumber const stnum{sfNumber}; BEAST_EXPECT(stnum.getSType() == STI_NUMBER); @@ -60,16 +40,11 @@ struct STNumber_test : public beast::unit_test::suite } std::initializer_list const mantissas = { - std::numeric_limits::min(), - -1, - 0, - 1, - std::numeric_limits::max()}; + std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}; for (std::int64_t mantissa : mantissas) testCombo(Number{mantissa}); - std::initializer_list const exponents = { - Number::minExponent, -1, 0, 1, Number::maxExponent - 1}; + std::initializer_list const exponents = {Number::minExponent, -1, 0, 1, Number::maxExponent - 1}; for (std::int32_t exponent : exponents) testCombo(Number{123, exponent}); @@ -83,67 +58,71 @@ struct STNumber_test : public beast::unit_test::suite } { - BEAST_EXPECT( - numberFromJson(sfNumber, Json::Value(42)) == - STNumber(sfNumber, 42)); - BEAST_EXPECT( - numberFromJson(sfNumber, Json::Value(-42)) == - STNumber(sfNumber, -42)); + BEAST_EXPECT(numberFromJson(sfNumber, Json::Value(42)) == STNumber(sfNumber, 42)); + BEAST_EXPECT(numberFromJson(sfNumber, Json::Value(-42)) == STNumber(sfNumber, -42)); - BEAST_EXPECT( - numberFromJson(sfNumber, Json::UInt(42)) == - STNumber(sfNumber, 42)); + BEAST_EXPECT(numberFromJson(sfNumber, Json::UInt(42)) == STNumber(sfNumber, 42)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123)); + BEAST_EXPECT(numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123)); - BEAST_EXPECT( - numberFromJson(sfNumber, "123") == STNumber(sfNumber, 123)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123)); + BEAST_EXPECT(numberFromJson(sfNumber, "123") == STNumber(sfNumber, 123)); + BEAST_EXPECT(numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123)); - BEAST_EXPECT( - numberFromJson(sfNumber, "3.14") == - STNumber(sfNumber, Number(314, -2))); - BEAST_EXPECT( - numberFromJson(sfNumber, "-3.14") == - STNumber(sfNumber, -Number(314, -2))); - BEAST_EXPECT( - numberFromJson(sfNumber, "3.14e2") == STNumber(sfNumber, 314)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-3.14e2") == - STNumber(sfNumber, -314)); + BEAST_EXPECT(numberFromJson(sfNumber, "3.14") == STNumber(sfNumber, Number(314, -2))); + BEAST_EXPECT(numberFromJson(sfNumber, "-3.14") == STNumber(sfNumber, -Number(314, -2))); + BEAST_EXPECT(numberFromJson(sfNumber, "3.14e2") == STNumber(sfNumber, 314)); + BEAST_EXPECT(numberFromJson(sfNumber, "-3.14e2") == STNumber(sfNumber, -314)); - BEAST_EXPECT( - numberFromJson(sfNumber, "1000e-2") == STNumber(sfNumber, 10)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-1000e-2") == - STNumber(sfNumber, -10)); + BEAST_EXPECT(numberFromJson(sfNumber, "1000e-2") == STNumber(sfNumber, 10)); + BEAST_EXPECT(numberFromJson(sfNumber, "-1000e-2") == STNumber(sfNumber, -10)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0.0") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0.000") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0.0") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0.000") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0e6") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0.0e6") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "0.000e6") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0e6") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0.0e6") == STNumber(sfNumber, 0)); - BEAST_EXPECT( - numberFromJson(sfNumber, "-0.000e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0.0") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0.000") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0.0") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0.000") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0.0e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "0.000e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0.0e6") == STNumber(sfNumber, 0)); + BEAST_EXPECT(numberFromJson(sfNumber, "-0.000e6") == STNumber(sfNumber, 0)); + + { + NumberRoundModeGuard mg(Number::towards_zero); + // maxint64 9,223,372,036,854,775,807 + auto const maxInt = std::to_string(std::numeric_limits::max()); + // minint64 -9,223,372,036,854,775,808 + auto const minInt = std::to_string(std::numeric_limits::min()); + if (Number::getMantissaScale() == MantissaRange::small) + { + BEAST_EXPECT( + numberFromJson(sfNumber, maxInt) == STNumber(sfNumber, Number{9'223'372'036'854'775, 3})); + BEAST_EXPECT( + numberFromJson(sfNumber, minInt) == STNumber(sfNumber, Number{-9'223'372'036'854'775, 3})); + } + else + { + BEAST_EXPECT( + numberFromJson(sfNumber, maxInt) == STNumber(sfNumber, Number{9'223'372'036'854'775'807, 0})); + BEAST_EXPECT( + numberFromJson(sfNumber, minInt) == + STNumber(sfNumber, Number{true, 9'223'372'036'854'775'808ULL, 0, Number::normalized{}})); + } + } + + constexpr auto imin = std::numeric_limits::min(); + BEAST_EXPECT(numberFromJson(sfNumber, imin) == STNumber(sfNumber, Number(imin, 0))); + BEAST_EXPECT(numberFromJson(sfNumber, std::to_string(imin)) == STNumber(sfNumber, Number(imin, 0))); + + constexpr auto imax = std::numeric_limits::max(); + BEAST_EXPECT(numberFromJson(sfNumber, imax) == STNumber(sfNumber, Number(imax, 0))); + BEAST_EXPECT(numberFromJson(sfNumber, std::to_string(imax)) == STNumber(sfNumber, Number(imax, 0))); + + constexpr auto umax = std::numeric_limits::max(); + BEAST_EXPECT(numberFromJson(sfNumber, umax) == STNumber(sfNumber, Number(umax, 0))); + BEAST_EXPECT(numberFromJson(sfNumber, std::to_string(umax)) == STNumber(sfNumber, Number(umax, 0))); // Obvious non-numbers tested here try @@ -273,15 +252,21 @@ struct STNumber_test : public beast::unit_test::suite } } } + + void + run() override + { + static_assert(!std::is_convertible_v); + + for (auto const scale : {MantissaRange::small, MantissaRange::large}) + { + NumberMantissaScaleGuard sg(scale); + testcase << to_string(Number::getMantissaScale()); + doRun(); + } + } }; -BEAST_DEFINE_TESTSUITE(STNumber, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STNumber, protocol, xrpl); -void -testCompile(std::ostream& out) -{ - STNumber number{sfNumber, 42}; - out << number; -} - -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STObject_test.cpp b/src/test/protocol/STObject_test.cpp index 47a7ab0ad2..861a1ab967 100644 --- a/src/test/protocol/STObject_test.cpp +++ b/src/test/protocol/STObject_test.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { class STObject_test : public beast::unit_test::suite { @@ -32,8 +13,7 @@ public: unexpected(sfGeneric.isUseful(), "sfGeneric must not be useful"); { // Try to put sfGeneric in an SOTemplate. - except( - [&]() { SOTemplate elements{{sfGeneric, soeREQUIRED}}; }); + except([&]() { SOTemplate elements{{sfGeneric, soeREQUIRED}}; }); } unexpected(sfInvalid.isUseful(), "sfInvalid must not be useful"); @@ -51,8 +31,7 @@ public: } { // Try to put sfInvalid in an SOTemplate. - except( - [&]() { SOTemplate elements{{sfInvalid, soeREQUIRED}}; }); + except([&]() { SOTemplate elements{{sfInvalid, soeREQUIRED}}; }); } { // Try to put the same SField into an SOTemplate twice. @@ -82,21 +61,15 @@ public: STObject object1(elements, sfTestObject); STObject object2(object1); - unexpected( - object1.getSerializer() != object2.getSerializer(), - "STObject error 1"); + unexpected(object1.getSerializer() != object2.getSerializer(), "STObject error 1"); - unexpected( - object1.isFieldPresent(sfTestH256) || - !object1.isFieldPresent(sfTestVL), - "STObject error"); + unexpected(object1.isFieldPresent(sfTestH256) || !object1.isFieldPresent(sfTestVL), "STObject error"); object1.makeFieldPresent(sfTestH256); unexpected(!object1.isFieldPresent(sfTestH256), "STObject Error 2"); - unexpected( - object1.getFieldH256(sfTestH256) != uint256(), "STObject error 3"); + unexpected(object1.getFieldH256(sfTestH256) != uint256(), "STObject error 3"); if (object1.getSerializer() == object2.getSerializer()) { @@ -115,9 +88,7 @@ public: unexpected(object1.getFlags() != 0, "STObject error 6"); - unexpected( - object1.getSerializer() != object2.getSerializer(), - "STObject error 7"); + unexpected(object1.getSerializer() != object2.getSerializer(), "STObject error 7"); STObject copy(object1); @@ -125,15 +96,11 @@ public: unexpected(copy.isFieldPresent(sfTestH256), "STObject error 9"); - unexpected( - object1.getSerializer() != copy.getSerializer(), - "STObject error 10"); + unexpected(object1.getSerializer() != copy.getSerializer(), "STObject error 10"); copy.setFieldU32(sfTestU32, 1); - unexpected( - object1.getSerializer() == copy.getSerializer(), - "STObject error 11"); + unexpected(object1.getSerializer() == copy.getSerializer(), "STObject error 11"); for (int i = 0; i < 1000; i++) { @@ -358,11 +325,7 @@ public: { STObject st(sfGeneric); auto const v = ~st[~sf1Outer]; - static_assert( - std::is_same< - std::decay_t, - std::optional>::value, - ""); + static_assert(std::is_same, std::optional>::value, ""); } // UDT scalar fields @@ -416,8 +379,7 @@ public: { STObject st(sfGeneric); BEAST_EXPECT(!st[~sf5]); - auto const kp = generateKeyPair( - KeyType::secp256k1, generateSeed("masterpassphrase")); + auto const kp = generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")); st[sf5] = kp.first; st[~sf5] = std::nullopt; } @@ -437,11 +399,7 @@ public: BEAST_EXPECT(cst[~sf]->size() == 2); BEAST_EXPECT(cst[sf][0] == 1); BEAST_EXPECT(cst[sf][1] == 2); - static_assert( - std::is_same< - decltype(cst[sfIndexes]), - std::vector const&>::value, - ""); + static_assert(std::is_same const&>::value, ""); } // Default by reference field @@ -477,7 +435,7 @@ public: st[sf3] = std::vector{}; BEAST_EXPECT(cst[sf3].size() == 0); } - } // namespace ripple + } // namespace xrpl void testMalformed() @@ -486,8 +444,7 @@ public: try { - std::array const payload{ - {0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}}; + std::array const payload{{0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}}; SerialIter sit{makeSlice(payload)}; auto obj = std::make_shared(sit, sfMetadata); BEAST_EXPECT(!obj); @@ -522,6 +479,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(STObject, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STObject, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STParsedJSON_test.cpp b/src/test/protocol/STParsedJSON_test.cpp index 1e1e1fb9f4..0ef7878cdc 100644 --- a/src/test/protocol/STParsedJSON_test.cpp +++ b/src/test/protocol/STParsedJSON_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { class STParsedJSON_test : public beast::unit_test::suite { @@ -279,9 +260,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfIndexNext)); - BEAST_EXPECT( - obj.object->getFieldU64(sfIndexNext) == - 18446744073709551615ull); + BEAST_EXPECT(obj.object->getFieldU64(sfIndexNext) == 18446744073709551615ull); } // Test min value for uint64 @@ -357,24 +336,8 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfEmailHash)); BEAST_EXPECT(obj.object->getFieldH128(sfEmailHash).size() == 16); std::array expected = { - 0x01, - 0x23, - 0x45, - 0x67, - 0x89, - 0xAB, - 0xCD, - 0xEF, - 0x01, - 0x23, - 0x45, - 0x67, - 0x89, - 0xAB, - 0xCD, - 0xEF}; - BEAST_EXPECT( - obj.object->getFieldH128(sfEmailHash) == uint128{expected}); + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + BEAST_EXPECT(obj.object->getFieldH128(sfEmailHash) == uint128{expected}); } // Valid lowercase hex string for UInt128 @@ -396,8 +359,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfEmailHash)); auto const& h128 = obj.object->getFieldH128(sfEmailHash); BEAST_EXPECT(h128.size() == 16); - bool allZero = std::all_of( - h128.begin(), h128.end(), [](auto b) { return b == 0; }); + bool allZero = std::all_of(h128.begin(), h128.end(), [](auto b) { return b == 0; }); BEAST_EXPECT(allZero); } @@ -460,14 +422,10 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency)); - BEAST_EXPECT( - obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20); - std::array expected = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, - 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67}; - BEAST_EXPECT( - obj.object->getFieldH160(sfTakerPaysCurrency) == - uint160{expected}); + BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20); + std::array expected = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67}; + BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency) == uint160{expected}); } // Valid lowercase hex string for UInt160 { @@ -476,8 +434,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency)); - BEAST_EXPECT( - obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20); + BEAST_EXPECT(obj.object->getFieldH160(sfTakerPaysCurrency).size() == 20); } // Empty string for UInt160 (should be valid, all zero) @@ -489,8 +446,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfTakerPaysCurrency)); auto const& h160 = obj.object->getFieldH160(sfTakerPaysCurrency); BEAST_EXPECT(h160.size() == 20); - bool allZero = std::all_of( - h160.begin(), h160.end(), [](auto b) { return b == 0; }); + bool allZero = std::all_of(h160.begin(), h160.end(), [](auto b) { return b == 0; }); BEAST_EXPECT(allZero); } @@ -513,8 +469,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Hex string too long for UInt160 (should fail) { Json::Value j; - j[sfTakerPaysCurrency] = - "0123456789ABCDEF0123456789ABCDEF0123456789"; + j[sfTakerPaysCurrency] = "0123456789ABCDEF0123456789ABCDEF0123456789"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -542,32 +497,24 @@ class STParsedJSON_test : public beast::unit_test::suite testcase("UInt192"); { Json::Value j; - j[sfMPTokenIssuanceID] = - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + j[sfMPTokenIssuanceID] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID)); - BEAST_EXPECT( - obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24); - std::array expected = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - BEAST_EXPECT( - obj.object->getFieldH192(sfMPTokenIssuanceID) == - uint192{expected}); + BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24); + std::array expected = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID) == uint192{expected}); } // Valid lowercase hex string for UInt192 { Json::Value j; - j[sfMPTokenIssuanceID] = - "ffffffffffffffffffffffffffffffffffffffffffffffff"; + j[sfMPTokenIssuanceID] = "ffffffffffffffffffffffffffffffffffffffffffffffff"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID)); - BEAST_EXPECT( - obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24); + BEAST_EXPECT(obj.object->getFieldH192(sfMPTokenIssuanceID).size() == 24); } // Empty string for UInt192 (should be valid, all zero) @@ -579,16 +526,14 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfMPTokenIssuanceID)); auto const& h192 = obj.object->getFieldH192(sfMPTokenIssuanceID); BEAST_EXPECT(h192.size() == 24); - bool allZero = std::all_of( - h192.begin(), h192.end(), [](auto b) { return b == 0; }); + bool allZero = std::all_of(h192.begin(), h192.end(), [](auto b) { return b == 0; }); BEAST_EXPECT(allZero); } // Odd-length hex string for UInt192 (should fail) { Json::Value j; - j[sfMPTokenIssuanceID] = - "0123456789ABCDEF0123456789ABCDEF0123456789ABCDE"; + j[sfMPTokenIssuanceID] = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDE"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -612,8 +557,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Hex string too long for UInt192 (should fail) { Json::Value j; - j[sfMPTokenIssuanceID] = - "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF00"; + j[sfMPTokenIssuanceID] = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF00"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -649,13 +593,10 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerHash)); BEAST_EXPECT(obj.object->getFieldH256(sfLedgerHash).size() == 32); - std::array expected = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - BEAST_EXPECT( - obj.object->getFieldH256(sfLedgerHash) == uint256{expected}); + std::array expected = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, + 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + BEAST_EXPECT(obj.object->getFieldH256(sfLedgerHash) == uint256{expected}); } // Valid lowercase hex string for UInt256 { @@ -678,8 +619,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfLedgerHash)); auto const& h256 = obj.object->getFieldH256(sfLedgerHash); BEAST_EXPECT(h256.size() == 32); - bool allZero = std::all_of( - h256.begin(), h256.end(), [](auto b) { return b == 0; }); + bool allZero = std::all_of(h256.begin(), h256.end(), [](auto b) { return b == 0; }); BEAST_EXPECT(allZero); } @@ -743,63 +683,60 @@ class STParsedJSON_test : public beast::unit_test::suite { Json::Value j; int const minInt32 = -2147483648; - j[sfDummyInt32] = minInt32; + j[sfLoanScale] = minInt32; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); - if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32))) - BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == minInt32); + if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale))) + BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == minInt32); } // max value { Json::Value j; int const maxInt32 = 2147483647; - j[sfDummyInt32] = maxInt32; + j[sfLoanScale] = maxInt32; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); - if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32))) - BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == maxInt32); + if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale))) + BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == maxInt32); } // max uint value { Json::Value j; unsigned int const maxUInt32 = 2147483647u; - j[sfDummyInt32] = maxUInt32; + j[sfLoanScale] = maxUInt32; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); - if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32))) - BEAST_EXPECT( - obj.object->getFieldI32(sfDummyInt32) == - static_cast(maxUInt32)); + if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale))) + BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == static_cast(maxUInt32)); } // Test with string value { Json::Value j; - j[sfDummyInt32] = "2147483647"; + j[sfLoanScale] = "2147483647"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); - if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32))) - BEAST_EXPECT( - obj.object->getFieldI32(sfDummyInt32) == 2147483647u); + if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale))) + BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == 2147483647u); } // Test with string negative value { Json::Value j; int value = -2147483648; - j[sfDummyInt32] = std::to_string(value); + j[sfLoanScale] = std::to_string(value); STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); - if (BEAST_EXPECT(obj.object->isFieldPresent(sfDummyInt32))) - BEAST_EXPECT(obj.object->getFieldI32(sfDummyInt32) == value); + if (BEAST_EXPECT(obj.object->isFieldPresent(sfLoanScale))) + BEAST_EXPECT(obj.object->getFieldI32(sfLoanScale) == value); } // Test out of range value for int32 (negative) { Json::Value j; - j[sfDummyInt32] = "-2147483649"; + j[sfLoanScale] = "-2147483649"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -807,7 +744,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Test out of range value for int32 (positive) { Json::Value j; - j[sfDummyInt32] = 2147483648u; + j[sfLoanScale] = 2147483648u; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -815,7 +752,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Test string value out of range { Json::Value j; - j[sfDummyInt32] = "2147483648"; + j[sfLoanScale] = "2147483648"; STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -823,7 +760,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Test bad_type (arrayValue) { Json::Value j; - j[sfDummyInt32] = Json::Value(Json::arrayValue); + j[sfLoanScale] = Json::Value(Json::arrayValue); STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -831,7 +768,7 @@ class STParsedJSON_test : public beast::unit_test::suite // Test bad_type (objectValue) { Json::Value j; - j[sfDummyInt32] = Json::Value(Json::objectValue); + j[sfLoanScale] = Json::Value(Json::objectValue); STParsedJSONObject obj("Test", j); BEAST_EXPECT(!obj.object.has_value()); } @@ -1006,8 +943,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfAccount)); auto const& acct = obj.object->getAccountID(sfAccount); BEAST_EXPECT(acct.size() == 20); - BEAST_EXPECT( - toBase58(acct) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"); + BEAST_EXPECT(toBase58(acct) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"); } // Valid hex string for AccountID @@ -1191,9 +1127,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfAmount)); - BEAST_EXPECT( - obj.object->getFieldAmount(sfAmount) == - STAmount(100000000000000000ull)); + BEAST_EXPECT(obj.object->getFieldAmount(sfAmount) == STAmount(100000000000000000ull)); } // Test with int value for Amount @@ -1203,8 +1137,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfAmount)); - BEAST_EXPECT( - obj.object->getFieldAmount(sfAmount) == STAmount(4294967295u)); + BEAST_EXPECT(obj.object->getFieldAmount(sfAmount) == STAmount(4294967295u)); } // Test with decimal string for Amount (should fail) @@ -1264,15 +1197,9 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!ps.empty()); BEAST_EXPECT(ps.size() == 1); BEAST_EXPECT(ps[0].size() == 1); - BEAST_EXPECT( - ps[0][0].getAccountID() == - parseBase58( - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")); + BEAST_EXPECT(ps[0][0].getAccountID() == parseBase58("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")); BEAST_EXPECT(to_string(ps[0][0].getCurrency()) == "USD"); - BEAST_EXPECT( - ps[0][0].getIssuerID() == - parseBase58( - "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe")); + BEAST_EXPECT(ps[0][0].getIssuerID() == parseBase58("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe")); } } @@ -1447,10 +1374,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(issue.currency.size() == 20); BEAST_EXPECT(to_string(issue.currency) == "USD"); BEAST_EXPECT(issue.account.size() == 20); - BEAST_EXPECT( - issue.account == - parseBase58( - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")); + BEAST_EXPECT(issue.account == parseBase58("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")); } } @@ -1476,8 +1400,7 @@ class STParsedJSON_test : public beast::unit_test::suite { Json::Value j; Json::Value issueJson(Json::objectValue); - issueJson["mpt_issuance_id"] = - "0000000000000000000000004D5054494431323334234234"; + issueJson["mpt_issuance_id"] = "0000000000000000000000004D5054494431323334234234"; j[sfAsset] = issueJson; STParsedJSONObject obj("Test", j); if (BEAST_EXPECT(obj.object.has_value())) @@ -1586,10 +1509,8 @@ class STParsedJSON_test : public beast::unit_test::suite { BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge)); auto const& bridgeField = (*obj.object)[sfXChainBridge]; - BEAST_EXPECT( - bridgeField->lockingChainIssue().currency.size() == 20); - BEAST_EXPECT( - bridgeField->issuingChainIssue().currency.size() == 20); + BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20); + BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20); } } @@ -1598,12 +1519,10 @@ class STParsedJSON_test : public beast::unit_test::suite Json::Value j; Json::Value bridge(Json::objectValue); Json::Value issuingChainIssue(Json::objectValue); - issuingChainIssue["currency"] = - "0123456789ABCDEF01230123456789ABCDEF0123"; + issuingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123"; issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; Json::Value lockingChainIssue(Json::objectValue); - lockingChainIssue["currency"] = - "0123456789ABCDEF01230123456789ABCDEF0123"; + lockingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123"; lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; bridge["LockingChainIssue"] = lockingChainIssue; bridge["IssuingChainIssue"] = issuingChainIssue; @@ -1615,10 +1534,8 @@ class STParsedJSON_test : public beast::unit_test::suite { BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge)); auto const& bridgeField = (*obj.object)[sfXChainBridge]; - BEAST_EXPECT( - bridgeField->lockingChainIssue().currency.size() == 20); - BEAST_EXPECT( - bridgeField->issuingChainIssue().currency.size() == 20); + BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20); + BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20); } } @@ -1768,9 +1685,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == - Number(12345, 0)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(12345, 0)); } // Valid uint value for STNumber @@ -1780,9 +1695,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == - Number(12345, 0)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(12345, 0)); } // Valid string integer value for STNumber @@ -1792,9 +1705,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == - Number(67890, 0)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(67890, 0)); } // Valid negative integer value for STNumber @@ -1804,8 +1715,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == Number(-42, 0)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(-42, 0)); } // Valid string negative integer value for STNumber @@ -1815,9 +1725,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == - Number(-123, 0)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(-123, 0)); } // Valid floating point value for STNumber @@ -1828,9 +1736,7 @@ class STParsedJSON_test : public beast::unit_test::suite if (BEAST_EXPECT(obj.object.has_value())) { BEAST_EXPECT(obj.object->isFieldPresent(sfNumber)); - BEAST_EXPECT( - obj.object->getFieldNumber(sfNumber).value() == - Number(314159, -5)); + BEAST_EXPECT(obj.object->getFieldNumber(sfNumber).value() == Number(314159, -5)); } } @@ -1880,8 +1786,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject obj("Test", j); BEAST_EXPECT(obj.object.has_value()); BEAST_EXPECT(obj.object->isFieldPresent(sfTransactionMetaData)); - auto const& result = - obj.object->peekFieldObject(sfTransactionMetaData); + auto const& result = obj.object->peekFieldObject(sfTransactionMetaData); BEAST_EXPECT(result.getFieldU8(sfTransactionResult) == 1); } @@ -2082,8 +1987,7 @@ class STParsedJSON_test : public beast::unit_test::suite catch (std::runtime_error& e) { std::string what(e.what()); - unexpected( - what.find("First level children of `Template`") != 0); + unexpected(what.find("First level children of `Template`") != 0); } } } @@ -2108,20 +2012,17 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject parsed("test", jv); if (BEAST_EXPECT(parsed.object)) { - std::string const& serialized( - to_string(parsed.object->getJson(JsonOptions::none))); + std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none))); BEAST_EXPECT(serialized == goodJson); } } } { - std::string const goodJson( - R"({"CloseResolution":19,"Method":"250",)" - R"("TransactionResult":"tecFROZEN"})"); - std::string const expectedJson( - R"({"CloseResolution":19,"Method":250,)" - R"("TransactionResult":"tecFROZEN"})"); + std::string const goodJson(R"({"CloseResolution":19,"Method":"250",)" + R"("TransactionResult":"tecFROZEN"})"); + std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)" + R"("TransactionResult":"tecFROZEN"})"); Json::Value jv; if (BEAST_EXPECT(parseJSONString(goodJson, jv))) @@ -2132,20 +2033,17 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject parsed("test", jv); if (BEAST_EXPECT(parsed.object)) { - std::string const& serialized( - to_string(parsed.object->getJson(JsonOptions::none))); + std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none))); BEAST_EXPECT(serialized == expectedJson); } } } { - std::string const goodJson( - R"({"CloseResolution":"19","Method":"250",)" - R"("TransactionResult":"tecFROZEN"})"); - std::string const expectedJson( - R"({"CloseResolution":19,"Method":250,)" - R"("TransactionResult":"tecFROZEN"})"); + std::string const goodJson(R"({"CloseResolution":"19","Method":"250",)" + R"("TransactionResult":"tecFROZEN"})"); + std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)" + R"("TransactionResult":"tecFROZEN"})"); Json::Value jv; if (BEAST_EXPECT(parseJSONString(goodJson, jv))) @@ -2156,8 +2054,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject parsed("test", jv); if (BEAST_EXPECT(parsed.object)) { - std::string const& serialized( - to_string(parsed.object->getJson(JsonOptions::none))); + std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none))); BEAST_EXPECT(serialized == expectedJson); } } @@ -2174,9 +2071,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.TransactionResult' is out of range."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransactionResult' is out of range."); } } @@ -2191,16 +2086,13 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.Method' has bad type."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' has bad type."); } } { - std::string const json( - R"({"CloseResolution":19,"Method":3294967296,)" - R"("TransactionResult":"tesSUCCESS"})"); + std::string const json(R"({"CloseResolution":19,"Method":3294967296,)" + R"("TransactionResult":"tesSUCCESS"})"); Json::Value jv; if (BEAST_EXPECT(parseJSONString(json, jv))) @@ -2209,9 +2101,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.Method' is out of range."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' is out of range."); } } @@ -2226,16 +2116,13 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.CloseResolution' is out of range."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.CloseResolution' is out of range."); } } { - std::string const json( - R"({"CloseResolution":19,"Method":3.141592653,)" - R"("TransactionResult":"tesSUCCESS"})"); + std::string const json(R"({"CloseResolution":19,"Method":3.141592653,)" + R"("TransactionResult":"tesSUCCESS"})"); Json::Value jv; if (BEAST_EXPECT(parseJSONString(json, jv))) @@ -2244,18 +2131,15 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.Method' has bad type."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.Method' has bad type."); } } { std::string const goodJson(R"({"CloseResolution":19,"Method":250,)" R"("TransferFee":"65535"})"); - std::string const expectedJson( - R"({"CloseResolution":19,"Method":250,)" - R"("TransferFee":65535})"); + std::string const expectedJson(R"({"CloseResolution":19,"Method":250,)" + R"("TransferFee":65535})"); Json::Value jv; if (BEAST_EXPECT(parseJSONString(goodJson, jv))) @@ -2263,8 +2147,7 @@ class STParsedJSON_test : public beast::unit_test::suite STParsedJSONObject parsed("test", jv); if (BEAST_EXPECT(parsed.object)) { - std::string const& serialized( - to_string(parsed.object->getJson(JsonOptions::none))); + std::string const& serialized(to_string(parsed.object->getJson(JsonOptions::none))); BEAST_EXPECT(serialized == expectedJson); } } @@ -2281,9 +2164,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.TransferFee' has invalid data."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has invalid data."); } } @@ -2298,9 +2179,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.TransferFee' has invalid data."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has invalid data."); } } @@ -2315,9 +2194,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(!parsed.object); BEAST_EXPECT(parsed.error); BEAST_EXPECT(parsed.error[jss::error] == "invalidParams"); - BEAST_EXPECT( - parsed.error[jss::error_message] == - "Field 'test.TransferFee' has bad type."); + BEAST_EXPECT(parsed.error[jss::error_message] == "Field 'test.TransferFee' has bad type."); } } } @@ -2351,6 +2228,6 @@ class STParsedJSON_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(STParsedJSON, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STParsedJSON, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STTx_test.cpp b/src/test/protocol/STTx_test.cpp index eaa7a15212..853ff35635 100644 --- a/src/test/protocol/STTx_test.cpp +++ b/src/test/protocol/STTx_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,7 +11,7 @@ #include -namespace ripple { +namespace xrpl { /** * Return true if the string loosely matches the regex. @@ -40,8 +21,7 @@ namespace ripple { inline bool matches(char const* string, char const* regex) { - return std::regex_search( - string, std::basic_regex(regex, std::regex_constants::icase)); + return std::regex_search(string, std::basic_regex(regex, std::regex_constants::icase)); } class STTx_test : public beast::unit_test::suite @@ -67,1323 +47,814 @@ public: { testcase("Malformed serialized form"); - constexpr unsigned char payload1[] = { - 0x0a, 0xff, 0xff, 0xff, 0xff, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x29, 0x1b, 0x1b, 0x1b, 0x1b, 0xef, 0xef, 0xef, - 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef}; + constexpr unsigned char payload1[] = {0x0a, 0xff, 0xff, 0xff, 0xff, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x29, 0x1b, 0x1b, 0x1b, 0x1b, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef}; constexpr unsigned char payload2[] = { - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, - 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, - 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, - 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, - 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, - 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, - 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, - 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, - 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, - 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, - 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, - 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, - 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, - 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, - 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, - 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, - 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, - 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, - 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, - 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, - 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0x3b, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, - 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, - 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, - 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, - 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, - 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, - 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, - 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, - 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, - 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, - 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, - 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, - 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, - 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xe7, 0x27, - 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, - 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, - 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, - 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, - 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, - 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, - 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, - 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, - 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x14, - 0x14, 0x14, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, - 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xe7, 0x27, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xda, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, - 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, - 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, - 0x3b, 0x3b, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, - 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, - 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, - 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, - 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, - 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0x29, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, - 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, - 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xef, 0xff, - 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, - 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, - 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, - 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, - 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, - 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, - 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, - 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, - 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, - 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0xff, 0xef, - 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x7f, - 0x3b, 0x3b, 0xef, 0xfd, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xfb, 0xef, - 0xfd, 0xf1, 0xff, 0xf1, 0xfd, 0xf1, 0xfb, 0xf1, 0xfd, 0xf1, 0xef, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0xff, 0xef, 0xff, 0x01, 0x00, 0xfd, 0xf1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, - 0xef, 0x3b, 0x3b, 0x43, 0x3b, 0x3b, 0xff, 0x3b, 0x12, 0xf1, 0x12, - 0x12, 0x12, 0xff}; + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, + 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, + 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, + 0x26, 0xdf, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, + 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, + 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, + 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, + 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, + 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, + 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, + 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, + 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, + 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, + 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, + 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, + 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xe7, 0x27, 0xdf, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, + 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, + 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, + 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, + 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, + 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, + 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, + 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, + 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, + 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, + 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, + 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, + 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, + 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, + 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x14, 0x14, 0x14, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, + 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, + 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, + 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, + 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xda, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, + 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, + 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, + 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0x29, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, + 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, + 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, + 0xe7, 0x12, 0x12, 0x12, 0x12, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, + 0x3b, 0x27, 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0x29, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xef, + 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, + 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, + 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xf4, 0xef, 0x3b, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3b, 0x3b, + 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, + 0xdf, 0xff, 0x3b, 0x3b, 0x3b, 0x3b, 0x29, 0x2b, 0x3b, 0x18, 0x3b, 0x3b, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0x3b, 0x3b, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, + 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xff, 0xe7, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, + 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x26, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xec, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, + 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, + 0xff, 0xef, 0xff, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3b, 0x3b, 0x3b, 0x27, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xe7, 0x3b, 0x3b, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0xff, + 0xef, 0xef, 0xff, 0xef, 0xef, 0xff, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x7f, 0x3b, 0x3b, 0xef, 0xfd, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xfb, 0xef, 0xfd, 0xf1, 0xff, 0xf1, 0xfd, + 0xf1, 0xfb, 0xf1, 0xfd, 0xf1, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0x01, 0x00, 0xfd, 0xf1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xef, 0xff, 0xef, 0xff, 0xef, 0x3b, 0x3b, 0x43, + 0x3b, 0x3b, 0xff, 0x3b, 0x12, 0xf1, 0x12, 0x12, 0x12, 0xff}; constexpr unsigned char payload3[] = { - 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, - 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, - 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x1e, 0x00, 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, - 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x24, 0x59, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x54, 0x72, 0x61, 0x6e, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, 0xf6, - 0x00, 0x00, 0x03, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, - 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, - 0x10, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; + 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, + 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x4f, 0x00, + 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x24, 0x59, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x54, 0x72, 0x61, 0x6e, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, + 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, 0xf6, + 0x00, 0x00, 0x03, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x73, + 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; constexpr unsigned char payload4[] = { - 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, - 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, - 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x1e, 0x00, 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, - 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x24, 0x59, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x54, 0x72, 0x61, 0x6e, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, - 0xf6, 0x00, 0x00, 0x03, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, - 0x00, 0x10, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; + 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, + 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, + 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x4f, + 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x24, 0x59, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x54, 0x72, 0x61, 0x6e, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, + 0xf6, 0x00, 0x00, 0x03, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, + 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; // Construct an STObject with 11 levels of object nesting so the // maximum nesting level exception is thrown. @@ -1398,14 +869,12 @@ public: // Make an STObject that nests objects ten levels deep. There's // a minimum transaction size we must meet, so include a hash256. uint256 const hash{42u}; - auto inner = - std::make_unique(recurse, sfTransactionMetaData); + auto inner = std::make_unique(recurse, sfTransactionMetaData); inner->setFieldH256(sfTransactionHash, hash); for (int i = 1; i < 10; ++i) { - auto outer = - std::make_unique(recurse, sfTransactionMetaData); + auto outer = std::make_unique(recurse, sfTransactionMetaData); outer->set(std::move(inner)); outer->setFieldH256(sfTransactionHash, hash); inner = std::move(outer); @@ -1417,7 +886,7 @@ public: SerialIter tenSit{tenDeep.slice()}; try { - auto stx = std::make_shared(tenSit); + auto stx = std::make_shared(tenSit); fail("STTx construction should have thrown."); } catch (std::runtime_error const& ex) @@ -1436,15 +905,12 @@ public: SerialIter tooDeepSit{tooDeep.slice()}; try { - auto stx = std::make_shared(tooDeepSit); + auto stx = std::make_shared(tooDeepSit); fail("STTx construction should have thrown."); } catch (std::runtime_error const& ex) { - BEAST_EXPECT( - std::strcmp( - ex.what(), "Maximum nesting depth of STVar exceeded") == - 0); + BEAST_EXPECT(std::strcmp(ex.what(), "Maximum nesting depth of STVar exceeded") == 0); } } { @@ -1482,7 +948,7 @@ public: SerialIter nineSit{nineDeep.slice()}; try { - auto stx = std::make_shared(nineSit); + auto stx = std::make_shared(nineSit); fail("STTx construction should have thrown."); } catch (std::runtime_error const& ex) @@ -1502,15 +968,12 @@ public: SerialIter tooDeepSit{tooDeep.slice()}; try { - auto stx = std::make_shared(tooDeepSit); + auto stx = std::make_shared(tooDeepSit); fail("STTx construction should have thrown."); } catch (std::runtime_error const& ex) { - BEAST_EXPECT( - std::strcmp( - ex.what(), "Maximum nesting depth of STVar exceeded") == - 0); + BEAST_EXPECT(std::strcmp(ex.what(), "Maximum nesting depth of STVar exceeded") == 0); } } @@ -1531,7 +994,7 @@ public: { // Verify we have a valid transaction. SerialIter sit{serialized.slice()}; - auto stx = std::make_shared(sit); + auto stx = std::make_shared(sit); } // Tweak the serialized data to change the ClearFlag to @@ -1543,13 +1006,12 @@ public: SerialIter sit{serialized.slice()}; try { - auto stx = std::make_shared(sit); + auto stx = std::make_shared(sit); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp(ex.what(), "Duplicate field detected") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Duplicate field detected") == 0); } } @@ -1570,9 +1032,9 @@ public: // vary. BEAST_EXPECT(!tx2.ParseFromArray(payload1, sizeof(payload1))); - ripple::SerialIter sit(ripple::makeSlice(tx2.rawtransaction())); + xrpl::SerialIter sit(xrpl::makeSlice(tx2.rawtransaction())); - auto stx = std::make_shared(sit); + auto stx = std::make_shared(sit); fail("An exception should have been thrown"); } catch (std::exception const&) @@ -1582,8 +1044,8 @@ public: try { - ripple::SerialIter sit{payload2}; - auto stx = std::make_shared(sit); + xrpl::SerialIter sit{payload2}; + auto stx = std::make_shared(sit); fail("An exception should have been thrown"); } catch (std::exception const& ex) @@ -1593,20 +1055,19 @@ public: try { - ripple::SerialIter sit{payload3}; - auto stx = std::make_shared(sit); + xrpl::SerialIter sit{payload3}; + auto stx = std::make_shared(sit); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp(ex.what(), "gFID: uncommon name out of range 0") == 0); + BEAST_EXPECT(strcmp(ex.what(), "gFID: uncommon name out of range 0") == 0); } try { - ripple::SerialIter sit{payload4}; - auto stx = std::make_shared(sit); + xrpl::SerialIter sit{payload4}; + auto stx = std::make_shared(sit); fail("An exception should have been thrown"); } catch (std::exception const& ex) @@ -1631,11 +1092,9 @@ public: // proper lifetime. std::unordered_set> const presets; Rules const defaultRules{presets}; - BEAST_EXPECT(!defaultRules.enabled(featureExpandedSignerList)); + BEAST_EXPECT(!defaultRules.enabled(featureAMM)); - unexpected( - !j.checkSign(STTx::RequireFullyCanonicalSig::yes, defaultRules), - "Transaction fails signature test"); + unexpected(!j.checkSign(defaultRules), "Transaction fails signature test"); Serializer rawTxn; j.add(rawTxn); @@ -1660,8 +1119,7 @@ public: if (STObject(j) != parsed.object) { log << "ORIG: " << j.getJson(JsonOptions::none) << '\n' - << "BUILT " << parsed.object->getJson(JsonOptions::none) - << std::endl; + << "BUILT " << parsed.object->getJson(JsonOptions::none) << std::endl; fail("Built a different transaction"); } else @@ -1689,8 +1147,7 @@ public: payment.setFieldAmount(sfAmount, STAmount(10000000000ull)); payment.setFieldAmount(sfFee, STAmount(10ull)); payment.setFieldU32(sfSequence, 1); - payment.setFieldVL( - sfSigningPubKey, Slice(kp1.first.data(), kp1.first.size())); + payment.setFieldVL(sfSigningPubKey, Slice(kp1.first.data(), kp1.first.size())); return payment; }; { @@ -1720,8 +1177,7 @@ public: { got = err.what(); } - BEAST_EXPECT( - got == "Field 'Paths' may not be explicitly set to default."); + BEAST_EXPECT(got == "Field 'Paths' may not be explicitly set to default."); } { // Make a Payment with an extra "SignerWeight" field. @@ -1737,8 +1193,7 @@ public: { got = err.what(); } - BEAST_EXPECT( - got == "Field 'SignerWeight' found in disallowed location."); + BEAST_EXPECT(got == "Field 'SignerWeight' found in disallowed location."); } { // Make a Payment that is missing the required Fee field. @@ -1796,31 +1251,30 @@ public: // the bad ones. // This lambda contains the bulk of the test code. - auto testMalformedSigningAccount = - [this, &txn](STObject const& signer, bool expectPass) { - // Create SigningAccounts array. - STArray signers(sfSigners, 1); - signers.push_back(signer); + auto testMalformedSigningAccount = [this, &txn](STObject const& signer, bool expectPass) { + // Create SigningAccounts array. + STArray signers(sfSigners, 1); + signers.push_back(signer); - // Insert signers into transaction. - STTx tempTxn(txn); - tempTxn.setFieldArray(sfSigners, signers); + // Insert signers into transaction. + STTx tempTxn(txn); + tempTxn.setFieldArray(sfSigners, signers); - Serializer rawTxn; - tempTxn.add(rawTxn); - SerialIter sit(rawTxn.slice()); - bool serialized = false; - try - { - STTx copy(sit); - serialized = true; - } - catch (std::exception const&) - { - ; // If it threw then serialization failed. - } - BEAST_EXPECT(serialized == expectPass); - }; + Serializer rawTxn; + tempTxn.add(rawTxn); + SerialIter sit(rawTxn.slice()); + bool serialized = false; + try + { + STTx copy(sit); + serialized = true; + } + catch (std::exception const&) + { + ; // If it threw then serialization failed. + } + BEAST_EXPECT(serialized == expectPass); + }; { // Test case 1. Make a valid Signer object. @@ -1857,7 +1311,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(STTx, protocol, ripple); -BEAST_DEFINE_TESTSUITE(InnerObjectFormatsSerializer, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STTx, protocol, xrpl); +BEAST_DEFINE_TESTSUITE(InnerObjectFormatsSerializer, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/STValidation_test.cpp b/src/test/protocol/STValidation_test.cpp index 784fc43c24..0c0951fde2 100644 --- a/src/test/protocol/STValidation_test.cpp +++ b/src/test/protocol/STValidation_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,152 +8,115 @@ #include #include -namespace ripple { +namespace xrpl { class STValidation_test : public beast::unit_test::suite { // No public key: static constexpr std::uint8_t payload1[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x3A, 0x4E, 0x69, 0x6B, 0x2B, 0x54, 0x69, 0x66, 0x66, - 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, - 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, - 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, - 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, - 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, - 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x76, 0x47, 0x30, 0x45, 0x02, - 0x21, 0x00, 0xAF, 0x1D, 0x17, 0xA2, 0x12, 0x7B, 0xA4, 0x6B, 0x40, 0xBD, - 0x58, 0x76, 0x39, 0x3F, 0xF4, 0x49, 0x6B, 0x25, 0xA1, 0xAD, 0xB7, 0x36, - 0xFB, 0x64, 0x4C, 0x05, 0x21, 0x0C, 0x43, 0x02, 0xE5, 0xEE, 0x02, 0x20, - 0x26, 0x01, 0x7C, 0x5F, 0x69, 0xDA, 0xD1, 0xC3, 0x28, 0xED, 0x80, 0x05, - 0x36, 0x86, 0x8B, 0x1B, 0x22, 0xE4, 0x8E, 0x09, 0x11, 0x52, 0x28, 0x5A, - 0x48, 0x8F, 0x98, 0x7A, 0x5A, 0x10, 0x74, 0xCC}; + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x3A, 0x4E, + 0x69, 0x6B, 0x2B, 0x54, 0x69, 0x66, 0x66, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, + 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, + 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, + 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, 0xD9, + 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xAF, 0x1D, 0x17, 0xA2, + 0x12, 0x7B, 0xA4, 0x6B, 0x40, 0xBD, 0x58, 0x76, 0x39, 0x3F, 0xF4, 0x49, 0x6B, 0x25, 0xA1, 0xAD, 0xB7, + 0x36, 0xFB, 0x64, 0x4C, 0x05, 0x21, 0x0C, 0x43, 0x02, 0xE5, 0xEE, 0x02, 0x20, 0x26, 0x01, 0x7C, 0x5F, + 0x69, 0xDA, 0xD1, 0xC3, 0x28, 0xED, 0x80, 0x05, 0x36, 0x86, 0x8B, 0x1B, 0x22, 0xE4, 0x8E, 0x09, 0x11, + 0x52, 0x28, 0x5A, 0x48, 0x8F, 0x98, 0x7A, 0x5A, 0x10, 0x74, 0xCC}; // Short public key: static constexpr std::uint8_t payload2[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, - 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, - 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, - 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, - 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, - 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x20, - 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, - 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, - 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x76, 0x46, 0x30, 0x44, - 0x02, 0x20, 0x34, 0x89, 0xA3, 0xBF, 0xA9, 0x97, 0x13, 0xBC, 0x87, 0x61, - 0xC5, 0x2B, 0x7F, 0xAA, 0xE9, 0x31, 0x4C, 0xCD, 0x6F, 0x57, 0x68, 0x70, - 0xC8, 0xDC, 0x58, 0x76, 0x91, 0x2F, 0x70, 0x2F, 0xD0, 0x78, 0x02, 0x20, - 0x7E, 0x57, 0x9D, 0xCA, 0x11, 0xF1, 0x3B, 0xA0, 0x39, 0x38, 0x37, 0x40, - 0xC5, 0xC8, 0xFE, 0xC1, 0xFC, 0xE9, 0xE7, 0x84, 0x6C, 0x2D, 0x47, 0x6E, + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, + 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, + 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, + 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, + 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x20, 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, + 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, + 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x76, 0x46, 0x30, 0x44, 0x02, 0x20, 0x34, 0x89, 0xA3, 0xBF, + 0xA9, 0x97, 0x13, 0xBC, 0x87, 0x61, 0xC5, 0x2B, 0x7F, 0xAA, 0xE9, 0x31, 0x4C, 0xCD, 0x6F, 0x57, 0x68, 0x70, + 0xC8, 0xDC, 0x58, 0x76, 0x91, 0x2F, 0x70, 0x2F, 0xD0, 0x78, 0x02, 0x20, 0x7E, 0x57, 0x9D, 0xCA, 0x11, 0xF1, + 0x3B, 0xA0, 0x39, 0x38, 0x37, 0x40, 0xC5, 0xC8, 0xFE, 0xC1, 0xFC, 0xE9, 0xE7, 0x84, 0x6C, 0x2D, 0x47, 0x6E, 0xD7, 0xFF, 0x83, 0x9D, 0xEF, 0x7D, 0xF7, 0x6A}; // Long public key: static constexpr std::uint8_t payload3[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, - 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, - 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, - 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, - 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, - 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x22, - 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, - 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, - 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x78, 0x76, 0x46, - 0x30, 0x44, 0x02, 0x20, 0x3C, 0xAB, 0xEE, 0x36, 0xD8, 0xF3, 0x74, 0x5F, - 0x50, 0x28, 0x66, 0x17, 0x57, 0x26, 0x6A, 0xBD, 0x9A, 0x19, 0x08, 0xAA, - 0x65, 0x94, 0x0B, 0xDF, 0x24, 0x20, 0x44, 0x99, 0x05, 0x8C, 0xB7, 0x3D, - 0x02, 0x20, 0x79, 0x66, 0xE6, 0xCC, 0xA2, 0x5E, 0x15, 0xFE, 0x18, 0x4B, - 0xB2, 0xA8, 0x01, 0x3A, 0xD6, 0x63, 0x54, 0x08, 0x1B, 0xDA, 0xD0, 0x04, + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, + 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, + 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, + 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, + 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x22, 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, + 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, + 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x78, 0x76, 0x46, 0x30, 0x44, 0x02, 0x20, 0x3C, 0xAB, + 0xEE, 0x36, 0xD8, 0xF3, 0x74, 0x5F, 0x50, 0x28, 0x66, 0x17, 0x57, 0x26, 0x6A, 0xBD, 0x9A, 0x19, 0x08, 0xAA, + 0x65, 0x94, 0x0B, 0xDF, 0x24, 0x20, 0x44, 0x99, 0x05, 0x8C, 0xB7, 0x3D, 0x02, 0x20, 0x79, 0x66, 0xE6, 0xCC, + 0xA2, 0x5E, 0x15, 0xFE, 0x18, 0x4B, 0xB2, 0xA8, 0x01, 0x3A, 0xD6, 0x63, 0x54, 0x08, 0x1B, 0xDA, 0xD0, 0x04, 0xEF, 0x4C, 0x73, 0xB3, 0xFF, 0xFE, 0xA9, 0x8E, 0x92, 0xE8}; // Ed25519 public key: static constexpr std::uint8_t payload4[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, - 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, - 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, - 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, - 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, - 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, - 0xED, 0x04, 0x8B, 0x9A, 0x31, 0x5E, 0xC7, 0x33, 0xC0, 0x15, 0x3B, 0x67, - 0x04, 0x73, 0x7A, 0x91, 0x3D, 0xEF, 0x57, 0x1D, 0xAD, 0xEC, 0x57, 0xE5, - 0x91, 0x5D, 0x55, 0xD9, 0x32, 0x9D, 0x45, 0x12, 0x85, 0x76, 0x40, 0x52, - 0x07, 0xF9, 0x0D, 0x18, 0x2B, 0xB7, 0xAF, 0x5D, 0x43, 0xF8, 0xF9, 0xC5, - 0xAD, 0xF9, 0xBA, 0x33, 0x23, 0xC0, 0x2F, 0x95, 0xFF, 0x36, 0x94, 0xD8, - 0x99, 0x99, 0xE0, 0x66, 0xF8, 0xB6, 0x27, 0x22, 0xFD, 0x29, 0x39, 0x30, - 0x39, 0xAB, 0x93, 0xDB, 0x9D, 0x2C, 0xE5, 0xF0, 0x4C, 0xB7, 0x30, 0xFD, - 0xC7, 0xD3, 0x21, 0xC9, 0x4E, 0x0D, 0x8A, 0x1B, 0xB2, 0x89, 0x97, 0x10, - 0x7E, 0x84, 0x09}; + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, + 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, + 0x4B, 0x40, 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, + 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, + 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0xED, + 0x04, 0x8B, 0x9A, 0x31, 0x5E, 0xC7, 0x33, 0xC0, 0x15, 0x3B, 0x67, 0x04, 0x73, 0x7A, 0x91, 0x3D, 0xEF, + 0x57, 0x1D, 0xAD, 0xEC, 0x57, 0xE5, 0x91, 0x5D, 0x55, 0xD9, 0x32, 0x9D, 0x45, 0x12, 0x85, 0x76, 0x40, + 0x52, 0x07, 0xF9, 0x0D, 0x18, 0x2B, 0xB7, 0xAF, 0x5D, 0x43, 0xF8, 0xF9, 0xC5, 0xAD, 0xF9, 0xBA, 0x33, + 0x23, 0xC0, 0x2F, 0x95, 0xFF, 0x36, 0x94, 0xD8, 0x99, 0x99, 0xE0, 0x66, 0xF8, 0xB6, 0x27, 0x22, 0xFD, + 0x29, 0x39, 0x30, 0x39, 0xAB, 0x93, 0xDB, 0x9D, 0x2C, 0xE5, 0xF0, 0x4C, 0xB7, 0x30, 0xFD, 0xC7, 0xD3, + 0x21, 0xC9, 0x4E, 0x0D, 0x8A, 0x1B, 0xB2, 0x89, 0x97, 0x10, 0x7E, 0x84, 0x09}; // No ledger sequence: static constexpr std::uint8_t payload5[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, - 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, - 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, 0x79, 0x39, - 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, - 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, - 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, 0xD9, 0x06, - 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, 0x9D, 0x19, 0xFB, 0x09, - 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, - 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, 0x92, 0x8C, 0x27, 0x51, 0xFC, - 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0x83, - 0xB3, 0x1B, 0xE9, 0x03, 0x8F, 0x4A, 0x92, 0x8B, 0x9B, 0x51, 0xEF, 0x79, - 0xED, 0xA1, 0x4A, 0x58, 0x9B, 0x20, 0xCF, 0x89, 0xC4, 0x75, 0x99, 0x5F, - 0x6D, 0x79, 0x51, 0x79, 0x07, 0xF9, 0x93, 0x02, 0x20, 0x39, 0xA6, 0x0C, - 0x77, 0x68, 0x84, 0x50, 0xDB, 0xDA, 0x64, 0x32, 0x74, 0xEC, 0x63, 0x48, - 0x48, 0x96, 0xB5, 0x94, 0x57, 0x55, 0x8D, 0x7D, 0xD8, 0x25, 0x78, 0xD1, - 0xEA, 0x5F, 0xD9, 0xC7, 0xAA}; + 0x22, 0x80, 0x00, 0x00, 0x01, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, + 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, + 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, + 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, + 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, + 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, + 0x3E, 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, + 0x83, 0xB3, 0x1B, 0xE9, 0x03, 0x8F, 0x4A, 0x92, 0x8B, 0x9B, 0x51, 0xEF, 0x79, 0xED, 0xA1, 0x4A, 0x58, + 0x9B, 0x20, 0xCF, 0x89, 0xC4, 0x75, 0x99, 0x5F, 0x6D, 0x79, 0x51, 0x79, 0x07, 0xF9, 0x93, 0x02, 0x20, + 0x39, 0xA6, 0x0C, 0x77, 0x68, 0x84, 0x50, 0xDB, 0xDA, 0x64, 0x32, 0x74, 0xEC, 0x63, 0x48, 0x48, 0x96, + 0xB5, 0x94, 0x57, 0x55, 0x8D, 0x7D, 0xD8, 0x25, 0x78, 0xD1, 0xEA, 0x5F, 0xD9, 0xC7, 0xAA}; // No sign time: static constexpr std::uint8_t payload6[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x51, 0x53, - 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, - 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, 0x79, 0x39, - 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, - 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, - 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, 0xD9, 0x06, - 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, 0x9D, 0x19, 0xFB, 0x09, - 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, - 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, 0x92, 0x8C, 0x27, 0x51, 0xFC, - 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xDD, - 0xB0, 0x59, 0x9A, 0x02, 0x3E, 0xF2, 0x44, 0xCE, 0x1D, 0xA8, 0x99, 0x06, - 0xF3, 0x8A, 0x4B, 0xEB, 0x95, 0x42, 0x63, 0x6A, 0x6C, 0x04, 0x30, 0x7F, - 0x62, 0x78, 0x3A, 0x89, 0xB0, 0x3F, 0x22, 0x02, 0x20, 0x4E, 0x6A, 0x55, - 0x63, 0x8A, 0x19, 0xED, 0xFE, 0x70, 0x34, 0xD1, 0x30, 0xED, 0x7C, 0xAF, - 0xB2, 0x78, 0xBB, 0x15, 0x6C, 0x42, 0x3E, 0x19, 0x5D, 0xEA, 0xC5, 0x5E, - 0x23, 0xE2, 0x14, 0x80, 0x54}; + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, + 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, 0x8C, 0xDE, 0xB8, + 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, + 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, 0x35, + 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, + 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, + 0x3E, 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, + 0xDD, 0xB0, 0x59, 0x9A, 0x02, 0x3E, 0xF2, 0x44, 0xCE, 0x1D, 0xA8, 0x99, 0x06, 0xF3, 0x8A, 0x4B, 0xEB, + 0x95, 0x42, 0x63, 0x6A, 0x6C, 0x04, 0x30, 0x7F, 0x62, 0x78, 0x3A, 0x89, 0xB0, 0x3F, 0x22, 0x02, 0x20, + 0x4E, 0x6A, 0x55, 0x63, 0x8A, 0x19, 0xED, 0xFE, 0x70, 0x34, 0xD1, 0x30, 0xED, 0x7C, 0xAF, 0xB2, 0x78, + 0xBB, 0x15, 0x6C, 0x42, 0x3E, 0x19, 0x5D, 0xEA, 0xC5, 0x5E, 0x23, 0xE2, 0x14, 0x80, 0x54}; // No signature field: static constexpr std::uint8_t payload7[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, - 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, - 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, - 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, - 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, - 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, - 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, - 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, - 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32}; + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, + 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, + 0x4B, 0x40, 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, + 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, + 0x2D, 0x18, 0xA6, 0x43, 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, + 0x9D, 0x19, 0xFB, 0x09, 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, + 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32}; // Good: static constexpr std::uint8_t payload8[] = { - 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, - 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, - 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, - 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, - 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, - 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, - 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, - 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, - 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, - 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, - 0x45, 0x02, 0x21, 0x00, 0xDD, 0x29, 0xDC, 0xAC, 0x82, 0x5E, 0xF9, 0xE2, - 0x2D, 0x26, 0x03, 0x95, 0xC2, 0x11, 0x3A, 0x2A, 0x83, 0xEE, 0xA0, 0x2B, - 0x9F, 0x2A, 0x51, 0xBD, 0x6B, 0xF7, 0x83, 0xCE, 0x4A, 0x7C, 0x52, 0x29, - 0x02, 0x20, 0x52, 0x45, 0xB9, 0x07, 0x57, 0xEF, 0xB2, 0x6C, 0x69, 0xC5, - 0x47, 0xCA, 0xE2, 0x76, 0x00, 0xFC, 0x35, 0x46, 0x5D, 0x19, 0x64, 0xCE, + 0x22, 0x80, 0x00, 0x00, 0x01, 0x26, 0x03, 0x4B, 0xEA, 0x97, 0x29, 0x26, 0x47, 0x31, 0x1A, 0x51, 0x53, 0x1F, + 0x1A, 0x4E, 0xBB, 0x43, 0x19, 0x69, 0x16, 0xF8, 0x3E, 0xEA, 0x5C, 0x77, 0x94, 0x08, 0x19, 0x0B, 0x4B, 0x40, + 0x8C, 0xDE, 0xB8, 0x79, 0x39, 0xF3, 0x9D, 0x66, 0x7B, 0x12, 0xCA, 0x97, 0x50, 0x17, 0x21, 0x0B, 0xAB, 0xBC, + 0x8C, 0xB7, 0xFB, 0x45, 0x49, 0xED, 0x1E, 0x07, 0xB4, 0xFB, 0xC5, 0xF2, 0xFB, 0x67, 0x2D, 0x18, 0xA6, 0x43, + 0x35, 0x28, 0xEB, 0xD9, 0x06, 0x3E, 0xB3, 0x8B, 0xC2, 0xE0, 0x73, 0x21, 0x02, 0x9D, 0x19, 0xFB, 0x09, 0x40, + 0xE5, 0xC0, 0xD8, 0x58, 0x73, 0xFA, 0x71, 0x19, 0x99, 0x94, 0x4A, 0x68, 0x7D, 0x12, 0x9D, 0xA5, 0xC3, 0x3E, + 0x92, 0x8C, 0x27, 0x51, 0xFC, 0x1B, 0x31, 0xEB, 0x32, 0x76, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xDD, 0x29, + 0xDC, 0xAC, 0x82, 0x5E, 0xF9, 0xE2, 0x2D, 0x26, 0x03, 0x95, 0xC2, 0x11, 0x3A, 0x2A, 0x83, 0xEE, 0xA0, 0x2B, + 0x9F, 0x2A, 0x51, 0xBD, 0x6B, 0xF7, 0x83, 0xCE, 0x4A, 0x7C, 0x52, 0x29, 0x02, 0x20, 0x52, 0x45, 0xB9, 0x07, + 0x57, 0xEF, 0xB2, 0x6C, 0x69, 0xC5, 0x47, 0xCA, 0xE2, 0x76, 0x00, 0xFC, 0x35, 0x46, 0x5D, 0x19, 0x64, 0xCE, 0xCA, 0x88, 0xA1, 0x2A, 0x20, 0xCF, 0x3C, 0xF9, 0xCE, 0xCF}; public: @@ -185,8 +129,7 @@ public: { SerialIter sit{payload8}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, true); + auto val = std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, true); BEAST_EXPECT(val); BEAST_EXPECT(val->isFieldPresent(sfLedgerSequence)); @@ -206,55 +149,49 @@ public: try { SerialIter sit{payload1}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = + std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp( - ex.what(), - "Field 'SigningPubKey' is required but missing.") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Field 'SigningPubKey' is required but missing.") == 0); } try { SerialIter sit{payload2}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = + std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp(ex.what(), "Invalid public key in validation") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Invalid public key in validation") == 0); } try { SerialIter sit{payload3}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = + std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp(ex.what(), "Invalid public key in validation") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Invalid public key in validation") == 0); } try { SerialIter sit{payload4}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = + std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("An exception should have been thrown"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp(ex.what(), "Invalid public key in validation") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Invalid public key in validation") == 0); } testcase("Deserialization: Missing Fields"); @@ -262,48 +199,36 @@ public: try { SerialIter sit{payload5}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("Expected exception not thrown from validation"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp( - ex.what(), - "Field 'LedgerSequence' is required but missing.") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Field 'LedgerSequence' is required but missing.") == 0); } try { SerialIter sit{payload6}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("Expected exception not thrown from validation"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp( - ex.what(), - "Field 'SigningTime' is required but missing.") == 0); + BEAST_EXPECT(strcmp(ex.what(), "Field 'SigningTime' is required but missing.") == 0); } try { SerialIter sit{payload7}; - auto val = std::make_shared( - sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); + auto val = std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, false); fail("Expected exception not thrown from validation"); } catch (std::exception const& ex) { - BEAST_EXPECT( - strcmp( - ex.what(), "Field 'Signature' is required but missing.") == - 0); + BEAST_EXPECT(strcmp(ex.what(), "Field 'Signature' is required but missing.") == 0); } testcase("Deserialization: Corrupted Data / Fuzzing"); @@ -326,14 +251,10 @@ public: { SerialIter sit{makeSlice(v2)}; - auto val = std::make_shared( - sit, - [](PublicKey const& pk) { return calcNodeID(pk); }, - true); + auto val = + std::make_shared(sit, [](PublicKey const& pk) { return calcNodeID(pk); }, true); - fail( - "Mutated validation signature checked out: offset=" + - std::to_string(i)); + fail("Mutated validation signature checked out: offset=" + std::to_string(i)); } catch (std::exception const&) { @@ -349,6 +270,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(STValidation, protocol, ripple); +BEAST_DEFINE_TESTSUITE(STValidation, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/SecretKey_test.cpp b/src/test/protocol/SecretKey_test.cpp index 248be5a0da..60081c8251 100644 --- a/src/test/protocol/SecretKey_test.cpp +++ b/src/test/protocol/SecretKey_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -28,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { class SecretKey_test : public beast::unit_test::suite { @@ -50,38 +31,29 @@ public: { testcase("secp256k1: canonicality"); - std::array const digestData{ - 0x34, 0xC1, 0x90, 0x28, 0xC8, 0x0D, 0x21, 0xF3, 0xF4, 0x8C, 0x93, - 0x54, 0x89, 0x5F, 0x8D, 0x5B, 0xF0, 0xD5, 0xEE, 0x7F, 0xF4, 0x57, - 0x64, 0x7C, 0xF6, 0x55, 0xF5, 0x53, 0x0A, 0x30, 0x22, 0xA7}; + std::array const digestData{0x34, 0xC1, 0x90, 0x28, 0xC8, 0x0D, 0x21, 0xF3, 0xF4, 0x8C, 0x93, + 0x54, 0x89, 0x5F, 0x8D, 0x5B, 0xF0, 0xD5, 0xEE, 0x7F, 0xF4, 0x57, + 0x64, 0x7C, 0xF6, 0x55, 0xF5, 0x53, 0x0A, 0x30, 0x22, 0xA7}; - std::array const pkData{ - 0x02, 0x50, 0x96, 0xEB, 0x12, 0xD3, 0xE9, 0x24, 0x23, 0x4E, 0x71, - 0x62, 0x36, 0x9C, 0x11, 0xD8, 0xBF, 0x87, 0x7E, 0xDA, 0x23, 0x87, - 0x78, 0xE7, 0xA3, 0x1F, 0xF0, 0xAA, 0xC5, 0xD0, 0xDB, 0xCF, 0x37}; + std::array const pkData{0x02, 0x50, 0x96, 0xEB, 0x12, 0xD3, 0xE9, 0x24, 0x23, 0x4E, 0x71, + 0x62, 0x36, 0x9C, 0x11, 0xD8, 0xBF, 0x87, 0x7E, 0xDA, 0x23, 0x87, + 0x78, 0xE7, 0xA3, 0x1F, 0xF0, 0xAA, 0xC5, 0xD0, 0xDB, 0xCF, 0x37}; - std::array const skData{ - 0xAA, 0x92, 0x14, 0x17, 0xE7, 0xE5, 0xC2, 0x99, 0xDA, 0x4E, 0xEC, - 0x16, 0xD1, 0xCA, 0xA9, 0x2F, 0x19, 0xB1, 0x9F, 0x2A, 0x68, 0x51, - 0x1F, 0x68, 0xEC, 0x73, 0xBB, 0xB2, 0xF5, 0x23, 0x6F, 0x3D}; + std::array const skData{0xAA, 0x92, 0x14, 0x17, 0xE7, 0xE5, 0xC2, 0x99, 0xDA, 0x4E, 0xEC, + 0x16, 0xD1, 0xCA, 0xA9, 0x2F, 0x19, 0xB1, 0x9F, 0x2A, 0x68, 0x51, + 0x1F, 0x68, 0xEC, 0x73, 0xBB, 0xB2, 0xF5, 0x23, 0x6F, 0x3D}; std::array const sig{ - 0x30, 0x45, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, - 0xBA, 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, 0x77, 0x91, 0x40, 0x8D, - 0x1F, 0xB8, 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, - 0x60, 0xF2, 0x46, 0x60, 0x02, 0x20, 0x50, 0x87, 0x39, 0xDB, 0x0A, - 0x2E, 0xF8, 0x16, 0x76, 0xE3, 0x9F, 0x45, 0x9C, 0x8B, 0xBB, 0x07, - 0xA0, 0x9C, 0x3E, 0x9F, 0x9B, 0xEB, 0x69, 0x62, 0x94, 0xD5, 0x24, - 0xD4, 0x79, 0xD6, 0x27, 0x40}; + 0x30, 0x45, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, 0xBA, 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, + 0x77, 0x91, 0x40, 0x8D, 0x1F, 0xB8, 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, 0x60, 0xF2, 0x46, + 0x60, 0x02, 0x20, 0x50, 0x87, 0x39, 0xDB, 0x0A, 0x2E, 0xF8, 0x16, 0x76, 0xE3, 0x9F, 0x45, 0x9C, 0x8B, 0xBB, + 0x07, 0xA0, 0x9C, 0x3E, 0x9F, 0x9B, 0xEB, 0x69, 0x62, 0x94, 0xD5, 0x24, 0xD4, 0x79, 0xD6, 0x27, 0x40}; std::array const non{ - 0x30, 0x46, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, - 0xBA, 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, 0x77, 0x91, 0x40, 0x8D, - 0x1F, 0xB8, 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, - 0x60, 0xF2, 0x46, 0x60, 0x02, 0x21, 0x00, 0xAF, 0x78, 0xC6, 0x24, - 0xF5, 0xD1, 0x07, 0xE9, 0x89, 0x1C, 0x60, 0xBA, 0x63, 0x74, 0x44, - 0xF7, 0x1A, 0x12, 0x9E, 0x47, 0x13, 0x5D, 0x36, 0xD9, 0x2A, 0xFD, - 0x39, 0xB8, 0x56, 0x60, 0x1A, 0x01}; + 0x30, 0x46, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, 0xBA, 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, + 0x77, 0x91, 0x40, 0x8D, 0x1F, 0xB8, 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, 0x60, 0xF2, 0x46, + 0x60, 0x02, 0x21, 0x00, 0xAF, 0x78, 0xC6, 0x24, 0xF5, 0xD1, 0x07, 0xE9, 0x89, 0x1C, 0x60, 0xBA, 0x63, 0x74, + 0x44, 0xF7, 0x1A, 0x12, 0x9E, 0x47, 0x13, 0x5D, 0x36, 0xD9, 0x2A, 0xFD, 0x39, 0xB8, 0x56, 0x60, 0x1A, 0x01}; auto const digest = uint256::fromVoid(digestData.data()); @@ -164,28 +136,27 @@ public: auto sig = sign(pk, sk, makeSlice(data)); BEAST_EXPECT(sig.size() != 0); - BEAST_EXPECT(verify(pk, makeSlice(data), sig, true)); + BEAST_EXPECT(verify(pk, makeSlice(data), sig)); // Construct wrong data: auto badData = data; // swaps the smallest and largest elements in buffer std::iter_swap( - std::min_element(badData.begin(), badData.end()), - std::max_element(badData.begin(), badData.end())); + std::min_element(badData.begin(), badData.end()), std::max_element(badData.begin(), badData.end())); // Wrong data: should fail - BEAST_EXPECT(!verify(pk, makeSlice(badData), sig, true)); + BEAST_EXPECT(!verify(pk, makeSlice(badData), sig)); // Slightly change the signature: if (auto ptr = sig.data()) ptr[j % sig.size()]++; // Wrong signature: should fail - BEAST_EXPECT(!verify(pk, makeSlice(data), sig, true)); + BEAST_EXPECT(!verify(pk, makeSlice(data), sig)); // Wrong data and signature: should fail - BEAST_EXPECT(!verify(pk, makeSlice(badData), sig, true)); + BEAST_EXPECT(!verify(pk, makeSlice(badData), sig)); } } } @@ -197,24 +168,20 @@ public: // Ensure that parsing some well-known secret keys works { - auto const sk1 = generateSecretKey( - KeyType::secp256k1, generateSeed("masterpassphrase")); + auto const sk1 = generateSecretKey(KeyType::secp256k1, generateSeed("masterpassphrase")); - auto const sk2 = parseBase58( - TokenType::NodePrivate, - "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe"); + auto const sk2 = + parseBase58(TokenType::NodePrivate, "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe"); BEAST_EXPECT(sk2); BEAST_EXPECT(sk1 == *sk2); } { - auto const sk1 = generateSecretKey( - KeyType::ed25519, generateSeed("masterpassphrase")); + auto const sk1 = generateSecretKey(KeyType::ed25519, generateSeed("masterpassphrase")); - auto const sk2 = parseBase58( - TokenType::NodePrivate, - "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36"); + auto const sk2 = + parseBase58(TokenType::NodePrivate, "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36"); BEAST_EXPECT(sk2); BEAST_EXPECT(sk1 == *sk2); @@ -223,8 +190,7 @@ public: // Try converting short, long and malformed data BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, "")); BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, " ")); - BEAST_EXPECT(!parseBase58( - TokenType::NodePrivate, "!35gty9mhju8nfjl")); + BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, "!35gty9mhju8nfjl")); auto const good = toBase58(TokenType::NodePrivate, randomSecretKey()); @@ -238,8 +204,7 @@ public: while (!s.empty()) { s.erase(r(s) % s.size(), 1); - BEAST_EXPECT( - !parseBase58(TokenType::NodePrivate, s)); + BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, s)); } } @@ -258,8 +223,7 @@ public: { auto s = good; s[i % s.size()] = c; - BEAST_EXPECT( - !parseBase58(TokenType::NodePrivate, s)); + BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, s)); } } @@ -270,8 +234,7 @@ public: for (auto c : std::string("ansrJqtv7")) { s[0] = c; - BEAST_EXPECT( - !parseBase58(TokenType::NodePrivate, s)); + BEAST_EXPECT(!parseBase58(TokenType::NodePrivate, s)); } } @@ -299,8 +262,7 @@ public: BEAST_EXPECT((si == sj) == (i == j)); - auto const skj = - parseBase58(TokenType::NodePrivate, sj); + auto const skj = parseBase58(TokenType::NodePrivate, sj); BEAST_EXPECT(skj && keys[j] == *skj); BEAST_EXPECT((*ski == *skj) == (i == j)); @@ -318,8 +280,7 @@ public: auto const id = parseBase58(test.addr); BEAST_EXPECT(id); - auto kp = - generateKeyPair(KeyType::secp256k1, Seed{makeSlice(test.seed)}); + auto kp = generateKeyPair(KeyType::secp256k1, Seed{makeSlice(test.seed)}); BEAST_EXPECT(kp.first == PublicKey{makeSlice(test.pubkey)}); BEAST_EXPECT(kp.second == SecretKey{makeSlice(test.seckey)}); @@ -337,8 +298,7 @@ public: auto const id = parseBase58(test.addr); BEAST_EXPECT(id); - auto kp = - generateKeyPair(KeyType::ed25519, Seed{makeSlice(test.seed)}); + auto kp = generateKeyPair(KeyType::ed25519, Seed{makeSlice(test.seed)}); BEAST_EXPECT(kp.first == PublicKey{makeSlice(test.pubkey)}); BEAST_EXPECT(kp.second == SecretKey{makeSlice(test.seckey)}); @@ -1513,6 +1473,6 @@ inline static TestKeyData const ed25519TestVectors[] = { // clang-format on }; -BEAST_DEFINE_TESTSUITE(SecretKey, protocol, ripple); +BEAST_DEFINE_TESTSUITE(SecretKey, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/Seed_test.cpp b/src/test/protocol/Seed_test.cpp index 0b89eb22a7..d6b200cca8 100644 --- a/src/test/protocol/Seed_test.cpp +++ b/src/test/protocol/Seed_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,18 +7,14 @@ #include -namespace ripple { +namespace xrpl { class Seed_test : public beast::unit_test::suite { static bool equal(Seed const& lhs, Seed const& rhs) { - return std::equal( - lhs.data(), - lhs.data() + lhs.size(), - rhs.data(), - rhs.data() + rhs.size()); + return std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size()); } public: @@ -81,15 +58,9 @@ public: testPassphrase() { testcase("generation from passphrase"); - BEAST_EXPECT( - testPassphrase("masterpassphrase") == - "snoPBrXtMeMyMHUVTgbuqAfg1SUTb"); - BEAST_EXPECT( - testPassphrase("Non-Random Passphrase") == - "snMKnVku798EnBwUfxeSD8953sLYA"); - BEAST_EXPECT( - testPassphrase("cookies excitement hand public") == - "sspUXGrmjQhq6mgc24jiRuevZiwKT"); + BEAST_EXPECT(testPassphrase("masterpassphrase") == "snoPBrXtMeMyMHUVTgbuqAfg1SUTb"); + BEAST_EXPECT(testPassphrase("Non-Random Passphrase") == "snMKnVku798EnBwUfxeSD8953sLYA"); + BEAST_EXPECT(testPassphrase("cookies excitement hand public") == "sspUXGrmjQhq6mgc24jiRuevZiwKT"); } void @@ -134,20 +105,14 @@ public: { testcase("Node keypair generation & signing (secp256k1)"); - auto const secretKey = generateSecretKey( - KeyType::secp256k1, generateSeed("masterpassphrase")); - auto const publicKey = - derivePublicKey(KeyType::secp256k1, secretKey); + auto const secretKey = generateSecretKey(KeyType::secp256k1, generateSeed("masterpassphrase")); + auto const publicKey = derivePublicKey(KeyType::secp256k1, secretKey); BEAST_EXPECT( - toBase58(TokenType::NodePublic, publicKey) == - "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9"); + toBase58(TokenType::NodePublic, publicKey) == "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9"); BEAST_EXPECT( - toBase58(TokenType::NodePrivate, secretKey) == - "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe"); - BEAST_EXPECT( - to_string(calcNodeID(publicKey)) == - "7E59C17D50F5959C7B158FEC95C8F815BF653DC8"); + toBase58(TokenType::NodePrivate, secretKey) == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe"); + BEAST_EXPECT(to_string(calcNodeID(publicKey)) == "7E59C17D50F5959C7B158FEC95C8F815BF653DC8"); auto sig = sign(publicKey, secretKey, makeSlice(message1)); BEAST_EXPECT(sig.size() != 0); @@ -159,9 +124,7 @@ public: // Verify with incorrect public key { auto const otherPublicKey = derivePublicKey( - KeyType::secp256k1, - generateSecretKey( - KeyType::secp256k1, generateSeed("otherpassphrase"))); + KeyType::secp256k1, generateSecretKey(KeyType::secp256k1, generateSeed("otherpassphrase"))); BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig)); } @@ -179,19 +142,14 @@ public: { testcase("Node keypair generation & signing (ed25519)"); - auto const secretKey = generateSecretKey( - KeyType::ed25519, generateSeed("masterpassphrase")); + auto const secretKey = generateSecretKey(KeyType::ed25519, generateSeed("masterpassphrase")); auto const publicKey = derivePublicKey(KeyType::ed25519, secretKey); BEAST_EXPECT( - toBase58(TokenType::NodePublic, publicKey) == - "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf"); + toBase58(TokenType::NodePublic, publicKey) == "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf"); BEAST_EXPECT( - toBase58(TokenType::NodePrivate, secretKey) == - "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36"); - BEAST_EXPECT( - to_string(calcNodeID(publicKey)) == - "AA066C988C712815CC37AF71472B7CBBBD4E2A0A"); + toBase58(TokenType::NodePrivate, secretKey) == "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36"); + BEAST_EXPECT(to_string(calcNodeID(publicKey)) == "AA066C988C712815CC37AF71472B7CBBBD4E2A0A"); auto sig = sign(publicKey, secretKey, makeSlice(message1)); BEAST_EXPECT(sig.size() != 0); @@ -203,9 +161,7 @@ public: // Verify with incorrect public key { auto const otherPublicKey = derivePublicKey( - KeyType::ed25519, - generateSecretKey( - KeyType::ed25519, generateSeed("otherpassphrase"))); + KeyType::ed25519, generateSecretKey(KeyType::ed25519, generateSeed("otherpassphrase"))); BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig)); } @@ -223,18 +179,13 @@ public: { testcase("Account keypair generation & signing (secp256k1)"); - auto const [pk, sk] = generateKeyPair( - KeyType::secp256k1, generateSeed("masterpassphrase")); + auto const [pk, sk] = generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")); + BEAST_EXPECT(toBase58(calcAccountID(pk)) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"); BEAST_EXPECT( - toBase58(calcAccountID(pk)) == - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"); + toBase58(TokenType::AccountPublic, pk) == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw"); BEAST_EXPECT( - toBase58(TokenType::AccountPublic, pk) == - "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw"); - BEAST_EXPECT( - toBase58(TokenType::AccountSecret, sk) == - "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh"); + toBase58(TokenType::AccountSecret, sk) == "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh"); auto sig = sign(pk, sk, makeSlice(message1)); BEAST_EXPECT(sig.size() != 0); @@ -245,11 +196,9 @@ public: // Verify with incorrect public key { - auto const otherKeyPair = generateKeyPair( - KeyType::secp256k1, generateSeed("otherpassphrase")); + auto const otherKeyPair = generateKeyPair(KeyType::secp256k1, generateSeed("otherpassphrase")); - BEAST_EXPECT( - !verify(otherKeyPair.first, makeSlice(message1), sig)); + BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig)); } // Correct public key but wrong signature @@ -265,18 +214,13 @@ public: { testcase("Account keypair generation & signing (ed25519)"); - auto const [pk, sk] = generateKeyPair( - KeyType::ed25519, generateSeed("masterpassphrase")); + auto const [pk, sk] = generateKeyPair(KeyType::ed25519, generateSeed("masterpassphrase")); + BEAST_EXPECT(to_string(calcAccountID(pk)) == "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf"); BEAST_EXPECT( - to_string(calcAccountID(pk)) == - "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf"); + toBase58(TokenType::AccountPublic, pk) == "aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR"); BEAST_EXPECT( - toBase58(TokenType::AccountPublic, pk) == - "aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR"); - BEAST_EXPECT( - toBase58(TokenType::AccountSecret, sk) == - "pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9"); + toBase58(TokenType::AccountSecret, sk) == "pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9"); auto sig = sign(pk, sk, makeSlice(message1)); BEAST_EXPECT(sig.size() != 0); @@ -287,11 +231,9 @@ public: // Verify with incorrect public key { - auto const otherKeyPair = generateKeyPair( - KeyType::ed25519, generateSeed("otherpassphrase")); + auto const otherKeyPair = generateKeyPair(KeyType::ed25519, generateSeed("otherpassphrase")); - BEAST_EXPECT( - !verify(otherKeyPair.first, makeSlice(message1), sig)); + BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig)); } // Correct public key but wrong signature @@ -311,39 +253,29 @@ public: testcase("Parsing"); // account IDs and node and account public and private - // keys should not be parseable as seeds. + // keys should not be parsable as seeds. auto const node1 = randomKeyPair(KeyType::secp256k1); - BEAST_EXPECT( - !parseGenericSeed(toBase58(TokenType::NodePublic, node1.first))); - BEAST_EXPECT( - !parseGenericSeed(toBase58(TokenType::NodePrivate, node1.second))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node1.first))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node1.second))); auto const node2 = randomKeyPair(KeyType::ed25519); - BEAST_EXPECT( - !parseGenericSeed(toBase58(TokenType::NodePublic, node2.first))); - BEAST_EXPECT( - !parseGenericSeed(toBase58(TokenType::NodePrivate, node2.second))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node2.first))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node2.second))); auto const account1 = generateKeyPair(KeyType::secp256k1, randomSeed()); - BEAST_EXPECT( - !parseGenericSeed(toBase58(calcAccountID(account1.first)))); - BEAST_EXPECT(!parseGenericSeed( - toBase58(TokenType::AccountPublic, account1.first))); - BEAST_EXPECT(!parseGenericSeed( - toBase58(TokenType::AccountSecret, account1.second))); + BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account1.first)))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account1.first))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account1.second))); auto const account2 = generateKeyPair(KeyType::ed25519, randomSeed()); - BEAST_EXPECT( - !parseGenericSeed(toBase58(calcAccountID(account2.first)))); - BEAST_EXPECT(!parseGenericSeed( - toBase58(TokenType::AccountPublic, account2.first))); - BEAST_EXPECT(!parseGenericSeed( - toBase58(TokenType::AccountSecret, account2.second))); + BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account2.first)))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account2.first))); + BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account2.second))); } void @@ -358,6 +290,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Seed, protocol, ripple); +BEAST_DEFINE_TESTSUITE(Seed, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/SeqProxy_test.cpp b/src/test/protocol/SeqProxy_test.cpp index 7a660c10d2..0e91680c8c 100644 --- a/src/test/protocol/SeqProxy_test.cpp +++ b/src/test/protocol/SeqProxy_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { struct SeqProxy_test : public beast::unit_test::suite { @@ -32,32 +13,28 @@ struct SeqProxy_test : public beast::unit_test::suite expectValues(SeqProxy seqProx, std::uint32_t value, SeqProxy::Type type) { bool const expectSeq{type == SeqProxy::seq}; - return (seqProx.value() == value) && (seqProx.isSeq() == expectSeq) && - (seqProx.isTicket() == !expectSeq); + return (seqProx.value() == value) && (seqProx.isSeq() == expectSeq) && (seqProx.isTicket() == !expectSeq); } // Exercise all SeqProxy comparison operators expecting lhs < rhs. static constexpr bool expectLt(SeqProxy lhs, SeqProxy rhs) { - return (lhs < rhs) && (lhs <= rhs) && (!(lhs == rhs)) && (lhs != rhs) && - (!(lhs >= rhs)) && (!(lhs > rhs)); + return (lhs < rhs) && (lhs <= rhs) && (!(lhs == rhs)) && (lhs != rhs) && (!(lhs >= rhs)) && (!(lhs > rhs)); } // Exercise all SeqProxy comparison operators expecting lhs == rhs. static constexpr bool expectEq(SeqProxy lhs, SeqProxy rhs) { - return (!(lhs < rhs)) && (lhs <= rhs) && (lhs == rhs) && - (!(lhs != rhs)) && (lhs >= rhs) && (!(lhs > rhs)); + return (!(lhs < rhs)) && (lhs <= rhs) && (lhs == rhs) && (!(lhs != rhs)) && (lhs >= rhs) && (!(lhs > rhs)); } // Exercise all SeqProxy comparison operators expecting lhs > rhs. static constexpr bool expectGt(SeqProxy lhs, SeqProxy rhs) { - return (!(lhs < rhs)) && (!(lhs <= rhs)) && (!(lhs == rhs)) && - (lhs != rhs) && (lhs >= rhs) && (lhs > rhs); + return (!(lhs < rhs)) && (!(lhs <= rhs)) && (!(lhs == rhs)) && (lhs != rhs) && (lhs >= rhs) && (lhs > rhs); } // Verify streaming. @@ -71,8 +48,7 @@ struct SeqProxy_test : public beast::unit_test::suite ss << seqProx; std::string str{ss.str()}; - return str.find(type) == 0 && str[type.size()] == ' ' && - str.find(value) == (type.size() + 1); + return str.find(type) == 0 && str[type.size()] == ' ' && str.find(value) == (type.size() + 1); } void @@ -81,8 +57,7 @@ struct SeqProxy_test : public beast::unit_test::suite // While SeqProxy supports values of zero, they are not // expected in the wild. Nevertheless they are tested here. // But so are values of 1, which are expected to occur in the wild. - static constexpr std::uint32_t uintMax{ - std::numeric_limits::max()}; + static constexpr std::uint32_t uintMax{std::numeric_limits::max()}; static constexpr SeqProxy::Type seq{SeqProxy::seq}; static constexpr SeqProxy::Type ticket{SeqProxy::ticket}; @@ -236,6 +211,6 @@ struct SeqProxy_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SeqProxy, protocol, ripple); +BEAST_DEFINE_TESTSUITE(SeqProxy, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/Serializer_test.cpp b/src/test/protocol/Serializer_test.cpp index d707943856..cd34446fa8 100644 --- a/src/test/protocol/Serializer_test.cpp +++ b/src/test/protocol/Serializer_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { struct Serializer_test : public beast::unit_test::suite { @@ -31,11 +12,7 @@ struct Serializer_test : public beast::unit_test::suite { { std::initializer_list const values = { - std::numeric_limits::min(), - -1, - 0, - 1, - std::numeric_limits::max()}; + std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}; for (std::int32_t value : values) { Serializer s; @@ -47,11 +24,7 @@ struct Serializer_test : public beast::unit_test::suite } { std::initializer_list const values = { - std::numeric_limits::min(), - -1, - 0, - 1, - std::numeric_limits::max()}; + std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}; for (std::int64_t value : values) { Serializer s; @@ -64,6 +37,6 @@ struct Serializer_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(Serializer, protocol, ripple); +BEAST_DEFINE_TESTSUITE(Serializer, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/protocol/TER_test.cpp b/src/test/protocol/TER_test.cpp index 0107f1c7d2..6dce46ed6b 100644 --- a/src/test/protocol/TER_test.cpp +++ b/src/test/protocol/TER_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { struct TER_test : public beast::unit_test::suite { @@ -33,8 +14,7 @@ struct TER_test : public beast::unit_test::suite for (auto i = -400; i < 400; ++i) { TER t = TER::fromInt(i); - auto inRange = isTelLocal(t) || isTemMalformed(t) || - isTefFailure(t) || isTerRetry(t) || isTesSuccess(t) || + auto inRange = isTelLocal(t) || isTemMalformed(t) || isTefFailure(t) || isTerRetry(t) || isTesSuccess(t) || isTecClaim(t); std::string token, text; @@ -68,36 +48,21 @@ struct TER_test : public beast::unit_test::suite // unless they are the same types. using To_t = std::decay_t(tup))>; using From_t = std::decay_t(tup))>; + static_assert(std::is_same::value == std::is_convertible::value, "Convert err"); static_assert( - std::is_same::value == - std::is_convertible::value, - "Convert err"); + std::is_same::value == std::is_constructible::value, "Construct err"); static_assert( - std::is_same::value == - std::is_constructible::value, - "Construct err"); - static_assert( - std::is_same::value == - std::is_assignable::value, - "Assign err"); + std::is_same::value == std::is_assignable::value, "Assign err"); // Assignment or conversion from integer to type should never work. - static_assert( - !std::is_convertible::value, "Convert err"); - static_assert( - !std::is_constructible::value, "Construct err"); - static_assert( - !std::is_assignable::value, "Assign err"); + static_assert(!std::is_convertible::value, "Convert err"); + static_assert(!std::is_constructible::value, "Construct err"); + static_assert(!std::is_assignable::value, "Assign err"); } }; // Fast iteration over the tuple. - template < - std::size_t I1, - std::size_t I2, - template - class Func, - typename Tup> + template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { @@ -107,12 +72,7 @@ struct TER_test : public beast::unit_test::suite } // Slow iteration over the tuple. - template < - std::size_t I1, - std::size_t I2, - template - class Func, - typename Tup> + template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { @@ -122,12 +82,7 @@ struct TER_test : public beast::unit_test::suite } // Finish iteration over the tuple. - template < - std::size_t I1, - std::size_t I2, - template - class Func, - typename Tup> + template class Func, typename Tup> std::enable_if_t testIterate(Tup const& tup, beast::unit_test::suite& s) { @@ -142,50 +97,38 @@ struct TER_test : public beast::unit_test::suite // are not valid. // Examples of each kind of enum. - static auto const terEnums = std::make_tuple( - telLOCAL_ERROR, - temMALFORMED, - tefFAILURE, - terRETRY, - tesSUCCESS, - tecCLAIM); - static int const hiIndex{ - std::tuple_size::value - 1}; + static auto const terEnums = + std::make_tuple(telLOCAL_ERROR, temMALFORMED, tefFAILURE, terRETRY, tesSUCCESS, tecCLAIM); + static int const hiIndex{std::tuple_size::value - 1}; // Verify that enums cannot be converted to other enum types. testIterate(terEnums, *this); // Lambda that verifies assignability and convertibility. - auto isConvertable = [](auto from, auto to) { + auto isConvertible = [](auto from, auto to) { using From_t = std::decay_t; using To_t = std::decay_t; - static_assert( - std::is_convertible::value, "Convert err"); - static_assert( - std::is_constructible::value, "Construct err"); - static_assert( - std::is_assignable::value, "Assign err"); + static_assert(std::is_convertible::value, "Convert err"); + static_assert(std::is_constructible::value, "Construct err"); + static_assert(std::is_assignable::value, "Assign err"); }; // Verify the right types convert to NotTEC. NotTEC const notTec; - isConvertable(telLOCAL_ERROR, notTec); - isConvertable(temMALFORMED, notTec); - isConvertable(tefFAILURE, notTec); - isConvertable(terRETRY, notTec); - isConvertable(tesSUCCESS, notTec); - isConvertable(notTec, notTec); + isConvertible(telLOCAL_ERROR, notTec); + isConvertible(temMALFORMED, notTec); + isConvertible(tefFAILURE, notTec); + isConvertible(terRETRY, notTec); + isConvertible(tesSUCCESS, notTec); + isConvertible(notTec, notTec); // Lambda that verifies types and not assignable or convertible. auto notConvertible = [](auto from, auto to) { using To_t = std::decay_t; using From_t = std::decay_t; - static_assert( - !std::is_convertible::value, "Convert err"); - static_assert( - !std::is_constructible::value, "Construct err"); - static_assert( - !std::is_assignable::value, "Assign err"); + static_assert(!std::is_convertible::value, "Convert err"); + static_assert(!std::is_constructible::value, "Construct err"); + static_assert(!std::is_assignable::value, "Assign err"); }; // Verify types that shouldn't convert to NotTEC. @@ -195,14 +138,14 @@ struct TER_test : public beast::unit_test::suite notConvertible(4, notTec); // Verify the right types convert to TER. - isConvertable(telLOCAL_ERROR, ter); - isConvertable(temMALFORMED, ter); - isConvertable(tefFAILURE, ter); - isConvertable(terRETRY, ter); - isConvertable(tesSUCCESS, ter); - isConvertable(tecCLAIM, ter); - isConvertable(notTec, ter); - isConvertable(ter, ter); + isConvertible(telLOCAL_ERROR, ter); + isConvertible(temMALFORMED, ter); + isConvertible(tefFAILURE, ter); + isConvertible(terRETRY, ter); + isConvertible(tesSUCCESS, ter); + isConvertible(tecCLAIM, ter); + isConvertible(notTec, ter); + isConvertible(ter, ter); // Verify that you can't convert from int to ter. notConvertible(4, ter); @@ -227,29 +170,17 @@ struct TER_test : public beast::unit_test::suite auto const lhs = std::get(tup); auto const rhs = std::get(tup); - static_assert( - std::is_same::value, - "== err"); + static_assert(std::is_same::value, "== err"); - static_assert( - std::is_same::value, - "!= err"); + static_assert(std::is_same::value, "!= err"); - static_assert( - std::is_same::value, - "< err"); + static_assert(std::is_same::value, "< err"); - static_assert( - std::is_same::value, - "<= err"); + static_assert(std::is_same::value, "<= err"); - static_assert( - std::is_same(lhs, rhs)), bool>::value, - "> err"); + static_assert(std::is_same(lhs, rhs)), bool>::value, "> err"); - static_assert( - std::is_same=(lhs, rhs)), bool>::value, - ">= err"); + static_assert(std::is_same=(lhs, rhs)), bool>::value, ">= err"); // Make sure a sampling of TER types exhibit the expected behavior // for all comparison operators. @@ -293,6 +224,6 @@ struct TER_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(TER, protocol, ripple); +BEAST_DEFINE_TESTSUITE(TER, protocol, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/resource/Logic_test.cpp b/src/test/resource/Logic_test.cpp index 49326e7dc5..f3e44e8b32 100644 --- a/src/test/resource/Logic_test.cpp +++ b/src/test/resource/Logic_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,22 +11,20 @@ #include -namespace ripple { +namespace xrpl { namespace Resource { class ResourceManager_test : public beast::unit_test::suite { public: - class TestLogic : private boost::base_from_member, - public Logic + class TestLogic : private boost::base_from_member, public Logic { private: using clock_type = boost::base_from_member; public: - explicit TestLogic(beast::Journal journal) - : Logic(beast::insight::NullCollector::New(), member, journal) + explicit TestLogic(beast::Journal journal) : Logic(beast::insight::NullCollector::New(), member, journal) { } @@ -74,8 +53,7 @@ public: { Gossip::Item item; item.balance = 100 + rand_int(499); - beast::IP::AddressV4::bytes_type d = { - {192, 0, 2, static_cast(v + i)}}; + beast::IP::AddressV4::bytes_type d = {{192, 0, 2, static_cast(v + i)}}; item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}}; gossip.items.push_back(item); } @@ -94,16 +72,11 @@ public: TestLogic logic(j); Charge const fee(dropThreshold + 1); - beast::IP::Endpoint const addr( - beast::IP::Endpoint::from_string("192.0.2.2")); + beast::IP::Endpoint const addr(beast::IP::Endpoint::from_string("192.0.2.2")); std::function ep = limited - ? std::bind( - &TestLogic::newInboundEndpoint, &logic, std::placeholders::_1) - : std::bind( - &TestLogic::newUnlimitedEndpoint, - &logic, - std::placeholders::_1); + ? std::bind(&TestLogic::newInboundEndpoint, &logic, std::placeholders::_1) + : std::bind(&TestLogic::newUnlimitedEndpoint, &logic, std::placeholders::_1); { Consumer c(ep(addr)); @@ -241,34 +214,28 @@ public: TestLogic logic(j); { - beast::IP::Endpoint address( - beast::IP::Endpoint::from_string("192.0.2.1")); + beast::IP::Endpoint address(beast::IP::Endpoint::from_string("192.0.2.1")); Consumer c(logic.newInboundEndpoint(address)); Charge fee(1000); - JLOG(j.info()) << "Charging " << c.to_string() << " " << fee - << " per second"; + JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second"; c.charge(fee); for (int i = 0; i < 128; ++i) { - JLOG(j.info()) << "Time= " - << logic.clock().now().time_since_epoch().count() + JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count() << ", Balance = " << c.balance(); logic.advance(); } } { - beast::IP::Endpoint address( - beast::IP::Endpoint::from_string("192.0.2.2")); + beast::IP::Endpoint address(beast::IP::Endpoint::from_string("192.0.2.2")); Consumer c(logic.newInboundEndpoint(address)); Charge fee(1000); - JLOG(j.info()) << "Charging " << c.to_string() << " " << fee - << " per second"; + JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second"; for (int i = 0; i < 128; ++i) { c.charge(fee); - JLOG(j.info()) << "Time= " - << logic.clock().now().time_since_epoch().count() + JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count() << ", Balance = " << c.balance(); logic.advance(); } @@ -291,7 +258,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ResourceManager, resource, ripple); +BEAST_DEFINE_TESTSUITE(ResourceManager, resource, xrpl); } // namespace Resource -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index d5bfc8e83d..cf515d7c84 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class AMMInfo_test : public jtx::AMMTestBase @@ -40,8 +21,7 @@ public: Account const bogie("bogie"); enum TestAccount { None, Alice, Bogie }; - auto accountId = [&](AMM const& ammAlice, - TestAccount v) -> std::optional { + auto accountId = [&](AMM const& ammAlice, TestAccount v) -> std::optional { if (v == Alice) return ammAlice.ammAccount(); else if (v == Bogie) @@ -54,8 +34,7 @@ public: testAMM([&](AMM& ammAlice, Env&) { Account const gw("gw"); auto const USD = gw["USD"]; - auto const jv = - ammAlice.ammRpcInfo({}, {}, USD.issue(), USD.issue()); + auto const jv = ammAlice.ammRpcInfo({}, {}, USD.issue(), USD.issue()); BEAST_EXPECT(jv[jss::error_message] == "Account not found."); }); @@ -65,11 +44,7 @@ public: BEAST_EXPECT(jv[jss::error_message] == "Account malformed."); }); - std::vector, - std::optional, - TestAccount, - bool>> const invalidParams = { + std::vector, std::optional, TestAccount, bool>> const invalidParams = { {xrpIssue(), std::nullopt, None, false}, {std::nullopt, USD.issue(), None, false}, {xrpIssue(), std::nullopt, Alice, false}, @@ -82,12 +57,7 @@ public: for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams) { auto const jv = ammAlice.ammRpcInfo( - std::nullopt, - std::nullopt, - iss1, - iss2, - accountId(ammAlice, acct), - ignoreParams); + std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams); BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters."); } }); @@ -125,60 +95,38 @@ public: // Invalid AMM account id testAMM([&](AMM& ammAlice, Env&) { - auto const jv = ammAlice.ammRpcInfo( - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - bogie.id()); + auto const jv = ammAlice.ammRpcInfo(std::nullopt, std::nullopt, std::nullopt, std::nullopt, bogie.id()); BEAST_EXPECT(jv[jss::error_message] == "Account malformed."); }); - std::vector, - std::optional, - TestAccount, - bool>> const invalidParamsBadAccount = { - {xrpIssue(), std::nullopt, None, false}, - {std::nullopt, USD.issue(), None, false}, - {xrpIssue(), std::nullopt, Bogie, false}, - {std::nullopt, USD.issue(), Bogie, false}, - {xrpIssue(), USD.issue(), Bogie, false}, - {std::nullopt, std::nullopt, None, true}}; + std::vector, std::optional, TestAccount, bool>> const + invalidParamsBadAccount = { + {xrpIssue(), std::nullopt, None, false}, + {std::nullopt, USD.issue(), None, false}, + {xrpIssue(), std::nullopt, Bogie, false}, + {std::nullopt, USD.issue(), Bogie, false}, + {xrpIssue(), USD.issue(), Bogie, false}, + {std::nullopt, std::nullopt, None, true}}; // Invalid parameters *and* invalid AMM account, default API version testAMM([&](AMM& ammAlice, Env&) { - for (auto const& [iss1, iss2, acct, ignoreParams] : - invalidParamsBadAccount) + for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount) { auto const jv = ammAlice.ammRpcInfo( - std::nullopt, - std::nullopt, - iss1, - iss2, - accountId(ammAlice, acct), - ignoreParams); + std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams); BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters."); } }); // Invalid parameters *and* invalid AMM account, API version 3 testAMM([&](AMM& ammAlice, Env&) { - for (auto const& [iss1, iss2, acct, ignoreParams] : - invalidParamsBadAccount) + for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount) { auto const jv = ammAlice.ammRpcInfo( - std::nullopt, - std::nullopt, - iss1, - iss2, - accountId(ammAlice, acct), - ignoreParams, - 3); + std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams, 3); BEAST_EXPECT( jv[jss::error_message] == - (acct == Bogie ? std::string("Account malformed.") - : std::string("Invalid parameters."))); + (acct == Bogie ? std::string("Account malformed.") : std::string("Invalid parameters."))); } }); } @@ -190,15 +138,9 @@ public: using namespace jtx; testAMM([&](AMM& ammAlice, Env&) { + BEAST_EXPECT(ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0})); BEAST_EXPECT(ammAlice.expectAmmRpcInfo( - XRP(10000), USD(10000), IOUAmount{10000000, 0})); - BEAST_EXPECT(ammAlice.expectAmmRpcInfo( - XRP(10000), - USD(10000), - IOUAmount{10000000, 0}, - std::nullopt, - std::nullopt, - ammAlice.ammAccount())); + XRP(10000), USD(10000), IOUAmount{10000000, 0}, std::nullopt, std::nullopt, ammAlice.ammAccount())); }); } @@ -210,8 +152,7 @@ public: using namespace jtx; testAMM( [&](AMM& ammAlice, Env& env) { - BEAST_EXPECT(ammAlice.expectAmmRpcInfo( - XRP(10000), USD(10000), IOUAmount{10000000, 0})); + BEAST_EXPECT(ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0})); std::unordered_map votes; votes.insert({alice.human(), 0}); for (int i = 0; i < 7; ++i) @@ -229,8 +170,7 @@ public: Account ed("ed"); Account bill("bill"); env.fund(XRP(1000), bob, ed, bill); - env(ammAlice.bid( - {.bidMin = 100, .authAccounts = {carol, bob, ed, bill}})); + env(ammAlice.bid({.bidMin = 100, .authAccounts = {carol, bob, ed, bill}})); if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectAmmRpcInfo( XRP(80000), @@ -251,13 +191,10 @@ public: { std::unordered_set authAccounts = { carol.human(), bob.human(), ed.human(), bill.human()}; - auto const ammInfo = i ? ammAlice.ammRpcInfo() - : ammAlice.ammRpcInfo( - std::nullopt, - std::nullopt, - std::nullopt, - std::nullopt, - ammAlice.ammAccount()); + auto const ammInfo = i + ? ammAlice.ammRpcInfo() + : ammAlice.ammRpcInfo( + std::nullopt, std::nullopt, std::nullopt, std::nullopt, ammAlice.ammAccount()); auto const& amm = ammInfo[jss::amm]; try { @@ -267,12 +204,9 @@ public: for (std::uint8_t i = 0; i < 8; ++i) { if (!BEAST_EXPECT( - votes[voteSlots[i][jss::account] - .asString()] == - voteSlots[i][jss::trading_fee] - .asUInt() && - voteSlots[i][jss::vote_weight].asUInt() == - 12500)) + votes[voteSlots[i][jss::account].asString()] == + voteSlots[i][jss::trading_fee].asUInt() && + voteSlots[i][jss::vote_weight].asUInt() == 12500)) return; votes.erase(voteSlots[i][jss::account].asString()); } @@ -284,27 +218,20 @@ public: auto const auctionSlot = amm[jss::auction_slot]; for (std::uint8_t i = 0; i < 4; ++i) { - if (!BEAST_EXPECT(authAccounts.contains( - auctionSlot[jss::auth_accounts][i] - [jss::account] - .asString()))) + if (!BEAST_EXPECT( + authAccounts.contains(auctionSlot[jss::auth_accounts][i][jss::account].asString()))) return; - authAccounts.erase( - auctionSlot[jss::auth_accounts][i][jss::account] - .asString()); + authAccounts.erase(auctionSlot[jss::auth_accounts][i][jss::account].asString()); } if (!BEAST_EXPECT(authAccounts.empty())) return; BEAST_EXPECT( - auctionSlot[jss::account].asString() == - alice.human() && + auctionSlot[jss::account].asString() == alice.human() && auctionSlot[jss::discounted_fee].asUInt() == 17 && - auctionSlot[jss::price][jss::value].asString() == - "5600" && + auctionSlot[jss::price][jss::value].asString() == "5600" && auctionSlot[jss::price][jss::currency].asString() == to_string(ammAlice.lptIssue().currency) && - auctionSlot[jss::price][jss::issuer].asString() == - to_string(ammAlice.lptIssue().account)); + auctionSlot[jss::price][jss::issuer].asString() == to_string(ammAlice.lptIssue().account)); } catch (std::exception const& e) { @@ -327,8 +254,7 @@ public: env.close(); auto test = [&](bool freeze) { auto const info = ammAlice.ammRpcInfo(); - BEAST_EXPECT( - info[jss::amm][jss::asset2_frozen].asBool() == freeze); + BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool() == freeze); }; test(true); env(fclear(gw, asfGlobalFreeze)); @@ -344,14 +270,8 @@ public: testcase("Invalid amm field"); testAMM([&](AMM& amm, Env&) { - auto const resp = amm.ammRpcInfo( - std::nullopt, - jss::validated.c_str(), - std::nullopt, - std::nullopt, - gw); - BEAST_EXPECT( - resp.isMember("error") && resp["error"] == "actNotFound"); + auto const resp = amm.ammRpcInfo(std::nullopt, jss::validated.c_str(), std::nullopt, std::nullopt, gw); + BEAST_EXPECT(resp.isMember("error") && resp["error"] == "actNotFound"); }); } @@ -369,7 +289,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AMMInfo, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AMMInfo, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountCurrencies_test.cpp b/src/test/rpc/AccountCurrencies_test.cpp index b21aacf865..f467b50adc 100644 --- a/src/test/rpc/AccountCurrencies_test.cpp +++ b/src/test/rpc/AccountCurrencies_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class AccountCurrencies_test : public beast::unit_test::suite { @@ -42,18 +23,15 @@ class AccountCurrencies_test : public beast::unit_test::suite Json::Value params; params[jss::account] = Account{"bob"}.human(); params[jss::ledger_hash] = 1; - auto const result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + auto const result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT(result[jss::error_message] == "ledgerHashNotString"); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'ledger_hash', not hex string."); } { // missing account field - auto const result = - env.rpc("json", "account_currencies", "{}")[jss::result]; + auto const result = env.rpc("json", "account_currencies", "{}")[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT( - result[jss::error_message] == "Missing field 'account'."); + BEAST_EXPECT(result[jss::error_message] == "Missing field 'account'."); } { @@ -61,13 +39,9 @@ class AccountCurrencies_test : public beast::unit_test::suite auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", - "account_currencies", - to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -83,13 +57,9 @@ class AccountCurrencies_test : public beast::unit_test::suite auto testInvalidIdentParam = [&](auto const& param) { Json::Value params; params[jss::ident] = param; - auto jrr = env.rpc( - "json", - "account_currencies", - to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'ident'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ident'."); }; testInvalidIdentParam(1); @@ -102,10 +72,8 @@ class AccountCurrencies_test : public beast::unit_test::suite { Json::Value params; - params[jss::account] = - "llIIOO"; // these are invalid in bitcoin alphabet - auto const result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + params[jss::account] = "llIIOO"; // these are invalid in bitcoin alphabet + auto const result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "actMalformed"); BEAST_EXPECT(result[jss::error_message] == "Account malformed."); } @@ -114,8 +82,7 @@ class AccountCurrencies_test : public beast::unit_test::suite // Cannot use a seed as account Json::Value params; params[jss::account] = "Bob"; - auto const result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + auto const result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "actMalformed"); BEAST_EXPECT(result[jss::error_message] == "Account malformed."); } @@ -123,8 +90,7 @@ class AccountCurrencies_test : public beast::unit_test::suite { // ask for nonexistent account Json::Value params; params[jss::account] = Account{"bob"}.human(); - auto const result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + auto const result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "actNotFound"); BEAST_EXPECT(result[jss::error_message] == "Account not found."); } @@ -152,20 +118,14 @@ class AccountCurrencies_test : public beast::unit_test::suite Json::Value params; params[jss::account] = alice.human(); - auto result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + auto result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; - auto arrayCheck = - [&result]( - Json::StaticString const& fld, - std::vector> const& expected) -> bool { - bool stat = result.isMember(fld) && result[fld].isArray() && - result[fld].size() == expected.size(); + auto arrayCheck = [&result]( + Json::StaticString const& fld, std::vector> const& expected) -> bool { + bool stat = result.isMember(fld) && result[fld].isArray() && result[fld].size() == expected.size(); for (size_t i = 0; stat && i < expected.size(); ++i) { - stat &= - (to_string(expected[i].value().currency) == - result[fld][i].asString()); + stat &= (to_string(expected[i].value().currency) == result[fld][i].asString()); } return stat; }; @@ -178,8 +138,7 @@ class AccountCurrencies_test : public beast::unit_test::suite env(pay(gw, alice, c.value()(50))); // send_currencies should be populated now - result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies)); BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies)); @@ -188,10 +147,8 @@ class AccountCurrencies_test : public beast::unit_test::suite env(trust(alice, gw["USD"](100), tfSetFreeze)); result = env.rpc("account_lines", alice.human()); for (auto const& l : result[jss::lines]) - BEAST_EXPECT( - l[jss::freeze].asBool() == (l[jss::currency] == "USD")); - result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + BEAST_EXPECT(l[jss::freeze].asBool() == (l[jss::currency] == "USD")); + result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies)); BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies)); // clear the freeze @@ -200,10 +157,8 @@ class AccountCurrencies_test : public beast::unit_test::suite // make a payment that exhausts the trustline from alice to gw for USA env(pay(gw, alice, gw["USA"](50))); // USA should now be missing from receive_currencies - result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; - decltype(gwCurrencies) gwCurrenciesNoUSA( - gwCurrencies.begin() + 1, gwCurrencies.end()); + result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; + decltype(gwCurrencies) gwCurrenciesNoUSA(gwCurrencies.begin() + 1, gwCurrencies.end()); BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrenciesNoUSA)); BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies)); @@ -211,8 +166,7 @@ class AccountCurrencies_test : public beast::unit_test::suite // so that send_currencies for alice will now omit USA env(trust(gw, alice["USA"](100))); env(pay(alice, gw, alice["USA"](200))); - result = env.rpc( - "json", "account_currencies", to_string(params))[jss::result]; + result = env.rpc("json", "account_currencies", to_string(params))[jss::result]; BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies)); BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrenciesNoUSA)); } @@ -226,6 +180,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AccountCurrencies, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountCurrencies, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 32a1202622..bdc8e63e3d 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class AccountInfo_test : public beast::unit_test::suite @@ -39,9 +20,7 @@ public: { // account_info with no account. auto const info = env.rpc("json", "account_info", "{ }"); - BEAST_EXPECT( - info[jss::result][jss::error_message] == - "Missing field 'account'."); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Missing field 'account'."); } { // account_info with a malformed account string. @@ -50,31 +29,23 @@ public: "account_info", "{\"account\": " "\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}"); - BEAST_EXPECT( - info[jss::result][jss::error_code] == rpcACT_MALFORMED); - BEAST_EXPECT( - info[jss::result][jss::error_message] == "Account malformed."); + BEAST_EXPECT(info[jss::result][jss::error_code] == rpcACT_MALFORMED); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed."); } { // account_info with an account that's not in the ledger. Account const bogie{"bogie"}; Json::Value params; params[jss::account] = bogie.human(); - auto const info = - env.rpc("json", "account_info", to_string(params)); - BEAST_EXPECT( - info[jss::result][jss::error_code] == rpcACT_NOT_FOUND); - BEAST_EXPECT( - info[jss::result][jss::error_message] == "Account not found."); + auto const info = env.rpc("json", "account_info", to_string(params)); + BEAST_EXPECT(info[jss::result][jss::error_code] == rpcACT_NOT_FOUND); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Account not found."); } { // Cannot use a seed as account - auto const info = - env.rpc("json", "account_info", R"({"account": "foo"})"); - BEAST_EXPECT( - info[jss::result][jss::error_code] == rpcACT_MALFORMED); - BEAST_EXPECT( - info[jss::result][jss::error_message] == "Account malformed."); + auto const info = env.rpc("json", "account_info", R"({"account": "foo"})"); + BEAST_EXPECT(info[jss::result][jss::error_code] == rpcACT_MALFORMED); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed."); } { // Cannot pass a non-string into the `account` param @@ -82,11 +53,9 @@ public: auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_info", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_info", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -102,11 +71,9 @@ public: auto testInvalidIdentParam = [&](auto const& param) { Json::Value params; params[jss::ident] = param; - auto jrr = env.rpc( - "json", "account_info", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_info", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'ident'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ident'."); }; testInvalidIdentParam(1); @@ -138,21 +105,14 @@ public: // Alice has no SignerList yet. { // account_info without the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withoutSigners)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); - BEAST_EXPECT(!info[jss::result][jss::account_data].isMember( - jss::signer_lists)); + auto const info = env.rpc("json", "account_info", to_string(withoutSigners)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists)); } { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; @@ -167,21 +127,14 @@ public: env(smallSigners); { // account_info without the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withoutSigners)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); - BEAST_EXPECT(!info[jss::result][jss::account_data].isMember( - jss::signer_lists)); + auto const info = env.rpc("json", "account_info", to_string(withoutSigners)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists)); } { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; @@ -221,11 +174,8 @@ public: env(bigSigners); { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; @@ -265,22 +215,19 @@ public: withSigners[jss::account] = alice.human(); withSigners[jss::signer_lists] = true; - auto const withSignersAsString = std::string("{ ") + - "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " + - "\"signer_lists\": asdfggh }"; + auto const withSignersAsString = std::string("{ ") + "\"api_version\": 2, \"account\": \"" + alice.human() + + "\", " + "\"signer_lists\": asdfggh }"; // Alice has no SignerList yet. { // account_info without the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withoutSigners)); + auto const info = env.rpc("json", "account_info", to_string(withoutSigners)); BEAST_EXPECT(info.isMember(jss::result)); BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists)); } { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -296,15 +243,13 @@ public: env(smallSigners); { // account_info without the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withoutSigners)); + auto const info = env.rpc("json", "account_info", to_string(withoutSigners)); BEAST_EXPECT(info.isMember(jss::result)); BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists)); } { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -321,8 +266,7 @@ public: } { // account_info with "signer_lists" as not bool should error out - auto const info = - env.rpc("json", "account_info", withSignersAsString); + auto const info = env.rpc("json", "account_info", withSignersAsString); BEAST_EXPECT(info[jss::status] == "error"); BEAST_EXPECT(info[jss::error] == "invalidParams"); } @@ -352,8 +296,7 @@ public: env(bigSigners); { // account_info with the "signer_lists" argument. - auto const info = - env.rpc("json", "account_info", to_string(withSigners)); + auto const info = env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -406,65 +349,42 @@ public: { // account_info without the "signer_lists" argument. auto const info = env.rpc("json2", withoutSigners); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); - BEAST_EXPECT(!info[jss::result][jss::account_data].isMember( - jss::signer_lists)); - BEAST_EXPECT( - info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists)); + BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5); } { // account_info with the "signer_lists" argument. auto const info = env.rpc("json2", withSigners); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; BEAST_EXPECT(signerLists.isArray()); BEAST_EXPECT(signerLists.size() == 0); - BEAST_EXPECT( - info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6); } { // Do both of the above as a batch job - auto const info = env.rpc( - "json2", '[' + withoutSigners + ", " + withSigners + ']'); - BEAST_EXPECT( - info[0u].isMember(jss::result) && - info[0u][jss::result].isMember(jss::account_data)); - BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember( - jss::signer_lists)); - BEAST_EXPECT( - info[0u].isMember(jss::jsonrpc) && - info[0u][jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info[0u].isMember(jss::ripplerpc) && - info[0u][jss::ripplerpc] == "2.0"); + auto const info = env.rpc("json2", '[' + withoutSigners + ", " + withSigners + ']'); + BEAST_EXPECT(info[0u].isMember(jss::result) && info[0u][jss::result].isMember(jss::account_data)); + BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember(jss::signer_lists)); + BEAST_EXPECT(info[0u].isMember(jss::jsonrpc) && info[0u][jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info[0u].isMember(jss::ripplerpc) && info[0u][jss::ripplerpc] == "2.0"); BEAST_EXPECT(info[0u].isMember(jss::id) && info[0u][jss::id] == 5); - BEAST_EXPECT( - info[1u].isMember(jss::result) && - info[1u][jss::result].isMember(jss::account_data)); + BEAST_EXPECT(info[1u].isMember(jss::result) && info[1u][jss::result].isMember(jss::account_data)); auto const& data = info[1u][jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; BEAST_EXPECT(signerLists.isArray()); BEAST_EXPECT(signerLists.size() == 0); - BEAST_EXPECT( - info[1u].isMember(jss::jsonrpc) && - info[1u][jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info[1u].isMember(jss::ripplerpc) && - info[1u][jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info[1u].isMember(jss::jsonrpc) && info[1u][jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info[1u].isMember(jss::ripplerpc) && info[1u][jss::ripplerpc] == "2.0"); BEAST_EXPECT(info[1u].isMember(jss::id) && info[1u][jss::id] == 6); } @@ -476,23 +396,16 @@ public: { // account_info without the "signer_lists" argument. auto const info = env.rpc("json2", withoutSigners); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); - BEAST_EXPECT(!info[jss::result][jss::account_data].isMember( - jss::signer_lists)); - BEAST_EXPECT( - info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists)); + BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5); } { // account_info with the "signer_lists" argument. auto const info = env.rpc("json2", withSigners); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; @@ -505,10 +418,8 @@ public: BEAST_EXPECT(signerEntries.size() == 1); auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName]; BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3); - BEAST_EXPECT( - info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6); } @@ -538,9 +449,7 @@ public: { // account_info with the "signer_lists" argument. auto const info = env.rpc("json2", withSigners); - BEAST_EXPECT( - info.isMember(jss::result) && - info[jss::result].isMember(jss::account_data)); + BEAST_EXPECT(info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); auto const& data = info[jss::result][jss::account_data]; BEAST_EXPECT(data.isMember(jss::signer_lists)); auto const& signerLists = data[jss::signer_lists]; @@ -558,10 +467,8 @@ public: BEAST_EXPECT(entry.isMember(sfAccount.jsonName)); BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1); } - BEAST_EXPECT( - info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0"); BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6); } } @@ -577,33 +484,27 @@ public: Account const bob{"bob"}; env.fund(XRP(1000), alice, bob); - auto getAccountFlag = [&env]( - std::string_view fName, - Account const& account) { + auto getAccountFlag = [&env](std::string_view fName, Account const& account) { Json::Value params; params[jss::account] = account.human(); - auto const info = - env.rpc("json", "account_info", to_string(params)); + auto const info = env.rpc("json", "account_info", to_string(params)); std::optional res; if (info[jss::result][jss::status] == "success" && info[jss::result][jss::account_flags].isMember(fName.data())) - res.emplace(info[jss::result][jss::account_flags][fName.data()] - .asBool()); + res.emplace(info[jss::result][jss::account_flags][fName.data()].asBool()); return res; }; - static constexpr std:: - array, 7> - asFlags{ - {{"defaultRipple", asfDefaultRipple}, - {"depositAuth", asfDepositAuth}, - {"disallowIncomingXRP", asfDisallowXRP}, - {"globalFreeze", asfGlobalFreeze}, - {"noFreeze", asfNoFreeze}, - {"requireAuthorization", asfRequireAuth}, - {"requireDestinationTag", asfRequireDest}}}; + static constexpr std::array, 7> asFlags{ + {{"defaultRipple", asfDefaultRipple}, + {"depositAuth", asfDepositAuth}, + {"disallowIncomingXRP", asfDisallowXRP}, + {"globalFreeze", asfGlobalFreeze}, + {"noFreeze", asfNoFreeze}, + {"requireAuthorization", asfRequireAuth}, + {"requireDestinationTag", asfRequireDest}}}; for (auto& asf : asFlags) { @@ -624,87 +525,66 @@ public: BEAST_EXPECT(f2.value()); } - static constexpr std:: - array, 4> - disallowIncomingFlags{ - {{"disallowIncomingCheck", asfDisallowIncomingCheck}, - {"disallowIncomingNFTokenOffer", - asfDisallowIncomingNFTokenOffer}, - {"disallowIncomingPayChan", asfDisallowIncomingPayChan}, - {"disallowIncomingTrustline", - asfDisallowIncomingTrustline}}}; + static constexpr std::array, 4> disallowIncomingFlags{ + {{"disallowIncomingCheck", asfDisallowIncomingCheck}, + {"disallowIncomingNFTokenOffer", asfDisallowIncomingNFTokenOffer}, + {"disallowIncomingPayChan", asfDisallowIncomingPayChan}, + {"disallowIncomingTrustline", asfDisallowIncomingTrustline}}}; - if (features[featureDisallowIncoming]) + for (auto& asf : disallowIncomingFlags) { - for (auto& asf : disallowIncomingFlags) - { - // Clear a flag and check that account_info returns results - // as expected - env(fclear(alice, asf.second)); - env.close(); - auto const f1 = getAccountFlag(asf.first, alice); - BEAST_EXPECT(f1.has_value()); - BEAST_EXPECT(!f1.value()); + // Clear a flag and check that account_info returns results + // as expected + env(fclear(alice, asf.second)); + env.close(); + auto const f1 = getAccountFlag(asf.first, alice); + BEAST_EXPECT(f1.has_value()); + BEAST_EXPECT(!f1.value()); - // Set a flag and check that account_info returns results - // as expected - env(fset(alice, asf.second)); - env.close(); - auto const f2 = getAccountFlag(asf.first, alice); - BEAST_EXPECT(f2.has_value()); - BEAST_EXPECT(f2.value()); - } - } - else - { - for (auto& asf : disallowIncomingFlags) - { - BEAST_EXPECT(!getAccountFlag(asf.first, alice)); - } + // Set a flag and check that account_info returns results + // as expected + env(fset(alice, asf.second)); + env.close(); + auto const f2 = getAccountFlag(asf.first, alice); + BEAST_EXPECT(f2.has_value()); + BEAST_EXPECT(f2.value()); } - static constexpr std::pair - allowTrustLineClawbackFlag{ - "allowTrustLineClawback", asfAllowTrustLineClawback}; + static constexpr std::pair allowTrustLineClawbackFlag{ + "allowTrustLineClawback", asfAllowTrustLineClawback}; if (features[featureClawback]) { // must use bob's account because alice has noFreeze set - auto const f1 = - getAccountFlag(allowTrustLineClawbackFlag.first, bob); + auto const f1 = getAccountFlag(allowTrustLineClawbackFlag.first, bob); BEAST_EXPECT(f1.has_value()); BEAST_EXPECT(!f1.value()); // Set allowTrustLineClawback env(fset(bob, allowTrustLineClawbackFlag.second)); env.close(); - auto const f2 = - getAccountFlag(allowTrustLineClawbackFlag.first, bob); + auto const f2 = getAccountFlag(allowTrustLineClawbackFlag.first, bob); BEAST_EXPECT(f2.has_value()); BEAST_EXPECT(f2.value()); } else { - BEAST_EXPECT( - !getAccountFlag(allowTrustLineClawbackFlag.first, bob)); + BEAST_EXPECT(!getAccountFlag(allowTrustLineClawbackFlag.first, bob)); } - static constexpr std::pair - allowTrustLineLockingFlag{ - "allowTrustLineLocking", asfAllowTrustLineLocking}; + static constexpr std::pair allowTrustLineLockingFlag{ + "allowTrustLineLocking", asfAllowTrustLineLocking}; if (features[featureTokenEscrow]) { - auto const f1 = - getAccountFlag(allowTrustLineLockingFlag.first, bob); + auto const f1 = getAccountFlag(allowTrustLineLockingFlag.first, bob); BEAST_EXPECT(f1.has_value()); BEAST_EXPECT(!f1.value()); // Set allowTrustLineLocking env(fset(bob, allowTrustLineLockingFlag.second)); env.close(); - auto const f2 = - getAccountFlag(allowTrustLineLockingFlag.first, bob); + auto const f2 = getAccountFlag(allowTrustLineLockingFlag.first, bob); BEAST_EXPECT(f2.has_value()); BEAST_EXPECT(f2.value()); } @@ -722,19 +602,14 @@ public: testSignerListsApiVersion2(); testSignerListsV2(); - FeatureBitset const allFeatures{ - ripple::test::jtx::testable_amendments()}; + FeatureBitset const allFeatures{xrpl::test::jtx::testable_amendments()}; testAccountFlags(allFeatures); - testAccountFlags(allFeatures - featureDisallowIncoming); - testAccountFlags( - allFeatures - featureDisallowIncoming - featureClawback); - testAccountFlags( - allFeatures - featureDisallowIncoming - featureClawback - - featureTokenEscrow); + testAccountFlags(allFeatures - featureClawback); + testAccountFlags(allFeatures - featureClawback - featureTokenEscrow); } }; -BEAST_DEFINE_TESTSUITE(AccountInfo, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountInfo, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountLines_test.cpp b/src/test/rpc/AccountLines_test.cpp index 10d8c1b4ac..1f5f190cfa 100644 --- a/src/test/rpc/AccountLines_test.cpp +++ b/src/test/rpc/AccountLines_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace RPC { class AccountLines_test : public beast::unit_test::suite @@ -41,30 +22,24 @@ public: // account_lines with no account. auto const lines = env.rpc("json", "account_lines", "{ }"); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::missing_field_error(jss::account)[jss::error_message]); + lines[jss::result][jss::error_message] == RPC::missing_field_error(jss::account)[jss::error_message]); } { // account_lines with a malformed account. Json::Value params; - params[jss::account] = - "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + params[jss::account] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); + lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); } { // test account non-string auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_lines", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_lines", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -79,23 +54,20 @@ public: // account_lines on an unfunded account. Json::Value params; params[jss::account] = alice.human(); - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); + lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); } env.fund(XRP(10000), alice); env.close(); - LedgerInfo const ledger3Info = env.closed()->info(); + LedgerHeader const ledger3Info = env.closed()->header(); BEAST_EXPECT(ledger3Info.seq == 3); { // alice is funded but has no lines. An empty array is returned. Json::Value params; params[jss::account] = alice.human(); - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0); } @@ -104,21 +76,17 @@ public: Json::Value params; params[jss::account] = alice.human(); params[jss::ledger_index] = "nonsense"; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - "ledgerIndexMalformed"); + lines[jss::result][jss::error_message] == "Invalid field 'ledger_index', not string or number."); } { // Specify a different ledger that doesn't exist. Json::Value params; params[jss::account] = alice.human(); params[jss::ledger_index] = 50000; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); - BEAST_EXPECT( - lines[jss::result][jss::error_message] == "ledgerNotFound"); + auto const lines = env.rpc("json", "account_lines", to_string(params)); + BEAST_EXPECT(lines[jss::result][jss::error_message] == "ledgerNotFound"); } // Create trust lines to share with alice. Account const gw1{"gw1"}; @@ -128,8 +96,7 @@ public: for (char c = 0; c <= ('Z' - 'A'); ++c) { // gw1 currencies have names "YAA" -> "YAZ". - gw1Currencies.push_back( - gw1[std::string("YA") + static_cast('A' + c)]); + gw1Currencies.push_back(gw1[std::string("YA") + static_cast('A' + c)]); IOU const& gw1Currency = gw1Currencies.back(); // Establish trust lines. @@ -137,7 +104,7 @@ public: env(pay(gw1, alice, gw1Currency(50 + c))); } env.close(); - LedgerInfo const ledger4Info = env.closed()->info(); + LedgerHeader const ledger4Info = env.closed()->header(); BEAST_EXPECT(ledger4Info.seq == 4); // Add another set of trust lines in another ledger so we can see @@ -153,8 +120,7 @@ public: for (char c = 0; c <= ('Z' - 'A'); ++c) { // gw2 currencies have names "ZAA" -> "ZAZ". - gw2Currencies.push_back( - gw2[std::string("ZA") + static_cast('A' + c)]); + gw2Currencies.push_back(gw2[std::string("ZA") + static_cast('A' + c)]); IOU const& gw2Currency = gw2Currencies.back(); // Establish trust lines. @@ -165,27 +131,19 @@ public: env.close(); // Set flags on gw2 trust lines so we can look for them. - env(trust( - alice, - gw2Currency(0), - gw2, - tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze)); + env(trust(alice, gw2Currency(0), gw2, tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze)); } env.close(); - LedgerInfo const ledger58Info = env.closed()->info(); + LedgerHeader const ledger58Info = env.closed()->header(); BEAST_EXPECT(ledger58Info.seq == 58); // A re-usable test for historic ledgers. - auto testAccountLinesHistory = [this, &env]( - Account const& account, - LedgerInfo const& info, - int count) { + auto testAccountLinesHistory = [this, &env](Account const& account, LedgerHeader const& info, int count) { // Get account_lines by ledger index. Json::Value paramsSeq; paramsSeq[jss::account] = account.human(); paramsSeq[jss::ledger_index] = info.seq; - auto const linesSeq = - env.rpc("json", "account_lines", to_string(paramsSeq)); + auto const linesSeq = env.rpc("json", "account_lines", to_string(paramsSeq)); BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count); @@ -193,8 +151,7 @@ public: Json::Value paramsHash; paramsHash[jss::account] = account.human(); paramsHash[jss::ledger_hash] = to_string(info.hash); - auto const linesHash = - env.rpc("json", "account_lines", to_string(paramsHash)); + auto const linesHash = env.rpc("json", "account_lines", to_string(paramsHash)); BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count); }; @@ -209,23 +166,32 @@ public: testAccountLinesHistory(alice, ledger58Info, 52); { - // Surprisingly, it's valid to specify both index and hash, in - // which case the hash wins. + // Invalid to specify both index and hash Json::Value params; params[jss::account] = alice.human(); params[jss::ledger_hash] = to_string(ledger4Info.hash); params[jss::ledger_index] = ledger58Info.seq; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); - BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); - BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); + auto const lines = env.rpc("json", "account_lines", to_string(params))[jss::result]; + BEAST_EXPECT(lines[jss::error] == "invalidParams"); + BEAST_EXPECT( + lines[jss::error_message] == + "Exactly one of 'ledger_hash' or 'ledger_index' can be " + "specified."); + } + { + // Invalid index + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_index] = Json::objectValue; + auto const lines = env.rpc("json", "account_lines", to_string(params))[jss::result]; + BEAST_EXPECT(lines[jss::error] == "invalidParams"); + BEAST_EXPECT(lines[jss::error_message] == "Invalid field 'ledger_index', not string or number."); } { // alice should have 52 trust lines in the current ledger. Json::Value params; params[jss::account] = alice.human(); - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52); } @@ -234,8 +200,7 @@ public: Json::Value params; params[jss::account] = alice.human(); params[jss::peer] = gw1.human(); - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); @@ -247,32 +212,26 @@ public: // Use a malformed peer. Json::Value params; params[jss::account] = alice.human(); - params[jss::peer] = - "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + params[jss::peer] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); + lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); } { // A negative limit should fail. Json::Value params; params[jss::account] = alice.human(); params[jss::limit] = -1; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::expected_field_message(jss::limit, "unsigned integer")); + lines[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); } { // Limit the response to 1 trust line. Json::Value paramsA; paramsA[jss::account] = alice.human(); paramsA[jss::limit] = 1; - auto const linesA = - env.rpc("json", "account_lines", to_string(paramsA)); + auto const linesA = env.rpc("json", "account_lines", to_string(paramsA)); BEAST_EXPECT(linesA[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1); @@ -281,8 +240,7 @@ public: Json::Value paramsB; paramsB[jss::account] = alice.human(); paramsB[jss::marker] = marker; - auto const linesB = - env.rpc("json", "account_lines", to_string(paramsB)); + auto const linesB = env.rpc("json", "account_lines", to_string(paramsB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51); @@ -291,8 +249,7 @@ public: paramsC[jss::account] = alice.human(); paramsC[jss::limit] = 3; paramsC[jss::marker] = marker; - auto const linesC = - env.rpc("json", "account_lines", to_string(paramsC)); + auto const linesC = env.rpc("json", "account_lines", to_string(paramsC)); BEAST_EXPECT(linesC[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3); @@ -301,22 +258,17 @@ public: Json::Value paramsD; paramsD[jss::account] = alice.human(); paramsD[jss::marker] = marker; - auto const linesD = - env.rpc("json", "account_lines", to_string(paramsD)); + auto const linesD = env.rpc("json", "account_lines", to_string(paramsD)); BEAST_EXPECT( - linesD[jss::result][jss::error_message] == - RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); + linesD[jss::result][jss::error_message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); } { // A non-string marker should also fail. Json::Value params; params[jss::account] = alice.human(); params[jss::marker] = true; - auto const lines = - env.rpc("json", "account_lines", to_string(params)); - BEAST_EXPECT( - lines[jss::result][jss::error_message] == - RPC::expected_field_message(jss::marker, "string")); + auto const lines = env.rpc("json", "account_lines", to_string(params)); + BEAST_EXPECT(lines[jss::result][jss::error_message] == RPC::expected_field_message(jss::marker, "string")); } { // Check that the flags we expect from alice to gw2 are present. @@ -324,8 +276,7 @@ public: params[jss::account] = alice.human(); params[jss::limit] = 10; params[jss::peer] = gw2.human(); - auto const lines = - env.rpc("json", "account_lines", to_string(params)); + auto const lines = env.rpc("json", "account_lines", to_string(params)); auto const& line = lines[jss::result][jss::lines][0u]; BEAST_EXPECT(line[jss::freeze].asBool() == true); BEAST_EXPECT(line[jss::deep_freeze].asBool() == true); @@ -338,8 +289,7 @@ public: paramsA[jss::account] = gw2.human(); paramsA[jss::limit] = 1; paramsA[jss::peer] = alice.human(); - auto const linesA = - env.rpc("json", "account_lines", to_string(paramsA)); + auto const linesA = env.rpc("json", "account_lines", to_string(paramsA)); auto const& lineA = linesA[jss::result][jss::lines][0u]; BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true); BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true); @@ -354,8 +304,7 @@ public: paramsB[jss::limit] = 25; paramsB[jss::marker] = marker; paramsB[jss::peer] = alice.human(); - auto const linesB = - env.rpc("json", "account_lines", to_string(paramsB)); + auto const linesB = env.rpc("json", "account_lines", to_string(paramsB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25); BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker)); @@ -398,10 +347,8 @@ public: Json::Value aliceObjectsParams; aliceObjectsParams[jss::account] = alice.human(); aliceObjectsParams[jss::limit] = 10; - Json::Value const aliceObjects = - env.rpc("json", "account_objects", to_string(aliceObjectsParams)); - Json::Value const& aliceSignerList = - aliceObjects[jss::result][jss::account_objects][0u]; + Json::Value const aliceObjects = env.rpc("json", "account_objects", to_string(aliceObjectsParams)); + Json::Value const& aliceSignerList = aliceObjects[jss::result][jss::account_objects][0u]; if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList)) { fail( @@ -417,33 +364,28 @@ public: Json::Value aliceLines1Params; aliceLines1Params[jss::account] = alice.human(); aliceLines1Params[jss::limit] = 1; - auto const aliceLines1 = - env.rpc("json", "account_lines", to_string(aliceLines1Params)); + auto const aliceLines1 = env.rpc("json", "account_lines", to_string(aliceLines1Params)); BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker)); // Verify that the marker points at the signer list. - std::string const aliceMarker = - aliceLines1[jss::result][jss::marker].asString(); - std::string const markerIndex = - aliceMarker.substr(0, aliceMarker.find(',')); + std::string const aliceMarker = aliceLines1[jss::result][jss::marker].asString(); + std::string const markerIndex = aliceMarker.substr(0, aliceMarker.find(',')); BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString()); // When we fetch Alice's remaining lines we should find one and no more. Json::Value aliceLines2Params; aliceLines2Params[jss::account] = alice.human(); aliceLines2Params[jss::marker] = aliceMarker; - auto const aliceLines2 = - env.rpc("json", "account_lines", to_string(aliceLines2Params)); + auto const aliceLines2 = env.rpc("json", "account_lines", to_string(aliceLines2Params)); BEAST_EXPECT(aliceLines2[jss::result][jss::lines].size() == 1); BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker)); - // Get account lines for beckys account, using alices SignerList as a + // Get account lines for becky's account, using alice's SignerList as a // marker. This should cause an error. Json::Value beckyLinesParams; beckyLinesParams[jss::account] = becky.human(); beckyLinesParams[jss::marker] = aliceMarker; - auto const beckyLines = - env.rpc("json", "account_lines", to_string(beckyLinesParams)); + auto const beckyLines = env.rpc("json", "account_lines", to_string(beckyLinesParams)); BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message)); } @@ -498,10 +440,8 @@ public: Json::Value linesBegParams; linesBegParams[jss::account] = alice.human(); linesBegParams[jss::limit] = 2; - auto const linesBeg = - env.rpc("json", "account_lines", to_string(linesBegParams)); - BEAST_EXPECT( - linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); + auto const linesBeg = env.rpc("json", "account_lines", to_string(linesBegParams)); + BEAST_EXPECT(linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker)); // alice pays 100 EUR to cheri. @@ -513,11 +453,9 @@ public: Json::Value linesEndParams; linesEndParams[jss::account] = alice.human(); linesEndParams[jss::marker] = linesBeg[jss::result][jss::marker]; - auto const linesEnd = - env.rpc("json", "account_lines", to_string(linesEndParams)); + auto const linesEnd = env.rpc("json", "account_lines", to_string(linesEndParams)); BEAST_EXPECT( - linesEnd[jss::result][jss::error_message] == - RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); + linesEnd[jss::result][jss::error_message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); } void @@ -575,48 +513,32 @@ public: env.close(); // Escrow, in each direction - env(escrow::create(alice, becky, XRP(1000)), - escrow::finish_time(env.now() + 1s)); - env(escrow::create(becky, alice, XRP(1000)), - escrow::finish_time(env.now() + 1s)); + env(escrow::create(alice, becky, XRP(1000)), escrow::finish_time(env.now() + 1s)); + env(escrow::create(becky, alice, XRP(1000)), escrow::finish_time(env.now() + 1s)); // Pay channels, in each direction env(payChan(alice, becky, XRP(1000), 100s, alice.pk())); env(payChan(becky, alice, XRP(1000), 100s, becky.pk())); // Mint NFTs, for each account - uint256 const aliceNFtokenID = - token::getNextID(env, alice, 0, tfTransferable); + uint256 const aliceNFtokenID = token::getNextID(env, alice, 0, tfTransferable); env(token::mint(alice, 0), txflags(tfTransferable)); - uint256 const beckyNFtokenID = - token::getNextID(env, becky, 0, tfTransferable); + uint256 const beckyNFtokenID = token::getNextID(env, becky, 0, tfTransferable); env(token::mint(becky, 0), txflags(tfTransferable)); // NFT Offers, for each other's NFTs - env(token::createOffer(alice, beckyNFtokenID, drops(1)), - token::owner(becky)); - env(token::createOffer(becky, aliceNFtokenID, drops(1)), - token::owner(alice)); + env(token::createOffer(alice, beckyNFtokenID, drops(1)), token::owner(becky)); + env(token::createOffer(becky, aliceNFtokenID, drops(1)), token::owner(alice)); - env(token::createOffer(becky, beckyNFtokenID, drops(1)), - txflags(tfSellNFToken), - token::destination(alice)); - env(token::createOffer(alice, aliceNFtokenID, drops(1)), - txflags(tfSellNFToken), - token::destination(becky)); + env(token::createOffer(becky, beckyNFtokenID, drops(1)), txflags(tfSellNFToken), token::destination(alice)); + env(token::createOffer(alice, aliceNFtokenID, drops(1)), txflags(tfSellNFToken), token::destination(becky)); - env(token::createOffer(gw1, beckyNFtokenID, drops(1)), - token::owner(becky), - token::destination(alice)); - env(token::createOffer(gw1, aliceNFtokenID, drops(1)), - token::owner(alice), - token::destination(becky)); + env(token::createOffer(gw1, beckyNFtokenID, drops(1)), token::owner(becky), token::destination(alice)); + env(token::createOffer(gw1, aliceNFtokenID, drops(1)), token::owner(alice), token::destination(becky)); - env(token::createOffer(becky, beckyNFtokenID, drops(1)), - txflags(tfSellNFToken)); - env(token::createOffer(alice, aliceNFtokenID, drops(1)), - txflags(tfSellNFToken)); + env(token::createOffer(becky, beckyNFtokenID, drops(1)), txflags(tfSellNFToken)); + env(token::createOffer(alice, aliceNFtokenID, drops(1)), txflags(tfSellNFToken)); // Checks, in each direction env(check::create(alice, becky, XRP(50))); @@ -645,9 +567,7 @@ public: // Now make repeated calls to `account_lines` with a limit of 1. // That should iterate all of alice's relevant objects, even though // the list will be empty for most calls. - auto getNextLine = [](Env& env, - Account const& alice, - std::optional const marker) { + auto getNextLine = [](Env& env, Account const& alice, std::optional const marker) { Json::Value params(Json::objectValue); params[jss::account] = alice.human(); params[jss::limit] = 1; @@ -663,17 +583,11 @@ public: constexpr std::size_t expectedNFTs = 1; std::size_t foundLines = 0; - auto hasMarker = [](auto const& aliceLines) { - return aliceLines[jss::result].isMember(jss::marker); - }; - auto marker = [](auto const& aliceLines) { - return aliceLines[jss::result][jss::marker].asString(); - }; + auto hasMarker = [](auto const& aliceLines) { return aliceLines[jss::result].isMember(jss::marker); }; + auto marker = [](auto const& aliceLines) { return aliceLines[jss::result][jss::marker].asString(); }; auto checkLines = [](auto const& aliceLines) { - return aliceLines.isMember(jss::result) && - !aliceLines[jss::result].isMember(jss::error_message) && - aliceLines[jss::result].isMember(jss::lines) && - aliceLines[jss::result][jss::lines].isArray() && + return aliceLines.isMember(jss::result) && !aliceLines[jss::result].isMember(jss::error_message) && + aliceLines[jss::result].isMember(jss::lines) && aliceLines[jss::result][jss::lines].isArray() && aliceLines[jss::result][jss::lines].size() <= 1; }; @@ -696,39 +610,28 @@ public: Json::Value aliceObjectsParams2; aliceObjectsParams2[jss::account] = alice.human(); aliceObjectsParams2[jss::limit] = 200; - Json::Value const aliceObjects = env.rpc( - "json", "account_objects", to_string(aliceObjectsParams2)); + Json::Value const aliceObjects = env.rpc("json", "account_objects", to_string(aliceObjectsParams2)); BEAST_EXPECT(aliceObjects.isMember(jss::result)); - BEAST_EXPECT( - !aliceObjects[jss::result].isMember(jss::error_message)); - BEAST_EXPECT( - aliceObjects[jss::result].isMember(jss::account_objects)); - BEAST_EXPECT( - aliceObjects[jss::result][jss::account_objects].isArray()); + BEAST_EXPECT(!aliceObjects[jss::result].isMember(jss::error_message)); + BEAST_EXPECT(aliceObjects[jss::result].isMember(jss::account_objects)); + BEAST_EXPECT(aliceObjects[jss::result][jss::account_objects].isArray()); // account_objects does not currently return NFTPages. If // that ever changes, without also changing account_lines, // this test will need to be updated. - BEAST_EXPECT( - aliceObjects[jss::result][jss::account_objects].size() == - iterations + expectedNFTs); + BEAST_EXPECT(aliceObjects[jss::result][jss::account_objects].size() == iterations + expectedNFTs); // If ledger object association ever changes, for whatever // reason, this test will need to be updated. - BEAST_EXPECTS( - iterations == expectedIterations, std::to_string(iterations)); + BEAST_EXPECTS(iterations == expectedIterations, std::to_string(iterations)); // Get becky's objects just to confirm that they're symmetrical Json::Value beckyObjectsParams; beckyObjectsParams[jss::account] = becky.human(); beckyObjectsParams[jss::limit] = 200; - Json::Value const beckyObjects = env.rpc( - "json", "account_objects", to_string(beckyObjectsParams)); + Json::Value const beckyObjects = env.rpc("json", "account_objects", to_string(beckyObjectsParams)); BEAST_EXPECT(beckyObjects.isMember(jss::result)); - BEAST_EXPECT( - !beckyObjects[jss::result].isMember(jss::error_message)); - BEAST_EXPECT( - beckyObjects[jss::result].isMember(jss::account_objects)); - BEAST_EXPECT( - beckyObjects[jss::result][jss::account_objects].isArray()); + BEAST_EXPECT(!beckyObjects[jss::result].isMember(jss::error_message)); + BEAST_EXPECT(beckyObjects[jss::result].isMember(jss::account_objects)); + BEAST_EXPECT(beckyObjects[jss::result][jss::account_objects].isArray()); // becky should have the same number of objects as alice, except the // 2 tickets that only alice created. BEAST_EXPECT( @@ -752,11 +655,8 @@ public: request[jss::jsonrpc] = "2.0"; request[jss::ripplerpc] = "2.0"; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); } { // account_lines with no account. @@ -766,21 +666,15 @@ public: request[jss::ripplerpc] = "2.0"; request[jss::id] = 5; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::missing_field_error(jss::account)[jss::error_message]); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == RPC::missing_field_error(jss::account)[jss::error_message]); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { // account_lines with a malformed account. Json::Value params; - params[jss::account] = - "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + params[jss::account] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; Json::Value request; request[jss::method] = "account_lines"; request[jss::jsonrpc] = "2.0"; @@ -788,14 +682,9 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } Account const alice{"alice"}; @@ -810,19 +699,14 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } env.fund(XRP(10000), alice); env.close(); - LedgerInfo const ledger3Info = env.closed()->info(); + LedgerHeader const ledger3Info = env.closed()->header(); BEAST_EXPECT(ledger3Info.seq == 3); { @@ -838,11 +722,8 @@ public: auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -857,13 +738,9 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == "ledgerIndexMalformed"); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == "Invalid field 'ledger_index', not string or number."); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -879,11 +756,8 @@ public: request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound"); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } // Create trust lines to share with alice. @@ -894,8 +768,7 @@ public: for (char c = 0; c <= ('Z' - 'A'); ++c) { // gw1 currencies have names "YAA" -> "YAZ". - gw1Currencies.push_back( - gw1[std::string("YA") + static_cast('A' + c)]); + gw1Currencies.push_back(gw1[std::string("YA") + static_cast('A' + c)]); IOU const& gw1Currency = gw1Currencies.back(); // Establish trust lines. @@ -903,7 +776,7 @@ public: env(pay(gw1, alice, gw1Currency(50 + c))); } env.close(); - LedgerInfo const ledger4Info = env.closed()->info(); + LedgerHeader const ledger4Info = env.closed()->header(); BEAST_EXPECT(ledger4Info.seq == 4); // Add another set of trust lines in another ledger so we can see @@ -919,8 +792,7 @@ public: for (char c = 0; c <= ('Z' - 'A'); ++c) { // gw2 currencies have names "ZAA" -> "ZAZ". - gw2Currencies.push_back( - gw2[std::string("ZA") + static_cast('A' + c)]); + gw2Currencies.push_back(gw2[std::string("ZA") + static_cast('A' + c)]); IOU const& gw2Currency = gw2Currencies.back(); // Establish trust lines. @@ -931,21 +803,14 @@ public: env.close(); // Set flags on gw2 trust lines so we can look for them. - env(trust( - alice, - gw2Currency(0), - gw2, - tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze)); + env(trust(alice, gw2Currency(0), gw2, tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze)); } env.close(); - LedgerInfo const ledger58Info = env.closed()->info(); + LedgerHeader const ledger58Info = env.closed()->header(); BEAST_EXPECT(ledger58Info.seq == 58); // A re-usable test for historic ledgers. - auto testAccountLinesHistory = [this, &env]( - Account const& account, - LedgerInfo const& info, - int count) { + auto testAccountLinesHistory = [this, &env](Account const& account, LedgerHeader const& info, int count) { // Get account_lines by ledger index. Json::Value paramsSeq; paramsSeq[jss::account] = account.human(); @@ -959,12 +824,8 @@ public: auto const linesSeq = env.rpc("json2", to_string(requestSeq)); BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count); - BEAST_EXPECT( - linesSeq.isMember(jss::jsonrpc) && - linesSeq[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesSeq.isMember(jss::ripplerpc) && - linesSeq[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesSeq.isMember(jss::jsonrpc) && linesSeq[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesSeq.isMember(jss::ripplerpc) && linesSeq[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5); // Get account_lines by ledger hash. @@ -980,14 +841,9 @@ public: auto const linesHash = env.rpc("json2", to_string(requestHash)); BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count); - BEAST_EXPECT( - linesHash.isMember(jss::jsonrpc) && - linesHash[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesHash.isMember(jss::ripplerpc) && - linesHash[jss::ripplerpc] == "2.0"); - BEAST_EXPECT( - linesHash.isMember(jss::id) && linesHash[jss::id] == 5); + BEAST_EXPECT(linesHash.isMember(jss::jsonrpc) && linesHash[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesHash.isMember(jss::ripplerpc) && linesHash[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesHash.isMember(jss::id) && linesHash[jss::id] == 5); }; // Alice should have no trust lines in ledger 3. @@ -1013,13 +869,13 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); - BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); + BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams"); BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + lines[jss::error][jss::message] == + "Exactly one of 'ledger_hash' or 'ledger_index' can be " + "specified."); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1035,11 +891,8 @@ public: auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1056,19 +909,15 @@ public: auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { // Use a malformed peer. Json::Value params; params[jss::account] = alice.human(); - params[jss::peer] = - "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + params[jss::peer] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; Json::Value request; request[jss::method] = "account_lines"; request[jss::jsonrpc] = "2.0"; @@ -1076,14 +925,9 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1099,13 +943,9 @@ public: request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::expected_field_message(jss::limit, "unsigned integer")); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + lines[jss::error][jss::message] == RPC::expected_field_message(jss::limit, "unsigned integer")); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1122,11 +962,8 @@ public: auto const linesA = env.rpc("json2", to_string(requestA)); BEAST_EXPECT(linesA[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1); - BEAST_EXPECT( - linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesA.isMember(jss::ripplerpc) && - linesA[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesA.isMember(jss::ripplerpc) && linesA[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5); // Pick up from where the marker left off. We should get 51. @@ -1143,11 +980,8 @@ public: auto const linesB = env.rpc("json2", to_string(requestB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51); - BEAST_EXPECT( - linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesB.isMember(jss::ripplerpc) && - linesB[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesB.isMember(jss::ripplerpc) && linesB[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5); // Go again from where the marker left off, but set a limit of 3. @@ -1164,11 +998,8 @@ public: auto const linesC = env.rpc("json2", to_string(requestC)); BEAST_EXPECT(linesC[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3); - BEAST_EXPECT( - linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesC.isMember(jss::ripplerpc) && - linesC[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesC.isMember(jss::ripplerpc) && linesC[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesC.isMember(jss::id) && linesC[jss::id] == 5); // Mess with the marker so it becomes bad and check for the error. @@ -1183,14 +1014,9 @@ public: requestD[jss::id] = 5; requestD[jss::params] = paramsD; auto const linesD = env.rpc("json2", to_string(requestD)); - BEAST_EXPECT( - linesD[jss::error][jss::message] == - RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); - BEAST_EXPECT( - linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesD.isMember(jss::ripplerpc) && - linesD[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesD[jss::error][jss::message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); + BEAST_EXPECT(linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesD.isMember(jss::ripplerpc) && linesD[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesD.isMember(jss::id) && linesD[jss::id] == 5); } { @@ -1205,14 +1031,9 @@ public: request[jss::id] = 5; request[jss::params] = params; auto const lines = env.rpc("json2", to_string(request)); - BEAST_EXPECT( - lines[jss::error][jss::message] == - RPC::expected_field_message(jss::marker, "string")); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines[jss::error][jss::message] == RPC::expected_field_message(jss::marker, "string")); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1233,11 +1054,8 @@ public: BEAST_EXPECT(line[jss::deep_freeze].asBool() == true); BEAST_EXPECT(line[jss::no_ripple].asBool() == true); BEAST_EXPECT(line[jss::peer_authorized].asBool() == true); - BEAST_EXPECT( - lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - lines.isMember(jss::ripplerpc) && - lines[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0"); BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5); } { @@ -1258,11 +1076,8 @@ public: BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true); BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true); BEAST_EXPECT(lineA[jss::authorized].asBool() == true); - BEAST_EXPECT( - linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesA.isMember(jss::ripplerpc) && - linesA[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesA.isMember(jss::ripplerpc) && linesA[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5); // Continue from the returned marker to make sure that works. @@ -1283,11 +1098,8 @@ public: BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25); BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker)); - BEAST_EXPECT( - linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesB.isMember(jss::ripplerpc) && - linesB[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesB.isMember(jss::ripplerpc) && linesB[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5); } } @@ -1352,14 +1164,10 @@ public: linesBegRequest[jss::id] = 5; linesBegRequest[jss::params] = linesBegParams; auto const linesBeg = env.rpc("json2", to_string(linesBegRequest)); - BEAST_EXPECT( - linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); + BEAST_EXPECT(linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker)); - BEAST_EXPECT( - linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesBeg.isMember(jss::ripplerpc) && - linesBeg[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesBeg.isMember(jss::ripplerpc) && linesBeg[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5); // alice pays 100 USD to cheri. @@ -1378,14 +1186,9 @@ public: linesEndRequest[jss::id] = 5; linesEndRequest[jss::params] = linesEndParams; auto const linesEnd = env.rpc("json2", to_string(linesEndRequest)); - BEAST_EXPECT( - linesEnd[jss::error][jss::message] == - RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); - BEAST_EXPECT( - linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - linesEnd.isMember(jss::ripplerpc) && - linesEnd[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(linesEnd[jss::error][jss::message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); + BEAST_EXPECT(linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(linesEnd.isMember(jss::ripplerpc) && linesEnd[jss::ripplerpc] == "2.0"); BEAST_EXPECT(linesEnd.isMember(jss::id) && linesEnd[jss::id] == 5); } @@ -1401,7 +1204,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AccountLines, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountLines, rpc, xrpl); } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 546bbe8715..0dec2bde7f 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,10 +14,10 @@ #include -namespace ripple { +namespace xrpl { namespace test { -static char const* bobs_account_objects[] = { +static char const* bob_account_objects[] = { R"json({ "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK", "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000", @@ -129,20 +110,16 @@ public: { Json::Value params; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Missing field 'account'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Missing field 'account'."); } // test account non-string { auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_objects", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_objects", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -155,19 +132,16 @@ public: // test error on malformed account string. { Json::Value params; - params[jss::account] = - "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV"; + params[jss::account] = "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV"; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == "Account malformed."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account malformed."); } // test error on account that's not in the ledger. { Json::Value params; params[jss::account] = Account{"bogie"}.human(); auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == "Account not found."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account not found."); } Account const bob{"bob"}; // test error on large ledger_index. @@ -176,8 +150,7 @@ public: params[jss::account] = bob.human(); params[jss::ledger_index] = 10; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == "ledgerNotFound"); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "ledgerNotFound"); } env.fund(XRP(1000), bob); @@ -187,9 +160,7 @@ public: params[jss::account] = bob.human(); params[jss::type] = 10; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'type', not string."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'type', not string."); } // test error on type param not a valid type { @@ -197,9 +168,7 @@ public: params[jss::account] = bob.human(); params[jss::type] = "expedited"; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'type'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'type'."); } // test error on limit -ve { @@ -207,9 +176,7 @@ public: params[jss::account] = bob.human(); params[jss::limit] = -1; auto resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'limit', not unsigned integer."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'limit', not unsigned integer."); } // test errors on marker { @@ -229,39 +196,27 @@ public: std::string mark = to_string(resume_marker); params[jss::marker] = 10; resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker', not string."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker', not string."); params[jss::marker] = "This is a string with no comma"; resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); params[jss::marker] = "This string has a comma, but is not hex"; resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); params[jss::marker] = std::string(&mark[1U], 64); resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); params[jss::marker] = std::string(&mark[1U], 65); resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); params[jss::marker] = std::string(&mark[1U], 65) + "not hex"; resp = env.rpc("json", "account_objects", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'marker'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); // Should this be an error? // A hex digit is absent from the end of marker. @@ -299,7 +254,7 @@ public: Json::Value bobj[4]; for (int i = 0; i < 4; ++i) - Json::Reader{}.parse(bobs_account_objects[i], bobj[i]); + Json::Reader{}.parse(bob_account_objects[i], bobj[i]); // test 'unstepped' // i.e. request account objects without explicit limit/marker paging @@ -342,8 +297,7 @@ public: params[jss::limit] = 1; for (int i = 0; i < 4; ++i) { - auto resp = - env.rpc("json", "account_objects", to_string(params)); + auto resp = env.rpc("json", "account_objects", to_string(params)); auto& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); auto& aobj = aobjs[0U]; @@ -424,8 +378,7 @@ public: BEAST_EXPECT(!resp.isMember(jss::marker)); Json::Value& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); - BEAST_EXPECT( - aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage); + BEAST_EXPECT(aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage); BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].size() == 1); } // test stepped one-at-a-time with limit=1, resume from prev marker @@ -434,8 +387,7 @@ public: params[jss::account] = bob.human(); params[jss::limit] = 1; - Json::Value resp = - env.rpc("json", "account_objects", to_string(params)); + Json::Value resp = env.rpc("json", "account_objects", to_string(params)); Json::Value& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); auto& aobj = aobjs[0U]; @@ -475,8 +427,7 @@ public: BEAST_EXPECT(!resp.isMember(jss::marker)); Json::Value& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); - BEAST_EXPECT( - aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage); + BEAST_EXPECT(aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage); BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].size() == 1); } // test stepped one-at-a-time with limit=1, resume from prev marker @@ -486,8 +437,7 @@ public: params[jss::limit] = 1; for (int i = 0; i < 5; ++i) { - Json::Value resp = - env.rpc("json", "account_objects", to_string(params)); + Json::Value resp = env.rpc("json", "account_objects", to_string(params)); Json::Value& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); auto& aobj = aobjs[0U]; @@ -541,8 +491,7 @@ public: params[jss::limit] = 1; for (int i = 0; i < 6; ++i) { - Json::Value resp = - env.rpc("json", "account_objects", to_string(params)); + Json::Value resp = env.rpc("json", "account_objects", to_string(params)); Json::Value& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs.size() == 1); auto& aobj = aobjs[0U]; @@ -577,8 +526,7 @@ public: Account const gw{"gateway"}; auto const USD = gw["USD"]; - auto const features = testable_amendments() | featureXChainBridge | - featurePermissionedDomains; + auto const features = testable_amendments() | featureXChainBridge | featurePermissionedDomains; Env env(*this, features); // Make a lambda we can use to get "account_objects" easily. @@ -608,8 +556,7 @@ public: // Make a lambda that checks if the response has error for invalid type auto acctObjsTypeIsInvalid = [](Json::Value const& resp) { return resp[jss::result].isMember(jss::error) && - resp[jss::result][jss::error_message] == - "Invalid field \'type\'."; + resp[jss::result][jss::error_message] == "Invalid field \'type\'."; }; env.fund(XRP(10000), gw, alice); @@ -650,8 +597,7 @@ public: auto const& nftPage = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(nftPage[sfNFTokens.jsonName].size() == 1); BEAST_EXPECT( - nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName] - [sfNFTokenID.jsonName] == to_string(nftID)); + nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName][sfNFTokenID.jsonName] == to_string(nftID)); } // Set up a trust line so we can find it. @@ -666,8 +612,7 @@ public: auto const& state = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5); - BEAST_EXPECT( - state[sfHighLimit.jsonName][jss::value].asUInt() == 1000); + BEAST_EXPECT(state[sfHighLimit.jsonName][jss::value].asUInt() == 1000); } // gw writes a check for USD(10) to alice. env(check::create(gw, alice, USD(10))); @@ -686,7 +631,7 @@ public: env(deposit::auth(gw, alice)); env.close(); { - // Find the preauthorization. + // Find the pre-authorization. Json::Value const resp = acctObjs(gw, jss::deposit_preauth); BEAST_EXPECT(acctObjsIsSize(resp, 1)); @@ -701,8 +646,7 @@ public: jvEscrow[jss::Account] = gw.human(); jvEscrow[jss::Destination] = gw.human(); jvEscrow[jss::Amount] = XRP(100).value().getJson(JsonOptions::none); - jvEscrow[sfFinishAfter.jsonName] = - env.now().time_since_epoch().count() + 1; + jvEscrow[sfFinishAfter.jsonName] = env.now().time_since_epoch().count() + 1; env(jvEscrow); env.close(); } @@ -730,30 +674,22 @@ public: Json::Value const resp = acctObjs(gw, jss::permissioned_domain); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& permissionedDomain = - resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT( - permissionedDomain.isMember(jss::Owner) && - (permissionedDomain[jss::Owner] == gw.human())); + auto const& permissionedDomain = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT(permissionedDomain.isMember(jss::Owner) && (permissionedDomain[jss::Owner] == gw.human())); bool const check1 = BEAST_EXPECT( permissionedDomain.isMember(jss::AcceptedCredentials) && permissionedDomain[jss::AcceptedCredentials].isArray() && (permissionedDomain[jss::AcceptedCredentials].size() == 1) && - (permissionedDomain[jss::AcceptedCredentials][0u].isMember( - jss::Credential))); + (permissionedDomain[jss::AcceptedCredentials][0u].isMember(jss::Credential))); if (check1) { - auto const& credential = - permissionedDomain[jss::AcceptedCredentials][0u] - [jss::Credential]; + auto const& credential = permissionedDomain[jss::AcceptedCredentials][0u][jss::Credential]; BEAST_EXPECT( - credential.isMember(sfIssuer.jsonName) && - (credential[sfIssuer.jsonName] == issuer.human())); + credential.isMember(sfIssuer.jsonName) && (credential[sfIssuer.jsonName] == issuer.human())); BEAST_EXPECT( credential.isMember(sfCredentialType.jsonName) && - (credential[sfCredentialType.jsonName] == - strHex(credentialType1))); + (credential[sfCredentialType.jsonName] == strHex(credentialType1))); } } @@ -771,30 +707,17 @@ public: return scEnv.rpc("json", "account_objects", to_string(params)); }; - Json::Value const resp = - scEnvAcctObjs(Account::master, jss::bridge); + Json::Value const resp = scEnvAcctObjs(Account::master, jss::bridge); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& acct_bridge = - resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT( - acct_bridge[sfAccount.jsonName] == Account::master.human()); - BEAST_EXPECT( - acct_bridge[sfLedgerEntryType.getJsonName()] == "Bridge"); - BEAST_EXPECT( - acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0); - BEAST_EXPECT( - acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() == - 0); - BEAST_EXPECT( - acct_bridge[sfXChainAccountCreateCount.getJsonName()] - .asUInt() == 0); - BEAST_EXPECT( - acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() == - 20000000); - BEAST_EXPECT( - acct_bridge[sfSignatureReward.getJsonName()].asUInt() == - 1000000); + auto const& acct_bridge = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT(acct_bridge[sfAccount.jsonName] == Account::master.human()); + BEAST_EXPECT(acct_bridge[sfLedgerEntryType.getJsonName()] == "Bridge"); + BEAST_EXPECT(acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0); + BEAST_EXPECT(acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() == 0); + BEAST_EXPECT(acct_bridge[sfXChainAccountCreateCount.getJsonName()].asUInt() == 0); + BEAST_EXPECT(acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() == 20000000); + BEAST_EXPECT(acct_bridge[sfSignatureReward.getJsonName()].asUInt() == 1000000); BEAST_EXPECT(acct_bridge[sfXChainBridge.getJsonName()] == x.jvb); } { @@ -804,8 +727,7 @@ public: Env scEnv(*this, envconfig(), features); x.createScBridgeObjects(scEnv); - scEnv( - xchain_create_claim_id(x.scAlice, x.jvb, x.reward, x.mcAlice)); + scEnv(xchain_create_claim_id(x.scAlice, x.jvb, x.reward, x.mcAlice)); scEnv.close(); scEnv(xchain_create_claim_id(x.scBob, x.jvb, x.reward, x.mcBob)); scEnv.close(); @@ -820,28 +742,21 @@ public: { // Find the xchain sequence number for Andrea. - Json::Value const resp = - scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id); + Json::Value const resp = scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& xchain_seq = - resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT( - xchain_seq[sfAccount.jsonName] == x.scAlice.human()); - BEAST_EXPECT( - xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1); + auto const& xchain_seq = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.scAlice.human()); + BEAST_EXPECT(xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1); } { // and the one for Bob - Json::Value const resp = - scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id); + Json::Value const resp = scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& xchain_seq = - resp[jss::result][jss::account_objects][0u]; + auto const& xchain_seq = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.scBob.human()); - BEAST_EXPECT( - xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2); + BEAST_EXPECT(xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2); } } { @@ -855,16 +770,7 @@ public: // account (Account::master) to collect the signatures until a // quorum is reached scEnv(test::jtx::create_account_attestation( - x.scAttester, - x.jvb, - x.mcCarol, - amt, - x.reward, - x.payees[0], - true, - 1, - x.scuAlice, - x.signers[0])); + x.scAttester, x.jvb, x.mcCarol, amt, x.reward, x.payees[0], true, 1, x.scuAlice, x.signers[0])); scEnv.close(); auto scEnvAcctObjs = [&](Account const& acct, char const* type) { @@ -877,19 +783,12 @@ public: { // Find the xchain_create_account_claim_id - Json::Value const resp = scEnvAcctObjs( - Account::master, jss::xchain_owned_create_account_claim_id); + Json::Value const resp = scEnvAcctObjs(Account::master, jss::xchain_owned_create_account_claim_id); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& xchain_create_account_claim_id = - resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT( - xchain_create_account_claim_id[sfAccount.jsonName] == - Account::master.human()); - BEAST_EXPECT( - xchain_create_account_claim_id[sfXChainAccountCreateCount - .getJsonName()] - .asUInt() == 1); + auto const& xchain_create_account_claim_id = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT(xchain_create_account_claim_id[sfAccount.jsonName] == Account::master.human()); + BEAST_EXPECT(xchain_create_account_claim_id[sfXChainAccountCreateCount.getJsonName()].asUInt() == 1); } } @@ -913,8 +812,7 @@ public: jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate; jvPayChan[jss::Account] = gw.human(); jvPayChan[jss::Destination] = alice.human(); - jvPayChan[jss::Amount] = - XRP(300).value().getJson(JsonOptions::none); + jvPayChan[jss::Amount] = XRP(300).value().getJson(JsonOptions::none); jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60; jvPayChan[sfPublicKey.jsonName] = strHex(gw.pk().slice()); env(jvPayChan); @@ -928,8 +826,7 @@ public: auto const& payChan = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human()); BEAST_EXPECT(payChan[sfAmount.jsonName].asUInt() == 300'000'000); - BEAST_EXPECT( - payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60); + BEAST_EXPECT(payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60); } { @@ -958,11 +855,9 @@ public: Json::Value const resp = acctObjs(gw, jss::signer_list); BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& signerList = - resp[jss::result][jss::account_objects][0u]; + auto const& signerList = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6); - auto const& entry = signerList[sfSignerEntries.jsonName][0u] - [sfSignerEntry.jsonName]; + auto const& entry = signerList[sfSignerEntries.jsonName][0u][sfSignerEntry.jsonName]; BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human()); BEAST_EXPECT(entry[sfSignerWeight.jsonName].asUInt() == 7); } @@ -1002,8 +897,7 @@ public: return v; }(); - std::uint32_t const expectedAccountObjects{ - static_cast(std::size(expectedLedgerTypes))}; + std::uint32_t const expectedAccountObjects{static_cast(std::size(expectedLedgerTypes))}; if (BEAST_EXPECT(acctObjsIsSize(resp, expectedAccountObjects))) { @@ -1012,8 +906,7 @@ public: gotLedgerTypes.reserve(expectedAccountObjects); for (std::uint32_t i = 0; i < expectedAccountObjects; ++i) { - gotLedgerTypes.push_back( - aobjs[i]["LedgerEntryType"].asString()); + gotLedgerTypes.push_back(aobjs[i]["LedgerEntryType"].asString()); } std::sort(gotLedgerTypes.begin(), gotLedgerTypes.end()); BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes); @@ -1036,19 +929,15 @@ public: } { // Make a lambda to get the types - auto getTypes = [&](Json::Value const& resp, - std::vector& typesOut) { + auto getTypes = [&](Json::Value const& resp, std::vector& typesOut) { auto const objs = resp[jss::result][jss::account_objects]; for (auto const& obj : resp[jss::result][jss::account_objects]) - typesOut.push_back( - obj[sfLedgerEntryType.fieldName].asString()); + typesOut.push_back(obj[sfLedgerEntryType.fieldName].asString()); std::sort(typesOut.begin(), typesOut.end()); }; // Make a lambda we can use to check the number of fetched // account objects and their ledger type - auto expectObjects = - [&](Json::Value const& resp, - std::vector const& types) -> bool { + auto expectObjects = [&](Json::Value const& resp, std::vector const& types) -> bool { if (!acctObjsIsSize(resp, types.size())) return false; std::vector typesOut; @@ -1062,36 +951,24 @@ public: auto const lines = getAccountLines(env, amm.ammAccount()); BEAST_EXPECT(lines[jss::lines].size() == 3); // request AMM only, doesn't depend on the limit - BEAST_EXPECT( - acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1)); // request first two objects auto resp = acctObjs(amm.ammAccount(), std::nullopt, 2); std::vector typesOut; getTypes(resp, typesOut); // request next two objects - resp = acctObjs( - amm.ammAccount(), - std::nullopt, - 10, - resp[jss::result][jss::marker].asString()); + resp = acctObjs(amm.ammAccount(), std::nullopt, 10, resp[jss::result][jss::marker].asString()); getTypes(resp, typesOut); BEAST_EXPECT( (typesOut == std::vector{ - jss::AMM.c_str(), - jss::RippleState.c_str(), - jss::RippleState.c_str(), - jss::RippleState.c_str()})); + jss::AMM.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str()})); // filter by state: there are three trustlines resp = acctObjs(amm.ammAccount(), jss::state, 10); - BEAST_EXPECT(expectObjects( - resp, - {jss::RippleState.c_str(), - jss::RippleState.c_str(), - jss::RippleState.c_str()})); - // AMM account doesn't own offers BEAST_EXPECT( - acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0)); + expectObjects(resp, {jss::RippleState.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str()})); + // AMM account doesn't own offers + BEAST_EXPECT(acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0)); // gw account doesn't own AMM object BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0)); } @@ -1144,8 +1021,7 @@ public: Json::Value params; params[jss::account] = bob.human(); params[jss::ledger_index] = "validated"; - Json::Value const resp = - env.rpc("json", "account_nfts", to_string(params)); + Json::Value const resp = env.rpc("json", "account_nfts", to_string(params)); Json::Value const& nfts = resp[jss::result][jss::account_nfts]; for (Json::Value const& nft : nfts) tokenIDs.push_back(nft["NFTokenID"]); @@ -1154,23 +1030,20 @@ public: // this lambda function is used to check if the account_nfts method // returns the correct token information. lastIndex is used to query the // last marker. - auto compareNFTs = [&tokenIDs, &env, &bob]( - unsigned const limit, unsigned const lastIndex) { + auto compareNFTs = [&tokenIDs, &env, &bob](unsigned const limit, unsigned const lastIndex) { Json::Value params; params[jss::account] = bob.human(); params[jss::limit] = limit; params[jss::marker] = tokenIDs[lastIndex]; params[jss::ledger_index] = "validated"; - Json::Value const resp = - env.rpc("json", "account_nfts", to_string(params)); + Json::Value const resp = env.rpc("json", "account_nfts", to_string(params)); if (resp[jss::result].isMember(jss::error)) return false; Json::Value const& nfts = resp[jss::result][jss::account_nfts]; - unsigned const nftsCount = tokenIDs.size() - lastIndex - 1 < limit - ? tokenIDs.size() - lastIndex - 1 - : limit; + unsigned const nftsCount = + tokenIDs.size() - lastIndex - 1 < limit ? tokenIDs.size() - lastIndex - 1 : limit; if (nfts.size() != nftsCount) return false; @@ -1191,26 +1064,22 @@ public: BEAST_EXPECT(compareNFTs(4, 7)); // lambda that holds common code for invalid cases. - auto testInvalidMarker = [&env, &bob]( - auto marker, char const* errorMessage) { + auto testInvalidMarker = [&env, &bob](auto marker, char const* errorMessage) { Json::Value params; params[jss::account] = bob.human(); params[jss::limit] = 4; params[jss::ledger_index] = jss::validated; params[jss::marker] = marker; - Json::Value const resp = - env.rpc("json", "account_nfts", to_string(params)); + Json::Value const resp = env.rpc("json", "account_nfts", to_string(params)); return resp[jss::result][jss::error_message] == errorMessage; }; // test an invalid marker that is not a string - BEAST_EXPECT( - testInvalidMarker(17, "Invalid field \'marker\', not string.")); + BEAST_EXPECT(testInvalidMarker(17, "Invalid field \'marker\', not string.")); // test an invalid marker that has a non-hex character BEAST_EXPECT(testInvalidMarker( - "00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G", - "Invalid field \'marker\'.")); + "00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G", "Invalid field \'marker\'.")); // this lambda function is used to create some fake marker using given // taxon and sequence because we want to test some unassociated markers @@ -1221,20 +1090,17 @@ public: std::uint16_t flags = 0, std::uint16_t fee = 0) { // the marker has the exact same format as an NFTokenID - return to_string(NFTokenMint::createNFTokenID( - flags, fee, issuer, nft::toTaxon(taxon), tokenSeq)); + return to_string(NFTokenMint::createNFTokenID(flags, fee, issuer, nft::toTaxon(taxon), tokenSeq)); }; // test an unassociated marker which does not exist in the NFTokenIDs - BEAST_EXPECT(testInvalidMarker( - createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000), - "Invalid field \'marker\'.")); + BEAST_EXPECT( + testInvalidMarker(createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000), "Invalid field \'marker\'.")); // test an unassociated marker which exceeds the maximum value of the // existing NFTokenID - BEAST_EXPECT(testInvalidMarker( - createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF), - "Invalid field \'marker\'.")); + BEAST_EXPECT( + testInvalidMarker(createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF), "Invalid field \'marker\'.")); } void @@ -1250,11 +1116,9 @@ public: auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_nfts", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_nfts", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -1325,10 +1189,8 @@ public: params[jss::limit] = limit; params[jss::ledger_index] = jss::validated; params[jss::marker] = marker; - Json::Value const resp = - env.rpc("json", "account_objects", to_string(params)); - return resp[jss::result][jss::error_message] == - "Invalid field \'marker\'."; + Json::Value const resp = env.rpc("json", "account_objects", to_string(params)); + return resp[jss::result][jss::error_message] == "Invalid field \'marker\'."; }; auto const markerStr = marker.asString(); @@ -1414,8 +1276,7 @@ public: auto resp = env.rpc("json", "account_objects", to_string(params)); auto& accountObjects = resp[jss::result][jss::account_objects]; BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); - BEAST_EXPECT( - accountObjects.size() == accountObjectSize - limit * 2); + BEAST_EXPECT(accountObjects.size() == accountObjectSize - limit * 2); BEAST_EXPECT(!resp[jss::result].isMember(jss::marker)); } @@ -1446,7 +1307,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AccountObjects, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountObjects, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index 59a6942ed2..ffa1d70992 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { class AccountOffers_test : public beast::unit_test::suite @@ -31,8 +12,7 @@ public: static bool checkMarker(Json::Value const& val) { - return val.isMember(jss::marker) && val[jss::marker].isString() && - val[jss::marker].asString().size() > 0; + return val.isMember(jss::marker) && val[jss::marker].isString() && val[jss::marker].asString().size() > 0; } void @@ -63,8 +43,7 @@ public: } // make non-limited RPC call - auto const jro_nl = - env.rpc("account_offers", bob.human())[jss::result][jss::offers]; + auto const jro_nl = env.rpc("account_offers", bob.human())[jss::result][jss::offers]; BEAST_EXPECT(checkArraySize(jro_nl, offer_count)); // now make a low-limit query, should get "corrected" @@ -73,8 +52,7 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::limit] = 1u; - auto const jrr_l = env.rpc( - "json", "account_offers", jvParams.toStyledString())[jss::result]; + auto const jrr_l = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; auto const& jro_l = jrr_l[jss::offers]; BEAST_EXPECT(checkMarker(jrr_l)); // 9u is the expected size, since one account object is a trustline @@ -84,8 +62,7 @@ public: void testSequential(bool asAdmin) { - testcase( - std::string("Sequential - ") + (asAdmin ? "admin" : "non-admin")); + testcase(std::string("Sequential - ") + (asAdmin ? "admin" : "non-admin")); using namespace jtx; Env env{*this, asAdmin ? envconfig() : envconfig(no_admin)}; @@ -107,8 +84,7 @@ public: env(offer(bob, XRP(30), USD_gw(6))); // make the RPC call - auto const jroOuter = - env.rpc("account_offers", bob.human())[jss::result][jss::offers]; + auto const jroOuter = env.rpc("account_offers", bob.human())[jss::result][jss::offers]; if (BEAST_EXPECT(checkArraySize(jroOuter, 3u))) { // Note that the returned offers are sorted by index, not by @@ -117,22 +93,19 @@ public: // if the sequence numbers or the account IDs change. BEAST_EXPECT(jroOuter[0u][jss::quality] == "100000000"); BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::currency] == "USD"); - BEAST_EXPECT( - jroOuter[0u][jss::taker_gets][jss::issuer] == gw.human()); + BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::issuer] == gw.human()); BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "2"); BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "200000000"); BEAST_EXPECT(jroOuter[1u][jss::quality] == "100000000"); BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::currency] == "USD"); - BEAST_EXPECT( - jroOuter[1u][jss::taker_gets][jss::issuer] == bob.human()); + BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::issuer] == bob.human()); BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::value] == "1"); BEAST_EXPECT(jroOuter[1u][jss::taker_pays] == "100000000"); BEAST_EXPECT(jroOuter[2u][jss::quality] == "5000000"); BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::currency] == "USD"); - BEAST_EXPECT( - jroOuter[2u][jss::taker_gets][jss::issuer] == gw.human()); + BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::issuer] == gw.human()); BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "6"); BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "30000000"); } @@ -142,10 +115,7 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::limit] = 1u; - auto const jrr_l_1 = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr_l_1 = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; auto const& jro_l_1 = jrr_l_1[jss::offers]; // there is a difference in the validation of the limit param // between admin and non-admin requests. with admin requests, the @@ -153,19 +123,14 @@ public: // non-admin there are pre-configured limit ranges applied. That's // why we have different BEAST_EXPECT()s here for the two scenarios BEAST_EXPECT(checkArraySize(jro_l_1, asAdmin ? 1u : 3u)); - BEAST_EXPECT( - asAdmin ? checkMarker(jrr_l_1) - : (!jrr_l_1.isMember(jss::marker))); + BEAST_EXPECT(asAdmin ? checkMarker(jrr_l_1) : (!jrr_l_1.isMember(jss::marker))); if (asAdmin) { BEAST_EXPECT(jroOuter[0u] == jro_l_1[0u]); // second item...with previous marker passed jvParams[jss::marker] = jrr_l_1[jss::marker]; - auto const jrr_l_2 = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr_l_2 = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; auto const& jro_l_2 = jrr_l_2[jss::offers]; BEAST_EXPECT(checkMarker(jrr_l_2)); BEAST_EXPECT(checkArraySize(jro_l_2, 1u)); @@ -174,10 +139,7 @@ public: // last item...with previous marker passed jvParams[jss::marker] = jrr_l_2[jss::marker]; jvParams[jss::limit] = 10u; - auto const jrr_l_3 = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr_l_3 = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; auto const& jro_l_3 = jrr_l_3[jss::offers]; BEAST_EXPECT(!jrr_l_3.isMember(jss::marker)); BEAST_EXPECT(checkArraySize(jro_l_3, 1u)); @@ -193,10 +155,7 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::limit] = 0u; - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr.isMember(jss::error_message)); } } @@ -229,11 +188,9 @@ public: auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_offers", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_offers", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -248,10 +205,7 @@ public: // empty string account Json::Value jvParams; jvParams[jss::account] = ""; - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "actMalformed"); BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error_message] == "Account malformed."); @@ -259,8 +213,7 @@ public: { // bogus account value - auto const jrr = env.rpc( - "account_offers", Account("bogus").human())[jss::result]; + auto const jrr = env.rpc("account_offers", Account("bogus").human())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "actNotFound"); BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error_message] == "Account not found."); @@ -271,15 +224,10 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::limit] = "0"; // NOT an integer - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'limit', not unsigned integer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not unsigned integer."); } { @@ -287,15 +235,10 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::marker] = "NOT_A_MARKER"; - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECTS( - jrr[jss::error_message] == "Invalid field 'marker'.", - jrr.toStyledString()); + BEAST_EXPECTS(jrr[jss::error_message] == "Invalid field 'marker'.", jrr.toStyledString()); } { @@ -303,15 +246,10 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::marker] = 1; - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'marker', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not string."); } { @@ -319,10 +257,7 @@ public: Json::Value jvParams; jvParams[jss::account] = bob.human(); jvParams[jss::ledger_index] = 10u; - auto const jrr = env.rpc( - "json", - "account_offers", - jvParams.toStyledString())[jss::result]; + auto const jrr = env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result]; BEAST_EXPECT(jrr[jss::error] == "lgrNotFound"); BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound"); @@ -339,7 +274,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AccountOffers, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountOffers, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index 52dc331a2b..2e238773f9 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { class AccountSet_test : public beast::unit_test::suite { @@ -54,8 +35,7 @@ public: using namespace test::jtx; Account const alice("alice"); - // Test without DepositAuth enabled initially. - Env env(*this, testable_amendments() - featureDepositAuth); + Env env(*this, testable_amendments()); env.fund(XRP(10000), noripple(alice)); // Give alice a regular key so she can legally set and clear @@ -64,12 +44,9 @@ public: env(regkey(alice, alie)); env.close(); - auto testFlags = [this, &alice, &alie, &env]( - std::initializer_list goodFlags) { + auto testFlags = [this, &alice, &alie, &env](std::initializer_list goodFlags) { std::uint32_t const orig_flags = (*env.le(alice))[sfFlags]; - for (std::uint32_t flag{1u}; - flag < std::numeric_limits::digits; - ++flag) + for (std::uint32_t flag{1u}; flag < std::numeric_limits::digits; ++flag) { if (flag == asfNoFreeze) { @@ -86,10 +63,8 @@ public: continue; } - if (flag == asfDisallowIncomingCheck || - flag == asfDisallowIncomingPayChan || - flag == asfDisallowIncomingNFTokenOffer || - flag == asfDisallowIncomingTrustline) + if (flag == asfDisallowIncomingCheck || flag == asfDisallowIncomingPayChan || + flag == asfDisallowIncomingNFTokenOffer || flag == asfDisallowIncomingTrustline) { // These flags are part of the DisallowIncoming amendment // and are tested elsewhere @@ -108,8 +83,7 @@ public: continue; } - if (std::find(goodFlags.begin(), goodFlags.end(), flag) != - goodFlags.end()) + if (std::find(goodFlags.begin(), goodFlags.end(), flag) != goodFlags.end()) { // Good flag env.require(nflags(alice, flag)); @@ -135,19 +109,6 @@ public: } } }; - - // Test with featureDepositAuth disabled. - testFlags( - {asfRequireDest, - asfRequireAuth, - asfDisallowXRP, - asfGlobalFreeze, - asfDisableMaster, - asfDefaultRipple}); - - // Enable featureDepositAuth and retest. - env.enableFeature(featureDepositAuth); - env.close(); testFlags( {asfRequireDest, asfRequireAuth, @@ -233,8 +194,7 @@ public: std::size_t const maxLength = 256; for (std::size_t len = maxLength - 1; len <= maxLength + 1; ++len) { - std::string domain2 = - std::string(len - domain.length() - 1, 'a') + "." + domain; + std::string domain2 = std::string(len - domain.length() - 1, 'a') + "." + domain; BEAST_EXPECT(domain2.length() == len); @@ -266,9 +226,7 @@ public: auto const rkp = randomKeyPair(KeyType::ed25519); jt[sfMessageKey.fieldName] = strHex(rkp.first.slice()); env(jt); - BEAST_EXPECT( - strHex((*env.le(alice))[sfMessageKey]) == - strHex(rkp.first.slice())); + BEAST_EXPECT(strHex((*env.le(alice))[sfMessageKey]) == strHex(rkp.first.slice())); jt[sfMessageKey.fieldName] = ""; env(jt); @@ -290,8 +248,7 @@ public: env.fund(XRP(10000), alice); auto jt = noop(alice); - std::string const locator = - "9633EC8AF54F16B5286DB1D7B519EF49EEFC050C0C8AC4384F1D88ACD1BFDF05"; + std::string const locator = "9633EC8AF54F16B5286DB1D7B519EF49EEFC050C0C8AC4384F1D88ACD1BFDF05"; jt[sfWalletLocator.fieldName] = locator; env(jt); BEAST_EXPECT(to_string((*env.le(alice))[sfWalletLocator]) == locator); @@ -335,9 +292,7 @@ public: testcase("TransferRate"); using namespace test::jtx; - auto doTests = [this]( - FeatureBitset const& features, - std::initializer_list testData) { + auto doTests = [this](FeatureBitset const& features, std::initializer_list testData) { Env env(*this, features); Account const alice("alice"); @@ -352,9 +307,7 @@ public: if (!(*env.le(alice))[~sfTransferRate]) BEAST_EXPECT(r.get == 1.0); else - BEAST_EXPECT( - *(*env.le(alice))[~sfTransferRate] == - r.get * QUALITY_ONE); + BEAST_EXPECT(*(*env.le(alice))[~sfTransferRate] == r.get * QUALITY_ONE); } }; @@ -382,8 +335,7 @@ public: auto const USD = gw["USD"]; // Test gateway with a variety of allowed transfer rates - for (double transferRate = 1.0; transferRate <= 2.0; - transferRate += 0.03125) + for (double transferRate = 1.0; transferRate <= 2.0; transferRate += 0.03125) { Env env(*this); env.fund(XRP(10000), gw, alice, bob); @@ -395,8 +347,7 @@ public: auto const amount = USD(1); Rate const rate(transferRate * QUALITY_ONE); - auto const amountWithRate = - toAmount(multiply(amount.value(), rate)); + auto const amountWithRate = toAmount(multiply(amount.value(), rate)); env(pay(gw, alice, USD(10))); env.close(); @@ -445,25 +396,22 @@ public: // Note that we're bypassing almost all of the ledger's safety // checks with this modify() call. If you call close() between // here and the end of the test all the effort will be lost. - env.app().openLedger().modify( - [&gw, transferRate](OpenView& view, beast::Journal j) { - // Get the account root we want to hijack. - auto const sle = view.read(keylet::account(gw.id())); - if (!sle) - return false; // This would be really surprising! + env.app().openLedger().modify([&gw, transferRate](OpenView& view, beast::Journal j) { + // Get the account root we want to hijack. + auto const sle = view.read(keylet::account(gw.id())); + if (!sle) + return false; // This would be really surprising! - // We'll insert a replacement for the account root - // with the higher (currently invalid) transfer rate. - auto replacement = std::make_shared(*sle, sle->key()); - (*replacement)[sfTransferRate] = - static_cast(transferRate * QUALITY_ONE); - view.rawReplace(replacement); - return true; - }); + // We'll insert a replacement for the account root + // with the higher (currently invalid) transfer rate. + auto replacement = std::make_shared(*sle, sle->key()); + (*replacement)[sfTransferRate] = static_cast(transferRate * QUALITY_ONE); + view.rawReplace(replacement); + return true; + }); auto const amount = USD(1); - auto const amountWithRate = toAmount( - multiply(amount.value(), Rate(transferRate * QUALITY_ONE))); + auto const amountWithRate = toAmount(multiply(amount.value(), Rate(transferRate * QUALITY_ONE))); env(pay(gw, alice, USD(10))); env(pay(alice, bob, amount), sendmax(USD(10))); @@ -511,9 +459,7 @@ public: jt[sfFlags.fieldName] = tfAccountSetMask; env(jt, ter(temINVALID_FLAG)); - env(fset(alice, asfDisableMaster), - sig(alice), - ter(tecNO_ALTERNATIVE_KEY)); + env(fset(alice, asfDisableMaster), sig(alice), ter(tecNO_ALTERNATIVE_KEY)); } void @@ -598,8 +544,7 @@ public: stx->at(sfSigningPubKey) = makeSlice(std::string("badkey")); env.app().openLedger().modify([&](OpenView& view, beast::Journal j) { - auto const result = - ripple::apply(env.app(), view, *stx, tapNONE, j); + auto const result = xrpl::apply(env.app(), view, *stx, tapNONE, j); BEAST_EXPECT(result.ter == temBAD_SIGNATURE); BEAST_EXPECT(!result.applied); return result.applied; @@ -626,6 +571,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(AccountSet, rpc, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(AccountSet, rpc, xrpl, 1); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index cbe7cc8f4a..3cc9dbc77c 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -28,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { @@ -71,38 +52,26 @@ class AccountTx_test : public beast::unit_test::suite checkSanity(Json::Value const& txNode, NodeSanity const& sane) { BEAST_EXPECT(txNode[jss::validated].asBool() == true); - BEAST_EXPECT( - txNode[jss::tx][sfTransactionType.jsonName].asString() == - sane.txType); + BEAST_EXPECT(txNode[jss::tx][sfTransactionType.jsonName].asString() == sane.txType); // Make sure all of the expected node types are present. boost::container::flat_set createdNodes; boost::container::flat_set deletedNodes; boost::container::flat_set modifiedNodes; - for (Json::Value const& metaNode : - txNode[jss::meta][sfAffectedNodes.jsonName]) + for (Json::Value const& metaNode : txNode[jss::meta][sfAffectedNodes.jsonName]) { if (metaNode.isMember(sfCreatedNode.jsonName)) - createdNodes.insert( - metaNode[sfCreatedNode.jsonName][sfLedgerEntryType.jsonName] - .asString()); + createdNodes.insert(metaNode[sfCreatedNode.jsonName][sfLedgerEntryType.jsonName].asString()); else if (metaNode.isMember(sfDeletedNode.jsonName)) - deletedNodes.insert( - metaNode[sfDeletedNode.jsonName][sfLedgerEntryType.jsonName] - .asString()); + deletedNodes.insert(metaNode[sfDeletedNode.jsonName][sfLedgerEntryType.jsonName].asString()); else if (metaNode.isMember(sfModifiedNode.jsonName)) - modifiedNodes.insert(metaNode[sfModifiedNode.jsonName] - [sfLedgerEntryType.jsonName] - .asString()); + modifiedNodes.insert(metaNode[sfModifiedNode.jsonName][sfLedgerEntryType.jsonName].asString()); else - fail( - "Unexpected or unlabeled node type in metadata.", - __FILE__, - __LINE__); + fail("Unexpected or unlabeled node type in metadata.", __FILE__, __LINE__); } BEAST_EXPECT(createdNodes == sane.created); @@ -131,47 +100,34 @@ class AccountTx_test : public beast::unit_test::suite switch (apiVersion) { case 1: - return j.isMember(jss::result) && - (j[jss::result][jss::status] == "success") && + return j.isMember(jss::result) && (j[jss::result][jss::status] == "success") && (j[jss::result][jss::transactions].size() == 2) && - (j[jss::result][jss::transactions][0u][jss::tx] - [jss::TransactionType] == jss::AccountSet) && - (j[jss::result][jss::transactions][1u][jss::tx] - [jss::TransactionType] == jss::Payment) && - (j[jss::result][jss::transactions][1u][jss::tx] - [jss::DeliverMax] == "10000000010") && - (j[jss::result][jss::transactions][1u][jss::tx] - [jss::Amount] == - j[jss::result][jss::transactions][1u][jss::tx] - [jss::DeliverMax]); + (j[jss::result][jss::transactions][0u][jss::tx][jss::TransactionType] == jss::AccountSet) && + (j[jss::result][jss::transactions][1u][jss::tx][jss::TransactionType] == jss::Payment) && + (j[jss::result][jss::transactions][1u][jss::tx][jss::DeliverMax] == "10000000010") && + (j[jss::result][jss::transactions][1u][jss::tx][jss::Amount] == + j[jss::result][jss::transactions][1u][jss::tx][jss::DeliverMax]); case 2: case 3: - if (j.isMember(jss::result) && - (j[jss::result][jss::status] == "success") && + if (j.isMember(jss::result) && (j[jss::result][jss::status] == "success") && (j[jss::result][jss::transactions].size() == 2) && - (j[jss::result][jss::transactions][0u][jss::tx_json] - [jss::TransactionType] == jss::AccountSet)) + (j[jss::result][jss::transactions][0u][jss::tx_json][jss::TransactionType] == jss::AccountSet)) { - auto const& payment = - j[jss::result][jss::transactions][1u]; + auto const& payment = j[jss::result][jss::transactions][1u]; return (payment.isMember(jss::tx_json)) && - (payment[jss::tx_json][jss::TransactionType] == - jss::Payment) && - (payment[jss::tx_json][jss::DeliverMax] == - "10000000010") && + (payment[jss::tx_json][jss::TransactionType] == jss::Payment) && + (payment[jss::tx_json][jss::DeliverMax] == "10000000010") && (!payment[jss::tx_json].isMember(jss::Amount)) && (!payment[jss::tx_json].isMember(jss::hash)) && (payment[jss::hash] == "9F3085D85F472D1CC29627F260DF68EDE59D42D1D0C33E345" "ECF0D4CE981D0A8") && - (payment[jss::validated] == true) && - (payment[jss::ledger_index] == 3) && + (payment[jss::validated] == true) && (payment[jss::ledger_index] == 3) && (payment[jss::ledger_hash] == "5476DCD816EA04CBBA57D47BBF1FC58A5217CC93A5ADD79CB" "580A5AFDD727E33") && - (payment[jss::close_time_iso] == - "2000-01-01T00:00:10Z"); + (payment[jss::close_time_iso] == "2000-01-01T00:00:10Z"); } else return false; @@ -182,117 +138,91 @@ class AccountTx_test : public beast::unit_test::suite }; auto noTxs = [](Json::Value const& j) { - return j.isMember(jss::result) && - (j[jss::result][jss::status] == "success") && + return j.isMember(jss::result) && (j[jss::result][jss::status] == "success") && (j[jss::result][jss::transactions].size() == 0); }; auto isErr = [](Json::Value const& j, error_code_i code) { - return j.isMember(jss::result) && - j[jss::result].isMember(jss::error) && + return j.isMember(jss::result) && j[jss::result].isMember(jss::error) && j[jss::result][jss::error] == RPC::get_error_info(code).token; }; Json::Value jParams; jParams[jss::api_version] = apiVersion; - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(jParams)), - rpcINVALID_PARAMS)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(jParams)), rpcINVALID_PARAMS)); jParams[jss::account] = "0xDEADBEEF"; - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(jParams)), - rpcACT_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(jParams)), rpcACT_MALFORMED)); jParams[jss::account] = A1.human(); - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(jParams)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(jParams)))); // Ledger min/max index { Json::Value p{jParams}; p[jss::ledger_index_min] = -1; p[jss::ledger_index_max] = -1; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); p[jss::ledger_index_min] = 0; p[jss::ledger_index_max] = 100; if (apiVersion < 2u) - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_IDX_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); p[jss::ledger_index_min] = 1; p[jss::ledger_index_max] = 2; if (apiVersion < 2u) - BEAST_EXPECT( - noTxs(env.rpc("json", "account_tx", to_string(p)))); + BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_IDX_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); p[jss::ledger_index_min] = 2; p[jss::ledger_index_max] = 1; BEAST_EXPECT(isErr( env.rpc("json", "account_tx", to_string(p)), - (apiVersion == 1 ? rpcLGR_IDXS_INVALID - : rpcINVALID_LGR_RANGE))); + (apiVersion == 1 ? rpcLGR_IDXS_INVALID : rpcINVALID_LGR_RANGE))); } // Ledger index min only { Json::Value p{jParams}; p[jss::ledger_index_min] = -1; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); p[jss::ledger_index_min] = 1; if (apiVersion < 2u) - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_IDX_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); - p[jss::ledger_index_min] = env.current()->info().seq; + p[jss::ledger_index_min] = env.current()->header().seq; BEAST_EXPECT(isErr( env.rpc("json", "account_tx", to_string(p)), - (apiVersion == 1 ? rpcLGR_IDXS_INVALID - : rpcINVALID_LGR_RANGE))); + (apiVersion == 1 ? rpcLGR_IDXS_INVALID : rpcINVALID_LGR_RANGE))); } // Ledger index max only { Json::Value p{jParams}; p[jss::ledger_index_max] = -1; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); - p[jss::ledger_index_max] = env.current()->info().seq; + p[jss::ledger_index_max] = env.current()->header().seq; if (apiVersion < 2u) - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_IDX_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); p[jss::ledger_index_max] = 3; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); - p[jss::ledger_index_max] = env.closed()->info().seq; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + p[jss::ledger_index_max] = env.closed()->header().seq; + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); - p[jss::ledger_index_max] = env.closed()->info().seq - 1; + p[jss::ledger_index_max] = env.closed()->header().seq - 1; BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p)))); } @@ -300,32 +230,27 @@ class AccountTx_test : public beast::unit_test::suite { Json::Value p{jParams}; - p[jss::ledger_index] = env.closed()->info().seq; - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + p[jss::ledger_index] = env.closed()->header().seq; + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); - p[jss::ledger_index] = env.closed()->info().seq - 1; + p[jss::ledger_index] = env.closed()->header().seq - 1; BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p)))); - p[jss::ledger_index] = env.current()->info().seq; - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_NOT_VALIDATED)); + p[jss::ledger_index] = env.current()->header().seq; + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_NOT_VALIDATED)); - p[jss::ledger_index] = env.current()->info().seq + 1; - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), rpcLGR_NOT_FOUND)); + p[jss::ledger_index] = env.current()->header().seq + 1; + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_NOT_FOUND)); } // Ledger Hash { Json::Value p{jParams}; - p[jss::ledger_hash] = to_string(env.closed()->info().hash); - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + p[jss::ledger_hash] = to_string(env.closed()->header().hash); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); - p[jss::ledger_hash] = to_string(env.closed()->info().parentHash); + p[jss::ledger_hash] = to_string(env.closed()->header().parentHash); BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p)))); } @@ -341,36 +266,28 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index] = -1; if (apiVersion < 2u) - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcINVALID_PARAMS)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); } // Ledger index max only { Json::Value p{jParams}; - p[jss::ledger_index_max] = env.current()->info().seq; + p[jss::ledger_index_max] = env.current()->header().seq; if (apiVersion < 2u) - BEAST_EXPECT(hasTxs( - env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcLGR_IDX_MALFORMED)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); } // test account non-string { auto testInvalidAccountParam = [&](auto const& param) { Json::Value params; params[jss::account] = param; - auto jrr = env.rpc( - "json", "account_tx", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "account_tx", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -390,9 +307,7 @@ class AccountTx_test : public beast::unit_test::suite BEAST_EXPECT(result[jss::result][jss::status] == "success"); } else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcINVALID_PARAMS)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); p[jss::binary] = true; Json::Value result{env.rpc("json", "account_tx", to_string(p))}; @@ -402,9 +317,7 @@ class AccountTx_test : public beast::unit_test::suite if (apiVersion < 2u) BEAST_EXPECT(result[jss::result][jss::status] == "success"); else - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcINVALID_PARAMS)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); p[jss::forward] = false; result = env.rpc("json", "account_tx", to_string(p)); @@ -416,90 +329,61 @@ class AccountTx_test : public beast::unit_test::suite // Test case: limit = 0 should fail (below minimum) p[jss::limit] = 0; - BEAST_EXPECT(isErr( - env.rpc("json", "account_tx", to_string(p)), - rpcINVALID_PARAMS)); + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); // Test case: limit = 1.2 should fail (not an integer) p[jss::limit] = 1.2; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = "10" should fail (string instead of integer) p[jss::limit] = "10"; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = true should fail (boolean instead of integer) p[jss::limit] = true; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = false should fail (boolean instead of integer) p[jss::limit] = false; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = -1 should fail (negative number) p[jss::limit] = -1; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = [] should fail (array instead of integer) p[jss::limit] = Json::Value(Json::arrayValue); BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = {} should fail (object instead of integer) p[jss::limit] = Json::Value(Json::objectValue); BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = "malformed" should fail (malformed string) p[jss::limit] = "malformed"; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = ["limit"] should fail (array with string) p[jss::limit] = Json::Value(Json::arrayValue); p[jss::limit].append("limit"); BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = {"limit": 10} should fail (object with @@ -507,19 +391,12 @@ class AccountTx_test : public beast::unit_test::suite p[jss::limit] = Json::Value(Json::objectValue); p[jss::limit][jss::limit] = 10; BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::error_message] == + env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); // Test case: limit = 10 should succeed (valid integer) p[jss::limit] = 10; - BEAST_EXPECT( - env.rpc( - "json", - "account_tx", - to_string(p))[jss::result][jss::status] == "success"); + BEAST_EXPECT(env.rpc("json", "account_tx", to_string(p))[jss::result][jss::status] == "success"); } } @@ -567,31 +444,26 @@ class AccountTx_test : public beast::unit_test::suite // Escrow { // Create an escrow. Requires either a CancelAfter or FinishAfter. - auto escrow = [](Account const& account, - Account const& to, - STAmount const& amount) { - Json::Value escro; - escro[jss::TransactionType] = jss::EscrowCreate; - escro[jss::Account] = account.human(); - escro[jss::Destination] = to.human(); - escro[jss::Amount] = amount.getJson(JsonOptions::none); - return escro; + auto escrow = [](Account const& account, Account const& to, STAmount const& amount) { + Json::Value escrow; + escrow[jss::TransactionType] = jss::EscrowCreate; + escrow[jss::Account] = account.human(); + escrow[jss::Destination] = to.human(); + escrow[jss::Amount] = amount.getJson(JsonOptions::none); + return escrow; }; NetClock::time_point const nextTime{env.now() + 2s}; Json::Value escrowWithFinish{escrow(alice, alice, XRP(500))}; - escrowWithFinish[sfFinishAfter.jsonName] = - nextTime.time_since_epoch().count(); + escrowWithFinish[sfFinishAfter.jsonName] = nextTime.time_since_epoch().count(); std::uint32_t const escrowFinishSeq{env.seq(alice)}; env(escrowWithFinish, sig(alie)); Json::Value escrowWithCancel{escrow(alice, alice, XRP(500))}; - escrowWithCancel[sfFinishAfter.jsonName] = - nextTime.time_since_epoch().count(); - escrowWithCancel[sfCancelAfter.jsonName] = - nextTime.time_since_epoch().count() + 1; + escrowWithCancel[sfFinishAfter.jsonName] = nextTime.time_since_epoch().count(); + escrowWithCancel[sfCancelAfter.jsonName] = nextTime.time_since_epoch().count() + 1; std::uint32_t const escrowCancelSeq{env.seq(alice)}; env(escrowWithCancel, sig(alie)); @@ -623,24 +495,20 @@ class AccountTx_test : public beast::unit_test::suite payChanCreate[jss::TransactionType] = jss::PaymentChannelCreate; payChanCreate[jss::Account] = alice.human(); payChanCreate[jss::Destination] = gw.human(); - payChanCreate[jss::Amount] = - XRP(500).value().getJson(JsonOptions::none); - payChanCreate[sfSettleDelay.jsonName] = - NetClock::duration{100s}.count(); + payChanCreate[jss::Amount] = XRP(500).value().getJson(JsonOptions::none); + payChanCreate[sfSettleDelay.jsonName] = NetClock::duration{100s}.count(); payChanCreate[sfPublicKey.jsonName] = strHex(alice.pk().slice()); env(payChanCreate, sig(alie)); env.close(); - std::string const payChanIndex{ - strHex(keylet::payChan(alice, gw, payChanSeq).key)}; + std::string const payChanIndex{strHex(keylet::payChan(alice, gw, payChanSeq).key)}; { Json::Value payChanFund; payChanFund[jss::TransactionType] = jss::PaymentChannelFund; payChanFund[jss::Account] = alice.human(); payChanFund[sfChannel.jsonName] = payChanIndex; - payChanFund[jss::Amount] = - XRP(200).value().getJson(JsonOptions::none); + payChanFund[jss::Amount] = XRP(200).value().getJson(JsonOptions::none); env(payChanFund, sig(alie)); env.close(); } @@ -670,7 +538,7 @@ class AccountTx_test : public beast::unit_test::suite env.close(); } { - // Deposit preauthorization with a Ticket. + // Deposit pre-authorization with a Ticket. std::uint32_t const tktSeq{env.seq(alice) + 1}; env(ticket::create(alice, 1), sig(alie)); env.close(); @@ -685,8 +553,7 @@ class AccountTx_test : public beast::unit_test::suite params[jss::ledger_index_min] = -1; params[jss::ledger_index_max] = -1; - Json::Value const result{ - env.rpc("json", "account_tx", to_string(params))}; + Json::Value const result{env.rpc("json", "account_tx", to_string(params))}; BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result][jss::transactions].isArray()); @@ -723,8 +590,7 @@ class AccountTx_test : public beast::unit_test::suite }; // clang-format on - BEAST_EXPECT( - std::size(sanity) == result[jss::result][jss::transactions].size()); + BEAST_EXPECT(std::size(sanity) == result[jss::result][jss::transactions].size()); for (unsigned int index{0}; index < std::size(sanity); ++index) { @@ -758,8 +624,7 @@ class AccountTx_test : public beast::unit_test::suite env(noop(becky)); // Close enough ledgers to be able to delete becky's account. - std::uint32_t const ledgerCount{ - env.current()->seq() + 257 - env.seq(becky)}; + std::uint32_t const ledgerCount{env.current()->seq() + 257 - env.seq(becky)}; for (std::uint32_t i = 0; i < ledgerCount; ++i) env.close(); @@ -800,35 +665,26 @@ class AccountTx_test : public beast::unit_test::suite params[jss::ledger_index_min] = -1; params[jss::ledger_index_max] = -1; - Json::Value const result{ - env.rpc("json", "account_tx", to_string(params))}; + Json::Value const result{env.rpc("json", "account_tx", to_string(params))}; BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result][jss::transactions].isArray()); // The first two transactions listed in sanity haven't happened yet. - constexpr unsigned int beckyDeletedOffest = 2; - BEAST_EXPECT( - std::size(sanity) == - result[jss::result][jss::transactions].size() + - beckyDeletedOffest); + constexpr unsigned int beckyDeletedOffset = 2; + BEAST_EXPECT(std::size(sanity) == result[jss::result][jss::transactions].size() + beckyDeletedOffset); Json::Value const& txs{result[jss::result][jss::transactions]}; - for (unsigned int index = beckyDeletedOffest; - index < std::size(sanity); - ++index) + for (unsigned int index = beckyDeletedOffset; index < std::size(sanity); ++index) { - checkSanity(txs[index - beckyDeletedOffest], sanity[index]); + checkSanity(txs[index - beckyDeletedOffset], sanity[index]); } } // All it takes is a large enough XRP payment to resurrect // becky's account. Try too small a payment. - env(pay(alice, - becky, - drops(env.current()->fees().accountReserve(0)) - XRP(1)), - ter(tecNO_DST_INSUF_XRP)); + env(pay(alice, becky, drops(env.current()->fees().accountReserve(0)) - XRP(1)), ter(tecNO_DST_INSUF_XRP)); env.close(); // Actually resurrect becky's account. @@ -850,14 +706,12 @@ class AccountTx_test : public beast::unit_test::suite params[jss::ledger_index_min] = -1; params[jss::ledger_index_max] = -1; - Json::Value const result{ - env.rpc("json", "account_tx", to_string(params))}; + Json::Value const result{env.rpc("json", "account_tx", to_string(params))}; BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result][jss::transactions].isArray()); - BEAST_EXPECT( - std::size(sanity) == result[jss::result][jss::transactions].size()); + BEAST_EXPECT(std::size(sanity) == result[jss::result][jss::transactions].size()); Json::Value const& txs{result[jss::result][jss::transactions]}; @@ -886,28 +740,23 @@ class AccountTx_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); // check the latest mpt-related txn is in alice's account history - auto const checkAliceAcctTx = [&](size_t size, - Json::StaticString txType) { + auto const checkAliceAcctTx = [&](size_t size, Json::StaticString txType) { Json::Value params; params[jss::account] = alice.human(); params[jss::limit] = 100; - auto const jv = - env.rpc("json", "account_tx", to_string(params))[jss::result]; + auto const jv = env.rpc("json", "account_tx", to_string(params))[jss::result]; BEAST_EXPECT(jv[jss::transactions].size() == size); auto const& tx0(jv[jss::transactions][0u][jss::tx]); BEAST_EXPECT(tx0[jss::TransactionType] == txType); - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; BEAST_EXPECT(tx0[jss::hash] == txHash); }; // alice creates issuance mptAlice.create( - {.ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer}); + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer}); checkAliceAcctTx(3, jss::MPTokenIssuanceCreate); @@ -922,7 +771,7 @@ class AccountTx_test : public beast::unit_test::suite // // ledger hash should be fixed regardless any change to account history // BEAST_EXPECT( - // to_string(env.closed()->info().hash) == + // to_string(env.closed()->header().hash) == // "0BD507BB87D3C0E73B462485E6E381798A8C82FC49BF17FE39C60E08A1AF035D"); // alice authorizes bob @@ -950,14 +799,13 @@ public: void run() override { - forAllApiVersions( - std::bind_front(&AccountTx_test::testParameters, this)); + forAllApiVersions(std::bind_front(&AccountTx_test::testParameters, this)); testContents(); testAccountDelete(); testMPT(); } }; -BEAST_DEFINE_TESTSUITE(AccountTx, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AccountTx, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/AmendmentBlocked_test.cpp b/src/test/rpc/AmendmentBlocked_test.cpp index 4708a873f6..73a8c6d299 100644 --- a/src/test/rpc/AmendmentBlocked_test.cpp +++ b/src/test/rpc/AmendmentBlocked_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { class AmendmentBlocked_test : public beast::unit_test::suite { @@ -79,12 +60,10 @@ class AmendmentBlocked_test : public beast::unit_test::suite pf_req[jss::subcommand] = "create"; pf_req[jss::source_account] = alice.human(); pf_req[jss::destination_account] = bob.human(); - pf_req[jss::destination_amount] = - bob["USD"](20).value().getJson(JsonOptions::none); + pf_req[jss::destination_amount] = bob["USD"](20).value().getJson(JsonOptions::none); jr = wsc->invoke("path_find", pf_req)[jss::result]; BEAST_EXPECT( - jr.isMember(jss::alternatives) && jr[jss::alternatives].isArray() && - jr[jss::alternatives].size() == 1); + jr.isMember(jss::alternatives) && jr[jss::alternatives].isArray() && jr[jss::alternatives].size() == 1); BEAST_EXPECT(!jr.isMember(jss::warnings)); // submit @@ -92,9 +71,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite Serializer s; jt.stx->add(s); jr = env.rpc("submit", strHex(s.slice()))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::engine_result) && - jr[jss::engine_result] == "tesSUCCESS"); + BEAST_EXPECT(jr.isMember(jss::engine_result) && jr[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // submit_multisigned @@ -119,11 +96,8 @@ class AmendmentBlocked_test : public beast::unit_test::suite Json::Value ms_req; ms_req[jss::tx_json] = jr[jss::tx_json]; - jr = env.rpc( - "json", "submit_multisigned", to_string(ms_req))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::engine_result) && - jr[jss::engine_result] == "tesSUCCESS"); + jr = env.rpc("json", "submit_multisigned", to_string(ms_req))[jss::result]; + BEAST_EXPECT(jr.isMember(jss::engine_result) && jr[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // set up an amendment warning. Nothing changes @@ -150,12 +124,10 @@ class AmendmentBlocked_test : public beast::unit_test::suite pf_req[jss::subcommand] = "create"; pf_req[jss::source_account] = alice.human(); pf_req[jss::destination_account] = bob.human(); - pf_req[jss::destination_amount] = - bob["USD"](20).value().getJson(JsonOptions::none); + pf_req[jss::destination_amount] = bob["USD"](20).value().getJson(JsonOptions::none); jr = wsc->invoke("path_find", pf_req)[jss::result]; BEAST_EXPECT( - jr.isMember(jss::alternatives) && jr[jss::alternatives].isArray() && - jr[jss::alternatives].size() == 1); + jr.isMember(jss::alternatives) && jr[jss::alternatives].isArray() && jr[jss::alternatives].size() == 1); BEAST_EXPECT(!jr.isMember(jss::warnings)); // submit @@ -163,9 +135,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite s.erase(); jt.stx->add(s); jr = env.rpc("submit", strHex(s.slice()))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::engine_result) && - jr[jss::engine_result] == "tesSUCCESS"); + BEAST_EXPECT(jr.isMember(jss::engine_result) && jr[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // submit_multisigned @@ -187,11 +157,8 @@ class AmendmentBlocked_test : public beast::unit_test::suite BEAST_EXPECT(!jr.isMember(jss::warnings)); ms_req[jss::tx_json] = jr[jss::tx_json]; - jr = env.rpc( - "json", "submit_multisigned", to_string(ms_req))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::engine_result) && - jr[jss::engine_result] == "tesSUCCESS"); + jr = env.rpc("json", "submit_multisigned", to_string(ms_req))[jss::result]; + BEAST_EXPECT(jr.isMember(jss::engine_result) && jr[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // make the network amendment blocked...now all the same @@ -201,36 +168,31 @@ class AmendmentBlocked_test : public beast::unit_test::suite // ledger_accept jr = env.rpc("ledger_accept")[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(jr[jss::status] == "error"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // ledger_current jr = env.rpc("ledger_current")[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(jr[jss::status] == "error"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // owner_info jr = env.rpc("owner_info", alice.human())[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(jr[jss::status] == "error"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // path_find jr = wsc->invoke("path_find", pf_req)[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(jr[jss::status] == "error"); BEAST_EXPECT(!jr.isMember(jss::warnings)); // submit jr = env.rpc("submit", strHex(s.slice()))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(jr[jss::status] == "error"); BEAST_EXPECT(!jr.isMember(jss::warnings)); @@ -240,10 +202,8 @@ class AmendmentBlocked_test : public beast::unit_test::suite jr = env.rpc("json", "sign_for", to_string(sign_for))[jss::result]; BEAST_EXPECT(jr[jss::status] == "success"); ms_req[jss::tx_json] = jr[jss::tx_json]; - jr = env.rpc( - "json", "submit_multisigned", to_string(ms_req))[jss::result]; - BEAST_EXPECT( - jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); + jr = env.rpc("json", "submit_multisigned", to_string(ms_req))[jss::result]; + BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked"); BEAST_EXPECT(!jr.isMember(jss::warnings)); } @@ -255,6 +215,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(AmendmentBlocked, rpc, ripple); +BEAST_DEFINE_TESTSUITE(AmendmentBlocked, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/BookChanges_test.cpp b/src/test/rpc/BookChanges_test.cpp index 41b26415af..4ea4b8233b 100644 --- a/src/test/rpc/BookChanges_test.cpp +++ b/src/test/rpc/BookChanges_test.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include "xrpl/beast/unit_test/suite.h" #include "xrpl/protocol/jss.h" -namespace ripple { +namespace xrpl { namespace test { class BookChanges_test : public beast::unit_test::suite @@ -77,8 +58,7 @@ public: // As per convention in XRPL, ledgers can be specified with strings // "closed", "validated" or "current" - Json::Value const resp = - env.rpc("json", "book_changes", to_string(Json::Value{})); + Json::Value const resp = env.rpc("json", "book_changes", to_string(Json::Value{})); BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); BEAST_EXPECT(resp[jss::result][jss::status] == "success"); @@ -94,27 +74,21 @@ public: using namespace jtx; FeatureBitset const all{ - jtx::testable_amendments() | featurePermissionedDomains | - featureCredentials | featurePermissionedDEX}; + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); PermissionedDEX permDex(env); - auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = - permDex; + auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = permDex; auto wsc = makeWSClient(env.app().config()); env(offer(alice, XRP(10), USD(10)), domain(domainID)); env.close(); - env(pay(bob, carol, USD(10)), - path(~USD), - sendmax(XRP(10)), - domain(domainID)); + env(pay(bob, carol, USD(10)), path(~USD), sendmax(XRP(10)), domain(domainID)); env.close(); - std::string const txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string const txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; Json::Value const txResult = env.rpc("tx", txHash)[jss::result]; auto const ledgerIndex = txResult[jss::ledger_index].asInt(); @@ -126,9 +100,7 @@ public: auto jrr = jv[jss::result]; BEAST_EXPECT(jrr[jss::changes].size() == 1); - BEAST_EXPECT( - jrr[jss::changes][0u][jss::domain].asString() == - to_string(domainID)); + BEAST_EXPECT(jrr[jss::changes][0u][jss::domain].asString() == to_string(domainID)); } void @@ -143,7 +115,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(BookChanges, rpc, ripple); +BEAST_DEFINE_TESTSUITE(BookChanges, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Book_test.cpp b/src/test/rpc/Book_test.cpp index 0d5366d3ef..543e163432 100644 --- a/src/test/rpc/Book_test.cpp +++ b/src/test/rpc/Book_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,17 +9,13 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class Book_test : public beast::unit_test::suite { std::string - getBookDir( - jtx::Env& env, - Issue const& in, - Issue const& out, - std::optional const& domain = std::nullopt) + getBookDir(jtx::Env& env, Issue const& in, Issue const& out, std::optional const& domain = std::nullopt) { std::string dir; auto uBookBase = getBookBase({in, out, domain}); @@ -48,8 +27,7 @@ class Book_test : public beast::unit_test::suite auto sleOfferDir = view->read(keylet::page(key.value())); uint256 offerIndex; unsigned int bookEntry; - cdirFirst( - *view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex); + cdirFirst(*view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex); auto sleOffer = view->read(keylet::offer(offerIndex)); dir = to_string(sleOffer->getFieldH256(sfBookDirectory)); } @@ -83,35 +61,28 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0); BEAST_EXPECT(!jv[jss::result].isMember(jss::asks)); BEAST_EXPECT(!jv[jss::result].isMember(jss::bids)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 1))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 1))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -127,10 +98,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -168,41 +137,32 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 1); BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 1); + jv[jss::result][jss::offers][0u][jss::TakerGets] == XRP(200).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerGets] == - XRP(200).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none)); + jv[jss::result][jss::offers][0u][jss::TakerPays] == USD(100).value().getJson(JsonOptions::none)); BEAST_EXPECT(!jv[jss::result].isMember(jss::asks)); BEAST_EXPECT(!jv[jss::result].isMember(jss::bids)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 3))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 3))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -218,10 +178,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -253,37 +211,28 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::asks) && - jv[jss::result][jss::asks].size() == 0); - BEAST_EXPECT( - jv[jss::result].isMember(jss::bids) && - jv[jss::result][jss::bids].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 0); BEAST_EXPECT(!jv[jss::result].isMember(jss::offers)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 1))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 1))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -296,10 +245,8 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - XRP(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none); })); } @@ -308,10 +255,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -350,49 +295,32 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::asks) && - jv[jss::result][jss::asks].size() == 1); - BEAST_EXPECT( - jv[jss::result].isMember(jss::bids) && - jv[jss::result][jss::bids].size() == 1); - BEAST_EXPECT( - jv[jss::result][jss::asks][0u][jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::asks][0u][jss::TakerPays] == - XRP(500).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][0u][jss::TakerGets] == - XRP(200).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][0u][jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 1); + BEAST_EXPECT(jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 1); + BEAST_EXPECT(jv[jss::result][jss::asks][0u][jss::TakerGets] == USD(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::asks][0u][jss::TakerPays] == XRP(500).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][0u][jss::TakerGets] == XRP(200).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][0u][jss::TakerPays] == USD(100).value().getJson(JsonOptions::none)); BEAST_EXPECT(!jv[jss::result].isMember(jss::offers)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 3))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 3))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -405,10 +333,8 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - XRP(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none); })); } @@ -417,10 +343,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -461,35 +385,28 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0); BEAST_EXPECT(!jv[jss::result].isMember(jss::asks)); BEAST_EXPECT(!jv[jss::result].isMember(jss::bids)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 1))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 1))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -502,18 +419,15 @@ public: { // Create an ask: TakerPays 700/CNY, TakerGets 100/JPY - env(offer("alice", CNY(700), JPY(100)), - require(owners("alice", 3))); + env(offer("alice", CNY(700), JPY(100)), require(owners("alice", 3))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - JPY(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - CNY(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none); })); } @@ -529,10 +443,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -586,47 +498,36 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 2); BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 2); + jv[jss::result][jss::offers][0u][jss::TakerGets] == XRP(200).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerGets] == - XRP(200).value().getJson(JsonOptions::none)); + jv[jss::result][jss::offers][0u][jss::TakerPays] == USD(100).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none)); + jv[jss::result][jss::offers][1u][jss::TakerGets] == CNY(200).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][1u][jss::TakerGets] == - CNY(200).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][1u][jss::TakerPays] == - JPY(100).value().getJson(JsonOptions::none)); + jv[jss::result][jss::offers][1u][jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none)); BEAST_EXPECT(!jv[jss::result].isMember(jss::asks)); BEAST_EXPECT(!jv[jss::result].isMember(jss::bids)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 5))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 5))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -639,18 +540,15 @@ public: { // Create an ask: TakerPays 700/CNY, TakerGets 100/JPY - env(offer("alice", CNY(700), JPY(100)), - require(owners("alice", 7))); + env(offer("alice", CNY(700), JPY(100)), require(owners("alice", 7))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - JPY(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - CNY(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none); })); } @@ -666,10 +564,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -712,37 +608,28 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::asks) && - jv[jss::result][jss::asks].size() == 0); - BEAST_EXPECT( - jv[jss::result].isMember(jss::bids) && - jv[jss::result][jss::bids].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 0); BEAST_EXPECT(!jv[jss::result].isMember(jss::offers)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 1))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 1))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -755,27 +642,22 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - XRP(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none); })); } { // Create an ask: TakerPays 700/CNY, TakerGets 100/JPY - env(offer("alice", CNY(700), JPY(100)), - require(owners("alice", 3))); + env(offer("alice", CNY(700), JPY(100)), require(owners("alice", 3))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - JPY(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - CNY(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none); })); } @@ -788,10 +670,8 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - CNY(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - JPY(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == CNY(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none); })); } @@ -800,10 +680,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -860,61 +738,36 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::asks) && - jv[jss::result][jss::asks].size() == 2); - BEAST_EXPECT( - jv[jss::result].isMember(jss::bids) && - jv[jss::result][jss::bids].size() == 2); - BEAST_EXPECT( - jv[jss::result][jss::asks][0u][jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::asks][0u][jss::TakerPays] == - XRP(500).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::asks][1u][jss::TakerGets] == - JPY(100).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::asks][1u][jss::TakerPays] == - CNY(500).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][0u][jss::TakerGets] == - XRP(200).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][0u][jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][1u][jss::TakerGets] == - CNY(200).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::bids][1u][jss::TakerPays] == - JPY(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 2); + BEAST_EXPECT(jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 2); + BEAST_EXPECT(jv[jss::result][jss::asks][0u][jss::TakerGets] == USD(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::asks][0u][jss::TakerPays] == XRP(500).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::asks][1u][jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::asks][1u][jss::TakerPays] == CNY(500).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][0u][jss::TakerGets] == XRP(200).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][0u][jss::TakerPays] == USD(100).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][1u][jss::TakerGets] == CNY(200).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::bids][1u][jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none)); BEAST_EXPECT(!jv[jss::result].isMember(jss::offers)); } { // Create an ask: TakerPays 700, TakerGets 100/USD - env(offer("alice", XRP(700), USD(100)), - require(owners("alice", 5))); + env(offer("alice", XRP(700), USD(100)), require(owners("alice", 5))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - XRP(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none); })); } @@ -927,27 +780,22 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - XRP(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - USD(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none); })); } { // Create an ask: TakerPays 700/CNY, TakerGets 100/JPY - env(offer("alice", CNY(700), JPY(100)), - require(owners("alice", 7))); + env(offer("alice", CNY(700), JPY(100)), require(owners("alice", 7))); env.close(); // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - JPY(100).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - CNY(700).value().getJson(JsonOptions::none); + t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none); })); } @@ -960,10 +808,8 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { auto const& t = jv[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - CNY(75).value().getJson(JsonOptions::none) && - t[jss::TakerPays] == - JPY(100).value().getJson(JsonOptions::none); + t[jss::TakerGets] == CNY(75).value().getJson(JsonOptions::none) && + t[jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none); })); } @@ -972,10 +818,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -1008,17 +852,13 @@ public: auto jv = wsc->invoke("subscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0); BEAST_EXPECT(!jv[jss::result].isMember(jss::asks)); BEAST_EXPECT(!jv[jss::result].isMember(jss::bids)); } @@ -1042,10 +882,8 @@ public: auto jv = wsc->invoke("book_offers", jvParams); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } auto jrr = jv[jss::result]; @@ -1054,20 +892,14 @@ public: BEAST_EXPECT(jrr[jss::offers].size() == 1); auto const jrOffer = jrr[jss::offers][0u]; BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human()); - BEAST_EXPECT( - jrOffer[sfBookDirectory.fieldName] == - getBookDir(env, XRP, USD.issue())); + BEAST_EXPECT(jrOffer[sfBookDirectory.fieldName] == getBookDir(env, XRP, USD.issue())); BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == "0"); BEAST_EXPECT(jrOffer[jss::Flags] == 0); BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer); BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == "0"); BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 5); - BEAST_EXPECT( - jrOffer[jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrOffer[jss::TakerPays] == - XRP(4000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[jss::TakerGets] == USD(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[jss::TakerPays] == XRP(4000).value().getJson(JsonOptions::none)); BEAST_EXPECT(jrOffer[jss::owner_funds] == "100"); BEAST_EXPECT(jrOffer[jss::quality] == "400000000"); @@ -1075,11 +907,8 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { auto const& t = jval[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none) && - t[jss::owner_funds] == "100" && - t[jss::TakerPays] == - XRP(4000).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(10).value().getJson(JsonOptions::none) && t[jss::owner_funds] == "100" && + t[jss::TakerPays] == XRP(4000).value().getJson(JsonOptions::none); })); env(offer(bob, XRP(2000), USD(5))); @@ -1088,20 +917,15 @@ public: BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { auto const& t = jval[jss::transaction]; return t[jss::TransactionType] == jss::OfferCreate && - t[jss::TakerGets] == - USD(5).value().getJson(JsonOptions::none) && - t[jss::owner_funds] == "50" && - t[jss::TakerPays] == - XRP(2000).value().getJson(JsonOptions::none); + t[jss::TakerGets] == USD(5).value().getJson(JsonOptions::none) && t[jss::owner_funds] == "50" && + t[jss::TakerPays] == XRP(2000).value().getJson(JsonOptions::none); })); jv = wsc->invoke("book_offers", jvParams); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } jrr = jv[jss::result]; @@ -1110,30 +934,22 @@ public: BEAST_EXPECT(jrr[jss::offers].size() == 2); auto const jrNextOffer = jrr[jss::offers][1u]; BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human()); - BEAST_EXPECT( - jrNextOffer[sfBookDirectory.fieldName] == - getBookDir(env, XRP, USD.issue())); + BEAST_EXPECT(jrNextOffer[sfBookDirectory.fieldName] == getBookDir(env, XRP, USD.issue())); BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] == "0"); BEAST_EXPECT(jrNextOffer[jss::Flags] == 0); BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == jss::Offer); BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] == "0"); BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 5); - BEAST_EXPECT( - jrNextOffer[jss::TakerGets] == - USD(5).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrNextOffer[jss::TakerPays] == - XRP(2000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrNextOffer[jss::TakerGets] == USD(5).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrNextOffer[jss::TakerPays] == XRP(2000).value().getJson(JsonOptions::none)); BEAST_EXPECT(jrNextOffer[jss::owner_funds] == "50"); BEAST_EXPECT(jrNextOffer[jss::quality] == "400000000"); jv = wsc->invoke("unsubscribe", books); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -1329,8 +1145,7 @@ public: { Json::Value jvParams; jvParams[jss::ledger_index] = 10u; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "lgrNotFound"); BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound"); } @@ -1338,22 +1153,18 @@ public: { Json::Value jvParams; jvParams[jss::ledger_index] = "validated"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Missing field 'taker_pays'."); + BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_pays'."); } { Json::Value jvParams; jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays] = Json::objectValue; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Missing field 'taker_gets'."); + BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_gets'."); } { @@ -1361,12 +1172,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays] = "not an object"; jvParams[jss::taker_gets] = Json::objectValue; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays', not object."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays', not object."); } { @@ -1374,12 +1182,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays] = Json::objectValue; jvParams[jss::taker_gets] = "not an object"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets', not object."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets', not object."); } { @@ -1387,12 +1192,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays] = Json::objectValue; jvParams[jss::taker_gets] = Json::objectValue; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Missing field 'taker_pays.currency'."); + BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_pays.currency'."); } { @@ -1400,12 +1202,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays][jss::currency] = 1; jvParams[jss::taker_gets] = Json::objectValue; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.currency', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.currency', not string."); } { @@ -1413,12 +1212,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets] = Json::objectValue; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Missing field 'taker_gets.currency'."); + BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_gets.currency'."); } { @@ -1426,12 +1222,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = 1; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets.currency', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets.currency', not string."); } { @@ -1439,12 +1232,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays][jss::currency] = "NOT_VALID"; jvParams[jss::taker_gets][jss::currency] = "XRP"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "srcCurMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.currency', bad currency."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.currency', bad currency."); } { @@ -1452,12 +1242,9 @@ public: jvParams[jss::ledger_index] = "validated"; jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "NOT_VALID"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "dstAmtMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets.currency', bad currency."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets.currency', bad currency."); } { @@ -1466,12 +1253,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = 1; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets.issuer', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets.issuer', not string."); } { @@ -1480,12 +1264,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_pays][jss::issuer] = 1; jvParams[jss::taker_gets][jss::currency] = "USD"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.issuer', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', not string."); } { @@ -1494,12 +1275,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_pays][jss::issuer] = gw.human() + "DEAD"; jvParams[jss::taker_gets][jss::currency] = "USD"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.issuer', bad issuer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', bad issuer."); } { @@ -1508,12 +1286,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_pays][jss::issuer] = toBase58(noAccount()); jvParams[jss::taker_gets][jss::currency] = "USD"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.issuer', bad issuer account one."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', bad issuer account one."); } { @@ -1522,12 +1297,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human() + "DEAD"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets.issuer', bad issuer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets.issuer', bad issuer."); } { @@ -1536,12 +1308,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = toBase58(noAccount()); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_gets.issuer', bad issuer account one."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets.issuer', bad issuer account one."); } { @@ -1551,8 +1320,7 @@ public: jvParams[jss::taker_pays][jss::issuer] = alice.human(); jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed"); BEAST_EXPECT( jrr[jss::error_message] == @@ -1567,12 +1335,9 @@ public: jvParams[jss::taker_pays][jss::issuer] = toBase58(xrpAccount()); jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker_pays.issuer', expected non-XRP issuer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', expected non-XRP issuer."); } { @@ -1582,12 +1347,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'taker', not string."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker', not string."); } { @@ -1597,8 +1359,7 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker'."); } @@ -1611,8 +1372,7 @@ public: jvParams[jss::taker_pays][jss::issuer] = gw.human(); jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "badMarket"); BEAST_EXPECT(jrr[jss::error_message] == "No such market."); } @@ -1625,12 +1385,9 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'limit', not unsigned integer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not unsigned integer."); } { @@ -1641,8 +1398,7 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit'."); } @@ -1653,8 +1409,7 @@ public: jvParams[jss::taker_pays][jss::currency] = "USD"; jvParams[jss::taker_pays][jss::issuer] = gw.human(); jvParams[jss::taker_gets][jss::currency] = "USD"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed"); BEAST_EXPECT( jrr[jss::error_message] == @@ -1669,8 +1424,7 @@ public: jvParams[jss::taker_pays][jss::issuer] = gw.human(); jvParams[jss::taker_gets][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed"); BEAST_EXPECT( jrr[jss::error_message] == @@ -1685,8 +1439,7 @@ public: jvParams[jss::taker_gets][jss::currency] = "EUR"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); jvParams[jss::domain] = "badString"; - auto const jrr = env.rpc( - "json", "book_offers", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "domainMalformed"); BEAST_EXPECT(jrr[jss::error_message] == "Unable to parse domain."); } @@ -1718,8 +1471,7 @@ public: jvParams[jss::taker_pays][jss::currency] = "XRP"; jvParams[jss::taker_gets][jss::currency] = "USD"; jvParams[jss::taker_gets][jss::issuer] = gw.human(); - auto jrr = - env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::offers].isArray()); BEAST_EXPECT(jrr[jss::offers].size() == (asAdmin ? 1u : 0u)); // NOTE - a marker field is not returned for this method @@ -1727,16 +1479,12 @@ public: jvParams[jss::limit] = RPC::Tuning::bookOffers.rmax + 1; jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::offers].isArray()); - BEAST_EXPECT( - jrr[jss::offers].size() == - (asAdmin ? RPC::Tuning::bookOffers.rmax + 1 : 0u)); + BEAST_EXPECT(jrr[jss::offers].size() == (asAdmin ? RPC::Tuning::bookOffers.rmax + 1 : 0u)); jvParams[jss::limit] = Json::nullValue; jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::offers].isArray()); - BEAST_EXPECT( - jrr[jss::offers].size() == - (asAdmin ? RPC::Tuning::bookOffers.rdefault : 0u)); + BEAST_EXPECT(jrr[jss::offers].size() == (asAdmin ? RPC::Tuning::bookOffers.rDefault : 0u)); } void @@ -1746,8 +1494,7 @@ public: using namespace jtx; FeatureBitset const all{ - jtx::testable_amendments() | featurePermissionedDomains | - featureCredentials | featurePermissionedDEX}; + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); PermissionedDEX permDex(env); @@ -1768,21 +1515,14 @@ public: BEAST_EXPECT(jrr[jss::offers].size() == 1); auto const jrOffer = jrr[jss::offers][0u]; BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human()); - BEAST_EXPECT( - jrOffer[sfBookDirectory.fieldName] == - getBookDir(env, XRP, USD.issue(), domainID)); + BEAST_EXPECT(jrOffer[sfBookDirectory.fieldName] == getBookDir(env, XRP, USD.issue(), domainID)); BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == "0"); BEAST_EXPECT(jrOffer[jss::Flags] == 0); BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer); BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == "0"); - BEAST_EXPECT( - jrOffer[jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrOffer[jss::TakerPays] == - XRP(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrOffer[sfDomainID.jsonName].asString() == to_string(domainID)); + BEAST_EXPECT(jrOffer[jss::TakerGets] == USD(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[jss::TakerPays] == XRP(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[sfDomainID.jsonName].asString() == to_string(domainID)); }; // book_offers: open book doesn't return offer @@ -1801,18 +1541,12 @@ public: } auto checkSubBooks = [&](Json::Value const& jv) { + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 1); BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 1); + jv[jss::result][jss::offers][0u][jss::TakerGets] == USD(10).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerPays] == - XRP(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][0u][sfDomainID.jsonName] - .asString() == to_string(domainID)); + jv[jss::result][jss::offers][0u][jss::TakerPays] == XRP(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::offers][0u][sfDomainID.jsonName].asString() == to_string(domainID)); }; // book_offers: requesting domain book returns hybrid offer @@ -1864,9 +1598,7 @@ public: auto jv = wsc->invoke("subscribe", books); if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 0); + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0); } } @@ -1877,8 +1609,7 @@ public: using namespace jtx; FeatureBitset const all{ - jtx::testable_amendments() | featurePermissionedDomains | - featureCredentials | featurePermissionedDEX}; + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); PermissionedDEX permDex(env); @@ -1891,9 +1622,7 @@ public: auto wsc = makeWSClient(env.app().config()); - env(offer(alice, XRP(10), USD(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(alice, XRP(10), USD(10)), domain(domainID), txflags(tfHybrid)); env.close(); auto checkBookOffers = [&](Json::Value const& jrr) { @@ -1901,21 +1630,14 @@ public: BEAST_EXPECT(jrr[jss::offers].size() == 1); auto const jrOffer = jrr[jss::offers][0u]; BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human()); - BEAST_EXPECT( - jrOffer[sfBookDirectory.fieldName] == - getBookDir(env, XRP, USD.issue(), domainID)); + BEAST_EXPECT(jrOffer[sfBookDirectory.fieldName] == getBookDir(env, XRP, USD.issue(), domainID)); BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == "0"); BEAST_EXPECT(jrOffer[jss::Flags] == lsfHybrid); BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer); BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == "0"); - BEAST_EXPECT( - jrOffer[jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrOffer[jss::TakerPays] == - XRP(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jrOffer[sfDomainID.jsonName].asString() == to_string(domainID)); + BEAST_EXPECT(jrOffer[jss::TakerGets] == USD(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[jss::TakerPays] == XRP(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jrOffer[sfDomainID.jsonName].asString() == to_string(domainID)); BEAST_EXPECT(jrOffer[sfAdditionalBooks.jsonName].size() == 1); }; @@ -1934,18 +1656,12 @@ public: } auto checkSubBooks = [&](Json::Value const& jv) { + BEAST_EXPECT(jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 1); BEAST_EXPECT( - jv[jss::result].isMember(jss::offers) && - jv[jss::result][jss::offers].size() == 1); + jv[jss::result][jss::offers][0u][jss::TakerGets] == USD(10).value().getJson(JsonOptions::none)); BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerGets] == - USD(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][0u][jss::TakerPays] == - XRP(10).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - jv[jss::result][jss::offers][0u][sfDomainID.jsonName] - .asString() == to_string(domainID)); + jv[jss::result][jss::offers][0u][jss::TakerPays] == XRP(10).value().getJson(JsonOptions::none)); + BEAST_EXPECT(jv[jss::result][jss::offers][0u][sfDomainID.jsonName].asString() == to_string(domainID)); }; // book_offers: requesting domain book returns hybrid offer @@ -2028,7 +1744,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(Book, rpc, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(Book, rpc, xrpl, 1); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Connect_test.cpp b/src/test/rpc/Connect_test.cpp index cc021ba08f..c029356bf6 100644 --- a/src/test/rpc/Connect_test.cpp +++ b/src/test/rpc/Connect_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class Connect_test : public beast::unit_test::suite { @@ -41,9 +22,7 @@ class Connect_test : public beast::unit_test::suite BEAST_EXPECT(result[jss::result][jss::status] == "error"); BEAST_EXPECT(result[jss::result].isMember(jss::error)); BEAST_EXPECT(result[jss::result][jss::error] == "notSynced"); - BEAST_EXPECT( - result[jss::result][jss::error_message] == - "Not synced to the network."); + BEAST_EXPECT(result[jss::result][jss::error_message] == "Not synced to the network."); } } @@ -55,6 +34,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Connect, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Connect, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/DeliveredAmount_test.cpp b/src/test/rpc/DeliveredAmount_test.cpp index c1aa77695d..8d376893ec 100644 --- a/src/test/rpc/DeliveredAmount_test.cpp +++ b/src/test/rpc/DeliveredAmount_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { // Helper class to track the expected number `delivered_amount` results. @@ -65,8 +46,7 @@ class CheckDeliveredAmount } public: - explicit CheckDeliveredAmount(bool afterSwitchTime) - : afterSwitchTime_(afterSwitchTime) + explicit CheckDeliveredAmount(bool afterSwitchTime) : afterSwitchTime_(afterSwitchTime) { } @@ -92,8 +72,7 @@ public: bool checkExpectedCounters() const { - return !numExpectedAvailable_ && !numExpectedNotSet_ && - !numExpectedSetUnavailable_; + return !numExpectedAvailable_ && !numExpectedNotSet_ && !numExpectedSetUnavailable_; } // Check if the transaction has `delivered_amount` in the metaData as @@ -127,8 +106,7 @@ public: { if (metaData.isMember(sfDeliveredAmount.jsonName)) { - if (metaData[jss::delivered_amount] != - metaData[sfDeliveredAmount.jsonName]) + if (metaData[jss::delivered_amount] != metaData[sfDeliveredAmount.jsonName]) return false; } else @@ -239,11 +217,8 @@ class DeliveredAmount_test : public beast::unit_test::suite auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 3); @@ -253,17 +228,14 @@ class DeliveredAmount_test : public beast::unit_test::suite // Check stream update while (true) { - auto const r = wsc->findMsg(1s, [&](auto const& jv) { - return jv[jss::ledger_index] == 4; - }); + auto const r = wsc->findMsg(1s, [&](auto const& jv) { return jv[jss::ledger_index] == 4; }); if (!r) break; if (!r->isMember(jss::transaction)) continue; - BEAST_EXPECT(checkDeliveredAmount.checkTxn( - (*r)[jss::transaction], (*r)[jss::meta])); + BEAST_EXPECT(checkDeliveredAmount.checkTxn((*r)[jss::transaction], (*r)[jss::meta])); } } BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters()); @@ -318,14 +290,10 @@ class DeliveredAmount_test : public beast::unit_test::suite jvParams[jss::ledger_index] = 4u; jvParams[jss::transactions] = true; jvParams[jss::expand] = true; - auto const jtxn = env.rpc( - "json", - "ledger", - to_string( - jvParams))[jss::result][jss::ledger][jss::transactions]; + auto const jtxn = + env.rpc("json", "ledger", to_string(jvParams))[jss::result][jss::ledger][jss::transactions]; for (auto const& t : jtxn) - BEAST_EXPECT( - checkDeliveredAmount.checkTxn(t, t[jss::metaData])); + BEAST_EXPECT(checkDeliveredAmount.checkTxn(t, t[jss::metaData])); BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters()); } } @@ -341,14 +309,9 @@ class DeliveredAmount_test : public beast::unit_test::suite Account const bob("bob"); Env env{*this, features}; - MPTTester mptAlice( - env, alice, {.holders = {bob, carol}, .close = false}); + MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .close = false}); - mptAlice.create( - {.transferFee = 25000, - .ownerCount = 1, - .holderCount = 0, - .flags = tfMPTCanTransfer}); + mptAlice.create({.transferFee = 25000, .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); auto const MPT = mptAlice["MPT"]; mptAlice.authorize({.account = bob}); @@ -362,29 +325,21 @@ class DeliveredAmount_test : public beast::unit_test::suite env.close(); // Get the hash for the most recent transaction. - std::string txHash{ - env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + std::string txHash{env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; Json::Value meta = env.rpc("tx", txHash)[jss::result][jss::meta]; if (features[fixMPTDeliveredAmount]) { - BEAST_EXPECT( - meta[sfDeliveredAmount.jsonName] == - STAmount{MPT(800)}.getJson(JsonOptions::none)); - BEAST_EXPECT( - meta[jss::delivered_amount] == - STAmount{MPT(800)}.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[sfDeliveredAmount.jsonName] == STAmount{MPT(800)}.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[jss::delivered_amount] == STAmount{MPT(800)}.getJson(JsonOptions::none)); } else { BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName)); - BEAST_EXPECT( - meta[jss::delivered_amount] = Json::Value("unavailable")); + BEAST_EXPECT(meta[jss::delivered_amount] = Json::Value("unavailable")); } - env(pay(bob, carol, MPT(1000)), - sendmax(MPT(1200)), - txflags(tfPartialPayment)); + env(pay(bob, carol, MPT(1000)), sendmax(MPT(1200)), txflags(tfPartialPayment)); env.close(); txHash = env.tx()->getJson(JsonOptions::none)[jss::hash].asString(); @@ -392,18 +347,13 @@ class DeliveredAmount_test : public beast::unit_test::suite if (features[fixMPTDeliveredAmount]) { - BEAST_EXPECT( - meta[sfDeliveredAmount.jsonName] == - STAmount{MPT(960)}.getJson(JsonOptions::none)); - BEAST_EXPECT( - meta[jss::delivered_amount] == - STAmount{MPT(960)}.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[sfDeliveredAmount.jsonName] == STAmount{MPT(960)}.getJson(JsonOptions::none)); + BEAST_EXPECT(meta[jss::delivered_amount] == STAmount{MPT(960)}.getJson(JsonOptions::none)); } else { BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName)); - BEAST_EXPECT( - meta[jss::delivered_amount] = Json::Value("unavailable")); + BEAST_EXPECT(meta[jss::delivered_amount] = Json::Value("unavailable")); } } @@ -422,7 +372,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(DeliveredAmount, rpc, ripple); +BEAST_DEFINE_TESTSUITE(DeliveredAmount, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 326766221a..e8abfd58b8 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace test { class DepositAuthorized_test : public beast::unit_test::suite @@ -77,47 +58,27 @@ public: // becky is authorized to deposit to herself. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(becky, becky, "validated").toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(becky, becky, "validated").toStyledString()), true); // alice should currently be authorized to deposit to becky. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky, "validated").toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(alice, becky, "validated").toStyledString()), true); // becky sets the DepositAuth flag in the current ledger. env(fset(becky, asfDepositAuth)); // alice is no longer authorized to deposit to becky in current ledger. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky).toStyledString()), - false); + env.rpc("json", "deposit_authorized", depositAuthArgs(alice, becky).toStyledString()), false); env.close(); // becky is still authorized to deposit to herself. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(becky, becky, "validated").toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(becky, becky, "validated").toStyledString()), true); // It's not a reciprocal arrangement. becky can deposit to alice. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(becky, alice, "current").toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(becky, alice, "current").toStyledString()), true); // becky creates a deposit authorization for alice. env(deposit::auth(becky, alice)); @@ -125,38 +86,22 @@ public: // alice is now authorized to deposit to becky. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky, "closed").toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(alice, becky, "closed").toStyledString()), true); // carol is still not authorized to deposit to becky. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(carol, becky).toStyledString()), - false); + env.rpc("json", "deposit_authorized", depositAuthArgs(carol, becky).toStyledString()), false); // becky clears the DepositAuth flag so carol becomes authorized. env(fclear(becky, asfDepositAuth)); env.close(); validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(carol, becky).toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(carol, becky).toStyledString()), true); // alice is still authorized to deposit to becky. validateDepositAuthResult( - env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky).toStyledString()), - true); + env.rpc("json", "deposit_authorized", depositAuthArgs(alice, becky).toStyledString()), true); } // Test malformed cases. @@ -169,10 +114,7 @@ public: Account const becky{"becky"}; // Lambda that checks the (error) result of deposit_authorized. - auto verifyErr = [this]( - Json::Value const& result, - char const* error, - char const* errorMsg) { + auto verifyErr = [this](Json::Value const& result, char const* error, char const* errorMsg) { BEAST_EXPECT(result[jss::result][jss::status] == jss::error); BEAST_EXPECT(result[jss::result][jss::error] == error); BEAST_EXPECT(result[jss::result][jss::error_message] == errorMsg); @@ -183,88 +125,67 @@ public: // Missing source_account field. Json::Value args{depositAuthArgs(alice, becky)}; args.removeMember(jss::source_account); - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr( - result, "invalidParams", "Missing field 'source_account'."); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "invalidParams", "Missing field 'source_account'."); } { // Non-string source_account field. Json::Value args{depositAuthArgs(alice, becky)}; args[jss::source_account] = 7.3; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr( - result, - "invalidParams", - "Invalid field 'source_account', not a string."); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "invalidParams", "Invalid field 'source_account', not a string."); } { // Corrupt source_account field. Json::Value args{depositAuthArgs(alice, becky)}; args[jss::source_account] = "rG1QQv2nh2gr7RCZ!P8YYcBUKCCN633jCn"; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; verifyErr(result, "actMalformed", "Account malformed."); } { // Missing destination_account field. Json::Value args{depositAuthArgs(alice, becky)}; args.removeMember(jss::destination_account); - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr( - result, - "invalidParams", - "Missing field 'destination_account'."); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "invalidParams", "Missing field 'destination_account'."); } { // Non-string destination_account field. Json::Value args{depositAuthArgs(alice, becky)}; args[jss::destination_account] = 7.3; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr( - result, - "invalidParams", - "Invalid field 'destination_account', not a string."); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "invalidParams", "Invalid field 'destination_account', not a string."); } { // Corrupt destination_account field. Json::Value args{depositAuthArgs(alice, becky)}; - args[jss::destination_account] = - "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas"; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + args[jss::destination_account] = "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas"; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; verifyErr(result, "actMalformed", "Account malformed."); } { // Request an invalid ledger. Json::Value args{depositAuthArgs(alice, becky, "-1")}; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr(result, "invalidParams", "ledgerIndexMalformed"); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "invalidParams", "Invalid field 'ledger_index', not string or number."); } { // Request a ledger that doesn't exist yet as a string. Json::Value args{depositAuthArgs(alice, becky, "17")}; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; verifyErr(result, "lgrNotFound", "ledgerNotFound"); } { // Request a ledger that doesn't exist yet. Json::Value args{depositAuthArgs(alice, becky)}; args[jss::ledger_index] = 17; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; verifyErr(result, "lgrNotFound", "ledgerNotFound"); } { // alice is not yet funded. Json::Value args{depositAuthArgs(alice, becky)}; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; verifyErr(result, "srcActNotFound", "Source account not found."); } env.fund(XRP(1000), alice); @@ -272,18 +193,15 @@ public: { // becky is not yet funded. Json::Value args{depositAuthArgs(alice, becky)}; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; - verifyErr( - result, "dstActNotFound", "Destination account not found."); + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; + verifyErr(result, "dstActNotFound", "Destination account not found."); } env.fund(XRP(1000), becky); env.close(); { // Once becky is funded try it again and see it succeed. Json::Value args{depositAuthArgs(alice, becky)}; - Json::Value const result{ - env.rpc("json", "deposit_authorized", args.toStyledString())}; + Json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())}; validateDepositAuthResult(result, true); } } @@ -297,14 +215,11 @@ public: std::vector credentialIDs = {}, std::string_view error = "") { - BEAST_EXPECT( - result[jss::status] == authorized ? jss::success : jss::error); + BEAST_EXPECT(result[jss::status] == authorized ? jss::success : jss::error); if (result.isMember(jss::deposit_authorized)) BEAST_EXPECT(result[jss::deposit_authorized] == authorized); if (authorized) - BEAST_EXPECT( - result.isMember(jss::deposit_authorized) && - (result[jss::deposit_authorized] == true)); + BEAST_EXPECT(result.isMember(jss::deposit_authorized) && (result[jss::deposit_authorized] == true)); BEAST_EXPECT(result.isMember(jss::error) == !error.empty()); if (!error.empty()) @@ -366,16 +281,13 @@ public: env.close(); { - testcase( - "deposit_authorized with credentials failure: empty array."); + testcase("deposit_authorized with credentials failure: empty array."); auto args = depositAuthArgs(alice, becky, "validated"); args[jss::credentials] = Json::arrayValue; - auto const jv = - env.rpc("json", "deposit_authorized", args.toStyledString()); - checkCredentialsResponse( - jv[jss::result], alice, becky, false, {}, "invalidParams"); + auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {}, "invalidParams"); } { @@ -388,10 +300,8 @@ public: args[jss::credentials].append(1); args[jss::credentials].append(3); - auto const jv = - env.rpc("json", "deposit_authorized", args.toStyledString()); - checkCredentialsResponse( - jv[jss::result], alice, becky, false, {}, "invalidParams"); + auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {}, "invalidParams"); } { @@ -403,15 +313,8 @@ public: args[jss::credentials] = Json::arrayValue; args[jss::credentials].append("hello world"); - auto const jv = - env.rpc("json", "deposit_authorized", args.toStyledString()); - checkCredentialsResponse( - jv[jss::result], - alice, - becky, - false, - {"hello world"}, - "invalidParams"); + auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {"hello world"}, "invalidParams"); } { @@ -426,8 +329,7 @@ public: {"0127AB8B4B29CCDBB61AA51C0799A8A6BB80B86A9899807C11ED576AF8516" "473"}); - auto const jv = - env.rpc("json", "deposit_authorized", args.toStyledString()); + auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString()); checkCredentialsResponse( jv[jss::result], alice, @@ -443,17 +345,8 @@ public: "deposit_authorized with credentials not authorized: " "credential not accepted"); auto const jv = env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky, "validated", {credIdx}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], - alice, - becky, - false, - {credIdx}, - "badCredentials"); + "json", "deposit_authorized", depositAuthArgs(alice, becky, "validated", {credIdx}).toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {credIdx}, "badCredentials"); } // alice accept credentials @@ -465,15 +358,8 @@ public: auto const jv = env.rpc( "json", "deposit_authorized", - depositAuthArgs(alice, becky, "validated", {credIdx, credIdx}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], - alice, - becky, - false, - {credIdx, credIdx}, - "badCredentials"); + depositAuthArgs(alice, becky, "validated", {credIdx, credIdx}).toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {credIdx, credIdx}, "badCredentials"); } { @@ -500,23 +386,15 @@ public: testcase("deposit_authorized too long credentials"); auto const jv = env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky, "validated", credIds) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], alice, becky, false, credIds, "invalidParams"); + "json", "deposit_authorized", depositAuthArgs(alice, becky, "validated", credIds).toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, false, credIds, "invalidParams"); } { testcase("deposit_authorized with credentials"); auto const jv = env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(alice, becky, "validated", {credIdx}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], alice, becky, true, {credIdx}); + "json", "deposit_authorized", depositAuthArgs(alice, becky, "validated", {credIdx}).toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, true, {credIdx}); } { @@ -528,17 +406,12 @@ public: // retrieve the index of the credentials auto jv = credentials::ledgerEntry(env, becky, diana, credType); - std::string const credBecky = - jv[jss::result][jss::index].asString(); + std::string const credBecky = jv[jss::result][jss::index].asString(); testcase("deposit_authorized account without preauth"); jv = env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(becky, alice, "validated", {credBecky}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], becky, alice, true, {credBecky}); + "json", "deposit_authorized", depositAuthArgs(becky, alice, "validated", {credBecky}).toStyledString()); + checkCredentialsResponse(jv[jss::result], becky, alice, true, {credBecky}); } { @@ -549,34 +422,20 @@ public: env.close(); // retrieve the index of the credentials auto jv = credentials::ledgerEntry(env, alice, carol, credType); - std::string const credDiana = - jv[jss::result][jss::index].asString(); + std::string const credDiana = jv[jss::result][jss::index].asString(); // alice try to use credential for different account jv = env.rpc( - "json", - "deposit_authorized", - depositAuthArgs(becky, alice, "validated", {credDiana}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], - becky, - alice, - false, - {credDiana}, - "badCredentials"); + "json", "deposit_authorized", depositAuthArgs(becky, alice, "validated", {credDiana}).toStyledString()); + checkCredentialsResponse(jv[jss::result], becky, alice, false, {credDiana}, "badCredentials"); } { testcase("deposit_authorized with expired credentials"); // check expired credentials - char const credType2[] = "fghijk"; - std::uint32_t const x = env.current() - ->info() - .parentCloseTime.time_since_epoch() - .count() + - 40; + char const credType2[] = "random"; + std::uint32_t const x = env.current()->header().parentCloseTime.time_since_epoch().count() + 40; // create credentials with expire time 40s auto jv = credentials::create(alice, carol, credType2); @@ -601,10 +460,8 @@ public: jv = env.rpc( "json", "deposit_authorized", - depositAuthArgs(alice, becky, "validated", {credIdx2}) - .toStyledString()); - checkCredentialsResponse( - jv[jss::result], alice, becky, true, {credIdx2}); + depositAuthArgs(alice, becky, "validated", {credIdx2}).toStyledString()); + checkCredentialsResponse(jv[jss::result], alice, becky, true, {credIdx2}); } // increase timer by 20s @@ -615,16 +472,9 @@ public: jv = env.rpc( "json", "deposit_authorized", - depositAuthArgs(alice, becky, "validated", {credIdx2}) - .toStyledString()); + depositAuthArgs(alice, becky, "validated", {credIdx2}).toStyledString()); - checkCredentialsResponse( - jv[jss::result], - alice, - becky, - false, - {credIdx2}, - "badCredentials"); + checkCredentialsResponse(jv[jss::result], alice, becky, false, {credIdx2}, "badCredentials"); } } } @@ -638,7 +488,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(DepositAuthorized, rpc, ripple); +BEAST_DEFINE_TESTSUITE(DepositAuthorized, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index 8e405a9a3c..21596634e3 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class Feature_test : public beast::unit_test::suite { @@ -33,13 +14,12 @@ class Feature_test : public beast::unit_test::suite { testcase("internals"); - auto const& supportedAmendments = ripple::detail::supportedAmendments(); - auto const& allAmendments = ripple::allAmendments(); + auto const& supportedAmendments = xrpl::detail::supportedAmendments(); + auto const& allAmendments = xrpl::allAmendments(); BEAST_EXPECT( supportedAmendments.size() == - ripple::detail::numDownVotedAmendments() + - ripple::detail::numUpVotedAmendments()); + xrpl::detail::numDownVotedAmendments() + xrpl::detail::numUpVotedAmendments()); { std::size_t up = 0, down = 0, obsolete = 0; for (auto const& [name, vote] : supportedAmendments) @@ -61,20 +41,15 @@ class Feature_test : public beast::unit_test::suite if (vote == VoteBehavior::Obsolete) { - BEAST_EXPECT( - allAmendments.contains(name) && - allAmendments.at(name) == AmendmentSupport::Retired); + BEAST_EXPECT(allAmendments.contains(name) && allAmendments.at(name) == AmendmentSupport::Retired); } else { - BEAST_EXPECT( - allAmendments.contains(name) && - allAmendments.at(name) == AmendmentSupport::Supported); + BEAST_EXPECT(allAmendments.contains(name) && allAmendments.at(name) == AmendmentSupport::Supported); } } - BEAST_EXPECT( - down + obsolete == ripple::detail::numDownVotedAmendments()); - BEAST_EXPECT(up == ripple::detail::numUpVotedAmendments()); + BEAST_EXPECT(down + obsolete == xrpl::detail::numDownVotedAmendments()); + BEAST_EXPECT(up == xrpl::detail::numUpVotedAmendments()); } { std::size_t supported = 0, unsupported = 0, retired = 0; @@ -98,9 +73,7 @@ class Feature_test : public beast::unit_test::suite } BEAST_EXPECT(supported + retired == supportedAmendments.size()); - BEAST_EXPECT( - allAmendments.size() - unsupported == - supportedAmendments.size()); + BEAST_EXPECT(allAmendments.size() - unsupported == supportedAmendments.size()); } } @@ -112,7 +85,7 @@ class Feature_test : public beast::unit_test::suite // Test all the supported features. In a perfect world, this would test // FeatureCollections::featureNames, but that's private. Leave it that // way. - auto const supported = ripple::detail::supportedAmendments(); + auto const supported = xrpl::detail::supportedAmendments(); for (auto const& [feature, vote] : supported) { @@ -121,30 +94,24 @@ class Feature_test : public beast::unit_test::suite if (BEAST_EXPECT(registered)) { BEAST_EXPECT(featureToName(*registered) == feature); - BEAST_EXPECT( - bitsetIndexToFeature(featureToBitsetIndex(*registered)) == - *registered); + BEAST_EXPECT(bitsetIndexToFeature(featureToBitsetIndex(*registered)) == *registered); } } // Test an arbitrary unknown feature uint256 zero{0}; BEAST_EXPECT(featureToName(zero) == to_string(zero)); - BEAST_EXPECT( - featureToName(zero) == - "0000000000000000000000000000000000000000000000000000000000000000"); + BEAST_EXPECT(featureToName(zero) == "0000000000000000000000000000000000000000000000000000000000000000"); // Test looking up an unknown feature BEAST_EXPECT(!getRegisteredFeature("unknown")); // Test a random sampling of the variables. If any of these get retired // or removed, swap out for any other feature. - BEAST_EXPECT( - featureToName(fixTrustLinesToSelf) == "fixTrustLinesToSelf"); - BEAST_EXPECT(featureToName(featureFlow) == "Flow"); - BEAST_EXPECT(featureToName(featureNegativeUNL) == "NegativeUNL"); - BEAST_EXPECT( - featureToName(fixIncludeKeyletFields) == "fixIncludeKeyletFields"); + BEAST_EXPECT(featureToName(fixRemoveNFTokenAutoTrustLine) == "fixRemoveNFTokenAutoTrustLine"); + BEAST_EXPECT(featureToName(featureBatch) == "Batch"); + BEAST_EXPECT(featureToName(featureDID) == "DID"); + BEAST_EXPECT(featureToName(fixIncludeKeyletFields) == "fixIncludeKeyletFields"); BEAST_EXPECT(featureToName(featureTokenEscrow) == "TokenEscrow"); } @@ -156,8 +123,7 @@ class Feature_test : public beast::unit_test::suite using namespace test::jtx; Env env{*this}; - std::map const& votes = - ripple::detail::supportedAmendments(); + std::map const& votes = xrpl::detail::supportedAmendments(); auto jrr = env.rpc("feature")[jss::result]; if (!BEAST_EXPECT(jrr.isMember(jss::features))) @@ -168,27 +134,18 @@ class Feature_test : public beast::unit_test::suite return; // default config - so all should be disabled, and // supported. Some may be vetoed. - bool expectVeto = - (votes.at(feature[jss::name].asString()) == - VoteBehavior::DefaultNo); - bool expectObsolete = - (votes.at(feature[jss::name].asString()) == - VoteBehavior::Obsolete); + bool expectVeto = (votes.at(feature[jss::name].asString()) == VoteBehavior::DefaultNo); + bool expectObsolete = (votes.at(feature[jss::name].asString()) == VoteBehavior::Obsolete); BEAST_EXPECTS( - feature.isMember(jss::enabled) && - !feature[jss::enabled].asBool(), + feature.isMember(jss::enabled) && !feature[jss::enabled].asBool(), feature[jss::name].asString() + " enabled"); BEAST_EXPECTS( - feature.isMember(jss::vetoed) && - feature[jss::vetoed].isBool() == !expectObsolete && - (!feature[jss::vetoed].isBool() || - feature[jss::vetoed].asBool() == expectVeto) && - (feature[jss::vetoed].isBool() || - feature[jss::vetoed].asString() == "Obsolete"), + feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool() == !expectObsolete && + (!feature[jss::vetoed].isBool() || feature[jss::vetoed].asBool() == expectVeto) && + (feature[jss::vetoed].isBool() || feature[jss::vetoed].asString() == "Obsolete"), feature[jss::name].asString() + " vetoed"); BEAST_EXPECTS( - feature.isMember(jss::supported) && - feature[jss::supported].asBool(), + feature.isMember(jss::supported) && feature[jss::supported].asBool(), feature[jss::name].asString() + " supported"); } } @@ -201,24 +158,22 @@ class Feature_test : public beast::unit_test::suite using namespace test::jtx; Env env{*this}; - auto jrr = env.rpc("feature", "MultiSignReserve")[jss::result]; + auto jrr = env.rpc("feature", "fixAMMOverflowOffer")[jss::result]; BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"); jrr.removeMember(jss::status); BEAST_EXPECT(jrr.size() == 1); BEAST_EXPECT( - jrr.isMember("586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF" - "1FC07EFE41D")); + jrr.isMember("12523DF04B553A0B1AD74F42DDB741DE8DC06A03FC089A0EF197E" + "2A87F1D8107")); auto feature = *(jrr.begin()); - BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name"); + BEAST_EXPECTS(feature[jss::name] == "fixAMMOverflowOffer", "name"); BEAST_EXPECTS(!feature[jss::enabled].asBool(), "enabled"); - BEAST_EXPECTS( - feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), "vetoed"); BEAST_EXPECTS(feature[jss::supported].asBool(), "supported"); // feature names are case-sensitive - expect error here - jrr = env.rpc("feature", "multiSignReserve")[jss::result]; + jrr = env.rpc("feature", "fMM")[jss::result]; BEAST_EXPECT(jrr[jss::error] == "badFeature"); BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid."); } @@ -234,8 +189,7 @@ class Feature_test : public beast::unit_test::suite auto testInvalidParam = [&](auto const& param) { Json::Value params; params[jss::feature] = param; - auto jrr = - env.rpc("json", "feature", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "feature", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters."); }; @@ -250,8 +204,7 @@ class Feature_test : public beast::unit_test::suite { auto jrr = env.rpc("feature", "AllTheThings")[jss::result]; BEAST_EXPECT(jrr[jss::error] == "badFeature"); - BEAST_EXPECT( - jrr[jss::error_message] == "Feature unknown or invalid."); + BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid."); } } @@ -274,25 +227,19 @@ class Feature_test : public beast::unit_test::suite // comparison to avoid maintenance as more amendments are added in // the future. BEAST_EXPECT(result[jss::features].size() >= 50); - for (auto it = result[jss::features].begin(); - it != result[jss::features].end(); - ++it) + for (auto it = result[jss::features].begin(); it != result[jss::features].end(); ++it) { uint256 id; (void)id.parseHex(it.key().asString().c_str()); if (!BEAST_EXPECT((*it).isMember(jss::name))) return; - bool expectEnabled = - env.app().getAmendmentTable().isEnabled(id); - bool expectSupported = - env.app().getAmendmentTable().isSupported(id); + bool expectEnabled = env.app().getAmendmentTable().isEnabled(id); + bool expectSupported = env.app().getAmendmentTable().isSupported(id); BEAST_EXPECTS( - (*it).isMember(jss::enabled) && - (*it)[jss::enabled].asBool() == expectEnabled, + (*it).isMember(jss::enabled) && (*it)[jss::enabled].asBool() == expectEnabled, (*it)[jss::name].asString() + " enabled"); BEAST_EXPECTS( - (*it).isMember(jss::supported) && - (*it)[jss::supported].asBool() == expectSupported, + (*it).isMember(jss::supported) && (*it)[jss::supported].asBool() == expectSupported, (*it)[jss::name].asString() + " supported"); BEAST_EXPECT(!(*it).isMember(jss::vetoed)); BEAST_EXPECT(!(*it).isMember(jss::majority)); @@ -308,12 +255,9 @@ class Feature_test : public beast::unit_test::suite params[jss::feature] = "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD" "EF"; - auto const result = - env.rpc("json", "feature", to_string(params))[jss::result]; - BEAST_EXPECTS( - result[jss::error] == "badFeature", result.toStyledString()); - BEAST_EXPECT( - result[jss::error_message] == "Feature unknown or invalid."); + auto const result = env.rpc("json", "feature", to_string(params))[jss::result]; + BEAST_EXPECTS(result[jss::error] == "badFeature", result.toStyledString()); + BEAST_EXPECT(result[jss::error_message] == "Feature unknown or invalid."); } { @@ -323,14 +267,9 @@ class Feature_test : public beast::unit_test::suite "A7"; // invalid param params[jss::vetoed] = true; - auto const result = - env.rpc("json", "feature", to_string(params))[jss::result]; - BEAST_EXPECTS( - result[jss::error] == "noPermission", - result[jss::error].asString()); - BEAST_EXPECT( - result[jss::error_message] == - "You don't have permission for this command."); + auto const result = env.rpc("json", "feature", to_string(params))[jss::result]; + BEAST_EXPECTS(result[jss::error] == "noPermission", result[jss::error].asString()); + BEAST_EXPECT(result[jss::error_message] == "You don't have permission for this command."); } } @@ -340,52 +279,36 @@ class Feature_test : public beast::unit_test::suite testcase("No Params, Some Enabled"); using namespace test::jtx; - Env env{ - *this, FeatureBitset(featureDepositAuth, featureDepositPreauth)}; + Env env{*this, FeatureBitset{}}; - std::map const& votes = - ripple::detail::supportedAmendments(); + std::map const& votes = xrpl::detail::supportedAmendments(); auto jrr = env.rpc("feature")[jss::result]; if (!BEAST_EXPECT(jrr.isMember(jss::features))) return; - for (auto it = jrr[jss::features].begin(); - it != jrr[jss::features].end(); - ++it) + for (auto it = jrr[jss::features].begin(); it != jrr[jss::features].end(); ++it) { uint256 id; (void)id.parseHex(it.key().asString().c_str()); if (!BEAST_EXPECT((*it).isMember(jss::name))) return; bool expectEnabled = env.app().getAmendmentTable().isEnabled(id); - bool expectSupported = - env.app().getAmendmentTable().isSupported(id); - bool expectVeto = - (votes.at((*it)[jss::name].asString()) == - VoteBehavior::DefaultNo); - bool expectObsolete = - (votes.at((*it)[jss::name].asString()) == - VoteBehavior::Obsolete); + bool expectSupported = env.app().getAmendmentTable().isSupported(id); + bool expectVeto = (votes.at((*it)[jss::name].asString()) == VoteBehavior::DefaultNo); + bool expectObsolete = (votes.at((*it)[jss::name].asString()) == VoteBehavior::Obsolete); BEAST_EXPECTS( - (*it).isMember(jss::enabled) && - (*it)[jss::enabled].asBool() == expectEnabled, + (*it).isMember(jss::enabled) && (*it)[jss::enabled].asBool() == expectEnabled, (*it)[jss::name].asString() + " enabled"); if (expectEnabled) - BEAST_EXPECTS( - !(*it).isMember(jss::vetoed), - (*it)[jss::name].asString() + " vetoed"); + BEAST_EXPECTS(!(*it).isMember(jss::vetoed), (*it)[jss::name].asString() + " vetoed"); else BEAST_EXPECTS( - (*it).isMember(jss::vetoed) && - (*it)[jss::vetoed].isBool() == !expectObsolete && - (!(*it)[jss::vetoed].isBool() || - (*it)[jss::vetoed].asBool() == expectVeto) && - ((*it)[jss::vetoed].isBool() || - (*it)[jss::vetoed].asString() == "Obsolete"), + (*it).isMember(jss::vetoed) && (*it)[jss::vetoed].isBool() == !expectObsolete && + (!(*it)[jss::vetoed].isBool() || (*it)[jss::vetoed].asBool() == expectVeto) && + ((*it)[jss::vetoed].isBool() || (*it)[jss::vetoed].asString() == "Obsolete"), (*it)[jss::name].asString() + " vetoed"); BEAST_EXPECTS( - (*it).isMember(jss::supported) && - (*it)[jss::supported].asBool() == expectSupported, + (*it).isMember(jss::supported) && (*it)[jss::supported].asBool() == expectSupported, (*it)[jss::name].asString() + " supported"); } } @@ -408,21 +331,11 @@ class Feature_test : public beast::unit_test::suite { if (!BEAST_EXPECT(feature.isMember(jss::name))) return; - BEAST_EXPECTS( - !feature.isMember(jss::majority), - feature[jss::name].asString() + " majority"); - BEAST_EXPECTS( - !feature.isMember(jss::count), - feature[jss::name].asString() + " count"); - BEAST_EXPECTS( - !feature.isMember(jss::threshold), - feature[jss::name].asString() + " threshold"); - BEAST_EXPECTS( - !feature.isMember(jss::validations), - feature[jss::name].asString() + " validations"); - BEAST_EXPECTS( - !feature.isMember(jss::vote), - feature[jss::name].asString() + " vote"); + BEAST_EXPECTS(!feature.isMember(jss::majority), feature[jss::name].asString() + " majority"); + BEAST_EXPECTS(!feature.isMember(jss::count), feature[jss::name].asString() + " count"); + BEAST_EXPECTS(!feature.isMember(jss::threshold), feature[jss::name].asString() + " threshold"); + BEAST_EXPECTS(!feature.isMember(jss::validations), feature[jss::name].asString() + " validations"); + BEAST_EXPECTS(!feature.isMember(jss::vote), feature[jss::name].asString() + " vote"); } auto majorities = getMajorityAmendments(*env.closed()); @@ -438,11 +351,10 @@ class Feature_test : public beast::unit_test::suite break; } - // There should be at least 5 amendments. Don't do exact comparison + // There should be at least 2 amendments. Don't do exact comparison // to avoid maintenance as more amendments are added in the future. - BEAST_EXPECT(majorities.size() >= 5); - std::map const& votes = - ripple::detail::supportedAmendments(); + BEAST_EXPECT(majorities.size() >= 2); + std::map const& votes = xrpl::detail::supportedAmendments(); jrr = env.rpc("feature")[jss::result]; if (!BEAST_EXPECT(jrr.isMember(jss::features))) @@ -451,36 +363,20 @@ class Feature_test : public beast::unit_test::suite { if (!BEAST_EXPECT(feature.isMember(jss::name))) return; - bool expectVeto = - (votes.at(feature[jss::name].asString()) == - VoteBehavior::DefaultNo); - bool expectObsolete = - (votes.at(feature[jss::name].asString()) == - VoteBehavior::Obsolete); + bool expectVeto = (votes.at(feature[jss::name].asString()) == VoteBehavior::DefaultNo); + bool expectObsolete = (votes.at(feature[jss::name].asString()) == VoteBehavior::Obsolete); BEAST_EXPECTS( - (expectVeto || expectObsolete) ^ - feature.isMember(jss::majority), + (expectVeto || expectObsolete) ^ feature.isMember(jss::majority), feature[jss::name].asString() + " majority"); BEAST_EXPECTS( - feature.isMember(jss::vetoed) && - feature[jss::vetoed].isBool() == !expectObsolete && - (!feature[jss::vetoed].isBool() || - feature[jss::vetoed].asBool() == expectVeto) && - (feature[jss::vetoed].isBool() || - feature[jss::vetoed].asString() == "Obsolete"), + feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool() == !expectObsolete && + (!feature[jss::vetoed].isBool() || feature[jss::vetoed].asBool() == expectVeto) && + (feature[jss::vetoed].isBool() || feature[jss::vetoed].asString() == "Obsolete"), feature[jss::name].asString() + " vetoed"); - BEAST_EXPECTS( - feature.isMember(jss::count), - feature[jss::name].asString() + " count"); - BEAST_EXPECTS( - feature.isMember(jss::threshold), - feature[jss::name].asString() + " threshold"); - BEAST_EXPECTS( - feature.isMember(jss::validations), - feature[jss::name].asString() + " validations"); - BEAST_EXPECT( - feature[jss::count] == - ((expectVeto || expectObsolete) ? 0 : 1)); + BEAST_EXPECTS(feature.isMember(jss::count), feature[jss::name].asString() + " count"); + BEAST_EXPECTS(feature.isMember(jss::threshold), feature[jss::name].asString() + " threshold"); + BEAST_EXPECTS(feature.isMember(jss::validations), feature[jss::name].asString() + " validations"); + BEAST_EXPECT(feature[jss::count] == ((expectVeto || expectObsolete) ? 0 : 1)); BEAST_EXPECT(feature[jss::threshold] == 1); BEAST_EXPECT(feature[jss::validations] == 1); BEAST_EXPECTS( @@ -495,8 +391,8 @@ class Feature_test : public beast::unit_test::suite testcase("Veto"); using namespace test::jtx; - Env env{*this, FeatureBitset(featureMultiSignReserve)}; - constexpr char const* featureName = "MultiSignReserve"; + Env env{*this, FeatureBitset{featurePriceOracle}}; + constexpr char const* featureName = "fixAMMOverflowOffer"; auto jrr = env.rpc("feature", featureName)[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -506,9 +402,7 @@ class Feature_test : public beast::unit_test::suite return; auto feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), "vetoed"); jrr = env.rpc("feature", featureName, "reject")[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -518,9 +412,7 @@ class Feature_test : public beast::unit_test::suite return; feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(), - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(), "vetoed"); jrr = env.rpc("feature", featureName, "accept")[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -530,9 +422,7 @@ class Feature_test : public beast::unit_test::suite return; feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(), "vetoed"); // anything other than accept or reject is an error jrr = env.rpc("feature", featureName, "maybe"); @@ -547,7 +437,20 @@ class Feature_test : public beast::unit_test::suite using namespace test::jtx; Env env{*this}; - constexpr char const* featureName = "CryptoConditionsSuite"; + + auto const& supportedAmendments = detail::supportedAmendments(); + auto obsoleteFeature = + std::find_if(std::begin(supportedAmendments), std::end(supportedAmendments), [](auto const& pair) { + return pair.second == VoteBehavior::Obsolete; + }); + + if (obsoleteFeature == std::end(supportedAmendments)) + { + pass(); + return; + } + + auto const featureName = obsoleteFeature->first; auto jrr = env.rpc("feature", featureName)[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -557,10 +460,7 @@ class Feature_test : public beast::unit_test::suite return; auto feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isString() && - feature[jss::vetoed].asString() == "Obsolete", - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete", "vetoed"); jrr = env.rpc("feature", featureName, "reject")[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -570,10 +470,7 @@ class Feature_test : public beast::unit_test::suite return; feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isString() && - feature[jss::vetoed].asString() == "Obsolete", - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete", "vetoed"); jrr = env.rpc("feature", featureName, "accept")[jss::result]; if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status")) @@ -583,10 +480,7 @@ class Feature_test : public beast::unit_test::suite return; feature = *(jrr.begin()); BEAST_EXPECTS(feature[jss::name] == featureName, "name"); - BEAST_EXPECTS( - feature[jss::vetoed].isString() && - feature[jss::vetoed].asString() == "Obsolete", - "vetoed"); + BEAST_EXPECTS(feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete", "vetoed"); // anything other than accept or reject is an error jrr = env.rpc("feature", featureName, "maybe"); @@ -611,6 +505,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Feature, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Feature, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/GRPCTestClientBase.h b/src/test/rpc/GRPCTestClientBase.h index 06531ef552..3c39cd1747 100644 --- a/src/test/rpc/GRPCTestClientBase.h +++ b/src/test/rpc/GRPCTestClientBase.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLED_GRPCTESTCLIENTBASE_H -#define RIPPLED_GRPCTESTCLIENTBASE_H +#pragma once #include @@ -26,19 +6,15 @@ #include -namespace ripple { +namespace xrpl { namespace test { struct GRPCTestClientBase { explicit GRPCTestClientBase(std::string const& port) - : stub_(org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub( - grpc::CreateChannel( - beast::IP::Endpoint( - boost::asio::ip::make_address(getEnvLocalhostAddr()), - std::stoi(port)) - .to_string(), - grpc::InsecureChannelCredentials()))) + : stub_(org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub(grpc::CreateChannel( + beast::IP::Endpoint(boost::asio::ip::make_address(getEnvLocalhostAddr()), std::stoi(port)).to_string(), + grpc::InsecureChannelCredentials()))) { } @@ -48,5 +24,4 @@ struct GRPCTestClientBase }; } // namespace test -} // namespace ripple -#endif // RIPPLED_GRPCTESTCLIENTBASE_H +} // namespace xrpl diff --git a/src/test/rpc/GatewayBalances_test.cpp b/src/test/rpc/GatewayBalances_test.cpp index 30f0701e9e..6415f6a51f 100644 --- a/src/test/rpc/GatewayBalances_test.cpp +++ b/src/test/rpc/GatewayBalances_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -22,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class GatewayBalances_test : public beast::unit_test::suite @@ -94,8 +77,7 @@ public: if (wsc->version() == 2) { expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - expect( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + expect(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); expect(jv.isMember(jss::id) && jv[jss::id] == 5); } @@ -115,9 +97,7 @@ public: auto c2 = hwBalance[1u][jss::currency]; expect(c1 == "USD" || c2 == "USD"); expect(c1 == "JPY" || c2 == "JPY"); - expect( - hwBalance[0u][jss::value] == "5000" && - hwBalance[1u][jss::value] == "5000"); + expect(hwBalance[0u][jss::value] == "5000" && hwBalance[1u][jss::value] == "5000"); } { @@ -182,8 +162,7 @@ public: expect(jv[jss::status] == "error"); auto response = jv[jss::result]; - auto const error = - apiVersion < 2u ? "invalidHotWallet" : "invalidParams"; + auto const error = apiVersion < 2u ? "invalidHotWallet" : "invalidParams"; BEAST_EXPECT(response[jss::error] == error); }); } @@ -202,8 +181,7 @@ public: auto USD = alice["USD"]; // The largest valid STAmount of USD: - STAmount const maxUSD( - USD.issue(), STAmount::cMaxValue, STAmount::cMaxOffset); + STAmount const maxUSD(USD.issue(), STAmount::cMaxValue, STAmount::cMaxOffset); // Create a hotwallet Account const hw{"hw"}; @@ -260,7 +238,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(GatewayBalances, rpc, ripple); +BEAST_DEFINE_TESTSUITE(GatewayBalances, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/GetAggregatePrice_test.cpp b/src/test/rpc/GetAggregatePrice_test.cpp index 9d007f7f52..e6cfb3a229 100644 --- a/src/test/rpc/GetAggregatePrice_test.cpp +++ b/src/test/rpc/GetAggregatePrice_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace jtx { namespace oracle { @@ -45,17 +26,12 @@ public: Env env(*this); auto const baseFee = env.current()->fees().base; // missing base_asset - auto ret = - Oracle::aggregatePrice(env, std::nullopt, "USD", oracles); - BEAST_EXPECT( - ret[jss::error_message].asString() == - "Missing field 'base_asset'."); + auto ret = Oracle::aggregatePrice(env, std::nullopt, "USD", oracles); + BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'base_asset'."); // missing quote_asset ret = Oracle::aggregatePrice(env, "XRP", std::nullopt, oracles); - BEAST_EXPECT( - ret[jss::error_message].asString() == - "Missing field 'quote_asset'."); + BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'quote_asset'."); // invalid base_asset, quote_asset std::vector invalidAsset = { @@ -85,9 +61,7 @@ public: // missing oracles array ret = Oracle::aggregatePrice(env, "XRP", "USD"); - BEAST_EXPECT( - ret[jss::error_message].asString() == - "Missing field 'oracles'."); + BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'oracles'."); // empty oracles array ret = Oracle::aggregatePrice(env, "XRP", "USD", OraclesData{}); @@ -102,8 +76,7 @@ public: ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, 2}}}); BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound"); // invalid values - std::vector invalidDocument = { - NoneTag, 1.2, -1, "", "none", "1.2"}; + std::vector invalidDocument = {NoneTag, 1.2, -1, "", "none", "1.2"}; for (auto const& v : invalidDocument) { ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, v}}}); @@ -112,51 +85,36 @@ public: BEAST_EXPECT(ret[jss::error].asString() == "invalidParams"); } // missing document id - ret = Oracle::aggregatePrice( - env, "XRP", "USD", {{{owner, std::nullopt}}}); + ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, std::nullopt}}}); BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed"); // invalid owner ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{some, 1}}}); BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound"); // missing account - ret = Oracle::aggregatePrice( - env, "XRP", "USD", {{{std::nullopt, 1}}}); + ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{std::nullopt, 1}}}); BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed"); // oracles have wrong asset pair env.fund(XRP(1'000), owner); Oracle oracle( - env, - {.owner = owner, - .series = {{"XRP", "EUR", 740, 1}}, - .fee = static_cast(baseFee.drops())}); - ret = Oracle::aggregatePrice( - env, "XRP", "USD", {{{owner, oracle.documentID()}}}); + env, {.owner = owner, .series = {{"XRP", "EUR", 740, 1}}, .fee = static_cast(baseFee.drops())}); + ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, oracle.documentID()}}}); BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound"); // invalid trim value - std::vector invalidTrim = { - NoneTag, 0, 26, -1, 1.2, "", "none", "1.2"}; + std::vector invalidTrim = {NoneTag, 0, 26, -1, 1.2, "", "none", "1.2"}; for (auto const& v : invalidTrim) { - ret = Oracle::aggregatePrice( - env, "XRP", "USD", {{{owner, oracle.documentID()}}}, v); + ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, oracle.documentID()}}}, v); BEAST_EXPECT(ret[jss::error].asString() == "invalidParams"); } // invalid time threshold value - std::vector invalidTime = { - NoneTag, -1, 1.2, "", "none", "1.2"}; + std::vector invalidTime = {NoneTag, -1, 1.2, "", "none", "1.2"}; for (auto const& v : invalidTime) { - ret = Oracle::aggregatePrice( - env, - "XRP", - "USD", - {{{owner, oracle.documentID()}}}, - std::nullopt, - v); + ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, oracle.documentID()}}}, std::nullopt, v); BEAST_EXPECT(ret[jss::error].asString() == "invalidParams"); } } @@ -164,16 +122,14 @@ public: // too many oracles { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); OraclesData oracles; for (int i = 0; i < 201; ++i) { Account const owner(std::to_string(i)); env.fund(XRP(1'000), owner); - Oracle oracle( - env, {.owner = owner, .documentID = i, .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .documentID = i, .fee = baseFee}); oracles.emplace_back(owner, oracle.documentID()); } auto const ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles); @@ -191,8 +147,7 @@ public: oracles.reserve(10); for (int i = 0; i < 10; ++i) { - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); Account const owner{std::to_string(i)}; env.fund(XRP(1'000), owner); @@ -200,8 +155,7 @@ public: env, {.owner = owner, .documentID = rand(), - .series = - {{"XRP", "USD", 740 + i, 1}, {"XRP", "EUR", 740, 1}}, + .series = {{"XRP", "USD", 740 + i, 1}, {"XRP", "EUR", 740, 1}}, .fee = baseFee}); oracles.emplace_back(owner, oracle.documentID()); } @@ -210,18 +164,32 @@ public: // Aggregate data set includes all price oracle instances, no trimming // or time threshold { - Env env(*this); - OraclesData oracles; - prep(env, oracles); - // entire and trimmed stats - auto ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles); - BEAST_EXPECT(ret[jss::entire_set][jss::mean] == "74.45"); - BEAST_EXPECT(ret[jss::entire_set][jss::size].asUInt() == 10); - BEAST_EXPECT( - ret[jss::entire_set][jss::standard_deviation] == - "0.3027650354097492"); - BEAST_EXPECT(ret[jss::median] == "74.45"); - BEAST_EXPECT(ret[jss::time] == 946694900); + auto const all = testable_amendments(); + for (auto const& feats : {all - featureSingleAssetVault - featureLendingProtocol, all}) + { + for (auto const mantissaSize : {MantissaRange::small, MantissaRange::large}) + { + // Regardless of the features enabled, RPC is controlled by + // the global mantissa size. And since it's a thread-local, + // overriding it locally won't make a difference either. + // This will mean all RPC will use the default of "large". + NumberMantissaScaleGuard mg(mantissaSize); + + Env env(*this, feats); + OraclesData oracles; + prep(env, oracles); + // entire and trimmed stats + auto ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles); + BEAST_EXPECT(ret[jss::entire_set][jss::mean] == "74.45"); + BEAST_EXPECT(ret[jss::entire_set][jss::size].asUInt() == 10); + // Short: 0.3027650354097492 + BEAST_EXPECTS( + ret[jss::entire_set][jss::standard_deviation] == "0.3027650354097491666", + ret[jss::entire_set][jss::standard_deviation].asString()); + BEAST_EXPECT(ret[jss::median] == "74.45"); + BEAST_EXPECT(ret[jss::time] == 946694900); + } + } } // Aggregate data set includes all price oracle instances @@ -230,19 +198,20 @@ public: OraclesData oracles; prep(env, oracles); // entire and trimmed stats - auto ret = - Oracle::aggregatePrice(env, "XRP", "USD", oracles, 20, 100); + auto ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles, 20, 100); BEAST_EXPECT(ret[jss::entire_set][jss::mean] == "74.45"); BEAST_EXPECT(ret[jss::entire_set][jss::size].asUInt() == 10); - BEAST_EXPECT( - ret[jss::entire_set][jss::standard_deviation] == - "0.3027650354097492"); + // Short: "0.3027650354097492", + BEAST_EXPECTS( + ret[jss::entire_set][jss::standard_deviation] == "0.3027650354097491666", + ret[jss::entire_set][jss::standard_deviation].asString()); BEAST_EXPECT(ret[jss::median] == "74.45"); BEAST_EXPECT(ret[jss::trimmed_set][jss::mean] == "74.45"); BEAST_EXPECT(ret[jss::trimmed_set][jss::size].asUInt() == 6); - BEAST_EXPECT( - ret[jss::trimmed_set][jss::standard_deviation] == - "0.187082869338697"); + // Short: "0.187082869338697", + BEAST_EXPECTS( + ret[jss::trimmed_set][jss::standard_deviation] == "0.1870828693386970693", + ret[jss::trimmed_set][jss::standard_deviation].asString()); BEAST_EXPECT(ret[jss::time] == 946694900); } @@ -250,86 +219,66 @@ public: // updated ledgers { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); OraclesData oracles; prep(env, oracles); for (int i = 0; i < 3; ++i) { Oracle oracle( - env, - {.owner = oracles[i].first, - .documentID = asUInt(*oracles[i].second), - .fee = baseFee}, - false); + env, {.owner = oracles[i].first, .documentID = asUInt(*oracles[i].second), .fee = baseFee}, false); // push XRP/USD by more than three ledgers, so this price // oracle is not included in the dataset - oracle.set(UpdateArg{ - .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); - oracle.set(UpdateArg{ - .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); - oracle.set(UpdateArg{ - .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); } for (int i = 3; i < 6; ++i) { Oracle oracle( - env, - {.owner = oracles[i].first, - .documentID = asUInt(*oracles[i].second), - .fee = baseFee}, - false); + env, {.owner = oracles[i].first, .documentID = asUInt(*oracles[i].second), .fee = baseFee}, false); // push XRP/USD by two ledgers, so this price // is included in the dataset - oracle.set(UpdateArg{ - .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); - oracle.set(UpdateArg{ - .series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "EUR", 740, 1}}, .fee = baseFee}); } // entire and trimmed stats - auto ret = - Oracle::aggregatePrice(env, "XRP", "USD", oracles, 20, "200"); + auto ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles, 20, "200"); BEAST_EXPECT(ret[jss::entire_set][jss::mean] == "74.6"); BEAST_EXPECT(ret[jss::entire_set][jss::size].asUInt() == 7); - BEAST_EXPECT( - ret[jss::entire_set][jss::standard_deviation] == - "0.2160246899469287"); + // Short: 0.2160246899469287 + BEAST_EXPECTS( + ret[jss::entire_set][jss::standard_deviation] == "0.2160246899469286744", + ret[jss::entire_set][jss::standard_deviation].asString()); BEAST_EXPECT(ret[jss::median] == "74.6"); BEAST_EXPECT(ret[jss::trimmed_set][jss::mean] == "74.6"); BEAST_EXPECT(ret[jss::trimmed_set][jss::size].asUInt() == 5); - BEAST_EXPECT( - ret[jss::trimmed_set][jss::standard_deviation] == - "0.158113883008419"); + // Short: 0.158113883008419 + BEAST_EXPECTS( + ret[jss::trimmed_set][jss::standard_deviation] == "0.1581138830084189666", + ret[jss::trimmed_set][jss::standard_deviation].asString()); BEAST_EXPECT(ret[jss::time] == 946694900); } // Reduced data set because of the time threshold { Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); OraclesData oracles; prep(env, oracles); for (int i = 0; i < oracles.size(); ++i) { Oracle oracle( - env, - {.owner = oracles[i].first, - .documentID = asUInt(*oracles[i].second), - .fee = baseFee}, - false); + env, {.owner = oracles[i].first, .documentID = asUInt(*oracles[i].second), .fee = baseFee}, false); // push XRP/USD by two ledgers, so this price // is included in the dataset - oracle.set(UpdateArg{ - .series = {{"XRP", "USD", 740, 1}}, .fee = baseFee}); + oracle.set(UpdateArg{.series = {{"XRP", "USD", 740, 1}}, .fee = baseFee}); } // entire stats only, limit lastUpdateTime to {200, 125} - auto ret = Oracle::aggregatePrice( - env, "XRP", "USD", oracles, std::nullopt, 75); + auto ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles, std::nullopt, 75); BEAST_EXPECT(ret[jss::entire_set][jss::mean] == "74"); BEAST_EXPECT(ret[jss::entire_set][jss::size].asUInt() == 8); BEAST_EXPECT(ret[jss::entire_set][jss::standard_deviation] == "0"); @@ -346,9 +295,9 @@ public: } }; -BEAST_DEFINE_TESTSUITE(GetAggregatePrice, rpc, ripple); +BEAST_DEFINE_TESTSUITE(GetAggregatePrice, rpc, xrpl); } // namespace oracle } // namespace jtx } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/GetCounts_test.cpp b/src/test/rpc/GetCounts_test.cpp index d0b3404781..07c29e3648 100644 --- a/src/test/rpc/GetCounts_test.cpp +++ b/src/test/rpc/GetCounts_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class GetCounts_test : public beast::unit_test::suite { @@ -45,12 +26,8 @@ class GetCounts_test : public beast::unit_test::suite BEAST_EXPECT(!result.isMember("Transaction")); BEAST_EXPECT(!result.isMember("STObject")); BEAST_EXPECT(!result.isMember("HashRouterEntry")); - BEAST_EXPECT( - result.isMember(jss::uptime) && - !result[jss::uptime].asString().empty()); - BEAST_EXPECT( - result.isMember(jss::dbKBTotal) && - result[jss::dbKBTotal].asInt() > 0); + BEAST_EXPECT(result.isMember(jss::uptime) && !result[jss::uptime].asString().empty()); + BEAST_EXPECT(result.isMember(jss::dbKBTotal) && result[jss::dbKBTotal].asInt() > 0); } // create some transactions @@ -70,8 +47,7 @@ class GetCounts_test : public beast::unit_test::suite result = env.rpc("get_counts")[jss::result]; BEAST_EXPECT(result[jss::status] == "success"); // compare with values reported by CountedObjects - auto const& objectCounts = - CountedObjects::getInstance().getCounts(10); + auto const& objectCounts = CountedObjects::getInstance().getCounts(10); for (auto const& it : objectCounts) { BEAST_EXPECTS(result.isMember(it.first), it.first); @@ -87,8 +63,7 @@ class GetCounts_test : public beast::unit_test::suite BEAST_EXPECT(result[jss::status] == "success"); // compare with values reported by CountedObjects - auto const& objectCounts = - CountedObjects::getInstance().getCounts(100); + auto const& objectCounts = CountedObjects::getInstance().getCounts(100); for (auto const& it : objectCounts) { BEAST_EXPECTS(result.isMember(it.first), it.first); @@ -106,9 +81,7 @@ class GetCounts_test : public beast::unit_test::suite env(pay(alice, bob, alice["USD"](5))); result = env.rpc("get_counts")[jss::result]; // deliberately don't call close so we have open Tx - BEAST_EXPECT( - result.isMember(jss::local_txs) && - result[jss::local_txs].asInt() > 0); + BEAST_EXPECT(result.isMember(jss::local_txs) && result[jss::local_txs].asInt() > 0); } } @@ -120,6 +93,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(GetCounts, rpc, ripple); +BEAST_DEFINE_TESTSUITE(GetCounts, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Handler_test.cpp b/src/test/rpc/Handler_test.cpp index c58d29252b..7aeb059f56 100644 --- a/src/test/rpc/Handler_test.cpp +++ b/src/test/rpc/Handler_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,8 +8,9 @@ #include #include #include +// cspell: words stdev -namespace ripple::test { +namespace xrpl::test { // NOTE: there should be no need for this function; // `std::cout << some_duration` should just work if built with a compliant @@ -87,8 +69,7 @@ class Handler_test : public beast::unit_test::suite double const mean_squared = (sum * sum) / (j * j); return std::make_tuple( clock::duration{static_cast(sum / j)}, - clock::duration{ - static_cast(std::sqrt((sum_squared / j) - mean_squared))}, + clock::duration{static_cast(std::sqrt((sum_squared / j) - mean_squared))}, j); } @@ -100,8 +81,7 @@ class Handler_test : public beast::unit_test::suite std::random_device dev; std::ranlux48 prng(dev()); - std::vector names = - test::jtx::make_vector(ripple::RPC::getHandlerNames()); + std::vector names = test::jtx::make_vector(xrpl::RPC::getHandlerNames()); std::uniform_int_distribution distr{0, names.size() - 1}; @@ -114,8 +94,7 @@ class Handler_test : public beast::unit_test::suite }, [&]() -> std::size_t { return distr(prng); }); - std::cout << "mean=" << mean << " stdev=" << stdev << " N=" << n - << '\n'; + std::cout << "mean=" << mean << " stdev=" << stdev << " N=" << n << '\n'; BEAST_EXPECT(dummy != 0); } @@ -128,6 +107,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE_MANUAL(Handler, rpc, ripple); +BEAST_DEFINE_TESTSUITE_MANUAL(Handler, rpc, xrpl); -} // namespace ripple::test +} // namespace xrpl::test diff --git a/src/test/rpc/JSONRPC_test.cpp b/src/test/rpc/JSONRPC_test.cpp index 31bdacfb9c..f0329748e1 100644 --- a/src/test/rpc/JSONRPC_test.cpp +++ b/src/test/rpc/JSONRPC_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace RPC { @@ -73,7 +54,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Minimal payment, no Amount only DeliverMax", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "secret": "masterpassphrase", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -82,15 +63,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'account'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'account'.", "Missing field 'tx_json.Sequence'."}}}, {"Pass in Fee with minimal payment, both Amount and DeliverMax.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -102,15 +80,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"Pass in Sequence, no Amount only DeliverMax", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -121,16 +96,13 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Fee'.", - "Missing field 'tx_json.SigningPubKey'."}}}, + {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}}, {"Pass in Sequence and Fee with minimal payment, both Amount and " "DeliverMax.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -152,7 +124,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Add 'fee_mult_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 7, @@ -164,15 +136,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Fee'.", - "Missing field 'tx_json.SigningPubKey'."}}}, + {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}}, {"Add 'fee_mult_max' and 'fee_div_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 7, @@ -185,15 +154,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Fee'.", - "Missing field 'tx_json.SigningPubKey'."}}}, + {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}}, {"fee_mult_max is ignored if 'Fee' is present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 0, @@ -215,7 +181,7 @@ static constexpr TxnTestData txnTestArray[] = { {"fee_div_max is ignored if 'Fee' is present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 100, @@ -238,7 +204,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid 'fee_mult_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": "NotAFeeMultiplier", @@ -258,7 +224,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid 'fee_div_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 5, @@ -279,7 +245,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid value for 'fee_mult_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 0, @@ -299,7 +265,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid value for 'fee_div_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 4, @@ -320,7 +286,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid zero value for 'fee_div_max' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "fee_mult_max": 4, @@ -341,7 +307,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Amount'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -358,7 +324,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid 'Amount'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -376,7 +342,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Destination'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -393,7 +359,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid 'Destination'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -411,7 +377,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Cannot create XRP to XRP paths.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "build_path": 1, @@ -430,7 +396,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Successful 'build_path'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "build_path": 1, @@ -445,15 +411,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"Not valid to include both 'Paths' and 'build_path'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "build_path": 1, @@ -477,7 +440,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Successful 'SendMax'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "build_path": 1, @@ -497,15 +460,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"'Amount' may not be XRP for pathfinding, but 'SendMax' may be XRP.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "build_path": 1, @@ -521,15 +481,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"'secret' must be present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -546,7 +503,7 @@ static constexpr TxnTestData txnTestArray[] = { {"'secret' must be non-empty.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "", "tx_json": { @@ -564,7 +521,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Use 'seed' instead of 'secret'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi", "key_type": "ed25519", "seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd", @@ -575,15 +532,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"Malformed 'seed'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi", "key_type": "ed25519", "seed": "not a seed", @@ -602,7 +556,7 @@ static constexpr TxnTestData txnTestArray[] = { {"'tx_json' must be present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "rx_json": { @@ -620,7 +574,7 @@ static constexpr TxnTestData txnTestArray[] = { {"'TransactionType' must be present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -637,7 +591,7 @@ static constexpr TxnTestData txnTestArray[] = { {"The 'TransactionType' must be a pre-established transaction type.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -655,7 +609,7 @@ static constexpr TxnTestData txnTestArray[] = { {"The 'TransactionType' may be represented with an integer.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -665,15 +619,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": 0 } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"'Account' must be present.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -690,7 +641,7 @@ static constexpr TxnTestData txnTestArray[] = { {"'Account' must be well formed.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -708,7 +659,7 @@ static constexpr TxnTestData txnTestArray[] = { {"The 'offline' tag may be added to the transaction.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 0, @@ -719,15 +670,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"If 'offline' is true then a 'Sequence' field must be supplied.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 1, @@ -747,7 +695,7 @@ static constexpr TxnTestData txnTestArray[] = { {"If 'offline' is true then a 'Fee' field must be supplied.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 1, @@ -767,7 +715,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Valid transaction if 'offline' is true.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 1, @@ -789,7 +737,7 @@ static constexpr TxnTestData txnTestArray[] = { {"'offline' and 'build_path' are mutually exclusive.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 1, @@ -811,7 +759,7 @@ static constexpr TxnTestData txnTestArray[] = { {"A 'Flags' field may be specified.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -822,15 +770,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"The 'Flags' field must be numeric.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -849,7 +794,7 @@ static constexpr TxnTestData txnTestArray[] = { {"It's okay to add a 'debug_signing' field.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "debug_signing": 0, @@ -860,15 +805,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"", - "", - "Missing field 'tx_json.Sequence'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}}, {"Single-sign a multisigned transaction.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux", "secret": "a", "tx_json": { @@ -890,15 +832,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType" : "Payment" } })", - {{"Already multisigned.", - "Already multisigned.", - "Secret does not match account.", - ""}}}, + {{"Already multisigned.", "Already multisigned.", "Secret does not match account.", ""}}}, {"Minimal sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -911,15 +850,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"Secret does not match account.", - "Secret does not match account.", - "", - "Missing field 'tx_json.Signers'."}}}, + {{"Secret does not match account.", "Secret does not match account.", "", "Missing field 'tx_json.Signers'."}}}, {"Minimal offline sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "offline": 1, @@ -938,7 +874,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Offline sign_for using 'seed' instead of 'secret'.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi", "key_type": "ed25519", "seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd", @@ -958,7 +894,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Malformed seed in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi", "key_type": "ed25519", "seed": "sh1yJfwoi98zCygwjUzuHmJDeVKd", @@ -973,15 +909,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"Disallowed seed.", - "Disallowed seed.", - "Disallowed seed.", - "Missing field 'tx_json.Signers'."}}}, + {{"Disallowed seed.", "Disallowed seed.", "Disallowed seed.", "Missing field 'tx_json.Signers'."}}}, {"Missing 'Account' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1001,7 +934,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Amount' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1021,7 +954,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Destination' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1041,7 +974,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Destination' in sign_for, use DeliverMax", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1061,7 +994,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Fee' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1081,7 +1014,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'Sequence' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1101,7 +1034,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'SigningPubKey' in sign_for is automatically filled in.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1121,7 +1054,7 @@ static constexpr TxnTestData txnTestArray[] = { {"In sign_for, an account may not sign for itself.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "secret": "a", "tx_json": { @@ -1142,7 +1075,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Cannot put duplicate accounts in Signers array", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1173,7 +1106,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Correctly append to pre-established Signers array", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux", "secret": "c", "tx_json": { @@ -1200,7 +1133,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Append to pre-established Signers array with bad signature", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux", "secret": "c", "tx_json": { @@ -1222,15 +1155,12 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType" : "Payment" } })", - {{"Already multisigned.", - "Already multisigned.", - "Invalid signature.", - "Invalid signature."}}}, + {{"Already multisigned.", "Already multisigned.", "Invalid signature.", "Invalid signature."}}}, {"Non-empty 'SigningPubKey' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1251,7 +1181,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Missing 'TransactionType' in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": { @@ -1271,7 +1201,7 @@ static constexpr TxnTestData txnTestArray[] = { {"TxnSignature in sign_for.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux", "secret": "c", "tx_json": { @@ -1302,7 +1232,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid field 'tx_json': string instead of object", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": "" @@ -1315,7 +1245,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid field 'tx_json': integer instead of object", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": 20160331 @@ -1328,7 +1258,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Invalid field 'tx_json': array instead of object", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "tx_json": [ "hello", "world" ] @@ -1341,7 +1271,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Pass in Fee with minimal payment, both Amount and DeliverMax.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "r9zN9x52FiCFAcicCLMQKbj1nxYhxJbbSy", "secret": "ssgN6zTvtM1q9XV8DvJpWm8LBYWiY", "tx_json": { @@ -1381,10 +1311,7 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"Missing field 'secret'.", - "Missing field 'secret'.", - "Missing field 'account'.", - ""}}}, + {{"Missing field 'secret'.", "Missing field 'secret'.", "Missing field 'account'.", ""}}}, {"Minimal submit_multisigned with bad signature.", __LINE__, @@ -1409,10 +1336,7 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"Missing field 'secret'.", - "Missing field 'secret'.", - "Missing field 'account'.", - "Invalid signature."}}}, + {{"Missing field 'secret'.", "Missing field 'secret'.", "Missing field 'account'.", "Invalid signature."}}}, {"Missing tx_json in submit_multisigned.", __LINE__, @@ -1428,10 +1352,7 @@ static constexpr TxnTestData txnTestArray[] = { } ] })", - {{"Missing field 'secret'.", - "Missing field 'secret'.", - "Missing field 'account'.", - "Missing field 'tx_json'."}}}, + {{"Missing field 'secret'.", "Missing field 'secret'.", "Missing field 'account'.", "Missing field 'tx_json'."}}}, {"Missing sequence in submit_multisigned.", __LINE__, @@ -1620,10 +1541,7 @@ static constexpr TxnTestData txnTestArray[] = { "TransactionType": "Payment" } })", - {{"Missing field 'secret'.", - "Missing field 'secret'.", - "Missing field 'account'.", - "Source account not found."}}}, + {{"Missing field 'secret'.", "Missing field 'secret'.", "Missing field 'account'.", "Source account not found."}}}, {"Missing Fee in submit_multisigned.", __LINE__, @@ -2022,7 +1940,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Payment cannot specify different DeliverMax and Amount.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "debug_signing": 0, @@ -2044,7 +1962,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Payment cannot specify bad DomainID.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "secret": "masterpassphrase", "debug_signing": 0, @@ -2067,7 +1985,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Minimal delegated transaction.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "secret": "a", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -2077,15 +1995,12 @@ static constexpr TxnTestData txnTestArray[] = { "Delegate": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA" } })", - {{"", - "", - "Missing field 'account'.", - "Missing field 'tx_json.Sequence'."}}}, + {{"", "", "Missing field 'account'.", "Missing field 'tx_json.Sequence'."}}}, {"Delegate not well formed.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "secret": "a", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -2103,7 +2018,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Delegate not in ledger.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "secret": "a", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -2121,7 +2036,7 @@ static constexpr TxnTestData txnTestArray[] = { {"Delegate and secret not match.", __LINE__, R"({ - "command": "doesnt_matter", + "command": "dummy_command", "secret": "aa", "tx_json": { "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", @@ -2146,12 +2061,10 @@ public: { testcase("bad RPC command"); test::jtx::Env env(*this); - Json::Value const result{ - env.rpc("bad_command", R"({"MakingThisUp": 0})")}; + Json::Value const result{env.rpc("bad_command", R"({"MakingThisUp": 0})")}; BEAST_EXPECT(result[jss::result][jss::error] == "unknownCmd"); - BEAST_EXPECT( - result[jss::result][jss::request][jss::command] == "bad_command"); + BEAST_EXPECT(result[jss::result][jss::request][jss::command] == "bad_command"); } void @@ -2188,19 +2101,12 @@ public: jt.jv.removeMember(jss::Fee); jt.jv.removeMember(jss::TxnSignature); req[jss::tx_json] = jt.jv; - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(result.size() == 0); BEAST_EXPECT( req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == - env.current()->fees().base.jsonClipped()); + req[jss::tx_json][jss::Fee] == env.current()->fees().base.jsonClipped()); } // test signers max size @@ -2259,19 +2165,12 @@ public: alice)); req[jss::tx_json] = jt.jv; - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(result.size() == 0); BEAST_EXPECT( req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == - env.current()->fees().base.jsonClipped()); + req[jss::tx_json][jss::Fee] == env.current()->fees().base.jsonClipped()); } } @@ -2280,28 +2179,18 @@ public: { testcase("autofill fees"); test::jtx::Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); auto ledger = env.current(); auto const& feeTrack = env.app().getFeeTrack(); { Json::Value req; - Json::Reader().parse( - "{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Reader().parse("{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == baseFee); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == baseFee); } { @@ -2310,33 +2199,18 @@ public: "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, " "\"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == baseFee); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == baseFee); } { Json::Value req; - Json::Reader().parse( - "{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Reader().parse("{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2350,14 +2224,8 @@ public: "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, " "\"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2369,14 +2237,8 @@ public: "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, " "\"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2388,14 +2250,8 @@ public: "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, " "\"tx_json\" : { } } ", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2405,22 +2261,14 @@ public: // transaction with a higher base fee Json::Value req; test::jtx::Account const alice("alice"); - req[jss::tx_json] = - test::jtx::acctdelete(env.master.human(), alice.human()); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrack, - env.app().getTxQ(), - env.app()); + req[jss::tx_json] = test::jtx::acctdelete(env.master.human(), alice.human()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrack, env.app().getTxQ(), env.app()); BEAST_EXPECT(result.size() == 0); BEAST_EXPECT( req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == - env.current()->fees().increment.jsonClipped()); + req[jss::tx_json][jss::Fee] == env.current()->fees().increment.jsonClipped()); } } @@ -2431,8 +2279,7 @@ public: using namespace test::jtx; Env env{*this, envconfig([](std::unique_ptr cfg) { cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue"); - cfg->section("transaction_queue") - .set("minimum_txn_in_ledger_standalone", "3"); + cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3"); return cfg; })}; LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack(); @@ -2446,19 +2293,11 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == 10); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 10); } { @@ -2470,19 +2309,11 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == 10); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 10); } // put 4 transactions into the open ledger @@ -2500,19 +2331,11 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == 8889); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 8889); } { @@ -2524,14 +2347,8 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2547,14 +2364,8 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee)); @@ -2570,19 +2381,11 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - req[jss::tx_json].isMember(jss::Fee) && - req[jss::tx_json][jss::Fee] == 8889); + BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 8889); } { @@ -2594,14 +2397,8 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); } @@ -2615,14 +2412,8 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); } @@ -2637,14 +2428,8 @@ public: "tx_json" : { } })", req); - Json::Value result = checkFee( - req, - Role::ADMIN, - true, - env.app().config(), - feeTrackOuter, - env.app().getTxQ(), - env.app()); + Json::Value result = + checkFee(req, Role::ADMIN, true, env.app().config(), feeTrackOuter, env.app().getTxQ(), env.app()); BEAST_EXPECT(RPC::contains_error(result)); } @@ -2660,13 +2445,10 @@ public: auto result = rpcResult[jss::result]; BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - result[jss::tx_json].isMember(jss::Fee) && - result[jss::tx_json][jss::Fee] == "10"); + BEAST_EXPECT(result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "10"); BEAST_EXPECT( result[jss::tx_json].isMember(jss::Sequence) && - result[jss::tx_json][jss::Sequence].isConvertibleTo( - Json::ValueType::uintValue)); + result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue)); } { @@ -2688,13 +2470,10 @@ public: auto result = rpcResult[jss::result]; BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - result[jss::tx_json].isMember(jss::Fee) && - result[jss::tx_json][jss::Fee] == "7813"); + BEAST_EXPECT(result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "7813"); BEAST_EXPECT( result[jss::tx_json].isMember(jss::Sequence) && - result[jss::tx_json][jss::Sequence].isConvertibleTo( - Json::ValueType::uintValue)); + result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue)); env.close(); } @@ -2716,13 +2495,10 @@ public: auto result = rpcResult[jss::result]; BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - result[jss::tx_json].isMember(jss::Fee) && - result[jss::tx_json][jss::Fee] == "47"); + BEAST_EXPECT(result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "47"); BEAST_EXPECT( result[jss::tx_json].isMember(jss::Sequence) && - result[jss::tx_json][jss::Sequence].isConvertibleTo( - Json::ValueType::uintValue)); + result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue)); } { @@ -2749,13 +2525,10 @@ public: auto result = rpcResult[jss::result]; BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - result[jss::tx_json].isMember(jss::Fee) && - result[jss::tx_json][jss::Fee] == "6806"); + BEAST_EXPECT(result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "6806"); BEAST_EXPECT( result[jss::tx_json].isMember(jss::Sequence) && - result[jss::tx_json][jss::Sequence].isConvertibleTo( - Json::ValueType::uintValue)); + result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue)); } } @@ -2779,19 +2552,13 @@ public: auto result = rpcResult[jss::result]; BEAST_EXPECT(!RPC::contains_error(result)); - BEAST_EXPECT( - result[jss::tx_json].isMember(jss::NetworkID) && - result[jss::tx_json][jss::NetworkID] == 1025); + BEAST_EXPECT(result[jss::tx_json].isMember(jss::NetworkID) && result[jss::tx_json][jss::NetworkID] == 1025); } } // A function that can be called as though it would process a transaction. static void - fakeProcessTransaction( - std::shared_ptr&, - bool, - bool, - NetworkOPs::FailHard) + fakeProcessTransaction(std::shared_ptr&, bool, bool, NetworkOPs::FailHard) { ; } @@ -2847,18 +2614,13 @@ public: Application& app, ProcessTransactionFn const& processTransaction); - using TestStuff = - std::tuple; + using TestStuff = std::tuple; static TestStuff const testFuncs[] = { TestStuff{transactionSign, nullptr, "sign", 0}, TestStuff{nullptr, transactionSubmit, "submit", 1}, TestStuff{transactionSignFor, nullptr, "sign_for", 2}, - TestStuff{ - nullptr, - transactionSubmitMultiSigned, - "submit_multisigned", - 3}}; + TestStuff{nullptr, transactionSubmitMultiSigned, "submit_multisigned", 3}}; for (auto testFunc : testFuncs) { @@ -2868,11 +2630,9 @@ public: Json::Value req; Json::Reader().parse(txnTest.json, req); if (RPC::contains_error(req)) - Throw( - "Internal JSONRPC_test error. Bad test JSON."); + Throw("Internal JSONRPC_test error. Bad test JSON."); - static Role const testedRoles[] = { - Role::GUEST, Role::USER, Role::ADMIN, Role::FORBID}; + static Role const testedRoles[] = {Role::GUEST, Role::USER, Role::ADMIN, Role::FORBID}; for (Role testRole : testedRoles) { @@ -2881,26 +2641,13 @@ public: if (signFn != nullptr) { assert(get<1>(testFunc) == nullptr); - result = signFn( - req, - 1, - NetworkOPs::FailHard::yes, - testRole, - 1s, - env.app()); + result = signFn(req, 1, NetworkOPs::FailHard::yes, testRole, 1s, env.app()); } else { auto const submitFn = get<1>(testFunc); assert(submitFn != nullptr); - result = submitFn( - req, - 1, - NetworkOPs::FailHard::yes, - testRole, - 1s, - env.app(), - processTxn); + result = submitFn(req, 1, NetworkOPs::FailHard::yes, testRole, 1s, env.app(), processTxn); } std::string errStr; @@ -2914,9 +2661,8 @@ public: else { std::ostringstream description; - description << txnTest.description << " Called " - << get<2>(testFunc) << "(). Got \'" - << errStr << "\'"; + description << txnTest.description << " Called " << get<2>(testFunc) << "(). Got \'" << errStr + << "\'"; fail(description.str(), __FILE__, txnTest.line); } } @@ -2936,7 +2682,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(JSONRPC, rpc, ripple); +BEAST_DEFINE_TESTSUITE(JSONRPC, rpc, xrpl); } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/KeyGeneration_test.cpp b/src/test/rpc/KeyGeneration_test.cpp index 3ea6a07e94..987985070d 100644 --- a/src/test/rpc/KeyGeneration_test.cpp +++ b/src/test/rpc/KeyGeneration_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace RPC { @@ -46,8 +27,7 @@ struct key_strings namespace common { static char const* passphrase = "REINDEER FLOTILLA"; -static char const* master_key = - "SCAT BERN ISLE FOR ROIL BUS SOAK AQUA FREE FOR DRAM BRIG"; +static char const* master_key = "SCAT BERN ISLE FOR ROIL BUS SOAK AQUA FREE FOR DRAM BRIG"; static char const* master_seed = "snMwVWs2hZzfDUF3p2tHZ3EgmyhFs"; static char const* master_seed_hex = "BE6A670A19B209E112146D0A7ED2AAD7"; } // namespace common @@ -94,7 +74,7 @@ static key_strings const strong_brain_strings = { "attacks.", }; -class WalletPropose_test : public ripple::TestSuite +class WalletPropose_test : public xrpl::TestSuite { public: void @@ -113,10 +93,7 @@ public: BEAST_EXPECT(result.isMember(jss::public_key_hex)); BEAST_EXPECT(result.isMember(jss::key_type)); - expectEquals( - result[jss::key_type], - params.isMember(jss::key_type) ? params[jss::key_type] - : "secp256k1"); + expectEquals(result[jss::key_type], params.isMember(jss::key_type) ? params[jss::key_type] : "secp256k1"); BEAST_EXPECT(!result.isMember(jss::warning)); std::string seed = result[jss::master_seed].asString(); @@ -138,17 +115,12 @@ public: expectEquals(result[jss::master_seed_hex], s.master_seed_hex); expectEquals(result[jss::public_key], s.public_key); expectEquals(result[jss::public_key_hex], s.public_key_hex); - expectEquals( - result[jss::key_type], - params.isMember(jss::key_type) ? params[jss::key_type] - : "secp256k1"); + expectEquals(result[jss::key_type], params.isMember(jss::key_type) ? params[jss::key_type] : "secp256k1"); return result; } void - testSeed( - std::optional const& keyType, - key_strings const& strings) + testSeed(std::optional const& keyType, key_strings const& strings) { testcase("seed"); @@ -162,9 +134,7 @@ public: } void - testSeedHex( - std::optional const& keyType, - key_strings const& strings) + testSeedHex(std::optional const& keyType, key_strings const& strings) { testcase("seed_hex"); @@ -178,10 +148,7 @@ public: } void - testLegacyPassphrase( - char const* value, - std::optional const& keyType, - key_strings const& strings) + testLegacyPassphrase(char const* value, std::optional const& keyType, key_strings const& strings) { Json::Value params; if (keyType) @@ -196,9 +163,7 @@ public: } void - testLegacyPassphrase( - std::optional const& keyType, - key_strings const& strings) + testLegacyPassphrase(std::optional const& keyType, key_strings const& strings) { testcase("passphrase"); @@ -209,9 +174,7 @@ public: } void - testKeyType( - std::optional const& keyType, - key_strings const& strings) + testKeyType(std::optional const& keyType, key_strings const& strings) { testcase(keyType ? *keyType : "no key_type"); @@ -242,9 +205,7 @@ public: params[jss::passphrase] = 20160506; auto result = walletPropose(params); BEAST_EXPECT(contains_error(result)); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'passphrase', not string."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'passphrase', not string."); } { @@ -253,9 +214,7 @@ public: params[jss::seed] = Json::objectValue; auto result = walletPropose(params); BEAST_EXPECT(contains_error(result)); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'seed', not string."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'seed', not string."); } { @@ -264,9 +223,7 @@ public: params[jss::seed_hex] = Json::arrayValue; auto result = walletPropose(params); BEAST_EXPECT(contains_error(result)); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'seed_hex', not string."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'seed_hex', not string."); } // Specifying multiple items at once @@ -300,9 +257,7 @@ public: params[jss::seed_hex] = common::master_seed_hex; auto result = walletPropose(params); BEAST_EXPECT(contains_error(result)); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'key_type', not string."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'key_type', not string."); } { @@ -311,22 +266,16 @@ public: params[jss::seed] = common::master_seed; auto result = walletPropose(params); BEAST_EXPECT(contains_error(result)); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'key_type', not string."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'key_type', not string."); } } void - testKeypairForSignature( - std::optional keyType, - key_strings const& strings) + testKeypairForSignature(std::optional keyType, key_strings const& strings) { - testcase( - "keypairForSignature - " + (keyType ? *keyType : "no key_type")); + testcase("keypairForSignature - " + (keyType ? *keyType : "no key_type")); - auto const publicKey = parseBase58( - TokenType::AccountPublic, strings.public_key); + auto const publicKey = parseBase58(TokenType::AccountPublic, strings.public_key); BEAST_EXPECT(publicKey); if (!keyType) @@ -436,9 +385,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'secret', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string."); } { @@ -450,9 +397,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'secret', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string."); } { @@ -465,9 +410,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'secret', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string."); } // Specify "secret" and "key_type" @@ -480,9 +423,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "The secret field is not allowed if key_type is used."); + BEAST_EXPECT(error[jss::error_message] == "The secret field is not allowed if key_type is used."); } // Specify unknown or bad "key_type" @@ -495,8 +436,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == "Invalid field 'key_type'."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type'."); } { @@ -508,9 +448,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'key_type', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type', not string."); } { @@ -522,9 +460,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'key_type', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type', not string."); } // Specify non-string passphrase @@ -537,9 +473,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'passphrase', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string."); } { // not a passphrase: object @@ -551,9 +485,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'passphrase', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string."); } { // not a passphrase: array @@ -565,9 +497,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'passphrase', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string."); } { // not a passphrase: empty string @@ -592,9 +522,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string."); } { // not a string: object @@ -606,9 +534,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string."); } { // not a string: array @@ -620,9 +546,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string."); } { // not a seed: empty @@ -671,9 +595,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed_hex', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string."); } { // not a string: object @@ -685,9 +607,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed_hex', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string."); } { // not a string: array @@ -699,9 +619,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); BEAST_EXPECT(!ret); - BEAST_EXPECT( - error[jss::error_message] == - "Invalid field 'seed_hex', not string."); + BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string."); } { // empty @@ -744,8 +662,7 @@ public: Json::Value params; Json::Value error; params[jss::key_type] = "secp256k1"; - params[jss::seed_hex] = - "BE6A670A19B209E112146D0A7ED2AAD72567D0FC913"; + params[jss::seed_hex] = "BE6A670A19B209E112146D0A7ED2AAD72567D0FC913"; auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); @@ -786,9 +703,7 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); - BEAST_EXPECT( - error[jss::error_message] == - "Specified seed is for an Ed25519 wallet."); + BEAST_EXPECT(error[jss::error_message] == "Specified seed is for an Ed25519 wallet."); } { @@ -818,60 +733,26 @@ public: auto ret = keypairForSignature(params, error); BEAST_EXPECT(contains_error(error)); - BEAST_EXPECT( - error[jss::error_message] == - "Specified seed is for an Ed25519 wallet."); + BEAST_EXPECT(error[jss::error_message] == "Specified seed is for an Ed25519 wallet."); } }; - test( - "sEdVWZmeUDgQdMEFKTK9kYVX71FKB7o", - "r34XnDB2zS11NZ1wKJzpU1mjWExGVugTaQ"); - test( - "sEd7zJoVnqg1FxB9EuaHC1AB5UPfHWz", - "rDw51qRrBEeMw7Na1Nh79LN7HYZDo7nZFE"); - test( - "sEdSxVntbihdLyabbfttMCqsaaucVR9", - "rwiyBDfAYegXZyaQcN2L1vAbKRYn2wNFMq"); - test( - "sEdSVwJjEXTYCztqDK4JD9WByH3otDX", - "rQJ4hZzNGkLQhLtKPCmu1ywEw1ai2vgUJN"); - test( - "sEdV3jXjKuUoQTSr1Rb4yw8Kyn9r46U", - "rERRw2Pxbau4tevE61V5vZUwD7Rus5Y6vW"); - test( - "sEdVeUZjuYT47Uy51FQCnzivsuWyiwB", - "rszewT5gRjUgWNEmnfMjvVYzJCkhvWY32i"); - test( - "sEd7MHTewdw4tFYeS7rk7XT4qHiA9jH", - "rBB2rvnf4ztwjgNhinFXQJ91nAZjkFgR3p"); - test( - "sEd7A5jFBSdWbNeKGriQvLr1thBScJh", - "rLAXz8Nz7aDivz7PwThsLFqaKrizepNCdA"); - test( - "sEdVPU9M2uyzVNT4Yb5Dn4tUtYjbFAw", - "rHbHRFPCxD5fnn98TBzsQHJ7SsRq7eHkRj"); - test( - "sEdVfF2zhAmS8gfMYzJ4yWBMeR4BZKc", - "r9PsneKHcAE7kUfiTixomM5Mnwi28tCc7h"); - test( - "sEdTjRtcsQkwthDXUSLi9DHNyJcR8GW", - "rM4soF4XS3wZrmLurvE6ZmudG16Lk5Dur5"); - test( - "sEdVNKeu1Lhpfh7Nf6tRDbxnmMyZ4Dv", - "r4ZwJxq6FDtWjapDtCGhjG6mtNm1nWdJcD"); - test( - "sEd7bK4gf5BHJ1WbaEWx8pKMA9MLHpC", - "rD6tnn51m4o1uXeEK9CFrZ3HR7DcFhiYnp"); - test( - "sEd7jCh3ppnQMsLdGcZ6TZayZaHhBLg", - "rTcBkiRQ1EfFQ4FCCwqXNHpn1yUTAACkj"); - test( - "sEdTFJezurQwSJAbkLygj2gQXBut2wh", - "rnXaMacNbRwcJddbbPbqdcpSUQcfzFmrR8"); - test( - "sEdSWajfQAAWFuDvVZF3AiGucReByLt", - "rBJtow6V3GTdsWMamrxetRDwWs6wwTxcKa"); + test("sEdVWZmeUDgQdMEFKTK9kYVX71FKB7o", "r34XnDB2zS11NZ1wKJzpU1mjWExGVugTaQ"); + test("sEd7zJoVnqg1FxB9EuaHC1AB5UPfHWz", "rDw51qRrBEeMw7Na1Nh79LN7HYZDo7nZFE"); + test("sEdSxVntbihdLyabbfttMCqsaaucVR9", "rwiyBDfAYegXZyaQcN2L1vAbKRYn2wNFMq"); + test("sEdSVwJjEXTYCztqDK4JD9WByH3otDX", "rQJ4hZzNGkLQhLtKPCmu1ywEw1ai2vgUJN"); + test("sEdV3jXjKuUoQTSr1Rb4yw8Kyn9r46U", "rERRw2Pxbau4tevE61V5vZUwD7Rus5Y6vW"); + test("sEdVeUZjuYT47Uy51FQCnzivsuWyiwB", "rszewT5gRjUgWNEmnfMjvVYzJCkhvWY32i"); + test("sEd7MHTewdw4tFYeS7rk7XT4qHiA9jH", "rBB2rvnf4ztwjgNhinFXQJ91nAZjkFgR3p"); + test("sEd7A5jFBSdWbNeKGriQvLr1thBScJh", "rLAXz8Nz7aDivz7PwThsLFqaKrizepNCdA"); + test("sEdVPU9M2uyzVNT4Yb5Dn4tUtYjbFAw", "rHbHRFPCxD5fnn98TBzsQHJ7SsRq7eHkRj"); + test("sEdVfF2zhAmS8gfMYzJ4yWBMeR4BZKc", "r9PsneKHcAE7kUfiTixomM5Mnwi28tCc7h"); + test("sEdTjRtcsQkwthDXUSLi9DHNyJcR8GW", "rM4soF4XS3wZrmLurvE6ZmudG16Lk5Dur5"); + test("sEdVNKeu1Lhpfh7Nf6tRDbxnmMyZ4Dv", "r4ZwJxq6FDtWjapDtCGhjG6mtNm1nWdJcD"); + test("sEd7bK4gf5BHJ1WbaEWx8pKMA9MLHpC", "rD6tnn51m4o1uXeEK9CFrZ3HR7DcFhiYnp"); + test("sEd7jCh3ppnQMsLdGcZ6TZayZaHhBLg", "rTcBkiRQ1EfFQ4FCCwqXNHpn1yUTAACkj"); + test("sEdTFJezurQwSJAbkLygj2gQXBut2wh", "rnXaMacNbRwcJddbbPbqdcpSUQcfzFmrR8"); + test("sEdSWajfQAAWFuDvVZF3AiGucReByLt", "rBJtow6V3GTdsWMamrxetRDwWs6wwTxcKa"); } void @@ -894,7 +775,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(WalletPropose, rpc, ripple); +BEAST_DEFINE_TESTSUITE(WalletPropose, rpc, xrpl); } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerClosed_test.cpp b/src/test/rpc/LedgerClosed_test.cpp index 37d6b1e393..d6b67ce406 100644 --- a/src/test/rpc/LedgerClosed_test.cpp +++ b/src/test/rpc/LedgerClosed_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class LedgerClosed_test : public beast::unit_test::suite { @@ -40,9 +21,7 @@ public: env.fund(XRP(10000), alice); auto lc_result = env.rpc("ledger_closed")[jss::result]; - BEAST_EXPECT( - lc_result[jss::ledger_hash] == - "CCC3B3E88CCAC17F1BE6B4A648A55999411F19E3FE55EB721960EB0DF28EDDA5"); + BEAST_EXPECT(lc_result[jss::ledger_hash] == "CCC3B3E88CCAC17F1BE6B4A648A55999411F19E3FE55EB721960EB0DF28EDDA5"); BEAST_EXPECT(lc_result[jss::ledger_index] == 2); env.close(); @@ -55,9 +34,7 @@ public: BEAST_EXPECT((*ar_alice)[sfBalance] == XRP(10000)); lc_result = env.rpc("ledger_closed")[jss::result]; - BEAST_EXPECT( - lc_result[jss::ledger_hash] == - "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D8F643B9552F0D895A31CDA78F541DE4E"); + BEAST_EXPECT(lc_result[jss::ledger_hash] == "0F1A9E0C109ADEF6DA2BDE19217C12BBEC57174CBDBD212B0EBDC1CEDB853185"); BEAST_EXPECT(lc_result[jss::ledger_index] == 3); } @@ -68,6 +45,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerClosed, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerClosed, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 120e49f129..0148185276 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class LedgerData_test : public beast::unit_test::suite { @@ -31,8 +12,7 @@ public: static bool checkMarker(Json::Value const& val) { - return val.isMember(jss::marker) && val[jss::marker].isString() && - val[jss::marker].asString().size() > 0; + return val.isMember(jss::marker) && val[jss::marker].isString() && val[jss::marker].asString().size() > 0; } void @@ -62,11 +42,8 @@ public: jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; { - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::ledger_current_index].isIntegral() && - jrr[jss::ledger_current_index].asInt() > 0); + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::ledger_current_index].isIntegral() && jrr[jss::ledger_current_index].asInt() > 0); BEAST_EXPECT(checkMarker(jrr)); BEAST_EXPECT(checkArraySize(jrr[jss::state], max_limit)); } @@ -75,11 +52,8 @@ public: for (auto delta = -1; delta <= 1; delta++) { jvParams[jss::limit] = max_limit + delta; - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; - BEAST_EXPECT(checkArraySize( - jrr[jss::state], - (delta > 0 && !asAdmin) ? max_limit : max_limit + delta)); + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; + BEAST_EXPECT(checkArraySize(jrr[jss::state], (delta > 0 && !asAdmin) ? max_limit : max_limit + delta)); } } @@ -105,11 +79,8 @@ public: Json::Value jvParams; jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = true; - auto const jrr = - env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::ledger_current_index].isIntegral() && - jrr[jss::ledger_current_index].asInt() > 0); + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::ledger_current_index].isIntegral() && jrr[jss::ledger_current_index].asInt() > 0); BEAST_EXPECT(!jrr.isMember(jss::marker)); BEAST_EXPECT(checkArraySize(jrr[jss::state], num_accounts + 4)); } @@ -130,47 +101,37 @@ public: // bad limit Json::Value jvParams; jvParams[jss::limit] = "0"; // NOT an integer - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'limit', not integer."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not integer."); } { // invalid marker Json::Value jvParams; jvParams[jss::marker] = "NOT_A_MARKER"; - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'marker', not valid."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid."); } { // invalid marker - not a string Json::Value jvParams; jvParams[jss::marker] = 1; - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); BEAST_EXPECT(jrr[jss::status] == "error"); - BEAST_EXPECT( - jrr[jss::error_message] == - "Invalid field 'marker', not valid."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid."); } { // ask for a bad ledger index Json::Value jvParams; jvParams[jss::ledger_index] = 10u; - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "lgrNotFound"); BEAST_EXPECT(jrr[jss::status] == "error"); BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound"); @@ -199,8 +160,7 @@ public: Json::Value jvParams; jvParams[jss::ledger_index] = "current"; jvParams[jss::binary] = false; - auto jrr = - env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; auto const total_count = jrr[jss::state].size(); // now make request with a limit and loop until we get all @@ -211,8 +171,7 @@ public: while (jrr.isMember(jss::marker)) { jvParams[jss::marker] = jrr[jss::marker]; - jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; running_total += jrr[jss::state].size(); } BEAST_EXPECT(running_total == total_count); @@ -231,24 +190,19 @@ public: // Closed ledger with non binary form Json::Value jvParams; jvParams[jss::ledger_index] = "closed"; - auto jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; if (BEAST_EXPECT(jrr.isMember(jss::ledger))) - BEAST_EXPECT( - jrr[jss::ledger][jss::ledger_hash] == - to_string(env.closed()->info().hash)); + BEAST_EXPECT(jrr[jss::ledger][jss::ledger_hash] == to_string(env.closed()->header().hash)); } { // Closed ledger with binary form Json::Value jvParams; jvParams[jss::ledger_index] = "closed"; jvParams[jss::binary] = true; - auto jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; if (BEAST_EXPECT(jrr.isMember(jss::ledger))) { - auto data = - strUnHex(jrr[jss::ledger][jss::ledger_data].asString()); + auto data = strUnHex(jrr[jss::ledger][jss::ledger_data].asString()); if (BEAST_EXPECT(data)) { Serializer s(data->data(), data->size()); @@ -262,8 +216,7 @@ public: // Current ledger with binary form Json::Value jvParams; jvParams[jss::binary] = true; - auto jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::ledger)); BEAST_EXPECT(!jrr[jss::ledger].isMember(jss::ledger_data)); } @@ -277,8 +230,7 @@ public: // Make sure fixInnerObjTemplate2 doesn't break amendments. for (FeatureBitset const& features : - {testable_amendments() - fixInnerObjTemplate2, - testable_amendments() | fixInnerObjTemplate2}) + {testable_amendments() - fixInnerObjTemplate2, testable_amendments() | fixInnerObjTemplate2}) { using namespace std::chrono; Env env{*this, envconfig(validator, ""), features}; @@ -291,8 +243,7 @@ public: Json::Value jvParams; jvParams[jss::ledger_index] = "current"; jvParams[jss::type] = type; - return env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + return env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; }; // Assert that state is an empty array. @@ -331,10 +282,7 @@ public: break; } - env(signers( - Account{"bob0"}, - 1, - {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}})); + env(signers(Account{"bob0"}, 1, {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}})); env(ticket::create(env.master, 1)); { @@ -343,10 +291,7 @@ public: jv[jss::Account] = Account{"bob5"}.human(); jv[jss::Destination] = Account{"bob6"}.human(); jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none); - jv[sfFinishAfter.fieldName] = - NetClock::time_point{env.now() + 10s} - .time_since_epoch() - .count(); + jv[sfFinishAfter.fieldName] = NetClock::time_point{env.now() + 10s}.time_since_epoch().count(); env(jv); } @@ -357,12 +302,8 @@ public: jv[jss::Destination] = Account{"bob7"}.human(); jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none); jv[jss::SettleDelay] = NetClock::duration{10s}.count(); - jv[sfPublicKey.fieldName] = - strHex(Account{"bob6"}.pk().slice()); - jv[sfCancelAfter.fieldName] = - NetClock::time_point{env.now() + 300s} - .time_since_epoch() - .count(); + jv[sfPublicKey.fieldName] = strHex(Account{"bob6"}.pk().slice()); + jv[sfCancelAfter.fieldName] = NetClock::time_point{env.now() + 300s}.time_since_epoch().count(); env(jv); } @@ -470,8 +411,7 @@ public: Json::Value jvParams; jvParams[jss::ledger_index] = "current"; jvParams[jss::type] = "misspelling"; - auto const jrr = env.rpc( - "json", "ledger_data", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember("error")); BEAST_EXPECT(jrr["error"] == "invalidParams"); BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'."); @@ -492,6 +432,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, rpc, ripple, 1); +BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, rpc, xrpl, 1); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index a88f6ab612..5d12e7bb83 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,6 +5,8 @@ #include #include +#include + #include #include #include @@ -31,14 +14,8 @@ #include #include -#if (defined(__clang_major__) && __clang_major__ < 15) -#include -using source_location = std::experimental::source_location; -#else #include -using std::source_location; -#endif -namespace ripple { +namespace xrpl { namespace test { @@ -49,6 +26,8 @@ enum class FieldType { CurrencyField, HashField, HashOrObjectField, + FixedHashField, + IssueField, ObjectField, StringField, TwoAccountArrayField, @@ -59,6 +38,8 @@ enum class FieldType { std::vector> mappings{ {jss::account, FieldType::AccountField}, {jss::accounts, FieldType::TwoAccountArrayField}, + {jss::asset, FieldType::IssueField}, + {jss::asset2, FieldType::IssueField}, {jss::authorize, FieldType::AccountField}, {jss::authorized, FieldType::AccountField}, {jss::credential_type, FieldType::BlobField}, @@ -74,17 +55,14 @@ std::vector> mappings{ FieldType getFieldType(Json::StaticString fieldName) { - auto it = std::ranges::find_if(mappings, [&fieldName](auto const& pair) { - return pair.first == fieldName; - }); + auto it = std::ranges::find_if(mappings, [&fieldName](auto const& pair) { return pair.first == fieldName; }); if (it != mappings.end()) { return it->second; } else { - Throw( - "`mappings` is missing field " + std::string(fieldName.c_str())); + Throw("`mappings` is missing field " + std::string(fieldName.c_str())); } } @@ -93,27 +71,29 @@ getTypeName(FieldType typeID) { switch (typeID) { - case FieldType::UInt32Field: - return "number"; - case FieldType::UInt64Field: - return "number"; - case FieldType::HashField: - return "hex string"; case FieldType::AccountField: return "AccountID"; + case FieldType::ArrayField: + return "array"; case FieldType::BlobField: return "hex string"; case FieldType::CurrencyField: return "Currency"; - case FieldType::ArrayField: - return "array"; + case FieldType::HashField: + case FieldType::FixedHashField: + return "hex string"; case FieldType::HashOrObjectField: return "hex string or object"; + case FieldType::IssueField: + return "Issue"; case FieldType::TwoAccountArrayField: return "length-2 array of Accounts"; + case FieldType::UInt32Field: + return "number"; + case FieldType::UInt64Field: + return "number"; default: - Throw( - "unknown type " + std::to_string(static_cast(typeID))); + Throw("unknown type " + std::to_string(static_cast(typeID))); } } @@ -124,35 +104,27 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value const& jv, std::string const& err, std::string const& msg, - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { if (BEAST_EXPECT(jv.isMember(jss::status))) - BEAST_EXPECTS( - jv[jss::status] == "error", std::to_string(location.line())); + BEAST_EXPECTS(jv[jss::status] == "error", std::to_string(location.line())); if (BEAST_EXPECT(jv.isMember(jss::error))) BEAST_EXPECTS( jv[jss::error] == err, - "Expected error " + err + ", received " + - jv[jss::error].asString() + ", at line " + - std::to_string(location.line()) + ", " + - jv.toStyledString()); + "Expected error " + err + ", received " + jv[jss::error].asString() + ", at line " + + std::to_string(location.line()) + ", " + jv.toStyledString()); if (msg.empty()) { BEAST_EXPECTS( - jv[jss::error_message] == Json::nullValue || - jv[jss::error_message] == "", - "Expected no error message, received \"" + - jv[jss::error_message].asString() + "\", at line " + - std::to_string(location.line()) + ", " + - jv.toStyledString()); + jv[jss::error_message] == Json::nullValue || jv[jss::error_message] == "", + "Expected no error message, received \"" + jv[jss::error_message].asString() + "\", at line " + + std::to_string(location.line()) + ", " + jv.toStyledString()); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) BEAST_EXPECTS( jv[jss::error_message] == msg, - "Expected error message \"" + msg + "\", received \"" + - jv[jss::error_message].asString() + "\", at line " + - std::to_string(location.line()) + ", " + - jv.toStyledString()); + "Expected error message \"" + msg + "\", received \"" + jv[jss::error_message].asString() + + "\", at line " + std::to_string(location.line()) + ", " + jv.toStyledString()); } std::vector @@ -195,10 +167,8 @@ class LedgerEntry_test : public beast::unit_test::suite injectArray // 20 }; - auto remove = - [&](std::vector indices) -> std::vector { - std::unordered_set indexSet( - indices.begin(), indices.end()); + auto remove = [&](std::vector indices) -> std::vector { + std::unordered_set indexSet(indices.begin(), indices.end()); std::vector values; values.reserve(allBadValues.size() - indexSet.size()); for (std::size_t i = 0; i < allBadValues.size(); ++i) @@ -211,38 +181,42 @@ class LedgerEntry_test : public beast::unit_test::suite return values; }; - static auto const& badUInt32Values = remove({2, 3}); - static auto const& badUInt64Values = remove({2, 3}); - static auto const& badHashValues = remove({2, 3, 7, 8, 16}); static auto const& badAccountValues = remove({12}); + static auto const& badArrayValues = remove({17, 20}); static auto const& badBlobValues = remove({3, 7, 8, 16}); static auto const& badCurrencyValues = remove({14}); - static auto const& badArrayValues = remove({17, 20}); + static auto const& badHashValues = remove({2, 3, 7, 8, 16}); + static auto const& badFixedHashValues = remove({1, 2, 3, 4, 7, 8, 16}); static auto const& badIndexValues = remove({12, 16, 18, 19}); + static auto const& badUInt32Values = remove({2, 3}); + static auto const& badUInt64Values = remove({2, 3}); + static auto const& badIssueValues = remove({}); switch (fieldType) { - case FieldType::UInt32Field: - return badUInt32Values; - case FieldType::UInt64Field: - return badUInt64Values; - case FieldType::HashField: - return badHashValues; case FieldType::AccountField: return badAccountValues; + case FieldType::ArrayField: + case FieldType::TwoAccountArrayField: + return badArrayValues; case FieldType::BlobField: return badBlobValues; case FieldType::CurrencyField: return badCurrencyValues; - case FieldType::ArrayField: - case FieldType::TwoAccountArrayField: - return badArrayValues; + case FieldType::HashField: + return badHashValues; case FieldType::HashOrObjectField: return badIndexValues; + case FieldType::FixedHashField: + return badFixedHashValues; + case FieldType::IssueField: + return badIssueValues; + case FieldType::UInt32Field: + return badUInt32Values; + case FieldType::UInt64Field: + return badUInt64Values; default: - Throw( - "unknown type " + - std::to_string(static_cast(fieldType))); + Throw("unknown type " + std::to_string(static_cast(fieldType))); } } @@ -255,34 +229,39 @@ class LedgerEntry_test : public beast::unit_test::suite arr[1u] = "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5"; return arr; }(); + static Json::Value const issueObject = []() { + Json::Value arr(Json::objectValue); + arr[jss::currency] = "XRP"; + return arr; + }(); auto const typeID = getFieldType(fieldName); switch (typeID) { - case FieldType::UInt32Field: - return 1; - case FieldType::UInt64Field: - return 1; - case FieldType::HashField: - return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6" - "B01403D6D"; case FieldType::AccountField: return "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5"; + case FieldType::ArrayField: + return Json::arrayValue; case FieldType::BlobField: return "ABCDEF"; case FieldType::CurrencyField: return "USD"; - case FieldType::ArrayField: - return Json::arrayValue; + case FieldType::HashField: + return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6" + "B01403D6D"; + case FieldType::IssueField: + return issueObject; case FieldType::HashOrObjectField: return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6" "B01403D6D"; case FieldType::TwoAccountArrayField: return twoAccountArray; + case FieldType::UInt32Field: + return 1; + case FieldType::UInt64Field: + return 1; default: - Throw( - "unknown type " + - std::to_string(static_cast(typeID))); + Throw("unknown type " + std::to_string(static_cast(typeID))); } } @@ -294,35 +273,24 @@ class LedgerEntry_test : public beast::unit_test::suite FieldType const typeID, std::string const& expectedError, bool required = true, - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { forAllApiVersions([&, this](unsigned apiVersion) { if (required) { correctRequest.removeMember(fieldName); - Json::Value const jrr = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(correctRequest))[jss::result]; + Json::Value const jrr = + env.rpc(apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; if (apiVersion < 2u) checkErrorValue(jrr, "unknownOption", "", location); else - checkErrorValue( - jrr, - "invalidParams", - "No ledger_entry params provided.", - location); + checkErrorValue(jrr, "invalidParams", "No ledger_entry params provided.", location); } auto tryField = [&](Json::Value fieldValue) -> void { correctRequest[fieldName] = fieldValue; - Json::Value const jrr = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(correctRequest))[jss::result]; - auto const expectedErrMsg = - RPC::expected_field_message(fieldName, getTypeName(typeID)); + Json::Value const jrr = + env.rpc(apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; + auto const expectedErrMsg = RPC::expected_field_message(fieldName, getTypeName(typeID)); checkErrorValue(jrr, expectedError, expectedErrMsg, location); }; @@ -347,48 +315,28 @@ class LedgerEntry_test : public beast::unit_test::suite FieldType typeID, std::string const& expectedError, bool required = true, - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { forAllApiVersions([&, this](unsigned apiVersion) { if (required) { correctRequest[parentFieldName].removeMember(fieldName); - Json::Value const jrr = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(correctRequest))[jss::result]; - checkErrorValue( - jrr, - "malformedRequest", - RPC::missing_field_message(fieldName.c_str()), - location); + Json::Value const jrr = + env.rpc(apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; + checkErrorValue(jrr, "malformedRequest", RPC::missing_field_message(fieldName.c_str()), location); correctRequest[parentFieldName][fieldName] = Json::nullValue; - Json::Value const jrr2 = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(correctRequest))[jss::result]; - checkErrorValue( - jrr2, - "malformedRequest", - RPC::missing_field_message(fieldName.c_str()), - location); + Json::Value const jrr2 = + env.rpc(apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; + checkErrorValue(jrr2, "malformedRequest", RPC::missing_field_message(fieldName.c_str()), location); } auto tryField = [&](Json::Value fieldValue) -> void { correctRequest[parentFieldName][fieldName] = fieldValue; - Json::Value const jrr = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(correctRequest))[jss::result]; + Json::Value const jrr = + env.rpc(apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; checkErrorValue( - jrr, - expectedError, - RPC::expected_field_message(fieldName, getTypeName(typeID)), - location); + jrr, expectedError, RPC::expected_field_message(fieldName, getTypeName(typeID)), location); }; auto const& badValues = getBadValues(typeID); @@ -404,16 +352,9 @@ class LedgerEntry_test : public beast::unit_test::suite runLedgerEntryTest( test::jtx::Env& env, Json::StaticString const& parentField, - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { - testMalformedField( - env, - Json::Value{}, - parentField, - FieldType::HashField, - "malformedRequest", - true, - location); + testMalformedField(env, Json::Value{}, parentField, FieldType::HashField, "malformedRequest", true, location); } struct Subfield @@ -428,23 +369,16 @@ class LedgerEntry_test : public beast::unit_test::suite test::jtx::Env& env, Json::StaticString const& parentField, std::vector const& subfields, - source_location const location = source_location::current()) + std::source_location const location = std::source_location::current()) { testMalformedField( - env, - Json::Value{}, - parentField, - FieldType::HashOrObjectField, - "malformedRequest", - true, - location); + env, Json::Value{}, parentField, FieldType::HashOrObjectField, "malformedRequest", true, location); Json::Value correctOutput; correctOutput[parentField] = Json::objectValue; for (auto const& subfield : subfields) { - correctOutput[parentField][subfield.fieldName] = - getCorrectValue(subfield.fieldName); + correctOutput[parentField][subfield.fieldName] = getCorrectValue(subfield.fieldName); } for (auto const& subfield : subfields) @@ -463,7 +397,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryInvalid() + testInvalid() { testcase("Invalid requests"); using namespace test::jtx; @@ -478,8 +412,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ledger_hash] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AA"; - auto const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound"); } { @@ -491,15 +424,9 @@ class LedgerEntry_test : public beast::unit_test::suite forAllApiVersions([&, this](unsigned apiVersion) { auto tryField = [&](Json::Value fieldValue) -> void { jvParams[jss::ledger_hash] = fieldValue; - Json::Value const jrr = env.rpc( - apiVersion, - "json", - "ledger_entry", - to_string(jvParams))[jss::result]; - auto const expectedErrMsg = fieldValue.isString() - ? "ledgerHashMalformed" - : "ledgerHashNotString"; - checkErrorValue(jrr, "invalidParams", expectedErrMsg); + Json::Value const jrr = + env.rpc(apiVersion, "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "invalidParams", "Invalid field 'ledger_hash', not hex string."); }; auto const& badValues = getBadValues(typeId); @@ -517,8 +444,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::index] = "00000000000000000000000000000000000000000000000000000000000000" "00"; - auto const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } @@ -530,22 +456,18 @@ class LedgerEntry_test : public beast::unit_test::suite "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAA"; jvParams[jss::api_version] = apiVersion; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; if (apiVersion < 2u) checkErrorValue(jrr, "unknownOption", ""); else - checkErrorValue( - jrr, - "invalidParams", - "No ledger_entry params provided."); + checkErrorValue(jrr, "invalidParams", "No ledger_entry params provided."); } }); } void - testLedgerEntryAccountRoot() + testAccountRoot() { testcase("AccountRoot"); using namespace test::jtx; @@ -558,7 +480,7 @@ class LedgerEntry_test : public beast::unit_test::suite env.fund(XRP(10000), alice); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Exercise ledger_closed along the way. Json::Value const jrr = env.rpc("ledger_closed")[jss::result]; @@ -572,15 +494,14 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::account_root] = alice.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000"); accountRootIndex = jrr[jss::index].asString(); } { - constexpr char alicesAcctRootBinary[]{ + constexpr char aliceAcctRootBinary[]{ "1100612200800000240000000425000000032D00000000559CE54C3B934E4" "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002" "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"}; @@ -590,17 +511,15 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::account_root] = alice.human(); jvParams[jss::binary] = 1; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node_binary)); - BEAST_EXPECT(jrr[jss::node_binary] == alicesAcctRootBinary); + BEAST_EXPECT(jrr[jss::node_binary] == aliceAcctRootBinary); } { // Request alice's account root using the index. Json::Value jvParams; jvParams[jss::index] = accountRootIndex; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(!jrr.isMember(jss::node_binary)); BEAST_EXPECT(jrr.isMember(jss::node)); BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human()); @@ -611,8 +530,7 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::index] = accountRootIndex; jvParams[jss::binary] = 0; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000"); @@ -622,8 +540,7 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::account] = alice.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000"); @@ -632,26 +549,148 @@ class LedgerEntry_test : public beast::unit_test::suite { // Check malformed cases Json::Value jvParams; - testMalformedField( - env, - jvParams, - jss::account_root, - FieldType::AccountField, - "malformedAddress"); + testMalformedField(env, jvParams, jss::account_root, FieldType::AccountField, "malformedAddress"); } { // Request an account that is not in the ledger. Json::Value jvParams; jvParams[jss::account_root] = Account("bob").human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } } void - testLedgerEntryCheck() + testAmendments() + { + testcase("Amendments"); + using namespace test::jtx; + Env env{*this}; + + // positive test + { + Keylet const keylet = keylet::amendments(); + + // easier to hack an object into the ledger than generate it + // legitimately + { + auto const amendments = [&](OpenView& view, beast::Journal) -> bool { + auto const sle = std::make_shared(keylet); + + // Create Amendments vector (enabled amendments) + std::vector enabledAmendments; + enabledAmendments.push_back( + uint256::fromVoid("42426C4D4F1009EE67080A9B7965B44656D7" + "714D104A72F9B4369F97ABF044EE")); + enabledAmendments.push_back( + uint256::fromVoid("4C97EBA926031A7CF7D7B36FDE3ED66DDA54" + "21192D63DE53FFB46E43B9DC8373")); + enabledAmendments.push_back( + uint256::fromVoid("03BDC0099C4E14163ADA272C1B6F6FABB448" + "CC3E51F522F978041E4B57D9158C")); + enabledAmendments.push_back( + uint256::fromVoid("35291ADD2D79EB6991343BDA0912269C817D" + "0F094B02226C1C14AD2858962ED4")); + sle->setFieldV256(sfAmendments, STVector256(enabledAmendments)); + + // Create Majorities array + STArray majorities; + + auto majority1 = STObject::makeInnerObject(sfMajority); + majority1.setFieldH256( + sfAmendment, + uint256::fromVoid("7BB62DC13EC72B775091E9C71BF8CF97E122" + "647693B50C5E87A80DFD6FCFAC50")); + majority1.setFieldU32(sfCloseTime, 779561310); + majorities.push_back(std::move(majority1)); + + auto majority2 = STObject::makeInnerObject(sfMajority); + majority2.setFieldH256( + sfAmendment, + uint256::fromVoid("755C971C29971C9F20C6F080F2ED96F87884" + "E40AD19554A5EBECDCEC8A1F77FE")); + majority2.setFieldU32(sfCloseTime, 779561310); + majorities.push_back(std::move(majority2)); + + sle->setFieldArray(sfMajorities, majorities); + + view.rawInsert(sle); + return true; + }; + env.app().openLedger().modify(amendments); + } + + Json::Value jvParams; + jvParams[jss::amendments] = to_string(keylet.key); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Amendments); + } + + // negative tests + testMalformedField(env, Json::Value{}, jss::amendments, FieldType::FixedHashField, "malformedRequest"); + } + + void + testAMM() + { + testcase("AMM"); + using namespace test::jtx; + Env env{*this}; + + // positive test + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + AMM amm(env, alice, XRP(10), alice["USD"](1000)); + env.close(); + + { + Json::Value jvParams; + jvParams[jss::amm] = to_string(amm.ammID()); + auto const result = env.rpc("json", "ledger_entry", to_string(jvParams)); + BEAST_EXPECT( + result.isObject() && result.isMember(jss::result) && !result[jss::result].isMember(jss::error) && + result[jss::result].isMember(jss::node) && + result[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + result[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::AMM); + } + + { + Json::Value jvParams; + Json::Value ammParams(Json::objectValue); + { + Json::Value obj(Json::objectValue); + obj[jss::currency] = "XRP"; + ammParams[jss::asset] = obj; + } + { + Json::Value obj(Json::objectValue); + obj[jss::currency] = "USD"; + obj[jss::issuer] = alice.human(); + ammParams[jss::asset2] = obj; + } + jvParams[jss::amm] = ammParams; + auto const result = env.rpc("json", "ledger_entry", to_string(jvParams)); + BEAST_EXPECT( + result.isObject() && result.isMember(jss::result) && !result[jss::result].isMember(jss::error) && + result[jss::result].isMember(jss::node) && + result[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + result[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::AMM); + } + + // negative tests + runLedgerEntryTest( + env, + jss::amm, + { + {jss::asset, "malformedRequest"}, + {jss::asset2, "malformedRequest"}, + }); + } + + void + testCheck() { testcase("Check"); using namespace test::jtx; @@ -665,16 +704,14 @@ class LedgerEntry_test : public beast::unit_test::suite env(check::create(env.master, alice, XRP(100))); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Request a check. Json::Value jvParams; jvParams[jss::check] = to_string(checkId.key); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); } { @@ -684,17 +721,14 @@ class LedgerEntry_test : public beast::unit_test::suite { Json::Value jvParams; jvParams[jss::account_root] = alice.human(); - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; accountRootIndex = jrr[jss::index].asString(); } Json::Value jvParams; jvParams[jss::check] = accountRootIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, "unexpectedLedgerType", "Unexpected ledger type."); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "unexpectedLedgerType", "Unexpected ledger type."); } { // Check malformed cases @@ -703,7 +737,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryCredentials() + testCredentials() { testcase("Credentials"); @@ -726,25 +760,19 @@ class LedgerEntry_test : public beast::unit_test::suite // Succeed auto jv = credentials::ledgerEntry(env, alice, issuer, credType); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - !jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && jv[jss::result].isMember(jss::node) && - jv[jss::result][jss::node].isMember( - sfLedgerEntryType.jsonName) && - jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == - jss::Credential); + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::Credential); std::string const credIdx = jv[jss::result][jss::index].asString(); jv = credentials::ledgerEntry(env, credIdx); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - !jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && jv[jss::result].isMember(jss::node) && - jv[jss::result][jss::node].isMember( - sfLedgerEntryType.jsonName) && - jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == - jss::Credential); + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::Credential); } { @@ -753,8 +781,7 @@ class LedgerEntry_test : public beast::unit_test::suite env, "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" "E4"); - checkErrorValue( - jv[jss::result], "entryNotFound", "Entry not found."); + checkErrorValue(jv[jss::result], "entryNotFound", "Entry not found."); } { @@ -771,7 +798,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryDelegate() + testDelegate() { testcase("Delegate"); @@ -784,7 +811,7 @@ class LedgerEntry_test : public beast::unit_test::suite env.close(); env(delegate::set(alice, bob, {"Payment", "CheckCreate"})); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; std::string delegateIndex; { // Request by account and authorize @@ -792,10 +819,8 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::delegate][jss::account] = alice.human(); jvParams[jss::delegate][jss::authorize] = bob.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate); BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human()); delegateIndex = jrr[jss::node][jss::index].asString(); @@ -805,10 +830,8 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::delegate] = delegateIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate); BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human()); } @@ -826,7 +849,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryDepositPreauth() + testDepositPreauth() { testcase("Deposit Preauth"); @@ -842,7 +865,7 @@ class LedgerEntry_test : public beast::unit_test::suite env(deposit::auth(alice, becky)); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; std::string depositPreauthIndex; { // Request a depositPreauth by owner and authorized. @@ -850,12 +873,9 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::deposit_preauth][jss::owner] = alice.human(); jvParams[jss::deposit_preauth][jss::authorized] = becky.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == - jss::DepositPreauth); + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth); BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human()); depositPreauthIndex = jrr[jss::node][jss::index].asString(); @@ -865,12 +885,9 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::deposit_preauth] = depositPreauthIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == - jss::DepositPreauth); + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth); BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human()); } @@ -887,7 +904,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryDepositPreauthCred() + testDepositPreauthCred() { testcase("Deposit Preauth with credentials"); @@ -916,26 +933,20 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); Json::Value jo; jo[jss::issuer] = issuer.human(); jo[jss::credential_type] = strHex(std::string_view(credType)); arr.append(std::move(jo)); - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); BEAST_EXPECT( - jrr.isObject() && jrr.isMember(jss::result) && - !jrr[jss::result].isMember(jss::error) && + jrr.isObject() && jrr.isMember(jss::result) && !jrr[jss::result].isMember(jss::error) && jrr[jss::result].isMember(jss::node) && - jrr[jss::result][jss::node].isMember( - sfLedgerEntryType.jsonName) && - jrr[jss::result][jss::node][sfLedgerEntryType.jsonName] == - jss::DepositPreauth); + jrr[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jrr[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth); } { @@ -950,16 +961,12 @@ class LedgerEntry_test : public beast::unit_test::suite jo[jss::issuer] = fieldValue; jo[jss::credential_type] = strHex(std::string_view(credType)); arr.append(jo); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - arr; + jvParams[jss::deposit_preauth][jss::authorized_credentials] = arr; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - auto const expectedErrMsg = fieldValue.isNull() - ? RPC::missing_field_message(jss::issuer.c_str()) - : RPC::expected_field_message(jss::issuer, "AccountID"); - checkErrorValue( - jrr, "malformedAuthorizedCredentials", expectedErrMsg); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + auto const expectedErrMsg = fieldValue.isNull() ? RPC::missing_field_message(jss::issuer.c_str()) + : RPC::expected_field_message(jss::issuer, "AccountID"); + checkErrorValue(jrr, "malformedAuthorizedCredentials", expectedErrMsg); }; auto const& badValues = getBadValues(FieldType::AccountField); @@ -976,23 +983,19 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); Json::Value jo; jo[jss::issuer] = issuer.human(); jo[jss::credential_type] = strHex(std::string_view(credType)); arr.append(jo); arr.append(std::move(jo)); - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedAuthorizedCredentials", - RPC::expected_field_message( - jss::authorized_credentials, "array")); + RPC::expected_field_message(jss::authorized_credentials, "array")); } { @@ -1007,17 +1010,13 @@ class LedgerEntry_test : public beast::unit_test::suite jo[jss::issuer] = issuer.human(); jo[jss::credential_type] = fieldValue; arr.append(jo); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - arr; + jvParams[jss::deposit_preauth][jss::authorized_credentials] = arr; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; auto const expectedErrMsg = fieldValue.isNull() ? RPC::missing_field_message(jss::credential_type.c_str()) - : RPC::expected_field_message( - jss::credential_type, "hex string"); - checkErrorValue( - jrr, "malformedAuthorizedCredentials", expectedErrMsg); + : RPC::expected_field_message(jss::credential_type, "hex string"); + checkErrorValue(jrr, "malformedAuthorizedCredentials", expectedErrMsg); }; auto const& badValues = getBadValues(FieldType::BlobField); @@ -1035,18 +1034,15 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::deposit_preauth][jss::owner] = bob.human(); jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); Json::Value jo; jo[jss::issuer] = issuer.human(); jo[jss::credential_type] = strHex(std::string_view(credType)); arr.append(std::move(jo)); - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedRequest", @@ -1074,14 +1070,11 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); arr.append("foobar"); - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedAuthorizedCredentials", @@ -1093,16 +1086,13 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); Json::Value payload = Json::arrayValue; payload.append(42); arr.append(std::move(payload)); - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedAuthorizedCredentials", @@ -1114,41 +1104,27 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedAuthorizedCredentials", - "Invalid field 'authorized_credentials', not array."); + "Invalid field 'authorized_credentials', array empty."); } { // Failed, authorized_credentials is too long static std::array const credTypes = { - "cred1", - "cred2", - "cred3", - "cred4", - "cred5", - "cred6", - "cred7", - "cred8", - "cred9"}; - static_assert( - sizeof(credTypes) / sizeof(credTypes[0]) > - maxCredentialsArraySize); + "cred1", "cred2", "cred3", "cred4", "cred5", "cred6", "cred7", "cred8", "cred9"}; + static_assert(sizeof(credTypes) / sizeof(credTypes[0]) > maxCredentialsArraySize); Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized_credentials] = - Json::arrayValue; + jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; - auto& arr( - jvParams[jss::deposit_preauth][jss::authorized_credentials]); + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); for (auto cred : credTypes) { @@ -1158,17 +1134,16 @@ class LedgerEntry_test : public beast::unit_test::suite arr.append(std::move(jo)); } - auto const jrr = - env.rpc("json", "ledger_entry", to_string(jvParams)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); checkErrorValue( jrr[jss::result], "malformedAuthorizedCredentials", - "Invalid field 'authorized_credentials', not array."); + "Invalid field 'authorized_credentials', array too long."); } } void - testLedgerEntryDirectory() + testDirectory() { testcase("Directory"); using namespace test::jtx; @@ -1190,7 +1165,7 @@ class LedgerEntry_test : public beast::unit_test::suite } env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Exercise ledger_closed along the way. Json::Value const jrr = env.rpc("ledger_closed")[jss::result]; @@ -1198,15 +1173,13 @@ class LedgerEntry_test : public beast::unit_test::suite BEAST_EXPECT(jrr[jss::ledger_index] == 5); } - std::string const dirRootIndex = - "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D"; + std::string const dirRootIndex = "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D"; { // Locate directory by index. Json::Value jvParams; jvParams[jss::directory] = dirRootIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 32); } { @@ -1214,8 +1187,7 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::directory] = Json::objectValue; jvParams[jss::directory][jss::dir_root] = dirRootIndex; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::index] == dirRootIndex); } { @@ -1224,8 +1196,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory] = Json::objectValue; jvParams[jss::directory][jss::owner] = alice.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::index] == dirRootIndex); } { @@ -1234,8 +1205,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory] = Json::objectValue; jvParams[jss::directory][jss::dir_root] = dirRootIndex; jvParams[jss::directory][jss::sub_index] = 1; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::index] != dirRootIndex); BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2); } @@ -1246,8 +1216,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory][jss::owner] = alice.human(); jvParams[jss::directory][jss::sub_index] = 1; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::index] != dirRootIndex); BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2); } @@ -1255,12 +1224,7 @@ class LedgerEntry_test : public beast::unit_test::suite // Bad directory argument. Json::Value jvParams; jvParams[jss::ledger_hash] = ledgerHash; - testMalformedField( - env, - jvParams, - jss::directory, - FieldType::HashOrObjectField, - "malformedRequest"); + testMalformedField(env, jvParams, jss::directory, FieldType::HashOrObjectField, "malformedRequest"); } { // Non-integer sub_index. @@ -1269,13 +1233,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory][jss::dir_root] = dirRootIndex; jvParams[jss::ledger_hash] = ledgerHash; testMalformedSubfield( - env, - jvParams, - jss::directory, - jss::sub_index, - FieldType::UInt64Field, - "malformedRequest", - false); + env, jvParams, jss::directory, jss::sub_index, FieldType::UInt64Field, "malformedRequest", false); } { // Malformed owner entry. @@ -1284,13 +1242,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ledger_hash] = ledgerHash; testMalformedSubfield( - env, - jvParams, - jss::directory, - jss::owner, - FieldType::AccountField, - "malformedAddress", - false); + env, jvParams, jss::directory, jss::owner, FieldType::AccountField, "malformedAddress", false); } { // Malformed directory object. Specifies both dir_root and owner. @@ -1299,12 +1251,8 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory][jss::owner] = alice.human(); jvParams[jss::directory][jss::dir_root] = dirRootIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, - "malformedRequest", - "Must have exactly one of `owner` and `dir_root` fields."); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", "Must have exactly one of `owner` and `dir_root` fields."); } { // Incomplete directory object. Missing both dir_root and owner. @@ -1312,17 +1260,13 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::directory] = Json::objectValue; jvParams[jss::directory][jss::sub_index] = 1; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, - "malformedRequest", - "Must have exactly one of `owner` and `dir_root` fields."); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", "Must have exactly one of `owner` and `dir_root` fields."); } } void - testLedgerEntryEscrow() + testEscrow() { testcase("Escrow"); using namespace test::jtx; @@ -1341,8 +1285,7 @@ class LedgerEntry_test : public beast::unit_test::suite jv[jss::Account] = account.human(); jv[jss::Destination] = to.human(); jv[jss::Amount] = amount.getJson(JsonOptions::none); - jv[sfFinishAfter.jsonName] = - cancelAfter.time_since_epoch().count() + 2; + jv[sfFinishAfter.jsonName] = cancelAfter.time_since_epoch().count() + 2; return jv; }; @@ -1350,7 +1293,7 @@ class LedgerEntry_test : public beast::unit_test::suite env(escrowCreate(alice, alice, XRP(333), env.now() + 2s)); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; std::string escrowIndex; { // Request the escrow using owner and sequence. @@ -1358,10 +1301,8 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::escrow] = Json::objectValue; jvParams[jss::escrow][jss::owner] = alice.human(); jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][jss::Amount] == XRP(333).value().getText()); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][jss::Amount] == XRP(333).value().getText()); escrowIndex = jrr[jss::index].asString(); } { @@ -1369,22 +1310,168 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::escrow] = escrowIndex; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][jss::Amount] == XRP(333).value().getText()); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][jss::Amount] == XRP(333).value().getText()); } { // Malformed escrow fields - runLedgerEntryTest( - env, - jss::escrow, - {{jss::owner, "malformedOwner"}, {jss::seq, "malformedSeq"}}); + runLedgerEntryTest(env, jss::escrow, {{jss::owner, "malformedOwner"}, {jss::seq, "malformedSeq"}}); } } void - testLedgerEntryOffer() + testFeeSettings() + { + testcase("Fee Settings"); + using namespace test::jtx; + Env env{*this}; + + // positive test + { + Keylet const keylet = keylet::fees(); + Json::Value jvParams; + jvParams[jss::fee] = to_string(keylet.key); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::FeeSettings); + } + + // negative tests + testMalformedField(env, Json::Value{}, jss::fee, FieldType::FixedHashField, "malformedRequest"); + } + + void + testLedgerHashes() + { + testcase("Ledger Hashes"); + using namespace test::jtx; + Env env{*this}; + + // positive test + { + Keylet const keylet = keylet::skip(); + Json::Value jvParams; + jvParams[jss::hashes] = to_string(keylet.key); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::LedgerHashes); + } + + // negative tests + testMalformedField(env, Json::Value{}, jss::hashes, FieldType::FixedHashField, "malformedRequest"); + } + + void + testNFTokenOffer() + { + testcase("NFT Offer"); + using namespace test::jtx; + Env env{*this}; + + // positive test + Account const issuer{"issuer"}; + Account const buyer{"buyer"}; + env.fund(XRP(1000), issuer, buyer); + + uint256 const nftokenID0 = token::getNextID(env, issuer, 0, tfTransferable); + env(token::mint(issuer, 0), txflags(tfTransferable)); + env.close(); + uint256 const offerID = keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftokenID0, drops(1)), token::destination(buyer), txflags(tfSellNFToken)); + + { + Json::Value jvParams; + jvParams[jss::nft_offer] = to_string(offerID); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NFTokenOffer); + BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == issuer.human()); + BEAST_EXPECT(jrr[jss::node][sfNFTokenID.jsonName] == to_string(nftokenID0)); + BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] == "1"); + } + + // negative tests + runLedgerEntryTest(env, jss::nft_offer); + } + + void + testNFTokenPage() + { + testcase("NFT Page"); + using namespace test::jtx; + Env env{*this}; + + // positive test + Account const issuer{"issuer"}; + env.fund(XRP(1000), issuer); + + env(token::mint(issuer, 0), txflags(tfTransferable)); + env.close(); + + auto const nftpage = keylet::nftpage_max(issuer); + BEAST_EXPECT(env.le(nftpage) != nullptr); + + { + Json::Value jvParams; + jvParams[jss::nft_page] = to_string(nftpage.key); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NFTokenPage); + } + + // negative tests + runLedgerEntryTest(env, jss::nft_page); + } + + void + testNegativeUNL() + { + testcase("Negative UNL"); + using namespace test::jtx; + Env env{*this}; + + // positive test + { + Keylet const keylet = keylet::negativeUNL(); + + // easier to hack an object into the ledger than generate it + // legitimately + { + auto const nUNL = [&](OpenView& view, beast::Journal) -> bool { + auto const sle = std::make_shared(keylet); + + // Create DisabledValidators array + STArray disabledValidators; + auto disabledValidator = STObject::makeInnerObject(sfDisabledValidator); + auto pubKeyBlob = strUnHex( + "ED58F6770DB5DD77E59D28CB650EC3816E2FC95021BB56E720C9A1" + "2DA79C58A3AB"); + disabledValidator.setFieldVL(sfPublicKey, *pubKeyBlob); + disabledValidator.setFieldU32(sfFirstLedgerSequence, 91371264); + disabledValidators.push_back(std::move(disabledValidator)); + + sle->setFieldArray(sfDisabledValidators, disabledValidators); + sle->setFieldH256( + sfPreviousTxnID, + uint256::fromVoid("8D47FFE664BE6C335108DF689537625855A6" + "A95160CC6D351341B9" + "2624D9C5E3")); + sle->setFieldU32(sfPreviousTxnLgrSeq, 91442944); + + view.rawInsert(sle); + return true; + }; + env.app().openLedger().modify(nUNL); + } + + Json::Value jvParams; + jvParams[jss::nunl] = to_string(keylet.key); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NegativeUNL); + } + + // negative tests + testMalformedField(env, Json::Value{}, jss::nunl, FieldType::FixedHashField, "malformedRequest"); + } + + void + testOffer() { testcase("Offer"); using namespace test::jtx; @@ -1398,7 +1485,7 @@ class LedgerEntry_test : public beast::unit_test::suite env(offer(alice, USD(321), XRP(322))); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; std::string offerIndex; { // Request the offer using owner and sequence. @@ -1407,8 +1494,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::offer][jss::account] = alice.human(); jvParams[jss::offer][jss::seq] = env.seq(alice) - 1; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000"); offerIndex = jrr[jss::index].asString(); } @@ -1416,23 +1502,18 @@ class LedgerEntry_test : public beast::unit_test::suite // Request the offer using its index. Json::Value jvParams; jvParams[jss::offer] = offerIndex; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000"); } { // Malformed offer fields - runLedgerEntryTest( - env, - jss::offer, - {{jss::account, "malformedAddress"}, - {jss::seq, "malformedRequest"}}); + runLedgerEntryTest(env, jss::offer, {{jss::account, "malformedAddress"}, {jss::seq, "malformedRequest"}}); } } void - testLedgerEntryPayChan() + testPayChan() { testcase("Pay Chan"); using namespace test::jtx; @@ -1462,17 +1543,15 @@ class LedgerEntry_test : public beast::unit_test::suite env(payChanCreate(alice, env.master, XRP(57), 18s, alice.pk())); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; - uint256 const payChanIndex{ - keylet::payChan(alice, env.master, env.seq(alice) - 1).key}; + uint256 const payChanIndex{keylet::payChan(alice, env.master, env.seq(alice) - 1).key}; { // Request the payment channel using its index. Json::Value jvParams; jvParams[jss::payment_channel] = to_string(payChanIndex); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] == "57000000"); BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "0"); BEAST_EXPECT(jrr[jss::node][sfSettleDelay.jsonName] == 18); @@ -1482,8 +1561,7 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::payment_channel] = ledgerHash; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } @@ -1494,7 +1572,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryRippleState() + testRippleState() { testcase("RippleState"); using namespace test::jtx; @@ -1514,7 +1592,7 @@ class LedgerEntry_test : public beast::unit_test::suite // check both aliases for (auto const& fieldName : {jss::ripple_state, jss::state}) { - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Request the trust line using the accounts and currency. Json::Value jvParams; @@ -1524,12 +1602,9 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][1u] = gw.human(); jvParams[fieldName][jss::currency] = "USD"; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); + BEAST_EXPECT(jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); } { // test basic malformed scenarios @@ -1549,8 +1624,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][0u] = alice.human(); jvParams[fieldName][jss::currency] = "USD"; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue( jrr, "malformedRequest", @@ -1567,8 +1641,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][2u] = alice.human(); jvParams[fieldName][jss::currency] = "USD"; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue( jrr, "malformedRequest", @@ -1587,15 +1660,9 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][1u] = gw.human(); jvParams[fieldName][jss::currency] = "USD"; - Json::Value const jrr = env.rpc( - "json", - "ledger_entry", - to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue( - jrr, - "malformedAddress", - RPC::expected_field_message( - jss::accounts, "array of Accounts")); + jrr, "malformedAddress", RPC::expected_field_message(jss::accounts, "array of Accounts")); } { @@ -1605,15 +1672,9 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][1u] = badAccount; jvParams[fieldName][jss::currency] = "USD"; - Json::Value const jrr = env.rpc( - "json", - "ledger_entry", - to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue( - jrr, - "malformedAddress", - RPC::expected_field_message( - jss::accounts, "array of Accounts")); + jrr, "malformedAddress", RPC::expected_field_message(jss::accounts, "array of Accounts")); } }; @@ -1633,18 +1694,23 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[fieldName][jss::accounts][1u] = alice.human(); jvParams[fieldName][jss::currency] = "USD"; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, - "malformedRequest", - "Cannot have a trustline to self."); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", "Cannot have a trustline to self."); } } } void - testLedgerEntryTicket() + testSignerList() + { + testcase("Signer List"); + using namespace test::jtx; + Env env{*this}; + runLedgerEntryTest(env, jss::signer_list); + } + + void + testTicket() { testcase("Ticket"); using namespace test::jtx; @@ -1656,18 +1722,16 @@ class LedgerEntry_test : public beast::unit_test::suite env(ticket::create(env.master, 2)); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; // Request four tickets: one before the first one we created, the // two created tickets, and the ticket that would come after the // last created ticket. { // Not a valid ticket requested by index. Json::Value jvParams; - jvParams[jss::ticket] = - to_string(getTicketIndex(env.master, tkt1 - 1)); + jvParams[jss::ticket] = to_string(getTicketIndex(env.master, tkt1 - 1)); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } { @@ -1675,10 +1739,8 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ticket] = to_string(getTicketIndex(env.master, tkt1)); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket); BEAST_EXPECT(jrr[jss::node][sfTicketSequence.jsonName] == tkt1); } { @@ -1688,11 +1750,8 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ticket][jss::account] = env.master.human(); jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][jss::index] == - to_string(getTicketIndex(env.master, tkt1 + 1))); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][jss::index] == to_string(getTicketIndex(env.master, tkt1 + 1))); } { // Not a valid ticket requested by account and sequence. @@ -1701,8 +1760,7 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::ticket][jss::account] = env.master.human(); jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } { @@ -1710,10 +1768,8 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ticket] = to_string(keylet::account(env.master).key); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, "unexpectedLedgerType", "Unexpected ledger type."); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "unexpectedLedgerType", "Unexpected ledger type."); } { @@ -1729,7 +1785,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryDID() + testDID() { testcase("DID"); using namespace test::jtx; @@ -1753,39 +1809,29 @@ class LedgerEntry_test : public beast::unit_test::suite env(didCreate(alice)); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Request the DID using its index. Json::Value jvParams; jvParams[jss::did] = alice.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfDIDDocument.jsonName] == - strHex(std::string{"data"})); - BEAST_EXPECT( - jrr[jss::node][sfURI.jsonName] == strHex(std::string{"uri"})); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfDIDDocument.jsonName] == strHex(std::string{"data"})); + BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(std::string{"uri"})); } { // Request an index that is not a DID. Json::Value jvParams; jvParams[jss::did] = env.master.human(); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } { // Malformed DID index Json::Value jvParams; - testMalformedField( - env, - jvParams, - jss::did, - FieldType::AccountField, - "malformedAddress"); + testMalformedField(env, jvParams, jss::did, FieldType::AccountField, "malformedAddress"); } } @@ -1793,16 +1839,13 @@ class LedgerEntry_test : public beast::unit_test::suite testInvalidOracleLedgerEntry() { testcase("Invalid Oracle Ledger Entry"); - using namespace ripple::test::jtx; - using namespace ripple::test::jtx::oracle; + using namespace xrpl::test::jtx; + using namespace xrpl::test::jtx::oracle; Env env(*this); Account const owner("owner"); env.fund(XRP(1'000), owner); - Oracle oracle( - env, - {.owner = owner, - .fee = static_cast(env.current()->fees().base.drops())}); + Oracle oracle(env, {.owner = owner, .fee = static_cast(env.current()->fees().base.drops())}); { // test basic malformed scenarios @@ -1820,12 +1863,11 @@ class LedgerEntry_test : public beast::unit_test::suite testOracleLedgerEntry() { testcase("Oracle Ledger Entry"); - using namespace ripple::test::jtx; - using namespace ripple::test::jtx::oracle; + using namespace xrpl::test::jtx; + using namespace xrpl::test::jtx::oracle; Env env(*this); - auto const baseFee = - static_cast(env.current()->fees().base.drops()); + auto const baseFee = static_cast(env.current()->fees().base.drops()); std::vector accounts; std::vector oracles; for (int i = 0; i < 10; ++i) @@ -1833,13 +1875,11 @@ class LedgerEntry_test : public beast::unit_test::suite Account const owner(std::string("owner") + std::to_string(i)); env.fund(XRP(1'000), owner); // different accounts can have the same asset pair - Oracle oracle( - env, {.owner = owner, .documentID = i, .fee = baseFee}); + Oracle oracle(env, {.owner = owner, .documentID = i, .fee = baseFee}); accounts.push_back(owner.id()); oracles.push_back(oracle.documentID()); // same account can have different asset pair - Oracle oracle1( - env, {.owner = owner, .documentID = i + 10, .fee = baseFee}); + Oracle oracle1(env, {.owner = owner, .documentID = i + 10, .fee = baseFee}); accounts.push_back(owner.id()); oracles.push_back(oracle1.documentID()); } @@ -1850,13 +1890,11 @@ class LedgerEntry_test : public beast::unit_test::suite if (i % 2) return Oracle::ledgerEntry(env, accounts[i], oracles[i]); // document id is string - return Oracle::ledgerEntry( - env, accounts[i], std::to_string(oracles[i])); + return Oracle::ledgerEntry(env, accounts[i], std::to_string(oracles[i])); }(); try { - BEAST_EXPECT( - jv[jss::node][jss::Owner] == to_string(accounts[i])); + BEAST_EXPECT(jv[jss::node][jss::Owner] == to_string(accounts[i])); } catch (...) { @@ -1866,7 +1904,7 @@ class LedgerEntry_test : public beast::unit_test::suite } void - testLedgerEntryMPT() + testMPT() { testcase("MPT"); using namespace test::jtx; @@ -1880,35 +1918,28 @@ class LedgerEntry_test : public beast::unit_test::suite {.transferFee = 10, .metadata = "123", .ownerCount = 1, - .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | - tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback}); + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | + tfMPTCanClawback}); mptAlice.authorize({.account = bob, .holderCount = 1}); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; - std::string const badMptID = - "00000193B9DDCAF401B5B3B26875986043F82CD0D13B4315"; + std::string const badMptID = "00000193B9DDCAF401B5B3B26875986043F82CD0D13B4315"; { // Request the MPTIssuance using its MPTIssuanceID. Json::Value jvParams; jvParams[jss::mpt_issuance] = strHex(mptAlice.issuanceID()); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfMPTokenMetadata.jsonName] == - strHex(std::string{"123"})); - BEAST_EXPECT( - jrr[jss::node][jss::mpt_issuance_id] == - strHex(mptAlice.issuanceID())); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfMPTokenMetadata.jsonName] == strHex(std::string{"123"})); + BEAST_EXPECT(jrr[jss::node][jss::mpt_issuance_id] == strHex(mptAlice.issuanceID())); } { // Request an index that is not a MPTIssuance. Json::Value jvParams; jvParams[jss::mpt_issuance] = badMptID; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } { @@ -1916,14 +1947,10 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::mptoken] = Json::objectValue; jvParams[jss::mptoken][jss::account] = bob.human(); - jvParams[jss::mptoken][jss::mpt_issuance_id] = - strHex(mptAlice.issuanceID()); + jvParams[jss::mptoken][jss::mpt_issuance_id] = strHex(mptAlice.issuanceID()); jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfMPTokenIssuanceID.jsonName] == - strHex(mptAlice.issuanceID())); + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfMPTokenIssuanceID.jsonName] == strHex(mptAlice.issuanceID())); } { // Request the MPToken using a bad mptIssuanceID. @@ -1932,24 +1959,18 @@ class LedgerEntry_test : public beast::unit_test::suite jvParams[jss::mptoken][jss::account] = bob.human(); jvParams[jss::mptoken][jss::mpt_issuance_id] = badMptID; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } { // Malformed MPTIssuance index Json::Value jvParams; - testMalformedField( - env, - jvParams, - jss::mptoken, - FieldType::HashOrObjectField, - "malformedRequest"); + testMalformedField(env, jvParams, jss::mptoken, FieldType::HashOrObjectField, "malformedRequest"); } } void - testLedgerEntryPermissionedDomain() + testPermissionedDomain() { testcase("PermissionedDomain"); @@ -1978,30 +1999,23 @@ class LedgerEntry_test : public beast::unit_test::suite params[jss::permissioned_domain][jss::seq] = seq; auto jv = env.rpc("json", "ledger_entry", to_string(params)); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - !jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && jv[jss::result].isMember(jss::node) && - jv[jss::result][jss::node].isMember( - sfLedgerEntryType.jsonName) && - jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == - jss::PermissionedDomain); + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::PermissionedDomain); std::string const pdIdx = jv[jss::result][jss::index].asString(); - BEAST_EXPECT( - strHex(keylet::permissionedDomain(alice, seq).key) == pdIdx); + BEAST_EXPECT(strHex(keylet::permissionedDomain(alice, seq).key) == pdIdx); params.clear(); params[jss::ledger_index] = jss::validated; params[jss::permissioned_domain] = pdIdx; jv = env.rpc("json", "ledger_entry", to_string(params)); BEAST_EXPECT( - jv.isObject() && jv.isMember(jss::result) && - !jv[jss::result].isMember(jss::error) && + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && jv[jss::result].isMember(jss::node) && - jv[jss::result][jss::node].isMember( - sfLedgerEntryType.jsonName) && - jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == - jss::PermissionedDomain); + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::PermissionedDomain); } { @@ -2012,8 +2026,7 @@ class LedgerEntry_test : public beast::unit_test::suite "12F1F1F1F180D67377B2FAB292A31C922470326268D2B9B74CD1E582645B9A" "DE"; auto const jrr = env.rpc("json", "ledger_entry", to_string(params)); - checkErrorValue( - jrr[jss::result], "entryNotFound", "Entry not found."); + checkErrorValue(jrr[jss::result], "entryNotFound", "Entry not found."); } { // test basic malformed scenarios @@ -2027,8 +2040,398 @@ class LedgerEntry_test : public beast::unit_test::suite } } + /// Test the ledger entry types that don't take parameters void - testLedgerEntryCLI() + testFixed() + { + using namespace test::jtx; + + Account const alice{"alice"}; + Account const bob{"bob"}; + + Env env{*this, envconfig([](auto cfg) { + cfg->START_UP = StartUpType::FRESH; + return cfg; + })}; + + env.close(); + + /** Verifies that the RPC result has the expected data + * + * @param good: Indicates that the request should have succeeded + * and returned a ledger object of `expectedType` type. + * @param jv: The RPC result Json value + * @param expectedType: The type that the ledger object should + * have if "good". + * @param expectedError: Optional. The expected error if not + * good. Defaults to "entryNotFound". + */ + auto checkResult = [&](bool good, + Json::Value const& jv, + Json::StaticString const& expectedType, + std::optional const& expectedError = {}) { + if (good) + { + BEAST_EXPECTS( + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && + jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == expectedType, + to_string(jv)); + } + else + { + BEAST_EXPECTS( + jv.isObject() && jv.isMember(jss::result) && jv[jss::result].isMember(jss::error) && + !jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::error] == expectedError.value_or("entryNotFound"), + to_string(jv)); + } + }; + + /** Runs a series of tests for a given fixed-position ledger + * entry. + * + * @param field: The Json request field to use. + * @param expectedType: The type that the ledger object should + * have if "good". + * @param expectedKey: The keylet of the fixed object. + * @param good: Indicates whether the object is expected to + * exist. + */ + auto test = [&](Json::StaticString const& field, + Json::StaticString const& expectedType, + Keylet const& expectedKey, + bool good) { + testcase << expectedType.c_str() << (good ? "" : " not") << " found"; + + auto const hexKey = strHex(expectedKey.key); + + { + // Test bad values + // "field":null + Json::Value params; + params[jss::ledger_index] = jss::validated; + params[field] = Json::nullValue; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "field":"string" + params[jss::ledger_index] = jss::validated; + params[field] = "arbitrary string"; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "field":false + params[jss::ledger_index] = jss::validated; + params[field] = false; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "invalidParams"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + + // "field":[incorrect index hash] + auto const badKey = strHex(expectedKey.key + uint256{1}); + params[jss::ledger_index] = jss::validated; + params[field] = badKey; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "entryNotFound"); + BEAST_EXPECTS(jv[jss::result][jss::index] == badKey, to_string(jv)); + } + + { + Json::Value params; + // "index":"field" using API 2 + params[jss::ledger_index] = jss::validated; + params[jss::index] = field; + params[jss::api_version] = 2; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + std::string const pdIdx = [&]() { + { + Json::Value params; + // Test good values + // Use the "field":true notation + params[jss::ledger_index] = jss::validated; + params[field] = true; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + // Index will always be returned for valid parameters. + std::string const pdIdx = jv[jss::result][jss::index].asString(); + BEAST_EXPECTS(hexKey == pdIdx, to_string(jv)); + checkResult(good, jv, expectedType); + + return pdIdx; + } + }(); + + { + Json::Value params; + // "field":"[index hash]" + params[jss::ledger_index] = jss::validated; + params[field] = hexKey; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(good, jv, expectedType); + BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey); + } + + { + // Bad value + // Use the "index":"field" notation with API 2 + Json::Value params; + params[jss::ledger_index] = jss::validated; + params[jss::index] = field; + params[jss::api_version] = 2; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, expectedType, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // Use the "index":"field" notation with API 3 + params[jss::ledger_index] = jss::validated; + params[jss::index] = field; + params[jss::api_version] = 3; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + // Index is correct either way + BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey); + checkResult(good, jv, expectedType); + } + + { + Json::Value params; + // Use the "index":"[index hash]" notation + params[jss::ledger_index] = jss::validated; + params[jss::index] = pdIdx; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + // Index is correct either way + BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey); + checkResult(good, jv, expectedType); + } + }; + + test(jss::amendments, jss::Amendments, keylet::amendments(), true); + test(jss::fee, jss::FeeSettings, keylet::fees(), true); + // There won't be an nunl + test(jss::nunl, jss::NegativeUNL, keylet::negativeUNL(), false); + // Can only get the short skip list this way + test(jss::hashes, jss::LedgerHashes, keylet::skip(), true); + } + + void + testHashes() + { + using namespace test::jtx; + + Account const alice{"alice"}; + Account const bob{"bob"}; + + Env env{*this, envconfig([](auto cfg) { + cfg->START_UP = StartUpType::FRESH; + return cfg; + })}; + + env.close(); + + /** Verifies that the RPC result has the expected data + * + * @param good: Indicates that the request should have succeeded + * and returned a ledger object of `expectedType` type. + * @param jv: The RPC result Json value + * @param expectedCount: The number of Hashes expected in the + * object if "good". + * @param expectedError: Optional. The expected error if not + * good. Defaults to "entryNotFound". + */ + auto checkResult = [&](bool good, + Json::Value const& jv, + int expectedCount, + std::optional const& expectedError = {}) { + if (good) + { + BEAST_EXPECTS( + jv.isObject() && jv.isMember(jss::result) && !jv[jss::result].isMember(jss::error) && + jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::LedgerHashes, + to_string(jv)); + BEAST_EXPECTS( + jv[jss::result].isMember(jss::node) && jv[jss::result][jss::node].isMember("Hashes") && + jv[jss::result][jss::node]["Hashes"].size() == expectedCount, + to_string(jv[jss::result][jss::node]["Hashes"].size())); + } + else + { + BEAST_EXPECTS( + jv.isObject() && jv.isMember(jss::result) && jv[jss::result].isMember(jss::error) && + !jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::error] == expectedError.value_or("entryNotFound"), + to_string(jv)); + } + }; + + /** Runs a series of tests for a given ledger index. + * + * @param ledger: The ledger index value of the "hashes" request + * parameter. May not necessarily be a number. + * @param expectedKey: The expected keylet of the object. + * @param good: Indicates whether the object is expected to + * exist. + * @param expectedCount: The number of Hashes expected in the + * object if "good". + */ + auto test = [&](Json::Value ledger, Keylet const& expectedKey, bool good, int expectedCount = 0) { + testcase << "LedgerHashes: seq: " << env.current()->header().seq << " \"hashes\":" << to_string(ledger) + << (good ? "" : " not") << " found"; + + auto const hexKey = strHex(expectedKey.key); + + { + // Test bad values + // "hashes":null + Json::Value params; + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = Json::nullValue; + auto jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "hashes":"non-uint string" + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = "arbitrary string"; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "hashes":"uint string" is invalid, too + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = "10"; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "malformedRequest"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "hashes":false + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = false; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "invalidParams"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + { + Json::Value params; + // "hashes":-1 + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = -1; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "internal"); + BEAST_EXPECT(!jv[jss::result].isMember(jss::index)); + } + + // "hashes":[incorrect index hash] + { + Json::Value params; + auto const badKey = strHex(expectedKey.key + uint256{1}); + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = badKey; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(false, jv, 0, "entryNotFound"); + BEAST_EXPECT(jv[jss::result][jss::index] == badKey); + } + + { + Json::Value params; + // Test good values + // Use the "hashes":ledger notation + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = ledger; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(good, jv, expectedCount); + // Index will always be returned for valid parameters. + std::string const pdIdx = jv[jss::result][jss::index].asString(); + BEAST_EXPECTS(hexKey == pdIdx, strHex(pdIdx)); + } + + { + Json::Value params; + // "hashes":"[index hash]" + params[jss::ledger_index] = jss::validated; + params[jss::hashes] = hexKey; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(good, jv, expectedCount); + // Index is correct either way + BEAST_EXPECTS( + hexKey == jv[jss::result][jss::index].asString(), strHex(jv[jss::result][jss::index].asString())); + } + + { + Json::Value params; + // Use the "index":"[index hash]" notation + params[jss::ledger_index] = jss::validated; + params[jss::index] = hexKey; + auto const jv = env.rpc("json", "ledger_entry", to_string(params)); + checkResult(good, jv, expectedCount); + // Index is correct either way + BEAST_EXPECTS( + hexKey == jv[jss::result][jss::index].asString(), strHex(jv[jss::result][jss::index].asString())); + } + }; + + // short skip list + test(true, keylet::skip(), true, 2); + // long skip list at index 0 + test(1, keylet::skip(1), false); + // long skip list at index 1 + test(1 << 17, keylet::skip(1 << 17), false); + + // Close more ledgers, but stop short of the flag ledger + for (auto i = env.current()->seq(); i <= 250; ++i) + env.close(); + + // short skip list + test(true, keylet::skip(), true, 249); + // long skip list at index 0 + test(1, keylet::skip(1), false); + // long skip list at index 1 + test(1 << 17, keylet::skip(1 << 17), false); + + // Close a flag ledger so the first "long" skip list is created + for (auto i = env.current()->seq(); i <= 260; ++i) + env.close(); + + // short skip list + test(true, keylet::skip(), true, 256); + // long skip list at index 0 + test(1, keylet::skip(1), true, 1); + // long skip list at index 1 + test(1 << 17, keylet::skip(1 << 17), false); + } + + void + testCLI() { testcase("command-line"); using namespace test::jtx; @@ -2043,13 +2446,11 @@ class LedgerEntry_test : public beast::unit_test::suite env(check::create(env.master, alice, XRP(100))); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; + std::string const ledgerHash{to_string(env.closed()->header().hash)}; { // Request a check. - Json::Value const jrr = - env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); + Json::Value const jrr = env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); } } @@ -2058,36 +2459,42 @@ public: void run() override { - testLedgerEntryInvalid(); - testLedgerEntryAccountRoot(); - testLedgerEntryCheck(); - testLedgerEntryCredentials(); - testLedgerEntryDelegate(); - testLedgerEntryDepositPreauth(); - testLedgerEntryDepositPreauthCred(); - testLedgerEntryDirectory(); - testLedgerEntryEscrow(); - testLedgerEntryOffer(); - testLedgerEntryPayChan(); - testLedgerEntryRippleState(); - testLedgerEntryTicket(); - testLedgerEntryDID(); + testInvalid(); + testAccountRoot(); + testAmendments(); + testAMM(); + testCheck(); + testCredentials(); + testDelegate(); + testDepositPreauth(); + testDepositPreauthCred(); + testDirectory(); + testEscrow(); + testFeeSettings(); + testLedgerHashes(); + testNFTokenOffer(); + testNFTokenPage(); + testNegativeUNL(); + testOffer(); + testPayChan(); + testRippleState(); + testSignerList(); + testTicket(); + testDID(); testInvalidOracleLedgerEntry(); testOracleLedgerEntry(); - testLedgerEntryMPT(); - testLedgerEntryPermissionedDomain(); - testLedgerEntryCLI(); + testMPT(); + testPermissionedDomain(); + testFixed(); + testHashes(); + testCLI(); } }; -class LedgerEntry_XChain_test : public beast::unit_test::suite, - public test::jtx::XChainBridgeObjects +class LedgerEntry_XChain_test : public beast::unit_test::suite, public test::jtx::XChainBridgeObjects { void - checkErrorValue( - Json::Value const& jv, - std::string const& err, - std::string const& msg) + checkErrorValue(Json::Value const& jv, std::string const& err, std::string const& msg) { if (BEAST_EXPECT(jv.isMember(jss::status))) BEAST_EXPECT(jv[jss::status] == "error"); @@ -2095,16 +2502,14 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, BEAST_EXPECT(jv[jss::error] == err); if (msg.empty()) { - BEAST_EXPECT( - jv[jss::error_message] == Json::nullValue || - jv[jss::error_message] == ""); + BEAST_EXPECT(jv[jss::error_message] == Json::nullValue || jv[jss::error_message] == ""); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) BEAST_EXPECT(jv[jss::error_message] == msg); } void - testLedgerEntryBridge() + testBridge() { testcase("ledger_entry: bridge"); using namespace test::jtx; @@ -2114,7 +2519,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, createBridgeObjects(mcEnv, scEnv); - std::string const ledgerHash{to_string(mcEnv.closed()->info().hash)}; + std::string const ledgerHash{to_string(mcEnv.closed()->header().hash)}; std::string bridge_index; Json::Value mcBridge; { @@ -2122,8 +2527,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, Json::Value jvParams; jvParams[jss::bridge_account] = mcDoor.human(); jvParams[jss::bridge] = jvb; - Json::Value const jrr = mcEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); auto r = jrr[jss::node]; @@ -2152,8 +2556,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, // request the bridge via RPC by index Json::Value jvParams; jvParams[jss::index] = bridge_index; - Json::Value const jrr = mcEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); BEAST_EXPECT(jrr[jss::node] == mcBridge); @@ -2165,8 +2568,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, jvParams[jss::bridge_account] = Account::master.human(); jvParams[jss::bridge] = jvb; jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = mcEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } @@ -2182,8 +2584,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, Json::Value jvParams; jvParams[jss::bridge_account] = mcDoor.human(); jvParams[jss::bridge] = jvb; - Json::Value const jrr = mcEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + Json::Value const jrr = mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); auto r = jrr[jss::node]; @@ -2195,7 +2596,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, } void - testLedgerEntryClaimID() + testClaimID() { testcase("ledger_entry: xchain_claim_id"); using namespace test::jtx; @@ -2215,18 +2616,15 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, // request the xchain_claim_id via RPC Json::Value jvParams; jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = - 1; - Json::Value const jrr = scEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 1; + Json::Value const jrr = scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); auto r = jrr[jss::node]; BEAST_EXPECT(r.isMember(jss::Account)); BEAST_EXPECT(r[jss::Account] == scAlice.human()); - BEAST_EXPECT( - r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); + BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 1); BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0); } @@ -2235,25 +2633,22 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, // request the xchain_claim_id via RPC Json::Value jvParams; jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = - 2; - Json::Value const jrr = scEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 2; + Json::Value const jrr = scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); auto r = jrr[jss::node]; BEAST_EXPECT(r.isMember(jss::Account)); BEAST_EXPECT(r[jss::Account] == scBob.human()); - BEAST_EXPECT( - r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); + BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2); BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0); } } void - testLedgerEntryCreateAccountClaimID() + testCreateAccountClaimID() { testcase("ledger_entry: xchain_create_account_claim_id"); using namespace test::jtx; @@ -2264,12 +2659,10 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, // note: signers.size() and quorum are both 5 in createBridgeObjects createBridgeObjects(mcEnv, scEnv); - auto scCarol = - Account("scCarol"); // Don't fund it - it will be created with the - // xchain transaction + auto scCarol = Account("scCarol"); // Don't fund it - it will be created with the + // xchain transaction auto const amt = XRP(1000); - mcEnv(sidechain_xchain_account_create( - mcAlice, jvb, scCarol, amt, reward)); + mcEnv(sidechain_xchain_account_create(mcAlice, jvb, scCarol, amt, reward)); mcEnv.close(); // send less than quorum of attestations (otherwise funds are @@ -2296,12 +2689,9 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, { // request the create account claim_id via RPC Json::Value jvParams; - jvParams[jss::xchain_owned_create_account_claim_id] = - jvXRPBridgeRPC; - jvParams[jss::xchain_owned_create_account_claim_id] - [jss::xchain_owned_create_account_claim_id] = 1; - Json::Value const jrr = scEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + jvParams[jss::xchain_owned_create_account_claim_id] = jvXRPBridgeRPC; + jvParams[jss::xchain_owned_create_account_claim_id][jss::xchain_owned_create_account_claim_id] = 1; + Json::Value const jrr = scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::node)); auto r = jrr[jss::node]; @@ -2312,47 +2702,32 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName)); BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 1); - BEAST_EXPECT( - r.isMember(sfXChainCreateAccountAttestations.jsonName)); + BEAST_EXPECT(r.isMember(sfXChainCreateAccountAttestations.jsonName)); auto attest = r[sfXChainCreateAccountAttestations.jsonName]; BEAST_EXPECT(attest.isArray()); BEAST_EXPECT(attest.size() == 3); - BEAST_EXPECT(attest[Json::Value::UInt(0)].isMember( - sfXChainCreateAccountProofSig.jsonName)); + BEAST_EXPECT(attest[Json::Value::UInt(0)].isMember(sfXChainCreateAccountProofSig.jsonName)); Json::Value a[num_attest]; for (size_t i = 0; i < num_attest; ++i) { - a[i] = attest[Json::Value::UInt(0)] - [sfXChainCreateAccountProofSig.jsonName]; - BEAST_EXPECT( - a[i].isMember(jss::Amount) && - a[i][jss::Amount].asInt() == 1000 * drop_per_xrp); - BEAST_EXPECT( - a[i].isMember(jss::Destination) && - a[i][jss::Destination] == scCarol.human()); + a[i] = attest[Json::Value::UInt(0)][sfXChainCreateAccountProofSig.jsonName]; + BEAST_EXPECT(a[i].isMember(jss::Amount) && a[i][jss::Amount].asInt() == 1000 * drop_per_xrp); + BEAST_EXPECT(a[i].isMember(jss::Destination) && a[i][jss::Destination] == scCarol.human()); BEAST_EXPECT( a[i].isMember(sfAttestationSignerAccount.jsonName) && - std::any_of( - signers.begin(), signers.end(), [&](signer const& s) { - return a[i][sfAttestationSignerAccount.jsonName] == - s.account.human(); - })); + std::any_of(signers.begin(), signers.end(), [&](signer const& s) { + return a[i][sfAttestationSignerAccount.jsonName] == s.account.human(); + })); BEAST_EXPECT( a[i].isMember(sfAttestationRewardAccount.jsonName) && - std::any_of( - payee.begin(), - payee.end(), - [&](Account const& account) { - return a[i][sfAttestationRewardAccount.jsonName] == - account.human(); - })); + std::any_of(payee.begin(), payee.end(), [&](Account const& account) { + return a[i][sfAttestationRewardAccount.jsonName] == account.human(); + })); BEAST_EXPECT( - a[i].isMember(sfWasLockingChainSend.jsonName) && - a[i][sfWasLockingChainSend.jsonName] == 1); + a[i].isMember(sfWasLockingChainSend.jsonName) && a[i][sfWasLockingChainSend.jsonName] == 1); BEAST_EXPECT( a[i].isMember(sfSignatureReward.jsonName) && - a[i][sfSignatureReward.jsonName].asInt() == - 1 * drop_per_xrp); + a[i][sfSignatureReward.jsonName].asInt() == 1 * drop_per_xrp); } } @@ -2366,12 +2741,9 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, { // request the create account claim_id via RPC Json::Value jvParams; - jvParams[jss::xchain_owned_create_account_claim_id] = - jvXRPBridgeRPC; - jvParams[jss::xchain_owned_create_account_claim_id] - [jss::xchain_owned_create_account_claim_id] = 1; - Json::Value const jrr = scEnv.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; + jvParams[jss::xchain_owned_create_account_claim_id] = jvXRPBridgeRPC; + jvParams[jss::xchain_owned_create_account_claim_id][jss::xchain_owned_create_account_claim_id] = 1; + Json::Value const jrr = scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "entryNotFound", "Entry not found."); } } @@ -2380,14 +2752,14 @@ public: void run() override { - testLedgerEntryBridge(); - testLedgerEntryClaimID(); - testLedgerEntryCreateAccountClaimID(); + testBridge(); + testClaimID(); + testCreateAccountClaimID(); } }; -BEAST_DEFINE_TESTSUITE(LedgerEntry, rpc, ripple); -BEAST_DEFINE_TESTSUITE(LedgerEntry_XChain, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerEntry, rpc, xrpl); +BEAST_DEFINE_TESTSUITE(LedgerEntry_XChain, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerHeader_test.cpp b/src/test/rpc/LedgerHeader_test.cpp index a80f706b6f..8b460fe6a4 100644 --- a/src/test/rpc/LedgerHeader_test.cpp +++ b/src/test/rpc/LedgerHeader_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class LedgerHeader_test : public beast::unit_test::suite { @@ -36,8 +17,7 @@ class LedgerHeader_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::api_version] = 1; params[jss::ledger_index] = "current"; - auto const result = - env.client().invoke("ledger_header", params)[jss::result]; + auto const result = env.client().invoke("ledger_header", params)[jss::result]; BEAST_EXPECT(result[jss::status] == "success"); BEAST_EXPECT(result.isMember("ledger")); BEAST_EXPECT(result[jss::ledger][jss::closed] == false); @@ -54,8 +34,7 @@ class LedgerHeader_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::api_version] = 1; params[jss::ledger_index] = "validated"; - auto const result = - env.client().invoke("ledger_header", params)[jss::result]; + auto const result = env.client().invoke("ledger_header", params)[jss::result]; BEAST_EXPECT(result[jss::status] == "success"); BEAST_EXPECT(result.isMember("ledger")); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); @@ -71,8 +50,7 @@ class LedgerHeader_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::api_version] = 2; - auto const result = - env.client().invoke("ledger_header", params)[jss::result]; + auto const result = env.client().invoke("ledger_header", params)[jss::result]; BEAST_EXPECT(result[jss::error] == "unknownCmd"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -87,6 +65,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerHeader, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerHeader, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 6e132857ae..a656db558c 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,17 +12,14 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class LedgerRPC_test : public beast::unit_test::suite { void - checkErrorValue( - Json::Value const& jv, - std::string const& err, - std::string const& msg) + checkErrorValue(Json::Value const& jv, std::string const& err, std::string const& msg) { if (BEAST_EXPECT(jv.isMember(jss::status))) BEAST_EXPECT(jv[jss::status] == "error"); @@ -49,12 +27,12 @@ class LedgerRPC_test : public beast::unit_test::suite BEAST_EXPECT(jv[jss::error] == err); if (msg.empty()) { - BEAST_EXPECT( - jv[jss::error_message] == Json::nullValue || - jv[jss::error_message] == ""); + BEAST_EXPECT(jv[jss::error_message] == Json::nullValue || jv[jss::error_message] == ""); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) - BEAST_EXPECT(jv[jss::error_message] == msg); + BEAST_EXPECTS( + jv[jss::error_message] == msg, + "Expected error message \"" + msg + "\", received \"" + jv[jss::error_message].asString() + "\""); } // Corrupt a valid address by replacing the 10th character with '!'. @@ -76,14 +54,13 @@ class LedgerRPC_test : public beast::unit_test::suite Env env{*this}; env.close(); - BEAST_EXPECT(env.current()->info().seq == 4); + BEAST_EXPECT(env.current()->header().seq == 4); { Json::Value jvParams; // can be either numeric or quoted numeric jvParams[jss::ledger_index] = 1; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true); BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1"); } @@ -91,8 +68,7 @@ class LedgerRPC_test : public beast::unit_test::suite { Json::Value jvParams; jvParams[jss::ledger_index] = "1"; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true); BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1"); } @@ -101,11 +77,8 @@ class LedgerRPC_test : public beast::unit_test::suite // using current identifier auto const jrr = env.rpc("ledger", "current")[jss::result]; BEAST_EXPECT(jrr[jss::ledger][jss::closed] == false); - BEAST_EXPECT( - jrr[jss::ledger][jss::ledger_index] == - std::to_string(env.current()->info().seq)); - BEAST_EXPECT( - jrr[jss::ledger_current_index] == env.current()->info().seq); + BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == std::to_string(env.current()->header().seq)); + BEAST_EXPECT(jrr[jss::ledger_current_index] == env.current()->header().seq); } } @@ -128,26 +101,23 @@ class LedgerRPC_test : public beast::unit_test::suite // ask for an arbitrary string - index Json::Value jvParams; jvParams[jss::ledger_index] = "potato"; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed"); + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "invalidParams", "Invalid field 'ledger_index', not string or number."); } { // ask for a negative index Json::Value jvParams; jvParams[jss::ledger_index] = -1; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed"); + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "invalidParams", "Invalid field 'ledger_index', not string or number."); } { // ask for a bad ledger index Json::Value jvParams; jvParams[jss::ledger_index] = 10u; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound"); } @@ -162,23 +132,20 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = "validated"; jvParams[jss::queue] = true; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; checkErrorValue(jrr, "invalidParams", "Invalid parameters."); } { // Request a ledger with a very large (double) sequence. - auto const ret = - env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }"); + auto const ret = env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }"); BEAST_EXPECT(RPC::contains_error(ret)); BEAST_EXPECT(ret[jss::error_message] == "Invalid parameters."); } { // Request a ledger with very large (integer) sequence. - auto const ret = env.rpc( - "json", "ledger", "{ \"ledger_index\" : 1000000000000000 }"); + auto const ret = env.rpc("json", "ledger", "{ \"ledger_index\" : 1000000000000000 }"); checkErrorValue(ret, "invalidParams", "Invalid parameters."); } } @@ -192,12 +159,11 @@ class LedgerRPC_test : public beast::unit_test::suite Env env{*this}; env.close(); - BEAST_EXPECT(env.current()->info().seq == 4); + BEAST_EXPECT(env.current()->header().seq == 4); { auto const jrr = env.rpc("ledger_current")[jss::result]; - BEAST_EXPECT( - jrr[jss::ledger_current_index] == env.current()->info().seq); + BEAST_EXPECT(jrr[jss::ledger_current_index] == env.current()->header().seq); } } @@ -214,8 +180,7 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = 3u; jvParams[jss::full] = true; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u); @@ -234,10 +199,8 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = 1u; jvParams[jss::full] = true; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; - checkErrorValue( - jrr, "noPermission", "You don't have permission for this command."); + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "noPermission", "You don't have permission for this command."); } void @@ -253,8 +216,7 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = 3u; jvParams[jss::accounts] = true; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u); @@ -272,9 +234,8 @@ class LedgerRPC_test : public beast::unit_test::suite auto cfg = envconfig(); cfg->FEES.reference_fee = 10; - Env env{ - *this, std::move(cfg), FeatureBitset{}}; // hashes requested below - // assume no amendments + Env env{*this, std::move(cfg), FeatureBitset{}}; // hashes requested below + // assume no amendments env.fund(XRP(10000), "alice"); env.close(); env.fund(XRP(10000), "bob"); @@ -287,8 +248,7 @@ class LedgerRPC_test : public beast::unit_test::suite // access via the legacy ledger field, keyword index values Json::Value jvParams; jvParams[jss::ledger] = "closed"; - auto jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::ledger)); BEAST_EXPECT(jrr.isMember(jss::ledger_hash)); BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5"); @@ -308,7 +268,7 @@ class LedgerRPC_test : public beast::unit_test::suite jvParams[jss::ledger] = "invalid"; jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ledger', not string or number."); // numeric index jvParams[jss::ledger] = 4; @@ -326,13 +286,12 @@ class LedgerRPC_test : public beast::unit_test::suite { std::string const hash3{ - "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D" - "8F643B9552F0D895A31CDA78F541DE4E"}; + "0F1A9E0C109ADEF6DA2BDE19217C12BBEC57174CBDBD212B0EBDC1CEDB8531" + "85"}; // access via the ledger_hash field Json::Value jvParams; jvParams[jss::ledger_hash] = hash3; - auto jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::ledger)); BEAST_EXPECT(jrr.isMember(jss::ledger_hash)); BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3"); @@ -341,13 +300,13 @@ class LedgerRPC_test : public beast::unit_test::suite jvParams[jss::ledger_hash] = "DEADBEEF" + hash3; jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ledger_hash', not hex string."); // request with non-string ledger_hash jvParams[jss::ledger_hash] = 2; jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ledger_hash', not hex string."); // malformed (non hex) hash jvParams[jss::ledger_hash] = @@ -355,7 +314,7 @@ class LedgerRPC_test : public beast::unit_test::suite "7F2775F2F7485BB37307984C3C0F2340"; jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ledger_hash', not hex string."); // properly formed, but just doesn't exist jvParams[jss::ledger_hash] = @@ -370,8 +329,7 @@ class LedgerRPC_test : public beast::unit_test::suite // access via the ledger_index field, keyword index values Json::Value jvParams; jvParams[jss::ledger_index] = "closed"; - auto jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::ledger)); BEAST_EXPECT(jrr.isMember(jss::ledger_hash)); BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5"); @@ -393,19 +351,17 @@ class LedgerRPC_test : public beast::unit_test::suite jvParams[jss::ledger_index] = "invalid"; jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ledger_index', not string or number."); // numeric index for (auto i : {1, 2, 3, 4, 5, 6}) { jvParams[jss::ledger_index] = i; - jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr.isMember(jss::ledger)); if (i < 6) BEAST_EXPECT(jrr.isMember(jss::ledger_hash)); - BEAST_EXPECT( - jrr[jss::ledger][jss::ledger_index] == std::to_string(i)); + BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == std::to_string(i)); } // numeric index - out of range @@ -475,16 +431,12 @@ class LedgerRPC_test : public beast::unit_test::suite env(noop(alice)); } - BEAST_EXPECT(env.current()->info().seq == 5); + BEAST_EXPECT(env.current()->header().seq == 5); // Put some txs in the queue // Alice auto aliceSeq = env.seq(alice); - env(pay(alice, "george", XRP(1000)), - last_ledger_seq(7), - ter(terQUEUED)); - env(offer(alice, XRP(50000), alice["USD"](5000)), - seq(aliceSeq + 1), - ter(terQUEUED)); + env(pay(alice, "george", XRP(1000)), last_ledger_seq(7), ter(terQUEUED)); + env(offer(alice, XRP(50000), alice["USD"](5000)), seq(aliceSeq + 1), ter(terQUEUED)); env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED)); // Bob auto batch = [&env](Account a) { @@ -508,7 +460,7 @@ class LedgerRPC_test : public beast::unit_test::suite env.close(); env.close(); env.close(); - BEAST_EXPECT(env.current()->info().seq == 8); + BEAST_EXPECT(env.current()->header().seq == 8); jrr = env.rpc("json", "ledger", to_string(jv))[jss::result]; BEAST_EXPECT(jrr[jss::queue_data].size() == 11); @@ -517,7 +469,7 @@ class LedgerRPC_test : public beast::unit_test::suite jrr = env.rpc("json", "ledger", to_string(jv))[jss::result]; std::string const txid0 = [&]() { - auto const& parentHash = env.current()->info().parentHash; + auto const& parentHash = env.current()->header().parentHash; if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2)) { std::string const txid1 = [&]() { @@ -559,7 +511,7 @@ class LedgerRPC_test : public beast::unit_test::suite jrr = env.rpc("json", "ledger", to_string(jv))[jss::result]; if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2)) { - auto const& parentHash = env.current()->info().parentHash; + auto const& parentHash = env.current()->header().parentHash; auto const txid1 = [&]() { auto const& txj = jrr[jss::queue_data][1u]; BEAST_EXPECT(txj[jss::account] == alice.human()); @@ -671,18 +623,14 @@ class LedgerRPC_test : public beast::unit_test::suite jvParams[jss::accounts] = true; jvParams[jss::expand] = true; jvParams[jss::type] = "hashes"; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); - for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size(); - i++) - if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] == - jss::LedgerHashes) + for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size(); i++) + if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] == jss::LedgerHashes) { - index = jrr[jss::ledger][jss::accountState][i]["index"] - .asString(); + index = jrr[jss::ledger][jss::accountState][i]["index"].asString(); hashesLedgerEntryIndex = i; } @@ -692,10 +640,8 @@ class LedgerRPC_test : public beast::unit_test::suite // jss::type is a deprecated field BEAST_EXPECT( - jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && - jrr[jss::warnings].size() == 1 && - jrr[jss::warnings][0u][jss::id].asInt() == - warnRPC_FIELDS_DEPRECATED); + jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && jrr[jss::warnings].size() == 1 && + jrr[jss::warnings][0u][jss::id].asInt() == warnRPC_FIELDS_DEPRECATED); } { Json::Value jvParams; @@ -703,21 +649,16 @@ class LedgerRPC_test : public beast::unit_test::suite jvParams[jss::accounts] = true; jvParams[jss::expand] = false; jvParams[jss::type] = "hashes"; - auto const jrr = - env.rpc("json", "ledger", to_string(jvParams))[jss::result]; + auto const jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result]; BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState)); BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); BEAST_EXPECT( - hashesLedgerEntryIndex > 0 && - jrr[jss::ledger][jss::accountState][hashesLedgerEntryIndex] == - index); + hashesLedgerEntryIndex > 0 && jrr[jss::ledger][jss::accountState][hashesLedgerEntryIndex] == index); // jss::type is a deprecated field BEAST_EXPECT( - jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && - jrr[jss::warnings].size() == 1 && - jrr[jss::warnings][0u][jss::id].asInt() == - warnRPC_FIELDS_DEPRECATED); + jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() && jrr[jss::warnings].size() == 1 && + jrr[jss::warnings][0u][jss::id].asInt() == warnRPC_FIELDS_DEPRECATED); } } @@ -738,7 +679,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(LedgerRPC, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerRPC, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/LedgerRequestRPC_test.cpp b/src/test/rpc/LedgerRequest_test.cpp similarity index 61% rename from src/test/rpc/LedgerRequestRPC_test.cpp rename to src/test/rpc/LedgerRequest_test.cpp index 7b9326963b..6a1bb2fb89 100644 --- a/src/test/rpc/LedgerRequestRPC_test.cpp +++ b/src/test/rpc/LedgerRequest_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,19 +8,16 @@ #include -namespace ripple { +namespace xrpl { namespace RPC { -class LedgerRequestRPC_test : public beast::unit_test::suite +class LedgerRequest_test : public beast::unit_test::suite { - static constexpr char const* hash1 = - "3020EB9E7BE24EF7D7A060CB051583EC117384636D1781AFB5B87F3E348DA489"; - static constexpr char const* accounthash1 = - "BD8A3D72CA73DDE887AD63666EC2BAD07875CBA997A102579B5B95ECDFFEAED8"; + static constexpr char const* hash1 = "3020EB9E7BE24EF7D7A060CB051583EC117384636D1781AFB5B87F3E348DA489"; + static constexpr char const* accounthash1 = "BD8A3D72CA73DDE887AD63666EC2BAD07875CBA997A102579B5B95ECDFFEAED8"; - static constexpr char const* zerohash = - "0000000000000000000000000000000000000000000000000000000000000000"; + static constexpr char const* zerohash = "0000000000000000000000000000000000000000000000000000000000000000"; public: void @@ -51,38 +29,34 @@ public: env.close(); env.close(); - BEAST_EXPECT(env.current()->info().seq == 5); + BEAST_EXPECT(env.current()->header().seq == 5); { // arbitrary text is converted to 0. auto const result = env.rpc("ledger_request", "arbitrary_text"); BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Ledger index too small"); + result[jss::result][jss::error_message] == "Ledger index too small"); } { auto const result = env.rpc("ledger_request", "-1"); BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Ledger index too small"); + result[jss::result][jss::error_message] == "Ledger index too small"); } { auto const result = env.rpc("ledger_request", "0"); BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Ledger index too small"); + result[jss::result][jss::error_message] == "Ledger index too small"); } { auto const result = env.rpc("ledger_request", "1"); BEAST_EXPECT( - !RPC::contains_error(result[jss::result]) && - result[jss::result][jss::ledger_index] == 1 && + !RPC::contains_error(result[jss::result]) && result[jss::result][jss::ledger_index] == 1 && result[jss::result].isMember(jss::ledger)); BEAST_EXPECT( result[jss::result][jss::ledger].isMember(jss::ledger_hash) && @@ -92,8 +66,7 @@ public: { auto const result = env.rpc("ledger_request", "2"); BEAST_EXPECT( - !RPC::contains_error(result[jss::result]) && - result[jss::result][jss::ledger_index] == 2 && + !RPC::contains_error(result[jss::result]) && result[jss::result][jss::ledger_index] == 2 && result[jss::result].isMember(jss::ledger)); BEAST_EXPECT( result[jss::result][jss::ledger].isMember(jss::ledger_hash) && @@ -103,26 +76,22 @@ public: { auto const result = env.rpc("ledger_request", "3"); BEAST_EXPECT( - !RPC::contains_error(result[jss::result]) && - result[jss::result][jss::ledger_index] == 3 && + !RPC::contains_error(result[jss::result]) && result[jss::result][jss::ledger_index] == 3 && result[jss::result].isMember(jss::ledger)); BEAST_EXPECT( result[jss::result][jss::ledger].isMember(jss::ledger_hash) && result[jss::result][jss::ledger][jss::ledger_hash].isString()); - auto const ledgerHash = - result[jss::result][jss::ledger][jss::ledger_hash].asString(); + auto const ledgerHash = result[jss::result][jss::ledger][jss::ledger_hash].asString(); { auto const r = env.rpc("ledger_request", ledgerHash); BEAST_EXPECT( - !RPC::contains_error(r[jss::result]) && - r[jss::result][jss::ledger_index] == 3 && + !RPC::contains_error(r[jss::result]) && r[jss::result][jss::ledger_index] == 3 && r[jss::result].isMember(jss::ledger)); BEAST_EXPECT( r[jss::result][jss::ledger].isMember(jss::ledger_hash) && - r[jss::result][jss::ledger][jss::ledger_hash] == - ledgerHash); + r[jss::result][jss::ledger][jss::ledger_hash] == ledgerHash); } } @@ -133,8 +102,7 @@ public: BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Invalid field 'ledger_hash'."); + result[jss::result][jss::error_message] == "Invalid field 'ledger_hash', not hex string."); } { @@ -142,25 +110,21 @@ public: auto const result = env.rpc("ledger_request", ledgerHash); - BEAST_EXPECT( - !RPC::contains_error(result[jss::result]) && - result[jss::result][jss::have_header] == false); + BEAST_EXPECT(!RPC::contains_error(result[jss::result]) && result[jss::result][jss::have_header] == false); } { auto const result = env.rpc("ledger_request", "4"); BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Ledger index too large"); + result[jss::result][jss::error_message] == "Ledger index too large"); } { auto const result = env.rpc("ledger_request", "5"); BEAST_EXPECT( RPC::contains_error(result[jss::result]) && - result[jss::result][jss::error_message] == - "Ledger index too large"); + result[jss::result][jss::error_message] == "Ledger index too large"); } } @@ -171,11 +135,8 @@ public: auto cfg = envconfig(); cfg->FEES.reference_fee = 10; - Env env{ - *this, - std::move(cfg), - FeatureBitset{}}; // the hashes being checked below - // assume no amendments + Env env{*this, std::move(cfg), FeatureBitset{}}; // the hashes being checked below + // assume no amendments Account const gw{"gateway"}; auto const USD = gw["USD"]; env.fund(XRP(100000), gw); @@ -195,8 +156,7 @@ public: auto result = env.rpc("ledger_request", "1")[jss::result]; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "100000000000000000"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash1); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == zerohash); @@ -204,11 +164,9 @@ public: BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == zerohash); result = env.rpc("ledger_request", "2")[jss::result]; - constexpr char const* hash2 = - "CCC3B3E88CCAC17F1BE6B4A648A55999411F19E3FE55EB721960EB0DF28EDDA5"; + constexpr char const* hash2 = "CCC3B3E88CCAC17F1BE6B4A648A55999411F19E3FE55EB721960EB0DF28EDDA5"; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "2"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "100000000000000000"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash2); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash1); @@ -218,52 +176,46 @@ public: BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == zerohash); result = env.rpc("ledger_request", "3")[jss::result]; - constexpr char const* hash3 = - "8D631B20BC989AF568FBA97375290544B0703A5ADC1CF9E9053580461690C9EE"; + constexpr char const* hash3 = "9FFD8AE09190D5002FE4252A1B29EABCF40DABBCE3B42619C6BD0BE381D51103"; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "3"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "99999999999999980"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999980"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash3); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash2); BEAST_EXPECT( result[jss::ledger][jss::account_hash] == - "BC9EF2A16BFF80BCFABA6FA84688D858D33BD0FA0435CAA9DF6DA4105A39A29E"); + "35738B8517F37D08983AF6BC7DA483CCA9CF6B41B1FECB31A20028D78FE0BB22"); BEAST_EXPECT( result[jss::ledger][jss::transaction_hash] == - "0213EC486C058B3942FBE3DAC6839949A5C5B02B8B4244C8998EFDF04DBD8222"); + "CBD7F0948EBFA2241DE4EA627939A0FFEE6B80A90FE09C42C825DA546E9B73FF"); result = env.rpc("ledger_request", "4")[jss::result]; - constexpr char const* hash4 = - "1A8E7098B23597E73094DADA58C9D62F3AB93A12C6F7666D56CA85A6CFDE530F"; + constexpr char const* hash4 = "7C9B614445517B8C6477E0AB10A35FFC1A23A34FEA41A91ECBDE884CC097C6E1"; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "4"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "99999999999999960"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999960"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash4); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash3); BEAST_EXPECT( result[jss::ledger][jss::account_hash] == - "C690188F123C91355ADA8BDF4AC5B5C927076D3590C215096868A5255264C6DD"); + "1EE701DD2A150205173E1EDE8D474DF6803EC95253DAAEE965B9D896CFC32A04"); BEAST_EXPECT( result[jss::ledger][jss::transaction_hash] == - "3CBDB8F42E04333E1642166BFB93AC9A7E1C6C067092CD5D881D6F3AB3D67E76"); + "9BBDDBF926100DFFF364E16268F544B19F5B9BC6ECCBBC104F98D13FA9F3BC35"); result = env.rpc("ledger_request", "5")[jss::result]; - constexpr char const* hash5 = - "C6A222D71AE65D7B4F240009EAD5DEB20D7EEDE5A4064F28BBDBFEEB6FBE48E5"; + constexpr char const* hash5 = "98885D02145CCE4AD2605F1809F17188DB2053B14ED399CAC985DD8E03DCA8C0"; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "5"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "99999999999999940"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999940"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash5); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash4); BEAST_EXPECT( result[jss::ledger][jss::account_hash] == - "EA81CD9D36740736F00CB747E0D0E32D3C10B695823D961F0FB9A1CE7133DD4D"); + "41D64D64796468DEA7AE2A7282C0BB525D6FD7ABC29453C5E5BC6406E947CBCE"); BEAST_EXPECT( result[jss::ledger][jss::transaction_hash] == - "C3D086CD6BDB9E97AD1D513B2C049EF2840BD21D0B3E22D84EBBB89B6D2EF59D"); + "8FE8592EF22FBC2E8C774C7A1ED76AA3FCE64BED17D748CBA9AFDF7072FE36C7"); result = env.rpc("ledger_request", "6")[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); @@ -281,34 +233,44 @@ public: env.fund(XRP(100000), gw); env.close(); - Json::Value jvParams; - jvParams[jss::ledger_hash] = - "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7"; - jvParams[jss::ledger_index] = "1"; - auto result = env.rpc( - "json", "ledger_request", jvParams.toStyledString())[jss::result]; - BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT(result[jss::status] == "error"); - BEAST_EXPECT( - result[jss::error_message] == - "Exactly one of ledger_hash and ledger_index can be set."); + { + Json::Value jvParams; + jvParams[jss::ledger_hash] = + "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936" + "C7"; + jvParams[jss::ledger_index] = "1"; + auto const result = env.rpc("json", "ledger_request", jvParams.toStyledString())[jss::result]; + BEAST_EXPECT(result[jss::error] == "invalidParams"); + BEAST_EXPECT(result[jss::status] == "error"); + BEAST_EXPECT( + result[jss::error_message] == + "Exactly one of 'ledger_hash' or 'ledger_index' can be " + "specified."); + } + + { + Json::Value jvParams; + jvParams[jss::ledger_index] = "index"; + auto const result = env.rpc("json", "ledger_request", jvParams.toStyledString())[jss::result]; + BEAST_EXPECT(result[jss::error] == "invalidParams"); + BEAST_EXPECT(result[jss::status] == "error"); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'ledger_index', not number."); + } // the purpose in this test is to force the ledger expiration/out of // date check to trigger env.timeKeeper().adjustCloseTime(weeks{3}); - result = env.rpc(apiVersion, "ledger_request", "1")[jss::result]; + auto const result = env.rpc(apiVersion, "ledger_request", "1")[jss::result]; BEAST_EXPECT(result[jss::status] == "error"); if (apiVersion == 1) { BEAST_EXPECT(result[jss::error] == "noCurrent"); - BEAST_EXPECT( - result[jss::error_message] == "Current ledger is unavailable."); + BEAST_EXPECT(result[jss::error_message] == "Current ledger is unavailable."); } else { BEAST_EXPECT(result[jss::error] == "notSynced"); - BEAST_EXPECT( - result[jss::error_message] == "Not synced to the network."); + BEAST_EXPECT(result[jss::error_message] == "Not synced to the network."); } } @@ -337,8 +299,7 @@ public: auto result = env.rpc("ledger_request", "1")[jss::result]; BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1"); - BEAST_EXPECT( - result[jss::ledger][jss::total_coins] == "100000000000000000"); + BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000"); BEAST_EXPECT(result[jss::ledger][jss::closed] == true); BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash1); BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == zerohash); @@ -368,14 +329,13 @@ public: { testLedgerRequest(); testEvolution(); - forAllApiVersions( - std::bind_front(&LedgerRequestRPC_test::testBadInput, this)); + forAllApiVersions(std::bind_front(&LedgerRequest_test::testBadInput, this)); testMoreThan256Closed(); testNonAdmin(); } }; -BEAST_DEFINE_TESTSUITE(LedgerRequestRPC, rpc, ripple); +BEAST_DEFINE_TESTSUITE(LedgerRequest, rpc, xrpl); } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/ManifestRPC_test.cpp b/src/test/rpc/ManifestRPC_test.cpp index d040ed5632..f42fdd7164 100644 --- a/src/test/rpc/ManifestRPC_test.cpp +++ b/src/test/rpc/ManifestRPC_test.cpp @@ -1,21 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Dev Null Productions, LLC - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== +// Copyright (c) 2020 Dev Null Productions #include @@ -26,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class ManifestRPC_test : public beast::unit_test::suite @@ -42,19 +25,16 @@ public: { // manifest with no public key auto const info = env.rpc("json", "manifest", "{ }"); - BEAST_EXPECT( - info[jss::result][jss::error_message] == - "Missing field 'public_key'."); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Missing field 'public_key'."); } { - // manifest with manlformed public key + // manifest with malformed public key auto const info = env.rpc( "json", "manifest", "{ \"public_key\": " "\"abcdef12345\"}"); - BEAST_EXPECT( - info[jss::result][jss::error_message] == "Invalid parameters."); + BEAST_EXPECT(info[jss::result][jss::error_message] == "Invalid parameters."); } } @@ -64,8 +44,7 @@ public: testcase("Lookup"); using namespace jtx; - std::string const key = - "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7"; + std::string const key = "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7"; Env env{*this, envconfig([&key](std::unique_ptr cfg) { cfg->section(SECTION_VALIDATORS).append(key); return cfg; @@ -90,6 +69,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ManifestRPC, rpc, ripple); +BEAST_DEFINE_TESTSUITE(ManifestRPC, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/NoRippleCheck_test.cpp b/src/test/rpc/NoRippleCheck_test.cpp index f379e273dd..0857561fda 100644 --- a/src/test/rpc/NoRippleCheck_test.cpp +++ b/src/test/rpc/NoRippleCheck_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +12,7 @@ #include -namespace ripple { +namespace xrpl { class NoRippleCheck_test : public beast::unit_test::suite { @@ -48,18 +29,15 @@ class NoRippleCheck_test : public beast::unit_test::suite env.close(); { // missing account field - auto const result = - env.rpc("json", "noripple_check", "{}")[jss::result]; + auto const result = env.rpc("json", "noripple_check", "{}")[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT( - result[jss::error_message] == "Missing field 'account'."); + BEAST_EXPECT(result[jss::error_message] == "Missing field 'account'."); } { // missing role field Json::Value params; params[jss::account] = alice.human(); - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::error_message] == "Missing field 'role'."); } @@ -70,11 +48,9 @@ class NoRippleCheck_test : public beast::unit_test::suite Json::Value params; params[jss::account] = param; params[jss::role] = "user"; - auto jrr = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto jrr = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jrr[jss::error_message] == "Invalid field 'account'."); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'."); }; testInvalidAccountParam(1); @@ -89,8 +65,7 @@ class NoRippleCheck_test : public beast::unit_test::suite Json::Value params; params[jss::account] = alice.human(); params[jss::role] = "not_a_role"; - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::error_message] == "Invalid field 'role'."); } @@ -100,12 +75,9 @@ class NoRippleCheck_test : public beast::unit_test::suite params[jss::account] = alice.human(); params[jss::role] = "user"; params[jss::limit] = -1; - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT( - result[jss::error_message] == - "Invalid field 'limit', not unsigned integer."); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'limit', not unsigned integer."); } { // invalid ledger (hash) @@ -113,10 +85,9 @@ class NoRippleCheck_test : public beast::unit_test::suite params[jss::account] = alice.human(); params[jss::role] = "user"; params[jss::ledger_hash] = 1; - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT(result[jss::error_message] == "ledgerHashNotString"); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'ledger_hash', not hex string."); } { // account not found @@ -124,8 +95,7 @@ class NoRippleCheck_test : public beast::unit_test::suite params[jss::account] = Account{"nobody"}.human(); params[jss::role] = "user"; params[jss::ledger] = "current"; - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "actNotFound"); BEAST_EXPECT(result[jss::error_message] == "Account not found."); } @@ -136,18 +106,43 @@ class NoRippleCheck_test : public beast::unit_test::suite params[jss::account] = toBase58(TokenType::NodePrivate, alice.sk()); params[jss::role] = "user"; params[jss::ledger] = "current"; - auto const result = env.rpc( - "json", "noripple_check", to_string(params))[jss::result]; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::error] == "actMalformed"); BEAST_EXPECT(result[jss::error_message] == "Account malformed."); } + + { + // ledger and ledger_hash are included + Json::Value params; + params[jss::account] = Account{"nobody"}.human(); + params[jss::role] = "user"; + params[jss::ledger] = "current"; + params[jss::ledger_hash] = "ABCDEF"; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; + BEAST_EXPECT(result[jss::error] == "invalidParams"); + BEAST_EXPECT( + result[jss::error_message] == + "Exactly one of 'ledger', 'ledger_hash', or 'ledger_index' can " + "be specified."); + } + + { + // invalid ledger + Json::Value params; + params[jss::account] = Account{"nobody"}.human(); + params[jss::role] = "user"; + params[jss::ledger] = Json::objectValue; + auto const result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; + BEAST_EXPECT(result[jss::error] == "invalidParams"); + BEAST_EXPECT(result[jss::error_message] == "Invalid field 'ledger', not string or number."); + } } void testBasic(bool user, bool problems) { - testcase << "Request noripple_check for " << (user ? "user" : "gateway") - << " role, expect" << (problems ? "" : " no") << " problems"; + testcase << "Request noripple_check for " << (user ? "user" : "gateway") << " role, expect" + << (problems ? "" : " no") << " problems"; using namespace test::jtx; Env env{*this}; @@ -172,8 +167,7 @@ class NoRippleCheck_test : public beast::unit_test::suite params[jss::account] = alice.human(); params[jss::role] = (user ? "user" : "gateway"); params[jss::ledger] = "current"; - auto result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + auto result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; auto const pa = result["problems"]; if (!BEAST_EXPECT(pa.isArray())) @@ -186,17 +180,13 @@ class NoRippleCheck_test : public beast::unit_test::suite if (user) { - BEAST_EXPECT(boost::starts_with( - pa[0u].asString(), "You appear to have set")); - BEAST_EXPECT(boost::starts_with( - pa[1u].asString(), "You should probably set")); + BEAST_EXPECT(boost::starts_with(pa[0u].asString(), "You appear to have set")); + BEAST_EXPECT(boost::starts_with(pa[1u].asString(), "You should probably set")); } else { - BEAST_EXPECT(boost::starts_with( - pa[0u].asString(), "You should immediately set")); - BEAST_EXPECT( - boost::starts_with(pa[1u].asString(), "You should clear")); + BEAST_EXPECT(boost::starts_with(pa[0u].asString(), "You should immediately set")); + BEAST_EXPECT(boost::starts_with(pa[1u].asString(), "You should clear")); } } else @@ -207,8 +197,7 @@ class NoRippleCheck_test : public beast::unit_test::suite // now make a second request asking for the relevant transactions this // time. params[jss::transactions] = true; - result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; if (!BEAST_EXPECT(result[jss::transactions].isArray())) return; @@ -224,12 +213,8 @@ class NoRippleCheck_test : public beast::unit_test::suite BEAST_EXPECT(txs[0u][jss::TransactionType] == jss::AccountSet); } - BEAST_EXPECT( - result[jss::transactions][txs.size() - 1][jss::Account] == - alice.human()); - BEAST_EXPECT( - result[jss::transactions][txs.size() - 1] - [jss::TransactionType] == jss::TrustSet); + BEAST_EXPECT(result[jss::transactions][txs.size() - 1][jss::Account] == alice.human()); + BEAST_EXPECT(result[jss::transactions][txs.size() - 1][jss::TransactionType] == jss::TrustSet); BEAST_EXPECT( result[jss::transactions][txs.size() - 1][jss::LimitAmount] == gw["USD"](100).value().getJson(JsonOptions::none)); @@ -256,8 +241,7 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite void testLimits(bool admin) { - testcase << "Check limits in returned data, " - << (admin ? "admin" : "non-admin"); + testcase << "Check limits in returned data, " << (admin ? "admin" : "non-admin"); using namespace test::jtx; @@ -271,27 +255,26 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite auto checkBalance = [&env]() { // this is endpoint drop prevention. Non admin ports will drop // requests if they are coming too fast, so we manipulate the - // resource manager here to reset the enpoint balance (for + // resource manager here to reset the endpoint balance (for // localhost) if we get too close to the drop limit. It would // be better if we could add this functionality to Env somehow // or otherwise disable endpoint charging for certain test // cases. - using namespace ripple::Resource; + using namespace xrpl::Resource; using namespace std::chrono; using namespace beast::IP; - auto c = env.app().getResourceManager().newInboundEndpoint( - Endpoint::from_string(test::getEnvLocalhostAddr())); + auto c = + env.app().getResourceManager().newInboundEndpoint(Endpoint::from_string(test::getEnvLocalhostAddr())); // if we go above the warning threshold, reset if (c.balance() > warningThreshold) { using ct = beast::abstract_clock; - c.entry().local_balance = - DecayingSample{steady_clock::now()}; + c.entry().local_balance = DecayingSample{steady_clock::now()}; } }; - for (auto i = 0; i < ripple::RPC::Tuning::noRippleCheck.rmax + 5; ++i) + for (auto i = 0; i < xrpl::RPC::Tuning::noRippleCheck.rmax + 5; ++i) { if (!admin) checkBalance(); @@ -302,23 +285,14 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite auto const baseFee = env.current()->fees().base; env(pay(env.master, gw, XRP(1000)), seq(autofill), - fee(toDrops( - txq.getMetrics(*env.current()).openLedgerFeeLevel, - baseFee) + - 1), + fee(toDrops(txq.getMetrics(*env.current()).openLedgerFeeLevel, baseFee) + 1), sig(autofill)); env(fset(gw, asfDefaultRipple), seq(autofill), - fee(toDrops( - txq.getMetrics(*env.current()).openLedgerFeeLevel, - baseFee) + - 1), + fee(toDrops(txq.getMetrics(*env.current()).openLedgerFeeLevel, baseFee) + 1), sig(autofill)); env(trust(alice, gw["USD"](10)), - fee(toDrops( - txq.getMetrics(*env.current()).openLedgerFeeLevel, - baseFee) + - 1)); + fee(toDrops(txq.getMetrics(*env.current()).openLedgerFeeLevel, baseFee) + 1)); env.close(); } @@ -327,33 +301,28 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite params[jss::account] = alice.human(); params[jss::role] = "user"; params[jss::ledger] = "current"; - auto result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + auto result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result["problems"].size() == 301); // one below minimum params[jss::limit] = 9; - result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result["problems"].size() == (admin ? 10 : 11)); // at minimum params[jss::limit] = 10; - result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result["problems"].size() == 11); // at max params[jss::limit] = 400; - result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result["problems"].size() == 401); // at max+1 params[jss::limit] = 401; - result = - env.rpc("json", "noripple_check", to_string(params))[jss::result]; + result = env.rpc("json", "noripple_check", to_string(params))[jss::result]; BEAST_EXPECT(result["problems"].size() == (admin ? 402 : 401)); } @@ -366,12 +335,12 @@ public: } }; -BEAST_DEFINE_TESTSUITE(NoRippleCheck, rpc, ripple); +BEAST_DEFINE_TESTSUITE(NoRippleCheck, rpc, xrpl); // These tests that deal with limit amounts are slow because of the // offer/account setup, so making them manual -- the additional coverage // provided by them is minimal -BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(NoRippleCheckLimits, rpc, ripple, 1); +BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(NoRippleCheckLimits, rpc, xrpl, 1); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/NoRipple_test.cpp b/src/test/rpc/NoRipple_test.cpp index 626a70ce00..9cfc69ccd5 100644 --- a/src/test/rpc/NoRipple_test.cpp +++ b/src/test/rpc/NoRipple_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -52,18 +33,13 @@ public: for (auto SetOrClear : {true, false}) { // Create a trust line with no-ripple flag setting - env(trust( - gw, - USD(100), - alice, - SetOrClear ? tfSetNoRipple : tfClearNoRipple)); + env(trust(gw, USD(100), alice, SetOrClear ? tfSetNoRipple : tfClearNoRipple)); env.close(); // Check no-ripple flag on sender 'gateway' - Json::Value lines{ - env.rpc("json", "account_lines", to_string(account_gw))}; - auto const& gline0 = lines[jss::result][jss::lines][0u]; - BEAST_EXPECT(gline0[jss::no_ripple].asBool() == SetOrClear); + Json::Value lines{env.rpc("json", "account_lines", to_string(account_gw))}; + auto const& gwLine0 = lines[jss::result][jss::lines][0u]; + BEAST_EXPECT(gwLine0[jss::no_ripple].asBool() == SetOrClear); // Check no-ripple peer flag on destination 'alice' lines = env.rpc("json", "account_lines", to_string(account_alice)); @@ -115,8 +91,7 @@ public: return dest_amt; }(); - auto const resp = - env.rpc("json", "ripple_path_find", to_string(params)); + auto const resp = env.rpc("json", "ripple_path_find", to_string(params)); BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 1); auto getAccountLines = [&env](Account const& acct) { @@ -186,8 +161,7 @@ public: return dest_amt; }(); - Json::Value const resp{ - env.rpc("json", "ripple_path_find", to_string(params))}; + Json::Value const resp{env.rpc("json", "ripple_path_find", to_string(params))}; BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0); env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY)); @@ -258,13 +232,11 @@ public: params[jss::role] = "gateway"; params[jss::transactions] = "asdf"; - auto lines = - env.rpc("json", "noripple_check", to_string(params)); + auto lines = env.rpc("json", "noripple_check", to_string(params)); if (apiVersion < 2u) BEAST_EXPECT(lines[jss::result][jss::status] == "success"); else - BEAST_EXPECT( - lines[jss::result][jss::error] == "invalidParams"); + BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams"); } } } @@ -275,9 +247,7 @@ public: testSetAndClear(); auto withFeatsTests = [this](FeatureBitset features) { - forAllApiVersions([&, this](unsigned testVersion) { - testDefaultRipple(features, testVersion); - }); + forAllApiVersions([&, this](unsigned testVersion) { testDefaultRipple(features, testVersion); }); testNegativeBalance(features); testPairwise(features); }; @@ -288,7 +258,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(NoRipple, rpc, ripple); +BEAST_DEFINE_TESTSUITE(NoRipple, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/OwnerInfo_test.cpp b/src/test/rpc/OwnerInfo_test.cpp index 0c517058ca..9e3fee04c2 100644 --- a/src/test/rpc/OwnerInfo_test.cpp +++ b/src/test/rpc/OwnerInfo_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { class OwnerInfo_test : public beast::unit_test::suite { @@ -41,32 +22,21 @@ class OwnerInfo_test : public beast::unit_test::suite env.close(); { // missing account field - auto const result = - env.rpc("json", "owner_info", "{}")[jss::result]; + auto const result = env.rpc("json", "owner_info", "{}")[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); - BEAST_EXPECT( - result[jss::error_message] == "Missing field 'account'."); + BEAST_EXPECT(result[jss::error_message] == "Missing field 'account'."); } { // ask for empty account Json::Value params; params[jss::account] = ""; - auto const result = - env.rpc("json", "owner_info", to_string(params))[jss::result]; - if (BEAST_EXPECT( - result.isMember(jss::accepted) && - result.isMember(jss::current))) + auto const result = env.rpc("json", "owner_info", to_string(params))[jss::result]; + if (BEAST_EXPECT(result.isMember(jss::accepted) && result.isMember(jss::current))) { - BEAST_EXPECT( - result[jss::accepted][jss::error] == "actMalformed"); - BEAST_EXPECT( - result[jss::accepted][jss::error_message] == - "Account malformed."); - BEAST_EXPECT( - result[jss::current][jss::error] == "actMalformed"); - BEAST_EXPECT( - result[jss::current][jss::error_message] == - "Account malformed."); + BEAST_EXPECT(result[jss::accepted][jss::error] == "actMalformed"); + BEAST_EXPECT(result[jss::accepted][jss::error_message] == "Account malformed."); + BEAST_EXPECT(result[jss::current][jss::error] == "actMalformed"); + BEAST_EXPECT(result[jss::current][jss::error_message] == "Account malformed."); } } @@ -75,8 +45,7 @@ class OwnerInfo_test : public beast::unit_test::suite // (deprecated) does not return an error, just empty fields. Json::Value params; params[jss::account] = Account{"bob"}.human(); - auto const result = - env.rpc("json", "owner_info", to_string(params))[jss::result]; + auto const result = env.rpc("json", "owner_info", to_string(params))[jss::result]; BEAST_EXPECT(result[jss::accepted] == Json::objectValue); BEAST_EXPECT(result[jss::current] == Json::objectValue); BEAST_EXPECT(result[jss::status] == "success"); @@ -108,11 +77,8 @@ class OwnerInfo_test : public beast::unit_test::suite Json::Value params; params[jss::account] = alice.human(); - auto const result = - env.rpc("json", "owner_info", to_string(params))[jss::result]; - if (!BEAST_EXPECT( - result.isMember(jss::accepted) && - result.isMember(jss::current))) + auto const result = env.rpc("json", "owner_info", to_string(params))[jss::result]; + if (!BEAST_EXPECT(result.isMember(jss::accepted) && result.isMember(jss::current))) { return; } @@ -126,27 +92,15 @@ class OwnerInfo_test : public beast::unit_test::suite BEAST_EXPECT( lines[0u][sfBalance.fieldName] == - (STAmount{Issue{to_currency("CNY"), noAccount()}, 0} - .value() - .getJson(JsonOptions::none))); - BEAST_EXPECT( - lines[0u][sfHighLimit.fieldName] == - alice["CNY"](1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - lines[0u][sfLowLimit.fieldName] == - gw["CNY"](0).value().getJson(JsonOptions::none)); + (STAmount{Issue{to_currency("CNY"), noAccount()}, 0}.value().getJson(JsonOptions::none))); + BEAST_EXPECT(lines[0u][sfHighLimit.fieldName] == alice["CNY"](1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(lines[0u][sfLowLimit.fieldName] == gw["CNY"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT( lines[1u][sfBalance.fieldName] == - (STAmount{Issue{to_currency("USD"), noAccount()}, 0} - .value() - .getJson(JsonOptions::none))); - BEAST_EXPECT( - lines[1u][sfHighLimit.fieldName] == - alice["USD"](1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - lines[1u][sfLowLimit.fieldName] == - USD(0).value().getJson(JsonOptions::none)); + (STAmount{Issue{to_currency("USD"), noAccount()}, 0}.value().getJson(JsonOptions::none))); + BEAST_EXPECT(lines[1u][sfHighLimit.fieldName] == alice["USD"](1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(lines[1u][sfLowLimit.fieldName] == USD(0).value().getJson(JsonOptions::none)); if (!BEAST_EXPECT(result[jss::accepted].isMember(jss::offers))) return; @@ -155,12 +109,8 @@ class OwnerInfo_test : public beast::unit_test::suite return; BEAST_EXPECT(offers[0u][jss::Account] == alice.human()); - BEAST_EXPECT( - offers[0u][sfTakerGets.fieldName] == - XRP(1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - offers[0u][sfTakerPays.fieldName] == - USD(1).value().getJson(JsonOptions::none)); + BEAST_EXPECT(offers[0u][sfTakerGets.fieldName] == XRP(1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(offers[0u][sfTakerPays.fieldName] == USD(1).value().getJson(JsonOptions::none)); // current ledger entry if (!BEAST_EXPECT(result[jss::current].isMember(jss::ripple_lines))) @@ -171,27 +121,15 @@ class OwnerInfo_test : public beast::unit_test::suite BEAST_EXPECT( lines[0u][sfBalance.fieldName] == - (STAmount{Issue{to_currency("CNY"), noAccount()}, -50} - .value() - .getJson(JsonOptions::none))); - BEAST_EXPECT( - lines[0u][sfHighLimit.fieldName] == - alice["CNY"](1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - lines[0u][sfLowLimit.fieldName] == - gw["CNY"](0).value().getJson(JsonOptions::none)); + (STAmount{Issue{to_currency("CNY"), noAccount()}, -50}.value().getJson(JsonOptions::none))); + BEAST_EXPECT(lines[0u][sfHighLimit.fieldName] == alice["CNY"](1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(lines[0u][sfLowLimit.fieldName] == gw["CNY"](0).value().getJson(JsonOptions::none)); BEAST_EXPECT( lines[1u][sfBalance.fieldName] == - (STAmount{Issue{to_currency("USD"), noAccount()}, -50} - .value() - .getJson(JsonOptions::none))); - BEAST_EXPECT( - lines[1u][sfHighLimit.fieldName] == - alice["USD"](1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - lines[1u][sfLowLimit.fieldName] == - gw["USD"](0).value().getJson(JsonOptions::none)); + (STAmount{Issue{to_currency("USD"), noAccount()}, -50}.value().getJson(JsonOptions::none))); + BEAST_EXPECT(lines[1u][sfHighLimit.fieldName] == alice["USD"](1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(lines[1u][sfLowLimit.fieldName] == gw["USD"](0).value().getJson(JsonOptions::none)); if (!BEAST_EXPECT(result[jss::current].isMember(jss::offers))) return; @@ -202,12 +140,8 @@ class OwnerInfo_test : public beast::unit_test::suite BEAST_EXPECT(offers[1u] == result[jss::accepted][jss::offers][0u]); BEAST_EXPECT(offers[0u][jss::Account] == alice.human()); - BEAST_EXPECT( - offers[0u][sfTakerGets.fieldName] == - XRP(1000).value().getJson(JsonOptions::none)); - BEAST_EXPECT( - offers[0u][sfTakerPays.fieldName] == - CNY(2).value().getJson(JsonOptions::none)); + BEAST_EXPECT(offers[0u][sfTakerGets.fieldName] == XRP(1000).value().getJson(JsonOptions::none)); + BEAST_EXPECT(offers[0u][sfTakerPays.fieldName] == CNY(2).value().getJson(JsonOptions::none)); } public: @@ -219,6 +153,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(OwnerInfo, rpc, ripple); +BEAST_DEFINE_TESTSUITE(OwnerInfo, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Peers_test.cpp b/src/test/rpc/Peers_test.cpp index d325da12c3..8e4e560f3e 100644 --- a/src/test/rpc/Peers_test.cpp +++ b/src/test/rpc/Peers_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { class Peers_test : public beast::unit_test::suite { @@ -41,24 +22,20 @@ class Peers_test : public beast::unit_test::suite // without modification of the cluster, expect an empty set // from this request auto peers = env.rpc("peers")[jss::result]; - BEAST_EXPECT( - peers.isMember(jss::cluster) && peers[jss::cluster].size() == 0); + BEAST_EXPECT(peers.isMember(jss::cluster) && peers[jss::cluster].size() == 0); BEAST_EXPECT(peers.isMember(jss::peers) && peers[jss::peers].isNull()); // insert some nodes in to the cluster std::unordered_map nodes; for (auto i = 0; i < 3; ++i) { - auto kp = generateKeyPair( - KeyType::secp256k1, generateSeed("seed" + std::to_string(i))); + auto kp = generateKeyPair(KeyType::secp256k1, generateSeed("seed" + std::to_string(i))); std::string name = "Node " + std::to_string(i); using namespace std::chrono_literals; - env.app().cluster().update( - kp.first, name, 200, env.timeKeeper().now() - 10s); - nodes.insert(std::make_pair( - toBase58(TokenType::NodePublic, kp.first), name)); + env.app().cluster().update(kp.first, name, 200, env.timeKeeper().now() - 10s); + nodes.insert(std::make_pair(toBase58(TokenType::NodePublic, kp.first), name)); } // make request, verify nodes we created match @@ -68,9 +45,7 @@ class Peers_test : public beast::unit_test::suite return; if (!BEAST_EXPECT(peers[jss::cluster].size() == nodes.size())) return; - for (auto it = peers[jss::cluster].begin(); - it != peers[jss::cluster].end(); - ++it) + for (auto it = peers[jss::cluster].begin(); it != peers[jss::cluster].end(); ++it) { auto key = it.key().asString(); auto search = nodes.find(key); @@ -92,6 +67,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Peers, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Peers, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index cc84a375f6..26f7ed0f18 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { struct RPCCallTestData @@ -54,11 +37,7 @@ struct RPCCallTestData std::initializer_list const& args_, Exception throwsWhat_, char const* exp_) - : description(description_) - , line(line_) - , args(args_) - , throwsWhat(throwsWhat_) - , exp(1, exp_) + : description(description_), line(line_), args(args_), throwsWhat(throwsWhat_), exp(1, exp_) { } @@ -68,11 +47,7 @@ struct RPCCallTestData std::initializer_list const& args_, Exception throwsWhat_, std::initializer_list exp_) - : description(description_) - , line(line_) - , args(args_) - , throwsWhat(throwsWhat_) - , exp(exp_) + : description(description_), line(line_), args(args_), throwsWhat(throwsWhat_), exp(exp_) { } @@ -103,9 +78,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_channels: account and ledger hash.", __LINE__, - {"account_channels", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rD5MbavGfiSC5m7mkxy1FANuT7s3HxqpoF"}, + {"account_channels", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rD5MbavGfiSC5m7mkxy1FANuT7s3HxqpoF"}, RPCCallTestData::no_exception, R"({ "method" : "account_channels", @@ -119,9 +92,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_channels: account and ledger index.", __LINE__, - {"account_channels", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "r9emE59aTWb85t64dAebKrxYMBTpzK5yR7"}, + {"account_channels", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "r9emE59aTWb85t64dAebKrxYMBTpzK5yR7"}, RPCCallTestData::no_exception, R"({ "method" : "account_channels", @@ -135,9 +106,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_channels: two accounts.", __LINE__, - {"account_channels", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"}, + {"account_channels", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"}, RPCCallTestData::no_exception, R"({ "method" : "account_channels", @@ -169,10 +138,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_channels: two accounts and ledger index.", __LINE__, - {"account_channels", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "90210"}, + {"account_channels", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "90210"}, RPCCallTestData::no_exception, R"({ "method" : "account_channels", @@ -325,11 +291,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_currencies: too many arguments.", __LINE__, - {"account_currencies", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "current", - "spare1", - "spare2"}, + {"account_currencies", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "current", "spare1", "spare2"}, RPCCallTestData::no_exception, R"({ "method" : "account_currencies", @@ -466,11 +428,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_info: too many arguments.", __LINE__, - {"account_info", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "current", - "extra1", - "extra2"}, + {"account_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "current", "extra1", "extra2"}, RPCCallTestData::no_exception, R"({ "method" : "account_info", @@ -519,9 +477,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_lines: peer.", __LINE__, - {"account_lines", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"}, + {"account_lines", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"}, RPCCallTestData::no_exception, R"({ "method" : "account_lines", @@ -535,10 +491,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_lines: peer and numeric ledger index.", __LINE__, - {"account_lines", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "888888888"}, + {"account_lines", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "888888888"}, RPCCallTestData::no_exception, R"({ "method" : "account_lines", @@ -553,10 +506,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_lines: peer and text ledger index.", __LINE__, - {"account_lines", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "closed"}, + {"account_lines", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "closed"}, RPCCallTestData::no_exception, R"({ "method" : "account_lines", @@ -705,10 +655,7 @@ static RPCCallTestData const rpcCallTestArray[] = { { "account_lines: invalid ledger selector.", __LINE__, - {"account_lines", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "not_a_ledger"}, + {"account_lines", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "not_a_ledger"}, RPCCallTestData::no_exception, R"({ "method" : "account_lines", @@ -1023,10 +970,7 @@ static RPCCallTestData const rpcCallTestArray[] = { {// Note: I believe this _ought_ to be detected as too many arguments. "account_offers: four arguments.", __LINE__, - {"account_offers", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "current", - "extra"}, + {"account_offers", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "current", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "account_offers", @@ -1145,12 +1089,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_tx: ledger_index plus trailing params.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "707", - "descending", - "binary", - "count"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "707", "descending", "binary", "count"}, RPCCallTestData::no_exception, R"({ "method" : "account_tx", @@ -1182,13 +1121,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_tx: ledger_index_min and _max plus trailing params.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "-1", - "413", - "binary", - "count", - "descending"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "-1", "413", "binary", "count", "descending"}, RPCCallTestData::no_exception, R"({ "method" : "account_tx", @@ -1222,14 +1155,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_tx: ledger_index_min and _max, limit, trailing args.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "247", - "-1", - "300", - "count", - "descending", - "binary"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "247", "-1", "300", "count", "descending", "binary"}, RPCCallTestData::no_exception, R"({ "method" : "account_tx", @@ -1248,12 +1174,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_tx: ledger_index_min and _max plus limit and offset.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "589", - "590", - "67", - "45"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "589", "590", "67", "45"}, RPCCallTestData::no_exception, R"({ "method" : "account_tx", @@ -1270,14 +1191,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"account_tx: ledger_index_min and _max, limit, offset, trailing.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "589", - "590", - "67", - "45", - "descending", - "count"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "589", "590", "67", "45", "descending", "count"}, RPCCallTestData::no_exception, R"({ "method" : "account_tx", @@ -1413,11 +1327,7 @@ static RPCCallTestData const rpcCallTestArray[] = { // Note: this really shouldn't throw, but does at the moment. "account_tx: non-integer offset.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "-1", - "-1", - "decending"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "-1", "-1", "decending"}, RPCCallTestData::bad_cast, R"()", }, @@ -1425,26 +1335,14 @@ static RPCCallTestData const rpcCallTestArray[] = { // Note: this really shouldn't throw, but does at the moment. "account_tx: non-integer limit.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "-1", - "-1", - "300", - "false"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "-1", "-1", "300", "false"}, RPCCallTestData::bad_cast, R"()", }, {// Note: this really shouldn't throw, but does at the moment. "account_tx: RIPD-1570.", __LINE__, - {"account_tx", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "-1", - "-1", - "2", - "false", - "false", - "false"}, + {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "-1", "-1", "2", "false", "false", "false"}, RPCCallTestData::bad_cast, R"()"}, @@ -1519,11 +1417,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"book_offers: add issuer and numeric ledger index.", __LINE__, - {"book_offers", - "USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "EUR", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "666"}, + {"book_offers", "USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "EUR", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "666"}, RPCCallTestData::no_exception, R"({ "method" : "book_offers", @@ -1544,11 +1438,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"book_offers: add issuer and text ledger index.", __LINE__, - {"book_offers", - "USD", - "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", - "current"}, + {"book_offers", "USD", "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "current"}, RPCCallTestData::no_exception, R"({ "method" : "book_offers", @@ -1601,8 +1491,6 @@ static RPCCallTestData const rpcCallTestArray[] = { "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", - "junk", // Note: indexing bug in parseBookOffers() requires junk - // param. "200", }, RPCCallTestData::no_exception, @@ -1614,7 +1502,6 @@ static RPCCallTestData const rpcCallTestArray[] = { "issuer" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "ledger_hash" : "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", "limit" : 200, - "proof" : true, "taker_gets" : { "currency" : "EUR", "issuer" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA" @@ -1634,8 +1521,8 @@ static RPCCallTestData const rpcCallTestArray[] = { "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", - "junk", // Note: indexing bug in parseBookOffers() requires junk param. "200", + "0", "MyMarker"}, RPCCallTestData::no_exception, R"({ @@ -1647,7 +1534,6 @@ static RPCCallTestData const rpcCallTestArray[] = { "ledger_hash" : "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", "limit" : 200, "marker" : "MyMarker", - "proof" : true, "taker_gets" : { "currency" : "EUR", "issuer" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA" @@ -1682,8 +1568,8 @@ static RPCCallTestData const rpcCallTestArray[] = { "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", - "junk", // Note: indexing bug in parseBookOffers() requires junk param. "200", + "0", "MyMarker", "extra"}, RPCCallTestData::no_exception, @@ -1787,12 +1673,19 @@ static RPCCallTestData const rpcCallTestArray[] = { "EUR/rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", - "junk", // Note: indexing bug in parseBookOffers() requires junk - // param. "not_a_number", }, - RPCCallTestData::bad_cast, - R"()"}, + RPCCallTestData::no_exception, + R"({ + "method" : "book_offers", + "params" : [ + { + "error" : "invalidParams", + "error_code" : 31, + "error_message" : "Invalid field 'limit'." + } + ] + })"}, // can_delete // ------------------------------------------------------------------ @@ -2439,10 +2332,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"deposit_authorized: with text ledger index.", __LINE__, - {"deposit_authorized", - "source_account_NotValidated", - "destination_account_NotValidated", - "validated"}, + {"deposit_authorized", "source_account_NotValidated", "destination_account_NotValidated", "validated"}, RPCCallTestData::no_exception, R"({ "method" : "deposit_authorized", @@ -2775,9 +2665,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"gateway_balances: 1 hotwallet.", __LINE__, - {"gateway_balances", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "hotwallet_is_not_validated"}, + {"gateway_balances", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "hotwallet_is_not_validated"}, RPCCallTestData::no_exception, R"({ "method" : "gateway_balances", @@ -2948,11 +2836,7 @@ static RPCCallTestData const rpcCallTestArray[] = { }, RPCCallTestData::bad_cast, R"()"}, - {"get_counts: count too large.", - __LINE__, - {"get_counts", "4294967296"}, - RPCCallTestData::bad_cast, - R"()"}, + {"get_counts: count too large.", __LINE__, {"get_counts", "4294967296"}, RPCCallTestData::bad_cast, R"()"}, // json // ------------------------------------------------------------------------ @@ -3179,9 +3063,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"json2: too many arguments.", __LINE__, - {"json2", - R"({"jsonrpc":"2.0","ripplerpc":"2.0","id":"A1","method":"call_this"})", - "extra"}, + {"json2", R"({"jsonrpc":"2.0","ripplerpc":"2.0","id":"A1","method":"call_this"})", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "json2", @@ -3477,8 +3359,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"ledger: ledger hash.", __LINE__, - {"ledger", - "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, + {"ledger", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, RPCCallTestData::no_exception, R"({ "method" : "ledger", @@ -3659,8 +3540,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"ledger_header: ledger hash.", __LINE__, - {"ledger_header", - "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, + {"ledger_header", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, RPCCallTestData::no_exception, R"({ "method" : "ledger_header", @@ -3758,8 +3638,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"ledger_request: ledger hash.", __LINE__, - {"ledger_request", - "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, + {"ledger_request", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789"}, RPCCallTestData::no_exception, R"({ "method" : "ledger_request", @@ -3935,7 +3814,7 @@ static RPCCallTestData const rpcCallTestArray[] = { } ] })"}, - {"log_level: partiton_name.", + {"log_level: partition_name.", __LINE__, {"log_level", "partition_name", "fatal"}, RPCCallTestData::no_exception, @@ -4267,10 +4146,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"peer_reservations_add: too many arguments.", __LINE__, - {"peer_reservations_add", - "public_key_string", - "public_key_description", - "spare"}, + {"peer_reservations_add", "public_key_string", "public_key_description", "spare"}, RPCCallTestData::no_exception, R"({ "method" : "peer_reservations_add", @@ -4314,10 +4190,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"peer_reservations_del: too many arguments.", __LINE__, - {"peer_reservations_del", - "public_key_string", - "public_key_description", - "spare"}, + {"peer_reservations_del", "public_key_string", "public_key_description", "spare"}, RPCCallTestData::no_exception, R"({ "method" : "peer_reservations_del", @@ -4664,12 +4537,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"sign: too many arguments.", __LINE__, - {"sign", - "my_secret", - R"({"json_argument":true})", - "offline", - "CounterpartySignature", - "extra"}, + {"sign", "my_secret", R"({"json_argument":true})", "offline", "CounterpartySignature", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "sign", @@ -4744,11 +4612,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"sign_for: offline.", __LINE__, - {"sign_for", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "my_secret", - R"({"json_argument":true})", - "offline"}, + {"sign_for", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "my_secret", R"({"json_argument":true})", "offline"}, RPCCallTestData::no_exception, R"({ "method" : "sign_for", @@ -4784,12 +4648,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"sign_for: too many arguments.", __LINE__, - {"sign_for", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "my_secret", - R"({"json_argument":true})", - "offline", - "extra"}, + {"sign_for", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "my_secret", R"({"json_argument":true})", "offline", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "sign_for", @@ -4822,11 +4681,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"sign_for: invalid final argument.", __LINE__, - {"sign_for", - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "my_secret", - R"({"json_argument":true})", - "ofline"}, + {"sign_for", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "my_secret", R"({"json_argument":true})", "ofline"}, RPCCallTestData::no_exception, R"({ "method" : "sign_for", @@ -4929,12 +4784,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"submit: too many arguments.", __LINE__, - {"submit", - "my_secret", - R"({"json_argument":true})", - "offline", - "CounterpartySignature", - "extra"}, + {"submit", "my_secret", R"({"json_argument":true})", "offline", "CounterpartySignature", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "submit", @@ -5199,9 +5049,7 @@ static RPCCallTestData const rpcCallTestArray[] = { // ----------------------------------------------------------- {"transaction_entry: ledger index.", __LINE__, - {"transaction_entry", - "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", - "4294967295"}, + {"transaction_entry", "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", "4294967295"}, RPCCallTestData::no_exception, R"({ "method" : "transaction_entry", @@ -5215,9 +5063,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"transaction_entry: text ledger index.", __LINE__, - {"transaction_entry", - "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", - "current"}, + {"transaction_entry", "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", "current"}, RPCCallTestData::no_exception, R"({ "method" : "transaction_entry", @@ -5264,10 +5110,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"transaction_entry: too many arguments.", __LINE__, - {"transaction_entry", - "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", - "validated", - "extra"}, + {"transaction_entry", "0123456789ABCDEFGHIJKLMNOPQRSTUV0123456789ABCDEFGHIJKLMNOPQRSTUV", "validated", "extra"}, RPCCallTestData::no_exception, R"({ "method" : "transaction_entry", @@ -5730,13 +5573,7 @@ static RPCCallTestData const rpcCallTestArray[] = { })"}, {"internal: with parameters.", __LINE__, - {"internal", - "command_name", - "string_arg", - "1", - "-1", - "4294967296", - "3.14159"}, + {"internal", "command_name", "string_arg", "1", "-1", "4294967296", "3.14159"}, RPCCallTestData::no_exception, R"({ "method" : "internal", @@ -5922,13 +5759,10 @@ public: testRPCCall(unsigned apiVersion) { testcase << "RPCCall API version " << apiVersion; - if (!BEAST_EXPECT( - apiVersion >= RPC::apiMinimumSupportedVersion && - apiVersion <= RPC::apiMaximumValidVersion)) + if (!BEAST_EXPECT(apiVersion >= RPC::apiMinimumSupportedVersion && apiVersion <= RPC::apiMaximumValidVersion)) return; - test::jtx::Env env( - *this, makeNetworkConfig(11111)); // Used only for its Journal. + test::jtx::Env env(*this, makeNetworkConfig(11111)); // Used only for its Journal. // For each RPCCall test. for (RPCCallTestData const& rpcCallTest : rpcCallTestArray) @@ -5936,12 +5770,9 @@ public: if (!BEAST_EXPECT(!rpcCallTest.exp.empty())) break; - std::vector const args{ - rpcCallTest.args.begin(), rpcCallTest.args.end()}; + std::vector const args{rpcCallTest.args.begin(), rpcCallTest.args.end()}; - char const* const expVersioned = - (apiVersion - RPC::apiMinimumSupportedVersion) < - rpcCallTest.exp.size() + char const* const expVersioned = (apiVersion - RPC::apiMinimumSupportedVersion) < rpcCallTest.exp.size() ? rpcCallTest.exp[apiVersion - RPC::apiMinimumSupportedVersion] : rpcCallTest.exp.back(); @@ -5954,8 +5785,7 @@ public: } catch (std::bad_cast const&) { - if ((rpcCallTest.throwsWhat == RPCCallTestData::bad_cast) && - (std::strlen(expVersioned) == 0)) + if ((rpcCallTest.throwsWhat == RPCCallTestData::bad_cast) && (std::strlen(expVersioned) == 0)) { pass(); } @@ -5968,14 +5798,12 @@ public: } Json::Value exp; - Json::Reader{}.parse( - updateAPIVersionString(expVersioned, apiVersion), exp); + Json::Reader{}.parse(updateAPIVersionString(expVersioned, apiVersion), exp); // Lambda to remove the "params[0u]:error_code" field if present. // Error codes are not expected to be stable between releases. auto rmErrorCode = [](Json::Value& json) { - if (json.isMember(jss::params) && json[jss::params].isArray() && - json[jss::params].size() > 0 && + if (json.isMember(jss::params) && json[jss::params].isArray() && json[jss::params].size() > 0 && json[jss::params][0u].isObject()) { json[jss::params][0u].removeMember(jss::error_code); @@ -5985,8 +5813,7 @@ public: rmErrorCode(exp); // Pass if we didn't expect a throw and we got what we expected. - if ((rpcCallTest.throwsWhat == RPCCallTestData::no_exception) && - (got == exp)) + if ((rpcCallTest.throwsWhat == RPCCallTestData::no_exception) && (got == exp)) { pass(); } @@ -6004,7 +5831,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RPCCall, rpc, ripple); +BEAST_DEFINE_TESTSUITE(RPCCall, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/RPCHelpers_test.cpp b/src/test/rpc/RPCHelpers_test.cpp index 1716301dae..f180bd5c1a 100644 --- a/src/test/rpc/RPCHelpers_test.cpp +++ b/src/test/rpc/RPCHelpers_test.cpp @@ -1,26 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { class RPCHelpers_test : public beast::unit_test::suite @@ -87,7 +70,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RPCHelpers, rpc, ripple); +BEAST_DEFINE_TESTSUITE(RPCHelpers, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/RPCOverload_test.cpp b/src/test/rpc/RPCOverload_test.cpp index 35755eff20..c8f02cd0a3 100644 --- a/src/test/rpc/RPCOverload_test.cpp +++ b/src/test/rpc/RPCOverload_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class RPCOverload_test : public beast::unit_test::suite @@ -44,9 +27,8 @@ public: Account const bob{"bob"}; env.fund(XRP(10000), alice, bob); - std::unique_ptr client = useWS - ? makeWSClient(env.app().config()) - : makeJSONRPCClient(env.app().config()); + std::unique_ptr client = + useWS ? makeWSClient(env.app().config()) : makeJSONRPCClient(env.app().config()); Json::Value tx = Json::objectValue; tx[jss::tx_json] = pay(alice, bob, XRP(1)); @@ -64,8 +46,7 @@ public: // When booted, we just get a null json response if (jv.isNull()) booted = true; - else if (!(jv.isMember(jss::status) && - (jv[jss::status] == "success"))) + else if (!(jv.isMember(jss::status) && (jv[jss::status] == "success"))) { // Don't use BEAST_EXPECT above b/c it will be called a // non-deterministic number of times and the number of tests run @@ -87,7 +68,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RPCOverload, rpc, ripple); +BEAST_DEFINE_TESTSUITE(RPCOverload, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/RobustTransaction_test.cpp b/src/test/rpc/RobustTransaction_test.cpp index bfd9e6251b..0934543fe0 100644 --- a/src/test/rpc/RobustTransaction_test.cpp +++ b/src/test/rpc/RobustTransaction_test.cpp @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -#include - #include +#include #include -namespace ripple { +namespace xrpl { namespace test { class RobustTransaction_test : public beast::unit_test::suite @@ -50,10 +30,8 @@ public: BEAST_EXPECT(jv[jss::status] == "success"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } } @@ -67,14 +45,11 @@ public: auto jv = wsc->invoke("submit", payment); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } - BEAST_EXPECT( - jv[jss::result][jss::engine_result] == "tefMAX_LEDGER"); + BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tefMAX_LEDGER"); // Submit past sequence transaction payment[jss::tx_json] = pay("alice", "bob", XRP(1)); @@ -82,10 +57,8 @@ public: jv = wsc->invoke("submit", payment); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tefPAST_SEQ"); @@ -95,10 +68,8 @@ public: jv = wsc->invoke("submit", payment); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "terPRE_SEQ"); @@ -108,10 +79,8 @@ public: jv = wsc->invoke("submit", payment); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS"); @@ -123,10 +92,8 @@ public: jv = wsc->invoke("ledger_accept"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index)); @@ -135,17 +102,13 @@ public: { // Check balances BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - auto const& ff = jv[jss::meta]["AffectedNodes"][1u] - ["ModifiedNode"]["FinalFields"]; - return ff[jss::Account] == Account("bob").human() && - ff["Balance"] == "10001000000"; + auto const& ff = jv[jss::meta]["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; + return ff[jss::Account] == Account("bob").human() && ff["Balance"] == "10001000000"; })); BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - auto const& ff = jv[jss::meta]["AffectedNodes"][1u] - ["ModifiedNode"]["FinalFields"]; - return ff[jss::Account] == Account("bob").human() && - ff["Balance"] == "10002000000"; + auto const& ff = jv[jss::meta]["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; + return ff[jss::Account] == Account("bob").human() && ff["Balance"] == "10002000000"; })); } @@ -157,10 +120,8 @@ public: jv = wsc->invoke("unsubscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -195,10 +156,8 @@ public: jv = wsc->invoke("submit", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS"); @@ -220,16 +179,14 @@ public: jv = wsc->invoke("account_tx", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } // Check balance - auto ff = jv[jss::result][jss::transactions][0u][jss::meta] - ["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; + auto ff = + jv[jss::result][jss::transactions][0u][jss::meta]["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; BEAST_EXPECT(ff[jss::Account] == Account("bob").human()); BEAST_EXPECT(ff["Balance"] == "10001000000"); } @@ -253,10 +210,8 @@ public: jv = wsc->invoke("submit", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS"); @@ -265,10 +220,8 @@ public: jv = wsc->invoke("ledger_accept"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index)); @@ -286,11 +239,8 @@ public: jv = wsc->invoke("subscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -302,22 +252,16 @@ public: auto jv = wsc->invoke("ledger_accept"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } - BEAST_EXPECT( - jv[jss::result].isMember(jss::ledger_current_index)); + BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index)); // Wait for the jobqueue to process everything env.app().getJobQueue().rendezvous(); - BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { - return jval[jss::type] == "ledgerClosed"; - })); + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { return jval[jss::type] == "ledgerClosed"; })); } { @@ -328,11 +272,8 @@ public: jv = wsc->invoke("unsubscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -350,11 +291,8 @@ public: jv = wsc->invoke("subscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -366,22 +304,16 @@ public: auto jv = wsc->invoke("ledger_accept"); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } - BEAST_EXPECT( - jv[jss::result].isMember(jss::ledger_current_index)); + BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index)); // Wait for the jobqueue to process everything env.app().getJobQueue().rendezvous(); - BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { - return jval[jss::type] == "ledgerClosed"; - })); + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jval) { return jval[jss::type] == "ledgerClosed"; })); } { @@ -392,11 +324,8 @@ public: jv = wsc->invoke("unsubscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && - jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -413,16 +342,14 @@ public: jv = wsc->invoke("account_tx", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } // Check balance - auto ff = jv[jss::result][jss::transactions][0u][jss::meta] - ["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; + auto ff = + jv[jss::result][jss::transactions][0u][jss::meta]["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"]; BEAST_EXPECT(ff[jss::Account] == Account("bob").human()); BEAST_EXPECT(ff["Balance"] == "10001000000"); } @@ -446,10 +373,8 @@ public: jv = wsc->invoke("subscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -460,15 +385,12 @@ public: Json::Value jv; jv[jss::secret] = toBase58(generateSeed("alice")); jv[jss::tx_json] = fset("alice", 0); - jv[jss::tx_json][jss::Fee] = - static_cast(env.current()->fees().base.drops()); + jv[jss::tx_json][jss::Fee] = static_cast(env.current()->fees().base.drops()); jv = wsc->invoke("submit", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS"); @@ -476,10 +398,8 @@ public: { // Check stream update - BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::transaction][jss::TransactionType] == - jss::AccountSet; - })); + BEAST_EXPECT(wsc->findMsg( + 5s, [&](auto const& jv) { return jv[jss::transaction][jss::TransactionType] == jss::AccountSet; })); } { @@ -490,10 +410,8 @@ public: jv = wsc->invoke("unsubscribe", jv); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -510,7 +428,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(RobustTransaction, rpc, ripple); +BEAST_DEFINE_TESTSUITE(RobustTransaction, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Roles_test.cpp b/src/test/rpc/Roles_test.cpp index 949d84c1e5..1750532a10 100644 --- a/src/test/rpc/Roles_test.cpp +++ b/src/test/rpc/Roles_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -48,27 +29,21 @@ class Roles_test : public beast::unit_test::suite Env env(*this); BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin"); - BEAST_EXPECT(makeWSClient(env.app().config()) - ->invoke("ping")["result"]["unlimited"] - .asBool()); + BEAST_EXPECT(makeWSClient(env.app().config())->invoke("ping")["result"]["unlimited"].asBool()); } { Env env{*this, envconfig(no_admin)}; BEAST_EXPECT(!env.rpc("ping")["result"].isMember("role")); - auto wsRes = - makeWSClient(env.app().config())->invoke("ping")["result"]; - BEAST_EXPECT( - !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); + auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"]; + BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); } { Env env{*this, envconfig(secure_gateway)}; BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied"); - auto wsRes = - makeWSClient(env.app().config())->invoke("ping")["result"]; - BEAST_EXPECT( - !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); + auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"]; + BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); std::unordered_map headers; Json::Value rpcRes; @@ -131,10 +106,8 @@ class Roles_test : public beast::unit_test::suite BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - wsRes = makeWSClient(env.app().config(), true, 2, headers) - ->invoke("ping")["result"]; - BEAST_EXPECT( - !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); + wsRes = makeWSClient(env.app().config(), true, 2, headers)->invoke("ping")["result"]; + BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); std::string const name = "xrposhi"; headers["X-User"] = name; @@ -143,18 +116,15 @@ class Roles_test : public beast::unit_test::suite BEAST_EXPECT(rpcRes["username"] == name); BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - wsRes = makeWSClient(env.app().config(), true, 2, headers) - ->invoke("ping")["result"]; + wsRes = makeWSClient(env.app().config(), true, 2, headers)->invoke("ping")["result"]; BEAST_EXPECT(wsRes["unlimited"].asBool()); // IPv6 tests. headers = {}; - headers["X-Forwarded-For"] = - "2001:db8:3333:4444:5555:6666:7777:8888"; + headers["X-Forwarded-For"] = "2001:db8:3333:4444:5555:6666:7777:8888"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers["X-Forwarded-For"] = @@ -162,16 +132,13 @@ class Roles_test : public beast::unit_test::suite "g:h:i:j:k:l"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - headers["X-Forwarded-For"] = - "[2001:db8:3333:4444:5555:6666:7777:8888]"; + headers["X-Forwarded-For"] = "[2001:db8:3333:4444:5555:6666:7777:8888]"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers["X-Forwarded-For"] = @@ -179,21 +146,17 @@ class Roles_test : public beast::unit_test::suite "[g:h:i:j:k:l]"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers = {}; - headers["Forwarded"] = - "for=\"[2001:db8:3333:4444:5555:6666:7777:aaaa]\""; + headers["Forwarded"] = "for=\"[2001:db8:3333:4444:5555:6666:7777:aaaa]\""; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:aaaa"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:aaaa"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - headers["Forwarded"] = - "For=\"[2001:db8:bb:cc:dd:ee:ff::]:2345\", for=99.00.11.22"; + headers["Forwarded"] = "For=\"[2001:db8:bb:cc:dd:ee:ff::]:2345\", for=99.00.11.22"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc:dd:ee:ff::"); @@ -212,8 +175,7 @@ class Roles_test : public beast::unit_test::suite headers["X-Forwarded-For"] = "2001:db8:3333:4444:5555:6666:1.2.3.4"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:1.2.3.4"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:1.2.3.4"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers["X-Forwarded-For"] = @@ -221,16 +183,13 @@ class Roles_test : public beast::unit_test::suite "g:h:i:j:k:l"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:5.6.7.8"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:5.6.7.8"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - headers["X-Forwarded-For"] = - "[2001:db8:3333:4444:5555:6666:9.10.11.12]"; + headers["X-Forwarded-For"] = "[2001:db8:3333:4444:5555:6666:9.10.11.12]"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:9.10.11.12"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:9.10.11.12"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers["X-Forwarded-For"] = @@ -238,21 +197,17 @@ class Roles_test : public beast::unit_test::suite "[g:h:i:j:k:l]"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:13.14.15.16"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:13.14.15.16"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); headers = {}; - headers["Forwarded"] = - "for=\"[2001:db8:3333:4444:5555:6666:20.19.18.17]\""; + headers["Forwarded"] = "for=\"[2001:db8:3333:4444:5555:6666:20.19.18.17]\""; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); - BEAST_EXPECT( - rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:20.19.18.17"); + BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:20.19.18.17"); BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString())); - headers["Forwarded"] = - "For=\"[2001:db8:bb:cc::24.23.22.21]\", for=99.00.11.22"; + headers["Forwarded"] = "For=\"[2001:db8:bb:cc::24.23.22.21]\", for=99.00.11.22"; rpcRes = env.rpc(headers, "ping")["result"]; BEAST_EXPECT(rpcRes["role"] == "proxied"); BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc::24.23.22.21"); @@ -270,18 +225,14 @@ class Roles_test : public beast::unit_test::suite { Env env{*this, envconfig(admin_localnet)}; BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin"); - BEAST_EXPECT(makeWSClient(env.app().config()) - ->invoke("ping")["result"]["unlimited"] - .asBool()); + BEAST_EXPECT(makeWSClient(env.app().config())->invoke("ping")["result"]["unlimited"].asBool()); } { Env env{*this, envconfig(secure_gateway_localnet)}; BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied"); - auto wsRes = - makeWSClient(env.app().config())->invoke("ping")["result"]; - BEAST_EXPECT( - !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); + auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"]; + BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool()); std::unordered_map headers; headers["X-Forwarded-For"] = "12.34.56.78"; @@ -389,8 +340,8 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Roles, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Roles, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/ServerDefinitions_test.cpp b/src/test/rpc/ServerDefinitions_test.cpp index 2c0101f947..20bd6ba363 100644 --- a/src/test/rpc/ServerDefinitions_test.cpp +++ b/src/test/rpc/ServerDefinitions_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -43,8 +24,7 @@ public: BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS)); BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); - BEAST_EXPECT( - result[jss::result].isMember(jss::TRANSACTION_RESULTS)); + BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::hash)); @@ -55,26 +35,17 @@ public: { auto const firstField = result[jss::result][jss::FIELDS][0u]; BEAST_EXPECT(firstField[0u].asString() == "Generic"); - BEAST_EXPECT( - firstField[1][jss::isSerialized].asBool() == false); - BEAST_EXPECT( - firstField[1][jss::isSigningField].asBool() == false); + BEAST_EXPECT(firstField[1][jss::isSerialized].asBool() == false); + BEAST_EXPECT(firstField[1][jss::isSigningField].asBool() == false); BEAST_EXPECT(firstField[1][jss::isVLEncoded].asBool() == false); BEAST_EXPECT(firstField[1][jss::nth].asUInt() == 0); BEAST_EXPECT(firstField[1][jss::type].asString() == "Unknown"); } - BEAST_EXPECT( - result[jss::result][jss::LEDGER_ENTRY_TYPES]["AccountRoot"] - .asUInt() == 97); - BEAST_EXPECT( - result[jss::result][jss::TRANSACTION_RESULTS]["tecDIR_FULL"] - .asUInt() == 121); - BEAST_EXPECT( - result[jss::result][jss::TRANSACTION_TYPES]["Payment"] - .asUInt() == 0); - BEAST_EXPECT( - result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); + BEAST_EXPECT(result[jss::result][jss::LEDGER_ENTRY_TYPES]["AccountRoot"].asUInt() == 97); + BEAST_EXPECT(result[jss::result][jss::TRANSACTION_RESULTS]["tecDIR_FULL"].asUInt() == 121); + BEAST_EXPECT(result[jss::result][jss::TRANSACTION_TYPES]["Payment"].asUInt() == 0); + BEAST_EXPECT(result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); // check exception SFields { @@ -115,18 +86,14 @@ public: Env env(*this); auto const firstResult = env.rpc("server_definitions"); auto const hash = firstResult[jss::result][jss::hash].asString(); - auto const hashParam = - std::string("{ ") + "\"hash\": \"" + hash + "\"}"; + auto const hashParam = std::string("{ ") + "\"hash\": \"" + hash + "\"}"; - auto const result = - env.rpc("json", "server_definitions", hashParam); + auto const result = env.rpc("json", "server_definitions", hashParam); BEAST_EXPECT(!result[jss::result].isMember(jss::error)); BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(!result[jss::result].isMember(jss::FIELDS)); - BEAST_EXPECT( - !result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); - BEAST_EXPECT( - !result[jss::result].isMember(jss::TRANSACTION_RESULTS)); + BEAST_EXPECT(!result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); + BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(!result[jss::result].isMember(jss::TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::hash)); @@ -138,17 +105,14 @@ public: std::string const hash = "54296160385A27154BFA70A239DD8E8FD4CC2DB7BA32D970BA3A5B132CF749" "D1"; - auto const hashParam = - std::string("{ ") + "\"hash\": \"" + hash + "\"}"; + auto const hashParam = std::string("{ ") + "\"hash\": \"" + hash + "\"}"; - auto const result = - env.rpc("json", "server_definitions", hashParam); + auto const result = env.rpc("json", "server_definitions", hashParam); BEAST_EXPECT(!result[jss::result].isMember(jss::error)); BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS)); BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); - BEAST_EXPECT( - result[jss::result].isMember(jss::TRANSACTION_RESULTS)); + BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::hash)); @@ -162,7 +126,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ServerDefinitions, rpc, ripple); +BEAST_DEFINE_TESTSUITE(ServerDefinitions, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index c131f7bc2b..054c3e563a 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -27,13 +8,12 @@ #include -namespace ripple { +namespace xrpl { namespace test { namespace validator_data { -static auto const public_key = - "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; +static auto const public_key = "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; static auto const token = "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n" @@ -71,8 +51,7 @@ protocol = wss2 admin = 127.0.0.1 )rippleConfig"); - p->loadFromString(boost::str( - toLoad % validator_data::token % validator_data::public_key)); + p->loadFromString(boost::str(toLoad % validator_data::token % validator_data::public_key)); setupConfigForUnitTests(*p); @@ -100,16 +79,12 @@ admin = 127.0.0.1 if (info.isMember(jss::git)) { auto const& git = info[jss::git]; + BEAST_EXPECT(git.isMember(jss::hash) || git.isMember(jss::branch)); BEAST_EXPECT( - git.isMember(jss::hash) || git.isMember(jss::branch)); - BEAST_EXPECT( - !git.isMember(jss::hash) || - (git[jss::hash].isString() && - git[jss::hash].asString().size() == 40)); + !git.isMember(jss::hash) || (git[jss::hash].isString() && git[jss::hash].asString().size() == 40)); BEAST_EXPECT( !git.isMember(jss::branch) || - (git[jss::branch].isString() && - git[jss::branch].asString().size() != 0)); + (git[jss::branch].isString() && git[jss::branch].asString().size() != 0)); } } @@ -117,8 +92,7 @@ admin = 127.0.0.1 Env env(*this); // Call NetworkOPs directly and set the admin flag to false. - auto const result = - env.app().getOPs().getServerInfo(true, false, 0); + auto const result = env.app().getOPs().getServerInfo(true, false, 0); // Expect that the admin ports are not included in the result. auto const& ports = result[jss::ports]; BEAST_EXPECT(ports.isArray() && ports.size() == 0); @@ -131,8 +105,7 @@ admin = 127.0.0.1 auto const& config = env.app().config(); auto const rpc_port = config["port_rpc"].get("port"); - auto const grpc_port = - config[SECTION_PORT_GRPC].get("port"); + auto const grpc_port = config[SECTION_PORT_GRPC].get("port"); auto const ws_port = config["port_ws"].get("port"); BEAST_EXPECT(grpc_port); BEAST_EXPECT(rpc_port); @@ -142,9 +115,7 @@ admin = 127.0.0.1 BEAST_EXPECT(!result[jss::result].isMember(jss::error)); BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result].isMember(jss::info)); - BEAST_EXPECT( - result[jss::result][jss::info][jss::pubkey_validator] == - validator_data::public_key); + BEAST_EXPECT(result[jss::result][jss::info][jss::pubkey_validator] == validator_data::public_key); auto const& ports = result[jss::result][jss::info][jss::ports]; BEAST_EXPECT(ports.isArray() && ports.size() == 3); @@ -181,7 +152,7 @@ admin = 127.0.0.1 } }; -BEAST_DEFINE_TESTSUITE(ServerInfo, rpc, ripple); +BEAST_DEFINE_TESTSUITE(ServerInfo, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Simulate_test.cpp b/src/test/rpc/Simulate_test.cpp index 5e7ab5be4d..194b0296ec 100644 --- a/src/test/rpc/Simulate_test.cpp +++ b/src/test/rpc/Simulate_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { @@ -50,8 +31,7 @@ class Simulate_test : public beast::unit_test::suite BEAST_EXPECT(result.isMember(jss::engine_result)); BEAST_EXPECT(result.isMember(jss::engine_result_code)); BEAST_EXPECT(result.isMember(jss::engine_result_message)); - BEAST_EXPECT( - result.isMember(jss::tx_json) || result.isMember(jss::tx_blob)); + BEAST_EXPECT(result.isMember(jss::tx_json) || result.isMember(jss::tx_blob)); Json::Value tx_json; if (result.isMember(jss::tx_json)) @@ -62,18 +42,14 @@ class Simulate_test : public beast::unit_test::suite { auto const unHexed = strUnHex(result[jss::tx_blob].asString()); SerialIter sitTrans(makeSlice(*unHexed)); - tx_json = STObject(std::ref(sitTrans), sfGeneric) - .getJson(JsonOptions::none); + tx_json = STObject(std::ref(sitTrans), sfGeneric).getJson(JsonOptions::none); } BEAST_EXPECT(tx_json[jss::TransactionType] == tx[jss::TransactionType]); BEAST_EXPECT(tx_json[jss::Account] == tx[jss::Account]); - BEAST_EXPECT( - tx_json[jss::SigningPubKey] == tx.get(jss::SigningPubKey, "")); - BEAST_EXPECT( - tx_json[jss::TxnSignature] == tx.get(jss::TxnSignature, "")); + BEAST_EXPECT(tx_json[jss::SigningPubKey] == tx.get(jss::SigningPubKey, "")); + BEAST_EXPECT(tx_json[jss::TxnSignature] == tx.get(jss::TxnSignature, "")); BEAST_EXPECT(tx_json[jss::Fee] == tx.get(jss::Fee, expectedFee)); - BEAST_EXPECT( - tx_json[jss::Sequence] == tx.get(jss::Sequence, expectedSequence)); + BEAST_EXPECT(tx_json[jss::Sequence] == tx.get(jss::Sequence, expectedSequence)); } void @@ -83,16 +59,14 @@ class Simulate_test : public beast::unit_test::suite int const expectedSequence, XRPAmount const& expectedFee) { - return checkBasicReturnValidity( - result, tx, expectedSequence, expectedFee.jsonClipped().asString()); + return checkBasicReturnValidity(result, tx, expectedSequence, expectedFee.jsonClipped().asString()); } void testTx( jtx::Env& env, Json::Value const& tx, - std::function const& - validate, + std::function const& validate, bool testSerialized = true) { env.close(); @@ -112,8 +86,7 @@ class Simulate_test : public beast::unit_test::suite // It is technically not a valid STObject, so the following line // will crash STParsedJSONObject const parsed(std::string(jss::tx_json), tx); - auto const tx_blob = - strHex(parsed.object->getSerializer().peekData()); + auto const tx_blob = strHex(parsed.object->getSerializer().peekData()); if (BEAST_EXPECT(parsed.object.has_value())) { Json::Value params; @@ -126,20 +99,15 @@ class Simulate_test : public beast::unit_test::suite validate(env.rpc("simulate", tx_blob, "binary"), tx); } - BEAST_EXPECTS( - env.current()->txCount() == 0, - std::to_string(env.current()->txCount())); + BEAST_EXPECTS(env.current()->txCount() == 0, std::to_string(env.current()->txCount())); } void testTxJsonMetadataField( jtx::Env& env, Json::Value const& tx, - std::function const& validate, + std::function const& + validate, Json::Value const& expectedMetadataKey, Json::Value const& expectedMetadataValue) { @@ -147,20 +115,10 @@ class Simulate_test : public beast::unit_test::suite Json::Value params; params[jss::tx_json] = tx; - validate( - env.rpc("json", "simulate", to_string(params)), - tx, - expectedMetadataKey, - expectedMetadataValue); - validate( - env.rpc("simulate", to_string(tx)), - tx, - expectedMetadataKey, - expectedMetadataValue); + validate(env.rpc("json", "simulate", to_string(params)), tx, expectedMetadataKey, expectedMetadataValue); + validate(env.rpc("simulate", to_string(tx)), tx, expectedMetadataKey, expectedMetadataValue); - BEAST_EXPECTS( - env.current()->txCount() == 0, - std::to_string(env.current()->txCount())); + BEAST_EXPECTS(env.current()->txCount() == 0, std::to_string(env.current()->txCount())); } Json::Value @@ -170,8 +128,7 @@ class Simulate_test : public beast::unit_test::suite { auto unHexed = strUnHex(txResult[jss::meta_blob].asString()); SerialIter sitTrans(makeSlice(*unHexed)); - return STObject(std::ref(sitTrans), sfGeneric) - .getJson(JsonOptions::none); + return STObject(std::ref(sitTrans), sfGeneric).getJson(JsonOptions::none); } return txResult[jss::meta]; @@ -190,9 +147,7 @@ class Simulate_test : public beast::unit_test::suite // No params Json::Value const params = Json::objectValue; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Neither `tx_blob` nor `tx_json` included."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Neither `tx_blob` nor `tx_json` included."); } { // Providing both `tx_json` and `tx_blob` @@ -201,9 +156,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_blob] = "1200"; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Can only include one of `tx_blob` and `tx_json`."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Can only include one of `tx_blob` and `tx_json`."); } { // `binary` isn't a boolean @@ -211,9 +164,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_blob] = "1200"; params[jss::binary] = "100"; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'binary'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'binary'."); } { // Invalid `tx_blob` @@ -221,9 +172,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_blob] = "12"; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx_blob'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx_blob'."); } { // Empty `tx_json` @@ -231,9 +180,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = Json::objectValue; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Missing field 'tx.TransactionType'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Missing field 'tx.TransactionType'."); } { // No tx.Account @@ -243,9 +190,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Missing field 'tx.Account'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Missing field 'tx.Account'."); } { // Empty `tx_blob` @@ -253,9 +198,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_blob] = ""; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx_blob'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx_blob'."); } { // Non-string `tx_blob` @@ -263,9 +206,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_blob] = 1.1; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx_blob'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx_blob'."); } { // Non-object `tx_json` @@ -273,61 +214,51 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = ""; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx_json', not object."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx_json', not object."); } { // `seed` field included Json::Value params = Json::objectValue; - params[jss::seed] = "doesnt_matter"; + params[jss::seed] = "random_data"; Json::Value tx_json = Json::objectValue; tx_json[jss::TransactionType] = jss::AccountSet; tx_json[jss::Account] = env.master.human(); params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'seed'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'seed'."); } { // `secret` field included Json::Value params = Json::objectValue; - params[jss::secret] = "doesnt_matter"; + params[jss::secret] = "random_data"; Json::Value tx_json = Json::objectValue; tx_json[jss::TransactionType] = jss::AccountSet; tx_json[jss::Account] = env.master.human(); params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'secret'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'secret'."); } { // `seed_hex` field included Json::Value params = Json::objectValue; - params[jss::seed_hex] = "doesnt_matter"; + params[jss::seed_hex] = "random_data"; Json::Value tx_json = Json::objectValue; tx_json[jss::TransactionType] = jss::AccountSet; tx_json[jss::Account] = env.master.human(); params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'seed_hex'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'seed_hex'."); } { // `passphrase` field included Json::Value params = Json::objectValue; - params[jss::passphrase] = "doesnt_matter"; + params[jss::passphrase] = "random_data"; Json::Value tx_json = Json::objectValue; tx_json[jss::TransactionType] = jss::AccountSet; tx_json[jss::Account] = env.master.human(); params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'passphrase'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'passphrase'."); } { // Invalid transaction @@ -338,9 +269,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_exception] == - "Field 'Destination' is required but missing."); + BEAST_EXPECT(resp[jss::result][jss::error_exception] == "Field 'Destination' is required but missing."); } { // Bad account @@ -352,11 +281,8 @@ class Simulate_test : public beast::unit_test::suite auto const resp = env.rpc("json", "simulate", to_string(params)); BEAST_EXPECTS( - resp[jss::result][jss::error] == "srcActMalformed", - resp[jss::result][jss::error].toStyledString()); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx.Account'."); + resp[jss::result][jss::error] == "srcActMalformed", resp[jss::result][jss::error].toStyledString()); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx.Account'."); } { // Account doesn't exist for Sequence autofill @@ -367,9 +293,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Source account not found."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Source account not found."); } { // Invalid Signers field @@ -381,9 +305,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx.Signers'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx.Signers'."); } { // Invalid Signers field @@ -396,9 +318,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Invalid field 'tx.Signers[0]'."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx.Signers[0]'."); } { // Invalid transaction @@ -410,9 +330,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Field 'tx_json.foo' is unknown."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Field 'tx_json.foo' is unknown."); } { // non-`"binary"` second param for CLI @@ -432,9 +350,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Transaction should not be signed."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Transaction should not be signed."); } { // Signed multisig transaction @@ -455,9 +371,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = tx_json; auto const resp = env.rpc("json", "simulate", to_string(params)); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == - "Transaction should not be signed."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Transaction should not be signed."); } } @@ -469,8 +383,7 @@ class Simulate_test : public beast::unit_test::suite using namespace jtx; Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->section("transaction_queue") - .set("minimum_txn_in_ledger_standalone", "3"); + cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3"); return cfg; })); @@ -523,8 +436,7 @@ class Simulate_test : public beast::unit_test::suite params[jss::tx_json] = jt.jv; auto const resp = env.rpc("json", "simulate", to_string(params)); BEAST_EXPECT(resp[jss::result][jss::error] == "notImpl"); - BEAST_EXPECT( - resp[jss::result][jss::error_message] == "Not implemented."); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Not implemented."); } void @@ -540,44 +452,33 @@ class Simulate_test : public beast::unit_test::suite static auto const newDomain = "123ABC"; { - auto validateOutput = [&](Json::Value const& resp, - Json::Value const& tx) { + auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, 1, env.current()->fees().base); + checkBasicReturnValidity(result, tx, 1, env.current()->fees().base); BEAST_EXPECT(result[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(result[jss::engine_result_code] == 0); BEAST_EXPECT( - result[jss::engine_result_message] == - "The simulated transaction would have been applied."); + result[jss::engine_result_message] == "The simulated transaction would have been applied."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) { Json::Value const metadata = getJsonMetadata(result); - if (BEAST_EXPECT( - metadata.isMember(sfAffectedNodes.jsonName))) + if (BEAST_EXPECT(metadata.isMember(sfAffectedNodes.jsonName))) { - BEAST_EXPECT( - metadata[sfAffectedNodes.jsonName].size() == 1); + BEAST_EXPECT(metadata[sfAffectedNodes.jsonName].size() == 1); auto node = metadata[sfAffectedNodes.jsonName][0u]; - if (BEAST_EXPECT( - node.isMember(sfModifiedNode.jsonName))) + if (BEAST_EXPECT(node.isMember(sfModifiedNode.jsonName))) { auto modifiedNode = node[sfModifiedNode]; - BEAST_EXPECT( - modifiedNode[sfLedgerEntryType] == - "AccountRoot"); + BEAST_EXPECT(modifiedNode[sfLedgerEntryType] == "AccountRoot"); auto finalFields = modifiedNode[sfFinalFields]; BEAST_EXPECT(finalFields[sfDomain] == newDomain); } } BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); } }; @@ -610,22 +511,16 @@ class Simulate_test : public beast::unit_test::suite Account const alice("alice"); { - std::function const& - testSimulation = [&](Json::Value const& resp, - Json::Value const& tx) { + std::function const& testSimulation = + [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, 1, env.current()->fees().base); + checkBasicReturnValidity(result, tx, 1, env.current()->fees().base); BEAST_EXPECT(result[jss::engine_result] == "temBAD_AMOUNT"); BEAST_EXPECT(result[jss::engine_result_code] == -298); - BEAST_EXPECT( - result[jss::engine_result_message] == - "Malformed: Bad amount."); + BEAST_EXPECT(result[jss::engine_result_message] == "Malformed: Bad amount."); - BEAST_EXPECT( - !result.isMember(jss::meta) && - !result.isMember(jss::meta_blob)); + BEAST_EXPECT(!result.isMember(jss::meta) && !result.isMember(jss::meta_blob)); }; Json::Value tx; @@ -658,15 +553,12 @@ class Simulate_test : public beast::unit_test::suite Account const alice("alice"); { - std::function const& - testSimulation = [&](Json::Value const& resp, - Json::Value const& tx) { + std::function const& testSimulation = + [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, 1, env.current()->fees().base); + checkBasicReturnValidity(result, tx, 1, env.current()->fees().base); - BEAST_EXPECT( - result[jss::engine_result] == "tecNO_DST_INSUF_XRP"); + BEAST_EXPECT(result[jss::engine_result] == "tecNO_DST_INSUF_XRP"); BEAST_EXPECT(result[jss::engine_result_code] == 125); BEAST_EXPECT( result[jss::engine_result_message] == @@ -674,38 +566,26 @@ class Simulate_test : public beast::unit_test::suite "create " "it."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) { Json::Value const metadata = getJsonMetadata(result); - if (BEAST_EXPECT( - metadata.isMember(sfAffectedNodes.jsonName))) + if (BEAST_EXPECT(metadata.isMember(sfAffectedNodes.jsonName))) { - BEAST_EXPECT( - metadata[sfAffectedNodes.jsonName].size() == 1); + BEAST_EXPECT(metadata[sfAffectedNodes.jsonName].size() == 1); auto node = metadata[sfAffectedNodes.jsonName][0u]; - if (BEAST_EXPECT( - node.isMember(sfModifiedNode.jsonName))) + if (BEAST_EXPECT(node.isMember(sfModifiedNode.jsonName))) { auto modifiedNode = node[sfModifiedNode]; - BEAST_EXPECT( - modifiedNode[sfLedgerEntryType] == - "AccountRoot"); + BEAST_EXPECT(modifiedNode[sfLedgerEntryType] == "AccountRoot"); auto finalFields = modifiedNode[sfFinalFields]; BEAST_EXPECT( finalFields[sfBalance] == - std::to_string( - 100'000'000'000'000'000 - - env.current()->fees().base.drops())); + std::to_string(100'000'000'000'000'000 - env.current()->fees().base.drops())); } } - BEAST_EXPECT( - metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == - "tecNO_DST_INSUF_XRP"); + BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tecNO_DST_INSUF_XRP"); } }; @@ -748,48 +628,37 @@ class Simulate_test : public beast::unit_test::suite env.close(); { - auto validateOutput = [&](Json::Value const& resp, - Json::Value const& tx) { + auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; checkBasicReturnValidity( result, tx, env.seq(alice), - tx.isMember(jss::Signers) ? env.current()->fees().base * 2 - : env.current()->fees().base); + tx.isMember(jss::Signers) ? env.current()->fees().base * 2 : env.current()->fees().base); BEAST_EXPECT(result[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(result[jss::engine_result_code] == 0); BEAST_EXPECT( - result[jss::engine_result_message] == - "The simulated transaction would have been applied."); + result[jss::engine_result_message] == "The simulated transaction would have been applied."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) { Json::Value const metadata = getJsonMetadata(result); - if (BEAST_EXPECT( - metadata.isMember(sfAffectedNodes.jsonName))) + if (BEAST_EXPECT(metadata.isMember(sfAffectedNodes.jsonName))) { - BEAST_EXPECT( - metadata[sfAffectedNodes.jsonName].size() == 1); + BEAST_EXPECT(metadata[sfAffectedNodes.jsonName].size() == 1); auto node = metadata[sfAffectedNodes.jsonName][0u]; - if (BEAST_EXPECT( - node.isMember(sfModifiedNode.jsonName))) + if (BEAST_EXPECT(node.isMember(sfModifiedNode.jsonName))) { auto modifiedNode = node[sfModifiedNode]; - BEAST_EXPECT( - modifiedNode[sfLedgerEntryType] == - "AccountRoot"); + BEAST_EXPECT(modifiedNode[sfLedgerEntryType] == "AccountRoot"); auto finalFields = modifiedNode[sfFinalFields]; BEAST_EXPECT(finalFields[sfDomain] == newDomain); } } BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); } }; @@ -818,8 +687,7 @@ class Simulate_test : public beast::unit_test::suite tx[sfTxnSignature] = ""; tx[sfSequence] = env.seq(alice); // transaction requires a non-base fee - tx[sfFee] = - (env.current()->fees().base * 2).jsonClipped().asString(); + tx[sfFee] = (env.current()->fees().base * 2).jsonClipped().asString(); tx[sfSigners][0u][sfSigner][jss::SigningPubKey] = ""; tx[sfSigners][0u][sfSigner][jss::TxnSignature] = ""; @@ -842,27 +710,17 @@ class Simulate_test : public beast::unit_test::suite env.close(); { - std::function const& - testSimulation = - [&](Json::Value const& resp, Json::Value const& tx) { - auto result = resp[jss::result]; - checkBasicReturnValidity( - result, - tx, - env.seq(env.master), - env.current()->fees().base); + std::function const& testSimulation = + [&](Json::Value const& resp, Json::Value const& tx) { + auto result = resp[jss::result]; + checkBasicReturnValidity(result, tx, env.seq(env.master), env.current()->fees().base); - BEAST_EXPECT( - result[jss::engine_result] == "tefMASTER_DISABLED"); - BEAST_EXPECT(result[jss::engine_result_code] == -188); - BEAST_EXPECT( - result[jss::engine_result_message] == - "Master key is disabled."); + BEAST_EXPECT(result[jss::engine_result] == "tefMASTER_DISABLED"); + BEAST_EXPECT(result[jss::engine_result_code] == -188); + BEAST_EXPECT(result[jss::engine_result_message] == "Master key is disabled."); - BEAST_EXPECT( - !result.isMember(jss::meta) && - !result.isMember(jss::meta_blob)); - }; + BEAST_EXPECT(!result.isMember(jss::meta) && !result.isMember(jss::meta_blob)); + }; Json::Value tx; @@ -905,25 +763,16 @@ class Simulate_test : public beast::unit_test::suite env.close(); { - std::function const& - testSimulation = [&](Json::Value const& resp, - Json::Value const& tx) { + std::function const& testSimulation = + [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, - tx, - env.seq(env.master), - env.current()->fees().base * 2); + checkBasicReturnValidity(result, tx, env.seq(env.master), env.current()->fees().base * 2); BEAST_EXPECT(result[jss::engine_result] == "temINVALID"); BEAST_EXPECT(result[jss::engine_result_code] == -277); - BEAST_EXPECT( - result[jss::engine_result_message] == - "The transaction is ill-formed."); + BEAST_EXPECT(result[jss::engine_result_message] == "The transaction is ill-formed."); - BEAST_EXPECT( - !result.isMember(jss::meta) && - !result.isMember(jss::meta_blob)); + BEAST_EXPECT(!result.isMember(jss::meta) && !result.isMember(jss::meta_blob)); }; Json::Value tx; @@ -948,8 +797,7 @@ class Simulate_test : public beast::unit_test::suite tx[sfTxnSignature] = ""; tx[sfSequence] = env.seq(env.master); tx[sfFee] = env.current()->fees().base.jsonClipped().asString(); - tx[sfSigners][0u][sfSigner][jss::SigningPubKey] = - strHex(becky.pk().slice()); + tx[sfSigners][0u][sfSigner][jss::SigningPubKey] = strHex(becky.pk().slice()); tx[sfSigners][0u][sfSigner][jss::TxnSignature] = ""; // test without autofill @@ -976,23 +824,16 @@ class Simulate_test : public beast::unit_test::suite env(signers(alice, 1, {{becky, 1}, {carol, 1}})); { - auto validateOutput = [&](Json::Value const& resp, - Json::Value const& tx) { + auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, env.seq(alice), env.current()->fees().base * 2); + checkBasicReturnValidity(result, tx, env.seq(alice), env.current()->fees().base * 2); BEAST_EXPECTS( - result[jss::engine_result] == "tefBAD_SIGNATURE", - result[jss::engine_result].toStyledString()); + result[jss::engine_result] == "tefBAD_SIGNATURE", result[jss::engine_result].toStyledString()); BEAST_EXPECT(result[jss::engine_result_code] == -186); - BEAST_EXPECT( - result[jss::engine_result_message] == - "A signature is provided for a non-signer."); + BEAST_EXPECT(result[jss::engine_result_message] == "A signature is provided for a non-signer."); - BEAST_EXPECT( - !result.isMember(jss::meta) && - !result.isMember(jss::meta_blob)); + BEAST_EXPECT(!result.isMember(jss::meta) && !result.isMember(jss::meta_blob)); }; Json::Value tx; @@ -1017,8 +858,7 @@ class Simulate_test : public beast::unit_test::suite tx[sfTxnSignature] = ""; tx[sfSequence] = env.seq(alice); // transaction requires a non-base fee - tx[sfFee] = - (env.current()->fees().base * 2).jsonClipped().asString(); + tx[sfFee] = (env.current()->fees().base * 2).jsonClipped().asString(); tx[sfSigners][0u][sfSigner][jss::TxnSignature] = ""; // test without autofill @@ -1045,57 +885,40 @@ class Simulate_test : public beast::unit_test::suite auto const credType = "123ABC"; auto jv = credentials::create(subject, issuer, credType); - uint32_t const t = - env.current()->info().parentCloseTime.time_since_epoch().count(); + uint32_t const t = env.current()->header().parentCloseTime.time_since_epoch().count(); jv[sfExpiration.jsonName] = t; env(jv); env.close(); { - auto validateOutput = [&](Json::Value const& resp, - Json::Value const& tx) { + auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, env.seq(subject), env.current()->fees().base); + checkBasicReturnValidity(result, tx, env.seq(subject), env.current()->fees().base); BEAST_EXPECT(result[jss::engine_result] == "tecEXPIRED"); BEAST_EXPECT(result[jss::engine_result_code] == 148); - BEAST_EXPECT( - result[jss::engine_result_message] == - "Expiration time is passed."); + BEAST_EXPECT(result[jss::engine_result_message] == "Expiration time is passed."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) { Json::Value const metadata = getJsonMetadata(result); - if (BEAST_EXPECT( - metadata.isMember(sfAffectedNodes.jsonName))) + if (BEAST_EXPECT(metadata.isMember(sfAffectedNodes.jsonName))) { - BEAST_EXPECT( - metadata[sfAffectedNodes.jsonName].size() == 5); + BEAST_EXPECT(metadata[sfAffectedNodes.jsonName].size() == 5); try { bool found = false; - for (auto const& node : - metadata[sfAffectedNodes.jsonName]) + for (auto const& node : metadata[sfAffectedNodes.jsonName]) { if (node.isMember(sfDeletedNode.jsonName) && - node[sfDeletedNode.jsonName] - [sfLedgerEntryType.jsonName] - .asString() == "Credential") + node[sfDeletedNode.jsonName][sfLedgerEntryType.jsonName].asString() == "Credential") { - auto const deleted = - node[sfDeletedNode.jsonName] - [sfFinalFields.jsonName]; - found = deleted[jss::Issuer] == - issuer.human() && - deleted[jss::Subject] == - subject.human() && - deleted["CredentialType"] == - strHex(std::string_view(credType)); + auto const deleted = node[sfDeletedNode.jsonName][sfFinalFields.jsonName]; + found = deleted[jss::Issuer] == issuer.human() && + deleted[jss::Subject] == subject.human() && + deleted["CredentialType"] == strHex(std::string_view(credType)); break; } } @@ -1107,8 +930,7 @@ class Simulate_test : public beast::unit_test::suite } } BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == "tecEXPIRED"); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tecEXPIRED"); } }; @@ -1127,18 +949,14 @@ class Simulate_test : public beast::unit_test::suite } // check that expired credentials weren't deleted - auto const jle = - credentials::ledgerEntry(env, subject, issuer, credType); + auto const jle = credentials::ledgerEntry(env, subject, issuer, credType); BEAST_EXPECT( - jle.isObject() && jle.isMember(jss::result) && - !jle[jss::result].isMember(jss::error) && - jle[jss::result].isMember(jss::node) && - jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle.isObject() && jle.isMember(jss::result) && !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && jle[jss::result][jss::node].isMember("LedgerEntryType") && jle[jss::result][jss::node]["LedgerEntryType"] == jss::Credential && jle[jss::result][jss::node][jss::Issuer] == issuer.human() && jle[jss::result][jss::node][jss::Subject] == subject.human() && - jle[jss::result][jss::node]["CredentialType"] == - strHex(std::string_view(credType))); + jle[jss::result][jss::node]["CredentialType"] == strHex(std::string_view(credType))); BEAST_EXPECT(ownerCount(env, issuer) == 1); BEAST_EXPECT(ownerCount(env, subject) == 0); @@ -1157,44 +975,33 @@ class Simulate_test : public beast::unit_test::suite static auto const newDomain = "123ABC"; { - auto validateOutput = [&](Json::Value const& resp, - Json::Value const& tx) { + auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { auto result = resp[jss::result]; - checkBasicReturnValidity( - result, tx, 1, env.current()->fees().base); + checkBasicReturnValidity(result, tx, 1, env.current()->fees().base); BEAST_EXPECT(result[jss::engine_result] == "tesSUCCESS"); BEAST_EXPECT(result[jss::engine_result_code] == 0); BEAST_EXPECT( - result[jss::engine_result_message] == - "The simulated transaction would have been applied."); + result[jss::engine_result_message] == "The simulated transaction would have been applied."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) { Json::Value const metadata = getJsonMetadata(result); - if (BEAST_EXPECT( - metadata.isMember(sfAffectedNodes.jsonName))) + if (BEAST_EXPECT(metadata.isMember(sfAffectedNodes.jsonName))) { - BEAST_EXPECT( - metadata[sfAffectedNodes.jsonName].size() == 1); + BEAST_EXPECT(metadata[sfAffectedNodes.jsonName].size() == 1); auto node = metadata[sfAffectedNodes.jsonName][0u]; - if (BEAST_EXPECT( - node.isMember(sfModifiedNode.jsonName))) + if (BEAST_EXPECT(node.isMember(sfModifiedNode.jsonName))) { auto modifiedNode = node[sfModifiedNode]; - BEAST_EXPECT( - modifiedNode[sfLedgerEntryType] == - "AccountRoot"); + BEAST_EXPECT(modifiedNode[sfLedgerEntryType] == "AccountRoot"); auto finalFields = modifiedNode[sfFinalFields]; BEAST_EXPECT(finalFields[sfDomain] == newDomain); } } BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); } }; @@ -1240,37 +1047,27 @@ class Simulate_test : public beast::unit_test::suite env.close(NetClock::time_point{446000000s}); { - auto validateOutput = - [&](Json::Value const& resp, - Json::Value const& tx, - Json::Value const& expectedMetadataKey, - Json::Value const& expectedMetadataValue) { - auto result = resp[jss::result]; + auto validateOutput = [&](Json::Value const& resp, + Json::Value const& tx, + Json::Value const& expectedMetadataKey, + Json::Value const& expectedMetadataValue) { + auto result = resp[jss::result]; - BEAST_EXPECT(result[jss::engine_result] == "tesSUCCESS"); - BEAST_EXPECT(result[jss::engine_result_code] == 0); - BEAST_EXPECT( - result[jss::engine_result_message] == - "The simulated transaction would have been applied."); + BEAST_EXPECT(result[jss::engine_result] == "tesSUCCESS"); + BEAST_EXPECT(result[jss::engine_result_code] == 0); + BEAST_EXPECT( + result[jss::engine_result_message] == "The simulated transaction would have been applied."); - if (BEAST_EXPECT( - result.isMember(jss::meta) || - result.isMember(jss::meta_blob))) - { - Json::Value const metadata = getJsonMetadata(result); + if (BEAST_EXPECT(result.isMember(jss::meta) || result.isMember(jss::meta_blob))) + { + Json::Value const metadata = getJsonMetadata(result); - BEAST_EXPECT( - metadata[sfTransactionIndex.jsonName] == 0); - BEAST_EXPECT( - metadata[sfTransactionResult.jsonName] == - "tesSUCCESS"); - BEAST_EXPECT( - metadata.isMember(expectedMetadataKey.asString())); - BEAST_EXPECT( - metadata[expectedMetadataKey.asString()] == - expectedMetadataValue); - } - }; + BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0); + BEAST_EXPECT(metadata[sfTransactionResult.jsonName] == "tesSUCCESS"); + BEAST_EXPECT(metadata.isMember(expectedMetadataKey.asString())); + BEAST_EXPECT(metadata[expectedMetadataKey.asString()] == expectedMetadataValue); + } + }; { Json::Value tx; @@ -1280,8 +1077,7 @@ class Simulate_test : public beast::unit_test::suite tx[sfAmount] = "100"; // test delivered amount - testTxJsonMetadataField( - env, tx, validateOutput, jss::delivered_amount, "100"); + testTxJsonMetadataField(env, tx, validateOutput, jss::delivered_amount, "100"); } { @@ -1290,11 +1086,9 @@ class Simulate_test : public beast::unit_test::suite tx[jss::TransactionType] = jss::NFTokenMint; tx[sfNFTokenTaxon] = 1; - Json::Value nftokenId = - to_string(token::getNextID(env, alice, 1)); + Json::Value nftokenId = to_string(token::getNextID(env, alice, 1)); // test nft synthetic - testTxJsonMetadataField( - env, tx, validateOutput, jss::nftoken_id, nftokenId); + testTxJsonMetadataField(env, tx, validateOutput, jss::nftoken_id, nftokenId); } { @@ -1302,15 +1096,9 @@ class Simulate_test : public beast::unit_test::suite tx[jss::Account] = alice.human(); tx[jss::TransactionType] = jss::MPTokenIssuanceCreate; - Json::Value mptIssuanceId = - to_string(makeMptID(env.seq(alice), alice)); + Json::Value mptIssuanceId = to_string(makeMptID(env.seq(alice), alice)); // test mpt issuance id - testTxJsonMetadataField( - env, - tx, - validateOutput, - jss::mpt_issuance_id, - mptIssuanceId); + testTxJsonMetadataField(env, tx, validateOutput, jss::mpt_issuance_id, mptIssuanceId); } } } @@ -1335,8 +1123,8 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Simulate, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Simulate, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Status_test.cpp b/src/test/rpc/Status_test.cpp index 884e684fb3..ac387196fe 100644 --- a/src/test/rpc/Status_test.cpp +++ b/src/test/rpc/Status_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { namespace RPC { class codeString_test : public beast::unit_test::suite @@ -131,11 +112,7 @@ private: template void - expectFill( - std::string const& label, - Type status, - Status::Strings messages, - std::string const& message) + expectFill(std::string const& label, Type status, Status::Strings messages, std::string const& message) { value_.clear(); fillJson(Status(status, messages)); @@ -147,20 +124,14 @@ private: expect(bool(error), prefix + "No error."); auto code = error[jss::code].asInt(); - expect( - status == code, - prefix + "Wrong status " + std::to_string(code) + - " != " + std::to_string(status)); + expect(status == code, prefix + "Wrong status " + std::to_string(code) + " != " + std::to_string(status)); auto m = error[jss::message].asString(); expect(m == message, m + " != " + message); auto d = error[jss::data]; size_t s1 = d.size(), s2 = messages.size(); - expect( - s1 == s2, - prefix + "Data sizes differ " + std::to_string(s1) + - " != " + std::to_string(s2)); + expect(s1 == s2, prefix + "Data sizes differ " + std::to_string(s1) + " != " + std::to_string(s2)); for (auto i = 0; i < std::min(s1, s2); ++i) { auto ds = d[i].asString(); @@ -172,17 +143,9 @@ private: test_error() { testcase("error"); - expectFill( - "temBAD_AMOUNT", - temBAD_AMOUNT, - {}, - "temBAD_AMOUNT: Malformed: Bad amount."); + expectFill("temBAD_AMOUNT", temBAD_AMOUNT, {}, "temBAD_AMOUNT: Malformed: Bad amount."); - expectFill( - "rpcBAD_SYNTAX", - rpcBAD_SYNTAX, - {"An error.", "Another error."}, - "badSyntax: Syntax error."); + expectFill("rpcBAD_SYNTAX", rpcBAD_SYNTAX, {"An error.", "Another error."}, "badSyntax: Syntax error."); expectFill("integer message", 23, {"Stuff."}, "23"); } @@ -221,4 +184,4 @@ public: BEAST_DEFINE_TESTSUITE(fillJson, rpc, RPC); } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 9ed02fa532..cce45fb4ef 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -1,20 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,7 +14,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { class Subscribe_test : public beast::unit_test::suite @@ -53,10 +36,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -76,9 +57,7 @@ public: env.app().getOPs().reportFeeChange(); // Check stream update - BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::type] == "serverStatus"; - })); + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { return jv[jss::type] == "serverStatus"; })); } { @@ -86,10 +65,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -124,16 +101,12 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2); - BEAST_EXPECT( - jv[jss::result][jss::network_id] == - env.app().config().NETWORK_ID); + BEAST_EXPECT(jv[jss::result][jss::network_id] == env.app().config().NETWORK_ID); } { @@ -142,8 +115,7 @@ public: // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::ledger_index] == 3 && - jv[jss::network_id] == env.app().config().NETWORK_ID; + return jv[jss::ledger_index] == 3 && jv[jss::network_id] == env.app().config().NETWORK_ID; })); } @@ -153,8 +125,7 @@ public: // Check stream update BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::ledger_index] == 4 && - jv[jss::network_id] == env.app().config().NETWORK_ID; + return jv[jss::ledger_index] == 4 && jv[jss::network_id] == env.app().config().NETWORK_ID; })); } @@ -162,10 +133,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -188,10 +157,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -203,8 +170,7 @@ public: // Check stream update for payment transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"] - ["NewFields"][jss::Account] // + return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"]["NewFields"][jss::Account] // == Account("alice").human() && jv[jss::transaction][jss::TransactionType] // == jss::Payment && @@ -218,8 +184,7 @@ public: // Check stream update for accountset transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"] - ["FinalFields"][jss::Account] == + return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"]["FinalFields"][jss::Account] == Account("alice").human(); })); @@ -228,8 +193,7 @@ public: // Check stream update for payment transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"] - ["NewFields"][jss::Account] // + return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"]["NewFields"][jss::Account] // == Account("bob").human() && jv[jss::transaction][jss::TransactionType] // == jss::Payment && @@ -243,8 +207,7 @@ public: // Check stream update for accountset transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"] - ["FinalFields"][jss::Account] == + return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"]["FinalFields"][jss::Account] == Account("bob").human(); })); } @@ -254,10 +217,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -271,10 +232,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -292,14 +251,12 @@ public: // Check stream updates BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][1u]["ModifiedNode"] - ["FinalFields"][jss::Account] == + return jv[jss::meta]["AffectedNodes"][1u]["ModifiedNode"]["FinalFields"][jss::Account] == Account("alice").human(); })); BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"] - ["NewFields"]["LowLimit"][jss::issuer] == + return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"]["NewFields"]["LowLimit"][jss::issuer] == Account("alice").human(); })); } @@ -308,10 +265,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -339,10 +294,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -354,8 +307,7 @@ public: // Check stream update for payment transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"] - ["NewFields"][jss::Account] // + return jv[jss::meta]["AffectedNodes"][1u]["CreatedNode"]["NewFields"][jss::Account] // == Account("alice").human() && jv[jss::close_time_iso] // == "2000-01-01T00:00:10Z" && @@ -378,8 +330,7 @@ public: // Check stream update for accountset transaction BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"] - ["FinalFields"][jss::Account] == + return jv[jss::meta]["AffectedNodes"][0u]["ModifiedNode"]["FinalFields"][jss::Account] == Account("alice").human(); })); } @@ -389,10 +340,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -414,10 +363,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -427,10 +374,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -445,16 +390,13 @@ public: auto& cfg = env.app().config(); if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty())) return; - auto const parsedseed = - parseBase58(cfg.section(SECTION_VALIDATION_SEED).values()[0]); + auto const parsedseed = parseBase58(cfg.section(SECTION_VALIDATION_SEED).values()[0]); if (!BEAST_EXPECT(parsedseed)) return; std::string const valPublicKey = toBase58( TokenType::NodePublic, - derivePublicKey( - KeyType::secp256k1, - generateSecretKey(KeyType::secp256k1, *parsedseed))); + derivePublicKey(KeyType::secp256k1, generateSecretKey(KeyType::secp256k1, *parsedseed))); auto wsc = makeWSClient(env.app().config()); Json::Value stream; @@ -466,10 +408,8 @@ public: auto jv = wsc->invoke("subscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -477,20 +417,17 @@ public: { // Lambda to check ledger validations from the stream. - auto validValidationFields = [&env, &valPublicKey]( - Json::Value const& jv) { + auto validValidationFields = [&env, &valPublicKey](Json::Value const& jv) { if (jv[jss::type] != "validationReceived") return false; if (jv[jss::validation_public_key].asString() != valPublicKey) return false; - if (jv[jss::ledger_hash] != - to_string(env.closed()->info().hash)) + if (jv[jss::ledger_hash] != to_string(env.closed()->header().hash)) return false; - if (jv[jss::ledger_index] != - std::to_string(env.closed()->info().seq)) + if (jv[jss::ledger_index] != std::to_string(env.closed()->header().seq)) return false; if (jv[jss::flags] != (vfFullyCanonicalSig | vfFullValidation)) @@ -515,13 +452,11 @@ public: return false; uint32_t netID = env.app().config().NETWORK_ID; - if (!jv.isMember(jss::network_id) || - jv[jss::network_id] != netID) + if (!jv.isMember(jss::network_id) || jv[jss::network_id] != netID) return false; // Certain fields are only added on a flag ledger. - bool const isFlagLedger = - (env.closed()->info().seq + 1) % 256 == 0; + bool const isFlagLedger = (env.closed()->header().seq + 1) % 256 == 0; if (jv.isMember(jss::server_version) != isFlagLedger) return false; @@ -537,7 +472,7 @@ public: // Check stream update. Look at enough stream entries so we see // at least one flag ledger. - while (env.closed()->info().seq < 300) + while (env.closed()->header().seq < 300) { env.close(); using namespace std::chrono_literals; @@ -549,10 +484,8 @@ public: auto jv = wsc->invoke("unsubscribe", stream); if (wsc->version() == 2) { - BEAST_EXPECT( - jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); - BEAST_EXPECT( - jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0"); + BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0"); BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5); } BEAST_EXPECT(jv[jss::status] == "success"); @@ -625,9 +558,7 @@ public: if (subscribe) { BEAST_EXPECT(jr[jss::error] == "invalidParams"); - BEAST_EXPECT( - jr[jss::error_message] == - "Only http and https is supported."); + BEAST_EXPECT(jr[jss::error_message] == "Only http and https is supported."); } } @@ -635,12 +566,9 @@ public: Env env_nonadmin{*this, no_admin(envconfig())}; Json::Value jv; jv[jss::url] = "no-url"; - auto jr = - env_nonadmin.rpc("json", method, to_string(jv))[jss::result]; + auto jr = env_nonadmin.rpc("json", method, to_string(jv))[jss::result]; BEAST_EXPECT(jr[jss::error] == "noPermission"); - BEAST_EXPECT( - jr[jss::error_message] == - "You don't have permission for this command."); + BEAST_EXPECT(jr[jss::error_message] == "You don't have permission for this command."); } std::initializer_list const nonArrays{ @@ -698,8 +626,7 @@ public: jv[jss::books][0u][jss::taker_pays] = Json::objectValue; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "srcCurMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Source currency is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Source currency is malformed."); } { @@ -711,8 +638,7 @@ public: jv[jss::books][0u][jss::taker_pays][jss::currency] = "ZZZZ"; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "srcCurMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Source currency is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Source currency is malformed."); } { @@ -725,8 +651,7 @@ public: jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "srcIsrMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Source issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Source issuer is malformed."); } { @@ -736,12 +661,10 @@ public: jv[jss::books][0u][jss::taker_gets] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = Json::objectValue; jv[jss::books][0u][jss::taker_pays][jss::currency] = "USD"; - jv[jss::books][0u][jss::taker_pays][jss::issuer] = - Account{"gateway"}.human() + "DEAD"; + jv[jss::books][0u][jss::taker_pays][jss::issuer] = Account{"gateway"}.human() + "DEAD"; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "srcIsrMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Source issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Source issuer is malformed."); } { @@ -749,16 +672,13 @@ public: jv[jss::books] = Json::arrayValue; jv[jss::books][0u] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); jv[jss::books][0u][jss::taker_gets] = Json::objectValue; auto jr = wsc->invoke(method, jv)[jss::result]; // NOTE: this error is slightly incongruous with the // equivalent source currency error BEAST_EXPECT(jr[jss::error] == "dstAmtMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == - "Destination amount/currency/issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Destination amount/currency/issuer is malformed."); } { @@ -766,16 +686,13 @@ public: jv[jss::books] = Json::arrayValue; jv[jss::books][0u] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); jv[jss::books][0u][jss::taker_gets][jss::currency] = "ZZZZ"; auto jr = wsc->invoke(method, jv)[jss::result]; // NOTE: this error is slightly incongruous with the // equivalent source currency error BEAST_EXPECT(jr[jss::error] == "dstAmtMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == - "Destination amount/currency/issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Destination amount/currency/issuer is malformed."); } { @@ -783,14 +700,12 @@ public: jv[jss::books] = Json::arrayValue; jv[jss::books][0u] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); jv[jss::books][0u][jss::taker_gets][jss::currency] = "USD"; jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "dstIsrMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Destination issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Destination issuer is malformed."); } { @@ -798,15 +713,12 @@ public: jv[jss::books] = Json::arrayValue; jv[jss::books][0u] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); jv[jss::books][0u][jss::taker_gets][jss::currency] = "USD"; - jv[jss::books][0u][jss::taker_gets][jss::issuer] = - Account{"gateway"}.human() + "DEAD"; + jv[jss::books][0u][jss::taker_gets][jss::issuer] = Account{"gateway"}.human() + "DEAD"; auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "dstIsrMalformed"); - BEAST_EXPECT( - jr[jss::error_message] == "Destination issuer is malformed."); + BEAST_EXPECT(jr[jss::error_message] == "Destination issuer is malformed."); } { @@ -814,11 +726,9 @@ public: jv[jss::books] = Json::arrayValue; jv[jss::books][0u] = Json::objectValue; jv[jss::books][0u][jss::taker_pays] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); jv[jss::books][0u][jss::taker_gets] = - Account{"gateway"}["USD"](1).value().getJson( - JsonOptions::include_date); + Account{"gateway"}["USD"](1).value().getJson(JsonOptions::include_date); auto jr = wsc->invoke(method, jv)[jss::result]; BEAST_EXPECT(jr[jss::error] == "badMarket"); BEAST_EXPECT(jr[jss::error_message] == "No such market."); @@ -871,8 +781,7 @@ public: * return true if the subscribe or unsubscribe result is a success */ auto goodSubRPC = [](Json::Value const& subReply) -> bool { - return subReply.isMember(jss::result) && - subReply[jss::result].isMember(jss::status) && + return subReply.isMember(jss::result) && subReply[jss::result].isMember(jss::status) && subReply[jss::result][jss::status] == jss::success; }; @@ -881,9 +790,7 @@ public: * return {true, true} if received numReplies replies and also * received a tx with the account_history_tx_first == true */ - auto getTxHash = [](WSClient& wsc, - IdxHashVec& v, - int numReplies) -> std::pair { + auto getTxHash = [](WSClient& wsc, IdxHashVec& v, int numReplies) -> std::pair { bool first_flag = false; for (int i = 0; i < numReplies; ++i) @@ -899,12 +806,10 @@ public: first_flag = true; bool boundary = r.isMember(jss::account_history_boundary); int ledger_idx = r[jss::ledger_index].asInt(); - if (r.isMember(jss::transaction) && - r[jss::transaction].isMember(jss::hash)) + if (r.isMember(jss::transaction) && r[jss::transaction].isMember(jss::hash)) { auto t{r[jss::transaction]}; - v.emplace_back( - idx, t[jss::hash].asString(), boundary, ledger_idx); + v.emplace_back(idx, t[jss::hash].asString(), boundary, ledger_idx); continue; } } @@ -930,8 +835,7 @@ public: { auto& from = (i % 2 == 0) ? a : b; auto& to = (i % 2 == 0) ? b : a; - env.apply( - pay(from, to, jtx::XRP(numXRP)), + env(pay(from, to, jtx::XRP(numXRP)), jtx::seq(jtx::autofill), jtx::fee(jtx::autofill), jtx::sig(jtx::autofill)); @@ -946,9 +850,7 @@ public: * and in the same order. * If sizeCompare is false, txHistoryVec is allowed to be larger. */ - auto hashCompare = [](IdxHashVec const& accountVec, - IdxHashVec const& txHistoryVec, - bool sizeCompare) -> bool { + auto hashCompare = [](IdxHashVec const& accountVec, IdxHashVec const& txHistoryVec, bool sizeCompare) -> bool { if (accountVec.empty() || txHistoryVec.empty()) return false; if (sizeCompare && accountVec.size() != (txHistoryVec.size())) @@ -974,8 +876,7 @@ public: return false; for (std::size_t i = 1; i < accountVec.size(); ++i) { - if (auto idx = getHistoryIndex(i); - !idx || *idx != *firstHistoryIndex + i) + if (auto idx = getHistoryIndex(i); !idx || *idx != *firstHistoryIndex + i) return false; } return true; @@ -1016,8 +917,7 @@ public: for (size_t i = 0; i < num_tx; ++i) { auto [idx, hash, boundary, ledger] = vec[i]; - if ((i + 1 == num_tx || ledger != std::get<3>(vec[i + 1])) != - boundary) + if ((i + 1 == num_tx || ledger != std::get<3>(vec[i + 1])) != boundary) return false; } return true; @@ -1036,8 +936,7 @@ public: auto wscTxHistory = makeWSClient(env.app().config()); Json::Value request; request[jss::account_history_tx_stream] = Json::objectValue; - request[jss::account_history_tx_stream][jss::account] = - alice.human(); + request[jss::account_history_tx_stream][jss::account] = alice.human(); auto jv = wscTxHistory->invoke("subscribe", request); if (!BEAST_EXPECT(goodSubRPC(jv))) return; @@ -1048,8 +947,7 @@ public: /* * unsubscribe history only, future txns should still be streamed */ - request[jss::account_history_tx_stream][jss::stop_history_tx_only] = - true; + request[jss::account_history_tx_stream][jss::stop_history_tx_only] = true; jv = wscTxHistory->invoke("unsubscribe", request); if (!BEAST_EXPECT(goodSubRPC(jv))) return; @@ -1064,8 +962,7 @@ public: /* * unsubscribe, future txns should not be streamed */ - request[jss::account_history_tx_stream][jss::stop_history_tx_only] = - false; + request[jss::account_history_tx_stream][jss::stop_history_tx_only] = false; jv = wscTxHistory->invoke("unsubscribe", request); BEAST_EXPECT(goodSubRPC(jv)); @@ -1082,14 +979,12 @@ public: auto wscTxHistory = makeWSClient(env.app().config()); Json::Value request; request[jss::account_history_tx_stream] = Json::objectValue; - request[jss::account_history_tx_stream][jss::account] = - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; + request[jss::account_history_tx_stream][jss::account] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; auto jv = wscTxHistory->invoke("subscribe", request); if (!BEAST_EXPECT(goodSubRPC(jv))) return; IdxHashVec genesisFullHistoryVec; - if (!BEAST_EXPECT( - !getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first)) + if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first)) return; /* @@ -1110,9 +1005,7 @@ public: r = getTxHash(*wscTxHistory, bobFullHistoryVec, 1); if (!BEAST_EXPECT(r.first && r.second)) return; - BEAST_EXPECT( - std::get<1>(bobFullHistoryVec.back()) == - std::get<1>(genesisFullHistoryVec.back())); + BEAST_EXPECT(std::get<1>(bobFullHistoryVec.back()) == std::get<1>(genesisFullHistoryVec.back())); /* * unsubscribe to prepare next test @@ -1120,8 +1013,7 @@ public: jv = wscTxHistory->invoke("unsubscribe", request); if (!BEAST_EXPECT(goodSubRPC(jv))) return; - request[jss::account_history_tx_stream][jss::account] = - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; + request[jss::account_history_tx_stream][jss::account] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; jv = wscTxHistory->invoke("unsubscribe", request); BEAST_EXPECT(goodSubRPC(jv)); @@ -1135,21 +1027,16 @@ public: jv = wscTxHistory->invoke("subscribe", request); bobFullHistoryVec.clear(); - BEAST_EXPECT( - getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second); + BEAST_EXPECT(getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second); jv = wscTxHistory->invoke("unsubscribe", request); - request[jss::account_history_tx_stream][jss::account] = - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; + request[jss::account_history_tx_stream][jss::account] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; jv = wscTxHistory->invoke("subscribe", request); genesisFullHistoryVec.clear(); - BEAST_EXPECT( - getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second); + BEAST_EXPECT(getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second); jv = wscTxHistory->invoke("unsubscribe", request); - BEAST_EXPECT( - std::get<1>(bobFullHistoryVec.back()) == - std::get<1>(genesisFullHistoryVec.back())); + BEAST_EXPECT(std::get<1>(bobFullHistoryVec.back()) == std::get<1>(genesisFullHistoryVec.back())); } { @@ -1180,8 +1067,7 @@ public: // subscribe account tx history Json::Value request; request[jss::account_history_tx_stream] = Json::objectValue; - request[jss::account_history_tx_stream][jss::account] = - alice.human(); + request[jss::account_history_tx_stream][jss::account] = alice.human(); jv = wscTxHistory->invoke("subscribe", request); // compare historical txns @@ -1199,8 +1085,7 @@ public: { // take out all history txns from stream to prepare next test IdxHashVec initFundTxns; - if (!BEAST_EXPECT( - getTxHash(*wscTxHistory, initFundTxns, 10).second) || + if (!BEAST_EXPECT(getTxHash(*wscTxHistory, initFundTxns, 10).second) || !BEAST_EXPECT(checkBoundary(initFundTxns, false))) return; } @@ -1246,8 +1131,7 @@ public: // subscribe Json::Value request; request[jss::account_history_tx_stream] = Json::objectValue; - request[jss::account_history_tx_stream][jss::account] = - carol.human(); + request[jss::account_history_tx_stream][jss::account] = carol.human(); auto ws = makeWSClient(env.app().config()); auto jv = ws->invoke("subscribe", request); { @@ -1273,15 +1157,12 @@ public: env.close(); // many payments, and close lots of ledgers - auto oneRound = [&](int numPayments) { - return sendPayments(env, alice, carol, numPayments, 300); - }; + auto oneRound = [&](int numPayments) { return sendPayments(env, alice, carol, numPayments, 300); }; // subscribe Json::Value request; request[jss::account_history_tx_stream] = Json::objectValue; - request[jss::account_history_tx_stream][jss::account] = - carol.human(); + request[jss::account_history_tx_stream][jss::account] = carol.human(); auto wscLong = makeWSClient(env.app().config()); auto jv = wscLong->invoke("subscribe", request); { @@ -1318,8 +1199,7 @@ public: using namespace jtx; using namespace std::chrono_literals; FeatureBitset const all{ - jtx::testable_amendments() | featurePermissionedDomains | - featureCredentials | featurePermissionedDEX}; + jtx::testable_amendments() | featurePermissionedDomains | featureCredentials | featurePermissionedDEX}; Env env(*this, all); PermissionedDEX permDex(env); @@ -1339,15 +1219,10 @@ public: auto jv = wsc->invoke("subscribe", streams); if (!BEAST_EXPECT(jv[jss::status] == "success")) return; - env(offer(alice, XRP(10), USD(10)), - domain(domainID), - txflags(tfHybrid)); + env(offer(alice, XRP(10), USD(10)), domain(domainID), txflags(tfHybrid)); env.close(); - env(pay(bob, carol, USD(5)), - path(~USD), - sendmax(XRP(5)), - domain(domainID)); + env(pay(bob, carol, USD(5)), path(~USD), sendmax(XRP(5)), domain(domainID)); env.close(); BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { @@ -1355,12 +1230,9 @@ public: return false; auto const jrOffer = jv[jss::changes][0u]; - return (jv[jss::changes][0u][jss::domain]).asString() == - strHex(domainID) && - jrOffer[jss::currency_a].asString() == "XRP_drops" && - jrOffer[jss::volume_a].asString() == "5000000" && - jrOffer[jss::currency_b].asString() == - "rHUKYAZyUFn8PCZWbPfwHfbVQXTYrYKkHb/USD" && + return (jv[jss::changes][0u][jss::domain]).asString() == strHex(domainID) && + jrOffer[jss::currency_a].asString() == "XRP_drops" && jrOffer[jss::volume_a].asString() == "5000000" && + jrOffer[jss::currency_b].asString() == "rHUKYAZyUFn8PCZWbPfwHfbVQXTYrYKkHb/USD" && jrOffer[jss::volume_b].asString() == "5"; })); } @@ -1379,7 +1251,7 @@ public: // // The values of these fields are dependent on the NFTokenID/OfferID // changed in its corresponding transaction. We want to validate each - // response to make sure the synethic fields hold the right values. + // response to make sure the synthetic fields hold the right values. testcase("Test synthetic fields from Subscribe response"); @@ -1406,49 +1278,46 @@ public: auto verifyNFTokenID = [&](uint256 const& actualNftID) { BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { uint256 nftID; - BEAST_EXPECT( - nftID.parseHex(jv[jss::meta][jss::nftoken_id].asString())); + BEAST_EXPECT(nftID.parseHex(jv[jss::meta][jss::nftoken_id].asString())); return nftID == actualNftID; })); }; // Verify `nftoken_ids` value equals to the NFTokenIDs that were // changed in the most recent NFTokenCancelOffer transaction - auto verifyNFTokenIDsInCancelOffer = - [&](std::vector actualNftIDs) { - BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { - std::vector metaIDs; - std::transform( - jv[jss::meta][jss::nftoken_ids].begin(), - jv[jss::meta][jss::nftoken_ids].end(), - std::back_inserter(metaIDs), - [this](Json::Value id) { - uint256 nftID; - BEAST_EXPECT(nftID.parseHex(id.asString())); - return nftID; - }); - // Sort both array to prepare for comparison - std::sort(metaIDs.begin(), metaIDs.end()); - std::sort(actualNftIDs.begin(), actualNftIDs.end()); + auto verifyNFTokenIDsInCancelOffer = [&](std::vector actualNftIDs) { + BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { + std::vector metaIDs; + std::transform( + jv[jss::meta][jss::nftoken_ids].begin(), + jv[jss::meta][jss::nftoken_ids].end(), + std::back_inserter(metaIDs), + [this](Json::Value id) { + uint256 nftID; + BEAST_EXPECT(nftID.parseHex(id.asString())); + return nftID; + }); + // Sort both array to prepare for comparison + std::sort(metaIDs.begin(), metaIDs.end()); + std::sort(actualNftIDs.begin(), actualNftIDs.end()); - // Make sure the expect number of NFTs is correct - BEAST_EXPECT(metaIDs.size() == actualNftIDs.size()); + // Make sure the expect number of NFTs is correct + BEAST_EXPECT(metaIDs.size() == actualNftIDs.size()); - // Check the value of NFT ID in the meta with the - // actual values - for (size_t i = 0; i < metaIDs.size(); ++i) - BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]); - return true; - })); - }; + // Check the value of NFT ID in the meta with the + // actual values + for (size_t i = 0; i < metaIDs.size(); ++i) + BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]); + return true; + })); + }; // Verify `offer_id` value equals to the offerID that was // changed in the most recent NFTokenCreateOffer tx auto verifyNFTokenOfferID = [&](uint256 const& offerID) { BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) { uint256 metaOfferID; - BEAST_EXPECT(metaOfferID.parseHex( - jv[jss::meta][jss::offer_id].asString())); + BEAST_EXPECT(metaOfferID.parseHex(jv[jss::meta][jss::offer_id].asString())); return metaOfferID == offerID; })); }; @@ -1457,14 +1326,12 @@ public: { // Alice mints 2 NFTs // Verify the NFTokenIDs are correct in the NFTokenMint tx meta - uint256 const nftId1{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId1{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId1); - uint256 const nftId2{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId2{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId2); @@ -1472,32 +1339,26 @@ public: // Alice creates one sell offer for each NFT // Verify the offer indexes are correct in the NFTokenCreateOffer tx // meta - uint256 const aliceOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId1, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId1, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex1); - uint256 const aliceOfferIndex2 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId2, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex2 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId2, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex2); // Alice cancels two offers she created // Verify the NFTokenIDs are correct in the NFTokenCancelOffer tx // meta - env(token::cancelOffer( - alice, {aliceOfferIndex1, aliceOfferIndex2})); + env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2})); env.close(); verifyNFTokenIDsInCancelOffer({nftId1, nftId2}); // Bobs creates a buy offer for nftId1 // Verify the offer id is correct in the NFTokenCreateOffer tx meta - auto const bobBuyOfferIndex = - keylet::nftoffer(bob, env.seq(bob)).key; + auto const bobBuyOfferIndex = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice)); env.close(); verifyNFTokenOfferID(bobBuyOfferIndex); @@ -1512,31 +1373,25 @@ public: // Check `nftoken_ids` in brokered mode { // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId); // Alice creates sell offer and set broker as destination - uint256 const offerAliceToBroker = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - token::destination(broker), - txflags(tfSellNFToken)); + uint256 const offerAliceToBroker = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), token::destination(broker), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(offerAliceToBroker); // Bob creates buy offer - uint256 const offerBobToBroker = - keylet::nftoffer(bob, env.seq(bob)).key; + uint256 const offerBobToBroker = keylet::nftoffer(bob, env.seq(bob)).key; env(token::createOffer(bob, nftId, drops(1)), token::owner(alice)); env.close(); verifyNFTokenOfferID(offerBobToBroker); // Check NFTokenID meta for NFTokenAcceptOffer in brokered mode - env(token::brokerOffers( - broker, offerBobToBroker, offerAliceToBroker)); + env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker)); env.close(); verifyNFTokenID(nftId); } @@ -1545,39 +1400,32 @@ public: // multiple offers are cancelled for the same NFT { // Alice mints a NFT - uint256 const nftId{ - token::getNextID(env, alice, 0u, tfTransferable)}; + uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)}; env(token::mint(alice, 0u), txflags(tfTransferable)); env.close(); verifyNFTokenID(nftId); // Alice creates 2 sell offers for the same NFT - uint256 const aliceOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex1); - uint256 const aliceOfferIndex2 = - keylet::nftoffer(alice, env.seq(alice)).key; - env(token::createOffer(alice, nftId, drops(1)), - txflags(tfSellNFToken)); + uint256 const aliceOfferIndex2 = keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken)); env.close(); verifyNFTokenOfferID(aliceOfferIndex2); // Make sure the metadata only has 1 nft id, since both offers are // for the same nft - env(token::cancelOffer( - alice, {aliceOfferIndex1, aliceOfferIndex2})); + env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2})); env.close(); verifyNFTokenIDsInCancelOffer({nftId}); } if (features[featureNFTokenMintOffer]) { - uint256 const aliceMintWithOfferIndex1 = - keylet::nftoffer(alice, env.seq(alice)).key; + uint256 const aliceMintWithOfferIndex1 = keylet::nftoffer(alice, env.seq(alice)).key; env(token::mint(alice), token::amount(XRP(0))); env.close(); verifyNFTokenOfferID(aliceMintWithOfferIndex1); @@ -1608,7 +1456,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Subscribe, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Subscribe, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/TransactionEntry_test.cpp b/src/test/rpc/TransactionEntry_test.cpp index 27e1f659b5..6302de4efa 100644 --- a/src/test/rpc/TransactionEntry_test.cpp +++ b/src/test/rpc/TransactionEntry_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class TransactionEntry_test : public beast::unit_test::suite { @@ -42,8 +23,7 @@ class TransactionEntry_test : public beast::unit_test::suite { // no params - auto const result = - env.client().invoke("transaction_entry", {})[jss::result]; + auto const result = env.client().invoke("transaction_entry", {})[jss::result]; BEAST_EXPECT(result[jss::error] == "fieldNotFoundTransaction"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -51,8 +31,7 @@ class TransactionEntry_test : public beast::unit_test::suite { Json::Value params{Json::objectValue}; params[jss::ledger] = 20; - auto const result = - env.client().invoke("transaction_entry", params)[jss::result]; + auto const result = env.client().invoke("transaction_entry", params)[jss::result]; BEAST_EXPECT(result[jss::error] == "lgrNotFound"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -61,8 +40,7 @@ class TransactionEntry_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::ledger] = "current"; params[jss::tx_hash] = "DEADBEEF"; - auto const result = - env.client().invoke("transaction_entry", params)[jss::result]; + auto const result = env.client().invoke("transaction_entry", params)[jss::result]; BEAST_EXPECT(result[jss::error] == "notYetImplemented"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -71,15 +49,13 @@ class TransactionEntry_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::ledger] = "closed"; params[jss::tx_hash] = "DEADBEEF"; - auto const result = - env.client().invoke("transaction_entry", params)[jss::result]; + auto const result = env.client().invoke("transaction_entry", params)[jss::result]; BEAST_EXPECT(!result[jss::ledger_hash].asString().empty()); BEAST_EXPECT(result[jss::error] == "malformedRequest"); BEAST_EXPECT(result[jss::status] == "error"); } - std::string const txHash{ - "E2FE8D4AF3FCC3944DDF6CD8CDDC5E3F0AD50863EF8919AFEF10CB6408CD4D05"}; + std::string const txHash{"E2FE8D4AF3FCC3944DDF6CD8CDDC5E3F0AD50863EF8919AFEF10CB6408CD4D05"}; // Command line format { @@ -99,24 +75,21 @@ class TransactionEntry_test : public beast::unit_test::suite { // First argument with too few characters - Json::Value const result{ - env.rpc("transaction_entry", txHash.substr(1), "closed")}; + Json::Value const result{env.rpc("transaction_entry", txHash.substr(1), "closed")}; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::status] == "error"); } { // First argument with too many characters - Json::Value const result{ - env.rpc("transaction_entry", txHash + "A", "closed")}; + Json::Value const result{env.rpc("transaction_entry", txHash + "A", "closed")}; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::status] == "error"); } { // Second argument not valid - Json::Value const result{ - env.rpc("transaction_entry", txHash, "closer")}; + Json::Value const result{env.rpc("transaction_entry", txHash, "closer")}; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -130,20 +103,16 @@ class TransactionEntry_test : public beast::unit_test::suite { // Three arguments - Json::Value const result{ - env.rpc("transaction_entry", txHash, "closed", "extra")}; + Json::Value const result{env.rpc("transaction_entry", txHash, "closed", "extra")}; BEAST_EXPECT(result[jss::error] == "badSyntax"); BEAST_EXPECT(result[jss::status] == "error"); } { // Valid structure, but transaction not found. - Json::Value const result{ - env.rpc("transaction_entry", txHash, "closed")}; - BEAST_EXPECT( - !result[jss::result][jss::ledger_hash].asString().empty()); - BEAST_EXPECT( - result[jss::result][jss::error] == "transactionNotFound"); + Json::Value const result{env.rpc("transaction_entry", txHash, "closed")}; + BEAST_EXPECT(!result[jss::result][jss::ledger_hash].asString().empty()); + BEAST_EXPECT(result[jss::result][jss::error] == "transactionNotFound"); BEAST_EXPECT(result[jss::result][jss::status] == "error"); } } @@ -170,8 +139,7 @@ class TransactionEntry_test : public beast::unit_test::suite params[jss::ledger_index] = index; params[jss::tx_hash] = txhash; params[jss::api_version] = apiVersion; - return env.client().invoke( - "transaction_entry", params)[jss::result]; + return env.client().invoke("transaction_entry", params)[jss::result]; }()}; if (!BEAST_EXPECT(resIndex.isMember(jss::tx_json))) @@ -187,8 +155,7 @@ class TransactionEntry_test : public beast::unit_test::suite BEAST_EXPECT(!resIndex[jss::tx_json].isMember(jss::Amount)); if (BEAST_EXPECT(!close_time_iso.empty())) - BEAST_EXPECT( - resIndex[jss::close_time_iso] == close_time_iso); + BEAST_EXPECT(resIndex[jss::close_time_iso] == close_time_iso); } else { @@ -202,12 +169,9 @@ class TransactionEntry_test : public beast::unit_test::suite Json::Value expected; Json::Reader().parse(expected_json, expected); if (RPC::contains_error(expected)) - Throw( - "Internal JSONRPC_test error. Bad test JSON."); + Throw("Internal JSONRPC_test error. Bad test JSON."); - for (auto memberIt = expected.begin(); - memberIt != expected.end(); - memberIt++) + for (auto memberIt = expected.begin(); memberIt != expected.end(); memberIt++) { auto const name = memberIt.memberName(); if (BEAST_EXPECT(resIndex[jss::tx_json].isMember(name))) @@ -230,25 +194,17 @@ class TransactionEntry_test : public beast::unit_test::suite params[jss::ledger_hash] = resIndex[jss::ledger_hash]; params[jss::tx_hash] = txhash; params[jss::api_version] = apiVersion; - Json::Value const resHash = env.client().invoke( - "transaction_entry", params)[jss::result]; + Json::Value const resHash = env.client().invoke("transaction_entry", params)[jss::result]; BEAST_EXPECT(resHash == resIndex); } // Use the command line form with the index. - Json::Value const clIndex{env.rpc( - apiVersion, - "transaction_entry", - txhash, - std::to_string(index))}; + Json::Value const clIndex{env.rpc(apiVersion, "transaction_entry", txhash, std::to_string(index))}; BEAST_EXPECT(clIndex["result"] == resIndex); // Use the command line form with the ledger_hash. - Json::Value const clHash{env.rpc( - apiVersion, - "transaction_entry", - txhash, - resIndex[jss::ledger_hash].asString())}; + Json::Value const clHash{ + env.rpc(apiVersion, "transaction_entry", txhash, resIndex[jss::ledger_hash].asString())}; BEAST_EXPECT(clHash["result"] == resIndex); }; @@ -257,15 +213,11 @@ class TransactionEntry_test : public beast::unit_test::suite env.fund(XRP(10000), A1); auto fund_1_tx = to_string(env.tx()->getTransactionID()); - BEAST_EXPECT( - fund_1_tx == - "F4E9DF90D829A9E8B423FF68C34413E240D8D8BB0EFD080DF08114ED398E2506"); + BEAST_EXPECT(fund_1_tx == "F4E9DF90D829A9E8B423FF68C34413E240D8D8BB0EFD080DF08114ED398E2506"); env.fund(XRP(10000), A2); auto fund_2_tx = to_string(env.tx()->getTransactionID()); - BEAST_EXPECT( - fund_2_tx == - "6853CD8226A05068C951CB1F54889FF4E40C5B440DC1C5BA38F114C4E0B1E705"); + BEAST_EXPECT(fund_2_tx == "6853CD8226A05068C951CB1F54889FF4E40C5B440DC1C5BA38F114C4E0B1E705"); env.close(); @@ -305,16 +257,12 @@ class TransactionEntry_test : public beast::unit_test::suite // refunds fees with a payment after TrustSet..so just ignore the type // in the check below auto trust_tx = to_string(env.tx()->getTransactionID()); - BEAST_EXPECT( - trust_tx == - "C992D97D88FF444A1AB0C06B27557EC54B7F7DA28254778E60238BEA88E0C101"); + BEAST_EXPECT(trust_tx == "C992D97D88FF444A1AB0C06B27557EC54B7F7DA28254778E60238BEA88E0C101"); env(pay(A2, A1, A2["USD"](5))); auto pay_tx = to_string(env.tx()->getTransactionID()); env.close(); - BEAST_EXPECT( - pay_tx == - "988046D484ACE9F5F6A8C792D89C6EA2DB307B5DDA9864AEBA88E6782ABD0865"); + BEAST_EXPECT(pay_tx == "988046D484ACE9F5F6A8C792D89C6EA2DB307B5DDA9864AEBA88E6782ABD0865"); check_tx( env.closed()->seq(), @@ -357,9 +305,7 @@ class TransactionEntry_test : public beast::unit_test::suite env(offer(A2, XRP(100), A2["USD"](1))); auto offer_tx = to_string(env.tx()->getTransactionID()); - BEAST_EXPECT( - offer_tx == - "5FCC1A27A7664F82A0CC4BE5766FBBB7C560D52B93AA7B550CD33B27AEC7EFFB"); + BEAST_EXPECT(offer_tx == "5FCC1A27A7664F82A0CC4BE5766FBBB7C560D52B93AA7B550CD33B27AEC7EFFB"); env.close(); check_tx( @@ -389,11 +335,10 @@ public: run() override { testBadInput(); - forAllApiVersions( - std::bind_front(&TransactionEntry_test::testRequest, this)); + forAllApiVersions(std::bind_front(&TransactionEntry_test::testRequest, this)); } }; -BEAST_DEFINE_TESTSUITE(TransactionEntry, rpc, ripple); +BEAST_DEFINE_TESTSUITE(TransactionEntry, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/TransactionHistory_test.cpp b/src/test/rpc/TransactionHistory_test.cpp index d5b1b27a35..1d555ecd8c 100644 --- a/src/test/rpc/TransactionHistory_test.cpp +++ b/src/test/rpc/TransactionHistory_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -27,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { class TransactionHistory_test : public beast::unit_test::suite { @@ -40,8 +21,7 @@ class TransactionHistory_test : public beast::unit_test::suite { // no params - auto const result = - env.client().invoke("tx_history", {})[jss::result]; + auto const result = env.client().invoke("tx_history", {})[jss::result]; BEAST_EXPECT(result[jss::error] == "invalidParams"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -50,8 +30,7 @@ class TransactionHistory_test : public beast::unit_test::suite // test at 1 greater than the allowed non-admin limit Json::Value params{Json::objectValue}; params[jss::start] = 10001; // limited to <= 10000 for non admin - auto const result = - env.client().invoke("tx_history", params)[jss::result]; + auto const result = env.client().invoke("tx_history", params)[jss::result]; BEAST_EXPECT(result[jss::error] == "noPermission"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -66,8 +45,7 @@ class TransactionHistory_test : public beast::unit_test::suite Json::Value params{Json::objectValue}; params[jss::api_version] = 2; - auto const result = - env.client().invoke("tx_history", params)[jss::result]; + auto const result = env.client().invoke("tx_history", params)[jss::result]; BEAST_EXPECT(result[jss::error] == "unknownCmd"); BEAST_EXPECT(result[jss::status] == "error"); } @@ -102,10 +80,8 @@ class TransactionHistory_test : public beast::unit_test::suite // is available in tx_history. Json::Value params{Json::objectValue}; params[jss::start] = 0; - auto result = - env.client().invoke("tx_history", params)[jss::result]; - if (!BEAST_EXPECT( - result[jss::txs].isArray() && result[jss::txs].size() > 0)) + auto result = env.client().invoke("tx_history", params)[jss::result]; + if (!BEAST_EXPECT(result[jss::txs].isArray() && result[jss::txs].size() > 0)) return; // search for a tx in history matching the last offer @@ -131,10 +107,8 @@ class TransactionHistory_test : public beast::unit_test::suite { Json::Value params{Json::objectValue}; params[jss::start] = start; - auto result = - env.client().invoke("tx_history", params)[jss::result]; - if (!BEAST_EXPECT( - result[jss::txs].isArray() && result[jss::txs].size() > 0)) + auto result = env.client().invoke("tx_history", params)[jss::result]; + if (!BEAST_EXPECT(result[jss::txs].isArray() && result[jss::txs].size() > 0)) break; total += result[jss::txs].size(); start += 20; @@ -153,8 +127,7 @@ class TransactionHistory_test : public beast::unit_test::suite { Json::Value params{Json::objectValue}; params[jss::start] = 10000; // limited to <= 10000 for non admin - auto const result = - env.client().invoke("tx_history", params)[jss::result]; + auto const result = env.client().invoke("tx_history", params)[jss::result]; BEAST_EXPECT(result[jss::status] == "success"); BEAST_EXPECT(result[jss::index] == 10000); } @@ -170,6 +143,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(TransactionHistory, rpc, ripple); +BEAST_DEFINE_TESTSUITE(TransactionHistory, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index e1db485572..acc8bccf61 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { class Transaction_test : public beast::unit_test::suite { @@ -59,8 +40,7 @@ class Transaction_test : public beast::unit_test::suite char const* BINARY = jss::binary.c_str(); char const* NOT_FOUND = RPC::get_error_info(rpcTXN_NOT_FOUND).token; char const* INVALID = RPC::get_error_info(rpcINVALID_LGR_RANGE).token; - char const* EXCESSIVE = - RPC::get_error_info(rpcEXCESSIVE_LGR_RANGE).token; + char const* EXCESSIVE = RPC::get_error_info(rpcEXCESSIVE_LGR_RANGE).token; Env env{*this, features}; auto const alice = Account("alice"); @@ -69,16 +49,15 @@ class Transaction_test : public beast::unit_test::suite std::vector> txns; std::vector> metas; - auto const startLegSeq = env.current()->info().seq; + auto const startLegSeq = env.current()->header().seq; for (int i = 0; i < 750; ++i) { env(noop(alice)); txns.emplace_back(env.tx()); env.close(); - metas.emplace_back( - env.closed()->txRead(env.tx()->getTransactionID()).second); + metas.emplace_back(env.closed()->txRead(env.tx()->getTransactionID()).second); } - auto const endLegSeq = env.closed()->info().seq; + auto const endLegSeq = env.closed()->header().seq; // Find the existing transactions for (size_t i = 0; i < txns.size(); ++i) @@ -86,19 +65,11 @@ class Transaction_test : public beast::unit_test::suite auto const& tx = txns[i]; auto const& meta = metas[i]; auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - BINARY, - to_string(startLegSeq), - to_string(endLegSeq)); + COMMAND, to_string(tx->getTransactionID()), BINARY, to_string(startLegSeq), to_string(endLegSeq)); BEAST_EXPECT(result[jss::result][jss::status] == jss::success); - BEAST_EXPECT( - result[jss::result][jss::tx] == - strHex(tx->getSerializer().getData())); - BEAST_EXPECT( - result[jss::result][jss::meta] == - strHex(meta->getSerializer().getData())); + BEAST_EXPECT(result[jss::result][jss::tx] == strHex(tx->getSerializer().getData())); + BEAST_EXPECT(result[jss::result][jss::meta] == strHex(meta->getSerializer().getData())); } auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx; @@ -112,8 +83,7 @@ class Transaction_test : public beast::unit_test::suite to_string(endLegSeq + deltaEndSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); if (deltaEndSeq) BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); @@ -138,8 +108,7 @@ class Transaction_test : public beast::unit_test::suite auto const deletedLedger = (startLegSeq + endLegSeq) / 2; { // Remove one of the ledgers from the database directly - dynamic_cast(&env.app().getRelationalDatabase()) - ->deleteTransactionByLedgerSeq(deletedLedger); + env.app().getRelationalDatabase().deleteTransactionByLedgerSeq(deletedLedger); } for (int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq) @@ -152,23 +121,18 @@ class Transaction_test : public beast::unit_test::suite to_string(endLegSeq + deltaEndSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); } // Provide range without providing the `binary` // field. (Tests parameter parsing) { - auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - to_string(startLegSeq), - to_string(endLegSeq)); + auto const result = + env.rpc(COMMAND, to_string(tx->getTransactionID()), to_string(startLegSeq), to_string(endLegSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); } @@ -177,14 +141,10 @@ class Transaction_test : public beast::unit_test::suite // field. (Tests parameter parsing) { auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - to_string(startLegSeq), - to_string(deletedLedger - 1)); + COMMAND, to_string(tx->getTransactionID()), to_string(startLegSeq), to_string(deletedLedger - 1)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(result[jss::result][jss::searched_all].asBool()); } @@ -193,10 +153,7 @@ class Transaction_test : public beast::unit_test::suite // field. (Tests parameter parsing) { auto const result = env.rpc( - COMMAND, - to_string(txns[0]->getTransactionID()), - to_string(startLegSeq), - to_string(deletedLedger - 1)); + COMMAND, to_string(txns[0]->getTransactionID()), to_string(startLegSeq), to_string(deletedLedger - 1)); BEAST_EXPECT(result[jss::result][jss::status] == jss::success); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); @@ -211,9 +168,7 @@ class Transaction_test : public beast::unit_test::suite to_string(deletedLedger - 1), to_string(startLegSeq)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } @@ -221,54 +176,35 @@ class Transaction_test : public beast::unit_test::suite // Provide an invalid range: (min < 0) { auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - BINARY, - to_string(-1), - to_string(deletedLedger - 1)); + COMMAND, to_string(tx->getTransactionID()), BINARY, to_string(-1), to_string(deletedLedger - 1)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } // Provide an invalid range: (min < 0, max < 0) { - auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - BINARY, - to_string(-20), - to_string(-10)); + auto const result = + env.rpc(COMMAND, to_string(tx->getTransactionID()), BINARY, to_string(-20), to_string(-10)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } // Provide an invalid range: (only one value) { - auto const result = env.rpc( - COMMAND, - to_string(tx->getTransactionID()), - BINARY, - to_string(20)); + auto const result = env.rpc(COMMAND, to_string(tx->getTransactionID()), BINARY, to_string(20)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } // Provide an invalid range: (only one value) { - auto const result = env.rpc( - COMMAND, to_string(tx->getTransactionID()), to_string(20)); + auto const result = env.rpc(COMMAND, to_string(tx->getTransactionID()), to_string(20)); // Since we only provided one value for the range, // the interface parses it as a false binary flag, @@ -290,8 +226,7 @@ class Transaction_test : public beast::unit_test::suite to_string(startLegSeq + 1001)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == EXCESSIVE); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == EXCESSIVE); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } @@ -309,8 +244,7 @@ class Transaction_test : public beast::unit_test::suite char const* BINARY = jss::binary.c_str(); char const* NOT_FOUND = RPC::get_error_info(rpcTXN_NOT_FOUND).token; char const* INVALID = RPC::get_error_info(rpcINVALID_LGR_RANGE).token; - char const* EXCESSIVE = - RPC::get_error_info(rpcEXCESSIVE_LGR_RANGE).token; + char const* EXCESSIVE = RPC::get_error_info(rpcEXCESSIVE_LGR_RANGE).token; Env env{*this, makeNetworkConfig(11111)}; uint32_t netID = env.app().config().NETWORK_ID; @@ -321,16 +255,15 @@ class Transaction_test : public beast::unit_test::suite std::vector> txns; std::vector> metas; - auto const startLegSeq = env.current()->info().seq; + auto const startLegSeq = env.current()->header().seq; for (int i = 0; i < 750; ++i) { env(noop(alice)); txns.emplace_back(env.tx()); env.close(); - metas.emplace_back( - env.closed()->txRead(env.tx()->getTransactionID()).second); + metas.emplace_back(env.closed()->txRead(env.tx()->getTransactionID()).second); } - auto const endLegSeq = env.closed()->info().seq; + auto const endLegSeq = env.closed()->header().seq; // Find the existing transactions for (size_t i = 0; i < txns.size(); ++i) @@ -346,28 +279,19 @@ class Transaction_test : public beast::unit_test::suite to_string(endLegSeq)); BEAST_EXPECT(result[jss::result][jss::status] == jss::success); - BEAST_EXPECT( - result[jss::result][jss::tx] == - strHex(tx->getSerializer().getData())); - BEAST_EXPECT( - result[jss::result][jss::meta] == - strHex(meta->getSerializer().getData())); + BEAST_EXPECT(result[jss::result][jss::tx] == strHex(tx->getSerializer().getData())); + BEAST_EXPECT(result[jss::result][jss::meta] == strHex(meta->getSerializer().getData())); } auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx; auto const ctid = *RPC::encodeCTID(endLegSeq, tx->getSeqValue(), netID); for (int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq) { - auto const result = env.rpc( - COMMAND, - ctid, - BINARY, - to_string(startLegSeq), - to_string(endLegSeq + deltaEndSeq)); + auto const result = + env.rpc(COMMAND, ctid, BINARY, to_string(startLegSeq), to_string(endLegSeq + deltaEndSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); if (deltaEndSeq) BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); @@ -395,34 +319,26 @@ class Transaction_test : public beast::unit_test::suite auto const deletedLedger = (startLegSeq + endLegSeq) / 2; { // Remove one of the ledgers from the database directly - dynamic_cast(&env.app().getRelationalDatabase()) - ->deleteTransactionByLedgerSeq(deletedLedger); + env.app().getRelationalDatabase().deleteTransactionByLedgerSeq(deletedLedger); } for (int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq) { - auto const result = env.rpc( - COMMAND, - ctid, - BINARY, - to_string(startLegSeq), - to_string(endLegSeq + deltaEndSeq)); + auto const result = + env.rpc(COMMAND, ctid, BINARY, to_string(startLegSeq), to_string(endLegSeq + deltaEndSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); } // Provide range without providing the `binary` // field. (Tests parameter parsing) { - auto const result = env.rpc( - COMMAND, ctid, to_string(startLegSeq), to_string(endLegSeq)); + auto const result = env.rpc(COMMAND, ctid, to_string(startLegSeq), to_string(endLegSeq)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); } @@ -430,15 +346,10 @@ class Transaction_test : public beast::unit_test::suite // Provide range without providing the `binary` // field. (Tests parameter parsing) { - auto const result = env.rpc( - COMMAND, - ctid, - to_string(startLegSeq), - to_string(deletedLedger - 1)); + auto const result = env.rpc(COMMAND, ctid, to_string(startLegSeq), to_string(deletedLedger - 1)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == NOT_FOUND); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == NOT_FOUND); BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); } @@ -460,44 +371,27 @@ class Transaction_test : public beast::unit_test::suite // Provide an invalid range: (min > max) { - auto const result = env.rpc( - COMMAND, - ctid, - BINARY, - to_string(deletedLedger - 1), - to_string(startLegSeq)); + auto const result = env.rpc(COMMAND, ctid, BINARY, to_string(deletedLedger - 1), to_string(startLegSeq)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } // Provide an invalid range: (min < 0) { - auto const result = env.rpc( - COMMAND, - ctid, - BINARY, - to_string(-1), - to_string(deletedLedger - 1)); + auto const result = env.rpc(COMMAND, ctid, BINARY, to_string(-1), to_string(deletedLedger - 1)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } // Provide an invalid range: (min < 0, max < 0) { - auto const result = - env.rpc(COMMAND, ctid, BINARY, to_string(-20), to_string(-10)); + auto const result = env.rpc(COMMAND, ctid, BINARY, to_string(-20), to_string(-10)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } @@ -506,9 +400,7 @@ class Transaction_test : public beast::unit_test::suite { auto const result = env.rpc(COMMAND, ctid, BINARY, to_string(20)); - BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == INVALID); + BEAST_EXPECT(result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == INVALID); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } @@ -529,16 +421,10 @@ class Transaction_test : public beast::unit_test::suite // Provide an invalid range: (max - min > 1000) { - auto const result = env.rpc( - COMMAND, - ctid, - BINARY, - to_string(startLegSeq), - to_string(startLegSeq + 1001)); + auto const result = env.rpc(COMMAND, ctid, BINARY, to_string(startLegSeq), to_string(startLegSeq + 1001)); BEAST_EXPECT( - result[jss::result][jss::status] == jss::error && - result[jss::result][jss::error] == EXCESSIVE); + result[jss::result][jss::status] == jss::error && result[jss::result][jss::error] == EXCESSIVE); BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all)); } @@ -556,8 +442,7 @@ class Transaction_test : public beast::unit_test::suite // Test case 1: Valid input values auto const expected11 = std::optional("CFFFFFFFFFFFFFFF"); - BEAST_EXPECT( - RPC::encodeCTID(0x0FFF'FFFFUL, 0xFFFFU, 0xFFFFU) == expected11); + BEAST_EXPECT(RPC::encodeCTID(0x0FFF'FFFFUL, 0xFFFFU, 0xFFFFU) == expected11); auto const expected12 = std::optional("C000000000000000"); BEAST_EXPECT(RPC::encodeCTID(0, 0, 0) == expected12); auto const expected13 = std::optional("C000000100020003"); @@ -575,17 +460,12 @@ class Transaction_test : public beast::unit_test::suite BEAST_EXPECT(!RPC::encodeCTID(0x0FFF'FFFFUL, 0xFFFFU, 0x1'0000U)); // Test case 5: Valid input values - auto const expected51 = - std::optional>( - std::make_tuple(0, 0, 0)); + auto const expected51 = std::optional>(std::make_tuple(0, 0, 0)); BEAST_EXPECT(RPC::decodeCTID("C000000000000000") == expected51); - auto const expected52 = - std::optional>( - std::make_tuple(1U, 2U, 3U)); + auto const expected52 = std::optional>(std::make_tuple(1U, 2U, 3U)); BEAST_EXPECT(RPC::decodeCTID("C000000100020003") == expected52); auto const expected53 = - std::optional>( - std::make_tuple(13249191UL, 12911U, 49221U)); + std::optional>(std::make_tuple(13249191UL, 12911U, 49221U)); BEAST_EXPECT(RPC::decodeCTID("C0CA2AA7326FC045") == expected53); // Test case 6: ctid not a string or big int @@ -606,20 +486,16 @@ class Transaction_test : public beast::unit_test::suite // Test case 11: Valid input values BEAST_EXPECT( (RPC::decodeCTID(0xCFFF'FFFF'FFFF'FFFFULL) == - std::optional>( - std::make_tuple(0x0FFF'FFFFUL, 0xFFFFU, 0xFFFFU)))); + std::optional>(std::make_tuple(0x0FFF'FFFFUL, 0xFFFFU, 0xFFFFU)))); BEAST_EXPECT( (RPC::decodeCTID(0xC000'0000'0000'0000ULL) == - std::optional>( - std::make_tuple(0, 0, 0)))); + std::optional>(std::make_tuple(0, 0, 0)))); BEAST_EXPECT( (RPC::decodeCTID(0xC000'0001'0002'0003ULL) == - std::optional>( - std::make_tuple(1U, 2U, 3U)))); + std::optional>(std::make_tuple(1U, 2U, 3U)))); BEAST_EXPECT( (RPC::decodeCTID(0xC0CA'2AA7'326F'C045ULL) == - std::optional>( - std::make_tuple(1324'9191UL, 12911U, 49221U)))); + std::optional>(std::make_tuple(1324'9191UL, 12911U, 49221U)))); // Test case 12: ctid not exactly 16 nibbles BEAST_EXPECT(!RPC::decodeCTID(0xC003'FFFF'FFFF'FFF)); @@ -634,7 +510,7 @@ class Transaction_test : public beast::unit_test::suite } void - testCTIDRPC(FeatureBitset features) + testRPCsForCTID(FeatureBitset features) { testcase("CTID RPC"); @@ -649,7 +525,7 @@ class Transaction_test : public beast::unit_test::suite auto const alice = Account("alice"); auto const bob = Account("bob"); - auto const startLegSeq = env.current()->info().seq; + auto const startLegSeq = env.current()->header().seq; env.fund(XRP(10000), alice, bob); env(pay(alice, bob, XRP(10))); env.close(); @@ -666,8 +542,7 @@ class Transaction_test : public beast::unit_test::suite jsonTx[jss::binary] = false; jsonTx[jss::ctid] = *ctid; jsonTx[jss::id] = 1; - auto const jrr = - env.rpc("json", "tx", to_string(jsonTx))[jss::result]; + auto const jrr = env.rpc("json", "tx", to_string(jsonTx))[jss::result]; BEAST_EXPECT(jrr[jss::ctid] == ctid); BEAST_EXPECT(jrr.isMember(jss::hash)); } @@ -680,7 +555,7 @@ class Transaction_test : public beast::unit_test::suite Account const alice = Account("alice"); Account const bob = Account("bob"); - std::uint32_t const startLegSeq = env.current()->info().seq; + std::uint32_t const startLegSeq = env.current()->header().seq; env.fund(XRP(10000), alice, bob); env(pay(alice, bob, XRP(10))); env.close(); @@ -690,14 +565,12 @@ class Transaction_test : public beast::unit_test::suite // Verify that there are at least two upper case letters in ctid and // test a mixed case - if (BEAST_EXPECT( - std::count_if(ctid.begin(), ctid.end(), isUpper) > 1)) + if (BEAST_EXPECT(std::count_if(ctid.begin(), ctid.end(), isUpper) > 1)) { // Change the first upper case letter to lower case. std::string mixedCase = ctid; { - auto const iter = std::find_if( - mixedCase.begin(), mixedCase.end(), isUpper); + auto const iter = std::find_if(mixedCase.begin(), mixedCase.end(), isUpper); *iter = std::tolower(*iter); } BEAST_EXPECT(ctid != mixedCase); @@ -706,8 +579,7 @@ class Transaction_test : public beast::unit_test::suite jsonTx[jss::binary] = false; jsonTx[jss::ctid] = mixedCase; jsonTx[jss::id] = 1; - Json::Value const jrr = - env.rpc("json", "tx", to_string(jsonTx))[jss::result]; + Json::Value const jrr = env.rpc("json", "tx", to_string(jsonTx))[jss::result]; BEAST_EXPECT(jrr[jss::ctid] == ctid); BEAST_EXPECT(jrr[jss::hash]); } @@ -728,7 +600,7 @@ class Transaction_test : public beast::unit_test::suite env(pay(alice, bob, XRP(10))); env.close(); - auto const ledgerSeq = env.current()->info().seq; + auto const ledgerSeq = env.current()->header().seq; env(noop(alice), ter(tesSUCCESS)); env.close(); @@ -737,8 +609,7 @@ class Transaction_test : public beast::unit_test::suite params[jss::id] = 1; auto const hash = env.tx()->getJson(JsonOptions::none)[jss::hash]; params[jss::transaction] = hash; - auto const jrr = - env.rpc("json", "tx", to_string(params))[jss::result]; + auto const jrr = env.rpc("json", "tx", to_string(params))[jss::result]; BEAST_EXPECT(jrr[jss::hash] == hash); BEAST_EXPECT(jrr.isMember(jss::ctid) == (netID <= 0xFFFF)); @@ -757,7 +628,7 @@ class Transaction_test : public beast::unit_test::suite auto const alice = Account("alice"); auto const bob = Account("bob"); - auto const startLegSeq = env.current()->info().seq; + auto const startLegSeq = env.current()->header().seq; env.fund(XRP(10000), alice, bob); env(pay(alice, bob, XRP(10))); env.close(); @@ -767,8 +638,7 @@ class Transaction_test : public beast::unit_test::suite jsonTx[jss::binary] = false; jsonTx[jss::ctid] = ctid; jsonTx[jss::id] = 1; - auto const jrr = - env.rpc("json", "tx", to_string(jsonTx))[jss::result]; + auto const jrr = env.rpc("json", "tx", to_string(jsonTx))[jss::result]; BEAST_EXPECT(jrr[jss::error] == "wrongNetwork"); BEAST_EXPECT(jrr[jss::error_code] == rpcWRONG_NETWORK); BEAST_EXPECT( @@ -806,8 +676,7 @@ class Transaction_test : public beast::unit_test::suite std::shared_ptr txn = env.tx(); env.close(); - std::shared_ptr meta = - env.closed()->txRead(env.tx()->getTransactionID()).second; + std::shared_ptr meta = env.closed()->txRead(env.tx()->getTransactionID()).second; Json::Value expected = txn->getJson(JsonOptions::none); expected[jss::DeliverMax] = expected[jss::Amount]; @@ -828,12 +697,8 @@ class Transaction_test : public beast::unit_test::suite BEAST_EXPECT(result[jss::result][jss::status] == jss::success); if (apiVersion > 1) { - BEAST_EXPECT( - result[jss::result][jss::close_time_iso] == - "2000-01-01T00:00:20Z"); - BEAST_EXPECT( - result[jss::result][jss::hash] == - to_string(txn->getTransactionID())); + BEAST_EXPECT(result[jss::result][jss::close_time_iso] == "2000-01-01T00:00:20Z"); + BEAST_EXPECT(result[jss::result][jss::hash] == to_string(txn->getTransactionID())); BEAST_EXPECT(result[jss::result][jss::validated] == true); BEAST_EXPECT(result[jss::result][jss::ledger_index] == 4); BEAST_EXPECT( @@ -842,13 +707,10 @@ class Transaction_test : public beast::unit_test::suite "D2"); } - for (auto memberIt = expected.begin(); memberIt != expected.end(); - memberIt++) + for (auto memberIt = expected.begin(); memberIt != expected.end(); memberIt++) { std::string const name = memberIt.memberName(); - auto const& result_transaction = - (apiVersion > 1 ? result[jss::result][jss::tx_json] - : result[jss::result]); + auto const& result_transaction = (apiVersion > 1 ? result[jss::result][jss::tx_json] : result[jss::result]); if (BEAST_EXPECT(result_transaction.isMember(name))) { auto const received = result_transaction[name]; @@ -865,8 +727,7 @@ class Transaction_test : public beast::unit_test::suite void testBinaryRequest(unsigned apiVersion) { - testcase( - "Test binary request API version " + std::to_string(apiVersion)); + testcase("Test binary request API version " + std::to_string(apiVersion)); using namespace test::jtx; using std::to_string; @@ -882,11 +743,9 @@ class Transaction_test : public beast::unit_test::suite env.fund(XRP(1000000), alice, gw); std::shared_ptr const txn = env.tx(); BEAST_EXPECT( - to_string(txn->getTransactionID()) == - "3F8BDE5A5F82C4F4708E5E9255B713E303E6E1A371FD5C7A704AFD1387C23981"); + to_string(txn->getTransactionID()) == "3F8BDE5A5F82C4F4708E5E9255B713E303E6E1A371FD5C7A704AFD1387C23981"); env.close(); - std::shared_ptr meta = - env.closed()->txRead(txn->getTransactionID()).second; + std::shared_ptr meta = env.closed()->txRead(txn->getTransactionID()).second; std::string const expected_tx_blob = serializeHex(*txn); std::string const expected_meta_blob = serializeHex(*meta); @@ -903,31 +762,24 @@ class Transaction_test : public beast::unit_test::suite { BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result][jss::validated] == true); - BEAST_EXPECT( - result[jss::result][jss::hash] == - to_string(txn->getTransactionID())); + BEAST_EXPECT(result[jss::result][jss::hash] == to_string(txn->getTransactionID())); BEAST_EXPECT(result[jss::result][jss::ledger_index] == 3); BEAST_EXPECT(result[jss::result][jss::ctid] == "C000000300030000"); if (apiVersion > 1) { - BEAST_EXPECT( - result[jss::result][jss::tx_blob] == expected_tx_blob); - BEAST_EXPECT( - result[jss::result][jss::meta_blob] == expected_meta_blob); + BEAST_EXPECT(result[jss::result][jss::tx_blob] == expected_tx_blob); + BEAST_EXPECT(result[jss::result][jss::meta_blob] == expected_meta_blob); BEAST_EXPECT( result[jss::result][jss::ledger_hash] == "2D5150E5A5AA436736A732291E437ABF01BC9E206C2DF3C77C4F856915" "7905AA"); - BEAST_EXPECT( - result[jss::result][jss::close_time_iso] == - "2000-01-01T00:00:10Z"); + BEAST_EXPECT(result[jss::result][jss::close_time_iso] == "2000-01-01T00:00:10Z"); } else { BEAST_EXPECT(result[jss::result][jss::tx] == expected_tx_blob); - BEAST_EXPECT( - result[jss::result][jss::meta] == expected_meta_blob); + BEAST_EXPECT(result[jss::result][jss::meta] == expected_meta_blob); BEAST_EXPECT(result[jss::result][jss::date] == 10); } } @@ -938,8 +790,7 @@ public: run() override { using namespace test::jtx; - forAllApiVersions( - std::bind_front(&Transaction_test::testBinaryRequest, this)); + forAllApiVersions(std::bind_front(&Transaction_test::testBinaryRequest, this)); FeatureBitset const all{testable_amendments()}; testWithFeats(all); @@ -951,12 +802,11 @@ public: testRangeRequest(features); testRangeCTIDRequest(features); testCTIDValidation(features); - testCTIDRPC(features); - forAllApiVersions( - std::bind_front(&Transaction_test::testRequest, this, features)); + testRPCsForCTID(features); + forAllApiVersions(std::bind_front(&Transaction_test::testRequest, this, features)); } }; -BEAST_DEFINE_TESTSUITE(Transaction, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Transaction, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/ValidatorInfo_test.cpp b/src/test/rpc/ValidatorInfo_test.cpp index 78ff267e57..41fa95940b 100644 --- a/src/test/rpc/ValidatorInfo_test.cpp +++ b/src/test/rpc/ValidatorInfo_test.cpp @@ -1,21 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Dev Null Productions, LLC - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== +// Copyright (c) 2020 Dev Null Productions #include @@ -27,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class ValidatorInfo_test : public beast::unit_test::suite @@ -42,8 +25,7 @@ public: { Env env(*this); auto const info = env.rpc("validator_info"); - BEAST_EXPECT( - info[jss::result][jss::error_message] == "not a validator"); + BEAST_EXPECT(info[jss::result][jss::error_message] == "not a validator"); } } @@ -86,10 +68,8 @@ public: "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==" "\n"}; - std::string const master_key = - "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; - std::string const ephemeral_key = - "n9KsDYGKhABVc4wK5u3MnVhgPinyJimyKGpr9VJYuBaY8EnJXR2x"; + std::string const master_key = "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; + std::string const ephemeral_key = "n9KsDYGKhABVc4wK5u3MnVhgPinyJimyKGpr9VJYuBaY8EnJXR2x"; std::string const manifest = "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/" "vCxHXXLplc2GnMhAkE1agqXxBwDwDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQI" @@ -107,8 +87,7 @@ public: BEAST_EXPECT(info[jss::result][jss::seq] == 1); BEAST_EXPECT(info[jss::result][jss::master_key] == master_key); BEAST_EXPECT(info[jss::result][jss::manifest] == manifest); - BEAST_EXPECT( - info[jss::result][jss::ephemeral_key] == ephemeral_key); + BEAST_EXPECT(info[jss::result][jss::ephemeral_key] == ephemeral_key); } } @@ -121,6 +100,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ValidatorInfo, rpc, ripple); +BEAST_DEFINE_TESTSUITE(ValidatorInfo, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/ValidatorRPC_test.cpp b/src/test/rpc/ValidatorRPC_test.cpp index bc54c8567c..a46d198b5a 100644 --- a/src/test/rpc/ValidatorRPC_test.cpp +++ b/src/test/rpc/ValidatorRPC_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -30,7 +11,7 @@ #include -namespace ripple { +namespace xrpl { namespace test { @@ -70,17 +51,14 @@ public: Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)}; auto const jrr = env.rpc("server_info")[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); - BEAST_EXPECT( - jrr[jss::info].isMember(jss::validator_list) == isAdmin); + BEAST_EXPECT(jrr[jss::info].isMember(jss::validator_list) == isAdmin); } { Env env{*this, isAdmin ? envconfig() : envconfig(no_admin)}; auto const jrr = env.rpc("server_state")[jss::result]; BEAST_EXPECT(jrr[jss::status] == "success"); - BEAST_EXPECT( - jrr[jss::state].isMember(jss::validator_list_expires) == - isAdmin); + BEAST_EXPECT(jrr[jss::state].isMember(jss::validator_list_expires) == isAdmin); } } } @@ -105,9 +83,7 @@ public: // Server info reports maximum expiration since not dynamic { auto const jrr = env.rpc("server_info")[jss::result]; - BEAST_EXPECT( - jrr[jss::info][jss::validator_list][jss::expiration] == - "never"); + BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "never"); } { auto const jrr = env.rpc("server_state")[jss::result]; @@ -120,8 +96,7 @@ public: auto const jrr = env.rpc("validators")[jss::result]; BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "never"); BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == keys.size()); - BEAST_EXPECT( - jrr[jss::trusted_validator_keys].size() == keys.size()); + BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == keys.size()); BEAST_EXPECT(jrr[jss::publisher_lists].size() == 0); BEAST_EXPECT(jrr[jss::local_static_keys].size() == keys.size()); for (auto const& jKey : jrr[jss::local_static_keys]) @@ -155,12 +130,10 @@ public: BEAST_EXPECT(jrrnUnlSize == 2); for (std::uint32_t x = 0; x < jrrnUnlSize; ++x) { - auto parsedKey = parseBase58( - TokenType::NodePublic, jrrnUnl[x].asString()); + auto parsedKey = parseBase58(TokenType::NodePublic, jrrnUnl[x].asString()); BEAST_EXPECT(parsedKey); if (parsedKey) - BEAST_EXPECT( - disabledKeys.find(*parsedKey) != disabledKeys.end()); + BEAST_EXPECT(disabledKeys.find(*parsedKey) != disabledKeys.end()); } disabledKeys.clear(); @@ -175,14 +148,11 @@ public: { using namespace test::jtx; - auto toStr = [](PublicKey const& publicKey) { - return toBase58(TokenType::NodePublic, publicKey); - }; + auto toStr = [](PublicKey const& publicKey) { return toBase58(TokenType::NodePublic, publicKey); }; // Validator keys that will be in the published list std::vector validators = { - TrustedPublisherServer::randomValidator(), - TrustedPublisherServer::randomValidator()}; + TrustedPublisherServer::randomValidator(), TrustedPublisherServer::randomValidator()}; std::set expectedKeys; for (auto const& val : validators) expectedKeys.insert(toStr(val.masterPublic)); @@ -194,28 +164,20 @@ public: NetClock::time_point const validFrom2{validUntil - 60s}; NetClock::time_point const validUntil2{validFrom2 + 3600s}; auto server = make_TrustedPublisherServer( - worker.get_io_context(), - validators, - validUntil, - {{validFrom2, validUntil2}}, - false, - 1, - false); + worker.get_io_context(), validators, validUntil, {{validFrom2, validUntil2}}, false, 1, false); //---------------------------------------------------------------------- // Publisher list site unavailable v1 { // Publisher site information using namespace std::string_literals; - std::string siteURI = - "http://"s + getEnvLocalhostAddr() + ":1234/validators"; + std::string siteURI = "http://"s + getEnvLocalhostAddr() + ":1234/validators"; Env env{ *this, envconfig([&](std::unique_ptr cfg) { cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI); - cfg->section(SECTION_VALIDATOR_LIST_KEYS) - .append(strHex(server->publisherPublic())); + cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic())); return cfg; }), }; @@ -225,24 +187,18 @@ public: { auto const jrr = env.rpc("server_info")[jss::result]; - BEAST_EXPECT( - jrr[jss::info][jss::validator_list][jss::expiration] == - "unknown"); + BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "unknown"); } { auto const jrr = env.rpc("server_state")[jss::result]; - BEAST_EXPECT( - jrr[jss::state][jss::validator_list_expires].asInt() == 0); + BEAST_EXPECT(jrr[jss::state][jss::validator_list_expires].asInt() == 0); } { auto const jrr = env.rpc("validators")[jss::result]; - BEAST_EXPECT( - jrr[jss::validation_quorum].asUInt() == - std::numeric_limits::max()); + BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == std::numeric_limits::max()); BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0); BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0); - BEAST_EXPECT( - jrr[jss::validator_list][jss::expiration] == "unknown"); + BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "unknown"); if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1)) { @@ -252,9 +208,7 @@ public: BEAST_EXPECT(!jp.isMember(jss::seq)); BEAST_EXPECT(!jp.isMember(jss::expiration)); BEAST_EXPECT(!jp.isMember(jss::version)); - BEAST_EXPECT( - jp[jss::pubkey_publisher] == - strHex(server->publisherPublic())); + BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic())); } BEAST_EXPECT(jrr[jss::signing_keys].size() == 0); } @@ -274,15 +228,13 @@ public: { // Publisher site information using namespace std::string_literals; - std::string siteURI = - "http://"s + getEnvLocalhostAddr() + ":1234/validators2"; + std::string siteURI = "http://"s + getEnvLocalhostAddr() + ":1234/validators2"; Env env{ *this, envconfig([&](std::unique_ptr cfg) { cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI); - cfg->section(SECTION_VALIDATOR_LIST_KEYS) - .append(strHex(server->publisherPublic())); + cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic())); return cfg; }), }; @@ -292,24 +244,18 @@ public: { auto const jrr = env.rpc("server_info")[jss::result]; - BEAST_EXPECT( - jrr[jss::info][jss::validator_list][jss::expiration] == - "unknown"); + BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == "unknown"); } { auto const jrr = env.rpc("server_state")[jss::result]; - BEAST_EXPECT( - jrr[jss::state][jss::validator_list_expires].asInt() == 0); + BEAST_EXPECT(jrr[jss::state][jss::validator_list_expires].asInt() == 0); } { auto const jrr = env.rpc("validators")[jss::result]; - BEAST_EXPECT( - jrr[jss::validation_quorum].asUInt() == - std::numeric_limits::max()); + BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == std::numeric_limits::max()); BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0); BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == 0); - BEAST_EXPECT( - jrr[jss::validator_list][jss::expiration] == "unknown"); + BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == "unknown"); if (BEAST_EXPECT(jrr[jss::publisher_lists].size() == 1)) { @@ -319,9 +265,7 @@ public: BEAST_EXPECT(!jp.isMember(jss::seq)); BEAST_EXPECT(!jp.isMember(jss::expiration)); BEAST_EXPECT(!jp.isMember(jss::version)); - BEAST_EXPECT( - jp[jss::pubkey_publisher] == - strHex(server->publisherPublic())); + BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic())); } BEAST_EXPECT(jrr[jss::signing_keys].size() == 0); } @@ -350,8 +294,7 @@ public: *this, envconfig([&](std::unique_ptr cfg) { cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI); - cfg->section(SECTION_VALIDATOR_LIST_KEYS) - .append(strHex(server->publisherPublic())); + cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic())); return cfg; }), }; @@ -363,35 +306,24 @@ public: startKeys.insert(calcNodeID(val.masterPublic)); env.app().validators().updateTrusted( - startKeys, - env.timeKeeper().now(), - env.app().getOPs(), - env.app().overlay(), - env.app().getHashRouter()); + startKeys, env.timeKeeper().now(), env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); { auto const jrr = env.rpc("server_info")[jss::result]; - BEAST_EXPECT( - jrr[jss::info][jss::validator_list][jss::expiration] == - to_string(validUntil)); + BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == to_string(validUntil)); } { auto const jrr = env.rpc("server_state")[jss::result]; BEAST_EXPECT( - jrr[jss::state][jss::validator_list_expires].asUInt() == - validUntil.time_since_epoch().count()); + jrr[jss::state][jss::validator_list_expires].asUInt() == validUntil.time_since_epoch().count()); } { auto const jrr = env.rpc("validators")[jss::result]; BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2); - BEAST_EXPECT( - jrr[jss::validator_list][jss::expiration] == - to_string(validUntil)); + BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == to_string(validUntil)); BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0); - BEAST_EXPECT( - jrr[jss::trusted_validator_keys].size() == - expectedKeys.size()); + BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == expectedKeys.size()); for (auto const& jKey : jrr[jss::trusted_validator_keys]) { BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1); @@ -412,9 +344,7 @@ public: BEAST_EXPECT(foundKeys == expectedKeys); } BEAST_EXPECT(jp[jss::seq].asUInt() == 1); - BEAST_EXPECT( - jp[jss::pubkey_publisher] == - strHex(server->publisherPublic())); + BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic())); BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil)); BEAST_EXPECT(jp[jss::version] == 1); } @@ -423,9 +353,7 @@ public: for (auto const& val : validators) { BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic))); - BEAST_EXPECT( - jsk[toStr(val.masterPublic)] == - toStr(val.signingPublic)); + BEAST_EXPECT(jsk[toStr(val.masterPublic)] == toStr(val.signingPublic)); } } { @@ -452,8 +380,7 @@ public: *this, envconfig([&](std::unique_ptr cfg) { cfg->section(SECTION_VALIDATOR_LIST_SITES).append(siteURI); - cfg->section(SECTION_VALIDATOR_LIST_KEYS) - .append(strHex(server->publisherPublic())); + cfg->section(SECTION_VALIDATOR_LIST_KEYS).append(strHex(server->publisherPublic())); return cfg; }), }; @@ -465,35 +392,24 @@ public: startKeys.insert(calcNodeID(val.masterPublic)); env.app().validators().updateTrusted( - startKeys, - env.timeKeeper().now(), - env.app().getOPs(), - env.app().overlay(), - env.app().getHashRouter()); + startKeys, env.timeKeeper().now(), env.app().getOPs(), env.app().overlay(), env.app().getHashRouter()); { auto const jrr = env.rpc("server_info")[jss::result]; - BEAST_EXPECT( - jrr[jss::info][jss::validator_list][jss::expiration] == - to_string(validUntil2)); + BEAST_EXPECT(jrr[jss::info][jss::validator_list][jss::expiration] == to_string(validUntil2)); } { auto const jrr = env.rpc("server_state")[jss::result]; BEAST_EXPECT( - jrr[jss::state][jss::validator_list_expires].asUInt() == - validUntil2.time_since_epoch().count()); + jrr[jss::state][jss::validator_list_expires].asUInt() == validUntil2.time_since_epoch().count()); } { auto const jrr = env.rpc("validators")[jss::result]; BEAST_EXPECT(jrr[jss::validation_quorum].asUInt() == 2); - BEAST_EXPECT( - jrr[jss::validator_list][jss::expiration] == - to_string(validUntil2)); + BEAST_EXPECT(jrr[jss::validator_list][jss::expiration] == to_string(validUntil2)); BEAST_EXPECT(jrr[jss::local_static_keys].size() == 0); - BEAST_EXPECT( - jrr[jss::trusted_validator_keys].size() == - expectedKeys.size()); + BEAST_EXPECT(jrr[jss::trusted_validator_keys].size() == expectedKeys.size()); for (auto const& jKey : jrr[jss::trusted_validator_keys]) { BEAST_EXPECT(expectedKeys.count(jKey.asString()) == 1); @@ -514,13 +430,10 @@ public: BEAST_EXPECT(foundKeys == expectedKeys); } BEAST_EXPECT(jp[jss::seq].asUInt() == 1); - BEAST_EXPECT( - jp[jss::pubkey_publisher] == - strHex(server->publisherPublic())); + BEAST_EXPECT(jp[jss::pubkey_publisher] == strHex(server->publisherPublic())); BEAST_EXPECT(jp[jss::expiration] == to_string(validUntil)); BEAST_EXPECT(jp[jss::version] == 2); - if (BEAST_EXPECT(jp.isMember(jss::remaining)) && - BEAST_EXPECT(jp[jss::remaining].isArray()) && + if (BEAST_EXPECT(jp.isMember(jss::remaining)) && BEAST_EXPECT(jp[jss::remaining].isArray()) && BEAST_EXPECT(jp[jss::remaining].size() == 1)) { auto const& r = jp[jss::remaining][0u]; @@ -535,10 +448,8 @@ public: BEAST_EXPECT(foundKeys == expectedKeys); } BEAST_EXPECT(r[jss::seq].asUInt() == 2); - BEAST_EXPECT( - r[jss::effective] == to_string(validFrom2)); - BEAST_EXPECT( - r[jss::expiration] == to_string(validUntil2)); + BEAST_EXPECT(r[jss::effective] == to_string(validFrom2)); + BEAST_EXPECT(r[jss::expiration] == to_string(validUntil2)); } } auto jsk = jrr[jss::signing_keys]; @@ -546,9 +457,7 @@ public: for (auto const& val : validators) { BEAST_EXPECT(jsk.isMember(toStr(val.masterPublic))); - BEAST_EXPECT( - jsk[toStr(val.masterPublic)] == - toStr(val.signingPublic)); + BEAST_EXPECT(jsk[toStr(val.masterPublic)] == toStr(val.signingPublic)); } } { @@ -573,15 +482,9 @@ public: using namespace test::jtx; Env env{*this}; auto result = env.rpc("validation_create"); - BEAST_EXPECT( - result.isMember(jss::result) && - result[jss::result][jss::status] == "success"); - result = env.rpc( - "validation_create", - "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE"); - BEAST_EXPECT( - result.isMember(jss::result) && - result[jss::result][jss::status] == "success"); + BEAST_EXPECT(result.isMember(jss::result) && result[jss::result][jss::status] == "success"); + result = env.rpc("validation_create", "BAWL MAN JADE MOON DOVE GEM SON NOW HAD ADEN GLOW TIRE"); + BEAST_EXPECT(result.isMember(jss::result) && result[jss::result][jss::status] == "success"); } void @@ -594,7 +497,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ValidatorRPC, rpc, ripple); +BEAST_DEFINE_TESTSUITE(ValidatorRPC, rpc, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/rpc/Version_test.cpp b/src/test/rpc/Version_test.cpp index 4c310b9ab9..1dec8627ed 100644 --- a/src/test/rpc/Version_test.cpp +++ b/src/test/rpc/Version_test.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { class Version_test : public beast::unit_test::suite { @@ -43,9 +24,7 @@ class Version_test : public beast::unit_test::suite auto jrr = env.rpc( "json", "version", - "{\"api_version\": " + - std::to_string(RPC::apiMaximumSupportedVersion) + - "}")[jss::result]; + "{\"api_version\": " + std::to_string(RPC::apiMaximumSupportedVersion) + "}")[jss::result]; BEAST_EXPECT(isCorrectReply(jrr)); jrr = env.rpc("version")[jss::result]; @@ -64,17 +43,13 @@ class Version_test : public beast::unit_test::suite if (re.isMember("error_what")) if (re["error_what"].isString()) { - return re["error_what"].asString().find( - jss::invalid_API_version.c_str()) == 0; + return re["error_what"].asString().find(jss::invalid_API_version.c_str()) == 0; } return false; }; auto re = env.rpc( - "json", - "version", - "{\"api_version\": " + - std::to_string(RPC::apiMinimumSupportedVersion - 1) + "}"); + "json", "version", "{\"api_version\": " + std::to_string(RPC::apiMinimumSupportedVersion - 1) + "}"); BEAST_EXPECT(badVersion(re)); BEAST_EXPECT(env.app().config().BETA_RPC_API); @@ -82,12 +57,7 @@ class Version_test : public beast::unit_test::suite "json", "version", "{\"api_version\": " + - std::to_string( - std::max( - RPC::apiMaximumSupportedVersion.value, - RPC::apiBetaVersion.value) + - 1) + - "}"); + std::to_string(std::max(RPC::apiMaximumSupportedVersion.value, RPC::apiBetaVersion.value) + 1) + "}"); BEAST_EXPECT(badVersion(re)); re = env.rpc("json", "version", "{\"api_version\": \"a\"}"); @@ -99,57 +69,38 @@ class Version_test : public beast::unit_test::suite { testcase("test getAPIVersionNumber function"); - unsigned int versionIfUnspecified = - RPC::apiVersionIfUnspecified < RPC::apiMinimumSupportedVersion + unsigned int versionIfUnspecified = RPC::apiVersionIfUnspecified < RPC::apiMinimumSupportedVersion ? RPC::apiInvalidVersion : RPC::apiVersionIfUnspecified; Json::Value j_array = Json::Value(Json::arrayValue); Json::Value j_null = Json::Value(Json::nullValue); - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_array, false) == versionIfUnspecified); - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_null, false) == versionIfUnspecified); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_array, false) == versionIfUnspecified); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_null, false) == versionIfUnspecified); Json::Value j_object = Json::Value(Json::objectValue); - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); j_object[jss::api_version] = RPC::apiVersionIfUnspecified.value; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); j_object[jss::api_version] = RPC::apiMinimumSupportedVersion.value; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiMinimumSupportedVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiMinimumSupportedVersion); j_object[jss::api_version] = RPC::apiMaximumSupportedVersion.value; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiMaximumSupportedVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiMaximumSupportedVersion); j_object[jss::api_version] = RPC::apiMinimumSupportedVersion - 1; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiInvalidVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiInvalidVersion); j_object[jss::api_version] = RPC::apiMaximumSupportedVersion + 1; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiInvalidVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiInvalidVersion); j_object[jss::api_version] = RPC::apiBetaVersion.value; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, true) == RPC::apiBetaVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, true) == RPC::apiBetaVersion); j_object[jss::api_version] = RPC::apiBetaVersion + 1; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, true) == RPC::apiInvalidVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, true) == RPC::apiInvalidVersion); j_object[jss::api_version] = RPC::apiInvalidVersion.value; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiInvalidVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiInvalidVersion); j_object[jss::api_version] = "a"; - BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object, false) == - RPC::apiInvalidVersion); + BEAST_EXPECT(RPC::getAPIVersionNumber(j_object, false) == RPC::apiInvalidVersion); } void @@ -174,19 +125,14 @@ class Version_test : public beast::unit_test::suite "\"params\": { " "\"api_version\": " + std::to_string(RPC::apiMaximumSupportedVersion) + "}}"; - auto re = env.rpc( - "json2", '[' + without_api_verion + ", " + with_api_verion + ']'); + auto re = env.rpc("json2", '[' + without_api_verion + ", " + with_api_verion + ']'); if (!BEAST_EXPECT(re.isArray())) return; if (!BEAST_EXPECT(re.size() == 2)) return; - BEAST_EXPECT( - re[0u].isMember(jss::result) && - re[0u][jss::result].isMember(jss::version)); - BEAST_EXPECT( - re[1u].isMember(jss::result) && - re[1u][jss::result].isMember(jss::version)); + BEAST_EXPECT(re[0u].isMember(jss::result) && re[0u][jss::result].isMember(jss::version)); + BEAST_EXPECT(re[1u].isMember(jss::result) && re[1u][jss::result].isMember(jss::version)); } void @@ -211,22 +157,14 @@ class Version_test : public beast::unit_test::suite "\"method\": \"version\", " "\"params\": { " "\"api_version\": " + - std::to_string(std::max( - RPC::apiMaximumSupportedVersion.value, - RPC::apiBetaVersion.value) + - 1) + - "}}"; - auto re = env.rpc( - "json2", - '[' + without_api_verion + ", " + with_wrong_api_verion + ']'); + std::to_string(std::max(RPC::apiMaximumSupportedVersion.value, RPC::apiBetaVersion.value) + 1) + "}}"; + auto re = env.rpc("json2", '[' + without_api_verion + ", " + with_wrong_api_verion + ']'); if (!BEAST_EXPECT(re.isArray())) return; if (!BEAST_EXPECT(re.size() == 2)) return; - BEAST_EXPECT( - re[0u].isMember(jss::result) && - re[0u][jss::result].isMember(jss::version)); + BEAST_EXPECT(re[0u].isMember(jss::result) && re[0u][jss::result].isMember(jss::version)); BEAST_EXPECT(re[1u].isMember(jss::error)); } @@ -265,20 +203,14 @@ class Version_test : public beast::unit_test::suite if (!BEAST_EXPECT(env.app().config().BETA_RPC_API == true)) return; - auto jrr = env.rpc( - "json", - "version", - "{\"api_version\": " + std::to_string(RPC::apiBetaVersion) + - "}")[jss::result]; + auto jrr = + env.rpc("json", "version", "{\"api_version\": " + std::to_string(RPC::apiBetaVersion) + "}")[jss::result]; if (!BEAST_EXPECT(jrr.isMember(jss::version))) return; - if (!BEAST_EXPECT(jrr[jss::version].isMember(jss::first)) && - jrr[jss::version].isMember(jss::last)) + if (!BEAST_EXPECT(jrr[jss::version].isMember(jss::first)) && jrr[jss::version].isMember(jss::last)) return; - BEAST_EXPECT( - jrr[jss::version][jss::first] == - RPC::apiMinimumSupportedVersion.value); + BEAST_EXPECT(jrr[jss::version][jss::first] == RPC::apiMinimumSupportedVersion.value); BEAST_EXPECT(jrr[jss::version][jss::last] == RPC::apiBetaVersion.value); } @@ -296,6 +228,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Version, rpc, ripple); +BEAST_DEFINE_TESTSUITE(Version, rpc, xrpl); -} // namespace ripple +} // namespace xrpl diff --git a/src/test/server/ServerStatus_test.cpp b/src/test/server/ServerStatus_test.cpp index 8bbad2cd99..ccfdf2fd2b 100644 --- a/src/test/server/ServerStatus_test.cpp +++ b/src/test/server/ServerStatus_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -43,24 +24,19 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { -class ServerStatus_test : public beast::unit_test::suite, - public beast::test::enable_yield_to +class ServerStatus_test : public beast::unit_test::suite, public beast::test::enable_yield_to { class myFields : public boost::beast::http::fields { }; auto - makeConfig( - std::string const& proto, - bool admin = true, - bool credentials = false) + makeConfig(std::string const& proto, bool admin = true, bool credentials = false) { - auto const section_name = - boost::starts_with(proto, "h") ? "port_rpc" : "port_ws"; + auto const section_name = boost::starts_with(proto, "h") ? "port_rpc" : "port_ws"; auto p = jtx::envconfig(); p->overwrite(section_name, "protocol", proto); @@ -114,8 +90,7 @@ class ServerStatus_test : public beast::unit_test::suite, std::array key; for (auto& v : key) v = d(e); - req.insert( - "Sec-WebSocket-Key", base64_encode(key.data(), key.size())); + req.insert("Sec-WebSocket-Key", base64_encode(key.data(), key.size())); }; req.insert("Sec-WebSocket-Version", "13"); req.insert(boost::beast::http::field::connection, "upgrade"); @@ -123,11 +98,7 @@ class ServerStatus_test : public beast::unit_test::suite, } auto - makeHTTPRequest( - std::string const& host, - uint16_t port, - std::string const& body, - myFields const& fields) + makeHTTPRequest(std::string const& host, uint16_t port, std::string const& body, myFields const& fields) { using namespace boost::asio; using namespace boost::beast::http; @@ -218,11 +189,9 @@ class ServerStatus_test : public beast::unit_test::suite, boost::beast::http::response& resp, boost::system::error_code& ec) { - auto const port = - env.app().config()["port_ws"].get("port"); + auto const port = env.app().config()["port_ws"].get("port"); auto ip = env.app().config()["port_ws"].get("ip"); - doRequest( - yield, makeWSUpgrade(*ip, *port), *ip, *port, secure, resp, ec); + doRequest(yield, makeWSUpgrade(*ip, *port), *ip, *port, secure, resp, ec); return; } @@ -236,17 +205,9 @@ class ServerStatus_test : public beast::unit_test::suite, std::string const& body = "", myFields const& fields = {}) { - auto const port = - env.app().config()["port_rpc"].get("port"); + auto const port = env.app().config()["port_rpc"].get("port"); auto const ip = env.app().config()["port_rpc"].get("ip"); - doRequest( - yield, - makeHTTPRequest(*ip, *port, body, fields), - *ip, - *port, - secure, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip, *port, body, fields), *ip, *port, secure, resp, ec); return; } @@ -298,9 +259,8 @@ class ServerStatus_test : public beast::unit_test::suite, void testAdminRequest(std::string const& proto, bool admin, bool credentials) { - testcase << "Admin request over " << proto << ", config " - << (admin ? "enabled" : "disabled") << ", credentials " - << (credentials ? "" : "not ") << "set"; + testcase << "Admin request over " << proto << ", config " << (admin ? "enabled" : "disabled") + << ", credentials " << (credentials ? "" : "not ") << "set"; using namespace jtx; Env env{*this, makeConfig(proto, admin, credentials)}; @@ -312,53 +272,34 @@ class ServerStatus_test : public beast::unit_test::suite, if (admin && credentials) { - auto const user = env.app() - .config()[proto_ws ? "port_ws" : "port_rpc"] - .get("admin_user"); + auto const user = env.app().config()[proto_ws ? "port_ws" : "port_rpc"].get("admin_user"); auto const password = - env.app() - .config()[proto_ws ? "port_ws" : "port_rpc"] - .get("admin_password"); + env.app().config()[proto_ws ? "port_ws" : "port_rpc"].get("admin_password"); // 1 - FAILS with wrong pass - jrr = makeAdminRequest( - env, proto, *user, *password + "_")[jss::result]; + jrr = makeAdminRequest(env, proto, *user, *password + "_")[jss::result]; + BEAST_EXPECT(jrr["error"] == proto_ws ? "forbidden" : "noPermission"); BEAST_EXPECT( - jrr["error"] == proto_ws ? "forbidden" : "noPermission"); - BEAST_EXPECT( - jrr["error_message"] == proto_ws - ? "Bad credentials." - : "You don't have permission for this command."); + jrr["error_message"] == proto_ws ? "Bad credentials." : "You don't have permission for this command."); // 2 - FAILS with password in an object - jrr = makeAdminRequest( - env, proto, *user, *password, true)[jss::result]; + jrr = makeAdminRequest(env, proto, *user, *password, true)[jss::result]; + BEAST_EXPECT(jrr["error"] == proto_ws ? "forbidden" : "noPermission"); BEAST_EXPECT( - jrr["error"] == proto_ws ? "forbidden" : "noPermission"); - BEAST_EXPECT( - jrr["error_message"] == proto_ws - ? "Bad credentials." - : "You don't have permission for this command."); + jrr["error_message"] == proto_ws ? "Bad credentials." : "You don't have permission for this command."); // 3 - FAILS with wrong user - jrr = makeAdminRequest( - env, proto, *user + "_", *password)[jss::result]; + jrr = makeAdminRequest(env, proto, *user + "_", *password)[jss::result]; + BEAST_EXPECT(jrr["error"] == proto_ws ? "forbidden" : "noPermission"); BEAST_EXPECT( - jrr["error"] == proto_ws ? "forbidden" : "noPermission"); - BEAST_EXPECT( - jrr["error_message"] == proto_ws - ? "Bad credentials." - : "You don't have permission for this command."); + jrr["error_message"] == proto_ws ? "Bad credentials." : "You don't have permission for this command."); // 4 - FAILS no credentials jrr = makeAdminRequest(env, proto, "", "")[jss::result]; + BEAST_EXPECT(jrr["error"] == proto_ws ? "forbidden" : "noPermission"); BEAST_EXPECT( - jrr["error"] == proto_ws ? "forbidden" : "noPermission"); - BEAST_EXPECT( - jrr["error_message"] == proto_ws - ? "Bad credentials." - : "You don't have permission for this command."); + jrr["error_message"] == proto_ws ? "Bad credentials." : "You don't have permission for this command."); // 5 - SUCCEEDS with proper credentials jrr = makeAdminRequest(env, proto, *user, *password)[jss::result]; @@ -378,12 +319,9 @@ class ServerStatus_test : public beast::unit_test::suite, { // 1 - FAILS - admin disabled jrr = makeAdminRequest(env, proto, "", "")[jss::result]; + BEAST_EXPECT(jrr["error"] == proto_ws ? "forbidden" : "noPermission"); BEAST_EXPECT( - jrr["error"] == proto_ws ? "forbidden" : "noPermission"); - BEAST_EXPECT( - jrr["error_message"] == proto_ws - ? "Bad credentials." - : "You don't have permission for this command."); + jrr["error_message"] == proto_ws ? "Bad credentials." : "You don't have permission for this command."); } } @@ -404,8 +342,7 @@ class ServerStatus_test : public beast::unit_test::suite, doWSRequest(env, yield, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; - BEAST_EXPECT( - resp.result() == boost::beast::http::status::unauthorized); + BEAST_EXPECT(resp.result() == boost::beast::http::status::unauthorized); } // secure request @@ -415,8 +352,7 @@ class ServerStatus_test : public beast::unit_test::suite, doWSRequest(env, yield, true, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; - BEAST_EXPECT( - resp.result() == boost::beast::http::status::unauthorized); + BEAST_EXPECT(resp.result() == boost::beast::http::status::unauthorized); } } @@ -464,8 +400,7 @@ class ServerStatus_test : public beast::unit_test::suite, return cfg; })}; - auto const port = - env.app().config()["port_ws"].get("port"); + auto const port = env.app().config()["port_ws"].get("port"); auto const ip = env.app().config()["port_ws"].get("ip"); boost::system::error_code ec; @@ -506,8 +441,7 @@ class ServerStatus_test : public beast::unit_test::suite, // The essence of this test is to have a client and server configured // out-of-phase with respect to ssl (secure client and insecure server // or vice-versa) - testcase << "Connect fails: " << client_protocol << " client to " - << server_protocol << " server"; + testcase << "Connect fails: " << client_protocol << " client to " << server_protocol << " server"; using namespace jtx; Env env{*this, makeConfig(server_protocol)}; @@ -520,12 +454,7 @@ class ServerStatus_test : public beast::unit_test::suite, } else { - doWSRequest( - env, - yield, - client_protocol == "wss" || client_protocol == "wss2", - resp, - ec); + doWSRequest(env, yield, client_protocol == "wss" || client_protocol == "wss2", resp, ec); BEAST_EXPECT(ec); } } @@ -533,15 +462,13 @@ class ServerStatus_test : public beast::unit_test::suite, void testAuth(bool secure, boost::asio::yield_context& yield) { - testcase << "Server with authorization, " - << (secure ? "secure" : "non-secure"); + testcase << "Server with authorization, " << (secure ? "secure" : "non-secure"); using namespace test::jtx; Env env{*this, envconfig([secure](std::unique_ptr cfg) { (*cfg)["port_rpc"].set("user", "me"); (*cfg)["port_rpc"].set("password", "secret"); - (*cfg)["port_rpc"].set( - "protocol", secure ? "https" : "http"); + (*cfg)["port_rpc"].set("protocol", secure ? "https" : "http"); if (secure) (*cfg)["port_ws"].set("protocol", "http,ws"); return cfg; @@ -567,16 +494,8 @@ class ServerStatus_test : public beast::unit_test::suite, doHTTPRequest(env, yield, secure, resp, ec, to_string(jr), auth); BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden); - auto const user = env.app() - .config() - .section("port_rpc") - .get("user") - .value(); - auto const pass = env.app() - .config() - .section("port_rpc") - .get("password") - .value(); + auto const user = env.app().config().section("port_rpc").get("user").value(); + auto const pass = env.app().config().section("port_rpc").get("password").value(); // try with the correct user/pass, but not encoded auth.set("Authorization", "Basic " + user + ":" + pass); @@ -603,10 +522,8 @@ class ServerStatus_test : public beast::unit_test::suite, return cfg; })}; - auto const port = - env.app().config()["port_rpc"].get("port").value(); - auto const ip = - env.app().config()["port_rpc"].get("ip").value(); + auto const port = env.app().config()["port_rpc"].get("port").value(); + auto const ip = env.app().config()["port_rpc"].get("ip").value(); boost::system::error_code ec; io_context& ios = get_io_context(); @@ -618,8 +535,7 @@ class ServerStatus_test : public beast::unit_test::suite, auto it = r.async_resolve(ip, std::to_string(port), yield[ec]); BEAST_EXPECT(!ec); - std::vector> - clients; + std::vector> clients; int connectionCount{1}; // starts at 1 because the Env already has one // for JSONRPCCLient @@ -631,8 +547,7 @@ class ServerStatus_test : public beast::unit_test::suite, int testTo = (limit == 0) ? 50 : limit + 1; while (connectionCount < testTo) { - clients.emplace_back(std::make_pair( - ip::tcp::socket{ios}, boost::beast::multi_buffer{})); + clients.emplace_back(std::make_pair(ip::tcp::socket{ios}, boost::beast::multi_buffer{})); async_connect(clients.back().first, it, yield[ec]); BEAST_EXPECT(!ec); auto req = makeHTTPRequest(ip, port, to_string(jr), {}); @@ -649,8 +564,7 @@ class ServerStatus_test : public beast::unit_test::suite, ++readCount; // expect the reads to fail for the clients that connected at or // above the limit. If limit is 0, all reads should succeed - BEAST_EXPECT( - (limit == 0 || readCount < limit - 1) ? (!ec) : bool(ec)); + BEAST_EXPECT((limit == 0 || readCount < limit - 1) ? (!ec) : bool(ec)); } } @@ -665,21 +579,14 @@ class ServerStatus_test : public beast::unit_test::suite, return cfg; })}; - auto const port = - env.app().config()["port_ws"].get("port").value(); - auto const ip = - env.app().config()["port_ws"].get("ip").value(); + auto const port = env.app().config()["port_ws"].get("port").value(); + auto const ip = env.app().config()["port_ws"].get("ip").value(); boost::beast::http::response resp; boost::system::error_code ec; doRequest(yield, makeWSUpgrade(ip, port), ip, port, true, resp, ec); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::switching_protocols); - BEAST_EXPECT( - resp.find("Upgrade") != resp.end() && - resp["Upgrade"] == "websocket"); - BEAST_EXPECT( - resp.find("Connection") != resp.end() && - boost::iequals(resp["Connection"], "upgrade")); + BEAST_EXPECT(resp.result() == boost::beast::http::status::switching_protocols); + BEAST_EXPECT(resp.find("Upgrade") != resp.end() && resp["Upgrade"] == "websocket"); + BEAST_EXPECT(resp.find("Connection") != resp.end() && boost::iequals(resp["Connection"], "upgrade")); } void @@ -690,22 +597,13 @@ class ServerStatus_test : public beast::unit_test::suite, using namespace test::jtx; Env env{*this}; - auto const port = - env.app().config()["port_ws"].get("port").value(); - auto const ip = - env.app().config()["port_ws"].get("ip").value(); + auto const port = env.app().config()["port_ws"].get("port").value(); + auto const ip = env.app().config()["port_ws"].get("ip").value(); boost::beast::http::response resp; boost::system::error_code ec; // body content is required here to avoid being // detected as a status request - doRequest( - yield, - makeHTTPRequest(ip, port, "foo", {}), - ip, - port, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(ip, port, "foo", {}), ip, port, false, resp, ec); BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden); BEAST_EXPECT(resp.body() == "Forbidden\r\n"); } @@ -720,10 +618,8 @@ class ServerStatus_test : public beast::unit_test::suite, using namespace boost::beast::http; Env env{*this}; - auto const port = - env.app().config()["port_ws"].get("port").value(); - auto const ip = - env.app().config()["port_ws"].get("ip").value(); + auto const port = env.app().config()["port_ws"].get("port").value(); + auto const ip = env.app().config()["port_ws"].get("ip").value(); boost::system::error_code ec; io_context& ios = get_io_context(); @@ -754,10 +650,8 @@ class ServerStatus_test : public beast::unit_test::suite, Json::Value resp; Json::Reader jr; - if (!BEAST_EXPECT(jr.parse( - boost::lexical_cast( - boost::beast::make_printable(sb.data())), - resp))) + if (!BEAST_EXPECT( + jr.parse(boost::lexical_cast(boost::beast::make_printable(sb.data())), resp))) return Json::objectValue; sb.consume(sb.size()); return resp; @@ -765,8 +659,7 @@ class ServerStatus_test : public beast::unit_test::suite, { // send invalid json auto resp = sendAndParse("NOT JSON"); - BEAST_EXPECT( - resp.isMember(jss::error) && resp[jss::error] == "jsonInvalid"); + BEAST_EXPECT(resp.isMember(jss::error) && resp[jss::error] == "jsonInvalid"); BEAST_EXPECT(!resp.isMember(jss::status)); } @@ -775,22 +668,17 @@ class ServerStatus_test : public beast::unit_test::suite, jv[jss::command] = "foo"; jv[jss::method] = "bar"; auto resp = sendAndParse(to_string(jv)); - BEAST_EXPECT( - resp.isMember(jss::error) && - resp[jss::error] == "missingCommand"); - BEAST_EXPECT( - resp.isMember(jss::status) && resp[jss::status] == "error"); + BEAST_EXPECT(resp.isMember(jss::error) && resp[jss::error] == "missingCommand"); + BEAST_EXPECT(resp.isMember(jss::status) && resp[jss::status] == "error"); } { // send a ping (not an error) Json::Value jv; jv[jss::command] = "ping"; auto resp = sendAndParse(to_string(jv)); + BEAST_EXPECT(resp.isMember(jss::status) && resp[jss::status] == "success"); BEAST_EXPECT( - resp.isMember(jss::status) && resp[jss::status] == "success"); - BEAST_EXPECT( - resp.isMember(jss::result) && - resp[jss::result].isMember(jss::role) && + resp.isMember(jss::result) && resp[jss::result].isMember(jss::role) && resp[jss::result][jss::role] == "admin"); } } @@ -798,8 +686,7 @@ class ServerStatus_test : public beast::unit_test::suite, void testAmendmentWarning(boost::asio::yield_context& yield) { - testcase( - "Status request over WS and RPC with/without Amendment Warning"); + testcase("Status request over WS and RPC with/without Amendment Warning"); using namespace jtx; using namespace boost::asio; using namespace boost::beast::http; @@ -824,8 +711,7 @@ class ServerStatus_test : public beast::unit_test::suite, auto si = env.rpc("server_info")[jss::result]; BEAST_EXPECT(si.isMember(jss::info)); BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked)); - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == true); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == true); BEAST_EXPECT(!si.isMember(jss::warnings)); // make an RPC server state request and look for @@ -833,39 +719,28 @@ class ServerStatus_test : public beast::unit_test::suite, si = env.rpc("server_state")[jss::result]; BEAST_EXPECT(si.isMember(jss::state)); BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked)); - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == true); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == true); BEAST_EXPECT(!si[jss::state].isMember(jss::warnings)); - auto const port_ws = - env.app().config()["port_ws"].get("port"); + auto const port_ws = env.app().config()["port_ws"].get("port"); auto const ip_ws = env.app().config()["port_ws"].get("ip"); boost::system::error_code ec; response resp; - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; BEAST_EXPECT(resp.result() == boost::beast::http::status::ok); - BEAST_EXPECT( - resp.body().find("connectivity is working.") != std::string::npos); + BEAST_EXPECT(resp.body().find("connectivity is working.") != std::string::npos); // mark the Network as having an Amendment Warning, but won't fail env.app().getOPs().setAmendmentWarned(); - env.app().getOPs().beginConsensus(env.closed()->info().hash, {}); + env.app().getOPs().beginConsensus(env.closed()->header().hash, {}); // consensus doesn't change - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == true); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == true); // RPC request server_info again, now unsupported majority should be // returned @@ -873,11 +748,9 @@ class ServerStatus_test : public beast::unit_test::suite, BEAST_EXPECT(si.isMember(jss::info)); BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked)); BEAST_EXPECT( - si[jss::info].isMember(jss::warnings) && - si[jss::info][jss::warnings].isArray() && + si[jss::info].isMember(jss::warnings) && si[jss::info][jss::warnings].isArray() && si[jss::info][jss::warnings].size() == 1 && - si[jss::info][jss::warnings][0u][jss::id].asInt() == - warnRPC_UNSUPPORTED_MAJORITY); + si[jss::info][jss::warnings][0u][jss::id].asInt() == warnRPC_UNSUPPORTED_MAJORITY); // RPC request server_state again, now unsupported majority should be // returned @@ -885,45 +758,27 @@ class ServerStatus_test : public beast::unit_test::suite, BEAST_EXPECT(si.isMember(jss::state)); BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked)); BEAST_EXPECT( - si[jss::state].isMember(jss::warnings) && - si[jss::state][jss::warnings].isArray() && + si[jss::state].isMember(jss::warnings) && si[jss::state][jss::warnings].isArray() && si[jss::state][jss::warnings].size() == 1 && - si[jss::state][jss::warnings][0u][jss::id].asInt() == - warnRPC_UNSUPPORTED_MAJORITY); + si[jss::state][jss::warnings][0u][jss::id].asInt() == warnRPC_UNSUPPORTED_MAJORITY); // but status does not indicate a problem - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; BEAST_EXPECT(resp.result() == boost::beast::http::status::ok); - BEAST_EXPECT( - resp.body().find("connectivity is working.") != std::string::npos); + BEAST_EXPECT(resp.body().find("connectivity is working.") != std::string::npos); // with ELB_SUPPORT, status still does not indicate a problem env.app().config().ELB_SUPPORT = true; - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; BEAST_EXPECT(resp.result() == boost::beast::http::status::ok); - BEAST_EXPECT( - resp.body().find("connectivity is working.") != std::string::npos); + BEAST_EXPECT(resp.body().find("connectivity is working.") != std::string::npos); } void @@ -954,8 +809,7 @@ class ServerStatus_test : public beast::unit_test::suite, auto si = env.rpc("server_info")[jss::result]; BEAST_EXPECT(si.isMember(jss::info)); BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked)); - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == true); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == true); BEAST_EXPECT(!si.isMember(jss::warnings)); // make an RPC server state request and look for @@ -963,102 +817,65 @@ class ServerStatus_test : public beast::unit_test::suite, si = env.rpc("server_state")[jss::result]; BEAST_EXPECT(si.isMember(jss::state)); BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked)); - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == true); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == true); BEAST_EXPECT(!si[jss::state].isMember(jss::warnings)); - auto const port_ws = - env.app().config()["port_ws"].get("port"); + auto const port_ws = env.app().config()["port_ws"].get("port"); auto const ip_ws = env.app().config()["port_ws"].get("ip"); boost::system::error_code ec; response resp; - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; BEAST_EXPECT(resp.result() == boost::beast::http::status::ok); - BEAST_EXPECT( - resp.body().find("connectivity is working.") != std::string::npos); + BEAST_EXPECT(resp.body().find("connectivity is working.") != std::string::npos); // mark the Network as Amendment Blocked, but still won't fail until // ELB is enabled (next step) env.app().getOPs().setAmendmentBlocked(); - env.app().getOPs().beginConsensus(env.closed()->info().hash, {}); + env.app().getOPs().beginConsensus(env.closed()->header().hash, {}); // consensus now sees validation disabled - BEAST_EXPECT( - env.app().getOPs().getConsensusInfo()["validating"] == false); + BEAST_EXPECT(env.app().getOPs().getConsensusInfo()["validating"] == false); // RPC request server_info again, now AB should be returned si = env.rpc("server_info")[jss::result]; BEAST_EXPECT(si.isMember(jss::info)); + BEAST_EXPECT(si[jss::info].isMember(jss::amendment_blocked) && si[jss::info][jss::amendment_blocked] == true); BEAST_EXPECT( - si[jss::info].isMember(jss::amendment_blocked) && - si[jss::info][jss::amendment_blocked] == true); - BEAST_EXPECT( - si[jss::info].isMember(jss::warnings) && - si[jss::info][jss::warnings].isArray() && + si[jss::info].isMember(jss::warnings) && si[jss::info][jss::warnings].isArray() && si[jss::info][jss::warnings].size() == 1 && - si[jss::info][jss::warnings][0u][jss::id].asInt() == - warnRPC_AMENDMENT_BLOCKED); + si[jss::info][jss::warnings][0u][jss::id].asInt() == warnRPC_AMENDMENT_BLOCKED); // RPC request server_state again, now AB should be returned si = env.rpc("server_state")[jss::result]; + BEAST_EXPECT(si[jss::state].isMember(jss::amendment_blocked) && si[jss::state][jss::amendment_blocked] == true); BEAST_EXPECT( - si[jss::state].isMember(jss::amendment_blocked) && - si[jss::state][jss::amendment_blocked] == true); - BEAST_EXPECT( - si[jss::state].isMember(jss::warnings) && - si[jss::state][jss::warnings].isArray() && + si[jss::state].isMember(jss::warnings) && si[jss::state][jss::warnings].isArray() && si[jss::state][jss::warnings].size() == 1 && - si[jss::state][jss::warnings][0u][jss::id].asInt() == - warnRPC_AMENDMENT_BLOCKED); + si[jss::state][jss::warnings][0u][jss::id].asInt() == warnRPC_AMENDMENT_BLOCKED); // but status does not indicate because it still relies on ELB // being enabled - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; BEAST_EXPECT(resp.result() == boost::beast::http::status::ok); - BEAST_EXPECT( - resp.body().find("connectivity is working.") != std::string::npos); + BEAST_EXPECT(resp.body().find("connectivity is working.") != std::string::npos); env.app().config().ELB_SUPPORT = true; - doRequest( - yield, - makeHTTPRequest(*ip_ws, *port_ws, "", {}), - *ip_ws, - *port_ws, - false, - resp, - ec); + doRequest(yield, makeHTTPRequest(*ip_ws, *port_ws, "", {}), *ip_ws, *port_ws, false, resp, ec); if (!BEAST_EXPECTS(!ec, ec.message())) return; - BEAST_EXPECT( - resp.result() == boost::beast::http::status::internal_server_error); - BEAST_EXPECT( - resp.body().find("cannot accept clients:") != std::string::npos); - BEAST_EXPECT( - resp.body().find("Server version too old") != std::string::npos); + BEAST_EXPECT(resp.result() == boost::beast::http::status::internal_server_error); + BEAST_EXPECT(resp.body().find("cannot accept clients:") != std::string::npos); + BEAST_EXPECT(resp.body().find("Server version too old") != std::string::npos); } void @@ -1073,8 +890,7 @@ class ServerStatus_test : public beast::unit_test::suite, { boost::beast::http::response resp; doHTTPRequest(env, yield, false, resp, ec, "{}"); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Unable to parse request: \r\n"); } @@ -1083,8 +899,7 @@ class ServerStatus_test : public beast::unit_test::suite, Json::Value jv; jv["invalid"] = 1; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Null method\r\n"); } @@ -1093,8 +908,7 @@ class ServerStatus_test : public beast::unit_test::suite, Json::Value jv(Json::arrayValue); jv.append("invalid"); doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Unable to parse request: \r\n"); } @@ -1105,8 +919,7 @@ class ServerStatus_test : public beast::unit_test::suite, j["invalid"] = 1; jv.append(j); doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Unable to parse request: \r\n"); } @@ -1116,8 +929,7 @@ class ServerStatus_test : public beast::unit_test::suite, jv[jss::method] = "batch"; jv[jss::params] = 2; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Malformed batch request\r\n"); } @@ -1128,8 +940,7 @@ class ServerStatus_test : public beast::unit_test::suite, jv[jss::params] = Json::objectValue; jv[jss::params]["invalid"] = 3; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Malformed batch request\r\n"); } @@ -1138,8 +949,7 @@ class ServerStatus_test : public beast::unit_test::suite, boost::beast::http::response resp; jv[jss::method] = Json::nullValue; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "Null method\r\n"); } @@ -1147,8 +957,7 @@ class ServerStatus_test : public beast::unit_test::suite, boost::beast::http::response resp; jv[jss::method] = 1; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "method is not string\r\n"); } @@ -1156,8 +965,7 @@ class ServerStatus_test : public beast::unit_test::suite, boost::beast::http::response resp; jv[jss::method] = ""; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); BEAST_EXPECT(resp.body() == "method is empty\r\n"); } @@ -1166,9 +974,8 @@ class ServerStatus_test : public beast::unit_test::suite, jv[jss::method] = "some_method"; jv[jss::params] = "params"; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); - BEAST_EXPECT(resp.body() == "params unparseable\r\n"); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.body() == "params unparsable\r\n"); } { @@ -1176,9 +983,8 @@ class ServerStatus_test : public beast::unit_test::suite, jv[jss::params] = Json::arrayValue; jv[jss::params][0u] = "not an object"; doHTTPRequest(env, yield, false, resp, ec, to_string(jv)); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::bad_request); - BEAST_EXPECT(resp.body() == "params unparseable\r\n"); + BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request); + BEAST_EXPECT(resp.body() == "params unparsable\r\n"); } } @@ -1199,8 +1005,7 @@ class ServerStatus_test : public beast::unit_test::suite, boost::beast::http::response resp; boost::system::error_code ec; doHTTPRequest(env, yield, false, resp, ec); - BEAST_EXPECT( - resp.result() == boost::beast::http::status::internal_server_error); + BEAST_EXPECT(resp.result() == boost::beast::http::status::internal_server_error); std::regex body{"Server cannot accept clients"}; BEAST_EXPECT(std::regex_search(resp.body(), body)); } @@ -1245,7 +1050,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(ServerStatus, server, ripple); +BEAST_DEFINE_TESTSUITE(ServerStatus, server, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index 874558f428..7347bf238c 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -41,7 +22,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { using socket_type = boost::beast::tcp_stream; @@ -54,9 +35,7 @@ public: { private: boost::asio::io_context io_context_; - std::optional> - work_; + std::optional> work_; std::thread thread_; public: @@ -86,14 +65,12 @@ public: beast::unit_test::suite& suite_; public: - explicit TestSink(beast::unit_test::suite& suite) - : Sink(beast::severities::kWarning, false), suite_(suite) + explicit TestSink(beast::unit_test::suite& suite) : Sink(beast::severities::kWarning, false), suite_(suite) { } void - write(beast::severities::Severity level, std::string const& text) - override + write(beast::severities::Severity level, std::string const& text) override { if (level < threshold()) return; @@ -102,8 +79,7 @@ public: } void - writeAlways(beast::severities::Severity level, std::string const& text) - override + writeAlways(beast::severities::Severity level, std::string const& text) override { suite_.log << text << std::endl; } @@ -130,10 +106,7 @@ public: } Handoff - onHandoff( - Session& session, - http_request_type&& request, - boost::asio::ip::tcp::endpoint remote_address) + onHandoff(Session& session, http_request_type&& request, boost::asio::ip::tcp::endpoint remote_address) { return Handoff{}; } @@ -149,9 +122,7 @@ public: } void - onWSMessage( - std::shared_ptr session, - std::vector const&) + onWSMessage(std::shared_ptr session, std::vector const&) { } @@ -218,8 +189,7 @@ public: { std::string got; got.resize(n); - boost::asio::buffer_copy( - boost::asio::buffer(&got[0], n), b.data()); + boost::asio::buffer_copy(boost::asio::buffer(&got[0], n), b.data()); return BEAST_EXPECT(got == match); } } @@ -305,9 +275,7 @@ public: TestHandler handler; auto s = make_Server(handler, thread.get_io_context(), journal); std::vector serverPort(1); - serverPort.back().ip = - boost::asio::ip::make_address(getEnvLocalhostAddr()), - serverPort.back().port = 0; + serverPort.back().ip = boost::asio::ip::make_address(getEnvLocalhostAddr()), serverPort.back().port = 0; serverPort.back().protocol.insert("http"); auto eps = s->ports(serverPort); test_request(eps.begin()->second); @@ -340,10 +308,7 @@ public: } Handoff - onHandoff( - Session& session, - http_request_type&& request, - boost::asio::ip::tcp::endpoint remote_address) + onHandoff(Session& session, http_request_type&& request, boost::asio::ip::tcp::endpoint remote_address) { return Handoff{}; } @@ -354,9 +319,7 @@ public: } void - onWSMessage( - std::shared_ptr session, - std::vector const& buffers) + onWSMessage(std::shared_ptr session, std::vector const& buffers) { } @@ -380,9 +343,7 @@ public: TestThread thread; auto s = make_Server(h, thread.get_io_context(), journal); std::vector serverPort(1); - serverPort.back().ip = - boost::asio::ip::make_address(getEnvLocalhostAddr()), - serverPort.back().port = 0; + serverPort.back().ip = boost::asio::ip::make_address(getEnvLocalhostAddr()), serverPort.back().port = 0; serverPort.back().protocol.insert("http"); s->ports(serverPort); } @@ -406,8 +367,7 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Missing 'ip' in [port_rpc]") != std::string::npos); + BEAST_EXPECT(messages.find("Missing 'ip' in [port_rpc]") != std::string::npos); except([&] { Env env{ @@ -419,8 +379,7 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Missing 'port' in [port_rpc]") != std::string::npos); + BEAST_EXPECT(messages.find("Missing 'port' in [port_rpc]") != std::string::npos); except([&] { Env env{ @@ -433,9 +392,7 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Invalid value '0' for key 'port' in [port_rpc]") == - std::string::npos); + BEAST_EXPECT(messages.find("Invalid value '0' for key 'port' in [port_rpc]") == std::string::npos); except([&] { Env env{ @@ -446,9 +403,7 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Invalid value '0' for key 'port' in [server]") != - std::string::npos); + BEAST_EXPECT(messages.find("Invalid value '0' for key 'port' in [server]") != std::string::npos); except([&] { Env env{ @@ -462,44 +417,36 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Missing 'protocol' in [port_rpc]") != - std::string::npos); + BEAST_EXPECT(messages.find("Missing 'protocol' in [port_rpc]") != std::string::npos); - except( - [&] // this creates a standard test config without the server - // section - { - Env env{ - *this, - envconfig([](std::unique_ptr cfg) { - cfg = std::make_unique(); - cfg->overwrite( - ConfigSection::nodeDatabase(), "type", "memory"); - cfg->overwrite( - ConfigSection::nodeDatabase(), "path", "main"); - cfg->deprecatedClearSection( - ConfigSection::importNodeDatabase()); - cfg->legacy("database_path", ""); - cfg->setupControl(true, true, true); - (*cfg)["port_peer"].set("ip", getEnvLocalhostAddr()); - (*cfg)["port_peer"].set("port", "8080"); - (*cfg)["port_peer"].set("protocol", "peer"); - (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); - (*cfg)["port_rpc"].set("port", "8081"); - (*cfg)["port_rpc"].set("protocol", "http,ws2"); - (*cfg)["port_rpc"].set("admin", getEnvLocalhostAddr()); - (*cfg)["port_ws"].set("ip", getEnvLocalhostAddr()); - (*cfg)["port_ws"].set("port", "8082"); - (*cfg)["port_ws"].set("protocol", "ws"); - (*cfg)["port_ws"].set("admin", getEnvLocalhostAddr()); - return cfg; - }), - std::make_unique(&messages)}; - }); - BEAST_EXPECT( - messages.find("Required section [server] is missing") != - std::string::npos); + except([&] // this creates a standard test config without the server + // section + { + Env env{ + *this, + envconfig([](std::unique_ptr cfg) { + cfg = std::make_unique(); + cfg->overwrite(ConfigSection::nodeDatabase(), "type", "memory"); + cfg->overwrite(ConfigSection::nodeDatabase(), "path", "main"); + cfg->deprecatedClearSection(ConfigSection::importNodeDatabase()); + cfg->legacy("database_path", ""); + cfg->setupControl(true, true, true); + (*cfg)["port_peer"].set("ip", getEnvLocalhostAddr()); + (*cfg)["port_peer"].set("port", "8080"); + (*cfg)["port_peer"].set("protocol", "peer"); + (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); + (*cfg)["port_rpc"].set("port", "8081"); + (*cfg)["port_rpc"].set("protocol", "http,ws2"); + (*cfg)["port_rpc"].set("admin", getEnvLocalhostAddr()); + (*cfg)["port_ws"].set("ip", getEnvLocalhostAddr()); + (*cfg)["port_ws"].set("port", "8082"); + (*cfg)["port_ws"].set("protocol", "ws"); + (*cfg)["port_ws"].set("admin", getEnvLocalhostAddr()); + return cfg; + }), + std::make_unique(&messages)}; + }); + BEAST_EXPECT(messages.find("Required section [server] is missing") != std::string::npos); except([&] // this creates a standard test config without some of the // port sections @@ -508,12 +455,9 @@ public: *this, envconfig([](std::unique_ptr cfg) { cfg = std::make_unique(); - cfg->overwrite( - ConfigSection::nodeDatabase(), "type", "memory"); - cfg->overwrite( - ConfigSection::nodeDatabase(), "path", "main"); - cfg->deprecatedClearSection( - ConfigSection::importNodeDatabase()); + cfg->overwrite(ConfigSection::nodeDatabase(), "type", "memory"); + cfg->overwrite(ConfigSection::nodeDatabase(), "path", "main"); + cfg->deprecatedClearSection(ConfigSection::importNodeDatabase()); cfg->legacy("database_path", ""); cfg->setupControl(true, true, true); (*cfg)["server"].append("port_peer"); @@ -523,8 +467,7 @@ public: }), std::make_unique(&messages)}; }); - BEAST_EXPECT( - messages.find("Missing section: [port_peer]") != std::string::npos); + BEAST_EXPECT(messages.find("Missing section: [port_peer]") != std::string::npos); } void @@ -536,7 +479,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(Server, server, ripple); +BEAST_DEFINE_TESTSUITE(Server, server, xrpl); } // namespace test -} // namespace ripple +} // namespace xrpl diff --git a/src/test/shamap/FetchPack_test.cpp b/src/test/shamap/FetchPack_test.cpp index 7ee5c6730a..8919241996 100644 --- a/src/test/shamap/FetchPack_test.cpp +++ b/src/test/shamap/FetchPack_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -32,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace tests { class FetchPack_test : public beast::unit_test::suite @@ -55,8 +36,7 @@ public: struct TestFilter : SHAMapSyncFilter { - TestFilter(Map& map, beast::Journal journal) - : mMap(map), mJournal(journal) + TestFilter(Map& map, beast::Journal journal) : mMap(map), mJournal(journal) { } @@ -91,7 +71,7 @@ public: { Serializer s; for (int d = 0; d < 3; ++d) - s.add32(ripple::rand_int(r)); + s.add32(xrpl::rand_int(r)); return make_shamapitem(s.getSHA512Half(), s.slice()); } @@ -100,8 +80,7 @@ public: { while (n--) { - auto const result(t.addItem( - SHAMapNodeType::tnACCOUNT_STATE, make_random_item(r))); + auto const result(t.addItem(SHAMapNodeType::tnACCOUNT_STATE, make_random_item(r))); assert(result); (void)result; } @@ -170,7 +149,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(FetchPack, shamap, ripple); +BEAST_DEFINE_TESTSUITE(FetchPack, shamap, xrpl); } // namespace tests -} // namespace ripple +} // namespace xrpl diff --git a/src/test/shamap/SHAMapSync_test.cpp b/src/test/shamap/SHAMapSync_test.cpp index 05fc265ff9..1add7a629e 100644 --- a/src/test/shamap/SHAMapSync_test.cpp +++ b/src/test/shamap/SHAMapSync_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace tests { class SHAMapSync_test : public beast::unit_test::suite @@ -76,8 +57,7 @@ public: if (beforeHash != map.getHash()) { - log << "Hashes do not match " << beforeHash << " " << map.getHash() - << std::endl; + log << "Hashes do not match " << beforeHash << " " << map.getHash() << std::endl; return false; } @@ -125,16 +105,11 @@ public: { std::vector> a; - BEAST_EXPECT(source.getNodeFat( - SHAMapNodeID(), a, rand_bool(eng_), rand_int(eng_, 2))); + BEAST_EXPECT(source.getNodeFat(SHAMapNodeID(), a, rand_bool(eng_), rand_int(eng_, 2))); unexpected(a.size() < 1, "NodeSize"); - BEAST_EXPECT( - destination - .addRootNode( - source.getHash(), makeSlice(a[0].second), nullptr) - .isGood()); + BEAST_EXPECT(destination.addRootNode(source.getHash(), makeSlice(a[0].second), nullptr).isGood()); } do @@ -155,8 +130,7 @@ public: // Don't use BEAST_EXPECT here b/c it will be called a // non-deterministic number of times and the number of tests run // should be deterministic - if (!source.getNodeFat( - it.first, b, rand_bool(eng_), rand_int(eng_, 2))) + if (!source.getNodeFat(it.first, b, rand_bool(eng_), rand_int(eng_, 2))) fail("", __FILE__, __LINE__); } @@ -171,10 +145,7 @@ public: // Don't use BEAST_EXPECT here b/c it will be called a // non-deterministic number of times and the number of tests run // should be deterministic - if (!destination - .addKnownNode( - b[i].first, makeSlice(b[i].second), nullptr) - .isUseful()) + if (!destination.addKnownNode(b[i].first, makeSlice(b[i].second), nullptr).isUseful()) fail("", __FILE__, __LINE__); } } while (true); @@ -187,7 +158,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple); +BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, xrpl); } // namespace tests -} // namespace ripple +} // namespace xrpl diff --git a/src/test/shamap/SHAMap_test.cpp b/src/test/shamap/SHAMap_test.cpp index 462b42b6cb..c91cc63749 100644 --- a/src/test/shamap/SHAMap_test.cpp +++ b/src/test/shamap/SHAMap_test.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace tests { #ifndef __INTELLISENSE__ @@ -136,16 +117,11 @@ public: tests::TestNodeFamily f(journal); // h3 and h4 differ only in the leaf, same terminal node (level 19) - constexpr uint256 h1( - "092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); - constexpr uint256 h2( - "436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe"); - constexpr uint256 h3( - "b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8"); - constexpr uint256 h4( - "b92891fe4ef6cee585fdc6fda2e09eb4d386363158ec3321b8123e5a772c6ca8"); - constexpr uint256 h5( - "a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); + constexpr uint256 h1("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); + constexpr uint256 h2("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe"); + constexpr uint256 h3("b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8"); + constexpr uint256 h4("b92891fe4ef6cee585fdc6fda2e09eb4d386363158ec3321b8123e5a772c6ca8"); + constexpr uint256 h5("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); SHAMap sMap(SHAMapType::FREE, f); sMap.invariants(); @@ -158,15 +134,9 @@ public: auto i4 = make_shamapitem(h4, IntToVUC(4)); auto i5 = make_shamapitem(h5, IntToVUC(5)); - unexpected( - !sMap.addItem( - SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(*i2)), - "no add"); + unexpected(!sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(*i2)), "no add"); sMap.invariants(); - unexpected( - !sMap.addItem( - SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(*i1)), - "no add"); + unexpected(!sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(*i1)), "no add"); sMap.invariants(); auto i = sMap.begin(); @@ -268,9 +238,7 @@ public: BEAST_EXPECT(map.getHash() == beast::zero); for (int k = 0; k < keys.size(); ++k) { - BEAST_EXPECT(map.addItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(keys[k], IntToVUC(k)))); + BEAST_EXPECT(map.addItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(keys[k], IntToVUC(k)))); BEAST_EXPECT(map.getHash().as_uint256() == hashes[k]); map.invariants(); } @@ -313,9 +281,7 @@ public: map.setUnbacked(); for (auto const& k : keys) { - map.addItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(k, IntToVUC(0))); + map.addItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(k, IntToVUC(0))); map.invariants(); } @@ -347,9 +313,7 @@ class SHAMapPathProof_test : public beast::unit_test::suite for (unsigned char c = 1; c < 100; ++c) { uint256 k(c); - map.addItem( - SHAMapNodeType::tnACCOUNT_STATE, - make_shamapitem(k, Slice{k.data(), k.size()})); + map.addItem(SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(k, Slice{k.data(), k.size()})); map.invariants(); auto root = map.getHash().as_uint256(); @@ -401,7 +365,7 @@ class SHAMapPathProof_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(SHAMap, shamap, ripple); -BEAST_DEFINE_TESTSUITE(SHAMapPathProof, shamap, ripple); +BEAST_DEFINE_TESTSUITE(SHAMap, shamap, xrpl); +BEAST_DEFINE_TESTSUITE(SHAMapPathProof, shamap, xrpl); } // namespace tests -} // namespace ripple +} // namespace xrpl diff --git a/src/test/shamap/common.h b/src/test/shamap/common.h index 6c7fcf4c39..fe2a1884da 100644 --- a/src/test/shamap/common.h +++ b/src/test/shamap/common.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED -#define RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { namespace tests { class TestNodeFamily : public Family @@ -43,23 +23,15 @@ private: public: TestNodeFamily(beast::Journal j) - : fbCache_(std::make_shared( - "App family full below cache", - clock_, - j)) - , tnCache_(std::make_shared( - "App family tree node cache", - 65536, - std::chrono::minutes{1}, - clock_, - j)) + : fbCache_(std::make_shared("App family full below cache", clock_, j)) + , tnCache_( + std::make_shared("App family tree node cache", 65536, std::chrono::minutes{1}, clock_, j)) , j_(j) { Section testSection; testSection.set("type", "memory"); testSection.set("path", "SHAMap_test"); - db_ = NodeStore::Manager::instance().make_Database( - megabytes(4), scheduler_, 1, testSection, j); + db_ = NodeStore::Manager::instance().make_Database(megabytes(4), scheduler_, 1, testSection, j); } NodeStore::Database& @@ -100,15 +72,13 @@ public: } void - missingNodeAcquireBySeq(std::uint32_t refNum, uint256 const& nodeHash) - override + missingNodeAcquireBySeq(std::uint32_t refNum, uint256 const& nodeHash) override { Throw("missing node"); } void - missingNodeAcquireByHash(uint256 const& refHash, std::uint32_t refNum) - override + missingNodeAcquireByHash(uint256 const& refHash, std::uint32_t refNum) override { Throw("missing node"); } @@ -128,6 +98,4 @@ public: }; } // namespace tests -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/unit_test/FileDirGuard.h b/src/test/unit_test/FileDirGuard.h index d3cabc2092..cf2eab7adb 100644 --- a/src/test/unit_test/FileDirGuard.h +++ b/src/test/unit_test/FileDirGuard.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* -This file is part of rippled: https://github.com/ripple/rippled -Copyright (c) 2018 Ripple Labs Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef TEST_UNIT_TEST_DIRGUARD_H -#define TEST_UNIT_TEST_DIRGUARD_H +#pragma once #include @@ -28,7 +8,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -namespace ripple { +namespace xrpl { namespace detail { /** @@ -52,8 +32,7 @@ protected: if (is_directory(toRm) && is_empty(toRm)) remove(toRm); else - test_.log << "Expected " << toRm.string() - << " to be an empty existing directory." << std::endl; + test_.log << "Expected " << toRm.string() << " to be an empty existing directory." << std::endl; } public: @@ -76,8 +55,7 @@ public: { // Cannot run the test. Someone created a file where we want to // put our directory - Throw( - "Cannot create directory: " + subDir_.string()); + Throw("Cannot create directory: " + subDir_.string()); } } @@ -121,8 +99,7 @@ public: std::string const& contents, bool useCounter = true, bool create = true) - : DirGuard(test, subDir, useCounter) - , file_(file.is_absolute() ? file : subdir() / file) + : DirGuard(test, subDir, useCounter), file_(file.is_absolute() ? file : subdir() / file) { if (!exists(file_)) { @@ -135,8 +112,7 @@ public: } else { - Throw( - "Refusing to overwrite existing file: " + file_.string()); + Throw("Refusing to overwrite existing file: " + file_.string()); } } @@ -152,8 +128,7 @@ public: else { if (created_) - test_.log << "Expected " << file_.string() - << " to be an existing file." << std::endl; + test_.log << "Expected " << file_.string() << " to be an existing file." << std::endl; } } catch (std::exception& e) @@ -177,6 +152,4 @@ public: }; } // namespace detail -} // namespace ripple - -#endif // TEST_UNIT_TEST_DIRGUARD_H +} // namespace xrpl diff --git a/src/test/unit_test/SuiteJournal.h b/src/test/unit_test/SuiteJournal.h index d56c297b0a..ad5f298b74 100644 --- a/src/test/unit_test/SuiteJournal.h +++ b/src/test/unit_test/SuiteJournal.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef TEST_UNIT_TEST_SUITE_JOURNAL_H -#define TEST_UNIT_TEST_SUITE_JOURNAL_H +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace test { // A Journal::Sink intended for use with the beast unit test framework. @@ -52,14 +32,11 @@ public: write(beast::severities::Severity level, std::string const& text) override; void - writeAlways(beast::severities::Severity level, std::string const& text) - override; + writeAlways(beast::severities::Severity level, std::string const& text) override; }; inline void -SuiteJournalSink::write( - beast::severities::Severity level, - std::string const& text) +SuiteJournalSink::write(beast::severities::Severity level, std::string const& text) { // Only write the string if the level at least equals the threshold. if (level >= threshold()) @@ -67,9 +44,7 @@ SuiteJournalSink::write( } inline void -SuiteJournalSink::writeAlways( - beast::severities::Severity level, - std::string const& text) +SuiteJournalSink::writeAlways(beast::severities::Severity level, std::string const& text) { using namespace beast::severities; @@ -130,9 +105,7 @@ class StreamSink : public beast::Journal::Sink std::stringstream strm_; public: - StreamSink( - beast::severities::Severity threshold = beast::severities::kDebug) - : Sink(threshold, false) + StreamSink(beast::severities::Severity threshold = beast::severities::kDebug) : Sink(threshold, false) { } @@ -145,8 +118,7 @@ public: } inline void - writeAlways(beast::severities::Severity level, std::string const& text) - override + writeAlways(beast::severities::Severity level, std::string const& text) override { strm_ << text << std::endl; } @@ -159,6 +131,4 @@ public: }; } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/test/unit_test/multi_runner.cpp b/src/test/unit_test/multi_runner.cpp index 796d1241c9..eefd0c8250 100644 --- a/src/test/unit_test/multi_runner.cpp +++ b/src/test/unit_test/multi_runner.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -68,10 +49,7 @@ results::add(suite_results const& r) if (elapsed >= std::chrono::seconds{1}) { auto const iter = std::lower_bound( - top.begin(), - top.end(), - elapsed, - [](run_time const& t1, typename clock_type::duration const& t2) { + top.begin(), top.end(), elapsed, [](run_time const& t1, typename clock_type::duration const& t2) { return t1.second > t2; }); @@ -80,25 +58,18 @@ results::add(suite_results const& r) if (top.size() == max_top && iter == top.end() - 1) { // avoid invalidating the iterator - *iter = run_time{ - static_string{static_string::string_view_type{r.name}}, - elapsed}; + *iter = run_time{static_string{static_string::string_view_type{r.name}}, elapsed}; } else { if (top.size() == max_top) top.resize(top.size() - 1); - top.emplace( - iter, - static_string{static_string::string_view_type{r.name}}, - elapsed); + top.emplace(iter, static_string{static_string::string_view_type{r.name}}, elapsed); } } else if (top.size() < max_top) { - top.emplace_back( - static_string{static_string::string_view_type{r.name}}, - elapsed); + top.emplace_back(static_string{static_string::string_view_type{r.name}}, elapsed); } } } @@ -120,9 +91,7 @@ results::merge(results const& r) r.top.begin(), r.top.end(), top_result.begin(), - [](run_time const& t1, run_time const& t2) { - return t1.second > t2.second; - }); + [](run_time const& t1, run_time const& t2) { return t1.second > t2.second; }); if (top_result.size() > max_top) top_result.resize(max_top); @@ -144,9 +113,8 @@ results::print(S& s) } auto const elapsed = clock_type::now() - start; - s << fmtdur(elapsed) << ", " << amount{suites, "suite"} << ", " - << amount{cases, "case"} << ", " << amount{total, "test"} << " total, " - << amount{failed, "failure"} << std::endl; + s << fmtdur(elapsed) << ", " << amount{suites, "suite"} << ", " << amount{cases, "case"} << ", " + << amount{total, "test"} << " total, " << amount{failed, "failure"} << std::endl; } //------------------------------------------------------------------------------ @@ -239,32 +207,26 @@ multi_runner_base::multi_runner_base() } shared_mem_ = boost::interprocess::shared_memory_object{ - std::conditional_t< - IsParent, - boost::interprocess::create_only_t, - boost::interprocess::open_only_t>{}, + std::conditional_t{}, shared_mem_name_, boost::interprocess::read_write}; if (IsParent) { shared_mem_.truncate(sizeof(inner)); - message_queue_ = - std::make_unique( - boost::interprocess::create_only, - message_queue_name_, - /*max messages*/ 16, - /*max message size*/ 1 << 20); + message_queue_ = std::make_unique( + boost::interprocess::create_only, + message_queue_name_, + /*max messages*/ 16, + /*max message size*/ 1 << 20); } else { - message_queue_ = - std::make_unique( - boost::interprocess::open_only, message_queue_name_); + message_queue_ = std::make_unique( + boost::interprocess::open_only, message_queue_name_); } - region_ = boost::interprocess::mapped_region{ - shared_mem_, boost::interprocess::read_write}; + region_ = boost::interprocess::mapped_region{shared_mem_, boost::interprocess::read_write}; if (IsParent) inner_ = new (region_.get_address()) inner{}; else @@ -351,9 +313,7 @@ multi_runner_base::print_results(S& s) template void -multi_runner_base::message_queue_send( - MessageType mt, - std::string const& s) +multi_runner_base::message_queue_send(MessageType mt, std::string const& s) { // must use a mutex since the two "sends" must happen in order std::lock_guard l{inner_->m_}; @@ -395,8 +355,7 @@ multi_runner_parent::multi_runner_parent() : os_(std::cout) { message_queue_thread_ = std::thread([this] { std::vector buf(1 << 20); - while (this->continue_message_queue_ || - this->message_queue_->get_num_msg()) + while (this->continue_message_queue_ || this->message_queue_->get_num_msg()) { // let children know the parent is still alive this->inc_keep_alive_count(); @@ -413,15 +372,13 @@ multi_runner_parent::multi_runner_parent() : os_(std::cout) { std::size_t recvd_size = 0; unsigned int priority = 0; - this->message_queue_->receive( - buf.data(), buf.size(), recvd_size, priority); + this->message_queue_->receive(buf.data(), buf.size(), recvd_size, priority); if (!recvd_size) continue; assert(recvd_size == 1); MessageType mt{*reinterpret_cast(buf.data())}; - this->message_queue_->receive( - buf.data(), buf.size(), recvd_size, priority); + this->message_queue_->receive(buf.data(), buf.size(), recvd_size, priority); if (recvd_size) { std::string s{buf.data(), recvd_size}; @@ -444,8 +401,7 @@ multi_runner_parent::multi_runner_parent() : os_(std::cout) } catch (std::exception const& e) { - std::cerr << "Error: " << e.what() - << " reading unit test message queue.\n"; + std::cerr << "Error: " << e.what() << " reading unit test message queue.\n"; return; } catch (...) @@ -470,8 +426,7 @@ multi_runner_parent::~multi_runner_parent() for (auto const& s : running_suites_) { - os_ << "\nSuite: " << s - << " failed to complete. The child process may have crashed.\n"; + os_ << "\nSuite: " << s << " failed to complete. The child process may have crashed.\n"; } } @@ -501,14 +456,8 @@ multi_runner_parent::add_failures(std::size_t failures) //------------------------------------------------------------------------------ -multi_runner_child::multi_runner_child( - std::size_t num_jobs, - bool quiet, - bool print_log) - : job_index_{checkout_job_index()} - , num_jobs_{num_jobs} - , quiet_{quiet} - , print_log_{!quiet || print_log} +multi_runner_child::multi_runner_child(std::size_t num_jobs, bool quiet, bool print_log) + : job_index_{checkout_job_index()}, num_jobs_{num_jobs}, quiet_{quiet}, print_log_{!quiet || print_log} { if (num_jobs_ > 1) { @@ -529,8 +478,7 @@ multi_runner_child::multi_runner_child( if (cur_count == last_count) { // assume parent process is no longer alive - std::cerr << "multi_runner_child " << job_index_ - << ": Assuming parent died, exiting.\n"; + std::cerr << "multi_runner_child " << job_index_ << ": Assuming parent died, exiting.\n"; std::exit(EXIT_FAILURE); } } @@ -585,8 +533,7 @@ multi_runner_child::on_suite_end() std::stringstream s; if (num_jobs_ > 1) s << job_index_ << "> "; - s << (suite_results_.failed > 0 ? "failed: " : "") - << suite_results_.name << " had " << suite_results_.failed + s << (suite_results_.failed > 0 ? "failed: " : "") << suite_results_.name << " had " << suite_results_.failed << " failures." << std::endl; message_queue_send(MessageType::log, s.str()); } @@ -605,8 +552,7 @@ multi_runner_child::on_case_begin(std::string const& name) std::stringstream s; if (num_jobs_ > 1) s << job_index_ << "> "; - s << suite_results_.name - << (case_results_.name.empty() ? "" : (" " + case_results_.name)) << '\n'; + s << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name)) << '\n'; message_queue_send(MessageType::log, s.str()); } @@ -630,8 +576,7 @@ multi_runner_child::on_fail(std::string const& reason) std::stringstream s; if (num_jobs_ > 1) s << job_index_ << "> "; - s << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") - << reason << '\n'; + s << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason << '\n'; message_queue_send(MessageType::log, s.str()); } @@ -655,4 +600,4 @@ template class multi_runner_base; template class multi_runner_base; } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/test/unit_test/multi_runner.h b/src/test/unit_test/multi_runner.h index bce62fb131..28ecaf85f9 100644 --- a/src/test/unit_test/multi_runner.h +++ b/src/test/unit_test/multi_runner.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef TEST_UNIT_TEST_MULTI_RUNNER_H -#define TEST_UNIT_TEST_MULTI_RUNNER_H +#pragma once #include #include @@ -39,7 +19,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -154,8 +134,7 @@ class multi_runner_base static constexpr char const* shared_mem_name_ = "RippledUnitTestSharedMem"; // name of the message queue a multi_runner_child will use to communicate // with multi_runner_parent - static constexpr char const* message_queue_name_ = - "RippledUnitTestMessageQueue"; + static constexpr char const* message_queue_name_ = "RippledUnitTestMessageQueue"; // `inner_` will be created in shared memory inner* inner_; @@ -252,8 +231,7 @@ public: /** A class to run a subset of unit tests */ -class multi_runner_child : public beast::unit_test::runner, - private detail::multi_runner_base +class multi_runner_child : public beast::unit_test::runner, private detail::multi_runner_base { private: std::size_t job_index_; @@ -354,6 +332,4 @@ multi_runner_child::run_multi(Pred pred) } } // namespace test -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/tests/README.md b/src/tests/README.md index 7c4cc5edf8..2a642a7633 100644 --- a/src/tests/README.md +++ b/src/tests/README.md @@ -1,5 +1,5 @@ # Unit tests This directory contains unit tests for the project. The difference from existing `src/test` folder -is that we switch to 3rd party testing framework (doctest). We intend to gradually move existing tests -from our own framework to doctest and such tests will be moved to this new folder. +is that we switch to 3rd party testing framework (`gtest`). We intend to gradually move existing tests +from our own framework to `gtest` and such tests will be moved to this new folder. diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index caa308dd1f..cfa056b0aa 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -1,18 +1,37 @@ -include(xrpl_add_test) +include(XrplAddTest) # Test requirements. -find_package(doctest REQUIRED) +find_package(GTest REQUIRED) + +# Custom target for all tests defined in this file +add_custom_target(xrpl.tests) + +# Test helpers +add_library(xrpl.helpers.test STATIC) +target_sources(xrpl.helpers.test PRIVATE helpers/TestSink.cpp) +target_include_directories(xrpl.helpers.test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(xrpl.helpers.test PRIVATE xrpl.libxrpl) # Common library dependencies for the rest of the tests. add_library(xrpl.imports.test INTERFACE) -target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest xrpl.libxrpl) +target_link_libraries(xrpl.imports.test INTERFACE gtest::gtest xrpl.libxrpl xrpl.helpers.test) # One test for each module. xrpl_add_test(basics) target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test) +add_dependencies(xrpl.tests xrpl.test.basics) + xrpl_add_test(crypto) target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test) +add_dependencies(xrpl.tests xrpl.test.crypto) + xrpl_add_test(json) target_link_libraries(xrpl.test.json PRIVATE xrpl.imports.test) -xrpl_add_test(net) -target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test) +add_dependencies(xrpl.tests xrpl.test.json) + +# Network unit tests are currently not supported on Windows +if (NOT WIN32) + xrpl_add_test(net) + target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test) + add_dependencies(xrpl.tests xrpl.test.net) +endif () diff --git a/src/tests/libxrpl/basics/RangeSet.cpp b/src/tests/libxrpl/basics/RangeSet.cpp index ac0e1d9551..d0fc656368 100644 --- a/src/tests/libxrpl/basics/RangeSet.cpp +++ b/src/tests/libxrpl/basics/RangeSet.cpp @@ -1,34 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include #include -using namespace ripple; +using namespace xrpl; -TEST_SUITE_BEGIN("RangeSet"); - -TEST_CASE("prevMissing") +TEST(RangeSet, prevMissing) { // Set will include: // [ 0, 5] @@ -50,80 +29,78 @@ TEST_CASE("prevMissing") expected = ((i % 10) > 6) ? (i - 1) : oneBelowRange; } - CHECK(prevMissing(set, i) == expected); + EXPECT_EQ(prevMissing(set, i), expected); } } -TEST_CASE("toString") +TEST(RangeSet, toString) { RangeSet set; - CHECK(to_string(set) == "empty"); + EXPECT_EQ(to_string(set), "empty"); set.insert(1); - CHECK(to_string(set) == "1"); + EXPECT_EQ(to_string(set), "1"); set.insert(range(4u, 6u)); - CHECK(to_string(set) == "1,4-6"); + EXPECT_EQ(to_string(set), "1,4-6"); set.insert(2); - CHECK(to_string(set) == "1-2,4-6"); + EXPECT_EQ(to_string(set), "1-2,4-6"); set.erase(range(4u, 5u)); - CHECK(to_string(set) == "1-2,6"); + EXPECT_EQ(to_string(set), "1-2,6"); } -TEST_CASE("fromString") +TEST(RangeSet, fromString) { RangeSet set; - CHECK(!from_string(set, "")); - CHECK(boost::icl::length(set) == 0); + EXPECT_FALSE(from_string(set, "")); + EXPECT_EQ(boost::icl::length(set), 0); - CHECK(!from_string(set, "#")); - CHECK(boost::icl::length(set) == 0); + EXPECT_FALSE(from_string(set, "#")); + EXPECT_EQ(boost::icl::length(set), 0); - CHECK(!from_string(set, ",")); - CHECK(boost::icl::length(set) == 0); + EXPECT_FALSE(from_string(set, ",")); + EXPECT_EQ(boost::icl::length(set), 0); - CHECK(!from_string(set, ",-")); - CHECK(boost::icl::length(set) == 0); + EXPECT_FALSE(from_string(set, ",-")); + EXPECT_EQ(boost::icl::length(set), 0); - CHECK(!from_string(set, "1,,2")); - CHECK(boost::icl::length(set) == 0); + EXPECT_FALSE(from_string(set, "1,,2")); + EXPECT_EQ(boost::icl::length(set), 0); - CHECK(from_string(set, "1")); - CHECK(boost::icl::length(set) == 1); - CHECK(boost::icl::first(set) == 1); + EXPECT_TRUE(from_string(set, "1")); + EXPECT_EQ(boost::icl::length(set), 1); + EXPECT_EQ(boost::icl::first(set), 1); - CHECK(from_string(set, "1,1")); - CHECK(boost::icl::length(set) == 1); - CHECK(boost::icl::first(set) == 1); + EXPECT_TRUE(from_string(set, "1,1")); + EXPECT_EQ(boost::icl::length(set), 1); + EXPECT_EQ(boost::icl::first(set), 1); - CHECK(from_string(set, "1-1")); - CHECK(boost::icl::length(set) == 1); - CHECK(boost::icl::first(set) == 1); + EXPECT_TRUE(from_string(set, "1-1")); + EXPECT_EQ(boost::icl::length(set), 1); + EXPECT_EQ(boost::icl::first(set), 1); - CHECK(from_string(set, "1,4-6")); - CHECK(boost::icl::length(set) == 4); - CHECK(boost::icl::first(set) == 1); - CHECK(!boost::icl::contains(set, 2)); - CHECK(!boost::icl::contains(set, 3)); - CHECK(boost::icl::contains(set, 4)); - CHECK(boost::icl::contains(set, 5)); - CHECK(boost::icl::last(set) == 6); + EXPECT_TRUE(from_string(set, "1,4-6")); + EXPECT_EQ(boost::icl::length(set), 4); + EXPECT_EQ(boost::icl::first(set), 1); + EXPECT_FALSE(boost::icl::contains(set, 2)); + EXPECT_FALSE(boost::icl::contains(set, 3)); + EXPECT_TRUE(boost::icl::contains(set, 4)); + EXPECT_TRUE(boost::icl::contains(set, 5)); + EXPECT_EQ(boost::icl::last(set), 6); - CHECK(from_string(set, "1-2,4-6")); - CHECK(boost::icl::length(set) == 5); - CHECK(boost::icl::first(set) == 1); - CHECK(boost::icl::contains(set, 2)); - CHECK(boost::icl::contains(set, 4)); - CHECK(boost::icl::last(set) == 6); + EXPECT_TRUE(from_string(set, "1-2,4-6")); + EXPECT_EQ(boost::icl::length(set), 5); + EXPECT_EQ(boost::icl::first(set), 1); + EXPECT_TRUE(boost::icl::contains(set, 2)); + EXPECT_TRUE(boost::icl::contains(set, 4)); + EXPECT_EQ(boost::icl::last(set), 6); - CHECK(from_string(set, "1-2,6")); - CHECK(boost::icl::length(set) == 3); - CHECK(boost::icl::first(set) == 1); - CHECK(boost::icl::contains(set, 2)); - CHECK(boost::icl::last(set) == 6); + EXPECT_TRUE(from_string(set, "1-2,6")); + EXPECT_EQ(boost::icl::length(set), 3); + EXPECT_EQ(boost::icl::first(set), 1); + EXPECT_TRUE(boost::icl::contains(set, 2)); + EXPECT_EQ(boost::icl::last(set), 6); } - -TEST_SUITE_END(); diff --git a/src/tests/libxrpl/basics/Slice.cpp b/src/tests/libxrpl/basics/Slice.cpp index eabd9b7dc7..4373f98168 100644 --- a/src/tests/libxrpl/basics/Slice.cpp +++ b/src/tests/libxrpl/basics/Slice.cpp @@ -1,67 +1,45 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include #include -using namespace ripple; +using namespace xrpl; -static std::uint8_t const data[] = { - 0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, - 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, - 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; +static std::uint8_t const data[] = {0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a, + 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c, + 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3}; -TEST_SUITE_BEGIN("Slice"); - -TEST_CASE("equality & inequality") +TEST(Slice, equality_and_inequality) { Slice const s0{}; - CHECK(s0.size() == 0); - CHECK(s0.data() == nullptr); - CHECK(s0 == s0); + EXPECT_EQ(s0.size(), 0); + EXPECT_EQ(s0.data(), nullptr); + EXPECT_EQ(s0, s0); // Test slices of equal and unequal size pointing to same data: for (std::size_t i = 0; i != sizeof(data); ++i) { Slice const s1{data, i}; - CHECK(s1.size() == i); - CHECK(s1.data() != nullptr); + EXPECT_EQ(s1.size(), i); + EXPECT_NE(s1.data(), nullptr); if (i == 0) - CHECK(s1 == s0); + EXPECT_EQ(s1, s0); else - CHECK(s1 != s0); + EXPECT_NE(s1, s0); for (std::size_t j = 0; j != sizeof(data); ++j) { Slice const s2{data, j}; if (i == j) - CHECK(s1 == s2); + EXPECT_EQ(s1, s2); else - CHECK(s1 != s2); + EXPECT_NE(s1, s2); } } @@ -72,22 +50,22 @@ TEST_CASE("equality & inequality") for (std::size_t i = 0; i != sizeof(data); ++i) a[i] = b[i] = data[i]; - CHECK(makeSlice(a) == makeSlice(b)); + EXPECT_EQ(makeSlice(a), makeSlice(b)); b[7]++; - CHECK(makeSlice(a) != makeSlice(b)); + EXPECT_NE(makeSlice(a), makeSlice(b)); a[7]++; - CHECK(makeSlice(a) == makeSlice(b)); + EXPECT_EQ(makeSlice(a), makeSlice(b)); } -TEST_CASE("indexing") +TEST(Slice, indexing) { Slice const s{data, sizeof(data)}; for (std::size_t i = 0; i != sizeof(data); ++i) - CHECK(s[i] == data[i]); + EXPECT_EQ(s[i], data[i]); } -TEST_CASE("advancing") +TEST(Slice, advancing) { for (std::size_t i = 0; i < sizeof(data); ++i) { @@ -96,10 +74,8 @@ TEST_CASE("advancing") Slice s(data + i, sizeof(data) - i); s += j; - CHECK(s.data() == data + i + j); - CHECK(s.size() == sizeof(data) - i - j); + EXPECT_EQ(s.data(), data + i + j); + EXPECT_EQ(s.size(), sizeof(data) - i - j); } } } - -TEST_SUITE_END(); diff --git a/src/tests/libxrpl/basics/base64.cpp b/src/tests/libxrpl/basics/base64.cpp index fe9b86abb1..cfffadf660 100644 --- a/src/tests/libxrpl/basics/base64.cpp +++ b/src/tests/libxrpl/basics/base64.cpp @@ -1,40 +1,22 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include -using namespace ripple; +using namespace xrpl; static void check(std::string const& in, std::string const& out) { auto const encoded = base64_encode(in); - CHECK(encoded == out); - CHECK(base64_decode(encoded) == in); + EXPECT_EQ(encoded, out); + EXPECT_EQ(base64_decode(encoded), in); } -TEST_CASE("base64") +TEST(base64, base64) { + // cspell: disable check("", ""); check("f", "Zg=="); check("fo", "Zm8="); @@ -42,6 +24,7 @@ TEST_CASE("base64") check("foob", "Zm9vYg=="); check("fooba", "Zm9vYmE="); check("foobar", "Zm9vYmFy"); + // cspell: enable check( "Man is distinguished, not only by his reason, but by this " @@ -63,5 +46,5 @@ TEST_CASE("base64") std::string const notBase64 = "not_base64!!"; std::string const truncated = "not"; - CHECK(base64_decode(notBase64) == base64_decode(truncated)); + EXPECT_EQ(base64_decode(notBase64), base64_decode(truncated)); } diff --git a/src/tests/libxrpl/basics/contract.cpp b/src/tests/libxrpl/basics/contract.cpp index 9ddf044f17..d9b729e85d 100644 --- a/src/tests/libxrpl/basics/contract.cpp +++ b/src/tests/libxrpl/basics/contract.cpp @@ -1,32 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include #include -using namespace ripple; +using namespace xrpl; -TEST_CASE("contract") +TEST(contract, contract) { try { @@ -34,7 +15,7 @@ TEST_CASE("contract") } catch (std::runtime_error const& e1) { - CHECK(std::string(e1.what()) == "Throw test"); + EXPECT_STREQ(e1.what(), "Throw test"); try { @@ -42,15 +23,15 @@ TEST_CASE("contract") } catch (std::runtime_error const& e2) { - CHECK(std::string(e2.what()) == "Throw test"); + EXPECT_STREQ(e2.what(), "Throw test"); } catch (...) { - CHECK(false); + FAIL() << "std::runtime_error should have been re-caught"; } } catch (...) { - CHECK(false); + FAIL() << "std::runtime_error should have been caught the first time"; } } diff --git a/src/tests/libxrpl/basics/main.cpp b/src/tests/libxrpl/basics/main.cpp index 0a3f254ea8..5142bbe08a 100644 --- a/src/tests/libxrpl/basics/main.cpp +++ b/src/tests/libxrpl/basics/main.cpp @@ -1,2 +1,8 @@ -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include +#include + +int +main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/tests/libxrpl/basics/mulDiv.cpp b/src/tests/libxrpl/basics/mulDiv.cpp index bdbbfdc741..c98c3fd61a 100644 --- a/src/tests/libxrpl/basics/mulDiv.cpp +++ b/src/tests/libxrpl/basics/mulDiv.cpp @@ -1,64 +1,45 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include #include -using namespace ripple; +using namespace xrpl; -TEST_CASE("mulDiv") +TEST(mulDiv, mulDiv) { auto const max = std::numeric_limits::max(); std::uint64_t const max32 = std::numeric_limits::max(); auto result = mulDiv(85, 20, 5); - REQUIRE(result); - CHECK(*result == 340); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 340); result = mulDiv(20, 85, 5); - REQUIRE(result); - CHECK(*result == 340); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 340); result = mulDiv(0, max - 1, max - 3); - REQUIRE(result); - CHECK(*result == 0); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0); result = mulDiv(max - 1, 0, max - 3); - REQUIRE(result); - CHECK(*result == 0); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0); result = mulDiv(max, 2, max / 2); - REQUIRE(result); - CHECK(*result == 4); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 4); result = mulDiv(max, 1000, max / 1000); - REQUIRE(result); - CHECK(*result == 1000000); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 1000000); result = mulDiv(max, 1000, max / 1001); - REQUIRE(result); - CHECK(*result == 1001000); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 1001000); result = mulDiv(max32 + 1, max32 + 1, 5); - REQUIRE(result); - CHECK(*result == 3689348814741910323); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result, 3689348814741910323); // Overflow result = mulDiv(max - 1, max - 2, 5); - CHECK(!result); + EXPECT_FALSE(result.has_value()); } diff --git a/src/tests/libxrpl/basics/scope.cpp b/src/tests/libxrpl/basics/scope.cpp index c9cfc1e7f8..309a41ec04 100644 --- a/src/tests/libxrpl/basics/scope.cpp +++ b/src/tests/libxrpl/basics/scope.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include -using namespace ripple; +using namespace xrpl; -TEST_CASE("scope_exit") +TEST(scope, scope_exit) { // scope_exit always executes the functor on destruction, // unless release() is called @@ -31,23 +12,23 @@ TEST_CASE("scope_exit") { scope_exit x{[&i]() { i = 1; }}; } - CHECK(i == 1); + EXPECT_EQ(i, 1); { scope_exit x{[&i]() { i = 2; }}; x.release(); } - CHECK(i == 1); + EXPECT_EQ(i, 1); { scope_exit x{[&i]() { i += 2; }}; auto x2 = std::move(x); } - CHECK(i == 3); + EXPECT_EQ(i, 3); { scope_exit x{[&i]() { i = 4; }}; x.release(); auto x2 = std::move(x); } - CHECK(i == 3); + EXPECT_EQ(i, 3); { try { @@ -58,7 +39,7 @@ TEST_CASE("scope_exit") { } } - CHECK(i == 5); + EXPECT_EQ(i, 5); { try { @@ -70,10 +51,10 @@ TEST_CASE("scope_exit") { } } - CHECK(i == 5); + EXPECT_EQ(i, 5); } -TEST_CASE("scope_fail") +TEST(scope, scope_fail) { // scope_fail executes the functor on destruction only // if an exception is unwinding, unless release() is called @@ -81,23 +62,23 @@ TEST_CASE("scope_fail") { scope_fail x{[&i]() { i = 1; }}; } - CHECK(i == 0); + EXPECT_EQ(i, 0); { scope_fail x{[&i]() { i = 2; }}; x.release(); } - CHECK(i == 0); + EXPECT_EQ(i, 0); { scope_fail x{[&i]() { i = 3; }}; auto x2 = std::move(x); } - CHECK(i == 0); + EXPECT_EQ(i, 0); { scope_fail x{[&i]() { i = 4; }}; x.release(); auto x2 = std::move(x); } - CHECK(i == 0); + EXPECT_EQ(i, 0); { try { @@ -108,7 +89,7 @@ TEST_CASE("scope_fail") { } } - CHECK(i == 5); + EXPECT_EQ(i, 5); { try { @@ -120,10 +101,10 @@ TEST_CASE("scope_fail") { } } - CHECK(i == 5); + EXPECT_EQ(i, 5); } -TEST_CASE("scope_success") +TEST(scope, scope_success) { // scope_success executes the functor on destruction only // if an exception is not unwinding, unless release() is called @@ -131,23 +112,23 @@ TEST_CASE("scope_success") { scope_success x{[&i]() { i = 1; }}; } - CHECK(i == 1); + EXPECT_EQ(i, 1); { scope_success x{[&i]() { i = 2; }}; x.release(); } - CHECK(i == 1); + EXPECT_EQ(i, 1); { scope_success x{[&i]() { i += 2; }}; auto x2 = std::move(x); } - CHECK(i == 3); + EXPECT_EQ(i, 3); { scope_success x{[&i]() { i = 4; }}; x.release(); auto x2 = std::move(x); } - CHECK(i == 3); + EXPECT_EQ(i, 3); { try { @@ -158,7 +139,7 @@ TEST_CASE("scope_success") { } } - CHECK(i == 3); + EXPECT_EQ(i, 3); { try { @@ -170,5 +151,5 @@ TEST_CASE("scope_success") { } } - CHECK(i == 3); + EXPECT_EQ(i, 3); } diff --git a/src/tests/libxrpl/basics/tagged_integer.cpp b/src/tests/libxrpl/basics/tagged_integer.cpp index d699b64a70..e24b299442 100644 --- a/src/tests/libxrpl/basics/tagged_integer.cpp +++ b/src/tests/libxrpl/basics/tagged_integer.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2014 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include #include -using namespace ripple; +using namespace xrpl; struct Tag1 { @@ -72,25 +53,15 @@ static_assert( !std::is_assignable::value, "TagUInt3 should not be assignable with a std::uint64_t"); -static_assert( - std::is_assignable::value, - "TagUInt1 should be assignable with a TagUInt1"); +static_assert(std::is_assignable::value, "TagUInt1 should be assignable with a TagUInt1"); -static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a TagUInt2"); +static_assert(!std::is_assignable::value, "TagUInt1 should not be assignable with a TagUInt2"); -static_assert( - std::is_assignable::value, - "TagUInt3 should be assignable with a TagUInt1"); +static_assert(std::is_assignable::value, "TagUInt3 should be assignable with a TagUInt1"); -static_assert( - !std::is_assignable::value, - "TagUInt1 should not be assignable with a TagUInt3"); +static_assert(!std::is_assignable::value, "TagUInt1 should not be assignable with a TagUInt3"); -static_assert( - !std::is_assignable::value, - "TagUInt3 should not be assignable with a TagUInt1"); +static_assert(!std::is_assignable::value, "TagUInt3 should not be assignable with a TagUInt1"); // Check convertibility of tagged_integers static_assert( @@ -109,139 +80,129 @@ static_assert( !std::is_convertible::value, "std::uint64_t should not be convertible to a TagUInt2"); -static_assert( - !std::is_convertible::value, - "TagUInt1 should not be convertible to TagUInt2"); +static_assert(!std::is_convertible::value, "TagUInt1 should not be convertible to TagUInt2"); -static_assert( - !std::is_convertible::value, - "TagUInt1 should not be convertible to TagUInt3"); +static_assert(!std::is_convertible::value, "TagUInt1 should not be convertible to TagUInt3"); -static_assert( - !std::is_convertible::value, - "TagUInt2 should not be convertible to a TagUInt3"); - -TEST_SUITE_BEGIN("tagged_integer"); +static_assert(!std::is_convertible::value, "TagUInt2 should not be convertible to a TagUInt3"); using TagInt = tagged_integer; -TEST_CASE("comparison operators") +TEST(tagged_integer, comparison_operators) { TagInt const zero(0); TagInt const one(1); - CHECK(one == one); - CHECK(!(one == zero)); + EXPECT_TRUE(one == one); + EXPECT_FALSE(one == zero); - CHECK(one != zero); - CHECK(!(one != one)); + EXPECT_TRUE(one != zero); + EXPECT_FALSE(one != one); - CHECK(zero < one); - CHECK(!(one < zero)); + EXPECT_TRUE(zero < one); + EXPECT_FALSE(one < zero); - CHECK(one > zero); - CHECK(!(zero > one)); + EXPECT_TRUE(one > zero); + EXPECT_FALSE(zero > one); - CHECK(one >= one); - CHECK(one >= zero); - CHECK(!(zero >= one)); + EXPECT_TRUE(one >= one); + EXPECT_TRUE(one >= zero); + EXPECT_FALSE(zero >= one); - CHECK(zero <= one); - CHECK(zero <= zero); - CHECK(!(one <= zero)); + EXPECT_TRUE(zero <= one); + EXPECT_TRUE(zero <= zero); + EXPECT_FALSE(one <= zero); } -TEST_CASE("increment / decrement operators") +TEST(tagged_integer, increment_decrement_operators) { TagInt const zero(0); TagInt const one(1); TagInt a{0}; ++a; - CHECK(a == one); + EXPECT_EQ(a, one); --a; - CHECK(a == zero); + EXPECT_EQ(a, zero); a++; - CHECK(a == one); + EXPECT_EQ(a, one); a--; - CHECK(a == zero); + EXPECT_EQ(a, zero); } -TEST_CASE("arithmetic operators") +TEST(tagged_integer, arithmetic_operators) { TagInt a{-2}; - CHECK(+a == TagInt{-2}); - CHECK(-a == TagInt{2}); - CHECK(TagInt{-3} + TagInt{4} == TagInt{1}); - CHECK(TagInt{-3} - TagInt{4} == TagInt{-7}); - CHECK(TagInt{-3} * TagInt{4} == TagInt{-12}); - CHECK(TagInt{8} / TagInt{4} == TagInt{2}); - CHECK(TagInt{7} % TagInt{4} == TagInt{3}); + EXPECT_EQ(+a, TagInt{-2}); + EXPECT_EQ(-a, TagInt{2}); + EXPECT_EQ(TagInt{-3} + TagInt{4}, TagInt{1}); + EXPECT_EQ(TagInt{-3} - TagInt{4}, TagInt{-7}); + EXPECT_EQ(TagInt{-3} * TagInt{4}, TagInt{-12}); + EXPECT_EQ(TagInt{8} / TagInt{4}, TagInt{2}); + EXPECT_EQ(TagInt{7} % TagInt{4}, TagInt{3}); - CHECK(~TagInt{8} == TagInt{~TagInt::value_type{8}}); - CHECK((TagInt{6} & TagInt{3}) == TagInt{2}); - CHECK((TagInt{6} | TagInt{3}) == TagInt{7}); - CHECK((TagInt{6} ^ TagInt{3}) == TagInt{5}); + EXPECT_EQ(~TagInt{8}, TagInt{~TagInt::value_type{8}}); + EXPECT_EQ((TagInt{6} & TagInt{3}), TagInt{2}); + EXPECT_EQ((TagInt{6} | TagInt{3}), TagInt{7}); + EXPECT_EQ((TagInt{6} ^ TagInt{3}), TagInt{5}); - CHECK((TagInt{4} << TagInt{2}) == TagInt{16}); - CHECK((TagInt{16} >> TagInt{2}) == TagInt{4}); + EXPECT_EQ((TagInt{4} << TagInt{2}), TagInt{16}); + EXPECT_EQ((TagInt{16} >> TagInt{2}), TagInt{4}); } -TEST_CASE("assignment operators") +TEST(tagged_integer, assignment_operators) { TagInt a{-2}; TagInt b{0}; b = a; - CHECK(b == TagInt{-2}); + EXPECT_EQ(b, TagInt{-2}); // -3 + 4 == 1 a = TagInt{-3}; a += TagInt{4}; - CHECK(a == TagInt{1}); + EXPECT_EQ(a, TagInt{1}); // -3 - 4 == -7 a = TagInt{-3}; a -= TagInt{4}; - CHECK(a == TagInt{-7}); + EXPECT_EQ(a, TagInt{-7}); // -3 * 4 == -12 a = TagInt{-3}; a *= TagInt{4}; - CHECK(a == TagInt{-12}); + EXPECT_EQ(a, TagInt{-12}); // 8/4 == 2 a = TagInt{8}; a /= TagInt{4}; - CHECK(a == TagInt{2}); + EXPECT_EQ(a, TagInt{2}); // 7 % 4 == 3 a = TagInt{7}; a %= TagInt{4}; - CHECK(a == TagInt{3}); + EXPECT_EQ(a, TagInt{3}); // 6 & 3 == 2 a = TagInt{6}; a /= TagInt{3}; - CHECK(a == TagInt{2}); + EXPECT_EQ(a, TagInt{2}); // 6 | 3 == 7 a = TagInt{6}; a |= TagInt{3}; - CHECK(a == TagInt{7}); + EXPECT_EQ(a, TagInt{7}); // 6 ^ 3 == 5 a = TagInt{6}; a ^= TagInt{3}; - CHECK(a == TagInt{5}); + EXPECT_EQ(a, TagInt{5}); // 4 << 2 == 16 a = TagInt{4}; a <<= TagInt{2}; - CHECK(a == TagInt{16}); + EXPECT_EQ(a, TagInt{16}); // 16 >> 2 == 4 a = TagInt{16}; a >>= TagInt{2}; - CHECK(a == TagInt{4}); + EXPECT_EQ(a, TagInt{4}); } - -TEST_SUITE_END(); diff --git a/src/tests/libxrpl/crypto/csprng.cpp b/src/tests/libxrpl/crypto/csprng.cpp index a55d49b67c..41dcfd57a9 100644 --- a/src/tests/libxrpl/crypto/csprng.cpp +++ b/src/tests/libxrpl/crypto/csprng.cpp @@ -1,34 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include +#include -using namespace ripple; +using namespace xrpl; -TEST_CASE("get values") +TEST(csprng, get_values) { auto& engine = crypto_prng(); auto rand_val = engine(); - CHECK(rand_val >= engine.min()); - CHECK(rand_val <= engine.max()); + EXPECT_GE(rand_val, engine.min()); + EXPECT_LE(rand_val, engine.max()); uint16_t twoByte{0}; engine(&twoByte, sizeof(uint16_t)); } diff --git a/src/tests/libxrpl/crypto/main.cpp b/src/tests/libxrpl/crypto/main.cpp index 0a3f254ea8..5142bbe08a 100644 --- a/src/tests/libxrpl/crypto/main.cpp +++ b/src/tests/libxrpl/crypto/main.cpp @@ -1,2 +1,8 @@ -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include +#include + +int +main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/tests/libxrpl/helpers/TestSink.cpp b/src/tests/libxrpl/helpers/TestSink.cpp new file mode 100644 index 0000000000..17cc110429 --- /dev/null +++ b/src/tests/libxrpl/helpers/TestSink.cpp @@ -0,0 +1,124 @@ +#include + +#include + +#include // for getenv + +#if BOOST_OS_WINDOWS +#include // for _isatty, _fileno +#include // for stdout +#else +#include // for isatty, STDOUT_FILENO +#endif + +#include + +namespace xrpl { + +TestSink::TestSink(beast::severities::Severity threshold) : Sink(threshold, false) +{ +} + +void +TestSink::write(beast::severities::Severity level, std::string const& text) +{ + if (level < threshold()) + return; + writeAlways(level, text); +} + +void +TestSink::writeAlways(beast::severities::Severity level, std::string const& text) +{ + auto supportsColor = [] { + // 1. Check for "NO_COLOR" environment variable (Standard convention) + if (std::getenv("NO_COLOR") != nullptr) + { + return false; + } + + // 2. Check for "CLICOLOR_FORCE" (Force color) + if (std::getenv("CLICOLOR_FORCE") != nullptr) + { + return true; + } + + // 3. Platform-specific check to see if stdout is a terminal +#if BOOST_OS_WINDOWS + // Windows: Check if the output handle is a character device + // _fileno(stdout) is usually 1 + // _isatty returns non-zero if the handle is a character device, 0 + // otherwise. + return _isatty(_fileno(stdout)) != 0; +#else + // Linux/macOS: Check if file descriptor 1 (stdout) is a TTY + // STDOUT_FILENO is 1 + // isatty returns 1 if the file descriptor is a TTY, 0 otherwise. + return isatty(STDOUT_FILENO) != 0; +#endif + }(); + + auto color = [level]() { + switch (level) + { + case beast::severities::kTrace: + return "\033[34m"; // blue + case beast::severities::kDebug: + return "\033[32m"; // green + case beast::severities::kInfo: + return "\033[36m"; // cyan + case beast::severities::kWarning: + return "\033[33m"; // yellow + case beast::severities::kError: + return "\033[31m"; // red + case beast::severities::kFatal: + default: + break; + } + return "\033[31m"; // red + }(); + + auto prefix = [level]() { + switch (level) + { + case beast::severities::kTrace: + return "TRC:"; + case beast::severities::kDebug: + return "DBG:"; + case beast::severities::kInfo: + return "INF:"; + case beast::severities::kWarning: + return "WRN:"; + case beast::severities::kError: + return "ERR:"; + case beast::severities::kFatal: + default: + break; + } + return "FTL:"; + }(); + + auto& stream = [level]() -> std::ostream& { + switch (level) + { + case beast::severities::kError: + case beast::severities::kFatal: + return std::cerr; + default: + return std::cout; + } + }(); + + constexpr auto reset = "\033[0m"; + + if (supportsColor) + { + stream << color << prefix << " " << text << reset << std::endl; + } + else + { + stream << prefix << " " << text << std::endl; + } +} + +} // namespace xrpl diff --git a/src/tests/libxrpl/helpers/TestSink.h b/src/tests/libxrpl/helpers/TestSink.h new file mode 100644 index 0000000000..daa40d014f --- /dev/null +++ b/src/tests/libxrpl/helpers/TestSink.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace xrpl { +class TestSink : public beast::Journal::Sink +{ +public: + static TestSink& + instance() + { + static TestSink sink{}; + return sink; + } + + TestSink(beast::severities::Severity threshold = beast::severities::kDebug); + + void + write(beast::severities::Severity level, std::string const& text) override; + + void + writeAlways(beast::severities::Severity level, std::string const& text) override; +}; +} // namespace xrpl diff --git a/src/tests/libxrpl/json/Output.cpp b/src/tests/libxrpl/json/Output.cpp index 3b542d81b0..96d7369d51 100644 --- a/src/tests/libxrpl/json/Output.cpp +++ b/src/tests/libxrpl/json/Output.cpp @@ -1,51 +1,30 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -#include +#include #include -using namespace ripple; +using namespace xrpl; using namespace Json; -TEST_SUITE_BEGIN("JsonOutput"); - static void checkOutput(std::string const& valueDesc) { std::string output; Json::Value value; - REQUIRE(Json::Reader().parse(valueDesc, value)); + ASSERT_TRUE(Json::Reader().parse(valueDesc, value)); auto out = stringOutput(output); outputJson(value, out); auto expected = Json::FastWriter().write(value); - CHECK(output == expected); - CHECK(output == valueDesc); - CHECK(output == jsonAsString(value)); + EXPECT_EQ(output, expected); + EXPECT_EQ(output, valueDesc); + EXPECT_EQ(output, jsonAsString(value)); } -TEST_CASE("output cases") +TEST(JsonOutput, output_cases) { checkOutput("{}"); checkOutput("[]"); @@ -55,5 +34,3 @@ TEST_CASE("output cases") checkOutput("[[]]"); checkOutput(R"({"array":[{"12":23},{},null,false,0.5]})"); } - -TEST_SUITE_END(); diff --git a/src/tests/libxrpl/json/Value.cpp b/src/tests/libxrpl/json/Value.cpp index 3da8e14ba4..1d1131b209 100644 --- a/src/tests/libxrpl/json/Value.cpp +++ b/src/tests/libxrpl/json/Value.cpp @@ -1,64 +1,51 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -#include +#include #include +#include #include #include #include -namespace ripple { +namespace xrpl { -TEST_SUITE_BEGIN("json_value"); +TEST(json_value, limits) +{ + using namespace Json; + static_assert(Value::minInt == Int(~(UInt(-1) / 2))); + static_assert(Value::maxInt == Int(UInt(-1) / 2)); + static_assert(Value::maxUInt == UInt(-1)); +} -TEST_CASE("construct and compare Json::StaticString") +TEST(json_value, construct_and_compare_Json_StaticString) { static constexpr char sample[]{"Contents of a Json::StaticString"}; static constexpr Json::StaticString test1(sample); char const* addrTest1{test1}; - CHECK(addrTest1 == &sample[0]); - CHECK(test1.c_str() == &sample[0]); + EXPECT_EQ(addrTest1, &sample[0]); + EXPECT_EQ(test1.c_str(), &sample[0]); - static constexpr Json::StaticString test2{ - "Contents of a Json::StaticString"}; + static constexpr Json::StaticString test2{"Contents of a Json::StaticString"}; static constexpr Json::StaticString test3{"Another StaticString"}; - CHECK(test1 == test2); - CHECK(test1 != test3); + EXPECT_EQ(test1, test2); + EXPECT_NE(test1, test3); std::string str{sample}; - CHECK(str == test2); - CHECK(str != test3); - CHECK(test2 == str); - CHECK(test3 != str); + EXPECT_EQ(str, test2); + EXPECT_NE(str, test3); + EXPECT_EQ(test2, str); + EXPECT_NE(test3, str); } -TEST_CASE("different types") +TEST(json_value, different_types) { // Exercise ValueType constructor static constexpr Json::StaticString staticStr{"staticStr"}; @@ -66,166 +53,162 @@ TEST_CASE("different types") auto testCopy = [](Json::ValueType typ) { Json::Value val{typ}; Json::Value cpy{val}; - CHECK(val.type() == typ); - CHECK(cpy.type() == typ); + EXPECT_EQ(val.type(), typ); + EXPECT_EQ(cpy.type(), typ); return val; }; { Json::Value const nullV{testCopy(Json::nullValue)}; - CHECK(nullV.isNull()); - CHECK(!nullV.isBool()); - CHECK(!nullV.isInt()); - CHECK(!nullV.isUInt()); - CHECK(!nullV.isIntegral()); - CHECK(!nullV.isDouble()); - CHECK(!nullV.isNumeric()); - CHECK(!nullV.isString()); - CHECK(!nullV.isArray()); - CHECK(nullV.isArrayOrNull()); - CHECK(!nullV.isObject()); - CHECK(nullV.isObjectOrNull()); + EXPECT_TRUE(nullV.isNull()); + EXPECT_FALSE(nullV.isBool()); + EXPECT_FALSE(nullV.isInt()); + EXPECT_FALSE(nullV.isUInt()); + EXPECT_FALSE(nullV.isIntegral()); + EXPECT_FALSE(nullV.isDouble()); + EXPECT_FALSE(nullV.isNumeric()); + EXPECT_FALSE(nullV.isString()); + EXPECT_FALSE(nullV.isArray()); + EXPECT_TRUE(nullV.isArrayOrNull()); + EXPECT_FALSE(nullV.isObject()); + EXPECT_TRUE(nullV.isObjectOrNull()); } { Json::Value const intV{testCopy(Json::intValue)}; - CHECK(!intV.isNull()); - CHECK(!intV.isBool()); - CHECK(intV.isInt()); - CHECK(!intV.isUInt()); - CHECK(intV.isIntegral()); - CHECK(!intV.isDouble()); - CHECK(intV.isNumeric()); - CHECK(!intV.isString()); - CHECK(!intV.isArray()); - CHECK(!intV.isArrayOrNull()); - CHECK(!intV.isObject()); - CHECK(!intV.isObjectOrNull()); + EXPECT_FALSE(intV.isNull()); + EXPECT_FALSE(intV.isBool()); + EXPECT_TRUE(intV.isInt()); + EXPECT_FALSE(intV.isUInt()); + EXPECT_TRUE(intV.isIntegral()); + EXPECT_FALSE(intV.isDouble()); + EXPECT_TRUE(intV.isNumeric()); + EXPECT_FALSE(intV.isString()); + EXPECT_FALSE(intV.isArray()); + EXPECT_FALSE(intV.isArrayOrNull()); + EXPECT_FALSE(intV.isObject()); + EXPECT_FALSE(intV.isObjectOrNull()); } { Json::Value const uintV{testCopy(Json::uintValue)}; - CHECK(!uintV.isNull()); - CHECK(!uintV.isBool()); - CHECK(!uintV.isInt()); - CHECK(uintV.isUInt()); - CHECK(uintV.isIntegral()); - CHECK(!uintV.isDouble()); - CHECK(uintV.isNumeric()); - CHECK(!uintV.isString()); - CHECK(!uintV.isArray()); - CHECK(!uintV.isArrayOrNull()); - CHECK(!uintV.isObject()); - CHECK(!uintV.isObjectOrNull()); + EXPECT_FALSE(uintV.isNull()); + EXPECT_FALSE(uintV.isBool()); + EXPECT_FALSE(uintV.isInt()); + EXPECT_TRUE(uintV.isUInt()); + EXPECT_TRUE(uintV.isIntegral()); + EXPECT_FALSE(uintV.isDouble()); + EXPECT_TRUE(uintV.isNumeric()); + EXPECT_FALSE(uintV.isString()); + EXPECT_FALSE(uintV.isArray()); + EXPECT_FALSE(uintV.isArrayOrNull()); + EXPECT_FALSE(uintV.isObject()); + EXPECT_FALSE(uintV.isObjectOrNull()); } { Json::Value const realV{testCopy(Json::realValue)}; - CHECK(!realV.isNull()); - CHECK(!realV.isBool()); - CHECK(!realV.isInt()); - CHECK(!realV.isUInt()); - CHECK(!realV.isIntegral()); - CHECK(realV.isDouble()); - CHECK(realV.isNumeric()); - CHECK(!realV.isString()); - CHECK(!realV.isArray()); - CHECK(!realV.isArrayOrNull()); - CHECK(!realV.isObject()); - CHECK(!realV.isObjectOrNull()); + EXPECT_FALSE(realV.isNull()); + EXPECT_FALSE(realV.isBool()); + EXPECT_FALSE(realV.isInt()); + EXPECT_FALSE(realV.isUInt()); + EXPECT_FALSE(realV.isIntegral()); + EXPECT_TRUE(realV.isDouble()); + EXPECT_TRUE(realV.isNumeric()); + EXPECT_FALSE(realV.isString()); + EXPECT_FALSE(realV.isArray()); + EXPECT_FALSE(realV.isArrayOrNull()); + EXPECT_FALSE(realV.isObject()); + EXPECT_FALSE(realV.isObjectOrNull()); } { Json::Value const stringV{testCopy(Json::stringValue)}; - CHECK(!stringV.isNull()); - CHECK(!stringV.isBool()); - CHECK(!stringV.isInt()); - CHECK(!stringV.isUInt()); - CHECK(!stringV.isIntegral()); - CHECK(!stringV.isDouble()); - CHECK(!stringV.isNumeric()); - CHECK(stringV.isString()); - CHECK(!stringV.isArray()); - CHECK(!stringV.isArrayOrNull()); - CHECK(!stringV.isObject()); - CHECK(!stringV.isObjectOrNull()); + EXPECT_FALSE(stringV.isNull()); + EXPECT_FALSE(stringV.isBool()); + EXPECT_FALSE(stringV.isInt()); + EXPECT_FALSE(stringV.isUInt()); + EXPECT_FALSE(stringV.isIntegral()); + EXPECT_FALSE(stringV.isDouble()); + EXPECT_FALSE(stringV.isNumeric()); + EXPECT_TRUE(stringV.isString()); + EXPECT_FALSE(stringV.isArray()); + EXPECT_FALSE(stringV.isArrayOrNull()); + EXPECT_FALSE(stringV.isObject()); + EXPECT_FALSE(stringV.isObjectOrNull()); } { Json::Value const staticStrV{staticStr}; { Json::Value cpy{staticStrV}; - CHECK(staticStrV.type() == Json::stringValue); - CHECK(cpy.type() == Json::stringValue); + EXPECT_EQ(staticStrV.type(), Json::stringValue); + EXPECT_EQ(cpy.type(), Json::stringValue); } - CHECK(!staticStrV.isNull()); - CHECK(!staticStrV.isBool()); - CHECK(!staticStrV.isInt()); - CHECK(!staticStrV.isUInt()); - CHECK(!staticStrV.isIntegral()); - CHECK(!staticStrV.isDouble()); - CHECK(!staticStrV.isNumeric()); - CHECK(staticStrV.isString()); - CHECK(!staticStrV.isArray()); - CHECK(!staticStrV.isArrayOrNull()); - CHECK(!staticStrV.isObject()); - CHECK(!staticStrV.isObjectOrNull()); + EXPECT_FALSE(staticStrV.isNull()); + EXPECT_FALSE(staticStrV.isBool()); + EXPECT_FALSE(staticStrV.isInt()); + EXPECT_FALSE(staticStrV.isUInt()); + EXPECT_FALSE(staticStrV.isIntegral()); + EXPECT_FALSE(staticStrV.isDouble()); + EXPECT_FALSE(staticStrV.isNumeric()); + EXPECT_TRUE(staticStrV.isString()); + EXPECT_FALSE(staticStrV.isArray()); + EXPECT_FALSE(staticStrV.isArrayOrNull()); + EXPECT_FALSE(staticStrV.isObject()); + EXPECT_FALSE(staticStrV.isObjectOrNull()); } { Json::Value const boolV{testCopy(Json::booleanValue)}; - CHECK(!boolV.isNull()); - CHECK(boolV.isBool()); - CHECK(!boolV.isInt()); - CHECK(!boolV.isUInt()); - CHECK(boolV.isIntegral()); - CHECK(!boolV.isDouble()); - CHECK(boolV.isNumeric()); - CHECK(!boolV.isString()); - CHECK(!boolV.isArray()); - CHECK(!boolV.isArrayOrNull()); - CHECK(!boolV.isObject()); - CHECK(!boolV.isObjectOrNull()); + EXPECT_FALSE(boolV.isNull()); + EXPECT_TRUE(boolV.isBool()); + EXPECT_FALSE(boolV.isInt()); + EXPECT_FALSE(boolV.isUInt()); + EXPECT_TRUE(boolV.isIntegral()); + EXPECT_FALSE(boolV.isDouble()); + EXPECT_TRUE(boolV.isNumeric()); + EXPECT_FALSE(boolV.isString()); + EXPECT_FALSE(boolV.isArray()); + EXPECT_FALSE(boolV.isArrayOrNull()); + EXPECT_FALSE(boolV.isObject()); + EXPECT_FALSE(boolV.isObjectOrNull()); } { Json::Value const arrayV{testCopy(Json::arrayValue)}; - CHECK(!arrayV.isNull()); - CHECK(!arrayV.isBool()); - CHECK(!arrayV.isInt()); - CHECK(!arrayV.isUInt()); - CHECK(!arrayV.isIntegral()); - CHECK(!arrayV.isDouble()); - CHECK(!arrayV.isNumeric()); - CHECK(!arrayV.isString()); - CHECK(arrayV.isArray()); - CHECK(arrayV.isArrayOrNull()); - CHECK(!arrayV.isObject()); - CHECK(!arrayV.isObjectOrNull()); + EXPECT_FALSE(arrayV.isNull()); + EXPECT_FALSE(arrayV.isBool()); + EXPECT_FALSE(arrayV.isInt()); + EXPECT_FALSE(arrayV.isUInt()); + EXPECT_FALSE(arrayV.isIntegral()); + EXPECT_FALSE(arrayV.isDouble()); + EXPECT_FALSE(arrayV.isNumeric()); + EXPECT_FALSE(arrayV.isString()); + EXPECT_TRUE(arrayV.isArray()); + EXPECT_TRUE(arrayV.isArrayOrNull()); + EXPECT_FALSE(arrayV.isObject()); + EXPECT_FALSE(arrayV.isObjectOrNull()); } { Json::Value const objectV{testCopy(Json::objectValue)}; - CHECK(!objectV.isNull()); - CHECK(!objectV.isBool()); - CHECK(!objectV.isInt()); - CHECK(!objectV.isUInt()); - CHECK(!objectV.isIntegral()); - CHECK(!objectV.isDouble()); - CHECK(!objectV.isNumeric()); - CHECK(!objectV.isString()); - CHECK(!objectV.isArray()); - CHECK(!objectV.isArrayOrNull()); - CHECK(objectV.isObject()); - CHECK(objectV.isObjectOrNull()); + EXPECT_FALSE(objectV.isNull()); + EXPECT_FALSE(objectV.isBool()); + EXPECT_FALSE(objectV.isInt()); + EXPECT_FALSE(objectV.isUInt()); + EXPECT_FALSE(objectV.isIntegral()); + EXPECT_FALSE(objectV.isDouble()); + EXPECT_FALSE(objectV.isNumeric()); + EXPECT_FALSE(objectV.isString()); + EXPECT_FALSE(objectV.isArray()); + EXPECT_FALSE(objectV.isArrayOrNull()); + EXPECT_TRUE(objectV.isObject()); + EXPECT_TRUE(objectV.isObjectOrNull()); } } -TEST_CASE("compare strings") +TEST(json_value, compare_strings) { - auto doCompare = [&](Json::Value const& lhs, - Json::Value const& rhs, - bool lhsEqRhs, - bool lhsLtRhs, - int line) { - CAPTURE(line); - CHECK((lhs == rhs) == lhsEqRhs); - CHECK((lhs != rhs) != lhsEqRhs); - CHECK((lhs < rhs) == (!(lhsEqRhs || !lhsLtRhs))); - CHECK((lhs <= rhs) == (lhsEqRhs || lhsLtRhs)); - CHECK((lhs >= rhs) == (lhsEqRhs || !lhsLtRhs)); - CHECK((lhs > rhs) == (!(lhsEqRhs || lhsLtRhs))); + auto doCompare = [&](Json::Value const& lhs, Json::Value const& rhs, bool lhsEqRhs, bool lhsLtRhs, int line) { + SCOPED_TRACE(line); + EXPECT_EQ((lhs == rhs), lhsEqRhs); + EXPECT_NE((lhs != rhs), lhsEqRhs); + EXPECT_EQ((lhs < rhs), (!(lhsEqRhs || !lhsLtRhs))); + EXPECT_EQ((lhs <= rhs), (lhsEqRhs || lhsLtRhs)); + EXPECT_EQ((lhs >= rhs), (lhsEqRhs || !lhsLtRhs)); + EXPECT_EQ((lhs > rhs), (!(lhsEqRhs || lhsLtRhs))); }; Json::Value const null0; @@ -566,43 +549,41 @@ TEST_CASE("compare strings") #pragma pop_macro("DO_COMPARE") } -TEST_CASE("bool") +TEST(json_value, bool) { - CHECK(!Json::Value()); + EXPECT_FALSE(Json::Value()); - CHECK(!Json::Value("")); + EXPECT_FALSE(Json::Value("")); - CHECK(bool(Json::Value("empty"))); - CHECK(bool(Json::Value(false))); - CHECK(bool(Json::Value(true))); - CHECK(bool(Json::Value(0))); - CHECK(bool(Json::Value(1))); + EXPECT_TRUE(bool(Json::Value("empty"))); + EXPECT_TRUE(bool(Json::Value(false))); + EXPECT_TRUE(bool(Json::Value(true))); + EXPECT_TRUE(bool(Json::Value(0))); + EXPECT_TRUE(bool(Json::Value(1))); Json::Value array(Json::arrayValue); - CHECK(!array); + EXPECT_FALSE(array); array.append(0); - CHECK(bool(array)); + EXPECT_TRUE(bool(array)); Json::Value object(Json::objectValue); - CHECK(!object); + EXPECT_FALSE(object); object[""] = false; - CHECK(bool(object)); + EXPECT_TRUE(bool(object)); } -TEST_CASE("bad json") +TEST(json_value, bad_json) { char const* s(R"({"method":"ledger","params":[{"ledger_index":1e300}]})"); Json::Value j; Json::Reader r; - CHECK(r.parse(s, j)); + EXPECT_TRUE(r.parse(s, j)); } -TEST_CASE("edge cases") +TEST(json_value, edge_cases) { - std::string json; - std::uint32_t max_uint = std::numeric_limits::max(); std::int32_t max_int = std::numeric_limits::max(); std::int32_t min_int = std::numeric_limits::min(); @@ -611,150 +592,220 @@ TEST_CASE("edge cases") std::int32_t a_large_int = max_int - 1978; std::int32_t a_small_int = min_int + 1978; - json = "{\"max_uint\":" + std::to_string(max_uint); - json += ",\"max_int\":" + std::to_string(max_int); - json += ",\"min_int\":" + std::to_string(min_int); - json += ",\"a_uint\":" + std::to_string(a_uint); - json += ",\"a_large_int\":" + std::to_string(a_large_int); - json += ",\"a_small_int\":" + std::to_string(a_small_int); - json += "}"; + { + std::string json = "{\"max_uint\":" + std::to_string(max_uint); + json += ",\"max_int\":" + std::to_string(max_int); + json += ",\"min_int\":" + std::to_string(min_int); + json += ",\"a_uint\":" + std::to_string(a_uint); + json += ",\"a_large_int\":" + std::to_string(a_large_int); + json += ",\"a_small_int\":" + std::to_string(a_small_int); + json += "}"; - Json::Value j1; - Json::Reader r1; + Json::Value j1; + Json::Reader r1; - CHECK(r1.parse(json, j1)); - CHECK(j1["max_uint"].asUInt() == max_uint); - CHECK(j1["max_int"].asInt() == max_int); - CHECK(j1["min_int"].asInt() == min_int); - CHECK(j1["a_uint"].asUInt() == a_uint); - CHECK(j1["a_uint"] > a_large_int); - CHECK(j1["a_uint"] > a_small_int); - CHECK(j1["a_large_int"].asInt() == a_large_int); - CHECK(j1["a_large_int"].asUInt() == a_large_int); - CHECK(j1["a_large_int"] < a_uint); - CHECK(j1["a_small_int"].asInt() == a_small_int); - CHECK(j1["a_small_int"] < a_uint); + EXPECT_TRUE(r1.parse(json, j1)); + EXPECT_EQ(j1["max_uint"].asUInt(), max_uint); + EXPECT_EQ(j1["max_uint"].asAbsUInt(), max_uint); + EXPECT_EQ(j1["max_int"].asInt(), max_int); + EXPECT_EQ(j1["max_int"].asAbsUInt(), max_int); + EXPECT_EQ(j1["min_int"].asInt(), min_int); + EXPECT_EQ(j1["min_int"].asAbsUInt(), static_cast(min_int) * -1); + EXPECT_EQ(j1["a_uint"].asUInt(), a_uint); + EXPECT_EQ(j1["a_uint"].asAbsUInt(), a_uint); + EXPECT_GT(j1["a_uint"], a_large_int); + EXPECT_GT(j1["a_uint"], a_small_int); + EXPECT_EQ(j1["a_large_int"].asInt(), a_large_int); + EXPECT_EQ(j1["a_large_int"].asAbsUInt(), a_large_int); + EXPECT_EQ(j1["a_large_int"].asUInt(), a_large_int); + EXPECT_LT(j1["a_large_int"], a_uint); + EXPECT_EQ(j1["a_small_int"].asInt(), a_small_int); + EXPECT_EQ(j1["a_small_int"].asAbsUInt(), static_cast(a_small_int) * -1); + EXPECT_LT(j1["a_small_int"], a_uint); + } - json = "{\"overflow\":"; - json += std::to_string(std::uint64_t(max_uint) + 1); - json += "}"; + std::uint64_t overflow = std::uint64_t(max_uint) + 1; + { + std::string json = "{\"overflow\":"; + json += std::to_string(overflow); + json += "}"; - Json::Value j2; - Json::Reader r2; + Json::Value j2; + Json::Reader r2; - CHECK(!r2.parse(json, j2)); + EXPECT_FALSE(r2.parse(json, j2)); + } - json = "{\"underflow\":"; - json += std::to_string(std::int64_t(min_int) - 1); - json += "}"; + std::int64_t underflow = std::int64_t(min_int) - 1; + { + std::string json = "{\"underflow\":"; + json += std::to_string(underflow); + json += "}"; - Json::Value j3; - Json::Reader r3; + Json::Value j3; + Json::Reader r3; - CHECK(!r3.parse(json, j3)); + EXPECT_FALSE(r3.parse(json, j3)); + } - Json::Value intString{"4294967296"}; - CHECK_THROWS_AS(intString.asUInt(), beast::BadLexicalCast); + { + Json::Value intString{std::to_string(overflow)}; + EXPECT_THROW(intString.asUInt(), beast::BadLexicalCast); + EXPECT_THROW(intString.asAbsUInt(), Json::error); - intString = "4294967295"; - CHECK(intString.asUInt() == 4294967295u); + intString = "4294967295"; + EXPECT_EQ(intString.asUInt(), 4294967295u); + EXPECT_EQ(intString.asAbsUInt(), 4294967295u); - intString = "0"; - CHECK(intString.asUInt() == 0); + intString = "0"; + EXPECT_EQ(intString.asUInt(), 0); + EXPECT_EQ(intString.asAbsUInt(), 0); - intString = "-1"; - CHECK_THROWS_AS(intString.asUInt(), beast::BadLexicalCast); + intString = "-1"; + EXPECT_THROW(intString.asUInt(), beast::BadLexicalCast); + EXPECT_EQ(intString.asAbsUInt(), 1); - intString = "2147483648"; - CHECK_THROWS_AS(intString.asInt(), beast::BadLexicalCast); + intString = "-4294967295"; + EXPECT_EQ(intString.asAbsUInt(), 4294967295); - intString = "2147483647"; - CHECK(intString.asInt() == 2147483647); + intString = "-4294967296"; + EXPECT_THROW(intString.asAbsUInt(), Json::error); - intString = "-2147483648"; - CHECK(intString.asInt() == -2147483648LL); // MSVC wants the LL + intString = "2147483648"; + EXPECT_THROW(intString.asInt(), beast::BadLexicalCast); + EXPECT_EQ(intString.asAbsUInt(), 2147483648); - intString = "-2147483649"; - CHECK_THROWS_AS(intString.asInt(), beast::BadLexicalCast); + intString = "2147483647"; + EXPECT_EQ(intString.asInt(), 2147483647); + EXPECT_EQ(intString.asAbsUInt(), 2147483647); + + intString = "-2147483648"; + EXPECT_EQ(intString.asInt(), -2147483648LL); // MSVC wants the LL + EXPECT_EQ(intString.asAbsUInt(), 2147483648LL); + + intString = "-2147483649"; + EXPECT_THROW(intString.asInt(), beast::BadLexicalCast); + EXPECT_EQ(intString.asAbsUInt(), 2147483649); + } + + { + Json::Value intReal{4294967297.0}; + EXPECT_THROW(intReal.asUInt(), Json::error); + EXPECT_THROW(intReal.asAbsUInt(), Json::error); + + intReal = 4294967295.0; + EXPECT_EQ(intReal.asUInt(), 4294967295u); + EXPECT_EQ(intReal.asAbsUInt(), 4294967295u); + + intReal = 0.0; + EXPECT_EQ(intReal.asUInt(), 0); + EXPECT_EQ(intReal.asAbsUInt(), 0); + + intReal = -1.0; + EXPECT_THROW(intReal.asUInt(), Json::error); + EXPECT_EQ(intReal.asAbsUInt(), 1); + + intReal = -4294967295.0; + EXPECT_EQ(intReal.asAbsUInt(), 4294967295); + + intReal = -4294967296.0; + EXPECT_THROW(intReal.asAbsUInt(), Json::error); + + intReal = 2147483648.0; + EXPECT_THROW(intReal.asInt(), Json::error); + EXPECT_EQ(intReal.asAbsUInt(), 2147483648); + + intReal = 2147483647.0; + EXPECT_EQ(intReal.asInt(), 2147483647); + EXPECT_EQ(intReal.asAbsUInt(), 2147483647); + + intReal = -2147483648.0; + EXPECT_EQ(intReal.asInt(), -2147483648LL); // MSVC wants the LL + EXPECT_EQ(intReal.asAbsUInt(), 2147483648LL); + + intReal = -2147483649.0; + EXPECT_THROW(intReal.asInt(), Json::error); + EXPECT_EQ(intReal.asAbsUInt(), 2147483649); + } } -TEST_CASE("copy") +TEST(json_value, copy) { Json::Value v1{2.5}; - CHECK(v1.isDouble()); - CHECK(v1.asDouble() == 2.5); + EXPECT_TRUE(v1.isDouble()); + EXPECT_EQ(v1.asDouble(), 2.5); Json::Value v2 = v1; - CHECK(v1.isDouble()); - CHECK(v1.asDouble() == 2.5); - CHECK(v2.isDouble()); - CHECK(v2.asDouble() == 2.5); - CHECK(v1 == v2); + EXPECT_TRUE(v1.isDouble()); + EXPECT_EQ(v1.asDouble(), 2.5); + EXPECT_TRUE(v2.isDouble()); + EXPECT_EQ(v2.asDouble(), 2.5); + EXPECT_EQ(v1, v2); v1 = v2; - CHECK(v1.isDouble()); - CHECK(v1.asDouble() == 2.5); - CHECK(v2.isDouble()); - CHECK(v2.asDouble() == 2.5); - CHECK(v1 == v2); + EXPECT_TRUE(v1.isDouble()); + EXPECT_EQ(v1.asDouble(), 2.5); + EXPECT_TRUE(v2.isDouble()); + EXPECT_EQ(v2.asDouble(), 2.5); + EXPECT_EQ(v1, v2); } -TEST_CASE("move") +TEST(json_value, move) { Json::Value v1{2.5}; - CHECK(v1.isDouble()); - CHECK(v1.asDouble() == 2.5); + EXPECT_TRUE(v1.isDouble()); + EXPECT_EQ(v1.asDouble(), 2.5); Json::Value v2 = std::move(v1); - CHECK(!v1); - CHECK(v2.isDouble()); - CHECK(v2.asDouble() == 2.5); - CHECK(v1 != v2); + EXPECT_FALSE(v1); + EXPECT_TRUE(v2.isDouble()); + EXPECT_EQ(v2.asDouble(), 2.5); + EXPECT_NE(v1, v2); v1 = std::move(v2); - CHECK(v1.isDouble()); - CHECK(v1.asDouble() == 2.5); - CHECK(!v2); - CHECK(v1 != v2); + EXPECT_TRUE(v1.isDouble()); + EXPECT_EQ(v1.asDouble(), 2.5); + EXPECT_FALSE(v2); + EXPECT_NE(v1, v2); } -TEST_CASE("comparisons") +TEST(json_value, comparisons) { Json::Value a, b; auto testEquals = [&](std::string const& name) { - CHECK(a == b); - CHECK(a <= b); - CHECK(a >= b); + EXPECT_TRUE(a == b); + EXPECT_TRUE(a <= b); + EXPECT_TRUE(a >= b); - CHECK(!(a != b)); - CHECK(!(a < b)); - CHECK(!(a > b)); + EXPECT_FALSE(a != b); + EXPECT_FALSE(a < b); + EXPECT_FALSE(a > b); - CHECK(b == a); - CHECK(b <= a); - CHECK(b >= a); + EXPECT_TRUE(b == a); + EXPECT_TRUE(b <= a); + EXPECT_TRUE(b >= a); - CHECK(!(b != a)); - CHECK(!(b < a)); - CHECK(!(b > a)); + EXPECT_FALSE(b != a); + EXPECT_FALSE(b < a); + EXPECT_FALSE(b > a); }; auto testGreaterThan = [&](std::string const& name) { - CHECK(!(a == b)); - CHECK(!(a <= b)); - CHECK(a >= b); + EXPECT_FALSE(a == b); + EXPECT_FALSE(a <= b); + EXPECT_TRUE(a >= b); - CHECK(a != b); - CHECK(!(a < b)); - CHECK(a > b); + EXPECT_TRUE(a != b); + EXPECT_FALSE(a < b); + EXPECT_TRUE(a > b); - CHECK(!(b == a)); - CHECK(b <= a); - CHECK(!(b >= a)); + EXPECT_FALSE(b == a); + EXPECT_TRUE(b <= a); + EXPECT_FALSE(b >= a); - CHECK(b != a); - CHECK(b < a); - CHECK(!(b > a)); + EXPECT_TRUE(b != a); + EXPECT_TRUE(b < a); + EXPECT_FALSE(b > a); }; a["a"] = Json::UInt(0); @@ -773,32 +824,30 @@ TEST_CASE("comparisons") testGreaterThan("big"); } -TEST_CASE("compact") +TEST(json_value, compact) { Json::Value j; Json::Reader r; char const* s("{\"array\":[{\"12\":23},{},null,false,0.5]}"); auto countLines = [](std::string const& str) { - return 1 + std::count_if(str.begin(), str.end(), [](char c) { - return c == '\n'; - }); + return 1 + std::count_if(str.begin(), str.end(), [](char c) { return c == '\n'; }); }; - CHECK(r.parse(s, j)); + EXPECT_TRUE(r.parse(s, j)); { std::stringstream ss; ss << j; - CHECK(countLines(ss.str()) > 1); + EXPECT_GT(countLines(ss.str()), 1); } { std::stringstream ss; ss << Json::Compact(std::move(j)); - CHECK(countLines(ss.str()) == 1); + EXPECT_EQ(countLines(ss.str()), 1); } } -TEST_CASE("conversions") +TEST(json_value, conversions) { // We have Json::Int, but not Json::Double or Json::Real. // We have Json::Int, Json::Value::Int, and Json::ValueType::intValue. @@ -807,326 +856,336 @@ TEST_CASE("conversions") { // null Json::Value val; - CHECK(val.isNull()); + EXPECT_TRUE(val.isNull()); // val.asCString() should trigger an assertion failure - CHECK(val.asString() == ""); - CHECK(val.asInt() == 0); - CHECK(val.asUInt() == 0); - CHECK(val.asDouble() == 0.0); - CHECK(val.asBool() == false); + EXPECT_EQ(val.asString(), ""); + EXPECT_EQ(val.asInt(), 0); + EXPECT_EQ(val.asUInt(), 0); + EXPECT_EQ(val.asAbsUInt(), 0); + EXPECT_EQ(val.asDouble(), 0.0); + EXPECT_FALSE(val.asBool()); - CHECK(val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(val.isConvertibleTo(Json::arrayValue)); - CHECK(val.isConvertibleTo(Json::objectValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::objectValue)); } { // int Json::Value val = -1234; - CHECK(val.isInt()); + EXPECT_TRUE(val.isInt()); // val.asCString() should trigger an assertion failure - CHECK(val.asString() == "-1234"); - CHECK(val.asInt() == -1234); - CHECK_THROWS_AS(val.asUInt(), Json::error); - CHECK(val.asDouble() == -1234.0); - CHECK(val.asBool() == true); + EXPECT_EQ(val.asString(), "-1234"); + EXPECT_EQ(val.asInt(), -1234); + EXPECT_THROW(val.asUInt(), Json::error); + EXPECT_EQ(val.asAbsUInt(), 1234u); + EXPECT_EQ(val.asDouble(), -1234.0); + EXPECT_TRUE(val.asBool()); - CHECK(!val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(!val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // uint Json::Value val = 1234U; - CHECK(val.isUInt()); + EXPECT_TRUE(val.isUInt()); // val.asCString() should trigger an assertion failure - CHECK(val.asString() == "1234"); - CHECK(val.asInt() == 1234); - CHECK(val.asUInt() == 1234u); - CHECK(val.asDouble() == 1234.0); - CHECK(val.asBool() == true); + EXPECT_EQ(val.asString(), "1234"); + EXPECT_EQ(val.asInt(), 1234); + EXPECT_EQ(val.asUInt(), 1234u); + EXPECT_EQ(val.asAbsUInt(), 1234u); + EXPECT_EQ(val.asDouble(), 1234.0); + EXPECT_TRUE(val.asBool()); - CHECK(!val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // real Json::Value val = 2.0; - CHECK(val.isDouble()); + EXPECT_TRUE(val.isDouble()); // val.asCString() should trigger an assertion failure - CHECK(std::regex_match(val.asString(), std::regex("^2\\.0*$"))); - CHECK(val.asInt() == 2); - CHECK(val.asUInt() == 2u); - CHECK(val.asDouble() == 2.0); - CHECK(val.asBool() == true); + EXPECT_TRUE(std::regex_match(val.asString(), std::regex("^2\\.0*$"))); + EXPECT_EQ(val.asInt(), 2); + EXPECT_EQ(val.asUInt(), 2u); + EXPECT_EQ(val.asAbsUInt(), 2u); + EXPECT_EQ(val.asDouble(), 2.0); + EXPECT_TRUE(val.asBool()); - CHECK(!val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // numeric string Json::Value val = "54321"; - CHECK(val.isString()); - CHECK(strcmp(val.asCString(), "54321") == 0); - CHECK(val.asString() == "54321"); - CHECK(val.asInt() == 54321); - CHECK(val.asUInt() == 54321u); - CHECK_THROWS_AS(val.asDouble(), Json::error); - CHECK(val.asBool() == true); + EXPECT_TRUE(val.isString()); + EXPECT_EQ(strcmp(val.asCString(), "54321"), 0); + EXPECT_EQ(val.asString(), "54321"); + EXPECT_EQ(val.asInt(), 54321); + EXPECT_EQ(val.asUInt(), 54321u); + EXPECT_EQ(val.asAbsUInt(), 54321); + EXPECT_THROW(val.asDouble(), Json::error); + EXPECT_TRUE(val.asBool()); - CHECK(!val.isConvertibleTo(Json::nullValue)); - CHECK(!val.isConvertibleTo(Json::intValue)); - CHECK(!val.isConvertibleTo(Json::uintValue)); - CHECK(!val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(!val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::nullValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::intValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::uintValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // non-numeric string Json::Value val(Json::stringValue); - CHECK(val.isString()); - CHECK(val.asCString() == nullptr); - CHECK(val.asString() == ""); - CHECK_THROWS_AS(val.asInt(), std::exception); - CHECK_THROWS_AS(val.asUInt(), std::exception); - CHECK_THROWS_AS(val.asDouble(), std::exception); - CHECK(val.asBool() == false); + EXPECT_TRUE(val.isString()); + EXPECT_EQ(val.asCString(), nullptr); + EXPECT_EQ(val.asString(), ""); + EXPECT_THROW(val.asInt(), std::exception); + EXPECT_THROW(val.asUInt(), std::exception); + EXPECT_THROW(val.asAbsUInt(), std::exception); + EXPECT_THROW(val.asDouble(), std::exception); + EXPECT_TRUE(val.asBool() == false); - CHECK(val.isConvertibleTo(Json::nullValue)); - CHECK(!val.isConvertibleTo(Json::intValue)); - CHECK(!val.isConvertibleTo(Json::uintValue)); - CHECK(!val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(!val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::nullValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::intValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::uintValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // bool false Json::Value val = false; - CHECK(val.isBool()); + EXPECT_TRUE(val.isBool()); // val.asCString() should trigger an assertion failure - CHECK(val.asString() == "false"); - CHECK(val.asInt() == 0); - CHECK(val.asUInt() == 0); - CHECK(val.asDouble() == 0.0); - CHECK(val.asBool() == false); + EXPECT_EQ(val.asString(), "false"); + EXPECT_EQ(val.asInt(), 0); + EXPECT_EQ(val.asUInt(), 0); + EXPECT_EQ(val.asAbsUInt(), 0); + EXPECT_EQ(val.asDouble(), 0.0); + EXPECT_FALSE(val.asBool()); - CHECK(val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // bool true Json::Value val = true; - CHECK(val.isBool()); + EXPECT_TRUE(val.isBool()); // val.asCString() should trigger an assertion failure - CHECK(val.asString() == "true"); - CHECK(val.asInt() == 1); - CHECK(val.asUInt() == 1); - CHECK(val.asDouble() == 1.0); - CHECK(val.asBool() == true); + EXPECT_EQ(val.asString(), "true"); + EXPECT_EQ(val.asInt(), 1); + EXPECT_EQ(val.asUInt(), 1); + EXPECT_EQ(val.asAbsUInt(), 1); + EXPECT_EQ(val.asDouble(), 1.0); + EXPECT_TRUE(val.asBool()); - CHECK(!val.isConvertibleTo(Json::nullValue)); - CHECK(val.isConvertibleTo(Json::intValue)); - CHECK(val.isConvertibleTo(Json::uintValue)); - CHECK(val.isConvertibleTo(Json::realValue)); - CHECK(val.isConvertibleTo(Json::stringValue)); - CHECK(val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::nullValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::intValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::uintValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::realValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::stringValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // array type Json::Value val(Json::arrayValue); - CHECK(val.isArray()); + EXPECT_TRUE(val.isArray()); // val.asCString should trigger an assertion failure - CHECK_THROWS_AS(val.asString(), Json::error); - CHECK_THROWS_AS(val.asInt(), Json::error); - CHECK_THROWS_AS(val.asUInt(), Json::error); - CHECK_THROWS_AS(val.asDouble(), Json::error); - CHECK(val.asBool() == false); // empty or not + EXPECT_THROW(val.asString(), Json::error); + EXPECT_THROW(val.asInt(), Json::error); + EXPECT_THROW(val.asUInt(), Json::error); + EXPECT_THROW(val.asAbsUInt(), Json::error); + EXPECT_THROW(val.asDouble(), Json::error); + EXPECT_FALSE(val.asBool()); // empty or not - CHECK(val.isConvertibleTo(Json::nullValue)); - CHECK(!val.isConvertibleTo(Json::intValue)); - CHECK(!val.isConvertibleTo(Json::uintValue)); - CHECK(!val.isConvertibleTo(Json::realValue)); - CHECK(!val.isConvertibleTo(Json::stringValue)); - CHECK(!val.isConvertibleTo(Json::booleanValue)); - CHECK(val.isConvertibleTo(Json::arrayValue)); - CHECK(!val.isConvertibleTo(Json::objectValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::nullValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::intValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::uintValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::realValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::stringValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::objectValue)); } { // object type Json::Value val(Json::objectValue); - CHECK(val.isObject()); + EXPECT_TRUE(val.isObject()); // val.asCString should trigger an assertion failure - CHECK_THROWS_AS(val.asString(), Json::error); - CHECK_THROWS_AS(val.asInt(), Json::error); - CHECK_THROWS_AS(val.asUInt(), Json::error); - CHECK_THROWS_AS(val.asDouble(), Json::error); - CHECK(val.asBool() == false); // empty or not + EXPECT_THROW(val.asString(), Json::error); + EXPECT_THROW(val.asInt(), Json::error); + EXPECT_THROW(val.asUInt(), Json::error); + EXPECT_THROW(val.asAbsUInt(), Json::error); + EXPECT_THROW(val.asDouble(), Json::error); + EXPECT_FALSE(val.asBool()); // empty or not - CHECK(val.isConvertibleTo(Json::nullValue)); - CHECK(!val.isConvertibleTo(Json::intValue)); - CHECK(!val.isConvertibleTo(Json::uintValue)); - CHECK(!val.isConvertibleTo(Json::realValue)); - CHECK(!val.isConvertibleTo(Json::stringValue)); - CHECK(!val.isConvertibleTo(Json::booleanValue)); - CHECK(!val.isConvertibleTo(Json::arrayValue)); - CHECK(val.isConvertibleTo(Json::objectValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::nullValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::intValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::uintValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::realValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::stringValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::booleanValue)); + EXPECT_FALSE(val.isConvertibleTo(Json::arrayValue)); + EXPECT_TRUE(val.isConvertibleTo(Json::objectValue)); } } -TEST_CASE("access members") +TEST(json_value, access_members) { Json::Value val; - CHECK(val.type() == Json::nullValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::nullValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); { Json::Value const constVal = val; - CHECK(constVal[7u].type() == Json::nullValue); - CHECK(!constVal.isMember("key")); - CHECK(constVal["key"].type() == Json::nullValue); - CHECK(constVal.getMemberNames().empty()); - CHECK(constVal.get(1u, "default0") == "default0"); - CHECK(constVal.get(std::string("not"), "oh") == "oh"); - CHECK(constVal.get("missing", "default2") == "default2"); + EXPECT_EQ(constVal[7u].type(), Json::nullValue); + EXPECT_FALSE(constVal.isMember("key")); + EXPECT_EQ(constVal["key"].type(), Json::nullValue); + EXPECT_TRUE(constVal.getMemberNames().empty()); + EXPECT_EQ(constVal.get(1u, "default0"), "default0"); + EXPECT_EQ(constVal.get(std::string("not"), "oh"), "oh"); + EXPECT_EQ(constVal.get("missing", "default2"), "default2"); } val = -7; - CHECK(val.type() == Json::intValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::intValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); val = 42u; - CHECK(val.type() == Json::uintValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::uintValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); val = 3.14159; - CHECK(val.type() == Json::realValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::realValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); val = true; - CHECK(val.type() == Json::booleanValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::booleanValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); val = "string"; - CHECK(val.type() == Json::stringValue); - CHECK(val.size() == 0); - CHECK(!val.isValidIndex(0)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.type(), Json::stringValue); + EXPECT_EQ(val.size(), 0); + EXPECT_FALSE(val.isValidIndex(0)); + EXPECT_FALSE(val.isMember("key")); val = Json::Value(Json::objectValue); - CHECK(val.type() == Json::objectValue); - CHECK(val.size() == 0); + EXPECT_EQ(val.type(), Json::objectValue); + EXPECT_EQ(val.size(), 0); static Json::StaticString const staticThree("three"); val[staticThree] = 3; val["two"] = 2; - CHECK(val.size() == 2); - CHECK(val.isValidIndex(1)); - CHECK(!val.isValidIndex(2)); - CHECK(val[staticThree] == 3); - CHECK(val.isMember("two")); - CHECK(val.isMember(staticThree)); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.size(), 2); + EXPECT_TRUE(val.isValidIndex(1)); + EXPECT_FALSE(val.isValidIndex(2)); + EXPECT_EQ(val[staticThree], 3); + EXPECT_TRUE(val.isMember("two")); + EXPECT_TRUE(val.isMember(staticThree)); + EXPECT_FALSE(val.isMember("key")); { Json::Value const constVal = val; - CHECK(constVal["two"] == 2); - CHECK(constVal["four"].type() == Json::nullValue); - CHECK(constVal[staticThree] == 3); - CHECK(constVal.isMember("two")); - CHECK(constVal.isMember(staticThree)); - CHECK(!constVal.isMember("key")); - CHECK(val.get(std::string("two"), "backup") == 2); - CHECK(val.get("missing", "default2") == "default2"); + EXPECT_EQ(constVal["two"], 2); + EXPECT_EQ(constVal["four"].type(), Json::nullValue); + EXPECT_EQ(constVal[staticThree], 3); + EXPECT_TRUE(constVal.isMember("two")); + EXPECT_TRUE(constVal.isMember(staticThree)); + EXPECT_FALSE(constVal.isMember("key")); + EXPECT_EQ(val.get(std::string("two"), "backup"), 2); + EXPECT_EQ(val.get("missing", "default2"), "default2"); } val = Json::Value(Json::arrayValue); - CHECK(val.type() == Json::arrayValue); - CHECK(val.size() == 0); + EXPECT_EQ(val.type(), Json::arrayValue); + EXPECT_EQ(val.size(), 0); val[0u] = "zero"; val[1u] = "one"; - CHECK(val.size() == 2); - CHECK(val.isValidIndex(1)); - CHECK(!val.isValidIndex(2)); - CHECK(val[20u].type() == Json::nullValue); - CHECK(!val.isMember("key")); + EXPECT_EQ(val.size(), 2); + EXPECT_TRUE(val.isValidIndex(1)); + EXPECT_FALSE(val.isValidIndex(2)); + EXPECT_EQ(val[20u].type(), Json::nullValue); + EXPECT_FALSE(val.isMember("key")); { Json::Value const constVal = val; - CHECK(constVal[0u] == "zero"); - CHECK(constVal[2u].type() == Json::nullValue); - CHECK(!constVal.isMember("key")); - CHECK(val.get(1u, "default0") == "one"); - CHECK(val.get(3u, "default1") == "default1"); + EXPECT_EQ(constVal[0u], "zero"); + EXPECT_EQ(constVal[2u].type(), Json::nullValue); + EXPECT_FALSE(constVal.isMember("key")); + EXPECT_EQ(val.get(1u, "default0"), "one"); + EXPECT_EQ(val.get(3u, "default1"), "default1"); } } -TEST_CASE("remove members") +TEST(json_value, remove_members) { Json::Value val; - CHECK(val.removeMember(std::string("member")).type() == Json::nullValue); + EXPECT_EQ(val.removeMember(std::string("member")).type(), Json::nullValue); val = Json::Value(Json::objectValue); static Json::StaticString const staticThree("three"); val[staticThree] = 3; val["two"] = 2; - CHECK(val.size() == 2); + EXPECT_EQ(val.size(), 2); - CHECK(val.removeMember(std::string("six")).type() == Json::nullValue); - CHECK(val.size() == 2); + EXPECT_EQ(val.removeMember(std::string("six")).type(), Json::nullValue); + EXPECT_EQ(val.size(), 2); - CHECK(val.removeMember(staticThree) == 3); - CHECK(val.size() == 1); + EXPECT_EQ(val.removeMember(staticThree), 3); + EXPECT_EQ(val.size(), 1); - CHECK(val.removeMember(staticThree).type() == Json::nullValue); - CHECK(val.size() == 1); + EXPECT_EQ(val.removeMember(staticThree).type(), Json::nullValue); + EXPECT_EQ(val.size(), 1); - CHECK(val.removeMember(std::string("two")) == 2); - CHECK(val.size() == 0); + EXPECT_EQ(val.removeMember(std::string("two")), 2); + EXPECT_EQ(val.size(), 0); - CHECK(val.removeMember(std::string("two")).type() == Json::nullValue); - CHECK(val.size() == 0); + EXPECT_EQ(val.removeMember(std::string("two")).type(), Json::nullValue); + EXPECT_EQ(val.size(), 0); } -TEST_CASE("iterator") +TEST(json_value, iterator) { { // Iterating an array. @@ -1143,27 +1202,27 @@ TEST_CASE("iterator") Json::ValueIterator i2 = e; --i2; - // key(), index(), and memberName() on an object iterator. - CHECK(b != e); - CHECK(!(b == e)); - CHECK(i1.key() == 0); - CHECK(i2.key() == 3); - CHECK(i1.index() == 0); - CHECK(i2.index() == 3); - CHECK(std::strcmp(i1.memberName(), "") == 0); - CHECK(std::strcmp(i2.memberName(), "") == 0); + // key(), index(), and memberName() on an array iterator. + EXPECT_TRUE(b != e); + EXPECT_FALSE(b == e); + EXPECT_EQ(i1.key(), 0); + EXPECT_EQ(i2.key(), 3); + EXPECT_EQ(i1.index(), 0); + EXPECT_EQ(i2.index(), 3); + EXPECT_STREQ(i1.memberName(), ""); + EXPECT_STREQ(i2.memberName(), ""); // Pre and post increment and decrement. *i1++ = "0"; - CHECK(*i1 == "one"); + EXPECT_EQ(*i1, "one"); *i1 = "1"; ++i1; *i2-- = "3"; - CHECK(*i2 == "two"); - CHECK(i1 == i2); + EXPECT_EQ(*i2, "two"); + EXPECT_EQ(i1, i2); *i2 = "2"; - CHECK(*i1 == "2"); + EXPECT_EQ(*i1, "2"); } { // Iterating a const object. @@ -1181,38 +1240,38 @@ TEST_CASE("iterator") --i2; // key(), index(), and memberName() on an object iterator. - CHECK(i1 != i2); - CHECK(!(i1 == i2)); - CHECK(i1.key() == "0"); - CHECK(i2.key() == "3"); - CHECK(i1.index() == -1); - CHECK(i2.index() == -1); - CHECK(std::strcmp(i1.memberName(), "0") == 0); - CHECK(std::strcmp(i2.memberName(), "3") == 0); + EXPECT_TRUE(i1 != i2); + EXPECT_FALSE(i1 == i2); + EXPECT_EQ(i1.key(), "0"); + EXPECT_EQ(i2.key(), "3"); + EXPECT_EQ(i1.index(), -1); + EXPECT_EQ(i2.index(), -1); + EXPECT_STREQ(i1.memberName(), "0"); + EXPECT_STREQ(i2.memberName(), "3"); // Pre and post increment and decrement. - CHECK(*i1++ == 0); - CHECK(*i1 == 1); + EXPECT_EQ(*i1++, 0); + EXPECT_EQ(*i1, 1); ++i1; - CHECK(*i2-- == 3); - CHECK(*i2 == 2); - CHECK(i1 == i2); - CHECK(*i1 == 2); + EXPECT_EQ(*i2--, 3); + EXPECT_EQ(*i2, 2); + EXPECT_EQ(i1, i2); + EXPECT_EQ(*i1, 2); } { // Iterating a non-const null object. Json::Value nul{}; - CHECK(nul.begin() == nul.end()); + EXPECT_EQ(nul.begin(), nul.end()); } { // Iterating a const Int. Json::Value const i{-3}; - CHECK(i.begin() == i.end()); + EXPECT_EQ(i.begin(), i.end()); } } -TEST_CASE("nest limits") +TEST(json_value, nest_limits) { Json::Reader r; { @@ -1230,14 +1289,14 @@ TEST_CASE("nest limits") // Within object nest limit auto json{nest(std::min(10u, Json::Reader::nest_limit))}; Json::Value j; - CHECK(r.parse(json, j)); + EXPECT_TRUE(r.parse(json, j)); } { // Exceed object nest limit auto json{nest(Json::Reader::nest_limit + 1)}; Json::Value j; - CHECK(!r.parse(json, j)); + EXPECT_FALSE(r.parse(json, j)); } } @@ -1254,41 +1313,39 @@ TEST_CASE("nest limits") // Exceed array nest limit auto json{nest(Json::Reader::nest_limit + 1)}; Json::Value j; - CHECK(!r.parse(json, j)); + EXPECT_FALSE(r.parse(json, j)); } } -TEST_CASE("memory leak") +TEST(json_value, memory_leak) { // When run with the address sanitizer, this test confirms there is no // memory leak with the scenarios below. { Json::Value a; a[0u] = 1; - CHECK(a.type() == Json::arrayValue); - CHECK(a[0u].type() == Json::intValue); + EXPECT_EQ(a.type(), Json::arrayValue); + EXPECT_EQ(a[0u].type(), Json::intValue); a = std::move(a[0u]); - CHECK(a.type() == Json::intValue); + EXPECT_EQ(a.type(), Json::intValue); } { Json::Value b; Json::Value temp; temp["a"] = "Probably avoids the small string optimization"; temp["b"] = "Also probably avoids the small string optimization"; - CHECK(temp.type() == Json::objectValue); + EXPECT_EQ(temp.type(), Json::objectValue); b.append(temp); - CHECK(temp.type() == Json::objectValue); - CHECK(b.size() == 1); + EXPECT_EQ(temp.type(), Json::objectValue); + EXPECT_EQ(b.size(), 1); b.append(std::move(temp)); - CHECK(b.size() == 2); + EXPECT_EQ(b.size(), 2); // Note that the type() == nullValue check is implementation // specific and not guaranteed to be valid in the future. - CHECK(temp.type() == Json::nullValue); + EXPECT_EQ(temp.type(), Json::nullValue); } } -TEST_SUITE_END(); - -} // namespace ripple +} // namespace xrpl diff --git a/src/tests/libxrpl/json/Writer.cpp b/src/tests/libxrpl/json/Writer.cpp index 59251aaf60..54c3221858 100644 --- a/src/tests/libxrpl/json/Writer.cpp +++ b/src/tests/libxrpl/json/Writer.cpp @@ -1,41 +1,22 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include #include +#include #include #include -using namespace ripple; +using namespace xrpl; using namespace Json; -TEST_SUITE_BEGIN("JsonWriter"); - -struct WriterFixture +class WriterFixture : public ::testing::Test { +protected: std::string output; std::unique_ptr writer; - WriterFixture() + void + SetUp() override { writer = std::make_unique(stringOutput(output)); } @@ -50,7 +31,7 @@ struct WriterFixture void expectOutput(std::string const& expected) const { - CHECK(output == expected); + EXPECT_EQ(output, expected); } void @@ -61,20 +42,20 @@ struct WriterFixture } }; -TEST_CASE_FIXTURE(WriterFixture, "trivial") +TEST_F(WriterFixture, trivial) { - CHECK(output.empty()); + EXPECT_TRUE(output.empty()); checkOutputAndReset(""); } -TEST_CASE_FIXTURE(WriterFixture, "near trivial") +TEST_F(WriterFixture, near_trivial) { - CHECK(output.empty()); + EXPECT_TRUE(output.empty()); writer->output(0); checkOutputAndReset("0"); } -TEST_CASE_FIXTURE(WriterFixture, "primitives") +TEST_F(WriterFixture, primitives) { writer->output(true); checkOutputAndReset("true"); @@ -98,7 +79,7 @@ TEST_CASE_FIXTURE(WriterFixture, "primitives") checkOutputAndReset("null"); } -TEST_CASE_FIXTURE(WriterFixture, "empty") +TEST_F(WriterFixture, empty) { writer->startRoot(Writer::array); writer->finish(); @@ -109,7 +90,7 @@ TEST_CASE_FIXTURE(WriterFixture, "empty") checkOutputAndReset("{}"); } -TEST_CASE_FIXTURE(WriterFixture, "escaping") +TEST_F(WriterFixture, escaping) { writer->output("\\"); checkOutputAndReset(R"("\\")"); @@ -127,7 +108,7 @@ TEST_CASE_FIXTURE(WriterFixture, "escaping") checkOutputAndReset(R"("\b\f\n\r\t")"); } -TEST_CASE_FIXTURE(WriterFixture, "array") +TEST_F(WriterFixture, array) { writer->startRoot(Writer::array); writer->append(12); @@ -135,7 +116,7 @@ TEST_CASE_FIXTURE(WriterFixture, "array") checkOutputAndReset("[12]"); } -TEST_CASE_FIXTURE(WriterFixture, "long array") +TEST_F(WriterFixture, long_array) { writer->startRoot(Writer::array); writer->append(12); @@ -145,7 +126,7 @@ TEST_CASE_FIXTURE(WriterFixture, "long array") checkOutputAndReset(R"([12,true,"hello"])"); } -TEST_CASE_FIXTURE(WriterFixture, "embedded array simple") +TEST_F(WriterFixture, embedded_array_simple) { writer->startRoot(Writer::array); writer->startAppend(Writer::array); @@ -154,7 +135,7 @@ TEST_CASE_FIXTURE(WriterFixture, "embedded array simple") checkOutputAndReset("[[]]"); } -TEST_CASE_FIXTURE(WriterFixture, "object") +TEST_F(WriterFixture, object) { writer->startRoot(Writer::object); writer->set("hello", "world"); @@ -162,7 +143,7 @@ TEST_CASE_FIXTURE(WriterFixture, "object") checkOutputAndReset(R"({"hello":"world"})"); } -TEST_CASE_FIXTURE(WriterFixture, "complex object") +TEST_F(WriterFixture, complex_object) { writer->startRoot(Writer::object); writer->set("hello", "world"); @@ -175,11 +156,10 @@ TEST_CASE_FIXTURE(WriterFixture, "complex object") writer->startSet(Writer::array, "subarray"); writer->append(23.5); writer->finishAll(); - checkOutputAndReset( - R"({"hello":"world","array":[true,12,[{"goodbye":"cruel world.","subarray":[23.5]}]]})"); + checkOutputAndReset(R"({"hello":"world","array":[true,12,[{"goodbye":"cruel world.","subarray":[23.5]}]]})"); } -TEST_CASE_FIXTURE(WriterFixture, "json value") +TEST_F(WriterFixture, json_value) { Json::Value value(Json::objectValue); value["foo"] = 23; @@ -188,5 +168,3 @@ TEST_CASE_FIXTURE(WriterFixture, "json value") writer->finish(); checkOutputAndReset(R"({"hello":{"foo":23}})"); } - -TEST_SUITE_END(); diff --git a/src/tests/libxrpl/json/main.cpp b/src/tests/libxrpl/json/main.cpp index 0a3f254ea8..5142bbe08a 100644 --- a/src/tests/libxrpl/json/main.cpp +++ b/src/tests/libxrpl/json/main.cpp @@ -1,2 +1,8 @@ -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include +#include + +int +main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/tests/libxrpl/net/HTTPClient.cpp b/src/tests/libxrpl/net/HTTPClient.cpp index 4d50c47220..72a351f9b7 100644 --- a/src/tests/libxrpl/net/HTTPClient.cpp +++ b/src/tests/libxrpl/net/HTTPClient.cpp @@ -1,38 +1,26 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include +#include +#include #include +#include +#include #include #include #include -#include +#include +#include #include #include +#include +#include #include -using namespace ripple; +using namespace xrpl; namespace { @@ -43,16 +31,19 @@ private: boost::asio::io_context ioc_; boost::asio::ip::tcp::acceptor acceptor_; boost::asio::ip::tcp::endpoint endpoint_; - std::atomic running_{true}; + bool running_{true}; + bool finished_{false}; unsigned short port_; // Custom headers to return - std::map custom_headers_; - std::string response_body_; - unsigned int status_code_{200}; + std::map customHeaders_; + std::string responseBody_; + unsigned int statusCode_{200}; + + beast::Journal j_; public: - TestHTTPServer() : acceptor_(ioc_), port_(0) + TestHTTPServer() : acceptor_(ioc_), port_(0), j_(TestSink::instance()) { // Bind to any available port endpoint_ = {boost::asio::ip::tcp::v4(), 0}; @@ -64,12 +55,17 @@ public: // Get the actual port that was assigned port_ = acceptor_.local_endpoint().port(); - accept(); + // Start the accept coroutine + boost::asio::co_spawn(ioc_, accept(), boost::asio::detached); } + TestHTTPServer(TestHTTPServer&&) = delete; + TestHTTPServer& + operator=(TestHTTPServer&&) = delete; + ~TestHTTPServer() { - stop(); + XRPL_ASSERT(finished(), "xrpl::TestHTTPServer::~TestHTTPServer : accept future ready"); } boost::asio::io_context& @@ -87,22 +83,21 @@ public: void setHeader(std::string const& name, std::string const& value) { - custom_headers_[name] = value; + customHeaders_[name] = value; } void setResponseBody(std::string const& body) { - response_body_ = body; + responseBody_ = body; } void setStatusCode(unsigned int code) { - status_code_ = code; + statusCode_ = code; } -private: void stop() { @@ -110,78 +105,80 @@ private: acceptor_.close(); } - void - accept() + bool + finished() const { - if (!running_) - return; - - acceptor_.async_accept( - ioc_, - endpoint_, - [&](boost::system::error_code const& error, - boost::asio::ip::tcp::socket peer) { - if (!running_) - return; - - if (!error) - { - handleConnection(std::move(peer)); - } - }); + return finished_; } - void +private: + boost::asio::awaitable + accept() + { + while (running_) + { + try + { + auto socket = co_await acceptor_.async_accept(boost::asio::use_awaitable); + + if (!running_) + break; + + // Handle this connection + co_await handleConnection(std::move(socket)); + } + catch (std::exception const& e) + { + // Accept or handle failed, stop accepting + JLOG(j_.debug()) << "Error: " << e.what(); + break; + } + } + + finished_ = true; + } + + boost::asio::awaitable handleConnection(boost::asio::ip::tcp::socket socket) { try { - // Read the HTTP request boost::beast::flat_buffer buffer; boost::beast::http::request req; - boost::beast::http::read(socket, buffer, req); + + // Read the HTTP request asynchronously + co_await boost::beast::http::async_read(socket, buffer, req, boost::asio::use_awaitable); // Create response boost::beast::http::response res; res.version(req.version()); - res.result(status_code_); + res.result(statusCode_); res.set(boost::beast::http::field::server, "TestServer"); - // Add custom headers - for (auto const& [name, value] : custom_headers_) + // Set body and prepare payload first + res.body() = responseBody_; + res.prepare_payload(); + + // Override Content-Length with custom headers after + // prepare_payload. This allows us to test case-insensitive + // header parsing. + for (auto const& [name, value] : customHeaders_) { res.set(name, value); } - // Set body and prepare payload first - res.body() = response_body_; - res.prepare_payload(); - - // Override Content-Length with custom headers after prepare_payload - // This allows us to test case-insensitive header parsing - for (auto const& [name, value] : custom_headers_) - { - if (boost::iequals(name, "Content-Length")) - { - res.erase(boost::beast::http::field::content_length); - res.set(name, value); - } - } - - // Send response - boost::beast::http::write(socket, res); + // Send response asynchronously + co_await boost::beast::http::async_write(socket, res, boost::asio::use_awaitable); // Shutdown socket gracefully - boost::system::error_code ec; - socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); + boost::system::error_code shutdownEc; + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, shutdownEc); } - catch (std::exception const&) + catch (std::exception const& e) { - // Connection handling errors are expected + // Error reading or writing, just close the connection + JLOG(j_.debug()) << "Connection error: " << e.what(); } - - if (running_) - accept(); } }; @@ -190,13 +187,13 @@ bool runHTTPTest( TestHTTPServer& server, std::string const& path, - std::atomic& completed, - std::atomic& result_status, - std::string& result_data, - boost::system::error_code& result_error) + bool& completed, + int& resultStatus, + std::string& resultData, + boost::system::error_code& resultError) { // Create a null journal for testing - beast::Journal j{beast::Journal::getNullSink()}; + beast::Journal j{TestSink::instance()}; // Initialize HTTPClient SSL context HTTPClient::initializeSSLContext("", "", false, j); @@ -209,12 +206,10 @@ runHTTPTest( path, 1024, // max response size std::chrono::seconds(5), - [&](boost::system::error_code const& ec, - int status, - std::string const& data) -> bool { - result_error = ec; - result_status = status; - result_data = data; + [&](boost::system::error_code const& ec, int status, std::string const& data) -> bool { + resultError = ec; + resultStatus = status; + resultData = data; completed = true; return false; // don't retry }, @@ -222,13 +217,17 @@ runHTTPTest( // Run the IO context until completion auto start = std::chrono::steady_clock::now(); - while (!completed && - std::chrono::steady_clock::now() - start < std::chrono::seconds(10)) + while (server.ioc().run_one() != 0) { - if (server.ioc().run_one() == 0) + if (std::chrono::steady_clock::now() - start >= std::chrono::seconds(10) || server.finished()) { break; } + + if (completed) + { + server.stop(); + } } return completed; @@ -236,10 +235,10 @@ runHTTPTest( } // anonymous namespace -TEST_CASE("HTTPClient case insensitive Content-Length") +TEST(HTTPClient, case_insensitive_content_length) { // Test different cases of Content-Length header - std::vector header_cases = { + std::vector headerCases = { "Content-Length", // Standard case "content-length", // Lowercase - this tests the regex icase fix "CONTENT-LENGTH", // Uppercase @@ -247,100 +246,86 @@ TEST_CASE("HTTPClient case insensitive Content-Length") "content-Length" // Mixed case 2 }; - for (auto const& header_name : header_cases) + for (auto const& headerName : headerCases) { TestHTTPServer server; - std::string test_body = "Hello World!"; - server.setResponseBody(test_body); - server.setHeader(header_name, std::to_string(test_body.size())); + std::string testBody = "Hello World!"; + server.setResponseBody(testBody); + server.setHeader(headerName, std::to_string(testBody.size())); - std::atomic completed{false}; - std::atomic result_status{0}; - std::string result_data; - boost::system::error_code result_error; + bool completed{false}; + int resultStatus{0}; + std::string resultData; + boost::system::error_code resultError; - bool test_completed = runHTTPTest( - server, - "/test", - completed, - result_status, - result_data, - result_error); + bool testCompleted = runHTTPTest(server, "/test", completed, resultStatus, resultData, resultError); // Verify results - CHECK(test_completed); - CHECK(!result_error); - CHECK(result_status == 200); - CHECK(result_data == test_body); + EXPECT_TRUE(testCompleted); + EXPECT_FALSE(resultError); + EXPECT_EQ(resultStatus, 200); + EXPECT_EQ(resultData, testBody); } } -TEST_CASE("HTTPClient basic HTTP request") +TEST(HTTPClient, basic_http_request) { TestHTTPServer server; - std::string test_body = "Test response body"; - server.setResponseBody(test_body); + std::string testBody = "Test response body"; + server.setResponseBody(testBody); server.setHeader("Content-Type", "text/plain"); - std::atomic completed{false}; - std::atomic result_status{0}; - std::string result_data; - boost::system::error_code result_error; + bool completed{false}; + int resultStatus{0}; + std::string resultData; + boost::system::error_code resultError; - bool test_completed = runHTTPTest( - server, "/basic", completed, result_status, result_data, result_error); + bool testCompleted = runHTTPTest(server, "/basic", completed, resultStatus, resultData, resultError); - CHECK(test_completed); - CHECK(!result_error); - CHECK(result_status == 200); - CHECK(result_data == test_body); + EXPECT_TRUE(testCompleted); + EXPECT_FALSE(resultError); + EXPECT_EQ(resultStatus, 200); + EXPECT_EQ(resultData, testBody); } -TEST_CASE("HTTPClient empty response") +TEST(HTTPClient, empty_response) { TestHTTPServer server; server.setResponseBody(""); // Empty body server.setHeader("Content-Length", "0"); - std::atomic completed{false}; - std::atomic result_status{0}; - std::string result_data; - boost::system::error_code result_error; + bool completed{false}; + int resultStatus{0}; + std::string resultData; + boost::system::error_code resultError; - bool test_completed = runHTTPTest( - server, "/empty", completed, result_status, result_data, result_error); + bool testCompleted = runHTTPTest(server, "/empty", completed, resultStatus, resultData, resultError); - CHECK(test_completed); - CHECK(!result_error); - CHECK(result_status == 200); - CHECK(result_data.empty()); + EXPECT_TRUE(testCompleted); + EXPECT_FALSE(resultError); + EXPECT_EQ(resultStatus, 200); + EXPECT_TRUE(resultData.empty()); } -TEST_CASE("HTTPClient different status codes") +TEST(HTTPClient, different_status_codes) { - std::vector status_codes = {200, 404, 500}; + std::vector statusCodes = {200, 404, 500}; - for (auto status : status_codes) + for (auto status : statusCodes) { TestHTTPServer server; server.setStatusCode(status); server.setResponseBody("Status " + std::to_string(status)); - std::atomic completed{false}; - std::atomic result_status{0}; - std::string result_data; - boost::system::error_code result_error; + bool completed{false}; + int resultStatus{0}; + std::string resultData; + boost::system::error_code resultError; - bool test_completed = runHTTPTest( - server, - "/status", - completed, - result_status, - result_data, - result_error); + bool testCompleted = runHTTPTest(server, "/status", completed, resultStatus, resultData, resultError); - CHECK(test_completed); - CHECK(!result_error); - CHECK(result_status == static_cast(status)); + EXPECT_TRUE(testCompleted); + EXPECT_FALSE(resultError); + EXPECT_EQ(resultStatus, static_cast(status)); } } diff --git a/src/tests/libxrpl/net/main.cpp b/src/tests/libxrpl/net/main.cpp index be9fc14bbf..5142bbe08a 100644 --- a/src/tests/libxrpl/net/main.cpp +++ b/src/tests/libxrpl/net/main.cpp @@ -1,21 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2024 Ripple Labs Inc. +#include - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include +int +main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/xrpld/app/consensus/RCLCensorshipDetector.h b/src/xrpld/app/consensus/RCLCensorshipDetector.h index f291c6c31b..fbdc6c2397 100644 --- a/src/xrpld/app/consensus/RCLCensorshipDetector.h +++ b/src/xrpld/app/consensus/RCLCensorshipDetector.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUS_RCLCENSORSHIPDETECTOR_H_INCLUDED -#define RIPPLE_APP_CONSENSUS_RCLCENSORSHIPDETECTOR_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { template class RCLCensorshipDetector @@ -38,8 +18,7 @@ public: TxID txid; Sequence seq; - TxIDSeq(TxID const& txid_, Sequence const& seq_) - : txid(txid_), seq(seq_) + TxIDSeq(TxID const& txid_, Sequence const& seq_) : txid(txid_), seq(seq_) { } }; @@ -141,6 +120,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 292ba7d483..35f8eec1a3 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -49,7 +30,7 @@ #include #include -namespace ripple { +namespace xrpl { RCLConsensus::RCLConsensus( Application& app, @@ -60,14 +41,7 @@ RCLConsensus::RCLConsensus( Consensus::clock_type const& clock, ValidatorKeys const& validatorKeys, beast::Journal journal) - : adaptor_( - app, - std::move(feeVote), - ledgerMaster, - localTxs, - inboundTransactions, - validatorKeys, - journal) + : adaptor_(app, std::move(feeVote), ledgerMaster, localTxs, inboundTransactions, validatorKeys, journal) , consensus_(clock, adaptor_, journal) , j_(journal) { @@ -88,36 +62,25 @@ RCLConsensus::Adaptor::Adaptor( , inboundTransactions_{inboundTransactions} , j_(journal) , validatorKeys_(validatorKeys) - , valCookie_( - 1 + - rand_int( - crypto_prng(), - std::numeric_limits::max() - 1)) + , valCookie_(1 + rand_int(crypto_prng(), std::numeric_limits::max() - 1)) , nUnlVote_(validatorKeys_.nodeID, j_) { - XRPL_ASSERT( - valCookie_, "ripple::RCLConsensus::Adaptor::Adaptor : nonzero cookie"); + XRPL_ASSERT(valCookie_, "xrpl::RCLConsensus::Adaptor::Adaptor : nonzero cookie"); - JLOG(j_.info()) << "Consensus engine started (cookie: " + - std::to_string(valCookie_) + ")"; + JLOG(j_.info()) << "Consensus engine started (cookie: " + std::to_string(valCookie_) + ")"; if (validatorKeys_.nodeID != beast::zero && validatorKeys_.keys) { std::stringstream ss; JLOG(j_.info()) << "Validator identity: " - << toBase58( - TokenType::NodePublic, - validatorKeys_.keys->masterPublicKey); + << toBase58(TokenType::NodePublic, validatorKeys_.keys->masterPublicKey); - if (validatorKeys_.keys->masterPublicKey != - validatorKeys_.keys->publicKey) + if (validatorKeys_.keys->masterPublicKey != validatorKeys_.keys->publicKey) { - JLOG(j_.debug()) - << "Validator ephemeral signing key: " - << toBase58( - TokenType::NodePublic, validatorKeys_.keys->publicKey) - << " (seq: " << std::to_string(validatorKeys_.sequence) << ")"; + JLOG(j_.debug()) << "Validator ephemeral signing key: " + << toBase58(TokenType::NodePublic, validatorKeys_.keys->publicKey) + << " (seq: " << std::to_string(validatorKeys_.sequence) << ")"; } } } @@ -137,28 +100,20 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash) // Tell the ledger acquire system that we need the consensus ledger acquiringLedger_ = hash; - app_.getJobQueue().addJob( - jtADVANCE, - "getConsensusLedger1", - [id = hash, &app = app_, this]() { - JLOG(j_.debug()) - << "JOB advanceLedger getConsensusLedger1 started"; - app.getInboundLedgers().acquireAsync( - id, 0, InboundLedger::Reason::CONSENSUS); - }); + app_.getJobQueue().addJob(jtADVANCE, "GetConsL1", [id = hash, &app = app_, this]() { + JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger1 started"; + app.getInboundLedgers().acquireAsync(id, 0, InboundLedger::Reason::CONSENSUS); + }); } return std::nullopt; } XRPL_ASSERT( - !built->open() && built->isImmutable(), - "ripple::RCLConsensus::Adaptor::acquireLedger : valid ledger state"); - XRPL_ASSERT( - built->info().hash == hash, - "ripple::RCLConsensus::Adaptor::acquireLedger : ledger hash match"); + !built->open() && built->isImmutable(), "xrpl::RCLConsensus::Adaptor::acquireLedger : valid ledger state"); + XRPL_ASSERT(built->header().hash == hash, "xrpl::RCLConsensus::Adaptor::acquireLedger : ledger hash match"); // Notify inbound transactions of the new ledger sequence number - inboundTransactions_.newRound(built->info().seq); + inboundTransactions_.newRound(built->header().seq); return RCLCxLedger(built); } @@ -173,10 +128,8 @@ RCLConsensus::Adaptor::share(RCLCxPeerPos const& peerPos) prop.set_proposeseq(proposal.proposeSeq()); prop.set_closetime(proposal.closeTime().time_since_epoch().count()); - prop.set_currenttxhash( - proposal.position().begin(), proposal.position().size()); - prop.set_previousledger( - proposal.prevLedger().begin(), proposal.position().size()); + prop.set_currenttxhash(proposal.position().begin(), proposal.position().size()); + prop.set_previousledger(proposal.prevLedger().begin(), proposal.position().size()); auto const pk = peerPos.publicKey().slice(); prop.set_nodepubkey(pk.data(), pk.size()); @@ -198,8 +151,7 @@ RCLConsensus::Adaptor::share(RCLCxTx const& tx) protocol::TMTransaction msg; msg.set_rawtransaction(slice.data(), slice.size()); msg.set_status(protocol::tsNEW); - msg.set_receivetimestamp( - app_.timeKeeper().now().time_since_epoch().count()); + msg.set_receivetimestamp(app_.timeKeeper().now().time_since_epoch().count()); static std::set skip{}; app_.overlay().relay(tx.id(), msg, skip); } @@ -212,15 +164,12 @@ void RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal) { JLOG(j_.trace()) << (proposal.isBowOut() ? "We bow out: " : "We propose: ") - << ripple::to_string(proposal.prevLedger()) << " -> " - << ripple::to_string(proposal.position()); + << xrpl::to_string(proposal.prevLedger()) << " -> " << xrpl::to_string(proposal.position()); protocol::TMProposeSet prop; - prop.set_currenttxhash( - proposal.position().begin(), proposal.position().size()); - prop.set_previousledger( - proposal.prevLedger().begin(), proposal.prevLedger().size()); + prop.set_currenttxhash(proposal.position().begin(), proposal.position().size()); + prop.set_previousledger(proposal.prevLedger().begin(), proposal.prevLedger().size()); prop.set_proposeseq(proposal.proposeSeq()); prop.set_closetime(proposal.closeTime().time_since_epoch().count()); @@ -235,18 +184,12 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal) prop.set_nodepubkey(keys.publicKey.data(), keys.publicKey.size()); - auto sig = - signDigest(keys.publicKey, keys.secretKey, proposal.signingHash()); + auto sig = signDigest(keys.publicKey, keys.secretKey, proposal.signingHash()); prop.set_signature(sig.data(), sig.size()); auto const suppression = proposalUniqueId( - proposal.position(), - proposal.prevLedger(), - proposal.proposeSeq(), - proposal.closeTime(), - keys.publicKey, - sig); + proposal.position(), proposal.prevLedger(), proposal.proposeSeq(), proposal.closeTime(), keys.publicKey, sig); app_.getHashRouter().addSuppression(suppression); @@ -282,25 +225,18 @@ RCLConsensus::Adaptor::proposersValidated(LedgerHash const& h) const } std::size_t -RCLConsensus::Adaptor::proposersFinished( - RCLCxLedger const& ledger, - LedgerHash const& h) const +RCLConsensus::Adaptor::proposersFinished(RCLCxLedger const& ledger, LedgerHash const& h) const { RCLValidations& vals = app_.getValidations(); - return vals.getNodesAfter( - RCLValidatedLedger(ledger.ledger_, vals.adaptor().journal()), h); + return vals.getNodesAfter(RCLValidatedLedger(ledger.ledger_, vals.adaptor().journal()), h); } uint256 -RCLConsensus::Adaptor::getPrevLedger( - uint256 ledgerID, - RCLCxLedger const& ledger, - ConsensusMode mode) +RCLConsensus::Adaptor::getPrevLedger(uint256 ledgerID, RCLCxLedger const& ledger, ConsensusMode mode) { RCLValidations& vals = app_.getValidations(); uint256 netLgr = vals.getPreferred( - RCLValidatedLedger{ledger.ledger_, vals.adaptor().journal()}, - ledgerMaster_.getValidLedgerIndex()); + RCLValidatedLedger{ledger.ledger_, vals.adaptor().journal()}, ledgerMaster_.getValidLedgerIndex()); if (netLgr != ledgerID) { @@ -314,10 +250,8 @@ RCLConsensus::Adaptor::getPrevLedger( } auto -RCLConsensus::Adaptor::onClose( - RCLCxLedger const& ledger, - NetClock::time_point const& closeTime, - ConsensusMode mode) -> Result +RCLConsensus::Adaptor::onClose(RCLCxLedger const& ledger, NetClock::time_point const& closeTime, ConsensusMode mode) + -> Result { bool const wrongLCL = mode == ConsensusMode::wrongLedger; bool const proposing = mode == ConsensusMode::proposing; @@ -328,24 +262,20 @@ RCLConsensus::Adaptor::onClose( ledgerMaster_.applyHeldTransactions(); // Tell the ledger master not to acquire the ledger we're probably building - ledgerMaster_.setBuildingLedger(prevLedger->info().seq + 1); + ledgerMaster_.setBuildingLedger(prevLedger->header().seq + 1); auto initialLedger = app_.openLedger().current(); - auto initialSet = - std::make_shared(SHAMapType::TRANSACTION, app_.getNodeFamily()); + auto initialSet = std::make_shared(SHAMapType::TRANSACTION, app_.getNodeFamily()); initialSet->setUnbacked(); // Build SHAMap containing all transactions in our open ledger for (auto const& tx : initialLedger->txs) { - JLOG(j_.trace()) << "Adding open ledger TX " - << tx.first->getTransactionID(); + JLOG(j_.trace()) << "Adding open ledger TX " << tx.first->getTransactionID(); Serializer s(2048); tx.first->add(s); - initialSet->addItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(tx.first->getTransactionID(), s.slice())); + initialSet->addItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(tx.first->getTransactionID(), s.slice())); } // Add pseudo-transactions to the set @@ -356,27 +286,19 @@ RCLConsensus::Adaptor::onClose( // previous ledger was flag ledger, add fee and amendment // pseudo-transactions auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger( - prevLedger->info().parentHash, prevLedger->seq() - 1)); + app_.getValidations().getTrustedForLedger(prevLedger->header().parentHash, prevLedger->seq() - 1)); if (validations.size() >= app_.validators().quorum()) { feeVote_->doVoting(prevLedger, validations, initialSet); - app_.getAmendmentTable().doVoting( - prevLedger, validations, initialSet, j_); + app_.getAmendmentTable().doVoting(prevLedger, validations, initialSet, j_); } } - else if ( - prevLedger->isVotingLedger() && - prevLedger->rules().enabled(featureNegativeUNL)) + else if (prevLedger->isVotingLedger()) { // previous ledger was a voting ledger, // so the current consensus session is for a flag ledger, // add negative UNL pseudo-transactions - nUnlVote_.doVoting( - prevLedger, - app_.validators().getTrustedMasterKeys(), - app_.getValidations(), - initialSet); + nUnlVote_.doVoting(prevLedger, app_.validators().getTrustedMasterKeys(), app_.getValidations(), initialSet); } } @@ -385,14 +307,12 @@ RCLConsensus::Adaptor::onClose( if (!wrongLCL) { - LedgerIndex const seq = prevLedger->info().seq + 1; + LedgerIndex const seq = prevLedger->header().seq + 1; RCLCensorshipDetector::TxIDSeqVec proposed; - initialSet->visitLeaves( - [&proposed, - seq](boost::intrusive_ptr const& item) { - proposed.emplace_back(item->key(), seq); - }); + initialSet->visitLeaves([&proposed, seq](boost::intrusive_ptr const& item) { + proposed.emplace_back(item->key(), seq); + }); censorshipDetector_.propose(std::move(proposed)); } @@ -403,7 +323,7 @@ RCLConsensus::Adaptor::onClose( return Result{ std::move(initialSet), RCLCxPeerPos::Proposal{ - initialLedger->info().parentHash, + initialLedger->header().parentHash, RCLCxPeerPos::Proposal::seqJoin, setHash, closeTime, @@ -420,13 +340,7 @@ RCLConsensus::Adaptor::onForceAccept( ConsensusMode const& mode, Json::Value&& consensusJson) { - doAccept( - result, - prevLedger, - closeResolution, - rawCloseTimes, - mode, - std::move(consensusJson)); + doAccept(result, prevLedger, closeResolution, rawCloseTimes, mode, std::move(consensusJson)); } void @@ -439,25 +353,16 @@ RCLConsensus::Adaptor::onAccept( Json::Value&& consensusJson, bool const validating) { - app_.getJobQueue().addJob( - jtACCEPT, - "acceptLedger", - [=, this, cj = std::move(consensusJson)]() mutable { - // Note that no lock is held or acquired during this job. - // This is because generic Consensus guarantees that once a ledger - // is accepted, the consensus results and capture by reference state - // will not change until startRound is called (which happens via - // endConsensus). - RclConsensusLogger clog("onAccept", validating, j_); - this->doAccept( - result, - prevLedger, - closeResolution, - rawCloseTimes, - mode, - std::move(cj)); - this->app_.getOPs().endConsensus(clog.ss()); - }); + app_.getJobQueue().addJob(jtACCEPT, "AcceptLedger", [=, this, cj = std::move(consensusJson)]() mutable { + // Note that no lock is held or acquired during this job. + // This is because generic Consensus guarantees that once a ledger + // is accepted, the consensus results and capture by reference state + // will not change until startRound is called (which happens via + // endConsensus). + RclConsensusLogger clog("onAccept", validating, j_); + this->doAccept(result, prevLedger, closeResolution, rawCloseTimes, mode, std::move(cj)); + this->app_.getOPs().endConsensus(clog.ss()); + }); } void @@ -490,17 +395,13 @@ RCLConsensus::Adaptor::doAccept( else { // We agreed on a close time - consensusCloseTime = effCloseTime( - consensusCloseTime, closeResolution, prevLedger.closeTime()); + consensusCloseTime = effCloseTime(consensusCloseTime, closeResolution, prevLedger.closeTime()); closeTimeCorrect = true; } - JLOG(j_.debug()) << "Report: Prop=" << (proposing ? "yes" : "no") - << " val=" << (validating_ ? "yes" : "no") - << " corLCL=" << (haveCorrectLCL ? "yes" : "no") - << " fail=" << (consensusFail ? "yes" : "no"); - JLOG(j_.debug()) << "Report: Prev = " << prevLedger.id() << ":" - << prevLedger.seq(); + JLOG(j_.debug()) << "Report: Prop=" << (proposing ? "yes" : "no") << " val=" << (validating_ ? "yes" : "no") + << " corLCL=" << (haveCorrectLCL ? "yes" : "no") << " fail=" << (consensusFail ? "yes" : "no"); + JLOG(j_.debug()) << "Report: Prev = " << prevLedger.id() << ":" << prevLedger.seq(); //-------------------------------------------------------------------------- std::set failed; @@ -517,15 +418,13 @@ RCLConsensus::Adaptor::doAccept( { try { - retriableTxs.insert( - std::make_shared(SerialIter{item.slice()})); + retriableTxs.insert(std::make_shared(SerialIter{item.slice()})); JLOG(j_.debug()) << " Tx: " << item.key(); } catch (std::exception const& ex) { failed.insert(item.key()); - JLOG(j_.warn()) - << " Tx: " << item.key() << " throws: " << ex.what(); + JLOG(j_.warn()) << " Tx: " << item.key() << " throws: " << ex.what(); } } @@ -552,9 +451,7 @@ RCLConsensus::Adaptor::doAccept( std::vector accepted; result.txns.map_->visitLeaves( - [&accepted](boost::intrusive_ptr const& item) { - accepted.push_back(item->key()); - }); + [&accepted](boost::intrusive_ptr const& item) { accepted.push_back(item->key()); }); // Track all the transactions which failed or were marked as retriable for (auto const& r : retriableTxs) @@ -562,9 +459,7 @@ RCLConsensus::Adaptor::doAccept( censorshipDetector_.check( std::move(accepted), - [curr = built.seq(), - j = app_.journal("CensorshipDetector"), - &failed](uint256 const& id, LedgerIndex seq) { + [curr = built.seq(), j = app_.journal("CensorshipDetector"), &failed](uint256 const& id, LedgerIndex seq) { if (failed.count(id)) return true; @@ -573,8 +468,7 @@ RCLConsensus::Adaptor::doAccept( if (wait && (wait % censorshipWarnInternal == 0)) { std::ostringstream ss; - ss << "Potential Censorship: Eligible tx " << id - << ", which we are tracking since ledger " << seq + ss << "Potential Censorship: Eligible tx " << id << ", which we are tracking since ledger " << seq << " has not been included as of ledger " << curr << "."; JLOG(j.warn()) << ss.str(); @@ -585,11 +479,9 @@ RCLConsensus::Adaptor::doAccept( } if (validating_) - validating_ = ledgerMaster_.isCompatible( - *built.ledger_, j_.warn(), "Not validating"); + validating_ = ledgerMaster_.isCompatible(*built.ledger_, j_.warn(), "Not validating"); - if (validating_ && !consensusFail && - app_.getValidations().canValidateSeq(built.seq())) + if (validating_ && !consensusFail && app_.getValidations().canValidateSeq(built.seq())) { validate(built, result.txns, proposing); JLOG(j_.info()) << "CNF Val " << newLCLHash; @@ -598,8 +490,7 @@ RCLConsensus::Adaptor::doAccept( JLOG(j_.info()) << "CNF buildLCL " << newLCLHash; // See if we can accept a ledger as fully-validated - ledgerMaster_.consensusBuilt( - built.ledger_, result.txns.id(), std::move(consensusJson)); + ledgerMaster_.consensusBuilt(built.ledger_, result.txns.id(), std::move(consensusJson)); //------------------------------------------------------------------------- { @@ -623,9 +514,8 @@ RCLConsensus::Adaptor::doAccept( // we voted NO try { - JLOG(j_.debug()) - << "Test applying disputed transaction that did" - << " not get in " << dispute.tx().id(); + JLOG(j_.debug()) << "Test applying disputed transaction that did" + << " not get in " << dispute.tx().id(); SerialIter sit(dispute.tx().tx_->slice()); auto txn = std::make_shared(sit); @@ -684,37 +574,31 @@ RCLConsensus::Adaptor::doAccept( // Do these need to exist? XRPL_ASSERT( - ledgerMaster_.getClosedLedger()->info().hash == built.id(), - "ripple::RCLConsensus::Adaptor::doAccept : ledger hash match"); + ledgerMaster_.getClosedLedger()->header().hash == built.id(), + "xrpl::RCLConsensus::Adaptor::doAccept : ledger hash match"); XRPL_ASSERT( - app_.openLedger().current()->info().parentHash == built.id(), - "ripple::RCLConsensus::Adaptor::doAccept : parent hash match"); + app_.openLedger().current()->header().parentHash == built.id(), + "xrpl::RCLConsensus::Adaptor::doAccept : parent hash match"); } //------------------------------------------------------------------------- // we entered the round with the network, // see how close our close time is to other node's // close time reports, and update our clock. - if ((mode == ConsensusMode::proposing || - mode == ConsensusMode::observing) && - !consensusFail) + if ((mode == ConsensusMode::proposing || mode == ConsensusMode::observing) && !consensusFail) { auto closeTime = rawCloseTimes.self; - JLOG(j_.info()) << "We closed at " - << closeTime.time_since_epoch().count(); + JLOG(j_.info()) << "We closed at " << closeTime.time_since_epoch().count(); using usec64_t = std::chrono::duration; - usec64_t closeTotal = - std::chrono::duration_cast(closeTime.time_since_epoch()); + usec64_t closeTotal = std::chrono::duration_cast(closeTime.time_since_epoch()); int closeCount = 1; for (auto const& [t, v] : rawCloseTimes.peers) { - JLOG(j_.info()) << std::to_string(v) << " time votes for " - << std::to_string(t.time_since_epoch().count()); + JLOG(j_.info()) << std::to_string(v) << " time votes for " << std::to_string(t.time_since_epoch().count()); closeCount += v; - closeTotal += - std::chrono::duration_cast(t.time_since_epoch()) * v; + closeTotal += std::chrono::duration_cast(t.time_since_epoch()) * v; } closeTotal += usec64_t(closeCount / 2); // for round to nearest @@ -723,20 +607,15 @@ RCLConsensus::Adaptor::doAccept( // Use signed times since we are subtracting using duration = std::chrono::duration; using time_point = std::chrono::time_point; - auto offset = time_point{closeTotal} - - std::chrono::time_point_cast(closeTime); - JLOG(j_.info()) << "Our close offset is estimated at " << offset.count() - << " (" << closeCount << ")"; + auto offset = time_point{closeTotal} - std::chrono::time_point_cast(closeTime); + JLOG(j_.info()) << "Our close offset is estimated at " << offset.count() << " (" << closeCount << ")"; app_.timeKeeper().adjustCloseTime(offset); } } void -RCLConsensus::Adaptor::notify( - protocol::NodeEvent ne, - RCLCxLedger const& ledger, - bool haveCorrectLCL) +RCLConsensus::Adaptor::notify(protocol::NodeEvent ne, RCLCxLedger const& ledger, bool haveCorrectLCL) { protocol::TMStatusChange s; @@ -747,11 +626,8 @@ RCLConsensus::Adaptor::notify( s.set_ledgerseq(ledger.seq()); s.set_networktime(app_.timeKeeper().now().time_since_epoch().count()); - s.set_ledgerhashprevious( - ledger.parentID().begin(), - std::decay_t::bytes); - s.set_ledgerhash( - ledger.id().begin(), std::decay_t::bytes); + s.set_ledgerhashprevious(ledger.parentID().begin(), std::decay_t::bytes); + s.set_ledgerhash(ledger.id().begin(), std::decay_t::bytes); std::uint32_t uMin, uMax; if (!ledgerMaster_.getFullValidatedRange(uMin, uMax)) @@ -766,8 +642,7 @@ RCLConsensus::Adaptor::notify( } s.set_firstseq(uMin); s.set_lastseq(uMax); - app_.overlay().foreach( - send_always(std::make_shared(s, protocol::mtSTATUS_CHANGE))); + app_.overlay().foreach(send_always(std::make_shared(s, protocol::mtSTATUS_CHANGE))); JLOG(j_.trace()) << "send status change to peer"; } @@ -785,19 +660,12 @@ RCLConsensus::Adaptor::buildLCL( if (auto const replayData = ledgerMaster_.releaseReplay()) { XRPL_ASSERT( - replayData->parent()->info().hash == previousLedger.id(), - "ripple::RCLConsensus::Adaptor::buildLCL : parent hash match"); + replayData->parent()->header().hash == previousLedger.id(), + "xrpl::RCLConsensus::Adaptor::buildLCL : parent hash match"); return buildLedger(*replayData, tapNONE, app_, j_); } return buildLedger( - previousLedger.ledger_, - closeTime, - closeTimeCorrect, - closeResolution, - app_, - retriableTxs, - failedTxs, - j_); + previousLedger.ledger_, closeTime, closeTimeCorrect, closeResolution, app_, retriableTxs, failedTxs, j_); }(); // Update fee computations based on accepted txs @@ -807,7 +675,7 @@ RCLConsensus::Adaptor::buildLCL( // And stash the ledger in the ledger master if (ledgerMaster_.storeLedger(built)) JLOG(j_.debug()) << "Consensus built ledger we already had"; - else if (app_.getInboundLedgers().find(built->info().hash)) + else if (app_.getInboundLedgers().find(built->header().hash)) JLOG(j_.debug()) << "Consensus built ledger we were acquiring"; else JLOG(j_.debug()) << "Consensus built new ledger"; @@ -815,10 +683,7 @@ RCLConsensus::Adaptor::buildLCL( } void -RCLConsensus::Adaptor::validate( - RCLCxLedger const& ledger, - RCLTxSet const& txns, - bool proposing) +RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger, RCLTxSet const& txns, bool proposing) { using namespace std::chrono_literals; @@ -837,11 +702,7 @@ RCLConsensus::Adaptor::validate( auto const& keys = *validatorKeys_.keys; auto v = std::make_shared( - lastValidationTime_, - keys.publicKey, - keys.secretKey, - validatorKeys_.nodeID, - [&](STValidation& v) { + lastValidationTime_, keys.publicKey, keys.secretKey, validatorKeys_.nodeID, [&](STValidation& v) { v.setFieldH256(sfLedgerHash, ledger.id()); v.setFieldH256(sfConsensusHash, txns.id()); @@ -850,21 +711,17 @@ RCLConsensus::Adaptor::validate( if (proposing) v.setFlag(vfFullValidation); - if (ledger.ledger_->rules().enabled(featureHardenedValidations)) - { - // Attest to the hash of what we consider to be the last fully - // validated ledger. This may be the hash of the ledger we are - // validating here, and that's fine. - if (auto const vl = ledgerMaster_.getValidatedLedger()) - v.setFieldH256(sfValidatedHash, vl->info().hash); + // Attest to the hash of what we consider to be the last fully + // validated ledger. This may be the hash of the ledger we are + // validating here, and that's fine. + if (auto const vl = ledgerMaster_.getValidatedLedger()) + v.setFieldH256(sfValidatedHash, vl->header().hash); - v.setFieldU64(sfCookie, valCookie_); + v.setFieldU64(sfCookie, valCookie_); - // Report our server version every flag ledger: - if (ledger.ledger_->isVotingLedger()) - v.setFieldU64( - sfServerVersion, BuildInfo::getEncodedVersion()); - } + // Report our server version every flag ledger: + if (ledger.ledger_->isVotingLedger()) + v.setFieldU64(sfServerVersion, BuildInfo::getEncodedVersion()); // Report our load { @@ -879,18 +736,15 @@ RCLConsensus::Adaptor::validate( if (ledger.ledger_->isVotingLedger()) { // Fees: - feeVote_->doValidation( - ledger.ledger_->fees(), ledger.ledger_->rules(), v); + feeVote_->doValidation(ledger.ledger_->fees(), ledger.ledger_->rules(), v); // Amendments // FIXME: pass `v` and have the function insert the array // directly? - auto const amendments = app_.getAmendmentTable().doValidation( - getEnabledAmendments(*ledger.ledger_)); + auto const amendments = app_.getAmendmentTable().doValidation(getEnabledAmendments(*ledger.ledger_)); if (!amendments.empty()) - v.setFieldV256( - sfAmendments, STVector256(sfAmendments, amendments)); + v.setFieldV256(sfAmendments, STVector256(sfAmendments, amendments)); } }); @@ -913,14 +767,11 @@ RCLConsensus::Adaptor::validate( void RCLConsensus::Adaptor::onModeChange(ConsensusMode before, ConsensusMode after) { - JLOG(j_.info()) << "Consensus mode change before=" << to_string(before) - << ", after=" << to_string(after); + JLOG(j_.info()) << "Consensus mode change before=" << to_string(before) << ", after=" << to_string(after); // If we were proposing but aren't any longer, we need to reset the // censorship tracking to avoid bogus warnings. - if ((before == ConsensusMode::proposing || - before == ConsensusMode::observing) && - before != after) + if ((before == ConsensusMode::proposing || before == ConsensusMode::observing) && before != after) censorshipDetector_.reset(); mode_ = after; @@ -939,9 +790,7 @@ RCLConsensus::getJson(bool full) const } void -RCLConsensus::timerEntry( - NetClock::time_point const& now, - std::unique_ptr const& clog) +RCLConsensus::timerEntry(NetClock::time_point const& now, std::unique_ptr const& clog) { try { @@ -978,33 +827,25 @@ RCLConsensus::gotTxSet(NetClock::time_point const& now, RCLTxSet const& txSet) //! @see Consensus::simulate void -RCLConsensus::simulate( - NetClock::time_point const& now, - std::optional consensusDelay) +RCLConsensus::simulate(NetClock::time_point const& now, std::optional consensusDelay) { std::lock_guard _{mutex_}; consensus_.simulate(now, consensusDelay); } bool -RCLConsensus::peerProposal( - NetClock::time_point const& now, - RCLCxPeerPos const& newProposal) +RCLConsensus::peerProposal(NetClock::time_point const& now, RCLCxPeerPos const& newProposal) { std::lock_guard _{mutex_}; return consensus_.peerProposal(now, newProposal); } bool -RCLConsensus::Adaptor::preStartRound( - RCLCxLedger const& prevLgr, - hash_set const& nowTrusted) +RCLConsensus::Adaptor::preStartRound(RCLCxLedger const& prevLgr, hash_set const& nowTrusted) { // We have a key, we do not want out of sync validations after a restart // and are not amendment blocked. - validating_ = validatorKeys_.keys && - prevLgr.seq() >= app_.getMaxDisallowedLedger() && - !app_.getOPs().isBlocked(); + validating_ = validatorKeys_.keys && prevLgr.seq() >= app_.getMaxDisallowedLedger() && !app_.getOPs().isBlocked(); // If we are not running in standalone mode and there's a configured UNL, // check to make sure that it's not expired. @@ -1024,22 +865,19 @@ RCLConsensus::Adaptor::preStartRound( if (validating_) { - JLOG(j_.info()) << "Entering consensus process, validating, synced=" - << (synced ? "yes" : "no"); + JLOG(j_.info()) << "Entering consensus process, validating, synced=" << (synced ? "yes" : "no"); } else { // Otherwise we just want to monitor the validation process. - JLOG(j_.info()) << "Entering consensus process, watching, synced=" - << (synced ? "yes" : "no"); + JLOG(j_.info()) << "Entering consensus process, watching, synced=" << (synced ? "yes" : "no"); } // Notify inbound ledgers that we are starting a new round inboundTransactions_.newRound(prevLgr.seq()); // Notify NegativeUNLVote that new validators are added - if (prevLgr.ledger_->rules().enabled(featureNegativeUNL) && - !nowTrusted.empty()) + if (!nowTrusted.empty()) nUnlVote_.newValidators(prevLgr.seq() + 1, nowTrusted); // propose only if we're in sync with the network (and validating) @@ -1065,9 +903,7 @@ RCLConsensus::Adaptor::getQuorumKeys() const } std::size_t -RCLConsensus::Adaptor::laggards( - Ledger_t::Seq const seq, - hash_set& trustedKeys) const +RCLConsensus::Adaptor::laggards(Ledger_t::Seq const seq, hash_set& trustedKeys) const { return app_.getValidations().laggards(seq, trustedKeys); } @@ -1095,20 +931,10 @@ RCLConsensus::startRound( std::unique_ptr const& clog) { std::lock_guard _{mutex_}; - consensus_.startRound( - now, - prevLgrId, - prevLgr, - nowUntrusted, - adaptor_.preStartRound(prevLgr, nowTrusted), - clog); + consensus_.startRound(now, prevLgrId, prevLgr, nowUntrusted, adaptor_.preStartRound(prevLgr, nowTrusted), clog); } -RclConsensusLogger::RclConsensusLogger( - char const* label, - bool const validating, - beast::Journal j) - : j_(j) +RclConsensusLogger::RclConsensusLogger(char const* label, bool const validating, beast::Journal j) : j_(j) { if (!validating && !j.info()) return; @@ -1123,13 +949,12 @@ RclConsensusLogger::~RclConsensusLogger() { if (!ss_) return; - auto const duration = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start_); + auto const duration = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start_); std::stringstream outSs; - outSs << header_ << "duration " << (duration.count() / 1000) << '.' - << std::setw(3) << std::setfill('0') << (duration.count() % 1000) - << "s. " << ss_->str(); + outSs << header_ << "duration " << (duration.count() / 1000) << '.' << std::setw(3) << std::setfill('0') + << (duration.count() % 1000) << "s. " << ss_->str(); j_.sink().writeAlways(beast::severities::kInfo, outSs.str()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLConsensus.h b/src/xrpld/app/consensus/RCLConsensus.h index 19568fca82..3e1b27cd9c 100644 --- a/src/xrpld/app/consensus/RCLConsensus.h +++ b/src/xrpld/app/consensus/RCLConsensus.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED -#define RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED +#pragma once #include #include @@ -27,9 +7,9 @@ #include #include #include -#include #include +#include #include #include @@ -40,7 +20,7 @@ #include #include -namespace ripple { +namespace xrpl { class InboundTransactions; class LocalTxs; @@ -78,12 +58,11 @@ class RCLConsensus // The timestamp of the last validation we used NetClock::time_point lastValidationTime_; - // These members are queried via public accesors and are atomic for + // These members are queried via public accessors and are atomic for // thread safety. std::atomic validating_{false}; std::atomic prevProposers_{0}; - std::atomic prevRoundTime_{ - std::chrono::milliseconds{0}}; + std::atomic prevRoundTime_{std::chrono::milliseconds{0}}; std::atomic mode_{ConsensusMode::observing}; RCLCensorshipDetector censorshipDetector_; @@ -138,9 +117,7 @@ class RCLConsensus @return Whether we enter the round proposing */ bool - preStartRound( - RCLCxLedger const& prevLedger, - hash_set const& nowTrusted); + preStartRound(RCLCxLedger const& prevLedger, hash_set const& nowTrusted); bool haveValidated() const; @@ -152,8 +129,7 @@ class RCLConsensus getQuorumKeys() const; std::size_t - laggards(Ledger_t::Seq const seq, hash_set& trustedKeys) - const; + laggards(Ledger_t::Seq const seq, hash_set& trustedKeys) const; /** Whether I am a validator. * @@ -281,10 +257,7 @@ class RCLConsensus the ledger matching ledgerID from the network */ uint256 - getPrevLedger( - uint256 ledgerID, - RCLCxLedger const& ledger, - ConsensusMode mode); + getPrevLedger(uint256 ledgerID, RCLCxLedger const& ledger, ConsensusMode mode); /** Notified of change in consensus mode @@ -302,10 +275,7 @@ class RCLConsensus @return Tentative consensus result */ Result - onClose( - RCLCxLedger const& ledger, - NetClock::time_point const& closeTime, - ConsensusMode mode); + onClose(RCLCxLedger const& ledger, NetClock::time_point const& closeTime, ConsensusMode mode); /** Process the accepted ledger. @@ -351,10 +321,7 @@ class RCLConsensus @param haveCorrectLCL Whether we believe we have the correct LCL. */ void - notify( - protocol::NodeEvent ne, - RCLCxLedger const& ledger, - bool haveCorrectLCL); + notify(protocol::NodeEvent ne, RCLCxLedger const& ledger, bool haveCorrectLCL); /** Accept a new ledger based on the given transactions. @@ -411,10 +378,7 @@ class RCLConsensus but are still around and trying to catch up. */ void - validate( - RCLCxLedger const& ledger, - RCLTxSet const& txns, - bool proposing); + validate(RCLCxLedger const& ledger, RCLTxSet const& txns, bool proposing); }; public: @@ -493,9 +457,7 @@ public: //! @see Consensus::timerEntry void - timerEntry( - NetClock::time_point const& now, - std::unique_ptr const& clog = {}); + timerEntry(NetClock::time_point const& now, std::unique_ptr const& clog = {}); //! @see Consensus::gotTxSet void @@ -511,15 +473,11 @@ public: //! @see Consensus::simulate void - simulate( - NetClock::time_point const& now, - std::optional consensusDelay); + simulate(NetClock::time_point const& now, std::optional consensusDelay); //! @see Consensus::proposal bool - peerProposal( - NetClock::time_point const& now, - RCLCxPeerPos const& newProposal); + peerProposal(NetClock::time_point const& now, RCLCxPeerPos const& newProposal); ConsensusParms const& parms() const @@ -555,10 +513,7 @@ class RclConsensusLogger std::chrono::steady_clock::time_point start_; public: - explicit RclConsensusLogger( - char const* label, - bool validating, - beast::Journal j); + explicit RclConsensusLogger(char const* label, bool validating, beast::Journal j); ~RclConsensusLogger(); std::unique_ptr const& @@ -567,6 +522,4 @@ public: return ss_; } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLCxLedger.h b/src/xrpld/app/consensus/RCLCxLedger.h index f9df1fe41a..6b96fc8af3 100644 --- a/src/xrpld/app/consensus/RCLCxLedger.h +++ b/src/xrpld/app/consensus/RCLCxLedger.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED -#define RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Represents a ledger in RCLConsensus. @@ -60,56 +40,56 @@ public: Seq const& seq() const { - return ledger_->info().seq; + return ledger_->header().seq; } //! Unique identifier (hash) of this ledger. ID const& id() const { - return ledger_->info().hash; + return ledger_->header().hash; } //! Unique identifier (hash) of this ledger's parent. ID const& parentID() const { - return ledger_->info().parentHash; + return ledger_->header().parentHash; } //! Resolution used when calculating this ledger's close time. NetClock::duration closeTimeResolution() const { - return ledger_->info().closeTimeResolution; + return ledger_->header().closeTimeResolution; } //! Whether consensus process agreed on close time of the ledger. bool closeAgree() const { - return ripple::getCloseAgree(ledger_->info()); + return xrpl::getCloseAgree(ledger_->header()); } //! The close time of this ledger NetClock::time_point closeTime() const { - return ledger_->info().closeTime; + return ledger_->header().closeTime; } //! The close time of this ledger's parent. NetClock::time_point parentCloseTime() const { - return ledger_->info().parentCloseTime; + return ledger_->header().parentCloseTime; } //! JSON representation of this ledger. Json::Value getJson() const { - return ripple::getJson({*ledger_, {}}); + return xrpl::getJson({*ledger_, {}}); } /** The ledger instance. @@ -119,5 +99,4 @@ public: */ std::shared_ptr ledger_; }; -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp index 83847b2e9e..4128d65c49 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.cpp +++ b/src/xrpld/app/consensus/RCLCxPeerPos.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { // Used to construct received proposals RCLCxPeerPos::RCLCxPeerPos( @@ -30,15 +11,13 @@ RCLCxPeerPos::RCLCxPeerPos( Slice const& signature, uint256 const& suppression, Proposal&& proposal) - : publicKey_(publicKey) - , suppression_(suppression) - , proposal_(std::move(proposal)) + : publicKey_(publicKey), suppression_(suppression), proposal_(std::move(proposal)) { // The maximum allowed size of a signature is 72 bytes; we verify // this elsewhere, but we want to be extra careful here: XRPL_ASSERT( signature.size() != 0 && signature.size() <= signature_.capacity(), - "ripple::RCLCxPeerPos::RCLCxPeerPos : valid signature size"); + "xrpl::RCLCxPeerPos::RCLCxPeerPos : valid signature size"); if (signature.size() != 0 && signature.size() <= signature_.capacity()) signature_.assign(signature.begin(), signature.end()); @@ -47,8 +26,7 @@ RCLCxPeerPos::RCLCxPeerPos( bool RCLCxPeerPos::checkSign() const { - return verifyDigest( - publicKey(), proposal_.signingHash(), signature(), false); + return verifyDigest(publicKey(), proposal_.signingHash(), signature(), false); } Json::Value @@ -82,4 +60,4 @@ proposalUniqueId( return s.getSHA512Half(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.h b/src/xrpld/app/consensus/RCLCxPeerPos.h index 63cfde8700..b9ef492aae 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.h +++ b/src/xrpld/app/consensus/RCLCxPeerPos.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED -#define RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED +#pragma once #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { /** A peer's signed, proposed position for use in RCLConsensus. @@ -56,11 +36,7 @@ public: @param proposal The consensus proposal */ - RCLCxPeerPos( - PublicKey const& publicKey, - Slice const& signature, - uint256 const& suppress, - Proposal&& proposal); + RCLCxPeerPos(PublicKey const& publicKey, Slice const& signature, uint256 const& suppress, Proposal&& proposal); //! Verify the signing hash of the proposal bool @@ -147,6 +123,4 @@ proposalUniqueId( Slice const& publicKey, Slice const& signature); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLCxTx.h b/src/xrpld/app/consensus/RCLCxTx.h index 94f43113a8..b7bde11a3b 100644 --- a/src/xrpld/app/consensus/RCLCxTx.h +++ b/src/xrpld/app/consensus/RCLCxTx.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED -#define RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** Represents a transaction in RCLConsensus. @@ -108,8 +88,7 @@ public: */ RCLTxSet(std::shared_ptr m) : map_{std::move(m)} { - XRPL_ASSERT( - map_, "ripple::RCLTxSet::MutableTxSet::RCLTxSet : non-null input"); + XRPL_ASSERT(map_, "xrpl::RCLTxSet::MutableTxSet::RCLTxSet : non-null input"); } /** Constructor from a previously created MutableTxSet @@ -176,8 +155,7 @@ public: for (auto const& [k, v] : delta) { XRPL_ASSERT( - (v.first && !v.second) || (v.second && !v.first), - "ripple::RCLTxSet::compare : either side is set"); + (v.first && !v.second) || (v.second && !v.first), "xrpl::RCLTxSet::compare : either side is set"); ret[k] = static_cast(v.first); } @@ -187,5 +165,4 @@ public: //! The SHAMap representing the transactions. std::shared_ptr map_; }; -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index 5305c95357..8c99ea9939 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -1,61 +1,38 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include -#include #include #include +#include +#include #include -namespace ripple { +namespace xrpl { -RCLValidatedLedger::RCLValidatedLedger(MakeGenesis) - : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()} +RCLValidatedLedger::RCLValidatedLedger(MakeGenesis) : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()} { } -RCLValidatedLedger::RCLValidatedLedger( - std::shared_ptr const& ledger, - beast::Journal j) - : ledgerID_{ledger->info().hash}, ledgerSeq_{ledger->seq()}, j_{j} +RCLValidatedLedger::RCLValidatedLedger(std::shared_ptr const& ledger, beast::Journal j) + : ledgerID_{ledger->header().hash}, ledgerSeq_{ledger->seq()}, j_{j} { auto const hashIndex = ledger->read(keylet::skip()); if (hashIndex) { XRPL_ASSERT( hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1), - "ripple::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid " + "xrpl::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid " "last ledger sequence"); ancestors_ = hashIndex->getFieldV256(sfHashes).value(); } else - JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_ - << " missing recent ancestor hashes"; + JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_ << " missing recent ancestor hashes"; } auto @@ -86,10 +63,8 @@ RCLValidatedLedger::operator[](Seq const& s) const -> ID return ancestors_[ancestors_.size() - diff]; } - JLOG(j_.warn()) << "Unable to determine hash of ancestor seq=" << s - << " from ledger hash=" << ledgerID_ - << " seq=" << ledgerSeq_ << " (available: " << minSeq() - << "-" << seq() << ")"; + JLOG(j_.warn()) << "Unable to determine hash of ancestor seq=" << s << " from ledger hash=" << ledgerID_ + << " seq=" << ledgerSeq_ << " (available: " << minSeq() << "-" << seq() << ")"; // Default ID that is less than all others return ID{0}; } @@ -113,8 +88,7 @@ mismatch(RCLValidatedLedger const& a, RCLValidatedLedger const& b) return (curr < lower) ? Seq{1} : (curr + Seq{1}); } -RCLValidationsAdaptor::RCLValidationsAdaptor(Application& app, beast::Journal j) - : app_(app), j_(j) +RCLValidationsAdaptor::RCLValidationsAdaptor(Application& app, beast::Journal j) : app_(app), j_(j) { } @@ -129,34 +103,23 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash) { using namespace std::chrono_literals; auto ledger = perf::measureDurationAndLog( - [&]() { return app_.getLedgerMaster().getLedgerByHash(hash); }, - "getLedgerByHash", - 10ms, - j_); + [&]() { return app_.getLedgerMaster().getLedgerByHash(hash); }, "getLedgerByHash", 10ms, j_); if (!ledger) { - JLOG(j_.warn()) - << "Need validated ledger for preferred ledger analysis " << hash; + JLOG(j_.warn()) << "Need validated ledger for preferred ledger analysis " << hash; Application* pApp = &app_; - app_.getJobQueue().addJob( - jtADVANCE, "getConsensusLedger2", [pApp, hash, this]() { - JLOG(j_.debug()) - << "JOB advanceLedger getConsensusLedger2 started"; - pApp->getInboundLedgers().acquireAsync( - hash, 0, InboundLedger::Reason::CONSENSUS); - }); + app_.getJobQueue().addJob(jtADVANCE, "GetConsL2", [pApp, hash, this]() { + JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger2 started"; + pApp->getInboundLedgers().acquireAsync(hash, 0, InboundLedger::Reason::CONSENSUS); + }); return std::nullopt; } - XRPL_ASSERT( - !ledger->open() && ledger->isImmutable(), - "ripple::RCLValidationsAdaptor::acquire : valid ledger state"); - XRPL_ASSERT( - ledger->info().hash == hash, - "ripple::RCLValidationsAdaptor::acquire : ledger hash match"); + XRPL_ASSERT(!ledger->open() && ledger->isImmutable(), "xrpl::RCLValidationsAdaptor::acquire : valid ledger state"); + XRPL_ASSERT(ledger->header().hash == hash, "xrpl::RCLValidationsAdaptor::acquire : ledger hash match"); return RCLValidatedLedger(std::move(ledger), j_); } @@ -186,8 +149,7 @@ handleNewValidation( auto& validations = app.getValidations(); // masterKey is seated only if validator is trusted or listed - auto const outcome = - validations.add(calcNodeID(masterKey.value_or(signingKey)), val); + auto const outcome = validations.add(calcNodeID(masterKey.value_or(signingKey)), val); if (outcome == ValStatus::current) { @@ -195,12 +157,10 @@ handleNewValidation( { if (bypassAccept == BypassAccept::yes) { - XRPL_ASSERT( - j, "ripple::handleNewValidation : journal is available"); + XRPL_ASSERT(j, "xrpl::handleNewValidation : journal is available"); if (j.has_value()) { - JLOG(j->trace()) << "Bypassing checkAccept for validation " - << val->getLedgerHash(); + JLOG(j->trace()) << "Bypassing checkAccept for validation " << val->getLedgerHash(); } } else @@ -219,9 +179,8 @@ handleNewValidation( // counterintuitively, we *especially* want to forward such validations, // so that our peers will also observe them and take independent notice of // such validators, informing their operators. - if (auto const ls = val->isTrusted() - ? validations.adaptor().journal().error() - : validations.adaptor().journal().info(); + if (auto const ls = + val->isTrusted() ? validations.adaptor().journal().error() : validations.adaptor().journal().info(); ls.active()) { auto const id = [&masterKey, &signingKey]() { @@ -234,17 +193,13 @@ handleNewValidation( }(); if (outcome == ValStatus::conflicting) - ls << "Byzantine Behavior Detector: " - << (val->isTrusted() ? "trusted " : "untrusted ") << id - << ": Conflicting validation for " << seq << "!\n[" - << val->getSerializer().slice() << "]"; + ls << "Byzantine Behavior Detector: " << (val->isTrusted() ? "trusted " : "untrusted ") << id + << ": Conflicting validation for " << seq << "!\n[" << val->getSerializer().slice() << "]"; if (outcome == ValStatus::multiple) - ls << "Byzantine Behavior Detector: " - << (val->isTrusted() ? "trusted " : "untrusted ") << id - << ": Multiple validations for " << seq << "/" << hash << "!\n[" - << val->getSerializer().slice() << "]"; + ls << "Byzantine Behavior Detector: " << (val->isTrusted() ? "trusted " : "untrusted ") << id + << ": Multiple validations for " << seq << "/" << hash << "!\n[" << val->getSerializer().slice() << "]"; } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/consensus/RCLValidations.h b/src/xrpld/app/consensus/RCLValidations.h index a9f872bee9..35c1686f9e 100644 --- a/src/xrpld/app/consensus/RCLValidations.h +++ b/src/xrpld/app/consensus/RCLValidations.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_CONSENSUSS_VALIDATIONS_H_INCLUDED -#define RIPPLE_APP_CONSENSUSS_VALIDATIONS_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { class Application; @@ -45,8 +25,8 @@ class RCLValidation std::shared_ptr val_; public: - using NodeKey = ripple::PublicKey; - using NodeID = ripple::NodeID; + using NodeKey = xrpl::PublicKey; + using NodeID = xrpl::NodeID; /** Constructor @@ -167,9 +147,7 @@ public: RCLValidatedLedger(MakeGenesis); - RCLValidatedLedger( - std::shared_ptr const& ledger, - beast::Journal j); + RCLValidatedLedger(std::shared_ptr const& ledger, beast::Journal j); /// The sequence (index) of the ledger Seq @@ -257,6 +235,4 @@ handleNewValidation( BypassAccept const bypassAccept = BypassAccept::no, std::optional j = std::nullopt); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AbstractFetchPackContainer.h b/src/xrpld/app/ledger/AbstractFetchPackContainer.h index a93169800e..3adc435bd6 100644 --- a/src/xrpld/app/ledger/AbstractFetchPackContainer.h +++ b/src/xrpld/app/ledger/AbstractFetchPackContainer.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED -#define RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** An interface facilitating retrieval of fetch packs without an application or ledgermaster object. @@ -35,7 +15,7 @@ class AbstractFetchPackContainer public: virtual ~AbstractFetchPackContainer() = default; - /** Retrieves partial ledger data of the coresponding hash from peers.` + /** Retrieves partial ledger data of the corresponding hash from peers.` @param nodeHash The 256-bit hash of the data to fetch. @return `std::nullopt` if the hash isn't cached, @@ -45,6 +25,4 @@ public: getFetchPack(uint256 const& nodeHash) = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AcceptedLedger.cpp b/src/xrpld/app/ledger/AcceptedLedger.cpp index 21efc4983f..89806c2337 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.cpp +++ b/src/xrpld/app/ledger/AcceptedLedger.cpp @@ -1,50 +1,24 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { -AcceptedLedger::AcceptedLedger( - std::shared_ptr const& ledger, - Application& app) - : mLedger(ledger) +AcceptedLedger::AcceptedLedger(std::shared_ptr const& ledger, Application& app) : mLedger(ledger) { transactions_.reserve(256); auto insertAll = [&](auto const& txns) { for (auto const& item : txns) - transactions_.emplace_back(std::make_unique( - ledger, item.first, item.second)); + transactions_.emplace_back(std::make_unique(ledger, item.first, item.second)); }; transactions_.reserve(256); insertAll(ledger->txs); - std::sort( - transactions_.begin(), - transactions_.end(), - [](auto const& a, auto const& b) { - return a->getTxnSeq() < b->getTxnSeq(); - }); + std::sort(transactions_.begin(), transactions_.end(), [](auto const& a, auto const& b) { + return a->getTxnSeq() < b->getTxnSeq(); + }); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AcceptedLedger.h b/src/xrpld/app/ledger/AcceptedLedger.h index 6b17d93c9d..c0f186c781 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.h +++ b/src/xrpld/app/ledger/AcceptedLedger.h @@ -1,28 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_ACCEPTEDLEDGER_H_INCLUDED -#define RIPPLE_APP_LEDGER_ACCEPTEDLEDGER_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { /** A ledger that has become irrevocable. @@ -43,9 +23,7 @@ namespace ripple { class AcceptedLedger : public CountedObject { public: - AcceptedLedger( - std::shared_ptr const& ledger, - Application& app); + AcceptedLedger(std::shared_ptr const& ledger, Application& app); std::shared_ptr const& getLedger() const @@ -76,6 +54,4 @@ private: std::vector> transactions_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp index 7944578f77..2ef05e511d 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,19 +5,15 @@ #include #include -namespace ripple { +namespace xrpl { AcceptedLedgerTx::AcceptedLedgerTx( std::shared_ptr const& ledger, std::shared_ptr const& txn, std::shared_ptr const& met) - : mTxn(txn) - , mMeta(txn->getTransactionID(), ledger->seq(), *met) - , mAffected(mMeta.getAffectedAccounts()) + : mTxn(txn), mMeta(txn->getTransactionID(), ledger->seq(), *met), mAffected(mMeta.getAffectedAccounts()) { - XRPL_ASSERT( - !ledger->open(), - "ripple::AcceptedLedgerTx::AcceptedLedgerTx : valid ledger state"); + XRPL_ASSERT(!ledger->open(), "xrpl::AcceptedLedgerTx::AcceptedLedgerTx : valid ledger state"); Serializer s; met->add(s); @@ -65,12 +42,8 @@ AcceptedLedgerTx::AcceptedLedgerTx( // If the offer create is not self funded then add the owner balance if (account != amount.issue().account) { - auto const ownerFunds = accountFunds( - *ledger, - account, - amount, - fhIGNORE_FREEZE, - beast::Journal{beast::Journal::getNullSink()}); + auto const ownerFunds = + accountFunds(*ledger, account, amount, fhIGNORE_FREEZE, beast::Journal{beast::Journal::getNullSink()}); mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText(); } } @@ -79,10 +52,8 @@ AcceptedLedgerTx::AcceptedLedgerTx( std::string AcceptedLedgerTx::getEscMeta() const { - XRPL_ASSERT( - !mRawMeta.empty(), - "ripple::AcceptedLedgerTx::getEscMeta : metadata is set"); + XRPL_ASSERT(!mRawMeta.empty(), "xrpl::AcceptedLedgerTx::getEscMeta : metadata is set"); return sqlBlobLiteral(mRawMeta); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.h b/src/xrpld/app/ledger/AcceptedLedgerTx.h index efa16371a7..6c936bbcf2 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.h +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_ACCEPTEDLEDGERTX_H_INCLUDED -#define RIPPLE_APP_LEDGER_ACCEPTEDLEDGERTX_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { class Logs; @@ -104,6 +84,4 @@ private: Json::Value mJson; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AccountStateSF.cpp b/src/xrpld/app/ledger/AccountStateSF.cpp index c1f2ca26fc..048a46e810 100644 --- a/src/xrpld/app/ledger/AccountStateSF.cpp +++ b/src/xrpld/app/ledger/AccountStateSF.cpp @@ -1,36 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { void -AccountStateSF::gotNode( - bool, - SHAMapHash const& nodeHash, - std::uint32_t ledgerSeq, - Blob&& nodeData, - SHAMapNodeType) const +AccountStateSF::gotNode(bool, SHAMapHash const& nodeHash, std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapNodeType) + const { - db_.store( - hotACCOUNT_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq); + db_.store(hotACCOUNT_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq); } std::optional @@ -39,4 +15,4 @@ AccountStateSF::getNode(SHAMapHash const& nodeHash) const return fp_.getFetchPack(nodeHash.as_uint256()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/AccountStateSF.h b/src/xrpld/app/ledger/AccountStateSF.h index 8a4e594f4a..fb9da3a616 100644 --- a/src/xrpld/app/ledger/AccountStateSF.h +++ b/src/xrpld/app/ledger/AccountStateSF.h @@ -1,49 +1,24 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_ACCOUNTSTATESF_H_INCLUDED -#define RIPPLE_APP_LEDGER_ACCOUNTSTATESF_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // This class is only needed on add functions // sync filter for account state nodes during ledger sync class AccountStateSF : public SHAMapSyncFilter { public: - AccountStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp) - : db_(db), fp_(fp) + AccountStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp) : db_(db), fp_(fp) { } void - gotNode( - bool fromFilter, - SHAMapHash const& nodeHash, - std::uint32_t ledgerSeq, - Blob&& nodeData, - SHAMapNodeType type) const override; + gotNode(bool fromFilter, SHAMapHash const& nodeHash, std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapNodeType type) + const override; std::optional getNode(SHAMapHash const& nodeHash) const override; @@ -53,6 +28,4 @@ private: AbstractFetchPackContainer& fp_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/BookListeners.cpp b/src/xrpld/app/ledger/BookListeners.cpp index fa5fa65059..4d72c6f3b3 100644 --- a/src/xrpld/app/ledger/BookListeners.cpp +++ b/src/xrpld/app/ledger/BookListeners.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { void BookListeners::addSubscriber(InfoSub::ref sub) @@ -36,9 +17,7 @@ BookListeners::removeSubscriber(std::uint64_t seq) } void -BookListeners::publish( - MultiApiJson const& jvObj, - hash_set& havePublished) +BookListeners::publish(MultiApiJson const& jvObj, hash_set& havePublished) { std::lock_guard sl(mLock); auto it = mListeners.cbegin(); @@ -49,7 +28,7 @@ BookListeners::publish( if (p) { - // Only publish jvObj if this is the first occurence + // Only publish jvObj if this is the first occurrence if (havePublished.emplace(p->getSeq()).second) { jvObj.visit( @@ -63,4 +42,4 @@ BookListeners::publish( } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/BookListeners.h b/src/xrpld/app/ledger/BookListeners.h index 5522ad3ec0..036e988749 100644 --- a/src/xrpld/app/ledger/BookListeners.h +++ b/src/xrpld/app/ledger/BookListeners.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED -#define RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Listen to public/subscribe messages from a book. */ class BookListeners @@ -69,6 +49,4 @@ private: hash_map mListeners; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/BuildLedger.h b/src/xrpld/app/ledger/BuildLedger.h index 980fe82ed8..7b4b85c4aa 100644 --- a/src/xrpld/app/ledger/BuildLedger.h +++ b/src/xrpld/app/ledger/BuildLedger.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED -#define RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class Application; class CanonicalTXSet; @@ -70,11 +50,6 @@ buildLedger( @return The newly built ledger */ std::shared_ptr -buildLedger( - LedgerReplay const& replayData, - ApplyFlags applyFlags, - Application& app, - beast::Journal j); +buildLedger(LedgerReplay const& replayData, ApplyFlags applyFlags, Application& app, beast::Journal j); -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp index 7d83b4c201..6a8dbd3d7d 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp @@ -1,34 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -#include #include +#include #include #include #include -namespace ripple { +namespace xrpl { ConsensusTransSetSF::ConsensusTransSetSF(Application& app, NodeCache& nodeCache) : app_(app), m_nodeCache(nodeCache), j_(app.journal("TransactionAcquire")) @@ -51,8 +32,7 @@ ConsensusTransSetSF::gotNode( if ((type == SHAMapNodeType::tnTRANSACTION_NM) && (nodeData.size() > 16)) { // this is a transaction, and we didn't have it - JLOG(j_.debug()) - << "Node on our acquiring TX set is TXN we may not have"; + JLOG(j_.debug()) << "Node on our acquiring TX set is TXN we may not have"; try { @@ -62,18 +42,15 @@ ConsensusTransSetSF::gotNode( auto stx = std::make_shared(std::ref(sit)); XRPL_ASSERT( stx->getTransactionID() == nodeHash.as_uint256(), - "ripple::ConsensusTransSetSF::gotNode : transaction hash " + "xrpl::ConsensusTransSetSF::gotNode : transaction hash " "match"); auto const pap = &app_; - app_.getJobQueue().addJob(jtTRANSACTION, "TXS->TXN", [pap, stx]() { - pap->getOPs().submitTransaction(stx); - }); + app_.getJobQueue().addJob( + jtTRANSACTION, "TxsToTxn", [pap, stx]() { pap->getOPs().submitTransaction(stx); }); } catch (std::exception const& ex) { - JLOG(j_.warn()) - << "Fetched invalid transaction in proposed set. Exception: " - << ex.what(); + JLOG(j_.warn()) << "Fetched invalid transaction in proposed set. Exception: " << ex.what(); } } } @@ -85,8 +62,7 @@ ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const if (m_nodeCache.retrieve(nodeHash, nodeData)) return nodeData; - auto txn = - app_.getMasterTransaction().fetch_from_cache(nodeHash.as_uint256()); + auto txn = app_.getMasterTransaction().fetch_from_cache(nodeHash.as_uint256()); if (txn) { @@ -97,7 +73,7 @@ ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const txn->getSTransaction()->add(s); XRPL_ASSERT( sha512Half(s.slice()) == nodeHash.as_uint256(), - "ripple::ConsensusTransSetSF::getNode : transaction hash match"); + "xrpl::ConsensusTransSetSF::getNode : transaction hash match"); nodeData = s.peekData(); return nodeData; } @@ -105,4 +81,4 @@ ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const return std::nullopt; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.h b/src/xrpld/app/ledger/ConsensusTransSetSF.h index 11add63db0..855577ecee 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.h +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_CONSENSUSTRANSSETSF_H_INCLUDED -#define RIPPLE_APP_LEDGER_CONSENSUSTRANSSETSF_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // Sync filters allow low-level SHAMapSync code to interact correctly with // higher-level structures such as caches and transaction stores @@ -41,12 +21,8 @@ public: // Note that the nodeData is overwritten by this call void - gotNode( - bool fromFilter, - SHAMapHash const& nodeHash, - std::uint32_t ledgerSeq, - Blob&& nodeData, - SHAMapNodeType type) const override; + gotNode(bool fromFilter, SHAMapHash const& nodeHash, std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapNodeType type) + const override; std::optional getNode(SHAMapHash const& nodeHash) const override; @@ -57,6 +33,4 @@ private: beast::Journal const j_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h index e8f244bfc0..46a8cf19b5 100644 --- a/src/xrpld/app/ledger/InboundLedger.h +++ b/src/xrpld/app/ledger/InboundLedger.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED -#define RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED +#pragma once #include #include @@ -31,7 +11,7 @@ #include #include -namespace ripple { +namespace xrpl { // A ledger we are trying to acquire class InboundLedger final : public TimeoutCounter, @@ -94,12 +74,9 @@ public: init(ScopedLockType& collectionLock); bool - gotData( - std::weak_ptr, - std::shared_ptr const&); + gotData(std::weak_ptr, std::shared_ptr const&); - using neededHash_t = - std::pair; + using neededHash_t = std::pair; /** Return a Json::objectValue. */ Json::Value @@ -124,9 +101,7 @@ private: enum class TriggerReason { added, reply, timeout }; void - filterNodes( - std::vector>& nodes, - TriggerReason reason); + filterNodes(std::vector>& nodes, TriggerReason reason); void trigger(std::shared_ptr const&, TriggerReason); @@ -191,13 +166,9 @@ private: // Data we have received from peers std::mutex mReceivedDataLock; - std::vector< - std::pair, std::shared_ptr>> - mReceivedData; + std::vector, std::shared_ptr>> mReceivedData; bool mReceiveDispatched; std::unique_ptr mPeerSet; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/InboundLedgers.h b/src/xrpld/app/ledger/InboundLedgers.h index 037897392f..30eb69ab7a 100644 --- a/src/xrpld/app/ledger/InboundLedgers.h +++ b/src/xrpld/app/ledger/InboundLedgers.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_INBOUNDLEDGERS_H_INCLUDED -#define RIPPLE_APP_LEDGER_INBOUNDLEDGERS_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Manages the lifetime of inbound ledgers. @@ -46,10 +26,7 @@ public: // Queue. TODO review whether all callers of acquire() can use this // instead. Inbound ledger acquisition is asynchronous anyway. virtual void - acquireAsync( - uint256 const& hash, - std::uint32_t seq, - InboundLedger::Reason reason) = 0; + acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) = 0; virtual std::shared_ptr find(LedgerHash const& hash) = 0; @@ -57,10 +34,7 @@ public: // VFALCO TODO Remove the dependency on the Peer object. // virtual bool - gotLedgerData( - LedgerHash const& ledgerHash, - std::shared_ptr, - std::shared_ptr) = 0; + gotLedgerData(LedgerHash const& ledgerHash, std::shared_ptr, std::shared_ptr) = 0; virtual void gotStaleData(std::shared_ptr packet) = 0; @@ -103,6 +77,4 @@ make_InboundLedgers( InboundLedgers::clock_type& clock, beast::insight::Collector::ptr const& collector); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/InboundTransactions.h b/src/xrpld/app/ledger/InboundTransactions.h index fc39f195ab..7b85f56c5f 100644 --- a/src/xrpld/app/ledger/InboundTransactions.h +++ b/src/xrpld/app/ledger/InboundTransactions.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED -#define RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class Application; @@ -64,10 +44,7 @@ public: * @param message The LedgerData message. */ virtual void - gotData( - uint256 const& setHash, - std::shared_ptr peer, - std::shared_ptr message) = 0; + gotData(uint256 const& setHash, std::shared_ptr peer, std::shared_ptr message) = 0; /** Add a transaction set. * @@ -77,10 +54,7 @@ public: * or constructed by ourself during consensus. */ virtual void - giveSet( - uint256 const& setHash, - std::shared_ptr const& set, - bool acquired) = 0; + giveSet(uint256 const& setHash, std::shared_ptr const& set, bool acquired) = 0; /** Informs the container if a new consensus round */ @@ -97,6 +71,4 @@ make_InboundTransactions( beast::insight::Collector::ptr const& collector, std::function const&, bool)> gotSet); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index cf99fbfaac..0f44601679 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -1,37 +1,16 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include #include -#include -#include #include #include #include +#include #include #include #include @@ -42,16 +21,17 @@ #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { create_genesis_t const create_genesis{}; uint256 -calculateLedgerHash(LedgerInfo const& info) +calculateLedgerHash(LedgerHeader const& info) { // VFALCO This has to match addRaw in View.h. return sha512Half( @@ -128,8 +108,7 @@ public: txs_iter_impl(txs_iter_impl const&) = default; - txs_iter_impl(bool metadata, SHAMap::const_iterator iter) - : metadata_(metadata), iter_(std::move(iter)) + txs_iter_impl(bool metadata, SHAMap::const_iterator iter) : metadata_(metadata), iter_(std::move(iter)) { } @@ -165,29 +144,23 @@ public: //------------------------------------------------------------------------------ -Ledger::Ledger( - create_genesis_t, - Config const& config, - std::vector const& amendments, - Family& family) +Ledger::Ledger(create_genesis_t, Config const& config, std::vector const& amendments, Family& family) : mImmutable(false) , txMap_(SHAMapType::TRANSACTION, family) , stateMap_(SHAMapType::STATE, family) , rules_{config.features} , j_(beast::Journal(beast::Journal::getNullSink())) { - info_.seq = 1; - info_.drops = INITIAL_XRP; - info_.closeTimeResolution = ledgerGenesisTimeResolution; + header_.seq = 1; + header_.drops = INITIAL_XRP; + header_.closeTimeResolution = ledgerGenesisTimeResolution; - static auto const id = calcAccountID( - generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")) - .first); + static auto const id = calcAccountID(generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")).first); { auto const sle = std::make_shared(keylet::account(id)); sle->setFieldU32(sfSequence, 1); sle->setAccountID(sfAccount, id); - sle->setFieldAmount(sfBalance, info_.drops); + sle->setFieldAmount(sfBalance, header_.drops); rawInsert(sle); } @@ -201,8 +174,7 @@ Ledger::Ledger( { auto sle = std::make_shared(keylet::fees()); // Whether featureXRPFees is supported will depend on startup options. - if (std::find(amendments.begin(), amendments.end(), featureXRPFees) != - amendments.end()) + if (std::find(amendments.begin(), amendments.end(), featureXRPFees) != amendments.end()) { sle->at(sfBaseFeeDrops) = config.FEES.reference_fee; sle->at(sfReserveBaseDrops) = config.FEES.account_reserve; @@ -210,14 +182,11 @@ Ledger::Ledger( } else { - if (auto const f = - config.FEES.reference_fee.dropsAs()) + if (auto const f = config.FEES.reference_fee.dropsAs()) sle->at(sfBaseFee) = *f; - if (auto const f = - config.FEES.account_reserve.dropsAs()) + if (auto const f = config.FEES.account_reserve.dropsAs()) sle->at(sfReserveBase) = *f; - if (auto const f = - config.FEES.owner_reserve.dropsAs()) + if (auto const f = config.FEES.owner_reserve.dropsAs()) sle->at(sfReserveIncrement) = *f; sle->at(sfReferenceFeeUnits) = Config::FEE_UNITS_DEPRECATED; } @@ -229,7 +198,7 @@ Ledger::Ledger( } Ledger::Ledger( - LedgerInfo const& info, + LedgerHeader const& info, bool& loaded, bool acquire, Config const& config, @@ -239,23 +208,21 @@ Ledger::Ledger( , txMap_(SHAMapType::TRANSACTION, info.txHash, family) , stateMap_(SHAMapType::STATE, info.accountHash, family) , rules_(config.features) - , info_(info) + , header_(info) , j_(j) { loaded = true; - if (info_.txHash.isNonZero() && - !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr)) + if (header_.txHash.isNonZero() && !txMap_.fetchRoot(SHAMapHash{header_.txHash}, nullptr)) { loaded = false; - JLOG(j.warn()) << "Don't have transaction root for ledger" << info_.seq; + JLOG(j.warn()) << "Don't have transaction root for ledger" << header_.seq; } - if (info_.accountHash.isNonZero() && - !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr)) + if (header_.accountHash.isNonZero() && !stateMap_.fetchRoot(SHAMapHash{header_.accountHash}, nullptr)) { loaded = false; - JLOG(j.warn()) << "Don't have state data root for ledger" << info_.seq; + JLOG(j.warn()) << "Don't have state data root for ledger" << header_.seq; } txMap_.setImmutable(); @@ -267,9 +234,9 @@ Ledger::Ledger( if (!loaded) { - info_.hash = calculateLedgerHash(info_); + header_.hash = calculateLedgerHash(header_); if (acquire) - family.missingNodeAcquireByHash(info_.hash, info_.seq); + family.missingNodeAcquireByHash(header_.hash, header_.seq); } } @@ -282,53 +249,46 @@ Ledger::Ledger(Ledger const& prevLedger, NetClock::time_point closeTime) , rules_(prevLedger.rules_) , j_(beast::Journal(beast::Journal::getNullSink())) { - info_.seq = prevLedger.info_.seq + 1; - info_.parentCloseTime = prevLedger.info_.closeTime; - info_.hash = prevLedger.info().hash + uint256(1); - info_.drops = prevLedger.info().drops; - info_.closeTimeResolution = prevLedger.info_.closeTimeResolution; - info_.parentHash = prevLedger.info().hash; - info_.closeTimeResolution = getNextLedgerTimeResolution( - prevLedger.info_.closeTimeResolution, - getCloseAgree(prevLedger.info()), - info_.seq); + header_.seq = prevLedger.header_.seq + 1; + header_.parentCloseTime = prevLedger.header_.closeTime; + header_.hash = prevLedger.header().hash + uint256(1); + header_.drops = prevLedger.header().drops; + header_.closeTimeResolution = prevLedger.header_.closeTimeResolution; + header_.parentHash = prevLedger.header().hash; + header_.closeTimeResolution = getNextLedgerTimeResolution( + prevLedger.header_.closeTimeResolution, getCloseAgree(prevLedger.header()), header_.seq); - if (prevLedger.info_.closeTime == NetClock::time_point{}) + if (prevLedger.header_.closeTime == NetClock::time_point{}) { - info_.closeTime = roundCloseTime(closeTime, info_.closeTimeResolution); + header_.closeTime = roundCloseTime(closeTime, header_.closeTimeResolution); } else { - info_.closeTime = - prevLedger.info_.closeTime + info_.closeTimeResolution; + header_.closeTime = prevLedger.header_.closeTime + header_.closeTimeResolution; } } -Ledger::Ledger(LedgerInfo const& info, Config const& config, Family& family) +Ledger::Ledger(LedgerHeader const& info, Config const& config, Family& family) : mImmutable(true) , txMap_(SHAMapType::TRANSACTION, info.txHash, family) , stateMap_(SHAMapType::STATE, info.accountHash, family) , rules_{config.features} - , info_(info) + , header_(info) , j_(beast::Journal(beast::Journal::getNullSink())) { - info_.hash = calculateLedgerHash(info_); + header_.hash = calculateLedgerHash(header_); } -Ledger::Ledger( - std::uint32_t ledgerSeq, - NetClock::time_point closeTime, - Config const& config, - Family& family) +Ledger::Ledger(std::uint32_t ledgerSeq, NetClock::time_point closeTime, Config const& config, Family& family) : mImmutable(false) , txMap_(SHAMapType::TRANSACTION, family) , stateMap_(SHAMapType::STATE, family) , rules_{config.features} , j_(beast::Journal(beast::Journal::getNullSink())) { - info_.seq = ledgerSeq; - info_.closeTime = closeTime; - info_.closeTimeResolution = ledgerDefaultTimeResolution; + header_.seq = ledgerSeq; + header_.closeTime = closeTime; + header_.closeTimeResolution = ledgerDefaultTimeResolution; defaultFees(config); setup(); } @@ -340,12 +300,12 @@ Ledger::setImmutable(bool rehash) // place the hash transitions to valid if (!mImmutable && rehash) { - info_.txHash = txMap_.getHash().as_uint256(); - info_.accountHash = stateMap_.getHash().as_uint256(); + header_.txHash = txMap_.getHash().as_uint256(); + header_.accountHash = stateMap_.getHash().as_uint256(); } if (rehash) - info_.hash = calculateLedgerHash(info_); + header_.hash = calculateLedgerHash(header_); mImmutable = true; txMap_.setImmutable(); @@ -354,17 +314,14 @@ Ledger::setImmutable(bool rehash) } void -Ledger::setAccepted( - NetClock::time_point closeTime, - NetClock::duration closeResolution, - bool correctCloseTime) +Ledger::setAccepted(NetClock::time_point closeTime, NetClock::duration closeResolution, bool correctCloseTime) { // Used when we witnessed the consensus. - XRPL_ASSERT(!open(), "ripple::Ledger::setAccepted : valid ledger state"); + XRPL_ASSERT(!open(), "xrpl::Ledger::setAccepted : valid ledger state"); - info_.closeTime = closeTime; - info_.closeTimeResolution = closeResolution; - info_.closeFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime; + header_.closeTime = closeTime; + header_.closeTimeResolution = closeResolution; + header_.closeFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime; setImmutable(); } @@ -372,8 +329,7 @@ bool Ledger::addSLE(SLE const& sle) { auto const s = sle.getSerializer(); - return stateMap_.addItem( - SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle.key(), s.slice())); + return stateMap_.addItem(SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle.key(), s.slice())); } //------------------------------------------------------------------------------ @@ -388,8 +344,7 @@ deserializeTx(SHAMapItem const& item) std::pair, std::shared_ptr> deserializeTxPlusMeta(SHAMapItem const& item) { - std::pair, std::shared_ptr> - result; + std::pair, std::shared_ptr> result; SerialIter sit(item.slice()); { SerialIter s(sit.getSlice(sit.getVLDataLength())); @@ -434,7 +389,7 @@ Ledger::read(Keylet const& k) const if (k.key == beast::zero) { // LCOV_EXCL_START - UNREACHABLE("ripple::Ledger::read : zero key"); + UNREACHABLE("xrpl::Ledger::read : zero key"); return nullptr; // LCOV_EXCL_STOP } @@ -462,8 +417,7 @@ Ledger::slesEnd() const -> std::unique_ptr } auto -Ledger::slesUpperBound(uint256 const& key) const - -> std::unique_ptr +Ledger::slesUpperBound(uint256 const& key) const -> std::unique_ptr { return std::make_unique(stateMap_.upper_bound(key)); } @@ -532,9 +486,7 @@ Ledger::rawInsert(std::shared_ptr const& sle) { Serializer ss; sle->add(ss); - if (!stateMap_.addGiveItem( - SHAMapNodeType::tnACCOUNT_STATE, - make_shamapitem(sle->key(), ss.slice()))) + if (!stateMap_.addGiveItem(SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle->key(), ss.slice()))) LogicError("Ledger::rawInsert: key already exists"); } @@ -543,9 +495,7 @@ Ledger::rawReplace(std::shared_ptr const& sle) { Serializer ss; sle->add(ss); - if (!stateMap_.updateGiveItem( - SHAMapNodeType::tnACCOUNT_STATE, - make_shamapitem(sle->key(), ss.slice()))) + if (!stateMap_.updateGiveItem(SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle->key(), ss.slice()))) LogicError("Ledger::rawReplace: key not found"); } @@ -555,15 +505,13 @@ Ledger::rawTxInsert( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - XRPL_ASSERT( - metaData, "ripple::Ledger::rawTxInsert : non-null metadata input"); + XRPL_ASSERT(metaData, "xrpl::Ledger::rawTxInsert : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); s.addVL(txn->peekData()); s.addVL(metaData->peekData()); - if (!txMap_.addGiveItem( - SHAMapNodeType::tnTRANSACTION_MD, make_shamapitem(key, s.slice()))) + if (!txMap_.addGiveItem(SHAMapNodeType::tnTRANSACTION_MD, make_shamapitem(key, s.slice()))) LogicError("duplicate_tx: " + to_string(key)); } @@ -573,9 +521,7 @@ Ledger::rawTxInsertWithHash( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - XRPL_ASSERT( - metaData, - "ripple::Ledger::rawTxInsertWithHash : non-null metadata input"); + XRPL_ASSERT(metaData, "xrpl::Ledger::rawTxInsertWithHash : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); @@ -629,11 +575,8 @@ Ledger::setup() { auto const baseFeeXRP = sle->at(~sfBaseFeeDrops); auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops); - auto const reserveIncrementXRP = - sle->at(~sfReserveIncrementDrops); - auto assign = [&ret]( - XRPAmount& dest, - std::optional const& src) { + auto const reserveIncrementXRP = sle->at(~sfReserveIncrementDrops); + auto assign = [&ret](XRPAmount& dest, std::optional const& src) { if (src) { if (src->native()) @@ -671,9 +614,7 @@ Ledger::setup() void Ledger::defaultFees(Config const& config) { - XRPL_ASSERT( - fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0, - "ripple::Ledger::defaultFees : zero fees"); + XRPL_ASSERT(fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0, "xrpl::Ledger::defaultFees : zero fees"); if (fees_.base == 0) fees_.base = config.FEES.reference_fee; if (fees_.reserve == 0) @@ -698,8 +639,7 @@ hash_set Ledger::negativeUNL() const { hash_set negUnl; - if (auto sle = read(keylet::negativeUNL()); - sle && sle->isFieldPresent(sfDisabledValidators)) + if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfDisabledValidators)) { auto const& nUnlData = sle->getFieldArray(sfDisabledValidators); for (auto const& n : nUnlData) @@ -723,8 +663,7 @@ Ledger::negativeUNL() const std::optional Ledger::validatorToDisable() const { - if (auto sle = read(keylet::negativeUNL()); - sle && sle->isFieldPresent(sfValidatorToDisable)) + if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToDisable)) { auto d = sle->getFieldVL(sfValidatorToDisable); auto s = makeSlice(d); @@ -738,8 +677,7 @@ Ledger::validatorToDisable() const std::optional Ledger::validatorToReEnable() const { - if (auto sle = read(keylet::negativeUNL()); - sle && sle->isFieldPresent(sfValidatorToReEnable)) + if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToReEnable)) { auto d = sle->getFieldVL(sfValidatorToReEnable); auto s = makeSlice(d); @@ -770,8 +708,7 @@ Ledger::updateNegativeUNL() for (auto v : oldNUnl) { if (hasToReEnable && v.isFieldPresent(sfPublicKey) && - v.getFieldVL(sfPublicKey) == - sle->getFieldVL(sfValidatorToReEnable)) + v.getFieldVL(sfPublicKey) == sle->getFieldVL(sfValidatorToReEnable)) continue; newNUnl.push_back(v); } @@ -780,8 +717,7 @@ Ledger::updateNegativeUNL() if (hasToDisable) { newNUnl.push_back(STObject::makeInnerObject(sfDisabledValidator)); - newNUnl.back().setFieldVL( - sfPublicKey, sle->getFieldVL(sfValidatorToDisable)); + newNUnl.back().setFieldVL(sfPublicKey, sle->getFieldVL(sfValidatorToDisable)); newNUnl.back().setFieldU32(sfFirstLedgerSequence, seq()); } @@ -807,11 +743,10 @@ Ledger::walkLedger(beast::Journal j, bool parallel) const std::vector missingNodes1; std::vector missingNodes2; - if (stateMap_.getHash().isZero() && !info_.accountHash.isZero() && - !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr)) + if (stateMap_.getHash().isZero() && !header_.accountHash.isZero() && + !stateMap_.fetchRoot(SHAMapHash{header_.accountHash}, nullptr)) { - missingNodes1.emplace_back( - SHAMapType::STATE, SHAMapHash{info_.accountHash}); + missingNodes1.emplace_back(SHAMapType::STATE, SHAMapHash{header_.accountHash}); } else { @@ -830,11 +765,10 @@ Ledger::walkLedger(beast::Journal j, bool parallel) const } } - if (txMap_.getHash().isZero() && info_.txHash.isNonZero() && - !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr)) + if (txMap_.getHash().isZero() && header_.txHash.isNonZero() && + !txMap_.fetchRoot(SHAMapHash{header_.txHash}, nullptr)) { - missingNodes2.emplace_back( - SHAMapType::TRANSACTION, SHAMapHash{info_.txHash}); + missingNodes2.emplace_back(SHAMapType::TRANSACTION, SHAMapHash{header_.txHash}); } else { @@ -855,9 +789,8 @@ Ledger::walkLedger(beast::Journal j, bool parallel) const bool Ledger::assertSensible(beast::Journal ledgerJ) const { - if (info_.hash.isNonZero() && info_.accountHash.isNonZero() && - (info_.accountHash == stateMap_.getHash().as_uint256()) && - (info_.txHash == txMap_.getHash().as_uint256())) + if (header_.hash.isNonZero() && header_.accountHash.isNonZero() && + (header_.accountHash == stateMap_.getHash().as_uint256()) && (header_.txHash == txMap_.getHash().as_uint256())) { return true; } @@ -865,12 +798,12 @@ Ledger::assertSensible(beast::Journal ledgerJ) const // LCOV_EXCL_START Json::Value j = getJson({*this, {}}); - j[jss::accountTreeHash] = to_string(info_.accountHash); - j[jss::transTreeHash] = to_string(info_.txHash); + j[jss::accountTreeHash] = to_string(header_.accountHash); + j[jss::transTreeHash] = to_string(header_.txHash); JLOG(ledgerJ.fatal()) << "ledger is not sensible" << j; - UNREACHABLE("ripple::Ledger::assertSensible : ledger is not sensible"); + UNREACHABLE("xrpl::Ledger::assertSensible : ledger is not sensible"); return false; // LCOV_EXCL_STOP @@ -881,10 +814,10 @@ Ledger::assertSensible(beast::Journal ledgerJ) const void Ledger::updateSkipList() { - if (info_.seq == 0) // genesis ledger has no previous ledger + if (header_.seq == 0) // genesis ledger has no previous ledger return; - std::uint32_t prevIndex = info_.seq - 1; + std::uint32_t prevIndex = header_.seq - 1; // update record of every 256th ledger if ((prevIndex & 0xff) == 0) @@ -905,10 +838,8 @@ Ledger::updateSkipList() created = false; } - XRPL_ASSERT( - hashes.size() <= 256, - "ripple::Ledger::updateSkipList : first maximum hashes size"); - hashes.push_back(info_.parentHash); + XRPL_ASSERT(hashes.size() <= 256, "xrpl::Ledger::updateSkipList : first maximum hashes size"); + hashes.push_back(header_.parentHash); sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); if (created) @@ -932,12 +863,10 @@ Ledger::updateSkipList() hashes = static_cast(sle->getFieldV256(sfHashes)); created = false; } - XRPL_ASSERT( - hashes.size() <= 256, - "ripple::Ledger::updateSkipList : second maximum hashes size"); + XRPL_ASSERT(hashes.size() <= 256, "xrpl::Ledger::updateSkipList : second maximum hashes size"); if (hashes.size() == 256) hashes.erase(hashes.begin()); - hashes.push_back(info_.parentHash); + hashes.push_back(header_.parentHash); sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); if (created) @@ -949,12 +878,12 @@ Ledger::updateSkipList() bool Ledger::isFlagLedger() const { - return info_.seq % FLAG_LEDGER_INTERVAL == 0; + return header_.seq % FLAG_LEDGER_INTERVAL == 0; } bool Ledger::isVotingLedger() const { - return (info_.seq + 1) % FLAG_LEDGER_INTERVAL == 0; + return (header_.seq + 1) % FLAG_LEDGER_INTERVAL == 0; } bool @@ -964,13 +893,10 @@ isFlagLedger(LedgerIndex seq) } static bool -saveValidatedLedger( - Application& app, - std::shared_ptr const& ledger, - bool current) +saveValidatedLedger(Application& app, std::shared_ptr const& ledger, bool current) { auto j = app.journal("Ledger"); - auto seq = ledger->info().seq; + auto seq = ledger->header().seq; if (!app.pendingSaves().startWork(seq)) { // The save was completed synchronously @@ -978,11 +904,9 @@ saveValidatedLedger( return true; } - auto const db = dynamic_cast(&app.getRelationalDatabase()); - if (!db) - Throw("Failed to get relational database"); + auto& db = app.getRelationalDatabase(); - auto const res = db->saveValidatedLedger(ledger, current); + auto const res = db.saveValidatedLedger(ledger, current); // Clients can now trust the database for // information about this ledger sequence. @@ -994,20 +918,15 @@ saveValidatedLedger( Returns false on error */ bool -pendSaveValidated( - Application& app, - std::shared_ptr const& ledger, - bool isSynchronous, - bool isCurrent) +pendSaveValidated(Application& app, std::shared_ptr const& ledger, bool isSynchronous, bool isCurrent) { - if (!app.getHashRouter().setFlags( - ledger->info().hash, HashRouterFlags::SAVED)) + if (!app.getHashRouter().setFlags(ledger->header().hash, HashRouterFlags::SAVED)) { // We have tried to save this ledger recently auto stream = app.journal("Ledger").debug(); - JLOG(stream) << "Double pend save for " << ledger->info().seq; + JLOG(stream) << "Double pend save for " << ledger->header().seq; - if (!isSynchronous || !app.pendingSaves().pending(ledger->info().seq)) + if (!isSynchronous || !app.pendingSaves().pending(ledger->header().seq)) { // Either we don't need it to be finished // or it is finished @@ -1015,14 +934,12 @@ pendSaveValidated( } } - XRPL_ASSERT( - ledger->isImmutable(), "ripple::pendSaveValidated : immutable ledger"); + XRPL_ASSERT(ledger->isImmutable(), "xrpl::pendSaveValidated : immutable ledger"); - if (!app.pendingSaves().shouldWork(ledger->info().seq, isSynchronous)) + if (!app.pendingSaves().shouldWork(ledger->header().seq, isSynchronous)) { auto stream = app.journal("Ledger").debug(); - JLOG(stream) << "Pend save with seq in pending saves " - << ledger->info().seq; + JLOG(stream) << "Pend save with seq in pending saves " << ledger->header().seq; return true; } @@ -1030,9 +947,7 @@ pendSaveValidated( // See if we can use the JobQueue. if (!isSynchronous && app.getJobQueue().addJob( - isCurrent ? jtPUBLEDGER : jtPUBOLDLEDGER, - std::to_string(ledger->seq()), - [&app, ledger, isCurrent]() { + isCurrent ? jtPUBLEDGER : jtPUBOLDLEDGER, std::to_string(ledger->seq()), [&app, ledger, isCurrent]() { saveValidatedLedger(app, ledger, isCurrent); })) { @@ -1061,22 +976,17 @@ Ledger::invariants() const /* * Make ledger using info loaded from database. * - * @param LedgerInfo: Ledger information. + * @param LedgerHeader: Ledger information. * @param app: Link to the Application. * @param acquire: Acquire the ledger if not found locally. * @return Shared pointer to the ledger. */ std::shared_ptr -loadLedgerHelper(LedgerInfo const& info, Application& app, bool acquire) +loadLedgerHelper(LedgerHeader const& info, Application& app, bool acquire) { bool loaded; - auto ledger = std::make_shared( - info, - loaded, - acquire, - app.config(), - app.getNodeFamily(), - app.journal("Ledger")); + auto ledger = + std::make_shared(info, loaded, acquire, app.config(), app.getNodeFamily(), app.journal("Ledger")); if (!loaded) ledger.reset(); @@ -1085,21 +995,17 @@ loadLedgerHelper(LedgerInfo const& info, Application& app, bool acquire) } static void -finishLoadByIndexOrHash( - std::shared_ptr const& ledger, - Config const& config, - beast::Journal j) +finishLoadByIndexOrHash(std::shared_ptr const& ledger, Config const& config, beast::Journal j) { if (!ledger) return; XRPL_ASSERT( - ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees()), - "ripple::finishLoadByIndexOrHash : valid ledger fees"); + ledger->header().seq < XRP_LEDGER_EARLIEST_FEES || ledger->read(keylet::fees()), + "xrpl::finishLoadByIndexOrHash : valid ledger fees"); ledger->setImmutable(); - JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->info().hash); + JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->header().hash); ledger->setFull(); } @@ -1107,8 +1013,7 @@ finishLoadByIndexOrHash( std::tuple, std::uint32_t, uint256> getLatestLedger(Application& app) { - std::optional const info = - app.getRelationalDatabase().getNewestLedgerInfo(); + std::optional const info = app.getRelationalDatabase().getNewestLedgerInfo(); if (!info) return {std::shared_ptr(), {}, {}}; return {loadLedgerHelper(*info, app, true), info->seq, info->hash}; @@ -1117,8 +1022,7 @@ getLatestLedger(Application& app) std::shared_ptr loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire) { - if (std::optional info = - app.getRelationalDatabase().getLedgerInfoByIndex(ledgerIndex)) + if (std::optional info = app.getRelationalDatabase().getLedgerInfoByIndex(ledgerIndex)) { std::shared_ptr ledger = loadLedgerHelper(*info, app, acquire); finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger")); @@ -1130,17 +1034,14 @@ loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire) std::shared_ptr loadByHash(uint256 const& ledgerHash, Application& app, bool acquire) { - if (std::optional info = - app.getRelationalDatabase().getLedgerInfoByHash(ledgerHash)) + if (std::optional info = app.getRelationalDatabase().getLedgerInfoByHash(ledgerHash)) { std::shared_ptr ledger = loadLedgerHelper(*info, app, acquire); finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger")); - XRPL_ASSERT( - !ledger || ledger->info().hash == ledgerHash, - "ripple::loadByHash : ledger hash match if loaded"); + XRPL_ASSERT(!ledger || ledger->header().hash == ledgerHash, "xrpl::loadByHash : ledger hash match if loaded"); return ledger; } return {}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/Ledger.h b/src/xrpld/app/ledger/Ledger.h index 5b74ee242a..cbfbc0030f 100644 --- a/src/xrpld/app/ledger/Ledger.h +++ b/src/xrpld/app/ledger/Ledger.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { class Application; class Job; @@ -101,20 +81,16 @@ public: Amendments specified are enabled in the genesis ledger */ - Ledger( - create_genesis_t, - Config const& config, - std::vector const& amendments, - Family& family); + Ledger(create_genesis_t, Config const& config, std::vector const& amendments, Family& family); - Ledger(LedgerInfo const& info, Config const& config, Family& family); + Ledger(LedgerHeader const& info, Config const& config, Family& family); /** Used for ledgers loaded from JSON files @param acquire If true, acquires the ledger if not found locally */ Ledger( - LedgerInfo const& info, + LedgerHeader const& info, bool& loaded, bool acquire, Config const& config, @@ -130,11 +106,7 @@ public: Ledger(Ledger const& previous, NetClock::time_point closeTime); // used for database ledgers - Ledger( - std::uint32_t ledgerSeq, - NetClock::time_point closeTime, - Config const& config, - Family& family); + Ledger(std::uint32_t ledgerSeq, NetClock::time_point closeTime, Config const& config, Family& family); ~Ledger() = default; @@ -148,16 +120,16 @@ public: return false; } - LedgerInfo const& - info() const override + LedgerHeader const& + header() const override { - return info_; + return header_; } void - setLedgerInfo(LedgerInfo const& info) + setLedgerInfo(LedgerHeader const& info) { - info_ = info; + header_ = info; } Fees const& @@ -179,8 +151,7 @@ public: exists(uint256 const& key) const; std::optional - succ(uint256 const& key, std::optional const& last = std::nullopt) - const override; + succ(uint256 const& key, std::optional const& last = std::nullopt) const override; std::shared_ptr read(Keylet const& k) const override; @@ -232,7 +203,7 @@ public: void rawDestroyXRP(XRPAmount const& fee) override { - info_.drops -= fee; + header_.drops -= fee; } // @@ -263,14 +234,11 @@ public: void setValidated() const { - info_.validated = true; + header_.validated = true; } void - setAccepted( - NetClock::time_point closeTime, - NetClock::duration closeResolution, - bool correctCloseTime); + setAccepted(NetClock::time_point closeTime, NetClock::duration closeResolution, bool correctCloseTime); void setImmutable(bool rehash = true); @@ -295,15 +263,15 @@ public: setFull() const { txMap_.setFull(); - txMap_.setLedgerSeq(info_.seq); + txMap_.setLedgerSeq(header_.seq); stateMap_.setFull(); - stateMap_.setLedgerSeq(info_.seq); + stateMap_.setLedgerSeq(header_.seq); } void setTotalDrops(std::uint64_t totDrops) { - info_.drops = totDrops; + header_.drops = totDrops; } SHAMap const& @@ -416,7 +384,7 @@ private: Fees fees_; Rules rules_; - LedgerInfo info_; + LedgerHeader header_; beast::Journal j_; }; @@ -435,14 +403,10 @@ isFlagLedger(LedgerIndex seq); //------------------------------------------------------------------------------ extern bool -pendSaveValidated( - Application& app, - std::shared_ptr const& ledger, - bool isSynchronous, - bool isCurrent); +pendSaveValidated(Application& app, std::shared_ptr const& ledger, bool isSynchronous, bool isCurrent); std::shared_ptr -loadLedgerHelper(LedgerInfo const& sinfo, Application& app, bool acquire); +loadLedgerHelper(LedgerHeader const& sinfo, Application& app, bool acquire); std::shared_ptr loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire = true); @@ -476,8 +440,6 @@ std::pair, std::shared_ptr> deserializeTxPlusMeta(SHAMapItem const& item); uint256 -calculateLedgerHash(LedgerInfo const& info); +calculateLedgerHash(LedgerHeader const& info); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerCleaner.h b/src/xrpld/app/ledger/LedgerCleaner.h index b086e02134..aa8d042c24 100644 --- a/src/xrpld/app/ledger/LedgerCleaner.h +++ b/src/xrpld/app/ledger/LedgerCleaner.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERCLEANER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERCLEANER_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Check the ledger/transaction databases to make sure they have continuity */ class LedgerCleaner : public beast::PropertyStream::Source @@ -62,6 +42,4 @@ public: std::unique_ptr make_LedgerCleaner(Application& app, beast::Journal journal); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index ccec209bd4..50fe56fd90 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,13 +6,11 @@ #include #include -namespace ripple { +namespace xrpl { // FIXME: Need to clean up ledgers by index at some point -LedgerHistory::LedgerHistory( - beast::insight::Collector::ptr const& collector, - Application& app) +LedgerHistory::LedgerHistory(beast::insight::Collector::ptr const& collector, Application& app) : app_(app) , collector_(collector) , mismatch_counter_(collector->make_counter("ledger.history", "mismatch")) @@ -41,34 +20,24 @@ LedgerHistory::LedgerHistory( std::chrono::seconds{app_.config().getValueFor(SizedItem::ledgerAge)}, stopwatch(), app_.journal("TaggedCache")) - , m_consensus_validated( - "ConsensusValidated", - 64, - std::chrono::minutes{5}, - stopwatch(), - app_.journal("TaggedCache")) + , m_consensus_validated("ConsensusValidated", 64, std::chrono::minutes{5}, stopwatch(), app_.journal("TaggedCache")) , j_(app.journal("LedgerHistory")) { } bool -LedgerHistory::insert( - std::shared_ptr const& ledger, - bool validated) +LedgerHistory::insert(std::shared_ptr const& ledger, bool validated) { if (!ledger->isImmutable()) LogicError("mutable Ledger in insert"); - XRPL_ASSERT( - ledger->stateMap().getHash().isNonZero(), - "ripple::LedgerHistory::insert : nonzero hash"); + XRPL_ASSERT(ledger->stateMap().getHash().isNonZero(), "xrpl::LedgerHistory::insert : nonzero hash"); std::unique_lock sl(m_ledgers_by_hash.peekMutex()); - bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache( - ledger->info().hash, ledger); + bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache(ledger->header().hash, ledger); if (validated) - mLedgersByIndex[ledger->info().seq] = ledger->info().hash; + mLedgersByIndex[ledger->header().seq] = ledger->header().hash; return alreadyHad; } @@ -102,20 +71,16 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index) if (!ret) return ret; - XRPL_ASSERT( - ret->info().seq == index, - "ripple::LedgerHistory::getLedgerBySeq : result sequence match"); + XRPL_ASSERT(ret->header().seq == index, "xrpl::LedgerHistory::getLedgerBySeq : result sequence match"); { // Add this ledger to the local tracking by index std::unique_lock sl(m_ledgers_by_hash.peekMutex()); - XRPL_ASSERT( - ret->isImmutable(), - "ripple::LedgerHistory::getLedgerBySeq : immutable result ledger"); - m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); - mLedgersByIndex[ret->info().seq] = ret->info().hash; - return (ret->info().seq == index) ? ret : nullptr; + XRPL_ASSERT(ret->isImmutable(), "xrpl::LedgerHistory::getLedgerBySeq : immutable result ledger"); + m_ledgers_by_hash.canonicalize_replace_client(ret->header().hash, ret); + mLedgersByIndex[ret->header().seq] = ret->header().hash; + return (ret->header().seq == index) ? ret : nullptr; } } @@ -128,11 +93,11 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) { XRPL_ASSERT( ret->isImmutable(), - "ripple::LedgerHistory::getLedgerByHash : immutable fetched " + "xrpl::LedgerHistory::getLedgerByHash : immutable fetched " "ledger"); XRPL_ASSERT( - ret->info().hash == hash, - "ripple::LedgerHistory::getLedgerByHash : fetched ledger hash " + ret->header().hash == hash, + "xrpl::LedgerHistory::getLedgerByHash : fetched ledger hash " "match"); return ret; } @@ -142,48 +107,32 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) if (!ret) return ret; - XRPL_ASSERT( - ret->isImmutable(), - "ripple::LedgerHistory::getLedgerByHash : immutable loaded ledger"); - XRPL_ASSERT( - ret->info().hash == hash, - "ripple::LedgerHistory::getLedgerByHash : loaded ledger hash match"); - m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); - XRPL_ASSERT( - ret->info().hash == hash, - "ripple::LedgerHistory::getLedgerByHash : result hash match"); + XRPL_ASSERT(ret->isImmutable(), "xrpl::LedgerHistory::getLedgerByHash : immutable loaded ledger"); + XRPL_ASSERT(ret->header().hash == hash, "xrpl::LedgerHistory::getLedgerByHash : loaded ledger hash match"); + m_ledgers_by_hash.canonicalize_replace_client(ret->header().hash, ret); + XRPL_ASSERT(ret->header().hash == hash, "xrpl::LedgerHistory::getLedgerByHash : result hash match"); return ret; } static void -log_one( - ReadView const& ledger, - uint256 const& tx, - char const* msg, - beast::Journal& j) +log_one(ReadView const& ledger, uint256 const& tx, char const* msg, beast::Journal& j) { auto metaData = ledger.txRead(tx).second; if (metaData != nullptr) { - JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg - << " is missing this transaction:\n" + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg << " is missing this transaction:\n" << metaData->getJson(JsonOptions::none); } else { - JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg - << " is missing this transaction."; + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg << " is missing this transaction."; } } static void -log_metadata_difference( - ReadView const& builtLedger, - ReadView const& validLedger, - uint256 const& tx, - beast::Journal j) +log_metadata_difference(ReadView const& builtLedger, ReadView const& validLedger, uint256 const& tx, beast::Journal j) { auto getMeta = [](ReadView const& ledger, uint256 const& txID) { std::optional ret; @@ -195,27 +144,22 @@ log_metadata_difference( auto validMetaData = getMeta(validLedger, tx); auto builtMetaData = getMeta(builtLedger, tx); - XRPL_ASSERT( - validMetaData || builtMetaData, - "ripple::log_metadata_difference : some metadata present"); + XRPL_ASSERT(validMetaData || builtMetaData, "xrpl::log_metadata_difference : some metadata present"); if (validMetaData && builtMetaData) { auto const& validNodes = validMetaData->getNodes(); auto const& builtNodes = builtMetaData->getNodes(); - bool const result_diff = - validMetaData->getResultTER() != builtMetaData->getResultTER(); + bool const result_diff = validMetaData->getResultTER() != builtMetaData->getResultTER(); - bool const index_diff = - validMetaData->getIndex() != builtMetaData->getIndex(); + bool const index_diff = validMetaData->getIndex() != builtMetaData->getIndex(); bool const nodes_diff = validNodes != builtNodes; if (!result_diff && !index_diff && !nodes_diff) { - JLOG(j.error()) << "MISMATCH on TX " << tx - << ": No apparent mismatches detected!"; + JLOG(j.error()) << "MISMATCH on TX " << tx << ": No apparent mismatches detected!"; return; } @@ -223,19 +167,15 @@ log_metadata_difference( { if (result_diff && index_diff) { - JLOG(j.debug()) << "MISMATCH on TX " << tx - << ": Different result and index!"; + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result and index!"; JLOG(j.debug()) << " Built:" - << " Result: " << builtMetaData->getResult() - << " Index: " << builtMetaData->getIndex(); + << " Result: " << builtMetaData->getResult() << " Index: " << builtMetaData->getIndex(); JLOG(j.debug()) << " Valid:" - << " Result: " << validMetaData->getResult() - << " Index: " << validMetaData->getIndex(); + << " Result: " << validMetaData->getResult() << " Index: " << validMetaData->getIndex(); } else if (result_diff) { - JLOG(j.debug()) - << "MISMATCH on TX " << tx << ": Different result!"; + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result!"; JLOG(j.debug()) << " Built:" << " Result: " << builtMetaData->getResult(); JLOG(j.debug()) << " Valid:" @@ -243,8 +183,7 @@ log_metadata_difference( } else if (index_diff) { - JLOG(j.debug()) - << "MISMATCH on TX " << tx << ": Different index!"; + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different index!"; JLOG(j.debug()) << " Built:" << " Index: " << builtMetaData->getIndex(); JLOG(j.debug()) << " Valid:" @@ -255,43 +194,33 @@ log_metadata_difference( { if (result_diff && index_diff) { - JLOG(j.debug()) << "MISMATCH on TX " << tx - << ": Different result, index and nodes!"; - JLOG(j.debug()) << " Built:\n" - << builtMetaData->getJson(JsonOptions::none); - JLOG(j.debug()) << " Valid:\n" - << validMetaData->getJson(JsonOptions::none); + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result, index and nodes!"; + JLOG(j.debug()) << " Built:\n" << builtMetaData->getJson(JsonOptions::none); + JLOG(j.debug()) << " Valid:\n" << validMetaData->getJson(JsonOptions::none); } else if (result_diff) { - JLOG(j.debug()) << "MISMATCH on TX " << tx - << ": Different result and nodes!"; - JLOG(j.debug()) - << " Built:" - << " Result: " << builtMetaData->getResult() << " Nodes:\n" - << builtNodes.getJson(JsonOptions::none); - JLOG(j.debug()) - << " Valid:" - << " Result: " << validMetaData->getResult() << " Nodes:\n" - << validNodes.getJson(JsonOptions::none); + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result and nodes!"; + JLOG(j.debug()) << " Built:" + << " Result: " << builtMetaData->getResult() << " Nodes:\n" + << builtNodes.getJson(JsonOptions::none); + JLOG(j.debug()) << " Valid:" + << " Result: " << validMetaData->getResult() << " Nodes:\n" + << validNodes.getJson(JsonOptions::none); } else if (index_diff) { - JLOG(j.debug()) << "MISMATCH on TX " << tx - << ": Different index and nodes!"; - JLOG(j.debug()) - << " Built:" - << " Index: " << builtMetaData->getIndex() << " Nodes:\n" - << builtNodes.getJson(JsonOptions::none); - JLOG(j.debug()) - << " Valid:" - << " Index: " << validMetaData->getIndex() << " Nodes:\n" - << validNodes.getJson(JsonOptions::none); + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different index and nodes!"; + JLOG(j.debug()) << " Built:" + << " Index: " << builtMetaData->getIndex() << " Nodes:\n" + << builtNodes.getJson(JsonOptions::none); + JLOG(j.debug()) << " Valid:" + << " Index: " << validMetaData->getIndex() << " Nodes:\n" + << validNodes.getJson(JsonOptions::none); } else // nodes_diff { - JLOG(j.debug()) - << "MISMATCH on TX " << tx << ": Different nodes!"; + JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different nodes!"; JLOG(j.debug()) << " Built:" << " Nodes:\n" << builtNodes.getJson(JsonOptions::none); @@ -306,15 +235,13 @@ log_metadata_difference( if (validMetaData) { - JLOG(j.error()) << "MISMATCH on TX " << tx - << ": Metadata Difference. Valid=\n" + JLOG(j.error()) << "MISMATCH on TX " << tx << ": Metadata Difference. Valid=\n" << validMetaData->getJson(JsonOptions::none); } if (builtMetaData) { - JLOG(j.error()) << "MISMATCH on TX " << tx - << ": Metadata Difference. Built=\n" + JLOG(j.error()) << "MISMATCH on TX " << tx << ": Metadata Difference. Built=\n" << builtMetaData->getJson(JsonOptions::none); } } @@ -328,10 +255,7 @@ leaves(SHAMap const& sm) std::vector v; for (auto const& item : sm) v.push_back(&item); - std::sort( - v.begin(), v.end(), [](SHAMapItem const* lhs, SHAMapItem const* rhs) { - return lhs->key() < rhs->key(); - }); + std::sort(v.begin(), v.end(), [](SHAMapItem const* lhs, SHAMapItem const* rhs) { return lhs->key() < rhs->key(); }); return v; } @@ -343,9 +267,7 @@ LedgerHistory::handleMismatch( std::optional const& validatedConsensusHash, Json::Value const& consensus) { - XRPL_ASSERT( - built != valid, - "ripple::LedgerHistory::handleMismatch : unequal hashes"); + XRPL_ASSERT(built != valid, "xrpl::LedgerHistory::handleMismatch : unequal hashes"); ++mismatch_counter_; auto builtLedger = getLedgerByHash(built); @@ -354,15 +276,13 @@ LedgerHistory::handleMismatch( if (!builtLedger || !validLedger) { JLOG(j_.error()) << "MISMATCH cannot be analyzed:" - << " builtLedger: " << to_string(built) << " -> " - << builtLedger << " validLedger: " << to_string(valid) - << " -> " << validLedger; + << " builtLedger: " << to_string(built) << " -> " << builtLedger + << " validLedger: " << to_string(valid) << " -> " << validLedger; return; } XRPL_ASSERT( - builtLedger->info().seq == validLedger->info().seq, - "ripple::LedgerHistory::handleMismatch : sequence match"); + builtLedger->header().seq == validLedger->header().seq, "xrpl::LedgerHistory::handleMismatch : sequence match"); if (auto stream = j_.debug()) { @@ -375,14 +295,14 @@ LedgerHistory::handleMismatch( // failure from transaction processing difference // Disagreement over prior ledger indicates sync issue - if (builtLedger->info().parentHash != validLedger->info().parentHash) + if (builtLedger->header().parentHash != validLedger->header().parentHash) { JLOG(j_.error()) << "MISMATCH on prior ledger"; return; } // Disagreement over close time indicates Byzantine failure - if (builtLedger->info().closeTime != validLedger->info().closeTime) + if (builtLedger->header().closeTime != validLedger->header().closeTime) { JLOG(j_.error()) << "MISMATCH on close time"; return; @@ -391,13 +311,11 @@ LedgerHistory::handleMismatch( if (builtConsensusHash && validatedConsensusHash) { if (builtConsensusHash != validatedConsensusHash) - JLOG(j_.error()) - << "MISMATCH on consensus transaction set " - << " built: " << to_string(*builtConsensusHash) - << " validated: " << to_string(*validatedConsensusHash); + JLOG(j_.error()) << "MISMATCH on consensus transaction set " + << " built: " << to_string(*builtConsensusHash) + << " validated: " << to_string(*validatedConsensusHash); else - JLOG(j_.error()) << "MISMATCH with same consensus transaction set: " - << to_string(*builtConsensusHash); + JLOG(j_.error()) << "MISMATCH with same consensus transaction set: " << to_string(*builtConsensusHash); } // Find differences between built and valid ledgers @@ -405,11 +323,10 @@ LedgerHistory::handleMismatch( auto const validTx = leaves(validLedger->txMap()); if (builtTx == validTx) - JLOG(j_.error()) << "MISMATCH with same " << builtTx.size() - << " transactions"; + JLOG(j_.error()) << "MISMATCH with same " << builtTx.size() << " transactions"; else - JLOG(j_.error()) << "MISMATCH with " << builtTx.size() << " built and " - << validTx.size() << " valid transactions."; + JLOG(j_.error()) << "MISMATCH with " << builtTx.size() << " built and " << validTx.size() + << " valid transactions."; JLOG(j_.error()) << "built\n" << getJson({*builtLedger, {}}); JLOG(j_.error()) << "valid\n" << getJson({*validLedger, {}}); @@ -434,8 +351,7 @@ LedgerHistory::handleMismatch( if ((*b)->slice() != (*v)->slice()) { // Same transaction with different metadata - log_metadata_difference( - *builtLedger, *validLedger, (*b)->key(), j_); + log_metadata_difference(*builtLedger, *validLedger, (*b)->key(), j_); } ++b; ++v; @@ -453,10 +369,9 @@ LedgerHistory::builtLedger( uint256 const& consensusHash, Json::Value consensus) { - LedgerIndex index = ledger->info().seq; - LedgerHash hash = ledger->info().hash; - XRPL_ASSERT( - !hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash"); + LedgerIndex index = ledger->header().seq; + LedgerHash hash = ledger->header().hash; + XRPL_ASSERT(!hash.isZero(), "xrpl::LedgerHistory::builtLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); @@ -467,15 +382,9 @@ LedgerHistory::builtLedger( { if (entry->validated.value() != hash) { - JLOG(j_.error()) << "MISMATCH: seq=" << index - << " validated:" << entry->validated.value() + JLOG(j_.error()) << "MISMATCH: seq=" << index << " validated:" << entry->validated.value() << " then:" << hash; - handleMismatch( - hash, - entry->validated.value(), - consensusHash, - entry->validatedConsensusHash, - consensus); + handleMismatch(hash, entry->validated.value(), consensusHash, entry->validatedConsensusHash, consensus); } else { @@ -490,15 +399,11 @@ LedgerHistory::builtLedger( } void -LedgerHistory::validatedLedger( - std::shared_ptr const& ledger, - std::optional const& consensusHash) +LedgerHistory::validatedLedger(std::shared_ptr const& ledger, std::optional const& consensusHash) { - LedgerIndex index = ledger->info().seq; - LedgerHash hash = ledger->info().hash; - XRPL_ASSERT( - !hash.isZero(), - "ripple::LedgerHistory::validatedLedger : nonzero hash"); + LedgerIndex index = ledger->header().seq; + LedgerHash hash = ledger->header().hash; + XRPL_ASSERT(!hash.isZero(), "xrpl::LedgerHistory::validatedLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); @@ -509,15 +414,9 @@ LedgerHistory::validatedLedger( { if (entry->built.value() != hash) { - JLOG(j_.error()) - << "MISMATCH: seq=" << index - << " built:" << entry->built.value() << " then:" << hash; + JLOG(j_.error()) << "MISMATCH: seq=" << index << " built:" << entry->built.value() << " then:" << hash; handleMismatch( - entry->built.value(), - hash, - entry->builtConsensusHash, - consensusHash, - entry->consensus.value()); + entry->built.value(), hash, entry->builtConsensusHash, consensusHash, entry->consensus.value()); } else { @@ -552,9 +451,9 @@ LedgerHistory::clearLedgerCachePrior(LedgerIndex seq) for (LedgerHash it : m_ledgers_by_hash.getKeys()) { auto const ledger = getLedgerByHash(it); - if (!ledger || ledger->info().seq < seq) + if (!ledger || ledger->header().seq < seq) m_ledgers_by_hash.del(it, false); } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerHistory.h b/src/xrpld/app/ledger/LedgerHistory.h index 33f8bf1d96..e8784eb599 100644 --- a/src/xrpld/app/ledger/LedgerHistory.h +++ b/src/xrpld/app/ledger/LedgerHistory.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERHISTORY_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERHISTORY_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include -namespace ripple { +namespace xrpl { // VFALCO TODO Rename to OldLedgers ? @@ -36,9 +16,7 @@ namespace ripple { class LedgerHistory { public: - LedgerHistory( - beast::insight::Collector::ptr const& collector, - Application& app); + LedgerHistory(beast::insight::Collector::ptr const& collector, Application& app); /** Track a ledger @return `true` if the ledger was already tracked @@ -81,16 +59,11 @@ public: /** Report that we have locally built a particular ledger */ void - builtLedger( - std::shared_ptr const&, - uint256 const& consensusHash, - Json::Value); + builtLedger(std::shared_ptr const&, uint256 const& consensusHash, Json::Value); /** Report that we have validated a particular ledger */ void - validatedLedger( - std::shared_ptr const&, - std::optional const& consensusHash); + validatedLedger(std::shared_ptr const&, std::optional const& consensusHash); /** Repair a hash to index mapping @param ledgerIndex The index whose mapping is to be repaired @@ -154,6 +127,4 @@ private: beast::Journal j_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerHolder.h b/src/xrpld/app/ledger/LedgerHolder.h index c0c9d74f46..8d2ac9f308 100644 --- a/src/xrpld/app/ledger/LedgerHolder.h +++ b/src/xrpld/app/ledger/LedgerHolder.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERHOLDER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERHOLDER_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // Can std::atomic> make this lock free? @@ -72,6 +52,4 @@ private: std::shared_ptr m_heldLedger; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerMaster.h b/src/xrpld/app/ledger/LedgerMaster.h index 5e0598d78b..ceb9fa9045 100644 --- a/src/xrpld/app/ledger/LedgerMaster.h +++ b/src/xrpld/app/ledger/LedgerMaster.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED +#pragma once #include #include @@ -40,7 +20,7 @@ #include #include -namespace ripple { +namespace xrpl { class Peer; class Transaction; @@ -108,10 +88,7 @@ public: storeLedger(std::shared_ptr ledger); void - setFullLedger( - std::shared_ptr const& ledger, - bool isSynchronous, - bool isCurrent); + setFullLedger(std::shared_ptr const& ledger, bool isSynchronous, bool isCurrent); /** Check the sequence number and parent close time of a ledger against our clock and last validated ledger to @@ -208,10 +185,7 @@ public: void checkAccept(uint256 const& hash, std::uint32_t seq); void - consensusBuilt( - std::shared_ptr const& ledger, - uint256 const& consensusHash, - Json::Value consensus); + consensusBuilt(std::shared_ptr const& ledger, uint256 const& consensusHash, Json::Value consensus); void setBuildingLedger(LedgerIndex index); @@ -357,8 +331,7 @@ private: int mPathFindThread{0}; // Pathfinder jobs dispatched bool mPathFindNewRequest{false}; - std::atomic_flag mGotFetchPackThread = - ATOMIC_FLAG_INIT; // GotFetchPack jobs dispatched + std::atomic_flag mGotFetchPackThread = ATOMIC_FLAG_INIT; // GotFetchPack jobs dispatched std::atomic mPubLedgerClose{0}; std::atomic mPubLedgerSeq{0}; @@ -392,14 +365,10 @@ private: struct Stats { template - Stats( - Handler const& handler, - beast::insight::Collector::ptr const& collector) + Stats(Handler const& handler, beast::insight::Collector::ptr const& collector) : hook(collector->make_hook(handler)) - , validatedLedgerAge( - collector->make_gauge("LedgerMaster", "Validated_Ledger_Age")) - , publishedLedgerAge( - collector->make_gauge("LedgerMaster", "Published_Ledger_Age")) + , validatedLedgerAge(collector->make_gauge("LedgerMaster", "Validated_Ledger_Age")) + , publishedLedgerAge(collector->make_gauge("LedgerMaster", "Published_Ledger_Age")) { } @@ -420,6 +389,4 @@ private: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerReplay.h b/src/xrpld/app/ledger/LedgerReplay.h index a3bdedf821..f4cbf9c69e 100644 --- a/src/xrpld/app/ledger/LedgerReplay.h +++ b/src/xrpld/app/ledger/LedgerReplay.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { class Ledger; class STTx; @@ -37,9 +17,7 @@ class LedgerReplay : public CountedObject std::map> orderedTxns_; public: - LedgerReplay( - std::shared_ptr parent, - std::shared_ptr replay); + LedgerReplay(std::shared_ptr parent, std::shared_ptr replay); LedgerReplay( std::shared_ptr parent, @@ -71,6 +49,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerReplayTask.h b/src/xrpld/app/ledger/LedgerReplayTask.h index 03110d8442..94eeee5f51 100644 --- a/src/xrpld/app/ledger/LedgerReplayTask.h +++ b/src/xrpld/app/ledger/LedgerReplayTask.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYTASK_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERREPLAYTASK_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { class InboundLedgers; class Ledger; class LedgerDeltaAcquire; @@ -36,10 +16,9 @@ namespace test { class LedgerReplayClient; } // namespace test -class LedgerReplayTask final - : public TimeoutCounter, - public std::enable_shared_from_this, - public CountedObject +class LedgerReplayTask final : public TimeoutCounter, + public std::enable_shared_from_this, + public CountedObject { public: class TaskParameter @@ -63,10 +42,7 @@ public: * @param finishLedgerHash hash of the last ledger in the range * @param totalNumLedgers number of ledgers to download */ - TaskParameter( - InboundLedger::Reason r, - uint256 const& finishLedgerHash, - std::uint32_t totalNumLedgers); + TaskParameter(InboundLedger::Reason r, uint256 const& finishLedgerHash, std::uint32_t totalNumLedgers); /** * fill all the fields that was not filled during construction @@ -78,10 +54,7 @@ public: * true on success */ bool - update( - uint256 const& hash, - std::uint32_t seq, - std::vector const& sList); + update(uint256 const& hash, std::uint32_t seq, std::vector const& sList); /** check if this task can be merged into an existing task */ bool @@ -142,10 +115,7 @@ private: * @param sList skip list */ void - updateSkipList( - uint256 const& hash, - std::uint32_t seq, - std::vector const& sList); + updateSkipList(uint256 const& hash, std::uint32_t seq, std::vector const& sList); /** * Notify this task (by a LedgerDeltaAcquire subtask) that a delta is ready @@ -180,6 +150,4 @@ private: friend class test::LedgerReplayClient; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerReplayer.h b/src/xrpld/app/ledger/LedgerReplayer.h index b00430303a..0d08e5a76f 100644 --- a/src/xrpld/app/ledger/LedgerReplayer.h +++ b/src/xrpld/app/ledger/LedgerReplayer.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERREPLAYER_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace test { class LedgerReplayClient; @@ -72,10 +52,7 @@ std::uint32_t constexpr MAX_QUEUED_TASKS = 100; class LedgerReplayer final { public: - LedgerReplayer( - Application& app, - InboundLedgers& inboundLedgers, - std::unique_ptr peerSetBuilder); + LedgerReplayer(Application& app, InboundLedgers& inboundLedgers, std::unique_ptr peerSetBuilder); ~LedgerReplayer(); @@ -87,10 +64,7 @@ public: * @note totalNumLedgers must > 0 && totalNumLedgers must <= 256 */ void - replay( - InboundLedger::Reason r, - uint256 const& finishLedgerHash, - std::uint32_t totalNumLedgers); + replay(InboundLedger::Reason r, uint256 const& finishLedgerHash, std::uint32_t totalNumLedgers); /** Create LedgerDeltaAcquire subtasks for the LedgerReplayTask task */ void @@ -103,9 +77,7 @@ public: * @note info and data must have been verified against the ledger hash */ void - gotSkipList( - LedgerInfo const& info, - boost::intrusive_ptr const& data); + gotSkipList(LedgerHeader const& info, boost::intrusive_ptr const& data); /** * Process a ledger delta (extracted from a TMReplayDeltaResponse message) @@ -114,9 +86,7 @@ public: * @note info and txns must have been verified against the ledger hash */ void - gotReplayDelta( - LedgerInfo const& info, - std::map>&& txns); + gotReplayDelta(LedgerHeader const& info, std::map>&& txns); /** Remove completed tasks */ void @@ -160,6 +130,4 @@ private: friend class test::LedgerReplayClient; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LedgerToJson.h b/src/xrpld/app/ledger/LedgerToJson.h index be017bca86..8cde134d23 100644 --- a/src/xrpld/app/ledger/LedgerToJson.h +++ b/src/xrpld/app/ledger/LedgerToJson.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERTOJSON_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERTOJSON_H_INCLUDED +#pragma once #include #include @@ -26,45 +6,31 @@ #include #include -#include #include -namespace ripple { +namespace xrpl { struct LedgerFill { - LedgerFill( - ReadView const& l, - RPC::Context* ctx, - int o = 0, - std::vector q = {}) + LedgerFill(ReadView const& l, RPC::Context const* ctx, int o = 0, std::vector q = {}) : ledger(l), options(o), txQueue(std::move(q)), context(ctx) { if (context) closeTime = context->ledgerMaster.getCloseTimeBySeq(ledger.seq()); } - enum Options { - dumpTxrp = 1, - dumpState = 2, - expand = 4, - full = 8, - binary = 16, - ownerFunds = 32, - dumpQueue = 64 - }; + enum Options { dumpTxrp = 1, dumpState = 2, expand = 4, full = 8, binary = 16, ownerFunds = 32, dumpQueue = 64 }; ReadView const& ledger; int options; std::vector txQueue; - RPC::Context* context; + RPC::Context const* context; std::optional closeTime; }; -/** Given a Ledger and options, fill a Json::Object or Json::Value with a +/** Given a Ledger and options, fill a Json::Value with a description of the ledger. */ - void addJson(Json::Value&, LedgerFill const&); @@ -72,6 +38,8 @@ addJson(Json::Value&, LedgerFill const&); Json::Value getJson(LedgerFill const&); -} // namespace ripple +/** Copy all the keys and values from one object into another. */ +void +copyFrom(Json::Value& to, Json::Value const& from); -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/LocalTxs.h b/src/xrpld/app/ledger/LocalTxs.h index 2d202a5b60..34dfede40f 100644 --- a/src/xrpld/app/ledger/LocalTxs.h +++ b/src/xrpld/app/ledger/LocalTxs.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LOCALTXS_H_INCLUDED -#define RIPPLE_APP_LEDGER_LOCALTXS_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { // Track transactions issued by local clients // Ensure we always apply them to our open ledger @@ -61,6 +41,4 @@ public: std::unique_ptr make_LocalTxs(); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/OpenLedger.h b/src/xrpld/app/ledger/OpenLedger.h index 9383a53575..187086862c 100644 --- a/src/xrpld/app/ledger/OpenLedger.h +++ b/src/xrpld/app/ledger/OpenLedger.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED -#define RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include -namespace ripple { +namespace xrpl { // How many total extra passes we make // We must ensure we make at least one non-retriable pass @@ -80,10 +60,7 @@ public: @param ledger A closed ledger */ - explicit OpenLedger( - std::shared_ptr const& ledger, - CachedSLEs& cache, - beast::Journal journal); + explicit OpenLedger(std::shared_ptr const& ledger, CachedSLEs& cache, beast::Journal journal); /** Returns `true` if there are no transactions. @@ -232,8 +209,7 @@ OpenLedger::apply( } catch (std::exception const& e) { - JLOG(j.error()) - << "OpenLedger::apply: Caught exception: " << e.what(); + JLOG(j.error()) << "OpenLedger::apply: Caught exception: " << e.what(); } } bool retry = true; @@ -265,8 +241,7 @@ OpenLedger::apply( // If there are any transactions left, we must have // tried them in at least one final pass - XRPL_ASSERT( - retries.empty() || !retry, "ripple::OpenLedger::apply : valid retries"); + XRPL_ASSERT(retries.empty() || !retry, "xrpl::OpenLedger::apply : valid retries"); } //------------------------------------------------------------------------------ @@ -285,6 +260,4 @@ debugTostr(SHAMap const& set); std::string debugTostr(std::shared_ptr const& view); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/OrderBookDB.cpp b/src/xrpld/app/ledger/OrderBookDB.cpp index 433a993772..81a3bf5e4a 100644 --- a/src/xrpld/app/ledger/OrderBookDB.cpp +++ b/src/xrpld/app/ledger/OrderBookDB.cpp @@ -1,37 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include +#include #include -namespace ripple { +namespace xrpl { -OrderBookDB::OrderBookDB(Application& app) - : app_(app), seq_(0), j_(app.journal("OrderBookDB")) +OrderBookDB::OrderBookDB(Application& app) : app_(app), seq_(0), j_(app.journal("OrderBookDB")) { } @@ -58,18 +38,14 @@ OrderBookDB::setup(std::shared_ptr const& ledger) if (seq_.exchange(ledger->seq()) != seq) return; - JLOG(j_.debug()) << "Full order book update: " << seq << " to " - << ledger->seq(); + JLOG(j_.debug()) << "Full order book update: " << seq << " to " << ledger->seq(); if (app_.config().PATH_SEARCH_MAX != 0) { if (app_.config().standalone()) update(ledger); else - app_.getJobQueue().addJob( - jtUPDATE_PF, - "OrderBookDB::update: " + std::to_string(ledger->seq()), - [this, ledger]() { update(ledger); }); + app_.getJobQueue().addJob(jtUPDATE_PF, "OrderBookUpd", [this, ledger]() { update(ledger); }); } } @@ -82,8 +58,7 @@ OrderBookDB::update(std::shared_ptr const& ledger) // A newer full update job is pending if (auto const seq = seq_.load(); seq > ledger->seq()) { - JLOG(j_.debug()) << "Eliding update for " << ledger->seq() - << " because of pending update to later " << seq; + JLOG(j_.debug()) << "Eliding update for " << ledger->seq() << " because of pending update to later " << seq; return; } @@ -106,14 +81,12 @@ OrderBookDB::update(std::shared_ptr const& ledger) { if (app_.isStopping()) { - JLOG(j_.info()) - << "Update halted because the process is stopping"; + JLOG(j_.info()) << "Update halted because the process is stopping"; seq_.store(0); return; } - if (sle->getType() == ltDIR_NODE && - sle->isFieldPresent(sfExchangeRate) && + if (sle->getType() == ltDIR_NODE && sle->isFieldPresent(sfExchangeRate) && sle->getFieldH256(sfRootIndex) == sle->key()) { Book book; @@ -125,7 +98,7 @@ OrderBookDB::update(std::shared_ptr const& ledger) book.domain = (*sle)[~sfDomainID]; if (book.domain) - domainBooks_[{book.in, *book.domain}].insert(book.out); + domainBooks[{book.in, *book.domain}].insert(book.out); else allBooks[book.in].insert(book.out); @@ -155,14 +128,12 @@ OrderBookDB::update(std::shared_ptr const& ledger) } catch (SHAMapMissingNode const& mn) { - JLOG(j_.info()) << "Missing node in " << ledger->seq() - << " during update: " << mn.what(); + JLOG(j_.info()) << "Missing node in " << ledger->seq() << " during update: " << mn.what(); seq_.store(0); return; } - JLOG(j_.debug()) << "Update completed (" << ledger->seq() << "): " << cnt - << " books found"; + JLOG(j_.debug()) << "Update completed (" << ledger->seq() << "): " << cnt << " books found"; { std::lock_guard sl(mLock); @@ -195,9 +166,7 @@ OrderBookDB::addOrderBook(Book const& book) // return list of all orderbooks that want this issuerID and currencyID std::vector -OrderBookDB::getBooksByTakerPays( - Issue const& issue, - std::optional const& domain) +OrderBookDB::getBooksByTakerPays(Issue const& issue, std::optional const& domain) { std::vector ret; @@ -225,9 +194,7 @@ OrderBookDB::getBooksByTakerPays( } int -OrderBookDB::getBookSize( - Issue const& issue, - std::optional const& domain) +OrderBookDB::getBookSize(Issue const& issue, std::optional const& domain) { std::lock_guard sl(mLock); @@ -238,8 +205,7 @@ OrderBookDB::getBookSize( } else { - if (auto it = domainBooks_.find({issue, *domain}); - it != domainBooks_.end()) + if (auto it = domainBooks_.find({issue, *domain}); it != domainBooks_.end()) return static_cast(it->second.size()); } @@ -268,7 +234,7 @@ OrderBookDB::makeBookListeners(Book const& book) mListeners[book] = ret; XRPL_ASSERT( getBookListeners(book) == ret, - "ripple::OrderBookDB::makeBookListeners : result roundtrip " + "xrpl::OrderBookDB::makeBookListeners : result roundtrip " "lookup"); } @@ -312,10 +278,8 @@ OrderBookDB::processTxn( if (node.getFieldU16(sfLedgerEntryType) == ltOFFER) { auto process = [&, this](SField const& field) { - if (auto data = dynamic_cast( - node.peekAtPField(field)); - data && data->isFieldPresent(sfTakerPays) && - data->isFieldPresent(sfTakerGets)) + if (auto data = dynamic_cast(node.peekAtPField(field)); + data && data->isFieldPresent(sfTakerPays) && data->isFieldPresent(sfTakerGets)) { auto listeners = getBookListeners( {data->getFieldAmount(sfTakerGets).issue(), @@ -338,10 +302,9 @@ OrderBookDB::processTxn( } catch (std::exception const& ex) { - JLOG(j_.info()) - << "processTxn: field not found (" << ex.what() << ")"; + JLOG(j_.info()) << "processTxn: field not found (" << ex.what() << ")"; } } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/OrderBookDB.h b/src/xrpld/app/ledger/OrderBookDB.h index 89c20b7074..da604d7e22 100644 --- a/src/xrpld/app/ledger/OrderBookDB.h +++ b/src/xrpld/app/ledger/OrderBookDB.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_ORDERBOOKDB_H_INCLUDED -#define RIPPLE_APP_LEDGER_ORDERBOOKDB_H_INCLUDED +#pragma once #include #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { class OrderBookDB { @@ -48,16 +28,12 @@ public: /** @return a list of all orderbooks that want this issuerID and currencyID. */ std::vector - getBooksByTakerPays( - Issue const&, - std::optional const& domain = std::nullopt); + getBooksByTakerPays(Issue const&, std::optional const& domain = std::nullopt); /** @return a count of all orderbooks that want this issuerID and currencyID. */ int - getBookSize( - Issue const&, - std::optional const& domain = std::nullopt); + getBookSize(Issue const&, std::optional const& domain = std::nullopt); bool isBookToXRP(Issue const&, std::optional domain = std::nullopt); @@ -69,10 +45,7 @@ public: // see if this txn effects any orderbook void - processTxn( - std::shared_ptr const& ledger, - AcceptedLedgerTx const& alTx, - MultiApiJson const& jvObj); + processTxn(std::shared_ptr const& ledger, AcceptedLedgerTx const& alTx, MultiApiJson const& jvObj); private: Application& app_; @@ -80,8 +53,7 @@ private: // Maps order books by "issue in" to "issue out": hardened_hash_map> allBooks_; - hardened_hash_map, hardened_hash_set> - domainBooks_; + hardened_hash_map, hardened_hash_set> domainBooks_; // does an order book to XRP exist hash_set xrpBooks_; @@ -100,6 +72,4 @@ private: beast::Journal const j_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/PendingSaves.h b/src/xrpld/app/ledger/PendingSaves.h index 20263fd1f3..76958fc78a 100644 --- a/src/xrpld/app/ledger/PendingSaves.h +++ b/src/xrpld/app/ledger/PendingSaves.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PENDINGSAVES_H_INCLUDED -#define RIPPLE_APP_PENDINGSAVES_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Keeps track of which ledgers haven't been fully saved. @@ -143,6 +123,4 @@ public: } }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/README.md b/src/xrpld/app/ledger/README.md index d2afe01e71..cb935897b8 100644 --- a/src/xrpld/app/ledger/README.md +++ b/src/xrpld/app/ledger/README.md @@ -450,7 +450,7 @@ back as the database goes. If requested, it can additionally repair the SQLite entries for transactions in each checked ledger. This was primarily intended to repair incorrect -entries created by a bug (since fixed) that could cause transasctions from a +entries created by a bug (since fixed) that could cause transactions from a ledger other than the fully-validated ledger to appear in the SQLite databases in addition to the transactions from the correct ledger. diff --git a/src/xrpld/app/ledger/TransactionMaster.h b/src/xrpld/app/ledger/TransactionMaster.h index 13e968e2f5..039ff5cb99 100644 --- a/src/xrpld/app/ledger/TransactionMaster.h +++ b/src/xrpld/app/ledger/TransactionMaster.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED -#define RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED +#pragma once #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { class Application; class STTx; @@ -46,9 +26,7 @@ public: std::shared_ptr fetch_from_cache(uint256 const&); - std::variant< - std::pair, std::shared_ptr>, - TxSearched> + std::variant, std::shared_ptr>, TxSearched> fetch(uint256 const&, error_code_i& ec); /** @@ -60,27 +38,15 @@ public: * the all ledgers in the provided range were present in * the database while the search was conducted. */ - std::variant< - std::pair, std::shared_ptr>, - TxSearched> - fetch( - uint256 const&, - ClosedInterval const& range, - error_code_i& ec); + std::variant, std::shared_ptr>, TxSearched> + fetch(uint256 const&, ClosedInterval const& range, error_code_i& ec); std::shared_ptr - fetch( - boost::intrusive_ptr const& item, - SHAMapNodeType type, - std::uint32_t uCommitLedger); + fetch(boost::intrusive_ptr const& item, SHAMapNodeType type, std::uint32_t uCommitLedger); // return value: true = we had the transaction already bool - inLedger( - uint256 const& hash, - std::uint32_t ledger, - std::optional tseq, - std::optional netID); + inLedger(uint256 const& hash, std::uint32_t ledger, std::optional tseq, std::optional netID); void canonicalize(std::shared_ptr* pTransaction); @@ -96,6 +62,4 @@ private: TaggedCache mCache; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/TransactionStateSF.cpp b/src/xrpld/app/ledger/TransactionStateSF.cpp index 30a4d2f817..ee2febbd83 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.cpp +++ b/src/xrpld/app/ledger/TransactionStateSF.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { void TransactionStateSF::gotNode( @@ -30,14 +11,8 @@ TransactionStateSF::gotNode( SHAMapNodeType type) const { - XRPL_ASSERT( - type != SHAMapNodeType::tnTRANSACTION_NM, - "ripple::TransactionStateSF::gotNode : valid input"); - db_.store( - hotTRANSACTION_NODE, - std::move(nodeData), - nodeHash.as_uint256(), - ledgerSeq); + XRPL_ASSERT(type != SHAMapNodeType::tnTRANSACTION_NM, "xrpl::TransactionStateSF::gotNode : valid input"); + db_.store(hotTRANSACTION_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq); } std::optional @@ -46,4 +21,4 @@ TransactionStateSF::getNode(SHAMapHash const& nodeHash) const return fp_.getFetchPack(nodeHash.as_uint256()); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/TransactionStateSF.h b/src/xrpld/app/ledger/TransactionStateSF.h index 64dfed7142..2851884cfd 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.h +++ b/src/xrpld/app/ledger/TransactionStateSF.h @@ -1,49 +1,24 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_TRANSACTIONSTATESF_H_INCLUDED -#define RIPPLE_APP_LEDGER_TRANSACTIONSTATESF_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { // This class is only needed on add functions // sync filter for transactions tree during ledger sync class TransactionStateSF : public SHAMapSyncFilter { public: - TransactionStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp) - : db_(db), fp_(fp) + TransactionStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp) : db_(db), fp_(fp) { } void - gotNode( - bool fromFilter, - SHAMapHash const& nodeHash, - std::uint32_t ledgerSeq, - Blob&& nodeData, - SHAMapNodeType type) const override; + gotNode(bool fromFilter, SHAMapHash const& nodeHash, std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapNodeType type) + const override; std::optional getNode(SHAMapHash const& nodeHash) const override; @@ -53,6 +28,4 @@ private: AbstractFetchPackContainer& fp_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp index 4305426753..1414441b35 100644 --- a/src/xrpld/app/ledger/detail/BuildLedger.cpp +++ b/src/xrpld/app/ledger/detail/BuildLedger.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { /* Generic buildLedgerImpl that dispatches to ApplyTxs invocable with signature void(OpenView&, std::shared_ptr const&) @@ -47,7 +28,7 @@ buildLedgerImpl( { auto built = std::make_shared(*parent, closeTime); - if (built->isFlagLedger() && built->rules().enabled(featureNegativeUNL)) + if (built->isFlagLedger()) { built->updateNegativeUNL(); } @@ -57,8 +38,7 @@ buildLedgerImpl( { OpenView accum(&*built); - XRPL_ASSERT( - !accum.open(), "ripple::buildLedgerImpl : valid ledger state"); + XRPL_ASSERT(!accum.open(), "xrpl::buildLedgerImpl : valid ledger state"); applyTxs(accum, built); accum.apply(*built); } @@ -70,16 +50,14 @@ buildLedgerImpl( int const asf = built->stateMap().flushDirty(hotACCOUNT_NODE); int const tmf = built->txMap().flushDirty(hotTRANSACTION_NODE); - JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf - << " transaction nodes"; + JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf << " transaction nodes"; } built->unshare(); // Accept ledger XRPL_ASSERT( - built->info().seq < XRP_LEDGER_EARLIEST_FEES || - built->read(keylet::fees()), - "ripple::buildLedgerImpl : valid ledger fees"); + built->header().seq < XRP_LEDGER_EARLIEST_FEES || built->read(keylet::fees()), + "xrpl::buildLedgerImpl : valid ledger fees"); built->setAccepted(closeTime, closeResolution, closeTimeCorrect); return built; @@ -110,8 +88,8 @@ applyTransactions( // Attempt to apply all of the retriable transactions for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass) { - JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass - << " begins (" << txns.size() << " transactions)"; + JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass << " begins (" << txns.size() + << " transactions)"; int changes = 0; auto it = txns.begin(); @@ -128,8 +106,7 @@ applyTransactions( continue; } - switch (applyTransaction( - app, view, *it->second, certainRetry, tapNONE, j)) + switch (applyTransaction(app, view, *it->second, certainRetry, tapNONE, j)) { case ApplyTransactionResult::Success: it = txns.erase(it); @@ -147,15 +124,14 @@ applyTransactions( } catch (std::exception const& ex) { - JLOG(j.warn()) - << "Transaction " << txid << " throws: " << ex.what(); + JLOG(j.warn()) << "Transaction " << txid << " throws: " << ex.what(); failed.insert(txid); it = txns.erase(it); } } - JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass - << " completed (" << changes << " changes)"; + JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass << " completed (" << changes + << " changes)"; // Accumulate changes. count += changes; @@ -171,9 +147,7 @@ applyTransactions( // If there are any transactions left, we must have // tried them in at least one final pass - XRPL_ASSERT( - txns.empty() || !certainRetry, - "ripple::applyTransactions : retry transactions"); + XRPL_ASSERT(txns.empty() || !certainRetry, "xrpl::applyTransactions : retry transactions"); return count; } @@ -189,8 +163,7 @@ buildLedger( std::set& failedTxns, beast::Journal j) { - JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close " - << closeTime.time_since_epoch().count() + JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close " << closeTime.time_since_epoch().count() << (closeTimeCorrect ? "" : " (incorrect)"); return buildLedgerImpl( @@ -201,44 +174,33 @@ buildLedger( app, j, [&](OpenView& accum, std::shared_ptr const& built) { - JLOG(j.debug()) - << "Attempting to apply " << txns.size() << " transactions"; + JLOG(j.debug()) << "Attempting to apply " << txns.size() << " transactions"; - auto const applied = - applyTransactions(app, built, txns, failedTxns, accum, j); + auto const applied = applyTransactions(app, built, txns, failedTxns, accum, j); if (!txns.empty() || !failedTxns.empty()) - JLOG(j.debug()) - << "Applied " << applied << " transactions; " - << failedTxns.size() << " failed and " << txns.size() - << " will be retried. " - << "Total transactions in ledger (including Inner Batch): " - << accum.txCount(); + JLOG(j.debug()) << "Applied " << applied << " transactions; " << failedTxns.size() << " failed and " + << txns.size() << " will be retried. " + << "Total transactions in ledger (including Inner Batch): " << accum.txCount(); else - JLOG(j.debug()) - << "Applied " << applied << " transactions. " - << "Total transactions in ledger (including Inner Batch): " - << accum.txCount(); + JLOG(j.debug()) << "Applied " << applied << " transactions. " + << "Total transactions in ledger (including Inner Batch): " << accum.txCount(); }); } // Build a ledger by replaying std::shared_ptr -buildLedger( - LedgerReplay const& replayData, - ApplyFlags applyFlags, - Application& app, - beast::Journal j) +buildLedger(LedgerReplay const& replayData, ApplyFlags applyFlags, Application& app, beast::Journal j) { auto const& replayLedger = replayData.replay(); - JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash; + JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->header().hash; return buildLedgerImpl( replayData.parent(), - replayLedger->info().closeTime, - ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0), - replayLedger->info().closeTimeResolution, + replayLedger->header().closeTime, + ((replayLedger->header().closeFlags & sLCF_NoConsensusTime) == 0), + replayLedger->header().closeTimeResolution, app, j, [&](OpenView& accum, std::shared_ptr const& built) { @@ -247,4 +209,4 @@ buildLedger( }); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 9bebb1ed38..3c8f61a915 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -1,32 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { using namespace std::chrono_literals; @@ -80,12 +61,7 @@ InboundLedger::InboundLedger( Reason reason, clock_type& clock, std::unique_ptr peerSet) - : TimeoutCounter( - app, - hash, - ledgerAcquireTimeout, - {jtLEDGER_DATA, "InboundLedger", 5}, - app.journal("InboundLedger")) + : TimeoutCounter(app, hash, ledgerAcquireTimeout, {jtLEDGER_DATA, "InboundLedger", 5}, app.journal("InboundLedger")) , m_clock(clock) , mHaveHeader(false) , mHaveState(false) @@ -121,9 +97,8 @@ InboundLedger::init(ScopedLockType& collectionLock) JLOG(journal_.debug()) << "Acquiring ledger we already have in " << " local store. " << hash_; XRPL_ASSERT( - mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees()), - "ripple::InboundLedger::init : valid ledger fees"); + mLedger->header().seq < XRP_LEDGER_EARLIEST_FEES || mLedger->read(keylet::fees()), + "xrpl::InboundLedger::init : valid ledger fees"); mLedger->setImmutable(); if (mReason == Reason::HISTORY) @@ -140,9 +115,8 @@ std::size_t InboundLedger::getPeerCount() const { auto const& peerIds = mPeerSet->getPeerIds(); - return std::count_if(peerIds.begin(), peerIds.end(), [this](auto id) { - return (app_.overlay().findPeerByShortID(id) != nullptr); - }); + return std::count_if( + peerIds.begin(), peerIds.end(), [this](auto id) { return (app_.overlay().findPeerByShortID(id) != nullptr); }); } void @@ -188,21 +162,15 @@ InboundLedger::~InboundLedger() } if (!isDone()) { - JLOG(journal_.debug()) - << "Acquire " << hash_ << " abort " - << ((timeouts_ == 0) ? std::string() - : (std::string("timeouts:") + - std::to_string(timeouts_) + " ")) - << mStats.get(); + JLOG(journal_.debug()) << "Acquire " << hash_ << " abort " + << ((timeouts_ == 0) ? std::string() + : (std::string("timeouts:") + std::to_string(timeouts_) + " ")) + << mStats.get(); } } static std::vector -neededHashes( - uint256 const& root, - SHAMap& map, - int max, - SHAMapSyncFilter* filter) +neededHashes(uint256 const& root, SHAMap& map, int max, SHAMapSyncFilter* filter) { std::vector ret; @@ -225,14 +193,13 @@ neededHashes( std::vector InboundLedger::neededTxHashes(int max, SHAMapSyncFilter* filter) const { - return neededHashes(mLedger->info().txHash, mLedger->txMap(), max, filter); + return neededHashes(mLedger->header().txHash, mLedger->txMap(), max, filter); } std::vector InboundLedger::neededStateHashes(int max, SHAMapSyncFilter* filter) const { - return neededHashes( - mLedger->info().accountHash, mLedger->stateMap(), max, filter); + return neededHashes(mLedger->header().accountHash, mLedger->stateMap(), max, filter); } // See how much of the ledger data is stored locally @@ -245,16 +212,11 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) auto makeLedger = [&, this](Blob const& data) { JLOG(journal_.trace()) << "Ledger header found in fetch pack"; mLedger = std::make_shared( - deserializePrefixedHeader(makeSlice(data)), - app_.config(), - app_.getNodeFamily()); - if (mLedger->info().hash != hash_ || - (mSeq != 0 && mSeq != mLedger->info().seq)) + deserializePrefixedHeader(makeSlice(data)), app_.config(), app_.getNodeFamily()); + if (mLedger->header().hash != hash_ || (mSeq != 0 && mSeq != mLedger->header().seq)) { // We know for a fact the ledger can never be acquired - JLOG(journal_.warn()) - << "hash " << hash_ << " seq " << std::to_string(mSeq) - << " cannot be a ledger"; + JLOG(journal_.warn()) << "hash " << hash_ << " seq " << std::to_string(mSeq) << " cannot be a ledger"; mLedger.reset(); failed_ = true; } @@ -274,8 +236,7 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) if (std::addressof(dstDB) != std::addressof(srcDB)) { Blob blob{nodeObject->getData()}; - dstDB.store( - hotLEDGER, std::move(blob), hash_, mLedger->info().seq); + dstDB.store(hotLEDGER, std::move(blob), hash_, mLedger->header().seq); } } else @@ -292,12 +253,11 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) return; // Store the ledger header in the ledger's database - mLedger->stateMap().family().db().store( - hotLEDGER, std::move(*data), hash_, mLedger->info().seq); + mLedger->stateMap().family().db().store(hotLEDGER, std::move(*data), hash_, mLedger->header().seq); } if (mSeq == 0) - mSeq = mLedger->info().seq; + mSeq = mLedger->header().seq; mLedger->stateMap().setLedgerSeq(mSeq); mLedger->txMap().setLedgerSeq(mSeq); mHaveHeader = true; @@ -305,17 +265,15 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) if (!mHaveTransactions) { - if (mLedger->info().txHash.isZero()) + if (mLedger->header().txHash.isZero()) { JLOG(journal_.trace()) << "No TXNs to fetch"; mHaveTransactions = true; } else { - TransactionStateSF filter( - mLedger->txMap().family().db(), app_.getLedgerMaster()); - if (mLedger->txMap().fetchRoot( - SHAMapHash{mLedger->info().txHash}, &filter)) + TransactionStateSF filter(mLedger->txMap().family().db(), app_.getLedgerMaster()); + if (mLedger->txMap().fetchRoot(SHAMapHash{mLedger->header().txHash}, &filter)) { if (neededTxHashes(1, &filter).empty()) { @@ -328,17 +286,14 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) if (!mHaveState) { - if (mLedger->info().accountHash.isZero()) + if (mLedger->header().accountHash.isZero()) { - JLOG(journal_.fatal()) - << "We are acquiring a ledger with a zero account hash"; + JLOG(journal_.fatal()) << "We are acquiring a ledger with a zero account hash"; failed_ = true; return; } - AccountStateSF filter( - mLedger->stateMap().family().db(), app_.getLedgerMaster()); - if (mLedger->stateMap().fetchRoot( - SHAMapHash{mLedger->info().accountHash}, &filter)) + AccountStateSF filter(mLedger->stateMap().family().db(), app_.getLedgerMaster()); + if (mLedger->stateMap().fetchRoot(SHAMapHash{mLedger->header().accountHash}, &filter)) { if (neededStateHashes(1, &filter).empty()) { @@ -353,9 +308,8 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) JLOG(journal_.debug()) << "Had everything locally"; complete_ = true; XRPL_ASSERT( - mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees()), - "ripple::InboundLedger::tryDB : valid ledger fees"); + mLedger->header().seq < XRP_LEDGER_EARLIEST_FEES || mLedger->read(keylet::fees()), + "xrpl::InboundLedger::tryDB : valid ledger fees"); mLedger->setImmutable(); } } @@ -377,13 +331,11 @@ InboundLedger::onTimer(bool wasProgress, ScopedLockType&) { if (mSeq != 0) { - JLOG(journal_.warn()) - << timeouts_ << " timeouts for ledger " << mSeq; + JLOG(journal_.warn()) << timeouts_ << " timeouts for ledger " << mSeq; } else { - JLOG(journal_.warn()) - << timeouts_ << " timeouts for ledger " << hash_; + JLOG(journal_.warn()) << timeouts_ << " timeouts for ledger " << hash_; } failed_ = true; done(); @@ -397,8 +349,7 @@ InboundLedger::onTimer(bool wasProgress, ScopedLockType&) mByHash = true; std::size_t pc = getPeerCount(); - JLOG(journal_.debug()) - << "No progress(" << pc << ") for ledger " << hash_; + JLOG(journal_.debug()) << "No progress(" << pc << ") for ledger " << hash_; // addPeers triggers if the reason is not HISTORY // So if the reason IS HISTORY, need to trigger after we add @@ -443,22 +394,17 @@ InboundLedger::done() touch(); JLOG(journal_.debug()) << "Acquire " << hash_ << (failed_ ? " fail " : " ") - << ((timeouts_ == 0) - ? std::string() - : (std::string("timeouts:") + - std::to_string(timeouts_) + " ")) + << ((timeouts_ == 0) ? std::string() + : (std::string("timeouts:") + std::to_string(timeouts_) + " ")) << mStats.get(); - XRPL_ASSERT( - complete_ || failed_, - "ripple::InboundLedger::done : complete or failed"); + XRPL_ASSERT(complete_ || failed_, "xrpl::InboundLedger::done : complete or failed"); if (complete_ && !failed_ && mLedger) { XRPL_ASSERT( - mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees()), - "ripple::InboundLedger::done : valid ledger fees"); + mLedger->header().seq < XRP_LEDGER_EARLIEST_FEES || mLedger->read(keylet::fees()), + "xrpl::InboundLedger::done : valid ledger fees"); mLedger->setImmutable(); switch (mReason) { @@ -472,17 +418,15 @@ InboundLedger::done() } // We hold the PeerSet lock, so must dispatch - app_.getJobQueue().addJob( - jtLEDGER_DATA, "AcquisitionDone", [self = shared_from_this()]() { - if (self->complete_ && !self->failed_) - { - self->app_.getLedgerMaster().checkAccept(self->getLedger()); - self->app_.getLedgerMaster().tryAdvance(); - } - else - self->app_.getInboundLedgers().logFailure( - self->hash_, self->mSeq); - }); + app_.getJobQueue().addJob(jtLEDGER_DATA, "AcqDone", [self = shared_from_this()]() { + if (self->complete_ && !self->failed_) + { + self->app_.getLedgerMaster().checkAccept(self->getLedger()); + self->app_.getLedgerMaster().tryAdvance(); + } + else + self->app_.getInboundLedgers().logFailure(self->hash_, self->mSeq); + }); } /** Request more nodes, perhaps from a specific peer @@ -494,9 +438,8 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (isDone()) { - JLOG(journal_.debug()) - << "Trigger on ledger: " << hash_ << (complete_ ? " completed" : "") - << (failed_ ? " failed" : ""); + JLOG(journal_.debug()) << "Trigger on ledger: " << hash_ << (complete_ ? " completed" : "") + << (failed_ ? " failed" : ""); return; } @@ -510,8 +453,7 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (complete_ || failed_) ss << " complete=" << complete_ << " failed=" << failed_; else - ss << " header=" << mHaveHeader << " tx=" << mHaveTransactions - << " as=" << mHaveState; + ss << " header=" << mHaveHeader << " tx=" << mHaveTransactions << " as=" << mHaveState; stream << ss.str(); } @@ -533,8 +475,7 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) // Be more aggressive if we've timed out at least once tmGL.set_querytype(protocol::qtINDIRECT); - if (!progress_ && !failed_ && mByHash && - (timeouts_ > ledgerBecomeAggressiveThreshold)) + if (!progress_ && !failed_ && mByHash && (timeouts_ > ledgerBecomeAggressiveThreshold)) { auto need = getNeededHashes(); @@ -563,22 +504,19 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) } } - auto packet = - std::make_shared(tmBH, protocol::mtGET_OBJECTS); + auto packet = std::make_shared(tmBH, protocol::mtGET_OBJECTS); auto const& peerIds = mPeerSet->getPeerIds(); - std::for_each( - peerIds.begin(), peerIds.end(), [this, &packet](auto id) { - if (auto p = app_.overlay().findPeerByShortID(id)) - { - mByHash = false; - p->send(packet); - } - }); + std::for_each(peerIds.begin(), peerIds.end(), [this, &packet](auto id) { + if (auto p = app_.overlay().findPeerByShortID(id)) + { + mByHash = false; + p->send(packet); + } + }); } else { - JLOG(journal_.info()) - << "getNeededHashes says acquire is complete"; + JLOG(journal_.info()) << "getNeededHashes says acquire is complete"; mHaveHeader = true; mHaveTransactions = true; mHaveState = true; @@ -594,14 +532,13 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) tmGL.set_itype(protocol::liBASE); if (mSeq != 0) tmGL.set_ledgerseq(mSeq); - JLOG(journal_.trace()) << "Sending header request to " - << (peer ? "selected peer" : "all peers"); + JLOG(journal_.trace()) << "Sending header request to " << (peer ? "selected peer" : "all peers"); mPeerSet->sendRequest(tmGL, peer); return; } if (mLedger) - tmGL.set_ledgerseq(mLedger->info().seq); + tmGL.set_ledgerseq(mLedger->header().seq); if (reason != TriggerReason::reply) { @@ -622,7 +559,7 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) { XRPL_ASSERT( mLedger, - "ripple::InboundLedger::trigger : non-null ledger to read state " + "xrpl::InboundLedger::trigger : non-null ledger to read state " "from"); if (!mLedger->stateMap().isValid()) @@ -634,20 +571,17 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) // we need the root node tmGL.set_itype(protocol::liAS_NODE); *tmGL.add_nodeids() = SHAMapNodeID().getRawString(); - JLOG(journal_.trace()) << "Sending AS root request to " - << (peer ? "selected peer" : "all peers"); + JLOG(journal_.trace()) << "Sending AS root request to " << (peer ? "selected peer" : "all peers"); mPeerSet->sendRequest(tmGL, peer); return; } else { - AccountStateSF filter( - mLedger->stateMap().family().db(), app_.getLedgerMaster()); + AccountStateSF filter(mLedger->stateMap().family().db(), app_.getLedgerMaster()); // Release the lock while we process the large state map sl.unlock(); - auto nodes = - mLedger->stateMap().getMissingNodes(missingNodesFind, &filter); + auto nodes = mLedger->stateMap().getMissingNodes(missingNodesFind, &filter); sl.lock(); // Make sure nothing happened while we released the lock @@ -677,10 +611,8 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) *(tmGL.add_nodeids()) = id.first.getRawString(); } - JLOG(journal_.trace()) - << "Sending AS node request (" << nodes.size() - << ") to " - << (peer ? "selected peer" : "all peers"); + JLOG(journal_.trace()) << "Sending AS node request (" << nodes.size() << ") to " + << (peer ? "selected peer" : "all peers"); mPeerSet->sendRequest(tmGL, peer); return; } @@ -697,7 +629,7 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) { XRPL_ASSERT( mLedger, - "ripple::InboundLedger::trigger : non-null ledger to read " + "xrpl::InboundLedger::trigger : non-null ledger to read " "transactions from"); if (!mLedger->txMap().isValid()) @@ -709,18 +641,15 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) // we need the root node tmGL.set_itype(protocol::liTX_NODE); *(tmGL.add_nodeids()) = SHAMapNodeID().getRawString(); - JLOG(journal_.trace()) << "Sending TX root request to " - << (peer ? "selected peer" : "all peers"); + JLOG(journal_.trace()) << "Sending TX root request to " << (peer ? "selected peer" : "all peers"); mPeerSet->sendRequest(tmGL, peer); return; } else { - TransactionStateSF filter( - mLedger->txMap().family().db(), app_.getLedgerMaster()); + TransactionStateSF filter(mLedger->txMap().family().db(), app_.getLedgerMaster()); - auto nodes = - mLedger->txMap().getMissingNodes(missingNodesFind, &filter); + auto nodes = mLedger->txMap().getMissingNodes(missingNodesFind, &filter); if (nodes.empty()) { @@ -745,9 +674,8 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) { *(tmGL.add_nodeids()) = n.first.getRawString(); } - JLOG(journal_.trace()) - << "Sending TX node request (" << nodes.size() - << ") to " << (peer ? "selected peer" : "all peers"); + JLOG(journal_.trace()) << "Sending TX node request (" << nodes.size() << ") to " + << (peer ? "selected peer" : "all peers"); mPeerSet->sendRequest(tmGL, peer); return; } @@ -761,25 +689,20 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (complete_ || failed_) { - JLOG(journal_.debug()) - << "Done:" << (complete_ ? " complete" : "") - << (failed_ ? " failed " : " ") << mLedger->info().seq; + JLOG(journal_.debug()) << "Done:" << (complete_ ? " complete" : "") << (failed_ ? " failed " : " ") + << mLedger->header().seq; sl.unlock(); done(); } } void -InboundLedger::filterNodes( - std::vector>& nodes, - TriggerReason reason) +InboundLedger::filterNodes(std::vector>& nodes, TriggerReason reason) { // Sort nodes so that the ones we haven't recently // requested come before the ones we have. auto dup = std::stable_partition( - nodes.begin(), nodes.end(), [this](auto const& item) { - return mRecentNodes.count(item.second) == 0; - }); + nodes.begin(), nodes.end(), [this](auto const& item) { return mRecentNodes.count(item.second) == 0; }); // If everything is a duplicate we don't want to send // any query at all except on a timeout where we need @@ -801,8 +724,7 @@ InboundLedger::filterNodes( nodes.erase(dup, nodes.end()); } - std::size_t const limit = - (reason == TriggerReason::reply) ? reqNodesReply : reqNodes; + std::size_t const limit = (reason == TriggerReason::reply) ? reqNodesReply : reqNodes; if (nodes.size() > limit) nodes.resize(limit); @@ -825,19 +747,15 @@ InboundLedger::takeHeader(std::string const& data) return true; auto* f = &app_.getNodeFamily(); - mLedger = std::make_shared( - deserializeHeader(makeSlice(data)), app_.config(), *f); - if (mLedger->info().hash != hash_ || - (mSeq != 0 && mSeq != mLedger->info().seq)) + mLedger = std::make_shared(deserializeHeader(makeSlice(data)), app_.config(), *f); + if (mLedger->header().hash != hash_ || (mSeq != 0 && mSeq != mLedger->header().seq)) { - JLOG(journal_.warn()) - << "Acquire hash mismatch: " << mLedger->info().hash - << "!=" << hash_; + JLOG(journal_.warn()) << "Acquire hash mismatch: " << mLedger->header().hash << "!=" << hash_; mLedger.reset(); return false; } if (mSeq == 0) - mSeq = mLedger->info().seq; + mSeq = mLedger->header().seq; mLedger->stateMap().setLedgerSeq(mSeq); mLedger->txMap().setLedgerSeq(mSeq); mHaveHeader = true; @@ -847,10 +765,10 @@ InboundLedger::takeHeader(std::string const& data) s.addRaw(data.data(), data.size()); f->db().store(hotLEDGER, std::move(s.modData()), hash_, mSeq); - if (mLedger->info().txHash.isZero()) + if (mLedger->header().txHash.isZero()) mHaveTransactions = true; - if (mLedger->info().accountHash.isZero()) + if (mLedger->header().accountHash.isZero()) mHaveState = true; mLedger->txMap().setSynching(); @@ -885,19 +803,16 @@ InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san) return; } - auto [map, rootHash, filter] = [&]() - -> std::tuple> { + auto [map, rootHash, filter] = [&]() -> std::tuple> { if (packet.type() == protocol::liTX_NODE) return { mLedger->txMap(), - SHAMapHash{mLedger->info().txHash}, - std::make_unique( - mLedger->txMap().family().db(), app_.getLedgerMaster())}; + SHAMapHash{mLedger->header().txHash}, + std::make_unique(mLedger->txMap().family().db(), app_.getLedgerMaster())}; return { mLedger->stateMap(), - SHAMapHash{mLedger->info().accountHash}, - std::make_unique( - mLedger->stateMap().family().db(), app_.getLedgerMaster())}; + SHAMapHash{mLedger->header().accountHash}, + std::make_unique(mLedger->stateMap().family().db(), app_.getLedgerMaster())}; }(); try @@ -964,15 +879,13 @@ InboundLedger::takeAsRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { // LCOV_EXCL_START - UNREACHABLE("ripple::InboundLedger::takeAsRootNode : no ledger header"); + UNREACHABLE("xrpl::InboundLedger::takeAsRootNode : no ledger header"); return false; // LCOV_EXCL_STOP } - AccountStateSF filter( - mLedger->stateMap().family().db(), app_.getLedgerMaster()); - san += mLedger->stateMap().addRootNode( - SHAMapHash{mLedger->info().accountHash}, data, &filter); + AccountStateSF filter(mLedger->stateMap().family().db(), app_.getLedgerMaster()); + san += mLedger->stateMap().addRootNode(SHAMapHash{mLedger->header().accountHash}, data, &filter); return san.isGood(); } @@ -991,15 +904,13 @@ InboundLedger::takeTxRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { // LCOV_EXCL_START - UNREACHABLE("ripple::InboundLedger::takeTxRootNode : no ledger header"); + UNREACHABLE("xrpl::InboundLedger::takeTxRootNode : no ledger header"); return false; // LCOV_EXCL_STOP } - TransactionStateSF filter( - mLedger->txMap().family().db(), app_.getLedgerMaster()); - san += mLedger->txMap().addRootNode( - SHAMapHash{mLedger->info().txHash}, data, &filter); + TransactionStateSF filter(mLedger->txMap().family().db(), app_.getLedgerMaster()); + san += mLedger->txMap().addRootNode(SHAMapHash{mLedger->header().txHash}, data, &filter); return san.isGood(); } @@ -1010,30 +921,25 @@ InboundLedger::getNeededHashes() if (!mHaveHeader) { - ret.push_back( - std::make_pair(protocol::TMGetObjectByHash::otLEDGER, hash_)); + ret.push_back(std::make_pair(protocol::TMGetObjectByHash::otLEDGER, hash_)); return ret; } if (!mHaveState) { - AccountStateSF filter( - mLedger->stateMap().family().db(), app_.getLedgerMaster()); + AccountStateSF filter(mLedger->stateMap().family().db(), app_.getLedgerMaster()); for (auto const& h : neededStateHashes(4, &filter)) { - ret.push_back( - std::make_pair(protocol::TMGetObjectByHash::otSTATE_NODE, h)); + ret.push_back(std::make_pair(protocol::TMGetObjectByHash::otSTATE_NODE, h)); } } if (!mHaveTransactions) { - TransactionStateSF filter( - mLedger->txMap().family().db(), app_.getLedgerMaster()); + TransactionStateSF filter(mLedger->txMap().family().db(), app_.getLedgerMaster()); for (auto const& h : neededTxHashes(4, &filter)) { - ret.push_back(std::make_pair( - protocol::TMGetObjectByHash::otTRANSACTION_NODE, h)); + ret.push_back(std::make_pair(protocol::TMGetObjectByHash::otTRANSACTION_NODE, h)); } } @@ -1044,9 +950,7 @@ InboundLedger::getNeededHashes() Returns 'true' if we need to dispatch */ bool -InboundLedger::gotData( - std::weak_ptr peer, - std::shared_ptr const& data) +InboundLedger::gotData(std::weak_ptr peer, std::shared_ptr const& data) { std::lock_guard sl(mReceivedDataLock); @@ -1071,17 +975,14 @@ InboundLedger::gotData( // TODO Change peer to Consumer // int -InboundLedger::processData( - std::shared_ptr peer, - protocol::TMLedgerData& packet) +InboundLedger::processData(std::shared_ptr peer, protocol::TMLedgerData& packet) { if (packet.type() == protocol::liBASE) { if (packet.nodes().empty()) { JLOG(journal_.warn()) << peer->id() << ": empty header data"; - peer->charge( - Resource::feeMalformedRequest, "ledger_data empty header"); + peer->charge(Resource::feeMalformedRequest, "ledger_data empty header"); return -1; } @@ -1096,9 +997,7 @@ InboundLedger::processData( if (!takeHeader(packet.nodes(0).nodedata())) { JLOG(journal_.warn()) << "Got invalid header data"; - peer->charge( - Resource::feeMalformedRequest, - "ledger_data invalid header"); + peer->charge(Resource::feeMalformedRequest, "ledger_data invalid header"); return -1; } @@ -1119,8 +1018,7 @@ InboundLedger::processData( } catch (std::exception const& ex) { - JLOG(journal_.warn()) - << "Included AS/TX root invalid: " << ex.what(); + JLOG(journal_.warn()) << "Included AS/TX root invalid: " << ex.what(); using namespace std::string_literals; peer->charge(Resource::feeInvalidData, "ledger_data "s + ex.what()); return -1; @@ -1133,11 +1031,9 @@ InboundLedger::processData( return san.getGood(); } - if ((packet.type() == protocol::liTX_NODE) || - (packet.type() == protocol::liAS_NODE)) + if ((packet.type() == protocol::liTX_NODE) || (packet.type() == protocol::liAS_NODE)) { - std::string type = packet.type() == protocol::liTX_NODE ? "liTX_NODE: " - : "liAS_NODE: "; + std::string type = packet.type() == protocol::liTX_NODE ? "liTX_NODE: " : "liAS_NODE: "; if (packet.nodes().empty()) { @@ -1154,8 +1050,7 @@ InboundLedger::processData( if (!node.has_nodeid() || !node.has_nodedata()) { JLOG(journal_.warn()) << "Got bad node"; - peer->charge( - Resource::feeMalformedRequest, "ledger_data bad node"); + peer->charge(Resource::feeMalformedRequest, "ledger_data bad node"); return -1; } } @@ -1163,10 +1058,8 @@ InboundLedger::processData( SHAMapAddNode san; receiveNode(packet, san); - JLOG(journal_.debug()) - << "Ledger " - << ((packet.type() == protocol::liTX_NODE) ? "TX" : "AS") - << " node stats: " << san.get(); + JLOG(journal_.debug()) << "Ledger " << ((packet.type() == protocol::liTX_NODE) ? "TX" : "AS") + << " node stats: " << san.get(); if (san.isUseful()) progress_ = true; @@ -1234,19 +1127,13 @@ struct PeerDataCounts #if _MSC_VER std::vector, int>> s; s.reserve(n); - std::sample( - counts.begin(), counts.end(), std::back_inserter(s), n, rng); + std::sample(counts.begin(), counts.end(), std::back_inserter(s), n, rng); for (auto& v : s) { outFunc(v); } #else - std::sample( - counts.begin(), - counts.end(), - boost::make_function_output_iterator(outFunc), - n, - rng); + std::sample(counts.begin(), counts.end(), boost::make_function_output_iterator(outFunc), n, rng); #endif } }; @@ -1297,9 +1184,7 @@ InboundLedger::runData() // Select a random sample of the peers that gives us the most nodes that are // useful dataCounts.prune(); - dataCounts.sampleN(maxUsefulPeers, [&](std::shared_ptr const& peer) { - trigger(peer, TriggerReason::reply); - }); + dataCounts.sampleN(maxUsefulPeers, [&](std::shared_ptr const& peer) { trigger(peer, TriggerReason::reply); }); } Json::Value @@ -1353,4 +1238,4 @@ InboundLedger::getJson(int) return ret; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index b05268f65b..626f58b686 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -1,33 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -#include -#include #include #include #include #include +#include +#include #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { class InboundLedgersImp : public InboundLedgers { @@ -67,19 +48,13 @@ public: /** @callgraph */ std::shared_ptr - acquire( - uint256 const& hash, - std::uint32_t seq, - InboundLedger::Reason reason) override + acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override { auto doAcquire = [&, seq, reason]() -> std::shared_ptr { - XRPL_ASSERT( - hash.isNonZero(), - "ripple::InboundLedgersImp::acquire::doAcquire : nonzero hash"); + XRPL_ASSERT(hash.isNonZero(), "xrpl::InboundLedgersImp::acquire::doAcquire : nonzero hash"); // probably not the right rule - if (app_.getOPs().isNeedNetworkLedger() && - (reason != InboundLedger::Reason::GENERIC) && + if (app_.getOPs().isNeedNetworkLedger() && (reason != InboundLedger::Reason::GENERIC) && (reason != InboundLedger::Reason::CONSENSUS)) return {}; @@ -101,12 +76,7 @@ public: else { inbound = std::make_shared( - app_, - hash, - seq, - reason, - std::ref(m_clock), - mPeerSetBuilder->build()); + app_, hash, seq, reason, std::ref(m_clock), mPeerSetBuilder->build()); mLedgers.emplace(hash, inbound); inbound->init(sl); ++mCounter; @@ -125,17 +95,14 @@ public: return inbound->getLedger(); }; using namespace std::chrono_literals; - std::shared_ptr ledger = perf::measureDurationAndLog( - doAcquire, "InboundLedgersImp::acquire", 500ms, j_); + std::shared_ptr ledger = + perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_); return ledger; } void - acquireAsync( - uint256 const& hash, - std::uint32_t seq, - InboundLedger::Reason reason) override + acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override { std::unique_lock lock(acquiresMutex_); try @@ -148,15 +115,11 @@ public: } catch (std::exception const& e) { - JLOG(j_.warn()) - << "Exception thrown for acquiring new inbound ledger " << hash - << ": " << e.what(); + JLOG(j_.warn()) << "Exception thrown for acquiring new inbound ledger " << hash << ": " << e.what(); } catch (...) { - JLOG(j_.warn()) - << "Unknown exception thrown for acquiring new inbound ledger " - << hash; + JLOG(j_.warn()) << "Unknown exception thrown for acquiring new inbound ledger " << hash; } pendingAcquires_.erase(hash); } @@ -164,9 +127,7 @@ public: std::shared_ptr find(uint256 const& hash) override { - XRPL_ASSERT( - hash.isNonZero(), - "ripple::InboundLedgersImp::find : nonzero input"); + XRPL_ASSERT(hash.isNonZero(), "xrpl::InboundLedgersImp::find : nonzero input"); std::shared_ptr ret; @@ -198,38 +159,28 @@ public: /** We received a TMLedgerData from a peer. */ bool - gotLedgerData( - LedgerHash const& hash, - std::shared_ptr peer, - std::shared_ptr packet) override + gotLedgerData(LedgerHash const& hash, std::shared_ptr peer, std::shared_ptr packet) + override { if (auto ledger = find(hash)) { - JLOG(j_.trace()) << "Got data (" << packet->nodes().size() - << ") for acquiring ledger: " << hash; + JLOG(j_.trace()) << "Got data (" << packet->nodes().size() << ") for acquiring ledger: " << hash; // Stash the data for later processing and see if we need to // dispatch if (ledger->gotData(std::weak_ptr(peer), packet)) - app_.getJobQueue().addJob( - jtLEDGER_DATA, "processLedgerData", [ledger]() { - ledger->runData(); - }); + app_.getJobQueue().addJob(jtLEDGER_DATA, "ProcessLData", [ledger]() { ledger->runData(); }); return true; } - JLOG(j_.trace()) << "Got data for ledger " << hash - << " which we're no longer acquiring"; + JLOG(j_.trace()) << "Got data for ledger " << hash << " which we're no longer acquiring"; // If it's state node data, stash it because it still might be // useful. if (packet->type() == protocol::liAS_NODE) { - app_.getJobQueue().addJob( - jtLEDGER_DATA, "gotStaleData", [this, packet]() { - gotStaleData(packet); - }); + app_.getJobQueue().addJob(jtLEDGER_DATA, "GotStaleData", [this, packet]() { gotStaleData(packet); }); } return false; @@ -271,8 +222,7 @@ public: if (!node.has_nodeid() || !node.has_nodedata()) return; - auto newNode = - SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata())); + auto newNode = SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata())); if (!newNode) return; @@ -281,8 +231,7 @@ public: newNode->serializeWithPrefix(s); app_.getLedgerMaster().addFetchPack( - newNode->getHash().as_uint256(), - std::make_shared(s.begin(), s.end())); + newNode->getHash().as_uint256(), std::make_shared(s.begin(), s.end())); } } catch (std::exception const&) @@ -328,9 +277,7 @@ public: acqs.reserve(mLedgers.size()); for (auto const& it : mLedgers) { - XRPL_ASSERT( - it.second, - "ripple::InboundLedgersImp::getInfo : non-null ledger"); + XRPL_ASSERT(it.second, "xrpl::InboundLedgersImp::getInfo : non-null ledger"); acqs.push_back(it); } for (auto const& it : mRecentFailures) @@ -367,7 +314,7 @@ public: { XRPL_ASSERT( it.second, - "ripple::InboundLedgersImp::gotFetchPack : non-null " + "xrpl::InboundLedgersImp::gotFetchPack : non-null " "ledger"); acquires.push_back(it.second); } @@ -420,13 +367,9 @@ public: beast::expire(mRecentFailures, kReacquireInterval); } - JLOG(j_.debug()) - << "Swept " << stuffToSweep.size() << " out of " << total - << " inbound ledgers. Duration: " - << std::chrono::duration_cast( - m_clock.now() - start) - .count() - << "ms"; + JLOG(j_.debug()) << "Swept " << stuffToSweep.size() << " out of " << total << " inbound ledgers. Duration: " + << std::chrono::duration_cast(m_clock.now() - start).count() + << "ms"; } void @@ -473,8 +416,7 @@ make_InboundLedgers( InboundLedgers::clock_type& clock, beast::insight::Collector::ptr const& collector) { - return std::make_unique( - app, clock, collector, make_PeerSetBuilder(app)); + return std::make_unique(app, clock, collector, make_PeerSetBuilder(app)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/InboundTransactions.cpp b/src/xrpld/app/ledger/detail/InboundTransactions.cpp index 54477ccaed..36ebb7bd9e 100644 --- a/src/xrpld/app/ledger/detail/InboundTransactions.cpp +++ b/src/xrpld/app/ledger/detail/InboundTransactions.cpp @@ -1,37 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -#include #include +#include #include #include #include #include -namespace ripple { +namespace xrpl { enum { // Ideal number of peers to start with @@ -49,8 +30,7 @@ public: TransactionAcquire::pointer mAcquire; std::shared_ptr mSet; - InboundTransactionSet(std::uint32_t seq, std::shared_ptr const& set) - : mSeq(seq), mSet(set) + InboundTransactionSet(std::uint32_t seq, std::shared_ptr const& set) : mSeq(seq), mSet(set) { ; } @@ -75,8 +55,7 @@ public: , m_peerSetBuilder(std::move(peerSetBuilder)) , j_(app_.journal("InboundTransactions")) { - m_zeroSet.mSet = std::make_shared( - SHAMapType::TRANSACTION, uint256(), app_.getNodeFamily()); + m_zeroSet.mSet = std::make_shared(SHAMapType::TRANSACTION, uint256(), app_.getNodeFamily()); m_zeroSet.mSet->setUnbacked(); } @@ -118,8 +97,7 @@ public: if (!acquire || stopping_) return std::shared_ptr(); - ta = std::make_shared( - app_, hash, m_peerSetBuilder->build()); + ta = std::make_shared(app_, hash, m_peerSetBuilder->build()); auto& obj = m_map[hash]; obj.mAcquire = ta; @@ -134,15 +112,12 @@ public: /** We received a TMLedgerData from a peer. */ void - gotData( - LedgerHash const& hash, - std::shared_ptr peer, - std::shared_ptr packet_ptr) override + gotData(LedgerHash const& hash, std::shared_ptr peer, std::shared_ptr packet_ptr) + override { protocol::TMLedgerData& packet = *packet_ptr; - JLOG(j_.trace()) << "Got data (" << packet.nodes().size() - << ") for acquiring ledger: " << hash; + JLOG(j_.trace()) << "Got data (" << packet.nodes().size() << ") for acquiring ledger: " << hash; TransactionAcquire::pointer ta = getAcquire(hash); @@ -179,10 +154,7 @@ public: } void - giveSet( - uint256 const& hash, - std::shared_ptr const& set, - bool fromAcquire) override + giveSet(uint256 const& hash, std::shared_ptr const& set, bool fromAcquire) override { bool isNew = true; @@ -220,8 +192,7 @@ public: auto it = m_map.begin(); - std::uint32_t const minSeq = - (seq < setKeepRounds) ? 0 : (seq - setKeepRounds); + std::uint32_t const minSeq = (seq < setKeepRounds) ? 0 : (seq - setKeepRounds); std::uint32_t maxSeq = seq + setKeepRounds; while (it != m_map.end()) @@ -273,8 +244,7 @@ make_InboundTransactions( beast::insight::Collector::ptr const& collector, std::function const&, bool)> gotSet) { - return std::make_unique( - app, collector, std::move(gotSet), make_PeerSetBuilder(app)); + return std::make_unique(app, collector, std::move(gotSet), make_PeerSetBuilder(app)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp index 7c0dccfb9b..f54c79f9c0 100644 --- a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp +++ b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { /* @@ -72,8 +53,7 @@ class LedgerCleanerImp : public LedgerCleaner //-------------------------------------------------------------------------- public: - LedgerCleanerImp(Application& app, beast::Journal journal) - : app_(app), j_(journal) + LedgerCleanerImp(Application& app, beast::Journal journal) : app_(app), j_(journal) { } @@ -227,14 +207,10 @@ private: { std::unique_lock lock(mutex_); state_ = State::notCleaning; - wakeup_.wait(lock, [this]() { - return (shouldExit_ || state_ == State::cleaning); - }); + wakeup_.wait(lock, [this]() { return (shouldExit_ || state_ == State::cleaning); }); if (shouldExit_) break; - XRPL_ASSERT( - state_ == State::cleaning, - "ripple::LedgerCleanerImp::run : is cleaning"); + XRPL_ASSERT(state_ == State::cleaning, "xrpl::LedgerCleanerImp::run : is cleaning"); } doLedgerCleaner(); } @@ -251,12 +227,9 @@ private: } catch (SHAMapMissingNode const& mn) { - JLOG(j_.warn()) - << "Ledger #" << ledger->info().seq << ": " << mn.what(); + JLOG(j_.warn()) << "Ledger #" << ledger->header().seq << ": " << mn.what(); app_.getInboundLedgers().acquire( - ledger->info().hash, - ledger->info().seq, - InboundLedger::Reason::GENERIC); + ledger->header().hash, ledger->header().seq, InboundLedger::Reason::GENERIC); } return hash ? *hash : beast::zero; // kludge } @@ -269,37 +242,29 @@ private: @return `true` if the ledger was cleaned. */ bool - doLedger( - LedgerIndex const& ledgerIndex, - LedgerHash const& ledgerHash, - bool doNodes, - bool doTxns) + doLedger(LedgerIndex const& ledgerIndex, LedgerHash const& ledgerHash, bool doNodes, bool doTxns) { - auto nodeLedger = app_.getInboundLedgers().acquire( - ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); + auto nodeLedger = app_.getInboundLedgers().acquire(ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); if (!nodeLedger) { JLOG(j_.debug()) << "Ledger " << ledgerIndex << " not available"; app_.getLedgerMaster().clearLedger(ledgerIndex); - app_.getInboundLedgers().acquire( - ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); + app_.getInboundLedgers().acquire(ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); return false; } auto dbLedger = loadByIndex(ledgerIndex, app_); - if (!dbLedger || (dbLedger->info().hash != ledgerHash) || - (dbLedger->info().parentHash != nodeLedger->info().parentHash)) + if (!dbLedger || (dbLedger->header().hash != ledgerHash) || + (dbLedger->header().parentHash != nodeLedger->header().parentHash)) { // Ideally we'd also check for more than one ledger with that index - JLOG(j_.debug()) - << "Ledger " << ledgerIndex << " mismatches SQL DB"; + JLOG(j_.debug()) << "Ledger " << ledgerIndex << " mismatches SQL DB"; doTxns = true; } if (!app_.getLedgerMaster().fixIndex(ledgerIndex, ledgerHash)) { - JLOG(j_.debug()) - << "ledger " << ledgerIndex << " had wrong entry in history"; + JLOG(j_.debug()) << "ledger " << ledgerIndex << " had wrong entry in history"; doTxns = true; } @@ -307,8 +272,7 @@ private: { JLOG(j_.debug()) << "Ledger " << ledgerIndex << " is missing nodes"; app_.getLedgerMaster().clearLedger(ledgerIndex); - app_.getInboundLedgers().acquire( - ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); + app_.getInboundLedgers().acquire(ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC); return false; } @@ -327,13 +291,11 @@ private: @return The hash of the ledger. This will be all-bits-zero if not found. */ LedgerHash - getHash( - LedgerIndex const& ledgerIndex, - std::shared_ptr& referenceLedger) + getHash(LedgerIndex const& ledgerIndex, std::shared_ptr& referenceLedger) { LedgerHash ledgerHash; - if (!referenceLedger || (referenceLedger->info().seq < ledgerIndex)) + if (!referenceLedger || (referenceLedger->header().seq < ledgerIndex)) { referenceLedger = app_.getLedgerMaster().getValidatedLedger(); if (!referenceLedger) @@ -343,7 +305,7 @@ private: } } - if (referenceLedger->info().seq >= ledgerIndex) + if (referenceLedger->header().seq >= ledgerIndex) { // See if the hash for the ledger we need is in the reference ledger ledgerHash = getLedgerHash(referenceLedger, ledgerIndex); @@ -356,18 +318,15 @@ private: LedgerHash refHash = getLedgerHash(referenceLedger, refIndex); bool const nonzero(refHash.isNonZero()); - XRPL_ASSERT( - nonzero, - "ripple::LedgerCleanerImp::getHash : nonzero hash"); + XRPL_ASSERT(nonzero, "xrpl::LedgerCleanerImp::getHash : nonzero hash"); if (nonzero) { // We found the hash and sequence of a better reference // ledger. - referenceLedger = app_.getInboundLedgers().acquire( - refHash, refIndex, InboundLedger::Reason::GENERIC); + referenceLedger = + app_.getInboundLedgers().acquire(refHash, refIndex, InboundLedger::Reason::GENERIC); if (referenceLedger) - ledgerHash = - getLedgerHash(referenceLedger, ledgerIndex); + ledgerHash = getLedgerHash(referenceLedger, ledgerIndex); } } } @@ -404,8 +363,7 @@ private: { std::lock_guard lock(mutex_); - if ((minRange_ > maxRange_) || (maxRange_ == 0) || - (minRange_ == 0)) + if ((minRange_ > maxRange_) || (maxRange_ == 0) || (minRange_ == 0)) { minRange_ = maxRange_ = 0; return; @@ -420,8 +378,7 @@ private: bool fail = false; if (ledgerHash.isZero()) { - JLOG(j_.info()) - << "Unable to get hash for ledger " << ledgerIndex; + JLOG(j_.info()) << "Unable to get hash for ledger " << ledgerIndex; fail = true; } else if (!doLedger(ledgerIndex, ledgerHash, doNodes, doTxns)) @@ -462,4 +419,4 @@ make_LedgerCleaner(Application& app, beast::Journal journal) return std::make_unique(app, journal); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp index d312a09008..f06beda768 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp @@ -1,32 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include -namespace ripple { +#include + +namespace xrpl { LedgerDeltaAcquire::LedgerDeltaAcquire( Application& app, @@ -38,9 +20,7 @@ LedgerDeltaAcquire::LedgerDeltaAcquire( app, ledgerHash, LedgerReplayParameters::SUB_TASK_TIMEOUT, - {jtREPLAY_TASK, - "LedgerReplayDelta", - LedgerReplayParameters::MAX_QUEUED_TASKS}, + {jtREPLAY_TASK, "LedReplDelta", LedgerReplayParameters::MAX_QUEUED_TASKS}, app.journal("LedgerReplayDelta")) , inboundLedgers_(inboundLedgers) , ledgerSeq_(ledgerSeq) @@ -82,26 +62,22 @@ LedgerDeltaAcquire::trigger(std::size_t limit, ScopedLockType& sl) peerSet_->addPeers( limit, [this](auto peer) { - return peer->supportsFeature(ProtocolFeature::LedgerReplay) && - peer->hasLedger(hash_, ledgerSeq_); + return peer->supportsFeature(ProtocolFeature::LedgerReplay) && peer->hasLedger(hash_, ledgerSeq_); }, [this](auto peer) { if (peer->supportsFeature(ProtocolFeature::LedgerReplay)) { - JLOG(journal_.trace()) - << "Add a peer " << peer->id() << " for " << hash_; + JLOG(journal_.trace()) << "Add a peer " << peer->id() << " for " << hash_; protocol::TMReplayDeltaRequest request; request.set_ledgerhash(hash_.data(), hash_.size()); peerSet_->sendRequest(request, peer); } else { - if (++noFeaturePeerCount >= - LedgerReplayParameters::MAX_NO_FEATURE_PEER_COUNT) + if (++noFeaturePeerCount >= LedgerReplayParameters::MAX_NO_FEATURE_PEER_COUNT) { JLOG(journal_.debug()) << "Fall back for " << hash_; - timerInterval_ = - LedgerReplayParameters::SUB_TASK_FALLBACK_TIMEOUT; + timerInterval_ = LedgerReplayParameters::SUB_TASK_FALLBACK_TIMEOUT; fallBack_ = true; } } @@ -109,8 +85,7 @@ LedgerDeltaAcquire::trigger(std::size_t limit, ScopedLockType& sl) } if (fallBack_) - inboundLedgers_.acquire( - hash_, ledgerSeq_, InboundLedger::Reason::GENERIC); + inboundLedgers_.acquire(hash_, ledgerSeq_, InboundLedger::Reason::GENERIC); } void @@ -137,7 +112,7 @@ LedgerDeltaAcquire::pmDowncast() void LedgerDeltaAcquire::processData( - LedgerInfo const& info, + LedgerHeader const& info, std::map>&& orderedTxns) { ScopedLockType sl(mtx_); @@ -148,8 +123,7 @@ LedgerDeltaAcquire::processData( if (info.seq == ledgerSeq_) { // create a temporary ledger for building a LedgerReplay object later - replayTemp_ = - std::make_shared(info, app_.config(), app_.getNodeFamily()); + replayTemp_ = std::make_shared(info, app_.config(), app_.getNodeFamily()); if (replayTemp_) { complete_ = true; @@ -161,15 +135,12 @@ LedgerDeltaAcquire::processData( } failed_ = true; - JLOG(journal_.error()) - << "failed to create a (info only) ledger from verified data " << hash_; + JLOG(journal_.error()) << "failed to create a (info only) ledger from verified data " << hash_; notify(sl); } void -LedgerDeltaAcquire::addDataCallback( - InboundLedger::Reason reason, - OnDeltaDataCB&& cb) +LedgerDeltaAcquire::addDataCallback(InboundLedger::Reason reason, OnDeltaDataCB&& cb) { ScopedLockType sl(mtx_); dataReadyCallbacks_.emplace_back(std::move(cb)); @@ -182,8 +153,7 @@ LedgerDeltaAcquire::addDataCallback( if (isDone()) { - JLOG(journal_.debug()) - << "task added to a finished LedgerDeltaAcquire " << hash_; + JLOG(journal_.debug()) << "task added to a finished LedgerDeltaAcquire " << hash_; notify(sl); } } @@ -199,16 +169,14 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr const& parent) if (failed_ || !complete_ || !replayTemp_) return {}; + XRPL_ASSERT(parent->seq() + 1 == replayTemp_->seq(), "xrpl::LedgerDeltaAcquire::tryBuild : parent sequence match"); XRPL_ASSERT( - parent->seq() + 1 == replayTemp_->seq(), - "ripple::LedgerDeltaAcquire::tryBuild : parent sequence match"); - XRPL_ASSERT( - parent->info().hash == replayTemp_->info().parentHash, - "ripple::LedgerDeltaAcquire::tryBuild : parent hash match"); + parent->header().hash == replayTemp_->header().parentHash, + "xrpl::LedgerDeltaAcquire::tryBuild : parent hash match"); // build ledger LedgerReplay replayData(parent, replayTemp_, std::move(orderedTxns_)); fullLedger_ = buildLedger(replayData, tapNONE, app_, journal_); - if (fullLedger_ && fullLedger_->info().hash == hash_) + if (fullLedger_ && fullLedger_->header().hash == hash_) { JLOG(journal_.info()) << "Built " << hash_; onLedgerBuilt(sl); @@ -218,22 +186,17 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr const& parent) { failed_ = true; complete_ = false; - JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent " - << parent->info().hash; + JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent " << parent->header().hash; Throw("Cannot replay ledger"); } } void -LedgerDeltaAcquire::onLedgerBuilt( - ScopedLockType& sl, - std::optional reason) +LedgerDeltaAcquire::onLedgerBuilt(ScopedLockType& sl, std::optional reason) { - JLOG(journal_.debug()) << "onLedgerBuilt " << hash_ - << (reason ? " for a new reason" : ""); + JLOG(journal_.debug()) << "onLedgerBuilt " << hash_ << (reason ? " for a new reason" : ""); - std::vector reasons( - reasons_.begin(), reasons_.end()); + std::vector reasons(reasons_.begin(), reasons_.end()); bool firstTime = true; if (reason) // small chance { @@ -241,32 +204,29 @@ LedgerDeltaAcquire::onLedgerBuilt( reasons.push_back(*reason); firstTime = false; } - app_.getJobQueue().addJob( - jtREPLAY_TASK, - "onLedgerBuilt", - [=, ledger = this->fullLedger_, &app = this->app_]() { - for (auto reason : reasons) + app_.getJobQueue().addJob(jtREPLAY_TASK, "OnLedBuilt", [=, ledger = this->fullLedger_, &app = this->app_]() { + for (auto reason : reasons) + { + switch (reason) { - switch (reason) - { - case InboundLedger::Reason::GENERIC: - app.getLedgerMaster().storeLedger(ledger); - break; - default: - // TODO for other use cases - break; - } + case InboundLedger::Reason::GENERIC: + app.getLedgerMaster().storeLedger(ledger); + break; + default: + // TODO for other use cases + break; } + } - if (firstTime) - app.getLedgerMaster().tryAdvance(); - }); + if (firstTime) + app.getLedgerMaster().tryAdvance(); + }); } void LedgerDeltaAcquire::notify(ScopedLockType& sl) { - XRPL_ASSERT(isDone(), "ripple::LedgerDeltaAcquire::notify : is done"); + XRPL_ASSERT(isDone(), "xrpl::LedgerDeltaAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; @@ -280,4 +240,4 @@ LedgerDeltaAcquire::notify(ScopedLockType& sl) sl.lock(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h index 2435964766..66b8f27b85 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERDELTAACQUIRE_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERDELTAACQUIRE_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { class InboundLedgers; class PeerSet; namespace test { @@ -41,10 +21,9 @@ class LedgerReplayClient; * from the network. Before asking peers, always check if the local * node has the ledger. */ -class LedgerDeltaAcquire final - : public TimeoutCounter, - public std::enable_shared_from_this, - public CountedObject +class LedgerDeltaAcquire final : public TimeoutCounter, + public std::enable_shared_from_this, + public CountedObject { public: /** @@ -52,8 +31,7 @@ public: * @param successful if the ledger delta data was acquired successfully * @param hash hash of the ledger to build */ - using OnDeltaDataCB = - std::function; + using OnDeltaDataCB = std::function; /** * Constructor @@ -87,9 +65,7 @@ public: * @note info and Txns must have been verified against the ledger hash */ void - processData( - LedgerInfo const& info, - std::map>&& orderedTxns); + processData(LedgerHeader const& info, std::map>&& orderedTxns); /** * Try to build the ledger if not already @@ -135,9 +111,7 @@ private: * is added. */ void - onLedgerBuilt( - ScopedLockType& sl, - std::optional reason = {}); + onLedgerBuilt(ScopedLockType& sl, std::optional reason = {}); /** * Call the OnDeltaDataCB callbacks @@ -161,6 +135,4 @@ private: friend class test::LedgerReplayClient; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index f39e8af0b6..1fd1a8a8b2 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -33,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +28,7 @@ #include #include #include +#include #include #include @@ -56,7 +37,7 @@ #include #include -namespace ripple { +namespace xrpl { // Don't catch up more than 100 ledgers (cannot exceed 256) static constexpr int MAX_LEDGER_GAP{100}; @@ -91,8 +72,7 @@ shouldAcquire( return minimumOnline.has_value() && candidateLedger >= *minimumOnline; }(); - JLOG(j.trace()) << "Missing ledger " << candidateLedger - << (ret ? " should" : " should NOT") << " be acquired"; + JLOG(j.trace()) << "Missing ledger " << candidateLedger << (ret ? " should" : " should NOT") << " be acquired"; return ret; } @@ -105,16 +85,10 @@ LedgerMaster::LedgerMaster( , m_journal(journal) , mLedgerHistory(collector, app) , standalone_(app_.config().standalone()) - , fetch_depth_( - app_.getSHAMapStore().clampFetchDepth(app_.config().FETCH_DEPTH)) + , fetch_depth_(app_.getSHAMapStore().clampFetchDepth(app_.config().FETCH_DEPTH)) , ledger_history_(app_.config().LEDGER_HISTORY) , ledger_fetch_size_(app_.config().getValueFor(SizedItem::ledgerFetch)) - , fetch_packs_( - "FetchPack", - 65536, - std::chrono::seconds{45}, - stopwatch, - app_.journal("TaggedCache")) + , fetch_packs_("FetchPack", 65536, std::chrono::seconds{45}, stopwatch, app_.journal("TaggedCache")) , m_stats(std::bind(&LedgerMaster::collect_metrics, this), collector) { } @@ -122,7 +96,7 @@ LedgerMaster::LedgerMaster( LedgerIndex LedgerMaster::getCurrentLedgerIndex() { - return app_.openLedger().current()->info().seq; + return app_.openLedger().current()->header().seq; } LedgerIndex @@ -132,10 +106,7 @@ LedgerMaster::getValidLedgerIndex() } bool -LedgerMaster::isCompatible( - ReadView const& view, - beast::Journal::Stream s, - char const* reason) +LedgerMaster::isCompatible(ReadView const& view, beast::Journal::Stream s, char const* reason) { auto validLedger = getValidatedLedger(); @@ -148,12 +119,7 @@ LedgerMaster::isCompatible( std::lock_guard sl(m_mutex); if ((mLastValidLedger.second != 0) && - !areCompatible( - mLastValidLedger.first, - mLastValidLedger.second, - view, - s, - reason)) + !areCompatible(mLastValidLedger.first, mLastValidLedger.second, view, s, reason)) { return false; } @@ -245,8 +211,7 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) if (!standalone_) { auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger( - l->info().hash, l->info().seq)); + app_.getValidations().getTrustedForLedger(l->header().hash, l->header().seq)); times.reserve(validations.size()); for (auto const& val : validations) times.push_back(val->getSignTime()); @@ -267,18 +232,17 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) } else { - signTime = l->info().closeTime; + signTime = l->header().closeTime; } mValidLedger.set(l); mValidLedgerSign = signTime.time_since_epoch().count(); XRPL_ASSERT( mValidLedgerSeq || !app_.getMaxDisallowedLedger() || - l->info().seq + max_ledger_difference_ > - app_.getMaxDisallowedLedger(), - "ripple::LedgerMaster::setValidLedger : valid ledger sequence"); + l->header().seq + max_ledger_difference_ > app_.getMaxDisallowedLedger(), + "xrpl::LedgerMaster::setValidLedger : valid ledger sequence"); (void)max_ledger_difference_; - mValidLedgerSeq = l->info().seq; + mValidLedgerSeq = l->header().seq; app_.getOPs().updateLocalTx(*l); app_.getSHAMapStore().onLedgerClosed(getValidatedLedger()); @@ -303,8 +267,7 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) // this message may be logged more than once per session, because // the node will otherwise function normally, and this gives // operators an opportunity to see and resolve the warning. - if (auto const first = - app_.getAmendmentTable().firstUnsupportedExpected()) + if (auto const first = app_.getAmendmentTable().firstUnsupportedExpected()) { JLOG(m_journal.error()) << "One or more unsupported amendments " "reached majority. Upgrade before " @@ -323,13 +286,12 @@ void LedgerMaster::setPubLedger(std::shared_ptr const& l) { mPubLedger = l; - mPubLedgerClose = l->info().closeTime.time_since_epoch().count(); - mPubLedgerSeq = l->info().seq; + mPubLedgerClose = l->header().closeTime.time_since_epoch().count(); + mPubLedgerSeq = l->header().seq; } void -LedgerMaster::addHeldTransaction( - std::shared_ptr const& transaction) +LedgerMaster::addHeldTransaction(std::shared_ptr const& transaction) { std::lock_guard ml(m_mutex); mHeldTransactions.insert(transaction->getSTransaction()); @@ -341,17 +303,16 @@ LedgerMaster::addHeldTransaction( bool LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) { - XRPL_ASSERT(ledger, "ripple::LedgerMaster::canBeCurrent : non-null input"); + XRPL_ASSERT(ledger, "xrpl::LedgerMaster::canBeCurrent : non-null input"); // Never jump to a candidate ledger that precedes our // last validated ledger auto validLedger = getValidatedLedger(); - if (validLedger && (ledger->info().seq < validLedger->info().seq)) + if (validLedger && (ledger->header().seq < validLedger->header().seq)) { - JLOG(m_journal.trace()) - << "Candidate for current ledger has low seq " << ledger->info().seq - << " < " << validLedger->info().seq; + JLOG(m_journal.trace()) << "Candidate for current ledger has low seq " << ledger->header().seq << " < " + << validLedger->header().seq; return false; } @@ -361,17 +322,14 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) // few ledgers as our clock can be off when we first start up auto closeTime = app_.timeKeeper().closeTime(); - auto ledgerClose = ledger->info().parentCloseTime; + auto ledgerClose = ledger->header().parentCloseTime; using namespace std::chrono_literals; - if ((validLedger || (ledger->info().seq > 10)) && - ((std::max(closeTime, ledgerClose) - std::min(closeTime, ledgerClose)) > - 5min)) + if ((validLedger || (ledger->header().seq > 10)) && + ((std::max(closeTime, ledgerClose) - std::min(closeTime, ledgerClose)) > 5min)) { - JLOG(m_journal.warn()) - << "Candidate for current ledger has close time " - << to_string(ledgerClose) << " at network time " - << to_string(closeTime) << " seq " << ledger->info().seq; + JLOG(m_journal.warn()) << "Candidate for current ledger has close time " << to_string(ledgerClose) + << " at network time " << to_string(closeTime) << " seq " << ledger->header().seq; return false; } @@ -382,25 +340,23 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) // every two seconds. The goal is to prevent a malicious ledger // from increasing our sequence unreasonably high - LedgerIndex maxSeq = validLedger->info().seq + 10; + LedgerIndex maxSeq = validLedger->header().seq + 10; - if (closeTime > validLedger->info().parentCloseTime) - maxSeq += std::chrono::duration_cast( - closeTime - validLedger->info().parentCloseTime) - .count() / + if (closeTime > validLedger->header().parentCloseTime) + maxSeq += + std::chrono::duration_cast(closeTime - validLedger->header().parentCloseTime) + .count() / 2; - if (ledger->info().seq > maxSeq) + if (ledger->header().seq > maxSeq) { - JLOG(m_journal.warn()) - << "Candidate for current ledger has high seq " - << ledger->info().seq << " > " << maxSeq; + JLOG(m_journal.warn()) << "Candidate for current ledger has high seq " << ledger->header().seq << " > " + << maxSeq; return false; } - JLOG(m_journal.trace()) - << "Acceptable seq range: " << validLedger->info().seq - << " <= " << ledger->info().seq << " <= " << maxSeq; + JLOG(m_journal.trace()) << "Acceptable seq range: " << validLedger->header().seq + << " <= " << ledger->header().seq << " <= " << maxSeq; } return true; @@ -409,7 +365,7 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) void LedgerMaster::switchLCL(std::shared_ptr const& lastClosed) { - XRPL_ASSERT(lastClosed, "ripple::LedgerMaster::switchLCL : non-null input"); + XRPL_ASSERT(lastClosed, "xrpl::LedgerMaster::switchLCL : non-null input"); if (!lastClosed->isImmutable()) LogicError("mutable ledger in switchLCL"); @@ -441,7 +397,7 @@ LedgerMaster::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash) bool LedgerMaster::storeLedger(std::shared_ptr ledger) { - bool validated = ledger->info().validated; + bool validated = ledger->header().validated; // Returns true if we already had the ledger return mLedgerHistory.insert(std::move(ledger), validated); } @@ -458,7 +414,7 @@ LedgerMaster::applyHeldTransactions() std::lock_guard sl(m_mutex); // VFALCO NOTE The hash for an open ledger is undefined so we use // something that is a reasonable substitute. - CanonicalTXSet set(app_.openLedger().current()->info().parentHash); + CanonicalTXSet set(app_.openLedger().current()->header().parentHash); std::swap(mHeldTransactions, set); return set; }(); @@ -501,10 +457,10 @@ LedgerMaster::isValidated(ReadView const& ledger) if (ledger.open()) return false; - if (ledger.info().validated) + if (ledger.header().validated) return true; - auto const seq = ledger.info().seq; + auto const seq = ledger.header().seq; try { // Use the skip list in the last validated ledger to see if ledger @@ -512,17 +468,14 @@ LedgerMaster::isValidated(ReadView const& ledger) // validated). auto const hash = walkHashBySeq(seq, InboundLedger::Reason::GENERIC); - if (!hash || ledger.info().hash != *hash) + if (!hash || ledger.header().hash != *hash) { // This ledger's hash is not the hash of the validated ledger if (hash) { - XRPL_ASSERT( - hash->isNonZero(), - "ripple::LedgerMaster::isValidated : nonzero hash"); - uint256 valHash = - app_.getRelationalDatabase().getHashByIndex(seq); - if (valHash == ledger.info().hash) + XRPL_ASSERT(hash->isNonZero(), "xrpl::LedgerMaster::isValidated : nonzero hash"); + uint256 valHash = app_.getRelationalDatabase().getHashByIndex(seq); + if (valHash == ledger.header().hash) { // SQL database doesn't match ledger chain clearLedger(seq); @@ -538,15 +491,13 @@ LedgerMaster::isValidated(ReadView const& ledger) } // Mark ledger as validated to save time if we see it again. - ledger.info().validated = true; + ledger.header().validated = true; return true; } // returns Ledgers we have all the nodes for bool -LedgerMaster::getFullValidatedRange( - std::uint32_t& minVal, - std::uint32_t& maxVal) +LedgerMaster::getFullValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal) { // Validated ledger is likely not stored in the DB yet so we use the // published ledger which is. @@ -616,7 +567,7 @@ LedgerMaster::getEarliestFetch() { // The earliest ledger we will let people fetch is ledger zero, // unless that creates a larger range than allowed - std::uint32_t e = getClosedLedger()->info().seq; + std::uint32_t e = getClosedLedger()->header().seq; if (e > fetch_depth_) e -= fetch_depth_; @@ -628,8 +579,8 @@ LedgerMaster::getEarliestFetch() void LedgerMaster::tryFill(std::shared_ptr ledger) { - std::uint32_t seq = ledger->info().seq; - uint256 prevHash = ledger->info().parentHash; + std::uint32_t seq = ledger->header().seq; + uint256 prevHash = ledger->header().parentHash; std::map ledgerHashes; @@ -660,20 +611,16 @@ LedgerMaster::tryFill(std::shared_ptr ledger) mCompleteLedgers.insert(range(minHas, maxHas)); } maxHas = minHas; - ledgerHashes = app_.getRelationalDatabase().getHashesByIndex( - (seq < 500) ? 0 : (seq - 499), seq); + ledgerHashes = app_.getRelationalDatabase().getHashesByIndex((seq < 500) ? 0 : (seq - 499), seq); it = ledgerHashes.find(seq); if (it == ledgerHashes.end()) break; - if (!nodeStore.fetchNodeObject( - ledgerHashes.begin()->second.ledgerHash, - ledgerHashes.begin()->first)) + if (!nodeStore.fetchNodeObject(ledgerHashes.begin()->second.ledgerHash, ledgerHashes.begin()->first)) { // The ledger is not backed by the node store - JLOG(m_journal.warn()) << "SQL DB ledger sequence " << seq - << " mismatches node store"; + JLOG(m_journal.warn()) << "SQL DB ledger sequence " << seq << " mismatches node store"; break; } } @@ -705,8 +652,7 @@ LedgerMaster::getFetchPack(LedgerIndex missing, InboundLedger::Reason reason) auto const haveHash{getLedgerHashForHistory(ledgerIndex, reason)}; if (!haveHash || haveHash->isZero()) { - JLOG(m_journal.error()) - << "No hash for fetch pack. Missing Index " << missing; + JLOG(m_journal.error()) << "No hash for fetch pack. Missing Index " << missing; return; } @@ -751,7 +697,7 @@ LedgerMaster::fixMismatch(ReadView const& ledger) int invalidate = 0; std::optional hash; - for (std::uint32_t lSeq = ledger.info().seq - 1; lSeq > 0; --lSeq) + for (std::uint32_t lSeq = ledger.header().seq - 1; lSeq > 0; --lSeq) { if (haveLedger(lSeq)) { @@ -761,9 +707,7 @@ LedgerMaster::fixMismatch(ReadView const& ledger) } catch (std::exception const& ex) { - JLOG(m_journal.warn()) - << "fixMismatch encounters partial ledger. Exception: " - << ex.what(); + JLOG(m_journal.warn()) << "fixMismatch encounters partial ledger. Exception: " << ex.what(); clearLedger(lSeq); return; } @@ -773,14 +717,13 @@ LedgerMaster::fixMismatch(ReadView const& ledger) // try to close the seam auto otherLedger = getLedgerBySeq(lSeq); - if (otherLedger && (otherLedger->info().hash == *hash)) + if (otherLedger && (otherLedger->header().hash == *hash)) { // we closed the seam if (invalidate != 0) { JLOG(m_journal.warn()) - << "Match at " << lSeq << ", " << invalidate - << " prior ledgers invalidated"; + << "Match at " << lSeq << ", " << invalidate << " prior ledgers invalidated"; } return; @@ -795,23 +738,17 @@ LedgerMaster::fixMismatch(ReadView const& ledger) // all prior ledgers invalidated if (invalidate != 0) { - JLOG(m_journal.warn()) - << "All " << invalidate << " prior ledgers invalidated"; + JLOG(m_journal.warn()) << "All " << invalidate << " prior ledgers invalidated"; } } void -LedgerMaster::setFullLedger( - std::shared_ptr const& ledger, - bool isSynchronous, - bool isCurrent) +LedgerMaster::setFullLedger(std::shared_ptr const& ledger, bool isSynchronous, bool isCurrent) { // A new ledger has been accepted as part of the trusted chain - JLOG(m_journal.debug()) << "Ledger " << ledger->info().seq - << " accepted :" << ledger->info().hash; + JLOG(m_journal.debug()) << "Ledger " << ledger->header().seq << " accepted :" << ledger->header().hash; XRPL_ASSERT( - ledger->stateMap().getHash().isNonZero(), - "ripple::LedgerMaster::setFullLedger : nonzero ledger state hash"); + ledger->stateMap().getHash().isNonZero(), "xrpl::LedgerMaster::setFullLedger : nonzero ledger state hash"); ledger->setValidated(); ledger->setFull(); @@ -822,23 +759,22 @@ LedgerMaster::setFullLedger( { // Check the SQL database's entry for the sequence before this // ledger, if it's not this ledger's parent, invalidate it - uint256 prevHash = - app_.getRelationalDatabase().getHashByIndex(ledger->info().seq - 1); - if (prevHash.isNonZero() && prevHash != ledger->info().parentHash) - clearLedger(ledger->info().seq - 1); + uint256 prevHash = app_.getRelationalDatabase().getHashByIndex(ledger->header().seq - 1); + if (prevHash.isNonZero() && prevHash != ledger->header().parentHash) + clearLedger(ledger->header().seq - 1); } pendSaveValidated(app_, ledger, isSynchronous, isCurrent); { std::lock_guard ml(mCompleteLock); - mCompleteLedgers.insert(ledger->info().seq); + mCompleteLedgers.insert(ledger->header().seq); } { std::lock_guard ml(m_mutex); - if (ledger->info().seq > mValidLedgerSeq) + if (ledger->header().seq > mValidLedgerSeq) setValidLedger(ledger); if (!mPubLedger) { @@ -846,17 +782,15 @@ LedgerMaster::setFullLedger( app_.getOrderBookDB().setup(ledger); } - if (ledger->info().seq != 0 && haveLedger(ledger->info().seq - 1)) + if (ledger->header().seq != 0 && haveLedger(ledger->header().seq - 1)) { // we think we have the previous ledger, double check - auto prevLedger = getLedgerBySeq(ledger->info().seq - 1); + auto prevLedger = getLedgerBySeq(ledger->header().seq - 1); - if (!prevLedger || - (prevLedger->info().hash != ledger->info().parentHash)) + if (!prevLedger || (prevLedger->header().hash != ledger->header().parentHash)) { - JLOG(m_journal.warn()) - << "Acquired ledger invalidates previous ledger: " - << (prevLedger ? "hashMismatch" : "missingLedger"); + JLOG(m_journal.warn()) << "Acquired ledger invalidates previous ledger: " + << (prevLedger ? "hashMismatch" : "missingLedger"); fixMismatch(*ledger); } } @@ -883,8 +817,7 @@ LedgerMaster::checkAccept(uint256 const& hash, std::uint32_t seq) if (seq < mValidLedgerSeq) return; - auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger(hash, seq)); + auto validations = app_.validators().negativeUNLFilter(app_.getValidations().getTrustedForLedger(hash, seq)); valCount = validations.size(); if (valCount >= app_.validators().quorum()) { @@ -914,8 +847,7 @@ LedgerMaster::checkAccept(uint256 const& hash, std::uint32_t seq) // FIXME: We may not want to fetch a ledger with just one // trusted validation - ledger = app_.getInboundLedgers().acquire( - hash, seq, InboundLedger::Reason::GENERIC); + ledger = app_.getInboundLedgers().acquire(hash, seq, InboundLedger::Reason::GENERIC); } if (ledger) @@ -945,23 +877,20 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) // publish? std::lock_guard ml(m_mutex); - if (ledger->info().seq <= mValidLedgerSeq) + if (ledger->header().seq <= mValidLedgerSeq) return; auto const minVal = getNeededValidations(); auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger( - ledger->info().hash, ledger->info().seq)); + app_.getValidations().getTrustedForLedger(ledger->header().hash, ledger->header().seq)); auto const tvc = validations.size(); if (tvc < minVal) // nothing we can do { - JLOG(m_journal.trace()) - << "Only " << tvc << " validations for " << ledger->info().hash; + JLOG(m_journal.trace()) << "Only " << tvc << " validations for " << ledger->header().hash; return; } - JLOG(m_journal.info()) << "Advancing accepted ledger to " - << ledger->info().seq << " with >= " << minVal + JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq << " with >= " << minVal << " validations"; ledger->setValidated(); @@ -975,10 +904,9 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) } std::uint32_t const base = app_.getFeeTrack().getLoadBase(); - auto fees = app_.getValidations().fees(ledger->info().hash, base); + auto fees = app_.getValidations().fees(ledger->header().hash, base); { - auto fees2 = - app_.getValidations().fees(ledger->info().parentHash, base); + auto fees2 = app_.getValidations().fees(ledger->header().parentHash, base); fees.reserve(fees.size() + fees2.size()); std::copy(fees2.begin(), fees2.end(), std::back_inserter(fees)); } @@ -1012,10 +940,10 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) // Check if the majority of validators run a higher version rippled // software. If so print a warning. // - // Once the HardenedValidations amendment is enabled, validators include - // their rippled software version in the validation messages of every - // (flag - 1) ledger. We wait for one ledger time before checking the - // version information to accumulate more validation messages. + // Validators include their rippled software version in the validation + // messages of every (flag - 1) ledger. We wait for one ledger time + // before checking the version information to accumulate more validation + // messages. auto currentTime = app_.timeKeeper().now(); bool needPrint = false; @@ -1025,8 +953,8 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) if (upgradeWarningPrevTime_ == TimeKeeper::time_point()) { // Have not printed the warning before, check if need to print. - auto const vals = app_.getValidations().getTrustedForLedger( - ledger->info().parentHash, ledger->info().seq - 1); + auto const vals = + app_.getValidations().getTrustedForLedger(ledger->header().parentHash, ledger->header().seq - 1); std::size_t higherVersionCount = 0; std::size_t rippledCount = 0; for (auto const& v : vals) @@ -1034,10 +962,8 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) if (v->isFieldPresent(sfServerVersion)) { auto version = v->getFieldU64(sfServerVersion); - higherVersionCount += - BuildInfo::isNewerVersion(version) ? 1 : 0; - rippledCount += - BuildInfo::isRippledVersion(version) ? 1 : 0; + higherVersionCount += BuildInfo::isNewerVersion(version) ? 1 : 0; + rippledCount += BuildInfo::isRippledVersion(version) ? 1 : 0; } } // We report only if (1) we have accumulated validation messages @@ -1048,13 +974,9 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) { constexpr std::size_t reportingPercent = 90; constexpr std::size_t cutoffPercent = 60; - auto const unlSize{ - app_.validators().getQuorumKeys().second.size()}; - needPrint = unlSize > 0 && - calculatePercent(vals.size(), unlSize) >= - reportingPercent && - calculatePercent(higherVersionCount, rippledCount) >= - cutoffPercent; + auto const unlSize{app_.validators().getQuorumKeys().second.size()}; + needPrint = unlSize > 0 && calculatePercent(vals.size(), unlSize) >= reportingPercent && + calculatePercent(higherVersionCount, rippledCount) >= cutoffPercent; } } // To throttle the warning messages, instead of printing a warning @@ -1096,18 +1018,17 @@ LedgerMaster::consensusBuilt( mLedgerHistory.builtLedger(ledger, consensusHash, std::move(consensus)); - if (ledger->info().seq <= mValidLedgerSeq) + if (ledger->header().seq <= mValidLedgerSeq) { auto stream = app_.journal("LedgerConsensus").info(); - JLOG(stream) << "Consensus built old ledger: " << ledger->info().seq - << " <= " << mValidLedgerSeq; + JLOG(stream) << "Consensus built old ledger: " << ledger->header().seq << " <= " << mValidLedgerSeq; return; } // See if this ledger can be the new fully-validated ledger checkAccept(ledger); - if (ledger->info().seq <= mValidLedgerSeq) + if (ledger->header().seq <= mValidLedgerSeq) { auto stream = app_.journal("LedgerConsensus").debug(); JLOG(stream) << "Consensus ledger fully validated"; @@ -1117,8 +1038,7 @@ LedgerMaster::consensusBuilt( // This ledger cannot be the new fully-validated ledger, but // maybe we saved up validations for some other ledger that can be - auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().currentTrusted()); + auto validations = app_.validators().negativeUNLFilter(app_.getValidations().currentTrusted()); // Track validation counts with sequence numbers class valSeq @@ -1153,7 +1073,7 @@ LedgerMaster::consensusBuilt( auto const neededValidations = getNeededValidations(); auto maxSeq = mValidLedgerSeq.load(); - auto maxLedger = ledger->info().hash; + auto maxLedger = ledger->header().hash; // Of the ledgers with sufficient validations, // find the one with the highest sequence @@ -1164,7 +1084,7 @@ LedgerMaster::consensusBuilt( if (v.second.ledgerSeq_ == 0) { if (auto l = getLedgerByHash(v.first)) - v.second.ledgerSeq_ = l->info().seq; + v.second.ledgerSeq_ = l->header().seq; } if (v.second.ledgerSeq_ > maxSeq) @@ -1183,15 +1103,13 @@ LedgerMaster::consensusBuilt( } std::optional -LedgerMaster::getLedgerHashForHistory( - LedgerIndex index, - InboundLedger::Reason reason) +LedgerMaster::getLedgerHashForHistory(LedgerIndex index, InboundLedger::Reason reason) { // Try to get the hash of a ledger we need to fetch for history std::optional ret; auto const& l{mHistLedger}; - if (l && l->info().seq >= index) + if (l && l->header().seq >= index) { ret = hashOfSeq(*l, index, m_journal); if (!ret) @@ -1205,8 +1123,7 @@ LedgerMaster::getLedgerHashForHistory( } std::vector> -LedgerMaster::findNewLedgersToPublish( - std::unique_lock& sl) +LedgerMaster::findNewLedgersToPublish(std::unique_lock& sl) { std::vector> ret; @@ -1221,15 +1138,13 @@ LedgerMaster::findNewLedgersToPublish( if (!mPubLedger) { - JLOG(m_journal.info()) - << "First published ledger will be " << mValidLedgerSeq; + JLOG(m_journal.info()) << "First published ledger will be " << mValidLedgerSeq; return {mValidLedger.get()}; } if (mValidLedgerSeq > (mPubLedgerSeq + MAX_LEDGER_GAP)) { - JLOG(m_journal.warn()) << "Gap in validated ledger stream " - << mPubLedgerSeq << " - " << mValidLedgerSeq - 1; + JLOG(m_journal.warn()) << "Gap in validated ledger stream " << mPubLedgerSeq << " - " << mValidLedgerSeq - 1; auto valLedger = mValidLedger.get(); ret.push_back(valLedger); @@ -1249,15 +1164,14 @@ LedgerMaster::findNewLedgersToPublish( auto pubSeq = mPubLedgerSeq + 1; // Next sequence to publish auto valLedger = mValidLedger.get(); - std::uint32_t valSeq = valLedger->info().seq; + std::uint32_t valSeq = valLedger->header().seq; scope_unlock sul{sl}; try { for (std::uint32_t seq = pubSeq; seq <= valSeq; ++seq) { - JLOG(m_journal.trace()) - << "Trying to fetch/publish valid ledger " << seq; + JLOG(m_journal.trace()) << "Trying to fetch/publish valid ledger " << seq; std::shared_ptr ledger; // This can throw @@ -1274,10 +1188,9 @@ LedgerMaster::findNewLedgersToPublish( else if (hash->isZero()) { // LCOV_EXCL_START - JLOG(m_journal.fatal()) << "Ledger: " << valSeq - << " does not have hash for " << seq; + JLOG(m_journal.fatal()) << "Ledger: " << valSeq << " does not have hash for " << seq; UNREACHABLE( - "ripple::LedgerMaster::findNewLedgersToPublish : ledger " + "xrpl::LedgerMaster::findNewLedgersToPublish : ledger " "not found"); // LCOV_EXCL_STOP } @@ -1290,12 +1203,11 @@ LedgerMaster::findNewLedgersToPublish( { // Can we try to acquire the ledger we need? if (!ledger && (++acqCount < ledger_fetch_size_)) - ledger = app_.getInboundLedgers().acquire( - *hash, seq, InboundLedger::Reason::GENERIC); + ledger = app_.getInboundLedgers().acquire(*hash, seq, InboundLedger::Reason::GENERIC); } // Did we acquire the next ledger we need to publish? - if (ledger && (ledger->info().seq == pubSeq)) + if (ledger && (ledger->header().seq == pubSeq)) { ledger->setValidated(); ret.push_back(ledger); @@ -1303,14 +1215,11 @@ LedgerMaster::findNewLedgersToPublish( } } - JLOG(m_journal.trace()) - << "ready to publish " << ret.size() << " ledgers."; + JLOG(m_journal.trace()) << "ready to publish " << ret.size() << " ledgers."; } catch (std::exception const& ex) { - JLOG(m_journal.error()) - << "Exception while trying to find ledgers to publish: " - << ex.what(); + JLOG(m_journal.error()) << "Exception while trying to find ledgers to publish: " << ex.what(); } if (app_.config().LEDGER_REPLAY) @@ -1325,26 +1234,19 @@ LedgerMaster::findNewLedgersToPublish( auto finishLedger = valLedger; while (startLedger->seq() + 1 < finishLedger->seq()) { - if (auto const parent = mLedgerHistory.getLedgerByHash( - finishLedger->info().parentHash); - parent) + if (auto const parent = mLedgerHistory.getLedgerByHash(finishLedger->header().parentHash); parent) { finishLedger = parent; } else { - auto numberLedgers = - finishLedger->seq() - startLedger->seq() + 1; - JLOG(m_journal.debug()) - << "Publish LedgerReplays " << numberLedgers - << " ledgers, from seq=" << startLedger->info().seq << ", " - << startLedger->info().hash - << " to seq=" << finishLedger->info().seq << ", " - << finishLedger->info().hash; + auto numberLedgers = finishLedger->seq() - startLedger->seq() + 1; + JLOG(m_journal.debug()) << "Publish LedgerReplays " << numberLedgers + << " ledgers, from seq=" << startLedger->header().seq << ", " + << startLedger->header().hash << " to seq=" << finishLedger->header().seq + << ", " << finishLedger->header().hash; app_.getLedgerReplayer().replay( - InboundLedger::Reason::GENERIC, - finishLedger->info().hash, - numberLedgers); + InboundLedger::Reason::GENERIC, finishLedger->header().hash, numberLedgers); break; } } @@ -1363,12 +1265,10 @@ LedgerMaster::tryAdvance() if (!mAdvanceThread && !mValidLedger.empty()) { mAdvanceThread = true; - app_.getJobQueue().addJob(jtADVANCE, "advanceLedger", [this]() { + app_.getJobQueue().addJob(jtADVANCE, "AdvanceLedger", [this]() { std::unique_lock sl(m_mutex); - XRPL_ASSERT( - !mValidLedger.empty() && mAdvanceThread, - "ripple::LedgerMaster::tryAdvance : has valid ledger"); + XRPL_ASSERT(!mValidLedger.empty() && mAdvanceThread, "xrpl::LedgerMaster::tryAdvance : has valid ledger"); JLOG(m_journal.trace()) << "advanceThread<"; @@ -1408,8 +1308,7 @@ LedgerMaster::updatePaths() { std::lock_guard ml(m_mutex); - if (!mValidLedger.empty() && - (!mPathLedger || (mPathLedger->info().seq != mValidLedgerSeq))) + if (!mValidLedger.empty() && (!mPathLedger || (mPathLedger->header().seq != mValidLedgerSeq))) { // We have a new valid ledger since the last full pathfinding mPathLedger = mValidLedger.get(); lastLedger = mPathLedger; @@ -1430,12 +1329,10 @@ LedgerMaster::updatePaths() if (!standalone_) { // don't pathfind with a ledger that's more than 60 seconds old using namespace std::chrono; - auto age = time_point_cast(app_.timeKeeper().closeTime()) - - lastLedger->info().closeTime; + auto age = time_point_cast(app_.timeKeeper().closeTime()) - lastLedger->header().closeTime; if (age > 1min) { - JLOG(m_journal.debug()) - << "Published ledger too old for updating paths"; + JLOG(m_journal.debug()) << "Published ledger too old for updating paths"; std::lock_guard ml(m_mutex); --mPathFindThread; mPathLedger.reset(); @@ -1452,10 +1349,9 @@ LedgerMaster::updatePaths() { --mPathFindThread; mPathLedger.reset(); - JLOG(m_journal.debug()) - << "No path requests found. Nothing to do for updating " - "paths. " - << mPathFindThread << " jobs remaining"; + JLOG(m_journal.debug()) << "No path requests found. Nothing to do for updating " + "paths. " + << mPathFindThread << " jobs remaining"; return; } } @@ -1465,9 +1361,8 @@ LedgerMaster::updatePaths() std::lock_guard ml(m_mutex); if (!pathRequests.requestsPending()) { - JLOG(m_journal.debug()) - << "No path requests left. No need for further updating " - "paths"; + JLOG(m_journal.debug()) << "No path requests left. No need for further updating " + "paths"; --mPathFindThread; mPathLedger.reset(); return; @@ -1480,17 +1375,13 @@ LedgerMaster::updatePaths() { // our parent is the problem app_.getInboundLedgers().acquire( - lastLedger->info().parentHash, - lastLedger->info().seq - 1, - InboundLedger::Reason::GENERIC); + lastLedger->header().parentHash, lastLedger->header().seq - 1, InboundLedger::Reason::GENERIC); } else { // this ledger is the problem app_.getInboundLedgers().acquire( - lastLedger->info().hash, - lastLedger->info().seq, - InboundLedger::Reason::GENERIC); + lastLedger->header().hash, lastLedger->header().seq, InboundLedger::Reason::GENERIC); } } } @@ -1500,7 +1391,7 @@ bool LedgerMaster::newPathRequest() { std::unique_lock ml(m_mutex); - mPathFindNewRequest = newPFWork("pf:newRequest", ml); + mPathFindNewRequest = newPFWork("PthFindNewReq", ml); return mPathFindNewRequest; } @@ -1521,24 +1412,18 @@ LedgerMaster::newOrderBookDB() std::unique_lock ml(m_mutex); mPathLedger.reset(); - return newPFWork("pf:newOBDB", ml); + return newPFWork("PthFindOBDB", ml); } /** A thread needs to be dispatched to handle pathfinding work of some kind. */ bool -LedgerMaster::newPFWork( - char const* name, - std::unique_lock&) +LedgerMaster::newPFWork(char const* name, std::unique_lock&) { - if (!app_.isStopping() && mPathFindThread < 2 && - app_.getPathRequests().requestsPending()) + if (!app_.isStopping() && mPathFindThread < 2 && app_.getPathRequests().requestsPending()) { - JLOG(m_journal.debug()) - << "newPFWork: Creating job. path find threads: " - << mPathFindThread; - if (app_.getJobQueue().addJob( - jtUPDATE_PF, name, [this]() { updatePaths(); })) + JLOG(m_journal.debug()) << "newPFWork: Creating job. path find threads: " << mPathFindThread; + if (app_.getJobQueue().addJob(jtUPDATE_PF, name, [this]() { updatePaths(); })) { ++mPathFindThread; } @@ -1600,20 +1485,16 @@ std::optional LedgerMaster::getCloseTimeBySeq(LedgerIndex ledgerIndex) { uint256 hash = getHashBySeq(ledgerIndex); - return hash.isNonZero() ? getCloseTimeByHash(hash, ledgerIndex) - : std::nullopt; + return hash.isNonZero() ? getCloseTimeByHash(hash, ledgerIndex) : std::nullopt; } std::optional -LedgerMaster::getCloseTimeByHash( - LedgerHash const& ledgerHash, - std::uint32_t index) +LedgerMaster::getCloseTimeByHash(LedgerHash const& ledgerHash, std::uint32_t index) { auto nodeObject = app_.getNodeStore().fetchNodeObject(ledgerHash, index); if (nodeObject && (nodeObject->getData().size() >= 120)) { - SerialIter it( - nodeObject->getData().data(), nodeObject->getData().size()); + SerialIter it(nodeObject->getData().data(), nodeObject->getData().size()); if (safe_cast(it.get32()) == HashPrefix::ledgerMaster) { it.skip( @@ -1654,7 +1535,7 @@ LedgerMaster::walkHashBySeq( std::shared_ptr const& referenceLedger, InboundLedger::Reason reason) { - if (!referenceLedger || (referenceLedger->info().seq < index)) + if (!referenceLedger || (referenceLedger->header().seq < index)) { // Nothing we can do. No validated ledger. return std::nullopt; @@ -1669,7 +1550,7 @@ LedgerMaster::walkHashBySeq( // be located easily and should contain the hash. LedgerIndex refIndex = getCandidateLedger(index); auto const refHash = hashOfSeq(*referenceLedger, refIndex, m_journal); - XRPL_ASSERT(refHash, "ripple::LedgerMaster::walkHashBySeq : found ledger"); + XRPL_ASSERT(refHash, "xrpl::LedgerMaster::walkHashBySeq : found ledger"); if (refHash) { // Try the hash and sequence of a better reference ledger just found @@ -1690,13 +1571,12 @@ LedgerMaster::walkHashBySeq( // Try to acquire the complete ledger if (!ledger) { - if (auto const l = app_.getInboundLedgers().acquire( - *refHash, refIndex, reason)) + if (auto const l = app_.getInboundLedgers().acquire(*refHash, refIndex, reason)) { ledgerHash = hashOfSeq(*l, index, m_journal); XRPL_ASSERT( ledgerHash, - "ripple::LedgerMaster::walkHashBySeq : has complete " + "xrpl::LedgerMaster::walkHashBySeq : has complete " "ledger"); } } @@ -1712,7 +1592,7 @@ LedgerMaster::getLedgerBySeq(std::uint32_t index) // Always prefer a validated ledger if (auto valid = mValidLedger.get()) { - if (valid->info().seq == index) + if (valid->header().seq == index) return valid; try @@ -1733,7 +1613,7 @@ LedgerMaster::getLedgerBySeq(std::uint32_t index) return ret; auto ret = mClosedLedger.get(); - if (ret && (ret->info().seq == index)) + if (ret && (ret->header().seq == index)) return ret; clearLedger(index); @@ -1747,7 +1627,7 @@ LedgerMaster::getLedgerByHash(uint256 const& hash) return ret; auto ret = mClosedLedger.get(); - if (ret && (ret->info().hash == hash)) + if (ret && (ret->header().hash == hash)) return ret; return {}; @@ -1809,38 +1689,29 @@ LedgerMaster::fetchForHistory( scope_unlock sul{sl}; if (auto hash = getLedgerHashForHistory(missing, reason)) { - XRPL_ASSERT( - hash->isNonZero(), - "ripple::LedgerMaster::fetchForHistory : found ledger"); + XRPL_ASSERT(hash->isNonZero(), "xrpl::LedgerMaster::fetchForHistory : found ledger"); auto ledger = getLedgerByHash(*hash); if (!ledger) { if (!app_.getInboundLedgers().isFailure(*hash)) { - ledger = - app_.getInboundLedgers().acquire(*hash, missing, reason); - if (!ledger && missing != fetch_seq_ && - missing > app_.getNodeStore().earliestLedgerSeq()) + ledger = app_.getInboundLedgers().acquire(*hash, missing, reason); + if (!ledger && missing != fetch_seq_ && missing > app_.getNodeStore().earliestLedgerSeq()) { - JLOG(m_journal.trace()) - << "fetchForHistory want fetch pack " << missing; + JLOG(m_journal.trace()) << "fetchForHistory want fetch pack " << missing; fetch_seq_ = missing; getFetchPack(missing, reason); } else - JLOG(m_journal.trace()) - << "fetchForHistory no fetch pack for " << missing; + JLOG(m_journal.trace()) << "fetchForHistory no fetch pack for " << missing; } else - JLOG(m_journal.debug()) - << "fetchForHistory found failed acquire"; + JLOG(m_journal.debug()) << "fetchForHistory found failed acquire"; } if (ledger) { - auto seq = ledger->info().seq; - XRPL_ASSERT( - seq == missing, - "ripple::LedgerMaster::fetchForHistory : sequence match"); + auto seq = ledger->header().seq; + XRPL_ASSERT(seq == missing, "xrpl::LedgerMaster::fetchForHistory : sequence match"); JLOG(m_journal.trace()) << "fetchForHistory acquired " << seq; setFullLedger(ledger, false, false); int fillInProgress; @@ -1850,18 +1721,14 @@ LedgerMaster::fetchForHistory( fillInProgress = mFillInProgress; } if (fillInProgress == 0 && - app_.getRelationalDatabase().getHashByIndex(seq - 1) == - ledger->info().parentHash) + app_.getRelationalDatabase().getHashByIndex(seq - 1) == ledger->header().parentHash) { { // Previous ledger is in DB std::lock_guard lock(m_mutex); mFillInProgress = seq; } - app_.getJobQueue().addJob( - jtADVANCE, "tryFill", [this, ledger]() { - tryFill(ledger); - }); + app_.getJobQueue().addJob(jtADVANCE, "TryFill", [this, ledger]() { tryFill(ledger); }); } progress = true; } @@ -1871,9 +1738,7 @@ LedgerMaster::fetchForHistory( // Do not fetch ledger sequences lower // than the earliest ledger sequence fetchSz = app_.getNodeStore().earliestLedgerSeq(); - fetchSz = missing >= fetchSz - ? std::min(ledger_fetch_size_, (missing - fetchSz) + 1) - : 0; + fetchSz = missing >= fetchSz ? std::min(ledger_fetch_size_, (missing - fetchSz) + 1) : 0; try { for (std::uint32_t i = 0; i < fetchSz; ++i) @@ -1883,7 +1748,7 @@ LedgerMaster::fetchForHistory( { XRPL_ASSERT( h->isNonZero(), - "ripple::LedgerMaster::fetchForHistory : " + "xrpl::LedgerMaster::fetchForHistory : " "prefetched ledger"); app_.getInboundLedgers().acquire(*h, seq, reason); } @@ -1891,23 +1756,17 @@ LedgerMaster::fetchForHistory( } catch (std::exception const& ex) { - JLOG(m_journal.warn()) - << "Threw while prefetching: " << ex.what(); + JLOG(m_journal.warn()) << "Threw while prefetching: " << ex.what(); } } } else { - JLOG(m_journal.fatal()) - << "Can't find ledger following prevMissing " << missing; - JLOG(m_journal.fatal()) - << "Pub:" << mPubLedgerSeq << " Val:" << mValidLedgerSeq; - JLOG(m_journal.fatal()) - << "Ledgers: " << app_.getLedgerMaster().getCompleteLedgers(); - JLOG(m_journal.fatal()) - << "Acquire reason: " - << (reason == InboundLedger::Reason::HISTORY ? "HISTORY" - : "NOT HISTORY"); + JLOG(m_journal.fatal()) << "Can't find ledger following prevMissing " << missing; + JLOG(m_journal.fatal()) << "Pub:" << mPubLedgerSeq << " Val:" << mValidLedgerSeq; + JLOG(m_journal.fatal()) << "Ledgers: " << app_.getLedgerMaster().getCompleteLedgers(); + JLOG(m_journal.fatal()) << "Acquire reason: " + << (reason == InboundLedger::Reason::HISTORY ? "HISTORY" : "NOT HISTORY"); clearLedger(missing + 1); progress = true; } @@ -1926,8 +1785,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) if (pubLedgers.empty()) { if (!standalone_ && !app_.getFeeTrack().isLoadedLocal() && - (app_.getJobQueue().getJobCount(jtPUBOLDLEDGER) < 10) && - (mValidLedgerSeq == mPubLedgerSeq) && + (app_.getJobQueue().getJobCount(jtPUBOLDLEDGER) < 10) && (mValidLedgerSeq == mPubLedgerSeq) && (getValidatedLedgerAge() < MAX_LEDGER_AGE_ACQUIRE) && (app_.getNodeStore().getWriteLoad() < MAX_WRITE_LOAD_ACQUIRE)) { @@ -1937,14 +1795,11 @@ LedgerMaster::doAdvance(std::unique_lock& sl) { std::lock_guard sll(mCompleteLock); missing = prevMissing( - mCompleteLedgers, - mPubLedger->info().seq, - app_.getNodeStore().earliestLedgerSeq()); + mCompleteLedgers, mPubLedger->header().seq, app_.getNodeStore().earliestLedgerSeq()); } if (missing) { - JLOG(m_journal.trace()) - << "tryAdvance discovered missing " << *missing; + JLOG(m_journal.trace()) << "tryAdvance discovered missing " << *missing; if ((mFillInProgress == 0 || *missing > mFillInProgress) && shouldAcquire( mValidLedgerSeq, @@ -1953,8 +1808,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) *missing, m_journal)) { - JLOG(m_journal.trace()) - << "advanceThread should acquire"; + JLOG(m_journal.trace()) << "advanceThread should acquire"; } else missing = std::nullopt; @@ -1964,8 +1818,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) fetchForHistory(*missing, progress, reason, sl); if (mValidLedgerSeq != mPubLedgerSeq) { - JLOG(m_journal.debug()) - << "tryAdvance found last valid changed"; + JLOG(m_journal.debug()) << "tryAdvance found last valid changed"; progress = true; } } @@ -1978,14 +1831,12 @@ LedgerMaster::doAdvance(std::unique_lock& sl) } else { - JLOG(m_journal.trace()) << "tryAdvance found " << pubLedgers.size() - << " ledgers to publish"; + JLOG(m_journal.trace()) << "tryAdvance found " << pubLedgers.size() << " ledgers to publish"; for (auto const& ledger : pubLedgers) { { scope_unlock sul{sl}; - JLOG(m_journal.debug()) - << "tryAdvance publishing seq " << ledger->info().seq; + JLOG(m_journal.debug()) << "tryAdvance publishing seq " << ledger->header().seq; setFullLedger(ledger, true, true); } @@ -1998,7 +1849,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) } app_.getOPs().clearNeedNetworkLedger(); - progress = newPFWork("pf:newLedger", sl); + progress = newPFWork("PthFindNewLed", sl); } if (progress) mAdvanceWork = true; @@ -2029,7 +1880,7 @@ LedgerMaster::gotFetchPack(bool progress, std::uint32_t seq) { if (!mGotFetchPackThread.test_and_set(std::memory_order_acquire)) { - app_.getJobQueue().addJob(jtLEDGER_DATA, "gotFetchPack", [&]() { + app_.getJobQueue().addJob(jtLEDGER_DATA, "GotFetchPack", [&]() { app_.getInboundLedgers().gotFetchPack(); mGotFetchPackThread.clear(std::memory_order_release); }); @@ -2070,28 +1921,26 @@ populateFetchPack( std::uint32_t seq, bool withLeaves = true) { - XRPL_ASSERT(cnt, "ripple::populateFetchPack : nonzero count input"); + XRPL_ASSERT(cnt, "xrpl::populateFetchPack : nonzero count input"); Serializer s(1024); - want.visitDifferences( - have, - [&s, withLeaves, &cnt, into, seq](SHAMapTreeNode const& n) -> bool { - if (!withLeaves && n.isLeaf()) - return true; + want.visitDifferences(have, [&s, withLeaves, &cnt, into, seq](SHAMapTreeNode const& n) -> bool { + if (!withLeaves && n.isLeaf()) + return true; - s.erase(); - n.serializeWithPrefix(s); + s.erase(); + n.serializeWithPrefix(s); - auto const& hash = n.getHash().as_uint256(); + auto const& hash = n.getHash().as_uint256(); - protocol::TMIndexedObject* obj = into->add_objects(); - obj->set_ledgerseq(seq); - obj->set_hash(hash.data(), hash.size()); - obj->set_data(s.getDataPtr(), s.getLength()); + protocol::TMIndexedObject* obj = into->add_objects(); + obj->set_ledgerseq(seq); + obj->set_hash(hash.data(), hash.size()); + obj->set_data(s.getDataPtr(), s.getLength()); - return --cnt != 0; - }); + return --cnt != 0; + }); } void @@ -2123,36 +1972,32 @@ LedgerMaster::makeFetchPack( if (!have) { - JLOG(m_journal.info()) - << "Peer requests fetch pack for ledger we don't have: " << have; + JLOG(m_journal.info()) << "Peer requests fetch pack for ledger we don't have: " << have; peer->charge(Resource::feeRequestNoReply, "get_object ledger"); return; } if (have->open()) { - JLOG(m_journal.warn()) - << "Peer requests fetch pack from open ledger: " << have; + JLOG(m_journal.warn()) << "Peer requests fetch pack from open ledger: " << have; peer->charge(Resource::feeMalformedRequest, "get_object ledger open"); return; } - if (have->info().seq < getEarliestFetch()) + if (have->header().seq < getEarliestFetch()) { JLOG(m_journal.debug()) << "Peer requests fetch pack that is too early"; peer->charge(Resource::feeMalformedRequest, "get_object ledger early"); return; } - auto want = getLedgerByHash(have->info().parentHash); + auto want = getLedgerByHash(have->header().parentHash); if (!want) { - JLOG(m_journal.info()) - << "Peer requests fetch pack for ledger whose predecessor we " - << "don't have: " << have; - peer->charge( - Resource::feeRequestNoReply, "get_object ledger no parent"); + JLOG(m_journal.info()) << "Peer requests fetch pack for ledger whose predecessor we " + << "don't have: " << have; + peer->charge(Resource::feeRequestNoReply, "get_object ledger no parent"); return; } @@ -2179,50 +2024,46 @@ LedgerMaster::makeFetchPack( // the same process adding the previous ledger to the FetchPack. do { - std::uint32_t lSeq = want->info().seq; + std::uint32_t lSeq = want->header().seq; { // Serialize the ledger header: hdr.erase(); hdr.add32(HashPrefix::ledgerMaster); - addRaw(want->info(), hdr); + addRaw(want->header(), hdr); // Add the data protocol::TMIndexedObject* obj = reply.add_objects(); - obj->set_hash( - want->info().hash.data(), want->info().hash.size()); + obj->set_hash(want->header().hash.data(), want->header().hash.size()); obj->set_data(hdr.getDataPtr(), hdr.getLength()); obj->set_ledgerseq(lSeq); } - populateFetchPack( - want->stateMap(), &have->stateMap(), 16384, &reply, lSeq); + populateFetchPack(want->stateMap(), &have->stateMap(), 16384, &reply, lSeq); // We use nullptr here because transaction maps are per ledger // and so the requestor is unlikely to already have it. - if (want->info().txHash.isNonZero()) + if (want->header().txHash.isNonZero()) populateFetchPack(want->txMap(), nullptr, 512, &reply, lSeq); if (reply.objects().size() >= 512) break; have = std::move(want); - want = getLedgerByHash(have->info().parentHash); + want = getLedgerByHash(have->header().parentHash); } while (want && UptimeClock::now() <= uptime + 1s); auto msg = std::make_shared(reply, protocol::mtGET_OBJECTS); - JLOG(m_journal.info()) - << "Built fetch pack with " << reply.objects().size() << " nodes (" - << msg->getBufferSize() << " bytes)"; + JLOG(m_journal.info()) << "Built fetch pack with " << reply.objects().size() << " nodes (" + << msg->getBufferSize() << " bytes)"; peer->send(msg); } catch (std::exception const& ex) { - JLOG(m_journal.warn()) - << "Exception building fetch pach. Exception: " << ex.what(); + JLOG(m_journal.warn()) << "Exception building fetch pack. Exception: " << ex.what(); } } @@ -2252,12 +2093,11 @@ LedgerMaster::txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex) return {}; for (auto it = lgr->txs.begin(); it != lgr->txs.end(); ++it) - if (it->first && it->second && - it->second->isFieldPresent(sfTransactionIndex) && + if (it->first && it->second && it->second->isFieldPresent(sfTransactionIndex) && it->second->getFieldU32(sfTransactionIndex) == txnIndex) return it->first->getTransactionID(); return {}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerReplay.cpp b/src/xrpld/app/ledger/detail/LedgerReplay.cpp index 40b4f9e412..e77adc9700 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplay.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplay.cpp @@ -1,30 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { -LedgerReplay::LedgerReplay( - std::shared_ptr parent, - std::shared_ptr replay) +LedgerReplay::LedgerReplay(std::shared_ptr parent, std::shared_ptr replay) : parent_{std::move(parent)}, replay_{std::move(replay)} { for (auto const& item : replay_->txMap()) @@ -39,10 +18,8 @@ LedgerReplay::LedgerReplay( std::shared_ptr parent, std::shared_ptr replay, std::map>&& orderedTxns) - : parent_{std::move(parent)} - , replay_{std::move(replay)} - , orderedTxns_{std::move(orderedTxns)} + : parent_{std::move(parent)}, replay_{std::move(replay)}, orderedTxns_{std::move(orderedTxns)} { } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp index 5bfad61bf4..4fcb924c27 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,26 +7,20 @@ #include -namespace ripple { -LedgerReplayMsgHandler::LedgerReplayMsgHandler( - Application& app, - LedgerReplayer& replayer) - : app_(app) - , replayer_(replayer) - , journal_(app.journal("LedgerReplayMsgHandler")) +namespace xrpl { +LedgerReplayMsgHandler::LedgerReplayMsgHandler(Application& app, LedgerReplayer& replayer) + : app_(app), replayer_(replayer), journal_(app.journal("LedgerReplayMsgHandler")) { } protocol::TMProofPathResponse -LedgerReplayMsgHandler::processProofPathRequest( - std::shared_ptr const& msg) +LedgerReplayMsgHandler::processProofPathRequest(std::shared_ptr const& msg) { protocol::TMProofPathRequest& packet = *msg; protocol::TMProofPathResponse reply; if (!packet.has_key() || !packet.has_ledgerhash() || !packet.has_type() || - packet.ledgerhash().size() != uint256::size() || - packet.key().size() != uint256::size() || + packet.ledgerhash().size() != uint256::size() || packet.key().size() != uint256::size() || !protocol::TMLedgerMapType_IsValid(packet.type())) { JLOG(journal_.debug()) << "getProofPath: Invalid request"; @@ -61,8 +36,7 @@ LedgerReplayMsgHandler::processProofPathRequest( auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash); if (!ledger) { - JLOG(journal_.debug()) - << "getProofPath: Don't have ledger " << ledgerHash; + JLOG(journal_.debug()) << "getProofPath: Don't have ledger " << ledgerHash; reply.set_error(protocol::TMReplyError::reNO_LEDGER); return reply; } @@ -72,7 +46,7 @@ LedgerReplayMsgHandler::processProofPathRequest( { case protocol::lmACCOUNT_STATE: return ledger->stateMap().getProofPath(key); - case protocol::lmTRANASCTION: + case protocol::lmTRANSACTION: return ledger->txMap().getProofPath(key); default: // should not be here @@ -83,34 +57,30 @@ LedgerReplayMsgHandler::processProofPathRequest( if (!path) { - JLOG(journal_.debug()) << "getProofPath: Don't have the node " << key - << " of ledger " << ledgerHash; + JLOG(journal_.debug()) << "getProofPath: Don't have the node " << key << " of ledger " << ledgerHash; reply.set_error(protocol::TMReplyError::reNO_NODE); return reply; } // pack header Serializer nData(128); - addRaw(ledger->info(), nData); + addRaw(ledger->header(), nData); reply.set_ledgerheader(nData.getDataPtr(), nData.getLength()); // pack path for (auto const& b : *path) reply.add_path(b.data(), b.size()); - JLOG(journal_.debug()) << "getProofPath for the node " << key - << " of ledger " << ledgerHash << " path length " + JLOG(journal_.debug()) << "getProofPath for the node " << key << " of ledger " << ledgerHash << " path length " << path->size(); return reply; } bool -LedgerReplayMsgHandler::processProofPathResponse( - std::shared_ptr const& msg) +LedgerReplayMsgHandler::processProofPathResponse(std::shared_ptr const& msg) { protocol::TMProofPathResponse& reply = *msg; - if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() || - !reply.has_type() || !reply.has_ledgerheader() || - reply.path_size() == 0) + if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() || !reply.has_type() || + !reply.has_ledgerheader() || reply.path_size() == 0) { JLOG(journal_.debug()) << "Bad message: Error reply"; return false; @@ -118,14 +88,12 @@ LedgerReplayMsgHandler::processProofPathResponse( if (reply.type() != protocol::lmACCOUNT_STATE) { - JLOG(journal_.debug()) - << "Bad message: we only support the state ShaMap for now"; + JLOG(journal_.debug()) << "Bad message: we only support the state ShaMap for now"; return false; } // deserialize the header - auto info = deserializeHeader( - {reply.ledgerheader().data(), reply.ledgerheader().size()}); + auto info = deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()}); uint256 replyHash(reply.ledgerhash()); if (calculateLedgerHash(info) != replyHash) { @@ -137,10 +105,9 @@ LedgerReplayMsgHandler::processProofPathResponse( uint256 key(reply.key()); if (key != keylet::skip().key) { - JLOG(journal_.debug()) - << "Bad message: we only support the short skip list for now. " - "Key in reply " - << key; + JLOG(journal_.debug()) << "Bad message: we only support the short skip list for now. " + "Key in reply " + << key; return false; } @@ -177,14 +144,12 @@ LedgerReplayMsgHandler::processProofPathResponse( } protocol::TMReplayDeltaResponse -LedgerReplayMsgHandler::processReplayDeltaRequest( - std::shared_ptr const& msg) +LedgerReplayMsgHandler::processReplayDeltaRequest(std::shared_ptr const& msg) { protocol::TMReplayDeltaRequest& packet = *msg; protocol::TMReplayDeltaResponse reply; - if (!packet.has_ledgerhash() || - packet.ledgerhash().size() != uint256::size()) + if (!packet.has_ledgerhash() || packet.ledgerhash().size() != uint256::size()) { JLOG(journal_.debug()) << "getReplayDelta: Invalid request"; reply.set_error(protocol::TMReplyError::reBAD_REQUEST); @@ -196,31 +161,28 @@ LedgerReplayMsgHandler::processReplayDeltaRequest( auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash); if (!ledger || !ledger->isImmutable()) { - JLOG(journal_.debug()) - << "getReplayDelta: Don't have ledger " << ledgerHash; + JLOG(journal_.debug()) << "getReplayDelta: Don't have ledger " << ledgerHash; reply.set_error(protocol::TMReplyError::reNO_LEDGER); return reply; } // pack header Serializer nData(128); - addRaw(ledger->info(), nData); + addRaw(ledger->header(), nData); reply.set_ledgerheader(nData.getDataPtr(), nData.getLength()); // pack transactions auto const& txMap = ledger->txMap(); - txMap.visitLeaves( - [&](boost::intrusive_ptr const& txNode) { - reply.add_transaction(txNode->data(), txNode->size()); - }); + txMap.visitLeaves([&](boost::intrusive_ptr const& txNode) { + reply.add_transaction(txNode->data(), txNode->size()); + }); - JLOG(journal_.debug()) << "getReplayDelta for ledger " << ledgerHash - << " txMap hash " << txMap.getHash().as_uint256(); + JLOG(journal_.debug()) << "getReplayDelta for ledger " << ledgerHash << " txMap hash " + << txMap.getHash().as_uint256(); return reply; } bool -LedgerReplayMsgHandler::processReplayDeltaResponse( - std::shared_ptr const& msg) +LedgerReplayMsgHandler::processReplayDeltaResponse(std::shared_ptr const& msg) { protocol::TMReplayDeltaResponse& reply = *msg; if (reply.has_error() || !reply.has_ledgerheader()) @@ -229,8 +191,7 @@ LedgerReplayMsgHandler::processReplayDeltaResponse( return false; } - auto info = deserializeHeader( - {reply.ledgerheader().data(), reply.ledgerheader().size()}); + auto info = deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()}); uint256 replyHash(reply.ledgerhash()); if (calculateLedgerHash(info) != replyHash) { @@ -250,8 +211,7 @@ LedgerReplayMsgHandler::processReplayDeltaResponse( // -- TxShaMapItem for building a ShaMap for verification // -- Tx // -- TxMetaData for Tx ordering - Serializer shaMapItemData( - reply.transaction(i).data(), reply.transaction(i).size()); + Serializer shaMapItemData(reply.transaction(i).data(), reply.transaction(i).size()); SerialIter txMetaSit(makeSlice(reply.transaction(i))); SerialIter txSit(txMetaSit.getSlice(txMetaSit.getVLDataLength())); @@ -267,9 +227,7 @@ LedgerReplayMsgHandler::processReplayDeltaResponse( STObject meta(metaSit, sfMetadata); orderedTxns.emplace(meta[sfTransactionIndex], std::move(tx)); - if (!txMap.addGiveItem( - SHAMapNodeType::tnTRANSACTION_MD, - make_shamapitem(tid, shaMapItemData.slice()))) + if (!txMap.addGiveItem(SHAMapNodeType::tnTRANSACTION_MD, make_shamapitem(tid, shaMapItemData.slice()))) { JLOG(journal_.debug()) << "Bad message: Cannot deserialize"; return false; @@ -292,4 +250,4 @@ LedgerReplayMsgHandler::processReplayDeltaResponse( return true; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h index 151a21b956..260f1ff753 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h +++ b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYMSGHANDLER_H_INCLUDED -#define RIPPLE_APP_LEDGER_LEDGERREPLAYMSGHANDLER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { class Application; class LedgerReplayer; @@ -38,8 +18,7 @@ public: * @note check has_error() and error() of the response for error */ protocol::TMProofPathResponse - processProofPathRequest( - std::shared_ptr const& msg); + processProofPathRequest(std::shared_ptr const& msg); /** * Process TMProofPathResponse @@ -47,16 +26,14 @@ public: * true otherwise */ bool - processProofPathResponse( - std::shared_ptr const& msg); + processProofPathResponse(std::shared_ptr const& msg); /** * Process TMReplayDeltaRequest and return TMReplayDeltaResponse * @note check has_error() and error() of the response for error */ protocol::TMReplayDeltaResponse - processReplayDeltaRequest( - std::shared_ptr const& msg); + processReplayDeltaRequest(std::shared_ptr const& msg); /** * Process TMReplayDeltaResponse @@ -64,8 +41,7 @@ public: * true otherwise */ bool - processReplayDeltaResponse( - std::shared_ptr const& msg); + processReplayDeltaResponse(std::shared_ptr const& msg); private: Application& app_; @@ -73,6 +49,4 @@ private: beast::Journal journal_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp index a9d2657f9b..b7d788e15a 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -namespace ripple { +namespace xrpl { LedgerReplayTask::TaskParameter::TaskParameter( InboundLedger::Reason r, @@ -33,15 +14,12 @@ LedgerReplayTask::TaskParameter::TaskParameter( { XRPL_ASSERT( finishLedgerHash.isNonZero() && totalNumLedgers > 0, - "ripple::LedgerReplayTask::TaskParameter::TaskParameter : valid " + "xrpl::LedgerReplayTask::TaskParameter::TaskParameter : valid " "inputs"); } bool -LedgerReplayTask::TaskParameter::update( - uint256 const& hash, - std::uint32_t seq, - std::vector const& sList) +LedgerReplayTask::TaskParameter::update(uint256 const& hash, std::uint32_t seq, std::vector const& sList) { if (finishHash_ != hash || sList.size() + 1 < totalLedgers_ || full_) return false; @@ -50,22 +28,18 @@ LedgerReplayTask::TaskParameter::update( skipList_ = sList; skipList_.emplace_back(finishHash_); startHash_ = skipList_[skipList_.size() - totalLedgers_]; - XRPL_ASSERT( - startHash_.isNonZero(), - "ripple::LedgerReplayTask::TaskParameter::update : nonzero start hash"); + XRPL_ASSERT(startHash_.isNonZero(), "xrpl::LedgerReplayTask::TaskParameter::update : nonzero start hash"); startSeq_ = finishSeq_ - totalLedgers_ + 1; full_ = true; return true; } bool -LedgerReplayTask::TaskParameter::canMergeInto( - TaskParameter const& existingTask) const +LedgerReplayTask::TaskParameter::canMergeInto(TaskParameter const& existingTask) const { if (reason_ == existingTask.reason_) { - if (finishHash_ == existingTask.finishHash_ && - totalLedgers_ <= existingTask.totalLedgers_) + if (finishHash_ == existingTask.finishHash_ && totalLedgers_ <= existingTask.totalLedgers_) { return true; } @@ -73,11 +47,9 @@ LedgerReplayTask::TaskParameter::canMergeInto( if (existingTask.full_) { auto const& exList = existingTask.skipList_; - if (auto i = std::find(exList.begin(), exList.end(), finishHash_); - i != exList.end()) + if (auto i = std::find(exList.begin(), exList.end(), finishHash_); i != exList.end()) { - return existingTask.totalLedgers_ >= - totalLedgers_ + (exList.end() - i) - 1; + return existingTask.totalLedgers_ >= totalLedgers_ + (exList.end() - i) - 1; } } } @@ -95,17 +67,14 @@ LedgerReplayTask::LedgerReplayTask( app, parameter.finishHash_, LedgerReplayParameters::TASK_TIMEOUT, - {jtREPLAY_TASK, - "LedgerReplayTask", - LedgerReplayParameters::MAX_QUEUED_TASKS}, + {jtREPLAY_TASK, "LedReplTask", LedgerReplayParameters::MAX_QUEUED_TASKS}, app.journal("LedgerReplayTask")) , inboundLedgers_(inboundLedgers) , replayer_(replayer) , parameter_(parameter) , maxTimeouts_(std::max( LedgerReplayParameters::TASK_MAX_TIMEOUTS_MINIMUM, - parameter.totalLedgers_ * - LedgerReplayParameters::TASK_MAX_TIMEOUTS_MULTIPLIER)) + parameter.totalLedgers_ * LedgerReplayParameters::TASK_MAX_TIMEOUTS_MULTIPLIER)) , skipListAcquirer_(skipListAcquirer) { JLOG(journal_.trace()) << "Create " << hash_; @@ -132,8 +101,7 @@ LedgerReplayTask::init() else { auto const skipListData = sptr->skipListAcquirer_->getData(); - sptr->updateSkipList( - hash, skipListData->ledgerSeq, skipListData->skipList); + sptr->updateSkipList(hash, skipListData->ledgerSeq, skipListData->skipList); } } }); @@ -158,16 +126,12 @@ LedgerReplayTask::trigger(ScopedLockType& sl) parent_ = app_.getLedgerMaster().getLedgerByHash(parameter_.startHash_); if (!parent_) { - parent_ = inboundLedgers_.acquire( - parameter_.startHash_, - parameter_.startSeq_, - InboundLedger::Reason::GENERIC); + parent_ = + inboundLedgers_.acquire(parameter_.startHash_, parameter_.startSeq_, InboundLedger::Reason::GENERIC); } if (parent_) { - JLOG(journal_.trace()) - << "Got start ledger " << parameter_.startHash_ << " for task " - << hash_; + JLOG(journal_.trace()) << "Got start ledger " << parameter_.startHash_ << " for task " << hash_; } } @@ -177,8 +141,7 @@ LedgerReplayTask::trigger(ScopedLockType& sl) void LedgerReplayTask::deltaReady(uint256 const& deltaHash) { - JLOG(journal_.trace()) << "Delta " << deltaHash << " ready for task " - << hash_; + JLOG(journal_.trace()) << "Delta " << deltaHash << " ready for task " << hash_; ScopedLockType sl(mtx_); if (!isDone()) tryAdvance(sl); @@ -188,14 +151,11 @@ void LedgerReplayTask::tryAdvance(ScopedLockType& sl) { JLOG(journal_.trace()) << "tryAdvance task " << hash_ - << (parameter_.full_ ? ", full parameter" - : ", waiting to fill parameter") - << ", deltaIndex=" << deltaToBuild_ - << ", totalDeltas=" << deltas_.size() << ", parent " - << (parent_ ? parent_->info().hash : uint256()); + << (parameter_.full_ ? ", full parameter" : ", waiting to fill parameter") + << ", deltaIndex=" << deltaToBuild_ << ", totalDeltas=" << deltas_.size() << ", parent " + << (parent_ ? parent_->header().hash : uint256()); - bool shouldTry = parent_ && parameter_.full_ && - parameter_.totalLedgers_ - 1 == deltas_.size(); + bool shouldTry = parent_ && parameter_.full_ && parameter_.totalLedgers_ - 1 == deltas_.size(); if (!shouldTry) return; @@ -205,14 +165,11 @@ LedgerReplayTask::tryAdvance(ScopedLockType& sl) { auto& delta = deltas_[deltaToBuild_]; XRPL_ASSERT( - parent_->seq() + 1 == delta->ledgerSeq_, - "ripple::LedgerReplayTask::tryAdvance : consecutive sequence"); + parent_->seq() + 1 == delta->ledgerSeq_, "xrpl::LedgerReplayTask::tryAdvance : consecutive sequence"); if (auto l = delta->tryBuild(parent_); l) { - JLOG(journal_.debug()) - << "Task " << hash_ << " got ledger " << l->info().hash - << " deltaIndex=" << deltaToBuild_ - << " totalDeltas=" << deltas_.size(); + JLOG(journal_.debug()) << "Task " << hash_ << " got ledger " << l->header().hash + << " deltaIndex=" << deltaToBuild_ << " totalDeltas=" << deltas_.size(); parent_ = l; } else @@ -229,10 +186,7 @@ LedgerReplayTask::tryAdvance(ScopedLockType& sl) } void -LedgerReplayTask::updateSkipList( - uint256 const& hash, - std::uint32_t seq, - std::vector const& sList) +LedgerReplayTask::updateSkipList(uint256 const& hash, std::uint32_t seq, std::vector const& sList) { { ScopedLockType sl(mtx_); @@ -259,8 +213,7 @@ LedgerReplayTask::onTimer(bool progress, ScopedLockType& sl) if (timeouts_ > maxTimeouts_) { failed_ = true; - JLOG(journal_.debug()) - << "LedgerReplayTask Failed, too many timeouts " << hash_; + JLOG(journal_.debug()) << "LedgerReplayTask Failed, too many timeouts " << hash_; } else { @@ -278,28 +231,25 @@ void LedgerReplayTask::addDelta(std::shared_ptr const& delta) { std::weak_ptr wptr = shared_from_this(); - delta->addDataCallback( - parameter_.reason_, [wptr](bool good, uint256 const& hash) { - if (auto sptr = wptr.lock(); sptr) - { - if (!good) - sptr->cancel(); - else - sptr->deltaReady(hash); - } - }); + delta->addDataCallback(parameter_.reason_, [wptr](bool good, uint256 const& hash) { + if (auto sptr = wptr.lock(); sptr) + { + if (!good) + sptr->cancel(); + else + sptr->deltaReady(hash); + } + }); ScopedLockType sl(mtx_); if (!isDone()) { - JLOG(journal_.trace()) - << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_ - << " totalDeltas=" << deltas_.size(); + JLOG(journal_.trace()) << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_ + << " totalDeltas=" << deltas_.size(); XRPL_ASSERT( - deltas_.empty() || - deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_, - "ripple::LedgerReplayTask::addDelta : no deltas or consecutive " - "sequence", ); + deltas_.empty() || deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_, + "xrpl::LedgerReplayTask::addDelta : no deltas or consecutive " + "sequence"); deltas_.push_back(delta); } } @@ -311,4 +261,4 @@ LedgerReplayTask::finished() const return isDone(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index 6de717be4f..b52abc5624 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { LedgerReplayer::LedgerReplayer( Application& app, @@ -41,18 +22,13 @@ LedgerReplayer::~LedgerReplayer() } void -LedgerReplayer::replay( - InboundLedger::Reason r, - uint256 const& finishLedgerHash, - std::uint32_t totalNumLedgers) +LedgerReplayer::replay(InboundLedger::Reason r, uint256 const& finishLedgerHash, std::uint32_t totalNumLedgers) { XRPL_ASSERT( - finishLedgerHash.isNonZero() && totalNumLedgers > 0 && - totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE, - "ripple::LedgerReplayer::replay : valid inputs"); + finishLedgerHash.isNonZero() && totalNumLedgers > 0 && totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE, + "xrpl::LedgerReplayer::replay : valid inputs"); - LedgerReplayTask::TaskParameter parameter( - r, finishLedgerHash, totalNumLedgers); + LedgerReplayTask::TaskParameter parameter(r, finishLedgerHash, totalNumLedgers); std::shared_ptr task; std::shared_ptr skipList; @@ -63,8 +39,7 @@ LedgerReplayer::replay( return; if (tasks_.size() >= LedgerReplayParameters::MAX_TASKS) { - JLOG(j_.info()) << "Too many replay tasks, dropping new task " - << parameter.finishHash_; + JLOG(j_.info()) << "Too many replay tasks, dropping new task " << parameter.finishHash_; return; } @@ -72,15 +47,12 @@ LedgerReplayer::replay( { if (parameter.canMergeInto(t->getTaskParameter())) { - JLOG(j_.info()) << "Task " << parameter.finishHash_ << " with " - << totalNumLedgers + JLOG(j_.info()) << "Task " << parameter.finishHash_ << " with " << totalNumLedgers << " ledgers merged into an existing task."; return; } } - JLOG(j_.info()) << "Replay " << totalNumLedgers - << " ledgers. Finish ledger hash " - << parameter.finishHash_; + JLOG(j_.info()) << "Replay " << totalNumLedgers << " ledgers. Finish ledger hash " << parameter.finishHash_; auto i = skipLists_.find(parameter.finishHash_); if (i != skipLists_.end()) @@ -89,16 +61,12 @@ LedgerReplayer::replay( if (!skipList) // cannot find, or found but cannot lock { skipList = std::make_shared( - app_, - inboundLedgers_, - parameter.finishHash_, - peerSetBuilder_->build()); + app_, inboundLedgers_, parameter.finishHash_, peerSetBuilder_->build()); skipLists_[parameter.finishHash_] = skipList; newSkipList = true; } - task = std::make_shared( - app_, inboundLedgers_, *this, skipList, std::move(parameter)); + task = std::make_shared(app_, inboundLedgers_, *this, skipList, std::move(parameter)); tasks_.push_back(task); } @@ -122,21 +90,15 @@ LedgerReplayer::createDeltas(std::shared_ptr task) JLOG(j_.trace()) << "Creating " << parameter.totalLedgers_ - 1 << " deltas"; if (parameter.totalLedgers_ > 1) { - auto skipListItem = std::find( - parameter.skipList_.begin(), - parameter.skipList_.end(), - parameter.startHash_); - if (skipListItem == parameter.skipList_.end() || - ++skipListItem == parameter.skipList_.end()) + auto skipListItem = std::find(parameter.skipList_.begin(), parameter.skipList_.end(), parameter.startHash_); + if (skipListItem == parameter.skipList_.end() || ++skipListItem == parameter.skipList_.end()) { - JLOG(j_.error()) << "Task parameter error when creating deltas " - << parameter.finishHash_; + JLOG(j_.error()) << "Task parameter error when creating deltas " << parameter.finishHash_; return; } for (std::uint32_t seq = parameter.startSeq_ + 1; - seq <= parameter.finishSeq_ && - skipListItem != parameter.skipList_.end(); + seq <= parameter.finishSeq_ && skipListItem != parameter.skipList_.end(); ++seq, ++skipListItem) { std::shared_ptr delta; @@ -152,11 +114,7 @@ LedgerReplayer::createDeltas(std::shared_ptr task) if (!delta) // cannot find, or found but cannot lock { delta = std::make_shared( - app_, - inboundLedgers_, - *skipListItem, - seq, - peerSetBuilder_->build()); + app_, inboundLedgers_, *skipListItem, seq, peerSetBuilder_->build()); deltas_[*skipListItem] = delta; newDelta = true; } @@ -170,9 +128,7 @@ LedgerReplayer::createDeltas(std::shared_ptr task) } void -LedgerReplayer::gotSkipList( - LedgerInfo const& info, - boost::intrusive_ptr const& item) +LedgerReplayer::gotSkipList(LedgerHeader const& info, boost::intrusive_ptr const& item) { std::shared_ptr skipList = {}; { @@ -193,9 +149,7 @@ LedgerReplayer::gotSkipList( } void -LedgerReplayer::gotReplayDelta( - LedgerInfo const& info, - std::map>&& txns) +LedgerReplayer::gotReplayDelta(LedgerHeader const& info, std::map>&& txns) { std::shared_ptr delta = {}; { @@ -221,8 +175,7 @@ LedgerReplayer::sweep() auto const start = std::chrono::steady_clock::now(); { std::lock_guard lock(mtx_); - JLOG(j_.debug()) << "Sweeping, LedgerReplayer has " << tasks_.size() - << " tasks, " << skipLists_.size() + JLOG(j_.debug()) << "Sweeping, LedgerReplayer has " << tasks_.size() << " tasks, " << skipLists_.size() << " skipLists, and " << deltas_.size() << " deltas."; tasks_.erase( @@ -232,8 +185,7 @@ LedgerReplayer::sweep() [this](auto const& t) -> bool { if (t->finished()) { - JLOG(j_.debug()) << "Sweep task " - << t->getTaskParameter().finishHash_; + JLOG(j_.debug()) << "Sweep task " << t->getTaskParameter().finishHash_; return true; } return false; @@ -254,11 +206,10 @@ LedgerReplayer::sweep() removeCannotLocked(skipLists_); removeCannotLocked(deltas_); } - JLOG(j_.debug()) << " LedgerReplayer sweep lock duration " - << std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count() - << "ms"; + JLOG(j_.debug()) + << " LedgerReplayer sweep lock duration " + << std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() + << "ms"; } void @@ -267,8 +218,7 @@ LedgerReplayer::stop() JLOG(j_.info()) << "Stopping..."; { std::lock_guard lock(mtx_); - std::for_each( - tasks_.begin(), tasks_.end(), [](auto& i) { i->cancel(); }); + std::for_each(tasks_.begin(), tasks_.end(), [](auto& i) { i->cancel(); }); tasks_.clear(); auto lockAndCancel = [](auto& i) { if (auto sptr = i.second.lock(); sptr) @@ -285,4 +235,4 @@ LedgerReplayer::stop() JLOG(j_.info()) << "Stopped"; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 0e6f81dfbc..a675550537 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace { @@ -51,19 +32,11 @@ isBinary(LedgerFill const& fill) return fill.options & LedgerFill::binary; } -template void -fillJson( - Object& json, - bool closed, - LedgerInfo const& info, - bool bFull, - unsigned apiVersion) +fillJson(Json::Value& json, bool closed, LedgerHeader const& info, bool bFull, unsigned apiVersion) { json[jss::parent_hash] = to_string(info.parentHash); - json[jss::ledger_index] = (apiVersion > 1) - ? Json::Value(info.seq) - : Json::Value(std::to_string(info.seq)); + json[jss::ledger_index] = (apiVersion > 1) ? Json::Value(info.seq) : Json::Value(std::to_string(info.seq)); if (closed) { @@ -83,8 +56,7 @@ fillJson( json[jss::close_flags] = info.closeFlags; // Always show fields that contribute to the ledger hash - json[jss::parent_close_time] = - info.parentCloseTime.time_since_epoch().count(); + json[jss::parent_close_time] = info.parentCloseTime.time_since_epoch().count(); json[jss::close_time] = info.closeTime.time_since_epoch().count(); json[jss::close_time_resolution] = info.closeTimeResolution.count(); @@ -97,9 +69,8 @@ fillJson( } } -template void -fillJsonBinary(Object& json, bool closed, LedgerInfo const& info) +fillJsonBinary(Json::Value& json, bool closed, LedgerHeader const& info) { if (!closed) json[jss::closed] = false; @@ -132,19 +103,15 @@ fillJsonTx( if (fill.context->apiVersion > 1) txJson[jss::hash] = to_string(txn->getTransactionID()); - auto const json_meta = - (fill.context->apiVersion > 1 ? jss::meta_blob : jss::meta); + auto const json_meta = (fill.context->apiVersion > 1 ? jss::meta_blob : jss::meta); if (stMeta) txJson[json_meta] = serializeHex(*stMeta); } else if (fill.context->apiVersion > 1) { - copyFrom( - txJson[jss::tx_json], - txn->getJson(JsonOptions::disable_API_prior_V2, false)); + copyFrom(txJson[jss::tx_json], txn->getJson(JsonOptions::disable_API_prior_V2, false)); txJson[jss::hash] = to_string(txn->getTransactionID()); - RPC::insertDeliverMax( - txJson[jss::tx_json], txnType, fill.context->apiVersion); + RPC::insertDeliverMax(txJson[jss::tx_json], txnType, fill.context->apiVersion); if (stMeta) { @@ -153,23 +120,16 @@ fillJsonTx( // If applicable, insert delivered amount if (txnType == ttPAYMENT || txnType == ttCHECK_CASH) RPC::insertDeliveredAmount( - txJson[jss::meta], - fill.ledger, - txn, - {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + txJson[jss::meta], fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); // If applicable, insert mpt issuance id - RPC::insertMPTokenIssuanceID( - txJson[jss::meta], - txn, - {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + RPC::insertMPTokenIssuanceID(txJson[jss::meta], txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); } if (!fill.ledger.open()) - txJson[jss::ledger_hash] = to_string(fill.ledger.info().hash); + txJson[jss::ledger_hash] = to_string(fill.ledger.header().hash); - bool const validated = - fill.context->ledgerMaster.isValidated(fill.ledger); + bool const validated = fill.context->ledgerMaster.isValidated(fill.ledger); txJson[jss::validated] = validated; if (validated) { @@ -190,21 +150,15 @@ fillJsonTx( // If applicable, insert delivered amount if (txnType == ttPAYMENT || txnType == ttCHECK_CASH) RPC::insertDeliveredAmount( - txJson[jss::metaData], - fill.ledger, - txn, - {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + txJson[jss::metaData], fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); // If applicable, insert mpt issuance id RPC::insertMPTokenIssuanceID( - txJson[jss::metaData], - txn, - {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + txJson[jss::metaData], txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); } } - if ((fill.options & LedgerFill::ownerFunds) && - txn->getTxnType() == ttOFFER_CREATE) + if ((fill.options & LedgerFill::ownerFunds) && txn->getTxnType() == ttOFFER_CREATE) { auto const account = txn->getAccountID(sfAccount); auto const amount = txn->getFieldAmount(sfTakerGets); @@ -214,11 +168,7 @@ fillJsonTx( if (account != amount.getIssuer()) { auto const ownerFunds = accountFunds( - fill.ledger, - account, - amount, - fhIGNORE_FREEZE, - beast::Journal{beast::Journal::getNullSink()}); + fill.ledger, account, amount, fhIGNORE_FREEZE, beast::Journal{beast::Journal::getNullSink()}); txJson[jss::owner_funds] = ownerFunds.getText(); } } @@ -226,11 +176,10 @@ fillJsonTx( return txJson; } -template void -fillJsonTx(Object& json, LedgerFill const& fill) +fillJsonTx(Json::Value& json, LedgerFill const& fill) { - auto&& txns = setArray(json, jss::transactions); + auto& txns = json[jss::transactions] = Json::arrayValue; auto bBinary = isBinary(fill); auto bExpanded = isExpanded(fill); @@ -239,8 +188,7 @@ fillJsonTx(Object& json, LedgerFill const& fill) auto appendAll = [&](auto const& txs) { for (auto& i : txs) { - txns.append( - fillJsonTx(fill, bBinary, bExpanded, i.first, i.second)); + txns.append(fillJsonTx(fill, bBinary, bExpanded, i.first, i.second)); } }; @@ -251,18 +199,16 @@ fillJsonTx(Object& json, LedgerFill const& fill) // Nothing the user can do about this. if (fill.context) { - JLOG(fill.context->j.error()) - << "Exception in " << __func__ << ": " << ex.what(); + JLOG(fill.context->j.error()) << "Exception in " << __func__ << ": " << ex.what(); } } } -template void -fillJsonState(Object& json, LedgerFill const& fill) +fillJsonState(Json::Value& json, LedgerFill const& fill) { auto& ledger = fill.ledger; - auto&& array = Json::setArray(json, jss::accountState); + auto& array = json[jss::accountState] = Json::arrayValue; auto expanded = isExpanded(fill); auto binary = isBinary(fill); @@ -270,7 +216,7 @@ fillJsonState(Object& json, LedgerFill const& fill) { if (binary) { - auto&& obj = appendObject(array); + auto& obj = array.append(Json::objectValue); obj[jss::hash] = to_string(sle->key()); obj[jss::tx_blob] = serializeHex(*sle); } @@ -281,24 +227,22 @@ fillJsonState(Object& json, LedgerFill const& fill) } } -template void -fillJsonQueue(Object& json, LedgerFill const& fill) +fillJsonQueue(Json::Value& json, LedgerFill const& fill) { - auto&& queueData = Json::setArray(json, jss::queue_data); + auto& queueData = json[jss::queue_data] = Json::arrayValue; auto bBinary = isBinary(fill); auto bExpanded = isExpanded(fill); for (auto const& tx : fill.txQueue) { - auto&& txJson = appendObject(queueData); + auto& txJson = queueData.append(Json::objectValue); txJson[jss::fee_level] = to_string(tx.feeLevel); if (tx.lastValid) txJson[jss::LastLedgerSequence] = *tx.lastValid; txJson[jss::fee] = to_string(tx.consequences.fee()); - auto const spend = - tx.consequences.potentialSpend() + tx.consequences.fee(); + auto const spend = tx.consequences.potentialSpend() + tx.consequences.fee(); txJson[jss::max_spend_drops] = to_string(spend); txJson[jss::auth_change] = tx.consequences.isBlocker(); @@ -316,23 +260,21 @@ fillJsonQueue(Object& json, LedgerFill const& fill) } } -template void -fillJson(Object& json, LedgerFill const& fill) +fillJson(Json::Value& json, LedgerFill const& fill) { // TODO: what happens if bBinary and bExtracted are both set? // Is there a way to report this back? auto bFull = isFull(fill); if (isBinary(fill)) - fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info()); + fillJsonBinary(json, !fill.ledger.open(), fill.ledger.header()); else fillJson( json, !fill.ledger.open(), - fill.ledger.info(), + fill.ledger.header(), bFull, - (fill.context ? fill.context->apiVersion - : RPC::apiMaximumSupportedVersion)); + (fill.context ? fill.context->apiVersion : RPC::apiMaximumSupportedVersion)); if (bFull || fill.options & LedgerFill::dumpTxrp) fillJsonTx(json, fill); @@ -346,7 +288,7 @@ fillJson(Object& json, LedgerFill const& fill) void addJson(Json::Value& json, LedgerFill const& fill) { - auto&& object = Json::addObject(json, jss::ledger); + auto& object = json[jss::ledger] = Json::objectValue; fillJson(object, fill); if ((fill.options & LedgerFill::dumpQueue) && !fill.txQueue.empty()) @@ -361,4 +303,20 @@ getJson(LedgerFill const& fill) return json; } -} // namespace ripple +void +copyFrom(Json::Value& to, Json::Value const& from) +{ + if (!to) // Short circuit this very common case. + to = from; + else + { + // TODO: figure out if there is a way to remove this clause + // or check that it does/needs to do a deep copy + XRPL_ASSERT(from.isObjectOrNull(), "copyFrom : invalid input type"); + auto const members = from.getMemberNames(); + for (auto const& m : members) + to[m] = from[m]; + } +} + +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/LocalTxs.cpp b/src/xrpld/app/ledger/detail/LocalTxs.cpp index 140bd32961..48bd80fbf2 100644 --- a/src/xrpld/app/ledger/detail/LocalTxs.cpp +++ b/src/xrpld/app/ledger/detail/LocalTxs.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -46,7 +27,7 @@ test-applied to all new open ledgers until seen in a fully- validated ledger */ -namespace ripple { +namespace xrpl { // This class wraps a pointer to a transaction along with // its expiration ledger. It also caches the issuing account. @@ -61,8 +42,7 @@ public: , m_seqProxy(txn->getSeqProxy()) { if (txn->isFieldPresent(sfLastLedgerSequence)) - m_expire = - std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1); + m_expire = std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1); } uint256 const& @@ -112,8 +92,7 @@ public: // Add a new transaction to the set of local transactions void - push_back(LedgerIndex index, std::shared_ptr const& txn) - override + push_back(LedgerIndex index, std::shared_ptr const& txn) override { std::lock_guard lock(m_lock); @@ -145,7 +124,7 @@ public: std::lock_guard lock(m_lock); m_txns.remove_if([&view](auto const& txn) { - if (txn.isExpired(view.info().seq)) + if (txn.isExpired(view.header().seq)) return true; if (view.txExists(txn.getID())) return true; @@ -156,8 +135,7 @@ public: if (!sleAcct) return false; - SeqProxy const acctSeq = - SeqProxy::sequence(sleAcct->getFieldU32(sfSequence)); + SeqProxy const acctSeq = SeqProxy::sequence(sleAcct->getFieldU32(sfSequence)); SeqProxy const seqProx = txn.getSeqProxy(); if (seqProx.isSeq()) @@ -194,4 +172,4 @@ make_LocalTxs() return std::make_unique(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/OpenLedger.cpp b/src/xrpld/app/ledger/detail/OpenLedger.cpp index 5bba544e31..698862d4da 100644 --- a/src/xrpld/app/ledger/detail/OpenLedger.cpp +++ b/src/xrpld/app/ledger/detail/OpenLedger.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,12 +11,9 @@ #include -namespace ripple { +namespace xrpl { -OpenLedger::OpenLedger( - std::shared_ptr const& ledger, - CachedSLEs& cache, - beast::Journal journal) +OpenLedger::OpenLedger(std::shared_ptr const& ledger, CachedSLEs& cache, beast::Journal journal) : j_(journal), cache_(cache), current_(create(ledger->rules(), ledger)) { } @@ -101,9 +79,7 @@ OpenLedger::accept( *ledger, boost::adaptors::transform( current_->txs, - [](std::pair< - std::shared_ptr, - std::shared_ptr> const& p) { + [](std::pair, std::shared_ptr> const& p) { return p.first; }), retries, @@ -124,8 +100,11 @@ OpenLedger::accept( auto const txId = tx->getTransactionID(); // skip batch txns + // The flag should only be settable if Batch feature is enabled. If + // Batch is not enabled, the flag is always invalid, so don't relay it + // regardless. // LCOV_EXCL_START - if (tx->isFlag(tfInnerBatchTxn) && rules.enabled(featureBatch)) + if (tx->isFlag(tfInnerBatchTxn)) { XRPL_ASSERT( txpair.second && txpair.second->isFieldPresent(sfParentBatchID), @@ -143,8 +122,7 @@ OpenLedger::accept( tx->add(s); msg.set_rawtransaction(s.data(), s.size()); msg.set_status(protocol::tsNEW); - msg.set_receivetimestamp( - app.timeKeeper().now().time_since_epoch().count()); + msg.set_receivetimestamp(app.timeKeeper().now().time_since_epoch().count()); app.overlay().relay(txId, msg, *toSkip); } } @@ -157,14 +135,9 @@ OpenLedger::accept( //------------------------------------------------------------------------------ std::shared_ptr -OpenLedger::create( - Rules const& rules, - std::shared_ptr const& ledger) +OpenLedger::create(Rules const& rules, std::shared_ptr const& ledger) { - return std::make_shared( - open_ledger, - rules, - std::make_shared(ledger, cache_)); + return std::make_shared(open_ledger, rules, std::make_shared(ledger, cache_)); } auto @@ -179,11 +152,10 @@ OpenLedger::apply_one( if (retry) flags = flags | tapRETRY; // If it's in anybody's proposed set, try to keep it in the ledger - auto const result = ripple::apply(app, view, *tx, flags, j); + auto const result = xrpl::apply(app, view, *tx, flags, j); if (result.applied || result.ter == terQUEUED) return Result::success; - if (isTefFailure(result.ter) || isTemMalformed(result.ter) || - isTelLocal(result.ter)) + if (isTefFailure(result.ter) || isTemMalformed(result.ter) || isTelLocal(result.ter)) return Result::failure; return Result::retry; } @@ -236,4 +208,4 @@ debugTostr(std::shared_ptr const& view) return ss.str(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp index fc7e4d140c..353b4fdbc8 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp @@ -1,29 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include -namespace ripple { +namespace xrpl { SkipListAcquire::SkipListAcquire( Application& app, @@ -34,9 +15,7 @@ SkipListAcquire::SkipListAcquire( app, ledgerHash, LedgerReplayParameters::SUB_TASK_TIMEOUT, - {jtREPLAY_TASK, - "SkipListAcquire", - LedgerReplayParameters::MAX_QUEUED_TASKS}, + {jtREPLAY_TASK, "SkipListAcq", LedgerReplayParameters::MAX_QUEUED_TASKS}, app.journal("LedgerReplaySkipList")) , inboundLedgers_(inboundLedgers) , peerSet_(std::move(peerSet)) @@ -75,32 +54,25 @@ SkipListAcquire::trigger(std::size_t limit, ScopedLockType& sl) peerSet_->addPeers( limit, [this](auto peer) { - return peer->supportsFeature(ProtocolFeature::LedgerReplay) && - peer->hasLedger(hash_, 0); + return peer->supportsFeature(ProtocolFeature::LedgerReplay) && peer->hasLedger(hash_, 0); }, [this](auto peer) { if (peer->supportsFeature(ProtocolFeature::LedgerReplay)) { - JLOG(journal_.trace()) - << "Add a peer " << peer->id() << " for " << hash_; + JLOG(journal_.trace()) << "Add a peer " << peer->id() << " for " << hash_; protocol::TMProofPathRequest request; request.set_ledgerhash(hash_.data(), hash_.size()); - request.set_key( - keylet::skip().key.data(), keylet::skip().key.size()); - request.set_type( - protocol::TMLedgerMapType::lmACCOUNT_STATE); + request.set_key(keylet::skip().key.data(), keylet::skip().key.size()); + request.set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE); peerSet_->sendRequest(request, peer); } else { - JLOG(journal_.trace()) << "Add a no feature peer " - << peer->id() << " for " << hash_; - if (++noFeaturePeerCount_ >= - LedgerReplayParameters::MAX_NO_FEATURE_PEER_COUNT) + JLOG(journal_.trace()) << "Add a no feature peer " << peer->id() << " for " << hash_; + if (++noFeaturePeerCount_ >= LedgerReplayParameters::MAX_NO_FEATURE_PEER_COUNT) { JLOG(journal_.debug()) << "Fall back for " << hash_; - timerInterval_ = - LedgerReplayParameters::SUB_TASK_FALLBACK_TIMEOUT; + timerInterval_ = LedgerReplayParameters::SUB_TASK_FALLBACK_TIMEOUT; fallBack_ = true; } } @@ -134,13 +106,9 @@ SkipListAcquire::pmDowncast() } void -SkipListAcquire::processData( - std::uint32_t ledgerSeq, - boost::intrusive_ptr const& item) +SkipListAcquire::processData(std::uint32_t ledgerSeq, boost::intrusive_ptr const& item) { - XRPL_ASSERT( - ledgerSeq != 0 && item, - "ripple::SkipListAcquire::processData : valid inputs"); + XRPL_ASSERT(ledgerSeq != 0 && item, "xrpl::SkipListAcquire::processData : valid inputs"); ScopedLockType sl(mtx_); if (isDone()) return; @@ -148,12 +116,9 @@ SkipListAcquire::processData( JLOG(journal_.trace()) << "got data for " << hash_; try { - if (auto sle = - std::make_shared(SerialIter{item->slice()}, item->key()); - sle) + if (auto sle = std::make_shared(SerialIter{item->slice()}, item->key()); sle) { - if (auto const& skipList = sle->getFieldV256(sfHashes).value(); - !skipList.empty()) + if (auto const& skipList = sle->getFieldV256(sfHashes).value(); !skipList.empty()) onSkipListAcquired(skipList, ledgerSeq, sl); return; } @@ -163,8 +128,7 @@ SkipListAcquire::processData( } failed_ = true; - JLOG(journal_.error()) << "failed to retrieve Skip list from verified data " - << hash_; + JLOG(journal_.error()) << "failed to retrieve Skip list from verified data " << hash_; notify(sl); } @@ -175,8 +139,7 @@ SkipListAcquire::addDataCallback(OnSkipListDataCB&& cb) dataReadyCallbacks_.emplace_back(std::move(cb)); if (isDone()) { - JLOG(journal_.debug()) - << "task added to a finished SkipListAcquire " << hash_; + JLOG(journal_.debug()) << "task added to a finished SkipListAcquire " << hash_; notify(sl); } } @@ -189,12 +152,9 @@ SkipListAcquire::getData() const } void -SkipListAcquire::retrieveSkipList( - std::shared_ptr const& ledger, - ScopedLockType& sl) +SkipListAcquire::retrieveSkipList(std::shared_ptr const& ledger, ScopedLockType& sl) { - if (auto const hashIndex = ledger->read(keylet::skip()); - hashIndex && hashIndex->isFieldPresent(sfHashes)) + if (auto const hashIndex = ledger->read(keylet::skip()); hashIndex && hashIndex->isFieldPresent(sfHashes)) { auto const& slist = hashIndex->getFieldV256(sfHashes).value(); if (!slist.empty()) @@ -205,16 +165,12 @@ SkipListAcquire::retrieveSkipList( } failed_ = true; - JLOG(journal_.error()) << "failed to retrieve Skip list from a ledger " - << hash_; + JLOG(journal_.error()) << "failed to retrieve Skip list from a ledger " << hash_; notify(sl); } void -SkipListAcquire::onSkipListAcquired( - std::vector const& skipList, - std::uint32_t ledgerSeq, - ScopedLockType& sl) +SkipListAcquire::onSkipListAcquired(std::vector const& skipList, std::uint32_t ledgerSeq, ScopedLockType& sl) { complete_ = true; data_ = std::make_shared(ledgerSeq, skipList); @@ -225,7 +181,7 @@ SkipListAcquire::onSkipListAcquired( void SkipListAcquire::notify(ScopedLockType& sl) { - XRPL_ASSERT(isDone(), "ripple::SkipListAcquire::notify : is done"); + XRPL_ASSERT(isDone(), "xrpl::SkipListAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; @@ -239,4 +195,4 @@ SkipListAcquire::notify(ScopedLockType& sl) sl.lock(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.h b/src/xrpld/app/ledger/detail/SkipListAcquire.h index 02ab81ed6b..f3bfb60bee 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.h +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_SKIPLISTACQUIRE_H_INCLUDED -#define RIPPLE_APP_LEDGER_SKIPLISTACQUIRE_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class InboundLedgers; class PeerSet; namespace test { @@ -38,10 +18,9 @@ class LedgerReplayClient; * Manage the retrieval of a skip list in a ledger from the network. * Before asking peers, always check if the local node has the ledger. */ -class SkipListAcquire final - : public TimeoutCounter, - public std::enable_shared_from_this, - public CountedObject +class SkipListAcquire final : public TimeoutCounter, + public std::enable_shared_from_this, + public CountedObject { public: /** @@ -49,17 +28,14 @@ public: * @param successful if the skipList data was acquired successfully * @param hash hash of the ledger that has the skipList */ - using OnSkipListDataCB = - std::function; + using OnSkipListDataCB = std::function; struct SkipListData { std::uint32_t const ledgerSeq; - std::vector const skipList; + std::vector const skipList; - SkipListData( - std::uint32_t const ledgerSeq, - std::vector const& skipList) + SkipListData(std::uint32_t const ledgerSeq, std::vector const& skipList) : ledgerSeq(ledgerSeq), skipList(skipList) { } @@ -94,9 +70,7 @@ public: * @note ledgerSeq and item must have been verified against the ledger hash */ void - processData( - std::uint32_t ledgerSeq, - boost::intrusive_ptr const& item); + processData(std::uint32_t ledgerSeq, boost::intrusive_ptr const& item); /** * Add a callback that will be called when the skipList is ready or failed. @@ -130,9 +104,7 @@ private: * @param sl lock. this function must be called with the lock */ void - retrieveSkipList( - std::shared_ptr const& ledger, - ScopedLockType& sl); + retrieveSkipList(std::shared_ptr const& ledger, ScopedLockType& sl); /** * Process the skip list @@ -141,10 +113,7 @@ private: * @param sl lock. this function must be called with the lock */ void - onSkipListAcquired( - std::vector const& skipList, - std::uint32_t ledgerSeq, - ScopedLockType& sl); + onSkipListAcquired(std::vector const& skipList, std::uint32_t ledgerSeq, ScopedLockType& sl); /** * Call the OnSkipListDataCB callbacks @@ -163,6 +132,4 @@ private: friend class test::LedgerReplayClient; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp index 774b70e4d1..0ce6de0d34 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp @@ -1,26 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include -namespace ripple { +#include + +namespace xrpl { using namespace std::chrono_literals; @@ -43,7 +25,7 @@ TimeoutCounter::TimeoutCounter( { XRPL_ASSERT( (timerInterval_ > 10ms) && (timerInterval_ < 30s), - "ripple::TimeoutCounter::TimeoutCounter : interval input inside range"); + "xrpl::TimeoutCounter::TimeoutCounter : interval input inside range"); } void @@ -52,17 +34,16 @@ TimeoutCounter::setTimer(ScopedLockType& sl) if (isDone()) return; timer_.expires_after(timerInterval_); - timer_.async_wait( - [wptr = pmDowncast()](boost::system::error_code const& ec) { - if (ec == boost::asio::error::operation_aborted) - return; + timer_.async_wait([wptr = pmDowncast()](boost::system::error_code const& ec) { + if (ec == boost::asio::error::operation_aborted) + return; - if (auto ptr = wptr.lock()) - { - ScopedLockType sl(ptr->mtx_); - ptr->queueJob(sl); - } - }); + if (auto ptr = wptr.lock()) + { + ScopedLockType sl(ptr->mtx_); + ptr->queueJob(sl); + } + }); } void @@ -71,22 +52,17 @@ TimeoutCounter::queueJob(ScopedLockType& sl) if (isDone()) return; if (queueJobParameter_.jobLimit && - app_.getJobQueue().getJobCountTotal(queueJobParameter_.jobType) >= - queueJobParameter_.jobLimit) + app_.getJobQueue().getJobCountTotal(queueJobParameter_.jobType) >= queueJobParameter_.jobLimit) { - JLOG(journal_.debug()) << "Deferring " << queueJobParameter_.jobName - << " timer due to load"; + JLOG(journal_.debug()) << "Deferring " << queueJobParameter_.jobName << " timer due to load"; setTimer(sl); return; } - app_.getJobQueue().addJob( - queueJobParameter_.jobType, - queueJobParameter_.jobName, - [wptr = pmDowncast()]() { - if (auto sptr = wptr.lock(); sptr) - sptr->invokeOnTimer(); - }); + app_.getJobQueue().addJob(queueJobParameter_.jobType, queueJobParameter_.jobName, [wptr = pmDowncast()]() { + if (auto sptr = wptr.lock(); sptr) + sptr->invokeOnTimer(); + }); } void @@ -125,4 +101,4 @@ TimeoutCounter::cancel() } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.h b/src/xrpld/app/ledger/detail/TimeoutCounter.h index 8da290dd36..5f5ccb2f43 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.h +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.h @@ -1,35 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_TIMEOUTCOUNTER_H_INCLUDED -#define RIPPLE_APP_LEDGER_TIMEOUTCOUNTER_H_INCLUDED +#pragma once #include -#include #include +#include #include #include -namespace ripple { +namespace xrpl { /** This class is an "active" object. It maintains its own timer @@ -121,7 +101,7 @@ protected: } // Used in this class for access to boost::asio::io_context and - // ripple::Overlay. Used in subtypes for the kitchen sink. + // xrpl::Overlay. Used in subtypes for the kitchen sink. Application& app_; beast::Journal journal_; mutable std::recursive_mutex mtx_; @@ -149,6 +129,4 @@ private: boost::asio::basic_waitable_timer timer_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp index 23694b3cb6..f838a912eb 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { using namespace std::chrono_literals; @@ -38,21 +19,12 @@ enum { MAX_TIMEOUTS = 20, }; -TransactionAcquire::TransactionAcquire( - Application& app, - uint256 const& hash, - std::unique_ptr peerSet) - : TimeoutCounter( - app, - hash, - TX_ACQUIRE_TIMEOUT, - {jtTXN_DATA, "TransactionAcquire", {}}, - app.journal("TransactionAcquire")) +TransactionAcquire::TransactionAcquire(Application& app, uint256 const& hash, std::unique_ptr peerSet) + : TimeoutCounter(app, hash, TX_ACQUIRE_TIMEOUT, {jtTXN_DATA, "TxAcq", {}}, app.journal("TransactionAcquire")) , mHaveRoot(false) , mPeerSet(std::move(peerSet)) { - mMap = std::make_shared( - SHAMapType::TRANSACTION, hash, app_.getNodeFamily()); + mMap = std::make_shared(SHAMapType::TRANSACTION, hash, app_.getNodeFamily()); mMap->setUnbacked(); } @@ -79,9 +51,7 @@ TransactionAcquire::done() // just updates the consensus and related structures when we acquire // a transaction set. No need to update them if we're shutting down. app_.getJobQueue().addJob( - jtTXN_DATA, "completeAcquire", [pap, hash, map]() { - pap->getInboundTransactions().giveSet(hash, map, true); - }); + jtTXN_DATA, "ComplAcquire", [pap, hash, map]() { pap->getInboundTransactions().giveSet(hash, map, true); }); } } @@ -123,8 +93,7 @@ TransactionAcquire::trigger(std::shared_ptr const& peer) if (!mHaveRoot) { - JLOG(journal_.trace()) << "TransactionAcquire::trigger " - << (peer ? "havePeer" : "noPeer") << " no root"; + JLOG(journal_.trace()) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root"; protocol::TMGetLedger tmGL; tmGL.set_ledgerhash(hash_.begin(), hash_.size()); tmGL.set_itype(protocol::liTS_CANDIDATE); @@ -203,11 +172,8 @@ TransactionAcquire::takeNodes( if (d.first.isRoot()) { if (mHaveRoot) - JLOG(journal_.debug()) - << "Got root TXS node, already have it"; - else if (!mMap->addRootNode( - SHAMapHash{hash_}, d.second, nullptr) - .isGood()) + JLOG(journal_.debug()) << "Got root TXS node, already have it"; + else if (!mMap->addRootNode(SHAMapHash{hash_}, d.second, nullptr).isGood()) { JLOG(journal_.warn()) << "TX acquire got bad root node"; } @@ -227,9 +193,7 @@ TransactionAcquire::takeNodes( } catch (std::exception const& ex) { - JLOG(journal_.error()) - << "Peer " << peer->id() - << " sent us junky transaction node data: " << ex.what(); + JLOG(journal_.error()) << "Peer " << peer->id() << " sent us junky transaction node data: " << ex.what(); return SHAMapAddNode::invalid(); } } @@ -238,9 +202,7 @@ void TransactionAcquire::addPeers(std::size_t limit) { mPeerSet->addPeers( - limit, - [this](auto peer) { return peer->hasTxSet(hash_); }, - [this](auto peer) { trigger(peer); }); + limit, [this](auto peer) { return peer->hasTxSet(hash_); }, [this](auto peer) { trigger(peer); }); } void @@ -263,4 +225,4 @@ TransactionAcquire::stillNeed() failed_ = false; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.h b/src/xrpld/app/ledger/detail/TransactionAcquire.h index 9289758727..4345c74fc6 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.h +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.h @@ -1,51 +1,25 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_LEDGER_TRANSACTIONACQUIRE_H_INCLUDED -#define RIPPLE_APP_LEDGER_TRANSACTIONACQUIRE_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { // VFALCO TODO rename to PeerTxRequest // A transaction set we are trying to acquire -class TransactionAcquire final - : public TimeoutCounter, - public std::enable_shared_from_this, - public CountedObject +class TransactionAcquire final : public TimeoutCounter, + public std::enable_shared_from_this, + public CountedObject { public: using pointer = std::shared_ptr; - TransactionAcquire( - Application& app, - uint256 const& hash, - std::unique_ptr peerSet); + TransactionAcquire(Application& app, uint256 const& hash, std::unique_ptr peerSet); ~TransactionAcquire() = default; SHAMapAddNode - takeNodes( - std::vector> const& data, - std::shared_ptr const&); + takeNodes(std::vector> const& data, std::shared_ptr const&); void init(int startPeers); @@ -73,6 +47,4 @@ private: pmDowncast() override; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/ledger/detail/TransactionMaster.cpp b/src/xrpld/app/ledger/detail/TransactionMaster.cpp index 1f5ab7e5b0..834234dd4e 100644 --- a/src/xrpld/app/ledger/detail/TransactionMaster.cpp +++ b/src/xrpld/app/ledger/detail/TransactionMaster.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,16 +6,10 @@ #include #include -namespace ripple { +namespace xrpl { TransactionMaster::TransactionMaster(Application& app) - : mApp(app) - , mCache( - "TransactionCache", - 65536, - std::chrono::minutes{30}, - stopwatch(), - mApp.journal("TaggedCache")) + : mApp(app), mCache("TransactionCache", 65536, std::chrono::minutes{30}, stopwatch(), mApp.journal("TaggedCache")) { } @@ -60,13 +35,10 @@ TransactionMaster::fetch_from_cache(uint256 const& txnID) return mCache.fetch(txnID); } -std::variant< - std::pair, std::shared_ptr>, - TxSearched> +std::variant, std::shared_ptr>, TxSearched> TransactionMaster::fetch(uint256 const& txnID, error_code_i& ec) { - using TxPair = - std::pair, std::shared_ptr>; + using TxPair = std::pair, std::shared_ptr>; if (auto txn = fetch_from_cache(txnID); txn && !txn->isValidated()) return std::pair{std::move(txn), nullptr}; @@ -84,16 +56,10 @@ TransactionMaster::fetch(uint256 const& txnID, error_code_i& ec) return std::pair{std::move(txn), std::move(txnMeta)}; } -std::variant< - std::pair, std::shared_ptr>, - TxSearched> -TransactionMaster::fetch( - uint256 const& txnID, - ClosedInterval const& range, - error_code_i& ec) +std::variant, std::shared_ptr>, TxSearched> +TransactionMaster::fetch(uint256 const& txnID, ClosedInterval const& range, error_code_i& ec) { - using TxPair = - std::pair, std::shared_ptr>; + using TxPair = std::pair, std::shared_ptr>; if (auto txn = fetch_from_cache(txnID); txn && !txn->isValidated()) return std::pair{std::move(txn), nullptr}; @@ -112,10 +78,7 @@ TransactionMaster::fetch( } std::shared_ptr -TransactionMaster::fetch( - boost::intrusive_ptr const& item, - SHAMapNodeType type, - std::uint32_t uCommitLedger) +TransactionMaster::fetch(boost::intrusive_ptr const& item, SHAMapNodeType type, std::uint32_t uCommitLedger) { std::shared_ptr txn; auto iTx = fetch_from_cache(item->key()); @@ -130,8 +93,7 @@ TransactionMaster::fetch( else if (type == SHAMapNodeType::tnTRANSACTION_MD) { auto blob = SerialIter{item->slice()}.getVL(); - txn = std::make_shared( - SerialIter{blob.data(), blob.size()}); + txn = std::make_shared(SerialIter{blob.data(), blob.size()}); } } else @@ -170,4 +132,4 @@ TransactionMaster::getCache() return mCache; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index 3725fcea6d..7a59d586e0 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -30,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -44,15 +24,11 @@ #include #include #include -#include -#include +#include #include -#include #include -#include #include #include -#include #include #include @@ -60,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,7 +46,9 @@ #include #include #include +#include #include +#include #include #include @@ -85,7 +65,7 @@ #include #include -namespace ripple { +namespace xrpl { static void fixConfigPorts(Config& config, Endpoints const& endpoints); @@ -108,10 +88,7 @@ private: beast::Journal journal, std::chrono::milliseconds interval, boost::asio::io_context& ios) - : m_event(ev) - , m_journal(journal) - , m_probe(interval, ios) - , lastSample_{} + : m_event(ev), m_journal(journal), m_probe(interval, ios), lastSample_{} { } @@ -134,8 +111,7 @@ private: m_event.notify(lastSample); if (lastSample >= 500ms) { - JLOG(m_journal.warn()) - << "io_context latency = " << lastSample.count(); + JLOG(m_journal.warn()) << "io_context latency = " << lastSample.count(); } } @@ -215,18 +191,14 @@ public: boost::asio::steady_timer sweepTimer_; boost::asio::steady_timer entropyTimer_; - std::unique_ptr mRelationalDatabase; + std::optional relationalDatabase_; std::unique_ptr mWalletDB; std::unique_ptr overlay_; std::optional trapTxID_; boost::asio::signal_set m_signals; - // Once we get C++20, we could use `std::atomic_flag` for `isTimeToStop` - // and eliminate the need for the condition variable and the mutex. - std::condition_variable stoppingCondition_; - mutable std::mutex stoppingMutex_; - std::atomic isTimeToStop = false; + std::atomic_flag isTimeToStop; std::atomic checkSigs_; @@ -241,7 +213,7 @@ public: static std::size_t numberOfThreads(Config const& config) { -#if RIPPLE_SINGLE_IO_SERVICE_THREAD +#if XRPL_SINGLE_IO_SERVICE_THREAD return 1; #else @@ -262,35 +234,24 @@ public: //-------------------------------------------------------------------------- - ApplicationImp( - std::unique_ptr config, - std::unique_ptr logs, - std::unique_ptr timeKeeper) + ApplicationImp(std::unique_ptr config, std::unique_ptr logs, std::unique_ptr timeKeeper) : BasicApp(numberOfThreads(*config)) , config_(std::move(config)) , logs_(std::move(logs)) , timeKeeper_(std::move(timeKeeper)) - , instanceCookie_( - 1 + - rand_int( - crypto_prng(), - std::numeric_limits::max() - 1)) + , instanceCookie_(1 + rand_int(crypto_prng(), std::numeric_limits::max() - 1)) , m_journal(logs_->journal("Application")) // PerfLog must be started before any other threads are launched. , perfLog_(perf::make_PerfLog( - perf::setup_PerfLog( - config_->section("perf"), - config_->CONFIG_DIR), + perf::setup_PerfLog(config_->section("perf"), config_->CONFIG_DIR), *this, logs_->journal("PerfLog"), [this] { signalStop("PerfLog"); })) , m_txMaster(*this) - , m_collectorManager(make_CollectorManager( - config_->section(SECTION_INSIGHT), - logs_->journal("Collector"))) + , m_collectorManager(make_CollectorManager(config_->section(SECTION_INSIGHT), logs_->journal("Collector"))) , m_jobQueue(std::make_unique( [](std::unique_ptr const& config) { @@ -300,8 +261,7 @@ public: if (config->WORKERS) return config->WORKERS; - auto count = - static_cast(std::thread::hardware_concurrency()); + auto count = static_cast(std::thread::hardware_concurrency()); // Be more aggressive about the number of threads to use // for the job queue if the server is configured as @@ -322,42 +282,24 @@ public: , m_nodeStoreScheduler(*m_jobQueue) - , m_shaMapStore(make_SHAMapStore( - *this, - m_nodeStoreScheduler, - logs_->journal("SHAMapStore"))) + , m_shaMapStore(make_SHAMapStore(*this, m_nodeStoreScheduler, logs_->journal("SHAMapStore"))) - , m_tempNodeCache( - "NodeCache", - 16384, - std::chrono::seconds{90}, - stopwatch(), - logs_->journal("TaggedCache")) + , m_tempNodeCache("NodeCache", 16384, std::chrono::seconds{90}, stopwatch(), logs_->journal("TaggedCache")) - , cachedSLEs_( - "Cached SLEs", - 0, - std::chrono::minutes(1), - stopwatch(), - logs_->journal("CachedSLEs")) + , cachedSLEs_("Cached SLEs", 0, std::chrono::minutes(1), stopwatch(), logs_->journal("CachedSLEs")) , validatorKeys_(*config_, m_journal) - , m_resourceManager(Resource::make_Manager( - m_collectorManager->collector(), - logs_->journal("Resource"))) + , m_resourceManager(Resource::make_Manager(m_collectorManager->collector(), logs_->journal("Resource"))) - , m_nodeStore(m_shaMapStore->makeNodeStore( - config_->PREFETCH_WORKERS > 0 ? config_->PREFETCH_WORKERS : 4)) + , m_nodeStore(m_shaMapStore->makeNodeStore(config_->PREFETCH_WORKERS > 0 ? config_->PREFETCH_WORKERS : 4)) , nodeFamily_(*this, *m_collectorManager) , m_orderBookDB(*this) - , m_pathRequests(std::make_unique( - *this, - logs_->journal("PathRequest"), - m_collectorManager->collector())) + , m_pathRequests( + std::make_unique(*this, logs_->journal("PathRequest"), m_collectorManager->collector())) , m_ledgerMaster(std::make_unique( *this, @@ -365,28 +307,19 @@ public: m_collectorManager->collector(), logs_->journal("LedgerMaster"))) - , ledgerCleaner_( - make_LedgerCleaner(*this, logs_->journal("LedgerCleaner"))) + , ledgerCleaner_(make_LedgerCleaner(*this, logs_->journal("LedgerCleaner"))) // VFALCO NOTE must come before NetworkOPs to prevent a crash due // to dependencies in the destructor. // - , m_inboundLedgers(make_InboundLedgers( - *this, - stopwatch(), - m_collectorManager->collector())) + , m_inboundLedgers(make_InboundLedgers(*this, stopwatch(), m_collectorManager->collector())) , m_inboundTransactions(make_InboundTransactions( *this, m_collectorManager->collector(), - [this](std::shared_ptr const& set, bool fromAcquire) { - gotTXSet(set, fromAcquire); - })) + [this](std::shared_ptr const& set, bool fromAcquire) { gotTXSet(set, fromAcquire); })) - , m_ledgerReplayer(std::make_unique( - *this, - *m_inboundLedgers, - make_PeerSetBuilder(*this))) + , m_ledgerReplayer(std::make_unique(*this, *m_inboundLedgers, make_PeerSetBuilder(*this))) , m_acceptedLedgerCache( "AcceptedLedger", @@ -410,14 +343,11 @@ public: , cluster_(std::make_unique(logs_->journal("Overlay"))) - , peerReservations_(std::make_unique( - logs_->journal("PeerReservationTable"))) + , peerReservations_(std::make_unique(logs_->journal("PeerReservationTable"))) - , validatorManifests_( - std::make_unique(logs_->journal("ManifestCache"))) + , validatorManifests_(std::make_unique(logs_->journal("ManifestCache"))) - , publisherManifests_( - std::make_unique(logs_->journal("ManifestCache"))) + , publisherManifests_(std::make_unique(logs_->journal("ManifestCache"))) , validators_(std::make_unique( *validatorManifests_, @@ -437,23 +367,15 @@ public: *m_resourceManager, *m_collectorManager)) - , mFeeTrack( - std::make_unique(logs_->journal("LoadManager"))) + , mFeeTrack(std::make_unique(logs_->journal("LoadManager"))) - , hashRouter_(std::make_unique( - setup_HashRouter(*config_), - stopwatch())) + , hashRouter_(std::make_unique(setup_HashRouter(*config_), stopwatch())) - , mValidations( - ValidationParms(), - stopwatch(), - *this, - logs_->journal("Validations")) + , mValidations(ValidationParms(), stopwatch(), *this, logs_->journal("Validations")) , m_loadManager(make_LoadManager(*this, logs_->journal("LoadManager"))) - , txQ_( - std::make_unique(setup_TxQ(*config_), logs_->journal("TxQ"))) + , txQ_(std::make_unique(setup_TxQ(*config_), logs_->journal("TxQ"))) , sweepTimer_(get_io_context()) @@ -463,8 +385,7 @@ public: , checkSigs_(true) - , m_resolver( - ResolverAsio::New(get_io_context(), logs_->journal("Resolver"))) + , m_resolver(ResolverAsio::New(get_io_context(), logs_->journal("Resolver"))) , m_io_latency_sampler( m_collectorManager->collector()->make_event("ios_latency"), @@ -564,8 +485,7 @@ public: if (nodeIdentity_) return *nodeIdentity_; - LogicError( - "Accessing Application::nodeIdentity() before it is initialized."); + LogicError("Accessing Application::nodeIdentity() before it is initialized."); } std::optional @@ -588,7 +508,7 @@ public: { XRPL_ASSERT( serverHandler_, - "ripple::ApplicationImp::getServerHandler : non-null server " + "xrpl::ApplicationImp::getServerHandler : non-null server " "handle"); return *serverHandler_; } @@ -795,17 +715,14 @@ public: Overlay& overlay() override { - XRPL_ASSERT( - overlay_, "ripple::ApplicationImp::overlay : non-null overlay"); + XRPL_ASSERT(overlay_, "xrpl::ApplicationImp::overlay : non-null overlay"); return *overlay_; } TxQ& getTxQ() override { - XRPL_ASSERT( - txQ_, - "ripple::ApplicationImp::getTxQ : non-null transaction queue"); + XRPL_ASSERT(txQ_, "xrpl::ApplicationImp::getTxQ : non-null transaction queue"); return *txQ_; } @@ -813,18 +730,16 @@ public: getRelationalDatabase() override { XRPL_ASSERT( - mRelationalDatabase, - "ripple::ApplicationImp::getRelationalDatabase : non-null " + relationalDatabase_, + "xrpl::ApplicationImp::getRelationalDatabase : non-null " "relational database"); - return *mRelationalDatabase; + return *relationalDatabase_; } DatabaseCon& getWalletDB() override { - XRPL_ASSERT( - mWalletDB, - "ripple::ApplicationImp::getWalletDB : non-null wallet database"); + XRPL_ASSERT(mWalletDB, "xrpl::ApplicationImp::getWalletDB : non-null wallet database"); return *mWalletDB; } @@ -841,13 +756,12 @@ public: { XRPL_ASSERT( mWalletDB.get() == nullptr, - "ripple::ApplicationImp::initRelationalDatabase : null wallet " + "xrpl::ApplicationImp::initRelationalDatabase : null wallet " "database"); try { - mRelationalDatabase = - RelationalDatabase::init(*this, *config_, *m_jobQueue); + relationalDatabase_.emplace(setup_RelationalDatabase(*this, *config_, *m_jobQueue)); // wallet database auto setup = setup_DatabaseCon(*config_, m_journal); @@ -857,8 +771,7 @@ public: } catch (std::exception const& e) { - JLOG(m_journal.fatal()) - << "Failed to initialize SQL databases: " << e.what(); + JLOG(m_journal.fatal()) << "Failed to initialize SQL databases: " << e.what(); return false; } @@ -872,27 +785,23 @@ public: { auto j = logs_->journal("NodeObject"); NodeStore::DummyScheduler dummyScheduler; - std::unique_ptr source = - NodeStore::Manager::instance().make_Database( - megabytes(config_->getValueFor( - SizedItem::burstSize, std::nullopt)), - dummyScheduler, - 0, - config_->section(ConfigSection::importNodeDatabase()), - j); + std::unique_ptr source = NodeStore::Manager::instance().make_Database( + megabytes(config_->getValueFor(SizedItem::burstSize, std::nullopt)), + dummyScheduler, + 0, + config_->section(ConfigSection::importNodeDatabase()), + j); - JLOG(j.warn()) << "Starting node import from '" << source->getName() - << "' to '" << m_nodeStore->getName() << "'."; + JLOG(j.warn()) << "Starting node import from '" << source->getName() << "' to '" << m_nodeStore->getName() + << "'."; using namespace std::chrono; auto const start = steady_clock::now(); m_nodeStore->importDatabase(*source); - auto const elapsed = - duration_cast(steady_clock::now() - start); - JLOG(j.warn()) << "Node import from '" << source->getName() - << "' took " << elapsed.count() << " seconds."; + auto const elapsed = duration_cast(steady_clock::now() - start); + JLOG(j.warn()) << "Node import from '" << source->getName() << "' took " << elapsed.count() << " seconds."; } return true; @@ -914,28 +823,23 @@ public: setSweepTimer() { // Only start the timer if waitHandlerCounter_ is not yet joined. - if (auto optionalCountedHandler = waitHandlerCounter_.wrap( - [this](boost::system::error_code const& e) { - if (e.value() == boost::system::errc::success) - { - m_jobQueue->addJob( - jtSWEEP, "sweep", [this]() { doSweep(); }); - } - // Recover as best we can if an unexpected error occurs. - if (e.value() != boost::system::errc::success && - e.value() != boost::asio::error::operation_aborted) - { - // Try again later and hope for the best. - JLOG(m_journal.error()) - << "Sweep timer got error '" << e.message() - << "'. Restarting timer."; - setSweepTimer(); - } - })) + if (auto optionalCountedHandler = waitHandlerCounter_.wrap([this](boost::system::error_code const& e) { + if (e.value() == boost::system::errc::success) + { + m_jobQueue->addJob(jtSWEEP, "sweep", [this]() { doSweep(); }); + } + // Recover as best we can if an unexpected error occurs. + if (e.value() != boost::system::errc::success && e.value() != boost::asio::error::operation_aborted) + { + // Try again later and hope for the best. + JLOG(m_journal.error()) << "Sweep timer got error '" << e.message() << "'. Restarting timer."; + setSweepTimer(); + } + })) { using namespace std::chrono; - sweepTimer_.expires_after(seconds{config_->SWEEP_INTERVAL.value_or( - config_->getValueFor(SizedItem::sweepInterval))}); + sweepTimer_.expires_after( + seconds{config_->SWEEP_INTERVAL.value_or(config_->getValueFor(SizedItem::sweepInterval))}); sweepTimer_.async_wait(std::move(*optionalCountedHandler)); } } @@ -944,24 +848,20 @@ public: setEntropyTimer() { // Only start the timer if waitHandlerCounter_ is not yet joined. - if (auto optionalCountedHandler = waitHandlerCounter_.wrap( - [this](boost::system::error_code const& e) { - if (e.value() == boost::system::errc::success) - { - crypto_prng().mix_entropy(); - setEntropyTimer(); - } - // Recover as best we can if an unexpected error occurs. - if (e.value() != boost::system::errc::success && - e.value() != boost::asio::error::operation_aborted) - { - // Try again later and hope for the best. - JLOG(m_journal.error()) - << "Entropy timer got error '" << e.message() - << "'. Restarting timer."; - setEntropyTimer(); - } - })) + if (auto optionalCountedHandler = waitHandlerCounter_.wrap([this](boost::system::error_code const& e) { + if (e.value() == boost::system::errc::success) + { + crypto_prng().mix_entropy(); + setEntropyTimer(); + } + // Recover as best we can if an unexpected error occurs. + if (e.value() != boost::system::errc::success && e.value() != boost::asio::error::operation_aborted) + { + // Try again later and hope for the best. + JLOG(m_journal.error()) << "Entropy timer got error '" << e.message() << "'. Restarting timer."; + setEntropyTimer(); + } + })) { using namespace std::chrono_literals; entropyTimer_.expires_after(5min); @@ -972,8 +872,8 @@ public: void doSweep() { - if (!config_->standalone() && - !getRelationalDatabase().transactionDbHasSpace(*config_)) + XRPL_ASSERT(relationalDatabase_, "xrpl::ApplicationImp::doSweep : non-null relational database"); + if (!config_->standalone() && !relationalDatabase_->transactionDbHasSpace(*config_)) { signalStop("Out of transaction DB space"); } @@ -983,52 +883,38 @@ public: // have listeners register for "onSweep ()" notification. { - std::shared_ptr const fullBelowCache = - nodeFamily_.getFullBelowCache(); + std::shared_ptr const fullBelowCache = nodeFamily_.getFullBelowCache(); - std::shared_ptr const treeNodeCache = - nodeFamily_.getTreeNodeCache(); + std::shared_ptr const treeNodeCache = nodeFamily_.getTreeNodeCache(); std::size_t const oldFullBelowSize = fullBelowCache->size(); std::size_t const oldTreeNodeSize = treeNodeCache->size(); nodeFamily_.sweep(); - JLOG(m_journal.debug()) - << "NodeFamily::FullBelowCache sweep. Size before: " - << oldFullBelowSize - << "; size after: " << fullBelowCache->size(); + JLOG(m_journal.debug()) << "NodeFamily::FullBelowCache sweep. Size before: " << oldFullBelowSize + << "; size after: " << fullBelowCache->size(); - JLOG(m_journal.debug()) - << "NodeFamily::TreeNodeCache sweep. Size before: " - << oldTreeNodeSize << "; size after: " << treeNodeCache->size(); + JLOG(m_journal.debug()) << "NodeFamily::TreeNodeCache sweep. Size before: " << oldTreeNodeSize + << "; size after: " << treeNodeCache->size(); } { - TaggedCache const& masterTxCache = - getMasterTransaction().getCache(); + TaggedCache const& masterTxCache = getMasterTransaction().getCache(); std::size_t const oldMasterTxSize = masterTxCache.size(); getMasterTransaction().sweep(); - JLOG(m_journal.debug()) - << "MasterTransaction sweep. Size before: " << oldMasterTxSize - << "; size after: " << masterTxCache.size(); + JLOG(m_journal.debug()) << "MasterTransaction sweep. Size before: " << oldMasterTxSize + << "; size after: " << masterTxCache.size(); } { - // Does not appear to have an associated cache. - getNodeStore().sweep(); - } - { - std::size_t const oldLedgerMasterCacheSize = - getLedgerMaster().getFetchPackCacheSize(); + std::size_t const oldLedgerMasterCacheSize = getLedgerMaster().getFetchPackCacheSize(); getLedgerMaster().sweep(); - JLOG(m_journal.debug()) - << "LedgerMaster sweep. Size before: " - << oldLedgerMasterCacheSize << "; size after: " - << getLedgerMaster().getFetchPackCacheSize(); + JLOG(m_journal.debug()) << "LedgerMaster sweep. Size before: " << oldLedgerMasterCacheSize + << "; size after: " << getLedgerMaster().getFetchPackCacheSize(); } { // NodeCache == TaggedCache @@ -1036,52 +922,36 @@ public: getTempNodeCache().sweep(); - JLOG(m_journal.debug()) - << "TempNodeCache sweep. Size before: " << oldTempNodeCacheSize - << "; size after: " << getTempNodeCache().size(); + JLOG(m_journal.debug()) << "TempNodeCache sweep. Size before: " << oldTempNodeCacheSize + << "; size after: " << getTempNodeCache().size(); } { - std::size_t const oldCurrentCacheSize = - getValidations().sizeOfCurrentCache(); - std::size_t const oldSizeSeqEnforcesSize = - getValidations().sizeOfSeqEnforcersCache(); - std::size_t const oldByLedgerSize = - getValidations().sizeOfByLedgerCache(); - std::size_t const oldBySequenceSize = - getValidations().sizeOfBySequenceCache(); + std::size_t const oldCurrentCacheSize = getValidations().sizeOfCurrentCache(); + std::size_t const oldSizeSeqEnforcesSize = getValidations().sizeOfSeqEnforcersCache(); + std::size_t const oldByLedgerSize = getValidations().sizeOfByLedgerCache(); + std::size_t const oldBySequenceSize = getValidations().sizeOfBySequenceCache(); getValidations().expire(m_journal); - JLOG(m_journal.debug()) - << "Validations Current expire. Size before: " - << oldCurrentCacheSize - << "; size after: " << getValidations().sizeOfCurrentCache(); + JLOG(m_journal.debug()) << "Validations Current expire. Size before: " << oldCurrentCacheSize + << "; size after: " << getValidations().sizeOfCurrentCache(); - JLOG(m_journal.debug()) - << "Validations SeqEnforcer expire. Size before: " - << oldSizeSeqEnforcesSize << "; size after: " - << getValidations().sizeOfSeqEnforcersCache(); + JLOG(m_journal.debug()) << "Validations SeqEnforcer expire. Size before: " << oldSizeSeqEnforcesSize + << "; size after: " << getValidations().sizeOfSeqEnforcersCache(); - JLOG(m_journal.debug()) - << "Validations ByLedger expire. Size before: " - << oldByLedgerSize - << "; size after: " << getValidations().sizeOfByLedgerCache(); + JLOG(m_journal.debug()) << "Validations ByLedger expire. Size before: " << oldByLedgerSize + << "; size after: " << getValidations().sizeOfByLedgerCache(); - JLOG(m_journal.debug()) - << "Validations BySequence expire. Size before: " - << oldBySequenceSize - << "; size after: " << getValidations().sizeOfBySequenceCache(); + JLOG(m_journal.debug()) << "Validations BySequence expire. Size before: " << oldBySequenceSize + << "; size after: " << getValidations().sizeOfBySequenceCache(); } { - std::size_t const oldInboundLedgersSize = - getInboundLedgers().cacheSize(); + std::size_t const oldInboundLedgersSize = getInboundLedgers().cacheSize(); getInboundLedgers().sweep(); - JLOG(m_journal.debug()) - << "InboundLedgers sweep. Size before: " - << oldInboundLedgersSize - << "; size after: " << getInboundLedgers().cacheSize(); + JLOG(m_journal.debug()) << "InboundLedgers sweep. Size before: " << oldInboundLedgersSize + << "; size after: " << getInboundLedgers().cacheSize(); } { size_t const oldTasksSize = getLedgerReplayer().tasksSize(); @@ -1090,39 +960,30 @@ public: getLedgerReplayer().sweep(); - JLOG(m_journal.debug()) - << "LedgerReplayer tasks sweep. Size before: " << oldTasksSize - << "; size after: " << getLedgerReplayer().tasksSize(); + JLOG(m_journal.debug()) << "LedgerReplayer tasks sweep. Size before: " << oldTasksSize + << "; size after: " << getLedgerReplayer().tasksSize(); - JLOG(m_journal.debug()) - << "LedgerReplayer deltas sweep. Size before: " - << oldDeltasSize - << "; size after: " << getLedgerReplayer().deltasSize(); + JLOG(m_journal.debug()) << "LedgerReplayer deltas sweep. Size before: " << oldDeltasSize + << "; size after: " << getLedgerReplayer().deltasSize(); - JLOG(m_journal.debug()) - << "LedgerReplayer skipLists sweep. Size before: " - << oldSkipListsSize - << "; size after: " << getLedgerReplayer().skipListsSize(); + JLOG(m_journal.debug()) << "LedgerReplayer skipLists sweep. Size before: " << oldSkipListsSize + << "; size after: " << getLedgerReplayer().skipListsSize(); } { - std::size_t const oldAcceptedLedgerSize = - m_acceptedLedgerCache.size(); + std::size_t const oldAcceptedLedgerSize = m_acceptedLedgerCache.size(); m_acceptedLedgerCache.sweep(); - JLOG(m_journal.debug()) - << "AcceptedLedgerCache sweep. Size before: " - << oldAcceptedLedgerSize - << "; size after: " << m_acceptedLedgerCache.size(); + JLOG(m_journal.debug()) << "AcceptedLedgerCache sweep. Size before: " << oldAcceptedLedgerSize + << "; size after: " << m_acceptedLedgerCache.size(); } { std::size_t const oldCachedSLEsSize = cachedSLEs_.size(); cachedSLEs_.sweep(); - JLOG(m_journal.debug()) - << "CachedSLEs sweep. Size before: " << oldCachedSLEsSize - << "; size after: " << cachedSLEs_.size(); + JLOG(m_journal.debug()) << "CachedSLEs sweep. Size before: " << oldCachedSLEsSize + << "; size after: " << cachedSLEs_.size(); } // Set timer to do another sweep later. @@ -1156,14 +1017,16 @@ private: loadLedgerFromFile(std::string const& ledgerID); bool - loadOldLedger( - std::string const& ledgerID, - bool replay, - bool isFilename, - std::optional trapTxID); + loadOldLedger(std::string const& ledgerID, bool replay, bool isFilename, std::optional trapTxID); void setMaxDisallowedLedger(); + + Application& + app() override + { + return *this; + } }; //------------------------------------------------------------------------------ @@ -1182,17 +1045,16 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) // to async_wait). m_signals.add(SIGINT); m_signals.add(SIGTERM); - m_signals.async_wait( - [this](boost::system::error_code const& ec, int signum) { - // Indicates the signal handler has been aborted; do nothing - if (ec == boost::asio::error::operation_aborted) - return; + m_signals.async_wait([this](boost::system::error_code const& ec, int signum) { + // Indicates the signal handler has been aborted; do nothing + if (ec == boost::asio::error::operation_aborted) + return; - JLOG(m_journal.info()) << "Received signal " << signum; + JLOG(m_journal.info()) << "Received signal " << signum; - if (signum == SIGTERM || signum == SIGINT) - signalStop("Signal: " + to_string(signum)); - }); + if (signum == SIGTERM || signum == SIGINT) + signalStop("Signal: " + to_string(signum)); + }); auto debug_log = config_->getDebugLogFile(); @@ -1209,8 +1071,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) logs_->threshold(kDebug); } - JLOG(m_journal.info()) << "Process starting: " - << BuildInfo::getFullVersionString() + JLOG(m_journal.info()) << "Process starting: " << BuildInfo::getFullVersionString() << ", Instance Cookie: " << instanceCookie_; if (numberOfThreads(*config_) < 2) @@ -1242,9 +1103,8 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) supported.reserve(amendments.size()); for (auto const& [a, vote] : amendments) { - auto const f = ripple::getRegisteredFeature(a); - XRPL_ASSERT( - f, "ripple::ApplicationImp::setup : registered feature"); + auto const f = xrpl::getRegisteredFeature(a); + XRPL_ASSERT(f, "xrpl::ApplicationImp::setup : registered feature"); if (f) supported.emplace_back(a, *f, vote); } @@ -1255,38 +1115,30 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) Section const& upVoted = config_->section(SECTION_AMENDMENTS); m_amendmentTable = make_AmendmentTable( - *this, - config().AMENDMENT_MAJORITY_TIME, - supported, - upVoted, - downVoted, - logs_->journal("Amendments")); + *this, config().AMENDMENT_MAJORITY_TIME, supported, upVoted, downVoted, logs_->journal("Amendments")); } Pathfinder::initPathTable(); auto const startUp = config_->START_UP; JLOG(m_journal.debug()) << "startUp: " << startUp; - if (startUp == Config::FRESH) + if (startUp == StartUpType::FRESH) { JLOG(m_journal.info()) << "Starting new Ledger"; startGenesisLedger(); } - else if ( - startUp == Config::LOAD || startUp == Config::LOAD_FILE || - startUp == Config::REPLAY) + else if (startUp == StartUpType::LOAD || startUp == StartUpType::LOAD_FILE || startUp == StartUpType::REPLAY) { JLOG(m_journal.info()) << "Loading specified Ledger"; if (!loadOldLedger( config_->START_LEDGER, - startUp == Config::REPLAY, - startUp == Config::LOAD_FILE, + startUp == StartUpType::REPLAY, + startUp == StartUpType::LOAD_FILE, config_->TRAP_TX_HASH)) { - JLOG(m_journal.error()) - << "The specified ledger could not be loaded."; + JLOG(m_journal.error()) << "The specified ledger could not be loaded."; if (config_->FAST_LOAD) { // Fall back to syncing from the network, such as @@ -1299,7 +1151,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) } } } - else if (startUp == Config::NETWORK) + else if (startUp == StartUpType::NETWORK) { // This should probably become the default once we have a stable // network. @@ -1315,8 +1167,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) if (auto const& forcedRange = config().FORCED_LEDGER_RANGE_PRESENT) { - m_ledgerMaster->setLedgerRangePresent( - forcedRange->first, forcedRange->second); + m_ledgerMaster->setLedgerRangePresent(forcedRange->first, forcedRange->second); } m_orderBookDB.setup(getLedgerMaster().getCurrentLedger()); @@ -1362,17 +1213,14 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) config().section(SECTION_VALIDATOR_LIST_KEYS).values(), config().VALIDATOR_LIST_THRESHOLD)) { - JLOG(m_journal.fatal()) - << "Invalid entry in validator configuration."; + JLOG(m_journal.fatal()) << "Invalid entry in validator configuration."; return false; } } - if (!validatorSites_->load( - config().section(SECTION_VALIDATOR_LIST_SITES).values())) + if (!validatorSites_->load(config().section(SECTION_VALIDATOR_LIST_SITES).values())) { - JLOG(m_journal.fatal()) - << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]"; + JLOG(m_journal.fatal()) << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]"; return false; } @@ -1402,8 +1250,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) add(*overlay_); // add to PropertyStream // start first consensus round - if (!m_networkOPs->beginConsensus( - m_ledgerMaster->getClosedLedger()->info().hash, {})) + if (!m_networkOPs->beginConsensus(m_ledgerMaster->getClosedLedger()->header().hash, {})) { JLOG(m_journal.fatal()) << "Unable to start consensus"; return false; @@ -1412,8 +1259,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) { try { - auto setup = setup_ServerHandler( - *config_, beast::logstream{m_journal.error()}); + auto setup = setup_ServerHandler(*config_, beast::logstream{m_journal.error()}); setup.makeContexts(); serverHandler_->setup(setup, m_journal); fixConfigPorts(*config_, serverHandler_->endpoints()); @@ -1437,8 +1283,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) // of message, if displayed, should be displayed from PeerFinder. if (config_->PEER_PRIVATE && config_->IPS_FIXED.empty()) { - JLOG(m_journal.warn()) - << "No outbound peer connections will be made"; + JLOG(m_journal.warn()) << "No outbound peer connections will be made"; } // VFALCO NOTE the state timer resets the deadlock detector. @@ -1463,12 +1308,10 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) JLOG(m_journal.warn()) << "*** rippled."; JLOG(m_journal.warn()) << "*** If you do not use them to sign " "transactions please edit your"; - JLOG(m_journal.warn()) - << "*** configuration file and remove the [enable_signing] stanza."; + JLOG(m_journal.warn()) << "*** configuration file and remove the [enable_signing] stanza."; JLOG(m_journal.warn()) << "*** If you do use them to sign transactions " "please migrate to a"; - JLOG(m_journal.warn()) - << "*** standalone signing solution as soon as possible."; + JLOG(m_journal.warn()) << "*** standalone signing solution as soon as possible."; } // @@ -1481,14 +1324,12 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) if (!jrReader.parse(cmd, jvCommand)) { - JLOG(m_journal.fatal()) << "Couldn't parse entry in [" - << SECTION_RPC_STARTUP << "]: '" << cmd; + JLOG(m_journal.fatal()) << "Couldn't parse entry in [" << SECTION_RPC_STARTUP << "]: '" << cmd; } if (!config_->quiet()) { - JLOG(m_journal.fatal()) - << "Startup RPC: " << jvCommand << std::endl; + JLOG(m_journal.fatal()) << "Startup RPC: " << jvCommand << std::endl; } Resource::Charge loadType = Resource::feeReferenceRPC; @@ -1523,8 +1364,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) void ApplicationImp::start(bool withTimers) { - JLOG(m_journal.info()) << "Application starting. Version is " - << BuildInfo::getVersionString(); + JLOG(m_journal.info()) << "Application starting. Version is " << BuildInfo::getVersionString(); if (withTimers) { @@ -1540,8 +1380,7 @@ ApplicationImp::start(bool withTimers) overlay_->start(); if (grpcServer_->start()) - fixConfigPorts( - *config_, {{SECTION_PORT_GRPC, grpcServer_->getEndpoint()}}); + fixConfigPorts(*config_, {{SECTION_PORT_GRPC, grpcServer_->getEndpoint()}}); ledgerCleaner_->start(); perfLog_->start(); @@ -1559,10 +1398,7 @@ ApplicationImp::run() getLoadManager().activateStallDetector(); } - { - std::unique_lock lk{stoppingMutex_}; - stoppingCondition_.wait(lk, [this] { return isTimeToStop.load(); }); - } + isTimeToStop.wait(false, std::memory_order_relaxed); JLOG(m_journal.debug()) << "Application stopping"; @@ -1590,8 +1426,7 @@ ApplicationImp::run() } catch (boost::system::system_error const& e) { - JLOG(m_journal.error()) - << "Application: sweepTimer cancel error: " << e.what(); + JLOG(m_journal.error()) << "Application: sweepTimer cancel error: " << e.what(); } try @@ -1600,8 +1435,7 @@ ApplicationImp::run() } catch (boost::system::system_error const& e) { - JLOG(m_journal.error()) - << "Application: entropyTimer cancel error: " << e.what(); + JLOG(m_journal.error()) << "Application: entropyTimer cancel error: " << e.what(); } } @@ -1617,14 +1451,11 @@ ApplicationImp::run() // TODO Store manifests in manifests.sqlite instead of wallet.db validatorManifests_->save( - getWalletDB(), "ValidatorManifests", [this](PublicKey const& pubKey) { - return validators().listed(pubKey); - }); + getWalletDB(), "ValidatorManifests", [this](PublicKey const& pubKey) { return validators().listed(pubKey); }); - publisherManifests_->save( - getWalletDB(), "PublisherManifests", [this](PublicKey const& pubKey) { - return validators().trustedPublisher(pubKey); - }); + publisherManifests_->save(getWalletDB(), "PublisherManifests", [this](PublicKey const& pubKey) { + return validators().trustedPublisher(pubKey); + }); // The order of these stop calls is delicate. // Re-ordering them risks undefined behavior. @@ -1649,14 +1480,14 @@ ApplicationImp::run() void ApplicationImp::signalStop(std::string msg) { - if (!isTimeToStop.exchange(true)) + if (!isTimeToStop.test_and_set(std::memory_order_acquire)) { if (msg.empty()) JLOG(m_journal.warn()) << "Server stopping"; else JLOG(m_journal.warn()) << "Server stopping: " << msg; - stoppingCondition_.notify_all(); + isTimeToStop.notify_all(); } } @@ -1675,7 +1506,7 @@ ApplicationImp::checkSigs(bool check) bool ApplicationImp::isStopping() const { - return isTimeToStop.load(); + return isTimeToStop.test(std::memory_order_relaxed); } int @@ -1707,20 +1538,17 @@ void ApplicationImp::startGenesisLedger() { std::vector const initialAmendments = - (config_->START_UP == Config::FRESH) ? m_amendmentTable->getDesired() - : std::vector{}; + (config_->START_UP == StartUpType::FRESH) ? m_amendmentTable->getDesired() : std::vector{}; - std::shared_ptr const genesis = std::make_shared( - create_genesis, *config_, initialAmendments, nodeFamily_); + std::shared_ptr const genesis = + std::make_shared(create_genesis, *config_, initialAmendments, nodeFamily_); m_ledgerMaster->storeLedger(genesis); - auto const next = - std::make_shared(*genesis, timeKeeper().closeTime()); + auto const next = std::make_shared(*genesis, timeKeeper().closeTime()); next->updateSkipList(); XRPL_ASSERT( - next->info().seq < XRP_LEDGER_EARLIEST_FEES || - next->read(keylet::fees()), - "ripple::ApplicationImp::startGenesisLedger : valid ledger fees"); + next->header().seq < XRP_LEDGER_EARLIEST_FEES || next->read(keylet::fees()), + "xrpl::ApplicationImp::startGenesisLedger : valid ledger fees"); next->setImmutable(); openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger")); m_ledgerMaster->storeLedger(next); @@ -1740,15 +1568,14 @@ ApplicationImp::getLastFullLedger() return ledger; XRPL_ASSERT( - ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees()), - "ripple::ApplicationImp::getLastFullLedger : valid ledger fees"); + ledger->header().seq < XRP_LEDGER_EARLIEST_FEES || ledger->read(keylet::fees()), + "xrpl::ApplicationImp::getLastFullLedger : valid ledger fees"); ledger->setImmutable(); if (getLedgerMaster().haveLedger(seq)) ledger->setValidated(); - if (ledger->info().hash == hash) + if (ledger->header().hash == hash) { JLOG(j.trace()) << "Loaded ledger: " << hash; return ledger; @@ -1825,18 +1652,15 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) if (ledger.get().isMember("close_time_resolution")) { using namespace std::chrono; - closeTimeResolution = - seconds{ledger.get()["close_time_resolution"].asUInt()}; + closeTimeResolution = seconds{ledger.get()["close_time_resolution"].asUInt()}; } if (ledger.get().isMember("close_time_estimated")) { - closeTimeEstimated = - ledger.get()["close_time_estimated"].asBool(); + closeTimeEstimated = ledger.get()["close_time_estimated"].asBool(); } if (ledger.get().isMember("total_coins")) { - totalDrops = beast::lexicalCastThrow( - ledger.get()["total_coins"].asString()); + totalDrops = beast::lexicalCastThrow(ledger.get()["total_coins"].asString()); } ledger = ledger.get()["accountState"]; @@ -1848,8 +1672,7 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) return nullptr; } - auto loadLedger = - std::make_shared(seq, closeTime, *config_, nodeFamily_); + auto loadLedger = std::make_shared(seq, closeTime, *config_, nodeFamily_); loadLedger->setTotalDrops(totalDrops); for (Json::UInt index = 0; index < ledger.get().size(); ++index) @@ -1886,8 +1709,7 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) if (!loadLedger->addSLE(sle)) { - JLOG(m_journal.fatal()) - << "Couldn't add serialized ledger: " << uIndex; + JLOG(m_journal.fatal()) << "Couldn't add serialized ledger: " << uIndex; return nullptr; } } @@ -1895,11 +1717,9 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) loadLedger->stateMap().flushDirty(hotACCOUNT_NODE); XRPL_ASSERT( - loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - loadLedger->read(keylet::fees()), - "ripple::ApplicationImp::loadLedgerFromFile : valid ledger fees"); - loadLedger->setAccepted( - closeTime, closeTimeResolution, !closeTimeEstimated); + loadLedger->header().seq < XRP_LEDGER_EARLIEST_FEES || loadLedger->read(keylet::fees()), + "xrpl::ApplicationImp::loadLedgerFromFile : valid ledger fees"); + loadLedger->setAccepted(closeTime, closeTimeResolution, !closeTimeEstimated); return loadLedger; } @@ -1938,12 +1758,7 @@ ApplicationImp::loadOldLedger( { // Try to build the ledger from the back end auto il = std::make_shared( - *this, - hash, - 0, - InboundLedger::Reason::GENERIC, - stopwatch(), - make_DummyPeerSet(*this)); + *this, hash, 0, InboundLedger::Reason::GENERIC, stopwatch(), make_DummyPeerSet(*this)); if (il->checkLocal()) loadLedger = il->getLedger(); } @@ -1974,16 +1789,15 @@ ApplicationImp::loadOldLedger( JLOG(m_journal.info()) << "Loading parent ledger"; - loadLedger = loadByHash(replayLedger->info().parentHash, *this); + loadLedger = loadByHash(replayLedger->header().parentHash, *this); if (!loadLedger) { - JLOG(m_journal.info()) - << "Loading parent ledger from node store"; + JLOG(m_journal.info()) << "Loading parent ledger from node store"; // Try to build the ledger from the back end auto il = std::make_shared( *this, - replayLedger->info().parentHash, + replayLedger->header().parentHash, 0, InboundLedger::Reason::GENERIC, stopwatch(), @@ -1997,7 +1811,7 @@ ApplicationImp::loadOldLedger( // LCOV_EXCL_START JLOG(m_journal.fatal()) << "Replay ledger missing/damaged"; UNREACHABLE( - "ripple::ApplicationImp::loadOldLedger : replay ledger " + "xrpl::ApplicationImp::loadOldLedger : replay ledger " "missing/damaged"); return false; // LCOV_EXCL_STOP @@ -2008,29 +1822,26 @@ ApplicationImp::loadOldLedger( using namespace date; static constexpr NetClock::time_point ledgerWarnTimePoint{ sys_days{January / 1 / 2018} - sys_days{January / 1 / 2000}}; - if (loadLedger->info().closeTime < ledgerWarnTimePoint) + if (loadLedger->header().closeTime < ledgerWarnTimePoint) { - JLOG(m_journal.fatal()) - << "\n\n*** WARNING ***\n" - "You are replaying a ledger from before " - << to_string(ledgerWarnTimePoint) - << " UTC.\n" - "This replay will not handle your ledger as it was " - "originally " - "handled.\nConsider running an earlier version of rippled " - "to " - "get the older rules.\n*** CONTINUING ***\n"; + JLOG(m_journal.fatal()) << "\n\n*** WARNING ***\n" + "You are replaying a ledger from before " + << to_string(ledgerWarnTimePoint) + << " UTC.\n" + "This replay will not handle your ledger as it was " + "originally " + "handled.\nConsider running an earlier version of rippled " + "to " + "get the older rules.\n*** CONTINUING ***\n"; } - JLOG(m_journal.info()) << "Loading ledger " << loadLedger->info().hash - << " seq:" << loadLedger->info().seq; + JLOG(m_journal.info()) << "Loading ledger " << loadLedger->header().hash << " seq:" << loadLedger->header().seq; - if (loadLedger->info().accountHash.isZero()) + if (loadLedger->header().accountHash.isZero()) { // LCOV_EXCL_START JLOG(m_journal.fatal()) << "Ledger is empty."; - UNREACHABLE( - "ripple::ApplicationImp::loadOldLedger : ledger is empty"); + UNREACHABLE("xrpl::ApplicationImp::loadOldLedger : ledger is empty"); return false; // LCOV_EXCL_STOP } @@ -2040,7 +1851,7 @@ ApplicationImp::loadOldLedger( // LCOV_EXCL_START JLOG(m_journal.fatal()) << "Ledger is missing nodes."; UNREACHABLE( - "ripple::ApplicationImp::loadOldLedger : ledger is missing " + "xrpl::ApplicationImp::loadOldLedger : ledger is missing " "nodes"); return false; // LCOV_EXCL_STOP @@ -2051,27 +1862,24 @@ ApplicationImp::loadOldLedger( // LCOV_EXCL_START JLOG(m_journal.fatal()) << "Ledger is not sensible."; UNREACHABLE( - "ripple::ApplicationImp::loadOldLedger : ledger is not " + "xrpl::ApplicationImp::loadOldLedger : ledger is not " "sensible"); return false; // LCOV_EXCL_STOP } - m_ledgerMaster->setLedgerRangePresent( - loadLedger->info().seq, loadLedger->info().seq); + m_ledgerMaster->setLedgerRangePresent(loadLedger->header().seq, loadLedger->header().seq); m_ledgerMaster->switchLCL(loadLedger); loadLedger->setValidated(); m_ledgerMaster->setFullLedger(loadLedger, true, false); - openLedger_.emplace( - loadLedger, cachedSLEs_, logs_->journal("OpenLedger")); + openLedger_.emplace(loadLedger, cachedSLEs_, logs_->journal("OpenLedger")); if (replay) { // inject transaction(s) from the replayLedger into our open ledger // and build replay structure - auto replayData = - std::make_unique(loadLedger, replayLedger); + auto replayData = std::make_unique(loadLedger, replayLedger); for (auto const& [_, tx] : replayData->orderedTxns()) { @@ -2088,34 +1896,30 @@ ApplicationImp::loadOldLedger( forceValidity(getHashRouter(), txID, Validity::SigGoodOnly); - openLedger_->modify( - [&txID, &s](OpenView& view, beast::Journal j) { - view.rawTxInsert(txID, std::move(s), nullptr); - return true; - }); + openLedger_->modify([&txID, &s](OpenView& view, beast::Journal j) { + view.rawTxInsert(txID, std::move(s), nullptr); + return true; + }); } m_ledgerMaster->takeReplay(std::move(replayData)); if (trapTxID && !trapTxID_) { - JLOG(m_journal.fatal()) - << "Ledger " << replayLedger->info().seq - << " does not contain the transaction hash " << *trapTxID; + JLOG(m_journal.fatal()) << "Ledger " << replayLedger->header().seq + << " does not contain the transaction hash " << *trapTxID; return false; } } } catch (SHAMapMissingNode const& mn) { - JLOG(m_journal.fatal()) - << "While loading specified ledger: " << mn.what(); + JLOG(m_journal.fatal()) << "While loading specified ledger: " << mn.what(); return false; } catch (boost::bad_lexical_cast&) { - JLOG(m_journal.fatal()) - << "Ledger specified '" << ledgerID << "' is not valid"; + JLOG(m_journal.fatal()) << "Ledger specified '" << ledgerID << "' is not valid"; return false; } @@ -2183,8 +1987,7 @@ ApplicationImp::setMaxDisallowedLedger() if (seq) maxDisallowedLedger_ = *seq; - JLOG(m_journal.trace()) - << "Max persisted ledger is " << maxDisallowedLedger_; + JLOG(m_journal.trace()) << "Max persisted ledger is " << maxDisallowedLedger_; } //------------------------------------------------------------------------------ @@ -2196,13 +1999,9 @@ Application::Application() : beast::PropertyStream::Source("app") //------------------------------------------------------------------------------ std::unique_ptr -make_Application( - std::unique_ptr config, - std::unique_ptr logs, - std::unique_ptr timeKeeper) +make_Application(std::unique_ptr config, std::unique_ptr logs, std::unique_ptr timeKeeper) { - return std::make_unique( - std::move(config), std::move(logs), std::move(timeKeeper)); + return std::make_unique(std::move(config), std::move(logs), std::move(timeKeeper)); } void @@ -2217,12 +2016,11 @@ fixConfigPorts(Config& config, Endpoints const& endpoints) auto const optPort = section.get("port"); if (optPort) { - std::uint16_t const port = - beast::lexicalCast(*optPort); + std::uint16_t const port = beast::lexicalCast(*optPort); if (!port) section.set("port", std::to_string(ep.port())); } } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index 6dc50097bb..5ecc84c11c 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -1,30 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED -#define RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED +#pragma once #include -#include #include #include +#include +#include #include #include @@ -33,7 +14,7 @@ #include -namespace ripple { +namespace xrpl { namespace unl { class Manager; @@ -110,7 +91,7 @@ class Validations; class RCLValidationsAdaptor; using RCLValidations = Validations; -class Application : public beast::PropertyStream::Source +class Application : public ServiceRegistry, public beast::PropertyStream::Source { public: /* VFALCO NOTE @@ -131,8 +112,6 @@ public: public: Application(); - virtual ~Application() = default; - virtual bool setup(boost::program_options::variables_map const& options) = 0; @@ -146,8 +125,6 @@ public: checkSigs() const = 0; virtual void checkSigs(bool) = 0; - virtual bool - isStopping() const = 0; // // --- @@ -157,109 +134,21 @@ public: virtual std::uint64_t instanceID() const = 0; - virtual Logs& - logs() = 0; virtual Config& config() = 0; - virtual boost::asio::io_context& - getIOContext() = 0; - - virtual CollectorManager& - getCollectorManager() = 0; - virtual Family& - getNodeFamily() = 0; - virtual TimeKeeper& - timeKeeper() = 0; - virtual JobQueue& - getJobQueue() = 0; - virtual NodeCache& - getTempNodeCache() = 0; - virtual CachedSLEs& - cachedSLEs() = 0; - virtual AmendmentTable& - getAmendmentTable() = 0; - virtual HashRouter& - getHashRouter() = 0; - virtual LoadFeeTrack& - getFeeTrack() = 0; - virtual LoadManager& - getLoadManager() = 0; - virtual Overlay& - overlay() = 0; - virtual TxQ& - getTxQ() = 0; - virtual ValidatorList& - validators() = 0; - virtual ValidatorSite& - validatorSites() = 0; - virtual ManifestCache& - validatorManifests() = 0; - virtual ManifestCache& - publisherManifests() = 0; - virtual Cluster& - cluster() = 0; - virtual PeerReservationTable& - peerReservations() = 0; - virtual RCLValidations& - getValidations() = 0; - virtual NodeStore::Database& - getNodeStore() = 0; - virtual InboundLedgers& - getInboundLedgers() = 0; - virtual InboundTransactions& - getInboundTransactions() = 0; - - virtual TaggedCache& - getAcceptedLedgerCache() = 0; - - virtual LedgerMaster& - getLedgerMaster() = 0; - virtual LedgerCleaner& - getLedgerCleaner() = 0; - virtual LedgerReplayer& - getLedgerReplayer() = 0; - virtual NetworkOPs& - getOPs() = 0; - virtual OrderBookDB& - getOrderBookDB() = 0; - virtual ServerHandler& - getServerHandler() = 0; - virtual TransactionMaster& - getMasterTransaction() = 0; - virtual perf::PerfLog& - getPerfLog() = 0; - virtual std::pair const& nodeIdentity() = 0; virtual std::optional getValidationPublicKey() const = 0; - virtual Resource::Manager& - getResourceManager() = 0; - virtual PathRequests& - getPathRequests() = 0; - virtual SHAMapStore& - getSHAMapStore() = 0; - virtual PendingSaves& - pendingSaves() = 0; - virtual OpenLedger& - openLedger() = 0; - virtual OpenLedger const& - openLedger() const = 0; - virtual RelationalDatabase& - getRelationalDatabase() = 0; - virtual std::chrono::milliseconds getIOLatency() = 0; virtual bool serverOkay(std::string& reason) = 0; - virtual beast::Journal - journal(std::string const& name) = 0; - /* Returns the number of file descriptors the application needs */ virtual int fdRequired() const = 0; @@ -278,11 +167,6 @@ public: }; std::unique_ptr -make_Application( - std::unique_ptr config, - std::unique_ptr logs, - std::unique_ptr timeKeeper); +make_Application(std::unique_ptr config, std::unique_ptr logs, std::unique_ptr timeKeeper); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/BasicApp.cpp b/src/xrpld/app/main/BasicApp.cpp index 87f440dfc8..be0c158b85 100644 --- a/src/xrpld/app/main/BasicApp.cpp +++ b/src/xrpld/app/main/BasicApp.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -31,8 +12,7 @@ BasicApp::BasicApp(std::size_t numberOfThreads) while (numberOfThreads--) { threads_.emplace_back([this, numberOfThreads]() { - beast::setCurrentThreadName( - "io svc #" + std::to_string(numberOfThreads)); + beast::setCurrentThreadName("io svc #" + std::to_string(numberOfThreads)); this->io_context_.run(); }); } diff --git a/src/xrpld/app/main/BasicApp.h b/src/xrpld/app/main/BasicApp.h index 276676ca18..278c255af3 100644 --- a/src/xrpld/app/main/BasicApp.h +++ b/src/xrpld/app/main/BasicApp.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_BASICAPP_H_INCLUDED -#define RIPPLE_APP_BASICAPP_H_INCLUDED +#pragma once #include @@ -30,9 +10,7 @@ class BasicApp { private: - std::optional> - work_; + std::optional> work_; std::vector threads_; boost::asio::io_context io_context_; @@ -46,5 +24,3 @@ public: return io_context_; } }; - -#endif diff --git a/src/xrpld/app/main/CollectorManager.cpp b/src/xrpld/app/main/CollectorManager.cpp index 81f59d8e2b..7a3306b60b 100644 --- a/src/xrpld/app/main/CollectorManager.cpp +++ b/src/xrpld/app/main/CollectorManager.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { class CollectorManagerImp : public CollectorManager { @@ -30,19 +11,16 @@ public: beast::insight::Collector::ptr m_collector; std::unique_ptr m_groups; - CollectorManagerImp(Section const& params, beast::Journal journal) - : m_journal(journal) + CollectorManagerImp(Section const& params, beast::Journal journal) : m_journal(journal) { std::string const& server = get(params, "server"); if (server == "statsd") { - beast::IP::Endpoint const address( - beast::IP::Endpoint::from_string(get(params, "address"))); + beast::IP::Endpoint const address(beast::IP::Endpoint::from_string(get(params, "address"))); std::string const& prefix(get(params, "prefix")); - m_collector = - beast::insight::StatsDCollector::New(address, prefix, journal); + m_collector = beast::insight::StatsDCollector::New(address, prefix, journal); } else { @@ -75,4 +53,4 @@ make_CollectorManager(Section const& params, beast::Journal journal) return std::make_unique(params, journal); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/CollectorManager.h b/src/xrpld/app/main/CollectorManager.h index 0bb3ae65c4..15785ec292 100644 --- a/src/xrpld/app/main/CollectorManager.h +++ b/src/xrpld/app/main/CollectorManager.h @@ -1,29 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_COLLECTORMANAGER_H_INCLUDED -#define RIPPLE_APP_MAIN_COLLECTORMANAGER_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Provides the beast::insight::Collector service. */ class CollectorManager @@ -41,6 +21,4 @@ public: std::unique_ptr make_CollectorManager(Section const& params, beast::Journal journal); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index a4bbcda0a5..9b07728eb8 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace { @@ -43,8 +24,7 @@ getEndpoint(std::string const& peer) peerClean = peer.substr(first + 1); } - std::optional endpoint = - beast::IP::Endpoint::from_string_checked(peerClean); + std::optional endpoint = beast::IP::Endpoint::from_string_checked(peerClean); if (endpoint) return beast::IP::to_asio_endpoint(endpoint.value()); } @@ -89,15 +69,7 @@ std::shared_ptr GRPCServerImpl::CallData::clone() { return std::make_shared>( - service_, - cq_, - app_, - bindListener_, - handler_, - forward_, - requiredCondition_, - loadType_, - secureGatewayIPs_); + service_, cq_, app_, bindListener_, handler_, forward_, requiredCondition_, loadType_, secureGatewayIPs_); } template @@ -107,8 +79,7 @@ GRPCServerImpl::CallData::process() // sanity check BOOST_ASSERT(!finished_); - std::shared_ptr> thisShared = - this->shared_from_this(); + std::shared_ptr> thisShared = this->shared_from_this(); // Need to set finished to true before processing the response, // because as soon as the response is posted to the completion @@ -119,26 +90,22 @@ GRPCServerImpl::CallData::process() // ensures that finished is always true when this CallData object // is returned as a tag in handleRpcs(), after sending the response finished_ = true; - auto coro = app_.getJobQueue().postCoro( - JobType::jtRPC, - "gRPC-Client", - [thisShared](std::shared_ptr coro) { + auto coro = + app_.getJobQueue().postCoro(JobType::jtRPC, "gRPC-Client", [thisShared](std::shared_ptr coro) { thisShared->process(coro); }); // If coro is null, then the JobQueue has already been shutdown if (!coro) { - grpc::Status status{ - grpc::StatusCode::INTERNAL, "Job Queue is already stopped"}; + grpc::Status status{grpc::StatusCode::INTERNAL, "Job Queue is already stopped"}; responder_.FinishWithError(status, this); } } template void -GRPCServerImpl::CallData::process( - std::shared_ptr coro) +GRPCServerImpl::CallData::process(std::shared_ptr coro) { try { @@ -146,9 +113,7 @@ GRPCServerImpl::CallData::process( bool isUnlimited = clientIsUnlimited(); if (!isUnlimited && usage.disconnect(app_.journal("gRPCServer"))) { - grpc::Status status{ - grpc::StatusCode::RESOURCE_EXHAUSTED, - "usage balance exceeds threshold"}; + grpc::Status status{grpc::StatusCode::RESOURCE_EXHAUSTED, "usage balance exceeds threshold"}; responder_.FinishWithError(status, this); } else @@ -170,8 +135,7 @@ GRPCServerImpl::CallData::process( toLog << user.value(); toLog << " isUnlimited = " << isUnlimited; - JLOG(app_.journal("GRPCServer::Calldata").debug()) - << toLog.str(); + JLOG(app_.journal("GRPCServer::Calldata").debug()) << toLog.str(); } RPC::GRPCContext context{ @@ -188,15 +152,12 @@ GRPCServerImpl::CallData::process( request_}; // Make sure we can currently handle the rpc - error_code_i conditionMetRes = - RPC::conditionMet(requiredCondition_, context); + error_code_i conditionMetRes = RPC::conditionMet(requiredCondition_, context); if (conditionMetRes != rpcSUCCESS) { RPC::ErrorInfo errorInfo = RPC::get_error_info(conditionMetRes); - grpc::Status status{ - grpc::StatusCode::FAILED_PRECONDITION, - errorInfo.message.c_str()}; + grpc::Status status{grpc::StatusCode::FAILED_PRECONDITION, errorInfo.message.c_str()}; responder_.FinishWithError(status, this); } else @@ -244,8 +205,7 @@ GRPCServerImpl::CallData::getUser() { if (auto descriptor = Request::GetDescriptor()->FindFieldByName("user")) { - std::string user = - Request::GetReflection()->GetString(request_, descriptor); + std::string user = Request::GetReflection()->GetString(request_, descriptor); if (!user.empty()) { return user; @@ -268,7 +228,7 @@ template std::optional GRPCServerImpl::CallData::getClientEndpoint() { - return ripple::getEndpoint(ctx_.peer()); + return xrpl::getEndpoint(ctx_.peer()); } template @@ -291,14 +251,11 @@ GRPCServerImpl::CallData::clientIsUnlimited() template void -GRPCServerImpl::CallData::setIsUnlimited( - Response& response, - bool isUnlimited) +GRPCServerImpl::CallData::setIsUnlimited(Response& response, bool isUnlimited) { if (isUnlimited) { - if (auto descriptor = - Response::GetDescriptor()->FindFieldByName("is_unlimited")) + if (auto descriptor = Response::GetDescriptor()->FindFieldByName("is_unlimited")) { Response::GetReflection()->SetBool(&response, descriptor, true); } @@ -311,13 +268,11 @@ GRPCServerImpl::CallData::getUsage() { auto endpoint = getClientEndpoint(); if (endpoint) - return app_.getResourceManager().newInboundEndpoint( - beast::IP::from_asio(endpoint.value())); + return app_.getResourceManager().newInboundEndpoint(beast::IP::from_asio(endpoint.value())); Throw("Failed to get client endpoint"); } -GRPCServerImpl::GRPCServerImpl(Application& app) - : app_(app), journal_(app_.journal("gRPC Server")) +GRPCServerImpl::GRPCServerImpl(Application& app) : app_(app), journal_(app_.journal("gRPC Server")) { // if present, get endpoint from config if (app_.config().exists(SECTION_PORT_GRPC)) @@ -333,8 +288,7 @@ GRPCServerImpl::GRPCServerImpl(Application& app) return; try { - boost::asio::ip::tcp::endpoint endpoint( - boost::asio::ip::make_address(*optIp), std::stoi(*optPort)); + boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address(*optIp), std::stoi(*optPort)); std::stringstream ss; ss << endpoint; @@ -360,11 +314,9 @@ GRPCServerImpl::GRPCServerImpl(Application& app) if (addr.is_unspecified()) { - JLOG(journal_.error()) - << "Can't pass unspecified IP in " - << "secure_gateway section of port_grpc"; - Throw( - "Unspecified IP in secure_gateway section"); + JLOG(journal_.error()) << "Can't pass unspecified IP in " + << "secure_gateway section of port_grpc"; + Throw("Unspecified IP in secure_gateway section"); } secureGatewayIPs_.emplace_back(addr); @@ -372,10 +324,8 @@ GRPCServerImpl::GRPCServerImpl(Application& app) } catch (std::exception const&) { - JLOG(journal_.error()) - << "Error parsing secure gateway IPs for grpc server"; - Throw( - "Error parsing secure_gateway section"); + JLOG(journal_.error()) << "Error parsing secure gateway IPs for grpc server"; + Throw("Error parsing secure_gateway section"); } } } @@ -413,11 +363,7 @@ GRPCServerImpl::handleRpcs() auto erase = [&requests](Processor* ptr) { auto it = std::find_if( - requests.begin(), - requests.end(), - [ptr](std::shared_ptr& sPtr) { - return sPtr.get() == ptr; - }); + requests.begin(), requests.end(), [ptr](std::shared_ptr& sPtr) { return sPtr.get() == ptr; }); BOOST_ASSERT(it != requests.end()); it->swap(requests.back()); requests.pop_back(); @@ -432,7 +378,7 @@ GRPCServerImpl::handleRpcs() // tells us whether there is any kind of event or cq_ is shutting down. // When cq_.Next(...) returns false, all work has been completed and the // loop can exit. When the server is shutdown, each CallData object that is - // listening for a request is forceably cancelled, and is returned by + // listening for a request is forcibly cancelled, and is returned by // cq_->Next() with ok set to false. Then, each CallData object processing // a request must complete (by sending data to the client), each of which // will be returned from cq_->Next() with ok set to true. After all @@ -479,21 +425,16 @@ GRPCServerImpl::setupListeners() { std::vector> requests; - auto addToRequests = [&requests](auto callData) { - requests.push_back(std::move(callData)); - }; + auto addToRequests = [&requests](auto callData) { requests.push_back(std::move(callData)); }; { - using cd = CallData< - org::xrpl::rpc::v1::GetLedgerRequest, - org::xrpl::rpc::v1::GetLedgerResponse>; + using cd = CallData; addToRequests(std::make_shared( service_, *cq_, app_, - &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService:: - RequestGetLedger, + &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedger, doLedgerGrpc, &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedger, RPC::NO_CONDITION, @@ -501,16 +442,13 @@ GRPCServerImpl::setupListeners() secureGatewayIPs_)); } { - using cd = CallData< - org::xrpl::rpc::v1::GetLedgerDataRequest, - org::xrpl::rpc::v1::GetLedgerDataResponse>; + using cd = CallData; addToRequests(std::make_shared( service_, *cq_, app_, - &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService:: - RequestGetLedgerData, + &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerData, doLedgerDataGrpc, &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerData, RPC::NO_CONDITION, @@ -518,16 +456,13 @@ GRPCServerImpl::setupListeners() secureGatewayIPs_)); } { - using cd = CallData< - org::xrpl::rpc::v1::GetLedgerDiffRequest, - org::xrpl::rpc::v1::GetLedgerDiffResponse>; + using cd = CallData; addToRequests(std::make_shared( service_, *cq_, app_, - &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService:: - RequestGetLedgerDiff, + &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerDiff, doLedgerDiffGrpc, &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerDiff, RPC::NO_CONDITION, @@ -535,16 +470,13 @@ GRPCServerImpl::setupListeners() secureGatewayIPs_)); } { - using cd = CallData< - org::xrpl::rpc::v1::GetLedgerEntryRequest, - org::xrpl::rpc::v1::GetLedgerEntryResponse>; + using cd = CallData; addToRequests(std::make_shared( service_, *cq_, app_, - &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService:: - RequestGetLedgerEntry, + &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerEntry, doLedgerEntryGrpc, &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerEntry, RPC::NO_CONDITION, @@ -568,8 +500,7 @@ GRPCServerImpl::start() // Listen on the given address without any authentication mechanism. // Actually binded port will be returned into "port" variable. int port = 0; - builder.AddListeningPort( - serverAddress_, grpc::InsecureServerCredentials(), &port); + builder.AddListeningPort(serverAddress_, grpc::InsecureServerCredentials(), &port); // Register "service_" as the instance through which we'll communicate with // clients. In this case it corresponds to an *asynchronous* service. builder.RegisterService(&service_); @@ -586,10 +517,8 @@ GRPCServerImpl::start() boost::asio::ip::tcp::endpoint GRPCServerImpl::getEndpoint() const { - std::string const addr = - serverAddress_.substr(0, serverAddress_.find_last_of(':')); - return boost::asio::ip::tcp::endpoint( - boost::asio::ip::make_address(addr), serverPort_); + std::string const addr = serverAddress_.substr(0, serverAddress_.find_last_of(':')); + return boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(addr), serverPort_); } bool @@ -620,7 +549,7 @@ GRPCServer::stop() GRPCServer::~GRPCServer() { - XRPL_ASSERT(!running_, "ripple::GRPCServer::~GRPCServer : is not running"); + XRPL_ASSERT(!running_, "xrpl::GRPCServer::~GRPCServer : is not running"); } boost::asio::ip::tcp::endpoint @@ -629,4 +558,4 @@ GRPCServer::getEndpoint() const return impl_.getEndpoint(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/GRPCServer.h b/src/xrpld/app/main/GRPCServer.h index c8beb86749..fdac2b6484 100644 --- a/src/xrpld/app/main/GRPCServer.h +++ b/src/xrpld/app/main/GRPCServer.h @@ -1,39 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_GRPCSERVER_H_INCLUDED -#define RIPPLE_CORE_GRPCSERVER_H_INCLUDED +#pragma once #include -#include #include #include #include #include #include +#include #include #include #include -namespace ripple { +namespace xrpl { // Interface that CallData implements class Processor @@ -104,17 +84,13 @@ private: // typedef for actual handler (that populates a response) // handlers are defined in rpc/GRPCHandlers.h template - using Handler = std::function( - RPC::GRPCContext&)>; + using Handler = std::function(RPC::GRPCContext&)>; // This implementation is currently limited to v1 of the API static unsigned constexpr apiVersion = 1; template - using Forward = std::function; + using Forward = std::function< + grpc::Status(org::xrpl::rpc::v1::XRPLedgerAPIService::Stub*, grpc::ClientContext*, Request, Response*)>; public: explicit GRPCServerImpl(Application& app); @@ -145,11 +121,9 @@ public: getEndpoint() const; private: - // Class encompasing the state and logic needed to serve a request. + // Class encompassing the state and logic needed to serve a request. template - class CallData - : public Processor, - public std::enable_shared_from_this> + class CallData : public Processor, public std::enable_shared_from_this> { private: // The means of communication with the gRPC runtime for an asynchronous @@ -324,5 +298,4 @@ private: std::thread thread_; bool running_ = false; }; -} // namespace ripple -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp index 9ae9e44a3a..d1336b20d9 100644 --- a/src/xrpld/app/main/LoadManager.cpp +++ b/src/xrpld/app/main/LoadManager.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { LoadManager::LoadManager(Application& app, beast::Journal journal) : app_(app), journal_(journal), lastHeartbeat_(), armed_(false) @@ -45,8 +26,7 @@ LoadManager::~LoadManager() catch (std::exception const& ex) { // Swallow the exception in a destructor. - JLOG(journal_.warn()) - << "std::exception in ~LoadManager. " << ex.what(); + JLOG(journal_.warn()) << "std::exception in ~LoadManager. " << ex.what(); } } @@ -74,9 +54,7 @@ void LoadManager::start() { JLOG(journal_.debug()) << "Starting"; - XRPL_ASSERT( - !thread_.joinable(), - "ripple::LoadManager::start : thread not joinable"); + XRPL_ASSERT(!thread_.joinable(), "xrpl::LoadManager::start : thread not joinable"); thread_ = std::thread{&LoadManager::run, this}; } @@ -124,8 +102,7 @@ LoadManager::run() // Measure the amount of time we have been stalled, in seconds. using namespace std::chrono; - auto const timeSpentStalled = - duration_cast(steady_clock::now() - lastHeartbeat); + auto const timeSpentStalled = duration_cast(steady_clock::now() - lastHeartbeat); constexpr auto reportingIntervalSeconds = 10s; constexpr auto stallFatalLogMessageTimeLimit = 90s; @@ -138,23 +115,17 @@ LoadManager::run() { if (timeSpentStalled < stallFatalLogMessageTimeLimit) { - JLOG(journal_.warn()) - << "Server stalled for " << timeSpentStalled.count() - << " seconds."; + JLOG(journal_.warn()) << "Server stalled for " << timeSpentStalled.count() << " seconds."; if (app_.getJobQueue().isOverloaded()) { - JLOG(journal_.warn()) - << "JobQueue: " << app_.getJobQueue().getJson(0); + JLOG(journal_.warn()) << "JobQueue: " << app_.getJobQueue().getJson(0); } } else { - JLOG(journal_.fatal()) - << "Server stalled for " << timeSpentStalled.count() - << " seconds."; - JLOG(journal_.fatal()) - << "JobQueue: " << app_.getJobQueue().getJson(0); + JLOG(journal_.fatal()) << "Server stalled for " << timeSpentStalled.count() << " seconds."; + JLOG(journal_.fatal()) << "JobQueue: " << app_.getJobQueue().getJson(0); } } @@ -163,11 +134,9 @@ LoadManager::run() // as a LogicError if (timeSpentStalled >= stallLogicErrorTimeLimit) { - JLOG(journal_.fatal()) - << "LogicError: Fatal server stall detected. Stalled time: " - << timeSpentStalled.count() << "s"; - JLOG(journal_.fatal()) - << "JobQueue: " << app_.getJobQueue().getJson(0); + JLOG(journal_.fatal()) << "LogicError: Fatal server stall detected. Stalled time: " + << timeSpentStalled.count() << "s"; + JLOG(journal_.fatal()) << "JobQueue: " << app_.getJobQueue().getJson(0); LogicError("Fatal server stall detected"); } } @@ -176,8 +145,7 @@ LoadManager::run() bool change = false; if (app_.getJobQueue().isOverloaded()) { - JLOG(journal_.info()) << "Raising local fee (JQ overload): " - << app_.getJobQueue().getJson(0); + JLOG(journal_.info()) << "Raising local fee (JQ overload): " << app_.getJobQueue().getJson(0); change = app_.getFeeTrack().raiseLocalFee(); } else @@ -201,4 +169,4 @@ make_LoadManager(Application& app, beast::Journal journal) return std::unique_ptr{new LoadManager{app, journal}}; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/LoadManager.h b/src/xrpld/app/main/LoadManager.h index 166c40538c..c36afb1804 100644 --- a/src/xrpld/app/main/LoadManager.h +++ b/src/xrpld/app/main/LoadManager.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_LOADMANAGER_H_INCLUDED -#define RIPPLE_APP_MAIN_LOADMANAGER_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { class Application; @@ -113,6 +93,4 @@ private: std::unique_ptr make_LoadManager(Application& app, beast::Journal journal); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 3dff9d4d5f..7bdccd12a7 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include #include #include #include @@ -27,6 +7,7 @@ #include #include #include +#include #include #include @@ -72,7 +53,7 @@ namespace po = boost::program_options; -namespace ripple { +namespace xrpl { bool adjustDescriptorLimit(int needed, beast::Journal j) @@ -105,11 +86,10 @@ adjustDescriptorLimit(int needed, beast::Journal j) if (needed > available) { - j.fatal() << "Insufficient number of file descriptors: " << needed - << " are needed, but only " << available << " are available."; + j.fatal() << "Insufficient number of file descriptors: " << needed << " are needed, but only " << available + << " are available."; - std::cerr << "Insufficient number of file descriptors: " << needed - << " are needed, but only " << available + std::cerr << "Insufficient number of file descriptors: " << needed << " are needed, but only " << available << " are available.\n"; return false; @@ -122,69 +102,68 @@ adjustDescriptorLimit(int needed, beast::Journal j) void printHelp(po::options_description const& desc) { - std::cerr - << systemName() << "d [options] \n" - << desc << std::endl - << "Commands: \n" - " account_currencies []\n" - " account_info | []\n" - " account_lines |\"\" []\n" - " account_channels |\"\" []\n" - " account_objects []\n" - " account_offers | []\n" - " account_tx accountID [ledger_index_min [ledger_index_max " - "[limit " - "]]] [binary]\n" - " book_changes []\n" - " book_offers [ " - "[ [ []]]]]\n" - " can_delete [||now|always|never]\n" - " channel_authorize \n" - " channel_verify \n" - " connect []\n" - " consensus_info\n" - " deposit_authorized " - "[ [, ...]]\n" - " feature [ [accept|reject]]\n" - " fetch_info [clear]\n" - " gateway_balances [] [ [ " - " ]]\n" - " get_counts\n" - " json \n" - " ledger [|current|closed|validated] [full]\n" - " ledger_accept\n" - " ledger_cleaner\n" - " ledger_closed\n" - " ledger_current\n" - " ledger_request \n" - " log_level [[] ]\n" - " logrotate\n" - " manifest \n" - " peers\n" - " ping\n" - " random\n" - " peer_reservations_add []\n" - " peer_reservations_del \n" - " peer_reservations_list\n" - " ripple ...\n" - " ripple_path_find []\n" - " server_definitions []\n" - " server_info [counters]\n" - " server_state [counters]\n" - " sign [offline]\n" - " sign_for " - "[offline] []\n" - " stop\n" - " simulate [|] []\n" - " submit |[ ]\n" - " submit_multisigned \n" - " tx \n" - " validation_create [||]\n" - " validator_info\n" - " validators\n" - " validator_list_sites\n" - " version\n" - " wallet_propose []\n"; + std::cerr << systemName() << "d [options] \n" + << desc << std::endl + << "Commands: \n" + " account_currencies []\n" + " account_info | []\n" + " account_lines |\"\" []\n" + " account_channels |\"\" []\n" + " account_objects []\n" + " account_offers | []\n" + " account_tx accountID [ledger_index_min [ledger_index_max " + "[limit " + "]]] [binary]\n" + " book_changes []\n" + " book_offers [ " + "[ [ []]]]]\n" + " can_delete [||now|always|never]\n" + " channel_authorize \n" + " channel_verify \n" + " connect []\n" + " consensus_info\n" + " deposit_authorized " + "[ [, ...]]\n" + " feature [ [accept|reject]]\n" + " fetch_info [clear]\n" + " gateway_balances [] [ [ " + " ]]\n" + " get_counts\n" + " json \n" + " ledger [|current|closed|validated] [full]\n" + " ledger_accept\n" + " ledger_cleaner\n" + " ledger_closed\n" + " ledger_current\n" + " ledger_request \n" + " log_level [[] ]\n" + " logrotate\n" + " manifest \n" + " peers\n" + " ping\n" + " random\n" + " peer_reservations_add []\n" + " peer_reservations_del \n" + " peer_reservations_list\n" + " ripple ...\n" + " ripple_path_find []\n" + " server_definitions []\n" + " server_info [counters]\n" + " server_state [counters]\n" + " sign [offline]\n" + " sign_for " + "[offline] []\n" + " stop\n" + " simulate [|] []\n" + " submit |[ ]\n" + " submit_multisigned \n" + " tx \n" + " validation_create [||]\n" + " validator_info\n" + " validators\n" + " validator_list_sites\n" + " version\n" + " wallet_propose []\n"; } //------------------------------------------------------------------------------ @@ -207,8 +186,7 @@ public: std::for_each(v.begin(), v.end(), [this](std::string s) { boost::trim(s); if (selectors_.empty() || !s.empty()) - selectors_.emplace_back( - beast::unit_test::selector::automatch, s); + selectors_.emplace_back(beast::unit_test::selector::automatch, s); }); } @@ -246,9 +224,7 @@ anyMissing(Runner& runner, multi_selector const& pred) { auto const missing = pred.size() - runner.suites(); runner.add_failures(missing); - std::cout << "Failed: " << missing - << " filters did not match any existing test suites" - << std::endl; + std::cout << "Failed: " << missing << " filters did not match any existing test suites" << std::endl; return true; } return false; @@ -267,9 +243,9 @@ runUnitTests( char** argv) { using namespace beast::unit_test; - using namespace ripple::test; + using namespace xrpl::test; - ripple::test::envUseIPv4 = (!ipv6); + xrpl::test::envUseIPv4 = (!ipv6); if (!child && num_jobs == 1) { @@ -278,8 +254,7 @@ runUnitTests( multi_runner_child child_runner{num_jobs, quiet, log}; child_runner.arg(argument); multi_selector pred(pattern); - auto const any_failed = - child_runner.run_multi(pred) || anyMissing(child_runner, pred); + auto const any_failed = child_runner.run_multi(pred) || anyMissing(child_runner, pred); if (any_failed) return EXIT_FAILURE; @@ -300,9 +275,7 @@ runUnitTests( } for (std::size_t i = 0; i < num_jobs; ++i) - children.emplace_back( - boost::process::v1::exe = exe_name, - boost::process::v1::args = args); + children.emplace_back(boost::process::v1::exe = exe_name, boost::process::v1::args = args); int bad_child_exits = 0; int terminated_child_exits = 0; @@ -350,8 +323,7 @@ run(int argc, char** argv) { using namespace std; - beast::setCurrentThreadName( - "rippled: main " + BuildInfo::getVersionString()); + beast::setCurrentThreadName("xrpld-main"); po::variables_map vm; @@ -368,42 +340,27 @@ run(int argc, char** argv) // Set up option parsing. // po::options_description gen("General Options"); - gen.add_options()( - "conf", po::value(), "Specify the configuration file.")( - "debug", "Enable normally suppressed debug logging")( - "help,h", "Display this message.")( + gen.add_options()("conf", po::value(), "Specify the configuration file.")( + "debug", "Enable normally suppressed debug logging")("help,h", "Display this message.")( "newnodeid", "Generate a new node identity for this server.")( - "nodeid", - po::value(), - "Specify the node identity for this server.")( - "quorum", - po::value(), - "Override the minimum validation quorum.")( - "silent", "No output to the console after startup.")( - "standalone,a", "Run with no peers.")("verbose,v", "Verbose logging.") + "nodeid", po::value(), "Specify the node identity for this server.")( + "quorum", po::value(), "Override the minimum validation quorum.")( + "silent", "No output to the console after startup.")("standalone,a", "Run with no peers.")( + "verbose,v", "Verbose logging.") ("force_ledger_present_range", po::value(), "Specify the range of present ledgers for testing purposes. Min and " - "max values are comma separated.")( - "version", "Display the build version."); + "max values are comma separated.")("version", "Display the build version."); po::options_description data("Ledger/Data Options"); data.add_options()("import", importText.c_str())( - "ledger", - po::value(), - "Load the specified ledger and start from the value given.")( - "ledgerfile", - po::value(), - "Load the specified ledger file.")( - "load", "Load the current ledger from the local DB.")( - "net", "Get the initial ledger from the network.")( + "ledger", po::value(), "Load the specified ledger and start from the value given.")( + "ledgerfile", po::value(), "Load the specified ledger file.")( + "load", "Load the current ledger from the local DB.")("net", "Get the initial ledger from the network.")( "replay", "Replay a ledger close.")( - "trap_tx_hash", - po::value(), - "Trap a specific transaction during replay.")( - "start", "Start from a fresh Ledger.")( - "vacuum", "VACUUM the transaction db.")( + "trap_tx_hash", po::value(), "Trap a specific transaction during replay.")( + "start", "Start from a fresh Ledger.")("vacuum", "VACUUM the transaction db.")( "valid", "Consider the initial ledger a valid network ledger."); po::options_description rpc("RPC Client Options"); @@ -438,16 +395,12 @@ run(int argc, char** argv) "is made available to each suite that runs. Interpretation of the " "argument is handled individually by any suite that accesses it -- " "as such, it typically only make sense to provide this when running " - "a single suite.")( - "unittest-ipv6", - "Use IPv6 localhost when running unittests (default is IPv4).")( + "a single suite.")("unittest-ipv6", "Use IPv6 localhost when running unittests (default is IPv4).")( "unittest-log", "Force unit test log message output. Only useful in combination with " "--quiet, in which case log messages will print but suite/case names " "will not.")( - "unittest-jobs", - po::value(), - "Number of unittest jobs to run in parallel (child processes)."); + "unittest-jobs", po::value(), "Number of unittest jobs to run in parallel (child processes)."); #endif // ENABLE_TESTS // These are hidden options, not intended to be shown in the usage/help @@ -461,11 +414,9 @@ run(int argc, char** argv) "purpose, " "so this option is not needed for users") #ifdef ENABLE_TESTS - ("unittest-child", - "For internal use only when spawning child unit test processes.") + ("unittest-child", "For internal use only when spawning child unit test processes.") #else - ("unittest", "Disabled in this build.")( - "unittest-child", "Disabled in this build.") + ("unittest", "Disabled in this build.")("unittest-child", "Disabled in this build.") #endif // ENABLE_TESTS ("fg", "Deprecated: server always in foreground mode."); @@ -517,8 +468,7 @@ run(int argc, char** argv) if (vm.count("version")) { - std::cout << "rippled version " << BuildInfo::getVersionString() - << std::endl; + std::cout << "rippled version " << BuildInfo::getVersionString() << std::endl; #ifdef GIT_COMMIT_HASH std::cout << "Git commit hash: " << GIT_COMMIT_HASH << std::endl; #endif @@ -580,15 +530,10 @@ run(int argc, char** argv) auto config = std::make_unique(); - auto configFile = - vm.count("conf") ? vm["conf"].as() : std::string(); + auto configFile = vm.count("conf") ? vm["conf"].as() : std::string(); // config file, quiet flag. - config->setup( - configFile, - bool(vm.count("quiet")), - bool(vm.count("silent")), - bool(vm.count("standalone"))); + config->setup(configFile, bool(vm.count("quiet")), bool(vm.count("silent")), bool(vm.count("standalone"))); if (vm.count("vacuum")) { @@ -606,8 +551,7 @@ run(int argc, char** argv) } catch (std::exception const& e) { - std::cerr << "exception " << e.what() << " in function " << __func__ - << std::endl; + std::cerr << "exception " << e.what() << " in function " << __func__ << std::endl; return -1; } @@ -621,9 +565,7 @@ run(int argc, char** argv) auto const r = [&vm]() -> std::vector { std::vector strVec; boost::split( - strVec, - vm["force_ledger_present_range"].as(), - boost::algorithm::is_any_of(",")); + strVec, vm["force_ledger_present_range"].as(), boost::algorithm::is_any_of(",")); std::vector result; for (auto& s : strVec) { @@ -638,15 +580,13 @@ run(int argc, char** argv) { if (r[0] > r[1]) { - throw std::runtime_error( - "Invalid force_ledger_present_range parameter"); + throw std::runtime_error("Invalid force_ledger_present_range parameter"); } config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]); } else { - throw std::runtime_error( - "Invalid force_ledger_present_range parameter"); + throw std::runtime_error("Invalid force_ledger_present_range parameter"); } } catch (std::exception const& e) @@ -661,7 +601,7 @@ run(int argc, char** argv) if (vm.count("start")) { - config->START_UP = Config::FRESH; + config->START_UP = StartUpType::FRESH; } if (vm.count("import")) @@ -672,7 +612,7 @@ run(int argc, char** argv) config->START_LEDGER = vm["ledger"].as(); if (vm.count("replay")) { - config->START_UP = Config::REPLAY; + config->START_UP = StartUpType::REPLAY; if (vm.count("trap_tx_hash")) { uint256 tmp = {}; @@ -691,36 +631,33 @@ run(int argc, char** argv) } } else - config->START_UP = Config::LOAD; + config->START_UP = StartUpType::LOAD; } else if (vm.count("ledgerfile")) { config->START_LEDGER = vm["ledgerfile"].as(); - config->START_UP = Config::LOAD_FILE; + config->START_UP = StartUpType::LOAD_FILE; } else if (vm.count("load") || config->FAST_LOAD) { - config->START_UP = Config::LOAD; + config->START_UP = StartUpType::LOAD; } if (vm.count("trap_tx_hash") && vm.count("replay") == 0) { - std::cerr << "Cannot use trap option without replay option" - << std::endl; + std::cerr << "Cannot use trap option without replay option" << std::endl; return -1; } if (vm.count("net") && !config->FAST_LOAD) { - if ((config->START_UP == Config::LOAD) || - (config->START_UP == Config::REPLAY)) + if ((config->START_UP == StartUpType::LOAD) || (config->START_UP == StartUpType::REPLAY)) { - std::cerr << "Net and load/replay options are incompatible" - << std::endl; + std::cerr << "Net and load/replay options are incompatible" << std::endl; return -1; } - config->START_UP = Config::NETWORK; + config->START_UP = StartUpType::NETWORK; } if (vm.count("valid")) @@ -732,12 +669,10 @@ run(int argc, char** argv) // happen after the config file is loaded. if (vm.count("rpc_ip")) { - auto endpoint = beast::IP::Endpoint::from_string_checked( - vm["rpc_ip"].as()); + auto endpoint = beast::IP::Endpoint::from_string_checked(vm["rpc_ip"].as()); if (!endpoint) { - std::cerr << "Invalid rpc_ip = " << vm["rpc_ip"].as() - << "\n"; + std::cerr << "Invalid rpc_ip = " << vm["rpc_ip"].as() << "\n"; return -1; } @@ -749,8 +684,7 @@ run(int argc, char** argv) std::cerr << "WARNING: using deprecated rpc_port param.\n"; try { - endpoint = - endpoint->at_port(vm["rpc_port"].as()); + endpoint = endpoint->at_port(vm["rpc_port"].as()); if (endpoint->port() == 0) throw std::domain_error("0"); } @@ -779,8 +713,7 @@ run(int argc, char** argv) } catch (std::exception const& e) { - std::cerr << "Invalid value specified for --quorum (" << e.what() - << ")\n"; + std::cerr << "Invalid value specified for --quorum (" << e.what() << ")\n"; return -1; } } @@ -803,13 +736,12 @@ run(int argc, char** argv) // say 1.7 or higher if (config->had_trailing_comments()) { - JLOG(logs->journal("Application").warn()) - << "Trailing comments were seen in your config file. " - << "The treatment of inline/trailing comments has changed " - "recently. " - << "Any `#` characters NOT intended to delimit comments should " - "be " - << "preceded by a \\"; + JLOG(logs->journal("Application").warn()) << "Trailing comments were seen in your config file. " + << "The treatment of inline/trailing comments has changed " + "recently. " + << "Any `#` characters NOT intended to delimit comments should " + "be " + << "preceded by a \\"; } // We want at least 1024 file descriptors. We'll @@ -820,16 +752,14 @@ run(int argc, char** argv) if (vm.count("debug")) setDebugLogSink(logs->makeSink("Debug", beast::severities::kTrace)); - auto app = make_Application( - std::move(config), std::move(logs), std::make_unique()); + auto app = make_Application(std::move(config), std::move(logs), std::make_unique()); if (!app->setup(vm)) return -1; // With our configuration parsed, ensure we have // enough file descriptors available: - if (!adjustDescriptorLimit( - app->fdRequired(), app->logs().journal("Application"))) + if (!adjustDescriptorLimit(app->fdRequired(), app->logs().journal("Application"))) return -1; // Start the server @@ -843,12 +773,11 @@ run(int argc, char** argv) // We have an RPC command to process: beast::setCurrentThreadName("rippled: rpc"); - return RPCCall::fromCommandLine( - *config, vm["parameters"].as>(), *logs); + return RPCCall::fromCommandLine(*config, vm["parameters"].as>(), *logs); // LCOV_EXCL_STOP } -} // namespace ripple +} // namespace xrpl int main(int argc, char** argv) @@ -873,5 +802,5 @@ main(int argc, char** argv) atexit(&google::protobuf::ShutdownProtobufLibrary); - return ripple::run(argc, argv); + return xrpl::run(argc, argv); } diff --git a/src/xrpld/app/main/NodeIdentity.cpp b/src/xrpld/app/main/NodeIdentity.cpp index a1da64a0f9..3019caeb31 100644 --- a/src/xrpld/app/main/NodeIdentity.cpp +++ b/src/xrpld/app/main/NodeIdentity.cpp @@ -1,34 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -#include #include #include -namespace ripple { +#include + +namespace xrpl { std::pair -getNodeIdentity( - Application& app, - boost::program_options::variables_map const& cmdline) +getNodeIdentity(Application& app, boost::program_options::variables_map const& cmdline) { std::optional seed; @@ -41,12 +21,10 @@ getNodeIdentity( } else if (app.config().exists(SECTION_NODE_SEED)) { - seed = parseBase58( - app.config().section(SECTION_NODE_SEED).lines().front()); + seed = parseBase58(app.config().section(SECTION_NODE_SEED).lines().front()); if (!seed) - Throw("Invalid [" SECTION_NODE_SEED - "] in configuration file"); + Throw("Invalid [" SECTION_NODE_SEED "] in configuration file"); } if (seed) @@ -65,4 +43,4 @@ getNodeIdentity( return getNodeIdentity(*db); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/NodeIdentity.h b/src/xrpld/app/main/NodeIdentity.h index 3616255c13..bebd5c261d 100644 --- a/src/xrpld/app/main/NodeIdentity.h +++ b/src/xrpld/app/main/NodeIdentity.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_NODEIDENTITY_H_INCLUDED -#define RIPPLE_APP_MAIN_NODEIDENTITY_H_INCLUDED +#pragma once #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { /** The cryptographic credentials identifying this server instance. @@ -35,10 +15,6 @@ namespace ripple { @param cmdline The command line parameters passed into the application. */ std::pair -getNodeIdentity( - Application& app, - boost::program_options::variables_map const& cmdline); +getNodeIdentity(Application& app, boost::program_options::variables_map const& cmdline); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/NodeStoreScheduler.cpp b/src/xrpld/app/main/NodeStoreScheduler.cpp index 6ef2ff3ca6..1b3ff4ab03 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.cpp +++ b/src/xrpld/app/main/NodeStoreScheduler.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { NodeStoreScheduler::NodeStoreScheduler(JobQueue& jobQueue) : jobQueue_(jobQueue) { @@ -31,9 +12,7 @@ NodeStoreScheduler::scheduleTask(NodeStore::Task& task) if (jobQueue_.isStopped()) return; - if (!jobQueue_.addJob(jtWRITE, "NodeObject::store", [&task]() { - task.performScheduledTask(); - })) + if (!jobQueue_.addJob(jtWRITE, "NObjStore", [&task]() { task.performScheduledTask(); })) { // Job not added, presumably because we're shutting down. // Recover by executing the task synchronously. @@ -48,10 +27,7 @@ NodeStoreScheduler::onFetch(NodeStore::FetchReport const& report) return; jobQueue_.addLoadEvents( - report.fetchType == NodeStore::FetchType::async ? jtNS_ASYNC_READ - : jtNS_SYNC_READ, - 1, - report.elapsed); + report.fetchType == NodeStore::FetchType::async ? jtNS_ASYNC_READ : jtNS_SYNC_READ, 1, report.elapsed); } void @@ -63,4 +39,4 @@ NodeStoreScheduler::onBatchWrite(NodeStore::BatchWriteReport const& report) jobQueue_.addLoadEvents(jtNS_WRITE, report.writeCount, report.elapsed); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/main/NodeStoreScheduler.h b/src/xrpld/app/main/NodeStoreScheduler.h index ffd024fe32..19e8d9d212 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.h +++ b/src/xrpld/app/main/NodeStoreScheduler.h @@ -1,30 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED -#define RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED - -#include +#pragma once +#include #include -namespace ripple { +namespace xrpl { /** A NodeStore::Scheduler which uses the JobQueue. */ class NodeStoreScheduler : public NodeStore::Scheduler @@ -43,6 +22,4 @@ private: JobQueue& jobQueue_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/main/Tuning.h b/src/xrpld/app/main/Tuning.h index c6ca81643e..0f612b1b1c 100644 --- a/src/xrpld/app/main/Tuning.h +++ b/src/xrpld/app/main/Tuning.h @@ -1,34 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MAIN_TUNING_H_INCLUDED -#define RIPPLE_APP_MAIN_TUNING_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { constexpr std::size_t fullBelowTargetSize = 524288; constexpr std::chrono::seconds fullBelowExpiration = std::chrono::minutes{10}; constexpr std::size_t maxPoppedTransactions = 10; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h index 8cc39468b1..cde485f5dc 100644 --- a/src/xrpld/app/misc/AMMHelpers.h +++ b/src/xrpld/app/misc/AMMHelpers.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED -#define RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED +#pragma once #include #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -56,10 +36,7 @@ enum class IsDeposit : bool { No = false, Yes = true }; * @return LP Tokens as IOU */ STAmount -ammLPTokens( - STAmount const& asset1, - STAmount const& asset2, - Issue const& lptIssue); +ammLPTokens(STAmount const& asset1, STAmount const& asset2, Issue const& lptIssue); /** Calculate LP Tokens given asset's deposit amount. * @param asset1Balance current AMM asset1 balance @@ -83,11 +60,7 @@ lpTokensOut( * @return */ STAmount -ammAssetIn( - STAmount const& asset1Balance, - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - std::uint16_t tfee); +ammAssetIn(STAmount const& asset1Balance, STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee); /** Calculate LP Tokens given asset's withdraw amount. Return 0 * if can't calculate. @@ -112,11 +85,7 @@ lpTokensIn( * @return calculated asset amount */ STAmount -ammAssetOut( - STAmount const& assetBalance, - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - std::uint16_t tfee); +ammAssetOut(STAmount const& assetBalance, STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee); /** Check if the relative distance between the qualities * is within the requested distance. @@ -126,10 +95,7 @@ ammAssetOut( * @return true if within dist, false otherwise */ inline bool -withinRelativeDistance( - Quality const& calcQuality, - Quality const& reqQuality, - Number const& dist) +withinRelativeDistance(Quality const& calcQuality, Quality const& reqQuality, Number const& dist) { if (calcQuality == reqQuality) return true; @@ -193,10 +159,7 @@ solveQuadraticEqSmallest(Number const& a, Number const& b, Number const& c); */ template std::optional> -getAMMOfferStartWithTakerGets( - TAmounts const& pool, - Quality const& targetQuality, - std::uint16_t const& tfee) +getAMMOfferStartWithTakerGets(TAmounts const& pool, Quality const& targetQuality, std::uint16_t const& tfee) { if (targetQuality.rate() == beast::zero) return std::nullopt; @@ -205,15 +168,13 @@ getAMMOfferStartWithTakerGets( auto const f = feeMult(tfee); auto const a = 1; auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out; - auto const c = - pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate(); + auto const c = pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate(); auto nTakerGets = solveQuadraticEqSmallest(a, b, c); if (!nTakerGets || *nTakerGets <= 0) return std::nullopt; // LCOV_EXCL_LINE - auto const nTakerGetsConstraint = - pool.out - pool.in / (targetQuality.rate() * f); + auto const nTakerGetsConstraint = pool.out - pool.in / (targetQuality.rate() * f); if (nTakerGetsConstraint <= 0) return std::nullopt; @@ -224,16 +185,13 @@ getAMMOfferStartWithTakerGets( auto getAmounts = [&pool, &tfee](Number const& nTakerGetsProposed) { // Round downward to minimize the offer and to maximize the quality. // This has the most impact when takerGets is XRP. - auto const takerGets = toAmount( - getIssue(pool.out), nTakerGetsProposed, Number::downward); - return TAmounts{ - swapAssetOut(pool, takerGets, tfee), takerGets}; + auto const takerGets = toAmount(getIssue(pool.out), nTakerGetsProposed, Number::downward); + return TAmounts{swapAssetOut(pool, takerGets, tfee), takerGets}; }; // Try to reduce the offer size to improve the quality. // The quality might still not match the targetQuality for a tiny offer. - if (auto const amounts = getAmounts(*nTakerGets); - Quality{amounts} < targetQuality) + if (auto const amounts = getAmounts(*nTakerGets); Quality{amounts} < targetQuality) return getAmounts(detail::reduceOffer(amounts.out)); else return amounts; @@ -264,10 +222,7 @@ getAMMOfferStartWithTakerGets( */ template std::optional> -getAMMOfferStartWithTakerPays( - TAmounts const& pool, - Quality const& targetQuality, - std::uint16_t tfee) +getAMMOfferStartWithTakerPays(TAmounts const& pool, Quality const& targetQuality, std::uint16_t tfee) { if (targetQuality.rate() == beast::zero) return std::nullopt; @@ -276,15 +231,13 @@ getAMMOfferStartWithTakerPays( auto const f = feeMult(tfee); auto const& a = f; auto const b = pool.in * (1 + f); - auto const c = - pool.in * pool.in - pool.in * pool.out * targetQuality.rate(); + auto const c = pool.in * pool.in - pool.in * pool.out * targetQuality.rate(); auto nTakerPays = solveQuadraticEqSmallest(a, b, c); if (!nTakerPays || nTakerPays <= 0) return std::nullopt; // LCOV_EXCL_LINE - auto const nTakerPaysConstraint = - pool.out * targetQuality.rate() - pool.in / f; + auto const nTakerPaysConstraint = pool.out * targetQuality.rate() - pool.in / f; if (nTakerPaysConstraint <= 0) return std::nullopt; @@ -295,16 +248,13 @@ getAMMOfferStartWithTakerPays( auto getAmounts = [&pool, &tfee](Number const& nTakerPaysProposed) { // Round downward to minimize the offer and to maximize the quality. // This has the most impact when takerPays is XRP. - auto const takerPays = toAmount( - getIssue(pool.in), nTakerPaysProposed, Number::downward); - return TAmounts{ - takerPays, swapAssetIn(pool, takerPays, tfee)}; + auto const takerPays = toAmount(getIssue(pool.in), nTakerPaysProposed, Number::downward); + return TAmounts{takerPays, swapAssetIn(pool, takerPays, tfee)}; }; // Try to reduce the offer size to improve the quality. // The quality might still not match the targetQuality for a tiny offer. - if (auto const amounts = getAmounts(*nTakerPays); - Quality{amounts} < targetQuality) + if (auto const amounts = getAmounts(*nTakerPays); Quality{amounts} < targetQuality) return getAmounts(detail::reduceOffer(amounts.in)); else return amounts; @@ -346,61 +296,48 @@ changeSpotPriceQuality( auto const f = feeMult(tfee); // 1 - fee auto const& a = f; auto const b = pool.in * (1 + f); - Number const c = - pool.in * pool.in - pool.in * pool.out * quality.rate(); + Number const c = pool.in * pool.in - pool.in * pool.out * quality.rate(); if (auto const res = b * b - 4 * a * c; res < 0) return std::nullopt; // LCOV_EXCL_LINE - else if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a); - nTakerPaysPropose > 0) + else if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a); nTakerPaysPropose > 0) { auto const nTakerPays = [&]() { // The fee might make the AMM offer quality less than CLOB // quality. Therefore, AMM offer has to satisfy this constraint: // o / i >= q. Substituting o with swapAssetIn() gives: i <= O / // q - I / (1 - fee). - auto const nTakerPaysConstraint = - pool.out * quality.rate() - pool.in / f; + auto const nTakerPaysConstraint = pool.out * quality.rate() - pool.in / f; if (nTakerPaysPropose > nTakerPaysConstraint) return nTakerPaysConstraint; return nTakerPaysPropose; }(); if (nTakerPays <= 0) { - JLOG(j.trace()) - << "changeSpotPriceQuality calc failed: " - << to_string(pool.in) << " " << to_string(pool.out) << " " - << quality << " " << tfee; + JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " " + << to_string(pool.out) << " " << quality << " " << tfee; return std::nullopt; } - auto const takerPays = - toAmount(getIssue(pool.in), nTakerPays, Number::upward); + auto const takerPays = toAmount(getIssue(pool.in), nTakerPays, Number::upward); // should not fail - if (auto const amounts = - TAmounts{ - takerPays, swapAssetIn(pool, takerPays, tfee)}; - Quality{amounts} < quality && - !withinRelativeDistance( - Quality{amounts}, quality, Number(1, -7))) + if (auto const amounts = TAmounts{takerPays, swapAssetIn(pool, takerPays, tfee)}; + Quality{amounts} < quality && !withinRelativeDistance(Quality{amounts}, quality, Number(1, -7))) { - JLOG(j.error()) - << "changeSpotPriceQuality failed: " << to_string(pool.in) - << " " << to_string(pool.out) << " " - << " " << quality << " " << tfee << " " - << to_string(amounts.in) << " " << to_string(amounts.out); + JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " " << to_string(pool.out) + << " " + << " " << quality << " " << tfee << " " << to_string(amounts.in) << " " + << to_string(amounts.out); Throw("changeSpotPriceQuality failed"); } else { - JLOG(j.trace()) - << "changeSpotPriceQuality succeeded: " - << to_string(pool.in) << " " << to_string(pool.out) << " " - << " " << quality << " " << tfee << " " - << to_string(amounts.in) << " " << to_string(amounts.out); + JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " " + << to_string(pool.out) << " " + << " " << quality << " " << tfee << " " << to_string(amounts.in) << " " + << to_string(amounts.out); return amounts; } } - JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " - << to_string(pool.in) << " " << to_string(pool.out) + JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " " << to_string(pool.out) << " " << quality << " " << tfee; return std::nullopt; } @@ -414,26 +351,20 @@ changeSpotPriceQuality( }(); if (!amounts) { - JLOG(j.trace()) << "changeSpotPrice calc failed: " << to_string(pool.in) - << " " << to_string(pool.out) << " " << quality << " " - << tfee << std::endl; + JLOG(j.trace()) << "changeSpotPrice calc failed: " << to_string(pool.in) << " " << to_string(pool.out) << " " + << quality << " " << tfee << std::endl; return std::nullopt; } if (Quality{*amounts} < quality) { - JLOG(j.error()) << "changeSpotPriceQuality failed: " - << to_string(pool.in) << " " << to_string(pool.out) - << " " << quality << " " << tfee << " " - << to_string(amounts->in) << " " - << to_string(amounts->out); + JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " " << to_string(pool.out) << " " + << quality << " " << tfee << " " << to_string(amounts->in) << " " << to_string(amounts->out); return std::nullopt; } - JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " - << to_string(pool.in) << " " << to_string(pool.out) << " " - << " " << quality << " " << tfee << " " - << to_string(amounts->in) << " " << to_string(amounts->out); + JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " " << to_string(pool.out) << " " + << " " << quality << " " << tfee << " " << to_string(amounts->in) << " " << to_string(amounts->out); return amounts; } @@ -461,13 +392,9 @@ changeSpotPriceQuality( */ template TOut -swapAssetIn( - TAmounts const& pool, - TIn const& assetIn, - std::uint16_t tfee) +swapAssetIn(TAmounts const& pool, TIn const& assetIn, std::uint16_t tfee) { - if (auto const& rules = getCurrentTransactionRules(); - rules && rules->enabled(fixAMMv1_1)) + if (auto const& rules = getCurrentTransactionRules(); rules && rules->enabled(fixAMMv1_1)) { // set rounding to always favor the amm. Clip to zero. // calculate: @@ -517,8 +444,7 @@ swapAssetIn( { return toAmount( getIssue(pool.out), - pool.out - - (pool.in * pool.out) / (pool.in + assetIn * feeMult(tfee)), + pool.out - (pool.in * pool.out) / (pool.in + assetIn * feeMult(tfee)), Number::downward); } } @@ -534,13 +460,9 @@ swapAssetIn( */ template TIn -swapAssetOut( - TAmounts const& pool, - TOut const& assetOut, - std::uint16_t tfee) +swapAssetOut(TAmounts const& pool, TOut const& assetOut, std::uint16_t tfee) { - if (auto const& rules = getCurrentTransactionRules(); - rules && rules->enabled(fixAMMv1_1)) + if (auto const& rules = getCurrentTransactionRules(); rules && rules->enabled(fixAMMv1_1)) { // set rounding to always favor the amm. Clip to zero. // calculate: @@ -590,8 +512,7 @@ swapAssetOut( { return toAmount( getIssue(pool.in), - ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) / - feeMult(tfee), + ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) / feeMult(tfee), Number::upward); } } @@ -613,10 +534,7 @@ square(Number const& n); * @param isDeposit Yes if deposit, No if withdraw */ STAmount -adjustLPTokens( - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - IsDeposit isDeposit); +adjustLPTokens(STAmount const& lptAMMBalance, STAmount const& lpTokens, IsDeposit isDeposit); /** Calls adjustLPTokens() and adjusts deposit or withdraw amounts if * the adjusted LP tokens are less than the provided LP tokens. @@ -675,11 +593,7 @@ getAssetRounding(IsDeposit isDeposit) */ template STAmount -getRoundedAsset( - Rules const& rules, - STAmount const& balance, - A const& frac, - IsDeposit isDeposit) +getRoundedAsset(Rules const& rules, STAmount const& balance, A const& frac, IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) { @@ -717,11 +631,7 @@ getRoundedAsset( * digits) when adding the lptokens to the balance. */ STAmount -getRoundedLPTokens( - Rules const& rules, - STAmount const& balance, - Number const& frac, - IsDeposit isDeposit); +getRoundedLPTokens(Rules const& rules, STAmount const& balance, Number const& frac, IsDeposit isDeposit); /** Round AMM single deposit/withdrawal LPToken amount. * The lambda's are used to delay evaluation until the function is executed @@ -774,12 +684,6 @@ adjustAssetOutByTokens( * is used to adjust equal deposit/withdraw amount. */ Number -adjustFracByTokens( - Rules const& rules, - STAmount const& lptAMMBalance, - STAmount const& tokens, - Number const& frac); +adjustFracByTokens(Rules const& rules, STAmount const& lptAMMBalance, STAmount const& tokens, Number const& frac); -} // namespace ripple - -#endif // RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/misc/AMMUtils.h b/src/xrpld/app/misc/AMMUtils.h index d89085b116..c97397a141 100644 --- a/src/xrpld/app/misc/AMMUtils.h +++ b/src/xrpld/app/misc/AMMUtils.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_AMMUTILS_H_INCLUDED -#define RIPPLE_APP_MISC_AMMUTILS_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include #include -namespace ripple { +namespace xrpl { class ReadView; class ApplyView; @@ -70,39 +50,25 @@ ammLPHolds( beast::Journal const j); STAmount -ammLPHolds( - ReadView const& view, - SLE const& ammSle, - AccountID const& lpAccount, - beast::Journal const j); +ammLPHolds(ReadView const& view, SLE const& ammSle, AccountID const& lpAccount, beast::Journal const j); /** Get AMM trading fee for the given account. The fee is discounted * if the account is the auction slot owner or one of the slot's authorized * accounts. */ std::uint16_t -getTradingFee( - ReadView const& view, - SLE const& ammSle, - AccountID const& account); +getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account); /** Returns total amount held by AMM for the given token. */ STAmount -ammAccountHolds( - ReadView const& view, - AccountID const& ammAccountID, - Issue const& issue); +ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Issue const& issue); /** Delete trustlines to AMM. If all trustlines are deleted then * AMM object and account are deleted. Otherwise tecIMPCOMPLETE is returned. */ TER -deleteAMMAccount( - Sandbox& view, - Issue const& asset, - Issue const& asset2, - beast::Journal j); +deleteAMMAccount(Sandbox& view, Issue const& asset, Issue const& asset2, beast::Journal j); /** Initialize Auction and Voting slots and set the trading/discounted fee. */ @@ -119,10 +85,7 @@ initializeFeeAuctionVote( * for instance Liquidity Provider has more than one LPToken trustline. */ Expected -isOnlyLiquidityProvider( - ReadView const& view, - Issue const& ammIssue, - AccountID const& lpAccount); +isOnlyLiquidityProvider(ReadView const& view, Issue const& ammIssue, AccountID const& lpAccount); /** Due to rounding, the LPTokenBalance of the last LP might * not match the LP's trustline balance. If it's within the tolerance, @@ -135,6 +98,4 @@ verifyAndAdjustLPTokenBalance( std::shared_ptr& ammSle, AccountID const& account); -} // namespace ripple - -#endif // RIPPLE_APP_MISC_AMMUTILS_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/misc/AmendmentTable.h b/src/xrpld/app/misc/AmendmentTable.h index deb0386236..94ac9608a7 100644 --- a/src/xrpld/app/misc/AmendmentTable.h +++ b/src/xrpld/app/misc/AmendmentTable.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_AMENDMENTTABLE_H_INCLUDED -#define RIPPLE_APP_MISC_AMENDMENTTABLE_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { /** The amendment table stores the list of enabled and potential amendments. Individuals amendments are voted on by validators during the consensus @@ -41,8 +21,7 @@ public: struct FeatureInfo { FeatureInfo() = delete; - FeatureInfo(std::string const& n, uint256 const& f, VoteBehavior v) - : name(n), feature(f), vote(v) + FeatureInfo(std::string const& n, uint256 const& f, VoteBehavior v) : name(n), feature(f), vote(v) { } @@ -90,8 +69,7 @@ public: /** Called when a new fully-validated ledger is accepted. */ void - doValidatedLedger( - std::shared_ptr const& lastValidatedLedger) + doValidatedLedger(std::shared_ptr const& lastValidatedLedger) { if (needValidatedLedger(lastValidatedLedger->seq())) doValidatedLedger( @@ -162,27 +140,23 @@ public: // Inject appropriate pseudo-transactions for (auto const& it : actions) { - STTx amendTx( - ttAMENDMENT, - [&it, seq = lastClosedLedger->seq() + 1](auto& obj) { - obj.setAccountID(sfAccount, AccountID()); - obj.setFieldH256(sfAmendment, it.first); - obj.setFieldU32(sfLedgerSequence, seq); + STTx amendTx(ttAMENDMENT, [&it, seq = lastClosedLedger->seq() + 1](auto& obj) { + obj.setAccountID(sfAccount, AccountID()); + obj.setFieldH256(sfAmendment, it.first); + obj.setFieldU32(sfLedgerSequence, seq); - if (it.second != 0) - obj.setFieldU32(sfFlags, it.second); - }); + if (it.second != 0) + obj.setFieldU32(sfFlags, it.second); + }); Serializer s; amendTx.add(s); - JLOG(j.debug()) << "Amendments: Adding pseudo-transaction: " - << amendTx.getTransactionID() << ": " + JLOG(j.debug()) << "Amendments: Adding pseudo-transaction: " << amendTx.getTransactionID() << ": " << strHex(s.slice()) << ": " << amendTx; initialPosition->addGiveItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(amendTx.getTransactionID(), s.slice())); + SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(amendTx.getTransactionID(), s.slice())); } } }; @@ -196,6 +170,4 @@ make_AmendmentTable( Section const& vetoed, beast::Journal journal); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/CanonicalTXSet.cpp b/src/xrpld/app/misc/CanonicalTXSet.cpp index 41ee1988e1..6e6102afe7 100644 --- a/src/xrpld/app/misc/CanonicalTXSet.cpp +++ b/src/xrpld/app/misc/CanonicalTXSet.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { bool operator<(CanonicalTXSet::Key const& lhs, CanonicalTXSet::Key const& rhs) @@ -52,10 +33,7 @@ void CanonicalTXSet::insert(std::shared_ptr const& txn) { map_.insert(std::make_pair( - Key(accountKey(txn->getAccountID(sfAccount)), - txn->getSeqProxy(), - txn->getTransactionID()), - txn)); + Key(accountKey(txn->getAccountID(sfAccount)), txn->getSeqProxy(), txn->getTransactionID()), txn)); } std::shared_ptr @@ -78,10 +56,8 @@ CanonicalTXSet::popAcctTransaction(std::shared_ptr const& tx) auto const seqProxy = tx->getSeqProxy(); Key const after(effectiveAccount, seqProxy, beast::zero); auto const itrNext{map_.lower_bound(after)}; - if (itrNext != map_.end() && - itrNext->first.getAccount() == effectiveAccount && - (!itrNext->second->getSeqProxy().isSeq() || - itrNext->second->getSeqProxy().value() == seqProxy.value() + 1)) + if (itrNext != map_.end() && itrNext->first.getAccount() == effectiveAccount && + (!itrNext->second->getSeqProxy().isSeq() || itrNext->second->getSeqProxy().value() == seqProxy.value() + 1)) { result = std::move(itrNext->second); map_.erase(itrNext); @@ -90,4 +66,4 @@ CanonicalTXSet::popAcctTransaction(std::shared_ptr const& tx) return result; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/CanonicalTXSet.h b/src/xrpld/app/misc/CanonicalTXSet.h index b061ff10dd..45f58b5701 100644 --- a/src/xrpld/app/misc/CanonicalTXSet.h +++ b/src/xrpld/app/misc/CanonicalTXSet.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_CANONICALTXSET_H_INCLUDED -#define RIPPLE_APP_MISC_CANONICALTXSET_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { /** Holds transactions which were deferred to the next pass of consensus. @@ -105,8 +85,7 @@ private: accountKey(AccountID const& account); public: - using const_iterator = - std::map>::const_iterator; + using const_iterator = std::map>::const_iterator; public: explicit CanonicalTXSet(LedgerHash const& saltHash) : salt_(saltHash) @@ -175,6 +154,4 @@ private: uint256 salt_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/DelegateUtils.h b/src/xrpld/app/misc/DelegateUtils.h index b51d808d66..78ccc46d0b 100644 --- a/src/xrpld/app/misc/DelegateUtils.h +++ b/src/xrpld/app/misc/DelegateUtils.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DELEGATEUTILS_H_INCLUDED -#define RIPPLE_APP_MISC_DELEGATEUTILS_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { /** * Check if the delegate account has permission to execute the transaction. @@ -52,6 +32,4 @@ loadGranularPermission( TxType const& type, std::unordered_set& granularPermissions); -} // namespace ripple - -#endif // RIPPLE_APP_MISC_DELEGATEUTILS_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/misc/DeliverMax.h b/src/xrpld/app/misc/DeliverMax.h index 815bf52189..1b4241f091 100644 --- a/src/xrpld/app/misc/DeliverMax.h +++ b/src/xrpld/app/misc/DeliverMax.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DELIVERMAX_H_INCLUDED -#define RIPPLE_APP_MISC_DELIVERMAX_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ namespace Json { class Value; } -namespace ripple { +namespace xrpl { namespace RPC { @@ -45,6 +25,4 @@ insertDeliverMax(Json::Value& tx_json, TxType txnType, unsigned int apiVersion); /** @} */ } // namespace RPC -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/FeeEscalation.md b/src/xrpld/app/misc/FeeEscalation.md index 468ab2b528..7843620320 100644 --- a/src/xrpld/app/misc/FeeEscalation.md +++ b/src/xrpld/app/misc/FeeEscalation.md @@ -237,7 +237,7 @@ often coincides with new ledgers with zero transactions. recover if the problem is temporary. These exact values were chosen experimentally, and can easily change in the future. - _Minimum `lastLedgerMedianFeeLevel`_. The value of 500 was chosen to - ensure that the first escalated fee was more significant and noticable + ensure that the first escalated fee was more significant and noticeable than what the default would allow. This exact value was chosen experimentally, and can easily change in the future. - _Transaction queue size limit_. The limit is computed based on the @@ -291,7 +291,7 @@ single-singed reference transaction. It is up to the user to compute the necessary fees for other types of transactions. (E.g. multiply all drop values by 5 for a multi-signed transaction with 4 signatures.) -The `fee` result is always instantanteous, and relates to the open +The `fee` result is always instantaneous, and relates to the open ledger. It includes the sequence number of the current open ledger, but may not make sense if rippled is not synced to the network. diff --git a/src/xrpld/app/misc/FeeVote.h b/src/xrpld/app/misc/FeeVote.h index 7992163567..3ecf474867 100644 --- a/src/xrpld/app/misc/FeeVote.h +++ b/src/xrpld/app/misc/FeeVote.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED -#define RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { /** Manager to process fee votes. */ class FeeVote @@ -38,10 +18,7 @@ public: @param baseValidation */ virtual void - doValidation( - Fees const& lastFees, - Rules const& rules, - STValidation& val) = 0; + doValidation(Fees const& lastFees, Rules const& rules, STValidation& val) = 0; /** Cast our local vote on the fee. @@ -63,6 +40,4 @@ struct FeeSetup; std::unique_ptr make_FeeVote(FeeSetup const& setup, beast::Journal journal); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index c688cd3b19..4c38b561f6 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -24,7 +5,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -37,8 +18,7 @@ private: std::map voteMap_; public: - VotableValue(value_type current, value_type target) - : current_(current), target_(target) + VotableValue(value_type current, value_type target) : current_(current), target_(target) { // Add our vote ++voteMap_[target_]; @@ -74,8 +54,7 @@ VotableValue::getVotes() const -> std::pair for (auto const& [key, val] : voteMap_) { // Take most voted value between current and target, inclusive - if ((key <= std::max(target_, current_)) && - (key >= std::min(target_, current_)) && (val > weight)) + if ((key <= std::max(target_, current_)) && (key >= std::min(target_, current_)) && (val > weight)) { ourVote = key; weight = val; @@ -99,8 +78,7 @@ public: FeeVoteImpl(FeeSetup const& setup, beast::Journal journal); void - doValidation(Fees const& lastFees, Rules const& rules, STValidation& val) - override; + doValidation(Fees const& lastFees, Rules const& rules, STValidation& val) override; void doVoting( @@ -111,55 +89,34 @@ public: //-------------------------------------------------------------------------- -FeeVoteImpl::FeeVoteImpl(FeeSetup const& setup, beast::Journal journal) - : target_(setup), journal_(journal) +FeeVoteImpl::FeeVoteImpl(FeeSetup const& setup, beast::Journal journal) : target_(setup), journal_(journal) { } void -FeeVoteImpl::doValidation( - Fees const& lastFees, - Rules const& rules, - STValidation& v) +FeeVoteImpl::doValidation(Fees const& lastFees, Rules const& rules, STValidation& v) { // Values should always be in a valid range (because the voting process // will ignore out-of-range values) but if we detect such a case, we do // not send a value. if (rules.enabled(featureXRPFees)) { - auto vote = [&v, this]( - auto const current, - XRPAmount target, - char const* name, - auto const& sfield) { + auto vote = [&v, this](auto const current, XRPAmount target, char const* name, auto const& sfield) { if (current != target) { - JLOG(journal_.info()) - << "Voting for " << name << " of " << target; + JLOG(journal_.info()) << "Voting for " << name << " of " << target; v[sfield] = target; } }; vote(lastFees.base, target_.reference_fee, "base fee", sfBaseFeeDrops); - vote( - lastFees.reserve, - target_.account_reserve, - "base reserve", - sfReserveBaseDrops); - vote( - lastFees.increment, - target_.owner_reserve, - "reserve increment", - sfReserveIncrementDrops); + vote(lastFees.reserve, target_.account_reserve, "base reserve", sfReserveBaseDrops); + vote(lastFees.increment, target_.owner_reserve, "reserve increment", sfReserveIncrementDrops); } else { - auto to32 = [](XRPAmount target) { - return target.dropsAs(); - }; - auto to64 = [](XRPAmount target) { - return target.dropsAs(); - }; + auto to32 = [](XRPAmount target) { return target.dropsAs(); }; + auto to64 = [](XRPAmount target) { return target.dropsAs(); }; auto vote = [&v, this]( auto const current, XRPAmount target, @@ -168,8 +125,7 @@ FeeVoteImpl::doValidation( auto const& sfield) { if (current != target) { - JLOG(journal_.info()) - << "Voting for " << name << " of " << target; + JLOG(journal_.info()) << "Voting for " << name << " of " << target; if (auto const f = convertCallback(target)) v[sfield] = *f; @@ -177,18 +133,8 @@ FeeVoteImpl::doValidation( }; vote(lastFees.base, target_.reference_fee, to64, "base fee", sfBaseFee); - vote( - lastFees.reserve, - target_.account_reserve, - to32, - "base reserve", - sfReserveBase); - vote( - lastFees.increment, - target_.owner_reserve, - to32, - "reserve increment", - sfReserveIncrement); + vote(lastFees.reserve, target_.account_reserve, to32, "base reserve", sfReserveBase); + vote(lastFees.increment, target_.owner_reserve, to32, "reserve increment", sfReserveIncrement); } } @@ -200,38 +146,32 @@ FeeVoteImpl::doVoting( { // LCL must be flag ledger XRPL_ASSERT( - lastClosedLedger && isFlagLedger(lastClosedLedger->seq()), - "ripple::FeeVoteImpl::doVoting : has a flag ledger"); + lastClosedLedger && isFlagLedger(lastClosedLedger->seq()), "xrpl::FeeVoteImpl::doVoting : has a flag ledger"); - detail::VotableValue baseFeeVote( - lastClosedLedger->fees().base, target_.reference_fee); + detail::VotableValue baseFeeVote(lastClosedLedger->fees().base, target_.reference_fee); - detail::VotableValue baseReserveVote( - lastClosedLedger->fees().reserve, target_.account_reserve); + detail::VotableValue baseReserveVote(lastClosedLedger->fees().reserve, target_.account_reserve); - detail::VotableValue incReserveVote( - lastClosedLedger->fees().increment, target_.owner_reserve); + detail::VotableValue incReserveVote(lastClosedLedger->fees().increment, target_.owner_reserve); auto const& rules = lastClosedLedger->rules(); if (rules.enabled(featureXRPFees)) { - auto doVote = [](std::shared_ptr const& val, - detail::VotableValue& value, - SF_AMOUNT const& xrpField) { - if (auto const field = ~val->at(~xrpField); - field && field->native()) - { - auto const vote = field->xrp(); - if (isLegalAmountSigned(vote)) - value.addVote(vote); + auto doVote = + [](std::shared_ptr const& val, detail::VotableValue& value, SF_AMOUNT const& xrpField) { + if (auto const field = ~val->at(~xrpField); field && field->native()) + { + auto const vote = field->xrp(); + if (isLegalAmountSigned(vote)) + value.addVote(vote); + else + value.noVote(); + } else + { value.noVote(); - } - else - { - value.noVote(); - } - }; + } + }; for (auto const& val : set) { @@ -244,28 +184,26 @@ FeeVoteImpl::doVoting( } else { - auto doVote = [](std::shared_ptr const& val, - detail::VotableValue& value, - auto const& valueField) { - if (auto const field = val->at(~valueField)) - { - using xrptype = XRPAmount::value_type; - auto const vote = *field; - if (vote <= std::numeric_limits::max() && - isLegalAmountSigned(XRPAmount{unsafe_cast(vote)})) - value.addVote( - XRPAmount{unsafe_cast(vote)}); + auto doVote = + [](std::shared_ptr const& val, detail::VotableValue& value, auto const& valueField) { + if (auto const field = val->at(~valueField)) + { + using XRPType = XRPAmount::value_type; + auto const vote = *field; + if (vote <= std::numeric_limits::max() && + isLegalAmountSigned(XRPAmount{unsafe_cast(vote)})) + value.addVote(XRPAmount{unsafe_cast(vote)}); + else + // Invalid amounts will be treated as if they're + // not provided. Don't throw because this value is + // provided by an external entity. + value.noVote(); + } else - // Invalid amounts will be treated as if they're - // not provided. Don't throw because this value is - // provided by an external entity. + { value.noVote(); - } - else - { - value.noVote(); - } - }; + } + }; for (auto const& val : set) { @@ -285,14 +223,13 @@ FeeVoteImpl::doVoting( auto const baseReserve = baseReserveVote.getVotes(); auto const incReserve = incReserveVote.getVotes(); - auto const seq = lastClosedLedger->info().seq + 1; + auto const seq = lastClosedLedger->header().seq + 1; // add transactions to our position if (baseFee.second || baseReserve.second || incReserve.second) { - JLOG(journal_.warn()) - << "We are voting for a fee change: " << baseFee.first << "/" - << baseReserve.first << "/" << incReserve.first; + JLOG(journal_.warn()) << "We are voting for a fee change: " << baseFee.first << "/" << baseReserve.first << "/" + << incReserve.first; STTx feeTx(ttFEE, [=, &rules](auto& obj) { obj[sfAccount] = AccountID(); @@ -307,13 +244,9 @@ FeeVoteImpl::doVoting( { // Without the featureXRPFees amendment, these fields are // required. - obj[sfBaseFee] = - baseFee.first.dropsAs(baseFeeVote.current()); - obj[sfReserveBase] = baseReserve.first.dropsAs( - baseReserveVote.current()); - obj[sfReserveIncrement] = - incReserve.first.dropsAs( - incReserveVote.current()); + obj[sfBaseFee] = baseFee.first.dropsAs(baseFeeVote.current()); + obj[sfReserveBase] = baseReserve.first.dropsAs(baseReserveVote.current()); + obj[sfReserveIncrement] = incReserve.first.dropsAs(incReserveVote.current()); obj[sfReferenceFeeUnits] = Config::FEE_UNITS_DEPRECATED; } }); @@ -325,9 +258,7 @@ FeeVoteImpl::doVoting( Serializer s; feeTx.add(s); - if (!initialPosition->addGiveItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(txID, s.slice()))) + if (!initialPosition->addGiveItem(SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(txID, s.slice()))) { JLOG(journal_.warn()) << "Ledger already had fee change"; } @@ -342,4 +273,4 @@ make_FeeVote(FeeSetup const& setup, beast::Journal journal) return std::make_unique(setup, journal); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp index b241d6a98a..eca46c9872 100644 --- a/src/xrpld/app/misc/HashRouter.cpp +++ b/src/xrpld/app/misc/HashRouter.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { auto HashRouter::emplace(uint256 const& key) -> std::pair @@ -33,11 +14,10 @@ HashRouter::emplace(uint256 const& key) -> std::pair return std::make_pair(std::ref(iter->second), false); } - // See if any supressions need to be expired + // See if any suppressions need to be expired expire(suppressionMap_, setup_.holdTime); - return std::make_pair( - std::ref(suppressionMap_.emplace(key, Entry()).first->second), true); + return std::make_pair(std::ref(suppressionMap_.emplace(key, Entry()).first->second), true); } void @@ -65,10 +45,7 @@ HashRouter::addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer) } bool -HashRouter::addSuppressionPeer( - uint256 const& key, - PeerShortID peer, - HashRouterFlags& flags) +HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer, HashRouterFlags& flags) { std::lock_guard lock(mutex_); @@ -105,8 +82,7 @@ HashRouter::getFlags(uint256 const& key) bool HashRouter::setFlags(uint256 const& key, HashRouterFlags flags) { - XRPL_ASSERT( - static_cast(flags), "ripple::HashRouter::setFlags : valid input"); + XRPL_ASSERT(static_cast(flags), "xrpl::HashRouter::setFlags : valid input"); std::lock_guard lock(mutex_); @@ -120,8 +96,7 @@ HashRouter::setFlags(uint256 const& key, HashRouterFlags flags) } auto -HashRouter::shouldRelay(uint256 const& key) - -> std::optional> +HashRouter::shouldRelay(uint256 const& key) -> std::optional> { std::lock_guard lock(mutex_); @@ -161,11 +136,10 @@ setup_HashRouter(Config const& config) } if (setup.relayTime > setup.holdTime) { - Throw( - "HashRouter relay time must be less than or equal to hold time"); + Throw("HashRouter relay time must be less than or equal to hold time"); } return setup; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/HashRouter.h b/src/xrpld/app/misc/HashRouter.h index 60a0b01155..ad6da520bd 100644 --- a/src/xrpld/app/misc/HashRouter.h +++ b/src/xrpld/app/misc/HashRouter.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED -#define RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { enum class HashRouterFlags : std::uint16_t { // Public flags @@ -173,9 +153,7 @@ private: last relay timestamp and return true. */ bool - shouldRelay( - Stopwatch::time_point const& now, - std::chrono::seconds relayTime) + shouldRelay(Stopwatch::time_point const& now, std::chrono::seconds relayTime) { if (relayed_ && *relayed_ + relayTime > now) return false; @@ -202,8 +180,7 @@ private: }; public: - HashRouter(Setup const& setup, Stopwatch& clock) - : setup_(setup), suppressionMap_(clock) + HashRouter(Setup const& setup, Stopwatch& clock) : setup_(setup), suppressionMap_(clock) { } @@ -212,7 +189,7 @@ public: virtual ~HashRouter() = default; - // VFALCO TODO Replace "Supression" terminology with something more + // VFALCO TODO Replace "Suppression" terminology with something more // semantically meaningful. void addSuppression(uint256 const& key); @@ -229,18 +206,11 @@ public: addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer); bool - addSuppressionPeer( - uint256 const& key, - PeerShortID peer, - HashRouterFlags& flags); + addSuppressionPeer(uint256 const& key, PeerShortID peer, HashRouterFlags& flags); // Add a peer suppression and return whether the entry should be processed bool - shouldProcess( - uint256 const& key, - PeerShortID peer, - HashRouterFlags& flags, - std::chrono::seconds tx_interval); + shouldProcess(uint256 const& key, PeerShortID peer, HashRouterFlags& flags, std::chrono::seconds tx_interval); /** Set the flags on a hash. @@ -278,17 +248,10 @@ private: Setup const setup_; // Stores all suppressed hashes and their expiration time - beast::aged_unordered_map< - uint256, - Entry, - Stopwatch::clock_type, - hardened_hash> - suppressionMap_; + beast::aged_unordered_map> suppressionMap_; }; HashRouter::Setup setup_HashRouter(Config const&); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/LendingHelpers.h b/src/xrpld/app/misc/LendingHelpers.h new file mode 100644 index 0000000000..f8297dfdf7 --- /dev/null +++ b/src/xrpld/app/misc/LendingHelpers.h @@ -0,0 +1,467 @@ +#pragma once + +#include +#include + +namespace xrpl { + +struct PreflightContext; + +// Lending protocol has dependencies, so capture them here. +bool +checkLendingProtocolDependencies(PreflightContext const& ctx); + +static constexpr std::uint32_t secondsInYear = 365 * 24 * 60 * 60; + +Number +loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval); + +/// Ensure the periodic payment is always rounded consistently +inline Number +roundPeriodicPayment(Asset const& asset, Number const& periodicPayment, std::int32_t scale) +{ + return roundToAsset(asset, periodicPayment, scale, Number::upward); +} + +/* Represents the breakdown of amounts to be paid and changes applied to the + * Loan object while processing a loan payment. + * + * This structure is returned after processing a loan payment transaction and + * captures the amounts that need to be paid. The actual ledger entry changes + * are made in LoanPay based on this structure values. + * + * The sum of principalPaid, interestPaid, and feePaid represents the total + * amount to be deducted from the borrower's account. The valueChange field + * tracks whether the loan's total value increased or decreased beyond normal + * amortization. + * + * This structure is explained in the XLS-66 spec, section 3.2.4.2 (Payment + * Processing). + */ +struct LoanPaymentParts +{ + // The amount of principal paid that reduces the loan balance. + // This amount is subtracted from sfPrincipalOutstanding in the Loan object + // and paid to the Vault + Number principalPaid = numZero; + + // The total amount of interest paid to the Vault. + // This includes: + // - Tracked interest from the amortization schedule + // - Untracked interest (e.g., late payment penalty interest) + // This value is always non-negative. + Number interestPaid = numZero; + + // The change in the loan's total value outstanding. + // - If valueChange < 0: Loan value decreased + // - If valueChange > 0: Loan value increased + // - If valueChange = 0: No value adjustment + // + // For regular on-time payments, this is always 0. Non-zero values occur + // when: + // - Overpayments reduce the loan balance beyond the scheduled amount + // - Late payments add penalty interest to the loan value + // - Early full payment may increase or decrease the loan value based on + // terms + Number valueChange = numZero; + + /* The total amount of fees paid to the Broker. + * This includes: + * - Tracked management fees from the amortization schedule + * - Untracked fees (e.g., late payment fees, service fees, origination + * fees) This value is always non-negative. + */ + Number feePaid = numZero; + + LoanPaymentParts& + operator+=(LoanPaymentParts const& other); + + bool + operator==(LoanPaymentParts const& other) const; +}; + +/** This structure captures the parts of a loan state. + * + * Whether the values are theoretical (unrounded) or rounded will depend on how + * it was computed. + * + * Many of the fields can be derived from each other, but they're all provided + * here to reduce code duplication and possible mistakes. + * e.g. + * * interestOutstanding = valueOutstanding - principalOutstanding + * * interestDue = interestOutstanding - managementFeeDue + */ +struct LoanState +{ + // Total value still due to be paid by the borrower. + Number valueOutstanding; + // Principal still due to be paid by the borrower. + Number principalOutstanding; + // Interest still due to be paid to the Vault. + // This is a portion of interestOutstanding + Number interestDue; + // Management fee still due to be paid to the broker. + // This is a portion of interestOutstanding + Number managementFeeDue; + + // Interest still due to be paid by the borrower. + Number + interestOutstanding() const + { + XRPL_ASSERT_PARTS( + interestDue + managementFeeDue == valueOutstanding - principalOutstanding, + "xrpl::LoanState::interestOutstanding", + "other values add up correctly"); + return interestDue + managementFeeDue; + } +}; + +/* Describes the initial computed properties of a loan. + * + * This structure contains the fundamental calculated values that define a + * loan's payment structure and amortization schedule. These properties are + * computed: + * - At loan creation (LoanSet transaction) + * - When loan terms change (e.g., after an overpayment that reduces the loan + * balance) + */ +struct LoanProperties +{ + // The unrounded amount to be paid at each regular payment period. + // Calculated using the standard amortization formula based on principal, + // interest rate, and number of payments. + // The actual amount paid in the LoanPay transaction must be rounded up to + // the precision of the asset and loan. + Number periodicPayment; + + // The loan's current state, with all values rounded to the loan's scale. + LoanState loanState; + + // The scale (decimal places) used for rounding all loan amounts. + // This is the maximum of: + // - The asset's native scale + // - A minimum scale required to represent the periodic payment accurately + // All loan state values (principal, interest, fees) are rounded to this + // scale. + std::int32_t loanScale; + + // The principal portion of the first payment. + Number firstPaymentPrincipal; +}; + +// Some values get re-rounded to the vault scale any time they are adjusted. In +// addition, they are prevented from ever going below zero. This helps avoid +// accumulated rounding errors and leftover dust amounts. +template +void +adjustImpreciseNumber(NumberProxy value, Number const& adjustment, Asset const& asset, int vaultScale) +{ + value = roundToAsset(asset, value + adjustment, vaultScale); + + if (*value < beast::zero) + value = 0; +} + +inline int +getAssetsTotalScale(SLE::const_ref vaultSle) +{ + if (!vaultSle) + return Number::minExponent - 1; // LCOV_EXCL_LINE + return STAmount{vaultSle->at(sfAsset), vaultSle->at(sfAssetsTotal)}.exponent(); +} + +TER +checkLoanGuards( + Asset const& vaultAsset, + Number const& principalRequested, + bool expectInterest, + std::uint32_t paymentTotal, + LoanProperties const& properties, + beast::Journal j); + +LoanState +computeTheoreticalLoanState( + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t const paymentRemaining, + TenthBips32 const managementFeeRate); + +// Constructs a valid LoanState object from arbitrary inputs +LoanState +constructLoanState( + Number const& totalValueOutstanding, + Number const& principalOutstanding, + Number const& managementFeeOutstanding); + +// Constructs a valid LoanState object from a Loan object, which always has +// rounded values +LoanState +constructRoundedLoanState(SLE::const_ref loan); + +Number +computeManagementFee(Asset const& asset, Number const& interest, TenthBips32 managementFeeRate, std::int32_t scale); + +Number +computeFullPaymentInterest( + Number const& theoreticalPrincipalOutstanding, + Number const& periodicRate, + NetClock::time_point parentCloseTime, + std::uint32_t paymentInterval, + std::uint32_t prevPaymentDate, + std::uint32_t startDate, + TenthBips32 closeInterestRate); + +namespace detail { +// These classes and functions should only be accessed by LendingHelper +// functions and unit tests + +enum class PaymentSpecialCase { none, final, extra }; + +/* Represents a single loan payment component parts. + +* This structure captures the "delta" (change) values that will be applied to +* the tracked fields in the Loan ledger object when a payment is processed. +* +* These are called "deltas" because they represent the amount by which each +* corresponding field in the Loan object will be reduced. +* They are "tracked" as they change tracked loan values. +*/ +struct PaymentComponents +{ + // The change in total value outstanding for this payment. + // This amount will be subtracted from sfTotalValueOutstanding in the Loan + // object. Equal to the sum of trackedPrincipalDelta, + // trackedInterestPart(), and trackedManagementFeeDelta. + Number trackedValueDelta; + + // The change in principal outstanding for this payment. + // This amount will be subtracted from sfPrincipalOutstanding in the Loan + // object, representing the portion of the payment that reduces the + // original loan amount. + Number trackedPrincipalDelta; + + // The change in management fee outstanding for this payment. + // This amount will be subtracted from sfManagementFeeOutstanding in the + // Loan object. This represents only the tracked management fees from the + // amortization schedule and does not include additional untracked fees + // (such as late payment fees) that go directly to the broker. + Number trackedManagementFeeDelta; + + // Indicates if this payment has special handling requirements. + // - none: Regular scheduled payment + // - final: The last payment that closes out the loan + // - extra: An additional payment beyond the regular schedule (overpayment) + PaymentSpecialCase specialCase = PaymentSpecialCase::none; + + // Calculates the tracked interest portion of this payment. + // This is derived from the other components as: + // trackedValueDelta - trackedPrincipalDelta - trackedManagementFeeDelta + // + // @return The amount of tracked interest included in this payment that + // will be paid to the vault. + Number + trackedInterestPart() const; +}; + +/* Extends PaymentComponents with untracked payment amounts. + * + * This structure adds untracked fees and interest to the base + * PaymentComponents, representing amounts that don't affect the Loan object's + * tracked state but are still part of the total payment due from the borrower. + * + * Untracked amounts include: + * - Late payment fees that go directly to the Broker + * - Late payment penalty interest that goes directly to the Vault + * - Service fees + * + * The key distinction is that tracked amounts reduce the Loan object's state + * (sfTotalValueOutstanding, sfPrincipalOutstanding, + * sfManagementFeeOutstanding), while untracked amounts are paid directly to the + * recipient without affecting the loan's amortization schedule. + */ +struct ExtendedPaymentComponents : public PaymentComponents +{ + // Additional management fees that go directly to the Broker. + // This includes fees not part of the standard amortization schedule + // (e.g., late fees, service fees, origination fees). + // This value may be negative, though the final value returned in + // LoanPaymentParts.feePaid will never be negative. + Number untrackedManagementFee; + + // Additional interest that goes directly to the Vault. + // This includes interest not part of the standard amortization schedule + // (e.g., late payment penalty interest). + // This value may be negative, though the final value returned in + // LoanPaymentParts.interestPaid will never be negative. + Number untrackedInterest; + + // The complete amount due from the borrower for this payment. + // Calculated as: trackedValueDelta + untrackedInterest + + // untrackedManagementFee + // + // This value is used to validate that the payment amount provided by the + // borrower is sufficient to cover all components of the payment. + Number totalDue; + + ExtendedPaymentComponents(PaymentComponents const& p, Number fee, Number interest = numZero) + : PaymentComponents(p) + , untrackedManagementFee(fee) + , untrackedInterest(interest) + , totalDue(trackedValueDelta + untrackedInterest + untrackedManagementFee) + { + } +}; + +/* Represents the differences between two loan states. + * + * This structure is used to capture the change in each component of a loan's + * state, typically when computing the difference between two LoanState objects + * (e.g., before and after a payment). It is a convenient way to capture changes + * in each component. How that difference is used depends on the context. + */ +struct LoanStateDeltas +{ + // The difference in principal outstanding between two loan states. + Number principal; + + // The difference in interest due between two loan states. + Number interest; + + // The difference in management fee outstanding between two loan states. + Number managementFee; + + /* Calculates the total change across all components. + * @return The sum of principal, interest, and management fee deltas. + */ + Number + total() const + { + return principal + interest + managementFee; + } + + // Ensures all delta values are non-negative. + void + nonNegative(); +}; + +Expected, TER> +tryOverpayment( + Asset const& asset, + std::int32_t loanScale, + ExtendedPaymentComponents const& overpaymentComponents, + LoanState const& roundedLoanState, + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentRemaining, + TenthBips16 const managementFeeRate, + beast::Journal j); + +Number +computeRaisedRate(Number const& periodicRate, std::uint32_t paymentsRemaining); + +Number +computePaymentFactor(Number const& periodicRate, std::uint32_t paymentsRemaining); + +std::pair +computeInterestAndFeeParts( + Asset const& asset, + Number const& interest, + TenthBips16 managementFeeRate, + std::int32_t loanScale); + +Number +loanPeriodicPayment(Number const& principalOutstanding, Number const& periodicRate, std::uint32_t paymentsRemaining); + +Number +loanPrincipalFromPeriodicPayment( + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentsRemaining); + +Number +loanLatePaymentInterest( + Number const& principalOutstanding, + TenthBips32 lateInterestRate, + NetClock::time_point parentCloseTime, + std::uint32_t nextPaymentDueDate); + +Number +loanAccruedInterest( + Number const& principalOutstanding, + Number const& periodicRate, + NetClock::time_point parentCloseTime, + std::uint32_t startDate, + std::uint32_t prevPaymentDate, + std::uint32_t paymentInterval); + +ExtendedPaymentComponents +computeOverpaymentComponents( + Asset const& asset, + int32_t const loanScale, + Number const& overpayment, + TenthBips32 const overpaymentInterestRate, + TenthBips32 const overpaymentFeeRate, + TenthBips16 const managementFeeRate); + +PaymentComponents +computePaymentComponents( + Asset const& asset, + std::int32_t scale, + Number const& totalValueOutstanding, + Number const& principalOutstanding, + Number const& managementFeeOutstanding, + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentRemaining, + TenthBips16 managementFeeRate); + +} // namespace detail + +detail::LoanStateDeltas +operator-(LoanState const& lhs, LoanState const& rhs); + +LoanState +operator-(LoanState const& lhs, detail::LoanStateDeltas const& rhs); + +LoanState +operator+(LoanState const& lhs, detail::LoanStateDeltas const& rhs); + +LoanProperties +computeLoanProperties( + Asset const& asset, + Number const& principalOutstanding, + TenthBips32 interestRate, + std::uint32_t paymentInterval, + std::uint32_t paymentsRemaining, + TenthBips32 managementFeeRate, + std::int32_t minimumScale); + +LoanProperties +computeLoanProperties( + Asset const& asset, + Number const& principalOutstanding, + Number const& periodicRate, + std::uint32_t paymentsRemaining, + TenthBips32 managementFeeRate, + std::int32_t minimumScale); + +bool +isRounded(Asset const& asset, Number const& value, std::int32_t scale); + +// Indicates what type of payment is being made. +// regular, late, and full are mutually exclusive. +// overpayment is an "add on" to a regular payment, and follows that path with +// potential extra work at the end. +enum class LoanPaymentType { regular = 0, late, full, overpayment }; + +Expected +loanMakePayment( + Asset const& asset, + ApplyView& view, + SLE::ref loan, + SLE::const_ref brokerSle, + STAmount const& amount, + LoanPaymentType const paymentType, + beast::Journal j); + +} // namespace xrpl diff --git a/src/xrpld/app/misc/LoadFeeTrack.h b/src/xrpld/app/misc/LoadFeeTrack.h index 0064359c76..8eb53187ce 100644 --- a/src/xrpld/app/misc/LoadFeeTrack.h +++ b/src/xrpld/app/misc/LoadFeeTrack.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_CORE_LOADFEETRACK_H_INCLUDED -#define RIPPLE_CORE_LOADFEETRACK_H_INCLUDED +#pragma once #include #include @@ -28,7 +8,7 @@ #include #include -namespace ripple { +namespace xrpl { struct Fees; @@ -44,8 +24,7 @@ struct Fees; class LoadFeeTrack final { public: - explicit LoadFeeTrack( - beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) + explicit LoadFeeTrack(beast::Journal journal = beast::Journal(beast::Journal::getNullSink())) : j_(journal) , localTxnLoadFee_(lftNormalFee) , remoteTxnLoadFee_(lftNormalFee) @@ -95,8 +74,7 @@ public: getLoadFactor() const { std::lock_guard sl(lock_); - return std::max( - {clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_}); + return std::max({clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_}); } std::pair @@ -105,8 +83,7 @@ public: std::lock_guard sl(lock_); return std::make_pair( - std::max(localTxnLoadFee_, remoteTxnLoadFee_), - std::max(remoteTxnLoadFee_, clusterTxnLoadFee_)); + std::max(localTxnLoadFee_, remoteTxnLoadFee_), std::max(remoteTxnLoadFee_, clusterTxnLoadFee_)); } void @@ -133,26 +110,21 @@ public: isLoadedCluster() const { std::lock_guard sl(lock_); - return (raiseCount_ != 0) || (localTxnLoadFee_ != lftNormalFee) || - (clusterTxnLoadFee_ != lftNormalFee); + return (raiseCount_ != 0) || (localTxnLoadFee_ != lftNormalFee) || (clusterTxnLoadFee_ != lftNormalFee); } private: - static std::uint32_t constexpr lftNormalFee = - 256; // 256 is the minimum/normal load factor - static std::uint32_t constexpr lftFeeIncFraction = - 4; // increase fee by 1/4 - static std::uint32_t constexpr lftFeeDecFraction = - 4; // decrease fee by 1/4 + static std::uint32_t constexpr lftNormalFee = 256; // 256 is the minimum/normal load factor + static std::uint32_t constexpr lftFeeIncFraction = 4; // increase fee by 1/4 + static std::uint32_t constexpr lftFeeDecFraction = 4; // decrease fee by 1/4 static std::uint32_t constexpr lftFeeMax = lftNormalFee * 1000000; beast::Journal const j_; std::mutex mutable lock_; - std::uint32_t localTxnLoadFee_; // Scale factor, lftNormalFee = normal fee - std::uint32_t remoteTxnLoadFee_; // Scale factor, lftNormalFee = normal fee - std::uint32_t - clusterTxnLoadFee_; // Scale factor, lftNormalFee = normal fee + std::uint32_t localTxnLoadFee_; // Scale factor, lftNormalFee = normal fee + std::uint32_t remoteTxnLoadFee_; // Scale factor, lftNormalFee = normal fee + std::uint32_t clusterTxnLoadFee_; // Scale factor, lftNormalFee = normal fee std::uint32_t raiseCount_; }; @@ -160,12 +132,6 @@ private: // Scale using load as well as base rate XRPAmount -scaleFeeLoad( - XRPAmount fee, - LoadFeeTrack const& feeTrack, - Fees const& fees, - bool bUnlimited); +scaleFeeLoad(XRPAmount fee, LoadFeeTrack const& feeTrack, Fees const& fees, bool bUnlimited); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp index d981ba200c..d4a64a34dd 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.cpp +++ b/src/xrpld/app/misc/NegativeUNLVote.cpp @@ -1,32 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -namespace ripple { +namespace xrpl { -NegativeUNLVote::NegativeUNLVote(NodeID const& myId, beast::Journal j) - : myId_(myId), j_(j) +NegativeUNLVote::NegativeUNLVote(NodeID const& myId, beast::Journal j) : myId_(myId), j_(j) { } @@ -78,31 +58,24 @@ NegativeUNLVote::doVoting( } } - auto const seq = prevLedger->info().seq + 1; + auto const seq = prevLedger->header().seq + 1; purgeNewValidators(seq); // Process the table and find all candidates to disable or to re-enable - auto const candidates = - findAllCandidates(unlNodeIDs, negUnlNodeIDs, *scoreTable); + auto const candidates = findAllCandidates(unlNodeIDs, negUnlNodeIDs, *scoreTable); // Pick one to disable and one to re-enable if any, add ttUNL_MODIFY Tx if (!candidates.toDisableCandidates.empty()) { - auto n = - choose(prevLedger->info().hash, candidates.toDisableCandidates); - XRPL_ASSERT( - nidToKeyMap.contains(n), - "ripple::NegativeUNLVote::doVoting : found node to disable"); + auto n = choose(prevLedger->header().hash, candidates.toDisableCandidates); + XRPL_ASSERT(nidToKeyMap.contains(n), "xrpl::NegativeUNLVote::doVoting : found node to disable"); addTx(seq, nidToKeyMap.at(n), ToDisable, initialSet); } if (!candidates.toReEnableCandidates.empty()) { - auto n = choose( - prevLedger->info().hash, candidates.toReEnableCandidates); - XRPL_ASSERT( - nidToKeyMap.contains(n), - "ripple::NegativeUNLVote::doVoting : found node to enable"); + auto n = choose(prevLedger->header().hash, candidates.toReEnableCandidates); + XRPL_ASSERT(nidToKeyMap.contains(n), "xrpl::NegativeUNLVote::doVoting : found node to enable"); addTx(seq, nidToKeyMap.at(n), ToReEnable, initialSet); } } @@ -124,30 +97,22 @@ NegativeUNLVote::addTx( Serializer s; negUnlTx.add(s); if (!initialSet->addGiveItem( - SHAMapNodeType::tnTRANSACTION_NM, - make_shamapitem(negUnlTx.getTransactionID(), s.slice()))) + SHAMapNodeType::tnTRANSACTION_NM, make_shamapitem(negUnlTx.getTransactionID(), s.slice()))) { - JLOG(j_.warn()) << "N-UNL: ledger seq=" << seq - << ", add ttUNL_MODIFY tx failed"; + JLOG(j_.warn()) << "N-UNL: ledger seq=" << seq << ", add ttUNL_MODIFY tx failed"; } else { JLOG(j_.debug()) << "N-UNL: ledger seq=" << seq - << ", add a ttUNL_MODIFY Tx with txID: " - << negUnlTx.getTransactionID() << ", the validator to " - << (modify == ToDisable ? "disable: " : "re-enable: ") - << vp; + << ", add a ttUNL_MODIFY Tx with txID: " << negUnlTx.getTransactionID() + << ", the validator to " << (modify == ToDisable ? "disable: " : "re-enable: ") << vp; } } NodeID -NegativeUNLVote::choose( - uint256 const& randomPadData, - std::vector const& candidates) +NegativeUNLVote::choose(uint256 const& randomPadData, std::vector const& candidates) { - XRPL_ASSERT( - !candidates.empty(), - "ripple::NegativeUNLVote::choose : non-empty input"); + XRPL_ASSERT(!candidates.empty(), "xrpl::NegativeUNLVote::choose : non-empty input"); static_assert(NodeID::bytes <= uint256::bytes); NodeID randomPad = NodeID::fromVoid(randomPadData.data()); NodeID txNodeID = candidates[0]; @@ -173,7 +138,7 @@ NegativeUNLVote::buildScoreTable( // Ask the validation container to keep enough validation message history // for next time. - auto const seq = prevLedger->info().seq + 1; + auto const seq = prevLedger->header().seq + 1; validations.setSeqToKeep(seq - 1, seq + FLAG_LEDGER_INTERVAL); // Find FLAG_LEDGER_INTERVAL (i.e. 256) previous ledger hashes @@ -187,9 +152,8 @@ NegativeUNLVote::buildScoreTable( auto const numAncestors = ledgerAncestors.size(); if (numAncestors < FLAG_LEDGER_INTERVAL) { - JLOG(j_.debug()) << "N-UNL: ledger " << seq - << " not enough history. Can trace back only " - << numAncestors << " ledgers."; + JLOG(j_.debug()) << "N-UNL: ledger " << seq << " not enough history. Can trace back only " << numAncestors + << " ledgers."; return {}; } @@ -204,8 +168,7 @@ NegativeUNLVote::buildScoreTable( // the score table. for (int i = 0; i < FLAG_LEDGER_INTERVAL; ++i) { - for (auto const& v : validations.getTrustedForLedger( - ledgerAncestors[numAncestors - 1 - i], seq - 2 - i)) + for (auto const& v : validations.getTrustedForLedger(ledgerAncestors[numAncestors - 1 - i], seq - 2 - i)) { if (scoreTable.count(v->getNodeID())) ++scoreTable[v->getNodeID()]; @@ -221,16 +184,12 @@ NegativeUNLVote::buildScoreTable( }(); if (myValidationCount < negativeUNLMinLocalValsToVote) { - JLOG(j_.debug()) << "N-UNL: ledger " << seq - << ". Local node only issued " << myValidationCount - << " validations in last " << FLAG_LEDGER_INTERVAL - << " ledgers." + JLOG(j_.debug()) << "N-UNL: ledger " << seq << ". Local node only issued " << myValidationCount + << " validations in last " << FLAG_LEDGER_INTERVAL << " ledgers." << " The reliability measurement could be wrong."; return {}; } - else if ( - myValidationCount > negativeUNLMinLocalValsToVote && - myValidationCount <= FLAG_LEDGER_INTERVAL) + else if (myValidationCount > negativeUNLMinLocalValsToVote && myValidationCount <= FLAG_LEDGER_INTERVAL) { return scoreTable; } @@ -238,9 +197,8 @@ NegativeUNLVote::buildScoreTable( { // cannot happen because validations.getTrustedForLedger does not // return multiple validations of the same ledger from a validator. - JLOG(j_.error()) << "N-UNL: ledger " << seq << ". Local node issued " - << myValidationCount << " validations in last " - << FLAG_LEDGER_INTERVAL << " ledgers. Too many!"; + JLOG(j_.error()) << "N-UNL: ledger " << seq << ". Local node issued " << myValidationCount + << " validations in last " << FLAG_LEDGER_INTERVAL << " ledgers. Too many!"; return {}; } } @@ -253,8 +211,7 @@ NegativeUNLVote::findAllCandidates( { // Compute if need to find more validators to disable auto const canAdd = [&]() -> bool { - auto const maxNegativeListed = static_cast( - std::ceil(unl.size() * negativeUNLMaxListed)); + auto const maxNegativeListed = static_cast(std::ceil(unl.size() * negativeUNLMaxListed)); std::size_t negativeListed = 0; for (auto const& n : unl) { @@ -262,11 +219,9 @@ NegativeUNLVote::findAllCandidates( ++negativeListed; } bool const result = negativeListed < maxNegativeListed; - JLOG(j_.trace()) << "N-UNL: nodeId " << myId_ << " lowWaterMark " - << negativeUNLLowWaterMark << " highWaterMark " - << negativeUNLHighWaterMark << " canAdd " << result - << " negativeListed " << negativeListed - << " maxNegativeListed " << maxNegativeListed; + JLOG(j_.trace()) << "N-UNL: nodeId " << myId_ << " lowWaterMark " << negativeUNLLowWaterMark + << " highWaterMark " << negativeUNLHighWaterMark << " canAdd " << result << " negativeListed " + << negativeListed << " maxNegativeListed " << maxNegativeListed; return result; }(); @@ -280,8 +235,7 @@ NegativeUNLVote::findAllCandidates( // (2) has less than negativeUNLLowWaterMark validations, // (3) is not in negUnl, and // (4) is not a new validator. - if (canAdd && score < negativeUNLLowWaterMark && - !negUnl.count(nodeId) && !newValidators_.count(nodeId)) + if (canAdd && score < negativeUNLLowWaterMark && !negUnl.count(nodeId) && !newValidators_.count(nodeId)) { JLOG(j_.trace()) << "N-UNL: toDisable candidate " << nodeId; candidates.toDisableCandidates.push_back(nodeId); @@ -321,17 +275,14 @@ NegativeUNLVote::findAllCandidates( } void -NegativeUNLVote::newValidators( - LedgerIndex seq, - hash_set const& nowTrusted) +NegativeUNLVote::newValidators(LedgerIndex seq, hash_set const& nowTrusted) { std::lock_guard lock(mutex_); for (auto const& n : nowTrusted) { if (newValidators_.find(n) == newValidators_.end()) { - JLOG(j_.trace()) << "N-UNL: add a new validator " << n - << " at ledger seq=" << seq; + JLOG(j_.trace()) << "N-UNL: add a new validator " << n << " at ledger seq=" << seq; newValidators_[n] = seq; } } @@ -355,4 +306,4 @@ NegativeUNLVote::purgeNewValidators(LedgerIndex seq) } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/NegativeUNLVote.h b/src/xrpld/app/misc/NegativeUNLVote.h index 72ed965717..4019d32f13 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.h +++ b/src/xrpld/app/misc/NegativeUNLVote.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_NEGATIVEUNLVOTE_H_INCLUDED -#define RIPPLE_APP_MISC_NEGATIVEUNLVOTE_H_INCLUDED +#pragma once #include @@ -29,7 +9,7 @@ #include -namespace ripple { +namespace xrpl { template class Validations; @@ -53,20 +33,17 @@ public: * An unreliable validator is a candidate to be disabled by the NegativeUNL * protocol. */ - static constexpr size_t negativeUNLLowWaterMark = - FLAG_LEDGER_INTERVAL * 50 / 100; + static constexpr size_t negativeUNLLowWaterMark = FLAG_LEDGER_INTERVAL * 50 / 100; /** * An unreliable validator must have more than negativeUNLHighWaterMark * validations in the last flag ledger period to be re-enabled. */ - static constexpr size_t negativeUNLHighWaterMark = - FLAG_LEDGER_INTERVAL * 80 / 100; + static constexpr size_t negativeUNLHighWaterMark = FLAG_LEDGER_INTERVAL * 80 / 100; /** * The minimum number of validations of the local node for it to * participate in the voting. */ - static constexpr size_t negativeUNLMinLocalValsToVote = - FLAG_LEDGER_INTERVAL * 90 / 100; + static constexpr size_t negativeUNLMinLocalValsToVote = FLAG_LEDGER_INTERVAL * 90 / 100; /** * We don't want to disable new validators immediately after adding them. * So we skip voting for disabling them for 2 flag ledgers. @@ -148,11 +125,7 @@ private: * @param initialSet the transaction set */ void - addTx( - LedgerIndex seq, - PublicKey const& vp, - NegativeUNLModify modify, - std::shared_ptr const& initialSet); + addTx(LedgerIndex seq, PublicKey const& vp, NegativeUNLModify modify, std::shared_ptr const& initialSet); /** * Pick one candidate from a vector of candidates. @@ -213,6 +186,4 @@ private: friend class test::NegativeUNLVoteScoreTable_test; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index d649bb3a29..7da26ada40 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -46,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +64,7 @@ #include #include -namespace ripple { +namespace xrpl { class NetworkOPsImp final : public NetworkOPs { @@ -101,16 +82,12 @@ class NetworkOPsImp final : public NetworkOPs bool applied = false; TER result; - TransactionStatus( - std::shared_ptr t, - bool a, - bool l, - FailHard f) + TransactionStatus(std::shared_ptr t, bool a, bool l, FailHard f) : transaction(t), admin(a), local(l), failType(f) { XRPL_ASSERT( local || failType == FailHard::no, - "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : " + "xrpl::NetworkOPsImp::TransactionStatus::TransactionStatus : " "valid inputs"); } }; @@ -153,8 +130,7 @@ class NetworkOPsImp final : public NetworkOPs OperatingMode mode_ = OperatingMode::DISCONNECTED; std::array counters_; mutable std::mutex mutex_; - std::chrono::steady_clock::time_point start_ = - std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point start_ = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point const processStart_ = start_; std::uint64_t initialSyncUs_{0}; static std::array const states_; @@ -162,8 +138,7 @@ class NetworkOPsImp final : public NetworkOPs public: explicit StateAccounting() { - counters_[static_cast(OperatingMode::DISCONNECTED)] - .transitions = 1; + counters_[static_cast(OperatingMode::DISCONNECTED)].transitions = 1; } /** @@ -204,10 +179,7 @@ class NetworkOPsImp final : public NetworkOPs { ServerFeeSummary() = default; - ServerFeeSummary( - XRPAmount fee, - TxQ::Metrics&& escalationMetrics, - LoadFeeTrack const& loadFeeTrack); + ServerFeeSummary(XRPAmount fee, TxQ::Metrics&& escalationMetrics, LoadFeeTrack const& loadFeeTrack); bool operator!=(ServerFeeSummary const& b) const; @@ -245,21 +217,15 @@ public: , accountHistoryTxTimer_(io_svc) , mConsensus( app, - make_FeeVote( - setup_FeeVote(app_.config().section("voting")), - app_.logs().journal("FeeVote")), + make_FeeVote(setup_FeeVote(app_.config().section("voting")), app_.logs().journal("FeeVote")), ledgerMaster, *m_localTX, app.getInboundTransactions(), beast::get_abstract_clock(), validatorKeys, app_.logs().journal("LedgerConsensus")) - , validatorPK_( - validatorKeys.keys ? validatorKeys.keys->publicKey - : decltype(validatorPK_){}) - , validatorMasterPK_( - validatorKeys.keys ? validatorKeys.keys->masterPublicKey - : decltype(validatorMasterPK_){}) + , validatorPK_(validatorKeys.keys ? validatorKeys.keys->publicKey : decltype(validatorPK_){}) + , validatorMasterPK_(validatorKeys.keys ? validatorKeys.keys->masterPublicKey : decltype(validatorMasterPK_){}) , m_ledgerMaster(ledgerMaster) , m_job_queue(job_queue) , m_standalone(standalone) @@ -295,11 +261,8 @@ public: submitTransaction(std::shared_ptr const&) override; void - processTransaction( - std::shared_ptr& transaction, - bool bUnlimited, - bool bLocal, - FailHard failType) override; + processTransaction(std::shared_ptr& transaction, bool bUnlimited, bool bLocal, FailHard failType) + override; void processTransactionSet(CanonicalTXSet const& set) override; @@ -309,14 +272,11 @@ public: * transactions and wait for this transaction to complete. * * @param transaction Transaction object. - * @param bUnliimited Whether a privileged client connection submitted it. + * @param bUnlimited Whether a privileged client connection submitted it. * @param failType fail_hard setting from transaction submission. */ void - doTransactionSync( - std::shared_ptr transaction, - bool bUnlimited, - FailHard failType); + doTransactionSync(std::shared_ptr transaction, bool bUnlimited, FailHard failType); /** * For transactions not submitted by a locally connected client, fire and @@ -328,10 +288,7 @@ public: * @param failType fail_hard setting from transaction submission. */ void - doTransactionAsync( - std::shared_ptr transaction, - bool bUnlimited, - FailHard failtype); + doTransactionAsync(std::shared_ptr transaction, bool bUnlimited, FailHard failtype); private: bool @@ -362,9 +319,7 @@ public: // Json::Value - getOwnerInfo( - std::shared_ptr lpLedger, - AccountID const& account) override; + getOwnerInfo(std::shared_ptr lpLedger, AccountID const& account) override; // // Book functions. @@ -385,9 +340,7 @@ public: processTrustedProposal(RCLCxPeerPos proposal) override; bool - recvValidation( - std::shared_ptr const& val, - std::string const& source) override; + recvValidation(std::shared_ptr const& val, std::string const& source) override; void mapComplete(std::shared_ptr const& map, bool fromAcquire) override; @@ -403,9 +356,7 @@ private: public: bool - beginConsensus( - uint256 const& networkClosed, - std::unique_ptr const& clog) override; + beginConsensus(uint256 const& networkClosed, std::unique_ptr const& clog) override; void endConsensus(std::unique_ptr const& clog) override; void @@ -459,8 +410,7 @@ public: Json::Value getLedgerFetchInfo() override; std::uint32_t - acceptLedger( - std::optional consensusDelay) override; + acceptLedger(std::optional consensusDelay) override; void reportFeeChange() override; void @@ -489,38 +439,22 @@ public: // InfoSub::Source. // void - subAccount( - InfoSub::ref ispListener, - hash_set const& vnaAccountIDs, - bool rt) override; + subAccount(InfoSub::ref ispListener, hash_set const& vnaAccountIDs, bool rt) override; void - unsubAccount( - InfoSub::ref ispListener, - hash_set const& vnaAccountIDs, - bool rt) override; + unsubAccount(InfoSub::ref ispListener, hash_set const& vnaAccountIDs, bool rt) override; // Just remove the subscription from the tracking // not from the InfoSub. Needed for InfoSub destruction void - unsubAccountInternal( - std::uint64_t seq, - hash_set const& vnaAccountIDs, - bool rt) override; + unsubAccountInternal(std::uint64_t seq, hash_set const& vnaAccountIDs, bool rt) override; error_code_i - subAccountHistory(InfoSub::ref ispListener, AccountID const& account) - override; + subAccountHistory(InfoSub::ref ispListener, AccountID const& account) override; void - unsubAccountHistory( - InfoSub::ref ispListener, - AccountID const& account, - bool historyOnly) override; + unsubAccountHistory(InfoSub::ref ispListener, AccountID const& account, bool historyOnly) override; void - unsubAccountHistoryInternal( - std::uint64_t seq, - AccountID const& account, - bool historyOnly) override; + unsubAccountHistoryInternal(std::uint64_t seq, AccountID const& account, bool historyOnly) override; bool subLedger(InfoSub::ref ispListener, Json::Value& jvResult) override; @@ -533,8 +467,7 @@ public: unsubBookChanges(std::uint64_t uListener) override; bool - subServer(InfoSub::ref ispListener, Json::Value& jvResult, bool admin) - override; + subServer(InfoSub::ref ispListener, Json::Value& jvResult, bool admin) override; bool unsubServer(std::uint64_t uListener) override; @@ -594,8 +527,7 @@ public: } catch (boost::system::system_error const& e) { - JLOG(m_journal.error()) - << "NetworkOPs: heartbeatTimer cancel error: " << e.what(); + JLOG(m_journal.error()) << "NetworkOPs: heartbeatTimer cancel error: " << e.what(); } try @@ -604,8 +536,7 @@ public: } catch (boost::system::system_error const& e) { - JLOG(m_journal.error()) - << "NetworkOPs: clusterTimer cancel error: " << e.what(); + JLOG(m_journal.error()) << "NetworkOPs: clusterTimer cancel error: " << e.what(); } try @@ -614,9 +545,7 @@ public: } catch (boost::system::system_error const& e) { - JLOG(m_journal.error()) - << "NetworkOPs: accountHistoryTxTimer cancel error: " - << e.what(); + JLOG(m_journal.error()) << "NetworkOPs: accountHistoryTxTimer cancel error: " << e.what(); } } // Make sure that any waitHandlers pending in our timers are done. @@ -724,16 +653,13 @@ private: InfoSub::wptr sinkWptr_; std::shared_ptr index_; }; - using SubAccountHistoryMapType = - hash_map>; + using SubAccountHistoryMapType = hash_map>; /** * @note called while holding mSubLock */ void - subAccountHistoryStart( - std::shared_ptr const& ledger, - SubAccountHistoryInfoWeak& subInfo); + subAccountHistoryStart(std::shared_ptr const& ledger, SubAccountHistoryInfoWeak& subInfo); void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo); void @@ -814,37 +740,18 @@ private: struct Stats { template - Stats( - Handler const& handler, - beast::insight::Collector::ptr const& collector) + Stats(Handler const& handler, beast::insight::Collector::ptr const& collector) : hook(collector->make_hook(handler)) - , disconnected_duration(collector->make_gauge( - "State_Accounting", - "Disconnected_duration")) - , connected_duration(collector->make_gauge( - "State_Accounting", - "Connected_duration")) - , syncing_duration( - collector->make_gauge("State_Accounting", "Syncing_duration")) - , tracking_duration(collector->make_gauge( - "State_Accounting", - "Tracking_duration")) - , full_duration( - collector->make_gauge("State_Accounting", "Full_duration")) - , disconnected_transitions(collector->make_gauge( - "State_Accounting", - "Disconnected_transitions")) - , connected_transitions(collector->make_gauge( - "State_Accounting", - "Connected_transitions")) - , syncing_transitions(collector->make_gauge( - "State_Accounting", - "Syncing_transitions")) - , tracking_transitions(collector->make_gauge( - "State_Accounting", - "Tracking_transitions")) - , full_transitions( - collector->make_gauge("State_Accounting", "Full_transitions")) + , disconnected_duration(collector->make_gauge("State_Accounting", "Disconnected_duration")) + , connected_duration(collector->make_gauge("State_Accounting", "Connected_duration")) + , syncing_duration(collector->make_gauge("State_Accounting", "Syncing_duration")) + , tracking_duration(collector->make_gauge("State_Accounting", "Tracking_duration")) + , full_duration(collector->make_gauge("State_Accounting", "Full_duration")) + , disconnected_transitions(collector->make_gauge("State_Accounting", "Disconnected_transitions")) + , connected_transitions(collector->make_gauge("State_Accounting", "Connected_transitions")) + , syncing_transitions(collector->make_gauge("State_Accounting", "Syncing_transitions")) + , tracking_transitions(collector->make_gauge("State_Accounting", "Tracking_transitions")) + , full_transitions(collector->make_gauge("State_Accounting", "Full_transitions")) { } @@ -872,22 +779,19 @@ private: //------------------------------------------------------------------------------ -static std::array const stateNames{ - {"disconnected", "connected", "syncing", "tracking", "full"}}; +static std::array const stateNames{{"disconnected", "connected", "syncing", "tracking", "full"}}; std::array const NetworkOPsImp::states_ = stateNames; -std::array const - NetworkOPsImp::StateAccounting::states_ = { - {Json::StaticString(stateNames[0]), - Json::StaticString(stateNames[1]), - Json::StaticString(stateNames[2]), - Json::StaticString(stateNames[3]), - Json::StaticString(stateNames[4])}}; +std::array const NetworkOPsImp::StateAccounting::states_ = { + {Json::StaticString(stateNames[0]), + Json::StaticString(stateNames[1]), + Json::StaticString(stateNames[2]), + Json::StaticString(stateNames[3]), + Json::StaticString(stateNames[4])}}; -static auto const genesisAccountId = calcAccountID( - generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")) - .first); +static auto const genesisAccountId = + calcAccountID(generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")).first); //------------------------------------------------------------------------------ inline OperatingMode @@ -969,21 +873,17 @@ NetworkOPsImp::setTimer( std::function onError) { // Only start the timer if waitHandlerCounter_ is not yet joined. - if (auto optionalCountedHandler = waitHandlerCounter_.wrap( - [this, onExpire, onError](boost::system::error_code const& e) { - if ((e.value() == boost::system::errc::success) && - (!m_job_queue.isStopped())) + if (auto optionalCountedHandler = + waitHandlerCounter_.wrap([this, onExpire, onError](boost::system::error_code const& e) { + if ((e.value() == boost::system::errc::success) && (!m_job_queue.isStopped())) { onExpire(); } // Recover as best we can if an unexpected error occurs. - if (e.value() != boost::system::errc::success && - e.value() != boost::asio::error::operation_aborted) + if (e.value() != boost::system::errc::success && e.value() != boost::asio::error::operation_aborted) { // Try again later and hope for the best. - JLOG(m_journal.error()) - << "Timer got error '" << e.message() - << "'. Restarting timer."; + JLOG(m_journal.error()) << "Timer got error '" << e.message() << "'. Restarting timer."; onError(); } })) @@ -999,11 +899,7 @@ NetworkOPsImp::setHeartbeatTimer() setTimer( heartbeatTimer_, mConsensus.parms().ledgerGRANULARITY, - [this]() { - m_job_queue.addJob(jtNETOP_TIMER, "NetOPs.heartbeat", [this]() { - processHeartbeatTimer(); - }); - }, + [this]() { m_job_queue.addJob(jtNETOP_TIMER, "NetHeart", [this]() { processHeartbeatTimer(); }); }, [this]() { setHeartbeatTimer(); }); } @@ -1015,19 +911,14 @@ NetworkOPsImp::setClusterTimer() setTimer( clusterTimer_, 10s, - [this]() { - m_job_queue.addJob(jtNETOP_CLUSTER, "NetOPs.cluster", [this]() { - processClusterTimer(); - }); - }, + [this]() { m_job_queue.addJob(jtNETOP_CLUSTER, "NetCluster", [this]() { processClusterTimer(); }); }, [this]() { setClusterTimer(); }); } void NetworkOPsImp::setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo) { - JLOG(m_journal.debug()) << "Scheduling AccountHistory job for account " - << toBase58(subInfo.index_->accountId_); + JLOG(m_journal.debug()) << "Scheduling AccountHistory job for account " << toBase58(subInfo.index_->accountId_); using namespace std::chrono_literals; setTimer( accountHistoryTxTimer_, @@ -1039,8 +930,7 @@ NetworkOPsImp::setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo) void NetworkOPsImp::processHeartbeatTimer() { - RclConsensusLogger clog( - "Heartbeat Timer", mConsensus.validating(), m_journal); + RclConsensusLogger clog("Heartbeat Timer", mConsensus.validating(), m_journal); { std::unique_lock lock{app_.getMasterMutex()}; @@ -1064,9 +954,8 @@ NetworkOPsImp::processHeartbeatTimer() } else { - CLOG(clog.ss()) - << "already DISCONNECTED. too few peers (" << numPeers - << "), need at least " << minPeerCount_; + CLOG(clog.ss()) << "already DISCONNECTED. too few peers (" << numPeers << "), need at least " + << minPeerCount_; } // MasterMutex lock need not be held to call setHeartbeatTimer() @@ -1081,10 +970,8 @@ NetworkOPsImp::processHeartbeatTimer() if (mMode == OperatingMode::DISCONNECTED) { setMode(OperatingMode::CONNECTED); - JLOG(m_journal.info()) - << "Node count (" << numPeers << ") is sufficient."; - CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers - << " peers. "; + JLOG(m_journal.info()) << "Node count (" << numPeers << ") is sufficient."; + CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers << " peers. "; } // Check if the last validated ledger forces a change between these @@ -1098,8 +985,7 @@ NetworkOPsImp::processHeartbeatTimer() auto newMode = mMode.load(); if (origMode != newMode) { - CLOG(clog.ss()) - << ", changing to " << strOperatingMode(newMode, true); + CLOG(clog.ss()) << ", changing to " << strOperatingMode(newMode, true); } CLOG(clog.ss()) << ". "; } @@ -1130,9 +1016,7 @@ NetworkOPsImp::processClusterTimer() bool const update = app_.cluster().update( app_.nodeIdentity().first, "", - (m_ledgerMaster.getValidatedLedgerAge() <= 4min) - ? app_.getFeeTrack().getLocalFee() - : 0, + (m_ledgerMaster.getValidatedLedgerAge() <= 4min) ? app_.getFeeTrack().getLocalFee() : 0, app_.timeKeeper().now()); if (!update) @@ -1159,17 +1043,14 @@ NetworkOPsImp::processClusterTimer() node.set_name(to_string(item.address)); node.set_cost(item.balance); } - app_.overlay().foreach(send_if( - std::make_shared(cluster, protocol::mtCLUSTER), - peer_in_cluster())); + app_.overlay().foreach(send_if(std::make_shared(cluster, protocol::mtCLUSTER), peer_in_cluster())); setClusterTimer(); } //------------------------------------------------------------------------------ std::string -NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin) - const +NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin) const { if (mode == OperatingMode::FULL && admin) { @@ -1197,11 +1078,9 @@ NetworkOPsImp::submitTransaction(std::shared_ptr const& iTrans) } // Enforce Network bar for batch txn - if (iTrans->isFlag(tfInnerBatchTxn) && - m_ledgerMaster.getValidatedRules().enabled(featureBatch)) + if (iTrans->isFlag(tfInnerBatchTxn) && m_ledgerMaster.getValidatedRules().enabled(featureBatch)) { - JLOG(m_journal.error()) - << "Submitted transaction invalid: tfInnerBatchTxn flag present."; + JLOG(m_journal.error()) << "Submitted transaction invalid: tfInnerBatchTxn flag present."; return; } @@ -1219,23 +1098,18 @@ NetworkOPsImp::submitTransaction(std::shared_ptr const& iTrans) try { - auto const [validity, reason] = checkValidity( - app_.getHashRouter(), - *trans, - m_ledgerMaster.getValidatedRules(), - app_.config()); + auto const [validity, reason] = + checkValidity(app_.getHashRouter(), *trans, m_ledgerMaster.getValidatedRules(), app_.config()); if (validity != Validity::Valid) { - JLOG(m_journal.warn()) - << "Submitted transaction invalid: " << reason; + JLOG(m_journal.warn()) << "Submitted transaction invalid: " << reason; return; } } catch (std::exception const& ex) { - JLOG(m_journal.warn()) - << "Exception checking transaction " << txid << ": " << ex.what(); + JLOG(m_journal.warn()) << "Exception checking transaction " << txid << ": " << ex.what(); return; } @@ -1244,7 +1118,7 @@ NetworkOPsImp::submitTransaction(std::shared_ptr const& iTrans) auto tx = std::make_shared(trans, reason, app_); - m_job_queue.addJob(jtTRANSACTION, "submitTxn", [this, tx]() { + m_job_queue.addJob(jtTRANSACTION, "SubmitTxn", [this, tx]() { auto t = tx; processTransaction(t, false, false, FailHard::no); }); @@ -1274,19 +1148,15 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr& transaction) { transaction->setStatus(INVALID); transaction->setResult(temINVALID_FLAG); - app_.getHashRouter().setFlags( - transaction->getID(), HashRouterFlags::BAD); + app_.getHashRouter().setFlags(transaction->getID(), HashRouterFlags::BAD); return false; } - // NOTE eahennis - I think this check is redundant, + // NOTE ximinez - I think this check is redundant, // but I'm not 100% sure yet. // If so, only cost is looking up HashRouter flags. - auto const [validity, reason] = - checkValidity(app_.getHashRouter(), sttx, view->rules(), app_.config()); - XRPL_ASSERT( - validity == Validity::Valid, - "ripple::NetworkOPsImp::processTransaction : valid validity"); + auto const [validity, reason] = checkValidity(app_.getHashRouter(), sttx, view->rules(), app_.config()); + XRPL_ASSERT(validity == Validity::Valid, "xrpl::NetworkOPsImp::processTransaction : valid validity"); // Not concerned with local checks at this point. if (validity == Validity::SigBad) @@ -1294,8 +1164,7 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr& transaction) JLOG(m_journal.info()) << "Transaction has bad signature: " << reason; transaction->setStatus(INVALID); transaction->setResult(temBAD_SIGNATURE); - app_.getHashRouter().setFlags( - transaction->getID(), HashRouterFlags::BAD); + app_.getHashRouter().setFlags(transaction->getID(), HashRouterFlags::BAD); return false; } @@ -1325,24 +1194,19 @@ NetworkOPsImp::processTransaction( } void -NetworkOPsImp::doTransactionAsync( - std::shared_ptr transaction, - bool bUnlimited, - FailHard failType) +NetworkOPsImp::doTransactionAsync(std::shared_ptr transaction, bool bUnlimited, FailHard failType) { std::lock_guard lock(mMutex); if (transaction->getApplying()) return; - mTransactions.push_back( - TransactionStatus(transaction, bUnlimited, false, failType)); + mTransactions.push_back(TransactionStatus(transaction, bUnlimited, false, failType)); transaction->setApplying(); if (mDispatchState == DispatchState::none) { - if (m_job_queue.addJob( - jtBATCH, "transactionBatch", [this]() { transactionBatch(); })) + if (m_job_queue.addJob(jtBATCH, "TxBatchAsync", [this]() { transactionBatch(); })) { mDispatchState = DispatchState::scheduled; } @@ -1350,24 +1214,18 @@ NetworkOPsImp::doTransactionAsync( } void -NetworkOPsImp::doTransactionSync( - std::shared_ptr transaction, - bool bUnlimited, - FailHard failType) +NetworkOPsImp::doTransactionSync(std::shared_ptr transaction, bool bUnlimited, FailHard failType) { std::unique_lock lock(mMutex); if (!transaction->getApplying()) { - mTransactions.push_back( - TransactionStatus(transaction, bUnlimited, true, failType)); + mTransactions.push_back(TransactionStatus(transaction, bUnlimited, true, failType)); transaction->setApplying(); } doTransactionSyncBatch( - lock, [&transaction](std::unique_lock const&) { - return transaction->getApplying(); - }); + lock, [&transaction](std::unique_lock const&) { return transaction->getApplying(); }); } void @@ -1389,9 +1247,7 @@ NetworkOPsImp::doTransactionSyncBatch( if (mTransactions.size()) { // More transactions need to be applied, but by another job. - if (m_job_queue.addJob(jtBATCH, "transactionBatch", [this]() { - transactionBatch(); - })) + if (m_job_queue.addJob(jtBATCH, "TxBatchSync", [this]() { transactionBatch(); })) { mDispatchState = DispatchState::scheduled; } @@ -1415,11 +1271,9 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set) { if (!reason.empty()) { - JLOG(m_journal.trace()) - << "Exception checking transaction: " << reason; + JLOG(m_journal.trace()) << "Exception checking transaction: " << reason; } - app_.getHashRouter().setFlags( - tx->getTransactionID(), HashRouterFlags::BAD); + app_.getHashRouter().setFlags(tx->getTransactionID(), HashRouterFlags::BAD); continue; } @@ -1459,13 +1313,9 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set) } doTransactionSyncBatch(lock, [&](std::unique_lock const&) { - XRPL_ASSERT( - lock.owns_lock(), - "ripple::NetworkOPsImp::processTransactionSet has lock"); + XRPL_ASSERT(lock.owns_lock(), "xrpl::NetworkOPsImp::processTransactionSet has lock"); return std::any_of( - mTransactions.begin(), mTransactions.end(), [](auto const& t) { - return t.transaction->getApplying(); - }); + mTransactions.begin(), mTransactions.end(), [](auto const& t) { return t.transaction->getApplying(); }); }); } @@ -1489,12 +1339,8 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) std::vector submit_held; std::vector transactions; mTransactions.swap(transactions); - XRPL_ASSERT( - !transactions.empty(), - "ripple::NetworkOPsImp::apply : non-empty transactions"); - XRPL_ASSERT( - mDispatchState != DispatchState::running, - "ripple::NetworkOPsImp::apply : is not running"); + XRPL_ASSERT(!transactions.empty(), "xrpl::NetworkOPsImp::apply : non-empty transactions"); + XRPL_ASSERT(mDispatchState != DispatchState::running, "xrpl::NetworkOPsImp::apply : is not running"); mDispatchState = DispatchState::running; @@ -1504,8 +1350,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) std::unique_lock masterLock{app_.getMasterMutex(), std::defer_lock}; bool changed = false; { - std::unique_lock ledgerLock{ - m_ledgerMaster.peekMutex(), std::defer_lock}; + std::unique_lock ledgerLock{m_ledgerMaster.peekMutex(), std::defer_lock}; std::lock(masterLock, ledgerLock); app_.openLedger().modify([&](OpenView& view, beast::Journal j) { @@ -1519,8 +1364,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (e.failType == FailHard::yes) flags |= tapFAIL_HARD; - auto const result = app_.getTxQ().apply( - app_, view, e.transaction->getSTransaction(), flags, j); + auto const result = app_.getTxQ().apply(app_, view, e.transaction->getSTransaction(), flags, j); e.result = result.ter; e.applied = result.applied; changed = changed || result.applied; @@ -1533,7 +1377,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) std::optional validatedLedgerIndex; if (auto const l = m_ledgerMaster.getValidatedLedger()) - validatedLedgerIndex = l->info().seq; + validatedLedgerIndex = l->header().seq; auto newOL = app_.openLedger().current(); for (TransactionStatus& e : transactions) @@ -1542,16 +1386,14 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (e.applied) { - pubProposedTransaction( - newOL, e.transaction->getSTransaction(), e.result); + pubProposedTransaction(newOL, e.transaction->getSTransaction(), e.result); e.transaction->setApplied(); } e.transaction->setResult(e.result); if (isTemMalformed(e.result)) - app_.getHashRouter().setFlags( - e.transaction->getID(), HashRouterFlags::BAD); + app_.getHashRouter().setFlags(e.transaction->getID(), HashRouterFlags::BAD); #ifdef DEBUG if (e.result != tesSUCCESS) @@ -1560,8 +1402,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (transResultInfo(e.result, token, human)) { - JLOG(m_journal.info()) - << "TransactionResult: " << token << ": " << human; + JLOG(m_journal.info()) << "TransactionResult: " << token << ": " << human; } } #endif @@ -1570,8 +1411,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (e.result == tesSUCCESS) { - JLOG(m_journal.debug()) - << "Transaction is now included in open ledger"; + JLOG(m_journal.debug()) << "Transaction is now included in open ledger"; e.transaction->setStatus(INCLUDED); // Pop as many "reasonable" transactions for this account as @@ -1580,8 +1420,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) auto const& txCur = e.transaction->getSTransaction(); std::size_t count = 0; - for (auto txNext = m_ledgerMaster.popAcctTransaction(txCur); - txNext && count < maxPoppedTransactions; + for (auto txNext = m_ledgerMaster.popAcctTransaction(txCur); txNext && count < maxPoppedTransactions; txNext = m_ledgerMaster.popAcctTransaction(txCur), ++count) { if (!batchLock.owns_lock()) @@ -1605,9 +1444,8 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) } else if (e.result == terQUEUED) { - JLOG(m_journal.debug()) - << "Transaction is likely to claim a" - << " fee, but is queued until fee drops"; + JLOG(m_journal.debug()) << "Transaction is likely to claim a" + << " fee, but is queued until fee drops"; e.transaction->setStatus(HELD); // Add to held transactions, because it could get @@ -1617,19 +1455,13 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) e.transaction->setQueued(); e.transaction->setKept(); } - else if ( - isTerRetry(e.result) || isTelLocal(e.result) || - isTefFailure(e.result)) + else if (isTerRetry(e.result) || isTelLocal(e.result) || isTefFailure(e.result)) { if (e.failType != FailHard::yes) { - auto const lastLedgerSeq = - e.transaction->getSTransaction()->at( - ~sfLastLedgerSequence); - auto const ledgersLeft = lastLedgerSeq - ? *lastLedgerSeq - - m_ledgerMaster.getCurrentLedgerIndex() - : std::optional{}; + auto const lastLedgerSeq = e.transaction->getSTransaction()->at(~sfLastLedgerSequence); + auto const ledgersLeft = lastLedgerSeq ? *lastLedgerSeq - m_ledgerMaster.getCurrentLedgerIndex() + : std::optional{}; // If any of these conditions are met, the transaction can // be held: // 1. It was submitted locally. (Note that this flag is only @@ -1646,60 +1478,48 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) // the other conditions, so don't hold it again. Time's // up!) // - if (e.local || - (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) || - app_.getHashRouter().setFlags( - e.transaction->getID(), HashRouterFlags::HELD)) + if (e.local || (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) || + app_.getHashRouter().setFlags(e.transaction->getID(), HashRouterFlags::HELD)) { // transaction should be held - JLOG(m_journal.debug()) - << "Transaction should be held: " << e.result; + JLOG(m_journal.debug()) << "Transaction should be held: " << e.result; e.transaction->setStatus(HELD); m_ledgerMaster.addHeldTransaction(e.transaction); e.transaction->setKept(); } else JLOG(m_journal.debug()) - << "Not holding transaction " - << e.transaction->getID() << ": " + << "Not holding transaction " << e.transaction->getID() << ": " << (e.local ? "local" : "network") << ", " - << "result: " << e.result << " ledgers left: " - << (ledgersLeft ? to_string(*ledgersLeft) - : "unspecified"); + << "result: " << e.result + << " ledgers left: " << (ledgersLeft ? to_string(*ledgersLeft) : "unspecified"); } } else { - JLOG(m_journal.debug()) - << "Status other than success " << e.result; + JLOG(m_journal.debug()) << "Status other than success " << e.result; e.transaction->setStatus(INVALID); } - auto const enforceFailHard = - e.failType == FailHard::yes && !isTesSuccess(e.result); + auto const enforceFailHard = e.failType == FailHard::yes && !isTesSuccess(e.result); if (addLocal && !enforceFailHard) { - m_localTX->push_back( - m_ledgerMaster.getCurrentLedgerIndex(), - e.transaction->getSTransaction()); + m_localTX->push_back(m_ledgerMaster.getCurrentLedgerIndex(), e.transaction->getSTransaction()); e.transaction->setKept(); } - if ((e.applied || - ((mMode != OperatingMode::FULL) && - (e.failType != FailHard::yes) && e.local) || + if ((e.applied || ((mMode != OperatingMode::FULL) && (e.failType != FailHard::yes) && e.local) || (e.result == terQUEUED)) && !enforceFailHard) { - auto const toSkip = - app_.getHashRouter().shouldRelay(e.transaction->getID()); - if (auto const sttx = *(e.transaction->getSTransaction()); - toSkip && - // Skip relaying if it's an inner batch txn and batch - // feature is enabled - !(sttx.isFlag(tfInnerBatchTxn) && - newOL->rules().enabled(featureBatch))) + auto const toSkip = app_.getHashRouter().shouldRelay(e.transaction->getID()); + if (auto const sttx = *(e.transaction->getSTransaction()); toSkip && + // Skip relaying if it's an inner batch txn. The flag should + // only be set if the Batch feature is enabled. If Batch is + // not enabled, the flag is always invalid, so don't relay + // it regardless. + !(sttx.isFlag(tfInnerBatchTxn))) { protocol::TMTransaction tx; Serializer s; @@ -1707,8 +1527,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) sttx.add(s); tx.set_rawtransaction(s.data(), s.size()); tx.set_status(protocol::tsCURRENT); - tx.set_receivetimestamp( - app_.timeKeeper().now().time_since_epoch().count()); + tx.set_receivetimestamp(app_.timeKeeper().now().time_since_epoch().count()); tx.set_deferred(e.result == terQUEUED); // FIXME: This should be when we received it app_.overlay().relay(e.transaction->getID(), tx, *toSkip); @@ -1719,10 +1538,8 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (validatedLedgerIndex) { auto [fee, accountSeq, availableSeq] = - app_.getTxQ().getTxRequiredFeeAndSeq( - *newOL, e.transaction->getSTransaction()); - e.transaction->setCurrentLedgerState( - *validatedLedgerIndex, fee, accountSeq, availableSeq); + app_.getTxQ().getTxRequiredFeeAndSeq(*newOL, e.transaction->getSTransaction()); + e.transaction->setCurrentLedgerState(*validatedLedgerIndex, fee, accountSeq, availableSeq); } } } @@ -1754,9 +1571,7 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) // Json::Value -NetworkOPsImp::getOwnerInfo( - std::shared_ptr lpLedger, - AccountID const& account) +NetworkOPsImp::getOwnerInfo(std::shared_ptr lpLedger, AccountID const& account) { Json::Value jvObjects(Json::objectValue); auto root = keylet::ownerDir(account); @@ -1770,30 +1585,24 @@ NetworkOPsImp::getOwnerInfo( for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes)) { auto sleCur = lpLedger->read(keylet::child(uDirEntry)); - XRPL_ASSERT( - sleCur, - "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE"); + XRPL_ASSERT(sleCur, "xrpl::NetworkOPsImp::getOwnerInfo : non-null child SLE"); switch (sleCur->getType()) { case ltOFFER: if (!jvObjects.isMember(jss::offers)) - jvObjects[jss::offers] = - Json::Value(Json::arrayValue); + jvObjects[jss::offers] = Json::Value(Json::arrayValue); - jvObjects[jss::offers].append( - sleCur->getJson(JsonOptions::none)); + jvObjects[jss::offers].append(sleCur->getJson(JsonOptions::none)); break; case ltRIPPLE_STATE: if (!jvObjects.isMember(jss::ripple_lines)) { - jvObjects[jss::ripple_lines] = - Json::Value(Json::arrayValue); + jvObjects[jss::ripple_lines] = Json::Value(Json::arrayValue); } - jvObjects[jss::ripple_lines].append( - sleCur->getJson(JsonOptions::none)); + jvObjects[jss::ripple_lines].append(sleCur->getJson(JsonOptions::none)); break; case ltACCOUNT_ROOT: @@ -1801,7 +1610,7 @@ NetworkOPsImp::getOwnerInfo( // LCOV_EXCL_START default: UNREACHABLE( - "ripple::NetworkOPsImp::getOwnerInfo : invalid " + "xrpl::NetworkOPsImp::getOwnerInfo : invalid " "type"); break; // LCOV_EXCL_STOP @@ -1813,9 +1622,7 @@ NetworkOPsImp::getOwnerInfo( if (uNodeDir) { sleNode = lpLedger->read(keylet::page(root, uNodeDir)); - XRPL_ASSERT( - sleNode, - "ripple::NetworkOPsImp::getOwnerInfo : read next page"); + XRPL_ASSERT(sleNode, "xrpl::NetworkOPsImp::getOwnerInfo : read next page"); } } while (uNodeDir); } @@ -1884,9 +1691,7 @@ NetworkOPsImp::clearUNLBlocked() } bool -NetworkOPsImp::checkLastClosedLedger( - Overlay::PeerSequence const& peerList, - uint256& networkClosed) +NetworkOPsImp::checkLastClosedLedger(Overlay::PeerSequence const& peerList, uint256& networkClosed) { // Returns true if there's an *abnormal* ledger issue, normal changing in // TRACKING mode should return false. Do we have sufficient validations for @@ -1900,8 +1705,8 @@ NetworkOPsImp::checkLastClosedLedger( if (!ourClosed) return false; - uint256 closedLedger = ourClosed->info().hash; - uint256 prevClosedLedger = ourClosed->info().parentHash; + uint256 closedLedger = ourClosed->header().hash; + uint256 prevClosedLedger = ourClosed->header().parentHash; JLOG(m_journal.trace()) << "OurClosed: " << closedLedger; JLOG(m_journal.trace()) << "PrevClosed: " << prevClosedLedger; @@ -1909,8 +1714,7 @@ NetworkOPsImp::checkLastClosedLedger( // Determine preferred last closed ledger auto& validations = app_.getValidations(); - JLOG(m_journal.debug()) - << "ValidationTrie " << Json::Compact(validations.getJsonTrie()); + JLOG(m_journal.debug()) << "ValidationTrie " << Json::Compact(validations.getJsonTrie()); // Will rely on peer LCL if no trusted validations exist hash_map peerCounts; @@ -1942,7 +1746,7 @@ NetworkOPsImp::checkLastClosedLedger( { // don't switch to our own previous ledger JLOG(m_journal.info()) << "We won't switch to our own previous ledger"; - networkClosed = ourClosed->info().hash; + networkClosed = ourClosed->header().hash; switchLedgers = false; } else @@ -1954,23 +1758,20 @@ NetworkOPsImp::checkLastClosedLedger( auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger); if (!consensus) - consensus = app_.getInboundLedgers().acquire( - closedLedger, 0, InboundLedger::Reason::CONSENSUS); + consensus = app_.getInboundLedgers().acquire(closedLedger, 0, InboundLedger::Reason::CONSENSUS); if (consensus && (!m_ledgerMaster.canBeCurrent(consensus) || - !m_ledgerMaster.isCompatible( - *consensus, m_journal.debug(), "Not switching"))) + !m_ledgerMaster.isCompatible(*consensus, m_journal.debug(), "Not switching"))) { // Don't switch to a ledger not on the validated chain // or with an invalid close time or sequence - networkClosed = ourClosed->info().hash; + networkClosed = ourClosed->header().hash; return false; } JLOG(m_journal.warn()) << "We are not running on the consensus ledger"; - JLOG(m_journal.info()) << "Our LCL: " << ourClosed->info().hash - << getJson({*ourClosed, {}}); + JLOG(m_journal.info()) << "Our LCL: " << ourClosed->header().hash << getJson({*ourClosed, {}}); JLOG(m_journal.info()) << "Net LCL " << closedLedger; if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL)) @@ -1990,12 +1791,10 @@ NetworkOPsImp::checkLastClosedLedger( } void -NetworkOPsImp::switchLastClosedLedger( - std::shared_ptr const& newLCL) +NetworkOPsImp::switchLastClosedLedger(std::shared_ptr const& newLCL) { // set the newLCL as our last closed ledger -- this is abnormal code - JLOG(m_journal.error()) - << "JUMP last closed ledger to " << newLCL->info().hash; + JLOG(m_journal.error()) << "JUMP last closed ledger to " << newLCL->header().hash; clearNeedNetworkLedger(); @@ -2033,29 +1832,22 @@ NetworkOPsImp::switchLastClosedLedger( protocol::TMStatusChange s; s.set_newevent(protocol::neSWITCHED_LEDGER); - s.set_ledgerseq(newLCL->info().seq); + s.set_ledgerseq(newLCL->header().seq); s.set_networktime(app_.timeKeeper().now().time_since_epoch().count()); - s.set_ledgerhashprevious( - newLCL->info().parentHash.begin(), newLCL->info().parentHash.size()); - s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size()); + s.set_ledgerhashprevious(newLCL->header().parentHash.begin(), newLCL->header().parentHash.size()); + s.set_ledgerhash(newLCL->header().hash.begin(), newLCL->header().hash.size()); - app_.overlay().foreach( - send_always(std::make_shared(s, protocol::mtSTATUS_CHANGE))); + app_.overlay().foreach(send_always(std::make_shared(s, protocol::mtSTATUS_CHANGE))); } bool -NetworkOPsImp::beginConsensus( - uint256 const& networkClosed, - std::unique_ptr const& clog) +NetworkOPsImp::beginConsensus(uint256 const& networkClosed, std::unique_ptr const& clog) { - XRPL_ASSERT( - networkClosed.isNonZero(), - "ripple::NetworkOPsImp::beginConsensus : nonzero input"); + XRPL_ASSERT(networkClosed.isNonZero(), "xrpl::NetworkOPsImp::beginConsensus : nonzero input"); - auto closingInfo = m_ledgerMaster.getCurrentLedger()->info(); + auto closingInfo = m_ledgerMaster.getCurrentLedger()->header(); - JLOG(m_journal.info()) << "Consensus time for #" << closingInfo.seq - << " with LCL " << closingInfo.parentHash; + JLOG(m_journal.info()) << "Consensus time for #" << closingInfo.seq << " with LCL " << closingInfo.parentHash; auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash); @@ -2074,16 +1866,15 @@ NetworkOPsImp::beginConsensus( } XRPL_ASSERT( - prevLedger->info().hash == closingInfo.parentHash, - "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches " + prevLedger->header().hash == closingInfo.parentHash, + "xrpl::NetworkOPsImp::beginConsensus : prevLedger hash matches " "parent"); XRPL_ASSERT( - closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash, - "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches " + closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->header().hash, + "xrpl::NetworkOPsImp::beginConsensus : closedLedger parent matches " "hash"); - if (prevLedger->rules().enabled(featureNegativeUNL)) - app_.validators().setNegativeUNL(prevLedger->negativeUNL()); + app_.validators().setNegativeUNL(prevLedger->negativeUNL()); TrustChanges const changes = app_.validators().updateTrusted( app_.getValidations().getCurrentNodeIDs(), closingInfo.parentCloseTime, @@ -2095,17 +1886,11 @@ NetworkOPsImp::beginConsensus( { app_.getValidations().trustChanged(changes.added, changes.removed); // Update the AmendmentTable so it tracks the current validators. - app_.getAmendmentTable().trustChanged( - app_.validators().getQuorumKeys().second); + app_.getAmendmentTable().trustChanged(app_.validators().getQuorumKeys().second); } mConsensus.startRound( - app_.timeKeeper().closeTime(), - networkClosed, - prevLedger, - changes.removed, - changes.added, - clog); + app_.timeKeeper().closeTime(), networkClosed, prevLedger, changes.removed, changes.added, clog); ConsensusPhase const currPhase = mConsensus.phase(); if (mLastConsensusPhase != currPhase) @@ -2133,11 +1918,10 @@ NetworkOPsImp::processTrustedProposal(RCLCxPeerPos peerPos) // // Another, innocuous explanation is unusual message routing and delays, // causing this node to receive its own messages back. - JLOG(m_journal.error()) - << "Received a proposal signed by MY KEY from a peer. This may " - "indicate a misconfiguration where another node has the same " - "validator key, or may be caused by unusual message routing and " - "delays."; + JLOG(m_journal.error()) << "Received a proposal signed by MY KEY from a peer. This may " + "indicate a misconfiguration where another node has the same " + "validator key, or may be caused by unusual message routing and " + "delays."; return false; } @@ -2155,8 +1939,7 @@ NetworkOPsImp::mapComplete(std::shared_ptr const& map, bool fromAcquire) protocol::TMHaveTransactionSet msg; msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8); msg.set_status(protocol::tsHAVE); - app_.overlay().foreach( - send_always(std::make_shared(msg, protocol::mtHAVE_SET))); + app_.overlay().foreach(send_always(std::make_shared(msg, protocol::mtHAVE_SET))); // We acquired it because consensus asked us to if (fromAcquire) @@ -2166,7 +1949,7 @@ NetworkOPsImp::mapComplete(std::shared_ptr const& map, bool fromAcquire) void NetworkOPsImp::endConsensus(std::unique_ptr const& clog) { - uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash; + uint256 deadLedger = m_ledgerMaster.getClosedLedger()->header().parentHash; for (auto const& it : app_.overlay().getActivePeers()) { @@ -2178,8 +1961,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr const& clog) } uint256 networkClosed; - bool ledgerChange = - checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed); + bool ledgerChange = checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed); if (networkClosed.isZero()) { @@ -2193,9 +1975,7 @@ NetworkOPsImp::endConsensus(std::unique_ptr const& clog) // timing to make sure there shouldn't be a newer LCL. We need this // information to do the next three tests. - if (((mMode == OperatingMode::CONNECTED) || - (mMode == OperatingMode::SYNCING)) && - !ledgerChange) + if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::SYNCING)) && !ledgerChange) { // Count number of peers that agree with us and UNL nodes whose // validations we have for LCL. If the ledger is good enough, go to @@ -2204,16 +1984,13 @@ NetworkOPsImp::endConsensus(std::unique_ptr const& clog) setMode(OperatingMode::TRACKING); } - if (((mMode == OperatingMode::CONNECTED) || - (mMode == OperatingMode::TRACKING)) && - !ledgerChange) + if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::TRACKING)) && !ledgerChange) { // check if the ledger is good enough to go to FULL // Note: Do not go to FULL if we don't have the previous ledger - // check if the ledger is bad enough to go to CONNECTE D -- TODO + // check if the ledger is bad enough to go to CONNECTED -- TODO auto current = m_ledgerMaster.getCurrentLedger(); - if (app_.timeKeeper().now() < (current->info().parentCloseTime + - 2 * current->info().closeTimeResolution)) + if (app_.timeKeeper().now() < (current->header().parentCloseTime + 2 * current->header().closeTimeResolution)) { setMode(OperatingMode::FULL); } @@ -2244,8 +2021,7 @@ NetworkOPsImp::pubManifest(Manifest const& mo) jvObj[jss::type] = "manifestReceived"; jvObj[jss::master_key] = toBase58(TokenType::NodePublic, mo.masterKey); if (mo.signingKey) - jvObj[jss::signing_key] = - toBase58(TokenType::NodePublic, *mo.signingKey); + jvObj[jss::signing_key] = toBase58(TokenType::NodePublic, *mo.signingKey); jvObj[jss::seq] = Json::UInt(mo.sequence); if (auto sig = mo.getSignature()) jvObj[jss::signature] = strHex(*sig); @@ -2254,8 +2030,7 @@ NetworkOPsImp::pubManifest(Manifest const& mo) jvObj[jss::domain] = mo.domain; jvObj[jss::manifest] = strHex(mo.serialized); - for (auto i = mStreamMaps[sManifests].begin(); - i != mStreamMaps[sManifests].end();) + for (auto i = mStreamMaps[sManifests].begin(); i != mStreamMaps[sManifests].end();) { if (auto p = i->second.lock()) { @@ -2282,11 +2057,9 @@ NetworkOPsImp::ServerFeeSummary::ServerFeeSummary( } bool -NetworkOPsImp::ServerFeeSummary::operator!=( - NetworkOPsImp::ServerFeeSummary const& b) const +NetworkOPsImp::ServerFeeSummary::operator!=(NetworkOPsImp::ServerFeeSummary const& b) const { - if (loadFactorServer != b.loadFactorServer || - loadBaseServer != b.loadBaseServer || baseFee != b.baseFee || + if (loadFactorServer != b.loadFactorServer || loadBaseServer != b.loadBaseServer || baseFee != b.baseFee || em.has_value() != b.em.has_value()) return true; @@ -2294,8 +2067,7 @@ NetworkOPsImp::ServerFeeSummary::operator!=( { return ( em->minProcessingFeeLevel != b.em->minProcessingFeeLevel || - em->openLedgerFeeLevel != b.em->openLedgerFeeLevel || - em->referenceFeeLevel != b.em->referenceFeeLevel); + em->openLedgerFeeLevel != b.em->openLedgerFeeLevel || em->referenceFeeLevel != b.em->referenceFeeLevel); } return false; @@ -2338,27 +2110,19 @@ NetworkOPsImp::pubServer() { auto const loadFactor = std::max( safe_cast(f.loadFactorServer), - mulDiv( - f.em->openLedgerFeeLevel, - f.loadBaseServer, - f.em->referenceFeeLevel) - .value_or(ripple::muldiv_max)); + mulDiv(f.em->openLedgerFeeLevel, f.loadBaseServer, f.em->referenceFeeLevel).value_or(xrpl::muldiv_max)); jvObj[jss::load_factor] = trunc32(loadFactor); - jvObj[jss::load_factor_fee_escalation] = - f.em->openLedgerFeeLevel.jsonClipped(); - jvObj[jss::load_factor_fee_queue] = - f.em->minProcessingFeeLevel.jsonClipped(); - jvObj[jss::load_factor_fee_reference] = - f.em->referenceFeeLevel.jsonClipped(); + jvObj[jss::load_factor_fee_escalation] = f.em->openLedgerFeeLevel.jsonClipped(); + jvObj[jss::load_factor_fee_queue] = f.em->minProcessingFeeLevel.jsonClipped(); + jvObj[jss::load_factor_fee_reference] = f.em->referenceFeeLevel.jsonClipped(); } else jvObj[jss::load_factor] = f.loadFactorServer; mLastFeeSummary = f; - for (auto i = mStreamMaps[sServer].begin(); - i != mStreamMaps[sServer].end();) + for (auto i = mStreamMaps[sServer].begin(); i != mStreamMaps[sServer].end();) { InfoSub::pointer p = i->second.lock(); @@ -2418,8 +2182,7 @@ NetworkOPsImp::pubValidation(std::shared_ptr const& val) auto const signerPublic = val->getSignerPublic(); jvObj[jss::type] = "validationReceived"; - jvObj[jss::validation_public_key] = - toBase58(TokenType::NodePublic, signerPublic); + jvObj[jss::validation_public_key] = toBase58(TokenType::NodePublic, signerPublic); jvObj[jss::ledger_hash] = to_string(val->getLedgerHash()); jvObj[jss::signature] = strHex(val->getSignature()); jvObj[jss::full] = val->isFull(); @@ -2437,8 +2200,7 @@ NetworkOPsImp::pubValidation(std::shared_ptr const& val) if (auto hash = (*val)[~sfValidatedHash]) jvObj[jss::validated_hash] = strHex(*hash); - auto const masterKey = - app_.validatorManifests().getMasterKey(signerPublic); + auto const masterKey = app_.validatorManifests().getMasterKey(signerPublic); if (masterKey != signerPublic) jvObj[jss::master_key] = toBase58(TokenType::NodePublic, masterKey); @@ -2472,16 +2234,13 @@ NetworkOPsImp::pubValidation(std::shared_ptr const& val) // (The ~ operator converts the Proxy to a std::optional, which // simplifies later operations) - if (auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); - baseFeeXRP && baseFeeXRP->native()) + if (auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); baseFeeXRP && baseFeeXRP->native()) jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped(); - if (auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops); - reserveBaseXRP && reserveBaseXRP->native()) + if (auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops); reserveBaseXRP && reserveBaseXRP->native()) jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped(); - if (auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops); - reserveIncXRP && reserveIncXRP->native()) + if (auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops); reserveIncXRP && reserveIncXRP->native()) jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped(); // NOTE Use MultiApiJson to publish two slightly different JSON objects @@ -2493,13 +2252,11 @@ NetworkOPsImp::pubValidation(std::shared_ptr const& val) // Type conversion for older API versions to string if (jvTx.isMember(jss::ledger_index)) { - jvTx[jss::ledger_index] = - std::to_string(jvTx[jss::ledger_index].asUInt()); + jvTx[jss::ledger_index] = std::to_string(jvTx[jss::ledger_index].asUInt()); } }); - for (auto i = mStreamMaps[sValidations].begin(); - i != mStreamMaps[sValidations].end();) + for (auto i = mStreamMaps[sValidations].begin(); i != mStreamMaps[sValidations].end();) { if (auto p = i->second.lock()) { @@ -2527,8 +2284,7 @@ NetworkOPsImp::pubPeerStatus(std::function const& func) jvObj[jss::type] = "peerStatusChange"; - for (auto i = mStreamMaps[sPeerStatus].begin(); - i != mStreamMaps[sPeerStatus].end();) + for (auto i = mStreamMaps[sPeerStatus].begin(); i != mStreamMaps[sPeerStatus].end();) { InfoSub::pointer p = i->second.lock(); @@ -2575,12 +2331,9 @@ NetworkOPsImp::setMode(OperatingMode om) } bool -NetworkOPsImp::recvValidation( - std::shared_ptr const& val, - std::string const& source) +NetworkOPsImp::recvValidation(std::shared_ptr const& val, std::string const& source) { - JLOG(m_journal.trace()) - << "recvValidation " << val->getLedgerHash() << " from " << source; + JLOG(m_journal.trace()) << "recvValidation " << val->getLedgerHash() << " from " << source; std::unique_lock lock(validationsMutex_); BypassAccept bypassAccept = BypassAccept::no; @@ -2595,15 +2348,12 @@ NetworkOPsImp::recvValidation( } catch (std::exception const& e) { - JLOG(m_journal.warn()) - << "Exception thrown for handling new validation " - << val->getLedgerHash() << ": " << e.what(); + JLOG(m_journal.warn()) << "Exception thrown for handling new validation " << val->getLedgerHash() << ": " + << e.what(); } catch (...) { - JLOG(m_journal.warn()) - << "Unknown exception thrown for handling new validation " - << val->getLedgerHash(); + JLOG(m_journal.warn()) << "Unknown exception thrown for handling new validation " << val->getLedgerHash(); } if (bypassAccept == BypassAccept::no) { @@ -2672,8 +2422,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) "One or more unsupported amendments have reached majority. " "Upgrade to the latest version before they are activated " "to avoid being amendment blocked."; - if (auto const expected = - app_.getAmendmentTable().firstUnsupportedExpected()) + if (auto const expected = app_.getAmendmentTable().firstUnsupportedExpected()) { auto& d = w[jss::details] = Json::objectValue; d[jss::expected_date] = expected->time_since_epoch().count(); @@ -2697,14 +2446,12 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) info[jss::server_state] = strOperatingMode(admin); - info[jss::time] = to_string(std::chrono::floor( - std::chrono::system_clock::now())); + info[jss::time] = to_string(std::chrono::floor(std::chrono::system_clock::now())); if (needNetworkLedger_) info[jss::network_ledger] = "waiting"; - info[jss::validation_quorum] = - static_cast(app_.validators().quorum()); + info[jss::validation_quorum] = static_cast(app_.validators().quorum()); if (admin) { @@ -2732,8 +2479,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (!human) { if (when) - info[jss::validator_list_expires] = - safe_cast(when->time_since_epoch().count()); + info[jss::validator_list_expires] = safe_cast(when->time_since_epoch().count()); else info[jss::validator_list_expires] = 0; } @@ -2779,16 +2525,13 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) } #endif } - info[jss::io_latency_ms] = - static_cast(app_.getIOLatency().count()); + info[jss::io_latency_ms] = static_cast(app_.getIOLatency().count()); if (admin) { - if (auto const localPubKey = app_.validators().localPublicKey(); - localPubKey && app_.getValidationPublicKey()) + if (auto const localPubKey = app_.validators().localPublicKey(); localPubKey && app_.getValidationPublicKey()) { - info[jss::pubkey_validator] = - toBase58(TokenType::NodePublic, localPubKey.value()); + info[jss::pubkey_validator] = toBase58(TokenType::NodePublic, localPubKey.value()); } else { @@ -2806,8 +2549,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) info[jss::current_activities] = app_.getPerfLog().currentJson(); } - info[jss::pubkey_node] = - toBase58(TokenType::NodePublic, app_.nodeIdentity().first); + info[jss::pubkey_node] = toBase58(TokenType::NodePublic, app_.nodeIdentity().first); info[jss::complete_ledgers] = app_.getLedgerMaster().getCompleteLedgers(); @@ -2826,13 +2568,11 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (human) { - lastClose[jss::converge_time_s] = - std::chrono::duration{mConsensus.prevRoundTime()}.count(); + lastClose[jss::converge_time_s] = std::chrono::duration{mConsensus.prevRoundTime()}.count(); } else { - lastClose[jss::converge_time] = - Json::Int(mConsensus.prevRoundTime().count()); + lastClose[jss::converge_time] = Json::Int(mConsensus.prevRoundTime().count()); } info[jss::last_close] = lastClose; @@ -2845,8 +2585,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (auto const netid = app_.overlay().networkID()) info[jss::network_id] = static_cast(*netid); - auto const escalationMetrics = - app_.getTxQ().getMetrics(*app_.openLedger().current()); + auto const escalationMetrics = app_.getTxQ().getMetrics(*app_.openLedger().current()); auto const loadFactorServer = app_.getFeeTrack().getLoadFactor(); auto const loadBaseServer = app_.getFeeTrack().getLoadBase(); @@ -2854,14 +2593,10 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) In practice, this just strips the units, but it will continue to work correctly if either base value ever changes. */ auto const loadFactorFeeEscalation = - mulDiv( - escalationMetrics.openLedgerFeeLevel, - loadBaseServer, - escalationMetrics.referenceFeeLevel) - .value_or(ripple::muldiv_max); + mulDiv(escalationMetrics.openLedgerFeeLevel, loadBaseServer, escalationMetrics.referenceFeeLevel) + .value_or(xrpl::muldiv_max); - auto const loadFactor = std::max( - safe_cast(loadFactorServer), loadFactorFeeEscalation); + auto const loadFactor = std::max(safe_cast(loadFactorServer), loadFactorFeeEscalation); if (!human) { @@ -2874,48 +2609,36 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) probably isn't enough extant XRP to drive the factor that high. */ - info[jss::load_factor_fee_escalation] = - escalationMetrics.openLedgerFeeLevel.jsonClipped(); - info[jss::load_factor_fee_queue] = - escalationMetrics.minProcessingFeeLevel.jsonClipped(); - info[jss::load_factor_fee_reference] = - escalationMetrics.referenceFeeLevel.jsonClipped(); + info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.jsonClipped(); + info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.jsonClipped(); + info[jss::load_factor_fee_reference] = escalationMetrics.referenceFeeLevel.jsonClipped(); } else { - info[jss::load_factor] = - static_cast(loadFactor) / loadBaseServer; + info[jss::load_factor] = static_cast(loadFactor) / loadBaseServer; if (loadFactorServer != loadFactor) - info[jss::load_factor_server] = - static_cast(loadFactorServer) / loadBaseServer; + info[jss::load_factor_server] = static_cast(loadFactorServer) / loadBaseServer; if (admin) { std::uint32_t fee = app_.getFeeTrack().getLocalFee(); if (fee != loadBaseServer) - info[jss::load_factor_local] = - static_cast(fee) / loadBaseServer; + info[jss::load_factor_local] = static_cast(fee) / loadBaseServer; fee = app_.getFeeTrack().getRemoteFee(); if (fee != loadBaseServer) - info[jss::load_factor_net] = - static_cast(fee) / loadBaseServer; + info[jss::load_factor_net] = static_cast(fee) / loadBaseServer; fee = app_.getFeeTrack().getClusterFee(); if (fee != loadBaseServer) - info[jss::load_factor_cluster] = - static_cast(fee) / loadBaseServer; + info[jss::load_factor_cluster] = static_cast(fee) / loadBaseServer; } - if (escalationMetrics.openLedgerFeeLevel != - escalationMetrics.referenceFeeLevel && + if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel && (admin || loadFactorFeeEscalation != loadFactor)) info[jss::load_factor_fee_escalation] = - escalationMetrics.openLedgerFeeLevel.decimalFromReference( - escalationMetrics.referenceFeeLevel); - if (escalationMetrics.minProcessingFeeLevel != - escalationMetrics.referenceFeeLevel) + escalationMetrics.openLedgerFeeLevel.decimalFromReference(escalationMetrics.referenceFeeLevel); + if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel) info[jss::load_factor_fee_queue] = - escalationMetrics.minProcessingFeeLevel.decimalFromReference( - escalationMetrics.referenceFeeLevel); + escalationMetrics.minProcessingFeeLevel.decimalFromReference(escalationMetrics.referenceFeeLevel); } bool valid = false; @@ -2930,16 +2653,15 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) { XRPAmount const baseFee = lpClosed->fees().base; Json::Value l(Json::objectValue); - l[jss::seq] = Json::UInt(lpClosed->info().seq); - l[jss::hash] = to_string(lpClosed->info().hash); + l[jss::seq] = Json::UInt(lpClosed->header().seq); + l[jss::hash] = to_string(lpClosed->header().hash); if (!human) { l[jss::base_fee] = baseFee.jsonClipped(); l[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped(); l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped(); - l[jss::close_time] = Json::Value::UInt( - lpClosed->info().closeTime.time_since_epoch().count()); + l[jss::close_time] = Json::Value::UInt(lpClosed->header().closeTime.time_since_epoch().count()); } else { @@ -2947,28 +2669,24 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) l[jss::reserve_base_xrp] = lpClosed->fees().reserve.decimalXRP(); l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP(); - if (auto const closeOffset = app_.timeKeeper().closeOffset(); - std::abs(closeOffset.count()) >= 60) - l[jss::close_time_offset] = - static_cast(closeOffset.count()); + if (auto const closeOffset = app_.timeKeeper().closeOffset(); std::abs(closeOffset.count()) >= 60) + l[jss::close_time_offset] = static_cast(closeOffset.count()); constexpr std::chrono::seconds highAgeThreshold{1000000}; if (m_ledgerMaster.haveValidated()) { auto const age = m_ledgerMaster.getValidatedLedgerAge(); - l[jss::age] = - Json::UInt(age < highAgeThreshold ? age.count() : 0); + l[jss::age] = Json::UInt(age < highAgeThreshold ? age.count() : 0); } else { - auto lCloseTime = lpClosed->info().closeTime; + auto lCloseTime = lpClosed->header().closeTime; auto closeTime = app_.timeKeeper().closeTime(); if (lCloseTime <= closeTime) { using namespace std::chrono_literals; auto age = closeTime - lCloseTime; - l[jss::age] = - Json::UInt(age < highAgeThreshold ? age.count() : 0); + l[jss::age] = Json::UInt(age < highAgeThreshold ? age.count() : 0); } } } @@ -2981,22 +2699,18 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) auto lpPublished = m_ledgerMaster.getPublishedLedger(); if (!lpPublished) info[jss::published_ledger] = "none"; - else if (lpPublished->info().seq != lpClosed->info().seq) - info[jss::published_ledger] = lpPublished->info().seq; + else if (lpPublished->header().seq != lpClosed->header().seq) + info[jss::published_ledger] = lpPublished->header().seq; } accounting_.json(info); info[jss::uptime] = UptimeClock::now().time_since_epoch().count(); - info[jss::jq_trans_overflow] = - std::to_string(app_.overlay().getJqTransOverflow()); - info[jss::peer_disconnects] = - std::to_string(app_.overlay().getPeerDisconnect()); - info[jss::peer_disconnects_resources] = - std::to_string(app_.overlay().getPeerDisconnectCharges()); + info[jss::jq_trans_overflow] = std::to_string(app_.overlay().getJqTransOverflow()); + info[jss::peer_disconnects] = std::to_string(app_.overlay().getPeerDisconnect()); + info[jss::peer_disconnects_resources] = std::to_string(app_.overlay().getPeerDisconnectCharges()); // This array must be sorted in increasing order. - static constexpr std::array protocols{ - "http", "https", "peer", "ws", "ws2", "wss", "wss2"}; + static constexpr std::array protocols{"http", "https", "peer", "ws", "ws2", "wss", "wss2"}; static_assert(std::is_sorted(std::begin(protocols), std::end(protocols))); { Json::Value ports{Json::arrayValue}; @@ -3004,8 +2718,8 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) { // Don't publish admin ports for non-admin users if (!admin && - !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() && - port.admin_user.empty() && port.admin_password.empty())) + !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() && port.admin_user.empty() && + port.admin_password.empty())) continue; std::vector proto; std::set_intersection( @@ -3060,13 +2774,14 @@ NetworkOPsImp::pubProposedTransaction( std::shared_ptr const& transaction, TER result) { - // never publish an inner txn inside a batch txn - if (transaction->isFlag(tfInnerBatchTxn) && - ledger->rules().enabled(featureBatch)) + // never publish an inner txn inside a batch txn. The flag should + // only be set if the Batch feature is enabled. If Batch is not + // enabled, the flag is always invalid, so don't publish it + // regardless. + if (transaction->isFlag(tfInnerBatchTxn)) return; - MultiApiJson jvObj = - transJson(transaction, result, false, ledger, std::nullopt); + MultiApiJson jvObj = transJson(transaction, result, false, ledger, std::nullopt); { std::lock_guard sl(mSubLock); @@ -3099,23 +2814,17 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) // Ledgers are published only when they acquire sufficient validations // Holes are filled across connection loss or other catastrophe - std::shared_ptr alpAccepted = - app_.getAcceptedLedgerCache().fetch(lpAccepted->info().hash); + std::shared_ptr alpAccepted = app_.getAcceptedLedgerCache().fetch(lpAccepted->header().hash); if (!alpAccepted) { alpAccepted = std::make_shared(lpAccepted, app_); - app_.getAcceptedLedgerCache().canonicalize_replace_client( - lpAccepted->info().hash, alpAccepted); + app_.getAcceptedLedgerCache().canonicalize_replace_client(lpAccepted->header().hash, alpAccepted); } - XRPL_ASSERT( - alpAccepted->getLedger().get() == lpAccepted.get(), - "ripple::NetworkOPsImp::pubLedger : accepted input"); + XRPL_ASSERT(alpAccepted->getLedger().get() == lpAccepted.get(), "xrpl::NetworkOPsImp::pubLedger : accepted input"); { - JLOG(m_journal.debug()) - << "Publishing ledger " << lpAccepted->info().seq << " " - << lpAccepted->info().hash; + JLOG(m_journal.debug()) << "Publishing ledger " << lpAccepted->header().seq << " " << lpAccepted->header().hash; std::lock_guard sl(mSubLock); @@ -3124,10 +2833,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) Json::Value jvObj(Json::objectValue); jvObj[jss::type] = "ledgerClosed"; - jvObj[jss::ledger_index] = lpAccepted->info().seq; - jvObj[jss::ledger_hash] = to_string(lpAccepted->info().hash); - jvObj[jss::ledger_time] = Json::Value::UInt( - lpAccepted->info().closeTime.time_since_epoch().count()); + jvObj[jss::ledger_index] = lpAccepted->header().seq; + jvObj[jss::ledger_hash] = to_string(lpAccepted->header().hash); + jvObj[jss::ledger_time] = Json::Value::UInt(lpAccepted->header().closeTime.time_since_epoch().count()); jvObj[jss::network_id] = app_.config().NETWORK_ID; @@ -3135,15 +2843,13 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) jvObj[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED; jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped(); jvObj[jss::reserve_base] = lpAccepted->fees().reserve.jsonClipped(); - jvObj[jss::reserve_inc] = - lpAccepted->fees().increment.jsonClipped(); + jvObj[jss::reserve_inc] = lpAccepted->fees().increment.jsonClipped(); jvObj[jss::txn_count] = Json::UInt(alpAccepted->size()); if (mMode >= OperatingMode::SYNCING) { - jvObj[jss::validated_ledgers] = - app_.getLedgerMaster().getCompleteLedgers(); + jvObj[jss::validated_ledgers] = app_.getLedgerMaster().getCompleteLedgers(); } auto it = mStreamMaps[sLedger].begin(); @@ -3162,7 +2868,7 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) if (!mStreamMaps[sBookChanges].empty()) { - Json::Value jvObj = ripple::RPC::computeBookChanges(lpAccepted); + Json::Value jvObj = xrpl::RPC::computeBookChanges(lpAccepted); auto it = mStreamMaps[sBookChanges].begin(); while (it != mStreamMaps[sBookChanges].end()) @@ -3191,8 +2897,7 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) auto& subInfo = inner.second; if (subInfo.index_->separationLedgerSeq_ == 0) { - subAccountHistoryStart( - alpAccepted->getLedger(), subInfo); + subAccountHistoryStart(alpAccepted->getLedger(), subInfo); } } } @@ -3204,8 +2909,7 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) for (auto const& accTx : *alpAccepted) { JLOG(m_journal.trace()) << "pubAccepted: " << accTx->getJson(); - pubValidatedTransaction( - lpAccepted, *accTx, accTx == *(--alpAccepted->end())); + pubValidatedTransaction(lpAccepted, *accTx, accTx == *(--alpAccepted->end())); } } @@ -3220,20 +2924,14 @@ NetworkOPsImp::reportFeeChange() // only schedule the job if something has changed if (f != mLastFeeSummary) { - m_job_queue.addJob( - jtCLIENT_FEE_CHANGE, "reportFeeChange->pubServer", [this]() { - pubServer(); - }); + m_job_queue.addJob(jtCLIENT_FEE_CHANGE, "PubFee", [this]() { pubServer(); }); } } void NetworkOPsImp::reportConsensusStateChange(ConsensusPhase phase) { - m_job_queue.addJob( - jtCLIENT_CONSENSUS, - "reportConsensusStateChange->pubConsensus", - [this, phase]() { pubConsensus(phase); }); + m_job_queue.addJob(jtCLIENT_CONSENSUS, "PubCons", [this, phase]() { pubConsensus(phase); }); } inline void @@ -3267,17 +2965,14 @@ NetworkOPsImp::transJson( // NOTE jvObj is not a finished object for either API version. After // it's populated, we need to finish it for a specific API version. This is // done in a loop, near the end of this function. - jvObj[jss::transaction] = - transaction->getJson(JsonOptions::disable_API_prior_V2, false); + jvObj[jss::transaction] = transaction->getJson(JsonOptions::disable_API_prior_V2, false); if (meta) { jvObj[jss::meta] = meta->get().getJson(JsonOptions::none); - RPC::insertDeliveredAmount( - jvObj[jss::meta], *ledger, transaction, meta->get()); + RPC::insertDeliveredAmount(jvObj[jss::meta], *ledger, transaction, meta->get()); RPC::insertNFTSyntheticInJson(jvObj, transaction, meta->get()); - RPC::insertMPTokenIssuanceID( - jvObj[jss::meta], transaction, meta->get()); + RPC::insertMPTokenIssuanceID(jvObj[jss::meta], transaction, meta->get()); } // add CTID where the needed data for it exists @@ -3289,28 +2984,25 @@ NetworkOPsImp::transJson( if (transaction->isFieldPresent(sfNetworkID)) netID = transaction->getFieldU32(sfNetworkID); - if (std::optional ctid = - RPC::encodeCTID(ledger->info().seq, txnSeq, netID); - ctid) + if (std::optional ctid = RPC::encodeCTID(ledger->header().seq, txnSeq, netID); ctid) jvObj[jss::ctid] = *ctid; } if (!ledger->open()) - jvObj[jss::ledger_hash] = to_string(ledger->info().hash); + jvObj[jss::ledger_hash] = to_string(ledger->header().hash); if (validated) { - jvObj[jss::ledger_index] = ledger->info().seq; - jvObj[jss::transaction][jss::date] = - ledger->info().closeTime.time_since_epoch().count(); + jvObj[jss::ledger_index] = ledger->header().seq; + jvObj[jss::transaction][jss::date] = ledger->header().closeTime.time_since_epoch().count(); jvObj[jss::validated] = true; - jvObj[jss::close_time_iso] = to_string_iso(ledger->info().closeTime); + jvObj[jss::close_time_iso] = to_string_iso(ledger->header().closeTime); // WRITEME: Put the account next seq here } else { jvObj[jss::validated] = false; - jvObj[jss::ledger_current_index] = ledger->info().seq; + jvObj[jss::ledger_current_index] = ledger->header().seq; } jvObj[jss::status] = validated ? "closed" : "proposed"; @@ -3326,12 +3018,7 @@ NetworkOPsImp::transJson( // If the offer create is not self funded then add the owner balance if (account != amount.issue().account) { - auto const ownerFunds = accountFunds( - *ledger, - account, - amount, - fhIGNORE_FREEZE, - app_.journal("View")); + auto const ownerFunds = accountFunds(*ledger, account, amount, fhIGNORE_FREEZE, app_.journal("View")); jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText(); } } @@ -3340,10 +3027,8 @@ NetworkOPsImp::transJson( MultiApiJson multiObj{jvObj}; forAllApiVersions( multiObj.visit(), // - [&]( - Json::Value& jvTx, std::integral_constant) { - RPC::insertDeliverMax( - jvTx[jss::transaction], transaction->getTxnType(), Version); + [&](Json::Value& jvTx, std::integral_constant) { + RPC::insertDeliverMax(jvTx[jss::transaction], transaction->getTxnType(), Version); if constexpr (Version > 1) { @@ -3430,13 +3115,11 @@ NetworkOPsImp::pubAccountTransaction( { std::lock_guard sl(mSubLock); - if (!mSubAccount.empty() || !mSubRTAccount.empty() || - !mSubAccountHistory.empty()) + if (!mSubAccount.empty() || !mSubRTAccount.empty() || !mSubAccountHistory.empty()) { for (auto const& affectedAccount : transaction.getAffected()) { - if (auto simiIt = mSubRTAccount.find(affectedAccount); - simiIt != mSubRTAccount.end()) + if (auto simiIt = mSubRTAccount.find(affectedAccount); simiIt != mSubRTAccount.end()) { auto it = simiIt->second.begin(); @@ -3455,8 +3138,7 @@ NetworkOPsImp::pubAccountTransaction( } } - if (auto simiIt = mSubAccount.find(affectedAccount); - simiIt != mSubAccount.end()) + if (auto simiIt = mSubAccount.find(affectedAccount); simiIt != mSubAccount.end()) { auto it = simiIt->second.begin(); while (it != simiIt->second.end()) @@ -3474,10 +3156,9 @@ NetworkOPsImp::pubAccountTransaction( } } - if (auto histoIt = mSubAccountHistory.find(affectedAccount); - histoIt != mSubAccountHistory.end()) + if (auto historyIt = mSubAccountHistory.find(affectedAccount); historyIt != mSubAccountHistory.end()) { - auto& subs = histoIt->second; + auto& subs = historyIt->second; auto it = subs.begin(); while (it != subs.end()) { @@ -3490,8 +3171,7 @@ NetworkOPsImp::pubAccountTransaction( if (auto isSptr = info.sinkWptr_.lock(); isSptr) { - accountHistoryNotify.emplace_back( - SubAccountHistoryInfo{isSptr, info.index_}); + accountHistoryNotify.emplace_back(SubAccountHistoryInfo{isSptr, info.index_}); ++it; } else @@ -3500,15 +3180,14 @@ NetworkOPsImp::pubAccountTransaction( } } if (subs.empty()) - mSubAccountHistory.erase(histoIt); + mSubAccountHistory.erase(historyIt); } } } } - JLOG(m_journal.trace()) - << "pubAccountTransaction: " - << "proposed=" << iProposed << ", accepted=" << iAccepted; + JLOG(m_journal.trace()) << "pubAccountTransaction: " + << "proposed=" << iProposed << ", accepted=" << iAccepted; if (!notify.empty() || !accountHistoryNotify.empty()) { @@ -3530,9 +3209,8 @@ NetworkOPsImp::pubAccountTransaction( jvObj.set(jss::account_history_boundary, true); XRPL_ASSERT( - jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none, - "ripple::NetworkOPsImp::pubAccountTransaction : " + jvObj.isMember(jss::account_history_tx_stream) == MultiApiJson::none, + "xrpl::NetworkOPsImp::pubAccountTransaction : " "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { @@ -3566,13 +3244,11 @@ NetworkOPsImp::pubProposedAccountTransaction( if (mSubRTAccount.empty()) return; - if (!mSubAccount.empty() || !mSubRTAccount.empty() || - !mSubAccountHistory.empty()) + if (!mSubAccount.empty() || !mSubRTAccount.empty() || !mSubAccountHistory.empty()) { for (auto const& affectedAccount : tx->getMentionedAccounts()) { - if (auto simiIt = mSubRTAccount.find(affectedAccount); - simiIt != mSubRTAccount.end()) + if (auto simiIt = mSubRTAccount.find(affectedAccount); simiIt != mSubRTAccount.end()) { auto it = simiIt->second.begin(); @@ -3607,9 +3283,8 @@ NetworkOPsImp::pubProposedAccountTransaction( [&](Json::Value const& jv) { isrListener->send(jv, true); }); XRPL_ASSERT( - jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none, - "ripple::NetworkOPs::pubProposedAccountTransaction : " + jvObj.isMember(jss::account_history_tx_stream) == MultiApiJson::none, + "xrpl::NetworkOPs::pubProposedAccountTransaction : " "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { @@ -3629,17 +3304,13 @@ NetworkOPsImp::pubProposedAccountTransaction( // void -NetworkOPsImp::subAccount( - InfoSub::ref isrListener, - hash_set const& vnaAccountIDs, - bool rt) +NetworkOPsImp::subAccount(InfoSub::ref isrListener, hash_set const& vnaAccountIDs, bool rt) { SubInfoMapType& subMap = rt ? mSubRTAccount : mSubAccount; for (auto const& naAccountID : vnaAccountIDs) { - JLOG(m_journal.trace()) - << "subAccount: account: " << toBase58(naAccountID); + JLOG(m_journal.trace()) << "subAccount: account: " << toBase58(naAccountID); isrListener->insertSubAccountInfo(naAccountID, rt); } @@ -3651,7 +3322,7 @@ NetworkOPsImp::subAccount( auto simIterator = subMap.find(naAccountID); if (simIterator == subMap.end()) { - // Not found, note that account has a new single listner. + // Not found, note that account has a new single listener. SubMapType usisElement; usisElement[isrListener->getSeq()] = isrListener; // VFALCO NOTE This is making a needless copy of naAccountID @@ -3666,10 +3337,7 @@ NetworkOPsImp::subAccount( } void -NetworkOPsImp::unsubAccount( - InfoSub::ref isrListener, - hash_set const& vnaAccountIDs, - bool rt) +NetworkOPsImp::unsubAccount(InfoSub::ref isrListener, hash_set const& vnaAccountIDs, bool rt) { for (auto const& naAccountID : vnaAccountIDs) { @@ -3682,10 +3350,7 @@ NetworkOPsImp::unsubAccount( } void -NetworkOPsImp::unsubAccountInternal( - std::uint64_t uSeq, - hash_set const& vnaAccountIDs, - bool rt) +NetworkOPsImp::unsubAccountInternal(std::uint64_t uSeq, hash_set const& vnaAccountIDs, bool rt) { std::lock_guard sl(mSubLock); @@ -3726,11 +3391,9 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) if (databaseType == DatabaseType::None) { // LCOV_EXCL_START - UNREACHABLE( - "ripple::NetworkOPsImp::addAccountHistoryJob : no database"); - JLOG(m_journal.error()) - << "AccountHistory job for account " - << toBase58(subInfo.index_->accountId_) << " no database"; + UNREACHABLE("xrpl::NetworkOPsImp::addAccountHistoryJob : no database"); + JLOG(m_journal.error()) << "AccountHistory job for account " << toBase58(subInfo.index_->accountId_) + << " no database"; if (auto sptr = subInfo.sinkWptr_.lock(); sptr) { sptr->send(rpcError(rpcINTERNAL), true); @@ -3740,299 +3403,252 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) // LCOV_EXCL_STOP } - app_.getJobQueue().addJob( - jtCLIENT_ACCT_HIST, - "AccountHistoryTxStream", - [this, dbType = databaseType, subInfo]() { - auto const& accountId = subInfo.index_->accountId_; - auto& lastLedgerSeq = subInfo.index_->historyLastLedgerSeq_; - auto& txHistoryIndex = subInfo.index_->historyTxIndex_; + app_.getJobQueue().addJob(jtCLIENT_ACCT_HIST, "HistTxStream", [this, dbType = databaseType, subInfo]() { + auto const& accountId = subInfo.index_->accountId_; + auto& lastLedgerSeq = subInfo.index_->historyLastLedgerSeq_; + auto& txHistoryIndex = subInfo.index_->historyTxIndex_; - JLOG(m_journal.trace()) - << "AccountHistory job for account " << toBase58(accountId) - << " started. lastLedgerSeq=" << lastLedgerSeq; + JLOG(m_journal.trace()) << "AccountHistory job for account " << toBase58(accountId) + << " started. lastLedgerSeq=" << lastLedgerSeq; - auto isFirstTx = [&](std::shared_ptr const& tx, - std::shared_ptr const& meta) -> bool { - /* - * genesis account: first tx is the one with seq 1 - * other account: first tx is the one created the account - */ - if (accountId == genesisAccountId) + auto isFirstTx = [&](std::shared_ptr const& tx, std::shared_ptr const& meta) -> bool { + /* + * genesis account: first tx is the one with seq 1 + * other account: first tx is the one created the account + */ + if (accountId == genesisAccountId) + { + auto stx = tx->getSTransaction(); + if (stx->getAccountID(sfAccount) == accountId && stx->getSeqValue() == 1) + return true; + } + + for (auto& node : meta->getNodes()) + { + if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT) + continue; + + if (node.isFieldPresent(sfNewFields)) { - auto stx = tx->getSTransaction(); - if (stx->getAccountID(sfAccount) == accountId && - stx->getSeqValue() == 1) - return true; - } - - for (auto& node : meta->getNodes()) - { - if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT) - continue; - - if (node.isFieldPresent(sfNewFields)) + if (auto inner = dynamic_cast(node.peekAtPField(sfNewFields)); inner) { - if (auto inner = dynamic_cast( - node.peekAtPField(sfNewFields)); - inner) + if (inner->isFieldPresent(sfAccount) && inner->getAccountID(sfAccount) == accountId) { - if (inner->isFieldPresent(sfAccount) && - inner->getAccountID(sfAccount) == accountId) - { - return true; - } + return true; } } } + } - return false; - }; + return false; + }; - auto send = [&](Json::Value const& jvObj, - bool unsubscribe) -> bool { - if (auto sptr = subInfo.sinkWptr_.lock()) - { - sptr->send(jvObj, true); - if (unsubscribe) - unsubAccountHistory(sptr, accountId, false); - return true; - } - - return false; - }; - - auto sendMultiApiJson = [&](MultiApiJson const& jvObj, - bool unsubscribe) -> bool { - if (auto sptr = subInfo.sinkWptr_.lock()) - { - jvObj.visit( - sptr->getApiVersion(), // - [&](Json::Value const& jv) { sptr->send(jv, true); }); - - if (unsubscribe) - unsubAccountHistory(sptr, accountId, false); - return true; - } - - return false; - }; - - auto getMoreTxns = - [&](std::uint32_t minLedger, - std::uint32_t maxLedger, - std::optional marker) - -> std::optional>> { - switch (dbType) - { - case Sqlite: { - auto db = static_cast( - &app_.getRelationalDatabase()); - RelationalDatabase::AccountTxPageOptions options{ - accountId, minLedger, maxLedger, marker, 0, true}; - return db->newestAccountTxPage(options); - } - // LCOV_EXCL_START - default: { - UNREACHABLE( - "ripple::NetworkOPsImp::addAccountHistoryJob : " - "getMoreTxns : invalid database type"); - return {}; - } - // LCOV_EXCL_STOP - } - }; - - /* - * search backward until the genesis ledger or asked to stop - */ - while (lastLedgerSeq >= 2 && !subInfo.index_->stopHistorical_) + auto send = [&](Json::Value const& jvObj, bool unsubscribe) -> bool { + if (auto sptr = subInfo.sinkWptr_.lock()) { - int feeChargeCount = 0; - if (auto sptr = subInfo.sinkWptr_.lock(); sptr) - { - sptr->getConsumer().charge(Resource::feeMediumBurdenRPC); - ++feeChargeCount; + sptr->send(jvObj, true); + if (unsubscribe) + unsubAccountHistory(sptr, accountId, false); + return true; + } + + return false; + }; + + auto sendMultiApiJson = [&](MultiApiJson const& jvObj, bool unsubscribe) -> bool { + if (auto sptr = subInfo.sinkWptr_.lock()) + { + jvObj.visit( + sptr->getApiVersion(), // + [&](Json::Value const& jv) { sptr->send(jv, true); }); + + if (unsubscribe) + unsubAccountHistory(sptr, accountId, false); + return true; + } + + return false; + }; + + auto getMoreTxns = [&](std::uint32_t minLedger, + std::uint32_t maxLedger, + std::optional marker) + -> std::optional< + std::pair>> { + switch (dbType) + { + case Sqlite: { + auto db = static_cast(&app_.getRelationalDatabase()); + RelationalDatabase::AccountTxPageOptions options{accountId, minLedger, maxLedger, marker, 0, true}; + return db->newestAccountTxPage(options); } - else - { - JLOG(m_journal.trace()) - << "AccountHistory job for account " - << toBase58(accountId) << " no InfoSub. Fee charged " - << feeChargeCount << " times."; - return; + // LCOV_EXCL_START + default: { + UNREACHABLE( + "xrpl::NetworkOPsImp::addAccountHistoryJob : " + "getMoreTxns : invalid database type"); + return {}; } + // LCOV_EXCL_STOP + } + }; - // try to search in 1024 ledgers till reaching genesis ledgers - auto startLedgerSeq = - (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2); - JLOG(m_journal.trace()) - << "AccountHistory job for account " << toBase58(accountId) - << ", working on ledger range [" << startLedgerSeq << "," - << lastLedgerSeq << "]"; + /* + * search backward until the genesis ledger or asked to stop + */ + while (lastLedgerSeq >= 2 && !subInfo.index_->stopHistorical_) + { + int feeChargeCount = 0; + if (auto sptr = subInfo.sinkWptr_.lock(); sptr) + { + sptr->getConsumer().charge(Resource::feeMediumBurdenRPC); + ++feeChargeCount; + } + else + { + JLOG(m_journal.trace()) << "AccountHistory job for account " << toBase58(accountId) + << " no InfoSub. Fee charged " << feeChargeCount << " times."; + return; + } - auto haveRange = [&]() -> bool { - std::uint32_t validatedMin = UINT_MAX; - std::uint32_t validatedMax = 0; - auto haveSomeValidatedLedgers = - app_.getLedgerMaster().getValidatedRange( - validatedMin, validatedMax); + // try to search in 1024 ledgers till reaching genesis ledgers + auto startLedgerSeq = (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2); + JLOG(m_journal.trace()) << "AccountHistory job for account " << toBase58(accountId) + << ", working on ledger range [" << startLedgerSeq << "," << lastLedgerSeq << "]"; - return haveSomeValidatedLedgers && - validatedMin <= startLedgerSeq && - lastLedgerSeq <= validatedMax; - }(); + auto haveRange = [&]() -> bool { + std::uint32_t validatedMin = UINT_MAX; + std::uint32_t validatedMax = 0; + auto haveSomeValidatedLedgers = app_.getLedgerMaster().getValidatedRange(validatedMin, validatedMax); - if (!haveRange) + return haveSomeValidatedLedgers && validatedMin <= startLedgerSeq && lastLedgerSeq <= validatedMax; + }(); + + if (!haveRange) + { + JLOG(m_journal.debug()) << "AccountHistory reschedule job for account " << toBase58(accountId) + << ", incomplete ledger range [" << startLedgerSeq << "," << lastLedgerSeq + << "]"; + setAccountHistoryJobTimer(subInfo); + return; + } + + std::optional marker{}; + while (!subInfo.index_->stopHistorical_) + { + auto dbResult = getMoreTxns(startLedgerSeq, lastLedgerSeq, marker); + if (!dbResult) { + // LCOV_EXCL_START + UNREACHABLE( + "xrpl::NetworkOPsImp::addAccountHistoryJob : " + "getMoreTxns failed"); JLOG(m_journal.debug()) - << "AccountHistory reschedule job for account " - << toBase58(accountId) << ", incomplete ledger range [" - << startLedgerSeq << "," << lastLedgerSeq << "]"; - setAccountHistoryJobTimer(subInfo); + << "AccountHistory job for account " << toBase58(accountId) << " getMoreTxns failed."; + send(rpcError(rpcINTERNAL), true); return; + // LCOV_EXCL_STOP } - std::optional marker{}; - while (!subInfo.index_->stopHistorical_) + auto const& txns = dbResult->first; + marker = dbResult->second; + size_t num_txns = txns.size(); + for (size_t i = 0; i < num_txns; ++i) { - auto dbResult = - getMoreTxns(startLedgerSeq, lastLedgerSeq, marker); - if (!dbResult) + auto const& [tx, meta] = txns[i]; + + if (!tx || !meta) + { + JLOG(m_journal.debug()) + << "AccountHistory job for account " << toBase58(accountId) << " empty tx or meta."; + send(rpcError(rpcINTERNAL), true); + return; + } + auto curTxLedger = app_.getLedgerMaster().getLedgerBySeq(tx->getLedger()); + if (!curTxLedger) { // LCOV_EXCL_START UNREACHABLE( - "ripple::NetworkOPsImp::addAccountHistoryJob : " - "getMoreTxns failed"); + "xrpl::NetworkOPsImp::addAccountHistoryJob : " + "getLedgerBySeq failed"); JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) << " getMoreTxns failed."; + << "AccountHistory job for account " << toBase58(accountId) << " no ledger."; + send(rpcError(rpcINTERNAL), true); + return; + // LCOV_EXCL_STOP + } + std::shared_ptr stTxn = tx->getSTransaction(); + if (!stTxn) + { + // LCOV_EXCL_START + UNREACHABLE( + "NetworkOPsImp::addAccountHistoryJob : " + "getSTransaction failed"); + JLOG(m_journal.debug()) + << "AccountHistory job for account " << toBase58(accountId) << " getSTransaction failed."; send(rpcError(rpcINTERNAL), true); return; // LCOV_EXCL_STOP } - auto const& txns = dbResult->first; - marker = dbResult->second; - size_t num_txns = txns.size(); - for (size_t i = 0; i < num_txns; ++i) + auto const mRef = std::ref(*meta); + auto const trR = meta->getResultTER(); + MultiApiJson jvTx = transJson(stTxn, trR, true, curTxLedger, mRef); + + jvTx.set(jss::account_history_tx_index, txHistoryIndex--); + if (i + 1 == num_txns || txns[i + 1].first->getLedger() != tx->getLedger()) + jvTx.set(jss::account_history_boundary, true); + + if (isFirstTx(tx, meta)) { - auto const& [tx, meta] = txns[i]; + jvTx.set(jss::account_history_tx_first, true); + sendMultiApiJson(jvTx, false); - if (!tx || !meta) - { - JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) << " empty tx or meta."; - send(rpcError(rpcINTERNAL), true); - return; - } - auto curTxLedger = - app_.getLedgerMaster().getLedgerBySeq( - tx->getLedger()); - if (!curTxLedger) - { - // LCOV_EXCL_START - UNREACHABLE( - "ripple::NetworkOPsImp::addAccountHistoryJob : " - "getLedgerBySeq failed"); - JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) << " no ledger."; - send(rpcError(rpcINTERNAL), true); - return; - // LCOV_EXCL_STOP - } - std::shared_ptr stTxn = - tx->getSTransaction(); - if (!stTxn) - { - // LCOV_EXCL_START - UNREACHABLE( - "NetworkOPsImp::addAccountHistoryJob : " - "getSTransaction failed"); - JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) - << " getSTransaction failed."; - send(rpcError(rpcINTERNAL), true); - return; - // LCOV_EXCL_STOP - } - - auto const mRef = std::ref(*meta); - auto const trR = meta->getResultTER(); - MultiApiJson jvTx = - transJson(stTxn, trR, true, curTxLedger, mRef); - - jvTx.set( - jss::account_history_tx_index, txHistoryIndex--); - if (i + 1 == num_txns || - txns[i + 1].first->getLedger() != tx->getLedger()) - jvTx.set(jss::account_history_boundary, true); - - if (isFirstTx(tx, meta)) - { - jvTx.set(jss::account_history_tx_first, true); - sendMultiApiJson(jvTx, false); - - JLOG(m_journal.trace()) - << "AccountHistory job for account " - << toBase58(accountId) - << " done, found last tx."; - return; - } - else - { - sendMultiApiJson(jvTx, false); - } - } - - if (marker) - { JLOG(m_journal.trace()) - << "AccountHistory job for account " - << toBase58(accountId) - << " paging, marker=" << marker->ledgerSeq << ":" - << marker->txnSeq; + << "AccountHistory job for account " << toBase58(accountId) << " done, found last tx."; + return; } else { - break; + sendMultiApiJson(jvTx, false); } } - if (!subInfo.index_->stopHistorical_) + if (marker) { - lastLedgerSeq = startLedgerSeq - 1; - if (lastLedgerSeq <= 1) - { - JLOG(m_journal.trace()) - << "AccountHistory job for account " - << toBase58(accountId) - << " done, reached genesis ledger."; - return; - } + JLOG(m_journal.trace()) << "AccountHistory job for account " << toBase58(accountId) + << " paging, marker=" << marker->ledgerSeq << ":" << marker->txnSeq; + } + else + { + break; } } - }); + + if (!subInfo.index_->stopHistorical_) + { + lastLedgerSeq = startLedgerSeq - 1; + if (lastLedgerSeq <= 1) + { + JLOG(m_journal.trace()) + << "AccountHistory job for account " << toBase58(accountId) << " done, reached genesis ledger."; + return; + } + } + } + }); } void -NetworkOPsImp::subAccountHistoryStart( - std::shared_ptr const& ledger, - SubAccountHistoryInfoWeak& subInfo) +NetworkOPsImp::subAccountHistoryStart(std::shared_ptr const& ledger, SubAccountHistoryInfoWeak& subInfo) { subInfo.index_->separationLedgerSeq_ = ledger->seq(); auto const& accountId = subInfo.index_->accountId_; auto const accountKeylet = keylet::account(accountId); if (!ledger->exists(accountKeylet)) { - JLOG(m_journal.debug()) - << "subAccountHistoryStart, no account " << toBase58(accountId) - << ", no need to add AccountHistory job."; + JLOG(m_journal.debug()) << "subAccountHistoryStart, no account " << toBase58(accountId) + << ", no need to add AccountHistory job."; return; } if (accountId == genesisAccountId) @@ -4041,10 +3657,8 @@ NetworkOPsImp::subAccountHistoryStart( { if (sleAcct->getFieldU32(sfSequence) == 1) { - JLOG(m_journal.debug()) - << "subAccountHistoryStart, genesis account " - << toBase58(accountId) - << " does not have tx, no need to add AccountHistory job."; + JLOG(m_journal.debug()) << "subAccountHistoryStart, genesis account " << toBase58(accountId) + << " does not have tx, no need to add AccountHistory job."; return; } } @@ -4052,7 +3666,7 @@ NetworkOPsImp::subAccountHistoryStart( { // LCOV_EXCL_START UNREACHABLE( - "ripple::NetworkOPsImp::subAccountHistoryStart : failed to " + "xrpl::NetworkOPsImp::subAccountHistoryStart : failed to " "access genesis account"); return; // LCOV_EXCL_STOP @@ -4061,36 +3675,29 @@ NetworkOPsImp::subAccountHistoryStart( subInfo.index_->historyLastLedgerSeq_ = ledger->seq(); subInfo.index_->haveHistorical_ = true; - JLOG(m_journal.debug()) - << "subAccountHistoryStart, add AccountHistory job: accountId=" - << toBase58(accountId) << ", currentLedgerSeq=" << ledger->seq(); + JLOG(m_journal.debug()) << "subAccountHistoryStart, add AccountHistory job: accountId=" << toBase58(accountId) + << ", currentLedgerSeq=" << ledger->seq(); addAccountHistoryJob(subInfo); } error_code_i -NetworkOPsImp::subAccountHistory( - InfoSub::ref isrListener, - AccountID const& accountId) +NetworkOPsImp::subAccountHistory(InfoSub::ref isrListener, AccountID const& accountId) { if (!isrListener->insertSubAccountHistory(accountId)) { - JLOG(m_journal.debug()) - << "subAccountHistory, already subscribed to account " - << toBase58(accountId); + JLOG(m_journal.debug()) << "subAccountHistory, already subscribed to account " << toBase58(accountId); return rpcINVALID_PARAMS; } std::lock_guard sl(mSubLock); - SubAccountHistoryInfoWeak ahi{ - isrListener, std::make_shared(accountId)}; + SubAccountHistoryInfoWeak ahi{isrListener, std::make_shared(accountId)}; auto simIterator = mSubAccountHistory.find(accountId); if (simIterator == mSubAccountHistory.end()) { hash_map inner; inner.emplace(isrListener->getSeq(), ahi); - mSubAccountHistory.insert( - simIterator, std::make_pair(accountId, inner)); + mSubAccountHistory.insert(simIterator, std::make_pair(accountId, inner)); } else { @@ -4107,18 +3714,14 @@ NetworkOPsImp::subAccountHistory( // The node does not have validated ledgers, so wait for // one before start streaming. // In this case, the subscription is also considered successful. - JLOG(m_journal.debug()) - << "subAccountHistory, no validated ledger yet, delay start"; + JLOG(m_journal.debug()) << "subAccountHistory, no validated ledger yet, delay start"; } return rpcSUCCESS; } void -NetworkOPsImp::unsubAccountHistory( - InfoSub::ref isrListener, - AccountID const& account, - bool historyOnly) +NetworkOPsImp::unsubAccountHistory(InfoSub::ref isrListener, AccountID const& account, bool historyOnly) { if (!historyOnly) isrListener->deleteSubAccountHistory(account); @@ -4126,10 +3729,7 @@ NetworkOPsImp::unsubAccountHistory( } void -NetworkOPsImp::unsubAccountHistoryInternal( - std::uint64_t seq, - AccountID const& account, - bool historyOnly) +NetworkOPsImp::unsubAccountHistoryInternal(std::uint64_t seq, AccountID const& account, bool historyOnly) { std::lock_guard sl(mSubLock); auto simIterator = mSubAccountHistory.find(account); @@ -4150,9 +3750,8 @@ NetworkOPsImp::unsubAccountHistoryInternal( mSubAccountHistory.erase(simIterator); } } - JLOG(m_journal.debug()) - << "unsubAccountHistory, account " << toBase58(account) - << ", historyOnly = " << (historyOnly ? "true" : "false"); + JLOG(m_journal.debug()) << "unsubAccountHistory, account " << toBase58(account) + << ", historyOnly = " << (historyOnly ? "true" : "false"); } } @@ -4164,7 +3763,7 @@ NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book) else { // LCOV_EXCL_START - UNREACHABLE("ripple::NetworkOPsImp::subBook : null book listeners"); + UNREACHABLE("xrpl::NetworkOPsImp::subBook : null book listeners"); // LCOV_EXCL_STOP } return true; @@ -4180,23 +3779,20 @@ NetworkOPsImp::unsubBook(std::uint64_t uSeq, Book const& book) } std::uint32_t -NetworkOPsImp::acceptLedger( - std::optional consensusDelay) +NetworkOPsImp::acceptLedger(std::optional consensusDelay) { // This code-path is exclusively used when the server is in standalone // mode via `ledger_accept` - XRPL_ASSERT( - m_standalone, "ripple::NetworkOPsImp::acceptLedger : is standalone"); + XRPL_ASSERT(m_standalone, "xrpl::NetworkOPsImp::acceptLedger : is standalone"); if (!m_standalone) - Throw( - "Operation only possible in STANDALONE mode."); + Throw("Operation only possible in STANDALONE mode."); // FIXME Could we improve on this and remove the need for a specialized // API in Consensus? - beginConsensus(m_ledgerMaster.getClosedLedger()->info().hash, {}); + beginConsensus(m_ledgerMaster.getClosedLedger()->header().hash, {}); mConsensus.simulate(app_.timeKeeper().closeTime(), consensusDelay); - return m_ledgerMaster.getCurrentLedger()->info().seq; + return m_ledgerMaster.getCurrentLedger()->header().seq; } // <-- bool: true=added, false=already there @@ -4205,10 +3801,9 @@ NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult) { if (auto lpClosed = m_ledgerMaster.getValidatedLedger()) { - jvResult[jss::ledger_index] = lpClosed->info().seq; - jvResult[jss::ledger_hash] = to_string(lpClosed->info().hash); - jvResult[jss::ledger_time] = Json::Value::UInt( - lpClosed->info().closeTime.time_since_epoch().count()); + jvResult[jss::ledger_index] = lpClosed->header().seq; + jvResult[jss::ledger_hash] = to_string(lpClosed->header().hash); + jvResult[jss::ledger_time] = Json::Value::UInt(lpClosed->header().closeTime.time_since_epoch().count()); if (!lpClosed->rules().enabled(featureXRPFees)) jvResult[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED; jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped(); @@ -4219,14 +3814,11 @@ NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult) if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger()) { - jvResult[jss::validated_ledgers] = - app_.getLedgerMaster().getCompleteLedgers(); + jvResult[jss::validated_ledgers] = app_.getLedgerMaster().getCompleteLedgers(); } std::lock_guard sl(mSubLock); - return mStreamMaps[sLedger] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sLedger].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=added, false=already there @@ -4234,9 +3826,7 @@ bool NetworkOPsImp::subBookChanges(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sBookChanges] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sBookChanges].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4260,9 +3850,7 @@ bool NetworkOPsImp::subManifests(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sManifests] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sManifests].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4275,10 +3863,7 @@ NetworkOPsImp::unsubManifests(std::uint64_t uSeq) // <-- bool: true=added, false=already there bool -NetworkOPsImp::subServer( - InfoSub::ref isrListener, - Json::Value& jvResult, - bool admin) +NetworkOPsImp::subServer(InfoSub::ref isrListener, Json::Value& jvResult, bool admin) { uint256 uRandom; @@ -4294,13 +3879,10 @@ NetworkOPsImp::subServer( jvResult[jss::load_base] = feeTrack.getLoadBase(); jvResult[jss::load_factor] = feeTrack.getLoadFactor(); jvResult[jss::hostid] = getHostId(admin); - jvResult[jss::pubkey_node] = - toBase58(TokenType::NodePublic, app_.nodeIdentity().first); + jvResult[jss::pubkey_node] = toBase58(TokenType::NodePublic, app_.nodeIdentity().first); std::lock_guard sl(mSubLock); - return mStreamMaps[sServer] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sServer].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4316,9 +3898,7 @@ bool NetworkOPsImp::subTransactions(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sTransactions] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sTransactions].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4334,9 +3914,7 @@ bool NetworkOPsImp::subRTTransactions(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sRTTransactions] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sRTTransactions].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4352,9 +3930,7 @@ bool NetworkOPsImp::subValidations(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sValidations] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sValidations].emplace(isrListener->getSeq(), isrListener).second; } void @@ -4376,9 +3952,7 @@ bool NetworkOPsImp::subPeerStatus(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sPeerStatus] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sPeerStatus].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4394,9 +3968,7 @@ bool NetworkOPsImp::subConsensus(InfoSub::ref isrListener) { std::lock_guard sl(mSubLock); - return mStreamMaps[sConsensusPhase] - .emplace(isrListener->getSeq(), isrListener) - .second; + return mStreamMaps[sConsensusPhase].emplace(isrListener->getSeq(), isrListener).second; } // <-- bool: true=erased, false=was not there @@ -4465,8 +4037,7 @@ NetworkOPsImp::getBookPage( Json::Value const& jvMarker, Json::Value& jvResult) { // CAUTION: This is the old get book page logic - Json::Value& jvOffers = - (jvResult[jss::offers] = Json::Value(Json::arrayValue)); + Json::Value& jvOffers = (jvResult[jss::offers] = Json::Value(Json::arrayValue)); std::unordered_map umBalance; uint256 const uBookBase = getBookBase(book); @@ -4483,8 +4054,7 @@ NetworkOPsImp::getBookPage( ReadView const& view = *lpLedger; - bool const bGlobalFreeze = isGlobalFrozen(view, book.out.account) || - isGlobalFrozen(view, book.in.account); + bool const bGlobalFreeze = isGlobalFrozen(view, book.out.account) || isGlobalFrozen(view, book.in.account); bool bDone = false; bool bDirectAdvance = true; @@ -4523,10 +4093,8 @@ NetworkOPsImp::getBookPage( cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex); - JLOG(m_journal.trace()) - << "getBookPage: uTipIndex=" << uTipIndex; - JLOG(m_journal.trace()) - << "getBookPage: offerIndex=" << offerIndex; + JLOG(m_journal.trace()) << "getBookPage: uTipIndex=" << uTipIndex; + JLOG(m_journal.trace()) << "getBookPage: offerIndex=" << offerIndex; } } @@ -4569,12 +4137,7 @@ NetworkOPsImp::getBookPage( // Did not find balance in table. saOwnerFunds = accountHolds( - view, - uOfferOwnerID, - book.out.currency, - book.out.account, - fhZERO_IF_FROZEN, - viewJ); + view, uOfferOwnerID, book.out.currency, book.out.account, fhZERO_IF_FROZEN, viewJ); if (saOwnerFunds < beast::zero) { @@ -4592,7 +4155,7 @@ NetworkOPsImp::getBookPage( Rate offerRate = parityRate; if (rate != parityRate - // Have a tranfer fee. + // Have a transfer fee. && uTakerID != book.out.account // Not taking offers of own IOUs. && book.out.account != uOfferOwnerID) @@ -4615,17 +4178,13 @@ NetworkOPsImp::getBookPage( saTakerGetsFunded = saOwnerFundsLimit; saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]); - std::min( - saTakerPays, - multiply( - saTakerGetsFunded, saDirRate, saTakerPays.issue())) + std::min(saTakerPays, multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue())) .setJson(jvOffer[jss::taker_pays_funded]); } STAmount saOwnerPays = (parityRate == offerRate) ? saTakerGetsFunded - : std::min( - saOwnerFunds, multiply(saTakerGetsFunded, offerRate)); + : std::min(saOwnerFunds, multiply(saTakerGetsFunded, offerRate)); umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays; @@ -4647,8 +4206,7 @@ NetworkOPsImp::getBookPage( } else { - JLOG(m_journal.trace()) - << "getBookPage: offerIndex=" << offerIndex; + JLOG(m_journal.trace()) << "getBookPage: offerIndex=" << offerIndex; } } } @@ -4681,8 +4239,7 @@ NetworkOPsImp::getBookPage( auto const rate = transferRate(lesActive, book.out.account); - bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.out.account) || - lesActive.isGlobalFrozen(book.in.account); + bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.out.account) || lesActive.isGlobalFrozen(book.in.account); while (iLimit-- > 0 && obIterator.nextOffer()) { @@ -4720,11 +4277,8 @@ NetworkOPsImp::getBookPage( { // Did not find balance in table. - saOwnerFunds = lesActive.accountHolds( - uOfferOwnerID, - book.out.currency, - book.out.account, - fhZERO_IF_FROZEN); + saOwnerFunds = + lesActive.accountHolds(uOfferOwnerID, book.out.currency, book.out.account, fhZERO_IF_FROZEN); if (saOwnerFunds.isNegative()) { @@ -4742,7 +4296,7 @@ NetworkOPsImp::getBookPage( Rate offerRate = parityRate; if (rate != parityRate - // Have a tranfer fee. + // Have a transfer fee. && uTakerID != book.out.account // Not taking offers of own IOUs. && book.out.account != uOfferOwnerID) @@ -4765,18 +4319,15 @@ NetworkOPsImp::getBookPage( saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]); - // TOOD(tom): The result of this expression is not used - what's + // TODO(tom): The result of this expression is not used - what's // going on here? - std::min( - saTakerPays, - multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue())) + std::min(saTakerPays, multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue())) .setJson(jvOffer[jss::taker_pays_funded]); } STAmount saOwnerPays = (parityRate == offerRate) ? saTakerGetsFunded - : std::min( - saOwnerFunds, multiply(saTakerGetsFunded, offerRate)); + : std::min(saOwnerFunds, multiply(saTakerGetsFunded, offerRate)); umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays; @@ -4799,38 +4350,22 @@ inline void NetworkOPsImp::collect_metrics() { auto [counters, mode, start, initialSync] = accounting_.getCounterData(); - auto const current = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start); + auto const current = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start); counters[static_cast(mode)].dur += current; std::lock_guard lock(m_statsMutex); - m_stats.disconnected_duration.set( - counters[static_cast(OperatingMode::DISCONNECTED)] - .dur.count()); - m_stats.connected_duration.set( - counters[static_cast(OperatingMode::CONNECTED)] - .dur.count()); - m_stats.syncing_duration.set( - counters[static_cast(OperatingMode::SYNCING)].dur.count()); - m_stats.tracking_duration.set( - counters[static_cast(OperatingMode::TRACKING)] - .dur.count()); - m_stats.full_duration.set( - counters[static_cast(OperatingMode::FULL)].dur.count()); + m_stats.disconnected_duration.set(counters[static_cast(OperatingMode::DISCONNECTED)].dur.count()); + m_stats.connected_duration.set(counters[static_cast(OperatingMode::CONNECTED)].dur.count()); + m_stats.syncing_duration.set(counters[static_cast(OperatingMode::SYNCING)].dur.count()); + m_stats.tracking_duration.set(counters[static_cast(OperatingMode::TRACKING)].dur.count()); + m_stats.full_duration.set(counters[static_cast(OperatingMode::FULL)].dur.count()); - m_stats.disconnected_transitions.set( - counters[static_cast(OperatingMode::DISCONNECTED)] - .transitions); - m_stats.connected_transitions.set( - counters[static_cast(OperatingMode::CONNECTED)] - .transitions); - m_stats.syncing_transitions.set( - counters[static_cast(OperatingMode::SYNCING)].transitions); - m_stats.tracking_transitions.set( - counters[static_cast(OperatingMode::TRACKING)] - .transitions); - m_stats.full_transitions.set( - counters[static_cast(OperatingMode::FULL)].transitions); + m_stats.disconnected_transitions.set(counters[static_cast(OperatingMode::DISCONNECTED)].transitions); + m_stats.connected_transitions.set(counters[static_cast(OperatingMode::CONNECTED)].transitions); + m_stats.syncing_transitions.set(counters[static_cast(OperatingMode::SYNCING)].transitions); + m_stats.tracking_transitions.set(counters[static_cast(OperatingMode::TRACKING)].transitions); + m_stats.full_transitions.set(counters[static_cast(OperatingMode::FULL)].transitions); } void @@ -4840,12 +4375,9 @@ NetworkOPsImp::StateAccounting::mode(OperatingMode om) std::lock_guard lock(mutex_); ++counters_[static_cast(om)].transitions; - if (om == OperatingMode::FULL && - counters_[static_cast(om)].transitions == 1) + if (om == OperatingMode::FULL && counters_[static_cast(om)].transitions == 1) { - initialSyncUs_ = std::chrono::duration_cast( - now - processStart_) - .count(); + initialSyncUs_ = std::chrono::duration_cast(now - processStart_).count(); } counters_[static_cast(mode_)].dur += std::chrono::duration_cast(now - start_); @@ -4858,8 +4390,8 @@ void NetworkOPsImp::StateAccounting::json(Json::Value& obj) const { auto [counters, mode, start, initialSync] = getCounterData(); - auto const current = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start); + auto const current = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start); counters[static_cast(mode)].dur += current; obj[jss::state_accounting] = Json::objectValue; @@ -4907,4 +4439,4 @@ make_NetworkOPs( collector); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/NetworkOPs.h b/src/xrpld/app/misc/NetworkOPs.h index bec0ad2341..66c915008a 100644 --- a/src/xrpld/app/misc/NetworkOPs.h +++ b/src/xrpld/app/misc/NetworkOPs.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED -#define RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED +#pragma once #include #include -#include #include +#include #include #include #include @@ -33,7 +13,7 @@ #include -namespace ripple { +namespace xrpl { // Operations that clients may wish to perform against the network // Master operational handler, server sequencer, network tracker @@ -50,9 +30,9 @@ class CanonicalTXSet; // should use this interface. The RPC code will primarily be a light wrapper // over this code. // -// Eventually, it will check the node's operating mode (synched, unsynched, -// etectera) and defer to the correct means of processing. The current -// code assumes this node is synched (and will continue to do so until +// Eventually, it will check the node's operating mode (synced, unsynced, +// etcetera) and defer to the correct means of processing. The current +// code assumes this node is synced (and will continue to do so until // there's a functional network. // @@ -111,8 +91,7 @@ public: virtual OperatingMode getOperatingMode() const = 0; virtual std::string - strOperatingMode(OperatingMode const mode, bool const admin = false) - const = 0; + strOperatingMode(OperatingMode const mode, bool const admin = false) const = 0; virtual std::string strOperatingMode(bool const admin = false) const = 0; @@ -135,11 +114,7 @@ public: * @param failType fail_hard setting from transaction submission. */ virtual void - processTransaction( - std::shared_ptr& transaction, - bool bUnlimited, - bool bLocal, - FailHard failType) = 0; + processTransaction(std::shared_ptr& transaction, bool bUnlimited, bool bLocal, FailHard failType) = 0; /** * Process a set of transactions synchronously, and ensuring that they are @@ -156,9 +131,7 @@ public: // virtual Json::Value - getOwnerInfo( - std::shared_ptr lpLedger, - AccountID const& account) = 0; + getOwnerInfo(std::shared_ptr lpLedger, AccountID const& account) = 0; //-------------------------------------------------------------------------- // @@ -182,18 +155,14 @@ public: processTrustedProposal(RCLCxPeerPos peerPos) = 0; virtual bool - recvValidation( - std::shared_ptr const& val, - std::string const& source) = 0; + recvValidation(std::shared_ptr const& val, std::string const& source) = 0; virtual void mapComplete(std::shared_ptr const& map, bool fromAcquire) = 0; // network state machine virtual bool - beginConsensus( - uint256 const& netLCL, - std::unique_ptr const& clog) = 0; + beginConsensus(uint256 const& netLCL, std::unique_ptr const& clog) = 0; virtual void endConsensus(std::unique_ptr const& clog) = 0; virtual void @@ -248,9 +217,7 @@ public: proposing being accepted. */ virtual std::uint32_t - acceptLedger( - std::optional consensusDelay = - std::nullopt) = 0; + acceptLedger(std::optional consensusDelay = std::nullopt) = 0; virtual void reportFeeChange() = 0; @@ -294,6 +261,4 @@ make_NetworkOPs( beast::Journal journal, beast::insight::Collector::ptr const& collector); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/PermissionedDEXHelpers.cpp b/src/xrpld/app/misc/PermissionedDEXHelpers.cpp index 279ef8d7e9..f88c2ab9d4 100644 --- a/src/xrpld/app/misc/PermissionedDEXHelpers.cpp +++ b/src/xrpld/app/misc/PermissionedDEXHelpers.cpp @@ -1,34 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace permissioned_dex { bool -accountInDomain( - ReadView const& view, - AccountID const& account, - Domain const& domainID) +accountInDomain(ReadView const& view, AccountID const& account, Domain const& domainID) { auto const sleDomain = view.read(keylet::permissionedDomain(domainID)); if (!sleDomain) @@ -40,26 +18,19 @@ accountInDomain( auto const& credentials = sleDomain->getFieldArray(sfAcceptedCredentials); - bool const inDomain = std::any_of( - credentials.begin(), credentials.end(), [&](auto const& credential) { - auto const sleCred = view.read(keylet::credential( - account, credential[sfIssuer], credential[sfCredentialType])); - if (!sleCred || !sleCred->isFlag(lsfAccepted)) - return false; + bool const inDomain = std::any_of(credentials.begin(), credentials.end(), [&](auto const& credential) { + auto const sleCred = view.read(keylet::credential(account, credential[sfIssuer], credential[sfCredentialType])); + if (!sleCred || !sleCred->isFlag(lsfAccepted)) + return false; - return !credentials::checkExpired( - sleCred, view.info().parentCloseTime); - }); + return !credentials::checkExpired(sleCred, view.header().parentCloseTime); + }); return inDomain; } bool -offerInDomain( - ReadView const& view, - uint256 const& offerID, - Domain const& domainID, - beast::Journal j) +offerInDomain(ReadView const& view, uint256 const& offerID, Domain const& domainID, beast::Journal j) { auto const sleOffer = view.read(keylet::offer(offerID)); @@ -73,11 +44,9 @@ offerInDomain( if (sleOffer->getFieldH256(sfDomainID) != domainID) return false; // LCOV_EXCL_LINE - if (sleOffer->isFlag(lsfHybrid) && - !sleOffer->isFieldPresent(sfAdditionalBooks)) + if (sleOffer->isFlag(lsfHybrid) && !sleOffer->isFieldPresent(sfAdditionalBooks)) { - JLOG(j.error()) << "Hybrid offer " << offerID - << " missing AdditionalBooks field"; + JLOG(j.error()) << "Hybrid offer " << offerID << " missing AdditionalBooks field"; return false; // LCOV_EXCL_LINE } @@ -86,4 +55,4 @@ offerInDomain( } // namespace permissioned_dex -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/PermissionedDEXHelpers.h b/src/xrpld/app/misc/PermissionedDEXHelpers.h index 409b32f4ba..832129db2f 100644 --- a/src/xrpld/app/misc/PermissionedDEXHelpers.h +++ b/src/xrpld/app/misc/PermissionedDEXHelpers.h @@ -1,43 +1,17 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #pragma once #include -namespace ripple { +namespace xrpl { namespace permissioned_dex { // Check if an account is in a permissioned domain [[nodiscard]] bool -accountInDomain( - ReadView const& view, - AccountID const& account, - Domain const& domainID); +accountInDomain(ReadView const& view, AccountID const& account, Domain const& domainID); // Check if an offer is in the permissioned domain [[nodiscard]] bool -offerInDomain( - ReadView const& view, - uint256 const& offerID, - Domain const& domainID, - beast::Journal j); +offerInDomain(ReadView const& view, uint256 const& offerID, Domain const& domainID, beast::Journal j); } // namespace permissioned_dex -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/SHAMapStore.h b/src/xrpld/app/misc/SHAMapStore.h index 1a0cbca5a5..67477593cb 100644 --- a/src/xrpld/app/misc/SHAMapStore.h +++ b/src/xrpld/app/misc/SHAMapStore.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_SHAMAPSTORE_H_INCLUDED -#define RIPPLE_APP_MISC_SHAMAPSTORE_H_INCLUDED +#pragma once #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { class TransactionMaster; @@ -103,10 +83,5 @@ public: //------------------------------------------------------------------------------ std::unique_ptr -make_SHAMapStore( - Application& app, - NodeStore::Scheduler& scheduler, - beast::Journal journal); -} // namespace ripple - -#endif +make_SHAMapStore(Application& app, NodeStore::Scheduler& scheduler, beast::Journal journal); +} // namespace xrpl diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index d775a2063a..c963d18d2c 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -1,41 +1,20 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -#include #include #include #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { void -SHAMapStoreImp::SavedStateDB::init( - BasicConfig const& config, - std::string const& dbName) +SHAMapStoreImp::SavedStateDB::init(BasicConfig const& config, std::string const& dbName) { std::lock_guard lock(mutex_); initStateDB(sqlDb_, config, dbName); @@ -46,7 +25,7 @@ SHAMapStoreImp::SavedStateDB::getCanDelete() { std::lock_guard lock(mutex_); - return ripple::getCanDelete(sqlDb_); + return xrpl::getCanDelete(sqlDb_); } LedgerIndex @@ -54,7 +33,7 @@ SHAMapStoreImp::SavedStateDB::setCanDelete(LedgerIndex canDelete) { std::lock_guard lock(mutex_); - return ripple::setCanDelete(sqlDb_, canDelete); + return xrpl::setCanDelete(sqlDb_, canDelete); } SavedState @@ -62,29 +41,26 @@ SHAMapStoreImp::SavedStateDB::getState() { std::lock_guard lock(mutex_); - return ripple::getSavedState(sqlDb_); + return xrpl::getSavedState(sqlDb_); } void SHAMapStoreImp::SavedStateDB::setState(SavedState const& state) { std::lock_guard lock(mutex_); - ripple::setSavedState(sqlDb_, state); + xrpl::setSavedState(sqlDb_, state); } void SHAMapStoreImp::SavedStateDB::setLastRotated(LedgerIndex seq) { std::lock_guard lock(mutex_); - ripple::setLastRotated(sqlDb_, seq); + xrpl::setLastRotated(sqlDb_, seq); } //------------------------------------------------------------------------------ -SHAMapStoreImp::SHAMapStoreImp( - Application& app, - NodeStore::Scheduler& scheduler, - beast::Journal journal) +SHAMapStoreImp::SHAMapStoreImp(Application& app, NodeStore::Scheduler& scheduler, beast::Journal journal) : app_(app) , scheduler_(scheduler) , journal_(journal) @@ -96,9 +72,7 @@ SHAMapStoreImp::SHAMapStoreImp( Section& section{config.section(ConfigSection::nodeDatabase())}; if (section.empty()) { - Throw( - "Missing [" + ConfigSection::nodeDatabase() + - "] entry in configuration file"); + Throw("Missing [" + ConfigSection::nodeDatabase() + "] entry in configuration file"); } // RocksDB only. Use sensible defaults if no values specified. @@ -106,9 +80,7 @@ SHAMapStoreImp::SHAMapStoreImp( { if (!section.exists("cache_mb")) { - section.set( - "cache_mb", - std::to_string(config.getValueFor(SizedItem::hashNodeDBCache))); + section.set("cache_mb", std::to_string(config.getValueFor(SizedItem::hashNodeDBCache))); } if (!section.exists("filter_bits") && (config.NODE_SIZE >= 2)) @@ -123,7 +95,7 @@ SHAMapStoreImp::SHAMapStoreImp( get_if_exists(section, "delete_batch", deleteBatch_); std::uint32_t temp; if (get_if_exists(section, "back_off_milliseconds", temp) || - // Included for backward compaibility with an undocumented setting + // Included for backward compatibility with an undocumented setting get_if_exists(section, "backOff", temp)) { backOff_ = std::chrono::milliseconds{temp}; @@ -135,14 +107,10 @@ SHAMapStoreImp::SHAMapStoreImp( get_if_exists(section, "advisory_delete", advisoryDelete_); - auto const minInterval = config.standalone() - ? minimumDeletionIntervalSA_ - : minimumDeletionInterval_; + auto const minInterval = config.standalone() ? minimumDeletionIntervalSA_ : minimumDeletionInterval_; if (deleteInterval_ < minInterval) { - Throw( - "online_delete must be at least " + - std::to_string(minInterval)); + Throw("online_delete must be at least " + std::to_string(minInterval)); } if (config.LEDGER_HISTORY > deleteInterval_) @@ -162,20 +130,6 @@ std::unique_ptr SHAMapStoreImp::makeNodeStore(int readThreads) { auto nscfg = app_.config().section(ConfigSection::nodeDatabase()); - - // Provide default values: - if (!nscfg.exists("cache_size")) - nscfg.set( - "cache_size", - std::to_string(app_.config().getValueFor( - SizedItem::treeCacheSize, std::nullopt))); - - if (!nscfg.exists("cache_age")) - nscfg.set( - "cache_age", - std::to_string(app_.config().getValueFor( - SizedItem::treeCacheAge, std::nullopt))); - std::unique_ptr db; if (deleteInterval_) @@ -206,8 +160,7 @@ SHAMapStoreImp::makeNodeStore(int readThreads) else { db = NodeStore::Manager::instance().make_Database( - megabytes( - app_.config().getValueFor(SizedItem::burstSize, std::nullopt)), + megabytes(app_.config().getValueFor(SizedItem::burstSize, std::nullopt)), scheduler_, readThreads, nscfg, @@ -248,11 +201,7 @@ bool SHAMapStoreImp::copyNode(std::uint64_t& nodeCount, SHAMapTreeNode const& node) { // Copy a single record from node to dbRotating_ - dbRotating_->fetchNodeObject( - node.getHash().as_uint256(), - 0, - NodeStore::FetchType::synchronous, - true); + dbRotating_->fetchNodeObject(node.getHash().as_uint256(), 0, NodeStore::FetchType::synchronous, true); if (!(++nodeCount % checkHealthInterval_)) { if (healthWait() == stopping) @@ -269,8 +218,6 @@ SHAMapStoreImp::run() LedgerIndex lastRotated = state_db_.getState().lastRotated; netOPs_ = &app_.getOPs(); ledgerMaster_ = &app_.getLedgerMaster(); - fullBelowCache_ = &(*app_.getNodeFamily().getFullBelowCache()); - treeNodeCache_ = &(*app_.getNodeFamily().getTreeNodeCache()); if (advisoryDelete_) canDelete_ = state_db_.getCanDelete(); @@ -297,7 +244,7 @@ SHAMapStoreImp::run() continue; } - LedgerIndex const validatedSeq = validatedLedger->info().seq; + LedgerIndex const validatedSeq = validatedLedger->header().seq; if (!lastRotated) { lastRotated = validatedSeq; @@ -305,18 +252,15 @@ SHAMapStoreImp::run() } bool const readyToRotate = - validatedSeq >= lastRotated + deleteInterval_ && - canDelete_ >= lastRotated - 1 && healthWait() == keepGoing; + validatedSeq >= lastRotated + deleteInterval_ && canDelete_ >= lastRotated - 1 && healthWait() == keepGoing; // will delete up to (not including) lastRotated if (readyToRotate) { - JLOG(journal_.warn()) - << "rotating validatedSeq " << validatedSeq << " lastRotated " - << lastRotated << " deleteInterval " << deleteInterval_ - << " canDelete_ " << canDelete_ << " state " - << app_.getOPs().strOperatingMode(false) << " age " - << ledgerMaster_->getValidatedLedgerAge().count() << 's'; + JLOG(journal_.warn()) << "rotating validatedSeq " << validatedSeq << " lastRotated " << lastRotated + << " deleteInterval " << deleteInterval_ << " canDelete_ " << canDelete_ << " state " + << app_.getOPs().strOperatingMode(false) << " age " + << ledgerMaster_->getValidatedLedgerAge().count() << 's'; clearPrior(lastRotated); if (healthWait() == stopping) @@ -328,25 +272,18 @@ SHAMapStoreImp::run() try { validatedLedger->stateMap().snapShot(false)->visitNodes( - std::bind( - &SHAMapStoreImp::copyNode, - this, - std::ref(nodeCount), - std::placeholders::_1)); + std::bind(&SHAMapStoreImp::copyNode, this, std::ref(nodeCount), std::placeholders::_1)); } catch (SHAMapMissingNode const& e) { - JLOG(journal_.error()) - << "Missing node while copying ledger before rotate: " - << e.what(); + JLOG(journal_.error()) << "Missing node while copying ledger before rotate: " << e.what(); continue; } if (healthWait() == stopping) return; // Only log if we completed without a "health" abort - JLOG(journal_.debug()) << "copied ledger " << validatedSeq - << " nodecount " << nodeCount; + JLOG(journal_.debug()) << "copied ledger " << validatedSeq << " nodecount " << nodeCount; JLOG(journal_.debug()) << "freshening caches"; freshenCaches(); @@ -357,8 +294,7 @@ SHAMapStoreImp::run() JLOG(journal_.trace()) << "Making a new backend"; auto newBackend = makeBackendRotating(); - JLOG(journal_.debug()) - << validatedSeq << " new backend " << newBackend->getName(); + JLOG(journal_.debug()) << validatedSeq << " new backend " << newBackend->getName(); clearCaches(validatedSeq); if (healthWait() == stopping) @@ -367,9 +303,7 @@ SHAMapStoreImp::run() lastRotated = validatedSeq; dbRotating_->rotate( - std::move(newBackend), - [&](std::string const& writableName, - std::string const& archiveName) { + std::move(newBackend), [&](std::string const& writableName, std::string const& archiveName) { SavedState savedState; savedState.writableDb = writableName; savedState.archiveDb = archiveName; @@ -394,8 +328,7 @@ SHAMapStoreImp::dbPaths() { if (!boost::filesystem::is_directory(dbPath)) { - journal_.error() - << "node db path must be a directory. " << dbPath.string(); + journal_.error() << "node db path must be a directory. " << dbPath.string(); Throw("node db path must be a directory."); } } @@ -432,9 +365,7 @@ SHAMapStoreImp::dbPaths() bool archiveDbExists = false; std::vector pathsToDelete; - for (boost::filesystem::directory_iterator it(dbPath); - it != boost::filesystem::directory_iterator(); - ++it) + for (boost::filesystem::directory_iterator it(dbPath); it != boost::filesystem::directory_iterator(); ++it) { if (!state.writableDb.compare(it->path().string())) writableDbExists = true; @@ -444,30 +375,23 @@ SHAMapStoreImp::dbPaths() pathsToDelete.push_back(it->path()); } - if ((!writableDbExists && state.writableDb.size()) || - (!archiveDbExists && state.archiveDb.size()) || - (writableDbExists != archiveDbExists) || - state.writableDb.empty() != state.archiveDb.empty()) + if ((!writableDbExists && state.writableDb.size()) || (!archiveDbExists && state.archiveDb.size()) || + (writableDbExists != archiveDbExists) || state.writableDb.empty() != state.archiveDb.empty()) { - boost::filesystem::path stateDbPathName = - app_.config().legacy("database_path"); + boost::filesystem::path stateDbPathName = app_.config().legacy("database_path"); stateDbPathName /= dbName_; stateDbPathName += "*"; - journal_.error() - << "state db error:\n" - << " writableDbExists " << writableDbExists << " archiveDbExists " - << archiveDbExists << '\n' - << " writableDb '" << state.writableDb << "' archiveDb '" - << state.archiveDb << "\n\n" - << "The existing data is in a corrupted state.\n" - << "To resume operation, remove the files matching " - << stateDbPathName.string() << " and contents of the directory " - << get(section, "path") << '\n' - << "Optionally, you can move those files to another\n" - << "location if you wish to analyze or back up the data.\n" - << "However, there is no guarantee that the data in its\n" - << "existing form is usable."; + journal_.error() << "state db error:\n" + << " writableDbExists " << writableDbExists << " archiveDbExists " << archiveDbExists << '\n' + << " writableDb '" << state.writableDb << "' archiveDb '" << state.archiveDb << "\n\n" + << "The existing data is in a corrupted state.\n" + << "To resume operation, remove the files matching " << stateDbPathName.string() + << " and contents of the directory " << get(section, "path") << '\n' + << "Optionally, you can move those files to another\n" + << "location if you wish to analyze or back up the data.\n" + << "However, there is no guarantee that the data in its\n" + << "existing form is usable."; Throw("state db error"); } @@ -498,8 +422,7 @@ SHAMapStoreImp::makeBackendRotating(std::string path) auto backend{NodeStore::Manager::instance().make_Backend( section, - megabytes( - app_.config().getValueFor(SizedItem::burstSize, std::nullopt)), + megabytes(app_.config().getValueFor(SizedItem::burstSize, std::nullopt)), scheduler_, app_.logs().journal(nodeStoreName_))}; backend->open(); @@ -513,14 +436,11 @@ SHAMapStoreImp::clearSql( std::function()> const& getMinSeq, std::function const& deleteBeforeSeq) { - XRPL_ASSERT( - deleteInterval_, - "ripple::SHAMapStoreImp::clearSql : nonzero delete interval"); + XRPL_ASSERT(deleteInterval_, "xrpl::SHAMapStoreImp::clearSql : nonzero delete interval"); LedgerIndex min = std::numeric_limits::max(); { - JLOG(journal_.trace()) - << "Begin: Look up lowest value of: " << TableName; + JLOG(journal_.trace()) << "Begin: Look up lowest value of: " << TableName; auto m = getMinSeq(); JLOG(journal_.trace()) << "End: Look up lowest value of: " << TableName; if (!m) @@ -537,18 +457,15 @@ SHAMapStoreImp::clearSql( return; } - JLOG(journal_.debug()) << "start deleting in: " << TableName << " from " - << min << " to " << lastRotated; + JLOG(journal_.debug()) << "start deleting in: " << TableName << " from " << min << " to " << lastRotated; while (min < lastRotated) { min = std::min(lastRotated, min + deleteBatch_); - JLOG(journal_.trace()) - << "Begin: Delete up to " << deleteBatch_ - << " rows with LedgerSeq < " << min << " from: " << TableName; + JLOG(journal_.trace()) << "Begin: Delete up to " << deleteBatch_ << " rows with LedgerSeq < " << min + << " from: " << TableName; deleteBeforeSeq(min); - JLOG(journal_.trace()) - << "End: Delete up to " << deleteBatch_ << " rows with LedgerSeq < " - << min << " from: " << TableName; + JLOG(journal_.trace()) << "End: Delete up to " << deleteBatch_ << " rows with LedgerSeq < " << min + << " from: " << TableName; if (healthWait() == stopping) return; if (min < lastRotated) @@ -563,16 +480,19 @@ void SHAMapStoreImp::clearCaches(LedgerIndex validatedSeq) { ledgerMaster_->clearLedgerCachePrior(validatedSeq); - fullBelowCache_->clear(); + // Also clear the FullBelowCache so its generation counter is bumped. + // This prevents stale "full below" markers from persisting across + // backend rotation/online deletion and interfering with SHAMap sync. + app_.getNodeFamily().getFullBelowCache()->clear(); } void SHAMapStoreImp::freshenCaches() { - if (freshenCache(*treeNodeCache_)) - return; - if (freshenCache(app_.getMasterTransaction().getCache())) + if (freshenCache(*app_.getNodeFamily().getTreeNodeCache())) return; + + freshenCache(app_.getMasterTransaction().getCache()); } void @@ -581,25 +501,19 @@ SHAMapStoreImp::clearPrior(LedgerIndex lastRotated) // Do not allow ledgers to be acquired from the network // that are about to be deleted. minimumOnline_ = lastRotated + 1; - JLOG(journal_.trace()) << "Begin: Clear internal ledgers up to " - << lastRotated; + JLOG(journal_.trace()) << "Begin: Clear internal ledgers up to " << lastRotated; ledgerMaster_->clearPriorLedgers(lastRotated); - JLOG(journal_.trace()) << "End: Clear internal ledgers up to " - << lastRotated; + JLOG(journal_.trace()) << "End: Clear internal ledgers up to " << lastRotated; if (healthWait() == stopping) return; - SQLiteDatabase* const db = - dynamic_cast(&app_.getRelationalDatabase()); - - if (!db) - Throw("Failed to get relational database"); + auto& db = app_.getRelationalDatabase(); clearSql( lastRotated, "Ledgers", - [db]() -> std::optional { return db->getMinLedgerSeq(); }, - [db](LedgerIndex min) -> void { db->deleteBeforeLedgerSeq(min); }); + [&db]() -> std::optional { return db.getMinLedgerSeq(); }, + [&db](LedgerIndex min) -> void { db.deleteBeforeLedgerSeq(min); }); if (healthWait() == stopping) return; @@ -609,24 +523,16 @@ SHAMapStoreImp::clearPrior(LedgerIndex lastRotated) clearSql( lastRotated, "Transactions", - [&db]() -> std::optional { - return db->getTransactionsMinLedgerSeq(); - }, - [&db](LedgerIndex min) -> void { - db->deleteTransactionsBeforeLedgerSeq(min); - }); + [&db]() -> std::optional { return db.getTransactionsMinLedgerSeq(); }, + [&db](LedgerIndex min) -> void { db.deleteTransactionsBeforeLedgerSeq(min); }); if (healthWait() == stopping) return; clearSql( lastRotated, "AccountTransactions", - [&db]() -> std::optional { - return db->getAccountTransactionsMinLedgerSeq(); - }, - [&db](LedgerIndex min) -> void { - db->deleteAccountTransactionsBeforeLedgerSeq(min); - }); + [&db]() -> std::optional { return db.getAccountTransactionsMinLedgerSeq(); }, + [&db](LedgerIndex min) -> void { db.deleteAccountTransactionsBeforeLedgerSeq(min); }); if (healthWait() == stopping) return; } @@ -641,8 +547,7 @@ SHAMapStoreImp::healthWait() { lock.unlock(); JLOG(journal_.warn()) << "Waiting " << recoveryWaitTime_.count() - << "s for node to stabilize. state: " - << app_.getOPs().strOperatingMode(mode, false) + << "s for node to stabilize. state: " << app_.getOPs().strOperatingMode(mode, false) << ". age " << age.count() << 's'; std::this_thread::sleep_for(recoveryWaitTime_); age = ledgerMaster_->getValidatedLedgerAge(); @@ -680,12 +585,9 @@ SHAMapStoreImp::minimumOnline() const //------------------------------------------------------------------------------ std::unique_ptr -make_SHAMapStore( - Application& app, - NodeStore::Scheduler& scheduler, - beast::Journal journal) +make_SHAMapStore(Application& app, NodeStore::Scheduler& scheduler, beast::Journal journal) { return std::make_unique(app, scheduler, journal); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/SHAMapStoreImp.h b/src/xrpld/app/misc/SHAMapStoreImp.h index 411035809b..df3c16b24f 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.h +++ b/src/xrpld/app/misc/SHAMapStoreImp.h @@ -1,38 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED -#define RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED +#pragma once #include #include -#include -#include #include #include +#include +#include #include #include #include -namespace ripple { +namespace xrpl { class NetworkOPs; @@ -73,7 +53,7 @@ private: // name of state database std::string const dbName_ = "state"; // prefix of on-disk nodestore backend instances - std::string const dbPrefix_ = "rippledb"; + std::string const dbPrefix_ = "rippledb"; // cspell: disable-line // check health/stop status as records are copied std::uint64_t const checkHealthInterval_ = 1000; // minimum # of ledgers to maintain for health of network @@ -106,29 +86,23 @@ private: /// If the node is out of sync during an online_delete healthWait() /// call, sleep the thread for this time, and continue checking until /// recovery. - /// See also: "recovery_wait_seconds" in rippled-example.cfg + /// See also: "recovery_wait_seconds" in xrpld-example.cfg std::chrono::seconds recoveryWaitTime_{5}; // these do not exist upon SHAMapStore creation, but do exist // as of run() or before NetworkOPs* netOPs_ = nullptr; LedgerMaster* ledgerMaster_ = nullptr; - FullBelowCache* fullBelowCache_ = nullptr; - TreeNodeCache* treeNodeCache_ = nullptr; static constexpr auto nodeStoreName_ = "NodeStore"; public: - SHAMapStoreImp( - Application& app, - NodeStore::Scheduler& scheduler, - beast::Journal journal); + SHAMapStoreImp(Application& app, NodeStore::Scheduler& scheduler, beast::Journal journal); std::uint32_t clampFetchDepth(std::uint32_t fetch_depth) const override { - return deleteInterval_ ? std::min(fetch_depth, deleteInterval_) - : fetch_depth; + return deleteInterval_ ? std::min(fetch_depth, deleteInterval_) : fetch_depth; } std::unique_ptr @@ -195,8 +169,7 @@ private: for (auto const& key : cache.getKeys()) { - dbRotating_->fetchNodeObject( - key, 0, NodeStore::FetchType::synchronous, true); + dbRotating_->fetchNodeObject(key, 0, NodeStore::FetchType::synchronous, true); if (!(++check % checkHealthInterval_) && healthWait() == stopping) return true; } @@ -244,6 +217,4 @@ public: stop() override; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/Transaction.h b/src/xrpld/app/misc/Transaction.h index 005ff16993..0a51e1c021 100644 --- a/src/xrpld/app/misc/Transaction.h +++ b/src/xrpld/app/misc/Transaction.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED -#define RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED +#pragma once #include #include @@ -28,11 +8,12 @@ #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { // // Transactions should be constructed in JSON with. Use STObject::parseJson to @@ -55,21 +36,15 @@ enum TransStatus { INCOMPLETE = 8 // needs more signatures }; -enum class TxSearched { all, some, unknown }; - // This class is for constructing and examining transactions. // Transactions are static so manipulation functions are unnecessary. -class Transaction : public std::enable_shared_from_this, - public CountedObject +class Transaction : public std::enable_shared_from_this, public CountedObject { public: using pointer = std::shared_ptr; using ref = pointer const&; - Transaction( - std::shared_ptr const&, - std::string&, - Application&) noexcept; + Transaction(std::shared_ptr const&, std::string&, Application&) noexcept; // The two boost::optional parameters are because SOCI requires // boost::optional (not std::optional) parameters. @@ -240,7 +215,7 @@ public: } /** - * @brief setQueued Set this flag once was put into heldtxns queue + * @brief setQueued Set this flag once was put into held-txns queue */ void setQueued() @@ -270,15 +245,8 @@ public: { CurrentLedgerState() = delete; - CurrentLedgerState( - LedgerIndex li, - XRPAmount fee, - std::uint32_t accSeqNext, - std::uint32_t accSeqAvail) - : validatedLedger{li} - , minFeeRequired{fee} - , accountSeqNext{accSeqNext} - , accountSeqAvail{accSeqAvail} + CurrentLedgerState(LedgerIndex li, XRPAmount fee, std::uint32_t accSeqNext, std::uint32_t accSeqAvail) + : validatedLedger{li}, minFeeRequired{fee}, accountSeqNext{accSeqNext}, accountSeqAvail{accSeqAvail} { } @@ -312,8 +280,7 @@ public: std::uint32_t accountSeq, std::uint32_t availableSeq) { - currentLedgerState_.emplace( - validatedLedger, fee, accountSeq, availableSeq); + currentLedgerState_.emplace(validatedLedger, fee, accountSeq, availableSeq); } Json::Value @@ -325,8 +292,7 @@ public: // at the time of search. struct Locator { - std::variant, ClosedInterval> - locator; + std::variant, ClosedInterval> locator; // @return true if transaction was found, false otherwise // @@ -336,8 +302,7 @@ public: bool isFound() { - return std::holds_alternative>( - locator); + return std::holds_alternative>(locator); } // @return key used to find transaction in nodestore @@ -371,29 +336,15 @@ public: static Locator locate(uint256 const& id, Application& app); - static std::variant< - std::pair, std::shared_ptr>, - TxSearched> + static std::variant, std::shared_ptr>, TxSearched> load(uint256 const& id, Application& app, error_code_i& ec); - static std::variant< - std::pair, std::shared_ptr>, - TxSearched> - load( - uint256 const& id, - Application& app, - ClosedInterval const& range, - error_code_i& ec); + static std::variant, std::shared_ptr>, TxSearched> + load(uint256 const& id, Application& app, ClosedInterval const& range, error_code_i& ec); private: - static std::variant< - std::pair, std::shared_ptr>, - TxSearched> - load( - uint256 const& id, - Application& app, - std::optional> const& range, - error_code_i& ec); + static std::variant, std::shared_ptr>, TxSearched> + load(uint256 const& id, Application& app, std::optional> const& range, error_code_i& ec); uint256 mTransactionID; @@ -432,6 +383,4 @@ private: beast::Journal j_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/TxQ.h b/src/xrpld/app/misc/TxQ.h index 6afd83b0d0..b50ff1a0b5 100644 --- a/src/xrpld/app/misc/TxQ.h +++ b/src/xrpld/app/misc/TxQ.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-19 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_TXQ_H_INCLUDED -#define RIPPLE_TXQ_H_INCLUDED +#pragma once #include @@ -34,7 +14,7 @@ #include -namespace ripple { +namespace xrpl { class Application; class Config; @@ -114,7 +94,7 @@ public: allowing more than `maximumTxnInLedger` "cheap" transactions into the open ledger. - @todo eahennis. This setting seems to go against our goals and + @todo ximinez. This setting seems to go against our goals and values. Can it be removed? */ std::optional maximumTxnInLedger; @@ -271,12 +251,7 @@ public: will return `{ terQUEUED, false }`. */ ApplyResult - apply( - Application& app, - OpenView& view, - std::shared_ptr const& tx, - ApplyFlags flags, - beast::Journal j); + apply(Application& app, OpenView& view, std::shared_ptr const& tx, ApplyFlags flags, beast::Journal j); /** Fill the new open ledger with transactions from the queue. @@ -333,9 +308,7 @@ public: * and first available sequence */ FeeAndSeq - getTxRequiredFeeAndSeq( - OpenView const& view, - std::shared_ptr const& tx) const; + getTxRequiredFeeAndSeq(OpenView const& view, std::shared_ptr const& tx) const; /** Returns information about the transactions currently in the queue for the account. @@ -365,9 +338,7 @@ public: private: // Implementation for nextQueuableSeq(). The passed lock must be held. SeqProxy - nextQueuableSeqImpl( - std::shared_ptr const& sleAccount, - std::lock_guard const&) const; + nextQueuableSeqImpl(std::shared_ptr const& sleAccount, std::lock_guard const&) const; /** Track and use the fee escalation metrics of the @@ -400,18 +371,11 @@ private: public: /// Constructor FeeMetrics(Setup const& setup, beast::Journal j) - : minimumTxnCount_( - setup.standAlone ? setup.minimumTxnInLedgerSA - : setup.minimumTxnInLedger) - , targetTxnCount_( - setup.targetTxnInLedger < minimumTxnCount_ - ? minimumTxnCount_ - : setup.targetTxnInLedger) + : minimumTxnCount_(setup.standAlone ? setup.minimumTxnInLedgerSA : setup.minimumTxnInLedger) + , targetTxnCount_(setup.targetTxnInLedger < minimumTxnCount_ ? minimumTxnCount_ : setup.targetTxnInLedger) , maximumTxnCount_( setup.maximumTxnInLedger - ? *setup.maximumTxnInLedger < targetTxnCount_ - ? targetTxnCount_ - : *setup.maximumTxnInLedger + ? *setup.maximumTxnInLedger < targetTxnCount_ ? targetTxnCount_ : *setup.maximumTxnInLedger : std::optional(std::nullopt)) , txnsExpected_(minimumTxnCount_) , recentTxnCounts_(setup.ledgersInQueue) @@ -431,11 +395,7 @@ private: @param setup Customization params. */ std::size_t - update( - Application& app, - ReadView const& view, - bool timeLeap, - TxQ::Setup const& setup); + update(Application& app, ReadView const& view, bool timeLeap, TxQ::Setup const& setup); /// Snapshot of the externally relevant FeeMetrics /// fields at any given time. @@ -556,12 +516,12 @@ private: /** Cached result of the `preflight` operation. Because `preflight` is expensive, minimize the number of times it needs to be done. - @invariant `pfresult` is never allowed to be empty. The + @invariant `pfResult` is never allowed to be empty. The `std::optional` is leveraged to allow `emplace`d construction and replacement without a copy assignment operation. */ - std::optional pfresult; + std::optional pfResult; /** Starting retry count for newly queued transactions. @@ -596,7 +556,7 @@ private: TxID const& txID, FeeLevel64 feeLevel, ApplyFlags const flags, - PreflightResult const& pfresult); + PreflightResult const& pfResult); /// Attempt to apply the queued transaction to the open ledger. ApplyResult @@ -607,7 +567,7 @@ private: TxConsequences const& consequences() const { - return pfresult->consequences; + return pfResult->consequences; } /// Return a TxDetails based on contained information. @@ -622,7 +582,7 @@ private: seqProxy, txn, retriesRemaining, - pfresult->ter, + pfResult->ter, lastResult}; } }; @@ -653,8 +613,7 @@ private: operator()(MaybeTx const& lhs, MaybeTx const& rhs) const { if (lhs.feeLevel == rhs.feeLevel) - return (lhs.txID ^ MaybeTx::parentHashComp) < - (rhs.txID ^ MaybeTx::parentHashComp); + return (lhs.txID ^ MaybeTx::parentHashComp) < (rhs.txID ^ MaybeTx::parentHashComp); return lhs.feeLevel > rhs.feeLevel; } }; @@ -747,13 +706,10 @@ private: std::optional const& replacedTxIter, std::shared_ptr const& tx); - using FeeHook = boost::intrusive::member_hook< - MaybeTx, - boost::intrusive::set_member_hook<>, - &MaybeTx::byFeeListHook>; + using FeeHook = + boost::intrusive::member_hook, &MaybeTx::byFeeListHook>; - using FeeMultiSet = boost::intrusive:: - multiset>; + using FeeMultiSet = boost::intrusive::multiset>; using AccountMap = std::map; @@ -821,16 +777,12 @@ private: FeeMultiSet::iterator_type erase(FeeMultiSet::const_iterator_type); /** Erase and return the next entry for the account (if fee level is higher), or next entry in byFee_ (lower fee level). - Used to get the next "applyable" MaybeTx for accept(). + Used to get the next "applicable" MaybeTx for accept(). */ - FeeMultiSet::iterator_type eraseAndAdvance( - FeeMultiSet::const_iterator_type); + FeeMultiSet::iterator_type eraseAndAdvance(FeeMultiSet::const_iterator_type); /// Erase a range of items, based on TxQAccount::TxMap iterators TxQAccount::TxMap::iterator - erase( - TxQAccount& txQAccount, - TxQAccount::TxMap::const_iterator begin, - TxQAccount::TxMap::const_iterator end); + erase(TxQAccount& txQAccount, TxQAccount::TxMap::const_iterator begin, TxQAccount::TxMap::const_iterator end); /** All-or-nothing attempt to try to apply the queued txs for @@ -845,7 +797,7 @@ private: AccountMap::iterator const& accountIter, TxQAccount::TxMap::iterator, FeeLevel64 feeLevelPaid, - PreflightResult const& pfresult, + PreflightResult const& pfResult, std::size_t const txExtraCount, ApplyFlags flags, FeeMetrics::Snapshot const& metricsSnapshot, @@ -862,17 +814,13 @@ template XRPAmount toDrops(FeeLevel const& level, XRPAmount baseFee) { - return mulDiv(level, baseFee, TxQ::baseLevel) - .value_or(XRPAmount(STAmount::cMaxNativeN)); + return mulDiv(level, baseFee, TxQ::baseLevel).value_or(XRPAmount(STAmount::cMaxNativeN)); } inline FeeLevel64 toFeeLevel(XRPAmount const& drops, XRPAmount const& baseFee) { - return mulDiv(drops, TxQ::baseLevel, baseFee) - .value_or(FeeLevel64(std::numeric_limits::max())); + return mulDiv(drops, TxQ::baseLevel, baseFee).value_or(FeeLevel64(std::numeric_limits::max())); } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/ValidatorKeys.h b/src/xrpld/app/misc/ValidatorKeys.h index d29d6cdc6d..296c63e09e 100644 --- a/src/xrpld/app/misc/ValidatorKeys.h +++ b/src/xrpld/app/misc/ValidatorKeys.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2017 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED -#define RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class Config; @@ -45,13 +25,8 @@ public: SecretKey secretKey; Keys() = delete; - Keys( - PublicKey const& masterPublic_, - PublicKey const& public_, - SecretKey const& secret_) - : masterPublicKey(masterPublic_) - , publicKey(public_) - , secretKey(secret_) + Keys(PublicKey const& masterPublic_, PublicKey const& public_, SecretKey const& secret_) + : masterPublicKey(masterPublic_), publicKey(public_), secretKey(secret_) { } }; @@ -78,6 +53,4 @@ private: bool configInvalid_ = false; //< Set to true if config was invalid }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h index 9a2018cbd4..f93ac8a32f 100644 --- a/src/xrpld/app/misc/ValidatorList.h +++ b/src/xrpld/app/misc/ValidatorList.h @@ -1,26 +1,5 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_VALIDATORLIST_H_INCLUDED -#define RIPPLE_APP_MISC_VALIDATORLIST_H_INCLUDED - -#include #include #include @@ -29,6 +8,7 @@ #include #include #include +#include #include @@ -40,7 +20,7 @@ class TMValidatorList; class TMValidatorListCollection; } // namespace protocol -namespace ripple { +namespace xrpl { class Overlay; class HashRouter; @@ -256,7 +236,7 @@ class ValidatorList // config file under the title of SECTION_VALIDATORS or [validators]. // This list is not associated with the masterKey of any publisher. - // Appropos PublisherListCollection fields, localPublisherList does not + // Apropos PublisherListCollection fields, localPublisherList does not // have any "remaining" manifests. It is assumed to be perennially // "available". The "validUntil" field is set to the highest possible // value of the field, hence this list is always valid. @@ -292,11 +272,7 @@ public: { explicit PublisherListStats() = default; explicit PublisherListStats(ListDisposition d); - PublisherListStats( - ListDisposition d, - PublicKey key, - PublisherStatus stat, - std::size_t seq); + PublisherListStats(ListDisposition d, PublicKey key, PublisherStatus stat, std::size_t seq); ListDisposition bestDisposition() const; @@ -316,10 +292,7 @@ public: struct MessageWithHash { explicit MessageWithHash() = default; - explicit MessageWithHash( - std::shared_ptr const& message_, - uint256 hash_, - std::size_t num_); + explicit MessageWithHash(std::shared_ptr const& message_, uint256 hash_, std::size_t num_); std::shared_ptr message; uint256 hash; std::size_t numVLs = 0; @@ -384,7 +357,7 @@ public: std::string const& rawManifest, std::map const& blobInfos, std::vector& messages, - std::size_t maxSize = maximiumMessageSize); + std::size_t maxSize = maximumMessageSize); /** Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it or sent it. @@ -623,22 +596,19 @@ public: May be called concurrently */ void - for_each_available( - std::function const& blobInfos, - PublicKey const& pubKey, - std::size_t maxSequence, - uint256 const& hash)> func) const; + for_each_available(std::function const& blobInfos, + PublicKey const& pubKey, + std::size_t maxSequence, + uint256 const& hash)> func) const; /** Returns the current valid list for the given publisher key, if available, as a Json object. */ std::optional - getAvailable( - std::string_view pubKey, - std::optional forceVersion = {}); + getAvailable(std::string_view pubKey, std::optional forceVersion = {}); /** Return the number of configured validator list sites. */ std::size_t @@ -711,8 +681,7 @@ public: * @return a filtered copy of the validations */ std::vector> - negativeUNLFilter( - std::vector>&& validations) const; + negativeUNLFilter(std::vector>&& validations) const; private: /** Return the number of configured validator list sites. */ @@ -798,9 +767,7 @@ private: lock_guard const&); static void - buildBlobInfos( - std::map& blobInfos, - PublisherListCollection const& lists); + buildBlobInfos(std::map& blobInfos, PublisherListCollection const& lists); static std::map buildBlobInfos(PublisherListCollection const& lists); @@ -837,10 +804,7 @@ private: writing to a cache file, or serving to a /vl/ query */ static Json::Value - buildFileData( - std::string const& pubKey, - PublisherListCollection const& pubCollection, - beast::Journal j); + buildFileData(std::string const& pubKey, PublisherListCollection const& pubCollection, beast::Journal j); /** Build a Json representation of the collection, suitable for writing to a cache file, or serving to a /vl/ query @@ -892,10 +856,7 @@ private: Calling public member function is expected to lock mutex */ bool - removePublisherList( - lock_guard const&, - PublicKey const& publisherKey, - PublisherStatus reason); + removePublisherList(lock_guard const&, PublicKey const& publisherKey, PublisherStatus reason); /** Return quorum for trusted validator set @@ -908,10 +869,7 @@ private: recently received validations */ std::size_t - calculateQuorum( - std::size_t unlSize, - std::size_t effectiveUnlSize, - std::size_t seenSize); + calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize); }; // hashing helpers @@ -946,7 +904,7 @@ hash_append(Hasher& h, std::map const& blobs) } } -} // namespace ripple +} // namespace xrpl namespace protocol { @@ -963,13 +921,7 @@ void hash_append(Hasher& h, TMValidatorListCollection const& msg) { using beast::hash_append; - hash_append( - h, - msg.manifest(), - ripple::ValidatorList::parseBlobs(msg), - msg.version()); + hash_append(h, msg.manifest(), xrpl::ValidatorList::parseBlobs(msg), msg.version()); } } // namespace protocol - -#endif diff --git a/src/xrpld/app/misc/ValidatorSite.h b/src/xrpld/app/misc/ValidatorSite.h index 58f9eaaeff..dc44e28bcb 100644 --- a/src/xrpld/app/misc/ValidatorSite.h +++ b/src/xrpld/app/misc/ValidatorSite.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED -#define RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED +#pragma once #include #include @@ -33,7 +13,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Validator Sites @@ -197,16 +177,12 @@ public: private: /// Load configured site URIs. bool - load( - std::vector const& siteURIs, - std::lock_guard const&); + load(std::vector const& siteURIs, std::lock_guard const&); /// Queue next site to be fetched /// lock over site_mutex_ and state_mutex_ required void - setTimer( - std::lock_guard const&, - std::lock_guard const&); + setTimer(std::lock_guard const&, std::lock_guard const&); /// request took too long void @@ -226,34 +202,22 @@ private: /// Store latest list fetched from anywhere void - onTextFetch( - boost::system::error_code const& ec, - std::string const& res, - std::size_t siteIdx); + onTextFetch(boost::system::error_code const& ec, std::string const& res, std::size_t siteIdx); /// Initiate request to given resource. /// lock over sites_mutex_ required void - makeRequest( - std::shared_ptr resource, - std::size_t siteIdx, - std::lock_guard const&); + makeRequest(std::shared_ptr resource, std::size_t siteIdx, std::lock_guard const&); /// Parse json response from validator list site. /// lock over sites_mutex_ required void - parseJsonResponse( - std::string const& res, - std::size_t siteIdx, - std::lock_guard const&); + parseJsonResponse(std::string const& res, std::size_t siteIdx, std::lock_guard const&); /// Interpret a redirect response. /// lock over sites_mutex_ required std::shared_ptr - processRedirect( - detail::response_type& res, - std::size_t siteIdx, - std::lock_guard const&); + processRedirect(detail::response_type& res, std::size_t siteIdx, std::lock_guard const&); /// If no sites are provided, or a site fails to load, /// get a list of local cache files from the ValidatorList. @@ -261,6 +225,4 @@ private: missingSite(std::lock_guard const&); }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp index 49ad01c3ae..ff3474f33d 100644 --- a/src/xrpld/app/misc/detail/AMMHelpers.cpp +++ b/src/xrpld/app/misc/detail/AMMHelpers.cpp @@ -1,35 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { STAmount -ammLPTokens( - STAmount const& asset1, - STAmount const& asset2, - Issue const& lptIssue) +ammLPTokens(STAmount const& asset1, STAmount const& asset2, Issue const& lptIssue) { // AMM invariant: sqrt(asset1 * asset2) >= LPTokensBalance - auto const rounding = - isFeatureEnabled(fixAMMv1_3) ? Number::downward : Number::getround(); + auto const rounding = isFeatureEnabled(fixAMMv1_3) ? Number::downward : Number::getround(); NumberRoundModeGuard g(rounding); auto const tokens = root2(asset1 * asset2); return toSTAmount(lptIssue, tokens); @@ -77,11 +54,7 @@ lpTokensOut( * (R/t2)**2 + R*(2*d/t2 - 1/f1) + d**2 - f2**2 = 0 */ STAmount -ammAssetIn( - STAmount const& asset1Balance, - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - std::uint16_t tfee) +ammAssetIn(STAmount const& asset1Balance, STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee) { auto const f1 = feeMult(tfee); auto const f2 = feeMultHalf(tfee) / f1; @@ -93,8 +66,7 @@ ammAssetIn( auto const c = d * d - f2 * f2; if (!isFeatureEnabled(fixAMMv1_3)) { - return toSTAmount( - asset1Balance.issue(), asset1Balance * solveQuadraticEq(a, b, c)); + return toSTAmount(asset1Balance.issue(), asset1Balance * solveQuadraticEq(a, b, c)); } else { @@ -142,11 +114,7 @@ lpTokensIn( * R = (t1**2 + t1*(f - 2)) / (t1*f - 1) */ STAmount -ammAssetOut( - STAmount const& assetBalance, - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - std::uint16_t tfee) +ammAssetOut(STAmount const& assetBalance, STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee) { auto const f = getFee(tfee); Number const t1 = lpTokens / lptAMMBalance; @@ -170,10 +138,7 @@ square(Number const& n) } STAmount -adjustLPTokens( - STAmount const& lptAMMBalance, - STAmount const& lpTokens, - IsDeposit isDeposit) +adjustLPTokens(STAmount const& lptAMMBalance, STAmount const& lpTokens, IsDeposit isDeposit) { // Force rounding downward to ensure adjusted tokens are less or equal // to requested tokens. @@ -197,21 +162,18 @@ adjustAmountsByLPTokens( if (isFeatureEnabled(fixAMMv1_3)) return std::make_tuple(amount, amount2, lpTokens); - auto const lpTokensActual = - adjustLPTokens(lptAMMBalance, lpTokens, isDeposit); + auto const lpTokensActual = adjustLPTokens(lptAMMBalance, lpTokens, isDeposit); if (lpTokensActual == beast::zero) { - auto const amount2Opt = - amount2 ? std::make_optional(STAmount{}) : std::nullopt; + auto const amount2Opt = amount2 ? std::make_optional(STAmount{}) : std::nullopt; return std::make_tuple(STAmount{}, amount2Opt, lpTokensActual); } if (lpTokensActual < lpTokens) { bool const ammRoundingEnabled = [&]() { - if (auto const& rules = getCurrentTransactionRules(); - rules && rules->enabled(fixAMMv1_1)) + if (auto const& rules = getCurrentTransactionRules(); rules && rules->enabled(fixAMMv1_1)) return true; return false; }(); @@ -221,41 +183,33 @@ adjustAmountsByLPTokens( { Number const fr = lpTokensActual / lpTokens; auto const amountActual = toSTAmount(amount.issue(), fr * amount); - auto const amount2Actual = - toSTAmount(amount2->issue(), fr * *amount2); + auto const amount2Actual = toSTAmount(amount2->issue(), fr * *amount2); if (!ammRoundingEnabled) return std::make_tuple( amountActual < amount ? amountActual : amount, amount2Actual < amount2 ? amount2Actual : amount2, lpTokensActual); else - return std::make_tuple( - amountActual, amount2Actual, lpTokensActual); + return std::make_tuple(amountActual, amount2Actual, lpTokensActual); } // Single trade auto const amountActual = [&]() { if (isDeposit == IsDeposit::Yes) - return ammAssetIn( - amountBalance, lptAMMBalance, lpTokensActual, tfee); + return ammAssetIn(amountBalance, lptAMMBalance, lpTokensActual, tfee); else if (!ammRoundingEnabled) - return ammAssetOut( - amountBalance, lptAMMBalance, lpTokens, tfee); + return ammAssetOut(amountBalance, lptAMMBalance, lpTokens, tfee); else - return ammAssetOut( - amountBalance, lptAMMBalance, lpTokensActual, tfee); + return ammAssetOut(amountBalance, lptAMMBalance, lpTokensActual, tfee); }(); if (!ammRoundingEnabled) - return amountActual < amount - ? std::make_tuple(amountActual, std::nullopt, lpTokensActual) - : std::make_tuple(amount, std::nullopt, lpTokensActual); + return amountActual < amount ? std::make_tuple(amountActual, std::nullopt, lpTokensActual) + : std::make_tuple(amount, std::nullopt, lpTokensActual); else return std::make_tuple(amountActual, std::nullopt, lpTokensActual); } - XRPL_ASSERT( - lpTokensActual == lpTokens, - "ripple::adjustAmountsByLPTokens : LP tokens match actual"); + XRPL_ASSERT(lpTokensActual == lpTokens, "xrpl::adjustAmountsByLPTokens : LP tokens match actual"); return {amount, amount2, lpTokensActual}; } @@ -308,11 +262,7 @@ getRoundedAsset( } STAmount -getRoundedLPTokens( - Rules const& rules, - STAmount const& balance, - Number const& frac, - IsDeposit isDeposit) +getRoundedLPTokens(Rules const& rules, STAmount const& balance, Number const& frac, IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) return toSTAmount(balance.issue(), balance * frac); @@ -398,15 +348,11 @@ adjustAssetOutByTokens( } Number -adjustFracByTokens( - Rules const& rules, - STAmount const& lptAMMBalance, - STAmount const& tokens, - Number const& frac) +adjustFracByTokens(Rules const& rules, STAmount const& lptAMMBalance, STAmount const& tokens, Number const& frac) { if (!rules.enabled(fixAMMv1_3)) return frac; return tokens / lptAMMBalance; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index 94cdb04287..36a40f1709 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { std::pair ammPoolHolds( @@ -36,10 +17,8 @@ ammPoolHolds( FreezeHandling freezeHandling, beast::Journal const j) { - auto const assetInBalance = - accountHolds(view, ammAccountID, issue1, freezeHandling, j); - auto const assetOutBalance = - accountHolds(view, ammAccountID, issue2, freezeHandling, j); + auto const assetInBalance = accountHolds(view, ammAccountID, issue1, freezeHandling, j); + auto const assetOutBalance = accountHolds(view, ammAccountID, issue2, freezeHandling, j); return std::make_pair(assetInBalance, assetOutBalance); } @@ -57,32 +36,25 @@ ammHolds( auto const issue2 = ammSle[sfAsset2].get(); if (optIssue1 && optIssue2) { - if (invalidAMMAssetPair( - *optIssue1, - *optIssue2, - std::make_optional(std::make_pair(issue1, issue2)))) + if (invalidAMMAssetPair(*optIssue1, *optIssue2, std::make_optional(std::make_pair(issue1, issue2)))) { // This error can only be hit if the AMM is corrupted // LCOV_EXCL_START - JLOG(j.debug()) << "ammHolds: Invalid optIssue1 or optIssue2 " - << *optIssue1 << " " << *optIssue2; + JLOG(j.debug()) << "ammHolds: Invalid optIssue1 or optIssue2 " << *optIssue1 << " " << *optIssue2; return std::nullopt; // LCOV_EXCL_STOP } return std::make_optional(std::make_pair(*optIssue1, *optIssue2)); } - auto const singleIssue = - [&issue1, &issue2, &j]( - Issue checkIssue, - char const* label) -> std::optional> { + auto const singleIssue = [&issue1, &issue2, &j]( + Issue checkIssue, char const* label) -> std::optional> { if (checkIssue == issue1) return std::make_optional(std::make_pair(issue1, issue2)); else if (checkIssue == issue2) return std::make_optional(std::make_pair(issue2, issue1)); // Unreachable unless AMM corrupted. // LCOV_EXCL_START - JLOG(j.debug()) - << "ammHolds: Invalid " << label << " " << checkIssue; + JLOG(j.debug()) << "ammHolds: Invalid " << label << " " << checkIssue; return std::nullopt; // LCOV_EXCL_STOP }; @@ -99,13 +71,8 @@ ammHolds( }(); if (!issues) return Unexpected(tecAMM_INVALID_TOKENS); - auto const [asset1, asset2] = ammPoolHolds( - view, - ammSle.getAccountID(sfAccount), - issues->first, - issues->second, - freezeHandling, - j); + auto const [asset1, asset2] = + ammPoolHolds(view, ammSle.getAccountID(sfAccount), issues->first, issues->second, freezeHandling, j); return std::make_tuple(asset1, asset2, ammSle[sfLPTokenBalance]); } @@ -131,15 +98,13 @@ ammLPHolds( { amount.clear(Issue{currency, ammAccount}); JLOG(j.trace()) << "ammLPHolds: no SLE " - << " lpAccount=" << to_string(lpAccount) - << " amount=" << amount.getFullText(); + << " lpAccount=" << to_string(lpAccount) << " amount=" << amount.getFullText(); } else if (isFrozen(view, lpAccount, currency, ammAccount)) { amount.clear(Issue{currency, ammAccount}); JLOG(j.trace()) << "ammLPHolds: frozen currency " - << " lpAccount=" << to_string(lpAccount) - << " amount=" << amount.getFullText(); + << " lpAccount=" << to_string(lpAccount) << " amount=" << amount.getFullText(); } else { @@ -152,19 +117,14 @@ ammLPHolds( amount.setIssuer(ammAccount); JLOG(j.trace()) << "ammLPHolds:" - << " lpAccount=" << to_string(lpAccount) - << " amount=" << amount.getFullText(); + << " lpAccount=" << to_string(lpAccount) << " amount=" << amount.getFullText(); } return view.balanceHook(lpAccount, ammAccount, amount); } STAmount -ammLPHolds( - ReadView const& view, - SLE const& ammSle, - AccountID const& lpAccount, - beast::Journal const j) +ammLPHolds(ReadView const& view, SLE const& ammSle, AccountID const& lpAccount, beast::Journal const j) { return ammLPHolds( view, @@ -180,25 +140,20 @@ getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account) { using namespace std::chrono; XRPL_ASSERT( - !view.rules().enabled(fixInnerObjTemplate) || - ammSle.isFieldPresent(sfAuctionSlot), - "ripple::getTradingFee : auction present"); + !view.rules().enabled(fixInnerObjTemplate) || ammSle.isFieldPresent(sfAuctionSlot), + "xrpl::getTradingFee : auction present"); if (ammSle.isFieldPresent(sfAuctionSlot)) { - auto const& auctionSlot = - static_cast(ammSle.peekAtField(sfAuctionSlot)); + auto const& auctionSlot = static_cast(ammSle.peekAtField(sfAuctionSlot)); // Not expired if (auto const expiration = auctionSlot[~sfExpiration]; - duration_cast( - view.info().parentCloseTime.time_since_epoch()) - .count() < expiration) + duration_cast(view.header().parentCloseTime.time_since_epoch()).count() < expiration) { if (auctionSlot[~sfAccount] == account) return auctionSlot[sfDiscountedFee]; if (auctionSlot.isFieldPresent(sfAuthAccounts)) { - for (auto const& acct : - auctionSlot.getFieldArray(sfAuthAccounts)) + for (auto const& acct : auctionSlot.getFieldArray(sfAuthAccounts)) if (acct[~sfAccount] == account) return auctionSlot[sfDiscountedFee]; } @@ -208,20 +163,15 @@ getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account) } STAmount -ammAccountHolds( - ReadView const& view, - AccountID const& ammAccountID, - Issue const& issue) +ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Issue const& issue) { if (isXRP(issue)) { if (auto const sle = view.read(keylet::account(ammAccountID))) return (*sle)[sfBalance]; } - else if (auto const sle = view.read( - keylet::line(ammAccountID, issue.account, issue.currency)); - sle && - !isFrozen(view, ammAccountID, issue.currency, issue.account)) + else if (auto const sle = view.read(keylet::line(ammAccountID, issue.account, issue.currency)); + sle && !isFrozen(view, ammAccountID, issue.currency, issue.account)) { auto amount = (*sle)[sfBalance]; if (ammAccountID > issue.account) @@ -234,18 +184,12 @@ ammAccountHolds( } static TER -deleteAMMTrustLines( - Sandbox& sb, - AccountID const& ammAccountID, - std::uint16_t maxTrustlinesToDelete, - beast::Journal j) +deleteAMMTrustLines(Sandbox& sb, AccountID const& ammAccountID, std::uint16_t maxTrustlinesToDelete, beast::Journal j) { return cleanupOnAccountDelete( sb, keylet::ownerDir(ammAccountID), - [&](LedgerEntryType nodeType, - uint256 const&, - std::shared_ptr& sleItem) -> std::pair { + [&](LedgerEntryType nodeType, uint256 const&, std::shared_ptr& sleItem) -> std::pair { // Skip AMM if (nodeType == LedgerEntryType::ltAMM) return {tesSUCCESS, SkipEntry::Yes}; @@ -253,9 +197,7 @@ deleteAMMTrustLines( if (nodeType != LedgerEntryType::ltRIPPLE_STATE) { // LCOV_EXCL_START - JLOG(j.error()) - << "deleteAMMTrustLines: deleting non-trustline " - << nodeType; + JLOG(j.error()) << "deleteAMMTrustLines: deleting non-trustline " << nodeType; return {tecINTERNAL, SkipEntry::No}; // LCOV_EXCL_STOP } @@ -264,34 +206,26 @@ deleteAMMTrustLines( if (sleItem->getFieldAmount(sfBalance) != beast::zero) { // LCOV_EXCL_START - JLOG(j.error()) - << "deleteAMMTrustLines: deleting trustline with " - "non-zero balance."; + JLOG(j.error()) << "deleteAMMTrustLines: deleting trustline with " + "non-zero balance."; return {tecINTERNAL, SkipEntry::No}; // LCOV_EXCL_STOP } - return { - deleteAMMTrustLine(sb, sleItem, ammAccountID, j), - SkipEntry::No}; + return {deleteAMMTrustLine(sb, sleItem, ammAccountID, j), SkipEntry::No}; }, j, maxTrustlinesToDelete); } TER -deleteAMMAccount( - Sandbox& sb, - Issue const& asset, - Issue const& asset2, - beast::Journal j) +deleteAMMAccount(Sandbox& sb, Issue const& asset, Issue const& asset2, beast::Journal j) { auto ammSle = sb.peek(keylet::amm(asset, asset2)); if (!ammSle) { // LCOV_EXCL_START - JLOG(j.error()) << "deleteAMMAccount: AMM object does not exist " - << asset << " " << asset2; + JLOG(j.error()) << "deleteAMMAccount: AMM object does not exist " << asset << " " << asset2; return tecINTERNAL; // LCOV_EXCL_STOP } @@ -301,20 +235,16 @@ deleteAMMAccount( if (!sleAMMRoot) { // LCOV_EXCL_START - JLOG(j.error()) << "deleteAMMAccount: AMM account does not exist " - << to_string(ammAccountID); + JLOG(j.error()) << "deleteAMMAccount: AMM account does not exist " << to_string(ammAccountID); return tecINTERNAL; // LCOV_EXCL_STOP } - if (auto const ter = - deleteAMMTrustLines(sb, ammAccountID, maxDeletableAMMTrustLines, j); - ter != tesSUCCESS) + if (auto const ter = deleteAMMTrustLines(sb, ammAccountID, maxDeletableAMMTrustLines, j); ter != tesSUCCESS) return ter; auto const ownerDirKeylet = keylet::ownerDir(ammAccountID); - if (!sb.dirRemove( - ownerDirKeylet, (*ammSle)[sfOwnerNode], ammSle->key(), false)) + if (!sb.dirRemove(ownerDirKeylet, (*ammSle)[sfOwnerNode], ammSle->key(), false)) { // LCOV_EXCL_START JLOG(j.error()) << "deleteAMMAccount: failed to remove dir link"; @@ -324,8 +254,7 @@ deleteAMMAccount( if (sb.exists(ownerDirKeylet) && !sb.emptyDirDelete(ownerDirKeylet)) { // LCOV_EXCL_START - JLOG(j.error()) << "deleteAMMAccount: cannot delete root dir node of " - << toBase58(ammAccountID); + JLOG(j.error()) << "deleteAMMAccount: cannot delete root dir node of " << toBase58(ammAccountID); return tecINTERNAL; // LCOV_EXCL_STOP } @@ -357,8 +286,7 @@ initializeFeeAuctionVote( // AMM creator gets the auction slot for free. // AuctionSlot is created on AMMCreate and updated on AMMDeposit // when AMM is in an empty state - if (rules.enabled(fixInnerObjTemplate) && - !ammSle->isFieldPresent(sfAuctionSlot)) + if (rules.enabled(fixInnerObjTemplate) && !ammSle->isFieldPresent(sfAuctionSlot)) { STObject auctionSlot = STObject::makeInnerObject(sfAuctionSlot); ammSle->set(std::move(auctionSlot)); @@ -366,9 +294,8 @@ initializeFeeAuctionVote( STObject& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot); auctionSlot.setAccountID(sfAccount, account); // current + sec in 24h - auto const expiration = std::chrono::duration_cast( - view.info().parentCloseTime.time_since_epoch()) - .count() + + auto const expiration = + std::chrono::duration_cast(view.header().parentCloseTime.time_since_epoch()).count() + TOTAL_TIME_SLOT_SECS; auctionSlot.setFieldU32(sfExpiration, expiration); auctionSlot.setFieldAmount(sfPrice, STAmount{lptIssue, 0}); @@ -384,10 +311,7 @@ initializeFeeAuctionVote( } Expected -isOnlyLiquidityProvider( - ReadView const& view, - Issue const& ammIssue, - AccountID const& lpAccount) +isOnlyLiquidityProvider(ReadView const& view, Issue const& ammIssue, AccountID const& lpAccount) { // Liquidity Provider (LP) must have one LPToken trustline std::uint8_t nLPTokenTrustLines = 0; @@ -429,10 +353,8 @@ isOnlyLiquidityProvider( return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE auto const lowLimit = sle->getFieldAmount(sfLowLimit); auto const highLimit = sle->getFieldAmount(sfHighLimit); - auto const isLPTrustline = lowLimit.getIssuer() == lpAccount || - highLimit.getIssuer() == lpAccount; - auto const isLPTokenTrustline = - lowLimit.issue() == ammIssue || highLimit.issue() == ammIssue; + auto const isLPTrustline = lowLimit.getIssuer() == lpAccount || highLimit.getIssuer() == lpAccount; + auto const isLPTokenTrustline = lowLimit.issue() == ammIssue || highLimit.issue() == ammIssue; // Liquidity Provider trustline if (isLPTrustline) @@ -455,8 +377,7 @@ isOnlyLiquidityProvider( auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); if (uNodeNext == 0) { - if (nLPTokenTrustLines != 1 || nIOUTrustLines == 0 || - nIOUTrustLines > 2) + if (nLPTokenTrustLines != 1 || nIOUTrustLines == 0 || nIOUTrustLines > 2) return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE return true; } @@ -472,15 +393,11 @@ verifyAndAdjustLPTokenBalance( std::shared_ptr& ammSle, AccountID const& account) { - if (auto const res = isOnlyLiquidityProvider(sb, lpTokens.issue(), account); - !res) + if (auto const res = isOnlyLiquidityProvider(sb, lpTokens.issue(), account); !res) return Unexpected(res.error()); else if (res.value()) { - if (withinRelativeDistance( - lpTokens, - ammSle->getFieldAmount(sfLPTokenBalance), - Number{1, -3})) + if (withinRelativeDistance(lpTokens, ammSle->getFieldAmount(sfLPTokenBalance), Number{1, -3})) { ammSle->setFieldAmount(sfLPTokenBalance, lpTokens); sb.update(ammSle); @@ -493,4 +410,4 @@ verifyAndAdjustLPTokenBalance( return true; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/AccountTxPaging.cpp b/src/xrpld/app/misc/detail/AccountTxPaging.cpp index ff59e4022f..e3fc2de4f8 100644 --- a/src/xrpld/app/misc/detail/AccountTxPaging.cpp +++ b/src/xrpld/app/misc/detail/AccountTxPaging.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -24,7 +5,7 @@ #include -namespace ripple { +namespace xrpl { void convertBlobsToTxResult( @@ -63,4 +44,4 @@ saveLedgerAsync(Application& app, std::uint32_t seq) pendSaveValidated(app, l, false, false); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/AccountTxPaging.h b/src/xrpld/app/misc/detail/AccountTxPaging.h index 062c3e867d..209ca67ab6 100644 --- a/src/xrpld/app/misc/detail/AccountTxPaging.h +++ b/src/xrpld/app/misc/detail/AccountTxPaging.h @@ -1,32 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. +#pragma once - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED -#define RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED - -#include +#include #include //------------------------------------------------------------------------------ -namespace ripple { +namespace xrpl { void convertBlobsToTxResult( @@ -40,6 +20,4 @@ convertBlobsToTxResult( void saveLedgerAsync(Application& app, std::uint32_t seq); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp index 9f73879700..3addfd2235 100644 --- a/src/xrpld/app/misc/detail/AmendmentTable.cpp +++ b/src/xrpld/app/misc/detail/AmendmentTable.cpp @@ -1,31 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -#include #include #include #include #include #include +#include #include #include @@ -35,7 +16,7 @@ #include #include -namespace ripple { +namespace xrpl { static std::vector> parseSection(Section const& section) @@ -56,15 +37,12 @@ parseSection(Section const& section) boost::smatch match; if (!boost::regex_match(line, match, re1)) - Throw( - "Invalid entry '" + line + "' in [" + section.name() + "]"); + Throw("Invalid entry '" + line + "' in [" + section.name() + "]"); uint256 id; if (!id.parseHex(match[1])) - Throw( - "Invalid amendment ID '" + match[1] + "' in [" + - section.name() + "]"); + Throw("Invalid amendment ID '" + match[1] + "' in [" + section.name() + "]"); names.push_back(std::make_pair(id, match[2])); } @@ -117,9 +95,7 @@ public: // // Call with AmendmentTable::mutex_ locked. void - trustChanged( - hash_set const& allTrusted, - std::lock_guard const& lock) + trustChanged(hash_set const& allTrusted, std::lock_guard const& lock) { decltype(recordedVotes_) newRecordedVotes; newRecordedVotes.reserve(allTrusted.size()); @@ -177,25 +153,20 @@ public: // validators with these newest votes. for (auto const& val : valSet) { - auto const pkHuman = - toBase58(TokenType::NodePublic, val->getSignerPublic()); + auto const pkHuman = toBase58(TokenType::NodePublic, val->getSignerPublic()); // If this validation comes from one of our trusted validators... - if (auto const iter = recordedVotes_.find(val->getSignerPublic()); - iter != recordedVotes_.end()) + if (auto const iter = recordedVotes_.find(val->getSignerPublic()); iter != recordedVotes_.end()) { iter->second.timeout = newTimeout; if (val->isFieldPresent(sfAmendments)) { auto const& choices = val->getFieldV256(sfAmendments); iter->second.upVotes.assign(choices.begin(), choices.end()); - JLOG(j.debug()) - << "recordVotes: Validation from trusted " << pkHuman - << " has " << choices.size() << " amendment votes: " - << boost::algorithm::join( - iter->second.upVotes | - boost::adaptors::transformed( - to_string<256, void>), - ", "); + JLOG(j.debug()) << "recordVotes: Validation from trusted " << pkHuman << " has " << choices.size() + << " amendment votes: " + << boost::algorithm::join( + iter->second.upVotes | boost::adaptors::transformed(to_string<256, void>), + ", "); // TODO: Maybe transform using to_short_string once #5126 is // merged // @@ -206,15 +177,12 @@ public: { // This validator does not upVote any amendments right now. iter->second.upVotes.clear(); - JLOG(j.debug()) << "recordVotes: Validation from trusted " - << pkHuman << " has no amendment votes."; + JLOG(j.debug()) << "recordVotes: Validation from trusted " << pkHuman << " has no amendment votes."; } } else { - JLOG(j.debug()) - << "recordVotes: Ignoring validation from untrusted " - << pkHuman; + JLOG(j.debug()) << "recordVotes: Ignoring validation from untrusted " << pkHuman; } } @@ -222,26 +190,21 @@ public: std::for_each( recordedVotes_.begin(), recordedVotes_.end(), - [&closeTime, newTimeout, &j]( - decltype(recordedVotes_)::value_type& votes) { - auto const pkHuman = - toBase58(TokenType::NodePublic, votes.first); + [&closeTime, newTimeout, &j](decltype(recordedVotes_)::value_type& votes) { + auto const pkHuman = toBase58(TokenType::NodePublic, votes.first); if (!votes.second.timeout) { XRPL_ASSERT( votes.second.upVotes.empty(), - "ripple::TrustedVotes::recordVotes : received no " + "xrpl::TrustedVotes::recordVotes : received no " "upvotes"); - JLOG(j.debug()) - << "recordVotes: Have not received any " - "amendment votes from " - << pkHuman << " since last timeout or startup"; + JLOG(j.debug()) << "recordVotes: Have not received any " + "amendment votes from " + << pkHuman << " since last timeout or startup"; } else if (closeTime > votes.second.timeout) { - JLOG(j.debug()) - << "recordVotes: Timeout: Clearing votes from " - << pkHuman; + JLOG(j.debug()) << "recordVotes: Timeout: Clearing votes from " << pkHuman; votes.second.timeout.reset(); votes.second.upVotes.clear(); } @@ -249,13 +212,11 @@ public: { XRPL_ASSERT( votes.second.timeout < newTimeout, - "ripple::TrustedVotes::recordVotes : votes not " + "xrpl::TrustedVotes::recordVotes : votes not " "expired"); using namespace std::chrono; - auto const age = duration_cast( - newTimeout - *votes.second.timeout); - JLOG(j.debug()) << "recordVotes: Using " << age.count() - << "min old cached votes from " << pkHuman; + auto const age = duration_cast(newTimeout - *votes.second.timeout); + JLOG(j.debug()) << "recordVotes: Using " << age.count() << "min old cached votes from " << pkHuman; } }); } @@ -271,9 +232,8 @@ public: for (auto& validatorVotes : recordedVotes_) { XRPL_ASSERT( - validatorVotes.second.timeout || - validatorVotes.second.upVotes.empty(), - "ripple::TrustedVotes::getVotes : valid votes"); + validatorVotes.second.timeout || validatorVotes.second.upVotes.empty(), + "xrpl::TrustedVotes::getVotes : valid votes"); if (validatorVotes.second.timeout) ++available; for (uint256 const& amendment : validatorVotes.second.upVotes) @@ -322,10 +282,7 @@ private: int threshold_ = 0; public: - AmendmentSet( - Rules const& rules, - TrustedVotes const& trustedVotes, - std::lock_guard const& lock) + AmendmentSet(Rules const& rules, TrustedVotes const& trustedVotes, std::lock_guard const& lock) { // process validations for ledger before flag ledger. auto [trustedCount, newVotes] = trustedVotes.getVotes(rules, lock); @@ -336,8 +293,7 @@ public: threshold_ = std::max( 1L, static_cast( - (trustedValidations_ * amendmentMajorityCalcThreshold.num) / - amendmentMajorityCalcThreshold.den)); + (trustedValidations_ * amendmentMajorityCalcThreshold.num) / amendmentMajorityCalcThreshold.den)); } bool @@ -428,8 +384,7 @@ private: get(uint256 const& amendment, std::lock_guard const& lock); AmendmentState const* - get(uint256 const& amendment, - std::lock_guard const& lock) const; + get(uint256 const& amendment, std::lock_guard const& lock) const; // Injects amendment json into v. Must be called with mutex_ locked. void @@ -441,10 +396,7 @@ private: std::lock_guard const& lock) const; void - persistVote( - uint256 const& amendment, - std::string const& name, - AmendmentVote vote) const; + persistVote(uint256 const& amendment, std::string const& name, AmendmentVote vote) const; public: AmendmentTableImpl( @@ -486,10 +438,7 @@ public: needValidatedLedger(LedgerIndex seq) const override; void - doValidatedLedger( - LedgerIndex seq, - std::set const& enabled, - majorityAmendments_t const& majority) override; + doValidatedLedger(LedgerIndex seq, std::set const& enabled, majorityAmendments_t const& majority) override; void trustChanged(hash_set const& allTrusted) override; @@ -518,11 +467,7 @@ AmendmentTableImpl::AmendmentTableImpl( Section const& enabled, Section const& vetoed, beast::Journal journal) - : lastUpdateSeq_(0) - , majorityTime_(majorityTime) - , unsupportedEnabled_(false) - , j_(journal) - , db_(app.getWalletDB()) + : lastUpdateSeq_(0), majorityTime_(majorityTime), unsupportedEnabled_(false), j_(journal), db_(app.getWalletDB()) { std::lock_guard lock(mutex_); @@ -554,8 +499,7 @@ AmendmentTableImpl::AmendmentTableImpl( break; } - JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name - << ") is supported and will be " + JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name << ") is supported and will be " << (s.vote == AmendmentVote::up ? "up" : "down") << " voted by default if not enabled on the ledger."; } @@ -582,9 +526,8 @@ AmendmentTableImpl::AmendmentTableImpl( { if (featureVotesExist) { // If the table existed, warn about duplicate config info - JLOG(j_.warn()) - << "[veto_amendments] section in config file ignored" - " in favor of data in db/wallet.db."; + JLOG(j_.warn()) << "[veto_amendments] section in config file ignored" + " in favor of data in db/wallet.db."; break; } else @@ -595,10 +538,8 @@ AmendmentTableImpl::AmendmentTableImpl( } else { - JLOG(j_.warn()) - << "[veto_amendments] section in config has amendment " - << '(' << a.first << ", " << a.second - << ") both [veto_amendments] and [amendments]."; + JLOG(j_.warn()) << "[veto_amendments] section in config has amendment " << '(' << a.first << ", " + << a.second << ") both [veto_amendments] and [amendments]."; } } } @@ -614,22 +555,18 @@ AmendmentTableImpl::AmendmentTableImpl( if (!amendment_hash || !amendment_name || !vote) { // These fields should never have nulls, but check - Throw( - "Invalid FeatureVotes row in wallet.db"); + Throw("Invalid FeatureVotes row in wallet.db"); } if (!amend_hash.parseHex(*amendment_hash)) { - Throw( - "Invalid amendment ID '" + *amendment_hash + - " in wallet.db"); + Throw("Invalid amendment ID '" + *amendment_hash + " in wallet.db"); } if (*vote == AmendmentVote::down) { // Unknown amendments are effectively vetoed already if (auto s = get(amend_hash, lock)) { - JLOG(j_.info()) << "Amendment {" << *amendment_name << ", " - << amend_hash << "} is downvoted."; + JLOG(j_.info()) << "Amendment {" << *amendment_name << ", " << amend_hash << "} is downvoted."; if (!amendment_name->empty()) s->name = *amendment_name; // An obsolete amendment's vote can never be changed @@ -641,8 +578,7 @@ AmendmentTableImpl::AmendmentTableImpl( { AmendmentState& s = add(amend_hash, lock); - JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", " - << amend_hash << "} is upvoted."; + JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", " << amend_hash << "} is upvoted."; if (!amendment_name->empty()) s.name = *amendment_name; // An obsolete amendment's vote can never be changed @@ -653,28 +589,21 @@ AmendmentTableImpl::AmendmentTableImpl( } AmendmentState& -AmendmentTableImpl::add( - uint256 const& amendmentHash, - std::lock_guard const&) +AmendmentTableImpl::add(uint256 const& amendmentHash, std::lock_guard const&) { // call with the mutex held return amendmentMap_[amendmentHash]; } AmendmentState* -AmendmentTableImpl::get( - uint256 const& amendmentHash, - std::lock_guard const& lock) +AmendmentTableImpl::get(uint256 const& amendmentHash, std::lock_guard const& lock) { // Forward to the const version of get. - return const_cast( - std::as_const(*this).get(amendmentHash, lock)); + return const_cast(std::as_const(*this).get(amendmentHash, lock)); } AmendmentState const* -AmendmentTableImpl::get( - uint256 const& amendmentHash, - std::lock_guard const&) const +AmendmentTableImpl::get(uint256 const& amendmentHash, std::lock_guard const&) const { // call with the mutex held auto ret = amendmentMap_.find(amendmentHash); @@ -700,14 +629,9 @@ AmendmentTableImpl::find(std::string const& name) const } void -AmendmentTableImpl::persistVote( - uint256 const& amendment, - std::string const& name, - AmendmentVote vote) const +AmendmentTableImpl::persistVote(uint256 const& amendment, std::string const& name, AmendmentVote vote) const { - XRPL_ASSERT( - vote != AmendmentVote::obsolete, - "ripple::AmendmentTableImpl::persistVote : valid vote input"); + XRPL_ASSERT(vote != AmendmentVote::obsolete, "xrpl::AmendmentTableImpl::persistVote : valid vote input"); auto db = db_.checkoutDb(); voteAmendment(*db, amendment, name, vote); } @@ -751,8 +675,7 @@ AmendmentTableImpl::enable(uint256 const& amendment) if (!s.supported) { - JLOG(j_.error()) << "Unsupported amendment " << amendment - << " activated."; + JLOG(j_.error()) << "Unsupported amendment " << amendment << " activated."; unsupportedEnabled_ = true; } @@ -801,8 +724,7 @@ AmendmentTableImpl::doValidation(std::set const& enabled) const amendments.reserve(amendmentMap_.size()); for (auto const& e : amendmentMap_) { - if (e.second.supported && e.second.vote == AmendmentVote::up && - (enabled.count(e.first) == 0)) + if (e.second.supported && e.second.vote == AmendmentVote::up && (enabled.count(e.first) == 0)) { amendments.push_back(e.first); JLOG(j_.info()) << "Voting for amendment " << e.second.name; @@ -831,8 +753,7 @@ AmendmentTableImpl::doVoting( majorityAmendments_t const& majorityAmendments, std::vector> const& valSet) { - JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count() - << ": " << enabledAmendments.size() << ", " + JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count() << ": " << enabledAmendments.size() << ", " << majorityAmendments.size() << ", " << valSet.size(); std::lock_guard lock(mutex_); @@ -841,11 +762,9 @@ AmendmentTableImpl::doVoting( previousTrustedVotes_.recordVotes(rules, valSet, closeTime, j_, lock); // Tally the most recent votes. - auto vote = - std::make_unique(rules, previousTrustedVotes_, lock); + auto vote = std::make_unique(rules, previousTrustedVotes_, lock); JLOG(j_.debug()) << "Counted votes from " << vote->trustedValidations() - << " valid trusted validations, threshold is: " - << vote->threshold(); + << " valid trusted validations, threshold is: " << vote->threshold(); // Map of amendments to the action to be taken for each one. The action is // the value of the flags in the pseudo-transaction @@ -874,13 +793,11 @@ AmendmentTableImpl::doVoting( auto const logStr = [&entry, &vote]() { std::stringstream ss; - ss << entry.first << " (" << entry.second.name << ") has " - << vote->votes(entry.first) << " votes"; + ss << entry.first << " (" << entry.second.name << ") has " << vote->votes(entry.first) << " votes"; return ss.str(); }(); - if (hasValMajority && !hasLedgerMajority && - entry.second.vote == AmendmentVote::up) + if (hasValMajority && !hasLedgerMajority && entry.second.vote == AmendmentVote::up) { // Ledger says no majority, validators say yes, and voting yes // locally @@ -894,8 +811,7 @@ AmendmentTableImpl::doVoting( actions[entry.first] = tfLostMajority; } else if ( - hasLedgerMajority && - ((*majorityTime + majorityTime_) <= closeTime) && + hasLedgerMajority && ((*majorityTime + majorityTime_) <= closeTime) && entry.second.vote == AmendmentVote::up) { // Ledger says majority held @@ -905,9 +821,7 @@ AmendmentTableImpl::doVoting( // Logging only below this point else if (hasValMajority && hasLedgerMajority) { - JLOG(j_.debug()) - << logStr - << ": amendment holding majority, waiting to be enabled"; + JLOG(j_.debug()) << logStr << ": amendment holding majority, waiting to be enabled"; } else if (!hasValMajority) { @@ -958,8 +872,7 @@ AmendmentTableImpl::doValidatedLedger( if (!s.supported) { - JLOG(j_.info()) << "Unsupported amendment " << hash - << " reached majority at " << to_string(time); + JLOG(j_.info()) << "Unsupported amendment " << hash << " reached majority at " << to_string(time); if (!firstUnsupportedExpected_ || firstUnsupportedExpected_ > time) firstUnsupportedExpected_ = time; } @@ -1018,12 +931,7 @@ AmendmentTableImpl::getJson(bool isAdmin) const std::lock_guard lock(mutex_); for (auto const& e : amendmentMap_) { - injectJson( - ret[to_string(e.first)] = Json::objectValue, - e.first, - e.second, - isAdmin, - lock); + injectJson(ret[to_string(e.first)] = Json::objectValue, e.first, e.second, isAdmin, lock); } } return ret; @@ -1039,8 +947,7 @@ AmendmentTableImpl::getJson(uint256 const& amendmentID, bool isAdmin) const AmendmentState const* a = get(amendmentID, lock); if (a) { - Json::Value& jAmendment = - (ret[to_string(amendmentID)] = Json::objectValue); + Json::Value& jAmendment = (ret[to_string(amendmentID)] = Json::objectValue); injectJson(jAmendment, amendmentID, *a, isAdmin, lock); } } @@ -1057,8 +964,7 @@ make_AmendmentTable( Section const& vetoed, beast::Journal journal) { - return std::make_unique( - app, majorityTime, supported, enabled, vetoed, journal); + return std::make_unique(app, majorityTime, supported, enabled, vetoed, journal); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/DelegateUtils.cpp b/src/xrpld/app/misc/detail/DelegateUtils.cpp index 19aed98776..74ec55cdee 100644 --- a/src/xrpld/app/misc/detail/DelegateUtils.cpp +++ b/src/xrpld/app/misc/detail/DelegateUtils.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2025 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { NotTEC checkTxPermission(std::shared_ptr const& delegate, STTx const& tx) { @@ -54,13 +35,11 @@ loadGranularPermission( for (auto const& permission : permissionArray) { auto const permissionValue = permission[sfPermissionValue]; - auto const granularValue = - static_cast(permissionValue); - auto const& type = - Permission::getInstance().getGranularTxType(granularValue); + auto const granularValue = static_cast(permissionValue); + auto const& type = Permission::getInstance().getGranularTxType(granularValue); if (type && *type == txType) granularPermissions.insert(granularValue); } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/DeliverMax.cpp b/src/xrpld/app/misc/detail/DeliverMax.cpp index 58a2359972..44500eec7e 100644 --- a/src/xrpld/app/misc/detail/DeliverMax.cpp +++ b/src/xrpld/app/misc/detail/DeliverMax.cpp @@ -1,27 +1,8 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { namespace RPC { void @@ -39,4 +20,4 @@ insertDeliverMax(Json::Value& tx_json, TxType txnType, unsigned int apiVersion) } } // namespace RPC -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/LendingHelpers.cpp b/src/xrpld/app/misc/detail/LendingHelpers.cpp new file mode 100644 index 0000000000..106eeb9301 --- /dev/null +++ b/src/xrpld/app/misc/detail/LendingHelpers.cpp @@ -0,0 +1,1798 @@ +#include +// DO NOT REMOVE forces header file include to sort first +#include + +namespace xrpl { + +bool +checkLendingProtocolDependencies(PreflightContext const& ctx) +{ + return ctx.rules.enabled(featureSingleAssetVault) && VaultCreate::checkExtraFeatures(ctx); +} + +LoanPaymentParts& +LoanPaymentParts::operator+=(LoanPaymentParts const& other) +{ + XRPL_ASSERT( + + other.principalPaid >= beast::zero, + "xrpl::LoanPaymentParts::operator+= : other principal " + "non-negative"); + XRPL_ASSERT( + other.interestPaid >= beast::zero, + "xrpl::LoanPaymentParts::operator+= : other interest paid " + "non-negative"); + XRPL_ASSERT( + other.feePaid >= beast::zero, + "xrpl::LoanPaymentParts::operator+= : other fee paid " + "non-negative"); + + principalPaid += other.principalPaid; + interestPaid += other.interestPaid; + valueChange += other.valueChange; + feePaid += other.feePaid; + return *this; +} + +bool +LoanPaymentParts::operator==(LoanPaymentParts const& other) const +{ + return principalPaid == other.principalPaid && interestPaid == other.interestPaid && + valueChange == other.valueChange && feePaid == other.feePaid; +} + +/* Converts annualized interest rate to per-payment-period rate. + * The rate is prorated based on the payment interval in seconds. + * + * Equation (1) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval) +{ + // Need floating point math, since we're dividing by a large number + return tenthBipsOfValue(Number(paymentInterval), interestRate) / secondsInYear; +} + +/* Checks if a value is already rounded to the specified scale. + * Returns true if rounding down and rounding up produce the same result, + * indicating no further precision exists beyond the scale. + */ +bool +isRounded(Asset const& asset, Number const& value, std::int32_t scale) +{ + return roundToAsset(asset, value, scale, Number::downward) == roundToAsset(asset, value, scale, Number::upward); +} + +namespace detail { + +void +LoanStateDeltas::nonNegative() +{ + if (principal < beast::zero) + principal = numZero; + if (interest < beast::zero) + interest = numZero; + if (managementFee < beast::zero) + managementFee = numZero; +} + +/* Computes (1 + periodicRate)^paymentsRemaining for amortization calculations. + * + * Equation (5) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +computeRaisedRate(Number const& periodicRate, std::uint32_t paymentsRemaining) +{ + return power(1 + periodicRate, paymentsRemaining); +} + +/* Computes the payment factor used in standard amortization formulas. + * This factor converts principal to periodic payment amount. + * + * Equation (6) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +computePaymentFactor(Number const& periodicRate, std::uint32_t paymentsRemaining) +{ + if (paymentsRemaining == 0) + return numZero; + + // For zero interest, payment factor is simply 1/paymentsRemaining + if (periodicRate == beast::zero) + return Number{1} / paymentsRemaining; + + Number const raisedRate = computeRaisedRate(periodicRate, paymentsRemaining); + + return (periodicRate * raisedRate) / (raisedRate - 1); +} + +/* Calculates the periodic payment amount using standard amortization formula. + * For interest-free loans, returns principal divided equally across payments. + * + * Equation (7) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +loanPeriodicPayment(Number const& principalOutstanding, Number const& periodicRate, std::uint32_t paymentsRemaining) +{ + if (principalOutstanding == 0 || paymentsRemaining == 0) + return 0; + + // Interest-free loans: equal principal payments + if (periodicRate == beast::zero) + return principalOutstanding / paymentsRemaining; + + return principalOutstanding * computePaymentFactor(periodicRate, paymentsRemaining); +} + +/* Reverse-calculates principal from periodic payment amount. + * Used to determine theoretical principal at any point in the schedule. + * + * Equation (10) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +loanPrincipalFromPeriodicPayment( + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentsRemaining) +{ + if (paymentsRemaining == 0) + return numZero; + + if (periodicRate == 0) + return periodicPayment * paymentsRemaining; + + return periodicPayment / computePaymentFactor(periodicRate, paymentsRemaining); +} + +/* + * Computes the interest and management fee parts from interest amount. + * + * Equation (33) from XLS-66 spec, Section A-2 Equation Glossary + */ +std::pair +computeInterestAndFeeParts( + Asset const& asset, + Number const& interest, + TenthBips16 managementFeeRate, + std::int32_t loanScale) +{ + auto const fee = computeManagementFee(asset, interest, managementFeeRate, loanScale); + + return std::make_pair(interest - fee, fee); +} + +/* Calculates penalty interest accrued on overdue payments. + * Returns 0 if payment is not late. + * + * Equation (16) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +loanLatePaymentInterest( + Number const& principalOutstanding, + TenthBips32 lateInterestRate, + NetClock::time_point parentCloseTime, + std::uint32_t nextPaymentDueDate) +{ + if (principalOutstanding == beast::zero) + return numZero; + + if (lateInterestRate == TenthBips32{0}) + return numZero; + + auto const now = parentCloseTime.time_since_epoch().count(); + + // If the payment is not late by any amount of time, then there's no late + // interest + if (now <= nextPaymentDueDate) + return 0; + + // Equation (3) from XLS-66 spec, Section A-2 Equation Glossary + auto const secondsOverdue = now - nextPaymentDueDate; + + auto const rate = loanPeriodicRate(lateInterestRate, secondsOverdue); + + return principalOutstanding * rate; +} + +/* Calculates interest accrued since the last payment based on time elapsed. + * Returns 0 if loan is paid ahead of schedule. + * + * Equation (27) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +loanAccruedInterest( + Number const& principalOutstanding, + Number const& periodicRate, + NetClock::time_point parentCloseTime, + std::uint32_t startDate, + std::uint32_t prevPaymentDate, + std::uint32_t paymentInterval) +{ + if (periodicRate == beast::zero) + return numZero; + + if (paymentInterval == 0) + return numZero; + + auto const lastPaymentDate = std::max(prevPaymentDate, startDate); + auto const now = parentCloseTime.time_since_epoch().count(); + + // If the loan has been paid ahead, then "lastPaymentDate" is in the future, + // and no interest has accrued. + if (now <= lastPaymentDate) + return numZero; + + // Equation (4) from XLS-66 spec, Section A-2 Equation Glossary + auto const secondsSinceLastPayment = now - lastPaymentDate; + + // Division is more likely to introduce rounding errors, which will then get + // amplified by multiplication. Therefore, we first multiply, and only then + // divide. + return principalOutstanding * periodicRate * secondsSinceLastPayment / paymentInterval; +} + +/* Applies a payment to the loan state and returns the breakdown of amounts + * paid. + * + * This is the core function that updates the Loan ledger object fields based on + * a computed payment. + + * The function is templated to work with both direct Number/uint32_t values + * (for testing/simulation) and ValueProxy types (for actual ledger updates). + */ +template +LoanPaymentParts +doPayment( + ExtendedPaymentComponents const& payment, + NumberProxy& totalValueOutstandingProxy, + NumberProxy& principalOutstandingProxy, + NumberProxy& managementFeeOutstandingProxy, + UInt32Proxy& paymentRemainingProxy, + UInt32Proxy& prevPaymentDateProxy, + UInt32OptionalProxy& nextDueDateProxy, + std::uint32_t paymentInterval) +{ + XRPL_ASSERT_PARTS(nextDueDateProxy, "xrpl::detail::doPayment", "Next due date proxy set"); + + if (payment.specialCase == PaymentSpecialCase::final) + { + XRPL_ASSERT_PARTS( + principalOutstandingProxy == payment.trackedPrincipalDelta, + "xrpl::detail::doPayment", + "Full principal payment"); + XRPL_ASSERT_PARTS( + totalValueOutstandingProxy == payment.trackedValueDelta, "xrpl::detail::doPayment", "Full value payment"); + XRPL_ASSERT_PARTS( + managementFeeOutstandingProxy == payment.trackedManagementFeeDelta, + "xrpl::detail::doPayment", + "Full management fee payment"); + + // Mark the loan as complete + paymentRemainingProxy = 0; + + // Record when the final payment was made + prevPaymentDateProxy = *nextDueDateProxy; + + // Clear the next due date. Setting it to 0 causes + // it to be removed from the Loan ledger object, saving space. + nextDueDateProxy = 0; + + // Zero out all tracked loan balances to mark the loan as paid off. + // These will be removed from the Loan object since they're default + // values. + principalOutstandingProxy = 0; + totalValueOutstandingProxy = 0; + managementFeeOutstandingProxy = 0; + } + else + { + // For regular payments (not overpayments), advance the payment schedule + if (payment.specialCase != PaymentSpecialCase::extra) + { + paymentRemainingProxy -= 1; + + prevPaymentDateProxy = nextDueDateProxy; + nextDueDateProxy += paymentInterval; + } + XRPL_ASSERT_PARTS( + principalOutstandingProxy > payment.trackedPrincipalDelta, + "xrpl::detail::doPayment", + "Partial principal payment"); + XRPL_ASSERT_PARTS( + totalValueOutstandingProxy > payment.trackedValueDelta, "xrpl::detail::doPayment", "Partial value payment"); + // Management fees are expected to be relatively small, and could get to + // zero before the loan is paid off + XRPL_ASSERT_PARTS( + managementFeeOutstandingProxy >= payment.trackedManagementFeeDelta, + "xrpl::detail::doPayment", + "Valid management fee"); + + // Apply the payment deltas to reduce the outstanding balances + principalOutstandingProxy -= payment.trackedPrincipalDelta; + totalValueOutstandingProxy -= payment.trackedValueDelta; + managementFeeOutstandingProxy -= payment.trackedManagementFeeDelta; + } + + // Principal can never exceed total value (principal is part of total value) + XRPL_ASSERT_PARTS( + // Use an explicit cast because the template parameter can be + // ValueProxy or Number + static_cast(principalOutstandingProxy) <= static_cast(totalValueOutstandingProxy), + "xrpl::detail::doPayment", + "principal does not exceed total"); + + XRPL_ASSERT_PARTS( + // Use an explicit cast because the template parameter can be + // ValueProxy or Number + static_cast(managementFeeOutstandingProxy) >= beast::zero, + "xrpl::detail::doPayment", + "fee outstanding stays valid"); + + return LoanPaymentParts{// Principal paid is straightforward - it's the tracked delta + .principalPaid = payment.trackedPrincipalDelta, + + // Interest paid combines: + // 1. Tracked interest from the amortization schedule + // (derived from the tracked deltas) + // 2. Untracked interest (e.g., late payment penalties) + .interestPaid = payment.trackedInterestPart() + payment.untrackedInterest, + + // Value change represents how the loan's total value changed beyond + // normal amortization. + .valueChange = payment.untrackedInterest, + + // Fee paid combines: + // 1. Tracked management fees from the amortization schedule + // 2. Untracked fees (e.g., late payment fees, service fees) + .feePaid = payment.trackedManagementFeeDelta + payment.untrackedManagementFee}; +} + +/* Simulates an overpayment to validate it won't break the loan's amortization. + * + * When a borrower pays more than the scheduled amount, the loan needs to be + * re-amortized with a lower principal. This function performs that calculation + * in a "sandbox" using temporary variables, allowing the caller to validate + * the result before committing changes to the actual ledger. + * + * The function preserves accumulated rounding errors across the re-amortization + * to ensure the loan state remains consistent with its payment history. + */ +Expected, TER> +tryOverpayment( + Asset const& asset, + std::int32_t loanScale, + ExtendedPaymentComponents const& overpaymentComponents, + LoanState const& roundedOldState, + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentRemaining, + TenthBips16 const managementFeeRate, + beast::Journal j) +{ + // Calculate what the loan state SHOULD be theoretically (at full precision) + auto const theoreticalState = + computeTheoreticalLoanState(periodicPayment, periodicRate, paymentRemaining, managementFeeRate); + + // Calculate the accumulated rounding errors. These need to be preserved + // across the re-amortization to maintain consistency with the loan's + // payment history. Without preserving these errors, the loan could end + // up with a different total value than what the borrower has actually paid. + auto const errors = roundedOldState - theoreticalState; + + // Compute the new principal by applying the overpayment to the theoretical + // principal. Use max with 0 to ensure we never go negative. + auto const newTheoreticalPrincipal = + std::max(theoreticalState.principalOutstanding - overpaymentComponents.trackedPrincipalDelta, Number{0}); + + // Compute new loan properties based on the reduced principal. This + // recalculates the periodic payment, total value, and management fees + // for the remaining payment schedule. + auto newLoanProperties = computeLoanProperties( + asset, newTheoreticalPrincipal, periodicRate, paymentRemaining, managementFeeRate, loanScale); + + JLOG(j.debug()) << "new periodic payment: " << newLoanProperties.periodicPayment + << ", new total value: " << newLoanProperties.loanState.valueOutstanding + << ", first payment principal: " << newLoanProperties.firstPaymentPrincipal; + + // Calculate what the new loan state should be with the new periodic payment + // including rounding errors + auto const newTheoreticalState = + computeTheoreticalLoanState( + newLoanProperties.periodicPayment, periodicRate, paymentRemaining, managementFeeRate) + + errors; + + JLOG(j.debug()) << "new theoretical value: " << newTheoreticalState.valueOutstanding + << ", principal: " << newTheoreticalState.principalOutstanding + << ", interest gross: " << newTheoreticalState.interestOutstanding(); + + // Update the loan state variables with the new values that include the + // preserved rounding errors. This ensures the loan's tracked state remains + // consistent with its payment history. + auto const principalOutstanding = std::clamp( + roundToAsset(asset, newTheoreticalState.principalOutstanding, loanScale, Number::upward), + numZero, + roundedOldState.principalOutstanding); + auto const totalValueOutstanding = std::clamp( + roundToAsset( + asset, principalOutstanding + newTheoreticalState.interestOutstanding(), loanScale, Number::upward), + numZero, + roundedOldState.valueOutstanding); + auto const managementFeeOutstanding = std::clamp( + roundToAsset(asset, newTheoreticalState.managementFeeDue, loanScale), + numZero, + roundedOldState.managementFeeDue); + + auto const roundedNewState = + constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding); + + // Update newLoanProperties so that checkLoanGuards can make an accurate + // evaluation. + newLoanProperties.loanState = roundedNewState; + + JLOG(j.debug()) << "new rounded value: " << roundedNewState.valueOutstanding + << ", principal: " << roundedNewState.principalOutstanding + << ", interest gross: " << roundedNewState.interestOutstanding(); + + // check that the loan is still valid + if (auto const ter = checkLoanGuards( + asset, + principalOutstanding, + // The loan may have been created with interest, but for + // small interest amounts, that may have already been paid + // off. Check what's still outstanding. This should + // guarantee that the interest checks pass. + roundedNewState.interestOutstanding() != beast::zero, + paymentRemaining, + newLoanProperties, + j)) + { + JLOG(j.warn()) << "Principal overpayment would cause the loan to be in " + "an invalid state. Ignore the overpayment"; + + return Unexpected(tesSUCCESS); + } + + // Validate that all computed properties are reasonable. These checks should + // never fail under normal circumstances, but we validate defensively. + if (newLoanProperties.periodicPayment <= 0 || newLoanProperties.loanState.valueOutstanding <= 0 || + newLoanProperties.loanState.managementFeeDue < 0) + { + // LCOV_EXCL_START + JLOG(j.warn()) << "Overpayment not allowed: Computed loan " + "properties are invalid. Does " + "not compute. TotalValueOutstanding: " + << newLoanProperties.loanState.valueOutstanding + << ", PeriodicPayment : " << newLoanProperties.periodicPayment + << ", ManagementFeeOwedToBroker: " << newLoanProperties.loanState.managementFeeDue; + return Unexpected(tesSUCCESS); + // LCOV_EXCL_STOP + } + + auto const deltas = roundedOldState - roundedNewState; + + // The change in loan management fee is equal to the change between the old + // and the new outstanding management fees + XRPL_ASSERT_PARTS( + deltas.managementFee == roundedOldState.managementFeeDue - managementFeeOutstanding, + "xrpl::detail::tryOverpayment", + "no fee change"); + + // Calculate how the loan's value changed due to the overpayment. + // This should be negative (value decreased) or zero. A principal + // overpayment should never increase the loan's value. + // The value change is derived from the reduction in interest due to + // the lower principal. + // We do not consider the change in management fee here, since + // management fees are excluded from the valueOutstanding. + auto const valueChange = -deltas.interest; + if (valueChange > 0) + { + JLOG(j.warn()) << "Principal overpayment would increase the value of " + "the loan. Ignore the overpayment"; + return Unexpected(tesSUCCESS); + } + + return std::make_pair( + LoanPaymentParts{ + // Principal paid is the reduction in principal outstanding + .principalPaid = deltas.principal, + // Interest paid is the reduction in interest due + .interestPaid = overpaymentComponents.untrackedInterest, + // Value change includes both the reduction from paying down + // principal (negative) and any untracked interest penalties + // (positive, e.g., if the overpayment itself incurs a fee) + .valueChange = valueChange + overpaymentComponents.untrackedInterest, + // Fee paid includes both the reduction in tracked management fees + // and any untracked fees on the overpayment itself + .feePaid = overpaymentComponents.untrackedManagementFee + overpaymentComponents.trackedManagementFeeDelta, + }, + newLoanProperties); +} + +/* Validates and applies an overpayment to the loan state. + * + * This function acts as a wrapper around tryOverpayment(), performing the + * re-amortization calculation in a sandbox (using temporary copies of the + * loan state), then validating the results before committing them to the + * actual ledger via the proxy objects. + * + * The two-step process (try in sandbox, then commit) ensures that if the + * overpayment would leave the loan in an invalid state, we can reject it + * gracefully without corrupting the ledger data. + */ +template +Expected +doOverpayment( + Asset const& asset, + std::int32_t loanScale, + ExtendedPaymentComponents const& overpaymentComponents, + NumberProxy& totalValueOutstandingProxy, + NumberProxy& principalOutstandingProxy, + NumberProxy& managementFeeOutstandingProxy, + NumberProxy& periodicPaymentProxy, + Number const& periodicRate, + std::uint32_t const paymentRemaining, + TenthBips16 const managementFeeRate, + beast::Journal j) +{ + auto const loanState = + constructLoanState(totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy); + auto const periodicPayment = periodicPaymentProxy; + JLOG(j.debug()) << "overpayment components:" + << ", totalValue before: " << *totalValueOutstandingProxy + << ", valueDelta: " << overpaymentComponents.trackedValueDelta + << ", principalDelta: " << overpaymentComponents.trackedPrincipalDelta + << ", managementFeeDelta: " << overpaymentComponents.trackedManagementFeeDelta + << ", interestPart: " << overpaymentComponents.trackedInterestPart() + << ", untrackedInterest: " << overpaymentComponents.untrackedInterest + << ", totalDue: " << overpaymentComponents.totalDue << ", payments remaining :" << paymentRemaining; + + // Attempt to re-amortize the loan with the overpayment applied. + // This modifies the temporary copies, leaving the proxies unchanged. + auto const ret = tryOverpayment( + asset, + loanScale, + overpaymentComponents, + loanState, + periodicPayment, + periodicRate, + paymentRemaining, + managementFeeRate, + j); + if (!ret) + return Unexpected(ret.error()); + + auto const& [loanPaymentParts, newLoanProperties] = *ret; + auto const newRoundedLoanState = newLoanProperties.loanState; + + // Safety check: the principal must have decreased. If it didn't (or + // increased!), something went wrong in the calculation and we should + // reject the overpayment. + if (principalOutstandingProxy <= newRoundedLoanState.principalOutstanding) + { + // LCOV_EXCL_START + JLOG(j.warn()) << "Overpayment not allowed: principal " + << "outstanding did not decrease. Before: " << *principalOutstandingProxy + << ". After: " << newRoundedLoanState.principalOutstanding; + return Unexpected(tesSUCCESS); + // LCOV_EXCL_STOP + } + + // The proxies still hold the original (pre-overpayment) values, which + // allows us to compute deltas and verify they match what we expect + // from the overpaymentComponents and loanPaymentParts. + + XRPL_ASSERT_PARTS( + overpaymentComponents.trackedPrincipalDelta == + principalOutstandingProxy - newRoundedLoanState.principalOutstanding, + "xrpl::detail::doOverpayment", + "principal change agrees"); + + // I'm not 100% sure the following asserts are correct. If in doubt, and + // everything else works, remove any that cause trouble. + + JLOG(j.debug()) << "valueChange: " << loanPaymentParts.valueChange + << ", totalValue before: " << *totalValueOutstandingProxy + << ", totalValue after: " << newRoundedLoanState.valueOutstanding + << ", totalValue delta: " << (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding) + << ", principalDelta: " << overpaymentComponents.trackedPrincipalDelta + << ", principalPaid: " << loanPaymentParts.principalPaid << ", Computed difference: " + << overpaymentComponents.trackedPrincipalDelta - + (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding); + + XRPL_ASSERT_PARTS( + loanPaymentParts.valueChange == + newRoundedLoanState.valueOutstanding - + (totalValueOutstandingProxy - overpaymentComponents.trackedPrincipalDelta) + + overpaymentComponents.trackedInterestPart(), + "xrpl::detail::doOverpayment", + "interest paid agrees"); + + XRPL_ASSERT_PARTS( + overpaymentComponents.trackedPrincipalDelta == loanPaymentParts.principalPaid, + "xrpl::detail::doOverpayment", + "principal payment matches"); + + // All validations passed, so update the proxy objects (which will + // modify the actual Loan ledger object) + totalValueOutstandingProxy = newRoundedLoanState.valueOutstanding; + principalOutstandingProxy = newRoundedLoanState.principalOutstanding; + managementFeeOutstandingProxy = newRoundedLoanState.managementFeeDue; + periodicPaymentProxy = newLoanProperties.periodicPayment; + + return loanPaymentParts; +} + +/* Computes the payment components for a late payment. + * + * A late payment is made after the grace period has expired and includes: + * 1. All components of a regular periodic payment + * 2. Late payment penalty interest (accrued since the due date) + * 3. Late payment fee charged by the broker + * + * The late penalty interest increases the loan's total value (the borrower + * owes more than scheduled), while the regular payment components follow + * the normal amortization schedule. + * + * Implements equation (15) from XLS-66 spec, Section A-2 Equation Glossary + */ +Expected +computeLatePayment( + Asset const& asset, + ApplyView const& view, + Number const& principalOutstanding, + std::int32_t nextDueDate, + ExtendedPaymentComponents const& periodic, + TenthBips32 lateInterestRate, + std::int32_t loanScale, + Number const& latePaymentFee, + STAmount const& amount, + TenthBips16 managementFeeRate, + beast::Journal j) +{ + // Check if the due date has passed. If not, reject the payment as + // being too soon + if (!hasExpired(view, nextDueDate)) + return Unexpected(tecTOO_SOON); + + // Calculate the penalty interest based on how long the payment is overdue. + auto const latePaymentInterest = + loanLatePaymentInterest(principalOutstanding, lateInterestRate, view.parentCloseTime(), nextDueDate); + + // Round the late interest and split it between the vault (net interest) + // and the broker (management fee portion). This lambda ensures we + // round before splitting to maintain precision. + auto const [roundedLateInterest, roundedLateManagementFee] = [&]() { + auto const interest = roundToAsset(asset, latePaymentInterest, loanScale); + return computeInterestAndFeeParts(asset, interest, managementFeeRate, loanScale); + }(); + + XRPL_ASSERT(roundedLateInterest >= 0, "xrpl::detail::computeLatePayment : valid late interest"); + XRPL_ASSERT_PARTS( + periodic.specialCase != PaymentSpecialCase::extra, + "xrpl::detail::computeLatePayment", + "no extra parts to this payment"); + + // Create the late payment components by copying the regular periodic + // payment and adding the late penalties. We use a lambda to construct + // this to keep the logic clear. This preserves all the other fields without + // having to enumerate them. + + ExtendedPaymentComponents const late{ + periodic, + // Untracked management fee includes: + // 1. Regular service fee (from periodic.untrackedManagementFee) + // 2. Late payment fee (fixed penalty) + // 3. Management fee portion of late interest + periodic.untrackedManagementFee + latePaymentFee + roundedLateManagementFee, + + // Untracked interest includes: + // 1. Any untracked interest from the regular payment (usually 0) + // 2. Late penalty interest (increases loan value) + // This positive value indicates the loan's value increased due + // to the late payment. + periodic.untrackedInterest + roundedLateInterest}; + + XRPL_ASSERT_PARTS( + isRounded(asset, late.totalDue, loanScale), "xrpl::detail::computeLatePayment", "total due is rounded"); + + // Check that the borrower provided enough funds to cover the late payment. + // The late payment is more expensive than a regular payment due to the + // penalties. + if (amount < late.totalDue) + { + JLOG(j.warn()) << "Late loan payment amount is insufficient. Due: " << late.totalDue << ", paid: " << amount; + return Unexpected(tecINSUFFICIENT_PAYMENT); + } + + return late; +} + +/* Computes payment components for paying off a loan early (before final + * payment). + * + * A full payment closes the loan immediately, paying off all outstanding + * balances plus a prepayment penalty and any accrued interest since the last + * payment. This is different from the final scheduled payment, which has no + * prepayment penalty. + * + * The function calculates: + * - Accrued interest since last payment (time-based) + * - Prepayment penalty (percentage of remaining principal) + * - Close payment fee (fixed fee for early closure) + * - All remaining principal and outstanding fees + * + * The loan's value may increase or decrease depending on whether the prepayment + * penalty exceeds the scheduled interest that would have been paid. + * + * Implements equation (26) from XLS-66 spec, Section A-2 Equation Glossary + */ +Expected +computeFullPayment( + Asset const& asset, + ApplyView& view, + Number const& principalOutstanding, + Number const& managementFeeOutstanding, + Number const& periodicPayment, + std::uint32_t paymentRemaining, + std::uint32_t prevPaymentDate, + std::uint32_t const startDate, + std::uint32_t const paymentInterval, + TenthBips32 const closeInterestRate, + std::int32_t loanScale, + Number const& totalInterestOutstanding, + Number const& periodicRate, + Number const& closePaymentFee, + STAmount const& amount, + TenthBips16 managementFeeRate, + beast::Journal j) +{ + // Full payment must be made before the final scheduled payment. + if (paymentRemaining <= 1) + { + // If this is the last payment, it has to be a regular payment + JLOG(j.warn()) << "Last payment cannot be a full payment."; + return Unexpected(tecKILLED); + } + + // Calculate the theoretical principal based on the payment schedule. + // This theoretical (unrounded) value is used to compute interest and + // penalties accurately. + Number const theoreticalPrincipalOutstanding = + loanPrincipalFromPeriodicPayment(periodicPayment, periodicRate, paymentRemaining); + + // Full payment interest includes both accrued interest (time since last + // payment) and prepayment penalty (for closing early). + auto const fullPaymentInterest = computeFullPaymentInterest( + theoreticalPrincipalOutstanding, + periodicRate, + view.parentCloseTime(), + paymentInterval, + prevPaymentDate, + startDate, + closeInterestRate); + + // Split the full payment interest into net interest (to vault) and + // management fee (to broker), applying proper rounding. + auto const [roundedFullInterest, roundedFullManagementFee] = [&]() { + auto const interest = roundToAsset(asset, fullPaymentInterest, loanScale, Number::downward); + return computeInterestAndFeeParts(asset, interest, managementFeeRate, loanScale); + }(); + + ExtendedPaymentComponents const full{ + PaymentComponents{ + // Pay off all tracked outstanding balances: principal, interest, + // and fees. + // This marks the loan as complete (final payment). + .trackedValueDelta = principalOutstanding + totalInterestOutstanding + managementFeeOutstanding, + .trackedPrincipalDelta = principalOutstanding, + + // All outstanding management fees are paid. This zeroes out the + // tracked fee balance. + .trackedManagementFeeDelta = managementFeeOutstanding, + .specialCase = PaymentSpecialCase::final, + }, + + // Untracked management fee includes: + // 1. Close payment fee (fixed fee for early closure) + // 2. Management fee on the full payment interest + // 3. Minus the outstanding tracked fee (already accounted for above) + // This can be negative because the outstanding fee is subtracted, but + // it gets combined with trackedManagementFeeDelta in the final + // accounting. + closePaymentFee + roundedFullManagementFee - managementFeeOutstanding, + + // Value change represents the difference between what the loan was + // expected to earn (totalInterestOutstanding) and what it actually + // earns (roundedFullInterest with prepayment penalty). + // - Positive: Prepayment penalty exceeds scheduled interest (loan value + // increases) + // - Negative: Prepayment penalty is less than scheduled interest (loan + // value decreases) + roundedFullInterest - totalInterestOutstanding, + }; + + XRPL_ASSERT_PARTS( + isRounded(asset, full.totalDue, loanScale), "xrpl::detail::computeFullPayment", "total due is rounded"); + + JLOG(j.trace()) << "computeFullPayment result: periodicPayment: " << periodicPayment + << ", periodicRate: " << periodicRate << ", paymentRemaining: " << paymentRemaining + << ", theoreticalPrincipalOutstanding: " << theoreticalPrincipalOutstanding + << ", fullPaymentInterest: " << fullPaymentInterest + << ", roundedFullInterest: " << roundedFullInterest + << ", roundedFullManagementFee: " << roundedFullManagementFee + << ", untrackedInterest: " << full.untrackedInterest; + + if (amount < full.totalDue) + // If the payment is less than the full payment amount, it's not + // sufficient to be a full payment. + return Unexpected(tecINSUFFICIENT_PAYMENT); + + return full; +} + +Number +PaymentComponents::trackedInterestPart() const +{ + return trackedValueDelta - (trackedPrincipalDelta + trackedManagementFeeDelta); +} + +/* Computes the breakdown of a regular periodic payment into principal, + * interest, and management fee components. + * + * This function determines how a single scheduled payment should be split among + * the three tracked loan components. The calculation accounts for accumulated + * rounding errors. + * + * The algorithm: + * 1. Calculate what the loan state SHOULD be after this payment (target) + * 2. Compare current state to target to get deltas + * 3. Adjust deltas to handle rounding artifacts and edge cases + * 4. Ensure deltas don't exceed available balances or payment amount + * + * Special handling for the final payment: all remaining balances are paid off + * regardless of the periodic payment amount. + * + * Implements the pseudo-code function `compute_payment_due()`. + */ +PaymentComponents +computePaymentComponents( + Asset const& asset, + std::int32_t scale, + Number const& totalValueOutstanding, + Number const& principalOutstanding, + Number const& managementFeeOutstanding, + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t paymentRemaining, + TenthBips16 managementFeeRate) +{ + XRPL_ASSERT_PARTS( + isRounded(asset, totalValueOutstanding, scale) && isRounded(asset, principalOutstanding, scale) && + isRounded(asset, managementFeeOutstanding, scale), + "xrpl::detail::computePaymentComponents", + "Outstanding values are rounded"); + XRPL_ASSERT_PARTS(paymentRemaining > 0, "xrpl::detail::computePaymentComponents", "some payments remaining"); + + auto const roundedPeriodicPayment = roundPeriodicPayment(asset, periodicPayment, scale); + + // Final payment: pay off everything remaining, ignoring the normal + // periodic payment amount. This ensures the loan completes cleanly. + if (paymentRemaining == 1 || totalValueOutstanding <= roundedPeriodicPayment) + { + // If there's only one payment left, we need to pay off each of the loan + // parts. + return PaymentComponents{ + .trackedValueDelta = totalValueOutstanding, + .trackedPrincipalDelta = principalOutstanding, + .trackedManagementFeeDelta = managementFeeOutstanding, + .specialCase = PaymentSpecialCase::final}; + } + + // Calculate what the loan state SHOULD be after this payment (the target). + // This is computed at full precision using the theoretical amortization. + LoanState const trueTarget = + computeTheoreticalLoanState(periodicPayment, periodicRate, paymentRemaining - 1, managementFeeRate); + + // Round the target to the loan's scale to match how actual loan values + // are stored. + LoanState const roundedTarget = LoanState{ + .valueOutstanding = roundToAsset(asset, trueTarget.valueOutstanding, scale), + .principalOutstanding = roundToAsset(asset, trueTarget.principalOutstanding, scale), + .interestDue = roundToAsset(asset, trueTarget.interestDue, scale), + .managementFeeDue = roundToAsset(asset, trueTarget.managementFeeDue, scale)}; + + // Get the current actual loan state from the ledger values + LoanState const currentLedgerState = + constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding); + + // The difference between current and target states gives us the payment + // components. Any discrepancies from accumulated rounding are captured + // here. + + LoanStateDeltas deltas = currentLedgerState - roundedTarget; + + // Rounding can occasionally produce negative deltas. Zero them out. + deltas.nonNegative(); + + XRPL_ASSERT_PARTS( + deltas.principal <= currentLedgerState.principalOutstanding, + "xrpl::detail::computePaymentComponents", + "principal delta not greater than outstanding"); + + // Cap each component to never exceed what's actually outstanding + deltas.principal = std::min(deltas.principal, currentLedgerState.principalOutstanding); + + XRPL_ASSERT_PARTS( + deltas.interest <= currentLedgerState.interestDue, + "xrpl::detail::computePaymentComponents", + "interest due delta not greater than outstanding"); + + // Cap interest to both the outstanding amount AND what's left of the + // periodic payment after principal is paid + deltas.interest = std::min( + {deltas.interest, + std::max(numZero, roundedPeriodicPayment - deltas.principal), + currentLedgerState.interestDue}); + + XRPL_ASSERT_PARTS( + deltas.managementFee <= currentLedgerState.managementFeeDue, + "xrpl::detail::computePaymentComponents", + "management fee due delta not greater than outstanding"); + + // Cap management fee to both the outstanding amount AND what's left of the + // periodic payment after principal and interest are paid + deltas.managementFee = std::min( + {deltas.managementFee, + roundedPeriodicPayment - (deltas.principal + deltas.interest), + currentLedgerState.managementFeeDue}); + + // The shortage must never be negative, which indicates that the parts are + // trying to take more than the whole payment. The excess can be positive, + // which indicates that we're not going to take the whole payment amount, + // but if so, it must be small. + auto takeFrom = [](Number& component, Number& excess) { + if (excess > beast::zero) + { + auto part = std::min(component, excess); + component -= part; + excess -= part; + } + XRPL_ASSERT_PARTS(excess >= beast::zero, "xrpl::detail::computePaymentComponents", "excess non-negative"); + }; + // Helper to reduce deltas when they collectively exceed a limit. + // Order matters: we prefer to reduce interest first (most flexible), + // then management fee, then principal (least flexible). + auto addressExcess = [&takeFrom](LoanStateDeltas& deltas, Number& excess) { + // This order is based on where errors are the least problematic + takeFrom(deltas.interest, excess); + takeFrom(deltas.managementFee, excess); + takeFrom(deltas.principal, excess); + }; + + // Check if deltas exceed the total outstanding value. This should never + // happen due to earlier caps, but handle it defensively. + Number totalOverpayment = deltas.total() - currentLedgerState.valueOutstanding; + + if (totalOverpayment > beast::zero) + { + // LCOV_EXCL_START + UNREACHABLE( + "xrpl::detail::computePaymentComponents : payment exceeded loan " + "state"); + addressExcess(deltas, totalOverpayment); + // LCOV_EXCL_STOP + } + + // Check if deltas exceed the periodic payment amount. Reduce if needed. + Number shortage = roundedPeriodicPayment - deltas.total(); + + XRPL_ASSERT_PARTS( + isRounded(asset, shortage, scale), "xrpl::detail::computePaymentComponents", "shortage is rounded"); + + if (shortage < beast::zero) + { + // Deltas exceed payment amount - reduce them proportionally + Number excess = -shortage; + addressExcess(deltas, excess); + shortage = -excess; + } + + // At this point, shortage >= 0 means we're paying less than the full + // periodic payment (due to rounding or component caps). + // shortage < 0 would mean we're trying to pay more than allowed (bug). + XRPL_ASSERT_PARTS(shortage >= beast::zero, "xrpl::detail::computePaymentComponents", "no shortage or excess"); + + // Final validation that all components are valid + XRPL_ASSERT_PARTS( + deltas.total() == deltas.principal + deltas.interest + deltas.managementFee, + "xrpl::detail::computePaymentComponents", + "total value adds up"); + + XRPL_ASSERT_PARTS( + deltas.principal >= beast::zero && deltas.principal <= currentLedgerState.principalOutstanding, + "xrpl::detail::computePaymentComponents", + "valid principal result"); + XRPL_ASSERT_PARTS( + deltas.interest >= beast::zero && deltas.interest <= currentLedgerState.interestDue, + "xrpl::detail::computePaymentComponents", + "valid interest result"); + XRPL_ASSERT_PARTS( + deltas.managementFee >= beast::zero && deltas.managementFee <= currentLedgerState.managementFeeDue, + "xrpl::detail::computePaymentComponents", + "valid fee result"); + + XRPL_ASSERT_PARTS( + deltas.principal + deltas.interest + deltas.managementFee > beast::zero, + "xrpl::detail::computePaymentComponents", + "payment parts add to payment"); + + // Final safety clamp to ensure no value exceeds its outstanding balance + return PaymentComponents{ + .trackedValueDelta = std::clamp(deltas.total(), numZero, currentLedgerState.valueOutstanding), + .trackedPrincipalDelta = std::clamp(deltas.principal, numZero, currentLedgerState.principalOutstanding), + .trackedManagementFeeDelta = std::clamp(deltas.managementFee, numZero, currentLedgerState.managementFeeDue), + }; +} + +/* Computes payment components for an overpayment scenario. + * + * An overpayment occurs when a borrower pays more than the scheduled periodic + * payment amount. The overpayment is treated as extra principal reduction, + * but incurs a fee and potentially a penalty interest charge. + * + * The calculation (Section 3.2.4.2.3 from XLS-66 spec): + * 1. Calculate gross penalty interest on the overpayment amount + * 2. Split the gross interest into net interest and management fee + * 3. Calculate the penalty fee + * 4. Determine the principal portion by subtracting the interest (gross) and + * management fee from the overpayment amount + * + * Unlike regular payments which follow the amortization schedule, overpayments + * apply to principal, reducing the loan balance and future interest costs. + * + * Equations (20), (21) and (22) from XLS-66 spec, Section A-2 Equation Glossary + */ +ExtendedPaymentComponents +computeOverpaymentComponents( + Asset const& asset, + int32_t const loanScale, + Number const& overpayment, + TenthBips32 const overpaymentInterestRate, + TenthBips32 const overpaymentFeeRate, + TenthBips16 const managementFeeRate) +{ + XRPL_ASSERT( + overpayment > 0 && isRounded(asset, overpayment, loanScale), + "xrpl::detail::computeOverpaymentComponents : valid overpayment " + "amount"); + + // First, deduct the fixed overpayment fee from the total amount. + // This reduces the effective payment that will be applied to the loan. + // Equation (22) from XLS-66 spec, Section A-2 Equation Glossary + Number const overpaymentFee = roundToAsset(asset, tenthBipsOfValue(overpayment, overpaymentFeeRate), loanScale); + + // Calculate the penalty interest on the effective payment amount. + // This interest doesn't follow the normal amortization schedule - it's + // a one-time charge for paying early. + // Equation (20) and (21) from XLS-66 spec, Section A-2 Equation Glossary + auto const [roundedOverpaymentInterest, roundedOverpaymentManagementFee] = [&]() { + auto const interest = roundToAsset(asset, tenthBipsOfValue(overpayment, overpaymentInterestRate), loanScale); + return detail::computeInterestAndFeeParts(asset, interest, managementFeeRate, loanScale); + }(); + + auto const result = detail::ExtendedPaymentComponents{ + // Build the payment components, after fees and penalty + // interest are deducted, the remainder goes entirely to principal + // reduction. + detail::PaymentComponents{ + .trackedValueDelta = overpayment - overpaymentFee, + .trackedPrincipalDelta = + overpayment - roundedOverpaymentInterest - roundedOverpaymentManagementFee - overpaymentFee, + .trackedManagementFeeDelta = roundedOverpaymentManagementFee, + .specialCase = detail::PaymentSpecialCase::extra}, + // Untracked management fee is the fixed overpayment fee + overpaymentFee, + // Untracked interest is the penalty interest charged for overpaying. + // This is positive, representing a one-time cost, but it's typically + // much smaller than the interest savings from reducing principal. + // It is equal to the paymentComponents.trackedInterestPart() + // but is kept separate for clarity. + roundedOverpaymentInterest}; + XRPL_ASSERT_PARTS( + result.trackedInterestPart() == roundedOverpaymentInterest, + "xrpl::detail::computeOverpaymentComponents", + "valid interest computation"); + return result; +} + +} // namespace detail + +detail::LoanStateDeltas +operator-(LoanState const& lhs, LoanState const& rhs) +{ + detail::LoanStateDeltas result{ + .principal = lhs.principalOutstanding - rhs.principalOutstanding, + .interest = lhs.interestDue - rhs.interestDue, + .managementFee = lhs.managementFeeDue - rhs.managementFeeDue, + }; + + return result; +} + +LoanState +operator-(LoanState const& lhs, detail::LoanStateDeltas const& rhs) +{ + LoanState result{ + .valueOutstanding = lhs.valueOutstanding - rhs.total(), + .principalOutstanding = lhs.principalOutstanding - rhs.principal, + .interestDue = lhs.interestDue - rhs.interest, + .managementFeeDue = lhs.managementFeeDue - rhs.managementFee, + }; + + return result; +} + +LoanState +operator+(LoanState const& lhs, detail::LoanStateDeltas const& rhs) +{ + LoanState result{ + .valueOutstanding = lhs.valueOutstanding + rhs.total(), + .principalOutstanding = lhs.principalOutstanding + rhs.principal, + .interestDue = lhs.interestDue + rhs.interest, + .managementFeeDue = lhs.managementFeeDue + rhs.managementFee, + }; + + return result; +} + +TER +checkLoanGuards( + Asset const& vaultAsset, + Number const& principalRequested, + bool expectInterest, + std::uint32_t paymentTotal, + LoanProperties const& properties, + beast::Journal j) +{ + auto const totalInterestOutstanding = properties.loanState.valueOutstanding - principalRequested; + // Guard 1: if there is no computed total interest over the life of the + // loan for a non-zero interest rate, we cannot properly amortize the + // loan + if (expectInterest && totalInterestOutstanding <= 0) + { + // Unless this is a zero-interest loan, there must be some interest + // due on the loan, even if it's (measurable) dust + JLOG(j.warn()) << "Loan for " << principalRequested << " with interest has no interest due"; + return tecPRECISION_LOSS; + } + // Guard 1a: If there is any interest computed over the life of the + // loan, for a zero interest rate, something went sideways. + if (!expectInterest && totalInterestOutstanding > 0) + { + // LCOV_EXCL_START + JLOG(j.warn()) << "Loan for " << principalRequested << " with no interest has interest due"; + return tecINTERNAL; + // LCOV_EXCL_STOP + } + + // Guard 2: if the principal portion of the first periodic payment is + // too small to be accurately represented with the given rounding mode, + // raise an error + if (properties.firstPaymentPrincipal <= 0) + { + // Check that some true (unrounded) principal is paid each period. + // Since the first payment pays the least principal, if it's good, + // they'll all be good. Note that the outstanding principal is + // rounded, and may not change right away. + JLOG(j.warn()) << "Loan is unable to pay principal."; + return tecPRECISION_LOSS; + } + + // Guard 3: If the periodic payment is so small that it can't even be + // rounded to a representable value, then the loan can't be paid. Also, + // avoids dividing by 0. + auto const roundedPayment = roundPeriodicPayment(vaultAsset, properties.periodicPayment, properties.loanScale); + if (roundedPayment == beast::zero) + { + JLOG(j.warn()) << "Loan Periodic payment (" << properties.periodicPayment << ") rounds to 0. "; + return tecPRECISION_LOSS; + } + + // Guard 4: if the rounded periodic payment is large enough that the + // loan can't be amortized in the specified number of payments, raise an + // error + { + NumberRoundModeGuard mg(Number::upward); + + if (std::int64_t const computedPayments{properties.loanState.valueOutstanding / roundedPayment}; + computedPayments != paymentTotal) + { + JLOG(j.warn()) << "Loan Periodic payment (" << properties.periodicPayment << ") rounding (" + << roundedPayment << ") on a total value of " << properties.loanState.valueOutstanding + << " can not complete the loan in the specified " + "number of payments (" + << computedPayments << " != " << paymentTotal << ")"; + return tecPRECISION_LOSS; + } + } + return tesSUCCESS; +} + +/* + * This function calculates the full payment interest accrued since the last + * payment, plus any prepayment penalty. + * + * Equations (27) and (28) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +computeFullPaymentInterest( + Number const& theoreticalPrincipalOutstanding, + Number const& periodicRate, + NetClock::time_point parentCloseTime, + std::uint32_t paymentInterval, + std::uint32_t prevPaymentDate, + std::uint32_t startDate, + TenthBips32 closeInterestRate) +{ + auto const accruedInterest = detail::loanAccruedInterest( + theoreticalPrincipalOutstanding, periodicRate, parentCloseTime, startDate, prevPaymentDate, paymentInterval); + XRPL_ASSERT( + accruedInterest >= 0, + "xrpl::detail::computeFullPaymentInterest : valid accrued " + "interest"); + + // Equation (28) from XLS-66 spec, Section A-2 Equation Glossary + auto const prepaymentPenalty = closeInterestRate == beast::zero + ? Number{} + : tenthBipsOfValue(theoreticalPrincipalOutstanding, closeInterestRate); + + XRPL_ASSERT( + prepaymentPenalty >= 0, + "xrpl::detail::computeFullPaymentInterest : valid prepayment " + "interest"); + + // Part of equation (27) from XLS-66 spec, Section A-2 Equation Glossary + return accruedInterest + prepaymentPenalty; +} + +/* Calculates the theoretical loan state at maximum precision for a given point + * in the amortization schedule. + * + * This function computes what the loan's outstanding balances should be based + * on the periodic payment amount and number of payments remaining, + * without considering any rounding that may have been applied to the actual + * Loan object's state. This "theoretical" (unrounded) state is used as a target + * for computing payment components and validating that the loan's tracked state + * hasn't drifted too far from the theoretical values. + * + * The theoretical state serves several purposes: + * 1. Computing the expected payment breakdown (principal, interest, fees) + * 2. Detecting and correcting rounding errors that accumulate over time + * 3. Validating that overpayments are calculated correctly + * 4. Ensuring the loan will be fully paid off at the end of its term + * + * If paymentRemaining is 0, returns a fully zeroed-out LoanState, + * representing a completely paid-off loan. + * + * Implements the `calculate_true_loan_state` function from the XLS-66 spec + * section 3.2.4.4 Transaction Pseudo-code + */ +LoanState +computeTheoreticalLoanState( + Number const& periodicPayment, + Number const& periodicRate, + std::uint32_t const paymentRemaining, + TenthBips32 const managementFeeRate) +{ + if (paymentRemaining == 0) + { + return LoanState{.valueOutstanding = 0, .principalOutstanding = 0, .interestDue = 0, .managementFeeDue = 0}; + } + + // Equation (30) from XLS-66 spec, Section A-2 Equation Glossary + Number const totalValueOutstanding = periodicPayment * paymentRemaining; + + Number const principalOutstanding = + detail::loanPrincipalFromPeriodicPayment(periodicPayment, periodicRate, paymentRemaining); + + // Equation (31) from XLS-66 spec, Section A-2 Equation Glossary + Number const interestOutstandingGross = totalValueOutstanding - principalOutstanding; + + // Equation (32) from XLS-66 spec, Section A-2 Equation Glossary + Number const managementFeeOutstanding = tenthBipsOfValue(interestOutstandingGross, managementFeeRate); + + // Equation (33) from XLS-66 spec, Section A-2 Equation Glossary + Number const interestOutstandingNet = interestOutstandingGross - managementFeeOutstanding; + + return LoanState{ + .valueOutstanding = totalValueOutstanding, + .principalOutstanding = principalOutstanding, + .interestDue = interestOutstandingNet, + .managementFeeDue = managementFeeOutstanding, + }; +}; + +/* Constructs a LoanState from rounded Loan ledger object values. + * + * This function creates a LoanState structure from the three tracked values + * stored in a Loan ledger object. Unlike calculateTheoreticalLoanState(), which + * computes theoretical unrounded values, this function works with values + * that have already been rounded to the loan's scale. + * + * The key difference from calculateTheoreticalLoanState(): + * - calculateTheoreticalLoanState: Computes theoretical values at full + * precision + * - constructRoundedLoanState: Builds state from actual rounded ledger values + * + * The interestDue field is derived from the other three values rather than + * stored directly, since it can be calculated as: + * interestDue = totalValueOutstanding - principalOutstanding - + * managementFeeOutstanding + * + * This ensures consistency across the codebase and prevents copy-paste errors + * when creating LoanState objects from Loan ledger data. + */ +LoanState +constructLoanState( + Number const& totalValueOutstanding, + Number const& principalOutstanding, + Number const& managementFeeOutstanding) +{ + // This implementation is pretty trivial, but ensures the calculations + // are consistent everywhere, and reduces copy/paste errors. + return LoanState{ + .valueOutstanding = totalValueOutstanding, + .principalOutstanding = principalOutstanding, + .interestDue = totalValueOutstanding - principalOutstanding - managementFeeOutstanding, + .managementFeeDue = managementFeeOutstanding}; +} + +LoanState +constructRoundedLoanState(SLE::const_ref loan) +{ + return constructLoanState( + loan->at(sfTotalValueOutstanding), loan->at(sfPrincipalOutstanding), loan->at(sfManagementFeeOutstanding)); +} + +/* + * This function calculates the fee owed to the broker based on the asset, + * value, and management fee rate. + * + * Equation (32) from XLS-66 spec, Section A-2 Equation Glossary + */ +Number +computeManagementFee(Asset const& asset, Number const& value, TenthBips32 managementFeeRate, std::int32_t scale) +{ + return roundToAsset(asset, tenthBipsOfValue(value, managementFeeRate), scale, Number::downward); +} + +/* + * Given the loan parameters, compute the derived properties of the loan. + * + * Pulls together several formulas from the XLS-66 spec, which are noted at each + * step, plus the concepts from 3.2.4.3 Conceptual Loan Value. They are used for + * to check some of the conditions in 3.2.1.5 Failure Conditions for the LoanSet + * transaction. + */ +LoanProperties +computeLoanProperties( + Asset const& asset, + Number const& principalOutstanding, + TenthBips32 interestRate, + std::uint32_t paymentInterval, + std::uint32_t paymentsRemaining, + TenthBips32 managementFeeRate, + std::int32_t minimumScale) +{ + auto const periodicRate = loanPeriodicRate(interestRate, paymentInterval); + XRPL_ASSERT(interestRate == 0 || periodicRate > 0, "xrpl::computeLoanProperties : valid rate"); + return computeLoanProperties( + asset, principalOutstanding, periodicRate, paymentsRemaining, managementFeeRate, minimumScale); +} + +/* + * Given the loan parameters, compute the derived properties of the loan. + * + * Pulls together several formulas from the XLS-66 spec, which are noted at each + * step, plus the concepts from 3.2.4.3 Conceptual Loan Value. They are used for + * to check some of the conditions in 3.2.1.5 Failure Conditions for the LoanSet + * transaction. + */ +LoanProperties +computeLoanProperties( + Asset const& asset, + Number const& principalOutstanding, + Number const& periodicRate, + std::uint32_t paymentsRemaining, + TenthBips32 managementFeeRate, + std::int32_t minimumScale) +{ + auto const periodicPayment = detail::loanPeriodicPayment(principalOutstanding, periodicRate, paymentsRemaining); + + auto const [totalValueOutstanding, loanScale] = [&]() { + // only round up if there should be interest + NumberRoundModeGuard mg(periodicRate == 0 ? Number::to_nearest : Number::upward); + // Use STAmount's internal rounding instead of roundToAsset, because + // we're going to use this result to determine the scale for all the + // other rounding. + + // Equation (30) from XLS-66 spec, Section A-2 Equation Glossary + STAmount amount{asset, periodicPayment * paymentsRemaining}; + + // Base the loan scale on the total value, since that's going to be + // the biggest number involved (barring unusual parameters for late, + // full, or over payments) + auto const loanScale = std::max(minimumScale, amount.exponent()); + XRPL_ASSERT_PARTS( + (amount.integral() && loanScale == 0) || + (!amount.integral() && loanScale >= static_cast(amount).exponent()), + "xrpl::computeLoanProperties", + "loanScale value fits expectations"); + + // We may need to truncate the total value because of the minimum + // scale + amount = roundToAsset(asset, amount, loanScale); + + return std::make_pair(amount, loanScale); + }(); + + // Since we just figured out the loan scale, we haven't been able to + // validate that the principal fits in it, so to allow this function to + // succeed, round it here, and let the caller do the validation. + auto const roundedPrincipalOutstanding = roundToAsset(asset, principalOutstanding, loanScale, Number::to_nearest); + + // Equation (31) from XLS-66 spec, Section A-2 Equation Glossary + auto const totalInterestOutstanding = totalValueOutstanding - roundedPrincipalOutstanding; + auto const feeOwedToBroker = computeManagementFee(asset, totalInterestOutstanding, managementFeeRate, loanScale); + + // Compute the principal part of the first payment. This is needed + // because the principal part may be rounded down to zero, which + // would prevent the principal from ever being paid down. + auto const firstPaymentPrincipal = [&]() { + // Compute the parts for the first payment. Ensure that the + // principal payment will actually change the principal. + auto const startingState = + computeTheoreticalLoanState(periodicPayment, periodicRate, paymentsRemaining, managementFeeRate); + + auto const firstPaymentState = + computeTheoreticalLoanState(periodicPayment, periodicRate, paymentsRemaining - 1, managementFeeRate); + + // The unrounded principal part needs to be large enough to affect + // the principal. What to do if not is left to the caller + return startingState.principalOutstanding - firstPaymentState.principalOutstanding; + }(); + + return LoanProperties{ + .periodicPayment = periodicPayment, + .loanState = constructLoanState(totalValueOutstanding, roundedPrincipalOutstanding, feeOwedToBroker), + .loanScale = loanScale, + .firstPaymentPrincipal = firstPaymentPrincipal, + }; +} + +/* + * This is the main function to make a loan payment. + * This function handles regular, late, full, and overpayments. + * It is an implementation of the make_payment function from the XLS-66 + * spec. Section 3.2.4.4 + */ +Expected +loanMakePayment( + Asset const& asset, + ApplyView& view, + SLE::ref loan, + SLE::const_ref brokerSle, + STAmount const& amount, + LoanPaymentType const paymentType, + beast::Journal j) +{ + using namespace Lending; + + auto principalOutstandingProxy = loan->at(sfPrincipalOutstanding); + auto paymentRemainingProxy = loan->at(sfPaymentRemaining); + + if (paymentRemainingProxy == 0 || principalOutstandingProxy == 0) + { + // Loan complete this is already checked in LoanPay::preclaim() + // LCOV_EXCL_START + JLOG(j.warn()) << "Loan is already paid off."; + return Unexpected(tecKILLED); + // LCOV_EXCL_STOP + } + + auto totalValueOutstandingProxy = loan->at(sfTotalValueOutstanding); + auto managementFeeOutstandingProxy = loan->at(sfManagementFeeOutstanding); + + // Next payment due date must be set unless the loan is complete + auto nextDueDateProxy = loan->at(sfNextPaymentDueDate); + if (*nextDueDateProxy == 0) + { + JLOG(j.warn()) << "Loan next payment due date is not set."; + return Unexpected(tecINTERNAL); + } + + std::int32_t const loanScale = loan->at(sfLoanScale); + + TenthBips32 const interestRate{loan->at(sfInterestRate)}; + + Number const serviceFee = loan->at(sfLoanServiceFee); + TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)}; + + Number const periodicPayment = loan->at(sfPeriodicPayment); + + auto prevPaymentDateProxy = loan->at(sfPreviousPaymentDueDate); + std::uint32_t const startDate = loan->at(sfStartDate); + + std::uint32_t const paymentInterval = loan->at(sfPaymentInterval); + + // Compute the periodic rate that will be used for calculations + // throughout + Number const periodicRate = loanPeriodicRate(interestRate, paymentInterval); + XRPL_ASSERT(interestRate == 0 || periodicRate > 0, "xrpl::loanMakePayment : valid rate"); + + XRPL_ASSERT(*totalValueOutstandingProxy > 0, "xrpl::loanMakePayment : valid total value"); + + view.update(loan); + + // ------------------------------------------------------------- + // A late payment not flagged as late overrides all other options. + if (paymentType != LoanPaymentType::late && hasExpired(view, nextDueDateProxy)) + { + // If the payment is late, and the late flag was not set, it's not + // valid + JLOG(j.warn()) << "Loan payment is overdue. Use the tfLoanLatePayment " + "transaction " + "flag to make a late payment. Loan was created on " + << startDate << ", prev payment due date is " << prevPaymentDateProxy + << ", next payment due date is " << nextDueDateProxy << ", ledger time is " + << view.parentCloseTime().time_since_epoch().count(); + return Unexpected(tecEXPIRED); + } + + // ------------------------------------------------------------- + // full payment handling + if (paymentType == LoanPaymentType::full) + { + TenthBips32 const closeInterestRate{loan->at(sfCloseInterestRate)}; + Number const closePaymentFee = roundToAsset(asset, loan->at(sfClosePaymentFee), loanScale); + + LoanState const roundedLoanState = + constructLoanState(totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy); + + if (auto const fullPaymentComponents = detail::computeFullPayment( + asset, + view, + principalOutstandingProxy, + managementFeeOutstandingProxy, + periodicPayment, + paymentRemainingProxy, + prevPaymentDateProxy, + startDate, + paymentInterval, + closeInterestRate, + loanScale, + roundedLoanState.interestDue, + periodicRate, + closePaymentFee, + amount, + managementFeeRate, + j)) + { + return doPayment( + *fullPaymentComponents, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + paymentRemainingProxy, + prevPaymentDateProxy, + nextDueDateProxy, + paymentInterval); + } + else if (fullPaymentComponents.error()) + // error() will be the TER returned if a payment is not made. It + // will only evaluate to true if it's unsuccessful. Otherwise, + // tesSUCCESS means nothing was done, so continue. + return Unexpected(fullPaymentComponents.error()); + + // LCOV_EXCL_START + UNREACHABLE("xrpl::loanMakePayment : invalid full payment result"); + JLOG(j.error()) << "Full payment computation failed unexpectedly."; + return Unexpected(tecINTERNAL); + // LCOV_EXCL_STOP + } + + // ------------------------------------------------------------- + // compute the periodic payment info that will be needed whether the + // payment is late or regular + detail::ExtendedPaymentComponents periodic{ + detail::computePaymentComponents( + asset, + loanScale, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + periodicPayment, + periodicRate, + paymentRemainingProxy, + managementFeeRate), + serviceFee}; + XRPL_ASSERT_PARTS(periodic.trackedPrincipalDelta >= 0, "xrpl::loanMakePayment", "regular payment valid principal"); + + // ------------------------------------------------------------- + // late payment handling + if (paymentType == LoanPaymentType::late) + { + TenthBips32 const lateInterestRate{loan->at(sfLateInterestRate)}; + Number const latePaymentFee = loan->at(sfLatePaymentFee); + + if (auto const latePaymentComponents = detail::computeLatePayment( + asset, + view, + principalOutstandingProxy, + nextDueDateProxy, + periodic, + lateInterestRate, + loanScale, + latePaymentFee, + amount, + managementFeeRate, + j)) + { + return doPayment( + *latePaymentComponents, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + paymentRemainingProxy, + prevPaymentDateProxy, + nextDueDateProxy, + paymentInterval); + } + else if (latePaymentComponents.error()) + { + // error() will be the TER returned if a payment is not made. It + // will only evaluate to true if it's unsuccessful. + return Unexpected(latePaymentComponents.error()); + } + + // LCOV_EXCL_START + UNREACHABLE("xrpl::loanMakePayment : invalid late payment result"); + JLOG(j.error()) << "Late payment computation failed unexpectedly."; + return Unexpected(tecINTERNAL); + // LCOV_EXCL_STOP + } + + // ------------------------------------------------------------- + // regular periodic payment handling + + XRPL_ASSERT_PARTS( + paymentType == LoanPaymentType::regular || paymentType == LoanPaymentType::overpayment, + "xrpl::loanMakePayment", + "regular payment type"); + + // Keep a running total of the actual parts paid + LoanPaymentParts totalParts; + Number totalPaid; + std::size_t numPayments = 0; + + while ((amount >= (totalPaid + periodic.totalDue)) && paymentRemainingProxy > 0 && + numPayments < loanMaximumPaymentsPerTransaction) + { + // Try to make more payments + XRPL_ASSERT_PARTS( + periodic.trackedPrincipalDelta >= 0, "xrpl::loanMakePayment", "payment pays non-negative principal"); + + totalPaid += periodic.totalDue; + totalParts += detail::doPayment( + periodic, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + paymentRemainingProxy, + prevPaymentDateProxy, + nextDueDateProxy, + paymentInterval); + ++numPayments; + + XRPL_ASSERT_PARTS( + (periodic.specialCase == detail::PaymentSpecialCase::final) == (paymentRemainingProxy == 0), + "xrpl::loanMakePayment", + "final payment is the final payment"); + + // Don't compute the next payment if this was the last payment + if (periodic.specialCase == detail::PaymentSpecialCase::final) + break; + + periodic = detail::ExtendedPaymentComponents{ + detail::computePaymentComponents( + asset, + loanScale, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + periodicPayment, + periodicRate, + paymentRemainingProxy, + managementFeeRate), + serviceFee}; + } + + if (numPayments == 0) + { + JLOG(j.warn()) << "Regular loan payment amount is insufficient. Due: " << periodic.totalDue + << ", paid: " << amount; + return Unexpected(tecINSUFFICIENT_PAYMENT); + } + + XRPL_ASSERT_PARTS( + totalParts.principalPaid + totalParts.interestPaid + totalParts.feePaid == totalPaid, + "xrpl::loanMakePayment", + "payment parts add up"); + XRPL_ASSERT_PARTS(totalParts.valueChange == 0, "xrpl::loanMakePayment", "no value change"); + + // ------------------------------------------------------------- + // overpayment handling + if (paymentType == LoanPaymentType::overpayment && loan->isFlag(lsfLoanOverpayment) && paymentRemainingProxy > 0 && + totalPaid < amount && numPayments < loanMaximumPaymentsPerTransaction) + { + TenthBips32 const overpaymentInterestRate{loan->at(sfOverpaymentInterestRate)}; + TenthBips32 const overpaymentFeeRate{loan->at(sfOverpaymentFee)}; + + // It shouldn't be possible for the overpayment to be greater than + // totalValueOutstanding, because that would have been processed as + // another normal payment. But cap it just in case. + Number const overpayment = std::min(amount - totalPaid, *totalValueOutstandingProxy); + + detail::ExtendedPaymentComponents const overpaymentComponents = detail::computeOverpaymentComponents( + asset, loanScale, overpayment, overpaymentInterestRate, overpaymentFeeRate, managementFeeRate); + + // Don't process an overpayment if the whole amount (or more!) + // gets eaten by fees and interest. + if (overpaymentComponents.trackedPrincipalDelta > 0) + { + XRPL_ASSERT_PARTS( + overpaymentComponents.untrackedInterest >= beast::zero, + "xrpl::loanMakePayment", + "overpayment penalty did not reduce value of loan"); + // Can't just use `periodicPayment` here, because it might + // change + auto periodicPaymentProxy = loan->at(sfPeriodicPayment); + if (auto const overResult = detail::doOverpayment( + asset, + loanScale, + overpaymentComponents, + totalValueOutstandingProxy, + principalOutstandingProxy, + managementFeeOutstandingProxy, + periodicPaymentProxy, + periodicRate, + paymentRemainingProxy, + managementFeeRate, + j)) + totalParts += *overResult; + else if (overResult.error()) + // error() will be the TER returned if a payment is not + // made. It will only evaluate to true if it's unsuccessful. + // Otherwise, tesSUCCESS means nothing was done, so + // continue. + return Unexpected(overResult.error()); + } + } + + // Check the final results are rounded, to double-check that the + // intermediate steps were rounded. + XRPL_ASSERT( + isRounded(asset, totalParts.principalPaid, loanScale) && totalParts.principalPaid >= beast::zero, + "xrpl::loanMakePayment : total principal paid is valid"); + XRPL_ASSERT( + isRounded(asset, totalParts.interestPaid, loanScale) && totalParts.interestPaid >= beast::zero, + "xrpl::loanMakePayment : total interest paid is valid"); + XRPL_ASSERT( + isRounded(asset, totalParts.valueChange, loanScale), "xrpl::loanMakePayment : loan value change is valid"); + XRPL_ASSERT( + isRounded(asset, totalParts.feePaid, loanScale) && totalParts.feePaid >= beast::zero, + "xrpl::loanMakePayment : fee paid is valid"); + return totalParts; +} +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp index 4728df9272..91a40c6a9d 100644 --- a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp +++ b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include @@ -26,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { bool LoadFeeTrack::raiseLocalFee() @@ -51,8 +32,7 @@ LoadFeeTrack::raiseLocalFee() if (origFee == localTxnLoadFee_) return false; - JLOG(j_.debug()) << "Local load fee raised from " << origFee << " to " - << localTxnLoadFee_; + JLOG(j_.debug()) << "Local load fee raised from " << origFee << " to " << localTxnLoadFee_; return true; } @@ -72,8 +52,7 @@ LoadFeeTrack::lowerLocalFee() if (origFee == localTxnLoadFee_) return false; - JLOG(j_.debug()) << "Local load fee lowered from " << origFee << " to " - << localTxnLoadFee_; + JLOG(j_.debug()) << "Local load fee lowered from " << origFee << " to " << localTxnLoadFee_; return true; } @@ -81,11 +60,7 @@ LoadFeeTrack::lowerLocalFee() // Scale using load as well as base rate XRPAmount -scaleFeeLoad( - XRPAmount fee, - LoadFeeTrack const& feeTrack, - Fees const& fees, - bool bUnlimited) +scaleFeeLoad(XRPAmount fee, LoadFeeTrack const& feeTrack, Fees const& fees, bool bUnlimited) { if (fee == 0) return fee; @@ -102,11 +77,10 @@ scaleFeeLoad( // fee = fee * feeFactor / (lftNormalFee); // without overflow, and as accurately as possible - auto const result = mulDiv( - fee, feeFactor, safe_cast(feeTrack.getLoadBase())); + auto const result = mulDiv(fee, feeFactor, safe_cast(feeTrack.getLoadBase())); if (!result) Throw("scaleFeeLoad"); return *result; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/Manifest.cpp b/src/xrpld/app/misc/detail/Manifest.cpp index c42256495e..dfcbdbb3ad 100644 --- a/src/xrpld/app/misc/detail/Manifest.cpp +++ b/src/xrpld/app/misc/detail/Manifest.cpp @@ -1,39 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include - #include #include #include #include #include #include +#include +#include +#include #include #include #include -namespace ripple { +namespace xrpl { std::string to_string(Manifest const& m) @@ -149,45 +129,31 @@ deserializeManifest(Slice s, beast::Journal journal) return std::nullopt; } - std::string const serialized( - reinterpret_cast(s.data()), s.size()); + std::string const serialized(reinterpret_cast(s.data()), s.size()); // If the manifest is revoked, then the signingKey will be unseated return Manifest(serialized, masterKey, signingKey, seq, domain); } catch (std::exception const& ex) { - JLOG(journal.error()) - << "Exception in " << __func__ << ": " << ex.what(); + JLOG(journal.error()) << "Exception in " << __func__ << ": " << ex.what(); return std::nullopt; } } template Stream& -logMftAct( - Stream& s, - std::string const& action, - PublicKey const& pk, - std::uint32_t seq) +logMftAct(Stream& s, std::string const& action, PublicKey const& pk, std::uint32_t seq) { - s << "Manifest: " << action - << ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq - << ";"; + s << "Manifest: " << action << ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq << ";"; return s; } template Stream& -logMftAct( - Stream& s, - std::string const& action, - PublicKey const& pk, - std::uint32_t seq, - std::uint32_t oldSeq) +logMftAct(Stream& s, std::string const& action, PublicKey const& pk, std::uint32_t seq, std::uint32_t oldSeq) { - s << "Manifest: " << action - << ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq + s << "Manifest: " << action << ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq << ";OldSeq: " << oldSeq << ";"; return s; } @@ -206,11 +172,10 @@ Manifest::verify() const // Signing key and signature are not required for // master key revocations - if (!revoked() && !ripple::verify(st, HashPrefix::manifest, *signingKey)) + if (!revoked() && !xrpl::verify(st, HashPrefix::manifest, *signingKey)) return false; - return ripple::verify( - st, HashPrefix::manifest, masterKey, sfMasterSignature); + return xrpl::verify(st, HashPrefix::manifest, masterKey, sfMasterSignature); } uint256 @@ -267,11 +232,8 @@ loadValidatorToken(std::vector const& blob, beast::Journal journal) { std::string tokenStr; - tokenStr.reserve(std::accumulate( - blob.cbegin(), - blob.cend(), - std::size_t(0), - [](std::size_t init, std::string const& s) { + tokenStr.reserve( + std::accumulate(blob.cbegin(), blob.cend(), std::size_t(0), [](std::size_t init, std::string const& s) { return init + s.size(); })); @@ -301,8 +263,7 @@ loadValidatorToken(std::vector const& blob, beast::Journal journal) } catch (std::exception const& ex) { - JLOG(journal.error()) - << "Exception in " << __func__ << ": " << ex.what(); + JLOG(journal.error()) << "Exception in " << __func__ << ": " << ex.what(); return std::nullopt; } } @@ -324,8 +285,7 @@ ManifestCache::getMasterKey(PublicKey const& pk) const { std::shared_lock lock{mutex_}; - if (auto const iter = signingToMasterKeys_.find(pk); - iter != signingToMasterKeys_.end()) + if (auto const iter = signingToMasterKeys_.find(pk); iter != signingToMasterKeys_.end()) return iter->second; return pk; @@ -389,11 +349,8 @@ ManifestCache::applyManifest(Manifest m) // comment below), `checkSignature` only needs to be set to true on the // first run. auto prewriteCheck = - [this, &m](auto const& iter, bool checkSignature, auto const& lock) - -> std::optional { - XRPL_ASSERT( - lock.owns_lock(), - "ripple::ManifestCache::applyManifest::prewriteCheck : locked"); + [this, &m](auto const& iter, bool checkSignature, auto const& lock) -> std::optional { + XRPL_ASSERT(lock.owns_lock(), "xrpl::ManifestCache::applyManifest::prewriteCheck : locked"); (void)lock; // not used. parameter is present to ensure the mutex is // locked when the lambda is called. if (iter != map_.end() && m.sequence <= iter->second.sequence) @@ -403,12 +360,7 @@ ManifestCache::applyManifest(Manifest m) // several cases including when we receive manifests from a peer who // doesn't have the latest data. if (auto stream = j_.debug()) - logMftAct( - stream, - "Stale", - m.masterKey, - m.sequence, - iter->second.sequence); + logMftAct(stream, "Stale", m.masterKey, m.sequence, iter->second.sequence); return ManifestDisposition::stale; } @@ -433,11 +385,9 @@ ManifestCache::applyManifest(Manifest m) // Sanity check: the master key of this manifest should not be used as // the ephemeral key of another manifest: - if (auto const x = signingToMasterKeys_.find(m.masterKey); - x != signingToMasterKeys_.end()) + if (auto const x = signingToMasterKeys_.find(m.masterKey); x != signingToMasterKeys_.end()) { - JLOG(j_.warn()) << to_string(m) - << ": Master key already used as ephemeral key for " + JLOG(j_.warn()) << to_string(m) << ": Master key already used as ephemeral key for " << toBase58(TokenType::NodePublic, x->second); return ManifestDisposition::badMasterKey; @@ -456,22 +406,17 @@ ManifestCache::applyManifest(Manifest m) // Sanity check: the ephemeral key of this manifest should not be // used as the master or ephemeral key of another manifest: - if (auto const x = signingToMasterKeys_.find(*m.signingKey); - x != signingToMasterKeys_.end()) + if (auto const x = signingToMasterKeys_.find(*m.signingKey); x != signingToMasterKeys_.end()) { - JLOG(j_.warn()) - << to_string(m) - << ": Ephemeral key already used as ephemeral key for " - << toBase58(TokenType::NodePublic, x->second); + JLOG(j_.warn()) << to_string(m) << ": Ephemeral key already used as ephemeral key for " + << toBase58(TokenType::NodePublic, x->second); return ManifestDisposition::badEphemeralKey; } if (auto const x = map_.find(*m.signingKey); x != map_.end()) { - JLOG(j_.warn()) - << to_string(m) << ": Ephemeral key used as master key for " - << to_string(x->second); + JLOG(j_.warn()) << to_string(m) << ": Ephemeral key used as master key for " << to_string(x->second); return ManifestDisposition::badEphemeralKey; } @@ -482,8 +427,7 @@ ManifestCache::applyManifest(Manifest m) { std::shared_lock sl{mutex_}; - if (auto d = - prewriteCheck(map_.find(m.masterKey), /*checkSig*/ true, sl)) + if (auto d = prewriteCheck(map_.find(m.masterKey), /*checkSig*/ true, sl)) return *d; } @@ -514,18 +458,17 @@ ManifestCache::applyManifest(Manifest m) auto masterKey = m.masterKey; map_.emplace(std::move(masterKey), std::move(m)); + + // Something has changed. Keep track of it. + seq_++; + return ManifestDisposition::accepted; } // An ephemeral key was revoked and superseded by a new key. This is // expected, but should happen infrequently. if (auto stream = j_.info()) - logMftAct( - stream, - "AcceptedUpdate", - m.masterKey, - m.sequence, - iter->second.sequence); + logMftAct(stream, "AcceptedUpdate", m.masterKey, m.sequence, iter->second.sequence); signingToMasterKeys_.erase(*iter->second.signingKey); @@ -544,7 +487,7 @@ void ManifestCache::load(DatabaseCon& dbCon, std::string const& dbTable) { auto db = dbCon.checkoutDb(); - ripple::getManifests(*db, dbTable, *this, j_); + xrpl::getManifests(*db, dbTable, *this, j_); } bool @@ -584,17 +527,14 @@ ManifestCache::load( configRevocation.cbegin(), configRevocation.cend(), std::size_t(0), - [](std::size_t init, std::string const& s) { - return init + s.size(); - })); + [](std::size_t init, std::string const& s) { return init + s.size(); })); for (auto const& line : configRevocation) revocationStr += boost::algorithm::trim_copy(line); auto mo = deserializeManifest(base64_decode(revocationStr)); - if (!mo || !mo->revoked() || - applyManifest(std::move(*mo)) == ManifestDisposition::invalid) + if (!mo || !mo->revoked() || applyManifest(std::move(*mo)) == ManifestDisposition::invalid) { JLOG(j_.error()) << "Invalid validator key revocation in config"; return false; @@ -615,4 +555,4 @@ ManifestCache::save( saveManifests(*db, dbTable, isTrusted, map_, j_); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp index cc38a77d72..8ffbc47b08 100644 --- a/src/xrpld/app/misc/detail/Transaction.cpp +++ b/src/xrpld/app/misc/detail/Transaction.cpp @@ -1,40 +1,18 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include -#include #include #include #include #include #include +#include -namespace ripple { +namespace xrpl { -Transaction::Transaction( - std::shared_ptr const& stx, - std::string& reason, - Application& app) noexcept +Transaction::Transaction(std::shared_ptr const& stx, std::string& reason, Application& app) noexcept : mTransaction(stx), mApp(app), j_(app.journal("Ledger")) { try @@ -90,7 +68,7 @@ Transaction::sqlTransactionStatus(boost::optional const& status) XRPL_ASSERT( c == txnSqlUnknown, - "ripple::Transaction::sqlTransactionStatus : unknown transaction " + "xrpl::Transaction::sqlTransactionStatus : unknown transaction " "status"); return INVALID; } @@ -102,8 +80,7 @@ Transaction::transactionFromSQL( Blob const& rawTxn, Application& app) { - std::uint32_t const inLedger = - rangeCheckedCast(ledgerSeq.value_or(0)); + std::uint32_t const inLedger = rangeCheckedCast(ledgerSeq.value_or(0)); SerialIter it(makeSlice(rawTxn)); auto txn = std::make_shared(it); @@ -115,45 +92,30 @@ Transaction::transactionFromSQL( return tr; } -std::variant< - std::pair, std::shared_ptr>, - TxSearched> +std::variant, std::shared_ptr>, TxSearched> Transaction::load(uint256 const& id, Application& app, error_code_i& ec) { return load(id, app, std::nullopt, ec); } -std::variant< - std::pair, std::shared_ptr>, - TxSearched> -Transaction::load( - uint256 const& id, - Application& app, - ClosedInterval const& range, - error_code_i& ec) +std::variant, std::shared_ptr>, TxSearched> +Transaction::load(uint256 const& id, Application& app, ClosedInterval const& range, error_code_i& ec) { using op = std::optional>; return load(id, app, op{range}, ec); } -std::variant< - std::pair, std::shared_ptr>, - TxSearched> +std::variant, std::shared_ptr>, TxSearched> Transaction::load( uint256 const& id, Application& app, std::optional> const& range, error_code_i& ec) { - auto const db = dynamic_cast(&app.getRelationalDatabase()); + auto& db = app.getRelationalDatabase(); - if (!db) - { - Throw("Failed to get relational database"); - } - - return db->getTransaction(id, range, ec); + return db.getTransaction(id, range, ec); } // options 1 to include the date of the transaction @@ -161,8 +123,7 @@ Json::Value Transaction::getJson(JsonOptions options, bool binary) const { // Note, we explicitly suppress `include_date` option here - Json::Value ret( - mTransaction->getJson(options & ~JsonOptions::include_date, binary)); + Json::Value ret(mTransaction->getJson(options & ~JsonOptions::include_date, binary)); // NOTE Binary STTx::getJson output might not be a JSON object if (ret.isObject() && mLedgerIndex) @@ -192,8 +153,7 @@ Transaction::getJson(JsonOptions options, bool binary) const if (mTxnSeq && netID) { - std::optional const ctid = - RPC::encodeCTID(mLedgerIndex, *mTxnSeq, *netID); + std::optional const ctid = RPC::encodeCTID(mLedgerIndex, *mTxnSeq, *netID); if (ctid) ret[jss::ctid] = *ctid; } @@ -202,4 +162,4 @@ Transaction::getJson(JsonOptions options, bool binary) const return ret; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index 23a083fbe8..61741b73f0 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013, 2019 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -31,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { ////////////////////////////////////////////////////////////////////////// @@ -53,7 +34,7 @@ getFeeLevelPaid(ReadView const& view, STTx const& tx) return std::pair{baseFee + mod, feePaid + mod}; }(); - XRPL_ASSERT(baseFee.signum() > 0, "ripple::getFeeLevelPaid : positive fee"); + XRPL_ASSERT(baseFee.signum() > 0, "xrpl::getFeeLevelPaid : positive fee"); if (effectiveFeePaid.signum() <= 0 || baseFee.signum() <= 0) { return FeeLevel64(0); @@ -74,37 +55,27 @@ getLastLedgerSequence(STTx const& tx) static FeeLevel64 increase(FeeLevel64 level, std::uint32_t increasePercent) { - return mulDiv(level, 100 + increasePercent, 100) - .value_or(static_cast(ripple::muldiv_max)); + return mulDiv(level, 100 + increasePercent, 100).value_or(static_cast(xrpl::muldiv_max)); } ////////////////////////////////////////////////////////////////////////// std::size_t -TxQ::FeeMetrics::update( - Application& app, - ReadView const& view, - bool timeLeap, - TxQ::Setup const& setup) +TxQ::FeeMetrics::update(Application& app, ReadView const& view, bool timeLeap, TxQ::Setup const& setup) { std::vector feeLevels; auto const txBegin = view.txs.begin(); auto const txEnd = view.txs.end(); auto const size = std::distance(txBegin, txEnd); feeLevels.reserve(size); - std::for_each(txBegin, txEnd, [&](auto const& tx) { - feeLevels.push_back(getFeeLevelPaid(view, *tx.first)); - }); + std::for_each(txBegin, txEnd, [&](auto const& tx) { feeLevels.push_back(getFeeLevelPaid(view, *tx.first)); }); std::sort(feeLevels.begin(), feeLevels.end()); - XRPL_ASSERT( - size == feeLevels.size(), - "ripple::TxQ::FeeMetrics::update : fee levels size"); + XRPL_ASSERT(size == feeLevels.size(), "xrpl::TxQ::FeeMetrics::update : fee levels size"); JLOG((timeLeap ? j_.warn() : j_.debug())) - << "Ledger " << view.info().seq << " has " << size << " transactions. " - << "Ledgers are processing " << (timeLeap ? "slowly" : "as expected") - << ". Expected transactions is currently " << txnsExpected_ - << " and multiplier is " << escalationMultiplier_; + << "Ledger " << view.header().seq << " has " << size << " transactions. " + << "Ledgers are processing " << (timeLeap ? "slowly" : "as expected") << ". Expected transactions is currently " + << txnsExpected_ << " and multiplier is " << escalationMultiplier_; if (timeLeap) { @@ -113,22 +84,17 @@ TxQ::FeeMetrics::update( auto const cutPct = 100 - setup.slowConsensusDecreasePercent; // upperLimit must be >= minimumTxnCount_ or std::clamp can give // unexpected results - auto const upperLimit = std::max( - mulDiv(txnsExpected_, cutPct, 100).value_or(ripple::muldiv_max), - minimumTxnCount_); + auto const upperLimit = + std::max(mulDiv(txnsExpected_, cutPct, 100).value_or(xrpl::muldiv_max), minimumTxnCount_); txnsExpected_ = std::clamp( - mulDiv(size, cutPct, 100).value_or(ripple::muldiv_max), - minimumTxnCount_, - upperLimit); + mulDiv(size, cutPct, 100).value_or(xrpl::muldiv_max), minimumTxnCount_, upperLimit); recentTxnCounts_.clear(); } else if (size > txnsExpected_ || size > targetTxnCount_) { recentTxnCounts_.push_back( - mulDiv(size, 100 + setup.normalConsensusIncreasePercent, 100) - .value_or(ripple::muldiv_max)); - auto const iter = - std::max_element(recentTxnCounts_.begin(), recentTxnCounts_.end()); + mulDiv(size, 100 + setup.normalConsensusIncreasePercent, 100).value_or(xrpl::muldiv_max)); + auto const iter = std::max_element(recentTxnCounts_.begin(), recentTxnCounts_.end()); BOOST_ASSERT(iter != recentTxnCounts_.end()); auto const next = [&] { // Grow quickly: If the max_element is >= the @@ -157,14 +123,11 @@ TxQ::FeeMetrics::update( // evaluates to the middle element; for an even // number of elements, it will add the two elements // on either side of the "middle" and average them. - escalationMultiplier_ = - (feeLevels[size / 2] + feeLevels[(size - 1) / 2] + FeeLevel64{1}) / - 2; - escalationMultiplier_ = - std::max(escalationMultiplier_, setup.minimumEscalationMultiplier); + escalationMultiplier_ = (feeLevels[size / 2] + feeLevels[(size - 1) / 2] + FeeLevel64{1}) / 2; + escalationMultiplier_ = std::max(escalationMultiplier_, setup.minimumEscalationMultiplier); } - JLOG(j_.debug()) << "Expected transactions updated to " << txnsExpected_ - << " and multiplier updated to " << escalationMultiplier_; + JLOG(j_.debug()) << "Expected transactions updated to " << txnsExpected_ << " and multiplier updated to " + << escalationMultiplier_; return size; } @@ -185,7 +148,7 @@ TxQ::FeeMetrics::scaleFeeLevel(Snapshot const& snapshot, OpenView const& view) // Compute escalated fee level // Don't care about the overflow flag return mulDiv(multiplier, current * current, target * target) - .value_or(static_cast(ripple::muldiv_max)); + .value_or(static_cast(xrpl::muldiv_max)); } return baseLevel; @@ -223,10 +186,7 @@ static_assert(sumOfFirstSquares(0x1FFFFF).first == true, ""); static_assert(sumOfFirstSquares(0x1FFFFF).second == 0x2AAAA8AAAAB00000ul, ""); static_assert(sumOfFirstSquares(0x200000).first == false, ""); -static_assert( - sumOfFirstSquares(0x200000).second == - std::numeric_limits::max(), - ""); +static_assert(sumOfFirstSquares(0x200000).second == std::numeric_limits::max(), ""); } // namespace detail @@ -252,7 +212,7 @@ TxQ::FeeMetrics::escalatedSeriesFeeLevel( XRPL_ASSERT( current > target, - "ripple::TxQ::FeeMetrics::escalatedSeriesFeeLevel : current over " + "xrpl::TxQ::FeeMetrics::escalatedSeriesFeeLevel : current over " "target"); /* Calculate (apologies for the terrible notation) @@ -268,8 +228,7 @@ TxQ::FeeMetrics::escalatedSeriesFeeLevel( // are nearly nil. if (!sumNlast.first) return {sumNlast.first, FeeLevel64{sumNlast.second}}; - auto const totalFeeLevel = mulDiv( - multiplier, sumNlast.second - sumNcurrent.second, target * target); + auto const totalFeeLevel = mulDiv(multiplier, sumNlast.second - sumNcurrent.second, target * target); return {totalFeeLevel.has_value(), *totalFeeLevel}; } @@ -281,7 +240,7 @@ TxQ::MaybeTx::MaybeTx( TxID const& txID_, FeeLevel64 feeLevel_, ApplyFlags const flags_, - PreflightResult const& pfresult_) + PreflightResult const& pfResult_) : txn(txn_) , feeLevel(feeLevel_) , txID(txID_) @@ -290,7 +249,7 @@ TxQ::MaybeTx::MaybeTx( , seqProxy(txn_->getSeqProxy()) , retriesRemaining(retriesAllowed) , flags(flags_) - , pfresult(pfresult_) + , pfResult(pfResult_) { } @@ -298,27 +257,23 @@ ApplyResult TxQ::MaybeTx::apply(Application& app, OpenView& view, beast::Journal j) { // If the rules or flags change, preflight again - XRPL_ASSERT( - pfresult, "ripple::TxQ::MaybeTx::apply : preflight result is set"); + XRPL_ASSERT(pfResult, "xrpl::TxQ::MaybeTx::apply : preflight result is set"); NumberSO stNumberSO{view.rules().enabled(fixUniversalNumber)}; - if (pfresult->rules != view.rules() || pfresult->flags != flags) + if (pfResult->rules != view.rules() || pfResult->flags != flags) { - JLOG(j.debug()) << "Queued transaction " << txID - << " rules or flags have changed. Flags from " - << pfresult->flags << " to " << flags; + JLOG(j.debug()) << "Queued transaction " << txID << " rules or flags have changed. Flags from " + << pfResult->flags << " to " << flags; - pfresult.emplace( - preflight(app, view.rules(), pfresult->tx, flags, pfresult->j)); + pfResult.emplace(preflight(app, view.rules(), pfResult->tx, flags, pfResult->j)); } - auto pcresult = preclaim(*pfresult, app, view); + auto pcresult = preclaim(*pfResult, app, view); return doApply(pcresult, app, view); } -TxQ::TxQAccount::TxQAccount(std::shared_ptr const& txn) - : TxQAccount(txn->getAccountID(sfAccount)) +TxQ::TxQAccount::TxQAccount(std::shared_ptr const& txn) : TxQAccount(txn->getAccountID(sfAccount)) { } @@ -343,11 +298,8 @@ TxQ::TxQAccount::add(MaybeTx&& txn) auto const seqProx = txn.seqProxy; auto result = transactions.emplace(seqProx, std::move(txn)); - XRPL_ASSERT( - result.second, "ripple::TxQ::TxQAccount::add : emplace succeeded"); - XRPL_ASSERT( - &result.first->second != &txn, - "ripple::TxQ::TxQAccount::add : transaction moved"); + XRPL_ASSERT(result.second, "xrpl::TxQ::TxQAccount::add : emplace succeeded"); + XRPL_ASSERT(&result.first->second != &txn, "xrpl::TxQ::TxQAccount::add : transaction moved"); return result.first->second; } @@ -360,8 +312,7 @@ TxQ::TxQAccount::remove(SeqProxy seqProx) ////////////////////////////////////////////////////////////////////////// -TxQ::TxQ(Setup const& setup, beast::Journal j) - : setup_(setup), j_(j), feeMetrics_(setup, j), maxSize_(std::nullopt) +TxQ::TxQ(Setup const& setup, beast::Journal j) : setup_(setup), j_(j), feeMetrics_(setup, j), maxSize_(std::nullopt) { } @@ -374,8 +325,7 @@ template bool TxQ::isFull() const { - static_assert( - fillPercentage > 0 && fillPercentage <= 100, "Invalid fill percentage"); + static_assert(fillPercentage > 0 && fillPercentage <= 100, "Invalid fill percentage"); return maxSize_ && byFee_.size() >= (*maxSize_ * fillPercentage / 100); } @@ -393,8 +343,7 @@ TxQ::canBeHeld( // AccountTxnID is not supported by the transaction // queue yet, but should be added in the future. // tapFAIL_HARD transactions are never held - if (tx.isFieldPresent(sfPreviousTxnID) || - tx.isFieldPresent(sfAccountTxnID) || (flags & tapFAIL_HARD)) + if (tx.isFieldPresent(sfPreviousTxnID) || tx.isFieldPresent(sfAccountTxnID) || (flags & tapFAIL_HARD)) return telCAN_NOT_QUEUE; { @@ -402,8 +351,7 @@ TxQ::canBeHeld( // promise to stick around for long enough that it has // a realistic chance of getting into a ledger. auto const lastValid = getLastLedgerSequence(tx); - if (lastValid && - *lastValid < view.info().seq + setup_.minimumLastLedgerBuffer) + if (lastValid && *lastValid < view.header().seq + setup_.minimumLastLedgerBuffer) return telCAN_NOT_QUEUE; } @@ -446,8 +394,7 @@ TxQ::canBeHeld( } auto -TxQ::erase(TxQ::FeeMultiSet::const_iterator_type candidateIter) - -> FeeMultiSet::iterator_type +TxQ::erase(TxQ::FeeMultiSet::const_iterator_type candidateIter) -> FeeMultiSet::iterator_type { auto& txQAccount = byAccount_.at(candidateIter->account); auto const seqProx = candidateIter->seqProxy; @@ -456,48 +403,39 @@ TxQ::erase(TxQ::FeeMultiSet::const_iterator_type candidateIter) // intrusive list remove it from the TxQAccount // so the memory can be freed. [[maybe_unused]] auto const found = txQAccount.remove(seqProx); - XRPL_ASSERT(found, "ripple::TxQ::erase : account removed"); + XRPL_ASSERT(found, "xrpl::TxQ::erase : account removed"); return newCandidateIter; } auto -TxQ::eraseAndAdvance(TxQ::FeeMultiSet::const_iterator_type candidateIter) - -> FeeMultiSet::iterator_type +TxQ::eraseAndAdvance(TxQ::FeeMultiSet::const_iterator_type candidateIter) -> FeeMultiSet::iterator_type { auto& txQAccount = byAccount_.at(candidateIter->account); - auto const accountIter = - txQAccount.transactions.find(candidateIter->seqProxy); - XRPL_ASSERT( - accountIter != txQAccount.transactions.end(), - "ripple::TxQ::eraseAndAdvance : account found"); + auto const accountIter = txQAccount.transactions.find(candidateIter->seqProxy); + XRPL_ASSERT(accountIter != txQAccount.transactions.end(), "xrpl::TxQ::eraseAndAdvance : account found"); // Note that sequence-based transactions must be applied in sequence order // from smallest to largest. But ticket-based transactions can be // applied in any order. XRPL_ASSERT( - candidateIter->seqProxy.isTicket() || - accountIter == txQAccount.transactions.begin(), - "ripple::TxQ::eraseAndAdvance : ticket or sequence"); + candidateIter->seqProxy.isTicket() || accountIter == txQAccount.transactions.begin(), + "xrpl::TxQ::eraseAndAdvance : ticket or sequence"); XRPL_ASSERT( - byFee_.iterator_to(accountIter->second) == candidateIter, - "ripple::TxQ::eraseAndAdvance : found in byFee"); + byFee_.iterator_to(accountIter->second) == candidateIter, "xrpl::TxQ::eraseAndAdvance : found in byFee"); auto const accountNextIter = std::next(accountIter); // Check if the next transaction for this account is earlier in the queue, // which means we skipped it earlier, and need to try it again. auto const feeNextIter = std::next(candidateIter); - bool const useAccountNext = - accountNextIter != txQAccount.transactions.end() && + bool const useAccountNext = accountNextIter != txQAccount.transactions.end() && accountNextIter->first > candidateIter->seqProxy && - (feeNextIter == byFee_.end() || - byFee_.value_comp()(accountNextIter->second, *feeNextIter)); + (feeNextIter == byFee_.end() || byFee_.value_comp()(accountNextIter->second, *feeNextIter)); auto const candidateNextIter = byFee_.erase(candidateIter); txQAccount.transactions.erase(accountIter); - return useAccountNext ? byFee_.iterator_to(accountNextIter->second) - : candidateNextIter; + return useAccountNext ? byFee_.iterator_to(accountNextIter->second) : candidateNextIter; } auto @@ -521,7 +459,7 @@ TxQ::tryClearAccountQueueUpThruTx( TxQ::AccountMap::iterator const& accountIter, TxQAccount::TxMap::iterator beginTxIter, FeeLevel64 feeLevelPaid, - PreflightResult const& pfresult, + PreflightResult const& pfResult, std::size_t const txExtraCount, ApplyFlags flags, FeeMetrics::Snapshot const& metricsSnapshot, @@ -530,26 +468,23 @@ TxQ::tryClearAccountQueueUpThruTx( SeqProxy const tSeqProx{tx.getSeqProxy()}; XRPL_ASSERT( beginTxIter != accountIter->second.transactions.end(), - "ripple::TxQ::tryClearAccountQueueUpThruTx : non-empty accounts input"); + "xrpl::TxQ::tryClearAccountQueueUpThruTx : non-empty accounts input"); // This check is only concerned with the range from // [aSeqProxy, tSeqProxy) auto endTxIter = accountIter->second.transactions.lower_bound(tSeqProx); auto const dist = std::distance(beginTxIter, endTxIter); - auto const requiredTotalFeeLevel = FeeMetrics::escalatedSeriesFeeLevel( - metricsSnapshot, view, txExtraCount, dist + 1); + auto const requiredTotalFeeLevel = + FeeMetrics::escalatedSeriesFeeLevel(metricsSnapshot, view, txExtraCount, dist + 1); // If the computation for the total manages to overflow (however extremely // unlikely), then there's no way we can confidently verify if the queue // can be cleared. if (!requiredTotalFeeLevel.first) return {telINSUF_FEE_P, false}; - auto const totalFeeLevelPaid = std::accumulate( - beginTxIter, - endTxIter, - feeLevelPaid, - [](auto const& total, auto const& txn) { + auto const totalFeeLevelPaid = + std::accumulate(beginTxIter, endTxIter, feeLevelPaid, [](auto const& total, auto const& txn) { return total + txn.second.feeLevel; }); @@ -596,7 +531,7 @@ TxQ::tryClearAccountQueueUpThruTx( } // Apply the current tx. Because the state of the view has been changed // by the queued txs, we also need to preclaim again. - auto const txResult = doApply(preclaim(pfresult, app, view), app, view); + auto const txResult = doApply(preclaim(pfResult, app, view), app, view); if (txResult.applied) { @@ -604,8 +539,7 @@ TxQ::tryClearAccountQueueUpThruTx( // queue. endTxIter = erase(accountIter->second, beginTxIter, endTxIter); // If `tx` is replacing a queued tx, delete that one, too. - if (endTxIter != accountIter->second.transactions.end() && - endTxIter->first == tSeqProx) + if (endTxIter != accountIter->second.transactions.end() && endTxIter->first == tSeqProx) erase(accountIter->second, endTxIter, std::next(endTxIter)); } @@ -726,21 +660,16 @@ TxQ::tryClearAccountQueueUpThruTx( // beyond that limit are rejected. // ApplyResult -TxQ::apply( - Application& app, - OpenView& view, - std::shared_ptr const& tx, - ApplyFlags flags, - beast::Journal j) +TxQ::apply(Application& app, OpenView& view, std::shared_ptr const& tx, ApplyFlags flags, beast::Journal j) { NumberSO stNumberSO{view.rules().enabled(fixUniversalNumber)}; // See if the transaction is valid, properly formed, // etc. before doing potentially expensive queue // replace and multi-transaction operations. - auto const pfresult = preflight(app, view.rules(), *tx, flags, j); - if (pfresult.ter != tesSUCCESS) - return {pfresult.ter, false}; + auto const pfResult = preflight(app, view.rules(), *tx, flags, j); + if (pfResult.ter != tesSUCCESS) + return {pfResult.ter, false}; // See if the transaction paid a high enough fee that it can go straight // into the ledger. @@ -764,8 +693,7 @@ TxQ::apply( // If the transaction needs a Ticket is that Ticket in the ledger? SeqProxy const acctSeqProx = SeqProxy::sequence((*sleAccount)[sfSequence]); SeqProxy const txSeqProx = tx->getSeqProxy(); - if (txSeqProx.isTicket() && - !view.exists(keylet::ticket(account, txSeqProx))) + if (txSeqProx.isTicket() && !view.exists(keylet::ticket(account, txSeqProx))) { if (txSeqProx.value() < acctSeqProx.value()) // The ticket number is low enough that it should already be @@ -793,10 +721,7 @@ TxQ::apply( // to individually check each queued ticket against the ledger. struct TxIter { - TxIter( - TxQAccount::TxMap::iterator first_, - TxQAccount::TxMap::iterator end_) - : first(first_), end(end_) + TxIter(TxQAccount::TxMap::iterator first_, TxQAccount::TxMap::iterator end_) : first(first_), end(end_) { } @@ -804,17 +729,13 @@ TxQ::apply( TxQAccount::TxMap::iterator end; }; - std::optional const txIter = - [accountIter, - accountIsInQueue, - acctSeqProx]() -> std::optional { + std::optional const txIter = [accountIter, accountIsInQueue, acctSeqProx]() -> std::optional { if (!accountIsInQueue) return {}; // Find the first transaction in the queue that we might apply. TxQAccount::TxMap& acctTxs = accountIter->second.transactions; - TxQAccount::TxMap::iterator const firstIter = - acctTxs.lower_bound(acctSeqProx); + TxQAccount::TxMap::iterator const firstIter = acctTxs.lower_bound(acctSeqProx); if (firstIter == acctTxs.end()) // Even though there may be transactions in the queue, there are @@ -824,39 +745,35 @@ TxQ::apply( return {TxIter{firstIter, acctTxs.end()}}; }(); - auto const acctTxCount{ - !txIter ? 0 : std::distance(txIter->first, txIter->end)}; + auto const acctTxCount{!txIter ? 0 : std::distance(txIter->first, txIter->end)}; // Is tx a blocker? If so there are very limited conditions when it // is allowed in the TxQ: // 1. If the account's queue is empty or // 2. If the blocker replaces the only entry in the account's queue. auto const transactionID = tx->getTransactionID(); - if (pfresult.consequences.isBlocker()) + if (pfResult.consequences.isBlocker()) { if (acctTxCount > 1) { // A blocker may not be co-resident with other transactions in // the account's queue. - JLOG(j_.trace()) - << "Rejecting blocker transaction " << transactionID - << ". Account has other queued transactions."; + JLOG(j_.trace()) << "Rejecting blocker transaction " << transactionID + << ". Account has other queued transactions."; return {telCAN_NOT_QUEUE_BLOCKS, false}; } if (acctTxCount == 1 && (txSeqProx != txIter->first->first)) { // The blocker is not replacing the lone queued transaction. - JLOG(j_.trace()) - << "Rejecting blocker transaction " << transactionID - << ". Blocker does not replace lone queued transaction."; + JLOG(j_.trace()) << "Rejecting blocker transaction " << transactionID + << ". Blocker does not replace lone queued transaction."; return {telCAN_NOT_QUEUE_BLOCKS, false}; } } // If the transaction is intending to replace a transaction in the queue // identify the one that might be replaced. - auto replacedTxIter = [accountIsInQueue, &accountIter, txSeqProx]() - -> std::optional { + auto replacedTxIter = [accountIsInQueue, &accountIter, txSeqProx]() -> std::optional { if (accountIsInQueue) { TxQAccount& txQAcct = accountIter->second; @@ -871,8 +788,7 @@ TxQ::apply( // replacement, so just pull it up now. auto const metricsSnapshot = feeMetrics_.getSnapshot(); auto const feeLevelPaid = getFeeLevelPaid(view, *tx); - auto const requiredFeeLevel = - getRequiredFeeLevel(view, flags, metricsSnapshot, lock); + auto const requiredFeeLevel = getRequiredFeeLevel(view, flags, metricsSnapshot, lock); // Is there a blocker already in the account's queue? If so, don't // allow additional transactions in the queue. @@ -883,9 +799,7 @@ TxQ::apply( // // We only need to check if txIter->first is a blocker because we // require that a blocker be alone in the account's queue. - if (acctTxCount == 1 && - txIter->first->second.consequences().isBlocker() && - (txIter->first->first != txSeqProx)) + if (acctTxCount == 1 && txIter->first->second.consequences().isBlocker() && (txIter->first->first != txSeqProx)) { return {telCAN_NOT_QUEUE_BLOCKED, false}; } @@ -900,29 +814,23 @@ TxQ::apply( // Is the current transaction's fee higher than // the queued transaction's fee + a percentage TxQAccount::TxMap::iterator const& existingIter = *replacedTxIter; - auto requiredRetryLevel = increase( - existingIter->second.feeLevel, setup_.retrySequencePercent); - JLOG(j_.trace()) - << "Found transaction in queue for account " << account - << " with " << txSeqProx << " new txn fee level is " - << feeLevelPaid << ", old txn fee level is " - << existingIter->second.feeLevel - << ", new txn needs fee level of " << requiredRetryLevel; + auto requiredRetryLevel = increase(existingIter->second.feeLevel, setup_.retrySequencePercent); + JLOG(j_.trace()) << "Found transaction in queue for account " << account << " with " << txSeqProx + << " new txn fee level is " << feeLevelPaid << ", old txn fee level is " + << existingIter->second.feeLevel << ", new txn needs fee level of " << requiredRetryLevel; if (feeLevelPaid > requiredRetryLevel) { // Continue, leaving the queued transaction marked for removal. // DO NOT REMOVE if the new tx fails, because there may // be other txs dependent on it in the queue. - JLOG(j_.trace()) << "Removing transaction from queue " - << existingIter->second.txID << " in favor of " + JLOG(j_.trace()) << "Removing transaction from queue " << existingIter->second.txID << " in favor of " << transactionID; } else { // Drop the current transaction - JLOG(j_.trace()) - << "Ignoring transaction " << transactionID - << " in favor of queued " << existingIter->second.txID; + JLOG(j_.trace()) << "Ignoring transaction " << transactionID << " in favor of queued " + << existingIter->second.txID; return {telCAN_NOT_QUEUE_FEE, false}; } } @@ -933,8 +841,7 @@ TxQ::apply( ApplyViewImpl applyView; OpenView openView; - MultiTxn(OpenView& view, ApplyFlags flags) - : applyView(&view, flags), openView(&applyView) + MultiTxn(OpenView& view, ApplyFlags flags) : applyView(&view, flags), openView(&applyView) { } }; @@ -975,14 +882,7 @@ TxQ::apply( { // If the transaction is queueable, create the multiTxn // object to hold the info we need to adjust for prior txns. - TER const ter{canBeHeld( - *tx, - flags, - view, - sleAccount, - accountIter, - replacedTxIter, - lock)}; + TER const ter{canBeHeld(*tx, flags, view, sleAccount, accountIter, replacedTxIter, lock)}; if (!isTesSuccess(ter)) return {ter, false}; @@ -1003,8 +903,7 @@ TxQ::apply( // Find the entry in the queue that precedes the new // transaction, if one does. - TxQAccount::TxMap::const_iterator const prevIter = - txQAcct.getPrevTx(txSeqProx); + TxQAccount::TxMap::const_iterator const prevIter = txQAcct.getPrevTx(txSeqProx); // Does the new transaction go to the front of the queue? // This can happen if: @@ -1012,8 +911,7 @@ TxQ::apply( // o The current first thing in the queue has a Ticket and // * The tx has a Ticket that precedes it or // * txSeqProx == acctSeqProx. - XRPL_ASSERT( - prevIter != txIter->end, "ripple::TxQ::apply : not end"); + XRPL_ASSERT(prevIter != txIter->end, "xrpl::TxQ::apply : not end"); if (prevIter == txIter->end || txSeqProx < prevIter->first) { // The first Sequence number in the queue must be the @@ -1033,8 +931,7 @@ TxQ::apply( // front of this one in the queue. Make sure the current // transaction fits in proper sequence order with the // previous transaction or is a ticket. - if (txSeqProx.isSeq() && - nextQueuableSeqImpl(sleAccount, lock) != txSeqProx) + if (txSeqProx.isSeq() && nextQueuableSeqImpl(sleAccount, lock) != txSeqProx) return {telCAN_NOT_QUEUE, false}; } @@ -1051,16 +948,15 @@ TxQ::apply( if (iter->first != txSeqProx) { totalFee += iter->second.consequences().fee(); - potentialSpend += - iter->second.consequences().potentialSpend(); + potentialSpend += iter->second.consequences().potentialSpend(); } else if (std::next(iter) != txIter->end) { // The fee for the candidate transaction _should_ be // counted if it's replacing a transaction in the middle // of the queue. - totalFee += pfresult.consequences.fee(); - potentialSpend += pfresult.consequences.potentialSpend(); + totalFee += pfResult.consequences.fee(); + potentialSpend += pfResult.consequences.potentialSpend(); } } @@ -1113,12 +1009,10 @@ TxQ::apply( */ auto const reserve = view.fees().reserve; auto const base = view.fees().base; - if (totalFee >= balance || - (reserve > 10 * base && totalFee >= reserve)) + if (totalFee >= balance || (reserve > 10 * base && totalFee >= reserve)) { // Drop the current transaction - JLOG(j_.trace()) << "Ignoring transaction " << transactionID - << ". Total fees in flight too high."; + JLOG(j_.trace()) << "Ignoring transaction " << transactionID << ". Total fees in flight too high."; return {telCAN_NOT_QUEUE_BALANCE, false}; } @@ -1132,22 +1026,19 @@ TxQ::apply( // Subtract the fees and XRP spend from all of the other // transactions in the queue. That prevents a transaction // inserted in the middle from fouling up later transactions. - auto const potentialTotalSpend = totalFee + - std::min(balance - std::min(balance, reserve), potentialSpend); + auto const potentialTotalSpend = totalFee + std::min(balance - std::min(balance, reserve), potentialSpend); XRPL_ASSERT( potentialTotalSpend > XRPAmount{0} || - (potentialTotalSpend == XRPAmount{0} && - multiTxn->applyView.fees().base == 0), - "ripple::TxQ::apply : total spend check"); + (potentialTotalSpend == XRPAmount{0} && multiTxn->applyView.fees().base == 0), + "xrpl::TxQ::apply : total spend check"); sleBump->setFieldAmount(sfBalance, balance - potentialTotalSpend); // The transaction's sequence/ticket will be valid when the other // transactions in the queue have been processed. If the tx has a // sequence, set the account to match it. If it has a ticket, use // the next queueable sequence, which is the closest approximation // to the most successful case. - sleBump->at(sfSequence) = txSeqProx.isSeq() - ? txSeqProx.value() - : nextQueuableSeqImpl(sleAccount, lock).value(); + sleBump->at(sfSequence) = + txSeqProx.isSeq() ? txSeqProx.value() : nextQueuableSeqImpl(sleAccount, lock).value(); } } @@ -1162,19 +1053,16 @@ TxQ::apply( // Note that earlier code has already verified that the sequence/ticket // is valid. So we use a special entry point that runs all of the // preclaim checks with the exception of the sequence check. - auto const pcresult = - preclaim(pfresult, app, multiTxn ? multiTxn->openView : view); + auto const pcresult = preclaim(pfResult, app, multiTxn ? multiTxn->openView : view); if (!pcresult.likelyToClaimFee) return {pcresult.ter, false}; // Too low of a fee should get caught by preclaim - XRPL_ASSERT(feeLevelPaid >= baseLevel, "ripple::TxQ::apply : minimum fee"); + XRPL_ASSERT(feeLevelPaid >= baseLevel, "xrpl::TxQ::apply : minimum fee"); - JLOG(j_.trace()) << "Transaction " << transactionID << " from account " - << account << " has fee level of " << feeLevelPaid - << " needs at least " << requiredFeeLevel - << " to get in the open ledger, which has " - << view.txCount() << " entries."; + JLOG(j_.trace()) << "Transaction " << transactionID << " from account " << account << " has fee level of " + << feeLevelPaid << " needs at least " << requiredFeeLevel + << " to get in the open ledger, which has " << view.txCount() << " entries."; /* Quick heuristic check to see if it's worth checking that this tx has a high enough fee to clear all the txs in front of it in the queue. @@ -1194,8 +1082,8 @@ TxQ::apply( conditions change, but don't waste the effort to clear). */ if (txSeqProx.isSeq() && txIter && multiTxn.has_value() && - txIter->first->second.retriesRemaining == MaybeTx::retriesAllowed && - feeLevelPaid > requiredFeeLevel && requiredFeeLevel > baseLevel) + txIter->first->second.retriesRemaining == MaybeTx::retriesAllowed && feeLevelPaid > requiredFeeLevel && + requiredFeeLevel > baseLevel) { OpenView sandbox(open_ledger, &view, view.rules()); @@ -1206,7 +1094,7 @@ TxQ::apply( accountIter, txIter->first, feeLevelPaid, - pfresult, + pfResult, view.txCount(), flags, metricsSnapshot, @@ -1224,13 +1112,11 @@ TxQ::apply( // If `multiTxn` has a value, then `canBeHeld` has already been verified if (!multiTxn) { - TER const ter{canBeHeld( - *tx, flags, view, sleAccount, accountIter, replacedTxIter, lock)}; + TER const ter{canBeHeld(*tx, flags, view, sleAccount, accountIter, replacedTxIter, lock)}; if (!isTesSuccess(ter)) { // Bail, transaction cannot be held - JLOG(j_.trace()) - << "Transaction " << transactionID << " cannot be held"; + JLOG(j_.trace()) << "Transaction " << transactionID << " cannot be held"; return {ter, false}; } } @@ -1253,10 +1139,8 @@ TxQ::apply( // is 2000, and an account can only have 10 transactions // queued. However, it can occur if settings are changed, // and there is unit test coverage. - JLOG(j_.info()) - << "Queue is full, and transaction " << transactionID - << " would kick a transaction from the same account (" - << account << ") out of the queue."; + JLOG(j_.info()) << "Queue is full, and transaction " << transactionID + << " would kick a transaction from the same account (" << account << ") out of the queue."; return {telCAN_NOT_QUEUE_FULL, false}; } auto const& endAccount = byAccount_.at(lastRIter->account); @@ -1264,8 +1148,7 @@ TxQ::apply( // Compute the average of all the txs for the endAccount, // but only if the last tx in the queue has a lower fee // level than this candidate tx. - if (lastRIter->feeLevel > feeLevelPaid || - endAccount.transactions.size() == 1) + if (lastRIter->feeLevel > feeLevelPaid || endAccount.transactions.size() == 1) return lastRIter->feeLevel; constexpr FeeLevel64 max{std::numeric_limits::max()}; @@ -1273,20 +1156,16 @@ TxQ::apply( endAccount.transactions.begin(), endAccount.transactions.end(), std::pair(0, 0), - [&](auto const& total, - auto const& txn) -> std::pair { + [&](auto const& total, auto const& txn) -> std::pair { // Check for overflow. - auto next = - txn.second.feeLevel / endAccount.transactions.size(); - auto mod = - txn.second.feeLevel % endAccount.transactions.size(); + auto next = txn.second.feeLevel / endAccount.transactions.size(); + auto mod = txn.second.feeLevel % endAccount.transactions.size(); if (total.first >= max - next || total.second >= max - mod) return {max, FeeLevel64{0}}; return {total.first + next, total.second + mod}; }); - return endTotal.first + - endTotal.second / endAccount.transactions.size(); + return endTotal.first + endTotal.second / endAccount.transactions.size(); }(); if (feeLevelPaid > endEffectiveFeeLevel) { @@ -1294,20 +1173,16 @@ TxQ::apply( // valuable, so kick out the cheapest transaction. auto dropRIter = endAccount.transactions.rbegin(); XRPL_ASSERT( - dropRIter->second.account == lastRIter->account, - "ripple::TxQ::apply : cheapest transaction found"); - JLOG(j_.info()) - << "Removing last item of account " << lastRIter->account - << " from queue with average fee of " << endEffectiveFeeLevel - << " in favor of " << transactionID << " with fee of " - << feeLevelPaid; + dropRIter->second.account == lastRIter->account, "xrpl::TxQ::apply : cheapest transaction found"); + JLOG(j_.info()) << "Removing last item of account " << lastRIter->account + << " from queue with average fee of " << endEffectiveFeeLevel << " in favor of " + << transactionID << " with fee of " << feeLevelPaid; erase(byFee_.iterator_to(dropRIter->second)); } else { - JLOG(j_.info()) - << "Queue is full, and transaction " << transactionID - << " fee is lower than end item's account average fee"; + JLOG(j_.info()) << "Queue is full, and transaction " << transactionID + << " fee is lower than end item's account average fee"; return {telCAN_NOT_QUEUE_FULL, false}; } } @@ -1322,9 +1197,8 @@ TxQ::apply( { // Create a new TxQAccount object and add the byAccount lookup. [[maybe_unused]] bool created = false; - std::tie(accountIter, created) = - byAccount_.emplace(account, TxQAccount(tx)); - XRPL_ASSERT(created, "ripple::TxQ::apply : account created"); + std::tie(accountIter, created) = byAccount_.emplace(account, TxQAccount(tx)); + XRPL_ASSERT(created, "xrpl::TxQ::apply : account created"); } // Modify the flags for use when coming out of the queue. // These changes _may_ cause an extra `preflight`, but as long as @@ -1334,15 +1208,13 @@ TxQ::apply( // Don't allow soft failures, which can lead to retries flags &= ~tapRETRY; - auto& candidate = accountIter->second.add( - {tx, transactionID, feeLevelPaid, flags, pfresult}); + auto& candidate = accountIter->second.add({tx, transactionID, feeLevelPaid, flags, pfResult}); // Then index it into the byFee lookup. byFee_.insert(candidate); - JLOG(j_.debug()) << "Added transaction " << candidate.txID - << " with result " << transToken(pfresult.ter) << " from " - << (accountIsInQueue ? "existing" : "new") << " account " - << candidate.account << " to queue." + JLOG(j_.debug()) << "Added transaction " << candidate.txID << " with result " << transToken(pfResult.ter) + << " from " << (accountIsInQueue ? "existing" : "new") << " account " << candidate.account + << " to queue." << " Flags: " << flags; return {terQUEUED, false}; @@ -1368,11 +1240,10 @@ TxQ::processClosedLedger(Application& app, ReadView const& view, bool timeLeap) feeMetrics_.update(app, view, timeLeap, setup_); auto const& snapshot = feeMetrics_.getSnapshot(); - auto ledgerSeq = view.info().seq; + auto ledgerSeq = view.header().seq; if (!timeLeap) - maxSize_ = std::max( - snapshot.txnsExpected * setup_.ledgersInQueue, setup_.queueSizeMin); + maxSize_ = std::max(snapshot.txnsExpected * setup_.ledgersInQueue, setup_.queueSizeMin); // Remove any queued candidates whose LastLedgerSequence has gone by. for (auto candidateIter = byFee_.begin(); candidateIter != byFee_.end();) @@ -1390,8 +1261,7 @@ TxQ::processClosedLedger(Application& app, ReadView const& view, bool timeLeap) // Remove any TxQAccounts that don't have candidates // under them - for (auto txQAccountIter = byAccount_.begin(); - txQAccountIter != byAccount_.end();) + for (auto txQAccountIter = byAccount_.begin(); txQAccountIter != byAccount_.end();) { if (txQAccountIter->second.empty()) txQAccountIter = byAccount_.erase(txQAccountIter); @@ -1448,72 +1318,56 @@ TxQ::accept(Application& app, OpenView& view) { auto& account = byAccount_.at(candidateIter->account); auto const beginIter = account.transactions.begin(); - if (candidateIter->seqProxy.isSeq() && - candidateIter->seqProxy > beginIter->first) + if (candidateIter->seqProxy.isSeq() && candidateIter->seqProxy > beginIter->first) { // There is a sequence transaction at the front of the queue and // candidate has a later sequence, so skip this candidate. We // need to process sequence-based transactions in sequence order. - JLOG(j_.trace()) - << "Skipping queued transaction " << candidateIter->txID - << " from account " << candidateIter->account - << " as it is not the first."; + JLOG(j_.trace()) << "Skipping queued transaction " << candidateIter->txID << " from account " + << candidateIter->account << " as it is not the first."; candidateIter++; continue; } - auto const requiredFeeLevel = - getRequiredFeeLevel(view, tapNONE, metricsSnapshot, lock); + auto const requiredFeeLevel = getRequiredFeeLevel(view, tapNONE, metricsSnapshot, lock); auto const feeLevelPaid = candidateIter->feeLevel; - JLOG(j_.trace()) << "Queued transaction " << candidateIter->txID - << " from account " << candidateIter->account - << " has fee level of " << feeLevelPaid - << " needs at least " << requiredFeeLevel; + JLOG(j_.trace()) << "Queued transaction " << candidateIter->txID << " from account " << candidateIter->account + << " has fee level of " << feeLevelPaid << " needs at least " << requiredFeeLevel; if (feeLevelPaid >= requiredFeeLevel) { - JLOG(j_.trace()) << "Applying queued transaction " - << candidateIter->txID << " to open ledger."; + JLOG(j_.trace()) << "Applying queued transaction " << candidateIter->txID << " to open ledger."; - auto const [txnResult, didApply, _metadata] = - candidateIter->apply(app, view, j_); + auto const [txnResult, didApply, _metadata] = candidateIter->apply(app, view, j_); if (didApply) { // Remove the candidate from the queue - JLOG(j_.debug()) - << "Queued transaction " << candidateIter->txID - << " applied successfully with " << transToken(txnResult) - << ". Remove from queue."; + JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " applied successfully with " + << transToken(txnResult) << ". Remove from queue."; candidateIter = eraseAndAdvance(candidateIter); ledgerChanged = true; } - else if ( - isTefFailure(txnResult) || isTemMalformed(txnResult) || - candidateIter->retriesRemaining <= 0) + else if (isTefFailure(txnResult) || isTemMalformed(txnResult) || candidateIter->retriesRemaining <= 0) { if (candidateIter->retriesRemaining <= 0) account.retryPenalty = true; else account.dropPenalty = true; - JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID - << " failed with " << transToken(txnResult) - << ". Remove from queue."; + JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " failed with " + << transToken(txnResult) << ". Remove from queue."; candidateIter = eraseAndAdvance(candidateIter); } else { - JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID - << " failed with " << transToken(txnResult) - << ". Leave in queue." - << " Applied: " << didApply - << ". Flags: " << candidateIter->flags; + JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " failed with " + << transToken(txnResult) << ". Leave in queue." + << " Applied: " << didApply << ". Flags: " << candidateIter->flags; if (account.retryPenalty && candidateIter->retriesRemaining > 2) candidateIter->retriesRemaining = 1; else --candidateIter->retriesRemaining; candidateIter->lastResult = txnResult; - if (account.dropPenalty && account.transactions.size() > 1 && - isFull<95>()) + if (account.dropPenalty && account.transactions.size() > 1 && isFull<95>()) { // The queue is close to full, this account has multiple // txs queued, and this account has had a transaction @@ -1522,12 +1376,9 @@ TxQ::accept(Application& app, OpenView& view) { // Since the failed transaction has a ticket, order // doesn't matter. Drop this one. - JLOG(j_.info()) - << "Queue is nearly full, and transaction " - << candidateIter->txID << " failed with " - << transToken(txnResult) - << ". Removing ticketed tx from account " - << account.account; + JLOG(j_.info()) << "Queue is nearly full, and transaction " << candidateIter->txID + << " failed with " << transToken(txnResult) + << ". Removing ticketed tx from account " << account.account; candidateIter = eraseAndAdvance(candidateIter); } else @@ -1538,15 +1389,11 @@ TxQ::accept(Application& app, OpenView& view) // this account. auto dropRIter = account.transactions.rbegin(); XRPL_ASSERT( - dropRIter->second.account == candidateIter->account, - "ripple::TxQ::accept : account check"); + dropRIter->second.account == candidateIter->account, "xrpl::TxQ::accept : account check"); - JLOG(j_.info()) - << "Queue is nearly full, and transaction " - << candidateIter->txID << " failed with " - << transToken(txnResult) - << ". Removing last item from account " - << account.account; + JLOG(j_.info()) << "Queue is nearly full, and transaction " << candidateIter->txID + << " failed with " << transToken(txnResult) + << ". Removing last item from account " << account.account; auto endIter = byFee_.iterator_to(dropRIter->second); if (endIter != candidateIter) erase(endIter); @@ -1567,7 +1414,7 @@ TxQ::accept(Application& app, OpenView& view) // ledger have been. Rebuild the queue using the open ledger's // parent hash, so that transactions paying the same fee are // reordered. - LedgerHash const& parentHash = view.info().parentHash; + LedgerHash const& parentHash = view.header().parentHash; if (parentHash == parentHash_) JLOG(j_.warn()) << "Parent ledger hash unchanged from " << parentHash; else @@ -1593,9 +1440,7 @@ TxQ::accept(Application& app, OpenView& view) byFee_.insert(candidate); } } - XRPL_ASSERT( - byFee_.size() == startingSize, - "ripple::TxQ::accept : byFee size match"); + XRPL_ASSERT(byFee_.size() == startingSize, "xrpl::TxQ::accept : byFee size match"); return ledgerChanged; } @@ -1617,9 +1462,7 @@ TxQ::nextQueuableSeq(std::shared_ptr const& sleAccount) const // sequence number, that is not used by a transaction in the queue, must // be found and returned. SeqProxy -TxQ::nextQueuableSeqImpl( - std::shared_ptr const& sleAccount, - std::lock_guard const&) const +TxQ::nextQueuableSeqImpl(std::shared_ptr const& sleAccount, std::lock_guard const&) const { // If the account is not in the ledger or a non-account was passed // then return zero. We have no idea. @@ -1630,8 +1473,7 @@ TxQ::nextQueuableSeqImpl( // If the account is not in the queue then acctSeqProx is good enough. auto const accountIter = byAccount_.find((*sleAccount)[sfAccount]); - if (accountIter == byAccount_.end() || - accountIter->second.transactions.empty()) + if (accountIter == byAccount_.end() || accountIter->second.transactions.empty()) return acctSeqProx; TxQAccount::TxMap const& acctTxs = accountIter->second.transactions; @@ -1641,8 +1483,7 @@ TxQ::nextQueuableSeqImpl( // wild, but it's uncommon. TxQAccount::TxMap::const_iterator txIter = acctTxs.lower_bound(acctSeqProx); - if (txIter == acctTxs.end() || !txIter->first.isSeq() || - txIter->first != acctSeqProx) + if (txIter == acctTxs.end() || !txIter->first.isSeq() || txIter->first != acctSeqProx) // Either... // o There are no queued sequence-based transactions equal to or // following acctSeqProx or @@ -1698,8 +1539,7 @@ TxQ::tryDirectApply( FeeLevel64 const requiredFeeLevel = [this, &view, flags]() { std::lock_guard lock(mutex_); - return getRequiredFeeLevel( - view, flags, feeMetrics_.getSnapshot(), lock); + return getRequiredFeeLevel(view, flags, feeMetrics_.getSnapshot(), lock); }(); // If the transaction's fee is high enough we may be able to put the @@ -1710,16 +1550,12 @@ TxQ::tryDirectApply( { // Attempt to apply the transaction directly. auto const transactionID = tx->getTransactionID(); - JLOG(j_.trace()) << "Applying transaction " << transactionID - << " to open ledger."; + JLOG(j_.trace()) << "Applying transaction " << transactionID << " to open ledger."; - auto const [txnResult, didApply, metadata] = - ripple::apply(app, view, *tx, flags, j); + auto const [txnResult, didApply, metadata] = xrpl::apply(app, view, *tx, flags, j); JLOG(j_.trace()) << "New transaction " << transactionID - << (didApply ? " applied successfully with " - : " failed with ") - << transToken(txnResult); + << (didApply ? " applied successfully with " : " failed with ") << transToken(txnResult); if (didApply) { @@ -1731,8 +1567,7 @@ TxQ::tryDirectApply( if (accountIter != byAccount_.end()) { TxQAccount& txQAcct = accountIter->second; - if (auto const existingIter = - txQAcct.transactions.find(txSeqProx); + if (auto const existingIter = txQAcct.transactions.find(txSeqProx); existingIter != txQAcct.transactions.end()) { removeFromByFee(existingIter, tx); @@ -1754,18 +1589,10 @@ TxQ::removeFromByFee( // If the transaction we're holding replaces a transaction in the // queue, remove the transaction that is being replaced. auto deleteIter = byFee_.iterator_to((*replacedTxIter)->second); - XRPL_ASSERT( - deleteIter != byFee_.end(), - "ripple::TxQ::removeFromByFee : found in byFee"); - XRPL_ASSERT( - &(*replacedTxIter)->second == &*deleteIter, - "ripple::TxQ::removeFromByFee : matching transaction"); - XRPL_ASSERT( - deleteIter->seqProxy == tx->getSeqProxy(), - "ripple::TxQ::removeFromByFee : matching sequence"); - XRPL_ASSERT( - deleteIter->account == (*tx)[sfAccount], - "ripple::TxQ::removeFromByFee : matching account"); + XRPL_ASSERT(deleteIter != byFee_.end(), "xrpl::TxQ::removeFromByFee : found in byFee"); + XRPL_ASSERT(&(*replacedTxIter)->second == &*deleteIter, "xrpl::TxQ::removeFromByFee : matching transaction"); + XRPL_ASSERT(deleteIter->seqProxy == tx->getSeqProxy(), "xrpl::TxQ::removeFromByFee : matching sequence"); + XRPL_ASSERT(deleteIter->account == (*tx)[sfAccount], "xrpl::TxQ::removeFromByFee : matching account"); erase(deleteIter); } @@ -1786,8 +1613,7 @@ TxQ::getMetrics(OpenView const& view) const result.txInLedger = view.txCount(); result.txPerLedger = snapshot.txnsExpected; result.referenceFeeLevel = baseLevel; - result.minProcessingFeeLevel = - isFull() ? byFee_.rbegin()->feeLevel + FeeLevel64{1} : baseLevel; + result.minProcessingFeeLevel = isFull() ? byFee_.rbegin()->feeLevel + FeeLevel64{1} : baseLevel; result.medFeeLevel = snapshot.escalationMultiplier; result.openLedgerFeeLevel = FeeMetrics::scaleFeeLevel(snapshot, view); @@ -1795,9 +1621,7 @@ TxQ::getMetrics(OpenView const& view) const } TxQ::FeeAndSeq -TxQ::getTxRequiredFeeAndSeq( - OpenView const& view, - std::shared_ptr const& tx) const +TxQ::getTxRequiredFeeAndSeq(OpenView const& view, std::shared_ptr const& tx) const { auto const account = (*tx)[sfAccount]; @@ -1812,8 +1636,7 @@ TxQ::getTxRequiredFeeAndSeq( std::uint32_t const accountSeq = sle ? (*sle)[sfSequence] : 0; std::uint32_t const availableSeq = nextQueuableSeqImpl(sle, lock).value(); return { - mulDiv(fee, baseFee, baseLevel) - .value_or(XRPAmount(std::numeric_limits::max())), + mulDiv(fee, baseFee, baseLevel).value_or(XRPAmount(std::numeric_limits::max())), accountSeq, availableSeq}; } @@ -1827,8 +1650,7 @@ TxQ::getAccountTxs(AccountID const& account) const AccountMap::const_iterator const accountIter{byAccount_.find(account)}; - if (accountIter == byAccount_.end() || - accountIter->second.transactions.empty()) + if (accountIter == byAccount_.end() || accountIter->second.transactions.empty()) return result; result.reserve(accountIter->second.transactions.size()); @@ -1870,7 +1692,7 @@ TxQ::doRPC(Application& app) const auto& levels = ret[jss::levels] = Json::objectValue; - ret[jss::ledger_current_index] = view->info().seq; + ret[jss::ledger_current_index] = view->header().seq; ret[jss::expected_ledger_size] = std::to_string(metrics.txPerLedger); ret[jss::current_ledger_size] = std::to_string(metrics.txInLedger); ret[jss::current_queue_size] = std::to_string(metrics.txCount); @@ -1895,12 +1717,10 @@ TxQ::doRPC(Application& app) const drops[jss::base_fee] = to_string(baseFee); drops[jss::median_fee] = to_string(toDrops(metrics.medFeeLevel, baseFee)); - drops[jss::minimum_fee] = to_string(toDrops( - metrics.minProcessingFeeLevel, - metrics.txCount >= metrics.txQMaxSize ? effectiveBaseFee : baseFee)); + drops[jss::minimum_fee] = to_string( + toDrops(metrics.minProcessingFeeLevel, metrics.txCount >= metrics.txQMaxSize ? effectiveBaseFee : baseFee)); auto openFee = toDrops(metrics.openLedgerFeeLevel, effectiveBaseFee); - if (effectiveBaseFee && - toFeeLevel(openFee, effectiveBaseFee) < metrics.openLedgerFeeLevel) + if (effectiveBaseFee && toFeeLevel(openFee, effectiveBaseFee) < metrics.openLedgerFeeLevel) openFee += 1; drops[jss::open_ledger_fee] = to_string(openFee); @@ -1917,13 +1737,9 @@ setup_TxQ(Config const& config) set(setup.ledgersInQueue, "ledgers_in_queue", section); set(setup.queueSizeMin, "minimum_queue_size", section); set(setup.retrySequencePercent, "retry_sequence_percent", section); - set(setup.minimumEscalationMultiplier, - "minimum_escalation_multiplier", - section); + set(setup.minimumEscalationMultiplier, "minimum_escalation_multiplier", section); set(setup.minimumTxnInLedger, "minimum_txn_in_ledger", section); - set(setup.minimumTxnInLedgerSA, - "minimum_txn_in_ledger_standalone", - section); + set(setup.minimumTxnInLedgerSA, "minimum_txn_in_ledger_standalone", section); set(setup.targetTxnInLedger, "target_txn_in_ledger", section); std::uint32_t max; if (set(max, "maximum_txn_in_ledger", section)) @@ -1954,21 +1770,15 @@ setup_TxQ(Config const& config) moot. (There are other ways to do that, including minimum_txn_in_ledger.) */ - set(setup.normalConsensusIncreasePercent, - "normal_consensus_increase_percent", - section); - setup.normalConsensusIncreasePercent = - std::clamp(setup.normalConsensusIncreasePercent, 0u, 1000u); + set(setup.normalConsensusIncreasePercent, "normal_consensus_increase_percent", section); + setup.normalConsensusIncreasePercent = std::clamp(setup.normalConsensusIncreasePercent, 0u, 1000u); /* If this percentage is outside of the 0-100 range, the results are nonsensical (uint overflows happen, so the limit grows instead of shrinking). 0 is not recommended. */ - set(setup.slowConsensusDecreasePercent, - "slow_consensus_decrease_percent", - section); - setup.slowConsensusDecreasePercent = - std::clamp(setup.slowConsensusDecreasePercent, 0u, 100u); + set(setup.slowConsensusDecreasePercent, "slow_consensus_decrease_percent", section); + setup.slowConsensusDecreasePercent = std::clamp(setup.slowConsensusDecreasePercent, 0u, 100u); set(setup.maximumTxnPerAccount, "maximum_txn_per_account", section); set(setup.minimumLastLedgerBuffer, "minimum_last_ledger_buffer", section); @@ -1977,4 +1787,4 @@ setup_TxQ(Config const& config) return setup; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/ValidatorKeys.cpp b/src/xrpld/app/misc/detail/ValidatorKeys.cpp index 8227c5bcdb..8f24f14b40 100644 --- a/src/xrpld/app/misc/detail/ValidatorKeys.cpp +++ b/src/xrpld/app/misc/detail/ValidatorKeys.cpp @@ -1,58 +1,33 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include #include #include #include #include #include +#include -namespace ripple { +namespace xrpl { ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j) { - if (config.exists(SECTION_VALIDATOR_TOKEN) && - config.exists(SECTION_VALIDATION_SEED)) + if (config.exists(SECTION_VALIDATOR_TOKEN) && config.exists(SECTION_VALIDATION_SEED)) { configInvalid_ = true; - JLOG(j.fatal()) << "Cannot specify both [" SECTION_VALIDATION_SEED - "] and [" SECTION_VALIDATOR_TOKEN "]"; + JLOG(j.fatal()) << "Cannot specify both [" SECTION_VALIDATION_SEED "] and [" SECTION_VALIDATOR_TOKEN "]"; return; } if (config.exists(SECTION_VALIDATOR_TOKEN)) { // token is non-const so it can be moved from - if (auto token = loadValidatorToken( - config.section(SECTION_VALIDATOR_TOKEN).lines())) + if (auto token = loadValidatorToken(config.section(SECTION_VALIDATOR_TOKEN).lines())) { - auto const pk = - derivePublicKey(KeyType::secp256k1, token->validationSecret); + auto const pk = derivePublicKey(KeyType::secp256k1, token->validationSecret); auto const m = deserializeManifest(base64_decode(token->manifest)); if (!m || pk != m->signingKey) { configInvalid_ = true; - JLOG(j.fatal()) - << "Invalid token specified in [" SECTION_VALIDATOR_TOKEN - "]"; + JLOG(j.fatal()) << "Invalid token specified in [" SECTION_VALIDATOR_TOKEN "]"; } else { @@ -65,19 +40,16 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j) else { configInvalid_ = true; - JLOG(j.fatal()) - << "Invalid token specified in [" SECTION_VALIDATOR_TOKEN "]"; + JLOG(j.fatal()) << "Invalid token specified in [" SECTION_VALIDATOR_TOKEN "]"; } } else if (config.exists(SECTION_VALIDATION_SEED)) { - auto const seed = parseBase58( - config.section(SECTION_VALIDATION_SEED).lines().front()); + auto const seed = parseBase58(config.section(SECTION_VALIDATION_SEED).lines().front()); if (!seed) { configInvalid_ = true; - JLOG(j.fatal()) - << "Invalid seed specified in [" SECTION_VALIDATION_SEED "]"; + JLOG(j.fatal()) << "Invalid seed specified in [" SECTION_VALIDATION_SEED "]"; } else { @@ -89,4 +61,4 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j) } } } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 926649808d..0edd0de9be 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -39,7 +20,7 @@ #include #include -namespace ripple { +namespace xrpl { std::string to_string(ListDisposition disposition) @@ -86,20 +67,17 @@ ValidatorList::PublisherListStats::PublisherListStats( ListDisposition ValidatorList::PublisherListStats::bestDisposition() const { - return dispositions.empty() ? ListDisposition::invalid - : dispositions.begin()->first; + return dispositions.empty() ? ListDisposition::invalid : dispositions.begin()->first; } ListDisposition ValidatorList::PublisherListStats::worstDisposition() const { - return dispositions.empty() ? ListDisposition::invalid - : dispositions.rbegin()->first; + return dispositions.empty() ? ListDisposition::invalid : dispositions.rbegin()->first; } void -ValidatorList::PublisherListStats::mergeDispositions( - PublisherListStats const& src) +ValidatorList::PublisherListStats::mergeDispositions(PublisherListStats const& src) { for (auto const& [disp, count] : src.dispositions) { @@ -156,8 +134,7 @@ ValidatorList::load( std::lock_guard lock{mutex_}; - JLOG(j_.debug()) - << "Loading configured trusted validator list publisher keys"; + JLOG(j_.debug()) << "Loading configured trusted validator list publisher keys"; std::size_t count = 0; for (auto key : publisherKeys) @@ -177,16 +154,13 @@ ValidatorList::load( if (publisherManifests_.revoked(id)) { - JLOG(j_.warn()) - << "Configured validator list publisher key is revoked: " - << key; + JLOG(j_.warn()) << "Configured validator list publisher key is revoked: " << key; status = PublisherStatus::revoked; } if (publisherLists_.count(id)) { - JLOG(j_.warn()) - << "Duplicate validator list publisher key: " << key; + JLOG(j_.warn()) << "Duplicate validator list publisher key: " << key; continue; } @@ -200,18 +174,15 @@ ValidatorList::load( // This should be enforced by Config class XRPL_ASSERT( listThreshold_ > 0 && listThreshold_ <= publisherLists_.size(), - "ripple::ValidatorList::load : list threshold inside range"); - JLOG(j_.debug()) << "Validator list threshold set in configuration to " - << listThreshold_; + "xrpl::ValidatorList::load : list threshold inside range"); + JLOG(j_.debug()) << "Validator list threshold set in configuration to " << listThreshold_; } else { // Want truncated result when dividing an odd integer - listThreshold_ = (publisherLists_.size() < 3) - ? 1 // - : publisherLists_.size() / 2 + 1; - JLOG(j_.debug()) << "Validator list threshold computed as " - << listThreshold_; + listThreshold_ = (publisherLists_.size() < 3) ? 1 // + : publisherLists_.size() / 2 + 1; + JLOG(j_.debug()) << "Validator list threshold computed as " << listThreshold_; } JLOG(j_.debug()) << "Loaded " << count << " keys"; @@ -224,12 +195,10 @@ ValidatorList::load( { // The local validator must meet listThreshold_ so the validator does // not ignore itself. - auto const [_, inserted] = - keyListings_.insert({*localPubKey_, listThreshold_}); + auto const [_, inserted] = keyListings_.insert({*localPubKey_, listThreshold_}); if (inserted) { - JLOG(j_.debug()) << "Added own master key " - << toBase58(TokenType::NodePublic, *localPubKey_); + JLOG(j_.debug()) << "Added own master key " << toBase58(TokenType::NodePublic, *localPubKey_); } } @@ -248,8 +217,7 @@ ValidatorList::load( return false; } - auto const id = - parseBase58(TokenType::NodePublic, match[1].str()); + auto const id = parseBase58(TokenType::NodePublic, match[1].str()); if (!id) { @@ -283,9 +251,7 @@ ValidatorList::load( } boost::filesystem::path -ValidatorList::getCacheFileName( - ValidatorList::lock_guard const&, - PublicKey const& pubKey) const +ValidatorList::getCacheFileName(ValidatorList::lock_guard const&, PublicKey const& pubKey) const { return dataPath_ / (filePrefix_ + strHex(pubKey)); } @@ -312,9 +278,8 @@ ValidatorList::buildFileData( XRPL_ASSERT( pubCollection.rawVersion == 2 || pubCollection.remaining.empty(), - "ripple::ValidatorList::buildFileData : valid publisher list input"); - auto const effectiveVersion = - forceVersion ? *forceVersion : pubCollection.rawVersion; + "xrpl::ValidatorList::buildFileData : valid publisher list input"); + auto const effectiveVersion = forceVersion ? *forceVersion : pubCollection.rawVersion; value[jss::manifest] = pubCollection.rawManifest; value[jss::version] = effectiveVersion; @@ -328,21 +293,18 @@ ValidatorList::buildFileData( value[jss::signature] = current.rawSignature; // This is only possible if "downgrading" a v2 UNL to v1, for // example for the /vl/ endpoint. - if (current.rawManifest && - *current.rawManifest != pubCollection.rawManifest) + if (current.rawManifest && *current.rawManifest != pubCollection.rawManifest) value[jss::manifest] = *current.rawManifest; break; } case 2: { Json::Value blobs(Json::arrayValue); - auto add = [&blobs, &outerManifest = pubCollection.rawManifest]( - PublisherList const& pubList) { + auto add = [&blobs, &outerManifest = pubCollection.rawManifest](PublisherList const& pubList) { auto& blob = blobs.append(Json::objectValue); blob[jss::blob] = pubList.rawBlob; blob[jss::signature] = pubList.rawSignature; - if (pubList.rawManifest && - *pubList.rawManifest != outerManifest) + if (pubList.rawManifest && *pubList.rawManifest != outerManifest) blob[jss::manifest] = *pubList.rawManifest; }; @@ -357,8 +319,7 @@ ValidatorList::buildFileData( break; } default: - JLOG(j.trace()) - << "Invalid VL version provided: " << effectiveVersion; + JLOG(j.trace()) << "Invalid VL version provided: " << effectiveVersion; value = Json::nullValue; } @@ -366,9 +327,7 @@ ValidatorList::buildFileData( } void -ValidatorList::cacheValidatorFile( - ValidatorList::lock_guard const& lock, - PublicKey const& pubKey) const +ValidatorList::cacheValidatorFile(ValidatorList::lock_guard const& lock, PublicKey const& pubKey) const { if (dataPath_.empty()) return; @@ -377,8 +336,7 @@ ValidatorList::cacheValidatorFile( boost::system::error_code ec; - Json::Value value = - buildFileData(strHex(pubKey), publisherLists_.at(pubKey), j_); + Json::Value value = buildFileData(strHex(pubKey), publisherLists_.at(pubKey), j_); // rippled should be the only process writing to this file, so // if it ever needs to be read, it is not expected to change externally, so // delay the refresh as long as possible: 24 hours. (See also @@ -390,8 +348,7 @@ ValidatorList::cacheValidatorFile( if (ec) { // Log and ignore any file I/O exceptions - JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value() - << ": " << ec.message(); + JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value() << ": " << ec.message(); } } @@ -403,8 +360,7 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) switch (version) { case 1: { - if (!body.isMember(jss::blob) || !body[jss::blob].isString() || - !body.isMember(jss::signature) || + if (!body.isMember(jss::blob) || !body[jss::blob].isString() || !body.isMember(jss::signature) || !body[jss::signature].isString() || // If the v2 field is present, the VL is malformed body.isMember(jss::blobs_v2)) @@ -412,9 +368,7 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) ValidatorBlobInfo& info = result.emplace_back(); info.blob = body[jss::blob].asString(); info.signature = body[jss::signature].asString(); - XRPL_ASSERT( - result.size() == 1, - "ripple::ValidatorList::parseBlobs : single element result"); + XRPL_ASSERT(result.size() == 1, "xrpl::ValidatorList::parseBlobs : single element result"); return result; } // Treat unknown versions as if they're the latest version. This @@ -423,8 +377,7 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) // validated elsewhere. case 2: default: { - if (!body.isMember(jss::blobs_v2) || - !body[jss::blobs_v2].isArray() || + if (!body.isMember(jss::blobs_v2) || !body[jss::blobs_v2].isArray() || body[jss::blobs_v2].size() > maxSupportedBlobs || // If any of the v1 fields are present, the VL is malformed body.isMember(jss::blob) || body.isMember(jss::signature)) @@ -433,10 +386,8 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) result.reserve(blobs.size()); for (auto const& blobInfo : blobs) { - if (!blobInfo.isObject() || - !blobInfo.isMember(jss::signature) || - !blobInfo[jss::signature].isString() || - !blobInfo.isMember(jss::blob) || + if (!blobInfo.isObject() || !blobInfo.isMember(jss::signature) || + !blobInfo[jss::signature].isString() || !blobInfo.isMember(jss::blob) || !blobInfo[jss::blob].isString()) return {}; ValidatorBlobInfo& info = result.emplace_back(); @@ -451,7 +402,7 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) } XRPL_ASSERT( result.size() == blobs.size(), - "ripple::ValidatorList::parseBlobs(version, Jason::Value) : " + "xrpl::ValidatorList::parseBlobs(version, Jason::Value) : " "result size matches"); return result; } @@ -485,7 +436,7 @@ ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body) } XRPL_ASSERT( result.size() == body.blobs_size(), - "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size " + "xrpl::ValidatorList::parseBlobs(TMValidatorList) : result size " "match"); return result; } @@ -508,7 +459,7 @@ splitMessage( { if (begin == 0 && end == 0) end = largeMsg.blobs_size(); - XRPL_ASSERT(begin < end, "ripple::splitMessage : valid inputs"); + XRPL_ASSERT(begin < end, "xrpl::splitMessage : valid inputs"); if (end <= begin) return 0; @@ -543,13 +494,9 @@ splitMessageParts( smallMsg.set_manifest(blob.manifest()); XRPL_ASSERT( - Message::totalSize(smallMsg) <= maximiumMessageSize, - "ripple::splitMessageParts : maximum message size"); + Message::totalSize(smallMsg) <= maximumMessageSize, "xrpl::splitMessageParts : maximum message size"); - messages.emplace_back( - std::make_shared(smallMsg, protocol::mtVALIDATORLIST), - sha512Half(smallMsg), - 1); + messages.emplace_back(std::make_shared(smallMsg, protocol::mtVALIDATOR_LIST), sha512Half(smallMsg), 1); return messages.back().numVLs; } else @@ -573,8 +520,7 @@ splitMessageParts( else { messages.emplace_back( - std::make_shared( - *smallMsg, protocol::mtVALIDATORLISTCOLLECTION), + std::make_shared(*smallMsg, protocol::mtVALIDATOR_LIST_COLLECTION), sha512Half(*smallMsg), smallMsg->blobs_size()); return messages.back().numVLs; @@ -594,11 +540,10 @@ buildValidatorListMessage( { XRPL_ASSERT( messages.empty(), - "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages " + "xrpl::buildValidatorListMessage(ValidatorBlobInfo) : empty messages " "input"); protocol::TMValidatorList msg; - auto const manifest = - currentBlob.manifest ? *currentBlob.manifest : rawManifest; + auto const manifest = currentBlob.manifest ? *currentBlob.manifest : rawManifest; auto const version = 1; msg.set_manifest(manifest); msg.set_blob(currentBlob.blob); @@ -607,13 +552,10 @@ buildValidatorListMessage( msg.set_version(version); XRPL_ASSERT( - Message::totalSize(msg) <= maximiumMessageSize, - "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum " + Message::totalSize(msg) <= maximumMessageSize, + "xrpl::buildValidatorListMessage(ValidatorBlobInfo) : maximum " "message size"); - messages.emplace_back( - std::make_shared(msg, protocol::mtVALIDATORLIST), - sha512Half(msg), - 1); + messages.emplace_back(std::make_shared(msg, protocol::mtVALIDATOR_LIST), sha512Half(msg), 1); return 1; } @@ -630,7 +572,7 @@ buildValidatorListMessage( { XRPL_ASSERT( messages.empty(), - "ripple::buildValidatorListMessage(std::map) : empty messages input"); protocol::TMValidatorListCollection msg; auto const version = rawVersion < 2 ? 2 : rawVersion; @@ -649,7 +591,7 @@ buildValidatorListMessage( } XRPL_ASSERT( msg.blobs_size() > 0, - "ripple::buildValidatorListMessage(std::map) : minimum message blobs"); if (Message::totalSize(msg) > maxSize) { @@ -659,9 +601,7 @@ buildValidatorListMessage( else { messages.emplace_back( - std::make_shared(msg, protocol::mtVALIDATORLISTCOLLECTION), - sha512Half(msg), - msg.blobs_size()); + std::make_shared(msg, protocol::mtVALIDATOR_LIST_COLLECTION), sha512Half(msg), msg.blobs_size()); return messages.back().numVLs; } } @@ -677,32 +617,22 @@ ValidatorList::buildValidatorListMessages( std::string const& rawManifest, std::map const& blobInfos, std::vector& messages, - std::size_t maxSize /*= maximiumMessageSize*/) + std::size_t maxSize /*= maximumMessageSize*/) { XRPL_ASSERT( !blobInfos.empty(), - "ripple::ValidatorList::buildValidatorListMessages : empty messages " + "xrpl::ValidatorList::buildValidatorListMessages : empty messages " "input"); auto const& [currentSeq, currentBlob] = *blobInfos.begin(); - auto numVLs = std::accumulate( - messages.begin(), - messages.end(), - 0, - [](std::size_t total, MessageWithHash const& m) { - return total + m.numVLs; - }); + auto numVLs = std::accumulate(messages.begin(), messages.end(), 0, [](std::size_t total, MessageWithHash const& m) { + return total + m.numVLs; + }); if (messageVersion == 2 && peerSequence < maxSequence) { // Version 2 if (messages.empty()) { - numVLs = buildValidatorListMessage( - messages, - peerSequence, - rawVersion, - rawManifest, - blobInfos, - maxSize); + numVLs = buildValidatorListMessage(messages, peerSequence, rawVersion, rawManifest, blobInfos, maxSize); if (messages.empty()) // No message was generated. Create an empty placeholder so we // dont' repeat the work later. @@ -718,11 +648,7 @@ ValidatorList::buildValidatorListMessages( if (messages.empty()) { numVLs = buildValidatorListMessage( - messages, - rawVersion, - currentBlob.manifest ? *currentBlob.manifest : rawManifest, - currentBlob, - maxSize); + messages, rawVersion, currentBlob.manifest ? *currentBlob.manifest : rawManifest, currentBlob, maxSize); if (messages.empty()) // No message was generated. Create an empty placeholder so we // dont' repeat the work later. @@ -749,25 +675,18 @@ ValidatorList::sendValidatorList( HashRouter& hashRouter, beast::Journal j) { - std::size_t const messageVersion = - peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2 - : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1 - : 0; + std::size_t const messageVersion = peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2 + : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1 + : 0; if (!messageVersion) return; auto const [newPeerSequence, numVLs] = buildValidatorListMessages( - messageVersion, - peerSequence, - maxSequence, - rawVersion, - rawManifest, - blobInfos, - messages); + messageVersion, peerSequence, maxSequence, rawVersion, rawManifest, blobInfos, messages); if (newPeerSequence) { XRPL_ASSERT( !messages.empty(), - "ripple::ValidatorList::sendValidatorList : non-empty messages " + "xrpl::ValidatorList::sendValidatorList : non-empty messages " "input"); // Don't send it next time. peer.setPublisherListSequence(publisherKey, newPeerSequence); @@ -784,28 +703,21 @@ ValidatorList::sendValidatorList( } // The only way sent wil be false is if the messages was too big, and // thus there will only be one entry without a message - XRPL_ASSERT( - sent || messages.size() == 1, - "ripple::ValidatorList::sendValidatorList : sent or one message"); + XRPL_ASSERT(sent || messages.size() == 1, "xrpl::ValidatorList::sendValidatorList : sent or one message"); if (sent) { if (messageVersion > 1) - JLOG(j.debug()) - << "Sent " << messages.size() - << " validator list collection(s) containing " << numVLs - << " validator list(s) for " << strHex(publisherKey) - << " with sequence range " << peerSequence << ", " - << newPeerSequence << " to " << peer.fingerprint(); + JLOG(j.debug()) << "Sent " << messages.size() << " validator list collection(s) containing " << numVLs + << " validator list(s) for " << strHex(publisherKey) << " with sequence range " + << peerSequence << ", " << newPeerSequence << " to " << peer.fingerprint(); else { XRPL_ASSERT( numVLs == 1, - "ripple::ValidatorList::sendValidatorList : one validator " + "xrpl::ValidatorList::sendValidatorList : one validator " "list"); - JLOG(j.debug()) - << "Sent validator list for " << strHex(publisherKey) - << " with sequence " << newPeerSequence << " to " - << peer.fingerprint(); + JLOG(j.debug()) << "Sent validator list for " << strHex(publisherKey) << " with sequence " + << newPeerSequence << " to " << peer.fingerprint(); } } } @@ -826,16 +738,7 @@ ValidatorList::sendValidatorList( { std::vector messages; sendValidatorList( - peer, - peerSequence, - publisherKey, - maxSequence, - rawVersion, - rawManifest, - blobInfos, - messages, - hashRouter, - j); + peer, peerSequence, publisherKey, maxSequence, rawVersion, rawManifest, blobInfos, messages, hashRouter, j); } // static @@ -846,8 +749,7 @@ ValidatorList::buildBlobInfos( { auto const& current = lists.current; auto const& remaining = lists.remaining; - blobInfos[current.sequence] = { - current.rawBlob, current.rawSignature, current.rawManifest}; + blobInfos[current.sequence] = {current.rawBlob, current.rawSignature, current.rawManifest}; for (auto const& [sequence, vl] : remaining) { blobInfos[sequence] = {vl.rawBlob, vl.rawSignature, vl.rawManifest}; @@ -856,8 +758,7 @@ ValidatorList::buildBlobInfos( // static std::map -ValidatorList::buildBlobInfos( - ValidatorList::PublisherListCollection const& lists) +ValidatorList::buildBlobInfos(ValidatorList::PublisherListCollection const& lists) { std::map result; buildBlobInfos(result, lists); @@ -889,30 +790,26 @@ ValidatorList::broadcastBlobs( // This will hold v2 messages indexed by the peer's // `publisherListSequence`. For each `publisherListSequence`, we'll // only send the VLs with higher sequences. - std::map> - messages2; + std::map> messages2; // If any peers are found that are worth considering, this list will // be built to hold info for all of the valid VLs. std::map blobInfos; XRPL_ASSERT( - lists.current.sequence == maxSequence || - lists.remaining.count(maxSequence) == 1, - "ripple::ValidatorList::broadcastBlobs : valid sequence"); + lists.current.sequence == maxSequence || lists.remaining.count(maxSequence) == 1, + "xrpl::ValidatorList::broadcastBlobs : valid sequence"); // Can't use overlay.foreach here because we need to modify // the peer, and foreach provides a const& for (auto& peer : overlay.getActivePeers()) { if (toSkip->count(peer->id()) == 0) { - auto const peerSequence = - peer->publisherListSequence(publisherKey).value_or(0); + auto const peerSequence = peer->publisherListSequence(publisherKey).value_or(0); if (peerSequence < maxSequence) { if (blobInfos.empty()) buildBlobInfos(blobInfos, lists); - auto const v2 = peer->supportsFeature( - ProtocolFeature::ValidatorList2Propagation); + auto const v2 = peer->supportsFeature(ProtocolFeature::ValidatorList2Propagation); sendValidatorList( *peer, peerSequence, @@ -944,8 +841,7 @@ ValidatorList::applyListsAndBroadcast( HashRouter& hashRouter, NetworkOPs& networkOPs) { - auto const result = - applyLists(manifest, version, blobs, std::move(siteUri), hash); + auto const result = applyLists(manifest, version, blobs, std::move(siteUri), hash); auto const disposition = result.bestDisposition(); if (disposition == ListDisposition::accepted) @@ -972,20 +868,12 @@ ValidatorList::applyListsAndBroadcast( // this function is only called for PublicKeys which are not specified // in the config file (Note: Keys specified in the local config file are // stored in ValidatorList::localPublisherList data member). - if (broadcast && result.status <= PublisherStatus::expired && - result.publisherKey && + if (broadcast && result.status <= PublisherStatus::expired && result.publisherKey && publisherLists_[*result.publisherKey].maxSequence) { auto const& pubCollection = publisherLists_[*result.publisherKey]; - broadcastBlobs( - *result.publisherKey, - pubCollection, - *pubCollection.maxSequence, - hash, - overlay, - hashRouter, - j_); + broadcastBlobs(*result.publisherKey, pubCollection, *pubCollection.maxSequence, hash, overlay, hashRouter, j_); } return result; @@ -999,10 +887,7 @@ ValidatorList::applyLists( std::string siteUri, std::optional const& hash /* = {} */) { - if (std::count( - std::begin(supportedListVersions), - std::end(supportedListVersions), - version) != 1) + if (std::count(std::begin(supportedListVersions), std::end(supportedListVersions), version) != 1) return PublisherListStats{ListDisposition::unsupported_version}; std::lock_guard lock{mutex_}; @@ -1010,19 +895,11 @@ ValidatorList::applyLists( PublisherListStats result; for (auto const& blobInfo : blobs) { - auto stats = applyList( - manifest, - blobInfo.manifest, - blobInfo.blob, - blobInfo.signature, - version, - siteUri, - hash, - lock); + auto stats = + applyList(manifest, blobInfo.manifest, blobInfo.blob, blobInfo.signature, version, siteUri, hash, lock); if (stats.bestDisposition() < result.bestDisposition() || - (stats.bestDisposition() == result.bestDisposition() && - stats.sequence > result.sequence)) + (stats.bestDisposition() == result.bestDisposition() && stats.sequence > result.sequence)) { stats.mergeDispositions(result); result = std::move(stats); @@ -1044,10 +921,9 @@ ValidatorList::applyLists( auto next = std::next(iter); XRPL_ASSERT( next == remaining.end() || next->first > iter->first, - "ripple::ValidatorList::applyLists : next is valid"); + "xrpl::ValidatorList::applyLists : next is valid"); if (iter->first <= current.sequence || - (next != remaining.end() && - next->second.validFrom <= iter->second.validFrom)) + (next != remaining.end() && next->second.validFrom <= iter->second.validFrom)) { iter = remaining.erase(iter); } @@ -1081,16 +957,13 @@ ValidatorList::updatePublisherList( auto iOld = oldList.begin(); while (iNew != publisherList.end() || iOld != oldList.end()) { - if (iOld == oldList.end() || - (iNew != publisherList.end() && *iNew < *iOld)) + if (iOld == oldList.end() || (iNew != publisherList.end() && *iNew < *iOld)) { // Increment list count for added keys ++keyListings_[*iNew]; ++iNew; } - else if ( - iNew == publisherList.end() || - (iOld != oldList.end() && *iOld < *iNew)) + else if (iNew == publisherList.end() || (iOld != oldList.end() && *iOld < *iNew)) { // Decrement list count for removed keys if (keyListings_[*iOld] <= 1) @@ -1117,16 +990,13 @@ ValidatorList::updatePublisherList( if (!m || !keyListings_.count(m->masterKey)) { - JLOG(j_.warn()) << "List for " << strHex(pubKey) - << " contained untrusted validator manifest"; + JLOG(j_.warn()) << "List for " << strHex(pubKey) << " contained untrusted validator manifest"; continue; } - if (auto const r = validatorManifests_.applyManifest(std::move(*m)); - r == ManifestDisposition::invalid) + if (auto const r = validatorManifests_.applyManifest(std::move(*m)); r == ManifestDisposition::invalid) { - JLOG(j_.warn()) << "List for " << strHex(pubKey) - << " contained invalid validator manifest"; + JLOG(j_.warn()) << "List for " << strHex(pubKey) << " contained invalid validator manifest"; } } } @@ -1153,13 +1023,11 @@ ValidatorList::applyList( return PublisherListStats{ListDisposition::invalid}; } - auto [result, pubKeyOpt] = - verify(lock, list, std::move(*m), blob, signature); + auto [result, pubKeyOpt] = verify(lock, list, std::move(*m), blob, signature); if (!pubKeyOpt) { - JLOG(j_.warn()) - << "UNL manifest is signed with an unrecognized master public key"; + JLOG(j_.warn()) << "UNL manifest is signed with an unrecognized master public key"; return PublisherListStats{result}; } @@ -1170,8 +1038,7 @@ ValidatorList::applyList( // we can only arrive here if the key used by the manifest matched one // of the loaded keys // LCOV_EXCL_START - UNREACHABLE( - "ripple::ValidatorList::applyList : invalid public key type"); + UNREACHABLE("xrpl::ValidatorList::applyList : invalid public key type"); return PublisherListStats{result}; // LCOV_EXCL_STOP } @@ -1183,16 +1050,11 @@ ValidatorList::applyList( { auto const& pubCollection = publisherLists_[pubKey]; if (pubCollection.maxSequence && - (result == ListDisposition::same_sequence || - result == ListDisposition::known_sequence)) + (result == ListDisposition::same_sequence || result == ListDisposition::known_sequence)) { // We've seen something valid list for this publisher // already, so return what we know about it. - return PublisherListStats{ - result, - pubKey, - pubCollection.status, - *pubCollection.maxSequence}; + return PublisherListStats{result, pubKey, pubCollection.status, *pubCollection.maxSequence}; } } return PublisherListStats{result}; @@ -1201,14 +1063,11 @@ ValidatorList::applyList( // Update publisher's list auto& pubCollection = publisherLists_[pubKey]; auto const sequence = list[jss::sequence].asUInt(); - auto const accepted = - (result == ListDisposition::accepted || - result == ListDisposition::expired); + auto const accepted = (result == ListDisposition::accepted || result == ListDisposition::expired); if (accepted) - pubCollection.status = result == ListDisposition::accepted - ? PublisherStatus::available - : PublisherStatus::expired; + pubCollection.status = + result == ListDisposition::accepted ? PublisherStatus::available : PublisherStatus::expired; pubCollection.rawManifest = globalManifest; if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence) pubCollection.maxSequence = sequence; @@ -1230,19 +1089,15 @@ ValidatorList::applyList( // Remove the entry in "remaining" pubCollection.remaining.erase(sequence); // Done - XRPL_ASSERT( - publisher.sequence == sequence, - "ripple::ValidatorList::applyList : publisher sequence match"); + XRPL_ASSERT(publisher.sequence == sequence, "xrpl::ValidatorList::applyList : publisher sequence match"); } else { - auto& publisher = accepted ? pubCollection.current - : pubCollection.remaining[sequence]; + auto& publisher = accepted ? pubCollection.current : pubCollection.remaining[sequence]; publisher.sequence = sequence; - publisher.validFrom = TimeKeeper::time_point{TimeKeeper::duration{ - list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}}; - publisher.validUntil = TimeKeeper::time_point{ - TimeKeeper::duration{list[jss::expiration].asUInt()}}; + publisher.validFrom = TimeKeeper::time_point{ + TimeKeeper::duration{list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}}; + publisher.validUntil = TimeKeeper::time_point{TimeKeeper::duration{list[jss::expiration].asUInt()}}; publisher.siteUri = std::move(siteUri); publisher.rawBlob = blob; publisher.rawSignature = signature; @@ -1263,23 +1118,18 @@ ValidatorList::applyList( if (val.isObject() && val.isMember(jss::validation_public_key) && val[jss::validation_public_key].isString()) { - std::optional const ret = - strUnHex(val[jss::validation_public_key].asString()); + std::optional const ret = strUnHex(val[jss::validation_public_key].asString()); if (!ret || !publicKeyType(makeSlice(*ret))) { - JLOG(j_.error()) - << "Invalid node identity: " - << val[jss::validation_public_key].asString(); + JLOG(j_.error()) << "Invalid node identity: " << val[jss::validation_public_key].asString(); } else { - publisherList.push_back( - PublicKey(Slice{ret->data(), ret->size()})); + publisherList.push_back(PublicKey(Slice{ret->data(), ret->size()})); } - if (val.isMember(jss::manifest) && - val[jss::manifest].isString()) + if (val.isMember(jss::manifest) && val[jss::manifest].isString()) manifests.push_back(val[jss::manifest].asString()); } } @@ -1297,8 +1147,7 @@ ValidatorList::applyList( pubCollection.rawVersion = std::max(pubCollection.rawVersion, 2u); } - PublisherListStats const applyResult{ - result, pubKey, pubCollection.status, *pubCollection.maxSequence}; + PublisherListStats const applyResult{result, pubKey, pubCollection.status, *pubCollection.maxSequence}; if (accepted) { @@ -1393,23 +1242,21 @@ ValidatorList::verify( auto const sig = strUnHex(signature); auto const data = base64_decode(blob); - if (!sig || !ripple::verify(*signingKey, makeSlice(data), makeSlice(*sig))) + if (!sig || !xrpl::verify(*signingKey, makeSlice(data), makeSlice(*sig))) return {ListDisposition::invalid, masterPubKey}; Json::Reader r; if (!r.parse(data, list)) return {ListDisposition::invalid, masterPubKey}; - if (list.isMember(jss::sequence) && list[jss::sequence].isInt() && - list.isMember(jss::expiration) && list[jss::expiration].isInt() && - (!list.isMember(jss::effective) || list[jss::effective].isInt()) && + if (list.isMember(jss::sequence) && list[jss::sequence].isInt() && list.isMember(jss::expiration) && + list[jss::expiration].isInt() && (!list.isMember(jss::effective) || list[jss::effective].isInt()) && list.isMember(jss::validators) && list[jss::validators].isArray()) { auto const sequence = list[jss::sequence].asUInt(); - auto const validFrom = TimeKeeper::time_point{TimeKeeper::duration{ - list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}}; - auto const validUntil = TimeKeeper::time_point{ - TimeKeeper::duration{list[jss::expiration].asUInt()}}; + auto const validFrom = TimeKeeper::time_point{ + TimeKeeper::duration{list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}}; + auto const validUntil = TimeKeeper::time_point{TimeKeeper::duration{list[jss::expiration].asUInt()}}; auto const now = timeKeeper_.now(); auto const& listCollection = publisherLists_[masterPubKey]; if (validUntil <= validFrom) @@ -1431,12 +1278,9 @@ ValidatorList::verify( // order. This may result in some duplicated processing, but // prevents the risk of missing valid data. Else return // known_sequence - return !listCollection.maxSequence || - sequence > *listCollection.maxSequence || + return !listCollection.maxSequence || sequence > *listCollection.maxSequence || (listCollection.remaining.count(sequence) == 0 && - validFrom < listCollection.remaining - .at(*listCollection.maxSequence) - .validFrom) + validFrom < listCollection.remaining.at(*listCollection.maxSequence).validFrom) ? std::make_pair(ListDisposition::pending, masterPubKey) : std::make_pair(ListDisposition::known_sequence, masterPubKey); } @@ -1458,9 +1302,7 @@ ValidatorList::listed(PublicKey const& identity) const } bool -ValidatorList::trusted( - ValidatorList::shared_lock const&, - PublicKey const& identity) const +ValidatorList::trusted(ValidatorList::shared_lock const&, PublicKey const& identity) const { auto const pubKey = validatorManifests_.getMasterKey(identity); return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end(); @@ -1485,9 +1327,7 @@ ValidatorList::getListedKey(PublicKey const& identity) const } std::optional -ValidatorList::getTrustedKey( - ValidatorList::shared_lock const&, - PublicKey const& identity) const +ValidatorList::getTrustedKey(ValidatorList::shared_lock const&, PublicKey const& identity) const { auto const pubKey = validatorManifests_.getMasterKey(identity); if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end()) @@ -1525,15 +1365,13 @@ ValidatorList::removePublisherList( PublisherStatus reason) { XRPL_ASSERT( - reason != PublisherStatus::available && - reason != PublisherStatus::unavailable, - "ripple::ValidatorList::removePublisherList : valid reason input"); + reason != PublisherStatus::available && reason != PublisherStatus::unavailable, + "xrpl::ValidatorList::removePublisherList : valid reason input"); auto const iList = publisherLists_.find(publisherKey); if (iList == publisherLists_.end()) return false; - JLOG(j_.debug()) << "Removing validator list for publisher " - << strHex(publisherKey); + JLOG(j_.debug()) << "Removing validator list for publisher " << strHex(publisherKey); for (auto const& val : iList->second.current.list) { @@ -1663,29 +1501,24 @@ ValidatorList::getJson() const } // Validator keys listed in the local config file - Json::Value& jLocalStaticKeys = - (res[jss::local_static_keys] = Json::arrayValue); + Json::Value& jLocalStaticKeys = (res[jss::local_static_keys] = Json::arrayValue); for (auto const& key : localPublisherList.list) jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key)); // Publisher lists - Json::Value& jPublisherLists = - (res[jss::publisher_lists] = Json::arrayValue); + Json::Value& jPublisherLists = (res[jss::publisher_lists] = Json::arrayValue); for (auto const& [publicKey, pubCollection] : publisherLists_) { Json::Value& curr = jPublisherLists.append(Json::objectValue); curr[jss::pubkey_publisher] = strHex(publicKey); - curr[jss::available] = - pubCollection.status == PublisherStatus::available; + curr[jss::available] = pubCollection.status == PublisherStatus::available; - auto appendList = [](PublisherList const& publisherList, - Json::Value& target) { + auto appendList = [](PublisherList const& publisherList, Json::Value& target) { target[jss::uri] = publisherList.siteUri; if (publisherList.validUntil != TimeKeeper::time_point{}) { - target[jss::seq] = - static_cast(publisherList.sequence); + target[jss::seq] = static_cast(publisherList.sequence); target[jss::expiration] = to_string(publisherList.validUntil); } if (publisherList.validFrom != TimeKeeper::time_point{}) @@ -1715,16 +1548,14 @@ ValidatorList::getJson() const appendList(future, r); // Race conditions can happen, so make this check "fuzzy" XRPL_ASSERT( - future.validFrom > timeKeeper_.now() + 600s, - "ripple::ValidatorList::getJson : minimum valid from"); + future.validFrom > timeKeeper_.now() + 600s, "xrpl::ValidatorList::getJson : minimum valid from"); } if (remaining.size()) curr[jss::remaining] = std::move(remaining); } // Trusted validator keys - Json::Value& jValidatorKeys = - (res[jss::trusted_validator_keys] = Json::arrayValue); + Json::Value& jValidatorKeys = (res[jss::trusted_validator_keys] = Json::arrayValue); for (auto const& k : trustedMasterKeys_) { jValidatorKeys.append(toBase58(TokenType::NodePublic, k)); @@ -1732,8 +1563,7 @@ ValidatorList::getJson() const // signing keys Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue); - validatorManifests_.for_each_manifest([&jSigningKeys, - this](Manifest const& manifest) { + validatorManifests_.for_each_manifest([&jSigningKeys, this](Manifest const& manifest) { auto it = keyListings_.find(manifest.masterKey); if (it != keyListings_.end() && manifest.signingKey) { @@ -1756,8 +1586,7 @@ ValidatorList::getJson() const } void -ValidatorList::for_each_listed( - std::function func) const +ValidatorList::for_each_listed(std::function func) const { std::shared_lock read_lock{mutex_}; @@ -1766,14 +1595,13 @@ ValidatorList::for_each_listed( } void -ValidatorList::for_each_available( - std::function const& blobInfos, - PublicKey const& pubKey, - std::size_t maxSequence, - uint256 const& hash)> func) const +ValidatorList::for_each_available(std::function const& blobInfos, + PublicKey const& pubKey, + std::size_t maxSequence, + uint256 const& hash)> func) const { std::shared_lock read_lock{mutex_}; @@ -1781,9 +1609,7 @@ ValidatorList::for_each_available( { if (plCollection.status != PublisherStatus::available) continue; - XRPL_ASSERT( - plCollection.maxSequence != 0, - "ripple::ValidatorList::for_each_available : nonzero maxSequence"); + XRPL_ASSERT(plCollection.maxSequence != 0, "xrpl::ValidatorList::for_each_available : nonzero maxSequence"); func( plCollection.rawManifest, plCollection.rawVersion, @@ -1795,9 +1621,7 @@ ValidatorList::for_each_available( } std::optional -ValidatorList::getAvailable( - std::string_view pubKey, - std::optional forceVersion /* = {} */) +ValidatorList::getAvailable(std::string_view pubKey, std::optional forceVersion /* = {} */) { std::shared_lock read_lock{mutex_}; @@ -1805,8 +1629,7 @@ ValidatorList::getAvailable( if (!keyBlob || !publicKeyType(makeSlice(*keyBlob))) { - JLOG(j_.warn()) << "Invalid requested validator list publisher key: " - << pubKey; + JLOG(j_.warn()) << "Invalid requested validator list publisher key: " << pubKey; return {}; } @@ -1814,27 +1637,21 @@ ValidatorList::getAvailable( auto const iter = publisherLists_.find(id); - if (iter == publisherLists_.end() || - iter->second.status != PublisherStatus::available) + if (iter == publisherLists_.end() || iter->second.status != PublisherStatus::available) return {}; - Json::Value value = - buildFileData(std::string{pubKey}, iter->second, forceVersion, j_); + Json::Value value = buildFileData(std::string{pubKey}, iter->second, forceVersion, j_); return value; } std::size_t -ValidatorList::calculateQuorum( - std::size_t unlSize, - std::size_t effectiveUnlSize, - std::size_t seenSize) +ValidatorList::calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize) { // Use quorum if specified via command line. if (minimumQuorum_ > 0) { - JLOG(j_.warn()) << "Using potentially unsafe quorum of " - << *minimumQuorum_ + JLOG(j_.warn()) << "Using potentially unsafe quorum of " << *minimumQuorum_ << " as specified on the command line"; return *minimumQuorum_; } @@ -1871,9 +1688,7 @@ ValidatorList::calculateQuorum( auto const errorThreshold = std::min( listThreshold_, // publisherLists_.size() - listThreshold_ + 1); - XRPL_ASSERT( - errorThreshold > 0, - "ripple::ValidatorList::calculateQuorum : nonzero error threshold"); + XRPL_ASSERT(errorThreshold > 0, "xrpl::ValidatorList::calculateQuorum : nonzero error threshold"); if (unavailable >= errorThreshold) return std::numeric_limits::max(); } @@ -1912,8 +1727,7 @@ ValidatorList::calculateQuorum( // Note that the negative UNL protocol introduced the // AbsoluteMinimumQuorum which is 60% of the original UNL size. The // effective quorum should not be lower than it. - return static_cast(std::max( - std::ceil(effectiveUnlSize * 0.8f), std::ceil(unlSize * 0.6f))); + return static_cast(std::max(std::ceil(effectiveUnlSize * 0.8f), std::ceil(unlSize * 0.6f))); } TrustChanges @@ -1944,35 +1758,30 @@ ValidatorList::updateTrusted( if (iter != remaining.end() && iter->second.validFrom <= closeTime) { // Find the LAST candidate that is ready to go live. - for (auto next = std::next(iter); next != remaining.end() && - next->second.validFrom <= closeTime; + for (auto next = std::next(iter); next != remaining.end() && next->second.validFrom <= closeTime; ++iter, ++next) { XRPL_ASSERT( std::next(iter) == next, - "ripple::ValidatorList::updateTrusted : sequential " + "xrpl::ValidatorList::updateTrusted : sequential " "remaining"); } XRPL_ASSERT( iter != remaining.end(), - "ripple::ValidatorList::updateTrusted : non-end of " + "xrpl::ValidatorList::updateTrusted : non-end of " "remaining"); // Rotate the pending list in to current auto sequence = iter->first; auto& candidate = iter->second; auto& current = collection.current; - XRPL_ASSERT( - candidate.validFrom <= closeTime, - "ripple::ValidatorList::updateTrusted : maximum time"); + XRPL_ASSERT(candidate.validFrom <= closeTime, "xrpl::ValidatorList::updateTrusted : maximum time"); auto const oldList = current.list; current = std::move(candidate); if (collection.status != PublisherStatus::available) collection.status = PublisherStatus::available; - XRPL_ASSERT( - current.sequence == sequence, - "ripple::ValidatorList::updateTrusted : sequence match"); + XRPL_ASSERT(current.sequence == sequence, "xrpl::ValidatorList::updateTrusted : sequence match"); // If the list is expired, remove the validators so they don't // get processed in. The expiration check below will do the rest // of the work @@ -1986,14 +1795,7 @@ ValidatorList::updateTrusted( // unknown (unlikely). Those that do understand v2 should // already have this list and are in the process of // switching themselves. - broadcastBlobs( - pubKey, - collection, - sequence, - current.hash, - overlay, - hashRouter, - j_); + broadcastBlobs(pubKey, collection, sequence, current.hash, overlay, hashRouter, j_); // Erase any candidates that we skipped over, plus this one remaining.erase(firstIter, std::next(iter)); @@ -2002,8 +1804,7 @@ ValidatorList::updateTrusted( // Remove if expired // ValidatorLists specified in the local config file never expire. // Hence, the below steps are not relevant for localPublisherList - if (collection.status == PublisherStatus::available && - collection.current.validUntil <= closeTime) + if (collection.status == PublisherStatus::available && collection.current.validUntil <= closeTime) { removePublisherList(lock, pubKey, PublisherStatus::expired); ops.setUNLBlocked(); @@ -2029,17 +1830,14 @@ ValidatorList::updateTrusted( } else { - XRPL_ASSERT( - kit->second >= listThreshold_, - "ripple::ValidatorList::updateTrusted : count meets threshold"); + XRPL_ASSERT(kit->second >= listThreshold_, "xrpl::ValidatorList::updateTrusted : count meets threshold"); ++it; } } for (auto const& val : keyListings_) { - if (val.second >= listThreshold_ && - !validatorManifests_.revoked(val.first) && + if (val.second >= listThreshold_ && !validatorManifests_.revoked(val.first) && trustedMasterKeys_.emplace(val.first).second) trustChanges.added.insert(calcNodeID(val.first)); } @@ -2054,18 +1852,14 @@ ValidatorList::updateTrusted( // manifests must contain a valid signingKey for (auto const& k : trustedMasterKeys_) { - std::optional const signingKey = - validatorManifests_.getSigningKey(k); - XRPL_ASSERT( - signingKey, - "ripple::ValidatorList::updateTrusted : found signing key"); + std::optional const signingKey = validatorManifests_.getSigningKey(k); + XRPL_ASSERT(signingKey, "xrpl::ValidatorList::updateTrusted : found signing key"); trustedSigningKeys_.insert(*signingKey); } } - JLOG(j_.debug()) - << trustedMasterKeys_.size() << " of " << keyListings_.size() - << " listed validators eligible for inclusion in the trusted set"; + JLOG(j_.debug()) << trustedMasterKeys_.size() << " of " << keyListings_.size() + << " listed validators eligible for inclusion in the trusted set"; auto const unlSize = trustedMasterKeys_.size(); auto effectiveUnlSize = unlSize; @@ -2090,20 +1884,16 @@ ValidatorList::updateTrusted( } quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize); - JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of " - << unlSize << " trusted validators (" - << trustChanges.added.size() << " added, " - << trustChanges.removed.size() << " removed)"; + JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of " << unlSize << " trusted validators (" + << trustChanges.added.size() << " added, " << trustChanges.removed.size() << " removed)"; if (unlSize < quorum_) { - JLOG(j_.warn()) << "New quorum of " << quorum_ - << " exceeds the number of trusted validators (" - << unlSize << ")"; + JLOG(j_.warn()) << "New quorum of " << quorum_ << " exceeds the number of trusted validators (" << unlSize + << ")"; } - if ((publisherLists_.size() || localPublisherList.list.size()) && - unlSize == 0) + if ((publisherLists_.size() || localPublisherList.list.size()) && unlSize == 0) { // No validators. Lock down. ops.setUNLBlocked(); @@ -2141,8 +1931,7 @@ ValidatorList::setNegativeUNL(hash_set const& negUnl) } std::vector> -ValidatorList::negativeUNLFilter( - std::vector>&& validations) const +ValidatorList::negativeUNLFilter(std::vector>&& validations) const { // Remove validations that are from validators on the negative UNL. auto ret = std::move(validations); @@ -2155,9 +1944,7 @@ ValidatorList::negativeUNLFilter( ret.begin(), ret.end(), [&](auto const& v) -> bool { - if (auto const masterKey = - getTrustedKey(read_lock, v->getSignerPublic()); - masterKey) + if (auto const masterKey = getTrustedKey(read_lock, v->getSignerPublic()); masterKey) { return negativeUNL_.count(*masterKey); } @@ -2172,4 +1959,4 @@ ValidatorList::negativeUNLFilter( return ret; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp index e235ff3e66..7d440028cf 100644 --- a/src/xrpld/app/misc/detail/ValidatorSite.cpp +++ b/src/xrpld/app/misc/detail/ValidatorSite.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -29,7 +10,7 @@ #include -namespace ripple { +namespace xrpl { auto constexpr default_refresh_interval = std::chrono::minutes{5}; auto constexpr error_retry_interval = std::chrono::seconds{30}; @@ -85,10 +66,7 @@ ValidatorSite::Site::Site(std::string uri) { } -ValidatorSite::ValidatorSite( - Application& app, - std::optional j, - std::chrono::seconds timeout) +ValidatorSite::ValidatorSite(Application& app, std::optional j, std::chrono::seconds timeout) : app_{app} , j_{j ? *j : app_.logs().journal("ValidatorSite")} , timer_{app_.getIOContext()} @@ -134,9 +112,7 @@ ValidatorSite::load(std::vector const& siteURIs) } bool -ValidatorSite::load( - std::vector const& siteURIs, - std::lock_guard const& lock_sites) +ValidatorSite::load(std::vector const& siteURIs, std::lock_guard const& lock_sites) { // If no sites are provided, act as if a site failed to load. if (siteURIs.empty()) @@ -152,8 +128,7 @@ ValidatorSite::load( } catch (std::exception const& e) { - JLOG(j_.error()) - << "Invalid validator site uri: " << uri << ": " << e.what(); + JLOG(j_.error()) << "Invalid validator site uri: " << uri << ": " << e.what(); return false; } } @@ -206,14 +181,10 @@ ValidatorSite::stop() } void -ValidatorSite::setTimer( - std::lock_guard const& site_lock, - std::lock_guard const& state_lock) +ValidatorSite::setTimer(std::lock_guard const& site_lock, std::lock_guard const& state_lock) { auto next = std::min_element( - sites_.begin(), sites_.end(), [](Site const& a, Site const& b) { - return a.nextRefresh < b.nextRefresh; - }); + sites_.begin(), sites_.end(), [](Site const& a, Site const& b) { return a.nextRefresh < b.nextRefresh; }); if (next != sites_.end()) { @@ -221,9 +192,7 @@ ValidatorSite::setTimer( cv_.notify_all(); timer_.expires_at(next->nextRefresh); auto idx = std::distance(sites_.begin(), next); - timer_.async_wait([this, idx](boost::system::error_code const& ec) { - this->onTimer(idx, ec); - }); + timer_.async_wait([this, idx](boost::system::error_code const& ec) { this->onTimer(idx, ec); }); } } @@ -249,15 +218,12 @@ ValidatorSite::makeRequest( } }; auto onFetch = [this, siteIdx, timeoutCancel]( - error_code const& err, - endpoint_type const& endpoint, - detail::response_type&& resp) { + error_code const& err, endpoint_type const& endpoint, detail::response_type&& resp) { timeoutCancel(); onSiteFetch(err, endpoint, std::move(resp), siteIdx); }; - auto onFetchFile = [this, siteIdx, timeoutCancel]( - error_code const& err, std::string const& resp) { + auto onFetchFile = [this, siteIdx, timeoutCancel](error_code const& err, std::string const& resp) { timeoutCancel(); onTextFetch(err, resp, siteIdx); }; @@ -292,8 +258,7 @@ ValidatorSite::makeRequest( else { BOOST_ASSERT(resource->pUrl.scheme == "file"); - sp = std::make_shared( - resource->pUrl.path, app_.getIOContext(), onFetchFile); + sp = std::make_shared(resource->pUrl.path, app_.getIOContext(), onFetchFile); } sites_[siteIdx].lastRequestSuccessful = false; @@ -303,9 +268,7 @@ ValidatorSite::makeRequest( // than requestTimeout_ to complete std::lock_guard lock_state{state_mutex_}; timer_.expires_after(requestTimeout_); - timer_.async_wait([this, siteIdx](boost::system::error_code const& ec) { - this->onRequestTimeout(siteIdx, ec); - }); + timer_.async_wait([this, siteIdx](boost::system::error_code const& ec) { this->onRequestTimeout(siteIdx, ec); }); } void @@ -324,8 +287,7 @@ ValidatorSite::onRequestTimeout(std::size_t siteIdx, error_code const& ec) // first, which will leave activeResource empty. auto const& site = sites_[siteIdx]; if (site.activeResource) - JLOG(j_.warn()) << "Request for " << site.activeResource->uri - << " took too long"; + JLOG(j_.warn()) << "Request for " << site.activeResource->uri << " took too long"; else JLOG(j_.error()) << "Request took too long, but a response has " "already been processed"; @@ -351,8 +313,7 @@ ValidatorSite::onTimer(std::size_t siteIdx, error_code const& ec) try { std::lock_guard lock{sites_mutex_}; - sites_[siteIdx].nextRefresh = - clock_type::now() + sites_[siteIdx].refreshInterval; + sites_[siteIdx].nextRefresh = clock_type::now() + sites_[siteIdx].refreshInterval; sites_[siteIdx].redirCount = 0; // the WorkSSL client ctor can throw if SSL init fails makeRequest(sites_[siteIdx].startingResource, siteIdx, lock); @@ -361,10 +322,7 @@ ValidatorSite::onTimer(std::size_t siteIdx, error_code const& ec) { JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what(); onSiteFetch( - boost::system::error_code{-1, boost::system::generic_category()}, - {}, - detail::response_type{}, - siteIdx); + boost::system::error_code{-1, boost::system::generic_category()}, {}, detail::response_type{}, siteIdx); } } @@ -379,8 +337,7 @@ ValidatorSite::parseJsonResponse( Json::Value body; if (!r.parse(res.data(), body)) { - JLOG(j_.warn()) << "Unable to parse JSON response from " - << sites_[siteIdx].activeResource->uri; + JLOG(j_.warn()) << "Unable to parse JSON response from " << sites_[siteIdx].activeResource->uri; throw std::runtime_error{"bad json"}; } return body; @@ -388,9 +345,8 @@ ValidatorSite::parseJsonResponse( auto const [valid, version, blobs] = [&body]() { // Check the easy fields first - bool valid = body.isObject() && body.isMember(jss::manifest) && - body[jss::manifest].isString() && body.isMember(jss::version) && - body[jss::version].isInt(); + bool valid = body.isObject() && body.isMember(jss::manifest) && body[jss::manifest].isString() && + body.isMember(jss::version) && body[jss::version].isInt(); // Check the version-specific blob & signature fields std::uint32_t version; std::vector blobs; @@ -405,90 +361,62 @@ ValidatorSite::parseJsonResponse( if (!valid) { - JLOG(j_.warn()) << "Missing fields in JSON response from " - << sites_[siteIdx].activeResource->uri; + JLOG(j_.warn()) << "Missing fields in JSON response from " << sites_[siteIdx].activeResource->uri; throw std::runtime_error{"missing fields"}; } auto const manifest = body[jss::manifest].asString(); - XRPL_ASSERT( - version == body[jss::version].asUInt(), - "ripple::ValidatorSite::parseJsonResponse : version match"); + XRPL_ASSERT(version == body[jss::version].asUInt(), "xrpl::ValidatorSite::parseJsonResponse : version match"); auto const& uri = sites_[siteIdx].activeResource->uri; auto const hash = sha512Half(manifest, blobs, version); auto const applyResult = app_.validators().applyListsAndBroadcast( - manifest, - version, - blobs, - uri, - hash, - app_.overlay(), - app_.getHashRouter(), - app_.getOPs()); + manifest, version, blobs, uri, hash, app_.overlay(), app_.getHashRouter(), app_.getOPs()); - sites_[siteIdx].lastRefreshStatus.emplace( - Site::Status{clock_type::now(), applyResult.bestDisposition(), ""}); + sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{clock_type::now(), applyResult.bestDisposition(), ""}); for (auto const& [disp, count] : applyResult.dispositions) { switch (disp) { case ListDisposition::accepted: - JLOG(j_.debug()) << "Applied " << count - << " new validator list(s) from " << uri; + JLOG(j_.debug()) << "Applied " << count << " new validator list(s) from " << uri; break; case ListDisposition::expired: - JLOG(j_.debug()) << "Applied " << count - << " expired validator list(s) from " << uri; + JLOG(j_.debug()) << "Applied " << count << " expired validator list(s) from " << uri; break; case ListDisposition::same_sequence: - JLOG(j_.debug()) - << "Ignored " << count - << " validator list(s) with current sequence from " << uri; + JLOG(j_.debug()) << "Ignored " << count << " validator list(s) with current sequence from " << uri; break; case ListDisposition::pending: - JLOG(j_.debug()) << "Processed " << count - << " future validator list(s) from " << uri; + JLOG(j_.debug()) << "Processed " << count << " future validator list(s) from " << uri; break; case ListDisposition::known_sequence: - JLOG(j_.debug()) - << "Ignored " << count - << " validator list(s) with future known sequence from " - << uri; + JLOG(j_.debug()) << "Ignored " << count << " validator list(s) with future known sequence from " << uri; break; case ListDisposition::stale: - JLOG(j_.warn()) << "Ignored " << count - << "stale validator list(s) from " << uri; + JLOG(j_.warn()) << "Ignored " << count << "stale validator list(s) from " << uri; break; case ListDisposition::untrusted: - JLOG(j_.warn()) << "Ignored " << count - << " untrusted validator list(s) from " << uri; + JLOG(j_.warn()) << "Ignored " << count << " untrusted validator list(s) from " << uri; break; case ListDisposition::invalid: - JLOG(j_.warn()) << "Ignored " << count - << " invalid validator list(s) from " << uri; + JLOG(j_.warn()) << "Ignored " << count << " invalid validator list(s) from " << uri; break; case ListDisposition::unsupported_version: - JLOG(j_.warn()) - << "Ignored " << count - << " unsupported version validator list(s) from " << uri; + JLOG(j_.warn()) << "Ignored " << count << " unsupported version validator list(s) from " << uri; break; default: BOOST_ASSERT(false); } } - if (body.isMember(jss::refresh_interval) && - body[jss::refresh_interval].isNumeric()) + if (body.isMember(jss::refresh_interval) && body[jss::refresh_interval].isNumeric()) { using namespace std::chrono_literals; - std::chrono::minutes const refresh = std::clamp( - std::chrono::minutes{body[jss::refresh_interval].asUInt()}, - 1min, - std::chrono::minutes{24h}); + std::chrono::minutes const refresh = + std::clamp(std::chrono::minutes{body[jss::refresh_interval].asUInt()}, 1min, std::chrono::minutes{24h}); sites_[siteIdx].refreshInterval = refresh; - sites_[siteIdx].nextRefresh = - clock_type::now() + sites_[siteIdx].refreshInterval; + sites_[siteIdx].nextRefresh = clock_type::now() + sites_[siteIdx].refreshInterval; } } @@ -502,37 +430,30 @@ ValidatorSite::processRedirect( std::shared_ptr newLocation; if (res.find(field::location) == res.end() || res[field::location].empty()) { - JLOG(j_.warn()) << "Request for validator list at " - << sites_[siteIdx].activeResource->uri + JLOG(j_.warn()) << "Request for validator list at " << sites_[siteIdx].activeResource->uri << " returned a redirect with no Location."; throw std::runtime_error{"missing location"}; } if (sites_[siteIdx].redirCount == max_redirects) { - JLOG(j_.warn()) << "Exceeded max redirects for validator list at " - << sites_[siteIdx].loadedResource->uri; + JLOG(j_.warn()) << "Exceeded max redirects for validator list at " << sites_[siteIdx].loadedResource->uri; throw std::runtime_error{"max redirects"}; } - JLOG(j_.debug()) << "Got redirect for validator list from " - << sites_[siteIdx].activeResource->uri + JLOG(j_.debug()) << "Got redirect for validator list from " << sites_[siteIdx].activeResource->uri << " to new location " << res[field::location]; try { - newLocation = - std::make_shared(std::string(res[field::location])); + newLocation = std::make_shared(std::string(res[field::location])); ++sites_[siteIdx].redirCount; - if (newLocation->pUrl.scheme != "http" && - newLocation->pUrl.scheme != "https") - throw std::runtime_error( - "invalid scheme in redirect " + newLocation->pUrl.scheme); + if (newLocation->pUrl.scheme != "http" && newLocation->pUrl.scheme != "https") + throw std::runtime_error("invalid scheme in redirect " + newLocation->pUrl.scheme); } catch (std::exception const& ex) { - JLOG(j_.error()) << "Invalid redirect location: " - << res[field::location]; + JLOG(j_.error()) << "Invalid redirect location: " << res[field::location]; throw; } return newLocation; @@ -549,15 +470,12 @@ ValidatorSite::onSiteFetch( { if (endpoint != endpoint_type{}) sites_[siteIdx].lastRequestEndpoint = endpoint; - JLOG(j_.debug()) << "Got completion for " - << sites_[siteIdx].activeResource->uri << " " - << endpoint; + JLOG(j_.debug()) << "Got completion for " << sites_[siteIdx].activeResource->uri << " " << endpoint; auto onError = [&](std::string const& errMsg, bool retry) { - sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{ - clock_type::now(), ListDisposition::invalid, errMsg}); + sites_[siteIdx].lastRefreshStatus.emplace( + Site::Status{clock_type::now(), ListDisposition::invalid, errMsg}); if (retry) - sites_[siteIdx].nextRefresh = - clock_type::now() + error_retry_interval; + sites_[siteIdx].nextRefresh = clock_type::now() + error_retry_interval; // See if there's a copy saved locally from last time we // saw the list. @@ -565,10 +483,8 @@ ValidatorSite::onSiteFetch( }; if (ec) { - JLOG(j_.warn()) - << "Problem retrieving from " - << sites_[siteIdx].activeResource->uri << " " << endpoint << " " - << ec.value() << ":" << ec.message(); + JLOG(j_.warn()) << "Problem retrieving from " << sites_[siteIdx].activeResource->uri << " " << endpoint + << " " << ec.value() << ":" << ec.message(); onError("fetch error", true); } else @@ -586,15 +502,13 @@ ValidatorSite::onSiteFetch( case status::permanent_redirect: case status::found: case status::temporary_redirect: { - auto newLocation = - processRedirect(res, siteIdx, lock_sites); + auto newLocation = processRedirect(res, siteIdx, lock_sites); XRPL_ASSERT( newLocation, - "ripple::ValidatorSite::onSiteFetch : non-null " + "xrpl::ValidatorSite::onSiteFetch : non-null " "validator"); // for perm redirects, also update our starting URI - if (res.result() == status::moved_permanently || - res.result() == status::permanent_redirect) + if (res.result() == status::moved_permanently || res.result() == status::permanent_redirect) { sites_[siteIdx].startingResource = newLocation; } @@ -603,19 +517,15 @@ ValidatorSite::onSiteFetch( // state update/notify below } default: { - JLOG(j_.warn()) - << "Request for validator list at " - << sites_[siteIdx].activeResource->uri << " " - << endpoint - << " returned bad status: " << res.result_int(); + JLOG(j_.warn()) << "Request for validator list at " << sites_[siteIdx].activeResource->uri + << " " << endpoint << " returned bad status: " << res.result_int(); onError("bad result code", true); } } } catch (std::exception const& ex) { - JLOG(j_.error()) - << "Exception in " << __func__ << ": " << ex.what(); + JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what(); onError(ex.what(), false); } } @@ -630,10 +540,7 @@ ValidatorSite::onSiteFetch( } void -ValidatorSite::onTextFetch( - boost::system::error_code const& ec, - std::string const& res, - std::size_t siteIdx) +ValidatorSite::onTextFetch(boost::system::error_code const& ec, std::string const& res, std::size_t siteIdx) { std::lock_guard lock_sites{sites_mutex_}; { @@ -641,8 +548,7 @@ ValidatorSite::onTextFetch( { if (ec) { - JLOG(j_.warn()) << "Problem retrieving from " - << sites_[siteIdx].activeResource->uri << " " + JLOG(j_.warn()) << "Problem retrieving from " << sites_[siteIdx].activeResource->uri << " " << ec.value() << ": " << ec.message(); throw std::runtime_error{"fetch error"}; } @@ -653,10 +559,9 @@ ValidatorSite::onTextFetch( } catch (std::exception const& ex) { - JLOG(j_.error()) - << "Exception in " << __func__ << ": " << ex.what(); - sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{ - clock_type::now(), ListDisposition::invalid, ex.what()}); + JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what(); + sites_[siteIdx].lastRefreshStatus.emplace( + Site::Status{clock_type::now(), ListDisposition::invalid, ex.what()}); } sites_[siteIdx].activeResource.reset(); } @@ -689,18 +594,14 @@ ValidatorSite::getJson() const v[jss::next_refresh_time] = to_string(site.nextRefresh); if (site.lastRefreshStatus) { - v[jss::last_refresh_time] = - to_string(site.lastRefreshStatus->refreshed); - v[jss::last_refresh_status] = - to_string(site.lastRefreshStatus->disposition); + v[jss::last_refresh_time] = to_string(site.lastRefreshStatus->refreshed); + v[jss::last_refresh_status] = to_string(site.lastRefreshStatus->disposition); if (!site.lastRefreshStatus->message.empty()) - v[jss::last_refresh_message] = - site.lastRefreshStatus->message; + v[jss::last_refresh_message] = site.lastRefreshStatus->message; } - v[jss::refresh_interval_min] = - static_cast(site.refreshInterval.count()); + v[jss::refresh_interval_min] = static_cast(site.refreshInterval.count()); } } return jrr; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/Work.h b/src/xrpld/app/misc/detail/Work.h index 15be569566..5261cf3bd7 100644 --- a/src/xrpld/app/misc/detail/Work.h +++ b/src/xrpld/app/misc/detail/Work.h @@ -1,34 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DETAIL_WORK_H_INCLUDED -#define RIPPLE_APP_MISC_DETAIL_WORK_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { namespace detail { -using response_type = - boost::beast::http::response; +using response_type = boost::beast::http::response; class Work { @@ -44,6 +23,4 @@ public: } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/WorkBase.h b/src/xrpld/app/misc/detail/WorkBase.h index a73cd3d597..e5fd72f118 100644 --- a/src/xrpld/app/misc/detail/WorkBase.h +++ b/src/xrpld/app/misc/detail/WorkBase.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED -#define RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED +#pragma once #include @@ -32,7 +12,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -44,15 +24,13 @@ protected: using endpoint_type = boost::asio::ip::tcp::endpoint; public: - using callback_type = std::function< - void(error_code const&, endpoint_type const&, response_type&&)>; + using callback_type = std::function; protected: using socket_type = boost::asio::ip::tcp::socket; using resolver_type = boost::asio::ip::tcp::resolver; using results_type = boost::asio::ip::tcp::resolver::results_type; - using request_type = - boost::beast::http::request; + using request_type = boost::beast::http::request; std::string host_; std::string path_; @@ -142,9 +120,7 @@ template WorkBase::~WorkBase() { if (cb_) - cb_(make_error_code(boost::system::errc::not_a_socket), - lastEndpoint_, - std::move(res_)); + cb_(make_error_code(boost::system::errc::not_a_socket), lastEndpoint_, std::move(res_)); close(); } @@ -154,20 +130,14 @@ WorkBase::run() { if (!strand_.running_in_this_thread()) return boost::asio::post( - ios_, - boost::asio::bind_executor( - strand_, std::bind(&WorkBase::run, impl().shared_from_this()))); + ios_, boost::asio::bind_executor(strand_, std::bind(&WorkBase::run, impl().shared_from_this()))); resolver_.async_resolve( host_, port_, boost::asio::bind_executor( strand_, - std::bind( - &WorkBase::onResolve, - impl().shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + std::bind(&WorkBase::onResolve, impl().shared_from_this(), std::placeholders::_1, std::placeholders::_2))); } template @@ -179,9 +149,7 @@ WorkBase::cancel() return boost::asio::post( ios_, - boost::asio::bind_executor( - strand_, - std::bind(&WorkBase::cancel, impl().shared_from_this()))); + boost::asio::bind_executor(strand_, std::bind(&WorkBase::cancel, impl().shared_from_this()))); } error_code ec; @@ -212,11 +180,7 @@ WorkBase::onResolve(error_code const& ec, results_type results) results, boost::asio::bind_executor( strand_, - std::bind( - &WorkBase::onConnect, - impl().shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); + std::bind(&WorkBase::onConnect, impl().shared_from_this(), std::placeholders::_1, std::placeholders::_2))); } template @@ -245,11 +209,7 @@ WorkBase::onStart() impl().stream(), req_, boost::asio::bind_executor( - strand_, - std::bind( - &WorkBase::onRequest, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&WorkBase::onRequest, impl().shared_from_this(), std::placeholders::_1))); } template @@ -264,11 +224,7 @@ WorkBase::onRequest(error_code const& ec) readBuf_, res_, boost::asio::bind_executor( - strand_, - std::bind( - &WorkBase::onResponse, - impl().shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&WorkBase::onResponse, impl().shared_from_this(), std::placeholders::_1))); } template @@ -279,7 +235,7 @@ WorkBase::onResponse(error_code const& ec) return fail(ec); close(); - XRPL_ASSERT(cb_, "ripple::detail::WorkBase::onResponse : callback is set"); + XRPL_ASSERT(cb_, "xrpl::detail::WorkBase::onResponse : callback is set"); cb_(ec, lastEndpoint_, std::move(res_)); cb_ = nullptr; } @@ -300,6 +256,4 @@ WorkBase::close() } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/WorkFile.h b/src/xrpld/app/misc/detail/WorkFile.h index 562e1c9ec1..8d2d4edb50 100644 --- a/src/xrpld/app/misc/detail/WorkFile.h +++ b/src/xrpld/app/misc/detail/WorkFile.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DETAIL_WORKFILE_H_INCLUDED -#define RIPPLE_APP_MISC_DETAIL_WORKFILE_H_INCLUDED +#pragma once #include @@ -30,7 +10,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace detail { @@ -43,14 +23,10 @@ protected: using response_type = std::string; public: - using callback_type = - std::function; + using callback_type = std::function; public: - WorkFile( - std::string const& path, - boost::asio::io_context& ios, - callback_type cb); + WorkFile(std::string const& path, boost::asio::io_context& ios, callback_type cb); ~WorkFile(); void @@ -68,14 +44,8 @@ private: //------------------------------------------------------------------------------ -WorkFile::WorkFile( - std::string const& path, - boost::asio::io_context& ios, - callback_type cb) - : path_(path) - , cb_(std::move(cb)) - , ios_(ios) - , strand_(boost::asio::make_strand(ios)) +WorkFile::WorkFile(std::string const& path, boost::asio::io_context& ios, callback_type cb) + : path_(path), cb_(std::move(cb)), ios_(ios), strand_(boost::asio::make_strand(ios)) { } @@ -90,14 +60,12 @@ WorkFile::run() { if (!strand_.running_in_this_thread()) return boost::asio::post( - ios_, - boost::asio::bind_executor( - strand_, std::bind(&WorkFile::run, shared_from_this()))); + ios_, boost::asio::bind_executor(strand_, std::bind(&WorkFile::run, shared_from_this()))); error_code ec; auto const fileContents = getFileContents(ec, path_, megabytes(1)); - XRPL_ASSERT(cb_, "ripple::detail::WorkFile::run : callback is set"); + XRPL_ASSERT(cb_, "xrpl::detail::WorkFile::run : callback is set"); cb_(ec, fileContents); cb_ = nullptr; } @@ -110,6 +78,4 @@ WorkFile::cancel() } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/WorkPlain.h b/src/xrpld/app/misc/detail/WorkPlain.h index 38dd0df9fa..d1df5b4b3b 100644 --- a/src/xrpld/app/misc/detail/WorkPlain.h +++ b/src/xrpld/app/misc/detail/WorkPlain.h @@ -1,34 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DETAIL_WORKPLAIN_H_INCLUDED -#define RIPPLE_APP_MISC_DETAIL_WORKPLAIN_H_INCLUDED +#pragma once #include -namespace ripple { +namespace xrpl { namespace detail { // Work over TCP/IP -class WorkPlain : public WorkBase, - public std::enable_shared_from_this +class WorkPlain : public WorkBase, public std::enable_shared_from_this { friend class WorkBase; @@ -79,6 +58,4 @@ WorkPlain::onConnect(error_code const& ec) } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/WorkSSL.cpp b/src/xrpld/app/misc/detail/WorkSSL.cpp index a262a66ca7..47902e900a 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.cpp +++ b/src/xrpld/app/misc/detail/WorkSSL.cpp @@ -1,25 +1,6 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2020 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { namespace detail { WorkSSL::WorkSSL( @@ -43,8 +24,7 @@ WorkSSL::WorkSSL( { auto ec = context_.preConnectVerify(stream_, host_); if (ec) - Throw( - boost::str(boost::format("preConnectVerify: %s") % ec.message())); + Throw(boost::str(boost::format("preConnectVerify: %s") % ec.message())); } void @@ -57,11 +37,7 @@ WorkSSL::onConnect(error_code const& ec) stream_.async_handshake( boost::asio::ssl::stream_base::client, boost::asio::bind_executor( - strand_, - std::bind( - &WorkSSL::onHandshake, - shared_from_this(), - std::placeholders::_1))); + strand_, std::bind(&WorkSSL::onHandshake, shared_from_this(), std::placeholders::_1))); } void @@ -75,4 +51,4 @@ WorkSSL::onHandshake(error_code const& ec) } // namespace detail -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/misc/detail/WorkSSL.h b/src/xrpld/app/misc/detail/WorkSSL.h index cadc3fd8fd..b12c774f6e 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.h +++ b/src/xrpld/app/misc/detail/WorkSSL.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_MISC_DETAIL_WORKSSL_H_INCLUDED -#define RIPPLE_APP_MISC_DETAIL_WORKSSL_H_INCLUDED +#pragma once #include #include @@ -31,13 +11,12 @@ #include -namespace ripple { +namespace xrpl { namespace detail { // Work over SSL -class WorkSSL : public WorkBase, - public std::enable_shared_from_this +class WorkSSL : public WorkBase, public std::enable_shared_from_this { friend class WorkBase; @@ -76,6 +55,4 @@ private: } // namespace detail -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/AMMContext.h b/src/xrpld/app/paths/AMMContext.h index f744b8a6c9..b0ff44c5ec 100644 --- a/src/xrpld/app/paths/AMMContext.h +++ b/src/xrpld/app/paths/AMMContext.h @@ -1,30 +1,10 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_AMMCONTEXT_H_INCLUDED -#define RIPPLE_APP_PATHS_AMMCONTEXT_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { /** Maintains AMM info per overall payment engine execution and * individual iteration. @@ -51,8 +31,7 @@ private: std::uint16_t ammIters_{0}; public: - AMMContext(AccountID const& account, bool multiPath) - : account_(account), multiPath_(multiPath) + AMMContext(AccountID const& account, bool multiPath) : account_(account), multiPath_(multiPath) { } ~AMMContext() = default; @@ -114,6 +93,4 @@ public: } }; -} // namespace ripple - -#endif // RIPPLE_APP_PATHS_AMMCONTEXT_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/paths/AMMLiquidity.h b/src/xrpld/app/paths/AMMLiquidity.h index cb1db93705..441c3b6e3d 100644 --- a/src/xrpld/app/paths/AMMLiquidity.h +++ b/src/xrpld/app/paths/AMMLiquidity.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_TX_AMMLIQUIDITY_H_INCLUDED -#define RIPPLE_APP_TX_AMMLIQUIDITY_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { template class AMMOffer; @@ -82,8 +62,7 @@ public: * quality. */ std::optional> - getOffer(ReadView const& view, std::optional const& clobQuality) - const; + getOffer(ReadView const& view, std::optional const& clobQuality) const; AccountID const& ammAccount() const @@ -150,6 +129,4 @@ private: maxOffer(TAmounts const& balances, Rules const& rules) const; }; -} // namespace ripple - -#endif // RIPPLE_APP_TX_AMMLIQUIDITY_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/paths/AMMOffer.h b/src/xrpld/app/paths/AMMOffer.h index 3c218c0f5e..ebaa7311c0 100644 --- a/src/xrpld/app/paths/AMMOffer.h +++ b/src/xrpld/app/paths/AMMOffer.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_AMMOFFER_H_INCLUDED -#define RIPPLE_APP_AMMOFFER_H_INCLUDED +#pragma once #include #include #include #include -namespace ripple { +namespace xrpl { template class AMMLiquidity; @@ -100,18 +80,14 @@ public: * current quality. */ TAmounts - limitOut( - TAmounts const& offrAmt, - TOut const& limit, - bool roundUp) const; + limitOut(TAmounts const& offerAmount, TOut const& limit, bool roundUp) const; /** Limit in of the provided offer. If one-path then swapIn * using current balances. If multi-path then ceil_in using * current quality. */ TAmounts - limitIn(TAmounts const& offrAmt, TIn const& limit, bool roundUp) - const; + limitIn(TAmounts const& offerAmount, TIn const& limit, bool roundUp) const; QualityFunction getQualityFunc() const; @@ -146,6 +122,4 @@ public: checkInvariant(TAmounts const& consumed, beast::Journal j) const; }; -} // namespace ripple - -#endif // RIPPLE_APP_AMMOFFER_H_INCLUDED +} // namespace xrpl diff --git a/src/xrpld/app/paths/AccountCurrencies.cpp b/src/xrpld/app/paths/AccountCurrencies.cpp index 8646b46939..8e51999018 100644 --- a/src/xrpld/app/paths/AccountCurrencies.cpp +++ b/src/xrpld/app/paths/AccountCurrencies.cpp @@ -1,31 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -namespace ripple { +namespace xrpl { hash_set -accountSourceCurrencies( - AccountID const& account, - std::shared_ptr const& lrCache, - bool includeXRP) +accountSourceCurrencies(AccountID const& account, std::shared_ptr const& lrCache, bool includeXRP) { hash_set currencies; @@ -33,8 +11,7 @@ accountSourceCurrencies( if (includeXRP) currencies.insert(xrpCurrency()); - if (auto const lines = - lrCache->getRippleLines(account, LineDirection::outgoing)) + if (auto const lines = lrCache->getRippleLines(account, LineDirection::outgoing)) { for (auto const& rspEntry : *lines) { @@ -43,10 +20,9 @@ accountSourceCurrencies( // Filter out non if (saBalance > beast::zero // Have IOUs to send. - || - (rspEntry.getLimitPeer() - // Peer extends credit. - && ((-saBalance) < rspEntry.getLimitPeer()))) // Credit left. + || (rspEntry.getLimitPeer() + // Peer extends credit. + && ((-saBalance) < rspEntry.getLimitPeer()))) // Credit left. { currencies.insert(saBalance.getCurrency()); } @@ -58,10 +34,7 @@ accountSourceCurrencies( } hash_set -accountDestCurrencies( - AccountID const& account, - std::shared_ptr const& lrCache, - bool includeXRP) +accountDestCurrencies(AccountID const& account, std::shared_ptr const& lrCache, bool includeXRP) { hash_set currencies; @@ -69,8 +42,7 @@ accountDestCurrencies( currencies.insert(xrpCurrency()); // Even if account doesn't exist - if (auto const lines = - lrCache->getRippleLines(account, LineDirection::outgoing)) + if (auto const lines = lrCache->getRippleLines(account, LineDirection::outgoing)) { for (auto const& rspEntry : *lines) { @@ -85,4 +57,4 @@ accountDestCurrencies( return currencies; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/AccountCurrencies.h b/src/xrpld/app/paths/AccountCurrencies.h index 566fad9104..eb8cc92aec 100644 --- a/src/xrpld/app/paths/AccountCurrencies.h +++ b/src/xrpld/app/paths/AccountCurrencies.h @@ -1,43 +1,15 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H_INCLUDED -#define RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H_INCLUDED +#pragma once #include #include -namespace ripple { +namespace xrpl { hash_set -accountDestCurrencies( - AccountID const& account, - std::shared_ptr const& cache, - bool includeXRP); +accountDestCurrencies(AccountID const& account, std::shared_ptr const& cache, bool includeXRP); hash_set -accountSourceCurrencies( - AccountID const& account, - std::shared_ptr const& lrLedger, - bool includeXRP); +accountSourceCurrencies(AccountID const& account, std::shared_ptr const& lrLedger, bool includeXRP); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp deleted file mode 100644 index f975385b28..0000000000 --- a/src/xrpld/app/paths/Credit.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include - -namespace ripple { - -STAmount -creditLimit( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency) -{ - STAmount result(Issue{currency, account}); - - auto sleRippleState = view.read(keylet::line(account, issuer, currency)); - - if (sleRippleState) - { - result = sleRippleState->getFieldAmount( - account < issuer ? sfLowLimit : sfHighLimit); - result.setIssuer(account); - } - - XRPL_ASSERT( - result.getIssuer() == account, - "ripple::creditLimit : result issuer match"); - XRPL_ASSERT( - result.getCurrency() == currency, - "ripple::creditLimit : result currency match"); - return result; -} - -IOUAmount -creditLimit2( - ReadView const& v, - AccountID const& acc, - AccountID const& iss, - Currency const& cur) -{ - return toAmount(creditLimit(v, acc, iss, cur)); -} - -STAmount -creditBalance( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency) -{ - STAmount result(Issue{currency, account}); - - auto sleRippleState = view.read(keylet::line(account, issuer, currency)); - - if (sleRippleState) - { - result = sleRippleState->getFieldAmount(sfBalance); - if (account < issuer) - result.negate(); - result.setIssuer(account); - } - - XRPL_ASSERT( - result.getIssuer() == account, - "ripple::creditBalance : result issuer match"); - XRPL_ASSERT( - result.getCurrency() == currency, - "ripple::creditBalance : result currency match"); - return result; -} - -} // namespace ripple diff --git a/src/xrpld/app/paths/Credit.h b/src/xrpld/app/paths/Credit.h deleted file mode 100644 index 12ea27a734..0000000000 --- a/src/xrpld/app/paths/Credit.h +++ /dev/null @@ -1,69 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_CREDIT_H_INCLUDED -#define RIPPLE_APP_PATHS_CREDIT_H_INCLUDED - -#include -#include -#include - -namespace ripple { - -/** Calculate the maximum amount of IOUs that an account can hold - @param ledger the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. - @return The maximum amount that can be held. -*/ -/** @{ */ -STAmount -creditLimit( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency); - -IOUAmount -creditLimit2( - ReadView const& v, - AccountID const& acc, - AccountID const& iss, - Currency const& cur); -/** @} */ - -/** Returns the amount of IOUs issued by issuer that are held by an account - @param ledger the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. -*/ -/** @{ */ -STAmount -creditBalance( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency); -/** @} */ - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/paths/Flow.cpp b/src/xrpld/app/paths/Flow.cpp index 3b14b8b968..1f6d29bfb9 100644 --- a/src/xrpld/app/paths/Flow.cpp +++ b/src/xrpld/app/paths/Flow.cpp @@ -1,42 +1,19 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include -#include #include #include #include #include #include +#include #include #include -namespace ripple { +namespace xrpl { template static auto -finishFlow( - PaymentSandbox& sb, - Issue const& srcIssue, - Issue const& dstIssue, - FlowResult&& f) +finishFlow(PaymentSandbox& sb, Issue const& srcIssue, Issue const& dstIssue, FlowResult&& f) { path::RippleCalc::Output result; if (f.ter == tesSUCCESS) @@ -113,8 +90,7 @@ flow( if (j.trace()) { - j.trace() << "\nsrc: " << src << "\ndst: " << dst - << "\nsrcIssue: " << srcIssue << "\ndstIssue: " << dstIssue; + j.trace() << "\nsrc: " << src << "\ndst: " << dst << "\nsrcIssue: " << srcIssue << "\ndstIssue: " << dstIssue; j.trace() << "\nNumStrands: " << strands.size(); for (auto const& curStrand : strands) { @@ -191,7 +167,7 @@ flow( flowDebugInfo)); } - XRPL_ASSERT(!srcIsXRP && !dstIsXRP, "ripple::flow : neither is XRP"); + XRPL_ASSERT(!srcIsXRP && !dstIsXRP, "xrpl::flow : neither is XRP"); return finishFlow( sb, srcIssue, @@ -209,4 +185,4 @@ flow( flowDebugInfo)); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/Flow.h b/src/xrpld/app/paths/Flow.h index 659f180484..1a46ce221a 100644 --- a/src/xrpld/app/paths/Flow.h +++ b/src/xrpld/app/paths/Flow.h @@ -1,31 +1,11 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_FLOW_H_INCLUDED -#define RIPPLE_APP_PATHS_FLOW_H_INCLUDED +#pragma once #include #include #include -namespace ripple { +namespace xrpl { namespace path { namespace detail { @@ -70,6 +50,4 @@ flow( beast::Journal j, path::detail::FlowDebugInfo* flowDebugInfo = nullptr); -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index a9db61d5b3..e2a3e14485 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -37,7 +18,7 @@ #include #include -namespace ripple { +namespace xrpl { PathRequest::PathRequest( Application& app, @@ -95,21 +76,17 @@ PathRequest::~PathRequest() if (quick_reply_ != steady_clock::time_point{}) { fast = " fast:"; - fast += std::to_string( - duration_cast(quick_reply_ - created_).count()); + fast += std::to_string(duration_cast(quick_reply_ - created_).count()); fast += "ms"; } if (full_reply_ != steady_clock::time_point{}) { full = " full:"; - full += std::to_string( - duration_cast(full_reply_ - created_).count()); + full += std::to_string(duration_cast(full_reply_ - created_).count()); full += "ms"; } - stream - << iIdentifier << " complete:" << fast << full << " total:" - << duration_cast(steady_clock::now() - created_).count() - << "ms"; + stream << iIdentifier << " complete:" << fast << full + << " total:" << duration_cast(steady_clock::now() - created_).count() << "ms"; } bool @@ -158,8 +135,7 @@ PathRequest::updateComplete() { std::lock_guard sl(mIndexLock); - XRPL_ASSERT( - mInProgress, "ripple::PathRequest::updateComplete : in progress"); + XRPL_ASSERT(mInProgress, "xrpl::PathRequest::updateComplete : in progress"); mInProgress = false; if (fCompletion) @@ -193,8 +169,7 @@ PathRequest::isValid(std::shared_ptr const& crCache) auto const sleDest = lrLedger->read(keylet::account(*raDstAccount)); - Json::Value& jvDestCur = - (jvStatus[jss::destination_currencies] = Json::arrayValue); + Json::Value& jvDestCur = (jvStatus[jss::destination_currencies] = Json::arrayValue); if (!sleDest) { @@ -217,16 +192,14 @@ PathRequest::isValid(std::shared_ptr const& crCache) { bool const disallowXRP(sleDest->getFlags() & lsfDisallowXRP); - auto usDestCurrID = - accountDestCurrencies(*raDstAccount, crCache, !disallowXRP); + auto usDestCurrID = accountDestCurrencies(*raDstAccount, crCache, !disallowXRP); for (auto const& currency : usDestCurrID) jvDestCur.append(to_string(currency)); - jvStatus[jss::destination_tag] = - (sleDest->getFlags() & lsfRequireDestTag); + jvStatus[jss::destination_tag] = (sleDest->getFlags() & lsfRequireDestTag); } - jvStatus[jss::ledger_hash] = to_string(lrLedger->info().hash); + jvStatus[jss::ledger_hash] = to_string(lrLedger->header().hash); jvStatus[jss::ledger_index] = lrLedger->seq(); return true; } @@ -241,9 +214,7 @@ PathRequest::isValid(std::shared_ptr const& crCache) in all cases. */ std::pair -PathRequest::doCreate( - std::shared_ptr const& cache, - Json::Value const& value) +PathRequest::doCreate(std::shared_ptr const& cache, Json::Value const& value) { bool valid = false; @@ -291,16 +262,14 @@ PathRequest::parseJson(Json::Value const& jvParams) return PFR_PJ_INVALID; } - raSrcAccount = - parseBase58(jvParams[jss::source_account].asString()); + raSrcAccount = parseBase58(jvParams[jss::source_account].asString()); if (!raSrcAccount) { jvStatus = rpcError(rpcSRC_ACT_MALFORMED); return PFR_PJ_INVALID; } - raDstAccount = - parseBase58(jvParams[jss::destination_account].asString()); + raDstAccount = parseBase58(jvParams[jss::destination_account].asString()); if (!raDstAccount) { jvStatus = rpcError(rpcDST_ACT_MALFORMED); @@ -315,10 +284,8 @@ PathRequest::parseJson(Json::Value const& jvParams) convert_all_ = saDstAmount == STAmount(saDstAmount.issue(), 1u, 0, true); - if ((saDstAmount.getCurrency().isZero() && - saDstAmount.getIssuer().isNonZero()) || - (saDstAmount.getCurrency() == badCurrency()) || - (!convert_all_ && saDstAmount <= beast::zero)) + if ((saDstAmount.getCurrency().isZero() && saDstAmount.getIssuer().isNonZero()) || + (saDstAmount.getCurrency() == badCurrency()) || (!convert_all_ && saDstAmount <= beast::zero)) { jvStatus = rpcError(rpcDST_AMT_MALFORMED); return PFR_PJ_INVALID; @@ -335,11 +302,9 @@ PathRequest::parseJson(Json::Value const& jvParams) saSendMax.emplace(); if (!amountFromJsonNoThrow(*saSendMax, jvParams[jss::send_max]) || - (saSendMax->getCurrency().isZero() && - saSendMax->getIssuer().isNonZero()) || + (saSendMax->getCurrency().isZero() && saSendMax->getIssuer().isNonZero()) || (saSendMax->getCurrency() == badCurrency()) || - (*saSendMax <= beast::zero && - *saSendMax != STAmount(saSendMax->issue(), 1u, 0, true))) + (*saSendMax <= beast::zero && *saSendMax != STAmount(saSendMax->issue(), 1u, 0, true))) { jvStatus = rpcError(rpcSENDMAX_MALFORMED); return PFR_PJ_INVALID; @@ -362,8 +327,7 @@ PathRequest::parseJson(Json::Value const& jvParams) { // Mandatory currency Currency srcCurrencyID; - if (!c.isObject() || !c.isMember(jss::currency) || - !c[jss::currency].isString() || + if (!c.isObject() || !c.isMember(jss::currency) || !c[jss::currency].isString() || !to_currency(srcCurrencyID, c[jss::currency].asString())) { jvStatus = rpcError(rpcSRC_CUR_MALFORMED); @@ -373,8 +337,7 @@ PathRequest::parseJson(Json::Value const& jvParams) // Optional issuer AccountID srcIssuerID; if (c.isMember(jss::issuer) && - (!c[jss::issuer].isString() || - !to_issuer(srcIssuerID, c[jss::issuer].asString()))) + (!c[jss::issuer].isString() || !to_issuer(srcIssuerID, c[jss::issuer].asString()))) { jvStatus = rpcError(rpcSRC_ISR_MALFORMED); return PFR_PJ_INVALID; @@ -400,8 +363,7 @@ PathRequest::parseJson(Json::Value const& jvParams) { // If neither is the source and they are not equal, then the // source issuer is illegal. - if (srcIssuerID != *raSrcAccount && - saSendMax->getIssuer() != *raSrcAccount && + if (srcIssuerID != *raSrcAccount && saSendMax->getIssuer() != *raSrcAccount && srcIssuerID != saSendMax->getIssuer()) { jvStatus = rpcError(rpcSRC_ISR_MALFORMED); @@ -412,18 +374,15 @@ PathRequest::parseJson(Json::Value const& jvParams) // Otherwise, use the one that's not the source. if (srcIssuerID != *raSrcAccount) { - sciSourceCurrencies.insert( - {srcCurrencyID, srcIssuerID}); + sciSourceCurrencies.insert({srcCurrencyID, srcIssuerID}); } else if (saSendMax->getIssuer() != *raSrcAccount) { - sciSourceCurrencies.insert( - {srcCurrencyID, saSendMax->getIssuer()}); + sciSourceCurrencies.insert({srcCurrencyID, saSendMax->getIssuer()}); } else { - sciSourceCurrencies.insert( - {srcCurrencyID, *raSrcAccount}); + sciSourceCurrencies.insert({srcCurrencyID, *raSrcAccount}); } } } @@ -440,8 +399,7 @@ PathRequest::parseJson(Json::Value const& jvParams) if (jvParams.isMember(jss::domain)) { uint256 num; - if (!jvParams[jss::domain].isString() || - !num.parseHex(jvParams[jss::domain].asString())) + if (!jvParams[jss::domain].isString() || !num.parseHex(jvParams[jss::domain].asString())) { jvStatus = rpcError(rpcDOMAIN_MALFORMED); return PFR_PJ_INVALID; @@ -491,15 +449,7 @@ PathRequest::getPathFinder( if (i != currency_map.end()) return i->second; auto pathfinder = std::make_unique( - cache, - *raSrcAccount, - *raDstAccount, - currency, - std::nullopt, - dst_amount, - saSendMax, - domain, - app_); + cache, *raSrcAccount, *raDstAccount, currency, std::nullopt, dst_amount, saSendMax, domain, app_); if (pathfinder->findPaths(level, continueCallback)) pathfinder->computePathRanks(max_paths_, continueCallback); else @@ -529,8 +479,7 @@ PathRequest::findPaths( { if (sourceCurrencies.size() >= RPC::Tuning::max_auto_src_cur) return false; - sourceCurrencies.insert( - {c, c.isZero() ? xrpAccount() : *raSrcAccount}); + sourceCurrencies.insert({c, c.isZero() ? xrpAccount() : *raSrcAccount}); } } } @@ -541,17 +490,9 @@ PathRequest::findPaths( { if (continueCallback && !continueCallback()) break; - JLOG(m_journal.debug()) - << iIdentifier - << " Trying to find paths: " << STAmount(issue, 1).getFullText(); + JLOG(m_journal.debug()) << iIdentifier << " Trying to find paths: " << STAmount(issue, 1).getFullText(); - auto& pathfinder = getPathFinder( - cache, - currency_map, - issue.currency, - dst_amount, - level, - continueCallback); + auto& pathfinder = getPathFinder(cache, currency_map, issue.currency, dst_amount, level, continueCallback); if (!pathfinder) { JLOG(m_journal.debug()) << iIdentifier << " No paths found"; @@ -559,12 +500,8 @@ PathRequest::findPaths( } STPath fullLiquidityPath; - auto ps = pathfinder->getBestPaths( - max_paths_, - fullLiquidityPath, - mContext[issue], - issue.account, - continueCallback); + auto ps = + pathfinder->getBestPaths(max_paths_, fullLiquidityPath, mContext[issue], issue.account, continueCallback); mContext[issue] = ps; auto const& sourceAccount = [&] { @@ -577,17 +514,14 @@ PathRequest::findPaths( return *raSrcAccount; }(); - STAmount saMaxAmount = saSendMax.value_or( - STAmount(Issue{issue.currency, sourceAccount}, 1u, 0, true)); + STAmount saMaxAmount = saSendMax.value_or(STAmount(Issue{issue.currency, sourceAccount}, 1u, 0, true)); - JLOG(m_journal.debug()) - << iIdentifier << " Paths found, calling rippleCalc"; + JLOG(m_journal.debug()) << iIdentifier << " Paths found, calling rippleCalc"; path::RippleCalc::Input rcInput; if (convert_all_) rcInput.partialPaymentAllowed = true; - auto sandbox = - std::make_unique(&*cache->getLedger(), tapNONE); + auto sandbox = std::make_unique(&*cache->getLedger(), tapNONE); auto rc = path::RippleCalc::rippleCalculate( *sandbox, saMaxAmount, // --> Amount to send is unlimited @@ -603,12 +537,10 @@ PathRequest::findPaths( if (!convert_all_ && !fullLiquidityPath.empty() && (rc.result() == terNO_LINE || rc.result() == tecPATH_PARTIAL)) { - JLOG(m_journal.debug()) - << iIdentifier << " Trying with an extra path element"; + JLOG(m_journal.debug()) << iIdentifier << " Trying with an extra path element"; ps.push_back(fullLiquidityPath); - sandbox = - std::make_unique(&*cache->getLedger(), tapNONE); + sandbox = std::make_unique(&*cache->getLedger(), tapNONE); rc = path::RippleCalc::rippleCalculate( *sandbox, saMaxAmount, // --> Amount to send is unlimited @@ -622,15 +554,11 @@ PathRequest::findPaths( if (rc.result() != tesSUCCESS) { - JLOG(m_journal.warn()) - << iIdentifier << " Failed with covering path " - << transHuman(rc.result()); + JLOG(m_journal.warn()) << iIdentifier << " Failed with covering path " << transHuman(rc.result()); } else { - JLOG(m_journal.debug()) - << iIdentifier << " Extra path element gives " - << transHuman(rc.result()); + JLOG(m_journal.debug()) << iIdentifier << " Extra path element gives " << transHuman(rc.result()); } } @@ -638,13 +566,11 @@ PathRequest::findPaths( { Json::Value jvEntry(Json::objectValue); rc.actualAmountIn.setIssuer(sourceAccount); - jvEntry[jss::source_amount] = - rc.actualAmountIn.getJson(JsonOptions::none); + jvEntry[jss::source_amount] = rc.actualAmountIn.getJson(JsonOptions::none); jvEntry[jss::paths_computed] = ps.getJson(JsonOptions::none); if (convert_all_) - jvEntry[jss::destination_amount] = - rc.actualAmountOut.getJson(JsonOptions::none); + jvEntry[jss::destination_amount] = rc.actualAmountOut.getJson(JsonOptions::none); if (hasCompletion()) { @@ -656,8 +582,7 @@ PathRequest::findPaths( } else { - JLOG(m_journal.debug()) << iIdentifier << " rippleCalc returns " - << transHuman(rc.result()); + JLOG(m_journal.debug()) << iIdentifier << " rippleCalc returns " << transHuman(rc.result()); } } @@ -677,8 +602,7 @@ PathRequest::doUpdate( std::function const& continueCallback) { using namespace std::chrono; - JLOG(m_journal.debug()) - << iIdentifier << " update " << (fast ? "fast" : "normal"); + JLOG(m_journal.debug()) << iIdentifier << " update " << (fast ? "fast" : "normal"); { std::lock_guard sl(mLock); @@ -692,8 +616,7 @@ PathRequest::doUpdate( if (hasCompletion()) { // Old ripple_path_find API gives destination_currencies - auto& destCurrencies = - (newStatus[jss::destination_currencies] = Json::arrayValue); + auto& destCurrencies = (newStatus[jss::destination_currencies] = Json::arrayValue); auto usCurrencies = accountDestCurrencies(*raDstAccount, cache, true); for (auto const& c : usCurrencies) destCurrencies.append(to_string(c)); @@ -727,8 +650,7 @@ PathRequest::doUpdate( else if (bLastSuccess) { // decrement, if possible - if (iLevel > app_.config().PATH_SEARCH || - (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))) + if (iLevel > app_.config().PATH_SEARCH || (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))) --iLevel; } else @@ -770,8 +692,7 @@ PathRequest::doUpdate( jvStatus = newStatus; } - JLOG(m_journal.debug()) - << iIdentifier << " update finished " << (fast ? "fast" : "normal"); + JLOG(m_journal.debug()) << iIdentifier << " update finished " << (fast ? "fast" : "normal"); return newStatus; } @@ -781,4 +702,4 @@ PathRequest::getSubscriber() const return wpSubscriber.lock(); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/PathRequest.h b/src/xrpld/app/paths/PathRequest.h index 854a0f6129..864d2cb932 100644 --- a/src/xrpld/app/paths/PathRequest.h +++ b/src/xrpld/app/paths/PathRequest.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_PATHREQUEST_H_INCLUDED -#define RIPPLE_APP_PATHS_PATHREQUEST_H_INCLUDED +#pragma once #include #include @@ -34,7 +14,7 @@ #include #include -namespace ripple { +namespace xrpl { // A pathfinding request submitted by a client // The request issuer must maintain a strong pointer @@ -122,14 +102,10 @@ private: std::function const&); /** Finds and sets a PathSet in the JSON argument. - Returns false if the source currencies are inavlid. + Returns false if the source currencies are invalid. */ bool - findPaths( - std::shared_ptr const&, - int const, - Json::Value&, - std::function const&); + findPaths(std::shared_ptr const&, int const, Json::Value&, std::function const&); int parseJson(Json::Value const&); @@ -177,6 +153,4 @@ private: static unsigned int const max_paths_ = 4; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/PathRequests.cpp b/src/xrpld/app/paths/PathRequests.cpp index 9ada526751..2c1ef8cbad 100644 --- a/src/xrpld/app/paths/PathRequests.cpp +++ b/src/xrpld/app/paths/PathRequests.cpp @@ -1,43 +1,22 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -#include #include +#include #include #include #include #include -namespace ripple { +namespace xrpl { /** Get the current RippleLineCache, updating it if necessary. Get the correct ledger to use. */ std::shared_ptr -PathRequests::getLineCache( - std::shared_ptr const& ledger, - bool authoritative) +PathRequests::getLineCache(std::shared_ptr const& ledger, bool authoritative) { std::lock_guard sl(mLock); @@ -45,22 +24,18 @@ PathRequests::getLineCache( std::uint32_t const lineSeq = lineCache ? lineCache->getLedger()->seq() : 0; std::uint32_t const lgrSeq = ledger->seq(); - JLOG(mJournal.debug()) << "getLineCache has cache for " << lineSeq - << ", considering " << lgrSeq; + JLOG(mJournal.debug()) << "getLineCache has cache for " << lineSeq << ", considering " << lgrSeq; - if ((lineSeq == 0) || // no ledger - (authoritative && (lgrSeq > lineSeq)) || // newer authoritative ledger - (authoritative && - ((lgrSeq + 8) < lineSeq)) || // we jumped way back for some reason - (lgrSeq > (lineSeq + 8))) // we jumped way forward for some reason + if ((lineSeq == 0) || // no ledger + (authoritative && (lgrSeq > lineSeq)) || // newer authoritative ledger + (authoritative && ((lgrSeq + 8) < lineSeq)) || // we jumped way back for some reason + (lgrSeq > (lineSeq + 8))) // we jumped way forward for some reason { - JLOG(mJournal.debug()) - << "getLineCache creating new cache for " << lgrSeq; + JLOG(mJournal.debug()) << "getLineCache creating new cache for " << lgrSeq; // Assign to the local before the member, because the member is a // weak_ptr, and will immediately discard it if there are no other // references. - lineCache_ = lineCache = std::make_shared( - ledger, app_.journal("RippleLineCache")); + lineCache_ = lineCache = std::make_shared(ledger, app_.journal("RippleLineCache")); } return lineCache; } @@ -68,8 +43,7 @@ PathRequests::getLineCache( void PathRequests::updateAll(std::shared_ptr const& inLedger) { - auto event = - app_.getJobQueue().makeLoadEvent(jtPATH_FIND, "PathRequest::updateAll"); + auto event = app_.getJobQueue().makeLoadEvent(jtPATH_FIND, "PathRequest::updateAll"); std::vector requests; std::shared_ptr cache; @@ -84,15 +58,12 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) bool newRequests = app_.getLedgerMaster().isNewPathRequest(); bool mustBreak = false; - JLOG(mJournal.trace()) << "updateAll seq=" << cache->getLedger()->seq() - << ", " << requests.size() << " requests"; + JLOG(mJournal.trace()) << "updateAll seq=" << cache->getLedger()->seq() << ", " << requests.size() << " requests"; int processed = 0, removed = 0; - auto getSubscriber = - [](PathRequest::pointer const& request) -> InfoSub::pointer { - if (auto ipSub = request->getSubscriber(); - ipSub && ipSub->getRequest() == request) + auto getSubscriber = [](PathRequest::pointer const& request) -> InfoSub::pointer { + if (auto ipSub = request->getSubscriber(); ipSub && ipSub->getRequest() == request) { return ipSub; } @@ -110,8 +81,7 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) auto request = wr.lock(); bool remove = true; - JLOG(mJournal.trace()) - << "updateAll request " << (request ? "" : "not ") << "found"; + JLOG(mJournal.trace()) << "updateAll request " << (request ? "" : "not ") << "found"; if (request) { @@ -121,8 +91,7 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) // indicates that this request is no longer relevant. return (bool)getSubscriber(request); }; - if (!request->needsUpdate( - newRequests, cache->getLedger()->seq())) + if (!request->needsUpdate(newRequests, cache->getLedger()->seq())) remove = false; else { @@ -134,8 +103,7 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) // it can be freed if the client disconnects, and // thus fail to lock later. ipSub.reset(); - Json::Value update = request->doUpdate( - cache, false, continueCallback); + Json::Value update = request->doUpdate(cache, false, continueCallback); request->updateComplete(); update[jss::type] = "path_find"; if ((ipSub = getSubscriber(request))) @@ -162,23 +130,19 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) // Remove any dangling weak pointers or weak // pointers that refer to this path request. - auto ret = std::remove_if( - requests_.begin(), - requests_.end(), - [&removed, &request](auto const& wl) { - auto r = wl.lock(); + auto ret = std::remove_if(requests_.begin(), requests_.end(), [&removed, &request](auto const& wl) { + auto r = wl.lock(); - if (r && r != request) - return false; - ++removed; - return true; - }); + if (r && r != request) + return false; + ++removed; + return true; + }); requests_.erase(ret, requests_.end()); } - mustBreak = - !newRequests && app_.getLedgerMaster().isNewPathRequest(); + mustBreak = !newRequests && app_.getLedgerMaster().isNewPathRequest(); // We weren't handling new requests and then // there was a new request @@ -216,8 +180,7 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) } } while (!app_.getJobQueue().isStopping()); - JLOG(mJournal.debug()) << "updateAll complete: " << processed - << " processed and " << removed << " removed"; + JLOG(mJournal.debug()) << "updateAll complete: " << processed << " processed and " << removed << " removed"; } bool @@ -234,13 +197,12 @@ PathRequests::insertPathRequest(PathRequest::pointer const& req) // Insert after any older unserviced requests but before // any serviced requests - auto ret = - std::find_if(requests_.begin(), requests_.end(), [](auto const& wl) { - auto r = wl.lock(); + auto ret = std::find_if(requests_.begin(), requests_.end(), [](auto const& wl) { + auto r = wl.lock(); - // We come before handled requests - return r && !r->isNew(); - }); + // We come before handled requests + return r && !r->isNew(); + }); requests_.emplace(ret, req); } @@ -252,11 +214,9 @@ PathRequests::makePathRequest( std::shared_ptr const& inLedger, Json::Value const& requestJson) { - auto req = std::make_shared( - app_, subscriber, ++mLastIdentifier, *this, mJournal); + auto req = std::make_shared(app_, subscriber, ++mLastIdentifier, *this, mJournal); - auto [valid, jvRes] = - req->doCreate(getLineCache(inLedger, false), requestJson); + auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), requestJson); if (valid) { @@ -278,8 +238,7 @@ PathRequests::makeLegacyPathRequest( { // This assignment must take place before the // completion function is called - req = std::make_shared( - app_, completion, consumer, ++mLastIdentifier, *this, mJournal); + req = std::make_shared(app_, completion, consumer, ++mLastIdentifier, *this, mJournal); auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request); @@ -307,11 +266,9 @@ PathRequests::doLegacyPathRequest( std::shared_ptr const& inLedger, Json::Value const& request) { - auto cache = std::make_shared( - inLedger, app_.journal("RippleLineCache")); + auto cache = std::make_shared(inLedger, app_.journal("RippleLineCache")); - auto req = std::make_shared( - app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal); + auto req = std::make_shared(app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal); auto [valid, jvRes] = req->doCreate(cache, request); if (valid) @@ -319,4 +276,4 @@ PathRequests::doLegacyPathRequest( return std::move(jvRes); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/PathRequests.h b/src/xrpld/app/paths/PathRequests.h index fadf6b7b7c..f89ca3c4da 100644 --- a/src/xrpld/app/paths/PathRequests.h +++ b/src/xrpld/app/paths/PathRequests.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_PATHREQUESTS_H_INCLUDED -#define RIPPLE_APP_PATHS_PATHREQUESTS_H_INCLUDED +#pragma once #include #include @@ -28,16 +8,13 @@ #include #include -namespace ripple { +namespace xrpl { class PathRequests { public: /** A collection of all PathRequest instances. */ - PathRequests( - Application& app, - beast::Journal journal, - beast::insight::Collector::ptr const& collector) + PathRequests(Application& app, beast::Journal journal, beast::insight::Collector::ptr const& collector) : app_(app), mJournal(journal), mLastIdentifier(0) { mFast = collector->make_event("pathfind_fast"); @@ -55,9 +32,7 @@ public: requestsPending() const; std::shared_ptr - getLineCache( - std::shared_ptr const& ledger, - bool authoritative); + getLineCache(std::shared_ptr const& ledger, bool authoritative); // Create a new-style path request that pushes // updates to a subscriber @@ -119,6 +94,4 @@ private: std::recursive_mutex mutable mLock; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 7f9c2f8437..b64ce0cc20 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -1,32 +1,13 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include #include #include #include -#include #include #include +#include #include #include @@ -59,12 +40,12 @@ final paths and the estimated cost are returned. The engine permits the search depth to be selected and the paths table includes the depth at which each path type is found. A search depth of zero causes no searching to be done. Extra paths can also be injected, and this -should be used to preserve previously-found paths across invokations for the +should be used to preserve previously-found paths across invocations for the same path request (particularly if the search depth may change). */ -namespace ripple { +namespace xrpl { namespace { @@ -81,10 +62,7 @@ struct AccountCandidate }; bool -compareAccountCandidate( - std::uint32_t seq, - AccountCandidate const& first, - AccountCandidate const& second) +compareAccountCandidate(std::uint32_t seq, AccountCandidate const& first, AccountCandidate const& second) { if (first.priority < second.priority) return false; @@ -170,17 +148,12 @@ Pathfinder::Pathfinder( Application& app) : mSrcAccount(uSrcAccount) , mDstAccount(uDstAccount) - , mEffectiveDst( - isXRP(saDstAmount.getIssuer()) ? uDstAccount - : saDstAmount.getIssuer()) + , mEffectiveDst(isXRP(saDstAmount.getIssuer()) ? uDstAccount : saDstAmount.getIssuer()) , mDstAmount(saDstAmount) , mSrcCurrency(uSrcCurrency) , mSrcIssuer(uSrcIssuer) , mSrcAmount(srcAmount.value_or(STAmount( - Issue{ - uSrcCurrency, - uSrcIssuer.value_or( - isXRP(uSrcCurrency) ? xrpAccount() : uSrcAccount)}, + Issue{uSrcCurrency, uSrcIssuer.value_or(isXRP(uSrcCurrency) ? xrpAccount() : uSrcAccount)}, 1u, 0, true))) @@ -192,14 +165,11 @@ Pathfinder::Pathfinder( , j_(app.journal("Pathfinder")) { XRPL_ASSERT( - !uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value()), - "ripple::Pathfinder::Pathfinder : valid inputs"); + !uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value()), "xrpl::Pathfinder::Pathfinder : valid inputs"); } bool -Pathfinder::findPaths( - int searchLevel, - std::function const& continueCallback) +Pathfinder::findPaths(int searchLevel, std::function const& continueCallback) { JLOG(j_.trace()) << "findPaths start"; if (mDstAmount == beast::zero) @@ -213,8 +183,7 @@ Pathfinder::findPaths( // below - why don't we do it each time we return false? } - if (mSrcAccount == mDstAccount && mDstAccount == mEffectiveDst && - mSrcCurrency == mDstAmount.getCurrency()) + if (mSrcAccount == mDstAccount && mDstAccount == mEffectiveDst && mSrcCurrency == mDstAmount.getCurrency()) { // No need to send to same account with same currency. JLOG(j_.debug()) << "Tried to send to same issuer"; @@ -222,8 +191,7 @@ Pathfinder::findPaths( return false; } - if (mSrcAccount == mEffectiveDst && - mSrcCurrency == mDstAmount.getCurrency()) + if (mSrcAccount == mEffectiveDst && mSrcCurrency == mDstAmount.getCurrency()) { // Default path might work, but any path would loop return true; @@ -236,13 +204,10 @@ Pathfinder::findPaths( auto& account = useIssuerAccount ? *mSrcIssuer : mSrcAccount; auto issuer = currencyIsXRP ? AccountID() : account; mSource = STPathElement(account, mSrcCurrency, issuer); - auto issuerString = - mSrcIssuer ? to_string(*mSrcIssuer) : std::string("none"); + auto issuerString = mSrcIssuer ? to_string(*mSrcIssuer) : std::string("none"); JLOG(j_.trace()) << "findPaths>" - << " mSrcAccount=" << mSrcAccount - << " mDstAccount=" << mDstAccount - << " mDstAmount=" << mDstAmount.getFullText() - << " mSrcCurrency=" << mSrcCurrency + << " mSrcAccount=" << mSrcAccount << " mDstAccount=" << mDstAccount + << " mDstAmount=" << mDstAmount.getFullText() << " mSrcCurrency=" << mSrcCurrency << " mSrcIssuer=" << issuerString; if (!mLedger) @@ -261,8 +226,7 @@ Pathfinder::findPaths( return false; } - if ((mEffectiveDst != mDstAccount) && - !mLedger->exists(keylet::account(mEffectiveDst))) + if ((mEffectiveDst != mDstAccount) && !mLedger->exists(keylet::account(mEffectiveDst))) { JLOG(j_.debug()) << "Non-existent gateway"; return false; @@ -281,9 +245,7 @@ Pathfinder::findPaths( auto const reserve = STAmount(mLedger->fees().reserve); if (mDstAmount < reserve) { - JLOG(j_.debug()) - << "New account not getting enough funding: " << mDstAmount - << " < " << reserve; + JLOG(j_.debug()) << "New account not getting enough funding: " << mDstAmount << " < " << reserve; return false; } } @@ -368,15 +330,7 @@ Pathfinder::getPathLiquidity( rcInput.partialPaymentAllowed = true; auto rc = path::RippleCalc::rippleCalculate( - sandbox, - mSrcAmount, - minDstAmount, - mDstAccount, - mSrcAccount, - pathSet, - mDomain, - app_.logs(), - &rcInput); + sandbox, mSrcAmount, minDstAmount, mDstAccount, mSrcAccount, pathSet, mDomain, app_.logs(), &rcInput); // If we can't get even the minimum liquidity requested, we're done. if (rc.result() != tesSUCCESS) return rc.result(); @@ -408,16 +362,13 @@ Pathfinder::getPathLiquidity( } catch (std::exception const& e) { - JLOG(j_.info()) << "checkpath: exception (" << e.what() << ") " - << path.getJson(JsonOptions::none); + JLOG(j_.info()) << "checkpath: exception (" << e.what() << ") " << path.getJson(JsonOptions::none); return tefEXCEPTION; } } void -Pathfinder::computePathRanks( - int maxPaths, - std::function const& continueCallback) +Pathfinder::computePathRanks(int maxPaths, std::function const& continueCallback) { mRemainingAmount = convertAmount(mDstAmount, convert_all_); @@ -441,14 +392,12 @@ Pathfinder::computePathRanks( if (rc.result() == tesSUCCESS) { - JLOG(j_.debug()) - << "Default path contributes: " << rc.actualAmountIn; + JLOG(j_.debug()) << "Default path contributes: " << rc.actualAmountIn; mRemainingAmount -= rc.actualAmountOut; } else { - JLOG(j_.debug()) - << "Default path fails: " << transToken(rc.result()); + JLOG(j_.debug()) << "Default path fails: " << transToken(rc.result()); } } catch (std::exception const&) @@ -500,8 +449,7 @@ Pathfinder::rankPaths( std::vector& rankedPaths, std::function const& continueCallback) { - JLOG(j_.trace()) << "rankPaths with " << paths.size() << " candidates, and " - << maxPaths << " maximum"; + JLOG(j_.trace()) << "rankPaths with " << paths.size() << " candidates, and " << maxPaths << " maximum"; rankedPaths.clear(); rankedPaths.reserve(paths.size()); @@ -526,21 +474,18 @@ Pathfinder::rankPaths( { STAmount liquidity; uint64_t uQuality; - auto const resultCode = getPathLiquidity( - currentPath, saMinDstAmount, liquidity, uQuality); + auto const resultCode = getPathLiquidity(currentPath, saMinDstAmount, liquidity, uQuality); if (resultCode != tesSUCCESS) { - JLOG(j_.debug()) - << "findPaths: dropping : " << transToken(resultCode) - << ": " << currentPath.getJson(JsonOptions::none); + JLOG(j_.debug()) << "findPaths: dropping : " << transToken(resultCode) << ": " + << currentPath.getJson(JsonOptions::none); } else { JLOG(j_.debug()) << "findPaths: quality: " << uQuality << ": " << currentPath.getJson(JsonOptions::none); - rankedPaths.push_back( - {uQuality, currentPath.size(), liquidity, i}); + rankedPaths.push_back({uQuality, currentPath.size(), liquidity, i}); } } } @@ -551,9 +496,7 @@ Pathfinder::rankPaths( // length of path // A better PathRank is lower, best are sorted to the beginning. std::sort( - rankedPaths.begin(), - rankedPaths.end(), - [&](Pathfinder::PathRank const& a, Pathfinder::PathRank const& b) { + rankedPaths.begin(), rankedPaths.end(), [&](Pathfinder::PathRank const& a, Pathfinder::PathRank const& b) { // 1) Higher quality (lower cost) is better if (!convert_all_ && a.quality != b.quality) return a.quality < b.quality; @@ -579,17 +522,13 @@ Pathfinder::getBestPaths( AccountID const& srcIssuer, std::function const& continueCallback) { - JLOG(j_.debug()) << "findPaths: " << mCompletePaths.size() << " paths and " - << extraPaths.size() << " extras"; + JLOG(j_.debug()) << "findPaths: " << mCompletePaths.size() << " paths and " << extraPaths.size() << " extras"; if (mCompletePaths.empty() && extraPaths.empty()) return mCompletePaths; - XRPL_ASSERT( - fullLiquidityPath.empty(), - "ripple::Pathfinder::getBestPaths : first empty path result"); - bool const issuerIsSender = - isXRP(mSrcCurrency) || (srcIssuer == mSrcAccount); + XRPL_ASSERT(fullLiquidityPath.empty(), "xrpl::Pathfinder::getBestPaths : first empty path result"); + bool const issuerIsSender = isXRP(mSrcCurrency) || (srcIssuer == mSrcAccount); std::vector extraPathRanks; rankPaths(maxPaths, extraPaths, extraPathRanks, continueCallback); @@ -604,8 +543,7 @@ Pathfinder::getBestPaths( auto pathsIterator = mPathRanks.begin(); auto extraPathsIterator = extraPathRanks.begin(); - while (pathsIterator != mPathRanks.end() || - extraPathsIterator != extraPathRanks.end()) + while (pathsIterator != mPathRanks.end() || extraPathsIterator != extraPathRanks.end()) { if (continueCallback && !continueCallback()) break; @@ -633,8 +571,7 @@ Pathfinder::getBestPaths( auto& pathRank = usePath ? *pathsIterator : *extraPathsIterator; - auto const& path = usePath ? mCompletePaths[pathRank.index] - : extraPaths[pathRank.index]; + auto const& path = usePath ? mCompletePaths[pathRank.index] : extraPaths[pathRank.index]; if (useExtraPath) ++extraPathsIterator; @@ -649,7 +586,7 @@ Pathfinder::getBestPaths( if (path.empty()) { // LCOV_EXCL_START - UNREACHABLE("ripple::Pathfinder::getBestPaths : path not found"); + UNREACHABLE("xrpl::Pathfinder::getBestPaths : path not found"); continue; // LCOV_EXCL_STOP } @@ -667,42 +604,33 @@ Pathfinder::getBestPaths( startsWithIssuer = true; } - if (iPathsLeft > 1 || - (iPathsLeft > 0 && pathRank.liquidity >= remaining)) + if (iPathsLeft > 1 || (iPathsLeft > 0 && pathRank.liquidity >= remaining)) // last path must fill { --iPathsLeft; remaining -= pathRank.liquidity; bestPaths.push_back(startsWithIssuer ? removeIssuer(path) : path); } - else if ( - iPathsLeft == 0 && pathRank.liquidity >= mDstAmount && - fullLiquidityPath.empty()) + else if (iPathsLeft == 0 && pathRank.liquidity >= mDstAmount && fullLiquidityPath.empty()) { // We found an extra path that can move the whole amount. fullLiquidityPath = (startsWithIssuer ? removeIssuer(path) : path); - JLOG(j_.debug()) << "Found extra full path: " - << fullLiquidityPath.getJson(JsonOptions::none); + JLOG(j_.debug()) << "Found extra full path: " << fullLiquidityPath.getJson(JsonOptions::none); } else { - JLOG(j_.debug()) << "Skipping a non-filling path: " - << path.getJson(JsonOptions::none); + JLOG(j_.debug()) << "Skipping a non-filling path: " << path.getJson(JsonOptions::none); } } if (remaining > beast::zero) { - XRPL_ASSERT( - fullLiquidityPath.empty(), - "ripple::Pathfinder::getBestPaths : second empty path result"); - JLOG(j_.info()) << "Paths could not send " << remaining << " of " - << mDstAmount; + XRPL_ASSERT(fullLiquidityPath.empty(), "xrpl::Pathfinder::getBestPaths : second empty path result"); + JLOG(j_.info()) << "Paths could not send " << remaining << " of " << mDstAmount; } else { - JLOG(j_.debug()) << "findPaths: RESULTS: " - << bestPaths.getJson(JsonOptions::none); + JLOG(j_.debug()) << "findPaths: RESULTS: " << bestPaths.getJson(JsonOptions::none); } return bestPaths; } @@ -711,9 +639,8 @@ bool Pathfinder::issueMatchesOrigin(Issue const& issue) { bool matchingCurrency = (issue.currency == mSrcCurrency); - bool matchingAccount = isXRP(issue.currency) || - (mSrcIssuer && issue.account == mSrcIssuer) || - issue.account == mSrcAccount; + bool matchingAccount = + isXRP(issue.currency) || (mSrcIssuer && issue.account == mSrcIssuer) || issue.account == mSrcAccount; return matchingCurrency && matchingAccount; } @@ -759,13 +686,11 @@ Pathfinder::getPathsOut( } else if ( rspEntry.getBalance() <= beast::zero && - (!rspEntry.getLimitPeer() || - -rspEntry.getBalance() >= rspEntry.getLimitPeer() || + (!rspEntry.getLimitPeer() || -rspEntry.getBalance() >= rspEntry.getLimitPeer() || (bAuthRequired && !rspEntry.getAuth()))) { } - else if ( - isDstCurrency && dstAccount == rspEntry.getAccountIDPeer()) + else if (isDstCurrency && dstAccount == rspEntry.getAccountIDPeer()) { count += 10000; // count a path to the destination extra } @@ -795,8 +720,7 @@ Pathfinder::addLinks( int addFlags, std::function const& continueCallback) { - JLOG(j_.debug()) << "addLink< on " << currentPaths.size() - << " source(s), flags=" << addFlags; + JLOG(j_.debug()) << "addLink< on " << currentPaths.size() << " source(s), flags=" << addFlags; for (auto const& path : currentPaths) { if (continueCallback && !continueCallback()) @@ -806,12 +730,9 @@ Pathfinder::addLinks( } STPathSet& -Pathfinder::addPathsForType( - PathType const& pathType, - std::function const& continueCallback) +Pathfinder::addPathsForType(PathType const& pathType, std::function const& continueCallback) { - JLOG(j_.debug()) << "addPathsForType " - << CollectionAndDelimiter(pathType, ", "); + JLOG(j_.debug()) << "addPathsForType " << CollectionAndDelimiter(pathType, ", "); // See if the set of paths for this type already exists. auto it = mPaths.find(pathType); if (it != mPaths.end()) @@ -828,12 +749,10 @@ Pathfinder::addPathsForType( PathType parentPathType = pathType; parentPathType.pop_back(); - STPathSet const& parentPaths = - addPathsForType(parentPathType, continueCallback); + STPathSet const& parentPaths = addPathsForType(parentPathType, continueCallback); STPathSet& pathsOut = mPaths[pathType]; - JLOG(j_.debug()) << "getPaths< adding onto '" - << pathTypeToString(parentPathType) << "' to get '" + JLOG(j_.debug()) << "getPaths< adding onto '" << pathTypeToString(parentPathType) << "' to get '" << pathTypeToString(pathType) << "'"; int initialSize = mCompletePaths.size(); @@ -844,9 +763,7 @@ Pathfinder::addPathsForType( { case nt_SOURCE: // Source must always be at the start, so pathsOut has to be empty. - XRPL_ASSERT( - pathsOut.empty(), - "ripple::Pathfinder::addPathsForType : empty paths"); + XRPL_ASSERT(pathsOut.empty(), "xrpl::Pathfinder::addPathsForType : empty paths"); pathsOut.push_back(STPath()); break; @@ -859,55 +776,36 @@ Pathfinder::addPathsForType( break; case nt_XRP_BOOK: - addLinks( - parentPaths, - pathsOut, - afADD_BOOKS | afOB_XRP, - continueCallback); + addLinks(parentPaths, pathsOut, afADD_BOOKS | afOB_XRP, continueCallback); break; case nt_DEST_BOOK: - addLinks( - parentPaths, - pathsOut, - afADD_BOOKS | afOB_LAST, - continueCallback); + addLinks(parentPaths, pathsOut, afADD_BOOKS | afOB_LAST, continueCallback); break; case nt_DESTINATION: // FIXME: What if a different issuer was specified on the // destination amount? // TODO(tom): what does this even mean? Should it be a JIRA? - addLinks( - parentPaths, - pathsOut, - afADD_ACCOUNTS | afAC_LAST, - continueCallback); + addLinks(parentPaths, pathsOut, afADD_ACCOUNTS | afAC_LAST, continueCallback); break; } if (mCompletePaths.size() != initialSize) { - JLOG(j_.debug()) << (mCompletePaths.size() - initialSize) - << " complete paths added"; + JLOG(j_.debug()) << (mCompletePaths.size() - initialSize) << " complete paths added"; } - JLOG(j_.debug()) << "getPaths> " << pathsOut.size() - << " partial paths found"; + JLOG(j_.debug()) << "getPaths> " << pathsOut.size() << " partial paths found"; return pathsOut; } bool -Pathfinder::isNoRipple( - AccountID const& fromAccount, - AccountID const& toAccount, - Currency const& currency) +Pathfinder::isNoRipple(AccountID const& fromAccount, AccountID const& toAccount, Currency const& currency) { - auto sleRipple = - mLedger->read(keylet::line(toAccount, fromAccount, currency)); + auto sleRipple = mLedger->read(keylet::line(toAccount, fromAccount, currency)); - auto const flag( - (toAccount > fromAccount) ? lsfHighNoRipple : lsfLowNoRipple); + auto const flag((toAccount > fromAccount) ? lsfHighNoRipple : lsfLowNoRipple); return sleRipple && (sleRipple->getFieldU32(sfFlags) & flag); } @@ -929,9 +827,7 @@ Pathfinder::isNoRippleOut(STPath const& currentPath) // If there's only one item in the path, return true if that item specifies // no ripple on the output. A path with no ripple on its output can't be // followed by a link with no ripple on its input. - auto const& fromAccount = (currentPath.size() == 1) - ? mSrcAccount - : (currentPath.end() - 2)->getAccountID(); + auto const& fromAccount = (currentPath.size() == 1) ? mSrcAccount : (currentPath.end() - 2)->getAccountID(); auto const& toAccount = endElement.getAccountID(); return isNoRipple(fromAccount, toAccount, endElement.getCurrency()); } @@ -978,8 +874,7 @@ Pathfinder::addLink( { if (mDstAmount.native() && !currentPath.empty()) { // non-default path to XRP destination - JLOG(j_.trace()) << "complete path found ax: " - << currentPath.getJson(JsonOptions::none); + JLOG(j_.trace()) << "complete path found ax: " << currentPath.getJson(JsonOptions::none); addUniquePath(mCompletePaths, currentPath); } } @@ -990,17 +885,13 @@ Pathfinder::addLink( if (sleEnd) { - bool const bRequireAuth( - sleEnd->getFieldU32(sfFlags) & lsfRequireAuth); - bool const bIsEndCurrency( - uEndCurrency == mDstAmount.getCurrency()); + bool const bRequireAuth(sleEnd->getFieldU32(sfFlags) & lsfRequireAuth); + bool const bIsEndCurrency(uEndCurrency == mDstAmount.getCurrency()); bool const bIsNoRippleOut(isNoRippleOut(currentPath)); bool const bDestOnly(addFlags & afAC_LAST); if (auto const lines = mRLCache->getRippleLines( - uEndAccount, - bIsNoRippleOut ? LineDirection::incoming - : LineDirection::outgoing)) + uEndAccount, bIsNoRippleOut ? LineDirection::incoming : LineDirection::outgoing)) { auto& rippleLines = *lines; @@ -1033,8 +924,7 @@ Pathfinder::addLink( // path is for correct currency and has not been // seen if (rs.getBalance() <= beast::zero && - (!rs.getLimitPeer() || - -rs.getBalance() >= rs.getLimitPeer() || + (!rs.getLimitPeer() || -rs.getBalance() >= rs.getLimitPeer() || (bRequireAuth && !rs.getAuth()))) { // path has no credit @@ -1052,18 +942,14 @@ Pathfinder::addLink( if (!currentPath.empty()) { JLOG(j_.trace()) - << "complete path found ae: " - << currentPath.getJson( - JsonOptions::none); - addUniquePath( - mCompletePaths, currentPath); + << "complete path found ae: " << currentPath.getJson(JsonOptions::none); + addUniquePath(mCompletePaths, currentPath); } } else if (!bDestOnly) { // this is a high-priority candidate - candidates.push_back( - {AccountCandidate::highPriority, acct}); + candidates.push_back({AccountCandidate::highPriority, acct}); } } else if (acct == mSrcAccount) @@ -1074,12 +960,7 @@ Pathfinder::addLink( { // save this candidate int out = getPathsOut( - uEndCurrency, - acct, - direction, - bIsEndCurrency, - mEffectiveDst, - continueCallback); + uEndCurrency, acct, direction, bIsEndCurrency, mEffectiveDst, continueCallback); if (out) candidates.push_back({out, acct}); } @@ -1092,10 +973,7 @@ Pathfinder::addLink( candidates.begin(), candidates.end(), std::bind( - compareAccountCandidate, - mLedger->seq(), - std::placeholders::_1, - std::placeholders::_2)); + compareAccountCandidate, mLedger->seq(), std::placeholders::_1, std::placeholders::_2)); int count = candidates.size(); // allow more paths from source @@ -1111,12 +989,8 @@ Pathfinder::addLink( return; // Add accounts to incompletePaths STPathElement pathElement( - STPathElement::typeAccount, - it->account, - uEndCurrency, - it->account); - incompletePaths.assembleAdd( - currentPath, pathElement); + STPathElement::typeAccount, it->account, uEndCurrency, it->account); + incompletePaths.assembleAdd(currentPath, pathElement); ++it; } } @@ -1134,35 +1008,24 @@ Pathfinder::addLink( if (addFlags & afOB_XRP) { // to XRP only - if (!bOnXRP && - app_.getOrderBookDB().isBookToXRP( - {uEndCurrency, uEndIssuer}, mDomain)) + if (!bOnXRP && app_.getOrderBookDB().isBookToXRP({uEndCurrency, uEndIssuer}, mDomain)) { - STPathElement pathElement( - STPathElement::typeCurrency, - xrpAccount(), - xrpCurrency(), - xrpAccount()); + STPathElement pathElement(STPathElement::typeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()); incompletePaths.assembleAdd(currentPath, pathElement); } } else { bool bDestOnly = (addFlags & afOB_LAST) != 0; - auto books = app_.getOrderBookDB().getBooksByTakerPays( - {uEndCurrency, uEndIssuer}, mDomain); - JLOG(j_.trace()) - << books.size() << " books found from this currency/issuer"; + auto books = app_.getOrderBookDB().getBooksByTakerPays({uEndCurrency, uEndIssuer}, mDomain); + JLOG(j_.trace()) << books.size() << " books found from this currency/issuer"; for (auto const& book : books) { if (continueCallback && !continueCallback()) return; - if (!currentPath.hasSeen( - xrpAccount(), book.out.currency, book.out.account) && - !issueMatchesOrigin(book.out) && - (!bDestOnly || - (book.out.currency == mDstAmount.getCurrency()))) + if (!currentPath.hasSeen(xrpAccount(), book.out.currency, book.out.account) && + !issueMatchesOrigin(book.out) && (!bDestOnly || (book.out.currency == mDstAmount.getCurrency()))) { STPath newPath(currentPath); @@ -1170,39 +1033,28 @@ Pathfinder::addLink( { // to XRP // add the order book itself - newPath.emplace_back( - STPathElement::typeCurrency, - xrpAccount(), - xrpCurrency(), - xrpAccount()); + newPath.emplace_back(STPathElement::typeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()); if (mDstAmount.getCurrency().isZero()) { // destination is XRP, add account and path is // complete - JLOG(j_.trace()) - << "complete path found bx: " - << currentPath.getJson(JsonOptions::none); + JLOG(j_.trace()) << "complete path found bx: " << currentPath.getJson(JsonOptions::none); addUniquePath(mCompletePaths, newPath); } else incompletePaths.push_back(newPath); } - else if (!currentPath.hasSeen( - book.out.account, - book.out.currency, - book.out.account)) + else if (!currentPath.hasSeen(book.out.account, book.out.currency, book.out.account)) { // Don't want the book if we've already seen the issuer // book -> account -> book - if ((newPath.size() >= 2) && - (newPath.back().isAccount()) && + if ((newPath.size() >= 2) && (newPath.back().isAccount()) && (newPath[newPath.size() - 2].isOffer())) { // replace the redundant account with the order book newPath[newPath.size() - 1] = STPathElement( - STPathElement::typeCurrency | - STPathElement::typeIssuer, + STPathElement::typeCurrency | STPathElement::typeIssuer, xrpAccount(), book.out.currency, book.out.account); @@ -1211,27 +1063,21 @@ Pathfinder::addLink( { // add the order book newPath.emplace_back( - STPathElement::typeCurrency | - STPathElement::typeIssuer, + STPathElement::typeCurrency | STPathElement::typeIssuer, xrpAccount(), book.out.currency, book.out.account); } - if (hasEffectiveDestination && - book.out.account == mDstAccount && + if (hasEffectiveDestination && book.out.account == mDstAccount && book.out.currency == mDstAmount.getCurrency()) { // We skipped a required issuer } - else if ( - book.out.account == mEffectiveDst && - book.out.currency == mDstAmount.getCurrency()) + else if (book.out.account == mEffectiveDst && book.out.currency == mDstAmount.getCurrency()) { // with the destination account, this path is // complete - JLOG(j_.trace()) - << "complete path found ba: " - << currentPath.getJson(JsonOptions::none); + JLOG(j_.trace()) << "complete path found ba: " << currentPath.getJson(JsonOptions::none); addUniquePath(mCompletePaths, newPath); } else @@ -1240,10 +1086,7 @@ Pathfinder::addLink( incompletePaths.assembleAdd( newPath, STPathElement( - STPathElement::typeAccount, - book.out.account, - book.out.currency, - book.out.account)); + STPathElement::typeAccount, book.out.account, book.out.currency, book.out.account)); } } } @@ -1299,7 +1142,7 @@ void fillPaths(Pathfinder::PaymentType type, PathCostList const& costs) { auto& list = mPathTable[type]; - XRPL_ASSERT(list.empty(), "ripple::fillPaths : empty paths"); + XRPL_ASSERT(list.empty(), "xrpl::fillPaths : empty paths"); for (auto& cost : costs) list.push_back({cost.cost, makePath(cost.path)}); } @@ -1311,7 +1154,7 @@ fillPaths(Pathfinder::PaymentType type, PathCostList const& costs) // 1 = include trivial paths to make common cases work // 4 = normal fast search level // 7 = normal slow search level -// 10 = most agressive +// 10 = most aggressive void Pathfinder::initPathTable() @@ -1320,6 +1163,7 @@ Pathfinder::initPathTable() mPathTable.clear(); fillPaths(pt_XRP_to_XRP, {}); + /* cspell: disable */ fillPaths( pt_XRP_to_nonXRP, @@ -1376,6 +1220,7 @@ Pathfinder::initPathTable() {8, "saafad"}, {9, "safaad"}, }); + /* cspell: enable */ } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/Pathfinder.h b/src/xrpld/app/paths/Pathfinder.h index b6c8bb8b2d..03f2d6f038 100644 --- a/src/xrpld/app/paths/Pathfinder.h +++ b/src/xrpld/app/paths/Pathfinder.h @@ -1,34 +1,14 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_PATHFINDER_H_INCLUDED -#define RIPPLE_APP_PATHS_PATHFINDER_H_INCLUDED +#pragma once #include #include -#include #include +#include #include #include -namespace ripple { +namespace xrpl { /** Calculates payment paths. @@ -59,15 +39,11 @@ public: initPathTable(); bool - findPaths( - int searchLevel, - std::function const& continueCallback = {}); + findPaths(int searchLevel, std::function const& continueCallback = {}); /** Compute the rankings of the paths. */ void - computePathRanks( - int maxPaths, - std::function const& continueCallback = {}); + computePathRanks(int maxPaths, std::function const& continueCallback = {}); /* Get the best paths, up to maxPaths in number, from mCompletePaths. @@ -83,11 +59,11 @@ public: std::function const& continueCallback = {}); enum NodeType { - nt_SOURCE, // The source account: with an issuer account, if needed. - nt_ACCOUNTS, // Accounts that connect from this source/currency. - nt_BOOKS, // Order books that connect to this currency. - nt_XRP_BOOK, // The order book from this currency to XRP. - nt_DEST_BOOK, // The order book to the destination currency/issuer. + nt_SOURCE, // The source account: with an issuer account, if needed. + nt_ACCOUNTS, // Accounts that connect from this source/currency. + nt_BOOKS, // Order books that connect to this currency. + nt_XRP_BOOK, // The order book from this currency to XRP. + nt_DEST_BOOK, // The order book to the destination currency/issuer. nt_DESTINATION // The destination account only. }; @@ -135,9 +111,7 @@ private: // Add all paths of one type to mCompletePaths. STPathSet& - addPathsForType( - PathType const& type, - std::function const& continueCallback); + addPathsForType(PathType const& type, std::function const& continueCallback); bool issueMatchesOrigin(Issue const&); @@ -183,10 +157,7 @@ private: // Is the "no ripple" flag set from one account to another? bool - isNoRipple( - AccountID const& fromAccount, - AccountID const& toAccount, - Currency const& currency); + isNoRipple(AccountID const& fromAccount, AccountID const& toAccount, Currency const& currency); void rankPaths( @@ -238,6 +209,4 @@ private: static std::uint32_t const afAC_LAST = 0x080; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/RippleCalc.cpp b/src/xrpld/app/paths/RippleCalc.cpp index 237f0b8f9c..0667e1971c 100644 --- a/src/xrpld/app/paths/RippleCalc.cpp +++ b/src/xrpld/app/paths/RippleCalc.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -25,7 +6,7 @@ #include #include -namespace ripple { +namespace xrpl { namespace path { RippleCalc::Output @@ -62,32 +43,19 @@ RippleCalc::rippleCalculate( PaymentSandbox flowSB(&view); auto j = l.journal("Flow"); - if (!view.rules().enabled(featureFlow)) { - // The new payment engine was enabled several years ago. New transaction - // should never use the old rules. Assume this is a replay - j.fatal() - << "Old payment rules are required for this transaction. Assuming " - "this is a replay and running with the new rules."; - } + bool const defaultPaths = !pInputs ? true : pInputs->defaultPathsAllowed; - { - bool const defaultPaths = - !pInputs ? true : pInputs->defaultPathsAllowed; - - bool const partialPayment = - !pInputs ? false : pInputs->partialPaymentAllowed; + bool const partialPayment = !pInputs ? false : pInputs->partialPaymentAllowed; auto const limitQuality = [&]() -> std::optional { - if (pInputs && pInputs->limitQuality && - saMaxAmountReq > beast::zero) + if (pInputs && pInputs->limitQuality && saMaxAmountReq > beast::zero) return Quality{Amounts(saMaxAmountReq, saDstAmountReq)}; return std::nullopt; }(); auto const sendMax = [&]() -> std::optional { - if (saMaxAmountReq >= beast::zero || - saMaxAmountReq.getCurrency() != saDstAmountReq.getCurrency() || + if (saMaxAmountReq >= beast::zero || saMaxAmountReq.getCurrency() != saDstAmountReq.getCurrency() || saMaxAmountReq.getIssuer() != uSrcAccountID) { return saMaxAmountReq; @@ -125,10 +93,8 @@ RippleCalc::rippleCalculate( } j.debug() << "RippleCalc Result> " - << " actualIn: " << flowOut.actualAmountIn - << ", actualOut: " << flowOut.actualAmountOut - << ", result: " << flowOut.result() - << ", dstAmtReq: " << saDstAmountReq + << " actualIn: " << flowOut.actualAmountIn << ", actualOut: " << flowOut.actualAmountOut + << ", result: " << flowOut.result() << ", dstAmtReq: " << saDstAmountReq << ", sendMax: " << saMaxAmountReq; flowSB.apply(view); @@ -136,4 +102,4 @@ RippleCalc::rippleCalculate( } } // namespace path -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/RippleCalc.h b/src/xrpld/app/paths/RippleCalc.h index 527c26f2ca..a5cecc18bf 100644 --- a/src/xrpld/app/paths/RippleCalc.h +++ b/src/xrpld/app/paths/RippleCalc.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED -#define RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED +#pragma once #include #include @@ -27,7 +7,7 @@ #include -namespace ripple { +namespace xrpl { class Config; namespace path { @@ -126,6 +106,4 @@ public: }; } // namespace path -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp index f047dc9500..aaef368cff 100644 --- a/src/xrpld/app/paths/RippleLineCache.cpp +++ b/src/xrpld/app/paths/RippleLineCache.cpp @@ -1,54 +1,27 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { -RippleLineCache::RippleLineCache( - std::shared_ptr const& ledger, - beast::Journal j) +RippleLineCache::RippleLineCache(std::shared_ptr const& ledger, beast::Journal j) : ledger_(ledger), journal_(j) { - JLOG(journal_.debug()) << "created for ledger " << ledger_->info().seq; + JLOG(journal_.debug()) << "created for ledger " << ledger_->header().seq; } RippleLineCache::~RippleLineCache() { - JLOG(journal_.debug()) << "destroyed for ledger " << ledger_->info().seq - << " with " << lines_.size() << " accounts and " - << totalLineCount_ << " distinct trust lines."; + JLOG(journal_.debug()) << "destroyed for ledger " << ledger_->header().seq << " with " << lines_.size() + << " accounts and " << totalLineCount_ << " distinct trust lines."; } std::shared_ptr> -RippleLineCache::getRippleLines( - AccountID const& accountID, - LineDirection direction) +RippleLineCache::getRippleLines(AccountID const& accountID, LineDirection direction) { auto const hash = hasher_(accountID); AccountKey key(accountID, direction, hash); AccountKey otherkey( - accountID, - direction == LineDirection::outgoing ? LineDirection::incoming - : LineDirection::outgoing, - hash); + accountID, direction == LineDirection::outgoing ? LineDirection::incoming : LineDirection::outgoing, hash); std::lock_guard sl(mLock); @@ -59,18 +32,13 @@ RippleLineCache::getRippleLines( // number of trust line objects held in memory. Ensure that there is // only a single set of trustlines in the cache per account. auto const size = otheriter->second ? otheriter->second->size() : 0; - JLOG(journal_.info()) - << "Request for " - << (direction == LineDirection::outgoing ? "outgoing" - : "incoming") - << " trust lines for account " << accountID << " found " << size - << (direction == LineDirection::outgoing ? " incoming" - : " outgoing") - << " trust lines. " - << (direction == LineDirection::outgoing - ? "Deleting the subset of incoming" - : "Returning the superset of outgoing") - << " trust lines. "; + JLOG(journal_.info()) << "Request for " << (direction == LineDirection::outgoing ? "outgoing" : "incoming") + << " trust lines for account " << accountID << " found " << size + << (direction == LineDirection::outgoing ? " incoming" : " outgoing") + << " trust lines. " + << (direction == LineDirection::outgoing ? "Deleting the subset of incoming" + : "Returning the superset of outgoing") + << " trust lines. "; if (direction == LineDirection::outgoing) { // This request is for the outgoing set, but there is already a @@ -78,9 +46,7 @@ RippleLineCache::getRippleLines( // to be replaced by the full set. The full set will be built // below, and will be returned, if needed, on subsequent calls // for either value of outgoing. - XRPL_ASSERT( - size <= totalLineCount_, - "ripple::RippleLineCache::getRippleLines : maximum lines"); + XRPL_ASSERT(size <= totalLineCount_, "xrpl::RippleLineCache::getRippleLines : maximum lines"); totalLineCount_ -= size; lines_.erase(otheriter); } @@ -100,34 +66,24 @@ RippleLineCache::getRippleLines( if (inserted) { - XRPL_ASSERT( - it->second == nullptr, - "ripple::RippleLineCache::getRippleLines : null lines"); - auto lines = - PathFindTrustLine::getItems(accountID, *ledger_, direction); + XRPL_ASSERT(it->second == nullptr, "xrpl::RippleLineCache::getRippleLines : null lines"); + auto lines = PathFindTrustLine::getItems(accountID, *ledger_, direction); if (lines.size()) { - it->second = std::make_shared>( - std::move(lines)); + it->second = std::make_shared>(std::move(lines)); totalLineCount_ += it->second->size(); } } XRPL_ASSERT( - !it->second || (it->second->size() > 0), - "ripple::RippleLineCache::getRippleLines : null or nonempty lines"); + !it->second || (it->second->size() > 0), "xrpl::RippleLineCache::getRippleLines : null or nonempty lines"); auto const size = it->second ? it->second->size() : 0; - JLOG(journal_.trace()) << "getRippleLines for ledger " - << ledger_->info().seq << " found " << size - << (key.direction_ == LineDirection::outgoing - ? " outgoing" - : " incoming") - << " lines for " << (inserted ? "new " : "existing ") - << accountID << " out of a total of " - << lines_.size() << " accounts and " - << totalLineCount_ << " trust lines"; + JLOG(journal_.trace()) << "getRippleLines for ledger " << ledger_->header().seq << " found " << size + << (key.direction_ == LineDirection::outgoing ? " outgoing" : " incoming") << " lines for " + << (inserted ? "new " : "existing ") << accountID << " out of a total of " << lines_.size() + << " accounts and " << totalLineCount_ << " trust lines"; return it->second; } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/RippleLineCache.h b/src/xrpld/app/paths/RippleLineCache.h index 6196211a70..5dbdb414ee 100644 --- a/src/xrpld/app/paths/RippleLineCache.h +++ b/src/xrpld/app/paths/RippleLineCache.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED -#define RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED +#pragma once #include #include @@ -30,15 +10,13 @@ #include #include -namespace ripple { +namespace xrpl { // Used by Pathfinder class RippleLineCache final : public CountedObject { public: - explicit RippleLineCache( - std::shared_ptr const& l, - beast::Journal j); + explicit RippleLineCache(std::shared_ptr const& l, beast::Journal j); ~RippleLineCache(); std::shared_ptr const& @@ -65,7 +43,7 @@ public: private: std::mutex mLock; - ripple::hardened_hash<> hasher_; + xrpl::hardened_hash<> hasher_; std::shared_ptr ledger_; beast::Journal journal_; @@ -76,10 +54,7 @@ private: LineDirection direction_; std::size_t hash_value_; - AccountKey( - AccountID const& account, - LineDirection direction, - std::size_t hash) + AccountKey(AccountID const& account, LineDirection direction, std::size_t hash) : account_(account), direction_(direction), hash_value_(hash) { } @@ -92,8 +67,7 @@ private: bool operator==(AccountKey const& lhs) const { - return hash_value_ == lhs.hash_value_ && account_ == lhs.account_ && - direction_ == lhs.direction_; + return hash_value_ == lhs.hash_value_ && account_ == lhs.account_ && direction_ == lhs.direction_; } std::size_t @@ -119,14 +93,8 @@ private: // most accounts are not going to have any entries (estimated over 90%), so // vectors will not need to be created for them. This should lead to far // less memory usage overall. - hash_map< - AccountKey, - std::shared_ptr>, - AccountKey::Hash> - lines_; + hash_map>, AccountKey::Hash> lines_; std::size_t totalLineCount_ = 0; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/TrustLine.cpp b/src/xrpld/app/paths/TrustLine.cpp index 28572b899e..f34dcbdf81 100644 --- a/src/xrpld/app/paths/TrustLine.cpp +++ b/src/xrpld/app/paths/TrustLine.cpp @@ -1,33 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { -TrustLineBase::TrustLineBase( - std::shared_ptr const& sle, - AccountID const& viewAccount) +TrustLineBase::TrustLineBase(std::shared_ptr const& sle, AccountID const& viewAccount) : key_(sle->key()) , mLowLimit(sle->getFieldAmount(sfLowLimit)) , mHighLimit(sle->getFieldAmount(sfHighLimit)) @@ -49,9 +28,7 @@ TrustLineBase::getJson(int) } std::optional -PathFindTrustLine::makeItem( - AccountID const& accountID, - std::shared_ptr const& sle) +PathFindTrustLine::makeItem(AccountID const& accountID, std::shared_ptr const& sle) { if (!sle || sle->getType() != ltRIPPLE_STATE) return {}; @@ -61,22 +38,14 @@ PathFindTrustLine::makeItem( namespace detail { template std::vector -getTrustLineItems( - AccountID const& accountID, - ReadView const& view, - LineDirection direction = LineDirection::outgoing) +getTrustLineItems(AccountID const& accountID, ReadView const& view, LineDirection direction = LineDirection::outgoing) { std::vector items; - forEachItem( - view, - accountID, - [&items, &accountID, &direction]( - std::shared_ptr const& sleCur) { - auto ret = T::makeItem(accountID, sleCur); - if (ret && - (direction == LineDirection::outgoing || !ret->getNoRipple())) - items.push_back(std::move(*ret)); - }); + forEachItem(view, accountID, [&items, &accountID, &direction](std::shared_ptr const& sleCur) { + auto ret = T::makeItem(accountID, sleCur); + if (ret && (direction == LineDirection::outgoing || !ret->getNoRipple())) + items.push_back(std::move(*ret)); + }); // This list may be around for a while, so free up any unneeded // capacity items.shrink_to_fit(); @@ -86,18 +55,12 @@ getTrustLineItems( } // namespace detail std::vector -PathFindTrustLine::getItems( - AccountID const& accountID, - ReadView const& view, - LineDirection direction) +PathFindTrustLine::getItems(AccountID const& accountID, ReadView const& view, LineDirection direction) { - return detail::getTrustLineItems( - accountID, view, direction); + return detail::getTrustLineItems(accountID, view, direction); } -RPCTrustLine::RPCTrustLine( - std::shared_ptr const& sle, - AccountID const& viewAccount) +RPCTrustLine::RPCTrustLine(std::shared_ptr const& sle, AccountID const& viewAccount) : TrustLineBase(sle, viewAccount) , lowQualityIn_(sle->getFieldU32(sfLowQualityIn)) , lowQualityOut_(sle->getFieldU32(sfLowQualityOut)) @@ -107,9 +70,7 @@ RPCTrustLine::RPCTrustLine( } std::optional -RPCTrustLine::makeItem( - AccountID const& accountID, - std::shared_ptr const& sle) +RPCTrustLine::makeItem(AccountID const& accountID, std::shared_ptr const& sle) { if (!sle || sle->getType() != ltRIPPLE_STATE) return {}; @@ -122,4 +83,4 @@ RPCTrustLine::getItems(AccountID const& accountID, ReadView const& view) return detail::getTrustLineItems(accountID, view); } -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/TrustLine.h b/src/xrpld/app/paths/TrustLine.h index 5cff89b177..a0fce8847a 100644 --- a/src/xrpld/app/paths/TrustLine.h +++ b/src/xrpld/app/paths/TrustLine.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED -#define RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED +#pragma once #include #include @@ -29,7 +9,7 @@ #include #include -namespace ripple { +namespace xrpl { /** Describes how an account was found in a path, and how to find the next set of paths. "Outgoing" is defined as the source account, or an account found via a @@ -55,9 +35,7 @@ class TrustLineBase protected: // This class should not be instantiated directly. Use one of the derived // classes. - TrustLineBase( - std::shared_ptr const& sle, - AccountID const& viewAccount); + TrustLineBase(std::shared_ptr const& sle, AccountID const& viewAccount); ~TrustLineBase() = default; TrustLineBase(TrustLineBase const&) = default; @@ -115,15 +93,13 @@ public: LineDirection getDirection() const { - return getNoRipple() ? LineDirection::incoming - : LineDirection::outgoing; + return getNoRipple() ? LineDirection::incoming : LineDirection::outgoing; } LineDirection getDirectionPeer() const { - return getNoRipplePeer() ? LineDirection::incoming - : LineDirection::outgoing; + return getNoRipplePeer() ? LineDirection::incoming : LineDirection::outgoing; } /** Have we set the freeze flag on our peer */ @@ -189,8 +165,7 @@ protected: }; // This wrapper is used for the path finder -class PathFindTrustLine final : public TrustLineBase, - public CountedObject +class PathFindTrustLine final : public TrustLineBase, public CountedObject { using TrustLineBase::TrustLineBase; @@ -201,25 +176,19 @@ public: makeItem(AccountID const& accountID, std::shared_ptr const& sle); static std::vector - getItems( - AccountID const& accountID, - ReadView const& view, - LineDirection direction); + getItems(AccountID const& accountID, ReadView const& view, LineDirection direction); }; // This wrapper is used for the `AccountLines` command and includes the quality // in and quality out values. -class RPCTrustLine final : public TrustLineBase, - public CountedObject +class RPCTrustLine final : public TrustLineBase, public CountedObject { using TrustLineBase::TrustLineBase; public: RPCTrustLine() = delete; - RPCTrustLine( - std::shared_ptr const& sle, - AccountID const& viewAccount); + RPCTrustLine(std::shared_ptr const& sle, AccountID const& viewAccount); Rate const& getQualityIn() const @@ -246,6 +215,4 @@ private: Rate highQualityOut_; }; -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index f24e67c7e1..ebbb51ce25 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -1,26 +1,7 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include -namespace ripple { +namespace xrpl { template AMMLiquidity::AMMLiquidity( @@ -56,15 +37,12 @@ AMMLiquidity::fetchBalances(ReadView const& view) const template TAmounts -AMMLiquidity::generateFibSeqOffer( - TAmounts const& balances) const +AMMLiquidity::generateFibSeqOffer(TAmounts const& balances) const { TAmounts cur{}; - cur.in = toAmount( - getIssue(balances.in), - InitialFibSeqPct * initialBalances_.in, - Number::rounding_mode::upward); + cur.in = + toAmount(getIssue(balances.in), InitialFibSeqPct * initialBalances_.in, Number::rounding_mode::upward); cur.out = swapAssetIn(initialBalances_, cur.in, tradingFee_); if (ammContext_.curIters() == 0) @@ -77,18 +55,13 @@ AMMLiquidity::generateFibSeqOffer( 196418, 317811, 514229, 832040, 1346269}; // clang-format on - XRPL_ASSERT( - !ammContext_.maxItersReached(), - "ripple::AMMLiquidity::generateFibSeqOffer : maximum iterations"); + XRPL_ASSERT(!ammContext_.maxItersReached(), "xrpl::AMMLiquidity::generateFibSeqOffer : maximum iterations"); cur.out = toAmount( - getIssue(balances.out), - cur.out * fib[ammContext_.curIters() - 1], - Number::rounding_mode::downward); + getIssue(balances.out), cur.out * fib[ammContext_.curIters() - 1], Number::rounding_mode::downward); // swapAssetOut() returns negative in this case if (cur.out >= balances.out) - Throw( - "AMMLiquidity: generateFibSeqOffer exceeds the balance"); + Throw("AMMLiquidity: generateFibSeqOffer exceeds the balance"); cur.in = swapAssetOut(balances, cur.out, tradingFee_); @@ -119,16 +92,13 @@ maxOut(T const& out, Issue const& iss) template std::optional> -AMMLiquidity::maxOffer( - TAmounts const& balances, - Rules const& rules) const +AMMLiquidity::maxOffer(TAmounts const& balances, Rules const& rules) const { if (!rules.enabled(fixAMMOverflowOffer)) { return AMMOffer( *this, - {maxAmount(), - swapAssetIn(balances, maxAmount(), tradingFee_)}, + {maxAmount(), swapAssetIn(balances, maxAmount(), tradingFee_)}, balances, Quality{balances}); } @@ -137,19 +107,13 @@ AMMLiquidity::maxOffer( auto const out = maxOut(balances.out, issueOut()); if (out <= TOut{0} || out >= balances.out) return std::nullopt; - return AMMOffer( - *this, - {swapAssetOut(balances, out, tradingFee_), out}, - balances, - Quality{balances}); + return AMMOffer(*this, {swapAssetOut(balances, out, tradingFee_), out}, balances, Quality{balances}); } } template std::optional> -AMMLiquidity::getOffer( - ReadView const& view, - std::optional const& clobQuality) const +AMMLiquidity::getOffer(ReadView const& view, std::optional const& clobQuality) const { // Can't generate more offers if multi-path. if (ammContext_.maxItersReached()) @@ -164,10 +128,8 @@ AMMLiquidity::getOffer( return std::nullopt; } - JLOG(j_.trace()) << "AMMLiquidity::getOffer balances " - << to_string(initialBalances_.in) << " " - << to_string(initialBalances_.out) << " new balances " - << to_string(balances.in) << " " + JLOG(j_.trace()) << "AMMLiquidity::getOffer balances " << to_string(initialBalances_.in) << " " + << to_string(initialBalances_.out) << " new balances " << to_string(balances.in) << " " << to_string(balances.out); // Can't generate AMM with a better quality than CLOB's @@ -178,9 +140,8 @@ AMMLiquidity::getOffer( // to the requested clobQuality but not exactly and potentially SPQ may keep // on approaching clobQuality for many iterations. Checking for the quality // threshold prevents this scenario. - if (auto const spotPriceQ = Quality{balances}; clobQuality && - (spotPriceQ <= clobQuality || - withinRelativeDistance(spotPriceQ, *clobQuality, Number(1, -7)))) + if (auto const spotPriceQ = Quality{balances}; + clobQuality && (spotPriceQ <= clobQuality || withinRelativeDistance(spotPriceQ, *clobQuality, Number(1, -7)))) { JLOG(j_.trace()) << "AMMLiquidity::getOffer, higher clob quality"; return std::nullopt; @@ -194,8 +155,7 @@ AMMLiquidity::getOffer( auto const amounts = generateFibSeqOffer(balances); if (clobQuality && Quality{amounts} < clobQuality) return std::nullopt; - return AMMOffer( - *this, amounts, balances, Quality{amounts}); + return AMMOffer(*this, amounts, balances, Quality{amounts}); } else if (!clobQuality) { @@ -206,18 +166,14 @@ AMMLiquidity::getOffer( // nullopt if the pool is small. return maxOffer(balances, view.rules()); } - else if ( - auto const amounts = changeSpotPriceQuality( - balances, *clobQuality, tradingFee_, view.rules(), j_)) + else if (auto const amounts = changeSpotPriceQuality(balances, *clobQuality, tradingFee_, view.rules(), j_)) { - return AMMOffer( - *this, *amounts, balances, Quality{*amounts}); + return AMMOffer(*this, *amounts, balances, Quality{*amounts}); } else if (view.rules().enabled(fixAMMv1_2)) { if (auto const maxAMMOffer = maxOffer(balances, view.rules()); - maxAMMOffer && - Quality{maxAMMOffer->amount()} > *clobQuality) + maxAMMOffer && Quality{maxAMMOffer->amount()} > *clobQuality) return maxAMMOffer; } } @@ -238,22 +194,16 @@ AMMLiquidity::getOffer( if (offer) { - if (offer->amount().in > beast::zero && - offer->amount().out > beast::zero) + if (offer->amount().in > beast::zero && offer->amount().out > beast::zero) { - JLOG(j_.trace()) - << "AMMLiquidity::getOffer, created " - << to_string(offer->amount().in) << "/" << issueIn_ << " " - << to_string(offer->amount().out) << "/" << issueOut_; + JLOG(j_.trace()) << "AMMLiquidity::getOffer, created " << to_string(offer->amount().in) << "/" << issueIn_ + << " " << to_string(offer->amount().out) << "/" << issueOut_; return offer; } - JLOG(j_.debug()) << "AMMLiquidity::getOffer, no valid offer " - << ammContext_.multiPath() << " " - << ammContext_.curIters() << " " - << (clobQuality ? clobQuality->rate() : STAmount{}) - << " " << to_string(balances.in) << " " - << to_string(balances.out); + JLOG(j_.debug()) << "AMMLiquidity::getOffer, no valid offer " << ammContext_.multiPath() << " " + << ammContext_.curIters() << " " << (clobQuality ? clobQuality->rate() : STAmount{}) << " " + << to_string(balances.in) << " " << to_string(balances.out); } return std::nullopt; @@ -264,4 +214,4 @@ template class AMMLiquidity; template class AMMLiquidity; template class AMMLiquidity; -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/detail/AMMOffer.cpp b/src/xrpld/app/paths/detail/AMMOffer.cpp index aa55a9759e..dd6b021689 100644 --- a/src/xrpld/app/paths/detail/AMMOffer.cpp +++ b/src/xrpld/app/paths/detail/AMMOffer.cpp @@ -1,28 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2023 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include -namespace ripple { +namespace xrpl { template AMMOffer::AMMOffer( @@ -30,11 +11,7 @@ AMMOffer::AMMOffer( TAmounts const& amounts, TAmounts const& balances, Quality const& quality) - : ammLiquidity_(ammLiquidity) - , amounts_(amounts) - , balances_(balances) - , quality_(quality) - , consumed_(false) + : ammLiquidity_(ammLiquidity), amounts_(amounts), balances_(balances), quality_(quality), consumed_(false) { } @@ -61,9 +38,7 @@ AMMOffer::amount() const template void -AMMOffer::consume( - ApplyView& view, - TAmounts const& consumed) +AMMOffer::consume(ApplyView& view, TAmounts const& consumed) { // Consumed offer must be less or equal to the original if (consumed.in > amounts_.in || consumed.out > amounts_.out) @@ -79,10 +54,7 @@ AMMOffer::consume( template TAmounts -AMMOffer::limitOut( - TAmounts const& offrAmt, - TOut const& limit, - bool roundUp) const +AMMOffer::limitOut(TAmounts const& offerAmount, TOut const& limit, bool roundUp) const { // Change the offer size proportionally to the original offer quality // to keep the strands quality order unchanged. The taker pays slightly @@ -94,7 +66,7 @@ AMMOffer::limitOut( { // It turns out that the ceil_out implementation has some slop in // it, which ceil_out_strict removes. - return quality().ceil_out_strict(offrAmt, limit, roundUp); + return quality().ceil_out_strict(offerAmount, limit, roundUp); } // Change the offer size according to the conservation function. The offer // quality is increased in this case, but it doesn't matter since there is @@ -104,19 +76,15 @@ AMMOffer::limitOut( template TAmounts -AMMOffer::limitIn( - TAmounts const& offrAmt, - TIn const& limit, - bool roundUp) const +AMMOffer::limitIn(TAmounts const& offerAmount, TIn const& limit, bool roundUp) const { // See the comments above in limitOut(). if (ammLiquidity_.multiPath()) { - if (auto const& rules = getCurrentTransactionRules(); - rules && rules->enabled(fixReducedOffersV2)) - return quality().ceil_in_strict(offrAmt, limit, roundUp); + if (auto const& rules = getCurrentTransactionRules(); rules && rules->enabled(fixReducedOffersV2)) + return quality().ceil_in_strict(offerAmount, limit, roundUp); - return quality().ceil_in(offrAmt, limit); + return quality().ceil_in(offerAmount, limit); } return {limit, swapAssetIn(balances_, limit, ammLiquidity_.tradingFee())}; } @@ -127,45 +95,33 @@ AMMOffer::getQualityFunc() const { if (ammLiquidity_.multiPath()) return QualityFunction{quality(), QualityFunction::CLOBLikeTag{}}; - return QualityFunction{ - balances_, ammLiquidity_.tradingFee(), QualityFunction::AMMTag{}}; + return QualityFunction{balances_, ammLiquidity_.tradingFee(), QualityFunction::AMMTag{}}; } template bool -AMMOffer::checkInvariant( - TAmounts const& consumed, - beast::Journal j) const +AMMOffer::checkInvariant(TAmounts const& consumed, beast::Journal j) const { if (consumed.in > amounts_.in || consumed.out > amounts_.out) { - JLOG(j.error()) << "AMMOffer::checkInvariant failed: consumed " - << to_string(consumed.in) << " " - << to_string(consumed.out) << " amounts " - << to_string(amounts_.in) << " " + JLOG(j.error()) << "AMMOffer::checkInvariant failed: consumed " << to_string(consumed.in) << " " + << to_string(consumed.out) << " amounts " << to_string(amounts_.in) << " " << to_string(amounts_.out); return false; } Number const product = balances_.in * balances_.out; - auto const newBalances = TAmounts{ - balances_.in + consumed.in, balances_.out - consumed.out}; + auto const newBalances = TAmounts{balances_.in + consumed.in, balances_.out - consumed.out}; Number const newProduct = newBalances.in * newBalances.out; - if (newProduct >= product || - withinRelativeDistance(product, newProduct, Number{1, -7})) + if (newProduct >= product || withinRelativeDistance(product, newProduct, Number{1, -7})) return true; - JLOG(j.error()) << "AMMOffer::checkInvariant failed: balances " - << to_string(balances_.in) << " " - << to_string(balances_.out) << " new balances " - << to_string(newBalances.in) << " " - << to_string(newBalances.out) << " product/newProduct " - << product << " " << newProduct << " diff " - << (product != Number{0} - ? to_string((product - newProduct) / product) - : "undefined"); + JLOG(j.error()) << "AMMOffer::checkInvariant failed: balances " << to_string(balances_.in) << " " + << to_string(balances_.out) << " new balances " << to_string(newBalances.in) << " " + << to_string(newBalances.out) << " product/newProduct " << product << " " << newProduct << " diff " + << (product != Number{0} ? to_string((product - newProduct) / product) : "undefined"); return false; } @@ -174,4 +130,4 @@ template class AMMOffer; template class AMMOffer; template class AMMOffer; -} // namespace ripple +} // namespace xrpl diff --git a/src/xrpld/app/paths/detail/AmountSpec.h b/src/xrpld/app/paths/detail/AmountSpec.h index d57e9140f8..690e67ae22 100644 --- a/src/xrpld/app/paths/detail/AmountSpec.h +++ b/src/xrpld/app/paths/detail/AmountSpec.h @@ -1,24 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED -#define RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED +#pragma once #include #include @@ -26,7 +6,7 @@ #include -namespace ripple { +namespace xrpl { struct AmountSpec { @@ -125,8 +105,7 @@ template <> inline IOUAmount& get(EitherAmount& amt) { - XRPL_ASSERT( - !amt.native, "ripple::get(EitherAmount&) : is not XRP"); + XRPL_ASSERT(!amt.native, "xrpl::get(EitherAmount&) : is not XRP"); return amt.iou; } @@ -134,7 +113,7 @@ template <> inline XRPAmount& get(EitherAmount& amt) { - XRPL_ASSERT(amt.native, "ripple::get(EitherAmount&) : is XRP"); + XRPL_ASSERT(amt.native, "xrpl::get(EitherAmount&) : is XRP"); return amt.xrp; } @@ -150,9 +129,7 @@ template <> inline IOUAmount const& get(EitherAmount const& amt) { - XRPL_ASSERT( - !amt.native, - "ripple::get(EitherAmount const&) : is not XRP"); + XRPL_ASSERT(!amt.native, "xrpl::get(EitherAmount const&) : is not XRP"); return amt.iou; } @@ -160,8 +137,7 @@ template <> inline XRPAmount const& get(EitherAmount const& amt) { - XRPL_ASSERT( - amt.native, "ripple::get(EitherAmount const&) : is XRP"); + XRPL_ASSERT(amt.native, "xrpl::get(EitherAmount const&) : is XRP"); return amt.xrp; } @@ -170,10 +146,9 @@ toAmountSpec(STAmount const& amt) { XRPL_ASSERT( amt.mantissa() < std::numeric_limits::max(), - "ripple::toAmountSpec(STAmount const&) : maximum mantissa"); + "xrpl::toAmountSpec(STAmount const&) : maximum mantissa"); bool const isNeg = amt.negative(); - std::int64_t const sMant = - isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); + std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); AmountSpec result; result.native = isXRP(amt); @@ -207,7 +182,7 @@ toAmountSpec(EitherAmount const& ea, std::optional const& c) r.currency = c; XRPL_ASSERT( ea.native == r.native, - "ripple::toAmountSpec(EitherAmount const&&, std::optional) : " + "xrpl::toAmountSpec(EitherAmount const&&, std::optional) : " "matching native"); if (r.native) { @@ -220,6 +195,4 @@ toAmountSpec(EitherAmount const& ea, std::optional const& c) return r; } -} // namespace ripple - -#endif +} // namespace xrpl diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 5ac08295fc..b9c8aa4e67 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -1,22 +1,3 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - #include #include #include @@ -39,7 +20,7 @@ #include #include -namespace ripple { +namespace xrpl { template class BookStep : public StepImp> @@ -128,8 +109,7 @@ public: DebtDirection debtDirection(ReadView const& sb, StrandDirection dir) const override { - return ownerPaysTransferFee_ ? DebtDirection::issues - : DebtDirection::redeems; + return ownerPaysTransferFee_ ? DebtDirection::issues : DebtDirection::redeems; } std::optional @@ -139,8 +119,7 @@ public: } std::pair, DebtDirection> - qualityUpperBound(ReadView const& v, DebtDirection prevStepDir) - const override; + qualityUpperBound(ReadView const& v, DebtDirection prevStepDir) const override; std::pair, DebtDirection> getQualityFunc(ReadView const& v, DebtDirection prevStepDir) const override; @@ -149,22 +128,13 @@ public: offersUsed() const override; std::pair - revImp( - PaymentSandbox& sb, - ApplyView& afView, - boost::container::flat_set& ofrsToRm, - TOut const& out); + revImp(PaymentSandbox& sb, ApplyView& afView, boost::container::flat_set& ofrsToRm, TOut const& out); std::pair - fwdImp( - PaymentSandbox& sb, - ApplyView& afView, - boost::container::flat_set& ofrsToRm, - TIn const& in); + fwdImp(PaymentSandbox& sb, ApplyView& afView, boost::container::flat_set& ofrsToRm, TIn const& in); std::pair - validFwd(PaymentSandbox& sb, ApplyView& afView, EitherAmount const& in) - override; + validFwd(PaymentSandbox& sb, ApplyView& afView, EitherAmount const& in) override; // Check for errors frozen constraints. TER @@ -182,9 +152,7 @@ protected: { std::ostringstream ostr; ostr << name << ": " - << "\ninIss: " << book_.in.account - << "\noutIss: " << book_.out.account - << "\ninCur: " << book_.in.currency + << "\ninIss: " << book_.in.account << "\noutIss: " << book_.out.account << "\ninCur: " << book_.in.currency << "\noutCur: " << book_.out.currency; return ostr.str(); } @@ -212,11 +180,7 @@ private: // Return the unfunded and bad offers and the number of offers consumed. template std::pair, std::uint32_t> - forEachOffer( - PaymentSandbox& sb, - ApplyView& afView, - DebtDirection prevStepDebtDir, - Callback& callback) const; + forEachOffer(PaymentSandbox& sb, ApplyView& afView, DebtDirection prevStepDebtDir, Callback& callback) const; // Offer is either TOffer or AMMOffer template